diff options
822 files changed, 33984 insertions, 6867 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt index 1c0dfa43952c..a35a8f0d6622 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm.txt @@ -255,6 +255,7 @@ compatible = "qcom,msmhamster-rumi" compatible = "qcom,msmhamster-cdp" compatible = "qcom,msmhamster-mtp" compatible = "qcom,msmfalcon-sim" +compatible = "qcom,msmfalcon-rumi" compatible = "qcom,msm8952-rumi" compatible = "qcom,msm8952-sim" compatible = "qcom,msm8952-qrd" diff --git a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt index ed0f7a337426..c1e2d3b2ba11 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt @@ -224,6 +224,12 @@ Optional child nodes qcom,mx-restriction-temp and qcom,mx-restriction-temp-hysteresis should also be present. Also, if this property is defined, will have to define vdd-cx-supply = <&phandle_of_regulator>. +- qcom,mx-restriction-sensor_id: sensor id, which needs to be monitored for requesting MX/CX + retention voltage. If this optional property is defined, msm_thermal + will monitor only this sensor, otherwise by default it will monitor + all TSENS for this feature. If this property exists, then the properties, + qcom,mx-restriction-temp, qcom,mx-restriction-temp-hysteresis and + qcom,mx-retention-min should also be defined to enable this feature. - qcom,therm-reset-temp: Degree above which the KTM will initiate a secure watchdog reset. When this property is defined, KTM will monitor all the tsens from boot time and will initiate a secure watchdog reset if any of the @@ -269,6 +275,7 @@ Example: qcom,mx-restriction-temp = <5>; qcom,mx-restriction-temp-hysteresis = <10>; qcom,mx-retention-min = <710000>; + qcom,mx-restriction-sensor_id = <2>; vdd-mx-supply = <&pma8084_s1>; qcom,cx-retention-min = <RPM_SMD_REGULATOR_LEVEL_RETENTION_PLUS>; vdd-cx-supply = <&pmd9635_s5_level>; diff --git a/Documentation/devicetree/bindings/arm/omap/omap.txt b/Documentation/devicetree/bindings/arm/omap/omap.txt index 9f4e5136e568..12af302bca6a 100644 --- a/Documentation/devicetree/bindings/arm/omap/omap.txt +++ b/Documentation/devicetree/bindings/arm/omap/omap.txt @@ -23,6 +23,7 @@ Optional properties: during suspend. - ti,no-reset-on-init: When present, the module should not be reset at init - ti,no-idle-on-init: When present, the module should not be idled at init +- ti,no-idle: When present, the module is never allowed to idle. Example: diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt index 00b778feaba8..9fc942cc627d 100644 --- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt +++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt @@ -401,6 +401,10 @@ Optional properties: - qcom,cmd-to-video-mode-switch-commands: List of commands that need to be sent to panel in order to switch from command mode to video mode dynamically. Refer to "qcom,mdss-dsi-on-command" section for adding commands. +- qcom,send-pps-before-switch: Boolean propety to indicate when PPS commands should be sent, + either before or after switch commands during dynamic resolution + switch in DSC panels. If the property is not present, the default + behavior is to send PPS commands after the switch commands. - qcom,mdss-dsi-panel-orientation: String used to indicate orientation of panel "180" = panel is flipped in both horizontal and vertical directions "hflip" = panel is flipped in horizontal direction @@ -619,6 +623,7 @@ Example: qcom,video-to-cmd-mode-switch-commands = [15 01 00 00 00 00 02 C2 0B 15 01 00 00 00 00 02 C2 08]; qcom,cmd-to-video-mode-switch-commands = [15 01 00 00 00 00 02 C2 03]; + qcom,send-pps-before-switch; qcom,panel-ack-disabled; qcom,mdss-dsi-horizontal-line-idle = <0 40 256>, <40 120 128>, @@ -650,6 +655,19 @@ Example: 29 00 00 00 00 00 02 B0 04 29 00 00 00 00 00 02 F1 00]; qcom,mdss-dsi-timing-switch-command-state = "dsi_lp_mode"; + + qcom,config-select = <&dsi_sim_vid_config0>; + dsi_sim_vid_config0: config0 { + qcom,lm-split = <360 360>; + qcom,mdss-dsc-encoders = <2>; + qcom,mdss-dsc-slice-height = <16>; + qcom,mdss-dsc-slice-width = <360>; + qcom,mdss-dsc-slice-per-pkt = <2>; + qcom,mdss-dsc-bit-per-component = <8>; + qcom,mdss-dsc-bit-per-pixel = <8>; + qcom,mdss-dsc-block-prediction-enable; + qcom,mdss-dsc-config-by-manufacture-cmd; + }; }; }; qcom,panel-supply-entries { diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt index 5097e994f483..ce2e38b905a1 100644 --- a/Documentation/devicetree/bindings/gpu/adreno.txt +++ b/Documentation/devicetree/bindings/gpu/adreno.txt @@ -31,6 +31,8 @@ Required properties: - qcom,base-leakage-coefficient: Dynamic leakage coefficient. - qcom,lm-limit: Current limit for GPU limit management. +- qcom,isense-clk-on-level: below or equal this power level isense clock is at XO rate, + above this powerlevel isense clock is at working frequency. Bus Scaling Data: - qcom,msm-bus,name: String property to describe the name of the 3D graphics processor. @@ -89,6 +91,7 @@ Optional Properties: - qcom,idle-timeout: This property represents the time in milliseconds for idle timeout. - qcom,deep-nap-timeout: This property represents the time in milliseconds for entering deeper power state. +- qcom,no-nap: If it exists software clockgating will be disabled at boot time. - qcom,chipid: If it exists this property is used to replace the chip identification read from the GPU hardware. This is used to override faulty hardware readings. diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt index 827f96c341b6..1102cb5d4f6f 100644 --- a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt +++ b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt @@ -6,6 +6,8 @@ camera sensor when background light is dim to capture good picture. It can also be used for flashlight/torch application. It is part of PMIC on Qualcomm Technologies Inc. reference platforms. +Main node: + Required properties: - compatible : Should be "qcom,qpnp-flash-led-v2" - reg : Base address and size for flash LED modules @@ -14,10 +16,17 @@ Optional properties: - qcom,hdrm-auto-mode : Boolean type to select headroom auto mode enabled or not - qcom,isc-delay : Integer type to specify short circuit delay. Valid values are 32, 64, 128, 192. Unit is us. +- qcom,hw-strobe-option : Integer type to specify hardware strobe option. Based on the specified + value, additional GPIO configuration may be required to provide strobing + support. Supported values are: + 0: Flash strobe is used for LED1, LED2, LED3 + 1: Flash strobe is used for LED1, LED2 and GPIO10 is used for LED3 + 2: Flash strobe is used for LED1; GPIO9 is used for LED2; GPIO10 is used for LED3 + +Child node: Contains settings for each individual LED. Each LED channel needs a flash node and +torch node for itself, and an individual switch node to serve as an overall switch. -Required properties inside child node. Child node contains settings for each individual LED. -Each LED channel needs a flash node and torch node for itself, and an individual switch node to -serve as an overall switch. +Required Properties: - label : Type of led that will be used, either "flash", "torch", or "switch. - qcom,led-name : Name of the LED. - qcom,default-led-trigger : Trigger for the camera flash and torch. Accepted values are @@ -29,28 +38,54 @@ serve as an overall switch. not required for switch node. - qcom,max-current : Maximum current allowed on this LED. Valid values should be integer from 0 to 1500 inclusive. Flash 2 should have maximum current of - 750 per hardware requirement. Unit is mA. This is not required for switch - node. + 750 per hardware requirement. Unit is mA. For torch, the maximum current + is clamped at 500 mA. This is not required for the switch node. - qcom,duration-ms : Required property for flash nodes but not needed for torch. Integer type specifying flash duration. Values are from 10ms to 1280ms with 10ms resolution. This is not required for switch node. +- qcom,led-mask : Required property for switch nodes. Bitmask to indicate which leds are + controlled by this switch node. Accepted values are in the range 1 to 7, + inclusive. Example: + qcom,led-mask = <4>; /* This switch node controls the flash2/torch2 led. */ -Optional properties inside child node: +Optional properties: +- qcom,current-ma : operational current intensity for LED in mA. Accepted values are a + positive integer in the range of 0 to qcom,max-current inclusive. - qcom,ires-ua : Integer type to specify current resolution. Accepted values should be 12500, 10000, 7500, and 5000. Unit is uA. - qcom,hdrm-voltage-mv : Integer type specifying headroom voltage. Values are from 125mV to 500mV with 25mV resolution. Default setting is 325mV - qcom,hdrm-vol-hi-lo-win-mv : Integer type to specify headroom voltage swing range. Values are from 0mV to 375mV with 25mV resolution. Default setting is 100mV. -- pinctrl-names : This should be defined if a target uses pinctrl framework and there is GPIO - requirement for flash LEDs. See "pinctrl" in - Documentation/devicetree/bindings/pinctrl/msm-pinctrl.txt. It should specify - the names of the configs that pinctrl can install in driver. - Following are the pinctrl configs that can be installed: - "led_enable" : Enablement configuration of pins. This should specify active - config defined in each pin or pin group. - "led_disable" : Disablement configuration of pins. This should specify inactive - config defined in each pin or pin groups. +- pinctrl-names : Name of the pinctrl configuration that will be used when external GPIOs + are used for enabling/disabling, HW strobing of flash LEDs. For more + information on using pinctrl, please refer + Documentation/devicetree/bindings/pinctrl/msm-pinctrl.txt + Following are the pinctrl configs that can be specified: + "led_enable" : pinctrl config to enable led. This should specify the active + configuration defined for each pin or pin group. + "led_disable" : pinctrl config to disable led. This should specify the sleep + configuration defined for each pin or pin group. + "strobe_enable" : pinctrl config to enable hw-strobe. This should specify the + active configuration defined for each pin or pin group. + "strobe_disable" : pinctrl config to disable hw-strobe. This should specify the + sleep configuration defined for each pin or pin group. +- qcom,hw-strobe-gpio : phandle to specify GPIO for hardware strobing. This is used when there is no + pinctrl support or PMIC GPIOs are used. +- qcom,hw-strobe-sel : Boolean property to enable hardware strobe. If not defined, software strobe + will be used. +- qcom,hw-strobe-edge-trigger : Boolean property to select trigger type. If defined, hw-strobe is set to + be edge triggered. Otherwise, it is level triggered. +- qcom,hw-strobe-active-low : Boolean property to select strobe signal polarity. If defined, hw-strobe + signal polarity is set to active-low, else it is active-high. +- reg<n> : reg<n> (<n> represents number. e.g. 0,1,2,..) subnode is to add support for + multiple power sources. This subnode should only be specified for switch nodes. + Required property inside regulator node: + - regulator-name : Name of the regulator which has to be used for this + switch node. + Optional property inside regulator node: + - max-voltage-uv : This specifies max voltage of regulator. Some switch + or boost regulator does not need this property. Example: qcom,leds@d300 { @@ -69,6 +104,7 @@ Example: qcom,default-led-trigger = "flash0_trigger"; qcom,id = <0>; + qcom,current-ma = <1000>; qcom,duration-ms = <1280>; qcom,ires-ua = <12500>; qcom,hdrm-voltage-mv = <325>; @@ -82,6 +118,7 @@ Example: qcom,default-led-trigger = "flash1_trigger"; qcom,id = <1>; + qcom,current-ma = <1000>; qcom,duration-ms = <1280>; qcom,ires-ua = <12500>; qcom,hdrm-voltage-mv = <325>; @@ -95,6 +132,7 @@ Example: qcom,default-led-trigger = "flash2_trigger"; qcom,id = <2>; + qcom,current-ma = <500>; qcom,duration-ms = <1280>; qcom,ires-ua = <12500>; qcom,hdrm-voltage-mv = <325>; @@ -107,10 +145,11 @@ Example: pmi8998_torch0: qcom,torch_0 { label = "torch"; qcom,led-name = "led:torch_0"; - qcom,max-current = <200>; + qcom,max-current = <500>; qcom,default-led-trigger = "torch0_trigger"; qcom,id = <0>; + qcom,current-ma = <300>; qcom,ires-ua = <12500>; qcom,hdrm-voltage-mv = <325>; qcom,hdrm-vol-hi-lo-win-mv = <100>; @@ -119,10 +158,11 @@ Example: pmi8998_torch1: qcom,torch_1 { label = "torch"; qcom,led-name = "led:torch_1"; - qcom,max-current = <200>; + qcom,max-current = <500>; qcom,default-led-trigger = "torch1_trigger"; qcom,id = <1>; + qcom,current-ma = <300>; qcom,ires-ua = <12500>; qcom,hdrm-voltage-mv = <325>; qcom,hdrm-vol-hi-lo-win-mv = <100>; @@ -131,10 +171,11 @@ Example: pmi8998_torch2: qcom,torch_2 { label = "torch"; qcom,led-name = "led:torch_2"; - qcom,max-current = <200>; + qcom,max-current = <500>; qcom,default-led-trigger = "torch2_trigger"; qcom,id = <2>; + qcom,current-ma = <300>; qcom,ires-ua = <12500>; qcom,hdrm-voltage-mv = <325>; qcom,hdrm-vol-hi-lo-win-mv = <100>; @@ -143,11 +184,28 @@ Example: pinctrl-1 = <&led_disable>; }; - pmi8998_switch: qcom,led_switch { + pmi8998_switch0: qcom,led_switch_0 { + label = "switch"; + qcom,led-name = "led:switch_0"; + qcom,led-mask = <3>; + qcom,default-led-trigger = + "switch0_trigger"; + reg0 { + regulator-name = "pmicobalt_bob"; + max-voltage-uv = <3600000>; + }; + }; + + pmi8998_switch1: qcom,led_switch_1 { label = "switch"; - qcom,led-name = "led:switch"; + qcom,led-name = "led:switch_1"; + qcom,led-mask = <4>; qcom,default-led-trigger = - "switch_trigger"; + "switch1_trigger"; + reg0 { + regulator-name = "pmicobalt_bob"; + max-voltage-uv = <3600000>; + }; }; }; diff --git a/Documentation/devicetree/bindings/mfd/qcom-i2c-pmic.txt b/Documentation/devicetree/bindings/mfd/qcom-i2c-pmic.txt index 9c7c856ea42b..7e9aee1a96b3 100644 --- a/Documentation/devicetree/bindings/mfd/qcom-i2c-pmic.txt +++ b/Documentation/devicetree/bindings/mfd/qcom-i2c-pmic.txt @@ -32,29 +32,29 @@ Platform independent properties: Definition: 7-bit I2C address of the device. - interrupt-parent - Usage: required + Usage: optional Value type: <phandle> Definition: phandle of the interrupt controller which services the summary interrupt. - interrupts - Usage: required + Usage: optional Value type: <prop-encoded-array> Definition: Summary interrupt specifier. - interrupt-controller - Usage: required + Usage: optional Value type: <empty> Definition: Boolean flag which indicates this device node is an interrupt controller. - #interrupt-cells - Usage: required + Usage: optional Value type: <u32> Definition: Number of cells to encode an interrupt source. - qcom,periph-map - Usage: required + Usage: optional Value type: <prop-encoded-array> Definition: A list of u32 arrays. This provides a mapping between the summary status register bits and peripheral addresses. diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,wcd-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,wcd-pinctrl.txt new file mode 100644 index 000000000000..add8b7d688a8 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,wcd-pinctrl.txt @@ -0,0 +1,138 @@ +Qualcomm Technologies, Inc. WCD GPIO block + +This binding describes the GPIO block found in the WCD934X series of +audio codec's from QTI. + +- compatible: + Usage: required + Value type: <string> + Definition: must be "qcom,wcd-pinctrl" + +- qcom,num-gpios: + Usage: required + Value type: <u32> + Definition: Number of GPIO's supported by the controller + +- gpio-controller: + Usage: required + Value type: <none> + Definition: Mark the device node as a GPIO controller + +- #gpio-cells: + Usage: required + Value type: <u32> + Definition: Must be 2; + the first cell will be used to define gpio number and the + second denotes the flags for this gpio + +Please refer to ../gpio/gpio.txt for a general description of GPIO bindings. + +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the meaning of the +phrase "pin configuration node". + +The pin configuration nodes act as a container for an arbitrary number of +subnodes. Each of these subnodes represents some desired configuration for a +pin or a list of pins. This configuration can include the +mux function to select on those pin(s), and various pin configuration +parameters, as listed below. + + +SUBNODES: + +The name of each subnode is not important; all subnodes should be enumerated +and processed purely based on their content. + +Each subnode only affects those parameters that are explicitly listed. In +other words, a subnode that lists a mux function but no pin configuration +parameters implies no information about any pin configuration parameters. +Similarly, a pin subnode that describes a pullup parameter implies no +information about e.g. the mux function. + +The following generic properties as defined in pinctrl-bindings.txt are valid +to specify in a pin configuration subnode: + +- pins: + Usage: required + Value type: <string-array> + Definition: List of gpio pins affected by the properties specified in + this subnode. Valid pins are: + gpio1-gpio5 for wcd9340 + +- bias-disable: + Usage: optional + Value type: <none> + Definition: The specified pins should be configured as no pull. + +- bias-pull-down: + Usage: optional + Value type: <none> + Definition: The specified pins should be configured as pull down. + +- bias-pull-up: + Usage: optional + Value type: <empty> + Definition: The specified pins should be configured as pull up. + +- qcom,pull-up-strength: + Usage: optional + Value type: <u32> + Definition: Specifies the strength to use for pull up, if selected. + +- bias-high-impedance: + Usage: optional + Value type: <none> + Definition: The specified pins will put in high-Z mode and disabled. + +- input-enable: + Usage: optional + Value type: <none> + Definition: The specified pins are put in input mode. + +- output-high: + Usage: optional + Value type: <none> + Definition: The specified pins are configured in output mode, driven + high. + +- output-low: + Usage: optional + Value type: <none> + Definition: The specified pins are configured in output mode, driven + low. + +- qcom,drive-strength: + Usage: optional + Value type: <u32> + Definition: Selects the drive strength for the specified pins. + +Example: + + wcd: wcd_pinctrl@5 { + compatible = "qcom,wcd-pinctl"; + qcom,num-gpios = <5> + gpio-controller; + #gpio-cells = <2>; + + spkr_1_wcd_en_active: spkr_1_wcd_en_active { + mux { + pins = "gpio2"; + }; + + config { + pins = "gpio2"; + output-high; + }; + }; + + spkr_1_wcd_en_sleep: spkr_1_wcd_en_sleep { + mux { + pins = "gpio2"; + }; + + config { + pins = "gpio2"; + input-enable; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index 660d87f46f3b..b30b6b87add6 100755 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -1986,9 +1986,11 @@ Example: * MSMCOBALT ASoC Machine driver Required properties: -- compatible : "qcom,msmcobalt-asoc-snd-tasha" +- compatible : "qcom,msmcobalt-asoc-snd-tasha" for tasha codec, + "qcom,msmcobalt-asoc-snd-tavil" for tavil codec. - qcom,model : The user-visible name of this sound card. - qcom,tasha-mclk-clk-freq : MCLK frequency value for tasha codec +- qcom,tavil-mclk-clk-freq : MCLK frequency value for tavil codec - qcom,audio-routing : A list of the connections between audio components. - asoc-platform: This is phandle list containing the references to platform device nodes that are used as part of the sound card dai-links. diff --git a/Documentation/devicetree/bindings/sound/qcom-usb-audio-qmi-dev.txt b/Documentation/devicetree/bindings/sound/qcom-usb-audio-qmi-dev.txt new file mode 100644 index 000000000000..9d3fb78f96a7 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom-usb-audio-qmi-dev.txt @@ -0,0 +1,26 @@ +QTI USB Audio QMI Device + +USB Audio QMI device is used to attach to remote processor IOMMU and +map USB Audio driver specific memory to iova to share with remote +processor. + +Required Properties: + +- compatible : "qcom,usb-audio-qmi-dev" + +- iommus : A list of phandle and IOMMU specifier pairs that describe the + IOMMU master interfaces of the device. + +- qcom,usb-audio-stream-id : Stream id is prepended to iova before passing + iova to remote processor. This allows remote processor to access iova. + +- qcom,usb-audio-intr-num : Interrupter number for external sub system + destination. + +Example: + usb_audio_qmi_dev { + compatible = "qcom,usb-audio-qmi-dev"; + iommus = <&lpass_q6_smmu 12>; + qcom,usb-audio-stream-id = <12>; + qcom,usb-audio-intr-num = <1>; + }; diff --git a/Documentation/devicetree/bindings/sound/taiko_codec.txt b/Documentation/devicetree/bindings/sound/wcd_codec.txt index 3bf9e7c74305..d585595f21c6 100755..100644 --- a/Documentation/devicetree/bindings/sound/taiko_codec.txt +++ b/Documentation/devicetree/bindings/sound/wcd_codec.txt @@ -1,10 +1,9 @@ -taiko audio CODEC +WCD audio CODEC Required properties: - - compatible : "qcom,taiko-slim-pgd" or "qcom,tapan-slim-pgd" for Tapan codec - or "qcom,tomtom-slim-pgd" for the Tomtom codec - or "qcom,tasha-slim-pgd" or "qcom,tasha-i2c-pgd" for Tasha Codec + - compatible : "qcom,tasha-slim-pgd" or "qcom,tasha-i2c-pgd" for Tasha Codec + or "qcom,tavil-slim-pgd" for Tavil Codec - elemental-addr: codec slimbus slave PGD enumeration address.(48 bits) - qcom,cdc-reset-gpio: gpio used for codec SOC reset. diff --git a/Documentation/devicetree/bindings/thermal/tsens.txt b/Documentation/devicetree/bindings/thermal/tsens.txt index 4f9a02065e44..9aa52dde2dd4 100644 --- a/Documentation/devicetree/bindings/thermal/tsens.txt +++ b/Documentation/devicetree/bindings/thermal/tsens.txt @@ -30,6 +30,8 @@ Required properties: should be "qcom,msm8937-tsens" for 8937 TSENS driver. should be "qcom,msmgold-tsens" for gold TSENS driver. should be "qcom,msmcobalt-tsens" for cobalt TSENS driver. + should be "qcom,msmhamster-tsens" for hamster TSENS driver. + should be "qcom,msmfalcon-tsens" for falcon TSENS driver. The compatible property is used to identify the respective fusemap to use for the corresponding SoC. - reg : offset and length of the TSENS registers. diff --git a/Documentation/devicetree/bindings/usb/msm-phy.txt b/Documentation/devicetree/bindings/usb/msm-phy.txt index e909c67ca20a..35bb94b2ef70 100644 --- a/Documentation/devicetree/bindings/usb/msm-phy.txt +++ b/Documentation/devicetree/bindings/usb/msm-phy.txt @@ -143,7 +143,7 @@ Example: QUSB2 High-Speed PHY Required properties: - - compatible: Should be "qcom,qusb2phy" + - compatible: Should be "qcom,qusb2phy" or "qcom,qusb2phy-v2" - reg: Address and length of the QUSB2 PHY register set - reg-names: Should be "qusb_phy_base". - <supply-name>-supply: phandle to the regulator device tree node diff --git a/Documentation/filesystems/efivarfs.txt b/Documentation/filesystems/efivarfs.txt index c477af086e65..686a64bba775 100644 --- a/Documentation/filesystems/efivarfs.txt +++ b/Documentation/filesystems/efivarfs.txt @@ -14,3 +14,10 @@ filesystem. efivarfs is typically mounted like this, mount -t efivarfs none /sys/firmware/efi/efivars + +Due to the presence of numerous firmware bugs where removing non-standard +UEFI variables causes the system firmware to fail to POST, efivarfs +files that are not well-known standardized variables are created +as immutable files. This doesn't prevent removal - "chattr -i" will work - +but it does prevent this kind of failure from being accomplished +accidentally. diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 8ec6be0dd1b1..65c1849f8269 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -3413,6 +3413,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ro [KNL] Mount root device read-only on boot + rodata= [KNL] + on Mark read-only kernel memory as read-only (default). + off Leave read-only kernel memory writable for debugging. + root= [KNL] Root filesystem See name_to_dev_t comment in init/do_mounts.c. diff --git a/Documentation/virtual/kvm/mmu.txt b/Documentation/virtual/kvm/mmu.txt index 3a4d681c3e98..b653641d4261 100644 --- a/Documentation/virtual/kvm/mmu.txt +++ b/Documentation/virtual/kvm/mmu.txt @@ -358,7 +358,8 @@ In the first case there are two additional complications: - if CR4.SMEP is enabled: since we've turned the page into a kernel page, the kernel may now execute it. We handle this by also setting spte.nx. If we get a user fetch or read fault, we'll change spte.u=1 and - spte.nx=gpte.nx back. + spte.nx=gpte.nx back. For this to work, KVM forces EFER.NX to 1 when + shadow paging is in use. - if CR4.SMAP is disabled: since the page has been changed to a kernel page, it can not be reused when CR4.SMAP is enabled. We set CR4.SMAP && !CR0.WP into shadow page's role to avoid this case. Note, @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 4 -SUBLEVEL = 3 +SUBLEVEL = 6 EXTRAVERSION = NAME = Blurry Fish Butt diff --git a/arch/arc/include/asm/irqflags-arcv2.h b/arch/arc/include/asm/irqflags-arcv2.h index 258b0e5ad332..68b6092349d7 100644 --- a/arch/arc/include/asm/irqflags-arcv2.h +++ b/arch/arc/include/asm/irqflags-arcv2.h @@ -22,6 +22,7 @@ #define AUX_IRQ_CTRL 0x00E #define AUX_IRQ_ACT 0x043 /* Active Intr across all levels */ #define AUX_IRQ_LVL_PEND 0x200 /* Pending Intr across all levels */ +#define AUX_IRQ_HINT 0x201 /* For generating Soft Interrupts */ #define AUX_IRQ_PRIORITY 0x206 #define ICAUSE 0x40a #define AUX_IRQ_SELECT 0x40b @@ -112,6 +113,16 @@ static inline int arch_irqs_disabled(void) return arch_irqs_disabled_flags(arch_local_save_flags()); } +static inline void arc_softirq_trigger(int irq) +{ + write_aux_reg(AUX_IRQ_HINT, irq); +} + +static inline void arc_softirq_clear(int irq) +{ + write_aux_reg(AUX_IRQ_HINT, 0); +} + #else .macro IRQ_DISABLE scratch diff --git a/arch/arc/kernel/entry-arcv2.S b/arch/arc/kernel/entry-arcv2.S index cbfec79137bf..c1264607bbff 100644 --- a/arch/arc/kernel/entry-arcv2.S +++ b/arch/arc/kernel/entry-arcv2.S @@ -45,11 +45,12 @@ VECTOR reserved ; Reserved slots VECTOR handle_interrupt ; (16) Timer0 VECTOR handle_interrupt ; unused (Timer1) VECTOR handle_interrupt ; unused (WDT) -VECTOR handle_interrupt ; (19) ICI (inter core interrupt) -VECTOR handle_interrupt -VECTOR handle_interrupt -VECTOR handle_interrupt -VECTOR handle_interrupt ; (23) End of fixed IRQs +VECTOR handle_interrupt ; (19) Inter core Interrupt (IPI) +VECTOR handle_interrupt ; (20) perf Interrupt +VECTOR handle_interrupt ; (21) Software Triggered Intr (Self IPI) +VECTOR handle_interrupt ; unused +VECTOR handle_interrupt ; (23) unused +# End of fixed IRQs .rept CONFIG_ARC_NUMBER_OF_INTERRUPTS - 8 VECTOR handle_interrupt @@ -211,7 +212,11 @@ debug_marker_syscall: ; (since IRQ NOT allowed in DS in ARCv2, this can only happen if orig ; entry was via Exception in DS which got preempted in kernel). ; -; IRQ RTIE won't reliably restore DE bit and/or BTA, needs handling +; IRQ RTIE won't reliably restore DE bit and/or BTA, needs workaround +; +; Solution is return from Intr w/o any delay slot quirks into a kernel trampoline +; and from pure kernel mode return to delay slot which handles DS bit/BTA correctly + .Lintr_ret_to_delay_slot: debug_marker_ds: @@ -222,18 +227,23 @@ debug_marker_ds: ld r2, [sp, PT_ret] ld r3, [sp, PT_status32] + ; STAT32 for Int return created from scratch + ; (No delay dlot, disable Further intr in trampoline) + bic r0, r3, STATUS_U_MASK|STATUS_DE_MASK|STATUS_IE_MASK|STATUS_L_MASK st r0, [sp, PT_status32] mov r1, .Lintr_ret_to_delay_slot_2 st r1, [sp, PT_ret] + ; Orig exception PC/STAT32 safekept @orig_r0 and @event stack slots st r2, [sp, 0] st r3, [sp, 4] b .Lisr_ret_fast_path .Lintr_ret_to_delay_slot_2: + ; Trampoline to restore orig exception PC/STAT32/BTA/AUX_USER_SP sub sp, sp, SZ_PT_REGS st r9, [sp, -4] @@ -243,11 +253,19 @@ debug_marker_ds: ld r9, [sp, 4] sr r9, [erstatus] + ; restore AUX_USER_SP if returning to U mode + bbit0 r9, STATUS_U_BIT, 1f + ld r9, [sp, PT_sp] + sr r9, [AUX_USER_SP] + +1: ld r9, [sp, 8] sr r9, [erbta] ld r9, [sp, -4] add sp, sp, SZ_PT_REGS + + ; return from pure kernel mode to delay slot rtie END(ret_from_exception) diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index bd237acdf4f2..30d806ce0c78 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -11,9 +11,12 @@ #include <linux/smp.h> #include <linux/irq.h> #include <linux/spinlock.h> +#include <asm/irqflags-arcv2.h> #include <asm/mcip.h> #include <asm/setup.h> +#define SOFTIRQ_IRQ 21 + static char smp_cpuinfo_buf[128]; static int idu_detected; @@ -22,6 +25,7 @@ static DEFINE_RAW_SPINLOCK(mcip_lock); static void mcip_setup_per_cpu(int cpu) { smp_ipi_irq_setup(cpu, IPI_IRQ); + smp_ipi_irq_setup(cpu, SOFTIRQ_IRQ); } static void mcip_ipi_send(int cpu) @@ -29,6 +33,12 @@ static void mcip_ipi_send(int cpu) unsigned long flags; int ipi_was_pending; + /* ARConnect can only send IPI to others */ + if (unlikely(cpu == raw_smp_processor_id())) { + arc_softirq_trigger(SOFTIRQ_IRQ); + return; + } + /* * NOTE: We must spin here if the other cpu hasn't yet * serviced a previous message. This can burn lots @@ -63,6 +73,11 @@ static void mcip_ipi_clear(int irq) unsigned long flags; unsigned int __maybe_unused copy; + if (unlikely(irq == SOFTIRQ_IRQ)) { + arc_softirq_clear(irq); + return; + } + raw_spin_lock_irqsave(&mcip_lock, flags); /* Who sent the IPI */ diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 863f2cd9096a..83082a5790d8 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -641,6 +641,7 @@ config ARCH_QCOM select CLKDEV_LOOKUP select GENERIC_CLOCKEVENTS select GENERIC_ALLOCATOR + select ARM_GIC select ARM_PATCH_PHYS_VIRT select ARM_HAS_SG_CHAIN select ARCH_HAS_OPP diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index b87d5d924238..815018770fb9 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -173,10 +173,9 @@ choice mobile SoCs in the Kona family of chips (e.g. bcm28155, bcm11351, etc...) - config DEBUG_BCM63XX + config DEBUG_BCM63XX_UART bool "Kernel low-level debugging on BCM63XX UART" depends on ARCH_BCM_63XX - select DEBUG_UART_BCM63XX config DEBUG_BERLIN_UART bool "Marvell Berlin SoC Debug UART" @@ -1359,7 +1358,7 @@ config DEBUG_LL_INCLUDE default "debug/vf.S" if DEBUG_VF_UART default "debug/vt8500.S" if DEBUG_VT8500_UART0 default "debug/zynq.S" if DEBUG_ZYNQ_UART0 || DEBUG_ZYNQ_UART1 - default "debug/bcm63xx.S" if DEBUG_UART_BCM63XX + default "debug/bcm63xx.S" if DEBUG_BCM63XX_UART default "debug/digicolor.S" if DEBUG_DIGICOLOR_UA0 default "mach/debug-macro.S" @@ -1375,10 +1374,6 @@ config DEBUG_UART_8250 ARCH_IOP33X || ARCH_IXP4XX || \ ARCH_LPC32XX || ARCH_MV78XX0 || ARCH_ORION5X || ARCH_RPC -# Compatibility options for BCM63xx -config DEBUG_UART_BCM63XX - def_bool ARCH_BCM_63XX - config DEBUG_UART_PHYS hex "Physical base address of debug UART" default 0x00100a00 if DEBUG_NETX_UART @@ -1473,7 +1468,7 @@ config DEBUG_UART_PHYS default 0xfffb0000 if DEBUG_OMAP1UART1 || DEBUG_OMAP7XXUART1 default 0xfffb0800 if DEBUG_OMAP1UART2 || DEBUG_OMAP7XXUART2 default 0xfffb9800 if DEBUG_OMAP1UART3 || DEBUG_OMAP7XXUART3 - default 0xfffe8600 if DEBUG_UART_BCM63XX + default 0xfffe8600 if DEBUG_BCM63XX_UART default 0xfffff700 if ARCH_IOP33X depends on ARCH_EP93XX || \ DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \ @@ -1485,7 +1480,7 @@ config DEBUG_UART_PHYS DEBUG_RCAR_GEN2_SCIF0 || DEBUG_RCAR_GEN2_SCIF2 || \ DEBUG_RMOBILE_SCIFA0 || DEBUG_RMOBILE_SCIFA1 || \ DEBUG_RMOBILE_SCIFA4 || DEBUG_S3C24XX_UART || \ - DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART || \ + DEBUG_BCM63XX_UART || DEBUG_ASM9260_UART || \ DEBUG_SIRFSOC_UART || DEBUG_DIGICOLOR_UA0 || \ DEBUG_AT91_UART @@ -1526,7 +1521,7 @@ config DEBUG_UART_VIRT default 0xfb10c000 if DEBUG_REALVIEW_PB1176_PORT default 0xfc40ab00 if DEBUG_BRCMSTB_UART default 0xfc705000 if DEBUG_ZTE_ZX - default 0xfcfe8600 if DEBUG_UART_BCM63XX + default 0xfcfe8600 if DEBUG_BCM63XX_UART default 0xfd000000 if ARCH_SPEAR3XX || ARCH_SPEAR6XX default 0xfd000000 if ARCH_SPEAR13XX default 0xfd012000 if ARCH_MV78XX0 @@ -1577,7 +1572,7 @@ config DEBUG_UART_VIRT DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \ DEBUG_NETX_UART || \ DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART || \ - DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART || \ + DEBUG_BCM63XX_UART || DEBUG_ASM9260_UART || \ DEBUG_SIRFSOC_UART || DEBUG_DIGICOLOR_UA0 config DEBUG_UART_8250_SHIFT diff --git a/arch/arm/boot/dts/armada-xp-axpwifiap.dts b/arch/arm/boot/dts/armada-xp-axpwifiap.dts index 23fc670c0427..5c21b236721f 100644 --- a/arch/arm/boot/dts/armada-xp-axpwifiap.dts +++ b/arch/arm/boot/dts/armada-xp-axpwifiap.dts @@ -70,8 +70,8 @@ soc { ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000 MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000 - MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000 - MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>; + MBUS_ID(0x09, 0x09) 0 0 0xf1100000 0x10000 + MBUS_ID(0x09, 0x05) 0 0 0xf1110000 0x10000>; pcie-controller { status = "okay"; diff --git a/arch/arm/boot/dts/armada-xp-db.dts b/arch/arm/boot/dts/armada-xp-db.dts index f774101416a5..ebe1d267406d 100644 --- a/arch/arm/boot/dts/armada-xp-db.dts +++ b/arch/arm/boot/dts/armada-xp-db.dts @@ -76,8 +76,8 @@ ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000 MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000 MBUS_ID(0x01, 0x2f) 0 0 0xf0000000 0x1000000 - MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000 - MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>; + MBUS_ID(0x09, 0x09) 0 0 0xf1100000 0x10000 + MBUS_ID(0x09, 0x05) 0 0 0xf1110000 0x10000>; devbus-bootcs { status = "okay"; diff --git a/arch/arm/boot/dts/armada-xp-gp.dts b/arch/arm/boot/dts/armada-xp-gp.dts index 4878d7353069..5730b875c4f5 100644 --- a/arch/arm/boot/dts/armada-xp-gp.dts +++ b/arch/arm/boot/dts/armada-xp-gp.dts @@ -95,8 +95,8 @@ ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000 MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000 MBUS_ID(0x01, 0x2f) 0 0 0xf0000000 0x1000000 - MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000 - MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>; + MBUS_ID(0x09, 0x09) 0 0 0xf1100000 0x10000 + MBUS_ID(0x09, 0x05) 0 0 0xf1110000 0x10000>; devbus-bootcs { status = "okay"; diff --git a/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts b/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts index 58b500873bfd..d960fef77ca1 100644 --- a/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts +++ b/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts @@ -65,8 +65,8 @@ soc { ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xd0000000 0x100000 MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000 - MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000 - MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>; + MBUS_ID(0x09, 0x09) 0 0 0xf1100000 0x10000 + MBUS_ID(0x09, 0x05) 0 0 0xf1110000 0x10000>; pcie-controller { status = "okay"; diff --git a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts index 6e9820e141f8..b89e6cf1271a 100644 --- a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts +++ b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts @@ -70,8 +70,8 @@ soc { ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000 MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000 - MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000 - MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>; + MBUS_ID(0x09, 0x09) 0 0 0xf1100000 0x10000 + MBUS_ID(0x09, 0x05) 0 0 0xf1110000 0x10000>; pcie-controller { status = "okay"; diff --git a/arch/arm/boot/dts/armada-xp-matrix.dts b/arch/arm/boot/dts/armada-xp-matrix.dts index 6ab33837a2b6..6522b04f4a8e 100644 --- a/arch/arm/boot/dts/armada-xp-matrix.dts +++ b/arch/arm/boot/dts/armada-xp-matrix.dts @@ -68,8 +68,8 @@ soc { ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000 MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000 - MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000 - MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>; + MBUS_ID(0x09, 0x09) 0 0 0xf1100000 0x10000 + MBUS_ID(0x09, 0x05) 0 0 0xf1110000 0x10000>; internal-regs { serial@12000 { diff --git a/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts b/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts index 6fe8972de0a2..db54c7158a36 100644 --- a/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts +++ b/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts @@ -64,8 +64,8 @@ soc { ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xd0000000 0x100000 MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000 - MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000 - MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>; + MBUS_ID(0x09, 0x09) 0 0 0xf1100000 0x10000 + MBUS_ID(0x09, 0x05) 0 0 0xf1110000 0x10000>; pcie-controller { status = "okay"; diff --git a/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts b/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts index a5db17782e08..853bd392a4fe 100644 --- a/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts +++ b/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts @@ -65,9 +65,9 @@ soc { ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xd0000000 0x100000 MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000 - MBUS_ID(0x01, 0x2f) 0 0 0xf0000000 0x8000000 - MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000 - MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>; + MBUS_ID(0x01, 0x2f) 0 0 0xe8000000 0x8000000 + MBUS_ID(0x09, 0x09) 0 0 0xf1100000 0x10000 + MBUS_ID(0x09, 0x05) 0 0 0xf1110000 0x10000>; devbus-bootcs { status = "okay"; diff --git a/arch/arm/boot/dts/armada-xp-synology-ds414.dts b/arch/arm/boot/dts/armada-xp-synology-ds414.dts index 2391b11dc546..d17dab0a6f51 100644 --- a/arch/arm/boot/dts/armada-xp-synology-ds414.dts +++ b/arch/arm/boot/dts/armada-xp-synology-ds414.dts @@ -78,8 +78,8 @@ soc { ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000 MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000 - MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000 - MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>; + MBUS_ID(0x09, 0x09) 0 0 0xf1100000 0x10000 + MBUS_ID(0x09, 0x05) 0 0 0xf1110000 0x10000>; pcie-controller { status = "okay"; diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi index fe99231cbde5..c2a03c740e79 100644 --- a/arch/arm/boot/dts/dra7.dtsi +++ b/arch/arm/boot/dts/dra7.dtsi @@ -1497,6 +1497,16 @@ 0x48485200 0x2E00>; #address-cells = <1>; #size-cells = <1>; + + /* + * Do not allow gating of cpsw clock as workaround + * for errata i877. Keeping internal clock disabled + * causes the device switching characteristics + * to degrade over time and eventually fail to meet + * the data manual delay time/skew specs. + */ + ti,no-idle; + /* * rx_thresh_pend * rx_pend diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index dd955be6c908..a42019b58897 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -116,7 +116,8 @@ dtb-$(CONFIG_ARCH_MSMCOBALT) += msmcobalt-sim.dtb \ dtb-$(CONFIG_ARCH_MSMHAMSTER) += msmhamster-rumi.dtb -dtb-$(CONFIG_ARCH_MSMFALCON) += msmfalcon-sim.dtb +dtb-$(CONFIG_ARCH_MSMFALCON) += msmfalcon-sim.dtb \ + msmfalcon-rumi.dtb ifeq ($(CONFIG_ARM64),y) always := $(dtb-y) diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi new file mode 100644 index 000000000000..28b0d6d9cf14 --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi @@ -0,0 +1,225 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&mdss_mdp { + dsi_dual_nt35597_truly_cmd: qcom,mdss_dsi_nt35597_truly_wqxga_cmd{ + qcom,mdss-dsi-panel-name = + "Dual nt35597 cmd mode dsi truly panel without DSC"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = [cd 32 22 00 60 64 26 34 29 03 + 04 00]; + qcom,adjust-timer-wakeup-ms = <1>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,ulps-enabled; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 10 00 02 FF 20 + 15 01 00 00 10 00 02 fb 01 + 15 01 00 00 10 00 02 00 01 + 15 01 00 00 10 00 02 01 55 + 15 01 00 00 10 00 02 02 45 + 15 01 00 00 10 00 02 05 40 + 15 01 00 00 10 00 02 06 19 + 15 01 00 00 10 00 02 07 1E + 15 01 00 00 10 00 02 0B 73 + 15 01 00 00 10 00 02 0C 73 + 15 01 00 00 10 00 02 0E B0 + 15 01 00 00 10 00 02 0F AE + 15 01 00 00 10 00 02 11 B8 + 15 01 00 00 10 00 02 13 00 + 15 01 00 00 10 00 02 58 80 + 15 01 00 00 10 00 02 59 01 + 15 01 00 00 10 00 02 5A 00 + 15 01 00 00 10 00 02 5B 01 + 15 01 00 00 10 00 02 5C 80 + 15 01 00 00 10 00 02 5D 81 + 15 01 00 00 10 00 02 5E 00 + 15 01 00 00 10 00 02 5F 01 + 15 01 00 00 10 00 02 72 31 + 15 01 00 00 10 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 10 00 02 ff 24 + 15 01 00 00 10 00 02 fb 01 + 15 01 00 00 10 00 02 00 1C + 15 01 00 00 10 00 02 01 0B + 15 01 00 00 10 00 02 02 0C + 15 01 00 00 10 00 02 03 01 + 15 01 00 00 10 00 02 04 0F + 15 01 00 00 10 00 02 05 10 + 15 01 00 00 10 00 02 06 10 + 15 01 00 00 10 00 02 07 10 + 15 01 00 00 10 00 02 08 89 + 15 01 00 00 10 00 02 09 8A + 15 01 00 00 10 00 02 0A 13 + 15 01 00 00 10 00 02 0B 13 + 15 01 00 00 10 00 02 0C 15 + 15 01 00 00 10 00 02 0D 15 + 15 01 00 00 10 00 02 0E 17 + 15 01 00 00 10 00 02 0F 17 + 15 01 00 00 10 00 02 10 1C + 15 01 00 00 10 00 02 11 0B + 15 01 00 00 10 00 02 12 0C + 15 01 00 00 10 00 02 13 01 + 15 01 00 00 10 00 02 14 0F + 15 01 00 00 10 00 02 15 10 + 15 01 00 00 10 00 02 16 10 + 15 01 00 00 10 00 02 17 10 + 15 01 00 00 10 00 02 18 89 + 15 01 00 00 10 00 02 19 8A + 15 01 00 00 10 00 02 1A 13 + 15 01 00 00 10 00 02 1B 13 + 15 01 00 00 10 00 02 1C 15 + 15 01 00 00 10 00 02 1D 15 + 15 01 00 00 10 00 02 1E 17 + 15 01 00 00 10 00 02 1F 17 + /* STV */ + 15 01 00 00 10 00 02 20 40 + 15 01 00 00 10 00 02 21 01 + 15 01 00 00 10 00 02 22 00 + 15 01 00 00 10 00 02 23 40 + 15 01 00 00 10 00 02 24 40 + 15 01 00 00 10 00 02 25 6D + 15 01 00 00 10 00 02 26 40 + 15 01 00 00 10 00 02 27 40 + /* Vend */ + 15 01 00 00 10 00 02 E0 00 + 15 01 00 00 10 00 02 DC 21 + 15 01 00 00 10 00 02 DD 22 + 15 01 00 00 10 00 02 DE 07 + 15 01 00 00 10 00 02 DF 07 + 15 01 00 00 10 00 02 E3 6D + 15 01 00 00 10 00 02 E1 07 + 15 01 00 00 10 00 02 E2 07 + /* UD */ + 15 01 00 00 10 00 02 29 D8 + 15 01 00 00 10 00 02 2A 2A + /* CLK */ + 15 01 00 00 10 00 02 4B 03 + 15 01 00 00 10 00 02 4C 11 + 15 01 00 00 10 00 02 4D 10 + 15 01 00 00 10 00 02 4E 01 + 15 01 00 00 10 00 02 4F 01 + 15 01 00 00 10 00 02 50 10 + 15 01 00 00 10 00 02 51 00 + 15 01 00 00 10 00 02 52 80 + 15 01 00 00 10 00 02 53 00 + 15 01 00 00 10 00 02 56 00 + 15 01 00 00 10 00 02 54 07 + 15 01 00 00 10 00 02 58 07 + 15 01 00 00 10 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 10 00 02 5B 43 + 15 01 00 00 10 00 02 5C 00 + 15 01 00 00 10 00 02 5F 73 + 15 01 00 00 10 00 02 60 73 + 15 01 00 00 10 00 02 63 22 + 15 01 00 00 10 00 02 64 00 + 15 01 00 00 10 00 02 67 08 + 15 01 00 00 10 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 10 00 02 72 02 + /* mux */ + 15 01 00 00 10 00 02 7A 80 + 15 01 00 00 10 00 02 7B 91 + 15 01 00 00 10 00 02 7C D8 + 15 01 00 00 10 00 02 7D 60 + 15 01 00 00 10 00 02 7F 15 + 15 01 00 00 10 00 02 75 15 + /* ABOFF */ + 15 01 00 00 10 00 02 B3 C0 + 15 01 00 00 10 00 02 B4 00 + 15 01 00 00 10 00 02 B5 00 + /* Source EQ */ + 15 01 00 00 10 00 02 78 00 + 15 01 00 00 10 00 02 79 00 + 15 01 00 00 10 00 02 80 00 + 15 01 00 00 10 00 02 83 00 + /* FP BP */ + 15 01 00 00 10 00 02 93 0A + 15 01 00 00 10 00 02 94 0A + /* Inversion Type */ + 15 01 00 00 10 00 02 8A 00 + 15 01 00 00 10 00 02 9B FF + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 10 00 02 9D B0 + 15 01 00 00 10 00 02 9F 63 + 15 01 00 00 10 00 02 98 10 + /* FRM */ + 15 01 00 00 10 00 02 EC 00 + /* CMD1 */ + 15 01 00 00 10 00 02 ff 10 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 10 00 04 3B 03 0A 0A + /* FTE on */ + 15 01 00 00 10 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 10 00 02 E5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 10 00 02 BB 10 + /* Non Reload MTP */ + 15 01 00 00 10 00 02 FB 01 + /* SlpOut + DispOn */ + 05 01 00 00 a0 00 02 11 00 + 05 01 00 00 a0 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,config-select = <&dsi_dual_nt35597_truly_cmd_config0>; + + dsi_dual_nt35597_truly_cmd_config0: config0 { + qcom,split-mode = "dualctl-split"; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi new file mode 100644 index 000000000000..d125a5783f9e --- /dev/null +++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi @@ -0,0 +1,213 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&mdss_mdp { + dsi_dual_nt35597_truly_video: qcom,mdss_dsi_nt35597_wqxga_video_truly { + qcom,mdss-dsi-panel-name = + "Dual nt35597 video mode dsi truly panel without DSC"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <720>; + qcom,mdss-dsi-panel-height = <2560>; + qcom,mdss-dsi-h-front-porch = <100>; + qcom,mdss-dsi-h-back-porch = <32>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <7>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-on-command = [ + /* CMD2_P0 */ + 15 01 00 00 10 00 02 FF 20 + 15 01 00 00 10 00 02 FB 01 + 15 01 00 00 10 00 02 00 01 + 15 01 00 00 10 00 02 01 55 + 15 01 00 00 10 00 02 02 45 + 15 01 00 00 10 00 02 05 40 + 15 01 00 00 10 00 02 06 19 + 15 01 00 00 10 00 02 07 1E + 15 01 00 00 10 00 02 0B 73 + 15 01 00 00 10 00 02 0C 73 + 15 01 00 00 10 00 02 0E B0 + 15 01 00 00 10 00 02 0F AE + 15 01 00 00 10 00 02 11 B8 + 15 01 00 00 10 00 02 13 00 + 15 01 00 00 10 00 02 58 80 + 15 01 00 00 10 00 02 59 01 + 15 01 00 00 10 00 02 5A 00 + 15 01 00 00 10 00 02 5B 01 + 15 01 00 00 10 00 02 5C 80 + 15 01 00 00 10 00 02 5D 81 + 15 01 00 00 10 00 02 5E 00 + 15 01 00 00 10 00 02 5F 01 + 15 01 00 00 10 00 02 72 31 + 15 01 00 00 10 00 02 68 03 + /* CMD2_P4 */ + 15 01 00 00 10 00 02 FF 24 + 15 01 00 00 10 00 02 FB 01 + 15 01 00 00 10 00 02 00 1C + 15 01 00 00 10 00 02 01 0B + 15 01 00 00 10 00 02 02 0C + 15 01 00 00 10 00 02 03 01 + 15 01 00 00 10 00 02 04 0F + 15 01 00 00 10 00 02 05 10 + 15 01 00 00 10 00 02 06 10 + 15 01 00 00 10 00 02 07 10 + 15 01 00 00 10 00 02 08 89 + 15 01 00 00 10 00 02 09 8A + 15 01 00 00 10 00 02 0A 13 + 15 01 00 00 10 00 02 0B 13 + 15 01 00 00 10 00 02 0C 15 + 15 01 00 00 10 00 02 0D 15 + 15 01 00 00 10 00 02 0E 17 + 15 01 00 00 10 00 02 0F 17 + 15 01 00 00 10 00 02 10 1C + 15 01 00 00 10 00 02 11 0B + 15 01 00 00 10 00 02 12 0C + 15 01 00 00 10 00 02 13 01 + 15 01 00 00 10 00 02 14 0F + 15 01 00 00 10 00 02 15 10 + 15 01 00 00 10 00 02 16 10 + 15 01 00 00 10 00 02 17 10 + 15 01 00 00 10 00 02 18 89 + 15 01 00 00 10 00 02 19 8A + 15 01 00 00 10 00 02 1A 13 + 15 01 00 00 10 00 02 1B 13 + 15 01 00 00 10 00 02 1C 15 + 15 01 00 00 10 00 02 1D 15 + 15 01 00 00 10 00 02 1E 17 + 15 01 00 00 10 00 02 1F 17 + /* STV */ + 15 01 00 00 10 00 02 20 40 + 15 01 00 00 10 00 02 21 01 + 15 01 00 00 10 00 02 22 00 + 15 01 00 00 10 00 02 23 40 + 15 01 00 00 10 00 02 24 40 + 15 01 00 00 10 00 02 25 6D + 15 01 00 00 10 00 02 26 40 + 15 01 00 00 10 00 02 27 40 + /* Vend */ + 15 01 00 00 10 00 02 E0 00 + 15 01 00 00 10 00 02 DC 21 + 15 01 00 00 10 00 02 DD 22 + 15 01 00 00 10 00 02 DE 07 + 15 01 00 00 10 00 02 DF 07 + 15 01 00 00 10 00 02 E3 6D + 15 01 00 00 10 00 02 E1 07 + 15 01 00 00 10 00 02 E2 07 + /* UD */ + 15 01 00 00 10 00 02 29 D8 + 15 01 00 00 10 00 02 2A 2A + /* CLK */ + 15 01 00 00 10 00 02 4B 03 + 15 01 00 00 10 00 02 4C 11 + 15 01 00 00 10 00 02 4D 10 + 15 01 00 00 10 00 02 4E 01 + 15 01 00 00 10 00 02 4F 01 + 15 01 00 00 10 00 02 50 10 + 15 01 00 00 10 00 02 51 00 + 15 01 00 00 10 00 02 52 80 + 15 01 00 00 10 00 02 53 00 + 15 01 00 00 10 00 02 56 00 + 15 01 00 00 10 00 02 54 07 + 15 01 00 00 10 00 02 58 07 + 15 01 00 00 10 00 02 55 25 + /* Reset XDONB */ + 15 01 00 00 10 00 02 5B 43 + 15 01 00 00 10 00 02 5C 00 + 15 01 00 00 10 00 02 5F 73 + 15 01 00 00 10 00 02 60 73 + 15 01 00 00 10 00 02 63 22 + 15 01 00 00 10 00 02 64 00 + 15 01 00 00 10 00 02 67 08 + 15 01 00 00 10 00 02 68 04 + /* Resolution:1440x2560*/ + 15 01 00 00 10 00 02 72 02 + /* mux */ + 15 01 00 00 10 00 02 7A 80 + 15 01 00 00 10 00 02 7B 91 + 15 01 00 00 10 00 02 7C D8 + 15 01 00 00 10 00 02 7D 60 + 15 01 00 00 10 00 02 7F 15 + 15 01 00 00 10 00 02 75 15 + /* ABOFF */ + 15 01 00 00 10 00 02 B3 C0 + 15 01 00 00 10 00 02 B4 00 + 15 01 00 00 10 00 02 B5 00 + /* Source EQ */ + 15 01 00 00 10 00 02 78 00 + 15 01 00 00 10 00 02 79 00 + 15 01 00 00 10 00 02 80 00 + 15 01 00 00 10 00 02 83 00 + /* FP BP */ + 15 01 00 00 10 00 02 93 0A + 15 01 00 00 10 00 02 94 0A + /* Inversion Type */ + 15 01 00 00 10 00 02 8A 00 + 15 01 00 00 10 00 02 9B FF + /* IMGSWAP =1 @PortSwap=1 */ + 15 01 00 00 10 00 02 9D B0 + 15 01 00 00 10 00 02 9F 63 + 15 01 00 00 10 00 02 98 10 + /* FRM */ + 15 01 00 00 10 00 02 EC 00 + /* CMD1 */ + 15 01 00 00 10 00 02 FF 10 + /* VBP+VSA=,VFP = 10H */ + 15 01 00 00 10 00 04 3B 03 0A 0A + /* FTE on */ + 15 01 00 00 10 00 02 35 00 + /* EN_BK =1(auto black) */ + 15 01 00 00 10 00 02 E5 01 + /* CMD mode(10) VDO mode(03) */ + 15 01 00 00 10 00 02 BB 03 + /* Non Reload MTP */ + 15 01 00 00 10 00 02 FB 01 + /* SlpOut + DispOn */ + 05 01 00 00 a0 00 02 11 00 + 05 01 00 00 a0 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [05 01 00 00 78 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,cmd-sync-wait-broadcast; + qcom,mdss-dsi-panel-timings = [e2 36 24 00 66 6a 28 38 2a 03 + 04 00]; + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 50>; + + qcom,config-select = <&dsi_dual_nt35597_truly_video_config0>; + + dsi_dual_nt35597_truly_video_config0: config0 { + qcom,split-mode = "dualctl-split"; + }; + + + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm-arm-smmu-cobalt.dtsi b/arch/arm/boot/dts/qcom/msm-arm-smmu-cobalt.dtsi index 41af9b66d3c9..ab46221089f3 100644 --- a/arch/arm/boot/dts/qcom/msm-arm-smmu-cobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msm-arm-smmu-cobalt.dtsi @@ -23,16 +23,16 @@ qcom,register-save; qcom,skip-init; #global-interrupts = <2>; - interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 231 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 364 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 365 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 366 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 367 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 368 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 369 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 370 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 431 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <GIC_SPI 229 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 231 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 364 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 365 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 366 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 367 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 368 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 369 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 370 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 431 IRQ_TYPE_EDGE_RISING>; clocks = <&clock_gcc clk_aggre1_noc_clk>; clock-names = "smmu_aggre1_noc_clk"; #clock-cells = <1>; @@ -46,28 +46,28 @@ qcom,register-save; qcom,skip-init; #global-interrupts = <2>; - interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 231 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 373 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 374 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 375 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 376 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 377 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 378 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 462 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 463 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 464 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 465 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 466 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 467 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 359 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <GIC_SPI 229 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 231 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 373 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 374 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 375 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 376 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 377 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 378 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 462 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 463 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 464 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 465 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 466 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 467 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 353 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 354 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 355 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 356 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 357 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 358 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 359 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 360 IRQ_TYPE_EDGE_RISING>; clocks = <&clock_gcc clk_aggre2_noc_clk>; clock-names = "smmu_aggre2_noc_clk"; #clock-cells = <1>; @@ -113,6 +113,7 @@ reg = <0xcd00000 0x40000>; #iommu-cells = <1>; qcom,register-save; + qcom,no-smr-check; qcom,skip-init; #global-interrupts = <2>; interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>, @@ -164,14 +165,14 @@ qcom,register-save; qcom,skip-init; #global-interrupts = <2>; - interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 231 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 329 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 332 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>; + interrupts = <GIC_SPI 229 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 231 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 329 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 330 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 331 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 332 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 116 IRQ_TYPE_EDGE_RISING>, + <GIC_SPI 117 IRQ_TYPE_EDGE_RISING>; vdd-supply = <&gdsc_gpu_cx>; clocks = <&clock_gcc clk_gcc_gpu_cfg_ahb_clk>, <&clock_gcc clk_gcc_bimc_gfx_clk>, diff --git a/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi index ab6b614471e5..6729899379c5 100644 --- a/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi +++ b/arch/arm/boot/dts/qcom/msm-audio-lpass.dtsi @@ -51,7 +51,6 @@ voice: qcom,msm-pcm-voice { compatible = "qcom,msm-pcm-voice"; qcom,destroy-cvd; - qcom,vote-bms; }; stub_codec: qcom,msm-stub-codec { diff --git a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi index b612ec3f42b5..fad834199be5 100644 --- a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi @@ -383,7 +383,6 @@ qcom,supported-sizes = <6>, <9>; qcom,ramp-index = <2>; #pwm-cells = <2>; - status = "disabled"; }; pmicobalt_pwm_4: pwm@b400 { @@ -396,7 +395,6 @@ qcom,supported-sizes = <6>, <9>; qcom,ramp-index = <3>; #pwm-cells = <2>; - status = "disabled"; }; pmicobalt_pwm_5: pwm@b500 { @@ -409,7 +407,6 @@ qcom,supported-sizes = <6>, <9>; qcom,ramp-index = <4>; #pwm-cells = <2>; - status = "disabled"; }; pmicobalt_pwm_6: pwm@b600 { @@ -425,6 +422,50 @@ status = "disabled"; }; + qcom,leds@d000 { + compatible = "qcom,leds-qpnp"; + reg = <0xd000 0x100>; + label = "rgb"; + status = "okay"; + + red_led: qcom,rgb_0 { + label = "rgb"; + qcom,id = <3>; + qcom,mode = "pwm"; + pwms = <&pmicobalt_pwm_5 0 0>; + qcom,pwm-us = <1000>; + qcom,max-current = <12>; + qcom,default-state = "off"; + linux,name = "red"; + linux,default-trigger = + "battery-charging"; + }; + + green_led: qcom,rgb_1 { + label = "rgb"; + qcom,id = <4>; + qcom,mode = "pwm"; + pwms = <&pmicobalt_pwm_4 0 0>; + qcom,pwm-us = <1000>; + qcom,max-current = <12>; + qcom,default-state = "off"; + linux,name = "green"; + linux,default-trigger = "battery-full"; + }; + + blue_led: qcom,rgb_2 { + label = "rgb"; + qcom,id = <5>; + qcom,mode = "pwm"; + pwms = <&pmicobalt_pwm_3 0 0>; + qcom,pwm-us = <1000>; + qcom,max-current = <12>; + qcom,default-state = "off"; + linux,name = "blue"; + linux,default-trigger = "boot-indication"; + }; + }; + labibb: qpnp-labibb-regulator { compatible = "qcom,qpnp-labibb-regulator"; #address-cells = <1>; @@ -565,9 +606,9 @@ label = "flash"; qcom,led-name = "led:flash_0"; qcom,max-current = <1500>; - qcom,default-led-trigger = - "flash0_trigger"; + qcom,default-led-trigger = "flash0_trigger"; qcom,id = <0>; + qcom,current-ma = <1000>; qcom,duration-ms = <1280>; qcom,ires-ua = <12500>; qcom,hdrm-voltage-mv = <325>; @@ -578,9 +619,9 @@ label = "flash"; qcom,led-name = "led:flash_1"; qcom,max-current = <1500>; - qcom,default-led-trigger = - "flash1_trigger"; + qcom,default-led-trigger = "flash1_trigger"; qcom,id = <1>; + qcom,current-ma = <1000>; qcom,duration-ms = <1280>; qcom,ires-ua = <12500>; qcom,hdrm-voltage-mv = <325>; @@ -591,9 +632,9 @@ label = "flash"; qcom,led-name = "led:flash_2"; qcom,max-current = <750>; - qcom,default-led-trigger = - "flash2_trigger"; + qcom,default-led-trigger = "flash2_trigger"; qcom,id = <2>; + qcom,current-ma = <500>; qcom,duration-ms = <1280>; qcom,ires-ua = <12500>; qcom,hdrm-voltage-mv = <325>; @@ -603,11 +644,65 @@ pinctrl-1 = <&led_disable>; }; - pmicobalt_switch: qcom,led_switch { + pmicobalt_torch0: qcom,torch_0 { + label = "torch"; + qcom,led-name = "led:torch_0"; + qcom,max-current = <500>; + qcom,default-led-trigger = "torch0_trigger"; + qcom,id = <0>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pmicobalt_torch1: qcom,torch_1 { + label = "torch"; + qcom,led-name = "led:torch_1"; + qcom,max-current = <500>; + qcom,default-led-trigger = "torch1_trigger"; + qcom,id = <1>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pmicobalt_torch2: qcom,torch_2 { + label = "torch"; + qcom,led-name = "led:torch_2"; + qcom,max-current = <500>; + qcom,default-led-trigger = "torch2_trigger"; + qcom,id = <2>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + pinctrl-names = "led_enable","led_disable"; + pinctrl-0 = <&led_enable>; + pinctrl-1 = <&led_disable>; + }; + + pmicobalt_switch0: qcom,led_switch_0 { + label = "switch"; + qcom,led-name = "led:switch_0"; + qcom,led-mask = <3>; + qcom,default-led-trigger = "switch0_trigger"; + reg0 { + regulator-name = "pmicobalt_bob"; + max-voltage-uv = <3600000>; + }; + }; + + pmicobalt_switch1: qcom,led_switch_1 { label = "switch"; - qcom,led-name = "led:switch"; - qcom,default-led-trigger = - "switch_trigger"; + qcom,led-name = "led:switch_1"; + qcom,led-mask = <4>; + qcom,default-led-trigger = "switch1_trigger"; + reg0 { + regulator-name = "pmicobalt_bob"; + max-voltage-uv = <3600000>; + }; }; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi index d81cc3dd14d8..2da89bd9ac6e 100644 --- a/arch/arm/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996.dtsi @@ -42,7 +42,7 @@ chosen { stdout-path = "serial0"; - bootargs = "sched_enable_hmp=1 sched_enable_power_aware=1"; + bootargs = "sched_enable_hmp=1 sched_enable_power_aware=1 rcupdate.rcu_expedited=1"; }; psci { diff --git a/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi index ae878c7f5bac..1ef5e6351aa6 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi @@ -30,6 +30,7 @@ sound-9335 { compatible = "qcom,msmcobalt-asoc-snd-tasha"; qcom,model = "msmcobalt-tasha-snd-card"; + qcom,hdmi-audio-rx; qcom,audio-routing = "AIF4 VI", "MCLK", @@ -98,8 +99,9 @@ "msm-dai-q6-dev.16396", "msm-dai-q6-dev.16398", "msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401", "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673"; - asoc-codec = <&stub_codec>; - asoc-codec-names = "msm-stub-codec.1"; + asoc-codec = <&stub_codec>, <&hdmi_audio>; + asoc-codec-names = "msm-stub-codec.1", + "msm-hdmi-audio-codec-rx"; qcom,wsa-max-devs = <2>; qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>, <&wsa881x_213>, <&wsa881x_214>; @@ -107,6 +109,78 @@ "SpkrLeft", "SpkrRight"; }; + sound-tavil { + compatible = "qcom,msmcobalt-asoc-snd-tavil"; + qcom,model = "msmcobalt-tavil-snd-card"; + + qcom,audio-routing = + "RX_BIAS", "MCLK", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "AMIC3", "MIC BIAS2", + "MIC BIAS2", "ANCRight Headset Mic", + "AMIC4", "MIC BIAS2", + "MIC BIAS2", "ANCLeft Headset Mic", + "AMIC5", "MIC BIAS3", + "MIC BIAS3", "Handset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; + qcom,tavil-mclk-clk-freq = <9600000>; + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>; + 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-cpe-lsm", + "msm-compr-dsp"; + asoc-cpu = <&dai_hdmi>, + <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, + <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>, + <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>, + <&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>, <&sb_5_rx>, + <&usb_audio_rx>, <&usb_audio_tx>; + asoc-cpu-names = "msm-dai-q6-hdmi.8", + "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", + "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", + "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389", + "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", + "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", + "msm-dai-q6-dev.16395", "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.16394", + "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673"; + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, + <&wsa881x_0213>, <&wsa881x_0214>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; + }; + cpe: qcom,msm-cpe-lsm { compatible = "qcom,msm-cpe-lsm"; }; @@ -139,6 +213,15 @@ #clock-cells = <1>; }; + clock_audio_lnbb: audio_ext_clk_lnbb { + status = "ok"; + compatible = "qcom,audio-ref-clk"; + clock-names = "osr_clk"; + clocks = <&clock_gcc clk_ln_bb_clk2>; + qcom,node_has_rpm_clock; + #clock-cells = <1>; + }; + wcd_rst_gpio: msm_cdc_pinctrl@64 { compatible = "qcom,msm-cdc-pinctrl"; qcom,cdc-rst-n-gpio = <&tlmm 64 0>; @@ -206,4 +289,56 @@ qcom,cdc-dmic-sample-rate = <4800000>; qcom,cdc-mad-dmic-rate = <600000>; }; + + tavil_codec { + compatible = "qcom,tavil-slim-pgd"; + elemental-addr = [00 01 50 02 17 02]; + + interrupt-parent = <&wcd9xxx_intc>; + interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 25 26 27 28 29 + 30 31>; + + qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>; + + clock-names = "wcd_clk"; + clocks = <&clock_audio_lnbb clk_audio_pmi_lnbb_clk>; + + cdc-vdd-buck-supply = <&pmcobalt_s4>; + qcom,cdc-vdd-buck-voltage = <1800000 1800000>; + qcom,cdc-vdd-buck-current = <650000>; + + cdc-buck-sido-supply = <&pmcobalt_s4>; + qcom,cdc-buck-sido-voltage = <1800000 1800000>; + qcom,cdc-buck-sido-current = <250000>; + + cdc-vdd-tx-h-supply = <&pmcobalt_s4>; + qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>; + qcom,cdc-vdd-tx-h-current = <25000>; + + cdc-vdd-rx-h-supply = <&pmcobalt_s4>; + qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>; + qcom,cdc-vdd-rx-h-current = <25000>; + + cdc-vddpx-1-supply = <&pmcobalt_s4>; + qcom,cdc-vddpx-1-voltage = <1800000 1800000>; + qcom,cdc-vddpx-1-current = <10000>; + + qcom,cdc-static-supplies = "cdc-vdd-buck", + "cdc-buck-sido", + "cdc-vdd-tx-h", + "cdc-vdd-rx-h", + "cdc-vddpx-1"; + + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + qcom,cdc-micbias4-mv = <1800>; + + qcom,cdc-mclk-clk-rate = <9600000>; + qcom,cdc-slim-ifd = "tavil-slim-ifd"; + qcom,cdc-slim-ifd-elemental-addr = [00 00 50 02 17 02]; + qcom,cdc-dmic-sample-rate = <4800000>; + qcom,cdc-mad-dmic-rate = <600000>; + }; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-bus.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-bus.dtsi index 4eb242fc1140..86decf438430 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-bus.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-bus.dtsi @@ -114,13 +114,9 @@ fab_gnoc: fab-gnoc { cell-id = <MSM_BUS_FAB_GNOC>; label = "fab-gnoc"; - qcom,fab-dev; qcom,virt-dev; qcom,base-name = "gnoc-base"; qcom,bypass-qos-prg; - clock-names = "bus_clk", "bus_a_clk"; - clocks = <&clock_gcc clk_bimc_msmbus_clk>, - <&clock_gcc clk_bimc_msmbus_a_clk>; }; fab_mnoc: fab-mnoc { @@ -135,6 +131,16 @@ clock-names = "bus_clk", "bus_a_clk"; clocks = <&clock_gcc clk_mmssnoc_axi_clk>, <&clock_gcc clk_mmssnoc_axi_a_clk>; + clk-mdss-axi-no-rate-supply = + <&gdsc_mdss>; + clk-mdss-ahb-no-rate-supply = + <&gdsc_mdss>; + clk-camss-ahb-no-rate-supply = + <&gdsc_camss_top>; + clk-video-ahb-no-rate-supply = + <&gdsc_venus>; + clk-video-axi-no-rate-supply = + <&gdsc_venus>; qcom,node-qos-clks { clock-names = "clk-noc-cfg-ahb-no-rate", @@ -145,6 +151,7 @@ "clk-video-ahb-no-rate", "clk-video-axi-no-rate"; clocks = + <&clock_gcc clk_mmssnoc_axi_clk>, <&clock_gcc clk_gcc_mmss_noc_cfg_ahb_clk>, <&clock_mmss clk_mmss_mnoc_ahb_clk>, <&clock_mmss clk_mmss_mdss_ahb_clk>, @@ -1450,7 +1457,6 @@ devfreq_spdm_gov { compatible = "qcom,gov_spdm_hyp"; interrupt-names = "spdm-irq"; - interrupt-edge; - interrupts = <0 192 0>; + interrupts = <0 192 IRQ_TYPE_EDGE_RISING>; }; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-cdp.dtsi index 83b55da92fa2..3ed038069319 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-cdp.dtsi @@ -16,7 +16,7 @@ cell-index = <0>; compatible = "qcom,camera-flash"; qcom,flash-source = <&pmicobalt_flash0 &pmicobalt_flash1>; - qcom,switch-source = <&pmicobalt_switch>; + qcom,switch-source = <&pmicobalt_switch0>; status = "ok"; }; @@ -24,7 +24,7 @@ cell-index = <1>; compatible = "qcom,camera-flash"; qcom,flash-source = <&pmicobalt_flash2>; - qcom,switch-source = <&pmicobalt_switch>; + qcom,switch-source = <&pmicobalt_switch1>; status = "ok"; }; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi index 83b55da92fa2..d152c0049f96 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi @@ -16,7 +16,7 @@ cell-index = <0>; compatible = "qcom,camera-flash"; qcom,flash-source = <&pmicobalt_flash0 &pmicobalt_flash1>; - qcom,switch-source = <&pmicobalt_switch>; + qcom,switch-source = <&pmicobalt_switch0>; status = "ok"; }; @@ -24,7 +24,7 @@ cell-index = <1>; compatible = "qcom,camera-flash"; qcom,flash-source = <&pmicobalt_flash2>; - qcom,switch-source = <&pmicobalt_switch>; + qcom,switch-source = <&pmicobalt_switch1>; status = "ok"; }; }; @@ -198,7 +198,7 @@ reg = <0x0>; qcom,csiphy-sd-index = <0>; qcom,csid-sd-index = <0>; - qcom,mount-angle = <90>; + qcom,mount-angle = <270>; qcom,led-flash-src = <&led_flash0>; qcom,actuator-src = <&actuator0>; qcom,ois-src = <&ois0>; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi index 2d0c674eaba8..b9626cd61553 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi @@ -254,6 +254,22 @@ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; }; +&dsi_dual_nt35597_truly_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_dual_nt35597_truly_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + &dsi_nt35597_dsc_video { qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; qcom,mdss-dsi-bl-min-level = <1>; @@ -284,6 +300,22 @@ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; }; +&dsi_dual_jdi_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,5v-boost-gpio = <&tlmm 51 0>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_dual_jdi_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,5v-boost-gpio = <&tlmm 51 0>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + &mdss_hdmi_tx { pinctrl-names = "hdmi_hpd_active", "hdmi_ddc_active", "hdmi_cec_active", "hdmi_active", "hdmi_sleep"; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-gpu.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-gpu.dtsi index 7a12053bef70..6ab19b298aa7 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-gpu.dtsi @@ -67,11 +67,12 @@ qcom,initial-pwrlevel = <4>; qcom,idle-timeout = <80>; //<HZ/12> + qcom,no-nap; /* * Timeout to enter deeper power saving state * from NAP. */ - qcom,deep-nap-timeout = <2>; //<HZ/50> + qcom,deep-nap-timeout = <200>; qcom,strtstp-sleepwake; qcom,highest-bank-bit = <15>; @@ -91,6 +92,7 @@ "mem_clk", "mem_iface_clk", "isense_clk", "rbcpr_clk", "iref_clk"; + qcom,isense-clk-on-level = <1>; /* Bus Scale Settings */ qcom,gpubw-dev = <&gpubw>; qcom,bus-control; @@ -128,9 +130,9 @@ qcom,gpu-pwrlevel@0 { reg = <0>; - qcom,gpu-freq = <504000000>; - qcom,bus-freq = <11>; - qcom,bus-min = <10>; + qcom,gpu-freq = <650000000>; + qcom,bus-freq = <12>; + qcom,bus-min = <11>; qcom,bus-max = <12>; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-mdss-panels.dtsi index 4953886f03b8..fc6c4d2eadd7 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-mdss-panels.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-mdss-panels.dtsi @@ -14,10 +14,14 @@ #include "dsi-panel-sim-dualmipi-video.dtsi" #include "dsi-panel-nt35597-dualmipi-wqxga-video.dtsi" #include "dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi" +#include "dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi" +#include "dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi" #include "dsi-panel-nt35597-dsc-wqxga-video.dtsi" #include "dsi-panel-nt35597-dsc-wqxga-cmd.dtsi" #include "dsi-panel-sharp-dsc-4k-video.dtsi" #include "dsi-panel-sharp-dsc-4k-cmd.dtsi" +#include "dsi-panel-jdi-dualmipi-video.dtsi" +#include "dsi-panel-jdi-dualmipi-cmd.dtsi" &soc { dsi_panel_pwr_supply: dsi_panel_pwr_supply { @@ -74,6 +78,8 @@ qcom,mdss-dsi-panel-timings = [00 1a 04 06 0a 0a 05 06 05 03 04 00]; qcom,mdss-dsi-t-clk-post = <0x0d>; qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "bta_check"; }; &dsi_dual_nt35597_cmd { @@ -82,6 +88,18 @@ qcom,mdss-dsi-t-clk-pre = <0x2d>; }; +&dsi_dual_nt35597_truly_video { + qcom,mdss-dsi-panel-timings = [00 1a 04 06 0a 0a 05 06 05 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x07>; + qcom,mdss-dsi-t-clk-pre = <0x25>; +}; + +&dsi_dual_nt35597_truly_cmd { + qcom,mdss-dsi-panel-timings = [00 1a 04 06 0a 0a 05 06 05 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x07>; + qcom,mdss-dsi-t-clk-pre = <0x25>; +}; + &dsi_nt35597_dsc_video { qcom,mdss-dsi-panel-timings = [00 12 03 04 07 07 04 04 03 03 04 00]; qcom,mdss-dsi-t-clk-post = <0x0b>; @@ -105,3 +123,15 @@ qcom,mdss-dsi-t-clk-post = <0x0d>; qcom,mdss-dsi-t-clk-pre = <0x25>; }; + +&dsi_dual_jdi_video { + qcom,mdss-dsi-panel-timings = [00 18 04 05 09 0a 05 06 04 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x06>; + qcom,mdss-dsi-t-clk-pre = <0x22>; +}; + +&dsi_dual_jdi_cmd { + qcom,mdss-dsi-panel-timings = [00 18 04 05 09 0a 05 06 04 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x06>; + qcom,mdss-dsi-t-clk-pre = <0x22>; +}; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-mdss.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-mdss.dtsi index b2f22572dcc8..3018ecd4e5eb 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-mdss.dtsi @@ -521,15 +521,16 @@ qcom,enable-load = <0>; qcom,disable-load = <0>; - clocks = <&clock_mmss clk_mmss_mdss_mdp_clk>, - <&clock_mmss clk_mmss_mnoc_ahb_clk>, + clocks = <&clock_mmss clk_mmss_mnoc_ahb_clk>, <&clock_mmss clk_mmss_mdss_ahb_clk>, <&clock_mmss clk_mmss_mdss_hdmi_clk>, + <&clock_mmss clk_mmss_mdss_mdp_clk>, <&clock_mmss clk_mmss_mdss_hdmi_dp_ahb_clk>, <&clock_mmss clk_mmss_mdss_extpclk_clk>; - clock-names = "mdp_core_clk", "mnoc_clk", "iface_clk", - "core_clk", "alt_iface_clk", "extp_clk"; + clock-names = "hpd_mnoc_clk", "hpd_iface_clk", + "hpd_core_clk", "hpd_mdp_core_clk", + "hpd_alt_iface_clk", "core_extp_clk"; qcom,mdss-fb-map = <&mdss_fb2>; qcom,pluggable; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi index c9af303b3738..6833bd1d7f4a 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-mtp.dtsi @@ -270,6 +270,22 @@ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; }; +&dsi_dual_nt35597_truly_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_dual_nt35597_truly_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + &dsi_nt35597_dsc_video { qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; qcom,mdss-dsi-bl-min-level = <1>; @@ -300,6 +316,22 @@ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; }; +&dsi_dual_jdi_video { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,5v-boost-gpio = <&tlmm 51 0>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&dsi_dual_jdi_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,5v-boost-gpio = <&tlmm 51 0>; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + &i2c_7 { status = "okay"; qcom,smb138x@8 { diff --git a/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi index fdcda8765a22..1094d96bd100 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi @@ -1375,24 +1375,24 @@ pmx_mdss: pmx_mdss { mdss_dsi_active: mdss_dsi_active { mux { - pins = "gpio94", "gpio91"; + pins = "gpio94", "gpio91", "gpio51"; function = "gpio"; }; config { - pins = "gpio94", "gpio91"; + pins = "gpio94", "gpio91", "gpio51"; drive-strength = <8>; /* 8 mA */ bias-disable = <0>; /* no pull */ }; }; mdss_dsi_suspend: mdss_dsi_suspend { mux { - pins = "gpio94", "gpio91"; + pins = "gpio94", "gpio91", "gpio51"; function = "gpio"; }; config { - pins = "gpio94", "gpio91"; + pins = "gpio94", "gpio91", "gpio51"; drive-strength = <2>; /* 2 mA */ bias-pull-down; /* pull down */ }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-pm.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-pm.dtsi index 73f612516f84..b5d3a85f9b15 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-pm.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-pm.dtsi @@ -382,7 +382,13 @@ <0xff 324>, /* lpass_qca_slimbus_bam_ee1_irq */ <0xff 432>, /* smmu_Cirpt[8] */ <0xff 433>, /* smmu_Cirpt[9] */ - <0xff 461>; /* o_ocimem_nonsec_irq */ + <0xff 461>, /* o_ocimem_nonsec_irq */ + <0xff 69>, /* o_pwr_dcvsh_interrupt */ + <0xff 70>, /* o_perf_dcvsh_interrupt */ + <0xff 166>, /* o_lm_int_2qgic */ + <0xff 238>, /* crypto_bam_irq[0] */ + <0xff 132>; /* qup_irq */ + qcom,gpio-parent = <&tlmm>; qcom,gpio-map = <3 1>, diff --git a/arch/arm/boot/dts/qcom/msmcobalt-qrd.dts b/arch/arm/boot/dts/qcom/msmcobalt-qrd.dts index 9848d6da33a5..d95507b505c2 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-qrd.dts +++ b/arch/arm/boot/dts/qcom/msmcobalt-qrd.dts @@ -14,7 +14,7 @@ /dts-v1/; #include "msmcobalt.dtsi" -#include "msmcobalt-mtp.dtsi" +#include "msmcobalt-qrd.dtsi" / { model = "Qualcomm Technologies, Inc. MSM COBALT QRD"; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi new file mode 100644 index 000000000000..1720aca3b298 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi @@ -0,0 +1,13 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "msmcobalt-mtp.dtsi" diff --git a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi index 21dbb8143061..12ee61b34d8c 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi @@ -82,7 +82,7 @@ rpm-regulator-smpa5 { status = "okay"; pmcobalt_s5: regulator-s5 { - regulator-min-microvolt = <2040000>; + regulator-min-microvolt = <1904000>; regulator-max-microvolt = <2040000>; status = "okay"; }; @@ -91,7 +91,7 @@ rpm-regulator-smpa7 { status = "okay"; pmcobalt_s7: regulator-s7 { - regulator-min-microvolt = <1028000>; + regulator-min-microvolt = <900000>; regulator-max-microvolt = <1028000>; status = "okay"; }; @@ -149,6 +149,9 @@ pmcobalt_l1: regulator-l1 { regulator-min-microvolt = <880000>; regulator-max-microvolt = <880000>; + proxy-supply = <&pmcobalt_l1>; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <73400>; status = "okay"; }; }; @@ -158,6 +161,9 @@ pmcobalt_l2: regulator-l2 { regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; + proxy-supply = <&pmcobalt_l2>; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <12560>; status = "okay"; }; }; @@ -298,6 +304,9 @@ pmcobalt_l14: regulator-l14 { regulator-min-microvolt = <1880000>; regulator-max-microvolt = <1880000>; + proxy-supply = <&pmcobalt_l14>; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <32000>; status = "okay"; }; }; @@ -533,45 +542,6 @@ /* Stub regulators */ / { - - /* PMCOBALT S10 = APC_0 supply */ - pmcobalt_s10: regulator-pmcobalt-s10 { - compatible = "qcom,stub-regulator"; - regulator-name = "pmcobalt_s10"; - qcom,hpm-min-load = <100000>; - regulator-min-microvolt = <352000>; - regulator-max-microvolt = <952000>; - }; - - /* - * PMCOBALT S11 + S12 + S13 = 3 phase APC_1 supply - * S13 is the gang leader - */ - pmcobalt_s13: regulator-pmcobalt-s13 { - compatible = "qcom,stub-regulator"; - regulator-name = "pmcobalt_s13"; - qcom,hpm-min-load = <100000>; - regulator-min-microvolt = <352000>; - regulator-max-microvolt = <952000>; - }; - - /* PM8005 S2 = VDD_MODEM supply */ - pm8005_s2: regulator-pm8005-s2 { - compatible = "qcom,stub-regulator"; - regulator-name = "pm8005_s2"; - qcom,hpm-min-load = <100000>; - regulator-min-microvolt = <352000>; - regulator-max-microvolt = <952000>; - }; - - pm8005_s3: regulator-pm8005-s3 { - compatible = "qcom,stub-regulator"; - regulator-name = "pm8005_s3"; - qcom,hpm-min-load = <100000>; - regulator-min-microvolt = <600000>; - regulator-max-microvolt = <600000>; - }; - gfx_stub_vreg: regulator-gfx-stub { compatible = "qcom,stub-regulator"; regulator-name = "gfx_stub_corner"; @@ -901,23 +871,23 @@ qcom,cpr-open-loop-voltage-fuse-adjustment = <0 0 0 0>, - <0 0 0 20000>, - <0 0 0 20000>, - <0 0 0 20000>, - <0 0 0 20000>, - <0 0 0 20000>, - <0 0 0 20000>, - <0 0 0 20000>; + <8000 0 0 52000>, + <8000 0 0 52000>, + <8000 0 0 52000>, + <8000 0 0 52000>, + <8000 0 0 52000>, + <8000 0 0 52000>, + <8000 0 0 52000>; qcom,cpr-closed-loop-voltage-fuse-adjustment = <0 0 0 0>, - <1000 0 0 21000>, - <1000 0 0 21000>, - <1000 0 0 21000>, - <1000 0 0 21000>, - <1000 0 0 21000>, - <1000 0 0 21000>, - <1000 0 0 21000>; + <0 0 0 50000>, + <0 0 0 50000>, + <0 0 0 50000>, + <0 0 0 50000>, + <0 0 0 50000>, + <0 0 0 50000>, + <0 0 0 50000>; qcom,allow-voltage-interpolation; qcom,allow-quotient-interpolation; @@ -1040,35 +1010,35 @@ 1580 1602 2158 3042 2780 2069 0 0>; qcom,cpr-open-loop-voltage-fuse-adjustment = - < 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 0 0>, - < 0 0 0 0>; + < 72000 0 0 0>, + < 72000 0 0 0>, + < 72000 0 0 0>, + < 72000 0 0 0>, + < 72000 0 0 0>, + < 72000 0 0 0>, + < 72000 0 0 0>, + < 72000 0 0 0>; qcom,cpr-closed-loop-voltage-adjustment = - < 150000 150000 150000 150000 - 150000 150000>, - < 150000 150000 150000 150000 - 150000 150000>, - < 150000 150000 150000 150000 - 150000 150000>, - < 150000 150000 150000 150000 - 150000 150000>, - < 150000 150000 150000 150000 - 150000 150000>, - < 150000 150000 150000 150000 - 150000 150000>, - < 150000 150000 150000 150000 - 150000 150000>, - < 150000 150000 150000 150000 - 150000 150000>; + < 65000 26000 8000 0 + 0 0>, + < 65000 26000 8000 0 + 0 0>, + < 65000 26000 8000 0 + 0 0>, + < 65000 26000 8000 0 + 0 0>, + < 65000 26000 8000 0 + 0 0>, + < 65000 26000 8000 0 + 0 0>, + < 65000 26000 8000 0 + 0 0>, + < 65000 26000 8000 0 + 0 0>; qcom,cpr-floor-to-ceiling-max-range = - <50000 50000 50000 50000 50000 50000>; + <75000 75000 75000 75000 75000 75000>; qcom,cpr-fused-closed-loop-voltage-adjustment-map = <0 0 1 2 3 4>; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-rumi.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-rumi.dtsi index 20d38f5616cb..105a83b56056 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-rumi.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-rumi.dtsi @@ -277,3 +277,11 @@ &pmicobalt_charger { qcom,suspend-input; }; + +&tsens0 { + status = "disabled"; +}; + +&tsens1 { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-sim.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-sim.dtsi index 3b79cee0ae1e..4e6b1dd9211a 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-sim.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-sim.dtsi @@ -114,3 +114,11 @@ &pmicobalt_charger { qcom,suspend-input; }; + +&tsens0 { + status = "disabled"; +}; + +&tsens1 { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-wcd.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-wcd.dtsi new file mode 100644 index 000000000000..7ae084debe06 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msmcobalt-wcd.dtsi @@ -0,0 +1,96 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&slim_aud { + tasha_codec { + wsa_spkr_sd1: msm_cdc_pinctrll { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_1_sd_n_active>; + pinctrl-1 = <&spkr_1_sd_n_sleep>; + }; + + wsa_spkr_sd2: msm_cdc_pinctrlr { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_2_sd_n_active>; + pinctrl-1 = <&spkr_2_sd_n_sleep>; + }; + }; + + tavil_codec { + wcd: wcd_pinctrl@5 { + compatible = "qcom,wcd-pinctrl"; + qcom,num-gpios = <5>; + gpio-controller; + #gpio-cells = <2>; + + spkr_1_wcd_en_active: spkr_1_wcd_en_active { + mux { + pins = "gpio2"; + }; + + config { + pins = "gpio2"; + output-high; + }; + }; + + spkr_1_wcd_en_sleep: spkr_1_wcd_en_sleep { + mux { + pins = "gpio2"; + }; + + config { + pins = "gpio2"; + input-enable; + }; + }; + + spkr_2_wcd_en_active: spkr_2_sd_n_active { + mux { + pins = "gpio3"; + }; + + config { + pins = "gpio3"; + output-high; + }; + }; + + spkr_2_wcd_en_sleep: spkr_2_sd_n_sleep { + mux { + pins = "gpio3"; + }; + + config { + pins = "gpio3"; + input-enable; + }; + }; + }; + + wsa_spkr_wcd_sd1: msm_cdc_pinctrll { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_1_wcd_en_active>; + pinctrl-1 = <&spkr_1_wcd_en_sleep>; + }; + + wsa_spkr_wcd_sd2: msm_cdc_pinctrlr { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_2_wcd_en_active>; + pinctrl-1 = <&spkr_2_wcd_en_sleep>; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-wsa881x.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-wsa881x.dtsi index 8f1f699cfc1f..baf05c1c241b 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-wsa881x.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-wsa881x.dtsi @@ -9,24 +9,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ - -&soc { - wsa_spkr_sd1: msm_cdc_pinctrl@65 { - compatible = "qcom,msm-cdc-pinctrl"; - qcom,cdc-rst-n-gpio = <&tlmm 65 0>; - pinctrl-names = "aud_active", "aud_sleep"; - pinctrl-0 = <&spkr_1_sd_n_active>; - pinctrl-1 = <&spkr_1_sd_n_sleep>; - }; - - wsa_spkr_sd2: msm_cdc_pinctrl@66 { - compatible = "qcom,msm-cdc-pinctrl"; - qcom,cdc-rst-n-gpio = <&tlmm 66 0>; - pinctrl-names = "aud_active", "aud_sleep"; - pinctrl-0 = <&spkr_2_sd_n_active>; - pinctrl-1 = <&spkr_2_sd_n_sleep>; - }; -}; +#include "msmcobalt-wcd.dtsi" &slim_aud { tasha_codec { @@ -60,4 +43,36 @@ }; }; }; + + tavil_codec { + swr_master { + compatible = "qcom,swr-wcd"; + #address-cells = <2>; + #size-cells = <0>; + + wsa881x_0211: wsa881x@20170211 { + compatible = "qcom,wsa881x"; + reg = <0x00 0x20170211>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd1>; + }; + + wsa881x_0212: wsa881x@20170212 { + compatible = "qcom,wsa881x"; + reg = <0x00 0x20170212>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>; + }; + + wsa881x_0213: wsa881x@21170213 { + compatible = "qcom,wsa881x"; + reg = <0x00 0x21170213>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd1>; + }; + + wsa881x_0214: wsa881x@21170214 { + compatible = "qcom,wsa881x"; + reg = <0x00 0x21170214>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>; + }; + }; + }; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt.dtsi b/arch/arm/boot/dts/qcom/msmcobalt.dtsi index 7d61d8f1d341..e748783b0c7d 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt.dtsi @@ -34,6 +34,7 @@ chosen { stdout-path = "serial0"; + bootargs = "rcupdate.rcu_expedited=1"; }; cpus { @@ -258,13 +259,25 @@ removed_regions: removed_regions@85800000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x85800000 0 0x5300000>; + reg = <0 0x85800000 0 0x3700000>; }; - peripheral_mem: peripheral_region@91900000 { + pil_slpi_mem: pil_slpi_region@93800000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x91900000 0 0x2e00000>; + reg = <0 0x93800000 0 0xf00000>; + }; + + pil_video_mem: pil_video_region@93300000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x93300000 0 0x500000>; + }; + + pil_adsp_mem: pil_adsp_region@91900000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x91900000 0 0x1a00000>; }; modem_mem: modem_region@8ac00000 { @@ -284,7 +297,7 @@ alloc-ranges = <0 0x00000000 0 0xffffffff>; reusable; alignment = <0 0x400000>; - size = <0 0x400000>; + size = <0 0x800000>; }; qseecom_mem: qseecom_region { @@ -310,6 +323,16 @@ alignment = <0 0x200000>; size = <0 0x5c00000>; }; + + /* global autoconfigured region for contiguous allocations */ + linux,cma { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x2000000>; + linux,cma-default; + }; }; }; @@ -646,7 +669,31 @@ < 1881600 >; qcom,cpufreq-table-4 = - < 300000 >; + < 300000 >, + < 345600 >, + < 422400 >, + < 480000 >, + < 556800 >, + < 633600 >, + < 710400 >, + < 787200 >, + < 844800 >, + < 902400 >, + < 979200 >, + < 1056000 >, + < 1171200 >, + < 1248000 >, + < 1324800 >, + < 1401600 >, + < 1478400 >, + < 1536000 >, + < 1632000 >, + < 1708800 >, + < 1785600 >, + < 1862400 >, + < 1939200 >, + < 2016000 >, + < 2092800 >; }; arm64-cpu-erp { @@ -774,7 +821,31 @@ < 1881600000 0x04040062 0x094e004e 0x4 >; qcom,perfcl-speedbin0-v0 = - < 300000000 0x0004000f 0x03200020 0x1>; + < 300000000 0x0004000f 0x01200020 0x1 >, + < 345600000 0x05040012 0x02200020 0x1 >, + < 422400000 0x05040016 0x02200020 0x1 >, + < 480000000 0x05040019 0x02200020 0x1 >, + < 556800000 0x0504001d 0x03200020 0x1 >, + < 633600000 0x05040021 0x03200020 0x1 >, + < 710400000 0x05040025 0x03200020 0x1 >, + < 787200000 0x05040029 0x04200020 0x1 >, + < 844800000 0x0404002c 0x04230023 0x1 >, + < 902400000 0x0404002f 0x04260026 0x1 >, + < 979200000 0x04040033 0x05290029 0x1 >, + < 1056000000 0x04040037 0x052c002c 0x1 >, + < 1171200000 0x0404003d 0x06310031 0x2 >, + < 1248000000 0x04040041 0x06340034 0x2 >, + < 1324800000 0x04040045 0x06370037 0x2 >, + < 1401600000 0x04040049 0x073a003a 0x2 >, + < 1478400000 0x0404004d 0x073e003e 0x2 >, + < 1536000000 0x04040050 0x07400040 0x2 >, + < 1632000000 0x04040055 0x08440044 0x3 >, + < 1708800000 0x04040059 0x08470047 0x3 >, + < 1785600000 0x0404005d 0x094a004a 0x3 >, + < 1862400000 0x04040061 0x094e004e 0x3 >, + < 1939200000 0x04040065 0x09510051 0x3 >, + < 2016000000 0x04040069 0x0a540054 0x3 >, + < 2092800000 0x0404006d 0x0a570057 0x3 >; qcom,up-timer = <1000 1000>; @@ -1052,34 +1123,6 @@ reg-names = "smem", "irq-reg-base", "aux-mem1", "smem_targ_info_reg"; qcom,mpu-enabled; - - qcom,smd-modem { - compatible = "qcom,smd"; - qcom,smd-edge = <0>; - qcom,smd-irq-offset = <0x0>; - qcom,smd-irq-bitmask = <0x1000>; - interrupts = <0 449 1>; - label = "modem"; - qcom,not-loadable; - }; - - qcom,smd-adsp { - compatible = "qcom,smd"; - qcom,smd-edge = <1>; - qcom,smd-irq-offset = <0x0>; - qcom,smd-irq-bitmask = <0x100>; - interrupts = <0 156 1>; - label = "adsp"; - }; - - qcom,smd-dsps { - compatible = "qcom,smd"; - qcom,smd-edge = <3>; - qcom,smd-irq-offset = <0x0>; - qcom,smd-irq-bitmask = <0x2000000>; - interrupts = <0 176 1>; - label = "dsps"; - }; }; qcom,msm-adsprpc-mem { @@ -1117,11 +1160,6 @@ label = "adsprpc-smd"; iommus = <&lpass_q6_smmu 11>; }; - qcom,msm_fastrpc_compute_cb5 { - compatible = "qcom,msm-fastrpc-compute-cb"; - label = "adsprpc-smd"; - iommus = <&lpass_q6_smmu 12>; - }; qcom,msm_fastrpc_compute_cb6 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "adsprpc-smd"; @@ -1411,10 +1449,6 @@ qcom,vreg-cx-voltage-level = <RPM_SMD_REGULATOR_LEVEL_BINNING RPM_SMD_REGULATOR_LEVEL_SVS 0>; - qcom,l1-supported; - qcom,l1ss-supported; - qcom,aux-clk-sync; - qcom,ep-latency = <10>; qcom,ep-wakeirq; @@ -1906,6 +1940,13 @@ "phy_phy_reset", "ref_clk_src", "ref_clk"; }; + usb_audio_qmi_dev { + compatible = "qcom,usb-audio-qmi-dev"; + iommus = <&lpass_q6_smmu 12>; + qcom,usb-audio-stream-id = <12>; + qcom,usb-audio-intr-num = <2>; + }; + dbm_1p5: dbm@a8f8000 { compatible = "qcom,usb-dbm-1p5"; reg = <0xa8f8000 0x300>; @@ -1936,7 +1977,7 @@ status = "ok"; qcom,ssctl-instance-id = <0x14>; qcom,firmware-name = "adsp"; - memory-region = <&peripheral_mem>; + memory-region = <&pil_adsp_mem>; /* GPIO inputs from lpass */ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>; @@ -2416,7 +2457,7 @@ qcom,ssctl-instance-id = <0x16>; qcom,firmware-name = "slpi"; status = "ok"; - memory-region = <&peripheral_mem>; + memory-region = <&pil_slpi_mem>; /* GPIO inputs from ssc */ qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_3_in 0 0>; @@ -2449,7 +2490,7 @@ qcom,pas-id = <9>; qcom,proxy-timeout-ms = <10000>; qcom,firmware-name = "venus"; - memory-region = <&peripheral_mem>; + memory-region = <&pil_video_mem>; status = "ok"; }; @@ -2497,6 +2538,12 @@ qcom,rtb-size = <0x100000>; }; + qcom,mpm2-sleep-counter@10a3000 { + compatible = "qcom,mpm2-sleep-counter"; + reg = <0x010a3000 0x1000>; + clock-frequency = <32768>; + }; + qcom,msm-imem@146bf000 { compatible = "qcom,msm-imem"; reg = <0x146bf000 0x1000>; @@ -2707,6 +2754,18 @@ qcom,smmu-support; status = "disabled"; }; + + qcom,qsee_ipc_irq_bridge { + compatible = "qcom,qsee-ipc-irq-bridge"; + + qcom,qsee-ipc-irq-spss { + qcom,rx-irq-clr = <0x1d08008 0x4>; + qcom,rx-irq-clr-mask = <0x2>; + qcom,dev-name = "qsee_ipc_irq_spss"; + interrupts = <0 349 4>; + label = "spss"; + }; + }; }; &clock_cpu { @@ -2746,6 +2805,8 @@ &gdsc_bimc_smmu { clock-names = "bus_clk"; clocks = <&clock_mmss clk_mmss_bimc_smmu_axi_clk>; + proxy-supply = <&gdsc_bimc_smmu>; + qcom,proxy-consumer-enable; status = "ok"; }; diff --git a/arch/arm/boot/dts/qcom/msmfalcon-ion.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-ion.dtsi new file mode 100644 index 000000000000..f6deef335844 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msmfalcon-ion.dtsi @@ -0,0 +1,52 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + qcom,ion { + compatible = "qcom,msm-ion"; + #address-cells = <1>; + #size-cells = <0>; + + system_heap: qcom,ion-heap@25 { + reg = <25>; + qcom,ion-heap-type = "SYSTEM"; + }; + + system_contig_heap: qcom,ion-heap@21 { + reg = <21>; + qcom,ion-heap-type = "SYSTEM_CONTIG"; + }; + + qcom,ion-heap@22 { /* ADSP HEAP */ + reg = <22>; + memory-region = <&adsp_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@27 { /* QSEECOM HEAP */ + reg = <27>; + memory-region = <&qseecom_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@10 { /* SECURE DISPLAY HEAP */ + reg = <10>; + memory-region = <&secure_display_memory>; + qcom,ion-heap-type = "HYP_CMA"; + }; + + qcom,ion-heap@9 { + reg = <9>; + qcom,ion-heap-type = "SYSTEM_SECURE"; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts new file mode 100644 index 000000000000..6631d31bac6d --- /dev/null +++ b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts @@ -0,0 +1,29 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "msmfalcon.dtsi" +#include "msmfalcon-pinctrl.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM FALCON RUMI"; + compatible = "qcom,msmfalcon-rumi", "qcom,msmfalcon", "qcom,rumi"; + qcom,board-id = <15 0>; +}; + +&uartblsp2dm1 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console_active>; +}; diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi index 6d931c1fbb89..ea60ed90cf4f 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon.dtsi @@ -11,7 +11,9 @@ */ #include "skeleton64.dtsi" -#include <dt-bindings/clock/msm-clocks-cobalt.h> +#include <dt-bindings/clock/qcom,gcc-msmfalcon.h> +#include <dt-bindings/clock/qcom,gpu-msmfalcon.h> +#include <dt-bindings/clock/qcom,mmcc-msmfalcon.h> #include <dt-bindings/interrupt-controller/arm-gic.h> / { @@ -128,6 +130,68 @@ }; soc: soc { }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + removed_regions: removed_regions@85800000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x85800000 0x0 0x3700000>; + }; + + modem_fw_mem: modem_fw_region@8ac00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x8ac00000 0x0 0x7800000>; + }; + + adsp_fw_mem: adsp_fw_region@92400000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x92400000 0x0 0x1e00000>; + }; + + cdsp_fw_mem: cdsp_fw_region@94200000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0x0 0x94200000 0x0 0x600000>; + }; + + venus_fw_mem: venus_fw_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x80000000 0x0 0x20000000>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x800000>; + }; + + adsp_mem: adsp_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x400000>; + }; + + qseecom_mem: qseecom_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x1400000>; + }; + + secure_display_memory: secure_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x5c00000>; + }; + }; }; &soc { @@ -159,13 +223,30 @@ clock-frequency = <19200000>; }; + qcom,sps { + compatible = "qcom,msm_sps_4k"; + qcom,pipe-attr-ee; + }; + + tsens: tsens@10ad000 { + compatible = "qcom,msmfalcon-tsens"; + reg = <0x10ad000 0x2000>, + <0x784240 0x1000>; + reg-names = "tsens_physical", "tsens_eeprom_physical"; + interrupts = <0 184 0>, <0 430 0>; + interrupt-names = "tsens-upper-lower", "tsens-critical"; + qcom,sensors = <14>; + qcom,slope = <3200 3200 3200 3200 3200 3200 3200 3200 + 3200 3200 3200 3200 3200 3200>; + }; + uartblsp2dm1: serial@0c1b0000 { compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; reg = <0xc1b0000 0x1000>; interrupts = <0 114 0>; status = "disabled"; - clocks = <&clock_gcc clk_gcc_blsp2_uart2_apps_clk>, - <&clock_gcc clk_gcc_blsp2_ahb_clk>; + clocks = <&clock_gcc GCC_BLSP2_UART2_APPS_CLK>, + <&clock_gcc GCC_BLSP2_AHB_CLK>; clock-names = "core", "iface"; }; @@ -232,4 +313,59 @@ compatible = "qcom,dummycc"; #clock-cells = <1>; }; + + qcom,ipc-spinlock@1f40000 { + compatible = "qcom,ipc-spinlock-sfpb"; + reg = <0x1f40000 0x8000>; + qcom,num-locks = <8>; + }; + + qcom,smem@86000000 { + compatible = "qcom,smem"; + reg = <0x86000000 0x200000>, + <0x17911008 0x4>, + <0x778000 0x7000>, + <0x1fd4000 0x8>; + reg-names = "smem", "irq-reg-base", "aux-mem1", + "smem_targ_info_reg"; + qcom,mpu-enabled; + }; + + glink_mpss: qcom,glink-ssr-modem { + compatible = "qcom,glink_ssr"; + label = "modem"; + qcom,edge = "mpss"; + qcom,notify-edges = <&glink_lpass>, <&glink_rpm>, + <&glink_cdsp>; + qcom,xprt = "smem"; + }; + + glink_lpass: qcom,glink-ssr-adsp { + compatible = "qcom,glink_ssr"; + label = "adsp"; + qcom,edge = "lpass"; + qcom,notify-edges = <&glink_mpss>, <&glink_rpm>, + <&glink_cdsp>; + qcom,xprt = "smem"; + }; + + glink_rpm: qcom,glink-ssr-rpm { + compatible = "qcom,glink_ssr"; + label = "rpm"; + qcom,edge = "rpm"; + qcom,notify-edges = <&glink_lpass>, <&glink_mpss>, + <&glink_cdsp>; + qcom,xprt = "smem"; + }; + + glink_cdsp: qcom,glink-ssr-cdsp { + compatible = "qcom,glink_ssr"; + label = "cdsp"; + qcom,edge = "cdsp"; + qcom,notify-edges = <&glink_lpass>, <&glink_mpss>, + <&glink_rpm>; + qcom,xprt = "smem"; + }; }; + +#include "msmfalcon-ion.dtsi" diff --git a/arch/arm/boot/dts/qcom/msmhamster.dtsi b/arch/arm/boot/dts/qcom/msmhamster.dtsi index cf34ad20f84a..e87cf7c153ea 100644 --- a/arch/arm/boot/dts/qcom/msmhamster.dtsi +++ b/arch/arm/boot/dts/qcom/msmhamster.dtsi @@ -58,3 +58,15 @@ < 670000000 RPM_SMD_REGULATOR_LEVEL_TURBO >, < 710000000 RPM_SMD_REGULATOR_LEVEL_TURBO >; }; + +&tsens0 { + compatible = "qcom,msmhamster-tsens"; +}; + +&tsens1 { + compatible = "qcom,msmhamster-tsens"; + qcom,client-id = <14 15 16 17 18 19 20>; + qcom,sensor-id = <0 1 3 4 5 6 7>; + qcom,sensors = <7>; + qcom,slope = <2901 2846 3200 3200 3200 3200 3200>; +}; diff --git a/arch/arm/boot/dts/sama5d2-pinfunc.h b/arch/arm/boot/dts/sama5d2-pinfunc.h index 1afe24629d1f..b0c912feaa2f 100644 --- a/arch/arm/boot/dts/sama5d2-pinfunc.h +++ b/arch/arm/boot/dts/sama5d2-pinfunc.h @@ -90,7 +90,7 @@ #define PIN_PA14__I2SC1_MCK PINMUX_PIN(PIN_PA14, 4, 2) #define PIN_PA14__FLEXCOM3_IO2 PINMUX_PIN(PIN_PA14, 5, 1) #define PIN_PA14__D9 PINMUX_PIN(PIN_PA14, 6, 2) -#define PIN_PA15 14 +#define PIN_PA15 15 #define PIN_PA15__GPIO PINMUX_PIN(PIN_PA15, 0, 0) #define PIN_PA15__SPI0_MOSI PINMUX_PIN(PIN_PA15, 1, 1) #define PIN_PA15__TF1 PINMUX_PIN(PIN_PA15, 2, 1) diff --git a/arch/arm/configs/msmcortex_defconfig b/arch/arm/configs/msmcortex_defconfig new file mode 100644 index 000000000000..9a3ffc5e555f --- /dev/null +++ b/arch/arm/configs/msmcortex_defconfig @@ -0,0 +1,562 @@ +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_RCU_EXPERT=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_SCHED=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_SCHED_HMP=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_MEMBARRIER is not set +CONFIG_EMBEDDED=y +# CONFIG_COMPAT_BRK is not set +CONFIG_PROFILING=y +CONFIG_CC_STACKPROTECTOR_REGULAR=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_SHA512=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_IOSCHED_DEADLINE is not set +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_MSMFALCON=y +CONFIG_SMP=y +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=8 +CONFIG_ARM_PSCI=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_CLEANCACHE=y +CONFIG_CMA=y +CONFIG_ZSMALLOC=y +CONFIG_SECCOMP=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y +CONFIG_SCHED_FREQ_INPUT=y +# CONFIG_CPU_FREQ_STAT is not set +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_DEBUG=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +# CONFIG_INET_LRO is not set +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_L2TP=y +CONFIG_L2TP_DEBUGFS=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +CONFIG_DNS_RESOLVER=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_BT=y +CONFIG_MSM_BT_POWER=y +CONFIG_BTFM_SLIM=y +CONFIG_BTFM_SLIM_WCN3990=y +CONFIG_CFG80211=y +CONFIG_CFG80211_INTERNAL_REGDB=y +# CONFIG_CFG80211_CRDA_SUPPORT is not set +CONFIG_RFKILL=y +CONFIG_NFC_NQ=y +CONFIG_IPC_ROUTER=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_DMA_CMA=y +CONFIG_CMA_SIZE_MBYTES=40 +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_UID_STAT=y +CONFIG_UID_CPUTIME=y +CONFIG_MSM_ULTRASOUND=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_NETDEVICES=y +CONFIG_BONDING=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_RNDIS_IPA=y +CONFIG_PHYLIB=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_MPPE=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_ATH_CARDS=y +CONFIG_CLD_LL_CORE=y +CONFIG_QPNP_POWER_ON=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_KEYRESET=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v21=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v21=y +CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v21=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_HBTP_INPUT=y +CONFIG_INPUT_KEYCHORD=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +CONFIG_SERIAL_MSM_HS=y +CONFIG_SERIAL_MSM_SMD=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_MSM_ADSPRPC=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_SLIMBUS=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_SOUNDWIRE=y +CONFIG_SPI=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPMI=y +CONFIG_PINCTRL_MSMCOBALT=y +CONFIG_PINCTRL_MSMFALCON=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_QPNP_PIN=y +CONFIG_APSS_CORE_EA=y +CONFIG_MSM_APM=y +CONFIG_QPNP_SMBCHARGER=y +CONFIG_SMB135X_CHARGER=y +CONFIG_SMB1351_USB_CHARGER=y +CONFIG_MSM_BCL_CTL=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_QPNP_SMB2=y +CONFIG_SMB138X_CHARGER=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_THERMAL=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_MFD_I2C_PMIC=y +CONFIG_MSM_CDC_PINCTRL=y +CONFIG_MSM_CDC_SUPPLY=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_CPR3_HMSS=y +CONFIG_REGULATOR_CPR3_MMSS=y +CONFIG_REGULATOR_CPRH_KBSS=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_ADV_DEBUG=y +CONFIG_VIDEO_FIXED_MINOR_RANGES=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_MSM_CAMERA=y +CONFIG_MSM_CAMERA_DEBUG=y +CONFIG_MSM_SDE_ROTATOR=y +CONFIG_QCOM_KGSL=y +CONFIG_FB=y +CONFIG_FB_VIRTUAL=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SOC=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_MICROSOFT=y +CONFIG_USB=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_DWC3=y +CONFIG_USB_ISP1760=y +CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_OTG_WAKELOCK=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_MTP=y +CONFIG_USB_CONFIGFS_F_PTP=y +CONFIG_USB_CONFIGFS_F_ACC=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_USB_CONFIGFS_F_GSI=y +CONFIG_USB_CONFIGFS_F_CDEV=y +CONFIG_USB_CONFIGFS_F_QDSS=y +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_TEST=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_QPNP_FLASH_V2=y +CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_CPU=y +CONFIG_SWITCH=y +CONFIG_EDAC=y +CONFIG_EDAC_MM_EDAC=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_SYNC=y +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_QPNP_REVID=y +CONFIG_QPNP_COINCELL=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_IPA=y +CONFIG_RMNET_IPA=y +CONFIG_GSI=y +CONFIG_IPA3=y +CONFIG_RMNET_IPA3=y +CONFIG_GPIO_USB_DETECT=y +CONFIG_USB_BAM=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_COMMON_LOG=y +CONFIG_MSM_SMEM=y +CONFIG_QPNP_HAPTIC=y +CONFIG_MSM_SMD=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_GLINK=y +CONFIG_MSM_GLINK_LOOPBACK_SERVER=y +CONFIG_MSM_GLINK_SMD_XPRT=y +CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y +CONFIG_MSM_SPCOM=y +CONFIG_MSM_SMEM_LOGGING=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_SMP2P_TEST=y +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_QCOM_DCC=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +CONFIG_MSM_SYSMON_GLINK_COMM=y +CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y +CONFIG_MSM_GLINK_PKT=y +CONFIG_MSM_SPM=y +CONFIG_QCOM_SCM=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_ICNSS=y +CONFIG_MSM_GLADIATOR_ERP_V2=y +CONFIG_PANIC_ON_GLADIATOR_ERROR_V2=y +CONFIG_MSM_GLADIATOR_HANG_DETECT=y +CONFIG_MSM_CORE_HANG_DETECT=y +CONFIG_MSM_RUN_QUEUE_STATS=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_QCOM_CPUSS_DUMP=y +CONFIG_MSM_QDSP6_APRV2_GLINK=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_TRACER_PKT=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_MSM_MPM_OF=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_CORE_CTL_HELPER=y +CONFIG_MSM_SERVICE_NOTIFIER=y +CONFIG_MEM_SHARE_QMI_SERVICE=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_EXTCON=y +CONFIG_IIO=y +CONFIG_QCOM_RRADC=y +CONFIG_PWM=y +CONFIG_PWM_QPNP=y +CONFIG_ARM_GIC_V3_ACL=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_MSM_TZ_LOG=y +CONFIG_SENSORS_SSC=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_FUSE_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 +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_INFO=y +CONFIG_PAGE_OWNER=y +CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_SLUB_DEBUG_PANIC_ON=y +CONFIG_DEBUG_OBJECTS=y +CONFIG_DEBUG_OBJECTS_FREE=y +CONFIG_DEBUG_OBJECTS_TIMERS=y +CONFIG_DEBUG_OBJECTS_WORK=y +CONFIG_DEBUG_OBJECTS_RCU_HEAD=y +CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y +CONFIG_SLUB_DEBUG_ON=y +CONFIG_DEBUG_KMEMLEAK=y +CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000 +CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y +CONFIG_DEBUG_STACK_USAGE=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_LOCKUP_DETECTOR=y +CONFIG_WQ_WATCHDOG=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANIC_ON_SCHED_BUG=y +CONFIG_PANIC_ON_RT_THROTTLING=y +CONFIG_SCHEDSTATS=y +CONFIG_SCHED_STACK_END_CHECK=y +CONFIG_TIMER_STATS=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_ATOMIC_SLEEP=y +CONFIG_DEBUG_LIST=y +CONFIG_FAULT_INJECTION=y +CONFIG_FAIL_PAGE_ALLOC=y +CONFIG_UFS_FAULT_INJECTION=y +CONFIG_FAULT_INJECTION_DEBUG_FS=y +CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y +CONFIG_IPC_LOGGING=y +CONFIG_QCOM_RTB=y +CONFIG_FUNCTION_TRACER=y +CONFIG_TRACER_SNAPSHOT=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_MEMTEST=y +CONFIG_PANIC_ON_DATA_CORRUPTION=y +CONFIG_PID_IN_CONTEXTIDR=y +CONFIG_DEBUG_SET_MODULE_RONX=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_REMOTE_ETM=y +CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_QPDI=y +CONFIG_CORESIGHT_SOURCE_DUMMY=y +CONFIG_SECURITY=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_ECHAINIV=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_OTA_CRYPTO=y +CONFIG_CRYPTO_DEV_QCE=y +CONFIG_XZ_DEC=y diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 9623a8a87e18..2005a47b491e 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -512,7 +512,6 @@ static inline int set_memory_nx(unsigned long addr, int numpages) { return 0; } #endif #ifdef CONFIG_DEBUG_RODATA -void mark_rodata_ro(void); void set_kernel_text_rw(void); void set_kernel_text_ro(void); #else diff --git a/arch/arm/include/asm/psci.h b/arch/arm/include/asm/psci.h index 68ee3ce17b82..b4c6d99364f1 100644 --- a/arch/arm/include/asm/psci.h +++ b/arch/arm/include/asm/psci.h @@ -16,7 +16,7 @@ extern struct smp_operations psci_smp_ops; -#ifdef CONFIG_ARM_PSCI +#if defined(CONFIG_SMP) && defined(CONFIG_ARM_PSCI) bool psci_smp_available(void); #else static inline bool psci_smp_available(void) { return false; } diff --git a/arch/arm/include/asm/xen/page-coherent.h b/arch/arm/include/asm/xen/page-coherent.h index 0375c8caa061..9408a994cc91 100644 --- a/arch/arm/include/asm/xen/page-coherent.h +++ b/arch/arm/include/asm/xen/page-coherent.h @@ -35,14 +35,21 @@ static inline void xen_dma_map_page(struct device *hwdev, struct page *page, dma_addr_t dev_addr, unsigned long offset, size_t size, enum dma_data_direction dir, struct dma_attrs *attrs) { - bool local = XEN_PFN_DOWN(dev_addr) == page_to_xen_pfn(page); + unsigned long page_pfn = page_to_xen_pfn(page); + unsigned long dev_pfn = XEN_PFN_DOWN(dev_addr); + unsigned long compound_pages = + (1<<compound_order(page)) * XEN_PFN_PER_PAGE; + bool local = (page_pfn <= dev_pfn) && + (dev_pfn - page_pfn < compound_pages); + /* - * Dom0 is mapped 1:1, while the Linux page can be spanned accross - * multiple Xen page, it's not possible to have a mix of local and - * foreign Xen page. So if the first xen_pfn == mfn the page is local - * otherwise it's a foreign page grant-mapped in dom0. If the page is - * local we can safely call the native dma_ops function, otherwise we - * call the xen specific function. + * Dom0 is mapped 1:1, while the Linux page can span across + * multiple Xen pages, it's not possible for it to contain a + * mix of local and foreign Xen pages. So if the first xen_pfn + * == mfn the page is local otherwise it's a foreign page + * grant-mapped in dom0. If the page is local we can safely + * call the native dma_ops function, otherwise we call the xen + * specific function. */ if (local) __generic_dma_ops(hwdev)->map_page(hwdev, page, offset, size, dir, attrs); diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c index edb0a0036110..598323a1842e 100644 --- a/arch/arm/kernel/topology.c +++ b/arch/arm/kernel/topology.c @@ -234,6 +234,9 @@ static int __init parse_dt_topology(void) unsigned long capacity = 0; int cpu = 0, ret = 0; + __cpu_capacity = kcalloc(nr_cpu_ids, sizeof(*__cpu_capacity), + GFP_NOWAIT); + cn = of_find_node_by_path("/cpus"); if (!cn) { pr_err("No CPU information found in DT\n"); @@ -260,9 +263,6 @@ static int __init parse_dt_topology(void) if (cpu_topology[cpu].cluster_id == -1) ret = -EINVAL; - __cpu_capacity = kcalloc(nr_cpu_ids, sizeof(*__cpu_capacity), - GFP_NOWAIT); - for_each_possible_cpu(cpu) { const u32 *rate; int len; @@ -456,38 +456,46 @@ static struct sched_domain_topology_level arm_topology[] = { { NULL, }, }; -/* - * init_cpu_topology is called at boot when only one cpu is running - * which prevent simultaneous write access to cpu_topology array - */ -void __init init_cpu_topology(void) +static void __init reset_cpu_topology(void) { unsigned int cpu; - /* init core mask and capacity */ for_each_possible_cpu(cpu) { - struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]); + struct cputopo_arm *cpu_topo = &cpu_topology[cpu]; cpu_topo->thread_id = -1; - cpu_topo->core_id = -1; + cpu_topo->core_id = -1; cpu_topo->cluster_id = -1; + cpumask_clear(&cpu_topo->core_sibling); cpumask_clear(&cpu_topo->thread_sibling); + } +} +static void __init reset_cpu_capacity(void) +{ + unsigned int cpu; + + for_each_possible_cpu(cpu) set_capacity_scale(cpu, SCHED_CAPACITY_SCALE); - } - smp_wmb(); +} - if (parse_dt_topology()) { - struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]); +/* + * init_cpu_topology is called at boot when only one cpu is running + * which prevent simultaneous write access to cpu_topology array + */ +void __init init_cpu_topology(void) +{ + unsigned int cpu; - cpu_topo->thread_id = -1; - cpu_topo->core_id = -1; - cpu_topo->cluster_id = -1; - cpumask_clear(&cpu_topo->core_sibling); - cpumask_clear(&cpu_topo->thread_sibling); + /* init core mask and capacity */ + reset_cpu_topology(); + reset_cpu_capacity(); + smp_wmb(); - set_capacity_scale(cpu, SCHED_CAPACITY_SCALE); + if (parse_dt_topology()) { + reset_cpu_topology(); + reset_cpu_capacity(); } for_each_possible_cpu(cpu) diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c index 96e935bbc38c..3705fc2921c2 100644 --- a/arch/arm/kvm/guest.c +++ b/arch/arm/kvm/guest.c @@ -155,7 +155,7 @@ static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) u64 val; val = kvm_arm_timer_get_reg(vcpu, reg->id); - return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)); + return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)) ? -EFAULT : 0; } static unsigned long num_core_regs(void) diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c index 7b76ce01c21d..8633c703546a 100644 --- a/arch/arm/mach-omap2/gpmc-onenand.c +++ b/arch/arm/mach-omap2/gpmc-onenand.c @@ -101,10 +101,8 @@ static void omap2_onenand_set_async_mode(void __iomem *onenand_base) static void set_onenand_cfg(void __iomem *onenand_base) { - u32 reg; + u32 reg = ONENAND_SYS_CFG1_RDY | ONENAND_SYS_CFG1_INT; - reg = readw(onenand_base + ONENAND_REG_SYS_CFG1); - reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9)); reg |= (latency << ONENAND_SYS_CFG1_BRL_SHIFT) | ONENAND_SYS_CFG1_BL_16; if (onenand_flags & ONENAND_FLAG_SYNCREAD) @@ -123,6 +121,7 @@ static void set_onenand_cfg(void __iomem *onenand_base) reg |= ONENAND_SYS_CFG1_VHF; else reg &= ~ONENAND_SYS_CFG1_VHF; + writew(reg, onenand_base + ONENAND_REG_SYS_CFG1); } @@ -289,6 +288,7 @@ static int omap2_onenand_setup_async(void __iomem *onenand_base) } } + onenand_async.sync_write = true; omap2_onenand_calc_async_timings(&t); ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_async); diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 48495ad82aba..8e0bd5939e5a 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2200,6 +2200,11 @@ static int _enable(struct omap_hwmod *oh) */ static int _idle(struct omap_hwmod *oh) { + if (oh->flags & HWMOD_NO_IDLE) { + oh->_int_flags |= _HWMOD_SKIP_ENABLE; + return 0; + } + pr_debug("omap_hwmod: %s: idling\n", oh->name); if (oh->_state != _HWMOD_STATE_ENABLED) { @@ -2504,6 +2509,8 @@ static int __init _init(struct omap_hwmod *oh, void *data) oh->flags |= HWMOD_INIT_NO_RESET; if (of_find_property(np, "ti,no-idle-on-init", NULL)) oh->flags |= HWMOD_INIT_NO_IDLE; + if (of_find_property(np, "ti,no-idle", NULL)) + oh->flags |= HWMOD_NO_IDLE; } oh->_state = _HWMOD_STATE_INITIALIZED; @@ -2630,7 +2637,7 @@ static void __init _setup_postsetup(struct omap_hwmod *oh) * XXX HWMOD_INIT_NO_IDLE does not belong in hwmod data - * it should be set by the core code as a runtime flag during startup */ - if ((oh->flags & HWMOD_INIT_NO_IDLE) && + if ((oh->flags & (HWMOD_INIT_NO_IDLE | HWMOD_NO_IDLE)) && (postsetup_state == _HWMOD_STATE_IDLE)) { oh->_int_flags |= _HWMOD_SKIP_ENABLE; postsetup_state = _HWMOD_STATE_ENABLED; diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h index 76bce11c85a4..7c7a31169475 100644 --- a/arch/arm/mach-omap2/omap_hwmod.h +++ b/arch/arm/mach-omap2/omap_hwmod.h @@ -525,6 +525,8 @@ struct omap_hwmod_omap4_prcm { * or idled. * HWMOD_OPT_CLKS_NEEDED: The optional clocks are needed for the module to * operate and they need to be handled at the same time as the main_clk. + * HWMOD_NO_IDLE: Do not idle the hwmod at all. Useful to handle certain + * IPs like CPSW on DRA7, where clocks to this module cannot be disabled. */ #define HWMOD_SWSUP_SIDLE (1 << 0) #define HWMOD_SWSUP_MSTANDBY (1 << 1) @@ -541,6 +543,7 @@ struct omap_hwmod_omap4_prcm { #define HWMOD_SWSUP_SIDLE_ACT (1 << 12) #define HWMOD_RECONFIG_IO_CHAIN (1 << 13) #define HWMOD_OPT_CLKS_NEEDED (1 << 14) +#define HWMOD_NO_IDLE (1 << 15) /* * omap_hwmod._int_flags definitions diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig index 918a3fa7e938..69261c70e1dd 100644 --- a/arch/arm/mach-qcom/Kconfig +++ b/arch/arm/mach-qcom/Kconfig @@ -1,10 +1,43 @@ if ARCH_QCOM menu "QCOM SoC Type" +config ARCH_MSMFALCON + bool "Enable Support for Qualcomm MSMFALCON" + select CLKDEV_LOOKUP + select HAVE_CLK + select HAVE_CLK_PREPARE + select PM_OPP + select SOC_BUS + select MSM_IRQ + select THERMAL_WRITABLE_TRIPS + select ARM_GIC_V3 + select ARM_AMBA + select SPARSE_IRQ + select MULTI_IRQ_HANDLER + select HAVE_ARM_ARCH_TIMER + select MAY_HAVE_SPARSE_IRQ + select PINCTRL_MSM_TLMM + select USE_PINCTRL_IRQ + select MSM_PM if PM + select QMI_ENCDEC + select CPU_FREQ + select CPU_FREQ_MSM + select PM_DEVFREQ + select MSM_DEVFREQ_DEVBW + select DEVFREQ_SIMPLE_DEV + select DEVFREQ_GOV_MSM_BW_HWMON + select MSM_BIMC_BWMON + select MSM_QDSP6V2_CODECS + select MSM_AUDIO_QDSP6V2 if SND_SOC + select MSM_RPM_SMD + select MSM_JTAGV8 if CORESIGHT_ETMV4 + help + This enables support for the MSMFALCON chipset. If you do not + wish to build a kernel that runs on this chipset, say 'N' here. + config ARCH_MSM8X60 bool "Enable support for MSM8X60" select ARCH_SUPPORTS_BIG_ENDIAN - select ARM_GIC select ARM_AMBA select QCOM_SCM if SMP select CLKSRC_QCOM @@ -15,7 +48,6 @@ config ARCH_MSM8960 bool "Enable support for MSM8960" select CLKSRC_QCOM select ARCH_SUPPORTS_BIG_ENDIAN - select ARM_GIC select ARM_AMBA select QCOM_SCM if SMP select CLKSRC_OF @@ -25,7 +57,6 @@ config ARCH_MSM8974 bool "Enable support for MSM8974" select HAVE_ARM_ARCH_TIMER select ARCH_SUPPORTS_BIG_ENDIAN - select ARM_GIC select ARM_AMBA select QCOM_SCM if SMP select CLKSRC_OF diff --git a/arch/arm/mach-qcom/Makefile b/arch/arm/mach-qcom/Makefile index 3d9f893ba3af..c5e30fff2b1e 100644 --- a/arch/arm/mach-qcom/Makefile +++ b/arch/arm/mach-qcom/Makefile @@ -1,3 +1,4 @@ obj-y := board.o obj-$(CONFIG_USE_OF) += board-dt.o +obj-$(CONFIG_ARCH_MSMFALCON) += board-falcon.o obj-$(CONFIG_SMP) += platsmp.o diff --git a/arch/arm/mach-qcom/board-falcon.c b/arch/arm/mach-qcom/board-falcon.c new file mode 100644 index 000000000000..e9374050b2cb --- /dev/null +++ b/arch/arm/mach-qcom/board-falcon.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <asm/mach/arch.h> +#include "board-dt.h" + +static const char *msmfalcon_dt_match[] __initconst = { + "qcom,msmfalcon", + "qcom,apqfalcon", + NULL +}; + +static void __init msmfalcon_init(void) +{ + board_dt_populate(NULL); +} + +DT_MACHINE_START(MSMFALCON_DT, + "Qualcomm Technologies, Inc. MSM FALCON (Flattened Device Tree)") + .init_machine = msmfalcon_init, + .dt_compat = msmfalcon_dt_match, +MACHINE_END diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index bf6a92504175..d41957eae6ef 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -2284,6 +2284,7 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, set_dma_ops(dev, dma_ops); } +EXPORT_SYMBOL(arch_setup_dma_ops); void arch_teardown_dma_ops(struct device *dev) { diff --git a/arch/arm/vdso/vdso.S b/arch/arm/vdso/vdso.S index b2b97e3e7bab..a62a7b64f49c 100644 --- a/arch/arm/vdso/vdso.S +++ b/arch/arm/vdso/vdso.S @@ -23,9 +23,8 @@ #include <linux/const.h> #include <asm/page.h> - __PAGE_ALIGNED_DATA - .globl vdso_start, vdso_end + .section .data..ro_after_init .balign PAGE_SIZE vdso_start: .incbin "arch/arm/vdso/vdso.so" diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 4e38de7ddd3e..711a73e401f7 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -56,12 +56,14 @@ config ARCH_QCOM select SOC_BUS select MSM_IRQ select THERMAL_WRITABLE_TRIPS + select RATIONAL help This enables support for the ARMv8 based Qualcomm chipsets. config ARCH_MSM8996 bool "Enable Support for Qualcomm MSM8996" depends on ARCH_QCOM + select COMMON_CLK_MSM help This enables support for the MSM8996 chipset. If you do not wish to build a kernel that runs on this chipset, say 'N' here. @@ -69,6 +71,7 @@ config ARCH_MSM8996 config ARCH_MSMCOBALT bool "Enable Support for Qualcomm MSMCOBALT" depends on ARCH_QCOM + select COMMON_CLK_MSM help This enables support for the MSMCOBALT chipset. If you do not wish to build a kernel that runs on this chipset, say 'N' here. @@ -76,6 +79,7 @@ config ARCH_MSMCOBALT config ARCH_MSMHAMSTER bool "Enable Support for Qualcomm Technologies Inc MSMHAMSTER" depends on ARCH_QCOM + select COMMON_CLK_MSM help This enables support for the MSMHAMSTER chipset. If you do not wish to build a kernel that runs @@ -84,6 +88,7 @@ config ARCH_MSMHAMSTER config ARCH_MSMFALCON bool "Enable Support for Qualcomm Technologies Inc MSMFALCON" depends on ARCH_QCOM + select COMMON_CLK_MSM help This enables support for the MSMFALCON chipset. If you do not wish to build a kernel that runs diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index a5c84594f6ad..285b32fa41c1 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -28,6 +28,7 @@ endif KBUILD_CFLAGS += -mgeneral-regs-only $(lseinstr) KBUILD_CFLAGS += -fno-pic +KBUILD_CFLAGS += $(call cc-option, -mpc-relative-literal-loads) KBUILD_AFLAGS += $(lseinstr) ifeq ($(CONFIG_CPU_BIG_ENDIAN), y) diff --git a/arch/arm64/configs/msm-perf_defconfig b/arch/arm64/configs/msm-perf_defconfig index 4569736834a5..f396b0b7f4cc 100644 --- a/arch/arm64/configs/msm-perf_defconfig +++ b/arch/arm64/configs/msm-perf_defconfig @@ -36,6 +36,9 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y CONFIG_PARTITION_ADVANCED=y CONFIG_ARCH_QCOM=y CONFIG_ARCH_MSM8996=y @@ -92,6 +95,7 @@ CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y +# CONFIG_NET_ACTIVITY_STATS is not set CONFIG_NETFILTER=y CONFIG_NF_CONNTRACK=y CONFIG_NF_CONNTRACK_SECMARK=y @@ -140,7 +144,6 @@ CONFIG_NETFILTER_XT_MATCH_MARK=y CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y -CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y @@ -228,7 +231,6 @@ CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_UID_STAT=y CONFIG_QSEECOM=y CONFIG_HDCP_QSEECOM=y CONFIG_UID_CPUTIME=y @@ -406,7 +408,10 @@ CONFIG_SND_SOC=y CONFIG_SND_SOC_MSM8996=y CONFIG_UHID=y CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y @@ -510,6 +515,7 @@ CONFIG_QCOM_SCM=y CONFIG_QCOM_SCM_XPU=y CONFIG_QCOM_WATCHDOG_V2=y CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_MSM_RUN_QUEUE_STATS=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_ADSP_LOADER=y CONFIG_MSM_PERFORMANCE=y @@ -565,7 +571,6 @@ CONFIG_CPU_FREQ_SWITCH_PROFILER=y CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_DEBUG_RODATA=y CONFIG_DEBUG_ALIGN_RODATA=y -CONFIG_KEYS=y CONFIG_PFK=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y @@ -573,7 +578,6 @@ CONFIG_SECURITY_SELINUX=y CONFIG_CRYPTO_ECHAINIV=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y -CONFIG_CRYPTO_SHA512=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCRYPTO=y diff --git a/arch/arm64/configs/msm_defconfig b/arch/arm64/configs/msm_defconfig index 9862bef3268d..c2902be72848 100644 --- a/arch/arm64/configs/msm_defconfig +++ b/arch/arm64/configs/msm_defconfig @@ -33,6 +33,9 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y CONFIG_PARTITION_ADVANCED=y CONFIG_ARCH_QCOM=y CONFIG_ARCH_MSM8996=y @@ -95,6 +98,7 @@ CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y +# CONFIG_NET_ACTIVITY_STATS is not set CONFIG_NETFILTER=y CONFIG_NF_CONNTRACK=y CONFIG_NF_CONNTRACK_SECMARK=y @@ -143,7 +147,6 @@ CONFIG_NETFILTER_XT_MATCH_MARK=y CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y -CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y @@ -221,7 +224,6 @@ CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_UID_STAT=y CONFIG_QSEECOM=y CONFIG_HDCP_QSEECOM=y CONFIG_UID_CPUTIME=y @@ -395,7 +397,10 @@ CONFIG_SND_SOC=y CONFIG_SND_SOC_MSM8996=y CONFIG_UHID=y CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y CONFIG_USB=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_EHCI_HCD=y @@ -511,6 +516,7 @@ CONFIG_QCOM_SCM=y CONFIG_QCOM_SCM_XPU=y CONFIG_QCOM_WATCHDOG_V2=y CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_MSM_RUN_QUEUE_STATS=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_ADSP_LOADER=y CONFIG_MSM_PERFORMANCE=y @@ -603,7 +609,6 @@ CONFIG_ARM64_PTDUMP=y CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_FREE_PAGES_RDONLY=y CONFIG_KERNEL_TEXT_RDONLY=y -CONFIG_KEYS=y CONFIG_PFK=y CONFIG_SECURITY=y CONFIG_SECURITY_SELINUX=y diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig index df423ad78631..be3e4ce1492a 100644 --- a/arch/arm64/configs/msmcortex-perf_defconfig +++ b/arch/arm64/configs/msmcortex-perf_defconfig @@ -35,6 +35,9 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y CONFIG_PARTITION_ADVANCED=y CONFIG_ARCH_QCOM=y CONFIG_ARCH_MSMCOBALT=y @@ -85,7 +88,6 @@ CONFIG_IP_PNP_DHCP=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y -# CONFIG_INET_LRO is not set CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y CONFIG_IPV6_OPTIMISTIC_DAD=y @@ -95,6 +97,7 @@ CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y +# CONFIG_NET_ACTIVITY_STATS is not set CONFIG_NETFILTER=y CONFIG_NF_CONNTRACK=y CONFIG_NF_CONNTRACK_SECMARK=y @@ -143,7 +146,6 @@ CONFIG_NETFILTER_XT_MATCH_MARK=y CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y -CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y @@ -222,7 +224,6 @@ CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_UID_STAT=y CONFIG_QSEECOM=y CONFIG_HDCP_QSEECOM=y CONFIG_SCSI=y @@ -319,6 +320,7 @@ CONFIG_QCOM_THERMAL_LIMITS_DCVS=y CONFIG_MFD_SPMI_PMIC=y CONFIG_MFD_I2C_PMIC=y CONFIG_WCD9335_CODEC=y +CONFIG_WCD934X_CODEC=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_RPM_SMD=y @@ -382,11 +384,16 @@ CONFIG_LOGO=y # CONFIG_LOGO_LINUX_VGA16 is not set CONFIG_SOUND=y CONFIG_SND=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_USB_AUDIO_QMI=y CONFIG_SND_SOC=y CONFIG_SND_SOC_MSMCOBALT=y CONFIG_UHID=y CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_XHCI_HCD=y @@ -483,7 +490,9 @@ CONFIG_QCOM_SCM=y CONFIG_QCOM_WATCHDOG_V2=y CONFIG_QCOM_MEMORY_DUMP_V2=y CONFIG_ICNSS=y +CONFIG_MSM_RUN_QUEUE_STATS=y CONFIG_MSM_BOOT_STATS=y +CONFIG_MSM_ADSP_LOADER=y CONFIG_MSM_PERFORMANCE=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y @@ -497,10 +506,13 @@ CONFIG_MSM_CORE_CTL_HELPER=y CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y CONFIG_MSM_RPM_LOG=y CONFIG_MSM_RPM_STATS_LOG=y +CONFIG_QSEE_IPC_IRQ_BRIDGE=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_SPDM_SCM=y +CONFIG_DEVFREQ_SPDM=y CONFIG_EXTCON=y CONFIG_IIO=y CONFIG_QCOM_RRADC=y @@ -534,7 +546,6 @@ CONFIG_CPU_FREQ_SWITCH_PROFILER=y CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_DEBUG_RODATA=y CONFIG_DEBUG_ALIGN_RODATA=y -CONFIG_KEYS=y CONFIG_PFK=y CONFIG_SECURITY=y CONFIG_SECURITY_SELINUX=y diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig index db5a2e854abe..2e9a7908307b 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -34,6 +34,9 @@ CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y # CONFIG_BLK_DEV_BSG is not set CONFIG_PARTITION_ADVANCED=y # CONFIG_IOSCHED_DEADLINE is not set @@ -86,7 +89,6 @@ CONFIG_IP_PNP_DHCP=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y -# CONFIG_INET_LRO is not set CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y CONFIG_IPV6_OPTIMISTIC_DAD=y @@ -96,6 +98,7 @@ CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y +# CONFIG_NET_ACTIVITY_STATS is not set CONFIG_NETFILTER=y CONFIG_NF_CONNTRACK=y CONFIG_NF_CONNTRACK_SECMARK=y @@ -144,7 +147,6 @@ CONFIG_NETFILTER_XT_MATCH_MARK=y CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y -CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y @@ -221,12 +223,10 @@ CONFIG_IPC_ROUTER=y CONFIG_IPC_ROUTER_SECURITY=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y CONFIG_DMA_CMA=y -CONFIG_CMA_SIZE_MBYTES=40 CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_UID_STAT=y CONFIG_QSEECOM=y CONFIG_HDCP_QSEECOM=y CONFIG_UID_CPUTIME=y @@ -325,6 +325,7 @@ CONFIG_QCOM_THERMAL_LIMITS_DCVS=y CONFIG_MFD_SPMI_PMIC=y CONFIG_MFD_I2C_PMIC=y CONFIG_WCD9335_CODEC=y +CONFIG_WCD934X_CODEC=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_RPM_SMD=y @@ -388,11 +389,16 @@ CONFIG_LOGO=y # CONFIG_LOGO_LINUX_VGA16 is not set CONFIG_SOUND=y CONFIG_SND=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_USB_AUDIO_QMI=y CONFIG_SND_SOC=y CONFIG_SND_SOC_MSMCOBALT=y CONFIG_UHID=y CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y CONFIG_USB=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_EHCI_HCD=y @@ -511,6 +517,7 @@ CONFIG_MSM_CORE_HANG_DETECT=y CONFIG_MSM_RUN_QUEUE_STATS=y CONFIG_MSM_BOOT_STATS=y CONFIG_QCOM_CPUSS_DUMP=y +CONFIG_MSM_ADSP_LOADER=y CONFIG_MSM_PERFORMANCE=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y @@ -525,10 +532,13 @@ CONFIG_MSM_SERVICE_NOTIFIER=y CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y CONFIG_MSM_RPM_LOG=y CONFIG_MSM_RPM_STATS_LOG=y +CONFIG_QSEE_IPC_IRQ_BRIDGE=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_SPDM_SCM=y +CONFIG_DEVFREQ_SPDM=y CONFIG_EXTCON=y CONFIG_IIO=y CONFIG_QCOM_RRADC=y @@ -620,7 +630,6 @@ CONFIG_CORESIGHT_TPDA=y CONFIG_CORESIGHT_TPDM=y CONFIG_CORESIGHT_QPDI=y CONFIG_CORESIGHT_SOURCE_DUMMY=y -CONFIG_KEYS=y CONFIG_PFK=y CONFIG_SECURITY=y CONFIG_SECURITY_SELINUX=y diff --git a/arch/arm64/include/asm/arch_gicv3.h b/arch/arm64/include/asm/arch_gicv3.h index 1cf33c338ec8..d925715c822f 100644 --- a/arch/arm64/include/asm/arch_gicv3.h +++ b/arch/arm64/include/asm/arch_gicv3.h @@ -104,7 +104,6 @@ static inline u64 gic_read_iar_common(void) asm volatile("mrs_s %0, " __stringify(ICC_IAR1_EL1) : "=r" (irqstat)); /* As per the architecture specification */ - isb(); mb(); return irqstat; } diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 63f52b55defe..eaa9cabf4066 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -34,7 +34,7 @@ /* * VMALLOC and SPARSEMEM_VMEMMAP ranges. * - * VMEMAP_SIZE: allows the whole VA space to be covered by a struct page array + * VMEMAP_SIZE: allows the whole linear region to be covered by a struct page array * (rounded up to PUD_SIZE). * VMALLOC_START: beginning of the kernel VA space * VMALLOC_END: extends to the available space below vmmemmap, PCI I/O space, @@ -51,7 +51,9 @@ #define VMALLOC_END (PAGE_OFFSET - PUD_SIZE - VMEMMAP_SIZE - SZ_64K) -#define vmemmap ((struct page *)(VMALLOC_END + SZ_64K)) +#define VMEMMAP_START (VMALLOC_END + SZ_64K) +#define vmemmap ((struct page *)VMEMMAP_START - \ + SECTION_ALIGN_DOWN(memstart_addr >> PAGE_SHIFT)) #define FIRST_USER_ADDRESS 0UL diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h index a3e9d6fdbf21..51b1c57c4443 100644 --- a/arch/arm64/include/asm/topology.h +++ b/arch/arm64/include/asm/topology.h @@ -21,6 +21,7 @@ extern struct cpu_topology cpu_topology[NR_CPUS]; void init_cpu_topology(void); void store_cpu_topology(unsigned int cpuid); const struct cpumask *cpu_coregroup_mask(int cpu); +unsigned long arch_get_cpu_efficiency(int cpu); #include <asm-generic/topology.h> diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c index 67fc833a26af..349b131baec3 100644 --- a/arch/arm64/kernel/topology.c +++ b/arch/arm64/kernel/topology.c @@ -215,6 +215,7 @@ unsigned long arch_get_cpu_efficiency(int cpu) { return per_cpu(cpu_efficiency, cpu); } +EXPORT_SYMBOL(arch_get_cpu_efficiency); /* * Iterate all CPUs' descriptor in DT and compute the efficiency diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index d250160d32bc..3039f080e2d5 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -186,7 +186,7 @@ static int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) u64 val; val = kvm_arm_timer_get_reg(vcpu, reg->id); - return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)); + return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)) ? -EFAULT : 0; } /** diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index e022cd8f274c..52406a2a39ad 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -321,8 +321,8 @@ void __init mem_init(void) #endif MLG(VMALLOC_START, VMALLOC_END), #ifdef CONFIG_SPARSEMEM_VMEMMAP - MLG((unsigned long)vmemmap, - (unsigned long)vmemmap + VMEMMAP_SIZE), + MLG(VMEMMAP_START, + VMEMMAP_START + VMEMMAP_SIZE), MLM((unsigned long)virt_to_page(PAGE_OFFSET), (unsigned long)virt_to_page(high_memory)), #endif diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 71683a853372..db459612de44 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2155,7 +2155,7 @@ config MIPS_MT_SMP select CPU_MIPSR2_IRQ_VI select CPU_MIPSR2_IRQ_EI select SYNC_R4K - select MIPS_GIC_IPI + select MIPS_GIC_IPI if MIPS_GIC select MIPS_MT select SMP select SMP_UP @@ -2253,7 +2253,7 @@ config MIPS_VPE_APSP_API_MT config MIPS_CMP bool "MIPS CMP framework support (DEPRECATED)" depends on SYS_SUPPORTS_MIPS_CMP && !CPU_MIPSR6 - select MIPS_GIC_IPI + select MIPS_GIC_IPI if MIPS_GIC select SMP select SYNC_R4K select SYS_SUPPORTS_SMP @@ -2273,7 +2273,7 @@ config MIPS_CPS select MIPS_CM select MIPS_CPC select MIPS_CPS_PM if HOTPLUG_CPU - select MIPS_GIC_IPI + select MIPS_GIC_IPI if MIPS_GIC select SMP select SYNC_R4K if (CEVT_R4K || CSRC_R4K) select SYS_SUPPORTS_HOTPLUG_CPU @@ -2292,6 +2292,7 @@ config MIPS_CPS_PM bool config MIPS_GIC_IPI + depends on MIPS_GIC bool config MIPS_CM diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h index 2046c0230224..21ed7150fec3 100644 --- a/arch/mips/include/asm/page.h +++ b/arch/mips/include/asm/page.h @@ -33,7 +33,7 @@ #define PAGE_SHIFT 16 #endif #define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) -#define PAGE_MASK (~(PAGE_SIZE - 1)) +#define PAGE_MASK (~((1 << PAGE_SHIFT) - 1)) /* * This is used for calculating the real page sizes diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h index 8957f15e21ec..18826aa15a7c 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h @@ -353,7 +353,7 @@ static inline pte_t pte_mkdirty(pte_t pte) static inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= _PAGE_ACCESSED; -#ifdef CONFIG_CPU_MIPSR2 +#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) if (!(pte_val(pte) & _PAGE_NO_READ)) pte_val(pte) |= _PAGE_SILENT_READ; else @@ -560,7 +560,7 @@ static inline pmd_t pmd_mkyoung(pmd_t pmd) { pmd_val(pmd) |= _PAGE_ACCESSED; -#ifdef CONFIG_CPU_MIPSR2 +#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) if (!(pmd_val(pmd) & _PAGE_NO_READ)) pmd_val(pmd) |= _PAGE_SILENT_READ; else diff --git a/arch/mips/include/asm/syscall.h b/arch/mips/include/asm/syscall.h index 6499d93ae68d..47bc45a67e9b 100644 --- a/arch/mips/include/asm/syscall.h +++ b/arch/mips/include/asm/syscall.h @@ -101,10 +101,8 @@ static inline void syscall_get_arguments(struct task_struct *task, /* O32 ABI syscall() - Either 64-bit with O32 or 32-bit */ if ((config_enabled(CONFIG_32BIT) || test_tsk_thread_flag(task, TIF_32BIT_REGS)) && - (regs->regs[2] == __NR_syscall)) { + (regs->regs[2] == __NR_syscall)) i++; - n++; - } while (n--) ret |= mips_get_syscall_arg(args++, task, regs, i++); diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index bd4385a8e6e8..2b521e07b860 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -121,6 +121,7 @@ static inline void calculate_cpu_foreign_map(void) cpumask_t temp_foreign_map; /* Re-calculate the mask */ + cpumask_clear(&temp_foreign_map); for_each_online_cpu(i) { core_present = 0; for_each_cpu(k, &temp_foreign_map) diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 886cb1976e90..ca9a81007489 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -690,15 +690,15 @@ static int simulate_sync(struct pt_regs *regs, unsigned int opcode) asmlinkage void do_ov(struct pt_regs *regs) { enum ctx_state prev_state; - siginfo_t info; + siginfo_t info = { + .si_signo = SIGFPE, + .si_code = FPE_INTOVF, + .si_addr = (void __user *)regs->cp0_epc, + }; prev_state = exception_enter(); die_if_kernel("Integer overflow", regs); - info.si_code = FPE_INTOVF; - info.si_signo = SIGFPE; - info.si_errno = 0; - info.si_addr = (void __user *) regs->cp0_epc; force_sig_info(SIGFPE, &info, current); exception_exit(prev_state); } @@ -874,7 +874,7 @@ out: void do_trap_or_bp(struct pt_regs *regs, unsigned int code, const char *str) { - siginfo_t info; + siginfo_t info = { 0 }; char b[40]; #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP @@ -903,7 +903,6 @@ void do_trap_or_bp(struct pt_regs *regs, unsigned int code, else info.si_code = FPE_INTOVF; info.si_signo = SIGFPE; - info.si_errno = 0; info.si_addr = (void __user *) regs->cp0_epc; force_sig_info(SIGFPE, &info, current); break; diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index b9b803facdbf..2683d04fdda5 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -702,7 +702,7 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu, } else if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U128) { void __user *uaddr = (void __user *)(long)reg->addr; - return copy_to_user(uaddr, vs, 16); + return copy_to_user(uaddr, vs, 16) ? -EFAULT : 0; } else { return -EINVAL; } @@ -732,7 +732,7 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu, } else if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U128) { void __user *uaddr = (void __user *)(long)reg->addr; - return copy_from_user(vs, uaddr, 16); + return copy_from_user(vs, uaddr, 16) ? -EFAULT : 0; } else { return -EINVAL; } diff --git a/arch/mips/loongson64/loongson-3/hpet.c b/arch/mips/loongson64/loongson-3/hpet.c index bf9f1a77f0e5..a2631a52ca99 100644 --- a/arch/mips/loongson64/loongson-3/hpet.c +++ b/arch/mips/loongson64/loongson-3/hpet.c @@ -13,6 +13,9 @@ #define SMBUS_PCI_REG64 0x64 #define SMBUS_PCI_REGB4 0xb4 +#define HPET_MIN_CYCLES 64 +#define HPET_MIN_PROG_DELTA (HPET_MIN_CYCLES + (HPET_MIN_CYCLES >> 1)) + static DEFINE_SPINLOCK(hpet_lock); DEFINE_PER_CPU(struct clock_event_device, hpet_clockevent_device); @@ -161,8 +164,9 @@ static int hpet_next_event(unsigned long delta, cnt += delta; hpet_write(HPET_T0_CMP, cnt); - res = ((int)(hpet_read(HPET_COUNTER) - cnt) > 0) ? -ETIME : 0; - return res; + res = (int)(cnt - hpet_read(HPET_COUNTER)); + + return res < HPET_MIN_CYCLES ? -ETIME : 0; } static irqreturn_t hpet_irq_handler(int irq, void *data) @@ -237,7 +241,7 @@ void __init setup_hpet_timer(void) cd->cpumask = cpumask_of(cpu); clockevent_set_clock(cd, HPET_FREQ); cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd); - cd->min_delta_ns = 5000; + cd->min_delta_ns = clockevent_delta2ns(HPET_MIN_PROG_DELTA, cd); clockevents_register_device(cd); setup_irq(HPET_T0_IRQ, &hpet_irq); diff --git a/arch/mips/loongson64/loongson-3/smp.c b/arch/mips/loongson64/loongson-3/smp.c index 1a4738a8f2d3..509832a9836c 100644 --- a/arch/mips/loongson64/loongson-3/smp.c +++ b/arch/mips/loongson64/loongson-3/smp.c @@ -30,13 +30,13 @@ #include "smp.h" DEFINE_PER_CPU(int, cpu_state); -DEFINE_PER_CPU(uint32_t, core0_c0count); static void *ipi_set0_regs[16]; static void *ipi_clear0_regs[16]; static void *ipi_status0_regs[16]; static void *ipi_en0_regs[16]; static void *ipi_mailbox_buf[16]; +static uint32_t core0_c0count[NR_CPUS]; /* read a 32bit value from ipi register */ #define loongson3_ipi_read32(addr) readl(addr) @@ -275,12 +275,14 @@ void loongson3_ipi_interrupt(struct pt_regs *regs) if (action & SMP_ASK_C0COUNT) { BUG_ON(cpu != 0); c0count = read_c0_count(); - for (i = 1; i < num_possible_cpus(); i++) - per_cpu(core0_c0count, i) = c0count; + c0count = c0count ? c0count : 1; + for (i = 1; i < nr_cpu_ids; i++) + core0_c0count[i] = c0count; + __wbflush(); /* Let others see the result ASAP */ } } -#define MAX_LOOPS 1111 +#define MAX_LOOPS 800 /* * SMP init and finish on secondary CPUs */ @@ -305,16 +307,20 @@ static void loongson3_init_secondary(void) cpu_logical_map(cpu) / loongson_sysconf.cores_per_package; i = 0; - __this_cpu_write(core0_c0count, 0); + core0_c0count[cpu] = 0; loongson3_send_ipi_single(0, SMP_ASK_C0COUNT); - while (!__this_cpu_read(core0_c0count)) { + while (!core0_c0count[cpu]) { i++; cpu_relax(); } if (i > MAX_LOOPS) i = MAX_LOOPS; - initcount = __this_cpu_read(core0_c0count) + i; + if (cpu_data[cpu].package) + initcount = core0_c0count[cpu] + i; + else /* Local access is faster for loops */ + initcount = core0_c0count[cpu] + i/2; + write_c0_count(initcount); } diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c index 3bd0597d9c3d..ddb8154610cc 100644 --- a/arch/mips/mm/sc-mips.c +++ b/arch/mips/mm/sc-mips.c @@ -164,11 +164,13 @@ static int __init mips_sc_probe_cm3(void) sets = cfg & CM_GCR_L2_CONFIG_SET_SIZE_MSK; sets >>= CM_GCR_L2_CONFIG_SET_SIZE_SHF; - c->scache.sets = 64 << sets; + if (sets) + c->scache.sets = 64 << sets; line_sz = cfg & CM_GCR_L2_CONFIG_LINE_SIZE_MSK; line_sz >>= CM_GCR_L2_CONFIG_LINE_SIZE_SHF; - c->scache.linesz = 2 << line_sz; + if (line_sz) + c->scache.linesz = 2 << line_sz; assoc = cfg & CM_GCR_L2_CONFIG_ASSOC_MSK; assoc >>= CM_GCR_L2_CONFIG_ASSOC_SHF; @@ -176,9 +178,12 @@ static int __init mips_sc_probe_cm3(void) c->scache.waysize = c->scache.sets * c->scache.linesz; c->scache.waybit = __ffs(c->scache.waysize); - c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT; + if (c->scache.linesz) { + c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT; + return 1; + } - return 1; + return 0; } void __weak platform_early_l2_init(void) diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index 32e0be27673f..29f73e00253d 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -242,7 +242,7 @@ static void output_pgtable_bits_defines(void) pr_define("_PAGE_HUGE_SHIFT %d\n", _PAGE_HUGE_SHIFT); pr_define("_PAGE_SPLITTING_SHIFT %d\n", _PAGE_SPLITTING_SHIFT); #endif -#ifdef CONFIG_CPU_MIPSR2 +#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) if (cpu_has_rixi) { #ifdef _PAGE_NO_EXEC_SHIFT pr_define("_PAGE_NO_EXEC_SHIFT %d\n", _PAGE_NO_EXEC_SHIFT); diff --git a/arch/parisc/include/asm/cache.h b/arch/parisc/include/asm/cache.h index 3d0e17bcc8e9..df0f52bd18b4 100644 --- a/arch/parisc/include/asm/cache.h +++ b/arch/parisc/include/asm/cache.h @@ -22,6 +22,9 @@ #define __read_mostly __attribute__((__section__(".data..read_mostly"))) +/* Read-only memory is marked before mark_rodata_ro() is called. */ +#define __ro_after_init __read_mostly + void parisc_cache_init(void); /* initializes cache-flushing */ void disable_sr_hashing_asm(int); /* low level support for above */ void disable_sr_hashing(void); /* turns off space register hashing */ diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h index 845272ce9cc5..7bd69bd43a01 100644 --- a/arch/parisc/include/asm/cacheflush.h +++ b/arch/parisc/include/asm/cacheflush.h @@ -121,10 +121,6 @@ flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vma } } -#ifdef CONFIG_DEBUG_RODATA -void mark_rodata_ro(void); -#endif - #include <asm/kmap_types.h> #define ARCH_HAS_KMAP diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c index 9585c81f755f..ce0b2b4075c7 100644 --- a/arch/parisc/kernel/ptrace.c +++ b/arch/parisc/kernel/ptrace.c @@ -269,14 +269,19 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, long do_syscall_trace_enter(struct pt_regs *regs) { - long ret = 0; - /* Do the secure computing check first. */ secure_computing_strict(regs->gr[20]); if (test_thread_flag(TIF_SYSCALL_TRACE) && - tracehook_report_syscall_entry(regs)) - ret = -1L; + tracehook_report_syscall_entry(regs)) { + /* + * Tracing decided this syscall should not happen or the + * debugger stored an invalid system call number. Skip + * the system call and the system call restart handling. + */ + regs->gr[20] = -1UL; + goto out; + } #ifdef CONFIG_64BIT if (!is_compat_task()) @@ -290,7 +295,8 @@ long do_syscall_trace_enter(struct pt_regs *regs) regs->gr[24] & 0xffffffff, regs->gr[23] & 0xffffffff); - return ret ? : regs->gr[20]; +out: + return regs->gr[20]; } void do_syscall_trace_exit(struct pt_regs *regs) diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S index 3fbd7252a4b2..fbafa0d0e2bf 100644 --- a/arch/parisc/kernel/syscall.S +++ b/arch/parisc/kernel/syscall.S @@ -343,7 +343,7 @@ tracesys_next: #endif comiclr,>>= __NR_Linux_syscalls, %r20, %r0 - b,n .Lsyscall_nosys + b,n .Ltracesys_nosys LDREGX %r20(%r19), %r19 @@ -359,6 +359,9 @@ tracesys_next: be 0(%sr7,%r19) ldo R%tracesys_exit(%r2),%r2 +.Ltracesys_nosys: + ldo -ENOSYS(%r0),%r28 /* set errno */ + /* Do *not* call this function on the gateway page, because it makes a direct call to syscall_trace. */ diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h index 8374afed9d0a..f8faaaeeca1e 100644 --- a/arch/powerpc/include/asm/opal-api.h +++ b/arch/powerpc/include/asm/opal-api.h @@ -157,7 +157,8 @@ #define OPAL_LEDS_GET_INDICATOR 114 #define OPAL_LEDS_SET_INDICATOR 115 #define OPAL_CEC_REBOOT2 116 -#define OPAL_LAST 116 +#define OPAL_CONSOLE_FLUSH 117 +#define OPAL_LAST 117 /* Device tree flags */ diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index 800115910e43..07a99e638449 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -35,6 +35,7 @@ int64_t opal_console_read(int64_t term_number, __be64 *length, uint8_t *buffer); int64_t opal_console_write_buffer_space(int64_t term_number, __be64 *length); +int64_t opal_console_flush(int64_t term_number); int64_t opal_rtc_read(__be32 *year_month_day, __be64 *hour_minute_second_millisecond); int64_t opal_rtc_write(uint32_t year_month_day, @@ -262,6 +263,8 @@ extern int opal_resync_timebase(void); extern void opal_lpc_init(void); +extern void opal_kmsg_init(void); + extern int opal_event_request(unsigned int opal_event_nr); struct opal_sg_list *opal_vmalloc_to_sg_list(void *vmalloc_addr, diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c index f69ecaa7ce33..52c1e273f8cd 100644 --- a/arch/powerpc/kernel/eeh_driver.c +++ b/arch/powerpc/kernel/eeh_driver.c @@ -418,8 +418,7 @@ static void *eeh_rmv_device(void *data, void *userdata) eeh_pcid_put(dev); if (driver->err_handler && driver->err_handler->error_detected && - driver->err_handler->slot_reset && - driver->err_handler->resume) + driver->err_handler->slot_reset) return NULL; } diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index 59663af9315f..e4f7d4eed20c 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c @@ -335,7 +335,7 @@ static void dedotify(Elf64_Sym *syms, unsigned int numsyms, char *strtab) if (syms[i].st_shndx == SHN_UNDEF) { char *name = strtab + syms[i].st_name; if (name[0] == '.') - memmove(name, name+1, strlen(name)); + syms[i].st_name++; } } } diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index e57cc383e5da..463af88c95a2 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -1370,6 +1370,20 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S) std r6, VCPU_ACOP(r9) stw r7, VCPU_GUEST_PID(r9) std r8, VCPU_WORT(r9) + /* + * Restore various registers to 0, where non-zero values + * set by the guest could disrupt the host. + */ + li r0, 0 + mtspr SPRN_IAMR, r0 + mtspr SPRN_CIABR, r0 + mtspr SPRN_DAWRX, r0 + mtspr SPRN_TCSCR, r0 + mtspr SPRN_WORT, r0 + /* Set MMCRS to 1<<31 to freeze and disable the SPMC counters */ + li r0, 1 + sldi r0, r0, 31 + mtspr SPRN_MMCRS, r0 8: /* Save and reset AMR and UAMOR before turning on the MMU */ diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile index 1c8cdb6250e7..b9de7ef48849 100644 --- a/arch/powerpc/platforms/powernv/Makefile +++ b/arch/powerpc/platforms/powernv/Makefile @@ -2,6 +2,7 @@ obj-y += setup.o opal-wrappers.o opal.o opal-async.o idle.o obj-y += opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o obj-y += rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o obj-y += opal-msglog.o opal-hmi.o opal-power.o opal-irqchip.o +obj-y += opal-kmsg.o obj-$(CONFIG_SMP) += smp.o subcore.o subcore-asm.o obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o pci-ioda.o diff --git a/arch/powerpc/platforms/powernv/opal-kmsg.c b/arch/powerpc/platforms/powernv/opal-kmsg.c new file mode 100644 index 000000000000..6f1214d4de92 --- /dev/null +++ b/arch/powerpc/platforms/powernv/opal-kmsg.c @@ -0,0 +1,75 @@ +/* + * kmsg dumper that ensures the OPAL console fully flushes panic messages + * + * Author: Russell Currey <ruscur@russell.cc> + * + * Copyright 2015 IBM Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/kmsg_dump.h> + +#include <asm/opal.h> +#include <asm/opal-api.h> + +/* + * Console output is controlled by OPAL firmware. The kernel regularly calls + * OPAL_POLL_EVENTS, which flushes some console output. In a panic state, + * however, the kernel no longer calls OPAL_POLL_EVENTS and the panic message + * may not be completely printed. This function does not actually dump the + * message, it just ensures that OPAL completely flushes the console buffer. + */ +static void force_opal_console_flush(struct kmsg_dumper *dumper, + enum kmsg_dump_reason reason) +{ + int i; + int64_t ret; + + /* + * Outside of a panic context the pollers will continue to run, + * so we don't need to do any special flushing. + */ + if (reason != KMSG_DUMP_PANIC) + return; + + if (opal_check_token(OPAL_CONSOLE_FLUSH)) { + ret = opal_console_flush(0); + + if (ret == OPAL_UNSUPPORTED || ret == OPAL_PARAMETER) + return; + + /* Incrementally flush until there's nothing left */ + while (opal_console_flush(0) != OPAL_SUCCESS); + } else { + /* + * If OPAL_CONSOLE_FLUSH is not implemented in the firmware, + * the console can still be flushed by calling the polling + * function enough times to flush the buffer. We don't know + * how much output still needs to be flushed, but we can be + * generous since the kernel is in panic and doesn't need + * to do much else. + */ + printk(KERN_NOTICE "opal: OPAL_CONSOLE_FLUSH missing.\n"); + for (i = 0; i < 1024; i++) { + opal_poll_events(NULL); + } + } +} + +static struct kmsg_dumper opal_kmsg_dumper = { + .dump = force_opal_console_flush +}; + +void __init opal_kmsg_init(void) +{ + int rc; + + /* Add our dumper to the list */ + rc = kmsg_dump_register(&opal_kmsg_dumper); + if (rc != 0) + pr_err("opal: kmsg_dump_register failed; returned %d\n", rc); +} diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S index b7a464fef7a7..e45b88a5d7e0 100644 --- a/arch/powerpc/platforms/powernv/opal-wrappers.S +++ b/arch/powerpc/platforms/powernv/opal-wrappers.S @@ -301,3 +301,4 @@ OPAL_CALL(opal_flash_erase, OPAL_FLASH_ERASE); OPAL_CALL(opal_prd_msg, OPAL_PRD_MSG); OPAL_CALL(opal_leds_get_ind, OPAL_LEDS_GET_INDICATOR); OPAL_CALL(opal_leds_set_ind, OPAL_LEDS_SET_INDICATOR); +OPAL_CALL(opal_console_flush, OPAL_CONSOLE_FLUSH); diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 57cffb80bc36..ae29eaf85e9e 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -758,6 +758,9 @@ static int __init opal_init(void) opal_pdev_init(opal_node, "ibm,opal-flash"); opal_pdev_init(opal_node, "ibm,opal-prd"); + /* Initialise OPAL kmsg dumper for flushing console on panic */ + opal_kmsg_init(); + return 0; } machine_subsys_initcall(powernv, opal_init); diff --git a/arch/s390/include/asm/fpu/internal.h b/arch/s390/include/asm/fpu/internal.h index 2559b16da525..17d9dcd29d45 100644 --- a/arch/s390/include/asm/fpu/internal.h +++ b/arch/s390/include/asm/fpu/internal.h @@ -48,6 +48,7 @@ static inline void convert_fp_to_vx(__vector128 *vxrs, freg_t *fprs) static inline void fpregs_store(_s390_fp_regs *fpregs, struct fpu *fpu) { fpregs->pad = 0; + fpregs->fpc = fpu->fpc; if (MACHINE_HAS_VX) convert_vx_to_fp((freg_t *)&fpregs->fprs, fpu->vxrs); else @@ -57,6 +58,7 @@ static inline void fpregs_store(_s390_fp_regs *fpregs, struct fpu *fpu) static inline void fpregs_load(_s390_fp_regs *fpregs, struct fpu *fpu) { + fpu->fpc = fpregs->fpc; if (MACHINE_HAS_VX) convert_fp_to_vx(fpu->vxrs, (freg_t *)&fpregs->fprs); else diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index efaac2c3bb77..e9a983f40a24 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -506,7 +506,6 @@ struct kvm_vcpu_arch { struct kvm_s390_sie_block *sie_block; unsigned int host_acrs[NUM_ACRS]; struct fpu host_fpregs; - struct fpu guest_fpregs; struct kvm_s390_local_interrupt local_int; struct hrtimer ckc_timer; struct kvm_s390_pgm_info pgm; diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h index fb1b93ea3e3f..e485817f7b1a 100644 --- a/arch/s390/include/asm/mmu_context.h +++ b/arch/s390/include/asm/mmu_context.h @@ -15,17 +15,25 @@ static inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm) { + spin_lock_init(&mm->context.list_lock); + INIT_LIST_HEAD(&mm->context.pgtable_list); + INIT_LIST_HEAD(&mm->context.gmap_list); cpumask_clear(&mm->context.cpu_attach_mask); atomic_set(&mm->context.attach_count, 0); mm->context.flush_mm = 0; - mm->context.asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS; - mm->context.asce_bits |= _ASCE_TYPE_REGION3; #ifdef CONFIG_PGSTE mm->context.alloc_pgste = page_table_allocate_pgste; mm->context.has_pgste = 0; mm->context.use_skey = 0; #endif - mm->context.asce_limit = STACK_TOP_MAX; + if (mm->context.asce_limit == 0) { + /* context created by exec, set asce limit to 4TB */ + mm->context.asce_bits = _ASCE_TABLE_LENGTH | + _ASCE_USER_BITS | _ASCE_TYPE_REGION3; + mm->context.asce_limit = STACK_TOP_MAX; + } else if (mm->context.asce_limit == (1UL << 31)) { + mm_inc_nr_pmds(mm); + } crst_table_init((unsigned long *) mm->pgd, pgd_entry_type(mm)); return 0; } @@ -111,8 +119,6 @@ static inline void activate_mm(struct mm_struct *prev, static inline void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) { - if (oldmm->context.asce_limit < mm->context.asce_limit) - crst_table_downgrade(mm, oldmm->context.asce_limit); } static inline void arch_exit_mmap(struct mm_struct *mm) diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h index 7b7858f158b4..d7cc79fb6191 100644 --- a/arch/s390/include/asm/pgalloc.h +++ b/arch/s390/include/asm/pgalloc.h @@ -100,12 +100,26 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) static inline pgd_t *pgd_alloc(struct mm_struct *mm) { - spin_lock_init(&mm->context.list_lock); - INIT_LIST_HEAD(&mm->context.pgtable_list); - INIT_LIST_HEAD(&mm->context.gmap_list); - return (pgd_t *) crst_table_alloc(mm); + unsigned long *table = crst_table_alloc(mm); + + if (!table) + return NULL; + if (mm->context.asce_limit == (1UL << 31)) { + /* Forking a compat process with 2 page table levels */ + if (!pgtable_pmd_page_ctor(virt_to_page(table))) { + crst_table_free(mm, table); + return NULL; + } + } + return (pgd_t *) table; +} + +static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) +{ + if (mm->context.asce_limit == (1UL << 31)) + pgtable_pmd_page_dtor(virt_to_page(pgd)); + crst_table_free(mm, (unsigned long *) pgd); } -#define pgd_free(mm, pgd) crst_table_free(mm, (unsigned long *) pgd) static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, pgtable_t pte) diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 9cd248f637c7..dc6c9c604543 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -181,6 +181,7 @@ int main(void) OFFSET(__LC_PSW_SAVE_AREA, _lowcore, psw_save_area); OFFSET(__LC_PREFIX_SAVE_AREA, _lowcore, prefixreg_save_area); OFFSET(__LC_FP_CREG_SAVE_AREA, _lowcore, fpt_creg_save_area); + OFFSET(__LC_TOD_PROGREG_SAVE_AREA, _lowcore, tod_progreg_save_area); OFFSET(__LC_CPU_TIMER_SAVE_AREA, _lowcore, cpu_timer_save_area); OFFSET(__LC_CLOCK_COMP_SAVE_AREA, _lowcore, clock_comp_save_area); OFFSET(__LC_AREGS_SAVE_AREA, _lowcore, access_regs_save_area); diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index 66c94417c0ba..4af60374eba0 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c @@ -271,7 +271,7 @@ static int restore_sigregs_ext32(struct pt_regs *regs, /* Restore high gprs from signal stack */ if (__copy_from_user(&gprs_high, &sregs_ext->gprs_high, - sizeof(&sregs_ext->gprs_high))) + sizeof(sregs_ext->gprs_high))) return -EFAULT; for (i = 0; i < NUM_GPRS; i++) *(__u32 *)®s->gprs[i] = gprs_high[i]; diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 846589281b04..575dc123bda2 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -1268,44 +1268,18 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) return 0; } -/* - * Backs up the current FP/VX register save area on a particular - * destination. Used to switch between different register save - * areas. - */ -static inline void save_fpu_to(struct fpu *dst) -{ - dst->fpc = current->thread.fpu.fpc; - dst->regs = current->thread.fpu.regs; -} - -/* - * Switches the FP/VX register save area from which to lazy - * restore register contents. - */ -static inline void load_fpu_from(struct fpu *from) -{ - current->thread.fpu.fpc = from->fpc; - current->thread.fpu.regs = from->regs; -} - void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) { /* Save host register state */ save_fpu_regs(); - save_fpu_to(&vcpu->arch.host_fpregs); - - if (test_kvm_facility(vcpu->kvm, 129)) { - current->thread.fpu.fpc = vcpu->run->s.regs.fpc; - /* - * Use the register save area in the SIE-control block - * for register restore and save in kvm_arch_vcpu_put() - */ - current->thread.fpu.vxrs = - (__vector128 *)&vcpu->run->s.regs.vrs; - } else - load_fpu_from(&vcpu->arch.guest_fpregs); + vcpu->arch.host_fpregs.fpc = current->thread.fpu.fpc; + vcpu->arch.host_fpregs.regs = current->thread.fpu.regs; + /* Depending on MACHINE_HAS_VX, data stored to vrs either + * has vector register or floating point register format. + */ + current->thread.fpu.regs = vcpu->run->s.regs.vrs; + current->thread.fpu.fpc = vcpu->run->s.regs.fpc; if (test_fp_ctl(current->thread.fpu.fpc)) /* User space provided an invalid FPC, let's clear it */ current->thread.fpu.fpc = 0; @@ -1321,19 +1295,13 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) atomic_andnot(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); gmap_disable(vcpu->arch.gmap); + /* Save guest register state */ save_fpu_regs(); + vcpu->run->s.regs.fpc = current->thread.fpu.fpc; - if (test_kvm_facility(vcpu->kvm, 129)) - /* - * kvm_arch_vcpu_load() set up the register save area to - * the &vcpu->run->s.regs.vrs and, thus, the vector registers - * are already saved. Only the floating-point control must be - * copied. - */ - vcpu->run->s.regs.fpc = current->thread.fpu.fpc; - else - save_fpu_to(&vcpu->arch.guest_fpregs); - load_fpu_from(&vcpu->arch.host_fpregs); + /* Restore host register state */ + current->thread.fpu.fpc = vcpu->arch.host_fpregs.fpc; + current->thread.fpu.regs = vcpu->arch.host_fpregs.regs; save_access_regs(vcpu->run->s.regs.acrs); restore_access_regs(vcpu->arch.host_acrs); @@ -1351,8 +1319,9 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu) memset(vcpu->arch.sie_block->gcr, 0, 16 * sizeof(__u64)); vcpu->arch.sie_block->gcr[0] = 0xE0UL; vcpu->arch.sie_block->gcr[14] = 0xC2000000UL; - vcpu->arch.guest_fpregs.fpc = 0; - asm volatile("lfpc %0" : : "Q" (vcpu->arch.guest_fpregs.fpc)); + /* make sure the new fpc will be lazily loaded */ + save_fpu_regs(); + current->thread.fpu.fpc = 0; vcpu->arch.sie_block->gbea = 1; vcpu->arch.sie_block->pp = 0; vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID; @@ -1501,19 +1470,6 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, vcpu->arch.local_int.wq = &vcpu->wq; vcpu->arch.local_int.cpuflags = &vcpu->arch.sie_block->cpuflags; - /* - * Allocate a save area for floating-point registers. If the vector - * extension is available, register contents are saved in the SIE - * control block. The allocated save area is still required in - * particular places, for example, in kvm_s390_vcpu_store_status(). - */ - vcpu->arch.guest_fpregs.fprs = kzalloc(sizeof(freg_t) * __NUM_FPRS, - GFP_KERNEL); - if (!vcpu->arch.guest_fpregs.fprs) { - rc = -ENOMEM; - goto out_free_sie_block; - } - rc = kvm_vcpu_init(vcpu, kvm, id); if (rc) goto out_free_sie_block; @@ -1734,19 +1690,27 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) { + /* make sure the new values will be lazily loaded */ + save_fpu_regs(); if (test_fp_ctl(fpu->fpc)) return -EINVAL; - memcpy(vcpu->arch.guest_fpregs.fprs, &fpu->fprs, sizeof(fpu->fprs)); - vcpu->arch.guest_fpregs.fpc = fpu->fpc; - save_fpu_regs(); - load_fpu_from(&vcpu->arch.guest_fpregs); + current->thread.fpu.fpc = fpu->fpc; + if (MACHINE_HAS_VX) + convert_fp_to_vx(current->thread.fpu.vxrs, (freg_t *)fpu->fprs); + else + memcpy(current->thread.fpu.fprs, &fpu->fprs, sizeof(fpu->fprs)); return 0; } int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) { - memcpy(&fpu->fprs, vcpu->arch.guest_fpregs.fprs, sizeof(fpu->fprs)); - fpu->fpc = vcpu->arch.guest_fpregs.fpc; + /* make sure we have the latest values */ + save_fpu_regs(); + if (MACHINE_HAS_VX) + convert_vx_to_fp((freg_t *)fpu->fprs, current->thread.fpu.vxrs); + else + memcpy(fpu->fprs, current->thread.fpu.fprs, sizeof(fpu->fprs)); + fpu->fpc = current->thread.fpu.fpc; return 0; } @@ -2266,41 +2230,50 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long gpa) { unsigned char archmode = 1; + freg_t fprs[NUM_FPRS]; unsigned int px; u64 clkcomp; int rc; + px = kvm_s390_get_prefix(vcpu); if (gpa == KVM_S390_STORE_STATUS_NOADDR) { if (write_guest_abs(vcpu, 163, &archmode, 1)) return -EFAULT; - gpa = SAVE_AREA_BASE; + gpa = 0; } else if (gpa == KVM_S390_STORE_STATUS_PREFIXED) { if (write_guest_real(vcpu, 163, &archmode, 1)) return -EFAULT; - gpa = kvm_s390_real_to_abs(vcpu, SAVE_AREA_BASE); + gpa = px; + } else + gpa -= __LC_FPREGS_SAVE_AREA; + + /* manually convert vector registers if necessary */ + if (MACHINE_HAS_VX) { + convert_vx_to_fp(fprs, (__vector128 *) vcpu->run->s.regs.vrs); + rc = write_guest_abs(vcpu, gpa + __LC_FPREGS_SAVE_AREA, + fprs, 128); + } else { + rc = write_guest_abs(vcpu, gpa + __LC_FPREGS_SAVE_AREA, + vcpu->run->s.regs.vrs, 128); } - rc = write_guest_abs(vcpu, gpa + offsetof(struct save_area, fp_regs), - vcpu->arch.guest_fpregs.fprs, 128); - rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, gp_regs), + rc |= write_guest_abs(vcpu, gpa + __LC_GPREGS_SAVE_AREA, vcpu->run->s.regs.gprs, 128); - rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, psw), + rc |= write_guest_abs(vcpu, gpa + __LC_PSW_SAVE_AREA, &vcpu->arch.sie_block->gpsw, 16); - px = kvm_s390_get_prefix(vcpu); - rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, pref_reg), + rc |= write_guest_abs(vcpu, gpa + __LC_PREFIX_SAVE_AREA, &px, 4); - rc |= write_guest_abs(vcpu, - gpa + offsetof(struct save_area, fp_ctrl_reg), - &vcpu->arch.guest_fpregs.fpc, 4); - rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, tod_reg), + rc |= write_guest_abs(vcpu, gpa + __LC_FP_CREG_SAVE_AREA, + &vcpu->run->s.regs.fpc, 4); + rc |= write_guest_abs(vcpu, gpa + __LC_TOD_PROGREG_SAVE_AREA, &vcpu->arch.sie_block->todpr, 4); - rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, timer), + rc |= write_guest_abs(vcpu, gpa + __LC_CPU_TIMER_SAVE_AREA, &vcpu->arch.sie_block->cputm, 8); clkcomp = vcpu->arch.sie_block->ckc >> 8; - rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, clk_cmp), + rc |= write_guest_abs(vcpu, gpa + __LC_CLOCK_COMP_SAVE_AREA, &clkcomp, 8); - rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, acc_regs), + rc |= write_guest_abs(vcpu, gpa + __LC_AREGS_SAVE_AREA, &vcpu->run->s.regs.acrs, 64); - rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, ctrl_regs), + rc |= write_guest_abs(vcpu, gpa + __LC_CREGS_SAVE_AREA, &vcpu->arch.sie_block->gcr, 128); return rc ? -EFAULT : 0; } @@ -2313,19 +2286,7 @@ int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr) * it into the save area */ save_fpu_regs(); - if (test_kvm_facility(vcpu->kvm, 129)) { - /* - * If the vector extension is available, the vector registers - * which overlaps with floating-point registers are saved in - * the SIE-control block. Hence, extract the floating-point - * registers and the FPC value and store them in the - * guest_fpregs structure. - */ - vcpu->arch.guest_fpregs.fpc = current->thread.fpu.fpc; - convert_vx_to_fp(vcpu->arch.guest_fpregs.fprs, - current->thread.fpu.vxrs); - } else - save_fpu_to(&vcpu->arch.guest_fpregs); + vcpu->run->s.regs.fpc = current->thread.fpu.fpc; save_access_regs(vcpu->run->s.regs.acrs); return kvm_s390_store_status_unloaded(vcpu, addr); diff --git a/arch/s390/mm/extable.c b/arch/s390/mm/extable.c index 4d1ee88864e8..18c8b819b0aa 100644 --- a/arch/s390/mm/extable.c +++ b/arch/s390/mm/extable.c @@ -52,12 +52,16 @@ void sort_extable(struct exception_table_entry *start, int i; /* Normalize entries to being relative to the start of the section */ - for (p = start, i = 0; p < finish; p++, i += 8) + for (p = start, i = 0; p < finish; p++, i += 8) { p->insn += i; + p->fixup += i + 4; + } sort(start, finish - start, sizeof(*start), cmp_ex, NULL); /* Denormalize all entries */ - for (p = start, i = 0; p < finish; p++, i += 8) + for (p = start, i = 0; p < finish; p++, i += 8) { p->insn -= i; + p->fixup -= i + 4; + } } #ifdef CONFIG_MODULES diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index 30e7ddb27a3a..c690c8e16a96 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c @@ -413,7 +413,7 @@ out: SYSCALL_DEFINE1(sparc64_personality, unsigned long, personality) { - int ret; + long ret; if (personality(current->personality) == PER_LINUX32 && personality(personality) == PER_LINUX) diff --git a/arch/um/configs/x86_64_um_defconfig b/arch/um/configs/x86_64_um_defconfig index 078e6d981acd..487b68bad250 100644 --- a/arch/um/configs/x86_64_um_defconfig +++ b/arch/um/configs/x86_64_um_defconfig @@ -655,7 +655,7 @@ CONFIG_IPV6_MULTIPLE_TABLES=y # CONFIG_IPV6_SUBTREES is not set # CONFIG_IPV6_MROUTE is not set # CONFIG_ANDROID_PARANOID_NETWORK is not set -CONFIG_NET_ACTIVITY_STATS=y +# CONFIG_NET_ACTIVITY_STATS is not set # CONFIG_NETWORK_SECMARK is not set # CONFIG_NET_PTP_CLASSIFY is not set # CONFIG_NETWORK_PHY_TIMESTAMPING is not set diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index 47f1ff056a54..22a358ef1b0c 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -94,6 +94,8 @@ static int start_ptraced_child(void) { int pid, n, status; + fflush(stdout); + pid = fork(); if (pid == 0) ptrace_child(); diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 136ddb36a046..d57eca6b3777 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -306,6 +306,9 @@ config ARCH_SUPPORTS_UPROBES config FIX_EARLYCON_MEM def_bool y +config DEBUG_RODATA + def_bool y + config PGTABLE_LEVELS int default 4 if X86_64 diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index 137dfa96aa14..1f6c306a9a00 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -91,28 +91,16 @@ config EFI_PGT_DUMP issues with the mapping of the EFI runtime regions into that table. -config DEBUG_RODATA - bool "Write protect kernel read-only data structures" - default y - depends on DEBUG_KERNEL - ---help--- - Mark the kernel read-only data as write-protected in the pagetables, - in order to catch accidental (and incorrect) writes to such const - data. This is recommended so that we can catch kernel bugs sooner. - If in doubt, say "Y". - config DEBUG_RODATA_TEST - bool "Testcase for the DEBUG_RODATA feature" - depends on DEBUG_RODATA + bool "Testcase for the marking rodata read-only" default y ---help--- - This option enables a testcase for the DEBUG_RODATA - feature as well as for the change_page_attr() infrastructure. + This option enables a testcase for the setting rodata read-only + as well as for the change_page_attr() infrastructure. If in doubt, say "N" config DEBUG_WX bool "Warn on W+X mappings at boot" - depends on DEBUG_RODATA select X86_PTDUMP_CORE ---help--- Generate a warning if any W+X mappings are found at boot. diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S index 6a1ae3751e82..15cfebaa7688 100644 --- a/arch/x86/entry/entry_64_compat.S +++ b/arch/x86/entry/entry_64_compat.S @@ -267,6 +267,7 @@ ENTRY(entry_INT80_compat) * Interrupts are off on entry. */ PARAVIRT_ADJUST_EXCEPTION_FRAME + ASM_CLAC /* Do this early to minimize exposure */ SWAPGS /* diff --git a/arch/x86/entry/vdso/vdso2c.h b/arch/x86/entry/vdso/vdso2c.h index 0224987556ce..3f69326ed545 100644 --- a/arch/x86/entry/vdso/vdso2c.h +++ b/arch/x86/entry/vdso/vdso2c.h @@ -140,7 +140,7 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len, fprintf(outfile, "#include <asm/vdso.h>\n"); fprintf(outfile, "\n"); fprintf(outfile, - "static unsigned char raw_data[%lu] __page_aligned_data = {", + "static unsigned char raw_data[%lu] __ro_after_init __aligned(PAGE_SIZE) = {", mapping_size); for (j = 0; j < stripped_len; j++) { if (j % 10 == 0) diff --git a/arch/x86/include/asm/cacheflush.h b/arch/x86/include/asm/cacheflush.h index e63aa38e85fb..61518cf79437 100644 --- a/arch/x86/include/asm/cacheflush.h +++ b/arch/x86/include/asm/cacheflush.h @@ -91,16 +91,10 @@ void clflush_cache_range(void *addr, unsigned int size); #define mmio_flush_range(addr, size) clflush_cache_range(addr, size) -#ifdef CONFIG_DEBUG_RODATA -void mark_rodata_ro(void); extern const int rodata_test_data; extern int kernel_set_to_readonly; void set_kernel_text_rw(void); void set_kernel_text_ro(void); -#else -static inline void set_kernel_text_rw(void) { } -static inline void set_kernel_text_ro(void) { } -#endif #ifdef CONFIG_DEBUG_RODATA_TEST int rodata_test(void); diff --git a/arch/x86/include/asm/irq.h b/arch/x86/include/asm/irq.h index 881b4768644a..e7de5c9a4fbd 100644 --- a/arch/x86/include/asm/irq.h +++ b/arch/x86/include/asm/irq.h @@ -23,11 +23,13 @@ extern void irq_ctx_init(int cpu); #define __ARCH_HAS_DO_SOFTIRQ +struct irq_desc; + #ifdef CONFIG_HOTPLUG_CPU #include <linux/cpumask.h> extern int check_irq_vectors_for_cpu_disable(void); extern void fixup_irqs(void); -extern void irq_force_complete_move(int); +extern void irq_force_complete_move(struct irq_desc *desc); #endif #ifdef CONFIG_HAVE_KVM @@ -37,7 +39,6 @@ extern void kvm_set_posted_intr_wakeup_handler(void (*handler)(void)); extern void (*x86_platform_ipi_callback)(void); extern void native_init_IRQ(void); -struct irq_desc; extern bool handle_irq(struct irq_desc *desc, struct pt_regs *regs); extern __visible unsigned int do_IRQ(struct pt_regs *regs); diff --git a/arch/x86/include/asm/kvm_para.h b/arch/x86/include/asm/kvm_para.h index c1adf33fdd0d..bc62e7cbf1b1 100644 --- a/arch/x86/include/asm/kvm_para.h +++ b/arch/x86/include/asm/kvm_para.h @@ -17,15 +17,8 @@ static inline bool kvm_check_and_clear_guest_paused(void) } #endif /* CONFIG_KVM_GUEST */ -#ifdef CONFIG_DEBUG_RODATA #define KVM_HYPERCALL \ ALTERNATIVE(".byte 0x0f,0x01,0xc1", ".byte 0x0f,0x01,0xd9", X86_FEATURE_VMMCALL) -#else -/* On AMD processors, vmcall will generate a trap that we will - * then rewrite to the appropriate instruction. - */ -#define KVM_HYPERCALL ".byte 0x0f,0x01,0xc1" -#endif /* For KVM hypercalls, a three-byte sequence of either the vmcall or the vmmcall * instruction. The hypervisor may replace it with something else but only the diff --git a/arch/x86/include/asm/sections.h b/arch/x86/include/asm/sections.h index 0a5242428659..13b6cdd0af57 100644 --- a/arch/x86/include/asm/sections.h +++ b/arch/x86/include/asm/sections.h @@ -7,7 +7,7 @@ extern char __brk_base[], __brk_limit[]; extern struct exception_table_entry __stop___ex_table[]; -#if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA) +#if defined(CONFIG_X86_64) extern char __end_rodata_hpage_align[]; #endif diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index d1daead5fcdd..adb3eaf8fe2a 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -16,6 +16,7 @@ #include <asm/cacheflush.h> #include <asm/realmode.h> +#include <linux/ftrace.h> #include "../../realmode/rm/wakeup.h" #include "sleep.h" @@ -107,7 +108,13 @@ int x86_acpi_suspend_lowlevel(void) saved_magic = 0x123456789abcdef0L; #endif /* CONFIG_64BIT */ + /* + * Pause/unpause graph tracing around do_suspend_lowlevel as it has + * inconsistent call/return info after it jumps to the wakeup vector. + */ + pause_graph_tracing(); do_suspend_lowlevel(); + unpause_graph_tracing(); return 0; } diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index f25321894ad2..fdb0fbfb1197 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -2521,6 +2521,7 @@ void __init setup_ioapic_dest(void) { int pin, ioapic, irq, irq_entry; const struct cpumask *mask; + struct irq_desc *desc; struct irq_data *idata; struct irq_chip *chip; @@ -2536,7 +2537,9 @@ void __init setup_ioapic_dest(void) if (irq < 0 || !mp_init_irq_at_boot(ioapic, irq)) continue; - idata = irq_get_irq_data(irq); + desc = irq_to_desc(irq); + raw_spin_lock_irq(&desc->lock); + idata = irq_desc_get_irq_data(desc); /* * Honour affinities which have been set in early boot @@ -2550,6 +2553,7 @@ void __init setup_ioapic_dest(void) /* Might be lapic_chip for irq 0 */ if (chip->irq_set_affinity) chip->irq_set_affinity(idata, mask, false); + raw_spin_unlock_irq(&desc->lock); } } #endif diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c index 861bc59c8f25..a35f6b5473f4 100644 --- a/arch/x86/kernel/apic/vector.c +++ b/arch/x86/kernel/apic/vector.c @@ -30,7 +30,7 @@ struct apic_chip_data { struct irq_domain *x86_vector_domain; static DEFINE_RAW_SPINLOCK(vector_lock); -static cpumask_var_t vector_cpumask; +static cpumask_var_t vector_cpumask, vector_searchmask, searched_cpumask; static struct irq_chip lapic_controller; #ifdef CONFIG_X86_IO_APIC static struct apic_chip_data *legacy_irq_data[NR_IRQS_LEGACY]; @@ -116,35 +116,47 @@ static int __assign_irq_vector(int irq, struct apic_chip_data *d, */ static int current_vector = FIRST_EXTERNAL_VECTOR + VECTOR_OFFSET_START; static int current_offset = VECTOR_OFFSET_START % 16; - int cpu, err; + int cpu, vector; - if (d->move_in_progress) + /* + * If there is still a move in progress or the previous move has not + * been cleaned up completely, tell the caller to come back later. + */ + if (d->move_in_progress || + cpumask_intersects(d->old_domain, cpu_online_mask)) return -EBUSY; /* Only try and allocate irqs on cpus that are present */ - err = -ENOSPC; cpumask_clear(d->old_domain); + cpumask_clear(searched_cpumask); cpu = cpumask_first_and(mask, cpu_online_mask); while (cpu < nr_cpu_ids) { - int new_cpu, vector, offset; + int new_cpu, offset; + /* Get the possible target cpus for @mask/@cpu from the apic */ apic->vector_allocation_domain(cpu, vector_cpumask, mask); + /* + * Clear the offline cpus from @vector_cpumask for searching + * and verify whether the result overlaps with @mask. If true, + * then the call to apic->cpu_mask_to_apicid_and() will + * succeed as well. If not, no point in trying to find a + * vector in this mask. + */ + cpumask_and(vector_searchmask, vector_cpumask, cpu_online_mask); + if (!cpumask_intersects(vector_searchmask, mask)) + goto next_cpu; + if (cpumask_subset(vector_cpumask, d->domain)) { - err = 0; if (cpumask_equal(vector_cpumask, d->domain)) - break; + goto success; /* - * New cpumask using the vector is a proper subset of - * the current in use mask. So cleanup the vector - * allocation for the members that are not used anymore. + * Mark the cpus which are not longer in the mask for + * cleanup. */ - cpumask_andnot(d->old_domain, d->domain, - vector_cpumask); - d->move_in_progress = - cpumask_intersects(d->old_domain, cpu_online_mask); - cpumask_and(d->domain, d->domain, vector_cpumask); - break; + cpumask_andnot(d->old_domain, d->domain, vector_cpumask); + vector = d->cfg.vector; + goto update; } vector = current_vector; @@ -156,45 +168,60 @@ next: vector = FIRST_EXTERNAL_VECTOR + offset; } - if (unlikely(current_vector == vector)) { - cpumask_or(d->old_domain, d->old_domain, - vector_cpumask); - cpumask_andnot(vector_cpumask, mask, d->old_domain); - cpu = cpumask_first_and(vector_cpumask, - cpu_online_mask); - continue; - } + /* If the search wrapped around, try the next cpu */ + if (unlikely(current_vector == vector)) + goto next_cpu; if (test_bit(vector, used_vectors)) goto next; - for_each_cpu_and(new_cpu, vector_cpumask, cpu_online_mask) { + for_each_cpu(new_cpu, vector_searchmask) { if (!IS_ERR_OR_NULL(per_cpu(vector_irq, new_cpu)[vector])) goto next; } /* Found one! */ current_vector = vector; current_offset = offset; - if (d->cfg.vector) { + /* Schedule the old vector for cleanup on all cpus */ + if (d->cfg.vector) cpumask_copy(d->old_domain, d->domain); - d->move_in_progress = - cpumask_intersects(d->old_domain, cpu_online_mask); - } - for_each_cpu_and(new_cpu, vector_cpumask, cpu_online_mask) + for_each_cpu(new_cpu, vector_searchmask) per_cpu(vector_irq, new_cpu)[vector] = irq_to_desc(irq); - d->cfg.vector = vector; - cpumask_copy(d->domain, vector_cpumask); - err = 0; - break; - } + goto update; - if (!err) { - /* cache destination APIC IDs into cfg->dest_apicid */ - err = apic->cpu_mask_to_apicid_and(mask, d->domain, - &d->cfg.dest_apicid); +next_cpu: + /* + * We exclude the current @vector_cpumask from the requested + * @mask and try again with the next online cpu in the + * result. We cannot modify @mask, so we use @vector_cpumask + * as a temporary buffer here as it will be reassigned when + * calling apic->vector_allocation_domain() above. + */ + cpumask_or(searched_cpumask, searched_cpumask, vector_cpumask); + cpumask_andnot(vector_cpumask, mask, searched_cpumask); + cpu = cpumask_first_and(vector_cpumask, cpu_online_mask); + continue; } + return -ENOSPC; - return err; +update: + /* + * Exclude offline cpus from the cleanup mask and set the + * move_in_progress flag when the result is not empty. + */ + cpumask_and(d->old_domain, d->old_domain, cpu_online_mask); + d->move_in_progress = !cpumask_empty(d->old_domain); + d->cfg.vector = vector; + cpumask_copy(d->domain, vector_cpumask); +success: + /* + * Cache destination APIC IDs into cfg->dest_apicid. This cannot fail + * as we already established, that mask & d->domain & cpu_online_mask + * is not empty. + */ + BUG_ON(apic->cpu_mask_to_apicid_and(mask, d->domain, + &d->cfg.dest_apicid)); + return 0; } static int assign_irq_vector(int irq, struct apic_chip_data *data, @@ -224,10 +251,8 @@ static int assign_irq_vector_policy(int irq, int node, static void clear_irq_vector(int irq, struct apic_chip_data *data) { struct irq_desc *desc; - unsigned long flags; int cpu, vector; - raw_spin_lock_irqsave(&vector_lock, flags); BUG_ON(!data->cfg.vector); vector = data->cfg.vector; @@ -237,10 +262,13 @@ static void clear_irq_vector(int irq, struct apic_chip_data *data) data->cfg.vector = 0; cpumask_clear(data->domain); - if (likely(!data->move_in_progress)) { - raw_spin_unlock_irqrestore(&vector_lock, flags); + /* + * If move is in progress or the old_domain mask is not empty, + * i.e. the cleanup IPI has not been processed yet, we need to remove + * the old references to desc from all cpus vector tables. + */ + if (!data->move_in_progress && cpumask_empty(data->old_domain)) return; - } desc = irq_to_desc(irq); for_each_cpu_and(cpu, data->old_domain, cpu_online_mask) { @@ -253,7 +281,6 @@ static void clear_irq_vector(int irq, struct apic_chip_data *data) } } data->move_in_progress = 0; - raw_spin_unlock_irqrestore(&vector_lock, flags); } void init_irq_alloc_info(struct irq_alloc_info *info, @@ -274,19 +301,24 @@ void copy_irq_alloc_info(struct irq_alloc_info *dst, struct irq_alloc_info *src) static void x86_vector_free_irqs(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs) { + struct apic_chip_data *apic_data; struct irq_data *irq_data; + unsigned long flags; int i; for (i = 0; i < nr_irqs; i++) { irq_data = irq_domain_get_irq_data(x86_vector_domain, virq + i); if (irq_data && irq_data->chip_data) { + raw_spin_lock_irqsave(&vector_lock, flags); clear_irq_vector(virq + i, irq_data->chip_data); - free_apic_chip_data(irq_data->chip_data); + apic_data = irq_data->chip_data; + irq_domain_reset_irq_data(irq_data); + raw_spin_unlock_irqrestore(&vector_lock, flags); + free_apic_chip_data(apic_data); #ifdef CONFIG_X86_IO_APIC if (virq + i < nr_legacy_irqs()) legacy_irq_data[virq + i] = NULL; #endif - irq_domain_reset_irq_data(irq_data); } } } @@ -404,6 +436,8 @@ int __init arch_early_irq_init(void) arch_init_htirq_domain(x86_vector_domain); BUG_ON(!alloc_cpumask_var(&vector_cpumask, GFP_KERNEL)); + BUG_ON(!alloc_cpumask_var(&vector_searchmask, GFP_KERNEL)); + BUG_ON(!alloc_cpumask_var(&searched_cpumask, GFP_KERNEL)); return arch_early_ioapic_init(); } @@ -492,14 +526,7 @@ static int apic_set_affinity(struct irq_data *irq_data, return -EINVAL; err = assign_irq_vector(irq, data, dest); - if (err) { - if (assign_irq_vector(irq, data, - irq_data_get_affinity_mask(irq_data))) - pr_err("Failed to recover vector for irq %d\n", irq); - return err; - } - - return IRQ_SET_MASK_OK; + return err ? err : IRQ_SET_MASK_OK; } static struct irq_chip lapic_controller = { @@ -511,20 +538,12 @@ static struct irq_chip lapic_controller = { #ifdef CONFIG_SMP static void __send_cleanup_vector(struct apic_chip_data *data) { - cpumask_var_t cleanup_mask; - - if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) { - unsigned int i; - - for_each_cpu_and(i, data->old_domain, cpu_online_mask) - apic->send_IPI_mask(cpumask_of(i), - IRQ_MOVE_CLEANUP_VECTOR); - } else { - cpumask_and(cleanup_mask, data->old_domain, cpu_online_mask); - apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR); - free_cpumask_var(cleanup_mask); - } + raw_spin_lock(&vector_lock); + cpumask_and(data->old_domain, data->old_domain, cpu_online_mask); data->move_in_progress = 0; + if (!cpumask_empty(data->old_domain)) + apic->send_IPI_mask(data->old_domain, IRQ_MOVE_CLEANUP_VECTOR); + raw_spin_unlock(&vector_lock); } void send_cleanup_vector(struct irq_cfg *cfg) @@ -568,12 +587,25 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void) goto unlock; /* - * Check if the irq migration is in progress. If so, we - * haven't received the cleanup request yet for this irq. + * Nothing to cleanup if irq migration is in progress + * or this cpu is not set in the cleanup mask. */ - if (data->move_in_progress) + if (data->move_in_progress || + !cpumask_test_cpu(me, data->old_domain)) goto unlock; + /* + * We have two cases to handle here: + * 1) vector is unchanged but the target mask got reduced + * 2) vector and the target mask has changed + * + * #1 is obvious, but in #2 we have two vectors with the same + * irq descriptor: the old and the new vector. So we need to + * make sure that we only cleanup the old vector. The new + * vector has the current @vector number in the config and + * this cpu is part of the target mask. We better leave that + * one alone. + */ if (vector == data->cfg.vector && cpumask_test_cpu(me, data->domain)) goto unlock; @@ -591,6 +623,7 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void) goto unlock; } __this_cpu_write(vector_irq[vector], VECTOR_UNUSED); + cpumask_clear_cpu(me, data->old_domain); unlock: raw_spin_unlock(&desc->lock); } @@ -619,12 +652,48 @@ void irq_complete_move(struct irq_cfg *cfg) __irq_complete_move(cfg, ~get_irq_regs()->orig_ax); } -void irq_force_complete_move(int irq) +/* + * Called with @desc->lock held and interrupts disabled. + */ +void irq_force_complete_move(struct irq_desc *desc) { - struct irq_cfg *cfg = irq_cfg(irq); + struct irq_data *irqdata = irq_desc_get_irq_data(desc); + struct apic_chip_data *data = apic_chip_data(irqdata); + struct irq_cfg *cfg = data ? &data->cfg : NULL; - if (cfg) - __irq_complete_move(cfg, cfg->vector); + if (!cfg) + return; + + __irq_complete_move(cfg, cfg->vector); + + /* + * This is tricky. If the cleanup of @data->old_domain has not been + * done yet, then the following setaffinity call will fail with + * -EBUSY. This can leave the interrupt in a stale state. + * + * The cleanup cannot make progress because we hold @desc->lock. So in + * case @data->old_domain is not yet cleaned up, we need to drop the + * lock and acquire it again. @desc cannot go away, because the + * hotplug code holds the sparse irq lock. + */ + raw_spin_lock(&vector_lock); + /* Clean out all offline cpus (including ourself) first. */ + cpumask_and(data->old_domain, data->old_domain, cpu_online_mask); + while (!cpumask_empty(data->old_domain)) { + raw_spin_unlock(&vector_lock); + raw_spin_unlock(&desc->lock); + cpu_relax(); + raw_spin_lock(&desc->lock); + /* + * Reevaluate apic_chip_data. It might have been cleared after + * we dropped @desc->lock. + */ + data = apic_chip_data(irqdata); + if (!data) + return; + raw_spin_lock(&vector_lock); + } + raw_spin_unlock(&vector_lock); } #endif diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 311bcf338f07..eb6bd34582c6 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -81,9 +81,9 @@ within(unsigned long addr, unsigned long start, unsigned long end) static unsigned long text_ip_addr(unsigned long ip) { /* - * On x86_64, kernel text mappings are mapped read-only with - * CONFIG_DEBUG_RODATA. So we use the kernel identity mapping instead - * of the kernel text mapping to modify the kernel text. + * On x86_64, kernel text mappings are mapped read-only, so we use + * the kernel identity mapping instead of the kernel text mapping + * to modify the kernel text. * * For 32bit kernels, these mappings are same and we can use * kernel identity mapping to modify code. diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c index f8062aaf5df9..61521dc19c10 100644 --- a/arch/x86/kernel/irq.c +++ b/arch/x86/kernel/irq.c @@ -462,7 +462,7 @@ void fixup_irqs(void) * non intr-remapping case, we can't wait till this interrupt * arrives at this cpu before completing the irq move. */ - irq_force_complete_move(irq); + irq_force_complete_move(desc); if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) { break_affinity = 1; @@ -470,6 +470,15 @@ void fixup_irqs(void) } chip = irq_data_get_irq_chip(data); + /* + * The interrupt descriptor might have been cleaned up + * already, but it is not yet removed from the radix tree + */ + if (!chip) { + raw_spin_unlock(&desc->lock); + continue; + } + if (!irqd_can_move_in_process_context(data) && chip->irq_mask) chip->irq_mask(data); diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index 44256a62702b..ed15cd486d06 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c @@ -750,9 +750,7 @@ void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip) int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt) { int err; -#ifdef CONFIG_DEBUG_RODATA char opc[BREAK_INSTR_SIZE]; -#endif /* CONFIG_DEBUG_RODATA */ bpt->type = BP_BREAKPOINT; err = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr, @@ -761,7 +759,6 @@ int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt) return err; err = probe_kernel_write((char *)bpt->bpt_addr, arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE); -#ifdef CONFIG_DEBUG_RODATA if (!err) return err; /* @@ -778,13 +775,12 @@ int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt) if (memcmp(opc, arch_kgdb_ops.gdb_bpt_instr, BREAK_INSTR_SIZE)) return -EINVAL; bpt->type = BP_POKE_BREAKPOINT; -#endif /* CONFIG_DEBUG_RODATA */ + return err; } int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt) { -#ifdef CONFIG_DEBUG_RODATA int err; char opc[BREAK_INSTR_SIZE]; @@ -801,8 +797,8 @@ int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt) if (err || memcmp(opc, bpt->saved_instr, BREAK_INSTR_SIZE)) goto knl_write; return err; + knl_write: -#endif /* CONFIG_DEBUG_RODATA */ return probe_kernel_write((char *)bpt->bpt_addr, (char *)bpt->saved_instr, BREAK_INSTR_SIZE); } diff --git a/arch/x86/kernel/test_nx.c b/arch/x86/kernel/test_nx.c index 3f92ce07e525..27538f183c3b 100644 --- a/arch/x86/kernel/test_nx.c +++ b/arch/x86/kernel/test_nx.c @@ -142,7 +142,6 @@ static int test_NX(void) * by the error message */ -#ifdef CONFIG_DEBUG_RODATA /* Test 3: Check if the .rodata section is executable */ if (rodata_test_data != 0xC3) { printk(KERN_ERR "test_nx: .rodata marker has invalid value\n"); @@ -151,7 +150,6 @@ static int test_NX(void) printk(KERN_ERR "test_nx: .rodata section is executable\n"); ret = -ENODEV; } -#endif #if 0 /* Test 4: Check if the .data section of a module is executable */ diff --git a/arch/x86/kernel/test_rodata.c b/arch/x86/kernel/test_rodata.c index 5ecbfe5099da..cb4a01b41e27 100644 --- a/arch/x86/kernel/test_rodata.c +++ b/arch/x86/kernel/test_rodata.c @@ -76,5 +76,5 @@ int rodata_test(void) } MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Testcase for the DEBUG_RODATA infrastructure"); +MODULE_DESCRIPTION("Testcase for marking rodata as read-only"); MODULE_AUTHOR("Arjan van de Ven <arjan@linux.intel.com>"); diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index 74e4bf11f562..fe133b710bef 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -41,29 +41,28 @@ ENTRY(phys_startup_64) jiffies_64 = jiffies; #endif -#if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA) +#if defined(CONFIG_X86_64) /* - * On 64-bit, align RODATA to 2MB so that even with CONFIG_DEBUG_RODATA - * we retain large page mappings for boundaries spanning kernel text, rodata - * and data sections. + * On 64-bit, align RODATA to 2MB so we retain large page mappings for + * boundaries spanning kernel text, rodata and data sections. * * However, kernel identity mappings will have different RWX permissions * to the pages mapping to text and to the pages padding (which are freed) the * text section. Hence kernel identity mappings will be broken to smaller * pages. For 64-bit, kernel text and kernel identity mappings are different, - * so we can enable protection checks that come with CONFIG_DEBUG_RODATA, - * as well as retain 2MB large page mappings for kernel text. + * so we can enable protection checks as well as retain 2MB large page + * mappings for kernel text. */ -#define X64_ALIGN_DEBUG_RODATA_BEGIN . = ALIGN(HPAGE_SIZE); +#define X64_ALIGN_RODATA_BEGIN . = ALIGN(HPAGE_SIZE); -#define X64_ALIGN_DEBUG_RODATA_END \ +#define X64_ALIGN_RODATA_END \ . = ALIGN(HPAGE_SIZE); \ __end_rodata_hpage_align = .; #else -#define X64_ALIGN_DEBUG_RODATA_BEGIN -#define X64_ALIGN_DEBUG_RODATA_END +#define X64_ALIGN_RODATA_BEGIN +#define X64_ALIGN_RODATA_END #endif @@ -112,13 +111,11 @@ SECTIONS EXCEPTION_TABLE(16) :text = 0x9090 -#if defined(CONFIG_DEBUG_RODATA) /* .text should occupy whole number of pages */ . = ALIGN(PAGE_SIZE); -#endif - X64_ALIGN_DEBUG_RODATA_BEGIN + X64_ALIGN_RODATA_BEGIN RO_DATA(PAGE_SIZE) - X64_ALIGN_DEBUG_RODATA_END + X64_ALIGN_RODATA_END /* Data */ .data : AT(ADDR(.data) - LOAD_OFFSET) { diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 1505587d06e9..b9b09fec173b 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -650,10 +650,10 @@ static __always_inline int __linearize(struct x86_emulate_ctxt *ctxt, u16 sel; la = seg_base(ctxt, addr.seg) + addr.ea; - *linear = la; *max_size = 0; switch (mode) { case X86EMUL_MODE_PROT64: + *linear = la; if (is_noncanonical_address(la)) goto bad; @@ -662,6 +662,7 @@ static __always_inline int __linearize(struct x86_emulate_ctxt *ctxt, goto bad; break; default: + *linear = la = (u32)la; usable = ctxt->ops->get_segment(ctxt, &sel, &desc, NULL, addr.seg); if (!usable) @@ -689,7 +690,6 @@ static __always_inline int __linearize(struct x86_emulate_ctxt *ctxt, if (size > *max_size) goto bad; } - la &= (u32)-1; break; } if (insn_aligned(ctxt, size) && ((la & (size - 1)) != 0)) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index e7c2c1428a69..8eb8a934b531 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -3754,13 +3754,15 @@ static void reset_rsvds_bits_mask_ept(struct kvm_vcpu *vcpu, void reset_shadow_zero_bits_mask(struct kvm_vcpu *vcpu, struct kvm_mmu *context) { + bool uses_nx = context->nx || context->base_role.smep_andnot_wp; + /* * Passing "true" to the last argument is okay; it adds a check * on bit 8 of the SPTEs which KVM doesn't use anyway. */ __reset_rsvds_bits_mask(vcpu, &context->shadow_zero_check, boot_cpu_data.x86_phys_bits, - context->shadow_root_level, context->nx, + context->shadow_root_level, uses_nx, guest_cpuid_has_gbpages(vcpu), is_pse(vcpu), true); } diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index 3058a22a658d..7be8a251363e 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h @@ -249,7 +249,7 @@ static int FNAME(update_accessed_dirty_bits)(struct kvm_vcpu *vcpu, return ret; kvm_vcpu_mark_page_dirty(vcpu, table_gfn); - walker->ptes[level] = pte; + walker->ptes[level - 1] = pte; } return 0; } diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 10e7693b3540..0958fa2b7cb7 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -595,6 +595,8 @@ struct vcpu_vmx { /* Support for PML */ #define PML_ENTITY_NUM 512 struct page *pml_pg; + + u64 current_tsc_ratio; }; enum segment_cache_field { @@ -1746,6 +1748,13 @@ static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr, return; } break; + case MSR_IA32_PEBS_ENABLE: + /* PEBS needs a quiescent period after being disabled (to write + * a record). Disabling PEBS through VMX MSR swapping doesn't + * provide that period, so a CPU could write host's record into + * guest's memory. + */ + wrmsrl(MSR_IA32_PEBS_ENABLE, 0); } for (i = 0; i < m->nr; ++i) @@ -1783,26 +1792,31 @@ static void reload_tss(void) static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset) { - u64 guest_efer; - u64 ignore_bits; + u64 guest_efer = vmx->vcpu.arch.efer; + u64 ignore_bits = 0; - guest_efer = vmx->vcpu.arch.efer; + if (!enable_ept) { + /* + * NX is needed to handle CR0.WP=1, CR4.SMEP=1. Testing + * host CPUID is more efficient than testing guest CPUID + * or CR4. Host SMEP is anyway a requirement for guest SMEP. + */ + if (boot_cpu_has(X86_FEATURE_SMEP)) + guest_efer |= EFER_NX; + else if (!(guest_efer & EFER_NX)) + ignore_bits |= EFER_NX; + } /* - * NX is emulated; LMA and LME handled by hardware; SCE meaningless - * outside long mode + * LMA and LME handled by hardware; SCE meaningless outside long mode. */ - ignore_bits = EFER_NX | EFER_SCE; + ignore_bits |= EFER_SCE; #ifdef CONFIG_X86_64 ignore_bits |= EFER_LMA | EFER_LME; /* SCE is meaningful only in long mode on Intel */ if (guest_efer & EFER_LMA) ignore_bits &= ~(u64)EFER_SCE; #endif - guest_efer &= ~ignore_bits; - guest_efer |= host_efer & ignore_bits; - vmx->guest_msrs[efer_offset].data = guest_efer; - vmx->guest_msrs[efer_offset].mask = ~ignore_bits; clear_atomic_switch_msr(vmx, MSR_EFER); @@ -1813,16 +1827,21 @@ static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset) */ if (cpu_has_load_ia32_efer || (enable_ept && ((vmx->vcpu.arch.efer ^ host_efer) & EFER_NX))) { - guest_efer = vmx->vcpu.arch.efer; if (!(guest_efer & EFER_LMA)) guest_efer &= ~EFER_LME; if (guest_efer != host_efer) add_atomic_switch_msr(vmx, MSR_EFER, guest_efer, host_efer); return false; - } + } else { + guest_efer &= ~ignore_bits; + guest_efer |= host_efer & ignore_bits; - return true; + vmx->guest_msrs[efer_offset].data = guest_efer; + vmx->guest_msrs[efer_offset].mask = ~ignore_bits; + + return true; + } } static unsigned long segment_base(u16 selector) @@ -2062,14 +2081,16 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp); vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */ - /* Setup TSC multiplier */ - if (cpu_has_vmx_tsc_scaling()) - vmcs_write64(TSC_MULTIPLIER, - vcpu->arch.tsc_scaling_ratio); - vmx->loaded_vmcs->cpu = cpu; } + /* Setup TSC multiplier */ + if (kvm_has_tsc_control && + vmx->current_tsc_ratio != vcpu->arch.tsc_scaling_ratio) { + vmx->current_tsc_ratio = vcpu->arch.tsc_scaling_ratio; + vmcs_write64(TSC_MULTIPLIER, vmx->current_tsc_ratio); + } + vmx_vcpu_pi_load(vcpu, cpu); } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 9a2ed8904513..d2945024ed33 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6544,12 +6544,12 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) * KVM_DEBUGREG_WONT_EXIT again. */ if (unlikely(vcpu->arch.switch_db_regs & KVM_DEBUGREG_WONT_EXIT)) { - int i; - WARN_ON(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP); kvm_x86_ops->sync_dirty_debug_regs(vcpu); - for (i = 0; i < KVM_NR_DB_REGS; i++) - vcpu->arch.eff_db[i] = vcpu->arch.db[i]; + kvm_update_dr0123(vcpu); + kvm_update_dr6(vcpu); + kvm_update_dr7(vcpu); + vcpu->arch.switch_db_regs &= ~KVM_DEBUGREG_RELOAD; } /* diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index cb4ef3de61f9..2ebfbaf61142 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c @@ -871,7 +871,6 @@ static noinline int do_test_wp_bit(void) return flag; } -#ifdef CONFIG_DEBUG_RODATA const int rodata_test_data = 0xC3; EXPORT_SYMBOL_GPL(rodata_test_data); @@ -960,5 +959,3 @@ void mark_rodata_ro(void) if (__supported_pte_mask & _PAGE_NX) debug_checkwx(); } -#endif - diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index ec081fe0ce2c..e08d141844ee 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -1062,7 +1062,6 @@ void __init mem_init(void) mem_init_print_info(NULL); } -#ifdef CONFIG_DEBUG_RODATA const int rodata_test_data = 0xC3; EXPORT_SYMBOL_GPL(rodata_test_data); @@ -1154,8 +1153,6 @@ void mark_rodata_ro(void) debug_checkwx(); } -#endif - int kern_addr_valid(unsigned long addr) { unsigned long above = ((long)addr) >> __VIRTUAL_MASK_SHIFT; diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c index b2fd67da1701..ef05755a1900 100644 --- a/arch/x86/mm/mpx.c +++ b/arch/x86/mm/mpx.c @@ -123,7 +123,7 @@ static int get_reg_offset(struct insn *insn, struct pt_regs *regs, break; } - if (regno > nr_registers) { + if (regno >= nr_registers) { WARN_ONCE(1, "decoded an instruction with an invalid register"); return -EINVAL; } diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index db20ee9a413a..4540e8880cd9 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -278,7 +278,7 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address, __pa_symbol(__end_rodata) >> PAGE_SHIFT)) pgprot_val(forbidden) |= _PAGE_RW; -#if defined(CONFIG_X86_64) && defined(CONFIG_DEBUG_RODATA) +#if defined(CONFIG_X86_64) /* * Once the kernel maps the text as RO (kernel_set_to_readonly is set), * kernel text mappings for the large page aligned text, rodata sections @@ -414,24 +414,30 @@ pmd_t *lookup_pmd_address(unsigned long address) phys_addr_t slow_virt_to_phys(void *__virt_addr) { unsigned long virt_addr = (unsigned long)__virt_addr; - unsigned long phys_addr, offset; + phys_addr_t phys_addr; + unsigned long offset; enum pg_level level; pte_t *pte; pte = lookup_address(virt_addr, &level); BUG_ON(!pte); + /* + * pXX_pfn() returns unsigned long, which must be cast to phys_addr_t + * before being left-shifted PAGE_SHIFT bits -- this trick is to + * make 32-PAE kernel work correctly. + */ switch (level) { case PG_LEVEL_1G: - phys_addr = pud_pfn(*(pud_t *)pte) << PAGE_SHIFT; + phys_addr = (phys_addr_t)pud_pfn(*(pud_t *)pte) << PAGE_SHIFT; offset = virt_addr & ~PUD_PAGE_MASK; break; case PG_LEVEL_2M: - phys_addr = pmd_pfn(*(pmd_t *)pte) << PAGE_SHIFT; + phys_addr = (phys_addr_t)pmd_pfn(*(pmd_t *)pte) << PAGE_SHIFT; offset = virt_addr & ~PMD_PAGE_MASK; break; default: - phys_addr = pte_pfn(*pte) << PAGE_SHIFT; + phys_addr = (phys_addr_t)pte_pfn(*pte) << PAGE_SHIFT; offset = virt_addr & ~PAGE_MASK; } diff --git a/block/bio.c b/block/bio.c index fd3159b2d4ac..b57f7818709d 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1091,9 +1091,12 @@ int bio_uncopy_user(struct bio *bio) if (!bio_flagged(bio, BIO_NULL_MAPPED)) { /* * if we're in a workqueue, the request is orphaned, so - * don't copy into a random user address space, just free. + * don't copy into a random user address space, just free + * and return -EINTR so user space doesn't expect any data. */ - if (current->mm && bio_data_dir(bio) == READ) + if (!current->mm) + ret = -EINTR; + else if (bio_data_dir(bio) == READ) ret = bio_copy_to_iter(bio, bmd->iter); if (bmd->is_our_pages) bio_free_pages(bio); diff --git a/block/blk-settings.c b/block/blk-settings.c index 77a482b88913..f9fcdf243a0a 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -91,8 +91,8 @@ void blk_set_default_limits(struct queue_limits *lim) lim->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK; lim->virt_boundary_mask = 0; lim->max_segment_size = BLK_MAX_SEGMENT_SIZE; - lim->max_sectors = lim->max_dev_sectors = lim->max_hw_sectors = - BLK_SAFE_MAX_SECTORS; + lim->max_sectors = lim->max_hw_sectors = BLK_SAFE_MAX_SECTORS; + lim->max_dev_sectors = 0; lim->chunk_sectors = 0; lim->max_write_same_sectors = 0; lim->max_discard_sectors = 0; diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 3405f7a41e25..5fdac394207a 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -465,6 +465,15 @@ static struct dmi_system_id video_dmi_table[] = { * as brightness control does not work. */ { + /* https://bugzilla.kernel.org/show_bug.cgi?id=21012 */ + .callback = video_disable_backlight_sysfs_if, + .ident = "Toshiba Portege R700", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R700"), + }, + }, + { /* https://bugs.freedesktop.org/show_bug.cgi?id=82634 */ .callback = video_disable_backlight_sysfs_if, .ident = "Toshiba Portege R830", @@ -473,6 +482,15 @@ static struct dmi_system_id video_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R830"), }, }, + { + /* https://bugzilla.kernel.org/show_bug.cgi?id=21012 */ + .callback = video_disable_backlight_sysfs_if, + .ident = "Toshiba Satellite R830", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE R830"), + }, + }, /* * Some machine's _DOD IDs don't have bit 31(Device ID Scheme) set * but the IDs actually follow the Device ID Scheme. diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index aa45d4802707..11d8209e6e5d 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c @@ -468,37 +468,16 @@ static void nfit_mem_find_spa_bdw(struct acpi_nfit_desc *acpi_desc, nfit_mem->bdw = NULL; } -static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc, +static void nfit_mem_init_bdw(struct acpi_nfit_desc *acpi_desc, struct nfit_mem *nfit_mem, struct acpi_nfit_system_address *spa) { u16 dcr = __to_nfit_memdev(nfit_mem)->region_index; struct nfit_memdev *nfit_memdev; struct nfit_flush *nfit_flush; - struct nfit_dcr *nfit_dcr; struct nfit_bdw *nfit_bdw; struct nfit_idt *nfit_idt; u16 idt_idx, range_index; - list_for_each_entry(nfit_dcr, &acpi_desc->dcrs, list) { - if (nfit_dcr->dcr->region_index != dcr) - continue; - nfit_mem->dcr = nfit_dcr->dcr; - break; - } - - if (!nfit_mem->dcr) { - dev_dbg(acpi_desc->dev, "SPA %d missing:%s%s\n", - spa->range_index, __to_nfit_memdev(nfit_mem) - ? "" : " MEMDEV", nfit_mem->dcr ? "" : " DCR"); - return -ENODEV; - } - - /* - * We've found enough to create an nvdimm, optionally - * find an associated BDW - */ - list_add(&nfit_mem->list, &acpi_desc->dimms); - list_for_each_entry(nfit_bdw, &acpi_desc->bdws, list) { if (nfit_bdw->bdw->region_index != dcr) continue; @@ -507,12 +486,12 @@ static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc, } if (!nfit_mem->bdw) - return 0; + return; nfit_mem_find_spa_bdw(acpi_desc, nfit_mem); if (!nfit_mem->spa_bdw) - return 0; + return; range_index = nfit_mem->spa_bdw->range_index; list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) { @@ -537,8 +516,6 @@ static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc, } break; } - - return 0; } static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc, @@ -547,7 +524,6 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc, struct nfit_mem *nfit_mem, *found; struct nfit_memdev *nfit_memdev; int type = nfit_spa_type(spa); - u16 dcr; switch (type) { case NFIT_SPA_DCR: @@ -558,14 +534,18 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc, } list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) { - int rc; + struct nfit_dcr *nfit_dcr; + u32 device_handle; + u16 dcr; if (nfit_memdev->memdev->range_index != spa->range_index) continue; found = NULL; dcr = nfit_memdev->memdev->region_index; + device_handle = nfit_memdev->memdev->device_handle; list_for_each_entry(nfit_mem, &acpi_desc->dimms, list) - if (__to_nfit_memdev(nfit_mem)->region_index == dcr) { + if (__to_nfit_memdev(nfit_mem)->device_handle + == device_handle) { found = nfit_mem; break; } @@ -578,6 +558,31 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc, if (!nfit_mem) return -ENOMEM; INIT_LIST_HEAD(&nfit_mem->list); + list_add(&nfit_mem->list, &acpi_desc->dimms); + } + + list_for_each_entry(nfit_dcr, &acpi_desc->dcrs, list) { + if (nfit_dcr->dcr->region_index != dcr) + continue; + /* + * Record the control region for the dimm. For + * the ACPI 6.1 case, where there are separate + * control regions for the pmem vs blk + * interfaces, be sure to record the extended + * blk details. + */ + if (!nfit_mem->dcr) + nfit_mem->dcr = nfit_dcr->dcr; + else if (nfit_mem->dcr->windows == 0 + && nfit_dcr->dcr->windows) + nfit_mem->dcr = nfit_dcr->dcr; + break; + } + + if (dcr && !nfit_mem->dcr) { + dev_err(acpi_desc->dev, "SPA %d missing DCR %d\n", + spa->range_index, dcr); + return -ENODEV; } if (type == NFIT_SPA_DCR) { @@ -594,6 +599,7 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc, nfit_mem->idt_dcr = nfit_idt->idt; break; } + nfit_mem_init_bdw(acpi_desc, nfit_mem, spa); } else { /* * A single dimm may belong to multiple SPA-PM @@ -602,13 +608,6 @@ static int nfit_mem_dcr_init(struct acpi_nfit_desc *acpi_desc, */ nfit_mem->memdev_pmem = nfit_memdev->memdev; } - - if (found) - continue; - - rc = nfit_mem_add(acpi_desc, nfit_mem, spa); - if (rc) - return rc; } return 0; diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index daaf1c4e1e0f..80e55cb0827b 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -135,14 +135,6 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"), }, }, - { - .callback = video_detect_force_vendor, - .ident = "Dell Inspiron 5737", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5737"), - }, - }, /* * These models have a working acpi_video backlight control, and using diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 6ccf8099c80b..4c67945ef36f 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -2089,7 +2089,7 @@ static int binder_thread_write(struct binder_proc *proc, if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); + ptr += sizeof(cookie); list_for_each_entry(w, &proc->delivered_death, entry) { struct binder_ref_death *tmp_death = container_of(w, struct binder_ref_death, work); diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 99921aa0daca..60a15831c009 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -367,15 +367,21 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */ { PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */ { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* Lewisburg RAID*/ + { PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Lewisburg AHCI*/ { PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* Lewisburg RAID*/ + { PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* Lewisburg RAID*/ { PCI_VDEVICE(INTEL, 0xa182), board_ahci }, /* Lewisburg AHCI*/ { PCI_VDEVICE(INTEL, 0xa184), board_ahci }, /* Lewisburg RAID*/ { PCI_VDEVICE(INTEL, 0xa186), board_ahci }, /* Lewisburg RAID*/ { PCI_VDEVICE(INTEL, 0xa18e), board_ahci }, /* Lewisburg RAID*/ + { PCI_VDEVICE(INTEL, 0xa1d2), board_ahci }, /* Lewisburg RAID*/ + { PCI_VDEVICE(INTEL, 0xa1d6), board_ahci }, /* Lewisburg RAID*/ { PCI_VDEVICE(INTEL, 0xa202), board_ahci }, /* Lewisburg AHCI*/ { PCI_VDEVICE(INTEL, 0xa204), board_ahci }, /* Lewisburg RAID*/ { PCI_VDEVICE(INTEL, 0xa206), board_ahci }, /* Lewisburg RAID*/ { PCI_VDEVICE(INTEL, 0xa20e), board_ahci }, /* Lewisburg RAID*/ + { PCI_VDEVICE(INTEL, 0xa252), board_ahci }, /* Lewisburg RAID*/ + { PCI_VDEVICE(INTEL, 0xa256), board_ahci }, /* Lewisburg RAID*/ /* JMicron 360/1/3/5/6, match class to avoid IDE function */ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 1f225cc1827f..998c6a85ad89 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1142,8 +1142,7 @@ static void ahci_port_init(struct device *dev, struct ata_port *ap, /* mark esata ports */ tmp = readl(port_mmio + PORT_CMD); - if ((tmp & PORT_CMD_HPCP) || - ((tmp & PORT_CMD_ESP) && (hpriv->cap & HOST_CAP_SXS))) + if ((tmp & PORT_CMD_ESP) && (hpriv->cap & HOST_CAP_SXS)) ap->pflags |= ATA_PFLAG_EXTERNAL; } diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 7e959f90c020..e417e1a1d02c 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -675,19 +675,18 @@ static int ata_ioc32(struct ata_port *ap) int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *scsidev, int cmd, void __user *arg) { - int val = -EINVAL, rc = -EINVAL; + unsigned long val; + int rc = -EINVAL; unsigned long flags; switch (cmd) { - case ATA_IOC_GET_IO32: + case HDIO_GET_32BIT: spin_lock_irqsave(ap->lock, flags); val = ata_ioc32(ap); spin_unlock_irqrestore(ap->lock, flags); - if (copy_to_user(arg, &val, 1)) - return -EFAULT; - return 0; + return put_user(val, (unsigned long __user *)arg); - case ATA_IOC_SET_IO32: + case HDIO_SET_32BIT: val = (unsigned long) arg; rc = 0; spin_lock_irqsave(ap->lock, flags); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index cdf6215a9a22..7dbba387d12a 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -997,12 +997,9 @@ static inline int ata_hsm_ok_in_wq(struct ata_port *ap, static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) { struct ata_port *ap = qc->ap; - unsigned long flags; if (ap->ops->error_handler) { if (in_wq) { - spin_lock_irqsave(ap->lock, flags); - /* EH might have kicked in while host lock is * released. */ @@ -1014,8 +1011,6 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) } else ata_port_freeze(ap); } - - spin_unlock_irqrestore(ap->lock, flags); } else { if (likely(!(qc->err_mask & AC_ERR_HSM))) ata_qc_complete(qc); @@ -1024,10 +1019,8 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) } } else { if (in_wq) { - spin_lock_irqsave(ap->lock, flags); ata_sff_irq_on(ap); ata_qc_complete(qc); - spin_unlock_irqrestore(ap->lock, flags); } else ata_qc_complete(qc); } @@ -1048,9 +1041,10 @@ int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, { struct ata_link *link = qc->dev->link; struct ata_eh_info *ehi = &link->eh_info; - unsigned long flags = 0; int poll_next; + lockdep_assert_held(ap->lock); + WARN_ON_ONCE((qc->flags & ATA_QCFLAG_ACTIVE) == 0); /* Make sure ata_sff_qc_issue() does not throw things @@ -1112,14 +1106,6 @@ fsm_start: } } - /* Send the CDB (atapi) or the first data block (ata pio out). - * During the state transition, interrupt handler shouldn't - * be invoked before the data transfer is complete and - * hsm_task_state is changed. Hence, the following locking. - */ - if (in_wq) - spin_lock_irqsave(ap->lock, flags); - if (qc->tf.protocol == ATA_PROT_PIO) { /* PIO data out protocol. * send first data block. @@ -1135,9 +1121,6 @@ fsm_start: /* send CDB */ atapi_send_cdb(ap, qc); - if (in_wq) - spin_unlock_irqrestore(ap->lock, flags); - /* if polling, ata_sff_pio_task() handles the rest. * otherwise, interrupt handler takes over from here. */ @@ -1361,12 +1344,14 @@ static void ata_sff_pio_task(struct work_struct *work) u8 status; int poll_next; + spin_lock_irq(ap->lock); + BUG_ON(ap->sff_pio_task_link == NULL); /* qc can be NULL if timeout occurred */ qc = ata_qc_from_tag(ap, link->active_tag); if (!qc) { ap->sff_pio_task_link = NULL; - return; + goto out_unlock; } fsm_start: @@ -1381,11 +1366,14 @@ fsm_start: */ status = ata_sff_busy_wait(ap, ATA_BUSY, 5); if (status & ATA_BUSY) { + spin_unlock_irq(ap->lock); ata_msleep(ap, 2); + spin_lock_irq(ap->lock); + status = ata_sff_busy_wait(ap, ATA_BUSY, 10); if (status & ATA_BUSY) { ata_sff_queue_pio_task(link, ATA_SHORT_PAUSE); - return; + goto out_unlock; } } @@ -1402,6 +1390,8 @@ fsm_start: */ if (poll_next) goto fsm_start; +out_unlock: + spin_unlock_irq(ap->lock); } /** diff --git a/drivers/ata/pata_rb532_cf.c b/drivers/ata/pata_rb532_cf.c index 12fe0f3bb7e9..c8b6a780a290 100644 --- a/drivers/ata/pata_rb532_cf.c +++ b/drivers/ata/pata_rb532_cf.c @@ -32,6 +32,8 @@ #include <linux/libata.h> #include <scsi/scsi_host.h> +#include <asm/mach-rc32434/rb.h> + #define DRV_NAME "pata-rb532-cf" #define DRV_VERSION "0.1.0" #define DRV_DESC "PATA driver for RouterBOARD 532 Compact Flash" @@ -107,6 +109,7 @@ static int rb532_pata_driver_probe(struct platform_device *pdev) int gpio; struct resource *res; struct ata_host *ah; + struct cf_device *pdata; struct rb532_cf_info *info; int ret; @@ -122,7 +125,13 @@ static int rb532_pata_driver_probe(struct platform_device *pdev) return -ENOENT; } - gpio = irq_to_gpio(irq); + pdata = dev_get_platdata(&pdev->dev); + if (!pdata) { + dev_err(&pdev->dev, "no platform data specified\n"); + return -EINVAL; + } + + gpio = pdata->gpio_pin; if (gpio < 0) { dev_err(&pdev->dev, "no GPIO found for irq%d\n", irq); return -ENOENT; diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index f16fa6cc23bc..8d456e3e42a0 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -667,6 +667,7 @@ void regmap_debugfs_init(struct regmap *map, const char *name) debugfs_create_x32("address", 0600, map->debugfs, &map->dump_address); + map->dump_count = 1; debugfs_create_u32("count", 0600, map->debugfs, &map->dump_count); debugfs_create_file("data", registers_mode, map->debugfs, diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c index 16378a195843..1317ddaa3c23 100644 --- a/drivers/bluetooth/bluetooth-power.c +++ b/drivers/bluetooth/bluetooth-power.c @@ -26,6 +26,7 @@ #include <linux/bluetooth-power.h> #include <linux/slab.h> #include <linux/regulator/consumer.h> +#include <linux/clk.h> #include <net/cnss.h> #include "btfm_slim.h" #include <linux/fs.h> @@ -169,6 +170,47 @@ static int bt_configure_vreg(struct bt_power_vreg_data *vreg) return rc; } +static int bt_clk_enable(struct bt_power_clk_data *clk) +{ + int rc = 0; + + BT_PWR_DBG("%s", clk->name); + + /* Get the clock handle for vreg */ + if (!clk->clk || clk->is_enabled) { + BT_PWR_ERR("error - node: %p, clk->is_enabled:%d", + clk->clk, clk->is_enabled); + return -EINVAL; + } + + rc = clk_prepare_enable(clk->clk); + if (rc) { + BT_PWR_ERR("failed to enable %s, rc(%d)\n", clk->name, rc); + return rc; + } + + clk->is_enabled = true; + return rc; +} + +static int bt_clk_disable(struct bt_power_clk_data *clk) +{ + int rc = 0; + + BT_PWR_DBG("%s", clk->name); + + /* Get the clock handle for vreg */ + if (!clk->clk || !clk->is_enabled) { + BT_PWR_ERR("error - node: %p, clk->is_enabled:%d", + clk->clk, clk->is_enabled); + return -EINVAL; + } + clk_disable_unprepare(clk->clk); + + clk->is_enabled = false; + return rc; +} + static int bt_configure_gpios(int on) { int rc = 0; @@ -252,6 +294,16 @@ static int bluetooth_power(int on) goto chip_pwd_fail; } } + /* Parse dt_info and check if a target requires clock voting. + * Enable BT clock when BT is on and disable it when BT is off + */ + if (bt_power_pdata->bt_chip_clk) { + rc = bt_clk_enable(bt_power_pdata->bt_chip_clk); + if (rc < 0) { + BT_PWR_ERR("bt_power gpio config failed"); + goto clk_fail; + } + } if (bt_power_pdata->bt_gpio_sys_rst > 0) { rc = bt_configure_gpios(on); if (rc < 0) { @@ -260,21 +312,31 @@ static int bluetooth_power(int on) } } } else { - bt_configure_gpios(on); + if (bt_power_pdata->bt_gpio_sys_rst > 0) + bt_configure_gpios(on); gpio_fail: if (bt_power_pdata->bt_gpio_sys_rst > 0) gpio_free(bt_power_pdata->bt_gpio_sys_rst); - bt_vreg_disable(bt_power_pdata->bt_chip_pwd); + if (bt_power_pdata->bt_chip_clk) + bt_clk_disable(bt_power_pdata->bt_chip_clk); +clk_fail: + if (bt_power_pdata->bt_chip_pwd) + bt_vreg_disable(bt_power_pdata->bt_chip_pwd); chip_pwd_fail: - bt_vreg_disable(bt_power_pdata->bt_vdd_ldo); + if (bt_power_pdata->bt_vdd_ldo) + bt_vreg_disable(bt_power_pdata->bt_vdd_ldo); vdd_ldo_fail: - bt_vreg_disable(bt_power_pdata->bt_vdd_pa); + if (bt_power_pdata->bt_vdd_pa) + bt_vreg_disable(bt_power_pdata->bt_vdd_pa); vdd_pa_fail: - bt_vreg_disable(bt_power_pdata->bt_vdd_core); + if (bt_power_pdata->bt_vdd_core) + bt_vreg_disable(bt_power_pdata->bt_vdd_core); vdd_core_fail: - bt_vreg_disable(bt_power_pdata->bt_vdd_xtal); + if (bt_power_pdata->bt_vdd_xtal) + bt_vreg_disable(bt_power_pdata->bt_vdd_xtal); vdd_xtal_fail: - bt_vreg_disable(bt_power_pdata->bt_vdd_io); + if (bt_power_pdata->bt_vdd_io) + bt_vreg_disable(bt_power_pdata->bt_vdd_io); } out: return rc; @@ -386,6 +448,7 @@ static int bt_dt_parse_vreg_info(struct device *dev, BT_PWR_DBG("vreg dev tree parse for %s", vreg_name); + *vreg_data = NULL; snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name); if (of_parse_phandle(np, prop_name, 0)) { vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL); @@ -431,6 +494,53 @@ err: return ret; } +static int bt_dt_parse_clk_info(struct device *dev, + struct bt_power_clk_data **clk_data) +{ + int ret = -EINVAL; + struct bt_power_clk_data *clk = NULL; + struct device_node *np = dev->of_node; + + BT_PWR_DBG(""); + + *clk_data = NULL; + if (of_parse_phandle(np, "clocks", 0)) { + clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL); + if (!clk) { + BT_PWR_ERR("No memory for clocks"); + ret = -ENOMEM; + goto err; + } + + /* Allocated 20 bytes size buffer for clock name string */ + clk->name = devm_kzalloc(dev, 20, GFP_KERNEL); + + /* Parse clock name from node */ + ret = of_property_read_string_index(np, "clock-names", 0, + &(clk->name)); + if (ret < 0) { + BT_PWR_ERR("reading \"clock-names\" failed"); + return ret; + } + + clk->clk = devm_clk_get(dev, clk->name); + if (IS_ERR(clk->clk)) { + ret = PTR_ERR(clk->clk); + BT_PWR_ERR("failed to get %s, ret (%d)", + clk->name, ret); + clk->clk = NULL; + return ret; + } + + *clk_data = clk; + } else { + BT_PWR_ERR("clocks is not provided in device tree"); + } + +err: + return ret; +} + static int bt_power_populate_dt_pinfo(struct platform_device *pdev) { int rc; @@ -482,6 +592,11 @@ static int bt_power_populate_dt_pinfo(struct platform_device *pdev) "qca,bt-chip-pwd"); if (rc < 0) BT_PWR_ERR("bt-chip-pwd not provided in device tree"); + + rc = bt_dt_parse_clk_info(&pdev->dev, + &bt_power_pdata->bt_chip_clk); + if (rc < 0) + BT_PWR_ERR("clock not provided in device tree"); } bt_power_pdata->bt_power_setup = bluetooth_power; diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 92f0ee388f9e..968897108c76 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -153,6 +153,10 @@ static const struct usb_device_id btusb_table[] = { { USB_VENDOR_AND_INTERFACE_INFO(0x13d3, 0xff, 0x01, 0x01), .driver_info = BTUSB_BCM_PATCHRAM }, + /* Toshiba Corp - Broadcom based */ + { USB_VENDOR_AND_INTERFACE_INFO(0x0930, 0xff, 0x01, 0x01), + .driver_info = BTUSB_BCM_PATCHRAM }, + /* Intel Bluetooth USB Bootloader (RAM module) */ { USB_DEVICE(0x8087, 0x0a5a), .driver_info = BTUSB_INTEL_BOOT | BTUSB_BROKEN_ISOC }, diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index e2a5d684ec18..d29192bfb9d0 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -63,6 +63,16 @@ #define IS_CACHE_ALIGNED(x) (((x) & ((L1_CACHE_BYTES)-1)) == 0) +#define FASTRPC_LINK_STATE_DOWN (0x0) +#define FASTRPC_LINK_STATE_UP (0x1) +#define FASTRPC_LINK_DISCONNECTED (0x0) +#define FASTRPC_LINK_CONNECTING (0x1) +#define FASTRPC_LINK_CONNECTED (0x3) +#define FASTRPC_LINK_DISCONNECTING (0x7) + +static int fastrpc_glink_open(int cid); +static void fastrpc_glink_close(void *chan, int cid); + static inline uint64_t buf_page_start(uint64_t buf) { uint64_t start = (uint64_t) buf & PAGE_MASK; @@ -161,6 +171,14 @@ struct fastrpc_session_ctx { int used; }; +struct fastrpc_glink_info { + int link_state; + int port_state; + struct glink_open_config cfg; + struct glink_link_info link_info; + void *link_notify_handle; +}; + struct fastrpc_channel_ctx { char *name; char *subsys; @@ -178,10 +196,7 @@ struct fastrpc_channel_ctx { int vmid; int ramdumpenabled; void *remoteheap_ramdump_dev; - struct glink_link_info link_info; - void *link_notify_handle; - struct glink_open_config cfg; - char *edge; + struct fastrpc_glink_info link; }; struct fastrpc_apps { @@ -244,13 +259,15 @@ static struct fastrpc_channel_ctx gcinfo[NUM_CHANNELS] = { .name = "adsprpc-smd", .subsys = "adsp", .channel = SMD_APPS_QDSP, - .edge = "lpass", + .link.link_info.edge = "lpass", + .link.link_info.transport = "smem", }, { .name = "sdsprpc-smd", .subsys = "dsps", .channel = SMD_APPS_DSPS, - .edge = "dsps", + .link.link_info.edge = "dsps", + .link.link_info.transport = "smem", .vmid = VMID_SSC_Q6, }, }; @@ -1719,16 +1736,14 @@ static void fastrpc_channel_close(struct kref *kref) int cid; ctx = container_of(kref, struct fastrpc_channel_ctx, kref); + cid = ctx - &gcinfo[0]; if (!me->glink) { smd_close(ctx->chan); } else { - glink_close(ctx->chan); - glink_unregister_link_state_cb(ctx->link_notify_handle); + fastrpc_glink_close(ctx->chan, cid); } ctx->chan = 0; - ctx->link_notify_handle = NULL; mutex_unlock(&me->smd_mutex); - cid = ctx - &gcinfo[0]; pr_info("'closed /dev/%s c %d %d'\n", gcinfo[cid].name, MAJOR(me->dev_no), cid); } @@ -1796,16 +1811,26 @@ void fastrpc_glink_notify_state(void *handle, const void *priv, unsigned event) { struct fastrpc_apps *me = &gfa; int cid = (int)(uintptr_t)priv; + struct fastrpc_glink_info *link; + if (cid < 0 || cid >= NUM_CHANNELS) + return; + link = &me->channel[cid].link; switch (event) { case GLINK_CONNECTED: + link->port_state = FASTRPC_LINK_CONNECTED; complete(&me->channel[cid].work); break; case GLINK_LOCAL_DISCONNECTED: + link->port_state = FASTRPC_LINK_DISCONNECTED; fastrpc_notify_drivers(me, cid); + if (link->link_state == FASTRPC_LINK_STATE_UP) + fastrpc_glink_open(cid); break; case GLINK_REMOTE_DISCONNECTED: - fastrpc_notify_drivers(me, cid); + fastrpc_glink_close(me->channel[cid].chan, cid); + break; + default: break; } } @@ -1875,46 +1900,99 @@ static int fastrpc_device_release(struct inode *inode, struct file *file) return 0; } -static void fastrpc_glink_register_cb(struct glink_link_state_cb_info *cb_info, +static void fastrpc_link_state_handler(struct glink_link_state_cb_info *cb_info, void *priv) { + struct fastrpc_apps *me = &gfa; + int cid = (int)((uintptr_t)priv); + struct fastrpc_glink_info *link; + + if (cid < 0 || cid >= NUM_CHANNELS) + return; + + link = &me->channel[cid].link; switch (cb_info->link_state) { case GLINK_LINK_STATE_UP: - if (priv) - complete(priv); + link->link_state = FASTRPC_LINK_STATE_UP; + complete(&me->channel[cid].work); break; case GLINK_LINK_STATE_DOWN: + link->link_state = FASTRPC_LINK_STATE_DOWN; break; default: - pr_err("adsprpc: unknown glnk state %d\n", cb_info->link_state); + pr_err("adsprpc: unknown link state %d\n", cb_info->link_state); break; } } -static int fastrpc_glink_open(int cid, struct fastrpc_apps *me) +static int fastrpc_glink_register(int cid, struct fastrpc_apps *me) { int err = 0; - void *handle = NULL; - struct glink_open_config *cfg = &me->channel[cid].cfg; - struct glink_link_info *link_info = &me->channel[cid].link_info; - - link_info->edge = gcinfo[cid].edge; - link_info->transport = "smem"; - link_info->glink_link_state_notif_cb = fastrpc_glink_register_cb; - me->channel[cid].link_notify_handle = glink_register_link_state_cb( - &me->channel[cid].link_info, - (void *)(&me->channel[cid].work)); - VERIFY(err, !IS_ERR_OR_NULL(me->channel[cid].link_notify_handle)); + struct fastrpc_glink_info *link; + + VERIFY(err, (cid >= 0 && cid < NUM_CHANNELS)); if (err) goto bail; + link = &me->channel[cid].link; + if (link->link_notify_handle != NULL) + goto bail; + + link->link_info.glink_link_state_notif_cb = fastrpc_link_state_handler; + link->link_notify_handle = glink_register_link_state_cb( + &link->link_info, + (void *)((uintptr_t)cid)); + VERIFY(err, !IS_ERR_OR_NULL(me->channel[cid].link.link_notify_handle)); + if (err) { + link->link_notify_handle = NULL; + goto bail; + } VERIFY(err, wait_for_completion_timeout(&me->channel[cid].work, - RPC_TIMEOUT)); + RPC_TIMEOUT)); +bail: + return err; +} + +static void fastrpc_glink_close(void *chan, int cid) +{ + int err = 0; + struct fastrpc_glink_info *link; + + VERIFY(err, (cid >= 0 && cid < NUM_CHANNELS)); + if (err) + return; + link = &gfa.channel[cid].link; + if (link->port_state == FASTRPC_LINK_CONNECTED) { + link->port_state = FASTRPC_LINK_DISCONNECTING; + glink_close(chan); + } +} + +static int fastrpc_glink_open(int cid) +{ + int err = 0; + void *handle = NULL; + struct fastrpc_apps *me = &gfa; + struct glink_open_config *cfg; + struct fastrpc_glink_info *link; + + VERIFY(err, (cid >= 0 && cid < NUM_CHANNELS)); + if (err) + goto bail; + link = &me->channel[cid].link; + cfg = &me->channel[cid].link.cfg; + VERIFY(err, (link->link_state == FASTRPC_LINK_STATE_UP)); if (err) goto bail; + if (link->port_state == FASTRPC_LINK_CONNECTED || + link->port_state == FASTRPC_LINK_CONNECTING) { + goto bail; + } + + link->port_state = FASTRPC_LINK_CONNECTING; cfg->priv = (void *)(uintptr_t)cid; - cfg->edge = gcinfo[cid].edge; + cfg->edge = gcinfo[cid].link.link_info.edge; cfg->name = FASTRPC_GLINK_GUID; cfg->notify_rx = fastrpc_glink_notify_rx; cfg->notify_tx_done = fastrpc_glink_notify_tx_done; @@ -1961,7 +2039,8 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) if ((kref_get_unless_zero(&me->channel[cid].kref) == 0) || (me->channel[cid].chan == 0)) { if (me->glink) { - VERIFY(err, 0 == fastrpc_glink_open(cid, me)); + fastrpc_glink_register(cid, me); + VERIFY(err, 0 == fastrpc_glink_open(cid)); } else { VERIFY(err, !smd_named_open_on_edge(FASTRPC_SMD_GUID, gcinfo[cid].channel, @@ -2124,14 +2203,11 @@ static int fastrpc_restart_notifier_cb(struct notifier_block *nb, ctx->ssrcount++; if (ctx->chan) { if (me->glink) { - glink_close(ctx->chan); - glink_unregister_link_state_cb( - ctx->link_notify_handle); + fastrpc_glink_close(ctx->chan, cid); } else { smd_close(ctx->chan); } ctx->chan = 0; - ctx->link_notify_handle = NULL; pr_info("'restart notifier: closed /dev/%s c %d %d'\n", gcinfo[cid].name, MAJOR(me->dev_no), cid); } @@ -2356,7 +2432,6 @@ static int fastrpc_probe(struct platform_device *pdev) } me->glink = of_property_read_bool(dev->of_node, "qcom,fastrpc-glink"); - pr_debug("adsprpc: channel link type: %d\n", me->glink); VERIFY(err, !of_platform_populate(pdev->dev.of_node, fastrpc_match_table, diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index cd54a184e997..ed763c7e98fc 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1955,6 +1955,18 @@ bool clk_is_match(const struct clk *p, const struct clk *q) } EXPORT_SYMBOL_GPL(clk_is_match); +int clk_set_flags(struct clk *clk, unsigned long flags) +{ + if (!clk) + return 0; + + if (!clk->core->ops->set_flags) + return -EINVAL; + + return clk->core->ops->set_flags(clk->core->hw, flags); +} +EXPORT_SYMBOL_GPL(clk_set_flags); + /*** debugfs support ***/ #ifdef CONFIG_DEBUG_FS diff --git a/drivers/clk/msm/Kconfig b/drivers/clk/msm/Kconfig index 17102dd1b3d1..d94678e9e4fc 100644 --- a/drivers/clk/msm/Kconfig +++ b/drivers/clk/msm/Kconfig @@ -1,5 +1,16 @@ +config COMMON_CLK_MSM + tristate "Support for MSM clock controllers" + depends on OF + depends on ARCH_QCOM + help + This support clock controller used by MSM devices which support + global, mmss and gpu clock controller. + Say Y if you want to support the clocks exposed by the MSM on + platforms such as msm8996, msmcobalt, msmfalcon etc. + config MSM_CLK_CONTROLLER_V2 bool "QTI clock driver" + depends on COMMON_CLK_MSM ---help--- Generate clock data structures from definitions found in device tree. diff --git a/drivers/clk/msm/Makefile b/drivers/clk/msm/Makefile index cd652c691ca3..daf0b81c9663 100644 --- a/drivers/clk/msm/Makefile +++ b/drivers/clk/msm/Makefile @@ -1,28 +1,30 @@ -obj-y += clock.o -obj-y += clock-dummy.o -obj-y += clock-generic.o -obj-y += clock-local2.o -obj-y += clock-pll.o -obj-y += clock-alpha-pll.o -obj-y += clock-rpm.o -obj-y += clock-voter.o +obj-$(CONFIG_COMMON_CLK_MSM) += clock.o +obj-$(CONFIG_COMMON_CLK_MSM) += clock-dummy.o +obj-$(CONFIG_COMMON_CLK_MSM) += clock-generic.o +obj-$(CONFIG_COMMON_CLK_MSM) += clock-local2.o +obj-$(CONFIG_COMMON_CLK_MSM) += clock-pll.o +obj-$(CONFIG_COMMON_CLK_MSM) += clock-alpha-pll.o +obj-$(CONFIG_COMMON_CLK_MSM) += clock-rpm.o +obj-$(CONFIG_COMMON_CLK_MSM) += clock-voter.o obj-$(CONFIG_MSM_CLK_CONTROLLER_V2) += msm-clock-controller.o -obj-y += clock-debug.o +obj-$(CONFIG_COMMON_CLK_MSM) += clock-debug.o # MSM 8996 -obj-$(CONFIG_ARCH_QCOM) += clock-gcc-8996.o -obj-$(CONFIG_ARCH_QCOM) += clock-mmss-8996.o -obj-$(CONFIG_ARCH_QCOM) += clock-cpu-8996.o +ifeq ($(CONFIG_COMMON_CLK_MSM), y) + obj-$(CONFIG_ARCH_QCOM) += clock-gcc-8996.o + obj-$(CONFIG_ARCH_QCOM) += clock-mmss-8996.o + obj-$(CONFIG_ARCH_QCOM) += clock-cpu-8996.o +endif # MSM COBALT -obj-$(CONFIG_ARCH_MSMCOBALT) += clock-gcc-cobalt.o -obj-$(CONFIG_ARCH_MSMCOBALT) += clock-gpu-cobalt.o -obj-$(CONFIG_ARCH_MSMCOBALT) += clock-mmss-cobalt.o -obj-$(CONFIG_ARCH_MSMCOBALT) += clock-osm.o +ifeq ($(CONFIG_COMMON_CLK_MSM), y) + obj-$(CONFIG_ARCH_MSMCOBALT) += clock-gcc-cobalt.o + obj-$(CONFIG_ARCH_MSMCOBALT) += clock-gpu-cobalt.o + obj-$(CONFIG_ARCH_MSMCOBALT) += clock-mmss-cobalt.o + obj-$(CONFIG_ARCH_MSMCOBALT) += clock-osm.o +endif -# CPU clocks - -obj-y += gdsc.o -obj-y += mdss/ +obj-$(CONFIG_COMMON_CLK_MSM) += gdsc.o +obj-$(CONFIG_COMMON_CLK_MSM) += mdss/ diff --git a/drivers/clk/msm/clock-alpha-pll.c b/drivers/clk/msm/clock-alpha-pll.c index 5c8c45fe4ff6..b9a1167a790d 100644 --- a/drivers/clk/msm/clock-alpha-pll.c +++ b/drivers/clk/msm/clock-alpha-pll.c @@ -1040,7 +1040,7 @@ static enum handoff fabia_alpha_pll_handoff(struct clk *c) if (!is_locked(pll)) { if (c->rate && fabia_alpha_pll_set_rate(c, c->rate)) WARN(1, "%s: Failed to configure rate\n", c->dbg_name); - __init_alpha_pll(c); + __init_fabia_alpha_pll(c); return HANDOFF_DISABLED_CLK; } else if (pll->fsm_en_mask && !is_fsm_mode(MODE_REG(pll))) { WARN(1, "%s should be in FSM mode but is not\n", c->dbg_name); diff --git a/drivers/clk/msm/clock-gcc-cobalt.c b/drivers/clk/msm/clock-gcc-cobalt.c index 1756157c996d..1524d3d8ed46 100644 --- a/drivers/clk/msm/clock-gcc-cobalt.c +++ b/drivers/clk/msm/clock-gcc-cobalt.c @@ -1698,19 +1698,6 @@ static struct branch_clk gcc_gpu_iref_clk = { }, }; -static struct local_vote_clk gcc_bimc_hmss_axi_clk = { - .cbcr_reg = GCC_BIMC_HMSS_AXI_CBCR, - .vote_reg = GCC_APCS_CLOCK_BRANCH_ENA_VOTE, - .en_mask = BIT(22), - .base = &virt_base, - .c = { - .dbg_name = "gcc_bimc_hmss_axi_clk", - .always_on = true, - .ops = &clk_ops_vote, - CLK_INIT(gcc_bimc_hmss_axi_clk.c), - }, -}; - static struct local_vote_clk gcc_hmss_ahb_clk = { .cbcr_reg = GCC_HMSS_AHB_CBCR, .vote_reg = GCC_APCS_CLOCK_BRANCH_ENA_VOTE, @@ -2439,7 +2426,7 @@ static struct mux_clk gcc_debug_mux = { { &ce1_clk.c, 0x0097 }, { &gcc_ce1_axi_m_clk.c, 0x0098 }, { &gcc_ce1_ahb_m_clk.c, 0x0099 }, - { &gcc_bimc_hmss_axi_clk.c, 0x00bb }, + { &measure_only_bimc_hmss_axi_clk.c, 0x00bb }, { &gcc_bimc_gfx_clk.c, 0x00ac }, { &gcc_hmss_ahb_clk.c, 0x00ba }, { &gcc_hmss_rbcpr_clk.c, 0x00bc }, @@ -2661,7 +2648,6 @@ static struct clk_lookup msm_clocks_gcc_cobalt[] = { CLK_LIST(gcc_gpu_cfg_ahb_clk), CLK_LIST(gcc_gpu_snoc_dvm_gfx_clk), CLK_LIST(gcc_gpu_iref_clk), - CLK_LIST(gcc_bimc_hmss_axi_clk), CLK_LIST(gcc_hmss_ahb_clk), CLK_LIST(gcc_hmss_dvm_bus_clk), CLK_LIST(gcc_hmss_rbcpr_clk), diff --git a/drivers/clk/msm/clock-gpu-cobalt.c b/drivers/clk/msm/clock-gpu-cobalt.c index 63870aaa487b..ce3e7916e658 100644 --- a/drivers/clk/msm/clock-gpu-cobalt.c +++ b/drivers/clk/msm/clock-gpu-cobalt.c @@ -285,9 +285,10 @@ static struct rcg_clk rbbmtimer_clk_src = { }; static struct clk_freq_tbl ftbl_gfx3d_isense_clk_src[] = { - F( 40000000, gpucc_gpll0, 15, 0, 0), - F( 200000000, gpucc_gpll0, 3, 0, 0), - F( 300000000, gpucc_gpll0, 2, 0, 0), + F( 19200000, gpucc_cxo_clk, 1, 0, 0), + F( 40000000, gpucc_gpll0, 15, 0, 0), + F( 200000000, gpucc_gpll0, 3, 0, 0), + F( 300000000, gpucc_gpll0, 2, 0, 0), F_END }; diff --git a/drivers/clk/msm/clock-local2.c b/drivers/clk/msm/clock-local2.c index 55fa76046def..6cf53c78d4d6 100644 --- a/drivers/clk/msm/clock-local2.c +++ b/drivers/clk/msm/clock-local2.c @@ -21,6 +21,7 @@ #include <linux/io.h> #include <linux/spinlock.h> #include <linux/delay.h> +#include <linux/rational.h> #include <linux/clk.h> #include <linux/clk/msm-clk-provider.h> #include <linux/clk/msm-clk.h> @@ -1735,6 +1736,46 @@ static struct clk *edp_clk_get_parent(struct clk *c) return freq->src_clk; } +static int rcg_clk_set_rate_dp(struct clk *clk, unsigned long rate) +{ + struct rcg_clk *rcg = to_rcg_clk(clk); + struct clk_freq_tbl *freq_tbl = rcg->current_freq; + unsigned long src_rate; + unsigned long num, den, flags; + + src_rate = clk_get_rate(clk->parent); + if (src_rate <= 0) { + pr_err("Invalid RCG parent rate\n"); + return -EINVAL; + } + + rational_best_approximation(src_rate, rate, + (unsigned long)(1 << 16) - 1, + (unsigned long)(1 << 16) - 1, &den, &num); + + if (!num || !den) { + pr_err("Invalid MN values derived for requested rate %lu\n", + rate); + return -EINVAL; + } + + freq_tbl->div_src_val &= ~BM(4, 0); + if (num == den) { + freq_tbl->m_val = 0; + freq_tbl->n_val = 0; + } else { + freq_tbl->m_val = num; + freq_tbl->n_val = ~(den - num); + freq_tbl->d_val = ~den; + } + + spin_lock_irqsave(&local_clock_reg_lock, flags); + if (!is_same_rcg_config(rcg, freq_tbl, true)) + __set_rate_mnd(rcg, freq_tbl); + spin_unlock_irqrestore(&local_clock_reg_lock, flags); + return 0; +} + static int gate_clk_enable(struct clk *c) { unsigned long flags; @@ -2291,6 +2332,15 @@ struct clk_ops clk_ops_rcg_edp = { .list_registers = rcg_hid_clk_list_registers, }; +struct clk_ops clk_ops_rcg_dp = { + .enable = rcg_clk_enable, + .disable = rcg_clk_disable, + .set_rate = rcg_clk_set_rate_dp, + .list_rate = rcg_clk_list_rate, + .handoff = pixel_rcg_handoff, + .list_registers = rcg_mnd_clk_list_registers, +}; + struct clk_ops clk_ops_branch = { .enable = branch_clk_enable, .prepare = branch_clk_prepare, diff --git a/drivers/clk/msm/clock-mmss-cobalt.c b/drivers/clk/msm/clock-mmss-cobalt.c index 47466ad04311..53c657ef3a25 100644 --- a/drivers/clk/msm/clock-mmss-cobalt.c +++ b/drivers/clk/msm/clock-mmss-cobalt.c @@ -46,7 +46,9 @@ static void __iomem *virt_base; #define mmpll10_pll_out_mm_source_val 4 #define dsi0phypll_mm_source_val 1 #define dsi1phypll_mm_source_val 2 -#define hdmiphypll_mm_source_val 1 +#define hdmiphypll_mm_source_val 1 +#define ext_dp_phy_pll_link_mm_source_val 1 +#define ext_dp_phy_pll_vco_mm_source_val 2 #define FIXDIV(div) (div ? (2 * (div) - 1) : (0)) @@ -61,9 +63,23 @@ static void __iomem *virt_base; | BVAL(10, 8, s##_mm_source_val), \ } +#define F_SLEW(f, s_f, s, div, m, n) \ + { \ + .freq_hz = (f), \ + .src_freq = (s_f), \ + .src_clk = &s.c, \ + .m_val = (m), \ + .n_val = ~((n)-(m)) * !!(n), \ + .d_val = ~(n),\ + .div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \ + | BVAL(10, 8, s##_mm_source_val), \ + } + DEFINE_EXT_CLK(mmsscc_xo, NULL); DEFINE_EXT_CLK(mmsscc_gpll0, NULL); DEFINE_EXT_CLK(mmsscc_gpll0_div, NULL); +DEFINE_EXT_CLK(ext_dp_phy_pll_vco, NULL); +DEFINE_EXT_CLK(ext_dp_phy_pll_link, NULL); static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL); @@ -1091,6 +1107,80 @@ static struct rcg_clk dp_aux_clk_src = { }, }; +static struct clk_freq_tbl ftbl_dp_pixel_clk_src[] = { + { + .div_src_val = BVAL(10, 8, ext_dp_phy_pll_vco_mm_source_val), + .src_clk = &ext_dp_phy_pll_vco.c, + }, + F_END +}; + +static struct rcg_clk dp_pixel_clk_src = { + .cmd_rcgr_reg = MMSS_DP_PIXEL_CMD_RCGR, + .set_rate = set_rate_mnd, + .current_freq = ftbl_dp_pixel_clk_src, + .base = &virt_base, + .c = { + .dbg_name = "dp_pixel_clk_src", + .parent = &ext_dp_phy_pll_vco.c, + .ops = &clk_ops_rcg_dp, + VDD_DIG_FMAX_MAP3(LOWER, 148380000, LOW, 296740000, + NOMINAL, 593470000), + CLK_INIT(dp_pixel_clk_src.c), + }, +}; + +static struct clk_freq_tbl ftbl_dp_link_clk_src[] = { + F_SLEW( 162000000, 324000000, ext_dp_phy_pll_link, 2, 0, 0), + F_SLEW( 270000000, 540000000, ext_dp_phy_pll_link, 2, 0, 0), + F_SLEW( 540000000, 1080000000, ext_dp_phy_pll_link, 2, 0, 0), + F_END +}; + +static struct rcg_clk dp_link_clk_src = { + .cmd_rcgr_reg = MMSS_DP_LINK_CMD_RCGR, + .set_rate = set_rate_hid, + .freq_tbl = ftbl_dp_link_clk_src, + .current_freq = ftbl_dp_link_clk_src, + .base = &virt_base, + .c = { + .dbg_name = "dp_link_clk_src", + .ops = &clk_ops_rcg, + .flags = CLKFLAG_NO_RATE_CACHE, + VDD_DIG_FMAX_MAP3(LOWER, 162000000, LOW, 270000000, + NOMINAL, 540000000), + CLK_INIT(dp_link_clk_src.c), + }, +}; + +/* + * Current understanding is that the DP PLL is going to be configured by using + * the set_rate ops for the dp_link_clk_src and dp_pixel_clk_src. When set_rate + * is called on this RCG, the rate call never makes it to the external DP + * clocks. + */ +static struct clk_freq_tbl ftbl_dp_crypto_clk_src[] = { + F_MM( 101250000, ext_dp_phy_pll_link, 1, 5, 16), + F_MM( 168750000, ext_dp_phy_pll_link, 1, 5, 16), + F_MM( 337500000, ext_dp_phy_pll_link, 1, 5, 16), + F_END +}; + +static struct rcg_clk dp_crypto_clk_src = { + .cmd_rcgr_reg = MMSS_DP_CRYPTO_CMD_RCGR, + .set_rate = set_rate_mnd, + .freq_tbl = ftbl_dp_crypto_clk_src, + .current_freq = ftbl_dp_crypto_clk_src, + .base = &virt_base, + .c = { + .dbg_name = "dp_crypto_clk_src", + .ops = &clk_ops_rcg_mnd, + VDD_DIG_FMAX_MAP3(LOWER, 101250000, LOW, 168750000, + NOMINAL, 337500000), + CLK_INIT(dp_crypto_clk_src.c), + }, +}; + static struct branch_clk mmss_bimc_smmu_ahb_clk = { .cbcr_reg = MMSS_BIMC_SMMU_AHB_CBCR, .has_sibling = 1, @@ -1936,6 +2026,56 @@ static struct branch_clk mmss_mdss_dp_aux_clk = { }, }; +static struct branch_clk mmss_mdss_dp_pixel_clk = { + .cbcr_reg = MMSS_MDSS_DP_PIXEL_CBCR, + .has_sibling = 0, + .base = &virt_base, + .c = { + .dbg_name = "mmss_mdss_dp_pixel_clk", + .parent = &dp_pixel_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(mmss_mdss_dp_pixel_clk.c), + }, +}; + +static struct branch_clk mmss_mdss_dp_link_clk = { + .cbcr_reg = MMSS_MDSS_DP_LINK_CBCR, + .has_sibling = 0, + .base = &virt_base, + .c = { + .dbg_name = "mmss_mdss_dp_link_clk", + .parent = &dp_link_clk_src.c, + .flags = CLKFLAG_NO_RATE_CACHE, + .ops = &clk_ops_branch, + CLK_INIT(mmss_mdss_dp_link_clk.c), + }, +}; + +/* Reset state of MMSS_MDSS_DP_LINK_INTF_DIV is 0x3 (div-4) */ +static struct branch_clk mmss_mdss_dp_link_intf_clk = { + .cbcr_reg = MMSS_MDSS_DP_LINK_INTF_CBCR, + .has_sibling = 1, + .base = &virt_base, + .c = { + .dbg_name = "mmss_mdss_dp_link_intf_clk", + .parent = &dp_link_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(mmss_mdss_dp_link_intf_clk.c), + }, +}; + +static struct branch_clk mmss_mdss_dp_crypto_clk = { + .cbcr_reg = MMSS_MDSS_DP_CRYPTO_CBCR, + .has_sibling = 0, + .base = &virt_base, + .c = { + .dbg_name = "mmss_mdss_dp_crypto_clk", + .parent = &dp_crypto_clk_src.c, + .ops = &clk_ops_branch, + CLK_INIT(mmss_mdss_dp_crypto_clk.c), + }, +}; + static struct branch_clk mmss_mdss_dp_gtc_clk = { .cbcr_reg = MMSS_MDSS_DP_GTC_CBCR, .has_sibling = 0, @@ -2313,10 +2453,14 @@ static struct mux_clk mmss_debug_mux = { { &mmss_fd_core_clk.c, 0x0089 }, { &mmss_fd_core_uar_clk.c, 0x008a }, { &mmss_fd_ahb_clk.c, 0x008c }, - { &mmss_camss_cphy_csid0_clk.c, 0x008d}, - { &mmss_camss_cphy_csid1_clk.c, 0x008e}, - { &mmss_camss_cphy_csid2_clk.c, 0x008f}, - { &mmss_camss_cphy_csid3_clk.c, 0x0090}, + { &mmss_camss_cphy_csid0_clk.c, 0x008d }, + { &mmss_camss_cphy_csid1_clk.c, 0x008e }, + { &mmss_camss_cphy_csid2_clk.c, 0x008f }, + { &mmss_camss_cphy_csid3_clk.c, 0x0090 }, + { &mmss_mdss_dp_link_clk.c, 0x0098 }, + { &mmss_mdss_dp_link_intf_clk.c, 0x0099 }, + { &mmss_mdss_dp_crypto_clk.c, 0x009a }, + { &mmss_mdss_dp_pixel_clk.c, 0x009b }, { &mmss_mdss_dp_aux_clk.c, 0x009c }, { &mmss_mdss_dp_gtc_clk.c, 0x009d }, { &mmss_mdss_byte0_intf_clk.c, 0x00ad }, @@ -2384,6 +2528,11 @@ static struct clk_lookup msm_clocks_mmss_cobalt[] = { CLK_LIST(pclk1_clk_src), CLK_LIST(ext_extpclk_clk_src), CLK_LIST(extpclk_clk_src), + CLK_LIST(ext_dp_phy_pll_vco), + CLK_LIST(ext_dp_phy_pll_link), + CLK_LIST(dp_pixel_clk_src), + CLK_LIST(dp_link_clk_src), + CLK_LIST(dp_crypto_clk_src), CLK_LIST(csi0phytimer_clk_src), CLK_LIST(csi1phytimer_clk_src), CLK_LIST(csi2phytimer_clk_src), @@ -2463,6 +2612,10 @@ static struct clk_lookup msm_clocks_mmss_cobalt[] = { CLK_LIST(mmss_mdss_byte0_intf_div_clk), CLK_LIST(mmss_mdss_byte1_intf_clk), CLK_LIST(mmss_mdss_dp_aux_clk), + CLK_LIST(mmss_mdss_dp_crypto_clk), + CLK_LIST(mmss_mdss_dp_pixel_clk), + CLK_LIST(mmss_mdss_dp_link_clk), + CLK_LIST(mmss_mdss_dp_link_intf_clk), CLK_LIST(mmss_mdss_dp_gtc_clk), CLK_LIST(mmss_mdss_esc0_clk), CLK_LIST(mmss_mdss_esc1_clk), @@ -2646,6 +2799,11 @@ int msm_mmsscc_cobalt_probe(struct platform_device *pdev) ext_extpclk_clk_src.dev = &pdev->dev; ext_extpclk_clk_src.clk_id = "extpclk_src"; + ext_dp_phy_pll_link.dev = &pdev->dev; + ext_dp_phy_pll_link.clk_id = "dp_link_src"; + ext_dp_phy_pll_vco.dev = &pdev->dev; + ext_dp_phy_pll_vco.clk_id = "dp_vco_div"; + is_vq = of_device_is_compatible(pdev->dev.of_node, "qcom,mmsscc-hamster"); if (is_vq) diff --git a/drivers/clk/msm/mdss/Kconfig b/drivers/clk/msm/mdss/Kconfig index 229780e45bb8..c332b34d39ee 100644 --- a/drivers/clk/msm/mdss/Kconfig +++ b/drivers/clk/msm/mdss/Kconfig @@ -1,5 +1,6 @@ config MSM_MDSS_PLL bool "MDSS pll programming" + depends on COMMON_CLK_MSM ---help--- It provides support for DSI, eDP and HDMI interface pll programming on MDSS hardware. It also handles the pll specific resources and turn them on/off when diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-cobalt.c b/drivers/clk/msm/mdss/mdss-dsi-pll-cobalt.c index e6153553e48a..1751f49b798c 100644 --- a/drivers/clk/msm/mdss/mdss-dsi-pll-cobalt.c +++ b/drivers/clk/msm/mdss/mdss-dsi-pll-cobalt.c @@ -509,7 +509,7 @@ static unsigned long dsi_pll_get_vco_rate(struct clk *c) 16); /* OUTDIV_1:0 field is (log(outdiv, 2)) */ - outdiv = MDSS_PLL_REG_R(pll->pll_base, PLL_OUTDIV); + outdiv = MDSS_PLL_REG_R(pll->pll_base, PLL_PLL_OUTDIV_RATE); outdiv &= 0x3; outdiv = 1 << outdiv; @@ -521,12 +521,12 @@ static unsigned long dsi_pll_get_vco_rate(struct clk *c) multiplier = 1 << 18; pll_freq = dec * (ref_clk * 2); tmp64 = (ref_clk * 2 * frac); - pll_freq += do_div(tmp64, multiplier); + pll_freq += div_u64(tmp64, multiplier); - vco_rate = do_div(pll_freq, outdiv); + vco_rate = div_u64(pll_freq, outdiv); - pr_debug("dec=0x%x\n, frac=0x%x, outdiv=%d, vco=%lu\n", - dec, frac, outdiv, (unsigned long)vco_rate); + pr_debug("dec=0x%x, frac=0x%x, outdiv=%d, vco=%llu\n", + dec, frac, outdiv, vco_rate); (void)mdss_pll_resource_enable(pll, false); diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 94419695cd2e..dc1b66f84af2 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -12,6 +12,7 @@ clk-qcom-y += clk-regmap-mux.o clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-krait.o clk-qcom-y += clk-hfpll.o clk-qcom-y += reset.o +clk-qcom-y += clk-dummy.o clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o diff --git a/drivers/clk/qcom/clk-dummy.c b/drivers/clk/qcom/clk-dummy.c new file mode 100644 index 000000000000..3205fbc6b8ba --- /dev/null +++ b/drivers/clk/qcom/clk-dummy.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +struct clk_dummy { + struct clk_hw hw; + unsigned long rrate; +}; + +#define to_clk_dummy(_hw) container_of(_hw, struct clk_dummy, hw) + +static int dummy_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_dummy *dummy = to_clk_dummy(hw); + + dummy->rrate = rate; + + pr_debug("set rate: %lu\n", rate); + + return 0; +} + +static long dummy_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + return rate; +} + +static unsigned long dummy_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_dummy *dummy = to_clk_dummy(hw); + + pr_debug("clock rate: %lu\n", dummy->rrate); + + return dummy->rrate; +} + +struct clk_ops clk_dummy_ops = { + .set_rate = dummy_clk_set_rate, + .round_rate = dummy_clk_round_rate, + .recalc_rate = dummy_clk_recalc_rate, +}; +EXPORT_SYMBOL_GPL(clk_dummy_ops); + +/** + * clk_register_dummy - register dummy clock with the + * clock framework + * @dev: device that is registering this clock + * @name: name of this clock + * @flags: framework-specific flags + */ +static struct clk *clk_register_dummy(struct device *dev, const char *name, + unsigned long flags) +{ + struct clk_dummy *dummy; + struct clk *clk; + struct clk_init_data init = {}; + + /* allocate dummy clock */ + dummy = kzalloc(sizeof(*dummy), GFP_KERNEL); + if (!dummy) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &clk_dummy_ops; + init.flags = flags | CLK_IS_BASIC; + init.num_parents = 0; + dummy->hw.init = &init; + + /* register the clock */ + clk = clk_register(dev, &dummy->hw); + if (IS_ERR(clk)) + kfree(dummy); + + return clk; +} + +/** + * of_dummy_clk_setup() - Setup function for simple fixed rate clock + */ +static void of_dummy_clk_setup(struct device_node *node) +{ + struct clk *clk; + const char *clk_name = "dummy_clk"; + + of_property_read_string(node, "clock-output-names", &clk_name); + + clk = clk_register_dummy(NULL, clk_name, 0); + if (!IS_ERR(clk)) + of_clk_add_provider(node, of_clk_src_simple_get, clk); + + pr_info("%s: Dummy clock registered\n", clk_name); +} +CLK_OF_DECLARE(dummy_clk, "qcom,dummycc", of_dummy_clk_setup); diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h index ae9bdeb21f29..10cabca921be 100644 --- a/drivers/clk/qcom/common.h +++ b/drivers/clk/qcom/common.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2014, 2016, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -48,5 +48,5 @@ extern int qcom_cc_really_probe(struct platform_device *pdev, struct regmap *regmap); extern int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc); - +extern struct clk_ops clk_dummy_ops; #endif diff --git a/drivers/clk/samsung/clk-cpu.c b/drivers/clk/samsung/clk-cpu.c index 2fe37f708dc7..813003d6ce09 100644 --- a/drivers/clk/samsung/clk-cpu.c +++ b/drivers/clk/samsung/clk-cpu.c @@ -148,6 +148,7 @@ static int exynos_cpuclk_pre_rate_change(struct clk_notifier_data *ndata, unsigned long alt_prate = clk_get_rate(cpuclk->alt_parent); unsigned long alt_div = 0, alt_div_mask = DIV_MASK; unsigned long div0, div1 = 0, mux_reg; + unsigned long flags; /* find out the divider values to use for clock data */ while ((cfg_data->prate * 1000) != ndata->new_rate) { @@ -156,7 +157,7 @@ static int exynos_cpuclk_pre_rate_change(struct clk_notifier_data *ndata, cfg_data++; } - spin_lock(cpuclk->lock); + spin_lock_irqsave(cpuclk->lock, flags); /* * For the selected PLL clock frequency, get the pre-defined divider @@ -212,7 +213,7 @@ static int exynos_cpuclk_pre_rate_change(struct clk_notifier_data *ndata, DIV_MASK_ALL); } - spin_unlock(cpuclk->lock); + spin_unlock_irqrestore(cpuclk->lock, flags); return 0; } @@ -223,6 +224,7 @@ static int exynos_cpuclk_post_rate_change(struct clk_notifier_data *ndata, const struct exynos_cpuclk_cfg_data *cfg_data = cpuclk->cfg; unsigned long div = 0, div_mask = DIV_MASK; unsigned long mux_reg; + unsigned long flags; /* find out the divider values to use for clock data */ if (cpuclk->flags & CLK_CPU_NEEDS_DEBUG_ALT_DIV) { @@ -233,7 +235,7 @@ static int exynos_cpuclk_post_rate_change(struct clk_notifier_data *ndata, } } - spin_lock(cpuclk->lock); + spin_lock_irqsave(cpuclk->lock, flags); /* select mout_apll as the alternate parent */ mux_reg = readl(base + E4210_SRC_CPU); @@ -246,7 +248,7 @@ static int exynos_cpuclk_post_rate_change(struct clk_notifier_data *ndata, } exynos_set_safe_div(base, div, div_mask); - spin_unlock(cpuclk->lock); + spin_unlock_irqrestore(cpuclk->lock, flags); return 0; } diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c index 6ee91401918e..4da2af9694a2 100644 --- a/drivers/clocksource/tcb_clksrc.c +++ b/drivers/clocksource/tcb_clksrc.c @@ -98,7 +98,8 @@ static int tc_shutdown(struct clock_event_device *d) __raw_writel(0xff, regs + ATMEL_TC_REG(2, IDR)); __raw_writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR)); - clk_disable(tcd->clk); + if (!clockevent_state_detached(d)) + clk_disable(tcd->clk); return 0; } diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/vt8500_timer.c index a92e94b40b5b..dfc3bb410b00 100644 --- a/drivers/clocksource/vt8500_timer.c +++ b/drivers/clocksource/vt8500_timer.c @@ -50,6 +50,8 @@ #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) +#define MIN_OSCR_DELTA 16 + static void __iomem *regbase; static cycle_t vt8500_timer_read(struct clocksource *cs) @@ -80,7 +82,7 @@ static int vt8500_timer_set_next_event(unsigned long cycles, cpu_relax(); writel((unsigned long)alarm, regbase + TIMER_MATCH_VAL); - if ((signed)(alarm - clocksource.read(&clocksource)) <= 16) + if ((signed)(alarm - clocksource.read(&clocksource)) <= MIN_OSCR_DELTA) return -ETIME; writel(1, regbase + TIMER_IER_VAL); @@ -151,7 +153,7 @@ static void __init vt8500_timer_init(struct device_node *np) pr_err("%s: setup_irq failed for %s\n", __func__, clockevent.name); clockevents_config_and_register(&clockevent, VT8500_TIMER_HZ, - 4, 0xf0000000); + MIN_OSCR_DELTA * 2, 0xf0000000); } CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init); diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index b260576ddb12..d994b0f652d3 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -356,16 +356,18 @@ static int cpufreq_governor_init(struct cpufreq_policy *policy, if (!have_governor_per_policy()) cdata->gdbs_data = dbs_data; + policy->governor_data = dbs_data; + ret = sysfs_create_group(get_governor_parent_kobj(policy), get_sysfs_attr(dbs_data)); if (ret) goto reset_gdbs_data; - policy->governor_data = dbs_data; - return 0; reset_gdbs_data: + policy->governor_data = NULL; + if (!have_governor_per_policy()) cdata->gdbs_data = NULL; cdata->exit(dbs_data, !policy->governor->initialized); @@ -386,16 +388,19 @@ static int cpufreq_governor_exit(struct cpufreq_policy *policy, if (!cdbs->shared || cdbs->shared->policy) return -EBUSY; - policy->governor_data = NULL; if (!--dbs_data->usage_count) { sysfs_remove_group(get_governor_parent_kobj(policy), get_sysfs_attr(dbs_data)); + policy->governor_data = NULL; + if (!have_governor_per_policy()) cdata->gdbs_data = NULL; cdata->exit(dbs_data, policy->governor->initialized == 1); kfree(dbs_data); + } else { + policy->governor_data = NULL; } free_common_dbs_info(policy, cdata); diff --git a/drivers/cpufreq/pxa2xx-cpufreq.c b/drivers/cpufreq/pxa2xx-cpufreq.c index 1d99c97defa9..096377232747 100644 --- a/drivers/cpufreq/pxa2xx-cpufreq.c +++ b/drivers/cpufreq/pxa2xx-cpufreq.c @@ -202,7 +202,7 @@ static void __init pxa_cpufreq_init_voltages(void) } } #else -static int pxa_cpufreq_change_voltage(struct pxa_freqs *pxa_freq) +static int pxa_cpufreq_change_voltage(const struct pxa_freqs *pxa_freq) { return 0; } diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index 370c661c7d7b..02f9aa4ebe05 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -176,6 +176,7 @@ #define AT_XDMAC_MAX_CHAN 0x20 #define AT_XDMAC_MAX_CSIZE 16 /* 16 data */ #define AT_XDMAC_MAX_DWIDTH 8 /* 64 bits */ +#define AT_XDMAC_RESIDUE_MAX_RETRIES 5 #define AT_XDMAC_DMA_BUSWIDTHS\ (BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) |\ @@ -1383,8 +1384,8 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, struct at_xdmac_desc *desc, *_desc; struct list_head *descs_list; enum dma_status ret; - int residue; - u32 cur_nda, mask, value; + int residue, retry; + u32 cur_nda, check_nda, cur_ubc, mask, value; u8 dwidth = 0; unsigned long flags; @@ -1421,7 +1422,42 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, cpu_relax(); } + /* + * When processing the residue, we need to read two registers but we + * can't do it in an atomic way. AT_XDMAC_CNDA is used to find where + * we stand in the descriptor list and AT_XDMAC_CUBC is used + * to know how many data are remaining for the current descriptor. + * Since the dma channel is not paused to not loose data, between the + * AT_XDMAC_CNDA and AT_XDMAC_CUBC read, we may have change of + * descriptor. + * For that reason, after reading AT_XDMAC_CUBC, we check if we are + * still using the same descriptor by reading a second time + * AT_XDMAC_CNDA. If AT_XDMAC_CNDA has changed, it means we have to + * read again AT_XDMAC_CUBC. + * Memory barriers are used to ensure the read order of the registers. + * A max number of retries is set because unlikely it can never ends if + * we are transferring a lot of data with small buffers. + */ cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc; + rmb(); + cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC); + for (retry = 0; retry < AT_XDMAC_RESIDUE_MAX_RETRIES; retry++) { + rmb(); + check_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc; + + if (likely(cur_nda == check_nda)) + break; + + cur_nda = check_nda; + rmb(); + cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC); + } + + if (unlikely(retry >= AT_XDMAC_RESIDUE_MAX_RETRIES)) { + ret = DMA_ERROR; + goto spin_unlock; + } + /* * Remove size of all microblocks already transferred and the current * one. Then add the remaining size to transfer of the current @@ -1434,7 +1470,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, if ((desc->lld.mbr_nda & 0xfffffffc) == cur_nda) break; } - residue += at_xdmac_chan_read(atchan, AT_XDMAC_CUBC) << dwidth; + residue += cur_ubc << dwidth; dma_set_residue(txstate, residue); @@ -1688,6 +1724,7 @@ static int at_xdmac_device_terminate_all(struct dma_chan *chan) list_for_each_entry_safe(desc, _desc, &atchan->xfers_list, xfer_node) at_xdmac_remove_xfer(atchan, desc); + clear_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status); clear_bit(AT_XDMAC_CHAN_IS_CYCLIC, &atchan->status); spin_unlock_irqrestore(&atchan->lock, flags); @@ -1820,6 +1857,8 @@ static int atmel_xdmac_resume(struct device *dev) atchan = to_at_xdmac_chan(chan); at_xdmac_chan_write(atchan, AT_XDMAC_CC, atchan->save_cc); if (at_xdmac_chan_is_cyclic(atchan)) { + if (at_xdmac_chan_is_paused(atchan)) + at_xdmac_device_resume(chan); at_xdmac_chan_write(atchan, AT_XDMAC_CNDA, atchan->save_cnda); at_xdmac_chan_write(atchan, AT_XDMAC_CNDC, atchan->save_cndc); at_xdmac_chan_write(atchan, AT_XDMAC_CIE, atchan->save_cim); diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index 7067b6ddc1db..4f099ea29f83 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -536,16 +536,17 @@ EXPORT_SYMBOL(dw_dma_get_dst_addr); /* Called with dwc->lock held and all DMAC interrupts disabled */ static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc, - u32 status_err, u32 status_xfer) + u32 status_block, u32 status_err, u32 status_xfer) { unsigned long flags; - if (dwc->mask) { + if (status_block & dwc->mask) { void (*callback)(void *param); void *callback_param; dev_vdbg(chan2dev(&dwc->chan), "new cyclic period llp 0x%08x\n", channel_readl(dwc, LLP)); + dma_writel(dw, CLEAR.BLOCK, dwc->mask); callback = dwc->cdesc->period_callback; callback_param = dwc->cdesc->period_callback_param; @@ -577,6 +578,7 @@ static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc, channel_writel(dwc, CTL_LO, 0); channel_writel(dwc, CTL_HI, 0); + dma_writel(dw, CLEAR.BLOCK, dwc->mask); dma_writel(dw, CLEAR.ERROR, dwc->mask); dma_writel(dw, CLEAR.XFER, dwc->mask); @@ -585,6 +587,9 @@ static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc, spin_unlock_irqrestore(&dwc->lock, flags); } + + /* Re-enable interrupts */ + channel_set_bit(dw, MASK.BLOCK, dwc->mask); } /* ------------------------------------------------------------------------- */ @@ -593,10 +598,12 @@ static void dw_dma_tasklet(unsigned long data) { struct dw_dma *dw = (struct dw_dma *)data; struct dw_dma_chan *dwc; + u32 status_block; u32 status_xfer; u32 status_err; int i; + status_block = dma_readl(dw, RAW.BLOCK); status_xfer = dma_readl(dw, RAW.XFER); status_err = dma_readl(dw, RAW.ERROR); @@ -605,16 +612,15 @@ static void dw_dma_tasklet(unsigned long data) for (i = 0; i < dw->dma.chancnt; i++) { dwc = &dw->chan[i]; if (test_bit(DW_DMA_IS_CYCLIC, &dwc->flags)) - dwc_handle_cyclic(dw, dwc, status_err, status_xfer); + dwc_handle_cyclic(dw, dwc, status_block, status_err, + status_xfer); else if (status_err & (1 << i)) dwc_handle_error(dw, dwc); else if (status_xfer & (1 << i)) dwc_scan_descriptors(dw, dwc); } - /* - * Re-enable interrupts. - */ + /* Re-enable interrupts */ channel_set_bit(dw, MASK.XFER, dw->all_chan_mask); channel_set_bit(dw, MASK.ERROR, dw->all_chan_mask); } @@ -635,6 +641,7 @@ static irqreturn_t dw_dma_interrupt(int irq, void *dev_id) * softirq handler. */ channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask); + channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask); channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask); status = dma_readl(dw, STATUS_INT); @@ -645,6 +652,7 @@ static irqreturn_t dw_dma_interrupt(int irq, void *dev_id) /* Try to recover */ channel_clear_bit(dw, MASK.XFER, (1 << 8) - 1); + channel_clear_bit(dw, MASK.BLOCK, (1 << 8) - 1); channel_clear_bit(dw, MASK.SRC_TRAN, (1 << 8) - 1); channel_clear_bit(dw, MASK.DST_TRAN, (1 << 8) - 1); channel_clear_bit(dw, MASK.ERROR, (1 << 8) - 1); @@ -1111,6 +1119,7 @@ static void dw_dma_off(struct dw_dma *dw) dma_writel(dw, CFG, 0); channel_clear_bit(dw, MASK.XFER, dw->all_chan_mask); + channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask); channel_clear_bit(dw, MASK.SRC_TRAN, dw->all_chan_mask); channel_clear_bit(dw, MASK.DST_TRAN, dw->all_chan_mask); channel_clear_bit(dw, MASK.ERROR, dw->all_chan_mask); @@ -1216,6 +1225,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan) /* Disable interrupts */ channel_clear_bit(dw, MASK.XFER, dwc->mask); + channel_clear_bit(dw, MASK.BLOCK, dwc->mask); channel_clear_bit(dw, MASK.ERROR, dwc->mask); spin_unlock_irqrestore(&dwc->lock, flags); @@ -1245,7 +1255,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan) int dw_dma_cyclic_start(struct dma_chan *chan) { struct dw_dma_chan *dwc = to_dw_dma_chan(chan); - struct dw_dma *dw = to_dw_dma(dwc->chan.device); + struct dw_dma *dw = to_dw_dma(chan->device); unsigned long flags; if (!test_bit(DW_DMA_IS_CYCLIC, &dwc->flags)) { @@ -1255,25 +1265,10 @@ int dw_dma_cyclic_start(struct dma_chan *chan) spin_lock_irqsave(&dwc->lock, flags); - /* Assert channel is idle */ - if (dma_readl(dw, CH_EN) & dwc->mask) { - dev_err(chan2dev(&dwc->chan), - "%s: BUG: Attempted to start non-idle channel\n", - __func__); - dwc_dump_chan_regs(dwc); - spin_unlock_irqrestore(&dwc->lock, flags); - return -EBUSY; - } - - dma_writel(dw, CLEAR.ERROR, dwc->mask); - dma_writel(dw, CLEAR.XFER, dwc->mask); + /* Enable interrupts to perform cyclic transfer */ + channel_set_bit(dw, MASK.BLOCK, dwc->mask); - /* Setup DMAC channel registers */ - channel_writel(dwc, LLP, dwc->cdesc->desc[0]->txd.phys); - channel_writel(dwc, CTL_LO, DWC_CTLL_LLP_D_EN | DWC_CTLL_LLP_S_EN); - channel_writel(dwc, CTL_HI, 0); - - channel_set_bit(dw, CH_EN, dwc->mask); + dwc_dostart(dwc, dwc->cdesc->desc[0]); spin_unlock_irqrestore(&dwc->lock, flags); @@ -1479,6 +1474,7 @@ void dw_dma_cyclic_free(struct dma_chan *chan) dwc_chan_disable(dw, dwc); + dma_writel(dw, CLEAR.BLOCK, dwc->mask); dma_writel(dw, CLEAR.ERROR, dwc->mask); dma_writel(dw, CLEAR.XFER, dwc->mask); @@ -1567,9 +1563,6 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata) /* Force dma off, just in case */ dw_dma_off(dw); - /* Disable BLOCK interrupts as well */ - channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask); - /* Create a pool of consistent memory blocks for hardware descriptors */ dw->desc_pool = dmam_pool_create("dw_dmac_desc_pool", chip->dev, sizeof(struct dw_desc), 4, 0); diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c index fc4156afa070..a59061e4221a 100644 --- a/drivers/dma/pxa_dma.c +++ b/drivers/dma/pxa_dma.c @@ -583,6 +583,8 @@ static void set_updater_desc(struct pxad_desc_sw *sw_desc, (PXA_DCMD_LENGTH & sizeof(u32)); if (flags & DMA_PREP_INTERRUPT) updater->dcmd |= PXA_DCMD_ENDIRQEN; + if (sw_desc->cyclic) + sw_desc->hw_desc[sw_desc->nb_desc - 2]->ddadr = sw_desc->first; } static bool is_desc_completed(struct virt_dma_desc *vd) @@ -673,6 +675,10 @@ static irqreturn_t pxad_chan_handler(int irq, void *dev_id) dev_dbg(&chan->vc.chan.dev->device, "%s(): checking txd %p[%x]: completed=%d\n", __func__, vd, vd->tx.cookie, is_desc_completed(vd)); + if (to_pxad_sw_desc(vd)->cyclic) { + vchan_cyclic_callback(vd); + break; + } if (is_desc_completed(vd)) { list_del(&vd->node); vchan_cookie_complete(vd); @@ -1080,7 +1086,7 @@ pxad_prep_dma_cyclic(struct dma_chan *dchan, return NULL; pxad_get_config(chan, dir, &dcmd, &dsadr, &dtadr); - dcmd |= PXA_DCMD_ENDIRQEN | (PXA_DCMD_LENGTH | period_len); + dcmd |= PXA_DCMD_ENDIRQEN | (PXA_DCMD_LENGTH & period_len); dev_dbg(&chan->vc.chan.dev->device, "%s(): buf_addr=0x%lx len=%zu period=%zu dir=%d flags=%lx\n", __func__, (unsigned long)buf_addr, len, period_len, dir, flags); diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c index 47e5078292c4..63d79d3795cc 100644 --- a/drivers/edac/edac_device.c +++ b/drivers/edac/edac_device.c @@ -441,16 +441,13 @@ void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev, */ void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev) { - int status; - if (!edac_dev->edac_check) return; - status = cancel_delayed_work(&edac_dev->work); - if (status == 0) { - /* workq instance might be running, wait for it */ - flush_workqueue(edac_workqueue); - } + edac_dev->op_state = OP_OFFLINE; + + cancel_delayed_work_sync(&edac_dev->work); + flush_workqueue(edac_workqueue); } /* diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 77ecd6a4179a..1b2c2187b347 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -586,18 +586,10 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec, */ static void edac_mc_workq_teardown(struct mem_ctl_info *mci) { - int status; - - if (mci->op_state != OP_RUNNING_POLL) - return; - - status = cancel_delayed_work(&mci->work); - if (status == 0) { - edac_dbg(0, "not canceled, flush the queue\n"); + mci->op_state = OP_OFFLINE; - /* workq instance might be running, wait for it */ - flush_workqueue(edac_workqueue); - } + cancel_delayed_work_sync(&mci->work); + flush_workqueue(edac_workqueue); } /* diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index a75acea0f674..58aed67b7eba 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -880,21 +880,26 @@ static struct device_type mci_attr_type = { int edac_create_sysfs_mci_device(struct mem_ctl_info *mci, const struct attribute_group **groups) { + char *name; int i, err; /* * The memory controller needs its own bus, in order to avoid * namespace conflicts at /sys/bus/edac. */ - mci->bus->name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx); - if (!mci->bus->name) + name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx); + if (!name) return -ENOMEM; + mci->bus->name = name; + edac_dbg(0, "creating bus %s\n", mci->bus->name); err = bus_register(mci->bus); - if (err < 0) - goto fail_free_name; + if (err < 0) { + kfree(name); + return err; + } /* get the /sys/devices/system/edac subsys reference */ mci->dev.type = &mci_attr_type; @@ -961,8 +966,8 @@ fail_unregister_dimm: device_unregister(&mci->dev); fail_unregister_bus: bus_unregister(mci->bus); -fail_free_name: - kfree(mci->bus->name); + kfree(name); + return err; } @@ -993,10 +998,12 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) void edac_unregister_sysfs(struct mem_ctl_info *mci) { + const char *name = mci->bus->name; + edac_dbg(1, "Unregistering device %s\n", dev_name(&mci->dev)); device_unregister(&mci->dev); bus_unregister(mci->bus); - kfree(mci->bus->name); + kfree(name); } static void mc_attr_release(struct device *dev) diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c index 2cf44b4db80c..b4b38603b804 100644 --- a/drivers/edac/edac_pci.c +++ b/drivers/edac/edac_pci.c @@ -274,13 +274,12 @@ static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci, */ static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci) { - int status; - edac_dbg(0, "\n"); - status = cancel_delayed_work(&pci->work); - if (status == 0) - flush_workqueue(edac_workqueue); + pci->op_state = OP_OFFLINE; + + cancel_delayed_work_sync(&pci->work); + flush_workqueue(edac_workqueue); } /* diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c index 756eca8c4cf8..10e6774ab2a2 100644 --- a/drivers/firmware/efi/efivars.c +++ b/drivers/firmware/efi/efivars.c @@ -221,7 +221,7 @@ sanity_check(struct efi_variable *var, efi_char16_t *name, efi_guid_t vendor, } if ((attributes & ~EFI_VARIABLE_MASK) != 0 || - efivar_validate(name, data, size) == false) { + efivar_validate(vendor, name, data, size) == false) { printk(KERN_ERR "efivars: Malformed variable content\n"); return -EINVAL; } @@ -447,7 +447,8 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj, } if ((attributes & ~EFI_VARIABLE_MASK) != 0 || - efivar_validate(name, data, size) == false) { + efivar_validate(new_var->VendorGuid, name, data, + size) == false) { printk(KERN_ERR "efivars: Malformed variable content\n"); return -EINVAL; } @@ -540,38 +541,30 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj, static int efivar_create_sysfs_entry(struct efivar_entry *new_var) { - int i, short_name_size; + int short_name_size; char *short_name; - unsigned long variable_name_size; - efi_char16_t *variable_name; + unsigned long utf8_name_size; + efi_char16_t *variable_name = new_var->var.VariableName; int ret; - variable_name = new_var->var.VariableName; - variable_name_size = ucs2_strlen(variable_name) * sizeof(efi_char16_t); - /* - * Length of the variable bytes in ASCII, plus the '-' separator, + * Length of the variable bytes in UTF8, plus the '-' separator, * plus the GUID, plus trailing NUL */ - short_name_size = variable_name_size / sizeof(efi_char16_t) - + 1 + EFI_VARIABLE_GUID_LEN + 1; - - short_name = kzalloc(short_name_size, GFP_KERNEL); + utf8_name_size = ucs2_utf8size(variable_name); + short_name_size = utf8_name_size + 1 + EFI_VARIABLE_GUID_LEN + 1; + short_name = kmalloc(short_name_size, GFP_KERNEL); if (!short_name) return -ENOMEM; - /* Convert Unicode to normal chars (assume top bits are 0), - ala UTF-8 */ - for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) { - short_name[i] = variable_name[i] & 0xFF; - } + ucs2_as_utf8(short_name, variable_name, short_name_size); + /* This is ugly, but necessary to separate one vendor's private variables from another's. */ - - *(short_name + strlen(short_name)) = '-'; + short_name[utf8_name_size] = '-'; efi_guid_to_str(&new_var->var.VendorGuid, - short_name + strlen(short_name)); + short_name + utf8_name_size + 1); new_var->kobj.kset = efivars_kset; diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c index 70a0fb10517f..7f2ea21c730d 100644 --- a/drivers/firmware/efi/vars.c +++ b/drivers/firmware/efi/vars.c @@ -165,67 +165,133 @@ validate_ascii_string(efi_char16_t *var_name, int match, u8 *buffer, } struct variable_validate { + efi_guid_t vendor; char *name; bool (*validate)(efi_char16_t *var_name, int match, u8 *data, unsigned long len); }; +/* + * This is the list of variables we need to validate, as well as the + * whitelist for what we think is safe not to default to immutable. + * + * If it has a validate() method that's not NULL, it'll go into the + * validation routine. If not, it is assumed valid, but still used for + * whitelisting. + * + * Note that it's sorted by {vendor,name}, but globbed names must come after + * any other name with the same prefix. + */ static const struct variable_validate variable_validate[] = { - { "BootNext", validate_uint16 }, - { "BootOrder", validate_boot_order }, - { "DriverOrder", validate_boot_order }, - { "Boot*", validate_load_option }, - { "Driver*", validate_load_option }, - { "ConIn", validate_device_path }, - { "ConInDev", validate_device_path }, - { "ConOut", validate_device_path }, - { "ConOutDev", validate_device_path }, - { "ErrOut", validate_device_path }, - { "ErrOutDev", validate_device_path }, - { "Timeout", validate_uint16 }, - { "Lang", validate_ascii_string }, - { "PlatformLang", validate_ascii_string }, - { "", NULL }, + { EFI_GLOBAL_VARIABLE_GUID, "BootNext", validate_uint16 }, + { EFI_GLOBAL_VARIABLE_GUID, "BootOrder", validate_boot_order }, + { EFI_GLOBAL_VARIABLE_GUID, "Boot*", validate_load_option }, + { EFI_GLOBAL_VARIABLE_GUID, "DriverOrder", validate_boot_order }, + { EFI_GLOBAL_VARIABLE_GUID, "Driver*", validate_load_option }, + { EFI_GLOBAL_VARIABLE_GUID, "ConIn", validate_device_path }, + { EFI_GLOBAL_VARIABLE_GUID, "ConInDev", validate_device_path }, + { EFI_GLOBAL_VARIABLE_GUID, "ConOut", validate_device_path }, + { EFI_GLOBAL_VARIABLE_GUID, "ConOutDev", validate_device_path }, + { EFI_GLOBAL_VARIABLE_GUID, "ErrOut", validate_device_path }, + { EFI_GLOBAL_VARIABLE_GUID, "ErrOutDev", validate_device_path }, + { EFI_GLOBAL_VARIABLE_GUID, "Lang", validate_ascii_string }, + { EFI_GLOBAL_VARIABLE_GUID, "OsIndications", NULL }, + { EFI_GLOBAL_VARIABLE_GUID, "PlatformLang", validate_ascii_string }, + { EFI_GLOBAL_VARIABLE_GUID, "Timeout", validate_uint16 }, + { LINUX_EFI_CRASH_GUID, "*", NULL }, + { NULL_GUID, "", NULL }, }; +static bool +variable_matches(const char *var_name, size_t len, const char *match_name, + int *match) +{ + for (*match = 0; ; (*match)++) { + char c = match_name[*match]; + char u = var_name[*match]; + + /* Wildcard in the matching name means we've matched */ + if (c == '*') + return true; + + /* Case sensitive match */ + if (!c && *match == len) + return true; + + if (c != u) + return false; + + if (!c) + return true; + } + return true; +} + bool -efivar_validate(efi_char16_t *var_name, u8 *data, unsigned long len) +efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, + unsigned long data_size) { int i; - u16 *unicode_name = var_name; + unsigned long utf8_size; + u8 *utf8_name; - for (i = 0; variable_validate[i].validate != NULL; i++) { - const char *name = variable_validate[i].name; - int match; + utf8_size = ucs2_utf8size(var_name); + utf8_name = kmalloc(utf8_size + 1, GFP_KERNEL); + if (!utf8_name) + return false; - for (match = 0; ; match++) { - char c = name[match]; - u16 u = unicode_name[match]; + ucs2_as_utf8(utf8_name, var_name, utf8_size); + utf8_name[utf8_size] = '\0'; - /* All special variables are plain ascii */ - if (u > 127) - return true; + for (i = 0; variable_validate[i].name[0] != '\0'; i++) { + const char *name = variable_validate[i].name; + int match = 0; - /* Wildcard in the matching name means we've matched */ - if (c == '*') - return variable_validate[i].validate(var_name, - match, data, len); + if (efi_guidcmp(vendor, variable_validate[i].vendor)) + continue; - /* Case sensitive match */ - if (c != u) + if (variable_matches(utf8_name, utf8_size+1, name, &match)) { + if (variable_validate[i].validate == NULL) break; - - /* Reached the end of the string while matching */ - if (!c) - return variable_validate[i].validate(var_name, - match, data, len); + kfree(utf8_name); + return variable_validate[i].validate(var_name, match, + data, data_size); } } - + kfree(utf8_name); return true; } EXPORT_SYMBOL_GPL(efivar_validate); +bool +efivar_variable_is_removable(efi_guid_t vendor, const char *var_name, + size_t len) +{ + int i; + bool found = false; + int match = 0; + + /* + * Check if our variable is in the validated variables list + */ + for (i = 0; variable_validate[i].name[0] != '\0'; i++) { + if (efi_guidcmp(variable_validate[i].vendor, vendor)) + continue; + + if (variable_matches(var_name, len, + variable_validate[i].name, &match)) { + found = true; + break; + } + } + + /* + * If it's in our list, it is removable. + */ + return found; +} +EXPORT_SYMBOL_GPL(efivar_variable_is_removable); + static efi_status_t check_var_size(u32 attributes, unsigned long size) { @@ -852,7 +918,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, *set = false; - if (efivar_validate(name, data, *size) == false) + if (efivar_validate(*vendor, name, data, *size) == false) return -EINVAL; /* diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index 04c270757030..ca066018ea34 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -22,7 +22,7 @@ amdgpu-y += amdgpu_device.o amdgpu_kms.o \ amdgpu_ucode.o amdgpu_bo_list.o amdgpu_ctx.o amdgpu_sync.o # add asic specific block -amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o gmc_v7_0.o cik_ih.o kv_smc.o kv_dpm.o \ +amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o cik_ih.o kv_smc.o kv_dpm.o \ ci_smc.o ci_dpm.o dce_v8_0.o gfx_v7_0.o cik_sdma.o uvd_v4_2.o vce_v2_0.o \ amdgpu_amdkfd_gfx_v7.o @@ -31,6 +31,7 @@ amdgpu-y += \ # add GMC block amdgpu-y += \ + gmc_v7_0.o \ gmc_v8_0.o # add IH block diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 048cfe073dae..bb1099c549df 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -604,8 +604,6 @@ struct amdgpu_sa_manager { uint32_t align; }; -struct amdgpu_sa_bo; - /* sub-allocation buffer */ struct amdgpu_sa_bo { struct list_head olist; @@ -2314,6 +2312,8 @@ bool amdgpu_ttm_bo_is_amdgpu_bo(struct ttm_buffer_object *bo); int amdgpu_ttm_tt_set_userptr(struct ttm_tt *ttm, uint64_t addr, uint32_t flags); bool amdgpu_ttm_tt_has_userptr(struct ttm_tt *ttm); +bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start, + unsigned long end); bool amdgpu_ttm_tt_is_readonly(struct ttm_tt *ttm); uint32_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm, struct ttm_mem_reg *mem); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index 89c3dd62ba21..119cdc2c43e7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -77,7 +77,7 @@ void amdgpu_connector_hotplug(struct drm_connector *connector) } else if (amdgpu_atombios_dp_needs_link_train(amdgpu_connector)) { /* Don't try to start link training before we * have the dpcd */ - if (!amdgpu_atombios_dp_get_dpcd(amdgpu_connector)) + if (amdgpu_atombios_dp_get_dpcd(amdgpu_connector)) return; /* set it to OFF so that drm_helper_connector_dpms() diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index d5b421330145..c961fe093e12 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1744,15 +1744,20 @@ int amdgpu_resume_kms(struct drm_device *dev, bool resume, bool fbcon) } /* post card */ - amdgpu_atom_asic_init(adev->mode_info.atom_context); + if (!amdgpu_card_posted(adev)) + amdgpu_atom_asic_init(adev->mode_info.atom_context); r = amdgpu_resume(adev); + if (r) + DRM_ERROR("amdgpu_resume failed (%d).\n", r); amdgpu_fence_driver_resume(adev); - r = amdgpu_ib_ring_tests(adev); - if (r) - DRM_ERROR("ib ring test failed (%d).\n", r); + if (resume) { + r = amdgpu_ib_ring_tests(adev); + if (r) + DRM_ERROR("ib ring test failed (%d).\n", r); + } r = amdgpu_late_init(adev); if (r) @@ -1788,6 +1793,7 @@ int amdgpu_resume_kms(struct drm_device *dev, bool resume, bool fbcon) } drm_kms_helper_poll_enable(dev); + drm_helper_hpd_irq_event(dev); if (fbcon) { amdgpu_fbdev_set_suspend(adev, 0); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index 5580d3420c3a..82903ca78529 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -72,8 +72,8 @@ static void amdgpu_flip_work_func(struct work_struct *__work) struct drm_crtc *crtc = &amdgpuCrtc->base; unsigned long flags; - unsigned i; - int vpos, hpos, stat, min_udelay; + unsigned i, repcnt = 4; + int vpos, hpos, stat, min_udelay = 0; struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id]; amdgpu_flip_wait_fence(adev, &work->excl); @@ -96,7 +96,7 @@ static void amdgpu_flip_work_func(struct work_struct *__work) * In practice this won't execute very often unless on very fast * machines because the time window for this to happen is very small. */ - for (;;) { + while (amdgpuCrtc->enabled && --repcnt) { /* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank * start in hpos, and to the "fudged earlier" vblank start in * vpos. @@ -112,12 +112,24 @@ static void amdgpu_flip_work_func(struct work_struct *__work) break; /* Sleep at least until estimated real start of hw vblank */ - spin_unlock_irqrestore(&crtc->dev->event_lock, flags); min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5); + if (min_udelay > vblank->framedur_ns / 2000) { + /* Don't wait ridiculously long - something is wrong */ + repcnt = 0; + break; + } + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); usleep_range(min_udelay, 2 * min_udelay); spin_lock_irqsave(&crtc->dev->event_lock, flags); }; + if (!repcnt) + DRM_DEBUG_DRIVER("Delay problem on crtc %d: min_udelay %d, " + "framedur %d, linedur %d, stat %d, vpos %d, " + "hpos %d\n", work->crtc_id, min_udelay, + vblank->framedur_ns / 1000, + vblank->linedur_ns / 1000, stat, vpos, hpos); + /* do the flip (mmio) */ adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base); /* set the flip status */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 0508c5cd103a..8d6668cedf6d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -250,11 +250,11 @@ static struct pci_device_id pciidlist[] = { {0x1002, 0x985F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_MULLINS|AMD_IS_MOBILITY|AMD_IS_APU}, #endif /* topaz */ - {0x1002, 0x6900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ|AMD_EXP_HW_SUPPORT}, - {0x1002, 0x6901, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ|AMD_EXP_HW_SUPPORT}, - {0x1002, 0x6902, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ|AMD_EXP_HW_SUPPORT}, - {0x1002, 0x6903, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ|AMD_EXP_HW_SUPPORT}, - {0x1002, 0x6907, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ|AMD_EXP_HW_SUPPORT}, + {0x1002, 0x6900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ}, + {0x1002, 0x6901, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ}, + {0x1002, 0x6902, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ}, + {0x1002, 0x6903, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ}, + {0x1002, 0x6907, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TOPAZ}, /* tonga */ {0x1002, 0x6920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA}, {0x1002, 0x6921, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA}, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c index b1969f2b2038..d4e2780c0796 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mn.c @@ -142,7 +142,8 @@ static void amdgpu_mn_invalidate_range_start(struct mmu_notifier *mn, list_for_each_entry(bo, &node->bos, mn_list) { - if (!bo->tbo.ttm || bo->tbo.ttm->state != tt_bound) + if (!amdgpu_ttm_tt_affect_userptr(bo->tbo.ttm, start, + end)) continue; r = amdgpu_bo_reserve(bo, true); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index c3ce103b6a33..b8fbbd7699e4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -33,6 +33,7 @@ #include <linux/slab.h> #include <drm/drmP.h> #include <drm/amdgpu_drm.h> +#include <drm/drm_cache.h> #include "amdgpu.h" #include "amdgpu_trace.h" @@ -261,6 +262,13 @@ int amdgpu_bo_create_restricted(struct amdgpu_device *adev, AMDGPU_GEM_DOMAIN_OA); bo->flags = flags; + + /* For architectures that don't support WC memory, + * mask out the WC flag from the BO + */ + if (!drm_arch_can_wc_memory()) + bo->flags &= ~AMDGPU_GEM_CREATE_CPU_GTT_USWC; + amdgpu_fill_placement_to_bo(bo, placement); /* Kernel allocation are uninterruptible */ r = ttm_bo_init(&adev->mman.bdev, &bo->tbo, size, type, @@ -399,7 +407,8 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, } if (fpfn > bo->placements[i].fpfn) bo->placements[i].fpfn = fpfn; - if (lpfn && lpfn < bo->placements[i].lpfn) + if (!bo->placements[i].lpfn || + (lpfn && lpfn < bo->placements[i].lpfn)) bo->placements[i].lpfn = lpfn; bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index 22a8c7d3a3ab..7ae15fad16ed 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -595,11 +595,6 @@ force: /* update display watermarks based on new power state */ amdgpu_display_bandwidth_update(adev); - /* update displays */ - amdgpu_dpm_display_configuration_changed(adev); - - adev->pm.dpm.current_active_crtcs = adev->pm.dpm.new_active_crtcs; - adev->pm.dpm.current_active_crtc_count = adev->pm.dpm.new_active_crtc_count; /* wait for the rings to drain */ for (i = 0; i < AMDGPU_MAX_RINGS; i++) { @@ -616,6 +611,12 @@ force: amdgpu_dpm_post_set_power_state(adev); + /* update displays */ + amdgpu_dpm_display_configuration_changed(adev); + + adev->pm.dpm.current_active_crtcs = adev->pm.dpm.new_active_crtcs; + adev->pm.dpm.current_active_crtc_count = adev->pm.dpm.new_active_crtc_count; + if (adev->pm.funcs->force_performance_level) { if (adev->pm.dpm.thermal_active) { enum amdgpu_dpm_forced_level level = adev->pm.dpm.forced_level; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c index 8b88edb0434b..ca72a2e487b9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c @@ -354,12 +354,15 @@ int amdgpu_sa_bo_new(struct amdgpu_sa_manager *sa_manager, for (i = 0, count = 0; i < AMDGPU_MAX_RINGS; ++i) if (fences[i]) - fences[count++] = fences[i]; + fences[count++] = fence_get(fences[i]); if (count) { spin_unlock(&sa_manager->wq.lock); t = fence_wait_any_timeout(fences, count, false, MAX_SCHEDULE_TIMEOUT); + for (i = 0; i < count; ++i) + fence_put(fences[i]); + r = (t > 0) ? 0 : t; spin_lock(&sa_manager->wq.lock); } else { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c index dd005c336c97..181ce39ef5e5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c @@ -293,7 +293,8 @@ int amdgpu_sync_rings(struct amdgpu_sync *sync, fence = to_amdgpu_fence(sync->sync_to[i]); /* check if we really need to sync */ - if (!amdgpu_fence_need_sync(fence, ring)) + if (!amdgpu_enable_scheduler && + !amdgpu_fence_need_sync(fence, ring)) continue; /* prevent GPU deadlocks */ @@ -303,7 +304,7 @@ int amdgpu_sync_rings(struct amdgpu_sync *sync, } if (amdgpu_enable_scheduler || !amdgpu_enable_semaphores) { - r = fence_wait(&fence->base, true); + r = fence_wait(sync->sync_to[i], true); if (r) return r; continue; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 8a1752ff3d8e..1cbb16e15307 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -712,7 +712,7 @@ static int amdgpu_ttm_tt_populate(struct ttm_tt *ttm) 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); if (pci_dma_mapping_error(adev->pdev, gtt->ttm.dma_address[i])) { - while (--i) { + while (i--) { pci_unmap_page(adev->pdev, gtt->ttm.dma_address[i], PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); gtt->ttm.dma_address[i] = 0; @@ -783,6 +783,25 @@ bool amdgpu_ttm_tt_has_userptr(struct ttm_tt *ttm) return !!gtt->userptr; } +bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start, + unsigned long end) +{ + struct amdgpu_ttm_tt *gtt = (void *)ttm; + unsigned long size; + + if (gtt == NULL) + return false; + + if (gtt->ttm.ttm.state != tt_bound || !gtt->userptr) + return false; + + size = (unsigned long)gtt->ttm.ttm.num_pages * PAGE_SIZE; + if (gtt->userptr > end || gtt->userptr + size <= start) + return false; + + return true; +} + bool amdgpu_ttm_tt_is_readonly(struct ttm_tt *ttm) { struct amdgpu_ttm_tt *gtt = (void *)ttm; @@ -808,7 +827,7 @@ uint32_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm, flags |= AMDGPU_PTE_SNOOPED; } - if (adev->asic_type >= CHIP_TOPAZ) + if (adev->asic_type >= CHIP_TONGA) flags |= AMDGPU_PTE_EXECUTABLE; flags |= AMDGPU_PTE_READABLE; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index b53d273eb7a1..8c5ec151ddac 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1010,13 +1010,13 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev, return -EINVAL; /* make sure object fit at this offset */ - eaddr = saddr + size; + eaddr = saddr + size - 1; if ((saddr >= eaddr) || (offset + size > amdgpu_bo_size(bo_va->bo))) return -EINVAL; last_pfn = eaddr / AMDGPU_GPU_PAGE_SIZE; - if (last_pfn > adev->vm_manager.max_pfn) { - dev_err(adev->dev, "va above limit (0x%08X > 0x%08X)\n", + if (last_pfn >= adev->vm_manager.max_pfn) { + dev_err(adev->dev, "va above limit (0x%08X >= 0x%08X)\n", last_pfn, adev->vm_manager.max_pfn); return -EINVAL; } @@ -1025,7 +1025,7 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev, eaddr /= AMDGPU_GPU_PAGE_SIZE; spin_lock(&vm->it_lock); - it = interval_tree_iter_first(&vm->va, saddr, eaddr - 1); + it = interval_tree_iter_first(&vm->va, saddr, eaddr); spin_unlock(&vm->it_lock); if (it) { struct amdgpu_bo_va_mapping *tmp; @@ -1046,7 +1046,7 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev, INIT_LIST_HEAD(&mapping->list); mapping->it.start = saddr; - mapping->it.last = eaddr - 1; + mapping->it.last = eaddr; mapping->offset = offset; mapping->flags = flags; @@ -1248,7 +1248,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm) { const unsigned align = min(AMDGPU_VM_PTB_ALIGN_SIZE, AMDGPU_VM_PTE_COUNT * 8); - unsigned pd_size, pd_entries, pts_size; + unsigned pd_size, pd_entries; int i, r; for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { @@ -1266,8 +1266,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm) pd_entries = amdgpu_vm_num_pdes(adev); /* allocate page table array */ - pts_size = pd_entries * sizeof(struct amdgpu_vm_pt); - vm->page_tables = kzalloc(pts_size, GFP_KERNEL); + vm->page_tables = drm_calloc_large(pd_entries, sizeof(struct amdgpu_vm_pt)); if (vm->page_tables == NULL) { DRM_ERROR("Cannot allocate memory for page table array\n"); return -ENOMEM; @@ -1327,7 +1326,7 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) for (i = 0; i < amdgpu_vm_num_pdes(adev); i++) amdgpu_bo_unref(&vm->page_tables[i].bo); - kfree(vm->page_tables); + drm_free_large(vm->page_tables); amdgpu_bo_unref(&vm->page_directory); fence_put(vm->page_directory_fence); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index 72793f93e2fc..aa491540ba85 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c @@ -3628,6 +3628,19 @@ static void gfx_v7_0_ring_emit_vm_flush(struct amdgpu_ring *ring, unsigned vm_id, uint64_t pd_addr) { int usepfp = (ring->type == AMDGPU_RING_TYPE_GFX); + uint32_t seq = ring->fence_drv.sync_seq; + uint64_t addr = ring->fence_drv.gpu_addr; + + amdgpu_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5)); + amdgpu_ring_write(ring, (WAIT_REG_MEM_MEM_SPACE(1) | /* memory */ + WAIT_REG_MEM_FUNCTION(3) | /* equal */ + WAIT_REG_MEM_ENGINE(usepfp))); /* pfp or me */ + amdgpu_ring_write(ring, addr & 0xfffffffc); + amdgpu_ring_write(ring, upper_32_bits(addr) & 0xffffffff); + amdgpu_ring_write(ring, seq); + amdgpu_ring_write(ring, 0xffffffff); + amdgpu_ring_write(ring, 4); /* poll interval */ + if (usepfp) { /* synce CE with ME to prevent CE fetch CEIB before context switch done */ amdgpu_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0)); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index e1dcab98e249..d1054034d14b 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -90,7 +90,6 @@ MODULE_FIRMWARE("amdgpu/topaz_ce.bin"); MODULE_FIRMWARE("amdgpu/topaz_pfp.bin"); MODULE_FIRMWARE("amdgpu/topaz_me.bin"); MODULE_FIRMWARE("amdgpu/topaz_mec.bin"); -MODULE_FIRMWARE("amdgpu/topaz_mec2.bin"); MODULE_FIRMWARE("amdgpu/topaz_rlc.bin"); MODULE_FIRMWARE("amdgpu/fiji_ce.bin"); @@ -807,7 +806,8 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev) adev->gfx.mec_fw_version = le32_to_cpu(cp_hdr->header.ucode_version); adev->gfx.mec_feature_version = le32_to_cpu(cp_hdr->ucode_feature_version); - if (adev->asic_type != CHIP_STONEY) { + if ((adev->asic_type != CHIP_STONEY) && + (adev->asic_type != CHIP_TOPAZ)) { snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mec2.bin", chip_name); err = request_firmware(&adev->gfx.mec2_fw, fw_name, adev->dev); if (!err) { @@ -4681,7 +4681,8 @@ static void gfx_v8_0_ring_emit_vm_flush(struct amdgpu_ring *ring, amdgpu_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5)); amdgpu_ring_write(ring, (WAIT_REG_MEM_MEM_SPACE(1) | /* memory */ - WAIT_REG_MEM_FUNCTION(3))); /* equal */ + WAIT_REG_MEM_FUNCTION(3) | /* equal */ + WAIT_REG_MEM_ENGINE(usepfp))); /* pfp or me */ amdgpu_ring_write(ring, addr & 0xfffffffc); amdgpu_ring_write(ring, upper_32_bits(addr) & 0xffffffff); amdgpu_ring_write(ring, seq); diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c index ed8abb58a785..272110cc18c2 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c @@ -42,9 +42,39 @@ static void gmc_v7_0_set_irq_funcs(struct amdgpu_device *adev); MODULE_FIRMWARE("radeon/bonaire_mc.bin"); MODULE_FIRMWARE("radeon/hawaii_mc.bin"); +MODULE_FIRMWARE("amdgpu/topaz_mc.bin"); + +static const u32 golden_settings_iceland_a11[] = +{ + mmVM_PRT_APERTURE0_LOW_ADDR, 0x0fffffff, 0x0fffffff, + mmVM_PRT_APERTURE1_LOW_ADDR, 0x0fffffff, 0x0fffffff, + mmVM_PRT_APERTURE2_LOW_ADDR, 0x0fffffff, 0x0fffffff, + mmVM_PRT_APERTURE3_LOW_ADDR, 0x0fffffff, 0x0fffffff +}; + +static const u32 iceland_mgcg_cgcg_init[] = +{ + mmMC_MEM_POWER_LS, 0xffffffff, 0x00000104 +}; + +static void gmc_v7_0_init_golden_registers(struct amdgpu_device *adev) +{ + switch (adev->asic_type) { + case CHIP_TOPAZ: + amdgpu_program_register_sequence(adev, + iceland_mgcg_cgcg_init, + (const u32)ARRAY_SIZE(iceland_mgcg_cgcg_init)); + amdgpu_program_register_sequence(adev, + golden_settings_iceland_a11, + (const u32)ARRAY_SIZE(golden_settings_iceland_a11)); + break; + default: + break; + } +} /** - * gmc8_mc_wait_for_idle - wait for MC idle callback. + * gmc7_mc_wait_for_idle - wait for MC idle callback. * * @adev: amdgpu_device pointer * @@ -132,13 +162,20 @@ static int gmc_v7_0_init_microcode(struct amdgpu_device *adev) case CHIP_HAWAII: chip_name = "hawaii"; break; + case CHIP_TOPAZ: + chip_name = "topaz"; + break; case CHIP_KAVERI: case CHIP_KABINI: return 0; default: BUG(); } - snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); + if (adev->asic_type == CHIP_TOPAZ) + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_mc.bin", chip_name); + else + snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); + err = request_firmware(&adev->mc.fw, fw_name, adev->dev); if (err) goto out; @@ -980,6 +1017,8 @@ static int gmc_v7_0_hw_init(void *handle) int r; struct amdgpu_device *adev = (struct amdgpu_device *)handle; + gmc_v7_0_init_golden_registers(adev); + gmc_v7_0_mc_program(adev); if (!(adev->flags & AMD_IS_APU)) { diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index d39028440814..ba4ad00ba8b4 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c @@ -42,9 +42,7 @@ static void gmc_v8_0_set_gart_funcs(struct amdgpu_device *adev); static void gmc_v8_0_set_irq_funcs(struct amdgpu_device *adev); -MODULE_FIRMWARE("amdgpu/topaz_mc.bin"); MODULE_FIRMWARE("amdgpu/tonga_mc.bin"); -MODULE_FIRMWARE("amdgpu/fiji_mc.bin"); static const u32 golden_settings_tonga_a11[] = { @@ -75,19 +73,6 @@ static const u32 fiji_mgcg_cgcg_init[] = mmMC_MEM_POWER_LS, 0xffffffff, 0x00000104 }; -static const u32 golden_settings_iceland_a11[] = -{ - mmVM_PRT_APERTURE0_LOW_ADDR, 0x0fffffff, 0x0fffffff, - mmVM_PRT_APERTURE1_LOW_ADDR, 0x0fffffff, 0x0fffffff, - mmVM_PRT_APERTURE2_LOW_ADDR, 0x0fffffff, 0x0fffffff, - mmVM_PRT_APERTURE3_LOW_ADDR, 0x0fffffff, 0x0fffffff -}; - -static const u32 iceland_mgcg_cgcg_init[] = -{ - mmMC_MEM_POWER_LS, 0xffffffff, 0x00000104 -}; - static const u32 cz_mgcg_cgcg_init[] = { mmMC_MEM_POWER_LS, 0xffffffff, 0x00000104 @@ -102,14 +87,6 @@ static const u32 stoney_mgcg_cgcg_init[] = static void gmc_v8_0_init_golden_registers(struct amdgpu_device *adev) { switch (adev->asic_type) { - case CHIP_TOPAZ: - amdgpu_program_register_sequence(adev, - iceland_mgcg_cgcg_init, - (const u32)ARRAY_SIZE(iceland_mgcg_cgcg_init)); - amdgpu_program_register_sequence(adev, - golden_settings_iceland_a11, - (const u32)ARRAY_SIZE(golden_settings_iceland_a11)); - break; case CHIP_FIJI: amdgpu_program_register_sequence(adev, fiji_mgcg_cgcg_init, @@ -229,15 +206,10 @@ static int gmc_v8_0_init_microcode(struct amdgpu_device *adev) DRM_DEBUG("\n"); switch (adev->asic_type) { - case CHIP_TOPAZ: - chip_name = "topaz"; - break; case CHIP_TONGA: chip_name = "tonga"; break; case CHIP_FIJI: - chip_name = "fiji"; - break; case CHIP_CARRIZO: case CHIP_STONEY: return 0; @@ -1003,7 +975,7 @@ static int gmc_v8_0_hw_init(void *handle) gmc_v8_0_mc_program(adev); - if (!(adev->flags & AMD_IS_APU)) { + if (adev->asic_type == CHIP_TONGA) { r = gmc_v8_0_mc_load_microcode(adev); if (r) { DRM_ERROR("Failed to load MC firmware!\n"); diff --git a/drivers/gpu/drm/amd/amdgpu/iceland_smc.c b/drivers/gpu/drm/amd/amdgpu/iceland_smc.c index 966d4b2ed9da..090486c18249 100644 --- a/drivers/gpu/drm/amd/amdgpu/iceland_smc.c +++ b/drivers/gpu/drm/amd/amdgpu/iceland_smc.c @@ -432,7 +432,7 @@ static uint32_t iceland_smu_get_mask_for_fw_type(uint32_t fw_type) case AMDGPU_UCODE_ID_CP_ME: return UCODE_ID_CP_ME_MASK; case AMDGPU_UCODE_ID_CP_MEC1: - return UCODE_ID_CP_MEC_MASK | UCODE_ID_CP_MEC_JT1_MASK | UCODE_ID_CP_MEC_JT2_MASK; + return UCODE_ID_CP_MEC_MASK | UCODE_ID_CP_MEC_JT1_MASK; case AMDGPU_UCODE_ID_CP_MEC2: return UCODE_ID_CP_MEC_MASK; case AMDGPU_UCODE_ID_RLC_G: @@ -522,12 +522,6 @@ static int iceland_smu_request_load_fw(struct amdgpu_device *adev) return -EINVAL; } - if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_CP_MEC_JT2, - &toc->entry[toc->num_entries++])) { - DRM_ERROR("Failed to get firmware entry for MEC_JT2\n"); - return -EINVAL; - } - if (iceland_smu_populate_single_firmware_entry(adev, UCODE_ID_SDMA0, &toc->entry[toc->num_entries++])) { DRM_ERROR("Failed to get firmware entry for SDMA0\n"); @@ -550,8 +544,8 @@ static int iceland_smu_request_load_fw(struct amdgpu_device *adev) UCODE_ID_CP_ME_MASK | UCODE_ID_CP_PFP_MASK | UCODE_ID_CP_MEC_MASK | - UCODE_ID_CP_MEC_JT1_MASK | - UCODE_ID_CP_MEC_JT2_MASK; + UCODE_ID_CP_MEC_JT1_MASK; + if (iceland_send_msg_to_smc_with_parameter_without_waiting(adev, PPSMC_MSG_LoadUcodes, fw_to_load)) { DRM_ERROR("Fail to request SMU load ucode\n"); diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_dpm.c b/drivers/gpu/drm/amd/amdgpu/tonga_dpm.c index 204903897b4f..63d6cb3c1110 100644 --- a/drivers/gpu/drm/amd/amdgpu/tonga_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/tonga_dpm.c @@ -122,25 +122,12 @@ static int tonga_dpm_hw_fini(void *handle) static int tonga_dpm_suspend(void *handle) { - return 0; + return tonga_dpm_hw_fini(handle); } static int tonga_dpm_resume(void *handle) { - int ret; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - mutex_lock(&adev->pm.mutex); - - ret = tonga_smu_start(adev); - if (ret) { - DRM_ERROR("SMU start failed\n"); - goto fail; - } - -fail: - mutex_unlock(&adev->pm.mutex); - return ret; + return tonga_dpm_hw_init(handle); } static int tonga_dpm_set_clockgating_state(void *handle, diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index 2adc1c855e85..3e9cbe398151 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c @@ -60,6 +60,7 @@ #include "vi.h" #include "vi_dpm.h" #include "gmc_v8_0.h" +#include "gmc_v7_0.h" #include "gfx_v8_0.h" #include "sdma_v2_4.h" #include "sdma_v3_0.h" @@ -1081,10 +1082,10 @@ static const struct amdgpu_ip_block_version topaz_ip_blocks[] = }, { .type = AMD_IP_BLOCK_TYPE_GMC, - .major = 8, - .minor = 0, + .major = 7, + .minor = 4, .rev = 0, - .funcs = &gmc_v8_0_ip_funcs, + .funcs = &gmc_v7_0_ip_funcs, }, { .type = AMD_IP_BLOCK_TYPE_IH, diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 541a610667ad..e0b4586a26fd 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -227,7 +227,7 @@ static int ast_get_dram_info(struct drm_device *dev) } while (ast_read32(ast, 0x10000) != 0x01); data = ast_read32(ast, 0x10004); - if (data & 0x400) + if (data & 0x40) ast->dram_bus_width = 16; else ast->dram_bus_width = 32; diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 809959d56d78..39d7e2e15c11 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -798,6 +798,18 @@ static struct drm_dp_mst_branch *drm_dp_add_mst_branch_device(u8 lct, u8 *rad) return mstb; } +static void drm_dp_free_mst_port(struct kref *kref); + +static void drm_dp_free_mst_branch_device(struct kref *kref) +{ + struct drm_dp_mst_branch *mstb = container_of(kref, struct drm_dp_mst_branch, kref); + if (mstb->port_parent) { + if (list_empty(&mstb->port_parent->next)) + kref_put(&mstb->port_parent->kref, drm_dp_free_mst_port); + } + kfree(mstb); +} + static void drm_dp_destroy_mst_branch_device(struct kref *kref) { struct drm_dp_mst_branch *mstb = container_of(kref, struct drm_dp_mst_branch, kref); @@ -805,6 +817,15 @@ static void drm_dp_destroy_mst_branch_device(struct kref *kref) bool wake_tx = false; /* + * init kref again to be used by ports to remove mst branch when it is + * not needed anymore + */ + kref_init(kref); + + if (mstb->port_parent && list_empty(&mstb->port_parent->next)) + kref_get(&mstb->port_parent->kref); + + /* * destroy all ports - don't need lock * as there are no more references to the mst branch * device at this point. @@ -830,7 +851,8 @@ static void drm_dp_destroy_mst_branch_device(struct kref *kref) if (wake_tx) wake_up(&mstb->mgr->tx_waitq); - kfree(mstb); + + kref_put(kref, drm_dp_free_mst_branch_device); } static void drm_dp_put_mst_branch_device(struct drm_dp_mst_branch *mstb) @@ -878,6 +900,7 @@ static void drm_dp_destroy_port(struct kref *kref) * from an EDID retrieval */ mutex_lock(&mgr->destroy_connector_lock); + kref_get(&port->parent->kref); list_add(&port->next, &mgr->destroy_connector_list); mutex_unlock(&mgr->destroy_connector_lock); schedule_work(&mgr->destroy_connector_work); @@ -973,17 +996,17 @@ static struct drm_dp_mst_port *drm_dp_get_port(struct drm_dp_mst_branch *mstb, u static u8 drm_dp_calculate_rad(struct drm_dp_mst_port *port, u8 *rad) { - int lct = port->parent->lct; + int parent_lct = port->parent->lct; int shift = 4; - int idx = lct / 2; - if (lct > 1) { - memcpy(rad, port->parent->rad, idx); - shift = (lct % 2) ? 4 : 0; + int idx = (parent_lct - 1) / 2; + if (parent_lct > 1) { + memcpy(rad, port->parent->rad, idx + 1); + shift = (parent_lct % 2) ? 4 : 0; } else rad[0] = 0; rad[idx] |= port->port_num << shift; - return lct + 1; + return parent_lct + 1; } /* @@ -1013,18 +1036,27 @@ static bool drm_dp_port_setup_pdt(struct drm_dp_mst_port *port) return send_link; } -static void drm_dp_check_port_guid(struct drm_dp_mst_branch *mstb, - struct drm_dp_mst_port *port) +static void drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, u8 *guid) { int ret; - if (port->dpcd_rev >= 0x12) { - port->guid_valid = drm_dp_validate_guid(mstb->mgr, port->guid); - if (!port->guid_valid) { - ret = drm_dp_send_dpcd_write(mstb->mgr, - port, - DP_GUID, - 16, port->guid); - port->guid_valid = true; + + memcpy(mstb->guid, guid, 16); + + if (!drm_dp_validate_guid(mstb->mgr, mstb->guid)) { + if (mstb->port_parent) { + ret = drm_dp_send_dpcd_write( + mstb->mgr, + mstb->port_parent, + DP_GUID, + 16, + mstb->guid); + } else { + + ret = drm_dp_dpcd_write( + mstb->mgr->aux, + DP_GUID, + mstb->guid, + 16); } } } @@ -1039,7 +1071,7 @@ static void build_mst_prop_path(const struct drm_dp_mst_branch *mstb, snprintf(proppath, proppath_size, "mst:%d", mstb->mgr->conn_base_id); for (i = 0; i < (mstb->lct - 1); i++) { int shift = (i % 2) ? 0 : 4; - int port_num = mstb->rad[i / 2] >> shift; + int port_num = (mstb->rad[i / 2] >> shift) & 0xf; snprintf(temp, sizeof(temp), "-%d", port_num); strlcat(proppath, temp, proppath_size); } @@ -1081,7 +1113,6 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, port->dpcd_rev = port_msg->dpcd_revision; port->num_sdp_streams = port_msg->num_sdp_streams; port->num_sdp_stream_sinks = port_msg->num_sdp_stream_sinks; - memcpy(port->guid, port_msg->peer_guid, 16); /* manage mstb port lists with mgr lock - take a reference for this list */ @@ -1094,11 +1125,9 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb, if (old_ddps != port->ddps) { if (port->ddps) { - drm_dp_check_port_guid(mstb, port); if (!port->input) drm_dp_send_enum_path_resources(mstb->mgr, mstb, port); } else { - port->guid_valid = false; port->available_pbn = 0; } } @@ -1157,10 +1186,8 @@ static void drm_dp_update_port(struct drm_dp_mst_branch *mstb, if (old_ddps != port->ddps) { if (port->ddps) { - drm_dp_check_port_guid(mstb, port); dowork = true; } else { - port->guid_valid = false; port->available_pbn = 0; } } @@ -1190,7 +1217,7 @@ static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device(struct drm_dp_mst_ for (i = 0; i < lct - 1; i++) { int shift = (i % 2) ? 0 : 4; - int port_num = rad[i / 2] >> shift; + int port_num = (rad[i / 2] >> shift) & 0xf; list_for_each_entry(port, &mstb->ports, next) { if (port->port_num == port_num) { @@ -1210,6 +1237,48 @@ out: return mstb; } +static struct drm_dp_mst_branch *get_mst_branch_device_by_guid_helper( + struct drm_dp_mst_branch *mstb, + uint8_t *guid) +{ + struct drm_dp_mst_branch *found_mstb; + struct drm_dp_mst_port *port; + + if (memcmp(mstb->guid, guid, 16) == 0) + return mstb; + + + list_for_each_entry(port, &mstb->ports, next) { + if (!port->mstb) + continue; + + found_mstb = get_mst_branch_device_by_guid_helper(port->mstb, guid); + + if (found_mstb) + return found_mstb; + } + + return NULL; +} + +static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device_by_guid( + struct drm_dp_mst_topology_mgr *mgr, + uint8_t *guid) +{ + struct drm_dp_mst_branch *mstb; + + /* find the port by iterating down */ + mutex_lock(&mgr->lock); + + mstb = get_mst_branch_device_by_guid_helper(mgr->mst_primary, guid); + + if (mstb) + kref_get(&mstb->kref); + + mutex_unlock(&mgr->lock); + return mstb; +} + static void drm_dp_check_and_send_link_address(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_branch *mstb) { @@ -1320,6 +1389,7 @@ static int set_hdr_from_dst_qlock(struct drm_dp_sideband_msg_hdr *hdr, struct drm_dp_sideband_msg_tx *txmsg) { struct drm_dp_mst_branch *mstb = txmsg->dst; + u8 req_type; /* both msg slots are full */ if (txmsg->seqno == -1) { @@ -1336,7 +1406,13 @@ static int set_hdr_from_dst_qlock(struct drm_dp_sideband_msg_hdr *hdr, txmsg->seqno = 1; mstb->tx_slots[txmsg->seqno] = txmsg; } - hdr->broadcast = 0; + + req_type = txmsg->msg[0] & 0x7f; + if (req_type == DP_CONNECTION_STATUS_NOTIFY || + req_type == DP_RESOURCE_STATUS_NOTIFY) + hdr->broadcast = 1; + else + hdr->broadcast = 0; hdr->path_msg = txmsg->path_msg; hdr->lct = mstb->lct; hdr->lcr = mstb->lct - 1; @@ -1438,26 +1514,18 @@ static void process_single_down_tx_qlock(struct drm_dp_mst_topology_mgr *mgr) } /* called holding qlock */ -static void process_single_up_tx_qlock(struct drm_dp_mst_topology_mgr *mgr) +static void process_single_up_tx_qlock(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_sideband_msg_tx *txmsg) { - struct drm_dp_sideband_msg_tx *txmsg; int ret; /* construct a chunk from the first msg in the tx_msg queue */ - if (list_empty(&mgr->tx_msg_upq)) { - mgr->tx_up_in_progress = false; - return; - } - - txmsg = list_first_entry(&mgr->tx_msg_upq, struct drm_dp_sideband_msg_tx, next); ret = process_single_tx_qlock(mgr, txmsg, true); - if (ret == 1) { - /* up txmsgs aren't put in slots - so free after we send it */ - list_del(&txmsg->next); - kfree(txmsg); - } else if (ret) + + if (ret != 1) DRM_DEBUG_KMS("failed to send msg in q %d\n", ret); - mgr->tx_up_in_progress = true; + + txmsg->dst->tx_slots[txmsg->seqno] = NULL; } static void drm_dp_queue_down_tx(struct drm_dp_mst_topology_mgr *mgr, @@ -1507,6 +1575,9 @@ static void drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr, txmsg->reply.u.link_addr.ports[i].num_sdp_streams, txmsg->reply.u.link_addr.ports[i].num_sdp_stream_sinks); } + + drm_dp_check_mstb_guid(mstb, txmsg->reply.u.link_addr.guid); + for (i = 0; i < txmsg->reply.u.link_addr.nports; i++) { drm_dp_add_port(mstb, mgr->dev, &txmsg->reply.u.link_addr.ports[i]); } @@ -1554,6 +1625,37 @@ static int drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr, return 0; } +static struct drm_dp_mst_port *drm_dp_get_last_connected_port_to_mstb(struct drm_dp_mst_branch *mstb) +{ + if (!mstb->port_parent) + return NULL; + + if (mstb->port_parent->mstb != mstb) + return mstb->port_parent; + + return drm_dp_get_last_connected_port_to_mstb(mstb->port_parent->parent); +} + +static struct drm_dp_mst_branch *drm_dp_get_last_connected_port_and_mstb(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_branch *mstb, + int *port_num) +{ + struct drm_dp_mst_branch *rmstb = NULL; + struct drm_dp_mst_port *found_port; + mutex_lock(&mgr->lock); + if (mgr->mst_primary) { + found_port = drm_dp_get_last_connected_port_to_mstb(mstb); + + if (found_port) { + rmstb = found_port->parent; + kref_get(&rmstb->kref); + *port_num = found_port->port_num; + } + } + mutex_unlock(&mgr->lock); + return rmstb; +} + static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, int id, @@ -1561,11 +1663,16 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, { struct drm_dp_sideband_msg_tx *txmsg; struct drm_dp_mst_branch *mstb; - int len, ret; + int len, ret, port_num; + port_num = port->port_num; mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent); - if (!mstb) - return -EINVAL; + if (!mstb) { + mstb = drm_dp_get_last_connected_port_and_mstb(mgr, port->parent, &port_num); + + if (!mstb) + return -EINVAL; + } txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); if (!txmsg) { @@ -1574,7 +1681,7 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, } txmsg->dst = mstb; - len = build_allocate_payload(txmsg, port->port_num, + len = build_allocate_payload(txmsg, port_num, id, pbn); @@ -1844,11 +1951,12 @@ static int drm_dp_send_up_ack_reply(struct drm_dp_mst_topology_mgr *mgr, drm_dp_encode_up_ack_reply(txmsg, req_type); mutex_lock(&mgr->qlock); - list_add_tail(&txmsg->next, &mgr->tx_msg_upq); - if (!mgr->tx_up_in_progress) { - process_single_up_tx_qlock(mgr); - } + + process_single_up_tx_qlock(mgr, txmsg); + mutex_unlock(&mgr->qlock); + + kfree(txmsg); return 0; } @@ -1927,31 +2035,17 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms mgr->mst_primary = mstb; kref_get(&mgr->mst_primary->kref); - { - struct drm_dp_payload reset_pay; - reset_pay.start_slot = 0; - reset_pay.num_slots = 0x3f; - drm_dp_dpcd_write_payload(mgr, 0, &reset_pay); - } - ret = drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, - DP_MST_EN | DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC); + DP_MST_EN | DP_UP_REQ_EN | DP_UPSTREAM_IS_SRC); if (ret < 0) { goto out_unlock; } - - /* sort out guid */ - ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, mgr->guid, 16); - if (ret != 16) { - DRM_DEBUG_KMS("failed to read DP GUID %d\n", ret); - goto out_unlock; - } - - mgr->guid_valid = drm_dp_validate_guid(mgr, mgr->guid); - if (!mgr->guid_valid) { - ret = drm_dp_dpcd_write(mgr->aux, DP_GUID, mgr->guid, 16); - mgr->guid_valid = true; + { + struct drm_dp_payload reset_pay; + reset_pay.start_slot = 0; + reset_pay.num_slots = 0x3f; + drm_dp_dpcd_write_payload(mgr, 0, &reset_pay); } queue_work(system_long_wq, &mgr->work); @@ -2145,28 +2239,51 @@ static int drm_dp_mst_handle_up_req(struct drm_dp_mst_topology_mgr *mgr) if (mgr->up_req_recv.have_eomt) { struct drm_dp_sideband_msg_req_body msg; - struct drm_dp_mst_branch *mstb; + struct drm_dp_mst_branch *mstb = NULL; bool seqno; - mstb = drm_dp_get_mst_branch_device(mgr, - mgr->up_req_recv.initial_hdr.lct, - mgr->up_req_recv.initial_hdr.rad); - if (!mstb) { - DRM_DEBUG_KMS("Got MST reply from unknown device %d\n", mgr->up_req_recv.initial_hdr.lct); - memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx)); - return 0; + + if (!mgr->up_req_recv.initial_hdr.broadcast) { + mstb = drm_dp_get_mst_branch_device(mgr, + mgr->up_req_recv.initial_hdr.lct, + mgr->up_req_recv.initial_hdr.rad); + if (!mstb) { + DRM_DEBUG_KMS("Got MST reply from unknown device %d\n", mgr->up_req_recv.initial_hdr.lct); + memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx)); + return 0; + } } seqno = mgr->up_req_recv.initial_hdr.seqno; drm_dp_sideband_parse_req(&mgr->up_req_recv, &msg); if (msg.req_type == DP_CONNECTION_STATUS_NOTIFY) { - drm_dp_send_up_ack_reply(mgr, mstb, msg.req_type, seqno, false); + drm_dp_send_up_ack_reply(mgr, mgr->mst_primary, msg.req_type, seqno, false); + + if (!mstb) + mstb = drm_dp_get_mst_branch_device_by_guid(mgr, msg.u.conn_stat.guid); + + if (!mstb) { + DRM_DEBUG_KMS("Got MST reply from unknown device %d\n", mgr->up_req_recv.initial_hdr.lct); + memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx)); + return 0; + } + drm_dp_update_port(mstb, &msg.u.conn_stat); + DRM_DEBUG_KMS("Got CSN: pn: %d ldps:%d ddps: %d mcs: %d ip: %d pdt: %d\n", msg.u.conn_stat.port_number, msg.u.conn_stat.legacy_device_plug_status, msg.u.conn_stat.displayport_device_plug_status, msg.u.conn_stat.message_capability_status, msg.u.conn_stat.input_port, msg.u.conn_stat.peer_device_type); (*mgr->cbs->hotplug)(mgr); } else if (msg.req_type == DP_RESOURCE_STATUS_NOTIFY) { - drm_dp_send_up_ack_reply(mgr, mstb, msg.req_type, seqno, false); + drm_dp_send_up_ack_reply(mgr, mgr->mst_primary, msg.req_type, seqno, false); + if (!mstb) + mstb = drm_dp_get_mst_branch_device_by_guid(mgr, msg.u.resource_stat.guid); + + if (!mstb) { + DRM_DEBUG_KMS("Got MST reply from unknown device %d\n", mgr->up_req_recv.initial_hdr.lct); + memset(&mgr->up_req_recv, 0, sizeof(struct drm_dp_sideband_msg_rx)); + return 0; + } + DRM_DEBUG_KMS("Got RSN: pn: %d avail_pbn %d\n", msg.u.resource_stat.port_number, msg.u.resource_stat.available_pbn); } @@ -2346,6 +2463,7 @@ bool drm_dp_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp DRM_DEBUG_KMS("payload: vcpi %d already allocated for pbn %d - requested pbn %d\n", port->vcpi.vcpi, port->vcpi.pbn, pbn); if (pbn == port->vcpi.pbn) { *slots = port->vcpi.num_slots; + drm_dp_put_port(port); return true; } } @@ -2505,32 +2623,31 @@ EXPORT_SYMBOL(drm_dp_check_act_status); */ int drm_dp_calc_pbn_mode(int clock, int bpp) { - fixed20_12 pix_bw; - fixed20_12 fbpp; - fixed20_12 result; - fixed20_12 margin, tmp; - u32 res; - - pix_bw.full = dfixed_const(clock); - fbpp.full = dfixed_const(bpp); - tmp.full = dfixed_const(8); - fbpp.full = dfixed_div(fbpp, tmp); - - result.full = dfixed_mul(pix_bw, fbpp); - margin.full = dfixed_const(54); - tmp.full = dfixed_const(64); - margin.full = dfixed_div(margin, tmp); - result.full = dfixed_div(result, margin); - - margin.full = dfixed_const(1006); - tmp.full = dfixed_const(1000); - margin.full = dfixed_div(margin, tmp); - result.full = dfixed_mul(result, margin); - - result.full = dfixed_div(result, tmp); - result.full = dfixed_ceil(result); - res = dfixed_trunc(result); - return res; + u64 kbps; + s64 peak_kbps; + u32 numerator; + u32 denominator; + + kbps = clock * bpp; + + /* + * margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006 + * The unit of 54/64Mbytes/sec is an arbitrary unit chosen based on + * common multiplier to render an integer PBN for all link rate/lane + * counts combinations + * calculate + * peak_kbps *= (1006/1000) + * peak_kbps *= (64/54) + * peak_kbps *= 8 convert to bytes + */ + + numerator = 64 * 1006; + denominator = 54 * 8 * 1000 * 1000; + + kbps *= numerator; + peak_kbps = drm_fixp_from_fraction(kbps, denominator); + + return drm_fixp2int_ceil(peak_kbps); } EXPORT_SYMBOL(drm_dp_calc_pbn_mode); @@ -2538,11 +2655,23 @@ static int test_calc_pbn_mode(void) { int ret; ret = drm_dp_calc_pbn_mode(154000, 30); - if (ret != 689) + if (ret != 689) { + DRM_ERROR("PBN calculation test failed - clock %d, bpp %d, expected PBN %d, actual PBN %d.\n", + 154000, 30, 689, ret); return -EINVAL; + } ret = drm_dp_calc_pbn_mode(234000, 30); - if (ret != 1047) + if (ret != 1047) { + DRM_ERROR("PBN calculation test failed - clock %d, bpp %d, expected PBN %d, actual PBN %d.\n", + 234000, 30, 1047, ret); + return -EINVAL; + } + ret = drm_dp_calc_pbn_mode(297000, 24); + if (ret != 1063) { + DRM_ERROR("PBN calculation test failed - clock %d, bpp %d, expected PBN %d, actual PBN %d.\n", + 297000, 24, 1063, ret); return -EINVAL; + } return 0; } @@ -2683,6 +2812,13 @@ static void drm_dp_tx_work(struct work_struct *work) mutex_unlock(&mgr->qlock); } +static void drm_dp_free_mst_port(struct kref *kref) +{ + struct drm_dp_mst_port *port = container_of(kref, struct drm_dp_mst_port, kref); + kref_put(&port->parent->kref, drm_dp_free_mst_branch_device); + kfree(port); +} + static void drm_dp_destroy_connector_work(struct work_struct *work) { struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work); @@ -2703,13 +2839,22 @@ static void drm_dp_destroy_connector_work(struct work_struct *work) list_del(&port->next); mutex_unlock(&mgr->destroy_connector_lock); + kref_init(&port->kref); + INIT_LIST_HEAD(&port->next); + mgr->cbs->destroy_connector(mgr, port->connector); drm_dp_port_teardown_pdt(port, port->pdt); - if (!port->input && port->vcpi.vcpi > 0) - drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi); - kfree(port); + if (!port->input && port->vcpi.vcpi > 0) { + if (mgr->mst_state) { + drm_dp_mst_reset_vcpi_slots(mgr, port); + drm_dp_update_payload_part1(mgr); + drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi); + } + } + + kref_put(&port->kref, drm_dp_free_mst_port); send_hotplug = true; } if (send_hotplug) @@ -2736,7 +2881,6 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, mutex_init(&mgr->qlock); mutex_init(&mgr->payload_lock); mutex_init(&mgr->destroy_connector_lock); - INIT_LIST_HEAD(&mgr->tx_msg_upq); INIT_LIST_HEAD(&mgr->tx_msg_downq); INIT_LIST_HEAD(&mgr->destroy_connector_list); INIT_WORK(&mgr->work, drm_dp_mst_link_probe_work); diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 607f493ae801..8090989185b2 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -221,6 +221,64 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe, diff = (flags & DRM_CALLED_FROM_VBLIRQ) != 0; } + /* + * Within a drm_vblank_pre_modeset - drm_vblank_post_modeset + * interval? If so then vblank irqs keep running and it will likely + * happen that the hardware vblank counter is not trustworthy as it + * might reset at some point in that interval and vblank timestamps + * are not trustworthy either in that interval. Iow. this can result + * in a bogus diff >> 1 which must be avoided as it would cause + * random large forward jumps of the software vblank counter. + */ + if (diff > 1 && (vblank->inmodeset & 0x2)) { + DRM_DEBUG_VBL("clamping vblank bump to 1 on crtc %u: diffr=%u" + " due to pre-modeset.\n", pipe, diff); + diff = 1; + } + + /* + * FIMXE: Need to replace this hack with proper seqlocks. + * + * Restrict the bump of the software vblank counter to a safe maximum + * value of +1 whenever there is the possibility that concurrent readers + * of vblank timestamps could be active at the moment, as the current + * implementation of the timestamp caching and updating is not safe + * against concurrent readers for calls to store_vblank() with a bump + * of anything but +1. A bump != 1 would very likely return corrupted + * timestamps to userspace, because the same slot in the cache could + * be concurrently written by store_vblank() and read by one of those + * readers without the read-retry logic detecting the collision. + * + * Concurrent readers can exist when we are called from the + * drm_vblank_off() or drm_vblank_on() functions and other non-vblank- + * irq callers. However, all those calls to us are happening with the + * vbl_lock locked to prevent drm_vblank_get(), so the vblank refcount + * can't increase while we are executing. Therefore a zero refcount at + * this point is safe for arbitrary counter bumps if we are called + * outside vblank irq, a non-zero count is not 100% safe. Unfortunately + * we must also accept a refcount of 1, as whenever we are called from + * drm_vblank_get() -> drm_vblank_enable() the refcount will be 1 and + * we must let that one pass through in order to not lose vblank counts + * during vblank irq off - which would completely defeat the whole + * point of this routine. + * + * Whenever we are called from vblank irq, we have to assume concurrent + * readers exist or can show up any time during our execution, even if + * the refcount is currently zero, as vblank irqs are usually only + * enabled due to the presence of readers, and because when we are called + * from vblank irq we can't hold the vbl_lock to protect us from sudden + * bumps in vblank refcount. Therefore also restrict bumps to +1 when + * called from vblank irq. + */ + if ((diff > 1) && (atomic_read(&vblank->refcount) > 1 || + (flags & DRM_CALLED_FROM_VBLIRQ))) { + DRM_DEBUG_VBL("clamping vblank bump to 1 on crtc %u: diffr=%u " + "refcount %u, vblirq %u\n", pipe, diff, + atomic_read(&vblank->refcount), + (flags & DRM_CALLED_FROM_VBLIRQ) != 0); + diff = 1; + } + DRM_DEBUG_VBL("updating vblank count on crtc %u:" " current=%u, diff=%u, hw=%u hw_last=%u\n", pipe, vblank->count, diff, cur_vblank, vblank->last); @@ -1313,7 +1371,13 @@ void drm_vblank_off(struct drm_device *dev, unsigned int pipe) spin_lock_irqsave(&dev->event_lock, irqflags); spin_lock(&dev->vbl_lock); - vblank_disable_and_save(dev, pipe); + DRM_DEBUG_VBL("crtc %d, vblank enabled %d, inmodeset %d\n", + pipe, vblank->enabled, vblank->inmodeset); + + /* Avoid redundant vblank disables without previous drm_vblank_on(). */ + if (drm_core_check_feature(dev, DRIVER_ATOMIC) || !vblank->inmodeset) + vblank_disable_and_save(dev, pipe); + wake_up(&vblank->queue); /* @@ -1415,6 +1479,9 @@ void drm_vblank_on(struct drm_device *dev, unsigned int pipe) return; spin_lock_irqsave(&dev->vbl_lock, irqflags); + DRM_DEBUG_VBL("crtc %d, vblank enabled %d, inmodeset %d\n", + pipe, vblank->enabled, vblank->inmodeset); + /* Drop our private "prevent drm_vblank_get" refcount */ if (vblank->inmodeset) { atomic_dec(&vblank->refcount); @@ -1427,8 +1494,7 @@ void drm_vblank_on(struct drm_device *dev, unsigned int pipe) * re-enable interrupts if there are users left, or the * user wishes vblank interrupts to be enabled all the time. */ - if (atomic_read(&vblank->refcount) != 0 || - (!dev->vblank_disable_immediate && drm_vblank_offdelay == 0)) + if (atomic_read(&vblank->refcount) != 0 || drm_vblank_offdelay == 0) WARN_ON(drm_vblank_enable(dev, pipe)); spin_unlock_irqrestore(&dev->vbl_lock, irqflags); } @@ -1523,6 +1589,7 @@ void drm_vblank_post_modeset(struct drm_device *dev, unsigned int pipe) if (vblank->inmodeset) { spin_lock_irqsave(&dev->vbl_lock, irqflags); dev->vblank_disable_allowed = true; + drm_reset_vblank_timestamp(dev, pipe); spin_unlock_irqrestore(&dev->vbl_lock, irqflags); if (vblank->inmodeset & 0x2) diff --git a/drivers/gpu/drm/gma500/gem.c b/drivers/gpu/drm/gma500/gem.c index c707fa6fca85..e3bdc8b1c32c 100644 --- a/drivers/gpu/drm/gma500/gem.c +++ b/drivers/gpu/drm/gma500/gem.c @@ -130,7 +130,7 @@ int psb_gem_create(struct drm_file *file, struct drm_device *dev, u64 size, return ret; } /* We have the initial and handle reference but need only one now */ - drm_gem_object_unreference(&r->gem); + drm_gem_object_unreference_unlocked(&r->gem); *handlep = handle; return 0; } diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index b4741d121a74..61fcb3b22297 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -402,6 +402,8 @@ static int i915_load_modeset_init(struct drm_device *dev) if (ret) goto cleanup_gem_stolen; + intel_setup_gmbus(dev); + /* Important: The output setup functions called by modeset_init need * working irqs for e.g. gmbus and dp aux transfers. */ intel_modeset_init(dev); @@ -451,6 +453,7 @@ cleanup_gem: cleanup_irq: intel_guc_ucode_fini(dev); drm_irq_uninstall(dev); + intel_teardown_gmbus(dev); cleanup_gem_stolen: i915_gem_cleanup_stolen(dev); cleanup_vga_switcheroo: @@ -1028,7 +1031,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) /* Try to make sure MCHBAR is enabled before poking at it */ intel_setup_mchbar(dev); - intel_setup_gmbus(dev); intel_opregion_setup(dev); i915_gem_load(dev); @@ -1099,7 +1101,6 @@ out_gem_unload: if (dev->pdev->msi_enabled) pci_disable_msi(dev->pdev); - intel_teardown_gmbus(dev); intel_teardown_mchbar(dev); pm_qos_remove_request(&dev_priv->pm_qos); destroy_workqueue(dev_priv->gpu_error.hangcheck_wq); @@ -1198,7 +1199,6 @@ int i915_driver_unload(struct drm_device *dev) intel_csr_ucode_fini(dev); - intel_teardown_gmbus(dev); intel_teardown_mchbar(dev); destroy_workqueue(dev_priv->hotplug.dp_wq); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 760e0ce4aa26..a6ad938f44a6 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -531,7 +531,10 @@ void intel_detect_pch(struct drm_device *dev) dev_priv->pch_type = PCH_SPT; DRM_DEBUG_KMS("Found SunrisePoint LP PCH\n"); WARN_ON(!IS_SKYLAKE(dev)); - } else if (id == INTEL_PCH_P2X_DEVICE_ID_TYPE) { + } else if ((id == INTEL_PCH_P2X_DEVICE_ID_TYPE) || + ((id == INTEL_PCH_QEMU_DEVICE_ID_TYPE) && + pch->subsystem_vendor == 0x1af4 && + pch->subsystem_device == 0x1100)) { dev_priv->pch_type = intel_virt_detect_pch(dev); } else continue; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f4af19a0d569..d3ce4da6a6ad 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2614,6 +2614,7 @@ struct drm_i915_cmd_table { #define INTEL_PCH_SPT_DEVICE_ID_TYPE 0xA100 #define INTEL_PCH_SPT_LP_DEVICE_ID_TYPE 0x9D00 #define INTEL_PCH_P2X_DEVICE_ID_TYPE 0x7100 +#define INTEL_PCH_QEMU_DEVICE_ID_TYPE 0x2900 /* qemu q35 has 2918 */ #define INTEL_PCH_TYPE(dev) (__I915__(dev)->pch_type) #define HAS_PCH_SPT(dev) (INTEL_PCH_TYPE(dev) == PCH_SPT) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 02ceb7a4b481..0433d25f9d23 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -340,6 +340,10 @@ void i915_gem_context_reset(struct drm_device *dev) i915_gem_context_unreference(lctx); ring->last_context = NULL; } + + /* Force the GPU state to be reinitialised on enabling */ + if (ring->default_context) + ring->default_context->legacy_hw_ctx.initialized = false; } } @@ -708,7 +712,7 @@ static int do_switch(struct drm_i915_gem_request *req) if (ret) goto unpin_out; - if (!to->legacy_hw_ctx.initialized) { + if (!to->legacy_hw_ctx.initialized || i915_gem_context_is_default(to)) { hw_flags |= MI_RESTORE_INHIBIT; /* NB: If we inhibit the restore, the context is not allowed to * die because future work may end up depending on valid address diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 0d228f909dcb..0f42a2782afc 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2354,9 +2354,13 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg) spt_irq_handler(dev, pch_iir); else cpt_irq_handler(dev, pch_iir); - } else - DRM_ERROR("The master control interrupt lied (SDE)!\n"); - + } else { + /* + * Like on previous PCH there seems to be something + * fishy going on with forwarding PCH interrupts. + */ + DRM_DEBUG_DRIVER("The master control interrupt lied (SDE)!\n"); + } } I915_WRITE_FW(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL); diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index a6752a61d99f..7e6158b889da 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1582,7 +1582,8 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc, DPLL_CFGCR2_KDIV(wrpll_params.kdiv) | DPLL_CFGCR2_PDIV(wrpll_params.pdiv) | wrpll_params.central_freq; - } else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) { + } else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT || + intel_encoder->type == INTEL_OUTPUT_DP_MST) { switch (crtc_state->port_clock / 2) { case 81000: ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 32cf97346978..f859a5b87ed4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11930,11 +11930,21 @@ connected_sink_compute_bpp(struct intel_connector *connector, pipe_config->pipe_bpp = connector->base.display_info.bpc*3; } - /* Clamp bpp to 8 on screens without EDID 1.4 */ - if (connector->base.display_info.bpc == 0 && bpp > 24) { - DRM_DEBUG_KMS("clamping display bpp (was %d) to default limit of 24\n", - bpp); - pipe_config->pipe_bpp = 24; + /* Clamp bpp to default limit on screens without EDID 1.4 */ + if (connector->base.display_info.bpc == 0) { + int type = connector->base.connector_type; + int clamp_bpp = 24; + + /* Fall back to 18 bpp when DP sink capability is unknown. */ + if (type == DRM_MODE_CONNECTOR_DisplayPort || + type == DRM_MODE_CONNECTOR_eDP) + clamp_bpp = 18; + + if (bpp > clamp_bpp) { + DRM_DEBUG_KMS("clamping display bpp (was %d) to default limit of %d\n", + bpp, clamp_bpp); + pipe_config->pipe_bpp = clamp_bpp; + } } } @@ -13537,11 +13547,12 @@ intel_check_primary_plane(struct drm_plane *plane, int max_scale = DRM_PLANE_HELPER_NO_SCALING; bool can_position = false; - /* use scaler when colorkey is not required */ - if (INTEL_INFO(plane->dev)->gen >= 9 && - state->ckey.flags == I915_SET_COLORKEY_NONE) { - min_scale = 1; - max_scale = skl_max_scale(to_intel_crtc(crtc), crtc_state); + if (INTEL_INFO(plane->dev)->gen >= 9) { + /* use scaler when colorkey is not required */ + if (state->ckey.flags == I915_SET_COLORKEY_NONE) { + min_scale = 1; + max_scale = skl_max_scale(to_intel_crtc(crtc), crtc_state); + } can_position = true; } @@ -15565,6 +15576,8 @@ void intel_modeset_cleanup(struct drm_device *dev) mutex_lock(&dev->struct_mutex); intel_cleanup_gt_powersave(dev); mutex_unlock(&dev->struct_mutex); + + intel_teardown_gmbus(dev); } /* diff --git a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c index a5e99ac305da..a8912aecc31f 100644 --- a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c +++ b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c @@ -207,7 +207,12 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) gpio = *data++; /* pull up/down */ - action = *data++; + action = *data++ & 1; + + if (gpio >= ARRAY_SIZE(gtable)) { + DRM_DEBUG_KMS("unknown gpio %u\n", gpio); + goto out; + } function = gtable[gpio].function_reg; pad = gtable[gpio].pad_reg; @@ -226,6 +231,7 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) vlv_gpio_nc_write(dev_priv, pad, val); mutex_unlock(&dev_priv->sb_lock); +out: return data; } diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c index b17785719598..d7a6437d9da2 100644 --- a/drivers/gpu/drm/i915/intel_hotplug.c +++ b/drivers/gpu/drm/i915/intel_hotplug.c @@ -468,9 +468,14 @@ void intel_hpd_init(struct drm_i915_private *dev_priv) list_for_each_entry(connector, &mode_config->connector_list, head) { struct intel_connector *intel_connector = to_intel_connector(connector); connector->polled = intel_connector->polled; - if (connector->encoder && !connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE) - connector->polled = DRM_CONNECTOR_POLL_HPD; + + /* MST has a dynamic intel_connector->encoder and it's reprobing + * is all handled by the MST helpers. */ if (intel_connector->mst_port) + continue; + + if (!connector->polled && I915_HAS_HOTPLUG(dev) && + intel_connector->encoder->hpd_pin > HPD_NONE) connector->polled = DRM_CONNECTOR_POLL_HPD; } diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 8324654037b6..f3bee54c414f 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -675,7 +675,7 @@ int intel_setup_gmbus(struct drm_device *dev) return 0; err: - while (--pin) { + while (pin--) { if (!intel_gmbus_is_valid_pin(dev_priv, pin)) continue; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 88e12bdf79e2..d69547a65dbb 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1706,6 +1706,7 @@ static int gen8_emit_flush_render(struct drm_i915_gem_request *request, if (flush_domains) { flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH; flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH; + flags |= PIPE_CONTROL_DC_FLUSH_ENABLE; flags |= PIPE_CONTROL_FLUSH_ENABLE; } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 9461a238f5d5..f6b2a814e629 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -347,6 +347,7 @@ gen7_render_ring_flush(struct drm_i915_gem_request *req, if (flush_domains) { flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH; flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH; + flags |= PIPE_CONTROL_DC_FLUSH_ENABLE; flags |= PIPE_CONTROL_FLUSH_ENABLE; } if (invalidate_domains) { @@ -419,6 +420,7 @@ gen8_render_ring_flush(struct drm_i915_gem_request *req, if (flush_domains) { flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH; flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH; + flags |= PIPE_CONTROL_DC_FLUSH_ENABLE; flags |= PIPE_CONTROL_FLUSH_ENABLE; } if (invalidate_domains) { diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 2e7cbe933533..2a5ed7460354 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -969,10 +969,13 @@ nouveau_connector_hotplug(struct nvif_notify *notify) NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", name); + mutex_lock(&drm->dev->mode_config.mutex); if (plugged) drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); else drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); + mutex_unlock(&drm->dev->mode_config.mutex); + drm_helper_hpd_irq_event(connector->dev); } diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 64c8d932d5f1..58a3f7cf2fb3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -634,10 +634,6 @@ nouveau_display_resume(struct drm_device *dev, bool runtime) nv_crtc->lut.depth = 0; } - /* Make sure that drm and hw vblank irqs get resumed if needed. */ - for (head = 0; head < dev->mode_config.num_crtc; head++) - drm_vblank_on(dev, head); - /* This should ensure we don't hit a locking problem when someone * wakes us up via a connector. We should never go into suspend * while the display is on anyways. @@ -647,6 +643,10 @@ nouveau_display_resume(struct drm_device *dev, bool runtime) drm_helper_resume_force_mode(dev); + /* Make sure that drm and hw vblank irqs get resumed if needed. */ + for (head = 0; head < dev->mode_config.num_crtc; head++) + drm_vblank_on(dev, head); + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); diff --git a/drivers/gpu/drm/nouveau/nouveau_platform.c b/drivers/gpu/drm/nouveau/nouveau_platform.c index 60e32c4e4e49..35ecc0d0458f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_platform.c +++ b/drivers/gpu/drm/nouveau/nouveau_platform.c @@ -24,7 +24,7 @@ static int nouveau_platform_probe(struct platform_device *pdev) { const struct nvkm_device_tegra_func *func; - struct nvkm_device *device; + struct nvkm_device *device = NULL; struct drm_device *drm; int ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c index 7f8a42721eb2..e7e581d6a8ff 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c @@ -252,32 +252,40 @@ nvkm_device_tegra_new(const struct nvkm_device_tegra_func *func, if (!(tdev = kzalloc(sizeof(*tdev), GFP_KERNEL))) return -ENOMEM; - *pdevice = &tdev->device; + tdev->func = func; tdev->pdev = pdev; tdev->irq = -1; tdev->vdd = devm_regulator_get(&pdev->dev, "vdd"); - if (IS_ERR(tdev->vdd)) - return PTR_ERR(tdev->vdd); + if (IS_ERR(tdev->vdd)) { + ret = PTR_ERR(tdev->vdd); + goto free; + } tdev->rst = devm_reset_control_get(&pdev->dev, "gpu"); - if (IS_ERR(tdev->rst)) - return PTR_ERR(tdev->rst); + if (IS_ERR(tdev->rst)) { + ret = PTR_ERR(tdev->rst); + goto free; + } tdev->clk = devm_clk_get(&pdev->dev, "gpu"); - if (IS_ERR(tdev->clk)) - return PTR_ERR(tdev->clk); + if (IS_ERR(tdev->clk)) { + ret = PTR_ERR(tdev->clk); + goto free; + } tdev->clk_pwr = devm_clk_get(&pdev->dev, "pwr"); - if (IS_ERR(tdev->clk_pwr)) - return PTR_ERR(tdev->clk_pwr); + if (IS_ERR(tdev->clk_pwr)) { + ret = PTR_ERR(tdev->clk_pwr); + goto free; + } nvkm_device_tegra_probe_iommu(tdev); ret = nvkm_device_tegra_power_up(tdev); if (ret) - return ret; + goto remove; tdev->gpu_speedo = tegra_sku_info.gpu_speedo_value; ret = nvkm_device_ctor(&nvkm_device_tegra_func, NULL, &pdev->dev, @@ -285,9 +293,19 @@ nvkm_device_tegra_new(const struct nvkm_device_tegra_func *func, cfg, dbg, detect, mmio, subdev_mask, &tdev->device); if (ret) - return ret; + goto powerdown; + + *pdevice = &tdev->device; return 0; + +powerdown: + nvkm_device_tegra_power_down(tdev); +remove: + nvkm_device_tegra_remove_iommu(tdev); +free: + kfree(tdev); + return ret; } #else int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c index 74e2f7c6c07e..9688970eca47 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c @@ -328,6 +328,7 @@ nvkm_dp_train(struct work_struct *w) .outp = outp, }, *dp = &_dp; u32 datarate = 0; + u8 pwr; int ret; if (!outp->base.info.location && disp->func->sor.magic) @@ -355,6 +356,15 @@ nvkm_dp_train(struct work_struct *w) /* disable link interrupt handling during link training */ nvkm_notify_put(&outp->irq); + /* ensure sink is not in a low-power state */ + if (!nvkm_rdaux(outp->aux, DPCD_SC00, &pwr, 1)) { + if ((pwr & DPCD_SC00_SET_POWER) != DPCD_SC00_SET_POWER_D0) { + pwr &= ~DPCD_SC00_SET_POWER; + pwr |= DPCD_SC00_SET_POWER_D0; + nvkm_wraux(outp->aux, DPCD_SC00, &pwr, 1); + } + } + /* enable down-spreading and execute pre-train script from vbios */ dp_link_train_init(dp, outp->dpcd[3] & 0x01); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h index 9596290329c7..6e10c5e0ef11 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h @@ -71,5 +71,11 @@ #define DPCD_LS0C_LANE1_POST_CURSOR2 0x0c #define DPCD_LS0C_LANE0_POST_CURSOR2 0x03 +/* DPCD Sink Control */ +#define DPCD_SC00 0x00600 +#define DPCD_SC00_SET_POWER 0x03 +#define DPCD_SC00_SET_POWER_D0 0x01 +#define DPCD_SC00_SET_POWER_D3 0x03 + void nvkm_dp_train(struct work_struct *); #endif diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c index 2ae8577497ca..7c2e78201ead 100644 --- a/drivers/gpu/drm/qxl/qxl_ioctl.c +++ b/drivers/gpu/drm/qxl/qxl_ioctl.c @@ -168,7 +168,8 @@ static int qxl_process_single_command(struct qxl_device *qdev, cmd->command_size)) return -EFAULT; - reloc_info = kmalloc(sizeof(struct qxl_reloc_info) * cmd->relocs_num, GFP_KERNEL); + reloc_info = kmalloc_array(cmd->relocs_num, + sizeof(struct qxl_reloc_info), GFP_KERNEL); if (!reloc_info) return -ENOMEM; diff --git a/drivers/gpu/drm/radeon/dce6_afmt.c b/drivers/gpu/drm/radeon/dce6_afmt.c index 752072771388..367a916f364e 100644 --- a/drivers/gpu/drm/radeon/dce6_afmt.c +++ b/drivers/gpu/drm/radeon/dce6_afmt.c @@ -301,6 +301,14 @@ void dce6_dp_audio_set_dto(struct radeon_device *rdev, * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator */ if (ASIC_IS_DCE8(rdev)) { + unsigned int div = (RREG32(DENTIST_DISPCLK_CNTL) & + DENTIST_DPREFCLK_WDIVIDER_MASK) >> + DENTIST_DPREFCLK_WDIVIDER_SHIFT; + div = radeon_audio_decode_dfs_div(div); + + if (div) + clock = clock * 100 / div; + WREG32(DCE8_DCCG_AUDIO_DTO1_PHASE, 24000); WREG32(DCE8_DCCG_AUDIO_DTO1_MODULE, clock); } else { diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c index 9953356fe263..3cf04a2f44bb 100644 --- a/drivers/gpu/drm/radeon/evergreen_hdmi.c +++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c @@ -289,6 +289,16 @@ void dce4_dp_audio_set_dto(struct radeon_device *rdev, * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator */ + if (ASIC_IS_DCE41(rdev)) { + unsigned int div = (RREG32(DCE41_DENTIST_DISPCLK_CNTL) & + DENTIST_DPREFCLK_WDIVIDER_MASK) >> + DENTIST_DPREFCLK_WDIVIDER_SHIFT; + div = radeon_audio_decode_dfs_div(div); + + if (div) + clock = 100 * clock / div; + } + WREG32(DCCG_AUDIO_DTO1_PHASE, 24000); WREG32(DCCG_AUDIO_DTO1_MODULE, clock); } diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 4aa5f755572b..13b6029d65cc 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -511,6 +511,11 @@ #define DCCG_AUDIO_DTO1_CNTL 0x05cc # define DCCG_AUDIO_DTO1_USE_512FBR_DTO (1 << 3) +#define DCE41_DENTIST_DISPCLK_CNTL 0x049c +# define DENTIST_DPREFCLK_WDIVIDER(x) (((x) & 0x7f) << 24) +# define DENTIST_DPREFCLK_WDIVIDER_MASK (0x7f << 24) +# define DENTIST_DPREFCLK_WDIVIDER_SHIFT 24 + /* DCE 4.0 AFMT */ #define HDMI_CONTROL 0x7030 # define HDMI_KEEPOUT_MODE (1 << 0) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 87db64983ea8..5580568088bb 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -268,6 +268,7 @@ struct radeon_clock { uint32_t current_dispclk; uint32_t dp_extclk; uint32_t max_pixel_clock; + uint32_t vco_freq; }; /* diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 8f285244c839..de9a2ffcf5f7 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -437,7 +437,9 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, } /* Fujitsu D3003-S2 board lists DVI-I as DVI-D and VGA */ - if (((dev->pdev->device == 0x9802) || (dev->pdev->device == 0x9806)) && + if (((dev->pdev->device == 0x9802) || + (dev->pdev->device == 0x9805) || + (dev->pdev->device == 0x9806)) && (dev->pdev->subsystem_vendor == 0x1734) && (dev->pdev->subsystem_device == 0x11bd)) { if (*connector_type == DRM_MODE_CONNECTOR_VGA) { @@ -448,14 +450,6 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, } } - /* Fujitsu D3003-S2 board lists DVI-I as DVI-I and VGA */ - if ((dev->pdev->device == 0x9805) && - (dev->pdev->subsystem_vendor == 0x1734) && - (dev->pdev->subsystem_device == 0x11bd)) { - if (*connector_type == DRM_MODE_CONNECTOR_VGA) - return false; - } - return true; } @@ -1112,6 +1106,31 @@ union firmware_info { ATOM_FIRMWARE_INFO_V2_2 info_22; }; +union igp_info { + struct _ATOM_INTEGRATED_SYSTEM_INFO info; + struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2; + struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6; + struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7; + struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8; +}; + +static void radeon_atombios_get_dentist_vco_freq(struct radeon_device *rdev) +{ + struct radeon_mode_info *mode_info = &rdev->mode_info; + int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); + union igp_info *igp_info; + u8 frev, crev; + u16 data_offset; + + if (atom_parse_data_header(mode_info->atom_context, index, NULL, + &frev, &crev, &data_offset)) { + igp_info = (union igp_info *)(mode_info->atom_context->bios + + data_offset); + rdev->clock.vco_freq = + le32_to_cpu(igp_info->info_6.ulDentistVCOFreq); + } +} + bool radeon_atom_get_clock_info(struct drm_device *dev) { struct radeon_device *rdev = dev->dev_private; @@ -1263,20 +1282,25 @@ bool radeon_atom_get_clock_info(struct drm_device *dev) rdev->mode_info.firmware_flags = le16_to_cpu(firmware_info->info.usFirmwareCapability.susAccess); + if (ASIC_IS_DCE8(rdev)) + rdev->clock.vco_freq = + le32_to_cpu(firmware_info->info_22.ulGPUPLL_OutputFreq); + else if (ASIC_IS_DCE5(rdev)) + rdev->clock.vco_freq = rdev->clock.current_dispclk; + else if (ASIC_IS_DCE41(rdev)) + radeon_atombios_get_dentist_vco_freq(rdev); + else + rdev->clock.vco_freq = rdev->clock.current_dispclk; + + if (rdev->clock.vco_freq == 0) + rdev->clock.vco_freq = 360000; /* 3.6 GHz */ + return true; } return false; } -union igp_info { - struct _ATOM_INTEGRATED_SYSTEM_INFO info; - struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2; - struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6; - struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7; - struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_8 info_8; -}; - bool radeon_atombios_sideport_present(struct radeon_device *rdev) { struct radeon_mode_info *mode_info = &rdev->mode_info; diff --git a/drivers/gpu/drm/radeon/radeon_audio.c b/drivers/gpu/drm/radeon/radeon_audio.c index 2c02e99b5f95..b214663b370d 100644 --- a/drivers/gpu/drm/radeon/radeon_audio.c +++ b/drivers/gpu/drm/radeon/radeon_audio.c @@ -739,9 +739,6 @@ static void radeon_audio_dp_mode_set(struct drm_encoder *encoder, struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - struct radeon_connector_atom_dig *dig_connector = - radeon_connector->con_priv; if (!dig || !dig->afmt) return; @@ -753,10 +750,7 @@ static void radeon_audio_dp_mode_set(struct drm_encoder *encoder, radeon_audio_write_speaker_allocation(encoder); radeon_audio_write_sad_regs(encoder); radeon_audio_write_latency_fields(encoder, mode); - if (rdev->clock.dp_extclk || ASIC_IS_DCE5(rdev)) - radeon_audio_set_dto(encoder, rdev->clock.default_dispclk * 10); - else - radeon_audio_set_dto(encoder, dig_connector->dp_clock); + radeon_audio_set_dto(encoder, rdev->clock.vco_freq * 10); radeon_audio_set_audio_packet(encoder); radeon_audio_select_pin(encoder); @@ -781,3 +775,15 @@ void radeon_audio_dpms(struct drm_encoder *encoder, int mode) if (radeon_encoder->audio && radeon_encoder->audio->dpms) radeon_encoder->audio->dpms(encoder, mode == DRM_MODE_DPMS_ON); } + +unsigned int radeon_audio_decode_dfs_div(unsigned int div) +{ + if (div >= 8 && div < 64) + return (div - 8) * 25 + 200; + else if (div >= 64 && div < 96) + return (div - 64) * 50 + 1600; + else if (div >= 96 && div < 128) + return (div - 96) * 100 + 3200; + else + return 0; +} diff --git a/drivers/gpu/drm/radeon/radeon_audio.h b/drivers/gpu/drm/radeon/radeon_audio.h index 059cc3012062..5c70cceaa4a6 100644 --- a/drivers/gpu/drm/radeon/radeon_audio.h +++ b/drivers/gpu/drm/radeon/radeon_audio.h @@ -79,5 +79,6 @@ void radeon_audio_fini(struct radeon_device *rdev); void radeon_audio_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode); void radeon_audio_dpms(struct drm_encoder *encoder, int mode); +unsigned int radeon_audio_decode_dfs_div(unsigned int div); #endif diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 1eca0acac016..3645b223aa37 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -403,7 +403,8 @@ static void radeon_flip_work_func(struct work_struct *__work) struct drm_crtc *crtc = &radeon_crtc->base; unsigned long flags; int r; - int vpos, hpos, stat, min_udelay; + int vpos, hpos, stat, min_udelay = 0; + unsigned repcnt = 4; struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id]; down_read(&rdev->exclusive_lock); @@ -454,7 +455,7 @@ static void radeon_flip_work_func(struct work_struct *__work) * In practice this won't execute very often unless on very fast * machines because the time window for this to happen is very small. */ - for (;;) { + while (radeon_crtc->enabled && --repcnt) { /* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank * start in hpos, and to the "fudged earlier" vblank start in * vpos. @@ -470,12 +471,24 @@ static void radeon_flip_work_func(struct work_struct *__work) break; /* Sleep at least until estimated real start of hw vblank */ - spin_unlock_irqrestore(&crtc->dev->event_lock, flags); min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5); + if (min_udelay > vblank->framedur_ns / 2000) { + /* Don't wait ridiculously long - something is wrong */ + repcnt = 0; + break; + } + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); usleep_range(min_udelay, 2 * min_udelay); spin_lock_irqsave(&crtc->dev->event_lock, flags); }; + if (!repcnt) + DRM_DEBUG_DRIVER("Delay problem on crtc %d: min_udelay %d, " + "framedur %d, linedur %d, stat %d, vpos %d, " + "hpos %d\n", work->crtc_id, min_udelay, + vblank->framedur_ns / 1000, + vblank->linedur_ns / 1000, stat, vpos, hpos); + /* do the flip (mmio) */ radeon_page_flip(rdev, radeon_crtc->crtc_id, work->base); diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 84d45633d28c..fb6ad143873f 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -33,6 +33,7 @@ #include <linux/slab.h> #include <drm/drmP.h> #include <drm/radeon_drm.h> +#include <drm/drm_cache.h> #include "radeon.h" #include "radeon_trace.h" @@ -245,6 +246,12 @@ int radeon_bo_create(struct radeon_device *rdev, DRM_INFO_ONCE("Please enable CONFIG_MTRR and CONFIG_X86_PAT for " "better performance thanks to write-combining\n"); bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC); +#else + /* For architectures that don't support WC memory, + * mask out the WC flag from the BO + */ + if (!drm_arch_can_wc_memory()) + bo->flags &= ~RADEON_GEM_GTT_WC; #endif radeon_ttm_placement_from_domain(bo, domain); diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 59abebd6b5dc..60ab31517153 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -1078,10 +1078,6 @@ force: /* update displays */ radeon_dpm_display_configuration_changed(rdev); - rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs; - rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count; - rdev->pm.dpm.single_display = single_display; - /* wait for the rings to drain */ for (i = 0; i < RADEON_NUM_RINGS; i++) { struct radeon_ring *ring = &rdev->ring[i]; @@ -1097,6 +1093,10 @@ force: radeon_dpm_post_set_power_state(rdev); + rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs; + rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count; + rdev->pm.dpm.single_display = single_display; + if (rdev->asic->dpm.force_performance_level) { if (rdev->pm.dpm.thermal_active) { enum radeon_dpm_forced_level level = rdev->pm.dpm.forced_level; diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c index c507896aca45..197b157b73d0 100644 --- a/drivers/gpu/drm/radeon/radeon_sa.c +++ b/drivers/gpu/drm/radeon/radeon_sa.c @@ -349,8 +349,13 @@ int radeon_sa_bo_new(struct radeon_device *rdev, /* see if we can skip over some allocations */ } while (radeon_sa_bo_next_hole(sa_manager, fences, tries)); + for (i = 0; i < RADEON_NUM_RINGS; ++i) + radeon_fence_ref(fences[i]); + spin_unlock(&sa_manager->wq.lock); r = radeon_fence_wait_any(rdev, fences, false); + for (i = 0; i < RADEON_NUM_RINGS; ++i) + radeon_fence_unref(&fences[i]); spin_lock(&sa_manager->wq.lock); /* if we have nothing to wait for block */ if (r == -ENOENT) { diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index e34307459e50..e06ac546a90f 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -758,7 +758,7 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm) 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); if (pci_dma_mapping_error(rdev->pdev, gtt->ttm.dma_address[i])) { - while (--i) { + while (i--) { pci_unmap_page(rdev->pdev, gtt->ttm.dma_address[i], PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); gtt->ttm.dma_address[i] = 0; diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c index 48d97c040f49..3979632b9225 100644 --- a/drivers/gpu/drm/radeon/radeon_vm.c +++ b/drivers/gpu/drm/radeon/radeon_vm.c @@ -455,15 +455,15 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, if (soffset) { /* make sure object fit at this offset */ - eoffset = soffset + size; + eoffset = soffset + size - 1; if (soffset >= eoffset) { r = -EINVAL; goto error_unreserve; } last_pfn = eoffset / RADEON_GPU_PAGE_SIZE; - if (last_pfn > rdev->vm_manager.max_pfn) { - dev_err(rdev->dev, "va above limit (0x%08X > 0x%08X)\n", + if (last_pfn >= rdev->vm_manager.max_pfn) { + dev_err(rdev->dev, "va above limit (0x%08X >= 0x%08X)\n", last_pfn, rdev->vm_manager.max_pfn); r = -EINVAL; goto error_unreserve; @@ -478,7 +478,7 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, eoffset /= RADEON_GPU_PAGE_SIZE; if (soffset || eoffset) { struct interval_tree_node *it; - it = interval_tree_iter_first(&vm->va, soffset, eoffset - 1); + it = interval_tree_iter_first(&vm->va, soffset, eoffset); if (it && it != &bo_va->it) { struct radeon_bo_va *tmp; tmp = container_of(it, struct radeon_bo_va, it); @@ -518,7 +518,7 @@ int radeon_vm_bo_set_addr(struct radeon_device *rdev, if (soffset || eoffset) { spin_lock(&vm->status_lock); bo_va->it.start = soffset; - bo_va->it.last = eoffset - 1; + bo_va->it.last = eoffset; list_add(&bo_va->vm_status, &vm->cleared); spin_unlock(&vm->status_lock); interval_tree_insert(&bo_va->it, &vm->va); @@ -888,7 +888,7 @@ static void radeon_vm_fence_pts(struct radeon_vm *vm, unsigned i; start >>= radeon_vm_block_size; - end >>= radeon_vm_block_size; + end = (end - 1) >> radeon_vm_block_size; for (i = start; i <= end; ++i) radeon_bo_fence(vm->page_tables[i].bo, fence, true); diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h index 4c4a7218a3bd..d1a7b58dd291 100644 --- a/drivers/gpu/drm/radeon/sid.h +++ b/drivers/gpu/drm/radeon/sid.h @@ -915,6 +915,11 @@ #define DCCG_AUDIO_DTO1_PHASE 0x05c0 #define DCCG_AUDIO_DTO1_MODULE 0x05c4 +#define DENTIST_DISPCLK_CNTL 0x0490 +# define DENTIST_DPREFCLK_WDIVIDER(x) (((x) & 0x7f) << 24) +# define DENTIST_DPREFCLK_WDIVIDER_MASK (0x7f << 24) +# define DENTIST_DPREFCLK_WDIVIDER_SHIFT 24 + #define AFMT_AUDIO_SRC_CONTROL 0x713c #define AFMT_AUDIO_SRC_SELECT(x) (((x) & 7) << 0) /* AFMT_AUDIO_SRC_SELECT diff --git a/drivers/gpu/drm/radeon/vce_v1_0.c b/drivers/gpu/drm/radeon/vce_v1_0.c index 07a0d378e122..a01efe39a820 100644 --- a/drivers/gpu/drm/radeon/vce_v1_0.c +++ b/drivers/gpu/drm/radeon/vce_v1_0.c @@ -178,12 +178,12 @@ int vce_v1_0_load_fw(struct radeon_device *rdev, uint32_t *data) return -EINVAL; } - for (i = 0; i < sign->num; ++i) { - if (sign->val[i].chip_id == chip_id) + for (i = 0; i < le32_to_cpu(sign->num); ++i) { + if (le32_to_cpu(sign->val[i].chip_id) == chip_id) break; } - if (i == sign->num) + if (i == le32_to_cpu(sign->num)) return -EINVAL; data += (256 - 64) / 4; @@ -191,18 +191,18 @@ int vce_v1_0_load_fw(struct radeon_device *rdev, uint32_t *data) data[1] = sign->val[i].nonce[1]; data[2] = sign->val[i].nonce[2]; data[3] = sign->val[i].nonce[3]; - data[4] = sign->len + 64; + data[4] = cpu_to_le32(le32_to_cpu(sign->len) + 64); memset(&data[5], 0, 44); memcpy(&data[16], &sign[1], rdev->vce_fw->size - sizeof(*sign)); - data += data[4] / 4; + data += le32_to_cpu(data[4]) / 4; data[0] = sign->val[i].sigval[0]; data[1] = sign->val[i].sigval[1]; data[2] = sign->val[i].sigval[2]; data[3] = sign->val[i].sigval[3]; - rdev->vce.keyselect = sign->val[i].keyselect; + rdev->vce.keyselect = le32_to_cpu(sign->val[i].keyselect); return 0; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c index 6377e8151000..67cebb23c940 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf.c @@ -247,7 +247,7 @@ static void __vmw_cmdbuf_header_free(struct vmw_cmdbuf_header *header) { struct vmw_cmdbuf_man *man = header->man; - BUG_ON(!spin_is_locked(&man->lock)); + lockdep_assert_held_once(&man->lock); if (header->inline_space) { vmw_cmdbuf_header_inline_free(header); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index c49812b80dd0..24fb348a44e1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -25,6 +25,7 @@ * **************************************************************************/ #include <linux/module.h> +#include <linux/console.h> #include <drm/drmP.h> #include "vmwgfx_drv.h" @@ -1538,6 +1539,12 @@ static int vmw_probe(struct pci_dev *pdev, const struct pci_device_id *ent) static int __init vmwgfx_init(void) { int ret; + +#ifdef CONFIG_VGA_CONSOLE + if (vgacon_text_force()) + return -EINVAL; +#endif + ret = drm_pci_init(&driver, &vmw_pci_driver); if (ret) DRM_ERROR("Failed initializing DRM.\n"); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 9b4bb9e74d73..7c2e118a77b0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -763,21 +763,25 @@ static int vmw_create_dmabuf_proxy(struct drm_device *dev, uint32_t format; struct drm_vmw_size content_base_size; struct vmw_resource *res; + unsigned int bytes_pp; int ret; switch (mode_cmd->depth) { case 32: case 24: format = SVGA3D_X8R8G8B8; + bytes_pp = 4; break; case 16: case 15: format = SVGA3D_R5G6B5; + bytes_pp = 2; break; case 8: format = SVGA3D_P8; + bytes_pp = 1; break; default: @@ -785,7 +789,7 @@ static int vmw_create_dmabuf_proxy(struct drm_device *dev, return -EINVAL; } - content_base_size.width = mode_cmd->width; + content_base_size.width = mode_cmd->pitch / bytes_pp; content_base_size.height = mode_cmd->height; content_base_size.depth = 1; diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index f2e13eb8339f..a0e28f3a278d 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -1050,6 +1050,17 @@ static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base) for (i = 0; i < ARRAY_SIZE(client_reg); i++) { const struct ipu_platform_reg *reg = &client_reg[i]; struct platform_device *pdev; + struct device_node *of_node; + + /* Associate subdevice with the corresponding port node */ + of_node = of_graph_get_port_by_id(dev->of_node, i); + if (!of_node) { + dev_info(dev, + "no port@%d node in %s, not using %s%d\n", + i, dev->of_node->full_name, + (i / 2) ? "DI" : "CSI", i % 2); + continue; + } pdev = platform_device_alloc(reg->name, id++); if (!pdev) { @@ -1057,17 +1068,9 @@ static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base) goto err_register; } + pdev->dev.of_node = of_node; pdev->dev.parent = dev; - /* Associate subdevice with the corresponding port node */ - pdev->dev.of_node = of_graph_get_port_by_id(dev->of_node, i); - if (!pdev->dev.of_node) { - dev_err(dev, "missing port@%d node in %s\n", i, - dev->of_node->full_name); - ret = -ENODEV; - goto err_register; - } - ret = platform_device_add_data(pdev, ®->pdata, sizeof(reg->pdata)); if (!ret) diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile index db5a9ca28408..90aee3cad5ad 100644 --- a/drivers/gpu/msm/Makefile +++ b/drivers/gpu/msm/Makefile @@ -33,6 +33,8 @@ msm_adreno-y += \ adreno_a3xx_snapshot.o \ adreno_a4xx_snapshot.o \ adreno_a5xx_snapshot.o \ + adreno_a4xx_preempt.o \ + adreno_a5xx_preempt.o \ adreno_sysfs.o \ adreno.o \ adreno_cp_parser.o \ diff --git a/drivers/gpu/msm/a5xx_reg.h b/drivers/gpu/msm/a5xx_reg.h index 913cedb885ad..207588844931 100644 --- a/drivers/gpu/msm/a5xx_reg.h +++ b/drivers/gpu/msm/a5xx_reg.h @@ -60,6 +60,8 @@ #define A5XX_CP_RB_BASE 0x800 #define A5XX_CP_RB_BASE_HI 0x801 #define A5XX_CP_RB_CNTL 0x802 +#define A5XX_CP_RB_RPTR_ADDR_LO 0x804 +#define A5XX_CP_RB_RPTR_ADDR_HI 0x805 #define A5XX_CP_RB_RPTR 0x806 #define A5XX_CP_RB_WPTR 0x807 #define A5XX_CP_PFP_STAT_ADDR 0x808 diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index b9a379bdc5a5..918231b73215 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -171,6 +171,30 @@ void adreno_writereg64(struct adreno_device *adreno_dev, } /** + * adreno_get_rptr() - Get the current ringbuffer read pointer + * @rb: Pointer the ringbuffer to query + * + * Get the latest rptr + */ +unsigned int adreno_get_rptr(struct adreno_ringbuffer *rb) +{ + struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb); + unsigned int rptr = 0; + + if (adreno_is_a3xx(adreno_dev)) + adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_RPTR, + &rptr); + else { + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + + kgsl_sharedmem_readl(&device->scratch, &rptr, + SCRATCH_RPTR_OFFSET(rb->id)); + } + + return rptr; +} + +/** * adreno_of_read_property() - Adreno read property * @node: Device node * @@ -1264,6 +1288,9 @@ static uint64_t _read_throttling_counters(struct adreno_device *adreno_dev) if (!ADRENO_FEATURE(adreno_dev, ADRENO_GPMU)) return 0; + if (!test_bit(ADRENO_THROTTLING_CTRL, &adreno_dev->pwrctrl_flag)) + return 0; + for (i = 0; i < ADRENO_GPMU_THROTTLE_COUNTERS; i++) { if (!adreno_dev->gpmu_throttle_counters[i]) return 0; @@ -1272,9 +1299,8 @@ static uint64_t _read_throttling_counters(struct adreno_device *adreno_dev) adreno_dev->gpmu_throttle_counters[i], &busy->throttle_cycles[i]); } - return th[CRC_50PCT] + th[CRC_LESS50PCT] / 3 + - (th[CRC_MORE50PCT] - th[IDLE_10PCT]) * 3; - + i = th[CRC_MORE50PCT] - th[IDLE_10PCT]; + return th[CRC_50PCT] + th[CRC_LESS50PCT] / 3 + (i < 0 ? 0 : i) * 3; } static void _update_threshold_count(struct adreno_device *adreno_dev, @@ -1288,6 +1314,28 @@ static void _update_threshold_count(struct adreno_device *adreno_dev, adreno_dev->lm_threshold_cross = adj; } +static void _set_secvid(struct kgsl_device *device) +{ + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + + /* Program GPU contect protection init values */ + if (device->mmu.secured) { + if (adreno_is_a4xx(adreno_dev)) + adreno_writereg(adreno_dev, + ADRENO_REG_RBBM_SECVID_TRUST_CONFIG, 0x2); + adreno_writereg(adreno_dev, + ADRENO_REG_RBBM_SECVID_TSB_CONTROL, 0x0); + + adreno_writereg64(adreno_dev, + ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE, + ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE_HI, + KGSL_IOMMU_SECURE_BASE); + adreno_writereg(adreno_dev, + ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_SIZE, + KGSL_IOMMU_SECURE_SIZE); + } +} + /** * _adreno_start - Power up the GPU and prepare to accept commands * @adreno_dev: Pointer to an adreno_device structure @@ -1330,26 +1378,13 @@ static int _adreno_start(struct adreno_device *adreno_dev) if (regulator_left_on) _soft_reset(adreno_dev); + adreno_ringbuffer_set_global(adreno_dev, 0); + status = kgsl_mmu_start(device); if (status) goto error_pwr_off; - /* Program GPU contect protection init values */ - if (device->mmu.secured) { - if (adreno_is_a4xx(adreno_dev)) - adreno_writereg(adreno_dev, - ADRENO_REG_RBBM_SECVID_TRUST_CONFIG, 0x2); - adreno_writereg(adreno_dev, - ADRENO_REG_RBBM_SECVID_TSB_CONTROL, 0x0); - - adreno_writereg64(adreno_dev, - ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE, - ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE_HI, - KGSL_IOMMU_SECURE_BASE); - adreno_writereg(adreno_dev, - ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_SIZE, - KGSL_IOMMU_SECURE_SIZE); - } + _set_secvid(device); status = adreno_ocmem_malloc(adreno_dev); if (status) { @@ -1531,6 +1566,22 @@ static int adreno_vbif_clear_pending_transactions(struct kgsl_device *device) return ret; } +static void adreno_set_active_ctxs_null(struct adreno_device *adreno_dev) +{ + int i; + struct adreno_ringbuffer *rb; + + FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { + if (rb->drawctxt_active) + kgsl_context_put(&(rb->drawctxt_active->base)); + rb->drawctxt_active = NULL; + + kgsl_sharedmem_writel(KGSL_DEVICE(adreno_dev), + &rb->pagetable_desc, PT_INFO_OFFSET(current_rb_ptname), + 0); + } +} + static int adreno_stop(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); @@ -1643,13 +1694,6 @@ int adreno_reset(struct kgsl_device *device, int fault) else kgsl_pwrctrl_change_state(device, KGSL_STATE_NAP); - /* Set the page table back to the default page table */ - kgsl_mmu_set_pt(&device->mmu, device->mmu.defaultpagetable); - kgsl_sharedmem_writel(device, - &adreno_dev->ringbuffers[0].pagetable_desc, - offsetof(struct adreno_ringbuffer_pagetable_info, - current_global_ptname), 0); - return ret; } @@ -2092,9 +2136,15 @@ static int adreno_soft_reset(struct kgsl_device *device) /* Reset the GPU */ _soft_reset(adreno_dev); + /* Set the page table back to the default page table */ + adreno_ringbuffer_set_global(adreno_dev, 0); + kgsl_mmu_set_pt(&device->mmu, device->mmu.defaultpagetable); + /* start of new CFF after reset */ kgsl_cffdump_open(device); + _set_secvid(device); + /* Enable 64 bit gpu addr if feature is set */ if (gpudev->enable_64bit && adreno_support_64bit(adreno_dev)) @@ -2147,8 +2197,6 @@ bool adreno_isidle(struct kgsl_device *device) if (!kgsl_state_is_awake(device)) return true; - adreno_get_rptr(ADRENO_CURRENT_RINGBUFFER(adreno_dev)); - /* * wptr is updated when we add commands to ringbuffer, add a barrier * to make sure updated wptr is compared to rptr @@ -2159,15 +2207,13 @@ bool adreno_isidle(struct kgsl_device *device) * ringbuffer is truly idle when all ringbuffers read and write * pointers are equal */ + FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { - if (rb->rptr != rb->wptr) - break; + if (!adreno_rb_empty(rb)) + return false; } - if (i == adreno_dev->num_ringbuffers) - return adreno_hw_isidle(adreno_dev); - - return false; + return adreno_hw_isidle(adreno_dev); } /** @@ -2265,25 +2311,11 @@ static int adreno_drain(struct kgsl_device *device) /* Caller must hold the device mutex. */ static int adreno_suspend_context(struct kgsl_device *device) { - int status = 0; - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - /* process any profiling results that are available */ - adreno_profile_process_results(adreno_dev); - - status = adreno_idle(device); - if (status) - return status; - /* set the device to default pagetable */ - kgsl_mmu_set_pt(&device->mmu, device->mmu.defaultpagetable); - kgsl_sharedmem_writel(device, - &adreno_dev->ringbuffers[0].pagetable_desc, - offsetof(struct adreno_ringbuffer_pagetable_info, - current_global_ptname), 0); - /* set ringbuffers to NULL ctxt */ - adreno_set_active_ctxs_null(adreno_dev); + adreno_profile_process_results(ADRENO_DEVICE(device)); - return status; + /* Wait for the device to go idle */ + return adreno_idle(device); } /** diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 7ac91f203a70..9f462bca26ce 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -193,6 +193,47 @@ enum adreno_gpurev { struct adreno_gpudev; +/* Time to allow preemption to complete (in ms) */ +#define ADRENO_PREEMPT_TIMEOUT 10000 + +/** + * enum adreno_preempt_states + * ADRENO_PREEMPT_NONE: No preemption is scheduled + * ADRENO_PREEMPT_START: The S/W has started + * ADRENO_PREEMPT_TRIGGERED: A preeempt has been triggered in the HW + * ADRENO_PREEMPT_FAULTED: The preempt timer has fired + * ADRENO_PREEMPT_PENDING: The H/W has signaled preemption complete + * ADRENO_PREEMPT_COMPLETE: Preemption could not be finished in the IRQ handler, + * worker has been scheduled + */ +enum adreno_preempt_states { + ADRENO_PREEMPT_NONE = 0, + ADRENO_PREEMPT_START, + ADRENO_PREEMPT_TRIGGERED, + ADRENO_PREEMPT_FAULTED, + ADRENO_PREEMPT_PENDING, + ADRENO_PREEMPT_COMPLETE, +}; + +/** + * struct adreno_preemption + * @state: The current state of preemption + * @counters: Memory descriptor for the memory where the GPU writes the + * preemption counters on switch + * @timer: A timer to make sure preemption doesn't stall + * @work: A work struct for the preemption worker (for 5XX) + * @token_submit: Indicates if a preempt token has been submitted in + * current ringbuffer (for 4XX) + */ +struct adreno_preemption { + atomic_t state; + struct kgsl_memdesc counters; + struct timer_list timer; + struct work_struct work; + bool token_submit; +}; + + struct adreno_busy_data { unsigned int gpu_busy; unsigned int vbif_ram_cycles; @@ -368,7 +409,7 @@ struct adreno_device { const struct firmware *lm_fw; uint32_t *lm_sequence; uint32_t lm_size; - struct kgsl_memdesc preemption_counters; + struct adreno_preemption preempt; struct work_struct gpmu_work; uint32_t lm_leakage; uint32_t lm_limit; @@ -458,6 +499,8 @@ enum adreno_regs { ADRENO_REG_CP_WFI_PEND_CTR, ADRENO_REG_CP_RB_BASE, ADRENO_REG_CP_RB_BASE_HI, + ADRENO_REG_CP_RB_RPTR_ADDR_LO, + ADRENO_REG_CP_RB_RPTR_ADDR_HI, ADRENO_REG_CP_RB_RPTR, ADRENO_REG_CP_RB_WPTR, ADRENO_REG_CP_CNTL, @@ -709,17 +752,12 @@ struct adreno_gpudev { void (*pwrlevel_change_settings)(struct adreno_device *, unsigned int prelevel, unsigned int postlevel, bool post); - int (*preemption_pre_ibsubmit)(struct adreno_device *, - struct adreno_ringbuffer *, unsigned int *, - struct kgsl_context *, uint64_t cond_addr, - struct kgsl_memobj_node *); + unsigned int (*preemption_pre_ibsubmit)(struct adreno_device *, + struct adreno_ringbuffer *rb, + unsigned int *, struct kgsl_context *); int (*preemption_yield_enable)(unsigned int *); - int (*preemption_post_ibsubmit)(struct adreno_device *, - struct adreno_ringbuffer *, unsigned int *, - struct kgsl_context *); - int (*preemption_token)(struct adreno_device *, - struct adreno_ringbuffer *, unsigned int *, - uint64_t gpuaddr); + unsigned int (*preemption_post_ibsubmit)(struct adreno_device *, + unsigned int *); int (*preemption_init)(struct adreno_device *); void (*preemption_schedule)(struct adreno_device *); void (*enable_64bit)(struct adreno_device *); @@ -1260,34 +1298,32 @@ static inline int adreno_bootstrap_ucode(struct adreno_device *adreno_dev) } /** - * adreno_preempt_state() - Check if preemption state is equal to given state + * adreno_in_preempt_state() - Check if preemption state is equal to given state * @adreno_dev: Device whose preemption state is checked * @state: State to compare against */ -static inline unsigned int adreno_preempt_state( - struct adreno_device *adreno_dev, - enum adreno_dispatcher_preempt_states state) +static inline bool adreno_in_preempt_state(struct adreno_device *adreno_dev, + enum adreno_preempt_states state) { - return atomic_read(&adreno_dev->dispatcher.preemption_state) == - state; + return atomic_read(&adreno_dev->preempt.state) == state; } - /** - * adreno_get_rptr() - Get the current ringbuffer read pointer - * @rb: Pointer the ringbuffer to query - * - * Get the current read pointer from the GPU register. + * adreno_set_preempt_state() - Set the specified preemption state + * @adreno_dev: Device to change preemption state + * @state: State to set */ -static inline unsigned int -adreno_get_rptr(struct adreno_ringbuffer *rb) +static inline void adreno_set_preempt_state(struct adreno_device *adreno_dev, + enum adreno_preempt_states state) { - struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb); - if (adreno_dev->cur_rb == rb && - adreno_preempt_state(adreno_dev, - ADRENO_DISPATCHER_PREEMPT_CLEAR)) - adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_RPTR, &(rb->rptr)); + /* + * atomic_set doesn't use barriers, so we need to do it ourselves. One + * before... + */ + smp_wmb(); + atomic_set(&adreno_dev->preempt.state, state); - return rb->rptr; + /* ... and one after */ + smp_wmb(); } static inline bool adreno_is_preemption_enabled( @@ -1295,7 +1331,6 @@ static inline bool adreno_is_preemption_enabled( { return test_bit(ADRENO_DEVICE_PREEMPTION, &adreno_dev->priv); } - /** * adreno_ctx_get_rb() - Return the ringbuffer that a context should * use based on priority @@ -1332,25 +1367,6 @@ static inline struct adreno_ringbuffer *adreno_ctx_get_rb( return &(adreno_dev->ringbuffers[ adreno_dev->num_ringbuffers - 1]); } -/* - * adreno_set_active_ctxs_null() - Put back reference to any active context - * and set the active context to NULL - * @adreno_dev: The adreno device - */ -static inline void adreno_set_active_ctxs_null(struct adreno_device *adreno_dev) -{ - int i; - struct adreno_ringbuffer *rb; - FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { - if (rb->drawctxt_active) - kgsl_context_put(&(rb->drawctxt_active->base)); - rb->drawctxt_active = NULL; - kgsl_sharedmem_writel(KGSL_DEVICE(adreno_dev), - &rb->pagetable_desc, - offsetof(struct adreno_ringbuffer_pagetable_info, - current_rb_ptname), 0); - } -} /* * adreno_compare_prio_level() - Compares 2 priority levels based on enum values @@ -1371,6 +1387,13 @@ void adreno_readreg64(struct adreno_device *adreno_dev, void adreno_writereg64(struct adreno_device *adreno_dev, enum adreno_regs lo, enum adreno_regs hi, uint64_t val); +unsigned int adreno_get_rptr(struct adreno_ringbuffer *rb); + +static inline bool adreno_rb_empty(struct adreno_ringbuffer *rb) +{ + return (adreno_get_rptr(rb) == rb->wptr); +} + static inline bool adreno_soft_fault_detect(struct adreno_device *adreno_dev) { return adreno_dev->fast_hang_detect && @@ -1400,4 +1423,36 @@ static inline bool adreno_support_64bit(struct adreno_device *adreno_dev) } #endif /*BITS_PER_LONG*/ +static inline void adreno_ringbuffer_set_global( + struct adreno_device *adreno_dev, int name) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + + kgsl_sharedmem_writel(device, + &adreno_dev->ringbuffers[0].pagetable_desc, + PT_INFO_OFFSET(current_global_ptname), name); +} + +static inline void adreno_ringbuffer_set_pagetable(struct adreno_ringbuffer *rb, + struct kgsl_pagetable *pt) +{ + struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + unsigned long flags; + + spin_lock_irqsave(&rb->preempt_lock, flags); + + kgsl_sharedmem_writel(device, &rb->pagetable_desc, + PT_INFO_OFFSET(current_rb_ptname), pt->name); + + kgsl_sharedmem_writeq(device, &rb->pagetable_desc, + PT_INFO_OFFSET(ttbr0), kgsl_mmu_pagetable_get_ttbr0(pt)); + + kgsl_sharedmem_writel(device, &rb->pagetable_desc, + PT_INFO_OFFSET(contextidr), + kgsl_mmu_pagetable_get_contextidr(pt)); + + spin_unlock_irqrestore(&rb->preempt_lock, flags); +} + #endif /*__ADRENO_H */ diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c index ea8b75f4c83b..2accbe5c5764 100644 --- a/drivers/gpu/msm/adreno_a3xx.c +++ b/drivers/gpu/msm/adreno_a3xx.c @@ -1756,9 +1756,9 @@ static int _ringbuffer_bootstrap_ucode(struct adreno_device *adreno_dev, *cmds++ = cp_type3_packet(CP_INTERRUPT, 1); *cmds++ = 0; - rb->wptr = rb->wptr - 2; + rb->_wptr = rb->_wptr - 2; adreno_ringbuffer_submit(rb, NULL); - rb->wptr = rb->wptr + 2; + rb->_wptr = rb->_wptr + 2; } else { for (i = pfp_idx; i < adreno_dev->pfp_fw_size; i++) *cmds++ = adreno_dev->pfp_fw[i]; diff --git a/drivers/gpu/msm/adreno_a4xx.c b/drivers/gpu/msm/adreno_a4xx.c index b1196da0cee1..b15d23cfbe0a 100644 --- a/drivers/gpu/msm/adreno_a4xx.c +++ b/drivers/gpu/msm/adreno_a4xx.c @@ -178,111 +178,6 @@ static const struct adreno_vbif_platform a4xx_vbif_platforms[] = { { adreno_is_a418, a430_vbif }, }; -/* a4xx_preemption_start() - Setup state to start preemption */ -static void a4xx_preemption_start(struct adreno_device *adreno_dev, - struct adreno_ringbuffer *rb) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - uint32_t val; - - /* - * Setup scratch registers from which the GPU will program the - * registers required to start execution of new ringbuffer - * set ringbuffer address - */ - kgsl_regwrite(device, A4XX_CP_SCRATCH_REG8, - rb->buffer_desc.gpuaddr); - kgsl_regread(device, A4XX_CP_RB_CNTL, &val); - /* scratch REG9 corresponds to CP_RB_CNTL register */ - kgsl_regwrite(device, A4XX_CP_SCRATCH_REG9, val); - /* scratch REG10 corresponds to rptr address */ - kgsl_regwrite(device, A4XX_CP_SCRATCH_REG10, 0); - /* scratch REG11 corresponds to rptr */ - kgsl_regwrite(device, A4XX_CP_SCRATCH_REG11, rb->rptr); - /* scratch REG12 corresponds to wptr */ - kgsl_regwrite(device, A4XX_CP_SCRATCH_REG12, rb->wptr); - /* - * scratch REG13 corresponds to IB1_BASE, - * 0 since we do not do switches in between IB's - */ - kgsl_regwrite(device, A4XX_CP_SCRATCH_REG13, 0); - /* scratch REG14 corresponds to IB1_BUFSZ */ - kgsl_regwrite(device, A4XX_CP_SCRATCH_REG14, 0); - /* scratch REG15 corresponds to IB2_BASE */ - kgsl_regwrite(device, A4XX_CP_SCRATCH_REG15, 0); - /* scratch REG16 corresponds to IB2_BUFSZ */ - kgsl_regwrite(device, A4XX_CP_SCRATCH_REG16, 0); - /* scratch REG17 corresponds to GPR11 */ - kgsl_regwrite(device, A4XX_CP_SCRATCH_REG17, rb->gpr11); -} - -/* a4xx_preemption_save() - Save the state after preemption is done */ -static void a4xx_preemption_save(struct adreno_device *adreno_dev, - struct adreno_ringbuffer *rb) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - - kgsl_regread(device, A4XX_CP_SCRATCH_REG18, &rb->rptr); - kgsl_regread(device, A4XX_CP_SCRATCH_REG23, &rb->gpr11); -} - -static int a4xx_preemption_token(struct adreno_device *adreno_dev, - struct adreno_ringbuffer *rb, unsigned int *cmds, - uint64_t gpuaddr) -{ - unsigned int *cmds_orig = cmds; - - /* Turn on preemption flag */ - /* preemption token - fill when pt switch command size is known */ - *cmds++ = cp_type3_packet(CP_PREEMPT_TOKEN, 3); - *cmds++ = (uint)gpuaddr; - *cmds++ = 1; - /* generate interrupt on preemption completion */ - *cmds++ = 1 << CP_PREEMPT_ORDINAL_INTERRUPT; - - return cmds - cmds_orig; - -} - -static int a4xx_preemption_pre_ibsubmit( - struct adreno_device *adreno_dev, - struct adreno_ringbuffer *rb, unsigned int *cmds, - struct kgsl_context *context, uint64_t cond_addr, - struct kgsl_memobj_node *ib) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - unsigned int *cmds_orig = cmds; - int exec_ib = 0; - - cmds += a4xx_preemption_token(adreno_dev, rb, cmds, - device->memstore.gpuaddr + - KGSL_MEMSTORE_OFFSET(context->id, preempted)); - - if (ib) - exec_ib = 1; - - *cmds++ = cp_type3_packet(CP_COND_EXEC, 4); - *cmds++ = cond_addr; - *cmds++ = cond_addr; - *cmds++ = 1; - *cmds++ = 7 + exec_ib * 3; - if (exec_ib) { - *cmds++ = cp_type3_packet(CP_INDIRECT_BUFFER_PFE, 2); - *cmds++ = ib->gpuaddr; - *cmds++ = (unsigned int) ib->size >> 2; - } - /* clear preemption flag */ - *cmds++ = cp_type3_packet(CP_MEM_WRITE, 2); - *cmds++ = cond_addr; - *cmds++ = 0; - *cmds++ = cp_type3_packet(CP_WAIT_MEM_WRITES, 1); - *cmds++ = 0; - *cmds++ = cp_type3_packet(CP_WAIT_FOR_ME, 1); - *cmds++ = 0; - - return cmds - cmds_orig; -} - /* * a4xx_is_sptp_idle() - A430 SP/TP should be off to be considered idle * @adreno_dev: The adreno device pointer @@ -723,6 +618,8 @@ static void a4xx_start(struct adreno_device *adreno_dev) gpudev->vbif_xin_halt_ctrl0_mask = A405_VBIF_XIN_HALT_CTRL0_MASK; + adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE); + a4xx_protect_init(adreno_dev); } @@ -839,6 +736,7 @@ static unsigned int a4xx_register_offsets[ADRENO_REG_REGISTER_MAX] = { ADRENO_REG_DEFINE(ADRENO_REG_CP_WFI_PEND_CTR, A4XX_CP_WFI_PEND_CTR), ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_BASE, A4XX_CP_RB_BASE), ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_BASE_HI, ADRENO_REG_SKIP), + ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_RPTR_ADDR_LO, A4XX_CP_RB_RPTR_ADDR), ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_RPTR, A4XX_CP_RB_RPTR), ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_WPTR, A4XX_CP_RB_WPTR), ADRENO_REG_DEFINE(ADRENO_REG_CP_CNTL, A4XX_CP_CNTL), @@ -1634,8 +1532,15 @@ static int a4xx_rb_start(struct adreno_device *adreno_dev, unsigned int start_type) { struct adreno_ringbuffer *rb = ADRENO_CURRENT_RINGBUFFER(adreno_dev); + struct kgsl_device *device = &adreno_dev->dev; + uint64_t addr; int ret; + addr = SCRATCH_RPTR_GPU_ADDR(device, rb->id); + + adreno_writereg64(adreno_dev, ADRENO_REG_CP_RB_RPTR_ADDR_LO, + ADRENO_REG_CP_RB_RPTR_ADDR_HI, addr); + /* * The size of the ringbuffer in the hardware is the log2 * representation of the size in quadwords (sizedwords / 2). @@ -1644,8 +1549,8 @@ static int a4xx_rb_start(struct adreno_device *adreno_dev, */ adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_CNTL, - (ilog2(KGSL_RB_DWORDS >> 1) & 0x3F) | - (1 << 27)); + ((ilog2(4) << 8) & 0x1F00) | + (ilog2(KGSL_RB_DWORDS >> 1) & 0x3F)); adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_BASE, rb->buffer_desc.gpuaddr); @@ -1755,6 +1660,19 @@ static struct adreno_coresight a4xx_coresight = { .groups = a4xx_coresight_groups, }; +static void a4xx_preempt_callback(struct adreno_device *adreno_dev, int bit) +{ + if (atomic_read(&adreno_dev->preempt.state) != ADRENO_PREEMPT_TRIGGERED) + return; + + trace_adreno_hw_preempt_trig_to_comp_int(adreno_dev->cur_rb, + adreno_dev->next_rb, + adreno_get_rptr(adreno_dev->cur_rb), + adreno_get_rptr(adreno_dev->next_rb)); + + adreno_dispatcher_schedule(KGSL_DEVICE(adreno_dev)); +} + #define A4XX_INT_MASK \ ((1 << A4XX_INT_RBBM_AHB_ERROR) | \ (1 << A4XX_INT_RBBM_REG_TIMEOUT) | \ @@ -1792,7 +1710,7 @@ static struct adreno_irq_funcs a4xx_irq_funcs[32] = { /* 6 - RBBM_ATB_ASYNC_OVERFLOW */ ADRENO_IRQ_CALLBACK(a4xx_err_callback), ADRENO_IRQ_CALLBACK(NULL), /* 7 - RBBM_GPC_ERR */ - ADRENO_IRQ_CALLBACK(adreno_dispatcher_preempt_callback), /* 8 - CP_SW */ + ADRENO_IRQ_CALLBACK(a4xx_preempt_callback), /* 8 - CP_SW */ ADRENO_IRQ_CALLBACK(a4xx_err_callback), /* 9 - CP_OPCODE_ERROR */ /* 10 - CP_RESERVED_BIT_ERROR */ ADRENO_IRQ_CALLBACK(a4xx_err_callback), @@ -1833,433 +1751,6 @@ static struct adreno_snapshot_data a4xx_snapshot_data = { .sect_sizes = &a4xx_snap_sizes, }; -#define ADRENO_RB_PREEMPT_TOKEN_DWORDS 125 - -static int a4xx_submit_preempt_token(struct adreno_ringbuffer *rb, - struct adreno_ringbuffer *incoming_rb) -{ - struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb); - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - unsigned int *ringcmds, *start; - struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); - int ptname; - struct kgsl_pagetable *pt; - int pt_switch_sizedwords = 0, total_sizedwords = 20; - unsigned link[ADRENO_RB_PREEMPT_TOKEN_DWORDS]; - uint i; - - if (incoming_rb->preempted_midway) { - - kgsl_sharedmem_readl(&incoming_rb->pagetable_desc, - &ptname, offsetof( - struct adreno_ringbuffer_pagetable_info, - current_rb_ptname)); - pt = kgsl_mmu_get_pt_from_ptname(&(device->mmu), - ptname); - /* - * always expect a valid pt, else pt refcounting is - * messed up or current pt tracking has a bug which - * could lead to eventual disaster - */ - BUG_ON(!pt); - /* set the ringbuffer for incoming RB */ - pt_switch_sizedwords = - adreno_iommu_set_pt_generate_cmds(incoming_rb, - &link[0], pt); - total_sizedwords += pt_switch_sizedwords; - } - - /* - * Allocate total_sizedwords space in RB, this is the max space - * required. - */ - ringcmds = adreno_ringbuffer_allocspace(rb, total_sizedwords); - - if (IS_ERR(ringcmds)) - return PTR_ERR(ringcmds); - - start = ringcmds; - - *ringcmds++ = cp_packet(adreno_dev, CP_SET_PROTECTED_MODE, 1); - *ringcmds++ = 0; - - if (incoming_rb->preempted_midway) { - for (i = 0; i < pt_switch_sizedwords; i++) - *ringcmds++ = link[i]; - } - - *ringcmds++ = cp_register(adreno_dev, adreno_getreg(adreno_dev, - ADRENO_REG_CP_PREEMPT_DISABLE), 1); - *ringcmds++ = 0; - - *ringcmds++ = cp_packet(adreno_dev, CP_SET_PROTECTED_MODE, 1); - *ringcmds++ = 1; - - ringcmds += gpudev->preemption_token(adreno_dev, rb, ringcmds, - device->memstore.gpuaddr + - KGSL_MEMSTORE_RB_OFFSET(rb, preempted)); - - if ((uint)(ringcmds - start) > total_sizedwords) { - KGSL_DRV_ERR(device, "Insufficient rb size allocated\n"); - BUG(); - } - - /* - * If we have commands less than the space reserved in RB - * adjust the wptr accordingly - */ - rb->wptr = rb->wptr - (total_sizedwords - (uint)(ringcmds - start)); - - /* submit just the preempt token */ - mb(); - kgsl_pwrscale_busy(device); - adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR, rb->wptr); - return 0; -} - -/** - * a4xx_preempt_trig_state() - Schedule preemption in TRIGGERRED - * state - * @adreno_dev: Device which is in TRIGGERRED state - */ -static void a4xx_preempt_trig_state( - struct adreno_device *adreno_dev) -{ - struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - unsigned int rbbase, val; - - /* - * Hardware not yet idle means that preemption interrupt - * may still occur, nothing to do here until interrupt signals - * completion of preemption, just return here - */ - if (!adreno_hw_isidle(adreno_dev)) - return; - - /* - * We just changed states, reschedule dispatcher to change - * preemption states - */ - if (ADRENO_DISPATCHER_PREEMPT_TRIGGERED != - atomic_read(&dispatcher->preemption_state)) { - adreno_dispatcher_schedule(device); - return; - } - - /* - * H/W is idle and we did not get a preemption interrupt, may - * be device went idle w/o encountering any preempt token or - * we already preempted w/o interrupt - */ - adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_BASE, &rbbase); - /* Did preemption occur, if so then change states and return */ - if (rbbase != adreno_dev->cur_rb->buffer_desc.gpuaddr) { - adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT_DEBUG, &val); - if (val && rbbase == adreno_dev->next_rb->buffer_desc.gpuaddr) { - KGSL_DRV_INFO(device, - "Preemption completed without interrupt\n"); - trace_adreno_hw_preempt_trig_to_comp(adreno_dev->cur_rb, - adreno_dev->next_rb); - atomic_set(&dispatcher->preemption_state, - ADRENO_DISPATCHER_PREEMPT_COMPLETE); - adreno_dispatcher_schedule(device); - return; - } - adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT); - /* reschedule dispatcher to take care of the fault */ - adreno_dispatcher_schedule(device); - return; - } - /* - * Check if preempt token was submitted after preemption trigger, if so - * then preemption should have occurred, since device is already idle it - * means something went wrong - trigger FT - */ - if (dispatcher->preempt_token_submit) { - adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT); - /* reschedule dispatcher to take care of the fault */ - adreno_dispatcher_schedule(device); - return; - } - /* - * Preempt token was not submitted after preemption trigger so device - * may have gone idle before preemption could occur, if there are - * commands that got submitted to current RB after triggering preemption - * then submit them as those commands may have a preempt token in them - */ - adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_RPTR, - &adreno_dev->cur_rb->rptr); - if (adreno_dev->cur_rb->rptr != adreno_dev->cur_rb->wptr) { - /* - * Memory barrier before informing the - * hardware of new commands - */ - mb(); - kgsl_pwrscale_busy(device); - adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR, - adreno_dev->cur_rb->wptr); - return; - } - - /* Submit preempt token to make preemption happen */ - if (adreno_drawctxt_switch(adreno_dev, adreno_dev->cur_rb, NULL, 0)) - BUG(); - if (a4xx_submit_preempt_token(adreno_dev->cur_rb, - adreno_dev->next_rb)) - BUG(); - dispatcher->preempt_token_submit = 1; - adreno_dev->cur_rb->wptr_preempt_end = adreno_dev->cur_rb->wptr; - trace_adreno_hw_preempt_token_submit(adreno_dev->cur_rb, - adreno_dev->next_rb); -} - -/** - * a4xx_preempt_clear_state() - Schedule preemption in - * CLEAR state. Preemption can be issued in this state. - * @adreno_dev: Device which is in CLEAR state - */ -static void a4xx_preempt_clear_state( - struct adreno_device *adreno_dev) - -{ - struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct adreno_dispatcher_cmdqueue *dispatch_tempq; - struct kgsl_cmdbatch *cmdbatch; - struct adreno_ringbuffer *highest_busy_rb; - int switch_low_to_high; - int ret; - - /* Device not awake means there is nothing to do */ - if (!kgsl_state_is_awake(device)) - return; - - /* keep updating the current rptr when preemption is clear */ - adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_RPTR, - &(adreno_dev->cur_rb->rptr)); - - highest_busy_rb = adreno_dispatcher_get_highest_busy_rb(adreno_dev); - if (!highest_busy_rb) - return; - - switch_low_to_high = adreno_compare_prio_level( - highest_busy_rb->id, - adreno_dev->cur_rb->id); - - /* already current then return */ - if (!switch_low_to_high) - return; - - if (switch_low_to_high < 0) { - /* - * if switching to lower priority make sure that the rptr and - * wptr are equal, when the lower rb is not starved - */ - if (adreno_dev->cur_rb->rptr != adreno_dev->cur_rb->wptr) - return; - /* - * switch to default context because when we switch back - * to higher context then its not known which pt will - * be current, so by making it default here the next - * commands submitted will set the right pt - */ - ret = adreno_drawctxt_switch(adreno_dev, - adreno_dev->cur_rb, - NULL, 0); - /* - * lower priority RB has to wait until space opens up in - * higher RB - */ - if (ret) - return; - - adreno_writereg(adreno_dev, - ADRENO_REG_CP_PREEMPT_DISABLE, 1); - } - - /* - * setup registers to do the switch to highest priority RB - * which is not empty or may be starving away(poor thing) - */ - a4xx_preemption_start(adreno_dev, highest_busy_rb); - - /* turn on IOMMU as the preemption may trigger pt switch */ - kgsl_mmu_enable_clk(&device->mmu); - - atomic_set(&dispatcher->preemption_state, - ADRENO_DISPATCHER_PREEMPT_TRIGGERED); - - adreno_dev->next_rb = highest_busy_rb; - mod_timer(&dispatcher->preempt_timer, jiffies + - msecs_to_jiffies(ADRENO_DISPATCH_PREEMPT_TIMEOUT)); - - trace_adreno_hw_preempt_clear_to_trig(adreno_dev->cur_rb, - adreno_dev->next_rb); - /* issue PREEMPT trigger */ - adreno_writereg(adreno_dev, ADRENO_REG_CP_PREEMPT, 1); - /* - * IOMMU clock can be safely switched off after the timestamp - * of the first command in the new rb - */ - dispatch_tempq = &adreno_dev->next_rb->dispatch_q; - if (dispatch_tempq->head != dispatch_tempq->tail) - cmdbatch = dispatch_tempq->cmd_q[dispatch_tempq->head]; - else - cmdbatch = NULL; - if (cmdbatch) - adreno_ringbuffer_mmu_disable_clk_on_ts(device, - adreno_dev->next_rb, - cmdbatch->global_ts); - else - adreno_ringbuffer_mmu_disable_clk_on_ts(device, - adreno_dev->next_rb, adreno_dev->next_rb->timestamp); - /* submit preempt token packet to ensure preemption */ - if (switch_low_to_high < 0) { - ret = a4xx_submit_preempt_token( - adreno_dev->cur_rb, adreno_dev->next_rb); - /* - * unexpected since we are submitting this when rptr = wptr, - * this was checked above already - */ - BUG_ON(ret); - dispatcher->preempt_token_submit = 1; - adreno_dev->cur_rb->wptr_preempt_end = adreno_dev->cur_rb->wptr; - } else { - dispatcher->preempt_token_submit = 0; - adreno_dispatcher_schedule(device); - adreno_dev->cur_rb->wptr_preempt_end = 0xFFFFFFFF; - } -} - -/** - * a4xx_preempt_complete_state() - Schedule preemption in - * COMPLETE state - * @adreno_dev: Device which is in COMPLETE state - */ -static void a4xx_preempt_complete_state( - struct adreno_device *adreno_dev) - -{ - struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct adreno_dispatcher_cmdqueue *dispatch_q; - unsigned int wptr, rbbase; - unsigned int val, val1; - - del_timer_sync(&dispatcher->preempt_timer); - - adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT, &val); - adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT_DEBUG, &val1); - - if (val || !val1) { - KGSL_DRV_ERR(device, - "Invalid state after preemption CP_PREEMPT: %08x, CP_PREEMPT_DEBUG: %08x\n", - val, val1); - adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT); - adreno_dispatcher_schedule(device); - return; - } - adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_BASE, &rbbase); - if (rbbase != adreno_dev->next_rb->buffer_desc.gpuaddr) { - KGSL_DRV_ERR(device, - "RBBASE incorrect after preemption, expected %x got %016llx\b", - rbbase, - adreno_dev->next_rb->buffer_desc.gpuaddr); - adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT); - adreno_dispatcher_schedule(device); - return; - } - - a4xx_preemption_save(adreno_dev, adreno_dev->cur_rb); - - dispatch_q = &(adreno_dev->cur_rb->dispatch_q); - /* new RB is the current RB */ - trace_adreno_hw_preempt_comp_to_clear(adreno_dev->next_rb, - adreno_dev->cur_rb); - adreno_dev->prev_rb = adreno_dev->cur_rb; - adreno_dev->cur_rb = adreno_dev->next_rb; - adreno_dev->cur_rb->preempted_midway = 0; - adreno_dev->cur_rb->wptr_preempt_end = 0xFFFFFFFF; - adreno_dev->next_rb = NULL; - if (adreno_disp_preempt_fair_sched) { - /* starved rb is now scheduled so unhalt dispatcher */ - if (ADRENO_DISPATCHER_RB_STARVE_TIMER_ELAPSED == - adreno_dev->cur_rb->starve_timer_state) - adreno_put_gpu_halt(adreno_dev); - adreno_dev->cur_rb->starve_timer_state = - ADRENO_DISPATCHER_RB_STARVE_TIMER_SCHEDULED; - adreno_dev->cur_rb->sched_timer = jiffies; - /* - * If the outgoing RB is has commands then set the - * busy time for it - */ - if (adreno_dev->prev_rb->rptr != adreno_dev->prev_rb->wptr) { - adreno_dev->prev_rb->starve_timer_state = - ADRENO_DISPATCHER_RB_STARVE_TIMER_INIT; - adreno_dev->prev_rb->sched_timer = jiffies; - } else { - adreno_dev->prev_rb->starve_timer_state = - ADRENO_DISPATCHER_RB_STARVE_TIMER_UNINIT; - } - } - atomic_set(&dispatcher->preemption_state, - ADRENO_DISPATCHER_PREEMPT_CLEAR); - if (adreno_compare_prio_level(adreno_dev->prev_rb->id, - adreno_dev->cur_rb->id) < 0) { - if (adreno_dev->prev_rb->wptr_preempt_end != - adreno_dev->prev_rb->rptr) - adreno_dev->prev_rb->preempted_midway = 1; - } else if (adreno_dev->prev_rb->wptr_preempt_end != - adreno_dev->prev_rb->rptr) { - BUG(); - } - /* submit wptr if required for new rb */ - adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_WPTR, &wptr); - if (adreno_dev->cur_rb->wptr != wptr) { - kgsl_pwrscale_busy(device); - adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR, - adreno_dev->cur_rb->wptr); - } - /* clear preemption register */ - adreno_writereg(adreno_dev, ADRENO_REG_CP_PREEMPT_DEBUG, 0); - adreno_preempt_process_dispatch_queue(adreno_dev, dispatch_q); -} - -static void a4xx_preemption_schedule( - struct adreno_device *adreno_dev) -{ - struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - - if (!adreno_is_preemption_enabled(adreno_dev)) - return; - - mutex_lock(&device->mutex); - - switch (atomic_read(&dispatcher->preemption_state)) { - case ADRENO_DISPATCHER_PREEMPT_CLEAR: - a4xx_preempt_clear_state(adreno_dev); - break; - case ADRENO_DISPATCHER_PREEMPT_TRIGGERED: - a4xx_preempt_trig_state(adreno_dev); - /* - * if we transitioned to next state then fall-through - * processing to next state - */ - if (!adreno_preempt_state(adreno_dev, - ADRENO_DISPATCHER_PREEMPT_COMPLETE)) - break; - case ADRENO_DISPATCHER_PREEMPT_COMPLETE: - a4xx_preempt_complete_state(adreno_dev); - break; - default: - BUG(); - } - - mutex_unlock(&device->mutex); -} - struct adreno_gpudev adreno_a4xx_gpudev = { .reg_offsets = &a4xx_reg_offsets, .ft_perf_counters = a4xx_ft_perf_counters, @@ -2284,6 +1775,6 @@ struct adreno_gpudev adreno_a4xx_gpudev = { .regulator_enable = a4xx_regulator_enable, .regulator_disable = a4xx_regulator_disable, .preemption_pre_ibsubmit = a4xx_preemption_pre_ibsubmit, - .preemption_token = a4xx_preemption_token, .preemption_schedule = a4xx_preemption_schedule, + .preemption_init = a4xx_preemption_init, }; diff --git a/drivers/gpu/msm/adreno_a4xx.h b/drivers/gpu/msm/adreno_a4xx.h index e425dc8e9f7b..5dabc26fd34f 100644 --- a/drivers/gpu/msm/adreno_a4xx.h +++ b/drivers/gpu/msm/adreno_a4xx.h @@ -47,6 +47,15 @@ "RBBM_DPM_THERMAL_YELLOW_ERR" }, \ { BIT(A4XX_INT_RBBM_DPM_THERMAL_RED_ERR), "RBBM_DPM_THERMAL_RED_ERR" } +unsigned int a4xx_preemption_pre_ibsubmit(struct adreno_device *adreno_dev, + struct adreno_ringbuffer *rb, + unsigned int *cmds, + struct kgsl_context *context); + +void a4xx_preemption_schedule(struct adreno_device *adreno_dev); + +int a4xx_preemption_init(struct adreno_device *adreno_dev); + void a4xx_snapshot(struct adreno_device *adreno_dev, struct kgsl_snapshot *snapshot); diff --git a/drivers/gpu/msm/adreno_a4xx_preempt.c b/drivers/gpu/msm/adreno_a4xx_preempt.c new file mode 100644 index 000000000000..4087ac60c89e --- /dev/null +++ b/drivers/gpu/msm/adreno_a4xx_preempt.c @@ -0,0 +1,571 @@ +/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "adreno.h" +#include "adreno_a4xx.h" +#include "adreno_trace.h" +#include "adreno_pm4types.h" + +#define ADRENO_RB_PREEMPT_TOKEN_DWORDS 125 + +static void a4xx_preemption_timer(unsigned long data) +{ + struct adreno_device *adreno_dev = (struct adreno_device *) data; + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + unsigned int cur_rptr = adreno_get_rptr(adreno_dev->cur_rb); + unsigned int next_rptr = adreno_get_rptr(adreno_dev->next_rb); + + KGSL_DRV_ERR(device, + "Preemption timed out. cur_rb rptr/wptr %x/%x id %d, next_rb rptr/wptr %x/%x id %d, disp_state: %d\n", + cur_rptr, adreno_dev->cur_rb->wptr, adreno_dev->cur_rb->id, + next_rptr, adreno_dev->next_rb->wptr, adreno_dev->next_rb->id, + atomic_read(&adreno_dev->preempt.state)); + + adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT); + adreno_dispatcher_schedule(device); +} + +static unsigned int a4xx_preemption_token(struct adreno_device *adreno_dev, + unsigned int *cmds, uint64_t gpuaddr) +{ + unsigned int *cmds_orig = cmds; + + /* Turn on preemption flag */ + /* preemption token - fill when pt switch command size is known */ + *cmds++ = cp_type3_packet(CP_PREEMPT_TOKEN, 3); + *cmds++ = (uint)gpuaddr; + *cmds++ = 1; + /* generate interrupt on preemption completion */ + *cmds++ = 1 << CP_PREEMPT_ORDINAL_INTERRUPT; + + return (unsigned int) (cmds - cmds_orig); +} + +unsigned int a4xx_preemption_pre_ibsubmit(struct adreno_device *adreno_dev, + struct adreno_ringbuffer *rb, unsigned int *cmds, + struct kgsl_context *context) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + unsigned int *cmds_orig = cmds; + unsigned int cond_addr = device->memstore.gpuaddr + + MEMSTORE_ID_GPU_ADDR(device, context->id, preempted); + + cmds += a4xx_preemption_token(adreno_dev, cmds, cond_addr); + + *cmds++ = cp_type3_packet(CP_COND_EXEC, 4); + *cmds++ = cond_addr; + *cmds++ = cond_addr; + *cmds++ = 1; + *cmds++ = 7; + + /* clear preemption flag */ + *cmds++ = cp_type3_packet(CP_MEM_WRITE, 2); + *cmds++ = cond_addr; + *cmds++ = 0; + *cmds++ = cp_type3_packet(CP_WAIT_MEM_WRITES, 1); + *cmds++ = 0; + *cmds++ = cp_type3_packet(CP_WAIT_FOR_ME, 1); + *cmds++ = 0; + + return (unsigned int) (cmds - cmds_orig); +} + + +static void a4xx_preemption_start(struct adreno_device *adreno_dev, + struct adreno_ringbuffer *rb) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + uint32_t val; + + /* + * Setup scratch registers from which the GPU will program the + * registers required to start execution of new ringbuffer + * set ringbuffer address + */ + kgsl_regwrite(device, A4XX_CP_SCRATCH_REG8, + rb->buffer_desc.gpuaddr); + kgsl_regread(device, A4XX_CP_RB_CNTL, &val); + /* scratch REG9 corresponds to CP_RB_CNTL register */ + kgsl_regwrite(device, A4XX_CP_SCRATCH_REG9, val); + /* scratch REG10 corresponds to rptr address */ + kgsl_regwrite(device, A4XX_CP_SCRATCH_REG10, + SCRATCH_RPTR_GPU_ADDR(device, rb->id)); + /* scratch REG11 corresponds to rptr */ + kgsl_regwrite(device, A4XX_CP_SCRATCH_REG11, adreno_get_rptr(rb)); + /* scratch REG12 corresponds to wptr */ + kgsl_regwrite(device, A4XX_CP_SCRATCH_REG12, rb->wptr); + /* + * scratch REG13 corresponds to IB1_BASE, + * 0 since we do not do switches in between IB's + */ + kgsl_regwrite(device, A4XX_CP_SCRATCH_REG13, 0); + /* scratch REG14 corresponds to IB1_BUFSZ */ + kgsl_regwrite(device, A4XX_CP_SCRATCH_REG14, 0); + /* scratch REG15 corresponds to IB2_BASE */ + kgsl_regwrite(device, A4XX_CP_SCRATCH_REG15, 0); + /* scratch REG16 corresponds to IB2_BUFSZ */ + kgsl_regwrite(device, A4XX_CP_SCRATCH_REG16, 0); + /* scratch REG17 corresponds to GPR11 */ + kgsl_regwrite(device, A4XX_CP_SCRATCH_REG17, rb->gpr11); +} + +static void a4xx_preemption_save(struct adreno_device *adreno_dev, + struct adreno_ringbuffer *rb) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + + kgsl_regread(device, A4XX_CP_SCRATCH_REG23, &rb->gpr11); +} + + +static int a4xx_submit_preempt_token(struct adreno_ringbuffer *rb, + struct adreno_ringbuffer *incoming_rb) +{ + struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + unsigned int *ringcmds, *start; + int ptname; + struct kgsl_pagetable *pt; + int pt_switch_sizedwords = 0, total_sizedwords = 20; + unsigned link[ADRENO_RB_PREEMPT_TOKEN_DWORDS]; + uint i; + + if (incoming_rb->preempted_midway) { + + kgsl_sharedmem_readl(&incoming_rb->pagetable_desc, + &ptname, PT_INFO_OFFSET(current_rb_ptname)); + pt = kgsl_mmu_get_pt_from_ptname(&(device->mmu), + ptname); + /* set the ringbuffer for incoming RB */ + pt_switch_sizedwords = + adreno_iommu_set_pt_generate_cmds(incoming_rb, + &link[0], pt); + total_sizedwords += pt_switch_sizedwords; + } + + /* + * Allocate total_sizedwords space in RB, this is the max space + * required. + */ + ringcmds = adreno_ringbuffer_allocspace(rb, total_sizedwords); + + if (IS_ERR(ringcmds)) + return PTR_ERR(ringcmds); + + start = ringcmds; + + *ringcmds++ = cp_packet(adreno_dev, CP_SET_PROTECTED_MODE, 1); + *ringcmds++ = 0; + + if (incoming_rb->preempted_midway) { + for (i = 0; i < pt_switch_sizedwords; i++) + *ringcmds++ = link[i]; + } + + *ringcmds++ = cp_register(adreno_dev, adreno_getreg(adreno_dev, + ADRENO_REG_CP_PREEMPT_DISABLE), 1); + *ringcmds++ = 0; + + *ringcmds++ = cp_packet(adreno_dev, CP_SET_PROTECTED_MODE, 1); + *ringcmds++ = 1; + + ringcmds += a4xx_preemption_token(adreno_dev, ringcmds, + device->memstore.gpuaddr + + MEMSTORE_RB_OFFSET(rb, preempted)); + + if ((uint)(ringcmds - start) > total_sizedwords) + KGSL_DRV_ERR(device, "Insufficient rb size allocated\n"); + + /* + * If we have commands less than the space reserved in RB + * adjust the wptr accordingly + */ + rb->wptr = rb->wptr - (total_sizedwords - (uint)(ringcmds - start)); + + /* submit just the preempt token */ + mb(); + kgsl_pwrscale_busy(device); + adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR, rb->wptr); + return 0; +} + +static void a4xx_preempt_trig_state(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + unsigned int rbbase, val; + int ret; + + /* + * Hardware not yet idle means that preemption interrupt + * may still occur, nothing to do here until interrupt signals + * completion of preemption, just return here + */ + if (!adreno_hw_isidle(adreno_dev)) + return; + + /* + * We just changed states, reschedule dispatcher to change + * preemption states + */ + + if (atomic_read(&adreno_dev->preempt.state) != + ADRENO_PREEMPT_TRIGGERED) { + adreno_dispatcher_schedule(device); + return; + } + + /* + * H/W is idle and we did not get a preemption interrupt, may + * be device went idle w/o encountering any preempt token or + * we already preempted w/o interrupt + */ + adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_BASE, &rbbase); + /* Did preemption occur, if so then change states and return */ + if (rbbase != adreno_dev->cur_rb->buffer_desc.gpuaddr) { + adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT_DEBUG, &val); + if (val && rbbase == adreno_dev->next_rb->buffer_desc.gpuaddr) { + KGSL_DRV_INFO(device, + "Preemption completed without interrupt\n"); + trace_adreno_hw_preempt_trig_to_comp(adreno_dev->cur_rb, + adreno_dev->next_rb, + adreno_get_rptr(adreno_dev->cur_rb), + adreno_get_rptr(adreno_dev->next_rb)); + adreno_set_preempt_state(adreno_dev, + ADRENO_PREEMPT_COMPLETE); + adreno_dispatcher_schedule(device); + return; + } + adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT); + /* reschedule dispatcher to take care of the fault */ + adreno_dispatcher_schedule(device); + return; + } + /* + * Check if preempt token was submitted after preemption trigger, if so + * then preemption should have occurred, since device is already idle it + * means something went wrong - trigger FT + */ + if (adreno_dev->preempt.token_submit) { + adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT); + /* reschedule dispatcher to take care of the fault */ + adreno_dispatcher_schedule(device); + return; + } + /* + * Preempt token was not submitted after preemption trigger so device + * may have gone idle before preemption could occur, if there are + * commands that got submitted to current RB after triggering preemption + * then submit them as those commands may have a preempt token in them + */ + if (!adreno_rb_empty(adreno_dev->cur_rb)) { + /* + * Memory barrier before informing the + * hardware of new commands + */ + mb(); + kgsl_pwrscale_busy(device); + adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR, + adreno_dev->cur_rb->wptr); + return; + } + + /* Submit preempt token to make preemption happen */ + ret = adreno_drawctxt_switch(adreno_dev, adreno_dev->cur_rb, + NULL, 0); + if (ret) + KGSL_DRV_ERR(device, + "Unable to switch context to NULL: %d\n", ret); + + ret = a4xx_submit_preempt_token(adreno_dev->cur_rb, + adreno_dev->next_rb); + if (ret) + KGSL_DRV_ERR(device, + "Unable to submit preempt token: %d\n", ret); + + adreno_dev->preempt.token_submit = true; + adreno_dev->cur_rb->wptr_preempt_end = adreno_dev->cur_rb->wptr; + trace_adreno_hw_preempt_token_submit(adreno_dev->cur_rb, + adreno_dev->next_rb, + adreno_get_rptr(adreno_dev->cur_rb), + adreno_get_rptr(adreno_dev->next_rb)); +} + +static struct adreno_ringbuffer *a4xx_next_ringbuffer( + struct adreno_device *adreno_dev) +{ + struct adreno_ringbuffer *rb, *next = NULL; + int i; + + FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { + if (!adreno_rb_empty(rb) && next == NULL) { + next = rb; + continue; + } + + if (!adreno_disp_preempt_fair_sched) + continue; + + switch (rb->starve_timer_state) { + case ADRENO_DISPATCHER_RB_STARVE_TIMER_UNINIT: + if (!adreno_rb_empty(rb) && + adreno_dev->cur_rb != rb) { + rb->starve_timer_state = + ADRENO_DISPATCHER_RB_STARVE_TIMER_INIT; + rb->sched_timer = jiffies; + } + break; + case ADRENO_DISPATCHER_RB_STARVE_TIMER_INIT: + if (time_after(jiffies, rb->sched_timer + + msecs_to_jiffies( + adreno_dispatch_starvation_time))) { + rb->starve_timer_state = + ADRENO_DISPATCHER_RB_STARVE_TIMER_ELAPSED; + /* halt dispatcher to remove starvation */ + adreno_get_gpu_halt(adreno_dev); + } + break; + case ADRENO_DISPATCHER_RB_STARVE_TIMER_SCHEDULED: + /* + * If the RB has not been running for the minimum + * time slice then allow it to run + */ + if (!adreno_rb_empty(rb) && time_before(jiffies, + adreno_dev->cur_rb->sched_timer + + msecs_to_jiffies(adreno_dispatch_time_slice))) + next = rb; + else + rb->starve_timer_state = + ADRENO_DISPATCHER_RB_STARVE_TIMER_UNINIT; + break; + case ADRENO_DISPATCHER_RB_STARVE_TIMER_ELAPSED: + default: + break; + } + } + + return next; +} + +static void a4xx_preempt_clear_state(struct adreno_device *adreno_dev) + +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct adreno_ringbuffer *highest_busy_rb; + int switch_low_to_high; + int ret; + + /* Device not awake means there is nothing to do */ + if (!kgsl_state_is_awake(device)) + return; + + highest_busy_rb = a4xx_next_ringbuffer(adreno_dev); + if (!highest_busy_rb || highest_busy_rb == adreno_dev->cur_rb) + return; + + switch_low_to_high = adreno_compare_prio_level( + highest_busy_rb->id, + adreno_dev->cur_rb->id); + + if (switch_low_to_high < 0) { + /* + * if switching to lower priority make sure that the rptr and + * wptr are equal, when the lower rb is not starved + */ + if (!adreno_rb_empty(adreno_dev->cur_rb)) + return; + /* + * switch to default context because when we switch back + * to higher context then its not known which pt will + * be current, so by making it default here the next + * commands submitted will set the right pt + */ + ret = adreno_drawctxt_switch(adreno_dev, + adreno_dev->cur_rb, + NULL, 0); + /* + * lower priority RB has to wait until space opens up in + * higher RB + */ + if (ret) { + KGSL_DRV_ERR(device, + "Unable to switch context to NULL: %d", + ret); + + return; + } + + adreno_writereg(adreno_dev, + ADRENO_REG_CP_PREEMPT_DISABLE, 1); + } + + /* + * setup registers to do the switch to highest priority RB + * which is not empty or may be starving away(poor thing) + */ + a4xx_preemption_start(adreno_dev, highest_busy_rb); + + adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_TRIGGERED); + + adreno_dev->next_rb = highest_busy_rb; + mod_timer(&adreno_dev->preempt.timer, jiffies + + msecs_to_jiffies(ADRENO_PREEMPT_TIMEOUT)); + + trace_adreno_hw_preempt_clear_to_trig(adreno_dev->cur_rb, + adreno_dev->next_rb, + adreno_get_rptr(adreno_dev->cur_rb), + adreno_get_rptr(adreno_dev->next_rb)); + /* issue PREEMPT trigger */ + adreno_writereg(adreno_dev, ADRENO_REG_CP_PREEMPT, 1); + + /* submit preempt token packet to ensure preemption */ + if (switch_low_to_high < 0) { + ret = a4xx_submit_preempt_token( + adreno_dev->cur_rb, adreno_dev->next_rb); + KGSL_DRV_ERR(device, + "Unable to submit preempt token: %d\n", ret); + adreno_dev->preempt.token_submit = true; + adreno_dev->cur_rb->wptr_preempt_end = adreno_dev->cur_rb->wptr; + } else { + adreno_dev->preempt.token_submit = false; + adreno_dispatcher_schedule(device); + adreno_dev->cur_rb->wptr_preempt_end = 0xFFFFFFFF; + } +} + +static void a4xx_preempt_complete_state(struct adreno_device *adreno_dev) + +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + unsigned int wptr, rbbase; + unsigned int val, val1; + unsigned int prevrptr; + + del_timer_sync(&adreno_dev->preempt.timer); + + adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT, &val); + adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT_DEBUG, &val1); + + if (val || !val1) { + KGSL_DRV_ERR(device, + "Invalid state after preemption CP_PREEMPT: %08x, CP_PREEMPT_DEBUG: %08x\n", + val, val1); + adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT); + adreno_dispatcher_schedule(device); + return; + } + adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_BASE, &rbbase); + if (rbbase != adreno_dev->next_rb->buffer_desc.gpuaddr) { + KGSL_DRV_ERR(device, + "RBBASE incorrect after preemption, expected %x got %016llx\b", + rbbase, + adreno_dev->next_rb->buffer_desc.gpuaddr); + adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT); + adreno_dispatcher_schedule(device); + return; + } + + a4xx_preemption_save(adreno_dev, adreno_dev->cur_rb); + + /* new RB is the current RB */ + trace_adreno_hw_preempt_comp_to_clear(adreno_dev->next_rb, + adreno_dev->cur_rb, + adreno_get_rptr(adreno_dev->next_rb), + adreno_get_rptr(adreno_dev->cur_rb)); + + adreno_dev->prev_rb = adreno_dev->cur_rb; + adreno_dev->cur_rb = adreno_dev->next_rb; + adreno_dev->cur_rb->preempted_midway = 0; + adreno_dev->cur_rb->wptr_preempt_end = 0xFFFFFFFF; + adreno_dev->next_rb = NULL; + + if (adreno_disp_preempt_fair_sched) { + /* starved rb is now scheduled so unhalt dispatcher */ + if (ADRENO_DISPATCHER_RB_STARVE_TIMER_ELAPSED == + adreno_dev->cur_rb->starve_timer_state) + adreno_put_gpu_halt(adreno_dev); + adreno_dev->cur_rb->starve_timer_state = + ADRENO_DISPATCHER_RB_STARVE_TIMER_SCHEDULED; + adreno_dev->cur_rb->sched_timer = jiffies; + /* + * If the outgoing RB is has commands then set the + * busy time for it + */ + if (!adreno_rb_empty(adreno_dev->prev_rb)) { + adreno_dev->prev_rb->starve_timer_state = + ADRENO_DISPATCHER_RB_STARVE_TIMER_INIT; + adreno_dev->prev_rb->sched_timer = jiffies; + } else { + adreno_dev->prev_rb->starve_timer_state = + ADRENO_DISPATCHER_RB_STARVE_TIMER_UNINIT; + } + } + adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE); + + prevrptr = adreno_get_rptr(adreno_dev->prev_rb); + + if (adreno_compare_prio_level(adreno_dev->prev_rb->id, + adreno_dev->cur_rb->id) < 0) { + if (adreno_dev->prev_rb->wptr_preempt_end != prevrptr) + adreno_dev->prev_rb->preempted_midway = 1; + } + + /* submit wptr if required for new rb */ + adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_WPTR, &wptr); + if (adreno_dev->cur_rb->wptr != wptr) { + kgsl_pwrscale_busy(device); + adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR, + adreno_dev->cur_rb->wptr); + } + /* clear preemption register */ + adreno_writereg(adreno_dev, ADRENO_REG_CP_PREEMPT_DEBUG, 0); +} + +void a4xx_preemption_schedule(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + + if (!adreno_is_preemption_enabled(adreno_dev)) + return; + + mutex_lock(&device->mutex); + + switch (atomic_read(&adreno_dev->preempt.state)) { + case ADRENO_PREEMPT_NONE: + a4xx_preempt_clear_state(adreno_dev); + break; + case ADRENO_PREEMPT_TRIGGERED: + a4xx_preempt_trig_state(adreno_dev); + /* + * if we transitioned to next state then fall-through + * processing to next state + */ + if (!adreno_in_preempt_state(adreno_dev, + ADRENO_PREEMPT_COMPLETE)) + break; + case ADRENO_PREEMPT_COMPLETE: + a4xx_preempt_complete_state(adreno_dev); + break; + default: + break; + } + + mutex_unlock(&device->mutex); +} + +int a4xx_preemption_init(struct adreno_device *adreno_dev) +{ + setup_timer(&adreno_dev->preempt.timer, a4xx_preemption_timer, + (unsigned long) adreno_dev); + + return 0; +} diff --git a/drivers/gpu/msm/adreno_a4xx_snapshot.c b/drivers/gpu/msm/adreno_a4xx_snapshot.c index b07e970aae32..6921af5c0ab5 100644 --- a/drivers/gpu/msm/adreno_a4xx_snapshot.c +++ b/drivers/gpu/msm/adreno_a4xx_snapshot.c @@ -534,9 +534,6 @@ void a4xx_snapshot(struct adreno_device *adreno_dev, kgsl_regwrite(device, A4XX_RBBM_CLOCK_CTL, 0); kgsl_regwrite(device, A4XX_RBBM_CLOCK_CTL2, 0); - /* Turn on MMU clocks since we read MMU registers */ - kgsl_mmu_enable_clk(&device->mmu); - /* Master set of (non debug) registers */ SNAPSHOT_REGISTERS(device, snapshot, a4xx_registers); @@ -554,8 +551,6 @@ void a4xx_snapshot(struct adreno_device *adreno_dev, a4xx_vbif_snapshot_registers, ARRAY_SIZE(a4xx_vbif_snapshot_registers)); - kgsl_mmu_disable_clk(&device->mmu); - kgsl_snapshot_indexed_registers(device, snapshot, A4XX_CP_STATE_DEBUG_INDEX, A4XX_CP_STATE_DEBUG_DATA, 0, snap_data->sect_sizes->cp_pfp); diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index 5fb912738796..96f72c59e4cd 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -60,19 +60,12 @@ static const struct adreno_vbif_platform a5xx_vbif_platforms[] = { { adreno_is_a506, a530_vbif }, }; -#define PREEMPT_RECORD(_field) \ - offsetof(struct a5xx_cp_preemption_record, _field) - -#define PREEMPT_SMMU_RECORD(_field) \ - offsetof(struct a5xx_cp_smmu_info, _field) - static void a5xx_irq_storm_worker(struct work_struct *work); static int _read_fw2_block_header(uint32_t *header, uint32_t id, uint32_t major, uint32_t minor); static void a5xx_gpmu_reset(struct work_struct *work); static int a5xx_gpmu_init(struct adreno_device *adreno_dev); - /** * Number of times to check if the regulator enabled before * giving up and returning failure. @@ -108,8 +101,9 @@ static void spin_idle_debug(struct kgsl_device *device, kgsl_regread(device, A5XX_CP_HW_FAULT, &hwfault); dev_err(device->dev, - " rb=%X/%X rbbm_status=%8.8X/%8.8X int_0_status=%8.8X\n", - rptr, wptr, status, status3, intstatus); + "rb=%d pos=%X/%X rbbm_status=%8.8X/%8.8X int_0_status=%8.8X\n", + adreno_dev->cur_rb->id, rptr, wptr, status, status3, intstatus); + dev_err(device->dev, " hwfault=%8.8X\n", hwfault); kgsl_device_snapshot(device, NULL); @@ -179,277 +173,6 @@ static void a5xx_check_features(struct adreno_device *adreno_dev) adreno_efuse_unmap(adreno_dev); } -/* - * a5xx_preemption_start() - Setup state to start preemption - */ -static void a5xx_preemption_start(struct adreno_device *adreno_dev, - struct adreno_ringbuffer *rb) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device); - uint64_t ttbr0; - uint32_t contextidr; - struct kgsl_pagetable *pt; - bool switch_default_pt = true; - - kgsl_sharedmem_writel(device, &rb->preemption_desc, - PREEMPT_RECORD(wptr), rb->wptr); - kgsl_regwrite(device, A5XX_CP_CONTEXT_SWITCH_RESTORE_ADDR_LO, - lower_32_bits(rb->preemption_desc.gpuaddr)); - kgsl_regwrite(device, A5XX_CP_CONTEXT_SWITCH_RESTORE_ADDR_HI, - upper_32_bits(rb->preemption_desc.gpuaddr)); - kgsl_sharedmem_readq(&rb->pagetable_desc, &ttbr0, - offsetof(struct adreno_ringbuffer_pagetable_info, ttbr0)); - kgsl_sharedmem_readl(&rb->pagetable_desc, &contextidr, - offsetof(struct adreno_ringbuffer_pagetable_info, contextidr)); - - spin_lock(&kgsl_driver.ptlock); - list_for_each_entry(pt, &kgsl_driver.pagetable_list, list) { - if (kgsl_mmu_pagetable_get_ttbr0(pt) == ttbr0) { - switch_default_pt = false; - break; - } - } - spin_unlock(&kgsl_driver.ptlock); - - if (switch_default_pt) { - ttbr0 = kgsl_mmu_pagetable_get_ttbr0( - device->mmu.defaultpagetable); - contextidr = kgsl_mmu_pagetable_get_contextidr( - device->mmu.defaultpagetable); - } - - kgsl_sharedmem_writeq(device, &iommu->smmu_info, - offsetof(struct a5xx_cp_smmu_info, ttbr0), ttbr0); - kgsl_sharedmem_writel(device, &iommu->smmu_info, - offsetof(struct a5xx_cp_smmu_info, context_idr), contextidr); -} - -/* - * a5xx_preemption_save() - Save the state after preemption is done - */ -static void a5xx_preemption_save(struct adreno_device *adreno_dev, - struct adreno_ringbuffer *rb) -{ - /* save the rptr from ctxrecord here */ - kgsl_sharedmem_readl(&rb->preemption_desc, &rb->rptr, - PREEMPT_RECORD(rptr)); -} - -#ifdef CONFIG_QCOM_KGSL_IOMMU -static int a5xx_preemption_iommu_init(struct adreno_device *adreno_dev) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device); - - /* Allocate mem for storing preemption smmu record */ - return kgsl_allocate_global(device, &iommu->smmu_info, PAGE_SIZE, - KGSL_MEMFLAGS_GPUREADONLY, KGSL_MEMDESC_PRIVILEGED); -} -#else -static int a5xx_preemption_iommu_init(struct adreno_device *adreno_dev) -{ - return -ENODEV; -} -#endif - -static int a5xx_preemption_init(struct adreno_device *adreno_dev) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct adreno_ringbuffer *rb; - int ret; - unsigned int i; - uint64_t addr; - - /* We are dependent on IOMMU to make preemption go on the CP side */ - if (kgsl_mmu_get_mmutype(device) != KGSL_MMU_TYPE_IOMMU) - return -ENODEV; - - /* Allocate mem for storing preemption counters */ - ret = kgsl_allocate_global(device, &adreno_dev->preemption_counters, - adreno_dev->num_ringbuffers * - A5XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE, 0, 0); - if (ret) - return ret; - - addr = adreno_dev->preemption_counters.gpuaddr; - - /* Allocate mem for storing preemption switch record */ - FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { - ret = kgsl_allocate_global(device, - &rb->preemption_desc, A5XX_CP_CTXRECORD_SIZE_IN_BYTES, - 0, KGSL_MEMDESC_PRIVILEGED); - if (ret) - return ret; - - /* Initialize the context switch record here */ - kgsl_sharedmem_writel(device, &rb->preemption_desc, - PREEMPT_RECORD(magic), A5XX_CP_CTXRECORD_MAGIC_REF); - kgsl_sharedmem_writel(device, &rb->preemption_desc, - PREEMPT_RECORD(info), 0); - kgsl_sharedmem_writel(device, &rb->preemption_desc, - PREEMPT_RECORD(data), 0); - kgsl_sharedmem_writel(device, &rb->preemption_desc, - PREEMPT_RECORD(cntl), 0x0800000C); - kgsl_sharedmem_writel(device, &rb->preemption_desc, - PREEMPT_RECORD(rptr), 0); - kgsl_sharedmem_writel(device, &rb->preemption_desc, - PREEMPT_RECORD(wptr), 0); - kgsl_sharedmem_writeq(device, &rb->preemption_desc, - PREEMPT_RECORD(rbase), - adreno_dev->ringbuffers[i].buffer_desc.gpuaddr); - kgsl_sharedmem_writeq(device, &rb->preemption_desc, - PREEMPT_RECORD(counter), addr); - - addr += A5XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE; - } - - return a5xx_preemption_iommu_init(adreno_dev); -} - -/* - * a5xx_preemption_token() - Preempt token on a5xx - * PM4 commands for preempt token on a5xx. These commands are - * submitted to ringbuffer to trigger preemption. - */ -static int a5xx_preemption_token(struct adreno_device *adreno_dev, - struct adreno_ringbuffer *rb, unsigned int *cmds, - uint64_t gpuaddr) -{ - unsigned int *cmds_orig = cmds; - - *cmds++ = cp_type7_packet(CP_CONTEXT_SWITCH_YIELD, 4); - cmds += cp_gpuaddr(adreno_dev, cmds, gpuaddr); - *cmds++ = 1; - /* generate interrupt on preemption completion */ - *cmds++ = 1; - - return cmds - cmds_orig; - -} - -/* - * a5xx_preemption_pre_ibsubmit() - Below PM4 commands are - * added at the beginning of every cmdbatch submission. - */ -static int a5xx_preemption_pre_ibsubmit( - struct adreno_device *adreno_dev, - struct adreno_ringbuffer *rb, unsigned int *cmds, - struct kgsl_context *context, uint64_t cond_addr, - struct kgsl_memobj_node *ib) -{ - unsigned int *cmds_orig = cmds; - uint64_t gpuaddr = rb->preemption_desc.gpuaddr; - unsigned int preempt_style = 0; - - if (context) { - /* - * Preemption from secure to unsecure needs Zap shader to be - * run to clear all secure content. CP does not know during - * preemption if it is switching between secure and unsecure - * contexts so restrict Secure contexts to be preempted at - * ringbuffer level. - */ - if (context->flags & KGSL_CONTEXT_SECURE) - preempt_style = KGSL_CONTEXT_PREEMPT_STYLE_RINGBUFFER; - else - preempt_style = ADRENO_PREEMPT_STYLE(context->flags); - } - - /* - * CP_PREEMPT_ENABLE_GLOBAL(global preemption) can only be set by KMD - * in ringbuffer. - * 1) set global preemption to 0x0 to disable global preemption. - * Only RB level preemption is allowed in this mode - * 2) Set global preemption to defer(0x2) for finegrain preemption. - * when global preemption is set to defer(0x2), - * CP_PREEMPT_ENABLE_LOCAL(local preemption) determines the - * preemption point. Local preemption - * can be enabled by both UMD(within IB) and KMD. - */ - *cmds++ = cp_type7_packet(CP_PREEMPT_ENABLE_GLOBAL, 1); - *cmds++ = ((preempt_style == KGSL_CONTEXT_PREEMPT_STYLE_FINEGRAIN) - ? 2 : 0); - - /* Turn CP protection OFF */ - *cmds++ = cp_type7_packet(CP_SET_PROTECTED_MODE, 1); - *cmds++ = 0; - - /* - * CP during context switch will save context switch info to - * a5xx_cp_preemption_record pointed by CONTEXT_SWITCH_SAVE_ADDR - */ - *cmds++ = cp_type4_packet(A5XX_CP_CONTEXT_SWITCH_SAVE_ADDR_LO, 1); - *cmds++ = lower_32_bits(gpuaddr); - *cmds++ = cp_type4_packet(A5XX_CP_CONTEXT_SWITCH_SAVE_ADDR_HI, 1); - *cmds++ = upper_32_bits(gpuaddr); - - /* Turn CP protection ON */ - *cmds++ = cp_type7_packet(CP_SET_PROTECTED_MODE, 1); - *cmds++ = 1; - - /* - * Enable local preemption for finegrain preemption in case of - * a misbehaving IB - */ - if (preempt_style == KGSL_CONTEXT_PREEMPT_STYLE_FINEGRAIN) { - *cmds++ = cp_type7_packet(CP_PREEMPT_ENABLE_LOCAL, 1); - *cmds++ = 1; - } else { - *cmds++ = cp_type7_packet(CP_PREEMPT_ENABLE_LOCAL, 1); - *cmds++ = 0; - } - - /* Enable CP_CONTEXT_SWITCH_YIELD packets in the IB2s */ - *cmds++ = cp_type7_packet(CP_YIELD_ENABLE, 1); - *cmds++ = 2; - - return cmds - cmds_orig; -} - -/* - * a5xx_preemption_yield_enable() - Below PM4 commands are - * added after every cmdbatch submission. - */ -static int a5xx_preemption_yield_enable(unsigned int *cmds) -{ - /* - * SRM -- set render mode (ex binning, direct render etc) - * SRM is set by UMD usually at start of IB to tell CP the type of - * preemption. - * KMD needs to set SRM to NULL to indicate CP that rendering is - * done by IB. - */ - *cmds++ = cp_type7_packet(CP_SET_RENDER_MODE, 5); - *cmds++ = 0; - *cmds++ = 0; - *cmds++ = 0; - *cmds++ = 0; - *cmds++ = 0; - - *cmds++ = cp_type7_packet(CP_YIELD_ENABLE, 1); - *cmds++ = 1; - - return 8; -} - -/* - * a5xx_preemption_post_ibsubmit() - Below PM4 commands are - * added after every cmdbatch submission. - */ -static int a5xx_preemption_post_ibsubmit(struct adreno_device *adreno_dev, - struct adreno_ringbuffer *rb, unsigned int *cmds, - struct kgsl_context *context) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - unsigned int ctx_id = context ? context->id : 0; - - return a5xx_preemption_token(adreno_dev, rb, cmds, - device->memstore.gpuaddr + - KGSL_MEMSTORE_OFFSET(ctx_id, preempted)); - -} - static void a5xx_platform_setup(struct adreno_device *adreno_dev) { uint64_t addr; @@ -1666,90 +1389,6 @@ static void a530_lm_enable(struct adreno_device *adreno_dev) adreno_is_a530v2(adreno_dev) ? 0x00060011 : 0x00000011); } -static int isense_cot(struct adreno_device *adreno_dev) -{ - unsigned int r, ret; - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - - kgsl_regrmw(device, A5XX_GPU_CS_AMP_CALIBRATION_DONE, - SW_OPAMP_CAL_DONE, 0); - kgsl_regrmw(device, A5XX_GPU_CS_AMP_CALIBRATION_CONTROL1, - AMP_SW_TRIM_START, 0); - kgsl_regrmw(device, A5XX_GPU_CS_AMP_CALIBRATION_CONTROL1, - AMP_SW_TRIM_START, AMP_SW_TRIM_START); - - for (ret = 0; ret < AMP_CALIBRATION_TIMEOUT; ret++) { - kgsl_regread(device, A5XX_GPU_CS_SENSOR_GENERAL_STATUS, &r); - if (r & SS_AMPTRIM_DONE) - break; - udelay(10); - } - - if (ret == AMP_CALIBRATION_TIMEOUT) - return -ETIMEDOUT; - - if (adreno_is_a540v1(adreno_dev)) { - /* HM */ - kgsl_regread(device, A5XX_GPU_CS_AMP_CALIBRATION_STATUS1_0, &r); - if (r & AMP_CALIBRATION_ERR) - return -EIO; - } - /* SPTP */ - kgsl_regread(device, A5XX_GPU_CS_AMP_CALIBRATION_STATUS1_2, &r); - if (r & AMP_CALIBRATION_ERR) - return -EIO; - /* RAC */ - kgsl_regread(device, A5XX_GPU_CS_AMP_CALIBRATION_STATUS1_4, &r); - if (r & AMP_CALIBRATION_ERR) - return -EIO; - - kgsl_regrmw(device, A5XX_GPU_CS_AMP_CALIBRATION_DONE, - SW_OPAMP_CAL_DONE, 1); - - return 0; -} - -static int isense_enable(struct adreno_device *adreno_dev) -{ - unsigned int r; - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - - kgsl_regrmw(device, A5XX_GPMU_GPMU_ISENSE_CTRL, 0, - ISENSE_CGC_EN_DISABLE); - - kgsl_regwrite(device, A5XX_GPU_CS_ENABLE_REG, - adreno_is_a540v1(adreno_dev) ? 7 : 6); - udelay(2); - kgsl_regread(device, A5XX_GPU_CS_SENSOR_GENERAL_STATUS, &r); - if ((r & CS_PWR_ON_STATUS) == 0) { - KGSL_CORE_ERR("GPMU: ISENSE enabling failure\n"); - return -EIO; - } - - return 0; -} - -static void isense_disable(struct adreno_device *adreno_dev) -{ - unsigned int r; - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - - kgsl_regwrite(device, A5XX_GPU_CS_ENABLE_REG, 0); - udelay(1); - kgsl_regread(device, A5XX_GPU_CS_SENSOR_GENERAL_STATUS, &r); - if ((r & CS_PWR_ON_STATUS) != 0) - KGSL_CORE_ERR("GPMU: ISENSE disabling failure\n"); -} - -static bool isense_is_enabled(struct adreno_device *adreno_dev) -{ - unsigned int r; - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - - kgsl_regread(device, A5XX_GPU_CS_SENSOR_GENERAL_STATUS, &r); - return r & CS_PWR_ON_STATUS; -} - static bool llm_is_enabled(struct adreno_device *adreno_dev) { unsigned int r; @@ -1851,7 +1490,7 @@ static void a540_lm_init(struct adreno_device *adreno_dev) uint32_t agc_lm_config = ((ADRENO_CHIPID_PATCH(adreno_dev->chipid) & 0x3) << AGC_GPU_VERSION_SHIFT); - unsigned int r, i; + unsigned int r; if (!test_bit(ADRENO_THROTTLING_CTRL, &adreno_dev->pwrctrl_flag)) agc_lm_config |= AGC_THROTTLE_DISABLE; @@ -1859,7 +1498,7 @@ static void a540_lm_init(struct adreno_device *adreno_dev) if (lm_on(adreno_dev)) { agc_lm_config |= AGC_LM_CONFIG_ENABLE_GPMU_ADAPTIVE | - AGC_THROTTLE_SEL_DCS; + AGC_LM_CONFIG_ISENSE_ENABLE; kgsl_regread(device, A5XX_GPMU_TEMP_SENSOR_CONFIG, &r); if (!(r & GPMU_BCL_ENABLED)) @@ -1872,35 +1511,16 @@ static void a540_lm_init(struct adreno_device *adreno_dev) KGSL_CORE_ERR( "GPMU: ISENSE end point calibration failure\n"); agc_lm_config |= AGC_LM_CONFIG_ENABLE_ERROR; - goto start_agc; - } - - if (!isense_enable(adreno_dev)) { - agc_lm_config |= AGC_LM_CONFIG_ENABLE_ERROR; - goto start_agc; - } - - for (i = 0; i < AMP_CALIBRATION_RETRY_CNT; i++) { - if (isense_cot(adreno_dev)) - cpu_relax(); - else - break; - } - - if (i == AMP_CALIBRATION_RETRY_CNT) { - KGSL_CORE_ERR("GPMU: ISENSE cold trimming failure\n"); - agc_lm_config |= AGC_LM_CONFIG_ENABLE_ERROR; } } -start_agc: kgsl_regwrite(device, AGC_MSG_STATE, 0x80000001); kgsl_regwrite(device, AGC_MSG_COMMAND, AGC_POWER_CONFIG_PRODUCTION_ID); (void) _write_voltage_table(adreno_dev, AGC_MSG_PAYLOAD); kgsl_regwrite(device, AGC_MSG_PAYLOAD + AGC_LM_CONFIG, agc_lm_config); kgsl_regwrite(device, AGC_MSG_PAYLOAD + AGC_LEVEL_CONFIG, - (unsigned int) (~GENMASK(LM_DCVS_LIMIT, 0) | - ~GENMASK(16+LM_DCVS_LIMIT, 16))); + (unsigned int) ~(GENMASK(LM_DCVS_LIMIT, 0) | + GENMASK(16+LM_DCVS_LIMIT, 16))); kgsl_regwrite(device, AGC_MSG_PAYLOAD_SIZE, (AGC_LEVEL_CONFIG + 1) * sizeof(uint32_t)); @@ -2018,8 +1638,6 @@ static void a5xx_pre_reset(struct adreno_device *adreno_dev) if (adreno_is_a540(adreno_dev) && lm_on(adreno_dev)) { if (llm_is_awake(adreno_dev)) sleep_llm(adreno_dev); - if (isense_is_enabled(adreno_dev)) - isense_disable(adreno_dev); } } @@ -2077,12 +1695,8 @@ out: static void a5xx_start(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); - unsigned int i, bit; - struct adreno_ringbuffer *rb; - uint64_t def_ttbr0; - uint32_t contextidr; + unsigned int bit; adreno_vbif_start(adreno_dev, a5xx_vbif_platforms, ARRAY_SIZE(a5xx_vbif_platforms)); @@ -2283,58 +1897,21 @@ static void a5xx_start(struct adreno_device *adreno_dev) } - if (adreno_is_preemption_enabled(adreno_dev)) { - struct kgsl_pagetable *pt = device->mmu.defaultpagetable; - - def_ttbr0 = kgsl_mmu_pagetable_get_ttbr0(pt); - contextidr = kgsl_mmu_pagetable_get_contextidr(pt); - - /* Initialize the context switch record here */ - kgsl_sharedmem_writel(device, &iommu->smmu_info, - PREEMPT_SMMU_RECORD(magic), - A5XX_CP_SMMU_INFO_MAGIC_REF); - kgsl_sharedmem_writeq(device, &iommu->smmu_info, - PREEMPT_SMMU_RECORD(ttbr0), def_ttbr0); - /* - * The CP doesn't actually use the asid field, so - * put a bad value into it until it is removed from - * the preemption record. - */ - kgsl_sharedmem_writeq(device, &iommu->smmu_info, - PREEMPT_SMMU_RECORD(asid), - 0xdecafbad); - kgsl_sharedmem_writeq(device, &iommu->smmu_info, - PREEMPT_SMMU_RECORD(context_idr), - contextidr); - adreno_writereg64(adreno_dev, - ADRENO_REG_CP_CONTEXT_SWITCH_SMMU_INFO_LO, - ADRENO_REG_CP_CONTEXT_SWITCH_SMMU_INFO_HI, - iommu->smmu_info.gpuaddr); - - FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { - kgsl_sharedmem_writel(device, &rb->preemption_desc, - PREEMPT_RECORD(rptr), 0); - kgsl_sharedmem_writel(device, &rb->preemption_desc, - PREEMPT_RECORD(wptr), 0); - kgsl_sharedmem_writeq(device, &rb->pagetable_desc, - offsetof(struct adreno_ringbuffer_pagetable_info, - ttbr0), def_ttbr0); - } - } - + a5xx_preemption_start(adreno_dev); a5xx_protect_init(adreno_dev); } +/* + * Follow the ME_INIT sequence with a preemption yield to allow the GPU to move + * to a different ringbuffer, if desired + */ static int _preemption_init( struct adreno_device *adreno_dev, struct adreno_ringbuffer *rb, unsigned int *cmds, struct kgsl_context *context) { - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); unsigned int *cmds_orig = cmds; uint64_t gpuaddr = rb->preemption_desc.gpuaddr; - uint64_t gpuaddr_token = device->memstore.gpuaddr + - KGSL_MEMSTORE_OFFSET(0, preempted); /* Turn CP protection OFF */ *cmds++ = cp_type7_packet(CP_SET_PROTECTED_MODE, 1); @@ -2363,8 +1940,8 @@ static int _preemption_init( *cmds++ = 1; *cmds++ = cp_type7_packet(CP_CONTEXT_SWITCH_YIELD, 4); - cmds += cp_gpuaddr(adreno_dev, cmds, gpuaddr_token); - *cmds++ = 1; + cmds += cp_gpuaddr(adreno_dev, cmds, 0x0); + *cmds++ = 0; /* generate interrupt on preemption completion */ *cmds++ = 1; @@ -2402,7 +1979,7 @@ static int a5xx_post_start(struct adreno_device *adreno_dev) if (adreno_is_preemption_enabled(adreno_dev)) cmds += _preemption_init(adreno_dev, rb, cmds, NULL); - rb->wptr = rb->wptr - (42 - (cmds - start)); + rb->_wptr = rb->_wptr - (42 - (cmds - start)); ret = adreno_ringbuffer_submit_spin(rb, NULL, 2000); if (ret) @@ -2700,8 +2277,15 @@ static int a5xx_rb_start(struct adreno_device *adreno_dev, unsigned int start_type) { struct adreno_ringbuffer *rb = ADRENO_CURRENT_RINGBUFFER(adreno_dev); + struct kgsl_device *device = &adreno_dev->dev; + uint64_t addr; int ret; + addr = SCRATCH_RPTR_GPU_ADDR(device, rb->id); + + adreno_writereg64(adreno_dev, ADRENO_REG_CP_RB_RPTR_ADDR_LO, + ADRENO_REG_CP_RB_RPTR_ADDR_HI, addr); + /* * The size of the ringbuffer in the hardware is the log2 * representation of the size in quadwords (sizedwords / 2). @@ -2710,8 +2294,7 @@ static int a5xx_rb_start(struct adreno_device *adreno_dev, */ adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_CNTL, - (ilog2(KGSL_RB_DWORDS >> 1) & 0x3F) | - (1 << 27)); + A5XX_CP_RB_CNTL_DEFAULT); adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_BASE, rb->buffer_desc.gpuaddr); @@ -3252,6 +2835,10 @@ static unsigned int a5xx_register_offsets[ADRENO_REG_REGISTER_MAX] = { ADRENO_REG_DEFINE(ADRENO_REG_CP_WFI_PEND_CTR, A5XX_CP_WFI_PEND_CTR), ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_BASE, A5XX_CP_RB_BASE), ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_BASE_HI, A5XX_CP_RB_BASE_HI), + ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_RPTR_ADDR_LO, + A5XX_CP_RB_RPTR_ADDR_LO), + ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_RPTR_ADDR_HI, + A5XX_CP_RB_RPTR_ADDR_HI), ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_RPTR, A5XX_CP_RB_RPTR), ADRENO_REG_DEFINE(ADRENO_REG_CP_RB_WPTR, A5XX_CP_RB_WPTR), ADRENO_REG_DEFINE(ADRENO_REG_CP_CNTL, A5XX_CP_CNTL), @@ -3521,6 +3108,8 @@ static void a5xx_cp_callback(struct adreno_device *adreno_dev, int bit) prev = cur; } + a5xx_preemption_trigger(adreno_dev); + kgsl_schedule_work(&device->event_work); adreno_dispatcher_schedule(device); } @@ -3605,9 +3194,6 @@ void a5x_gpc_err_int_callback(struct adreno_device *adreno_dev, int bit) (1 << A5XX_INT_RBBM_ATB_ASYNC_OVERFLOW) | \ (1 << A5XX_INT_RBBM_GPC_ERROR) | \ (1 << A5XX_INT_CP_HW_ERROR) | \ - (1 << A5XX_INT_CP_IB1) | \ - (1 << A5XX_INT_CP_IB2) | \ - (1 << A5XX_INT_CP_RB) | \ (1 << A5XX_INT_CP_CACHE_FLUSH_TS) | \ (1 << A5XX_INT_RBBM_ATB_BUS_OVERFLOW) | \ (1 << A5XX_INT_UCHE_OOB_ACCESS) | \ @@ -3630,7 +3216,7 @@ static struct adreno_irq_funcs a5xx_irq_funcs[32] = { /* 6 - RBBM_ATB_ASYNC_OVERFLOW */ ADRENO_IRQ_CALLBACK(a5xx_err_callback), ADRENO_IRQ_CALLBACK(a5x_gpc_err_int_callback), /* 7 - GPC_ERR */ - ADRENO_IRQ_CALLBACK(adreno_dispatcher_preempt_callback),/* 8 - CP_SW */ + ADRENO_IRQ_CALLBACK(a5xx_preempt_callback),/* 8 - CP_SW */ ADRENO_IRQ_CALLBACK(a5xx_cp_hw_err_callback), /* 9 - CP_HW_ERROR */ /* 10 - CP_CCU_FLUSH_DEPTH_TS */ ADRENO_IRQ_CALLBACK(NULL), @@ -3638,9 +3224,9 @@ static struct adreno_irq_funcs a5xx_irq_funcs[32] = { ADRENO_IRQ_CALLBACK(NULL), /* 12 - CP_CCU_RESOLVE_TS */ ADRENO_IRQ_CALLBACK(NULL), - ADRENO_IRQ_CALLBACK(adreno_cp_callback), /* 13 - CP_IB2_INT */ - ADRENO_IRQ_CALLBACK(adreno_cp_callback), /* 14 - CP_IB1_INT */ - ADRENO_IRQ_CALLBACK(adreno_cp_callback), /* 15 - CP_RB_INT */ + ADRENO_IRQ_CALLBACK(NULL), /* 13 - CP_IB2_INT */ + ADRENO_IRQ_CALLBACK(NULL), /* 14 - CP_IB1_INT */ + ADRENO_IRQ_CALLBACK(NULL), /* 15 - CP_RB_INT */ /* 16 - CCP_UNUSED_1 */ ADRENO_IRQ_CALLBACK(NULL), ADRENO_IRQ_CALLBACK(NULL), /* 17 - CP_RB_DONE_TS */ @@ -3877,323 +3463,6 @@ static struct adreno_coresight a5xx_coresight = { .groups = a5xx_coresight_groups, }; -/** - * a5xx_preempt_trig_state() - Schedule preemption in TRIGGERRED - * state - * @adreno_dev: Device which is in TRIGGERRED state - */ -static void a5xx_preempt_trig_state( - struct adreno_device *adreno_dev) -{ - struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - unsigned int preempt_busy; - uint64_t rbbase; - - /* - * triggered preemption, check for busy bits, if not set go to complete - * bit 0: When high indicates CP is not done with preemption. - * bit 4: When high indicates that the CP is actively switching between - * application contexts. - * Check both the bits to make sure CP is done with preemption. - */ - adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT, &preempt_busy); - if (!(preempt_busy & 0x11)) { - - adreno_readreg64(adreno_dev, ADRENO_REG_CP_RB_BASE, - ADRENO_REG_CP_RB_BASE_HI, &rbbase); - /* Did preemption occur, if so then change states and return */ - if (rbbase != adreno_dev->cur_rb->buffer_desc.gpuaddr) { - if (rbbase == - adreno_dev->next_rb->buffer_desc.gpuaddr) { - KGSL_DRV_INFO(device, - "Preemption completed without interrupt\n"); - trace_adreno_hw_preempt_trig_to_comp( - adreno_dev->cur_rb, - adreno_dev->next_rb); - atomic_set(&dispatcher->preemption_state, - ADRENO_DISPATCHER_PREEMPT_COMPLETE); - } else { - /* - * Something wrong with preemption. - * Set fault and reschedule dispatcher to take - * care of fault. - */ - adreno_set_gpu_fault(adreno_dev, - ADRENO_PREEMPT_FAULT); - } - adreno_dispatcher_schedule(device); - return; - } - } - - /* - * Preemption is still happening. - * Hardware not yet idle means that preemption interrupt - * may still occur, nothing to do here until interrupt signals - * completion of preemption, just return here - */ - if (!adreno_hw_isidle(adreno_dev)) - return; - - /* - * We just changed states, reschedule dispatcher to change - * preemption states - */ - if (ADRENO_DISPATCHER_PREEMPT_TRIGGERED != - atomic_read(&dispatcher->preemption_state)) { - adreno_dispatcher_schedule(device); - return; - } - - - adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT); - - /* reschedule dispatcher to take care of the fault */ - adreno_dispatcher_schedule(device); -} - -/** - * a5xx_preempt_clear_state() - Schedule preemption in CLEAR - * state. Preemption can be issued in this state. - * @adreno_dev: Device which is in CLEAR state - */ -static void a5xx_preempt_clear_state( - struct adreno_device *adreno_dev) - -{ - struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct adreno_ringbuffer *highest_busy_rb; - int switch_low_to_high; - int ret; - - /* Device not awake means there is nothing to do */ - if (!kgsl_state_is_awake(device)) - return; - - /* keep updating the current rptr when preemption is clear */ - adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_RPTR, - &(adreno_dev->cur_rb->rptr)); - - highest_busy_rb = adreno_dispatcher_get_highest_busy_rb(adreno_dev); - if (!highest_busy_rb) - return; - - switch_low_to_high = adreno_compare_prio_level( - highest_busy_rb->id, adreno_dev->cur_rb->id); - - /* already current then return */ - if (!switch_low_to_high) - return; - - if (switch_low_to_high < 0) { - - if (!adreno_hw_isidle(adreno_dev)) { - adreno_dispatcher_schedule(device); - return; - } - - /* - * if switching to lower priority make sure that the rptr and - * wptr are equal, when the lower rb is not starved - */ - if (adreno_dev->cur_rb->rptr != adreno_dev->cur_rb->wptr) - return; - /* - * switch to default context because when we switch back - * to higher context then its not known which pt will - * be current, so by making it default here the next - * commands submitted will set the right pt - */ - ret = adreno_drawctxt_switch(adreno_dev, - adreno_dev->cur_rb, - NULL, 0); - /* - * lower priority RB has to wait until space opens up in - * higher RB - */ - if (ret) - return; - } - - /* rptr could be updated in drawctxt switch above, update it here */ - adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_RPTR, - &(adreno_dev->cur_rb->rptr)); - - /* turn on IOMMU as the preemption may trigger pt switch */ - kgsl_mmu_enable_clk(&device->mmu); - - /* - * setup memory to do the switch to highest priority RB - * which is not empty or may be starving away(poor thing) - */ - a5xx_preemption_start(adreno_dev, highest_busy_rb); - - atomic_set(&dispatcher->preemption_state, - ADRENO_DISPATCHER_PREEMPT_TRIGGERED); - - adreno_dev->next_rb = highest_busy_rb; - mod_timer(&dispatcher->preempt_timer, jiffies + - msecs_to_jiffies(ADRENO_DISPATCH_PREEMPT_TIMEOUT)); - - trace_adreno_hw_preempt_clear_to_trig(adreno_dev->cur_rb, - adreno_dev->next_rb); - /* issue PREEMPT trigger */ - adreno_writereg(adreno_dev, ADRENO_REG_CP_PREEMPT, 1); - - adreno_dispatcher_schedule(device); -} - -/** - * a5xx_preempt_complete_state() - Schedule preemption in - * COMPLETE state - * @adreno_dev: Device which is in COMPLETE state - */ -static void a5xx_preempt_complete_state( - struct adreno_device *adreno_dev) - -{ - struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct adreno_dispatcher_cmdqueue *dispatch_q; - uint64_t rbbase; - unsigned int wptr; - unsigned int val; - static unsigned long wait_for_preemption_complete; - - del_timer_sync(&dispatcher->preempt_timer); - - adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT, &val); - - if (val) { - /* - * Wait for 50ms for preemption state to be updated by CP - * before triggering hang - */ - if (wait_for_preemption_complete == 0) - wait_for_preemption_complete = jiffies + - msecs_to_jiffies(50); - if (time_after(jiffies, wait_for_preemption_complete)) { - wait_for_preemption_complete = 0; - KGSL_DRV_ERR(device, - "Invalid state after preemption CP_PREEMPT:%08x STOP:%1x BUSY:%1x\n", - val, (val & 0x1), (val & 0x10)>>4); - adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT); - } - adreno_dispatcher_schedule(device); - return; - } - - wait_for_preemption_complete = 0; - adreno_readreg64(adreno_dev, ADRENO_REG_CP_RB_BASE, - ADRENO_REG_CP_RB_BASE_HI, &rbbase); - if (rbbase != adreno_dev->next_rb->buffer_desc.gpuaddr) { - KGSL_DRV_ERR(device, - "RBBASE incorrect after preemption, expected %016llx got %016llx\b", - rbbase, - adreno_dev->next_rb->buffer_desc.gpuaddr); - adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT); - adreno_dispatcher_schedule(device); - return; - } - - a5xx_preemption_save(adreno_dev, adreno_dev->cur_rb); - - dispatch_q = &(adreno_dev->cur_rb->dispatch_q); - /* new RB is the current RB */ - trace_adreno_hw_preempt_comp_to_clear(adreno_dev->next_rb, - adreno_dev->cur_rb); - adreno_dev->prev_rb = adreno_dev->cur_rb; - adreno_dev->cur_rb = adreno_dev->next_rb; - adreno_dev->cur_rb->preempted_midway = 0; - adreno_dev->cur_rb->wptr_preempt_end = 0xFFFFFFFF; - adreno_dev->next_rb = NULL; - - if (adreno_disp_preempt_fair_sched) { - /* starved rb is now scheduled so unhalt dispatcher */ - if (ADRENO_DISPATCHER_RB_STARVE_TIMER_ELAPSED == - adreno_dev->cur_rb->starve_timer_state) - adreno_put_gpu_halt(adreno_dev); - adreno_dev->cur_rb->starve_timer_state = - ADRENO_DISPATCHER_RB_STARVE_TIMER_SCHEDULED; - adreno_dev->cur_rb->sched_timer = jiffies; - /* - * If the outgoing RB is has commands then set the - * busy time for it - */ - if (adreno_dev->prev_rb->rptr != adreno_dev->prev_rb->wptr) { - adreno_dev->prev_rb->starve_timer_state = - ADRENO_DISPATCHER_RB_STARVE_TIMER_INIT; - adreno_dev->prev_rb->sched_timer = jiffies; - } else { - adreno_dev->prev_rb->starve_timer_state = - ADRENO_DISPATCHER_RB_STARVE_TIMER_UNINIT; - } - } - adreno_ringbuffer_mmu_disable_clk_on_ts(device, adreno_dev->cur_rb, - adreno_dev->cur_rb->timestamp); - - atomic_set(&dispatcher->preemption_state, - ADRENO_DISPATCHER_PREEMPT_CLEAR); - - /* submit wptr if required for new rb */ - adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_WPTR, &wptr); - if (adreno_dev->cur_rb->wptr != wptr) { - kgsl_pwrscale_busy(device); - adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR, - adreno_dev->cur_rb->wptr); - } - - adreno_preempt_process_dispatch_queue(adreno_dev, dispatch_q); -} - -static void a5xx_preemption_schedule( - struct adreno_device *adreno_dev) -{ - struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct adreno_ringbuffer *rb; - int i = 0; - - if (!adreno_is_preemption_enabled(adreno_dev)) - return; - - mutex_lock(&device->mutex); - - /* - * This barrier is needed for most updated preemption_state - * to be read. - */ - smp_mb(); - - if (KGSL_STATE_ACTIVE == device->state) - FOR_EACH_RINGBUFFER(adreno_dev, rb, i) - rb->rptr = adreno_get_rptr(rb); - - switch (atomic_read(&dispatcher->preemption_state)) { - case ADRENO_DISPATCHER_PREEMPT_CLEAR: - a5xx_preempt_clear_state(adreno_dev); - break; - case ADRENO_DISPATCHER_PREEMPT_TRIGGERED: - a5xx_preempt_trig_state(adreno_dev); - /* - * if we transitioned to next state then fall-through - * processing to next state - */ - if (!adreno_preempt_state(adreno_dev, - ADRENO_DISPATCHER_PREEMPT_COMPLETE)) - break; - case ADRENO_DISPATCHER_PREEMPT_COMPLETE: - a5xx_preempt_complete_state(adreno_dev); - break; - default: - BUG(); - } - - mutex_unlock(&device->mutex); -} - struct adreno_gpudev adreno_a5xx_gpudev = { .reg_offsets = &a5xx_reg_offsets, .ft_perf_counters = a5xx_ft_perf_counters, @@ -4221,7 +3490,6 @@ struct adreno_gpudev adreno_a5xx_gpudev = { a5xx_preemption_yield_enable, .preemption_post_ibsubmit = a5xx_preemption_post_ibsubmit, - .preemption_token = a5xx_preemption_token, .preemption_init = a5xx_preemption_init, .preemption_schedule = a5xx_preemption_schedule, .enable_64bit = a5xx_enable_64bit, diff --git a/drivers/gpu/msm/adreno_a5xx.h b/drivers/gpu/msm/adreno_a5xx.h index 1174ea68287f..7965bb7b5440 100644 --- a/drivers/gpu/msm/adreno_a5xx.h +++ b/drivers/gpu/msm/adreno_a5xx.h @@ -112,6 +112,8 @@ void a5xx_crashdump_init(struct adreno_device *adreno_dev); void a5xx_hwcg_set(struct adreno_device *adreno_dev, bool on); +#define A5XX_CP_RB_CNTL_DEFAULT (((ilog2(4) << 8) & 0x1F00) | \ + (ilog2(KGSL_RB_DWORDS >> 1) & 0x3F)) /* GPMU interrupt multiplexor */ #define FW_INTR_INFO (0) #define LLM_ACK_ERR_INTR (1) @@ -192,6 +194,7 @@ void a5xx_hwcg_set(struct adreno_device *adreno_dev, bool on); #define AGC_LM_CONFIG_ENABLE_GPMU_ADAPTIVE (1) #define AGC_LM_CONFIG_ENABLE_ERROR (3 << 4) +#define AGC_LM_CONFIG_ISENSE_ENABLE (1 << 4) #define AGC_THROTTLE_SEL_DCS (1 << 8) #define AGC_THROTTLE_DISABLE (2 << 8) @@ -205,7 +208,7 @@ void a5xx_hwcg_set(struct adreno_device *adreno_dev, bool on); #define AGC_LEVEL_CONFIG (140/4) -#define LM_DCVS_LIMIT 2 +#define LM_DCVS_LIMIT 1 /* FW file tages */ #define GPMU_FIRMWARE_ID 2 #define GPMU_SEQUENCE_ID 3 @@ -231,4 +234,22 @@ static inline bool lm_on(struct adreno_device *adreno_dev) return ADRENO_FEATURE(adreno_dev, ADRENO_LM) && test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag); } + +/* Preemption functions */ +void a5xx_preemption_trigger(struct adreno_device *adreno_dev); +void a5xx_preemption_schedule(struct adreno_device *adreno_dev); +void a5xx_preemption_start(struct adreno_device *adreno_dev); +int a5xx_preemption_init(struct adreno_device *adreno_dev); +int a5xx_preemption_yield_enable(unsigned int *cmds); + +unsigned int a5xx_preemption_post_ibsubmit(struct adreno_device *adreno_dev, + unsigned int *cmds); +unsigned int a5xx_preemption_pre_ibsubmit( + struct adreno_device *adreno_dev, + struct adreno_ringbuffer *rb, + unsigned int *cmds, struct kgsl_context *context); + + +void a5xx_preempt_callback(struct adreno_device *adreno_dev, int bit); + #endif diff --git a/drivers/gpu/msm/adreno_a5xx_preempt.c b/drivers/gpu/msm/adreno_a5xx_preempt.c new file mode 100644 index 000000000000..c1463b824c67 --- /dev/null +++ b/drivers/gpu/msm/adreno_a5xx_preempt.c @@ -0,0 +1,574 @@ +/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * 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 "adreno.h" +#include "adreno_a5xx.h" +#include "a5xx_reg.h" +#include "adreno_trace.h" +#include "adreno_pm4types.h" + +#define PREEMPT_RECORD(_field) \ + offsetof(struct a5xx_cp_preemption_record, _field) + +#define PREEMPT_SMMU_RECORD(_field) \ + offsetof(struct a5xx_cp_smmu_info, _field) + +static void _update_wptr(struct adreno_device *adreno_dev) +{ + struct adreno_ringbuffer *rb = adreno_dev->cur_rb; + unsigned int wptr; + unsigned long flags; + + spin_lock_irqsave(&rb->preempt_lock, flags); + + adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_WPTR, &wptr); + + if (wptr != rb->wptr) { + adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR, + rb->wptr); + + rb->dispatch_q.expires = jiffies + + msecs_to_jiffies(adreno_cmdbatch_timeout); + } + + spin_unlock_irqrestore(&rb->preempt_lock, flags); +} + +static inline bool adreno_move_preempt_state(struct adreno_device *adreno_dev, + enum adreno_preempt_states old, enum adreno_preempt_states new) +{ + return (atomic_cmpxchg(&adreno_dev->preempt.state, old, new) == old); +} + +static void _a5xx_preemption_done(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + unsigned int status; + + /* + * In the very unlikely case that the power is off, do nothing - the + * state will be reset on power up and everybody will be happy + */ + + if (!kgsl_state_is_awake(device)) + return; + + adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT, &status); + + if (status != 0) { + KGSL_DRV_ERR(device, + "Preemption not complete: status=%X cur=%d R/W=%X/%X next=%d R/W=%X/%X\n", + status, adreno_dev->cur_rb->id, + adreno_get_rptr(adreno_dev->cur_rb), + adreno_dev->cur_rb->wptr, adreno_dev->next_rb->id, + adreno_get_rptr(adreno_dev->next_rb), + adreno_dev->next_rb->wptr); + + /* Set a fault and restart */ + adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT); + adreno_dispatcher_schedule(device); + + return; + } + + del_timer_sync(&adreno_dev->preempt.timer); + + trace_adreno_preempt_done(adreno_dev->cur_rb, adreno_dev->next_rb); + + /* Clean up all the bits */ + adreno_dev->prev_rb = adreno_dev->cur_rb; + adreno_dev->cur_rb = adreno_dev->next_rb; + adreno_dev->next_rb = NULL; + + /* Update the wptr for the new command queue */ + _update_wptr(adreno_dev); + + /* Update the dispatcher timer for the new command queue */ + mod_timer(&adreno_dev->dispatcher.timer, + adreno_dev->cur_rb->dispatch_q.expires); + + /* Clear the preempt state */ + adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE); +} + +static void _a5xx_preemption_fault(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + unsigned int status; + + /* + * If the power is on check the preemption status one more time - if it + * was successful then just transition to the complete state + */ + if (kgsl_state_is_awake(device)) { + adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT, &status); + + if (status == 0) { + adreno_set_preempt_state(adreno_dev, + ADRENO_PREEMPT_COMPLETE); + + adreno_dispatcher_schedule(device); + return; + } + } + + KGSL_DRV_ERR(device, + "Preemption timed out: cur=%d R/W=%X/%X, next=%d R/W=%X/%X\n", + adreno_dev->cur_rb->id, + adreno_get_rptr(adreno_dev->cur_rb), adreno_dev->cur_rb->wptr, + adreno_dev->next_rb->id, + adreno_get_rptr(adreno_dev->next_rb), + adreno_dev->next_rb->wptr); + + adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT); + adreno_dispatcher_schedule(device); +} + +static void _a5xx_preemption_worker(struct work_struct *work) +{ + struct adreno_preemption *preempt = container_of(work, + struct adreno_preemption, work); + struct adreno_device *adreno_dev = container_of(preempt, + struct adreno_device, preempt); + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + + /* Need to take the mutex to make sure that the power stays on */ + mutex_lock(&device->mutex); + + if (adreno_in_preempt_state(adreno_dev, ADRENO_PREEMPT_FAULTED)) + _a5xx_preemption_fault(adreno_dev); + + mutex_unlock(&device->mutex); +} + +static void _a5xx_preemption_timer(unsigned long data) +{ + struct adreno_device *adreno_dev = (struct adreno_device *) data; + + /* We should only be here from a triggered state */ + if (!adreno_move_preempt_state(adreno_dev, + ADRENO_PREEMPT_TRIGGERED, ADRENO_PREEMPT_FAULTED)) + return; + + /* Schedule the worker to take care of the details */ + queue_work(system_unbound_wq, &adreno_dev->preempt.work); +} + +/* Find the highest priority active ringbuffer */ +static struct adreno_ringbuffer *a5xx_next_ringbuffer( + struct adreno_device *adreno_dev) +{ + struct adreno_ringbuffer *rb; + unsigned long flags; + unsigned int i; + + FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { + bool empty; + + spin_lock_irqsave(&rb->preempt_lock, flags); + empty = adreno_rb_empty(rb); + spin_unlock_irqrestore(&rb->preempt_lock, flags); + + if (empty == false) + return rb; + } + + return NULL; +} + +void a5xx_preemption_trigger(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device); + struct adreno_ringbuffer *next; + uint64_t ttbr0; + unsigned int contextidr; + unsigned long flags; + + /* Put ourselves into a possible trigger state */ + if (!adreno_move_preempt_state(adreno_dev, + ADRENO_PREEMPT_NONE, ADRENO_PREEMPT_START)) + return; + + /* Get the next ringbuffer to preempt in */ + next = a5xx_next_ringbuffer(adreno_dev); + + /* + * Nothing to do if every ringbuffer is empty or if the current + * ringbuffer is the only active one + */ + if (next == NULL || next == adreno_dev->cur_rb) { + /* + * Update any critical things that might have been skipped while + * we were looking for a new ringbuffer + */ + + if (next != NULL) { + _update_wptr(adreno_dev); + + mod_timer(&adreno_dev->dispatcher.timer, + adreno_dev->cur_rb->dispatch_q.expires); + } + + adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE); + return; + } + + /* Turn off the dispatcher timer */ + del_timer(&adreno_dev->dispatcher.timer); + + /* + * This is the most critical section - we need to take care not to race + * until we have programmed the CP for the switch + */ + + spin_lock_irqsave(&next->preempt_lock, flags); + + /* Get the pagetable from the pagetable info */ + kgsl_sharedmem_readq(&next->pagetable_desc, &ttbr0, + PT_INFO_OFFSET(ttbr0)); + kgsl_sharedmem_readl(&next->pagetable_desc, &contextidr, + PT_INFO_OFFSET(contextidr)); + + kgsl_sharedmem_writel(device, &next->preemption_desc, + PREEMPT_RECORD(wptr), next->wptr); + + spin_unlock_irqrestore(&next->preempt_lock, flags); + + /* And write it to the smmu info */ + kgsl_sharedmem_writeq(device, &iommu->smmu_info, + PREEMPT_SMMU_RECORD(ttbr0), ttbr0); + kgsl_sharedmem_writel(device, &iommu->smmu_info, + PREEMPT_SMMU_RECORD(context_idr), contextidr); + + kgsl_regwrite(device, A5XX_CP_CONTEXT_SWITCH_RESTORE_ADDR_LO, + lower_32_bits(next->preemption_desc.gpuaddr)); + kgsl_regwrite(device, A5XX_CP_CONTEXT_SWITCH_RESTORE_ADDR_HI, + upper_32_bits(next->preemption_desc.gpuaddr)); + + adreno_dev->next_rb = next; + + /* Start the timer to detect a stuck preemption */ + mod_timer(&adreno_dev->preempt.timer, + jiffies + msecs_to_jiffies(ADRENO_PREEMPT_TIMEOUT)); + + trace_adreno_preempt_trigger(adreno_dev->cur_rb, adreno_dev->next_rb); + + adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_TRIGGERED); + + /* Trigger the preemption */ + adreno_writereg(adreno_dev, ADRENO_REG_CP_PREEMPT, 1); +} + +void a5xx_preempt_callback(struct adreno_device *adreno_dev, int bit) +{ + unsigned int status; + + if (!adreno_move_preempt_state(adreno_dev, + ADRENO_PREEMPT_TRIGGERED, ADRENO_PREEMPT_PENDING)) + return; + + adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT, &status); + + if (status != 0) { + KGSL_DRV_ERR(KGSL_DEVICE(adreno_dev), + "preempt interrupt with non-zero status: %X\n", status); + + /* + * Under the assumption that this is a race between the + * interrupt and the register, schedule the worker to clean up. + * If the status still hasn't resolved itself by the time we get + * there then we have to assume something bad happened + */ + adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_COMPLETE); + adreno_dispatcher_schedule(KGSL_DEVICE(adreno_dev)); + return; + } + + del_timer(&adreno_dev->preempt.timer); + + trace_adreno_preempt_done(adreno_dev->cur_rb, + adreno_dev->next_rb); + + adreno_dev->prev_rb = adreno_dev->cur_rb; + adreno_dev->cur_rb = adreno_dev->next_rb; + adreno_dev->next_rb = NULL; + + /* Update the wptr if it changed while preemption was ongoing */ + _update_wptr(adreno_dev); + + /* Update the dispatcher timer for the new command queue */ + mod_timer(&adreno_dev->dispatcher.timer, + adreno_dev->cur_rb->dispatch_q.expires); + + adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE); +} + +void a5xx_preemption_schedule(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + + if (!adreno_is_preemption_enabled(adreno_dev)) + return; + + mutex_lock(&device->mutex); + + if (adreno_in_preempt_state(adreno_dev, ADRENO_PREEMPT_COMPLETE)) + _a5xx_preemption_done(adreno_dev); + + a5xx_preemption_trigger(adreno_dev); + + mutex_unlock(&device->mutex); +} + +unsigned int a5xx_preemption_pre_ibsubmit( + struct adreno_device *adreno_dev, + struct adreno_ringbuffer *rb, + unsigned int *cmds, struct kgsl_context *context) +{ + unsigned int *cmds_orig = cmds; + uint64_t gpuaddr = rb->preemption_desc.gpuaddr; + unsigned int preempt_style = 0; + + if (context) { + /* + * Preemption from secure to unsecure needs Zap shader to be + * run to clear all secure content. CP does not know during + * preemption if it is switching between secure and unsecure + * contexts so restrict Secure contexts to be preempted at + * ringbuffer level. + */ + if (context->flags & KGSL_CONTEXT_SECURE) + preempt_style = KGSL_CONTEXT_PREEMPT_STYLE_RINGBUFFER; + else + preempt_style = ADRENO_PREEMPT_STYLE(context->flags); + } + + /* + * CP_PREEMPT_ENABLE_GLOBAL(global preemption) can only be set by KMD + * in ringbuffer. + * 1) set global preemption to 0x0 to disable global preemption. + * Only RB level preemption is allowed in this mode + * 2) Set global preemption to defer(0x2) for finegrain preemption. + * when global preemption is set to defer(0x2), + * CP_PREEMPT_ENABLE_LOCAL(local preemption) determines the + * preemption point. Local preemption + * can be enabled by both UMD(within IB) and KMD. + */ + *cmds++ = cp_type7_packet(CP_PREEMPT_ENABLE_GLOBAL, 1); + *cmds++ = ((preempt_style == KGSL_CONTEXT_PREEMPT_STYLE_FINEGRAIN) + ? 2 : 0); + + /* Turn CP protection OFF */ + *cmds++ = cp_type7_packet(CP_SET_PROTECTED_MODE, 1); + *cmds++ = 0; + + /* + * CP during context switch will save context switch info to + * a5xx_cp_preemption_record pointed by CONTEXT_SWITCH_SAVE_ADDR + */ + *cmds++ = cp_type4_packet(A5XX_CP_CONTEXT_SWITCH_SAVE_ADDR_LO, 1); + *cmds++ = lower_32_bits(gpuaddr); + *cmds++ = cp_type4_packet(A5XX_CP_CONTEXT_SWITCH_SAVE_ADDR_HI, 1); + *cmds++ = upper_32_bits(gpuaddr); + + /* Turn CP protection ON */ + *cmds++ = cp_type7_packet(CP_SET_PROTECTED_MODE, 1); + *cmds++ = 1; + + /* + * Enable local preemption for finegrain preemption in case of + * a misbehaving IB + */ + if (preempt_style == KGSL_CONTEXT_PREEMPT_STYLE_FINEGRAIN) { + *cmds++ = cp_type7_packet(CP_PREEMPT_ENABLE_LOCAL, 1); + *cmds++ = 1; + } else { + *cmds++ = cp_type7_packet(CP_PREEMPT_ENABLE_LOCAL, 1); + *cmds++ = 0; + } + + /* Enable CP_CONTEXT_SWITCH_YIELD packets in the IB2s */ + *cmds++ = cp_type7_packet(CP_YIELD_ENABLE, 1); + *cmds++ = 2; + + return (unsigned int) (cmds - cmds_orig); +} + +int a5xx_preemption_yield_enable(unsigned int *cmds) +{ + /* + * SRM -- set render mode (ex binning, direct render etc) + * SRM is set by UMD usually at start of IB to tell CP the type of + * preemption. + * KMD needs to set SRM to NULL to indicate CP that rendering is + * done by IB. + */ + *cmds++ = cp_type7_packet(CP_SET_RENDER_MODE, 5); + *cmds++ = 0; + *cmds++ = 0; + *cmds++ = 0; + *cmds++ = 0; + *cmds++ = 0; + + *cmds++ = cp_type7_packet(CP_YIELD_ENABLE, 1); + *cmds++ = 1; + + return 8; +} + +unsigned int a5xx_preemption_post_ibsubmit(struct adreno_device *adreno_dev, + unsigned int *cmds) +{ + int dwords = 0; + + cmds[dwords++] = cp_type7_packet(CP_CONTEXT_SWITCH_YIELD, 4); + /* Write NULL to the address to skip the data write */ + dwords += cp_gpuaddr(adreno_dev, &cmds[dwords], 0x0); + cmds[dwords++] = 1; + /* generate interrupt on preemption completion */ + cmds[dwords++] = 1; + + return dwords; +} + +void a5xx_preemption_start(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device); + struct adreno_ringbuffer *rb; + unsigned int i; + + if (!adreno_is_preemption_enabled(adreno_dev)) + return; + + /* Force the state to be clear */ + adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE); + + kgsl_sharedmem_writel(device, &iommu->smmu_info, + PREEMPT_SMMU_RECORD(magic), A5XX_CP_SMMU_INFO_MAGIC_REF); + kgsl_sharedmem_writeq(device, &iommu->smmu_info, + PREEMPT_SMMU_RECORD(ttbr0), MMU_DEFAULT_TTBR0(device)); + + /* The CP doesn't use the asid record, so poison it */ + kgsl_sharedmem_writel(device, &iommu->smmu_info, + PREEMPT_SMMU_RECORD(asid), 0xDECAFBAD); + kgsl_sharedmem_writel(device, &iommu->smmu_info, + PREEMPT_SMMU_RECORD(context_idr), + MMU_DEFAULT_CONTEXTIDR(device)); + + adreno_writereg64(adreno_dev, + ADRENO_REG_CP_CONTEXT_SWITCH_SMMU_INFO_LO, + ADRENO_REG_CP_CONTEXT_SWITCH_SMMU_INFO_HI, + iommu->smmu_info.gpuaddr); + + FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { + kgsl_sharedmem_writel(device, &rb->preemption_desc, + PREEMPT_RECORD(rptr), 0); + kgsl_sharedmem_writel(device, &rb->preemption_desc, + PREEMPT_RECORD(wptr), 0); + + adreno_ringbuffer_set_pagetable(rb, + device->mmu.defaultpagetable); + } + +} + +static int a5xx_preemption_ringbuffer_init(struct adreno_device *adreno_dev, + struct adreno_ringbuffer *rb, uint64_t counteraddr) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + int ret; + + ret = kgsl_allocate_global(device, &rb->preemption_desc, + A5XX_CP_CTXRECORD_SIZE_IN_BYTES, 0, KGSL_MEMDESC_PRIVILEGED); + if (ret) + return ret; + + kgsl_sharedmem_writel(device, &rb->preemption_desc, + PREEMPT_RECORD(magic), A5XX_CP_CTXRECORD_MAGIC_REF); + kgsl_sharedmem_writel(device, &rb->preemption_desc, + PREEMPT_RECORD(info), 0); + kgsl_sharedmem_writel(device, &rb->preemption_desc, + PREEMPT_RECORD(data), 0); + kgsl_sharedmem_writel(device, &rb->preemption_desc, + PREEMPT_RECORD(cntl), A5XX_CP_RB_CNTL_DEFAULT); + kgsl_sharedmem_writel(device, &rb->preemption_desc, + PREEMPT_RECORD(rptr), 0); + kgsl_sharedmem_writel(device, &rb->preemption_desc, + PREEMPT_RECORD(wptr), 0); + kgsl_sharedmem_writeq(device, &rb->preemption_desc, + PREEMPT_RECORD(rptr_addr), SCRATCH_RPTR_GPU_ADDR(device, + rb->id)); + kgsl_sharedmem_writeq(device, &rb->preemption_desc, + PREEMPT_RECORD(rbase), rb->buffer_desc.gpuaddr); + kgsl_sharedmem_writeq(device, &rb->preemption_desc, + PREEMPT_RECORD(counter), counteraddr); + + return 0; +} + +#ifdef CONFIG_QCOM_KGSL_IOMMU +static int a5xx_preemption_iommu_init(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct kgsl_iommu *iommu = KGSL_IOMMU_PRIV(device); + + /* Allocate mem for storing preemption smmu record */ + return kgsl_allocate_global(device, &iommu->smmu_info, PAGE_SIZE, + KGSL_MEMFLAGS_GPUREADONLY, KGSL_MEMDESC_PRIVILEGED); +} +#else +static int a5xx_preemption_iommu_init(struct adreno_device *adreno_dev) +{ + return -ENODEV; +} +#endif + +int a5xx_preemption_init(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct adreno_preemption *preempt = &adreno_dev->preempt; + struct adreno_ringbuffer *rb; + int ret; + unsigned int i; + uint64_t addr; + + /* We are dependent on IOMMU to make preemption go on the CP side */ + if (kgsl_mmu_get_mmutype(device) != KGSL_MMU_TYPE_IOMMU) + return -ENODEV; + + INIT_WORK(&preempt->work, _a5xx_preemption_worker); + + setup_timer(&preempt->timer, _a5xx_preemption_timer, + (unsigned long) adreno_dev); + + /* Allocate mem for storing preemption counters */ + ret = kgsl_allocate_global(device, &preempt->counters, + adreno_dev->num_ringbuffers * + A5XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE, 0, 0); + if (ret) + return ret; + + addr = preempt->counters.gpuaddr; + + /* Allocate mem for storing preemption switch record */ + FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { + ret = a5xx_preemption_ringbuffer_init(adreno_dev, rb, addr); + if (ret) + return ret; + + addr += A5XX_CP_CTXRECORD_PREEMPTION_COUNTER_SIZE; + } + + return a5xx_preemption_iommu_init(adreno_dev); +} diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c index 1a1db3ab3dc9..9cbcd06d7658 100644 --- a/drivers/gpu/msm/adreno_debugfs.c +++ b/drivers/gpu/msm/adreno_debugfs.c @@ -226,8 +226,7 @@ static void cmdbatch_print(struct seq_file *s, struct kgsl_cmdbatch *cmdbatch) if (cmdbatch->flags & KGSL_CONTEXT_SYNC) return; - seq_printf(s, "\t%d: ib: expires: %lu", - cmdbatch->timestamp, cmdbatch->expires); + seq_printf(s, "\t%d: ", cmdbatch->timestamp); seq_puts(s, " flags: "); print_flags(s, cmdbatch_flags, ARRAY_SIZE(cmdbatch_flags), diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index 3f36a93ea110..ac3805800691 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -28,10 +28,10 @@ #define CMDQUEUE_NEXT(_i, _s) (((_i) + 1) % (_s)) /* Time in ms after which the dispatcher tries to schedule an unscheduled RB */ -static unsigned int _dispatch_starvation_time = 2000; +unsigned int adreno_dispatch_starvation_time = 2000; /* Amount of time in ms that a starved RB is permitted to execute for */ -static unsigned int _dispatch_time_slice = 25; +unsigned int adreno_dispatch_time_slice = 25; /* * If set then dispatcher tries to schedule lower priority RB's after if they @@ -78,6 +78,24 @@ unsigned int adreno_cmdbatch_timeout = 2000; /* Interval for reading and comparing fault detection registers */ static unsigned int _fault_timer_interval = 200; +#define CMDQUEUE_RB(_cmdqueue) \ + ((struct adreno_ringbuffer *) \ + container_of((_cmdqueue), struct adreno_ringbuffer, dispatch_q)) + +#define CMDQUEUE(_ringbuffer) (&(_ringbuffer)->dispatch_q) + +static int adreno_dispatch_retire_cmdqueue(struct adreno_device *adreno_dev, + struct adreno_dispatcher_cmdqueue *cmdqueue); + +static inline bool cmdqueue_is_current( + struct adreno_dispatcher_cmdqueue *cmdqueue) +{ + struct adreno_ringbuffer *rb = CMDQUEUE_RB(cmdqueue); + struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb); + + return (adreno_dev->cur_rb == rb); +} + static void _add_context(struct adreno_device *adreno_dev, struct adreno_context *drawctxt) { @@ -283,7 +301,8 @@ static void _retire_marker(struct kgsl_cmdbatch *cmdbatch) /* Retire pending GPU events for the object */ kgsl_process_event_group(device, &context->events); - trace_adreno_cmdbatch_retired(cmdbatch, -1, 0, 0, drawctxt->rb); + trace_adreno_cmdbatch_retired(cmdbatch, -1, 0, 0, drawctxt->rb, + adreno_get_rptr(drawctxt->rb)); kgsl_cmdbatch_destroy(cmdbatch); } @@ -576,8 +595,15 @@ static int sendcmd(struct adreno_device *adreno_dev, if (dispatcher->inflight == 1) { if (ret == 0) { + + /* Stop fault timer before reading fault registers */ + del_timer_sync(&dispatcher->fault_timer); + fault_detect_read(adreno_dev); + /* Start the fault timer on first submission */ + start_fault_timer(adreno_dev); + if (!test_and_set_bit(ADRENO_DISPATCHER_ACTIVE, &dispatcher->priv)) reinit_completion(&dispatcher->idle_gate); @@ -594,11 +620,15 @@ static int sendcmd(struct adreno_device *adreno_dev, dispatch_q->inflight--; /* + * Don't log a message in case of: * -ENOENT means that the context was detached before the - * command was submitted - don't log a message in that case + * command was submitted + * -ENOSPC means that there temporarily isn't any room in the + * ringbuffer + * -PROTO means that a fault is currently being worked */ - if (ret != -ENOENT) + if (ret != -ENOENT && ret != -ENOSPC && ret != -EPROTO) KGSL_DRV_ERR(device, "Unable to submit command to the ringbuffer %d\n", ret); @@ -609,7 +639,8 @@ static int sendcmd(struct adreno_device *adreno_dev, nsecs = do_div(secs, 1000000000); trace_adreno_cmdbatch_submitted(cmdbatch, (int) dispatcher->inflight, - time.ticks, (unsigned long) secs, nsecs / 1000, drawctxt->rb); + time.ticks, (unsigned long) secs, nsecs / 1000, drawctxt->rb, + adreno_get_rptr(drawctxt->rb)); cmdbatch->submit_ticks = time.ticks; @@ -618,28 +649,26 @@ static int sendcmd(struct adreno_device *adreno_dev, ADRENO_DISPATCH_CMDQUEUE_SIZE; /* - * If this is the first command in the pipe then the GPU will - * immediately start executing it so we can start the expiry timeout on - * the command batch here. Subsequent command batches will have their - * timer started when the previous command batch is retired. - * Set the timer if the cmdbatch was submitted to current - * active RB else this timer will need to be set when the - * RB becomes active, also if dispatcher is not is CLEAR - * state then the cmdbatch it is currently executing is - * unclear so do not set timer in that case either. + * For the first submission in any given command queue update the + * expected expire time - this won't actually be used / updated until + * the command queue in question goes current, but universally setting + * it here avoids the possibilty of some race conditions with preempt */ - if (1 == dispatch_q->inflight && - (&(adreno_dev->cur_rb->dispatch_q)) == dispatch_q && - adreno_preempt_state(adreno_dev, - ADRENO_DISPATCHER_PREEMPT_CLEAR)) { - cmdbatch->expires = jiffies + + + if (dispatch_q->inflight == 1) + dispatch_q->expires = jiffies + msecs_to_jiffies(adreno_cmdbatch_timeout); - mod_timer(&dispatcher->timer, cmdbatch->expires); + + /* + * If we believe ourselves to be current and preemption isn't a thing, + * then set up the timer. If this misses, then preemption is indeed a + * thing and the timer will be set up in due time + */ + if (!adreno_in_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE)) { + if (cmdqueue_is_current(dispatch_q)) + mod_timer(&dispatcher->timer, dispatch_q->expires); } - /* Start the fault detection timer on the first submission */ - if (dispatcher->inflight == 1) - start_fault_timer(adreno_dev); /* * we just submitted something, readjust ringbuffer @@ -924,87 +953,6 @@ static int get_timestamp(struct adreno_context *drawctxt, } /** - * adreno_dispatcher_preempt_timer() - Timer that triggers when preemption has - * not completed - * @data: Pointer to adreno device that did not preempt in timely manner - */ -static void adreno_dispatcher_preempt_timer(unsigned long data) -{ - struct adreno_device *adreno_dev = (struct adreno_device *) data; - struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; - - KGSL_DRV_ERR(KGSL_DEVICE(adreno_dev), - "Preemption timed out. cur_rb rptr/wptr %x/%x id %d, next_rb rptr/wptr %x/%x id %d, disp_state: %d\n", - adreno_dev->cur_rb->rptr, adreno_dev->cur_rb->wptr, - adreno_dev->cur_rb->id, adreno_dev->next_rb->rptr, - adreno_dev->next_rb->wptr, adreno_dev->next_rb->id, - atomic_read(&dispatcher->preemption_state)); - adreno_set_gpu_fault(adreno_dev, ADRENO_PREEMPT_FAULT); - adreno_dispatcher_schedule(KGSL_DEVICE(adreno_dev)); -} - -/** - * adreno_dispatcher_get_highest_busy_rb() - Returns the highest priority RB - * which is busy - * @adreno_dev: Device whose RB is returned - */ -struct adreno_ringbuffer *adreno_dispatcher_get_highest_busy_rb( - struct adreno_device *adreno_dev) -{ - struct adreno_ringbuffer *rb, *highest_busy_rb = NULL; - int i; - - FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { - if (rb->rptr != rb->wptr && !highest_busy_rb) { - highest_busy_rb = rb; - goto done; - } - - if (!adreno_disp_preempt_fair_sched) - continue; - - switch (rb->starve_timer_state) { - case ADRENO_DISPATCHER_RB_STARVE_TIMER_UNINIT: - if (rb->rptr != rb->wptr && - adreno_dev->cur_rb != rb) { - rb->starve_timer_state = - ADRENO_DISPATCHER_RB_STARVE_TIMER_INIT; - rb->sched_timer = jiffies; - } - break; - case ADRENO_DISPATCHER_RB_STARVE_TIMER_INIT: - if (time_after(jiffies, rb->sched_timer + - msecs_to_jiffies(_dispatch_starvation_time))) { - rb->starve_timer_state = - ADRENO_DISPATCHER_RB_STARVE_TIMER_ELAPSED; - /* halt dispatcher to remove starvation */ - adreno_get_gpu_halt(adreno_dev); - } - break; - case ADRENO_DISPATCHER_RB_STARVE_TIMER_SCHEDULED: - BUG_ON(adreno_dev->cur_rb != rb); - /* - * If the RB has not been running for the minimum - * time slice then allow it to run - */ - if ((rb->rptr != rb->wptr) && time_before(jiffies, - adreno_dev->cur_rb->sched_timer + - msecs_to_jiffies(_dispatch_time_slice))) - highest_busy_rb = rb; - else - rb->starve_timer_state = - ADRENO_DISPATCHER_RB_STARVE_TIMER_UNINIT; - break; - case ADRENO_DISPATCHER_RB_STARVE_TIMER_ELAPSED: - default: - break; - } - } -done: - return highest_busy_rb; -} - -/** * adreno_dispactcher_queue_cmd() - Queue a new command in the context * @adreno_dev: Pointer to the adreno device struct * @drawctxt: Pointer to the adreno draw context @@ -1433,7 +1381,7 @@ static void adreno_fault_header(struct kgsl_device *device, if (rb != NULL) pr_fault(device, cmdbatch, "gpu fault rb %d rb sw r/w %4.4x/%4.4x\n", - rb->id, rb->rptr, rb->wptr); + rb->id, rptr, rb->wptr); } else { int id = (rb != NULL) ? rb->id : -1; @@ -1444,7 +1392,7 @@ static void adreno_fault_header(struct kgsl_device *device, if (rb != NULL) dev_err(device->dev, "RB[%d] gpu fault rb sw r/w %4.4x/%4.4x\n", - rb->id, rb->rptr, rb->wptr); + rb->id, rptr, rb->wptr); } } @@ -1751,6 +1699,27 @@ replay: kfree(replay); } +static void do_header_and_snapshot(struct kgsl_device *device, + struct adreno_ringbuffer *rb, struct kgsl_cmdbatch *cmdbatch) +{ + /* Always dump the snapshot on a non-cmdbatch failure */ + if (cmdbatch == NULL) { + adreno_fault_header(device, rb, NULL); + kgsl_device_snapshot(device, NULL); + return; + } + + /* Skip everything if the PMDUMP flag is set */ + if (test_bit(KGSL_FT_SKIP_PMDUMP, &cmdbatch->fault_policy)) + return; + + /* Print the fault header */ + adreno_fault_header(device, rb, cmdbatch); + + if (!(cmdbatch->context->flags & KGSL_CONTEXT_NO_SNAPSHOT)) + kgsl_device_snapshot(device, cmdbatch->context); +} + static int dispatcher_do_fault(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); @@ -1787,7 +1756,7 @@ static int dispatcher_do_fault(struct adreno_device *adreno_dev) /* Turn off all the timers */ del_timer_sync(&dispatcher->timer); del_timer_sync(&dispatcher->fault_timer); - del_timer_sync(&dispatcher->preempt_timer); + del_timer_sync(&adreno_dev->preempt.timer); mutex_lock(&device->mutex); @@ -1813,14 +1782,12 @@ static int dispatcher_do_fault(struct adreno_device *adreno_dev) * retire cmdbatches from all the dispatch_q's before starting recovery */ FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { - adreno_dispatch_process_cmdqueue(adreno_dev, - &(rb->dispatch_q), 0); + adreno_dispatch_retire_cmdqueue(adreno_dev, + &(rb->dispatch_q)); /* Select the active dispatch_q */ if (base == rb->buffer_desc.gpuaddr) { dispatch_q = &(rb->dispatch_q); hung_rb = rb; - adreno_readreg(adreno_dev, ADRENO_REG_CP_RB_RPTR, - &hung_rb->rptr); if (adreno_dev->cur_rb != hung_rb) { adreno_dev->prev_rb = adreno_dev->cur_rb; adreno_dev->cur_rb = hung_rb; @@ -1834,7 +1801,7 @@ static int dispatcher_do_fault(struct adreno_device *adreno_dev) } } - if (dispatch_q && (dispatch_q->tail != dispatch_q->head)) { + if (!adreno_cmdqueue_is_empty(dispatch_q)) { cmdbatch = dispatch_q->cmd_q[dispatch_q->head]; trace_adreno_cmdbatch_fault(cmdbatch, fault); } @@ -1842,17 +1809,7 @@ static int dispatcher_do_fault(struct adreno_device *adreno_dev) adreno_readreg64(adreno_dev, ADRENO_REG_CP_IB1_BASE, ADRENO_REG_CP_IB1_BASE_HI, &base); - /* - * Dump the snapshot information if this is the first - * detected fault for the oldest active command batch - */ - - if (cmdbatch == NULL || - !test_bit(KGSL_FT_SKIP_PMDUMP, &cmdbatch->fault_policy)) { - adreno_fault_header(device, hung_rb, cmdbatch); - kgsl_device_snapshot(device, - cmdbatch ? cmdbatch->context : NULL); - } + do_header_and_snapshot(device, hung_rb, cmdbatch); /* Terminate the stalled transaction and resume the IOMMU */ if (fault & ADRENO_IOMMU_PAGE_FAULT) @@ -1860,8 +1817,6 @@ static int dispatcher_do_fault(struct adreno_device *adreno_dev) /* Reset the dispatcher queue */ dispatcher->inflight = 0; - atomic_set(&dispatcher->preemption_state, - ADRENO_DISPATCHER_PREEMPT_CLEAR); /* Reset the GPU and make sure halt is not set during recovery */ halt = adreno_gpu_halt(adreno_dev); @@ -1875,12 +1830,12 @@ static int dispatcher_do_fault(struct adreno_device *adreno_dev) if (hung_rb != NULL) { kgsl_sharedmem_writel(device, &device->memstore, - KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_MAX + hung_rb->id, - soptimestamp), hung_rb->timestamp); + MEMSTORE_RB_OFFSET(hung_rb, soptimestamp), + hung_rb->timestamp); kgsl_sharedmem_writel(device, &device->memstore, - KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_MAX + hung_rb->id, - eoptimestamp), hung_rb->timestamp); + MEMSTORE_RB_OFFSET(hung_rb, eoptimestamp), + hung_rb->timestamp); /* Schedule any pending events to be run */ kgsl_process_event_group(device, &hung_rb->events); @@ -1953,139 +1908,170 @@ static void cmdbatch_profile_ticks(struct adreno_device *adreno_dev, *retire = entry->retired; } -int adreno_dispatch_process_cmdqueue(struct adreno_device *adreno_dev, - struct adreno_dispatcher_cmdqueue *dispatch_q, - int long_ib_detect) +static void retire_cmdbatch(struct adreno_device *adreno_dev, + struct kgsl_cmdbatch *cmdbatch) { - struct adreno_dispatcher *dispatcher = &(adreno_dev->dispatcher); - uint64_t start_ticks = 0, retire_ticks = 0; + struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; + struct adreno_context *drawctxt = ADRENO_CONTEXT(cmdbatch->context); + uint64_t start = 0, end = 0; - struct adreno_dispatcher_cmdqueue *active_q = - &(adreno_dev->cur_rb->dispatch_q); + if (cmdbatch->fault_recovery != 0) { + set_bit(ADRENO_CONTEXT_FAULT, &cmdbatch->context->priv); + _print_recovery(KGSL_DEVICE(adreno_dev), cmdbatch); + } + + if (test_bit(CMDBATCH_FLAG_PROFILE, &cmdbatch->priv)) + cmdbatch_profile_ticks(adreno_dev, cmdbatch, &start, &end); + + trace_adreno_cmdbatch_retired(cmdbatch, (int) dispatcher->inflight, + start, end, ADRENO_CMDBATCH_RB(cmdbatch), + adreno_get_rptr(drawctxt->rb)); + + drawctxt->submit_retire_ticks[drawctxt->ticks_index] = + end - cmdbatch->submit_ticks; + + drawctxt->ticks_index = (drawctxt->ticks_index + 1) % + SUBMIT_RETIRE_TICKS_SIZE; + + kgsl_cmdbatch_destroy(cmdbatch); +} + +static int adreno_dispatch_retire_cmdqueue(struct adreno_device *adreno_dev, + struct adreno_dispatcher_cmdqueue *cmdqueue) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; int count = 0; - while (dispatch_q->head != dispatch_q->tail) { + while (!adreno_cmdqueue_is_empty(cmdqueue)) { struct kgsl_cmdbatch *cmdbatch = - dispatch_q->cmd_q[dispatch_q->head]; - struct adreno_context *drawctxt; - BUG_ON(cmdbatch == NULL); + cmdqueue->cmd_q[cmdqueue->head]; - drawctxt = ADRENO_CONTEXT(cmdbatch->context); + if (!kgsl_check_timestamp(device, cmdbatch->context, + cmdbatch->timestamp)) + break; - /* - * First try to expire the timestamp. This happens if the - * context is valid and the timestamp expired normally or if the - * context was destroyed before the command batch was finished - * in the GPU. Either way retire the command batch advance the - * pointers and continue processing the queue - */ + retire_cmdbatch(adreno_dev, cmdbatch); - if (kgsl_check_timestamp(KGSL_DEVICE(adreno_dev), - cmdbatch->context, cmdbatch->timestamp)) { + dispatcher->inflight--; + cmdqueue->inflight--; - /* - * If the cmdbatch in question had faulted announce its - * successful completion to the world - */ + cmdqueue->cmd_q[cmdqueue->head] = NULL; - if (cmdbatch->fault_recovery != 0) { - /* Mark the context as faulted and recovered */ - set_bit(ADRENO_CONTEXT_FAULT, - &cmdbatch->context->priv); + cmdqueue->head = CMDQUEUE_NEXT(cmdqueue->head, + ADRENO_DISPATCH_CMDQUEUE_SIZE); - _print_recovery(KGSL_DEVICE(adreno_dev), - cmdbatch); - } + count++; + } - /* Reduce the number of inflight command batches */ - dispatcher->inflight--; - dispatch_q->inflight--; + return count; +} - /* - * If kernel profiling is enabled get the submit and - * retired ticks from the buffer - */ +static void _adreno_dispatch_check_timeout(struct adreno_device *adreno_dev, + struct adreno_dispatcher_cmdqueue *cmdqueue) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct kgsl_cmdbatch *cmdbatch = cmdqueue->cmd_q[cmdqueue->head]; - if (test_bit(CMDBATCH_FLAG_PROFILE, &cmdbatch->priv)) - cmdbatch_profile_ticks(adreno_dev, cmdbatch, - &start_ticks, &retire_ticks); + /* Don't timeout if the timer hasn't expired yet (duh) */ + if (time_is_after_jiffies(cmdqueue->expires)) + return; - trace_adreno_cmdbatch_retired(cmdbatch, - (int) dispatcher->inflight, start_ticks, - retire_ticks, ADRENO_CMDBATCH_RB(cmdbatch)); + /* Don't timeout if the IB timeout is disabled globally */ + if (!adreno_long_ib_detect(adreno_dev)) + return; - /* Record the delta between submit and retire ticks */ - drawctxt->submit_retire_ticks[drawctxt->ticks_index] = - retire_ticks - cmdbatch->submit_ticks; + /* Don't time out if the context has disabled it */ + if (cmdbatch->context->flags & KGSL_CONTEXT_NO_FAULT_TOLERANCE) + return; - drawctxt->ticks_index = (drawctxt->ticks_index + 1) - % SUBMIT_RETIRE_TICKS_SIZE; + pr_context(device, cmdbatch->context, "gpu timeout ctx %d ts %d\n", + cmdbatch->context->id, cmdbatch->timestamp); - /* Zero the old entry*/ - dispatch_q->cmd_q[dispatch_q->head] = NULL; + adreno_set_gpu_fault(adreno_dev, ADRENO_TIMEOUT_FAULT); +} - /* Advance the buffer head */ - dispatch_q->head = CMDQUEUE_NEXT(dispatch_q->head, - ADRENO_DISPATCH_CMDQUEUE_SIZE); +static int adreno_dispatch_process_cmdqueue(struct adreno_device *adreno_dev, + struct adreno_dispatcher_cmdqueue *cmdqueue) +{ + int count = adreno_dispatch_retire_cmdqueue(adreno_dev, cmdqueue); - /* Destroy the retired command batch */ - kgsl_cmdbatch_destroy(cmdbatch); + /* Nothing to do if there are no pending commands */ + if (adreno_cmdqueue_is_empty(cmdqueue)) + return count; - /* Update the expire time for the next command batch */ + /* Don't update the cmdqueue timeout if we are about to preempt out */ + if (!adreno_in_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE)) + return count; - if (dispatch_q->inflight > 0 && - dispatch_q == active_q) { - cmdbatch = - dispatch_q->cmd_q[dispatch_q->head]; - cmdbatch->expires = jiffies + - msecs_to_jiffies( - adreno_cmdbatch_timeout); - } + /* Don't update the cmdqueue timeout if it isn't active */ + if (!cmdqueue_is_current(cmdqueue)) + return count; - count++; - continue; - } - /* - * Break here if fault detection is disabled for the context or - * if the long running IB detection is disaled device wide or - * if the dispatch q is not active - * Long running command buffers will be allowed to run to - * completion - but badly behaving command buffers (infinite - * shaders etc) can end up running forever. - */ + /* + * If the current ringbuffer retired any commands then universally + * reset the timeout + */ - if (!long_ib_detect || - drawctxt->base.flags & KGSL_CONTEXT_NO_FAULT_TOLERANCE - || dispatch_q != active_q) - break; + if (count) { + cmdqueue->expires = jiffies + + msecs_to_jiffies(adreno_cmdbatch_timeout); + return count; + } - /* - * The last line of defense is to check if the command batch has - * timed out. If we get this far but the timeout hasn't expired - * yet then the GPU is still ticking away - */ + /* + * If we get here then 1) the ringbuffer is current and 2) we haven't + * retired anything. Check to see if the timeout if valid for the + * current cmdbatch and fault if it has expired + */ + _adreno_dispatch_check_timeout(adreno_dev, cmdqueue); + return 0; +} - if (time_is_after_jiffies(cmdbatch->expires)) - break; +/* Update the dispatcher timers */ +static void _dispatcher_update_timers(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; - /* Boom goes the dynamite */ + /* Kick the idle timer */ + mutex_lock(&device->mutex); + kgsl_pwrscale_update(device); + mod_timer(&device->idle_timer, + jiffies + device->pwrctrl.interval_timeout); + mutex_unlock(&device->mutex); - pr_context(KGSL_DEVICE(adreno_dev), cmdbatch->context, - "gpu timeout ctx %d ts %d\n", - cmdbatch->context->id, cmdbatch->timestamp); + /* Check to see if we need to update the command timer */ + if (adreno_in_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE)) { + struct adreno_dispatcher_cmdqueue *cmdqueue = + CMDQUEUE(adreno_dev->cur_rb); - adreno_set_gpu_fault(adreno_dev, ADRENO_TIMEOUT_FAULT); - break; + if (!adreno_cmdqueue_is_empty(cmdqueue)) + mod_timer(&dispatcher->timer, cmdqueue->expires); } - return count; } -/** - * adreno_dispatcher_work() - Master work handler for the dispatcher - * @work: Pointer to the work struct for the current work queue - * - * Process expired commands and send new ones. - */ +/* Take down the dispatcher and release any power states */ +static void _dispatcher_power_down(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher; + + mutex_lock(&device->mutex); + + if (test_and_clear_bit(ADRENO_DISPATCHER_ACTIVE, &dispatcher->priv)) + complete_all(&dispatcher->idle_gate); + + del_timer_sync(&dispatcher->fault_timer); + + if (test_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv)) { + kgsl_active_count_put(device); + clear_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv); + } + + mutex_unlock(&device->mutex); +} + static void adreno_dispatcher_work(struct work_struct *work) { struct adreno_dispatcher *dispatcher = @@ -2095,95 +2081,50 @@ static void adreno_dispatcher_work(struct work_struct *work) struct kgsl_device *device = KGSL_DEVICE(adreno_dev); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); int count = 0; - int cur_rb_id = adreno_dev->cur_rb->id; + unsigned int i = 0; mutex_lock(&dispatcher->mutex); - if (ADRENO_DISPATCHER_PREEMPT_CLEAR == - atomic_read(&dispatcher->preemption_state)) - /* process the active q*/ - count = adreno_dispatch_process_cmdqueue(adreno_dev, - &(adreno_dev->cur_rb->dispatch_q), - adreno_long_ib_detect(adreno_dev)); - - else if (ADRENO_DISPATCHER_PREEMPT_TRIGGERED == - atomic_read(&dispatcher->preemption_state)) - count = adreno_dispatch_process_cmdqueue(adreno_dev, - &(adreno_dev->cur_rb->dispatch_q), 0); - - /* Check if gpu fault occurred */ - if (dispatcher_do_fault(adreno_dev)) - goto done; - - if (gpudev->preemption_schedule) - gpudev->preemption_schedule(adreno_dev); - - if (cur_rb_id != adreno_dev->cur_rb->id) { - struct adreno_dispatcher_cmdqueue *dispatch_q = - &(adreno_dev->cur_rb->dispatch_q); - /* active level switched, clear new level cmdbatches */ - count = adreno_dispatch_process_cmdqueue(adreno_dev, - dispatch_q, - adreno_long_ib_detect(adreno_dev)); - /* - * If GPU has already completed all the commands in new incoming - * RB then we may not get another interrupt due to which - * dispatcher may not run again. Schedule dispatcher here so - * we can come back and process the other RB's if required - */ - if (dispatch_q->head == dispatch_q->tail) - adreno_dispatcher_schedule(device); - } /* - * If inflight went to 0, queue back up the event processor to catch - * stragglers + * As long as there are inflight commands, process retired comamnds from + * all cmdqueues */ - if (dispatcher->inflight == 0 && count) - kgsl_schedule_work(&device->event_work); - - /* Try to dispatch new commands */ - _adreno_dispatcher_issuecmds(adreno_dev); - -done: - /* Either update the timer for the next command batch or disable it */ - if (dispatcher->inflight) { - struct kgsl_cmdbatch *cmdbatch = - adreno_dev->cur_rb->dispatch_q.cmd_q[ - adreno_dev->cur_rb->dispatch_q.head]; - if (cmdbatch && adreno_preempt_state(adreno_dev, - ADRENO_DISPATCHER_PREEMPT_CLEAR)) - /* Update the timeout timer for the next cmdbatch */ - mod_timer(&dispatcher->timer, cmdbatch->expires); - - /* There are still things in flight - update the idle counts */ - mutex_lock(&device->mutex); - kgsl_pwrscale_update(device); - mod_timer(&device->idle_timer, jiffies + - device->pwrctrl.interval_timeout); - mutex_unlock(&device->mutex); - } else { - /* There is nothing left in the pipeline. Shut 'er down boys */ - mutex_lock(&device->mutex); + for (i = 0; i < adreno_dev->num_ringbuffers; i++) { + struct adreno_dispatcher_cmdqueue *cmdqueue = + CMDQUEUE(&adreno_dev->ringbuffers[i]); - if (test_and_clear_bit(ADRENO_DISPATCHER_ACTIVE, - &dispatcher->priv)) - complete_all(&dispatcher->idle_gate); + count += adreno_dispatch_process_cmdqueue(adreno_dev, + cmdqueue); + if (dispatcher->inflight == 0) + break; + } - /* - * Stop the fault timer before decrementing the active count to - * avoid reading the hardware registers while we are trying to - * turn clocks off - */ - del_timer_sync(&dispatcher->fault_timer); + /* + * dispatcher_do_fault() returns 0 if no faults occurred. If that is the + * case, then clean up preemption and try to schedule more work + */ + if (dispatcher_do_fault(adreno_dev) == 0) { + /* Clean up after preemption */ + if (gpudev->preemption_schedule) + gpudev->preemption_schedule(adreno_dev); - if (test_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv)) { - kgsl_active_count_put(device); - clear_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv); - } + /* Re-kick the event engine to catch stragglers */ + if (dispatcher->inflight == 0 && count != 0) + kgsl_schedule_work(&device->event_work); - mutex_unlock(&device->mutex); + /* Run the scheduler for to dispatch new commands */ + _adreno_dispatcher_issuecmds(adreno_dev); } + /* + * If there are commands pending, update the timers, otherwise release + * the power state to prepare for power down + */ + if (dispatcher->inflight > 0) + _dispatcher_update_timers(adreno_dev); + else + _dispatcher_power_down(adreno_dev); + mutex_unlock(&dispatcher->mutex); } @@ -2305,7 +2246,7 @@ void adreno_dispatcher_close(struct adreno_device *adreno_dev) FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { struct adreno_dispatcher_cmdqueue *dispatch_q = &(rb->dispatch_q); - while (dispatch_q->head != dispatch_q->tail) { + while (!adreno_cmdqueue_is_empty(dispatch_q)) { kgsl_cmdbatch_destroy( dispatch_q->cmd_q[dispatch_q->head]); dispatch_q->head = (dispatch_q->head + 1) @@ -2395,9 +2336,9 @@ static DISPATCHER_UINT_ATTR(fault_throttle_burst, 0644, 0, static DISPATCHER_UINT_ATTR(disp_preempt_fair_sched, 0644, 0, adreno_disp_preempt_fair_sched); static DISPATCHER_UINT_ATTR(dispatch_time_slice, 0644, 0, - _dispatch_time_slice); + adreno_dispatch_time_slice); static DISPATCHER_UINT_ATTR(dispatch_starvation_time, 0644, 0, - _dispatch_starvation_time); + adreno_dispatch_starvation_time); static struct attribute *dispatcher_attrs[] = { &dispatcher_attr_inflight.attr, @@ -2474,9 +2415,6 @@ int adreno_dispatcher_init(struct adreno_device *adreno_dev) setup_timer(&dispatcher->fault_timer, adreno_dispatcher_fault_timer, (unsigned long) adreno_dev); - setup_timer(&dispatcher->preempt_timer, adreno_dispatcher_preempt_timer, - (unsigned long) adreno_dev); - INIT_WORK(&dispatcher->work, adreno_dispatcher_work); init_completion(&dispatcher->idle_gate); @@ -2485,9 +2423,6 @@ int adreno_dispatcher_init(struct adreno_device *adreno_dev) plist_head_init(&dispatcher->pending); spin_lock_init(&dispatcher->plist_lock); - atomic_set(&dispatcher->preemption_state, - ADRENO_DISPATCHER_PREEMPT_CLEAR); - ret = kobject_init_and_add(&dispatcher->kobj, &ktype_dispatcher, &device->dev->kobj, "dispatch"); @@ -2544,49 +2479,3 @@ int adreno_dispatcher_idle(struct adreno_device *adreno_dev) adreno_dispatcher_schedule(device); return ret; } - -void adreno_preempt_process_dispatch_queue(struct adreno_device *adreno_dev, - struct adreno_dispatcher_cmdqueue *dispatch_q) -{ - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - struct kgsl_cmdbatch *cmdbatch; - - if (dispatch_q->head != dispatch_q->tail) { - /* - * retire cmdbacthes from previous q, and don't check for - * timeout since the cmdbatch may have been preempted - */ - adreno_dispatch_process_cmdqueue(adreno_dev, - dispatch_q, 0); - } - - /* set the timer for the first cmdbatch of active dispatch_q */ - dispatch_q = &(adreno_dev->cur_rb->dispatch_q); - if (dispatch_q->head != dispatch_q->tail) { - cmdbatch = dispatch_q->cmd_q[dispatch_q->head]; - cmdbatch->expires = jiffies + - msecs_to_jiffies(adreno_cmdbatch_timeout); - } - kgsl_schedule_work(&device->event_work); -} - -/** - * adreno_dispatcher_preempt_callback() - Callback funcion for CP_SW interrupt - * @adreno_dev: The device on which the interrupt occurred - * @bit: Interrupt bit in the interrupt status register - */ -void adreno_dispatcher_preempt_callback(struct adreno_device *adreno_dev, - int bit) -{ - struct adreno_dispatcher *dispatcher = &(adreno_dev->dispatcher); - - if (ADRENO_DISPATCHER_PREEMPT_TRIGGERED != - atomic_read(&dispatcher->preemption_state)) - return; - - trace_adreno_hw_preempt_trig_to_comp_int(adreno_dev->cur_rb, - adreno_dev->next_rb); - atomic_set(&dispatcher->preemption_state, - ADRENO_DISPATCHER_PREEMPT_COMPLETE); - adreno_dispatcher_schedule(KGSL_DEVICE(adreno_dev)); -} diff --git a/drivers/gpu/msm/adreno_dispatch.h b/drivers/gpu/msm/adreno_dispatch.h index 308d5b936819..699c3e4adb27 100644 --- a/drivers/gpu/msm/adreno_dispatch.h +++ b/drivers/gpu/msm/adreno_dispatch.h @@ -11,29 +11,13 @@ * */ - #ifndef ____ADRENO_DISPATCHER_H #define ____ADRENO_DISPATCHER_H -/* Time to allow preemption to complete (in ms) */ -#define ADRENO_DISPATCH_PREEMPT_TIMEOUT 10000 - extern unsigned int adreno_disp_preempt_fair_sched; extern unsigned int adreno_cmdbatch_timeout; - -/** - * enum adreno_dispatcher_preempt_states - States of dispatcher for ringbuffer - * preemption - * @ADRENO_DISPATCHER_PREEMPT_CLEAR: No preemption is underway, - * only 1 preemption can be underway at any point - * @ADRENO_DISPATCHER_PREEMPT_TRIGGERED: A preemption is underway - * @ADRENO_DISPATCHER_PREEMPT_COMPLETE: A preemption has just completed - */ -enum adreno_dispatcher_preempt_states { - ADRENO_DISPATCHER_PREEMPT_CLEAR = 0, - ADRENO_DISPATCHER_PREEMPT_TRIGGERED, - ADRENO_DISPATCHER_PREEMPT_COMPLETE, -}; +extern unsigned int adreno_dispatch_starvation_time; +extern unsigned int adreno_dispatch_time_slice; /** * enum adreno_dispatcher_starve_timer_states - Starvation control states of @@ -71,6 +55,7 @@ enum adreno_dispatcher_starve_timer_states { * @head: Head pointer to the q * @tail: Queues tail pointer * @active_context_count: Number of active contexts seen in this rb cmdqueue + * @expires: The jiffies value at which this cmdqueue has run too long */ struct adreno_dispatcher_cmdqueue { struct kgsl_cmdbatch *cmd_q[ADRENO_DISPATCH_CMDQUEUE_SIZE]; @@ -78,6 +63,7 @@ struct adreno_dispatcher_cmdqueue { unsigned int head; unsigned int tail; int active_context_count; + unsigned long expires; }; /** @@ -92,11 +78,6 @@ struct adreno_dispatcher_cmdqueue { * @work: work_struct to put the dispatcher in a work queue * @kobj: kobject for the dispatcher directory in the device sysfs node * @idle_gate: Gate to wait on for dispatcher to idle - * @preemption_state: Indicated what state the dispatcher is in, states are - * defined by enum adreno_dispatcher_preempt_states - * @preempt_token_submit: Indicates if a preempt token has been subnitted in - * current ringbuffer. - * @preempt_timer: Timer to track if preemption occured within specified time * @disp_preempt_fair_sched: If set then dispatcher will try to be fair to * starving RB's by scheduling them in and enforcing a minimum time slice * for every RB that is scheduled to run on the device @@ -113,9 +94,6 @@ struct adreno_dispatcher { struct work_struct work; struct kobject kobj; struct completion idle_gate; - atomic_t preemption_state; - int preempt_token_submit; - struct timer_list preempt_timer; unsigned int disp_preempt_fair_sched; }; @@ -141,12 +119,12 @@ void adreno_dispatcher_queue_context(struct kgsl_device *device, struct adreno_context *drawctxt); void adreno_dispatcher_preempt_callback(struct adreno_device *adreno_dev, int bit); -struct adreno_ringbuffer *adreno_dispatcher_get_highest_busy_rb( - struct adreno_device *adreno_dev); -int adreno_dispatch_process_cmdqueue(struct adreno_device *adreno_dev, - struct adreno_dispatcher_cmdqueue *dispatch_q, - int long_ib_detect); void adreno_preempt_process_dispatch_queue(struct adreno_device *adreno_dev, struct adreno_dispatcher_cmdqueue *dispatch_q); +static inline bool adreno_cmdqueue_is_empty( + struct adreno_dispatcher_cmdqueue *cmdqueue) +{ + return (cmdqueue != NULL && cmdqueue->head == cmdqueue->tail); +} #endif /* __ADRENO_DISPATCHER_H */ diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c index d8498d938b6a..fb95f6108fb8 100644 --- a/drivers/gpu/msm/adreno_drawctxt.c +++ b/drivers/gpu/msm/adreno_drawctxt.c @@ -346,7 +346,8 @@ adreno_drawctxt_create(struct kgsl_device_private *dev_priv, KGSL_CONTEXT_PWR_CONSTRAINT | KGSL_CONTEXT_IFH_NOP | KGSL_CONTEXT_SECURE | - KGSL_CONTEXT_PREEMPT_STYLE_MASK); + KGSL_CONTEXT_PREEMPT_STYLE_MASK | + KGSL_CONTEXT_NO_SNAPSHOT); /* Check for errors before trying to initialize */ @@ -466,20 +467,6 @@ void adreno_drawctxt_detach(struct kgsl_context *context) list_del_init(&drawctxt->active_node); spin_unlock(&adreno_dev->active_list_lock); - /* deactivate context */ - mutex_lock(&device->mutex); - if (rb->drawctxt_active == drawctxt) { - if (adreno_dev->cur_rb == rb) { - if (!kgsl_active_count_get(device)) { - adreno_drawctxt_switch(adreno_dev, rb, NULL, 0); - kgsl_active_count_put(device); - } else - BUG(); - } else - adreno_drawctxt_switch(adreno_dev, rb, NULL, 0); - } - mutex_unlock(&device->mutex); - spin_lock(&drawctxt->lock); count = drawctxt_detach_cmdbatches(drawctxt, list); spin_unlock(&drawctxt->lock); @@ -548,12 +535,21 @@ void adreno_drawctxt_destroy(struct kgsl_context *context) kfree(drawctxt); } +static void _drawctxt_switch_wait_callback(struct kgsl_device *device, + struct kgsl_event_group *group, + void *priv, int result) +{ + struct adreno_context *drawctxt = (struct adreno_context *) priv; + + kgsl_context_put(&drawctxt->base); +} + /** * adreno_drawctxt_switch - switch the current draw context in a given RB * @adreno_dev - The 3D device that owns the context * @rb: The ringubffer pointer on which the current context is being changed * @drawctxt - the 3D context to switch to - * @flags - Flags to accompany the switch (from user space) + * @flags: Control flags for the switch * * Switch the current draw context in given RB */ @@ -583,8 +579,7 @@ int adreno_drawctxt_switch(struct adreno_device *adreno_dev, if (drawctxt != NULL && kgsl_context_detached(&drawctxt->base)) return -ENOENT; - trace_adreno_drawctxt_switch(rb, - drawctxt, flags); + trace_adreno_drawctxt_switch(rb, drawctxt); /* Get a refcount to the new instance */ if (drawctxt) { @@ -596,16 +591,18 @@ int adreno_drawctxt_switch(struct adreno_device *adreno_dev, /* No context - set the default pagetable and thats it. */ new_pt = device->mmu.defaultpagetable; } - ret = adreno_ringbuffer_set_pt_ctx(rb, new_pt, drawctxt); - if (ret) { - KGSL_DRV_ERR(device, - "Failed to set pagetable on rb %d\n", rb->id); + ret = adreno_ringbuffer_set_pt_ctx(rb, new_pt, drawctxt, flags); + if (ret) return ret; - } - /* Put the old instance of the active drawctxt */ - if (rb->drawctxt_active) - kgsl_context_put(&rb->drawctxt_active->base); + if (rb->drawctxt_active) { + /* Wait for the timestamp to expire */ + if (kgsl_add_event(device, &rb->events, rb->timestamp, + _drawctxt_switch_wait_callback, + rb->drawctxt_active)) { + kgsl_context_put(&rb->drawctxt_active->base); + } + } rb->drawctxt_active = drawctxt; return 0; diff --git a/drivers/gpu/msm/adreno_drawctxt.h b/drivers/gpu/msm/adreno_drawctxt.h index 7e80247e9322..5ea911954991 100644 --- a/drivers/gpu/msm/adreno_drawctxt.h +++ b/drivers/gpu/msm/adreno_drawctxt.h @@ -104,6 +104,9 @@ enum adreno_context_priv { ADRENO_CONTEXT_SKIP_CMD, }; +/* Flags for adreno_drawctxt_switch() */ +#define ADRENO_CONTEXT_SWITCH_FORCE_GPU BIT(0) + struct kgsl_context *adreno_drawctxt_create(struct kgsl_device_private *, uint32_t *flags); diff --git a/drivers/gpu/msm/adreno_ioctl.c b/drivers/gpu/msm/adreno_ioctl.c index 519087a77b83..0d5e3e094c36 100644 --- a/drivers/gpu/msm/adreno_ioctl.c +++ b/drivers/gpu/msm/adreno_ioctl.c @@ -103,7 +103,7 @@ static long adreno_ioctl_preemption_counters_query( levels_to_copy = gpudev->num_prio_levels; if (copy_to_user((void __user *) (uintptr_t) read->counters, - adreno_dev->preemption_counters.hostptr, + adreno_dev->preempt.counters.hostptr, levels_to_copy * size_level)) return -EFAULT; diff --git a/drivers/gpu/msm/adreno_iommu.c b/drivers/gpu/msm/adreno_iommu.c index 2eeda01b3c4d..aa00dcb84185 100644 --- a/drivers/gpu/msm/adreno_iommu.c +++ b/drivers/gpu/msm/adreno_iommu.c @@ -275,6 +275,7 @@ static bool _ctx_switch_use_cpu_path( struct adreno_ringbuffer *rb) { struct kgsl_mmu *mmu = KGSL_MMU(adreno_dev); + /* * If rb is current, we can use cpu path when GPU is * idle and we are switching to default pt. @@ -284,7 +285,7 @@ static bool _ctx_switch_use_cpu_path( if (adreno_dev->cur_rb == rb) return adreno_isidle(KGSL_DEVICE(adreno_dev)) && (new_pt == mmu->defaultpagetable); - else if ((rb->wptr == rb->rptr) && + else if (adreno_rb_empty(rb) && (new_pt == mmu->defaultpagetable)) return true; @@ -360,8 +361,7 @@ static unsigned int _adreno_mmu_set_pt_update_condition( */ *cmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 1); cmds += cp_gpuaddr(adreno_dev, cmds, (rb->pagetable_desc.gpuaddr + - offsetof(struct adreno_ringbuffer_pagetable_info, - switch_pt_enable))); + PT_INFO_OFFSET(switch_pt_enable))); *cmds++ = 1; *cmds++ = cp_packet(adreno_dev, CP_WAIT_MEM_WRITES, 1); *cmds++ = 0; @@ -375,14 +375,11 @@ static unsigned int _adreno_mmu_set_pt_update_condition( *cmds++ = (1 << 8) | (1 << 4) | 3; cmds += cp_gpuaddr(adreno_dev, cmds, (adreno_dev->ringbuffers[0].pagetable_desc.gpuaddr + - offsetof(struct adreno_ringbuffer_pagetable_info, - current_global_ptname))); + PT_INFO_OFFSET(current_global_ptname))); *cmds++ = ptname; *cmds++ = 0xFFFFFFFF; - cmds += cp_gpuaddr(adreno_dev, cmds, - (rb->pagetable_desc.gpuaddr + - offsetof(struct adreno_ringbuffer_pagetable_info, - switch_pt_enable))); + cmds += cp_gpuaddr(adreno_dev, cmds, (rb->pagetable_desc.gpuaddr + + PT_INFO_OFFSET(switch_pt_enable))); *cmds++ = 0; *cmds++ = cp_packet(adreno_dev, CP_WAIT_MEM_WRITES, 1); *cmds++ = 0; @@ -406,23 +403,18 @@ static unsigned int _adreno_iommu_pt_update_pid_to_mem( unsigned int *cmds_orig = cmds; *cmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 1); - cmds += cp_gpuaddr(adreno_dev, cmds, - (rb->pagetable_desc.gpuaddr + - offsetof(struct adreno_ringbuffer_pagetable_info, - current_rb_ptname))); + cmds += cp_gpuaddr(adreno_dev, cmds, (rb->pagetable_desc.gpuaddr + + PT_INFO_OFFSET(current_rb_ptname))); *cmds++ = ptname; *cmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 1); cmds += cp_gpuaddr(adreno_dev, cmds, - (adreno_dev->ringbuffers[0].pagetable_desc.gpuaddr + - offsetof(struct adreno_ringbuffer_pagetable_info, - current_global_ptname))); + (adreno_dev->ringbuffers[0].pagetable_desc.gpuaddr + + PT_INFO_OFFSET(current_global_ptname))); *cmds++ = ptname; /* pagetable switch done, Housekeeping: set the switch_pt_enable to 0 */ *cmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 1); - cmds += cp_gpuaddr(adreno_dev, cmds, - (rb->pagetable_desc.gpuaddr + - offsetof(struct adreno_ringbuffer_pagetable_info, - switch_pt_enable))); + cmds += cp_gpuaddr(adreno_dev, cmds, (rb->pagetable_desc.gpuaddr + + PT_INFO_OFFSET(switch_pt_enable))); *cmds++ = 0; *cmds++ = cp_packet(adreno_dev, CP_WAIT_MEM_WRITES, 1); *cmds++ = 0; @@ -444,14 +436,10 @@ static unsigned int _adreno_iommu_set_pt_v1(struct adreno_ringbuffer *rb, /* set flag that indicates whether pt switch is required*/ cmds += _adreno_mmu_set_pt_update_condition(rb, cmds, ptname); *cmds++ = cp_mem_packet(adreno_dev, CP_COND_EXEC, 4, 2); - cmds += cp_gpuaddr(adreno_dev, cmds, - (rb->pagetable_desc.gpuaddr + - offsetof(struct adreno_ringbuffer_pagetable_info, - switch_pt_enable))); - cmds += cp_gpuaddr(adreno_dev, cmds, - (rb->pagetable_desc.gpuaddr + - offsetof(struct adreno_ringbuffer_pagetable_info, - switch_pt_enable))); + cmds += cp_gpuaddr(adreno_dev, cmds, (rb->pagetable_desc.gpuaddr + + PT_INFO_OFFSET(switch_pt_enable))); + cmds += cp_gpuaddr(adreno_dev, cmds, (rb->pagetable_desc.gpuaddr + + PT_INFO_OFFSET(switch_pt_enable))); *cmds++ = 1; /* Exec count to be filled later */ cond_exec_ptr = cmds; @@ -566,7 +554,7 @@ static unsigned int _adreno_iommu_set_pt_v2_a5xx(struct kgsl_device *device, *cmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 4, 1); cmds += cp_gpuaddr(adreno_dev, cmds, (rb->pagetable_desc.gpuaddr + - offsetof(struct adreno_ringbuffer_pagetable_info, ttbr0))); + PT_INFO_OFFSET(ttbr0))); *cmds++ = lower_32_bits(ttbr0); *cmds++ = upper_32_bits(ttbr0); *cmds++ = contextidr; @@ -651,14 +639,14 @@ static unsigned int __add_curr_ctxt_cmds(struct adreno_ringbuffer *rb, *cmds++ = KGSL_CONTEXT_TO_MEM_IDENTIFIER; *cmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 1); - cmds += cp_gpuaddr(adreno_dev, cmds, device->memstore.gpuaddr + - KGSL_MEMSTORE_RB_OFFSET(rb, current_context)); + cmds += cp_gpuaddr(adreno_dev, cmds, + MEMSTORE_RB_GPU_ADDR(device, rb, current_context)); *cmds++ = (drawctxt ? drawctxt->base.id : 0); *cmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 1); - cmds += cp_gpuaddr(adreno_dev, cmds, device->memstore.gpuaddr + - KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, - current_context)); + cmds += cp_gpuaddr(adreno_dev, cmds, + MEMSTORE_ID_GPU_ADDR(device, + KGSL_MEMSTORE_GLOBAL, current_context)); *cmds++ = (drawctxt ? drawctxt->base.id : 0); /* Invalidate UCHE for new context */ @@ -706,7 +694,7 @@ static void _set_ctxt_cpu(struct adreno_ringbuffer *rb, } /* Update rb memstore with current context */ kgsl_sharedmem_writel(device, &device->memstore, - KGSL_MEMSTORE_RB_OFFSET(rb, current_context), + MEMSTORE_RB_OFFSET(rb, current_context), drawctxt ? drawctxt->base.id : 0); } @@ -746,26 +734,11 @@ static int _set_pagetable_cpu(struct adreno_ringbuffer *rb, if (result) return result; /* write the new pt set to memory var */ - kgsl_sharedmem_writel(device, - &adreno_dev->ringbuffers[0].pagetable_desc, - offsetof( - struct adreno_ringbuffer_pagetable_info, - current_global_ptname), new_pt->name); + adreno_ringbuffer_set_global(adreno_dev, new_pt->name); } /* Update the RB pagetable info here */ - kgsl_sharedmem_writel(device, &rb->pagetable_desc, - offsetof( - struct adreno_ringbuffer_pagetable_info, - current_rb_ptname), new_pt->name); - kgsl_sharedmem_writeq(device, &rb->pagetable_desc, - offsetof( - struct adreno_ringbuffer_pagetable_info, - ttbr0), kgsl_mmu_pagetable_get_ttbr0(new_pt)); - kgsl_sharedmem_writel(device, &rb->pagetable_desc, - offsetof( - struct adreno_ringbuffer_pagetable_info, - contextidr), kgsl_mmu_pagetable_get_contextidr(new_pt)); + adreno_ringbuffer_set_pagetable(rb, new_pt); return 0; } @@ -795,8 +768,6 @@ static int _set_pagetable_gpu(struct adreno_ringbuffer *rb, return 0; } - kgsl_mmu_enable_clk(KGSL_MMU(adreno_dev)); - cmds += adreno_iommu_set_pt_generate_cmds(rb, cmds, new_pt); if ((unsigned int) (cmds - link) > (PAGE_SIZE / sizeof(unsigned int))) { @@ -812,16 +783,6 @@ static int _set_pagetable_gpu(struct adreno_ringbuffer *rb, KGSL_CMD_FLAGS_PMODE, link, (unsigned int)(cmds - link)); - /* - * On error disable the IOMMU clock right away otherwise turn it off - * after the command has been retired - */ - if (result) - kgsl_mmu_disable_clk(KGSL_MMU(adreno_dev)); - else - adreno_ringbuffer_mmu_disable_clk_on_ts(KGSL_DEVICE(adreno_dev), - rb, rb->timestamp); - kfree(link); return result; } @@ -886,7 +847,8 @@ int adreno_iommu_init(struct adreno_device *adreno_dev) */ int adreno_iommu_set_pt_ctx(struct adreno_ringbuffer *rb, struct kgsl_pagetable *new_pt, - struct adreno_context *drawctxt) + struct adreno_context *drawctxt, + unsigned long flags) { struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb); struct kgsl_device *device = KGSL_DEVICE(adreno_dev); @@ -897,7 +859,8 @@ int adreno_iommu_set_pt_ctx(struct adreno_ringbuffer *rb, if (rb->drawctxt_active) cur_pt = rb->drawctxt_active->base.proc_priv->pagetable; - cpu_path = _ctx_switch_use_cpu_path(adreno_dev, new_pt, rb); + cpu_path = !(flags & ADRENO_CONTEXT_SWITCH_FORCE_GPU) && + _ctx_switch_use_cpu_path(adreno_dev, new_pt, rb); /* Pagetable switch */ if (new_pt != cur_pt) { @@ -907,10 +870,8 @@ int adreno_iommu_set_pt_ctx(struct adreno_ringbuffer *rb, result = _set_pagetable_gpu(rb, new_pt); } - if (result) { - KGSL_DRV_ERR(device, "Error switching pagetable %d\n", result); + if (result) return result; - } /* Context switch */ if (cpu_path) @@ -918,8 +879,5 @@ int adreno_iommu_set_pt_ctx(struct adreno_ringbuffer *rb, else result = _set_ctxt_gpu(rb, drawctxt); - if (result) - KGSL_DRV_ERR(device, "Error switching context %d\n", result); - return result; } diff --git a/drivers/gpu/msm/adreno_iommu.h b/drivers/gpu/msm/adreno_iommu.h index c557c65bb4c9..5a6c2c549370 100644 --- a/drivers/gpu/msm/adreno_iommu.h +++ b/drivers/gpu/msm/adreno_iommu.h @@ -17,7 +17,8 @@ #ifdef CONFIG_QCOM_KGSL_IOMMU int adreno_iommu_set_pt_ctx(struct adreno_ringbuffer *rb, struct kgsl_pagetable *new_pt, - struct adreno_context *drawctxt); + struct adreno_context *drawctxt, + unsigned long flags); int adreno_iommu_init(struct adreno_device *adreno_dev); @@ -33,7 +34,8 @@ static inline int adreno_iommu_init(struct adreno_device *adreno_dev) static inline int adreno_iommu_set_pt_ctx(struct adreno_ringbuffer *rb, struct kgsl_pagetable *new_pt, - struct adreno_context *drawctxt) + struct adreno_context *drawctxt, + unsigned long flags) { return 0; } diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c index dceb8fb93461..0160939e97f9 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -30,8 +30,6 @@ #include "a3xx_reg.h" #include "adreno_a5xx.h" -#define GSL_RB_NOP_SIZEDWORDS 2 - #define RB_HOSTPTR(_rb, _pos) \ ((unsigned int *) ((_rb)->buffer_desc.hostptr + \ ((_pos) * sizeof(unsigned int)))) @@ -50,86 +48,89 @@ static void _cff_write_ringbuffer(struct adreno_ringbuffer *rb) if (device->cff_dump_enable == 0) return; - /* - * This code is predicated on the fact that we write a full block of - * stuff without wrapping - */ - BUG_ON(rb->wptr < rb->last_wptr); - - size = (rb->wptr - rb->last_wptr) * sizeof(unsigned int); + size = (rb->_wptr - rb->last_wptr) * sizeof(unsigned int); hostptr = RB_HOSTPTR(rb, rb->last_wptr); gpuaddr = RB_GPUADDR(rb, rb->last_wptr); kgsl_cffdump_memcpy(device, gpuaddr, hostptr, size); + rb->last_wptr = rb->_wptr; } -void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb, +static void adreno_get_submit_time(struct adreno_device *adreno_dev, struct adreno_submit_time *time) { - struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb); - BUG_ON(rb->wptr == 0); - - /* Write the changes to CFF if so enabled */ - _cff_write_ringbuffer(rb); - + unsigned long flags; /* - * Read the current GPU ticks and wallclock for most accurate - * profiling + * Here we are attempting to create a mapping between the + * GPU time domain (alwayson counter) and the CPU time domain + * (local_clock) by sampling both values as close together as + * possible. This is useful for many types of debugging and + * profiling. In order to make this mapping as accurate as + * possible, we must turn off interrupts to avoid running + * interrupt handlers between the two samples. */ - if (time != NULL) { - /* - * Here we are attempting to create a mapping between the - * GPU time domain (alwayson counter) and the CPU time domain - * (local_clock) by sampling both values as close together as - * possible. This is useful for many types of debugging and - * profiling. In order to make this mapping as accurate as - * possible, we must turn off interrupts to avoid running - * interrupt handlers between the two samples. - */ - unsigned long flags; - local_irq_save(flags); + local_irq_save(flags); - /* Read always on registers */ - if (!adreno_is_a3xx(adreno_dev)) { - adreno_readreg64(adreno_dev, - ADRENO_REG_RBBM_ALWAYSON_COUNTER_LO, - ADRENO_REG_RBBM_ALWAYSON_COUNTER_HI, - &time->ticks); + /* Read always on registers */ + if (!adreno_is_a3xx(adreno_dev)) { + adreno_readreg64(adreno_dev, + ADRENO_REG_RBBM_ALWAYSON_COUNTER_LO, + ADRENO_REG_RBBM_ALWAYSON_COUNTER_HI, + &time->ticks); - /* - * Mask hi bits as they may be incorrect on - * a4x and some a5x - */ - if (ADRENO_GPUREV(adreno_dev) >= 400 && + /* Mask hi bits as they may be incorrect on some targets */ + if (ADRENO_GPUREV(adreno_dev) >= 400 && ADRENO_GPUREV(adreno_dev) <= ADRENO_REV_A530) - time->ticks &= 0xFFFFFFFF; - } - else - time->ticks = 0; + time->ticks &= 0xFFFFFFFF; + } else + time->ticks = 0; - /* Get the kernel clock for time since boot */ - time->ktime = local_clock(); + /* Get the kernel clock for time since boot */ + time->ktime = local_clock(); - /* Get the timeofday for the wall time (for the user) */ - getnstimeofday(&time->utime); + /* Get the timeofday for the wall time (for the user) */ + getnstimeofday(&time->utime); - local_irq_restore(flags); - } + local_irq_restore(flags); +} + +void adreno_ringbuffer_wptr(struct adreno_device *adreno_dev, + struct adreno_ringbuffer *rb) +{ + unsigned long flags; - /* Memory barrier before informing the hardware of new commands */ - mb(); + spin_lock_irqsave(&rb->preempt_lock, flags); + if (adreno_in_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE)) { - if (adreno_preempt_state(adreno_dev, ADRENO_DISPATCHER_PREEMPT_CLEAR) && - (adreno_dev->cur_rb == rb)) { - /* - * Let the pwrscale policy know that new commands have - * been submitted. - */ - kgsl_pwrscale_busy(KGSL_DEVICE(adreno_dev)); - adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR, rb->wptr); + if (adreno_dev->cur_rb == rb) { + /* + * Let the pwrscale policy know that new commands have + * been submitted. + */ + kgsl_pwrscale_busy(KGSL_DEVICE(adreno_dev)); + adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_WPTR, + rb->_wptr); + } } + + rb->wptr = rb->_wptr; + spin_unlock_irqrestore(&rb->preempt_lock, flags); +} + +void adreno_ringbuffer_submit(struct adreno_ringbuffer *rb, + struct adreno_submit_time *time) +{ + struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb); + + /* Write the changes to CFF if so enabled */ + _cff_write_ringbuffer(rb); + + if (time != NULL) + adreno_get_submit_time(adreno_dev, time); + + adreno_ringbuffer_wptr(adreno_dev, rb); } int adreno_ringbuffer_submit_spin(struct adreno_ringbuffer *rb, @@ -141,125 +142,36 @@ int adreno_ringbuffer_submit_spin(struct adreno_ringbuffer *rb, return adreno_spin_idle(adreno_dev, timeout); } -static int -adreno_ringbuffer_waitspace(struct adreno_ringbuffer *rb, - unsigned int numcmds, int wptr_ahead) +unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb, + unsigned int dwords) { - int nopcount = 0; - unsigned int freecmds; - unsigned int wptr = rb->wptr; - unsigned int *cmds = NULL; - uint64_t gpuaddr; - unsigned long wait_time; - unsigned long wait_timeout = msecs_to_jiffies(ADRENO_IDLE_TIMEOUT); - unsigned int rptr; struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb); + unsigned int rptr = adreno_get_rptr(rb); + unsigned int ret; - /* if wptr ahead, fill the remaining with NOPs */ - if (wptr_ahead) { - /* -1 for header */ - nopcount = KGSL_RB_DWORDS - rb->wptr - 1; - - cmds = RB_HOSTPTR(rb, rb->wptr); - gpuaddr = RB_GPUADDR(rb, rb->wptr); - - rptr = adreno_get_rptr(rb); - /* For non current rb we don't expect the rptr to move */ - if ((adreno_dev->cur_rb != rb || - !adreno_preempt_state(adreno_dev, - ADRENO_DISPATCHER_PREEMPT_CLEAR)) && - !rptr) - return -ENOSPC; - - /* Make sure that rptr is not 0 before submitting - * commands at the end of ringbuffer. We do not - * want the rptr and wptr to become equal when - * the ringbuffer is not empty */ - wait_time = jiffies + wait_timeout; - while (!rptr) { - rptr = adreno_get_rptr(rb); - if (time_after(jiffies, wait_time)) - return -ETIMEDOUT; - } - - rb->wptr = 0; - } - - rptr = adreno_get_rptr(rb); - freecmds = rptr - rb->wptr; - if (freecmds == 0 || freecmds > numcmds) - goto done; + if (rptr <= rb->_wptr) { + unsigned int *cmds; - /* non current rptr will not advance anyway or if preemption underway */ - if (adreno_dev->cur_rb != rb || - !adreno_preempt_state(adreno_dev, - ADRENO_DISPATCHER_PREEMPT_CLEAR)) { - rb->wptr = wptr; - return -ENOSPC; - } - - wait_time = jiffies + wait_timeout; - /* wait for space in ringbuffer */ - while (1) { - rptr = adreno_get_rptr(rb); - - freecmds = rptr - rb->wptr; - - if (freecmds == 0 || freecmds > numcmds) - break; - - if (time_after(jiffies, wait_time)) { - KGSL_DRV_ERR(KGSL_DEVICE(adreno_dev), - "Timed out waiting for freespace in RB rptr: 0x%x, wptr: 0x%x, rb id %d\n", - rptr, wptr, rb->id); - return -ETIMEDOUT; + if (rb->_wptr + dwords <= (KGSL_RB_DWORDS - 2)) { + ret = rb->_wptr; + rb->_wptr = (rb->_wptr + dwords) % KGSL_RB_DWORDS; + return RB_HOSTPTR(rb, ret); } - } -done: - if (wptr_ahead) { - *cmds = cp_packet(adreno_dev, CP_NOP, nopcount); - kgsl_cffdump_write(KGSL_DEVICE(adreno_dev), gpuaddr, *cmds); - } - return 0; -} + cmds = RB_HOSTPTR(rb, rb->_wptr); + *cmds = cp_packet(adreno_dev, CP_NOP, + KGSL_RB_DWORDS - rb->_wptr - 1); -unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb, - unsigned int numcmds) -{ - unsigned int *ptr = NULL; - int ret = 0; - unsigned int rptr; - BUG_ON(numcmds >= KGSL_RB_DWORDS); - - rptr = adreno_get_rptr(rb); - /* check for available space */ - if (rb->wptr >= rptr) { - /* wptr ahead or equal to rptr */ - /* reserve dwords for nop packet */ - if ((rb->wptr + numcmds) > (KGSL_RB_DWORDS - - GSL_RB_NOP_SIZEDWORDS)) - ret = adreno_ringbuffer_waitspace(rb, numcmds, 1); - } else { - /* wptr behind rptr */ - if ((rb->wptr + numcmds) >= rptr) - ret = adreno_ringbuffer_waitspace(rb, numcmds, 0); - /* check for remaining space */ - /* reserve dwords for nop packet */ - if (!ret && (rb->wptr + numcmds) > (KGSL_RB_DWORDS - - GSL_RB_NOP_SIZEDWORDS)) - ret = adreno_ringbuffer_waitspace(rb, numcmds, 1); + rb->_wptr = 0; } - if (!ret) { - rb->last_wptr = rb->wptr; - - ptr = (unsigned int *)rb->buffer_desc.hostptr + rb->wptr; - rb->wptr += numcmds; - } else - ptr = ERR_PTR(ret); + if (rb->_wptr + dwords < rptr) { + ret = rb->_wptr; + rb->_wptr = (rb->_wptr + dwords) % KGSL_RB_DWORDS; + return RB_HOSTPTR(rb, ret); + } - return ptr; + return ERR_PTR(-ENOSPC); } /** @@ -279,8 +191,10 @@ int adreno_ringbuffer_start(struct adreno_device *adreno_dev, FOR_EACH_RINGBUFFER(adreno_dev, rb, i) { kgsl_sharedmem_set(device, &(rb->buffer_desc), 0, 0xAA, KGSL_RB_SIZE); + kgsl_sharedmem_writel(device, &device->scratch, + SCRATCH_RPTR_OFFSET(rb->id), 0); rb->wptr = 0; - rb->rptr = 0; + rb->_wptr = 0; rb->wptr_preempt_end = 0xFFFFFFFF; rb->starve_timer_state = ADRENO_DISPATCHER_RB_STARVE_TIMER_UNINIT; @@ -322,6 +236,8 @@ static int _adreno_ringbuffer_probe(struct adreno_device *adreno_dev, rb->timestamp = 0; init_waitqueue_head(&rb->ts_expire_waitq); + spin_lock_init(&rb->preempt_lock); + /* * Allocate mem for storing RB pagetables and commands to * switch pagetable @@ -433,6 +349,18 @@ int cp_secure_mode(struct adreno_device *adreno_dev, uint *cmds, return cmds - start; } +static inline int cp_mem_write(struct adreno_device *adreno_dev, + unsigned int *cmds, uint64_t gpuaddr, unsigned int value) +{ + int dwords = 0; + + cmds[dwords++] = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 1); + dwords += cp_gpuaddr(adreno_dev, &cmds[dwords], gpuaddr); + cmds[dwords++] = value; + + return dwords; +} + static int adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, unsigned int flags, unsigned int *cmds, @@ -446,18 +374,20 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, unsigned int total_sizedwords = sizedwords; unsigned int i; unsigned int context_id = 0; - uint64_t gpuaddr = device->memstore.gpuaddr; bool profile_ready; struct adreno_context *drawctxt = rb->drawctxt_active; struct kgsl_context *context = NULL; bool secured_ctxt = false; - uint64_t cond_addr; static unsigned int _seq_cnt; if (drawctxt != NULL && kgsl_context_detached(&drawctxt->base) && !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) return -ENOENT; + /* On fault return error so that we don't keep submitting */ + if (adreno_gpu_fault(adreno_dev) != 0) + return -EPROTO; + rb->timestamp++; /* If this is a internal IB, use the global timestamp for it */ @@ -529,7 +459,7 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, * required in ringbuffer and adjust the write pointer depending on * gpucore at the end of this function. */ - total_sizedwords += 4; /* sop timestamp */ + total_sizedwords += 8; /* sop timestamp */ total_sizedwords += 5; /* eop timestamp */ if (drawctxt && !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) { @@ -564,14 +494,9 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, *ringcmds++ = KGSL_CMD_IDENTIFIER; if (adreno_is_preemption_enabled(adreno_dev) && - gpudev->preemption_pre_ibsubmit) { - cond_addr = device->memstore.gpuaddr + - KGSL_MEMSTORE_OFFSET(context_id, - preempted); + gpudev->preemption_pre_ibsubmit) ringcmds += gpudev->preemption_pre_ibsubmit( - adreno_dev, rb, ringcmds, context, - cond_addr, NULL); - } + adreno_dev, rb, ringcmds, context); if (flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE) { *ringcmds++ = cp_packet(adreno_dev, CP_NOP, 1); @@ -601,16 +526,15 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, adreno_profile_preib_processing(adreno_dev, drawctxt, &flags, &ringcmds); - /* start-of-pipeline timestamp */ - *ringcmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 1); + /* start-of-pipeline timestamp for the context */ if (drawctxt && !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) - ringcmds += cp_gpuaddr(adreno_dev, ringcmds, - gpuaddr + KGSL_MEMSTORE_OFFSET(context_id, - soptimestamp)); - else - ringcmds += cp_gpuaddr(adreno_dev, ringcmds, - gpuaddr + KGSL_MEMSTORE_RB_OFFSET(rb, soptimestamp)); - *ringcmds++ = timestamp; + ringcmds += cp_mem_write(adreno_dev, ringcmds, + MEMSTORE_ID_GPU_ADDR(device, context_id, soptimestamp), + timestamp); + + /* start-of-pipeline timestamp for the ringbuffer */ + ringcmds += cp_mem_write(adreno_dev, ringcmds, + MEMSTORE_RB_GPU_ADDR(device, rb, soptimestamp), rb->timestamp); if (secured_ctxt) ringcmds += cp_secure_mode(adreno_dev, ringcmds, 1); @@ -659,11 +583,9 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, * early detection of timestamp interrupt storms to stave * off system collapse. */ - *ringcmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 1); - ringcmds += cp_gpuaddr(adreno_dev, ringcmds, gpuaddr + - KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL, - ref_wait_ts)); - *ringcmds++ = ++_seq_cnt; + ringcmds += cp_mem_write(adreno_dev, ringcmds, + MEMSTORE_ID_GPU_ADDR(device, KGSL_MEMSTORE_GLOBAL, + ref_wait_ts), ++_seq_cnt); /* * end-of-pipeline timestamp. If per context timestamps is not @@ -677,16 +599,17 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, *ringcmds++ = CACHE_FLUSH_TS; if (drawctxt && !(flags & KGSL_CMD_FLAGS_INTERNAL_ISSUE)) { - ringcmds += cp_gpuaddr(adreno_dev, ringcmds, gpuaddr + - KGSL_MEMSTORE_OFFSET(context_id, eoptimestamp)); + ringcmds += cp_gpuaddr(adreno_dev, ringcmds, + MEMSTORE_ID_GPU_ADDR(device, context_id, eoptimestamp)); *ringcmds++ = timestamp; - *ringcmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 1); - ringcmds += cp_gpuaddr(adreno_dev, ringcmds, gpuaddr + - KGSL_MEMSTORE_RB_OFFSET(rb, eoptimestamp)); - *ringcmds++ = rb->timestamp; + + /* Write the end of pipeline timestamp to the ringbuffer too */ + ringcmds += cp_mem_write(adreno_dev, ringcmds, + MEMSTORE_RB_GPU_ADDR(device, rb, eoptimestamp), + rb->timestamp); } else { - ringcmds += cp_gpuaddr(adreno_dev, ringcmds, gpuaddr + - KGSL_MEMSTORE_RB_OFFSET(rb, eoptimestamp)); + ringcmds += cp_gpuaddr(adreno_dev, ringcmds, + MEMSTORE_RB_GPU_ADDR(device, rb, eoptimestamp)); *ringcmds++ = timestamp; } @@ -707,8 +630,8 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, if (gpudev->preemption_post_ibsubmit && adreno_is_preemption_enabled(adreno_dev)) - ringcmds += gpudev->preemption_post_ibsubmit(adreno_dev, rb, - ringcmds, &drawctxt->base); + ringcmds += gpudev->preemption_post_ibsubmit(adreno_dev, + ringcmds); /* * If we have more ringbuffer commands than space reserved @@ -722,7 +645,7 @@ adreno_ringbuffer_addcmds(struct adreno_ringbuffer *rb, * required. If we have commands less than the space reserved in RB * adjust the wptr accordingly. */ - rb->wptr = rb->wptr - (total_sizedwords - (ringcmds - start)); + rb->_wptr = rb->_wptr - (total_sizedwords - (ringcmds - start)); adreno_ringbuffer_submit(rb, time); @@ -1063,14 +986,24 @@ int adreno_ringbuffer_submitcmd(struct adreno_device *adreno_dev, *cmds++ = cp_packet(adreno_dev, CP_NOP, 1); *cmds++ = KGSL_END_OF_IB_IDENTIFIER; - ret = adreno_drawctxt_switch(adreno_dev, rb, drawctxt, cmdbatch->flags); + /* Context switches commands should *always* be on the GPU */ + ret = adreno_drawctxt_switch(adreno_dev, rb, drawctxt, + ADRENO_CONTEXT_SWITCH_FORCE_GPU); /* * In the unlikely event of an error in the drawctxt switch, * treat it like a hang */ - if (ret) + if (ret) { + /* + * It is "normal" to get a -ENOSPC or a -ENOENT. Don't log it, + * the upper layers know how to handle it + */ + if (ret != -ENOSPC && ret != -ENOENT) + KGSL_DRV_ERR(device, + "Unable to switch draw context: %d\n", ret); goto done; + } if (test_bit(CMDBATCH_FLAG_WFI, &cmdbatch->priv)) flags = KGSL_CMD_FLAGS_WFI; @@ -1138,44 +1071,6 @@ done: } /** - * adreno_ringbuffer_mmu_clk_disable_event() - Callback function that - * disables the MMU clocks. - * @device: Device pointer - * @context: The ringbuffer context pointer - * @data: Pointer containing the adreno_mmu_disable_clk_param structure - * @type: The event call type (RETIRED or CANCELLED) - */ -static void adreno_ringbuffer_mmu_clk_disable_event(struct kgsl_device *device, - struct kgsl_event_group *group, void *data, int type) -{ - kgsl_mmu_disable_clk(&device->mmu); -} - -/* - * adreno_ringbuffer_mmu_disable_clk_on_ts() - Sets up event to disable MMU - * clocks - * @device - The kgsl device pointer - * @rb: The ringbuffer in whose event list the event is added - * @timestamp: The timestamp on which the event should trigger - * - * Creates an event to disable the MMU clocks on timestamp and if event - * already exists then updates the timestamp of disabling the MMU clocks - * with the passed in ts if it is greater than the current value at which - * the clocks will be disabled - * Return - void - */ -void -adreno_ringbuffer_mmu_disable_clk_on_ts(struct kgsl_device *device, - struct adreno_ringbuffer *rb, unsigned int timestamp) -{ - if (kgsl_add_event(device, &(rb->events), timestamp, - adreno_ringbuffer_mmu_clk_disable_event, NULL)) { - KGSL_DRV_ERR(device, - "Failed to add IOMMU disable clk event\n"); - } -} - -/** * adreno_ringbuffer_wait_callback() - Callback function for event registered * on a ringbuffer timestamp * @device: Device for which the the callback is valid diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h index f1980fd92961..b126f710b5e6 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.h +++ b/drivers/gpu/msm/adreno_ringbuffer.h @@ -73,13 +73,16 @@ struct adreno_ringbuffer_pagetable_info { unsigned int contextidr; }; +#define PT_INFO_OFFSET(_field) \ + offsetof(struct adreno_ringbuffer_pagetable_info, _field) + /** * struct adreno_ringbuffer - Definition for an adreno ringbuffer object * @flags: Internal control flags for the ringbuffer - * @buffer_desc: Pointer to the ringbuffer memory descriptor - * @wptr: Local copy of the wptr offset - * @rptr: Read pointer offset in dwords from baseaddr - * @last_wptr: offset of the last H/W committed wptr + * @buffer_desc: Pointer to the ringbuffer memory descripto + * @_wptr: The next value of wptr to be written to the hardware on submit + * @wptr: Local copy of the wptr offset last written to hardware + * @last_wptr: offset of the last wptr that was written to CFF * @rb_ctx: The context that represents a ringbuffer * @id: Priority level of the ringbuffer, also used as an ID * @fault_detect_ts: The last retired global timestamp read during fault detect @@ -101,12 +104,13 @@ struct adreno_ringbuffer_pagetable_info { * @sched_timer: Timer that tracks how long RB has been waiting to be scheduled * or how long it has been scheduled for after preempting in * @starve_timer_state: Indicates the state of the wait. + * @preempt_lock: Lock to protect the wptr pointer while it is being updated */ struct adreno_ringbuffer { uint32_t flags; struct kgsl_memdesc buffer_desc; + unsigned int _wptr; unsigned int wptr; - unsigned int rptr; unsigned int last_wptr; int id; unsigned int fault_detect_ts; @@ -122,14 +126,12 @@ struct adreno_ringbuffer { int preempted_midway; unsigned long sched_timer; enum adreno_dispatcher_starve_timer_states starve_timer_state; + spinlock_t preempt_lock; }; /* Returns the current ringbuffer */ #define ADRENO_CURRENT_RINGBUFFER(a) ((a)->cur_rb) -#define KGSL_MEMSTORE_RB_OFFSET(rb, field) \ - KGSL_MEMSTORE_OFFSET((rb->id + KGSL_MEMSTORE_MAX), field) - int cp_secure_mode(struct adreno_device *adreno_dev, uint *cmds, int set); int adreno_ringbuffer_issueibcmds(struct kgsl_device_private *dev_priv, @@ -170,9 +172,6 @@ void adreno_ringbuffer_read_pfp_ucode(struct kgsl_device *device); void adreno_ringbuffer_read_pm4_ucode(struct kgsl_device *device); -void adreno_ringbuffer_mmu_disable_clk_on_ts(struct kgsl_device *device, - struct adreno_ringbuffer *rb, unsigned int ts); - int adreno_ringbuffer_waittimestamp(struct adreno_ringbuffer *rb, unsigned int timestamp, unsigned int msecs); @@ -204,9 +203,10 @@ static inline unsigned int adreno_ringbuffer_dec_wrapped(unsigned int val, } static inline int adreno_ringbuffer_set_pt_ctx(struct adreno_ringbuffer *rb, - struct kgsl_pagetable *pt, struct adreno_context *context) + struct kgsl_pagetable *pt, struct adreno_context *context, + unsigned long flags) { - return adreno_iommu_set_pt_ctx(rb, pt, context); + return adreno_iommu_set_pt_ctx(rb, pt, context, flags); } #endif /* __ADRENO_RINGBUFFER_H */ diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c index ca61d36a1384..b069b16c75ef 100644 --- a/drivers/gpu/msm/adreno_snapshot.c +++ b/drivers/gpu/msm/adreno_snapshot.c @@ -467,7 +467,7 @@ static size_t snapshot_rb(struct kgsl_device *device, u8 *buf, header->start = 0; header->end = KGSL_RB_DWORDS; header->wptr = rb->wptr; - header->rptr = rb->rptr; + header->rptr = adreno_get_rptr(rb); header->rbsize = KGSL_RB_DWORDS; header->count = KGSL_RB_DWORDS; adreno_rb_readtimestamp(adreno_dev, rb, KGSL_TIMESTAMP_QUEUED, @@ -741,8 +741,7 @@ static size_t snapshot_global(struct kgsl_device *device, u8 *buf, header->size = memdesc->size >> 2; header->gpuaddr = memdesc->gpuaddr; - header->ptbase = - kgsl_mmu_pagetable_get_ttbr0(device->mmu.defaultpagetable); + header->ptbase = MMU_DEFAULT_TTBR0(device); header->type = SNAPSHOT_GPU_OBJECT_GLOBAL; memcpy(ptr, memdesc->hostptr, memdesc->size); diff --git a/drivers/gpu/msm/adreno_trace.h b/drivers/gpu/msm/adreno_trace.h index 5f1bbb9a83b3..f52ddfa894d5 100644 --- a/drivers/gpu/msm/adreno_trace.h +++ b/drivers/gpu/msm/adreno_trace.h @@ -55,8 +55,8 @@ TRACE_EVENT(adreno_cmdbatch_queued, TRACE_EVENT(adreno_cmdbatch_submitted, TP_PROTO(struct kgsl_cmdbatch *cmdbatch, int inflight, uint64_t ticks, unsigned long secs, unsigned long usecs, - struct adreno_ringbuffer *rb), - TP_ARGS(cmdbatch, inflight, ticks, secs, usecs, rb), + struct adreno_ringbuffer *rb, unsigned int rptr), + TP_ARGS(cmdbatch, inflight, ticks, secs, usecs, rb, rptr), TP_STRUCT__entry( __field(unsigned int, id) __field(unsigned int, timestamp) @@ -81,7 +81,7 @@ TRACE_EVENT(adreno_cmdbatch_submitted, __entry->usecs = usecs; __entry->prio = cmdbatch->context->priority; __entry->rb_id = rb->id; - __entry->rptr = rb->rptr; + __entry->rptr = rptr; __entry->wptr = rb->wptr; __entry->q_inflight = rb->dispatch_q.inflight; ), @@ -100,8 +100,8 @@ TRACE_EVENT(adreno_cmdbatch_submitted, TRACE_EVENT(adreno_cmdbatch_retired, TP_PROTO(struct kgsl_cmdbatch *cmdbatch, int inflight, uint64_t start, uint64_t retire, - struct adreno_ringbuffer *rb), - TP_ARGS(cmdbatch, inflight, start, retire, rb), + struct adreno_ringbuffer *rb, unsigned int rptr), + TP_ARGS(cmdbatch, inflight, start, retire, rb, rptr), TP_STRUCT__entry( __field(unsigned int, id) __field(unsigned int, timestamp) @@ -126,7 +126,7 @@ TRACE_EVENT(adreno_cmdbatch_retired, __entry->retire = retire; __entry->prio = cmdbatch->context->priority; __entry->rb_id = rb->id; - __entry->rptr = rb->rptr; + __entry->rptr = rptr; __entry->wptr = rb->wptr; __entry->q_inflight = rb->dispatch_q.inflight; ), @@ -267,9 +267,8 @@ TRACE_EVENT(adreno_drawctxt_wait_done, TRACE_EVENT(adreno_drawctxt_switch, TP_PROTO(struct adreno_ringbuffer *rb, - struct adreno_context *newctx, - unsigned int flags), - TP_ARGS(rb, newctx, flags), + struct adreno_context *newctx), + TP_ARGS(rb, newctx), TP_STRUCT__entry( __field(int, rb_level) __field(unsigned int, oldctx) @@ -283,8 +282,8 @@ TRACE_EVENT(adreno_drawctxt_switch, __entry->newctx = newctx ? newctx->base.id : 0; ), TP_printk( - "rb level=%d oldctx=%u newctx=%u flags=%X", - __entry->rb_level, __entry->oldctx, __entry->newctx, flags + "rb level=%d oldctx=%u newctx=%u", + __entry->rb_level, __entry->oldctx, __entry->newctx ) ); @@ -427,8 +426,9 @@ TRACE_EVENT(kgsl_a5xx_irq_status, DECLARE_EVENT_CLASS(adreno_hw_preempt_template, TP_PROTO(struct adreno_ringbuffer *cur_rb, - struct adreno_ringbuffer *new_rb), - TP_ARGS(cur_rb, new_rb), + struct adreno_ringbuffer *new_rb, + unsigned int cur_rptr, unsigned int new_rptr), + TP_ARGS(cur_rb, new_rb, cur_rptr, new_rptr), TP_STRUCT__entry(__field(int, cur_level) __field(int, new_level) __field(unsigned int, cur_rptr) @@ -440,8 +440,8 @@ DECLARE_EVENT_CLASS(adreno_hw_preempt_template, ), TP_fast_assign(__entry->cur_level = cur_rb->id; __entry->new_level = new_rb->id; - __entry->cur_rptr = cur_rb->rptr; - __entry->new_rptr = new_rb->rptr; + __entry->cur_rptr = cur_rptr; + __entry->new_rptr = new_rptr; __entry->cur_wptr = cur_rb->wptr; __entry->new_wptr = new_rb->wptr; __entry->cur_rbbase = cur_rb->buffer_desc.gpuaddr; @@ -458,26 +458,30 @@ DECLARE_EVENT_CLASS(adreno_hw_preempt_template, DEFINE_EVENT(adreno_hw_preempt_template, adreno_hw_preempt_clear_to_trig, TP_PROTO(struct adreno_ringbuffer *cur_rb, - struct adreno_ringbuffer *new_rb), - TP_ARGS(cur_rb, new_rb) + struct adreno_ringbuffer *new_rb, + unsigned int cur_rptr, unsigned int new_rptr), + TP_ARGS(cur_rb, new_rb, cur_rptr, new_rptr) ); DEFINE_EVENT(adreno_hw_preempt_template, adreno_hw_preempt_trig_to_comp, TP_PROTO(struct adreno_ringbuffer *cur_rb, - struct adreno_ringbuffer *new_rb), - TP_ARGS(cur_rb, new_rb) + struct adreno_ringbuffer *new_rb, + unsigned int cur_rptr, unsigned int new_rptr), + TP_ARGS(cur_rb, new_rb, cur_rptr, new_rptr) ); DEFINE_EVENT(adreno_hw_preempt_template, adreno_hw_preempt_trig_to_comp_int, TP_PROTO(struct adreno_ringbuffer *cur_rb, - struct adreno_ringbuffer *new_rb), - TP_ARGS(cur_rb, new_rb) + struct adreno_ringbuffer *new_rb, + unsigned int cur_rptr, unsigned int new_rptr), + TP_ARGS(cur_rb, new_rb, cur_rptr, new_rptr) ); TRACE_EVENT(adreno_hw_preempt_comp_to_clear, TP_PROTO(struct adreno_ringbuffer *cur_rb, - struct adreno_ringbuffer *new_rb), - TP_ARGS(cur_rb, new_rb), + struct adreno_ringbuffer *new_rb, + unsigned int cur_rptr, unsigned int new_rptr), + TP_ARGS(cur_rb, new_rb, cur_rptr, new_rptr), TP_STRUCT__entry(__field(int, cur_level) __field(int, new_level) __field(unsigned int, cur_rptr) @@ -490,8 +494,8 @@ TRACE_EVENT(adreno_hw_preempt_comp_to_clear, ), TP_fast_assign(__entry->cur_level = cur_rb->id; __entry->new_level = new_rb->id; - __entry->cur_rptr = cur_rb->rptr; - __entry->new_rptr = new_rb->rptr; + __entry->cur_rptr = cur_rptr; + __entry->new_rptr = new_rptr; __entry->cur_wptr = cur_rb->wptr; __entry->new_wptr_end = new_rb->wptr_preempt_end; __entry->new_wptr = new_rb->wptr; @@ -509,8 +513,9 @@ TRACE_EVENT(adreno_hw_preempt_comp_to_clear, TRACE_EVENT(adreno_hw_preempt_token_submit, TP_PROTO(struct adreno_ringbuffer *cur_rb, - struct adreno_ringbuffer *new_rb), - TP_ARGS(cur_rb, new_rb), + struct adreno_ringbuffer *new_rb, + unsigned int cur_rptr, unsigned int new_rptr), + TP_ARGS(cur_rb, new_rb, cur_rptr, new_rptr), TP_STRUCT__entry(__field(int, cur_level) __field(int, new_level) __field(unsigned int, cur_rptr) @@ -523,8 +528,8 @@ TRACE_EVENT(adreno_hw_preempt_token_submit, ), TP_fast_assign(__entry->cur_level = cur_rb->id; __entry->new_level = new_rb->id; - __entry->cur_rptr = cur_rb->rptr; - __entry->new_rptr = new_rb->rptr; + __entry->cur_rptr = cur_rptr; + __entry->new_rptr = new_rptr; __entry->cur_wptr = cur_rb->wptr; __entry->cur_wptr_end = cur_rb->wptr_preempt_end; __entry->new_wptr = new_rb->wptr; @@ -541,23 +546,37 @@ TRACE_EVENT(adreno_hw_preempt_token_submit, ) ); -TRACE_EVENT(adreno_rb_starve, - TP_PROTO(struct adreno_ringbuffer *rb), - TP_ARGS(rb), - TP_STRUCT__entry(__field(int, id) - __field(unsigned int, rptr) - __field(unsigned int, wptr) +TRACE_EVENT(adreno_preempt_trigger, + TP_PROTO(struct adreno_ringbuffer *cur, struct adreno_ringbuffer *next), + TP_ARGS(cur, next), + TP_STRUCT__entry( + __field(struct adreno_ringbuffer *, cur) + __field(struct adreno_ringbuffer *, next) ), - TP_fast_assign(__entry->id = rb->id; - __entry->rptr = rb->rptr; - __entry->wptr = rb->wptr; + TP_fast_assign( + __entry->cur = cur; + __entry->next = next; ), - TP_printk( - "rb %d r/w %x/%x starved", __entry->id, __entry->rptr, - __entry->wptr + TP_printk("trigger from id=%d to id=%d", + __entry->cur->id, __entry->next->id ) ); +TRACE_EVENT(adreno_preempt_done, + TP_PROTO(struct adreno_ringbuffer *cur, struct adreno_ringbuffer *next), + TP_ARGS(cur, next), + TP_STRUCT__entry( + __field(struct adreno_ringbuffer *, cur) + __field(struct adreno_ringbuffer *, next) + ), + TP_fast_assign( + __entry->cur = cur; + __entry->next = next; + ), + TP_printk("done switch to id=%d from id=%d", + __entry->next->id, __entry->cur->id + ) +); #endif /* _ADRENO_TRACE_H */ /* This part must be outside protection */ diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 2563591f376e..f77dbb7f20af 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -233,6 +233,8 @@ int kgsl_readtimestamp(struct kgsl_device *device, void *priv, } EXPORT_SYMBOL(kgsl_readtimestamp); +static long gpumem_free_entry(struct kgsl_mem_entry *entry); + /* Scheduled by kgsl_mem_entry_put_deferred() */ static void _deferred_put(struct work_struct *work) { @@ -247,10 +249,8 @@ kgsl_mem_entry_create(void) { struct kgsl_mem_entry *entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (entry != NULL) { + if (entry != NULL) kref_init(&entry->refcount); - INIT_WORK(&entry->work, _deferred_put); - } return entry; } @@ -1150,6 +1150,8 @@ static int kgsl_open_device(struct kgsl_device *device) atomic_inc(&device->active_cnt); kgsl_sharedmem_set(device, &device->memstore, 0, 0, device->memstore.size); + kgsl_sharedmem_set(device, &device->scratch, 0, 0, + device->scratch.size); result = device->ftbl->init(device); if (result) @@ -1855,7 +1857,10 @@ static long gpuobj_free_on_timestamp(struct kgsl_device_private *dev_priv, static void gpuobj_free_fence_func(void *priv) { - kgsl_mem_entry_put_deferred((struct kgsl_mem_entry *) priv); + struct kgsl_mem_entry *entry = priv; + + INIT_WORK(&entry->work, _deferred_put); + queue_work(kgsl_driver.mem_workqueue, &entry->work); } static long gpuobj_free_on_fence(struct kgsl_device_private *dev_priv, @@ -3910,11 +3915,13 @@ int kgsl_device_platform_probe(struct kgsl_device *device) status = kgsl_allocate_global(device, &device->memstore, KGSL_MEMSTORE_SIZE, 0, 0); - if (status != 0) { - KGSL_DRV_ERR(device, "kgsl_allocate_global failed %d\n", - status); + if (status != 0) goto error_close_mmu; - } + + status = kgsl_allocate_global(device, &device->scratch, + PAGE_SIZE, 0, 0); + if (status != 0) + goto error_free_memstore; /* * The default request type PM_QOS_REQ_ALL_CORES is @@ -3964,6 +3971,8 @@ int kgsl_device_platform_probe(struct kgsl_device *device) return 0; +error_free_memstore: + kgsl_free_global(device, &device->memstore); error_close_mmu: kgsl_mmu_close(device); error_pwrctrl_close: @@ -3990,6 +3999,8 @@ void kgsl_device_platform_remove(struct kgsl_device *device) idr_destroy(&device->context_idr); + kgsl_free_global(device, &device->scratch); + kgsl_free_global(device, &device->memstore); kgsl_mmu_close(device); @@ -4091,8 +4102,9 @@ static int __init kgsl_core_init(void) INIT_LIST_HEAD(&kgsl_driver.pagetable_list); kgsl_driver.workqueue = create_singlethread_workqueue("kgsl-workqueue"); - kgsl_driver.mem_workqueue = - create_singlethread_workqueue("kgsl-mementry"); + + kgsl_driver.mem_workqueue = alloc_workqueue("kgsl-mementry", + WQ_UNBOUND | WQ_MEM_RECLAIM, 0); kgsl_events_init(); diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index dfe83be799b3..c172021c8944 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -37,6 +37,32 @@ #define KGSL_MEMSTORE_MAX (KGSL_MEMSTORE_SIZE / \ sizeof(struct kgsl_devmemstore) - 1 - KGSL_PRIORITY_MAX_RB_LEVELS) +#define MEMSTORE_RB_OFFSET(rb, field) \ + KGSL_MEMSTORE_OFFSET(((rb)->id + KGSL_MEMSTORE_MAX), field) + +#define MEMSTORE_ID_GPU_ADDR(dev, iter, field) \ + ((dev)->memstore.gpuaddr + KGSL_MEMSTORE_OFFSET(iter, field)) + +#define MEMSTORE_RB_GPU_ADDR(dev, rb, field) \ + ((dev)->memstore.gpuaddr + \ + KGSL_MEMSTORE_OFFSET(((rb)->id + KGSL_MEMSTORE_MAX), field)) + +/* + * SCRATCH MEMORY: The scratch memory is one page worth of data that + * is mapped into the GPU. This allows for some 'shared' data between + * the GPU and CPU. For example, it will be used by the GPU to write + * each updated RPTR for each RB. + * + * Used Data: + * Offset: Length(bytes): What + * 0x0: 4 * KGSL_PRIORITY_MAX_RB_LEVELS: RB0 RPTR + */ + +/* Shadow global helpers */ +#define SCRATCH_RPTR_OFFSET(id) ((id) * sizeof(unsigned int)) +#define SCRATCH_RPTR_GPU_ADDR(dev, id) \ + ((dev)->scratch.gpuaddr + SCRATCH_RPTR_OFFSET(id)) + /* Timestamp window used to detect rollovers (half of integer range) */ #define KGSL_TIMESTAMP_WINDOW 0x80000000 @@ -447,21 +473,6 @@ kgsl_mem_entry_put(struct kgsl_mem_entry *entry) kref_put(&entry->refcount, kgsl_mem_entry_destroy); } -/** - * kgsl_mem_entry_put_deferred() - Schedule a task to put the memory entry - * @entry: Mem entry to put - * - * This function is for atomic contexts where a normal kgsl_mem_entry_put() - * would result in the memory entry getting destroyed and possibly taking - * mutexes along the way. Schedule the work to happen outside of the atomic - * context. - */ -static inline void kgsl_mem_entry_put_deferred(struct kgsl_mem_entry *entry) -{ - if (entry != NULL) - queue_work(kgsl_driver.mem_workqueue, &entry->work); -} - /* * kgsl_addr_range_overlap() - Checks if 2 ranges overlap * @gpuaddr1: Start of first address range diff --git a/drivers/gpu/msm/kgsl_cmdbatch.h b/drivers/gpu/msm/kgsl_cmdbatch.h index 1547ac02fdbf..d5cbf375b5d3 100644 --- a/drivers/gpu/msm/kgsl_cmdbatch.h +++ b/drivers/gpu/msm/kgsl_cmdbatch.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -31,7 +31,6 @@ * @fault_policy: Internal policy describing how to handle this command in case * of a fault * @fault_recovery: recovery actions actually tried for this batch - * @expires: Point in time when the cmdbatch is considered to be hung * @refcount: kref structure to maintain the reference count * @cmdlist: List of IBs to issue * @memlist: List of all memory used in this command batch @@ -61,7 +60,6 @@ struct kgsl_cmdbatch { unsigned long priv; unsigned long fault_policy; unsigned long fault_recovery; - unsigned long expires; struct kref refcount; struct list_head cmdlist; struct list_head memlist; diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index c3fb2b81fcbd..4159a5fe375f 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -227,6 +227,7 @@ struct kgsl_device { /* GPU shader memory size */ unsigned int shader_mem_len; struct kgsl_memdesc memstore; + struct kgsl_memdesc scratch; const char *iomemname; const char *shadermemname; diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c index e1f9ad17d0ff..6f70b9ddd376 100644 --- a/drivers/gpu/msm/kgsl_events.c +++ b/drivers/gpu/msm/kgsl_events.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -56,6 +56,23 @@ static void _kgsl_event_worker(struct work_struct *work) kmem_cache_free(events_cache, event); } +/* return true if the group needs to be processed */ +static bool _do_process_group(unsigned int processed, unsigned int cur) +{ + if (processed == cur) + return false; + + /* + * This ensures that the timestamp didn't slip back accidently, maybe + * due to a memory barrier issue. This is highly unlikely but we've + * been burned here in the past. + */ + if ((cur < processed) && ((processed - cur) < KGSL_TIMESTAMP_WINDOW)) + return false; + + return true; +} + static void _process_event_group(struct kgsl_device *device, struct kgsl_event_group *group, bool flush) { @@ -80,11 +97,7 @@ static void _process_event_group(struct kgsl_device *device, group->readtimestamp(device, group->priv, KGSL_TIMESTAMP_RETIRED, ×tamp); - /* - * If no timestamps have been retired since the last time we were here - * then we can avoid going through this loop - */ - if (!flush && timestamp_cmp(timestamp, group->processed) <= 0) + if (!flush && _do_process_group(group->processed, timestamp) == false) goto out; list_for_each_entry_safe(event, tmp, &group->events, node) { diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index a338559ac0bb..103d290eb681 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -220,9 +220,6 @@ static int _attach_pt(struct kgsl_iommu_pt *iommu_pt, if (ret == 0) iommu_pt->attached = true; - else - KGSL_CORE_ERR("iommu_attach_device(%s) failed: %d\n", - ctx->name, ret); return ret; } @@ -1452,25 +1449,25 @@ done: return ret; } +static int kgsl_iommu_set_pt(struct kgsl_mmu *mmu, struct kgsl_pagetable *pt); + static int kgsl_iommu_start(struct kgsl_mmu *mmu) { int status; struct kgsl_iommu *iommu = _IOMMU_PRIV(mmu); - struct kgsl_iommu_context *ctx = &iommu->ctx[KGSL_IOMMU_CONTEXT_USER]; status = _setup_user_context(mmu); if (status) return status; status = _setup_secure_context(mmu); - if (status) + if (status) { _detach_context(&iommu->ctx[KGSL_IOMMU_CONTEXT_USER]); - else { - kgsl_iommu_enable_clk(mmu); - KGSL_IOMMU_SET_CTX_REG(ctx, TLBIALL, 1); - kgsl_iommu_disable_clk(mmu); + return status; } - return status; + + /* Make sure the hardware is programmed to the default pagetable */ + return kgsl_iommu_set_pt(mmu, mmu->defaultpagetable); } static int @@ -1707,23 +1704,15 @@ kgsl_iommu_get_current_ttbr0(struct kgsl_mmu *mmu) * * Return - void */ -static int kgsl_iommu_set_pt(struct kgsl_mmu *mmu, - struct kgsl_pagetable *pt) +static int kgsl_iommu_set_pt(struct kgsl_mmu *mmu, struct kgsl_pagetable *pt) { - struct kgsl_device *device = KGSL_MMU_DEVICE(mmu); struct kgsl_iommu *iommu = _IOMMU_PRIV(mmu); struct kgsl_iommu_context *ctx = &iommu->ctx[KGSL_IOMMU_CONTEXT_USER]; - int ret = 0; uint64_t ttbr0, temp; unsigned int contextidr; unsigned long wait_for_flush; - /* - * If using a global pagetable, we can skip all this - * because the pagetable will be set up by the iommu - * driver and never changed at runtime. - */ - if (!kgsl_mmu_is_perprocess(mmu)) + if ((pt != mmu->defaultpagetable) && !kgsl_mmu_is_perprocess(mmu)) return 0; kgsl_iommu_enable_clk(mmu); @@ -1731,14 +1720,6 @@ static int kgsl_iommu_set_pt(struct kgsl_mmu *mmu, ttbr0 = kgsl_mmu_pagetable_get_ttbr0(pt); contextidr = kgsl_mmu_pagetable_get_contextidr(pt); - /* - * Taking the liberty to spin idle since this codepath - * is invoked when we can spin safely for it to be idle - */ - ret = adreno_spin_idle(ADRENO_DEVICE(device), ADRENO_IDLE_TIMEOUT); - if (ret) - return ret; - KGSL_IOMMU_SET_CTX_REG_Q(ctx, TTBR0, ttbr0); KGSL_IOMMU_SET_CTX_REG(ctx, CONTEXTIDR, contextidr); @@ -1767,10 +1748,8 @@ static int kgsl_iommu_set_pt(struct kgsl_mmu *mmu, cpu_relax(); } - /* Disable smmu clock */ kgsl_iommu_disable_clk(mmu); - - return ret; + return 0; } /* @@ -1788,8 +1767,6 @@ static int kgsl_iommu_set_pf_policy(struct kgsl_mmu *mmu, struct kgsl_iommu_context *ctx = &iommu->ctx[KGSL_IOMMU_CONTEXT_USER]; struct kgsl_device *device = KGSL_MMU_DEVICE(mmu); struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - int ret = 0; - unsigned int sctlr_val; if ((adreno_dev->ft_pf_policy & BIT(KGSL_FT_PAGEFAULT_GPUHALT_ENABLE)) == @@ -1798,10 +1775,7 @@ static int kgsl_iommu_set_pf_policy(struct kgsl_mmu *mmu, /* If not attached, policy will be updated during the next attach */ if (ctx->default_pt != NULL) { - /* Need to idle device before changing options */ - ret = device->ftbl->idle(device); - if (ret) - return ret; + unsigned int sctlr_val; kgsl_iommu_enable_clk(mmu); @@ -1820,7 +1794,7 @@ static int kgsl_iommu_set_pf_policy(struct kgsl_mmu *mmu, kgsl_iommu_disable_clk(mmu); } - return ret; + return 0; } static struct kgsl_protected_registers * diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h index 3652aa2e6ec4..5339917911b1 100644 --- a/drivers/gpu/msm/kgsl_mmu.h +++ b/drivers/gpu/msm/kgsl_mmu.h @@ -21,6 +21,12 @@ #define KGSL_MMU_GLOBAL_PT 0 #define KGSL_MMU_SECURE_PT 1 +#define MMU_DEFAULT_TTBR0(_d) \ + (kgsl_mmu_pagetable_get_ttbr0((_d)->mmu.defaultpagetable)) + +#define MMU_DEFAULT_CONTEXTIDR(_d) \ + (kgsl_mmu_pagetable_get_contextidr((_d)->mmu.defaultpagetable)) + struct kgsl_device; enum kgsl_mmutype { diff --git a/drivers/gpu/msm/kgsl_pool.c b/drivers/gpu/msm/kgsl_pool.c index 48b7b0872425..7fb3b37ac191 100644 --- a/drivers/gpu/msm/kgsl_pool.c +++ b/drivers/gpu/msm/kgsl_pool.c @@ -298,17 +298,18 @@ int kgsl_pool_alloc_page(int *page_size, struct page **pages, return -EINVAL; pool = _kgsl_get_pool_from_order(order); - pool_idx = kgsl_pool_idx_lookup(order); + if (pool == NULL) + return -EINVAL; - if (pool != NULL) - page = _kgsl_pool_get_page(pool); + pool_idx = kgsl_pool_idx_lookup(order); + page = _kgsl_pool_get_page(pool); /* Allocate a new page if not allocated from pool */ if (page == NULL) { gfp_t gfp_mask = kgsl_gfp_mask(order); /* Only allocate non-reserved memory for certain pools */ - if (!pool->allocation_allowed) { + if (!pool->allocation_allowed && pool_idx > 0) { *page_size = PAGE_SIZE << kgsl_pools[pool_idx-1].pool_order; *align = ilog2(*page_size); diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 830579d94bcf..2b9eef8b6351 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -81,6 +81,8 @@ static void kgsl_pwrctrl_set_state(struct kgsl_device *device, static void kgsl_pwrctrl_request_state(struct kgsl_device *device, unsigned int state); static void kgsl_pwrctrl_retention_clk(struct kgsl_device *device, int state); +static int _isense_clk_set_rate(struct kgsl_pwrctrl *pwr, int level); + /** * _record_pwrevent() - Record the history of the new event @@ -387,6 +389,8 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device, /* Change register settings if any BEFORE pwrlevel change*/ kgsl_pwrctrl_pwrlevel_change_settings(device, 0); clk_set_rate(pwr->grp_clks[0], pwrlevel->gpu_freq); + _isense_clk_set_rate(pwr, pwr->active_pwrlevel); + trace_kgsl_pwrlevel(device, pwr->active_pwrlevel, pwrlevel->gpu_freq, pwr->previous_pwrlevel, @@ -1374,15 +1378,23 @@ static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state, clk_set_rate(pwr->grp_clks[0], pwr->pwrlevels[pwr->num_pwrlevels - 1]. gpu_freq); + _isense_clk_set_rate(pwr, + pwr->num_pwrlevels - 1); } + + /* Turn off the IOMMU clocks */ + kgsl_mmu_disable_clk(&device->mmu); } else if (requested_state == KGSL_STATE_SLEEP) { /* High latency clock maintenance. */ for (i = KGSL_MAX_CLKS - 1; i > 0; i--) clk_unprepare(pwr->grp_clks[i]); - if ((pwr->pwrlevels[0].gpu_freq > 0)) + if ((pwr->pwrlevels[0].gpu_freq > 0)) { clk_set_rate(pwr->grp_clks[0], pwr->pwrlevels[pwr->num_pwrlevels - 1]. gpu_freq); + _isense_clk_set_rate(pwr, + pwr->num_pwrlevels - 1); + } } } else if (state == KGSL_PWRFLAGS_ON) { if (!test_and_set_bit(KGSL_PWRFLAGS_CLK_ON, @@ -1392,11 +1404,15 @@ static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state, /* High latency clock maintenance. */ if ((device->state != KGSL_STATE_NAP) && (device->state != KGSL_STATE_DEEP_NAP)) { - if (pwr->pwrlevels[0].gpu_freq > 0) + if (pwr->pwrlevels[0].gpu_freq > 0) { clk_set_rate(pwr->grp_clks[0], pwr->pwrlevels [pwr->active_pwrlevel]. gpu_freq); + _isense_clk_set_rate(pwr, + pwr->active_pwrlevel); + } + for (i = KGSL_MAX_CLKS - 1; i > 0; i--) clk_prepare(pwr->grp_clks[i]); } @@ -1415,7 +1431,11 @@ static void kgsl_pwrctrl_clk(struct kgsl_device *device, int state, pwr->gpu_bimc_interface_enabled = 1; } } + + /* Turn on the IOMMU clocks */ + kgsl_mmu_enable_clk(&device->mmu); } + } } @@ -1720,9 +1740,27 @@ static int _get_clocks(struct kgsl_device *device) } } + if (pwr->isense_clk_indx && of_property_read_u32(dev->of_node, + "qcom,isense-clk-on-level", &pwr->isense_clk_on_level)) { + KGSL_CORE_ERR("Couldn't get isense clock on level\n"); + return -ENXIO; + } return 0; } +static int _isense_clk_set_rate(struct kgsl_pwrctrl *pwr, int level) +{ + int rate; + + if (!pwr->isense_clk_indx) + return -EINVAL; + + rate = clk_round_rate(pwr->grp_clks[pwr->isense_clk_indx], + level > pwr->isense_clk_on_level ? + KGSL_XO_CLK_FREQ : KGSL_ISENSE_CLK_FREQ); + return clk_set_rate(pwr->grp_clks[pwr->isense_clk_indx], rate); +} + int kgsl_pwrctrl_init(struct kgsl_device *device) { int i, k, m, n = 0, result; @@ -1771,6 +1809,9 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) pwr->power_flags = BIT(KGSL_PWRFLAGS_RETENTION_ON); + if (of_property_read_bool(pdev->dev.of_node, "qcom,no-nap")) + device->pwrctrl.ctrl_flags |= BIT(KGSL_PWRFLAGS_NAP_OFF); + if (pwr->num_pwrlevels == 0) { KGSL_PWR_ERR(device, "No power levels are defined\n"); return -EINVAL; @@ -1799,9 +1840,7 @@ int kgsl_pwrctrl_init(struct kgsl_device *device) clk_set_rate(pwr->grp_clks[6], clk_round_rate(pwr->grp_clks[6], KGSL_RBBMTIMER_CLK_FREQ)); - if (pwr->isense_clk_indx) - clk_set_rate(pwr->grp_clks[pwr->isense_clk_indx], - KGSL_ISENSE_CLK_FREQ); + _isense_clk_set_rate(pwr, pwr->num_pwrlevels - 1); result = get_regulators(device); if (result) @@ -2577,7 +2616,8 @@ void kgsl_active_count_put(struct kgsl_device *device) device->requested_state == KGSL_STATE_NONE) { kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP); kgsl_schedule_work(&device->idle_check_ws); - } + } else if (!nap_on) + kgsl_pwrscale_update_stats(device); mod_timer(&device->idle_timer, jiffies + device->pwrctrl.interval_timeout); diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h index 9d2c6ce0c269..0029c389484f 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.h +++ b/drivers/gpu/msm/kgsl_pwrctrl.h @@ -33,7 +33,8 @@ /* Only two supported levels, min & max */ #define KGSL_CONSTRAINT_PWR_MAXLEVELS 2 -#define KGSL_RBBMTIMER_CLK_FREQ 19200000 +#define KGSL_XO_CLK_FREQ 19200000 +#define KGSL_RBBMTIMER_CLK_FREQ KGSL_XO_CLK_FREQ #define KGSL_ISENSE_CLK_FREQ 200000000 /* Symbolic table for the constraint type */ @@ -154,6 +155,8 @@ struct kgsl_regulator { * @deep_nap_timer - Timer struct for entering deep nap * @deep_nap_timeout - Timeout for entering deep nap * @gx_retention - true if retention voltage is allowed + * isense_clk_indx - index of isense clock, 0 if no isense + * isense_clk_on_level - isense clock rate is XO rate below this level. */ struct kgsl_pwrctrl { @@ -162,6 +165,7 @@ struct kgsl_pwrctrl { struct clk *dummy_mx_clk; struct clk *gpu_bimc_int_clk; int isense_clk_indx; + int isense_clk_on_level; unsigned long power_flags; unsigned long ctrl_flags; struct kgsl_pwrlevel pwrlevels[KGSL_MAX_PWRLEVELS]; diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index c4dcab048cb8..9098f13f2f44 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -630,10 +630,19 @@ int vmbus_sendpacket_ctl(struct vmbus_channel *channel, void *buffer, * on the ring. We will not signal if more data is * to be placed. * + * Based on the channel signal state, we will decide + * which signaling policy will be applied. + * * If we cannot write to the ring-buffer; signal the host * even if we may not have written anything. This is a rare * enough condition that it should not matter. */ + + if (channel->signal_policy) + signal = true; + else + kick_q = true; + if (((ret == 0) && kick_q && signal) || (ret)) vmbus_setevent(channel); @@ -733,10 +742,19 @@ int vmbus_sendpacket_pagebuffer_ctl(struct vmbus_channel *channel, * on the ring. We will not signal if more data is * to be placed. * + * Based on the channel signal state, we will decide + * which signaling policy will be applied. + * * If we cannot write to the ring-buffer; signal the host * even if we may not have written anything. This is a rare * enough condition that it should not matter. */ + + if (channel->signal_policy) + signal = true; + else + kick_q = true; + if (((ret == 0) && kick_q && signal) || (ret)) vmbus_setevent(channel); diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c index f155b8380481..2b3105c8aed3 100644 --- a/drivers/hwmon/ads1015.c +++ b/drivers/hwmon/ads1015.c @@ -126,7 +126,7 @@ static int ads1015_reg_to_mv(struct i2c_client *client, unsigned int channel, struct ads1015_data *data = i2c_get_clientdata(client); unsigned int pga = data->channel_data[channel].pga; int fullscale = fullscale_table[pga]; - const unsigned mask = data->id == ads1115 ? 0x7fff : 0x7ff0; + const int mask = data->id == ads1115 ? 0x7fff : 0x7ff0; return DIV_ROUND_CLOSEST(reg * fullscale, mask); } diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c index c8487894b312..c43318d3416e 100644 --- a/drivers/hwmon/dell-smm-hwmon.c +++ b/drivers/hwmon/dell-smm-hwmon.c @@ -932,6 +932,17 @@ MODULE_DEVICE_TABLE(dmi, i8k_dmi_table); static struct dmi_system_id i8k_blacklist_dmi_table[] __initdata = { { /* + * CPU fan speed going up and down on Dell Studio XPS 8000 + * for unknown reasons. + */ + .ident = "Dell Studio XPS 8000", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Studio XPS 8000"), + }, + }, + { + /* * CPU fan speed going up and down on Dell Studio XPS 8100 * for unknown reasons. */ diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index 82de3deeb18a..685568b1236d 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c @@ -406,16 +406,11 @@ static int gpio_fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *state) { struct gpio_fan_data *fan_data = cdev->devdata; - int r; if (!fan_data) return -EINVAL; - r = get_fan_speed_index(fan_data); - if (r < 0) - return r; - - *state = r; + *state = fan_data->speed_index; return 0; } diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index dc52b8a3c734..a4d2ac601556 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -647,7 +647,7 @@ static int coresight_name_match(struct device *dev, void *data) to_match = data; i_csdev = to_coresight_device(dev); - if (!strcmp(to_match, dev_name(&i_csdev->dev))) + if (to_match && !strcmp(to_match, dev_name(&i_csdev->dev))) return 1; return 0; diff --git a/drivers/i2c/busses/i2c-brcmstb.c b/drivers/i2c/busses/i2c-brcmstb.c index 8e9637eea512..81115abf3c1f 100644 --- a/drivers/i2c/busses/i2c-brcmstb.c +++ b/drivers/i2c/busses/i2c-brcmstb.c @@ -562,8 +562,7 @@ static int brcmstb_i2c_probe(struct platform_device *pdev) if (!dev) return -ENOMEM; - dev->bsc_regmap = devm_kzalloc(&pdev->dev, sizeof(struct bsc_regs *), - GFP_KERNEL); + dev->bsc_regmap = devm_kzalloc(&pdev->dev, sizeof(*dev->bsc_regmap), GFP_KERNEL); if (!dev->bsc_regmap) return -ENOMEM; diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index f62d69799a9c..27fa0cb09538 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1271,6 +1271,8 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) switch (dev->device) { case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS: case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS: + case PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS: + case PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS: case PCI_DEVICE_ID_INTEL_DNV_SMBUS: priv->features |= FEATURE_I2C_BLOCK_READ; priv->features |= FEATURE_IRQ; diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 0a26dd6d9b19..d6d2b3582910 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -782,11 +782,11 @@ static void cm_enter_timewait(struct cm_id_private *cm_id_priv) wait_time = cm_convert_to_ms(cm_id_priv->av.timeout); /* Check if the device started its remove_one */ - spin_lock_irq(&cm.lock); + spin_lock_irqsave(&cm.lock, flags); if (!cm_dev->going_down) queue_delayed_work(cm.wq, &cm_id_priv->timewait_info->work.work, msecs_to_jiffies(wait_time)); - spin_unlock_irq(&cm.lock); + spin_unlock_irqrestore(&cm.lock, flags); cm_id_priv->timewait_info = NULL; } diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 2d762a2ecd81..17a15c56028c 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -453,7 +453,7 @@ static inline int cma_validate_port(struct ib_device *device, u8 port, if ((dev_type != ARPHRD_INFINIBAND) && rdma_protocol_ib(device, port)) return ret; - if (dev_type == ARPHRD_ETHER) + if (dev_type == ARPHRD_ETHER && rdma_protocol_roce(device, port)) ndev = dev_get_by_index(&init_net, bound_if_index); ret = ib_find_cached_gid_by_port(device, gid, port, ndev, NULL); diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index cb78b1e9bcd9..f504ba73e5dc 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -149,7 +149,7 @@ static int iwch_l2t_send(struct t3cdev *tdev, struct sk_buff *skb, struct l2t_en error = l2t_send(tdev, skb, l2e); if (error < 0) kfree_skb(skb); - return error; + return error < 0 ? error : 0; } int iwch_cxgb3_ofld_send(struct t3cdev *tdev, struct sk_buff *skb) @@ -165,7 +165,7 @@ int iwch_cxgb3_ofld_send(struct t3cdev *tdev, struct sk_buff *skb) error = cxgb3_ofld_send(tdev, skb); if (error < 0) kfree_skb(skb); - return error; + return error < 0 ? error : 0; } static void release_tid(struct t3cdev *tdev, u32 hwtid, struct sk_buff *skb) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 7e97cb55a6bf..c4e091528390 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -275,7 +275,7 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, props->max_sge = min(max_rq_sg, max_sq_sg); props->max_sge_rd = props->max_sge; props->max_cq = 1 << MLX5_CAP_GEN(mdev, log_max_cq); - props->max_cqe = (1 << MLX5_CAP_GEN(mdev, log_max_eq_sz)) - 1; + props->max_cqe = (1 << MLX5_CAP_GEN(mdev, log_max_cq_sz)) - 1; props->max_mr = 1 << MLX5_CAP_GEN(mdev, log_max_mkey); props->max_pd = 1 << MLX5_CAP_GEN(mdev, log_max_pd); props->max_qp_rd_atom = 1 << MLX5_CAP_GEN(mdev, log_max_ra_req_qp); diff --git a/drivers/infiniband/hw/qib/qib_qp.c b/drivers/infiniband/hw/qib/qib_qp.c index 40f85bb3e0d3..3eff35c2d453 100644 --- a/drivers/infiniband/hw/qib/qib_qp.c +++ b/drivers/infiniband/hw/qib/qib_qp.c @@ -100,9 +100,10 @@ static u32 credit_table[31] = { 32768 /* 1E */ }; -static void get_map_page(struct qib_qpn_table *qpt, struct qpn_map *map) +static void get_map_page(struct qib_qpn_table *qpt, struct qpn_map *map, + gfp_t gfp) { - unsigned long page = get_zeroed_page(GFP_KERNEL); + unsigned long page = get_zeroed_page(gfp); /* * Free the page if someone raced with us installing it. @@ -121,7 +122,7 @@ static void get_map_page(struct qib_qpn_table *qpt, struct qpn_map *map) * zero/one for QP type IB_QPT_SMI/IB_QPT_GSI. */ static int alloc_qpn(struct qib_devdata *dd, struct qib_qpn_table *qpt, - enum ib_qp_type type, u8 port) + enum ib_qp_type type, u8 port, gfp_t gfp) { u32 i, offset, max_scan, qpn; struct qpn_map *map; @@ -151,7 +152,7 @@ static int alloc_qpn(struct qib_devdata *dd, struct qib_qpn_table *qpt, max_scan = qpt->nmaps - !offset; for (i = 0;;) { if (unlikely(!map->page)) { - get_map_page(qpt, map); + get_map_page(qpt, map, gfp); if (unlikely(!map->page)) break; } @@ -983,13 +984,21 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd, size_t sz; size_t sg_list_sz; struct ib_qp *ret; + gfp_t gfp; + if (init_attr->cap.max_send_sge > ib_qib_max_sges || init_attr->cap.max_send_wr > ib_qib_max_qp_wrs || - init_attr->create_flags) { - ret = ERR_PTR(-EINVAL); - goto bail; - } + init_attr->create_flags & ~(IB_QP_CREATE_USE_GFP_NOIO)) + return ERR_PTR(-EINVAL); + + /* GFP_NOIO is applicable in RC QPs only */ + if (init_attr->create_flags & IB_QP_CREATE_USE_GFP_NOIO && + init_attr->qp_type != IB_QPT_RC) + return ERR_PTR(-EINVAL); + + gfp = init_attr->create_flags & IB_QP_CREATE_USE_GFP_NOIO ? + GFP_NOIO : GFP_KERNEL; /* Check receive queue parameters if no SRQ is specified. */ if (!init_attr->srq) { @@ -1021,7 +1030,8 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd, sz = sizeof(struct qib_sge) * init_attr->cap.max_send_sge + sizeof(struct qib_swqe); - swq = vmalloc((init_attr->cap.max_send_wr + 1) * sz); + swq = __vmalloc((init_attr->cap.max_send_wr + 1) * sz, + gfp, PAGE_KERNEL); if (swq == NULL) { ret = ERR_PTR(-ENOMEM); goto bail; @@ -1037,13 +1047,13 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd, } else if (init_attr->cap.max_recv_sge > 1) sg_list_sz = sizeof(*qp->r_sg_list) * (init_attr->cap.max_recv_sge - 1); - qp = kzalloc(sz + sg_list_sz, GFP_KERNEL); + qp = kzalloc(sz + sg_list_sz, gfp); if (!qp) { ret = ERR_PTR(-ENOMEM); goto bail_swq; } RCU_INIT_POINTER(qp->next, NULL); - qp->s_hdr = kzalloc(sizeof(*qp->s_hdr), GFP_KERNEL); + qp->s_hdr = kzalloc(sizeof(*qp->s_hdr), gfp); if (!qp->s_hdr) { ret = ERR_PTR(-ENOMEM); goto bail_qp; @@ -1058,8 +1068,16 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd, qp->r_rq.max_sge = init_attr->cap.max_recv_sge; sz = (sizeof(struct ib_sge) * qp->r_rq.max_sge) + sizeof(struct qib_rwqe); - qp->r_rq.wq = vmalloc_user(sizeof(struct qib_rwq) + - qp->r_rq.size * sz); + if (gfp != GFP_NOIO) + qp->r_rq.wq = vmalloc_user( + sizeof(struct qib_rwq) + + qp->r_rq.size * sz); + else + qp->r_rq.wq = __vmalloc( + sizeof(struct qib_rwq) + + qp->r_rq.size * sz, + gfp, PAGE_KERNEL); + if (!qp->r_rq.wq) { ret = ERR_PTR(-ENOMEM); goto bail_qp; @@ -1090,7 +1108,7 @@ struct ib_qp *qib_create_qp(struct ib_pd *ibpd, dev = to_idev(ibpd->device); dd = dd_from_dev(dev); err = alloc_qpn(dd, &dev->qpn_table, init_attr->qp_type, - init_attr->port_num); + init_attr->port_num, gfp); if (err < 0) { ret = ERR_PTR(err); vfree(qp->r_rq.wq); diff --git a/drivers/infiniband/hw/qib/qib_verbs_mcast.c b/drivers/infiniband/hw/qib/qib_verbs_mcast.c index f8ea069a3eaf..b2fb5286dbd9 100644 --- a/drivers/infiniband/hw/qib/qib_verbs_mcast.c +++ b/drivers/infiniband/hw/qib/qib_verbs_mcast.c @@ -286,15 +286,13 @@ int qib_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) struct qib_ibdev *dev = to_idev(ibqp->device); struct qib_ibport *ibp = to_iport(ibqp->device, qp->port_num); struct qib_mcast *mcast = NULL; - struct qib_mcast_qp *p, *tmp; + struct qib_mcast_qp *p, *tmp, *delp = NULL; struct rb_node *n; int last = 0; int ret; - if (ibqp->qp_num <= 1 || qp->state == IB_QPS_RESET) { - ret = -EINVAL; - goto bail; - } + if (ibqp->qp_num <= 1 || qp->state == IB_QPS_RESET) + return -EINVAL; spin_lock_irq(&ibp->lock); @@ -303,8 +301,7 @@ int qib_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) while (1) { if (n == NULL) { spin_unlock_irq(&ibp->lock); - ret = -EINVAL; - goto bail; + return -EINVAL; } mcast = rb_entry(n, struct qib_mcast, rb_node); @@ -328,6 +325,7 @@ int qib_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) */ list_del_rcu(&p->list); mcast->n_attached--; + delp = p; /* If this was the last attached QP, remove the GID too. */ if (list_empty(&mcast->qp_list)) { @@ -338,15 +336,16 @@ int qib_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) } spin_unlock_irq(&ibp->lock); + /* QP not attached */ + if (!delp) + return -EINVAL; + /* + * Wait for any list walkers to finish before freeing the + * list element. + */ + wait_event(mcast->wait, atomic_read(&mcast->refcount) <= 1); + qib_mcast_qp_free(delp); - if (p) { - /* - * Wait for any list walkers to finish before freeing the - * list element. - */ - wait_event(mcast->wait, atomic_read(&mcast->refcount) <= 1); - qib_mcast_qp_free(p); - } if (last) { atomic_dec(&mcast->refcount); wait_event(mcast->wait, !atomic_read(&mcast->refcount)); @@ -355,11 +354,7 @@ int qib_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) dev->n_mcast_grps_allocated--; spin_unlock_irq(&dev->n_mcast_grps_lock); } - - ret = 0; - -bail: - return ret; + return 0; } int qib_mcast_tree_empty(struct qib_ibport *ibp) diff --git a/drivers/input/touchscreen/it7258_ts_i2c.c b/drivers/input/touchscreen/it7258_ts_i2c.c new file mode 100644 index 000000000000..048358e2ef9d --- /dev/null +++ b/drivers/input/touchscreen/it7258_ts_i2c.c @@ -0,0 +1,851 @@ +/* drivers/input/touchscreen/it7258_ts_i2c.c + * + * Copyright (C) 2014 ITE Tech. Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/firmware.h> +#include <linux/gpio.h> +#include <linux/slab.h> +#include <linux/wakelock.h> + +#define MAX_BUFFER_SIZE 144 +#define DEVICE_NAME "IT7260" +#define SCREEN_X_RESOLUTION 320 +#define SCREEN_Y_RESOLUTION 320 + +#define BUF_COMMAND 0x20 /* all commands writes go to this idx */ +#define BUF_SYS_COMMAND 0x40 +#define BUF_QUERY 0x80 /* "revice ready?" and "wake up please" and "read touch data" reads go to this idx */ +#define BUF_RESPONSE 0xA0 /* most command responce reads go to this idx */ +#define BUF_SYS_RESPONSE 0xC0 +#define BUF_POINT_INFO 0xE0 /* reads of "point" go through here and produce 14 bytes of data */ + +/* commands and their subcommands. when no subcommands exist, a zero is send as the second byte */ +#define CMD_IDENT_CHIP 0x00 +#define CMD_READ_VERSIONS 0x01 /* VERSION_LENGTH bytes of data in response */ +# define VER_FIRMWARE 0x00 +# define VER_CONFIG 0x06 +# define VERSION_LENGTH 10 +#define CMD_PWR_CTL 0x04 /* subcommand is zero, next byte is power mode */ +# define PWR_CTL_LOW_POWER_MODE 0x01 /* idle mode */ +# define PWR_CTL_SLEEP_MODE 0x02 /* sleep mode */ +#define CMD_UNKNOWN_7 0x07 /* command is not documented in the datasheet v1.0.0.7 */ +#define CMD_FIRMWARE_REINIT_C 0x0C +#define CMD_CALIBRATE 0x13 /* needs to be followed by 4 bytes of zeroes */ +#define CMD_FIRMWARE_UPGRADE 0x60 +# define FIRMWARE_MODE_ENTER 0x00 +# define FIRMWARE_MODE_EXIT 0x80 +#define CMD_SET_START_OFFSET 0x61 /* address for FW read/write */ +#define CMD_FW_WRITE 0x62 /* subcommand is number of bytes to write */ +#define CMD_FW_READ 0x63 /* subcommand is number of bytes to read */ +#define CMD_FIRMWARE_REINIT_6F 0x6F + +#define FW_WRITE_CHUNK_SIZE 128 +#define FW_WRITE_RETRY_COUNT 4 +#define CHIP_FLASH_SIZE 0x8000 +#define SYSFS_FW_UPLOAD_MODE_MANUAL 2 +#define SYSFS_RESULT_FAIL (-1) +#define SYSFS_RESULT_NOT_DONE 0 +#define SYSFS_RESULT_SUCCESS 1 +#define DEVICE_READY_MAX_WAIT 500 + +/* result of reading with BUF_QUERY bits */ +#define CMD_STATUS_BITS 0x07 +#define CMD_STATUS_DONE 0x00 +#define CMD_STATUS_BUSY 0x01 +#define CMD_STATUS_ERROR 0x02 +#define PT_INFO_BITS 0xF8 +#define BT_INFO_NONE 0x00 +#define PT_INFO_YES 0x80 +#define BT_INFO_NONE_BUT_DOWN 0x08 /* no new data but finder(s) still down */ + +/* use this to include integers in commands */ +#define CMD_UINT16(v) ((uint8_t)(v)) , ((uint8_t)((v) >> 8)) + + +struct FingerData { + uint8_t xLo; + uint8_t hi; + uint8_t yLo; + uint8_t pressure; +} __attribute__((packed)); + +struct PointData { + uint8_t flags; + uint8_t palm; + struct FingerData fd[3]; +} __attribute__((packed)); + +#define PD_FLAGS_DATA_TYPE_BITS 0xF0 +/* other types (like chip-detected gestures) exist but we do not care */ +#define PD_FLAGS_DATA_TYPE_TOUCH 0x00 +#define PD_FLAGS_NOT_PEN 0x08 /* set if pen touched, clear if finger(s) */ +#define PD_FLAGS_HAVE_FINGERS 0x07 /* a bit for each finger data that is valid (from lsb to msb) */ +#define PD_PALM_FLAG_BIT 0x01 +#define FD_PRESSURE_BITS 0x0F +#define FD_PRESSURE_NONE 0x00 +#define FD_PRESSURE_HOVER 0x01 +#define FD_PRESSURE_LIGHT 0x02 +#define FD_PRESSURE_NORMAL 0x04 +#define FD_PRESSURE_HIGH 0x08 +#define FD_PRESSURE_HEAVY 0x0F + +struct IT7260_ts_data { + struct i2c_client *client; + struct input_dev *input_dev; +}; + +static int8_t fwUploadResult = SYSFS_RESULT_NOT_DONE; +static int8_t calibrationWasSuccessful = SYSFS_RESULT_NOT_DONE; +static bool devicePresent = false; +static DEFINE_MUTEX(sleepModeMutex); +static bool chipAwake = true; +static bool hadFingerDown = false; +static bool isDeviceSleeping = false; +static bool isDeviceSuspend = false; +static struct input_dev *input_dev; +static struct IT7260_ts_data *gl_ts; + +#define LOGE(...) pr_err(DEVICE_NAME ": " __VA_ARGS__) +#define LOGI(...) printk(DEVICE_NAME ": " __VA_ARGS__) + +/* internal use func - does not make sure chip is ready before read */ +static bool i2cReadNoReadyCheck(uint8_t bufferIndex, uint8_t *dataBuffer, uint16_t dataLength) +{ + struct i2c_msg msgs[2] = { + { + .addr = gl_ts->client->addr, + .flags = I2C_M_NOSTART, + .len = 1, + .buf = &bufferIndex + }, + { + .addr = gl_ts->client->addr, + .flags = I2C_M_RD, + .len = dataLength, + .buf = dataBuffer + } + }; + + memset(dataBuffer, 0xFF, dataLength); + + return i2c_transfer(gl_ts->client->adapter, msgs, 2); +} + +static bool i2cWriteNoReadyCheck(uint8_t bufferIndex, const uint8_t *dataBuffer, uint16_t dataLength) +{ + uint8_t txbuf[257]; + struct i2c_msg msg = { + .addr = gl_ts->client->addr, + .flags = 0, + .len = dataLength + 1, + .buf = txbuf + }; + + /* just to be careful */ + BUG_ON(dataLength > sizeof(txbuf) - 1); + + txbuf[0] = bufferIndex; + memcpy(txbuf + 1, dataBuffer, dataLength); + + return i2c_transfer(gl_ts->client->adapter, &msg, 1); +} + +/* + * Device is apparently always ready for i2c but not for actual register reads/writes. + * This function ascertains it is ready for that too. the results of this call often + * were ignored. + */ +static bool waitDeviceReady(bool forever, bool slowly) +{ + uint8_t ucQuery; + uint32_t count = DEVICE_READY_MAX_WAIT; + + do{ + if (!i2cReadNoReadyCheck(BUF_QUERY, &ucQuery, sizeof(ucQuery))) + ucQuery = CMD_STATUS_BUSY; + + if (slowly) + mdelay(1000); + if (!forever) + count--; + + }while((ucQuery & CMD_STATUS_BUSY) && count); + + return !ucQuery; +} + +static bool i2cRead(uint8_t bufferIndex, uint8_t *dataBuffer, uint16_t dataLength) +{ + waitDeviceReady(false, false); + return i2cReadNoReadyCheck(bufferIndex, dataBuffer, dataLength); +} + +static bool i2cWrite(uint8_t bufferIndex, const uint8_t *dataBuffer, uint16_t dataLength) +{ + waitDeviceReady(false, false); + return i2cWriteNoReadyCheck(bufferIndex, dataBuffer, dataLength); +} + +static bool chipFirmwareReinitialize(uint8_t cmdOfChoice) +{ + uint8_t cmd[] = {cmdOfChoice}; + uint8_t rsp[2]; + + if (!i2cWrite(BUF_COMMAND, cmd, sizeof(cmd))) + return false; + + if (!i2cRead(BUF_RESPONSE, rsp, sizeof(rsp))) + return false; + + /* a reply of two zero bytes signifies success */ + return !rsp[0] && !rsp[1]; +} + +static bool chipFirmwareUpgradeModeEnterExit(bool enter) +{ + uint8_t cmd[] = {CMD_FIRMWARE_UPGRADE, 0, 'I', 'T', '7', '2', '6', '0', 0x55, 0xAA}; + uint8_t resp[2]; + + cmd[1] = enter ? FIRMWARE_MODE_ENTER : FIRMWARE_MODE_EXIT; + if (!i2cWrite(BUF_COMMAND, cmd, sizeof(cmd))) + return false; + + if (!i2cRead(BUF_RESPONSE, resp, sizeof(resp))) + return false; + + /* a reply of two zero bytes signifies success */ + return !resp[0] && !resp[1]; +} + +static bool chipSetStartOffset(uint16_t offset) +{ + uint8_t cmd[] = {CMD_SET_START_OFFSET, 0, CMD_UINT16(offset)}; + uint8_t resp[2]; + + if (!i2cWrite(BUF_COMMAND, cmd, 4)) + return false; + + + if (!i2cRead(BUF_RESPONSE, resp, sizeof(resp))) + return false; + + + /* a reply of two zero bytes signifies success */ + return !resp[0] && !resp[1]; +} + + +/* write fwLength bytes from fwData at chip offset writeStartOffset */ +static bool chipFlashWriteAndVerify(unsigned int fwLength, const uint8_t *fwData, uint16_t writeStartOffset) +{ + uint32_t curDataOfst; + + for (curDataOfst = 0; curDataOfst < fwLength; curDataOfst += FW_WRITE_CHUNK_SIZE) { + + uint8_t cmdWrite[2 + FW_WRITE_CHUNK_SIZE] = {CMD_FW_WRITE}; + uint8_t bufRead[FW_WRITE_CHUNK_SIZE]; + uint8_t cmdRead[2] = {CMD_FW_READ}; + unsigned i, nRetries; + uint32_t curWriteSz; + + /* figure out how much to write */ + curWriteSz = fwLength - curDataOfst; + if (curWriteSz > FW_WRITE_CHUNK_SIZE) + curWriteSz = FW_WRITE_CHUNK_SIZE; + + /* prepare the write command */ + cmdWrite[1] = curWriteSz; + for (i = 0; i < curWriteSz; i++) + cmdWrite[i + 2] = fwData[curDataOfst + i]; + + /* prepare the read command */ + cmdRead[1] = curWriteSz; + + for (nRetries = 0; nRetries < FW_WRITE_RETRY_COUNT; nRetries++) { + + /* set write offset and write the data*/ + chipSetStartOffset(writeStartOffset + curDataOfst); + i2cWrite(BUF_COMMAND, cmdWrite, 2 + curWriteSz); + + /* set offset and read the data back */ + chipSetStartOffset(writeStartOffset + curDataOfst); + i2cWrite(BUF_COMMAND, cmdRead, sizeof(cmdRead)); + i2cRead(BUF_RESPONSE, bufRead, curWriteSz); + + /* verify. If success break out of retry loop */ + for (i = 0; i < curWriteSz && bufRead[i] == cmdWrite[i + 2]; i++); + if (i == curWriteSz) + break; + LOGE("write of data offset %u failed on try %u at byte %u/%u\n", curDataOfst, nRetries, i, curWriteSz); + } + /* if we've failed after all the retries, tell the caller */ + if (nRetries == FW_WRITE_RETRY_COUNT) + return false; + } + + return true; +} + +static bool chipFirmwareUpload(uint32_t fwLen, const uint8_t *fwData, uint32_t cfgLen, const uint8_t *cfgData) +{ + bool success = false; + + /* enter fw upload mode */ + if (!chipFirmwareUpgradeModeEnterExit(true)) + return false; + + /* flash the firmware if requested */ + if (fwLen && fwData && !chipFlashWriteAndVerify(fwLen, fwData, 0)) { + LOGE("failed to upload touch firmware\n"); + goto out; + } + + /* flash config data if requested */ + if (fwLen && fwData && !chipFlashWriteAndVerify(cfgLen, cfgData, CHIP_FLASH_SIZE - cfgLen)) { + LOGE("failed to upload touch cfg data\n"); + goto out; + } + + success = true; + +out: + return chipFirmwareUpgradeModeEnterExit(false) && chipFirmwareReinitialize(CMD_FIRMWARE_REINIT_6F) && success; +} + +/* + * both buffers should be VERSION_LENGTH in size, + * but only a part of them is significant + */ +static bool chipGetVersions(uint8_t *verFw, uint8_t *verCfg, bool logIt) +{ + /* this code to get versions is reproduced as was written, but it does not make sense. Something here *PROBABLY IS* wrong */ + static const uint8_t cmdReadFwVer[] = {CMD_READ_VERSIONS, VER_FIRMWARE}; + static const uint8_t cmdReadCfgVer[] = {CMD_READ_VERSIONS, VER_CONFIG}; + bool ret = true; + + /* this structure is so that we definitely do all the calls, but still return a status in case anyone cares */ + ret = i2cWrite(BUF_COMMAND, cmdReadFwVer, sizeof(cmdReadFwVer)) && ret; + ret = i2cRead(BUF_RESPONSE, verFw, VERSION_LENGTH) && ret; + ret = i2cWrite(BUF_COMMAND, cmdReadCfgVer, sizeof(cmdReadCfgVer)) && ret; + ret = i2cRead(BUF_RESPONSE, verCfg, VERSION_LENGTH) && ret; + + if (logIt) + LOGI("current versions: fw@{%X,%X,%X,%X}, cfg@{%X,%X,%X,%X}\n", + verFw[5], verFw[6], verFw[7], verFw[8], + verCfg[1], verCfg[2], verCfg[3], verCfg[4]); + + return ret; +} + +static ssize_t sysfsUpgradeStore(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + const struct firmware *fw, *cfg; + uint8_t verFw[10], verCfg[10]; + unsigned fwLen = 0, cfgLen = 0; + bool manualUpgrade, success; + int mode = 0; + + if (request_firmware(&fw, "it7260.fw", dev)) + LOGE("failed to get firmware for it7260\n"); + else + fwLen = fw->size; + + + if (request_firmware(&cfg, "it7260.cfg", dev)) + LOGE("failed to get config data for it7260\n"); + else + cfgLen = cfg->size; + + sscanf(buf, "%d", &mode); + manualUpgrade = mode == SYSFS_FW_UPLOAD_MODE_MANUAL; + LOGI("firmware found %ub of fw and %ub of config in %s mode\n", + fwLen, cfgLen, manualUpgrade ? "manual" : "normal"); + + chipGetVersions(verFw, verCfg, true); + + fwUploadResult = SYSFS_RESULT_NOT_DONE; + if (fwLen && cfgLen) { + if (manualUpgrade || (verFw[5] < fw->data[8] || verFw[6] < + fw->data[9] || verFw[7] < fw->data[10] || verFw[8] < + fw->data[11]) || (verCfg[1] < cfg->data[cfgLen - 8] + || verCfg[2] < cfg->data[cfgLen - 7] || verCfg[3] < + cfg->data[cfgLen - 6] || + verCfg[4] < cfg->data[cfgLen - 5])){ + LOGI("firmware/config will be upgraded\n"); + disable_irq(gl_ts->client->irq); + success = chipFirmwareUpload(fwLen, fw->data, cfgLen, cfg->data); + enable_irq(gl_ts->client->irq); + + fwUploadResult = success ? SYSFS_RESULT_SUCCESS : SYSFS_RESULT_FAIL; + LOGI("upload %s\n", success ? "success" : "failed"); + } + else { + LOGI("firmware/config upgrade not needed\n"); + } + } + + if (fwLen) + release_firmware(fw); + + if (cfgLen) + release_firmware(cfg); + + return count; +} + +static ssize_t sysfsUpgradeShow(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d", fwUploadResult); +} + +static ssize_t sysfsCalibrationShow(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d", calibrationWasSuccessful); +} + +static bool chipSendCalibrationCmd(bool autoTuneOn) +{ + uint8_t cmdCalibrate[] = {CMD_CALIBRATE, 0, autoTuneOn ? 1 : 0, 0, 0}; + return i2cWrite(BUF_COMMAND, cmdCalibrate, sizeof(cmdCalibrate)); +} + +static ssize_t sysfsCalibrationStore(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + uint8_t resp; + + if (!chipSendCalibrationCmd(false)) + LOGE("failed to send calibration command\n"); + else { + calibrationWasSuccessful = i2cRead(BUF_RESPONSE, &resp, sizeof(resp)) ? SYSFS_RESULT_SUCCESS : SYSFS_RESULT_FAIL; + + /* previous logic that was here never called chipFirmwareReinitialize() due to checking a guaranteed-not-null value against null. We now call it. Hopefully this is OK */ + if (!resp) + LOGI("chipFirmwareReinitialize -> %s\n", chipFirmwareReinitialize(CMD_FIRMWARE_REINIT_6F) ? "success" : "fail"); + } + + return count; +} + +static ssize_t sysfsPointShow(struct device *dev, struct device_attribute *attr, char *buf) +{ + uint8_t pointData[sizeof(struct PointData)]; + bool readSuccess; + ssize_t ret; + + readSuccess = i2cReadNoReadyCheck(BUF_POINT_INFO, pointData, sizeof(pointData)); + ret = sprintf(buf, "point_show read ret[%d]--point[%x][%x][%x][%x][%x][%x][%x][%x][%x][%x][%x][%x][%x][%x]=\n", + readSuccess, pointData[0],pointData[1],pointData[2],pointData[3], + pointData[4],pointData[5],pointData[6],pointData[7],pointData[8], + pointData[9],pointData[10],pointData[11],pointData[12],pointData[13]); + + + LOGI("%s", buf); + + return ret; +} + +static ssize_t sysfsPointStore(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return count; +} + +static ssize_t sysfsStatusShow(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", devicePresent ? 1 : 0); +} + +static ssize_t sysfsStatusStore(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + uint8_t verFw[10], verCfg[10]; + + chipGetVersions(verFw, verCfg, true); + + return count; +} + +static ssize_t sysfsVersionShow(struct device *dev, struct device_attribute *attr, char *buf) +{ + uint8_t verFw[10], verCfg[10]; + + chipGetVersions(verFw, verCfg, false); + return sprintf(buf, "%x,%x,%x,%x # %x,%x,%x,%x\n",verFw[5], verFw[6], verFw[7], verFw[8], verCfg[1], verCfg[2], verCfg[3], verCfg[4]); +} + +static ssize_t sysfsVersionStore(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + return count; +} + +static ssize_t sysfsSleepShow(struct device *dev, struct device_attribute *attr, char *buf) +{ + /* + * The usefulness of this was questionable at best - we were at least leaking a byte of + * kernel data (by claiming to return a byte but not writing to buf. To fix this now + * we actually return the sleep status + */ + if (!mutex_lock_interruptible(&sleepModeMutex)) { + *buf = chipAwake ? '1' : '0'; + mutex_unlock(&sleepModeMutex); + return 1; + } + else + return -EINTR; +} + +static ssize_t sysfsSleepStore(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + static const uint8_t cmdGoSleep[] = {CMD_PWR_CTL, 0x00, PWR_CTL_SLEEP_MODE}; + int goToSleepVal; + bool goToWake; + uint8_t dummy; + + sscanf(buf, "%d", &goToSleepVal); + goToWake = !goToSleepVal; /* convert to bool of proper polarity */ + + if (!mutex_lock_interruptible(&sleepModeMutex)) { + if ((chipAwake && goToWake) || (!chipAwake && !goToWake)) + LOGE("duplicate request to %s chip\n", goToWake ? "wake" : "sleep"); + else if (goToWake) { + i2cReadNoReadyCheck(BUF_QUERY, &dummy, sizeof(dummy)); + enable_irq(gl_ts->client->irq); + LOGI("touch is going to wake!\n\n"); + } else { + disable_irq(gl_ts->client->irq); + i2cWriteNoReadyCheck(BUF_COMMAND, cmdGoSleep, sizeof(cmdGoSleep)); + LOGI("touch is going to sleep...\n\n"); + } + chipAwake = goToWake; + mutex_unlock(&sleepModeMutex); + return count; + } else + return -EINTR; +} + + +static DEVICE_ATTR(status, S_IRUGO|S_IWUSR|S_IWGRP, sysfsStatusShow, sysfsStatusStore); +static DEVICE_ATTR(version, S_IRUGO|S_IWUSR|S_IWGRP, sysfsVersionShow, sysfsVersionStore); +static DEVICE_ATTR(sleep, S_IRUGO|S_IWUSR|S_IWGRP, sysfsSleepShow, sysfsSleepStore); + +static struct attribute *it7260_attrstatus[] = { + &dev_attr_status.attr, + &dev_attr_version.attr, + &dev_attr_sleep.attr, + NULL +}; + +static const struct attribute_group it7260_attrstatus_group = { + .attrs = it7260_attrstatus, +}; + +static DEVICE_ATTR(calibration, S_IRUGO|S_IWUSR|S_IWGRP, sysfsCalibrationShow, sysfsCalibrationStore); +static DEVICE_ATTR(upgrade, S_IRUGO|S_IWUSR|S_IWGRP, sysfsUpgradeShow, sysfsUpgradeStore); +static DEVICE_ATTR(point, S_IRUGO|S_IWUSR|S_IWGRP, sysfsPointShow, sysfsPointStore); + + +static struct attribute *it7260_attributes[] = { + &dev_attr_calibration.attr, + &dev_attr_upgrade.attr, + &dev_attr_point.attr, + NULL +}; + +static const struct attribute_group it7260_attr_group = { + .attrs = it7260_attributes, +}; + +static void chipExternalCalibration(bool autoTuneEnabled) +{ + uint8_t resp[2]; + + LOGI("sent calibration command -> %d\n", chipSendCalibrationCmd(autoTuneEnabled)); + waitDeviceReady(true, true); + i2cReadNoReadyCheck(BUF_RESPONSE, resp, sizeof(resp)); + chipFirmwareReinitialize(CMD_FIRMWARE_REINIT_C); +} + +void sendCalibrationCmd(void) +{ + chipExternalCalibration(false); +} +EXPORT_SYMBOL(sendCalibrationCmd); + +static void readFingerData(uint16_t *xP, uint16_t *yP, uint8_t *pressureP, const struct FingerData *fd) +{ + uint16_t x = fd->xLo; + uint16_t y = fd->yLo; + + x += ((uint16_t)(fd->hi & 0x0F)) << 8; + y += ((uint16_t)(fd->hi & 0xF0)) << 4; + + if (xP) + *xP = x; + if (yP) + *yP = y; + if (pressureP) + *pressureP = fd->pressure & FD_PRESSURE_BITS; +} + +static void readTouchDataPoint(void) +{ + struct PointData pointData; + uint8_t devStatus; + uint8_t pressure = FD_PRESSURE_NONE; + uint16_t x, y; + + /* verify there is point data to read & it is readable and valid */ + i2cReadNoReadyCheck(BUF_QUERY, &devStatus, sizeof(devStatus)); + if (!((devStatus & PT_INFO_BITS) & PT_INFO_YES)) { + LOGE("readTouchDataPoint() called when no data available (0x%02X)\n", devStatus); + return; + } + if (!i2cReadNoReadyCheck(BUF_POINT_INFO, (void*)&pointData, sizeof(pointData))) { + LOGE("readTouchDataPoint() failed to read point data buffer\n"); + return; + } + if ((pointData.flags & PD_FLAGS_DATA_TYPE_BITS) != PD_FLAGS_DATA_TYPE_TOUCH) { + LOGE("readTouchDataPoint() dropping non-point data of type 0x%02X\n", pointData.flags); + return; + } + + if ((pointData.flags & PD_FLAGS_HAVE_FINGERS) & 1) + readFingerData(&x, &y, &pressure, pointData.fd); + + if (pressure >= FD_PRESSURE_LIGHT) { + + if (!hadFingerDown) + hadFingerDown = true; + + readFingerData(&x, &y, &pressure, pointData.fd); + + input_report_abs(gl_ts->input_dev, ABS_X, x); + input_report_abs(gl_ts->input_dev, ABS_Y, y); + input_report_key(gl_ts->input_dev, BTN_TOUCH, 1); + input_sync(gl_ts->input_dev); + + } else if (hadFingerDown) { + hadFingerDown = false; + + input_report_key(gl_ts->input_dev, BTN_TOUCH, 0); + input_sync(gl_ts->input_dev); + } + +} + +static irqreturn_t IT7260_ts_threaded_handler(int irq, void *devid) +{ + smp_rmb(); + if (isDeviceSleeping) { + smp_wmb(); + } else { + readTouchDataPoint(); + } + + return IRQ_HANDLED; +} + +static bool chipIdentifyIT7260(void) +{ + static const uint8_t cmdIdent[] = {CMD_IDENT_CHIP}; + static const uint8_t expectedID[] = {0x0A, 'I', 'T', 'E', '7', '2', '6', '0'}; + uint8_t chipID[10] = {0,}; + + waitDeviceReady(true, false); + + if (!i2cWriteNoReadyCheck(BUF_COMMAND, cmdIdent, sizeof(cmdIdent))) { + LOGE("i2cWrite() failed\n"); + return false; + } + + waitDeviceReady(true, false); + + if (!i2cReadNoReadyCheck(BUF_RESPONSE, chipID, sizeof(chipID))) { + LOGE("i2cRead() failed\n"); + return false; + } + pr_info("chipIdentifyIT7260 read id: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + chipID[0], chipID[1], chipID[2], chipID[3], chipID[4], + chipID[5], chipID[6], chipID[7], chipID[8], chipID[9]); + + if (memcmp(chipID, expectedID, sizeof(expectedID))) + return false; + + if (chipID[8] == '5' && chipID[9] == '6') + LOGI("rev BX3 found\n"); + else if (chipID[8] == '6' && chipID[9] == '6') + LOGI("rev BX4 found\n"); + else + LOGI("unknown revision (0x%02X 0x%02X) found\n", chipID[8], chipID[9]); + + return true; +} + +static int IT7260_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + static const uint8_t cmdStart[] = {CMD_UNKNOWN_7}; + struct IT7260_i2c_platform_data *pdata; + uint8_t rsp[2]; + int ret = -1; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + LOGE("need I2C_FUNC_I2C\n"); + ret = -ENODEV; + goto err_out; + } + + if (!client->irq) { + LOGE("need IRQ\n"); + ret = -ENODEV; + goto err_out; + } + gl_ts = kzalloc(sizeof(*gl_ts), GFP_KERNEL); + if (!gl_ts) { + ret = -ENOMEM; + goto err_out; + } + + gl_ts->client = client; + i2c_set_clientdata(client, gl_ts); + pdata = client->dev.platform_data; + + if (sysfs_create_group(&(client->dev.kobj), &it7260_attrstatus_group)) { + dev_err(&client->dev, "failed to register sysfs #1\n"); + goto err_sysfs_grp_create_1; + } + + if (!chipIdentifyIT7260()) { + LOGI ("chipIdentifyIT7260 FAIL"); + goto err_ident_fail_or_input_alloc; + } + + input_dev = input_allocate_device(); + if (!input_dev) { + LOGE("failed to allocate input device\n"); + ret = -ENOMEM; + goto err_ident_fail_or_input_alloc; + } + gl_ts->input_dev = input_dev; + + input_dev->name = DEVICE_NAME; + input_dev->phys = "I2C"; + input_dev->id.bustype = BUS_I2C; + input_dev->id.vendor = 0x0001; + input_dev->id.product = 0x7260; + set_bit(EV_SYN, input_dev->evbit); + set_bit(EV_KEY, input_dev->evbit); + set_bit(EV_ABS, input_dev->evbit); + set_bit(INPUT_PROP_DIRECT,input_dev->propbit); + set_bit(BTN_TOUCH, input_dev->keybit); + set_bit(KEY_SLEEP,input_dev->keybit); + set_bit(KEY_WAKEUP,input_dev->keybit); + set_bit(KEY_POWER,input_dev->keybit); + input_set_abs_params(input_dev, ABS_X, 0, SCREEN_X_RESOLUTION, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, SCREEN_Y_RESOLUTION, 0, 0); + + if (input_register_device(input_dev)) { + LOGE("failed to register input device\n"); + goto err_input_register; + } + + if (request_threaded_irq(client->irq, NULL, IT7260_ts_threaded_handler, IRQF_TRIGGER_LOW | IRQF_ONESHOT, client->name, gl_ts)) { + dev_err(&client->dev, "request_irq failed\n"); + goto err_irq_reg; + } + + if (sysfs_create_group(&(client->dev.kobj), &it7260_attr_group)) { + dev_err(&client->dev, "failed to register sysfs #2\n"); + goto err_sysfs_grp_create_2; + } + + devicePresent = true; + + i2cWriteNoReadyCheck(BUF_COMMAND, cmdStart, sizeof(cmdStart)); + mdelay(10); + i2cReadNoReadyCheck(BUF_RESPONSE, rsp, sizeof(rsp)); + mdelay(10); + + return 0; + +err_sysfs_grp_create_2: + free_irq(client->irq, gl_ts); + +err_irq_reg: + input_unregister_device(input_dev); + input_dev = NULL; + +err_input_register: + if (input_dev) + input_free_device(input_dev); + +err_ident_fail_or_input_alloc: + sysfs_remove_group(&(client->dev.kobj), &it7260_attrstatus_group); + +err_sysfs_grp_create_1: + kfree(gl_ts); + +err_out: + return ret; +} + +static int IT7260_ts_remove(struct i2c_client *client) +{ + devicePresent = false; + return 0; +} + +static const struct i2c_device_id IT7260_ts_id[] = { + { DEVICE_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, IT7260_ts_id); + +static const struct of_device_id IT7260_match_table[] = { + { .compatible = "ITE,IT7260_ts",}, + {}, +}; + +static int IT7260_ts_resume(struct i2c_client *i2cdev) +{ + isDeviceSuspend = false; + return 0; +} + +static int IT7260_ts_suspend(struct i2c_client *i2cdev, pm_message_t pmesg) +{ + isDeviceSuspend = true; + return 0; +} + +static struct i2c_driver IT7260_ts_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DEVICE_NAME, + .of_match_table = IT7260_match_table, + }, + .probe = IT7260_ts_probe, + .remove = IT7260_ts_remove, + .id_table = IT7260_ts_id, + .resume = IT7260_ts_resume, + .suspend = IT7260_ts_suspend, +}; + +module_i2c_driver(IT7260_ts_driver); + +MODULE_DESCRIPTION("IT7260 Touchscreen Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 013bdfff2d4d..bf4959f4225b 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -228,6 +228,10 @@ static int amd_iommu_enable_interrupts(void); static int __init iommu_go_to_state(enum iommu_init_state state); static void init_device_table_dma(void); +static int iommu_pc_get_set_reg_val(struct amd_iommu *iommu, + u8 bank, u8 cntr, u8 fxn, + u64 *value, bool is_write); + static inline void update_last_devid(u16 devid) { if (devid > amd_iommu_last_bdf) @@ -1016,6 +1020,34 @@ static void amd_iommu_erratum_746_workaround(struct amd_iommu *iommu) } /* + * Family15h Model 30h-3fh (IOMMU Mishandles ATS Write Permission) + * Workaround: + * BIOS should enable ATS write permission check by setting + * L2_DEBUG_3[AtsIgnoreIWDis](D0F2xF4_x47[0]) = 1b + */ +static void amd_iommu_ats_write_check_workaround(struct amd_iommu *iommu) +{ + u32 value; + + if ((boot_cpu_data.x86 != 0x15) || + (boot_cpu_data.x86_model < 0x30) || + (boot_cpu_data.x86_model > 0x3f)) + return; + + /* Test L2_DEBUG_3[AtsIgnoreIWDis] == 1 */ + value = iommu_read_l2(iommu, 0x47); + + if (value & BIT(0)) + return; + + /* Set L2_DEBUG_3[AtsIgnoreIWDis] = 1 */ + iommu_write_l2(iommu, 0x47, value | BIT(0)); + + pr_info("AMD-Vi: Applying ATS write check workaround for IOMMU at %s\n", + dev_name(&iommu->dev->dev)); +} + +/* * This function clues the initialization function for one IOMMU * together and also allocates the command buffer and programs the * hardware. It does NOT enable the IOMMU. This is done afterwards. @@ -1142,8 +1174,8 @@ static void init_iommu_perf_ctr(struct amd_iommu *iommu) amd_iommu_pc_present = true; /* Check if the performance counters can be written to */ - if ((0 != amd_iommu_pc_get_set_reg_val(0, 0, 0, 0, &val, true)) || - (0 != amd_iommu_pc_get_set_reg_val(0, 0, 0, 0, &val2, false)) || + if ((0 != iommu_pc_get_set_reg_val(iommu, 0, 0, 0, &val, true)) || + (0 != iommu_pc_get_set_reg_val(iommu, 0, 0, 0, &val2, false)) || (val != val2)) { pr_err("AMD-Vi: Unable to write to IOMMU perf counter.\n"); amd_iommu_pc_present = false; @@ -1284,6 +1316,7 @@ static int iommu_init_pci(struct amd_iommu *iommu) } amd_iommu_erratum_746_workaround(iommu); + amd_iommu_ats_write_check_workaround(iommu); iommu->iommu_dev = iommu_device_create(&iommu->dev->dev, iommu, amd_iommu_groups, "ivhd%d", @@ -2283,22 +2316,15 @@ u8 amd_iommu_pc_get_max_counters(u16 devid) } EXPORT_SYMBOL(amd_iommu_pc_get_max_counters); -int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn, +static int iommu_pc_get_set_reg_val(struct amd_iommu *iommu, + u8 bank, u8 cntr, u8 fxn, u64 *value, bool is_write) { - struct amd_iommu *iommu; u32 offset; u32 max_offset_lim; - /* Make sure the IOMMU PC resource is available */ - if (!amd_iommu_pc_present) - return -ENODEV; - - /* Locate the iommu associated with the device ID */ - iommu = amd_iommu_rlookup_table[devid]; - /* Check for valid iommu and pc register indexing */ - if (WARN_ON((iommu == NULL) || (fxn > 0x28) || (fxn & 7))) + if (WARN_ON((fxn > 0x28) || (fxn & 7))) return -ENODEV; offset = (u32)(((0x40|bank) << 12) | (cntr << 8) | fxn); @@ -2322,3 +2348,16 @@ int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn, return 0; } EXPORT_SYMBOL(amd_iommu_pc_get_set_reg_val); + +int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn, + u64 *value, bool is_write) +{ + struct amd_iommu *iommu = amd_iommu_rlookup_table[devid]; + + /* Make sure the IOMMU PC resource is available */ + if (!amd_iommu_pc_present || iommu == NULL) + return -ENODEV; + + return iommu_pc_get_set_reg_val(iommu, bank, cntr, fxn, + value, is_write); +} diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 55a19e49205b..3821c4786662 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -329,7 +329,8 @@ static int dmar_pci_bus_notifier(struct notifier_block *nb, /* Only care about add/remove events for physical functions */ if (pdev->is_virtfn) return NOTIFY_DONE; - if (action != BUS_NOTIFY_ADD_DEVICE && action != BUS_NOTIFY_DEL_DEVICE) + if (action != BUS_NOTIFY_ADD_DEVICE && + action != BUS_NOTIFY_REMOVED_DEVICE) return NOTIFY_DONE; info = dmar_alloc_pci_notify_info(pdev, action); @@ -339,7 +340,7 @@ static int dmar_pci_bus_notifier(struct notifier_block *nb, down_write(&dmar_global_lock); if (action == BUS_NOTIFY_ADD_DEVICE) dmar_pci_bus_add_dev(info); - else if (action == BUS_NOTIFY_DEL_DEVICE) + else if (action == BUS_NOTIFY_REMOVED_DEVICE) dmar_pci_bus_del_dev(info); up_write(&dmar_global_lock); diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 986a53e3eb96..a2e1b7f14df2 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -4367,7 +4367,7 @@ int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info) rmrru->devices_cnt); if(ret < 0) return ret; - } else if (info->event == BUS_NOTIFY_DEL_DEVICE) { + } else if (info->event == BUS_NOTIFY_REMOVED_DEVICE) { dmar_remove_dev_scope(info, rmrr->segment, rmrru->devices, rmrru->devices_cnt); } @@ -4387,7 +4387,7 @@ int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info) break; else if(ret < 0) return ret; - } else if (info->event == BUS_NOTIFY_DEL_DEVICE) { + } else if (info->event == BUS_NOTIFY_REMOVED_DEVICE) { if (dmar_remove_dev_scope(info, atsr->segment, atsru->devices, atsru->devices_cnt)) break; diff --git a/drivers/iommu/io-pgtable-fast.c b/drivers/iommu/io-pgtable-fast.c index 44307f67fd22..9a25ebfdc778 100644 --- a/drivers/iommu/io-pgtable-fast.c +++ b/drivers/iommu/io-pgtable-fast.c @@ -420,6 +420,9 @@ av8l_fast_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie) struct av8l_fast_io_pgtable *data = av8l_fast_alloc_pgtable_data(cfg); + if (!data) + return NULL; + /* restrict according to the fast map requirements */ cfg->ias = 32; cfg->pgsize_bitmap = SZ_4K; diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c index a97c082d18d8..c78178c0e1a1 100644 --- a/drivers/iommu/iommu-debug.c +++ b/drivers/iommu/iommu-debug.c @@ -1379,7 +1379,7 @@ static int __apply_to_new_mapping(struct seq_file *s, struct dma_iommu_mapping *mapping; struct iommu_debug_device *ddev = s->private; struct device *dev = ddev->dev; - int ret, fast = 1; + int ret = -EINVAL, fast = 1; phys_addr_t pt_phys; mapping = arm_iommu_create_mapping(&platform_bus_type, 0, SZ_1G * 4ULL); @@ -1688,7 +1688,7 @@ static const struct file_operations iommu_debug_atos_fops = { static ssize_t iommu_debug_map_write(struct file *file, const char __user *ubuf, size_t count, loff_t *offset) { - ssize_t retval; + ssize_t retval = -EINVAL; int ret; char *comma1, *comma2, *comma3; char buf[100]; diff --git a/drivers/irqchip/irq-atmel-aic-common.c b/drivers/irqchip/irq-atmel-aic-common.c index b12a5d58546f..37199b9b2cfa 100644 --- a/drivers/irqchip/irq-atmel-aic-common.c +++ b/drivers/irqchip/irq-atmel-aic-common.c @@ -86,7 +86,7 @@ int aic_common_set_priority(int priority, unsigned *val) priority > AT91_AIC_IRQ_MAX_PRIORITY) return -EINVAL; - *val &= AT91_AIC_PRIOR; + *val &= ~AT91_AIC_PRIOR; *val |= priority; return 0; diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index e23d1d18f9d6..a159529f9d53 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -597,11 +597,6 @@ static void its_unmask_irq(struct irq_data *d) lpi_set_config(d, true); } -static void its_eoi_irq(struct irq_data *d) -{ - gic_write_eoir(d->hwirq); -} - static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bool force) { @@ -638,7 +633,7 @@ static struct irq_chip its_irq_chip = { .name = "ITS", .irq_mask = its_mask_irq, .irq_unmask = its_unmask_irq, - .irq_eoi = its_eoi_irq, + .irq_eoi = irq_chip_eoi_parent, .irq_set_affinity = its_set_affinity, .irq_compose_msi_msg = its_irq_compose_msi_msg, }; diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 6095bd2ccb58..022473473971 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -29,6 +29,7 @@ #include <linux/irqchip.h> #include <linux/irqchip/arm-gic-v3.h> #include <linux/syscore_ops.h> +#include <linux/irqchip/msm-mpm-irq.h> #include <asm/cputype.h> #include <asm/exception.h> @@ -1107,6 +1108,7 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare gic_dist_init(); gic_cpu_init(); gic_cpu_pm_init(); + of_mpm_init(); #ifdef CONFIG_ARM_GIC_PANIC_HANDLER atomic_notifier_chain_register(&panic_notifier_list, &gic_panic_blk); diff --git a/drivers/irqchip/irq-mxs.c b/drivers/irqchip/irq-mxs.c index c22e2d40cb30..efe50845939d 100644 --- a/drivers/irqchip/irq-mxs.c +++ b/drivers/irqchip/irq-mxs.c @@ -241,6 +241,7 @@ static int __init asm9260_of_init(struct device_node *np, writel(0, icoll_priv.intr + i); icoll_add_domain(np, ASM9260_NUM_IRQS); + set_handle_irq(icoll_handle_irq); return 0; } diff --git a/drivers/irqchip/irq-omap-intc.c b/drivers/irqchip/irq-omap-intc.c index 8587d0f8d8c0..f6cb1b8bb981 100644 --- a/drivers/irqchip/irq-omap-intc.c +++ b/drivers/irqchip/irq-omap-intc.c @@ -47,6 +47,7 @@ #define INTC_ILR0 0x0100 #define ACTIVEIRQ_MASK 0x7f /* omap2/3 active interrupt bits */ +#define SPURIOUSIRQ_MASK (0x1ffffff << 7) #define INTCPS_NR_ILR_REGS 128 #define INTCPS_NR_MIR_REGS 4 @@ -330,11 +331,35 @@ static int __init omap_init_irq(u32 base, struct device_node *node) static asmlinkage void __exception_irq_entry omap_intc_handle_irq(struct pt_regs *regs) { + extern unsigned long irq_err_count; u32 irqnr; irqnr = intc_readl(INTC_SIR); + + /* + * A spurious IRQ can result if interrupt that triggered the + * sorting is no longer active during the sorting (10 INTC + * functional clock cycles after interrupt assertion). Or a + * change in interrupt mask affected the result during sorting + * time. There is no special handling required except ignoring + * the SIR register value just read and retrying. + * See section 6.2.5 of AM335x TRM Literature Number: SPRUH73K + * + * Many a times, a spurious interrupt situation has been fixed + * by adding a flush for the posted write acking the IRQ in + * the device driver. Typically, this is going be the device + * driver whose interrupt was handled just before the spurious + * IRQ occurred. Pay attention to those device drivers if you + * run into hitting the spurious IRQ condition below. + */ + if (unlikely((irqnr & SPURIOUSIRQ_MASK) == SPURIOUSIRQ_MASK)) { + pr_err_once("%s: spurious irq!\n", __func__); + irq_err_count++; + omap_ack_irq(NULL); + return; + } + irqnr &= ACTIVEIRQ_MASK; - WARN_ONCE(!irqnr, "Spurious IRQ ?\n"); handle_domain_irq(domain, irqnr, regs); } diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c index 89636557dec1..786ffa822851 100644 --- a/drivers/leds/leds-qpnp-flash-v2.c +++ b/drivers/leds/leds-qpnp-flash-v2.c @@ -16,36 +16,39 @@ #include <linux/errno.h> #include <linux/slab.h> #include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/gpio.h> #include <linux/regmap.h> #include <linux/platform_device.h> +#include <linux/regulator/consumer.h> #include <linux/leds-qpnp-flash-v2.h> #define FLASH_LED_REG_SAFETY_TMR(base) (base + 0x40) #define FLASH_LED_REG_TGR_CURRENT(base) (base + 0x43) #define FLASH_LED_REG_MOD_CTRL(base) (base + 0x46) #define FLASH_LED_REG_IRES(base) (base + 0x47) +#define FLASH_LED_REG_STROBE_CFG(base) (base + 0x48) #define FLASH_LED_REG_STROBE_CTRL(base) (base + 0x49) -#define FLASH_LED_REG_CHANNEL_CTRL(base) (base + 0x4C) +#define FLASH_LED_EN_LED_CTRL(base) (base + 0x4C) #define FLASH_LED_REG_HDRM_PRGM(base) (base + 0x4D) #define FLASH_LED_REG_HDRM_AUTO_MODE_CTRL(base) (base + 0x50) #define FLASH_LED_REG_ISC_DELAY(base) (base + 0x52) -#define FLASH_LED_HDRM_MODE_PRGM_MASK 0xFF -#define FLASH_LED_HDRM_VOL_MASK 0xF0 -#define FLASH_LED_CURRENT_MASK 0x3F -#define FLASH_LED_STROBE_CTRL_MASK 0x07 -#define FLASH_LED_SAFETY_TMR_MASK_MASK 0x7F -#define FLASH_LED_MOD_CTRL_MASK 0x80 -#define FLASH_LED_ISC_DELAY_MASK 0x03 +#define FLASH_LED_HDRM_MODE_PRGM_MASK GENMASK(7, 0) +#define FLASH_LED_HDRM_VOL_MASK GENMASK(7, 4) +#define FLASH_LED_CURRENT_MASK GENMASK(6, 0) +#define FLASH_LED_ENABLE_MASK GENMASK(2, 0) +#define FLASH_LED_SAFETY_TMR_MASK GENMASK(7, 0) +#define FLASH_LED_ISC_DELAY_MASK GENMASK(1, 0) +#define FLASH_LED_MOD_CTRL_MASK BIT(7) +#define FLASH_LED_HW_SW_STROBE_SEL_MASK BIT(2) -#define FLASH_LED_TYPE_FLASH 0 -#define FLASH_LED_TYPE_TORCH 1 #define FLASH_LED_HEADROOM_AUTO_MODE_ENABLED true #define FLASH_LED_ISC_DELAY_SHIFT 6 #define FLASH_LED_ISC_DELAY_DEFAULT_US 3 #define FLASH_LED_SAFETY_TMR_VAL_OFFSET 1 #define FLASH_LED_SAFETY_TMR_VAL_DIVISOR 10 -#define FLASH_LED_SAFETY_TMR_ENABLED 0x08 +#define FLASH_LED_SAFETY_TMR_ENABLE BIT(7) #define FLASH_LED_IRES_BASE 3 #define FLASH_LED_IRES_DIVISOR 2500 #define FLASH_LED_IRES_MIN_UA 5000 @@ -56,16 +59,74 @@ #define FLASH_LED_HDRM_VOL_HI_LO_WIN_DEFAULT_MV 0x04 #define FLASH_LED_HDRM_VOL_BASE_MV 125 #define FLASH_LED_HDRM_VOL_STEP_MV 25 -#define FLASH_LED_STROBE_ENABLE 0x01 -#define FLASH_LED_MOD_ENABLE 0x80 +#define FLASH_LED_STROBE_CFG_DEFAULT 0x00 +#define FLASH_LED_HW_STROBE_OPTION_1 0x00 +#define FLASH_LED_HW_STROBE_OPTION_2 0x01 +#define FLASH_LED_HW_STROBE_OPTION_3 0x02 +#define FLASH_LED_ENABLE BIT(0) +#define FLASH_LED_MOD_ENABLE BIT(7) #define FLASH_LED_DISABLE 0x00 #define FLASH_LED_SAFETY_TMR_DISABLED 0x13 +#define FLASH_LED_MIN_CURRENT_MA 25 + +enum flash_led_type { + FLASH_LED_TYPE_FLASH, + FLASH_LED_TYPE_TORCH, +}; + +enum { + LED1 = 0, + LED2, + LED3, +}; + +/* + * Configurations for each individual LED + */ +struct flash_node_data { + struct platform_device *pdev; + struct led_classdev cdev; + struct pinctrl *pinctrl; + struct pinctrl_state *gpio_state_active; + struct pinctrl_state *gpio_state_suspend; + struct pinctrl_state *hw_strobe_state_active; + struct pinctrl_state *hw_strobe_state_suspend; + int hw_strobe_gpio; + int ires_ua; + int max_current; + int current_ma; + u8 duration; + u8 id; + u8 type; + u8 ires; + u8 hdrm_val; + u8 current_reg_val; + u8 trigger; + bool led_on; +}; + +struct flash_regulator_data { + struct regulator *vreg; + const char *reg_name; + u32 max_volt_uv; +}; + +struct flash_switch_data { + struct platform_device *pdev; + struct led_classdev cdev; + struct flash_regulator_data *reg_data; + int led_mask; + int num_regulators; + bool regulator_on; + bool enabled; +}; /* * Flash LED configuration read from device tree */ struct flash_led_platform_data { u8 isc_delay_us; + u8 hw_strobe_option; bool hdrm_auto_mode_en; }; @@ -79,8 +140,9 @@ struct qpnp_flash_led { struct flash_node_data *fnode; struct flash_switch_data *snode; spinlock_t lock; - int num_led_nodes; - int num_avail_leds; + int num_fnodes; + int num_snodes; + int enable; u16 base; }; @@ -91,12 +153,13 @@ qpnp_flash_led_masked_write(struct qpnp_flash_led *led, u16 addr, u8 mask, int rc; rc = regmap_update_bits(led->regmap, addr, mask, val); - if (rc) + if (rc < 0) dev_err(&led->pdev->dev, "Unable to update bits from 0x%02X, rc = %d\n", addr, rc); - - dev_dbg(&led->pdev->dev, "Write 0x%02X to addr 0x%02X\n", val, addr); + else + dev_dbg(&led->pdev->dev, "Wrote 0x%02X to addr 0x%02X\n", + val, addr); return rc; } @@ -112,13 +175,13 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led) int rc, i, addr_offset; u8 val = 0; - for (i = 0; i < led->num_avail_leds; i++) { + for (i = 0; i < led->num_fnodes; i++) { addr_offset = led->fnode[i].id; rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_HDRM_PRGM(led->base + addr_offset), FLASH_LED_HDRM_MODE_PRGM_MASK, led->fnode[i].hdrm_val); - if (rc) + if (rc < 0) return rc; val |= 0x1 << led->fnode[i].id; @@ -127,133 +190,306 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led) rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_HDRM_AUTO_MODE_CTRL(led->base), FLASH_LED_HDRM_MODE_PRGM_MASK, val); - if (rc) + if (rc < 0) return rc; rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_ISC_DELAY(led->base), FLASH_LED_ISC_DELAY_MASK, led->pdata->isc_delay_us); - if (rc) + if (rc < 0) return rc; return 0; } +static int qpnp_flash_led_hw_strobe_enable(struct flash_node_data *fnode, + int hw_strobe_option, bool on) +{ + int rc = 0; + + /* + * If the LED controlled by this fnode is not GPIO controlled + * for the given strobe_option, return. + */ + if (hw_strobe_option == FLASH_LED_HW_STROBE_OPTION_1) + return 0; + else if (hw_strobe_option == FLASH_LED_HW_STROBE_OPTION_2 + && fnode->id != LED3) + return 0; + else if (hw_strobe_option == FLASH_LED_HW_STROBE_OPTION_3 + && fnode->id == LED1) + return 0; + + if (gpio_is_valid(fnode->hw_strobe_gpio)) { + gpio_set_value(fnode->hw_strobe_gpio, on ? 1 : 0); + } else if (fnode->hw_strobe_state_active && + fnode->hw_strobe_state_suspend) { + rc = pinctrl_select_state(fnode->pinctrl, + on ? fnode->hw_strobe_state_active : + fnode->hw_strobe_state_suspend); + if (rc < 0) { + dev_err(&fnode->pdev->dev, + "failed to change hw strobe pin state\n"); + return rc; + } + } + + return rc; +} + +static int qpnp_flash_led_regulator_enable(struct qpnp_flash_led *led, + struct flash_switch_data *snode, bool on) +{ + int i, rc = 0; + + if (snode->regulator_on == on) + return 0; + + if (on == false) { + i = snode->num_regulators; + goto out; + } + + for (i = 0; i < snode->num_regulators; i++) { + rc = regulator_enable(snode->reg_data[i].vreg); + if (rc < 0) { + dev_err(&led->pdev->dev, + "regulator enable failed, rc=%d\n", rc); + goto out; + } + } + snode->regulator_on = true; + + return rc; + +out: + while (i--) + regulator_disable(snode->reg_data[i].vreg); + + snode->regulator_on = false; + return rc; +} + +static int qpnp_flash_led_get_max_avail_current(struct flash_switch_data *snode, + struct qpnp_flash_led *led) +{ + return 3750; +} + static void qpnp_flash_led_node_set(struct flash_node_data *fnode, int value) { - int prgm_current_ma; + int prgm_current_ma = value; + + if (value <= 0) + prgm_current_ma = 0; + else if (value < FLASH_LED_MIN_CURRENT_MA) + prgm_current_ma = FLASH_LED_MIN_CURRENT_MA; - prgm_current_ma = value < 0 ? 0 : value; - prgm_current_ma = value > fnode->cdev.max_brightness ? - fnode->cdev.max_brightness : value; + prgm_current_ma = min(prgm_current_ma, fnode->max_current); + fnode->current_ma = prgm_current_ma; fnode->cdev.brightness = prgm_current_ma; - fnode->brightness = prgm_current_ma * 1000 / fnode->ires_ua + 1; + fnode->current_reg_val = prgm_current_ma * 1000 / fnode->ires_ua + 1; fnode->led_on = prgm_current_ma != 0; } +static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode) +{ + struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev); + int i, rc, addr_offset; + + rc = qpnp_flash_led_masked_write(led, + FLASH_LED_EN_LED_CTRL(led->base), + snode->led_mask, FLASH_LED_DISABLE); + if (rc < 0) + return rc; + + led->enable--; + if (led->enable == 0) { + rc = qpnp_flash_led_masked_write(led, + FLASH_LED_REG_MOD_CTRL(led->base), + FLASH_LED_MOD_CTRL_MASK, FLASH_LED_DISABLE); + if (rc < 0) + return rc; + } + + for (i = 0; i < led->num_fnodes; i++) { + if (!led->fnode[i].led_on || + !(snode->led_mask & BIT(led->fnode[i].id))) + continue; + + addr_offset = led->fnode[i].id; + rc = qpnp_flash_led_masked_write(led, + FLASH_LED_REG_TGR_CURRENT(led->base + addr_offset), + FLASH_LED_CURRENT_MASK, 0); + if (rc < 0) + return rc; + + led->fnode[i].led_on = false; + + if (led->fnode[i].pinctrl) { + rc = pinctrl_select_state(led->fnode[i].pinctrl, + led->fnode[i].gpio_state_suspend); + if (rc < 0) { + dev_err(&led->pdev->dev, + "failed to disable GPIO, rc=%d\n", rc); + return rc; + } + } + + if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_MASK) { + rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i], + led->pdata->hw_strobe_option, false); + if (rc < 0) { + dev_err(&led->pdev->dev, + "Unable to disable hw strobe, rc=%d\n", + rc); + return rc; + } + } + } + + qpnp_flash_led_regulator_enable(led, snode, false); + snode->enabled = false; + return 0; +} + static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on) { struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev); int rc, i, addr_offset; u8 val; - if (!on) - goto leds_turn_off; + if (snode->enabled == on) { + dev_warn(&led->pdev->dev, "Switch node is already %s!\n", + on ? "enabled" : "disabled"); + return 0; + } + + if (!on) { + rc = qpnp_flash_led_switch_disable(snode); + return rc; + } + + rc = qpnp_flash_led_regulator_enable(led, snode, true); + if (rc < 0) + return rc; + /* Iterate over all leds for this switch node */ val = 0; - for (i = 0; i < led->num_led_nodes; i++) - val |= led->fnode[i].ires << (led->fnode[i].id * 2); + for (i = 0; i < led->num_fnodes; i++) + if (snode->led_mask & BIT(led->fnode[i].id)) + val |= led->fnode[i].ires << (led->fnode[i].id * 2); + rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_IRES(led->base), FLASH_LED_CURRENT_MASK, val); - if (rc) + if (rc < 0) + return rc; + + rc = qpnp_flash_led_masked_write(led, + FLASH_LED_REG_STROBE_CFG(led->base), + FLASH_LED_ENABLE_MASK, + led->pdata->hw_strobe_option); + if (rc < 0) return rc; val = 0; - for (i = 0; i < led->num_avail_leds; i++) { - if (!led->fnode[i].led_on) + for (i = 0; i < led->num_fnodes; i++) { + if (!led->fnode[i].led_on || + !(snode->led_mask & BIT(led->fnode[i].id))) continue; addr_offset = led->fnode[i].id; rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_STROBE_CTRL(led->base + addr_offset), - FLASH_LED_STROBE_CTRL_MASK, FLASH_LED_STROBE_ENABLE); - if (rc) + FLASH_LED_ENABLE_MASK, led->fnode[i].trigger); + if (rc < 0) return rc; rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_TGR_CURRENT(led->base + addr_offset), - FLASH_LED_CURRENT_MASK, led->fnode[i].brightness); - if (rc) + FLASH_LED_CURRENT_MASK, led->fnode[i].current_reg_val); + if (rc < 0) return rc; rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_SAFETY_TMR(led->base + addr_offset), - FLASH_LED_SAFETY_TMR_MASK_MASK, led->fnode[i].duration); - if (rc) + FLASH_LED_SAFETY_TMR_MASK, led->fnode[i].duration); + if (rc < 0) return rc; - val |= FLASH_LED_STROBE_ENABLE << led->fnode[i].id; + val |= FLASH_LED_ENABLE << led->fnode[i].id; if (led->fnode[i].pinctrl) { rc = pinctrl_select_state(led->fnode[i].pinctrl, led->fnode[i].gpio_state_active); - if (rc) { + if (rc < 0) { dev_err(&led->pdev->dev, "failed to enable GPIO\n"); return rc; } } + + if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_MASK) { + rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i], + led->pdata->hw_strobe_option, true); + if (rc < 0) { + dev_err(&led->pdev->dev, + "Unable to enable hw strobe\n"); + return rc; + } + } } - rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_MOD_CTRL(led->base), + if (led->enable == 0) { + rc = qpnp_flash_led_masked_write(led, + FLASH_LED_REG_MOD_CTRL(led->base), FLASH_LED_MOD_CTRL_MASK, FLASH_LED_MOD_ENABLE); - if (rc) - return rc; + if (rc < 0) + return rc; + } + led->enable++; rc = qpnp_flash_led_masked_write(led, - FLASH_LED_REG_CHANNEL_CTRL(led->base), - FLASH_LED_STROBE_CTRL_MASK, val); - if (rc) + FLASH_LED_EN_LED_CTRL(led->base), + snode->led_mask, val); + if (rc < 0) return rc; + snode->enabled = true; return 0; +} -leds_turn_off: - rc = qpnp_flash_led_masked_write(led, - FLASH_LED_REG_CHANNEL_CTRL(led->base), - FLASH_LED_STROBE_CTRL_MASK, FLASH_LED_DISABLE); - if (rc) - return rc; - - rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_MOD_CTRL(led->base), - FLASH_LED_MOD_CTRL_MASK, FLASH_LED_DISABLE); - if (rc) - return rc; +int qpnp_flash_led_prepare(struct led_classdev *led_cdev, int options) +{ + struct flash_switch_data *snode = + container_of(led_cdev, struct flash_switch_data, cdev); + struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev); + int rc, val = 0; - for (i = 0; i < led->num_led_nodes; i++) { - if (!led->fnode[i].led_on) - continue; + if (!(options & (ENABLE_REGULATOR | QUERY_MAX_CURRENT))) { + dev_err(&led->pdev->dev, "Invalid options %d\n", options); + return -EINVAL; + } - addr_offset = led->fnode[i].id; - rc = qpnp_flash_led_masked_write(led, - FLASH_LED_REG_TGR_CURRENT(led->base + addr_offset), - FLASH_LED_CURRENT_MASK, 0); - if (rc) + if (options & ENABLE_REGULATOR) { + rc = qpnp_flash_led_regulator_enable(led, snode, true); + if (rc < 0) { + dev_err(&led->pdev->dev, + "enable regulator failed, rc=%d\n", rc); return rc; - led->fnode[i].led_on = false; + } + } - if (led->fnode[i].pinctrl) { - rc = pinctrl_select_state(led->fnode[i].pinctrl, - led->fnode[i].gpio_state_suspend); - if (rc) { - dev_err(&led->pdev->dev, - "failed to disable GPIO\n"); - return rc; - } + if (options & QUERY_MAX_CURRENT) { + val = qpnp_flash_led_get_max_avail_current(snode, led); + if (val < 0) { + dev_err(&led->pdev->dev, + "query max current failed, rc=%d\n", val); + return val; } } - return 0; + return val; } static void qpnp_flash_led_brightness_set(struct led_classdev *led_cdev, @@ -264,7 +500,7 @@ static void qpnp_flash_led_brightness_set(struct led_classdev *led_cdev, struct qpnp_flash_led *led = dev_get_drvdata(&fnode->pdev->dev); int rc; - if (!strcmp(led_cdev->name, "led:switch")) { + if (!strncmp(led_cdev->name, "led:switch", strlen("led:switch"))) { snode = container_of(led_cdev, struct flash_switch_data, cdev); led = dev_get_drvdata(&snode->pdev->dev); } else { @@ -273,53 +509,141 @@ static void qpnp_flash_led_brightness_set(struct led_classdev *led_cdev, } spin_lock(&led->lock); - if (!fnode) { + if (snode) { rc = qpnp_flash_led_switch_set(snode, value > 0); - if (rc) { + if (rc < 0) dev_err(&led->pdev->dev, "Failed to set flash LED switch\n"); - goto exit; - } - } else { + } else if (fnode) { qpnp_flash_led_node_set(fnode, value); } -exit: spin_unlock(&led->lock); } +static int qpnp_flash_led_regulator_setup(struct qpnp_flash_led *led, + struct flash_switch_data *snode, bool on) +{ + int i, rc = 0; + + if (on == false) { + i = snode->num_regulators; + goto out; + } + + for (i = 0; i < snode->num_regulators; i++) { + snode->reg_data[i].vreg = regulator_get(snode->cdev.dev, + snode->reg_data[i].reg_name); + if (IS_ERR(snode->reg_data[i].vreg)) { + rc = PTR_ERR(snode->reg_data[i].vreg); + dev_err(&led->pdev->dev, + "Failed to get regulator, rc=%d\n", rc); + goto out; + } + + if (regulator_count_voltages(snode->reg_data[i].vreg) > 0) { + rc = regulator_set_voltage(snode->reg_data[i].vreg, + snode->reg_data[i].max_volt_uv, + snode->reg_data[i].max_volt_uv); + if (rc < 0) { + dev_err(&led->pdev->dev, + "regulator set voltage failed, rc=%d\n", + rc); + regulator_put(snode->reg_data[i].vreg); + goto out; + } + } + } + + return rc; + +out: + while (i--) { + if (regulator_count_voltages(snode->reg_data[i].vreg) > 0) + regulator_set_voltage(snode->reg_data[i].vreg, 0, + snode->reg_data[i].max_volt_uv); + + regulator_put(snode->reg_data[i].vreg); + } + + return rc; +} + +static int qpnp_flash_led_regulator_parse_dt(struct qpnp_flash_led *led, + struct flash_switch_data *snode, + struct device_node *node) { + + int i = 0, rc = 0, num_regs = 0; + struct device_node *temp = NULL; + const char *temp_string; + u32 val; + + while ((temp = of_get_next_available_child(node, temp))) { + if (of_find_property(temp, "regulator-name", NULL)) + num_regs++; + } + snode->num_regulators = num_regs; + + if (snode->num_regulators == 0) + return 0; + + snode->reg_data = devm_kcalloc(&led->pdev->dev, snode->num_regulators, + sizeof(*snode->reg_data), + GFP_KERNEL); + if (!snode->reg_data) + return -ENOMEM; + + for_each_available_child_of_node(node, temp) { + rc = of_property_read_string(temp, "regulator-name", + &temp_string); + if (!rc) + snode->reg_data[i].reg_name = temp_string; + else { + dev_err(&led->pdev->dev, + "Unable to read regulator name, rc=%d\n", rc); + return rc; + } + + rc = of_property_read_u32(temp, "max-voltage-uv", &val); + if (!rc) { + snode->reg_data[i].max_volt_uv = val; + } else if (rc != -EINVAL) { + dev_err(&led->pdev->dev, + "Unable to read max voltage, rc=%d\n", rc); + return rc; + } + + i++; + } + + return 0; +} + static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, struct flash_node_data *fnode, struct device_node *node) { const char *temp_string; int rc; u32 val; + bool strobe_sel = 0, edge_trigger = 0, active_high = 0; fnode->pdev = led->pdev; fnode->cdev.brightness_set = qpnp_flash_led_brightness_set; fnode->cdev.brightness_get = qpnp_flash_led_brightness_get; rc = of_property_read_string(node, "qcom,led-name", &fnode->cdev.name); - if (rc) { + if (rc < 0) { dev_err(&led->pdev->dev, "Unable to read flash LED names\n"); return rc; } - rc = of_property_read_u32(node, "qcom,max-current", &val); - if (!rc) { - fnode->cdev.max_brightness = val; - } else { - dev_err(&led->pdev->dev, "Unable to read max current\n"); - return rc; - } - rc = of_property_read_string(node, "label", &temp_string); if (!rc) { - if (!strcmp(temp_string, "flash")) + if (!strcmp(temp_string, "flash")) { fnode->type = FLASH_LED_TYPE_FLASH; - else if (!strcmp(temp_string, "torch")) + } else if (!strcmp(temp_string, "torch")) { fnode->type = FLASH_LED_TYPE_TORCH; - else { + } else { dev_err(&led->pdev->dev, "Wrong flash LED type\n"); return rc; } @@ -338,7 +662,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, rc = of_property_read_string(node, "qcom,default-led-trigger", &fnode->cdev.default_trigger); - if (rc) { + if (rc < 0) { dev_err(&led->pdev->dev, "Unable to read trigger name\n"); return rc; } @@ -355,13 +679,43 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, return rc; } + rc = of_property_read_u32(node, "qcom,max-current", &val); + if (!rc) { + if (val < FLASH_LED_MIN_CURRENT_MA) + val = FLASH_LED_MIN_CURRENT_MA; + fnode->max_current = val; + fnode->cdev.max_brightness = val; + } else { + dev_err(&led->pdev->dev, + "Unable to read max current, rc=%d\n", rc); + return rc; + } + + rc = of_property_read_u32(node, "qcom,current-ma", &val); + if (!rc) { + if (val < FLASH_LED_MIN_CURRENT_MA || + val > fnode->max_current) + dev_warn(&led->pdev->dev, + "Invalid operational current specified, capping it\n"); + if (val < FLASH_LED_MIN_CURRENT_MA) + val = FLASH_LED_MIN_CURRENT_MA; + if (val > fnode->max_current) + val = fnode->max_current; + fnode->current_ma = val; + fnode->cdev.brightness = val; + } else if (rc != -EINVAL) { + dev_err(&led->pdev->dev, + "Unable to read operational current, rc=%d\n", rc); + return rc; + } + fnode->duration = FLASH_LED_SAFETY_TMR_DISABLED; rc = of_property_read_u32(node, "qcom,duration-ms", &val); if (!rc) { fnode->duration = (u8)(((val - FLASH_LED_SAFETY_TMR_VAL_OFFSET) / FLASH_LED_SAFETY_TMR_VAL_DIVISOR) | - FLASH_LED_SAFETY_TMR_ENABLED); + FLASH_LED_SAFETY_TMR_ENABLE); } else if (rc == -EINVAL) { if (fnode->type == FLASH_LED_TYPE_FLASH) { dev_err(&led->pdev->dev, @@ -398,17 +752,62 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, return rc; } + strobe_sel = of_property_read_bool(node, "qcom,hw-strobe-sel"); + if (strobe_sel) { + edge_trigger = of_property_read_bool(node, + "qcom,hw-strobe-edge-trigger"); + active_high = !of_property_read_bool(node, + "qcom,hw-strobe-active-low"); + } + fnode->trigger = (strobe_sel << 2) | (edge_trigger << 1) | active_high; + + if (fnode->trigger & FLASH_LED_HW_SW_STROBE_SEL_MASK) { + if (of_find_property(node, "qcom,hw-strobe-gpio", NULL)) { + fnode->hw_strobe_gpio = of_get_named_gpio(node, + "qcom,hw-strobe-gpio", 0); + if (fnode->hw_strobe_gpio < 0) { + dev_err(&led->pdev->dev, + "Invalid gpio specified\n"); + return fnode->hw_strobe_gpio; + } + gpio_direction_output(fnode->hw_strobe_gpio, 0); + } else { + fnode->hw_strobe_gpio = -1; + fnode->hw_strobe_state_active = + pinctrl_lookup_state(fnode->pinctrl, + "strobe_enable"); + if (IS_ERR_OR_NULL(fnode->hw_strobe_state_active)) { + dev_err(&led->pdev->dev, + "No active pin for hardware strobe, rc=%ld\n", + PTR_ERR(fnode->hw_strobe_state_active)); + fnode->hw_strobe_state_active = NULL; + } + + fnode->hw_strobe_state_suspend = + pinctrl_lookup_state(fnode->pinctrl, + "strobe_disable"); + if (IS_ERR_OR_NULL(fnode->hw_strobe_state_suspend)) { + dev_err(&led->pdev->dev, + "No suspend pin for hardware strobe, rc=%ld\n", + PTR_ERR(fnode->hw_strobe_state_suspend) + ); + fnode->hw_strobe_state_suspend = NULL; + } + } + } + rc = led_classdev_register(&led->pdev->dev, &fnode->cdev); - if (rc) { + if (rc < 0) { dev_err(&led->pdev->dev, "Unable to register led node %d\n", fnode->id); return rc; } + fnode->cdev.dev->of_node = node; fnode->pinctrl = devm_pinctrl_get(fnode->cdev.dev); if (IS_ERR_OR_NULL(fnode->pinctrl)) { - dev_err(&led->pdev->dev, "No pinctrl defined\n"); + dev_warn(&led->pdev->dev, "No pinctrl defined\n"); fnode->pinctrl = NULL; } else { fnode->gpio_state_active = @@ -436,34 +835,64 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, } static int qpnp_flash_led_parse_and_register_switch(struct qpnp_flash_led *led, + struct flash_switch_data *snode, struct device_node *node) { - int rc; + int rc = 0; - rc = of_property_read_string(node, "qcom,led-name", - &led->snode->cdev.name); - if (rc) { - dev_err(&led->pdev->dev, "Failed to read switch node name\n"); + rc = of_property_read_string(node, "qcom,led-name", &snode->cdev.name); + if (rc < 0) { + dev_err(&led->pdev->dev, + "Failed to read switch node name, rc=%d\n", rc); return rc; } rc = of_property_read_string(node, "qcom,default-led-trigger", - &led->snode->cdev.default_trigger); - if (rc) { - dev_err(&led->pdev->dev, "Unable to read trigger name\n"); + &snode->cdev.default_trigger); + if (rc < 0) { + dev_err(&led->pdev->dev, + "Unable to read trigger name, rc=%d\n", rc); + return rc; + } + + rc = of_property_read_u32(node, "qcom,led-mask", &snode->led_mask); + if (rc < 0) { + dev_err(&led->pdev->dev, "Unable to read led mask rc=%d\n", rc); + return rc; + } + + if (snode->led_mask < 1 || snode->led_mask > 7) { + dev_err(&led->pdev->dev, "Invalid value for led-mask\n"); + return -EINVAL; + } + + rc = qpnp_flash_led_regulator_parse_dt(led, snode, node); + if (rc < 0) { + dev_err(&led->pdev->dev, + "Unable to parse regulator data, rc=%d\n", rc); return rc; } - led->snode->pdev = led->pdev; - led->snode->cdev.brightness_set = qpnp_flash_led_brightness_set; - led->snode->cdev.brightness_get = qpnp_flash_led_brightness_get; - rc = led_classdev_register(&led->pdev->dev, &led->snode->cdev); - if (rc) { + if (snode->num_regulators) { + rc = qpnp_flash_led_regulator_setup(led, snode, true); + if (rc < 0) { + dev_err(&led->pdev->dev, + "Unable to setup regulator, rc=%d\n", rc); + return rc; + } + } + + snode->pdev = led->pdev; + snode->cdev.brightness_set = qpnp_flash_led_brightness_set; + snode->cdev.brightness_get = qpnp_flash_led_brightness_get; + rc = led_classdev_register(&led->pdev->dev, &snode->cdev); + if (rc < 0) { dev_err(&led->pdev->dev, "Unable to register led switch node\n"); return rc; } + snode->cdev.dev->of_node = node; return 0; } @@ -486,6 +915,14 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led, return rc; } + rc = of_property_read_u32(node, "qcom,hw-strobe-option", &val); + if (!rc) { + led->pdata->hw_strobe_option = (u8)val; + } else if (rc != -EINVAL) { + dev_err(&led->pdev->dev, "Unable to parse hw strobe option\n"); + return rc; + } + return 0; } @@ -493,6 +930,7 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) { struct qpnp_flash_led *led; struct device_node *node, *temp; + const char *temp_string; unsigned int base; int rc, i = 0; @@ -503,7 +941,7 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) } rc = of_property_read_u32(node, "reg", &base); - if (rc) { + if (rc < 0) { dev_err(&pdev->dev, "Couldn't find reg in node %s, rc = %d\n", node->full_name, rc); return rc; @@ -528,56 +966,77 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) return -ENOMEM; rc = qpnp_flash_led_parse_common_dt(led, node); - if (rc) { + if (rc < 0) { dev_err(&pdev->dev, "Failed to parse common flash LED device tree\n"); return rc; } - for_each_child_of_node(node, temp) - led->num_led_nodes++; - if (!led->num_led_nodes) { + for_each_available_child_of_node(node, temp) { + rc = of_property_read_string(temp, "label", &temp_string); + if (rc < 0) { + dev_err(&pdev->dev, + "Failed to parse label, rc=%d\n", rc); + return rc; + } + + if (!strcmp("switch", temp_string)) { + led->num_snodes++; + } else if (!strcmp("flash", temp_string) || + !strcmp("torch", temp_string)) { + led->num_fnodes++; + } else { + dev_err(&pdev->dev, + "Invalid label for led node\n"); + return -EINVAL; + } + } + + if (!led->num_fnodes) { dev_err(&pdev->dev, "No LED nodes defined\n"); return -ECHILD; } - led->fnode = devm_kzalloc(&pdev->dev, - sizeof(struct flash_node_data) * (--led->num_led_nodes), - GFP_KERNEL); + led->fnode = devm_kcalloc(&pdev->dev, led->num_fnodes, + sizeof(*led->fnode), + GFP_KERNEL); if (!led->fnode) return -ENOMEM; + led->snode = devm_kcalloc(&pdev->dev, led->num_snodes, + sizeof(*led->snode), + GFP_KERNEL); + if (!led->snode) + return -ENOMEM; + temp = NULL; - for (i = 0; i < led->num_led_nodes; i++) { - temp = of_get_next_child(node, temp); + for (i = 0; i < led->num_fnodes; i++) { + temp = of_get_next_available_child(node, temp); rc = qpnp_flash_led_parse_each_led_dt(led, &led->fnode[i], temp); - if (rc) { + if (rc < 0) { dev_err(&pdev->dev, - "Unable to parse flash node %d\n", i); + "Unable to parse flash node %d rc=%d\n", i, rc); goto error_led_register; } } - led->num_avail_leds = i; - - led->snode = devm_kzalloc(&pdev->dev, - sizeof(struct flash_switch_data), GFP_KERNEL); - if (!led->snode) { - rc = -ENOMEM; - goto error_led_register; - } - temp = of_get_next_child(node, temp); - rc = qpnp_flash_led_parse_and_register_switch(led, temp); - if (rc) { - dev_err(&pdev->dev, - "Unable to parse and register switch node\n"); - goto error_led_register; + for (i = 0; i < led->num_snodes; i++) { + temp = of_get_next_available_child(node, temp); + rc = qpnp_flash_led_parse_and_register_switch(led, + &led->snode[i], temp); + if (rc < 0) { + dev_err(&pdev->dev, + "Unable to parse and register switch node, rc=%d\n", + rc); + goto error_switch_register; + } } rc = qpnp_flash_led_init_settings(led); - if (rc) { - dev_err(&pdev->dev, "Failed to initialize flash LED\n"); + if (rc < 0) { + dev_err(&pdev->dev, + "Failed to initialize flash LED, rc=%d\n", rc); goto error_switch_register; } @@ -588,7 +1047,9 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) return 0; error_switch_register: - led_classdev_unregister(&led->snode->cdev); + while (i > 0) + led_classdev_unregister(&led->snode[--i].cdev); + i = led->num_fnodes; error_led_register: while (i > 0) led_classdev_unregister(&led->fnode[--i].cdev); @@ -599,9 +1060,21 @@ error_led_register: static int qpnp_flash_led_remove(struct platform_device *pdev) { struct qpnp_flash_led *led = dev_get_drvdata(&pdev->dev); - int i = led->num_led_nodes; + int i; + + for (i = 0; i < led->num_snodes; i++) { + if (led->snode[i].num_regulators) { + if (led->snode[i].regulator_on) + qpnp_flash_led_regulator_enable(led, + &led->snode[i], false); + qpnp_flash_led_regulator_setup(led, + &led->snode[i], false); + } + } - led_classdev_unregister(&led->snode->cdev); + while (i > 0) + led_classdev_unregister(&led->snode[--i].cdev); + i = led->num_fnodes; while (i > 0) led_classdev_unregister(&led->fnode[--i].cdev); diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c index 83392f856dfd..22b9e34ceb75 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c @@ -1741,6 +1741,7 @@ static void bch_btree_gc(struct cache_set *c) do { ret = btree_root(gc_root, c, &op, &writes, &stats); closure_sync(&writes); + cond_resched(); if (ret && ret != -EAGAIN) pr_warn("gc failed!"); @@ -2162,8 +2163,10 @@ int bch_btree_insert_check_key(struct btree *b, struct btree_op *op, rw_lock(true, b, b->level); if (b->key.ptr[0] != btree_ptr || - b->seq != seq + 1) + b->seq != seq + 1) { + op->lock = b->level; goto out; + } } SET_KEY_PTRS(check_key, 1); diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 679a093a3bf6..8d0ead98eb6e 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -685,6 +685,8 @@ static void bcache_device_link(struct bcache_device *d, struct cache_set *c, WARN(sysfs_create_link(&d->kobj, &c->kobj, "cache") || sysfs_create_link(&c->kobj, &d->kobj, d->name), "Couldn't create device <-> cache set symlinks"); + + clear_bit(BCACHE_DEV_UNLINK_DONE, &d->flags); } static void bcache_device_detach(struct bcache_device *d) @@ -847,8 +849,11 @@ void bch_cached_dev_run(struct cached_dev *dc) buf[SB_LABEL_SIZE] = '\0'; env[2] = kasprintf(GFP_KERNEL, "CACHED_LABEL=%s", buf); - if (atomic_xchg(&dc->running, 1)) + if (atomic_xchg(&dc->running, 1)) { + kfree(env[1]); + kfree(env[2]); return; + } if (!d->c && BDEV_STATE(&dc->sb) != BDEV_STATE_NONE) { @@ -1933,6 +1938,8 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, else err = "device busy"; mutex_unlock(&bch_register_lock); + if (attr == &ksysfs_register_quiet) + goto out; } goto err; } @@ -1971,8 +1978,7 @@ out: err_close: blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); err: - if (attr != &ksysfs_register_quiet) - pr_info("error opening %s: %s", path, err); + pr_info("error opening %s: %s", path, err); ret = -EINVAL; goto out; } @@ -2066,8 +2072,10 @@ static int __init bcache_init(void) closure_debug_init(); bcache_major = register_blkdev(0, "bcache"); - if (bcache_major < 0) + if (bcache_major < 0) { + unregister_reboot_notifier(&reboot); return bcache_major; + } if (!(bcache_wq = create_workqueue("bcache")) || !(bcache_kobj = kobject_create_and_add("bcache", fs_kobj)) || diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c index b23f88d9f18c..b9346cd9cda1 100644 --- a/drivers/md/bcache/writeback.c +++ b/drivers/md/bcache/writeback.c @@ -323,6 +323,10 @@ void bcache_dev_sectors_dirty_add(struct cache_set *c, unsigned inode, static bool dirty_pred(struct keybuf *buf, struct bkey *k) { + struct cached_dev *dc = container_of(buf, struct cached_dev, writeback_keys); + + BUG_ON(KEY_INODE(k) != dc->disk.id); + return KEY_DIRTY(k); } @@ -372,11 +376,24 @@ next: } } +/* + * Returns true if we scanned the entire disk + */ static bool refill_dirty(struct cached_dev *dc) { struct keybuf *buf = &dc->writeback_keys; + struct bkey start = KEY(dc->disk.id, 0, 0); struct bkey end = KEY(dc->disk.id, MAX_KEY_OFFSET, 0); - bool searched_from_start = false; + struct bkey start_pos; + + /* + * make sure keybuf pos is inside the range for this disk - at bringup + * we might not be attached yet so this disk's inode nr isn't + * initialized then + */ + if (bkey_cmp(&buf->last_scanned, &start) < 0 || + bkey_cmp(&buf->last_scanned, &end) > 0) + buf->last_scanned = start; if (dc->partial_stripes_expensive) { refill_full_stripes(dc); @@ -384,14 +401,20 @@ static bool refill_dirty(struct cached_dev *dc) return false; } - if (bkey_cmp(&buf->last_scanned, &end) >= 0) { - buf->last_scanned = KEY(dc->disk.id, 0, 0); - searched_from_start = true; - } - + start_pos = buf->last_scanned; bch_refill_keybuf(dc->disk.c, buf, &end, dirty_pred); - return bkey_cmp(&buf->last_scanned, &end) >= 0 && searched_from_start; + if (bkey_cmp(&buf->last_scanned, &end) < 0) + return false; + + /* + * If we get to the end start scanning again from the beginning, and + * only scan up to where we initially started scanning from: + */ + buf->last_scanned = start; + bch_refill_keybuf(dc->disk.c, buf, &start_pos, dirty_pred); + + return bkey_cmp(&buf->last_scanned, &start_pos) >= 0; } static int bch_writeback_thread(void *arg) diff --git a/drivers/md/bcache/writeback.h b/drivers/md/bcache/writeback.h index 0a9dab187b79..073a042aed24 100644 --- a/drivers/md/bcache/writeback.h +++ b/drivers/md/bcache/writeback.h @@ -63,7 +63,8 @@ static inline bool should_writeback(struct cached_dev *dc, struct bio *bio, static inline void bch_writeback_queue(struct cached_dev *dc) { - wake_up_process(dc->writeback_thread); + if (!IS_ERR_OR_NULL(dc->writeback_thread)) + wake_up_process(dc->writeback_thread); } static inline void bch_writeback_add(struct cached_dev *dc) diff --git a/drivers/md/dm-exception-store.h b/drivers/md/dm-exception-store.h index fae34e7a0b1e..12b5216c2cfe 100644 --- a/drivers/md/dm-exception-store.h +++ b/drivers/md/dm-exception-store.h @@ -69,7 +69,7 @@ struct dm_exception_store_type { * Update the metadata with this exception. */ void (*commit_exception) (struct dm_exception_store *store, - struct dm_exception *e, + struct dm_exception *e, int valid, void (*callback) (void *, int success), void *callback_context); diff --git a/drivers/md/dm-req-crypt.c b/drivers/md/dm-req-crypt.c index dd3e9d97c75b..0ec61ee586b7 100644 --- a/drivers/md/dm-req-crypt.c +++ b/drivers/md/dm-req-crypt.c @@ -873,6 +873,7 @@ static int req_crypt_endio(struct dm_target *ti, struct request *clone, /* If it is for ICE, free up req_io and return */ if (encryption_mode == DM_REQ_CRYPT_ENCRYPTION_MODE_TRANSPARENT) { mempool_free(req_io, req_io_pool); + err = error; goto submit_request; } @@ -999,26 +1000,28 @@ submit_request: } -static void req_crypt_dtr(struct dm_target *ti) +static void deconfigure_qcrypto(void) { - DMDEBUG("dm-req-crypt Destructor.\n"); - if (req_page_pool) { mempool_destroy(req_page_pool); req_page_pool = NULL; } - if (req_io_pool) { - mempool_destroy(req_io_pool); - req_io_pool = NULL; - } if (req_scatterlist_pool) { mempool_destroy(req_scatterlist_pool); req_scatterlist_pool = NULL; } - kfree(ice_settings); - ice_settings = NULL; + if (req_crypt_split_io_queue) { + destroy_workqueue(req_crypt_split_io_queue); + req_crypt_split_io_queue = NULL; + } + if (req_crypt_queue) { + destroy_workqueue(req_crypt_queue); + req_crypt_queue = NULL; + } + + kmem_cache_destroy(_req_dm_scatterlist_pool); mutex_lock(&engine_list_mutex); kfree(pfe_eng); @@ -1031,16 +1034,21 @@ static void req_crypt_dtr(struct dm_target *ti) crypto_free_ablkcipher(tfm); tfm = NULL; } - if (req_crypt_split_io_queue) { - destroy_workqueue(req_crypt_split_io_queue); - req_crypt_split_io_queue = NULL; - } - if (req_crypt_queue) { - destroy_workqueue(req_crypt_queue); - req_crypt_queue = NULL; +} + +static void req_crypt_dtr(struct dm_target *ti) +{ + DMDEBUG("dm-req-crypt Destructor.\n"); + + mempool_destroy(req_io_pool); + req_io_pool = NULL; + + if (encryption_mode == DM_REQ_CRYPT_ENCRYPTION_MODE_TRANSPARENT) { + kfree(ice_settings); + ice_settings = NULL; + } else { + deconfigure_qcrypto(); } - if (_req_dm_scatterlist_pool) - kmem_cache_destroy(_req_dm_scatterlist_pool); if (_req_crypt_io_pool) kmem_cache_destroy(_req_crypt_io_pool); @@ -1051,6 +1059,128 @@ static void req_crypt_dtr(struct dm_target *ti) } } +static int configure_qcrypto(void) +{ + struct crypto_engine_entry *eng_list = NULL; + struct block_device *bdev = NULL; + int err = DM_REQ_CRYPT_ERROR, i; + struct request_queue *q = NULL; + + bdev = dev->bdev; + q = bdev_get_queue(bdev); + blk_queue_max_hw_sectors(q, DM_REQ_CRYPT_QUEUE_SIZE); + + /* Allocate the crypto alloc blk cipher and keep the handle */ + tfm = crypto_alloc_ablkcipher("qcom-xts(aes)", 0, 0); + if (IS_ERR(tfm)) { + DMERR("%s ablkcipher tfm allocation failed : error\n", + __func__); + tfm = NULL; + goto exit_err; + } + + num_engines_fde = num_engines_pfe = 0; + + mutex_lock(&engine_list_mutex); + num_engines = (dm_qcrypto_func.get_num_engines)(); + if (!num_engines) { + DMERR(KERN_INFO "%s qcrypto_get_num_engines failed\n", + __func__); + err = DM_REQ_CRYPT_ERROR; + mutex_unlock(&engine_list_mutex); + goto exit_err; + } + + eng_list = kcalloc(num_engines, sizeof(*eng_list), GFP_KERNEL); + if (eng_list == NULL) { + DMERR("%s engine list allocation failed\n", __func__); + err = DM_REQ_CRYPT_ERROR; + mutex_unlock(&engine_list_mutex); + goto exit_err; + } + + (dm_qcrypto_func.get_engine_list)(num_engines, eng_list); + + for (i = 0; i < num_engines; i++) { + if (eng_list[i].ce_device == FDE_KEY_ID) + num_engines_fde++; + if (eng_list[i].ce_device == PFE_KEY_ID) + num_engines_pfe++; + } + + fde_eng = kcalloc(num_engines_fde, sizeof(*fde_eng), GFP_KERNEL); + if (fde_eng == NULL) { + DMERR("%s fde engine list allocation failed\n", __func__); + mutex_unlock(&engine_list_mutex); + goto exit_err; + } + + pfe_eng = kcalloc(num_engines_pfe, sizeof(*pfe_eng), GFP_KERNEL); + if (pfe_eng == NULL) { + DMERR("%s pfe engine list allocation failed\n", __func__); + mutex_unlock(&engine_list_mutex); + goto exit_err; + } + + fde_cursor = 0; + pfe_cursor = 0; + + for (i = 0; i < num_engines; i++) { + if (eng_list[i].ce_device == FDE_KEY_ID) + fde_eng[fde_cursor++] = eng_list[i]; + if (eng_list[i].ce_device == PFE_KEY_ID) + pfe_eng[pfe_cursor++] = eng_list[i]; + } + + fde_cursor = 0; + pfe_cursor = 0; + mutex_unlock(&engine_list_mutex); + + _req_dm_scatterlist_pool = kmem_cache_create("req_dm_scatterlist", + sizeof(struct scatterlist) * MAX_SG_LIST, + __alignof__(struct scatterlist), 0, NULL); + if (!_req_dm_scatterlist_pool) + goto exit_err; + + req_crypt_queue = alloc_workqueue("req_cryptd", + WQ_UNBOUND | + WQ_CPU_INTENSIVE | + WQ_MEM_RECLAIM, + 0); + if (!req_crypt_queue) { + DMERR("%s req_crypt_queue not allocated\n", __func__); + goto exit_err; + } + + req_crypt_split_io_queue = alloc_workqueue("req_crypt_split", + WQ_UNBOUND | + WQ_CPU_INTENSIVE | + WQ_MEM_RECLAIM, + 0); + if (!req_crypt_split_io_queue) { + DMERR("%s req_crypt_split_io_queue not allocated\n", __func__); + goto exit_err; + } + req_scatterlist_pool = mempool_create_slab_pool(MIN_IOS, + _req_dm_scatterlist_pool); + if (!req_scatterlist_pool) { + DMERR("%s req_scatterlist_pool is not allocated\n", __func__); + err = -ENOMEM; + goto exit_err; + } + + req_page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0); + if (!req_page_pool) { + DMERR("%s req_page_pool not allocated\n", __func__); + goto exit_err; + } + + err = 0; + +exit_err: + kfree(eng_list); + return err; +} /* * Construct an encryption mapping: @@ -1058,12 +1188,10 @@ static void req_crypt_dtr(struct dm_target *ti) */ static int req_crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) { + int err = DM_REQ_CRYPT_ERROR; unsigned long long tmpll; char dummy; - int err = DM_REQ_CRYPT_ERROR, i; - struct crypto_engine_entry *eng_list = NULL; - struct block_device *bdev = NULL; - struct request_queue *q = NULL; + int ret; DMDEBUG("dm-req-crypt Constructor.\n"); @@ -1122,154 +1250,48 @@ static int req_crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) goto ctr_exit; } - _req_dm_scatterlist_pool = kmem_cache_create("req_dm_scatterlist", - sizeof(struct scatterlist) * MAX_SG_LIST, - __alignof__(struct scatterlist), 0, NULL); - if (!_req_dm_scatterlist_pool) { - err = DM_REQ_CRYPT_ERROR; - goto ctr_exit; - } - encryption_mode = DM_REQ_CRYPT_ENCRYPTION_MODE_CRYPTO; if (argc >= 7 && argv[6]) { - if (!strcmp(argv[6], "ice")) { + if (!strcmp(argv[6], "ice")) encryption_mode = DM_REQ_CRYPT_ENCRYPTION_MODE_TRANSPARENT; - ice_settings = - kzalloc(sizeof(struct ice_crypto_setting), - GFP_KERNEL); - if (!ice_settings) { - err = -ENOMEM; - goto ctr_exit; - } - ice_settings->key_size = ICE_CRYPTO_KEY_SIZE_128; - ice_settings->algo_mode = ICE_CRYPTO_ALGO_MODE_AES_XTS; - ice_settings->key_mode = ICE_CRYPTO_USE_LUT_SW_KEY; - if (kstrtou16(argv[1], 10, &ice_settings->key_index) || - ice_settings->key_index < 0 || - ice_settings->key_index > - MAX_MSM_ICE_KEY_LUT_SIZE) { - DMERR("%s Err: key index %d received for ICE\n", - __func__, ice_settings->key_index); - err = DM_REQ_CRYPT_ERROR; - goto ctr_exit; - } - } - } - - if (encryption_mode != DM_REQ_CRYPT_ENCRYPTION_MODE_TRANSPARENT) { - bdev = dev->bdev; - q = bdev_get_queue(bdev); - blk_queue_max_hw_sectors(q, DM_REQ_CRYPT_QUEUE_SIZE); - } - - req_crypt_queue = alloc_workqueue("req_cryptd", - WQ_UNBOUND | - WQ_CPU_INTENSIVE| - WQ_MEM_RECLAIM, - 0); - if (!req_crypt_queue) { - DMERR("%s req_crypt_queue not allocated\n", __func__); - err = DM_REQ_CRYPT_ERROR; - goto ctr_exit; - } - - req_crypt_split_io_queue = alloc_workqueue("req_crypt_split", - WQ_UNBOUND | - WQ_CPU_INTENSIVE | - WQ_MEM_RECLAIM, - 0); - if (!req_crypt_split_io_queue) { - DMERR("%s req_crypt_split_io_queue not allocated\n", __func__); - err = DM_REQ_CRYPT_ERROR; - goto ctr_exit; - } - - /* Allocate the crypto alloc blk cipher and keep the handle */ - tfm = crypto_alloc_ablkcipher("qcom-xts(aes)", 0, 0); - if (IS_ERR(tfm)) { - DMERR("%s ablkcipher tfm allocation failed : error\n", - __func__); - err = DM_REQ_CRYPT_ERROR; - tfm = NULL; - goto ctr_exit; - } - - num_engines_fde = num_engines_pfe = 0; - - mutex_lock(&engine_list_mutex); - num_engines = (dm_qcrypto_func.get_num_engines)(); - if (!num_engines) { - DMERR(KERN_INFO "%s qcrypto_get_num_engines failed\n", - __func__); - err = -DM_REQ_CRYPT_ERROR; - mutex_unlock(&engine_list_mutex); - goto ctr_exit; - } - - eng_list = kcalloc(num_engines, sizeof(*eng_list), GFP_KERNEL); - if (NULL == eng_list) { - DMERR("%s engine list allocation failed\n", __func__); - mutex_unlock(&engine_list_mutex); - goto ctr_exit; - } - - (dm_qcrypto_func.get_engine_list)(num_engines, eng_list); - - for (i = 0; i < num_engines; i++) { - if (eng_list[i].ce_device == FDE_KEY_ID) - num_engines_fde++; - if (eng_list[i].ce_device == PFE_KEY_ID) - num_engines_pfe++; } - fde_eng = kcalloc(num_engines_fde, sizeof(*fde_eng), GFP_KERNEL); - if (NULL == fde_eng) { - DMERR("%s fde engine list allocation failed\n", __func__); - mutex_unlock(&engine_list_mutex); - goto ctr_exit; - } - - pfe_eng = kcalloc(num_engines_pfe, sizeof(*pfe_eng), GFP_KERNEL); - if (NULL == pfe_eng) { - DMERR("%s pfe engine list allocation failed\n", __func__); - mutex_unlock(&engine_list_mutex); - goto ctr_exit; - } - - fde_cursor = 0; - pfe_cursor = 0; - - for (i = 0; i < num_engines; i++) { - if (eng_list[i].ce_device == FDE_KEY_ID) - fde_eng[fde_cursor++] = eng_list[i]; - if (eng_list[i].ce_device == PFE_KEY_ID) - pfe_eng[pfe_cursor++] = eng_list[i]; + if (encryption_mode == DM_REQ_CRYPT_ENCRYPTION_MODE_TRANSPARENT) { + /* configure ICE settings */ + ice_settings = + kzalloc(sizeof(struct ice_crypto_setting), GFP_KERNEL); + if (!ice_settings) { + err = -ENOMEM; + goto ctr_exit; + } + ice_settings->key_size = ICE_CRYPTO_KEY_SIZE_128; + ice_settings->algo_mode = ICE_CRYPTO_ALGO_MODE_AES_XTS; + ice_settings->key_mode = ICE_CRYPTO_USE_LUT_SW_KEY; + if (kstrtou16(argv[1], 0, &ice_settings->key_index) || + ice_settings->key_index < 0 || + ice_settings->key_index > MAX_MSM_ICE_KEY_LUT_SIZE) { + DMERR("%s Err: key index %d received for ICE\n", + __func__, ice_settings->key_index); + err = DM_REQ_CRYPT_ERROR; + goto ctr_exit; + } + } else { + ret = configure_qcrypto(); + if (ret) { + DMERR("%s failed to configure qcrypto\n", __func__); + err = ret; + goto ctr_exit; + } } - fde_cursor = 0; - pfe_cursor = 0; - mutex_unlock(&engine_list_mutex); - req_io_pool = mempool_create_slab_pool(MIN_IOS, _req_crypt_io_pool); - BUG_ON(!req_io_pool); if (!req_io_pool) { DMERR("%s req_io_pool not allocated\n", __func__); - err = DM_REQ_CRYPT_ERROR; + err = -ENOMEM; goto ctr_exit; } - req_page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0); - if (!req_page_pool) { - DMERR("%s req_page_pool not allocated\n", __func__); - err = DM_REQ_CRYPT_ERROR; - goto ctr_exit; - } - - req_scatterlist_pool = mempool_create_slab_pool(MIN_IOS, - _req_dm_scatterlist_pool); - BUG_ON(!req_scatterlist_pool); - /* * If underlying device supports flush/discard, mapped target * should also allow it @@ -1284,7 +1306,6 @@ ctr_exit: if (err) req_crypt_dtr(ti); - kfree(eng_list); return err; } diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c index 3164b8bce294..4d3909393f2c 100644 --- a/drivers/md/dm-snap-persistent.c +++ b/drivers/md/dm-snap-persistent.c @@ -695,7 +695,7 @@ static int persistent_prepare_exception(struct dm_exception_store *store, } static void persistent_commit_exception(struct dm_exception_store *store, - struct dm_exception *e, + struct dm_exception *e, int valid, void (*callback) (void *, int success), void *callback_context) { @@ -704,6 +704,9 @@ static void persistent_commit_exception(struct dm_exception_store *store, struct core_exception ce; struct commit_callback *cb; + if (!valid) + ps->valid = 0; + ce.old_chunk = e->old_chunk; ce.new_chunk = e->new_chunk; write_exception(ps, ps->current_committed++, &ce); diff --git a/drivers/md/dm-snap-transient.c b/drivers/md/dm-snap-transient.c index 9b7c8c8049d6..4d50a12cf00c 100644 --- a/drivers/md/dm-snap-transient.c +++ b/drivers/md/dm-snap-transient.c @@ -52,12 +52,12 @@ static int transient_prepare_exception(struct dm_exception_store *store, } static void transient_commit_exception(struct dm_exception_store *store, - struct dm_exception *e, + struct dm_exception *e, int valid, void (*callback) (void *, int success), void *callback_context) { /* Just succeed */ - callback(callback_context, 1); + callback(callback_context, valid); } static void transient_usage(struct dm_exception_store *store, diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index c06b74e91cd6..61f184ad081c 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -1438,8 +1438,9 @@ static void __invalidate_snapshot(struct dm_snapshot *s, int err) dm_table_event(s->ti->table); } -static void pending_complete(struct dm_snap_pending_exception *pe, int success) +static void pending_complete(void *context, int success) { + struct dm_snap_pending_exception *pe = context; struct dm_exception *e; struct dm_snapshot *s = pe->snap; struct bio *origin_bios = NULL; @@ -1509,24 +1510,13 @@ out: free_pending_exception(pe); } -static void commit_callback(void *context, int success) -{ - struct dm_snap_pending_exception *pe = context; - - pending_complete(pe, success); -} - static void complete_exception(struct dm_snap_pending_exception *pe) { struct dm_snapshot *s = pe->snap; - if (unlikely(pe->copy_error)) - pending_complete(pe, 0); - - else - /* Update the metadata if we are persistent */ - s->store->type->commit_exception(s->store, &pe->e, - commit_callback, pe); + /* Update the metadata if we are persistent */ + s->store->type->commit_exception(s->store, &pe->e, !pe->copy_error, + pending_complete, pe); } /* diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 63903a5a5d9e..a1cc797fe88f 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -3453,8 +3453,8 @@ static void pool_postsuspend(struct dm_target *ti) struct pool_c *pt = ti->private; struct pool *pool = pt->pool; - cancel_delayed_work(&pool->waker); - cancel_delayed_work(&pool->no_space_timeout); + cancel_delayed_work_sync(&pool->waker); + cancel_delayed_work_sync(&pool->no_space_timeout); flush_workqueue(pool->wq); (void) commit(pool); } diff --git a/drivers/md/dm.c b/drivers/md/dm.c index d7e7eeba424c..c46c9dc9b667 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1191,6 +1191,8 @@ static void dm_unprep_request(struct request *rq) if (clone) free_rq_clone(clone); + else if (!tio->md->queue->mq_ops) + free_rq_tio(tio); } /* diff --git a/drivers/md/persistent-data/dm-space-map-metadata.c b/drivers/md/persistent-data/dm-space-map-metadata.c index fca6dbcf9a47..7e44005595c1 100644 --- a/drivers/md/persistent-data/dm-space-map-metadata.c +++ b/drivers/md/persistent-data/dm-space-map-metadata.c @@ -152,12 +152,9 @@ static int brb_peek(struct bop_ring_buffer *brb, struct block_op *result) static int brb_pop(struct bop_ring_buffer *brb) { - struct block_op *bop; - if (brb_empty(brb)) return -ENODATA; - bop = brb->bops + brb->begin; brb->begin = brb_next(brb, brb->begin); return 0; diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index c38ef1a72b4a..e2a3833170e3 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -2313,9 +2313,9 @@ static int dvb_frontend_ioctl_legacy(struct file *file, dev_dbg(fe->dvb->device, "%s: current delivery system on cache: %d, V3 type: %d\n", __func__, c->delivery_system, fe->ops.info.type); - /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't - * do it, it is done for it. */ - info->caps |= FE_CAN_INVERSION_AUTO; + /* Set CAN_INVERSION_AUTO bit on in other than oneshot mode */ + if (!(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) + info->caps |= FE_CAN_INVERSION_AUTO; err = 0; break; } diff --git a/drivers/media/dvb-frontends/tda1004x.c b/drivers/media/dvb-frontends/tda1004x.c index 0e209b56c76c..c6abeb4fba9d 100644 --- a/drivers/media/dvb-frontends/tda1004x.c +++ b/drivers/media/dvb-frontends/tda1004x.c @@ -903,9 +903,18 @@ static int tda1004x_get_fe(struct dvb_frontend *fe) { struct dtv_frontend_properties *fe_params = &fe->dtv_property_cache; struct tda1004x_state* state = fe->demodulator_priv; + int status; dprintk("%s\n", __func__); + status = tda1004x_read_byte(state, TDA1004X_STATUS_CD); + if (status == -1) + return -EIO; + + /* Only update the properties cache if device is locked */ + if (!(status & 8)) + return 0; + // inversion status fe_params->inversion = INVERSION_OFF; if (tda1004x_read_byte(state, TDA1004X_CONFC1) & 0x20) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 5631ec004eed..01adcdc52346 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -1960,10 +1960,9 @@ static int adv76xx_isr(struct v4l2_subdev *sd, u32 status, bool *handled) } /* tx 5v detect */ - tx_5v = io_read(sd, 0x70) & info->cable_det_mask; + tx_5v = irq_reg_0x70 & info->cable_det_mask; if (tx_5v) { v4l2_dbg(1, debug, sd, "%s: tx_5v: 0x%x\n", __func__, tx_5v); - io_write(sd, 0x71, tx_5v); adv76xx_s_detect_tx_5v_ctrl(sd); if (handled) *handled = true; diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c index 60a834588767..c1aeb8c43e81 100644 --- a/drivers/media/platform/msm/camera_v2/camera/camera.c +++ b/drivers/media/platform/msm/camera_v2/camera/camera.c @@ -475,6 +475,38 @@ static int camera_v4l2_unsubscribe_event(struct v4l2_fh *fh, return rc; } +static long camera_v4l2_vidioc_private_ioctl(struct file *filep, void *fh, + bool valid_prio, unsigned int cmd, void *arg) +{ + struct camera_v4l2_private *sp = fh_to_private(fh); + struct msm_video_device *pvdev = video_drvdata(filep); + struct msm_camera_private_ioctl_arg *k_ioctl = arg; + long rc = -EINVAL; + + if (WARN_ON(!k_ioctl || !pvdev)) + return -EIO; + + switch (k_ioctl->id) { + case MSM_CAMERA_PRIV_IOCTL_ID_RETURN_BUF: { + struct msm_camera_return_buf ptr, *tmp = NULL; + + MSM_CAM_GET_IOCTL_ARG_PTR(&tmp, &k_ioctl->ioctl_ptr, + sizeof(tmp)); + if (copy_from_user(&ptr, tmp, + sizeof(struct msm_camera_return_buf))) { + return -EFAULT; + } + rc = msm_vb2_return_buf_by_idx(pvdev->vdev->num, sp->stream_id, + ptr.index); + } + break; + default: + pr_debug("unimplemented id %d", k_ioctl->id); + return -EINVAL; + } + return rc; +} + static const struct v4l2_ioctl_ops camera_v4l2_ioctl_ops = { .vidioc_querycap = camera_v4l2_querycap, .vidioc_s_crop = camera_v4l2_s_crop, @@ -499,6 +531,7 @@ static const struct v4l2_ioctl_ops camera_v4l2_ioctl_ops = { /* event subscribe/unsubscribe */ .vidioc_subscribe_event = camera_v4l2_subscribe_event, .vidioc_unsubscribe_event = camera_v4l2_unsubscribe_event, + .vidioc_default = camera_v4l2_vidioc_private_ioctl, }; static int camera_v4l2_fh_open(struct file *filep) @@ -747,10 +780,62 @@ static int camera_v4l2_close(struct file *filep) } #ifdef CONFIG_COMPAT +static long camera_handle_internal_compat_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + long rc = 0; + struct msm_camera_private_ioctl_arg k_ioctl; + void __user *tmp_compat_ioctl_ptr = NULL; + + rc = msm_copy_camera_private_ioctl_args(arg, + &k_ioctl, &tmp_compat_ioctl_ptr); + if (rc < 0) { + pr_err("Subdev cmd %d failed\n", cmd); + return rc; + } + switch (k_ioctl.id) { + case MSM_CAMERA_PRIV_IOCTL_ID_RETURN_BUF: { + if (k_ioctl.size != sizeof(struct msm_camera_return_buf)) { + pr_debug("Invalid size for id %d with size %d", + k_ioctl.id, k_ioctl.size); + return -EINVAL; + } + k_ioctl.ioctl_ptr = (__u64)tmp_compat_ioctl_ptr; + if (!k_ioctl.ioctl_ptr) { + pr_debug("Invalid ptr for id %d", k_ioctl.id); + return -EINVAL; + } + rc = camera_v4l2_vidioc_private_ioctl(file, file->private_data, + 0, cmd, (void *)&k_ioctl); + } + break; + default: + pr_debug("unimplemented id %d", k_ioctl.id); + return -EINVAL; + } + return rc; +} + long camera_v4l2_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - return -ENOIOCTLCMD; + long ret = 0; + + switch (cmd) { + case VIDIOC_MSM_CAMERA_PRIVATE_IOCTL_CMD: { + ret = camera_handle_internal_compat_ioctl(file, cmd, arg); + if (ret < 0) { + pr_debug("Subdev cmd %d fail\n", cmd); + return ret; + } + } + break; + default: + ret = -ENOIOCTLCMD; + break; + + } + return ret; } #endif static struct v4l2_file_operations camera_v4l2_fops = { diff --git a/drivers/media/platform/msm/camera_v2/fd/Makefile b/drivers/media/platform/msm/camera_v2/fd/Makefile index 82b37a73bfa3..8d01d3a8708d 100644 --- a/drivers/media/platform/msm/camera_v2/fd/Makefile +++ b/drivers/media/platform/msm/camera_v2/fd/Makefile @@ -1,5 +1,8 @@ GCC_VERSION := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc) ccflags-y += -Idrivers/media/video/msm ccflags-y += -Idrivers/media/platform/msm/camera_v2/common +ccflags-y += -Idrivers/media/platform/msm/camera_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_v2/pproc/cpp +ccflags-y += -Idrivers/media/platform/msm/camera_v2/msm_buf_mgr/ obj-$(CONFIG_MSM_FD) += msm_fd_dev.o msm_fd_hw.o diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h index 95465fb24feb..763b6a575326 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -40,6 +40,7 @@ #define VFE40_8952_VERSION 0x10060000 #define VFE40_8976_VERSION 0x10050000 #define VFE40_8937_VERSION 0x10080000 +#define VFE40_8917_VERSION 0x10080001 #define VFE40_8953_VERSION 0x10090000 #define VFE32_8909_VERSION 0x30600 @@ -652,6 +653,7 @@ struct dual_vfe_resource { struct msm_vfe_stats_shared_data *stats_data[MAX_VFE]; struct msm_vfe_axi_shared_data *axi_data[MAX_VFE]; uint32_t wm_reload_mask[MAX_VFE]; + uint32_t epoch_sync_mask; }; struct master_slave_resource_info { diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c index d4f0453d72ff..d42ada769380 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c @@ -101,29 +101,21 @@ static void msm_vfe40_config_irq(struct vfe_device *vfe_dev, uint32_t irq0_mask, uint32_t irq1_mask, enum msm_isp_irq_operation oper) { - uint32_t val; - switch (oper) { case MSM_ISP_IRQ_ENABLE: - val = msm_camera_io_r(vfe_dev->vfe_base + 0x28); - val |= irq0_mask; - msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x28); - val = msm_camera_io_r(vfe_dev->vfe_base + 0x2C); - val |= irq1_mask; - msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x2C); + vfe_dev->irq0_mask |= irq0_mask; + vfe_dev->irq1_mask |= irq1_mask; break; case MSM_ISP_IRQ_DISABLE: - val = msm_camera_io_r(vfe_dev->vfe_base + 0x28); - val &= ~irq0_mask; - msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x28); - val = msm_camera_io_r(vfe_dev->vfe_base + 0x2C); - val &= ~irq1_mask; - msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x2C); + vfe_dev->irq0_mask &= ~irq0_mask; + vfe_dev->irq1_mask &= ~irq1_mask; break; case MSM_ISP_IRQ_SET: - msm_camera_io_w_mb(irq0_mask, vfe_dev->vfe_base + 0x28); - msm_camera_io_w_mb(irq1_mask, vfe_dev->vfe_base + 0x2C); + vfe_dev->irq0_mask = irq0_mask; + vfe_dev->irq1_mask = irq1_mask; } + msm_camera_io_w_mb(vfe_dev->irq0_mask, vfe_dev->vfe_base + 0x28); + msm_camera_io_w_mb(vfe_dev->irq1_mask, vfe_dev->vfe_base + 0x2C); } static int32_t msm_vfe40_init_qos_parms(struct vfe_device *vfe_dev, @@ -326,6 +318,7 @@ static void msm_vfe40_init_hardware_reg(struct vfe_device *vfe_dev) break; case VFE40_8937_VERSION: case VFE40_8953_VERSION: + case VFE40_8917_VERSION: default: ISP_DBG("%s: No special QOS\n", __func__); } @@ -334,10 +327,8 @@ static void msm_vfe40_init_hardware_reg(struct vfe_device *vfe_dev) msm_vfe40_init_vbif_parms(vfe_dev, &vbif_parms); /* BUS_CFG */ msm_camera_io_w(0x10000001, vfe_dev->vfe_base + 0x50); - vfe_dev->irq0_mask = 0xE00000F1; - vfe_dev->irq1_mask = 0xFEFFFFFF; - msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe40_config_irq(vfe_dev, 0x800000E0, 0xFEFFFF7E, + MSM_ISP_IRQ_ENABLE); msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30); msm_camera_io_w_mb(0xFEFFFFFF, vfe_dev->vfe_base + 0x34); msm_camera_io_w(1, vfe_dev->vfe_base + 0x24); @@ -345,15 +336,13 @@ static void msm_vfe40_init_hardware_reg(struct vfe_device *vfe_dev) msm_camera_io_w(0, vfe_dev->vfe_base + 0x30); msm_camera_io_w_mb(0, vfe_dev->vfe_base + 0x34); msm_camera_io_w(1, vfe_dev->vfe_base + 0x24); - msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); } static void msm_vfe40_clear_status_reg(struct vfe_device *vfe_dev) { vfe_dev->irq0_mask = (1 << 31); vfe_dev->irq1_mask = 0; - msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, + msm_vfe40_config_irq(vfe_dev, (1 << 31), 0, MSM_ISP_IRQ_SET); msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30); msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x34); @@ -588,7 +577,6 @@ static void msm_vfe40_read_irq_status(struct vfe_device *vfe_dev, if (*irq_status1 & (1 << 0)) { vfe_dev->error_info.camif_status = msm_camera_io_r(vfe_dev->vfe_base + 0x31C); - vfe_dev->irq1_mask &= ~(1 << 0); msm_vfe40_config_irq(vfe_dev, 0, (1 << 0), MSM_ISP_IRQ_DISABLE); } @@ -811,11 +799,9 @@ static void msm_vfe40_axi_cfg_comp_mask(struct vfe_device *vfe_dev, comp_mask |= (axi_data->composite_info[comp_mask_index]. stream_composite_mask << (comp_mask_index * 8)); - vfe_dev->irq0_mask |= 1 << (comp_mask_index + 25); - msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40); - msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe40_config_irq(vfe_dev, 1 << (comp_mask_index + 25), 0, + MSM_ISP_IRQ_ENABLE); } static void msm_vfe40_axi_clear_comp_mask(struct vfe_device *vfe_dev, @@ -827,27 +813,24 @@ static void msm_vfe40_axi_clear_comp_mask(struct vfe_device *vfe_dev, comp_mask = msm_camera_io_r(vfe_dev->vfe_base + 0x40); comp_mask &= ~(0x7F << (comp_mask_index * 8)); - vfe_dev->irq0_mask &= ~(1 << (comp_mask_index + 25)); - msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40); - msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe40_config_irq(vfe_dev, (1 << (comp_mask_index + 25)), 0, + MSM_ISP_IRQ_DISABLE); } static void msm_vfe40_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - vfe_dev->irq0_mask |= 1 << (stream_info->wm[0] + 8); - msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe40_config_irq(vfe_dev, 1 << (stream_info->wm[0] + 8), 0, + MSM_ISP_IRQ_ENABLE); } static void msm_vfe40_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { vfe_dev->irq0_mask &= ~(1 << (stream_info->wm[0] + 8)); - msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe40_config_irq(vfe_dev, (1 << (stream_info->wm[0] + 8)), 0, + MSM_ISP_IRQ_DISABLE); } static void msm_vfe40_cfg_framedrop(void __iomem *vfe_base, @@ -1087,10 +1070,8 @@ static void msm_vfe40_cfg_fetch_engine(struct vfe_device *vfe_dev, temp |= (1 << 1); msm_camera_io_w(temp, vfe_dev->vfe_base + 0x50); - vfe_dev->irq0_mask &= 0xFEFFFFFF; - vfe_dev->irq0_mask |= (1 << 24); - msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe40_config_irq(vfe_dev, (1 << 24), 0, + MSM_ISP_IRQ_ENABLE); msm_camera_io_w((fe_cfg->fetch_height - 1), vfe_dev->vfe_base + 0x238); @@ -1381,13 +1362,11 @@ static void msm_vfe40_update_camif_state(struct vfe_device *vfe_dev, return; if (update_state == ENABLE_CAMIF) { - msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30); - msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x34); + msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x30); + msm_camera_io_w_mb(0x81, vfe_dev->vfe_base + 0x34); msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x24); - vfe_dev->irq0_mask |= 0xF7; - msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask, - vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe40_config_irq(vfe_dev, 0xF7, 0x81, + MSM_ISP_IRQ_ENABLE); msm_camera_io_w_mb(0x140000, vfe_dev->vfe_base + 0x318); bus_en = @@ -1412,8 +1391,8 @@ static void msm_vfe40_update_camif_state(struct vfe_device *vfe_dev, if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN) update_state = DISABLE_CAMIF; - msm_vfe40_config_irq(vfe_dev, 0, 0, - MSM_ISP_IRQ_SET); + msm_vfe40_config_irq(vfe_dev, 0, 0x81, + MSM_ISP_IRQ_DISABLE); val = msm_camera_io_r(vfe_dev->vfe_base + 0x464); /* disable danger signal */ msm_camera_io_w_mb(val & ~(1 << 8), vfe_dev->vfe_base + 0x464); @@ -1475,6 +1454,7 @@ static void msm_vfe40_axi_cfg_wm_reg( wm_bit_shift = VFE40_WM_BIT_SHIFT; } else if (vfe_dev->vfe_hw_version == VFE40_8976_VERSION || vfe_dev->vfe_hw_version == VFE40_8937_VERSION || + vfe_dev->vfe_hw_version == VFE40_8917_VERSION || vfe_dev->vfe_hw_version == VFE40_8953_VERSION) { burst_len = VFE40_BURST_LEN_8952_VERSION; wm_bit_shift = VFE40_WM_BIT_SHIFT_8976_VERSION; @@ -1895,6 +1875,9 @@ static void msm_vfe40_stats_cfg_comp_mask(struct vfe_device *vfe_dev, comp_mask_reg |= mask_bf_scale << (16 + request_comp_index * 8); atomic_set(stats_comp_mask, stats_mask | atomic_read(stats_comp_mask)); + msm_vfe40_config_irq(vfe_dev, + 1 << (request_comp_index + 29), 0, + MSM_ISP_IRQ_ENABLE); } else { if (!(atomic_read(stats_comp_mask) & stats_mask)) return; @@ -1902,6 +1885,9 @@ static void msm_vfe40_stats_cfg_comp_mask(struct vfe_device *vfe_dev, ~stats_mask & atomic_read(stats_comp_mask)); comp_mask_reg &= ~(mask_bf_scale << (16 + request_comp_index * 8)); + msm_vfe40_config_irq(vfe_dev, + 1 << (request_comp_index + 29), 0, + MSM_ISP_IRQ_DISABLE); } msm_camera_io_w(comp_mask_reg, vfe_dev->vfe_base + 0x44); @@ -1917,20 +1903,18 @@ static void msm_vfe40_stats_cfg_wm_irq_mask( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { - vfe_dev->irq0_mask |= - 1 << (STATS_IDX(stream_info->stream_handle) + 16); - msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe40_config_irq(vfe_dev, + 1 << (STATS_IDX(stream_info->stream_handle) + 16), 0, + MSM_ISP_IRQ_ENABLE); } static void msm_vfe40_stats_clear_wm_irq_mask( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { - vfe_dev->irq0_mask &= - ~(1 << (STATS_IDX(stream_info->stream_handle) + 16)); - msm_vfe40_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe40_config_irq(vfe_dev, + (1 << (STATS_IDX(stream_info->stream_handle) + 16)), 0, + MSM_ISP_IRQ_DISABLE); } static void msm_vfe40_stats_cfg_wm_reg( @@ -1986,6 +1970,7 @@ static void msm_vfe40_stats_cfg_ub(struct vfe_device *vfe_dev) if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION || vfe_dev->vfe_hw_version == VFE40_8939_VERSION || vfe_dev->vfe_hw_version == VFE40_8937_VERSION || + vfe_dev->vfe_hw_version == VFE40_8917_VERSION || vfe_dev->vfe_hw_version == VFE40_8953_VERSION) { stats_burst_len = VFE40_STATS_BURST_LEN_8916_VERSION; ub_offset = VFE40_UB_SIZE_8916; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c index 08b20395813c..388656b9ca30 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c @@ -70,30 +70,22 @@ static void msm_vfe44_config_irq(struct vfe_device *vfe_dev, uint32_t irq0_mask, uint32_t irq1_mask, enum msm_isp_irq_operation oper) { - uint32_t val; - switch (oper) { case MSM_ISP_IRQ_ENABLE: - val = msm_camera_io_r(vfe_dev->vfe_base + 0x28); - val |= irq0_mask; - msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x28); - val = msm_camera_io_r(vfe_dev->vfe_base + 0x2C); - val |= irq1_mask; - msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x2C); + vfe_dev->irq0_mask |= irq0_mask; + vfe_dev->irq1_mask |= irq1_mask; break; case MSM_ISP_IRQ_DISABLE: - val = msm_camera_io_r(vfe_dev->vfe_base + 0x28); - val &= ~irq0_mask; - msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x28); - val = msm_camera_io_r(vfe_dev->vfe_base + 0x2C); - val &= ~irq1_mask; - msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x2C); + vfe_dev->irq0_mask &= ~irq0_mask; + vfe_dev->irq1_mask &= ~irq1_mask; break; case MSM_ISP_IRQ_SET: - msm_camera_io_w_mb(irq0_mask, vfe_dev->vfe_base + 0x28); - msm_camera_io_w_mb(irq1_mask, vfe_dev->vfe_base + 0x2C); + vfe_dev->irq0_mask = irq0_mask; + vfe_dev->irq1_mask = irq1_mask; break; } + msm_camera_io_w_mb(irq0_mask, vfe_dev->vfe_base + 0x28); + msm_camera_io_w_mb(irq1_mask, vfe_dev->vfe_base + 0x2C); } static int32_t msm_vfe44_init_dt_parms(struct vfe_device *vfe_dev, @@ -181,10 +173,8 @@ static void msm_vfe44_init_hardware_reg(struct vfe_device *vfe_dev) /* BUS_CFG */ msm_camera_io_w(0x10000001, vfe_dev->vfe_base + 0x50); - vfe_dev->irq0_mask = 0xE00000F1; - vfe_dev->irq1_mask = 0xFFFFFFFF; - msm_vfe44_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe44_config_irq(vfe_dev, 0x800000E0, 0xFFFFFF7E, + MSM_ISP_IRQ_ENABLE); msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30); msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x34); msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x24); @@ -193,9 +183,7 @@ static void msm_vfe44_init_hardware_reg(struct vfe_device *vfe_dev) static void msm_vfe44_clear_status_reg(struct vfe_device *vfe_dev) { - vfe_dev->irq0_mask = 0x80000000; - vfe_dev->irq1_mask = 0; - msm_vfe44_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, + msm_vfe44_config_irq(vfe_dev, 0x80000000, 0, MSM_ISP_IRQ_SET); msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30); msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x34); @@ -419,7 +407,6 @@ static void msm_vfe44_read_irq_status(struct vfe_device *vfe_dev, if (*irq_status1 & (1 << 0)) { vfe_dev->error_info.camif_status = msm_camera_io_r(vfe_dev->vfe_base + 0x31C); - vfe_dev->irq1_mask &= ~(1 << 0); msm_vfe44_config_irq(vfe_dev, 0, (1 << 0), MSM_ISP_IRQ_DISABLE); } @@ -650,9 +637,8 @@ static void msm_vfe44_axi_cfg_comp_mask(struct vfe_device *vfe_dev, stream_composite_mask << (comp_mask_index * 8)); msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40); - vfe_dev->irq0_mask |= 1 << (comp_mask_index + 25); - msm_vfe44_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe44_config_irq(vfe_dev, 1 << (comp_mask_index + 25), 0, + MSM_ISP_IRQ_ENABLE); } static void msm_vfe44_axi_clear_comp_mask(struct vfe_device *vfe_dev, @@ -664,25 +650,22 @@ static void msm_vfe44_axi_clear_comp_mask(struct vfe_device *vfe_dev, comp_mask &= ~(0x7F << (comp_mask_index * 8)); msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x40); - vfe_dev->irq0_mask &= ~(1 << (comp_mask_index + 25)); - msm_vfe44_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe44_config_irq(vfe_dev, (1 << (comp_mask_index + 25)), 0, + MSM_ISP_IRQ_DISABLE); } static void msm_vfe44_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - vfe_dev->irq0_mask |= 1 << (stream_info->wm[0] + 8); - msm_vfe44_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe44_config_irq(vfe_dev, 1 << (stream_info->wm[0] + 8), 0, + MSM_ISP_IRQ_ENABLE); } static void msm_vfe44_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - vfe_dev->irq0_mask &= ~(1 << (stream_info->wm[0] + 8)); - msm_vfe44_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe44_config_irq(vfe_dev, (1 << (stream_info->wm[0] + 8)), 0, + MSM_ISP_IRQ_DISABLE); } static void msm_vfe44_cfg_framedrop(void __iomem *vfe_base, @@ -918,10 +901,8 @@ static void msm_vfe44_cfg_fetch_engine(struct vfe_device *vfe_dev, temp |= (1 << 1); msm_camera_io_w(temp, vfe_dev->vfe_base + 0x50); - vfe_dev->irq0_mask &= 0xFEFFFFFF; - vfe_dev->irq0_mask |= (1 << 24); - msm_vfe44_config_irq(vfe_dev, vfe_dev->irq0_mask, - vfe_dev->irq1_mask, MSM_ISP_IRQ_SET); + msm_vfe44_config_irq(vfe_dev, (1 << 24), 0, + MSM_ISP_IRQ_SET); msm_camera_io_w((fe_cfg->fetch_height - 1) & 0xFFF, vfe_dev->vfe_base + 0x238); @@ -1045,13 +1026,12 @@ static void msm_vfe44_update_camif_state(struct vfe_device *vfe_dev, return; if (update_state == ENABLE_CAMIF) { - msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x30); - msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x34); + msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x30); + msm_camera_io_w_mb(0x81, vfe_dev->vfe_base + 0x34); msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x24); - vfe_dev->irq0_mask |= 0xF7; - msm_vfe44_config_irq(vfe_dev, vfe_dev->irq0_mask, - vfe_dev->irq1_mask, MSM_ISP_IRQ_SET); + msm_vfe44_config_irq(vfe_dev, 0xF7, 0x81, + MSM_ISP_IRQ_ENABLE); msm_camera_io_w_mb(0x140000, vfe_dev->vfe_base + 0x318); bus_en = @@ -1075,7 +1055,7 @@ static void msm_vfe44_update_camif_state(struct vfe_device *vfe_dev, if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN) update_state = DISABLE_CAMIF; msm_vfe44_config_irq(vfe_dev, 0, - 0, MSM_ISP_IRQ_SET); + 0x81, MSM_ISP_IRQ_DISABLE); val = msm_camera_io_r(vfe_dev->vfe_base + 0xC18); /* disable danger signal */ msm_camera_io_w_mb(val & ~(1 << 8), vfe_dev->vfe_base + 0xC18); @@ -1526,6 +1506,9 @@ static void msm_vfe44_stats_cfg_comp_mask( comp_mask_reg |= mask_bf_scale << (16 + request_comp_index * 8); atomic_set(stats_comp_mask, stats_mask | atomic_read(stats_comp_mask)); + msm_vfe44_config_irq(vfe_dev, + 1 << (request_comp_index + 29), 0, + MSM_ISP_IRQ_ENABLE); } else { if (!(atomic_read(stats_comp_mask) & stats_mask)) return; @@ -1540,6 +1523,9 @@ static void msm_vfe44_stats_cfg_comp_mask( ~stats_mask & atomic_read(stats_comp_mask)); comp_mask_reg &= ~(mask_bf_scale << (16 + request_comp_index * 8)); + msm_vfe44_config_irq(vfe_dev, + 1 << (request_comp_index + 29), 0, + MSM_ISP_IRQ_DISABLE); } msm_camera_io_w(comp_mask_reg, vfe_dev->vfe_base + 0x44); @@ -1555,20 +1541,18 @@ static void msm_vfe44_stats_cfg_wm_irq_mask( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { - vfe_dev->irq0_mask |= - 1 << (STATS_IDX(stream_info->stream_handle) + 15); - msm_vfe44_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe44_config_irq(vfe_dev, + 1 << (STATS_IDX(stream_info->stream_handle) + 15), 0, + MSM_ISP_IRQ_ENABLE); } static void msm_vfe44_stats_clear_wm_irq_mask( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { - vfe_dev->irq0_mask &= - ~(1 << (STATS_IDX(stream_info->stream_handle) + 15)); - msm_vfe44_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe44_config_irq(vfe_dev, + (1 << (STATS_IDX(stream_info->stream_handle) + 15)), 0, + MSM_ISP_IRQ_DISABLE); } static void msm_vfe44_stats_cfg_wm_reg( diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c index 9f815e65edc8..40bb044fde47 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c @@ -92,30 +92,24 @@ static void msm_vfe46_config_irq(struct vfe_device *vfe_dev, uint32_t irq0_mask, uint32_t irq1_mask, enum msm_isp_irq_operation oper) { - uint32_t val; - switch (oper) { case MSM_ISP_IRQ_ENABLE: - val = msm_camera_io_r(vfe_dev->vfe_base + 0x5C); - val |= irq0_mask; - msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x5C); - val = msm_camera_io_r(vfe_dev->vfe_base + 0x60); - val |= irq1_mask; - msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x60); + vfe_dev->irq0_mask |= irq0_mask; + vfe_dev->irq1_mask |= irq1_mask; break; case MSM_ISP_IRQ_DISABLE: - val = msm_camera_io_r(vfe_dev->vfe_base + 0x5C); - val &= ~irq0_mask; - msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x5C); - val = msm_camera_io_r(vfe_dev->vfe_base + 0x60); - val &= ~irq1_mask; - msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x60); + vfe_dev->irq0_mask &= ~irq0_mask; + vfe_dev->irq1_mask &= ~irq1_mask; break; case MSM_ISP_IRQ_SET: - msm_camera_io_w_mb(irq0_mask, vfe_dev->vfe_base + 0x5C); - msm_camera_io_w_mb(irq1_mask, vfe_dev->vfe_base + 0x60); + vfe_dev->irq0_mask = irq0_mask; + vfe_dev->irq1_mask = irq1_mask; break; } + msm_camera_io_w_mb(vfe_dev->irq0_mask, + vfe_dev->vfe_base + 0x5C); + msm_camera_io_w_mb(vfe_dev->irq1_mask, + vfe_dev->vfe_base + 0x60); } static int32_t msm_vfe46_init_dt_parms(struct vfe_device *vfe_dev, @@ -208,20 +202,16 @@ static void msm_vfe46_init_hardware_reg(struct vfe_device *vfe_dev) /* BUS_CFG */ msm_camera_io_w(0x00000001, vfe_dev->vfe_base + 0x84); /* IRQ_MASK/CLEAR */ - vfe_dev->irq0_mask = 0xE00000F1; - vfe_dev->irq1_mask = 0xE1FFFFFF; - msm_vfe46_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe46_config_irq(vfe_dev, 0x810000E0, 0xFFFFFF7E, + MSM_ISP_IRQ_ENABLE); msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x64); msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x68); + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x58); } static void msm_vfe46_clear_status_reg(struct vfe_device *vfe_dev) { - vfe_dev->irq0_mask = 0x80000000; - vfe_dev->irq1_mask = 0x0; - msm_vfe46_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe46_config_irq(vfe_dev, 0x80000000, 0, MSM_ISP_IRQ_SET); msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x64); msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x68); msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x58); @@ -355,7 +345,6 @@ static void msm_vfe46_read_irq_status(struct vfe_device *vfe_dev, if (*irq_status1 & (1 << 0)) { vfe_dev->error_info.camif_status = msm_camera_io_r(vfe_dev->vfe_base + 0x3D0); - vfe_dev->irq1_mask &= ~(1 << 0); msm_vfe46_config_irq(vfe_dev, 0, (1 << 0), MSM_ISP_IRQ_DISABLE); } @@ -587,9 +576,8 @@ static void msm_vfe46_axi_cfg_comp_mask(struct vfe_device *vfe_dev, stream_composite_mask << (comp_mask_index * 8)); msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x74); - vfe_dev->irq0_mask |= 1 << (comp_mask_index + 25); - msm_vfe46_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe46_config_irq(vfe_dev, 1 << (comp_mask_index + 25), 0, + MSM_ISP_IRQ_ENABLE); } static void msm_vfe46_axi_clear_comp_mask(struct vfe_device *vfe_dev, @@ -601,25 +589,22 @@ static void msm_vfe46_axi_clear_comp_mask(struct vfe_device *vfe_dev, comp_mask &= ~(0x7F << (comp_mask_index * 8)); msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x74); - vfe_dev->irq0_mask |= 1 << (comp_mask_index + 25); - msm_vfe46_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe46_config_irq(vfe_dev, 1 << (comp_mask_index + 25), 0, + MSM_ISP_IRQ_DISABLE); } static void msm_vfe46_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - vfe_dev->irq0_mask |= 1 << (stream_info->wm[0] + 8); - msm_vfe46_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe46_config_irq(vfe_dev, 1 << (stream_info->wm[0] + 8), 0, + MSM_ISP_IRQ_ENABLE); } static void msm_vfe46_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - vfe_dev->irq0_mask &= ~(1 << (stream_info->wm[0] + 8)); - msm_vfe46_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe46_config_irq(vfe_dev, (1 << (stream_info->wm[0] + 8)), 0, + MSM_ISP_IRQ_DISABLE); } static void msm_vfe46_cfg_framedrop(void __iomem *vfe_base, @@ -857,10 +842,8 @@ static void msm_vfe46_cfg_fetch_engine(struct vfe_device *vfe_dev, temp |= (1 << 1); msm_camera_io_w(temp, vfe_dev->vfe_base + 0x84); - vfe_dev->irq0_mask &= 0xFEFFFFFF; - vfe_dev->irq0_mask |= (1 << 24); - msm_vfe46_config_irq(vfe_dev, vfe_dev->irq0_mask, - vfe_dev->irq1_mask, MSM_ISP_IRQ_SET); + msm_vfe46_config_irq(vfe_dev, 1 << 24, 0, + MSM_ISP_IRQ_ENABLE); temp = fe_cfg->fetch_height - 1; msm_camera_io_w(temp & 0x3FFF, vfe_dev->vfe_base + 0x278); @@ -1120,9 +1103,11 @@ static void msm_vfe46_update_camif_state(struct vfe_device *vfe_dev, return; if (update_state == ENABLE_CAMIF) { - vfe_dev->irq0_mask |= 0xF5; - msm_vfe46_config_irq(vfe_dev, vfe_dev->irq0_mask, - vfe_dev->irq1_mask, MSM_ISP_IRQ_SET); + msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x64); + msm_camera_io_w(0x81, vfe_dev->vfe_base + 0x68); + msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x58); + msm_vfe46_config_irq(vfe_dev, 0x15, 0x81, + MSM_ISP_IRQ_ENABLE); bus_en = ((vfe_dev->axi_data. @@ -1148,7 +1133,8 @@ static void msm_vfe46_update_camif_state(struct vfe_device *vfe_dev, if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN) update_state = DISABLE_CAMIF; - msm_vfe46_config_irq(vfe_dev, 0, 0, MSM_ISP_IRQ_SET); + msm_vfe46_config_irq(vfe_dev, 0, 0x81, + MSM_ISP_IRQ_DISABLE); /* disable danger signal */ val = msm_camera_io_r(vfe_dev->vfe_base + 0xC18); val &= ~(1 << 8); @@ -1611,6 +1597,9 @@ static void msm_vfe46_stats_cfg_comp_mask( comp_mask_reg |= mask_bf_scale << (16 + request_comp_index * 8); atomic_set(stats_comp_mask, stats_mask | atomic_read(stats_comp_mask)); + msm_vfe46_config_irq(vfe_dev, + 1 << (request_comp_index + 29), 0, + MSM_ISP_IRQ_ENABLE); } else { if (!(atomic_read(stats_comp_mask) & stats_mask)) return; @@ -1625,6 +1614,9 @@ static void msm_vfe46_stats_cfg_comp_mask( ~stats_mask & atomic_read(stats_comp_mask)); comp_mask_reg &= ~(mask_bf_scale << (16 + request_comp_index * 8)); + msm_vfe46_config_irq(vfe_dev, + 1 << (request_comp_index + 29), 0, + MSM_ISP_IRQ_DISABLE); } msm_camera_io_w(comp_mask_reg, vfe_dev->vfe_base + 0x78); @@ -1640,19 +1632,18 @@ static void msm_vfe46_stats_cfg_wm_irq_mask( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { - vfe_dev->irq0_mask |= 1 << (STATS_IDX(stream_info->stream_handle) + 15); - msm_vfe46_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe46_config_irq(vfe_dev, + 1 << (STATS_IDX(stream_info->stream_handle) + 15), 0, + MSM_ISP_IRQ_ENABLE); } static void msm_vfe46_stats_clear_wm_irq_mask( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { - vfe_dev->irq0_mask &= - ~(1 << (STATS_IDX(stream_info->stream_handle) + 15)); - msm_vfe46_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe46_config_irq(vfe_dev, + 1 << (STATS_IDX(stream_info->stream_handle) + 15), 0, + MSM_ISP_IRQ_DISABLE); } static void msm_vfe46_stats_cfg_wm_reg( diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c index 20aa69f322db..290f100ffeba 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c @@ -149,30 +149,24 @@ void msm_vfe47_config_irq(struct vfe_device *vfe_dev, uint32_t irq0_mask, uint32_t irq1_mask, enum msm_isp_irq_operation oper) { - uint32_t val; - switch (oper) { case MSM_ISP_IRQ_ENABLE: - val = msm_camera_io_r(vfe_dev->vfe_base + 0x5C); - val |= irq0_mask; - msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x5C); - val = msm_camera_io_r(vfe_dev->vfe_base + 0x60); - val |= irq1_mask; - msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x60); + vfe_dev->irq0_mask |= irq0_mask; + vfe_dev->irq1_mask |= irq1_mask; break; case MSM_ISP_IRQ_DISABLE: - val = msm_camera_io_r(vfe_dev->vfe_base + 0x5C); - val &= ~irq0_mask; - msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x5C); - val = msm_camera_io_r(vfe_dev->vfe_base + 0x60); - val &= ~irq1_mask; - msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x60); + vfe_dev->irq0_mask &= ~irq0_mask; + vfe_dev->irq1_mask &= ~irq1_mask; break; case MSM_ISP_IRQ_SET: - msm_camera_io_w_mb(irq0_mask, vfe_dev->vfe_base + 0x5C); - msm_camera_io_w_mb(irq1_mask, vfe_dev->vfe_base + 0x60); + vfe_dev->irq0_mask = irq0_mask; + vfe_dev->irq1_mask = irq1_mask; break; } + msm_camera_io_w_mb(vfe_dev->irq0_mask, + vfe_dev->vfe_base + 0x5C); + msm_camera_io_w_mb(vfe_dev->irq1_mask, + vfe_dev->vfe_base + 0x60); } static int32_t msm_vfe47_init_dt_parms(struct vfe_device *vfe_dev, @@ -285,13 +279,6 @@ int msm_vfe47_init_hardware(struct vfe_device *vfe_dev) else id = CAM_AHB_CLIENT_VFE1; - rc = cam_config_ahb_clk(NULL, 0, id, CAM_AHB_SVS_VOTE); - if (rc < 0) { - pr_err("%s: failed to vote for AHB\n", __func__); - goto ahb_vote_fail; - } - vfe_dev->ahb_vote = CAM_AHB_SVS_VOTE; - rc = vfe_dev->hw_info->vfe_ops.platform_ops.enable_regulators( vfe_dev, 1); if (rc) @@ -302,6 +289,13 @@ int msm_vfe47_init_hardware(struct vfe_device *vfe_dev) if (rc) goto clk_enable_failed; + rc = cam_config_ahb_clk(NULL, 0, id, CAM_AHB_SVS_VOTE); + if (rc < 0) { + pr_err("%s: failed to vote for AHB\n", __func__); + goto ahb_vote_fail; + } + vfe_dev->ahb_vote = CAM_AHB_SVS_VOTE; + vfe_dev->common_data->dual_vfe_res->vfe_base[vfe_dev->pdev->id] = vfe_dev->vfe_base; @@ -312,14 +306,14 @@ int msm_vfe47_init_hardware(struct vfe_device *vfe_dev) return rc; irq_enable_fail: vfe_dev->common_data->dual_vfe_res->vfe_base[vfe_dev->pdev->id] = NULL; - vfe_dev->hw_info->vfe_ops.platform_ops.enable_clks(vfe_dev, 0); -clk_enable_failed: - vfe_dev->hw_info->vfe_ops.platform_ops.enable_regulators(vfe_dev, 0); -enable_regulators_failed: if (cam_config_ahb_clk(NULL, 0, id, CAM_AHB_SUSPEND_VOTE) < 0) pr_err("%s: failed to remove vote for AHB\n", __func__); vfe_dev->ahb_vote = CAM_AHB_SUSPEND_VOTE; ahb_vote_fail: + vfe_dev->hw_info->vfe_ops.platform_ops.enable_clks(vfe_dev, 0); +clk_enable_failed: + vfe_dev->hw_info->vfe_ops.platform_ops.enable_regulators(vfe_dev, 0); +enable_regulators_failed: return rc; } @@ -338,9 +332,6 @@ void msm_vfe47_release_hardware(struct vfe_device *vfe_dev) msm_isp_flush_tasklet(vfe_dev); vfe_dev->common_data->dual_vfe_res->vfe_base[vfe_dev->pdev->id] = NULL; - vfe_dev->hw_info->vfe_ops.platform_ops.enable_clks( - vfe_dev, 0); - vfe_dev->hw_info->vfe_ops.platform_ops.enable_regulators(vfe_dev, 0); msm_isp_update_bandwidth(ISP_VFE0 + vfe_dev->pdev->id, 0, 0); @@ -351,7 +342,12 @@ void msm_vfe47_release_hardware(struct vfe_device *vfe_dev) if (cam_config_ahb_clk(NULL, 0, id, CAM_AHB_SUSPEND_VOTE) < 0) pr_err("%s: failed to vote for AHB\n", __func__); - vfe_dev->ahb_vote = CAM_AHB_SUSPEND_VOTE; + + vfe_dev->ahb_vote = CAM_AHB_SUSPEND_VOTE; + + vfe_dev->hw_info->vfe_ops.platform_ops.enable_clks( + vfe_dev, 0); + vfe_dev->hw_info->vfe_ops.platform_ops.enable_regulators(vfe_dev, 0); } void msm_vfe47_init_hardware_reg(struct vfe_device *vfe_dev) @@ -382,19 +378,16 @@ void msm_vfe47_init_hardware_reg(struct vfe_device *vfe_dev) /* BUS_CFG */ msm_camera_io_w(0x00000101, vfe_dev->vfe_base + 0x84); /* IRQ_MASK/CLEAR */ - vfe_dev->irq0_mask = 0xE00000F3; - vfe_dev->irq1_mask = 0xFFFFFFFF; - msm_vfe47_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe47_config_irq(vfe_dev, 0x810000E0, 0xFFFFFF7E, + MSM_ISP_IRQ_ENABLE); msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x64); msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x68); + msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x58); } void msm_vfe47_clear_status_reg(struct vfe_device *vfe_dev) { - vfe_dev->irq0_mask = 0x80000000; - vfe_dev->irq1_mask = 0x0; - msm_vfe47_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, + msm_vfe47_config_irq(vfe_dev, 0x80000000, 0x0, MSM_ISP_IRQ_SET); msm_camera_io_w(0xFFFFFFFF, vfe_dev->vfe_base + 0x64); msm_camera_io_w_mb(0xFFFFFFFF, vfe_dev->vfe_base + 0x68); @@ -543,7 +536,6 @@ void msm_vfe47_read_irq_status(struct vfe_device *vfe_dev, vfe_dev->error_info.camif_status = msm_camera_io_r(vfe_dev->vfe_base + 0x4A4); /* mask off camif error after first occurrance */ - vfe_dev->irq1_mask &= ~(1 << 0); msm_vfe47_config_irq(vfe_dev, 0, (1 << 0), MSM_ISP_IRQ_DISABLE); } @@ -785,9 +777,8 @@ void msm_vfe47_axi_cfg_comp_mask(struct vfe_device *vfe_dev, stream_composite_mask << (comp_mask_index * 8)); msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x74); - vfe_dev->irq0_mask |= 1 << (comp_mask_index + 25); - msm_vfe47_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe47_config_irq(vfe_dev, 1 << (comp_mask_index + 25), 0, + MSM_ISP_IRQ_ENABLE); } void msm_vfe47_axi_clear_comp_mask(struct vfe_device *vfe_dev, @@ -799,25 +790,22 @@ void msm_vfe47_axi_clear_comp_mask(struct vfe_device *vfe_dev, comp_mask &= ~(0x7F << (comp_mask_index * 8)); msm_camera_io_w(comp_mask, vfe_dev->vfe_base + 0x74); - vfe_dev->irq0_mask &= ~(1 << (comp_mask_index + 25)); - msm_vfe47_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe47_config_irq(vfe_dev, (1 << (comp_mask_index + 25)), 0, + MSM_ISP_IRQ_DISABLE); } void msm_vfe47_axi_cfg_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - vfe_dev->irq0_mask |= 1 << (stream_info->wm[0] + 8); - msm_vfe47_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe47_config_irq(vfe_dev, 1 << (stream_info->wm[0] + 8), 0, + MSM_ISP_IRQ_ENABLE); } void msm_vfe47_axi_clear_wm_irq_mask(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info) { - vfe_dev->irq0_mask &= ~(1 << (stream_info->wm[0] + 8)); - msm_vfe47_config_irq(vfe_dev, vfe_dev->irq0_mask, vfe_dev->irq1_mask, - MSM_ISP_IRQ_SET); + msm_vfe47_config_irq(vfe_dev, (1 << (stream_info->wm[0] + 8)), 0, + MSM_ISP_IRQ_DISABLE); } void msm_vfe47_cfg_framedrop(void __iomem *vfe_base, @@ -1065,10 +1053,8 @@ void msm_vfe47_cfg_fetch_engine(struct vfe_device *vfe_dev, temp |= (1 << 1); msm_camera_io_w(temp, vfe_dev->vfe_base + 0x84); - vfe_dev->irq0_mask &= 0xFEFFFFFF; - vfe_dev->irq0_mask |= (1 << 24); - msm_vfe47_config_irq(vfe_dev, vfe_dev->irq0_mask, - vfe_dev->irq1_mask, MSM_ISP_IRQ_SET); + msm_vfe47_config_irq(vfe_dev, (1 << 24), 0, + MSM_ISP_IRQ_ENABLE); temp = fe_cfg->fetch_height - 1; msm_camera_io_w(temp & 0x3FFF, vfe_dev->vfe_base + 0x308); @@ -1394,9 +1380,11 @@ void msm_vfe47_update_camif_state(struct vfe_device *vfe_dev, val = msm_camera_io_r(vfe_dev->vfe_base + 0x47C); if (update_state == ENABLE_CAMIF) { - vfe_dev->irq0_mask |= 0xF5; - msm_vfe47_config_irq(vfe_dev, vfe_dev->irq0_mask, - vfe_dev->irq1_mask, MSM_ISP_IRQ_SET); + msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x64); + msm_camera_io_w(0x81, vfe_dev->vfe_base + 0x68); + msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x58); + msm_vfe47_config_irq(vfe_dev, 0x15, 0x81, + MSM_ISP_IRQ_ENABLE); if ((vfe_dev->hvx_cmd > HVX_DISABLE) && (vfe_dev->hvx_cmd <= HVX_ROUND_TRIP)) @@ -1427,8 +1415,9 @@ void msm_vfe47_update_camif_state(struct vfe_device *vfe_dev, /* For testgen always halt on camif boundary */ if (vfe_dev->axi_data.src_info[VFE_PIX_0].input_mux == TESTGEN) update_state = DISABLE_CAMIF; - /* turn off all irq before camif disable */ - msm_vfe47_config_irq(vfe_dev, 0, 0, MSM_ISP_IRQ_SET); + /* turn off camif violation and error irqs */ + msm_vfe47_config_irq(vfe_dev, 0, 0x81, + MSM_ISP_IRQ_DISABLE); val = msm_camera_io_r(vfe_dev->vfe_base + 0x464); /* disable danger signal */ msm_camera_io_w_mb(val & ~(1 << 8), vfe_dev->vfe_base + 0x464); @@ -1896,6 +1885,8 @@ void msm_vfe47_stats_cfg_comp_mask( comp_mask_reg |= stats_mask << (request_comp_index * 16); atomic_set(stats_comp_mask, stats_mask | atomic_read(stats_comp_mask)); + msm_vfe47_config_irq(vfe_dev, 1 << (29 + request_comp_index), + 0, MSM_ISP_IRQ_ENABLE); } else { if (!(atomic_read(stats_comp_mask) & stats_mask)) return; @@ -1903,6 +1894,8 @@ void msm_vfe47_stats_cfg_comp_mask( atomic_set(stats_comp_mask, ~stats_mask & atomic_read(stats_comp_mask)); comp_mask_reg &= ~(stats_mask << (request_comp_index * 16)); + msm_vfe47_config_irq(vfe_dev, 1 << (29 + request_comp_index), + 0, MSM_ISP_IRQ_DISABLE); } msm_camera_io_w(comp_mask_reg, vfe_dev->vfe_base + 0x78); @@ -1919,49 +1912,39 @@ void msm_vfe47_stats_cfg_wm_irq_mask( struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info) { - uint32_t irq_mask; - uint32_t irq_mask_1; - - irq_mask = vfe_dev->irq0_mask; - irq_mask_1 = vfe_dev->irq1_mask; - switch (STATS_IDX(stream_info->stream_handle)) { case STATS_COMP_IDX_AEC_BG: - irq_mask |= 1 << 15; + msm_vfe47_config_irq(vfe_dev, 1 << 15, 0, MSM_ISP_IRQ_ENABLE); break; case STATS_COMP_IDX_HDR_BE: - irq_mask |= 1 << 16; + msm_vfe47_config_irq(vfe_dev, 1 << 16, 0, MSM_ISP_IRQ_ENABLE); break; case STATS_COMP_IDX_BG: - irq_mask |= 1 << 17; + msm_vfe47_config_irq(vfe_dev, 1 << 17, 0, MSM_ISP_IRQ_ENABLE); break; case STATS_COMP_IDX_BF: - irq_mask |= 1 << 18; - irq_mask_1 |= 1 << 26; + msm_vfe47_config_irq(vfe_dev, 1 << 18, 1 << 26, + MSM_ISP_IRQ_ENABLE); break; case STATS_COMP_IDX_HDR_BHIST: - irq_mask |= 1 << 19; + msm_vfe47_config_irq(vfe_dev, 1 << 19, 0, MSM_ISP_IRQ_ENABLE); break; case STATS_COMP_IDX_RS: - irq_mask |= 1 << 20; + msm_vfe47_config_irq(vfe_dev, 1 << 20, 0, MSM_ISP_IRQ_ENABLE); break; case STATS_COMP_IDX_CS: - irq_mask |= 1 << 21; + msm_vfe47_config_irq(vfe_dev, 1 << 21, 0, MSM_ISP_IRQ_ENABLE); break; case STATS_COMP_IDX_IHIST: - irq_mask |= 1 << 22; + msm_vfe47_config_irq(vfe_dev, 1 << 22, 0, MSM_ISP_IRQ_ENABLE); break; case STATS_COMP_IDX_BHIST: - irq_mask |= 1 << 23; + msm_vfe47_config_irq(vfe_dev, 1 << 23, 0, MSM_ISP_IRQ_ENABLE); break; default: pr_err("%s: Invalid stats idx %d\n", __func__, STATS_IDX(stream_info->stream_handle)); } - - msm_vfe47_config_irq(vfe_dev, irq_mask, irq_mask_1, MSM_ISP_IRQ_SET); - vfe_dev->irq0_mask = irq_mask; - vfe_dev->irq1_mask = irq_mask_1; } void msm_vfe47_stats_clear_wm_irq_mask( @@ -1975,41 +1958,37 @@ void msm_vfe47_stats_clear_wm_irq_mask( switch (STATS_IDX(stream_info->stream_handle)) { case STATS_COMP_IDX_AEC_BG: - irq_mask &= ~(1 << 15); + msm_vfe47_config_irq(vfe_dev, 1 << 15, 0, MSM_ISP_IRQ_DISABLE); break; case STATS_COMP_IDX_HDR_BE: - irq_mask &= ~(1 << 16); + msm_vfe47_config_irq(vfe_dev, 1 << 16, 0, MSM_ISP_IRQ_DISABLE); break; case STATS_COMP_IDX_BG: - irq_mask &= ~(1 << 17); + msm_vfe47_config_irq(vfe_dev, 1 << 17, 0, MSM_ISP_IRQ_DISABLE); break; case STATS_COMP_IDX_BF: - irq_mask &= ~(1 << 18); - irq_mask_1 &= ~(1 << 26); + msm_vfe47_config_irq(vfe_dev, 1 << 18, 1 << 26, + MSM_ISP_IRQ_DISABLE); break; case STATS_COMP_IDX_HDR_BHIST: - irq_mask &= ~(1 << 19); + msm_vfe47_config_irq(vfe_dev, 1 << 19, 0, MSM_ISP_IRQ_DISABLE); break; case STATS_COMP_IDX_RS: - irq_mask &= ~(1 << 20); + msm_vfe47_config_irq(vfe_dev, 1 << 20, 0, MSM_ISP_IRQ_DISABLE); break; case STATS_COMP_IDX_CS: - irq_mask &= ~(1 << 21); + msm_vfe47_config_irq(vfe_dev, 1 << 21, 0, MSM_ISP_IRQ_DISABLE); break; case STATS_COMP_IDX_IHIST: - irq_mask &= ~(1 << 22); + msm_vfe47_config_irq(vfe_dev, 1 << 22, 0, MSM_ISP_IRQ_DISABLE); break; case STATS_COMP_IDX_BHIST: - irq_mask &= ~(1 << 23); + msm_vfe47_config_irq(vfe_dev, 1 << 23, 0, MSM_ISP_IRQ_DISABLE); break; default: pr_err("%s: Invalid stats idx %d\n", __func__, STATS_IDX(stream_info->stream_handle)); } - - msm_vfe47_config_irq(vfe_dev, irq_mask, irq_mask_1, MSM_ISP_IRQ_SET); - vfe_dev->irq0_mask = irq_mask; - vfe_dev->irq1_mask = irq_mask_1; } void msm_vfe47_stats_cfg_wm_reg( diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index fbac6d81ded0..8721fc18eaa8 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -540,6 +540,89 @@ static void msm_isp_cfg_framedrop_reg(struct vfe_device *vfe_dev, } /** + * msm_isp_check_epoch_status() - check the epock signal for framedrop + * + * @vfe_dev: The h/w on which the epoch signel is reveived + * @frame_src: The source of the epoch signal for this frame + * + * For dual vfe case and pixel stream, if both vfe's epoch signal is + * received, this function will return success. + * It will also return the vfe1 for further process + * For none dual VFE stream or none pixl source, this + * funciton will just return success. + * + * Returns 1 - epoch received is complete. + * 0 - epoch reveived is not complete. + */ +static int msm_isp_check_epoch_status(struct vfe_device **vfe_dev, + enum msm_vfe_input_src frame_src) +{ + struct vfe_device *vfe_dev_cur = *vfe_dev; + struct vfe_device *vfe_dev_other = NULL; + uint32_t vfe_id_other = 0; + uint32_t vfe_id_cur = 0; + uint32_t epoch_mask = 0; + unsigned long flags; + int completed = 0; + + spin_lock_irqsave( + &vfe_dev_cur->common_data->common_dev_data_lock, flags); + + if (vfe_dev_cur->is_split && + frame_src == VFE_PIX_0) { + if (vfe_dev_cur->pdev->id == ISP_VFE0) { + vfe_id_cur = ISP_VFE0; + vfe_id_other = ISP_VFE1; + } else { + vfe_id_cur = ISP_VFE1; + vfe_id_other = ISP_VFE0; + } + vfe_dev_other = vfe_dev_cur->common_data->dual_vfe_res-> + vfe_dev[vfe_id_other]; + + if (vfe_dev_cur->common_data->dual_vfe_res-> + epoch_sync_mask & (1 << vfe_id_cur)) { + /* serious scheduling delay */ + pr_err("Missing epoch: vfe %d, epoch mask 0x%x\n", + vfe_dev_cur->pdev->id, + vfe_dev_cur->common_data->dual_vfe_res-> + epoch_sync_mask); + goto fatal; + } + + vfe_dev_cur->common_data->dual_vfe_res-> + epoch_sync_mask |= (1 << vfe_id_cur); + + epoch_mask = (1 << vfe_id_cur) | (1 << vfe_id_other); + if ((vfe_dev_cur->common_data->dual_vfe_res-> + epoch_sync_mask & epoch_mask) == epoch_mask) { + + if (vfe_id_other == ISP_VFE0) + *vfe_dev = vfe_dev_cur; + else + *vfe_dev = vfe_dev_other; + + vfe_dev_cur->common_data->dual_vfe_res-> + epoch_sync_mask &= ~epoch_mask; + completed = 1; + } + } else + completed = 1; + + spin_unlock_irqrestore( + &vfe_dev_cur->common_data->common_dev_data_lock, flags); + + return completed; +fatal: + spin_unlock_irqrestore( + &vfe_dev_cur->common_data->common_dev_data_lock, flags); + /* new error event code will be added later */ + msm_isp_halt_send_error(vfe_dev_cur, ISP_EVENT_PING_PONG_MISMATCH); + return 0; +} + + +/** * msm_isp_update_framedrop_reg() - Update frame period pattern on h/w * @vfe_dev: The h/w on which the perion pattern is updated. * @frame_src: Input source. @@ -554,10 +637,15 @@ void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev, enum msm_vfe_input_src frame_src) { int i; - struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data; + struct msm_vfe_axi_shared_data *axi_data = NULL; struct msm_vfe_axi_stream *stream_info; unsigned long flags; + if (msm_isp_check_epoch_status(&vfe_dev, frame_src) != 1) + return; + + axi_data = &vfe_dev->axi_data; + for (i = 0; i < VFE_AXI_SRC_MAX; i++) { if (SRC_TO_INTF(axi_data->stream_info[i].stream_src) != frame_src) { @@ -1100,15 +1188,9 @@ int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg) vfe_dev->vt_enable = stream_cfg_cmd->vt_enable; msm_isp_start_avtimer(); } - if (stream_info->num_planes > 1) { + if (stream_info->num_planes > 1) msm_isp_axi_reserve_comp_mask( &vfe_dev->axi_data, stream_info); - vfe_dev->hw_info->vfe_ops.axi_ops. - cfg_comp_mask(vfe_dev, stream_info); - } else { - vfe_dev->hw_info->vfe_ops.axi_ops. - cfg_wm_irq_mask(vfe_dev, stream_info); - } for (i = 0; i < stream_info->num_planes; i++) { vfe_dev->hw_info->vfe_ops.axi_ops. @@ -1164,14 +1246,8 @@ int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg) clear_wm_xbar_reg(vfe_dev, stream_info, i); } - if (stream_info->num_planes > 1) { - vfe_dev->hw_info->vfe_ops.axi_ops. - clear_comp_mask(vfe_dev, stream_info); + if (stream_info->num_planes > 1) msm_isp_axi_free_comp_mask(&vfe_dev->axi_data, stream_info); - } else { - vfe_dev->hw_info->vfe_ops.axi_ops. - clear_wm_irq_mask(vfe_dev, stream_info); - } vfe_dev->hw_info->vfe_ops.axi_ops.clear_framedrop(vfe_dev, stream_info); msm_isp_axi_free_wm(axi_data, stream_info); @@ -1937,6 +2013,13 @@ static void msm_isp_get_camif_update_state_and_halt( pix_stream_cnt++; } + if (vfe_dev->axi_data.num_active_stream == stream_cfg_cmd->num_streams + && (stream_cfg_cmd->cmd == STOP_STREAM || + stream_cfg_cmd->cmd == STOP_IMMEDIATELY)) + *halt = 1; + else + *halt = 0; + if ((pix_stream_cnt) && (axi_data->src_info[VFE_PIX_0].input_mux != EXTERNAL_READ)) { if (cur_pix_stream_cnt == 0 && pix_stream_cnt && @@ -1944,24 +2027,17 @@ static void msm_isp_get_camif_update_state_and_halt( *camif_update = ENABLE_CAMIF; else if (cur_pix_stream_cnt && (cur_pix_stream_cnt - pix_stream_cnt) == 0 && - stream_cfg_cmd->cmd == STOP_STREAM) - *camif_update = DISABLE_CAMIF; - else if (cur_pix_stream_cnt && - (cur_pix_stream_cnt - pix_stream_cnt) == 0 && - stream_cfg_cmd->cmd == STOP_IMMEDIATELY) - *camif_update = DISABLE_CAMIF_IMMEDIATELY; + (stream_cfg_cmd->cmd == STOP_STREAM || + stream_cfg_cmd->cmd == STOP_IMMEDIATELY)) { + if (*halt) + *camif_update = DISABLE_CAMIF_IMMEDIATELY; + else + *camif_update = DISABLE_CAMIF; + } else *camif_update = NO_UPDATE; } else *camif_update = NO_UPDATE; - - if (vfe_dev->axi_data.num_active_stream == stream_cfg_cmd->num_streams - && (stream_cfg_cmd->cmd == STOP_STREAM || - stream_cfg_cmd->cmd == STOP_IMMEDIATELY)) - *halt = 1; - else - *halt = 0; - } static void msm_isp_update_camif_output_count( @@ -2529,6 +2605,13 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev, return rc; } spin_unlock_irqrestore(&stream_info->lock, flags); + if (stream_info->num_planes > 1) { + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_comp_mask(vfe_dev, stream_info); + } else { + vfe_dev->hw_info->vfe_ops.axi_ops. + cfg_wm_irq_mask(vfe_dev, stream_info); + } stream_info->state = START_PENDING; @@ -2584,6 +2667,7 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev, vfe_dev->hw_info->vfe_ops.core_ops. update_camif_state(vfe_dev, camif_update); vfe_dev->axi_data.camif_state = CAMIF_ENABLE; + vfe_dev->common_data->dual_vfe_res->epoch_sync_mask = 0; } if (wait_for_complete) { @@ -2644,35 +2728,28 @@ static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev, spin_unlock_irqrestore(&stream_info->lock, flags); wait_for_complete_for_this_stream = 0; + if (stream_info->num_planes > 1) + vfe_dev->hw_info->vfe_ops.axi_ops. + clear_comp_mask(vfe_dev, stream_info); + else + vfe_dev->hw_info->vfe_ops.axi_ops. + clear_wm_irq_mask(vfe_dev, stream_info); + stream_info->state = STOP_PENDING; - ISP_DBG("Stop axi Stream 0x%x\n", stream_info->stream_id); - if (stream_info->stream_src == CAMIF_RAW || - stream_info->stream_src == IDEAL_RAW) { - /* We dont get reg update IRQ for raw snapshot - * so frame skip cant be ocnfigured - */ - if ((camif_update != DISABLE_CAMIF_IMMEDIATELY) && - (!ext_read)) - wait_for_complete_for_this_stream = 1; - - } else if (stream_info->stream_type == BURST_STREAM && - stream_info->runtime_num_burst_capture == 0) { - /* Configure AXI writemasters to stop immediately - * since for burst case, write masters already skip - * all frames. - */ - if (stream_info->stream_src == RDI_INTF_0 || - stream_info->stream_src == RDI_INTF_1 || - stream_info->stream_src == RDI_INTF_2) - wait_for_complete_for_this_stream = 1; - } else { - if ((camif_update != DISABLE_CAMIF_IMMEDIATELY) && - !halt && (!ext_read)) - wait_for_complete_for_this_stream = 1; - } - ISP_DBG("%s: vfe_dev %d camif_update %d halt %d wait %d\n", - __func__, vfe_dev->pdev->id, camif_update, halt, + + if (!halt && !ext_read && + !(stream_info->stream_type == BURST_STREAM && + stream_info->runtime_num_burst_capture == 0)) + wait_for_complete_for_this_stream = 1; + + ISP_DBG("%s: stream 0x%x, vfe %d camif %d halt %d wait %d\n", + __func__, + stream_info->stream_id, + vfe_dev->pdev->id, + camif_update, + halt, wait_for_complete_for_this_stream); + intf = SRC_TO_INTF(stream_info->stream_src); if (!wait_for_complete_for_this_stream || stream_info->state == INACTIVE || diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c index e98c99fcb62d..4aef6b5c7f38 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c @@ -444,10 +444,6 @@ int msm_isp_request_stats_stream(struct vfe_device *vfe_dev, void *arg) stream_info->framedrop_pattern = 0x1; stream_info->framedrop_period = framedrop_period - 1; - if (!stream_info->composite_flag) - vfe_dev->hw_info->vfe_ops.stats_ops. - cfg_wm_irq_mask(vfe_dev, stream_info); - if (stream_info->init_stats_frame_drop == 0) vfe_dev->hw_info->vfe_ops.stats_ops.cfg_wm_reg(vfe_dev, stream_info); @@ -485,10 +481,6 @@ int msm_isp_release_stats_stream(struct vfe_device *vfe_dev, void *arg) rc = msm_isp_cfg_stats_stream(vfe_dev, &stream_cfg_cmd); } - if (!stream_info->composite_flag) - vfe_dev->hw_info->vfe_ops.stats_ops. - clear_wm_irq_mask(vfe_dev, stream_info); - vfe_dev->hw_info->vfe_ops.stats_ops.clear_wm_reg(vfe_dev, stream_info); memset(stream_info, 0, sizeof(struct msm_vfe_stats_stream)); return 0; @@ -711,6 +703,9 @@ static int msm_isp_start_stats_stream(struct vfe_device *vfe_dev, pr_err("%s: No buffer for stream%d\n", __func__, idx); return rc; } + if (!stream_info->composite_flag) + vfe_dev->hw_info->vfe_ops.stats_ops. + cfg_wm_irq_mask(vfe_dev, stream_info); if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) stream_info->state = STATS_START_PENDING; @@ -784,6 +779,10 @@ static int msm_isp_stop_stats_stream(struct vfe_device *vfe_dev, return -EINVAL; } + if (!stream_info->composite_flag) + vfe_dev->hw_info->vfe_ops.stats_ops. + clear_wm_irq_mask(vfe_dev, stream_info); + if (vfe_dev->axi_data.src_info[VFE_PIX_0].active) stream_info->state = STATS_STOP_PENDING; else diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c index 460746089c53..5e24b146619d 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c @@ -1005,7 +1005,8 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev, case VFE_READ_DMI_16BIT: case VFE_READ_DMI_32BIT: case VFE_READ_DMI_64BIT: { - if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT) { + if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT || + reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) { if ((reg_cfg_cmd->u.dmi_info.hi_tbl_offset <= reg_cfg_cmd->u.dmi_info.lo_tbl_offset) || (reg_cfg_cmd->u.dmi_info.hi_tbl_offset - @@ -1917,11 +1918,16 @@ int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) ISP_DBG("%s open_cnt %u\n", __func__, vfe_dev->vfe_open_cnt); - if (vfe_dev->common_data == NULL) { - pr_err("%s: Error in probe. No common_data\n", __func__); + if (vfe_dev->common_data == NULL || + vfe_dev->common_data->dual_vfe_res == NULL) { + pr_err("%s: Error in probe. No common_data or dual vfe res\n", + __func__); return -EINVAL; } + if (vfe_dev->pdev->id == ISP_VFE0) + vfe_dev->common_data->dual_vfe_res->epoch_sync_mask = 0; + mutex_lock(&vfe_dev->realtime_mutex); mutex_lock(&vfe_dev->core_mutex); diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c index 4c0991e0dd26..c9656e748f09 100644 --- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c @@ -58,6 +58,9 @@ static int msm_ispif_clk_ahb_enable(struct ispif_device *ispif, int enable); static int ispif_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh); +static long msm_ispif_subdev_ioctl_unlocked(struct v4l2_subdev *sd, + unsigned int cmd, void *arg); + int msm_ispif_get_clk_info(struct ispif_device *ispif_dev, struct platform_device *pdev); @@ -95,6 +98,192 @@ static struct msm_cam_clk_info ispif_8626_reset_clk_info[] = { {"camss_csi_vfe_clk", NO_SET_RATE}, }; +#ifdef CONFIG_COMPAT +struct ispif_cfg_data_ext_32 { + enum ispif_cfg_type_t cfg_type; + compat_caddr_t data; + uint32_t size; +}; + +#define VIDIOC_MSM_ISPIF_CFG_EXT_COMPAT \ + _IOWR('V', BASE_VIDIOC_PRIVATE+1, struct ispif_cfg_data_ext_32) +#endif + +static void msm_ispif_get_pack_mask_from_cfg( + struct msm_ispif_pack_cfg *pack_cfg, + struct msm_ispif_params_entry *entry, + uint32_t *pack_mask) +{ + int i; + uint32_t temp; + + if (WARN_ON(!entry)) + return; + + memset(pack_mask, 0, sizeof(uint32_t) * 2); + for (i = 0; i < entry->num_cids; i++) { + temp = (pack_cfg[entry->cids[i]].pack_mode & 0x3)| + (pack_cfg[entry->cids[i]].even_odd_sel & 0x1) << 2 | + (pack_cfg[entry->cids[i]].pixel_swap_en & 0x1) << 3; + temp = (temp & 0xF) << ((entry->cids[i] % CID8) * 4); + + if (entry->cids[i] > CID7) + pack_mask[1] |= temp; + else + pack_mask[0] |= temp; + CDBG("%s:num %d cid %d mode %d pack_mask %x %x\n", + __func__, entry->num_cids, entry->cids[i], + pack_cfg[i].pack_mode, + pack_mask[0], pack_mask[1]); + + } +} + +static int msm_ispif_config2(struct ispif_device *ispif, + void *data) +{ + int rc = 0, i = 0; + enum msm_ispif_intftype intftype; + enum msm_ispif_vfe_intf vfe_intf; + uint32_t pack_cfg_mask[2]; + struct msm_ispif_param_data_ext *params = + (struct msm_ispif_param_data_ext *)data; + + if (WARN_ON(!ispif) || WARN_ON(!params)) + return -EINVAL; + + if (ispif->ispif_state != ISPIF_POWER_UP) { + pr_err("%s: ispif invalid state %d\n", __func__, + ispif->ispif_state); + rc = -EPERM; + return rc; + } + if (params->num > MAX_PARAM_ENTRIES) { + pr_err("%s: invalid param entries %d\n", __func__, + params->num); + rc = -EINVAL; + return rc; + } + + for (i = 0; i < params->num; i++) { + intftype = params->entries[i].intftype; + vfe_intf = params->entries[i].vfe_intf; + + CDBG("%s, num %d intftype %x, vfe_intf %d, csid %d\n", __func__, + params->num, intftype, vfe_intf, + params->entries[i].csid); + + if ((intftype >= INTF_MAX) || + (vfe_intf >= ispif->vfe_info.num_vfe) || + (ispif->csid_version <= CSID_VERSION_V22 && + (vfe_intf > VFE0))) { + pr_err("%s: VFEID %d and CSID version %d mismatch\n", + __func__, vfe_intf, ispif->csid_version); + return -EINVAL; + } + + msm_ispif_get_pack_mask_from_cfg(params->pack_cfg, + ¶ms->entries[i], pack_cfg_mask); + msm_ispif_cfg_pack_mode(ispif, intftype, vfe_intf, + pack_cfg_mask); + } + return rc; +} + +static long msm_ispif_cmd_ext(struct v4l2_subdev *sd, + void *arg) +{ + long rc = 0; + struct ispif_device *ispif = + (struct ispif_device *)v4l2_get_subdevdata(sd); + struct ispif_cfg_data_ext pcdata; + struct msm_ispif_param_data_ext *params = NULL; +#ifdef CONFIG_COMPAT + struct ispif_cfg_data_ext_32 *pcdata32 = + (struct ispif_cfg_data_ext_32 *)arg; + + if (pcdata32 == NULL) { + pr_err("Invalid params passed from user\n"); + return -EINVAL; + } + pcdata.cfg_type = pcdata32->cfg_type; + pcdata.size = pcdata32->size; + pcdata.data = compat_ptr(pcdata32->data); + +#else + struct ispif_cfg_data_ext *pcdata64 = + (struct ispif_cfg_data_ext *)arg; + + if (pcdata64 == NULL) { + pr_err("Invalid params passed from user\n"); + return -EINVAL; + } + pcdata.cfg_type = pcdata64->cfg_type; + pcdata.size = pcdata64->size; + pcdata.data = pcdata64->data; +#endif + if (pcdata.size != sizeof(struct msm_ispif_param_data_ext)) { + pr_err("%s: payload size mismatch\n", __func__); + return -EINVAL; + } + + params = kzalloc(sizeof(struct msm_ispif_param_data_ext), GFP_KERNEL); + if (!params) { + CDBG("%s: params alloc failed\n", __func__); + return -ENOMEM; + } + if (copy_from_user(params, (void __user *)(pcdata.data), + pcdata.size)) { + kfree(params); + return -EFAULT; + } + + mutex_lock(&ispif->mutex); + switch (pcdata.cfg_type) { + case ISPIF_CFG2: + rc = msm_ispif_config2(ispif, params); + msm_ispif_io_dump_reg(ispif); + break; + default: + pr_err("%s: invalid cfg_type\n", __func__); + rc = -EINVAL; + break; + } + mutex_unlock(&ispif->mutex); + kfree(params); + return rc; +} + +#ifdef CONFIG_COMPAT +static long msm_ispif_subdev_ioctl_compat(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + if (WARN_ON(!sd)) + return -EINVAL; + + switch (cmd) { + case VIDIOC_MSM_ISPIF_CFG_EXT_COMPAT: + return msm_ispif_cmd_ext(sd, arg); + + default: + return msm_ispif_subdev_ioctl_unlocked(sd, cmd, arg); + } +} +static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + if (is_compat_task()) + return msm_ispif_subdev_ioctl_compat(sd, cmd, arg); + else + return msm_ispif_subdev_ioctl_unlocked(sd, cmd, arg); +} +#else +static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + return msm_ispif_subdev_ioctl_unlocked(sd, cmd, arg); +} +#endif static void msm_ispif_put_regulator(struct ispif_device *ispif_dev) { int i; @@ -649,7 +838,6 @@ static uint16_t msm_ispif_get_cids_mask_from_cfg( { int i; uint16_t cids_mask = 0; - BUG_ON(!entry); for (i = 0; i < entry->num_cids; i++) @@ -657,14 +845,15 @@ static uint16_t msm_ispif_get_cids_mask_from_cfg( return cids_mask; } - static int msm_ispif_config(struct ispif_device *ispif, - struct msm_ispif_param_data *params) + void *data) { int rc = 0, i = 0; uint16_t cid_mask; enum msm_ispif_intftype intftype; enum msm_ispif_vfe_intf vfe_intf; + struct msm_ispif_param_data *params = + (struct msm_ispif_param_data *)data; BUG_ON(!ispif); BUG_ON(!params); @@ -1415,7 +1604,7 @@ static long msm_ispif_cmd(struct v4l2_subdev *sd, void *arg) } static struct v4l2_file_operations msm_ispif_v4l2_subdev_fops; -static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd, +static long msm_ispif_subdev_ioctl_unlocked(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { struct ispif_device *ispif = @@ -1424,6 +1613,8 @@ static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd, switch (cmd) { case VIDIOC_MSM_ISPIF_CFG: return msm_ispif_cmd(sd, arg); + case VIDIOC_MSM_ISPIF_CFG_EXT: + return msm_ispif_cmd_ext(sd, arg); case MSM_SD_NOTIFY_FREEZE: { ispif->ispif_sof_debug = 0; ispif->ispif_rdi0_debug = 0; diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h index b82fd34f2396..d488ca618537 100644 --- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -115,4 +115,10 @@ #define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x000001 #define ISPIF_STOP_INTF_IMMEDIATELY 0xAAAAAAAA + +/* ISPIF RDI pack mode not supported */ +static inline void msm_ispif_cfg_pack_mode(struct ispif_device *ispif, + uint8_t intftype, uint8_t vfe_intf, uint32_t *pack_cfg_mask) +{ +} #endif /* __MSM_ISPIF_HWREG_V1_H__ */ diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h index 01dce6d45897..8ae61dc2d4f6 100644 --- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v2.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -96,4 +96,9 @@ #define ISPIF_STOP_INTF_IMMEDIATELY 0xAAAAAAAA +/* ISPIF RDI pack mode not supported */ +static inline void msm_ispif_cfg_pack_mode(struct ispif_device *ispif, + uint8_t intftype, uint8_t vfe_intf, uint32_t *pack_cfg_mask) +{ +} #endif /* __MSM_ISPIF_HWREG_V2_H__ */ diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v3.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v3.h index 343575263816..94cc974441ee 100644 --- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v3.h +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v3.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -10,8 +10,8 @@ * GNU General Public License for more details. */ -#ifndef __MSM_ISPIF_HWREG_V2_H__ -#define __MSM_ISPIF_HWREG_V2_H__ +#ifndef __MSM_ISPIF_HWREG_V3_H__ +#define __MSM_ISPIF_HWREG_V3_H__ /* common registers */ #define ISPIF_RST_CMD_ADDR 0x008 @@ -99,4 +99,38 @@ #define ISPIF_STOP_INTF_IMMEDIATELY 0xAAAAAAAA -#endif /* __MSM_ISPIF_HWREG_V2_H__ */ +/* ISPIF RDI pack mode support */ +static inline void msm_ispif_cfg_pack_mode(struct ispif_device *ispif, + uint8_t intftype, uint8_t vfe_intf, uint32_t *pack_cfg_mask) +{ + uint32_t pack_addr[2]; + + if (WARN_ON(!ispif)) + return; + + switch (intftype) { + case RDI0: + pack_addr[0] = ISPIF_VFE_m_RDI_INTF_n_PACK_0(vfe_intf, 0); + pack_addr[1] = ISPIF_VFE_m_RDI_INTF_n_PACK_1(vfe_intf, 0); + break; + case RDI1: + pack_addr[0] = ISPIF_VFE_m_RDI_INTF_n_PACK_0(vfe_intf, 1); + pack_addr[1] = ISPIF_VFE_m_RDI_INTF_n_PACK_1(vfe_intf, 1); + break; + case RDI2: + pack_addr[0] = ISPIF_VFE_m_RDI_INTF_n_PACK_0(vfe_intf, 2); + pack_addr[1] = ISPIF_VFE_m_RDI_INTF_n_PACK_1(vfe_intf, 2); + break; + default: + pr_debug("%s: pack_mode not supported on intftype=%d\n", + __func__, intftype); + return; + } + pr_debug("%s: intftype %d pack_mask %x: 0x%x, %x:0x%x\n", + __func__, intftype, pack_addr[0], + pack_cfg_mask[0], pack_addr[1], + pack_cfg_mask[1]); + msm_camera_io_w_mb(pack_cfg_mask[0], ispif->base + pack_addr[0]); + msm_camera_io_w_mb(pack_cfg_mask[1], ispif->base + pack_addr[1]); +} +#endif /* __MSM_ISPIF_HWREG_V3_H__ */ diff --git a/drivers/media/platform/msm/camera_v2/msm.c b/drivers/media/platform/msm/camera_v2/msm.c index a34dbb80b468..c6dc4b75e479 100644 --- a/drivers/media/platform/msm/camera_v2/msm.c +++ b/drivers/media/platform/msm/camera_v2/msm.c @@ -1099,6 +1099,28 @@ struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q) } EXPORT_SYMBOL(msm_get_stream_from_vb2q); +#ifdef CONFIG_COMPAT +long msm_copy_camera_private_ioctl_args(unsigned long arg, + struct msm_camera_private_ioctl_arg *k_ioctl, + void __user **tmp_compat_ioctl_ptr) +{ + struct msm_camera_private_ioctl_arg *up_ioctl_ptr = + (struct msm_camera_private_ioctl_arg *)arg; + + if (WARN_ON(!arg || !k_ioctl || !tmp_compat_ioctl_ptr)) + return -EIO; + + k_ioctl->id = up_ioctl_ptr->id; + k_ioctl->size = up_ioctl_ptr->size; + k_ioctl->result = up_ioctl_ptr->result; + k_ioctl->reserved = up_ioctl_ptr->reserved; + *tmp_compat_ioctl_ptr = compat_ptr(up_ioctl_ptr->ioctl_ptr); + + return 0; +} +EXPORT_SYMBOL(msm_copy_camera_private_ioctl_args); +#endif + static void msm_sd_notify(struct v4l2_subdev *sd, unsigned int notification, void *arg) { diff --git a/drivers/media/platform/msm/camera_v2/msm.h b/drivers/media/platform/msm/camera_v2/msm.h index cab07df2a5bb..2b3576b8edd2 100644 --- a/drivers/media/platform/msm/camera_v2/msm.h +++ b/drivers/media/platform/msm/camera_v2/msm.h @@ -133,4 +133,9 @@ struct vb2_queue *msm_get_stream_vb2q(unsigned int session_id, unsigned int stream_id); struct msm_stream *msm_get_stream_from_vb2q(struct vb2_queue *q); struct msm_session *msm_session_find(unsigned int session_id); +#ifdef CONFIG_COMPAT +long msm_copy_camera_private_ioctl_args(unsigned long arg, + struct msm_camera_private_ioctl_arg *k_ioctl, + void __user **tmp_compat_ioctl_ptr); +#endif #endif /*_MSM_H */ diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c index b6cbdcc32360..ac9a4b2048d1 100644 --- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c +++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c @@ -48,6 +48,7 @@ static int32_t msm_buf_mngr_hdl_cont_get_buf(struct msm_buf_mngr_device *dev, } return 0; } + static int32_t msm_buf_mngr_get_buf(struct msm_buf_mngr_device *dev, void __user *argp) { @@ -91,6 +92,52 @@ static int32_t msm_buf_mngr_get_buf(struct msm_buf_mngr_device *dev, return rc; } +static int32_t msm_buf_mngr_get_buf_by_idx(struct msm_buf_mngr_device *dev, + void *argp) +{ + unsigned long flags; + int32_t rc = 0; + struct msm_buf_mngr_info *buf_info = + (struct msm_buf_mngr_info *)argp; + struct msm_get_bufs *new_entry = + kzalloc(sizeof(struct msm_get_bufs), GFP_KERNEL); + + if (!new_entry) + return -ENOMEM; + + if (!buf_info) { + kfree(new_entry); + return -EIO; + } + + INIT_LIST_HEAD(&new_entry->entry); + new_entry->vb2_v4l2_buf = dev->vb2_ops.get_buf_by_idx( + buf_info->session_id, buf_info->stream_id, buf_info->index); + if (!new_entry->vb2_v4l2_buf) { + pr_debug("%s:Get buf is null\n", __func__); + kfree(new_entry); + return -EINVAL; + } + new_entry->session_id = buf_info->session_id; + new_entry->stream_id = buf_info->stream_id; + new_entry->index = new_entry->vb2_v4l2_buf->vb2_buf.index; + spin_lock_irqsave(&dev->buf_q_spinlock, flags); + list_add_tail(&new_entry->entry, &dev->buf_qhead); + spin_unlock_irqrestore(&dev->buf_q_spinlock, flags); + if (buf_info->type == MSM_CAMERA_BUF_MNGR_BUF_USER) { + mutex_lock(&dev->cont_mutex); + if (!list_empty(&dev->cont_qhead)) { + rc = msm_buf_mngr_hdl_cont_get_buf(dev, buf_info); + } else { + pr_err("Nothing mapped in user buf for %d,%d\n", + buf_info->session_id, buf_info->stream_id); + rc = -EINVAL; + } + mutex_unlock(&dev->cont_mutex); + } + return rc; +} + static int32_t msm_buf_mngr_buf_done(struct msm_buf_mngr_device *buf_mngr_dev, struct msm_buf_mngr_info *buf_info) { @@ -413,6 +460,67 @@ static int msm_generic_buf_mngr_close(struct v4l2_subdev *sd, return rc; } +int msm_cam_buf_mgr_ops(unsigned int cmd, void *argp) +{ + int rc = 0; + + if (!msm_buf_mngr_dev) + return -ENODEV; + if (!argp) + return -EINVAL; + + switch (cmd) { + case VIDIOC_MSM_BUF_MNGR_GET_BUF: + rc = msm_buf_mngr_get_buf(msm_buf_mngr_dev, argp); + break; + case VIDIOC_MSM_BUF_MNGR_BUF_DONE: + rc = msm_buf_mngr_buf_done(msm_buf_mngr_dev, argp); + break; + case VIDIOC_MSM_BUF_MNGR_PUT_BUF: + rc = msm_buf_mngr_put_buf(msm_buf_mngr_dev, argp); + break; + case VIDIOC_MSM_BUF_MNGR_IOCTL_CMD: { + struct msm_camera_private_ioctl_arg *k_ioctl = argp; + + switch (k_ioctl->id) { + case MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX: { + struct msm_buf_mngr_info *tmp = NULL; + + if (!k_ioctl->ioctl_ptr) + return -EINVAL; + if (k_ioctl->size != sizeof(struct msm_buf_mngr_info)) + return -EINVAL; + + MSM_CAM_GET_IOCTL_ARG_PTR(&tmp, &k_ioctl->ioctl_ptr, + sizeof(tmp)); + rc = msm_buf_mngr_get_buf_by_idx(msm_buf_mngr_dev, + tmp); + } + break; + default: + pr_debug("unimplemented id %d", k_ioctl->id); + return -EINVAL; + } + break; + } + default: + return -ENOIOCTLCMD; + } + + return rc; +} + +int msm_cam_buf_mgr_register_ops(struct msm_cam_buf_mgr_req_ops *cb_struct) +{ + if (!msm_buf_mngr_dev) + return -ENODEV; + if (!cb_struct) + return -EINVAL; + + cb_struct->msm_cam_buf_mgr_ops = msm_cam_buf_mgr_ops; + return 0; +} + static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { @@ -425,16 +533,45 @@ static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd, rc = -ENOMEM; return rc; } - switch (cmd) { - case VIDIOC_MSM_BUF_MNGR_GET_BUF: - rc = msm_buf_mngr_get_buf(buf_mngr_dev, argp); + case VIDIOC_MSM_BUF_MNGR_IOCTL_CMD: { + struct msm_camera_private_ioctl_arg k_ioctl, *ptr; + + if (!arg) + return -EINVAL; + ptr = arg; + k_ioctl = *ptr; + switch (k_ioctl.id) { + case MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX: { + struct msm_buf_mngr_info buf_info, *tmp = NULL; + + if (k_ioctl.size != sizeof(struct msm_buf_mngr_info)) + return -EINVAL; + if (!k_ioctl.ioctl_ptr) + return -EINVAL; + + MSM_CAM_GET_IOCTL_ARG_PTR(&tmp, &k_ioctl.ioctl_ptr, + sizeof(tmp)); + if (copy_from_user(&buf_info, tmp, + sizeof(struct msm_buf_mngr_info))) { + return -EFAULT; + } + MSM_CAM_GET_IOCTL_ARG_PTR(&k_ioctl.ioctl_ptr, + &buf_info, sizeof(void *)); + argp = &k_ioctl; + rc = msm_cam_buf_mgr_ops(cmd, argp); + } + break; + default: + pr_debug("unimplemented id %d", k_ioctl.id); + return -EINVAL; + } break; + } + case VIDIOC_MSM_BUF_MNGR_GET_BUF: case VIDIOC_MSM_BUF_MNGR_BUF_DONE: - rc = msm_buf_mngr_buf_done(buf_mngr_dev, argp); - break; case VIDIOC_MSM_BUF_MNGR_PUT_BUF: - rc = msm_buf_mngr_put_buf(buf_mngr_dev, argp); + rc = msm_cam_buf_mgr_ops(cmd, argp); break; case VIDIOC_MSM_BUF_MNGR_INIT: rc = msm_generic_buf_mngr_open(sd, NULL); @@ -462,6 +599,107 @@ static long msm_buf_mngr_subdev_ioctl(struct v4l2_subdev *sd, } #ifdef CONFIG_COMPAT +static long msm_camera_buf_mgr_fetch_buf_info( + struct msm_buf_mngr_info32_t *buf_info32, + struct msm_buf_mngr_info *buf_info, unsigned long arg) +{ + if (!arg || !buf_info32 || !buf_info) + return -EINVAL; + + if (copy_from_user(buf_info32, (void __user *)arg, + sizeof(struct msm_buf_mngr_info32_t))) + return -EFAULT; + + buf_info->session_id = buf_info32->session_id; + buf_info->stream_id = buf_info32->stream_id; + buf_info->frame_id = buf_info32->frame_id; + buf_info->index = buf_info32->index; + buf_info->timestamp.tv_sec = (long) buf_info32->timestamp.tv_sec; + buf_info->timestamp.tv_usec = (long) buf_info32-> + timestamp.tv_usec; + buf_info->reserved = buf_info32->reserved; + buf_info->type = buf_info32->type; + return 0; +} + +static long msm_camera_buf_mgr_update_buf_info( + struct msm_buf_mngr_info32_t *buf_info32, + struct msm_buf_mngr_info *buf_info, unsigned long arg) +{ + if (!arg || !buf_info32 || !buf_info) + return -EINVAL; + + buf_info32->session_id = buf_info->session_id; + buf_info32->stream_id = buf_info->stream_id; + buf_info32->index = buf_info->index; + buf_info32->timestamp.tv_sec = (int32_t) buf_info-> + timestamp.tv_sec; + buf_info32->timestamp.tv_usec = (int32_t) buf_info->timestamp. + tv_usec; + buf_info32->reserved = buf_info->reserved; + buf_info32->type = buf_info->type; + buf_info32->user_buf.buf_cnt = buf_info->user_buf.buf_cnt; + memcpy(&buf_info32->user_buf.buf_idx, + &buf_info->user_buf.buf_idx, + sizeof(buf_info->user_buf.buf_idx)); + if (copy_to_user((void __user *)arg, buf_info32, + sizeof(struct msm_buf_mngr_info32_t))) + return -EFAULT; + return 0; +} +static long msm_camera_buf_mgr_internal_compat_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + long rc = 0; + struct msm_camera_private_ioctl_arg k_ioctl; + void __user *tmp_compat_ioctl_ptr = NULL; + + rc = msm_copy_camera_private_ioctl_args(arg, + &k_ioctl, &tmp_compat_ioctl_ptr); + if (rc < 0) { + pr_err("Subdev cmd %d failed\n", cmd); + return rc; + } + + switch (k_ioctl.id) { + case MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX: { + struct msm_buf_mngr_info32_t buf_info32; + struct msm_buf_mngr_info buf_info; + + if (k_ioctl.size != sizeof(struct msm_buf_mngr_info32_t)) { + pr_err("Invalid size for id %d with size %d", + k_ioctl.id, k_ioctl.size); + return -EINVAL; + } + if (!tmp_compat_ioctl_ptr) { + pr_err("Invalid ptr for id %d", k_ioctl.id); + return -EINVAL; + } + k_ioctl.ioctl_ptr = (__u64)&buf_info; + rc = msm_camera_buf_mgr_fetch_buf_info(&buf_info32, &buf_info, + (unsigned long)tmp_compat_ioctl_ptr); + if (rc < 0) { + pr_err("Fetch buf info failed for cmd=%d", cmd); + return rc; + } + rc = v4l2_subdev_call(sd, core, ioctl, cmd, &k_ioctl); + if (rc < 0) { + pr_err("Subdev cmd %d failed for id %d", cmd, + k_ioctl.id); + return rc; + } + } + break; + default: + pr_debug("unimplemented id %d", k_ioctl.id); + return -EINVAL; + } + + return 0; +} + static long msm_bmgr_subdev_fops_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -469,8 +707,6 @@ static long msm_bmgr_subdev_fops_compat_ioctl(struct file *file, struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); int32_t rc = 0; - void __user *up = (void __user *)arg; - /* Convert 32 bit IOCTL ID's to 64 bit IOCTL ID's * except VIDIOC_MSM_CPP_CFG32, which needs special * processing @@ -486,13 +722,14 @@ static long msm_bmgr_subdev_fops_compat_ioctl(struct file *file, cmd = VIDIOC_MSM_BUF_MNGR_PUT_BUF; break; case VIDIOC_MSM_BUF_MNGR_CONT_CMD: - cmd = VIDIOC_MSM_BUF_MNGR_CONT_CMD; break; case VIDIOC_MSM_BUF_MNGR_FLUSH32: cmd = VIDIOC_MSM_BUF_MNGR_FLUSH; break; + case VIDIOC_MSM_BUF_MNGR_IOCTL_CMD: + break; default: - pr_debug("%s : unsupported compat type", __func__); + pr_debug("unsupported compat type\n"); return -ENOIOCTLCMD; } @@ -504,65 +741,51 @@ static long msm_bmgr_subdev_fops_compat_ioctl(struct file *file, struct msm_buf_mngr_info32_t buf_info32; struct msm_buf_mngr_info buf_info; - if (copy_from_user(&buf_info32, (void __user *)up, - sizeof(struct msm_buf_mngr_info32_t))) - return -EFAULT; - - buf_info.session_id = buf_info32.session_id; - buf_info.stream_id = buf_info32.stream_id; - buf_info.frame_id = buf_info32.frame_id; - buf_info.index = buf_info32.index; - buf_info.timestamp.tv_sec = (long) buf_info32.timestamp.tv_sec; - buf_info.timestamp.tv_usec = (long) buf_info32. - timestamp.tv_usec; - buf_info.reserved = buf_info32.reserved; - buf_info.type = buf_info32.type; - + rc = msm_camera_buf_mgr_fetch_buf_info(&buf_info32, &buf_info, + arg); + if (rc < 0) { + pr_err("Fetch buf info failed for cmd=%d\n", cmd); + return rc; + } rc = v4l2_subdev_call(sd, core, ioctl, cmd, &buf_info); if (rc < 0) { - pr_debug("%s : Subdev cmd %d fail", __func__, cmd); + pr_debug("Subdev cmd %d fail\n", cmd); + return rc; + } + rc = msm_camera_buf_mgr_update_buf_info(&buf_info32, &buf_info, + arg); + if (rc < 0) { + pr_err("Update buf info failed for cmd=%d\n", cmd); + return rc; + } + break; + } + case VIDIOC_MSM_BUF_MNGR_IOCTL_CMD: { + rc = msm_camera_buf_mgr_internal_compat_ioctl(file, cmd, arg); + if (rc < 0) { + pr_debug("Subdev cmd %d fail\n", cmd); return rc; } - - buf_info32.session_id = buf_info.session_id; - buf_info32.stream_id = buf_info.stream_id; - buf_info32.index = buf_info.index; - buf_info32.timestamp.tv_sec = (int32_t) buf_info. - timestamp.tv_sec; - buf_info32.timestamp.tv_usec = (int32_t) buf_info.timestamp. - tv_usec; - buf_info32.reserved = buf_info.reserved; - buf_info32.type = buf_info.type; - buf_info32.user_buf.buf_cnt = buf_info.user_buf.buf_cnt; - memcpy(&buf_info32.user_buf.buf_idx, - &buf_info.user_buf.buf_idx, - sizeof(buf_info.user_buf.buf_idx)); - if (copy_to_user((void __user *)up, &buf_info32, - sizeof(struct msm_buf_mngr_info32_t))) - return -EFAULT; } break; case VIDIOC_MSM_BUF_MNGR_CONT_CMD: { struct msm_buf_mngr_main_cont_info cont_cmd; - if (copy_from_user(&cont_cmd, (void __user *)up, + if (copy_from_user(&cont_cmd, (void __user *)arg, sizeof(struct msm_buf_mngr_main_cont_info))) return -EFAULT; rc = v4l2_subdev_call(sd, core, ioctl, cmd, &cont_cmd); if (rc < 0) { - pr_debug("%s : Subdev cmd %d fail", __func__, cmd); + pr_debug("Subdev cmd %d fail\n", cmd); return rc; } } break; default: - pr_debug("%s : unsupported compat type", __func__); + pr_debug("unsupported compat type\n"); return -ENOIOCTLCMD; break; } - - - return 0; } #endif diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h index dc7f745f6190..c2f1a1527800 100644 --- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h +++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -52,4 +52,14 @@ struct msm_buf_mngr_user_buf_cont_info { uint32_t cnt; struct ion_handle *ion_handle; }; + +/* kernel space functions*/ +struct msm_cam_buf_mgr_req_ops { + int (*msm_cam_buf_mgr_ops)(unsigned int cmd, void *argp); +}; + +/* API to register callback from client. This assumes cb_struct is allocated by + * client. + */ +int msm_cam_buf_mgr_register_ops(struct msm_cam_buf_mgr_req_ops *cb_struct); #endif diff --git a/drivers/media/platform/msm/camera_v2/msm_sd.h b/drivers/media/platform/msm/camera_v2/msm_sd.h index 6bb95ad0de87..d893d9fc07e3 100644 --- a/drivers/media/platform/msm/camera_v2/msm_sd.h +++ b/drivers/media/platform/msm/camera_v2/msm_sd.h @@ -73,6 +73,8 @@ struct msm_sd_req_vb2_q { unsigned int stream_id); struct vb2_queue * (*get_vb2_queue)(int session_id, unsigned int stream_id); + struct vb2_v4l2_buffer * (*get_buf_by_idx)(int session_id, + unsigned int stream_id, uint32_t index); int (*put_buf)(struct vb2_v4l2_buffer *vb2_buf, int session_id, unsigned int stream_id); int (*buf_done)(struct vb2_v4l2_buffer *vb2_v4l2_buf, int session_id, @@ -85,6 +87,9 @@ struct msm_sd_req_vb2_q { #define MSM_SD_NOTIFY_PUT_SD 0x00000002 #define MSM_SD_NOTIFY_REQ_CB 0x00000003 +#define MSM_CAM_GET_IOCTL_ARG_PTR(ptr, \ + ioctl_ptr, len) memcpy(ptr, ioctl_ptr, len) + int msm_sd_register(struct msm_sd_subdev *msm_subdev); int msm_sd_unregister(struct msm_sd_subdev *sd); struct v4l2_subdev *msm_sd_get_subdev(struct v4l2_subdev *sd, diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c index 6e0dac4608a9..59135225cb15 100644 --- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c +++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.c @@ -231,6 +231,41 @@ end: return vb2_v4l2_buf; } +static struct vb2_v4l2_buffer *msm_vb2_get_buf_by_idx(int session_id, + unsigned int stream_id, uint32_t index) +{ + struct msm_stream *stream; + struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; + struct msm_vb2_buffer *msm_vb2 = NULL; + unsigned long flags; + + stream = msm_get_stream(session_id, stream_id); + if (IS_ERR_OR_NULL(stream)) + return NULL; + + spin_lock_irqsave(&stream->stream_lock, flags); + + if (!stream->vb2_q) { + pr_err("%s: stream q not available\n", __func__); + goto end; + } + + list_for_each_entry(msm_vb2, &(stream->queued_list), list) { + vb2_v4l2_buf = &(msm_vb2->vb2_v4l2_buf); + if ((vb2_v4l2_buf->vb2_buf.index != index) || msm_vb2->in_freeq + || vb2_v4l2_buf->vb2_buf.state != VB2_BUF_STATE_ACTIVE) + continue; + + msm_vb2->in_freeq = 1; + goto end; + } + msm_vb2 = NULL; + vb2_v4l2_buf = NULL; +end: + spin_unlock_irqrestore(&stream->stream_lock, flags); + return vb2_v4l2_buf; +} + static int msm_vb2_put_buf(struct vb2_v4l2_buffer *vb, int session_id, unsigned int stream_id) { @@ -320,6 +355,48 @@ static int msm_vb2_buf_done(struct vb2_v4l2_buffer *vb, int session_id, return rc; } +long msm_vb2_return_buf_by_idx(int session_id, unsigned int stream_id, + uint32_t index) +{ + struct msm_stream *stream; + struct vb2_v4l2_buffer *vb2_v4l2_buf = NULL; + struct msm_vb2_buffer *msm_vb2 = NULL; + unsigned long flags; + long rc = -EINVAL; + + stream = msm_get_stream(session_id, stream_id); + if (IS_ERR_OR_NULL(stream)) + return rc; + + spin_lock_irqsave(&stream->stream_lock, flags); + + if (!stream->vb2_q) { + pr_err("%s: stream q not available\n", __func__); + goto end; + } + + list_for_each_entry(msm_vb2, &(stream->queued_list), list) { + vb2_v4l2_buf = &(msm_vb2->vb2_v4l2_buf); + if ((vb2_v4l2_buf->vb2_buf.index != index) + || vb2_v4l2_buf->vb2_buf.state != VB2_BUF_STATE_ACTIVE) + continue; + + if (!msm_vb2->in_freeq) { + vb2_buffer_done(&vb2_v4l2_buf->vb2_buf, + VB2_BUF_STATE_ERROR); + rc = 0; + } else { + rc = -EINVAL; + } + break; + } + +end: + spin_unlock_irqrestore(&stream->stream_lock, flags); + return rc; +} +EXPORT_SYMBOL(msm_vb2_return_buf_by_idx); + static int msm_vb2_flush_buf(int session_id, unsigned int stream_id) { unsigned long flags; @@ -350,11 +427,11 @@ int msm_vb2_request_cb(struct msm_sd_req_vb2_q *req) } req->get_buf = msm_vb2_get_buf; + req->get_buf_by_idx = msm_vb2_get_buf_by_idx; req->get_vb2_queue = msm_vb2_get_queue; req->put_buf = msm_vb2_put_buf; req->buf_done = msm_vb2_buf_done; req->flush_buf = msm_vb2_flush_buf; - return 0; } diff --git a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h index 96fa1d4c64c9..53511d5416d7 100644 --- a/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h +++ b/drivers/media/platform/msm/camera_v2/msm_vb2/msm_vb2.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -65,5 +65,7 @@ struct msm_stream { struct vb2_ops *msm_vb2_get_q_ops(void); struct vb2_mem_ops *msm_vb2_get_q_mem_ops(void); int msm_vb2_request_cb(struct msm_sd_req_vb2_q *req_sd); +long msm_vb2_return_buf_by_idx(int session_id, unsigned int stream_id, + uint32_t index); #endif /*_MSM_VB_H */ diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c index a7ac094f6c1e..140d33582c87 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c @@ -90,10 +90,42 @@ static const struct v4l2_fmtdesc fmtdesc[] = { .pixelformat = SDE_PIX_FMT_BGRX_8888, }, { + .description = "SDE/XBGR_8888", + .pixelformat = SDE_PIX_FMT_XBGR_8888, + }, + { .description = "RGBA_5551", .pixelformat = SDE_PIX_FMT_RGBA_5551, }, { + .description = "ARGB_1555", + .pixelformat = SDE_PIX_FMT_ARGB_1555, + }, + { + .description = "ABGR_1555", + .pixelformat = SDE_PIX_FMT_ABGR_1555, + }, + { + .description = "BGRA_5551", + .pixelformat = SDE_PIX_FMT_BGRA_5551, + }, + { + .description = "BGRX_5551", + .pixelformat = SDE_PIX_FMT_BGRX_5551, + }, + { + .description = "RGBX_5551", + .pixelformat = SDE_PIX_FMT_RGBX_5551, + }, + { + .description = "XBGR_1555", + .pixelformat = SDE_PIX_FMT_XBGR_1555, + }, + { + .description = "XRGB_1555", + .pixelformat = SDE_PIX_FMT_XRGB_1555, + }, + { .description = "ARGB_4444", .pixelformat = SDE_PIX_FMT_ARGB_4444, }, @@ -102,6 +134,30 @@ static const struct v4l2_fmtdesc fmtdesc[] = { .pixelformat = SDE_PIX_FMT_RGBA_4444, }, { + .description = "BGRA_4444", + .pixelformat = SDE_PIX_FMT_BGRA_4444, + }, + { + .description = "ABGR_4444", + .pixelformat = SDE_PIX_FMT_ABGR_4444, + }, + { + .description = "RGBX_4444", + .pixelformat = SDE_PIX_FMT_RGBX_4444, + }, + { + .description = "XRGB_4444", + .pixelformat = SDE_PIX_FMT_XRGB_4444, + }, + { + .description = "BGRX_4444", + .pixelformat = SDE_PIX_FMT_BGRX_4444, + }, + { + .description = "XBGR_4444", + .pixelformat = SDE_PIX_FMT_XBGR_4444, + }, + { .description = "RGB_888", .pixelformat = SDE_PIX_FMT_RGB_888, }, diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c index 8e5793362875..5318c9da1277 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c @@ -318,6 +318,10 @@ static struct sde_mdp_format_params sde_mdp_format_map[] = { SDE_PIX_FMT_BGRX_8888, SDE_MDP_FMT_LINEAR, VALID_ROT_WB_ALL | VALID_MDP_WB_INTF_FORMAT, 0, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, SDE_MDP_COMPRESS_NONE), + FMT_RGB_8888( + SDE_PIX_FMT_XBGR_8888, SDE_MDP_FMT_LINEAR, + VALID_ROT_WB_ALL | VALID_MDP_WB_INTF_FORMAT, + 0, C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, SDE_MDP_COMPRESS_NONE), FMT_YUV_PSEUDO(SDE_PIX_FMT_Y_CRCB_H2V1, SDE_MDP_FMT_LINEAR, SDE_MDP_CHROMA_H2V1, SDE_MDP_PIXEL_NORMAL, @@ -401,10 +405,36 @@ static struct sde_mdp_format_params sde_mdp_format_map[] = { }, FMT_RGB_1555(SDE_PIX_FMT_RGBA_5551, 1, VALID_ROT_WB_ALL, C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr), + FMT_RGB_1555(SDE_PIX_FMT_ARGB_1555, 1, VALID_ROT_WB_ALL, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA), + FMT_RGB_1555(SDE_PIX_FMT_ABGR_1555, 1, VALID_ROT_WB_ALL, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), + FMT_RGB_1555(SDE_PIX_FMT_BGRA_5551, 1, VALID_ROT_WB_ALL, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb), + FMT_RGB_1555(SDE_PIX_FMT_BGRX_5551, 0, VALID_ROT_WB_ALL, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb), + FMT_RGB_1555(SDE_PIX_FMT_RGBX_5551, 0, VALID_ROT_WB_ALL, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr), + FMT_RGB_1555(SDE_PIX_FMT_XBGR_1555, 0, VALID_ROT_WB_ALL, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), + FMT_RGB_1555(SDE_PIX_FMT_XRGB_1555, 0, VALID_ROT_WB_ALL, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA), FMT_RGB_4444(SDE_PIX_FMT_RGBA_4444, 1, VALID_ROT_WB_ALL, C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr), FMT_RGB_4444(SDE_PIX_FMT_ARGB_4444, 1, VALID_ROT_WB_ALL, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA), + FMT_RGB_4444(SDE_PIX_FMT_BGRA_4444, 1, VALID_ROT_WB_ALL, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb), + FMT_RGB_4444(SDE_PIX_FMT_ABGR_4444, 1, VALID_ROT_WB_ALL, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), + FMT_RGB_4444(SDE_PIX_FMT_RGBX_4444, 0, VALID_ROT_WB_ALL, + C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr), + FMT_RGB_4444(SDE_PIX_FMT_XRGB_4444, 0, VALID_ROT_WB_ALL, + C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA), + FMT_RGB_4444(SDE_PIX_FMT_BGRX_4444, 0, VALID_ROT_WB_ALL, + C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb), + FMT_RGB_4444(SDE_PIX_FMT_XBGR_4444, 0, VALID_ROT_WB_ALL, + C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA), FMT_RGB_1010102(SDE_PIX_FMT_RGBA_1010102, SDE_MDP_FMT_LINEAR, VALID_ROT_R3_WB_FORMAT | VALID_MDP_WB_INTF_FORMAT, 1, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, SDE_MDP_COMPRESS_NONE), diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c index d5388db4a9b1..c141797bcd3c 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c @@ -575,14 +575,6 @@ static u32 sde_hw_rotator_start_regdma(struct sde_hw_rotator_context *ctx, if (rot->irq_num >= 0) reinit_completion(&ctx->regdma_comp); - /* enable IRQ for first regdma submission from idle */ - if (atomic_read(&rot->regdma_submit_count) == - atomic_read(&rot->regdma_done_count)) { - SDEROT_DBG("Enable IRQ! regdma submitcnt==donecnt -> %d\n", - atomic_read(&rot->regdma_submit_count)); - enable_irq(rot->irq_num); - } - /* * Last ROT command must be ROT_START before REGDMA start */ @@ -640,9 +632,6 @@ static u32 sde_hw_rotator_start_regdma(struct sde_hw_rotator_context *ctx, enableInt | (ts_length << 14) | offset); } - /* Update REGDMA submit count */ - atomic_inc(&rot->regdma_submit_count); - /* Update command queue write ptr */ sde_hw_rotator_put_regdma_segment(ctx, wrptr); @@ -731,7 +720,6 @@ static u32 sde_hw_rotator_wait_done_regdma( u32 last_ts; u32 int_id; u32 sts = 0; - u32 d_count; unsigned long flags; if (rot->irq_num >= 0) { @@ -753,6 +741,8 @@ static u32 sde_hw_rotator_wait_done_regdma( SDEROT_ERR( "Timeout wait for regdma interrupt status, ts:%X\n", ctx->timestamp); + SDEROT_ERR("last_isr:0x%X, last_ts:0x%X, rc=%d\n", + last_isr, last_ts, rc); if (status & REGDMA_WATCHDOG_INT) SDEROT_ERR("REGDMA watchdog interrupt\n"); @@ -784,17 +774,6 @@ static u32 sde_hw_rotator_wait_done_regdma( status = 0; } - /* regardless success or timeout, update done count */ - d_count = atomic_inc_return(&rot->regdma_done_count); - - /* disable IRQ if no more regdma submission in queue */ - if (d_count == atomic_read(&rot->regdma_submit_count)) { - SDEROT_DBG( - "Disable IRQ!! regdma donecnt==submitcnt -> %d\n", - d_count); - disable_irq_nosync(rot->irq_num); - } - spin_unlock_irqrestore(&rot->rotisr_lock, flags); } else { int cnt = 200; @@ -1027,6 +1006,9 @@ static struct sde_rot_hw_resource *sde_hw_rotator_alloc_ext( sde_hw_rotator_swts_create(resinfo->rot); } + if (resinfo->rot->irq_num >= 0) + enable_irq(resinfo->rot->irq_num); + SDEROT_DBG("New rotator resource:%p, priority:%d\n", resinfo, wb_id); @@ -1053,6 +1035,9 @@ static void sde_hw_rotator_free_ext(struct sde_rot_mgr *mgr, resinfo, hw->wb_id, atomic_read(&hw->num_active), hw->pending_count); + if (resinfo->rot->irq_num >= 0) + disable_irq(resinfo->rot->irq_num); + devm_kfree(&mgr->pdev->dev, resinfo); } @@ -1505,8 +1490,7 @@ static irqreturn_t sde_hw_rotator_regdmairq_handler(int irq, void *ptr) ctx->last_regdma_isr_status = isr; ctx->last_regdma_timestamp = ts; SDEROT_DBG( - "regdma complete: ctx:%p, ts:%X, dcount:%X\n", - ctx, ts, atomic_read(&rot->regdma_done_count)); + "regdma complete: ctx:%p, ts:%X\n", ctx, ts); complete_all(&ctx->regdma_comp); ts = (ts - 1) & SDE_REGDMA_SWTS_MASK; @@ -1854,8 +1838,6 @@ int sde_rotator_r3_init(struct sde_rot_mgr *mgr) atomic_set(&rot->timestamp[0], 0); atomic_set(&rot->timestamp[1], 0); - atomic_set(&rot->regdma_submit_count, 0); - atomic_set(&rot->regdma_done_count, 0); ret = sde_rotator_hw_rev_init(rot); if (ret) diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h index 5196b1351542..610caf16c764 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h @@ -263,9 +263,6 @@ struct sde_hw_rotator { struct completion rot_comp; struct completion regdma_comp; - atomic_t regdma_submit_count; - atomic_t regdma_done_count; - spinlock_t rotctx_lock; spinlock_t rotisr_lock; diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c index 0469ffc95ef5..d58684109395 100644 --- a/drivers/media/platform/msm/vidc/hfi_packetization.c +++ b/drivers/media/platform/msm/vidc/hfi_packetization.c @@ -91,7 +91,7 @@ static int nal_type[] = { static inline int hal_to_hfi_type(int property, int hal_type) { - if (hal_type && roundup_pow_of_two(hal_type) != hal_type) { + if (hal_type <= 0 || roundup_pow_of_two(hal_type) != hal_type) { /* Not a power of 2, it's not going * to be in any of the tables anyway */ return -EINVAL; @@ -1448,6 +1448,12 @@ int create_pkt_cmd_session_set_property( case HAL_RATE_CONTROL_VBR_VFR: pkt->rg_property_data[1] = HFI_RATE_CONTROL_VBR_VFR; break; + case HAL_RATE_CONTROL_MBR_CFR: + pkt->rg_property_data[1] = HFI_RATE_CONTROL_MBR_CFR; + break; + case HAL_RATE_CONTROL_MBR_VFR: + pkt->rg_property_data[1] = HFI_RATE_CONTROL_MBR_VFR; + break; default: dprintk(VIDC_ERR, "Invalid Rate control setting: %p\n", @@ -1559,6 +1565,25 @@ int create_pkt_cmd_session_set_property( sizeof(struct hfi_quantization_range); break; } + case HAL_PARAM_VENC_SESSION_QP_RANGE_PACKED: + { + struct hfi_quantization_range *hfi; + struct hfi_quantization_range *hal_range = + (struct hfi_quantization_range *) pdata; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE; + hfi = (struct hfi_quantization_range *) + &pkt->rg_property_data[1]; + + hfi->min_qp = hal_range->min_qp; + hfi->max_qp = hal_range->max_qp; + hfi->layer_id = hal_range->layer_id; + + pkt->size += sizeof(u32) + + sizeof(struct hfi_quantization_range); + break; + } case HAL_PARAM_VENC_SEARCH_RANGE: { struct hfi_vc1e_perf_cfg_type *hfi; diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c index 009d8271563d..4ae13944362a 100644 --- a/drivers/media/platform/msm/vidc/msm_smem.c +++ b/drivers/media/platform/msm/vidc/msm_smem.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -462,6 +462,23 @@ struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset, return mem; } +bool msm_smem_compare_buffers(void *clt, int fd, void *priv) +{ + struct smem_client *client = clt; + struct ion_handle *handle = NULL; + bool ret = false; + + if (!clt || !priv) { + dprintk(VIDC_ERR, "Invalid params: %p, %p\n", + clt, priv); + return false; + } + handle = ion_import_dma_buf(client->clnt, fd); + ret = handle == priv; + handle ? ion_free(client->clnt, handle) : 0; + return ret; +} + static int ion_cache_operations(struct smem_client *client, struct msm_smem *mem, enum smem_cache_ops cache_op) { diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index 54cb04fcc4f0..d8c6e30204d1 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -615,6 +615,12 @@ static u32 get_frame_size_nv12_ubwc(int plane, u32 height, u32 width) return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_UBWC, width, height); } +static u32 get_frame_size_compressed_full_yuv(int plane, + u32 max_mbs_per_frame, u32 size_per_mb) +{ + return (max_mbs_per_frame * size_per_mb * 3 / 2); +} + static u32 get_frame_size_compressed(int plane, u32 max_mbs_per_frame, u32 size_per_mb) { @@ -791,7 +797,7 @@ struct msm_vidc_format vdec_formats[] = { .description = "VP9 compressed format", .fourcc = V4L2_PIX_FMT_VP9, .num_planes = 1, - .get_frame_size = get_frame_size_compressed, + .get_frame_size = get_frame_size_compressed_full_yuv, .type = OUTPUT_PORT, }, { @@ -2835,4 +2841,3 @@ int msm_vdec_ctrl_init(struct msm_vidc_inst *inst) return msm_comm_ctrl_init(inst, msm_vdec_ctrls, ARRAY_SIZE(msm_vdec_ctrls), &msm_vdec_ctrl_ops); } - diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index 14b62984eae9..0e668b93598f 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -73,6 +73,8 @@ static const char *const mpeg_video_rate_control[] = { "VBR CFR", "CBR VFR", "CBR CFR", + "MBR CFR", + "MBR VFR", NULL }; @@ -233,7 +235,7 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { .name = "Video Framerate and Bitrate Control", .type = V4L2_CTRL_TYPE_MENU, .minimum = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF, - .maximum = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR, + .maximum = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_VFR, .default_value = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF, .step = 0, .menu_skip_mask = ~( @@ -241,7 +243,9 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR) | (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR) | (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR) | - (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR) + (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_CFR) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_VFR) ), .qmenu = mpeg_video_rate_control, }, @@ -529,6 +533,28 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { .step = 1, }, { + .id = V4L2_CID_MPEG_VIDEO_MIN_QP_PACKED, + .name = "H264 Minimum QP PACKED", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0x00010101, + .maximum = 0x00333333, + .default_value = 0x00010101, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MAX_QP_PACKED, + .name = "H264 Maximum QP PACKED", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0x00010101, + .maximum = 0x00333333, + .default_value = 0x00333333, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, .name = "Slice Mode", .type = V4L2_CTRL_TYPE_MENU, @@ -1552,52 +1578,6 @@ static int msm_venc_toggle_hier_p(struct msm_vidc_inst *inst, int layers) return rc; } -static int set_bitrate_for_each_layer(struct msm_vidc_inst *inst, - u32 num_enh_layers, u32 total_bitrate) -{ - u32 property_id = 0; - int i = 0, rc = 0; - struct hfi_device *hdev = NULL; - struct hal_bitrate bitrate; - struct hal_enable enable; - int bitrate_table[3][4] = { - {50, 50, 0, 0}, - {34, 33, 33, 0}, - {25, 25, 25, 25} - }; - - if (!inst || !inst->core || !inst->core->device) { - dprintk(VIDC_ERR, "%s - invalid input\n", __func__); - return -EINVAL; - } - - if (!num_enh_layers || num_enh_layers > ARRAY_SIZE(bitrate_table)) { - dprintk(VIDC_ERR, "%s - invalid number of enh layers: %d\n", - __func__, num_enh_layers); - return -EINVAL; - } - hdev = inst->core->device; - - property_id = HAL_PARAM_VENC_BITRATE_TYPE; - enable.enable = V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_ENABLE; - rc = call_hfi_op(hdev, session_set_property, - (void *)inst->session, property_id, &enable); - if (rc) { - dprintk(VIDC_ERR, "Failed to set layerwise bitrate\n"); - return false; - } - - for (i = 0; !rc && i <= num_enh_layers; i++) { - property_id = HAL_CONFIG_VENC_TARGET_BITRATE; - bitrate.bit_rate = (u32)((total_bitrate * - bitrate_table[num_enh_layers - 1][i]) / 100); - bitrate.layer_id = i; - rc = call_hfi_op(hdev, session_set_property, - (void *)inst->session, property_id, &bitrate); - } - return rc; -} - static inline int msm_venc_power_save_mode_enable(struct msm_vidc_inst *inst) { u32 rc = 0; @@ -2246,10 +2226,14 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR: update_ctrl.val = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR; + break; case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR: case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR: + case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_CFR: + case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_VFR: update_ctrl.val = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; + break; } final_mode = ctrl->val; @@ -2269,26 +2253,10 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) } case V4L2_CID_MPEG_VIDEO_BITRATE: { - struct v4l2_ctrl *hier_p = TRY_GET_CTRL( - V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS); - + property_id = HAL_CONFIG_VENC_TARGET_BITRATE; + bitrate.bit_rate = ctrl->val; bitrate.layer_id = 0; - if (hier_p->val && - inst->fmts[CAPTURE_PORT]->fourcc == - V4L2_PIX_FMT_H264) { - rc = set_bitrate_for_each_layer(inst, - hier_p->val, ctrl->val); - if (rc) { - dprintk(VIDC_ERR, - "failed to set bitrate for multiple layers\n"); - rc = -EINVAL; - } - } else { - property_id = HAL_CONFIG_VENC_TARGET_BITRATE; - bitrate.bit_rate = ctrl->val; - bitrate.layer_id = 0; - pdata = &bitrate; - } + pdata = &bitrate; break; } case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: @@ -2570,6 +2538,46 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) pdata = &qp_range; break; } + case V4L2_CID_MPEG_VIDEO_MIN_QP_PACKED: { + struct v4l2_ctrl *qp_max; + + qp_max = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MAX_QP_PACKED); + if (ctrl->val >= qp_max->val) { + dprintk(VIDC_ERR, + "Bad range: Min QP PACKED (0x%x) > Max QP PACKED (0x%x)\n", + ctrl->val, qp_max->val); + rc = -ERANGE; + break; + } + + property_id = HAL_PARAM_VENC_SESSION_QP_RANGE_PACKED; + qp_range.layer_id = 0; + qp_range.max_qp = qp_max->val; + qp_range.min_qp = ctrl->val; + + pdata = &qp_range; + break; + } + case V4L2_CID_MPEG_VIDEO_MAX_QP_PACKED: { + struct v4l2_ctrl *qp_min; + + qp_min = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MIN_QP_PACKED); + if (ctrl->val <= qp_min->val) { + dprintk(VIDC_ERR, + "Bad range: Max QP PACKED (%d) < Min QP PACKED (%d)\n", + ctrl->val, qp_min->val); + rc = -ERANGE; + break; + } + + property_id = HAL_PARAM_VENC_SESSION_QP_RANGE_PACKED; + qp_range.layer_id = 0; + qp_range.max_qp = ctrl->val; + qp_range.min_qp = qp_min->val; + + pdata = &qp_range; + break; + } case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: { int temp = 0; @@ -3236,8 +3244,8 @@ static int try_set_ext_ctrl(struct msm_vidc_inst *inst, bitrate.bit_rate = control[i].value; property_id = HAL_CONFIG_VENC_TARGET_BITRATE; pdata = &bitrate; - dprintk(VIDC_DBG, "layerwise bitrate for %d\n", - i); + dprintk(VIDC_DBG, "bitrate for layer(%d)=%d\n", + i, bitrate.bit_rate); rc = call_hfi_op(hdev, session_set_property, (void *)inst->session, property_id, pdata); diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index 51be8df7ff35..2dab1f98f30a 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -213,7 +213,9 @@ struct buffer_info *get_registered_buf(struct msm_vidc_inst *inst, *plane = 0; list_for_each_entry(temp, &inst->registeredbufs.list, list) { for (i = 0; i < min(temp->num_planes, VIDEO_MAX_PLANES); i++) { - bool fd_matches = fd == temp->fd[i]; + bool ion_hndl_matches = temp->handle[i] ? + msm_smem_compare_buffers(inst->mem_client, fd, + temp->handle[i]->smem_priv) : false; bool device_addr_matches = device_addr == temp->device_addr[i]; bool contains_within = CONTAINS(temp->buff_off[i], @@ -223,7 +225,7 @@ struct buffer_info *get_registered_buf(struct msm_vidc_inst *inst, temp->buff_off[i], temp->size[i]); if (!temp->inactive && - (fd_matches || device_addr_matches) && + (ion_hndl_matches || device_addr_matches) && (contains_within || overlaps)) { dprintk(VIDC_DBG, "This memory region is already mapped\n"); @@ -386,13 +388,6 @@ static inline bool is_dynamic_output_buffer_mode(struct v4l2_buffer *b, } -static inline bool is_encoder_input_buffer(struct v4l2_buffer *b, - struct msm_vidc_inst *inst) -{ - return b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && - inst->session_type == MSM_VIDC_ENCODER; -} - static inline void save_v4l2_buffer(struct v4l2_buffer *b, struct buffer_info *binfo) { @@ -907,8 +902,7 @@ int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b) for (i = 0; i < b->length; i++) { if (EXTRADATA_IDX(b->length) && - (i == EXTRADATA_IDX(b->length)) && - !b->m.planes[i].m.userptr) { + i == EXTRADATA_IDX(b->length)) { continue; } buffer_info = device_to_uvaddr(&inst->registeredbufs, @@ -943,8 +937,8 @@ int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b) if (rc) return rc; - if (is_dynamic_output_buffer_mode(b, inst) || - is_encoder_input_buffer(b, inst)) { + + if (is_dynamic_output_buffer_mode(b, inst)) { buffer_info->dequeued = true; dprintk(VIDC_DBG, "[DEQUEUED]: fd[0] = %d\n", diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 9565c28ca008..05bfabce2bb2 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -1704,36 +1704,6 @@ static struct vb2_buffer *get_vb_from_device_addr(struct buf_queue *bufq, return vb; } - -static void handle_dynamic_input_buffer(struct msm_vidc_inst *inst, - ion_phys_addr_t device_addr) -{ - struct buffer_info *binfo = NULL, *temp = NULL; - - if (inst->session_type == MSM_VIDC_ENCODER) { - binfo = device_to_uvaddr(&inst->registeredbufs, device_addr); - if (!binfo) { - dprintk(VIDC_ERR, - "%s buffer not found in registered list\n", - __func__); - return; - } - dprintk(VIDC_DBG, - "EBD fd[0] = %d -> EBD_ref_released, addr: %pa\n", - binfo->fd[0], &device_addr); - - mutex_lock(&inst->registeredbufs.lock); - list_for_each_entry(temp, &inst->registeredbufs.list, - list) { - if (temp == binfo) { - binfo->pending_deletion = true; - break; - } - } - mutex_unlock(&inst->registeredbufs.lock); - } -} - static void handle_ebd(enum hal_command_response cmd, void *data) { struct msm_vidc_cb_data_done *response = data; @@ -1754,8 +1724,6 @@ static void handle_ebd(enum hal_command_response cmd, void *data) return; } - handle_dynamic_input_buffer(inst, response->input_done.packet_buffer); - vb = get_vb_from_device_addr(&inst->bufq[OUTPUT_PORT], response->input_done.packet_buffer); if (vb) { @@ -3471,18 +3439,21 @@ int msm_vidc_comm_cmd(void *instance, union msm_v4l2_cmd *cmd) output_buf = get_buff_req_buffer(inst, msm_comm_get_hal_output_buffer(inst)); - if (!output_buf) { + if (output_buf) { + if (dec) { + ptr = (u32 *)dec->raw.data; + ptr[0] = output_buf->buffer_size; + ptr[1] = output_buf->buffer_count_actual; + dprintk(VIDC_DBG, + "Reconfig hint, size is %u, count is %u\n", + ptr[0], ptr[1]); + } else { + dprintk(VIDC_ERR, "Null decoder\n"); + } + } else { dprintk(VIDC_DBG, "This output buffer not required, buffer_type: %x\n", HAL_BUFFER_OUTPUT); - } else { - ptr = (u32 *)dec->raw.data; - ptr[0] = output_buf->buffer_size; - ptr[1] = output_buf->buffer_count_actual; - dprintk(VIDC_DBG, - "Reconfig hint, size is %u, count is %u\n", - ptr[0], ptr[1]); - } break; } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c index 3a31f8256857..fb79661dd2d7 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -73,7 +73,7 @@ static ssize_t core_info_read(struct file *file, char __user *buf, { struct msm_vidc_core *core = file->private_data; struct hfi_device *hdev; - struct hal_fw_info fw_info; + struct hal_fw_info fw_info = { {0} }; int i = 0, rc = 0; if (!core || !core->device) { diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h index c127a17b6157..72c1ddcf3a70 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h @@ -373,6 +373,7 @@ struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset, struct context_bank_info *msm_smem_get_context_bank(void *clt, bool is_secure, enum hal_buffer buffer_type); void msm_vidc_fw_unload_handler(struct work_struct *work); +bool msm_smem_compare_buffers(void *clt, int fd, void *priv); /* XXX: normally should be in msm_vidc.h, but that's meant for public APIs, * whereas this is private */ int msm_vidc_destroy(struct msm_vidc_inst *inst); diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 5525e35a029f..ac53b3bcb4ed 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -1238,6 +1238,13 @@ static unsigned long __get_clock_rate_with_bitrate(struct clock_info *clock, break; } } + + /* + * Current bitrate is higher than max supported load. + * Select max frequency to handle this load. + */ + if (i < 0) + supported_clk[j] = table[0].freq; } for (i = 0; i < data->num_sessions; i++) @@ -2218,9 +2225,14 @@ static int venus_hfi_core_init(void *device) if (rc || __iface_cmdq_write(dev, &version_pkt)) dprintk(VIDC_WARN, "Failed to send image version pkt to f/w\n"); - if (dev->res->pm_qos_latency_us) + if (dev->res->pm_qos_latency_us) { +#ifdef CONFIG_SMP + dev->qos.type = PM_QOS_REQ_AFFINE_IRQ; + dev->qos.irq = dev->hal_data->irq; +#endif pm_qos_add_request(&dev->qos, PM_QOS_CPU_DMA_LATENCY, dev->res->pm_qos_latency_us); + } mutex_unlock(&dev->lock); return rc; @@ -2244,7 +2256,8 @@ static int venus_hfi_core_release(void *dev) mutex_lock(&device->lock); - if (device->res->pm_qos_latency_us) + if (device->res->pm_qos_latency_us && + pm_qos_request_active(&device->qos)) pm_qos_remove_request(&device->qos); __set_state(device, VENUS_STATE_DEINIT); __unload_fw(device); @@ -4208,7 +4221,8 @@ static inline int __suspend(struct venus_hfi_device *device) dprintk(VIDC_DBG, "Entering power collapse\n"); - if (device->res->pm_qos_latency_us) + if (device->res->pm_qos_latency_us && + pm_qos_request_active(&device->qos)) pm_qos_remove_request(&device->qos); rc = __tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND); @@ -4235,6 +4249,9 @@ static inline int __resume(struct venus_hfi_device *device) } else if (device->power_enabled) { dprintk(VIDC_DBG, "Power is already enabled\n"); goto exit; + } else if (!__core_in_valid_state(device)) { + dprintk(VIDC_DBG, "venus_hfi_device in deinit state."); + return -EINVAL; } dprintk(VIDC_DBG, "Resuming from power collapse\n"); @@ -4270,9 +4287,14 @@ static inline int __resume(struct venus_hfi_device *device) */ __set_threshold_registers(device); - if (device->res->pm_qos_latency_us) + if (device->res->pm_qos_latency_us) { +#ifdef CONFIG_SMP + device->qos.type = PM_QOS_REQ_AFFINE_IRQ; + device->qos.irq = device->hal_data->irq; +#endif pm_qos_add_request(&device->qos, PM_QOS_CPU_DMA_LATENCY, device->res->pm_qos_latency_us); + } dprintk(VIDC_INFO, "Resumed from power collapse\n"); exit: device->skip_pc_count = 0; @@ -4399,7 +4421,7 @@ static int venus_hfi_get_fw_info(void *dev, struct hal_fw_info *fw_info) goto fail_version_string; } - for (i--; i < VENUS_VERSION_LENGTH && j < VENUS_VERSION_LENGTH; i++) + for (i--; i < VENUS_VERSION_LENGTH && j < VENUS_VERSION_LENGTH - 1; i++) fw_info->version[j++] = version[i]; fw_info->version[j] = '\0'; diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h index 8c4fa786a424..cbb4e3569b13 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi.h @@ -363,6 +363,9 @@ struct hfi_hybrid_hierp { #define HFI_RATE_CONTROL_VBR_CFR (HFI_OX_BASE + 0x3) #define HFI_RATE_CONTROL_CBR_VFR (HFI_OX_BASE + 0x4) #define HFI_RATE_CONTROL_CBR_CFR (HFI_OX_BASE + 0x5) +#define HFI_RATE_CONTROL_MBR_CFR (HFI_OX_BASE + 0x6) +#define HFI_RATE_CONTROL_MBR_VFR (HFI_OX_BASE + 0x7) + struct hfi_uncompressed_plane_actual_constraints_info { u32 buffer_type; diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h index a368257e8a66..624fd53debe8 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h @@ -236,6 +236,7 @@ enum hal_property { HAL_PARAM_VENC_LOW_LATENCY, HAL_PARAM_VENC_CONSTRAINED_INTRA_PRED, HAL_CONFIG_VENC_BLUR_RESOLUTION, + HAL_PARAM_VENC_SESSION_QP_RANGE_PACKED, }; enum hal_domain { @@ -710,6 +711,8 @@ enum hal_rate_control { HAL_RATE_CONTROL_VBR_CFR, HAL_RATE_CONTROL_CBR_VFR, HAL_RATE_CONTROL_CBR_CFR, + HAL_RATE_CONTROL_MBR_CFR, + HAL_RATE_CONTROL_MBR_VFR, HAL_UNUSED_RC = 0x10000000, }; diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c index 7830aef3db45..40f77685cc4a 100644 --- a/drivers/media/rc/sunxi-cir.c +++ b/drivers/media/rc/sunxi-cir.c @@ -153,6 +153,8 @@ static int sunxi_ir_probe(struct platform_device *pdev) if (!ir) return -ENOMEM; + spin_lock_init(&ir->ir_lock); + if (of_device_is_compatible(dn, "allwinner,sun5i-a13-ir")) ir->fifo_size = 64; else diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index ce157edd45fa..0e1ca2b00e61 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -168,6 +168,7 @@ static int si2157_init(struct dvb_frontend *fe) len = fw->data[fw->size - remaining]; if (len > SI2157_ARGLEN) { dev_err(&client->dev, "Bad firmware length\n"); + ret = -EINVAL; goto err_release_firmware; } memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len); diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c index 146071b8e116..bfff1d1c70ab 100644 --- a/drivers/media/usb/gspca/ov534.c +++ b/drivers/media/usb/gspca/ov534.c @@ -1491,8 +1491,13 @@ static void sd_set_streamparm(struct gspca_dev *gspca_dev, struct v4l2_fract *tpf = &cp->timeperframe; struct sd *sd = (struct sd *) gspca_dev; - /* Set requested framerate */ - sd->frame_rate = tpf->denominator / tpf->numerator; + if (tpf->numerator == 0 || tpf->denominator == 0) + /* Set default framerate */ + sd->frame_rate = 30; + else + /* Set requested framerate */ + sd->frame_rate = tpf->denominator / tpf->numerator; + if (gspca_dev->streaming) set_frame_rate(gspca_dev); diff --git a/drivers/media/usb/gspca/topro.c b/drivers/media/usb/gspca/topro.c index c70ff406b07a..c028a5c2438e 100644 --- a/drivers/media/usb/gspca/topro.c +++ b/drivers/media/usb/gspca/topro.c @@ -4802,7 +4802,11 @@ static void sd_set_streamparm(struct gspca_dev *gspca_dev, struct v4l2_fract *tpf = &cp->timeperframe; int fr, i; - sd->framerate = tpf->denominator / tpf->numerator; + if (tpf->numerator == 0 || tpf->denominator == 0) + sd->framerate = 30; + else + sd->framerate = tpf->denominator / tpf->numerator; + if (gspca_dev->streaming) setframerate(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure)); diff --git a/drivers/media/v4l2-core/videobuf2-v4l2.c b/drivers/media/v4l2-core/videobuf2-v4l2.c index 27b4b9e7c0c2..502984c724ff 100644 --- a/drivers/media/v4l2-core/videobuf2-v4l2.c +++ b/drivers/media/v4l2-core/videobuf2-v4l2.c @@ -822,10 +822,10 @@ unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) return res | POLLERR; /* - * For output streams you can write as long as there are fewer buffers - * queued than there are buffers available. + * For output streams you can call write() as long as there are fewer + * buffers queued than there are buffers available. */ - if (q->is_output && q->queued_count < q->num_buffers) + if (q->is_output && q->fileio && q->queued_count < q->num_buffers) return res | POLLOUT | POLLWRNORM; if (list_empty(&q->done_list)) { diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 6622ef8f45bb..a97f5df7a7db 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1563,6 +1563,23 @@ config WCD9335_CODEC The WCD9335 codec support either I2C/I2S or Slimbus for control and data exchnage with master processor. +config WCD934X_CODEC + tristate "WCD934X Codec" + depends on SLIMBUS + select SOUNDWIRE_WCD_CTRL + select MFD_CORE + select WCD9XXX_CODEC_UTIL + select MSM_CDC_SUPPLY + select MSM_CDC_PINCTRL + select REGMAP_ALLOW_WRITE_DEBUGFS + select PINCTRL_WCD + help + Enables the WCD9xxx codec core driver. The core driver provides + read/write capability to registers which are part of the + WCD934X core and gives the ability to use the WCD934X codec. + The WCD934X codec supports either I2C/I2S or Slimbus for + control and data exchange with master processor. + menu "Multimedia Capabilities Port drivers" depends on ARCH_SA1100 diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 794e525a72c9..ff82ba49d70b 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -197,6 +197,8 @@ obj-$(CONFIG_WCD9330_CODEC) += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o\ wcd9330-regmap.o obj-$(CONFIG_WCD9335_CODEC) += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o\ wcd9335-regmap.o wcd9335-tables.o +obj-$(CONFIG_WCD934X_CODEC) += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o\ + wcd934x-regmap.o wcd934x-tables.o intel-soc-pmic-objs := intel_soc_pmic_core.o intel_soc_pmic_crc.o intel-soc-pmic-$(CONFIG_INTEL_PMC_IPC) += intel_soc_pmic_bxtwc.o obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o diff --git a/drivers/mfd/msm-cdc-pinctrl.c b/drivers/mfd/msm-cdc-pinctrl.c index a19e3a536950..3ffd20245877 100644 --- a/drivers/mfd/msm-cdc-pinctrl.c +++ b/drivers/mfd/msm-cdc-pinctrl.c @@ -25,6 +25,7 @@ struct msm_cdc_pinctrl_info { struct pinctrl *pinctrl; struct pinctrl_state *pinctrl_active; struct pinctrl_state *pinctrl_sleep; + int gpio; bool state; }; @@ -54,6 +55,28 @@ static struct msm_cdc_pinctrl_info *msm_cdc_pinctrl_get_gpiodata( } /* + * msm_cdc_get_gpio_state: select pinctrl sleep state + * @np: pointer to struct device_node + * + * Returns error code for failure and GPIO value on success + */ +int msm_cdc_get_gpio_state(struct device_node *np) +{ + struct msm_cdc_pinctrl_info *gpio_data; + int value = -EINVAL; + + gpio_data = msm_cdc_pinctrl_get_gpiodata(np); + if (!gpio_data) + return value; + + if (gpio_is_valid(gpio_data->gpio)) + value = gpio_get_value_cansleep(gpio_data->gpio); + + return value; +} +EXPORT_SYMBOL(msm_cdc_get_gpio_state); + +/* * msm_cdc_pinctrl_select_sleep_state: select pinctrl sleep state * @np: pointer to struct device_node * @@ -165,6 +188,17 @@ static int msm_cdc_pinctrl_probe(struct platform_device *pdev) dev_err(&pdev->dev, "%s: set cdc gpio sleep state fail: %d\n", __func__, ret); + gpio_data->gpio = of_get_named_gpio(pdev->dev.of_node, + "qcom,cdc-rst-n-gpio", 0); + if (gpio_is_valid(gpio_data->gpio)) { + ret = gpio_request(gpio_data->gpio, "MSM_CDC_RESET"); + if (ret) { + dev_err(&pdev->dev, "%s: Failed to request gpio %d\n", + __func__, gpio_data->gpio); + goto err_lookup_state; + } + } + dev_set_drvdata(&pdev->dev, gpio_data); return 0; diff --git a/drivers/mfd/msm-cdc-supply.c b/drivers/mfd/msm-cdc-supply.c index d553f7b3f492..bfb19de8ce89 100644 --- a/drivers/mfd/msm-cdc-supply.c +++ b/drivers/mfd/msm-cdc-supply.c @@ -202,7 +202,6 @@ int msm_cdc_release_supplies(struct device *dev, msm_cdc_disable_static_supplies(dev, supplies, cdc_vreg, num_supplies); - for (i = 0; i < num_supplies; i++) { if (regulator_count_voltages(supplies[i].consumer) < 0) continue; @@ -210,9 +209,9 @@ int msm_cdc_release_supplies(struct device *dev, regulator_set_voltage(supplies[i].consumer, 0, cdc_vreg[i].max_uV); regulator_set_load(supplies[i].consumer, 0); + devm_regulator_put(supplies[i].consumer); + supplies[i].consumer = NULL; } - - regulator_bulk_free(num_supplies, supplies); devm_kfree(dev, supplies); return rc; diff --git a/drivers/mfd/qcom-i2c-pmic.c b/drivers/mfd/qcom-i2c-pmic.c index 4d0bdce755a6..9eb75d876577 100644 --- a/drivers/mfd/qcom-i2c-pmic.c +++ b/drivers/mfd/qcom-i2c-pmic.c @@ -58,7 +58,6 @@ struct i2c_pmic_periph { struct i2c_pmic { struct device *dev; - struct i2c_client *client; struct regmap *regmap; struct irq_domain *domain; struct i2c_pmic_periph *periph; @@ -497,25 +496,28 @@ static struct regmap_config i2c_pmic_regmap_config = { static int i2c_pmic_probe(struct i2c_client *client, const struct i2c_device_id *id) { - int rc; struct i2c_pmic *chip; + int rc = 0; chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; + chip->dev = &client->dev; chip->regmap = devm_regmap_init_i2c(client, &i2c_pmic_regmap_config); if (!chip->regmap) return -ENODEV; + i2c_set_clientdata(client, chip); + if (!of_property_read_bool(chip->dev->of_node, "interrupt-controller")) + goto probe_children; + chip->domain = irq_domain_add_tree(client->dev.of_node, &i2c_pmic_domain_ops, chip); - if (!chip->domain) - return -ENOMEM; - - chip->client = client; - chip->dev = &client->dev; - i2c_set_clientdata(client, chip); + if (!chip->domain) { + rc = -ENOMEM; + goto cleanup; + } rc = i2c_pmic_parse_dt(chip); if (rc < 0) { @@ -549,6 +551,8 @@ static int i2c_pmic_probe(struct i2c_client *client, } enable_irq_wake(client->irq); + +probe_children: of_platform_populate(chip->dev->of_node, NULL, NULL, chip->dev); pr_info("I2C PMIC probe successful\n"); return rc; @@ -565,7 +569,8 @@ static int i2c_pmic_remove(struct i2c_client *client) struct i2c_pmic *chip = i2c_get_clientdata(client); of_platform_depopulate(chip->dev); - irq_domain_remove(chip->domain); + if (chip->domain) + irq_domain_remove(chip->domain); i2c_set_clientdata(client, NULL); return 0; } diff --git a/drivers/mfd/wcd934x-regmap.c b/drivers/mfd/wcd934x-regmap.c new file mode 100644 index 000000000000..7f16f1f3f417 --- /dev/null +++ b/drivers/mfd/wcd934x-regmap.c @@ -0,0 +1,1860 @@ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/mfd/wcd9xxx/core.h> +#include <linux/mfd/wcd934x/registers.h> +#include <linux/regmap.h> +#include <linux/device.h> +#include "wcd9xxx-regmap.h" + +static const struct reg_default wcd934x_defaults[] = { + { WCD934X_PAGE0_PAGE_REGISTER, 0x00 }, + { WCD934X_CODEC_RPM_CLK_BYPASS, 0x00 }, + { WCD934X_CODEC_RPM_CLK_GATE, 0x1f }, + { WCD934X_CODEC_RPM_CLK_MCLK_CFG, 0x00 }, + { WCD934X_CODEC_RPM_CLK_MCLK2_CFG, 0x02 }, + { WCD934X_CODEC_RPM_I2S_DSD_CLK_SEL, 0x00 }, + { WCD934X_CODEC_RPM_RST_CTL, 0x00 }, + { WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x04 }, + { WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE1, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE2, 0x08 }, + { WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE3, 0x01 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_CTL, 0x10 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_TEST0, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_TEST1, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT0, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT1, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT2, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT3, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT4, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT5, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT6, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT7, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT8, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT9, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT10, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT11, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT12, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT13, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT14, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT15, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_EFUSE_STATUS, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_NONNEGO, 0x0d }, + { WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_1, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_2, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_3, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_ANA_WAIT_STATE_CTL, 0xcc }, + { WCD934X_CHIP_TIER_CTRL_SLNQ_WAIT_STATE_CTL, 0xcc }, + { WCD934X_CHIP_TIER_CTRL_I2C_ACTIVE, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_ALT_FUNC_EN, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_GPIO_CTL_OE, 0x00 }, + { WCD934X_CHIP_TIER_CTRL_GPIO_CTL_DATA, 0x00 }, + { WCD934X_DATA_HUB_RX0_CFG, 0x00 }, + { WCD934X_DATA_HUB_RX1_CFG, 0x00 }, + { WCD934X_DATA_HUB_RX2_CFG, 0x00 }, + { WCD934X_DATA_HUB_RX3_CFG, 0x00 }, + { WCD934X_DATA_HUB_RX4_CFG, 0x00 }, + { WCD934X_DATA_HUB_RX5_CFG, 0x00 }, + { WCD934X_DATA_HUB_RX6_CFG, 0x00 }, + { WCD934X_DATA_HUB_RX7_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX0_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX1_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX2_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX3_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX4_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX5_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX6_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX7_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX8_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX9_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX10_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX11_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX13_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX14_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_SB_TX15_INP_CFG, 0x00 }, + { WCD934X_DATA_HUB_I2S_TX0_CFG, 0x00 }, + { WCD934X_DATA_HUB_I2S_TX1_0_CFG, 0x00 }, + { WCD934X_DATA_HUB_I2S_TX1_1_CFG, 0x00 }, + { WCD934X_DATA_HUB_I2S_0_CTL, 0x0c }, + { WCD934X_DATA_HUB_I2S_1_CTL, 0x0c }, + { WCD934X_DATA_HUB_I2S_2_CTL, 0x0c }, + { WCD934X_DATA_HUB_I2S_3_CTL, 0x0c }, + { WCD934X_DATA_HUB_I2S_CLKSRC_CTL, 0x00 }, + { WCD934X_DATA_HUB_I2S_COMMON_CTL, 0x00 }, + { WCD934X_DATA_HUB_I2S_0_TDM_CTL, 0x00 }, + { WCD934X_DATA_HUB_I2S_STATUS, 0x00 }, + { WCD934X_DMA_RDMA_CTL_0, 0x00 }, + { WCD934X_DMA_CH_2_3_CFG_RDMA_0, 0xff }, + { WCD934X_DMA_CH_0_1_CFG_RDMA_0, 0xff }, + { WCD934X_DMA_RDMA_CTL_1, 0x00 }, + { WCD934X_DMA_CH_2_3_CFG_RDMA_1, 0xff }, + { WCD934X_DMA_CH_0_1_CFG_RDMA_1, 0xff }, + { WCD934X_DMA_RDMA_CTL_2, 0x00 }, + { WCD934X_DMA_CH_2_3_CFG_RDMA_2, 0xff }, + { WCD934X_DMA_CH_0_1_CFG_RDMA_2, 0xff }, + { WCD934X_DMA_RDMA_CTL_3, 0x00 }, + { WCD934X_DMA_CH_2_3_CFG_RDMA_3, 0xff }, + { WCD934X_DMA_CH_0_1_CFG_RDMA_3, 0xff }, + { WCD934X_DMA_RDMA_CTL_4, 0x00 }, + { WCD934X_DMA_CH_2_3_CFG_RDMA_4, 0xff }, + { WCD934X_DMA_CH_0_1_CFG_RDMA_4, 0xff }, + { WCD934X_DMA_RDMA4_PRT_CFG, 0x00 }, + { WCD934X_DMA_RDMA_SBTX0_7_CFG, 0x00 }, + { WCD934X_DMA_RDMA_SBTX8_11_CFG, 0x00 }, + { WCD934X_DMA_WDMA_CTL_0, 0x00 }, + { WCD934X_DMA_CH_4_5_CFG_WDMA_0, 0x00 }, + { WCD934X_DMA_CH_2_3_CFG_WDMA_0, 0x00 }, + { WCD934X_DMA_CH_0_1_CFG_WDMA_0, 0x00 }, + { WCD934X_DMA_WDMA_CTL_1, 0x00 }, + { WCD934X_DMA_CH_4_5_CFG_WDMA_1, 0x00 }, + { WCD934X_DMA_CH_2_3_CFG_WDMA_1, 0x00 }, + { WCD934X_DMA_CH_0_1_CFG_WDMA_1, 0x00 }, + { WCD934X_DMA_WDMA_CTL_2, 0x00 }, + { WCD934X_DMA_CH_4_5_CFG_WDMA_2, 0x00 }, + { WCD934X_DMA_CH_2_3_CFG_WDMA_2, 0x00 }, + { WCD934X_DMA_CH_0_1_CFG_WDMA_2, 0x00 }, + { WCD934X_DMA_WDMA_CTL_3, 0x00 }, + { WCD934X_DMA_CH_4_5_CFG_WDMA_3, 0x00 }, + { WCD934X_DMA_CH_2_3_CFG_WDMA_3, 0x00 }, + { WCD934X_DMA_CH_0_1_CFG_WDMA_3, 0x00 }, + { WCD934X_DMA_WDMA_CTL_4, 0x00 }, + { WCD934X_DMA_CH_4_5_CFG_WDMA_4, 0x00 }, + { WCD934X_DMA_CH_2_3_CFG_WDMA_4, 0x00 }, + { WCD934X_DMA_CH_0_1_CFG_WDMA_4, 0x00 }, + { WCD934X_DMA_WDMA0_PRT_CFG, 0x00 }, + { WCD934X_DMA_WDMA3_PRT_CFG, 0x00 }, + { WCD934X_DMA_WDMA4_PRT0_3_CFG, 0x00 }, + { WCD934X_DMA_WDMA4_PRT4_7_CFG, 0x00 }, + { WCD934X_PAGE1_PAGE_REGISTER, 0x00 }, + { WCD934X_CPE_FLL_USER_CTL_0, 0x71 }, + { WCD934X_CPE_FLL_USER_CTL_1, 0x34 }, + { WCD934X_CPE_FLL_USER_CTL_2, 0x0b }, + { WCD934X_CPE_FLL_USER_CTL_3, 0x02 }, + { WCD934X_CPE_FLL_USER_CTL_4, 0x04 }, + { WCD934X_CPE_FLL_USER_CTL_5, 0x02 }, + { WCD934X_CPE_FLL_USER_CTL_6, 0x6e }, + { WCD934X_CPE_FLL_USER_CTL_7, 0x00 }, + { WCD934X_CPE_FLL_USER_CTL_8, 0x94 }, + { WCD934X_CPE_FLL_USER_CTL_9, 0x50 }, + { WCD934X_CPE_FLL_L_VAL_CTL_0, 0x53 }, + { WCD934X_CPE_FLL_L_VAL_CTL_1, 0x00 }, + { WCD934X_CPE_FLL_DSM_FRAC_CTL_0, 0x00 }, + { WCD934X_CPE_FLL_DSM_FRAC_CTL_1, 0xff }, + { WCD934X_CPE_FLL_CONFIG_CTL_0, 0x6b }, + { WCD934X_CPE_FLL_CONFIG_CTL_1, 0x05 }, + { WCD934X_CPE_FLL_CONFIG_CTL_2, 0x08 }, + { WCD934X_CPE_FLL_CONFIG_CTL_3, 0x00 }, + { WCD934X_CPE_FLL_CONFIG_CTL_4, 0x10 }, + { WCD934X_CPE_FLL_TEST_CTL_0, 0x80 }, + { WCD934X_CPE_FLL_TEST_CTL_1, 0x00 }, + { WCD934X_CPE_FLL_TEST_CTL_2, 0x00 }, + { WCD934X_CPE_FLL_TEST_CTL_3, 0x00 }, + { WCD934X_CPE_FLL_TEST_CTL_4, 0x00 }, + { WCD934X_CPE_FLL_TEST_CTL_5, 0x00 }, + { WCD934X_CPE_FLL_TEST_CTL_6, 0x00 }, + { WCD934X_CPE_FLL_TEST_CTL_7, 0x33 }, + { WCD934X_CPE_FLL_FREQ_CTL_0, 0x00 }, + { WCD934X_CPE_FLL_FREQ_CTL_1, 0x00 }, + { WCD934X_CPE_FLL_FREQ_CTL_2, 0x00 }, + { WCD934X_CPE_FLL_FREQ_CTL_3, 0x00 }, + { WCD934X_CPE_FLL_SSC_CTL_0, 0x00 }, + { WCD934X_CPE_FLL_SSC_CTL_1, 0x00 }, + { WCD934X_CPE_FLL_SSC_CTL_2, 0x00 }, + { WCD934X_CPE_FLL_SSC_CTL_3, 0x00 }, + { WCD934X_CPE_FLL_FLL_MODE, 0x20 }, + { WCD934X_CPE_FLL_STATUS_0, 0x00 }, + { WCD934X_CPE_FLL_STATUS_1, 0x00 }, + { WCD934X_CPE_FLL_STATUS_2, 0x00 }, + { WCD934X_CPE_FLL_STATUS_3, 0x00 }, + { WCD934X_I2S_FLL_USER_CTL_0, 0x41 }, + { WCD934X_I2S_FLL_USER_CTL_1, 0x94 }, + { WCD934X_I2S_FLL_USER_CTL_2, 0x08 }, + { WCD934X_I2S_FLL_USER_CTL_3, 0x02 }, + { WCD934X_I2S_FLL_USER_CTL_4, 0x04 }, + { WCD934X_I2S_FLL_USER_CTL_5, 0x02 }, + { WCD934X_I2S_FLL_USER_CTL_6, 0x40 }, + { WCD934X_I2S_FLL_USER_CTL_7, 0x00 }, + { WCD934X_I2S_FLL_USER_CTL_8, 0x5f }, + { WCD934X_I2S_FLL_USER_CTL_9, 0x02 }, + { WCD934X_I2S_FLL_L_VAL_CTL_0, 0x40 }, + { WCD934X_I2S_FLL_L_VAL_CTL_1, 0x00 }, + { WCD934X_I2S_FLL_DSM_FRAC_CTL_0, 0x00 }, + { WCD934X_I2S_FLL_DSM_FRAC_CTL_1, 0xff }, + { WCD934X_I2S_FLL_CONFIG_CTL_0, 0x6b }, + { WCD934X_I2S_FLL_CONFIG_CTL_1, 0x05 }, + { WCD934X_I2S_FLL_CONFIG_CTL_2, 0x08 }, + { WCD934X_I2S_FLL_CONFIG_CTL_3, 0x00 }, + { WCD934X_I2S_FLL_CONFIG_CTL_4, 0x30 }, + { WCD934X_I2S_FLL_TEST_CTL_0, 0x80 }, + { WCD934X_I2S_FLL_TEST_CTL_1, 0x00 }, + { WCD934X_I2S_FLL_TEST_CTL_2, 0x00 }, + { WCD934X_I2S_FLL_TEST_CTL_3, 0x00 }, + { WCD934X_I2S_FLL_TEST_CTL_4, 0x00 }, + { WCD934X_I2S_FLL_TEST_CTL_5, 0x00 }, + { WCD934X_I2S_FLL_TEST_CTL_6, 0x00 }, + { WCD934X_I2S_FLL_TEST_CTL_7, 0xff }, + { WCD934X_I2S_FLL_FREQ_CTL_0, 0x00 }, + { WCD934X_I2S_FLL_FREQ_CTL_1, 0x00 }, + { WCD934X_I2S_FLL_FREQ_CTL_2, 0x00 }, + { WCD934X_I2S_FLL_FREQ_CTL_3, 0x00 }, + { WCD934X_I2S_FLL_SSC_CTL_0, 0x00 }, + { WCD934X_I2S_FLL_SSC_CTL_1, 0x00 }, + { WCD934X_I2S_FLL_SSC_CTL_2, 0x00 }, + { WCD934X_I2S_FLL_SSC_CTL_3, 0x00 }, + { WCD934X_I2S_FLL_FLL_MODE, 0x00 }, + { WCD934X_I2S_FLL_STATUS_0, 0x00 }, + { WCD934X_I2S_FLL_STATUS_1, 0x00 }, + { WCD934X_I2S_FLL_STATUS_2, 0x00 }, + { WCD934X_I2S_FLL_STATUS_3, 0x00 }, + { WCD934X_SB_FLL_USER_CTL_0, 0x41 }, + { WCD934X_SB_FLL_USER_CTL_1, 0x94 }, + { WCD934X_SB_FLL_USER_CTL_2, 0x08 }, + { WCD934X_SB_FLL_USER_CTL_3, 0x02 }, + { WCD934X_SB_FLL_USER_CTL_4, 0x04 }, + { WCD934X_SB_FLL_USER_CTL_5, 0x02 }, + { WCD934X_SB_FLL_USER_CTL_6, 0x40 }, + { WCD934X_SB_FLL_USER_CTL_7, 0x00 }, + { WCD934X_SB_FLL_USER_CTL_8, 0x5e }, + { WCD934X_SB_FLL_USER_CTL_9, 0x01 }, + { WCD934X_SB_FLL_L_VAL_CTL_0, 0x40 }, + { WCD934X_SB_FLL_L_VAL_CTL_1, 0x00 }, + { WCD934X_SB_FLL_DSM_FRAC_CTL_0, 0x00 }, + { WCD934X_SB_FLL_DSM_FRAC_CTL_1, 0xff }, + { WCD934X_SB_FLL_CONFIG_CTL_0, 0x6b }, + { WCD934X_SB_FLL_CONFIG_CTL_1, 0x05 }, + { WCD934X_SB_FLL_CONFIG_CTL_2, 0x08 }, + { WCD934X_SB_FLL_CONFIG_CTL_3, 0x00 }, + { WCD934X_SB_FLL_CONFIG_CTL_4, 0x10 }, + { WCD934X_SB_FLL_TEST_CTL_0, 0x00 }, + { WCD934X_SB_FLL_TEST_CTL_1, 0x00 }, + { WCD934X_SB_FLL_TEST_CTL_2, 0x00 }, + { WCD934X_SB_FLL_TEST_CTL_3, 0x00 }, + { WCD934X_SB_FLL_TEST_CTL_4, 0x00 }, + { WCD934X_SB_FLL_TEST_CTL_5, 0x00 }, + { WCD934X_SB_FLL_TEST_CTL_6, 0x00 }, + { WCD934X_SB_FLL_TEST_CTL_7, 0xff }, + { WCD934X_SB_FLL_FREQ_CTL_0, 0x00 }, + { WCD934X_SB_FLL_FREQ_CTL_1, 0x00 }, + { WCD934X_SB_FLL_FREQ_CTL_2, 0x00 }, + { WCD934X_SB_FLL_FREQ_CTL_3, 0x00 }, + { WCD934X_SB_FLL_SSC_CTL_0, 0x00 }, + { WCD934X_SB_FLL_SSC_CTL_1, 0x00 }, + { WCD934X_SB_FLL_SSC_CTL_2, 0x00 }, + { WCD934X_SB_FLL_SSC_CTL_3, 0x00 }, + { WCD934X_SB_FLL_FLL_MODE, 0x00 }, + { WCD934X_SB_FLL_STATUS_0, 0x00 }, + { WCD934X_SB_FLL_STATUS_1, 0x00 }, + { WCD934X_SB_FLL_STATUS_2, 0x00 }, + { WCD934X_SB_FLL_STATUS_3, 0x00 }, + { WCD934X_PAGE2_PAGE_REGISTER, 0x00 }, + { WCD934X_CPE_SS_CPE_CTL, 0x05 }, + { WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_0, 0x01 }, + { WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_1, 0x00 }, + { WCD934X_CPE_SS_PWR_CPEFLL_CTL, 0x02 }, + { WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_0, 0xff }, + { WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_1, 0x0f }, + { WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_OVERRIDE, 0x00 }, + { WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_0, 0xff }, + { WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_1, 0xff }, + { WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_2, 0xff }, + { WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_3, 0xff }, + { WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_4, 0xff }, + { WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_5, 0xff }, + { WCD934X_CPE_SS_PWR_CPE_DRAM1_SHUTDOWN, 0x07 }, + { WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL, 0x00 }, + { WCD934X_CPE_SS_SOC_SW_COLLAPSE_OVERRIDE_CTL, 0x20 }, + { WCD934X_CPE_SS_SOC_SW_COLLAPSE_OVERRIDE_CTL1, 0x00 }, + { WCD934X_CPE_SS_US_BUF_INT_PERIOD, 0x60 }, + { WCD934X_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD, 0x13 }, + { WCD934X_CPE_SS_SVA_CFG, 0x41 }, + { WCD934X_CPE_SS_US_CFG, 0x00 }, + { WCD934X_CPE_SS_MAD_CTL, 0x00 }, + { WCD934X_CPE_SS_CPAR_CTL, 0x00 }, + { WCD934X_CPE_SS_DMIC0_CTL, 0x00 }, + { WCD934X_CPE_SS_DMIC1_CTL, 0x00 }, + { WCD934X_CPE_SS_DMIC2_CTL, 0x00 }, + { WCD934X_CPE_SS_DMIC_CFG, 0x80 }, + { WCD934X_CPE_SS_CPAR_CFG, 0x00 }, + { WCD934X_CPE_SS_WDOG_CFG, 0x01 }, + { WCD934X_CPE_SS_BACKUP_INT, 0x00 }, + { WCD934X_CPE_SS_STATUS, 0x00 }, + { WCD934X_CPE_SS_CPE_OCD_CFG, 0x00 }, + { WCD934X_CPE_SS_SS_ERROR_INT_MASK_0A, 0xff }, + { WCD934X_CPE_SS_SS_ERROR_INT_MASK_0B, 0x3f }, + { WCD934X_CPE_SS_SS_ERROR_INT_MASK_1A, 0xff }, + { WCD934X_CPE_SS_SS_ERROR_INT_MASK_1B, 0x3f }, + { WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0A, 0x00 }, + { WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0B, 0x00 }, + { WCD934X_CPE_SS_SS_ERROR_INT_STATUS_1A, 0x00 }, + { WCD934X_CPE_SS_SS_ERROR_INT_STATUS_1B, 0x00 }, + { WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_0A, 0x00 }, + { WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_0B, 0x00 }, + { WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_1A, 0x00 }, + { WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_1B, 0x00 }, + { WCD934X_SOC_MAD_MAIN_CTL_1, 0x00 }, + { WCD934X_SOC_MAD_MAIN_CTL_2, 0x00 }, + { WCD934X_SOC_MAD_AUDIO_CTL_1, 0x00 }, + { WCD934X_SOC_MAD_AUDIO_CTL_2, 0x00 }, + { WCD934X_SOC_MAD_AUDIO_CTL_3, 0x00 }, + { WCD934X_SOC_MAD_AUDIO_CTL_4, 0x00 }, + { WCD934X_SOC_MAD_AUDIO_CTL_5, 0x00 }, + { WCD934X_SOC_MAD_AUDIO_CTL_6, 0x00 }, + { WCD934X_SOC_MAD_AUDIO_CTL_7, 0x00 }, + { WCD934X_SOC_MAD_AUDIO_CTL_8, 0x00 }, + { WCD934X_SOC_MAD_AUDIO_IIR_CTL_PTR, 0x00 }, + { WCD934X_SOC_MAD_AUDIO_IIR_CTL_VAL, 0x40 }, + { WCD934X_SOC_MAD_ULTR_CTL_1, 0x00 }, + { WCD934X_SOC_MAD_ULTR_CTL_2, 0x00 }, + { WCD934X_SOC_MAD_ULTR_CTL_3, 0x00 }, + { WCD934X_SOC_MAD_ULTR_CTL_4, 0x00 }, + { WCD934X_SOC_MAD_ULTR_CTL_5, 0x00 }, + { WCD934X_SOC_MAD_ULTR_CTL_6, 0x00 }, + { WCD934X_SOC_MAD_ULTR_CTL_7, 0x00 }, + { WCD934X_SOC_MAD_BEACON_CTL_1, 0x00 }, + { WCD934X_SOC_MAD_BEACON_CTL_2, 0x00 }, + { WCD934X_SOC_MAD_BEACON_CTL_3, 0x00 }, + { WCD934X_SOC_MAD_BEACON_CTL_4, 0x00 }, + { WCD934X_SOC_MAD_BEACON_CTL_5, 0x00 }, + { WCD934X_SOC_MAD_BEACON_CTL_6, 0x00 }, + { WCD934X_SOC_MAD_BEACON_CTL_7, 0x00 }, + { WCD934X_SOC_MAD_BEACON_CTL_8, 0x00 }, + { WCD934X_SOC_MAD_BEACON_IIR_CTL_PTR, 0x00 }, + { WCD934X_SOC_MAD_BEACON_IIR_CTL_VAL, 0x00 }, + { WCD934X_SOC_MAD_INP_SEL, 0x00 }, + { WCD934X_PAGE4_PAGE_REGISTER, 0x00 }, + { WCD934X_INTR_CFG, 0x00 }, + { WCD934X_INTR_CLR_COMMIT, 0x00 }, + { WCD934X_INTR_PIN1_MASK0, 0xff }, + { WCD934X_INTR_PIN1_MASK1, 0xff }, + { WCD934X_INTR_PIN1_MASK2, 0xff }, + { WCD934X_INTR_PIN1_MASK3, 0xff }, + { WCD934X_INTR_PIN1_STATUS0, 0x00 }, + { WCD934X_INTR_PIN1_STATUS1, 0x00 }, + { WCD934X_INTR_PIN1_STATUS2, 0x00 }, + { WCD934X_INTR_PIN1_STATUS3, 0x00 }, + { WCD934X_INTR_PIN1_CLEAR0, 0x00 }, + { WCD934X_INTR_PIN1_CLEAR1, 0x00 }, + { WCD934X_INTR_PIN1_CLEAR2, 0x00 }, + { WCD934X_INTR_PIN1_CLEAR3, 0x00 }, + { WCD934X_INTR_PIN2_MASK3, 0xff }, + { WCD934X_INTR_PIN2_STATUS3, 0x00 }, + { WCD934X_INTR_PIN2_CLEAR3, 0x00 }, + { WCD934X_INTR_CPESS_SUMRY_MASK2, 0xff }, + { WCD934X_INTR_CPESS_SUMRY_MASK3, 0xff }, + { WCD934X_INTR_CPESS_SUMRY_STATUS2, 0x00 }, + { WCD934X_INTR_CPESS_SUMRY_STATUS3, 0x00 }, + { WCD934X_INTR_CPESS_SUMRY_CLEAR2, 0x00 }, + { WCD934X_INTR_CPESS_SUMRY_CLEAR3, 0x00 }, + { WCD934X_INTR_LEVEL0, 0x03 }, + { WCD934X_INTR_LEVEL1, 0xe0 }, + { WCD934X_INTR_LEVEL2, 0x94 }, + { WCD934X_INTR_LEVEL3, 0x80 }, + { WCD934X_INTR_BYPASS0, 0x00 }, + { WCD934X_INTR_BYPASS1, 0x00 }, + { WCD934X_INTR_BYPASS2, 0x00 }, + { WCD934X_INTR_BYPASS3, 0x00 }, + { WCD934X_INTR_SET0, 0x00 }, + { WCD934X_INTR_SET1, 0x00 }, + { WCD934X_INTR_SET2, 0x00 }, + { WCD934X_INTR_SET3, 0x00 }, + { WCD934X_INTR_CODEC_MISC_MASK, 0x7f }, + { WCD934X_INTR_CODEC_MISC_STATUS, 0x00 }, + { WCD934X_INTR_CODEC_MISC_CLEAR, 0x00 }, + { WCD934X_PAGE5_PAGE_REGISTER, 0x00 }, + { WCD934X_SLNQ_DIG_DEVICE, 0x49 }, + { WCD934X_SLNQ_DIG_REVISION, 0x01 }, + { WCD934X_SLNQ_DIG_H_COMMAND, 0x00 }, + { WCD934X_SLNQ_DIG_NUMBER_OF_BYTE_MSB, 0x00 }, + { WCD934X_SLNQ_DIG_NUMBER_OF_BYTE_LSB, 0x00 }, + { WCD934X_SLNQ_DIG_MASTER_ADDRESS_MSB, 0x00 }, + { WCD934X_SLNQ_DIG_MASTER_ADDRESS_LSB, 0x00 }, + { WCD934X_SLNQ_DIG_SLAVE_ADDRESS_MSB, 0x00 }, + { WCD934X_SLNQ_DIG_SLAVE_ADDRESS_LSB, 0x00 }, + { WCD934X_SLNQ_DIG_TIMER0_INTERRUPT_MSB, 0x40 }, + { WCD934X_SLNQ_DIG_TIMER0_INTERRUPT_LSB, 0x00 }, + { WCD934X_SLNQ_DIG_TIMER1_INTERRUPT_MSB, 0x40 }, + { WCD934X_SLNQ_DIG_TIMER1_INTERRUPT_LSB, 0x00 }, + { WCD934X_SLNQ_DIG_TIMER2_INTERRUPT_MSB, 0x40 }, + { WCD934X_SLNQ_DIG_TIMER2_INTERRUPT_LSB, 0x00 }, + { WCD934X_SLNQ_DIG_COMM_CTL, 0x00 }, + { WCD934X_SLNQ_DIG_FRAME_CTRL, 0x01 }, + { WCD934X_SLNQ_DIG_PDM_2ND_DATA_CH1_2, 0x77 }, + { WCD934X_SLNQ_DIG_PDM_2ND_DATA_CH3_4, 0x77 }, + { WCD934X_SLNQ_DIG_PDM_2ND_DATA_CH5, 0x70 }, + { WCD934X_SLNQ_DIG_SW_EVENT_RD, 0x00 }, + { WCD934X_SLNQ_DIG_SW_EVENT_CTRL, 0x00 }, + { WCD934X_SLNQ_DIG_PDM_SELECT_1, 0x12 }, + { WCD934X_SLNQ_DIG_PDM_SELECT_2, 0x34 }, + { WCD934X_SLNQ_DIG_PDM_SELECT_3, 0x55 }, + { WCD934X_SLNQ_DIG_PDM_SAMPLING_FREQ, 0x01 }, + { WCD934X_SLNQ_DIG_PDM_DC_CONVERSION_CTL, 0x00 }, + { WCD934X_SLNQ_DIG_PDM_DC_CONVERSION_SEL, 0x11 }, + { WCD934X_SLNQ_DIG_PDM_DC_CONV_CHA_MSB, 0x00 }, + { WCD934X_SLNQ_DIG_PDM_DC_CONV_CHA_LSB, 0x00 }, + { WCD934X_SLNQ_DIG_PDM_DC_CONV_CHB_MSB, 0x00 }, + { WCD934X_SLNQ_DIG_PDM_DC_CONV_CHB_LSB, 0x00 }, + { WCD934X_SLNQ_DIG_RAM_CNTRL, 0x01 }, + { WCD934X_SLNQ_DIG_SRAM_BANK, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_0, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_1, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_2, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_3, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_4, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_5, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_6, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_7, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_8, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_9, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_A, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_B, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_C, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_D, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_E, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_F, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_10, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_11, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_12, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_13, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_14, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_15, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_16, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_17, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_18, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_19, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_1A, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_1B, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_1C, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_1D, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_1E, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_1F, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_20, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_21, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_22, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_23, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_24, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_25, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_26, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_27, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_28, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_29, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_2A, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_2B, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_2C, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_2D, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_2E, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_2F, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_30, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_31, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_32, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_33, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_34, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_35, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_36, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_37, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_38, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_39, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_3A, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_3B, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_3C, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_3D, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_3E, 0x00 }, + { WCD934X_SLNQ_DIG_SRAM_BYTE_3F, 0x00 }, + { WCD934X_SLNQ_DIG_TOP_CTRL1, 0x00 }, + { WCD934X_SLNQ_DIG_TOP_CTRL2, 0x00 }, + { WCD934X_SLNQ_DIG_PDM_CTRL, 0x00 }, + { WCD934X_SLNQ_DIG_PDM_MUTE_CTRL, 0x20 }, + { WCD934X_SLNQ_DIG_DEC_BYPASS_CTRL, 0x00 }, + { WCD934X_SLNQ_DIG_DEC_BYPASS_STATUS, 0x00 }, + { WCD934X_SLNQ_DIG_DEC_BYPASS_FS, 0x00 }, + { WCD934X_SLNQ_DIG_DEC_BYPASS_IN_SEL, 0x00 }, + { WCD934X_SLNQ_DIG_GPOUT_ENABLE, 0x00 }, + { WCD934X_SLNQ_DIG_GPOUT_VAL, 0x00 }, + { WCD934X_SLNQ_DIG_ANA_INTERRUPT_MASK, 0x00 }, + { WCD934X_SLNQ_DIG_ANA_INTERRUPT_STATUS, 0x00 }, + { WCD934X_SLNQ_DIG_ANA_INTERRUPT_CLR, 0x00 }, + { WCD934X_SLNQ_DIG_IP_TESTING, 0x00 }, + { WCD934X_SLNQ_DIG_INTERRUPT_CNTRL, 0x0f }, + { WCD934X_SLNQ_DIG_INTERRUPT_CNT, 0x00 }, + { WCD934X_SLNQ_DIG_INTERRUPT_CNT_MSB, 0xff }, + { WCD934X_SLNQ_DIG_INTERRUPT_CNT_LSB, 0xff }, + { WCD934X_SLNQ_DIG_INTERRUPT_MASK0, 0xff }, + { WCD934X_SLNQ_DIG_INTERRUPT_MASK1, 0xff }, + { WCD934X_SLNQ_DIG_INTERRUPT_MASK2, 0xff }, + { WCD934X_SLNQ_DIG_INTERRUPT_MASK3, 0xff }, + { WCD934X_SLNQ_DIG_INTERRUPT_MASK4, 0x1f }, + { WCD934X_SLNQ_DIG_INTERRUPT_STATUS0, 0x00 }, + { WCD934X_SLNQ_DIG_INTERRUPT_STATUS1, 0x00 }, + { WCD934X_SLNQ_DIG_INTERRUPT_STATUS2, 0x00 }, + { WCD934X_SLNQ_DIG_INTERRUPT_STATUS3, 0x00 }, + { WCD934X_SLNQ_DIG_INTERRUPT_STATUS4, 0x00 }, + { WCD934X_SLNQ_DIG_INTERRUPT_CLR0, 0x00 }, + { WCD934X_SLNQ_DIG_INTERRUPT_CLR1, 0x00 }, + { WCD934X_SLNQ_DIG_INTERRUPT_CLR2, 0x00 }, + { WCD934X_SLNQ_DIG_INTERRUPT_CLR3, 0x00 }, + { WCD934X_SLNQ_DIG_INTERRUPT_CLR4, 0x00 }, + { WCD934X_ANA_PAGE_REGISTER, 0x00 }, + { WCD934X_ANA_BIAS, 0x00 }, + { WCD934X_ANA_RCO, 0x00 }, + { WCD934X_ANA_PAGE6_SPARE2, 0x00 }, + { WCD934X_ANA_PAGE6_SPARE3, 0x00 }, + { WCD934X_ANA_BUCK_CTL, 0x00 }, + { WCD934X_ANA_BUCK_STATUS, 0x00 }, + { WCD934X_ANA_RX_SUPPLIES, 0x00 }, + { WCD934X_ANA_HPH, 0x0c }, + { WCD934X_ANA_EAR, 0x00 }, + { WCD934X_ANA_LO_1_2, 0x3c }, + { WCD934X_ANA_MAD_SETUP, 0x01 }, + { WCD934X_ANA_AMIC1, 0x20 }, + { WCD934X_ANA_AMIC2, 0x00 }, + { WCD934X_ANA_AMIC3, 0x20 }, + { WCD934X_ANA_AMIC4, 0x00 }, + { WCD934X_ANA_MBHC_MECH, 0x39 }, + { WCD934X_ANA_MBHC_ELECT, 0x08 }, + { WCD934X_ANA_MBHC_ZDET, 0x00 }, + { WCD934X_ANA_MBHC_RESULT_1, 0x00 }, + { WCD934X_ANA_MBHC_RESULT_2, 0x00 }, + { WCD934X_ANA_MBHC_RESULT_3, 0x00 }, + { WCD934X_ANA_MBHC_BTN0, 0x00 }, + { WCD934X_ANA_MBHC_BTN1, 0x10 }, + { WCD934X_ANA_MBHC_BTN2, 0x20 }, + { WCD934X_ANA_MBHC_BTN3, 0x30 }, + { WCD934X_ANA_MBHC_BTN4, 0x40 }, + { WCD934X_ANA_MBHC_BTN5, 0x50 }, + { WCD934X_ANA_MBHC_BTN6, 0x60 }, + { WCD934X_ANA_MBHC_BTN7, 0x70 }, + { WCD934X_ANA_MICB1, 0x10 }, + { WCD934X_ANA_MICB2, 0x10 }, + { WCD934X_ANA_MICB2_RAMP, 0x00 }, + { WCD934X_ANA_MICB3, 0x10 }, + { WCD934X_ANA_MICB4, 0x10 }, + { WCD934X_ANA_VBADC, 0x00 }, + { WCD934X_BIAS_CTL, 0x28 }, + { WCD934X_BIAS_VBG_FINE_ADJ, 0x65 }, + { WCD934X_RCO_CTRL_1, 0x44 }, + { WCD934X_RCO_CTRL_2, 0x48 }, + { WCD934X_RCO_CAL, 0x00 }, + { WCD934X_RCO_CAL_1, 0x00 }, + { WCD934X_RCO_CAL_2, 0x00 }, + { WCD934X_RCO_TEST_CTRL, 0x00 }, + { WCD934X_RCO_CAL_OUT_1, 0x00 }, + { WCD934X_RCO_CAL_OUT_2, 0x00 }, + { WCD934X_RCO_CAL_OUT_3, 0x00 }, + { WCD934X_RCO_CAL_OUT_4, 0x00 }, + { WCD934X_RCO_CAL_OUT_5, 0x00 }, + { WCD934X_SIDO_MODE_1, 0x84 }, + { WCD934X_SIDO_MODE_2, 0xfe }, + { WCD934X_SIDO_MODE_3, 0xf6 }, + { WCD934X_SIDO_MODE_4, 0x56 }, + { WCD934X_SIDO_VCL_1, 0x00 }, + { WCD934X_SIDO_VCL_2, 0x6c }, + { WCD934X_SIDO_VCL_3, 0x44 }, + { WCD934X_SIDO_CCL_1, 0x57 }, + { WCD934X_SIDO_CCL_2, 0x92 }, + { WCD934X_SIDO_CCL_3, 0x35 }, + { WCD934X_SIDO_CCL_4, 0x61 }, + { WCD934X_SIDO_CCL_5, 0x6d }, + { WCD934X_SIDO_CCL_6, 0x60 }, + { WCD934X_SIDO_CCL_7, 0x6f }, + { WCD934X_SIDO_CCL_8, 0x6f }, + { WCD934X_SIDO_CCL_9, 0x6e }, + { WCD934X_SIDO_CCL_10, 0x26 }, + { WCD934X_SIDO_FILTER_1, 0x92 }, + { WCD934X_SIDO_FILTER_2, 0x54 }, + { WCD934X_SIDO_DRIVER_1, 0x77 }, + { WCD934X_SIDO_DRIVER_2, 0x55 }, + { WCD934X_SIDO_DRIVER_3, 0x55 }, + { WCD934X_SIDO_CAL_CODE_EXT_1, 0x9c }, + { WCD934X_SIDO_CAL_CODE_EXT_2, 0x82 }, + { WCD934X_SIDO_CAL_CODE_OUT_1, 0x00 }, + { WCD934X_SIDO_CAL_CODE_OUT_2, 0x00 }, + { WCD934X_SIDO_TEST_1, 0x00 }, + { WCD934X_SIDO_TEST_2, 0x00 }, + { WCD934X_MBHC_CTL_CLK, 0x30 }, + { WCD934X_MBHC_CTL_ANA, 0x00 }, + { WCD934X_MBHC_CTL_SPARE_1, 0x00 }, + { WCD934X_MBHC_CTL_SPARE_2, 0x00 }, + { WCD934X_MBHC_CTL_BCS, 0x00 }, + { WCD934X_MBHC_STATUS_SPARE_1, 0x00 }, + { WCD934X_MBHC_TEST_CTL, 0x00 }, + { WCD934X_VBADC_SUBBLOCK_EN, 0xde }, + { WCD934X_VBADC_IBIAS_FE, 0x58 }, + { WCD934X_VBADC_BIAS_ADC, 0x51 }, + { WCD934X_VBADC_FE_CTRL, 0x1c }, + { WCD934X_VBADC_ADC_REF, 0x20 }, + { WCD934X_VBADC_ADC_IO, 0x80 }, + { WCD934X_VBADC_ADC_SAR, 0xff }, + { WCD934X_VBADC_DEBUG, 0x00 }, + { WCD934X_LDOH_MODE, 0x2b }, + { WCD934X_LDOH_BIAS, 0x68 }, + { WCD934X_LDOH_STB_LOADS, 0x00 }, + { WCD934X_LDOH_SLOWRAMP, 0x50 }, + { WCD934X_MICB1_TEST_CTL_1, 0x1a }, + { WCD934X_MICB1_TEST_CTL_2, 0x18 }, + { WCD934X_MICB1_TEST_CTL_3, 0xa4 }, + { WCD934X_MICB2_TEST_CTL_1, 0x1a }, + { WCD934X_MICB2_TEST_CTL_2, 0x18 }, + { WCD934X_MICB2_TEST_CTL_3, 0xa4 }, + { WCD934X_MICB3_TEST_CTL_1, 0x1a }, + { WCD934X_MICB3_TEST_CTL_2, 0x18 }, + { WCD934X_MICB3_TEST_CTL_3, 0xa4 }, + { WCD934X_MICB4_TEST_CTL_1, 0x1a }, + { WCD934X_MICB4_TEST_CTL_2, 0x18 }, + { WCD934X_MICB4_TEST_CTL_3, 0xa4 }, + { WCD934X_TX_COM_ADC_VCM, 0x39 }, + { WCD934X_TX_COM_BIAS_ATEST, 0xc0 }, + { WCD934X_TX_COM_ADC_INT1_IB, 0x6f }, + { WCD934X_TX_COM_ADC_INT2_IB, 0x4f }, + { WCD934X_TX_COM_TXFE_DIV_CTL, 0x2e }, + { WCD934X_TX_COM_TXFE_DIV_START, 0x00 }, + { WCD934X_TX_COM_TXFE_DIV_STOP_9P6M, 0xc7 }, + { WCD934X_TX_COM_TXFE_DIV_STOP_12P288M, 0xff }, + { WCD934X_TX_1_2_TEST_EN, 0xcc }, + { WCD934X_TX_1_2_ADC_IB, 0x09 }, + { WCD934X_TX_1_2_ATEST_REFCTL, 0x0a }, + { WCD934X_TX_1_2_TEST_CTL, 0x38 }, + { WCD934X_TX_1_2_TEST_BLK_EN, 0xff }, + { WCD934X_TX_1_2_TXFE_CLKDIV, 0x00 }, + { WCD934X_TX_1_2_SAR1_ERR, 0x00 }, + { WCD934X_TX_1_2_SAR2_ERR, 0x00 }, + { WCD934X_TX_3_4_TEST_EN, 0xcc }, + { WCD934X_TX_3_4_ADC_IB, 0x09 }, + { WCD934X_TX_3_4_ATEST_REFCTL, 0x0a }, + { WCD934X_TX_3_4_TEST_CTL, 0x38 }, + { WCD934X_TX_3_4_TEST_BLK_EN, 0xff }, + { WCD934X_TX_3_4_TXFE_CLKDIV, 0x00 }, + { WCD934X_TX_3_4_SAR1_ERR, 0x00 }, + { WCD934X_TX_3_4_SAR2_ERR, 0x00 }, + { WCD934X_CLASSH_MODE_1, 0x40 }, + { WCD934X_CLASSH_MODE_2, 0x3a }, + { WCD934X_CLASSH_MODE_3, 0x00 }, + { WCD934X_CLASSH_CTRL_VCL_1, 0x70 }, + { WCD934X_CLASSH_CTRL_VCL_2, 0x82 }, + { WCD934X_CLASSH_CTRL_CCL_1, 0x31 }, + { WCD934X_CLASSH_CTRL_CCL_2, 0x80 }, + { WCD934X_CLASSH_CTRL_CCL_3, 0x80 }, + { WCD934X_CLASSH_CTRL_CCL_4, 0x51 }, + { WCD934X_CLASSH_CTRL_CCL_5, 0x00 }, + { WCD934X_CLASSH_BUCK_TMUX_A_D, 0x00 }, + { WCD934X_CLASSH_BUCK_SW_DRV_CNTL, 0x77 }, + { WCD934X_CLASSH_SPARE, 0x00 }, + { WCD934X_FLYBACK_EN, 0x4e }, + { WCD934X_FLYBACK_VNEG_CTRL_1, 0x0b }, + { WCD934X_FLYBACK_VNEG_CTRL_2, 0x45 }, + { WCD934X_FLYBACK_VNEG_CTRL_3, 0x74 }, + { WCD934X_FLYBACK_VNEG_CTRL_4, 0x7f }, + { WCD934X_FLYBACK_VNEG_CTRL_5, 0x83 }, + { WCD934X_FLYBACK_VNEG_CTRL_6, 0x98 }, + { WCD934X_FLYBACK_VNEG_CTRL_7, 0xa9 }, + { WCD934X_FLYBACK_VNEG_CTRL_8, 0x68 }, + { WCD934X_FLYBACK_VNEG_CTRL_9, 0x64 }, + { WCD934X_FLYBACK_VNEGDAC_CTRL_1, 0xed }, + { WCD934X_FLYBACK_VNEGDAC_CTRL_2, 0xf0 }, + { WCD934X_FLYBACK_VNEGDAC_CTRL_3, 0xa6 }, + { WCD934X_FLYBACK_CTRL_1, 0x65 }, + { WCD934X_FLYBACK_TEST_CTL, 0x00 }, + { WCD934X_RX_AUX_SW_CTL, 0x00 }, + { WCD934X_RX_PA_AUX_IN_CONN, 0x00 }, + { WCD934X_RX_TIMER_DIV, 0x32 }, + { WCD934X_RX_OCP_CTL, 0x1f }, + { WCD934X_RX_OCP_COUNT, 0x77 }, + { WCD934X_RX_BIAS_EAR_DAC, 0xa0 }, + { WCD934X_RX_BIAS_EAR_AMP, 0xaa }, + { WCD934X_RX_BIAS_HPH_LDO, 0xa9 }, + { WCD934X_RX_BIAS_HPH_PA, 0xaa }, + { WCD934X_RX_BIAS_HPH_RDACBUFF_CNP2, 0x8a }, + { WCD934X_RX_BIAS_HPH_RDAC_LDO, 0x88 }, + { WCD934X_RX_BIAS_HPH_CNP1, 0x82 }, + { WCD934X_RX_BIAS_HPH_LOWPOWER, 0x82 }, + { WCD934X_RX_BIAS_DIFFLO_PA, 0x80 }, + { WCD934X_RX_BIAS_DIFFLO_REF, 0x88 }, + { WCD934X_RX_BIAS_DIFFLO_LDO, 0x88 }, + { WCD934X_RX_BIAS_SELO_DAC_PA, 0xa8 }, + { WCD934X_RX_BIAS_BUCK_RST, 0x08 }, + { WCD934X_RX_BIAS_BUCK_VREF_ERRAMP, 0x44 }, + { WCD934X_RX_BIAS_FLYB_ERRAMP, 0x40 }, + { WCD934X_RX_BIAS_FLYB_BUFF, 0xaa }, + { WCD934X_RX_BIAS_FLYB_MID_RST, 0x14 }, + { WCD934X_HPH_L_STATUS, 0x04 }, + { WCD934X_HPH_R_STATUS, 0x04 }, + { WCD934X_HPH_CNP_EN, 0x80 }, + { WCD934X_HPH_CNP_WG_CTL, 0x9a }, + { WCD934X_HPH_CNP_WG_TIME, 0x14 }, + { WCD934X_HPH_OCP_CTL, 0x28 }, + { WCD934X_HPH_AUTO_CHOP, 0x16 }, + { WCD934X_HPH_CHOP_CTL, 0x83 }, + { WCD934X_HPH_PA_CTL1, 0x46 }, + { WCD934X_HPH_PA_CTL2, 0x50 }, + { WCD934X_HPH_L_EN, 0x80 }, + { WCD934X_HPH_L_TEST, 0xe0 }, + { WCD934X_HPH_L_ATEST, 0x50 }, + { WCD934X_HPH_R_EN, 0x80 }, + { WCD934X_HPH_R_TEST, 0xe0 }, + { WCD934X_HPH_R_ATEST, 0x54 }, + { WCD934X_HPH_RDAC_CLK_CTL1, 0x99 }, + { WCD934X_HPH_RDAC_CLK_CTL2, 0x9b }, + { WCD934X_HPH_RDAC_LDO_CTL, 0x33 }, + { WCD934X_HPH_RDAC_CHOP_CLK_LP_CTL, 0x00 }, + { WCD934X_HPH_REFBUFF_UHQA_CTL, 0xa8 }, + { WCD934X_HPH_REFBUFF_LP_CTL, 0x0a }, + { WCD934X_HPH_L_DAC_CTL, 0x00 }, + { WCD934X_HPH_R_DAC_CTL, 0x00 }, + { WCD934X_EAR_EN_REG, 0x60 }, + { WCD934X_EAR_CMBUFF, 0x05 }, + { WCD934X_EAR_ICTL, 0x40 }, + { WCD934X_EAR_EN_DBG_CTL, 0x00 }, + { WCD934X_EAR_CNP, 0xe0 }, + { WCD934X_EAR_DAC_CTL_ATEST, 0x00 }, + { WCD934X_EAR_STATUS_REG, 0x04 }, + { WCD934X_EAR_EAR_MISC, 0x28 }, + { WCD934X_DIFF_LO_MISC, 0x03 }, + { WCD934X_DIFF_LO_LO2_COMPANDER, 0x00 }, + { WCD934X_DIFF_LO_LO1_COMPANDER, 0x00 }, + { WCD934X_DIFF_LO_COMMON, 0x40 }, + { WCD934X_DIFF_LO_BYPASS_EN, 0x00 }, + { WCD934X_DIFF_LO_CNP, 0x20 }, + { WCD934X_DIFF_LO_CORE_OUT_PROG, 0xa0 }, + { WCD934X_DIFF_LO_LDO_OUT_PROG, 0x00 }, + { WCD934X_DIFF_LO_COM_SWCAP_REFBUF_FREQ, 0x8b }, + { WCD934X_DIFF_LO_COM_PA_FREQ, 0xb0 }, + { WCD934X_DIFF_LO_RESERVED_REG, 0x60 }, + { WCD934X_DIFF_LO_LO1_STATUS_1, 0x00 }, + { WCD934X_DIFF_LO_LO1_STATUS_2, 0x00 }, + { WCD934X_ANA_NEW_PAGE_REGISTER, 0x00 }, + { WCD934X_HPH_NEW_ANA_HPH2, 0x00 }, + { WCD934X_HPH_NEW_ANA_HPH3, 0x00 }, + { WCD934X_SLNQ_ANA_EN, 0x02 }, + { WCD934X_SLNQ_ANA_STATUS, 0x00 }, + { WCD934X_SLNQ_ANA_LDO_CONFIG, 0xea }, + { WCD934X_SLNQ_ANA_LDO_OCP_CONFIG, 0x95 }, + { WCD934X_SLNQ_ANA_TX_LDO_CONFIG, 0xb6 }, + { WCD934X_SLNQ_ANA_TX_DRV_CONFIG, 0x26 }, + { WCD934X_SLNQ_ANA_RX_CONFIG_1, 0x64 }, + { WCD934X_SLNQ_ANA_RX_CONFIG_2, 0x40 }, + { WCD934X_SLNQ_ANA_PLL_ENABLES, 0x00 }, + { WCD934X_SLNQ_ANA_PLL_PRESET, 0x08 }, + { WCD934X_SLNQ_ANA_PLL_STATUS, 0x00 }, + { WCD934X_CLK_SYS_PLL_ENABLES, 0x00 }, + { WCD934X_CLK_SYS_PLL_PRESET, 0x00 }, + { WCD934X_CLK_SYS_PLL_STATUS, 0x00 }, + { WCD934X_CLK_SYS_MCLK_PRG, 0x00 }, + { WCD934X_CLK_SYS_MCLK2_PRG1, 0x00 }, + { WCD934X_CLK_SYS_MCLK2_PRG2, 0x00 }, + { WCD934X_CLK_SYS_XO_PRG, 0x00 }, + { WCD934X_CLK_SYS_XO_CAP_XTP, 0x00 }, + { WCD934X_CLK_SYS_XO_CAP_XTM, 0x00 }, + { WCD934X_BOOST_BST_EN_DLY, 0x40 }, + { WCD934X_BOOST_CTRL_ILIM, 0x9c }, + { WCD934X_BOOST_VOUT_SETTING, 0xca }, + { WCD934X_SIDO_NEW_VOUT_A_STARTUP, 0x05 }, + { WCD934X_SIDO_NEW_VOUT_D_STARTUP, 0x0d }, + { WCD934X_SIDO_NEW_VOUT_D_FREQ1, 0x07 }, + { WCD934X_SIDO_NEW_VOUT_D_FREQ2, 0x00 }, + { WCD934X_MBHC_NEW_ELECT_REM_CLAMP_CTL, 0x00 }, + { WCD934X_MBHC_NEW_CTL_1, 0x02 }, + { WCD934X_MBHC_NEW_CTL_2, 0x05 }, + { WCD934X_MBHC_NEW_PLUG_DETECT_CTL, 0xe9 }, + { WCD934X_MBHC_NEW_ZDET_ANA_CTL, 0x0f }, + { WCD934X_MBHC_NEW_ZDET_RAMP_CTL, 0x00 }, + { WCD934X_MBHC_NEW_FSM_STATUS, 0x00 }, + { WCD934X_MBHC_NEW_ADC_RESULT, 0x00 }, + { WCD934X_TX_NEW_AMIC_4_5_SEL, 0x00 }, + { WCD934X_VBADC_NEW_ADC_MODE, 0x10 }, + { WCD934X_VBADC_NEW_ADC_DOUTMSB, 0x00 }, + { WCD934X_VBADC_NEW_ADC_DOUTLSB, 0x00 }, + { WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, 0x00 }, + { WCD934X_HPH_NEW_INT_RDAC_HD2_CTL, 0xa0 }, + { WCD934X_HPH_NEW_INT_RDAC_VREF_CTL, 0x10 }, + { WCD934X_HPH_NEW_INT_RDAC_OVERRIDE_CTL, 0x00 }, + { WCD934X_HPH_NEW_INT_RDAC_MISC1, 0x00 }, + { WCD934X_HPH_NEW_INT_PA_MISC1, 0x22 }, + { WCD934X_HPH_NEW_INT_PA_MISC2, 0x00 }, + { WCD934X_HPH_NEW_INT_PA_RDAC_MISC, 0x00 }, + { WCD934X_HPH_NEW_INT_HPH_TIMER1, 0xfe }, + { WCD934X_HPH_NEW_INT_HPH_TIMER2, 0x02 }, + { WCD934X_HPH_NEW_INT_HPH_TIMER3, 0x4e }, + { WCD934X_HPH_NEW_INT_HPH_TIMER4, 0x54 }, + { WCD934X_HPH_NEW_INT_PA_RDAC_MISC2, 0x00 }, + { WCD934X_HPH_NEW_INT_PA_RDAC_MISC3, 0x00 }, + { WCD934X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI, 0x62 }, + { WCD934X_RX_NEW_INT_HPH_RDAC_BIAS_ULP, 0x01 }, + { WCD934X_RX_NEW_INT_HPH_RDAC_LDO_LP, 0x11 }, + { WCD934X_SLNQ_INT_ANA_INT_LDO_TEST, 0x0d }, + { WCD934X_SLNQ_INT_ANA_INT_LDO_DEBUG_1, 0x85 }, + { WCD934X_SLNQ_INT_ANA_INT_LDO_DEBUG_2, 0xb4 }, + { WCD934X_SLNQ_INT_ANA_INT_TX_LDO_TEST, 0x16 }, + { WCD934X_SLNQ_INT_ANA_INT_TX_DRV_TEST, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_RX_TEST, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_RX_TEST_STATUS, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_RX_DEBUG_1, 0x50 }, + { WCD934X_SLNQ_INT_ANA_INT_RX_DEBUG_2, 0x04 }, + { WCD934X_SLNQ_INT_ANA_INT_CLK_CTRL, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_RESERVED_1, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_RESERVED_2, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_POST_DIV_REG0, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_POST_DIV_REG1, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_REF_DIV_REG0, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_REF_DIV_REG1, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_FILTER_REG0, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_FILTER_REG1, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_L_VAL, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_M_VAL, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_N_VAL, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_TEST_REG0, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_PFD_CP_DSM_PROG, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_VCO_PROG, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_TEST_REG1, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_LDO_LOCK_CFG, 0x00 }, + { WCD934X_SLNQ_INT_ANA_INT_PLL_DIG_LOCK_DET_CFG, 0x00 }, + { WCD934X_CLK_SYS_INT_POST_DIV_REG0, 0x00 }, + { WCD934X_CLK_SYS_INT_POST_DIV_REG1, 0x00 }, + { WCD934X_CLK_SYS_INT_REF_DIV_REG0, 0x00 }, + { WCD934X_CLK_SYS_INT_REF_DIV_REG1, 0x00 }, + { WCD934X_CLK_SYS_INT_FILTER_REG0, 0x00 }, + { WCD934X_CLK_SYS_INT_FILTER_REG1, 0x00 }, + { WCD934X_CLK_SYS_INT_PLL_L_VAL, 0x00 }, + { WCD934X_CLK_SYS_INT_PLL_M_VAL, 0x00 }, + { WCD934X_CLK_SYS_INT_PLL_N_VAL, 0x00 }, + { WCD934X_CLK_SYS_INT_TEST_REG0, 0x00 }, + { WCD934X_CLK_SYS_INT_PFD_CP_DSM_PROG, 0x00 }, + { WCD934X_CLK_SYS_INT_VCO_PROG, 0x00 }, + { WCD934X_CLK_SYS_INT_TEST_REG1, 0x00 }, + { WCD934X_CLK_SYS_INT_LDO_LOCK_CFG, 0x00 }, + { WCD934X_CLK_SYS_INT_DIG_LOCK_DET_CFG, 0x00 }, + { WCD934X_CLK_SYS_INT_CLK_TEST1, 0x00 }, + { WCD934X_CLK_SYS_INT_CLK_TEST2, 0x00 }, + { WCD934X_CLK_SYS_INT_CLK_TEST3, 0x00 }, + { WCD934X_CLK_SYS_INT_XO_TEST1, 0x98 }, + { WCD934X_CLK_SYS_INT_XO_TEST2, 0x00 }, + { WCD934X_BOOST_INT_VCOMP_HYST, 0x02 }, + { WCD934X_BOOST_INT_VLOOP_FILTER, 0xef }, + { WCD934X_BOOST_INT_CTRL_IDELTA, 0xa8 }, + { WCD934X_BOOST_INT_CTRL_ILIM_STARTUP, 0x17 }, + { WCD934X_BOOST_INT_CTRL_MIN_ONTIME, 0x5f }, + { WCD934X_BOOST_INT_CTRL_MAX_ONTIME, 0x88 }, + { WCD934X_BOOST_INT_CTRL_TIMING, 0x0a }, + { WCD934X_BOOST_INT_TMUX_A_D, 0x00 }, + { WCD934X_BOOST_INT_SW_DRV_CNTL, 0xf8 }, + { WCD934X_BOOST_INT_SPARE1, 0x00 }, + { WCD934X_BOOST_INT_SPARE2, 0x00 }, + { WCD934X_SIDO_NEW_INT_RAMP_STATUS, 0x00 }, + { WCD934X_SIDO_NEW_INT_SPARE_1, 0x00 }, + { WCD934X_SIDO_NEW_INT_DEBUG_VOUT_SETTING_A, 0x64 }, + { WCD934X_SIDO_NEW_INT_DEBUG_VOUT_SETTING_D, 0x40 }, + { WCD934X_SIDO_NEW_INT_RAMP_INC_WAIT, 0x24 }, + { WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_CTL, 0x09 }, + { WCD934X_SIDO_NEW_INT_RAMP_IBLEED_CTL, 0x7d }, + { WCD934X_SIDO_NEW_INT_DEBUG_CPROVR_TEST, 0x00 }, + { WCD934X_SIDO_NEW_INT_RAMP_CTL_A, 0x14 }, + { WCD934X_SIDO_NEW_INT_RAMP_CTL_D, 0x14 }, + { WCD934X_SIDO_NEW_INT_RAMP_TIMEOUT_PERIOD, 0x33 }, + { WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_SETTING1, 0x3f }, + { WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_SETTING2, 0x74 }, + { WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_SETTING3, 0x33 }, + { WCD934X_SIDO_NEW_INT_HIGH_ACCU_MODE_SEL1, 0x1d }, + { WCD934X_SIDO_NEW_INT_HIGH_ACCU_MODE_SEL2, 0x0a }, + { WCD934X_MBHC_NEW_INT_SLNQ_HPF, 0x50 }, + { WCD934X_MBHC_NEW_INT_SLNQ_REF, 0x24 }, + { WCD934X_MBHC_NEW_INT_SLNQ_COMP, 0x50 }, + { WCD934X_MBHC_NEW_INT_SPARE_2, 0x00 }, + { WCD934X_PAGE10_PAGE_REGISTER, 0x00 }, + { WCD934X_CDC_ANC0_CLK_RESET_CTL, 0x00 }, + { WCD934X_CDC_ANC0_MODE_1_CTL, 0x00 }, + { WCD934X_CDC_ANC0_MODE_2_CTL, 0x00 }, + { WCD934X_CDC_ANC0_FF_SHIFT, 0x00 }, + { WCD934X_CDC_ANC0_FB_SHIFT, 0x00 }, + { WCD934X_CDC_ANC0_LPF_FF_A_CTL, 0x00 }, + { WCD934X_CDC_ANC0_LPF_FF_B_CTL, 0x00 }, + { WCD934X_CDC_ANC0_LPF_FB_CTL, 0x00 }, + { WCD934X_CDC_ANC0_SMLPF_CTL, 0x00 }, + { WCD934X_CDC_ANC0_DCFLT_SHIFT_CTL, 0x00 }, + { WCD934X_CDC_ANC0_IIR_ADAPT_CTL, 0x00 }, + { WCD934X_CDC_ANC0_IIR_COEFF_1_CTL, 0x00 }, + { WCD934X_CDC_ANC0_IIR_COEFF_2_CTL, 0x00 }, + { WCD934X_CDC_ANC0_FF_A_GAIN_CTL, 0x00 }, + { WCD934X_CDC_ANC0_FF_B_GAIN_CTL, 0x00 }, + { WCD934X_CDC_ANC0_FB_GAIN_CTL, 0x00 }, + { WCD934X_CDC_ANC0_RC_COMMON_CTL, 0x00 }, + { WCD934X_CDC_ANC0_FIFO_COMMON_CTL, 0x88 }, + { WCD934X_CDC_ANC0_RC0_STATUS_FMIN_CNTR, 0x00 }, + { WCD934X_CDC_ANC0_RC1_STATUS_FMIN_CNTR, 0x00 }, + { WCD934X_CDC_ANC0_RC0_STATUS_FMAX_CNTR, 0x00 }, + { WCD934X_CDC_ANC0_RC1_STATUS_FMAX_CNTR, 0x00 }, + { WCD934X_CDC_ANC0_STATUS_FIFO, 0x00 }, + { WCD934X_CDC_ANC1_CLK_RESET_CTL, 0x00 }, + { WCD934X_CDC_ANC1_MODE_1_CTL, 0x00 }, + { WCD934X_CDC_ANC1_MODE_2_CTL, 0x00 }, + { WCD934X_CDC_ANC1_FF_SHIFT, 0x00 }, + { WCD934X_CDC_ANC1_FB_SHIFT, 0x00 }, + { WCD934X_CDC_ANC1_LPF_FF_A_CTL, 0x00 }, + { WCD934X_CDC_ANC1_LPF_FF_B_CTL, 0x00 }, + { WCD934X_CDC_ANC1_LPF_FB_CTL, 0x00 }, + { WCD934X_CDC_ANC1_SMLPF_CTL, 0x00 }, + { WCD934X_CDC_ANC1_DCFLT_SHIFT_CTL, 0x00 }, + { WCD934X_CDC_ANC1_IIR_ADAPT_CTL, 0x00 }, + { WCD934X_CDC_ANC1_IIR_COEFF_1_CTL, 0x00 }, + { WCD934X_CDC_ANC1_IIR_COEFF_2_CTL, 0x00 }, + { WCD934X_CDC_ANC1_FF_A_GAIN_CTL, 0x00 }, + { WCD934X_CDC_ANC1_FF_B_GAIN_CTL, 0x00 }, + { WCD934X_CDC_ANC1_FB_GAIN_CTL, 0x00 }, + { WCD934X_CDC_ANC1_RC_COMMON_CTL, 0x00 }, + { WCD934X_CDC_ANC1_FIFO_COMMON_CTL, 0x88 }, + { WCD934X_CDC_ANC1_RC0_STATUS_FMIN_CNTR, 0x00 }, + { WCD934X_CDC_ANC1_RC1_STATUS_FMIN_CNTR, 0x00 }, + { WCD934X_CDC_ANC1_RC0_STATUS_FMAX_CNTR, 0x00 }, + { WCD934X_CDC_ANC1_RC1_STATUS_FMAX_CNTR, 0x00 }, + { WCD934X_CDC_ANC1_STATUS_FIFO, 0x00 }, + { WCD934X_CDC_TX0_TX_PATH_CTL, 0x04 }, + { WCD934X_CDC_TX0_TX_PATH_CFG0, 0x10 }, + { WCD934X_CDC_TX0_TX_PATH_CFG1, 0x03 }, + { WCD934X_CDC_TX0_TX_VOL_CTL, 0x00 }, + { WCD934X_CDC_TX0_TX_PATH_192_CTL, 0x00 }, + { WCD934X_CDC_TX0_TX_PATH_192_CFG, 0x00 }, + { WCD934X_CDC_TX0_TX_PATH_SEC0, 0x00 }, + { WCD934X_CDC_TX0_TX_PATH_SEC1, 0x00 }, + { WCD934X_CDC_TX0_TX_PATH_SEC2, 0x01 }, + { WCD934X_CDC_TX0_TX_PATH_SEC3, 0x3c }, + { WCD934X_CDC_TX0_TX_PATH_SEC4, 0x20 }, + { WCD934X_CDC_TX0_TX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_TX0_TX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_TX0_TX_PATH_SEC7, 0x25 }, + { WCD934X_CDC_TX1_TX_PATH_CTL, 0x04 }, + { WCD934X_CDC_TX1_TX_PATH_CFG0, 0x10 }, + { WCD934X_CDC_TX1_TX_PATH_CFG1, 0x03 }, + { WCD934X_CDC_TX1_TX_VOL_CTL, 0x00 }, + { WCD934X_CDC_TX1_TX_PATH_192_CTL, 0x00 }, + { WCD934X_CDC_TX1_TX_PATH_192_CFG, 0x00 }, + { WCD934X_CDC_TX1_TX_PATH_SEC0, 0x00 }, + { WCD934X_CDC_TX1_TX_PATH_SEC1, 0x00 }, + { WCD934X_CDC_TX1_TX_PATH_SEC2, 0x01 }, + { WCD934X_CDC_TX1_TX_PATH_SEC3, 0x3c }, + { WCD934X_CDC_TX1_TX_PATH_SEC4, 0x20 }, + { WCD934X_CDC_TX1_TX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_TX1_TX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_TX2_TX_PATH_CTL, 0x04 }, + { WCD934X_CDC_TX2_TX_PATH_CFG0, 0x10 }, + { WCD934X_CDC_TX2_TX_PATH_CFG1, 0x03 }, + { WCD934X_CDC_TX2_TX_VOL_CTL, 0x00 }, + { WCD934X_CDC_TX2_TX_PATH_192_CTL, 0x00 }, + { WCD934X_CDC_TX2_TX_PATH_192_CFG, 0x00 }, + { WCD934X_CDC_TX2_TX_PATH_SEC0, 0x00 }, + { WCD934X_CDC_TX2_TX_PATH_SEC1, 0x00 }, + { WCD934X_CDC_TX2_TX_PATH_SEC2, 0x01 }, + { WCD934X_CDC_TX2_TX_PATH_SEC3, 0x3c }, + { WCD934X_CDC_TX2_TX_PATH_SEC4, 0x20 }, + { WCD934X_CDC_TX2_TX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_TX2_TX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_TX3_TX_PATH_CTL, 0x04 }, + { WCD934X_CDC_TX3_TX_PATH_CFG0, 0x10 }, + { WCD934X_CDC_TX3_TX_PATH_CFG1, 0x03 }, + { WCD934X_CDC_TX3_TX_VOL_CTL, 0x00 }, + { WCD934X_CDC_TX3_TX_PATH_192_CTL, 0x00 }, + { WCD934X_CDC_TX3_TX_PATH_192_CFG, 0x00 }, + { WCD934X_CDC_TX3_TX_PATH_SEC0, 0x00 }, + { WCD934X_CDC_TX3_TX_PATH_SEC1, 0x00 }, + { WCD934X_CDC_TX3_TX_PATH_SEC2, 0x01 }, + { WCD934X_CDC_TX3_TX_PATH_SEC3, 0x3c }, + { WCD934X_CDC_TX3_TX_PATH_SEC4, 0x20 }, + { WCD934X_CDC_TX3_TX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_TX3_TX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_TX4_TX_PATH_CTL, 0x04 }, + { WCD934X_CDC_TX4_TX_PATH_CFG0, 0x10 }, + { WCD934X_CDC_TX4_TX_PATH_CFG1, 0x03 }, + { WCD934X_CDC_TX4_TX_VOL_CTL, 0x00 }, + { WCD934X_CDC_TX4_TX_PATH_192_CTL, 0x00 }, + { WCD934X_CDC_TX4_TX_PATH_192_CFG, 0x00 }, + { WCD934X_CDC_TX4_TX_PATH_SEC0, 0x00 }, + { WCD934X_CDC_TX4_TX_PATH_SEC1, 0x00 }, + { WCD934X_CDC_TX4_TX_PATH_SEC2, 0x01 }, + { WCD934X_CDC_TX4_TX_PATH_SEC3, 0x3c }, + { WCD934X_CDC_TX4_TX_PATH_SEC4, 0x20 }, + { WCD934X_CDC_TX4_TX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_TX4_TX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_TX5_TX_PATH_CTL, 0x04 }, + { WCD934X_CDC_TX5_TX_PATH_CFG0, 0x10 }, + { WCD934X_CDC_TX5_TX_PATH_CFG1, 0x03 }, + { WCD934X_CDC_TX5_TX_VOL_CTL, 0x00 }, + { WCD934X_CDC_TX5_TX_PATH_192_CTL, 0x00 }, + { WCD934X_CDC_TX5_TX_PATH_192_CFG, 0x00 }, + { WCD934X_CDC_TX5_TX_PATH_SEC0, 0x00 }, + { WCD934X_CDC_TX5_TX_PATH_SEC1, 0x00 }, + { WCD934X_CDC_TX5_TX_PATH_SEC2, 0x01 }, + { WCD934X_CDC_TX5_TX_PATH_SEC3, 0x3c }, + { WCD934X_CDC_TX5_TX_PATH_SEC4, 0x20 }, + { WCD934X_CDC_TX5_TX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_TX5_TX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_TX6_TX_PATH_CTL, 0x04 }, + { WCD934X_CDC_TX6_TX_PATH_CFG0, 0x10 }, + { WCD934X_CDC_TX6_TX_PATH_CFG1, 0x03 }, + { WCD934X_CDC_TX6_TX_VOL_CTL, 0x00 }, + { WCD934X_CDC_TX6_TX_PATH_192_CTL, 0x00 }, + { WCD934X_CDC_TX6_TX_PATH_192_CFG, 0x00 }, + { WCD934X_CDC_TX6_TX_PATH_SEC0, 0x00 }, + { WCD934X_CDC_TX6_TX_PATH_SEC1, 0x00 }, + { WCD934X_CDC_TX6_TX_PATH_SEC2, 0x01 }, + { WCD934X_CDC_TX6_TX_PATH_SEC3, 0x3c }, + { WCD934X_CDC_TX6_TX_PATH_SEC4, 0x20 }, + { WCD934X_CDC_TX6_TX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_TX6_TX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_TX7_TX_PATH_CTL, 0x04 }, + { WCD934X_CDC_TX7_TX_PATH_CFG0, 0x10 }, + { WCD934X_CDC_TX7_TX_PATH_CFG1, 0x03 }, + { WCD934X_CDC_TX7_TX_VOL_CTL, 0x00 }, + { WCD934X_CDC_TX7_TX_PATH_192_CTL, 0x00 }, + { WCD934X_CDC_TX7_TX_PATH_192_CFG, 0x00 }, + { WCD934X_CDC_TX7_TX_PATH_SEC0, 0x00 }, + { WCD934X_CDC_TX7_TX_PATH_SEC1, 0x00 }, + { WCD934X_CDC_TX7_TX_PATH_SEC2, 0x01 }, + { WCD934X_CDC_TX7_TX_PATH_SEC3, 0x3c }, + { WCD934X_CDC_TX7_TX_PATH_SEC4, 0x20 }, + { WCD934X_CDC_TX7_TX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_TX7_TX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_TX8_TX_PATH_CTL, 0x04 }, + { WCD934X_CDC_TX8_TX_PATH_CFG0, 0x10 }, + { WCD934X_CDC_TX8_TX_PATH_CFG1, 0x03 }, + { WCD934X_CDC_TX8_TX_VOL_CTL, 0x00 }, + { WCD934X_CDC_TX8_TX_PATH_192_CTL, 0x00 }, + { WCD934X_CDC_TX8_TX_PATH_192_CFG, 0x00 }, + { WCD934X_CDC_TX8_TX_PATH_SEC0, 0x00 }, + { WCD934X_CDC_TX8_TX_PATH_SEC1, 0x00 }, + { WCD934X_CDC_TX8_TX_PATH_SEC2, 0x01 }, + { WCD934X_CDC_TX8_TX_PATH_SEC3, 0x3c }, + { WCD934X_CDC_TX8_TX_PATH_SEC4, 0x20 }, + { WCD934X_CDC_TX8_TX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_TX8_TX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL, 0x02 }, + { WCD934X_CDC_TX9_SPKR_PROT_PATH_CFG0, 0x00 }, + { WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL, 0x02 }, + { WCD934X_CDC_TX10_SPKR_PROT_PATH_CFG0, 0x00 }, + { WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL, 0x02 }, + { WCD934X_CDC_TX11_SPKR_PROT_PATH_CFG0, 0x00 }, + { WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL, 0x02 }, + { WCD934X_CDC_TX12_SPKR_PROT_PATH_CFG0, 0x00 }, + { WCD934X_PAGE11_PAGE_REGISTER, 0x00 }, + { WCD934X_CDC_COMPANDER1_CTL0, 0x60 }, + { WCD934X_CDC_COMPANDER1_CTL1, 0xdb }, + { WCD934X_CDC_COMPANDER1_CTL2, 0xff }, + { WCD934X_CDC_COMPANDER1_CTL3, 0x35 }, + { WCD934X_CDC_COMPANDER1_CTL4, 0xff }, + { WCD934X_CDC_COMPANDER1_CTL5, 0x00 }, + { WCD934X_CDC_COMPANDER1_CTL6, 0x01 }, + { WCD934X_CDC_COMPANDER1_CTL7, 0x08 }, + { WCD934X_CDC_COMPANDER2_CTL0, 0x60 }, + { WCD934X_CDC_COMPANDER2_CTL1, 0xdb }, + { WCD934X_CDC_COMPANDER2_CTL2, 0xff }, + { WCD934X_CDC_COMPANDER2_CTL3, 0x35 }, + { WCD934X_CDC_COMPANDER2_CTL4, 0xff }, + { WCD934X_CDC_COMPANDER2_CTL5, 0x00 }, + { WCD934X_CDC_COMPANDER2_CTL6, 0x01 }, + { WCD934X_CDC_COMPANDER2_CTL7, 0x08 }, + { WCD934X_CDC_COMPANDER3_CTL0, 0x60 }, + { WCD934X_CDC_COMPANDER3_CTL1, 0xdb }, + { WCD934X_CDC_COMPANDER3_CTL2, 0xff }, + { WCD934X_CDC_COMPANDER3_CTL3, 0x35 }, + { WCD934X_CDC_COMPANDER3_CTL4, 0xff }, + { WCD934X_CDC_COMPANDER3_CTL5, 0x00 }, + { WCD934X_CDC_COMPANDER3_CTL6, 0x01 }, + { WCD934X_CDC_COMPANDER3_CTL7, 0x08 }, + { WCD934X_CDC_COMPANDER4_CTL0, 0x60 }, + { WCD934X_CDC_COMPANDER4_CTL1, 0xdb }, + { WCD934X_CDC_COMPANDER4_CTL2, 0xff }, + { WCD934X_CDC_COMPANDER4_CTL3, 0x35 }, + { WCD934X_CDC_COMPANDER4_CTL4, 0xff }, + { WCD934X_CDC_COMPANDER4_CTL5, 0x00 }, + { WCD934X_CDC_COMPANDER4_CTL6, 0x01 }, + { WCD934X_CDC_COMPANDER4_CTL7, 0x08 }, + { WCD934X_CDC_COMPANDER7_CTL0, 0x60 }, + { WCD934X_CDC_COMPANDER7_CTL1, 0xdb }, + { WCD934X_CDC_COMPANDER7_CTL2, 0xff }, + { WCD934X_CDC_COMPANDER7_CTL3, 0x35 }, + { WCD934X_CDC_COMPANDER7_CTL4, 0xff }, + { WCD934X_CDC_COMPANDER7_CTL5, 0x00 }, + { WCD934X_CDC_COMPANDER7_CTL6, 0x01 }, + { WCD934X_CDC_COMPANDER7_CTL7, 0x08 }, + { WCD934X_CDC_COMPANDER8_CTL0, 0x60 }, + { WCD934X_CDC_COMPANDER8_CTL1, 0xdb }, + { WCD934X_CDC_COMPANDER8_CTL2, 0xff }, + { WCD934X_CDC_COMPANDER8_CTL3, 0x35 }, + { WCD934X_CDC_COMPANDER8_CTL4, 0xff }, + { WCD934X_CDC_COMPANDER8_CTL5, 0x00 }, + { WCD934X_CDC_COMPANDER8_CTL6, 0x01 }, + { WCD934X_CDC_COMPANDER8_CTL7, 0x08 }, + { WCD934X_CDC_RX0_RX_PATH_CTL, 0x04 }, + { WCD934X_CDC_RX0_RX_PATH_CFG0, 0x00 }, + { WCD934X_CDC_RX0_RX_PATH_CFG1, 0x64 }, + { WCD934X_CDC_RX0_RX_PATH_CFG2, 0x8f }, + { WCD934X_CDC_RX0_RX_VOL_CTL, 0x00 }, + { WCD934X_CDC_RX0_RX_PATH_MIX_CTL, 0x04 }, + { WCD934X_CDC_RX0_RX_PATH_MIX_CFG, 0x7e }, + { WCD934X_CDC_RX0_RX_VOL_MIX_CTL, 0x00 }, + { WCD934X_CDC_RX0_RX_PATH_SEC0, 0xfc }, + { WCD934X_CDC_RX0_RX_PATH_SEC1, 0x08 }, + { WCD934X_CDC_RX0_RX_PATH_SEC2, 0x00 }, + { WCD934X_CDC_RX0_RX_PATH_SEC3, 0x00 }, + { WCD934X_CDC_RX0_RX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_RX0_RX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_RX0_RX_PATH_SEC7, 0x00 }, + { WCD934X_CDC_RX0_RX_PATH_MIX_SEC0, 0x08 }, + { WCD934X_CDC_RX0_RX_PATH_MIX_SEC1, 0x00 }, + { WCD934X_CDC_RX0_RX_PATH_DSMDEM_CTL, 0x00 }, + { WCD934X_CDC_RX1_RX_PATH_CTL, 0x04 }, + { WCD934X_CDC_RX1_RX_PATH_CFG0, 0x00 }, + { WCD934X_CDC_RX1_RX_PATH_CFG1, 0x64 }, + { WCD934X_CDC_RX1_RX_PATH_CFG2, 0x8f }, + { WCD934X_CDC_RX1_RX_VOL_CTL, 0x00 }, + { WCD934X_CDC_RX1_RX_PATH_MIX_CTL, 0x04 }, + { WCD934X_CDC_RX1_RX_PATH_MIX_CFG, 0x7e }, + { WCD934X_CDC_RX1_RX_VOL_MIX_CTL, 0x00 }, + { WCD934X_CDC_RX1_RX_PATH_SEC0, 0xfc }, + { WCD934X_CDC_RX1_RX_PATH_SEC1, 0x08 }, + { WCD934X_CDC_RX1_RX_PATH_SEC2, 0x00 }, + { WCD934X_CDC_RX1_RX_PATH_SEC3, 0x00 }, + { WCD934X_CDC_RX1_RX_PATH_SEC4, 0x00 }, + { WCD934X_CDC_RX1_RX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_RX1_RX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_RX1_RX_PATH_SEC7, 0x00 }, + { WCD934X_CDC_RX1_RX_PATH_MIX_SEC0, 0x08 }, + { WCD934X_CDC_RX1_RX_PATH_MIX_SEC1, 0x00 }, + { WCD934X_CDC_RX1_RX_PATH_DSMDEM_CTL, 0x00 }, + { WCD934X_CDC_RX2_RX_PATH_CTL, 0x04 }, + { WCD934X_CDC_RX2_RX_PATH_CFG0, 0x00 }, + { WCD934X_CDC_RX2_RX_PATH_CFG1, 0x64 }, + { WCD934X_CDC_RX2_RX_PATH_CFG2, 0x8f }, + { WCD934X_CDC_RX2_RX_VOL_CTL, 0x00 }, + { WCD934X_CDC_RX2_RX_PATH_MIX_CTL, 0x04 }, + { WCD934X_CDC_RX2_RX_PATH_MIX_CFG, 0x7e }, + { WCD934X_CDC_RX2_RX_VOL_MIX_CTL, 0x00 }, + { WCD934X_CDC_RX2_RX_PATH_SEC0, 0xfc }, + { WCD934X_CDC_RX2_RX_PATH_SEC1, 0x08 }, + { WCD934X_CDC_RX2_RX_PATH_SEC2, 0x00 }, + { WCD934X_CDC_RX2_RX_PATH_SEC3, 0x00 }, + { WCD934X_CDC_RX2_RX_PATH_SEC4, 0x00 }, + { WCD934X_CDC_RX2_RX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_RX2_RX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_RX2_RX_PATH_SEC7, 0x00 }, + { WCD934X_CDC_RX2_RX_PATH_MIX_SEC0, 0x08 }, + { WCD934X_CDC_RX2_RX_PATH_MIX_SEC1, 0x00 }, + { WCD934X_CDC_RX2_RX_PATH_DSMDEM_CTL, 0x00 }, + { WCD934X_CDC_RX3_RX_PATH_CTL, 0x04 }, + { WCD934X_CDC_RX3_RX_PATH_CFG0, 0x00 }, + { WCD934X_CDC_RX3_RX_PATH_CFG1, 0x64 }, + { WCD934X_CDC_RX3_RX_PATH_CFG2, 0x8f }, + { WCD934X_CDC_RX3_RX_VOL_CTL, 0x00 }, + { WCD934X_CDC_RX3_RX_PATH_MIX_CTL, 0x04 }, + { WCD934X_CDC_RX3_RX_PATH_MIX_CFG, 0x7e }, + { WCD934X_CDC_RX3_RX_VOL_MIX_CTL, 0x00 }, + { WCD934X_CDC_RX3_RX_PATH_SEC0, 0xfc }, + { WCD934X_CDC_RX3_RX_PATH_SEC1, 0x08 }, + { WCD934X_CDC_RX3_RX_PATH_SEC2, 0x00 }, + { WCD934X_CDC_RX3_RX_PATH_SEC3, 0x00 }, + { WCD934X_CDC_RX3_RX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_RX3_RX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_RX3_RX_PATH_SEC7, 0x00 }, + { WCD934X_CDC_RX3_RX_PATH_MIX_SEC0, 0x08 }, + { WCD934X_CDC_RX3_RX_PATH_MIX_SEC1, 0x00 }, + { WCD934X_CDC_RX3_RX_PATH_DSMDEM_CTL, 0x00 }, + { WCD934X_CDC_RX4_RX_PATH_CTL, 0x04 }, + { WCD934X_CDC_RX4_RX_PATH_CFG0, 0x00 }, + { WCD934X_CDC_RX4_RX_PATH_CFG1, 0x64 }, + { WCD934X_CDC_RX4_RX_PATH_CFG2, 0x8f }, + { WCD934X_CDC_RX4_RX_VOL_CTL, 0x00 }, + { WCD934X_CDC_RX4_RX_PATH_MIX_CTL, 0x04 }, + { WCD934X_CDC_RX4_RX_PATH_MIX_CFG, 0x7e }, + { WCD934X_CDC_RX4_RX_VOL_MIX_CTL, 0x00 }, + { WCD934X_CDC_RX4_RX_PATH_SEC0, 0xfc }, + { WCD934X_CDC_RX4_RX_PATH_SEC1, 0x08 }, + { WCD934X_CDC_RX4_RX_PATH_SEC2, 0x00 }, + { WCD934X_CDC_RX4_RX_PATH_SEC3, 0x00 }, + { WCD934X_CDC_RX4_RX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_RX4_RX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_RX4_RX_PATH_SEC7, 0x00 }, + { WCD934X_CDC_RX4_RX_PATH_MIX_SEC0, 0x08 }, + { WCD934X_CDC_RX4_RX_PATH_MIX_SEC1, 0x00 }, + { WCD934X_CDC_RX4_RX_PATH_DSMDEM_CTL, 0x00 }, + { WCD934X_CDC_RX7_RX_PATH_CTL, 0x04 }, + { WCD934X_CDC_RX7_RX_PATH_CFG0, 0x00 }, + { WCD934X_CDC_RX7_RX_PATH_CFG1, 0x64 }, + { WCD934X_CDC_RX7_RX_PATH_CFG2, 0x8f }, + { WCD934X_CDC_RX7_RX_VOL_CTL, 0x00 }, + { WCD934X_CDC_RX7_RX_PATH_MIX_CTL, 0x04 }, + { WCD934X_CDC_RX7_RX_PATH_MIX_CFG, 0x7e }, + { WCD934X_CDC_RX7_RX_VOL_MIX_CTL, 0x00 }, + { WCD934X_CDC_RX7_RX_PATH_SEC0, 0x04 }, + { WCD934X_CDC_RX7_RX_PATH_SEC1, 0x08 }, + { WCD934X_CDC_RX7_RX_PATH_SEC2, 0x00 }, + { WCD934X_CDC_RX7_RX_PATH_SEC3, 0x00 }, + { WCD934X_CDC_RX7_RX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_RX7_RX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_RX7_RX_PATH_SEC7, 0x00 }, + { WCD934X_CDC_RX7_RX_PATH_MIX_SEC0, 0x08 }, + { WCD934X_CDC_RX7_RX_PATH_MIX_SEC1, 0x00 }, + { WCD934X_CDC_RX7_RX_PATH_DSMDEM_CTL, 0x00 }, + { WCD934X_CDC_RX8_RX_PATH_CTL, 0x04 }, + { WCD934X_CDC_RX8_RX_PATH_CFG0, 0x00 }, + { WCD934X_CDC_RX8_RX_PATH_CFG1, 0x64 }, + { WCD934X_CDC_RX8_RX_PATH_CFG2, 0x8f }, + { WCD934X_CDC_RX8_RX_VOL_CTL, 0x00 }, + { WCD934X_CDC_RX8_RX_PATH_MIX_CTL, 0x04 }, + { WCD934X_CDC_RX8_RX_PATH_MIX_CFG, 0x7e }, + { WCD934X_CDC_RX8_RX_VOL_MIX_CTL, 0x00 }, + { WCD934X_CDC_RX8_RX_PATH_SEC0, 0x04 }, + { WCD934X_CDC_RX8_RX_PATH_SEC1, 0x08 }, + { WCD934X_CDC_RX8_RX_PATH_SEC2, 0x00 }, + { WCD934X_CDC_RX8_RX_PATH_SEC3, 0x00 }, + { WCD934X_CDC_RX8_RX_PATH_SEC5, 0x00 }, + { WCD934X_CDC_RX8_RX_PATH_SEC6, 0x00 }, + { WCD934X_CDC_RX8_RX_PATH_SEC7, 0x00 }, + { WCD934X_CDC_RX8_RX_PATH_MIX_SEC0, 0x08 }, + { WCD934X_CDC_RX8_RX_PATH_MIX_SEC1, 0x00 }, + { WCD934X_CDC_RX8_RX_PATH_DSMDEM_CTL, 0x00 }, + { WCD934X_PAGE12_PAGE_REGISTER, 0x00 }, + { WCD934X_CDC_CLSH_CRC, 0x00 }, + { WCD934X_CDC_CLSH_DLY_CTRL, 0x03 }, + { WCD934X_CDC_CLSH_DECAY_CTRL, 0x02 }, + { WCD934X_CDC_CLSH_HPH_V_PA, 0x1c }, + { WCD934X_CDC_CLSH_EAR_V_PA, 0x39 }, + { WCD934X_CDC_CLSH_HPH_V_HD, 0x0c }, + { WCD934X_CDC_CLSH_EAR_V_HD, 0x0c }, + { WCD934X_CDC_CLSH_K1_MSB, 0x01 }, + { WCD934X_CDC_CLSH_K1_LSB, 0x00 }, + { WCD934X_CDC_CLSH_K2_MSB, 0x00 }, + { WCD934X_CDC_CLSH_K2_LSB, 0x80 }, + { WCD934X_CDC_CLSH_IDLE_CTRL, 0x00 }, + { WCD934X_CDC_CLSH_IDLE_HPH, 0x00 }, + { WCD934X_CDC_CLSH_IDLE_EAR, 0x00 }, + { WCD934X_CDC_CLSH_TEST0, 0x07 }, + { WCD934X_CDC_CLSH_TEST1, 0x00 }, + { WCD934X_CDC_CLSH_OVR_VREF, 0x00 }, + { WCD934X_CDC_BOOST0_BOOST_PATH_CTL, 0x00 }, + { WCD934X_CDC_BOOST0_BOOST_CTL, 0xb2 }, + { WCD934X_CDC_BOOST0_BOOST_CFG1, 0x00 }, + { WCD934X_CDC_BOOST0_BOOST_CFG2, 0x00 }, + { WCD934X_CDC_BOOST1_BOOST_PATH_CTL, 0x00 }, + { WCD934X_CDC_BOOST1_BOOST_CTL, 0xb2 }, + { WCD934X_CDC_BOOST1_BOOST_CFG1, 0x00 }, + { WCD934X_CDC_BOOST1_BOOST_CFG2, 0x00 }, + { WCD934X_CDC_VBAT_VBAT_PATH_CTL, 0x00 }, + { WCD934X_CDC_VBAT_VBAT_CFG, 0x1a }, + { WCD934X_CDC_VBAT_VBAT_ADC_CAL1, 0x00 }, + { WCD934X_CDC_VBAT_VBAT_ADC_CAL2, 0x00 }, + { WCD934X_CDC_VBAT_VBAT_ADC_CAL3, 0x04 }, + { WCD934X_CDC_VBAT_VBAT_PK_EST1, 0xe0 }, + { WCD934X_CDC_VBAT_VBAT_PK_EST2, 0x01 }, + { WCD934X_CDC_VBAT_VBAT_PK_EST3, 0x40 }, + { WCD934X_CDC_VBAT_VBAT_RF_PROC1, 0x2a }, + { WCD934X_CDC_VBAT_VBAT_RF_PROC2, 0x86 }, + { WCD934X_CDC_VBAT_VBAT_TAC1, 0x70 }, + { WCD934X_CDC_VBAT_VBAT_TAC2, 0x18 }, + { WCD934X_CDC_VBAT_VBAT_TAC3, 0x18 }, + { WCD934X_CDC_VBAT_VBAT_TAC4, 0x03 }, + { WCD934X_CDC_VBAT_VBAT_GAIN_UPD1, 0x01 }, + { WCD934X_CDC_VBAT_VBAT_GAIN_UPD2, 0x00 }, + { WCD934X_CDC_VBAT_VBAT_GAIN_UPD3, 0x64 }, + { WCD934X_CDC_VBAT_VBAT_GAIN_UPD4, 0x01 }, + { WCD934X_CDC_VBAT_VBAT_DEBUG1, 0x00 }, + { WCD934X_CDC_VBAT_VBAT_GAIN_UPD_MON, 0x00 }, + { WCD934X_CDC_VBAT_VBAT_GAIN_MON_VAL, 0x00 }, + { WCD934X_CDC_VBAT_VBAT_BAN, 0x0c }, + { WCD934X_MIXING_ASRC0_CLK_RST_CTL, 0x00 }, + { WCD934X_MIXING_ASRC0_CTL0, 0x00 }, + { WCD934X_MIXING_ASRC0_CTL1, 0x00 }, + { WCD934X_MIXING_ASRC0_FIFO_CTL, 0xa8 }, + { WCD934X_MIXING_ASRC0_STATUS_FMIN_CNTR_LSB, 0x00 }, + { WCD934X_MIXING_ASRC0_STATUS_FMIN_CNTR_MSB, 0x00 }, + { WCD934X_MIXING_ASRC0_STATUS_FMAX_CNTR_LSB, 0x00 }, + { WCD934X_MIXING_ASRC0_STATUS_FMAX_CNTR_MSB, 0x00 }, + { WCD934X_MIXING_ASRC0_STATUS_FIFO, 0x00 }, + { WCD934X_MIXING_ASRC1_CLK_RST_CTL, 0x00 }, + { WCD934X_MIXING_ASRC1_CTL0, 0x00 }, + { WCD934X_MIXING_ASRC1_CTL1, 0x00 }, + { WCD934X_MIXING_ASRC1_FIFO_CTL, 0xa8 }, + { WCD934X_MIXING_ASRC1_STATUS_FMIN_CNTR_LSB, 0x00 }, + { WCD934X_MIXING_ASRC1_STATUS_FMIN_CNTR_MSB, 0x00 }, + { WCD934X_MIXING_ASRC1_STATUS_FMAX_CNTR_LSB, 0x00 }, + { WCD934X_MIXING_ASRC1_STATUS_FMAX_CNTR_MSB, 0x00 }, + { WCD934X_MIXING_ASRC1_STATUS_FIFO, 0x00 }, + { WCD934X_MIXING_ASRC2_CLK_RST_CTL, 0x00 }, + { WCD934X_MIXING_ASRC2_CTL0, 0x00 }, + { WCD934X_MIXING_ASRC2_CTL1, 0x00 }, + { WCD934X_MIXING_ASRC2_FIFO_CTL, 0xa8 }, + { WCD934X_MIXING_ASRC2_STATUS_FMIN_CNTR_LSB, 0x00 }, + { WCD934X_MIXING_ASRC2_STATUS_FMIN_CNTR_MSB, 0x00 }, + { WCD934X_MIXING_ASRC2_STATUS_FMAX_CNTR_LSB, 0x00 }, + { WCD934X_MIXING_ASRC2_STATUS_FMAX_CNTR_MSB, 0x00 }, + { WCD934X_MIXING_ASRC2_STATUS_FIFO, 0x00 }, + { WCD934X_MIXING_ASRC3_CLK_RST_CTL, 0x00 }, + { WCD934X_MIXING_ASRC3_CTL0, 0x00 }, + { WCD934X_MIXING_ASRC3_CTL1, 0x00 }, + { WCD934X_MIXING_ASRC3_FIFO_CTL, 0xa8 }, + { WCD934X_MIXING_ASRC3_STATUS_FMIN_CNTR_LSB, 0x00 }, + { WCD934X_MIXING_ASRC3_STATUS_FMIN_CNTR_MSB, 0x00 }, + { WCD934X_MIXING_ASRC3_STATUS_FMAX_CNTR_LSB, 0x00 }, + { WCD934X_MIXING_ASRC3_STATUS_FMAX_CNTR_MSB, 0x00 }, + { WCD934X_MIXING_ASRC3_STATUS_FIFO, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_WR_DATA_0, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_WR_DATA_1, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_WR_DATA_2, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_WR_DATA_3, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_WR_ADDR_0, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_WR_ADDR_1, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_WR_ADDR_2, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_WR_ADDR_3, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_RD_ADDR_0, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_RD_ADDR_1, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_RD_ADDR_2, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_RD_ADDR_3, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_RD_DATA_0, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_RD_DATA_1, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_RD_DATA_2, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_RD_DATA_3, 0x00 }, + { WCD934X_SWR_AHB_BRIDGE_ACCESS_CFG, 0x0f }, + { WCD934X_SWR_AHB_BRIDGE_ACCESS_STATUS, 0x03 }, + { WCD934X_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL, 0x04 }, + { WCD934X_CDC_SIDETONE_SRC0_ST_SRC_PATH_CFG1, 0x00 }, + { WCD934X_CDC_SIDETONE_SRC1_ST_SRC_PATH_CTL, 0x04 }, + { WCD934X_CDC_SIDETONE_SRC1_ST_SRC_PATH_CFG1, 0x00 }, + { WCD934X_SIDETONE_ASRC0_CLK_RST_CTL, 0x00 }, + { WCD934X_SIDETONE_ASRC0_CTL0, 0x00 }, + { WCD934X_SIDETONE_ASRC0_CTL1, 0x00 }, + { WCD934X_SIDETONE_ASRC0_FIFO_CTL, 0xa8 }, + { WCD934X_SIDETONE_ASRC0_STATUS_FMIN_CNTR_LSB, 0x00 }, + { WCD934X_SIDETONE_ASRC0_STATUS_FMIN_CNTR_MSB, 0x00 }, + { WCD934X_SIDETONE_ASRC0_STATUS_FMAX_CNTR_LSB, 0x00 }, + { WCD934X_SIDETONE_ASRC0_STATUS_FMAX_CNTR_MSB, 0x00 }, + { WCD934X_SIDETONE_ASRC0_STATUS_FIFO, 0x00 }, + { WCD934X_SIDETONE_ASRC1_CLK_RST_CTL, 0x00 }, + { WCD934X_SIDETONE_ASRC1_CTL0, 0x00 }, + { WCD934X_SIDETONE_ASRC1_CTL1, 0x00 }, + { WCD934X_SIDETONE_ASRC1_FIFO_CTL, 0xa8 }, + { WCD934X_SIDETONE_ASRC1_STATUS_FMIN_CNTR_LSB, 0x00 }, + { WCD934X_SIDETONE_ASRC1_STATUS_FMIN_CNTR_MSB, 0x00 }, + { WCD934X_SIDETONE_ASRC1_STATUS_FMAX_CNTR_LSB, 0x00 }, + { WCD934X_SIDETONE_ASRC1_STATUS_FMAX_CNTR_MSB, 0x00 }, + { WCD934X_SIDETONE_ASRC1_STATUS_FIFO, 0x00 }, + { WCD934X_EC_REF_HQ0_EC_REF_HQ_PATH_CTL, 0x00 }, + { WCD934X_EC_REF_HQ0_EC_REF_HQ_CFG0, 0x01 }, + { WCD934X_EC_REF_HQ1_EC_REF_HQ_PATH_CTL, 0x00 }, + { WCD934X_EC_REF_HQ1_EC_REF_HQ_CFG0, 0x01 }, + { WCD934X_EC_ASRC0_CLK_RST_CTL, 0x00 }, + { WCD934X_EC_ASRC0_CTL0, 0x00 }, + { WCD934X_EC_ASRC0_CTL1, 0x00 }, + { WCD934X_EC_ASRC0_FIFO_CTL, 0xa8 }, + { WCD934X_EC_ASRC0_STATUS_FMIN_CNTR_LSB, 0x00 }, + { WCD934X_EC_ASRC0_STATUS_FMIN_CNTR_MSB, 0x00 }, + { WCD934X_EC_ASRC0_STATUS_FMAX_CNTR_LSB, 0x00 }, + { WCD934X_EC_ASRC0_STATUS_FMAX_CNTR_MSB, 0x00 }, + { WCD934X_EC_ASRC0_STATUS_FIFO, 0x00 }, + { WCD934X_EC_ASRC1_CLK_RST_CTL, 0x00 }, + { WCD934X_EC_ASRC1_CTL0, 0x00 }, + { WCD934X_EC_ASRC1_CTL1, 0x00 }, + { WCD934X_EC_ASRC1_FIFO_CTL, 0xa8 }, + { WCD934X_EC_ASRC1_STATUS_FMIN_CNTR_LSB, 0x00 }, + { WCD934X_EC_ASRC1_STATUS_FMIN_CNTR_MSB, 0x00 }, + { WCD934X_EC_ASRC1_STATUS_FMAX_CNTR_LSB, 0x00 }, + { WCD934X_EC_ASRC1_STATUS_FMAX_CNTR_MSB, 0x00 }, + { WCD934X_EC_ASRC1_STATUS_FIFO, 0x00 }, + { WCD934X_PAGE13_PAGE_REGISTER, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG0, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG1, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG0, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG1, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG0, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG1, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG0, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG1, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG0, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG1, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG0, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG1, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG0, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG1, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG0, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG1, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG2, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG3, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG4, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_ANC_CFG0, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_SPLINE_ASRC_CFG0, 0x00 }, + { WCD934X_CDC_RX_INP_MUX_EC_REF_HQ_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX10_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX11_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX12_CFG0, 0x00 }, + { WCD934X_CDC_TX_INP_MUX_ADC_MUX13_CFG0, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG1, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG2, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG3, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG0, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG1, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG2, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG3, 0x00 }, + { WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0, 0x00 }, + { WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1, 0x00 }, + { WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2, 0x00 }, + { WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3, 0x00 }, + { WCD934X_CDC_CLK_RST_CTRL_MCLK_CONTROL, 0x00 }, + { WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, 0x0c }, + { WCD934X_CDC_CLK_RST_CTRL_SWR_CONTROL, 0x00 }, + { WCD934X_CDC_CLK_RST_CTRL_DSD_CONTROL, 0x00 }, + { WCD934X_CDC_CLK_RST_CTRL_ASRC_SHARE_CONTROL, 0x0f }, + { WCD934X_CDC_CLK_RST_CTRL_GFM_CONTROL, 0x00 }, + { WCD934X_CDC_PROX_DETECT_PROX_CTL, 0x08 }, + { WCD934X_CDC_PROX_DETECT_PROX_POLL_PERIOD0, 0x00 }, + { WCD934X_CDC_PROX_DETECT_PROX_POLL_PERIOD1, 0x4b }, + { WCD934X_CDC_PROX_DETECT_PROX_SIG_PATTERN_LSB, 0x00 }, + { WCD934X_CDC_PROX_DETECT_PROX_SIG_PATTERN_MSB, 0x00 }, + { WCD934X_CDC_PROX_DETECT_PROX_STATUS, 0x00 }, + { WCD934X_CDC_PROX_DETECT_PROX_TEST_CTRL, 0x00 }, + { WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB, 0x00 }, + { WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB, 0x00 }, + { WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB_RD, 0x00 }, + { WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB_RD, 0x00 }, + { WCD934X_CDC_PROX_DETECT_PROX_CTL_REPEAT_PAT, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_PATH_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B5_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B6_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B7_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B8_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_CTL, 0x40 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_PATH_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B5_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B6_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B7_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B8_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_CTL, 0x40 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_COEF_B1_CTL, 0x00 }, + { WCD934X_CDC_SIDETONE_IIR1_IIR_COEF_B2_CTL, 0x00 }, + { WCD934X_CDC_TOP_TOP_CFG0, 0x00 }, + { WCD934X_CDC_TOP_TOP_CFG1, 0x00 }, + { WCD934X_CDC_TOP_TOP_CFG7, 0x00 }, + { WCD934X_CDC_TOP_HPHL_COMP_WR_LSB, 0x00 }, + { WCD934X_CDC_TOP_HPHL_COMP_WR_MSB, 0x00 }, + { WCD934X_CDC_TOP_HPHL_COMP_LUT, 0x00 }, + { WCD934X_CDC_TOP_HPHL_COMP_RD_LSB, 0x00 }, + { WCD934X_CDC_TOP_HPHL_COMP_RD_MSB, 0x00 }, + { WCD934X_CDC_TOP_HPHR_COMP_WR_LSB, 0x00 }, + { WCD934X_CDC_TOP_HPHR_COMP_WR_MSB, 0x00 }, + { WCD934X_CDC_TOP_HPHR_COMP_LUT, 0x00 }, + { WCD934X_CDC_TOP_HPHR_COMP_RD_LSB, 0x00 }, + { WCD934X_CDC_TOP_HPHR_COMP_RD_MSB, 0x00 }, + { WCD934X_CDC_TOP_DIFFL_COMP_WR_LSB, 0x00 }, + { WCD934X_CDC_TOP_DIFFL_COMP_WR_MSB, 0x00 }, + { WCD934X_CDC_TOP_DIFFL_COMP_LUT, 0x00 }, + { WCD934X_CDC_TOP_DIFFL_COMP_RD_LSB, 0x00 }, + { WCD934X_CDC_TOP_DIFFL_COMP_RD_MSB, 0x00 }, + { WCD934X_CDC_TOP_DIFFR_COMP_WR_LSB, 0x00 }, + { WCD934X_CDC_TOP_DIFFR_COMP_WR_MSB, 0x00 }, + { WCD934X_CDC_TOP_DIFFR_COMP_LUT, 0x00 }, + { WCD934X_CDC_TOP_DIFFR_COMP_RD_LSB, 0x00 }, + { WCD934X_CDC_TOP_DIFFR_COMP_RD_MSB, 0x00 }, + { WCD934X_CDC_DSD0_PATH_CTL, 0x00 }, + { WCD934X_CDC_DSD0_CFG0, 0x00 }, + { WCD934X_CDC_DSD0_CFG1, 0x00 }, + { WCD934X_CDC_DSD0_CFG2, 0x42 }, + { WCD934X_CDC_DSD0_CFG3, 0x00 }, + { WCD934X_CDC_DSD0_CFG4, 0x02 }, + { WCD934X_CDC_DSD0_CFG5, 0x00 }, + { WCD934X_CDC_DSD1_PATH_CTL, 0x00 }, + { WCD934X_CDC_DSD1_CFG0, 0x00 }, + { WCD934X_CDC_DSD1_CFG1, 0x00 }, + { WCD934X_CDC_DSD1_CFG2, 0x42 }, + { WCD934X_CDC_DSD1_CFG3, 0x00 }, + { WCD934X_CDC_DSD1_CFG4, 0x02 }, + { WCD934X_CDC_DSD1_CFG5, 0x00 }, + { WCD934X_CDC_RX_IDLE_DET_PATH_CTL, 0x00 }, + { WCD934X_CDC_RX_IDLE_DET_CFG0, 0x07 }, + { WCD934X_CDC_RX_IDLE_DET_CFG1, 0x3c }, + { WCD934X_CDC_RX_IDLE_DET_CFG2, 0x00 }, + { WCD934X_CDC_RX_IDLE_DET_CFG3, 0x00 }, + { WCD934X_PAGE14_PAGE_REGISTER, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_CLK_RST_CTL, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_CTL, 0x09 }, + { WCD934X_CDC_RATE_EST0_RE_PULSE_SUPR_CTL, 0x06 }, + { WCD934X_CDC_RATE_EST0_RE_TIMER, 0x01 }, + { WCD934X_CDC_RATE_EST0_RE_BW_SW, 0x20 }, + { WCD934X_CDC_RATE_EST0_RE_THRESH, 0xa0 }, + { WCD934X_CDC_RATE_EST0_RE_STATUS, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_CTRL, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_TIMER2, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW1, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW2, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW3, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW4, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW5, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW1, 0x08 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW2, 0x07 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW3, 0x05 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW4, 0x05 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW5, 0x05 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW1, 0x08 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW2, 0x07 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW3, 0x05 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW4, 0x05 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW5, 0x05 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW1, 0x03 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW2, 0x03 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW3, 0x03 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW4, 0x03 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW5, 0x03 }, + { WCD934X_CDC_RATE_EST0_RE_RMAX_DIAG, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_RMIN_DIAG, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_PH_DET, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_DIAG_CLR, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_MB_SW_STATE, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_MAST_DIAG_STATE, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_RATE_OUT_7_0, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_RATE_OUT_15_8, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_RATE_OUT_23_16, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_RATE_OUT_31_24, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_RATE_OUT_39_32, 0x00 }, + { WCD934X_CDC_RATE_EST0_RE_RATE_OUT_40_43, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_CLK_RST_CTL, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_CTL, 0x09 }, + { WCD934X_CDC_RATE_EST1_RE_PULSE_SUPR_CTL, 0x06 }, + { WCD934X_CDC_RATE_EST1_RE_TIMER, 0x01 }, + { WCD934X_CDC_RATE_EST1_RE_BW_SW, 0x20 }, + { WCD934X_CDC_RATE_EST1_RE_THRESH, 0xa0 }, + { WCD934X_CDC_RATE_EST1_RE_STATUS, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_CTRL, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_TIMER2, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW1, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW2, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW3, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW4, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW5, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW1, 0x08 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW2, 0x07 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW3, 0x05 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW4, 0x05 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW5, 0x05 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW1, 0x08 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW2, 0x07 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW3, 0x05 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW4, 0x05 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW5, 0x05 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW1, 0x03 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW2, 0x03 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW3, 0x03 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW4, 0x03 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW5, 0x03 }, + { WCD934X_CDC_RATE_EST1_RE_RMAX_DIAG, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_RMIN_DIAG, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_PH_DET, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_DIAG_CLR, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_MB_SW_STATE, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_MAST_DIAG_STATE, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_RATE_OUT_7_0, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_RATE_OUT_15_8, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_RATE_OUT_23_16, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_RATE_OUT_31_24, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_RATE_OUT_39_32, 0x00 }, + { WCD934X_CDC_RATE_EST1_RE_RATE_OUT_40_43, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_CLK_RST_CTL, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_CTL, 0x09 }, + { WCD934X_CDC_RATE_EST2_RE_PULSE_SUPR_CTL, 0x06 }, + { WCD934X_CDC_RATE_EST2_RE_TIMER, 0x01 }, + { WCD934X_CDC_RATE_EST2_RE_BW_SW, 0x20 }, + { WCD934X_CDC_RATE_EST2_RE_THRESH, 0xa0 }, + { WCD934X_CDC_RATE_EST2_RE_STATUS, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_CTRL, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_TIMER2, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW1, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW2, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW3, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW4, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW5, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW1, 0x08 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW2, 0x07 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW3, 0x05 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW4, 0x05 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW5, 0x05 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW1, 0x08 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW2, 0x07 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW3, 0x05 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW4, 0x05 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW5, 0x05 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW1, 0x03 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW2, 0x03 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW3, 0x03 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW4, 0x03 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW5, 0x03 }, + { WCD934X_CDC_RATE_EST2_RE_RMAX_DIAG, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_RMIN_DIAG, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_PH_DET, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_DIAG_CLR, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_MB_SW_STATE, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_MAST_DIAG_STATE, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_RATE_OUT_7_0, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_RATE_OUT_15_8, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_RATE_OUT_23_16, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_RATE_OUT_31_24, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_RATE_OUT_39_32, 0x00 }, + { WCD934X_CDC_RATE_EST2_RE_RATE_OUT_40_43, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_CLK_RST_CTL, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_CTL, 0x09 }, + { WCD934X_CDC_RATE_EST3_RE_PULSE_SUPR_CTL, 0x06 }, + { WCD934X_CDC_RATE_EST3_RE_TIMER, 0x01 }, + { WCD934X_CDC_RATE_EST3_RE_BW_SW, 0x20 }, + { WCD934X_CDC_RATE_EST3_RE_THRESH, 0xa0 }, + { WCD934X_CDC_RATE_EST3_RE_STATUS, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_CTRL, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_TIMER2, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW1, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW2, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW3, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW4, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW5, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW1, 0x08 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW2, 0x07 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW3, 0x05 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW4, 0x05 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW5, 0x05 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW1, 0x08 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW2, 0x07 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW3, 0x05 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW4, 0x05 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW5, 0x05 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW1, 0x03 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW2, 0x03 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW3, 0x03 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW4, 0x03 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW5, 0x03 }, + { WCD934X_CDC_RATE_EST3_RE_RMAX_DIAG, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_RMIN_DIAG, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_PH_DET, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_DIAG_CLR, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_MB_SW_STATE, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_MAST_DIAG_STATE, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_RATE_OUT_7_0, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_RATE_OUT_15_8, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_RATE_OUT_23_16, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_RATE_OUT_31_24, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_RATE_OUT_39_32, 0x00 }, + { WCD934X_CDC_RATE_EST3_RE_RATE_OUT_40_43, 0x00 }, + { WCD934X_PAGE15_PAGE_REGISTER, 0x00 }, + { WCD934X_SPLINE_SRC0_CLK_RST_CTL_0, 0x20 }, + { WCD934X_SPLINE_SRC0_STATUS, 0x00 }, + { WCD934X_SPLINE_SRC1_CLK_RST_CTL_0, 0x20 }, + { WCD934X_SPLINE_SRC1_STATUS, 0x00 }, + { WCD934X_SPLINE_SRC2_CLK_RST_CTL_0, 0x20 }, + { WCD934X_SPLINE_SRC2_STATUS, 0x00 }, + { WCD934X_SPLINE_SRC3_CLK_RST_CTL_0, 0x20 }, + { WCD934X_SPLINE_SRC3_STATUS, 0x00 }, + { WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG0, 0x11 }, + { WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG1, 0x20 }, + { WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG2, 0x00 }, + { WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG3, 0x08 }, + { WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG0, 0x11 }, + { WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG1, 0x20 }, + { WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG2, 0x00 }, + { WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG3, 0x08 }, + { WCD934X_CDC_DEBUG_SPLINE_SRC_DEBUG_CFG0, 0x00 }, + { WCD934X_CDC_DEBUG_SPLINE_SRC_DEBUG_CFG1, 0x00 }, + { WCD934X_CDC_DEBUG_RC_RE_ASRC_DEBUG_CFG0, 0x00 }, + { WCD934X_CDC_DEBUG_ANC0_RC0_FIFO_CTL, 0x4c }, + { WCD934X_CDC_DEBUG_ANC0_RC1_FIFO_CTL, 0x4c }, + { WCD934X_CDC_DEBUG_ANC1_RC0_FIFO_CTL, 0x4c }, + { WCD934X_CDC_DEBUG_ANC1_RC1_FIFO_CTL, 0x4c }, + { WCD934X_CDC_DEBUG_ANC_RC_RST_DBG_CNTR, 0x00 }, + { WCD934X_PAGE80_PAGE_REGISTER, 0x00 }, + { WCD934X_CODEC_CPR_WR_DATA_0, 0x00 }, + { WCD934X_CODEC_CPR_WR_DATA_1, 0x00 }, + { WCD934X_CODEC_CPR_WR_DATA_2, 0x00 }, + { WCD934X_CODEC_CPR_WR_DATA_3, 0x00 }, + { WCD934X_CODEC_CPR_WR_ADDR_0, 0x00 }, + { WCD934X_CODEC_CPR_WR_ADDR_1, 0x00 }, + { WCD934X_CODEC_CPR_WR_ADDR_2, 0x00 }, + { WCD934X_CODEC_CPR_WR_ADDR_3, 0x00 }, + { WCD934X_CODEC_CPR_RD_ADDR_0, 0x00 }, + { WCD934X_CODEC_CPR_RD_ADDR_1, 0x00 }, + { WCD934X_CODEC_CPR_RD_ADDR_2, 0x00 }, + { WCD934X_CODEC_CPR_RD_ADDR_3, 0x00 }, + { WCD934X_CODEC_CPR_RD_DATA_0, 0x00 }, + { WCD934X_CODEC_CPR_RD_DATA_1, 0x00 }, + { WCD934X_CODEC_CPR_RD_DATA_2, 0x00 }, + { WCD934X_CODEC_CPR_RD_DATA_3, 0x00 }, + { WCD934X_CODEC_CPR_ACCESS_CFG, 0x0f }, + { WCD934X_CODEC_CPR_ACCESS_STATUS, 0x03 }, + { WCD934X_CODEC_CPR_NOM_CX_VDD, 0xb4 }, + { WCD934X_CODEC_CPR_SVS_CX_VDD, 0x5c }, + { WCD934X_CODEC_CPR_SVS2_CX_VDD, 0x40 }, + { WCD934X_CODEC_CPR_NOM_MX_VDD, 0xb4 }, + { WCD934X_CODEC_CPR_SVS_MX_VDD, 0xb4 }, + { WCD934X_CODEC_CPR_SVS2_MX_VDD, 0xa0 }, + { WCD934X_CODEC_CPR_SVS2_MIN_CX_VDD, 0x28 }, + { WCD934X_CODEC_CPR_MAX_SVS2_STEP, 0x08 }, + { WCD934X_CODEC_CPR_CTL, 0x00 }, + { WCD934X_CODEC_CPR_SW_MODECHNG_STATUS, 0x00 }, + { WCD934X_CODEC_CPR_SW_MODECHNG_START, 0x00 }, + { WCD934X_CODEC_CPR_CPR_STATUS, 0x00 }, + { WCD934X_PAGE128_PAGE_REGISTER, 0x00 }, + { WCD934X_TLMM_BIST_MODE_PINCFG, 0x00 }, + { WCD934X_TLMM_RF_PA_ON_PINCFG, 0x00 }, + { WCD934X_TLMM_INTR1_PINCFG, 0x00 }, + { WCD934X_TLMM_INTR2_PINCFG, 0x00 }, + { WCD934X_TLMM_SWR_DATA_PINCFG, 0x00 }, + { WCD934X_TLMM_SWR_CLK_PINCFG, 0x00 }, + { WCD934X_TLMM_I2S_2_SCK_PINCFG, 0x00 }, + { WCD934X_TLMM_SLIMBUS_DATA1_PINCFG, 0x00 }, + { WCD934X_TLMM_SLIMBUS_DATA2_PINCFG, 0x00 }, + { WCD934X_TLMM_SLIMBUS_CLK_PINCFG, 0x00 }, + { WCD934X_TLMM_I2C_CLK_PINCFG, 0x00 }, + { WCD934X_TLMM_I2C_DATA_PINCFG, 0x00 }, + { WCD934X_TLMM_I2S_0_RX_PINCFG, 0x00 }, + { WCD934X_TLMM_I2S_0_TX_PINCFG, 0x00 }, + { WCD934X_TLMM_I2S_0_SCK_PINCFG, 0x00 }, + { WCD934X_TLMM_I2S_0_WS_PINCFG, 0x00 }, + { WCD934X_TLMM_I2S_1_RX_PINCFG, 0x00 }, + { WCD934X_TLMM_I2S_1_TX_PINCFG, 0x00 }, + { WCD934X_TLMM_I2S_1_SCK_PINCFG, 0x00 }, + { WCD934X_TLMM_I2S_1_WS_PINCFG, 0x00 }, + { WCD934X_TLMM_DMIC1_CLK_PINCFG, 0x00 }, + { WCD934X_TLMM_DMIC1_DATA_PINCFG, 0x00 }, + { WCD934X_TLMM_DMIC2_CLK_PINCFG, 0x00 }, + { WCD934X_TLMM_DMIC2_DATA_PINCFG, 0x00 }, + { WCD934X_TLMM_DMIC3_CLK_PINCFG, 0x00 }, + { WCD934X_TLMM_DMIC3_DATA_PINCFG, 0x00 }, + { WCD934X_TLMM_JTCK_PINCFG, 0x00 }, + { WCD934X_TLMM_GPIO1_PINCFG, 0x00 }, + { WCD934X_TLMM_GPIO2_PINCFG, 0x00 }, + { WCD934X_TLMM_GPIO3_PINCFG, 0x00 }, + { WCD934X_TLMM_GPIO4_PINCFG, 0x00 }, + { WCD934X_TLMM_SPI_S_CSN_PINCFG, 0x00 }, + { WCD934X_TLMM_SPI_S_CLK_PINCFG, 0x00 }, + { WCD934X_TLMM_SPI_S_DOUT_PINCFG, 0x00 }, + { WCD934X_TLMM_SPI_S_DIN_PINCFG, 0x00 }, + { WCD934X_TLMM_BA_N_PINCFG, 0x00 }, + { WCD934X_TLMM_GPIO0_PINCFG, 0x00 }, + { WCD934X_TLMM_I2S_2_RX_PINCFG, 0x00 }, + { WCD934X_TLMM_I2S_2_WS_PINCFG, 0x00 }, + { WCD934X_TEST_DEBUG_PIN_CTL_OE_0, 0x00 }, + { WCD934X_TEST_DEBUG_PIN_CTL_OE_1, 0x00 }, + { WCD934X_TEST_DEBUG_PIN_CTL_OE_2, 0x00 }, + { WCD934X_TEST_DEBUG_PIN_CTL_OE_3, 0x00 }, + { WCD934X_TEST_DEBUG_PIN_CTL_OE_4, 0x00 }, + { WCD934X_TEST_DEBUG_PIN_CTL_DATA_0, 0x00 }, + { WCD934X_TEST_DEBUG_PIN_CTL_DATA_1, 0x00 }, + { WCD934X_TEST_DEBUG_PIN_CTL_DATA_2, 0x00 }, + { WCD934X_TEST_DEBUG_PIN_CTL_DATA_3, 0x00 }, + { WCD934X_TEST_DEBUG_PIN_CTL_DATA_4, 0x00 }, + { WCD934X_TEST_DEBUG_PAD_DRVCTL_0, 0x00 }, + { WCD934X_TEST_DEBUG_PAD_DRVCTL_1, 0x00 }, + { WCD934X_TEST_DEBUG_PIN_STATUS, 0x00 }, + { WCD934X_TEST_DEBUG_NPL_DLY_TEST_1, 0x10 }, + { WCD934X_TEST_DEBUG_NPL_DLY_TEST_2, 0x60 }, + { WCD934X_TEST_DEBUG_MEM_CTRL, 0x00 }, + { WCD934X_TEST_DEBUG_DEBUG_BUS_SEL, 0x00 }, + { WCD934X_TEST_DEBUG_DEBUG_JTAG, 0x00 }, + { WCD934X_TEST_DEBUG_DEBUG_EN_1, 0x00 }, + { WCD934X_TEST_DEBUG_DEBUG_EN_2, 0x00 }, + { WCD934X_TEST_DEBUG_DEBUG_EN_3, 0x00 }, + { WCD934X_TEST_DEBUG_DEBUG_EN_4, 0x00 }, + { WCD934X_TEST_DEBUG_DEBUG_EN_5, 0x00 }, + { WCD934X_TEST_DEBUG_ANA_DTEST_DIR, 0x00 }, + { WCD934X_TEST_DEBUG_PAD_INP_DISABLE_0, 0x00 }, + { WCD934X_TEST_DEBUG_PAD_INP_DISABLE_1, 0x00 }, + { WCD934X_TEST_DEBUG_PAD_INP_DISABLE_2, 0x00 }, + { WCD934X_TEST_DEBUG_PAD_INP_DISABLE_3, 0x00 }, + { WCD934X_TEST_DEBUG_PAD_INP_DISABLE_4, 0x00 }, + { WCD934X_TEST_DEBUG_SYSMEM_CTRL, 0x00 }, + { WCD934X_TEST_DEBUG_SOC_SW_PWR_SEQ_DELAY, 0x00 }, + { WCD934X_TEST_DEBUG_LVAL_NOM_LOW, 0x96 }, + { WCD934X_TEST_DEBUG_LVAL_NOM_HIGH, 0x00 }, + { WCD934X_TEST_DEBUG_LVAL_SVS_SVS2_LOW, 0x53 }, + { WCD934X_TEST_DEBUG_LVAL_SVS_SVS2_HIGH, 0x00 }, + { WCD934X_TEST_DEBUG_SPI_SLAVE_CHAR, 0x00 }, + { WCD934X_TEST_DEBUG_CODEC_DIAGS, 0x00 }, +}; + +static bool wcd934x_is_readable_register(struct device *dev, unsigned int reg) +{ + u8 pg_num, reg_offset; + const u8 *reg_tbl = NULL; + + /* + * Get the page number from MSB of codec register. If its 0x80, assign + * the corresponding page index PAGE_0x80. + */ + pg_num = reg >> 0x8; + if (pg_num == 0x80) + pg_num = WCD934X_PAGE_0X80; + else if (pg_num > 0xF) + return false; + + reg_tbl = wcd934x_reg[pg_num]; + reg_offset = reg & 0xFF; + + if (reg_tbl && reg_tbl[reg_offset]) + return true; + else + return false; +} + +static bool wcd934x_is_volatile_register(struct device *dev, unsigned int reg) +{ + u8 pg_num, reg_offset; + const u8 *reg_tbl = NULL; + + pg_num = reg >> 0x8; + if (pg_num == 0x80) + pg_num = WCD934X_PAGE_0X80; + else if (pg_num > 0xF) + return false; + + reg_tbl = wcd934x_reg[pg_num]; + reg_offset = reg & 0xFF; + + if (reg_tbl && reg_tbl[reg_offset] == WCD934X_READ) + return true; + + return false; +} + +struct regmap_config wcd934x_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wcd934x_defaults, + .num_reg_defaults = ARRAY_SIZE(wcd934x_defaults), + .max_register = WCD934X_MAX_REGISTER, + .volatile_reg = wcd934x_is_volatile_register, + .readable_reg = wcd934x_is_readable_register, + .can_multi_write = true, +}; diff --git a/drivers/mfd/wcd934x-tables.c b/drivers/mfd/wcd934x-tables.c new file mode 100644 index 000000000000..ab5d18cd8493 --- /dev/null +++ b/drivers/mfd/wcd934x-tables.c @@ -0,0 +1,2120 @@ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/types.h> +#include <linux/mfd/wcd934x/registers.h> + +#define WCD934X_REG(reg) ((reg) & 0xFF) + +const u8 wcd934x_page0_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE0_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_RPM_CLK_BYPASS)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_RPM_CLK_GATE)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_RPM_CLK_MCLK_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_RPM_CLK_MCLK2_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_RPM_I2S_DSD_CLK_SEL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_RPM_RST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_TEST0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_TEST1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT4)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT5)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT6)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT7)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT8)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT9)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT10)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT11)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT12)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT13)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT14)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT15)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_EFUSE_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_NONNEGO)] = + WCD934X_READ, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_ANA_WAIT_STATE_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_SLNQ_WAIT_STATE_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_I2C_ACTIVE)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_ALT_FUNC_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_GPIO_CTL_OE)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CHIP_TIER_CTRL_GPIO_CTL_DATA)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_RX0_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_RX1_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_RX2_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_RX3_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_RX4_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_RX5_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_RX6_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_RX7_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX0_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX1_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX2_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX3_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX4_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX5_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX6_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX7_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX8_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX9_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX10_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX11_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX13_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX14_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_SB_TX15_INP_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_I2S_TX0_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_I2S_TX1_0_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_I2S_TX1_1_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_I2S_0_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_I2S_1_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_I2S_2_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_I2S_3_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_I2S_CLKSRC_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_I2S_COMMON_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_I2S_0_TDM_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DATA_HUB_I2S_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_DMA_RDMA_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_RDMA_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_RDMA_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_RDMA_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_RDMA_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_RDMA_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_RDMA_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_RDMA_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_RDMA_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_RDMA_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_RDMA_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_RDMA_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_RDMA_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_RDMA_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_RDMA_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_RDMA4_PRT_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_RDMA_SBTX0_7_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_RDMA_SBTX8_11_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_WDMA_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_4_5_CFG_WDMA_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_WDMA_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_WDMA_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_WDMA_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_4_5_CFG_WDMA_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_WDMA_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_WDMA_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_WDMA_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_4_5_CFG_WDMA_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_WDMA_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_WDMA_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_WDMA_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_4_5_CFG_WDMA_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_WDMA_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_WDMA_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_WDMA_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_4_5_CFG_WDMA_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_2_3_CFG_WDMA_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_CH_0_1_CFG_WDMA_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_WDMA0_PRT_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_WDMA3_PRT_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_WDMA4_PRT0_3_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DMA_WDMA4_PRT4_7_CFG)] = WCD934X_READ_WRITE, +}; + +const u8 wcd934x_page1_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE1_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_8)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_USER_CTL_9)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_L_VAL_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_L_VAL_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_DSM_FRAC_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_DSM_FRAC_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_CONFIG_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_CONFIG_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_CONFIG_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_CONFIG_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_CONFIG_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_TEST_CTL_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_FREQ_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_FREQ_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_FREQ_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_FREQ_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_SSC_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_SSC_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_SSC_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_SSC_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_FLL_MODE)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_FLL_STATUS_0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CPE_FLL_STATUS_1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CPE_FLL_STATUS_2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CPE_FLL_STATUS_3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_8)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_USER_CTL_9)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_L_VAL_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_L_VAL_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_DSM_FRAC_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_DSM_FRAC_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_CONFIG_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_CONFIG_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_CONFIG_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_CONFIG_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_CONFIG_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_TEST_CTL_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_FREQ_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_FREQ_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_FREQ_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_FREQ_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_SSC_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_SSC_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_SSC_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_SSC_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_FLL_MODE)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_I2S_FLL_STATUS_0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_I2S_FLL_STATUS_1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_I2S_FLL_STATUS_2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_I2S_FLL_STATUS_3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SB_FLL_USER_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_USER_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_USER_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_USER_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_USER_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_USER_CTL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_USER_CTL_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_USER_CTL_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_USER_CTL_8)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_USER_CTL_9)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_L_VAL_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_L_VAL_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_DSM_FRAC_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_DSM_FRAC_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_CONFIG_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_CONFIG_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_CONFIG_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_CONFIG_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_CONFIG_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_TEST_CTL_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_FREQ_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_FREQ_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_FREQ_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_FREQ_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_SSC_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_SSC_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_SSC_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_SSC_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_FLL_MODE)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SB_FLL_STATUS_0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SB_FLL_STATUS_1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SB_FLL_STATUS_2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SB_FLL_STATUS_3)] = WCD934X_READ, +}; + +const u8 wcd934x_page2_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE2_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_CPE_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_CPEFLL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_OVERRIDE)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_PWR_CPE_DRAM1_SHUTDOWN)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SOC_SW_COLLAPSE_OVERRIDE_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SOC_SW_COLLAPSE_OVERRIDE_CTL1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_US_BUF_INT_PERIOD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SVA_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_US_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_MAD_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_CPAR_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_DMIC0_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_DMIC1_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_DMIC2_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_DMIC_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_CPAR_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_WDOG_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_BACKUP_INT)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_STATUS)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_CPE_OCD_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_MASK_0A)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_MASK_0B)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_MASK_1A)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_MASK_1B)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0A)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0B)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_STATUS_1A)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_STATUS_1B)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_0A)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_0B)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_1A)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_1B)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_MAIN_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_MAIN_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_AUDIO_CTL_8)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_AUDIO_IIR_CTL_PTR)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_AUDIO_IIR_CTL_VAL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_ULTR_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_ULTR_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_ULTR_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_ULTR_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_ULTR_CTL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_ULTR_CTL_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_ULTR_CTL_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_BEACON_CTL_8)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_BEACON_IIR_CTL_PTR)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_BEACON_IIR_CTL_VAL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SOC_MAD_INP_SEL)] = WCD934X_READ_WRITE, +}; + +const u8 wcd934x_page4_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE4_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_CLR_COMMIT)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_INTR_PIN1_MASK0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_PIN1_MASK1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_PIN1_MASK2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_PIN1_MASK3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_PIN1_STATUS0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_INTR_PIN1_STATUS1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_INTR_PIN1_STATUS2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_INTR_PIN1_STATUS3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_INTR_PIN1_CLEAR0)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_INTR_PIN1_CLEAR1)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_INTR_PIN1_CLEAR2)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_INTR_PIN1_CLEAR3)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_INTR_PIN2_MASK3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_PIN2_STATUS3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_INTR_PIN2_CLEAR3)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_INTR_CPESS_SUMRY_MASK2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_CPESS_SUMRY_MASK3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_CPESS_SUMRY_STATUS2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_INTR_CPESS_SUMRY_STATUS3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_INTR_CPESS_SUMRY_CLEAR2)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_INTR_CPESS_SUMRY_CLEAR3)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_INTR_LEVEL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_LEVEL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_LEVEL2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_LEVEL3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_BYPASS0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_BYPASS1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_BYPASS2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_BYPASS3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_SET0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_SET1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_SET2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_SET3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_CODEC_MISC_MASK)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_INTR_CODEC_MISC_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_INTR_CODEC_MISC_CLEAR)] = WCD934X_WRITE, +}; + +const u8 wcd934x_page5_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE5_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_DEVICE)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_REVISION)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_H_COMMAND)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_NUMBER_OF_BYTE_MSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_NUMBER_OF_BYTE_LSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_MASTER_ADDRESS_MSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_MASTER_ADDRESS_LSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SLAVE_ADDRESS_MSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SLAVE_ADDRESS_LSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_TIMER0_INTERRUPT_MSB)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_TIMER0_INTERRUPT_LSB)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_TIMER1_INTERRUPT_MSB)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_TIMER1_INTERRUPT_LSB)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_TIMER2_INTERRUPT_MSB)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_TIMER2_INTERRUPT_LSB)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_COMM_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_FRAME_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_2ND_DATA_CH1_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_2ND_DATA_CH3_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_2ND_DATA_CH5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SW_EVENT_RD)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_SW_EVENT_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_SELECT_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_SELECT_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_SELECT_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_SAMPLING_FREQ)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_DC_CONVERSION_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_DC_CONVERSION_SEL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_DC_CONV_CHA_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_DC_CONV_CHA_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_DC_CONV_CHB_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_DC_CONV_CHB_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_RAM_CNTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BANK)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_8)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_9)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_A)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_B)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_C)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_D)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_E)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_F)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_10)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_11)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_12)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_13)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_14)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_15)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_16)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_17)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_18)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_19)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_1A)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_1B)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_1C)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_1D)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_1E)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_1F)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_20)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_21)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_22)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_23)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_24)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_25)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_26)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_27)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_28)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_29)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_2A)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_2B)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_2C)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_2D)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_2E)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_2F)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_30)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_31)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_32)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_33)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_34)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_35)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_36)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_37)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_38)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_39)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_3A)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_3B)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_3C)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_3D)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_3E)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_SRAM_BYTE_3F)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_TOP_CTRL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_TOP_CTRL2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_PDM_MUTE_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_DEC_BYPASS_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_DEC_BYPASS_STATUS)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_DEC_BYPASS_FS)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_DEC_BYPASS_IN_SEL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_GPOUT_ENABLE)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_GPOUT_VAL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_ANA_INTERRUPT_MASK)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_ANA_INTERRUPT_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_ANA_INTERRUPT_CLR)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_IP_TESTING)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CNTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CNT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CNT_MSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CNT_LSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_MASK0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_MASK1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_MASK2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_MASK3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_MASK4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_STATUS0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_STATUS1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_STATUS2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_STATUS3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_STATUS4)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CLR0)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CLR1)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CLR2)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CLR3)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_SLNQ_DIG_INTERRUPT_CLR4)] = WCD934X_WRITE, +}; + +const u8 wcd934x_page6_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_ANA_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_BIAS)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_RCO)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_PAGE6_SPARE2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_PAGE6_SPARE3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_BUCK_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_BUCK_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_ANA_RX_SUPPLIES)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_HPH)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_EAR)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_LO_1_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MAD_SETUP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_AMIC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_AMIC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_AMIC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_AMIC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MBHC_MECH)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MBHC_ELECT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MBHC_ZDET)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MBHC_RESULT_1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_ANA_MBHC_RESULT_2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_ANA_MBHC_RESULT_3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_ANA_MBHC_BTN0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MBHC_BTN1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MBHC_BTN2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MBHC_BTN3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MBHC_BTN4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MBHC_BTN5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MBHC_BTN6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MBHC_BTN7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MICB1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MICB2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MICB2_RAMP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MICB3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_MICB4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_ANA_VBADC)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BIAS_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BIAS_VBG_FINE_ADJ)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RCO_CTRL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RCO_CTRL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RCO_CAL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RCO_CAL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RCO_CAL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RCO_TEST_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RCO_CAL_OUT_1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_RCO_CAL_OUT_2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_RCO_CAL_OUT_3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_RCO_CAL_OUT_4)] = WCD934X_READ, + [WCD934X_REG(WCD934X_RCO_CAL_OUT_5)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SIDO_MODE_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_MODE_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_MODE_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_MODE_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_VCL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_VCL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_VCL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CCL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CCL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CCL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CCL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CCL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CCL_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CCL_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CCL_8)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CCL_9)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CCL_10)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_FILTER_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_FILTER_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_DRIVER_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_DRIVER_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_DRIVER_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CAL_CODE_EXT_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CAL_CODE_EXT_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_CAL_CODE_OUT_1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SIDO_CAL_CODE_OUT_2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SIDO_TEST_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_TEST_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_CTL_CLK)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_CTL_ANA)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_CTL_SPARE_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_CTL_SPARE_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_CTL_BCS)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_STATUS_SPARE_1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MBHC_TEST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_VBADC_SUBBLOCK_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_VBADC_IBIAS_FE)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_VBADC_BIAS_ADC)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_VBADC_FE_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_VBADC_ADC_REF)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_VBADC_ADC_IO)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_VBADC_ADC_SAR)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_VBADC_DEBUG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_LDOH_MODE)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_LDOH_BIAS)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_LDOH_STB_LOADS)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_LDOH_SLOWRAMP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB1_TEST_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB1_TEST_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB1_TEST_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB2_TEST_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB2_TEST_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB2_TEST_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB3_TEST_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB3_TEST_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB3_TEST_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB4_TEST_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB4_TEST_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MICB4_TEST_CTL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_COM_ADC_VCM)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_COM_BIAS_ATEST)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_COM_ADC_INT1_IB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_COM_ADC_INT2_IB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_COM_TXFE_DIV_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_COM_TXFE_DIV_START)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_COM_TXFE_DIV_STOP_9P6M)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_COM_TXFE_DIV_STOP_12P288M)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_1_2_TEST_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_1_2_ADC_IB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_1_2_ATEST_REFCTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_1_2_TEST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_1_2_TEST_BLK_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_1_2_TXFE_CLKDIV)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_1_2_SAR1_ERR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_TX_1_2_SAR2_ERR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_TX_3_4_TEST_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_3_4_ADC_IB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_3_4_ATEST_REFCTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_3_4_TEST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_3_4_TEST_BLK_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_3_4_TXFE_CLKDIV)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TX_3_4_SAR1_ERR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_TX_3_4_SAR2_ERR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CLASSH_MODE_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_MODE_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_MODE_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_CTRL_VCL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_CTRL_VCL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_CTRL_CCL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_CTRL_CCL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_CTRL_CCL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_CTRL_CCL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_CTRL_CCL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_BUCK_TMUX_A_D)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_BUCK_SW_DRV_CNTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLASSH_SPARE)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_8)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEG_CTRL_9)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEGDAC_CTRL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEGDAC_CTRL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_VNEGDAC_CTRL_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_CTRL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_FLYBACK_TEST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_AUX_SW_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_PA_AUX_IN_CONN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_TIMER_DIV)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_OCP_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_OCP_COUNT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_EAR_DAC)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_EAR_AMP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_HPH_LDO)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_HPH_PA)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_HPH_RDACBUFF_CNP2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_HPH_RDAC_LDO)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_HPH_CNP1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_HPH_LOWPOWER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_DIFFLO_PA)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_DIFFLO_REF)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_DIFFLO_LDO)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_SELO_DAC_PA)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_BUCK_RST)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_BUCK_VREF_ERRAMP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_FLYB_ERRAMP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_FLYB_BUFF)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_BIAS_FLYB_MID_RST)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_L_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_HPH_R_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_HPH_CNP_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_CNP_WG_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_CNP_WG_TIME)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_OCP_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_AUTO_CHOP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_CHOP_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_PA_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_PA_CTL2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_L_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_L_TEST)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_L_ATEST)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_R_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_R_TEST)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_R_ATEST)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_RDAC_CLK_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_RDAC_CLK_CTL2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_RDAC_LDO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_RDAC_CHOP_CLK_LP_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_REFBUFF_UHQA_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_REFBUFF_LP_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_L_DAC_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_R_DAC_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EAR_EN_REG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EAR_CMBUFF)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EAR_ICTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EAR_EN_DBG_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EAR_CNP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EAR_DAC_CTL_ATEST)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EAR_STATUS_REG)] = WCD934X_READ, + [WCD934X_REG(WCD934X_EAR_EAR_MISC)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_MISC)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_LO2_COMPANDER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_LO1_COMPANDER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_COMMON)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_BYPASS_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_CNP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_CORE_OUT_PROG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_LDO_OUT_PROG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_COM_SWCAP_REFBUF_FREQ)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_COM_PA_FREQ)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_RESERVED_REG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_DIFF_LO_LO1_STATUS_1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_DIFF_LO_LO1_STATUS_2)] = WCD934X_READ, +}; + +const u8 wcd934x_page7_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_ANA_NEW_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_ANA_HPH2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_ANA_HPH3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_ANA_EN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_ANA_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_ANA_LDO_CONFIG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_ANA_LDO_OCP_CONFIG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_ANA_TX_LDO_CONFIG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_ANA_TX_DRV_CONFIG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_ANA_RX_CONFIG_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_ANA_RX_CONFIG_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_ANA_PLL_ENABLES)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_ANA_PLL_PRESET)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_ANA_PLL_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CLK_SYS_PLL_ENABLES)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_PLL_PRESET)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_PLL_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CLK_SYS_MCLK_PRG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_MCLK2_PRG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_MCLK2_PRG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_XO_PRG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_XO_CAP_XTP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_XO_CAP_XTM)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_BST_EN_DLY)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_CTRL_ILIM)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_VOUT_SETTING)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_VOUT_A_STARTUP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_VOUT_D_STARTUP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_VOUT_D_FREQ1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_VOUT_D_FREQ2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_NEW_ELECT_REM_CLAMP_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_NEW_CTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_NEW_CTL_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_NEW_PLUG_DETECT_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_NEW_ZDET_ANA_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_NEW_ZDET_RAMP_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_NEW_FSM_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MBHC_NEW_ADC_RESULT)] = WCD934X_READ, + [WCD934X_REG(WCD934X_TX_NEW_AMIC_4_5_SEL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_VBADC_NEW_ADC_MODE)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_VBADC_NEW_ADC_DOUTMSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_VBADC_NEW_ADC_DOUTLSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_RDAC_HD2_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_RDAC_VREF_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_RDAC_OVERRIDE_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_RDAC_MISC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_PA_MISC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_PA_MISC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_PA_RDAC_MISC)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_HPH_TIMER1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_HPH_TIMER2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_HPH_TIMER3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_HPH_TIMER4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_PA_RDAC_MISC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_HPH_NEW_INT_PA_RDAC_MISC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_NEW_INT_HPH_RDAC_BIAS_ULP)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_RX_NEW_INT_HPH_RDAC_LDO_LP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_LDO_TEST)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_LDO_DEBUG_1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_LDO_DEBUG_2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_TX_LDO_TEST)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_TX_DRV_TEST)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_RX_TEST)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_RX_TEST_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_RX_DEBUG_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_RX_DEBUG_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_CLK_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_RESERVED_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_RESERVED_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_POST_DIV_REG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_POST_DIV_REG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_REF_DIV_REG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_REF_DIV_REG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_FILTER_REG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_FILTER_REG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_L_VAL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_M_VAL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_N_VAL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_TEST_REG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_PFD_CP_DSM_PROG)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_VCO_PROG)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_TEST_REG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_LDO_LOCK_CFG)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SLNQ_INT_ANA_INT_PLL_DIG_LOCK_DET_CFG)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_POST_DIV_REG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_POST_DIV_REG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_REF_DIV_REG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_REF_DIV_REG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_FILTER_REG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_FILTER_REG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_PLL_L_VAL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_PLL_M_VAL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_PLL_N_VAL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_TEST_REG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_PFD_CP_DSM_PROG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_VCO_PROG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_TEST_REG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_LDO_LOCK_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_DIG_LOCK_DET_CFG)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_CLK_TEST1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_CLK_TEST2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_CLK_TEST3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_XO_TEST1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CLK_SYS_INT_XO_TEST2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_INT_VCOMP_HYST)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_INT_VLOOP_FILTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_INT_CTRL_IDELTA)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_INT_CTRL_ILIM_STARTUP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_INT_CTRL_MIN_ONTIME)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_INT_CTRL_MAX_ONTIME)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_INT_CTRL_TIMING)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_INT_TMUX_A_D)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_INT_SW_DRV_CNTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_INT_SPARE1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_BOOST_INT_SPARE2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_RAMP_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_SPARE_1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_DEBUG_VOUT_SETTING_A)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_DEBUG_VOUT_SETTING_D)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_RAMP_INC_WAIT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_RAMP_IBLEED_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_DEBUG_CPROVR_TEST)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_RAMP_CTL_A)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_RAMP_CTL_D)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_RAMP_TIMEOUT_PERIOD)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_SETTING1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_SETTING2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_SETTING3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_HIGH_ACCU_MODE_SEL1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDO_NEW_INT_HIGH_ACCU_MODE_SEL2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_NEW_INT_SLNQ_HPF)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_NEW_INT_SLNQ_REF)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_NEW_INT_SLNQ_COMP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MBHC_NEW_INT_SPARE_2)] = WCD934X_READ_WRITE, + +}; + +const u8 wcd934x_page10_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE10_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_CLK_RESET_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_MODE_1_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_MODE_2_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_FF_SHIFT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_FB_SHIFT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_LPF_FF_A_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_LPF_FF_B_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_LPF_FB_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_SMLPF_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_DCFLT_SHIFT_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_IIR_ADAPT_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_IIR_COEFF_1_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_IIR_COEFF_2_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_FF_A_GAIN_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_FF_B_GAIN_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_FB_GAIN_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_RC_COMMON_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_FIFO_COMMON_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC0_RC0_STATUS_FMIN_CNTR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_ANC0_RC1_STATUS_FMIN_CNTR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_ANC0_RC0_STATUS_FMAX_CNTR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_ANC0_RC1_STATUS_FMAX_CNTR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_ANC0_STATUS_FIFO)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_ANC1_CLK_RESET_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_MODE_1_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_MODE_2_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_FF_SHIFT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_FB_SHIFT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_LPF_FF_A_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_LPF_FF_B_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_LPF_FB_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_SMLPF_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_DCFLT_SHIFT_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_IIR_ADAPT_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_IIR_COEFF_1_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_IIR_COEFF_2_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_FF_A_GAIN_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_FF_B_GAIN_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_FB_GAIN_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_RC_COMMON_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_FIFO_COMMON_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_ANC1_RC0_STATUS_FMIN_CNTR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_ANC1_RC1_STATUS_FMIN_CNTR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_ANC1_RC0_STATUS_FMAX_CNTR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_ANC1_RC1_STATUS_FMAX_CNTR)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_ANC1_STATUS_FIFO)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_192_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_192_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX0_TX_PATH_SEC7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_192_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_192_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_SEC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX1_TX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_192_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_192_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_SEC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX2_TX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_192_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_192_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_SEC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX3_TX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_192_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_192_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_SEC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX4_TX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_192_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_192_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_SEC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX5_TX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_192_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_192_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_SEC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX6_TX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_192_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_192_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_SEC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX7_TX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_192_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_192_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_SEC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX8_TX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX9_SPKR_PROT_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX10_SPKR_PROT_PATH_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX11_SPKR_PROT_PATH_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX12_SPKR_PROT_PATH_CFG0)] = + WCD934X_READ_WRITE, +}; + +const u8 wcd934x_page11_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE11_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL6)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_COMPANDER1_CTL7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL6)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_COMPANDER2_CTL7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL6)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_COMPANDER3_CTL7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL6)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_COMPANDER4_CTL7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL6)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_COMPANDER7_CTL7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL6)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_COMPANDER8_CTL7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_MIX_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_VOL_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_SEC7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_MIX_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_MIX_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX0_RX_PATH_DSMDEM_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_MIX_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_VOL_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_SEC7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_MIX_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_MIX_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX1_RX_PATH_DSMDEM_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_MIX_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_VOL_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_SEC7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_MIX_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_MIX_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX2_RX_PATH_DSMDEM_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_MIX_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_VOL_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_SEC7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_MIX_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_MIX_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX3_RX_PATH_DSMDEM_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_MIX_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_VOL_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_SEC7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_MIX_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_MIX_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX4_RX_PATH_DSMDEM_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_MIX_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_VOL_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_SEC7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_MIX_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_MIX_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX7_RX_PATH_DSMDEM_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_VOL_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_MIX_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_VOL_MIX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_SEC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_SEC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_SEC5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_SEC6)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_SEC7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_MIX_SEC0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_MIX_SEC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX8_RX_PATH_DSMDEM_CTL)] = WCD934X_READ_WRITE, +}; + +const u8 wcd934x_page12_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE12_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_CRC)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_DLY_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_DECAY_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_HPH_V_PA)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_EAR_V_PA)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_HPH_V_HD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_EAR_V_HD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_K1_MSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_K1_LSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_K2_MSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_K2_LSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_IDLE_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_IDLE_HPH)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_IDLE_EAR)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_TEST0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_TEST1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLSH_OVR_VREF)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_BOOST0_BOOST_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_BOOST0_BOOST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_BOOST0_BOOST_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_BOOST0_BOOST_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_BOOST1_BOOST_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_BOOST1_BOOST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_BOOST1_BOOST_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_BOOST1_BOOST_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_ADC_CAL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_ADC_CAL2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_ADC_CAL3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_PK_EST1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_PK_EST2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_PK_EST3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_RF_PROC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_RF_PROC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_TAC1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_TAC2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_TAC3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_TAC4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_GAIN_UPD1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_GAIN_UPD2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_GAIN_UPD3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_GAIN_UPD4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_DEBUG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_GAIN_UPD_MON)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_GAIN_MON_VAL)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_VBAT_VBAT_BAN)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC0_CLK_RST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC0_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC0_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC0_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC0_STATUS_FMIN_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC0_STATUS_FMIN_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC0_STATUS_FMAX_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC0_STATUS_FMAX_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC0_STATUS_FIFO)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC1_CLK_RST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC1_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC1_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC1_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC1_STATUS_FMIN_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC1_STATUS_FMIN_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC1_STATUS_FMAX_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC1_STATUS_FMAX_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC1_STATUS_FIFO)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC2_CLK_RST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC2_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC2_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC2_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC2_STATUS_FMIN_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC2_STATUS_FMIN_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC2_STATUS_FMAX_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC2_STATUS_FMAX_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC2_STATUS_FIFO)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC3_CLK_RST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC3_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC3_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC3_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_MIXING_ASRC3_STATUS_FMIN_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC3_STATUS_FMIN_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC3_STATUS_FMAX_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC3_STATUS_FMAX_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_MIXING_ASRC3_STATUS_FIFO)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_DATA_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_DATA_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_DATA_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_DATA_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_ADDR_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_ADDR_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_ADDR_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_WR_ADDR_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_ADDR_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_ADDR_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_ADDR_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_ADDR_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_DATA_0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_DATA_1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_DATA_2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_RD_DATA_3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_ACCESS_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SWR_AHB_BRIDGE_ACCESS_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_SRC0_ST_SRC_PATH_CFG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_SRC1_ST_SRC_PATH_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_SRC1_ST_SRC_PATH_CFG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDETONE_ASRC0_CLK_RST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDETONE_ASRC0_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDETONE_ASRC0_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDETONE_ASRC0_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDETONE_ASRC0_STATUS_FMIN_CNTR_LSB)] = + WCD934X_READ, + [WCD934X_REG(WCD934X_SIDETONE_ASRC0_STATUS_FMIN_CNTR_MSB)] = + WCD934X_READ, + [WCD934X_REG(WCD934X_SIDETONE_ASRC0_STATUS_FMAX_CNTR_LSB)] = + WCD934X_READ, + [WCD934X_REG(WCD934X_SIDETONE_ASRC0_STATUS_FMAX_CNTR_MSB)] = + WCD934X_READ, + [WCD934X_REG(WCD934X_SIDETONE_ASRC0_STATUS_FIFO)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SIDETONE_ASRC1_CLK_RST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDETONE_ASRC1_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDETONE_ASRC1_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDETONE_ASRC1_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SIDETONE_ASRC1_STATUS_FMIN_CNTR_LSB)] = + WCD934X_READ, + [WCD934X_REG(WCD934X_SIDETONE_ASRC1_STATUS_FMIN_CNTR_MSB)] = + WCD934X_READ, + [WCD934X_REG(WCD934X_SIDETONE_ASRC1_STATUS_FMAX_CNTR_LSB)] = + WCD934X_READ, + [WCD934X_REG(WCD934X_SIDETONE_ASRC1_STATUS_FMAX_CNTR_MSB)] = + WCD934X_READ, + [WCD934X_REG(WCD934X_SIDETONE_ASRC1_STATUS_FIFO)] = WCD934X_READ, + [WCD934X_REG(WCD934X_EC_REF_HQ0_EC_REF_HQ_PATH_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_REF_HQ0_EC_REF_HQ_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_REF_HQ1_EC_REF_HQ_PATH_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_REF_HQ1_EC_REF_HQ_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_ASRC0_CLK_RST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_ASRC0_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_ASRC0_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_ASRC0_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_ASRC0_STATUS_FMIN_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_EC_ASRC0_STATUS_FMIN_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_EC_ASRC0_STATUS_FMAX_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_EC_ASRC0_STATUS_FMAX_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_EC_ASRC0_STATUS_FIFO)] = WCD934X_READ, + [WCD934X_REG(WCD934X_EC_ASRC1_CLK_RST_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_ASRC1_CTL0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_ASRC1_CTL1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_ASRC1_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_EC_ASRC1_STATUS_FMIN_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_EC_ASRC1_STATUS_FMIN_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_EC_ASRC1_STATUS_FMAX_CNTR_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_EC_ASRC1_STATUS_FMAX_CNTR_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_EC_ASRC1_STATUS_FIFO)] = WCD934X_READ, +}; + +const u8 wcd934x_page13_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE13_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_ANC_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_SPLINE_ASRC_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_INP_MUX_EC_REF_HQ_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX5_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX6_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX7_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX8_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX10_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX11_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX12_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TX_INP_MUX_ADC_MUX13_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLK_RST_CTRL_MCLK_CONTROL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLK_RST_CTRL_SWR_CONTROL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLK_RST_CTRL_DSD_CONTROL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLK_RST_CTRL_ASRC_SHARE_CONTROL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_CLK_RST_CTRL_GFM_CONTROL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_POLL_PERIOD0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_POLL_PERIOD1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_SIG_PATTERN_LSB)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_SIG_PATTERN_MSB)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_TEST_CTRL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB_RD)] = + WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB_RD)] = + WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_PROX_DETECT_PROX_CTL_REPEAT_PAT)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_PATH_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B5_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B6_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B7_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B8_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_PATH_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B5_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B6_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B7_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B8_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_COEF_B1_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_SIDETONE_IIR1_IIR_COEF_B2_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_TOP_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_TOP_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_TOP_CFG7)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_HPHL_COMP_WR_LSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_HPHL_COMP_WR_MSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_HPHL_COMP_LUT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_HPHL_COMP_RD_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_TOP_HPHL_COMP_RD_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_TOP_HPHR_COMP_WR_LSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_HPHR_COMP_WR_MSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_HPHR_COMP_LUT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_HPHR_COMP_RD_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_TOP_HPHR_COMP_RD_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_TOP_DIFFL_COMP_WR_LSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_DIFFL_COMP_WR_MSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_DIFFL_COMP_LUT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_DIFFL_COMP_RD_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_TOP_DIFFL_COMP_RD_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_TOP_DIFFR_COMP_WR_LSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_DIFFR_COMP_WR_MSB)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_DIFFR_COMP_LUT)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_TOP_DIFFR_COMP_RD_LSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_TOP_DIFFR_COMP_RD_MSB)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_DSD0_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD0_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD0_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD0_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD0_CFG3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD0_CFG4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD0_CFG5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD1_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD1_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD1_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD1_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD1_CFG3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD1_CFG4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DSD1_CFG5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_IDLE_DET_PATH_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_IDLE_DET_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_IDLE_DET_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_IDLE_DET_CFG2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RX_IDLE_DET_CFG3)] = WCD934X_READ_WRITE, +}; + +const u8 wcd934x_page14_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE14_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_CLK_RST_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_PULSE_SUPR_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_TIMER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_BW_SW)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_THRESH)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_TIMER2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RMAX_DIAG)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RMIN_DIAG)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_PH_DET)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_DIAG_CLR)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_MB_SW_STATE)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_MAST_DIAG_STATE)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RATE_OUT_7_0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RATE_OUT_15_8)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RATE_OUT_23_16)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RATE_OUT_31_24)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RATE_OUT_39_32)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST0_RE_RATE_OUT_40_43)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_CLK_RST_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_PULSE_SUPR_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_TIMER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_BW_SW)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_THRESH)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_TIMER2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RMAX_DIAG)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RMIN_DIAG)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_PH_DET)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_DIAG_CLR)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_MB_SW_STATE)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_MAST_DIAG_STATE)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RATE_OUT_7_0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RATE_OUT_15_8)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RATE_OUT_23_16)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RATE_OUT_31_24)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RATE_OUT_39_32)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST1_RE_RATE_OUT_40_43)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_CLK_RST_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_PULSE_SUPR_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_TIMER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_BW_SW)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_THRESH)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_TIMER2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RMAX_DIAG)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RMIN_DIAG)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_PH_DET)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_DIAG_CLR)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_MB_SW_STATE)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_MAST_DIAG_STATE)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RATE_OUT_7_0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RATE_OUT_15_8)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RATE_OUT_23_16)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RATE_OUT_31_24)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RATE_OUT_39_32)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST2_RE_RATE_OUT_40_43)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_CLK_RST_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_PULSE_SUPR_CTL)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_TIMER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_BW_SW)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_THRESH)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_TIMER2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW5)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RMAX_DIAG)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RMIN_DIAG)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_PH_DET)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_DIAG_CLR)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_MB_SW_STATE)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_MAST_DIAG_STATE)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RATE_OUT_7_0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RATE_OUT_15_8)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RATE_OUT_23_16)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RATE_OUT_31_24)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RATE_OUT_39_32)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_RATE_EST3_RE_RATE_OUT_40_43)] = WCD934X_READ, +}; + +const u8 wcd934x_page15_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE15_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SPLINE_SRC0_CLK_RST_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SPLINE_SRC0_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SPLINE_SRC1_CLK_RST_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SPLINE_SRC1_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SPLINE_SRC2_CLK_RST_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SPLINE_SRC2_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_SPLINE_SRC3_CLK_RST_CTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_SPLINE_SRC3_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_SPLINE_SRC_DEBUG_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_SPLINE_SRC_DEBUG_CFG1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_RC_RE_ASRC_DEBUG_CFG0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_ANC0_RC0_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_ANC0_RC1_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_ANC1_RC0_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_ANC1_RC1_FIFO_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CDC_DEBUG_ANC_RC_RST_DBG_CNTR)] = + WCD934X_READ_WRITE, +}; + +const u8 wcd934x_page_0x80_reg_access[WCD934X_PAGE_SIZE] = { + [WCD934X_REG(WCD934X_PAGE80_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_DATA_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_DATA_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_DATA_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_DATA_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_ADDR_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_ADDR_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_ADDR_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_WR_ADDR_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_ADDR_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_ADDR_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_ADDR_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_ADDR_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_DATA_0)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_DATA_1)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_DATA_2)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CODEC_CPR_RD_DATA_3)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CODEC_CPR_ACCESS_CFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_ACCESS_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CODEC_CPR_NOM_CX_VDD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_SVS_CX_VDD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_SVS2_CX_VDD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_NOM_MX_VDD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_SVS_MX_VDD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_SVS2_MX_VDD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_SVS2_MIN_CX_VDD)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_MAX_SVS2_STEP)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_CTL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_SW_MODECHNG_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_CODEC_CPR_SW_MODECHNG_START)] = WCD934X_WRITE, + [WCD934X_REG(WCD934X_CODEC_CPR_CPR_STATUS)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_PAGE128_PAGE_REGISTER)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_BIST_MODE_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_RF_PA_ON_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_INTR1_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_INTR2_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_SWR_DATA_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_SWR_CLK_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2S_2_SCK_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_SLIMBUS_DATA1_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_SLIMBUS_DATA2_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_SLIMBUS_CLK_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2C_CLK_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2C_DATA_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2S_0_RX_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2S_0_TX_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2S_0_SCK_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2S_0_WS_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2S_1_RX_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2S_1_TX_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2S_1_SCK_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2S_1_WS_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_DMIC1_CLK_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_DMIC1_DATA_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_DMIC2_CLK_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_DMIC2_DATA_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_DMIC3_CLK_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_DMIC3_DATA_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_JTCK_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_GPIO1_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_GPIO2_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_GPIO3_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_GPIO4_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_SPI_S_CSN_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_SPI_S_CLK_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_SPI_S_DOUT_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_SPI_S_DIN_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_BA_N_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_GPIO0_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2S_2_RX_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TLMM_I2S_2_WS_PINCFG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_OE_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_OE_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_OE_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_OE_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_OE_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_DATA_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_DATA_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_DATA_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_DATA_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PIN_CTL_DATA_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PAD_DRVCTL_0)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PAD_DRVCTL_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PIN_STATUS)] = WCD934X_READ, + [WCD934X_REG(WCD934X_TEST_DEBUG_NPL_DLY_TEST_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_NPL_DLY_TEST_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_MEM_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_DEBUG_BUS_SEL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_DEBUG_JTAG)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_DEBUG_EN_1)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_DEBUG_EN_2)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_DEBUG_EN_3)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_DEBUG_EN_4)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_DEBUG_EN_5)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_ANA_DTEST_DIR)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PAD_INP_DISABLE_0)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PAD_INP_DISABLE_1)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PAD_INP_DISABLE_2)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PAD_INP_DISABLE_3)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_PAD_INP_DISABLE_4)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_SYSMEM_CTRL)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_SOC_SW_PWR_SEQ_DELAY)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_LVAL_NOM_LOW)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_LVAL_NOM_HIGH)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_LVAL_SVS_SVS2_LOW)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_LVAL_SVS_SVS2_HIGH)] = + WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_SPI_SLAVE_CHAR)] = WCD934X_READ_WRITE, + [WCD934X_REG(WCD934X_TEST_DEBUG_CODEC_DIAGS)] = WCD934X_READ, +}; + +const u8 * const wcd934x_reg[WCD934X_NUM_PAGES] = { + [WCD934X_PAGE_0] = wcd934x_page0_reg_access, + [WCD934X_PAGE_1] = wcd934x_page1_reg_access, + [WCD934X_PAGE_2] = wcd934x_page2_reg_access, + [WCD934X_PAGE_4] = wcd934x_page4_reg_access, + [WCD934X_PAGE_5] = wcd934x_page5_reg_access, + [WCD934X_PAGE_6] = wcd934x_page6_reg_access, + [WCD934X_PAGE_7] = wcd934x_page7_reg_access, + [WCD934X_PAGE_10] = wcd934x_page10_reg_access, + [WCD934X_PAGE_11] = wcd934x_page11_reg_access, + [WCD934X_PAGE_12] = wcd934x_page12_reg_access, + [WCD934X_PAGE_13] = wcd934x_page13_reg_access, + [WCD934X_PAGE_14] = wcd934x_page14_reg_access, + [WCD934X_PAGE_15] = wcd934x_page15_reg_access, + [WCD934X_PAGE_0X80] = wcd934x_page_0x80_reg_access, +}; diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c index 555fac10377f..31ac6624b8b4 100644 --- a/drivers/mfd/wcd9xxx-core.c +++ b/drivers/mfd/wcd9xxx-core.c @@ -87,6 +87,7 @@ static const int wcd9xxx_cdc_types[] = { [WCD9XXX] = WCD9XXX, [WCD9330] = WCD9330, [WCD9335] = WCD9335, + [WCD934X] = WCD934X, }; static const struct of_device_id wcd9xxx_of_match[] = { @@ -326,7 +327,7 @@ int wcd9xxx_slim_write_repeat(struct wcd9xxx *wcd9xxx, unsigned short reg, struct slim_ele_access slim_msg; mutex_lock(&wcd9xxx->io_lock); - if (wcd9xxx->type == WCD9335) { + if (wcd9xxx->type == WCD9335 || wcd9xxx->type == WCD934X) { ret = wcd9xxx_page_write(wcd9xxx, ®); if (ret) goto done; @@ -1321,7 +1322,7 @@ static int wcd9xxx_slim_probe(struct slim_device *slim) * Vout_D to be ready after BUCK_SIDO is powered up. * SYS_RST_N shouldn't be pulled high during this time */ - if (wcd9xxx->type == WCD9335) + if (wcd9xxx->type == WCD9335 || wcd9xxx->type == WCD934X) usleep_range(600, 650); else usleep_range(5, 10); @@ -1507,6 +1508,7 @@ static int wcd9xxx_slim_device_down(struct slim_device *sldev) wcd9xxx_irq_exit(&wcd9xxx->core_res); if (wcd9xxx->dev_down) wcd9xxx->dev_down(wcd9xxx); + wcd9xxx_reset_low(wcd9xxx->dev); return 0; } @@ -1554,6 +1556,7 @@ static const struct slim_device_id wcd_slim_device_id[] = { {"tapan-slim-pgd", 0}, {"tomtom-slim-pgd", WCD9330}, {"tasha-slim-pgd", WCD9335}, + {"tavil-slim-pgd", WCD934X}, {} }; diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c index 8024fab80295..1b93c83ae98e 100644 --- a/drivers/mfd/wcd9xxx-irq.c +++ b/drivers/mfd/wcd9xxx-irq.c @@ -390,18 +390,21 @@ void wcd9xxx_free_irq(struct wcd9xxx_core_resource *wcd9xxx_res, void wcd9xxx_enable_irq(struct wcd9xxx_core_resource *wcd9xxx_res, int irq) { - enable_irq(phyirq_to_virq(wcd9xxx_res, irq)); + if (wcd9xxx_res->irq) + enable_irq(phyirq_to_virq(wcd9xxx_res, irq)); } void wcd9xxx_disable_irq(struct wcd9xxx_core_resource *wcd9xxx_res, int irq) { - disable_irq_nosync(phyirq_to_virq(wcd9xxx_res, irq)); + if (wcd9xxx_res->irq) + disable_irq_nosync(phyirq_to_virq(wcd9xxx_res, irq)); } void wcd9xxx_disable_irq_sync( struct wcd9xxx_core_resource *wcd9xxx_res, int irq) { - disable_irq(phyirq_to_virq(wcd9xxx_res, irq)); + if (wcd9xxx_res->irq) + disable_irq(phyirq_to_virq(wcd9xxx_res, irq)); } static int wcd9xxx_irq_setup_downstream_irq( @@ -551,6 +554,7 @@ void wcd9xxx_irq_exit(struct wcd9xxx_core_resource *wcd9xxx_res) disable_irq_wake(wcd9xxx_res->irq); free_irq(wcd9xxx_res->irq, wcd9xxx_res); /* Release parent's of node */ + wcd9xxx_res->irq = 0; wcd9xxx_irq_put_upstream_irq(wcd9xxx_res); } mutex_destroy(&wcd9xxx_res->irq_lock); diff --git a/drivers/mfd/wcd9xxx-regmap.h b/drivers/mfd/wcd9xxx-regmap.h index bca3962b30bb..62e4a620c71c 100644 --- a/drivers/mfd/wcd9xxx-regmap.h +++ b/drivers/mfd/wcd9xxx-regmap.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -19,6 +19,10 @@ typedef int (*regmap_patch_fptr)(struct regmap *, int); +#ifdef CONFIG_WCD934X_CODEC +extern struct regmap_config wcd934x_regmap_config; +#endif + #ifdef CONFIG_WCD9335_CODEC extern struct regmap_config wcd9335_regmap_config; extern int wcd9335_regmap_register_patch(struct regmap *regmap, @@ -34,6 +38,11 @@ static inline struct regmap_config *wcd9xxx_get_regmap_config(int type) struct regmap_config *regmap_config; switch (type) { +#ifdef CONFIG_WCD934X_CODEC + case WCD934X: + regmap_config = &wcd934x_regmap_config; + break; +#endif #ifdef CONFIG_WCD9335_CODEC case WCD9335: regmap_config = &wcd9335_regmap_config; diff --git a/drivers/mfd/wcd9xxx-utils.c b/drivers/mfd/wcd9xxx-utils.c index 6bfe3d5a1788..22d61d96a11d 100644 --- a/drivers/mfd/wcd9xxx-utils.c +++ b/drivers/mfd/wcd9xxx-utils.c @@ -37,6 +37,16 @@ static enum wcd9xxx_intf_status wcd9xxx_intf = -1; +static struct mfd_cell tavil_devs[] = { + { + .name = "qcom-wcd-pinctrl", + .of_compatible = "qcom,wcd-pinctrl", + }, + { + .name = "tavil_codec", + }, +}; + static struct mfd_cell tasha_devs[] = { { .name = "tasha_codec", @@ -418,7 +428,7 @@ int wcd9xxx_page_write(struct wcd9xxx *wcd9xxx, unsigned short *reg) unsigned short c_reg, reg_addr; u8 pg_num, prev_pg_num; - if (wcd9xxx->type != WCD9335) + if (wcd9xxx->type != WCD9335 && wcd9xxx->type != WCD934X) return ret; c_reg = *reg; @@ -618,6 +628,7 @@ int wcd9xxx_reset(struct device *dev) { struct wcd9xxx *wcd9xxx; int rc; + int value; if (!dev) return -ENODEV; @@ -632,6 +643,12 @@ int wcd9xxx_reset(struct device *dev) return -EINVAL; } + value = msm_cdc_get_gpio_state(wcd9xxx->wcd_rst_np); + if (value > 0) { + wcd9xxx->avoid_cdc_rstlow = 1; + return 0; + } + rc = msm_cdc_pinctrl_select_sleep_state(wcd9xxx->wcd_rst_np); if (rc) { dev_err(dev, "%s: wcd sleep state request fail!\n", @@ -679,6 +696,11 @@ int wcd9xxx_reset_low(struct device *dev) __func__); return -EINVAL; } + if (wcd9xxx->avoid_cdc_rstlow) { + wcd9xxx->avoid_cdc_rstlow = 0; + dev_dbg(dev, "%s: avoid pull down of reset GPIO\n", __func__); + return 0; + } rc = msm_cdc_pinctrl_select_sleep_state(wcd9xxx->wcd_rst_np); if (rc) @@ -803,6 +825,10 @@ int wcd9xxx_get_codec_info(struct device *dev) } switch (wcd9xxx->type) { + case WCD934X: + cinfo->dev = tavil_devs; + cinfo->size = ARRAY_SIZE(tavil_devs); + break; case WCD9335: cinfo->dev = tasha_devs; cinfo->size = ARRAY_SIZE(tasha_devs); diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index 85761d7eb333..be2c8e248e2e 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -414,7 +414,7 @@ static int cxl_setup_psl_timebase(struct cxl *adapter, struct pci_dev *dev) delta = mftb() - psl_tb; if (delta < 0) delta = -delta; - } while (cputime_to_usecs(delta) > 16); + } while (tb_to_ns(delta) > 16000); return 0; } diff --git a/drivers/misc/cxl/vphb.c b/drivers/misc/cxl/vphb.c index c241e15cacb1..cbd4331fb45c 100644 --- a/drivers/misc/cxl/vphb.c +++ b/drivers/misc/cxl/vphb.c @@ -203,7 +203,7 @@ static int cxl_pcie_write_config(struct pci_bus *bus, unsigned int devfn, mask <<= shift; val <<= shift; - v = (in_le32(ioaddr) & ~mask) || (val & mask); + v = (in_le32(ioaddr) & ~mask) | (val & mask); out_le32(ioaddr, v); return PCIBIOS_SUCCESSFUL; diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c index 11fdadc68e53..2a6eaf1122b4 100644 --- a/drivers/misc/lkdtm.c +++ b/drivers/misc/lkdtm.c @@ -103,6 +103,7 @@ enum ctype { CT_EXEC_USERSPACE, CT_ACCESS_USERSPACE, CT_WRITE_RO, + CT_WRITE_RO_AFTER_INIT, CT_WRITE_KERN, }; @@ -140,6 +141,7 @@ static char* cp_type[] = { "EXEC_USERSPACE", "ACCESS_USERSPACE", "WRITE_RO", + "WRITE_RO_AFTER_INIT", "WRITE_KERN", }; @@ -162,6 +164,7 @@ static DEFINE_SPINLOCK(lock_me_up); static u8 data_area[EXEC_SIZE]; static const unsigned long rodata = 0xAA55AA55; +static unsigned long ro_after_init __ro_after_init = 0x55AA5500; module_param(recur_count, int, 0644); MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test"); @@ -503,11 +506,28 @@ static void lkdtm_do_action(enum ctype which) break; } case CT_WRITE_RO: { - unsigned long *ptr; + /* Explicitly cast away "const" for the test. */ + unsigned long *ptr = (unsigned long *)&rodata; - ptr = (unsigned long *)&rodata; + pr_info("attempting bad rodata write at %p\n", ptr); + *ptr ^= 0xabcd1234; - pr_info("attempting bad write at %p\n", ptr); + break; + } + case CT_WRITE_RO_AFTER_INIT: { + unsigned long *ptr = &ro_after_init; + + /* + * Verify we were written to during init. Since an Oops + * is considered a "success", a failure is to just skip the + * real test. + */ + if ((*ptr & 0xAA) != 0xAA) { + pr_info("%p was NOT written during init!?\n", ptr); + break; + } + + pr_info("attempting bad ro_after_init write at %p\n", ptr); *ptr ^= 0xabcd1234; break; @@ -817,6 +837,9 @@ static int __init lkdtm_module_init(void) int n_debugfs_entries = 1; /* Assume only the direct entry */ int i; + /* Make sure we can write to __ro_after_init values during __init */ + ro_after_init |= 0xAA; + /* Register debugfs interface */ lkdtm_debugfs_root = debugfs_create_dir("provoke-crash", NULL); if (!lkdtm_debugfs_root) { diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index b2f2486b3d75..80f9afcb1382 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -458,7 +458,11 @@ static int mei_ioctl_client_notify_request(struct file *file, u32 request) { struct mei_cl *cl = file->private_data; - return mei_cl_notify_request(cl, file, request); + if (request != MEI_HBM_NOTIFICATION_START && + request != MEI_HBM_NOTIFICATION_STOP) + return -EINVAL; + + return mei_cl_notify_request(cl, file, (u8)request); } /** @@ -657,7 +661,9 @@ out: * @file: pointer to file structure * @band: band bitmap * - * Return: poll mask + * Return: negative on error, + * 0 if it did no changes, + * and positive a process was added or deleted */ static int mei_fasync(int fd, struct file *file, int band) { @@ -665,7 +671,7 @@ static int mei_fasync(int fd, struct file *file, int band) struct mei_cl *cl = file->private_data; if (!mei_cl_is_connected(cl)) - return POLLERR; + return -ENODEV; return fasync_helper(fd, file, band, &cl->ev_async); } diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 1aec5e559dd5..273728482227 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -433,7 +433,6 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, smc_id = TZ_OS_APP_SHUTDOWN_ID; desc.arginfo = TZ_OS_APP_SHUTDOWN_ID_PARAM_ID; desc.args[0] = req->app_id; - __qseecom_reentrancy_check_if_no_app_blocked(smc_id); ret = scm_call2(smc_id, &desc); break; } @@ -2104,6 +2103,9 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, return 0; } + __qseecom_cleanup_app(data); + __qseecom_reentrancy_check_if_no_app_blocked(TZ_OS_APP_SHUTDOWN_ID); + if (data->client.app_id > 0) { spin_lock_irqsave(&qseecom.registered_app_list_lock, flags); list_for_each_entry(ptr_app, &qseecom.registered_app_list_head, @@ -2132,11 +2134,9 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, } } - if (found_dead_app) { + if (found_dead_app) pr_warn("cleanup app_id %d(%s)\n", data->client.app_id, (char *)data->client.app_name); - __qseecom_cleanup_app(data); - } if (unload) { struct qseecom_unload_app_ireq req; @@ -2165,7 +2165,6 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, if (resp.result == QSEOS_RESULT_SUCCESS) pr_debug("App (%d) is unloaded!!\n", data->client.app_id); - __qseecom_cleanup_app(data); if (resp.result == QSEOS_RESULT_INCOMPLETE) { ret = __qseecom_process_incomplete_cmd(data, &resp); if (ret) { diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 78dae0679645..5489f243a682 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1190,8 +1190,7 @@ static int mmc_select_hs400(struct mmc_card *card) mmc_set_clock(host, max_dtr); /* Switch card to HS mode */ - val = EXT_CSD_TIMING_HS | - card->drive_strength << EXT_CSD_DRV_STR_SHIFT; + val = EXT_CSD_TIMING_HS; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, card->ext_csd.generic_cmd6_time, @@ -1298,8 +1297,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card) mmc_set_clock(host, max_dtr); /* Switch HS400 to HS DDR */ - val = EXT_CSD_TIMING_HS | - card->drive_strength << EXT_CSD_DRV_STR_SHIFT; + val = EXT_CSD_TIMING_HS; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, card->ext_csd.generic_cmd6_time, true, send_status, true); diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index f239e5d21856..7b84030ffe92 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -696,9 +696,9 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card) * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104. */ if (!mmc_host_is_spi(card->host) && - (card->sd_bus_speed == UHS_SDR50_BUS_SPEED || - card->sd_bus_speed == UHS_DDR50_BUS_SPEED || - card->sd_bus_speed == UHS_SDR104_BUS_SPEED)) { + (card->host->ios.timing == MMC_TIMING_UHS_SDR50 || + card->host->ios.timing == MMC_TIMING_UHS_DDR50 || + card->host->ios.timing == MMC_TIMING_UHS_SDR104)) { err = mmc_execute_tuning(card); /* @@ -708,7 +708,7 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card) * difference between v3.00 and 3.01 spec means that CMD19 * tuning is also available for DDR50 mode. */ - if (err && card->sd_bus_speed == UHS_DDR50_BUS_SPEED) { + if (err && card->host->ios.timing == MMC_TIMING_UHS_DDR50) { pr_warn("%s: ddr50 tuning failed\n", mmc_hostname(card->host)); err = 0; diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 059c39f62e27..895dfbb7fbf5 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -611,8 +611,8 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card) * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104. */ if (!mmc_host_is_spi(card->host) && - ((card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR50) || - (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104))) + ((card->host->ios.timing == MMC_TIMING_UHS_SDR50) || + (card->host->ios.timing == MMC_TIMING_UHS_SDR104))) err = mmc_execute_tuning(card); out: return err; @@ -709,7 +709,7 @@ try_again: */ if (!powered_resume && (rocr & ocr & R4_18V_PRESENT)) { err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, - ocr); + ocr_card); if (err == -EAGAIN) { sdio_reset(host); mmc_go_idle(host); diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index fb266745f824..acece3299756 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1886,7 +1886,7 @@ static struct amba_id mmci_ids[] = { { .id = 0x00280180, .mask = 0x00ffffff, - .data = &variant_u300, + .data = &variant_nomadik, }, { .id = 0x00480180, diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index ce08896b9d69..28a057fae0a1 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -804,7 +804,7 @@ static int pxamci_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Failed requesting gpio_ro %d\n", gpio_ro); goto out; } else { - mmc->caps |= host->pdata->gpio_card_ro_invert ? + mmc->caps2 |= host->pdata->gpio_card_ro_invert ? 0 : MMC_CAP2_RO_ACTIVE_HIGH; } diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index f6047fc94062..a5cda926d38e 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -146,6 +146,33 @@ static const struct sdhci_acpi_chip sdhci_acpi_chip_int = { .ops = &sdhci_acpi_ops_int, }; +static int bxt_get_cd(struct mmc_host *mmc) +{ + int gpio_cd = mmc_gpio_get_cd(mmc); + struct sdhci_host *host = mmc_priv(mmc); + unsigned long flags; + int ret = 0; + + if (!gpio_cd) + return 0; + + pm_runtime_get_sync(mmc->parent); + + spin_lock_irqsave(&host->lock, flags); + + if (host->flags & SDHCI_DEVICE_DEAD) + goto out; + + ret = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); +out: + spin_unlock_irqrestore(&host->lock, flags); + + pm_runtime_mark_last_busy(mmc->parent); + pm_runtime_put_autosuspend(mmc->parent); + + return ret; +} + static int sdhci_acpi_emmc_probe_slot(struct platform_device *pdev, const char *hid, const char *uid) { @@ -196,6 +223,9 @@ static int sdhci_acpi_sd_probe_slot(struct platform_device *pdev, /* Platform specific code during sd probe slot goes here */ + if (hid && !strcmp(hid, "80865ACA")) + host->mmc_host_ops.get_cd = bxt_get_cd; + return 0; } diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index cf7ad458b4f4..45ee07d3a761 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -277,7 +277,7 @@ static int spt_select_drive_strength(struct sdhci_host *host, if (sdhci_pci_spt_drive_strength > 0) drive_strength = sdhci_pci_spt_drive_strength & 0xf; else - drive_strength = 1; /* 33-ohm */ + drive_strength = 0; /* Default 50-ohm */ if ((mmc_driver_type_mask(drive_strength) & card_drv) == 0) drive_strength = 0; /* Default 50-ohm */ @@ -330,6 +330,33 @@ static void spt_read_drive_strength(struct sdhci_host *host) sdhci_pci_spt_drive_strength = 0x10 | ((val >> 12) & 0xf); } +static int bxt_get_cd(struct mmc_host *mmc) +{ + int gpio_cd = mmc_gpio_get_cd(mmc); + struct sdhci_host *host = mmc_priv(mmc); + unsigned long flags; + int ret = 0; + + if (!gpio_cd) + return 0; + + pm_runtime_get_sync(mmc->parent); + + spin_lock_irqsave(&host->lock, flags); + + if (host->flags & SDHCI_DEVICE_DEAD) + goto out; + + ret = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); +out: + spin_unlock_irqrestore(&host->lock, flags); + + pm_runtime_mark_last_busy(mmc->parent); + pm_runtime_put_autosuspend(mmc->parent); + + return ret; +} + static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot) { slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE | @@ -362,6 +389,10 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot) slot->cd_con_id = NULL; slot->cd_idx = 0; slot->cd_override_level = true; + if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BXT_SD || + slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_APL_SD) + slot->host->mmc_host_ops.get_cd = bxt_get_cd; + return 0; } diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 6bfd95823da7..36b75f048e76 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -626,7 +626,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, if (len) { /* tran, valid */ - sdhci_adma_write_desc(host, desc, addr, len, ADMA2_TRAN_VALID); + sdhci_adma_write_desc(host, desc, addr, len, + ADMA2_TRAN_VALID); desc += host->desc_sz; } @@ -3383,7 +3384,7 @@ static int sdhci_runtime_pm_put(struct sdhci_host *host) static void sdhci_runtime_pm_bus_on(struct sdhci_host *host) { - if (host->runtime_suspended || host->bus_on) + if (host->bus_on) return; host->bus_on = true; pm_runtime_get_noresume(host->mmc->parent); @@ -3391,7 +3392,7 @@ static void sdhci_runtime_pm_bus_on(struct sdhci_host *host) static void sdhci_runtime_pm_bus_off(struct sdhci_host *host) { - if (host->runtime_suspended || !host->bus_on) + if (!host->bus_on) return; host->bus_on = false; pm_runtime_put_noidle(host->mmc->parent); @@ -3484,6 +3485,8 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev, host = mmc_priv(mmc); host->mmc = mmc; + host->mmc_host_ops = sdhci_ops; + mmc->ops = &host->mmc_host_ops; spin_lock_init(&host->lock); ratelimit_state_init(&host->dbg_dump_rs, SDHCI_DBG_DUMP_RS_INTERVAL, @@ -3885,7 +3888,6 @@ int sdhci_add_host(struct sdhci_host *host) /* * Set host parameters. */ - mmc->ops = &sdhci_ops; max_clk = host->max_clk; if (host->ops->get_min_clock) diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index da963972b9a4..a1f9c48879fa 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -521,6 +521,7 @@ struct sdhci_host { /* Internal data */ struct mmc_host *mmc; /* MMC structure */ + struct mmc_host_ops mmc_host_ops; /* MMC host ops */ u64 dma_mask; /* custom DMA mask */ u64 coherent_dma_mask; diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c index 4498e92116b8..b47122d3e8d8 100644 --- a/drivers/mmc/host/usdhi6rol0.c +++ b/drivers/mmc/host/usdhi6rol0.c @@ -1634,7 +1634,7 @@ static void usdhi6_timeout_work(struct work_struct *work) struct usdhi6_host *host = container_of(d, struct usdhi6_host, timeout_work); struct mmc_request *mrq = host->mrq; struct mmc_data *data = mrq ? mrq->data : NULL; - struct scatterlist *sg = host->sg ?: data->sg; + struct scatterlist *sg; dev_warn(mmc_dev(host->mmc), "%s timeout wait %u CMD%d: IRQ 0x%08x:0x%08x, last IRQ 0x%08x\n", @@ -1666,6 +1666,7 @@ static void usdhi6_timeout_work(struct work_struct *work) case USDHI6_WAIT_FOR_MWRITE: case USDHI6_WAIT_FOR_READ: case USDHI6_WAIT_FOR_WRITE: + sg = host->sg ?: data->sg; dev_dbg(mmc_dev(host->mmc), "%c: page #%u @ +0x%zx %ux%u in SG%u. Current SG %u bytes @ %u\n", data->flags & MMC_DATA_READ ? 'R' : 'W', host->page_idx, diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c index 2a1b6e037e1a..0134ba32a057 100644 --- a/drivers/mtd/ubi/upd.c +++ b/drivers/mtd/ubi/upd.c @@ -193,7 +193,7 @@ int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, vol->changing_leb = 1; vol->ch_lnum = req->lnum; - vol->upd_buf = vmalloc(req->bytes); + vol->upd_buf = vmalloc(ALIGN((int)req->bytes, ubi->min_io_size)); if (!vol->upd_buf) return -ENOMEM; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index f1692e418fe4..28bbca0af238 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -214,6 +214,8 @@ static void bond_uninit(struct net_device *bond_dev); static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev, struct rtnl_link_stats64 *stats); static void bond_slave_arr_handler(struct work_struct *work); +static bool bond_time_in_interval(struct bonding *bond, unsigned long last_act, + int mod); /*---------------------------- General routines -----------------------------*/ @@ -2418,7 +2420,7 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond, struct slave *slave) { struct arphdr *arp = (struct arphdr *)skb->data; - struct slave *curr_active_slave; + struct slave *curr_active_slave, *curr_arp_slave; unsigned char *arp_ptr; __be32 sip, tip; int alen, is_arp = skb->protocol == __cpu_to_be16(ETH_P_ARP); @@ -2465,26 +2467,41 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond, &sip, &tip); curr_active_slave = rcu_dereference(bond->curr_active_slave); + curr_arp_slave = rcu_dereference(bond->current_arp_slave); - /* Backup slaves won't see the ARP reply, but do come through - * here for each ARP probe (so we swap the sip/tip to validate - * the probe). In a "redundant switch, common router" type of - * configuration, the ARP probe will (hopefully) travel from - * the active, through one switch, the router, then the other - * switch before reaching the backup. + /* We 'trust' the received ARP enough to validate it if: + * + * (a) the slave receiving the ARP is active (which includes the + * current ARP slave, if any), or + * + * (b) the receiving slave isn't active, but there is a currently + * active slave and it received valid arp reply(s) after it became + * the currently active slave, or + * + * (c) there is an ARP slave that sent an ARP during the prior ARP + * interval, and we receive an ARP reply on any slave. We accept + * these because switch FDB update delays may deliver the ARP + * reply to a slave other than the sender of the ARP request. * - * We 'trust' the arp requests if there is an active slave and - * it received valid arp reply(s) after it became active. This - * is done to avoid endless looping when we can't reach the + * Note: for (b), backup slaves are receiving the broadcast ARP + * request, not a reply. This request passes from the sending + * slave through the L2 switch(es) to the receiving slave. Since + * this is checking the request, sip/tip are swapped for + * validation. + * + * This is done to avoid endless looping when we can't reach the * arp_ip_target and fool ourselves with our own arp requests. */ - if (bond_is_active_slave(slave)) bond_validate_arp(bond, slave, sip, tip); else if (curr_active_slave && time_after(slave_last_rx(bond, curr_active_slave), curr_active_slave->last_link_up)) bond_validate_arp(bond, slave, tip, sip); + else if (curr_arp_slave && (arp->ar_op == htons(ARPOP_REPLY)) && + bond_time_in_interval(bond, + dev_trans_start(curr_arp_slave->dev), 1)) + bond_validate_arp(bond, slave, sip, tip); out_unlock: if (arp != (struct arphdr *)skb->data) diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index fc5b75675cd8..eb7192fab593 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -117,6 +117,9 @@ MODULE_LICENSE("GPL v2"); */ #define EMS_USB_ARM7_CLOCK 8000000 +#define CPC_TX_QUEUE_TRIGGER_LOW 25 +#define CPC_TX_QUEUE_TRIGGER_HIGH 35 + /* * CAN-Message representation in a CPC_MSG. Message object type is * CPC_MSG_TYPE_CAN_FRAME or CPC_MSG_TYPE_RTR_FRAME or @@ -278,6 +281,11 @@ static void ems_usb_read_interrupt_callback(struct urb *urb) switch (urb->status) { case 0: dev->free_slots = dev->intr_in_buffer[1]; + if(dev->free_slots > CPC_TX_QUEUE_TRIGGER_HIGH){ + if (netif_queue_stopped(netdev)){ + netif_wake_queue(netdev); + } + } break; case -ECONNRESET: /* unlink */ @@ -526,8 +534,6 @@ static void ems_usb_write_bulk_callback(struct urb *urb) /* Release context */ context->echo_index = MAX_TX_URBS; - if (netif_queue_stopped(netdev)) - netif_wake_queue(netdev); } /* @@ -587,7 +593,7 @@ static int ems_usb_start(struct ems_usb *dev) int err, i; dev->intr_in_buffer[0] = 0; - dev->free_slots = 15; /* initial size */ + dev->free_slots = 50; /* initial size */ for (i = 0; i < MAX_RX_URBS; i++) { struct urb *urb = NULL; @@ -835,7 +841,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne /* Slow down tx path */ if (atomic_read(&dev->active_tx_urbs) >= MAX_TX_URBS || - dev->free_slots < 5) { + dev->free_slots < CPC_TX_QUEUE_TRIGGER_LOW) { netif_stop_queue(netdev); } } diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index 5eee62badf45..cbc99d5649af 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -826,9 +826,8 @@ static struct gs_can *gs_make_candev(unsigned int channel, struct usb_interface static void gs_destroy_candev(struct gs_can *dev) { unregister_candev(dev->netdev); - free_candev(dev->netdev); usb_kill_anchored_urbs(&dev->tx_submitted); - kfree(dev); + free_candev(dev->netdev); } static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -913,12 +912,15 @@ static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id * for (i = 0; i < icount; i++) { dev->canch[i] = gs_make_candev(i, intf); if (IS_ERR_OR_NULL(dev->canch[i])) { + /* save error code to return later */ + rc = PTR_ERR(dev->canch[i]); + /* on failure destroy previously created candevs */ icount = i; - for (i = 0; i < icount; i++) { + for (i = 0; i < icount; i++) gs_destroy_candev(dev->canch[i]); - dev->canch[i] = NULL; - } + + usb_kill_anchored_urbs(&dev->rx_submitted); kfree(dev); return rc; } @@ -939,16 +941,12 @@ static void gs_usb_disconnect(struct usb_interface *intf) return; } - for (i = 0; i < GS_MAX_INTF; i++) { - struct gs_can *can = dev->canch[i]; - - if (!can) - continue; - - gs_destroy_candev(can); - } + for (i = 0; i < GS_MAX_INTF; i++) + if (dev->canch[i]) + gs_destroy_candev(dev->canch[i]); usb_kill_anchored_urbs(&dev->rx_submitted); + kfree(dev); } static const struct usb_device_id gs_usb_table[] = { diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index b06dba05594a..2dea39b5cb0b 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -1519,7 +1519,7 @@ int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port, /* no PVID with ranges, otherwise it's a bug */ if (pvid) - err = _mv88e6xxx_port_pvid_set(ds, port, vid); + err = _mv88e6xxx_port_pvid_set(ds, port, vlan->vid_end); unlock: mutex_unlock(&ps->smi_mutex); diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 79789d8e52da..ca5ac5d6f4e6 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -7833,6 +7833,14 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, return ret; } +static bool tg3_tso_bug_gso_check(struct tg3_napi *tnapi, struct sk_buff *skb) +{ + /* Check if we will never have enough descriptors, + * as gso_segs can be more than current ring size + */ + return skb_shinfo(skb)->gso_segs < tnapi->tx_pending / 3; +} + static netdev_tx_t tg3_start_xmit(struct sk_buff *, struct net_device *); /* Use GSO to workaround all TSO packets that meet HW bug conditions @@ -7936,14 +7944,19 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) * vlan encapsulated. */ if (skb->protocol == htons(ETH_P_8021Q) || - skb->protocol == htons(ETH_P_8021AD)) - return tg3_tso_bug(tp, tnapi, txq, skb); + skb->protocol == htons(ETH_P_8021AD)) { + if (tg3_tso_bug_gso_check(tnapi, skb)) + return tg3_tso_bug(tp, tnapi, txq, skb); + goto drop; + } if (!skb_is_gso_v6(skb)) { if (unlikely((ETH_HLEN + hdr_len) > 80) && - tg3_flag(tp, TSO_BUG)) - return tg3_tso_bug(tp, tnapi, txq, skb); - + tg3_flag(tp, TSO_BUG)) { + if (tg3_tso_bug_gso_check(tnapi, skb)) + return tg3_tso_bug(tp, tnapi, txq, skb); + goto drop; + } ip_csum = iph->check; ip_tot_len = iph->tot_len; iph->check = 0; @@ -8075,7 +8088,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) if (would_hit_hwbug) { tg3_tx_skb_unmap(tnapi, tnapi->tx_prod, i); - if (mss) { + if (mss && tg3_tso_bug_gso_check(tnapi, skb)) { /* If it's a TSO packet, do GSO instead of * allocating and copying to a large linear SKB */ diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h index 1671fa3332c2..7ba6d530b0c0 100644 --- a/drivers/net/ethernet/cisco/enic/enic.h +++ b/drivers/net/ethernet/cisco/enic/enic.h @@ -33,7 +33,7 @@ #define DRV_NAME "enic" #define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver" -#define DRV_VERSION "2.3.0.12" +#define DRV_VERSION "2.3.0.20" #define DRV_COPYRIGHT "Copyright 2008-2013 Cisco Systems, Inc" #define ENIC_BARS_MAX 6 diff --git a/drivers/net/ethernet/cisco/enic/vnic_dev.c b/drivers/net/ethernet/cisco/enic/vnic_dev.c index 1ffd1050860b..1fdf5fe12a95 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_dev.c +++ b/drivers/net/ethernet/cisco/enic/vnic_dev.c @@ -298,7 +298,8 @@ static int _vnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, int wait) { struct devcmd2_controller *dc2c = vdev->devcmd2; - struct devcmd2_result *result = dc2c->result + dc2c->next_result; + struct devcmd2_result *result; + u8 color; unsigned int i; int delay, err; u32 fetch_index, new_posted; @@ -336,13 +337,17 @@ static int _vnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, if (dc2c->cmd_ring[posted].flags & DEVCMD2_FNORESULT) return 0; + result = dc2c->result + dc2c->next_result; + color = dc2c->color; + + dc2c->next_result++; + if (dc2c->next_result == dc2c->result_size) { + dc2c->next_result = 0; + dc2c->color = dc2c->color ? 0 : 1; + } + for (delay = 0; delay < wait; delay++) { - if (result->color == dc2c->color) { - dc2c->next_result++; - if (dc2c->next_result == dc2c->result_size) { - dc2c->next_result = 0; - dc2c->color = dc2c->color ? 0 : 1; - } + if (result->color == color) { if (result->error) { err = result->error; if (err != ERR_ECMDUNKNOWN || diff --git a/drivers/net/ethernet/mellanox/mlx4/en_clock.c b/drivers/net/ethernet/mellanox/mlx4/en_clock.c index 038f9ce391e6..1494997c4f7e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_clock.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_clock.c @@ -236,6 +236,24 @@ static const struct ptp_clock_info mlx4_en_ptp_clock_info = { .enable = mlx4_en_phc_enable, }; +#define MLX4_EN_WRAP_AROUND_SEC 10ULL + +/* This function calculates the max shift that enables the user range + * of MLX4_EN_WRAP_AROUND_SEC values in the cycles register. + */ +static u32 freq_to_shift(u16 freq) +{ + u32 freq_khz = freq * 1000; + u64 max_val_cycles = freq_khz * 1000 * MLX4_EN_WRAP_AROUND_SEC; + u64 max_val_cycles_rounded = is_power_of_2(max_val_cycles + 1) ? + max_val_cycles : roundup_pow_of_two(max_val_cycles) - 1; + /* calculate max possible multiplier in order to fit in 64bit */ + u64 max_mul = div_u64(0xffffffffffffffffULL, max_val_cycles_rounded); + + /* This comes from the reverse of clocksource_khz2mult */ + return ilog2(div_u64(max_mul * freq_khz, 1000000)); +} + void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev) { struct mlx4_dev *dev = mdev->dev; @@ -254,12 +272,7 @@ void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev) memset(&mdev->cycles, 0, sizeof(mdev->cycles)); mdev->cycles.read = mlx4_en_read_clock; mdev->cycles.mask = CLOCKSOURCE_MASK(48); - /* Using shift to make calculation more accurate. Since current HW - * clock frequency is 427 MHz, and cycles are given using a 48 bits - * register, the biggest shift when calculating using u64, is 14 - * (max_cycles * multiplier < 2^64) - */ - mdev->cycles.shift = 14; + mdev->cycles.shift = freq_to_shift(dev->caps.hca_core_clock); mdev->cycles.mult = clocksource_khz2mult(1000 * dev->caps.hca_core_clock, mdev->cycles.shift); mdev->nominal_c_mult = mdev->cycles.mult; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 7869f97de5da..67e9633ea9c7 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2381,8 +2381,6 @@ out: /* set offloads */ priv->dev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_RXCSUM | NETIF_F_TSO | NETIF_F_GSO_UDP_TUNNEL; - priv->dev->hw_features |= NETIF_F_GSO_UDP_TUNNEL; - priv->dev->features |= NETIF_F_GSO_UDP_TUNNEL; } static void mlx4_en_del_vxlan_offloads(struct work_struct *work) @@ -2393,8 +2391,6 @@ static void mlx4_en_del_vxlan_offloads(struct work_struct *work) /* unset offloads */ priv->dev->hw_enc_features &= ~(NETIF_F_IP_CSUM | NETIF_F_RXCSUM | NETIF_F_TSO | NETIF_F_GSO_UDP_TUNNEL); - priv->dev->hw_features &= ~NETIF_F_GSO_UDP_TUNNEL; - priv->dev->features &= ~NETIF_F_GSO_UDP_TUNNEL; ret = mlx4_SET_PORT_VXLAN(priv->mdev->dev, priv->port, VXLAN_STEER_BY_OUTER_MAC, 0); @@ -3020,6 +3016,11 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, priv->rss_hash_fn = ETH_RSS_HASH_TOP; } + if (mdev->dev->caps.tunnel_offload_mode == MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) { + dev->hw_features |= NETIF_F_GSO_UDP_TUNNEL; + dev->features |= NETIF_F_GSO_UDP_TUNNEL; + } + mdev->pndev[port] = dev; mdev->upper[port] = NULL; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_port.c b/drivers/net/ethernet/mellanox/mlx4/en_port.c index ee99e67187f5..3904b5fc0b7c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_port.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_port.c @@ -238,11 +238,11 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset) stats->collisions = 0; stats->rx_dropped = be32_to_cpu(mlx4_en_stats->RDROP); stats->rx_length_errors = be32_to_cpu(mlx4_en_stats->RdropLength); - stats->rx_over_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw); + stats->rx_over_errors = 0; stats->rx_crc_errors = be32_to_cpu(mlx4_en_stats->RCRC); stats->rx_frame_errors = 0; stats->rx_fifo_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw); - stats->rx_missed_errors = be32_to_cpu(mlx4_en_stats->RdropOvflw); + stats->rx_missed_errors = 0; stats->tx_aborted_errors = 0; stats->tx_carrier_errors = 0; stats->tx_fifo_errors = 0; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 617fb22b5d81..7dbeafa65934 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -45,6 +45,7 @@ #include <linux/if_bridge.h> #include <linux/workqueue.h> #include <linux/jiffies.h> +#include <linux/rtnetlink.h> #include <net/switchdev.h> #include "spectrum.h" @@ -812,6 +813,7 @@ static void mlxsw_sp_fdb_notify_work(struct work_struct *work) mlxsw_sp = container_of(work, struct mlxsw_sp, fdb_notify.dw.work); + rtnl_lock(); do { mlxsw_reg_sfn_pack(sfn_pl); err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(sfn), sfn_pl); @@ -824,6 +826,7 @@ static void mlxsw_sp_fdb_notify_work(struct work_struct *work) mlxsw_sp_fdb_notify_rec_process(mlxsw_sp, sfn_pl, i); } while (num_rec); + rtnl_unlock(); kfree(sfn_pl); mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp); diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index e9f2349e98bc..52ec3d6e056a 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -3531,12 +3531,14 @@ static void rocker_port_fdb_learn_work(struct work_struct *work) info.addr = lw->addr; info.vid = lw->vid; + rtnl_lock(); if (learned && removing) call_switchdev_notifiers(SWITCHDEV_FDB_DEL, lw->rocker_port->dev, &info.info); else if (learned && !removing) call_switchdev_notifiers(SWITCHDEV_FDB_ADD, lw->rocker_port->dev, &info.info); + rtnl_unlock(); rocker_port_kfree(lw->trans, work); } diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index 47b711739ba9..e6cefd0e3262 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -845,6 +845,11 @@ static void decode_rxts(struct dp83640_private *dp83640, struct skb_shared_hwtstamps *shhwtstamps = NULL; struct sk_buff *skb; unsigned long flags; + u8 overflow; + + overflow = (phy_rxts->ns_hi >> 14) & 0x3; + if (overflow) + pr_debug("rx timestamp queue overflow, count %d\n", overflow); spin_lock_irqsave(&dp83640->rx_lock, flags); @@ -887,6 +892,7 @@ static void decode_txts(struct dp83640_private *dp83640, struct skb_shared_hwtstamps shhwtstamps; struct sk_buff *skb; u64 ns; + u8 overflow; /* We must already have the skb that triggered this. */ @@ -896,6 +902,17 @@ static void decode_txts(struct dp83640_private *dp83640, pr_debug("have timestamp but tx_queue empty\n"); return; } + + overflow = (phy_txts->ns_hi >> 14) & 0x3; + if (overflow) { + pr_debug("tx timestamp queue overflow, count %d\n", overflow); + while (skb) { + skb_complete_tx_timestamp(skb, NULL); + skb = skb_dequeue(&dp83640->tx_queue); + } + return; + } + ns = phy2txts(phy_txts); memset(&shhwtstamps, 0, sizeof(shhwtstamps)); shhwtstamps.hwtstamp = ns_to_ktime(ns); diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index 0a37f840fcc5..4e0068e775f9 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -395,6 +395,8 @@ static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb) if (!__pppoe_xmit(sk_pppox(relay_po), skb)) goto abort_put; + + sock_put(sk_pppox(relay_po)); } else { if (sock_queue_rcv_skb(sk, skb)) goto abort_kfree; diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c index 597c53e0a2ec..f7e8c79349ad 100644 --- a/drivers/net/ppp/pptp.c +++ b/drivers/net/ppp/pptp.c @@ -129,24 +129,27 @@ static int lookup_chan_dst(u16 call_id, __be32 d_addr) return i < MAX_CALLID; } -static int add_chan(struct pppox_sock *sock) +static int add_chan(struct pppox_sock *sock, + struct pptp_addr *sa) { static int call_id; spin_lock(&chan_lock); - if (!sock->proto.pptp.src_addr.call_id) { + if (!sa->call_id) { call_id = find_next_zero_bit(callid_bitmap, MAX_CALLID, call_id + 1); if (call_id == MAX_CALLID) { call_id = find_next_zero_bit(callid_bitmap, MAX_CALLID, 1); if (call_id == MAX_CALLID) goto out_err; } - sock->proto.pptp.src_addr.call_id = call_id; - } else if (test_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap)) + sa->call_id = call_id; + } else if (test_bit(sa->call_id, callid_bitmap)) { goto out_err; + } - set_bit(sock->proto.pptp.src_addr.call_id, callid_bitmap); - rcu_assign_pointer(callid_sock[sock->proto.pptp.src_addr.call_id], sock); + sock->proto.pptp.src_addr = *sa; + set_bit(sa->call_id, callid_bitmap); + rcu_assign_pointer(callid_sock[sa->call_id], sock); spin_unlock(&chan_lock); return 0; @@ -416,7 +419,6 @@ static int pptp_bind(struct socket *sock, struct sockaddr *uservaddr, struct sock *sk = sock->sk; struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr; struct pppox_sock *po = pppox_sk(sk); - struct pptp_opt *opt = &po->proto.pptp; int error = 0; if (sockaddr_len < sizeof(struct sockaddr_pppox)) @@ -424,10 +426,22 @@ static int pptp_bind(struct socket *sock, struct sockaddr *uservaddr, lock_sock(sk); - opt->src_addr = sp->sa_addr.pptp; - if (add_chan(po)) + if (sk->sk_state & PPPOX_DEAD) { + error = -EALREADY; + goto out; + } + + if (sk->sk_state & PPPOX_BOUND) { error = -EBUSY; + goto out; + } + + if (add_chan(po, &sp->sa_addr.pptp)) + error = -EBUSY; + else + sk->sk_state |= PPPOX_BOUND; +out: release_sock(sk); return error; } @@ -498,7 +512,7 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr, } opt->dst_addr = sp->sa_addr.pptp; - sk->sk_state = PPPOX_CONNECTED; + sk->sk_state |= PPPOX_CONNECTED; end: release_sock(sk); diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 5fccc5a8153f..982e0acd1a36 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -492,6 +492,7 @@ static const struct usb_device_id products[] = { /* 3. Combined interface devices matching on interface number */ {QMI_FIXED_INTF(0x0408, 0xea42, 4)}, /* Yota / Megafon M100-1 */ + {QMI_FIXED_INTF(0x05c6, 0x6001, 3)}, /* 4G LTE usb-modem U901 */ {QMI_FIXED_INTF(0x05c6, 0x7000, 0)}, {QMI_FIXED_INTF(0x05c6, 0x7001, 1)}, {QMI_FIXED_INTF(0x05c6, 0x7002, 1)}, diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 405a7b6cca25..e0fcda4ddd55 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1984,11 +1984,6 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, vxlan->cfg.port_max, true); if (info) { - if (info->key.tun_flags & TUNNEL_CSUM) - flags |= VXLAN_F_UDP_CSUM; - else - flags &= ~VXLAN_F_UDP_CSUM; - ttl = info->key.ttl; tos = info->key.tos; @@ -2003,8 +1998,15 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, goto drop; sk = vxlan->vn4_sock->sock->sk; - if (info && (info->key.tun_flags & TUNNEL_DONT_FRAGMENT)) - df = htons(IP_DF); + if (info) { + if (info->key.tun_flags & TUNNEL_DONT_FRAGMENT) + df = htons(IP_DF); + + if (info->key.tun_flags & TUNNEL_CSUM) + flags |= VXLAN_F_UDP_CSUM; + else + flags &= ~VXLAN_F_UDP_CSUM; + } memset(&fl4, 0, sizeof(fl4)); fl4.flowi4_oif = rdst ? rdst->remote_ifindex : 0; @@ -2102,6 +2104,13 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, return; } + if (info) { + if (info->key.tun_flags & TUNNEL_CSUM) + flags &= ~VXLAN_F_UDP_ZERO_CSUM6_TX; + else + flags |= VXLAN_F_UDP_ZERO_CSUM6_TX; + } + ttl = ttl ? : ip6_dst_hoplimit(ndst); err = vxlan6_xmit_skb(ndst, sk, skb, dev, &saddr, &dst->sin6.sin6_addr, 0, ttl, src_port, dst_port, htonl(vni << 8), md, diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 49eb2e27b11b..18e95148e891 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -378,6 +378,10 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, /* social scan on P2P_DEVICE is handled as p2p search */ if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE && wil_p2p_is_social_scan(request)) { + if (!wil->p2p.p2p_dev_started) { + wil_err(wil, "P2P search requested on stopped P2P device\n"); + return -EIO; + } wil->scan_request = request; wil->radio_wdev = wdev; rc = wil_p2p_search(wil, request); @@ -1351,6 +1355,7 @@ static int wil_cfg80211_start_p2p_device(struct wiphy *wiphy, struct wil6210_priv *wil = wiphy_to_wil(wiphy); wil_dbg_misc(wil, "%s: entered\n", __func__); + wil->p2p.p2p_dev_started = 1; return 0; } @@ -1358,8 +1363,19 @@ static void wil_cfg80211_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); + u8 started; wil_dbg_misc(wil, "%s: entered\n", __func__); + mutex_lock(&wil->mutex); + started = wil_p2p_stop_discovery(wil); + if (started && wil->scan_request) { + cfg80211_scan_done(wil->scan_request, 1); + wil->scan_request = NULL; + wil->radio_wdev = wil->wdev; + } + mutex_unlock(&wil->mutex); + + wil->p2p.p2p_dev_started = 0; } static struct cfg80211_ops wil_cfg80211_ops = { diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 2a05031ba631..bd4c17ca2484 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -14,10 +14,15 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <linux/moduleparam.h> #include <linux/etherdevice.h> #include "wil6210.h" #include "txrx.h" +static bool alt_ifname; /* = false; */ +module_param(alt_ifname, bool, S_IRUGO); +MODULE_PARM_DESC(alt_ifname, " use an alternate interface name wigigN instead of wlanN"); + static int wil_open(struct net_device *ndev) { struct wil6210_priv *wil = ndev_to_wil(ndev); @@ -136,6 +141,7 @@ void *wil_if_alloc(struct device *dev) struct wil6210_priv *wil; struct ieee80211_channel *ch; int rc = 0; + const char *ifname = alt_ifname ? "wigig%d" : "wlan%d"; wdev = wil_cfg80211_init(dev); if (IS_ERR(wdev)) { @@ -160,7 +166,7 @@ void *wil_if_alloc(struct device *dev) ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels; cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT); - ndev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, wil_dev_setup); + ndev = alloc_netdev(0, ifname, NET_NAME_UNKNOWN, wil_dev_setup); if (!ndev) { dev_err(dev, "alloc_netdev_mqs failed\n"); rc = -ENOMEM; diff --git a/drivers/net/wireless/ath/wil6210/p2p.c b/drivers/net/wireless/ath/wil6210/p2p.c index 1c9153894dca..213b8259638c 100644 --- a/drivers/net/wireless/ath/wil6210/p2p.c +++ b/drivers/net/wireless/ath/wil6210/p2p.c @@ -114,8 +114,10 @@ int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration, u8 channel = P2P_DMG_SOCIAL_CHANNEL; int rc; - if (chan) - channel = chan->hw_value; + if (!chan) + return -EINVAL; + + channel = chan->hw_value; wil_dbg_misc(wil, "%s: duration %d\n", __func__, duration); diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index a67725419c76..cd0bfdf34248 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -461,6 +461,7 @@ struct wil_tid_crypto_rx { struct wil_p2p_info { struct ieee80211_channel listen_chan; u8 discovery_started; + u8 p2p_dev_started; u64 cookie; struct timer_list discovery_timer; /* listen/search duration */ struct work_struct discovery_expired_work; /* listen/search expire */ diff --git a/drivers/net/wireless/cnss/cnss_common.c b/drivers/net/wireless/cnss/cnss_common.c index 3639d3245077..498dd87e1a91 100644 --- a/drivers/net/wireless/cnss/cnss_common.c +++ b/drivers/net/wireless/cnss/cnss_common.c @@ -21,7 +21,7 @@ #include <linux/mutex.h> #include <linux/rwsem.h> #include <net/cnss.h> -#include <net/cnss_common.h> +#include "cnss_common.h" #include <net/cfg80211.h> enum cnss_dev_bus_type { diff --git a/drivers/net/wireless/cnss/cnss_common.h b/drivers/net/wireless/cnss/cnss_common.h new file mode 100644 index 000000000000..db5ed02d47ab --- /dev/null +++ b/drivers/net/wireless/cnss/cnss_common.h @@ -0,0 +1,40 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _NET_CNSS_COMMON_H_ +#define _NET_CNSS_COMMON_H_ + +#define MAX_FIRMWARE_SIZE (1 * 1024 * 1024) +/* max 20mhz channel count */ +#define CNSS_MAX_CH_NUM 45 + +int cnss_pci_request_bus_bandwidth(int bandwidth); +int cnss_sdio_request_bus_bandwidth(int bandwidth); + +void cnss_sdio_device_crashed(void); +void cnss_pci_device_crashed(void); + +void cnss_pci_device_self_recovery(void); +void cnss_sdio_device_self_recovery(void); + +void *cnss_pci_get_virt_ramdump_mem(unsigned long *size); +void *cnss_sdio_get_virt_ramdump_mem(unsigned long *size); + +void cnss_sdio_schedule_recovery_work(void); +void cnss_pci_schedule_recovery_work(void); + +int cnss_pcie_set_wlan_mac_address(const u8 *in, uint32_t len); +int cnss_sdio_set_wlan_mac_address(const u8 *in, uint32_t len); + +u8 *cnss_pci_get_wlan_mac_address(uint32_t *num); +u8 *cnss_sdio_get_wlan_mac_address(uint32_t *num); +#endif /* _NET_CNSS_COMMON_H_ */ diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c index 322de8b58cd5..daa7f65690db 100644 --- a/drivers/net/wireless/cnss/cnss_pci.c +++ b/drivers/net/wireless/cnss/cnss_pci.c @@ -48,7 +48,7 @@ #include <net/cfg80211.h> #include <soc/qcom/memory_dump.h> #include <net/cnss.h> -#include <net/cnss_common.h> +#include "cnss_common.h" #ifdef CONFIG_WCNSS_MEM_PRE_ALLOC #include <net/cnss_prealloc.h> @@ -2059,7 +2059,6 @@ end: *num = 0; return NULL; } -EXPORT_SYMBOL(cnss_pci_get_wlan_mac_address); /** * cnss_get_wlan_mac_address() - API to return MAC addresses buffer @@ -2149,7 +2148,6 @@ int cnss_pcie_set_wlan_mac_address(const u8 *in, uint32_t len) } return 0; } -EXPORT_SYMBOL(cnss_pcie_set_wlan_mac_address); int cnss_wlan_register_driver(struct cnss_wlan_driver *driver) { diff --git a/drivers/net/wireless/cnss/cnss_sdio.c b/drivers/net/wireless/cnss/cnss_sdio.c index e8833e499bcd..bb64e2149742 100644 --- a/drivers/net/wireless/cnss/cnss_sdio.c +++ b/drivers/net/wireless/cnss/cnss_sdio.c @@ -27,7 +27,7 @@ #include <soc/qcom/ramdump.h> #include <soc/qcom/memory_dump.h> #include <net/cnss.h> -#include <net/cnss_common.h> +#include "cnss_common.h" #include <linux/pm_qos.h> #include <linux/msm-bus.h> #include <linux/msm-bus-board.h> @@ -1161,14 +1161,12 @@ int cnss_sdio_set_wlan_mac_address(const u8 *in, uint32_t len) { return 0; } -EXPORT_SYMBOL(cnss_sdio_set_wlan_mac_address); u8 *cnss_sdio_get_wlan_mac_address(uint32_t *num) { *num = 0; return NULL; } -EXPORT_SYMBOL(cnss_sdio_get_wlan_mac_address); static const struct of_device_id cnss_sdio_dt_match[] = { {.compatible = "qcom,cnss_sdio"}, diff --git a/drivers/net/wireless/iwlwifi/dvm/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c index e18629a16fb0..0961f33de05e 100644 --- a/drivers/net/wireless/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/iwlwifi/dvm/lib.c @@ -1154,6 +1154,9 @@ int iwlagn_suspend(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan) priv->ucode_loaded = false; iwl_trans_stop_device(priv->trans); + ret = iwl_trans_start_hw(priv->trans); + if (ret) + goto out; priv->wowlan = true; diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index d6e0c1b5c20c..8215d7405f64 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -1267,6 +1267,10 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, return -EBUSY; } + /* we don't support "match all" in the firmware */ + if (!req->n_match_sets) + return -EOPNOTSUPP; + ret = iwl_mvm_check_running_scans(mvm, type); if (ret) return ret; diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index c652a66be803..6743edf43aa8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -421,6 +421,15 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) return -1; } + /* + * Increase the pending frames counter, so that later when a reply comes + * in and the counter is decreased - we don't start getting negative + * values. + * Note that we don't need to make sure it isn't agg'd, since we're + * TXing non-sta + */ + atomic_inc(&mvm->pending_frames[sta_id]); + return 0; } diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 639761fb2bfb..d58c094f2f04 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -384,6 +384,7 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x095B, 0x5310, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5302, iwl7265_n_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5210, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x5C10, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5012, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5412, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5410, iwl7265_2ac_cfg)}, @@ -401,10 +402,10 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x095A, 0x900A, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9110, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9112, iwl7265_2ac_cfg)}, - {IWL_PCI_DEVICE(0x095A, 0x9210, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095B, 0x9210, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x9200, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9510, iwl7265_2ac_cfg)}, - {IWL_PCI_DEVICE(0x095A, 0x9310, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095B, 0x9310, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9410, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5020, iwl7265_2n_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x502A, iwl7265_2n_cfg)}, diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 90283453073c..8c7204738aa3 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -7,6 +7,7 @@ * * Copyright(c) 2007 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@ * * Copyright(c) 2005 - 2015 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH + * Copyright(c) 2016 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -924,9 +926,16 @@ monitor: if (dest->monitor_mode == EXTERNAL_MODE && trans_pcie->fw_mon_size) { iwl_write_prph(trans, le32_to_cpu(dest->base_reg), trans_pcie->fw_mon_phys >> dest->base_shift); - iwl_write_prph(trans, le32_to_cpu(dest->end_reg), - (trans_pcie->fw_mon_phys + - trans_pcie->fw_mon_size) >> dest->end_shift); + if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) + iwl_write_prph(trans, le32_to_cpu(dest->end_reg), + (trans_pcie->fw_mon_phys + + trans_pcie->fw_mon_size - 256) >> + dest->end_shift); + else + iwl_write_prph(trans, le32_to_cpu(dest->end_reg), + (trans_pcie->fw_mon_phys + + trans_pcie->fw_mon_size) >> + dest->end_shift); } } diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index f46c9d7f6528..7f471bff435c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -801,7 +801,9 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) hw_queue); if (rx_remained_cnt == 0) return; - + buffer_desc = &rtlpci->rx_ring[rxring_idx].buffer_desc[ + rtlpci->rx_ring[rxring_idx].idx]; + pdesc = (struct rtl_rx_desc *)skb->data; } else { /* rx descriptor */ pdesc = &rtlpci->rx_ring[rxring_idx].desc[ rtlpci->rx_ring[rxring_idx].idx]; @@ -824,13 +826,6 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) new_skb = dev_alloc_skb(rtlpci->rxbuffersize); if (unlikely(!new_skb)) goto no_new; - if (rtlpriv->use_new_trx_flow) { - buffer_desc = - &rtlpci->rx_ring[rxring_idx].buffer_desc - [rtlpci->rx_ring[rxring_idx].idx]; - /*means rx wifi info*/ - pdesc = (struct rtl_rx_desc *)skb->data; - } memset(&rx_status , 0 , sizeof(rx_status)); rtlpriv->cfg->ops->query_rx_desc(hw, &stats, &rx_status, (u8 *)pdesc, skb); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c index 11344121c55e..47e32cb0ec1a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c @@ -88,8 +88,6 @@ int rtl88e_init_sw_vars(struct ieee80211_hw *hw) u8 tid; rtl8188ee_bt_reg_init(hw); - rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support; - rtlpriv->dm.dm_initialgain_enable = 1; rtlpriv->dm.dm_flag = 0; rtlpriv->dm.disable_framebursting = 0; @@ -138,6 +136,11 @@ int rtl88e_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; + rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support; + rtlpriv->cfg->mod_params->sw_crypto = + rtlpriv->cfg->mod_params->sw_crypto; + rtlpriv->cfg->mod_params->disable_watchdog = + rtlpriv->cfg->mod_params->disable_watchdog; if (rtlpriv->cfg->mod_params->disable_watchdog) pr_info("watchdog disabled\n"); if (!rtlpriv->psc.inactiveps) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c index de6cb6c3a48c..4780bdc63b2b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c @@ -139,6 +139,8 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; + rtlpriv->cfg->mod_params->sw_crypto = + rtlpriv->cfg->mod_params->sw_crypto; if (!rtlpriv->psc.inactiveps) pr_info("rtl8192ce: Power Save off (module option)\n"); if (!rtlpriv->psc.fwctrl_lps) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c index fd4a5353d216..7c6f7f0d18c6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c @@ -65,6 +65,8 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->dm.disable_framebursting = false; rtlpriv->dm.thermalvalue = 0; rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug; + rtlpriv->cfg->mod_params->sw_crypto = + rtlpriv->cfg->mod_params->sw_crypto; /* for firmware buf */ rtlpriv->rtlhal.pfirmware = vzalloc(0x4000); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c index b19d0398215f..c6e09a19de1a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c @@ -376,8 +376,8 @@ module_param_named(swlps, rtl92de_mod_params.swctrl_lps, bool, 0444); module_param_named(fwlps, rtl92de_mod_params.fwctrl_lps, bool, 0444); MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n"); MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n"); -MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); -MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); +MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 1)\n"); +MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 0)\n"); MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c index e1fd27c888bf..31baca41ac2f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c @@ -187,6 +187,8 @@ static int rtl92s_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; + rtlpriv->cfg->mod_params->sw_crypto = + rtlpriv->cfg->mod_params->sw_crypto; if (!rtlpriv->psc.inactiveps) pr_info("Power Save off (module option)\n"); if (!rtlpriv->psc.fwctrl_lps) @@ -425,8 +427,8 @@ module_param_named(swlps, rtl92se_mod_params.swctrl_lps, bool, 0444); module_param_named(fwlps, rtl92se_mod_params.fwctrl_lps, bool, 0444); MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n"); MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n"); -MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); -MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); +MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 1)\n"); +MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 0)\n"); MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c index 3859b3e3d158..ff49a8c0ff61 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c @@ -150,6 +150,11 @@ int rtl8723e_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; + rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support; + rtlpriv->cfg->mod_params->sw_crypto = + rtlpriv->cfg->mod_params->sw_crypto; + rtlpriv->cfg->mod_params->disable_watchdog = + rtlpriv->cfg->mod_params->disable_watchdog; if (rtlpriv->cfg->mod_params->disable_watchdog) pr_info("watchdog disabled\n"); rtlpriv->psc.reg_fwctrl_lps = 3; @@ -267,6 +272,8 @@ static struct rtl_mod_params rtl8723e_mod_params = { .swctrl_lps = false, .fwctrl_lps = true, .debug = DBG_EMERG, + .msi_support = false, + .disable_watchdog = false, }; static struct rtl_hal_cfg rtl8723e_hal_cfg = { @@ -383,12 +390,14 @@ module_param_named(debug, rtl8723e_mod_params.debug, int, 0444); module_param_named(ips, rtl8723e_mod_params.inactiveps, bool, 0444); module_param_named(swlps, rtl8723e_mod_params.swctrl_lps, bool, 0444); module_param_named(fwlps, rtl8723e_mod_params.fwctrl_lps, bool, 0444); +module_param_named(msi, rtl8723e_mod_params.msi_support, bool, 0444); module_param_named(disable_watchdog, rtl8723e_mod_params.disable_watchdog, bool, 0444); MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n"); MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n"); MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); +MODULE_PARM_DESC(msi, "Set to 1 to use MSI interrupts mode (default 0)\n"); MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); MODULE_PARM_DESC(disable_watchdog, "Set to 1 to disable the watchdog (default 0)\n"); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c index d091f1d5f91e..a78eaeda0008 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c @@ -93,7 +93,6 @@ int rtl8723be_init_sw_vars(struct ieee80211_hw *hw) struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); rtl8723be_bt_reg_init(hw); - rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support; rtlpriv->btcoexist.btc_ops = rtl_btc_get_ops_pointer(); rtlpriv->dm.dm_initialgain_enable = 1; @@ -151,6 +150,10 @@ int rtl8723be_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support; + rtlpriv->cfg->mod_params->sw_crypto = + rtlpriv->cfg->mod_params->sw_crypto; + rtlpriv->cfg->mod_params->disable_watchdog = + rtlpriv->cfg->mod_params->disable_watchdog; if (rtlpriv->cfg->mod_params->disable_watchdog) pr_info("watchdog disabled\n"); rtlpriv->psc.reg_fwctrl_lps = 3; @@ -267,6 +270,9 @@ static struct rtl_mod_params rtl8723be_mod_params = { .inactiveps = true, .swctrl_lps = false, .fwctrl_lps = true, + .msi_support = false, + .disable_watchdog = false, + .debug = DBG_EMERG, }; static struct rtl_hal_cfg rtl8723be_hal_cfg = { diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c index 86f3a4800d1d..3f9eeabc5464 100644 --- a/drivers/net/wireless/wcnss/wcnss_wlan.c +++ b/drivers/net/wireless/wcnss/wcnss_wlan.c @@ -3339,7 +3339,7 @@ static ssize_t wcnss_wlan_write(struct file *fp, const char __user return -EFAULT; if ((UINT32_MAX - count < penv->user_cal_rcvd) || - MAX_CALIBRATED_DATA_SIZE < count + penv->user_cal_rcvd) { + (penv->user_cal_exp_size < count + penv->user_cal_rcvd)) { pr_err(DEVICE " invalid size to write %zu\n", count + penv->user_cal_rcvd); rc = -ENOMEM; diff --git a/drivers/nfc/nq-nci.c b/drivers/nfc/nq-nci.c index 88011626e05e..918f8c82acdd 100644 --- a/drivers/nfc/nq-nci.c +++ b/drivers/nfc/nq-nci.c @@ -325,8 +325,10 @@ static int nqx_ese_pwr(struct nqx_dev *nqx_dev, unsigned long int arg) } else if (arg == 3) { if (!nqx_dev->nfc_ven_enabled) r = 0; - else - r = gpio_get_value(nqx_dev->ese_gpio); + else { + if (gpio_is_valid(nqx_dev->ese_gpio)) + r = gpio_get_value(nqx_dev->ese_gpio); + } } return r; } @@ -375,11 +377,14 @@ int nfc_ioctl_power_states(struct file *filp, unsigned long arg) __func__, nqx_dev); if (gpio_is_valid(nqx_dev->firm_gpio)) gpio_set_value(nqx_dev->firm_gpio, 0); - if (!gpio_get_value(nqx_dev->ese_gpio)) { - dev_dbg(&nqx_dev->client->dev, "disabling en_gpio\n"); - gpio_set_value(nqx_dev->en_gpio, 0); - } else { - dev_dbg(&nqx_dev->client->dev, "keeping en_gpio high\n"); + + if (gpio_is_valid(nqx_dev->ese_gpio)) { + if (!gpio_get_value(nqx_dev->ese_gpio)) { + dev_dbg(&nqx_dev->client->dev, "disabling en_gpio\n"); + gpio_set_value(nqx_dev->en_gpio, 0); + } else { + dev_dbg(&nqx_dev->client->dev, "keeping en_gpio high\n"); + } } r = nqx_clock_deselect(nqx_dev); if (r < 0) @@ -405,9 +410,11 @@ int nfc_ioctl_power_states(struct file *filp, unsigned long arg) * We are switching to Dowload Mode, toggle the enable pin * in order to set the NFCC in the new mode */ - if (gpio_get_value(nqx_dev->ese_gpio)) { - dev_err(&nqx_dev->client->dev, "FW download forbidden while ese is on\n"); - return -EBUSY; /* Device or resource busy */ + if (gpio_is_valid(nqx_dev->ese_gpio)) { + if (gpio_get_value(nqx_dev->ese_gpio)) { + dev_err(&nqx_dev->client->dev, "FW download forbidden while ese is on\n"); + return -EBUSY; /* Device or resource busy */ + } } gpio_set_value(nqx_dev->en_gpio, 1); msleep(20); @@ -828,6 +835,7 @@ static int nqx_probe(struct i2c_client *client, nqx_dev->en_gpio = platform_data->en_gpio; nqx_dev->irq_gpio = platform_data->irq_gpio; nqx_dev->firm_gpio = platform_data->firm_gpio; + nqx_dev->ese_gpio = platform_data->ese_gpio; nqx_dev->clkreq_gpio = platform_data->clkreq_gpio; nqx_dev->pdata = platform_data; diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 4fa916dffc91..72a2c1969646 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -636,6 +636,13 @@ static u32 __of_msi_map_rid(struct device *dev, struct device_node **np, msi_base = be32_to_cpup(msi_map + 2); rid_len = be32_to_cpup(msi_map + 3); + if (rid_base & ~map_mask) { + dev_err(parent_dev, + "Invalid msi-map translation - msi-map-mask (0x%x) ignores rid-base (0x%x)\n", + map_mask, rid_base); + return rid_out; + } + msi_controller_node = of_find_node_by_phandle(phandle); matched = (masked_rid >= rid_base && @@ -655,7 +662,7 @@ static u32 __of_msi_map_rid(struct device *dev, struct device_node **np, if (!matched) return rid_out; - rid_out = masked_rid + msi_base; + rid_out = masked_rid - rid_base + msi_base; dev_dbg(dev, "msi-map at: %s, using mask %08x, rid-base: %08x, msi-base: %08x, length: %08x, rid: %08x -> %08x\n", dev_name(parent_dev), map_mask, rid_base, msi_base, diff --git a/drivers/of/of_batterydata.c b/drivers/of/of_batterydata.c index 5f140cd0c2a6..4410f270f557 100644 --- a/drivers/of/of_batterydata.c +++ b/drivers/of/of_batterydata.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -312,32 +312,15 @@ static int64_t of_batterydata_convert_battery_id_kohm(int batt_id_uv, struct device_node *of_batterydata_get_best_profile( const struct device_node *batterydata_container_node, - const char *psy_name, const char *batt_type) + int batt_id_kohm, const char *batt_type) { struct batt_ids batt_ids; struct device_node *node, *best_node = NULL; - struct power_supply *psy; const char *battery_type = NULL; - union power_supply_propval ret = {0, }; int delta = 0, best_delta = 0, best_id_kohm = 0, id_range_pct, - batt_id_kohm = 0, i = 0, rc = 0, limit = 0; + i = 0, rc = 0, limit = 0; bool in_range = false; - psy = power_supply_get_by_name(psy_name); - if (!psy) { - pr_err("%s supply not found. defer\n", psy_name); - return ERR_PTR(-EPROBE_DEFER); - } - - rc = power_supply_get_property(psy, POWER_SUPPLY_PROP_RESISTANCE_ID, - &ret); - if (rc) { - pr_err("failed to retrieve resistance value rc=%d\n", rc); - return ERR_PTR(-ENOSYS); - } - - batt_id_kohm = ret.intval / 1000; - /* read battery id range percentage for best profile */ rc = of_property_read_u32(batterydata_container_node, "qcom,batt-id-range-pct", &id_range_pct); diff --git a/drivers/pci/host/pci-keystone-dw.c b/drivers/pci/host/pci-keystone-dw.c index ed34c9520a02..6153853ca9c3 100644 --- a/drivers/pci/host/pci-keystone-dw.c +++ b/drivers/pci/host/pci-keystone-dw.c @@ -58,11 +58,6 @@ #define to_keystone_pcie(x) container_of(x, struct keystone_pcie, pp) -static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys) -{ - return sys->private_data; -} - static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset, u32 *bit_pos) { @@ -108,7 +103,7 @@ static void ks_dw_pcie_msi_irq_ack(struct irq_data *d) struct pcie_port *pp; msi = irq_data_get_msi_desc(d); - pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi)); + pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi); ks_pcie = to_keystone_pcie(pp); offset = d->irq - irq_linear_revmap(pp->irq_domain, 0); update_reg_offset_bit_pos(offset, ®_offset, &bit_pos); @@ -146,7 +141,7 @@ static void ks_dw_pcie_msi_irq_mask(struct irq_data *d) u32 offset; msi = irq_data_get_msi_desc(d); - pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi)); + pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi); ks_pcie = to_keystone_pcie(pp); offset = d->irq - irq_linear_revmap(pp->irq_domain, 0); @@ -167,7 +162,7 @@ static void ks_dw_pcie_msi_irq_unmask(struct irq_data *d) u32 offset; msi = irq_data_get_msi_desc(d); - pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi)); + pp = (struct pcie_port *) msi_desc_to_pci_sysdata(msi); ks_pcie = to_keystone_pcie(pp); offset = d->irq - irq_linear_revmap(pp->irq_domain, 0); diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index a5d627a89c31..e278aab1e530 100644 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -2342,6 +2342,9 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev, if (!base_sel) { PCIE_DBG_FS(dev, "Invalid base_sel: 0x%x\n", base_sel); break; + } else if (base_sel - 1 == MSM_PCIE_RES_PARF) { + pcie_parf_dump(dev); + break; } else if (base_sel - 1 == MSM_PCIE_RES_PHY) { pcie_phy_dump(dev); break; diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index ff538568a617..0b3e0bfa7be5 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -953,8 +953,10 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot) { pci_lock_rescan_remove(); - if (slot->flags & SLOT_IS_GOING_AWAY) + if (slot->flags & SLOT_IS_GOING_AWAY) { + pci_unlock_rescan_remove(); return -ENODEV; + } /* configure all functions */ if (!(slot->flags & SLOT_ENABLED)) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 314db8c1047a..42d8617352ae 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4772,8 +4772,10 @@ int pci_get_new_domain_nr(void) void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent) { static int use_dt_domains = -1; - int domain = of_get_pci_domain_nr(parent->of_node); + int domain = -1; + if (parent) + domain = of_get_pci_domain_nr(parent->of_node); /* * Check DT domain and use_dt_domains values. * diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index 0bf82a20a0fb..48d21e0edd56 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c @@ -262,7 +262,6 @@ static struct aer_rpc *aer_alloc_rpc(struct pcie_device *dev) rpc->rpd = dev; INIT_WORK(&rpc->dpc_handler, aer_isr); mutex_init(&rpc->rpc_mutex); - init_waitqueue_head(&rpc->wait_release); /* Use PCIe bus function to store rpc into PCIe device */ set_service_data(dev, rpc); @@ -285,8 +284,7 @@ static void aer_remove(struct pcie_device *dev) if (rpc->isr) free_irq(dev->irq, dev); - wait_event(rpc->wait_release, rpc->prod_idx == rpc->cons_idx); - + flush_work(&rpc->dpc_handler); aer_disable_rootport(rpc); kfree(rpc); set_service_data(dev, NULL); diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h index 84420b7c9456..945c939a86c5 100644 --- a/drivers/pci/pcie/aer/aerdrv.h +++ b/drivers/pci/pcie/aer/aerdrv.h @@ -72,7 +72,6 @@ struct aer_rpc { * recovery on the same * root port hierarchy */ - wait_queue_head_t wait_release; }; struct aer_broadcast_data { diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index fba785e9df75..4e14de0f0f98 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -811,8 +811,6 @@ void aer_isr(struct work_struct *work) while (get_e_source(rpc, &e_src)) aer_isr_one_error(p_device, &e_src); mutex_unlock(&rpc->rpc_mutex); - - wake_up(&rpc->wait_release); } /** diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index c777b97207d5..5f70fee59a94 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -53,7 +53,7 @@ struct pcifront_device { }; struct pcifront_sd { - int domain; + struct pci_sysdata sd; struct pcifront_device *pdev; }; @@ -67,7 +67,9 @@ static inline void pcifront_init_sd(struct pcifront_sd *sd, unsigned int domain, unsigned int bus, struct pcifront_device *pdev) { - sd->domain = domain; + /* Because we do not expose that information via XenBus. */ + sd->sd.node = first_online_node; + sd->sd.domain = domain; sd->pdev = pdev; } @@ -468,8 +470,8 @@ static int pcifront_scan_root(struct pcifront_device *pdev, dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n", domain, bus); - bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL); - sd = kmalloc(sizeof(*sd), GFP_KERNEL); + bus_entry = kzalloc(sizeof(*bus_entry), GFP_KERNEL); + sd = kzalloc(sizeof(*sd), GFP_KERNEL); if (!bus_entry || !sd) { err = -ENOMEM; goto err_out; diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index 8c7f27db6ad3..e7e574dc667a 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -275,20 +275,21 @@ EXPORT_SYMBOL_GPL(phy_exit); int phy_power_on(struct phy *phy) { - int ret; + int ret = 0; if (!phy) - return 0; + goto out; if (phy->pwr) { ret = regulator_enable(phy->pwr); if (ret) - return ret; + goto out; } ret = phy_pm_runtime_get_sync(phy); if (ret < 0 && ret != -ENOTSUPP) - return ret; + goto err_pm_sync; + ret = 0; /* Override possible ret == -ENOTSUPP */ mutex_lock(&phy->mutex); @@ -296,19 +297,20 @@ int phy_power_on(struct phy *phy) ret = phy->ops->power_on(phy); if (ret < 0) { dev_err(&phy->dev, "phy poweron failed --> %d\n", ret); - goto out; + goto err_pwr_on; } } ++phy->power_count; mutex_unlock(&phy->mutex); return 0; -out: +err_pwr_on: mutex_unlock(&phy->mutex); phy_pm_runtime_put_sync(phy); +err_pm_sync: if (phy->pwr) regulator_disable(phy->pwr); - +out: return ret; } EXPORT_SYMBOL_GPL(phy_power_on); diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index b9819b929a91..4805c4feac74 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -120,4 +120,11 @@ config PINCTRL_MSMFALCON This is the pinctrl, pinmux, pinconf and gpiolib driver for the Qualcomm TLMM block found in the Qualcomm MSMFALCON platform. +config PINCTRL_WCD + tristate "Qualcomm Technologies, Inc WCD pin controller driver" + depends on WCD934X_CODEC + help + This is the pinctrl, pinmux, pinconf and gpiolib driver for the + WCD gpio controller block. + endif diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 0d390906ea00..bddc21431eeb 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -15,3 +15,4 @@ obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-mpp.o obj-$(CONFIG_PINCTRL_MSM8996) += pinctrl-msm8996.o obj-$(CONFIG_PINCTRL_MSMCOBALT) += pinctrl-msmcobalt.o obj-$(CONFIG_PINCTRL_MSMFALCON) += pinctrl-msmfalcon.o +obj-$(CONFIG_PINCTRL_WCD) += pinctrl-wcd.o diff --git a/drivers/pinctrl/qcom/pinctrl-wcd.c b/drivers/pinctrl/qcom/pinctrl-wcd.c new file mode 100644 index 000000000000..08d87f7452eb --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-wcd.c @@ -0,0 +1,443 @@ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/gpio.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinmux.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/mfd/wcd934x/registers.h> + +#include "../core.h" +#include "../pinctrl-utils.h" + +#define WCD_REG_DIR_CTL WCD934X_CHIP_TIER_CTRL_GPIO_CTL_OE +#define WCD_REG_VAL_CTL WCD934X_CHIP_TIER_CTRL_GPIO_CTL_DATA +#define WCD_GPIO_PULL_UP 1 +#define WCD_GPIO_PULL_DOWN 2 +#define WCD_GPIO_BIAS_DISABLE 3 +#define WCD_GPIO_STRING_LEN 20 + +/** + * struct wcd_gpio_pad - keep current GPIO settings + * @offset: offset of gpio. + * @is_valid: Set to false, when GPIO in high Z state. + * @value: value of a pin + * @output_enabled: Set to true if GPIO is output and false if it is input + * @pullup: Constant current which flow through GPIO output buffer. + * @strength: Drive strength of a pin + */ +struct wcd_gpio_pad { + u16 offset; + bool is_valid; + bool value; + bool output_enabled; + unsigned int pullup; + unsigned int strength; +}; + +struct wcd_gpio_priv { + struct device *dev; + struct regmap *map; + struct pinctrl_dev *ctrl; + struct gpio_chip chip; +}; + +static inline struct wcd_gpio_priv *to_gpio_state(struct gpio_chip *chip) +{ + return container_of(chip, struct wcd_gpio_priv, chip); +}; + +static int wcd_gpio_read(struct wcd_gpio_priv *priv_data, + struct wcd_gpio_pad *pad, unsigned int addr) +{ + unsigned int val; + int ret; + + ret = regmap_read(priv_data->map, addr, &val); + if (ret < 0) + dev_err(priv_data->dev, "%s: read 0x%x failed\n", + __func__, addr); + else + ret = (val >> pad->offset); + + return ret; +} + +static int wcd_gpio_write(struct wcd_gpio_priv *priv_data, + struct wcd_gpio_pad *pad, unsigned int addr, + unsigned int val) +{ + int ret; + + ret = regmap_update_bits(priv_data->map, addr, (1 << pad->offset), + val << pad->offset); + if (ret < 0) + dev_err(priv_data->dev, "write 0x%x failed\n", addr); + + return ret; +} + +static int wcd_get_groups_count(struct pinctrl_dev *pctldev) +{ + return pctldev->desc->npins; +} + +static const char *wcd_get_group_name(struct pinctrl_dev *pctldev, + unsigned pin) +{ + return pctldev->desc->pins[pin].name; +} + +static int wcd_get_group_pins(struct pinctrl_dev *pctldev, unsigned pin, + const unsigned **pins, unsigned *num_pins) +{ + *pins = &pctldev->desc->pins[pin].number; + *num_pins = 1; + return 0; +} + +static const struct pinctrl_ops wcd_pinctrl_ops = { + .get_groups_count = wcd_get_groups_count, + .get_group_name = wcd_get_group_name, + .get_group_pins = wcd_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_group, + .dt_free_map = pinctrl_utils_dt_free_map, +}; + +static int wcd_config_get(struct pinctrl_dev *pctldev, + unsigned int pin, unsigned long *config) +{ + unsigned param = pinconf_to_config_param(*config); + struct wcd_gpio_pad *pad; + unsigned arg; + + pad = pctldev->desc->pins[pin].drv_data; + + switch (param) { + case PIN_CONFIG_BIAS_PULL_DOWN: + arg = pad->pullup == WCD_GPIO_PULL_DOWN; + break; + case PIN_CONFIG_BIAS_DISABLE: + arg = pad->pullup = WCD_GPIO_BIAS_DISABLE; + break; + case PIN_CONFIG_BIAS_PULL_UP: + arg = pad->pullup == WCD_GPIO_PULL_UP; + break; + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + arg = !pad->is_valid; + break; + case PIN_CONFIG_INPUT_ENABLE: + arg = pad->output_enabled; + break; + case PIN_CONFIG_OUTPUT: + arg = pad->value; + break; + default: + return -EINVAL; + } + + *config = pinconf_to_config_packed(param, arg); + return 0; +} + +static int wcd_config_set(struct pinctrl_dev *pctldev, unsigned int pin, + unsigned long *configs, unsigned nconfs) +{ + struct wcd_gpio_priv *priv_data = pinctrl_dev_get_drvdata(pctldev); + struct wcd_gpio_pad *pad; + unsigned param, arg; + int i, ret; + + pad = pctldev->desc->pins[pin].drv_data; + + for (i = 0; i < nconfs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + + dev_dbg(priv_data->dev, "%s: param: %d arg: %d", + __func__, param, arg); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + pad->pullup = WCD_GPIO_BIAS_DISABLE; + break; + case PIN_CONFIG_BIAS_PULL_UP: + pad->pullup = WCD_GPIO_PULL_UP; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + pad->pullup = WCD_GPIO_PULL_DOWN; + break; + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + pad->is_valid = false; + break; + case PIN_CONFIG_INPUT_ENABLE: + pad->output_enabled = false; + break; + case PIN_CONFIG_OUTPUT: + pad->output_enabled = true; + pad->value = arg; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + pad->strength = arg; + break; + default: + ret = -EINVAL; + goto done; + } + } + + if (pad->output_enabled) { + ret = wcd_gpio_write(priv_data, pad, WCD_REG_DIR_CTL, + pad->output_enabled); + if (ret < 0) + goto done; + ret = wcd_gpio_write(priv_data, pad, WCD_REG_VAL_CTL, + pad->value); + } else + ret = wcd_gpio_write(priv_data, pad, WCD_REG_DIR_CTL, + pad->output_enabled); +done: + return ret; +} + +static const struct pinconf_ops wcd_pinconf_ops = { + .is_generic = true, + .pin_config_group_get = wcd_config_get, + .pin_config_group_set = wcd_config_set, +}; + +static int wcd_gpio_direction_input(struct gpio_chip *chip, unsigned pin) +{ + struct wcd_gpio_priv *priv_data = to_gpio_state(chip); + unsigned long config; + + config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1); + + return wcd_config_set(priv_data->ctrl, pin, &config, 1); +} + +static int wcd_gpio_direction_output(struct gpio_chip *chip, + unsigned pin, int val) +{ + struct wcd_gpio_priv *priv_data = to_gpio_state(chip); + unsigned long config; + + config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val); + + return wcd_config_set(priv_data->ctrl, pin, &config, 1); +} + +static int wcd_gpio_get(struct gpio_chip *chip, unsigned pin) +{ + struct wcd_gpio_priv *priv_data = to_gpio_state(chip); + struct wcd_gpio_pad *pad; + int value; + + pad = priv_data->ctrl->desc->pins[pin].drv_data; + + if (!pad->is_valid) + return -EINVAL; + + value = wcd_gpio_read(priv_data, pad, WCD_REG_VAL_CTL); + return value; +} + +static void wcd_gpio_set(struct gpio_chip *chip, unsigned pin, int value) +{ + struct wcd_gpio_priv *priv_data = to_gpio_state(chip); + unsigned long config; + + config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value); + + wcd_config_set(priv_data->ctrl, pin, &config, 1); +} + +static const struct gpio_chip wcd_gpio_chip = { + .direction_input = wcd_gpio_direction_input, + .direction_output = wcd_gpio_direction_output, + .get = wcd_gpio_get, + .set = wcd_gpio_set, +}; + +static int wcd_pinctrl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct pinctrl_pin_desc *pindesc; + struct pinctrl_desc *pctrldesc; + struct wcd_gpio_pad *pad, *pads; + struct wcd_gpio_priv *priv_data; + int ret, i, j; + u32 npins; + char **name; + + ret = of_property_read_u32(dev->of_node, "qcom,num-gpios", &npins); + if (ret) { + dev_err(dev, "%s: Looking up %s property in node %s failed\n", + __func__, "qcom,num-gpios", dev->of_node->full_name); + ret = -EINVAL; + goto err_priv_alloc; + } + if (!npins) { + dev_err(dev, "%s: no.of pins are 0\n", __func__); + ret = -EINVAL; + goto err_priv_alloc; + } + + priv_data = devm_kzalloc(dev, sizeof(*priv_data), GFP_KERNEL); + if (!priv_data) { + ret = -ENOMEM; + goto err_priv_alloc; + } + + priv_data->dev = dev; + priv_data->map = dev_get_regmap(dev->parent, NULL); + if (!priv_data->map) { + dev_err(dev, "%s: failed to get regmap\n", __func__); + ret = -EINVAL; + goto err_regmap; + } + + pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL); + if (!pindesc) { + ret = -ENOMEM; + goto err_pinsec_alloc; + } + + pads = devm_kcalloc(dev, npins, sizeof(*pads), GFP_KERNEL); + if (!pads) { + ret = -ENOMEM; + goto err_pads_alloc; + } + + pctrldesc = devm_kzalloc(dev, sizeof(*pctrldesc), GFP_KERNEL); + if (!pctrldesc) { + ret = -ENOMEM; + goto err_pinctrl_alloc; + } + + pctrldesc->pctlops = &wcd_pinctrl_ops; + pctrldesc->confops = &wcd_pinconf_ops; + pctrldesc->owner = THIS_MODULE; + pctrldesc->name = dev_name(dev); + pctrldesc->pins = pindesc; + pctrldesc->npins = npins; + + name = devm_kcalloc(dev, npins, sizeof(char *), GFP_KERNEL); + if (!name) { + ret = -ENOMEM; + goto err_name_alloc; + } + for (i = 0; i < npins; i++, pindesc++) { + name[i] = devm_kzalloc(dev, sizeof(char) * WCD_GPIO_STRING_LEN, + GFP_KERNEL); + if (!name[i]) { + ret = -ENOMEM; + goto err_pin; + } + pad = &pads[i]; + pindesc->drv_data = pad; + pindesc->number = i; + snprintf(name[i], (WCD_GPIO_STRING_LEN - 1), "gpio%d", (i+1)); + pindesc->name = name[i]; + pad->offset = i; + pad->is_valid = true; + } + + priv_data->chip = wcd_gpio_chip; + priv_data->chip.dev = dev; + priv_data->chip.base = -1; + priv_data->chip.ngpio = npins; + priv_data->chip.label = dev_name(dev); + priv_data->chip.of_gpio_n_cells = 2; + priv_data->chip.can_sleep = false; + + priv_data->ctrl = pinctrl_register(pctrldesc, dev, priv_data); + if (IS_ERR(priv_data->ctrl)) { + dev_err(dev, "%s: failed to register to pinctrl\n", __func__); + ret = PTR_ERR(priv_data->ctrl); + goto err_pin; + } + + ret = gpiochip_add(&priv_data->chip); + if (ret) { + dev_err(dev, "%s: can't add gpio chip\n", __func__); + goto err_chip; + } + + ret = gpiochip_add_pin_range(&priv_data->chip, dev_name(dev), 0, 0, + npins); + if (ret) { + dev_err(dev, "%s: failed to add pin range\n", __func__); + goto err_range; + } + platform_set_drvdata(pdev, priv_data); + + return 0; + +err_range: + gpiochip_remove(&priv_data->chip); +err_chip: + pinctrl_unregister(priv_data->ctrl); +err_pin: + for (j = 0; j < i; j++) + devm_kfree(dev, name[j]); + devm_kfree(dev, name); +err_name_alloc: + devm_kfree(dev, pctrldesc); +err_pinctrl_alloc: + devm_kfree(dev, pads); +err_pads_alloc: + devm_kfree(dev, pindesc); +err_pinsec_alloc: +err_regmap: + devm_kfree(dev, priv_data); +err_priv_alloc: + return ret; +} + +static int wcd_pinctrl_remove(struct platform_device *pdev) +{ + struct wcd_gpio_priv *priv_data = platform_get_drvdata(pdev); + + gpiochip_remove(&priv_data->chip); + pinctrl_unregister(priv_data->ctrl); + + return 0; +} + +static const struct of_device_id wcd_pinctrl_of_match[] = { + { .compatible = "qcom,wcd-pinctrl" }, + { }, +}; + +MODULE_DEVICE_TABLE(of, wcd_pinctrl_of_match); + +static struct platform_driver wcd_pinctrl_driver = { + .driver = { + .name = "qcom-wcd-pinctrl", + .of_match_table = wcd_pinctrl_of_match, + }, + .probe = wcd_pinctrl_probe, + .remove = wcd_pinctrl_remove, +}; + +module_platform_driver(wcd_pinctrl_driver); + +MODULE_DESCRIPTION("Qualcomm Technologies, Inc WCD GPIO pin control driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/platform/msm/ipa/ipa_rm.c b/drivers/platform/msm/ipa/ipa_rm.c index a9813311f156..bf6352452283 100644 --- a/drivers/platform/msm/ipa/ipa_rm.c +++ b/drivers/platform/msm/ipa/ipa_rm.c @@ -986,6 +986,8 @@ int ipa_rm_stat(char *buf, int size) unsigned long flags; int i, cnt = 0, result = EINVAL; struct ipa_rm_resource *resource = NULL; + u32 sum_bw_prod = 0; + u32 sum_bw_cons = 0; if (!buf || size < 0) return result; @@ -1005,6 +1007,24 @@ int ipa_rm_stat(char *buf, int size) cnt += result; } } + + for (i = 0; i < IPA_RM_RESOURCE_PROD_MAX; i++) + sum_bw_prod += ipa_rm_ctx->prof_vote.bw_prods[i]; + + for (i = 0; i < IPA_RM_RESOURCE_CONS_MAX; i++) + sum_bw_cons += ipa_rm_ctx->prof_vote.bw_cons[i]; + + result = scnprintf(buf + cnt, size - cnt, + "All prod bandwidth: %d, All cons bandwidth: %d\n", + sum_bw_prod, sum_bw_cons); + cnt += result; + + result = scnprintf(buf + cnt, size - cnt, + "Voting: voltage %d, bandwidth %d\n", + ipa_rm_ctx->prof_vote.curr_volt, + ipa_rm_ctx->prof_vote.curr_bw); + cnt += result; + result = cnt; bail: spin_unlock_irqrestore(&ipa_rm_ctx->ipa_rm_lock, flags); diff --git a/drivers/platform/msm/ipa/ipa_rm_inactivity_timer.c b/drivers/platform/msm/ipa/ipa_rm_inactivity_timer.c index 2f2cef05441d..8e33d7164dd6 100644 --- a/drivers/platform/msm/ipa/ipa_rm_inactivity_timer.c +++ b/drivers/platform/msm/ipa/ipa_rm_inactivity_timer.c @@ -78,7 +78,7 @@ static void ipa_rm_inactivity_timer_func(struct work_struct *work) if (ipa_rm_it_handles[me->resource_name].reschedule_work) { IPA_RM_DBG_LOW("%s: setting delayed work\n", __func__); ipa_rm_it_handles[me->resource_name].reschedule_work = false; - schedule_delayed_work( + queue_delayed_work(system_unbound_wq, &ipa_rm_it_handles[me->resource_name].work, ipa_rm_it_handles[me->resource_name].jiffies); } else if (ipa_rm_it_handles[me->resource_name].resource_requested) { @@ -262,7 +262,8 @@ int ipa_rm_inactivity_timer_release_resource( ipa_rm_it_handles[resource_name].work_in_progress = true; ipa_rm_it_handles[resource_name].reschedule_work = false; IPA_RM_DBG_LOW("%s: setting delayed work\n", __func__); - schedule_delayed_work(&ipa_rm_it_handles[resource_name].work, + queue_delayed_work(system_unbound_wq, + &ipa_rm_it_handles[resource_name].work, ipa_rm_it_handles[resource_name].jiffies); spin_unlock_irqrestore(&ipa_rm_it_handles[resource_name].lock, flags); diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.c b/drivers/platform/msm/ipa/ipa_rm_resource.c index cc00f8cf7fb6..0a3f66307eee 100644 --- a/drivers/platform/msm/ipa/ipa_rm_resource.c +++ b/drivers/platform/msm/ipa/ipa_rm_resource.c @@ -1133,7 +1133,7 @@ int ipa_rm_resource_producer_print_stat( nbytes = scnprintf(buf + cnt, size - cnt, ipa_rm_resource_str(resource->name)); cnt += nbytes; - nbytes = scnprintf(buf + cnt, size - cnt, "["); + nbytes = scnprintf(buf + cnt, size - cnt, "[%d, ", resource->max_bw); cnt += nbytes; switch (resource->state) { @@ -1170,7 +1170,8 @@ int ipa_rm_resource_producer_print_stat( nbytes = scnprintf(buf + cnt, size - cnt, ipa_rm_resource_str(consumer->name)); cnt += nbytes; - nbytes = scnprintf(buf + cnt, size - cnt, "["); + nbytes = scnprintf(buf + cnt, size - cnt, "[%d, ", + consumer->max_bw); cnt += nbytes; switch (consumer->state) { diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c index 761aa6f9a4a1..790a0b41147e 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c @@ -485,6 +485,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, struct ipa_hdr_proc_ctx_tbl *htbl = &ipa_ctx->hdr_proc_ctx_tbl; int id; int needed_len; + int mem_size; IPADBG("processing type %d hdr_hdl %d\n", proc_ctx->type, proc_ctx->hdr_hdl); @@ -529,6 +530,14 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, goto bad_len; } + mem_size = (ipa_ctx->hdr_proc_ctx_tbl_lcl) ? + IPA_MEM_PART(apps_hdr_proc_ctx_size) : + IPA_MEM_PART(apps_hdr_proc_ctx_size_ddr); + if (htbl->end + ipa_hdr_proc_ctx_bin_sz[bin] > mem_size) { + IPAERR("hdr proc ctx table overflow\n"); + goto bad_len; + } + if (list_empty(&htbl->head_free_offset_list[bin])) { offset = kmem_cache_zalloc(ipa_ctx->hdr_proc_ctx_offset_cache, GFP_KERNEL); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 747ae3d82b68..c553be1ad717 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -218,6 +218,7 @@ static struct { bool disable_htw; bool fast_map; bool s1_bypass; + bool use_64_bit_dma_mask; u32 ipa_base; u32 ipa_size; } smmu_info; @@ -3961,7 +3962,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, goto fail_bind; } - result = ipa3_init_mem_partition(ipa_dev->of_node); + result = ipa3_init_mem_partition(master_dev->of_node); if (result) { IPAERR(":ipa3_init_mem_partition failed!\n"); result = -ENODEV; @@ -4715,7 +4716,7 @@ static int ipa_smmu_uc_cb_probe(struct device *dev) cb->va_end = cb->va_start + cb->va_size; IPADBG("UC va_start=0x%x va_sise=0x%x\n", cb->va_start, cb->va_size); - if (ipa3_ctx->use_64_bit_dma_mask) { + if (smmu_info.use_64_bit_dma_mask) { if (dma_set_mask(dev, DMA_BIT_MASK(64)) || dma_set_coherent_mask(dev, DMA_BIT_MASK(64))) { IPAERR("DMA set 64bit mask failed\n"); @@ -4826,7 +4827,7 @@ static int ipa_smmu_ap_cb_probe(struct device *dev) cb->va_end = cb->va_start + cb->va_size; IPADBG("AP va_start=0x%x va_sise=0x%x\n", cb->va_start, cb->va_size); - if (ipa3_ctx->use_64_bit_dma_mask) { + if (smmu_info.use_64_bit_dma_mask) { if (dma_set_mask(dev, DMA_BIT_MASK(64)) || dma_set_coherent_mask(dev, DMA_BIT_MASK(64))) { IPAERR("DMA set 64bit mask failed\n"); @@ -5035,6 +5036,9 @@ int ipa3_plat_drv_probe(struct platform_device *pdev_p, if (of_property_read_bool(pdev_p->dev.of_node, "qcom,smmu-fast-map")) smmu_info.fast_map = true; + if (of_property_read_bool(pdev_p->dev.of_node, + "qcom,use-64-bit-dma-mask")) + smmu_info.use_64_bit_dma_mask = true; smmu_info.arm_smmu = true; pr_info("IPA smmu_info.s1_bypass=%d smmu_info.fast_map=%d\n", smmu_info.s1_bypass, smmu_info.fast_map); @@ -5059,16 +5063,16 @@ int ipa3_plat_drv_probe(struct platform_device *pdev_p, return -EOPNOTSUPP; } } - } - if (!ipa3_bus_scale_table) - ipa3_bus_scale_table = msm_bus_cl_get_pdata(pdev_p); + if (!ipa3_bus_scale_table) + ipa3_bus_scale_table = msm_bus_cl_get_pdata(pdev_p); - /* Proceed to real initialization */ - result = ipa3_pre_init(&ipa3_res, dev); - if (result) { - IPAERR("ipa3_init failed\n"); - return result; + /* Proceed to real initialization */ + result = ipa3_pre_init(&ipa3_res, dev); + if (result) { + IPAERR("ipa3_init failed\n"); + return result; + } } return result; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c index 851e71777c32..029647213531 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c @@ -324,6 +324,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, struct ipa3_hdr_proc_ctx_tbl *htbl = &ipa3_ctx->hdr_proc_ctx_tbl; int id; int needed_len; + int mem_size; IPADBG_LOW("processing type %d hdr_hdl %d\n", proc_ctx->type, proc_ctx->hdr_hdl); @@ -366,6 +367,14 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, goto bad_len; } + mem_size = (ipa3_ctx->hdr_proc_ctx_tbl_lcl) ? + IPA_MEM_PART(apps_hdr_proc_ctx_size) : + IPA_MEM_PART(apps_hdr_proc_ctx_size_ddr); + if (htbl->end + ipa_hdr_proc_ctx_bin_sz[bin] > mem_size) { + IPAERR("hdr proc ctx table overflow\n"); + goto bad_len; + } + if (list_empty(&htbl->head_free_offset_list[bin])) { offset = kmem_cache_zalloc(ipa3_ctx->hdr_proc_ctx_offset_cache, GFP_KERNEL); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c index a702a2e52e39..4f6097c6da35 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c @@ -1213,7 +1213,8 @@ int ipahal_cp_proc_ctx_to_hw_buff(enum ipa_hdr_proc_type type, if (!base || !hdr_len || (!phys_base && !hdr_base_addr) || - !hdr_base_addr || !offset_entry) { + !hdr_base_addr || + ((is_hdr_proc_ctx == false) && !offset_entry)) { IPAHAL_ERR("failed on validating params"); return -EINVAL; } diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index a313dfc0245f..d78ee151c9e4 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -865,6 +865,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = { }, }, { + .ident = "Lenovo ideapad Y700-17ISK", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-17ISK"), + }, + }, + { .ident = "Lenovo Yoga 2 11 / 13 / Pro", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), @@ -893,6 +900,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = { }, }, { + .ident = "Lenovo Yoga 700", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 700"), + }, + }, + { .ident = "Lenovo Yoga 900", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index c01302989ee4..b0f62141ea4d 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -2484,6 +2484,14 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) brightness = __get_lcd_brightness(dev); if (brightness < 0) return 0; + /* + * If transflective backlight is supported and the brightness is zero + * (lowest brightness level), the set_lcd_brightness function will + * activate the transflective backlight, making the LCD appear to be + * turned off, simply increment the brightness level to avoid that. + */ + if (dev->tr_backlight_supported && brightness == 0) + brightness++; ret = set_lcd_brightness(dev, brightness); if (ret) { pr_debug("Backlight method is read-only, disabling backlight support\n"); diff --git a/drivers/power/qcom-charger/qpnp-fg.c b/drivers/power/qcom-charger/qpnp-fg.c index 8660c1f8c3f5..0658f0d3b1eb 100644 --- a/drivers/power/qcom-charger/qpnp-fg.c +++ b/drivers/power/qcom-charger/qpnp-fg.c @@ -4772,8 +4772,7 @@ fail: #define BATTERY_PSY_WAIT_MS 2000 static int fg_batt_profile_init(struct fg_chip *chip) { - int rc = 0, ret; - int len; + int rc = 0, ret, len, batt_id; struct device_node *node = chip->pdev->dev.of_node; struct device_node *batt_node, *profile_node; const char *data, *batt_type_str; @@ -4802,14 +4801,16 @@ wait: goto no_profile; } + batt_id = get_sram_prop_now(chip, FG_DATA_BATT_ID); + batt_id /= 1000; if (fg_debug_mask & FG_STATUS) - pr_info("battery id = %d\n", - get_sram_prop_now(chip, FG_DATA_BATT_ID)); - profile_node = of_batterydata_get_best_profile(batt_node, "bms", + pr_info("battery id = %dKOhms\n", batt_id); + + profile_node = of_batterydata_get_best_profile(batt_node, batt_id, fg_batt_type); - if (!profile_node) { - pr_err("couldn't find profile handle\n"); - rc = -ENODATA; + if (IS_ERR_OR_NULL(profile_node)) { + rc = PTR_ERR(profile_node); + pr_err("couldn't find profile handle %d\n", rc); goto no_profile; } diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c index dbdcd9026541..7810ecb9b15b 100644 --- a/drivers/power/qcom-charger/qpnp-smb2.c +++ b/drivers/power/qcom-charger/qpnp-smb2.c @@ -145,6 +145,7 @@ static enum power_supply_property smb2_usb_props[] = { POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION, POWER_SUPPLY_PROP_PD_ALLOWED, POWER_SUPPLY_PROP_PD_ACTIVE, + POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, }; static int smb2_usb_get_prop(struct power_supply *psy, @@ -201,6 +202,9 @@ static int smb2_usb_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_PD_ACTIVE: val->intval = chg->pd_active; break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED: + rc = smblib_get_prop_input_current_settled(chg, val); + break; default: pr_err("get prop %d is not supported\n", psp); rc = -EINVAL; @@ -592,6 +596,8 @@ static int smb2_determine_initial_status(struct smb2 *chip) smblib_handle_usb_plugin(0, &irq_data); smblib_handle_usb_typec_change(0, &irq_data); smblib_handle_usb_source_change(0, &irq_data); + smblib_handle_chg_state_change(0, &irq_data); + smblib_handle_icl_change(0, &irq_data); return 0; } @@ -601,14 +607,16 @@ static int smb2_determine_initial_status(struct smb2 *chip) **************************/ struct smb2_irq_info { - const char *name; - const irq_handler_t handler; + const char *name; + const irq_handler_t handler; + const bool wake; + int irq; }; -static const struct smb2_irq_info smb2_irqs[] = { +static struct smb2_irq_info smb2_irqs[] = { /* CHARGER IRQs */ { "chg-error", smblib_handle_debug }, - { "chg-state-change", smblib_handle_chg_state_change }, + { "chg-state-change", smblib_handle_chg_state_change, true }, { "step-chg-state-change", smblib_handle_debug }, { "step-chg-soc-update-fail", smblib_handle_debug }, { "step-chg-soc-update-request", smblib_handle_debug }, @@ -629,10 +637,10 @@ static const struct smb2_irq_info smb2_irqs[] = { { "usbin-lt-3p6v", smblib_handle_debug }, { "usbin-uv", smblib_handle_debug }, { "usbin-ov", smblib_handle_debug }, - { "usbin-plugin", smblib_handle_usb_plugin }, - { "usbin-src-change", smblib_handle_usb_source_change }, - { "usbin-icl-change", smblib_handle_icl_change }, - { "type-c-change", smblib_handle_usb_typec_change }, + { "usbin-plugin", smblib_handle_usb_plugin, true }, + { "usbin-src-change", smblib_handle_usb_source_change, true }, + { "usbin-icl-change", smblib_handle_icl_change, true }, + { "type-c-change", smblib_handle_usb_typec_change, true }, /* DC INPUT IRQs */ { "dcin-collapse", smblib_handle_debug }, { "dcin-lt-3p6v", smblib_handle_debug }, @@ -701,6 +709,10 @@ static int smb2_request_interrupt(struct smb2 *chip, return rc; } + smb2_irqs[irq_index].irq = irq; + if (smb2_irqs[irq_index].wake) + enable_irq_wake(irq); + return rc; } diff --git a/drivers/power/qcom-charger/qpnp-smbcharger.c b/drivers/power/qcom-charger/qpnp-smbcharger.c index 2536f4ec5c15..6c1e58d046e8 100644 --- a/drivers/power/qcom-charger/qpnp-smbcharger.c +++ b/drivers/power/qcom-charger/qpnp-smbcharger.c @@ -3507,19 +3507,27 @@ static int smbchg_config_chg_battery_type(struct smbchg_chip *chip) if (chip->battery_type && !strcmp(prop.strval, chip->battery_type)) return 0; + chip->battery_type = prop.strval; batt_node = of_parse_phandle(node, "qcom,battery-data", 0); if (!batt_node) { pr_smb(PR_MISC, "No batterydata available\n"); return 0; } + rc = power_supply_get_property(chip->bms_psy, + POWER_SUPPLY_PROP_RESISTANCE_ID, &prop); + if (rc < 0) { + pr_smb(PR_STATUS, "Unable to read battery-id rc=%d\n", rc); + return 0; + } + profile_node = of_batterydata_get_best_profile(batt_node, - "bms", NULL); - if (!profile_node) { - pr_err("couldn't find profile handle\n"); - return -EINVAL; + prop.intval / 1000, NULL); + if (IS_ERR_OR_NULL(profile_node)) { + rc = PTR_ERR(profile_node); + pr_err("couldn't find profile handle %d\n", rc); + return rc; } - chip->battery_type = prop.strval; /* change vfloat */ rc = of_property_read_u32(profile_node, "qcom,max-voltage-uv", diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c index 46b824376847..55bcc9ec443e 100644 --- a/drivers/power/qcom-charger/smb-lib.c +++ b/drivers/power/qcom-charger/smb-lib.c @@ -339,16 +339,32 @@ static int smblib_detach_usb(struct smb_charger *chg) return rc; } -static struct power_supply *get_parallel_psy(struct smb_charger *chg) +static int pl_notifier_call(struct notifier_block *nb, + unsigned long ev, void *v) { - if (chg->pl.psy) - return chg->pl.psy; + struct power_supply *psy = v; + struct smb_charger *chg = container_of(nb, struct smb_charger, pl.nb); - chg->pl.psy = power_supply_get_by_name("parallel"); - if (!chg->pl.psy) - smblib_dbg(chg, PR_MISC, "parallel charger not found\n"); + if (strcmp(psy->desc->name, "parallel") == 0) { + chg->pl.psy = psy; + schedule_work(&chg->pl_detect_work); + } + + return NOTIFY_OK; +} + +static int register_pl_notifier(struct smb_charger *chg) +{ + int rc; + + chg->pl.nb.notifier_call = pl_notifier_call; + rc = power_supply_reg_notifier(&chg->pl.nb); + if (rc < 0) { + pr_err("Couldn't register psy notifier rc = %d\n", rc); + return rc; + } - return chg->pl.psy; + return 0; } /********************* @@ -436,7 +452,7 @@ static int smblib_fv_vote_callback(struct votable *votable, void *data, return rc; } - if (chg->mode == PARALLEL_MASTER && get_parallel_psy(chg)) { + if (chg->mode == PARALLEL_MASTER && chg->pl.psy) { pval.intval = fv_uv + PARALLEL_FLOAT_VOLTAGE_DELTA_UV; rc = power_supply_set_property(chg->pl.psy, POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval); @@ -545,7 +561,7 @@ static int smblib_pl_disable_vote_callback(struct votable *votable, void *data, union power_supply_propval pval = {0, }; int rc; - if (chg->mode != PARALLEL_MASTER || !get_parallel_psy(chg)) + if (chg->mode != PARALLEL_MASTER || !chg->pl.psy) return 0; chg->pl.taper_percent = 100; @@ -662,7 +678,8 @@ int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev) int smblib_get_prop_input_suspend(struct smb_charger *chg, union power_supply_propval *val) { - val->intval = get_client_vote(chg->usb_suspend_votable, USER_VOTER); + val->intval = get_client_vote(chg->usb_suspend_votable, USER_VOTER) && + get_client_vote(chg->dc_suspend_votable, USER_VOTER); return 0; } @@ -697,15 +714,23 @@ int smblib_get_prop_batt_status(struct smb_charger *chg, { int rc; u8 stat; - union power_supply_propval online_pval = {0, }; + union power_supply_propval pval = {0, }; + + smblib_get_prop_input_suspend(chg, &pval); + if (pval.intval) { + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + return rc; + } - rc = smblib_get_prop_usb_online(chg, &online_pval); + rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat); if (rc < 0) { - dev_err(chg->dev, "Couldn't get prop usb online rc=%d\n", rc); + dev_err(chg->dev, "Couldn't read POWER_PATH_STATUS rc=%d\n", + rc); return rc; } - if (!online_pval.intval) { + if (!(stat & (USE_USBIN_BIT | USE_DCIN_BIT)) || + !(stat & VALID_INPUT_POWER_SOURCE_BIT)) { val->intval = POWER_SUPPLY_STATUS_DISCHARGING; return rc; } @@ -720,7 +745,7 @@ int smblib_get_prop_batt_status(struct smb_charger *chg, stat); stat = stat & BATTERY_CHARGER_STATUS_MASK; - if (stat == COMPLETED_CHARGE || stat == INHIBIT_CHARGE) + if (stat >= COMPLETED_CHARGE) val->intval = POWER_SUPPLY_STATUS_FULL; else val->intval = POWER_SUPPLY_STATUS_CHARGING; @@ -783,22 +808,16 @@ int smblib_get_prop_batt_health(struct smb_charger *chg, goto done; } - switch (stat & BAT_TEMP_STATUS_MASK) { - case BAT_TEMP_STATUS_TOO_COLD_BIT: + if (stat & BAT_TEMP_STATUS_TOO_COLD_BIT) val->intval = POWER_SUPPLY_HEALTH_COLD; - break; - case BAT_TEMP_STATUS_TOO_HOT_BIT: + else if (stat & BAT_TEMP_STATUS_TOO_HOT_BIT) val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; - break; - case BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT: + else if (stat & BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT) val->intval = POWER_SUPPLY_HEALTH_COOL; - break; - case BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT: + else if (stat & BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT) val->intval = POWER_SUPPLY_HEALTH_WARM; - break; - default: + else val->intval = POWER_SUPPLY_HEALTH_GOOD; - } done: return rc; @@ -1066,6 +1085,12 @@ int smblib_get_prop_pd_allowed(struct smb_charger *chg, return 0; } +int smblib_get_prop_input_current_settled(struct smb_charger *chg, + union power_supply_propval *val) +{ + return smblib_get_charge_param(chg, &chg->param.icl_stat, &val->intval); +} + /******************* * USB PSY SETTERS * * *****************/ @@ -1199,7 +1224,7 @@ irqreturn_t smblib_handle_chg_state_change(int irq, void *data) smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); - if (chg->mode != PARALLEL_MASTER || !get_parallel_psy(chg)) + if (chg->mode != PARALLEL_MASTER) return IRQ_HANDLED; rc = smblib_get_prop_batt_charge_type(chg, &pval); @@ -1559,6 +1584,17 @@ static void smblib_hvdcp_detect_work(struct work_struct *work) } } +static void smblib_pl_detect_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + pl_detect_work); + + power_supply_unreg_notifier(&chg->pl.nb); + + if (!get_effective_result_locked(chg->pl_disable_votable)) + rerun_election(chg->pl_disable_votable); +} + #define MINIMUM_PARALLEL_FCC_UA 500000 #define PL_TAPER_WORK_DELAY_MS 100 #define TAPER_RESIDUAL_PERCENT 75 @@ -1681,6 +1717,7 @@ int smblib_init(struct smb_charger *chg) int rc = 0; mutex_init(&chg->write_lock); + INIT_WORK(&chg->pl_detect_work, smblib_pl_detect_work); INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work); INIT_DELAYED_WORK(&chg->pl_taper_work, smblib_pl_taper_work); @@ -1690,7 +1727,20 @@ int smblib_init(struct smb_charger *chg) if (rc < 0) { dev_err(chg->dev, "Couldn't create votables rc=%d\n", rc); + return rc; + } + + chg->pl.psy = power_supply_get_by_name("parallel"); + if (!chg->pl.psy) { + rc = register_pl_notifier(chg); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't register notifier rc=%d\n", + rc); + return rc; + } } + break; case PARALLEL_SLAVE: break; diff --git a/drivers/power/qcom-charger/smb-lib.h b/drivers/power/qcom-charger/smb-lib.h index fbadf02d9958..8b3d00b6a5c1 100644 --- a/drivers/power/qcom-charger/smb-lib.h +++ b/drivers/power/qcom-charger/smb-lib.h @@ -65,6 +65,7 @@ struct smb_params { }; struct parallel_params { + struct notifier_block nb; struct power_supply *psy; int *master_percent; int taper_percent; @@ -107,6 +108,7 @@ struct smb_charger { struct votable *pl_disable_votable; /* work */ + struct work_struct pl_detect_work; struct delayed_work hvdcp_detect_work; struct delayed_work ps_change_timeout_work; struct delayed_work pl_taper_work; @@ -182,6 +184,8 @@ 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, union power_supply_propval *val); +int smblib_get_prop_input_current_settled(struct smb_charger *chg, + union power_supply_propval *val); int smblib_set_prop_usb_current_max(struct smb_charger *chg, const union power_supply_propval *val); int smblib_set_prop_usb_voltage_min(struct smb_charger *chg, diff --git a/drivers/power/qcom-charger/smb138x-charger.c b/drivers/power/qcom-charger/smb138x-charger.c index 2b65bf293cd1..9a6baff27dac 100644 --- a/drivers/power/qcom-charger/smb138x-charger.c +++ b/drivers/power/qcom-charger/smb138x-charger.c @@ -423,7 +423,7 @@ static int smb138x_parallel_prop_is_writeable(struct power_supply *psy, static const struct power_supply_desc parallel_psy_desc = { .name = "parallel", - .type = POWER_SUPPLY_TYPE_BATTERY, + .type = POWER_SUPPLY_TYPE_USB_PARALLEL, .properties = smb138x_parallel_props, .num_properties = ARRAY_SIZE(smb138x_parallel_props), .get_property = smb138x_parallel_get_prop, @@ -842,12 +842,6 @@ static int smb138x_slave_probe(struct smb138x *chip) return rc; } - rc = smb138x_init_parallel_psy(chip); - if (rc < 0) { - pr_err("Couldn't initialize parallel psy rc=%d\n", rc); - return rc; - } - /* suspend usb input */ rc = smblib_set_usb_suspend(chg, true); if (rc < 0) { @@ -878,6 +872,13 @@ static int smb138x_slave_probe(struct smb138x *chip) return rc; } + /* keep at the end of probe, ready to serve before notifying others */ + rc = smb138x_init_parallel_psy(chip); + if (rc < 0) { + pr_err("Couldn't initialize parallel psy rc=%d\n", rc); + return rc; + } + return rc; } diff --git a/drivers/power/qcom/msm-core.c b/drivers/power/qcom/msm-core.c index 49ed2eb3e40f..e990425bd63a 100644 --- a/drivers/power/qcom/msm-core.c +++ b/drivers/power/qcom/msm-core.c @@ -428,8 +428,8 @@ static int update_userspace_power(struct sched_params __user *argp) /* Copy the same power values for all the cpus in the cpumask * argp->cpumask within the cluster (argp->cluster) */ - spin_lock(&update_lock); get_user(cpumask, &argp->cpumask); + spin_lock(&update_lock); for (i = 0; i < MAX_CORES_PER_CLUSTER; i++, cpumask >>= 1) { if (!(cpumask & 0x01)) continue; diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 67818321aaa2..409fa4ad9c9c 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -456,6 +456,7 @@ config REGULATOR_MC13892 config REGULATOR_MT6311 tristate "MediaTek MT6311 PMIC" depends on I2C + select REGMAP_I2C help Say y here to select this option to enable the power regulator of MediaTek MT6311 PMIC. diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index 35de22fdb7a0..f2e1a39ce0f3 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c @@ -27,8 +27,8 @@ #define AXP20X_IO_ENABLED 0x03 #define AXP20X_IO_DISABLED 0x07 -#define AXP22X_IO_ENABLED 0x04 -#define AXP22X_IO_DISABLED 0x03 +#define AXP22X_IO_ENABLED 0x03 +#define AXP22X_IO_DISABLED 0x04 #define AXP20X_WORKMODE_DCDC2_MASK BIT(2) #define AXP20X_WORKMODE_DCDC3_MASK BIT(1) diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index a263c10359e1..4abfbdb285ec 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -3031,6 +3031,7 @@ static void dasd_setup_queue(struct dasd_block *block) max = block->base->discipline->max_blocks << block->s2b_shift; } queue_flag_set_unlocked(QUEUE_FLAG_NONROT, block->request_queue); + block->request_queue->limits.max_dev_sectors = max; blk_queue_logical_block_size(block->request_queue, block->bp_block); blk_queue_max_hw_sectors(block->request_queue, max); diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 184b1dbeb554..286782c60da4 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c @@ -264,8 +264,10 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) spin_unlock_irqrestore(&lcu->lock, flags); cancel_work_sync(&lcu->suc_data.worker); spin_lock_irqsave(&lcu->lock, flags); - if (device == lcu->suc_data.device) + if (device == lcu->suc_data.device) { + dasd_put_device(device); lcu->suc_data.device = NULL; + } } was_pending = 0; if (device == lcu->ruac_data.device) { @@ -273,8 +275,10 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) was_pending = 1; cancel_delayed_work_sync(&lcu->ruac_data.dwork); spin_lock_irqsave(&lcu->lock, flags); - if (device == lcu->ruac_data.device) + if (device == lcu->ruac_data.device) { + dasd_put_device(device); lcu->ruac_data.device = NULL; + } } private->lcu = NULL; spin_unlock_irqrestore(&lcu->lock, flags); @@ -549,8 +553,10 @@ static void lcu_update_work(struct work_struct *work) if ((rc && (rc != -EOPNOTSUPP)) || (lcu->flags & NEED_UAC_UPDATE)) { DBF_DEV_EVENT(DBF_WARNING, device, "could not update" " alias data in lcu (rc = %d), retry later", rc); - schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ); + if (!schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ)) + dasd_put_device(device); } else { + dasd_put_device(device); lcu->ruac_data.device = NULL; lcu->flags &= ~UPDATE_PENDING; } @@ -593,8 +599,10 @@ static int _schedule_lcu_update(struct alias_lcu *lcu, */ if (!usedev) return -EINVAL; + dasd_get_device(usedev); lcu->ruac_data.device = usedev; - schedule_delayed_work(&lcu->ruac_data.dwork, 0); + if (!schedule_delayed_work(&lcu->ruac_data.dwork, 0)) + dasd_put_device(usedev); return 0; } @@ -723,7 +731,7 @@ static int reset_summary_unit_check(struct alias_lcu *lcu, ASCEBC((char *) &cqr->magic, 4); ccw = cqr->cpaddr; ccw->cmd_code = DASD_ECKD_CCW_RSCK; - ccw->flags = 0 ; + ccw->flags = CCW_FLAG_SLI; ccw->count = 16; ccw->cda = (__u32)(addr_t) cqr->data; ((char *)cqr->data)[0] = reason; @@ -930,6 +938,7 @@ static void summary_unit_check_handling_work(struct work_struct *work) /* 3. read new alias configuration */ _schedule_lcu_update(lcu, device); lcu->suc_data.device = NULL; + dasd_put_device(device); spin_unlock_irqrestore(&lcu->lock, flags); } @@ -989,6 +998,8 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *device, } lcu->suc_data.reason = reason; lcu->suc_data.device = device; + dasd_get_device(device); spin_unlock(&lcu->lock); - schedule_work(&lcu->suc_data.worker); + if (!schedule_work(&lcu->suc_data.worker)) + dasd_put_device(device); }; diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index cb61f300f8b5..277b5c8c825c 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -67,7 +67,7 @@ static const u8 DASD_DIAG_CMS1[] = { 0xc3, 0xd4, 0xe2, 0xf1 };/* EBCDIC CMS1 */ * and function code cmd. * In case of an exception return 3. Otherwise return result of bitwise OR of * resulting condition code and DIAG return code. */ -static inline int dia250(void *iob, int cmd) +static inline int __dia250(void *iob, int cmd) { register unsigned long reg2 asm ("2") = (unsigned long) iob; typedef union { @@ -77,7 +77,6 @@ static inline int dia250(void *iob, int cmd) int rc; rc = 3; - diag_stat_inc(DIAG_STAT_X250); asm volatile( " diag 2,%2,0x250\n" "0: ipm %0\n" @@ -91,6 +90,12 @@ static inline int dia250(void *iob, int cmd) return rc; } +static inline int dia250(void *iob, int cmd) +{ + diag_stat_inc(DIAG_STAT_X250); + return __dia250(iob, cmd); +} + /* Initialize block I/O to DIAG device using the specified blocksize and * block offset. On success, return zero and set end_block to contain the * number of blocks on the device minus the specified offset. Return non-zero diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 16a1935cc9c1..e197c6f39de2 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -2192,7 +2192,7 @@ qla2x00_init_rings(scsi_qla_host_t *vha) /* Clear outstanding commands array. */ for (que = 0; que < ha->max_req_queues; que++) { req = ha->req_q_map[que]; - if (!req) + if (!req || !test_bit(que, ha->req_qid_map)) continue; req->out_ptr = (void *)(req->ring + req->length); *req->out_ptr = 0; @@ -2209,7 +2209,7 @@ qla2x00_init_rings(scsi_qla_host_t *vha) for (que = 0; que < ha->max_rsp_queues; que++) { rsp = ha->rsp_q_map[que]; - if (!rsp) + if (!rsp || !test_bit(que, ha->rsp_qid_map)) continue; rsp->in_ptr = (void *)(rsp->ring + rsp->length); *rsp->in_ptr = 0; @@ -4961,7 +4961,7 @@ qla25xx_init_queues(struct qla_hw_data *ha) for (i = 1; i < ha->max_rsp_queues; i++) { rsp = ha->rsp_q_map[i]; - if (rsp) { + if (rsp && test_bit(i, ha->rsp_qid_map)) { rsp->options &= ~BIT_0; ret = qla25xx_init_rsp_que(base_vha, rsp); if (ret != QLA_SUCCESS) @@ -4976,8 +4976,8 @@ qla25xx_init_queues(struct qla_hw_data *ha) } for (i = 1; i < ha->max_req_queues; i++) { req = ha->req_q_map[i]; - if (req) { - /* Clear outstanding commands array. */ + if (req && test_bit(i, ha->req_qid_map)) { + /* Clear outstanding commands array. */ req->options &= ~BIT_0; ret = qla25xx_init_req_que(base_vha, req); if (ret != QLA_SUCCESS) diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index ccf6a7f99024..0e59731f95ad 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -3018,9 +3018,9 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) "MSI-X: Failed to enable support " "-- %d/%d\n Retry with %d vectors.\n", ha->msix_count, ret, ret); + ha->msix_count = ret; + ha->max_rsp_queues = ha->msix_count - 1; } - ha->msix_count = ret; - ha->max_rsp_queues = ha->msix_count - 1; ha->msix_entries = kzalloc(sizeof(struct qla_msix_entry) * ha->msix_count, GFP_KERNEL); if (!ha->msix_entries) { diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index c5dd594f6c31..cf7ba52bae66 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -600,7 +600,7 @@ qla25xx_delete_queues(struct scsi_qla_host *vha) /* Delete request queues */ for (cnt = 1; cnt < ha->max_req_queues; cnt++) { req = ha->req_q_map[cnt]; - if (req) { + if (req && test_bit(cnt, ha->req_qid_map)) { ret = qla25xx_delete_req_que(vha, req); if (ret != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x00ea, @@ -614,7 +614,7 @@ qla25xx_delete_queues(struct scsi_qla_host *vha) /* Delete response queues */ for (cnt = 1; cnt < ha->max_rsp_queues; cnt++) { rsp = ha->rsp_q_map[cnt]; - if (rsp) { + if (rsp && test_bit(cnt, ha->rsp_qid_map)) { ret = qla25xx_delete_rsp_que(vha, rsp); if (ret != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x00eb, diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index bfa9a64c316b..fc6674db4f2d 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -397,6 +397,9 @@ static void qla2x00_free_queues(struct qla_hw_data *ha) int cnt; for (cnt = 0; cnt < ha->max_req_queues; cnt++) { + if (!test_bit(cnt, ha->req_qid_map)) + continue; + req = ha->req_q_map[cnt]; qla2x00_free_req_que(ha, req); } @@ -404,6 +407,9 @@ static void qla2x00_free_queues(struct qla_hw_data *ha) ha->req_q_map = NULL; for (cnt = 0; cnt < ha->max_rsp_queues; cnt++) { + if (!test_bit(cnt, ha->rsp_qid_map)) + continue; + rsp = ha->rsp_q_map[cnt]; qla2x00_free_rsp_que(ha, rsp); } diff --git a/drivers/scsi/qla2xxx/qla_tmpl.c b/drivers/scsi/qla2xxx/qla_tmpl.c index ddbe2e7ac14d..c3e622524604 100644 --- a/drivers/scsi/qla2xxx/qla_tmpl.c +++ b/drivers/scsi/qla2xxx/qla_tmpl.c @@ -395,6 +395,10 @@ qla27xx_fwdt_entry_t263(struct scsi_qla_host *vha, if (ent->t263.queue_type == T263_QUEUE_TYPE_REQ) { for (i = 0; i < vha->hw->max_req_queues; i++) { struct req_que *req = vha->hw->req_q_map[i]; + + if (!test_bit(i, vha->hw->req_qid_map)) + continue; + if (req || !buf) { length = req ? req->length : REQUEST_ENTRY_CNT_24XX; @@ -408,6 +412,10 @@ qla27xx_fwdt_entry_t263(struct scsi_qla_host *vha, } else if (ent->t263.queue_type == T263_QUEUE_TYPE_RSP) { for (i = 0; i < vha->hw->max_rsp_queues; i++) { struct rsp_que *rsp = vha->hw->rsp_q_map[i]; + + if (!test_bit(i, vha->hw->rsp_qid_map)) + continue; + if (rsp || !buf) { length = rsp ? rsp->length : RESPONSE_ENTRY_CNT_MQ; @@ -634,6 +642,10 @@ qla27xx_fwdt_entry_t274(struct scsi_qla_host *vha, if (ent->t274.queue_type == T274_QUEUE_TYPE_REQ_SHAD) { for (i = 0; i < vha->hw->max_req_queues; i++) { struct req_que *req = vha->hw->req_q_map[i]; + + if (!test_bit(i, vha->hw->req_qid_map)) + continue; + if (req || !buf) { qla27xx_insert16(i, buf, len); qla27xx_insert16(1, buf, len); @@ -645,6 +657,10 @@ qla27xx_fwdt_entry_t274(struct scsi_qla_host *vha, } else if (ent->t274.queue_type == T274_QUEUE_TYPE_RSP_SHAD) { for (i = 0; i < vha->hw->max_rsp_queues; i++) { struct rsp_que *rsp = vha->hw->rsp_q_map[i]; + + if (!test_bit(i, vha->hw->rsp_qid_map)) + continue; + if (rsp || !buf) { qla27xx_insert16(i, buf, len); qla27xx_insert16(1, buf, len); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index faaf363cb3e2..6d6606e1568a 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2820,7 +2820,7 @@ static int sd_revalidate_disk(struct gendisk *disk) sdkp->opt_xfer_blocks <= SD_DEF_XFER_BLOCKS && sdkp->opt_xfer_blocks * sdp->sector_size >= PAGE_CACHE_SIZE) rw_max = q->limits.io_opt = - logical_to_sectors(sdp, sdkp->opt_xfer_blocks); + sdkp->opt_xfer_blocks * sdp->sector_size; else rw_max = BLK_DEF_MAX_SECTORS; diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 36fd682edab8..60dc8b21044a 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -2332,7 +2332,8 @@ void ufs_qcom_print_hw_debug_reg_all(struct ufs_hba *hba, void *priv, reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_PRDT_RAM); print_fn(hba, reg, 64, "UFS_UFS_DBG_RD_PRDT_RAM ", priv); - ufshcd_writel(hba, (reg & ~UFS_BIT(17)), REG_UFS_CFG1); + /* clear bit 17 - UTP_DBG_RAMS_EN */ + ufshcd_rmwl(hba, UFS_BIT(17), 0, REG_UFS_CFG1); reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_UAWM); print_fn(hba, reg, 4, "UFS_DBG_RD_REG_UAWM ", priv); diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index ad679e5d3f76..9135415a5a51 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -1215,6 +1215,21 @@ int ufshcd_hold(struct ufs_hba *hba, bool async) start: switch (hba->clk_gating.state) { case CLKS_ON: + /* + * Wait for the ungate work to complete if in progress. + * Though the clocks may be in ON state, the link could + * still be in hibner8 state if hibern8 is allowed + * during clock gating. + * Make sure we exit hibern8 state also in addition to + * clocks being ON. + */ + if (ufshcd_can_hibern8_during_gating(hba) && + ufshcd_is_link_hibern8(hba)) { + spin_unlock_irqrestore(hba->host->host_lock, flags); + flush_work(&hba->clk_gating.ungate_work); + spin_lock_irqsave(hba->host->host_lock, flags); + goto start; + } break; case REQ_CLKS_OFF: if (cancel_delayed_work(&hba->clk_gating.gate_work)) { diff --git a/drivers/sh/pm_runtime.c b/drivers/sh/pm_runtime.c index 91a003011acf..a9bac3bf20de 100644 --- a/drivers/sh/pm_runtime.c +++ b/drivers/sh/pm_runtime.c @@ -34,7 +34,7 @@ static struct pm_clk_notifier_block platform_bus_notifier = { static int __init sh_pm_runtime_init(void) { - if (IS_ENABLED(CONFIG_ARCH_SHMOBILE)) { + if (IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_ARCH_SHMOBILE)) { if (!of_find_compatible_node(NULL, NULL, "renesas,cpg-mstp-clocks")) return 0; diff --git a/drivers/soc/qcom/glink_private.h b/drivers/soc/qcom/glink_private.h index 2f064e546f48..cdd6988418f7 100644 --- a/drivers/soc/qcom/glink_private.h +++ b/drivers/soc/qcom/glink_private.h @@ -19,6 +19,7 @@ #include <linux/kernel.h> #include <linux/kref.h> #include <linux/ratelimit.h> +#include <linux/sched.h> #include <linux/seq_file.h> #include <linux/spinlock.h> #include <linux/types.h> diff --git a/drivers/soc/qcom/glink_smd_xprt.c b/drivers/soc/qcom/glink_smd_xprt.c index 52eedb507709..6abe943069d0 100644 --- a/drivers/soc/qcom/glink_smd_xprt.c +++ b/drivers/soc/qcom/glink_smd_xprt.c @@ -731,6 +731,7 @@ static void process_reopen_event(struct work_struct *work) mutex_unlock(&einfo->rx_cmd_lock); } if (ch->local_legacy) { + ch->local_legacy = false; mutex_lock(&einfo->rx_cmd_lock); einfo->xprt_if.glink_core_if_ptr->rx_cmd_ch_close_ack( &einfo->xprt_if, @@ -944,6 +945,7 @@ static void smd_data_ch_close(struct channel *ch) ch->smd_ch = NULL; } else if (ch->local_legacy) { ch_work = kzalloc(sizeof(*ch_work), GFP_KERNEL); + ch->local_legacy = false; if (ch_work) { ch_work->ch = ch; INIT_WORK(&ch_work->work, deferred_close_ack); @@ -952,7 +954,6 @@ static void smd_data_ch_close(struct channel *ch) } mutex_unlock(&ch->ch_probe_lock); - ch->local_legacy = false; spin_lock_irqsave(&ch->intents_lock, flags); while (!list_empty(&ch->intents)) { @@ -1854,8 +1855,14 @@ static int tx_cmd_rx_intent_req(struct glink_transport_if *if_ptr, struct edge_info *einfo; struct channel *ch; unsigned long flags; + int rcu_id; einfo = container_of(if_ptr, struct edge_info, xprt_if); + rcu_id = srcu_read_lock(&einfo->ssr_sync); + if (einfo->in_ssr) { + srcu_read_unlock(&einfo->ssr_sync, rcu_id); + return -EFAULT; + } spin_lock_irqsave(&einfo->channels_lock, flags); list_for_each_entry(ch, &einfo->channels, node) { if (lcid == ch->lcid) @@ -1871,6 +1878,7 @@ static int tx_cmd_rx_intent_req(struct glink_transport_if *if_ptr, ch->rcid, ch->next_intent_id++, size); + srcu_read_unlock(&einfo->ssr_sync, rcu_id); return 0; } diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c index d7d08dc588e5..84f346385f18 100644 --- a/drivers/soc/qcom/glink_smem_native_xprt.c +++ b/drivers/soc/qcom/glink_smem_native_xprt.c @@ -2191,6 +2191,8 @@ static int subsys_name_to_id(const char *name) return SMEM_WCNSS; if (!strcmp(name, "spss")) return SMEM_SPSS; + if (!strcmp(name, "cdsp")) + return SMEM_CDSP; return -ENODEV; } diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index f4b63ec4b325..883f23d8234d 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -36,6 +36,7 @@ #include <soc/qcom/memory_dump.h> #include <soc/qcom/icnss.h> #include <soc/qcom/msm_qmi_interface.h> +#include <soc/qcom/secure_buffer.h> #include "wlan_firmware_service_v01.h" @@ -97,6 +98,16 @@ } while (0) #endif +enum icnss_debug_quirks { + HW_ALWAY_ON, + HW_DEBUG_ENABLE, +}; + +#define ICNSS_QUIRKS_DEFAULT 0 + +unsigned long quirks = ICNSS_QUIRKS_DEFAULT; +module_param(quirks, ulong, 0600); + void *icnss_ipc_log_context; enum icnss_driver_event_type { @@ -123,6 +134,7 @@ enum icnss_driver_state { ICNSS_FW_READY, ICNSS_DRIVER_PROBED, ICNSS_FW_TEST_MODE, + ICNSS_SUSPEND, }; struct ce_irq_list { @@ -522,6 +534,105 @@ int icnss_power_off(struct device *dev) } EXPORT_SYMBOL(icnss_power_off); +int icnss_map_msa_permissions(struct icnss_data *priv, u32 index) +{ + int ret = 0; + phys_addr_t addr; + u32 size; + u32 source_vmlist[1] = {VMID_HLOS}; + int dest_vmids[3] = {VMID_MSS_MSA, VMID_WLAN, 0}; + int dest_perms[3] = {PERM_READ|PERM_WRITE, + PERM_READ|PERM_WRITE, + PERM_READ|PERM_WRITE}; + int source_nelems = sizeof(source_vmlist)/sizeof(u32); + int dest_nelems = 0; + + addr = priv->icnss_mem_region[index].reg_addr; + size = priv->icnss_mem_region[index].size; + + if (!priv->icnss_mem_region[index].secure_flag) { + dest_vmids[2] = VMID_WLAN_CE; + dest_nelems = 3; + } else { + dest_vmids[2] = 0; + dest_nelems = 2; + } + ret = hyp_assign_phys(addr, size, source_vmlist, source_nelems, + dest_vmids, dest_perms, dest_nelems); + if (ret) { + icnss_pr_err("region %u hyp_assign_phys failed IPA=%pa size=%u err=%d\n", + index, &addr, size, ret); + goto out; + } + icnss_pr_dbg("hypervisor map for region %u: source=%x, dest_nelems=%d, dest[0]=%x, dest[1]=%x, dest[2]=%x\n", + index, source_vmlist[0], dest_nelems, + dest_vmids[0], dest_vmids[1], dest_vmids[2]); +out: + return ret; + +} + +int icnss_unmap_msa_permissions(struct icnss_data *priv, u32 index) +{ + int ret = 0; + phys_addr_t addr; + u32 size; + u32 dest_vmids[1] = {VMID_HLOS}; + int source_vmlist[3] = {VMID_MSS_MSA, VMID_WLAN, 0}; + int dest_perms[1] = {PERM_READ|PERM_WRITE}; + int source_nelems = 0; + int dest_nelems = sizeof(dest_vmids)/sizeof(u32); + + addr = priv->icnss_mem_region[index].reg_addr; + size = priv->icnss_mem_region[index].size; + if (!priv->icnss_mem_region[index].secure_flag) { + source_vmlist[2] = VMID_WLAN_CE; + source_nelems = 3; + } else { + source_vmlist[2] = 0; + source_nelems = 2; + } + + ret = hyp_assign_phys(addr, size, source_vmlist, source_nelems, + dest_vmids, dest_perms, dest_nelems); + if (ret) { + icnss_pr_err("region %u hyp_assign_phys failed IPA=%pa size=%u err=%d\n", + index, &addr, size, ret); + goto out; + } + icnss_pr_dbg("hypervisor unmap for region %u, source_nelems=%d, source[0]=%x, source[1]=%x, source[2]=%x, dest=%x\n", + index, source_nelems, + source_vmlist[0], source_vmlist[1], source_vmlist[2], + dest_vmids[0]); +out: + return ret; +} + +static int icnss_setup_msa_permissions(struct icnss_data *priv) +{ + int ret = 0; + + ret = icnss_map_msa_permissions(priv, 0); + if (ret) + return ret; + + ret = icnss_map_msa_permissions(priv, 1); + if (ret) + goto err_map_msa; + + return ret; + +err_map_msa: + icnss_unmap_msa_permissions(priv, 0); + return ret; +} + +static void icnss_remove_msa_permissions(struct icnss_data *priv) +{ + icnss_unmap_msa_permissions(priv, 0); + icnss_unmap_msa_permissions(priv, 1); +} + static int wlfw_msa_mem_info_send_sync_msg(void) { int ret = 0; @@ -783,6 +894,8 @@ static int wlfw_wlan_mode_send_sync_msg(enum wlfw_driver_mode_enum_v01 mode) memset(&resp, 0, sizeof(resp)); req.mode = mode; + req.hw_debug_valid = 1; + req.hw_debug = !!test_bit(HW_DEBUG_ENABLE, &quirks); req_desc.max_msg_len = WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN; req_desc.msg_id = QMI_WLFW_WLAN_MODE_REQ_V01; @@ -1036,19 +1149,27 @@ static int icnss_driver_event_server_arrive(void *data) icnss_pr_err("Failed to send MSA info: %d\n", ret); goto err_power_on; } + ret = icnss_setup_msa_permissions(penv); + if (ret < 0) { + icnss_pr_err("Failed to setup msa permissions: %d\n", + ret); + goto err_power_on; + } ret = wlfw_msa_ready_send_sync_msg(); if (ret < 0) { icnss_pr_err("Failed to send MSA ready : %d\n", ret); - goto err_power_on; + goto err_setup_msa; } ret = wlfw_cap_send_sync_msg(); if (ret < 0) { icnss_pr_err("Failed to get capability: %d\n", ret); - goto err_power_on; + goto err_setup_msa; } return ret; +err_setup_msa: + icnss_remove_msa_permissions(penv); err_power_on: icnss_hw_power_off(penv); fail: @@ -1990,6 +2111,9 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_data *priv) case ICNSS_FW_TEST_MODE: seq_puts(s, "FW TEST MODE"); continue; + case ICNSS_SUSPEND: + seq_puts(s, "DRIVER SUSPENDED"); + continue; } seq_printf(s, "UNKNOWN-%d", i); @@ -2350,6 +2474,54 @@ static int icnss_remove(struct platform_device *pdev) return 0; } +static int icnss_suspend(struct platform_device *pdev, + pm_message_t state) +{ + int ret = 0; + + if (!penv) { + ret = -ENODEV; + goto out; + } + + icnss_pr_dbg("Driver suspending, state: 0x%lx\n", + penv->state); + + if (!penv->ops) + goto out; + + if (penv->ops->suspend) + ret = penv->ops->suspend(&pdev->dev, state); + +out: + if (ret == 0) + set_bit(ICNSS_SUSPEND, &penv->state); + return ret; +} + +static int icnss_resume(struct platform_device *pdev) +{ + int ret = 0; + + if (!penv) { + ret = -ENODEV; + goto out; + } + + icnss_pr_dbg("Driver resuming, state: 0x%lx\n", + penv->state); + + if (!penv->ops) + goto out; + + if (penv->ops->resume) + ret = penv->ops->resume(&pdev->dev); + +out: + if (ret == 0) + clear_bit(ICNSS_SUSPEND, &penv->state); + return ret; +} static const struct of_device_id icnss_dt_match[] = { {.compatible = "qcom,icnss"}, @@ -2361,6 +2533,8 @@ MODULE_DEVICE_TABLE(of, icnss_dt_match); static struct platform_driver icnss_driver = { .probe = icnss_probe, .remove = icnss_remove, + .suspend = icnss_suspend, + .resume = icnss_resume, .driver = { .name = "icnss", .owner = THIS_MODULE, diff --git a/drivers/soc/qcom/memory_dump_v2.c b/drivers/soc/qcom/memory_dump_v2.c index c0b884f34e15..af141c808c81 100644 --- a/drivers/soc/qcom/memory_dump_v2.c +++ b/drivers/soc/qcom/memory_dump_v2.c @@ -17,6 +17,7 @@ #include <linux/err.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/kmemleak.h> #include <soc/qcom/memory_dump.h> #include <soc/qcom/scm.h> @@ -152,6 +153,7 @@ static int __init init_memory_dump(void) ret = -ENOMEM; goto err1; } + kmemleak_not_leak(table); table->version = MSM_DUMP_TABLE_VERSION; entry.id = MSM_DUMP_TABLE_APPS; diff --git a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c index 14e46b38c6df..7e5f1661932f 100644 --- a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c +++ b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c @@ -330,6 +330,7 @@ struct apr_svc_ch_dev *apr_tal_open(uint32_t clnt, uint32_t dest, uint32_t dl, if (IS_ERR_OR_NULL(apr_ch->handle)) { pr_err("%s: glink_open failed %s\n", __func__, svc_names[dest][clnt]); + apr_ch->handle = NULL; goto unlock; } diff --git a/drivers/soc/qcom/qdsp6v2/voice_svc.c b/drivers/soc/qcom/qdsp6v2/voice_svc.c index 23b8292c8db5..67c58d1e6d4c 100644 --- a/drivers/soc/qcom/qdsp6v2/voice_svc.c +++ b/drivers/soc/qcom/qdsp6v2/voice_svc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -188,7 +188,8 @@ static int voice_svc_send_req(struct voice_svc_cmd_request *apr_request, int ret = 0; void *apr_handle = NULL; struct apr_data *aprdata = NULL; - uint32_t user_payload_size = 0; + uint32_t user_payload_size; + uint32_t payload_size; pr_debug("%s\n", __func__); @@ -200,15 +201,19 @@ static int voice_svc_send_req(struct voice_svc_cmd_request *apr_request, } user_payload_size = apr_request->payload_size; + payload_size = sizeof(struct apr_data) + user_payload_size; - aprdata = kmalloc(sizeof(struct apr_data) + user_payload_size, - GFP_KERNEL); - - if (aprdata == NULL) { - pr_err("%s: aprdata kmalloc failed.\n", __func__); - - ret = -ENOMEM; + if (payload_size <= user_payload_size) { + pr_err("%s: invalid payload size ( 0x%x ).\n", + __func__, user_payload_size); + ret = -EINVAL; goto done; + } else { + aprdata = kmalloc(payload_size, GFP_KERNEL); + if (aprdata == NULL) { + ret = -ENOMEM; + goto done; + } } voice_svc_update_hdr(apr_request, aprdata); @@ -388,18 +393,31 @@ static ssize_t voice_svc_write(struct file *file, const char __user *buf, switch (cmd) { case MSG_REGISTER: - ret = process_reg_cmd( + if (count >= + (sizeof(struct voice_svc_register) + + sizeof(*data))) { + ret = process_reg_cmd( (struct voice_svc_register *)data->payload, prtd); - if (!ret) - ret = count; - + if (!ret) + ret = count; + } else { + pr_err("%s: invalid payload size\n", __func__); + ret = -EINVAL; + goto done; + } break; case MSG_REQUEST: + if (count >= (sizeof(struct voice_svc_cmd_request) + + sizeof(*data))) { ret = voice_svc_send_req( (struct voice_svc_cmd_request *)data->payload, prtd); if (!ret) ret = count; - + } else { + pr_err("%s: invalid payload size\n", __func__); + ret = -EINVAL; + goto done; + } break; default: pr_debug("%s: Invalid command: %u\n", __func__, cmd); diff --git a/drivers/soc/qcom/service-locator.c b/drivers/soc/qcom/service-locator.c index 37c73401a1c6..e4d235957981 100644 --- a/drivers/soc/qcom/service-locator.c +++ b/drivers/soc/qcom/service-locator.c @@ -39,15 +39,11 @@ #define LOCATOR_NOT_PRESENT 0 #define LOCATOR_PRESENT 1 -#define LOCATOR_UNKNOWN -1 -static u32 locator_status = LOCATOR_UNKNOWN; +static u32 locator_status = LOCATOR_NOT_PRESENT; static bool service_inited; -int enable; -module_param(enable, int, 0); - -DECLARE_COMPLETION(locator_status_known); +module_param_named(enable, locator_status, uint, S_IRUGO | S_IWUSR); static void service_locator_svc_arrive(struct work_struct *work); static void service_locator_svc_exit(struct work_struct *work); @@ -70,47 +66,6 @@ struct pd_qmi_data service_locator; /* Please refer soc/qcom/service-locator.h for use about APIs defined here */ -static ssize_t show_service_locator_status(struct class *cl, - struct class_attribute *attr, - char *buf) -{ - return scnprintf(buf, PAGE_SIZE, "%x\n", locator_status); -} - -static ssize_t store_service_locator_status(struct class *cl, - struct class_attribute *attr, - const char *buf, size_t size) -{ - u32 val; - - if (kstrtos32(buf, 10, &val) < 0) - goto err; - if (val != LOCATOR_NOT_PRESENT && val != LOCATOR_PRESENT) - goto err; - - mutex_lock(&service_init_mutex); - locator_status = val; - complete_all(&locator_status_known); - mutex_unlock(&service_init_mutex); - return size; -err: - pr_err("Invalid input parameters\n"); - return -EINVAL; -} - -static struct class_attribute service_locator_class_attr[] = { - __ATTR(service_locator_status, S_IRUGO | S_IWUSR, - show_service_locator_status, - store_service_locator_status), - __ATTR_NULL, -}; - -static struct class service_locator_class = { - .name = "service_locator", - .owner = THIS_MODULE, - .class_attrs = service_locator_class_attr, -}; - static int service_locator_svc_event_notify(struct notifier_block *this, unsigned long code, void *_cmd) @@ -338,30 +293,13 @@ static int init_service_locator(void) mutex_lock(&service_init_mutex); if (locator_status == LOCATOR_NOT_PRESENT) { - pr_err("Service Locator not present\n"); + pr_err("Service Locator not enabled\n"); rc = -ENODEV; goto inited; } if (service_inited) goto inited; - if (locator_status != LOCATOR_PRESENT) { - mutex_unlock(&service_init_mutex); - rc = wait_for_completion_timeout(&locator_status_known, - msecs_to_jiffies(INITIAL_TIMEOUT)); - if (!rc) { - locator_status = LOCATOR_NOT_PRESENT; - pr_err("Timed out waiting for Service Locator\n"); - return -ENODEV; - } - mutex_lock(&service_init_mutex); - if (locator_status == LOCATOR_NOT_PRESENT) { - pr_err("Service Locator not present\n"); - rc = -ENODEV; - goto inited; - } - } - service_locator.notifier.notifier_call = service_locator_svc_event_notify; init_completion(&service_locator.service_available); @@ -509,10 +447,7 @@ static struct dentry *test_servloc_file; static int __init service_locator_init(void) { - if (!enable) - locator_status = LOCATOR_NOT_PRESENT; - - class_register(&service_locator_class); + pr_debug("service_locator_status = %d\n", locator_status); test_servloc_file = debugfs_create_file("test_servloc", S_IRUGO | S_IWUSR, NULL, NULL, &servloc_fops); @@ -523,7 +458,6 @@ static int __init service_locator_init(void) static void __exit service_locator_exit(void) { - class_unregister(&service_locator_class); debugfs_remove(test_servloc_file); } diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c index 0551011b537f..45af4b601634 100644 --- a/drivers/soc/qcom/spcom.c +++ b/drivers/soc/qcom/spcom.c @@ -136,8 +136,13 @@ /* The SPSS RAM size is 256 KB so SP App must fit into it */ #define SPCOM_MAX_APP_SIZE SZ_256K -/* ACK timeout from remote side for TX data */ -#define TX_DONE_TIMEOUT_MSEC 100 +/* + * ACK timeout from remote side for TX data. + * Normally, it takes few msec for SPSS to responde with ACK for TX data. + * However, due to SPSS HW issue, the SPSS might disable interrupts + * for a very long time. + */ +#define TX_DONE_TIMEOUT_MSEC 5000 /* * Initial transaction id, use non-zero nonce for debug. diff --git a/drivers/soc/qcom/wlan_firmware_service_v01.c b/drivers/soc/qcom/wlan_firmware_service_v01.c index e899459a5a40..b33575116c18 100644 --- a/drivers/soc/qcom/wlan_firmware_service_v01.c +++ b/drivers/soc/qcom/wlan_firmware_service_v01.c @@ -462,6 +462,24 @@ struct elem_info wlfw_wlan_mode_req_msg_v01_ei[] = { mode), }, { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01, + hw_debug_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01, + hw_debug), + }, + { .data_type = QMI_EOTI, .is_array = NO_ARRAY, .is_array = QMI_COMMON_TLV_TYPE, diff --git a/drivers/soc/qcom/wlan_firmware_service_v01.h b/drivers/soc/qcom/wlan_firmware_service_v01.h index 6e96cbabd9d8..bf47da7cdecb 100644 --- a/drivers/soc/qcom/wlan_firmware_service_v01.h +++ b/drivers/soc/qcom/wlan_firmware_service_v01.h @@ -180,8 +180,10 @@ extern struct elem_info wlfw_pin_connect_result_ind_msg_v01_ei[]; struct wlfw_wlan_mode_req_msg_v01 { enum wlfw_driver_mode_enum_v01 mode; + uint8_t hw_debug_valid; + uint8_t hw_debug; }; -#define WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN 7 +#define WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN 11 extern struct elem_info wlfw_wlan_mode_req_msg_v01_ei[]; struct wlfw_wlan_mode_resp_msg_v01 { diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index aebad36391c9..8feac599e9ab 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -1571,6 +1571,7 @@ static int atmel_spi_probe(struct platform_device *pdev) as->use_cs_gpios = true; if (atmel_spi_is_v2(as) && + pdev->dev.of_node && !of_get_property(pdev->dev.of_node, "cs-gpios", NULL)) { as->use_cs_gpios = false; master->num_chipselect = 4; diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 1f8903d356e5..ed8283e7397a 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1024,6 +1024,16 @@ static int omap2_mcspi_setup(struct spi_device *spi) spi->controller_state = cs; /* Link this to context save list */ list_add_tail(&cs->node, &ctx->cs); + + if (gpio_is_valid(spi->cs_gpio)) { + ret = gpio_request(spi->cs_gpio, dev_name(&spi->dev)); + if (ret) { + dev_err(&spi->dev, "failed to request gpio\n"); + return ret; + } + gpio_direction_output(spi->cs_gpio, + !(spi->mode & SPI_CS_HIGH)); + } } if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx) { @@ -1032,15 +1042,6 @@ static int omap2_mcspi_setup(struct spi_device *spi) return ret; } - if (gpio_is_valid(spi->cs_gpio)) { - ret = gpio_request(spi->cs_gpio, dev_name(&spi->dev)); - if (ret) { - dev_err(&spi->dev, "failed to request gpio\n"); - return ret; - } - gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); - } - ret = pm_runtime_get_sync(mcspi->dev); if (ret < 0) return ret; diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index f98eabeb382c..5e1fd988b22c 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -783,7 +783,7 @@ pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u8 *apid) } static int -pmic_arb_mode_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode) +pmic_arb_mode_v1_v3(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode) { *mode = S_IRUSR | S_IWUSR; return 0; @@ -940,7 +940,7 @@ static u32 pmic_arb_irq_clear_v2(u8 n) static const struct pmic_arb_ver_ops pmic_arb_v1 = { .ver_str = "v1", .ppid_to_apid = pmic_arb_ppid_to_apid_v1, - .mode = pmic_arb_mode_v1, + .mode = pmic_arb_mode_v1_v3, .non_data_cmd = pmic_arb_non_data_cmd_v1, .offset = pmic_arb_offset_v1, .fmt_cmd = pmic_arb_fmt_cmd_v1, @@ -966,7 +966,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v2 = { static const struct pmic_arb_ver_ops pmic_arb_v3 = { .ver_str = "v3", .ppid_to_apid = pmic_arb_ppid_to_apid_v2, - .mode = pmic_arb_mode_v2, + .mode = pmic_arb_mode_v1_v3, .non_data_cmd = pmic_arb_non_data_cmd_v2, .offset = pmic_arb_offset_v2, .fmt_cmd = pmic_arb_fmt_cmd_v2, @@ -1134,6 +1134,7 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) } irq_set_chained_handler_and_data(pa->irq, pmic_arb_chained_irq, pa); + enable_irq_wake(pa->irq); err = spmi_controller_add(ctrl); if (err) diff --git a/drivers/staging/android/sync.h b/drivers/staging/android/sync.h index 0b5fb0cad9fd..c8196dd61baa 100644 --- a/drivers/staging/android/sync.h +++ b/drivers/staging/android/sync.h @@ -92,7 +92,7 @@ struct sync_timeline_ops { struct sync_timeline { struct kref kref; const struct sync_timeline_ops *ops; - char name[32]; + char name[64]; /* protected by child_list_lock */ bool destroyed; diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c index 79ac19246548..70b8f4fabfad 100644 --- a/drivers/staging/panel/panel.c +++ b/drivers/staging/panel/panel.c @@ -825,8 +825,7 @@ static void lcd_write_cmd_s(int cmd) lcd_send_serial(0x1F); /* R/W=W, RS=0 */ lcd_send_serial(cmd & 0x0F); lcd_send_serial((cmd >> 4) & 0x0F); - /* the shortest command takes at least 40 us */ - usleep_range(40, 100); + udelay(40); /* the shortest command takes at least 40 us */ spin_unlock_irq(&pprt_lock); } @@ -837,8 +836,7 @@ static void lcd_write_data_s(int data) lcd_send_serial(0x5F); /* R/W=W, RS=1 */ lcd_send_serial(data & 0x0F); lcd_send_serial((data >> 4) & 0x0F); - /* the shortest data takes at least 40 us */ - usleep_range(40, 100); + udelay(40); /* the shortest data takes at least 40 us */ spin_unlock_irq(&pprt_lock); } @@ -848,20 +846,19 @@ static void lcd_write_cmd_p8(int cmd) spin_lock_irq(&pprt_lock); /* present the data to the data port */ w_dtr(pprt, cmd); - /* maintain the data during 20 us before the strobe */ - usleep_range(20, 100); + udelay(20); /* maintain the data during 20 us before the strobe */ bits.e = BIT_SET; bits.rs = BIT_CLR; bits.rw = BIT_CLR; set_ctrl_bits(); - usleep_range(40, 100); /* maintain the strobe during 40 us */ + udelay(40); /* maintain the strobe during 40 us */ bits.e = BIT_CLR; set_ctrl_bits(); - usleep_range(120, 500); /* the shortest command takes at least 120 us */ + udelay(120); /* the shortest command takes at least 120 us */ spin_unlock_irq(&pprt_lock); } @@ -871,20 +868,19 @@ static void lcd_write_data_p8(int data) spin_lock_irq(&pprt_lock); /* present the data to the data port */ w_dtr(pprt, data); - /* maintain the data during 20 us before the strobe */ - usleep_range(20, 100); + udelay(20); /* maintain the data during 20 us before the strobe */ bits.e = BIT_SET; bits.rs = BIT_SET; bits.rw = BIT_CLR; set_ctrl_bits(); - usleep_range(40, 100); /* maintain the strobe during 40 us */ + udelay(40); /* maintain the strobe during 40 us */ bits.e = BIT_CLR; set_ctrl_bits(); - usleep_range(45, 100); /* the shortest data takes at least 45 us */ + udelay(45); /* the shortest data takes at least 45 us */ spin_unlock_irq(&pprt_lock); } @@ -894,7 +890,7 @@ static void lcd_write_cmd_tilcd(int cmd) spin_lock_irq(&pprt_lock); /* present the data to the control port */ w_ctr(pprt, cmd); - usleep_range(60, 120); + udelay(60); spin_unlock_irq(&pprt_lock); } @@ -904,7 +900,7 @@ static void lcd_write_data_tilcd(int data) spin_lock_irq(&pprt_lock); /* present the data to the data port */ w_dtr(pprt, data); - usleep_range(60, 120); + udelay(60); spin_unlock_irq(&pprt_lock); } @@ -947,7 +943,7 @@ static void lcd_clear_fast_s(void) lcd_send_serial(0x5F); /* R/W=W, RS=1 */ lcd_send_serial(' ' & 0x0F); lcd_send_serial((' ' >> 4) & 0x0F); - usleep_range(40, 100); /* the shortest data takes at least 40 us */ + udelay(40); /* the shortest data takes at least 40 us */ } spin_unlock_irq(&pprt_lock); @@ -971,7 +967,7 @@ static void lcd_clear_fast_p8(void) w_dtr(pprt, ' '); /* maintain the data during 20 us before the strobe */ - usleep_range(20, 100); + udelay(20); bits.e = BIT_SET; bits.rs = BIT_SET; @@ -979,13 +975,13 @@ static void lcd_clear_fast_p8(void) set_ctrl_bits(); /* maintain the strobe during 40 us */ - usleep_range(40, 100); + udelay(40); bits.e = BIT_CLR; set_ctrl_bits(); /* the shortest data takes at least 45 us */ - usleep_range(45, 100); + udelay(45); } spin_unlock_irq(&pprt_lock); @@ -1007,7 +1003,7 @@ static void lcd_clear_fast_tilcd(void) for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) { /* present the data to the data port */ w_dtr(pprt, ' '); - usleep_range(60, 120); + udelay(60); } spin_unlock_irq(&pprt_lock); diff --git a/drivers/staging/speakup/serialio.c b/drivers/staging/speakup/serialio.c index 3b5835b28128..a5bbb338f275 100644 --- a/drivers/staging/speakup/serialio.c +++ b/drivers/staging/speakup/serialio.c @@ -6,6 +6,11 @@ #include "spk_priv.h" #include "serialio.h" +#include <linux/serial_core.h> +/* WARNING: Do not change this to <linux/serial.h> without testing that + * SERIAL_PORT_DFNS does get defined to the appropriate value. */ +#include <asm/serial.h> + #ifndef SERIAL_PORT_DFNS #define SERIAL_PORT_DFNS #endif @@ -23,9 +28,15 @@ const struct old_serial_port *spk_serial_init(int index) int baud = 9600, quot = 0; unsigned int cval = 0; int cflag = CREAD | HUPCL | CLOCAL | B9600 | CS8; - const struct old_serial_port *ser = rs_table + index; + const struct old_serial_port *ser; int err; + if (index >= ARRAY_SIZE(rs_table)) { + pr_info("no port info for ttyS%d\n", index); + return NULL; + } + ser = rs_table + index; + /* Divisor, bytesize and parity */ quot = ser->baud_base / baud; cval = cflag & (CSIZE | CSTOPB); diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 88ea4e4f124b..3436a83568ea 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -826,6 +826,49 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) return dev; } +/* + * Check if the underlying struct block_device request_queue supports + * the QUEUE_FLAG_DISCARD bit for UNMAP/WRITE_SAME in SCSI + TRIM + * in ATA and we need to set TPE=1 + */ +bool target_configure_unmap_from_queue(struct se_dev_attrib *attrib, + struct request_queue *q, int block_size) +{ + if (!blk_queue_discard(q)) + return false; + + attrib->max_unmap_lba_count = (q->limits.max_discard_sectors << 9) / + block_size; + /* + * Currently hardcoded to 1 in Linux/SCSI code.. + */ + attrib->max_unmap_block_desc_count = 1; + attrib->unmap_granularity = q->limits.discard_granularity / block_size; + attrib->unmap_granularity_alignment = q->limits.discard_alignment / + block_size; + return true; +} +EXPORT_SYMBOL(target_configure_unmap_from_queue); + +/* + * Convert from blocksize advertised to the initiator to the 512 byte + * units unconditionally used by the Linux block layer. + */ +sector_t target_to_linux_sector(struct se_device *dev, sector_t lb) +{ + switch (dev->dev_attrib.block_size) { + case 4096: + return lb << 3; + case 2048: + return lb << 2; + case 1024: + return lb << 1; + default: + return lb; + } +} +EXPORT_SYMBOL(target_to_linux_sector); + int target_configure_device(struct se_device *dev) { struct se_hba *hba = dev->se_hba; diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index e3195700211a..75f0f08b2a34 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -160,25 +160,11 @@ static int fd_configure_device(struct se_device *dev) " block_device blocks: %llu logical_block_size: %d\n", dev_size, div_u64(dev_size, fd_dev->fd_block_size), fd_dev->fd_block_size); - /* - * Check if the underlying struct block_device request_queue supports - * the QUEUE_FLAG_DISCARD bit for UNMAP/WRITE_SAME in SCSI + TRIM - * in ATA and we need to set TPE=1 - */ - if (blk_queue_discard(q)) { - dev->dev_attrib.max_unmap_lba_count = - q->limits.max_discard_sectors; - /* - * Currently hardcoded to 1 in Linux/SCSI code.. - */ - dev->dev_attrib.max_unmap_block_desc_count = 1; - dev->dev_attrib.unmap_granularity = - q->limits.discard_granularity >> 9; - dev->dev_attrib.unmap_granularity_alignment = - q->limits.discard_alignment; + + if (target_configure_unmap_from_queue(&dev->dev_attrib, q, + fd_dev->fd_block_size)) pr_debug("IFILE: BLOCK Discard support available," - " disabled by default\n"); - } + " disabled by default\n"); /* * Enable write same emulation for IBLOCK and use 0xFFFF as * the smaller WRITE_SAME(10) only has a two-byte block count. @@ -490,9 +476,12 @@ fd_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb) if (S_ISBLK(inode->i_mode)) { /* The backend is block device, use discard */ struct block_device *bdev = inode->i_bdev; + struct se_device *dev = cmd->se_dev; - ret = blkdev_issue_discard(bdev, lba, - nolb, GFP_KERNEL, 0); + ret = blkdev_issue_discard(bdev, + target_to_linux_sector(dev, lba), + target_to_linux_sector(dev, nolb), + GFP_KERNEL, 0); if (ret < 0) { pr_warn("FILEIO: blkdev_issue_discard() failed: %d\n", ret); diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index f29c69120054..2c53dcefff3e 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -121,27 +121,11 @@ static int iblock_configure_device(struct se_device *dev) dev->dev_attrib.hw_max_sectors = queue_max_hw_sectors(q); dev->dev_attrib.hw_queue_depth = q->nr_requests; - /* - * Check if the underlying struct block_device request_queue supports - * the QUEUE_FLAG_DISCARD bit for UNMAP/WRITE_SAME in SCSI + TRIM - * in ATA and we need to set TPE=1 - */ - if (blk_queue_discard(q)) { - dev->dev_attrib.max_unmap_lba_count = - q->limits.max_discard_sectors; - - /* - * Currently hardcoded to 1 in Linux/SCSI code.. - */ - dev->dev_attrib.max_unmap_block_desc_count = 1; - dev->dev_attrib.unmap_granularity = - q->limits.discard_granularity >> 9; - dev->dev_attrib.unmap_granularity_alignment = - q->limits.discard_alignment; - + if (target_configure_unmap_from_queue(&dev->dev_attrib, q, + dev->dev_attrib.hw_block_size)) pr_debug("IBLOCK: BLOCK Discard support available," - " disabled by default\n"); - } + " disabled by default\n"); + /* * Enable write same emulation for IBLOCK and use 0xFFFF as * the smaller WRITE_SAME(10) only has a two-byte block count. @@ -413,9 +397,13 @@ static sense_reason_t iblock_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb) { struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd; + struct se_device *dev = cmd->se_dev; int ret; - ret = blkdev_issue_discard(bdev, lba, nolb, GFP_KERNEL, 0); + ret = blkdev_issue_discard(bdev, + target_to_linux_sector(dev, lba), + target_to_linux_sector(dev, nolb), + GFP_KERNEL, 0); if (ret < 0) { pr_err("blkdev_issue_discard() failed: %d\n", ret); return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; @@ -431,8 +419,10 @@ iblock_execute_write_same(struct se_cmd *cmd) struct scatterlist *sg; struct bio *bio; struct bio_list list; - sector_t block_lba = cmd->t_task_lba; - sector_t sectors = sbc_get_write_same_sectors(cmd); + struct se_device *dev = cmd->se_dev; + sector_t block_lba = target_to_linux_sector(dev, cmd->t_task_lba); + sector_t sectors = target_to_linux_sector(dev, + sbc_get_write_same_sectors(cmd)); if (cmd->prot_op) { pr_err("WRITE_SAME: Protection information with IBLOCK" @@ -646,12 +636,12 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, enum dma_data_direction data_direction) { struct se_device *dev = cmd->se_dev; + sector_t block_lba = target_to_linux_sector(dev, cmd->t_task_lba); struct iblock_req *ibr; struct bio *bio, *bio_start; struct bio_list list; struct scatterlist *sg; u32 sg_num = sgl_nents; - sector_t block_lba; unsigned bio_cnt; int rw = 0; int i; @@ -677,24 +667,6 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, rw = READ; } - /* - * Convert the blocksize advertised to the initiator to the 512 byte - * units unconditionally used by the Linux block layer. - */ - if (dev->dev_attrib.block_size == 4096) - block_lba = (cmd->t_task_lba << 3); - else if (dev->dev_attrib.block_size == 2048) - block_lba = (cmd->t_task_lba << 2); - else if (dev->dev_attrib.block_size == 1024) - block_lba = (cmd->t_task_lba << 1); - else if (dev->dev_attrib.block_size == 512) - block_lba = cmd->t_task_lba; - else { - pr_err("Unsupported SCSI -> BLOCK LBA conversion:" - " %u\n", dev->dev_attrib.block_size); - return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - } - ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL); if (!ibr) goto fail; diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 28fb3016370f..46b1991fbb50 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -68,23 +68,25 @@ void core_tmr_release_req(struct se_tmr_req *tmr) if (dev) { spin_lock_irqsave(&dev->se_tmr_lock, flags); - list_del(&tmr->tmr_list); + list_del_init(&tmr->tmr_list); spin_unlock_irqrestore(&dev->se_tmr_lock, flags); } kfree(tmr); } -static void core_tmr_handle_tas_abort( - struct se_node_acl *tmr_nacl, - struct se_cmd *cmd, - int tas) +static void core_tmr_handle_tas_abort(struct se_cmd *cmd, int tas) { - bool remove = true; + unsigned long flags; + bool remove = true, send_tas; /* * TASK ABORTED status (TAS) bit support */ - if ((tmr_nacl && (tmr_nacl != cmd->se_sess->se_node_acl)) && tas) { + spin_lock_irqsave(&cmd->t_state_lock, flags); + send_tas = (cmd->transport_state & CMD_T_TAS); + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + + if (send_tas) { remove = false; transport_send_task_abort(cmd); } @@ -107,6 +109,46 @@ static int target_check_cdb_and_preempt(struct list_head *list, return 1; } +static bool __target_check_io_state(struct se_cmd *se_cmd, + struct se_session *tmr_sess, int tas) +{ + struct se_session *sess = se_cmd->se_sess; + + assert_spin_locked(&sess->sess_cmd_lock); + WARN_ON_ONCE(!irqs_disabled()); + /* + * If command already reached CMD_T_COMPLETE state within + * target_complete_cmd() or CMD_T_FABRIC_STOP due to shutdown, + * this se_cmd has been passed to fabric driver and will + * not be aborted. + * + * Otherwise, obtain a local se_cmd->cmd_kref now for TMR + * ABORT_TASK + LUN_RESET for CMD_T_ABORTED processing as + * long as se_cmd->cmd_kref is still active unless zero. + */ + spin_lock(&se_cmd->t_state_lock); + if (se_cmd->transport_state & (CMD_T_COMPLETE | CMD_T_FABRIC_STOP)) { + pr_debug("Attempted to abort io tag: %llu already complete or" + " fabric stop, skipping\n", se_cmd->tag); + spin_unlock(&se_cmd->t_state_lock); + return false; + } + if (sess->sess_tearing_down || se_cmd->cmd_wait_set) { + pr_debug("Attempted to abort io tag: %llu already shutdown," + " skipping\n", se_cmd->tag); + spin_unlock(&se_cmd->t_state_lock); + return false; + } + se_cmd->transport_state |= CMD_T_ABORTED; + + if ((tmr_sess != se_cmd->se_sess) && tas) + se_cmd->transport_state |= CMD_T_TAS; + + spin_unlock(&se_cmd->t_state_lock); + + return kref_get_unless_zero(&se_cmd->cmd_kref); +} + void core_tmr_abort_task( struct se_device *dev, struct se_tmr_req *tmr, @@ -130,34 +172,21 @@ void core_tmr_abort_task( if (tmr->ref_task_tag != ref_tag) continue; - if (!kref_get_unless_zero(&se_cmd->cmd_kref)) - continue; - printk("ABORT_TASK: Found referenced %s task_tag: %llu\n", se_cmd->se_tfo->get_fabric_name(), ref_tag); - spin_lock(&se_cmd->t_state_lock); - if (se_cmd->transport_state & CMD_T_COMPLETE) { - printk("ABORT_TASK: ref_tag: %llu already complete," - " skipping\n", ref_tag); - spin_unlock(&se_cmd->t_state_lock); + if (!__target_check_io_state(se_cmd, se_sess, 0)) { spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); - - target_put_sess_cmd(se_cmd); - goto out; } - se_cmd->transport_state |= CMD_T_ABORTED; - spin_unlock(&se_cmd->t_state_lock); - list_del_init(&se_cmd->se_cmd_list); spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); cancel_work_sync(&se_cmd->work); transport_wait_for_tasks(se_cmd); - target_put_sess_cmd(se_cmd); transport_cmd_finish_abort(se_cmd, true); + target_put_sess_cmd(se_cmd); printk("ABORT_TASK: Sending TMR_FUNCTION_COMPLETE for" " ref_tag: %llu\n", ref_tag); @@ -178,9 +207,11 @@ static void core_tmr_drain_tmr_list( struct list_head *preempt_and_abort_list) { LIST_HEAD(drain_tmr_list); + struct se_session *sess; struct se_tmr_req *tmr_p, *tmr_pp; struct se_cmd *cmd; unsigned long flags; + bool rc; /* * Release all pending and outgoing TMRs aside from the received * LUN_RESET tmr.. @@ -206,17 +237,39 @@ static void core_tmr_drain_tmr_list( if (target_check_cdb_and_preempt(preempt_and_abort_list, cmd)) continue; + sess = cmd->se_sess; + if (WARN_ON_ONCE(!sess)) + continue; + + spin_lock(&sess->sess_cmd_lock); spin_lock(&cmd->t_state_lock); - if (!(cmd->transport_state & CMD_T_ACTIVE)) { + if (!(cmd->transport_state & CMD_T_ACTIVE) || + (cmd->transport_state & CMD_T_FABRIC_STOP)) { spin_unlock(&cmd->t_state_lock); + spin_unlock(&sess->sess_cmd_lock); continue; } if (cmd->t_state == TRANSPORT_ISTATE_PROCESSING) { spin_unlock(&cmd->t_state_lock); + spin_unlock(&sess->sess_cmd_lock); continue; } + if (sess->sess_tearing_down || cmd->cmd_wait_set) { + spin_unlock(&cmd->t_state_lock); + spin_unlock(&sess->sess_cmd_lock); + continue; + } + cmd->transport_state |= CMD_T_ABORTED; spin_unlock(&cmd->t_state_lock); + rc = kref_get_unless_zero(&cmd->cmd_kref); + if (!rc) { + printk("LUN_RESET TMR: non-zero kref_get_unless_zero\n"); + spin_unlock(&sess->sess_cmd_lock); + continue; + } + spin_unlock(&sess->sess_cmd_lock); + list_move_tail(&tmr_p->tmr_list, &drain_tmr_list); } spin_unlock_irqrestore(&dev->se_tmr_lock, flags); @@ -230,20 +283,26 @@ static void core_tmr_drain_tmr_list( (preempt_and_abort_list) ? "Preempt" : "", tmr_p, tmr_p->function, tmr_p->response, cmd->t_state); + cancel_work_sync(&cmd->work); + transport_wait_for_tasks(cmd); + transport_cmd_finish_abort(cmd, 1); + target_put_sess_cmd(cmd); } } static void core_tmr_drain_state_list( struct se_device *dev, struct se_cmd *prout_cmd, - struct se_node_acl *tmr_nacl, + struct se_session *tmr_sess, int tas, struct list_head *preempt_and_abort_list) { LIST_HEAD(drain_task_list); + struct se_session *sess; struct se_cmd *cmd, *next; unsigned long flags; + int rc; /* * Complete outstanding commands with TASK_ABORTED SAM status. @@ -282,6 +341,16 @@ static void core_tmr_drain_state_list( if (prout_cmd == cmd) continue; + sess = cmd->se_sess; + if (WARN_ON_ONCE(!sess)) + continue; + + spin_lock(&sess->sess_cmd_lock); + rc = __target_check_io_state(cmd, tmr_sess, tas); + spin_unlock(&sess->sess_cmd_lock); + if (!rc) + continue; + list_move_tail(&cmd->state_list, &drain_task_list); cmd->state_active = false; } @@ -289,7 +358,7 @@ static void core_tmr_drain_state_list( while (!list_empty(&drain_task_list)) { cmd = list_entry(drain_task_list.next, struct se_cmd, state_list); - list_del(&cmd->state_list); + list_del_init(&cmd->state_list); pr_debug("LUN_RESET: %s cmd: %p" " ITT/CmdSN: 0x%08llx/0x%08x, i_state: %d, t_state: %d" @@ -313,16 +382,11 @@ static void core_tmr_drain_state_list( * loop above, but we do it down here given that * cancel_work_sync may block. */ - if (cmd->t_state == TRANSPORT_COMPLETE) - cancel_work_sync(&cmd->work); - - spin_lock_irqsave(&cmd->t_state_lock, flags); - target_stop_cmd(cmd, &flags); - - cmd->transport_state |= CMD_T_ABORTED; - spin_unlock_irqrestore(&cmd->t_state_lock, flags); + cancel_work_sync(&cmd->work); + transport_wait_for_tasks(cmd); - core_tmr_handle_tas_abort(tmr_nacl, cmd, tas); + core_tmr_handle_tas_abort(cmd, tas); + target_put_sess_cmd(cmd); } } @@ -334,6 +398,7 @@ int core_tmr_lun_reset( { struct se_node_acl *tmr_nacl = NULL; struct se_portal_group *tmr_tpg = NULL; + struct se_session *tmr_sess = NULL; int tas; /* * TASK_ABORTED status bit, this is configurable via ConfigFS @@ -352,8 +417,9 @@ int core_tmr_lun_reset( * or struct se_device passthrough.. */ if (tmr && tmr->task_cmd && tmr->task_cmd->se_sess) { - tmr_nacl = tmr->task_cmd->se_sess->se_node_acl; - tmr_tpg = tmr->task_cmd->se_sess->se_tpg; + tmr_sess = tmr->task_cmd->se_sess; + tmr_nacl = tmr_sess->se_node_acl; + tmr_tpg = tmr_sess->se_tpg; if (tmr_nacl && tmr_tpg) { pr_debug("LUN_RESET: TMR caller fabric: %s" " initiator port %s\n", @@ -366,7 +432,7 @@ int core_tmr_lun_reset( dev->transport->name, tas); core_tmr_drain_tmr_list(dev, tmr, preempt_and_abort_list); - core_tmr_drain_state_list(dev, prout_cmd, tmr_nacl, tas, + core_tmr_drain_state_list(dev, prout_cmd, tmr_sess, tas, preempt_and_abort_list); /* diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 4fdcee2006d1..94f4ffac723f 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -528,9 +528,6 @@ void transport_deregister_session(struct se_session *se_sess) } EXPORT_SYMBOL(transport_deregister_session); -/* - * Called with cmd->t_state_lock held. - */ static void target_remove_from_state_list(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; @@ -555,10 +552,6 @@ static int transport_cmd_check_stop(struct se_cmd *cmd, bool remove_from_lists, { unsigned long flags; - spin_lock_irqsave(&cmd->t_state_lock, flags); - if (write_pending) - cmd->t_state = TRANSPORT_WRITE_PENDING; - if (remove_from_lists) { target_remove_from_state_list(cmd); @@ -568,6 +561,10 @@ static int transport_cmd_check_stop(struct se_cmd *cmd, bool remove_from_lists, cmd->se_lun = NULL; } + spin_lock_irqsave(&cmd->t_state_lock, flags); + if (write_pending) + cmd->t_state = TRANSPORT_WRITE_PENDING; + /* * Determine if frontend context caller is requesting the stopping of * this command for frontend exceptions. @@ -621,6 +618,8 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd) void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) { + bool ack_kref = (cmd->se_cmd_flags & SCF_ACK_KREF); + if (cmd->se_cmd_flags & SCF_SE_LUN_CMD) transport_lun_remove_cmd(cmd); /* @@ -632,7 +631,7 @@ void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) if (transport_cmd_check_stop_to_fabric(cmd)) return; - if (remove) + if (remove && ack_kref) transport_put_cmd(cmd); } @@ -700,7 +699,7 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) * Check for case where an explicit ABORT_TASK has been received * and transport_wait_for_tasks() will be waiting for completion.. */ - if (cmd->transport_state & CMD_T_ABORTED && + if (cmd->transport_state & CMD_T_ABORTED || cmd->transport_state & CMD_T_STOP) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); complete_all(&cmd->t_transport_stop_comp); @@ -1850,19 +1849,21 @@ static bool target_handle_task_attr(struct se_cmd *cmd) return true; } +static int __transport_check_aborted_status(struct se_cmd *, int); + void target_execute_cmd(struct se_cmd *cmd) { /* - * If the received CDB has aleady been aborted stop processing it here. - */ - if (transport_check_aborted_status(cmd, 1)) - return; - - /* * Determine if frontend context caller is requesting the stopping of * this command for frontend exceptions. + * + * If the received CDB has aleady been aborted stop processing it here. */ spin_lock_irq(&cmd->t_state_lock); + if (__transport_check_aborted_status(cmd, 1)) { + spin_unlock_irq(&cmd->t_state_lock); + return; + } if (cmd->transport_state & CMD_T_STOP) { pr_debug("%s:%d CMD_T_STOP for ITT: 0x%08llx\n", __func__, __LINE__, cmd->tag); @@ -2213,20 +2214,14 @@ static inline void transport_free_pages(struct se_cmd *cmd) } /** - * transport_release_cmd - free a command - * @cmd: command to free + * transport_put_cmd - release a reference to a command + * @cmd: command to release * - * This routine unconditionally frees a command, and reference counting - * or list removal must be done in the caller. + * This routine releases our reference to the command and frees it if possible. */ -static int transport_release_cmd(struct se_cmd *cmd) +static int transport_put_cmd(struct se_cmd *cmd) { BUG_ON(!cmd->se_tfo); - - if (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) - core_tmr_release_req(cmd->se_tmr_req); - if (cmd->t_task_cdb != cmd->__t_task_cdb) - kfree(cmd->t_task_cdb); /* * If this cmd has been setup with target_get_sess_cmd(), drop * the kref and call ->release_cmd() in kref callback. @@ -2234,18 +2229,6 @@ static int transport_release_cmd(struct se_cmd *cmd) return target_put_sess_cmd(cmd); } -/** - * transport_put_cmd - release a reference to a command - * @cmd: command to release - * - * This routine releases our reference to the command and frees it if possible. - */ -static int transport_put_cmd(struct se_cmd *cmd) -{ - transport_free_pages(cmd); - return transport_release_cmd(cmd); -} - void *transport_kmap_data_sg(struct se_cmd *cmd) { struct scatterlist *sg = cmd->t_data_sg; @@ -2441,34 +2424,58 @@ static void transport_write_pending_qf(struct se_cmd *cmd) } } -int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) +static bool +__transport_wait_for_tasks(struct se_cmd *, bool, bool *, bool *, + unsigned long *flags); + +static void target_wait_free_cmd(struct se_cmd *cmd, bool *aborted, bool *tas) { unsigned long flags; + + spin_lock_irqsave(&cmd->t_state_lock, flags); + __transport_wait_for_tasks(cmd, true, aborted, tas, &flags); + spin_unlock_irqrestore(&cmd->t_state_lock, flags); +} + +int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks) +{ int ret = 0; + bool aborted = false, tas = false; if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) { if (wait_for_tasks && (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) - transport_wait_for_tasks(cmd); + target_wait_free_cmd(cmd, &aborted, &tas); - ret = transport_release_cmd(cmd); + if (!aborted || tas) + ret = transport_put_cmd(cmd); } else { if (wait_for_tasks) - transport_wait_for_tasks(cmd); + target_wait_free_cmd(cmd, &aborted, &tas); /* * Handle WRITE failure case where transport_generic_new_cmd() * has already added se_cmd to state_list, but fabric has * failed command before I/O submission. */ - if (cmd->state_active) { - spin_lock_irqsave(&cmd->t_state_lock, flags); + if (cmd->state_active) target_remove_from_state_list(cmd); - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - } if (cmd->se_lun) transport_lun_remove_cmd(cmd); - ret = transport_put_cmd(cmd); + if (!aborted || tas) + ret = transport_put_cmd(cmd); + } + /* + * If the task has been internally aborted due to TMR ABORT_TASK + * or LUN_RESET, target_core_tmr.c is responsible for performing + * the remaining calls to target_put_sess_cmd(), and not the + * callers of this function. + */ + if (aborted) { + pr_debug("Detected CMD_T_ABORTED for ITT: %llu\n", cmd->tag); + wait_for_completion(&cmd->cmd_wait_comp); + cmd->se_tfo->release_cmd(cmd); + ret = 1; } return ret; } @@ -2508,26 +2515,46 @@ out: } EXPORT_SYMBOL(target_get_sess_cmd); +static void target_free_cmd_mem(struct se_cmd *cmd) +{ + transport_free_pages(cmd); + + if (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) + core_tmr_release_req(cmd->se_tmr_req); + if (cmd->t_task_cdb != cmd->__t_task_cdb) + kfree(cmd->t_task_cdb); +} + static void target_release_cmd_kref(struct kref *kref) { struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref); struct se_session *se_sess = se_cmd->se_sess; unsigned long flags; + bool fabric_stop; spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); if (list_empty(&se_cmd->se_cmd_list)) { spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); + target_free_cmd_mem(se_cmd); se_cmd->se_tfo->release_cmd(se_cmd); return; } - if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) { + + spin_lock(&se_cmd->t_state_lock); + fabric_stop = (se_cmd->transport_state & CMD_T_FABRIC_STOP); + spin_unlock(&se_cmd->t_state_lock); + + if (se_cmd->cmd_wait_set || fabric_stop) { + list_del_init(&se_cmd->se_cmd_list); spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); + target_free_cmd_mem(se_cmd); complete(&se_cmd->cmd_wait_comp); return; } - list_del(&se_cmd->se_cmd_list); + list_del_init(&se_cmd->se_cmd_list); spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); + target_free_cmd_mem(se_cmd); se_cmd->se_tfo->release_cmd(se_cmd); } @@ -2539,6 +2566,7 @@ int target_put_sess_cmd(struct se_cmd *se_cmd) struct se_session *se_sess = se_cmd->se_sess; if (!se_sess) { + target_free_cmd_mem(se_cmd); se_cmd->se_tfo->release_cmd(se_cmd); return 1; } @@ -2555,6 +2583,7 @@ void target_sess_cmd_list_set_waiting(struct se_session *se_sess) { struct se_cmd *se_cmd; unsigned long flags; + int rc; spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); if (se_sess->sess_tearing_down) { @@ -2564,8 +2593,15 @@ void target_sess_cmd_list_set_waiting(struct se_session *se_sess) se_sess->sess_tearing_down = 1; list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list); - list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list) - se_cmd->cmd_wait_set = 1; + list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list) { + rc = kref_get_unless_zero(&se_cmd->cmd_kref); + if (rc) { + se_cmd->cmd_wait_set = 1; + spin_lock(&se_cmd->t_state_lock); + se_cmd->transport_state |= CMD_T_FABRIC_STOP; + spin_unlock(&se_cmd->t_state_lock); + } + } spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); } @@ -2578,15 +2614,25 @@ void target_wait_for_sess_cmds(struct se_session *se_sess) { struct se_cmd *se_cmd, *tmp_cmd; unsigned long flags; + bool tas; list_for_each_entry_safe(se_cmd, tmp_cmd, &se_sess->sess_wait_list, se_cmd_list) { - list_del(&se_cmd->se_cmd_list); + list_del_init(&se_cmd->se_cmd_list); pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:" " %d\n", se_cmd, se_cmd->t_state, se_cmd->se_tfo->get_cmd_state(se_cmd)); + spin_lock_irqsave(&se_cmd->t_state_lock, flags); + tas = (se_cmd->transport_state & CMD_T_TAS); + spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); + + if (!target_put_sess_cmd(se_cmd)) { + if (tas) + target_put_sess_cmd(se_cmd); + } + wait_for_completion(&se_cmd->cmd_wait_comp); pr_debug("After cmd_wait_comp: se_cmd: %p t_state: %d" " fabric state: %d\n", se_cmd, se_cmd->t_state, @@ -2608,53 +2654,75 @@ void transport_clear_lun_ref(struct se_lun *lun) wait_for_completion(&lun->lun_ref_comp); } -/** - * transport_wait_for_tasks - wait for completion to occur - * @cmd: command to wait - * - * Called from frontend fabric context to wait for storage engine - * to pause and/or release frontend generated struct se_cmd. - */ -bool transport_wait_for_tasks(struct se_cmd *cmd) +static bool +__transport_wait_for_tasks(struct se_cmd *cmd, bool fabric_stop, + bool *aborted, bool *tas, unsigned long *flags) + __releases(&cmd->t_state_lock) + __acquires(&cmd->t_state_lock) { - unsigned long flags; - spin_lock_irqsave(&cmd->t_state_lock, flags); + assert_spin_locked(&cmd->t_state_lock); + WARN_ON_ONCE(!irqs_disabled()); + + if (fabric_stop) + cmd->transport_state |= CMD_T_FABRIC_STOP; + + if (cmd->transport_state & CMD_T_ABORTED) + *aborted = true; + + if (cmd->transport_state & CMD_T_TAS) + *tas = true; + if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD) && - !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) { - spin_unlock_irqrestore(&cmd->t_state_lock, flags); + !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) return false; - } if (!(cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) && - !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) { - spin_unlock_irqrestore(&cmd->t_state_lock, flags); + !(cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) return false; - } - if (!(cmd->transport_state & CMD_T_ACTIVE)) { - spin_unlock_irqrestore(&cmd->t_state_lock, flags); + if (!(cmd->transport_state & CMD_T_ACTIVE)) + return false; + + if (fabric_stop && *aborted) return false; - } cmd->transport_state |= CMD_T_STOP; - pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08llx i_state: %d, t_state: %d, CMD_T_STOP\n", - cmd, cmd->tag, cmd->se_tfo->get_cmd_state(cmd), cmd->t_state); + pr_debug("wait_for_tasks: Stopping %p ITT: 0x%08llx i_state: %d," + " t_state: %d, CMD_T_STOP\n", cmd, cmd->tag, + cmd->se_tfo->get_cmd_state(cmd), cmd->t_state); - spin_unlock_irqrestore(&cmd->t_state_lock, flags); + spin_unlock_irqrestore(&cmd->t_state_lock, *flags); wait_for_completion(&cmd->t_transport_stop_comp); - spin_lock_irqsave(&cmd->t_state_lock, flags); + spin_lock_irqsave(&cmd->t_state_lock, *flags); cmd->transport_state &= ~(CMD_T_ACTIVE | CMD_T_STOP); - pr_debug("wait_for_tasks: Stopped wait_for_completion(&cmd->t_transport_stop_comp) for ITT: 0x%08llx\n", - cmd->tag); + pr_debug("wait_for_tasks: Stopped wait_for_completion(&cmd->" + "t_transport_stop_comp) for ITT: 0x%08llx\n", cmd->tag); + + return true; +} +/** + * transport_wait_for_tasks - wait for completion to occur + * @cmd: command to wait + * + * Called from frontend fabric context to wait for storage engine + * to pause and/or release frontend generated struct se_cmd. + */ +bool transport_wait_for_tasks(struct se_cmd *cmd) +{ + unsigned long flags; + bool ret, aborted = false, tas = false; + + spin_lock_irqsave(&cmd->t_state_lock, flags); + ret = __transport_wait_for_tasks(cmd, false, &aborted, &tas, &flags); spin_unlock_irqrestore(&cmd->t_state_lock, flags); - return true; + return ret; } EXPORT_SYMBOL(transport_wait_for_tasks); @@ -2836,28 +2904,49 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd, } EXPORT_SYMBOL(transport_send_check_condition_and_sense); -int transport_check_aborted_status(struct se_cmd *cmd, int send_status) +static int __transport_check_aborted_status(struct se_cmd *cmd, int send_status) + __releases(&cmd->t_state_lock) + __acquires(&cmd->t_state_lock) { + assert_spin_locked(&cmd->t_state_lock); + WARN_ON_ONCE(!irqs_disabled()); + if (!(cmd->transport_state & CMD_T_ABORTED)) return 0; - /* * If cmd has been aborted but either no status is to be sent or it has * already been sent, just return */ - if (!send_status || !(cmd->se_cmd_flags & SCF_SEND_DELAYED_TAS)) + if (!send_status || !(cmd->se_cmd_flags & SCF_SEND_DELAYED_TAS)) { + if (send_status) + cmd->se_cmd_flags |= SCF_SEND_DELAYED_TAS; return 1; + } - pr_debug("Sending delayed SAM_STAT_TASK_ABORTED status for CDB: 0x%02x ITT: 0x%08llx\n", - cmd->t_task_cdb[0], cmd->tag); + pr_debug("Sending delayed SAM_STAT_TASK_ABORTED status for CDB:" + " 0x%02x ITT: 0x%08llx\n", cmd->t_task_cdb[0], cmd->tag); cmd->se_cmd_flags &= ~SCF_SEND_DELAYED_TAS; cmd->scsi_status = SAM_STAT_TASK_ABORTED; trace_target_cmd_complete(cmd); + + spin_unlock_irq(&cmd->t_state_lock); cmd->se_tfo->queue_status(cmd); + spin_lock_irq(&cmd->t_state_lock); return 1; } + +int transport_check_aborted_status(struct se_cmd *cmd, int send_status) +{ + int ret; + + spin_lock_irq(&cmd->t_state_lock); + ret = __transport_check_aborted_status(cmd, send_status); + spin_unlock_irq(&cmd->t_state_lock); + + return ret; +} EXPORT_SYMBOL(transport_check_aborted_status); void transport_send_task_abort(struct se_cmd *cmd) @@ -2879,11 +2968,17 @@ void transport_send_task_abort(struct se_cmd *cmd) */ if (cmd->data_direction == DMA_TO_DEVICE) { if (cmd->se_tfo->write_pending_status(cmd) != 0) { - cmd->transport_state |= CMD_T_ABORTED; + spin_lock_irqsave(&cmd->t_state_lock, flags); + if (cmd->se_cmd_flags & SCF_SEND_DELAYED_TAS) { + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + goto send_abort; + } cmd->se_cmd_flags |= SCF_SEND_DELAYED_TAS; + spin_unlock_irqrestore(&cmd->t_state_lock, flags); return; } } +send_abort: cmd->scsi_status = SAM_STAT_TASK_ABORTED; transport_lun_remove_cmd(cmd); @@ -2900,8 +2995,17 @@ static void target_tmr_work(struct work_struct *work) struct se_cmd *cmd = container_of(work, struct se_cmd, work); struct se_device *dev = cmd->se_dev; struct se_tmr_req *tmr = cmd->se_tmr_req; + unsigned long flags; int ret; + spin_lock_irqsave(&cmd->t_state_lock, flags); + if (cmd->transport_state & CMD_T_ABORTED) { + tmr->response = TMR_FUNCTION_REJECTED; + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + goto check_stop; + } + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + switch (tmr->function) { case TMR_ABORT_TASK: core_tmr_abort_task(dev, tmr, cmd->se_sess); @@ -2934,9 +3038,17 @@ static void target_tmr_work(struct work_struct *work) break; } + spin_lock_irqsave(&cmd->t_state_lock, flags); + if (cmd->transport_state & CMD_T_ABORTED) { + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + goto check_stop; + } cmd->t_state = TRANSPORT_ISTATE_PROCESSING; + spin_unlock_irqrestore(&cmd->t_state_lock, flags); + cmd->se_tfo->queue_tm_rsp(cmd); +check_stop: transport_cmd_check_stop_to_fabric(cmd); } diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index e3fbc5a5d88f..6ceac4f2d4b2 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -377,26 +377,28 @@ static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_device, * get_load() - get load for a cpu since last updated * @cpufreq_device: &struct cpufreq_cooling_device for this cpu * @cpu: cpu number + * @cpu_idx: index of the cpu in cpufreq_device->allowed_cpus * * Return: The average load of cpu @cpu in percentage since this * function was last called. */ -static u32 get_load(struct cpufreq_cooling_device *cpufreq_device, int cpu) +static u32 get_load(struct cpufreq_cooling_device *cpufreq_device, int cpu, + int cpu_idx) { u32 load; u64 now, now_idle, delta_time, delta_idle; now_idle = get_cpu_idle_time(cpu, &now, 0); - delta_idle = now_idle - cpufreq_device->time_in_idle[cpu]; - delta_time = now - cpufreq_device->time_in_idle_timestamp[cpu]; + delta_idle = now_idle - cpufreq_device->time_in_idle[cpu_idx]; + delta_time = now - cpufreq_device->time_in_idle_timestamp[cpu_idx]; if (delta_time <= delta_idle) load = 0; else load = div64_u64(100 * (delta_time - delta_idle), delta_time); - cpufreq_device->time_in_idle[cpu] = now_idle; - cpufreq_device->time_in_idle_timestamp[cpu] = now; + cpufreq_device->time_in_idle[cpu_idx] = now_idle; + cpufreq_device->time_in_idle_timestamp[cpu_idx] = now; return load; } @@ -598,7 +600,7 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev, u32 load; if (cpu_online(cpu)) - load = get_load(cpufreq_device, cpu); + load = get_load(cpufreq_device, cpu, i); else load = 0; diff --git a/drivers/thermal/msm-tsens.c b/drivers/thermal/msm-tsens.c index 4b995dcd2d14..9e2ba25ce1ac 100644 --- a/drivers/thermal/msm-tsens.c +++ b/drivers/thermal/msm-tsens.c @@ -926,6 +926,12 @@ static struct of_device_id tsens_match[] = { { .compatible = "qcom,msmcobalt-tsens", .data = (void *)TSENS_CALIB_FUSE_MAP_NONE, }, + { .compatible = "qcom,msmhamster-tsens", + .data = (void *)TSENS_CALIB_FUSE_MAP_NONE, + }, + { .compatible = "qcom,msmfalcon-tsens", + .data = (void *)TSENS_CALIB_FUSE_MAP_NONE, + }, {} }; @@ -970,7 +976,8 @@ static int32_t get_tsens_sensor_for_client_id(struct tsens_tm_device *tmdev, } if (!strcmp(id->compatible, "qcom,msm8996-tsens") || - (!strcmp(id->compatible, "qcom,msmcobalt-tsens"))) { + (!strcmp(id->compatible, "qcom,msmcobalt-tsens")) || + (!strcmp(id->compatible, "qcom,msmhamster-tsens"))) { while (i < tmdev->tsens_num_sensor && !id_found) { if (tmdev->sensor[i].sensor_client_id == sensor_client_id) { @@ -1090,7 +1097,8 @@ int tsens_get_hw_id_mapping(int sensor_sw_id, int *sensor_client_id) } if (!strcmp(id->compatible, "qcom,msm8996-tsens") || - (!strcmp(id->compatible, "qcom,msmcobalt-tsens"))) { + (!strcmp(id->compatible, "qcom,msmcobalt-tsens")) || + (!strcmp(id->compatible, "qcom,msmhamster-tsens"))) { /* Assign a client id which will be used to get the * controller and hw_sensor details */ @@ -5412,10 +5420,12 @@ static int get_device_tree_data(struct platform_device *pdev, (!strcmp(id->compatible, "qcom,msm8994-tsens")) || (!strcmp(id->compatible, "qcom,msm8992-tsens"))) tmdev->tsens_type = TSENS_TYPE2; - else if (!strcmp(id->compatible, "qcom,msm8996-tsens")) + else if (!strcmp(id->compatible, "qcom,msm8996-tsens") || + (!strcmp(id->compatible, "qcom,msmcobalt-tsens"))) tmdev->tsens_type = TSENS_TYPE3; else if (!strcmp(id->compatible, "qcom,msmtitanium-tsens") || - (!strcmp(id->compatible, "qcom,msmcobalt-tsens"))) { + (!strcmp(id->compatible, "qcom,msmfalcon-tsens") || + (!strcmp(id->compatible, "qcom,msmhamster-tsens")))) { tmdev->tsens_type = TSENS_TYPE3; tsens_poll_check = 0; } else if (!strcmp(id->compatible, "qcom,msm8952-tsens") || @@ -5435,7 +5445,9 @@ static int get_device_tree_data(struct platform_device *pdev, (!strcmp(id->compatible, "qcom,msm8952-tsens")) || (!strcmp(id->compatible, "qcom,msm8937-tsens")) || (!strcmp(id->compatible, "qcom,msmtitanium-tsens")) || - (!strcmp(id->compatible, "qcom,msmcobalt-tsens"))) + (!strcmp(id->compatible, "qcom,msmcobalt-tsens")) || + (!strcmp(id->compatible, "qcom,msmfalcon-tsens") || + (!strcmp(id->compatible, "qcom,msmhamster-tsens")))) tmdev->tsens_valid_status_check = true; } @@ -5449,7 +5461,9 @@ static int get_device_tree_data(struct platform_device *pdev, if (!strcmp(id->compatible, "qcom,msm8996-tsens") || (!strcmp(id->compatible, "qcom,msmcobalt-tsens")) || - (!strcmp(id->compatible, "qcom,msmtitanium-tsens"))) { + (!strcmp(id->compatible, "qcom,msmhamster-tsens")) || + (!strcmp(id->compatible, "qcom,msmfalcon-tsens") || + (!strcmp(id->compatible, "qcom,msmtitanium-tsens")))) { tmdev->tsens_critical_irq = platform_get_irq_byname(pdev, "tsens-critical"); diff --git a/drivers/thermal/msm_lmh_dcvs.c b/drivers/thermal/msm_lmh_dcvs.c index 3c37f0728481..cd45eeccbfe7 100644 --- a/drivers/thermal/msm_lmh_dcvs.c +++ b/drivers/thermal/msm_lmh_dcvs.c @@ -44,11 +44,13 @@ #define MSM_LIMITS_ALGO_MODE_ENABLE 0x454E424C #define MSM_LIMITS_HI_THRESHOLD 0x48494748 -#define MSM_LIMITS_LO_THRESHOLD 0x4C4F5700 +#define MSM_LIMITS_ARM_THRESHOLD 0x41524D00 #define MSM_LIMITS_CLUSTER_0 0x6370302D #define MSM_LIMITS_CLUSTER_1 0x6370312D +#define MSM_LIMITS_HIGH_THRESHOLD_VAL 95000 +#define MSM_LIMITS_ARM_THRESHOLD_VAL 65000 #define MSM_LIMITS_POLLING_DELAY_MS 10 #define MSM_LIMITS_CLUSTER_0_REQ 0x179C1B04 #define MSM_LIMITS_CLUSTER_1_REQ 0x179C3B04 @@ -203,7 +205,7 @@ static int lmh_activate_trip(struct thermal_zone_device *dev, hw->temp_limits[LIMITS_TRIP_HI]) return -EINVAL; - thresh = (trip == LIMITS_TRIP_LO) ? MSM_LIMITS_LO_THRESHOLD : + thresh = (trip == LIMITS_TRIP_LO) ? MSM_LIMITS_ARM_THRESHOLD : MSM_LIMITS_HI_THRESHOLD; temp = hw->temp_limits[trip]; @@ -306,11 +308,11 @@ static int msm_lmh_dcvs_probe(struct platform_device *pdev) if (ret) return ret; - hw->default_lo.temp = 65000; + hw->default_lo.temp = MSM_LIMITS_ARM_THRESHOLD_VAL; hw->default_lo.trip = THERMAL_TRIP_CONFIGURABLE_LOW; hw->default_lo.notify = trip_notify; - hw->default_hi.temp = 95000; + hw->default_hi.temp = MSM_LIMITS_HIGH_THRESHOLD_VAL; hw->default_hi.trip = THERMAL_TRIP_CONFIGURABLE_HI; hw->default_hi.notify = trip_notify; diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c index f36108542738..bbc6a8e96d41 100644 --- a/drivers/thermal/msm_thermal.c +++ b/drivers/thermal/msm_thermal.c @@ -5879,6 +5879,13 @@ static int probe_vdd_mx(struct device_node *node, if (ret) goto read_node_done; + /* + * Monitor only this sensor if defined, otherwise monitor all tsens + */ + key = "qcom,mx-restriction-sensor_id"; + if (of_property_read_u32(node, key, &data->vdd_mx_sensor_id)) + data->vdd_mx_sensor_id = MONITOR_ALL_TSENS; + vdd_mx = devm_regulator_get(&pdev->dev, "vdd-mx"); if (IS_ERR_OR_NULL(vdd_mx)) { ret = PTR_ERR(vdd_mx); @@ -5905,7 +5912,7 @@ static int probe_vdd_mx(struct device_node *node, } ret = sensor_mgr_init_threshold(&thresh[MSM_VDD_MX_RESTRICTION], - MONITOR_ALL_TSENS, + data->vdd_mx_sensor_id, data->vdd_mx_temp_degC + data->vdd_mx_temp_hyst_degC, data->vdd_mx_temp_degC, vdd_mx_notify); @@ -6878,6 +6885,9 @@ static void thermal_mx_config_read(struct seq_file *m, void *data) if (vdd_cx) seq_printf(m, "cx retention value:%d\n", msm_thermal_info.vdd_cx_min); + if (msm_thermal_info.vdd_mx_sensor_id != MONITOR_ALL_TSENS) + seq_printf(m, "tsens sensor:tsens_tz_sensor%d\n", + msm_thermal_info.vdd_mx_sensor_id); } } diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c index 2f9f7086ac3d..ea9366ad3e6b 100644 --- a/drivers/thermal/step_wise.c +++ b/drivers/thermal/step_wise.c @@ -63,6 +63,19 @@ static unsigned long get_target_state(struct thermal_instance *instance, next_target = instance->target; dev_dbg(&cdev->device, "cur_state=%ld\n", cur_state); + if (!instance->initialized) { + if (throttle) { + next_target = (cur_state + 1) >= instance->upper ? + instance->upper : + ((cur_state + 1) < instance->lower ? + instance->lower : (cur_state + 1)); + } else { + next_target = THERMAL_NO_TARGET; + } + + return next_target; + } + switch (trend) { case THERMAL_TREND_RAISING: if (throttle) { @@ -149,7 +162,7 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) dev_dbg(&instance->cdev->device, "old_target=%d, target=%d\n", old_target, (int)instance->target); - if (old_target == instance->target) + if (instance->initialized && old_target == instance->target) continue; /* Activate a passive thermal instance */ @@ -161,7 +174,7 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) instance->target == THERMAL_NO_TARGET) update_passive_instance(tz, trip_type, -1); - + instance->initialized = true; instance->cdev->updated = false; /* cdev needs update */ } diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 625ce0b64987..df8c82aa2dd9 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -39,6 +39,7 @@ #include <linux/kthread.h> #include <net/netlink.h> #include <net/genetlink.h> +#include <linux/suspend.h> #define CREATE_TRACE_POINTS #include <trace/events/thermal.h> @@ -63,6 +64,8 @@ static LIST_HEAD(thermal_governor_list); static DEFINE_MUTEX(thermal_list_lock); static DEFINE_MUTEX(thermal_governor_lock); +static atomic_t in_suspend; + static struct thermal_governor *def_governor; static struct thermal_governor *__find_governor(const char *name) @@ -932,14 +935,31 @@ static void update_temperature(struct thermal_zone_device *tz) mutex_unlock(&tz->lock); trace_thermal_temperature(tz); - dev_dbg(&tz->device, "last_temperature=%d, current_temperature=%d\n", - tz->last_temperature, tz->temperature); + if (tz->last_temperature == THERMAL_TEMP_INVALID) + dev_dbg(&tz->device, "last_temperature N/A, current_temperature=%d\n", + tz->temperature); + else + dev_dbg(&tz->device, "last_temperature=%d, current_temperature=%d\n", + tz->last_temperature, tz->temperature); +} + +static void thermal_zone_device_reset(struct thermal_zone_device *tz) +{ + struct thermal_instance *pos; + + tz->temperature = THERMAL_TEMP_INVALID; + tz->passive = 0; + list_for_each_entry(pos, &tz->thermal_instances, tz_node) + pos->initialized = false; } void thermal_zone_device_update(struct thermal_zone_device *tz) { int count; + if (atomic_read(&in_suspend)) + return; + if (!tz->ops->get_temp) return; @@ -1771,6 +1791,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, if (!result) { list_add_tail(&dev->tz_node, &tz->thermal_instances); list_add_tail(&dev->cdev_node, &cdev->thermal_instances); + atomic_set(&tz->need_update, 1); } mutex_unlock(&cdev->lock); mutex_unlock(&tz->lock); @@ -1880,6 +1901,7 @@ __thermal_cooling_device_register(struct device_node *np, const struct thermal_cooling_device_ops *ops) { struct thermal_cooling_device *cdev; + struct thermal_zone_device *pos = NULL; int result; if (type && strlen(type) >= THERMAL_NAME_LENGTH) @@ -1924,6 +1946,12 @@ __thermal_cooling_device_register(struct device_node *np, /* Update binding information for 'this' new cdev */ bind_cdev(cdev); + mutex_lock(&thermal_list_lock); + list_for_each_entry(pos, &thermal_tz_list, node) + if (atomic_cmpxchg(&pos->need_update, 1, 0)) + thermal_zone_device_update(pos); + mutex_unlock(&thermal_list_lock); + return cdev; } @@ -2257,6 +2285,8 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type, tz->trips = trips; tz->passive_delay = passive_delay; tz->polling_delay = polling_delay; + /* A new thermal zone needs to be updated anyway. */ + atomic_set(&tz->need_update, 1); dev_set_name(&tz->device, "thermal_zone%d", tz->id); result = device_register(&tz->device); @@ -2352,7 +2382,10 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type, INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check); - thermal_zone_device_update(tz); + thermal_zone_device_reset(tz); + /* Update the new thermal zone and mark it as already updated. */ + if (atomic_cmpxchg(&tz->need_update, 1, 0)) + thermal_zone_device_update(tz); return tz; @@ -2597,6 +2630,36 @@ static void thermal_unregister_governors(void) thermal_gov_power_allocator_unregister(); } +static int thermal_pm_notify(struct notifier_block *nb, + unsigned long mode, void *_unused) +{ + struct thermal_zone_device *tz; + + switch (mode) { + case PM_HIBERNATION_PREPARE: + case PM_RESTORE_PREPARE: + case PM_SUSPEND_PREPARE: + atomic_set(&in_suspend, 1); + break; + case PM_POST_HIBERNATION: + case PM_POST_RESTORE: + case PM_POST_SUSPEND: + atomic_set(&in_suspend, 0); + list_for_each_entry(tz, &thermal_tz_list, node) { + thermal_zone_device_reset(tz); + thermal_zone_device_update(tz); + } + break; + default: + break; + } + return 0; +} + +static struct notifier_block thermal_pm_nb = { + .notifier_call = thermal_pm_notify, +}; + static int __init thermal_init(void) { int result; @@ -2617,6 +2680,11 @@ static int __init thermal_init(void) if (result) goto exit_netlink; + result = register_pm_notifier(&thermal_pm_nb); + if (result) + pr_warn("Thermal: Can not register suspend notifier, return %d\n", + result); + return 0; exit_netlink: @@ -2636,6 +2704,7 @@ error: static void __exit thermal_exit(void) { + unregister_pm_notifier(&thermal_pm_nb); of_thermal_destroy_zones(); genetlink_exit(); class_unregister(&thermal_class); diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h index d7ac1fccd659..749d41abfbab 100644 --- a/drivers/thermal/thermal_core.h +++ b/drivers/thermal/thermal_core.h @@ -41,6 +41,7 @@ struct thermal_instance { struct thermal_zone_device *tz; struct thermal_cooling_device *cdev; int trip; + bool initialized; unsigned long upper; /* Highest cooling state for this trip point */ unsigned long lower; /* Lowest cooling state for this trip point */ unsigned long target; /* expected cooling state */ diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index 45f86da1d6d3..03b6743461d1 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -158,7 +158,7 @@ static void ci_otg_work(struct work_struct *work) int ci_hdrc_otg_init(struct ci_hdrc *ci) { INIT_WORK(&ci->work, ci_otg_work); - ci->wq = create_singlethread_workqueue("ci_otg"); + ci->wq = create_freezable_workqueue("ci_otg"); if (!ci->wq) { dev_err(ci->dev, "can't create workqueue\n"); return -ENODEV; diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index e4c70dce3e7c..fa4e23930614 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1841,6 +1841,11 @@ static const struct usb_device_id acm_ids[] = { }, #endif + /*Samsung phone in firmware update mode */ + { USB_DEVICE(0x04e8, 0x685d), + .driver_info = IGNORE_DEVICE, + }, + /* Exclude Infineon Flash Loader utility */ { USB_DEVICE(0x058b, 0x0041), .driver_info = IGNORE_DEVICE, diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 9b2b98cf1823..5cc655908fda 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2202,8 +2202,65 @@ int usb_hcd_get_frame_number (struct usb_device *udev) return hcd->driver->get_frame_number (hcd); } +int usb_hcd_sec_event_ring_setup(struct usb_device *udev, + unsigned intr_num) +{ + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + + if (!HCD_RH_RUNNING(hcd)) + return 0; + + return hcd->driver->sec_event_ring_setup(hcd, intr_num); +} + +int usb_hcd_sec_event_ring_cleanup(struct usb_device *udev, + unsigned intr_num) +{ + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + + if (!HCD_RH_RUNNING(hcd)) + return 0; + + return hcd->driver->sec_event_ring_cleanup(hcd, intr_num); +} + /*-------------------------------------------------------------------------*/ +dma_addr_t +usb_hcd_get_sec_event_ring_dma_addr(struct usb_device *udev, + unsigned intr_num) +{ + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + + if (!HCD_RH_RUNNING(hcd)) + return 0; + + return hcd->driver->get_sec_event_ring_dma_addr(hcd, intr_num); +} + +dma_addr_t +usb_hcd_get_dcba_dma_addr(struct usb_device *udev) +{ + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + + if (!HCD_RH_RUNNING(hcd)) + return 0; + + return hcd->driver->get_dcba_dma_addr(hcd, udev); +} + +dma_addr_t +usb_hcd_get_xfer_ring_dma_addr(struct usb_device *udev, + struct usb_host_endpoint *ep) +{ + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + + if (!HCD_RH_RUNNING(hcd)) + return 0; + + return hcd->driver->get_xfer_ring_dma_addr(hcd, udev, ep); +} + #ifdef CONFIG_PM int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg) diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index f8bbd0b6d9fe..b43d542e3bd4 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -669,6 +669,57 @@ int usb_get_current_frame_number(struct usb_device *dev) } EXPORT_SYMBOL_GPL(usb_get_current_frame_number); +int usb_sec_event_ring_setup(struct usb_device *dev, + unsigned intr_num) +{ + if (dev->state == USB_STATE_NOTATTACHED) + return 0; + + return usb_hcd_sec_event_ring_setup(dev, intr_num); +} +EXPORT_SYMBOL(usb_sec_event_ring_setup); + +int usb_sec_event_ring_cleanup(struct usb_device *dev, + unsigned intr_num) +{ + if (dev->state == USB_STATE_NOTATTACHED) + return 0; + + return usb_hcd_sec_event_ring_cleanup(dev, intr_num); +} +EXPORT_SYMBOL(usb_sec_event_ring_cleanup); + +dma_addr_t +usb_get_sec_event_ring_dma_addr(struct usb_device *dev, + unsigned intr_num) +{ + if (dev->state == USB_STATE_NOTATTACHED) + return 0; + + return usb_hcd_get_sec_event_ring_dma_addr(dev, intr_num); +} +EXPORT_SYMBOL(usb_get_sec_event_ring_dma_addr); + +dma_addr_t +usb_get_dcba_dma_addr(struct usb_device *dev) +{ + if (dev->state == USB_STATE_NOTATTACHED) + return 0; + + return usb_hcd_get_dcba_dma_addr(dev); +} +EXPORT_SYMBOL(usb_get_dcba_dma_addr); + +dma_addr_t usb_get_xfer_ring_dma_addr(struct usb_device *dev, + struct usb_host_endpoint *ep) +{ + if (dev->state == USB_STATE_NOTATTACHED) + return 0; + + return usb_hcd_get_xfer_ring_dma_addr(dev, ep); +} +EXPORT_SYMBOL(usb_get_xfer_ring_dma_addr); + /*-------------------------------------------------------------------*/ /* * __usb_get_extra_descriptor() finds a descriptor of specific type in the diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index a395097a2098..7585c603cb3d 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1021,8 +1021,8 @@ static int dwc3_probe(struct platform_device *pdev) /* will be enabled in dwc3_msm_resume() */ irq_set_status_flags(irq, IRQ_NOAUTOEN); - ret = devm_request_irq(dev, irq, dwc3_interrupt, IRQF_SHARED, "dwc3", - dwc); + ret = devm_request_threaded_irq(dev, irq, NULL, dwc3_interrupt, + IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc); if (ret) { dev_err(dwc->dev, "failed to request irq #%d --> %d\n", irq, ret); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index fa2a9d9a293a..95191221bc3c 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -513,6 +513,7 @@ struct dwc3_ep_events { * @trb_dma_pool: dma pool used to get aligned trb memory pool * @trb_pool: array of transaction buffers * @trb_pool_dma: dma address of @trb_pool + * @num_trbs: num of trbs in the trb dma pool * @free_slot: next slot which is going to be used * @busy_slot: first slot which is owned by HW * @desc: usb_endpoint_descriptor pointer @@ -539,6 +540,7 @@ struct dwc3_ep { struct dma_pool *trb_dma_pool; struct dwc3_trb *trb_pool; dma_addr_t trb_pool_dma; + u32 num_trbs; u32 free_slot; u32 busy_slot; const struct usb_ss_ep_comp_descriptor *comp_desc; @@ -964,7 +966,6 @@ struct dwc3 { unsigned pullups_connected:1; unsigned resize_fifos:1; unsigned setup_packet_pending:1; - unsigned start_config_issued:1; unsigned three_stage_setup:1; unsigned usb3_lpm_capable:1; diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index f9c0b6a04224..49bed21b1284 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -969,6 +969,8 @@ static int gsi_prepare_trbs(struct usb_ep *ep, struct usb_gsi_request *req) return -ENOMEM; } + dep->num_trbs = num_trbs; + dep->trb_pool = dma_pool_alloc(dep->trb_dma_pool, GFP_KERNEL, &dep->trb_pool_dma); if (!dep->trb_pool) { diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 283f648a5e05..4ee0faa87cff 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -586,7 +586,6 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) int ret; u32 reg; - dwc->start_config_issued = false; cfg = le16_to_cpu(ctrl->wValue); switch (state) { @@ -772,9 +771,6 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_ISOCH_DELAY"); ret = dwc3_ep0_set_isoch_delay(dwc, ctrl); break; - case USB_REQ_SET_INTERFACE: - dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_INTERFACE"); - /* Fall through */ default: dwc3_trace(trace_dwc3_ep0, "Forwarding to gadget driver"); ret = dwc3_ep0_delegate_req(dwc, ctrl); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 76d39a6fb68c..35994b827549 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -390,18 +390,20 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, static int dwc3_alloc_trb_pool(struct dwc3_ep *dep) { struct dwc3 *dwc = dep->dwc; + u32 num_trbs = DWC3_TRB_NUM; if (dep->trb_pool) return 0; dep->trb_pool = dma_zalloc_coherent(dwc->dev, - sizeof(struct dwc3_trb) * DWC3_TRB_NUM, + sizeof(struct dwc3_trb) * num_trbs, &dep->trb_pool_dma, GFP_KERNEL); if (!dep->trb_pool) { dev_err(dep->dwc->dev, "failed to allocate trb pool for %s\n", dep->name); return -ENOMEM; } + dep->num_trbs = num_trbs; return 0; } @@ -424,24 +426,66 @@ static void dwc3_free_trb_pool(struct dwc3_ep *dep) } } +static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep); + +/** + * dwc3_gadget_start_config - Configure EP resources + * @dwc: pointer to our controller context structure + * @dep: endpoint that is being enabled + * + * The assignment of transfer resources cannot perfectly follow the + * data book due to the fact that the controller driver does not have + * all knowledge of the configuration in advance. It is given this + * information piecemeal by the composite gadget framework after every + * SET_CONFIGURATION and SET_INTERFACE. Trying to follow the databook + * programming model in this scenario can cause errors. For two + * reasons: + * + * 1) The databook says to do DEPSTARTCFG for every SET_CONFIGURATION + * and SET_INTERFACE (8.1.5). This is incorrect in the scenario of + * multiple interfaces. + * + * 2) The databook does not mention doing more DEPXFERCFG for new + * endpoint on alt setting (8.1.6). + * + * The following simplified method is used instead: + * + * All hardware endpoints can be assigned a transfer resource and this + * setting will stay persistent until either a core reset or + * hibernation. So whenever we do a DEPSTARTCFG(0) we can go ahead and + * do DEPXFERCFG for every hardware endpoint as well. We are + * guaranteed that there are as many transfer resources as endpoints. + * + * This function is called for each endpoint when it is being enabled + * but is triggered only when called for EP0-out, which always happens + * first, and which should only happen in one of the above conditions. + */ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep) { struct dwc3_gadget_ep_cmd_params params; u32 cmd; + int i; + int ret; + + if (dep->number) + return 0; memset(¶ms, 0x00, sizeof(params)); + cmd = DWC3_DEPCMD_DEPSTARTCFG; - if (dep->number != 1) { - cmd = DWC3_DEPCMD_DEPSTARTCFG; - /* XferRscIdx == 0 for ep0 and 2 for the remaining */ - if (dep->number > 1) { - if (dwc->start_config_issued) - return 0; - dwc->start_config_issued = true; - cmd |= DWC3_DEPCMD_PARAM(2); - } + ret = dwc3_send_gadget_ep_cmd(dwc, 0, cmd, ¶ms); + if (ret) + return ret; + + for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) { + struct dwc3_ep *dep = dwc->eps[i]; - return dwc3_send_gadget_ep_cmd(dwc, 0, cmd, ¶ms); + if (!dep) + continue; + + ret = dwc3_gadget_set_xfer_resource(dwc, dep); + if (ret) + return ret; } return 0; @@ -567,13 +611,6 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, struct dwc3_trb *trb_st_hw; struct dwc3_trb *trb_link; - ret = dwc3_gadget_set_xfer_resource(dwc, dep); - if (ret) { - dev_err(dwc->dev, "set_xfer_resource() failed for %s\n", - dep->name); - return ret; - } - dep->endpoint.desc = desc; dep->comp_desc = comp_desc; dep->type = usb_endpoint_type(desc); @@ -688,7 +725,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) */ if (dep->number > 1) { memset(&dep->trb_pool[0], 0, - sizeof(struct dwc3_trb) * DWC3_TRB_NUM); + sizeof(struct dwc3_trb) * dep->num_trbs); dbg_event(dep->number, "Clr_TRB", 0); } @@ -1750,6 +1787,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (is_on) { + dbg_event(0xFF, "Pullup_enable", is_on); if (dwc->revision <= DWC3_REVISION_187A) { reg &= ~DWC3_DCTL_TRGTULST_MASK; reg |= DWC3_DCTL_TRGTULST_RX_DET; @@ -1787,6 +1825,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) dwc->pullups_connected = true; } else { + dbg_event(0xFF, "Pullup_disable", is_on); dwc3_gadget_disable_irq(dwc); __dwc3_gadget_ep_disable(dwc->eps[0]); __dwc3_gadget_ep_disable(dwc->eps[1]); @@ -1812,8 +1851,15 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) break; } timeout--; - if (!timeout) + if (!timeout) { + dev_err(dwc->dev, "failed to %s controller\n", + is_on ? "start" : "stop"); + if (is_on) + dbg_event(0xFF, "STARTTOUT", reg); + else + dbg_event(0xFF, "STOPTOUT", reg); return -ETIMEDOUT; + } udelay(1); } while (1); @@ -2011,8 +2057,6 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GSBUSCFG1, reg); } - dwc->start_config_issued = false; - /* Start with SuperSpeed Default */ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512); @@ -2722,7 +2766,6 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) dbg_event(0xFF, "DISCONNECT", 0); dwc3_disconnect_gadget(dwc); - dwc->start_config_issued = false; dwc->gadget.speed = USB_SPEED_UNKNOWN; dwc->setup_packet_pending = false; @@ -2783,7 +2826,6 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) dwc3_stop_active_transfers(dwc); dwc3_clear_stall_all_ep(dwc); - dwc->start_config_issued = false; /* bus reset issued due to missing status stage of a control transfer */ dwc->resize_fifos = 0; diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 6964933e5077..468a7bcd8dbd 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -2387,7 +2387,7 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f) info.in_epname = "gsi-epin"; info.out_epname = "gsi-epout"; gsi->d_port.in_aggr_size = GSI_IN_MBIM_AGGR_SIZE; - info.in_req_buf_len = GSI_IN_BUFF_SIZE; + info.in_req_buf_len = GSI_IN_MBIM_AGGR_SIZE; info.in_req_num_buf = num_in_bufs; gsi->d_port.out_aggr_size = GSI_OUT_AGGR_SIZE; info.out_req_buf_len = GSI_OUT_MBIM_BUF_LEN; @@ -2459,12 +2459,12 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f) info.ss_desc_hdr = ecm_gsi_ss_function; info.in_epname = "gsi-epin"; info.out_epname = "gsi-epout"; - gsi->d_port.in_aggr_size = GSI_IN_ECM_AGGR_SIZE; + gsi->d_port.in_aggr_size = GSI_ECM_AGGR_SIZE; info.in_req_buf_len = GSI_IN_BUFF_SIZE; info.in_req_num_buf = num_in_bufs; - gsi->d_port.out_aggr_size = GSI_OUT_AGGR_SIZE; + gsi->d_port.out_aggr_size = GSI_ECM_AGGR_SIZE; info.out_req_buf_len = GSI_OUT_ECM_BUF_LEN; - info.out_req_num_buf = num_out_bufs; + info.out_req_num_buf = GSI_ECM_NUM_OUT_BUFFERS; info.notify_buf_len = GSI_CTRL_NOTIFY_BUFF_LEN; /* export host's Ethernet address in CDC format */ @@ -2574,11 +2574,16 @@ static void gsi_unbind(struct usb_configuration *c, struct usb_function *f) if (gsi->prot_id == IPA_USB_MBIM) mbim_gsi_ext_config_desc.function.subCompatibleID[0] = 0; - if (gadget_is_superspeed(c->cdev->gadget)) + if (gadget_is_superspeed(c->cdev->gadget)) { usb_free_descriptors(f->ss_descriptors); - if (gadget_is_dualspeed(c->cdev->gadget)) + f->ss_descriptors = NULL; + } + if (gadget_is_dualspeed(c->cdev->gadget)) { usb_free_descriptors(f->hs_descriptors); + f->hs_descriptors = NULL; + } usb_free_descriptors(f->fs_descriptors); + f->fs_descriptors = NULL; if (gsi->c_port.notify) { kfree(gsi->c_port.notify_req->buf); diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h index eb42feff0712..d56012779c78 100644 --- a/drivers/usb/gadget/function/f_gsi.h +++ b/drivers/usb/gadget/function/f_gsi.h @@ -38,12 +38,13 @@ #define GSI_NUM_IN_BUFFERS 7 #define GSI_IN_BUFF_SIZE 2048 #define GSI_NUM_OUT_BUFFERS 7 +#define GSI_ECM_NUM_OUT_BUFFERS 31 #define GSI_OUT_AGGR_SIZE 24576 #define GSI_IN_RNDIS_AGGR_SIZE 9216 #define GSI_IN_MBIM_AGGR_SIZE 16384 #define GSI_IN_RMNET_AGGR_SIZE 16384 -#define GSI_IN_ECM_AGGR_SIZE 2048 +#define GSI_ECM_AGGR_SIZE 2048 #define GSI_OUT_MBIM_BUF_LEN 16384 #define GSI_OUT_RMNET_BUF_LEN 16384 diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index bea936a6678b..e0b77946f013 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -1258,6 +1258,9 @@ static ssize_t debug_read_status(struct file *file, char __user *ubuf, int ret; int result = 0; + if (!ui_dev) + return -EINVAL; + tty = ui_dev->port.tty; gser = ui_dev->port_usb; @@ -1307,6 +1310,9 @@ static ssize_t debug_write_reset(struct file *file, const char __user *buf, struct gs_port *ui_dev = file->private_data; unsigned long flags; + if (!ui_dev) + return -EINVAL; + spin_lock_irqsave(&ui_dev->port_lock, flags); ui_dev->nbytes_from_host = ui_dev->nbytes_to_tty = ui_dev->nbytes_from_tty = ui_dev->nbytes_to_host = 0; @@ -1336,6 +1342,9 @@ static void usb_debugfs_init(struct gs_port *ui_dev, int port_num) { char buf[48]; + if (!ui_dev) + return; + snprintf(buf, 48, "usb_serial%d", port_num); gs_dent = debugfs_create_dir(buf, 0); if (!gs_dent || IS_ERR(gs_dent)) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index c48cbe731356..2ac142e3cce9 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1786,25 +1786,73 @@ void xhci_free_command(struct xhci_hcd *xhci, kfree(command); } -void xhci_mem_cleanup(struct xhci_hcd *xhci) +int xhci_sec_event_ring_cleanup(struct usb_hcd *hcd, unsigned intr_num) { + int size; + struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct device *dev = xhci_to_hcd(xhci)->self.controller; + + if (intr_num > xhci->max_interrupters) { + xhci_err(xhci, "invalid secondary interrupter num %d\n", + intr_num); + return -EINVAL; + } + + size = + sizeof(struct xhci_erst_entry)*(xhci->sec_erst[intr_num].num_entries); + if (xhci->sec_erst[intr_num].entries) + dma_free_coherent(dev, size, xhci->sec_erst[intr_num].entries, + xhci->sec_erst[intr_num].erst_dma_addr); + xhci->sec_erst[intr_num].entries = NULL; + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed SEC ERST#%d", + intr_num); + if (xhci->sec_event_ring[intr_num]) + xhci_ring_free(xhci, xhci->sec_event_ring[intr_num]); + xhci->sec_event_ring[intr_num] = NULL; + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Freed sec event ring"); + + return 0; +} + +void xhci_event_ring_cleanup(struct xhci_hcd *xhci) +{ int size; - int i, j, num_ports; + unsigned int i; + struct device *dev = xhci_to_hcd(xhci)->self.controller; - del_timer_sync(&xhci->cmd_timer); + /* sec event ring clean up */ + for (i = 1; i <= xhci->max_interrupters; i++) + xhci_sec_event_ring_cleanup(xhci_to_hcd(xhci), i); - /* Free the Event Ring Segment Table and the actual Event Ring */ + kfree(xhci->sec_ir_set); + xhci->sec_ir_set = NULL; + kfree(xhci->sec_erst); + xhci->sec_erst = NULL; + kfree(xhci->sec_event_ring); + xhci->sec_event_ring = NULL; + + /* primary event ring clean up */ size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries); if (xhci->erst.entries) dma_free_coherent(dev, size, xhci->erst.entries, xhci->erst.erst_dma_addr); xhci->erst.entries = NULL; - xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed ERST"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed primary ERST"); if (xhci->event_ring) xhci_ring_free(xhci, xhci->event_ring); xhci->event_ring = NULL; - xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed event ring"); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed priamry event ring"); +} + +void xhci_mem_cleanup(struct xhci_hcd *xhci) +{ + struct device *dev = xhci_to_hcd(xhci)->self.controller; + int i, j, num_ports; + + del_timer_sync(&xhci->cmd_timer); + + xhci_event_ring_cleanup(xhci); if (xhci->lpm_command) xhci_free_command(xhci, xhci->lpm_command); @@ -2039,30 +2087,6 @@ static int xhci_check_trb_in_td_math(struct xhci_hcd *xhci) return 0; } -static void xhci_set_hc_event_deq(struct xhci_hcd *xhci) -{ - u64 temp; - dma_addr_t deq; - - deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, - xhci->event_ring->dequeue); - if (deq == 0 && !in_interrupt()) - xhci_warn(xhci, "WARN something wrong with SW event ring " - "dequeue ptr.\n"); - /* Update HC event ring dequeue pointer */ - temp = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); - temp &= ERST_PTR_MASK; - /* Don't clear the EHB bit (which is RW1C) because - * there might be more events to service. - */ - temp &= ~ERST_EHB; - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Write event ring dequeue pointer, " - "preserving EHB bit"); - xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp, - &xhci->ir_set->erst_dequeue); -} - static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, __le32 __iomem *addr, u8 major_revision, int max_caps) { @@ -2340,13 +2364,184 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) return 0; } +int xhci_event_ring_setup(struct xhci_hcd *xhci, struct xhci_ring **er, + struct xhci_intr_reg __iomem *ir_set, struct xhci_erst *erst, + unsigned int intr_num, gfp_t flags) +{ + dma_addr_t dma, deq; + u64 val_64; + unsigned int val; + struct xhci_segment *seg; + struct device *dev = xhci_to_hcd(xhci)->self.controller; + + *er = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, + TYPE_EVENT, flags); + if (!*er) + return -ENOMEM; + + erst->entries = dma_alloc_coherent(dev, + sizeof(struct xhci_erst_entry) * ERST_NUM_SEGS, &dma, + flags); + if (!erst->entries) { + xhci_ring_free(xhci, *er); + return -ENOMEM; + } + + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "intr# %d: Allocated event ring segment table at 0x%llx", + intr_num, (unsigned long long)dma); + + memset(erst->entries, 0, sizeof(struct xhci_erst_entry)*ERST_NUM_SEGS); + erst->num_entries = ERST_NUM_SEGS; + erst->erst_dma_addr = dma; + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "intr# %d: num segs = %i, virt addr = %p, dma addr = 0x%llx", + intr_num, + erst->num_entries, + erst->entries, + (unsigned long long)erst->erst_dma_addr); + + /* set ring base address and size for each segment table entry */ + for (val = 0, seg = (*er)->first_seg; val < ERST_NUM_SEGS; val++) { + struct xhci_erst_entry *entry = &erst->entries[val]; + + entry->seg_addr = cpu_to_le64(seg->dma); + entry->seg_size = cpu_to_le32(TRBS_PER_SEGMENT); + entry->rsvd = 0; + seg = seg->next; + } + + /* set ERST count with the number of entries in the segment table */ + val = readl_relaxed(&ir_set->erst_size); + val &= ERST_SIZE_MASK; + val |= ERST_NUM_SEGS; + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Write ERST size = %i to ir_set %d (some bits preserved)", val, + intr_num); + writel_relaxed(val, &ir_set->erst_size); + + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "intr# %d: Set ERST entries to point to event ring.", + intr_num); + /* set the segment table base address */ + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Set ERST base address for ir_set %d = 0x%llx", + intr_num, + (unsigned long long)erst->erst_dma_addr); + val_64 = xhci_read_64(xhci, &ir_set->erst_base); + val_64 &= ERST_PTR_MASK; + val_64 |= (erst->erst_dma_addr & (u64) ~ERST_PTR_MASK); + xhci_write_64(xhci, val_64, &ir_set->erst_base); + + /* Set the event ring dequeue address */ + deq = xhci_trb_virt_to_dma((*er)->deq_seg, (*er)->dequeue); + if (deq == 0 && !in_interrupt()) + xhci_warn(xhci, + "intr# %d:WARN something wrong with SW event ring deq ptr.\n", + intr_num); + /* Update HC event ring dequeue pointer */ + val_64 = xhci_read_64(xhci, &ir_set->erst_dequeue); + val_64 &= ERST_PTR_MASK; + /* Don't clear the EHB bit (which is RW1C) because + * there might be more events to service. + */ + val_64 &= ~ERST_EHB; + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "intr# %d:Write event ring dequeue pointer, preserving EHB bit", + intr_num); + xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | val_64, + &ir_set->erst_dequeue); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Wrote ERST address to ir_set %d.", intr_num); + xhci_print_ir_set(xhci, intr_num); + + return 0; +} + +int xhci_sec_event_ring_setup(struct usb_hcd *hcd, unsigned intr_num) +{ + int ret; + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + if ((xhci->xhc_state & XHCI_STATE_HALTED) || !xhci->sec_ir_set + || !xhci->sec_event_ring || !xhci->sec_erst || + intr_num > xhci->max_interrupters) { + xhci_err(xhci, + "%s:state %x ir_set %p evt_ring %p erst %p intr# %d\n", + __func__, xhci->xhc_state, xhci->sec_ir_set, + xhci->sec_event_ring, xhci->sec_erst, intr_num); + return -EINVAL; + } + + if (xhci->sec_event_ring && xhci->sec_event_ring[intr_num] + && xhci->sec_event_ring[intr_num]->first_seg) + goto done; + + xhci->sec_ir_set[intr_num] = &xhci->run_regs->ir_set[intr_num]; + ret = xhci_event_ring_setup(xhci, + &xhci->sec_event_ring[intr_num], + xhci->sec_ir_set[intr_num], + &xhci->sec_erst[intr_num], + intr_num, GFP_KERNEL); + if (ret) { + xhci_err(xhci, "sec event ring setup failed inter#%d\n", + intr_num); + return ret; + } +done: + return 0; +} + +int xhci_event_ring_init(struct xhci_hcd *xhci, gfp_t flags) +{ + int ret = 0; + + /* primary + secondary */ + xhci->max_interrupters = HCS_MAX_INTRS(xhci->hcs_params1); + + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "// Allocating primary event ring"); + + /* Set ir_set to interrupt register set 0 */ + xhci->ir_set = &xhci->run_regs->ir_set[0]; + ret = xhci_event_ring_setup(xhci, &xhci->event_ring, xhci->ir_set, + &xhci->erst, 0, flags); + if (ret) { + xhci_err(xhci, "failed to setup primary event ring\n"); + goto fail; + } + + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "// Allocating sec event ring related pointers"); + + xhci->sec_ir_set = kcalloc(xhci->max_interrupters, + sizeof(*xhci->sec_ir_set), flags); + if (!xhci->sec_ir_set) { + ret = -ENOMEM; + goto fail; + } + + xhci->sec_event_ring = kcalloc(xhci->max_interrupters, + sizeof(*xhci->sec_event_ring), flags); + if (!xhci->sec_event_ring) { + ret = -ENOMEM; + goto fail; + } + + xhci->sec_erst = kcalloc(xhci->max_interrupters, + sizeof(*xhci->sec_erst), flags); + if (!xhci->sec_erst) + ret = -ENOMEM; +fail: + return ret; +} + int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) { dma_addr_t dma; struct device *dev = xhci_to_hcd(xhci)->self.controller; unsigned int val, val2; u64 val_64; - struct xhci_segment *seg; u32 page_size, temp; int i; @@ -2472,73 +2667,16 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) xhci->dba = (void __iomem *) xhci->cap_regs + val; xhci_dbg_regs(xhci); xhci_print_run_regs(xhci); - /* Set ir_set to interrupt register set 0 */ - xhci->ir_set = &xhci->run_regs->ir_set[0]; /* * Event ring setup: Allocate a normal ring, but also setup * the event ring segment table (ERST). Section 4.9.3. */ - xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Allocating event ring"); - xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT, - flags); - if (!xhci->event_ring) - goto fail; - if (xhci_check_trb_in_td_math(xhci) < 0) + if (xhci_event_ring_init(xhci, GFP_KERNEL)) goto fail; - xhci->erst.entries = dma_alloc_coherent(dev, - sizeof(struct xhci_erst_entry) * ERST_NUM_SEGS, &dma, - GFP_KERNEL); - if (!xhci->erst.entries) + if (xhci_check_trb_in_td_math(xhci) < 0) goto fail; - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Allocated event ring segment table at 0x%llx", - (unsigned long long)dma); - - memset(xhci->erst.entries, 0, sizeof(struct xhci_erst_entry)*ERST_NUM_SEGS); - xhci->erst.num_entries = ERST_NUM_SEGS; - xhci->erst.erst_dma_addr = dma; - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "Set ERST to 0; private num segs = %i, virt addr = %p, dma addr = 0x%llx", - xhci->erst.num_entries, - xhci->erst.entries, - (unsigned long long)xhci->erst.erst_dma_addr); - - /* set ring base address and size for each segment table entry */ - for (val = 0, seg = xhci->event_ring->first_seg; val < ERST_NUM_SEGS; val++) { - struct xhci_erst_entry *entry = &xhci->erst.entries[val]; - entry->seg_addr = cpu_to_le64(seg->dma); - entry->seg_size = cpu_to_le32(TRBS_PER_SEGMENT); - entry->rsvd = 0; - seg = seg->next; - } - - /* set ERST count with the number of entries in the segment table */ - val = readl(&xhci->ir_set->erst_size); - val &= ERST_SIZE_MASK; - val |= ERST_NUM_SEGS; - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Write ERST size = %i to ir_set 0 (some bits preserved)", - val); - writel(val, &xhci->ir_set->erst_size); - - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Set ERST entries to point to event ring."); - /* set the segment table base address */ - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Set ERST base address for ir_set 0 = 0x%llx", - (unsigned long long)xhci->erst.erst_dma_addr); - val_64 = xhci_read_64(xhci, &xhci->ir_set->erst_base); - val_64 &= ERST_PTR_MASK; - val_64 |= (xhci->erst.erst_dma_addr & (u64) ~ERST_PTR_MASK); - xhci_write_64(xhci, val_64, &xhci->ir_set->erst_base); - - /* Set the event ring dequeue address */ - xhci_set_hc_event_deq(xhci); - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "Wrote ERST address to ir_set 0."); - xhci_print_ir_set(xhci, 0); /* * XXX: Might need to set the Interrupter Moderation Register to diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 197757c20102..8125a8f96311 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -237,11 +237,11 @@ static int xhci_plat_probe(struct platform_device *pdev) goto put_usb3_hcd; } - ret = usb_add_hcd(hcd, irq, IRQF_SHARED); + ret = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_ONESHOT); if (ret) goto disable_usb_phy; - ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); + ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED | IRQF_ONESHOT); if (ret) goto dealloc_usb2_hcd; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index e57340a86eb3..42f74d55e3bd 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -4968,6 +4968,61 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) } EXPORT_SYMBOL_GPL(xhci_gen_setup); +dma_addr_t xhci_get_sec_event_ring_dma_addr(struct usb_hcd *hcd, + unsigned intr_num) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + if (intr_num > xhci->max_interrupters) { + xhci_err(xhci, "intr num %d > max intrs %d\n", intr_num, + xhci->max_interrupters); + return 0; + } + + if (!(xhci->xhc_state & XHCI_STATE_HALTED) && + xhci->sec_event_ring && xhci->sec_event_ring[intr_num] + && xhci->sec_event_ring[intr_num]->first_seg) + return xhci->sec_event_ring[intr_num]->first_seg->dma; + + return 0; +} + +dma_addr_t xhci_get_dcba_dma_addr(struct usb_hcd *hcd, + struct usb_device *udev) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + if (!(xhci->xhc_state & XHCI_STATE_HALTED) && xhci->dcbaa) + return xhci->dcbaa->dev_context_ptrs[udev->slot_id]; + + return 0; +} + +dma_addr_t xhci_get_xfer_ring_dma_addr(struct usb_hcd *hcd, + struct usb_device *udev, struct usb_host_endpoint *ep) +{ + int ret; + unsigned int ep_index; + struct xhci_virt_device *virt_dev; + + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + ret = xhci_check_args(hcd, udev, ep, 1, true, __func__); + if (ret <= 0) { + xhci_err(xhci, "%s: invalid args\n", __func__); + return 0; + } + + virt_dev = xhci->devs[udev->slot_id]; + ep_index = xhci_get_endpoint_index(&ep->desc); + + if (virt_dev->eps[ep_index].ring && + virt_dev->eps[ep_index].ring->first_seg) + return virt_dev->eps[ep_index].ring->first_seg->dma; + + return 0; +} + static const struct hc_driver xhci_hc_driver = { .description = "xhci-hcd", .product_desc = "xHCI Host Controller", @@ -5027,6 +5082,11 @@ static const struct hc_driver xhci_hc_driver = { .enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout, .disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout, .find_raw_port_number = xhci_find_raw_port_number, + .sec_event_ring_setup = xhci_sec_event_ring_setup, + .sec_event_ring_cleanup = xhci_sec_event_ring_cleanup, + .get_sec_event_ring_dma_addr = xhci_get_sec_event_ring_dma_addr, + .get_xfer_ring_dma_addr = xhci_get_xfer_ring_dma_addr, + .get_dcba_dma_addr = xhci_get_dcba_dma_addr, }; void xhci_init_driver(struct hc_driver *drv, diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 0b9451250e33..a6e94e029a10 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1514,6 +1514,9 @@ struct xhci_hcd { /* Our HCD's current interrupter register set */ struct xhci_intr_reg __iomem *ir_set; + /* secondary interrupter */ + struct xhci_intr_reg __iomem **sec_ir_set; + /* Cached register copies of read-only HC data */ __u32 hcs_params1; __u32 hcs_params2; @@ -1554,6 +1557,11 @@ struct xhci_hcd { struct xhci_command *current_cmd; struct xhci_ring *event_ring; struct xhci_erst erst; + + /* secondary event ring and erst */ + struct xhci_ring **sec_event_ring; + struct xhci_erst *sec_erst; + /* Scratchpad */ struct xhci_scratchpad *scratchpad; /* Store LPM test failed devices' information */ @@ -1811,6 +1819,8 @@ struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci, void xhci_urb_free_priv(struct urb_priv *urb_priv); void xhci_free_command(struct xhci_hcd *xhci, struct xhci_command *command); +int xhci_sec_event_ring_setup(struct usb_hcd *hcd, unsigned intr_num); +int xhci_sec_event_ring_cleanup(struct usb_hcd *hcd, unsigned intr_num); /* xHCI host controller glue */ typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *); diff --git a/drivers/usb/pd/qpnp-pdphy.c b/drivers/usb/pd/qpnp-pdphy.c index 4585393a9552..70bb916d863f 100644 --- a/drivers/usb/pd/qpnp-pdphy.c +++ b/drivers/usb/pd/qpnp-pdphy.c @@ -318,7 +318,7 @@ int pd_phy_open(struct pd_phy_params *params) struct usb_pdphy *pdphy = __pdphy; if (!pdphy) { - dev_err(pdphy->dev, "%s: pdphy not found\n", __func__); + pr_err("%s: pdphy not found\n", __func__); return -ENODEV; } @@ -382,7 +382,7 @@ int pd_phy_signal(enum pd_sig_type type, unsigned int timeout_ms) timeout_ms); if (!pdphy) { - dev_err(pdphy->dev, "%s: pdphy not found\n", __func__); + pr_err("%s: pdphy not found\n", __func__); return -ENODEV; } @@ -440,7 +440,7 @@ int pd_phy_write(u16 hdr, const u8 *data, size_t data_len, data, data_len, false); if (!pdphy) { - dev_err(pdphy->dev, "%s: pdphy not found\n", __func__); + pr_err("%s: pdphy not found\n", __func__); return -ENODEV; } @@ -507,7 +507,7 @@ void pd_phy_close(void) struct usb_pdphy *pdphy = __pdphy; if (!pdphy) { - dev_err(pdphy->dev, "%s: pdphy not found\n", __func__); + pr_err("%s: pdphy not found\n", __func__); return; } @@ -766,15 +766,17 @@ static int pdphy_probe(struct platform_device *pdev) if (ret < 0) return ret; + /* usbpd_create() could call back to us, so have __pdphy ready */ + __pdphy = pdphy; + pdphy->usbpd = usbpd_create(&pdev->dev); if (IS_ERR(pdphy->usbpd)) { dev_err(&pdev->dev, "usbpd_create failed: %ld\n", PTR_ERR(pdphy->usbpd)); + __pdphy = NULL; return PTR_ERR(pdphy->usbpd); } - __pdphy = pdphy; - pdphy_create_debugfs_entries(pdphy); return 0; diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index 5857f8ee8317..170f3ce3e881 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -26,7 +26,7 @@ obj-$(CONFIG_USB_QCOM_8X16_PHY) += phy-qcom-8x16-usb.o obj-$(CONFIG_USB_MSM_HSPHY) += phy-msm-hsusb.o obj-$(CONFIG_USB_MSM_SSPHY) += phy-msm-ssusb.o obj-$(CONFIG_USB_MSM_SSPHY_QMP) += phy-msm-ssusb-qmp.o -obj-$(CONFIG_MSM_QUSB_PHY) += phy-msm-qusb.o +obj-$(CONFIG_MSM_QUSB_PHY) += phy-msm-qusb.o phy-msm-qusb-v2.o obj-$(CONFIG_USB_MV_OTG) += phy-mv-usb.o obj-$(CONFIG_USB_MXS_PHY) += phy-mxs-usb.o obj-$(CONFIG_USB_RCAR_PHY) += phy-rcar-usb.o diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c new file mode 100644 index 000000000000..1bc6b6ba4517 --- /dev/null +++ b/drivers/usb/phy/phy-msm-qusb-v2.c @@ -0,0 +1,955 @@ +/* + * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/clk.h> +#include <linux/clk/msm-clk.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/power_supply.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/usb/phy.h> +#include <linux/usb/msm_hsusb.h> + +#define QUSB2PHY_PWR_CTRL1 0x210 +#define PWR_CTRL1_POWR_DOWN BIT(0) + +#define QUSB2PHY_PLL_COMMON_STATUS_ONE 0x1A0 +#define CORE_READY_STATUS BIT(0) + +/* In case Efuse register shows zero, use this value */ +#define TUNE2_DEFAULT_HIGH_NIBBLE 0xB +#define TUNE2_DEFAULT_LOW_NIBBLE 0x3 + +/* Get TUNE2's high nibble value read from efuse */ +#define TUNE2_HIGH_NIBBLE_VAL(val, pos, mask) ((val >> pos) & mask) + +#define QUSB2PHY_INTR_CTRL 0x22C +#define DMSE_INTR_HIGH_SEL BIT(4) +#define DPSE_INTR_HIGH_SEL BIT(3) +#define CHG_DET_INTR_EN BIT(2) +#define DMSE_INTR_EN BIT(1) +#define DPSE_INTR_EN BIT(0) + +#define QUSB2PHY_INTR_STAT 0x230 +#define DMSE_INTERRUPT BIT(1) +#define DPSE_INTERRUPT BIT(0) + +#define QUSB2PHY_PORT_TUNE2 0x240 + +#define HS_PHY_CTRL_REG 0x10 +#define UTMI_OTG_VBUS_VALID BIT(20) +#define SW_SESSVLD_SEL BIT(28) + +#define QUSB2PHY_1P8_VOL_MIN 1800000 /* uV */ +#define QUSB2PHY_1P8_VOL_MAX 1800000 /* uV */ +#define QUSB2PHY_1P8_HPM_LOAD 30000 /* uA */ + +#define QUSB2PHY_3P3_VOL_MIN 3075000 /* uV */ +#define QUSB2PHY_3P3_VOL_MAX 3200000 /* uV */ +#define QUSB2PHY_3P3_HPM_LOAD 30000 /* uA */ + +unsigned int phy_tune2; +module_param(phy_tune2, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(phy_tune2, "QUSB PHY v2 TUNE2"); + +struct qusb_phy { + struct usb_phy phy; + void __iomem *base; + void __iomem *qscratch_base; + void __iomem *tune2_efuse_reg; + + struct clk *ref_clk_src; + struct clk *ref_clk; + struct clk *cfg_ahb_clk; + struct clk *phy_reset; + + struct regulator *vdd; + struct regulator *vdda33; + struct regulator *vdda18; + int vdd_levels[3]; /* none, low, high */ + int init_seq_len; + int *qusb_phy_init_seq; + + u32 tune2_val; + int tune2_efuse_bit_pos; + int tune2_efuse_num_of_bits; + + bool power_enabled; + bool clocks_enabled; + bool cable_connected; + bool suspended; + bool rm_pulldown; + + struct regulator_desc dpdm_rdesc; + struct regulator_dev *dpdm_rdev; + + /* emulation targets specific */ + void __iomem *emu_phy_base; + bool emulation; + int *emu_init_seq; + int emu_init_seq_len; + int *phy_pll_reset_seq; + int phy_pll_reset_seq_len; + int *emu_dcm_reset_seq; + int emu_dcm_reset_seq_len; +}; + +static void qusb_phy_enable_clocks(struct qusb_phy *qphy, bool on) +{ + dev_dbg(qphy->phy.dev, "%s(): clocks_enabled:%d on:%d\n", + __func__, qphy->clocks_enabled, on); + + if (!qphy->clocks_enabled && on) { + clk_prepare_enable(qphy->ref_clk_src); + clk_prepare_enable(qphy->ref_clk); + clk_prepare_enable(qphy->cfg_ahb_clk); + qphy->clocks_enabled = true; + } + + if (qphy->clocks_enabled && !on) { + clk_disable_unprepare(qphy->ref_clk); + clk_disable_unprepare(qphy->ref_clk_src); + clk_disable_unprepare(qphy->cfg_ahb_clk); + qphy->clocks_enabled = false; + } + + dev_dbg(qphy->phy.dev, "%s(): clocks_enabled:%d\n", __func__, + qphy->clocks_enabled); +} + +static int qusb_phy_config_vdd(struct qusb_phy *qphy, int high) +{ + int min, ret; + + min = high ? 1 : 0; /* low or none? */ + ret = regulator_set_voltage(qphy->vdd, qphy->vdd_levels[min], + qphy->vdd_levels[2]); + if (ret) { + dev_err(qphy->phy.dev, "unable to set voltage for qusb vdd\n"); + return ret; + } + + dev_dbg(qphy->phy.dev, "min_vol:%d max_vol:%d\n", + qphy->vdd_levels[min], qphy->vdd_levels[2]); + return ret; +} + +static int qusb_phy_enable_power(struct qusb_phy *qphy, bool on, + bool toggle_vdd) +{ + int ret = 0; + + dev_dbg(qphy->phy.dev, "%s turn %s regulators. power_enabled:%d\n", + __func__, on ? "on" : "off", qphy->power_enabled); + + if (toggle_vdd && qphy->power_enabled == on) { + dev_dbg(qphy->phy.dev, "PHYs' regulators are already ON.\n"); + return 0; + } + + if (!on) + goto disable_vdda33; + + if (toggle_vdd) { + ret = qusb_phy_config_vdd(qphy, true); + if (ret) { + dev_err(qphy->phy.dev, "Unable to config VDD:%d\n", + ret); + goto err_vdd; + } + + ret = regulator_enable(qphy->vdd); + if (ret) { + dev_err(qphy->phy.dev, "Unable to enable VDD\n"); + goto unconfig_vdd; + } + } + + ret = regulator_set_load(qphy->vdda18, QUSB2PHY_1P8_HPM_LOAD); + if (ret < 0) { + dev_err(qphy->phy.dev, "Unable to set HPM of vdda18:%d\n", ret); + goto disable_vdd; + } + + ret = regulator_set_voltage(qphy->vdda18, QUSB2PHY_1P8_VOL_MIN, + QUSB2PHY_1P8_VOL_MAX); + if (ret) { + dev_err(qphy->phy.dev, + "Unable to set voltage for vdda18:%d\n", ret); + goto put_vdda18_lpm; + } + + ret = regulator_enable(qphy->vdda18); + if (ret) { + dev_err(qphy->phy.dev, "Unable to enable vdda18:%d\n", ret); + goto unset_vdda18; + } + + ret = regulator_set_load(qphy->vdda33, QUSB2PHY_3P3_HPM_LOAD); + if (ret < 0) { + dev_err(qphy->phy.dev, "Unable to set HPM of vdda33:%d\n", ret); + goto disable_vdda18; + } + + ret = regulator_set_voltage(qphy->vdda33, QUSB2PHY_3P3_VOL_MIN, + QUSB2PHY_3P3_VOL_MAX); + if (ret) { + dev_err(qphy->phy.dev, + "Unable to set voltage for vdda33:%d\n", ret); + goto put_vdda33_lpm; + } + + ret = regulator_enable(qphy->vdda33); + if (ret) { + dev_err(qphy->phy.dev, "Unable to enable vdda33:%d\n", ret); + goto unset_vdd33; + } + + if (toggle_vdd) + qphy->power_enabled = true; + + pr_debug("%s(): QUSB PHY's regulators are turned ON.\n", __func__); + return ret; + +disable_vdda33: + ret = regulator_disable(qphy->vdda33); + if (ret) + dev_err(qphy->phy.dev, "Unable to disable vdda33:%d\n", ret); + +unset_vdd33: + ret = regulator_set_voltage(qphy->vdda33, 0, QUSB2PHY_3P3_VOL_MAX); + if (ret) + dev_err(qphy->phy.dev, + "Unable to set (0) voltage for vdda33:%d\n", ret); + +put_vdda33_lpm: + ret = regulator_set_load(qphy->vdda33, 0); + if (ret < 0) + dev_err(qphy->phy.dev, "Unable to set (0) HPM of vdda33\n"); + +disable_vdda18: + ret = regulator_disable(qphy->vdda18); + if (ret) + dev_err(qphy->phy.dev, "Unable to disable vdda18:%d\n", ret); + +unset_vdda18: + ret = regulator_set_voltage(qphy->vdda18, 0, QUSB2PHY_1P8_VOL_MAX); + if (ret) + dev_err(qphy->phy.dev, + "Unable to set (0) voltage for vdda18:%d\n", ret); + +put_vdda18_lpm: + ret = regulator_set_load(qphy->vdda18, 0); + if (ret < 0) + dev_err(qphy->phy.dev, "Unable to set LPM of vdda18\n"); + +disable_vdd: + if (toggle_vdd) { + ret = regulator_disable(qphy->vdd); + if (ret) + dev_err(qphy->phy.dev, "Unable to disable vdd:%d\n", + ret); + +unconfig_vdd: + ret = qusb_phy_config_vdd(qphy, false); + if (ret) + dev_err(qphy->phy.dev, "Unable unconfig VDD:%d\n", + ret); + } +err_vdd: + if (toggle_vdd) + qphy->power_enabled = false; + dev_dbg(qphy->phy.dev, "QUSB PHY's regulators are turned OFF.\n"); + return ret; +} + +static int qusb_phy_update_dpdm(struct usb_phy *phy, int value) +{ + struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy); + int ret = 0; + + dev_dbg(phy->dev, "%s value:%d rm_pulldown:%d\n", + __func__, value, qphy->rm_pulldown); + + switch (value) { + case POWER_SUPPLY_DP_DM_DPF_DMF: + dev_dbg(phy->dev, "POWER_SUPPLY_DP_DM_DPF_DMF\n"); + if (!qphy->rm_pulldown) { + ret = qusb_phy_enable_power(qphy, true, false); + if (ret >= 0) { + qphy->rm_pulldown = true; + dev_dbg(phy->dev, "DP_DM_F: rm_pulldown:%d\n", + qphy->rm_pulldown); + } + } + + break; + + case POWER_SUPPLY_DP_DM_DPR_DMR: + dev_dbg(phy->dev, "POWER_SUPPLY_DP_DM_DPR_DMR\n"); + if (qphy->rm_pulldown) { + ret = qusb_phy_enable_power(qphy, false, false); + if (ret >= 0) { + qphy->rm_pulldown = false; + dev_dbg(phy->dev, "DP_DM_R: rm_pulldown:%d\n", + qphy->rm_pulldown); + } + } + break; + + default: + ret = -EINVAL; + dev_err(phy->dev, "Invalid power supply property(%d)\n", value); + break; + } + + return ret; +} + +static void qusb_phy_get_tune2_param(struct qusb_phy *qphy) +{ + u8 num_of_bits; + u32 bit_mask = 1; + + pr_debug("%s(): num_of_bits:%d bit_pos:%d\n", __func__, + qphy->tune2_efuse_num_of_bits, + qphy->tune2_efuse_bit_pos); + + /* get bit mask based on number of bits to use with efuse reg */ + if (qphy->tune2_efuse_num_of_bits) { + num_of_bits = qphy->tune2_efuse_num_of_bits; + bit_mask = (bit_mask << num_of_bits) - 1; + } + + /* + * Read EFUSE register having TUNE2 parameter's high nibble. + * If efuse register shows value as 0x0, then use default value + * as 0xB as high nibble. Otherwise use efuse register based + * value for this purpose. + */ + qphy->tune2_val = readl_relaxed(qphy->tune2_efuse_reg); + pr_debug("%s(): bit_mask:%d efuse based tune2 value:%d\n", + __func__, bit_mask, qphy->tune2_val); + + qphy->tune2_val = TUNE2_HIGH_NIBBLE_VAL(qphy->tune2_val, + qphy->tune2_efuse_bit_pos, bit_mask); + + if (!qphy->tune2_val) + qphy->tune2_val = TUNE2_DEFAULT_HIGH_NIBBLE; + + /* Get TUNE2 byte value using high and low nibble value */ + qphy->tune2_val = ((qphy->tune2_val << 0x4) | + TUNE2_DEFAULT_LOW_NIBBLE); +} + +static void qusb_phy_write_seq(void __iomem *base, u32 *seq, int cnt, + unsigned long delay) +{ + int i; + + pr_debug("Seq count:%d\n", cnt); + for (i = 0; i < cnt; i = i+2) { + pr_debug("write 0x%02x to 0x%02x\n", seq[i], seq[i+1]); + writel_relaxed(seq[i], base + seq[i+1]); + if (delay) + usleep_range(delay, (delay + 2000)); + } +} + +static int qusb_phy_init(struct usb_phy *phy) +{ + struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy); + int ret; + u8 reg; + + dev_dbg(phy->dev, "%s\n", __func__); + + ret = qusb_phy_enable_power(qphy, true, true); + if (ret) + return ret; + + qusb_phy_enable_clocks(qphy, true); + + /* Perform phy reset */ + clk_reset(qphy->phy_reset, CLK_RESET_ASSERT); + usleep_range(100, 150); + clk_reset(qphy->phy_reset, CLK_RESET_DEASSERT); + + if (qphy->emulation) { + if (qphy->emu_init_seq) + qusb_phy_write_seq(qphy->emu_phy_base, + qphy->emu_init_seq, qphy->emu_init_seq_len, 0); + + if (qphy->qusb_phy_init_seq) + qusb_phy_write_seq(qphy->base, qphy->qusb_phy_init_seq, + qphy->init_seq_len, 0); + + /* Wait for 5ms as per QUSB2 RUMI sequence */ + usleep_range(5000, 7000); + + if (qphy->phy_pll_reset_seq) + qusb_phy_write_seq(qphy->base, qphy->phy_pll_reset_seq, + qphy->phy_pll_reset_seq_len, 10000); + + if (qphy->emu_dcm_reset_seq) + qusb_phy_write_seq(qphy->emu_phy_base, + qphy->emu_dcm_reset_seq, + qphy->emu_dcm_reset_seq_len, 10000); + + return 0; + } + + /* Disable the PHY */ + writel_relaxed(readl_relaxed(qphy->base + QUSB2PHY_PWR_CTRL1) | + PWR_CTRL1_POWR_DOWN, + qphy->base + QUSB2PHY_PWR_CTRL1); + + if (qphy->qusb_phy_init_seq) + qusb_phy_write_seq(qphy->base, qphy->qusb_phy_init_seq, + qphy->init_seq_len, 0); + /* + * Check for EFUSE value only if tune2_efuse_reg is available + * and try to read EFUSE value only once i.e. not every USB + * cable connect case. + */ + if (qphy->tune2_efuse_reg) { + if (!qphy->tune2_val) + qusb_phy_get_tune2_param(qphy); + + pr_debug("%s(): Programming TUNE2 parameter as:%x\n", __func__, + qphy->tune2_val); + writel_relaxed(qphy->tune2_val, + qphy->base + QUSB2PHY_PORT_TUNE2); + } + + /* If phy_tune2 modparam set, override tune2 value */ + if (phy_tune2) { + pr_debug("%s(): (modparam) TUNE2 val:0x%02x\n", + __func__, phy_tune2); + writel_relaxed(phy_tune2, + qphy->base + QUSB2PHY_PORT_TUNE2); + } + + /* ensure above writes are completed before re-enabling PHY */ + wmb(); + + /* Enable the PHY */ + writel_relaxed(readl_relaxed(qphy->base + QUSB2PHY_PWR_CTRL1) & + ~PWR_CTRL1_POWR_DOWN, + qphy->base + QUSB2PHY_PWR_CTRL1); + + /* Ensure above write is completed before turning ON ref clk */ + wmb(); + + /* Require to get phy pll lock successfully */ + usleep_range(150, 160); + + reg = readb_relaxed(qphy->base + QUSB2PHY_PLL_COMMON_STATUS_ONE); + dev_dbg(phy->dev, "QUSB2PHY_PLL_COMMON_STATUS_ONE:%x\n", reg); + if (!(reg & CORE_READY_STATUS)) { + dev_err(phy->dev, "QUSB PHY PLL LOCK fails:%x\n", reg); + WARN_ON(1); + } + return 0; +} + +static void qusb_phy_shutdown(struct usb_phy *phy) +{ + struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy); + + dev_dbg(phy->dev, "%s\n", __func__); + + qusb_phy_enable_clocks(qphy, true); + + /* Disable the PHY */ + writel_relaxed(readl_relaxed(qphy->base + QUSB2PHY_PWR_CTRL1) | + PWR_CTRL1_POWR_DOWN, + qphy->base + QUSB2PHY_PWR_CTRL1); + + /* Makes sure that above write goes through */ + wmb(); + + qusb_phy_enable_clocks(qphy, false); +} +/** + * Performs QUSB2 PHY suspend/resume functionality. + * + * @uphy - usb phy pointer. + * @suspend - to enable suspend or not. 1 - suspend, 0 - resume + * + */ +static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) +{ + struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy); + u32 linestate = 0, intr_mask = 0; + + if (qphy->suspended && suspend) { + dev_dbg(phy->dev, "%s: USB PHY is already suspended\n", + __func__); + return 0; + } + + if (suspend) { + /* Bus suspend case */ + if (qphy->cable_connected || + (qphy->phy.flags & PHY_HOST_MODE)) { + /* Disable all interrupts */ + writel_relaxed(0x00, + qphy->base + QUSB2PHY_INTR_CTRL); + + linestate = readl_relaxed(qphy->base + + QUSB2PHY_INTR_STAT); + /* + * D+/D- interrupts are level-triggered, but we are + * only interested if the line state changes, so enable + * the high/low trigger based on current state. In + * other words, enable the triggers _opposite_ of what + * the current D+/D- levels are. + * e.g. if currently D+ high, D- low (HS 'J'/Suspend), + * configure the mask to trigger on D+ low OR D- high + */ + intr_mask = DMSE_INTERRUPT | DPSE_INTERRUPT; + if (!(linestate & DPSE_INTR_EN)) /* D+ low */ + intr_mask |= DPSE_INTR_HIGH_SEL; + if (!(linestate & DMSE_INTR_EN)) /* D- low */ + intr_mask |= DMSE_INTR_HIGH_SEL; + + writel_relaxed(intr_mask, + qphy->base + QUSB2PHY_INTR_CTRL); + + /* Makes sure that above write goes through */ + wmb(); + qusb_phy_enable_clocks(qphy, false); + } else { /* Cable disconnect case */ + /* Disable all interrupts */ + writel_relaxed(0x00, + qphy->base + QUSB2PHY_INTR_CTRL); + + /* Put PHY into non-driving mode */ + writel_relaxed(0x23, + qphy->base + QUSB2PHY_PWR_CTRL1); + + /* Makes sure that above write goes through */ + wmb(); + + qusb_phy_enable_clocks(qphy, false); + qusb_phy_enable_power(qphy, false, true); + } + qphy->suspended = true; + } else { + /* Bus resume case */ + if (qphy->cable_connected || + (qphy->phy.flags & PHY_HOST_MODE)) { + qusb_phy_enable_clocks(qphy, true); + /* Clear all interrupts on resume */ + writel_relaxed(0x00, + qphy->base + QUSB2PHY_INTR_CTRL); + + /* Makes sure that above write goes through */ + wmb(); + } else { /* Cable connect case */ + qusb_phy_enable_power(qphy, true, true); + qusb_phy_enable_clocks(qphy, true); + } + qphy->suspended = false; + } + + return 0; +} + +static void qusb_write_readback(void *base, u32 offset, + const u32 mask, u32 val) +{ + u32 write_val, tmp = readl_relaxed(base + offset); + + tmp &= ~mask; /* retain other bits */ + write_val = tmp | val; + + writel_relaxed(write_val, base + offset); + + /* Read back to see if val was written */ + tmp = readl_relaxed(base + offset); + tmp &= mask; /* clear other bits */ + + if (tmp != val) + pr_err("%s: write: %x to QSCRATCH: %x FAILED\n", + __func__, val, offset); +} + +static int qusb_phy_notify_connect(struct usb_phy *phy, + enum usb_device_speed speed) +{ + struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy); + + qphy->cable_connected = true; + + dev_dbg(phy->dev, " cable_connected=%d\n", qphy->cable_connected); + + /* Set OTG VBUS Valid from HSPHY to controller */ + qusb_write_readback(qphy->qscratch_base, HS_PHY_CTRL_REG, + UTMI_OTG_VBUS_VALID, + UTMI_OTG_VBUS_VALID); + + /* Indicate value is driven by UTMI_OTG_VBUS_VALID bit */ + qusb_write_readback(qphy->qscratch_base, HS_PHY_CTRL_REG, + SW_SESSVLD_SEL, SW_SESSVLD_SEL); + + dev_dbg(phy->dev, "QUSB2 phy connect notification\n"); + return 0; +} + +static int qusb_phy_notify_disconnect(struct usb_phy *phy, + enum usb_device_speed speed) +{ + struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy); + + qphy->cable_connected = false; + + dev_dbg(phy->dev, " cable_connected=%d\n", qphy->cable_connected); + + /* Set OTG VBUS Valid from HSPHY to controller */ + qusb_write_readback(qphy->qscratch_base, HS_PHY_CTRL_REG, + UTMI_OTG_VBUS_VALID, 0); + + /* Indicate value is driven by UTMI_OTG_VBUS_VALID bit */ + qusb_write_readback(qphy->qscratch_base, HS_PHY_CTRL_REG, + SW_SESSVLD_SEL, 0); + + dev_dbg(phy->dev, "QUSB2 phy disconnect notification\n"); + return 0; +} + +static int qusb_phy_dpdm_regulator_enable(struct regulator_dev *rdev) +{ + struct qusb_phy *qphy = rdev_get_drvdata(rdev); + + dev_dbg(qphy->phy.dev, "%s\n", __func__); + return qusb_phy_update_dpdm(&qphy->phy, POWER_SUPPLY_DP_DM_DPF_DMF); +} + +static int qusb_phy_dpdm_regulator_disable(struct regulator_dev *rdev) +{ + struct qusb_phy *qphy = rdev_get_drvdata(rdev); + + dev_dbg(qphy->phy.dev, "%s\n", __func__); + return qusb_phy_update_dpdm(&qphy->phy, POWER_SUPPLY_DP_DM_DPR_DMR); +} + +static int qusb_phy_dpdm_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct qusb_phy *qphy = rdev_get_drvdata(rdev); + + dev_dbg(qphy->phy.dev, "%s qphy->rm_pulldown = %d\n", __func__, + qphy->rm_pulldown); + return qphy->rm_pulldown; +} + +static struct regulator_ops qusb_phy_dpdm_regulator_ops = { + .enable = qusb_phy_dpdm_regulator_enable, + .disable = qusb_phy_dpdm_regulator_disable, + .is_enabled = qusb_phy_dpdm_regulator_is_enabled, +}; + +static int qusb_phy_regulator_init(struct qusb_phy *qphy) +{ + struct device *dev = qphy->phy.dev; + struct regulator_config cfg = {}; + struct regulator_init_data *init_data; + + init_data = devm_kzalloc(dev, sizeof(*init_data), GFP_KERNEL); + if (!init_data) + return -ENOMEM; + + init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_STATUS; + qphy->dpdm_rdesc.owner = THIS_MODULE; + qphy->dpdm_rdesc.type = REGULATOR_VOLTAGE; + qphy->dpdm_rdesc.ops = &qusb_phy_dpdm_regulator_ops; + qphy->dpdm_rdesc.name = kbasename(dev->of_node->full_name); + + cfg.dev = dev; + cfg.init_data = init_data; + cfg.driver_data = qphy; + cfg.of_node = dev->of_node; + + qphy->dpdm_rdev = devm_regulator_register(dev, &qphy->dpdm_rdesc, &cfg); + if (IS_ERR(qphy->dpdm_rdev)) + return PTR_ERR(qphy->dpdm_rdev); + + return 0; +} + +static int qusb_phy_probe(struct platform_device *pdev) +{ + struct qusb_phy *qphy; + struct device *dev = &pdev->dev; + struct resource *res; + int ret = 0, size = 0; + + qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL); + if (!qphy) + return -ENOMEM; + + qphy->phy.dev = dev; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "qusb_phy_base"); + qphy->base = devm_ioremap_resource(dev, res); + if (IS_ERR(qphy->base)) + return PTR_ERR(qphy->base); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "qscratch_base"); + if (res) { + qphy->qscratch_base = devm_ioremap_resource(dev, res); + if (IS_ERR(qphy->qscratch_base)) { + dev_dbg(dev, "couldn't ioremap qscratch_base\n"); + qphy->qscratch_base = NULL; + } + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "emu_phy_base"); + if (res) { + qphy->emu_phy_base = devm_ioremap_resource(dev, res); + if (IS_ERR(qphy->emu_phy_base)) { + dev_dbg(dev, "couldn't ioremap emu_phy_base\n"); + qphy->emu_phy_base = NULL; + } + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "tune2_efuse_addr"); + if (res) { + qphy->tune2_efuse_reg = devm_ioremap_nocache(dev, res->start, + resource_size(res)); + if (!IS_ERR_OR_NULL(qphy->tune2_efuse_reg)) { + ret = of_property_read_u32(dev->of_node, + "qcom,tune2-efuse-bit-pos", + &qphy->tune2_efuse_bit_pos); + if (!ret) { + ret = of_property_read_u32(dev->of_node, + "qcom,tune2-efuse-num-bits", + &qphy->tune2_efuse_num_of_bits); + } + + if (ret) { + dev_err(dev, + "DT Value for tune2 efuse is invalid.\n"); + return -EINVAL; + } + } + } + + qphy->ref_clk_src = devm_clk_get(dev, "ref_clk_src"); + if (IS_ERR(qphy->ref_clk_src)) + dev_dbg(dev, "clk get failed for ref_clk_src\n"); + + qphy->ref_clk = devm_clk_get(dev, "ref_clk"); + if (IS_ERR(qphy->ref_clk)) + dev_dbg(dev, "clk get failed for ref_clk\n"); + else + clk_set_rate(qphy->ref_clk, 19200000); + + qphy->cfg_ahb_clk = devm_clk_get(dev, "cfg_ahb_clk"); + if (IS_ERR(qphy->cfg_ahb_clk)) + return PTR_ERR(qphy->cfg_ahb_clk); + + qphy->phy_reset = devm_clk_get(dev, "phy_reset"); + if (IS_ERR(qphy->phy_reset)) + return PTR_ERR(qphy->phy_reset); + + qphy->emulation = of_property_read_bool(dev->of_node, + "qcom,emulation"); + + of_get_property(dev->of_node, "qcom,emu-init-seq", &size); + if (size) { + qphy->emu_init_seq = devm_kzalloc(dev, + size, GFP_KERNEL); + if (qphy->emu_init_seq) { + qphy->emu_init_seq_len = + (size / sizeof(*qphy->emu_init_seq)); + if (qphy->emu_init_seq_len % 2) { + dev_err(dev, "invalid emu_init_seq_len\n"); + return -EINVAL; + } + + of_property_read_u32_array(dev->of_node, + "qcom,qemu-init-seq", + qphy->emu_init_seq, + qphy->emu_init_seq_len); + } else { + dev_dbg(dev, + "error allocating memory for emu_init_seq\n"); + } + } + + of_get_property(dev->of_node, "qcom,phy-pll-reset-seq", &size); + if (size) { + qphy->phy_pll_reset_seq = devm_kzalloc(dev, + size, GFP_KERNEL); + if (qphy->phy_pll_reset_seq) { + qphy->phy_pll_reset_seq_len = + (size / sizeof(*qphy->phy_pll_reset_seq)); + if (qphy->phy_pll_reset_seq_len % 2) { + dev_err(dev, "invalid phy_pll_reset_seq_len\n"); + return -EINVAL; + } + + of_property_read_u32_array(dev->of_node, + "qcom,phy-pll-reset-seq", + qphy->phy_pll_reset_seq, + qphy->phy_pll_reset_seq_len); + } else { + dev_dbg(dev, + "error allocating memory for phy_pll_reset_seq\n"); + } + } + + of_get_property(dev->of_node, "qcom,emu-dcm-reset-seq", &size); + if (size) { + qphy->emu_dcm_reset_seq = devm_kzalloc(dev, + size, GFP_KERNEL); + if (qphy->emu_dcm_reset_seq) { + qphy->emu_dcm_reset_seq_len = + (size / sizeof(*qphy->emu_dcm_reset_seq)); + if (qphy->emu_dcm_reset_seq_len % 2) { + dev_err(dev, "invalid emu_dcm_reset_seq_len\n"); + return -EINVAL; + } + + of_property_read_u32_array(dev->of_node, + "qcom,emu-dcm-reset-seq", + qphy->emu_dcm_reset_seq, + qphy->emu_dcm_reset_seq_len); + } else { + dev_dbg(dev, + "error allocating memory for emu_dcm_reset_seq\n"); + } + } + + of_get_property(dev->of_node, "qcom,qusb-phy-init-seq", &size); + if (size) { + qphy->qusb_phy_init_seq = devm_kzalloc(dev, + size, GFP_KERNEL); + if (qphy->qusb_phy_init_seq) { + qphy->init_seq_len = + (size / sizeof(*qphy->qusb_phy_init_seq)); + if (qphy->init_seq_len % 2) { + dev_err(dev, "invalid init_seq_len\n"); + return -EINVAL; + } + + of_property_read_u32_array(dev->of_node, + "qcom,qusb-phy-init-seq", + qphy->qusb_phy_init_seq, + qphy->init_seq_len); + } else { + dev_err(dev, + "error allocating memory for phy_init_seq\n"); + } + } + + ret = of_property_read_u32_array(dev->of_node, "qcom,vdd-voltage-level", + (u32 *) qphy->vdd_levels, + ARRAY_SIZE(qphy->vdd_levels)); + if (ret) { + dev_err(dev, "error reading qcom,vdd-voltage-level property\n"); + return ret; + } + + qphy->vdd = devm_regulator_get(dev, "vdd"); + if (IS_ERR(qphy->vdd)) { + dev_err(dev, "unable to get vdd supply\n"); + return PTR_ERR(qphy->vdd); + } + + qphy->vdda33 = devm_regulator_get(dev, "vdda33"); + if (IS_ERR(qphy->vdda33)) { + dev_err(dev, "unable to get vdda33 supply\n"); + return PTR_ERR(qphy->vdda33); + } + + qphy->vdda18 = devm_regulator_get(dev, "vdda18"); + if (IS_ERR(qphy->vdda18)) { + dev_err(dev, "unable to get vdda18 supply\n"); + return PTR_ERR(qphy->vdda18); + } + + platform_set_drvdata(pdev, qphy); + + qphy->phy.label = "msm-qusb-phy-v2"; + qphy->phy.init = qusb_phy_init; + qphy->phy.set_suspend = qusb_phy_set_suspend; + qphy->phy.shutdown = qusb_phy_shutdown; + qphy->phy.type = USB_PHY_TYPE_USB2; + + if (qphy->qscratch_base) { + qphy->phy.notify_connect = qusb_phy_notify_connect; + qphy->phy.notify_disconnect = qusb_phy_notify_disconnect; + } + + ret = usb_add_phy_dev(&qphy->phy); + if (ret) + return ret; + + ret = qusb_phy_regulator_init(qphy); + if (ret) + usb_remove_phy(&qphy->phy); + + return ret; +} + +static int qusb_phy_remove(struct platform_device *pdev) +{ + struct qusb_phy *qphy = platform_get_drvdata(pdev); + + usb_remove_phy(&qphy->phy); + + if (qphy->clocks_enabled) { + clk_disable_unprepare(qphy->cfg_ahb_clk); + clk_disable_unprepare(qphy->ref_clk); + clk_disable_unprepare(qphy->ref_clk_src); + qphy->clocks_enabled = false; + } + + qusb_phy_enable_power(qphy, false, true); + + return 0; +} + +static const struct of_device_id qusb_phy_id_table[] = { + { .compatible = "qcom,qusb2phy-v2", }, + { }, +}; +MODULE_DEVICE_TABLE(of, qusb_phy_id_table); + +static struct platform_driver qusb_phy_driver = { + .probe = qusb_phy_probe, + .remove = qusb_phy_remove, + .driver = { + .name = "msm-qusb-phy-v2", + .of_match_table = of_match_ptr(qusb_phy_id_table), + }, +}; + +module_platform_driver(qusb_phy_driver); + +MODULE_DESCRIPTION("MSM QUSB2 PHY v2 driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 1dd9919081f8..7a76fe4c2f9e 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -162,6 +162,9 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */ { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ { USB_DEVICE(0x18EF, 0xE025) }, /* ELV Marble Sound Board 1 */ + { USB_DEVICE(0x1901, 0x0190) }, /* GE B850 CP2105 Recorder interface */ + { USB_DEVICE(0x1901, 0x0193) }, /* GE B650 CP2104 PMC interface */ + { USB_DEVICE(0x19CF, 0x3000) }, /* Parrot NMEA GPS Flight Recorder */ { USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */ { USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */ { USB_DEVICE(0x1BA4, 0x0002) }, /* Silicon Labs 358x factory default */ diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index db86e512e0fc..348e19834b83 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -270,6 +270,7 @@ static void option_instat_callback(struct urb *urb); #define TELIT_PRODUCT_UE910_V2 0x1012 #define TELIT_PRODUCT_LE922_USBCFG0 0x1042 #define TELIT_PRODUCT_LE922_USBCFG3 0x1043 +#define TELIT_PRODUCT_LE922_USBCFG5 0x1045 #define TELIT_PRODUCT_LE920 0x1200 #define TELIT_PRODUCT_LE910 0x1201 @@ -315,6 +316,7 @@ static void option_instat_callback(struct urb *urb); #define TOSHIBA_PRODUCT_G450 0x0d45 #define ALINK_VENDOR_ID 0x1e0e +#define SIMCOM_PRODUCT_SIM7100E 0x9001 /* Yes, ALINK_VENDOR_ID */ #define ALINK_PRODUCT_PH300 0x9100 #define ALINK_PRODUCT_3GU 0x9200 @@ -607,6 +609,10 @@ static const struct option_blacklist_info zte_1255_blacklist = { .reserved = BIT(3) | BIT(4), }; +static const struct option_blacklist_info simcom_sim7100e_blacklist = { + .reserved = BIT(5) | BIT(6), +}; + static const struct option_blacklist_info telit_le910_blacklist = { .sendsetup = BIT(0), .reserved = BIT(1) | BIT(2), @@ -1122,9 +1128,13 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC650) }, { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) }, { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */ + { USB_DEVICE_AND_INTERFACE_INFO(QUALCOMM_VENDOR_ID, 0x6001, 0xff, 0xff, 0xff), /* 4G LTE usb-modem U901 */ + .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */ + { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9003), /* Quectel UC20 */ + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { 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), @@ -1176,6 +1186,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG3), .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG5, 0xff), + .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910), .driver_info = (kernel_ulong_t)&telit_le910_blacklist }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920), @@ -1645,6 +1657,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(ALINK_VENDOR_ID, 0x9000) }, { USB_DEVICE(ALINK_VENDOR_ID, ALINK_PRODUCT_PH300) }, { USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) }, + { USB_DEVICE(ALINK_VENDOR_ID, SIMCOM_PRODUCT_SIM7100E), + .driver_info = (kernel_ulong_t)&simcom_sim7100e_blacklist }, { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S_X200), .driver_info = (kernel_ulong_t)&alcatel_x200_blacklist }, diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 9919d2a9faf2..1bc6089b9008 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -157,14 +157,17 @@ static const struct usb_device_id id_table[] = { {DEVICE_SWI(0x1199, 0x9056)}, /* Sierra Wireless Modem */ {DEVICE_SWI(0x1199, 0x9060)}, /* Sierra Wireless Modem */ {DEVICE_SWI(0x1199, 0x9061)}, /* Sierra Wireless Modem */ - {DEVICE_SWI(0x1199, 0x9070)}, /* Sierra Wireless MC74xx/EM74xx */ - {DEVICE_SWI(0x1199, 0x9071)}, /* Sierra Wireless MC74xx/EM74xx */ + {DEVICE_SWI(0x1199, 0x9070)}, /* Sierra Wireless MC74xx */ + {DEVICE_SWI(0x1199, 0x9071)}, /* Sierra Wireless MC74xx */ + {DEVICE_SWI(0x1199, 0x9078)}, /* Sierra Wireless EM74xx */ + {DEVICE_SWI(0x1199, 0x9079)}, /* Sierra Wireless EM74xx */ {DEVICE_SWI(0x413c, 0x81a2)}, /* Dell Wireless 5806 Gobi(TM) 4G LTE Mobile Broadband Card */ {DEVICE_SWI(0x413c, 0x81a3)}, /* Dell Wireless 5570 HSPA+ (42Mbps) Mobile Broadband Card */ {DEVICE_SWI(0x413c, 0x81a4)}, /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */ {DEVICE_SWI(0x413c, 0x81a8)}, /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */ {DEVICE_SWI(0x413c, 0x81a9)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */ {DEVICE_SWI(0x413c, 0x81b1)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */ + {DEVICE_SWI(0x413c, 0x81b3)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */ /* Huawei devices */ {DEVICE_HWI(0x03f0, 0x581d)}, /* HP lt4112 LTE/HSPA+ Gobi 4G Modem (Huawei me906e) */ diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index 56bf6dbb93db..9982cb176ce8 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -446,7 +446,8 @@ static long vfio_pci_ioctl(void *device_data, info.num_regions = VFIO_PCI_NUM_REGIONS; info.num_irqs = VFIO_PCI_NUM_IRQS; - return copy_to_user((void __user *)arg, &info, minsz); + return copy_to_user((void __user *)arg, &info, minsz) ? + -EFAULT : 0; } else if (cmd == VFIO_DEVICE_GET_REGION_INFO) { struct pci_dev *pdev = vdev->pdev; @@ -520,7 +521,8 @@ static long vfio_pci_ioctl(void *device_data, return -EINVAL; } - return copy_to_user((void __user *)arg, &info, minsz); + return copy_to_user((void __user *)arg, &info, minsz) ? + -EFAULT : 0; } else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) { struct vfio_irq_info info; @@ -555,7 +557,8 @@ static long vfio_pci_ioctl(void *device_data, else info.flags |= VFIO_IRQ_INFO_NORESIZE; - return copy_to_user((void __user *)arg, &info, minsz); + return copy_to_user((void __user *)arg, &info, minsz) ? + -EFAULT : 0; } else if (cmd == VFIO_DEVICE_SET_IRQS) { struct vfio_irq_set hdr; diff --git a/drivers/vfio/platform/vfio_platform_common.c b/drivers/vfio/platform/vfio_platform_common.c index 418cdd9ba3f4..e65b142d3422 100644 --- a/drivers/vfio/platform/vfio_platform_common.c +++ b/drivers/vfio/platform/vfio_platform_common.c @@ -219,7 +219,8 @@ static long vfio_platform_ioctl(void *device_data, info.num_regions = vdev->num_regions; info.num_irqs = vdev->num_irqs; - return copy_to_user((void __user *)arg, &info, minsz); + return copy_to_user((void __user *)arg, &info, minsz) ? + -EFAULT : 0; } else if (cmd == VFIO_DEVICE_GET_REGION_INFO) { struct vfio_region_info info; @@ -240,7 +241,8 @@ static long vfio_platform_ioctl(void *device_data, info.size = vdev->regions[info.index].size; info.flags = vdev->regions[info.index].flags; - return copy_to_user((void __user *)arg, &info, minsz); + return copy_to_user((void __user *)arg, &info, minsz) ? + -EFAULT : 0; } else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) { struct vfio_irq_info info; @@ -259,7 +261,8 @@ static long vfio_platform_ioctl(void *device_data, info.flags = vdev->irqs[info.index].flags; info.count = vdev->irqs[info.index].count; - return copy_to_user((void __user *)arg, &info, minsz); + return copy_to_user((void __user *)arg, &info, minsz) ? + -EFAULT : 0; } else if (cmd == VFIO_DEVICE_SET_IRQS) { struct vfio_irq_set hdr; diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index 59d47cb638d5..ecb826eefe02 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -999,7 +999,8 @@ static long vfio_iommu_type1_ioctl(void *iommu_data, info.iova_pgsizes = vfio_pgsize_bitmap(iommu); - return copy_to_user((void __user *)arg, &info, minsz); + return copy_to_user((void __user *)arg, &info, minsz) ? + -EFAULT : 0; } else if (cmd == VFIO_IOMMU_MAP_DMA) { struct vfio_iommu_type1_dma_map map; @@ -1032,7 +1033,8 @@ static long vfio_iommu_type1_ioctl(void *iommu_data, if (ret) return ret; - return copy_to_user((void __user *)arg, &unmap, minsz); + return copy_to_user((void __user *)arg, &unmap, minsz) ? + -EFAULT : 0; } return -ENOTTY; diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 92f394927f24..6e92917ba77a 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -709,6 +709,7 @@ static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info, } if (!err) { + ops->cur_blink_jiffies = HZ / 5; info->fbcon_par = ops; if (vc) @@ -956,6 +957,7 @@ static const char *fbcon_startup(void) ops->currcon = -1; ops->graphics = 1; ops->cur_rotate = -1; + ops->cur_blink_jiffies = HZ / 5; info->fbcon_par = ops; p->con_rotate = initial_rotation; set_blitting_type(vc, info); diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index 8f1ab774044d..06e5502910b2 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -1338,8 +1338,6 @@ static int mdss_dsi_update_panel_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata, ctrl_pdata->panel_mode = pinfo->mipi.mode; mdss_panel_get_dst_fmt(pinfo->bpp, pinfo->mipi.mode, pinfo->mipi.pixel_packing, &(pinfo->mipi.dst_format)); - pinfo->cont_splash_enabled = 0; - return ret; } @@ -2705,6 +2703,7 @@ static struct device_node *mdss_dsi_find_panel_of_node( struct mdss_panel_info *pinfo = &ctrl_pdata->panel_data.panel_info; len = strlen(panel_cfg); + ctrl_pdata->panel_data.dsc_cfg_np_name[0] = '\0'; if (!len) { /* no panel cfg chg, parse dt */ pr_debug("%s:%d: no cmd line cfg present\n", @@ -2788,18 +2787,11 @@ static struct device_node *mdss_dsi_find_panel_of_node( strlcpy(cfg_np_name, str2, MDSS_MAX_PANEL_LEN); } - } - - pr_debug("%s: cfg_np_name:%s\n", __func__, cfg_np_name); - if (str2) { - ctrl_pdata->panel_data.cfg_np = - of_get_child_by_name(dsi_pan_node, - cfg_np_name); - if (!ctrl_pdata->panel_data.cfg_np) - pr_warn("%s: can't find config node:%s. either no such node or bad name\n", - __func__, cfg_np_name); + strlcpy(ctrl_pdata->panel_data.dsc_cfg_np_name, + cfg_np_name, MDSS_MAX_PANEL_LEN); } } + return dsi_pan_node; } end: diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index ecffc12ecd72..bd1854092c6a 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -920,10 +920,17 @@ static inline enum dsi_logical_lane_id mdss_dsi_physical_to_logical_lane( static inline enum dsi_physical_lane_id mdss_dsi_logical_to_physical_lane( struct mdss_dsi_ctrl_pdata *ctrl, enum dsi_logical_lane_id id) { + int i; + if (id >= DSI_LOGICAL_LANE_MAX) return DSI_PHYSICAL_LANE_INVALID; - return ctrl->lane_map[id]; + for (i = DSI_LOGICAL_LANE_0; i < DSI_LOGICAL_LANE_MAX; i++) { + if (BIT(i) == ctrl->lane_map[id]) + break; + } + + return i; } #endif /* MDSS_DSI_H */ diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index 707b1cbbd07b..9548ea471385 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -630,12 +630,21 @@ static void mdss_dsi_panel_switch_mode(struct mdss_panel_data *pdata, pr_debug("%s: sending switch commands\n", __func__); pcmds = &pt->switch_cmds; flags |= CMD_REQ_DMA_TPG; + flags |= CMD_REQ_COMMIT; } else { pr_warn("%s: Invalid mode switch attempted\n", __func__); return; } + if ((pdata->panel_info.compression_mode == COMPRESSION_DSC) && + (pdata->panel_info.send_pps_before_switch)) + mdss_dsi_panel_dsc_pps_send(ctrl_pdata, &pdata->panel_info); + mdss_dsi_panel_cmds_send(ctrl_pdata, pcmds, flags); + + if ((pdata->panel_info.compression_mode == COMPRESSION_DSC) && + (!pdata->panel_info.send_pps_before_switch)) + mdss_dsi_panel_dsc_pps_send(ctrl_pdata, &pdata->panel_info); } static void mdss_dsi_panel_bl_ctrl(struct mdss_panel_data *pdata, @@ -1268,8 +1277,39 @@ end: return rc; } +static struct device_node *mdss_dsi_panel_get_dsc_cfg_np( + struct device_node *np, struct mdss_panel_data *panel_data, + bool default_timing) +{ + struct device_node *dsc_cfg_np = NULL; + + + /* Read the dsc config node specified by command line */ + if (default_timing) { + dsc_cfg_np = of_get_child_by_name(np, + panel_data->dsc_cfg_np_name); + if (!dsc_cfg_np) + pr_warn_once("%s: cannot find dsc config node:%s\n", + __func__, panel_data->dsc_cfg_np_name); + } + + /* + * Fall back to default from DT as nothing is specified + * in command line. + */ + if (!dsc_cfg_np && of_find_property(np, "qcom,config-select", NULL)) { + dsc_cfg_np = of_parse_phandle(np, "qcom,config-select", 0); + if (!dsc_cfg_np) + pr_warn_once("%s:err parsing qcom,config-select\n", + __func__); + } + + return dsc_cfg_np; +} + static int mdss_dsi_parse_topology_config(struct device_node *np, - struct dsi_panel_timing *pt, struct mdss_panel_data *panel_data) + struct dsi_panel_timing *pt, struct mdss_panel_data *panel_data, + bool default_timing) { int rc = 0; bool is_split_display = panel_data->panel_info.is_split_display; @@ -1277,19 +1317,14 @@ static int mdss_dsi_parse_topology_config(struct device_node *np, struct mdss_panel_timing *timing = &pt->timing; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct mdss_panel_info *pinfo; - struct device_node *cfg_np; + struct device_node *cfg_np = NULL; ctrl_pdata = container_of(panel_data, struct mdss_dsi_ctrl_pdata, panel_data); - cfg_np = ctrl_pdata->panel_data.cfg_np; pinfo = &ctrl_pdata->panel_data.panel_info; - if (!cfg_np && of_find_property(np, "qcom,config-select", NULL)) { - cfg_np = of_parse_phandle(np, "qcom,config-select", 0); - if (!cfg_np) - pr_err("%s:err parsing qcom,config-select\n", __func__); - ctrl_pdata->panel_data.cfg_np = cfg_np; - } + cfg_np = mdss_dsi_panel_get_dsc_cfg_np(np, + &ctrl_pdata->panel_data, default_timing); if (cfg_np) { if (!of_property_read_u32_array(cfg_np, "qcom,lm-split", @@ -1331,6 +1366,10 @@ static int mdss_dsi_parse_topology_config(struct device_node *np, if (rc) goto end; + pinfo->send_pps_before_switch = + of_property_read_bool(np, + "qcom,mdss-dsi-send-pps-before-switch"); + rc = mdss_dsi_parse_dsc_params(cfg_np, &pt->timing, is_split_display); } else if (!strcmp(data, "fbc")) { @@ -1480,11 +1519,13 @@ static int mdss_dsi_nt35596_read_status(struct mdss_dsi_ctrl_pdata *ctrl_pdata) } static void mdss_dsi_parse_roi_alignment(struct device_node *np, - struct mdss_panel_info *pinfo) + struct dsi_panel_timing *pt) { int len = 0; u32 value[6]; struct property *data; + struct mdss_panel_timing *timing = &pt->timing; + data = of_find_property(np, "qcom,panel-roi-alignment", &len); len /= sizeof(u32); if (!data || (len != 6)) { @@ -1496,19 +1537,21 @@ static void mdss_dsi_parse_roi_alignment(struct device_node *np, pr_debug("%s: Error reading panel roi alignment values", __func__); else { - pinfo->xstart_pix_align = value[0]; - pinfo->ystart_pix_align = value[1]; - pinfo->width_pix_align = value[2]; - pinfo->height_pix_align = value[3]; - pinfo->min_width = value[4]; - pinfo->min_height = value[5]; + timing->roi_alignment.xstart_pix_align = value[0]; + timing->roi_alignment.ystart_pix_align = value[1]; + timing->roi_alignment.width_pix_align = value[2]; + timing->roi_alignment.height_pix_align = value[3]; + timing->roi_alignment.min_width = value[4]; + timing->roi_alignment.min_height = value[5]; } pr_debug("%s: ROI alignment: [%d, %d, %d, %d, %d, %d]", - __func__, pinfo->xstart_pix_align, - pinfo->width_pix_align, pinfo->ystart_pix_align, - pinfo->height_pix_align, pinfo->min_width, - pinfo->min_height); + __func__, timing->roi_alignment.xstart_pix_align, + timing->roi_alignment.width_pix_align, + timing->roi_alignment.ystart_pix_align, + timing->roi_alignment.height_pix_align, + timing->roi_alignment.min_width, + timing->roi_alignment.min_height); } } @@ -1638,6 +1681,38 @@ static void mdss_dsi_parse_esd_params(struct device_node *np, if (!pinfo->esd_check_enabled) return; + ctrl->status_mode = ESD_MAX; + rc = of_property_read_string(np, + "qcom,mdss-dsi-panel-status-check-mode", &string); + if (!rc) { + if (!strcmp(string, "bta_check")) { + ctrl->status_mode = ESD_BTA; + } else if (!strcmp(string, "reg_read")) { + ctrl->status_mode = ESD_REG; + ctrl->check_read_status = + mdss_dsi_gen_read_status; + } else if (!strcmp(string, "reg_read_nt35596")) { + ctrl->status_mode = ESD_REG_NT35596; + ctrl->status_error_count = 0; + ctrl->check_read_status = + mdss_dsi_nt35596_read_status; + } else if (!strcmp(string, "te_signal_check")) { + if (pinfo->mipi.mode == DSI_CMD_MODE) { + ctrl->status_mode = ESD_TE; + } else { + pr_err("TE-ESD not valid for video mode\n"); + goto error; + } + } else { + pr_err("No valid panel-status-check-mode string\n"); + goto error; + } + } + + if ((ctrl->status_mode == ESD_BTA) || (ctrl->status_mode == ESD_TE) || + (ctrl->status_mode == ESD_MAX)) + return; + mdss_dsi_parse_dcs_cmds(np, &ctrl->status_cmds, "qcom,mdss-dsi-panel-status-command", "qcom,mdss-dsi-panel-status-command-state"); @@ -1693,43 +1768,14 @@ static void mdss_dsi_parse_esd_params(struct device_node *np, memset(ctrl->status_value, 0, ctrl->groups * status_len); } - ctrl->status_mode = ESD_MAX; - rc = of_property_read_string(np, - "qcom,mdss-dsi-panel-status-check-mode", &string); - if (!rc) { - if (!strcmp(string, "bta_check")) { - ctrl->status_mode = ESD_BTA; - } else if (!strcmp(string, "reg_read")) { - ctrl->status_mode = ESD_REG; - ctrl->check_read_status = - mdss_dsi_gen_read_status; - } else if (!strcmp(string, "reg_read_nt35596")) { - ctrl->status_mode = ESD_REG_NT35596; - ctrl->status_error_count = 0; - ctrl->check_read_status = - mdss_dsi_nt35596_read_status; - } else if (!strcmp(string, "te_signal_check")) { - if (pinfo->mipi.mode == DSI_CMD_MODE) { - ctrl->status_mode = ESD_TE; - } else { - pr_err("TE-ESD not valid for video mode\n"); - goto error; - } - } else { - pr_err("No valid panel-status-check-mode string\n"); - goto error; - } - } - return; -error: - kfree(ctrl->return_buf); error2: kfree(ctrl->status_value); error1: kfree(ctrl->status_valid_params); kfree(ctrl->status_cmds_rlen); +error: pinfo->esd_check_enabled = false; } @@ -2157,10 +2203,13 @@ static int mdss_dsi_panel_timing_from_dt(struct device_node *np, static int mdss_dsi_panel_config_res_properties(struct device_node *np, struct dsi_panel_timing *pt, - struct mdss_panel_data *panel_data) + struct mdss_panel_data *panel_data, + bool default_timing) { int rc = 0; + mdss_dsi_parse_roi_alignment(np, pt); + mdss_dsi_parse_dcs_cmds(np, &pt->on_cmds, "qcom,mdss-dsi-on-command", "qcom,mdss-dsi-on-command-state"); @@ -2172,7 +2221,7 @@ static int mdss_dsi_panel_config_res_properties(struct device_node *np, "qcom,mdss-dsi-timing-switch-command", "qcom,mdss-dsi-timing-switch-command-state"); - rc = mdss_dsi_parse_topology_config(np, pt, panel_data); + rc = mdss_dsi_parse_topology_config(np, pt, panel_data, default_timing); if (rc) { pr_err("%s: parsing compression params failed. rc:%d\n", __func__, rc); @@ -2192,6 +2241,7 @@ static int mdss_panel_parse_display_timings(struct device_node *np, struct device_node *entry; int num_timings, rc; int i = 0, active_ndx = 0; + bool default_timing = false; ctrl = container_of(panel_data, struct mdss_dsi_ctrl_pdata, panel_data); @@ -2210,7 +2260,7 @@ static int mdss_panel_parse_display_timings(struct device_node *np, rc = mdss_dsi_panel_timing_from_dt(np, &pt, panel_data); if (!rc) { mdss_dsi_panel_config_res_properties(np, &pt, - panel_data); + panel_data, true); rc = mdss_dsi_panel_timing_switch(ctrl, &pt.timing); } return rc; @@ -2237,14 +2287,14 @@ static int mdss_panel_parse_display_timings(struct device_node *np, goto exit; } - mdss_dsi_panel_config_res_properties(entry, (modedb + i), - panel_data); - - /* if default is set, use it otherwise use first as default */ - if (of_property_read_bool(entry, - "qcom,mdss-dsi-timing-default")) + default_timing = of_property_read_bool(entry, + "qcom,mdss-dsi-timing-default"); + if (default_timing) active_ndx = i; + mdss_dsi_panel_config_res_properties(entry, (modedb + i), + panel_data, default_timing); + list_add(&modedb[i].timing.list, &panel_data->timings_list); i++; @@ -2450,8 +2500,6 @@ static int mdss_panel_parse_dt(struct device_node *np, rc = of_property_read_u32(np, "qcom,mdss-dsi-post-init-delay", &tmp); pinfo->mipi.post_init_delay = (!rc ? tmp : 0); - mdss_dsi_parse_roi_alignment(np, pinfo); - mdss_dsi_parse_trigger(np, &(pinfo->mipi.mdp_trigger), "qcom,mdss-dsi-mdp-trigger"); diff --git a/drivers/video/fbdev/msm/mdss_dsi_phy_v3.c b/drivers/video/fbdev/msm/mdss_dsi_phy_v3.c index 9f419c91661c..7d201a574a00 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_phy_v3.c +++ b/drivers/video/fbdev/msm/mdss_dsi_phy_v3.c @@ -160,6 +160,25 @@ static void mdss_dsi_phy_v3_config_timings(struct mdss_dsi_ctrl_pdata *ctrl) } } +static void mdss_dsi_phy_v3_config_lpcdrx(struct mdss_dsi_ctrl_pdata *ctrl, + bool enable) +{ + struct mdss_dsi_phy_ctrl *pd = + &(((ctrl->panel_data).panel_info.mipi).dsi_phy_db); + enum dsi_physical_lane_id phy_lane_0 = + mdss_dsi_logical_to_physical_lane(ctrl, DSI_LOGICAL_LANE_0); + + /* + * LPRX and CDRX need to enabled only for physical data lane + * corresponding to the logical data lane 0 + */ + if (enable) + DSI_PHY_W32(ctrl->phy_io.base, LNX_LPRX_CTRL(phy_lane_0), + pd->strength[(phy_lane_0 * 2) + 1]); + else + DSI_PHY_W32(ctrl->phy_io.base, LNX_LPRX_CTRL(phy_lane_0), 0); +} + static void mdss_dsi_phy_v3_config_lane_settings( struct mdss_dsi_ctrl_pdata *ctrl) { @@ -172,11 +191,17 @@ static void mdss_dsi_phy_v3_config_lane_settings( for (i = 0; i < 5; i++) { DSI_PHY_W32(ctrl->phy_io.base, LNX_LPTX_STR_CTRL(i), pd->strength[(i * 2)]); - DSI_PHY_W32(ctrl->phy_io.base, LNX_LPRX_CTRL(i), - pd->strength[(i * 2) + 1]); + /* + * Disable LPRX and CDRX for all lanes. And later on, it will + * be only enabled for the physical data lane corresponding + * to the logical data lane 0 + */ + DSI_PHY_W32(ctrl->phy_io.base, LNX_LPRX_CTRL(i), 0); + DSI_PHY_W32(ctrl->phy_io.base, LNX_HSTX_STR_CTRL(i), 0x88); DSI_PHY_W32(ctrl->phy_io.base, LNX_PIN_SWAP(i), 0x0); } + mdss_dsi_phy_v3_config_lpcdrx(ctrl, true); /* Other settings */ for (i = 0; i < 5; i++) { @@ -259,6 +284,12 @@ int mdss_dsi_phy_v3_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl, bool enable) active_lanes); usleep_range(100, 110); + /* Disable LPRX and CDRX */ + mdss_dsi_phy_v3_config_lpcdrx(ctrl, false); + + /* Disable lane LDOs */ + DSI_PHY_W32(ctrl->phy_io.base, CMN_VREG_CTRL, 0x19); + /* Check to make sure that all active data lanes are in ULPS */ lane_status = DSI_PHY_R32(ctrl->phy_io.base, CMN_LANE_STATUS0); if (lane_status & active_lanes) { @@ -268,6 +299,12 @@ int mdss_dsi_phy_v3_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl, bool enable) goto error; } } else { + /* Enable lane LDOs */ + DSI_PHY_W32(ctrl->phy_io.base, CMN_VREG_CTRL, 0x59); + + /* Enable LPRX and CDRX */ + mdss_dsi_phy_v3_config_lpcdrx(ctrl, true); + /* * ULPS Exit Request * Hardware requirement is to wait for at least 1ms @@ -276,6 +313,12 @@ int mdss_dsi_phy_v3_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl, bool enable) active_lanes); usleep_range(1000, 1010); + /* Clear ULPS request flags on all lanes */ + DSI_PHY_W32(ctrl->phy_io.base, CMN_DSI_LANE_CTRL1, 0); + + /* Clear ULPS exit flags on all lanes */ + DSI_PHY_W32(ctrl->phy_io.base, CMN_DSI_LANE_CTRL2, 0); + /* * Sometimes when exiting ULPS, it is possible that some DSI * lanes are not in the stop state which could lead to DSI @@ -286,8 +329,6 @@ int mdss_dsi_phy_v3_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl, bool enable) active_lanes); DSI_PHY_W32(ctrl->phy_io.base, CMN_DSI_LANE_CTRL3, 0); - DSI_PHY_W32(ctrl->phy_io.base, CMN_DSI_LANE_CTRL2, 0); - DSI_PHY_W32(ctrl->phy_io.base, CMN_DSI_LANE_CTRL1, 0); lane_status = DSI_PHY_R32(ctrl->phy_io.base, CMN_LANE_STATUS0); } @@ -306,6 +347,7 @@ int mdss_dsi_phy_v3_shutdown(struct mdss_dsi_ctrl_pdata *ctrl) if (mdss_dsi_phy_v3_is_pll_on(ctrl)) pr_warn("Disabling phy with PLL still enabled\n"); + mdss_dsi_phy_v3_config_lpcdrx(ctrl, false); mdss_dsi_phy_v3_lanes_disable(ctrl); /* Turn off all PHY blocks */ diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index 5888ad9e36be..cc8ce49c7387 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -559,10 +559,14 @@ static ssize_t mdss_fb_get_panel_info(struct device *dev, "min_fps=%d\nmax_fps=%d\npanel_name=%s\n" "primary_panel=%d\nis_pluggable=%d\ndisplay_id=%s\n" "is_cec_supported=%d\nis_pingpong_split=%d\n", - pinfo->partial_update_enabled, pinfo->xstart_pix_align, - pinfo->width_pix_align, pinfo->ystart_pix_align, - pinfo->height_pix_align, pinfo->min_width, - pinfo->min_height, pinfo->partial_update_roi_merge, + pinfo->partial_update_enabled, + pinfo->roi_alignment.xstart_pix_align, + pinfo->roi_alignment.width_pix_align, + pinfo->roi_alignment.ystart_pix_align, + pinfo->roi_alignment.height_pix_align, + pinfo->roi_alignment.min_width, + pinfo->roi_alignment.min_height, + pinfo->partial_update_roi_merge, pinfo->dynamic_fps, pinfo->min_fps, pinfo->max_fps, pinfo->panel_name, pinfo->is_prim_panel, pinfo->is_pluggable, pinfo->display_id, @@ -983,6 +987,30 @@ static void mdss_fb_videomode_from_panel_timing(struct fb_videomode *videomode, } } +static void mdss_fb_set_split_mode(struct msm_fb_data_type *mfd, + struct mdss_panel_data *pdata) +{ + if (pdata->panel_info.is_split_display) { + struct mdss_panel_data *pnext = pdata->next; + + mfd->split_fb_left = pdata->panel_info.lm_widths[0]; + if (pnext) + mfd->split_fb_right = pnext->panel_info.lm_widths[0]; + + if (pdata->panel_info.use_pingpong_split) + mfd->split_mode = MDP_PINGPONG_SPLIT; + else + mfd->split_mode = MDP_DUAL_LM_DUAL_DISPLAY; + } else if ((pdata->panel_info.lm_widths[0] != 0) + && (pdata->panel_info.lm_widths[1] != 0)) { + mfd->split_fb_left = pdata->panel_info.lm_widths[0]; + mfd->split_fb_right = pdata->panel_info.lm_widths[1]; + mfd->split_mode = MDP_DUAL_LM_SINGLE_DISPLAY; + } else { + mfd->split_mode = MDP_SPLIT_MODE_NONE; + } +} + static int mdss_fb_init_panel_modes(struct msm_fb_data_type *mfd, struct mdss_panel_data *pdata) { @@ -1054,6 +1082,7 @@ static int mdss_fb_probe(struct platform_device *pdev) struct msm_fb_data_type *mfd = NULL; struct mdss_panel_data *pdata; struct fb_info *fbi; + struct mdss_overlay_private *mdp5_data = NULL; int rc; if (fbi_list_index >= MAX_FBI_LIST) @@ -1103,25 +1132,8 @@ static int mdss_fb_probe(struct platform_device *pdev) mfd->pdev = pdev; mfd->split_fb_left = mfd->split_fb_right = 0; - mfd->split_mode = MDP_SPLIT_MODE_NONE; - if (pdata->panel_info.is_split_display) { - struct mdss_panel_data *pnext = pdata->next; - - mfd->split_fb_left = pdata->panel_info.lm_widths[0]; - if (pnext) - mfd->split_fb_right = pnext->panel_info.lm_widths[0]; - - if (pdata->panel_info.use_pingpong_split) - mfd->split_mode = MDP_PINGPONG_SPLIT; - else - mfd->split_mode = MDP_DUAL_LM_DUAL_DISPLAY; - } else if ((pdata->panel_info.lm_widths[0] != 0) && - (pdata->panel_info.lm_widths[1] != 0)) { - mfd->split_fb_left = pdata->panel_info.lm_widths[0]; - mfd->split_fb_right = pdata->panel_info.lm_widths[1]; - mfd->split_mode = MDP_DUAL_LM_SINGLE_DISPLAY; - } + mdss_fb_set_split_mode(mfd, pdata); pr_info("fb%d: split_mode:%d left:%d right:%d\n", mfd->index, mfd->split_mode, mfd->split_fb_left, mfd->split_fb_right); @@ -1189,6 +1201,13 @@ static int mdss_fb_probe(struct platform_device *pdev) } mfd->mdp_sync_pt_data.notifier.notifier_call = __mdss_fb_sync_buf_done_callback; + + /* Initialize CWB notifier callback */ + mdp5_data = mfd_to_mdp5_data(mfd); + if (test_bit(MDSS_CAPS_CWB_SUPPORTED, + mdp5_data->mdata->mdss_caps_map)) + mdp5_data->cwb.cwb_sync_pt_data.notifier.notifier_call = + __mdss_fb_sync_buf_done_callback; } mdss_fb_set_mdp_sync_pt_threshold(mfd, mfd->panel.type); @@ -3095,38 +3114,27 @@ u32 mdss_fb_get_mode_switch(struct msm_fb_data_type *mfd) * panel mode being switching into. */ static int __ioctl_transition_dyn_mode_state(struct msm_fb_data_type *mfd, - unsigned int cmd, int validate) + unsigned int cmd, bool validate, bool null_commit) { if (mfd->switch_state == MDSS_MDP_NO_UPDATE_REQUESTED) return 0; mutex_lock(&mfd->switch_lock); switch (cmd) { - case MSMFB_BUFFER_SYNC: - if (mfd->switch_state == MDSS_MDP_WAIT_FOR_SYNC) { - if (mfd->switch_new_mode != SWITCH_RESOLUTION) - mdss_fb_set_mdp_sync_pt_threshold(mfd, - mfd->switch_new_mode); - mfd->switch_state = MDSS_MDP_WAIT_FOR_COMMIT; - } - break; - case MSMFB_OVERLAY_PREPARE: - if (mfd->switch_state == MDSS_MDP_WAIT_FOR_PREP) { - if (mfd->switch_new_mode != SWITCH_RESOLUTION) - mfd->pending_switch = true; - mfd->switch_state = MDSS_MDP_WAIT_FOR_SYNC; - } - break; case MSMFB_ATOMIC_COMMIT: - if ((mfd->switch_state == MDSS_MDP_WAIT_FOR_PREP) && validate) { + if ((mfd->switch_state == MDSS_MDP_WAIT_FOR_VALIDATE) + && validate) { if (mfd->switch_new_mode != SWITCH_RESOLUTION) mfd->pending_switch = true; - mfd->switch_state = MDSS_MDP_WAIT_FOR_SYNC; - } else if (mfd->switch_state == MDSS_MDP_WAIT_FOR_SYNC) { + mfd->switch_state = MDSS_MDP_WAIT_FOR_COMMIT; + } else if (mfd->switch_state == MDSS_MDP_WAIT_FOR_COMMIT) { if (mfd->switch_new_mode != SWITCH_RESOLUTION) mdss_fb_set_mdp_sync_pt_threshold(mfd, mfd->switch_new_mode); - mfd->switch_state = MDSS_MDP_WAIT_FOR_COMMIT; + mfd->switch_state = MDSS_MDP_WAIT_FOR_KICKOFF; + } else if ((mfd->switch_state == MDSS_MDP_WAIT_FOR_VALIDATE) + && null_commit) { + mfd->switch_state = MDSS_MDP_WAIT_FOR_KICKOFF; } break; } @@ -3220,7 +3228,7 @@ int mdss_fb_atomic_commit(struct fb_info *info, pr_err("wait for kickoff failed\n"); } else { __ioctl_transition_dyn_mode_state(mfd, - MSMFB_ATOMIC_COMMIT, 1); + MSMFB_ATOMIC_COMMIT, true, false); if (mfd->panel.type == WRITEBACK_PANEL) { output_layer = commit_v1->output_layer; wb_change = !mdss_fb_is_wb_config_same(mfd, @@ -3246,6 +3254,9 @@ int mdss_fb_atomic_commit(struct fb_info *info, pr_err("pan display idle call failed\n"); goto end; } + __ioctl_transition_dyn_mode_state(mfd, + MSMFB_ATOMIC_COMMIT, false, + (commit_v1->input_layer_cnt ? 0 : 1)); ret = mfd->mdp.pre_commit(mfd, file, commit_v1); if (ret) { @@ -3398,6 +3409,8 @@ static void mdss_fb_var_to_panelinfo(struct fb_var_screeninfo *var, void mdss_panelinfo_to_fb_var(struct mdss_panel_info *pinfo, struct fb_var_screeninfo *var) { + u32 frame_rate; + var->xres = mdss_fb_get_panel_xres(pinfo); var->yres = pinfo->yres; var->lower_margin = pinfo->lcdc.v_front_porch - @@ -3409,9 +3422,21 @@ void mdss_panelinfo_to_fb_var(struct mdss_panel_info *pinfo, var->left_margin = pinfo->lcdc.h_back_porch; var->hsync_len = pinfo->lcdc.h_pulse_width; - if (pinfo->clk_rate) - var->pixclock = KHZ2PICOS((unsigned long int) - pinfo->clk_rate/1000); + frame_rate = mdss_panel_get_framerate(pinfo); + if (frame_rate) { + unsigned long clk_rate, h_total, v_total; + + h_total = var->xres + var->left_margin + + var->right_margin + var->hsync_len; + v_total = var->yres + var->lower_margin + + var->upper_margin + var->vsync_len; + clk_rate = h_total * v_total * frame_rate; + var->pixclock = KHZ2PICOS(clk_rate / 1000); + } else if (pinfo->clk_rate) { + var->pixclock = KHZ2PICOS( + (unsigned long int) pinfo->clk_rate / 1000); + } + if (pinfo->physical_width) var->width = pinfo->physical_width; if (pinfo->physical_height) @@ -3442,13 +3467,19 @@ static int __mdss_fb_perform_commit(struct msm_fb_data_type *mfd) sync_pt_data->flushed = false; mutex_lock(&mfd->switch_lock); - if (mfd->switch_state == MDSS_MDP_WAIT_FOR_COMMIT) { + if (mfd->switch_state == MDSS_MDP_WAIT_FOR_KICKOFF) { dynamic_dsi_switch = 1; new_dsi_mode = mfd->switch_new_mode; + } else if (mfd->switch_state != MDSS_MDP_NO_UPDATE_REQUESTED) { + pr_err("invalid commit on fb%d with state = %d\n", + mfd->index, mfd->switch_state); + mutex_unlock(&mfd->switch_lock); + goto skip_commit; } mutex_unlock(&mfd->switch_lock); - if (dynamic_dsi_switch) { + MDSS_XLOG(mfd->index, mfd->split_mode, new_dsi_mode, + XLOG_FUNC_ENTRY); pr_debug("Triggering dyn mode switch to %d\n", new_dsi_mode); ret = mfd->mdp.mode_switch(mfd, new_dsi_mode); if (ret) @@ -3478,6 +3509,8 @@ static int __mdss_fb_perform_commit(struct msm_fb_data_type *mfd) pr_err("pan display failed %x on fb%d\n", ret, mfd->index); } + +skip_commit: if (!ret) mdss_fb_update_backlight(mfd); @@ -3487,11 +3520,14 @@ static int __mdss_fb_perform_commit(struct msm_fb_data_type *mfd) } if (dynamic_dsi_switch) { + MDSS_XLOG(mfd->index, mfd->split_mode, new_dsi_mode, + XLOG_FUNC_EXIT); mfd->mdp.mode_switch_post(mfd, new_dsi_mode); mutex_lock(&mfd->switch_lock); mfd->switch_state = MDSS_MDP_NO_UPDATE_REQUESTED; mutex_unlock(&mfd->switch_lock); - mfd->panel.type = new_dsi_mode; + if (new_dsi_mode != SWITCH_RESOLUTION) + mfd->panel.type = new_dsi_mode; pr_debug("Dynamic mode switch completed\n"); } @@ -3675,7 +3711,10 @@ static int mdss_fb_videomode_switch(struct msm_fb_data_type *mfd, mdss_fb_wait_for_kickoff(mfd); pr_debug("fb%d: changing display mode to %s\n", mfd->index, mode->name); - + MDSS_XLOG(mfd->index, mode->name, + mdss_fb_get_panel_xres(mfd->panel_info), + mfd->panel_info->yres, mfd->split_mode, + XLOG_FUNC_ENTRY); tmp = pdata; do { if (!tmp->event_handler) { @@ -3690,13 +3729,16 @@ static int mdss_fb_videomode_switch(struct msm_fb_data_type *mfd, tmp = tmp->next; } while (tmp && !ret); + if (!ret) + mdss_fb_set_split_mode(mfd, pdata); + if (!ret && mfd->mdp.configure_panel) { int dest_ctrl = 1; /* todo: currently assumes no changes in video/cmd mode */ if (!mdss_fb_is_power_off(mfd)) { mutex_lock(&mfd->switch_lock); - mfd->switch_state = MDSS_MDP_WAIT_FOR_PREP; + mfd->switch_state = MDSS_MDP_WAIT_FOR_VALIDATE; mfd->switch_new_mode = SWITCH_RESOLUTION; mutex_unlock(&mfd->switch_lock); dest_ctrl = 0; @@ -3705,14 +3747,10 @@ static int mdss_fb_videomode_switch(struct msm_fb_data_type *mfd, pdata->panel_info.mipi.mode, dest_ctrl); } - if (!ret) { - if (pdata->next && pdata->next->active) - mfd->split_mode = MDP_DUAL_LM_DUAL_DISPLAY; - else - mfd->split_mode = MDP_SPLIT_MODE_NONE; - mdss_fb_validate_split(0, 0, mfd); - } - + MDSS_XLOG(mfd->index, mode->name, + mdss_fb_get_panel_xres(mfd->panel_info), + mfd->panel_info->yres, mfd->split_mode, + XLOG_FUNC_EXIT); pr_debug("fb%d: %s mode change complete\n", mfd->index, mode->name); return ret; @@ -4593,7 +4631,7 @@ static int mdss_fb_immediate_mode_switch(struct msm_fb_data_type *mfd, u32 mode) ret = -EAGAIN; goto exit; } - mfd->switch_state = MDSS_MDP_WAIT_FOR_PREP; + mfd->switch_state = MDSS_MDP_WAIT_FOR_VALIDATE; mfd->switch_new_mode = tranlated_mode; exit: @@ -4697,8 +4735,6 @@ int mdss_fb_do_ioctl(struct fb_info *info, unsigned int cmd, if (ret) goto exit; - __ioctl_transition_dyn_mode_state(mfd, cmd, 0); - switch (cmd) { case MSMFB_CURSOR: ret = mdss_fb_cursor(info, argp); diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h index af670f607e54..56997e40d244 100644 --- a/drivers/video/fbdev/msm/mdss_fb.h +++ b/drivers/video/fbdev/msm/mdss_fb.h @@ -129,15 +129,15 @@ enum mdp_mmap_type { * enum dyn_mode_switch_state - Lists next stage for dynamic mode switch work * * @MDSS_MDP_NO_UPDATE_REQUESTED: incoming frame is processed normally - * @MDSS_MDP_WAIT_FOR_PREP: Waiting for OVERLAY_PREPARE to be called - * @MDSS_MDP_WAIT_FOR_SYNC: Waiting for BUFFER_SYNC to be called - * @MDSS_MDP_WAIT_FOR_COMMIT: Waiting for COMMIT to be called + * @MDSS_MDP_WAIT_FOR_VALIDATE: Waiting for ATOMIC_COMMIT-validate to be called + * @MDSS_MDP_WAIT_FOR_COMMIT: Waiting for ATOMIC_COMMIT-commit to be called + * @MDSS_MDP_WAIT_FOR_KICKOFF: Waiting for KICKOFF to be called */ enum dyn_mode_switch_state { MDSS_MDP_NO_UPDATE_REQUESTED, - MDSS_MDP_WAIT_FOR_PREP, - MDSS_MDP_WAIT_FOR_SYNC, + MDSS_MDP_WAIT_FOR_VALIDATE, MDSS_MDP_WAIT_FOR_COMMIT, + MDSS_MDP_WAIT_FOR_KICKOFF, }; /** diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c index 77d7c04e6f0e..6a6cdc8b502c 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c @@ -67,6 +67,13 @@ enum edid_sink_mode { SINK_MODE_HDMI }; +enum luminance_value { + NO_LUMINANCE_DATA = 3, + MAXIMUM_LUMINANCE = 4, + FRAME_AVERAGE_LUMINANCE = 5, + MINIMUM_LUMINANCE = 6 +}; + enum data_block_types { RESERVED, AUDIO_DATA_BLOCK, @@ -82,6 +89,7 @@ enum extended_data_block_types { VIDEO_CAPABILITY_DATA_BLOCK = 0x0, VENDOR_SPECIFIC_VIDEO_DATA_BLOCK = 0x01, HDMI_VIDEO_DATA_BLOCK = 0x04, + HDR_STATIC_METADATA_DATA_BLOCK = 0x06, Y420_VIDEO_DATA_BLOCK = 0x0E, VIDEO_FORMAT_PREFERENCE_DATA_BLOCK = 0x0D, Y420_CAPABILITY_MAP_DATA_BLOCK = 0x0F, @@ -143,11 +151,13 @@ struct hdmi_edid_ctrl { char vendor_id[EDID_VENDOR_ID_SIZE]; bool keep_resv_timings; bool edid_override; + bool hdr_supported; struct hdmi_edid_sink_data sink_data; struct hdmi_edid_init_data init_data; struct hdmi_edid_sink_caps sink_caps; struct hdmi_edid_override_data override_data; + struct hdmi_edid_hdr_data hdr_data; }; static bool hdmi_edid_is_mode_supported(struct hdmi_edid_ctrl *edid_ctrl, @@ -203,6 +213,14 @@ static int hdmi_edid_reset_parser(struct hdmi_edid_ctrl *edid_ctrl) if (!edid_ctrl->keep_resv_timings) hdmi_reset_resv_timing_info(); + /* reset HDR related data */ + edid_ctrl->hdr_supported = false; + edid_ctrl->hdr_data.eotf = 0; + edid_ctrl->hdr_data.descriptor = 0; + edid_ctrl->hdr_data.max_luminance = 0; + edid_ctrl->hdr_data.avg_luminance = 0; + edid_ctrl->hdr_data.min_luminance = 0; + return 0; } @@ -762,6 +780,30 @@ err: } static DEVICE_ATTR(add_res, S_IWUSR, NULL, hdmi_edid_sysfs_wta_add_resolution); +static ssize_t hdmi_edid_sysfs_rda_hdr_data(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + struct hdmi_edid_ctrl *edid_ctrl = hdmi_edid_get_ctrl(dev); + + if (!edid_ctrl) { + DEV_ERR("%s: invalid input\n", __func__); + return -EINVAL; + } + + ret = scnprintf(buf, PAGE_SIZE, "%d, %u, %u, %u, %u, %u\n", + edid_ctrl->hdr_supported, + edid_ctrl->hdr_data.eotf, + edid_ctrl->hdr_data.descriptor, + edid_ctrl->hdr_data.max_luminance, + edid_ctrl->hdr_data.avg_luminance, + edid_ctrl->hdr_data.min_luminance); + DEV_DBG("%s: '%s'\n", __func__, buf); + + return ret; +} +static DEVICE_ATTR(hdr_data, S_IRUGO, hdmi_edid_sysfs_rda_hdr_data, NULL); + static struct attribute *hdmi_edid_fs_attrs[] = { &dev_attr_edid_modes.attr, &dev_attr_pa.attr, @@ -775,6 +817,7 @@ static struct attribute *hdmi_edid_fs_attrs[] = { &dev_attr_res_info.attr, &dev_attr_res_info_data.attr, &dev_attr_add_res.attr, + &dev_attr_hdr_data.attr, NULL, }; @@ -899,6 +942,47 @@ static void hdmi_edid_parse_Y420VDB(struct hdmi_edid_ctrl *edid_ctrl, } } +static bool hdmi_edid_is_luminance_value_present(u32 block_length, + enum luminance_value value) +{ + return block_length > NO_LUMINANCE_DATA && value <= block_length; +} + +static void hdmi_edid_parse_hdrdb(struct hdmi_edid_ctrl *edid_ctrl, + const u8 *data_block) +{ + u8 len = 0; + + if (!edid_ctrl || !data_block) { + pr_err("%s: invalid input\n", __func__); + return; + } + + /* Byte 1: Length of Data Block */ + len = data_block[0] & 0x1F; + + /* Byte 3: Electro-Optical Transfer Functions */ + edid_ctrl->hdr_data.eotf = data_block[2] & 0x3F; + + /* Byte 4: Static Metadata Descriptors */ + edid_ctrl->hdr_data.descriptor = data_block[3] & 0x1; + + /* Byte 5: Desired Content Maximum Luminance */ + if (hdmi_edid_is_luminance_value_present(len, MAXIMUM_LUMINANCE)) + edid_ctrl->hdr_data.max_luminance = + data_block[MAXIMUM_LUMINANCE]; + + /* Byte 6: Desired Content Max Frame-average Luminance */ + if (hdmi_edid_is_luminance_value_present(len, FRAME_AVERAGE_LUMINANCE)) + edid_ctrl->hdr_data.avg_luminance = + data_block[FRAME_AVERAGE_LUMINANCE]; + + /* Byte 7: Desired Content Min Luminance */ + if (hdmi_edid_is_luminance_value_present(len, MINIMUM_LUMINANCE)) + edid_ctrl->hdr_data.min_luminance = + data_block[MINIMUM_LUMINANCE]; +} + static void hdmi_edid_parse_Y420CMDB(struct hdmi_edid_ctrl *edid_ctrl, const u8 *in_buf) { @@ -1045,6 +1129,12 @@ static void hdmi_edid_extract_extended_data_blocks( __func__, etag[2]); hdmi_edid_parse_Y420VDB(edid_ctrl, etag); break; + case HDR_STATIC_METADATA_DATA_BLOCK: + DEV_DBG("%s found HDR Static Metadata. Byte 3 = 0x%x", + __func__, etag[2]); + hdmi_edid_parse_hdrdb(edid_ctrl, etag); + edid_ctrl->hdr_supported = true; + break; default: DEV_DBG("%s: Tag Code %d not supported\n", __func__, etag[1]); @@ -2355,6 +2445,31 @@ u8 hdmi_edid_get_deep_color(void *input) return edid_ctrl->deep_color; } +/** + * hdmi_edid_get_hdr_data() - get the HDR capabiliies of the sink + * @input: edid parser data + * + * This API returns HDR info associated with the sink: + * electro-optical transfer function, static metadata descriptor, + * desired content max luminance data, desired content max + * frame-average luminance data, and desired content min luminance + * data. + * + * Return: HDR data. + */ +void hdmi_edid_get_hdr_data(void *input, + struct hdmi_edid_hdr_data *hdr_data) +{ + struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input; + + if (!edid_ctrl || !hdr_data) { + DEV_ERR("%s: invalid input\n", __func__); + return; + } + + hdr_data = &edid_ctrl->hdr_data; +} + bool hdmi_edid_is_s3d_mode_supported(void *input, u32 video_mode, u32 s3d_mode) { int i; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.h b/drivers/video/fbdev/msm/mdss_hdmi_edid.h index 7b4b2dccc802..c818f3fc0d19 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_edid.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.h @@ -28,6 +28,22 @@ struct hdmi_edid_init_data { u32 buf_size; }; +/* + * struct hdmi_edid_hdr_data - HDR Static Metadata + * @eotf: Electro-Optical Transfer Function + * @descriptor: Static Metadata Descriptor + * @max_luminance: Desired Content Maximum Luminance + * @avg_luminance: Desired Content Frame-average Luminance + * @min_luminance: Desired Content Minimum Luminance + */ +struct hdmi_edid_hdr_data { + u32 eotf; + u32 descriptor; + u32 max_luminance; + u32 avg_luminance; + u32 min_luminance; +}; + int hdmi_edid_parser(void *edid_ctrl); u32 hdmi_edid_get_raw_data(void *edid_ctrl, u8 *buf, u32 size); u8 hdmi_edid_get_sink_scaninfo(void *edid_ctrl, u32 resolution); @@ -44,5 +60,7 @@ void *hdmi_edid_init(struct hdmi_edid_init_data *init_data); bool hdmi_edid_is_s3d_mode_supported(void *input, u32 video_mode, u32 s3d_mode); u8 hdmi_edid_get_deep_color(void *edid_ctrl); +void hdmi_edid_get_hdr_data(void *edid_ctrl, + struct hdmi_edid_hdr_data *hdr_data); #endif /* __HDMI_EDID_H__ */ diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index 7887b865f3c4..3d773371713d 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -21,6 +21,7 @@ #include <linux/of_platform.h> #include <linux/types.h> #include <linux/hdcp_qseecom.h> +#include <linux/msm_mdp.h> #define REG_DUMP 0 @@ -77,6 +78,8 @@ #define HDMI_TX_MIN_FPS 20000 #define HDMI_TX_MAX_FPS 120000 +#define HDMI_TX_VERSION_403 0x40000003 /* msmcobalt */ + /* Enable HDCP by default */ static bool hdcp_feature_on = true; @@ -149,7 +152,6 @@ const char *hdmi_pm_name(enum hdmi_tx_power_module_type module) static int hdmi_tx_get_version(struct hdmi_tx_ctrl *hdmi_ctrl) { int rc; - int reg_val; struct dss_io_data *io; rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, true); @@ -165,11 +167,11 @@ static int hdmi_tx_get_version(struct hdmi_tx_ctrl *hdmi_ctrl) goto fail; } - reg_val = DSS_REG_R(io, HDMI_VERSION); - reg_val = (reg_val & 0xF0000000) >> 28; - hdmi_ctrl->hdmi_tx_ver = reg_val; + hdmi_ctrl->hdmi_tx_version = DSS_REG_R(io, HDMI_VERSION); + hdmi_ctrl->hdmi_tx_major_version = + MDSS_GET_MAJOR(hdmi_ctrl->hdmi_tx_version); - switch (hdmi_ctrl->hdmi_tx_ver) { + switch (hdmi_ctrl->hdmi_tx_major_version) { case (HDMI_TX_VERSION_3): hdmi_ctrl->max_pclk_khz = HDMI_TX_3_MAX_PCLK_RATE; break; @@ -285,7 +287,7 @@ static inline bool hdmi_tx_is_hdcp_enabled(struct hdmi_tx_ctrl *hdmi_ctrl) static inline bool hdmi_tx_dc_support(struct hdmi_tx_ctrl *hdmi_ctrl) { - return hdmi_ctrl->dc_support && + return hdmi_ctrl->dc_feature_on && hdmi_ctrl->dc_support && (hdmi_edid_get_deep_color( hdmi_tx_get_fd(HDMI_TX_FEAT_EDID)) & BIT(1)); } @@ -1671,7 +1673,7 @@ static int hdmi_tx_init_panel(struct hdmi_tx_ctrl *hdmi_ctrl) panel_init_data.spd_vendor_name = hdmi_ctrl->spd_vendor_name; panel_init_data.spd_product_description = hdmi_ctrl->spd_product_description; - panel_init_data.version = hdmi_ctrl->hdmi_tx_ver; + panel_init_data.version = hdmi_ctrl->hdmi_tx_major_version; panel_init_data.ddc = &hdmi_ctrl->ddc_ctrl; panel_init_data.timing = &hdmi_ctrl->timing; @@ -1741,7 +1743,7 @@ static int hdmi_tx_init_hdcp(struct hdmi_tx_ctrl *hdmi_ctrl) hdcp_init_data.workq = hdmi_ctrl->workq; hdcp_init_data.notify_status = hdmi_tx_hdcp_cb; hdcp_init_data.cb_data = (void *)hdmi_ctrl; - hdcp_init_data.hdmi_tx_ver = hdmi_ctrl->hdmi_tx_ver; + hdcp_init_data.hdmi_tx_ver = hdmi_ctrl->hdmi_tx_major_version; hdcp_init_data.timing = &hdmi_ctrl->timing; if (hdmi_ctrl->hdcp14_present) { @@ -2176,7 +2178,7 @@ static int hdmi_tx_check_capability(struct hdmi_tx_ctrl *hdmi_ctrl) } /* check if hdmi and hdcp are disabled */ - if (hdmi_ctrl->hdmi_tx_ver < HDMI_TX_VERSION_4) { + if (hdmi_ctrl->hdmi_tx_major_version < HDMI_TX_VERSION_4) { hdcp_disabled = DSS_REG_R_ND(io, QFPROM_RAW_FEAT_CONFIG_ROW0_LSB) & BIT(31); @@ -2202,8 +2204,12 @@ static int hdmi_tx_check_capability(struct hdmi_tx_ctrl *hdmi_ctrl) } } - DEV_DBG("%s: Features <HDMI:%s, HDCP:%s>\n", __func__, - hdmi_disabled ? "OFF" : "ON", hdcp_disabled ? "OFF" : "ON"); + if (hdmi_ctrl->hdmi_tx_version >= HDMI_TX_VERSION_403) + hdmi_ctrl->dc_feature_on = true; + + DEV_DBG("%s: Features <HDMI:%s, HDCP:%s, Deep Color:%s>\n", __func__, + hdmi_disabled ? "OFF" : "ON", hdcp_disabled ? "OFF" : "ON", + hdmi_ctrl->dc_feature_on ? "OFF" : "ON"); if (hdmi_disabled) { DEV_ERR("%s: HDMI disabled\n", __func__); @@ -2244,7 +2250,7 @@ static void hdmi_tx_set_mode(struct hdmi_tx_ctrl *hdmi_ctrl, u32 power_on) * version less than 4. From 4 onwards, this bit is controlled * by TZ */ - if (hdmi_ctrl->hdmi_tx_ver < 4 && + if (hdmi_ctrl->hdmi_tx_major_version < 4 && hdmi_tx_is_hdcp_enabled(hdmi_ctrl) && !hdmi_ctrl->pdata.primary) hdmi_ctrl_reg |= BIT(2); @@ -2835,6 +2841,9 @@ static int hdmi_tx_setup_tmds_clk_rate(struct hdmi_tx_ctrl *hdmi_ctrl) rate = timing->pixel_freq / rate_ratio; + if (hdmi_tx_dc_support(hdmi_ctrl)) + rate += rate >> 2; + end: return rate; } @@ -3246,7 +3255,7 @@ static irqreturn_t hdmi_tx_isr(int irq, void *data) } if (hdmi_ddc_isr(&hdmi_ctrl->ddc_ctrl, - hdmi_ctrl->hdmi_tx_ver)) + hdmi_ctrl->hdmi_tx_major_version)) DEV_ERR("%s: hdmi_ddc_isr failed\n", __func__); if (hdmi_tx_get_fd(HDMI_TX_FEAT_CEC_HW)) { @@ -3905,95 +3914,142 @@ static void hdmi_tx_put_dt_clk_data(struct device *dev, module_power->num_clk = 0; } /* hdmi_tx_put_dt_clk_data */ -/* todo: once clk are moved to device tree then change this implementation */ -static int hdmi_tx_get_dt_clk_data(struct device *dev, - struct dss_module_power *mp, u32 module_type) +static int hdmi_tx_is_clk_prefix(const char *clk_prefix, const char *clk_name) { - int rc = 0; + return !strncmp(clk_name, clk_prefix, strlen(clk_prefix)); +} - if (!dev || !mp) { - DEV_ERR("%s: invalid input\n", __func__); - return -EINVAL; +static int hdmi_tx_init_power_data(struct device *dev, + struct hdmi_tx_platform_data *pdata) +{ + int num_clk = 0, i = 0, rc = 0; + int hpd_clk_count = 0, core_clk_count = 0; + const char *hpd_clk = "hpd"; + const char *core_clk = "core"; + struct dss_module_power *hpd_power_data = NULL; + struct dss_module_power *core_power_data = NULL; + const char *clk_name; + + num_clk = of_property_count_strings(dev->of_node, + "clock-names"); + if (num_clk <= 0) { + pr_err("%s: no clocks are defined\n", __func__); + rc = -EINVAL; + goto exit; } - DEV_DBG("%s: module: '%s'\n", __func__, hdmi_tx_pm_name(module_type)); + hpd_power_data = &pdata->power_data[HDMI_TX_HPD_PM]; + core_power_data = &pdata->power_data[HDMI_TX_CORE_PM]; - switch (module_type) { - case HDMI_TX_HPD_PM: - mp->num_clk = 5; - mp->clk_config = devm_kzalloc(dev, sizeof(struct dss_clk) * - mp->num_clk, GFP_KERNEL); - if (!mp->clk_config) { - DEV_ERR("%s: can't alloc '%s' clk mem\n", __func__, - hdmi_tx_pm_name(module_type)); - goto error; - } + for (i = 0; i < num_clk; i++) { + of_property_read_string_index(dev->of_node, "clock-names", + i, &clk_name); - snprintf(mp->clk_config[0].clk_name, 32, "%s", "iface_clk"); - mp->clk_config[0].type = DSS_CLK_AHB; - mp->clk_config[0].rate = 0; + if (hdmi_tx_is_clk_prefix(hpd_clk, clk_name)) + hpd_clk_count++; + if (hdmi_tx_is_clk_prefix(core_clk, clk_name)) + core_clk_count++; + } - snprintf(mp->clk_config[1].clk_name, 32, "%s", "mnoc_clk"); - mp->clk_config[1].type = DSS_CLK_AHB; - mp->clk_config[1].rate = 0; + /* Initialize the HPD power module */ + if (hpd_clk_count <= 0) { + pr_err("%s: no hpd clocks are defined\n", __func__); + rc = -EINVAL; + goto exit; + } - snprintf(mp->clk_config[2].clk_name, 32, "%s", "core_clk"); - mp->clk_config[2].type = DSS_CLK_OTHER; - mp->clk_config[2].rate = 19200000; + hpd_power_data->num_clk = hpd_clk_count; + hpd_power_data->clk_config = devm_kzalloc(dev, sizeof(struct dss_clk) * + hpd_power_data->num_clk, GFP_KERNEL); + if (!hpd_power_data->clk_config) { + rc = -EINVAL; + goto exit; + } - /* - * This clock is required to clock MDSS interrupt registers - * when HDMI is the only block turned on within MDSS. Since - * rate for this clock is controlled by MDP driver, treat this - * similar to AHB clock and do not set rate for it. - */ - snprintf(mp->clk_config[3].clk_name, 32, "%s", "mdp_core_clk"); - mp->clk_config[3].type = DSS_CLK_AHB; - mp->clk_config[3].rate = 0; + /* Initialize the CORE power module */ + if (core_clk_count <= 0) { + pr_err("%s: no core clocks are defined\n", __func__); + rc = -EINVAL; + goto core_clock_error; + } - snprintf(mp->clk_config[4].clk_name, 32, "%s", "alt_iface_clk"); - mp->clk_config[4].type = DSS_CLK_AHB; - mp->clk_config[4].rate = 0; - break; + core_power_data->num_clk = core_clk_count; + core_power_data->clk_config = devm_kzalloc(dev, sizeof(struct dss_clk) * + core_power_data->num_clk, GFP_KERNEL); + if (!core_power_data->clk_config) { + core_power_data->num_clk = 0; + rc = -EINVAL; + goto core_clock_error; + } - case HDMI_TX_CORE_PM: - mp->num_clk = 1; - mp->clk_config = devm_kzalloc(dev, sizeof(struct dss_clk) * - mp->num_clk, GFP_KERNEL); - if (!mp->clk_config) { - DEV_ERR("%s: can't alloc '%s' clk mem\n", __func__, - hdmi_tx_pm_name(module_type)); - goto error; - } + return rc; - snprintf(mp->clk_config[0].clk_name, 32, "%s", "extp_clk"); - mp->clk_config[0].type = DSS_CLK_PCLK; - /* This rate will be overwritten when core is powered on */ - mp->clk_config[0].rate = 148500000; - break; +core_clock_error: + hdmi_tx_put_dt_clk_data(dev, hpd_power_data); +exit: + return rc; +} - case HDMI_TX_DDC_PM: - case HDMI_TX_CEC_PM: - mp->num_clk = 0; - DEV_DBG("%s: no clk\n", __func__); - break; +static int hdmi_tx_get_dt_clk_data(struct device *dev, + struct hdmi_tx_platform_data *pdata) +{ + int rc = 0, i = 0; + const char *clk_name; + int num_clk = 0; + int hpd_clk_index = 0, core_clk_index = 0; + int hpd_clk_count = 0, core_clk_count = 0; + const char *hpd_clk = "hpd"; + const char *core_clk = "core"; + struct dss_module_power *hpd_power_data = NULL; + struct dss_module_power *core_power_data = NULL; - default: - DEV_ERR("%s: invalid module type=%d\n", __func__, - module_type); - return -EINVAL; + if (!dev || !pdata) { + pr_err("%s: invalid input\n", __func__); + rc = -EINVAL; + goto exit; } - return rc; + rc = hdmi_tx_init_power_data(dev, pdata); + if (rc) { + pr_err("%s: failed to initialize power data\n", __func__); + rc = -EINVAL; + goto exit; + } -error: - if (mp->clk_config) { - devm_kfree(dev, mp->clk_config); - mp->clk_config = NULL; + hpd_power_data = &pdata->power_data[HDMI_TX_HPD_PM]; + hpd_clk_count = hpd_power_data->num_clk; + core_power_data = &pdata->power_data[HDMI_TX_CORE_PM]; + core_clk_count = core_power_data->num_clk; + + num_clk = hpd_clk_count + core_clk_count; + + for (i = 0; i < num_clk; i++) { + of_property_read_string_index(dev->of_node, "clock-names", + i, &clk_name); + + if (hdmi_tx_is_clk_prefix(hpd_clk, clk_name) + && hpd_clk_index < hpd_clk_count) { + struct dss_clk *clk = + &hpd_power_data->clk_config[hpd_clk_index]; + strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name)); + clk->type = DSS_CLK_AHB; + hpd_clk_index++; + } else if (hdmi_tx_is_clk_prefix(core_clk, clk_name) + && core_clk_index < core_clk_count) { + struct dss_clk *clk = + &core_power_data->clk_config[core_clk_index]; + strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name)); + clk->type = DSS_CLK_PCLK; + core_clk_index++; + } } - mp->num_clk = 0; + + pr_debug("%s: HDMI clock parsing successful\n", __func__); return rc; + +exit: + return rc; } /* hdmi_tx_get_dt_clk_data */ static void hdmi_tx_put_dt_vreg_data(struct device *dev, @@ -4353,14 +4409,11 @@ static int hdmi_tx_get_dt_data(struct platform_device *pdev, } /* CLK */ - for (i = 0; i < HDMI_TX_MAX_PM; i++) { - rc = hdmi_tx_get_dt_clk_data(&pdev->dev, - &pdata->power_data[i], i); - if (rc) { - DEV_ERR("%s: '%s' get_dt_clk_data failed.rc=%d\n", - __func__, hdmi_tx_pm_name(i), rc); - goto error; - } + rc = hdmi_tx_get_dt_clk_data(&pdev->dev, pdata); + if (rc) { + DEV_ERR("%s: get_dt_clk_data failed.rc=%d\n", + __func__, rc); + goto error; } if (!hdmi_ctrl->pdata.primary) @@ -4412,6 +4465,33 @@ static int hdmi_tx_init_event_handler(struct hdmi_tx_ctrl *hdmi_ctrl) return 0; } +static int hdmi_tx_validate_config(struct hdmi_tx_ctrl *hdmi_ctrl) +{ + int i = 0, rc = 0; + u32 version = hdmi_ctrl->hdmi_tx_version; + bool clk_found = false; + const char *mnoc_clk = "hpd_mnoc_clk"; + struct dss_clk *clk_config = + hdmi_ctrl->pdata.power_data[HDMI_TX_HPD_PM].clk_config; + u32 num_clk = hdmi_ctrl->pdata.power_data[HDMI_TX_HPD_PM].num_clk; + + if (version >= HDMI_TX_VERSION_403) { + for (i = 0; i < num_clk; i++) { + if (hdmi_tx_is_clk_prefix(mnoc_clk, + clk_config[i].clk_name)) + clk_found = true; + } + + if (!clk_found) { + pr_err("%s: %s must be defined for HDMI version 0x%08x\n", + __func__, mnoc_clk, version); + rc = -EINVAL; + } + } + + return rc; +} + static int hdmi_tx_probe(struct platform_device *pdev) { int rc = 0, i; @@ -4484,7 +4564,14 @@ static int hdmi_tx_probe(struct platform_device *pdev) if (rc) { DEV_ERR("%s: FAILED: hdmi_tx_get_version. rc=%d\n", __func__, rc); - goto failed_reg_panel; + goto failed_res_init; + } + + rc = hdmi_tx_validate_config(hdmi_ctrl); + if (rc) { + DEV_ERR("%s: FAILED: validate config. rc=%d\n", + __func__, rc); + goto failed_res_init; } rc = hdmi_tx_dev_init(hdmi_ctrl); diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.h b/drivers/video/fbdev/msm/mdss_hdmi_tx.h index a83b20d59836..462edac31c09 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.h @@ -94,7 +94,8 @@ struct hdmi_tx_ctrl { u32 panel_power_on; u32 panel_suspend; u32 vic; - u32 hdmi_tx_ver; + u32 hdmi_tx_version; + u32 hdmi_tx_major_version; u32 max_pclk_khz; u32 hpd_state; u32 hpd_off_pending; @@ -125,6 +126,7 @@ struct hdmi_tx_ctrl { bool hdcp22_present; bool power_data_enable[HDMI_TX_MAX_PM]; bool dc_support; + bool dc_feature_on; void (*hdmi_tx_hpd_done)(void *data); void *downstream_data; diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c index a7b90d149c27..5a355f226179 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -1638,9 +1638,16 @@ static int mdss_mdp_gdsc_notifier_call(struct notifier_block *self, if (event & REGULATOR_EVENT_ENABLE) { __mdss_restore_sec_cfg(mdata); } else if (event & REGULATOR_EVENT_PRE_DISABLE) { - pr_debug("mdss gdsc is getting disabled\n"); - /* halt the vbif transactions */ - mdss_mdp_vbif_axi_halt(mdata); + int active_cnt = atomic_read(&mdata->active_intf_cnt); + + pr_debug("mdss gdsc is getting disabled, active_cnt=%d\n", + active_cnt); + /* + * halt the vbif transactions only if we have any active + * overlay session + */ + if (active_cnt) + mdss_mdp_vbif_axi_halt(mdata); } return NOTIFY_OK; @@ -4543,14 +4550,14 @@ static void apply_dynamic_ot_limit(u32 *ot_lim, return; /* Dynamic OT setting done only for rotator and WFD */ - if (!((params->is_rot && params->is_yuv) || params->is_wb)) + if (!((params->is_rot && params->is_yuv) || params->is_wfd)) return; res = params->width * params->height; pr_debug("w:%d h:%d rot:%d yuv:%d wb:%d res:%d fps:%d\n", params->width, params->height, params->is_rot, - params->is_yuv, params->is_wb, res, params->frame_rate); + params->is_yuv, params->is_wfd, res, params->frame_rate); switch (mdata->mdp_rev) { case MDSS_MDP_HW_REV_114: diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index e7bc1c607d70..d6cd6825e262 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -86,6 +86,11 @@ #define MAX_LAYER_COUNT 0xC +/* For SRC QSEED3, when user space does not send the scaler information, + * this flag allows pixel _extension to be programmed when scaler is disabled + */ +#define ENABLE_PIXEL_EXT_ONLY 0x80000000 + /** * Destination Scaler control flags setting * @@ -397,6 +402,8 @@ struct mdss_mdp_cwb { void *priv_data; struct msm_sync_pt_data cwb_sync_pt_data; struct blocking_notifier_head notifier_head; + struct workqueue_struct *cwb_work_queue; + struct work_struct cwb_work; }; struct mdss_mdp_ctl { @@ -503,6 +510,9 @@ struct mdss_mdp_ctl { u64 last_input_time; int pending_mode_switch; u16 frame_rate; + + /* dynamic resolution switch during cont-splash handoff */ + bool switch_with_handoff; }; struct mdss_mdp_mixer { @@ -897,7 +907,7 @@ struct mdss_mdp_set_ot_params { u32 height; u16 frame_rate; bool is_rot; - bool is_wb; + bool is_wfd; bool is_yuv; bool is_vbif_nrt; u32 reg_off_vbif_lim_conf; diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index fcea868ff082..cd8df78bc8c0 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -561,7 +561,8 @@ static u32 __calc_qseed3_mdp_clk_rate(struct mdss_mdp_pipe *pipe, u64 active_line; u64 backfill_line; - ver_dwnscale = ((u64)src_h << PHASE_STEP_SHIFT) / dst.h; + ver_dwnscale = (u64)src_h << PHASE_STEP_SHIFT; + do_div(ver_dwnscale, dst.h); if (ver_dwnscale > (MDSS_MDP_QSEED3_VER_DOWNSCALE_LIM << PHASE_STEP_SHIFT)) { @@ -3358,9 +3359,12 @@ int mdss_mdp_cwb_setup(struct mdss_mdp_ctl *ctl) if (cwb->priv_data == NULL) { pr_err("fail to get writeback context\n"); rc = -ENOMEM; - goto cwb_setup_done; + goto cwb_setup_fail; } + /* reset wb to null to avoid deferencing in ctl free */ + ctl->wb = NULL; + mutex_lock(&cwb->queue_lock); cwb_data = list_first_entry_or_null(&cwb->data_queue, struct mdss_mdp_wb_data, next); @@ -3368,13 +3372,13 @@ int mdss_mdp_cwb_setup(struct mdss_mdp_ctl *ctl) if (cwb_data == NULL) { pr_err("no output buffer for cwb\n"); rc = -ENOMEM; - goto cwb_setup_done; + goto cwb_setup_fail; } rc = mdss_mdp_data_map(&cwb_data->data, true, DMA_FROM_DEVICE); if (rc) { pr_err("fail to acquire CWB output buffer\n"); - goto cwb_setup_done; + goto cwb_setup_fail; } memset(&wb_args, 0, sizeof(wb_args)); @@ -3383,7 +3387,7 @@ int mdss_mdp_cwb_setup(struct mdss_mdp_ctl *ctl) rc = mdss_mdp_writeback_prepare_cwb(ctl, &wb_args); if (rc) { pr_err("failed to writeback prepare cwb\n"); - goto cwb_setup_done; + goto cwb_setup_fail; } /* Select MEM_SEL to WB */ @@ -3409,11 +3413,13 @@ int mdss_mdp_cwb_setup(struct mdss_mdp_ctl *ctl) sctl->opmode; mdss_mdp_ctl_write(sctl, MDSS_MDP_REG_CTL_TOP, opmode); } + goto cwb_setup_done; -cwb_setup_done: - cwb->valid = 0; +cwb_setup_fail: atomic_add_unless(&mdp5_data->wb_busy, -1, 0); +cwb_setup_done: + cwb->valid = 0; return 0; } @@ -3616,10 +3622,28 @@ skip_intf_reconfig: ctl->width = get_panel_xres(&pdata->panel_info); ctl->height = get_panel_yres(&pdata->panel_info); } - if (ctl->mixer_left) { - ctl->mixer_left->width = ctl->width; - ctl->mixer_left->height = ctl->height; + + if (ctl->mfd->split_mode == MDP_DUAL_LM_SINGLE_DISPLAY) { + if (ctl->mixer_left) { + ctl->mixer_left->width = ctl->width / 2; + ctl->mixer_left->height = ctl->height; + } + if (ctl->mixer_right) { + ctl->mixer_right->width = ctl->width / 2; + ctl->mixer_right->height = ctl->height; + } + } else { + /* + * Handles MDP_SPLIT_MODE_NONE, MDP_DUAL_LM_DUAL_DISPLAY and + * MDP_PINGPONG_SPLIT case. + */ + if (ctl->mixer_left) { + ctl->mixer_left->width = ctl->width; + ctl->mixer_left->height = ctl->height; + } } + ctl->roi = (struct mdss_rect) {0, 0, ctl->width, ctl->height}; + ctl->border_x_off = pdata->panel_info.lcdc.border_left; ctl->border_y_off = pdata->panel_info.lcdc.border_top; @@ -3955,7 +3979,13 @@ static void mdss_mdp_ctl_restore_sub(struct mdss_mdp_ctl *ctl) mdss_mdp_pp_resume(ctl->mfd); if (is_dsc_compression(&ctl->panel_data->panel_info)) { - mdss_mdp_ctl_dsc_setup(ctl, + /* + * Avoid redundant call to dsc_setup when mode switch + * is in progress. During the switch, dsc_setup is + * handled in mdss_mode_switch() function. + */ + if (ctl->pending_mode_switch != SWITCH_RESOLUTION) + mdss_mdp_ctl_dsc_setup(ctl, &ctl->panel_data->panel_info); } else if (ctl->panel_data->panel_info.compression_mode == COMPRESSION_FBC) { diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c index 4874e055b274..a1e5982bccda 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -2048,11 +2048,12 @@ static int mdss_mdp_cmd_panel_on(struct mdss_mdp_ctl *ctl, WARN(rc, "intf %d panel on error (%d)\n", ctl->intf_num, rc); - rc = mdss_mdp_tearcheck_enable(ctl, true); - WARN(rc, "intf %d tearcheck enable error (%d)\n", - ctl->intf_num, rc); } + rc = mdss_mdp_tearcheck_enable(ctl, true); + WARN(rc, "intf %d tearcheck enable error (%d)\n", + ctl->intf_num, rc); + ctx->panel_power_state = MDSS_PANEL_POWER_ON; if (sctx) sctx->panel_power_state = MDSS_PANEL_POWER_ON; @@ -3340,9 +3341,6 @@ void mdss_mdp_switch_to_vid_mode(struct mdss_mdp_ctl *ctl, int prep) static int mdss_mdp_cmd_reconfigure(struct mdss_mdp_ctl *ctl, enum dynamic_switch_modes mode, bool prep) { - struct dsi_panel_clk_ctrl clk_ctrl; - int ret, rc = 0; - if (mdss_mdp_ctl_is_power_off(ctl)) return 0; @@ -3353,41 +3351,39 @@ static int mdss_mdp_cmd_reconfigure(struct mdss_mdp_ctl *ctl, mdss_mdp_switch_to_vid_mode(ctl, prep); } else if (mode == SWITCH_RESOLUTION) { if (prep) { - /* make sure any pending transfer is finished */ - ret = mdss_mdp_cmd_wait4pingpong(ctl, NULL); - if (ret) - return ret; - + mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); /* - * keep a ref count on clocks to prevent them from - * being disabled while switch happens + * Setup DSC conifg early, as DSI configuration during + * resolution switch would rely on DSC params for + * stream configs. */ - mdss_bus_bandwidth_ctrl(true); - rc = mdss_iommu_ctrl(1); - if (IS_ERR_VALUE(rc)) - pr_err("IOMMU attach failed\n"); + mdss_mdp_cmd_dsc_reconfig(ctl); - clk_ctrl.state = MDSS_DSI_CLK_ON; - clk_ctrl.client = DSI_CLK_REQ_MDP_CLIENT; - mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); - mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_CLK_CTRL, - (void *)&clk_ctrl, - CTL_INTF_EVENT_FLAG_DEFAULT); + /* + * Make explicit cmd_panel_on call, when dynamic + * resolution switch request comes before cont-splash + * handoff, to match the ctl_stop/ctl_start done + * during the reconfiguration. + */ + if (ctl->switch_with_handoff) { + struct mdss_mdp_cmd_ctx *ctx; + struct mdss_mdp_ctl *sctl; + + ctx = (struct mdss_mdp_cmd_ctx *) + ctl->intf_ctx[MASTER_CTX]; + if (ctx && + __mdss_mdp_cmd_is_panel_power_off(ctx)) { + sctl = mdss_mdp_get_split_ctl(ctl); + mdss_mdp_cmd_panel_on(ctl, sctl); + } + ctl->switch_with_handoff = false; + } mdss_mdp_ctl_stop(ctl, MDSS_PANEL_POWER_OFF); mdss_mdp_ctl_intf_event(ctl, - MDSS_EVENT_DSI_DYNAMIC_SWITCH, - (void *) mode, - CTL_INTF_EVENT_FLAG_DEFAULT); + MDSS_EVENT_DSI_DYNAMIC_SWITCH, + (void *) mode, CTL_INTF_EVENT_FLAG_DEFAULT); } else { - /* release ref count after switch is complete */ - clk_ctrl.state = MDSS_DSI_CLK_OFF; - clk_ctrl.client = DSI_CLK_REQ_MDP_CLIENT; - mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_CLK_CTRL, - (void *)&clk_ctrl, - CTL_INTF_EVENT_FLAG_DEFAULT); - mdss_iommu_ctrl(0); - mdss_bus_bandwidth_ctrl(false); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); } } diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c index 237157c81515..9026b99cd87a 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c @@ -124,6 +124,28 @@ static inline void mdp_wb_write(struct mdss_mdp_writeback_ctx *ctx, writel_relaxed(val, ctx->base + reg); } +static void mdss_mdp_set_ot_limit_wb(struct mdss_mdp_writeback_ctx *ctx, + int is_wfd) +{ + struct mdss_mdp_set_ot_params ot_params; + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + + ot_params.xin_id = ctx->xin_id; + ot_params.num = ctx->wb_num; + ot_params.width = ctx->width; + ot_params.height = ctx->height; + ot_params.frame_rate = ctx->frame_rate; + ot_params.reg_off_vbif_lim_conf = MMSS_VBIF_WR_LIM_CONF; + ot_params.reg_off_mdp_clk_ctrl = ctx->clk_ctrl.reg_off; + ot_params.bit_off_mdp_clk_ctrl = ctx->clk_ctrl.bit_off; + ot_params.is_rot = (ctx->type == MDSS_MDP_WRITEBACK_TYPE_ROTATOR); + ot_params.is_wfd = is_wfd; + ot_params.is_yuv = ctx->dst_fmt->is_yuv; + ot_params.is_vbif_nrt = mdss_mdp_is_nrt_vbif_base_defined(mdata); + + mdss_mdp_set_ot_limit(&ot_params); +} + static int mdss_mdp_writeback_addr_setup(struct mdss_mdp_writeback_ctx *ctx, const struct mdss_mdp_data *in_data) { @@ -202,18 +224,18 @@ static void mdss_mdp_writeback_cwb_overflow(void *arg) { struct mdss_mdp_ctl *ctl = arg; struct mdss_overlay_private *mdp5_data = NULL; + struct mdss_mdp_writeback_ctx *ctx = NULL; pr_err("Buffer overflow triggered ctl=%d\n", ctl->num); MDSS_XLOG(ctl->num); - if (ctl->mfd) + if (!ctl->mfd) return; mdp5_data = mfd_to_mdp5_data(ctl->mfd); + ctx = mdp5_data->cwb.priv_data; mdp5_data->cwb.valid = 0; - blocking_notifier_call_chain(&mdp5_data->cwb.notifier_head, - MDP_NOTIFY_FRAME_TIMEOUT, NULL); - + mdss_mdp_irq_disable_nosync(ctx->intr_type, ctx->intf_num); mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, CWB_PPB_0); if (mdss_mdp_get_split_ctl(ctl)) mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, @@ -231,7 +253,7 @@ static void mdss_mdp_writeback_cwb_intr_done(void *arg) struct mdss_overlay_private *mdp5_data = NULL; struct mdss_mdp_writeback_ctx *ctx = NULL; - if (ctl->mfd) + if (!ctl->mfd) return; mdp5_data = mfd_to_mdp5_data(ctl->mfd); @@ -239,9 +261,12 @@ static void mdss_mdp_writeback_cwb_intr_done(void *arg) mdp5_data->cwb.valid = 0; mdss_mdp_irq_disable_nosync(ctx->intr_type, ctx->intf_num); + mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, CWB_PPB_0); + if (mdss_mdp_get_split_ctl(ctl)) + mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, + CWB_PPB_1); - blocking_notifier_call_chain(&mdp5_data->cwb.notifier_head, - MDP_NOTIFY_FRAME_DONE, NULL); + queue_work(mdp5_data->cwb.cwb_work_queue, &mdp5_data->cwb.cwb_work); if (!atomic_add_unless(&mdp5_data->wb_busy, -1, 0)) pr_err("Invalid state for WB\n"); @@ -462,6 +487,10 @@ int mdss_mdp_writeback_prepare_cwb(struct mdss_mdp_ctl *ctl, sctl->intf_num, mdss_mdp_writeback_cwb_overflow, sctl); } + + if (ctl->mdata->default_ot_wr_limit || ctl->mdata->default_ot_rd_limit) + mdss_mdp_set_ot_limit_wb(ctx, false); + return ret; } @@ -840,28 +869,6 @@ static int mdss_mdp_wb_wait4comp(struct mdss_mdp_ctl *ctl, void *arg) return rc; } -static void mdss_mdp_set_ot_limit_wb(struct mdss_mdp_writeback_ctx *ctx) -{ - struct mdss_mdp_set_ot_params ot_params; - struct mdss_data_type *mdata = mdss_mdp_get_mdata(); - - ot_params.xin_id = ctx->xin_id; - ot_params.num = ctx->wb_num; - ot_params.width = ctx->width; - ot_params.height = ctx->height; - ot_params.frame_rate = ctx->frame_rate; - ot_params.reg_off_vbif_lim_conf = MMSS_VBIF_WR_LIM_CONF; - ot_params.reg_off_mdp_clk_ctrl = ctx->clk_ctrl.reg_off; - ot_params.bit_off_mdp_clk_ctrl = ctx->clk_ctrl.bit_off; - ot_params.is_rot = (ctx->type == MDSS_MDP_WRITEBACK_TYPE_ROTATOR); - ot_params.is_wb = true; - ot_params.is_yuv = ctx->dst_fmt->is_yuv; - ot_params.is_vbif_nrt = mdss_mdp_is_nrt_vbif_base_defined(mdata); - - mdss_mdp_set_ot_limit(&ot_params); - -} - static int mdss_mdp_writeback_display(struct mdss_mdp_ctl *ctl, void *arg) { struct mdss_mdp_writeback_ctx *ctx; @@ -884,7 +891,7 @@ static int mdss_mdp_writeback_display(struct mdss_mdp_ctl *ctl, void *arg) if (ctl->mdata->default_ot_wr_limit || ctl->mdata->default_ot_rd_limit) - mdss_mdp_set_ot_limit_wb(ctx); + mdss_mdp_set_ot_limit_wb(ctx, true); wb_args = (struct mdss_mdp_writeback_arg *) arg; if (!wb_args) diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c index 65b3b9739be6..17cbdd44755a 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_layer.c +++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c @@ -1836,7 +1836,7 @@ static int __validate_layers(struct msm_fb_data_type *mfd, struct mdss_mdp_mixer *mixer = NULL; struct mdp_input_layer *layer, *prev_layer, *layer_list; struct mdss_mdp_validate_info_t *validate_info_list = NULL; - bool is_single_layer = false; + bool is_single_layer = false, force_validate; enum layer_pipe_q pipe_q_type; enum layer_zorder_used zorder_used[MDSS_MDP_MAX_STAGE] = {0}; enum mdss_mdp_pipe_rect rect_num; @@ -1895,6 +1895,15 @@ static int __validate_layers(struct msm_fb_data_type *mfd, rec_ndx[rect_num] |= layer_list[i].pipe_ndx; } + /* + * Force all layers to go through full validation after + * dynamic resolution switch, immaterial of the configs in + * the layer. + */ + mutex_lock(&mfd->switch_lock); + force_validate = (mfd->switch_state != MDSS_MDP_NO_UPDATE_REQUESTED); + mutex_unlock(&mfd->switch_lock); + for (i = 0; i < layer_count; i++) { enum layer_zorder_used z = LAYER_ZORDER_NONE; @@ -1980,8 +1989,9 @@ static int __validate_layers(struct msm_fb_data_type *mfd, * are same. validation can be skipped if only buffer handle * is changed. */ - pipe = __find_layer_in_validate_q(&validate_info_list[i], - mdp5_data); + pipe = (force_validate) ? NULL : + __find_layer_in_validate_q( + &validate_info_list[i], mdp5_data); if (pipe) { if (mixer_mux == MDSS_MDP_MIXER_MUX_RIGHT) right_plist[right_cnt++] = pipe; diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index 0173f73ffe6b..2baa1b9cd8b5 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -54,6 +54,7 @@ static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd); static void __overlay_kickoff_requeue(struct msm_fb_data_type *mfd); static void __vsync_retire_signal(struct msm_fb_data_type *mfd, int val); static int __vsync_set_vsync_handler(struct msm_fb_data_type *mfd); +static void __cwb_wq_handler(struct work_struct *cwb_work); static int mdss_mdp_update_panel_info(struct msm_fb_data_type *mfd, int mode, int dest_ctrl); static int mdss_mdp_set_cfg(struct msm_fb_data_type *mfd, @@ -560,7 +561,8 @@ int mdss_mdp_overlay_setup_scaling(struct mdss_mdp_pipe *pipe) rc, src, pipe->dst.h); } - if (test_bit(MDSS_CAPS_QSEED3, mdata->mdss_caps_map)) + if (test_bit(MDSS_CAPS_QSEED3, mdata->mdss_caps_map) && + (pipe->type == MDSS_MDP_PIPE_TYPE_VIG)) mdss_mdp_pipe_calc_qseed3_cfg(pipe); else mdss_mdp_pipe_calc_pixel_extn(pipe); @@ -1710,8 +1712,9 @@ int mdss_mode_switch(struct msm_fb_data_type *mfd, u32 mode) { struct mdss_rect l_roi, r_roi; struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd); + struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); struct mdss_mdp_ctl *sctl; - int rc; + int rc = 0; pr_debug("fb%d switch to mode=%x\n", mfd->index, mode); ATRACE_FUNC(); @@ -1724,9 +1727,42 @@ int mdss_mode_switch(struct msm_fb_data_type *mfd, u32 mode) /* No need for mode validation. It has been done in ioctl call */ if (mode == SWITCH_RESOLUTION) { if (ctl->ops.reconfigure) { - rc = ctl->ops.reconfigure(ctl, mode, 1); - if (rc) + /* wait for previous frame to complete before switch */ + if (ctl->ops.wait_pingpong) + rc = ctl->ops.wait_pingpong(ctl, NULL); + if (!rc && sctl && sctl->ops.wait_pingpong) + rc = sctl->ops.wait_pingpong(sctl, NULL); + if (rc) { + pr_err("wait for pp failed before resolution switch\n"); return rc; + } + + /* + * Configure the mixer parameters before the switch as + * the DSC parameter calculation is based on the mixer + * ROI. And set it to full ROI as driver expects the + * first frame after the resolution switch to be a + * full frame update. + */ + if (ctl->mixer_left) { + l_roi = (struct mdss_rect) {0, 0, + ctl->mixer_left->width, + ctl->mixer_left->height}; + ctl->mixer_left->roi_changed = true; + ctl->mixer_left->valid_roi = true; + } + if (ctl->mixer_right) { + r_roi = (struct mdss_rect) {0, 0, + ctl->mixer_right->width, + ctl->mixer_right->height}; + ctl->mixer_right->roi_changed = true; + ctl->mixer_right->valid_roi = true; + } + mdss_mdp_set_roi(ctl, &l_roi, &r_roi); + + mutex_lock(&mdp5_data->ov_lock); + ctl->ops.reconfigure(ctl, mode, 1); + mutex_unlock(&mdp5_data->ov_lock); /* * For Video mode panels, reconfigure is not defined. * So doing an explicit ctrl stop during resolution switch @@ -1849,7 +1885,13 @@ static void __validate_and_set_roi(struct msm_fb_data_type *mfd, l_roi.x, l_roi.y, l_roi.w, l_roi.h, r_roi.x, r_roi.y, r_roi.w, r_roi.h); - if (!ctl->panel_data->panel_info.partial_update_enabled) + /* + * Configure full ROI + * - If partial update is disabled + * - If it is the first frame update after dynamic resolution switch + */ + if (!ctl->panel_data->panel_info.partial_update_enabled + || (ctl->pending_mode_switch == SWITCH_RESOLUTION)) goto set_roi; skip_partial_update = false; @@ -4293,6 +4335,22 @@ static int mdss_mdp_overlay_precommit(struct msm_fb_data_type *mfd) mfd->index, ret); ret = -EPIPE; } + + /* + * If we are in process of mode switch we may have an invalid state. + * We can allow commit to happen if there are no pipes attached as only + * border color will be seen regardless of resolution or mode. + */ + if ((mfd->switch_state != MDSS_MDP_NO_UPDATE_REQUESTED) && + (mfd->switch_state != MDSS_MDP_WAIT_FOR_COMMIT)) { + if (list_empty(&mdp5_data->pipes_used)) { + mfd->switch_state = MDSS_MDP_WAIT_FOR_COMMIT; + } else { + pr_warn("Invalid commit on fb%d with state=%d\n", + mfd->index, mfd->switch_state); + ret = -EINVAL; + } + } mutex_unlock(&mdp5_data->ov_lock); return ret; @@ -4823,6 +4881,39 @@ static void mdss_mdp_set_lm_flag(struct msm_fb_data_type *mfd) } } +static void mdss_mdp_handle_invalid_switch_state(struct msm_fb_data_type *mfd) +{ + int rc = 0; + struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); + struct mdss_mdp_ctl *ctl = mdp5_data->ctl; + struct mdss_mdp_ctl *sctl = mdss_mdp_get_split_ctl(ctl); + struct mdss_mdp_data *buf, *tmpbuf; + + mfd->switch_state = MDSS_MDP_NO_UPDATE_REQUESTED; + + /* + * Handle only for cmd mode panels as for video mode, buffers + * cannot be freed at this point. Needs revisting to handle the + * use case for video mode panels. + */ + if (mfd->panel_info->type == MIPI_CMD_PANEL) { + if (ctl->ops.wait_pingpong) + rc = ctl->ops.wait_pingpong(ctl, NULL); + if (!rc && sctl && sctl->ops.wait_pingpong) + rc = sctl->ops.wait_pingpong(sctl, NULL); + if (rc) { + pr_err("wait for pp failed\n"); + return; + } + + mutex_lock(&mdp5_data->list_lock); + list_for_each_entry_safe(buf, tmpbuf, + &mdp5_data->bufs_used, buf_list) + list_move(&buf->buf_list, &mdp5_data->bufs_freelist); + mutex_unlock(&mdp5_data->list_lock); + } +} + static int mdss_mdp_overlay_on(struct msm_fb_data_type *mfd) { int rc; @@ -4942,6 +5033,7 @@ static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd) struct mdss_mdp_mixer *mixer; int need_cleanup; int retire_cnt; + bool destroy_ctl = false; if (!mfd) return -ENODEV; @@ -4998,6 +5090,18 @@ static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd) mutex_unlock(&mdp5_data->list_lock); mutex_unlock(&mdp5_data->ov_lock); + destroy_ctl = !mfd->ref_cnt || mfd->panel_reconfig; + + mutex_lock(&mfd->switch_lock); + if (mfd->switch_state != MDSS_MDP_NO_UPDATE_REQUESTED) { + destroy_ctl = true; + need_cleanup = false; + pr_warn("fb%d blank while mode switch (%d) in progress\n", + mfd->index, mfd->switch_state); + mdss_mdp_handle_invalid_switch_state(mfd); + } + mutex_unlock(&mfd->switch_lock); + if (need_cleanup) { pr_debug("cleaning up pipes on fb%d\n", mfd->index); mdss_mdp_overlay_kickoff(mfd, NULL); @@ -5051,7 +5155,7 @@ ctl_stop: mdss_mdp_ctl_notifier_unregister(mdp5_data->ctl, &mfd->mdp_sync_pt_data.notifier); - if (!mfd->ref_cnt || mfd->panel_reconfig) { + if (destroy_ctl) { mdp5_data->borderfill_enable = false; mdss_mdp_ctl_destroy(mdp5_data->ctl); mdp5_data->ctl = NULL; @@ -5300,6 +5404,15 @@ __vsync_retire_get_fence(struct msm_sync_pt_data *sync_pt_data) "mdp-retire", value); } +static void __cwb_wq_handler(struct work_struct *cwb_work) +{ + struct mdss_mdp_cwb *cwb = NULL; + + cwb = container_of(cwb_work, struct mdss_mdp_cwb, cwb_work); + blocking_notifier_call_chain(&cwb->notifier_head, + MDP_NOTIFY_FRAME_DONE, NULL); +} + static int __vsync_set_vsync_handler(struct msm_fb_data_type *mfd) { struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); @@ -5354,6 +5467,7 @@ static int mdss_mdp_update_panel_info(struct msm_fb_data_type *mfd, int ret = 0; struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); struct mdss_mdp_ctl *ctl = mdp5_data->ctl; + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); struct mdss_panel_data *pdata; struct mdss_mdp_ctl *sctl; @@ -5387,6 +5501,13 @@ static int mdss_mdp_update_panel_info(struct msm_fb_data_type *mfd, */ mdss_mdp_ctl_reconfig(ctl, pdata); + /* + * Set flag when dynamic resolution switch happens before + * handoff of cont-splash + */ + if (mdata->handoff_pending) + ctl->switch_with_handoff = true; + sctl = mdss_mdp_get_split_ctl(ctl); if (sctl) { if (mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) { @@ -5492,15 +5613,22 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd) mutex_init(&mdp5_data->list_lock); mutex_init(&mdp5_data->ov_lock); mutex_init(&mdp5_data->dfps_lock); + + mfd->mdp.private1 = mdp5_data; + mfd->wait_for_kickoff = true; + mdp5_data->hw_refresh = true; mdp5_data->cursor_ndx[CURSOR_PIPE_LEFT] = MSMFB_NEW_REQUEST; mdp5_data->cursor_ndx[CURSOR_PIPE_RIGHT] = MSMFB_NEW_REQUEST; init_waitqueue_head(&mdp5_data->wb_waitq); + atomic_set(&mdp5_data->wb_busy, 0); mutex_init(&mdp5_data->cwb.queue_lock); + mutex_init(&mdp5_data->cwb.cwb_sync_pt_data.sync_mutex); INIT_LIST_HEAD(&mdp5_data->cwb.data_queue); snprintf(timeline_name, sizeof(timeline_name), "cwb%d", mfd->index); + mdp5_data->cwb.cwb_sync_pt_data.fence_name = "cwb-fence"; mdp5_data->cwb.cwb_sync_pt_data.timeline = sw_sync_timeline_create(timeline_name); if (mdp5_data->cwb.cwb_sync_pt_data.timeline == NULL) { @@ -5509,10 +5637,15 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd) } blocking_notifier_chain_register(&mdp5_data->cwb.notifier_head, - &mfd->mdp_sync_pt_data.notifier); + &mdp5_data->cwb.cwb_sync_pt_data.notifier); + mdp5_data->cwb.cwb_work_queue = alloc_ordered_workqueue("%s", + WQ_UNBOUND | WQ_MEM_RECLAIM, "cwb_wq"); + if (!mdp5_data->cwb.cwb_work_queue) { + pr_err("failed to create cwb work queue\n"); + return -EPERM; + } - mfd->mdp.private1 = mdp5_data; - mfd->wait_for_kickoff = true; + INIT_WORK(&mdp5_data->cwb.cwb_work, __cwb_wq_handler); rc = mdss_mdp_overlay_fb_parse_dt(mfd); if (rc) diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c index e011e35ac62e..bcb4867b4ffd 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c @@ -2379,7 +2379,7 @@ static void mdss_mdp_set_ot_limit_pipe(struct mdss_mdp_pipe *pipe) ot_params.bit_off_mdp_clk_ctrl = pipe->clk_ctrl.bit_off + CLK_FORCE_ON_OFFSET; ot_params.is_rot = pipe->mixer_left->rotator_mode; - ot_params.is_wb = ctl->intf_num == MDSS_MDP_NO_INTF; + ot_params.is_wfd = ctl->intf_num == MDSS_MDP_NO_INTF; ot_params.is_yuv = pipe->src_fmt->is_yuv; ot_params.frame_rate = pipe->frame_rate; @@ -3136,6 +3136,13 @@ void mdss_mdp_pipe_calc_qseed3_cfg(struct mdss_mdp_pipe *pipe) pipe->scaler.src_height[i]); } + if ((!pipe->src_fmt->is_yuv) && + (pipe->src.w == pipe->dst.w) && + (pipe->src.h == pipe->dst.h)) { + pipe->scaler.enable = ENABLE_PIXEL_EXT_ONLY; + return; + } + pipe->scaler.dst_width = pipe->dst.w; pipe->scaler.dst_height = pipe->dst.h; /* assign filters */ @@ -3143,5 +3150,6 @@ void mdss_mdp_pipe_calc_qseed3_cfg(struct mdss_mdp_pipe *pipe) pipe->scaler.uv_filter_cfg = FILTER_BILINEAR; pipe->scaler.alpha_filter_cfg = FILTER_ALPHA_BILINEAR; pipe->scaler.lut_flag = 0; + pipe->scaler.blend_cfg = 1; pipe->scaler.enable = ENABLE_SCALE; } diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c index 437e01535924..c4cbc220baf8 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pp.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c @@ -1491,13 +1491,18 @@ int mdss_mdp_scaler_lut_cfg(struct mdp_scale_data_v2 *scaler, uint32_t *lut_type[QSEED3_FILTERS] = {NULL, NULL, NULL, NULL, NULL}; uint32_t lut_offset, lut_len; struct mdss_mdp_qseed3_lut_tbl *lut_tbl; - /* for each filter, 4 lut regions offset and length table */ + /* for each filter, 4 lut regions length and offset table */ static uint32_t offset_tbl[QSEED3_FILTERS][QSEED3_LUT_REGIONS][2] = { + /* DIR */ {{18, 0x000}, {12, 0x120}, {12, 0x1E0}, {8, 0x2A0} }, + /* Y_CIR */ {{6, 0x320}, {3, 0x3E0}, {3, 0x440}, {3, 0x4A0} }, - {{6, 0x380}, {3, 0x410}, {3, 0x470}, {3, 0x4d0} }, - {{6, 0x500}, {3, 0x5c0}, {3, 0x620}, {3, 0x680} }, - {{6, 0x560}, {3, 0x5f0}, {3, 0x650}, {3, 0x6b0} }, + /* Y_SEP */ + {{6, 0x380}, {3, 0x410}, {3, 0x470}, {3, 0x4D0} }, + /* UV_CIR */ + {{6, 0x500}, {3, 0x5C0}, {3, 0x620}, {3, 0x680} }, + /* UV_SEP */ + {{6, 0x560}, {3, 0x5F0}, {3, 0x650}, {3, 0x6B0} }, }; mdata = mdss_mdp_get_mdata(); @@ -1518,13 +1523,14 @@ int mdss_mdp_scaler_lut_cfg(struct mdp_scale_data_v2 *scaler, lut_type[1] = lut_tbl->cir_lut + scaler->y_rgb_cir_lut_idx * CIR_LUT_COEFFS; - if (scaler->lut_flag & SCALER_LUT_UV_CIR_WR) - lut_type[2] = lut_tbl->cir_lut + - scaler->uv_cir_lut_idx * CIR_LUT_COEFFS; if (scaler->lut_flag & SCALER_LUT_Y_SEP_WR) - lut_type[3] = + lut_type[2] = lut_tbl->sep_lut + scaler->y_rgb_sep_lut_idx * SEP_LUT_COEFFS; + if (scaler->lut_flag & SCALER_LUT_UV_CIR_WR) + lut_type[3] = + lut_tbl->cir_lut + scaler->uv_cir_lut_idx * + CIR_LUT_COEFFS; if (scaler->lut_flag & SCALER_LUT_UV_SEP_WR) lut_type[4] = lut_tbl->sep_lut + scaler->uv_sep_lut_idx * @@ -1622,25 +1628,26 @@ int mdss_mdp_qseed3_setup(struct mdp_scale_data_v2 *scaler, pr_debug("scaler->enable=%d", scaler->enable); - if (scaler->enable) { + + if (fmt->is_yuv) + op_mode |= (1 << SCALER_COLOR_SPACE); + if (fmt->alpha_enable) + op_mode |= SCALER_ALPHA_EN; + if (!fmt->unpack_dx_format) + op_mode |= 0x1 << SCALER_BIT_WIDTH; + + if (scaler->enable & ENABLE_SCALE) { op_mode |= SCALER_EN; op_mode |= (scaler->y_rgb_filter_cfg & 0x3) << Y_FILTER_CFG; - if (fmt->is_yuv) { - op_mode |= (1 << SCALER_COLOR_SPACE); + if (fmt->is_yuv) op_mode |= (scaler->uv_filter_cfg & 0x3) << UV_FILTER_CFG; - } - if (fmt->alpha_enable) { - op_mode |= SCALER_ALPHA_EN; + if (fmt->alpha_enable) op_mode |= (scaler->alpha_filter_cfg & 1) << ALPHA_FILTER_CFG; - } - - if (!fmt->unpack_dx_format) - op_mode |= 0x1 << SCALER_BIT_WIDTH; op_mode |= (scaler->blend_cfg & 1) << SCALER_BLEND_CFG; @@ -1712,9 +1719,9 @@ int mdss_mdp_qseed3_setup(struct mdp_scale_data_v2 *scaler, writel_relaxed(scaler->phase_step_y[1] & PHASE_STEP_BITS, MDSS_MDP_REG_SCALER_PHASE_STEP_UV_V + offset); - writel_relaxed(preload, MDSS_MDP_REG_SCALER_PRELOAD + offset); + writel_relaxed(src_y_rgb, MDSS_MDP_REG_SCALER_SRC_SIZE_Y_RGB_A + offset); @@ -1723,10 +1730,22 @@ int mdss_mdp_qseed3_setup(struct mdp_scale_data_v2 *scaler, writel_relaxed(dst, MDSS_MDP_REG_SCALER_DST_SIZE + offset); + + pr_debug("phase_init %x, step_y_h %x, step_y_v %x, step_uv_h %x, step_uv_v %x\n", + phase_init, + scaler->phase_step_x[0] & PHASE_STEP_BITS, + scaler->phase_step_x[1] & PHASE_STEP_BITS, + scaler->phase_step_y[0] & PHASE_STEP_BITS, + scaler->phase_step_y[1] & PHASE_STEP_BITS); + pr_debug("src_size_y_rgb %x, src_size_uv %x, dst_size %x,\n", + src_y_rgb, + src_uv, + dst); } else { op_mode &= ~SCALER_EN; } + pr_debug("op_mode %x\n", op_mode); writel_relaxed(op_mode, MDSS_MDP_REG_SCALER_OP_MODE + offset); return rc; @@ -3099,8 +3118,8 @@ static int pp_ad_calc_bl(struct msm_fb_data_type *mfd, int bl_in, int *bl_out, mutex_lock(&ad->lock); if (!mfd->ad_bl_level) mfd->ad_bl_level = bl_in; - if (!(ad->state & PP_AD_STATE_RUN)) { - pr_debug("AD is not running.\n"); + if (!(ad->sts & PP_STS_ENABLE)) { + pr_debug("AD is not enabled.\n"); mutex_unlock(&ad->lock); return -EPERM; } @@ -3123,22 +3142,27 @@ static int pp_ad_calc_bl(struct msm_fb_data_type *mfd, int bl_in, int *bl_out, return ret; } - ret = pp_ad_attenuate_bl(ad, temp, &temp); - if (ret) { - pr_err("Failed to attenuate BL: %d\n", ret); - mutex_unlock(&ad->lock); - return ret; - } - ad_bl_out = temp; + if (ad->init.alpha > 0) { + ret = pp_ad_attenuate_bl(ad, temp, &temp); + if (ret) { + pr_err("Failed to attenuate BL: %d\n", ret); + mutex_unlock(&ad->lock); + return ret; + } + ad_bl_out = temp; - ret = pp_ad_linearize_bl(ad, temp, &temp, MDP_PP_AD_BL_LINEAR_INV); - if (ret) { - pr_err("Failed to inverse linearize BL: %d\n", ret); - mutex_unlock(&ad->lock); - return ret; + ret = pp_ad_linearize_bl(ad, temp, &temp, + MDP_PP_AD_BL_LINEAR_INV); + if (ret) { + pr_err("Failed to inverse linearize BL: %d\n", ret); + mutex_unlock(&ad->lock); + return ret; + } + *bl_out = temp; + } else { + ad_bl_out = temp; } - *bl_out = temp; if (pp_ad_bl_threshold_check(ad->init.al_thresh, ad->init.alpha_base, ad->last_bl, ad_bl_out)) { mfd->ad_bl_level = ad_bl_out; @@ -6193,6 +6217,8 @@ static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd) ad->sts &= ~PP_AD_STS_DIRTY_DATA; ad->state |= PP_AD_STATE_DATA; pr_debug("dirty data, last_bl = %d\n", ad->last_bl); + if (!bl_mfd->ad_bl_level) + bl_mfd->ad_bl_level = bl_mfd->bl_level; bl = bl_mfd->ad_bl_level; if (ad->last_bl != bl) { @@ -6280,6 +6306,7 @@ static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd) memset(&ad->cfg, 0, sizeof(struct mdss_ad_cfg)); bl_mfd->ext_bl_ctrl = 0; bl_mfd->ext_ad_ctrl = -1; + bl_mfd->ad_bl_level = 0; } ad->state &= ~PP_AD_STATE_RUN; } @@ -6384,7 +6411,7 @@ static void pp_ad_cfg_lut(char __iomem *addr, u32 *data) } /* must call this function from within ad->lock */ -static int pp_ad_attenuate_bl(struct mdss_ad_info *ad, u32 bl, u32 *bl_out) +static int pp_ad_attenuate_bl(struct mdss_ad_info *ad, u32 bl, u32 *bl_out) { u32 shift = 0, ratio_temp = 0; u32 n, lut_interval, bl_att; @@ -7401,8 +7428,8 @@ static int pp_mfd_ad_release_all(struct msm_fb_data_type *mfd) ad->mfd = NULL; ad->bl_mfd = NULL; ad->state = 0; - cancel_work_sync(&ad->calc_work); mutex_unlock(&ad->lock); + cancel_work_sync(&ad->calc_work); ctl = mfd_to_ctl(mfd); if (ctl && ctl->ops.remove_vsync_handler) diff --git a/drivers/video/fbdev/msm/mdss_panel.c b/drivers/video/fbdev/msm/mdss_panel.c index aab8c9c63451..97025b3a9c23 100644 --- a/drivers/video/fbdev/msm/mdss_panel.c +++ b/drivers/video/fbdev/msm/mdss_panel.c @@ -645,6 +645,7 @@ void mdss_panel_info_from_timing(struct mdss_panel_timing *pt, pinfo->fbc = pt->fbc; pinfo->compression_mode = pt->compression_mode; + pinfo->roi_alignment = pt->roi_alignment; pinfo->te = pt->te; /* override te parameters if panel is in sw te mode */ diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index 1b4d7d8c5f82..7a49f37660dd 100644 --- a/drivers/video/fbdev/msm/mdss_panel.h +++ b/drivers/video/fbdev/msm/mdss_panel.h @@ -580,6 +580,15 @@ struct mdss_mdp_pp_tear_check { u32 refx100; }; +struct mdss_panel_roi_alignment { + u32 xstart_pix_align; + u32 width_pix_align; + u32 ystart_pix_align; + u32 height_pix_align; + u32 min_width; + u32 min_height; +}; + struct mdss_panel_info { u32 xres; u32 yres; @@ -628,15 +637,10 @@ struct mdss_panel_info { int panel_max_fps; int panel_max_vtotal; u32 mode_sel_state; - u32 xstart_pix_align; - u32 width_pix_align; - u32 ystart_pix_align; - u32 height_pix_align; - u32 min_width; - u32 min_height; u32 min_fps; u32 max_fps; u32 prg_fet; + struct mdss_panel_roi_alignment roi_alignment; u32 cont_splash_enabled; bool esd_rdy; @@ -696,6 +700,12 @@ struct mdss_panel_info { u8 dsc_enc_total; /* max 2 */ struct dsc_desc dsc; + /* + * To determine, if DSC panel requires the pps to be sent + * before or after the switch, during dynamic resolution switching + */ + bool send_pps_before_switch; + struct lcd_panel_info lcdc; struct fbc_panel_info fbc; struct mipi_panel_info mipi; @@ -745,6 +755,7 @@ struct mdss_panel_timing { u32 compression_mode; struct mdss_mdp_pp_tear_check te; + struct mdss_panel_roi_alignment roi_alignment; }; struct mdss_panel_data { @@ -771,7 +782,8 @@ struct mdss_panel_data { struct mdss_panel_timing *current_timing; bool active; - struct device_node *cfg_np; /* NULL if config node is not present */ + /* To store dsc cfg name passed by bootloader */ + char dsc_cfg_np_name[MDSS_MAX_PANEL_LEN]; struct mdss_panel_data *next; }; diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 7efc32945810..7d3e5d0e9aa4 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -209,8 +209,8 @@ static unsigned leak_balloon(struct virtio_balloon *vb, size_t num) */ if (vb->num_pfns != 0) tell_host(vb, vb->deflate_vq); - mutex_unlock(&vb->balloon_lock); release_pages_balloon(vb); + mutex_unlock(&vb->balloon_lock); return num_freed_pages; } diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c index 78f804af6c20..2046a68ad0ba 100644 --- a/drivers/virtio/virtio_pci_common.c +++ b/drivers/virtio/virtio_pci_common.c @@ -545,6 +545,7 @@ err_enable_device: static void virtio_pci_remove(struct pci_dev *pci_dev) { struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); + struct device *dev = get_device(&vp_dev->vdev.dev); unregister_virtio_device(&vp_dev->vdev); @@ -554,6 +555,7 @@ static void virtio_pci_remove(struct pci_dev *pci_dev) virtio_pci_modern_remove(vp_dev); pci_disable_device(pci_dev); + put_device(dev); } static struct pci_driver virtio_pci_driver = { diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c index 73dafdc494aa..fb0221434f81 100644 --- a/drivers/xen/xen-pciback/pciback_ops.c +++ b/drivers/xen/xen-pciback/pciback_ops.c @@ -227,8 +227,9 @@ int xen_pcibk_enable_msix(struct xen_pcibk_device *pdev, /* * PCI_COMMAND_MEMORY must be enabled, otherwise we may not be able * to access the BARs where the MSI-X entries reside. + * But VF devices are unique in which the PF needs to be checked. */ - pci_read_config_word(dev, PCI_COMMAND, &cmd); + pci_read_config_word(pci_physfn(dev), PCI_COMMAND, &cmd); if (dev->msi_enabled || !(cmd & PCI_COMMAND_MEMORY)) return -ENXIO; @@ -332,6 +333,9 @@ void xen_pcibk_do_op(struct work_struct *data) struct xen_pcibk_dev_data *dev_data = NULL; struct xen_pci_op *op = &pdev->op; int test_intx = 0; +#ifdef CONFIG_PCI_MSI + unsigned int nr = 0; +#endif *op = pdev->sh_info->op; barrier(); @@ -360,6 +364,7 @@ void xen_pcibk_do_op(struct work_struct *data) op->err = xen_pcibk_disable_msi(pdev, dev, op); break; case XEN_PCI_OP_enable_msix: + nr = op->value; op->err = xen_pcibk_enable_msix(pdev, dev, op); break; case XEN_PCI_OP_disable_msix: @@ -382,7 +387,7 @@ void xen_pcibk_do_op(struct work_struct *data) if (op->cmd == XEN_PCI_OP_enable_msix && op->err == 0) { unsigned int i; - for (i = 0; i < op->value; i++) + for (i = 0; i < nr; i++) pdev->sh_info->op.msix_entries[i].vector = op->msix_entries[i].vector; } diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index ad4eb1024d1f..51387d75c7bf 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c @@ -939,12 +939,12 @@ out: spin_unlock_irqrestore(&info->v2p_lock, flags); out_free: - mutex_lock(&tpg->tv_tpg_mutex); - tpg->tv_tpg_fe_count--; - mutex_unlock(&tpg->tv_tpg_mutex); - - if (err) + if (err) { + mutex_lock(&tpg->tv_tpg_mutex); + tpg->tv_tpg_fe_count--; + mutex_unlock(&tpg->tv_tpg_mutex); kfree(new); + } return err; } diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index 3e36e4adc4a3..9aba42b78253 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c @@ -328,8 +328,8 @@ static inline void __btrfs_queue_work(struct __btrfs_workqueue *wq, list_add_tail(&work->ordered_list, &wq->ordered_list); spin_unlock_irqrestore(&wq->list_lock, flags); } - queue_work(wq->normal_wq, &work->normal_work); trace_btrfs_work_queued(work); + queue_work(wq->normal_wq, &work->normal_work); } void btrfs_queue_work(struct btrfs_workqueue *wq, diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 35489e7129a7..385b449fd7ed 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1572,7 +1572,7 @@ struct btrfs_fs_info { spinlock_t delayed_iput_lock; struct list_head delayed_iputs; - struct rw_semaphore delayed_iput_sem; + struct mutex cleaner_delayed_iput_mutex; /* this protects tree_mod_seq_list */ spinlock_t tree_mod_seq_lock; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 0ddca6734494..41fb43183406 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1582,8 +1582,23 @@ int btrfs_init_fs_root(struct btrfs_root *root) ret = get_anon_bdev(&root->anon_dev); if (ret) goto free_writers; + + mutex_lock(&root->objectid_mutex); + ret = btrfs_find_highest_objectid(root, + &root->highest_objectid); + if (ret) { + mutex_unlock(&root->objectid_mutex); + goto free_root_dev; + } + + ASSERT(root->highest_objectid <= BTRFS_LAST_FREE_OBJECTID); + + mutex_unlock(&root->objectid_mutex); + return 0; +free_root_dev: + free_anon_bdev(root->anon_dev); free_writers: btrfs_free_subvolume_writers(root->subv_writers); fail: @@ -1781,7 +1796,10 @@ static int cleaner_kthread(void *arg) goto sleep; } + mutex_lock(&root->fs_info->cleaner_delayed_iput_mutex); btrfs_run_delayed_iputs(root); + mutex_unlock(&root->fs_info->cleaner_delayed_iput_mutex); + again = btrfs_clean_one_deleted_snapshot(root); mutex_unlock(&root->fs_info->cleaner_mutex); @@ -2541,8 +2559,8 @@ int open_ctree(struct super_block *sb, mutex_init(&fs_info->delete_unused_bgs_mutex); mutex_init(&fs_info->reloc_mutex); mutex_init(&fs_info->delalloc_root_mutex); + mutex_init(&fs_info->cleaner_delayed_iput_mutex); seqlock_init(&fs_info->profiles_lock); - init_rwsem(&fs_info->delayed_iput_sem); INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots); INIT_LIST_HEAD(&fs_info->space_info); @@ -2667,6 +2685,7 @@ int open_ctree(struct super_block *sb, if (btrfs_check_super_csum(bh->b_data)) { printk(KERN_ERR "BTRFS: superblock checksum mismatch\n"); err = -EINVAL; + brelse(bh); goto fail_alloc; } @@ -2899,6 +2918,18 @@ retry_root_backup: tree_root->commit_root = btrfs_root_node(tree_root); btrfs_set_root_refs(&tree_root->root_item, 1); + mutex_lock(&tree_root->objectid_mutex); + ret = btrfs_find_highest_objectid(tree_root, + &tree_root->highest_objectid); + if (ret) { + mutex_unlock(&tree_root->objectid_mutex); + goto recovery_tree_root; + } + + ASSERT(tree_root->highest_objectid <= BTRFS_LAST_FREE_OBJECTID); + + mutex_unlock(&tree_root->objectid_mutex); + ret = btrfs_read_roots(fs_info, tree_root); if (ret) goto recovery_tree_root; diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index c4661db2b72a..2368cac1115a 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -4086,8 +4086,10 @@ commit_trans: !atomic_read(&root->fs_info->open_ioctl_trans)) { need_commit--; - if (need_commit > 0) + if (need_commit > 0) { + btrfs_start_delalloc_roots(fs_info, 0, -1); btrfs_wait_ordered_roots(fs_info, -1); + } trans = btrfs_join_transaction(root); if (IS_ERR(trans)) @@ -4100,11 +4102,12 @@ commit_trans: if (ret) return ret; /* - * make sure that all running delayed iput are - * done + * The cleaner kthread might still be doing iput + * operations. Wait for it to finish so that + * more space is released. */ - down_write(&root->fs_info->delayed_iput_sem); - up_write(&root->fs_info->delayed_iput_sem); + mutex_lock(&root->fs_info->cleaner_delayed_iput_mutex); + mutex_unlock(&root->fs_info->cleaner_delayed_iput_mutex); goto again; } else { btrfs_end_transaction(trans, root); diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c index 767a6056ac45..07573dc1614a 100644 --- a/fs/btrfs/inode-map.c +++ b/fs/btrfs/inode-map.c @@ -515,7 +515,7 @@ out: return ret; } -static int btrfs_find_highest_objectid(struct btrfs_root *root, u64 *objectid) +int btrfs_find_highest_objectid(struct btrfs_root *root, u64 *objectid) { struct btrfs_path *path; int ret; @@ -555,13 +555,6 @@ int btrfs_find_free_objectid(struct btrfs_root *root, u64 *objectid) int ret; mutex_lock(&root->objectid_mutex); - if (unlikely(root->highest_objectid < BTRFS_FIRST_FREE_OBJECTID)) { - ret = btrfs_find_highest_objectid(root, - &root->highest_objectid); - if (ret) - goto out; - } - if (unlikely(root->highest_objectid >= BTRFS_LAST_FREE_OBJECTID)) { ret = -ENOSPC; goto out; diff --git a/fs/btrfs/inode-map.h b/fs/btrfs/inode-map.h index ddb347bfee23..c8e864b2d530 100644 --- a/fs/btrfs/inode-map.h +++ b/fs/btrfs/inode-map.h @@ -9,5 +9,6 @@ int btrfs_save_ino_cache(struct btrfs_root *root, struct btrfs_trans_handle *trans); int btrfs_find_free_objectid(struct btrfs_root *root, u64 *objectid); +int btrfs_find_highest_objectid(struct btrfs_root *root, u64 *objectid); #endif diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 54b5f0de623b..4bc9dbf29a73 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3142,8 +3142,6 @@ void btrfs_run_delayed_iputs(struct btrfs_root *root) if (empty) return; - down_read(&fs_info->delayed_iput_sem); - spin_lock(&fs_info->delayed_iput_lock); list_splice_init(&fs_info->delayed_iputs, &list); spin_unlock(&fs_info->delayed_iput_lock); @@ -3154,8 +3152,6 @@ void btrfs_run_delayed_iputs(struct btrfs_root *root) iput(delayed->inode); kfree(delayed); } - - up_read(&root->fs_info->delayed_iput_sem); } /* @@ -6493,7 +6489,7 @@ out_unlock_inode: static int btrfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { - struct btrfs_trans_handle *trans; + struct btrfs_trans_handle *trans = NULL; struct btrfs_root *root = BTRFS_I(dir)->root; struct inode *inode = d_inode(old_dentry); u64 index; @@ -6519,6 +6515,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, trans = btrfs_start_transaction(root, 5); if (IS_ERR(trans)) { err = PTR_ERR(trans); + trans = NULL; goto fail; } @@ -6552,9 +6549,10 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, btrfs_log_new_name(trans, inode, NULL, parent); } - btrfs_end_transaction(trans, root); btrfs_balance_delayed_items(root); fail: + if (trans) + btrfs_end_transaction(trans, root); if (drop_inode) { inode_dec_link_count(inode); iput(inode); @@ -8548,15 +8546,28 @@ int btrfs_readpage(struct file *file, struct page *page) static int btrfs_writepage(struct page *page, struct writeback_control *wbc) { struct extent_io_tree *tree; - + struct inode *inode = page->mapping->host; + int ret; if (current->flags & PF_MEMALLOC) { redirty_page_for_writepage(wbc, page); unlock_page(page); return 0; } + + /* + * If we are under memory pressure we will call this directly from the + * VM, we need to make sure we have the inode referenced for the ordered + * extent. If not just return like we didn't do anything. + */ + if (!igrab(inode)) { + redirty_page_for_writepage(wbc, page); + return AOP_WRITEPAGE_ACTIVATE; + } tree = &BTRFS_I(page->mapping->host)->io_tree; - return extent_write_full_page(tree, page, btrfs_get_extent, wbc); + ret = extent_write_full_page(tree, page, btrfs_get_extent, wbc); + btrfs_add_delayed_iput(inode); + return ret; } static int btrfs_writepages(struct address_space *mapping, @@ -9650,9 +9661,11 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, /* * 2 items for inode item and ref * 2 items for dir items + * 1 item for updating parent inode item + * 1 item for the inline extent item * 1 item for xattr if selinux is on */ - trans = btrfs_start_transaction(root, 5); + trans = btrfs_start_transaction(root, 7); if (IS_ERR(trans)) return PTR_ERR(trans); diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 08fd3f0f34fd..f07d01bc4875 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -568,6 +568,10 @@ static noinline int create_subvol(struct inode *dir, goto fail; } + mutex_lock(&new_root->objectid_mutex); + new_root->highest_objectid = new_dirid; + mutex_unlock(&new_root->objectid_mutex); + /* * insert the directory item */ diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index 7cf8509deda7..2c849b08a91b 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c @@ -310,8 +310,16 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root) set_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED, &root->state); err = btrfs_insert_fs_root(root->fs_info, root); + /* + * The root might have been inserted already, as before we look + * for orphan roots, log replay might have happened, which + * triggers a transaction commit and qgroup accounting, which + * in turn reads and inserts fs roots while doing backref + * walking. + */ + if (err == -EEXIST) + err = 0; if (err) { - BUG_ON(err == -EEXIST); btrfs_free_fs_root(root); break; } diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 355a458cba1a..63a6152be04b 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -1469,7 +1469,21 @@ static int read_symlink(struct btrfs_root *root, ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) goto out; - BUG_ON(ret); + if (ret) { + /* + * An empty symlink inode. Can happen in rare error paths when + * creating a symlink (transaction committed before the inode + * eviction handler removed the symlink inode items and a crash + * happened in between or the subvol was snapshoted in between). + * Print an informative message to dmesg/syslog so that the user + * can delete the symlink. + */ + btrfs_err(root->fs_info, + "Found empty symlink inode %llu at root %llu", + ino, root->root_key.objectid); + ret = -EIO; + goto out; + } ei = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_file_extent_item); diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 24154e422945..fe609b81dd1b 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1956,6 +1956,8 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes) * there are other factors that may change the result (like a new metadata * chunk). * + * If metadata is exhausted, f_bavail will be 0. + * * FIXME: not accurate for mixed block groups, total and free/used are ok, * available appears slightly larger. */ @@ -1967,11 +1969,13 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) struct btrfs_space_info *found; u64 total_used = 0; u64 total_free_data = 0; + u64 total_free_meta = 0; int bits = dentry->d_sb->s_blocksize_bits; __be32 *fsid = (__be32 *)fs_info->fsid; unsigned factor = 1; struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv; int ret; + u64 thresh = 0; /* * holding chunk_muext to avoid allocating new chunks, holding @@ -1997,6 +2001,8 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) } } } + if (found->flags & BTRFS_BLOCK_GROUP_METADATA) + total_free_meta += found->disk_total - found->disk_used; total_used += found->disk_used; } @@ -2019,6 +2025,24 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_bavail += div_u64(total_free_data, factor); buf->f_bavail = buf->f_bavail >> bits; + /* + * We calculate the remaining metadata space minus global reserve. If + * this is (supposedly) smaller than zero, there's no space. But this + * does not hold in practice, the exhausted state happens where's still + * some positive delta. So we apply some guesswork and compare the + * delta to a 4M threshold. (Practically observed delta was ~2M.) + * + * We probably cannot calculate the exact threshold value because this + * depends on the internal reservations requested by various + * operations, so some operations that consume a few metadata will + * succeed even if the Avail is zero. But this is better than the other + * way around. + */ + thresh = 4 * 1024 * 1024; + + if (total_free_meta - thresh < block_rsv->size) + buf->f_bavail = 0; + buf->f_type = BTRFS_SUPER_MAGIC; buf->f_bsize = dentry->d_sb->s_blocksize; buf->f_namelen = BTRFS_NAME_LEN; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 9e084477d320..9c62a6f9757a 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -232,6 +232,7 @@ static struct btrfs_device *__alloc_device(void) spin_lock_init(&dev->reada_lock); atomic_set(&dev->reada_in_flight, 0); atomic_set(&dev->dev_stats_ccnt, 0); + btrfs_device_data_ordered_init(dev); INIT_RADIX_TREE(&dev->reada_zones, GFP_NOFS & ~__GFP_DIRECT_RECLAIM); INIT_RADIX_TREE(&dev->reada_extents, GFP_NOFS & ~__GFP_DIRECT_RECLAIM); diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index c3cc1609025f..44b3d4280abb 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -31,19 +31,15 @@ * so that it will fit. We use hash_64 to convert the value to 31 bits, and * then add 1, to ensure that we don't end up with a 0 as the value. */ -#if BITS_PER_LONG == 64 static inline ino_t cifs_uniqueid_to_ino_t(u64 fileid) { + if ((sizeof(ino_t)) < (sizeof(u64))) + return (ino_t)hash_64(fileid, (sizeof(ino_t) * 8) - 1) + 1; + return (ino_t)fileid; + } -#else -static inline ino_t -cifs_uniqueid_to_ino_t(u64 fileid) -{ - return (ino_t)hash_64(fileid, (sizeof(ino_t) * 8) - 1) + 1; -} -#endif extern struct file_system_type cifs_fs_type; extern const struct address_space_operations cifs_addr_ops; diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 90b4f9f7de66..76fcb50295a3 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1396,11 +1396,10 @@ openRetry: * current bigbuf. */ static int -cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) +discard_remaining_data(struct TCP_Server_Info *server) { unsigned int rfclen = get_rfc1002_length(server->smallbuf); int remaining = rfclen + 4 - server->total_read; - struct cifs_readdata *rdata = mid->callback_data; while (remaining > 0) { int length; @@ -1414,10 +1413,20 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) remaining -= length; } - dequeue_mid(mid, rdata->result); return 0; } +static int +cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) +{ + int length; + struct cifs_readdata *rdata = mid->callback_data; + + length = discard_remaining_data(server); + dequeue_mid(mid, rdata->result); + return length; +} + int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) { @@ -1446,6 +1455,12 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) return length; server->total_read += length; + if (server->ops->is_status_pending && + server->ops->is_status_pending(buf, server, 0)) { + discard_remaining_data(server); + return -1; + } + /* Was the SMB read successful? */ rdata->result = server->ops->map_error(buf, false); if (rdata->result != 0) { diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 767555518d40..373b5cd1c913 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -1109,21 +1109,25 @@ parse_lease_state(struct TCP_Server_Info *server, struct smb2_create_rsp *rsp, { char *data_offset; struct create_context *cc; - unsigned int next = 0; + unsigned int next; + unsigned int remaining; char *name; data_offset = (char *)rsp + 4 + le32_to_cpu(rsp->CreateContextsOffset); + remaining = le32_to_cpu(rsp->CreateContextsLength); cc = (struct create_context *)data_offset; - do { - cc = (struct create_context *)((char *)cc + next); + while (remaining >= sizeof(struct create_context)) { name = le16_to_cpu(cc->NameOffset) + (char *)cc; - if (le16_to_cpu(cc->NameLength) != 4 || - strncmp(name, "RqLs", 4)) { - next = le32_to_cpu(cc->Next); - continue; - } - return server->ops->parse_lease_buf(cc, epoch); - } while (next != 0); + if (le16_to_cpu(cc->NameLength) == 4 && + strncmp(name, "RqLs", 4) == 0) + return server->ops->parse_lease_buf(cc, epoch); + + next = le32_to_cpu(cc->Next); + if (!next) + break; + remaining -= next; + cc = (struct create_context *)((char *)cc + next); + } return 0; } diff --git a/fs/dcache.c b/fs/dcache.c index 5c33aeb0f68f..877bcbbd03ff 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -269,9 +269,6 @@ static inline int dname_external(const struct dentry *dentry) return dentry->d_name.name != dentry->d_iname; } -/* - * Make sure other CPUs see the inode attached before the type is set. - */ static inline void __d_set_inode_and_type(struct dentry *dentry, struct inode *inode, unsigned type_flags) @@ -279,28 +276,18 @@ static inline void __d_set_inode_and_type(struct dentry *dentry, unsigned flags; dentry->d_inode = inode; - smp_wmb(); flags = READ_ONCE(dentry->d_flags); flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU); flags |= type_flags; WRITE_ONCE(dentry->d_flags, flags); } -/* - * Ideally, we want to make sure that other CPUs see the flags cleared before - * the inode is detached, but this is really a violation of RCU principles - * since the ordering suggests we should always set inode before flags. - * - * We should instead replace or discard the entire dentry - but that sucks - * performancewise on mass deletion/rename. - */ static inline void __d_clear_type_and_inode(struct dentry *dentry) { unsigned flags = READ_ONCE(dentry->d_flags); flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU); WRITE_ONCE(dentry->d_flags, flags); - smp_wmb(); dentry->d_inode = NULL; } @@ -370,9 +357,11 @@ static void dentry_unlink_inode(struct dentry * dentry) __releases(dentry->d_inode->i_lock) { struct inode *inode = dentry->d_inode; + + raw_write_seqcount_begin(&dentry->d_seq); __d_clear_type_and_inode(dentry); hlist_del_init(&dentry->d_u.d_alias); - dentry_rcuwalk_invalidate(dentry); + raw_write_seqcount_end(&dentry->d_seq); spin_unlock(&dentry->d_lock); spin_unlock(&inode->i_lock); if (!inode->i_nlink) @@ -1757,8 +1746,9 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode) spin_lock(&dentry->d_lock); if (inode) hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry); + raw_write_seqcount_begin(&dentry->d_seq); __d_set_inode_and_type(dentry, inode, add_flags); - dentry_rcuwalk_invalidate(dentry); + raw_write_seqcount_end(&dentry->d_seq); spin_unlock(&dentry->d_lock); fsnotify_d_instantiate(dentry, inode); } diff --git a/fs/direct-io.c b/fs/direct-io.c index cfcf7db05812..0f1517d0b969 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -486,8 +486,8 @@ static int dio_bio_complete(struct dio *dio, struct bio *bio) dio->io_error = -EIO; if (dio->is_async && dio->rw == READ && dio->should_dirty) { - bio_check_pages_dirty(bio); /* transfers ownership */ err = bio->bi_error; + bio_check_pages_dirty(bio); /* transfers ownership */ } else { bio_for_each_segment_all(bvec, bio, i) { struct page *page = bvec->bv_page; diff --git a/fs/efivarfs/file.c b/fs/efivarfs/file.c index 90001da9abfd..66842e55c48c 100644 --- a/fs/efivarfs/file.c +++ b/fs/efivarfs/file.c @@ -10,6 +10,7 @@ #include <linux/efi.h> #include <linux/fs.h> #include <linux/slab.h> +#include <linux/mount.h> #include "internal.h" @@ -103,9 +104,78 @@ out_free: return size; } +static int +efivarfs_ioc_getxflags(struct file *file, void __user *arg) +{ + struct inode *inode = file->f_mapping->host; + unsigned int i_flags; + unsigned int flags = 0; + + i_flags = inode->i_flags; + if (i_flags & S_IMMUTABLE) + flags |= FS_IMMUTABLE_FL; + + if (copy_to_user(arg, &flags, sizeof(flags))) + return -EFAULT; + return 0; +} + +static int +efivarfs_ioc_setxflags(struct file *file, void __user *arg) +{ + struct inode *inode = file->f_mapping->host; + unsigned int flags; + unsigned int i_flags = 0; + int error; + + if (!inode_owner_or_capable(inode)) + return -EACCES; + + if (copy_from_user(&flags, arg, sizeof(flags))) + return -EFAULT; + + if (flags & ~FS_IMMUTABLE_FL) + return -EOPNOTSUPP; + + if (!capable(CAP_LINUX_IMMUTABLE)) + return -EPERM; + + if (flags & FS_IMMUTABLE_FL) + i_flags |= S_IMMUTABLE; + + + error = mnt_want_write_file(file); + if (error) + return error; + + mutex_lock(&inode->i_mutex); + inode_set_flags(inode, i_flags, S_IMMUTABLE); + mutex_unlock(&inode->i_mutex); + + mnt_drop_write_file(file); + + return 0; +} + +long +efivarfs_file_ioctl(struct file *file, unsigned int cmd, unsigned long p) +{ + void __user *arg = (void __user *)p; + + switch (cmd) { + case FS_IOC_GETFLAGS: + return efivarfs_ioc_getxflags(file, arg); + case FS_IOC_SETFLAGS: + return efivarfs_ioc_setxflags(file, arg); + } + + return -ENOTTY; +} + const struct file_operations efivarfs_file_operations = { .open = simple_open, .read = efivarfs_file_read, .write = efivarfs_file_write, .llseek = no_llseek, + .unlocked_ioctl = efivarfs_file_ioctl, }; diff --git a/fs/efivarfs/inode.c b/fs/efivarfs/inode.c index 3381b9da9ee6..e2ab6d0497f2 100644 --- a/fs/efivarfs/inode.c +++ b/fs/efivarfs/inode.c @@ -15,7 +15,8 @@ #include "internal.h" struct inode *efivarfs_get_inode(struct super_block *sb, - const struct inode *dir, int mode, dev_t dev) + const struct inode *dir, int mode, + dev_t dev, bool is_removable) { struct inode *inode = new_inode(sb); @@ -23,6 +24,7 @@ struct inode *efivarfs_get_inode(struct super_block *sb, inode->i_ino = get_next_ino(); inode->i_mode = mode; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_flags = is_removable ? 0 : S_IMMUTABLE; switch (mode & S_IFMT) { case S_IFREG: inode->i_fop = &efivarfs_file_operations; @@ -102,22 +104,17 @@ static void efivarfs_hex_to_guid(const char *str, efi_guid_t *guid) static int efivarfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) { - struct inode *inode; + struct inode *inode = NULL; struct efivar_entry *var; int namelen, i = 0, err = 0; + bool is_removable = false; if (!efivarfs_valid_name(dentry->d_name.name, dentry->d_name.len)) return -EINVAL; - inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0); - if (!inode) - return -ENOMEM; - var = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL); - if (!var) { - err = -ENOMEM; - goto out; - } + if (!var) + return -ENOMEM; /* length of the variable name itself: remove GUID and separator */ namelen = dentry->d_name.len - EFI_VARIABLE_GUID_LEN - 1; @@ -125,6 +122,16 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry, efivarfs_hex_to_guid(dentry->d_name.name + namelen + 1, &var->var.VendorGuid); + if (efivar_variable_is_removable(var->var.VendorGuid, + dentry->d_name.name, namelen)) + is_removable = true; + + inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0, is_removable); + if (!inode) { + err = -ENOMEM; + goto out; + } + for (i = 0; i < namelen; i++) var->var.VariableName[i] = dentry->d_name.name[i]; @@ -138,7 +145,8 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry, out: if (err) { kfree(var); - iput(inode); + if (inode) + iput(inode); } return err; } diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h index b5ff16addb7c..b4505188e799 100644 --- a/fs/efivarfs/internal.h +++ b/fs/efivarfs/internal.h @@ -15,7 +15,8 @@ extern const struct file_operations efivarfs_file_operations; extern const struct inode_operations efivarfs_dir_inode_operations; extern bool efivarfs_valid_name(const char *str, int len); extern struct inode *efivarfs_get_inode(struct super_block *sb, - const struct inode *dir, int mode, dev_t dev); + const struct inode *dir, int mode, dev_t dev, + bool is_removable); extern struct list_head efivarfs_list; diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index 86a2121828c3..abb244b06024 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -118,8 +118,9 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, struct dentry *dentry, *root = sb->s_root; unsigned long size = 0; char *name; - int len, i; + int len; int err = -ENOMEM; + bool is_removable = false; entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) @@ -128,15 +129,17 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, memcpy(entry->var.VariableName, name16, name_size); memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); - len = ucs2_strlen(entry->var.VariableName); + len = ucs2_utf8size(entry->var.VariableName); /* name, plus '-', plus GUID, plus NUL*/ name = kmalloc(len + 1 + EFI_VARIABLE_GUID_LEN + 1, GFP_KERNEL); if (!name) goto fail; - for (i = 0; i < len; i++) - name[i] = entry->var.VariableName[i] & 0xFF; + ucs2_as_utf8(name, entry->var.VariableName, len); + + if (efivar_variable_is_removable(entry->var.VendorGuid, name, len)) + is_removable = true; name[len] = '-'; @@ -144,7 +147,8 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, name[len + EFI_VARIABLE_GUID_LEN+1] = '\0'; - inode = efivarfs_get_inode(sb, d_inode(root), S_IFREG | 0644, 0); + inode = efivarfs_get_inode(sb, d_inode(root), S_IFREG | 0644, 0, + is_removable); if (!inode) goto fail_name; @@ -200,7 +204,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_d_op = &efivarfs_d_ops; sb->s_time_gran = 1; - inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0); + inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0, true); if (!inode) return -ENOMEM; inode->i_op = &efivarfs_dir_inode_operations; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index ea433a7f4bca..06bda0361e7c 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -657,6 +657,34 @@ has_zeroout: return retval; } +/* + * Update EXT4_MAP_FLAGS in bh->b_state. For buffer heads attached to pages + * we have to be careful as someone else may be manipulating b_state as well. + */ +static void ext4_update_bh_state(struct buffer_head *bh, unsigned long flags) +{ + unsigned long old_state; + unsigned long new_state; + + flags &= EXT4_MAP_FLAGS; + + /* Dummy buffer_head? Set non-atomically. */ + if (!bh->b_page) { + bh->b_state = (bh->b_state & ~EXT4_MAP_FLAGS) | flags; + return; + } + /* + * Someone else may be modifying b_state. Be careful! This is ugly but + * once we get rid of using bh as a container for mapping information + * to pass to / from get_block functions, this can go away. + */ + do { + old_state = READ_ONCE(bh->b_state); + new_state = (old_state & ~EXT4_MAP_FLAGS) | flags; + } while (unlikely( + cmpxchg(&bh->b_state, old_state, new_state) != old_state)); +} + /* Maximum number of blocks we map for direct IO at once. */ #define DIO_MAX_BLOCKS 4096 @@ -693,7 +721,7 @@ static int _ext4_get_block(struct inode *inode, sector_t iblock, ext4_io_end_t *io_end = ext4_inode_aio(inode); map_bh(bh, inode->i_sb, map.m_pblk); - bh->b_state = (bh->b_state & ~EXT4_MAP_FLAGS) | map.m_flags; + ext4_update_bh_state(bh, map.m_flags); if (IS_DAX(inode) && buffer_unwritten(bh)) { /* * dgc: I suspect unwritten conversion on ext4+DAX is @@ -1669,7 +1697,7 @@ int ext4_da_get_block_prep(struct inode *inode, sector_t iblock, return ret; map_bh(bh, inode->i_sb, map.m_pblk); - bh->b_state = (bh->b_state & ~EXT4_MAP_FLAGS) | map.m_flags; + ext4_update_bh_state(bh, map.m_flags); if (buffer_unwritten(bh)) { /* A delayed write to unwritten bh should be marked diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 28cd6508f4aa..bf8c78920bee 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -223,6 +223,9 @@ static void wb_wait_for_completion(struct backing_dev_info *bdi, #define WB_FRN_HIST_MAX_SLOTS (WB_FRN_HIST_THR_SLOTS / 2 + 1) /* one round can affect upto 5 slots */ +static atomic_t isw_nr_in_flight = ATOMIC_INIT(0); +static struct workqueue_struct *isw_wq; + void __inode_attach_wb(struct inode *inode, struct page *page) { struct backing_dev_info *bdi = inode_to_bdi(inode); @@ -424,6 +427,8 @@ skip_switch: iput(inode); kfree(isw); + + atomic_dec(&isw_nr_in_flight); } static void inode_switch_wbs_rcu_fn(struct rcu_head *rcu_head) @@ -433,7 +438,7 @@ static void inode_switch_wbs_rcu_fn(struct rcu_head *rcu_head) /* needs to grab bh-unsafe locks, bounce to work item */ INIT_WORK(&isw->work, inode_switch_wbs_work_fn); - schedule_work(&isw->work); + queue_work(isw_wq, &isw->work); } /** @@ -469,7 +474,8 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id) /* while holding I_WB_SWITCH, no one else can update the association */ spin_lock(&inode->i_lock); - if (inode->i_state & (I_WB_SWITCH | I_FREEING) || + if (!(inode->i_sb->s_flags & MS_ACTIVE) || + inode->i_state & (I_WB_SWITCH | I_FREEING) || inode_to_wb(inode) == isw->new_wb) { spin_unlock(&inode->i_lock); goto out_free; @@ -480,6 +486,8 @@ static void inode_switch_wbs(struct inode *inode, int new_wb_id) ihold(inode); isw->inode = inode; + atomic_inc(&isw_nr_in_flight); + /* * In addition to synchronizing among switchers, I_WB_SWITCH tells * the RCU protected stat update paths to grab the mapping's @@ -842,6 +850,33 @@ restart: wb_put(last_wb); } +/** + * cgroup_writeback_umount - flush inode wb switches for umount + * + * This function is called when a super_block is about to be destroyed and + * flushes in-flight inode wb switches. An inode wb switch goes through + * RCU and then workqueue, so the two need to be flushed in order to ensure + * that all previously scheduled switches are finished. As wb switches are + * rare occurrences and synchronize_rcu() can take a while, perform + * flushing iff wb switches are in flight. + */ +void cgroup_writeback_umount(void) +{ + if (atomic_read(&isw_nr_in_flight)) { + synchronize_rcu(); + flush_workqueue(isw_wq); + } +} + +static int __init cgroup_writeback_init(void) +{ + isw_wq = alloc_workqueue("inode_switch_wbs", 0, 0); + if (!isw_wq) + return -ENOMEM; + return 0; +} +fs_initcall(cgroup_writeback_init); + #else /* CONFIG_CGROUP_WRITEBACK */ static struct bdi_writeback * diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 2ac99db3750e..5a7b3229b956 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -730,15 +730,13 @@ static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, init_special_inode(inode, mode, dev); err = do_mknod(name, mode, MAJOR(dev), MINOR(dev)); - if (!err) + if (err) goto out_free; err = read_name(inode, name); __putname(name); if (err) goto out_put; - if (err) - goto out_put; d_instantiate(dentry, inode); return 0; diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index ae4d5a1fa4c9..bffb908acbd4 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c @@ -375,12 +375,11 @@ static int hpfs_unlink(struct inode *dir, struct dentry *dentry) struct inode *inode = d_inode(dentry); dnode_secno dno; int r; - int rep = 0; int err; hpfs_lock(dir->i_sb); hpfs_adjust_length(name, &len); -again: + err = -ENOENT; de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh); if (!de) @@ -400,33 +399,9 @@ again: hpfs_error(dir->i_sb, "there was error when removing dirent"); err = -EFSERROR; break; - case 2: /* no space for deleting, try to truncate file */ - + case 2: /* no space for deleting */ err = -ENOSPC; - if (rep++) - break; - - dentry_unhash(dentry); - if (!d_unhashed(dentry)) { - hpfs_unlock(dir->i_sb); - return -ENOSPC; - } - if (generic_permission(inode, MAY_WRITE) || - !S_ISREG(inode->i_mode) || - get_write_access(inode)) { - d_rehash(dentry); - } else { - struct iattr newattrs; - /*pr_info("truncating file before delete.\n");*/ - newattrs.ia_size = 0; - newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; - err = notify_change(dentry, &newattrs, NULL); - put_write_access(inode); - if (!err) - goto again; - } - hpfs_unlock(dir->i_sb); - return -ENOSPC; + break; default: drop_nlink(inode); err = 0; diff --git a/fs/jffs2/README.Locking b/fs/jffs2/README.Locking index 3ea36554107f..8918ac905a3b 100644 --- a/fs/jffs2/README.Locking +++ b/fs/jffs2/README.Locking @@ -2,10 +2,6 @@ JFFS2 LOCKING DOCUMENTATION --------------------------- -At least theoretically, JFFS2 does not require the Big Kernel Lock -(BKL), which was always helpfully obtained for it by Linux 2.4 VFS -code. It has its own locking, as described below. - This document attempts to describe the existing locking rules for JFFS2. It is not expected to remain perfectly up to date, but ought to be fairly close. @@ -69,6 +65,7 @@ Ordering constraints: any f->sem held. 2. Never attempt to lock two file mutexes in one thread. No ordering rules have been made for doing so. + 3. Never lock a page cache page with f->sem held. erase_completion_lock spinlock diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index a3750f902adc..c1f04947d7dc 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c @@ -49,7 +49,8 @@ next_inode(int *i, struct jffs2_inode_cache *ic, struct jffs2_sb_info *c) static void jffs2_build_inode_pass1(struct jffs2_sb_info *c, - struct jffs2_inode_cache *ic) + struct jffs2_inode_cache *ic, + int *dir_hardlinks) { struct jffs2_full_dirent *fd; @@ -68,19 +69,21 @@ static void jffs2_build_inode_pass1(struct jffs2_sb_info *c, dbg_fsbuild("child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n", fd->name, fd->ino, ic->ino); jffs2_mark_node_obsolete(c, fd->raw); + /* Clear the ic/raw union so it doesn't cause problems later. */ + fd->ic = NULL; continue; } + /* From this point, fd->raw is no longer used so we can set fd->ic */ + fd->ic = child_ic; + child_ic->pino_nlink++; + /* If we appear (at this stage) to have hard-linked directories, + * set a flag to trigger a scan later */ if (fd->type == DT_DIR) { - if (child_ic->pino_nlink) { - JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", - fd->name, fd->ino, ic->ino); - /* TODO: What do we do about it? */ - } else { - child_ic->pino_nlink = ic->ino; - } - } else - child_ic->pino_nlink++; + child_ic->flags |= INO_FLAGS_IS_DIR; + if (child_ic->pino_nlink > 1) + *dir_hardlinks = 1; + } dbg_fsbuild("increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino); /* Can't free scan_dents so far. We might need them in pass 2 */ @@ -94,8 +97,7 @@ static void jffs2_build_inode_pass1(struct jffs2_sb_info *c, */ static int jffs2_build_filesystem(struct jffs2_sb_info *c) { - int ret; - int i; + int ret, i, dir_hardlinks = 0; struct jffs2_inode_cache *ic; struct jffs2_full_dirent *fd; struct jffs2_full_dirent *dead_fds = NULL; @@ -119,7 +121,7 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) /* Now scan the directory tree, increasing nlink according to every dirent found. */ for_each_inode(i, c, ic) { if (ic->scan_dents) { - jffs2_build_inode_pass1(c, ic); + jffs2_build_inode_pass1(c, ic, &dir_hardlinks); cond_resched(); } } @@ -155,6 +157,20 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) } dbg_fsbuild("pass 2a complete\n"); + + if (dir_hardlinks) { + /* If we detected directory hardlinks earlier, *hopefully* + * they are gone now because some of the links were from + * dead directories which still had some old dirents lying + * around and not yet garbage-collected, but which have + * been discarded above. So clear the pino_nlink field + * in each directory, so that the final scan below can + * print appropriate warnings. */ + for_each_inode(i, c, ic) { + if (ic->flags & INO_FLAGS_IS_DIR) + ic->pino_nlink = 0; + } + } dbg_fsbuild("freeing temporary data structures\n"); /* Finally, we can scan again and free the dirent structs */ @@ -162,6 +178,33 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) while(ic->scan_dents) { fd = ic->scan_dents; ic->scan_dents = fd->next; + /* We do use the pino_nlink field to count nlink of + * directories during fs build, so set it to the + * parent ino# now. Now that there's hopefully only + * one. */ + if (fd->type == DT_DIR) { + if (!fd->ic) { + /* We'll have complained about it and marked the coresponding + raw node obsolete already. Just skip it. */ + continue; + } + + /* We *have* to have set this in jffs2_build_inode_pass1() */ + BUG_ON(!(fd->ic->flags & INO_FLAGS_IS_DIR)); + + /* We clear ic->pino_nlink ∀ directories' ic *only* if dir_hardlinks + * is set. Otherwise, we know this should never trigger anyway, so + * we don't do the check. And ic->pino_nlink still contains the nlink + * value (which is 1). */ + if (dir_hardlinks && fd->ic->pino_nlink) { + JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u is also hard linked from dir ino #%u\n", + fd->name, fd->ino, ic->ino, fd->ic->pino_nlink); + /* Should we unlink it from its previous parent? */ + } + + /* For directories, ic->pino_nlink holds that parent inode # */ + fd->ic->pino_nlink = ic->ino; + } jffs2_free_full_dirent(fd); } ic->scan_dents = NULL; @@ -240,11 +283,7 @@ static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, /* Reduce nlink of the child. If it's now zero, stick it on the dead_fds list to be cleaned up later. Else just free the fd */ - - if (fd->type == DT_DIR) - child_ic->pino_nlink = 0; - else - child_ic->pino_nlink--; + child_ic->pino_nlink--; if (!child_ic->pino_nlink) { dbg_fsbuild("inode #%u (\"%s\") now has no links; adding to dead_fds list.\n", diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index d211b8e18566..30c4c9ebb693 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -843,9 +843,14 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, pr_notice("%s(): Link succeeded, unlink failed (err %d). You now have a hard link\n", __func__, ret); - /* Might as well let the VFS know */ - d_instantiate(new_dentry, d_inode(old_dentry)); - ihold(d_inode(old_dentry)); + /* + * We can't keep the target in dcache after that. + * For one thing, we can't afford dentry aliases for directories. + * For another, if there was a victim, we _can't_ set new inode + * for that sucker and we have to trigger mount eviction - the + * caller won't do it on its own since we are returning an error. + */ + d_invalidate(new_dentry); new_dir_i->i_mtime = new_dir_i->i_ctime = ITIME(now); return ret; } diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index f509f62e12f6..3361979d728c 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -137,39 +137,33 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, struct page *pg; struct inode *inode = mapping->host; struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - struct jffs2_raw_inode ri; - uint32_t alloc_len = 0; pgoff_t index = pos >> PAGE_CACHE_SHIFT; uint32_t pageofs = index << PAGE_CACHE_SHIFT; int ret = 0; - jffs2_dbg(1, "%s()\n", __func__); - - if (pageofs > inode->i_size) { - ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len, - ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); - if (ret) - return ret; - } - - mutex_lock(&f->sem); pg = grab_cache_page_write_begin(mapping, index, flags); - if (!pg) { - if (alloc_len) - jffs2_complete_reservation(c); - mutex_unlock(&f->sem); + if (!pg) return -ENOMEM; - } *pagep = pg; - if (alloc_len) { + jffs2_dbg(1, "%s()\n", __func__); + + if (pageofs > inode->i_size) { /* Make new hole frag from old EOF to new page */ + struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); + struct jffs2_raw_inode ri; struct jffs2_full_dnode *fn; + uint32_t alloc_len; jffs2_dbg(1, "Writing new hole frag 0x%x-0x%x between current EOF and new page\n", (unsigned int)inode->i_size, pageofs); + ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len, + ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); + if (ret) + goto out_page; + + mutex_lock(&f->sem); memset(&ri, 0, sizeof(ri)); ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); @@ -196,6 +190,7 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, if (IS_ERR(fn)) { ret = PTR_ERR(fn); jffs2_complete_reservation(c); + mutex_unlock(&f->sem); goto out_page; } ret = jffs2_add_full_dnode_to_inode(c, f, fn); @@ -210,10 +205,12 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, jffs2_mark_node_obsolete(c, fn->raw); jffs2_free_full_dnode(fn); jffs2_complete_reservation(c); + mutex_unlock(&f->sem); goto out_page; } jffs2_complete_reservation(c); inode->i_size = pageofs; + mutex_unlock(&f->sem); } /* @@ -222,18 +219,18 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping, * case of a short-copy. */ if (!PageUptodate(pg)) { + mutex_lock(&f->sem); ret = jffs2_do_readpage_nolock(inode, pg); + mutex_unlock(&f->sem); if (ret) goto out_page; } - mutex_unlock(&f->sem); jffs2_dbg(1, "end write_begin(). pg->flags %lx\n", pg->flags); return ret; out_page: unlock_page(pg); page_cache_release(pg); - mutex_unlock(&f->sem); return ret; } diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 5a2dec2b064c..95d5880a63ee 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -1296,14 +1296,17 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era BUG_ON(start > orig_start); } - /* First, use readpage() to read the appropriate page into the page cache */ - /* Q: What happens if we actually try to GC the _same_ page for which commit_write() - * triggered garbage collection in the first place? - * A: I _think_ it's OK. read_cache_page shouldn't deadlock, we'll write out the - * page OK. We'll actually write it out again in commit_write, which is a little - * suboptimal, but at least we're correct. - */ + /* The rules state that we must obtain the page lock *before* f->sem, so + * drop f->sem temporarily. Since we also hold c->alloc_sem, nothing's + * actually going to *change* so we're safe; we only allow reading. + * + * It is important to note that jffs2_write_begin() will ensure that its + * page is marked Uptodate before allocating space. That means that if we + * end up here trying to GC the *same* page that jffs2_write_begin() is + * trying to write out, read_cache_page() will not deadlock. */ + mutex_unlock(&f->sem); pg_ptr = jffs2_gc_fetch_page(c, f, start, &pg); + mutex_lock(&f->sem); if (IS_ERR(pg_ptr)) { pr_warn("read_cache_page() returned error: %ld\n", diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index fa35ff79ab35..0637271f3770 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -194,6 +194,7 @@ struct jffs2_inode_cache { #define INO_STATE_CLEARING 6 /* In clear_inode() */ #define INO_FLAGS_XATTR_CHECKED 0x01 /* has no duplicate xattr_ref */ +#define INO_FLAGS_IS_DIR 0x02 /* is a directory */ #define RAWNODE_CLASS_INODE_CACHE 0 #define RAWNODE_CLASS_XATTR_DATUM 1 @@ -249,7 +250,10 @@ struct jffs2_readinode_info struct jffs2_full_dirent { - struct jffs2_raw_node_ref *raw; + union { + struct jffs2_raw_node_ref *raw; + struct jffs2_inode_cache *ic; /* Just during part of build */ + }; struct jffs2_full_dirent *next; uint32_t version; uint32_t ino; /* == zero for unlink */ diff --git a/fs/locks.c b/fs/locks.c index 0d2b3267e2a3..6333263b7bc8 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -2182,7 +2182,6 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, goto out; } -again: error = flock_to_posix_lock(filp, file_lock, &flock); if (error) goto out; @@ -2224,19 +2223,22 @@ again: * Attempt to detect a close/fcntl race and recover by * releasing the lock that was just acquired. */ - /* - * we need that spin_lock here - it prevents reordering between - * update of i_flctx->flc_posix and check for it done in close(). - * rcu_read_lock() wouldn't do. - */ - spin_lock(¤t->files->file_lock); - f = fcheck(fd); - spin_unlock(¤t->files->file_lock); - if (!error && f != filp && flock.l_type != F_UNLCK) { - flock.l_type = F_UNLCK; - goto again; + if (!error && file_lock->fl_type != F_UNLCK) { + /* + * We need that spin_lock here - it prevents reordering between + * update of i_flctx->flc_posix and check for it done in + * close(). rcu_read_lock() wouldn't do. + */ + spin_lock(¤t->files->file_lock); + f = fcheck(fd); + spin_unlock(¤t->files->file_lock); + if (f != filp) { + file_lock->fl_type = F_UNLCK; + error = do_lock_file_wait(filp, cmd, file_lock); + WARN_ON_ONCE(error); + error = -EBADF; + } } - out: locks_free_lock(file_lock); return error; @@ -2322,7 +2324,6 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, goto out; } -again: error = flock64_to_posix_lock(filp, file_lock, &flock); if (error) goto out; @@ -2364,14 +2365,22 @@ again: * Attempt to detect a close/fcntl race and recover by * releasing the lock that was just acquired. */ - spin_lock(¤t->files->file_lock); - f = fcheck(fd); - spin_unlock(¤t->files->file_lock); - if (!error && f != filp && flock.l_type != F_UNLCK) { - flock.l_type = F_UNLCK; - goto again; + if (!error && file_lock->fl_type != F_UNLCK) { + /* + * We need that spin_lock here - it prevents reordering between + * update of i_flctx->flc_posix and check for it done in + * close(). rcu_read_lock() wouldn't do. + */ + spin_lock(¤t->files->file_lock); + f = fcheck(fd); + spin_unlock(¤t->files->file_lock); + if (f != filp) { + file_lock->fl_type = F_UNLCK; + error = do_lock_file_wait(filp, cmd, file_lock); + WARN_ON_ONCE(error); + error = -EBADF; + } } - out: locks_free_lock(file_lock); return error; diff --git a/fs/namei.c b/fs/namei.c index 5fd8a57d132b..558ea922a515 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1711,6 +1711,11 @@ static inline int should_follow_link(struct nameidata *nd, struct path *link, return 0; if (!follow) return 0; + /* make sure that d_is_symlink above matches inode */ + if (nd->flags & LOOKUP_RCU) { + if (read_seqcount_retry(&link->dentry->d_seq, seq)) + return -ECHILD; + } return pick_link(nd, link, inode, seq); } @@ -1742,11 +1747,11 @@ static int walk_component(struct nameidata *nd, int flags) if (err < 0) return err; - inode = d_backing_inode(path.dentry); seq = 0; /* we are already out of RCU mode */ err = -ENOENT; if (d_is_negative(path.dentry)) goto out_path_put; + inode = d_backing_inode(path.dentry); } if (flags & WALK_PUT) @@ -3136,12 +3141,12 @@ retry_lookup: return error; BUG_ON(nd->flags & LOOKUP_RCU); - inode = d_backing_inode(path.dentry); seq = 0; /* out of RCU mode, so the value doesn't matter */ if (unlikely(d_is_negative(path.dentry))) { path_to_nameidata(&path, nd); return -ENOENT; } + inode = d_backing_inode(path.dentry); finish_lookup: if (nd->depth) put_link(nd); @@ -3150,11 +3155,6 @@ finish_lookup: if (unlikely(error)) return error; - if (unlikely(d_is_symlink(path.dentry)) && !(open_flag & O_PATH)) { - path_to_nameidata(&path, nd); - return -ELOOP; - } - if ((nd->flags & LOOKUP_RCU) || nd->path.mnt != path.mnt) { path_to_nameidata(&path, nd); } else { @@ -3173,6 +3173,10 @@ finish_open: return error; } audit_inode(nd->name, nd->path.dentry, 0); + if (unlikely(d_is_symlink(nd->path.dentry)) && !(open_flag & O_PATH)) { + error = -ELOOP; + goto out; + } error = -EISDIR; if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry)) goto out; @@ -3216,6 +3220,10 @@ opened: goto exit_fput; } out: + if (unlikely(error > 0)) { + WARN_ON(1); + error = -EINVAL; + } if (got_write) mnt_drop_write(nd->path.mnt); path_put(&save_parent); diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index f0e3e9e747dd..03446c5a3ec1 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -633,7 +633,7 @@ ncp_fill_cache(struct file *file, struct dir_context *ctx, d_rehash(newdent); } else { spin_lock(&dentry->d_lock); - NCP_FINFO(inode)->flags &= ~NCPI_DIR_CACHE; + NCP_FINFO(dir)->flags &= ~NCPI_DIR_CACHE; spin_unlock(&dentry->d_lock); } } else { diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index f496ed721d27..98a44157353a 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2461,9 +2461,9 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, dentry = d_add_unique(dentry, igrab(state->inode)); if (dentry == NULL) { dentry = opendata->dentry; - } else if (dentry != ctx->dentry) { + } else { dput(ctx->dentry); - ctx->dentry = dget(dentry); + ctx->dentry = dentry; } nfs_set_verifier(dentry, nfs_save_change_attribute(d_inode(opendata->dir))); diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 7f604727f487..e6795c7c76a8 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -956,6 +956,7 @@ clean_orphan: tmp_ret = ocfs2_del_inode_from_orphan(osb, inode, di_bh, update_isize, end); if (tmp_ret < 0) { + ocfs2_inode_unlock(inode, 1); ret = tmp_ret; mlog_errno(ret); brelse(di_bh); diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index 692ceda3bc21..a2b1d7ce3e1a 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -618,7 +618,8 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir) * sole user of this dentry. Too tricky... Just unhash for * now. */ - d_drop(dentry); + if (!err) + d_drop(dentry); mutex_unlock(&dir->i_mutex); return err; @@ -903,6 +904,13 @@ static int ovl_rename2(struct inode *olddir, struct dentry *old, if (!overwrite && new_is_dir && !old_opaque && new_opaque) ovl_remove_opaque(newdentry); + /* + * Old dentry now lives in different location. Dentries in + * lowerstack are stale. We cannot drop them here because + * access to them is lockless. This could be only pure upper + * or opaque directory - numlower is zero. Or upper non-dir + * entry - its pureness is tracked by flag opaque. + */ if (old_opaque != new_opaque) { ovl_dentry_set_opaque(old, new_opaque); if (!overwrite) diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index b29036aa8d7c..05ac9a95e881 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -65,6 +65,8 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr) mutex_lock(&upperdentry->d_inode->i_mutex); err = notify_change(upperdentry, attr, NULL); + if (!err) + ovl_copyattr(upperdentry->d_inode, dentry->d_inode); mutex_unlock(&upperdentry->d_inode->i_mutex); } ovl_drop_write(dentry); diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index f42c9407fbad..000b2ed05c29 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -76,12 +76,14 @@ enum ovl_path_type ovl_path_type(struct dentry *dentry) if (oe->__upperdentry) { type = __OVL_PATH_UPPER; - if (oe->numlower) { - if (S_ISDIR(dentry->d_inode->i_mode)) - type |= __OVL_PATH_MERGE; - } else if (!oe->opaque) { + /* + * Non-dir dentry can hold lower dentry from previous + * location. Its purity depends only on opaque flag. + */ + if (oe->numlower && S_ISDIR(dentry->d_inode->i_mode)) + type |= __OVL_PATH_MERGE; + else if (!oe->opaque) type |= __OVL_PATH_PURE; - } } else { if (oe->numlower > 1) type |= __OVL_PATH_MERGE; @@ -322,6 +324,7 @@ static const struct dentry_operations ovl_dentry_operations = { static const struct dentry_operations ovl_reval_dentry_operations = { .d_release = ovl_dentry_release, + .d_select_inode = ovl_d_select_inode, .d_revalidate = ovl_dentry_revalidate, .d_weak_revalidate = ovl_dentry_weak_revalidate, }; diff --git a/fs/super.c b/fs/super.c index 1014e7cc355f..8d99a7b948ff 100644 --- a/fs/super.c +++ b/fs/super.c @@ -415,6 +415,7 @@ void generic_shutdown_super(struct super_block *sb) sb->s_flags &= ~MS_ACTIVE; fsnotify_unmount_inodes(sb); + cgroup_writeback_umount(); evict_inodes(sb); diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index 68a62457e685..d473e6e07a7e 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -287,6 +287,12 @@ int handle_userfault(struct vm_area_struct *vma, unsigned long address, goto out; /* + * We don't do userfault handling for the final child pid update. + */ + if (current->flags & PF_EXITING) + goto out; + + /* * Check that we can return VM_FAULT_RETRY. * * NOTE: it should become possible to return VM_FAULT_RETRY diff --git a/include/asm-generic/cputime_nsecs.h b/include/asm-generic/cputime_nsecs.h index 0419485891f2..0f1c6f315cdc 100644 --- a/include/asm-generic/cputime_nsecs.h +++ b/include/asm-generic/cputime_nsecs.h @@ -75,7 +75,7 @@ typedef u64 __nocast cputime64_t; */ static inline cputime_t timespec_to_cputime(const struct timespec *val) { - u64 ret = val->tv_sec * NSEC_PER_SEC + val->tv_nsec; + u64 ret = (u64)val->tv_sec * NSEC_PER_SEC + val->tv_nsec; return (__force cputime_t) ret; } static inline void cputime_to_timespec(const cputime_t ct, struct timespec *val) @@ -91,7 +91,8 @@ static inline void cputime_to_timespec(const cputime_t ct, struct timespec *val) */ static inline cputime_t timeval_to_cputime(const struct timeval *val) { - u64 ret = val->tv_sec * NSEC_PER_SEC + val->tv_usec * NSEC_PER_USEC; + u64 ret = (u64)val->tv_sec * NSEC_PER_SEC + + val->tv_usec * NSEC_PER_USEC; return (__force cputime_t) ret; } static inline void cputime_to_timeval(const cputime_t ct, struct timeval *val) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index c4bd0e2c173c..772c784ba763 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -256,6 +256,7 @@ .rodata : AT(ADDR(.rodata) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start_rodata) = .; \ *(.rodata) *(.rodata.*) \ + *(.data..ro_after_init) /* Read only after init */ \ *(__vermagic) /* Kernel version magic */ \ . = ALIGN(8); \ VMLINUX_SYMBOL(__start___tracepoints_ptrs) = .; \ diff --git a/include/drm/drm_cache.h b/include/drm/drm_cache.h index 7bfb063029d8..461a0558bca4 100644 --- a/include/drm/drm_cache.h +++ b/include/drm/drm_cache.h @@ -35,4 +35,13 @@ void drm_clflush_pages(struct page *pages[], unsigned long num_pages); +static inline bool drm_arch_can_wc_memory(void) +{ +#if defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE) + return false; +#else + return true; +#endif +} + #endif diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index 5340099741ae..f356f9716474 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h @@ -44,8 +44,6 @@ struct drm_dp_vcpi { /** * struct drm_dp_mst_port - MST port * @kref: reference count for this port. - * @guid_valid: for DP 1.2 devices if we have validated the GUID. - * @guid: guid for DP 1.2 device on this port. * @port_num: port number * @input: if this port is an input port. * @mcs: message capability status - DP 1.2 spec. @@ -70,10 +68,6 @@ struct drm_dp_vcpi { struct drm_dp_mst_port { struct kref kref; - /* if dpcd 1.2 device is on this port - its GUID info */ - bool guid_valid; - u8 guid[16]; - u8 port_num; bool input; bool mcs; @@ -109,10 +103,12 @@ struct drm_dp_mst_port { * @tx_slots: transmission slots for this device. * @last_seqno: last sequence number used to talk to this. * @link_address_sent: if a link address message has been sent to this device yet. + * @guid: guid for DP 1.2 branch device. port under this branch can be + * identified by port #. * * This structure represents an MST branch device, there is one - * primary branch device at the root, along with any others connected - * to downstream ports + * primary branch device at the root, along with any other branches connected + * to downstream port of parent branches. */ struct drm_dp_mst_branch { struct kref kref; @@ -131,6 +127,9 @@ struct drm_dp_mst_branch { struct drm_dp_sideband_msg_tx *tx_slots[2]; int last_seqno; bool link_address_sent; + + /* global unique identifier to identify branch devices */ + u8 guid[16]; }; @@ -405,11 +404,9 @@ struct drm_dp_payload { * @conn_base_id: DRM connector ID this mgr is connected to. * @down_rep_recv: msg receiver state for down replies. * @up_req_recv: msg receiver state for up requests. - * @lock: protects mst state, primary, guid, dpcd. + * @lock: protects mst state, primary, dpcd. * @mst_state: if this manager is enabled for an MST capable port. * @mst_primary: pointer to the primary branch device. - * @guid_valid: GUID valid for the primary branch device. - * @guid: GUID for primary port. * @dpcd: cache of DPCD for primary port. * @pbn_div: PBN to slots divisor. * @@ -431,13 +428,11 @@ struct drm_dp_mst_topology_mgr { struct drm_dp_sideband_msg_rx up_req_recv; /* pointer to info about the initial MST device */ - struct mutex lock; /* protects mst_state + primary + guid + dpcd */ + struct mutex lock; /* protects mst_state + primary + dpcd */ bool mst_state; struct drm_dp_mst_branch *mst_primary; - /* primary MST device GUID */ - bool guid_valid; - u8 guid[16]; + u8 dpcd[DP_RECEIVER_CAP_SIZE]; u8 sink_count; int pbn_div; @@ -450,9 +445,7 @@ struct drm_dp_mst_topology_mgr { the mstb tx_slots and txmsg->state once they are queued */ struct mutex qlock; struct list_head tx_msg_downq; - struct list_head tx_msg_upq; bool tx_down_in_progress; - bool tx_up_in_progress; /* payload info + lock for it */ struct mutex payload_lock; diff --git a/include/drm/drm_fixed.h b/include/drm/drm_fixed.h index d639049a613d..553210c02ee0 100644 --- a/include/drm/drm_fixed.h +++ b/include/drm/drm_fixed.h @@ -73,18 +73,28 @@ static inline u32 dfixed_div(fixed20_12 A, fixed20_12 B) #define DRM_FIXED_ONE (1ULL << DRM_FIXED_POINT) #define DRM_FIXED_DECIMAL_MASK (DRM_FIXED_ONE - 1) #define DRM_FIXED_DIGITS_MASK (~DRM_FIXED_DECIMAL_MASK) +#define DRM_FIXED_EPSILON 1LL +#define DRM_FIXED_ALMOST_ONE (DRM_FIXED_ONE - DRM_FIXED_EPSILON) static inline s64 drm_int2fixp(int a) { return ((s64)a) << DRM_FIXED_POINT; } -static inline int drm_fixp2int(int64_t a) +static inline int drm_fixp2int(s64 a) { return ((s64)a) >> DRM_FIXED_POINT; } -static inline unsigned drm_fixp_msbset(int64_t a) +static inline int drm_fixp2int_ceil(s64 a) +{ + if (a > 0) + return drm_fixp2int(a + DRM_FIXED_ALMOST_ONE); + else + return drm_fixp2int(a - DRM_FIXED_ALMOST_ONE); +} + +static inline unsigned drm_fixp_msbset(s64 a) { unsigned shift, sign = (a >> 63) & 1; @@ -136,6 +146,45 @@ static inline s64 drm_fixp_div(s64 a, s64 b) return result; } +static inline s64 drm_fixp_from_fraction(s64 a, s64 b) +{ + s64 res; + bool a_neg = a < 0; + bool b_neg = b < 0; + u64 a_abs = a_neg ? -a : a; + u64 b_abs = b_neg ? -b : b; + u64 rem; + + /* determine integer part */ + u64 res_abs = div64_u64_rem(a_abs, b_abs, &rem); + + /* determine fractional part */ + { + u32 i = DRM_FIXED_POINT; + + do { + rem <<= 1; + res_abs <<= 1; + if (rem >= b_abs) { + res_abs |= 1; + rem -= b_abs; + } + } while (--i != 0); + } + + /* round up LSB */ + { + u64 summand = (rem << 1) >= b_abs; + + res_abs += summand; + } + + res = (s64) res_abs; + if (a_neg ^ b_neg) + res = -res; + return res; +} + static inline s64 drm_fixp_exp(s64 x) { s64 tolerance = div64_s64(DRM_FIXED_ONE, 1000000); diff --git a/include/dt-bindings/clock/audio-ext-clk.h b/include/dt-bindings/clock/audio-ext-clk.h index 4945d6956293..6e4932342751 100644 --- a/include/dt-bindings/clock/audio-ext-clk.h +++ b/include/dt-bindings/clock/audio-ext-clk.h @@ -18,4 +18,5 @@ #define clk_audio_pmi_clk 0xcbfe416d #define clk_audio_ap_clk2 0x454d1e91 #define clk_audio_lpass_mclk 0xf0f2a284 +#define clk_audio_pmi_lnbb_clk 0x57312343 #endif diff --git a/include/dt-bindings/clock/msm-clocks-cobalt.h b/include/dt-bindings/clock/msm-clocks-cobalt.h index d3cfc622b323..47cd73b08a83 100644 --- a/include/dt-bindings/clock/msm-clocks-cobalt.h +++ b/include/dt-bindings/clock/msm-clocks-cobalt.h @@ -197,7 +197,6 @@ #define clk_gcc_gpu_snoc_dvm_gfx_clk 0xc9147451 #define clk_gcc_gpu_bimc_gfx_clk 0x3909459b #define clk_gcc_gpu_bimc_gfx_src_clk 0x377cb748 -#define clk_gcc_bimc_hmss_axi_clk 0x84653931 #define clk_gcc_gpu_cfg_ahb_clk 0x72f20a57 #define clk_gcc_gpu_iref_clk 0xfd82abad #define clk_gcc_hmss_ahb_clk 0x62818713 @@ -306,6 +305,11 @@ #define clk_csi2_clk_src 0x4113589f #define clk_csi3_clk_src 0xfd934012 #define clk_fd_core_clk_src 0xe4799ab7 +#define clk_ext_dp_phy_pll_vco 0x441b576b +#define clk_ext_dp_phy_pll_link 0xea12644c +#define clk_dp_link_clk_src 0x370d0626 +#define clk_dp_crypto_clk_src 0xf8faa811 +#define clk_dp_pixel_clk_src 0xf5dfbabf #define clk_ext_extpclk_clk_src 0xe5b273af #define clk_ext_pclk0_clk_src 0x087c1612 #define clk_ext_pclk1_clk_src 0x8067c5a3 @@ -405,6 +409,10 @@ #define clk_mmss_mdss_byte1_intf_clk 0xcf654d8e #define clk_mmss_mdss_byte1_intf_div_clk 0xcdf334c5 #define clk_mmss_mdss_dp_aux_clk 0x23125eb6 +#define clk_mmss_mdss_dp_crypto_clk 0x9a072d4e +#define clk_mmss_mdss_dp_link_clk 0x8dd302d1 +#define clk_mmss_mdss_dp_link_intf_clk 0x70e386e6 +#define clk_mmss_mdss_dp_pixel_clk 0xb707b765 #define clk_mmss_mdss_dp_gtc_clk 0xb59c151a #define clk_mmss_mdss_esc0_clk 0x5721ff83 #define clk_mmss_mdss_esc1_clk 0xc3d0376b diff --git a/include/dt-bindings/clock/msm-clocks-hwio-cobalt.h b/include/dt-bindings/clock/msm-clocks-hwio-cobalt.h index af26f826e18c..757344602f4a 100644 --- a/include/dt-bindings/clock/msm-clocks-hwio-cobalt.h +++ b/include/dt-bindings/clock/msm-clocks-hwio-cobalt.h @@ -171,7 +171,6 @@ #define GCC_GPU_CFG_AHB_CBCR 0x71004 #define GCC_GPU_SNOC_DVM_GFX_CBCR 0x71018 #define GCC_GPU_IREF_EN 0x88010 -#define GCC_BIMC_HMSS_AXI_CBCR 0x48004 #define GCC_HMSS_AHB_CBCR 0x48000 #define GCC_HMSS_DVM_BUS_CBCR 0x4808C #define GCC_HMSS_RBCPR_CBCR 0x48008 diff --git a/include/dt-bindings/clock/qcom,gcc-msmfalcon.h b/include/dt-bindings/clock/qcom,gcc-msmfalcon.h new file mode 100644 index 000000000000..d0a8419ee54c --- /dev/null +++ b/include/dt-bindings/clock/qcom,gcc-msmfalcon.h @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DT_BINDINGS_CLK_MSM_GCC_FALCON_H +#define _DT_BINDINGS_CLK_MSM_GCC_FALCON_H + +/* Clocks */ +#define GPLL0 0 +#define GPLL1 1 +#define GPLL2 2 +#define GPLL3 3 +#define GPLL4 4 +#define GPLL5 5 +#define GPLL6 6 +#define MMSS_QM_CORE_CLK_SRC 7 +#define USB30_MASTER_CLK_SRC 8 +#define USB30_MOCK_UTMI_CLK_SRC 9 +#define USB3_PHY_AUX_CLK_SRC 10 +#define USB20_MASTER_CLK_SRC 11 +#define USB20_MOCK_UTMI_CLK_SRC 12 +#define SDCC2_APPS_CLK_SRC 13 +#define SDCC1_ICE_CORE_CLK_SRC 14 +#define SDCC1_APPS_CLK_SRC 15 +#define BLSP1_QUP1_SPI_APPS_CLK_SRC 16 +#define BLSP1_QUP1_I2C_APPS_CLK_SRC 17 +#define BLSP1_UART1_APPS_CLK_SRC 18 +#define BLSP1_QUP2_SPI_APPS_CLK_SRC 19 +#define BLSP1_QUP2_I2C_APPS_CLK_SRC 20 +#define BLSP1_UART2_APPS_CLK_SRC 21 +#define BLSP1_QUP3_SPI_APPS_CLK_SRC 22 +#define BLSP1_QUP3_I2C_APPS_CLK_SRC 23 +#define BLSP1_QUP4_SPI_APPS_CLK_SRC 24 +#define BLSP1_QUP4_I2C_APPS_CLK_SRC 25 +#define BLSP2_QUP1_SPI_APPS_CLK_SRC 26 +#define BLSP2_QUP1_I2C_APPS_CLK_SRC 27 +#define BLSP2_UART1_APPS_CLK_SRC 28 +#define BLSP2_QUP2_SPI_APPS_CLK_SRC 29 +#define BLSP2_QUP2_I2C_APPS_CLK_SRC 30 +#define BLSP2_UART2_APPS_CLK_SRC 31 +#define BLSP2_QUP3_SPI_APPS_CLK_SRC 32 +#define BLSP2_QUP3_I2C_APPS_CLK_SRC 33 +#define BLSP2_QUP4_SPI_APPS_CLK_SRC 34 +#define BLSP2_QUP4_I2C_APPS_CLK_SRC 35 +#define PDM2_CLK_SRC 36 +#define HMSS_AHB_CLK_SRC 37 +#define BIMC_HMSS_AXI_CLK_SRC 38 +#define HMSS_RBCPR_CLK_SRC 39 +#define HMSS_GPLL0_CLK_SRC 40 +#define HMSS_GPLL4_CLK_SRC 41 +#define GP1_CLK_SRC 42 +#define GP2_CLK_SRC 43 +#define GP3_CLK_SRC 44 +#define UFS_AXI_CLK_SRC 45 +#define UFS_ICE_CORE_CLK_SRC 46 +#define UFS_UNIPRO_CORE_CLK_SRC 47 +#define UFS_PHY_AUX_CLK_SRC 48 +#define QSPI_SER_CLK_SRC 49 +#define GLM_CLK_SRC 50 +#define GCC_MMSS_SYS_NOC_AXI_CLK 51 +#define GCC_MMSS_NOC_CFG_AHB_CLK 52 +#define GCC_MMSS_QM_CORE_CLK 53 +#define GCC_MMSS_QM_AHB_CLK 54 +#define GCC_USB30_MASTER_CLK 55 +#define GCC_USB30_SLEEP_CLK 56 +#define GCC_USB30_MOCK_UTMI_CLK 57 +#define GCC_USB3_PHY_AUX_CLK 58 +#define GCC_USB3_PHY_PIPE_CLK 59 +#define GCC_USB20_MASTER_CLK 60 +#define GCC_USB20_SLEEP_CLK 61 +#define GCC_USB20_MOCK_UTMI_CLK 62 +#define GCC_USB_PHY_CFG_AHB2PHY_CLK 63 +#define GCC_SDCC2_APPS_CLK 64 +#define GCC_SDCC2_AHB_CLK 65 +#define GCC_SDCC1_APPS_CLK 66 +#define GCC_SDCC1_AHB_CLK 67 +#define GCC_SDCC1_ICE_CORE_CLK 68 +#define GCC_BLSP1_AHB_CLK 69 +#define GCC_BLSP1_SLEEP_CLK 70 +#define GCC_BLSP1_QUP1_SPI_APPS_CLK 71 +#define GCC_BLSP1_QUP1_I2C_APPS_CLK 72 +#define GCC_BLSP1_UART1_APPS_CLK 73 +#define GCC_BLSP1_QUP2_SPI_APPS_CLK 74 +#define GCC_BLSP1_QUP2_I2C_APPS_CLK 75 +#define GCC_BLSP1_UART2_APPS_CLK 76 +#define GCC_BLSP1_QUP3_SPI_APPS_CLK 77 +#define GCC_BLSP1_QUP3_I2C_APPS_CLK 78 +#define GCC_BLSP1_QUP4_SPI_APPS_CLK 79 +#define GCC_BLSP1_QUP4_I2C_APPS_CLK 80 +#define GCC_BLSP2_AHB_CLK 81 +#define GCC_BLSP2_SLEEP_CLK 82 +#define GCC_BLSP2_QUP1_SPI_APPS_CLK 83 +#define GCC_BLSP2_QUP1_I2C_APPS_CLK 84 +#define GCC_BLSP2_UART1_APPS_CLK 85 +#define GCC_BLSP2_QUP2_SPI_APPS_CLK 86 +#define GCC_BLSP2_QUP2_I2C_APPS_CLK 87 +#define GCC_BLSP2_UART2_APPS_CLK 88 +#define GCC_BLSP2_QUP3_SPI_APPS_CLK 89 +#define GCC_BLSP2_QUP3_I2C_APPS_CLK 90 +#define GCC_BLSP2_QUP4_SPI_APPS_CLK 91 +#define GCC_BLSP2_QUP4_I2C_APPS_CLK 92 +#define GCC_PDM_AHB_CLK 93 +#define GCC_PDM_XO4_CLK 94 +#define GCC_PDM2_CLK 95 +#define GCC_PRNG_AHB_CLK 96 +#define GCC_BIMC_GFX_CLK 97 +#define GCC_MCCC_CFG_AHB_CLK 98 +#define GCC_LPASS_TRIG_CLK 99 +#define GCC_LPASS_AT_CLK 100 +#define GCC_TURING_TRIG_CLK 101 +#define GCC_TURING_AT_CLK 102 +#define GCC_HMSS_AHB_CLK 103 +#define GCC_BIMC_HMSS_AXI_CLK 104 +#define GCC_HMSS_RBCPR_CLK 105 +#define GCC_HMSS_TRIG_CLK 106 +#define GCC_HMSS_AT_CLK 107 +#define GCC_HMSS_DVM_BUS_CLK 108 +#define GCC_GP1_CLK 109 +#define GCC_GP2_CLK 110 +#define GCC_GP3_CLK 111 +#define GCC_UFS_AXI_CLK 112 +#define GCC_UFS_AHB_CLK 113 +#define GCC_UFS_TX_SYMBOL_0_CLK 114 +#define GCC_UFS_RX_SYMBOL_0_CLK 115 +#define GCC_UFS_UNIPRO_CORE_CLK 116 +#define GCC_UFS_ICE_CORE_CLK 117 +#define GCC_UFS_PHY_AUX_CLK 118 +#define GCC_UFS_RX_SYMBOL_1_CLK 119 +#define GCC_AGGRE2_USB3_AXI_CLK 120 +#define GCC_AGGRE2_UFS_AXI_CLK 121 +#define GCC_QSPI_AHB_CLK 122 +#define GCC_QSPI_SER_CLK 123 +#define GCC_GLM_AHB_CLK 124 +#define GCC_GLM_CLK 125 +#define GCC_GLM_XO_CLK 126 +#define GCC_WCSS_AHB_S0_CLK 127 +#define GCC_WCSS_AXI_M_CLK 128 +#define GCC_WCSS_ECAHB_CLK 129 +#define GCC_WCSS_SHDREG_AHB_CLK 130 +#define GCC_GPU_CFG_AHB_CLK 131 +#define GCC_GPU_BIMC_GFX_SRC_CLK 132 +#define GCC_GPU_BIMC_GFX_CLK 133 +#define GCC_GPU_SNOC_DVM_GFX_CLK 134 + +/* Block Resets */ +#define GCC_SYSTEM_NOC_BCR 0 +#define GCC_CONFIG_NOC_BCR 1 +#define GCC_IMEM_BCR 2 +#define GCC_MMSS_BCR 3 +#define GCC_PIMEM_BCR 4 +#define GCC_QDSS_BCR 5 +#define GCC_USB_30_BCR 6 +#define GCC_USB_20_BCR 7 +#define GCC_QUSB2PHY_PRIM_BCR 8 +#define GCC_QUSB2PHY_SEC_BCR 9 +#define GCC_USB_PHY_CFG_AHB2PHY_BCR 10 +#define GCC_SDCC2_BCR 11 +#define GCC_SDCC1_BCR 12 +#define GCC_BLSP1_BCR 13 +#define GCC_BLSP1_QUP1_BCR 14 +#define GCC_BLSP1_UART1_BCR 15 +#define GCC_BLSP1_QUP2_BCR 16 +#define GCC_BLSP1_UART2_BCR 17 +#define GCC_BLSP1_QUP3_BCR 18 +#define GCC_BLSP1_QUP4_BCR 19 +#define GCC_BLSP2_BCR 20 +#define GCC_BLSP2_QUP1_BCR 21 +#define GCC_BLSP2_UART1_BCR 22 +#define GCC_BLSP2_QUP2_BCR 23 +#define GCC_BLSP2_UART2_BCR 24 +#define GCC_BLSP2_QUP3_BCR 25 +#define GCC_BLSP2_QUP4_BCR 26 +#define GCC_PDM_BCR 27 +#define GCC_PRNG_BCR 28 +#define GCC_TCSR_BCR 29 +#define GCC_BOOT_ROM_BCR 30 +#define GCC_MSG_RAM_BCR 31 +#define GCC_TLMM_BCR 32 +#define GCC_MPM_BCR 33 +#define GCC_SEC_CTRL_BCR 34 +#define GCC_SPMI_BCR 35 +#define GCC_SPDM_BCR 36 +#define GCC_CE1_BCR 37 +#define GCC_BIMC_BCR 38 +#define GCC_SNOC_BUS_TIMEOUT0_BCR 39 +#define GCC_SNOC_BUS_TIMEOUT1_BCR 40 +#define GCC_SNOC_BUS_TIMEOUT3_BCR 41 +#define GCC_SNOC_BUS_TIMEOUT_EXTREF_BCR 42 +#define GCC_SNOC_BUS_TIMEOUT4_BCR 43 +#define GCC_PNOC_BUS_TIMEOUT0_BCR 44 +#define GCC_CNOC_PERIPH_BUS_TIMEOUT1_BCR 45 +#define GCC_CNOC_PERIPH_BUS_TIMEOUT2_BCR 46 +#define GCC_CNOC_BUS_TIMEOUT0_BCR 47 +#define GCC_CNOC_BUS_TIMEOUT2_BCR 48 +#define GCC_CNOC_BUS_TIMEOUT3_BCR 49 +#define GCC_CNOC_BUS_TIMEOUT4_BCR 50 +#define GCC_CNOC_BUS_TIMEOUT5_BCR 51 +#define GCC_CNOC_BUS_TIMEOUT6_BCR 52 +#define GCC_CNOC_BUS_TIMEOUT7_BCR 53 +#define GCC_CNOC_BUS_TIMEOUT8_BCR 54 +#define GCC_CNOC_BUS_TIMEOUT9_BCR 55 +#define GCC_CNOC_BUS_TIMEOUT10_BCR 56 +#define GCC_CNOC_BUS_TIMEOUT11_BCR 57 +#define GCC_CNOC_BUS_TIMEOUT12_BCR 58 +#define GCC_CNOC_BUS_TIMEOUT13_BCR 59 +#define GCC_CNOC_BUS_TIMEOUT14_BCR 60 +#define GCC_CNOC_BUS_TIMEOUT_EXTREF_BCR 61 +#define GCC_APB2JTAG_BCR 62 +#define GCC_RBCPR_CX_BCR 63 +#define GCC_RBCPR_MX_BCR 64 +#define GCC_OBT_ODT_BCR 65 +#define GCC_UFS_BCR 66 +#define GCC_VS_BCR 67 +#define GCC_AGGRE2_NOC_BCR 68 +#define GCC_DCC_BCR 69 +#define GCC_QSPI_BCR 70 +#define GCC_IPA_BCR 71 +#define GCC_GLM_BCR 72 +#define GCC_MSMPU_BCR 73 +#define GCC_QREFS_VBG_CAL_BCR 74 +#define GCC_WCSS_BCR 75 +#define GCC_GPU_BCR 76 +#define GCC_AHB2PHY_EAST_BCR 77 +#define GCC_CM_PHY_REFGEN1_BCR 78 +#define GCC_CM_PHY_REFGEN2_BCR 79 +#define GCC_SRAM_SENSOR_BCR 80 + +/* GDSC */ +#define UFS_GDSC 0 +#define USB_30_GDSC 1 +#define DDR_DIM_WRAPPER_GDSC 2 +#define MMSS_GDSC 3 + +#endif diff --git a/include/dt-bindings/clock/qcom,gpu-msmfalcon.h b/include/dt-bindings/clock/qcom,gpu-msmfalcon.h new file mode 100644 index 000000000000..a167716e9cc6 --- /dev/null +++ b/include/dt-bindings/clock/qcom,gpu-msmfalcon.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DT_BINDINGS_CLK_MSM_GPU_FALCON_H +#define _DT_BINDINGS_CLK_MSM_GPU_FALCON_H + +/* Clocks */ +#define GPU_PLL0_PLL 0 +#define GPU_PLL1_PLL 1 +#define GFX3D_CLK_SRC 2 +#define RBBMTIMER_CLK_SRC 3 +#define RBCPR_CLK_SRC 4 +#define GPUCC_CXO_CLK 5 +#define GPUCC_GFX3D_CLK 6 +#define GPUCC_RBBMTIMER_CLK 7 +#define GPUCC_RBCPR_CLK 8 + +/* Block Reset */ +#define GPU_CC_GPU_GX_BCR 0 +#define GPU_CC_GPU_CX_BCR 1 +#define GPU_CC_RBCPR_BCR 2 +#define GPU_CC_SPDM_BCR 3 + +/* GDSC */ +#define GPU_GX_GDSC 0 +#define GPU_CX_GDSC 1 + +#endif diff --git a/include/dt-bindings/clock/qcom,mmcc-msmfalcon.h b/include/dt-bindings/clock/qcom,mmcc-msmfalcon.h new file mode 100644 index 000000000000..57aed7c8f43f --- /dev/null +++ b/include/dt-bindings/clock/qcom,mmcc-msmfalcon.h @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DT_BINDINGS_CLK_MSM_MMCC_FALCON_H +#define _DT_BINDINGS_CLK_MSM_MMCC_FALCON_H + +/* Clocks */ +#define MMPLL3_PLL 0 +#define MMPLL4_PLL 1 +#define MMPLL5_PLL 2 +#define MMPLL6_PLL 3 +#define MMPLL7_PLL 4 +#define MMPLL8_PLL 5 +#define AHB_CLK_SRC 6 +#define VIDEO_CORE_CLK_SRC 7 +#define PCLK0_CLK_SRC 8 +#define PCLK1_CLK_SRC 9 +#define MDP_CLK_SRC 10 +#define ROT_CLK_SRC 11 +#define VSYNC_CLK_SRC 12 +#define BYTE0_CLK_SRC 13 +#define BYTE1_CLK_SRC 14 +#define ESC0_CLK_SRC 15 +#define ESC1_CLK_SRC 16 +#define DP_LINK_CLK_SRC 17 +#define DP_CRYPTO_CLK_SRC 18 +#define DP_PIXEL_CLK_SRC 19 +#define DP_AUX_CLK_SRC 20 +#define DP_GTC_CLK_SRC 21 +#define CAMSS_GP0_CLK_SRC 22 +#define CAMSS_GP1_CLK_SRC 23 +#define MCLK0_CLK_SRC 24 +#define MCLK1_CLK_SRC 25 +#define MCLK2_CLK_SRC 26 +#define MCLK3_CLK_SRC 27 +#define CCI_CLK_SRC 28 +#define CSI0PHYTIMER_CLK_SRC 29 +#define CSI1PHYTIMER_CLK_SRC 30 +#define CSI2PHYTIMER_CLK_SRC 31 +#define JPEG0_CLK_SRC 32 +#define VFE0_CLK_SRC 33 +#define VFE1_CLK_SRC 34 +#define CPP_CLK_SRC 35 +#define CSIPHY_CLK_SRC 36 +#define CSI0_CLK_SRC 37 +#define CSI1_CLK_SRC 38 +#define CSI2_CLK_SRC 39 +#define CSI3_CLK_SRC 40 +#define MMSS_CXO_CLK 41 +#define MMSS_SLEEP_CLK 42 +#define MMSS_MNOC_AHB_CLK 43 +#define MMSS_MISC_AHB_CLK 44 +#define MMSS_MISC_CXO_CLK 45 +#define MMSS_BIMC_SMMU_AHB_CLK 46 +#define MMSS_BIMC_SMMU_AXI_CLK 47 +#define MMSS_SNOC_DVM_AXI_CLK 48 +#define MMSS_THROTTLE_CAMSS_CXO_CLK 49 +#define MMSS_THROTTLE_CAMSS_AHB_CLK 50 +#define MMSS_THROTTLE_CAMSS_AXI_CLK 51 +#define MMSS_THROTTLE_MDSS_CXO_CLK 52 +#define MMSS_THROTTLE_MDSS_AHB_CLK 53 +#define MMSS_THROTTLE_MDSS_AXI_CLK 54 +#define MMSS_THROTTLE_VIDEO_CXO_CLK 55 +#define MMSS_THROTTLE_VIDEO_AHB_CLK 56 +#define MMSS_THROTTLE_VIDEO_AXI_CLK 57 +#define MMSS_VIDEO_CORE_CLK 58 +#define MMSS_VIDEO_AXI_CLK 59 +#define MMSS_VIDEO_AHB_CLK 60 +#define MMSS_MDSS_AHB_CLK 61 +#define MMSS_MDSS_HDMI_DP_AHB_CLK 62 +#define MMSS_MDSS_PCLK0_CLK 63 +#define MMSS_MDSS_PCLK1_CLK 64 +#define MMSS_MDSS_VSYNC_CLK 65 +#define MMSS_MDSS_BYTE0_CLK 66 +#define MMSS_MDSS_BYTE0_INTF_CLK 67 +#define MMSS_MDSS_BYTE1_CLK 68 +#define MMSS_MDSS_BYTE1_INTF_CLK 69 +#define MMSS_MDSS_ESC0_CLK 70 +#define MMSS_MDSS_ESC1_CLK 71 +#define MMSS_MDSS_DP_LINK_CLK 72 +#define MMSS_MDSS_DP_LINK_INTF_CLK 73 +#define MMSS_MDSS_DP_CRYPTO_CLK 74 +#define MMSS_MDSS_DP_PIXEL_CLK 75 +#define MMSS_MDSS_DP_AUX_CLK 76 +#define MMSS_MDSS_DP_GTC_CLK 77 +#define MMSS_CAMSS_TOP_AHB_CLK 78 +#define MMSS_CAMSS_AHB_CLK 79 +#define MMSS_CAMSS_GP0_CLK 80 +#define MMSS_CAMSS_GP1_CLK 81 +#define MMSS_CAMSS_MCLK0_CLK 82 +#define MMSS_CAMSS_MCLK1_CLK 83 +#define MMSS_CAMSS_MCLK2_CLK 84 +#define MMSS_CAMSS_MCLK3_CLK 85 +#define MMSS_CAMSS_CCI_CLK 86 +#define MMSS_CAMSS_CCI_AHB_CLK 87 +#define MMSS_CAMSS_CSI0PHYTIMER_CLK 88 +#define MMSS_CAMSS_CSI1PHYTIMER_CLK 89 +#define MMSS_CAMSS_CSI2PHYTIMER_CLK 90 +#define MMSS_CAMSS_JPEG_AHB_CLK 91 +#define MMSS_CAMSS_VFE_VBIF_AHB_CLK 92 +#define MMSS_CAMSS_VFE0_STREAM_CLK 93 +#define MMSS_CAMSS_VFE0_AHB_CLK 94 +#define MMSS_CAMSS_VFE1_STREAM_CLK 95 +#define MMSS_CAMSS_VFE1_AHB_CLK 96 +#define MMSS_CAMSS_CPP_VBIF_AHB_CLK 97 +#define MMSS_CAMSS_CPP_AHB_CLK 98 +#define MMSS_CAMSS_CSIPHY0_CLK 99 +#define MMSS_CAMSS_CSIPHY1_CLK 100 +#define MMSS_CAMSS_CSIPHY2_CLK 101 +#define MMSS_CSIPHY_AHB2CRIF_CLK 102 +#define MMSS_CAMSS_CSI0_CLK 103 +#define MMSS_CAMSS_CPHY_CSID0_CLK 104 +#define MMSS_CAMSS_CSI0_AHB_CLK 105 +#define MMSS_CAMSS_CSI0RDI_CLK 106 +#define MMSS_CAMSS_CSI0PIX_CLK 107 +#define MMSS_CAMSS_CSI1_CLK 108 +#define MMSS_CAMSS_CPHY_CSID1_CLK 109 +#define MMSS_CAMSS_CSI1_AHB_CLK 110 +#define MMSS_CAMSS_CSI1RDI_CLK 111 +#define MMSS_CAMSS_CSI1PIX_CLK 112 +#define MMSS_CAMSS_CSI2_CLK 113 +#define MMSS_CAMSS_CPHY_CSID2_CLK 114 +#define MMSS_CAMSS_CSI2_AHB_CLK 115 +#define MMSS_CAMSS_CSI2RDI_CLK 116 +#define MMSS_CAMSS_CSI2PIX_CLK 117 +#define MMSS_CAMSS_CSI3_CLK 118 +#define MMSS_CAMSS_CPHY_CSID3_CLK 119 +#define MMSS_CAMSS_CSI3_AHB_CLK 120 +#define MMSS_CAMSS_CSI3RDI_CLK 121 +#define MMSS_CAMSS_CSI3PIX_CLK 122 +#define MMSS_CAMSS_ISPIF_AHB_CLK 123 + +/* Block Resets */ +#define MMSS_MNOCAHB_BCR 0 +#define MMSS_MISC_BCR 1 +#define MMSS_BTO_BCR 2 +#define MMSS_MNOCAXI_BCR 3 +#define MMSS_BIMC_SMMU_BCR 4 +#define MMSS_THROTTLE_CAMSS_BCR 5 +#define MMSS_THROTTLE_MDSS_BCR 6 +#define MMSS_THROTTLE_VIDEO_BCR 7 +#define MMSS_VIDEO_TOP_BCR 8 +#define MMSS_MDSS_BCR 9 +#define MMSS_CAMSS_TOP_BCR 10 +#define MMSS_CAMSS_AHB_BCR 11 +#define MMSS_CAMSS_MICRO_BCR 12 +#define MMSS_CAMSS_CCI_BCR 13 +#define MMSS_CAMSS_PHY0_BCR 14 +#define MMSS_CAMSS_PHY1_BCR 15 +#define MMSS_CAMSS_PHY2_BCR 16 +#define MMSS_CAMSS_JPEG_BCR 17 +#define MMSS_CAMSS_VFE_VBIF_BCR 18 +#define MMSS_CAMSS_VFE0_BCR 19 +#define MMSS_CAMSS_VFE1_BCR 20 +#define MMSS_CAMSS_CSI_VFE0_BCR 21 +#define MMSS_CAMSS_CSI_VFE1_BCR 22 +#define MMSS_CAMSS_CPP_TOP_BCR 23 +#define MMSS_CAMSS_CPP_BCR 24 +#define MMSS_CAMSS_CSIPHY_BCR 25 +#define MMSS_CAMSS_CSI0_BCR 26 +#define MMSS_CAMSS_CSI0RDI_BCR 27 +#define MMSS_CAMSS_CSI0PIX_BCR 28 +#define MMSS_CAMSS_CSI1_BCR 29 +#define MMSS_CAMSS_CSI1RDI_BCR 30 +#define MMSS_CAMSS_CSI1PIX_BCR 31 +#define MMSS_CAMSS_CSI2_BCR 32 +#define MMSS_CAMSS_CSI2RDI_BCR 33 +#define MMSS_CAMSS_CSI2PIX_BCR 34 +#define MMSS_CAMSS_CSI3_BCR 35 +#define MMSS_CAMSS_CSI3RDI_BCR 36 +#define MMSS_CAMSS_CSI3PIX_BCR 37 +#define MMSS_CAMSS_ISPIF_BCR 38 + +/* GDSC */ +#define VIDEO_TOP_GDSC 0 +#define VIDEO_SUBCORE0_GDSC 1 +#define CAMSS_VFE0_GDSC 2 +#define BIMC_SMMU_GDSC 3 +#define CAMSS_TOP_GDSC 4 +#define MDSS_GDSC 5 +#define CAMSS_CPP_GDSC 6 +#define CAMSS_VFE1_GDSC 7 + +#endif diff --git a/include/linux/ata.h b/include/linux/ata.h index d2992bfa1706..c1a2f345cbe6 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -487,8 +487,8 @@ enum ata_tf_protocols { }; enum ata_ioctls { - ATA_IOC_GET_IO32 = 0x309, - ATA_IOC_SET_IO32 = 0x324, + ATA_IOC_GET_IO32 = 0x309, /* HDIO_GET_32BIT */ + ATA_IOC_SET_IO32 = 0x324, /* HDIO_SET_32BIT */ }; /* core structures */ diff --git a/include/linux/bio.h b/include/linux/bio.h index b9b6e046b52e..fbe47bc700bd 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -310,6 +310,38 @@ static inline void bio_clear_flag(struct bio *bio, unsigned int bit) bio->bi_flags &= ~(1U << bit); } +static inline void bio_get_first_bvec(struct bio *bio, struct bio_vec *bv) +{ + *bv = bio_iovec(bio); +} + +static inline void bio_get_last_bvec(struct bio *bio, struct bio_vec *bv) +{ + struct bvec_iter iter = bio->bi_iter; + int idx; + + if (unlikely(!bio_multiple_segments(bio))) { + *bv = bio_iovec(bio); + return; + } + + bio_advance_iter(bio, &iter, iter.bi_size); + + if (!iter.bi_bvec_done) + idx = iter.bi_idx - 1; + else /* in the middle of bvec */ + idx = iter.bi_idx; + + *bv = bio->bi_io_vec[idx]; + + /* + * iter.bi_bvec_done records actual length of the last bvec + * if this bio ends in the middle of one io vector + */ + if (iter.bi_bvec_done) + bv->bv_len = iter.bi_bvec_done; +} + enum bip_flags { BIP_BLOCK_INTEGRITY = 1 << 0, /* block layer owns integrity data */ BIP_MAPPED_INTEGRITY = 1 << 1, /* ref tag has been remapped */ diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 45bae2b85f46..84af69b95026 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1373,6 +1373,13 @@ static inline void put_dev_sector(Sector p) page_cache_release(p.v); } +static inline bool __bvec_gap_to_prev(struct request_queue *q, + struct bio_vec *bprv, unsigned int offset) +{ + return offset || + ((bprv->bv_offset + bprv->bv_len) & queue_virt_boundary(q)); +} + /* * Check if adding a bio_vec after bprv with offset would create a gap in * the SG list. Most drivers don't care about this, but some do. @@ -1382,18 +1389,22 @@ static inline bool bvec_gap_to_prev(struct request_queue *q, { if (!queue_virt_boundary(q)) return false; - return offset || - ((bprv->bv_offset + bprv->bv_len) & queue_virt_boundary(q)); + return __bvec_gap_to_prev(q, bprv, offset); } static inline bool bio_will_gap(struct request_queue *q, struct bio *prev, struct bio *next) { - if (!bio_has_data(prev)) - return false; + if (bio_has_data(prev) && queue_virt_boundary(q)) { + struct bio_vec pb, nb; + + bio_get_last_bvec(prev, &pb); + bio_get_first_bvec(next, &nb); - return bvec_gap_to_prev(q, &prev->bi_io_vec[prev->bi_vcnt - 1], - next->bi_io_vec[0].bv_offset); + return __bvec_gap_to_prev(q, &pb, nb.bv_offset); + } + + return false; } static inline bool req_gap_back_merge(struct request *req, struct bio *bio) diff --git a/include/linux/bluetooth-power.h b/include/linux/bluetooth-power.h index d2dfc1477c9d..7be94d298b88 100644 --- a/include/linux/bluetooth-power.h +++ b/include/linux/bluetooth-power.h @@ -44,6 +44,15 @@ struct bt_power_vreg_data { bool is_enabled; }; +struct bt_power_clk_data { + /* clock regulator handle */ + struct clk *clk; + /* clock name */ + const char *name; + /* is this clock enabled? */ + bool is_enabled; +}; + /* * Platform data for the bluetooth power driver. */ @@ -67,6 +76,8 @@ struct bluetooth_power_platform_data { * shares a common gpio to bring chip out of reset. */ struct bt_power_vreg_data *bt_chip_pwd; + /* bluetooth reference clock */ + struct bt_power_clk_data *bt_chip_clk; /* Optional: Bluetooth power setup function */ int (*bt_power_setup)(int); }; diff --git a/include/linux/cache.h b/include/linux/cache.h index 17e7e82d2aa7..1be04f8c563a 100644 --- a/include/linux/cache.h +++ b/include/linux/cache.h @@ -12,10 +12,24 @@ #define SMP_CACHE_BYTES L1_CACHE_BYTES #endif +/* + * __read_mostly is used to keep rarely changing variables out of frequently + * updated cachelines. If an architecture doesn't support it, ignore the + * hint. + */ #ifndef __read_mostly #define __read_mostly #endif +/* + * __ro_after_init is used to mark things that are read-only after init (i.e. + * after mark_rodata_ro() has been called). These are effectively read-only, + * but may get written to during init, so can't live in .rodata (via "const"). + */ +#ifndef __ro_after_init +#define __ro_after_init __attribute__((__section__(".data..ro_after_init"))) +#endif + #ifndef ____cacheline_aligned #define ____cacheline_aligned __attribute__((__aligned__(SMP_CACHE_BYTES))) #endif diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index 71b1d6cdcb5d..8dbd7879fdc6 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -220,6 +220,7 @@ struct ceph_connection { struct ceph_entity_addr actual_peer_addr; /* message out temps */ + struct ceph_msg_header out_hdr; struct ceph_msg *out_msg; /* sending message (== tail of out_sent) */ bool out_msg_done; @@ -229,7 +230,6 @@ struct ceph_connection { int out_kvec_left; /* kvec's left in out_kvec */ int out_skip; /* skip this many bytes */ int out_kvec_bytes; /* total bytes left */ - bool out_kvec_is_msg; /* kvec refers to out_msg */ int out_more; /* there is more data after the kvecs */ __le64 out_temp_ack; /* for writing an ack */ struct ceph_timespec out_temp_keepalive2; /* for writing keepalive2 diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h index 4a4eea01956c..a702c042b716 100644 --- a/include/linux/cgroup-defs.h +++ b/include/linux/cgroup-defs.h @@ -133,6 +133,12 @@ struct cgroup_subsys_state { */ u64 serial_nr; + /* + * Incremented by online self and children. Used to guarantee that + * parents are not offlined before their children. + */ + atomic_t online_cnt; + /* percpu_ref killing and RCU release */ struct rcu_head rcu_head; struct work_struct destroy_work; diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 03b9f6fab0ff..23026ba6ff25 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -173,6 +173,8 @@ struct clk_rate_request { * directory is provided as an argument. Called with * prepare_lock held. Returns 0 on success, -EERROR otherwise. * + * @set_flags: Set custom flags which deals with hardware specifics. Returns 0 + * on success, -EEROR otherwise. * * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow * implementations to split any work between atomic (enable) and sleepable @@ -213,6 +215,7 @@ struct clk_ops { int (*set_phase)(struct clk_hw *hw, int degrees); void (*init)(struct clk_hw *hw); int (*debug_init)(struct clk_hw *hw, struct dentry *dentry); + int (*set_flags)(struct clk_hw *hw, unsigned flags); }; /** diff --git a/include/linux/clk.h b/include/linux/clk.h index c06bbd5ce952..76708a7c46c0 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -408,6 +408,16 @@ struct clk *clk_get_parent(struct clk *clk); */ struct clk *clk_get_sys(const char *dev_id, const char *con_id); +/** + * clk_set_flags - set the custom specific flags for this clock + * @clk: clock source + * @flags: custom flags which would be hardware specific, defined for specific + * hardware. + * + * Returns success 0 or negative errno. + */ +int clk_set_flags(struct clk *clk, unsigned long flags); + #else /* !CONFIG_HAVE_CLK */ static inline struct clk *clk_get(struct device *dev, const char *id) diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h index 85a868ccb493..fea160ee5803 100644 --- a/include/linux/cpuset.h +++ b/include/linux/cpuset.h @@ -137,6 +137,8 @@ static inline void set_mems_allowed(nodemask_t nodemask) task_unlock(current); } +extern void cpuset_post_attach_flush(void); + #else /* !CONFIG_CPUSETS */ static inline bool cpusets_enabled(void) { return false; } @@ -243,6 +245,10 @@ static inline bool read_mems_allowed_retry(unsigned int seq) return false; } +static inline void cpuset_post_attach_flush(void) +{ +} + #endif /* !CONFIG_CPUSETS */ #endif /* _LINUX_CPUSET_H */ diff --git a/include/linux/dcache.h b/include/linux/dcache.h index d67ae119cf4e..8a2e009c8a5a 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -409,9 +409,7 @@ static inline bool d_mountpoint(const struct dentry *dentry) */ static inline unsigned __d_entry_type(const struct dentry *dentry) { - unsigned type = READ_ONCE(dentry->d_flags); - smp_rmb(); - return type & DCACHE_ENTRY_TYPE; + return dentry->d_flags & DCACHE_ENTRY_TYPE; } static inline bool d_is_miss(const struct dentry *dentry) diff --git a/include/linux/efi.h b/include/linux/efi.h index 569b5a866bb1..47be3ad7d3e5 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -1199,7 +1199,10 @@ int efivar_entry_iter(int (*func)(struct efivar_entry *, void *), struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid, struct list_head *head, bool remove); -bool efivar_validate(efi_char16_t *var_name, u8 *data, unsigned long len); +bool efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, + unsigned long data_size); +bool efivar_variable_is_removable(efi_guid_t vendor, const char *name, + size_t len); extern struct work_struct efivar_work; void efivar_run_worker(void); diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 8fdc17b84739..ae6a711dcd1d 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -630,6 +630,11 @@ struct hv_input_signal_event_buffer { struct hv_input_signal_event event; }; +enum hv_signal_policy { + HV_SIGNAL_POLICY_DEFAULT = 0, + HV_SIGNAL_POLICY_EXPLICIT, +}; + struct vmbus_channel { /* Unique channel id */ int id; @@ -757,8 +762,21 @@ struct vmbus_channel { * link up channels based on their CPU affinity. */ struct list_head percpu_list; + /* + * Host signaling policy: The default policy will be + * based on the ring buffer state. We will also support + * a policy where the client driver can have explicit + * signaling control. + */ + enum hv_signal_policy signal_policy; }; +static inline void set_channel_signal_state(struct vmbus_channel *c, + enum hv_signal_policy policy) +{ + c->signal_policy = policy; +} + static inline void set_channel_read_state(struct vmbus_channel *c, bool state) { c->batched_reading = state; diff --git a/include/linux/inet_lro.h b/include/linux/inet_lro.h index 9a715cfa1fe3..365fb3be7ee7 100644 --- a/include/linux/inet_lro.h +++ b/include/linux/inet_lro.h @@ -81,6 +81,7 @@ struct net_lro_mgr { #define LRO_F_EXTRACT_VLAN_ID 2 /* Set flag if VLAN IDs are extracted from received packets and eth protocol is still ETH_P_8021Q */ +#define LRO_F_NI 4 /* If not NAPI, Pass packets to stack via NI */ /* * Set for generated SKBs that are not added to @@ -122,6 +123,50 @@ struct net_lro_mgr { }; /* + * Large Receive Offload (LRO) information provided by the driver + * + * Fields must be set by driver when using the lro_receive_skb_ext() + */ +struct net_lro_info { + /* bitmask indicating the supported fields */ + unsigned long valid_fields; + /* + * Driver has checked the LRO eligibilty of the skb + */ + #define LRO_ELIGIBILITY_CHECKED (1 << 0) + /* + * Driver has provided the TCP payload checksum + */ + #define LRO_TCP_DATA_CSUM (1 << 1) + /* + * Driver has extracted the TCP window from the skb + * The value is in network format + */ + #define LRO_TCP_WIN (1 << 2) + /* + * Driver has extracted the TCP sequence number from skb + * The value is in network format + */ + #define LRO_TCP_SEQ_NUM (1 << 3) + /* + * Driver has extracted the TCP ack number from the skb + * The value is in network format + */ + #define LRO_TCP_ACK_NUM (1 << 4) + /* + * Driver has provided the LRO descriptor + */ + #define LRO_DESC (1 << 5) + + bool lro_eligible; + __wsum tcp_data_csum; + __be16 tcp_win; + __be32 tcp_seq_num; + __be32 tcp_ack_num; + struct net_lro_desc *lro_desc; +}; + +/* * Processes a SKB * * @lro_mgr: LRO manager to use @@ -133,10 +178,54 @@ struct net_lro_mgr { void lro_receive_skb(struct net_lro_mgr *lro_mgr, struct sk_buff *skb, void *priv); + +/* + * Processes an SKB + * + * This API provides means to pass any LRO information that has already + * been extracted by the driver + * + * @lro_mgr: LRO manager to use + * @skb: SKB to aggregate + * @priv: Private data that may be used by driver functions + * (for example get_tcp_ip_hdr) + * @lro_info: LRO information extracted by the driver + */ + +void lro_receive_skb_ext(struct net_lro_mgr *lro_mgr, + struct sk_buff *skb, + void *priv, + struct net_lro_info *lro_info); + +/* + * Processes a fragment list + * + * This functions aggregate fragments and generate SKBs do pass + * the packets to the stack. + * + * @lro_mgr: LRO manager to use + * @frags: Fragment to be processed. Must contain entire header in first + * element. + * @len: Length of received data + * @true_size: Actual size of memory the fragment is consuming + * @priv: Private data that may be used by driver functions + * (for example get_tcp_ip_hdr) + */ + +void lro_receive_frags(struct net_lro_mgr *lro_mgr, + struct skb_frag_struct *frags, + int len, int true_size, void *priv, __wsum sum); + /* * Forward all aggregated SKBs held by lro_mgr to network stack */ void lro_flush_all(struct net_lro_mgr *lro_mgr); +void lro_flush_pkt(struct net_lro_mgr *lro_mgr, + struct iphdr *iph, struct tcphdr *tcph); + +void lro_flush_desc(struct net_lro_mgr *lro_mgr, + struct net_lro_desc *lro_desc); + #endif diff --git a/include/linux/init.h b/include/linux/init.h index b449f378f995..aedb254abc37 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -142,6 +142,10 @@ void prepare_namespace(void); void __init load_default_modules(void); int __init init_rootfs(void); +#ifdef CONFIG_DEBUG_RODATA +void mark_rodata_ro(void); +#endif + extern void (*late_time_init)(void); extern bool initcall_debug; diff --git a/include/linux/leds-qpnp-flash-v2.h b/include/linux/leds-qpnp-flash-v2.h index 353466f6c108..47fd0699a9c1 100644 --- a/include/linux/leds-qpnp-flash-v2.h +++ b/include/linux/leds-qpnp-flash-v2.h @@ -16,29 +16,9 @@ #include <linux/leds.h> #include "leds.h" -/* - * Configurations for each individual LED - */ -struct flash_node_data { - struct platform_device *pdev; - struct led_classdev cdev; - struct pinctrl *pinctrl; - struct pinctrl_state *gpio_state_active; - struct pinctrl_state *gpio_state_suspend; - int ires_ua; - u16 prgm_current; - u8 duration; - u8 id; - u8 type; - u8 ires; - u8 hdrm_val; - u8 brightness; - bool led_on; -}; +#define ENABLE_REGULATOR BIT(0) +#define QUERY_MAX_CURRENT BIT(1) -struct flash_switch_data { - struct platform_device *pdev; - struct led_classdev cdev; -}; +int qpnp_flash_led_prepare(struct led_classdev *led_cdev, int options); #endif diff --git a/include/linux/libata.h b/include/linux/libata.h index 600c1e0626a5..b20a2752f934 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -718,7 +718,7 @@ struct ata_device { union { u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */ u32 gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */ - }; + } ____cacheline_aligned; /* DEVSLP Timing Variables from Identify Device Data Log */ u8 devslp_timing[ATA_LOG_DEVSLP_SIZE]; diff --git a/include/linux/mfd/msm-cdc-pinctrl.h b/include/linux/mfd/msm-cdc-pinctrl.h index 395b935b6aec..951b8d4d1ed9 100644 --- a/include/linux/mfd/msm-cdc-pinctrl.h +++ b/include/linux/mfd/msm-cdc-pinctrl.h @@ -20,6 +20,7 @@ extern int msm_cdc_pinctrl_select_sleep_state(struct device_node *); extern int msm_cdc_pinctrl_select_active_state(struct device_node *); extern bool msm_cdc_pinctrl_get_state(struct device_node *); +extern int msm_cdc_get_gpio_state(struct device_node *); #else int msm_cdc_pinctrl_select_sleep_state(struct device_node *np) @@ -30,6 +31,11 @@ int msm_cdc_pinctrl_select_active_state(struct device_node *np) { return 0; } +int msm_cdc_get_gpio_state(struct device_node *np) +{ + return 0; +} +# #endif #endif diff --git a/include/linux/mfd/wcd934x/registers.h b/include/linux/mfd/wcd934x/registers.h new file mode 100644 index 000000000000..871bf6a778b1 --- /dev/null +++ b/include/linux/mfd/wcd934x/registers.h @@ -0,0 +1,1845 @@ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _WCD934X_REGISTERS_H +#define _WCD934X_REGISTERS_H + +#define WCD934X_PAGE_SIZE 256 +#define WCD934X_NUM_PAGES 256 + +extern const u8 * const wcd934x_reg[WCD934X_NUM_PAGES]; + +enum { + WCD934X_PAGE_0 = 0, + WCD934X_PAGE_1, + WCD934X_PAGE_2, + WCD934X_PAGE_4 = 4, + WCD934X_PAGE_5, + WCD934X_PAGE_6, + WCD934X_PAGE_7, + WCD934X_PAGE_10 = 0xA, + WCD934X_PAGE_11, + WCD934X_PAGE_12, + WCD934X_PAGE_13, + WCD934X_PAGE_14, + WCD934X_PAGE_15, + WCD934X_PAGE_0X80, +}; + +enum { + WCD934X_WRITE = 0, + WCD934X_READ, + WCD934X_READ_WRITE, +}; + +/* Page-0 Registers */ +#define WCD934X_PAGE0_PAGE_REGISTER 0x0000 +#define WCD934X_CODEC_RPM_CLK_BYPASS 0x0001 +#define WCD934X_CODEC_RPM_CLK_GATE 0x0002 +#define WCD934X_CODEC_RPM_CLK_MCLK_CFG 0x0003 +#define WCD934X_CODEC_RPM_CLK_MCLK2_CFG 0x0004 +#define WCD934X_CODEC_RPM_I2S_DSD_CLK_SEL 0x0005 +#define WCD934X_CODEC_RPM_RST_CTL 0x0009 +#define WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL 0x0011 +#define WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0 0x0021 +#define WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE1 0x0022 +#define WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE2 0x0023 +#define WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE3 0x0024 +#define WCD934X_CHIP_TIER_CTRL_EFUSE_CTL 0x0025 +#define WCD934X_CHIP_TIER_CTRL_EFUSE_TEST0 0x0026 +#define WCD934X_CHIP_TIER_CTRL_EFUSE_TEST1 0x0027 +#define WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT0 0x0029 +#define WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT1 0x002a +#define WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT2 0x002b +#define WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT3 0x002c +#define WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT4 0x002d +#define WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT5 0x002e +#define WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT6 0x002f +#define WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT7 0x0030 +#define WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT8 0x0031 +#define WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT9 0x0032 +#define WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT10 0x0033 +#define WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT11 0x0034 +#define WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT12 0x0035 +#define WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT13 0x0036 +#define WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT14 0x0037 +#define WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT15 0x0038 +#define WCD934X_CHIP_TIER_CTRL_EFUSE_STATUS 0x0039 +#define WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_NONNEGO 0x003a +#define WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_1 0x003b +#define WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_2 0x003c +#define WCD934X_CHIP_TIER_CTRL_I2C_SLAVE_ID_3 0x003d +#define WCD934X_CHIP_TIER_CTRL_ANA_WAIT_STATE_CTL 0x003e +#define WCD934X_CHIP_TIER_CTRL_SLNQ_WAIT_STATE_CTL 0x003f +#define WCD934X_CHIP_TIER_CTRL_I2C_ACTIVE 0x0040 +#define WCD934X_CHIP_TIER_CTRL_ALT_FUNC_EN 0x0041 +#define WCD934X_CHIP_TIER_CTRL_GPIO_CTL_OE 0x0042 +#define WCD934X_CHIP_TIER_CTRL_GPIO_CTL_DATA 0x0043 +#define WCD934X_DATA_HUB_RX0_CFG 0x0051 +#define WCD934X_DATA_HUB_RX1_CFG 0x0052 +#define WCD934X_DATA_HUB_RX2_CFG 0x0053 +#define WCD934X_DATA_HUB_RX3_CFG 0x0054 +#define WCD934X_DATA_HUB_RX4_CFG 0x0055 +#define WCD934X_DATA_HUB_RX5_CFG 0x0056 +#define WCD934X_DATA_HUB_RX6_CFG 0x0057 +#define WCD934X_DATA_HUB_RX7_CFG 0x0058 +#define WCD934X_DATA_HUB_SB_TX0_INP_CFG 0x0061 +#define WCD934X_DATA_HUB_SB_TX1_INP_CFG 0x0062 +#define WCD934X_DATA_HUB_SB_TX2_INP_CFG 0x0063 +#define WCD934X_DATA_HUB_SB_TX3_INP_CFG 0x0064 +#define WCD934X_DATA_HUB_SB_TX4_INP_CFG 0x0065 +#define WCD934X_DATA_HUB_SB_TX5_INP_CFG 0x0066 +#define WCD934X_DATA_HUB_SB_TX6_INP_CFG 0x0067 +#define WCD934X_DATA_HUB_SB_TX7_INP_CFG 0x0068 +#define WCD934X_DATA_HUB_SB_TX8_INP_CFG 0x0069 +#define WCD934X_DATA_HUB_SB_TX9_INP_CFG 0x006a +#define WCD934X_DATA_HUB_SB_TX10_INP_CFG 0x006b +#define WCD934X_DATA_HUB_SB_TX11_INP_CFG 0x006c +#define WCD934X_DATA_HUB_SB_TX13_INP_CFG 0x006e +#define WCD934X_DATA_HUB_SB_TX14_INP_CFG 0x006f +#define WCD934X_DATA_HUB_SB_TX15_INP_CFG 0x0070 +#define WCD934X_DATA_HUB_I2S_TX0_CFG 0x0071 +#define WCD934X_DATA_HUB_I2S_TX1_0_CFG 0x0073 +#define WCD934X_DATA_HUB_I2S_TX1_1_CFG 0x0074 +#define WCD934X_DATA_HUB_I2S_0_CTL 0x0081 +#define WCD934X_DATA_HUB_I2S_1_CTL 0x0082 +#define WCD934X_DATA_HUB_I2S_2_CTL 0x0083 +#define WCD934X_DATA_HUB_I2S_3_CTL 0x0084 +#define WCD934X_DATA_HUB_I2S_CLKSRC_CTL 0x0085 +#define WCD934X_DATA_HUB_I2S_COMMON_CTL 0x0086 +#define WCD934X_DATA_HUB_I2S_0_TDM_CTL 0x0087 +#define WCD934X_DATA_HUB_I2S_STATUS 0x0088 +#define WCD934X_DMA_RDMA_CTL_0 0x0091 +#define WCD934X_DMA_CH_2_3_CFG_RDMA_0 0x0092 +#define WCD934X_DMA_CH_0_1_CFG_RDMA_0 0x0093 +#define WCD934X_DMA_RDMA_CTL_1 0x0094 +#define WCD934X_DMA_CH_2_3_CFG_RDMA_1 0x0095 +#define WCD934X_DMA_CH_0_1_CFG_RDMA_1 0x0096 +#define WCD934X_DMA_RDMA_CTL_2 0x0097 +#define WCD934X_DMA_CH_2_3_CFG_RDMA_2 0x0098 +#define WCD934X_DMA_CH_0_1_CFG_RDMA_2 0x0099 +#define WCD934X_DMA_RDMA_CTL_3 0x009A +#define WCD934X_DMA_CH_2_3_CFG_RDMA_3 0x009B +#define WCD934X_DMA_CH_0_1_CFG_RDMA_3 0x009C +#define WCD934X_DMA_RDMA_CTL_4 0x009D +#define WCD934X_DMA_CH_2_3_CFG_RDMA_4 0x009E +#define WCD934X_DMA_CH_0_1_CFG_RDMA_4 0x009F +#define WCD934X_DMA_RDMA4_PRT_CFG 0x00b1 +#define WCD934X_DMA_RDMA_SBTX0_7_CFG 0x00b9 +#define WCD934X_DMA_RDMA_SBTX8_11_CFG 0x00ba +#define WCD934X_DMA_WDMA_CTL_0 0x00c1 +#define WCD934X_DMA_CH_4_5_CFG_WDMA_0 0x00c2 +#define WCD934X_DMA_CH_2_3_CFG_WDMA_0 0x00c3 +#define WCD934X_DMA_CH_0_1_CFG_WDMA_0 0x00c4 +#define WCD934X_DMA_WDMA_CTL_1 0x00C6 +#define WCD934X_DMA_CH_4_5_CFG_WDMA_1 0x00C7 +#define WCD934X_DMA_CH_2_3_CFG_WDMA_1 0x00C8 +#define WCD934X_DMA_CH_0_1_CFG_WDMA_1 0x00C9 +#define WCD934X_DMA_WDMA_CTL_2 0x00CB +#define WCD934X_DMA_CH_4_5_CFG_WDMA_2 0x00CC +#define WCD934X_DMA_CH_2_3_CFG_WDMA_2 0x00CD +#define WCD934X_DMA_CH_0_1_CFG_WDMA_2 0x00CE +#define WCD934X_DMA_WDMA_CTL_3 0x00D0 +#define WCD934X_DMA_CH_4_5_CFG_WDMA_3 0x00D1 +#define WCD934X_DMA_CH_2_3_CFG_WDMA_3 0x00D2 +#define WCD934X_DMA_CH_0_1_CFG_WDMA_3 0x00D3 +#define WCD934X_DMA_WDMA_CTL_4 0x00D5 +#define WCD934X_DMA_CH_4_5_CFG_WDMA_4 0x00D6 +#define WCD934X_DMA_CH_2_3_CFG_WDMA_4 0x00D7 +#define WCD934X_DMA_CH_0_1_CFG_WDMA_4 0x00D8 +#define WCD934X_DMA_WDMA0_PRT_CFG 0x00E1 +#define WCD934X_DMA_WDMA3_PRT_CFG 0x00E2 +#define WCD934X_DMA_WDMA4_PRT0_3_CFG 0x00E3 +#define WCD934X_DMA_WDMA4_PRT4_7_CFG 0x00E4 +#define WCD934X_PAGE1_PAGE_REGISTER 0x0100 +#define WCD934X_CPE_FLL_USER_CTL_0 0x0101 +#define WCD934X_CPE_FLL_USER_CTL_1 0x0102 +#define WCD934X_CPE_FLL_USER_CTL_2 0x0103 +#define WCD934X_CPE_FLL_USER_CTL_3 0x0104 +#define WCD934X_CPE_FLL_USER_CTL_4 0x0105 +#define WCD934X_CPE_FLL_USER_CTL_5 0x0106 +#define WCD934X_CPE_FLL_USER_CTL_6 0x0107 +#define WCD934X_CPE_FLL_USER_CTL_7 0x0108 +#define WCD934X_CPE_FLL_USER_CTL_8 0x0109 +#define WCD934X_CPE_FLL_USER_CTL_9 0x010a +#define WCD934X_CPE_FLL_L_VAL_CTL_0 0x010b +#define WCD934X_CPE_FLL_L_VAL_CTL_1 0x010c +#define WCD934X_CPE_FLL_DSM_FRAC_CTL_0 0x010d +#define WCD934X_CPE_FLL_DSM_FRAC_CTL_1 0x010e +#define WCD934X_CPE_FLL_CONFIG_CTL_0 0x010f +#define WCD934X_CPE_FLL_CONFIG_CTL_1 0x0110 +#define WCD934X_CPE_FLL_CONFIG_CTL_2 0x0111 +#define WCD934X_CPE_FLL_CONFIG_CTL_3 0x0112 +#define WCD934X_CPE_FLL_CONFIG_CTL_4 0x0113 +#define WCD934X_CPE_FLL_TEST_CTL_0 0x0114 +#define WCD934X_CPE_FLL_TEST_CTL_1 0x0115 +#define WCD934X_CPE_FLL_TEST_CTL_2 0x0116 +#define WCD934X_CPE_FLL_TEST_CTL_3 0x0117 +#define WCD934X_CPE_FLL_TEST_CTL_4 0x0118 +#define WCD934X_CPE_FLL_TEST_CTL_5 0x0119 +#define WCD934X_CPE_FLL_TEST_CTL_6 0x011a +#define WCD934X_CPE_FLL_TEST_CTL_7 0x011b +#define WCD934X_CPE_FLL_FREQ_CTL_0 0x011c +#define WCD934X_CPE_FLL_FREQ_CTL_1 0x011d +#define WCD934X_CPE_FLL_FREQ_CTL_2 0x011e +#define WCD934X_CPE_FLL_FREQ_CTL_3 0x011f +#define WCD934X_CPE_FLL_SSC_CTL_0 0x0120 +#define WCD934X_CPE_FLL_SSC_CTL_1 0x0121 +#define WCD934X_CPE_FLL_SSC_CTL_2 0x0122 +#define WCD934X_CPE_FLL_SSC_CTL_3 0x0123 +#define WCD934X_CPE_FLL_FLL_MODE 0x0124 +#define WCD934X_CPE_FLL_STATUS_0 0x0125 +#define WCD934X_CPE_FLL_STATUS_1 0x0126 +#define WCD934X_CPE_FLL_STATUS_2 0x0127 +#define WCD934X_CPE_FLL_STATUS_3 0x0128 +#define WCD934X_I2S_FLL_USER_CTL_0 0x0141 +#define WCD934X_I2S_FLL_USER_CTL_1 0x0142 +#define WCD934X_I2S_FLL_USER_CTL_2 0x0143 +#define WCD934X_I2S_FLL_USER_CTL_3 0x0144 +#define WCD934X_I2S_FLL_USER_CTL_4 0x0145 +#define WCD934X_I2S_FLL_USER_CTL_5 0x0146 +#define WCD934X_I2S_FLL_USER_CTL_6 0x0147 +#define WCD934X_I2S_FLL_USER_CTL_7 0x0148 +#define WCD934X_I2S_FLL_USER_CTL_8 0x0149 +#define WCD934X_I2S_FLL_USER_CTL_9 0x014a +#define WCD934X_I2S_FLL_L_VAL_CTL_0 0x014b +#define WCD934X_I2S_FLL_L_VAL_CTL_1 0x014c +#define WCD934X_I2S_FLL_DSM_FRAC_CTL_0 0x014d +#define WCD934X_I2S_FLL_DSM_FRAC_CTL_1 0x014e +#define WCD934X_I2S_FLL_CONFIG_CTL_0 0x014f +#define WCD934X_I2S_FLL_CONFIG_CTL_1 0x0150 +#define WCD934X_I2S_FLL_CONFIG_CTL_2 0x0151 +#define WCD934X_I2S_FLL_CONFIG_CTL_3 0x0152 +#define WCD934X_I2S_FLL_CONFIG_CTL_4 0x0153 +#define WCD934X_I2S_FLL_TEST_CTL_0 0x0154 +#define WCD934X_I2S_FLL_TEST_CTL_1 0x0155 +#define WCD934X_I2S_FLL_TEST_CTL_2 0x0156 +#define WCD934X_I2S_FLL_TEST_CTL_3 0x0157 +#define WCD934X_I2S_FLL_TEST_CTL_4 0x0158 +#define WCD934X_I2S_FLL_TEST_CTL_5 0x0159 +#define WCD934X_I2S_FLL_TEST_CTL_6 0x015a +#define WCD934X_I2S_FLL_TEST_CTL_7 0x015b +#define WCD934X_I2S_FLL_FREQ_CTL_0 0x015c +#define WCD934X_I2S_FLL_FREQ_CTL_1 0x015d +#define WCD934X_I2S_FLL_FREQ_CTL_2 0x015e +#define WCD934X_I2S_FLL_FREQ_CTL_3 0x015f +#define WCD934X_I2S_FLL_SSC_CTL_0 0x0160 +#define WCD934X_I2S_FLL_SSC_CTL_1 0x0161 +#define WCD934X_I2S_FLL_SSC_CTL_2 0x0162 +#define WCD934X_I2S_FLL_SSC_CTL_3 0x0163 +#define WCD934X_I2S_FLL_FLL_MODE 0x0164 +#define WCD934X_I2S_FLL_STATUS_0 0x0165 +#define WCD934X_I2S_FLL_STATUS_1 0x0166 +#define WCD934X_I2S_FLL_STATUS_2 0x0167 +#define WCD934X_I2S_FLL_STATUS_3 0x0168 +#define WCD934X_SB_FLL_USER_CTL_0 0x0181 +#define WCD934X_SB_FLL_USER_CTL_1 0x0182 +#define WCD934X_SB_FLL_USER_CTL_2 0x0183 +#define WCD934X_SB_FLL_USER_CTL_3 0x0184 +#define WCD934X_SB_FLL_USER_CTL_4 0x0185 +#define WCD934X_SB_FLL_USER_CTL_5 0x0186 +#define WCD934X_SB_FLL_USER_CTL_6 0x0187 +#define WCD934X_SB_FLL_USER_CTL_7 0x0188 +#define WCD934X_SB_FLL_USER_CTL_8 0x0189 +#define WCD934X_SB_FLL_USER_CTL_9 0x018a +#define WCD934X_SB_FLL_L_VAL_CTL_0 0x018b +#define WCD934X_SB_FLL_L_VAL_CTL_1 0x018c +#define WCD934X_SB_FLL_DSM_FRAC_CTL_0 0x018d +#define WCD934X_SB_FLL_DSM_FRAC_CTL_1 0x018e +#define WCD934X_SB_FLL_CONFIG_CTL_0 0x018f +#define WCD934X_SB_FLL_CONFIG_CTL_1 0x0190 +#define WCD934X_SB_FLL_CONFIG_CTL_2 0x0191 +#define WCD934X_SB_FLL_CONFIG_CTL_3 0x0192 +#define WCD934X_SB_FLL_CONFIG_CTL_4 0x0193 +#define WCD934X_SB_FLL_TEST_CTL_0 0x0194 +#define WCD934X_SB_FLL_TEST_CTL_1 0x0195 +#define WCD934X_SB_FLL_TEST_CTL_2 0x0196 +#define WCD934X_SB_FLL_TEST_CTL_3 0x0197 +#define WCD934X_SB_FLL_TEST_CTL_4 0x0198 +#define WCD934X_SB_FLL_TEST_CTL_5 0x0199 +#define WCD934X_SB_FLL_TEST_CTL_6 0x019a +#define WCD934X_SB_FLL_TEST_CTL_7 0x019b +#define WCD934X_SB_FLL_FREQ_CTL_0 0x019c +#define WCD934X_SB_FLL_FREQ_CTL_1 0x019d +#define WCD934X_SB_FLL_FREQ_CTL_2 0x019e +#define WCD934X_SB_FLL_FREQ_CTL_3 0x019f +#define WCD934X_SB_FLL_SSC_CTL_0 0x01a0 +#define WCD934X_SB_FLL_SSC_CTL_1 0x01a1 +#define WCD934X_SB_FLL_SSC_CTL_2 0x01a2 +#define WCD934X_SB_FLL_SSC_CTL_3 0x01a3 +#define WCD934X_SB_FLL_FLL_MODE 0x01a4 +#define WCD934X_SB_FLL_STATUS_0 0x01a5 +#define WCD934X_SB_FLL_STATUS_1 0x01a6 +#define WCD934X_SB_FLL_STATUS_2 0x01a7 +#define WCD934X_SB_FLL_STATUS_3 0x01a8 +#define WCD934X_PAGE2_PAGE_REGISTER 0x0200 +#define WCD934X_CPE_SS_CPE_CTL 0x0201 +#define WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_0 0x0202 +#define WCD934X_CPE_SS_PWR_SYS_PSTATE_CTL_1 0x0203 +#define WCD934X_CPE_SS_PWR_CPEFLL_CTL 0x0204 +#define WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_0 0x0205 +#define WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_1 0x0206 +#define WCD934X_CPE_SS_PWR_CPE_SYSMEM_DEEPSLP_OVERRIDE 0x0207 +#define WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_0 0x0208 +#define WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_1 0x0209 +#define WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_2 0x020a +#define WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_3 0x020b +#define WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_4 0x020c +#define WCD934X_CPE_SS_PWR_CPE_SYSMEM_SHUTDOWN_5 0x020d +#define WCD934X_CPE_SS_PWR_CPE_DRAM1_SHUTDOWN 0x020e +#define WCD934X_CPE_SS_SOC_SW_COLLAPSE_CTL 0x020f +#define WCD934X_CPE_SS_SOC_SW_COLLAPSE_OVERRIDE_CTL 0x0210 +#define WCD934X_CPE_SS_SOC_SW_COLLAPSE_OVERRIDE_CTL1 0x0211 +#define WCD934X_CPE_SS_US_BUF_INT_PERIOD 0x0212 +#define WCD934X_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD 0x0213 +#define WCD934X_CPE_SS_SVA_CFG 0x0214 +#define WCD934X_CPE_SS_US_CFG 0x0215 +#define WCD934X_CPE_SS_MAD_CTL 0x0216 +#define WCD934X_CPE_SS_CPAR_CTL 0x0217 +#define WCD934X_CPE_SS_DMIC0_CTL 0x0218 +#define WCD934X_CPE_SS_DMIC1_CTL 0x0219 +#define WCD934X_CPE_SS_DMIC2_CTL 0x021a +#define WCD934X_CPE_SS_DMIC_CFG 0x021b +#define WCD934X_CPE_SS_CPAR_CFG 0x021c +#define WCD934X_CPE_SS_WDOG_CFG 0x021d +#define WCD934X_CPE_SS_BACKUP_INT 0x021e +#define WCD934X_CPE_SS_STATUS 0x021f +#define WCD934X_CPE_SS_CPE_OCD_CFG 0x0220 +#define WCD934X_CPE_SS_SS_ERROR_INT_MASK_0A 0x0221 +#define WCD934X_CPE_SS_SS_ERROR_INT_MASK_0B 0x0222 +#define WCD934X_CPE_SS_SS_ERROR_INT_MASK_1A 0x0223 +#define WCD934X_CPE_SS_SS_ERROR_INT_MASK_1B 0x0224 +#define WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0A 0x0225 +#define WCD934X_CPE_SS_SS_ERROR_INT_STATUS_0B 0x0226 +#define WCD934X_CPE_SS_SS_ERROR_INT_STATUS_1A 0x0227 +#define WCD934X_CPE_SS_SS_ERROR_INT_STATUS_1B 0x0228 +#define WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_0A 0x0229 +#define WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_0B 0x022a +#define WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_1A 0x022b +#define WCD934X_CPE_SS_SS_ERROR_INT_CLEAR_1B 0x022c +#define WCD934X_SOC_MAD_MAIN_CTL_1 0x0281 +#define WCD934X_SOC_MAD_MAIN_CTL_2 0x0282 +#define WCD934X_SOC_MAD_AUDIO_CTL_1 0x0283 +#define WCD934X_SOC_MAD_AUDIO_CTL_2 0x0284 +#define WCD934X_SOC_MAD_AUDIO_CTL_3 0x0285 +#define WCD934X_SOC_MAD_AUDIO_CTL_4 0x0286 +#define WCD934X_SOC_MAD_AUDIO_CTL_5 0x0287 +#define WCD934X_SOC_MAD_AUDIO_CTL_6 0x0288 +#define WCD934X_SOC_MAD_AUDIO_CTL_7 0x0289 +#define WCD934X_SOC_MAD_AUDIO_CTL_8 0x028a +#define WCD934X_SOC_MAD_AUDIO_IIR_CTL_PTR 0x028b +#define WCD934X_SOC_MAD_AUDIO_IIR_CTL_VAL 0x028c +#define WCD934X_SOC_MAD_ULTR_CTL_1 0x028d +#define WCD934X_SOC_MAD_ULTR_CTL_2 0x028e +#define WCD934X_SOC_MAD_ULTR_CTL_3 0x028f +#define WCD934X_SOC_MAD_ULTR_CTL_4 0x0290 +#define WCD934X_SOC_MAD_ULTR_CTL_5 0x0291 +#define WCD934X_SOC_MAD_ULTR_CTL_6 0x0292 +#define WCD934X_SOC_MAD_ULTR_CTL_7 0x0293 +#define WCD934X_SOC_MAD_BEACON_CTL_1 0x0294 +#define WCD934X_SOC_MAD_BEACON_CTL_2 0x0295 +#define WCD934X_SOC_MAD_BEACON_CTL_3 0x0296 +#define WCD934X_SOC_MAD_BEACON_CTL_4 0x0297 +#define WCD934X_SOC_MAD_BEACON_CTL_5 0x0298 +#define WCD934X_SOC_MAD_BEACON_CTL_6 0x0299 +#define WCD934X_SOC_MAD_BEACON_CTL_7 0x029a +#define WCD934X_SOC_MAD_BEACON_CTL_8 0x029b +#define WCD934X_SOC_MAD_BEACON_IIR_CTL_PTR 0x029c +#define WCD934X_SOC_MAD_BEACON_IIR_CTL_VAL 0x029d +#define WCD934X_SOC_MAD_INP_SEL 0x029e +#define WCD934X_PAGE4_PAGE_REGISTER 0x0400 +#define WCD934X_INTR_CFG 0x0401 +#define WCD934X_INTR_CLR_COMMIT 0x0402 +#define WCD934X_INTR_PIN1_MASK0 0x0409 +#define WCD934X_INTR_PIN1_MASK1 0x040a +#define WCD934X_INTR_PIN1_MASK2 0x040b +#define WCD934X_INTR_PIN1_MASK3 0x040c +#define WCD934X_INTR_PIN1_STATUS0 0x0411 +#define WCD934X_INTR_PIN1_STATUS1 0x0412 +#define WCD934X_INTR_PIN1_STATUS2 0x0413 +#define WCD934X_INTR_PIN1_STATUS3 0x0414 +#define WCD934X_INTR_PIN1_CLEAR0 0x0419 +#define WCD934X_INTR_PIN1_CLEAR1 0x041a +#define WCD934X_INTR_PIN1_CLEAR2 0x041b +#define WCD934X_INTR_PIN1_CLEAR3 0x041c +#define WCD934X_INTR_PIN2_MASK3 0x0424 +#define WCD934X_INTR_PIN2_STATUS3 0x042c +#define WCD934X_INTR_PIN2_CLEAR3 0x0434 +#define WCD934X_INTR_CPESS_SUMRY_MASK2 0x043b +#define WCD934X_INTR_CPESS_SUMRY_MASK3 0x043c +#define WCD934X_INTR_CPESS_SUMRY_STATUS2 0x0443 +#define WCD934X_INTR_CPESS_SUMRY_STATUS3 0x0444 +#define WCD934X_INTR_CPESS_SUMRY_CLEAR2 0x044b +#define WCD934X_INTR_CPESS_SUMRY_CLEAR3 0x044c +#define WCD934X_INTR_LEVEL0 0x0461 +#define WCD934X_INTR_LEVEL1 0x0462 +#define WCD934X_INTR_LEVEL2 0x0463 +#define WCD934X_INTR_LEVEL3 0x0464 +#define WCD934X_INTR_BYPASS0 0x0469 +#define WCD934X_INTR_BYPASS1 0x046a +#define WCD934X_INTR_BYPASS2 0x046b +#define WCD934X_INTR_BYPASS3 0x046c +#define WCD934X_INTR_SET0 0x0471 +#define WCD934X_INTR_SET1 0x0472 +#define WCD934X_INTR_SET2 0x0473 +#define WCD934X_INTR_SET3 0x0474 +#define WCD934X_INTR_CODEC_MISC_MASK 0x04b1 +#define WCD934X_INTR_CODEC_MISC_STATUS 0x04b2 +#define WCD934X_INTR_CODEC_MISC_CLEAR 0x04b3 +#define WCD934X_PAGE5_PAGE_REGISTER 0x0500 +#define WCD934X_SLNQ_DIG_DEVICE 0x0501 +#define WCD934X_SLNQ_DIG_REVISION 0x0502 +#define WCD934X_SLNQ_DIG_H_COMMAND 0x0511 +#define WCD934X_SLNQ_DIG_NUMBER_OF_BYTE_MSB 0x0512 +#define WCD934X_SLNQ_DIG_NUMBER_OF_BYTE_LSB 0x0513 +#define WCD934X_SLNQ_DIG_MASTER_ADDRESS_MSB 0x0514 +#define WCD934X_SLNQ_DIG_MASTER_ADDRESS_LSB 0x0515 +#define WCD934X_SLNQ_DIG_SLAVE_ADDRESS_MSB 0x0516 +#define WCD934X_SLNQ_DIG_SLAVE_ADDRESS_LSB 0x0517 +#define WCD934X_SLNQ_DIG_TIMER0_INTERRUPT_MSB 0x0518 +#define WCD934X_SLNQ_DIG_TIMER0_INTERRUPT_LSB 0x0519 +#define WCD934X_SLNQ_DIG_TIMER1_INTERRUPT_MSB 0x051a +#define WCD934X_SLNQ_DIG_TIMER1_INTERRUPT_LSB 0x051b +#define WCD934X_SLNQ_DIG_TIMER2_INTERRUPT_MSB 0x051c +#define WCD934X_SLNQ_DIG_TIMER2_INTERRUPT_LSB 0x051d +#define WCD934X_SLNQ_DIG_COMM_CTL 0x0520 +#define WCD934X_SLNQ_DIG_FRAME_CTRL 0x0542 +#define WCD934X_SLNQ_DIG_PDM_2ND_DATA_CH1_2 0x055c +#define WCD934X_SLNQ_DIG_PDM_2ND_DATA_CH3_4 0x055d +#define WCD934X_SLNQ_DIG_PDM_2ND_DATA_CH5 0x055e +#define WCD934X_SLNQ_DIG_SW_EVENT_RD 0x0561 +#define WCD934X_SLNQ_DIG_SW_EVENT_CTRL 0x0562 +#define WCD934X_SLNQ_DIG_PDM_SELECT_1 0x0563 +#define WCD934X_SLNQ_DIG_PDM_SELECT_2 0x0564 +#define WCD934X_SLNQ_DIG_PDM_SELECT_3 0x0565 +#define WCD934X_SLNQ_DIG_PDM_SAMPLING_FREQ 0x0566 +#define WCD934X_SLNQ_DIG_PDM_DC_CONVERSION_CTL 0x0569 +#define WCD934X_SLNQ_DIG_PDM_DC_CONVERSION_SEL 0x056a +#define WCD934X_SLNQ_DIG_PDM_DC_CONV_CHA_MSB 0x056b +#define WCD934X_SLNQ_DIG_PDM_DC_CONV_CHA_LSB 0x056c +#define WCD934X_SLNQ_DIG_PDM_DC_CONV_CHB_MSB 0x056d +#define WCD934X_SLNQ_DIG_PDM_DC_CONV_CHB_LSB 0x056e +#define WCD934X_SLNQ_DIG_RAM_CNTRL 0x0571 +#define WCD934X_SLNQ_DIG_SRAM_BANK 0x0572 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_0 0x0573 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_1 0x0574 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_2 0x0575 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_3 0x0576 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_4 0x0577 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_5 0x0578 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_6 0x0579 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_7 0x057a +#define WCD934X_SLNQ_DIG_SRAM_BYTE_8 0x057b +#define WCD934X_SLNQ_DIG_SRAM_BYTE_9 0x057c +#define WCD934X_SLNQ_DIG_SRAM_BYTE_A 0x057d +#define WCD934X_SLNQ_DIG_SRAM_BYTE_B 0x057e +#define WCD934X_SLNQ_DIG_SRAM_BYTE_C 0x057f +#define WCD934X_SLNQ_DIG_SRAM_BYTE_D 0x0580 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_E 0x0581 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_F 0x0582 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_10 0x0583 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_11 0x0584 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_12 0x0585 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_13 0x0586 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_14 0x0587 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_15 0x0588 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_16 0x0589 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_17 0x058a +#define WCD934X_SLNQ_DIG_SRAM_BYTE_18 0x058b +#define WCD934X_SLNQ_DIG_SRAM_BYTE_19 0x058c +#define WCD934X_SLNQ_DIG_SRAM_BYTE_1A 0x058d +#define WCD934X_SLNQ_DIG_SRAM_BYTE_1B 0x058e +#define WCD934X_SLNQ_DIG_SRAM_BYTE_1C 0x058f +#define WCD934X_SLNQ_DIG_SRAM_BYTE_1D 0x0590 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_1E 0x0591 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_1F 0x0592 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_20 0x0593 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_21 0x0594 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_22 0x0595 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_23 0x0596 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_24 0x0597 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_25 0x0598 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_26 0x0599 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_27 0x059a +#define WCD934X_SLNQ_DIG_SRAM_BYTE_28 0x059b +#define WCD934X_SLNQ_DIG_SRAM_BYTE_29 0x059c +#define WCD934X_SLNQ_DIG_SRAM_BYTE_2A 0x059d +#define WCD934X_SLNQ_DIG_SRAM_BYTE_2B 0x059e +#define WCD934X_SLNQ_DIG_SRAM_BYTE_2C 0x059f +#define WCD934X_SLNQ_DIG_SRAM_BYTE_2D 0x05a0 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_2E 0x05a1 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_2F 0x05a2 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_30 0x05a3 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_31 0x05a4 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_32 0x05a5 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_33 0x05a6 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_34 0x05a7 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_35 0x05a8 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_36 0x05a9 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_37 0x05aa +#define WCD934X_SLNQ_DIG_SRAM_BYTE_38 0x05ab +#define WCD934X_SLNQ_DIG_SRAM_BYTE_39 0x05ac +#define WCD934X_SLNQ_DIG_SRAM_BYTE_3A 0x05ad +#define WCD934X_SLNQ_DIG_SRAM_BYTE_3B 0x05ae +#define WCD934X_SLNQ_DIG_SRAM_BYTE_3C 0x05af +#define WCD934X_SLNQ_DIG_SRAM_BYTE_3D 0x05b0 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_3E 0x05b1 +#define WCD934X_SLNQ_DIG_SRAM_BYTE_3F 0x05b2 +#define WCD934X_SLNQ_DIG_TOP_CTRL1 0x05b3 +#define WCD934X_SLNQ_DIG_TOP_CTRL2 0x05b4 +#define WCD934X_SLNQ_DIG_PDM_CTRL 0x05b5 +#define WCD934X_SLNQ_DIG_PDM_MUTE_CTRL 0x05b6 +#define WCD934X_SLNQ_DIG_DEC_BYPASS_CTRL 0x05b7 +#define WCD934X_SLNQ_DIG_DEC_BYPASS_STATUS 0x05b8 +#define WCD934X_SLNQ_DIG_DEC_BYPASS_FS 0x05b9 +#define WCD934X_SLNQ_DIG_DEC_BYPASS_IN_SEL 0x05ba +#define WCD934X_SLNQ_DIG_GPOUT_ENABLE 0x05bb +#define WCD934X_SLNQ_DIG_GPOUT_VAL 0x05bc +#define WCD934X_SLNQ_DIG_ANA_INTERRUPT_MASK 0x05be +#define WCD934X_SLNQ_DIG_ANA_INTERRUPT_STATUS 0x05bf +#define WCD934X_SLNQ_DIG_ANA_INTERRUPT_CLR 0x05c0 +#define WCD934X_SLNQ_DIG_IP_TESTING 0x05c1 +#define WCD934X_SLNQ_DIG_INTERRUPT_CNTRL 0x05e3 +#define WCD934X_SLNQ_DIG_INTERRUPT_CNT 0x05e9 +#define WCD934X_SLNQ_DIG_INTERRUPT_CNT_MSB 0x05eb +#define WCD934X_SLNQ_DIG_INTERRUPT_CNT_LSB 0x05ec +#define WCD934X_SLNQ_DIG_INTERRUPT_MASK0 0x05f1 +#define WCD934X_SLNQ_DIG_INTERRUPT_MASK1 0x05f2 +#define WCD934X_SLNQ_DIG_INTERRUPT_MASK2 0x05f3 +#define WCD934X_SLNQ_DIG_INTERRUPT_MASK3 0x05f4 +#define WCD934X_SLNQ_DIG_INTERRUPT_MASK4 0x05f5 +#define WCD934X_SLNQ_DIG_INTERRUPT_STATUS0 0x05f6 +#define WCD934X_SLNQ_DIG_INTERRUPT_STATUS1 0x05f7 +#define WCD934X_SLNQ_DIG_INTERRUPT_STATUS2 0x05f8 +#define WCD934X_SLNQ_DIG_INTERRUPT_STATUS3 0x05f9 +#define WCD934X_SLNQ_DIG_INTERRUPT_STATUS4 0x05fa +#define WCD934X_SLNQ_DIG_INTERRUPT_CLR0 0x05fb +#define WCD934X_SLNQ_DIG_INTERRUPT_CLR1 0x05fc +#define WCD934X_SLNQ_DIG_INTERRUPT_CLR2 0x05fd +#define WCD934X_SLNQ_DIG_INTERRUPT_CLR3 0x05fe +#define WCD934X_SLNQ_DIG_INTERRUPT_CLR4 0x05ff +#define WCD934X_ANA_PAGE_REGISTER 0x0600 +#define WCD934X_ANA_BIAS 0x0601 +#define WCD934X_ANA_RCO 0x0603 +#define WCD934X_ANA_PAGE6_SPARE2 0x0604 +#define WCD934X_ANA_PAGE6_SPARE3 0x0605 +#define WCD934X_ANA_BUCK_CTL 0x0606 +#define WCD934X_ANA_BUCK_STATUS 0x0607 +#define WCD934X_ANA_RX_SUPPLIES 0x0608 +#define WCD934X_ANA_HPH 0x0609 +#define WCD934X_ANA_EAR 0x060a +#define WCD934X_ANA_LO_1_2 0x060b +#define WCD934X_ANA_MAD_SETUP 0x060d +#define WCD934X_ANA_AMIC1 0x060e +#define WCD934X_ANA_AMIC2 0x060f +#define WCD934X_ANA_AMIC3 0x0610 +#define WCD934X_ANA_AMIC4 0x0611 +#define WCD934X_ANA_MBHC_MECH 0x0614 +#define WCD934X_ANA_MBHC_ELECT 0x0615 +#define WCD934X_ANA_MBHC_ZDET 0x0616 +#define WCD934X_ANA_MBHC_RESULT_1 0x0617 +#define WCD934X_ANA_MBHC_RESULT_2 0x0618 +#define WCD934X_ANA_MBHC_RESULT_3 0x0619 +#define WCD934X_ANA_MBHC_BTN0 0x061a +#define WCD934X_ANA_MBHC_BTN1 0x061b +#define WCD934X_ANA_MBHC_BTN2 0x061c +#define WCD934X_ANA_MBHC_BTN3 0x061d +#define WCD934X_ANA_MBHC_BTN4 0x061e +#define WCD934X_ANA_MBHC_BTN5 0x061f +#define WCD934X_ANA_MBHC_BTN6 0x0620 +#define WCD934X_ANA_MBHC_BTN7 0x0621 +#define WCD934X_ANA_MICB1 0x0622 +#define WCD934X_ANA_MICB2 0x0623 +#define WCD934X_ANA_MICB2_RAMP 0x0624 +#define WCD934X_ANA_MICB3 0x0625 +#define WCD934X_ANA_MICB4 0x0626 +#define WCD934X_ANA_VBADC 0x0627 +#define WCD934X_BIAS_CTL 0x0628 +#define WCD934X_BIAS_VBG_FINE_ADJ 0x0629 +#define WCD934X_RCO_CTRL_1 0x062e +#define WCD934X_RCO_CTRL_2 0x062f +#define WCD934X_RCO_CAL 0x0630 +#define WCD934X_RCO_CAL_1 0x0631 +#define WCD934X_RCO_CAL_2 0x0632 +#define WCD934X_RCO_TEST_CTRL 0x0633 +#define WCD934X_RCO_CAL_OUT_1 0x0634 +#define WCD934X_RCO_CAL_OUT_2 0x0635 +#define WCD934X_RCO_CAL_OUT_3 0x0636 +#define WCD934X_RCO_CAL_OUT_4 0x0637 +#define WCD934X_RCO_CAL_OUT_5 0x0638 +#define WCD934X_SIDO_MODE_1 0x063a +#define WCD934X_SIDO_MODE_2 0x063b +#define WCD934X_SIDO_MODE_3 0x063c +#define WCD934X_SIDO_MODE_4 0x063d +#define WCD934X_SIDO_VCL_1 0x063e +#define WCD934X_SIDO_VCL_2 0x063f +#define WCD934X_SIDO_VCL_3 0x0640 +#define WCD934X_SIDO_CCL_1 0x0641 +#define WCD934X_SIDO_CCL_2 0x0642 +#define WCD934X_SIDO_CCL_3 0x0643 +#define WCD934X_SIDO_CCL_4 0x0644 +#define WCD934X_SIDO_CCL_5 0x0645 +#define WCD934X_SIDO_CCL_6 0x0646 +#define WCD934X_SIDO_CCL_7 0x0647 +#define WCD934X_SIDO_CCL_8 0x0648 +#define WCD934X_SIDO_CCL_9 0x0649 +#define WCD934X_SIDO_CCL_10 0x064a +#define WCD934X_SIDO_FILTER_1 0x064b +#define WCD934X_SIDO_FILTER_2 0x064c +#define WCD934X_SIDO_DRIVER_1 0x064d +#define WCD934X_SIDO_DRIVER_2 0x064e +#define WCD934X_SIDO_DRIVER_3 0x064f +#define WCD934X_SIDO_CAL_CODE_EXT_1 0x0650 +#define WCD934X_SIDO_CAL_CODE_EXT_2 0x0651 +#define WCD934X_SIDO_CAL_CODE_OUT_1 0x0652 +#define WCD934X_SIDO_CAL_CODE_OUT_2 0x0653 +#define WCD934X_SIDO_TEST_1 0x0654 +#define WCD934X_SIDO_TEST_2 0x0655 +#define WCD934X_MBHC_CTL_CLK 0x0656 +#define WCD934X_MBHC_CTL_ANA 0x0657 +#define WCD934X_MBHC_CTL_SPARE_1 0x0658 +#define WCD934X_MBHC_CTL_SPARE_2 0x0659 +#define WCD934X_MBHC_CTL_BCS 0x065a +#define WCD934X_MBHC_STATUS_SPARE_1 0x065b +#define WCD934X_MBHC_TEST_CTL 0x065c +#define WCD934X_VBADC_SUBBLOCK_EN 0x065d +#define WCD934X_VBADC_IBIAS_FE 0x065e +#define WCD934X_VBADC_BIAS_ADC 0x065f +#define WCD934X_VBADC_FE_CTRL 0x0660 +#define WCD934X_VBADC_ADC_REF 0x0661 +#define WCD934X_VBADC_ADC_IO 0x0662 +#define WCD934X_VBADC_ADC_SAR 0x0663 +#define WCD934X_VBADC_DEBUG 0x0664 +#define WCD934X_LDOH_MODE 0x0667 +#define WCD934X_LDOH_BIAS 0x0668 +#define WCD934X_LDOH_STB_LOADS 0x0669 +#define WCD934X_LDOH_SLOWRAMP 0x066a +#define WCD934X_MICB1_TEST_CTL_1 0x066b +#define WCD934X_MICB1_TEST_CTL_2 0x066c +#define WCD934X_MICB1_TEST_CTL_3 0x066d +#define WCD934X_MICB2_TEST_CTL_1 0x066e +#define WCD934X_MICB2_TEST_CTL_2 0x066f +#define WCD934X_MICB2_TEST_CTL_3 0x0670 +#define WCD934X_MICB3_TEST_CTL_1 0x0671 +#define WCD934X_MICB3_TEST_CTL_2 0x0672 +#define WCD934X_MICB3_TEST_CTL_3 0x0673 +#define WCD934X_MICB4_TEST_CTL_1 0x0674 +#define WCD934X_MICB4_TEST_CTL_2 0x0675 +#define WCD934X_MICB4_TEST_CTL_3 0x0676 +#define WCD934X_TX_COM_ADC_VCM 0x0677 +#define WCD934X_TX_COM_BIAS_ATEST 0x0678 +#define WCD934X_TX_COM_ADC_INT1_IB 0x0679 +#define WCD934X_TX_COM_ADC_INT2_IB 0x067a +#define WCD934X_TX_COM_TXFE_DIV_CTL 0x067b +#define WCD934X_TX_COM_TXFE_DIV_START 0x067c +#define WCD934X_TX_COM_TXFE_DIV_STOP_9P6M 0x067d +#define WCD934X_TX_COM_TXFE_DIV_STOP_12P288M 0x067e +#define WCD934X_TX_1_2_TEST_EN 0x067f +#define WCD934X_TX_1_2_ADC_IB 0x0680 +#define WCD934X_TX_1_2_ATEST_REFCTL 0x0681 +#define WCD934X_TX_1_2_TEST_CTL 0x0682 +#define WCD934X_TX_1_2_TEST_BLK_EN 0x0683 +#define WCD934X_TX_1_2_TXFE_CLKDIV 0x0684 +#define WCD934X_TX_1_2_SAR1_ERR 0x0685 +#define WCD934X_TX_1_2_SAR2_ERR 0x0686 +#define WCD934X_TX_3_4_TEST_EN 0x0687 +#define WCD934X_TX_3_4_ADC_IB 0x0688 +#define WCD934X_TX_3_4_ATEST_REFCTL 0x0689 +#define WCD934X_TX_3_4_TEST_CTL 0x068a +#define WCD934X_TX_3_4_TEST_BLK_EN 0x068b +#define WCD934X_TX_3_4_TXFE_CLKDIV 0x068c +#define WCD934X_TX_3_4_SAR1_ERR 0x068d +#define WCD934X_TX_3_4_SAR2_ERR 0x068e +#define WCD934X_CLASSH_MODE_1 0x0697 +#define WCD934X_CLASSH_MODE_2 0x0698 +#define WCD934X_CLASSH_MODE_3 0x0699 +#define WCD934X_CLASSH_CTRL_VCL_1 0x069a +#define WCD934X_CLASSH_CTRL_VCL_2 0x069b +#define WCD934X_CLASSH_CTRL_CCL_1 0x069c +#define WCD934X_CLASSH_CTRL_CCL_2 0x069d +#define WCD934X_CLASSH_CTRL_CCL_3 0x069e +#define WCD934X_CLASSH_CTRL_CCL_4 0x069f +#define WCD934X_CLASSH_CTRL_CCL_5 0x06a0 +#define WCD934X_CLASSH_BUCK_TMUX_A_D 0x06a1 +#define WCD934X_CLASSH_BUCK_SW_DRV_CNTL 0x06a2 +#define WCD934X_CLASSH_SPARE 0x06a3 +#define WCD934X_FLYBACK_EN 0x06a4 +#define WCD934X_FLYBACK_VNEG_CTRL_1 0x06a5 +#define WCD934X_FLYBACK_VNEG_CTRL_2 0x06a6 +#define WCD934X_FLYBACK_VNEG_CTRL_3 0x06a7 +#define WCD934X_FLYBACK_VNEG_CTRL_4 0x06a8 +#define WCD934X_FLYBACK_VNEG_CTRL_5 0x06a9 +#define WCD934X_FLYBACK_VNEG_CTRL_6 0x06aa +#define WCD934X_FLYBACK_VNEG_CTRL_7 0x06ab +#define WCD934X_FLYBACK_VNEG_CTRL_8 0x06ac +#define WCD934X_FLYBACK_VNEG_CTRL_9 0x06ad +#define WCD934X_FLYBACK_VNEGDAC_CTRL_1 0x06ae +#define WCD934X_FLYBACK_VNEGDAC_CTRL_2 0x06af +#define WCD934X_FLYBACK_VNEGDAC_CTRL_3 0x06b0 +#define WCD934X_FLYBACK_CTRL_1 0x06b1 +#define WCD934X_FLYBACK_TEST_CTL 0x06b2 +#define WCD934X_RX_AUX_SW_CTL 0x06b3 +#define WCD934X_RX_PA_AUX_IN_CONN 0x06b4 +#define WCD934X_RX_TIMER_DIV 0x06b5 +#define WCD934X_RX_OCP_CTL 0x06b6 +#define WCD934X_RX_OCP_COUNT 0x06b7 +#define WCD934X_RX_BIAS_EAR_DAC 0x06b8 +#define WCD934X_RX_BIAS_EAR_AMP 0x06b9 +#define WCD934X_RX_BIAS_HPH_LDO 0x06ba +#define WCD934X_RX_BIAS_HPH_PA 0x06bb +#define WCD934X_RX_BIAS_HPH_RDACBUFF_CNP2 0x06bc +#define WCD934X_RX_BIAS_HPH_RDAC_LDO 0x06bd +#define WCD934X_RX_BIAS_HPH_CNP1 0x06be +#define WCD934X_RX_BIAS_HPH_LOWPOWER 0x06bf +#define WCD934X_RX_BIAS_DIFFLO_PA 0x06c0 +#define WCD934X_RX_BIAS_DIFFLO_REF 0x06c1 +#define WCD934X_RX_BIAS_DIFFLO_LDO 0x06c2 +#define WCD934X_RX_BIAS_SELO_DAC_PA 0x06c3 +#define WCD934X_RX_BIAS_BUCK_RST 0x06c4 +#define WCD934X_RX_BIAS_BUCK_VREF_ERRAMP 0x06c5 +#define WCD934X_RX_BIAS_FLYB_ERRAMP 0x06c6 +#define WCD934X_RX_BIAS_FLYB_BUFF 0x06c7 +#define WCD934X_RX_BIAS_FLYB_MID_RST 0x06c8 +#define WCD934X_HPH_L_STATUS 0x06c9 +#define WCD934X_HPH_R_STATUS 0x06ca +#define WCD934X_HPH_CNP_EN 0x06cb +#define WCD934X_HPH_CNP_WG_CTL 0x06cc +#define WCD934X_HPH_CNP_WG_TIME 0x06cd +#define WCD934X_HPH_OCP_CTL 0x06ce +#define WCD934X_HPH_AUTO_CHOP 0x06cf +#define WCD934X_HPH_CHOP_CTL 0x06d0 +#define WCD934X_HPH_PA_CTL1 0x06d1 +#define WCD934X_HPH_PA_CTL2 0x06d2 +#define WCD934X_HPH_L_EN 0x06d3 +#define WCD934X_HPH_L_TEST 0x06d4 +#define WCD934X_HPH_L_ATEST 0x06d5 +#define WCD934X_HPH_R_EN 0x06d6 +#define WCD934X_HPH_R_TEST 0x06d7 +#define WCD934X_HPH_R_ATEST 0x06d8 +#define WCD934X_HPH_RDAC_CLK_CTL1 0x06d9 +#define WCD934X_HPH_RDAC_CLK_CTL2 0x06da +#define WCD934X_HPH_RDAC_LDO_CTL 0x06db +#define WCD934X_HPH_RDAC_CHOP_CLK_LP_CTL 0x06dc +#define WCD934X_HPH_REFBUFF_UHQA_CTL 0x06dd +#define WCD934X_HPH_REFBUFF_LP_CTL 0x06de +#define WCD934X_HPH_L_DAC_CTL 0x06df +#define WCD934X_HPH_R_DAC_CTL 0x06e0 +#define WCD934X_EAR_EN_REG 0x06e1 +#define WCD934X_EAR_CMBUFF 0x06e2 +#define WCD934X_EAR_ICTL 0x06e3 +#define WCD934X_EAR_EN_DBG_CTL 0x06e4 +#define WCD934X_EAR_CNP 0x06e5 +#define WCD934X_EAR_DAC_CTL_ATEST 0x06e6 +#define WCD934X_EAR_STATUS_REG 0x06e7 +#define WCD934X_EAR_EAR_MISC 0x06e8 +#define WCD934X_DIFF_LO_MISC 0x06e9 +#define WCD934X_DIFF_LO_LO2_COMPANDER 0x06ea +#define WCD934X_DIFF_LO_LO1_COMPANDER 0x06eb +#define WCD934X_DIFF_LO_COMMON 0x06ec +#define WCD934X_DIFF_LO_BYPASS_EN 0x06ed +#define WCD934X_DIFF_LO_CNP 0x06ee +#define WCD934X_DIFF_LO_CORE_OUT_PROG 0x06ef +#define WCD934X_DIFF_LO_LDO_OUT_PROG 0x06f0 +#define WCD934X_DIFF_LO_COM_SWCAP_REFBUF_FREQ 0x06f1 +#define WCD934X_DIFF_LO_COM_PA_FREQ 0x06f2 +#define WCD934X_DIFF_LO_RESERVED_REG 0x06f3 +#define WCD934X_DIFF_LO_LO1_STATUS_1 0x06f4 +#define WCD934X_DIFF_LO_LO1_STATUS_2 0x06f5 +#define WCD934X_ANA_NEW_PAGE_REGISTER 0x0700 +#define WCD934X_HPH_NEW_ANA_HPH2 0x0701 +#define WCD934X_HPH_NEW_ANA_HPH3 0x0702 +#define WCD934X_SLNQ_ANA_EN 0x0703 +#define WCD934X_SLNQ_ANA_STATUS 0x0704 +#define WCD934X_SLNQ_ANA_LDO_CONFIG 0x0705 +#define WCD934X_SLNQ_ANA_LDO_OCP_CONFIG 0x0706 +#define WCD934X_SLNQ_ANA_TX_LDO_CONFIG 0x0707 +#define WCD934X_SLNQ_ANA_TX_DRV_CONFIG 0x0708 +#define WCD934X_SLNQ_ANA_RX_CONFIG_1 0x0709 +#define WCD934X_SLNQ_ANA_RX_CONFIG_2 0x070a +#define WCD934X_SLNQ_ANA_PLL_ENABLES 0x070b +#define WCD934X_SLNQ_ANA_PLL_PRESET 0x070c +#define WCD934X_SLNQ_ANA_PLL_STATUS 0x070d +#define WCD934X_CLK_SYS_PLL_ENABLES 0x070e +#define WCD934X_CLK_SYS_PLL_PRESET 0x070f +#define WCD934X_CLK_SYS_PLL_STATUS 0x0710 +#define WCD934X_CLK_SYS_MCLK_PRG 0x0711 +#define WCD934X_CLK_SYS_MCLK2_PRG1 0x0712 +#define WCD934X_CLK_SYS_MCLK2_PRG2 0x0713 +#define WCD934X_CLK_SYS_XO_PRG 0x0714 +#define WCD934X_CLK_SYS_XO_CAP_XTP 0x0715 +#define WCD934X_CLK_SYS_XO_CAP_XTM 0x0716 +#define WCD934X_BOOST_BST_EN_DLY 0x0718 +#define WCD934X_BOOST_CTRL_ILIM 0x0719 +#define WCD934X_BOOST_VOUT_SETTING 0x071a +#define WCD934X_SIDO_NEW_VOUT_A_STARTUP 0x071b +#define WCD934X_SIDO_NEW_VOUT_D_STARTUP 0x071c +#define WCD934X_SIDO_NEW_VOUT_D_FREQ1 0x071d +#define WCD934X_SIDO_NEW_VOUT_D_FREQ2 0x071e +#define WCD934X_MBHC_NEW_ELECT_REM_CLAMP_CTL 0x071f +#define WCD934X_MBHC_NEW_CTL_1 0x0720 +#define WCD934X_MBHC_NEW_CTL_2 0x0721 +#define WCD934X_MBHC_NEW_PLUG_DETECT_CTL 0x0722 +#define WCD934X_MBHC_NEW_ZDET_ANA_CTL 0x0723 +#define WCD934X_MBHC_NEW_ZDET_RAMP_CTL 0x0724 +#define WCD934X_MBHC_NEW_FSM_STATUS 0x0725 +#define WCD934X_MBHC_NEW_ADC_RESULT 0x0726 +#define WCD934X_TX_NEW_AMIC_4_5_SEL 0x0727 +#define WCD934X_VBADC_NEW_ADC_MODE 0x072f +#define WCD934X_VBADC_NEW_ADC_DOUTMSB 0x0730 +#define WCD934X_VBADC_NEW_ADC_DOUTLSB 0x0731 +#define WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL 0x0732 +#define WCD934X_HPH_NEW_INT_RDAC_HD2_CTL 0x0733 +#define WCD934X_HPH_NEW_INT_RDAC_VREF_CTL 0x0734 +#define WCD934X_HPH_NEW_INT_RDAC_OVERRIDE_CTL 0x0735 +#define WCD934X_HPH_NEW_INT_RDAC_MISC1 0x0736 +#define WCD934X_HPH_NEW_INT_PA_MISC1 0x0737 +#define WCD934X_HPH_NEW_INT_PA_MISC2 0x0738 +#define WCD934X_HPH_NEW_INT_PA_RDAC_MISC 0x0739 +#define WCD934X_HPH_NEW_INT_HPH_TIMER1 0x073a +#define WCD934X_HPH_NEW_INT_HPH_TIMER2 0x073b +#define WCD934X_HPH_NEW_INT_HPH_TIMER3 0x073c +#define WCD934X_HPH_NEW_INT_HPH_TIMER4 0x073d +#define WCD934X_HPH_NEW_INT_PA_RDAC_MISC2 0x073e +#define WCD934X_HPH_NEW_INT_PA_RDAC_MISC3 0x073f +#define WCD934X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI 0x0745 +#define WCD934X_RX_NEW_INT_HPH_RDAC_BIAS_ULP 0x0746 +#define WCD934X_RX_NEW_INT_HPH_RDAC_LDO_LP 0x0747 +#define WCD934X_SLNQ_INT_ANA_INT_LDO_TEST 0x074b +#define WCD934X_SLNQ_INT_ANA_INT_LDO_DEBUG_1 0x074c +#define WCD934X_SLNQ_INT_ANA_INT_LDO_DEBUG_2 0x074d +#define WCD934X_SLNQ_INT_ANA_INT_TX_LDO_TEST 0x074e +#define WCD934X_SLNQ_INT_ANA_INT_TX_DRV_TEST 0x074f +#define WCD934X_SLNQ_INT_ANA_INT_RX_TEST 0x0750 +#define WCD934X_SLNQ_INT_ANA_INT_RX_TEST_STATUS 0x0751 +#define WCD934X_SLNQ_INT_ANA_INT_RX_DEBUG_1 0x0752 +#define WCD934X_SLNQ_INT_ANA_INT_RX_DEBUG_2 0x0753 +#define WCD934X_SLNQ_INT_ANA_INT_CLK_CTRL 0x0754 +#define WCD934X_SLNQ_INT_ANA_INT_RESERVED_1 0x0755 +#define WCD934X_SLNQ_INT_ANA_INT_RESERVED_2 0x0756 +#define WCD934X_SLNQ_INT_ANA_INT_PLL_POST_DIV_REG0 0x0757 +#define WCD934X_SLNQ_INT_ANA_INT_PLL_POST_DIV_REG1 0x0758 +#define WCD934X_SLNQ_INT_ANA_INT_PLL_REF_DIV_REG0 0x0759 +#define WCD934X_SLNQ_INT_ANA_INT_PLL_REF_DIV_REG1 0x075a +#define WCD934X_SLNQ_INT_ANA_INT_PLL_FILTER_REG0 0x075b +#define WCD934X_SLNQ_INT_ANA_INT_PLL_FILTER_REG1 0x075c +#define WCD934X_SLNQ_INT_ANA_INT_PLL_L_VAL 0x075d +#define WCD934X_SLNQ_INT_ANA_INT_PLL_M_VAL 0x075e +#define WCD934X_SLNQ_INT_ANA_INT_PLL_N_VAL 0x075f +#define WCD934X_SLNQ_INT_ANA_INT_PLL_TEST_REG0 0x0760 +#define WCD934X_SLNQ_INT_ANA_INT_PLL_PFD_CP_DSM_PROG 0x0761 +#define WCD934X_SLNQ_INT_ANA_INT_PLL_VCO_PROG 0x0762 +#define WCD934X_SLNQ_INT_ANA_INT_PLL_TEST_REG1 0x0763 +#define WCD934X_SLNQ_INT_ANA_INT_PLL_LDO_LOCK_CFG 0x0764 +#define WCD934X_SLNQ_INT_ANA_INT_PLL_DIG_LOCK_DET_CFG 0x0765 +#define WCD934X_CLK_SYS_INT_POST_DIV_REG0 0x076c +#define WCD934X_CLK_SYS_INT_POST_DIV_REG1 0x076d +#define WCD934X_CLK_SYS_INT_REF_DIV_REG0 0x076e +#define WCD934X_CLK_SYS_INT_REF_DIV_REG1 0x076f +#define WCD934X_CLK_SYS_INT_FILTER_REG0 0x0770 +#define WCD934X_CLK_SYS_INT_FILTER_REG1 0x0771 +#define WCD934X_CLK_SYS_INT_PLL_L_VAL 0x0772 +#define WCD934X_CLK_SYS_INT_PLL_M_VAL 0x0773 +#define WCD934X_CLK_SYS_INT_PLL_N_VAL 0x0774 +#define WCD934X_CLK_SYS_INT_TEST_REG0 0x0775 +#define WCD934X_CLK_SYS_INT_PFD_CP_DSM_PROG 0x0776 +#define WCD934X_CLK_SYS_INT_VCO_PROG 0x0777 +#define WCD934X_CLK_SYS_INT_TEST_REG1 0x0778 +#define WCD934X_CLK_SYS_INT_LDO_LOCK_CFG 0x0779 +#define WCD934X_CLK_SYS_INT_DIG_LOCK_DET_CFG 0x077a +#define WCD934X_CLK_SYS_INT_CLK_TEST1 0x077b +#define WCD934X_CLK_SYS_INT_CLK_TEST2 0x077c +#define WCD934X_CLK_SYS_INT_CLK_TEST3 0x077d +#define WCD934X_CLK_SYS_INT_XO_TEST1 0x077e +#define WCD934X_CLK_SYS_INT_XO_TEST2 0x077f +#define WCD934X_BOOST_INT_VCOMP_HYST 0x0787 +#define WCD934X_BOOST_INT_VLOOP_FILTER 0x0788 +#define WCD934X_BOOST_INT_CTRL_IDELTA 0x0789 +#define WCD934X_BOOST_INT_CTRL_ILIM_STARTUP 0x078a +#define WCD934X_BOOST_INT_CTRL_MIN_ONTIME 0x078b +#define WCD934X_BOOST_INT_CTRL_MAX_ONTIME 0x078c +#define WCD934X_BOOST_INT_CTRL_TIMING 0x078d +#define WCD934X_BOOST_INT_TMUX_A_D 0x078e +#define WCD934X_BOOST_INT_SW_DRV_CNTL 0x078f +#define WCD934X_BOOST_INT_SPARE1 0x0790 +#define WCD934X_BOOST_INT_SPARE2 0x0791 +#define WCD934X_SIDO_NEW_INT_RAMP_STATUS 0x0796 +#define WCD934X_SIDO_NEW_INT_SPARE_1 0x0797 +#define WCD934X_SIDO_NEW_INT_DEBUG_VOUT_SETTING_A 0x0798 +#define WCD934X_SIDO_NEW_INT_DEBUG_VOUT_SETTING_D 0x0799 +#define WCD934X_SIDO_NEW_INT_RAMP_INC_WAIT 0x079a +#define WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_CTL 0x079b +#define WCD934X_SIDO_NEW_INT_RAMP_IBLEED_CTL 0x079c +#define WCD934X_SIDO_NEW_INT_DEBUG_CPROVR_TEST 0x079d +#define WCD934X_SIDO_NEW_INT_RAMP_CTL_A 0x079e +#define WCD934X_SIDO_NEW_INT_RAMP_CTL_D 0x079f +#define WCD934X_SIDO_NEW_INT_RAMP_TIMEOUT_PERIOD 0x07a0 +#define WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_SETTING1 0x07a1 +#define WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_SETTING2 0x07a2 +#define WCD934X_SIDO_NEW_INT_DYNAMIC_IPEAK_SETTING3 0x07a3 +#define WCD934X_SIDO_NEW_INT_HIGH_ACCU_MODE_SEL1 0x07a4 +#define WCD934X_SIDO_NEW_INT_HIGH_ACCU_MODE_SEL2 0x07a5 +#define WCD934X_MBHC_NEW_INT_SLNQ_HPF 0x07af +#define WCD934X_MBHC_NEW_INT_SLNQ_REF 0x07b0 +#define WCD934X_MBHC_NEW_INT_SLNQ_COMP 0x07b1 +#define WCD934X_MBHC_NEW_INT_SPARE_2 0x07b2 +#define WCD934X_PAGE10_PAGE_REGISTER 0x0a00 +#define WCD934X_CDC_ANC0_CLK_RESET_CTL 0x0a01 +#define WCD934X_CDC_ANC0_MODE_1_CTL 0x0a02 +#define WCD934X_CDC_ANC0_MODE_2_CTL 0x0a03 +#define WCD934X_CDC_ANC0_FF_SHIFT 0x0a04 +#define WCD934X_CDC_ANC0_FB_SHIFT 0x0a05 +#define WCD934X_CDC_ANC0_LPF_FF_A_CTL 0x0a06 +#define WCD934X_CDC_ANC0_LPF_FF_B_CTL 0x0a07 +#define WCD934X_CDC_ANC0_LPF_FB_CTL 0x0a08 +#define WCD934X_CDC_ANC0_SMLPF_CTL 0x0a09 +#define WCD934X_CDC_ANC0_DCFLT_SHIFT_CTL 0x0a0a +#define WCD934X_CDC_ANC0_IIR_ADAPT_CTL 0x0a0b +#define WCD934X_CDC_ANC0_IIR_COEFF_1_CTL 0x0a0c +#define WCD934X_CDC_ANC0_IIR_COEFF_2_CTL 0x0a0d +#define WCD934X_CDC_ANC0_FF_A_GAIN_CTL 0x0a0e +#define WCD934X_CDC_ANC0_FF_B_GAIN_CTL 0x0a0f +#define WCD934X_CDC_ANC0_FB_GAIN_CTL 0x0a10 +#define WCD934X_CDC_ANC0_RC_COMMON_CTL 0x0a11 +#define WCD934X_CDC_ANC0_FIFO_COMMON_CTL 0x0a13 +#define WCD934X_CDC_ANC0_RC0_STATUS_FMIN_CNTR 0x0a14 +#define WCD934X_CDC_ANC0_RC1_STATUS_FMIN_CNTR 0x0a15 +#define WCD934X_CDC_ANC0_RC0_STATUS_FMAX_CNTR 0x0a16 +#define WCD934X_CDC_ANC0_RC1_STATUS_FMAX_CNTR 0x0a17 +#define WCD934X_CDC_ANC0_STATUS_FIFO 0x0a18 +#define WCD934X_CDC_ANC1_CLK_RESET_CTL 0x0a19 +#define WCD934X_CDC_ANC1_MODE_1_CTL 0x0a1a +#define WCD934X_CDC_ANC1_MODE_2_CTL 0x0a1b +#define WCD934X_CDC_ANC1_FF_SHIFT 0x0a1c +#define WCD934X_CDC_ANC1_FB_SHIFT 0x0a1d +#define WCD934X_CDC_ANC1_LPF_FF_A_CTL 0x0a1e +#define WCD934X_CDC_ANC1_LPF_FF_B_CTL 0x0a1f +#define WCD934X_CDC_ANC1_LPF_FB_CTL 0x0a20 +#define WCD934X_CDC_ANC1_SMLPF_CTL 0x0a21 +#define WCD934X_CDC_ANC1_DCFLT_SHIFT_CTL 0x0a22 +#define WCD934X_CDC_ANC1_IIR_ADAPT_CTL 0x0a23 +#define WCD934X_CDC_ANC1_IIR_COEFF_1_CTL 0x0a24 +#define WCD934X_CDC_ANC1_IIR_COEFF_2_CTL 0x0a25 +#define WCD934X_CDC_ANC1_FF_A_GAIN_CTL 0x0a26 +#define WCD934X_CDC_ANC1_FF_B_GAIN_CTL 0x0a27 +#define WCD934X_CDC_ANC1_FB_GAIN_CTL 0x0a28 +#define WCD934X_CDC_ANC1_RC_COMMON_CTL 0x0a29 +#define WCD934X_CDC_ANC1_FIFO_COMMON_CTL 0x0a2b +#define WCD934X_CDC_ANC1_RC0_STATUS_FMIN_CNTR 0x0a2c +#define WCD934X_CDC_ANC1_RC1_STATUS_FMIN_CNTR 0x0a2d +#define WCD934X_CDC_ANC1_RC0_STATUS_FMAX_CNTR 0x0a2e +#define WCD934X_CDC_ANC1_RC1_STATUS_FMAX_CNTR 0x0a2f +#define WCD934X_CDC_ANC1_STATUS_FIFO 0x0a30 +#define WCD934X_CDC_TX0_TX_PATH_CTL 0x0a31 +#define WCD934X_CDC_TX0_TX_PATH_CFG0 0x0a32 +#define WCD934X_CDC_TX0_TX_PATH_CFG1 0x0a33 +#define WCD934X_CDC_TX0_TX_VOL_CTL 0x0a34 +#define WCD934X_CDC_TX0_TX_PATH_192_CTL 0x0a35 +#define WCD934X_CDC_TX0_TX_PATH_192_CFG 0x0a36 +#define WCD934X_CDC_TX0_TX_PATH_SEC0 0x0a37 +#define WCD934X_CDC_TX0_TX_PATH_SEC1 0x0a38 +#define WCD934X_CDC_TX0_TX_PATH_SEC2 0x0a39 +#define WCD934X_CDC_TX0_TX_PATH_SEC3 0x0a3a +#define WCD934X_CDC_TX0_TX_PATH_SEC4 0x0a3b +#define WCD934X_CDC_TX0_TX_PATH_SEC5 0x0a3c +#define WCD934X_CDC_TX0_TX_PATH_SEC6 0x0a3d +#define WCD934X_CDC_TX0_TX_PATH_SEC7 0x0a3e +#define WCD934X_CDC_TX1_TX_PATH_CTL 0x0a41 +#define WCD934X_CDC_TX1_TX_PATH_CFG0 0x0a42 +#define WCD934X_CDC_TX1_TX_PATH_CFG1 0x0a43 +#define WCD934X_CDC_TX1_TX_VOL_CTL 0x0a44 +#define WCD934X_CDC_TX1_TX_PATH_192_CTL 0x0a45 +#define WCD934X_CDC_TX1_TX_PATH_192_CFG 0x0a46 +#define WCD934X_CDC_TX1_TX_PATH_SEC0 0x0a47 +#define WCD934X_CDC_TX1_TX_PATH_SEC1 0x0a48 +#define WCD934X_CDC_TX1_TX_PATH_SEC2 0x0a49 +#define WCD934X_CDC_TX1_TX_PATH_SEC3 0x0a4a +#define WCD934X_CDC_TX1_TX_PATH_SEC4 0x0a4b +#define WCD934X_CDC_TX1_TX_PATH_SEC5 0x0a4c +#define WCD934X_CDC_TX1_TX_PATH_SEC6 0x0a4d +#define WCD934X_CDC_TX2_TX_PATH_CTL 0x0a51 +#define WCD934X_CDC_TX2_TX_PATH_CFG0 0x0a52 +#define WCD934X_CDC_TX2_TX_PATH_CFG1 0x0a53 +#define WCD934X_CDC_TX2_TX_VOL_CTL 0x0a54 +#define WCD934X_CDC_TX2_TX_PATH_192_CTL 0x0a55 +#define WCD934X_CDC_TX2_TX_PATH_192_CFG 0x0a56 +#define WCD934X_CDC_TX2_TX_PATH_SEC0 0x0a57 +#define WCD934X_CDC_TX2_TX_PATH_SEC1 0x0a58 +#define WCD934X_CDC_TX2_TX_PATH_SEC2 0x0a59 +#define WCD934X_CDC_TX2_TX_PATH_SEC3 0x0a5a +#define WCD934X_CDC_TX2_TX_PATH_SEC4 0x0a5b +#define WCD934X_CDC_TX2_TX_PATH_SEC5 0x0a5c +#define WCD934X_CDC_TX2_TX_PATH_SEC6 0x0a5d +#define WCD934X_CDC_TX3_TX_PATH_CTL 0x0a61 +#define WCD934X_CDC_TX3_TX_PATH_CFG0 0x0a62 +#define WCD934X_CDC_TX3_TX_PATH_CFG1 0x0a63 +#define WCD934X_CDC_TX3_TX_VOL_CTL 0x0a64 +#define WCD934X_CDC_TX3_TX_PATH_192_CTL 0x0a65 +#define WCD934X_CDC_TX3_TX_PATH_192_CFG 0x0a66 +#define WCD934X_CDC_TX3_TX_PATH_SEC0 0x0a67 +#define WCD934X_CDC_TX3_TX_PATH_SEC1 0x0a68 +#define WCD934X_CDC_TX3_TX_PATH_SEC2 0x0a69 +#define WCD934X_CDC_TX3_TX_PATH_SEC3 0x0a6a +#define WCD934X_CDC_TX3_TX_PATH_SEC4 0x0a6b +#define WCD934X_CDC_TX3_TX_PATH_SEC5 0x0a6c +#define WCD934X_CDC_TX3_TX_PATH_SEC6 0x0a6d +#define WCD934X_CDC_TX4_TX_PATH_CTL 0x0a71 +#define WCD934X_CDC_TX4_TX_PATH_CFG0 0x0a72 +#define WCD934X_CDC_TX4_TX_PATH_CFG1 0x0a73 +#define WCD934X_CDC_TX4_TX_VOL_CTL 0x0a74 +#define WCD934X_CDC_TX4_TX_PATH_192_CTL 0x0a75 +#define WCD934X_CDC_TX4_TX_PATH_192_CFG 0x0a76 +#define WCD934X_CDC_TX4_TX_PATH_SEC0 0x0a77 +#define WCD934X_CDC_TX4_TX_PATH_SEC1 0x0a78 +#define WCD934X_CDC_TX4_TX_PATH_SEC2 0x0a79 +#define WCD934X_CDC_TX4_TX_PATH_SEC3 0x0a7a +#define WCD934X_CDC_TX4_TX_PATH_SEC4 0x0a7b +#define WCD934X_CDC_TX4_TX_PATH_SEC5 0x0a7c +#define WCD934X_CDC_TX4_TX_PATH_SEC6 0x0a7d +#define WCD934X_CDC_TX5_TX_PATH_CTL 0x0a81 +#define WCD934X_CDC_TX5_TX_PATH_CFG0 0x0a82 +#define WCD934X_CDC_TX5_TX_PATH_CFG1 0x0a83 +#define WCD934X_CDC_TX5_TX_VOL_CTL 0x0a84 +#define WCD934X_CDC_TX5_TX_PATH_192_CTL 0x0a85 +#define WCD934X_CDC_TX5_TX_PATH_192_CFG 0x0a86 +#define WCD934X_CDC_TX5_TX_PATH_SEC0 0x0a87 +#define WCD934X_CDC_TX5_TX_PATH_SEC1 0x0a88 +#define WCD934X_CDC_TX5_TX_PATH_SEC2 0x0a89 +#define WCD934X_CDC_TX5_TX_PATH_SEC3 0x0a8a +#define WCD934X_CDC_TX5_TX_PATH_SEC4 0x0a8b +#define WCD934X_CDC_TX5_TX_PATH_SEC5 0x0a8c +#define WCD934X_CDC_TX5_TX_PATH_SEC6 0x0a8d +#define WCD934X_CDC_TX6_TX_PATH_CTL 0x0a91 +#define WCD934X_CDC_TX6_TX_PATH_CFG0 0x0a92 +#define WCD934X_CDC_TX6_TX_PATH_CFG1 0x0a93 +#define WCD934X_CDC_TX6_TX_VOL_CTL 0x0a94 +#define WCD934X_CDC_TX6_TX_PATH_192_CTL 0x0a95 +#define WCD934X_CDC_TX6_TX_PATH_192_CFG 0x0a96 +#define WCD934X_CDC_TX6_TX_PATH_SEC0 0x0a97 +#define WCD934X_CDC_TX6_TX_PATH_SEC1 0x0a98 +#define WCD934X_CDC_TX6_TX_PATH_SEC2 0x0a99 +#define WCD934X_CDC_TX6_TX_PATH_SEC3 0x0a9a +#define WCD934X_CDC_TX6_TX_PATH_SEC4 0x0a9b +#define WCD934X_CDC_TX6_TX_PATH_SEC5 0x0a9c +#define WCD934X_CDC_TX6_TX_PATH_SEC6 0x0a9d +#define WCD934X_CDC_TX7_TX_PATH_CTL 0x0aa1 +#define WCD934X_CDC_TX7_TX_PATH_CFG0 0x0aa2 +#define WCD934X_CDC_TX7_TX_PATH_CFG1 0x0aa3 +#define WCD934X_CDC_TX7_TX_VOL_CTL 0x0aa4 +#define WCD934X_CDC_TX7_TX_PATH_192_CTL 0x0aa5 +#define WCD934X_CDC_TX7_TX_PATH_192_CFG 0x0aa6 +#define WCD934X_CDC_TX7_TX_PATH_SEC0 0x0aa7 +#define WCD934X_CDC_TX7_TX_PATH_SEC1 0x0aa8 +#define WCD934X_CDC_TX7_TX_PATH_SEC2 0x0aa9 +#define WCD934X_CDC_TX7_TX_PATH_SEC3 0x0aaa +#define WCD934X_CDC_TX7_TX_PATH_SEC4 0x0aab +#define WCD934X_CDC_TX7_TX_PATH_SEC5 0x0aac +#define WCD934X_CDC_TX7_TX_PATH_SEC6 0x0aad +#define WCD934X_CDC_TX8_TX_PATH_CTL 0x0ab1 +#define WCD934X_CDC_TX8_TX_PATH_CFG0 0x0ab2 +#define WCD934X_CDC_TX8_TX_PATH_CFG1 0x0ab3 +#define WCD934X_CDC_TX8_TX_VOL_CTL 0x0ab4 +#define WCD934X_CDC_TX8_TX_PATH_192_CTL 0x0ab5 +#define WCD934X_CDC_TX8_TX_PATH_192_CFG 0x0ab6 +#define WCD934X_CDC_TX8_TX_PATH_SEC0 0x0ab7 +#define WCD934X_CDC_TX8_TX_PATH_SEC1 0x0ab8 +#define WCD934X_CDC_TX8_TX_PATH_SEC2 0x0ab9 +#define WCD934X_CDC_TX8_TX_PATH_SEC3 0x0aba +#define WCD934X_CDC_TX8_TX_PATH_SEC4 0x0abb +#define WCD934X_CDC_TX8_TX_PATH_SEC5 0x0abc +#define WCD934X_CDC_TX8_TX_PATH_SEC6 0x0abd +#define WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL 0x0ac2 +#define WCD934X_CDC_TX9_SPKR_PROT_PATH_CFG0 0x0ac3 +#define WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL 0x0ac6 +#define WCD934X_CDC_TX10_SPKR_PROT_PATH_CFG0 0x0ac7 +#define WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL 0x0aca +#define WCD934X_CDC_TX11_SPKR_PROT_PATH_CFG0 0x0acb +#define WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL 0x0ace +#define WCD934X_CDC_TX12_SPKR_PROT_PATH_CFG0 0x0acf +#define WCD934X_PAGE11_PAGE_REGISTER 0x0b00 +#define WCD934X_CDC_COMPANDER1_CTL0 0x0b01 +#define WCD934X_CDC_COMPANDER1_CTL1 0x0b02 +#define WCD934X_CDC_COMPANDER1_CTL2 0x0b03 +#define WCD934X_CDC_COMPANDER1_CTL3 0x0b04 +#define WCD934X_CDC_COMPANDER1_CTL4 0x0b05 +#define WCD934X_CDC_COMPANDER1_CTL5 0x0b06 +#define WCD934X_CDC_COMPANDER1_CTL6 0x0b07 +#define WCD934X_CDC_COMPANDER1_CTL7 0x0b08 +#define WCD934X_CDC_COMPANDER2_CTL0 0x0b09 +#define WCD934X_CDC_COMPANDER2_CTL1 0x0b0a +#define WCD934X_CDC_COMPANDER2_CTL2 0x0b0b +#define WCD934X_CDC_COMPANDER2_CTL3 0x0b0c +#define WCD934X_CDC_COMPANDER2_CTL4 0x0b0d +#define WCD934X_CDC_COMPANDER2_CTL5 0x0b0e +#define WCD934X_CDC_COMPANDER2_CTL6 0x0b0f +#define WCD934X_CDC_COMPANDER2_CTL7 0x0b10 +#define WCD934X_CDC_COMPANDER3_CTL0 0x0b11 +#define WCD934X_CDC_COMPANDER3_CTL1 0x0b12 +#define WCD934X_CDC_COMPANDER3_CTL2 0x0b13 +#define WCD934X_CDC_COMPANDER3_CTL3 0x0b14 +#define WCD934X_CDC_COMPANDER3_CTL4 0x0b15 +#define WCD934X_CDC_COMPANDER3_CTL5 0x0b16 +#define WCD934X_CDC_COMPANDER3_CTL6 0x0b17 +#define WCD934X_CDC_COMPANDER3_CTL7 0x0b18 +#define WCD934X_CDC_COMPANDER4_CTL0 0x0b19 +#define WCD934X_CDC_COMPANDER4_CTL1 0x0b1a +#define WCD934X_CDC_COMPANDER4_CTL2 0x0b1b +#define WCD934X_CDC_COMPANDER4_CTL3 0x0b1c +#define WCD934X_CDC_COMPANDER4_CTL4 0x0b1d +#define WCD934X_CDC_COMPANDER4_CTL5 0x0b1e +#define WCD934X_CDC_COMPANDER4_CTL6 0x0b1f +#define WCD934X_CDC_COMPANDER4_CTL7 0x0b20 +#define WCD934X_CDC_COMPANDER7_CTL0 0x0b31 +#define WCD934X_CDC_COMPANDER7_CTL1 0x0b32 +#define WCD934X_CDC_COMPANDER7_CTL2 0x0b33 +#define WCD934X_CDC_COMPANDER7_CTL3 0x0b34 +#define WCD934X_CDC_COMPANDER7_CTL4 0x0b35 +#define WCD934X_CDC_COMPANDER7_CTL5 0x0b36 +#define WCD934X_CDC_COMPANDER7_CTL6 0x0b37 +#define WCD934X_CDC_COMPANDER7_CTL7 0x0b38 +#define WCD934X_CDC_COMPANDER8_CTL0 0x0b39 +#define WCD934X_CDC_COMPANDER8_CTL1 0x0b3a +#define WCD934X_CDC_COMPANDER8_CTL2 0x0b3b +#define WCD934X_CDC_COMPANDER8_CTL3 0x0b3c +#define WCD934X_CDC_COMPANDER8_CTL4 0x0b3d +#define WCD934X_CDC_COMPANDER8_CTL5 0x0b3e +#define WCD934X_CDC_COMPANDER8_CTL6 0x0b3f +#define WCD934X_CDC_COMPANDER8_CTL7 0x0b40 +#define WCD934X_CDC_RX0_RX_PATH_CTL 0x0b41 +#define WCD934X_CDC_RX0_RX_PATH_CFG0 0x0b42 +#define WCD934X_CDC_RX0_RX_PATH_CFG1 0x0b43 +#define WCD934X_CDC_RX0_RX_PATH_CFG2 0x0b44 +#define WCD934X_CDC_RX0_RX_VOL_CTL 0x0b45 +#define WCD934X_CDC_RX0_RX_PATH_MIX_CTL 0x0b46 +#define WCD934X_CDC_RX0_RX_PATH_MIX_CFG 0x0b47 +#define WCD934X_CDC_RX0_RX_VOL_MIX_CTL 0x0b48 +#define WCD934X_CDC_RX0_RX_PATH_SEC0 0x0b49 +#define WCD934X_CDC_RX0_RX_PATH_SEC1 0x0b4a +#define WCD934X_CDC_RX0_RX_PATH_SEC2 0x0b4b +#define WCD934X_CDC_RX0_RX_PATH_SEC3 0x0b4c +#define WCD934X_CDC_RX0_RX_PATH_SEC5 0x0b4e +#define WCD934X_CDC_RX0_RX_PATH_SEC6 0x0b4f +#define WCD934X_CDC_RX0_RX_PATH_SEC7 0x0b50 +#define WCD934X_CDC_RX0_RX_PATH_MIX_SEC0 0x0b51 +#define WCD934X_CDC_RX0_RX_PATH_MIX_SEC1 0x0b52 +#define WCD934X_CDC_RX0_RX_PATH_DSMDEM_CTL 0x0b53 +#define WCD934X_CDC_RX1_RX_PATH_CTL 0x0b55 +#define WCD934X_CDC_RX1_RX_PATH_CFG0 0x0b56 +#define WCD934X_CDC_RX1_RX_PATH_CFG1 0x0b57 +#define WCD934X_CDC_RX1_RX_PATH_CFG2 0x0b58 +#define WCD934X_CDC_RX1_RX_VOL_CTL 0x0b59 +#define WCD934X_CDC_RX1_RX_PATH_MIX_CTL 0x0b5a +#define WCD934X_CDC_RX1_RX_PATH_MIX_CFG 0x0b5b +#define WCD934X_CDC_RX1_RX_VOL_MIX_CTL 0x0b5c +#define WCD934X_CDC_RX1_RX_PATH_SEC0 0x0b5d +#define WCD934X_CDC_RX1_RX_PATH_SEC1 0x0b5e +#define WCD934X_CDC_RX1_RX_PATH_SEC2 0x0b5f +#define WCD934X_CDC_RX1_RX_PATH_SEC3 0x0b60 +#define WCD934X_CDC_RX1_RX_PATH_SEC4 0x0b61 +#define WCD934X_CDC_RX1_RX_PATH_SEC5 0x0b62 +#define WCD934X_CDC_RX1_RX_PATH_SEC6 0x0b63 +#define WCD934X_CDC_RX1_RX_PATH_SEC7 0x0b64 +#define WCD934X_CDC_RX1_RX_PATH_MIX_SEC0 0x0b65 +#define WCD934X_CDC_RX1_RX_PATH_MIX_SEC1 0x0b66 +#define WCD934X_CDC_RX1_RX_PATH_DSMDEM_CTL 0x0b67 +#define WCD934X_CDC_RX2_RX_PATH_CTL 0x0b69 +#define WCD934X_CDC_RX2_RX_PATH_CFG0 0x0b6a +#define WCD934X_CDC_RX2_RX_PATH_CFG1 0x0b6b +#define WCD934X_CDC_RX2_RX_PATH_CFG2 0x0b6c +#define WCD934X_CDC_RX2_RX_VOL_CTL 0x0b6d +#define WCD934X_CDC_RX2_RX_PATH_MIX_CTL 0x0b6e +#define WCD934X_CDC_RX2_RX_PATH_MIX_CFG 0x0b6f +#define WCD934X_CDC_RX2_RX_VOL_MIX_CTL 0x0b70 +#define WCD934X_CDC_RX2_RX_PATH_SEC0 0x0b71 +#define WCD934X_CDC_RX2_RX_PATH_SEC1 0x0b72 +#define WCD934X_CDC_RX2_RX_PATH_SEC2 0x0b73 +#define WCD934X_CDC_RX2_RX_PATH_SEC3 0x0b74 +#define WCD934X_CDC_RX2_RX_PATH_SEC4 0x0b75 +#define WCD934X_CDC_RX2_RX_PATH_SEC5 0x0b76 +#define WCD934X_CDC_RX2_RX_PATH_SEC6 0x0b77 +#define WCD934X_CDC_RX2_RX_PATH_SEC7 0x0b78 +#define WCD934X_CDC_RX2_RX_PATH_MIX_SEC0 0x0b79 +#define WCD934X_CDC_RX2_RX_PATH_MIX_SEC1 0x0b7a +#define WCD934X_CDC_RX2_RX_PATH_DSMDEM_CTL 0x0b7b +#define WCD934X_CDC_RX3_RX_PATH_CTL 0x0b7d +#define WCD934X_CDC_RX3_RX_PATH_CFG0 0x0b7e +#define WCD934X_CDC_RX3_RX_PATH_CFG1 0x0b7f +#define WCD934X_CDC_RX3_RX_PATH_CFG2 0x0b80 +#define WCD934X_CDC_RX3_RX_VOL_CTL 0x0b81 +#define WCD934X_CDC_RX3_RX_PATH_MIX_CTL 0x0b82 +#define WCD934X_CDC_RX3_RX_PATH_MIX_CFG 0x0b83 +#define WCD934X_CDC_RX3_RX_VOL_MIX_CTL 0x0b84 +#define WCD934X_CDC_RX3_RX_PATH_SEC0 0x0b85 +#define WCD934X_CDC_RX3_RX_PATH_SEC1 0x0b86 +#define WCD934X_CDC_RX3_RX_PATH_SEC2 0x0b87 +#define WCD934X_CDC_RX3_RX_PATH_SEC3 0x0b88 +#define WCD934X_CDC_RX3_RX_PATH_SEC5 0x0b8a +#define WCD934X_CDC_RX3_RX_PATH_SEC6 0x0b8b +#define WCD934X_CDC_RX3_RX_PATH_SEC7 0x0b8c +#define WCD934X_CDC_RX3_RX_PATH_MIX_SEC0 0x0b8d +#define WCD934X_CDC_RX3_RX_PATH_MIX_SEC1 0x0b8e +#define WCD934X_CDC_RX3_RX_PATH_DSMDEM_CTL 0x0b8f +#define WCD934X_CDC_RX4_RX_PATH_CTL 0x0b91 +#define WCD934X_CDC_RX4_RX_PATH_CFG0 0x0b92 +#define WCD934X_CDC_RX4_RX_PATH_CFG1 0x0b93 +#define WCD934X_CDC_RX4_RX_PATH_CFG2 0x0b94 +#define WCD934X_CDC_RX4_RX_VOL_CTL 0x0b95 +#define WCD934X_CDC_RX4_RX_PATH_MIX_CTL 0x0b96 +#define WCD934X_CDC_RX4_RX_PATH_MIX_CFG 0x0b97 +#define WCD934X_CDC_RX4_RX_VOL_MIX_CTL 0x0b98 +#define WCD934X_CDC_RX4_RX_PATH_SEC0 0x0b99 +#define WCD934X_CDC_RX4_RX_PATH_SEC1 0x0b9a +#define WCD934X_CDC_RX4_RX_PATH_SEC2 0x0b9b +#define WCD934X_CDC_RX4_RX_PATH_SEC3 0x0b9c +#define WCD934X_CDC_RX4_RX_PATH_SEC5 0x0b9e +#define WCD934X_CDC_RX4_RX_PATH_SEC6 0x0b9f +#define WCD934X_CDC_RX4_RX_PATH_SEC7 0x0ba0 +#define WCD934X_CDC_RX4_RX_PATH_MIX_SEC0 0x0ba1 +#define WCD934X_CDC_RX4_RX_PATH_MIX_SEC1 0x0ba2 +#define WCD934X_CDC_RX4_RX_PATH_DSMDEM_CTL 0x0ba3 +#define WCD934X_CDC_RX7_RX_PATH_CTL 0x0bcd +#define WCD934X_CDC_RX7_RX_PATH_CFG0 0x0bce +#define WCD934X_CDC_RX7_RX_PATH_CFG1 0x0bcf +#define WCD934X_CDC_RX7_RX_PATH_CFG2 0x0bd0 +#define WCD934X_CDC_RX7_RX_VOL_CTL 0x0bd1 +#define WCD934X_CDC_RX7_RX_PATH_MIX_CTL 0x0bd2 +#define WCD934X_CDC_RX7_RX_PATH_MIX_CFG 0x0bd3 +#define WCD934X_CDC_RX7_RX_VOL_MIX_CTL 0x0bd4 +#define WCD934X_CDC_RX7_RX_PATH_SEC0 0x0bd5 +#define WCD934X_CDC_RX7_RX_PATH_SEC1 0x0bd6 +#define WCD934X_CDC_RX7_RX_PATH_SEC2 0x0bd7 +#define WCD934X_CDC_RX7_RX_PATH_SEC3 0x0bd8 +#define WCD934X_CDC_RX7_RX_PATH_SEC5 0x0bda +#define WCD934X_CDC_RX7_RX_PATH_SEC6 0x0bdb +#define WCD934X_CDC_RX7_RX_PATH_SEC7 0x0bdc +#define WCD934X_CDC_RX7_RX_PATH_MIX_SEC0 0x0bdd +#define WCD934X_CDC_RX7_RX_PATH_MIX_SEC1 0x0bde +#define WCD934X_CDC_RX7_RX_PATH_DSMDEM_CTL 0x0bdf +#define WCD934X_CDC_RX8_RX_PATH_CTL 0x0be1 +#define WCD934X_CDC_RX8_RX_PATH_CFG0 0x0be2 +#define WCD934X_CDC_RX8_RX_PATH_CFG1 0x0be3 +#define WCD934X_CDC_RX8_RX_PATH_CFG2 0x0be4 +#define WCD934X_CDC_RX8_RX_VOL_CTL 0x0be5 +#define WCD934X_CDC_RX8_RX_PATH_MIX_CTL 0x0be6 +#define WCD934X_CDC_RX8_RX_PATH_MIX_CFG 0x0be7 +#define WCD934X_CDC_RX8_RX_VOL_MIX_CTL 0x0be8 +#define WCD934X_CDC_RX8_RX_PATH_SEC0 0x0be9 +#define WCD934X_CDC_RX8_RX_PATH_SEC1 0x0bea +#define WCD934X_CDC_RX8_RX_PATH_SEC2 0x0beb +#define WCD934X_CDC_RX8_RX_PATH_SEC3 0x0bec +#define WCD934X_CDC_RX8_RX_PATH_SEC5 0x0bee +#define WCD934X_CDC_RX8_RX_PATH_SEC6 0x0bef +#define WCD934X_CDC_RX8_RX_PATH_SEC7 0x0bf0 +#define WCD934X_CDC_RX8_RX_PATH_MIX_SEC0 0x0bf1 +#define WCD934X_CDC_RX8_RX_PATH_MIX_SEC1 0x0bf2 +#define WCD934X_CDC_RX8_RX_PATH_DSMDEM_CTL 0x0bf3 +#define WCD934X_PAGE12_PAGE_REGISTER 0x0c00 +#define WCD934X_CDC_CLSH_CRC 0x0c01 +#define WCD934X_CDC_CLSH_DLY_CTRL 0x0c02 +#define WCD934X_CDC_CLSH_DECAY_CTRL 0x0c03 +#define WCD934X_CDC_CLSH_HPH_V_PA 0x0c04 +#define WCD934X_CDC_CLSH_EAR_V_PA 0x0c05 +#define WCD934X_CDC_CLSH_HPH_V_HD 0x0c06 +#define WCD934X_CDC_CLSH_EAR_V_HD 0x0c07 +#define WCD934X_CDC_CLSH_K1_MSB 0x0c08 +#define WCD934X_CDC_CLSH_K1_LSB 0x0c09 +#define WCD934X_CDC_CLSH_K2_MSB 0x0c0a +#define WCD934X_CDC_CLSH_K2_LSB 0x0c0b +#define WCD934X_CDC_CLSH_IDLE_CTRL 0x0c0c +#define WCD934X_CDC_CLSH_IDLE_HPH 0x0c0d +#define WCD934X_CDC_CLSH_IDLE_EAR 0x0c0e +#define WCD934X_CDC_CLSH_TEST0 0x0c0f +#define WCD934X_CDC_CLSH_TEST1 0x0c10 +#define WCD934X_CDC_CLSH_OVR_VREF 0x0c11 +#define WCD934X_CDC_BOOST0_BOOST_PATH_CTL 0x0c19 +#define WCD934X_CDC_BOOST0_BOOST_CTL 0x0c1a +#define WCD934X_CDC_BOOST0_BOOST_CFG1 0x0c1b +#define WCD934X_CDC_BOOST0_BOOST_CFG2 0x0c1c +#define WCD934X_CDC_BOOST1_BOOST_PATH_CTL 0x0c21 +#define WCD934X_CDC_BOOST1_BOOST_CTL 0x0c22 +#define WCD934X_CDC_BOOST1_BOOST_CFG1 0x0c23 +#define WCD934X_CDC_BOOST1_BOOST_CFG2 0x0c24 +#define WCD934X_CDC_VBAT_VBAT_PATH_CTL 0x0c3d +#define WCD934X_CDC_VBAT_VBAT_CFG 0x0c3e +#define WCD934X_CDC_VBAT_VBAT_ADC_CAL1 0x0c3f +#define WCD934X_CDC_VBAT_VBAT_ADC_CAL2 0x0c40 +#define WCD934X_CDC_VBAT_VBAT_ADC_CAL3 0x0c41 +#define WCD934X_CDC_VBAT_VBAT_PK_EST1 0x0c42 +#define WCD934X_CDC_VBAT_VBAT_PK_EST2 0x0c43 +#define WCD934X_CDC_VBAT_VBAT_PK_EST3 0x0c44 +#define WCD934X_CDC_VBAT_VBAT_RF_PROC1 0x0c45 +#define WCD934X_CDC_VBAT_VBAT_RF_PROC2 0x0c46 +#define WCD934X_CDC_VBAT_VBAT_TAC1 0x0c47 +#define WCD934X_CDC_VBAT_VBAT_TAC2 0x0c48 +#define WCD934X_CDC_VBAT_VBAT_TAC3 0x0c49 +#define WCD934X_CDC_VBAT_VBAT_TAC4 0x0c4a +#define WCD934X_CDC_VBAT_VBAT_GAIN_UPD1 0x0c4b +#define WCD934X_CDC_VBAT_VBAT_GAIN_UPD2 0x0c4c +#define WCD934X_CDC_VBAT_VBAT_GAIN_UPD3 0x0c4d +#define WCD934X_CDC_VBAT_VBAT_GAIN_UPD4 0x0c4e +#define WCD934X_CDC_VBAT_VBAT_DEBUG1 0x0c4f +#define WCD934X_CDC_VBAT_VBAT_GAIN_UPD_MON 0x0c50 +#define WCD934X_CDC_VBAT_VBAT_GAIN_MON_VAL 0x0c51 +#define WCD934X_CDC_VBAT_VBAT_BAN 0x0c52 +#define WCD934X_MIXING_ASRC0_CLK_RST_CTL 0x0c55 +#define WCD934X_MIXING_ASRC0_CTL0 0x0c56 +#define WCD934X_MIXING_ASRC0_CTL1 0x0c57 +#define WCD934X_MIXING_ASRC0_FIFO_CTL 0x0c58 +#define WCD934X_MIXING_ASRC0_STATUS_FMIN_CNTR_LSB 0x0c59 +#define WCD934X_MIXING_ASRC0_STATUS_FMIN_CNTR_MSB 0x0c5a +#define WCD934X_MIXING_ASRC0_STATUS_FMAX_CNTR_LSB 0x0c5b +#define WCD934X_MIXING_ASRC0_STATUS_FMAX_CNTR_MSB 0x0c5c +#define WCD934X_MIXING_ASRC0_STATUS_FIFO 0x0c5d +#define WCD934X_MIXING_ASRC1_CLK_RST_CTL 0x0c61 +#define WCD934X_MIXING_ASRC1_CTL0 0x0c62 +#define WCD934X_MIXING_ASRC1_CTL1 0x0c63 +#define WCD934X_MIXING_ASRC1_FIFO_CTL 0x0c64 +#define WCD934X_MIXING_ASRC1_STATUS_FMIN_CNTR_LSB 0x0c65 +#define WCD934X_MIXING_ASRC1_STATUS_FMIN_CNTR_MSB 0x0c66 +#define WCD934X_MIXING_ASRC1_STATUS_FMAX_CNTR_LSB 0x0c67 +#define WCD934X_MIXING_ASRC1_STATUS_FMAX_CNTR_MSB 0x0c68 +#define WCD934X_MIXING_ASRC1_STATUS_FIFO 0x0c69 +#define WCD934X_MIXING_ASRC2_CLK_RST_CTL 0x0c6d +#define WCD934X_MIXING_ASRC2_CTL0 0x0c6e +#define WCD934X_MIXING_ASRC2_CTL1 0x0c6f +#define WCD934X_MIXING_ASRC2_FIFO_CTL 0x0c70 +#define WCD934X_MIXING_ASRC2_STATUS_FMIN_CNTR_LSB 0x0c71 +#define WCD934X_MIXING_ASRC2_STATUS_FMIN_CNTR_MSB 0x0c72 +#define WCD934X_MIXING_ASRC2_STATUS_FMAX_CNTR_LSB 0x0c73 +#define WCD934X_MIXING_ASRC2_STATUS_FMAX_CNTR_MSB 0x0c74 +#define WCD934X_MIXING_ASRC2_STATUS_FIFO 0x0c75 +#define WCD934X_MIXING_ASRC3_CLK_RST_CTL 0x0c79 +#define WCD934X_MIXING_ASRC3_CTL0 0x0c7a +#define WCD934X_MIXING_ASRC3_CTL1 0x0c7b +#define WCD934X_MIXING_ASRC3_FIFO_CTL 0x0c7c +#define WCD934X_MIXING_ASRC3_STATUS_FMIN_CNTR_LSB 0x0c7d +#define WCD934X_MIXING_ASRC3_STATUS_FMIN_CNTR_MSB 0x0c7e +#define WCD934X_MIXING_ASRC3_STATUS_FMAX_CNTR_LSB 0x0c7f +#define WCD934X_MIXING_ASRC3_STATUS_FMAX_CNTR_MSB 0x0c80 +#define WCD934X_MIXING_ASRC3_STATUS_FIFO 0x0c81 +#define WCD934X_SWR_AHB_BRIDGE_WR_DATA_0 0x0c85 +#define WCD934X_SWR_AHB_BRIDGE_WR_DATA_1 0x0c86 +#define WCD934X_SWR_AHB_BRIDGE_WR_DATA_2 0x0c87 +#define WCD934X_SWR_AHB_BRIDGE_WR_DATA_3 0x0c88 +#define WCD934X_SWR_AHB_BRIDGE_WR_ADDR_0 0x0c89 +#define WCD934X_SWR_AHB_BRIDGE_WR_ADDR_1 0x0c8a +#define WCD934X_SWR_AHB_BRIDGE_WR_ADDR_2 0x0c8b +#define WCD934X_SWR_AHB_BRIDGE_WR_ADDR_3 0x0c8c +#define WCD934X_SWR_AHB_BRIDGE_RD_ADDR_0 0x0c8d +#define WCD934X_SWR_AHB_BRIDGE_RD_ADDR_1 0x0c8e +#define WCD934X_SWR_AHB_BRIDGE_RD_ADDR_2 0x0c8f +#define WCD934X_SWR_AHB_BRIDGE_RD_ADDR_3 0x0c90 +#define WCD934X_SWR_AHB_BRIDGE_RD_DATA_0 0x0c91 +#define WCD934X_SWR_AHB_BRIDGE_RD_DATA_1 0x0c92 +#define WCD934X_SWR_AHB_BRIDGE_RD_DATA_2 0x0c93 +#define WCD934X_SWR_AHB_BRIDGE_RD_DATA_3 0x0c94 +#define WCD934X_SWR_AHB_BRIDGE_ACCESS_CFG 0x0c95 +#define WCD934X_SWR_AHB_BRIDGE_ACCESS_STATUS 0x0c96 +#define WCD934X_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL 0x0cb5 +#define WCD934X_CDC_SIDETONE_SRC0_ST_SRC_PATH_CFG1 0x0cb6 +#define WCD934X_CDC_SIDETONE_SRC1_ST_SRC_PATH_CTL 0x0cb9 +#define WCD934X_CDC_SIDETONE_SRC1_ST_SRC_PATH_CFG1 0x0cba +#define WCD934X_SIDETONE_ASRC0_CLK_RST_CTL 0x0cbd +#define WCD934X_SIDETONE_ASRC0_CTL0 0x0cbe +#define WCD934X_SIDETONE_ASRC0_CTL1 0x0cbf +#define WCD934X_SIDETONE_ASRC0_FIFO_CTL 0x0cc0 +#define WCD934X_SIDETONE_ASRC0_STATUS_FMIN_CNTR_LSB 0x0cc1 +#define WCD934X_SIDETONE_ASRC0_STATUS_FMIN_CNTR_MSB 0x0cc2 +#define WCD934X_SIDETONE_ASRC0_STATUS_FMAX_CNTR_LSB 0x0cc3 +#define WCD934X_SIDETONE_ASRC0_STATUS_FMAX_CNTR_MSB 0x0cc4 +#define WCD934X_SIDETONE_ASRC0_STATUS_FIFO 0x0cc5 +#define WCD934X_SIDETONE_ASRC1_CLK_RST_CTL 0x0cc9 +#define WCD934X_SIDETONE_ASRC1_CTL0 0x0cca +#define WCD934X_SIDETONE_ASRC1_CTL1 0x0ccb +#define WCD934X_SIDETONE_ASRC1_FIFO_CTL 0x0ccc +#define WCD934X_SIDETONE_ASRC1_STATUS_FMIN_CNTR_LSB 0x0ccd +#define WCD934X_SIDETONE_ASRC1_STATUS_FMIN_CNTR_MSB 0x0cce +#define WCD934X_SIDETONE_ASRC1_STATUS_FMAX_CNTR_LSB 0x0ccf +#define WCD934X_SIDETONE_ASRC1_STATUS_FMAX_CNTR_MSB 0x0cd0 +#define WCD934X_SIDETONE_ASRC1_STATUS_FIFO 0x0cd1 +#define WCD934X_EC_REF_HQ0_EC_REF_HQ_PATH_CTL 0x0cd5 +#define WCD934X_EC_REF_HQ0_EC_REF_HQ_CFG0 0x0cd6 +#define WCD934X_EC_REF_HQ1_EC_REF_HQ_PATH_CTL 0x0cdd +#define WCD934X_EC_REF_HQ1_EC_REF_HQ_CFG0 0x0cde +#define WCD934X_EC_ASRC0_CLK_RST_CTL 0x0ce5 +#define WCD934X_EC_ASRC0_CTL0 0x0ce6 +#define WCD934X_EC_ASRC0_CTL1 0x0ce7 +#define WCD934X_EC_ASRC0_FIFO_CTL 0x0ce8 +#define WCD934X_EC_ASRC0_STATUS_FMIN_CNTR_LSB 0x0ce9 +#define WCD934X_EC_ASRC0_STATUS_FMIN_CNTR_MSB 0x0cea +#define WCD934X_EC_ASRC0_STATUS_FMAX_CNTR_LSB 0x0ceb +#define WCD934X_EC_ASRC0_STATUS_FMAX_CNTR_MSB 0x0cec +#define WCD934X_EC_ASRC0_STATUS_FIFO 0x0ced +#define WCD934X_EC_ASRC1_CLK_RST_CTL 0x0cf1 +#define WCD934X_EC_ASRC1_CTL0 0x0cf2 +#define WCD934X_EC_ASRC1_CTL1 0x0cf3 +#define WCD934X_EC_ASRC1_FIFO_CTL 0x0cf4 +#define WCD934X_EC_ASRC1_STATUS_FMIN_CNTR_LSB 0x0cf5 +#define WCD934X_EC_ASRC1_STATUS_FMIN_CNTR_MSB 0x0cf6 +#define WCD934X_EC_ASRC1_STATUS_FMAX_CNTR_LSB 0x0cf7 +#define WCD934X_EC_ASRC1_STATUS_FMAX_CNTR_MSB 0x0cf8 +#define WCD934X_EC_ASRC1_STATUS_FIFO 0x0cf9 +#define WCD934X_PAGE13_PAGE_REGISTER 0x0d00 +#define WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG0 0x0d01 +#define WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG1 0x0d02 +#define WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG0 0x0d03 +#define WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG1 0x0d04 +#define WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG0 0x0d05 +#define WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG1 0x0d06 +#define WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG0 0x0d07 +#define WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG1 0x0d08 +#define WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG0 0x0d09 +#define WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG1 0x0d0a +#define WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG0 0x0d0f +#define WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG1 0x0d10 +#define WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG0 0x0d11 +#define WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG1 0x0d12 +#define WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG0 0x0d13 +#define WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG1 0x0d14 +#define WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG2 0x0d15 +#define WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG3 0x0d16 +#define WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG4 0x0d17 +#define WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0 0x0d18 +#define WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1 0x0d19 +#define WCD934X_CDC_RX_INP_MUX_ANC_CFG0 0x0d1a +#define WCD934X_CDC_RX_INP_MUX_SPLINE_ASRC_CFG0 0x0d1b +#define WCD934X_CDC_RX_INP_MUX_EC_REF_HQ_CFG0 0x0d1c +#define WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0 0x0d1d +#define WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1 0x0d1e +#define WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG0 0x0d1f +#define WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1 0x0d20 +#define WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG0 0x0d21 +#define WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG1 0x0d22 +#define WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG0 0x0d23 +#define WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1 0x0d25 +#define WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 0x0d26 +#define WCD934X_CDC_TX_INP_MUX_ADC_MUX5_CFG0 0x0d27 +#define WCD934X_CDC_TX_INP_MUX_ADC_MUX6_CFG0 0x0d28 +#define WCD934X_CDC_TX_INP_MUX_ADC_MUX7_CFG0 0x0d29 +#define WCD934X_CDC_TX_INP_MUX_ADC_MUX8_CFG0 0x0d2a +#define WCD934X_CDC_TX_INP_MUX_ADC_MUX10_CFG0 0x0d2b +#define WCD934X_CDC_TX_INP_MUX_ADC_MUX11_CFG0 0x0d2c +#define WCD934X_CDC_TX_INP_MUX_ADC_MUX12_CFG0 0x0d2d +#define WCD934X_CDC_TX_INP_MUX_ADC_MUX13_CFG0 0x0d2e +#define WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0 0x0d31 +#define WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG1 0x0d32 +#define WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG2 0x0d33 +#define WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG3 0x0d34 +#define WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG0 0x0d35 +#define WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG1 0x0d36 +#define WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG2 0x0d37 +#define WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG3 0x0d38 +#define WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0 0x0d3a +#define WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1 0x0d3b +#define WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2 0x0d3c +#define WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3 0x0d3d +#define WCD934X_CDC_CLK_RST_CTRL_MCLK_CONTROL 0x0d41 +#define WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL 0x0d42 +#define WCD934X_CDC_CLK_RST_CTRL_SWR_CONTROL 0x0d43 +#define WCD934X_CDC_CLK_RST_CTRL_DSD_CONTROL 0x0d44 +#define WCD934X_CDC_CLK_RST_CTRL_ASRC_SHARE_CONTROL 0x0d45 +#define WCD934X_CDC_CLK_RST_CTRL_GFM_CONTROL 0x0d46 +#define WCD934X_CDC_PROX_DETECT_PROX_CTL 0x0d49 +#define WCD934X_CDC_PROX_DETECT_PROX_POLL_PERIOD0 0x0d4a +#define WCD934X_CDC_PROX_DETECT_PROX_POLL_PERIOD1 0x0d4b +#define WCD934X_CDC_PROX_DETECT_PROX_SIG_PATTERN_LSB 0x0d4c +#define WCD934X_CDC_PROX_DETECT_PROX_SIG_PATTERN_MSB 0x0d4d +#define WCD934X_CDC_PROX_DETECT_PROX_STATUS 0x0d4e +#define WCD934X_CDC_PROX_DETECT_PROX_TEST_CTRL 0x0d4f +#define WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB 0x0d50 +#define WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB 0x0d51 +#define WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB_RD 0x0d52 +#define WCD934X_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB_RD 0x0d53 +#define WCD934X_CDC_PROX_DETECT_PROX_CTL_REPEAT_PAT 0x0d54 +#define WCD934X_CDC_SIDETONE_IIR0_IIR_PATH_CTL 0x0d55 +#define WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL 0x0d56 +#define WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL 0x0d57 +#define WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL 0x0d58 +#define WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL 0x0d59 +#define WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B5_CTL 0x0d5a +#define WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B6_CTL 0x0d5b +#define WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B7_CTL 0x0d5c +#define WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B8_CTL 0x0d5d +#define WCD934X_CDC_SIDETONE_IIR0_IIR_CTL 0x0d5e +#define WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL 0x0d5f +#define WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL 0x0d60 +#define WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL 0x0d61 +#define WCD934X_CDC_SIDETONE_IIR1_IIR_PATH_CTL 0x0d65 +#define WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL 0x0d66 +#define WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL 0x0d67 +#define WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL 0x0d68 +#define WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL 0x0d69 +#define WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B5_CTL 0x0d6a +#define WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B6_CTL 0x0d6b +#define WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B7_CTL 0x0d6c +#define WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B8_CTL 0x0d6d +#define WCD934X_CDC_SIDETONE_IIR1_IIR_CTL 0x0d6e +#define WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL 0x0d6f +#define WCD934X_CDC_SIDETONE_IIR1_IIR_COEF_B1_CTL 0x0d70 +#define WCD934X_CDC_SIDETONE_IIR1_IIR_COEF_B2_CTL 0x0d71 +#define WCD934X_CDC_TOP_TOP_CFG0 0x0d81 +#define WCD934X_CDC_TOP_TOP_CFG1 0x0d82 +#define WCD934X_CDC_TOP_TOP_CFG7 0x0d88 +#define WCD934X_CDC_TOP_HPHL_COMP_WR_LSB 0x0d89 +#define WCD934X_CDC_TOP_HPHL_COMP_WR_MSB 0x0d8a +#define WCD934X_CDC_TOP_HPHL_COMP_LUT 0x0d8b +#define WCD934X_CDC_TOP_HPHL_COMP_RD_LSB 0x0d8c +#define WCD934X_CDC_TOP_HPHL_COMP_RD_MSB 0x0d8d +#define WCD934X_CDC_TOP_HPHR_COMP_WR_LSB 0x0d8e +#define WCD934X_CDC_TOP_HPHR_COMP_WR_MSB 0x0d8f +#define WCD934X_CDC_TOP_HPHR_COMP_LUT 0x0d90 +#define WCD934X_CDC_TOP_HPHR_COMP_RD_LSB 0x0d91 +#define WCD934X_CDC_TOP_HPHR_COMP_RD_MSB 0x0d92 +#define WCD934X_CDC_TOP_DIFFL_COMP_WR_LSB 0x0d93 +#define WCD934X_CDC_TOP_DIFFL_COMP_WR_MSB 0x0d94 +#define WCD934X_CDC_TOP_DIFFL_COMP_LUT 0x0d95 +#define WCD934X_CDC_TOP_DIFFL_COMP_RD_LSB 0x0d96 +#define WCD934X_CDC_TOP_DIFFL_COMP_RD_MSB 0x0d97 +#define WCD934X_CDC_TOP_DIFFR_COMP_WR_LSB 0x0d98 +#define WCD934X_CDC_TOP_DIFFR_COMP_WR_MSB 0x0d99 +#define WCD934X_CDC_TOP_DIFFR_COMP_LUT 0x0d9a +#define WCD934X_CDC_TOP_DIFFR_COMP_RD_LSB 0x0d9b +#define WCD934X_CDC_TOP_DIFFR_COMP_RD_MSB 0x0d9c +#define WCD934X_CDC_DSD0_PATH_CTL 0x0db1 +#define WCD934X_CDC_DSD0_CFG0 0x0db2 +#define WCD934X_CDC_DSD0_CFG1 0x0db3 +#define WCD934X_CDC_DSD0_CFG2 0x0db4 +#define WCD934X_CDC_DSD0_CFG3 0x0db5 +#define WCD934X_CDC_DSD0_CFG4 0x0db6 +#define WCD934X_CDC_DSD0_CFG5 0x0db7 +#define WCD934X_CDC_DSD1_PATH_CTL 0x0dc1 +#define WCD934X_CDC_DSD1_CFG0 0x0dc2 +#define WCD934X_CDC_DSD1_CFG1 0x0dc3 +#define WCD934X_CDC_DSD1_CFG2 0x0dc4 +#define WCD934X_CDC_DSD1_CFG3 0x0dc5 +#define WCD934X_CDC_DSD1_CFG4 0x0dc6 +#define WCD934X_CDC_DSD1_CFG5 0x0dc7 +#define WCD934X_CDC_RX_IDLE_DET_PATH_CTL 0x0dd1 +#define WCD934X_CDC_RX_IDLE_DET_CFG0 0x0dd2 +#define WCD934X_CDC_RX_IDLE_DET_CFG1 0x0dd3 +#define WCD934X_CDC_RX_IDLE_DET_CFG2 0x0dd4 +#define WCD934X_CDC_RX_IDLE_DET_CFG3 0x0dd5 +#define WCD934X_PAGE14_PAGE_REGISTER 0x0e00 +#define WCD934X_CDC_RATE_EST0_RE_CLK_RST_CTL 0x0e01 +#define WCD934X_CDC_RATE_EST0_RE_CTL 0x0e02 +#define WCD934X_CDC_RATE_EST0_RE_PULSE_SUPR_CTL 0x0e03 +#define WCD934X_CDC_RATE_EST0_RE_TIMER 0x0e04 +#define WCD934X_CDC_RATE_EST0_RE_BW_SW 0x0e05 +#define WCD934X_CDC_RATE_EST0_RE_THRESH 0x0e06 +#define WCD934X_CDC_RATE_EST0_RE_STATUS 0x0e07 +#define WCD934X_CDC_RATE_EST0_RE_DIAG_CTRL 0x0e09 +#define WCD934X_CDC_RATE_EST0_RE_DIAG_TIMER2 0x0e0c +#define WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW1 0x0e0d +#define WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW2 0x0e0e +#define WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW3 0x0e0f +#define WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW4 0x0e10 +#define WCD934X_CDC_RATE_EST0_RE_DIAG_OFFSET_BW5 0x0e11 +#define WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW1 0x0e12 +#define WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW2 0x0e13 +#define WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW3 0x0e14 +#define WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW4 0x0e15 +#define WCD934X_CDC_RATE_EST0_RE_DIAG_LIMIT_BW5 0x0e16 +#define WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW1 0x0e17 +#define WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW2 0x0e18 +#define WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW3 0x0e19 +#define WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW4 0x0e1a +#define WCD934X_CDC_RATE_EST0_RE_DIAG_LIMITD1_BW5 0x0e1b +#define WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW1 0x0e1c +#define WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW2 0x0e1d +#define WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW3 0x0e1e +#define WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW4 0x0e1f +#define WCD934X_CDC_RATE_EST0_RE_DIAG_HYST_BW5 0x0e20 +#define WCD934X_CDC_RATE_EST0_RE_RMAX_DIAG 0x0e21 +#define WCD934X_CDC_RATE_EST0_RE_RMIN_DIAG 0x0e22 +#define WCD934X_CDC_RATE_EST0_RE_PH_DET 0x0e23 +#define WCD934X_CDC_RATE_EST0_RE_DIAG_CLR 0x0e24 +#define WCD934X_CDC_RATE_EST0_RE_MB_SW_STATE 0x0e25 +#define WCD934X_CDC_RATE_EST0_RE_MAST_DIAG_STATE 0x0e26 +#define WCD934X_CDC_RATE_EST0_RE_RATE_OUT_7_0 0x0e27 +#define WCD934X_CDC_RATE_EST0_RE_RATE_OUT_15_8 0x0e28 +#define WCD934X_CDC_RATE_EST0_RE_RATE_OUT_23_16 0x0e29 +#define WCD934X_CDC_RATE_EST0_RE_RATE_OUT_31_24 0x0e2a +#define WCD934X_CDC_RATE_EST0_RE_RATE_OUT_39_32 0x0e2b +#define WCD934X_CDC_RATE_EST0_RE_RATE_OUT_40_43 0x0e2c +#define WCD934X_CDC_RATE_EST1_RE_CLK_RST_CTL 0x0e31 +#define WCD934X_CDC_RATE_EST1_RE_CTL 0x0e32 +#define WCD934X_CDC_RATE_EST1_RE_PULSE_SUPR_CTL 0x0e33 +#define WCD934X_CDC_RATE_EST1_RE_TIMER 0x0e34 +#define WCD934X_CDC_RATE_EST1_RE_BW_SW 0x0e35 +#define WCD934X_CDC_RATE_EST1_RE_THRESH 0x0e36 +#define WCD934X_CDC_RATE_EST1_RE_STATUS 0x0e37 +#define WCD934X_CDC_RATE_EST1_RE_DIAG_CTRL 0x0e39 +#define WCD934X_CDC_RATE_EST1_RE_DIAG_TIMER2 0x0e3c +#define WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW1 0x0e3d +#define WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW2 0x0e3e +#define WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW3 0x0e3f +#define WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW4 0x0e40 +#define WCD934X_CDC_RATE_EST1_RE_DIAG_OFFSET_BW5 0x0e41 +#define WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW1 0x0e42 +#define WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW2 0x0e43 +#define WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW3 0x0e44 +#define WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW4 0x0e45 +#define WCD934X_CDC_RATE_EST1_RE_DIAG_LIMIT_BW5 0x0e46 +#define WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW1 0x0e47 +#define WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW2 0x0e48 +#define WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW3 0x0e49 +#define WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW4 0x0e4a +#define WCD934X_CDC_RATE_EST1_RE_DIAG_LIMITD1_BW5 0x0e4b +#define WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW1 0x0e4c +#define WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW2 0x0e4d +#define WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW3 0x0e4e +#define WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW4 0x0e4f +#define WCD934X_CDC_RATE_EST1_RE_DIAG_HYST_BW5 0x0e50 +#define WCD934X_CDC_RATE_EST1_RE_RMAX_DIAG 0x0e51 +#define WCD934X_CDC_RATE_EST1_RE_RMIN_DIAG 0x0e52 +#define WCD934X_CDC_RATE_EST1_RE_PH_DET 0x0e53 +#define WCD934X_CDC_RATE_EST1_RE_DIAG_CLR 0x0e54 +#define WCD934X_CDC_RATE_EST1_RE_MB_SW_STATE 0x0e55 +#define WCD934X_CDC_RATE_EST1_RE_MAST_DIAG_STATE 0x0e56 +#define WCD934X_CDC_RATE_EST1_RE_RATE_OUT_7_0 0x0e57 +#define WCD934X_CDC_RATE_EST1_RE_RATE_OUT_15_8 0x0e58 +#define WCD934X_CDC_RATE_EST1_RE_RATE_OUT_23_16 0x0e59 +#define WCD934X_CDC_RATE_EST1_RE_RATE_OUT_31_24 0x0e5a +#define WCD934X_CDC_RATE_EST1_RE_RATE_OUT_39_32 0x0e5b +#define WCD934X_CDC_RATE_EST1_RE_RATE_OUT_40_43 0x0e5c +#define WCD934X_CDC_RATE_EST2_RE_CLK_RST_CTL 0x0e61 +#define WCD934X_CDC_RATE_EST2_RE_CTL 0x0e62 +#define WCD934X_CDC_RATE_EST2_RE_PULSE_SUPR_CTL 0x0e63 +#define WCD934X_CDC_RATE_EST2_RE_TIMER 0x0e64 +#define WCD934X_CDC_RATE_EST2_RE_BW_SW 0x0e65 +#define WCD934X_CDC_RATE_EST2_RE_THRESH 0x0e66 +#define WCD934X_CDC_RATE_EST2_RE_STATUS 0x0e67 +#define WCD934X_CDC_RATE_EST2_RE_DIAG_CTRL 0x0e69 +#define WCD934X_CDC_RATE_EST2_RE_DIAG_TIMER2 0x0e6c +#define WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW1 0x0e6d +#define WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW2 0x0e6e +#define WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW3 0x0e6f +#define WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW4 0x0e70 +#define WCD934X_CDC_RATE_EST2_RE_DIAG_OFFSET_BW5 0x0e71 +#define WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW1 0x0e72 +#define WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW2 0x0e73 +#define WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW3 0x0e74 +#define WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW4 0x0e75 +#define WCD934X_CDC_RATE_EST2_RE_DIAG_LIMIT_BW5 0x0e76 +#define WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW1 0x0e77 +#define WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW2 0x0e78 +#define WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW3 0x0e79 +#define WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW4 0x0e7a +#define WCD934X_CDC_RATE_EST2_RE_DIAG_LIMITD1_BW5 0x0e7b +#define WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW1 0x0e7c +#define WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW2 0x0e7d +#define WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW3 0x0e7e +#define WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW4 0x0e7f +#define WCD934X_CDC_RATE_EST2_RE_DIAG_HYST_BW5 0x0e80 +#define WCD934X_CDC_RATE_EST2_RE_RMAX_DIAG 0x0e81 +#define WCD934X_CDC_RATE_EST2_RE_RMIN_DIAG 0x0e82 +#define WCD934X_CDC_RATE_EST2_RE_PH_DET 0x0e83 +#define WCD934X_CDC_RATE_EST2_RE_DIAG_CLR 0x0e84 +#define WCD934X_CDC_RATE_EST2_RE_MB_SW_STATE 0x0e85 +#define WCD934X_CDC_RATE_EST2_RE_MAST_DIAG_STATE 0x0e86 +#define WCD934X_CDC_RATE_EST2_RE_RATE_OUT_7_0 0x0e87 +#define WCD934X_CDC_RATE_EST2_RE_RATE_OUT_15_8 0x0e88 +#define WCD934X_CDC_RATE_EST2_RE_RATE_OUT_23_16 0x0e89 +#define WCD934X_CDC_RATE_EST2_RE_RATE_OUT_31_24 0x0e8a +#define WCD934X_CDC_RATE_EST2_RE_RATE_OUT_39_32 0x0e8b +#define WCD934X_CDC_RATE_EST2_RE_RATE_OUT_40_43 0x0e8c +#define WCD934X_CDC_RATE_EST3_RE_CLK_RST_CTL 0x0e91 +#define WCD934X_CDC_RATE_EST3_RE_CTL 0x0e92 +#define WCD934X_CDC_RATE_EST3_RE_PULSE_SUPR_CTL 0x0e93 +#define WCD934X_CDC_RATE_EST3_RE_TIMER 0x0e94 +#define WCD934X_CDC_RATE_EST3_RE_BW_SW 0x0e95 +#define WCD934X_CDC_RATE_EST3_RE_THRESH 0x0e96 +#define WCD934X_CDC_RATE_EST3_RE_STATUS 0x0e97 +#define WCD934X_CDC_RATE_EST3_RE_DIAG_CTRL 0x0e99 +#define WCD934X_CDC_RATE_EST3_RE_DIAG_TIMER2 0x0e9c +#define WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW1 0x0e9d +#define WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW2 0x0e9e +#define WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW3 0x0e9f +#define WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW4 0x0ea0 +#define WCD934X_CDC_RATE_EST3_RE_DIAG_OFFSET_BW5 0x0ea1 +#define WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW1 0x0ea2 +#define WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW2 0x0ea3 +#define WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW3 0x0ea4 +#define WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW4 0x0ea5 +#define WCD934X_CDC_RATE_EST3_RE_DIAG_LIMIT_BW5 0x0ea6 +#define WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW1 0x0ea7 +#define WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW2 0x0ea8 +#define WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW3 0x0ea9 +#define WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW4 0x0eaa +#define WCD934X_CDC_RATE_EST3_RE_DIAG_LIMITD1_BW5 0x0eab +#define WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW1 0x0eac +#define WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW2 0x0ead +#define WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW3 0x0eae +#define WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW4 0x0eaf +#define WCD934X_CDC_RATE_EST3_RE_DIAG_HYST_BW5 0x0eb0 +#define WCD934X_CDC_RATE_EST3_RE_RMAX_DIAG 0x0eb1 +#define WCD934X_CDC_RATE_EST3_RE_RMIN_DIAG 0x0eb2 +#define WCD934X_CDC_RATE_EST3_RE_PH_DET 0x0eb3 +#define WCD934X_CDC_RATE_EST3_RE_DIAG_CLR 0x0eb4 +#define WCD934X_CDC_RATE_EST3_RE_MB_SW_STATE 0x0eb5 +#define WCD934X_CDC_RATE_EST3_RE_MAST_DIAG_STATE 0x0eb6 +#define WCD934X_CDC_RATE_EST3_RE_RATE_OUT_7_0 0x0eb7 +#define WCD934X_CDC_RATE_EST3_RE_RATE_OUT_15_8 0x0eb8 +#define WCD934X_CDC_RATE_EST3_RE_RATE_OUT_23_16 0x0eb9 +#define WCD934X_CDC_RATE_EST3_RE_RATE_OUT_31_24 0x0eba +#define WCD934X_CDC_RATE_EST3_RE_RATE_OUT_39_32 0x0ebb +#define WCD934X_CDC_RATE_EST3_RE_RATE_OUT_40_43 0x0ebc +#define WCD934X_PAGE15_PAGE_REGISTER 0x0f00 +#define WCD934X_SPLINE_SRC0_CLK_RST_CTL_0 0x0f01 +#define WCD934X_SPLINE_SRC0_STATUS 0x0f02 +#define WCD934X_SPLINE_SRC1_CLK_RST_CTL_0 0x0f19 +#define WCD934X_SPLINE_SRC1_STATUS 0x0f1a +#define WCD934X_SPLINE_SRC2_CLK_RST_CTL_0 0x0f31 +#define WCD934X_SPLINE_SRC2_STATUS 0x0f32 +#define WCD934X_SPLINE_SRC3_CLK_RST_CTL_0 0x0f49 +#define WCD934X_SPLINE_SRC3_STATUS 0x0f4a +#define WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG0 0x0fa1 +#define WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG1 0x0fa2 +#define WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG2 0x0fa3 +#define WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG3 0x0fa4 +#define WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG0 0x0fa5 +#define WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG1 0x0fa6 +#define WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG2 0x0fa7 +#define WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG3 0x0fa8 +#define WCD934X_CDC_DEBUG_SPLINE_SRC_DEBUG_CFG0 0x0fa9 +#define WCD934X_CDC_DEBUG_SPLINE_SRC_DEBUG_CFG1 0x0faa +#define WCD934X_CDC_DEBUG_RC_RE_ASRC_DEBUG_CFG0 0x0fab +#define WCD934X_CDC_DEBUG_ANC0_RC0_FIFO_CTL 0x0fac +#define WCD934X_CDC_DEBUG_ANC0_RC1_FIFO_CTL 0x0fad +#define WCD934X_CDC_DEBUG_ANC1_RC0_FIFO_CTL 0x0fae +#define WCD934X_CDC_DEBUG_ANC1_RC1_FIFO_CTL 0x0faf +#define WCD934X_CDC_DEBUG_ANC_RC_RST_DBG_CNTR 0x0fb0 +#define WCD934X_PAGE80_PAGE_REGISTER 0x5000 +#define WCD934X_CODEC_CPR_WR_DATA_0 0x5001 +#define WCD934X_CODEC_CPR_WR_DATA_1 0x5002 +#define WCD934X_CODEC_CPR_WR_DATA_2 0x5003 +#define WCD934X_CODEC_CPR_WR_DATA_3 0x5004 +#define WCD934X_CODEC_CPR_WR_ADDR_0 0x5005 +#define WCD934X_CODEC_CPR_WR_ADDR_1 0x5006 +#define WCD934X_CODEC_CPR_WR_ADDR_2 0x5007 +#define WCD934X_CODEC_CPR_WR_ADDR_3 0x5008 +#define WCD934X_CODEC_CPR_RD_ADDR_0 0x5009 +#define WCD934X_CODEC_CPR_RD_ADDR_1 0x500a +#define WCD934X_CODEC_CPR_RD_ADDR_2 0x500b +#define WCD934X_CODEC_CPR_RD_ADDR_3 0x500c +#define WCD934X_CODEC_CPR_RD_DATA_0 0x500d +#define WCD934X_CODEC_CPR_RD_DATA_1 0x500e +#define WCD934X_CODEC_CPR_RD_DATA_2 0x500f +#define WCD934X_CODEC_CPR_RD_DATA_3 0x5010 +#define WCD934X_CODEC_CPR_ACCESS_CFG 0x5011 +#define WCD934X_CODEC_CPR_ACCESS_STATUS 0x5012 +#define WCD934X_CODEC_CPR_NOM_CX_VDD 0x5021 +#define WCD934X_CODEC_CPR_SVS_CX_VDD 0x5022 +#define WCD934X_CODEC_CPR_SVS2_CX_VDD 0x5023 +#define WCD934X_CODEC_CPR_NOM_MX_VDD 0x5024 +#define WCD934X_CODEC_CPR_SVS_MX_VDD 0x5025 +#define WCD934X_CODEC_CPR_SVS2_MX_VDD 0x5026 +#define WCD934X_CODEC_CPR_SVS2_MIN_CX_VDD 0x5027 +#define WCD934X_CODEC_CPR_MAX_SVS2_STEP 0x5028 +#define WCD934X_CODEC_CPR_CTL 0x5029 +#define WCD934X_CODEC_CPR_SW_MODECHNG_STATUS 0x502a +#define WCD934X_CODEC_CPR_SW_MODECHNG_START 0x502b +#define WCD934X_CODEC_CPR_CPR_STATUS 0x502c +#define WCD934X_PAGE128_PAGE_REGISTER 0x8000 +#define WCD934X_TLMM_BIST_MODE_PINCFG 0x8001 +#define WCD934X_TLMM_RF_PA_ON_PINCFG 0x8002 +#define WCD934X_TLMM_INTR1_PINCFG 0x8003 +#define WCD934X_TLMM_INTR2_PINCFG 0x8004 +#define WCD934X_TLMM_SWR_DATA_PINCFG 0x8005 +#define WCD934X_TLMM_SWR_CLK_PINCFG 0x8006 +#define WCD934X_TLMM_I2S_2_SCK_PINCFG 0x8007 +#define WCD934X_TLMM_SLIMBUS_DATA1_PINCFG 0x8008 +#define WCD934X_TLMM_SLIMBUS_DATA2_PINCFG 0x8009 +#define WCD934X_TLMM_SLIMBUS_CLK_PINCFG 0x800a +#define WCD934X_TLMM_I2C_CLK_PINCFG 0x800b +#define WCD934X_TLMM_I2C_DATA_PINCFG 0x800c +#define WCD934X_TLMM_I2S_0_RX_PINCFG 0x800d +#define WCD934X_TLMM_I2S_0_TX_PINCFG 0x800e +#define WCD934X_TLMM_I2S_0_SCK_PINCFG 0x800f +#define WCD934X_TLMM_I2S_0_WS_PINCFG 0x8010 +#define WCD934X_TLMM_I2S_1_RX_PINCFG 0x8011 +#define WCD934X_TLMM_I2S_1_TX_PINCFG 0x8012 +#define WCD934X_TLMM_I2S_1_SCK_PINCFG 0x8013 +#define WCD934X_TLMM_I2S_1_WS_PINCFG 0x8014 +#define WCD934X_TLMM_DMIC1_CLK_PINCFG 0x8015 +#define WCD934X_TLMM_DMIC1_DATA_PINCFG 0x8016 +#define WCD934X_TLMM_DMIC2_CLK_PINCFG 0x8017 +#define WCD934X_TLMM_DMIC2_DATA_PINCFG 0x8018 +#define WCD934X_TLMM_DMIC3_CLK_PINCFG 0x8019 +#define WCD934X_TLMM_DMIC3_DATA_PINCFG 0x801a +#define WCD934X_TLMM_JTCK_PINCFG 0x801b +#define WCD934X_TLMM_GPIO1_PINCFG 0x801c +#define WCD934X_TLMM_GPIO2_PINCFG 0x801d +#define WCD934X_TLMM_GPIO3_PINCFG 0x801e +#define WCD934X_TLMM_GPIO4_PINCFG 0x801f +#define WCD934X_TLMM_SPI_S_CSN_PINCFG 0x8020 +#define WCD934X_TLMM_SPI_S_CLK_PINCFG 0x8021 +#define WCD934X_TLMM_SPI_S_DOUT_PINCFG 0x8022 +#define WCD934X_TLMM_SPI_S_DIN_PINCFG 0x8023 +#define WCD934X_TLMM_BA_N_PINCFG 0x8024 +#define WCD934X_TLMM_GPIO0_PINCFG 0x8025 +#define WCD934X_TLMM_I2S_2_RX_PINCFG 0x8026 +#define WCD934X_TLMM_I2S_2_WS_PINCFG 0x8027 +#define WCD934X_TEST_DEBUG_PIN_CTL_OE_0 0x8031 +#define WCD934X_TEST_DEBUG_PIN_CTL_OE_1 0x8032 +#define WCD934X_TEST_DEBUG_PIN_CTL_OE_2 0x8033 +#define WCD934X_TEST_DEBUG_PIN_CTL_OE_3 0x8034 +#define WCD934X_TEST_DEBUG_PIN_CTL_OE_4 0x8035 +#define WCD934X_TEST_DEBUG_PIN_CTL_DATA_0 0x8036 +#define WCD934X_TEST_DEBUG_PIN_CTL_DATA_1 0x8037 +#define WCD934X_TEST_DEBUG_PIN_CTL_DATA_2 0x8038 +#define WCD934X_TEST_DEBUG_PIN_CTL_DATA_3 0x8039 +#define WCD934X_TEST_DEBUG_PIN_CTL_DATA_4 0x803a +#define WCD934X_TEST_DEBUG_PAD_DRVCTL_0 0x803b +#define WCD934X_TEST_DEBUG_PAD_DRVCTL_1 0x803c +#define WCD934X_TEST_DEBUG_PIN_STATUS 0x803d +#define WCD934X_TEST_DEBUG_NPL_DLY_TEST_1 0x803e +#define WCD934X_TEST_DEBUG_NPL_DLY_TEST_2 0x803f +#define WCD934X_TEST_DEBUG_MEM_CTRL 0x8040 +#define WCD934X_TEST_DEBUG_DEBUG_BUS_SEL 0x8041 +#define WCD934X_TEST_DEBUG_DEBUG_JTAG 0x8042 +#define WCD934X_TEST_DEBUG_DEBUG_EN_1 0x8043 +#define WCD934X_TEST_DEBUG_DEBUG_EN_2 0x8044 +#define WCD934X_TEST_DEBUG_DEBUG_EN_3 0x8045 +#define WCD934X_TEST_DEBUG_DEBUG_EN_4 0x8046 +#define WCD934X_TEST_DEBUG_DEBUG_EN_5 0x8047 +#define WCD934X_TEST_DEBUG_ANA_DTEST_DIR 0x804a +#define WCD934X_TEST_DEBUG_PAD_INP_DISABLE_0 0x804b +#define WCD934X_TEST_DEBUG_PAD_INP_DISABLE_1 0x804c +#define WCD934X_TEST_DEBUG_PAD_INP_DISABLE_2 0x804d +#define WCD934X_TEST_DEBUG_PAD_INP_DISABLE_3 0x804e +#define WCD934X_TEST_DEBUG_PAD_INP_DISABLE_4 0x804f +#define WCD934X_TEST_DEBUG_SYSMEM_CTRL 0x8050 +#define WCD934X_TEST_DEBUG_SOC_SW_PWR_SEQ_DELAY 0x8051 +#define WCD934X_TEST_DEBUG_LVAL_NOM_LOW 0x8052 +#define WCD934X_TEST_DEBUG_LVAL_NOM_HIGH 0x8053 +#define WCD934X_TEST_DEBUG_LVAL_SVS_SVS2_LOW 0x8054 +#define WCD934X_TEST_DEBUG_LVAL_SVS_SVS2_HIGH 0x8055 +#define WCD934X_TEST_DEBUG_SPI_SLAVE_CHAR 0x8056 +#define WCD934X_TEST_DEBUG_CODEC_DIAGS 0x8057 +#define WCD934X_MAX_REGISTER 0x80FF + +/* SLIMBUS Slave Registers */ +#define WCD934X_SLIM_PGD_PORT_INT_RX_EN0 (0x30) +#define WCD934X_SLIM_PGD_PORT_INT_TX_EN0 (0x32) +#define WCD934X_SLIM_PGD_PORT_INT_STATUS_RX_0 (0x34) +#define WCD934X_SLIM_PGD_PORT_INT_STATUS_RX_1 (0x35) +#define WCD934X_SLIM_PGD_PORT_INT_STATUS_TX_0 (0x36) +#define WCD934X_SLIM_PGD_PORT_INT_STATUS_TX_1 (0x37) +#define WCD934X_SLIM_PGD_PORT_INT_CLR_RX_0 (0x38) +#define WCD934X_SLIM_PGD_PORT_INT_CLR_RX_1 (0x39) +#define WCD934X_SLIM_PGD_PORT_INT_CLR_TX_0 (0x3A) +#define WCD934X_SLIM_PGD_PORT_INT_CLR_TX_1 (0x3B) +#define WCD934X_SLIM_PGD_PORT_INT_RX_SOURCE0 (0x60) +#define WCD934X_SLIM_PGD_PORT_INT_TX_SOURCE0 (0x70) + +#endif diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h index 96937a4338a8..75908dfa8d64 100644 --- a/include/linux/mfd/wcd9xxx/core.h +++ b/include/linux/mfd/wcd9xxx/core.h @@ -76,6 +76,7 @@ enum codec_variant { WCD9330, WCD9335, WCD9326, + WCD934X, }; enum wcd9xxx_slim_slave_addr_type { @@ -252,6 +253,7 @@ enum wcd9xxx_chipid_major { TOMTOM_MAJOR = cpu_to_le16(0x105), TASHA_MAJOR = cpu_to_le16(0x0), TASHA2P0_MAJOR = cpu_to_le16(0x107), + TAVIL_MAJOR = cpu_to_le16(0x108), }; enum codec_power_states { @@ -328,6 +330,7 @@ struct wcd9xxx { struct wcd9xxx_codec_type *codec_type; bool prev_pg_valid; u8 prev_pg; + u8 avoid_cdc_rstlow; struct wcd9xxx_power_region *wcd9xxx_pwr[WCD9XXX_MAX_PWR_REGIONS]; }; diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx-utils.h b/include/linux/mfd/wcd9xxx/wcd9xxx-utils.h index 441d70b97f4e..7c35d7fecc50 100644 --- a/include/linux/mfd/wcd9xxx/wcd9xxx-utils.h +++ b/include/linux/mfd/wcd9xxx/wcd9xxx-utils.h @@ -33,6 +33,13 @@ typedef int (*codec_bringdown_fn)(struct wcd9xxx *); typedef int (*codec_type_fn)(struct wcd9xxx *, struct wcd9xxx_codec_type *); +#ifdef CONFIG_WCD934X_CODEC +extern int wcd934x_bringup(struct wcd9xxx *wcd9xxx); +extern int wcd934x_bringdown(struct wcd9xxx *wcd9xxx); +extern int wcd934x_get_codec_info(struct wcd9xxx *, + struct wcd9xxx_codec_type *); +#endif + #ifdef CONFIG_WCD9335_CODEC extern int wcd9335_bringup(struct wcd9xxx *wcd9xxx); extern int wcd9335_bringdown(struct wcd9xxx *wcd9xxx); @@ -52,6 +59,11 @@ static inline codec_bringdown_fn wcd9xxx_bringdown_fn(int type) codec_bringdown_fn cdc_bdown_fn; switch (type) { +#ifdef CONFIG_WCD934X_CODEC + case WCD934X: + cdc_bdown_fn = wcd934x_bringdown; + break; +#endif #ifdef CONFIG_WCD9335_CODEC case WCD9335: cdc_bdown_fn = wcd9335_bringdown; @@ -75,6 +87,11 @@ static inline codec_bringup_fn wcd9xxx_bringup_fn(int type) codec_bringup_fn cdc_bup_fn; switch (type) { +#ifdef CONFIG_WCD934X_CODEC + case WCD934X: + cdc_bup_fn = wcd934x_bringup; + break; +#endif #ifdef CONFIG_WCD9335_CODEC case WCD9335: cdc_bup_fn = wcd9335_bringup; @@ -98,6 +115,11 @@ static inline codec_type_fn wcd9xxx_get_codec_info_fn(int type) codec_type_fn cdc_type_fn; switch (type) { +#ifdef CONFIG_WCD934X_CODEC + case WCD934X: + cdc_type_fn = wcd934x_get_codec_info; + break; +#endif #ifdef CONFIG_WCD9335_CODEC case WCD9335: cdc_type_fn = wcd9335_get_codec_info; diff --git a/include/linux/msm_thermal.h b/include/linux/msm_thermal.h index 52331a5897f2..f3ec960536aa 100644 --- a/include/linux/msm_thermal.h +++ b/include/linux/msm_thermal.h @@ -74,6 +74,7 @@ struct msm_thermal_data { int32_t cx_phase_request_key; int32_t vdd_mx_temp_degC; int32_t vdd_mx_temp_hyst_degC; + int32_t vdd_mx_sensor_id; int32_t therm_reset_temp_degC; }; diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index c0e961474a52..5455b660bd88 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -544,9 +544,7 @@ extern int nfs_readpage_async(struct nfs_open_context *, struct inode *, static inline loff_t nfs_size_to_loff_t(__u64 size) { - if (size > (__u64) OFFSET_MAX - 1) - return OFFSET_MAX - 1; - return (loff_t) size; + return min_t(u64, size, OFFSET_MAX); } static inline ino_t diff --git a/include/linux/of_batterydata.h b/include/linux/of_batterydata.h index fe2c996de264..5505371488d0 100644 --- a/include/linux/of_batterydata.h +++ b/include/linux/of_batterydata.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -39,10 +39,7 @@ int of_batterydata_read_data(struct device_node *container_node, * of_batterydata_get_best_profile() - Find matching battery data device node * @batterydata_container_node: pointer to the battery-data container device * node containing the profile nodes. - * @psy_name: Name of the power supply which holds the - * POWER_SUPPLY_RESISTANCE_ID value to be used to match - * against the id resistances specified in the corresponding - * battery data profiles. + * @batt_id_kohm: Battery ID in KOhms for which we want to find the profile. * @batt_type: Battery type which we want to force load the profile. * * This routine returns a device_node pointer to the closest match battery data @@ -50,7 +47,7 @@ int of_batterydata_read_data(struct device_node *container_node, */ struct device_node *of_batterydata_get_best_profile( struct device_node *batterydata_container_node, - const char *psy_name, const char *batt_type); + int batt_id_kohm, const char *batt_type); #else static inline int of_batterydata_read_data(struct device_node *container_node, struct bms_battery_data *batt_data, @@ -60,7 +57,7 @@ static inline int of_batterydata_read_data(struct device_node *container_node, } static inline struct device_node *of_batterydata_get_best_profile( struct device_node *batterydata_container_node, - struct device_node *best_node, const char *psy_name) + int batt_id_kohm, const char *batt_type) { return -ENXIO; } diff --git a/include/linux/sched.h b/include/linux/sched.h index 61a5c00e66cd..06dd540192c7 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1482,6 +1482,7 @@ struct task_struct { u32 init_load_pct; u64 last_wake_ts; u64 last_switch_out_ts; + u64 last_cpu_selected_ts; struct related_thread_group *grp; struct list_head grp_list; u64 cpu_cycles; diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h index 50777b5b1e4c..92d112aeec68 100644 --- a/include/linux/shmem_fs.h +++ b/include/linux/shmem_fs.h @@ -15,10 +15,7 @@ struct shmem_inode_info { unsigned int seals; /* shmem seals */ unsigned long flags; unsigned long alloced; /* data pages alloced to file */ - union { - unsigned long swapped; /* subtotal assigned to swap */ - char *symlink; /* unswappable short symlink */ - }; + unsigned long swapped; /* subtotal assigned to swap */ struct shared_policy policy; /* NUMA memory alloc policy */ struct list_head swaplist; /* chain of maybes on swap */ struct simple_xattrs xattrs; /* list of xattrs */ diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 9147f9f34cbe..75f136a22a5e 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -219,6 +219,7 @@ struct sk_buff; #else #define MAX_SKB_FRAGS (65536/PAGE_SIZE + 1) #endif +extern int sysctl_max_skb_frags; typedef struct skb_frag_struct skb_frag_t; diff --git a/include/linux/thermal.h b/include/linux/thermal.h index e7f3180bcb95..a81516c611c4 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -43,6 +43,9 @@ /* Default weight of a bound cooling device */ #define THERMAL_WEIGHT_DEFAULT 0 +/* use value, which < 0K, to indicate an invalid/uninitialized temperature */ +#define THERMAL_TEMP_INVALID -274000 + /* Unit conversion macros */ #define DECI_KELVIN_TO_CELSIUS(t) ({ \ long _t = (t); \ @@ -201,6 +204,7 @@ struct sensor_info { * @forced_passive: If > 0, temperature at which to switch on all ACPI * processor cooling devices. Currently only used by the * step-wise governor. + * @need_update: if equals 1, thermal_zone_device_update needs to be invoked. * @ops: operations this &thermal_zone_device supports * @tzp: thermal zone parameters * @governor: pointer to the governor for this thermal zone @@ -228,6 +232,7 @@ struct thermal_zone_device { int emul_temperature; int passive; unsigned int forced_passive; + atomic_t need_update; struct thermal_zone_device_ops *ops; struct thermal_zone_params *tzp; struct thermal_governor *governor; diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h index f01c2ff9845b..6ff6ab8534dd 100644 --- a/include/linux/trace_events.h +++ b/include/linux/trace_events.h @@ -575,6 +575,8 @@ enum { FILTER_DYN_STRING, FILTER_PTR_STRING, FILTER_TRACE_FN, + FILTER_COMM, + FILTER_CPU, }; extern int trace_event_raw_init(struct trace_event_call *call); diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index 03c7efb60c91..27e32b2b602f 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h @@ -148,9 +148,6 @@ extern void syscall_unregfunc(void); void *it_func; \ void *__data; \ \ - if (!cpu_online(raw_smp_processor_id())) \ - return; \ - \ if (!(cond)) \ return; \ prercu; \ @@ -357,15 +354,19 @@ extern void syscall_unregfunc(void); * "void *__data, proto" as the callback prototype. */ #define DECLARE_TRACE_NOARGS(name) \ - __DECLARE_TRACE(name, void, , 1, void *__data, __data) + __DECLARE_TRACE(name, void, , \ + cpu_online(raw_smp_processor_id()), \ + void *__data, __data) #define DECLARE_TRACE(name, proto, args) \ - __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), 1, \ - PARAMS(void *__data, proto), \ - PARAMS(__data, args)) + __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), \ + cpu_online(raw_smp_processor_id()), \ + PARAMS(void *__data, proto), \ + PARAMS(__data, args)) #define DECLARE_TRACE_CONDITION(name, proto, args, cond) \ - __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), PARAMS(cond), \ + __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), \ + cpu_online(raw_smp_processor_id()) && (PARAMS(cond)), \ PARAMS(void *__data, proto), \ PARAMS(__data, args)) diff --git a/include/linux/ucs2_string.h b/include/linux/ucs2_string.h index cbb20afdbc01..bb679b48f408 100644 --- a/include/linux/ucs2_string.h +++ b/include/linux/ucs2_string.h @@ -11,4 +11,8 @@ unsigned long ucs2_strlen(const ucs2_char_t *s); unsigned long ucs2_strsize(const ucs2_char_t *data, unsigned long maxlength); int ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len); +unsigned long ucs2_utf8size(const ucs2_char_t *src); +unsigned long ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, + unsigned long maxlength); + #endif /* _LINUX_UCS2_STRING_H_ */ diff --git a/include/linux/usb.h b/include/linux/usb.h index b79925dd2b41..246945be000c 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -734,6 +734,17 @@ static inline bool usb_device_no_sg_constraint(struct usb_device *udev) /* for drivers using iso endpoints */ extern int usb_get_current_frame_number(struct usb_device *usb_dev); +extern int usb_sec_event_ring_setup(struct usb_device *dev, + unsigned intr_num); +extern int usb_sec_event_ring_cleanup(struct usb_device *dev, + unsigned intr_num); + +extern dma_addr_t +usb_get_sec_event_ring_dma_addr(struct usb_device *dev, + unsigned intr_num); +extern dma_addr_t usb_get_dcba_dma_addr(struct usb_device *dev); +extern dma_addr_t usb_get_xfer_ring_dma_addr(struct usb_device *dev, + struct usb_host_endpoint *ep); /* Sets up a group of bulk endpoints to support multiple stream IDs. */ extern int usb_alloc_streams(struct usb_interface *interface, diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index f89c24bd53a4..3740366d9fc5 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -396,6 +396,14 @@ struct hc_driver { /* Call for power on/off the port if necessary */ int (*port_power)(struct usb_hcd *hcd, int portnum, bool enable); + int (*sec_event_ring_setup)(struct usb_hcd *hcd, unsigned intr_num); + int (*sec_event_ring_cleanup)(struct usb_hcd *hcd, unsigned intr_num); + dma_addr_t (*get_sec_event_ring_dma_addr)(struct usb_hcd *hcd, + unsigned intr_num); + dma_addr_t (*get_xfer_ring_dma_addr)(struct usb_hcd *hcd, + struct usb_device *udev, struct usb_host_endpoint *ep); + dma_addr_t (*get_dcba_dma_addr)(struct usb_hcd *hcd, + struct usb_device *udev); }; static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd) @@ -434,6 +442,17 @@ extern int usb_hcd_alloc_bandwidth(struct usb_device *udev, struct usb_host_interface *old_alt, struct usb_host_interface *new_alt); extern int usb_hcd_get_frame_number(struct usb_device *udev); +extern int usb_hcd_sec_event_ring_setup(struct usb_device *udev, + unsigned intr_num); +extern int usb_hcd_sec_event_ring_cleanup(struct usb_device *udev, + unsigned intr_num); +extern dma_addr_t +usb_hcd_get_sec_event_ring_dma_addr(struct usb_device *udev, + unsigned intr_num); +extern dma_addr_t usb_hcd_get_dcba_dma_addr(struct usb_device *udev); +extern dma_addr_t +usb_hcd_get_xfer_ring_dma_addr(struct usb_device *udev, + struct usb_host_endpoint *ep); extern struct usb_hcd *usb_create_hcd(const struct hc_driver *driver, struct device *dev, const char *bus_name); diff --git a/include/linux/writeback.h b/include/linux/writeback.h index b333c945e571..d0b5ca5d4e08 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -198,6 +198,7 @@ void wbc_attach_and_unlock_inode(struct writeback_control *wbc, void wbc_detach_inode(struct writeback_control *wbc); void wbc_account_io(struct writeback_control *wbc, struct page *page, size_t bytes); +void cgroup_writeback_umount(void); /** * inode_attach_wb - associate an inode with its wb @@ -301,6 +302,10 @@ static inline void wbc_account_io(struct writeback_control *wbc, { } +static inline void cgroup_writeback_umount(void) +{ +} + #endif /* CONFIG_CGROUP_WRITEBACK */ /* diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 647ebfe5174f..4984d372b04b 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -17,7 +17,7 @@ #include <linux/poll.h> #include <linux/dma-buf.h> -#define VB2_MAX_FRAME (32) +#define VB2_MAX_FRAME (64) #define VB2_MAX_PLANES (8) enum vb2_memory { diff --git a/include/net/af_unix.h b/include/net/af_unix.h index 2a91a0561a47..9b4c418bebd8 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -6,8 +6,8 @@ #include <linux/mutex.h> #include <net/sock.h> -void unix_inflight(struct file *fp); -void unix_notinflight(struct file *fp); +void unix_inflight(struct user_struct *user, struct file *fp); +void unix_notinflight(struct user_struct *user, struct file *fp); void unix_gc(void); void wait_for_unix_gc(void); struct sock *unix_get_socket(struct file *filp); diff --git a/include/net/cnss.h b/include/net/cnss.h index 78d68fd22ded..ab9b50100504 100644 --- a/include/net/cnss.h +++ b/include/net/cnss.h @@ -15,7 +15,6 @@ #include <linux/device.h> #include <linux/skbuff.h> #include <linux/pci.h> -#include <net/cnss_common.h> #include <linux/mmc/sdio_func.h> #ifdef CONFIG_CNSS @@ -212,4 +211,35 @@ extern int cnss_wlan_query_oob_status(void); extern int cnss_wlan_register_oob_irq_handler(oob_irq_handler_t handler, void *pm_oob); extern int cnss_wlan_unregister_oob_irq_handler(void *pm_oob); + + +extern void cnss_dump_stack(struct task_struct *task); +extern u8 *cnss_common_get_wlan_mac_address(struct device *dev, uint32_t *num); +extern void cnss_init_work(struct work_struct *work, work_func_t func); +extern void cnss_flush_delayed_work(void *dwork); +extern void cnss_flush_work(void *work); +extern void cnss_pm_wake_lock_timeout(struct wakeup_source *ws, ulong msec); +extern void cnss_pm_wake_lock_release(struct wakeup_source *ws); +extern void cnss_pm_wake_lock_destroy(struct wakeup_source *ws); +extern void cnss_get_monotonic_boottime(struct timespec *ts); +extern void cnss_get_boottime(struct timespec *ts); +extern void cnss_init_delayed_work(struct delayed_work *work, work_func_t + func); +extern int cnss_vendor_cmd_reply(struct sk_buff *skb); +extern int cnss_set_cpus_allowed_ptr(struct task_struct *task, ulong cpu); +extern int cnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count); +extern int cnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 *ch_count, + u16 buf_len); +extern int cnss_wlan_set_dfs_nol(const void *info, u16 info_len); +extern int cnss_wlan_get_dfs_nol(void *info, u16 info_len); +extern int cnss_common_request_bus_bandwidth(struct device *dev, int + bandwidth); +extern void cnss_common_device_crashed(struct device *dev); +extern void cnss_common_device_self_recovery(struct device *dev); +extern void *cnss_common_get_virt_ramdump_mem(struct device *dev, unsigned long + *size); +extern void cnss_common_schedule_recovery_work(struct device *dev); +extern int cnss_common_set_wlan_mac_address(struct device *dev, const u8 *in, + uint32_t len); +extern u8 *cnss_common_get_wlan_mac_address(struct device *dev, uint32_t *num); #endif /* _NET_CNSS_H_ */ diff --git a/include/net/cnss_common.h b/include/net/cnss_common.h deleted file mode 100644 index c5175a190b37..000000000000 --- a/include/net/cnss_common.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _NET_CNSS_COMMON_H_ -#define _NET_CNSS_COMMON_H_ - -#ifdef CONFIG_CNSS - -#define MAX_FIRMWARE_SIZE (1 * 1024 * 1024) -/* max 20mhz channel count */ -#define CNSS_MAX_CH_NUM 45 - -extern int cnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count); -extern int cnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, - u16 *ch_count, u16 buf_len); - -extern int cnss_wlan_set_dfs_nol(const void *info, u16 info_len); -extern int cnss_wlan_get_dfs_nol(void *info, u16 info_len); - -extern void cnss_init_work(struct work_struct *work, work_func_t func); -extern void cnss_flush_work(void *work); -extern void cnss_flush_delayed_work(void *dwork); -extern void cnss_pm_wake_lock_timeout(struct wakeup_source *ws, ulong msec); -extern void cnss_pm_wake_lock_release(struct wakeup_source *ws); -extern void cnss_pm_wake_lock_destroy(struct wakeup_source *ws); -extern void cnss_get_monotonic_boottime(struct timespec *ts); -extern void cnss_get_boottime(struct timespec *ts); -extern void cnss_init_delayed_work(struct delayed_work *work, work_func_t func); -extern int cnss_vendor_cmd_reply(struct sk_buff *skb); -extern int cnss_set_cpus_allowed_ptr(struct task_struct *task, ulong cpu); -extern void cnss_dump_stack(struct task_struct *task); - -int cnss_pci_request_bus_bandwidth(int bandwidth); -int cnss_sdio_request_bus_bandwidth(int bandwidth); -extern int cnss_common_request_bus_bandwidth(struct device *dev, - int bandwidth); - -void cnss_sdio_device_crashed(void); -void cnss_pci_device_crashed(void); -extern void cnss_common_device_crashed(struct device *dev); - -void cnss_pci_device_self_recovery(void); -void cnss_sdio_device_self_recovery(void); -extern void cnss_common_device_self_recovery(struct device *dev); - -void *cnss_pci_get_virt_ramdump_mem(unsigned long *size); -void *cnss_sdio_get_virt_ramdump_mem(unsigned long *size); -extern void *cnss_common_get_virt_ramdump_mem(struct device *dev, - unsigned long *size); - -void cnss_sdio_schedule_recovery_work(void); -void cnss_pci_schedule_recovery_work(void); -extern void cnss_common_schedule_recovery_work(struct device *dev); - -extern int cnss_pcie_set_wlan_mac_address(const u8 *in, uint32_t len); -extern int cnss_sdio_set_wlan_mac_address(const u8 *in, uint32_t len); -extern int cnss_common_set_wlan_mac_address(struct device *dev, - const u8 *in, uint32_t len); - -u8 *cnss_pci_get_wlan_mac_address(uint32_t *num); -u8 *cnss_sdio_get_wlan_mac_address(uint32_t *num); -extern u8 *cnss_common_get_wlan_mac_address(struct device *dev, uint32_t *num); -#endif -#endif /* _NET_CNSS_COMMON_H_ */ diff --git a/include/net/dst_metadata.h b/include/net/dst_metadata.h index 6816f0fa5693..30a56ab2ccfb 100644 --- a/include/net/dst_metadata.h +++ b/include/net/dst_metadata.h @@ -44,6 +44,24 @@ static inline bool skb_valid_dst(const struct sk_buff *skb) return dst && !(dst->flags & DST_METADATA); } +static inline int skb_metadata_dst_cmp(const struct sk_buff *skb_a, + const struct sk_buff *skb_b) +{ + const struct metadata_dst *a, *b; + + if (!(skb_a->_skb_refdst | skb_b->_skb_refdst)) + return 0; + + a = (const struct metadata_dst *) skb_dst(skb_a); + b = (const struct metadata_dst *) skb_dst(skb_b); + + if (!a != !b || a->u.tun_info.options_len != b->u.tun_info.options_len) + return 1; + + return memcmp(&a->u.tun_info, &b->u.tun_info, + sizeof(a->u.tun_info) + a->u.tun_info.options_len); +} + struct metadata_dst *metadata_dst_alloc(u8 optslen, gfp_t flags); struct metadata_dst __percpu *metadata_dst_alloc_percpu(u8 optslen, gfp_t flags); diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index 481fe1c9044c..49dcad4fe99e 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h @@ -270,8 +270,9 @@ struct dst_entry *inet_csk_route_child_sock(const struct sock *sk, struct sock *newsk, const struct request_sock *req); -void inet_csk_reqsk_queue_add(struct sock *sk, struct request_sock *req, - struct sock *child); +struct sock *inet_csk_reqsk_queue_add(struct sock *sk, + struct request_sock *req, + struct sock *child); void inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req, unsigned long timeout); struct sock *inet_csk_complete_hashdance(struct sock *sk, struct sock *child, diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 4bbd221637cd..ba82feec2590 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -64,8 +64,16 @@ static inline bool rt6_need_strict(const struct in6_addr *daddr) void ip6_route_input(struct sk_buff *skb); -struct dst_entry *ip6_route_output(struct net *net, const struct sock *sk, - struct flowi6 *fl6); +struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk, + struct flowi6 *fl6, int flags); + +static inline struct dst_entry *ip6_route_output(struct net *net, + const struct sock *sk, + struct flowi6 *fl6) +{ + return ip6_route_output_flags(net, sk, fl6, 0); +} + struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6, int flags); diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index 9f4df68105ab..3f98233388fb 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -61,6 +61,7 @@ struct fib_nh_exception { struct rtable __rcu *fnhe_rth_input; struct rtable __rcu *fnhe_rth_output; unsigned long fnhe_stamp; + struct rcu_head rcu; }; struct fnhe_hash_bucket { diff --git a/include/net/iw_handler.h b/include/net/iw_handler.h index 8f81bbbc38fc..e0f4109e64c6 100644 --- a/include/net/iw_handler.h +++ b/include/net/iw_handler.h @@ -439,6 +439,12 @@ int dev_get_wireless_info(char *buffer, char **start, off_t offset, int length); /* Send a single event to user space */ void wireless_send_event(struct net_device *dev, unsigned int cmd, union iwreq_data *wrqu, const char *extra); +#ifdef CONFIG_WEXT_CORE +/* flush all previous wext events - if work is done from netdev notifiers */ +void wireless_nlevent_flush(void); +#else +static inline void wireless_nlevent_flush(void) {} +#endif /* We may need a function to send a stream of events to user space. * More on that later... */ diff --git a/include/net/scm.h b/include/net/scm.h index 262532d111f5..59fa93c01d2a 100644 --- a/include/net/scm.h +++ b/include/net/scm.h @@ -21,6 +21,7 @@ struct scm_creds { struct scm_fp_list { short count; short max; + struct user_struct *user; struct file *fp[SCM_MAX_FD]; }; diff --git a/include/net/tcp.h b/include/net/tcp.h index 984e59d99deb..15ee95fcd561 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -141,6 +141,9 @@ void tcp_time_wait(struct sock *sk, int state, int timeo); * most likely due to retrans in 3WHS. */ +/* Number of full MSS to receive before Acking RFC2581 */ +#define TCP_DELACK_SEG 1 + #define TCP_RESOURCE_PROBE_INTERVAL ((unsigned)(HZ/2U)) /* Maximal interval between probes * for local resources. */ @@ -287,6 +290,11 @@ extern int sysctl_tcp_pacing_ca_ratio; extern int sysctl_tcp_default_init_rwnd; extern atomic_long_t tcp_memory_allocated; + +/* sysctl variables for controlling various tcp parameters */ +extern int sysctl_tcp_delack_seg; +extern int sysctl_tcp_use_userconfig; + extern struct percpu_counter tcp_sockets_allocated; extern int tcp_memory_pressure; @@ -377,6 +385,12 @@ ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags); +/* sysctl master controller */ +extern int tcp_use_userconfig_sysctl_handler(struct ctl_table *, int, + void __user *, size_t *, loff_t *); +extern int tcp_proc_delayed_ack_control(struct ctl_table *, int, + void __user *, size_t *, loff_t *); + static inline void tcp_dec_quickack_mode(struct sock *sk, const unsigned int pkts) { @@ -450,7 +464,7 @@ const u8 *tcp_parse_md5sig_option(const struct tcphdr *th); void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb); void tcp_v4_mtu_reduced(struct sock *sk); -void tcp_req_err(struct sock *sk, u32 seq); +void tcp_req_err(struct sock *sk, u32 seq, bool abort); int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb); struct sock *tcp_create_openreq_child(const struct sock *sk, struct request_sock *req, diff --git a/include/soc/qcom/clock-local2.h b/include/soc/qcom/clock-local2.h index 7f785cf4d3a2..4f2fa36e920f 100644 --- a/include/soc/qcom/clock-local2.h +++ b/include/soc/qcom/clock-local2.h @@ -255,6 +255,7 @@ extern struct clk_ops clk_ops_branch_hw_ctl; extern struct clk_ops clk_ops_vote; extern struct clk_ops clk_ops_rcg_hdmi; extern struct clk_ops clk_ops_rcg_edp; +extern struct clk_ops clk_ops_rcg_dp; extern struct clk_ops clk_ops_byte; extern struct clk_ops clk_ops_pixel; extern struct clk_ops clk_ops_byte_multiparent; diff --git a/include/soc/qcom/smem.h b/include/soc/qcom/smem.h index 9295532dec8a..79bcc1b31cf8 100644 --- a/include/soc/qcom/smem.h +++ b/include/soc/qcom/smem.h @@ -26,6 +26,7 @@ enum { SMEM_TZ, SMEM_SPSS, SMEM_HYP, + SMEM_CDSP, NUM_SMEM_SUBSYSTEMS, }; diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 56cf8e485ef2..28ee5c2e6bcd 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -94,5 +94,8 @@ sense_reason_t passthrough_parse_cdb(struct se_cmd *cmd, sense_reason_t (*exec_cmd)(struct se_cmd *cmd)); bool target_sense_desc_format(struct se_device *dev); +sector_t target_to_linux_sector(struct se_device *dev, sector_t lb); +bool target_configure_unmap_from_queue(struct se_dev_attrib *attrib, + struct request_queue *q, int block_size); #endif /* TARGET_CORE_BACKEND_H */ diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index aabf0aca0171..689f4d207122 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -138,6 +138,7 @@ enum se_cmd_flags_table { SCF_COMPARE_AND_WRITE = 0x00080000, SCF_COMPARE_AND_WRITE_POST = 0x00100000, SCF_PASSTHROUGH_PROT_SG_TO_MEM_NOALLOC = 0x00200000, + SCF_ACK_KREF = 0x00400000, }; /* struct se_dev_entry->lun_flags and struct se_lun->lun_access */ @@ -490,6 +491,8 @@ struct se_cmd { #define CMD_T_DEV_ACTIVE (1 << 7) #define CMD_T_REQUEST_STOP (1 << 8) #define CMD_T_BUSY (1 << 9) +#define CMD_T_TAS (1 << 10) +#define CMD_T_FABRIC_STOP (1 << 11) spinlock_t t_state_lock; struct kref cmd_kref; struct completion t_transport_stop_comp; diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 29e3be2ce18c..32172c8f7d37 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -347,7 +347,7 @@ header-y += nfs_mount.h header-y += nl80211.h header-y += n_r3964.h header-y += nubus.h -header-y += nvme.h +header-y += nvme_ioctl.h header-y += nvram.h header-y += omap3isp.h header-y += omapfb.h diff --git a/include/uapi/linux/msm_kgsl.h b/include/uapi/linux/msm_kgsl.h index 34503420c882..dbba773cd49d 100644 --- a/include/uapi/linux/msm_kgsl.h +++ b/include/uapi/linux/msm_kgsl.h @@ -43,13 +43,13 @@ /* This is a cmdbatch exclusive flag - use the CMDBATCH equivalent instead */ #define KGSL_CONTEXT_SYNC 0x00000400 #define KGSL_CONTEXT_PWR_CONSTRAINT 0x00000800 - #define KGSL_CONTEXT_PRIORITY_MASK 0x0000F000 #define KGSL_CONTEXT_PRIORITY_SHIFT 12 #define KGSL_CONTEXT_PRIORITY_UNDEF 0 #define KGSL_CONTEXT_IFH_NOP 0x00010000 #define KGSL_CONTEXT_SECURE 0x00020000 +#define KGSL_CONTEXT_NO_SNAPSHOT 0x00040000 #define KGSL_CONTEXT_PREEMPT_STYLE_MASK 0x0E000000 #define KGSL_CONTEXT_PREEMPT_STYLE_SHIFT 25 diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 0c5c83a84362..27fe13a534b4 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -702,7 +702,13 @@ enum v4l2_mpeg_vidc_video_rate_control { V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR = 2, V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR = 3, V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR = 4, + V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_CFR = 5, + V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_VFR = 6, }; +#define V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_CFR \ + V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_CFR +#define V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_VFR \ + V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_VFR #define V4L2_CID_MPEG_VIDC_VIDEO_ROTATION (V4L2_CID_MPEG_MSM_VIDC_BASE+14) enum v4l2_mpeg_vidc_video_rotation { @@ -1155,6 +1161,11 @@ enum v4l2_mpeg_vidc_video_lowlatency_mode { #define V4L2_CID_MPEG_VIDC_VIDEO_BLUR_HEIGHT \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 90) +#define V4L2_CID_MPEG_VIDEO_MIN_QP_PACKED \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 91) +#define V4L2_CID_MPEG_VIDEO_MAX_QP_PACKED \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 92) + /* Camera class control IDs */ #define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900) diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index c7bb78a0d57b..46b0402a730f 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -70,7 +70,7 @@ * Common stuff for both V4L1 and V4L2 * Moved from videodev.h */ -#define VIDEO_MAX_FRAME 32 +#define VIDEO_MAX_FRAME 64 #define VIDEO_MAX_PLANES 8 /* diff --git a/include/uapi/media/msm_sde_rotator.h b/include/uapi/media/msm_sde_rotator.h index d771959f2e03..461a171a42c1 100644 --- a/include/uapi/media/msm_sde_rotator.h +++ b/include/uapi/media/msm_sde_rotator.h @@ -13,9 +13,23 @@ #define SDE_PIX_FMT_BGRA_8888 V4L2_PIX_FMT_ARGB32 #define SDE_PIX_FMT_RGBX_8888 v4l2_fourcc('X', 'B', '2', '4') #define SDE_PIX_FMT_BGRX_8888 V4L2_PIX_FMT_XRGB32 +#define SDE_PIX_FMT_XBGR_8888 v4l2_fourcc('R', 'X', '2', '4') #define SDE_PIX_FMT_RGBA_5551 v4l2_fourcc('R', 'A', '1', '5') +#define SDE_PIX_FMT_ARGB_1555 V4L2_PIX_FMT_ARGB555 +#define SDE_PIX_FMT_ABGR_1555 v4l2_fourcc('A', 'B', '1', '5') +#define SDE_PIX_FMT_BGRA_5551 v4l2_fourcc('B', 'A', '1', '5') +#define SDE_PIX_FMT_BGRX_5551 v4l2_fourcc('B', 'X', '1', '5') +#define SDE_PIX_FMT_RGBX_5551 v4l2_fourcc('R', 'X', '1', '5') +#define SDE_PIX_FMT_XBGR_1555 v4l2_fourcc('X', 'B', '1', '5') +#define SDE_PIX_FMT_XRGB_1555 V4L2_PIX_FMT_XRGB555 #define SDE_PIX_FMT_ARGB_4444 V4L2_PIX_FMT_ARGB444 #define SDE_PIX_FMT_RGBA_4444 v4l2_fourcc('R', 'A', '1', '2') +#define SDE_PIX_FMT_BGRA_4444 v4l2_fourcc('B', 'A', '1', '2') +#define SDE_PIX_FMT_ABGR_4444 v4l2_fourcc('A', 'B', '1', '2') +#define SDE_PIX_FMT_RGBX_4444 v4l2_fourcc('R', 'X', '1', '2') +#define SDE_PIX_FMT_XRGB_4444 V4L2_PIX_FMT_XRGB444 +#define SDE_PIX_FMT_BGRX_4444 v4l2_fourcc('B', 'X', '1', '2') +#define SDE_PIX_FMT_XBGR_4444 v4l2_fourcc('X', 'B', '1', '2') #define SDE_PIX_FMT_RGB_888 V4L2_PIX_FMT_RGB24 #define SDE_PIX_FMT_BGR_888 V4L2_PIX_FMT_BGR24 #define SDE_PIX_FMT_RGB_565 V4L2_PIX_FMT_RGB565 diff --git a/include/uapi/media/msmb_camera.h b/include/uapi/media/msmb_camera.h index 092551d0cc16..fe70daa772df 100644 --- a/include/uapi/media/msmb_camera.h +++ b/include/uapi/media/msmb_camera.h @@ -202,5 +202,24 @@ struct msm_camera_user_buf_cont_t { unsigned int buf_idx[MSM_CAMERA_MAX_USER_BUFF_CNT]; }; +struct msm_camera_return_buf { + __u32 index; + __u32 reserved; +}; + +#define MSM_CAMERA_PRIV_IOCTL_ID_BASE 0 +#define MSM_CAMERA_PRIV_IOCTL_ID_RETURN_BUF 1 + +struct msm_camera_private_ioctl_arg { + __u32 id; + __u32 size; + __u32 result; + __u32 reserved; + __user __u64 ioctl_ptr; +}; + +#define VIDIOC_MSM_CAMERA_PRIVATE_IOCTL_CMD \ + _IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_camera_private_ioctl_arg) + #endif diff --git a/include/uapi/media/msmb_generic_buf_mgr.h b/include/uapi/media/msmb_generic_buf_mgr.h index a68b174b97bb..2961cae1e7c1 100644 --- a/include/uapi/media/msmb_generic_buf_mgr.h +++ b/include/uapi/media/msmb_generic_buf_mgr.h @@ -34,6 +34,9 @@ struct msm_buf_mngr_main_cont_info { int32_t cont_fd; }; +#define MSM_CAMERA_BUF_MNGR_IOCTL_ID_BASE 0 +#define MSM_CAMERA_BUF_MNGR_IOCTL_ID_GET_BUF_BY_IDX 1 + #define VIDIOC_MSM_BUF_MNGR_GET_BUF \ _IOWR('V', BASE_VIDIOC_PRIVATE + 33, struct msm_buf_mngr_info) @@ -55,5 +58,9 @@ struct msm_buf_mngr_main_cont_info { #define VIDIOC_MSM_BUF_MNGR_FLUSH \ _IOWR('V', BASE_VIDIOC_PRIVATE + 39, struct msm_buf_mngr_info) +#define VIDIOC_MSM_BUF_MNGR_IOCTL_CMD \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 40, \ + struct msm_camera_private_ioctl_arg) + #endif diff --git a/include/uapi/media/msmb_ispif.h b/include/uapi/media/msmb_ispif.h index 26bd8a2ce87f..7f4deaf12683 100644 --- a/include/uapi/media/msmb_ispif.h +++ b/include/uapi/media/msmb_ispif.h @@ -72,6 +72,24 @@ enum msm_ispif_csid { CSID_MAX }; +enum msm_ispif_pixel_odd_even { + PIX_EVEN, + PIX_ODD +}; + +enum msm_ispif_pixel_pack_mode { + PACK_BYTE, + PACK_PLAIN_PACK, + PACK_NV_P8, + PACK_NV_P16 +}; + +struct msm_ispif_pack_cfg { + int pixel_swap_en; + enum msm_ispif_pixel_odd_even even_odd_sel; + enum msm_ispif_pixel_pack_mode pack_mode; +}; + struct msm_ispif_params_entry { enum msm_ispif_vfe_intf vfe_intf; enum msm_ispif_intftype intftype; @@ -83,6 +101,12 @@ struct msm_ispif_params_entry { uint16_t crop_end_pixel; }; +struct msm_ispif_param_data_ext { + uint32_t num; + struct msm_ispif_params_entry entries[MAX_PARAM_ENTRIES]; + struct msm_ispif_pack_cfg pack_cfg[CID_MAX]; +}; + struct msm_ispif_param_data { uint32_t num; struct msm_ispif_params_entry entries[MAX_PARAM_ENTRIES]; @@ -111,6 +135,7 @@ enum ispif_cfg_type_t { ISPIF_RELEASE, ISPIF_ENABLE_REG_DUMP, ISPIF_SET_VFE_INFO, + ISPIF_CFG2, }; struct ispif_cfg_data { @@ -123,8 +148,19 @@ struct ispif_cfg_data { }; }; +struct ispif_cfg_data_ext { + enum ispif_cfg_type_t cfg_type; + void __user *data; + uint32_t size; +}; + +#define ISPIF_RDI_PACK_MODE_SUPPORT 1 + #define VIDIOC_MSM_ISPIF_CFG \ _IOWR('V', BASE_VIDIOC_PRIVATE, struct ispif_cfg_data) +#define VIDIOC_MSM_ISPIF_CFG_EXT \ + _IOWR('V', BASE_VIDIOC_PRIVATE+1, struct ispif_cfg_data_ext) + #endif diff --git a/init/main.c b/init/main.c index 9e64d7097f1a..fbafa271531c 100644 --- a/init/main.c +++ b/init/main.c @@ -93,9 +93,6 @@ static int kernel_init(void *); extern void init_IRQ(void); extern void fork_init(void); extern void radix_tree_init(void); -#ifndef CONFIG_DEBUG_RODATA -static inline void mark_rodata_ro(void) { } -#endif /* * Debug helper: via this flag we know that we are in 'early bootup code' @@ -929,6 +926,28 @@ static int try_to_run_init_process(const char *init_filename) static noinline void __init kernel_init_freeable(void); +#ifdef CONFIG_DEBUG_RODATA +static bool rodata_enabled = true; +static int __init set_debug_rodata(char *str) +{ + return strtobool(str, &rodata_enabled); +} +__setup("rodata=", set_debug_rodata); + +static void mark_readonly(void) +{ + if (rodata_enabled) + mark_rodata_ro(); + else + pr_info("Kernel memory protection disabled.\n"); +} +#else +static inline void mark_readonly(void) +{ + pr_warn("This architecture does not have kernel memory protection.\n"); +} +#endif + static int __ref kernel_init(void *unused) { int ret; @@ -937,7 +956,7 @@ static int __ref kernel_init(void *unused) /* need to finish all async __init code before freeing the memory */ async_synchronize_full(); free_initmem(); - mark_rodata_ro(); + mark_readonly(); system_state = SYSTEM_RUNNING; numa_default_policy(); diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index d1d3e8f57de9..2e7f7ab739e4 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2082,7 +2082,7 @@ static void adjust_branches(struct bpf_prog *prog, int pos, int delta) /* adjust offset of jmps if necessary */ if (i < pos && i + insn->off + 1 > pos) insn->off += delta; - else if (i > pos && i + insn->off + 1 < pos) + else if (i > pos + delta && i + insn->off + 1 <= pos + delta) insn->off -= delta; } } diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 359d881f7ffe..d5512e1e7138 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -57,7 +57,7 @@ #include <linux/vmalloc.h> /* TODO: replace with more sophisticated array */ #include <linux/kthread.h> #include <linux/delay.h> - +#include <linux/cpuset.h> #include <linux/atomic.h> /* @@ -2819,6 +2819,7 @@ out_unlock_rcu: out_unlock_threadgroup: percpu_up_write(&cgroup_threadgroup_rwsem); cgroup_kn_unlock(of->kn); + cpuset_post_attach_flush(); return ret ?: nbytes; } @@ -4838,6 +4839,7 @@ static void init_and_link_css(struct cgroup_subsys_state *css, INIT_LIST_HEAD(&css->sibling); INIT_LIST_HEAD(&css->children); css->serial_nr = css_serial_nr_next++; + atomic_set(&css->online_cnt, 0); if (cgroup_parent(cgrp)) { css->parent = cgroup_css(cgroup_parent(cgrp), ss); @@ -4860,6 +4862,10 @@ static int online_css(struct cgroup_subsys_state *css) if (!ret) { css->flags |= CSS_ONLINE; rcu_assign_pointer(css->cgroup->subsys[ss->id], css); + + atomic_inc(&css->online_cnt); + if (css->parent) + atomic_inc(&css->parent->online_cnt); } return ret; } @@ -5091,10 +5097,15 @@ static void css_killed_work_fn(struct work_struct *work) container_of(work, struct cgroup_subsys_state, destroy_work); mutex_lock(&cgroup_mutex); - offline_css(css); - mutex_unlock(&cgroup_mutex); - css_put(css); + do { + offline_css(css); + css_put(css); + /* @css can't go away while we're holding cgroup_mutex */ + css = css->parent; + } while (css && atomic_dec_and_test(&css->online_cnt)); + + mutex_unlock(&cgroup_mutex); } /* css kill confirmation processing requires process context, bounce */ @@ -5103,8 +5114,10 @@ static void css_killed_ref_fn(struct percpu_ref *ref) struct cgroup_subsys_state *css = container_of(ref, struct cgroup_subsys_state, refcnt); - INIT_WORK(&css->destroy_work, css_killed_work_fn); - queue_work(cgroup_destroy_wq, &css->destroy_work); + if (atomic_dec_and_test(&css->online_cnt)) { + INIT_WORK(&css->destroy_work, css_killed_work_fn); + queue_work(cgroup_destroy_wq, &css->destroy_work); + } } /** diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 02a8ea5c9963..2ade632197d5 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -286,6 +286,8 @@ static struct cpuset top_cpuset = { static DEFINE_MUTEX(cpuset_mutex); static DEFINE_SPINLOCK(callback_lock); +static struct workqueue_struct *cpuset_migrate_mm_wq; + /* * CPU / memory hotplug is handled asynchronously. */ @@ -971,31 +973,51 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs, } /* - * cpuset_migrate_mm - * - * Migrate memory region from one set of nodes to another. - * - * Temporarilly set tasks mems_allowed to target nodes of migration, - * so that the migration code can allocate pages on these nodes. - * - * While the mm_struct we are migrating is typically from some - * other task, the task_struct mems_allowed that we are hacking - * is for our current task, which must allocate new pages for that - * migrating memory region. + * Migrate memory region from one set of nodes to another. This is + * performed asynchronously as it can be called from process migration path + * holding locks involved in process management. All mm migrations are + * performed in the queued order and can be waited for by flushing + * cpuset_migrate_mm_wq. */ +struct cpuset_migrate_mm_work { + struct work_struct work; + struct mm_struct *mm; + nodemask_t from; + nodemask_t to; +}; + +static void cpuset_migrate_mm_workfn(struct work_struct *work) +{ + struct cpuset_migrate_mm_work *mwork = + container_of(work, struct cpuset_migrate_mm_work, work); + + /* on a wq worker, no need to worry about %current's mems_allowed */ + do_migrate_pages(mwork->mm, &mwork->from, &mwork->to, MPOL_MF_MOVE_ALL); + mmput(mwork->mm); + kfree(mwork); +} + static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from, const nodemask_t *to) { - struct task_struct *tsk = current; - - tsk->mems_allowed = *to; + struct cpuset_migrate_mm_work *mwork; - do_migrate_pages(mm, from, to, MPOL_MF_MOVE_ALL); + mwork = kzalloc(sizeof(*mwork), GFP_KERNEL); + if (mwork) { + mwork->mm = mm; + mwork->from = *from; + mwork->to = *to; + INIT_WORK(&mwork->work, cpuset_migrate_mm_workfn); + queue_work(cpuset_migrate_mm_wq, &mwork->work); + } else { + mmput(mm); + } +} - rcu_read_lock(); - guarantee_online_mems(task_cs(tsk), &tsk->mems_allowed); - rcu_read_unlock(); +void cpuset_post_attach_flush(void) +{ + flush_workqueue(cpuset_migrate_mm_wq); } /* @@ -1096,7 +1118,8 @@ static void update_tasks_nodemask(struct cpuset *cs) mpol_rebind_mm(mm, &cs->mems_allowed); if (migrate) cpuset_migrate_mm(mm, &cs->old_mems_allowed, &newmems); - mmput(mm); + else + mmput(mm); } css_task_iter_end(&it); @@ -1541,11 +1564,11 @@ static void cpuset_attach(struct cgroup_taskset *tset) * @old_mems_allowed is the right nodesets that we * migrate mm from. */ - if (is_memory_migrate(cs)) { + if (is_memory_migrate(cs)) cpuset_migrate_mm(mm, &oldcs->old_mems_allowed, &cpuset_attach_nodemask_to); - } - mmput(mm); + else + mmput(mm); } } @@ -1710,6 +1733,7 @@ out_unlock: mutex_unlock(&cpuset_mutex); kernfs_unbreak_active_protection(of->kn); css_put(&cs->css); + flush_workqueue(cpuset_migrate_mm_wq); return retval ?: nbytes; } @@ -2355,6 +2379,9 @@ void __init cpuset_init_smp(void) top_cpuset.effective_mems = node_states[N_MEMORY]; register_hotmemory_notifier(&cpuset_track_online_nodes_nb); + + cpuset_migrate_mm_wq = alloc_ordered_workqueue("cpuset_migrate_mm", 0); + BUG_ON(!cpuset_migrate_mm_wq); } /** diff --git a/kernel/debug/kdb/kdb_bp.c b/kernel/debug/kdb/kdb_bp.c index e1dbf4a2c69e..90ff129c88a2 100644 --- a/kernel/debug/kdb/kdb_bp.c +++ b/kernel/debug/kdb/kdb_bp.c @@ -153,13 +153,11 @@ static int _kdb_bp_install(struct pt_regs *regs, kdb_bp_t *bp) } else { kdb_printf("%s: failed to set breakpoint at 0x%lx\n", __func__, bp->bp_addr); -#ifdef CONFIG_DEBUG_RODATA if (!bp->bp_type) { kdb_printf("Software breakpoints are unavailable.\n" - " Change the kernel CONFIG_DEBUG_RODATA=n\n" + " Boot the kernel with rodata=off\n" " OR use hw breaks: help bph\n"); } -#endif return 1; } return 0; diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index a302cf9a2126..57bff7857e87 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -138,7 +138,8 @@ irqreturn_t handle_irq_event_percpu(struct irq_desc *desc) unsigned int flags = 0, irq = desc->irq_data.irq; struct irqaction *action = desc->action; - do { + /* action might have become NULL since we dropped the lock */ + while (action) { irqreturn_t res; trace_irq_handler_entry(irq, action); @@ -173,7 +174,7 @@ irqreturn_t handle_irq_event_percpu(struct irq_desc *desc) retval |= res; action = action->next; - } while (action); + } add_interrupt_randomness(irq, flags); diff --git a/kernel/memremap.c b/kernel/memremap.c index 7a4e473cea4d..25ced161ebeb 100644 --- a/kernel/memremap.c +++ b/kernel/memremap.c @@ -133,8 +133,10 @@ void *devm_memremap(struct device *dev, resource_size_t offset, if (addr) { *ptr = addr; devres_add(dev, ptr); - } else + } else { devres_free(ptr); + return ERR_PTR(-ENXIO); + } return addr; } diff --git a/kernel/module.c b/kernel/module.c index 2ec4df630677..fe5248ab3378 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2495,7 +2495,6 @@ static void layout_symtab(struct module *mod, struct load_info *info) strsect->sh_flags |= SHF_ALLOC; strsect->sh_entsize = get_offset(mod, &mod->init_size, strsect, info->index.str) | INIT_OFFSET_MASK; - mod->init_size = debug_align(mod->init_size); pr_debug("\t%s\n", info->secstrings + strsect->sh_name); /* We'll tack temporary mod_kallsyms on the end. */ diff --git a/kernel/resource.c b/kernel/resource.c index 035b989b582b..4c9835c09dcd 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -1083,9 +1083,10 @@ struct resource * __request_region(struct resource *parent, if (!conflict) break; if (conflict != parent) { - parent = conflict; - if (!(conflict->flags & IORESOURCE_BUSY)) + if (!(conflict->flags & IORESOURCE_BUSY)) { + parent = conflict; continue; + } } if (conflict->flags & flags & IORESOURCE_MUXED) { add_wait_queue(&muxed_resource_wait, &wait); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 2fd5c5688dd0..f640c0e3c7ea 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2053,7 +2053,7 @@ static int send_notification(struct rq *rq, int check_pred, int check_groups) unsigned int cur_freq, freq_required; unsigned long flags; int rc = 0; - u64 group_load = 0, new_load; + u64 group_load = 0, new_load = 0; if (!sched_enable_hmp) return 0; @@ -3056,6 +3056,7 @@ static inline void mark_task_starting(struct task_struct *p) wallclock = sched_ktime_clock(); p->ravg.mark_start = p->last_wake_ts = wallclock; + p->last_cpu_selected_ts = wallclock; p->last_switch_out_ts = 0; update_task_cpu_cycles(p, cpu_of(rq)); } diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index b9ee3dc4a1a6..958d79e1933c 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -2678,6 +2678,9 @@ static unsigned int __read_mostly sched_short_sleep_task_threshold = 2000 * NSEC_PER_USEC; unsigned int __read_mostly sysctl_sched_select_prev_cpu_us = 2000; +static unsigned int __read_mostly +sched_long_cpu_selection_threshold = 100 * NSEC_PER_MSEC; + unsigned int __read_mostly sysctl_sched_restrict_cluster_spill; void update_up_down_migrate(void) @@ -3455,6 +3458,7 @@ bias_to_prev_cpu(struct cpu_select_env *env, struct cluster_cpu_stats *stats) struct sched_cluster *cluster; if (env->boost_type != SCHED_BOOST_NONE || env->reason || + !task->ravg.mark_start || env->need_idle || !sched_short_sleep_task_threshold) return false; @@ -3463,6 +3467,10 @@ bias_to_prev_cpu(struct cpu_select_env *env, struct cluster_cpu_stats *stats) unlikely(!cpu_active(prev_cpu))) return false; + if (task->ravg.mark_start - task->last_cpu_selected_ts >= + sched_long_cpu_selection_threshold) + return false; + /* * This function should be used by task wake up path only as it's * assuming p->last_switch_out_ts as last sleep time. @@ -3604,6 +3612,7 @@ retry: if (stats.best_capacity_cpu >= 0) target = stats.best_capacity_cpu; } + p->last_cpu_selected_ts = sched_ktime_clock(); out: rcu_read_unlock(); @@ -4334,7 +4343,7 @@ __update_load_avg(u64 now, int cpu, struct sched_avg *sa, return 0; sa->last_update_time = now; - if (sched_use_pelt && !cfs_rq && weight) { + if (sched_use_pelt && cfs_rq && weight) { se = container_of(sa, struct sched_entity, avg); if (entity_is_task(se) && se->on_rq) dec_hmp_sched_stats_fair(rq_of(cfs_rq), task_of(se)); diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 580ac2d4024f..15a1795bbba1 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -316,24 +316,24 @@ static inline void seccomp_sync_threads(void) put_seccomp_filter(thread); smp_store_release(&thread->seccomp.filter, caller->seccomp.filter); + + /* + * Don't let an unprivileged task work around + * the no_new_privs restriction by creating + * a thread that sets it up, enters seccomp, + * then dies. + */ + if (task_no_new_privs(caller)) + task_set_no_new_privs(thread); + /* * Opt the other thread into seccomp if needed. * As threads are considered to be trust-realm * equivalent (see ptrace_may_access), it is safe to * allow one thread to transition the other. */ - if (thread->seccomp.mode == SECCOMP_MODE_DISABLED) { - /* - * Don't let an unprivileged task work around - * the no_new_privs restriction by creating - * a thread that sets it up, enters seccomp, - * then dies. - */ - if (task_no_new_privs(caller)) - task_set_no_new_privs(thread); - + if (thread->seccomp.mode == SECCOMP_MODE_DISABLED) seccomp_assign_mode(thread, SECCOMP_MODE_FILTER); - } } } diff --git a/kernel/time/posix-clock.c b/kernel/time/posix-clock.c index ce033c7aa2e8..9cff0ab82b63 100644 --- a/kernel/time/posix-clock.c +++ b/kernel/time/posix-clock.c @@ -69,10 +69,10 @@ static ssize_t posix_clock_read(struct file *fp, char __user *buf, static unsigned int posix_clock_poll(struct file *fp, poll_table *wait) { struct posix_clock *clk = get_posix_clock(fp); - int result = 0; + unsigned int result = 0; if (!clk) - return -ENODEV; + return POLLERR; if (clk->ops.poll) result = clk->ops.poll(clk, fp, wait); diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 7f0f1d8d46b0..651ff1a3a306 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -997,9 +997,9 @@ static void tick_nohz_switch_to_nohz(void) /* Get the next period */ next = tick_init_jiffy_update(); - hrtimer_forward_now(&ts->sched_timer, tick_period); hrtimer_set_expires(&ts->sched_timer, next); - tick_program_event(next, 1); + hrtimer_forward_now(&ts->sched_timer, tick_period); + tick_program_event(hrtimer_get_expires(&ts->sched_timer), 1); tick_nohz_activate(ts, NOHZ_MODE_LOWRES); } diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index d563c1960302..99188ee5d9d0 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -305,8 +305,7 @@ static inline s64 timekeeping_get_ns(struct tk_read_base *tkr) delta = timekeeping_get_delta(tkr); - nsec = delta * tkr->mult + tkr->xtime_nsec; - nsec >>= tkr->shift; + nsec = (delta * tkr->mult + tkr->xtime_nsec) >> tkr->shift; /* If arch requires, add in get_arch_timeoffset() */ return nsec + arch_gettimeoffset(); diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 52bb846af3d6..fda3b6e1b3a0 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -97,16 +97,16 @@ trace_find_event_field(struct trace_event_call *call, char *name) struct ftrace_event_field *field; struct list_head *head; - field = __find_event_field(&ftrace_generic_fields, name); + head = trace_get_fields(call); + field = __find_event_field(head, name); if (field) return field; - field = __find_event_field(&ftrace_common_fields, name); + field = __find_event_field(&ftrace_generic_fields, name); if (field) return field; - head = trace_get_fields(call); - return __find_event_field(head, name); + return __find_event_field(&ftrace_common_fields, name); } static int __trace_define_field(struct list_head *head, const char *type, @@ -171,8 +171,10 @@ static int trace_define_generic_fields(void) { int ret; - __generic_field(int, cpu, FILTER_OTHER); - __generic_field(char *, comm, FILTER_PTR_STRING); + __generic_field(int, CPU, FILTER_CPU); + __generic_field(int, cpu, FILTER_CPU); + __generic_field(char *, COMM, FILTER_COMM); + __generic_field(char *, comm, FILTER_COMM); return ret; } @@ -870,7 +872,8 @@ t_next(struct seq_file *m, void *v, loff_t *pos) * The ftrace subsystem is for showing formats only. * They can not be enabled or disabled via the event files. */ - if (call->class && call->class->reg) + if (call->class && call->class->reg && + !(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE)) return file; } diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index f93a219b18da..6816302542b2 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -1043,13 +1043,14 @@ static int init_pred(struct filter_parse_state *ps, return -EINVAL; } - if (is_string_field(field)) { + if (field->filter_type == FILTER_COMM) { + filter_build_regex(pred); + fn = filter_pred_comm; + pred->regex.field_len = TASK_COMM_LEN; + } else if (is_string_field(field)) { filter_build_regex(pred); - if (!strcmp(field->name, "comm")) { - fn = filter_pred_comm; - pred->regex.field_len = TASK_COMM_LEN; - } else if (field->filter_type == FILTER_STATIC_STRING) { + if (field->filter_type == FILTER_STATIC_STRING) { fn = filter_pred_string; pred->regex.field_len = field->size; } else if (field->filter_type == FILTER_DYN_STRING) @@ -1072,7 +1073,7 @@ static int init_pred(struct filter_parse_state *ps, } pred->val = val; - if (!strcmp(field->name, "cpu")) + if (field->filter_type == FILTER_CPU) fn = filter_pred_cpu; else fn = select_comparison_fn(pred->op, field->size, diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 58fe79122a61..ef84d9874d03 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -571,6 +571,16 @@ static struct pool_workqueue *unbound_pwq_by_node(struct workqueue_struct *wq, int node) { assert_rcu_or_wq_mutex_or_pool_mutex(wq); + + /* + * XXX: @node can be NUMA_NO_NODE if CPU goes offline while a + * delayed item is pending. The plan is to keep CPU -> NODE + * mapping valid and stable across CPU on/offlines. Once that + * happens, this workaround can be removed. + */ + if (unlikely(node == NUMA_NO_NODE)) + return wq->dfl_pwq; + return rcu_dereference_raw(wq->numa_pwq_tbl[node]); } @@ -1465,13 +1475,13 @@ static void __queue_delayed_work(int cpu, struct workqueue_struct *wq, timer_stats_timer_set_start_info(&dwork->timer); dwork->wq = wq; - /* timer isn't guaranteed to run in this cpu, record earlier */ - if (cpu == WORK_CPU_UNBOUND) - cpu = raw_smp_processor_id(); dwork->cpu = cpu; timer->expires = jiffies + delay; - add_timer_on(timer, cpu); + if (unlikely(cpu != WORK_CPU_UNBOUND)) + add_timer_on(timer, cpu); + else + add_timer(timer); } /** diff --git a/lib/Kconfig b/lib/Kconfig index 8b169b9793ec..7f6feb7a4687 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -210,9 +210,11 @@ config RANDOM32_SELFTEST # compression support is select'ed if needed # config 842_COMPRESS + select CRC32 tristate config 842_DECOMPRESS + select CRC32 tristate config ZLIB_INFLATE diff --git a/lib/ucs2_string.c b/lib/ucs2_string.c index 6f500ef2301d..f0b323abb4c6 100644 --- a/lib/ucs2_string.c +++ b/lib/ucs2_string.c @@ -49,3 +49,65 @@ ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len) } } EXPORT_SYMBOL(ucs2_strncmp); + +unsigned long +ucs2_utf8size(const ucs2_char_t *src) +{ + unsigned long i; + unsigned long j = 0; + + for (i = 0; i < ucs2_strlen(src); i++) { + u16 c = src[i]; + + if (c >= 0x800) + j += 3; + else if (c >= 0x80) + j += 2; + else + j += 1; + } + + return j; +} +EXPORT_SYMBOL(ucs2_utf8size); + +/* + * copy at most maxlength bytes of whole utf8 characters to dest from the + * ucs2 string src. + * + * The return value is the number of characters copied, not including the + * final NUL character. + */ +unsigned long +ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, unsigned long maxlength) +{ + unsigned int i; + unsigned long j = 0; + unsigned long limit = ucs2_strnlen(src, maxlength); + + for (i = 0; maxlength && i < limit; i++) { + u16 c = src[i]; + + if (c >= 0x800) { + if (maxlength < 3) + break; + maxlength -= 3; + dest[j++] = 0xe0 | (c & 0xf000) >> 12; + dest[j++] = 0x80 | (c & 0x0fc0) >> 6; + dest[j++] = 0x80 | (c & 0x003f); + } else if (c >= 0x80) { + if (maxlength < 2) + break; + maxlength -= 2; + dest[j++] = 0xc0 | (c & 0x7c0) >> 6; + dest[j++] = 0x80 | (c & 0x03f); + } else { + maxlength -= 1; + dest[j++] = c & 0x7f; + } + } + if (maxlength) + dest[j] = '\0'; + return j; +} +EXPORT_SYMBOL(ucs2_as_utf8); diff --git a/mm/balloon_compaction.c b/mm/balloon_compaction.c index d3116be5a00f..300117f1a08f 100644 --- a/mm/balloon_compaction.c +++ b/mm/balloon_compaction.c @@ -61,6 +61,7 @@ struct page *balloon_page_dequeue(struct balloon_dev_info *b_dev_info) bool dequeued_page; dequeued_page = false; + spin_lock_irqsave(&b_dev_info->pages_lock, flags); list_for_each_entry_safe(page, tmp, &b_dev_info->pages, lru) { /* * Block others from accessing the 'page' while we get around @@ -75,15 +76,14 @@ struct page *balloon_page_dequeue(struct balloon_dev_info *b_dev_info) continue; } #endif - spin_lock_irqsave(&b_dev_info->pages_lock, flags); balloon_page_delete(page); __count_vm_event(BALLOON_DEFLATE); - spin_unlock_irqrestore(&b_dev_info->pages_lock, flags); unlock_page(page); dequeued_page = true; break; } } + spin_unlock_irqrestore(&b_dev_info->pages_lock, flags); if (!dequeued_page) { /* diff --git a/mm/memory.c b/mm/memory.c index 7b82889114e5..6098837a4e5e 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3400,8 +3400,18 @@ static int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, if (unlikely(pmd_none(*pmd)) && unlikely(__pte_alloc(mm, vma, pmd, address))) return VM_FAULT_OOM; - /* if an huge pmd materialized from under us just retry later */ - if (unlikely(pmd_trans_huge(*pmd))) + /* + * If a huge pmd materialized under us just retry later. Use + * pmd_trans_unstable() instead of pmd_trans_huge() to ensure the pmd + * didn't become pmd_trans_huge under us and then back to pmd_none, as + * a result of MADV_DONTNEED running immediately after a huge pmd fault + * in a different thread of this mm, in turn leading to a misleading + * pmd_trans_huge() retval. All we have to ensure is that it is a + * regular pmd that we can walk with pte_offset_map() and we can do that + * through an atomic read in C, which is what pmd_trans_unstable() + * provides. + */ + if (unlikely(pmd_trans_unstable(pmd))) return 0; /* * A regular pmd is established and it can't morph into a huge pmd diff --git a/mm/migrate.c b/mm/migrate.c index 85b91eb19ea9..cd1e63062459 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -1580,7 +1580,7 @@ static struct page *alloc_misplaced_dst_page(struct page *page, (GFP_HIGHUSER_MOVABLE | __GFP_THISNODE | __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN) & - ~(__GFP_IO | __GFP_FS), 0); + ~__GFP_RECLAIM, 0); return newpage; } diff --git a/mm/shmem.c b/mm/shmem.c index 40d1d3b0ea2f..b82e56ebabdd 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -620,8 +620,7 @@ static void shmem_evict_inode(struct inode *inode) list_del_init(&info->swaplist); mutex_unlock(&shmem_swaplist_mutex); } - } else - kfree(info->symlink); + } simple_xattrs_free(&info->xattrs); WARN_ON(inode->i_blocks); @@ -2462,13 +2461,12 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s info = SHMEM_I(inode); inode->i_size = len-1; if (len <= SHORT_SYMLINK_LEN) { - info->symlink = kmemdup(symname, len, GFP_KERNEL); - if (!info->symlink) { + inode->i_link = kmemdup(symname, len, GFP_KERNEL); + if (!inode->i_link) { iput(inode); return -ENOMEM; } inode->i_op = &shmem_short_symlink_operations; - inode->i_link = info->symlink; } else { error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL); if (error) { @@ -3083,6 +3081,7 @@ static struct inode *shmem_alloc_inode(struct super_block *sb) static void shmem_destroy_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); + kfree(inode->i_link); kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode)); } diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 9e9cca3689a0..795ddd8b2f77 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -307,6 +307,9 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev, /* check that it's our buffer */ if (lowpan_is_ipv6(*skb_network_header(skb))) { + /* Pull off the 1-byte of 6lowpan header. */ + skb_pull(skb, 1); + /* Copy the packet so that the IPv6 header is * properly aligned. */ @@ -317,6 +320,7 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev, local_skb->protocol = htons(ETH_P_IPV6); local_skb->pkt_type = PACKET_HOST; + local_skb->dev = dev; skb_set_transport_header(local_skb, sizeof(struct ipv6hdr)); @@ -335,6 +339,8 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev, if (!local_skb) goto drop; + local_skb->dev = dev; + ret = iphc_decompress(local_skb, dev, chan); if (ret < 0) { kfree_skb(local_skb); @@ -343,7 +349,6 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev, local_skb->protocol = htons(ETH_P_IPV6); local_skb->pkt_type = PACKET_HOST; - local_skb->dev = dev; if (give_skb_to_upper(local_skb, dev) != NET_RX_SUCCESS) { diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 3e0ab381c4e2..2ad1f7fb65a3 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -722,8 +722,12 @@ static void hci_req_add_le_create_conn(struct hci_request *req, if (hci_update_random_address(req, false, &own_addr_type)) return; + /* Set window to be the same value as the interval to enable + * continuous scanning. + */ cp.scan_interval = cpu_to_le16(hdev->le_scan_interval); - cp.scan_window = cpu_to_le16(hdev->le_scan_window); + cp.scan_window = cp.scan_interval; + bacpy(&cp.peer_addr, &conn->dst); cp.peer_addr_type = conn->dst_type; cp.own_address_type = own_addr_type; diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index 981f8a202c27..02778c5bc149 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -175,21 +175,29 @@ static u8 update_white_list(struct hci_request *req) * command to remove it from the controller. */ list_for_each_entry(b, &hdev->le_white_list, list) { - struct hci_cp_le_del_from_white_list cp; + /* If the device is neither in pend_le_conns nor + * pend_le_reports then remove it from the whitelist. + */ + if (!hci_pend_le_action_lookup(&hdev->pend_le_conns, + &b->bdaddr, b->bdaddr_type) && + !hci_pend_le_action_lookup(&hdev->pend_le_reports, + &b->bdaddr, b->bdaddr_type)) { + struct hci_cp_le_del_from_white_list cp; + + cp.bdaddr_type = b->bdaddr_type; + bacpy(&cp.bdaddr, &b->bdaddr); - if (hci_pend_le_action_lookup(&hdev->pend_le_conns, - &b->bdaddr, b->bdaddr_type) || - hci_pend_le_action_lookup(&hdev->pend_le_reports, - &b->bdaddr, b->bdaddr_type)) { - white_list_entries++; + hci_req_add(req, HCI_OP_LE_DEL_FROM_WHITE_LIST, + sizeof(cp), &cp); continue; } - cp.bdaddr_type = b->bdaddr_type; - bacpy(&cp.bdaddr, &b->bdaddr); + if (hci_find_irk_by_addr(hdev, &b->bdaddr, b->bdaddr_type)) { + /* White list can not be used with RPAs */ + return 0x00; + } - hci_req_add(req, HCI_OP_LE_DEL_FROM_WHITE_LIST, - sizeof(cp), &cp); + white_list_entries++; } /* Since all no longer valid white list entries have been diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 92214d97890b..6f2c704e41ab 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -1072,22 +1072,6 @@ static void smp_notify_keys(struct l2cap_conn *conn) hcon->dst_type = smp->remote_irk->addr_type; queue_work(hdev->workqueue, &conn->id_addr_update_work); } - - /* When receiving an indentity resolving key for - * a remote device that does not use a resolvable - * private address, just remove the key so that - * it is possible to use the controller white - * list for scanning. - * - * Userspace will have been told to not store - * this key at this point. So it is safe to - * just remove it. - */ - if (!bacmp(&smp->remote_irk->rpa, BDADDR_ANY)) { - list_del_rcu(&smp->remote_irk->list); - kfree_rcu(smp->remote_irk, rcu); - smp->remote_irk = NULL; - } } if (smp->csrk) { diff --git a/net/bridge/br.c b/net/bridge/br.c index a1abe4936fe1..3addc05b9a16 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c @@ -121,6 +121,7 @@ static struct notifier_block br_device_notifier = { .notifier_call = br_device_event }; +/* called with RTNL */ static int br_switchdev_event(struct notifier_block *unused, unsigned long event, void *ptr) { @@ -130,7 +131,6 @@ static int br_switchdev_event(struct notifier_block *unused, struct switchdev_notifier_fdb_info *fdb_info; int err = NOTIFY_DONE; - rtnl_lock(); p = br_port_get_rtnl(dev); if (!p) goto out; @@ -155,7 +155,6 @@ static int br_switchdev_event(struct notifier_block *unused, } out: - rtnl_unlock(); return err; } diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 9981039ef4ff..63ae5dd24fc5 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -672,6 +672,8 @@ static void reset_connection(struct ceph_connection *con) } con->in_seq = 0; con->in_seq_acked = 0; + + con->out_skip = 0; } /* @@ -771,6 +773,8 @@ static u32 get_global_seq(struct ceph_messenger *msgr, u32 gt) static void con_out_kvec_reset(struct ceph_connection *con) { + BUG_ON(con->out_skip); + con->out_kvec_left = 0; con->out_kvec_bytes = 0; con->out_kvec_cur = &con->out_kvec[0]; @@ -779,9 +783,9 @@ static void con_out_kvec_reset(struct ceph_connection *con) static void con_out_kvec_add(struct ceph_connection *con, size_t size, void *data) { - int index; + int index = con->out_kvec_left; - index = con->out_kvec_left; + BUG_ON(con->out_skip); BUG_ON(index >= ARRAY_SIZE(con->out_kvec)); con->out_kvec[index].iov_len = size; @@ -790,6 +794,27 @@ static void con_out_kvec_add(struct ceph_connection *con, con->out_kvec_bytes += size; } +/* + * Chop off a kvec from the end. Return residual number of bytes for + * that kvec, i.e. how many bytes would have been written if the kvec + * hadn't been nuked. + */ +static int con_out_kvec_skip(struct ceph_connection *con) +{ + int off = con->out_kvec_cur - con->out_kvec; + int skip = 0; + + if (con->out_kvec_bytes > 0) { + skip = con->out_kvec[off + con->out_kvec_left - 1].iov_len; + BUG_ON(con->out_kvec_bytes < skip); + BUG_ON(!con->out_kvec_left); + con->out_kvec_bytes -= skip; + con->out_kvec_left--; + } + + return skip; +} + #ifdef CONFIG_BLOCK /* @@ -1175,6 +1200,13 @@ static bool ceph_msg_data_advance(struct ceph_msg_data_cursor *cursor, return new_piece; } +static size_t sizeof_footer(struct ceph_connection *con) +{ + return (con->peer_features & CEPH_FEATURE_MSG_AUTH) ? + sizeof(struct ceph_msg_footer) : + sizeof(struct ceph_msg_footer_old); +} + static void prepare_message_data(struct ceph_msg *msg, u32 data_len) { BUG_ON(!msg); @@ -1197,7 +1229,6 @@ static void prepare_write_message_footer(struct ceph_connection *con) m->footer.flags |= CEPH_MSG_FOOTER_COMPLETE; dout("prepare_write_message_footer %p\n", con); - con->out_kvec_is_msg = true; con->out_kvec[v].iov_base = &m->footer; if (con->peer_features & CEPH_FEATURE_MSG_AUTH) { if (con->ops->sign_message) @@ -1225,7 +1256,6 @@ static void prepare_write_message(struct ceph_connection *con) u32 crc; con_out_kvec_reset(con); - con->out_kvec_is_msg = true; con->out_msg_done = false; /* Sneak an ack in there first? If we can get it into the same @@ -1265,18 +1295,19 @@ static void prepare_write_message(struct ceph_connection *con) /* tag + hdr + front + middle */ con_out_kvec_add(con, sizeof (tag_msg), &tag_msg); - con_out_kvec_add(con, sizeof (m->hdr), &m->hdr); + con_out_kvec_add(con, sizeof(con->out_hdr), &con->out_hdr); con_out_kvec_add(con, m->front.iov_len, m->front.iov_base); if (m->middle) con_out_kvec_add(con, m->middle->vec.iov_len, m->middle->vec.iov_base); - /* fill in crc (except data pages), footer */ + /* fill in hdr crc and finalize hdr */ crc = crc32c(0, &m->hdr, offsetof(struct ceph_msg_header, crc)); con->out_msg->hdr.crc = cpu_to_le32(crc); - con->out_msg->footer.flags = 0; + memcpy(&con->out_hdr, &con->out_msg->hdr, sizeof(con->out_hdr)); + /* fill in front and middle crc, footer */ crc = crc32c(0, m->front.iov_base, m->front.iov_len); con->out_msg->footer.front_crc = cpu_to_le32(crc); if (m->middle) { @@ -1288,6 +1319,7 @@ static void prepare_write_message(struct ceph_connection *con) dout("%s front_crc %u middle_crc %u\n", __func__, le32_to_cpu(con->out_msg->footer.front_crc), le32_to_cpu(con->out_msg->footer.middle_crc)); + con->out_msg->footer.flags = 0; /* is there a data payload? */ con->out_msg->footer.data_crc = 0; @@ -1492,7 +1524,6 @@ static int write_partial_kvec(struct ceph_connection *con) } } con->out_kvec_left = 0; - con->out_kvec_is_msg = false; ret = 1; out: dout("write_partial_kvec %p %d left in %d kvecs ret = %d\n", con, @@ -1584,6 +1615,7 @@ static int write_partial_skip(struct ceph_connection *con) { int ret; + dout("%s %p %d left\n", __func__, con, con->out_skip); while (con->out_skip > 0) { size_t size = min(con->out_skip, (int) PAGE_CACHE_SIZE); @@ -2313,9 +2345,9 @@ static int read_partial_message(struct ceph_connection *con) ceph_pr_addr(&con->peer_addr.in_addr), seq, con->in_seq + 1); con->in_base_pos = -front_len - middle_len - data_len - - sizeof(m->footer); + sizeof_footer(con); con->in_tag = CEPH_MSGR_TAG_READY; - return 0; + return 1; } else if ((s64)seq - (s64)con->in_seq > 1) { pr_err("read_partial_message bad seq %lld expected %lld\n", seq, con->in_seq + 1); @@ -2338,10 +2370,10 @@ static int read_partial_message(struct ceph_connection *con) /* skip this message */ dout("alloc_msg said skip message\n"); con->in_base_pos = -front_len - middle_len - data_len - - sizeof(m->footer); + sizeof_footer(con); con->in_tag = CEPH_MSGR_TAG_READY; con->in_seq++; - return 0; + return 1; } BUG_ON(!con->in_msg); @@ -2506,13 +2538,13 @@ more: more_kvec: /* kvec data queued? */ - if (con->out_skip) { - ret = write_partial_skip(con); + if (con->out_kvec_left) { + ret = write_partial_kvec(con); if (ret <= 0) goto out; } - if (con->out_kvec_left) { - ret = write_partial_kvec(con); + if (con->out_skip) { + ret = write_partial_skip(con); if (ret <= 0) goto out; } @@ -3050,16 +3082,31 @@ void ceph_msg_revoke(struct ceph_msg *msg) ceph_msg_put(msg); } if (con->out_msg == msg) { - dout("%s %p msg %p - was sending\n", __func__, con, msg); - con->out_msg = NULL; - if (con->out_kvec_is_msg) { - con->out_skip = con->out_kvec_bytes; - con->out_kvec_is_msg = false; + BUG_ON(con->out_skip); + /* footer */ + if (con->out_msg_done) { + con->out_skip += con_out_kvec_skip(con); + } else { + BUG_ON(!msg->data_length); + if (con->peer_features & CEPH_FEATURE_MSG_AUTH) + con->out_skip += sizeof(msg->footer); + else + con->out_skip += sizeof(msg->old_footer); } + /* data, middle, front */ + if (msg->data_length) + con->out_skip += msg->cursor.total_resid; + if (msg->middle) + con->out_skip += con_out_kvec_skip(con); + con->out_skip += con_out_kvec_skip(con); + + dout("%s %p msg %p - was sending, will write %d skip %d\n", + __func__, con, msg, con->out_kvec_bytes, con->out_skip); msg->hdr.seq = 0; - + con->out_msg = NULL; ceph_msg_put(msg); } + mutex_unlock(&con->mutex); } diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index f8f235930d88..a28e47ff1b1b 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -2843,8 +2843,8 @@ static struct ceph_msg *get_reply(struct ceph_connection *con, mutex_lock(&osdc->request_mutex); req = __lookup_request(osdc, tid); if (!req) { - pr_warn("%s osd%d tid %llu unknown, skipping\n", - __func__, osd->o_osd, tid); + dout("%s osd%d tid %llu unknown, skipping\n", __func__, + osd->o_osd, tid); m = NULL; *skip = 1; goto out; diff --git a/net/core/dev.c b/net/core/dev.c index 51b156ed09d7..95b832edc303 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4150,6 +4150,7 @@ static void gro_list_prepare(struct napi_struct *napi, struct sk_buff *skb) diffs = (unsigned long)p->dev ^ (unsigned long)skb->dev; diffs |= p->vlan_tci ^ skb->vlan_tci; + diffs |= skb_metadata_dst_cmp(p, skb); if (maclen == ETH_HLEN) diffs |= compare_ether_header(skb_mac_header(p), skb_mac_header(skb)); @@ -4347,10 +4348,12 @@ static gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb) break; case GRO_MERGED_FREE: - if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD) + if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD) { + skb_dst_drop(skb); kmem_cache_free(skbuff_head_cache, skb); - else + } else { __kfree_skb(skb); + } break; case GRO_HELD: @@ -7153,8 +7156,10 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, dev->priv_flags = IFF_XMIT_DST_RELEASE | IFF_XMIT_DST_RELEASE_PERM; setup(dev); - if (!dev->tx_queue_len) + if (!dev->tx_queue_len) { dev->priv_flags |= IFF_NO_QUEUE; + dev->tx_queue_len = 1; + } dev->num_tx_queues = txqs; dev->real_num_tx_queues = txqs; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index b32fe21ba2e6..08764a380f9a 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -209,7 +209,6 @@ ip: case htons(ETH_P_IPV6): { const struct ipv6hdr *iph; struct ipv6hdr _iph; - __be32 flow_label; ipv6: iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph); @@ -231,8 +230,12 @@ ipv6: key_control->addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; } - flow_label = ip6_flowlabel(iph); - if (flow_label) { + if ((dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_FLOW_LABEL) || + (flags & FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL)) && + ip6_flowlabel(iph)) { + __be32 flow_label = ip6_flowlabel(iph); + if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_FLOW_LABEL)) { key_tags = skb_flow_dissector_target(flow_dissector, @@ -431,6 +434,13 @@ ip_proto_again: goto out_bad; proto = eth->h_proto; nhoff += sizeof(*eth); + + /* Cap headers that we access via pointers at the + * end of the Ethernet header as our maximum alignment + * at that point is only 2 bytes. + */ + if (NET_IP_ALIGN) + hlen = nhoff; } key_control->flags |= FLOW_DIS_ENCAPSULATION; diff --git a/net/core/scm.c b/net/core/scm.c index 8a1741b14302..dce0acb929f1 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -87,6 +87,7 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp) *fplp = fpl; fpl->count = 0; fpl->max = SCM_MAX_FD; + fpl->user = NULL; } fpp = &fpl->fp[fpl->count]; @@ -107,6 +108,10 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp) *fpp++ = file; fpl->count++; } + + if (!fpl->user) + fpl->user = get_uid(current_user()); + return num; } @@ -119,6 +124,7 @@ void __scm_destroy(struct scm_cookie *scm) scm->fp = NULL; for (i=fpl->count-1; i>=0; i--) fput(fpl->fp[i]); + free_uid(fpl->user); kfree(fpl); } } @@ -336,6 +342,7 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl) for (i = 0; i < fpl->count; i++) get_file(fpl->fp[i]); new_fpl->max = new_fpl->count; + new_fpl->user = get_uid(fpl->user); } return new_fpl; } diff --git a/net/core/skbuff.c b/net/core/skbuff.c index b1082a4819fe..2d1dd16327a2 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -79,6 +79,8 @@ struct kmem_cache *skbuff_head_cache __read_mostly; static struct kmem_cache *skbuff_fclone_cache __read_mostly; +int sysctl_max_skb_frags __read_mostly = MAX_SKB_FRAGS; +EXPORT_SYMBOL(sysctl_max_skb_frags); /** * skb_panic - private function for out-of-line support diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index 95b6139d710c..a6beb7b6ae55 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -26,6 +26,7 @@ static int zero = 0; static int one = 1; static int min_sndbuf = SOCK_MIN_SNDBUF; static int min_rcvbuf = SOCK_MIN_RCVBUF; +static int max_skb_frags = MAX_SKB_FRAGS; static int net_msg_warn; /* Unused, but still a sysctl */ @@ -392,6 +393,15 @@ static struct ctl_table net_core_table[] = { .mode = 0644, .proc_handler = proc_dointvec }, + { + .procname = "max_skb_frags", + .data = &sysctl_max_skb_frags, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &one, + .extra2 = &max_skb_frags, + }, { } }; diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 5684e14932bd..902d606324a0 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -824,26 +824,26 @@ lookup: if (sk->sk_state == DCCP_NEW_SYN_RECV) { struct request_sock *req = inet_reqsk(sk); - struct sock *nsk = NULL; + struct sock *nsk; sk = req->rsk_listener; - if (likely(sk->sk_state == DCCP_LISTEN)) { - nsk = dccp_check_req(sk, skb, req); - } else { + if (unlikely(sk->sk_state != DCCP_LISTEN)) { inet_csk_reqsk_queue_drop_and_put(sk, req); goto lookup; } + sock_hold(sk); + nsk = dccp_check_req(sk, skb, req); if (!nsk) { reqsk_put(req); - goto discard_it; + goto discard_and_relse; } if (nsk == sk) { - sock_hold(sk); reqsk_put(req); } else if (dccp_child_process(sk, nsk, skb)) { dccp_v4_ctl_send_reset(sk, skb); - goto discard_it; + goto discard_and_relse; } else { + sock_put(sk); return 0; } } diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 9c6d0508e63a..b8608b71a66d 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -691,26 +691,26 @@ lookup: if (sk->sk_state == DCCP_NEW_SYN_RECV) { struct request_sock *req = inet_reqsk(sk); - struct sock *nsk = NULL; + struct sock *nsk; sk = req->rsk_listener; - if (likely(sk->sk_state == DCCP_LISTEN)) { - nsk = dccp_check_req(sk, skb, req); - } else { + if (unlikely(sk->sk_state != DCCP_LISTEN)) { inet_csk_reqsk_queue_drop_and_put(sk, req); goto lookup; } + sock_hold(sk); + nsk = dccp_check_req(sk, skb, req); if (!nsk) { reqsk_put(req); - goto discard_it; + goto discard_and_relse; } if (nsk == sk) { - sock_hold(sk); reqsk_put(req); } else if (dccp_child_process(sk, nsk, skb)) { dccp_v6_ctl_send_reset(sk, skb); - goto discard_it; + goto discard_and_relse; } else { + sock_put(sk); return 0; } } diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 3792624af316..011e73357ba5 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1853,7 +1853,7 @@ static int inet_netconf_get_devconf(struct sk_buff *in_skb, if (err < 0) goto errout; - err = EINVAL; + err = -EINVAL; if (!tb[NETCONFA_IFINDEX]) goto errout; diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 82a93aef5a9e..dc0b2db33f50 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -796,14 +796,16 @@ static void inet_child_forget(struct sock *sk, struct request_sock *req, reqsk_put(req); } -void inet_csk_reqsk_queue_add(struct sock *sk, struct request_sock *req, - struct sock *child) +struct sock *inet_csk_reqsk_queue_add(struct sock *sk, + struct request_sock *req, + struct sock *child) { struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue; spin_lock(&queue->rskq_lock); if (unlikely(sk->sk_state != TCP_LISTEN)) { inet_child_forget(sk, req, child); + child = NULL; } else { req->sk = child; req->dl_next = NULL; @@ -815,6 +817,7 @@ void inet_csk_reqsk_queue_add(struct sock *sk, struct request_sock *req, sk_acceptq_added(sk); } spin_unlock(&queue->rskq_lock); + return child; } EXPORT_SYMBOL(inet_csk_reqsk_queue_add); @@ -824,11 +827,8 @@ struct sock *inet_csk_complete_hashdance(struct sock *sk, struct sock *child, if (own_req) { inet_csk_reqsk_queue_drop(sk, req); reqsk_queue_removed(&inet_csk(sk)->icsk_accept_queue, req); - inet_csk_reqsk_queue_add(sk, req, child); - /* Warning: caller must not call reqsk_put(req); - * child stole last reference on it. - */ - return child; + if (inet_csk_reqsk_queue_add(sk, req, child)) + return child; } /* Too bad, another child took ownership of the request, undo. */ bh_unlock_sock(child); diff --git a/net/ipv4/inet_lro.c b/net/ipv4/inet_lro.c index f17ea49b28fb..8f26145c34e2 100644 --- a/net/ipv4/inet_lro.c +++ b/net/ipv4/inet_lro.c @@ -145,20 +145,37 @@ static __wsum lro_tcp_data_csum(struct iphdr *iph, struct tcphdr *tcph, int len) } static void lro_init_desc(struct net_lro_desc *lro_desc, struct sk_buff *skb, - struct iphdr *iph, struct tcphdr *tcph) + struct iphdr *iph, struct tcphdr *tcph, + struct net_lro_info *lro_info) { int nr_frags; __be32 *ptr; u32 tcp_data_len = TCP_PAYLOAD_LENGTH(iph, tcph); + u64 hw_marked = 0; + + if (lro_info) + hw_marked = lro_info->valid_fields; nr_frags = skb_shinfo(skb)->nr_frags; lro_desc->parent = skb; lro_desc->next_frag = &(skb_shinfo(skb)->frags[nr_frags]); lro_desc->iph = iph; lro_desc->tcph = tcph; - lro_desc->tcp_next_seq = ntohl(tcph->seq) + tcp_data_len; - lro_desc->tcp_ack = tcph->ack_seq; - lro_desc->tcp_window = tcph->window; + + if (hw_marked & LRO_TCP_SEQ_NUM) + lro_desc->tcp_next_seq = lro_info->tcp_seq_num + tcp_data_len; + else + lro_desc->tcp_next_seq = ntohl(tcph->seq) + tcp_data_len; + + if (hw_marked & LRO_TCP_ACK_NUM) + lro_desc->tcp_ack = htonl(lro_info->tcp_ack_num); + else + lro_desc->tcp_ack = tcph->ack_seq; + + if (hw_marked & LRO_TCP_WIN) + lro_desc->tcp_window = htons(lro_info->tcp_win); + else + lro_desc->tcp_window = tcph->window; lro_desc->pkt_aggr_cnt = 1; lro_desc->ip_tot_len = ntohs(iph->tot_len); @@ -173,8 +190,11 @@ static void lro_init_desc(struct net_lro_desc *lro_desc, struct sk_buff *skb, lro_desc->mss = tcp_data_len; lro_desc->active = 1; - lro_desc->data_csum = lro_tcp_data_csum(iph, tcph, - tcp_data_len); + if (hw_marked & LRO_TCP_DATA_CSUM) + lro_desc->data_csum = lro_info->tcp_data_csum; + else + lro_desc->data_csum = lro_tcp_data_csum(iph, tcph, + tcp_data_len); } static inline void lro_clear_desc(struct net_lro_desc *lro_desc) @@ -183,16 +203,29 @@ static inline void lro_clear_desc(struct net_lro_desc *lro_desc) } static void lro_add_common(struct net_lro_desc *lro_desc, struct iphdr *iph, - struct tcphdr *tcph, int tcp_data_len) + struct tcphdr *tcph, int tcp_data_len, + struct net_lro_info *lro_info) { struct sk_buff *parent = lro_desc->parent; __be32 *topt; + u64 hw_marked = 0; + + if (lro_info) + hw_marked = lro_info->valid_fields; lro_desc->pkt_aggr_cnt++; lro_desc->ip_tot_len += tcp_data_len; lro_desc->tcp_next_seq += tcp_data_len; - lro_desc->tcp_window = tcph->window; - lro_desc->tcp_ack = tcph->ack_seq; + + if (hw_marked & LRO_TCP_WIN) + lro_desc->tcp_window = htons(lro_info->tcp_win); + else + lro_desc->tcp_window = tcph->window; + + if (hw_marked & LRO_TCP_ACK_NUM) + lro_desc->tcp_ack = htonl(lro_info->tcp_ack_num); + else + lro_desc->tcp_ack = tcph->ack_seq; /* don't update tcp_rcv_tsval, would not work with PAWS */ if (lro_desc->tcp_saw_tstamp) { @@ -200,10 +233,17 @@ static void lro_add_common(struct net_lro_desc *lro_desc, struct iphdr *iph, lro_desc->tcp_rcv_tsecr = *(topt + 2); } - lro_desc->data_csum = csum_block_add(lro_desc->data_csum, - lro_tcp_data_csum(iph, tcph, - tcp_data_len), - parent->len); + if (hw_marked & LRO_TCP_DATA_CSUM) + lro_desc->data_csum = csum_block_add(lro_desc->data_csum, + lro_info->tcp_data_csum, + parent->len); + else + lro_desc->data_csum = + csum_block_add(lro_desc->data_csum, + lro_tcp_data_csum(iph, + tcph, + tcp_data_len), + parent->len); parent->len += tcp_data_len; parent->data_len += tcp_data_len; @@ -212,12 +252,13 @@ static void lro_add_common(struct net_lro_desc *lro_desc, struct iphdr *iph, } static void lro_add_packet(struct net_lro_desc *lro_desc, struct sk_buff *skb, - struct iphdr *iph, struct tcphdr *tcph) + struct iphdr *iph, struct tcphdr *tcph, + struct net_lro_info *lro_info) { struct sk_buff *parent = lro_desc->parent; int tcp_data_len = TCP_PAYLOAD_LENGTH(iph, tcph); - lro_add_common(lro_desc, iph, tcph, tcp_data_len); + lro_add_common(lro_desc, iph, tcph, tcp_data_len, lro_info); skb_pull(skb, (skb->len - tcp_data_len)); parent->truesize += skb->truesize; @@ -230,6 +271,29 @@ static void lro_add_packet(struct net_lro_desc *lro_desc, struct sk_buff *skb, lro_desc->last_skb = skb; } +static void lro_add_frags(struct net_lro_desc *lro_desc, + int len, int hlen, int truesize, + struct skb_frag_struct *skb_frags, + struct iphdr *iph, struct tcphdr *tcph) +{ + struct sk_buff *skb = lro_desc->parent; + int tcp_data_len = TCP_PAYLOAD_LENGTH(iph, tcph); + + lro_add_common(lro_desc, iph, tcph, tcp_data_len, NULL); + + skb->truesize += truesize; + + skb_frags[0].page_offset += hlen; + skb_frag_size_sub(&skb_frags[0], hlen); + + while (tcp_data_len > 0) { + *lro_desc->next_frag = *skb_frags; + tcp_data_len -= skb_frag_size(skb_frags); + lro_desc->next_frag++; + skb_frags++; + skb_shinfo(skb)->nr_frags++; + } +} static int lro_check_tcp_conn(struct net_lro_desc *lro_desc, struct iphdr *iph, @@ -284,6 +348,8 @@ static void lro_flush(struct net_lro_mgr *lro_mgr, if (lro_mgr->features & LRO_F_NAPI) netif_receive_skb(lro_desc->parent); + else if (lro_mgr->features & LRO_F_NI) + netif_rx_ni(lro_desc->parent); else netif_rx(lro_desc->parent); @@ -292,12 +358,13 @@ static void lro_flush(struct net_lro_mgr *lro_mgr, } static int __lro_proc_skb(struct net_lro_mgr *lro_mgr, struct sk_buff *skb, - void *priv) + void *priv, struct net_lro_info *lro_info) { struct net_lro_desc *lro_desc; struct iphdr *iph; struct tcphdr *tcph; u64 flags; + u64 hw_marked = 0; int vlan_hdr_len = 0; if (!lro_mgr->get_skb_header || @@ -308,7 +375,14 @@ static int __lro_proc_skb(struct net_lro_mgr *lro_mgr, struct sk_buff *skb, if (!(flags & LRO_IPV4) || !(flags & LRO_TCP)) goto out; - lro_desc = lro_get_desc(lro_mgr, lro_mgr->lro_arr, iph, tcph); + if (lro_info) + hw_marked = lro_info->valid_fields; + + if (hw_marked & LRO_DESC) + lro_desc = lro_info->lro_desc; + else + lro_desc = lro_get_desc(lro_mgr, lro_mgr->lro_arr, iph, tcph); + if (!lro_desc) goto out; @@ -317,22 +391,38 @@ static int __lro_proc_skb(struct net_lro_mgr *lro_mgr, struct sk_buff *skb, vlan_hdr_len = VLAN_HLEN; if (!lro_desc->active) { /* start new lro session */ - if (lro_tcp_ip_check(iph, tcph, skb->len - vlan_hdr_len, NULL)) - goto out; + if (hw_marked & LRO_ELIGIBILITY_CHECKED) { + if (!lro_info->lro_eligible) + goto out; + } else { + if (lro_tcp_ip_check(iph, tcph, + skb->len - vlan_hdr_len, NULL)) + goto out; + } skb->ip_summed = lro_mgr->ip_summed_aggr; - lro_init_desc(lro_desc, skb, iph, tcph); + lro_init_desc(lro_desc, skb, iph, tcph, lro_info); LRO_INC_STATS(lro_mgr, aggregated); return 0; } - if (lro_desc->tcp_next_seq != ntohl(tcph->seq)) - goto out2; + if (hw_marked & LRO_TCP_SEQ_NUM) { + if (lro_desc->tcp_next_seq != lro_info->tcp_seq_num) + goto out2; + } else { + if (lro_desc->tcp_next_seq != ntohl(tcph->seq)) + goto out2; + } - if (lro_tcp_ip_check(iph, tcph, skb->len, lro_desc)) - goto out2; + if (hw_marked & LRO_ELIGIBILITY_CHECKED) { + if (!lro_info->lro_eligible) + goto out2; + } else { + if (lro_tcp_ip_check(iph, tcph, skb->len, lro_desc)) + goto out2; + } - lro_add_packet(lro_desc, skb, iph, tcph); + lro_add_packet(lro_desc, skb, iph, tcph, lro_info); LRO_INC_STATS(lro_mgr, aggregated); if ((lro_desc->pkt_aggr_cnt >= lro_mgr->max_aggr) || @@ -348,19 +438,161 @@ out: return 1; } +static struct sk_buff *lro_gen_skb(struct net_lro_mgr *lro_mgr, + struct skb_frag_struct *frags, + int len, int true_size, + void *mac_hdr, + int hlen, __wsum sum, + u32 ip_summed) +{ + struct sk_buff *skb; + struct skb_frag_struct *skb_frags; + int data_len = len; + int hdr_len = min(len, hlen); + + skb = netdev_alloc_skb(lro_mgr->dev, hlen + lro_mgr->frag_align_pad); + if (!skb) + return NULL; + + skb_reserve(skb, lro_mgr->frag_align_pad); + skb->len = len; + skb->data_len = len - hdr_len; + skb->truesize += true_size; + skb->tail += hdr_len; + + memcpy(skb->data, mac_hdr, hdr_len); + + skb_frags = skb_shinfo(skb)->frags; + while (data_len > 0) { + *skb_frags = *frags; + data_len -= skb_frag_size(frags); + skb_frags++; + frags++; + skb_shinfo(skb)->nr_frags++; + } + + skb_shinfo(skb)->frags[0].page_offset += hdr_len; + skb_frag_size_sub(&skb_shinfo(skb)->frags[0], hdr_len); + + skb->ip_summed = ip_summed; + skb->csum = sum; + skb->protocol = eth_type_trans(skb, lro_mgr->dev); + return skb; +} + +static struct sk_buff *__lro_proc_segment(struct net_lro_mgr *lro_mgr, + struct skb_frag_struct *frags, + int len, int true_size, + void *priv, __wsum sum) +{ + struct net_lro_desc *lro_desc; + struct iphdr *iph; + struct tcphdr *tcph; + struct sk_buff *skb; + u64 flags; + void *mac_hdr; + int mac_hdr_len; + int hdr_len = LRO_MAX_PG_HLEN; + int vlan_hdr_len = 0; + + if (!lro_mgr->get_frag_header || + lro_mgr->get_frag_header(frags, (void *)&mac_hdr, (void *)&iph, + (void *)&tcph, &flags, priv)) { + mac_hdr = skb_frag_address(frags); + goto out1; + } + + if (!(flags & LRO_IPV4) || !(flags & LRO_TCP)) + goto out1; + + hdr_len = (int)((void *)(tcph) + TCP_HDR_LEN(tcph) - mac_hdr); + mac_hdr_len = (int)((void *)(iph) - mac_hdr); + + lro_desc = lro_get_desc(lro_mgr, lro_mgr->lro_arr, iph, tcph); + if (!lro_desc) + goto out1; + + if (!lro_desc->active) { /* start new lro session */ + if (lro_tcp_ip_check(iph, tcph, len - mac_hdr_len, NULL)) + goto out1; + + skb = lro_gen_skb(lro_mgr, frags, len, true_size, mac_hdr, + hdr_len, 0, lro_mgr->ip_summed_aggr); + if (!skb) + goto out; + + if ((skb->protocol == htons(ETH_P_8021Q)) && + !(lro_mgr->features & LRO_F_EXTRACT_VLAN_ID)) + vlan_hdr_len = VLAN_HLEN; + + iph = (void *)(skb->data + vlan_hdr_len); + tcph = (void *)((u8 *)skb->data + vlan_hdr_len + + IP_HDR_LEN(iph)); + + lro_init_desc(lro_desc, skb, iph, tcph, NULL); + LRO_INC_STATS(lro_mgr, aggregated); + return NULL; + } + + if (lro_desc->tcp_next_seq != ntohl(tcph->seq)) + goto out2; + + if (lro_tcp_ip_check(iph, tcph, len - mac_hdr_len, lro_desc)) + goto out2; + + lro_add_frags(lro_desc, len, hdr_len, true_size, frags, iph, tcph); + LRO_INC_STATS(lro_mgr, aggregated); + + if ((skb_shinfo(lro_desc->parent)->nr_frags >= lro_mgr->max_aggr) || + lro_desc->parent->len > (0xFFFF - lro_mgr->dev->mtu)) + lro_flush(lro_mgr, lro_desc); + + return NULL; + +out2: /* send aggregated packets to the stack */ + lro_flush(lro_mgr, lro_desc); + +out1: /* Original packet has to be posted to the stack */ + skb = lro_gen_skb(lro_mgr, frags, len, true_size, mac_hdr, + hdr_len, sum, lro_mgr->ip_summed); +out: + return skb; +} + void lro_receive_skb(struct net_lro_mgr *lro_mgr, struct sk_buff *skb, void *priv) { - if (__lro_proc_skb(lro_mgr, skb, priv)) { + if (__lro_proc_skb(lro_mgr, skb, priv, NULL)) { if (lro_mgr->features & LRO_F_NAPI) netif_receive_skb(skb); + else if (lro_mgr->features & LRO_F_NI) + netif_rx_ni(skb); else netif_rx(skb); } } EXPORT_SYMBOL(lro_receive_skb); +void lro_receive_frags(struct net_lro_mgr *lro_mgr, + struct skb_frag_struct *frags, + int len, int true_size, void *priv, __wsum sum) +{ + struct sk_buff *skb; + + skb = __lro_proc_segment(lro_mgr, frags, len, true_size, priv, sum); + if (!skb) + return; + + if (lro_mgr->features & LRO_F_NAPI) + netif_receive_skb(skb); + else if (lro_mgr->features & LRO_F_NI) + netif_rx_ni(skb); + else + netif_rx(skb); +} +EXPORT_SYMBOL(lro_receive_frags); + void lro_flush_all(struct net_lro_mgr *lro_mgr) { int i; @@ -372,3 +604,35 @@ void lro_flush_all(struct net_lro_mgr *lro_mgr) } } EXPORT_SYMBOL(lro_flush_all); + +void lro_flush_pkt(struct net_lro_mgr *lro_mgr, struct iphdr *iph, + struct tcphdr *tcph) +{ + struct net_lro_desc *lro_desc; + + lro_desc = lro_get_desc(lro_mgr, lro_mgr->lro_arr, iph, tcph); + if (lro_desc && lro_desc->active) + lro_flush(lro_mgr, lro_desc); +} +EXPORT_SYMBOL(lro_flush_pkt); + +void lro_flush_desc(struct net_lro_mgr *lro_mgr, struct net_lro_desc *lro_desc) +{ + if (lro_desc->active) + lro_flush(lro_mgr, lro_desc); +} +EXPORT_SYMBOL(lro_flush_desc); + +void lro_receive_skb_ext(struct net_lro_mgr *lro_mgr, struct sk_buff *skb, + void *priv, struct net_lro_info *lro_info) +{ + if (__lro_proc_skb(lro_mgr, skb, priv, lro_info)) { + if (lro_mgr->features & LRO_F_NAPI) + netif_receive_skb(skb); + else if (lro_mgr->features & LRO_F_NI) + netif_rx_ni(skb); + else + netif_rx(skb); + } +} +EXPORT_SYMBOL(lro_receive_skb_ext); diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 1fe55ae81781..b8a0607dab96 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -661,6 +661,7 @@ int ip_defrag(struct net *net, struct sk_buff *skb, u32 user) struct ipq *qp; IP_INC_STATS_BH(net, IPSTATS_MIB_REASMREQDS); + skb_orphan(skb); /* Lookup (or create) queue header */ qp = ip_find(net, ip_hdr(skb), user, vif); diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 5f73a7c03e27..a50124260f5a 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -249,6 +249,8 @@ int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc, switch (cmsg->cmsg_type) { case IP_RETOPTS: err = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)); + + /* Our caller is responsible for freeing ipc->opt */ err = ip_options_get(net, &ipc->opt, CMSG_DATA(cmsg), err < 40 ? err : 40); if (err) diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c index 6fb869f646bf..a04dee536b8e 100644 --- a/net/ipv4/netfilter/nf_defrag_ipv4.c +++ b/net/ipv4/netfilter/nf_defrag_ipv4.c @@ -27,8 +27,6 @@ static int nf_ct_ipv4_gather_frags(struct net *net, struct sk_buff *skb, { int err; - skb_orphan(skb); - local_bh_disable(); err = ip_defrag(net, skb, user); local_bh_enable(); diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index b27e98010dea..0d5278ca4777 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -746,8 +746,10 @@ static int ping_v4_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) if (msg->msg_controllen) { err = ip_cmsg_send(sock_net(sk), msg, &ipc, false); - if (err) + if (unlikely(err)) { + kfree(ipc.opt); return err; + } if (ipc.opt) free = 1; } diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 865895d3fb27..a9b479a1c4a0 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -547,8 +547,10 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) if (msg->msg_controllen) { err = ip_cmsg_send(net, msg, &ipc, false); - if (err) + if (unlikely(err)) { + kfree(ipc.opt); goto out; + } if (ipc.opt) free = 1; } diff --git a/net/ipv4/route.c b/net/ipv4/route.c index a0d842f4e9cf..79a957ea6545 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -129,6 +129,7 @@ static int ip_rt_mtu_expires __read_mostly = 10 * 60 * HZ; static int ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; static int ip_rt_min_advmss __read_mostly = 256; +static int ip_rt_gc_timeout __read_mostly = RT_GC_TIMEOUT; /* * Interface to generic destination cache. */ @@ -757,7 +758,7 @@ static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flow struct fib_nh *nh = &FIB_RES_NH(res); update_or_create_fnhe(nh, fl4->daddr, new_gw, - 0, 0); + 0, jiffies + ip_rt_gc_timeout); } if (kill_route) rt->dst.obsolete = DST_OBSOLETE_KILL; @@ -1558,6 +1559,36 @@ static void ip_handle_martian_source(struct net_device *dev, #endif } +static void ip_del_fnhe(struct fib_nh *nh, __be32 daddr) +{ + struct fnhe_hash_bucket *hash; + struct fib_nh_exception *fnhe, __rcu **fnhe_p; + u32 hval = fnhe_hashfun(daddr); + + spin_lock_bh(&fnhe_lock); + + hash = rcu_dereference_protected(nh->nh_exceptions, + lockdep_is_held(&fnhe_lock)); + hash += hval; + + fnhe_p = &hash->chain; + fnhe = rcu_dereference_protected(*fnhe_p, lockdep_is_held(&fnhe_lock)); + while (fnhe) { + if (fnhe->fnhe_daddr == daddr) { + rcu_assign_pointer(*fnhe_p, rcu_dereference_protected( + fnhe->fnhe_next, lockdep_is_held(&fnhe_lock))); + fnhe_flush_routes(fnhe); + kfree_rcu(fnhe, rcu); + break; + } + fnhe_p = &fnhe->fnhe_next; + fnhe = rcu_dereference_protected(fnhe->fnhe_next, + lockdep_is_held(&fnhe_lock)); + } + + spin_unlock_bh(&fnhe_lock); +} + /* called in rcu_read_lock() section */ static int __mkroute_input(struct sk_buff *skb, const struct fib_result *res, @@ -1611,11 +1642,20 @@ static int __mkroute_input(struct sk_buff *skb, fnhe = find_exception(&FIB_RES_NH(*res), daddr); if (do_cache) { - if (fnhe) + if (fnhe) { rth = rcu_dereference(fnhe->fnhe_rth_input); - else - rth = rcu_dereference(FIB_RES_NH(*res).nh_rth_input); + if (rth && rth->dst.expires && + time_after(jiffies, rth->dst.expires)) { + ip_del_fnhe(&FIB_RES_NH(*res), daddr); + fnhe = NULL; + } else { + goto rt_cache; + } + } + + rth = rcu_dereference(FIB_RES_NH(*res).nh_rth_input); +rt_cache: if (rt_cache_valid(rth)) { skb_dst_set_noref(skb, &rth->dst); goto out; @@ -2016,19 +2056,29 @@ static struct rtable *__mkroute_output(const struct fib_result *res, struct fib_nh *nh = &FIB_RES_NH(*res); fnhe = find_exception(nh, fl4->daddr); - if (fnhe) + if (fnhe) { prth = &fnhe->fnhe_rth_output; - else { - if (unlikely(fl4->flowi4_flags & - FLOWI_FLAG_KNOWN_NH && - !(nh->nh_gw && - nh->nh_scope == RT_SCOPE_LINK))) { - do_cache = false; - goto add; + rth = rcu_dereference(*prth); + if (rth && rth->dst.expires && + time_after(jiffies, rth->dst.expires)) { + ip_del_fnhe(nh, fl4->daddr); + fnhe = NULL; + } else { + goto rt_cache; } - prth = raw_cpu_ptr(nh->nh_pcpu_rth_output); } + + if (unlikely(fl4->flowi4_flags & + FLOWI_FLAG_KNOWN_NH && + !(nh->nh_gw && + nh->nh_scope == RT_SCOPE_LINK))) { + do_cache = false; + goto add; + } + prth = raw_cpu_ptr(nh->nh_pcpu_rth_output); rth = rcu_dereference(*prth); + +rt_cache: if (rt_cache_valid(rth)) { dst_hold(&rth->dst); return rth; @@ -2582,7 +2632,6 @@ void ip_rt_multicast_event(struct in_device *in_dev) } #ifdef CONFIG_SYSCTL -static int ip_rt_gc_timeout __read_mostly = RT_GC_TIMEOUT; static int ip_rt_gc_interval __read_mostly = 60 * HZ; static int ip_rt_gc_min_interval __read_mostly = HZ / 2; static int ip_rt_gc_elasticity __read_mostly = 8; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 24029ecf17ac..a839dcbc0fd8 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -42,6 +42,10 @@ static int tcp_syn_retries_min = 1; static int tcp_syn_retries_max = MAX_TCP_SYNCNT; static int ip_ping_group_range_min[] = { 0, 0 }; static int ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX }; +static int tcp_delack_seg_min = TCP_DELACK_MIN; +static int tcp_delack_seg_max = 60; +static int tcp_use_userconfig_min; +static int tcp_use_userconfig_max = 1; /* Update system visible IP port range */ static void set_local_port_range(struct net *net, int range[2]) @@ -821,6 +825,25 @@ static struct ctl_table ipv4_table[] = { .proc_handler = proc_dointvec_minmax, .extra1 = &one }, + { + .procname = "tcp_delack_seg", + .data = &sysctl_tcp_delack_seg, + .maxlen = sizeof(sysctl_tcp_delack_seg), + .mode = 0644, + .proc_handler = tcp_proc_delayed_ack_control, + .extra1 = &tcp_delack_seg_min, + .extra2 = &tcp_delack_seg_max, + }, + { + .procname = "tcp_use_userconfig", + .data = &sysctl_tcp_use_userconfig, + .maxlen = sizeof(sysctl_tcp_use_userconfig), + .mode = 0644, + .proc_handler = tcp_use_userconfig_sysctl_handler, + .extra1 = &tcp_use_userconfig_min, + .extra2 = &tcp_use_userconfig_max, + }, + { } }; diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 8398bb9c3503..e5cdafcc2140 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -283,6 +283,7 @@ #include <asm/uaccess.h> #include <asm/ioctls.h> +#include <asm/unaligned.h> #include <net/busy_poll.h> int sysctl_tcp_fin_timeout __read_mostly = TCP_FIN_TIMEOUT; @@ -305,6 +306,12 @@ EXPORT_SYMBOL(sysctl_tcp_wmem); atomic_long_t tcp_memory_allocated; /* Current allocated memory. */ EXPORT_SYMBOL(tcp_memory_allocated); +int sysctl_tcp_delack_seg __read_mostly = TCP_DELACK_SEG; +EXPORT_SYMBOL(sysctl_tcp_delack_seg); + +int sysctl_tcp_use_userconfig __read_mostly; +EXPORT_SYMBOL(sysctl_tcp_use_userconfig); + /* * Current number of TCP sockets. */ @@ -942,7 +949,7 @@ new_segment: i = skb_shinfo(skb)->nr_frags; can_coalesce = skb_can_coalesce(skb, i, page, offset); - if (!can_coalesce && i >= MAX_SKB_FRAGS) { + if (!can_coalesce && i >= sysctl_max_skb_frags) { tcp_mark_push(tp, skb); goto new_segment; } @@ -1215,7 +1222,7 @@ new_segment: if (!skb_can_coalesce(skb, i, pfrag->page, pfrag->offset)) { - if (i == MAX_SKB_FRAGS || !sg) { + if (i == sysctl_max_skb_frags || !sg) { tcp_mark_push(tp, skb); goto new_segment; } @@ -1405,8 +1412,11 @@ static void tcp_cleanup_rbuf(struct sock *sk, int copied) /* Delayed ACKs frequently hit locked sockets during bulk * receive. */ if (icsk->icsk_ack.blocked || - /* Once-per-two-segments ACK was not sent by tcp_input.c */ - tp->rcv_nxt - tp->rcv_wup > icsk->icsk_ack.rcv_mss || + /* Once-per-sysctl_tcp_delack_seg segments + * ACK was not sent by tcp_input.c + */ + tp->rcv_nxt - tp->rcv_wup > (icsk->icsk_ack.rcv_mss) * + sysctl_tcp_delack_seg || /* * If this read emptied read buffer, we send ACK, if * connection is not bidirectional, user drained @@ -2654,6 +2664,7 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info) const struct inet_connection_sock *icsk = inet_csk(sk); u32 now = tcp_time_stamp; unsigned int start; + u64 rate64; u32 rate; memset(info, 0, sizeof(*info)); @@ -2719,10 +2730,12 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info) info->tcpi_total_retrans = tp->total_retrans; rate = READ_ONCE(sk->sk_pacing_rate); - info->tcpi_pacing_rate = rate != ~0U ? rate : ~0ULL; + rate64 = rate != ~0U ? rate : ~0ULL; + put_unaligned(rate64, &info->tcpi_pacing_rate); rate = READ_ONCE(sk->sk_max_pacing_rate); - info->tcpi_max_pacing_rate = rate != ~0U ? rate : ~0ULL; + rate64 = rate != ~0U ? rate : ~0ULL; + put_unaligned(rate64, &info->tcpi_max_pacing_rate); /* Expose reference count for socket */ if (sk->sk_socket) { @@ -2734,8 +2747,8 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info) do { start = u64_stats_fetch_begin_irq(&tp->syncp); - info->tcpi_bytes_acked = tp->bytes_acked; - info->tcpi_bytes_received = tp->bytes_received; + put_unaligned(tp->bytes_acked, &info->tcpi_bytes_acked); + put_unaligned(tp->bytes_received, &info->tcpi_bytes_received); } while (u64_stats_fetch_retry_irq(&tp->syncp, start)); info->tcpi_segs_out = tp->segs_out; info->tcpi_segs_in = tp->segs_in; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index da34f830f4bc..b8f7e621e16e 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4955,7 +4955,8 @@ static void __tcp_ack_snd_check(struct sock *sk, int ofo_possible) struct tcp_sock *tp = tcp_sk(sk); /* More than one full frame received... */ - if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss && + if (((tp->rcv_nxt - tp->rcv_wup) > (inet_csk(sk)->icsk_ack.rcv_mss) * + sysctl_tcp_delack_seg && /* ... and right edge of window advances far enough. * (tcp_recvmsg() will send ACK otherwise). Or... */ diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 3cafb12bdb20..f5cfc5ff0712 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -312,7 +312,7 @@ static void do_redirect(struct sk_buff *skb, struct sock *sk) /* handle ICMP messages on TCP_NEW_SYN_RECV request sockets */ -void tcp_req_err(struct sock *sk, u32 seq) +void tcp_req_err(struct sock *sk, u32 seq, bool abort) { struct request_sock *req = inet_reqsk(sk); struct net *net = sock_net(sk); @@ -324,7 +324,7 @@ void tcp_req_err(struct sock *sk, u32 seq) if (seq != tcp_rsk(req)->snt_isn) { NET_INC_STATS_BH(net, LINUX_MIB_OUTOFWINDOWICMPS); - } else { + } else if (abort) { /* * Still in SYN_RECV, just remove it silently. * There is no good way to pass the error to the newly @@ -384,7 +384,12 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info) } seq = ntohl(th->seq); if (sk->sk_state == TCP_NEW_SYN_RECV) - return tcp_req_err(sk, seq); + return tcp_req_err(sk, seq, + type == ICMP_PARAMETERPROB || + type == ICMP_TIME_EXCEEDED || + (type == ICMP_DEST_UNREACH && + (code == ICMP_NET_UNREACH || + code == ICMP_HOST_UNREACH))); bh_lock_sock(sk); /* If too many ICMPs get dropped on busy @@ -705,7 +710,8 @@ release_sk1: outside socket context is ugly, certainly. What can I do? */ -static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, +static void tcp_v4_send_ack(struct net *net, + struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 tsval, u32 tsecr, int oif, struct tcp_md5sig_key *key, int reply_flags, u8 tos) @@ -720,7 +726,6 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, ]; } rep; struct ip_reply_arg arg; - struct net *net = dev_net(skb_dst(skb)->dev); memset(&rep.th, 0, sizeof(struct tcphdr)); memset(&arg, 0, sizeof(arg)); @@ -782,7 +787,8 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) struct inet_timewait_sock *tw = inet_twsk(sk); struct tcp_timewait_sock *tcptw = tcp_twsk(sk); - tcp_v4_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, + tcp_v4_send_ack(sock_net(sk), skb, + tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, tcp_time_stamp + tcptw->tw_ts_offset, tcptw->tw_ts_recent, @@ -801,8 +807,10 @@ static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, /* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV * sk->sk_state == TCP_SYN_RECV -> for Fast Open. */ - tcp_v4_send_ack(skb, (sk->sk_state == TCP_LISTEN) ? - tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt, + u32 seq = (sk->sk_state == TCP_LISTEN) ? tcp_rsk(req)->snt_isn + 1 : + tcp_sk(sk)->snd_nxt; + + tcp_v4_send_ack(sock_net(sk), skb, seq, tcp_rsk(req)->rcv_nxt, req->rsk_rcv_wnd, tcp_time_stamp, req->ts_recent, @@ -1588,28 +1596,30 @@ process: if (sk->sk_state == TCP_NEW_SYN_RECV) { struct request_sock *req = inet_reqsk(sk); - struct sock *nsk = NULL; + struct sock *nsk; sk = req->rsk_listener; - if (tcp_v4_inbound_md5_hash(sk, skb)) - goto discard_and_relse; - if (likely(sk->sk_state == TCP_LISTEN)) { - nsk = tcp_check_req(sk, skb, req, false); - } else { + if (unlikely(tcp_v4_inbound_md5_hash(sk, skb))) { + reqsk_put(req); + goto discard_it; + } + if (unlikely(sk->sk_state != TCP_LISTEN)) { inet_csk_reqsk_queue_drop_and_put(sk, req); goto lookup; } + sock_hold(sk); + nsk = tcp_check_req(sk, skb, req, false); if (!nsk) { reqsk_put(req); - goto discard_it; + goto discard_and_relse; } if (nsk == sk) { - sock_hold(sk); reqsk_put(req); } else if (tcp_child_process(sk, nsk, skb)) { tcp_v4_send_reset(nsk, skb); - goto discard_it; + goto discard_and_relse; } else { + sock_put(sk); return 0; } } diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 193ba1fa8a9a..ce20968de667 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -32,6 +32,40 @@ int sysctl_tcp_retries2 __read_mostly = TCP_RETR2; int sysctl_tcp_orphan_retries __read_mostly; int sysctl_tcp_thin_linear_timeouts __read_mostly; +/*Function to reset tcp_ack related sysctl on resetting master control */ +void set_tcp_default(void) +{ + sysctl_tcp_delack_seg = TCP_DELACK_SEG; +} + +/*sysctl handler for tcp_ack realted master control */ +int tcp_proc_delayed_ack_control(struct ctl_table *table, int write, + void __user *buffer, size_t *length, + loff_t *ppos) +{ + int ret = proc_dointvec_minmax(table, write, buffer, length, ppos); + + /* The ret value will be 0 if the input validation is successful + * and the values are written to sysctl table. If not, the stack + * will continue to work with currently configured values + */ + return ret; +} + +/*sysctl handler for tcp_ack realted master control */ +int tcp_use_userconfig_sysctl_handler(struct ctl_table *table, int write, + void __user *buffer, size_t *length, + loff_t *ppos) +{ + int ret = proc_dointvec_minmax(table, write, buffer, length, ppos); + + if (write && ret == 0) { + if (!sysctl_tcp_use_userconfig) + set_tcp_default(); + } + return ret; +} + static void tcp_write_err(struct sock *sk) { sk->sk_err = sk->sk_err_soft ? : ETIMEDOUT; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 424e036f9c4f..5411b65b7702 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -971,8 +971,10 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) if (msg->msg_controllen) { err = ip_cmsg_send(sock_net(sk), msg, &ipc, sk->sk_family == AF_INET6); - if (err) + if (unlikely(err)) { + kfree(ipc.opt); return err; + } if (ipc.opt) free = 1; connected = 0; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index cff2bccc9d89..bb9a2e90948e 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -587,7 +587,7 @@ static int inet6_netconf_get_devconf(struct sk_buff *in_skb, if (err < 0) goto errout; - err = EINVAL; + err = -EINVAL; if (!tb[NETCONFA_IFINDEX]) goto errout; diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 0dcb7ff082bd..ea2aa52578db 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -163,6 +163,9 @@ ipv4_connected: fl6.fl6_sport = inet->inet_sport; fl6.flowi6_uid = sock_i_uid(sk); + if (!fl6.flowi6_oif) + fl6.flowi6_oif = np->sticky_pktinfo.ipi6_ifindex; + if (!fl6.flowi6_oif && (addr_type&IPV6_ADDR_MULTICAST)) fl6.flowi6_oif = np->mcast_oif; diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 1f9ebe3cbb4a..dc2db4f7b182 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -540,12 +540,13 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) } spin_lock_bh(&ip6_sk_fl_lock); for (sflp = &np->ipv6_fl_list; - (sfl = rcu_dereference(*sflp)) != NULL; + (sfl = rcu_dereference_protected(*sflp, + lockdep_is_held(&ip6_sk_fl_lock))) != NULL; sflp = &sfl->next) { if (sfl->fl->label == freq.flr_label) { if (freq.flr_label == (np->flow_label&IPV6_FLOWLABEL_MASK)) np->flow_label &= ~IPV6_FLOWLABEL_MASK; - *sflp = rcu_dereference(sfl->next); + *sflp = sfl->next; spin_unlock_bh(&ip6_sk_fl_lock); fl_release(sfl->fl); kfree_rcu(sfl, rcu); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 6473889f1736..31144c486c52 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -909,6 +909,7 @@ static int ip6_dst_lookup_tail(struct net *net, const struct sock *sk, struct rt6_info *rt; #endif int err; + int flags = 0; /* The correct way to handle this would be to do * ip6_route_get_saddr, and then ip6_route_output; however, @@ -940,10 +941,13 @@ static int ip6_dst_lookup_tail(struct net *net, const struct sock *sk, dst_release(*dst); *dst = NULL; } + + if (fl6->flowi6_oif) + flags |= RT6_LOOKUP_F_IFACE; } if (!*dst) - *dst = ip6_route_output(net, sk, fl6); + *dst = ip6_route_output_flags(net, sk, fl6, flags); err = (*dst)->error; if (err) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 02ba70201e05..dd76806358fe 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1170,11 +1170,10 @@ static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags); } -struct dst_entry *ip6_route_output(struct net *net, const struct sock *sk, - struct flowi6 *fl6) +struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk, + struct flowi6 *fl6, int flags) { struct dst_entry *dst; - int flags = 0; bool any_src; dst = l3mdev_rt6_dst_by_oif(net, fl6); @@ -1195,7 +1194,7 @@ struct dst_entry *ip6_route_output(struct net *net, const struct sock *sk, return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output); } -EXPORT_SYMBOL(ip6_route_output); +EXPORT_SYMBOL_GPL(ip6_route_output_flags); struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig) { diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index ce737f178a6b..dab6da85a10e 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -329,6 +329,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, struct tcp_sock *tp; __u32 seq, snd_una; struct sock *sk; + bool fatal; int err; sk = __inet6_lookup_established(net, &tcp_hashinfo, @@ -347,8 +348,9 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, return; } seq = ntohl(th->seq); + fatal = icmpv6_err_convert(type, code, &err); if (sk->sk_state == TCP_NEW_SYN_RECV) - return tcp_req_err(sk, seq); + return tcp_req_err(sk, seq, fatal); bh_lock_sock(sk); if (sock_owned_by_user(sk) && type != ICMPV6_PKT_TOOBIG) @@ -402,7 +404,6 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, goto out; } - icmpv6_err_convert(type, code, &err); /* Might be for an request_sock */ switch (sk->sk_state) { @@ -1388,7 +1389,7 @@ process: if (sk->sk_state == TCP_NEW_SYN_RECV) { struct request_sock *req = inet_reqsk(sk); - struct sock *nsk = NULL; + struct sock *nsk; sk = req->rsk_listener; tcp_v6_fill_cb(skb, hdr, th); @@ -1396,24 +1397,24 @@ process: reqsk_put(req); goto discard_it; } - if (likely(sk->sk_state == TCP_LISTEN)) { - nsk = tcp_check_req(sk, skb, req, false); - } else { + if (unlikely(sk->sk_state != TCP_LISTEN)) { inet_csk_reqsk_queue_drop_and_put(sk, req); goto lookup; } + sock_hold(sk); + nsk = tcp_check_req(sk, skb, req, false); if (!nsk) { reqsk_put(req); - goto discard_it; + goto discard_and_relse; } if (nsk == sk) { - sock_hold(sk); reqsk_put(req); tcp_v6_restore_cb(skb); } else if (tcp_child_process(sk, nsk, skb)) { tcp_v6_send_reset(nsk, skb); - goto discard_it; + goto discard_and_relse; } else { + sock_put(sk); return 0; } } diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 435608c4306d..20ab7b2ec463 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -708,6 +708,9 @@ static int iucv_sock_bind(struct socket *sock, struct sockaddr *addr, if (!addr || addr->sa_family != AF_IUCV) return -EINVAL; + if (addr_len < sizeof(struct sockaddr_iucv)) + return -EINVAL; + lock_sock(sk); if (sk->sk_state != IUCV_OPEN) { err = -EBADFD; diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c index f93c5be612a7..2caaa84ce92d 100644 --- a/net/l2tp/l2tp_netlink.c +++ b/net/l2tp/l2tp_netlink.c @@ -124,8 +124,13 @@ static int l2tp_tunnel_notify(struct genl_family *family, ret = l2tp_nl_tunnel_send(msg, info->snd_portid, info->snd_seq, NLM_F_ACK, tunnel, cmd); - if (ret >= 0) - return genlmsg_multicast_allns(family, msg, 0, 0, GFP_ATOMIC); + if (ret >= 0) { + ret = genlmsg_multicast_allns(family, msg, 0, 0, GFP_ATOMIC); + /* We don't care if no one is listening */ + if (ret == -ESRCH) + ret = 0; + return ret; + } nlmsg_free(msg); @@ -147,8 +152,13 @@ static int l2tp_session_notify(struct genl_family *family, ret = l2tp_nl_session_send(msg, info->snd_portid, info->snd_seq, NLM_F_ACK, session, cmd); - if (ret >= 0) - return genlmsg_multicast_allns(family, msg, 0, 0, GFP_ATOMIC); + if (ret >= 0) { + ret = genlmsg_multicast_allns(family, msg, 0, 0, GFP_ATOMIC); + /* We don't care if no one is listening */ + if (ret == -ESRCH) + ret = 0; + return ret; + } nlmsg_free(msg); diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 10ad4ac1fa0b..367784be5df2 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -291,7 +291,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, } /* prepare A-MPDU MLME for Rx aggregation */ - tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL); + tid_agg_rx = kzalloc(sizeof(*tid_agg_rx), GFP_KERNEL); if (!tid_agg_rx) goto end; diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 337bb5d78003..6a12b0f5cac8 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -1732,7 +1732,6 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local) if (sdata->vif.type != NL80211_IFTYPE_ADHOC) continue; sdata->u.ibss.last_scan_completed = jiffies; - ieee80211_queue_work(&local->hw, &sdata->work); } mutex_unlock(&local->iflist_mtx); } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 5322b4c71630..6837a46ca4a2 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -92,7 +92,7 @@ struct ieee80211_fragment_entry { u16 extra_len; u16 last_frag; u8 rx_queue; - bool ccmp; /* Whether fragments were encrypted with CCMP */ + bool check_sequential_pn; /* needed for CCMP/GCMP */ u8 last_pn[6]; /* PN of the last fragment if CCMP was used */ }; diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index fa28500f28fd..6f85b6ab8e51 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -1370,17 +1370,6 @@ out: sdata_unlock(sdata); } -void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) -{ - struct ieee80211_sub_if_data *sdata; - - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) - if (ieee80211_vif_is_mesh(&sdata->vif) && - ieee80211_sdata_running(sdata)) - ieee80211_queue_work(&local->hw, &sdata->work); - rcu_read_unlock(); -} void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) { diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index a1596344c3ba..4a8019f79fb2 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -362,14 +362,10 @@ static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata) return sdata->u.mesh.mesh_pp_id == IEEE80211_PATH_PROTOCOL_HWMP; } -void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local); - void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata); void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata); void ieee80211s_stop(void); #else -static inline void -ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {} static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata) { return false; } static inline void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 3aa04344942b..83097c3832d1 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4003,8 +4003,6 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) if (!ieee80211_hw_check(&sdata->local->hw, CONNECTION_MONITOR)) ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.monitor_work); - /* and do all the other regular work too */ - ieee80211_queue_work(&sdata->local->hw, &sdata->work); } } diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index 3ece7d1034c8..b54f398cda5d 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -711,7 +711,7 @@ static u32 minstrel_get_expected_throughput(void *priv_sta) * computing cur_tp */ tmp_mrs = &mi->r[idx].stats; - tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_ewma); + tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_ewma) * 10; tmp_cur_tp = tmp_cur_tp * 1200 * 8 / 1024; return tmp_cur_tp; diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 3928dbd24e25..239ed6e92b89 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -691,7 +691,7 @@ minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb) if (likely(sta->ampdu_mlme.tid_tx[tid])) return; - ieee80211_start_tx_ba_session(pubsta, tid, 5000); + ieee80211_start_tx_ba_session(pubsta, tid, 0); } static void @@ -871,7 +871,7 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, * - if station is in dynamic SMPS (and streams > 1) * - for fallback rates, to increase chances of getting through */ - if (offset > 0 && + if (offset > 0 || (mi->sta->smps_mode == IEEE80211_SMPS_DYNAMIC && group->streams > 1)) { ratetbl->rate[offset].count = ratetbl->rate[offset].count_rts; @@ -1334,7 +1334,8 @@ static u32 minstrel_ht_get_expected_throughput(void *priv_sta) prob = mi->groups[i].rates[j].prob_ewma; /* convert tp_avg from pkt per second in kbps */ - tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * AVG_PKT_SIZE * 8 / 1024; + tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * 10; + tp_avg = tp_avg * AVG_PKT_SIZE * 8 / 1024; return tp_avg; } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 82af407fea7a..4cbf36cae806 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1754,7 +1754,7 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, entry->seq = seq; entry->rx_queue = rx_queue; entry->last_frag = frag; - entry->ccmp = 0; + entry->check_sequential_pn = false; entry->extra_len = 0; return entry; @@ -1850,15 +1850,27 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) rx->seqno_idx, &(rx->skb)); if (rx->key && (rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP || - rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP_256) && + rx->key->conf.cipher == WLAN_CIPHER_SUITE_CCMP_256 || + rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP || + rx->key->conf.cipher == WLAN_CIPHER_SUITE_GCMP_256) && ieee80211_has_protected(fc)) { int queue = rx->security_idx; - /* Store CCMP PN so that we can verify that the next - * fragment has a sequential PN value. */ - entry->ccmp = 1; + + /* Store CCMP/GCMP PN so that we can verify that the + * next fragment has a sequential PN value. + */ + entry->check_sequential_pn = true; memcpy(entry->last_pn, rx->key->u.ccmp.rx_pn[queue], IEEE80211_CCMP_PN_LEN); + BUILD_BUG_ON(offsetof(struct ieee80211_key, + u.ccmp.rx_pn) != + offsetof(struct ieee80211_key, + u.gcmp.rx_pn)); + BUILD_BUG_ON(sizeof(rx->key->u.ccmp.rx_pn[queue]) != + sizeof(rx->key->u.gcmp.rx_pn[queue])); + BUILD_BUG_ON(IEEE80211_CCMP_PN_LEN != + IEEE80211_GCMP_PN_LEN); } return RX_QUEUED; } @@ -1873,15 +1885,21 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) return RX_DROP_MONITOR; } - /* Verify that MPDUs within one MSDU have sequential PN values. - * (IEEE 802.11i, 8.3.3.4.5) */ - if (entry->ccmp) { + /* "The receiver shall discard MSDUs and MMPDUs whose constituent + * MPDU PN values are not incrementing in steps of 1." + * see IEEE P802.11-REVmc/D5.0, 12.5.3.4.4, item d (for CCMP) + * and IEEE P802.11-REVmc/D5.0, 12.5.5.4.4, item d (for GCMP) + */ + if (entry->check_sequential_pn) { int i; u8 pn[IEEE80211_CCMP_PN_LEN], *rpn; int queue; + if (!rx->key || (rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP && - rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP_256)) + rx->key->conf.cipher != WLAN_CIPHER_SUITE_CCMP_256 && + rx->key->conf.cipher != WLAN_CIPHER_SUITE_GCMP && + rx->key->conf.cipher != WLAN_CIPHER_SUITE_GCMP_256)) return RX_DROP_UNUSABLE; memcpy(pn, entry->last_pn, IEEE80211_CCMP_PN_LEN); for (i = IEEE80211_CCMP_PN_LEN - 1; i >= 0; i--) { @@ -3367,6 +3385,7 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx) return false; /* ignore action frames to TDLS-peers */ if (ieee80211_is_action(hdr->frame_control) && + !is_broadcast_ether_addr(bssid) && !ether_addr_equal(bssid, hdr->addr1)) return false; } diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index a413e52f7691..acbe182b75d1 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -314,6 +314,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) bool was_scanning = local->scanning; struct cfg80211_scan_request *scan_req; struct ieee80211_sub_if_data *scan_sdata; + struct ieee80211_sub_if_data *sdata; lockdep_assert_held(&local->mtx); @@ -373,7 +374,16 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) ieee80211_mlme_notify_scan_completed(local); ieee80211_ibss_notify_scan_completed(local); - ieee80211_mesh_notify_scan_completed(local); + + /* Requeue all the work that might have been ignored while + * the scan was in progress; if there was none this will + * just be a no-op for the particular interface. + */ + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (ieee80211_sdata_running(sdata)) + ieee80211_queue_work(&sdata->local->hw, &sdata->work); + } + if (was_scanning) ieee80211_start_next_roc(local); } diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c index 1605691d9414..d933cb89efac 100644 --- a/net/openvswitch/vport-vxlan.c +++ b/net/openvswitch/vport-vxlan.c @@ -90,7 +90,7 @@ static struct vport *vxlan_tnl_create(const struct vport_parms *parms) int err; struct vxlan_config conf = { .no_share = true, - .flags = VXLAN_F_COLLECT_METADATA, + .flags = VXLAN_F_COLLECT_METADATA | VXLAN_F_UDP_ZERO_CSUM6_RX, }; if (!options) { diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 9f843bbe8c10..d778d99326df 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -1097,17 +1097,6 @@ static unsigned int rfkill_fop_poll(struct file *file, poll_table *wait) return res; } -static bool rfkill_readable(struct rfkill_data *data) -{ - bool r; - - mutex_lock(&data->mtx); - r = !list_empty(&data->events); - mutex_unlock(&data->mtx); - - return r; -} - static ssize_t rfkill_fop_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { @@ -1124,8 +1113,11 @@ static ssize_t rfkill_fop_read(struct file *file, char __user *buf, goto out; } mutex_unlock(&data->mtx); + /* since we re-check and it just compares pointers, + * using !list_empty() without locking isn't a problem + */ ret = wait_event_interruptible(data->read_wait, - rfkill_readable(data)); + !list_empty(&data->events)); mutex_lock(&data->mtx); if (ret) diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index ba92bdb5b8bf..34967c19da85 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1891,6 +1891,7 @@ reset: } tp = old_tp; + protocol = tc_skb_protocol(skb); goto reclassify; #endif } diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 3d9ea9a48289..8b4ff315695e 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -60,6 +60,8 @@ #include <net/inet_common.h> #include <net/inet_ecn.h> +#define MAX_SCTP_PORT_HASH_ENTRIES (64 * 1024) + /* Global data structures. */ struct sctp_globals sctp_globals __read_mostly; @@ -1352,6 +1354,8 @@ static __init int sctp_init(void) unsigned long limit; int max_share; int order; + int num_entries; + int max_entry_order; sock_skb_cb_check_size(sizeof(struct sctp_ulpevent)); @@ -1404,14 +1408,24 @@ static __init int sctp_init(void) /* Size and allocate the association hash table. * The methodology is similar to that of the tcp hash tables. + * Though not identical. Start by getting a goal size */ if (totalram_pages >= (128 * 1024)) goal = totalram_pages >> (22 - PAGE_SHIFT); else goal = totalram_pages >> (24 - PAGE_SHIFT); - for (order = 0; (1UL << order) < goal; order++) - ; + /* Then compute the page order for said goal */ + order = get_order(goal); + + /* Now compute the required page order for the maximum sized table we + * want to create + */ + max_entry_order = get_order(MAX_SCTP_PORT_HASH_ENTRIES * + sizeof(struct sctp_bind_hashbucket)); + + /* Limit the page order by that maximum hash table size */ + order = min(order, max_entry_order); do { sctp_assoc_hashsize = (1UL << order) * PAGE_SIZE / @@ -1445,20 +1459,35 @@ static __init int sctp_init(void) INIT_HLIST_HEAD(&sctp_ep_hashtable[i].chain); } - /* Allocate and initialize the SCTP port hash table. */ + /* Allocate and initialize the SCTP port hash table. + * Note that order is initalized to start at the max sized + * table we want to support. If we can't get that many pages + * reduce the order and try again + */ do { - sctp_port_hashsize = (1UL << order) * PAGE_SIZE / - sizeof(struct sctp_bind_hashbucket); - if ((sctp_port_hashsize > (64 * 1024)) && order > 0) - continue; sctp_port_hashtable = (struct sctp_bind_hashbucket *) __get_free_pages(GFP_ATOMIC|__GFP_NOWARN, order); } while (!sctp_port_hashtable && --order > 0); + if (!sctp_port_hashtable) { pr_err("Failed bind hash alloc\n"); status = -ENOMEM; goto err_bhash_alloc; } + + /* Now compute the number of entries that will fit in the + * port hash space we allocated + */ + num_entries = (1UL << order) * PAGE_SIZE / + sizeof(struct sctp_bind_hashbucket); + + /* And finish by rounding it down to the nearest power of two + * this wastes some memory of course, but its needed because + * the hash function operates based on the assumption that + * that the number of entries is a power of two + */ + sctp_port_hashsize = rounddown_pow_of_two(num_entries); + for (i = 0; i < sctp_port_hashsize; i++) { spin_lock_init(&sctp_port_hashtable[i].lock); INIT_HLIST_HEAD(&sctp_port_hashtable[i].chain); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index ef1d90fdc773..be1489fc3234 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -5542,6 +5542,7 @@ static int sctp_getsockopt_hmac_ident(struct sock *sk, int len, struct sctp_hmac_algo_param *hmacs; __u16 data_len = 0; u32 num_idents; + int i; if (!ep->auth_enable) return -EACCES; @@ -5559,8 +5560,12 @@ static int sctp_getsockopt_hmac_ident(struct sock *sk, int len, return -EFAULT; if (put_user(num_idents, &p->shmac_num_idents)) return -EFAULT; - if (copy_to_user(p->shmac_idents, hmacs->hmac_ids, data_len)) - return -EFAULT; + for (i = 0; i < num_idents; i++) { + __u16 hmacid = ntohs(hmacs->hmac_ids[i]); + + if (copy_to_user(&p->shmac_idents[i], &hmacid, sizeof(__u16))) + return -EFAULT; + } return 0; } @@ -6640,6 +6645,7 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) if (cmsgs->srinfo->sinfo_flags & ~(SCTP_UNORDERED | SCTP_ADDR_OVER | + SCTP_SACK_IMMEDIATELY | SCTP_ABORT | SCTP_EOF)) return -EINVAL; break; @@ -6663,6 +6669,7 @@ static int sctp_msghdr_parse(const struct msghdr *msg, sctp_cmsgs_t *cmsgs) if (cmsgs->sinfo->snd_flags & ~(SCTP_UNORDERED | SCTP_ADDR_OVER | + SCTP_SACK_IMMEDIATELY | SCTP_ABORT | SCTP_EOF)) return -EINVAL; break; diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 5e4f815c2b34..21e20353178e 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c @@ -1225,7 +1225,7 @@ int qword_get(char **bpp, char *dest, int bufsize) if (bp[0] == '\\' && bp[1] == 'x') { /* HEX STRING */ bp += 2; - while (len < bufsize) { + while (len < bufsize - 1) { int h, l; h = hex_to_bin(bp[0]); diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index f34e535e93bd..d5d7132ac847 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -20,6 +20,7 @@ #include <linux/list.h> #include <linux/workqueue.h> #include <linux/if_vlan.h> +#include <linux/rtnetlink.h> #include <net/ip_fib.h> #include <net/switchdev.h> @@ -565,7 +566,6 @@ int switchdev_port_obj_dump(struct net_device *dev, struct switchdev_obj *obj, } EXPORT_SYMBOL_GPL(switchdev_port_obj_dump); -static DEFINE_MUTEX(switchdev_mutex); static RAW_NOTIFIER_HEAD(switchdev_notif_chain); /** @@ -580,9 +580,9 @@ int register_switchdev_notifier(struct notifier_block *nb) { int err; - mutex_lock(&switchdev_mutex); + rtnl_lock(); err = raw_notifier_chain_register(&switchdev_notif_chain, nb); - mutex_unlock(&switchdev_mutex); + rtnl_unlock(); return err; } EXPORT_SYMBOL_GPL(register_switchdev_notifier); @@ -598,9 +598,9 @@ int unregister_switchdev_notifier(struct notifier_block *nb) { int err; - mutex_lock(&switchdev_mutex); + rtnl_lock(); err = raw_notifier_chain_unregister(&switchdev_notif_chain, nb); - mutex_unlock(&switchdev_mutex); + rtnl_unlock(); return err; } EXPORT_SYMBOL_GPL(unregister_switchdev_notifier); @@ -614,16 +614,17 @@ EXPORT_SYMBOL_GPL(unregister_switchdev_notifier); * Call all network notifier blocks. This should be called by driver * when it needs to propagate hardware event. * Return values are same as for atomic_notifier_call_chain(). + * rtnl_lock must be held. */ int call_switchdev_notifiers(unsigned long val, struct net_device *dev, struct switchdev_notifier_info *info) { int err; + ASSERT_RTNL(); + info->dev = dev; - mutex_lock(&switchdev_mutex); err = raw_notifier_call_chain(&switchdev_notif_chain, val, info); - mutex_unlock(&switchdev_mutex); return err; } EXPORT_SYMBOL_GPL(call_switchdev_notifiers); diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 9dc239dfe192..92e367a0a5ce 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -399,8 +399,10 @@ int tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg) hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family, NLM_F_MULTI, TIPC_NL_LINK_GET); - if (!hdr) + if (!hdr) { + tipc_bcast_unlock(net); return -EMSGSIZE; + } attrs = nla_nest_start(msg->skb, TIPC_NLA_LINK); if (!attrs) diff --git a/net/tipc/node.c b/net/tipc/node.c index 20cddec0a43c..3926b561f873 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -168,12 +168,6 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr, u16 capabilities) skb_queue_head_init(&n_ptr->bc_entry.inputq1); __skb_queue_head_init(&n_ptr->bc_entry.arrvq); skb_queue_head_init(&n_ptr->bc_entry.inputq2); - hlist_add_head_rcu(&n_ptr->hash, &tn->node_htable[tipc_hashfn(addr)]); - list_for_each_entry_rcu(temp_node, &tn->node_list, list) { - if (n_ptr->addr < temp_node->addr) - break; - } - list_add_tail_rcu(&n_ptr->list, &temp_node->list); n_ptr->state = SELF_DOWN_PEER_LEAVING; n_ptr->signature = INVALID_NODE_SIG; n_ptr->active_links[0] = INVALID_BEARER_ID; @@ -193,6 +187,12 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr, u16 capabilities) tipc_node_get(n_ptr); setup_timer(&n_ptr->timer, tipc_node_timeout, (unsigned long)n_ptr); n_ptr->keepalive_intv = U32_MAX; + hlist_add_head_rcu(&n_ptr->hash, &tn->node_htable[tipc_hashfn(addr)]); + list_for_each_entry_rcu(temp_node, &tn->node_list, list) { + if (n_ptr->addr < temp_node->addr) + break; + } + list_add_tail_rcu(&n_ptr->list, &temp_node->list); exit: spin_unlock_bh(&tn->node_list_lock); return n_ptr; diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c index 350cca33ee0a..69ee2eeef968 100644 --- a/net/tipc/subscr.c +++ b/net/tipc/subscr.c @@ -289,15 +289,14 @@ static void tipc_subscrb_rcv_cb(struct net *net, int conid, struct sockaddr_tipc *addr, void *usr_data, void *buf, size_t len) { - struct tipc_subscriber *subscriber = usr_data; + struct tipc_subscriber *subscrb = usr_data; struct tipc_subscription *sub = NULL; struct tipc_net *tn = net_generic(net, tipc_net_id); - tipc_subscrp_create(net, (struct tipc_subscr *)buf, subscriber, &sub); - if (sub) - tipc_nametbl_subscribe(sub); - else - tipc_conn_terminate(tn->topsrv, subscriber->conid); + if (tipc_subscrp_create(net, (struct tipc_subscr *)buf, subscrb, &sub)) + return tipc_conn_terminate(tn->topsrv, subscrb->conid); + + tipc_nametbl_subscribe(sub); } /* Handle one request to establish a new subscriber */ diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index e3f85bc8b135..898a53a562b8 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1496,7 +1496,7 @@ static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb) UNIXCB(skb).fp = NULL; for (i = scm->fp->count-1; i >= 0; i--) - unix_notinflight(scm->fp->fp[i]); + unix_notinflight(scm->fp->user, scm->fp->fp[i]); } static void unix_destruct_scm(struct sk_buff *skb) @@ -1561,7 +1561,7 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) return -ENOMEM; for (i = scm->fp->count - 1; i >= 0; i--) - unix_inflight(scm->fp->fp[i]); + unix_inflight(scm->fp->user, scm->fp->fp[i]); return max_level; } @@ -1781,7 +1781,12 @@ restart_locked: goto out_unlock; } - if (unlikely(unix_peer(other) != sk && unix_recvq_full(other))) { + /* other == sk && unix_peer(other) != sk if + * - unix_peer(sk) == NULL, destination address bound to sk + * - unix_peer(sk) == sk by time of get but disconnected before lock + */ + if (other != sk && + unlikely(unix_peer(other) != sk && unix_recvq_full(other))) { if (timeo) { timeo = unix_wait_for_peer(other, timeo); @@ -2270,13 +2275,15 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state) size_t size = state->size; unsigned int last_len; - err = -EINVAL; - if (sk->sk_state != TCP_ESTABLISHED) + if (unlikely(sk->sk_state != TCP_ESTABLISHED)) { + err = -EINVAL; goto out; + } - err = -EOPNOTSUPP; - if (flags & MSG_OOB) + if (unlikely(flags & MSG_OOB)) { + err = -EOPNOTSUPP; goto out; + } target = sock_rcvlowat(sk, flags & MSG_WAITALL, size); timeo = sock_rcvtimeo(sk, noblock); @@ -2322,9 +2329,11 @@ again: goto unlock; unix_state_unlock(sk); - err = -EAGAIN; - if (!timeo) + if (!timeo) { + err = -EAGAIN; break; + } + mutex_unlock(&u->readlock); timeo = unix_stream_data_wait(sk, timeo, last, @@ -2332,6 +2341,7 @@ again: if (signal_pending(current)) { err = sock_intr_errno(timeo); + scm_destroy(&scm); goto out; } diff --git a/net/unix/diag.c b/net/unix/diag.c index c512f64d5287..4d9679701a6d 100644 --- a/net/unix/diag.c +++ b/net/unix/diag.c @@ -220,7 +220,7 @@ done: return skb->len; } -static struct sock *unix_lookup_by_ino(int ino) +static struct sock *unix_lookup_by_ino(unsigned int ino) { int i; struct sock *sk; diff --git a/net/unix/garbage.c b/net/unix/garbage.c index 8fcdc2283af5..6a0d48525fcf 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c @@ -116,7 +116,7 @@ struct sock *unix_get_socket(struct file *filp) * descriptor if it is for an AF_UNIX socket. */ -void unix_inflight(struct file *fp) +void unix_inflight(struct user_struct *user, struct file *fp) { struct sock *s = unix_get_socket(fp); @@ -133,11 +133,11 @@ void unix_inflight(struct file *fp) } unix_tot_inflight++; } - fp->f_cred->user->unix_inflight++; + user->unix_inflight++; spin_unlock(&unix_gc_lock); } -void unix_notinflight(struct file *fp) +void unix_notinflight(struct user_struct *user, struct file *fp) { struct sock *s = unix_get_socket(fp); @@ -152,7 +152,7 @@ void unix_notinflight(struct file *fp) list_del_init(&u->link); unix_tot_inflight--; } - fp->f_cred->user->unix_inflight--; + user->unix_inflight--; spin_unlock(&unix_gc_lock); } diff --git a/net/wireless/core.c b/net/wireless/core.c index e2cd8b8c2f09..7426ab13cede 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -1095,6 +1095,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, return NOTIFY_DONE; } + wireless_nlevent_flush(); + return NOTIFY_OK; } diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 816c9075ba3c..ad4b729262fd 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -3456,16 +3456,16 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) params.smps_mode = NL80211_SMPS_OFF; } + params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]); + if (params.pbss && !rdev->wiphy.bands[IEEE80211_BAND_60GHZ]) + return -EOPNOTSUPP; + if (info->attrs[NL80211_ATTR_ACL_POLICY]) { params.acl = parse_acl_data(&rdev->wiphy, info); if (IS_ERR(params.acl)) return PTR_ERR(params.acl); } - params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]); - if (params.pbss && !rdev->wiphy.bands[IEEE80211_BAND_60GHZ]) - return -EOPNOTSUPP; - wdev_lock(wdev); err = rdev_start_ap(rdev, dev, ¶ms); if (!err) { diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c index c8717c1d082e..b50ee5d622e1 100644 --- a/net/wireless/wext-core.c +++ b/net/wireless/wext-core.c @@ -342,6 +342,40 @@ static const int compat_event_type_size[] = { /* IW event code */ +void wireless_nlevent_flush(void) +{ + struct sk_buff *skb; + struct net *net; + + ASSERT_RTNL(); + + for_each_net(net) { + while ((skb = skb_dequeue(&net->wext_nlevents))) + rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, + GFP_KERNEL); + } +} +EXPORT_SYMBOL_GPL(wireless_nlevent_flush); + +static int wext_netdev_notifier_call(struct notifier_block *nb, + unsigned long state, void *ptr) +{ + /* + * When a netdev changes state in any way, flush all pending messages + * to avoid them going out in a strange order, e.g. RTM_NEWLINK after + * RTM_DELLINK, or with IFF_UP after without IFF_UP during dev_close() + * or similar - all of which could otherwise happen due to delays from + * schedule_work(). + */ + wireless_nlevent_flush(); + + return NOTIFY_OK; +} + +static struct notifier_block wext_netdev_notifier = { + .notifier_call = wext_netdev_notifier_call, +}; + static int __net_init wext_pernet_init(struct net *net) { skb_queue_head_init(&net->wext_nlevents); @@ -360,7 +394,12 @@ static struct pernet_operations wext_pernet_ops = { static int __init wireless_nlevent_init(void) { - return register_pernet_subsys(&wext_pernet_ops); + int err = register_pernet_subsys(&wext_pernet_ops); + + if (err) + return err; + + return register_netdevice_notifier(&wext_netdev_notifier); } subsys_initcall(wireless_nlevent_init); @@ -368,17 +407,8 @@ subsys_initcall(wireless_nlevent_init); /* Process events generated by the wireless layer or the driver. */ static void wireless_nlevent_process(struct work_struct *work) { - struct sk_buff *skb; - struct net *net; - rtnl_lock(); - - for_each_net(net) { - while ((skb = skb_dequeue(&net->wext_nlevents))) - rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, - GFP_KERNEL); - } - + wireless_nlevent_flush(); rtnl_unlock(); } diff --git a/scripts/ld-version.sh b/scripts/ld-version.sh index 198580d245e0..1659b409ef10 100755 --- a/scripts/ld-version.sh +++ b/scripts/ld-version.sh @@ -1,7 +1,7 @@ #!/usr/bin/awk -f # extract linker version number from stdin and turn into single number { - gsub(".*)", ""); + gsub(".*\\)", ""); split($1,a, "."); print a[1]*10000000 + a[2]*100000 + a[3]*10000 + a[4]*100 + a[5]; exit diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index dacf71a43ad4..ba6c34ea5429 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -62,7 +62,7 @@ vmlinux_link() -Wl,--start-group \ ${KBUILD_VMLINUX_MAIN} \ -Wl,--end-group \ - -lutil -lrt ${1} + -lutil -lrt -lpthread ${1} rm -f linux fi } diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index ff81026f6ddb..7c57c7fcf5a2 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -398,12 +398,10 @@ static int smk_copy_relabel(struct list_head *nhead, struct list_head *ohead, */ static inline unsigned int smk_ptrace_mode(unsigned int mode) { - switch (mode) { - case PTRACE_MODE_READ: - return MAY_READ; - case PTRACE_MODE_ATTACH: + if (mode & PTRACE_MODE_ATTACH) return MAY_READWRITE; - } + if (mode & PTRACE_MODE_READ) + return MAY_READ; return 0; } diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index d3c19c970a06..cb6ed10816d4 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c @@ -281,7 +281,7 @@ static int yama_ptrace_access_check(struct task_struct *child, int rc = 0; /* require ptrace target be a child of ptracer on attach */ - if (mode == PTRACE_MODE_ATTACH) { + if (mode & PTRACE_MODE_ATTACH) { switch (ptrace_scope) { case YAMA_SCOPE_DISABLED: /* No additional restrictions. */ @@ -307,7 +307,7 @@ static int yama_ptrace_access_check(struct task_struct *child, } } - if (rc) { + if (rc && (mode & PTRACE_MODE_NOAUDIT) == 0) { printk_ratelimited(KERN_NOTICE "ptrace of pid %d was attempted by: %s (pid %d)\n", child->pid, current->comm, current->pid); diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index b9c0910fb8c4..0608f216f359 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c @@ -170,6 +170,19 @@ struct snd_ctl_elem_value32 { unsigned char reserved[128]; }; +#ifdef CONFIG_X86_X32 +/* x32 has a different alignment for 64bit values from ia32 */ +struct snd_ctl_elem_value_x32 { + struct snd_ctl_elem_id id; + unsigned int indirect; /* bit-field causes misalignment */ + union { + s32 integer[128]; + unsigned char data[512]; + s64 integer64[64]; + } value; + unsigned char reserved[128]; +}; +#endif /* CONFIG_X86_X32 */ /* get the value type and count of the control */ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, @@ -219,9 +232,11 @@ static int get_elem_size(int type, int count) static int copy_ctl_value_from_user(struct snd_card *card, struct snd_ctl_elem_value *data, - struct snd_ctl_elem_value32 __user *data32, + void __user *userdata, + void __user *valuep, int *typep, int *countp) { + struct snd_ctl_elem_value32 __user *data32 = userdata; int i, type, size; int uninitialized_var(count); unsigned int indirect; @@ -239,8 +254,9 @@ static int copy_ctl_value_from_user(struct snd_card *card, if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN || type == SNDRV_CTL_ELEM_TYPE_INTEGER) { for (i = 0; i < count; i++) { + s32 __user *intp = valuep; int val; - if (get_user(val, &data32->value.integer[i])) + if (get_user(val, &intp[i])) return -EFAULT; data->value.integer.value[i] = val; } @@ -250,8 +266,7 @@ static int copy_ctl_value_from_user(struct snd_card *card, dev_err(card->dev, "snd_ioctl32_ctl_elem_value: unknown type %d\n", type); return -EINVAL; } - if (copy_from_user(data->value.bytes.data, - data32->value.data, size)) + if (copy_from_user(data->value.bytes.data, valuep, size)) return -EFAULT; } @@ -261,7 +276,8 @@ static int copy_ctl_value_from_user(struct snd_card *card, } /* restore the value to 32bit */ -static int copy_ctl_value_to_user(struct snd_ctl_elem_value32 __user *data32, +static int copy_ctl_value_to_user(void __user *userdata, + void __user *valuep, struct snd_ctl_elem_value *data, int type, int count) { @@ -270,22 +286,22 @@ static int copy_ctl_value_to_user(struct snd_ctl_elem_value32 __user *data32, if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN || type == SNDRV_CTL_ELEM_TYPE_INTEGER) { for (i = 0; i < count; i++) { + s32 __user *intp = valuep; int val; val = data->value.integer.value[i]; - if (put_user(val, &data32->value.integer[i])) + if (put_user(val, &intp[i])) return -EFAULT; } } else { size = get_elem_size(type, count); - if (copy_to_user(data32->value.data, - data->value.bytes.data, size)) + if (copy_to_user(valuep, data->value.bytes.data, size)) return -EFAULT; } return 0; } -static int snd_ctl_elem_read_user_compat(struct snd_card *card, - struct snd_ctl_elem_value32 __user *data32) +static int ctl_elem_read_user(struct snd_card *card, + void __user *userdata, void __user *valuep) { struct snd_ctl_elem_value *data; int err, type, count; @@ -294,7 +310,9 @@ static int snd_ctl_elem_read_user_compat(struct snd_card *card, if (data == NULL) return -ENOMEM; - if ((err = copy_ctl_value_from_user(card, data, data32, &type, &count)) < 0) + err = copy_ctl_value_from_user(card, data, userdata, valuep, + &type, &count); + if (err < 0) goto error; snd_power_lock(card); @@ -303,14 +321,15 @@ static int snd_ctl_elem_read_user_compat(struct snd_card *card, err = snd_ctl_elem_read(card, data); snd_power_unlock(card); if (err >= 0) - err = copy_ctl_value_to_user(data32, data, type, count); + err = copy_ctl_value_to_user(userdata, valuep, data, + type, count); error: kfree(data); return err; } -static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file, - struct snd_ctl_elem_value32 __user *data32) +static int ctl_elem_write_user(struct snd_ctl_file *file, + void __user *userdata, void __user *valuep) { struct snd_ctl_elem_value *data; struct snd_card *card = file->card; @@ -320,7 +339,9 @@ static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file, if (data == NULL) return -ENOMEM; - if ((err = copy_ctl_value_from_user(card, data, data32, &type, &count)) < 0) + err = copy_ctl_value_from_user(card, data, userdata, valuep, + &type, &count); + if (err < 0) goto error; snd_power_lock(card); @@ -329,12 +350,39 @@ static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file, err = snd_ctl_elem_write(card, file, data); snd_power_unlock(card); if (err >= 0) - err = copy_ctl_value_to_user(data32, data, type, count); + err = copy_ctl_value_to_user(userdata, valuep, data, + type, count); error: kfree(data); return err; } +static int snd_ctl_elem_read_user_compat(struct snd_card *card, + struct snd_ctl_elem_value32 __user *data32) +{ + return ctl_elem_read_user(card, data32, &data32->value); +} + +static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file, + struct snd_ctl_elem_value32 __user *data32) +{ + return ctl_elem_write_user(file, data32, &data32->value); +} + +#ifdef CONFIG_X86_X32 +static int snd_ctl_elem_read_user_x32(struct snd_card *card, + struct snd_ctl_elem_value_x32 __user *data32) +{ + return ctl_elem_read_user(card, data32, &data32->value); +} + +static int snd_ctl_elem_write_user_x32(struct snd_ctl_file *file, + struct snd_ctl_elem_value_x32 __user *data32) +{ + return ctl_elem_write_user(file, data32, &data32->value); +} +#endif /* CONFIG_X86_X32 */ + /* add or replace a user control */ static int snd_ctl_elem_add_compat(struct snd_ctl_file *file, struct snd_ctl_elem_info32 __user *data32, @@ -393,6 +441,10 @@ enum { SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct snd_ctl_elem_value32), SNDRV_CTL_IOCTL_ELEM_ADD32 = _IOWR('U', 0x17, struct snd_ctl_elem_info32), SNDRV_CTL_IOCTL_ELEM_REPLACE32 = _IOWR('U', 0x18, struct snd_ctl_elem_info32), +#ifdef CONFIG_X86_X32 + SNDRV_CTL_IOCTL_ELEM_READ_X32 = _IOWR('U', 0x12, struct snd_ctl_elem_value_x32), + SNDRV_CTL_IOCTL_ELEM_WRITE_X32 = _IOWR('U', 0x13, struct snd_ctl_elem_value_x32), +#endif /* CONFIG_X86_X32 */ }; static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) @@ -431,6 +483,12 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns return snd_ctl_elem_add_compat(ctl, argp, 0); case SNDRV_CTL_IOCTL_ELEM_REPLACE32: return snd_ctl_elem_add_compat(ctl, argp, 1); +#ifdef CONFIG_X86_X32 + case SNDRV_CTL_IOCTL_ELEM_READ_X32: + return snd_ctl_elem_read_user_x32(ctl->card, argp); + case SNDRV_CTL_IOCTL_ELEM_WRITE_X32: + return snd_ctl_elem_write_user_x32(ctl, argp); +#endif /* CONFIG_X86_X32 */ } down_read(&snd_ioctl_rwsem); diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 2666d8b58d88..e1512aea9f60 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -183,6 +183,14 @@ static int snd_pcm_ioctl_channel_info_compat(struct snd_pcm_substream *substream return err; } +#ifdef CONFIG_X86_X32 +/* X32 ABI has the same struct as x86-64 for snd_pcm_channel_info */ +static int snd_pcm_channel_info_user(struct snd_pcm_substream *substream, + struct snd_pcm_channel_info __user *src); +#define snd_pcm_ioctl_channel_info_x32(s, p) \ + snd_pcm_channel_info_user(s, p) +#endif /* CONFIG_X86_X32 */ + struct snd_pcm_status32 { s32 state; struct compat_timespec trigger_tstamp; @@ -243,6 +251,71 @@ static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream, return err; } +#ifdef CONFIG_X86_X32 +/* X32 ABI has 64bit timespec and 64bit alignment */ +struct snd_pcm_status_x32 { + s32 state; + u32 rsvd; /* alignment */ + struct timespec trigger_tstamp; + struct timespec tstamp; + u32 appl_ptr; + u32 hw_ptr; + s32 delay; + u32 avail; + u32 avail_max; + u32 overrange; + s32 suspended_state; + u32 audio_tstamp_data; + struct timespec audio_tstamp; + struct timespec driver_tstamp; + u32 audio_tstamp_accuracy; + unsigned char reserved[52-2*sizeof(struct timespec)]; +} __packed; + +#define put_timespec(src, dst) copy_to_user(dst, src, sizeof(*dst)) + +static int snd_pcm_status_user_x32(struct snd_pcm_substream *substream, + struct snd_pcm_status_x32 __user *src, + bool ext) +{ + struct snd_pcm_status status; + int err; + + memset(&status, 0, sizeof(status)); + /* + * with extension, parameters are read/write, + * get audio_tstamp_data from user, + * ignore rest of status structure + */ + if (ext && get_user(status.audio_tstamp_data, + (u32 __user *)(&src->audio_tstamp_data))) + return -EFAULT; + err = snd_pcm_status(substream, &status); + if (err < 0) + return err; + + if (clear_user(src, sizeof(*src))) + return -EFAULT; + if (put_user(status.state, &src->state) || + put_timespec(&status.trigger_tstamp, &src->trigger_tstamp) || + put_timespec(&status.tstamp, &src->tstamp) || + put_user(status.appl_ptr, &src->appl_ptr) || + put_user(status.hw_ptr, &src->hw_ptr) || + put_user(status.delay, &src->delay) || + put_user(status.avail, &src->avail) || + put_user(status.avail_max, &src->avail_max) || + put_user(status.overrange, &src->overrange) || + put_user(status.suspended_state, &src->suspended_state) || + put_user(status.audio_tstamp_data, &src->audio_tstamp_data) || + put_timespec(&status.audio_tstamp, &src->audio_tstamp) || + put_timespec(&status.driver_tstamp, &src->driver_tstamp) || + put_user(status.audio_tstamp_accuracy, &src->audio_tstamp_accuracy)) + return -EFAULT; + + return err; +} +#endif /* CONFIG_X86_X32 */ + /* both for HW_PARAMS and HW_REFINE */ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream, int refine, @@ -469,6 +542,93 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream, return 0; } +#ifdef CONFIG_X86_X32 +/* X32 ABI has 64bit timespec and 64bit alignment */ +struct snd_pcm_mmap_status_x32 { + s32 state; + s32 pad1; + u32 hw_ptr; + u32 pad2; /* alignment */ + struct timespec tstamp; + s32 suspended_state; + struct timespec audio_tstamp; +} __packed; + +struct snd_pcm_mmap_control_x32 { + u32 appl_ptr; + u32 avail_min; +}; + +struct snd_pcm_sync_ptr_x32 { + u32 flags; + u32 rsvd; /* alignment */ + union { + struct snd_pcm_mmap_status_x32 status; + unsigned char reserved[64]; + } s; + union { + struct snd_pcm_mmap_control_x32 control; + unsigned char reserved[64]; + } c; +} __packed; + +static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream, + struct snd_pcm_sync_ptr_x32 __user *src) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + volatile struct snd_pcm_mmap_status *status; + volatile struct snd_pcm_mmap_control *control; + u32 sflags; + struct snd_pcm_mmap_control scontrol; + struct snd_pcm_mmap_status sstatus; + snd_pcm_uframes_t boundary; + int err; + + if (snd_BUG_ON(!runtime)) + return -EINVAL; + + if (get_user(sflags, &src->flags) || + get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) || + get_user(scontrol.avail_min, &src->c.control.avail_min)) + return -EFAULT; + if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) { + err = snd_pcm_hwsync(substream); + if (err < 0) + return err; + } + status = runtime->status; + control = runtime->control; + boundary = recalculate_boundary(runtime); + if (!boundary) + boundary = 0x7fffffff; + snd_pcm_stream_lock_irq(substream); + /* FIXME: we should consider the boundary for the sync from app */ + if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) + control->appl_ptr = scontrol.appl_ptr; + else + scontrol.appl_ptr = control->appl_ptr % boundary; + if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) + control->avail_min = scontrol.avail_min; + else + scontrol.avail_min = control->avail_min; + sstatus.state = status->state; + sstatus.hw_ptr = status->hw_ptr % boundary; + sstatus.tstamp = status->tstamp; + sstatus.suspended_state = status->suspended_state; + sstatus.audio_tstamp = status->audio_tstamp; + snd_pcm_stream_unlock_irq(substream); + if (put_user(sstatus.state, &src->s.status.state) || + put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) || + put_timespec(&sstatus.tstamp, &src->s.status.tstamp) || + put_user(sstatus.suspended_state, &src->s.status.suspended_state) || + put_timespec(&sstatus.audio_tstamp, &src->s.status.audio_tstamp) || + put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) || + put_user(scontrol.avail_min, &src->c.control.avail_min)) + return -EFAULT; + + return 0; +} +#endif /* CONFIG_X86_X32 */ /* */ @@ -487,6 +647,12 @@ enum { SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct snd_xfern32), SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct snd_xfern32), SNDRV_PCM_IOCTL_SYNC_PTR32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr32), +#ifdef CONFIG_X86_X32 + SNDRV_PCM_IOCTL_CHANNEL_INFO_X32 = _IOR('A', 0x32, struct snd_pcm_channel_info), + SNDRV_PCM_IOCTL_STATUS_X32 = _IOR('A', 0x20, struct snd_pcm_status_x32), + SNDRV_PCM_IOCTL_STATUS_EXT_X32 = _IOWR('A', 0x24, struct snd_pcm_status_x32), + SNDRV_PCM_IOCTL_SYNC_PTR_X32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr_x32), +#endif /* CONFIG_X86_X32 */ }; static int snd_compressed_ioctl32(struct snd_pcm_substream *substream, @@ -591,6 +757,16 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l return snd_pcm_ioctl_rewind_compat(substream, argp); case SNDRV_PCM_IOCTL_FORWARD32: return snd_pcm_ioctl_forward_compat(substream, argp); +#ifdef CONFIG_X86_X32 + case SNDRV_PCM_IOCTL_STATUS_X32: + return snd_pcm_status_user_x32(substream, argp, false); + case SNDRV_PCM_IOCTL_STATUS_EXT_X32: + return snd_pcm_status_user_x32(substream, argp, true); + case SNDRV_PCM_IOCTL_SYNC_PTR_X32: + return snd_pcm_ioctl_sync_ptr_x32(substream, argp); + case SNDRV_PCM_IOCTL_CHANNEL_INFO_X32: + return snd_pcm_ioctl_channel_info_x32(substream, argp); +#endif /* CONFIG_X86_X32 */ default: if (_IOC_TYPE(cmd) == 'C') return snd_compressed_ioctl32(substream, cmd, argp); diff --git a/sound/core/rawmidi_compat.c b/sound/core/rawmidi_compat.c index 5268c1f58c25..09a89094dcf7 100644 --- a/sound/core/rawmidi_compat.c +++ b/sound/core/rawmidi_compat.c @@ -94,9 +94,58 @@ static int snd_rawmidi_ioctl_status_compat(struct snd_rawmidi_file *rfile, return 0; } +#ifdef CONFIG_X86_X32 +/* X32 ABI has 64bit timespec and 64bit alignment */ +struct snd_rawmidi_status_x32 { + s32 stream; + u32 rsvd; /* alignment */ + struct timespec tstamp; + u32 avail; + u32 xruns; + unsigned char reserved[16]; +} __attribute__((packed)); + +#define put_timespec(src, dst) copy_to_user(dst, src, sizeof(*dst)) + +static int snd_rawmidi_ioctl_status_x32(struct snd_rawmidi_file *rfile, + struct snd_rawmidi_status_x32 __user *src) +{ + int err; + struct snd_rawmidi_status status; + + if (rfile->output == NULL) + return -EINVAL; + if (get_user(status.stream, &src->stream)) + return -EFAULT; + + switch (status.stream) { + case SNDRV_RAWMIDI_STREAM_OUTPUT: + err = snd_rawmidi_output_status(rfile->output, &status); + break; + case SNDRV_RAWMIDI_STREAM_INPUT: + err = snd_rawmidi_input_status(rfile->input, &status); + break; + default: + return -EINVAL; + } + if (err < 0) + return err; + + if (put_timespec(&status.tstamp, &src->tstamp) || + put_user(status.avail, &src->avail) || + put_user(status.xruns, &src->xruns)) + return -EFAULT; + + return 0; +} +#endif /* CONFIG_X86_X32 */ + enum { SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct snd_rawmidi_params32), SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct snd_rawmidi_status32), +#ifdef CONFIG_X86_X32 + SNDRV_RAWMIDI_IOCTL_STATUS_X32 = _IOWR('W', 0x20, struct snd_rawmidi_status_x32), +#endif /* CONFIG_X86_X32 */ }; static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) @@ -115,6 +164,10 @@ static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsign return snd_rawmidi_ioctl_params_compat(rfile, argp); case SNDRV_RAWMIDI_IOCTL_STATUS32: return snd_rawmidi_ioctl_status_compat(rfile, argp); +#ifdef CONFIG_X86_X32 + case SNDRV_RAWMIDI_IOCTL_STATUS_X32: + return snd_rawmidi_ioctl_status_x32(rfile, argp); +#endif /* CONFIG_X86_X32 */ } return -ENOIOCTLCMD; } diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c index 7354b8bed860..cb23899100ee 100644 --- a/sound/core/seq/oss/seq_oss.c +++ b/sound/core/seq/oss/seq_oss.c @@ -148,8 +148,6 @@ odev_release(struct inode *inode, struct file *file) if ((dp = file->private_data) == NULL) return 0; - snd_seq_oss_drain_write(dp); - mutex_lock(®ister_mutex); snd_seq_oss_release(dp); mutex_unlock(®ister_mutex); diff --git a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h index b43924325249..d7b4d016b547 100644 --- a/sound/core/seq/oss/seq_oss_device.h +++ b/sound/core/seq/oss/seq_oss_device.h @@ -127,7 +127,6 @@ int snd_seq_oss_write(struct seq_oss_devinfo *dp, const char __user *buf, int co unsigned int snd_seq_oss_poll(struct seq_oss_devinfo *dp, struct file *file, poll_table * wait); void snd_seq_oss_reset(struct seq_oss_devinfo *dp); -void snd_seq_oss_drain_write(struct seq_oss_devinfo *dp); /* */ void snd_seq_oss_process_queue(struct seq_oss_devinfo *dp, abstime_t time); diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c index 6779e82b46dd..92c96a95a903 100644 --- a/sound/core/seq/oss/seq_oss_init.c +++ b/sound/core/seq/oss/seq_oss_init.c @@ -436,22 +436,6 @@ snd_seq_oss_release(struct seq_oss_devinfo *dp) /* - * Wait until the queue is empty (if we don't have nonblock) - */ -void -snd_seq_oss_drain_write(struct seq_oss_devinfo *dp) -{ - if (! dp->timer->running) - return; - if (is_write_mode(dp->file_mode) && !is_nonblock_mode(dp->file_mode) && - dp->writeq) { - while (snd_seq_oss_writeq_sync(dp->writeq)) - ; - } -} - - -/* * reset sequencer devices */ void diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c index e05802ae6e1b..2e908225d754 100644 --- a/sound/core/timer_compat.c +++ b/sound/core/timer_compat.c @@ -70,13 +70,14 @@ static int snd_timer_user_status_compat(struct file *file, struct snd_timer_status32 __user *_status) { struct snd_timer_user *tu; - struct snd_timer_status status; + struct snd_timer_status32 status; tu = file->private_data; if (snd_BUG_ON(!tu->timeri)) return -ENXIO; memset(&status, 0, sizeof(status)); - status.tstamp = tu->tstamp; + status.tstamp.tv_sec = tu->tstamp.tv_sec; + status.tstamp.tv_nsec = tu->tstamp.tv_nsec; status.resolution = snd_timer_resolution(tu->timeri); status.lost = tu->timeri->lost; status.overrun = tu->overrun; @@ -88,12 +89,21 @@ static int snd_timer_user_status_compat(struct file *file, return 0; } +#ifdef CONFIG_X86_X32 +/* X32 ABI has the same struct as x86-64 */ +#define snd_timer_user_status_x32(file, s) \ + snd_timer_user_status(file, s) +#endif /* CONFIG_X86_X32 */ + /* */ enum { SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct snd_timer_info32), SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct snd_timer_status32), +#ifdef CONFIG_X86_X32 + SNDRV_TIMER_IOCTL_STATUS_X32 = _IOW('T', 0x14, struct snd_timer_status), +#endif /* CONFIG_X86_X32 */ }; static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) @@ -122,6 +132,10 @@ static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, uns return snd_timer_user_info_compat(file, argp); case SNDRV_TIMER_IOCTL_STATUS32: return snd_timer_user_status_compat(file, argp); +#ifdef CONFIG_X86_X32 + case SNDRV_TIMER_IOCTL_STATUS_X32: + return snd_timer_user_status_x32(file, argp); +#endif /* CONFIG_X86_X32 */ } return -ENOIOCTLCMD; } diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 2c13298e80b7..2ff692dd2c5f 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -357,7 +357,10 @@ enum { ((pci)->device == 0x0d0c) || \ ((pci)->device == 0x160c)) -#define IS_BROXTON(pci) ((pci)->device == 0x5a98) +#define IS_SKL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa170) +#define IS_SKL_LP(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9d70) +#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98) +#define IS_SKL_PLUS(pci) (IS_SKL(pci) || IS_SKL_LP(pci) || IS_BXT(pci)) static char *driver_short_names[] = { [AZX_DRIVER_ICH] = "HDA Intel", @@ -534,13 +537,13 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset) if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) snd_hdac_set_codec_wakeup(bus, true); - if (IS_BROXTON(pci)) { + if (IS_SKL_PLUS(pci)) { pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val); val = val & ~INTEL_HDA_CGCTL_MISCBDCGE; pci_write_config_dword(pci, INTEL_HDA_CGCTL, val); } azx_init_chip(chip, full_reset); - if (IS_BROXTON(pci)) { + if (IS_SKL_PLUS(pci)) { pci_read_config_dword(pci, INTEL_HDA_CGCTL, &val); val = val | INTEL_HDA_CGCTL_MISCBDCGE; pci_write_config_dword(pci, INTEL_HDA_CGCTL, val); @@ -549,7 +552,7 @@ static void hda_intel_init_chip(struct azx *chip, bool full_reset) snd_hdac_set_codec_wakeup(bus, false); /* reduce dma latency to avoid noise */ - if (IS_BROXTON(pci)) + if (IS_BXT(pci)) bxt_reduce_dma_latency(chip); } @@ -971,11 +974,6 @@ static int azx_resume(struct device *dev) /* put codec down to D3 at hibernation for Intel SKL+; * otherwise BIOS may still access the codec and screw up the driver */ -#define IS_SKL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa170) -#define IS_SKL_LP(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9d70) -#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98) -#define IS_SKL_PLUS(pci) (IS_SKL(pci) || IS_SKL_LP(pci) || IS_BXT(pci)) - static int azx_freeze_noirq(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index efd4980cffb8..c2430b36e1ce 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4749,6 +4749,7 @@ enum { ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE, ALC293_FIXUP_LENOVO_SPK_NOISE, ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY, + ALC255_FIXUP_DELL_SPK_NOISE, }; static const struct hda_fixup alc269_fixups[] = { @@ -5368,6 +5369,12 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc233_fixup_lenovo_line2_mic_hotkey, }, + [ALC255_FIXUP_DELL_SPK_NOISE] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_disable_aamix, + .chained = true, + .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -5379,6 +5386,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x080d, "Acer Aspire V5-122P", ALC269_FIXUP_ASPIRE_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK), SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK), + SND_PCI_QUIRK(0x1025, 0x0762, "Acer Aspire E1-472", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572), SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572), SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS), SND_PCI_QUIRK(0x1025, 0x106d, "Acer Cloudbook 14", ALC283_FIXUP_CHROME_BOOK), @@ -5410,6 +5418,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x06df, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK), SND_PCI_QUIRK(0x1028, 0x06e0, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK), SND_PCI_QUIRK(0x1028, 0x0704, "Dell XPS 13", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE), + SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE), SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 2875b4f6d8c9..7c8941b8b2de 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -2879,7 +2879,7 @@ static int snd_hdsp_get_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl { struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - ucontrol->value.enumerated.item[0] = hdsp_dds_offset(hdsp); + ucontrol->value.integer.value[0] = hdsp_dds_offset(hdsp); return 0; } @@ -2891,7 +2891,7 @@ static int snd_hdsp_put_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl if (!snd_hdsp_use_is_exclusive(hdsp)) return -EBUSY; - val = ucontrol->value.enumerated.item[0]; + val = ucontrol->value.integer.value[0]; spin_lock_irq(&hdsp->lock); if (val != hdsp_dds_offset(hdsp)) change = (hdsp_set_dds_offset(hdsp, val) == 0) ? 1 : 0; diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 8bc8016c173d..a4a999a0317e 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -1601,6 +1601,9 @@ static void hdspm_set_dds_value(struct hdspm *hdspm, int rate) { u64 n; + if (snd_BUG_ON(rate <= 0)) + return; + if (rate >= 112000) rate /= 4; else if (rate >= 56000) @@ -2215,6 +2218,8 @@ static int hdspm_get_system_sample_rate(struct hdspm *hdspm) } else { /* slave mode, return external sample rate */ rate = hdspm_external_sample_rate(hdspm); + if (!rate) + rate = hdspm->system_sample_rate; } } @@ -2260,8 +2265,11 @@ static int snd_hdspm_put_system_sample_rate(struct snd_kcontrol *kcontrol, ucontrol) { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + int rate = ucontrol->value.integer.value[0]; - hdspm_set_dds_value(hdspm, ucontrol->value.enumerated.item[0]); + if (rate < 27000 || rate > 207000) + return -EINVAL; + hdspm_set_dds_value(hdspm, ucontrol->value.integer.value[0]); return 0; } @@ -4449,7 +4457,7 @@ static int snd_hdspm_get_tco_word_term(struct snd_kcontrol *kcontrol, { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - ucontrol->value.enumerated.item[0] = hdspm->tco->term; + ucontrol->value.integer.value[0] = hdspm->tco->term; return 0; } @@ -4460,8 +4468,8 @@ static int snd_hdspm_put_tco_word_term(struct snd_kcontrol *kcontrol, { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - if (hdspm->tco->term != ucontrol->value.enumerated.item[0]) { - hdspm->tco->term = ucontrol->value.enumerated.item[0]; + if (hdspm->tco->term != ucontrol->value.integer.value[0]) { + hdspm->tco->term = ucontrol->value.integer.value[0]; hdspm_tco_write(hdspm); diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 913bc0e06098..871c2980f4f7 100755 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -724,6 +724,12 @@ config SND_SOC_WCD9335 tristate depends on WCD9335_CODEC +config SND_SOC_WCD934X + tristate + depends on WCD934X_CODEC + select SND_SOC_WCD9XXX_V2 + select AUDIO_EXT_CLK + config SND_SOC_WSA881X tristate select MSM_CDC_PINCTRL @@ -967,7 +973,7 @@ config SND_SOC_MSM_STUB config SND_SOC_MSM_HDMI_CODEC_RX bool "HDMI Audio Playback" - depends on FB_MSM_MDSS_HDMI_PANEL && (SND_SOC_APQ8084 || SND_SOC_MSM8994 || SND_SOC_MSM8996) + depends on FB_MSM_MDSS_HDMI_PANEL && (SND_SOC_APQ8084 || SND_SOC_MSM8994 || SND_SOC_MSM8996 || SND_SOC_MSMCOBALT) help HDMI audio drivers should be built only if the platform supports hdmi panel. diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 07dd6266725f..ed2e49ddf432 100755..100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -133,6 +133,7 @@ snd-soc-uda1380-objs := uda1380.o snd-soc-wcd9320-objs := wcd9320.o wcd9320-tables.o snd-soc-wcd9330-objs := wcd9330.o wcd9330-tables.o snd-soc-wcd9335-objs := wcd9335.o +snd-soc-wcd934x-objs := wcd934x.o snd-soc-wcd9xxx-objs := wcd9xxx-resmgr.o wcd9xxx-mbhc.o wcd9xxx-common.o wcdcal-hwdep.o snd-soc-wcd9xxx-v2-objs := wcd9xxx-common-v2.o wcd9xxx-resmgr-v2.o audio-ext-clock-objs := audio-ext-clk.o @@ -340,6 +341,7 @@ obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o obj-$(CONFIG_SND_SOC_WCD9320) += snd-soc-wcd9320.o obj-$(CONFIG_SND_SOC_WCD9330) += snd-soc-wcd9330.o obj-$(CONFIG_SND_SOC_WCD9335) += snd-soc-wcd9335.o +obj-$(CONFIG_SND_SOC_WCD934X) += wcd934x/ obj-$(CONFIG_AUDIO_EXT_CLK) += audio-ext-clock.o obj-$(CONFIG_SND_SOC_WCD9XXX) += snd-soc-wcd9xxx.o obj-$(CONFIG_SND_SOC_WCD9XXX_V2) += snd-soc-wcd9xxx-v2.o diff --git a/sound/soc/codecs/audio-ext-clk.c b/sound/soc/codecs/audio-ext-clk.c index 2d7e55f69990..7faabcfb1db1 100755 --- a/sound/soc/codecs/audio-ext-clk.c +++ b/sound/soc/codecs/audio-ext-clk.c @@ -146,6 +146,15 @@ static struct audio_ext_pmi_clk audio_pmi_clk = { }, }; +static struct audio_ext_pmi_clk audio_pmi_lnbb_clk = { + .gpio = -EINVAL, + .c = { + .dbg_name = "audio_ext_pmi_lnbb_clk", + .ops = &clk_ops_dummy, + CLK_INIT(audio_pmi_lnbb_clk.c), + }, +}; + static struct audio_ext_ap_clk audio_ap_clk = { .gpio = -EINVAL, .c = { @@ -166,6 +175,7 @@ static struct audio_ext_ap_clk2 audio_ap_clk2 = { static struct clk_lookup audio_ref_clock[] = { CLK_LIST(audio_ap_clk), CLK_LIST(audio_pmi_clk), + CLK_LIST(audio_pmi_lnbb_clk), CLK_LIST(audio_ap_clk2), }; @@ -216,38 +226,44 @@ static int audio_ref_clk_probe(struct platform_device *pdev) { int clk_gpio; int ret; - struct clk *div_clk1; + struct clk *audio_clk; clk_gpio = of_get_named_gpio(pdev->dev.of_node, "qcom,audio-ref-clk-gpio", 0); - if (clk_gpio < 0) { - dev_err(&pdev->dev, - "Looking up %s property in node %s failed %d\n", - "qcom,audio-ref-clk-gpio", - pdev->dev.of_node->full_name, - clk_gpio); - ret = -EINVAL; - goto err; - } - ret = gpio_request(clk_gpio, "EXT_CLK"); - if (ret) { - dev_err(&pdev->dev, - "Request ext clk gpio failed %d, err:%d\n", - clk_gpio, ret); - goto err; - } - if (of_property_read_bool(pdev->dev.of_node, - "qcom,node_has_rpm_clock")) { - div_clk1 = clk_get(&pdev->dev, "osr_clk"); - if (IS_ERR(div_clk1)) { - dev_err(&pdev->dev, "Failed to get RPM div clk\n"); - ret = PTR_ERR(div_clk1); - goto err_gpio; + if (clk_gpio > 0) { + ret = gpio_request(clk_gpio, "EXT_CLK"); + if (ret) { + dev_err(&pdev->dev, + "Request ext clk gpio failed %d, err:%d\n", + clk_gpio, ret); + goto err; + } + if (of_property_read_bool(pdev->dev.of_node, + "qcom,node_has_rpm_clock")) { + audio_clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(audio_clk)) { + dev_err(&pdev->dev, "Failed to get RPM div clk\n"); + ret = PTR_ERR(audio_clk); + goto err_gpio; + } + audio_pmi_clk.c.parent = audio_clk; + audio_pmi_clk.gpio = clk_gpio; + } else + audio_ap_clk.gpio = clk_gpio; + + } else { + if (of_property_read_bool(pdev->dev.of_node, + "qcom,node_has_rpm_clock")) { + audio_clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(audio_clk)) { + dev_err(&pdev->dev, "Failed to get lnbbclk2\n"); + ret = PTR_ERR(audio_clk); + goto err; + } + audio_pmi_lnbb_clk.c.parent = audio_clk; + audio_pmi_lnbb_clk.gpio = -EINVAL; } - audio_pmi_clk.c.parent = div_clk1; - audio_pmi_clk.gpio = clk_gpio; - } else - audio_ap_clk.gpio = clk_gpio; + } ret = audio_get_pinctrl(pdev); if (ret) diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c index 36ab897b8dc0..63ffacad61e1 100644 --- a/sound/soc/codecs/wcd-mbhc-v2.c +++ b/sound/soc/codecs/wcd-mbhc-v2.c @@ -315,12 +315,17 @@ out_micb_en: mbhc->is_hs_recording); break; case WCD_EVENT_POST_MICBIAS_2_OFF: + if (!mbhc->mbhc_cb->mbhc_micbias_control) + mbhc->is_hs_recording = false; + if (mbhc->micbias_enable) { + wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB); + break; + } + if (mbhc->mbhc_cb->set_auto_zeroing) mbhc->mbhc_cb->set_auto_zeroing(codec, false); - if (mbhc->mbhc_cb->set_micbias_value) + if (mbhc->mbhc_cb->set_micbias_value && !mbhc->micbias_enable) mbhc->mbhc_cb->set_micbias_value(codec); - if (!mbhc->mbhc_cb->mbhc_micbias_control) - mbhc->is_hs_recording = false; /* Enable PULL UP if PA's are enabled */ if ((test_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state)) || (test_bit(WCD_MBHC_EVENT_PA_HPHR, @@ -578,6 +583,10 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic( mbhc->codec, MIC_BIAS_2, false); + if (mbhc->mbhc_cb->set_micbias_value) { + mbhc->mbhc_cb->set_micbias_value(mbhc->codec); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 0); + } mbhc->micbias_enable = false; } @@ -611,6 +620,12 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic( mbhc->codec, MIC_BIAS_2, false); + if (mbhc->mbhc_cb->set_micbias_value) { + mbhc->mbhc_cb->set_micbias_value( + mbhc->codec); + WCD_MBHC_REG_UPDATE_BITS( + WCD_MBHC_MICB_CTRL, 0); + } mbhc->micbias_enable = false; } mbhc->hph_type = WCD_MBHC_HPH_NONE; @@ -979,7 +994,7 @@ static bool wcd_is_special_headset(struct wcd_mbhc *mbhc) mbhc->mbhc_cb->mbhc_common_micb_ctrl(codec, MBHC_COMMON_MICB_PRECHARGE, false); - if (mbhc->mbhc_cb->set_micbias_value) + if (mbhc->mbhc_cb->set_micbias_value && !mbhc->micbias_enable) mbhc->mbhc_cb->set_micbias_value(codec); if (mbhc->mbhc_cb->set_auto_zeroing) mbhc->mbhc_cb->set_auto_zeroing(codec, false); @@ -1039,7 +1054,7 @@ static void wcd_enable_mbhc_supply(struct wcd_mbhc *mbhc, wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB); } else { if (plug_type == MBHC_PLUG_TYPE_HEADSET) { - if (mbhc->is_hs_recording) + if (mbhc->is_hs_recording || mbhc->micbias_enable) wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB); else if ((test_bit(WCD_MBHC_EVENT_PA_HPHL, @@ -1192,6 +1207,9 @@ correct_plug_type: if (mbhc->micbias_enable) { mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic( mbhc->codec, MIC_BIAS_2, false); + if (mbhc->mbhc_cb->set_micbias_value) + mbhc->mbhc_cb->set_micbias_value( + mbhc->codec); mbhc->micbias_enable = false; } goto exit; @@ -1214,6 +1232,9 @@ correct_plug_type: if (mbhc->micbias_enable) { mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic( mbhc->codec, MIC_BIAS_2, false); + if (mbhc->mbhc_cb->set_micbias_value) + mbhc->mbhc_cb->set_micbias_value( + mbhc->codec); mbhc->micbias_enable = false; } goto exit; @@ -1382,6 +1403,15 @@ exit: micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc, MIC_BIAS_2); } + + if (mbhc->mbhc_cfg->detect_extn_cable && + ((plug_type == MBHC_PLUG_TYPE_HEADPHONE) || + (plug_type == MBHC_PLUG_TYPE_HEADSET)) && + !mbhc->hs_detect_work_stop) { + WCD_MBHC_RSC_LOCK(mbhc); + wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM, true); + WCD_MBHC_RSC_UNLOCK(mbhc); + } if (mbhc->mbhc_cb->set_cap_mode) mbhc->mbhc_cb->set_cap_mode(codec, micbias1, micbias2); @@ -1734,6 +1764,10 @@ static irqreturn_t wcd_mbhc_hs_rem_irq(int irq, void *data) } } while (!time_after(jiffies, timeout)); + if (wcd_swch_level_remove(mbhc)) { + pr_debug("%s: Switch level is low ", __func__); + goto exit; + } pr_debug("%s: headset %s actually removed\n", __func__, removed ? "" : "not "); @@ -1768,6 +1802,7 @@ static irqreturn_t wcd_mbhc_hs_rem_irq(int irq, void *data) } } } +exit: WCD_MBHC_RSC_UNLOCK(mbhc); pr_debug("%s: leave\n", __func__); return IRQ_HANDLED; diff --git a/sound/soc/codecs/wcd9330.c b/sound/soc/codecs/wcd9330.c index 84368d817dc9..16a23aa9770c 100644 --- a/sound/soc/codecs/wcd9330.c +++ b/sound/soc/codecs/wcd9330.c @@ -8472,7 +8472,10 @@ static int tomtom_post_reset_cb(struct wcd9xxx *wcd9xxx) wcd9xxx_mbhc_deinit(&tomtom->mbhc); tomtom->mbhc_started = false; - rco_clk_rate = TOMTOM_MCLK_CLK_9P6MHZ; + if (wcd9xxx->mclk_rate == TOMTOM_MCLK_CLK_12P288MHZ) + rco_clk_rate = TOMTOM_MCLK_CLK_12P288MHZ; + else + rco_clk_rate = TOMTOM_MCLK_CLK_9P6MHZ; ret = wcd9xxx_mbhc_init(&tomtom->mbhc, &tomtom->resmgr, codec, tomtom_enable_mbhc_micbias, @@ -8814,7 +8817,10 @@ static int tomtom_codec_probe(struct snd_soc_codec *codec) tomtom->clsh_d.is_dynamic_vdd_cp = false; wcd9xxx_clsh_init(&tomtom->clsh_d, &tomtom->resmgr); - rco_clk_rate = TOMTOM_MCLK_CLK_9P6MHZ; + if (wcd9xxx->mclk_rate == TOMTOM_MCLK_CLK_12P288MHZ) + rco_clk_rate = TOMTOM_MCLK_CLK_12P288MHZ; + else + rco_clk_rate = TOMTOM_MCLK_CLK_9P6MHZ; tomtom->fw_data = kzalloc(sizeof(*(tomtom->fw_data)), GFP_KERNEL); if (!tomtom->fw_data) { diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index c941729be2aa..f46057d027e0 100755 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -129,6 +129,7 @@ #define WCD9335_DEC_PWR_LVL_LP 0x02 #define WCD9335_DEC_PWR_LVL_HP 0x04 #define WCD9335_DEC_PWR_LVL_DF 0x00 +#define WCD9335_STRING_LEN 100 #define CALCULATE_VOUT_D(req_mv) (((req_mv - 650) * 10) / 25) @@ -349,6 +350,12 @@ enum { CPE_NOMINAL, HPH_PA_DELAY, SB_CLK_GEAR, + ANC_MIC_AMIC1, + ANC_MIC_AMIC2, + ANC_MIC_AMIC3, + ANC_MIC_AMIC4, + ANC_MIC_AMIC5, + ANC_MIC_AMIC6, }; enum { @@ -576,6 +583,7 @@ static struct snd_soc_dai_driver tasha_dai[]; static int wcd9335_get_micb_vout_ctl_val(u32 micb_mv); static int tasha_config_compander(struct snd_soc_codec *, int, int); +static void tasha_codec_set_tx_hold(struct snd_soc_codec *, u16, bool); /* Hold instance to soundwire platform device */ struct tasha_swr_ctrl_data { @@ -779,7 +787,7 @@ struct tasha_priv { /* to track the status */ unsigned long status_mask; - struct work_struct swr_add_devices_work; + struct work_struct tasha_add_child_devices_work; struct wcd_swr_ctrl_platform_data swr_plat_data; /* Port values for Rx and Tx codec_dai */ @@ -3775,7 +3783,7 @@ static int tasha_codec_enable_anc(struct snd_soc_dapm_widget *w, WCD9335_CDC_ANC0_IIR_COEFF_2_CTL); anc_writes_size = anc_cal_size / 2; snd_soc_update_bits(codec, - WCD9335_CDC_ANC0_CLK_RESET_CTL, 0x38, 0x38); + WCD9335_CDC_ANC0_CLK_RESET_CTL, 0x39, 0x39); } else if (!strcmp(w->name, "RX INT2 DAC") || !strcmp(w->name, "RX INT4 DAC")) { tasha_realign_anc_coeff(codec, @@ -3783,7 +3791,7 @@ static int tasha_codec_enable_anc(struct snd_soc_dapm_widget *w, WCD9335_CDC_ANC1_IIR_COEFF_2_CTL); i = anc_cal_size / 2; snd_soc_update_bits(codec, - WCD9335_CDC_ANC1_CLK_RESET_CTL, 0x38, 0x38); + WCD9335_CDC_ANC1_CLK_RESET_CTL, 0x39, 0x39); } for (; i < anc_writes_size; i++) { @@ -3793,16 +3801,23 @@ static int tasha_codec_enable_anc(struct snd_soc_dapm_widget *w, if (!strcmp(w->name, "RX INT1 DAC") || !strcmp(w->name, "RX INT3 DAC")) { snd_soc_update_bits(codec, - WCD9335_CDC_ANC0_CLK_RESET_CTL, 0x38, 0x00); + WCD9335_CDC_ANC0_CLK_RESET_CTL, 0x08, 0x08); } else if (!strcmp(w->name, "RX INT2 DAC") || !strcmp(w->name, "RX INT4 DAC")) { snd_soc_update_bits(codec, - WCD9335_CDC_ANC1_CLK_RESET_CTL, 0x38, 0x00); + WCD9335_CDC_ANC1_CLK_RESET_CTL, 0x08, 0x08); } if (!hwdep_cal) release_firmware(fw); break; + case SND_SOC_DAPM_POST_PMU: + /* Remove ANC Rx from reset */ + snd_soc_update_bits(codec, WCD9335_CDC_ANC0_CLK_RESET_CTL, + 0x08, 0x00); + snd_soc_update_bits(codec, WCD9335_CDC_ANC1_CLK_RESET_CTL, + 0x08, 0x00); + break; case SND_SOC_DAPM_POST_PMD: if (!strcmp(w->name, "ANC HPHL PA") || !strcmp(w->name, "ANC EAR PA") || @@ -3842,6 +3857,22 @@ err: return ret; } +static void tasha_codec_clear_anc_tx_hold(struct tasha_priv *tasha) +{ + if (test_and_clear_bit(ANC_MIC_AMIC1, &tasha->status_mask)) + tasha_codec_set_tx_hold(tasha->codec, WCD9335_ANA_AMIC1, false); + if (test_and_clear_bit(ANC_MIC_AMIC2, &tasha->status_mask)) + tasha_codec_set_tx_hold(tasha->codec, WCD9335_ANA_AMIC2, false); + if (test_and_clear_bit(ANC_MIC_AMIC3, &tasha->status_mask)) + tasha_codec_set_tx_hold(tasha->codec, WCD9335_ANA_AMIC3, false); + if (test_and_clear_bit(ANC_MIC_AMIC4, &tasha->status_mask)) + tasha_codec_set_tx_hold(tasha->codec, WCD9335_ANA_AMIC4, false); + if (test_and_clear_bit(ANC_MIC_AMIC5, &tasha->status_mask)) + tasha_codec_set_tx_hold(tasha->codec, WCD9335_ANA_AMIC5, false); + if (test_and_clear_bit(ANC_MIC_AMIC6, &tasha->status_mask)) + tasha_codec_set_tx_hold(tasha->codec, WCD9335_ANA_AMIC6, false); +} + static void tasha_codec_hph_post_pa_config(struct tasha_priv *tasha, int mode, int event) { @@ -3860,6 +3891,13 @@ static void tasha_codec_hph_post_pa_config(struct tasha_priv *tasha, scale_val = 0x1; break; } + if (tasha->anc_func) { + /* Clear Tx FE HOLD if both PAs are enabled */ + if ((snd_soc_read(tasha->codec, WCD9335_ANA_HPH) & + 0xC0) == 0xC0) { + tasha_codec_clear_anc_tx_hold(tasha); + } + } break; case SND_SOC_DAPM_PRE_PMD: scale_val = 0x6; @@ -3926,9 +3964,20 @@ static int tasha_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: + if ((!(strcmp(w->name, "ANC HPHR PA"))) && + (test_bit(HPH_PA_DELAY, &tasha->status_mask))) { + snd_soc_update_bits(codec, WCD9335_ANA_HPH, 0xC0, 0xC0); + } set_bit(HPH_PA_DELAY, &tasha->status_mask); break; case SND_SOC_DAPM_POST_PMU: + if ((snd_soc_read(codec, WCD9335_ANA_HPH) & 0xC0) != 0xC0) + /* + * If PA_EN is not set (potentially in ANC case) then + * do nothing for POST_PMU and let left channel handle + * everything. + */ + break; /* * 7ms sleep is required after PA is enabled as per * HW requirement @@ -3946,13 +3995,31 @@ static int tasha_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, WCD9335_CDC_RX2_RX_PATH_MIX_CTL, 0x10, 0x00); + + if (!(strcmp(w->name, "ANC HPHR PA"))) { + /* Do everything needed for left channel */ + snd_soc_update_bits(codec, WCD9335_CDC_RX1_RX_PATH_CTL, + 0x10, 0x00); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_read(codec, + WCD9335_CDC_RX1_RX_PATH_MIX_CTL)) & + 0x10) + snd_soc_update_bits(codec, + WCD9335_CDC_RX1_RX_PATH_MIX_CTL, + 0x10, 0x00); + /* Remove ANC Rx from reset */ + ret = tasha_codec_enable_anc(w, kcontrol, event); + } tasha_codec_override(codec, hph_mode, event); break; + case SND_SOC_DAPM_PRE_PMD: blocking_notifier_call_chain(&tasha->notifier, WCD_EVENT_PRE_HPHR_PA_OFF, &tasha->mbhc); tasha_codec_hph_post_pa_config(tasha, hph_mode, event); + if (!(strcmp(w->name, "ANC HPHR PA"))) + snd_soc_update_bits(codec, WCD9335_ANA_HPH, 0x40, 0x00); break; case SND_SOC_DAPM_POST_PMD: /* 5ms sleep is required after PA is disabled as per @@ -3988,9 +4055,20 @@ static int tasha_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: + if ((!(strcmp(w->name, "ANC HPHL PA"))) && + (test_bit(HPH_PA_DELAY, &tasha->status_mask))) { + snd_soc_update_bits(codec, WCD9335_ANA_HPH, 0xC0, 0xC0); + } set_bit(HPH_PA_DELAY, &tasha->status_mask); break; case SND_SOC_DAPM_POST_PMU: + if ((snd_soc_read(codec, WCD9335_ANA_HPH) & 0xC0) != 0xC0) + /* + * If PA_EN is not set (potentially in ANC case) then + * do nothing for POST_PMU and let right channel handle + * everything. + */ + break; /* * 7ms sleep is required after PA is enabled as per * HW requirement @@ -4009,6 +4087,22 @@ static int tasha_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, WCD9335_CDC_RX1_RX_PATH_MIX_CTL, 0x10, 0x00); + + if (!(strcmp(w->name, "ANC HPHL PA"))) { + /* Do everything needed for right channel */ + snd_soc_update_bits(codec, WCD9335_CDC_RX2_RX_PATH_CTL, + 0x10, 0x00); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_read(codec, + WCD9335_CDC_RX2_RX_PATH_MIX_CTL)) & + 0x10) + snd_soc_update_bits(codec, + WCD9335_CDC_RX2_RX_PATH_MIX_CTL, + 0x10, 0x00); + + /* Remove ANC Rx from reset */ + ret = tasha_codec_enable_anc(w, kcontrol, event); + } tasha_codec_override(codec, hph_mode, event); break; case SND_SOC_DAPM_PRE_PMD: @@ -4016,6 +4110,8 @@ static int tasha_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, WCD_EVENT_PRE_HPHL_PA_OFF, &tasha->mbhc); tasha_codec_hph_post_pa_config(tasha, hph_mode, event); + if (!(strcmp(w->name, "ANC HPHL PA"))) + snd_soc_update_bits(codec, WCD9335_ANA_HPH, 0x80, 0x00); break; case SND_SOC_DAPM_POST_PMD: /* 5ms sleep is required after PA is disabled as per @@ -4083,6 +4179,9 @@ static int tasha_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, lineout_mix_vol_reg, 0x10, 0x00); + if (!(strcmp(w->name, "ANC LINEOUT1 PA")) || + !(strcmp(w->name, "ANC LINEOUT2 PA"))) + ret = tasha_codec_enable_anc(w, kcontrol, event); tasha_codec_override(codec, CLS_AB, event); break; case SND_SOC_DAPM_POST_PMD: @@ -5394,8 +5493,8 @@ static int tasha_codec_tx_adc_cfg(struct snd_soc_dapm_widget *w, { int adc_mux_n = w->shift; struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec); int amic_n; - u16 amic_reg; dev_dbg(codec->dev, "%s: event: %d\n", __func__, event); @@ -5403,8 +5502,13 @@ static int tasha_codec_tx_adc_cfg(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMU: amic_n = tasha_codec_find_amic_input(codec, adc_mux_n); if (amic_n) { - amic_reg = WCD9335_ANA_AMIC1 + amic_n - 1; - tasha_codec_set_tx_hold(codec, amic_reg, false); + /* + * Prevent ANC Rx pop by leaving Tx FE in HOLD + * state until PA is up. Track AMIC being used + * so we can release the HOLD later. + */ + set_bit(ANC_MIC_AMIC1 + amic_n - 1, + &tasha->status_mask); } break; default: @@ -5616,9 +5720,20 @@ static int tasha_codec_enable_dec(struct snd_soc_dapm_widget *w, msecs_to_jiffies(300)); break; case SND_SOC_DAPM_PRE_PMD: + hpf_cut_off_freq = + tasha->tx_hpf_work[decimator].hpf_cut_off_freq; snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x10, 0x10); snd_soc_update_bits(codec, dec_cfg_reg, 0x08, 0x00); - cancel_delayed_work_sync(&tasha->tx_hpf_work[decimator].dwork); + if (cancel_delayed_work_sync( + &tasha->tx_hpf_work[decimator].dwork)) { + if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) { + tasha_codec_vote_max_bw(codec, true); + snd_soc_update_bits(codec, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + hpf_cut_off_freq << 5); + tasha_codec_vote_max_bw(codec, false); + } + } cancel_delayed_work_sync( &tasha->tx_mute_dwork[decimator].dwork); break; @@ -7511,9 +7626,9 @@ static int tasha_mad_input_put(struct snd_kcontrol *kcontrol, "%s: tasha input widget = %s\n", __func__, mad_input_widget); - for (i = 0; i < card->num_dapm_routes; i++) { - if (!strcmp(card->dapm_routes[i].sink, mad_input_widget)) { - source_widget = card->dapm_routes[i].source; + for (i = 0; i < card->num_of_dapm_routes; i++) { + if (!strcmp(card->of_dapm_routes[i].sink, mad_input_widget)) { + source_widget = card->of_dapm_routes[i].source; if (!source_widget) { dev_err(codec->dev, "%s: invalid source widget\n", @@ -10512,11 +10627,11 @@ static const struct snd_soc_dapm_widget tasha_dapm_widgets[] = { tasha_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_PGA_E("ANC HPHL PA", WCD9335_ANA_HPH, 7, 0, NULL, 0, + SND_SOC_DAPM_PGA_E("ANC HPHL PA", SND_SOC_NOPM, 0, 0, NULL, 0, tasha_codec_enable_hphl_pa, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_PGA_E("ANC HPHR PA", WCD9335_ANA_HPH, 6, 0, NULL, 0, + SND_SOC_DAPM_PGA_E("ANC HPHR PA", SND_SOC_NOPM, 0, 0, NULL, 0, tasha_codec_enable_hphr_pa, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), @@ -13350,7 +13465,7 @@ static int tasha_swrm_handle_irq(void *handle, return ret; } -static void wcd_swr_ctrl_add_devices(struct work_struct *work) +static void tasha_add_child_devices(struct work_struct *work) { struct tasha_priv *tasha; struct platform_device *pdev; @@ -13359,9 +13474,10 @@ static void wcd_swr_ctrl_add_devices(struct work_struct *work) struct tasha_swr_ctrl_data *swr_ctrl_data = NULL, *temp; int ret, ctrl_num = 0; struct wcd_swr_ctrl_platform_data *platdata; + char plat_dev_name[WCD9335_STRING_LEN]; tasha = container_of(work, struct tasha_priv, - swr_add_devices_work); + tasha_add_child_devices_work); if (!tasha) { pr_err("%s: Memory for WCD9335 does not exist\n", __func__); @@ -13382,17 +13498,17 @@ static void wcd_swr_ctrl_add_devices(struct work_struct *work) platdata = &tasha->swr_plat_data; for_each_child_of_node(wcd9xxx->dev->of_node, node) { - temp = krealloc(swr_ctrl_data, - (ctrl_num + 1) * sizeof(struct tasha_swr_ctrl_data), - GFP_KERNEL); - if (!temp) { - dev_err(wcd9xxx->dev, "out of memory\n"); - ret = -ENOMEM; - goto err; - } - swr_ctrl_data = temp; - swr_ctrl_data[ctrl_num].swr_pdev = NULL; - pdev = platform_device_alloc("tasha_swr_ctrl", -1); + if (!strcmp(node->name, "swr_master")) + strlcpy(plat_dev_name, "tasha_swr_ctrl", + (WCD9335_STRING_LEN - 1)); + else if (strnstr(node->name, "msm_cdc_pinctrl", + strlen("msm_cdc_pinctrl")) != NULL) + strlcpy(plat_dev_name, node->name, + (WCD9335_STRING_LEN - 1)); + else + continue; + + pdev = platform_device_alloc(plat_dev_name, -1); if (!pdev) { dev_err(wcd9xxx->dev, "%s: pdev memory alloc failed\n", __func__); @@ -13402,28 +13518,45 @@ static void wcd_swr_ctrl_add_devices(struct work_struct *work) pdev->dev.parent = tasha->dev; pdev->dev.of_node = node; - ret = platform_device_add_data(pdev, platdata, - sizeof(*platdata)); - if (ret) { - dev_err(&pdev->dev, "%s: cannot add plat data for ctrl:%d\n", - __func__, ctrl_num); - goto fail_pdev_add; + if (!strcmp(node->name, "swr_master")) { + ret = platform_device_add_data(pdev, platdata, + sizeof(*platdata)); + if (ret) { + dev_err(&pdev->dev, + "%s: cannot add plat data ctrl:%d\n", + __func__, ctrl_num); + goto fail_pdev_add; + } } ret = platform_device_add(pdev); if (ret) { - dev_err(&pdev->dev, "%s: Cannot add swr platform device\n", + dev_err(&pdev->dev, + "%s: Cannot add platform device\n", __func__); goto fail_pdev_add; } - swr_ctrl_data[ctrl_num].swr_pdev = pdev; - ctrl_num++; - dev_dbg(&pdev->dev, "%s: Added soundwire ctrl device(s)\n", - __func__); + if (!strcmp(node->name, "swr_master")) { + temp = krealloc(swr_ctrl_data, + (ctrl_num + 1) * sizeof( + struct tasha_swr_ctrl_data), + GFP_KERNEL); + if (!temp) { + dev_err(wcd9xxx->dev, "out of memory\n"); + ret = -ENOMEM; + goto err; + } + swr_ctrl_data = temp; + swr_ctrl_data[ctrl_num].swr_pdev = pdev; + ctrl_num++; + dev_dbg(&pdev->dev, + "%s: Added soundwire ctrl device(s)\n", + __func__); + tasha->nr = ctrl_num; + tasha->swr_ctrl_data = swr_ctrl_data; + } } - tasha->nr = ctrl_num; - tasha->swr_ctrl_data = swr_ctrl_data; return; fail_pdev_add: @@ -13523,7 +13656,8 @@ static int tasha_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&tasha->power_gate_work, tasha_codec_power_gate_work); mutex_init(&tasha->power_lock); mutex_init(&tasha->sido_lock); - INIT_WORK(&tasha->swr_add_devices_work, wcd_swr_ctrl_add_devices); + INIT_WORK(&tasha->tasha_add_child_devices_work, + tasha_add_child_devices); BLOCKING_INIT_NOTIFIER_HEAD(&tasha->notifier); mutex_init(&tasha->micb_lock); mutex_init(&tasha->swr_read_lock); @@ -13534,7 +13668,7 @@ static int tasha_probe(struct platform_device *pdev) GFP_KERNEL); if (!cdc_pwr) { ret = -ENOMEM; - goto cdc_pwr_fail; + goto err_cdc_pwr; } tasha->wcd9xxx->wcd9xxx_pwr[WCD9XXX_DIG_CORE_REGION_1] = cdc_pwr; cdc_pwr->pwr_collapse_reg_min = TASHA_DIG_CORE_REG_MIN; @@ -13543,18 +13677,6 @@ static int tasha_probe(struct platform_device *pdev) WCD_REGION_POWER_COLLAPSE_REMOVE, WCD9XXX_DIG_CORE_REGION_1); - if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS) - ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tasha, - tasha_dai, ARRAY_SIZE(tasha_dai)); - else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) - ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tasha, - tasha_i2s_dai, - ARRAY_SIZE(tasha_i2s_dai)); - if (ret) { - dev_err(&pdev->dev, "%s: Codec registration failed\n", - __func__); - goto cdc_reg_fail; - } mutex_init(&tasha->codec_mutex); /* * Init resource manager so that if child nodes such as SoundWire @@ -13565,7 +13687,7 @@ static int tasha_probe(struct platform_device *pdev) ret = PTR_ERR(resmgr); dev_err(&pdev->dev, "%s: Failed to initialize wcd resmgr\n", __func__); - goto unregister_codec; + goto err_resmgr; } tasha->resmgr = resmgr; tasha->swr_plat_data.handle = (void *) tasha; @@ -13580,7 +13702,7 @@ static int tasha_probe(struct platform_device *pdev) if (IS_ERR(wcd_ext_clk)) { dev_err(tasha->wcd9xxx->dev, "%s: clk get %s failed\n", __func__, "wcd_ext_clk"); - goto resmgr_remove; + goto err_clk; } tasha->wcd_ext_clk = wcd_ext_clk; tasha->sido_voltage = SIDO_VOLTAGE_NOMINAL_MV; @@ -13594,23 +13716,38 @@ static int tasha_probe(struct platform_device *pdev) __func__, "wcd_native_clk"); else tasha->wcd_native_clk = wcd_native_clk; + + if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS) + ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tasha, + tasha_dai, ARRAY_SIZE(tasha_dai)); + else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) + ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tasha, + tasha_i2s_dai, + ARRAY_SIZE(tasha_i2s_dai)); + else + ret = -EINVAL; + if (ret) { + dev_err(&pdev->dev, "%s: Codec registration failed, ret = %d\n", + __func__, ret); + goto err_cdc_reg; + } /* Update codec register default values */ tasha_update_reg_defaults(tasha); - schedule_work(&tasha->swr_add_devices_work); - + schedule_work(&tasha->tasha_add_child_devices_work); tasha_get_codec_ver(tasha); + dev_info(&pdev->dev, "%s: Tasha driver probe done\n", __func__); return ret; -resmgr_remove: +err_cdc_reg: + clk_put(tasha->wcd_ext_clk); + if (tasha->wcd_native_clk) + clk_put(tasha->wcd_native_clk); +err_clk: wcd_resmgr_remove(tasha->resmgr); -unregister_codec: - if ((wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS) || - (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)) - snd_soc_unregister_codec(&pdev->dev); -cdc_reg_fail: +err_resmgr: devm_kfree(&pdev->dev, cdc_pwr); -cdc_pwr_fail: +err_cdc_pwr: devm_kfree(&pdev->dev, tasha); return ret; } diff --git a/sound/soc/codecs/wcd934x/Makefile b/sound/soc/codecs/wcd934x/Makefile new file mode 100644 index 000000000000..ddb8053ec525 --- /dev/null +++ b/sound/soc/codecs/wcd934x/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for wcd934x codec driver. +# +snd-soc-wcd934x-objs := wcd934x.o +obj-$(CONFIG_SND_SOC_WCD934X) += snd-soc-wcd934x.o diff --git a/sound/soc/codecs/wcd934x/wcd934x-routing.h b/sound/soc/codecs/wcd934x/wcd934x-routing.h new file mode 100644 index 000000000000..4735ef9722ed --- /dev/null +++ b/sound/soc/codecs/wcd934x/wcd934x-routing.h @@ -0,0 +1,1001 @@ +/* + * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef WCD934X_ROUTING_H +#define WCD934X_ROUTING_H + +#include <sound/soc-dapm.h> + +const struct snd_soc_dapm_route tavil_slim_audio_map[] = { + + /* Virtual input widgets */ + {"AIF1 CAP", NULL, "AIF1_CAP Mixer"}, + {"AIF2 CAP", NULL, "AIF2_CAP Mixer"}, + {"AIF3 CAP", NULL, "AIF3_CAP Mixer"}, + + /* Virtual input widget Mixer */ + {"AIF1_CAP Mixer", "SLIM TX0", "SLIM TX0"}, + {"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1"}, + {"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2"}, + {"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3"}, + {"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4"}, + {"AIF1_CAP Mixer", "SLIM TX5", "SLIM TX5"}, + {"AIF1_CAP Mixer", "SLIM TX6", "SLIM TX6"}, + {"AIF1_CAP Mixer", "SLIM TX7", "SLIM TX7"}, + {"AIF1_CAP Mixer", "SLIM TX8", "SLIM TX8"}, + {"AIF1_CAP Mixer", "SLIM TX9", "SLIM TX9"}, + {"AIF1_CAP Mixer", "SLIM TX10", "SLIM TX10"}, + {"AIF1_CAP Mixer", "SLIM TX11", "SLIM TX11"}, + {"AIF1_CAP Mixer", "SLIM TX13", "SLIM TX13"}, + + {"AIF2_CAP Mixer", "SLIM TX0", "SLIM TX0"}, + {"AIF2_CAP Mixer", "SLIM TX1", "SLIM TX1"}, + {"AIF2_CAP Mixer", "SLIM TX2", "SLIM TX2"}, + {"AIF2_CAP Mixer", "SLIM TX3", "SLIM TX3"}, + {"AIF2_CAP Mixer", "SLIM TX4", "SLIM TX4"}, + {"AIF2_CAP Mixer", "SLIM TX5", "SLIM TX5"}, + {"AIF2_CAP Mixer", "SLIM TX6", "SLIM TX6"}, + {"AIF2_CAP Mixer", "SLIM TX7", "SLIM TX7"}, + {"AIF2_CAP Mixer", "SLIM TX8", "SLIM TX8"}, + {"AIF2_CAP Mixer", "SLIM TX9", "SLIM TX9"}, + {"AIF2_CAP Mixer", "SLIM TX10", "SLIM TX10"}, + {"AIF2_CAP Mixer", "SLIM TX11", "SLIM TX11"}, + {"AIF2_CAP Mixer", "SLIM TX13", "SLIM TX13"}, + + {"AIF3_CAP Mixer", "SLIM TX0", "SLIM TX0"}, + {"AIF3_CAP Mixer", "SLIM TX1", "SLIM TX1"}, + {"AIF3_CAP Mixer", "SLIM TX2", "SLIM TX2"}, + {"AIF3_CAP Mixer", "SLIM TX3", "SLIM TX3"}, + {"AIF3_CAP Mixer", "SLIM TX4", "SLIM TX4"}, + {"AIF3_CAP Mixer", "SLIM TX5", "SLIM TX5"}, + {"AIF3_CAP Mixer", "SLIM TX6", "SLIM TX6"}, + {"AIF3_CAP Mixer", "SLIM TX7", "SLIM TX7"}, + {"AIF3_CAP Mixer", "SLIM TX8", "SLIM TX8"}, + {"AIF3_CAP Mixer", "SLIM TX9", "SLIM TX9"}, + {"AIF3_CAP Mixer", "SLIM TX10", "SLIM TX10"}, + {"AIF3_CAP Mixer", "SLIM TX11", "SLIM TX11"}, + {"AIF3_CAP Mixer", "SLIM TX13", "SLIM TX13"}, + + {"SLIM RX0 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX5 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX6 MUX", "AIF1_PB", "AIF1 PB"}, + {"SLIM RX7 MUX", "AIF1_PB", "AIF1 PB"}, + + {"SLIM RX0 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX1 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX2 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX3 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX4 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX5 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX6 MUX", "AIF2_PB", "AIF2 PB"}, + {"SLIM RX7 MUX", "AIF2_PB", "AIF2 PB"}, + + {"SLIM RX0 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX1 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX2 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX3 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX4 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX5 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX6 MUX", "AIF3_PB", "AIF3 PB"}, + {"SLIM RX7 MUX", "AIF3_PB", "AIF3 PB"}, + + {"SLIM RX0 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX1 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX2 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX3 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX4 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX5 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX6 MUX", "AIF4_PB", "AIF4 PB"}, + {"SLIM RX7 MUX", "AIF4_PB", "AIF4 PB"}, + + {"SLIM RX0", NULL, "SLIM RX0 MUX"}, + {"SLIM RX1", NULL, "SLIM RX1 MUX"}, + {"SLIM RX2", NULL, "SLIM RX2 MUX"}, + {"SLIM RX3", NULL, "SLIM RX3 MUX"}, + {"SLIM RX4", NULL, "SLIM RX4 MUX"}, + {"SLIM RX5", NULL, "SLIM RX5 MUX"}, + {"SLIM RX6", NULL, "SLIM RX6 MUX"}, + {"SLIM RX7", NULL, "SLIM RX7 MUX"}, + +}; + +const struct snd_soc_dapm_route tavil_audio_map[] = { + + /* CDC Tx interface with SLIMBUS */ + {"SLIM TX0", NULL, "CDC_IF TX0 MUX"}, + {"SLIM TX1", NULL, "CDC_IF TX1 MUX"}, + {"SLIM TX2", NULL, "CDC_IF TX2 MUX"}, + {"SLIM TX3", NULL, "CDC_IF TX3 MUX"}, + {"SLIM TX4", NULL, "CDC_IF TX4 MUX"}, + {"SLIM TX5", NULL, "CDC_IF TX5 MUX"}, + {"SLIM TX6", NULL, "CDC_IF TX6 MUX"}, + {"SLIM TX7", NULL, "CDC_IF TX7 MUX"}, + {"SLIM TX8", NULL, "CDC_IF TX8 MUX"}, + {"SLIM TX9", NULL, "CDC_IF TX9 MUX"}, + {"SLIM TX10", NULL, "CDC_IF TX10 MUX"}, + {"SLIM TX11", NULL, "CDC_IF TX11 MUX"}, + {"SLIM TX13", NULL, "CDC_IF TX13 MUX"}, + + {"CDC_IF TX0 MUX", "DEC0", "ADC MUX0"}, + {"CDC_IF TX0 MUX", "RX_MIX_TX0", "RX MIX TX0 MUX"}, + {"CDC_IF TX0 MUX", "DEC0_192", "ADC US MUX0"}, + + {"CDC_IF TX1 MUX", "DEC1", "ADC MUX1"}, + {"CDC_IF TX1 MUX", "RX_MIX_TX1", "RX MIX TX1 MUX"}, + {"CDC_IF TX1 MUX", "DEC1_192", "ADC US MUX1"}, + + {"CDC_IF TX2 MUX", "DEC2", "ADC MUX2"}, + {"CDC_IF TX2 MUX", "RX_MIX_TX2", "RX MIX TX2 MUX"}, + {"CDC_IF TX2 MUX", "DEC2_192", "ADC US MUX2"}, + + {"CDC_IF TX3 MUX", "DEC3", "ADC MUX3"}, + {"CDC_IF TX3 MUX", "RX_MIX_TX3", "RX MIX TX3 MUX"}, + {"CDC_IF TX3 MUX", "DEC3_192", "ADC US MUX3"}, + + {"CDC_IF TX4 MUX", "DEC4", "ADC MUX4"}, + {"CDC_IF TX4 MUX", "RX_MIX_TX4", "RX MIX TX4 MUX"}, + {"CDC_IF TX4 MUX", "DEC4_192", "ADC US MUX4"}, + + {"CDC_IF TX5 MUX", "DEC5", "ADC MUX5"}, + {"CDC_IF TX5 MUX", "RX_MIX_TX5", "RX MIX TX5 MUX"}, + {"CDC_IF TX5 MUX", "DEC5_192", "ADC US MUX5"}, + + {"CDC_IF TX6 MUX", "DEC6", "ADC MUX6"}, + {"CDC_IF TX6 MUX", "RX_MIX_TX6", "RX MIX TX6 MUX"}, + {"CDC_IF TX6 MUX", "DEC6_192", "ADC US MUX6"}, + + {"CDC_IF TX7 MUX", "DEC7", "ADC MUX7"}, + {"CDC_IF TX7 MUX", "RX_MIX_TX7", "RX MIX TX7 MUX"}, + {"CDC_IF TX7 MUX", "DEC7_192", "ADC US MUX7"}, + + {"CDC_IF TX8 MUX", "DEC8", "ADC MUX8"}, + {"CDC_IF TX8 MUX", "RX_MIX_TX8", "RX MIX TX8 MUX"}, + {"CDC_IF TX8 MUX", "DEC8_192", "ADC US MUX8"}, + + {"CDC_IF TX9 MUX", "DEC7", "ADC MUX7"}, + {"CDC_IF TX9 MUX", "DEC7_192", "ADC US MUX7"}, + {"CDC_IF TX10 MUX", "DEC6", "ADC MUX6"}, + {"CDC_IF TX10 MUX", "DEC6_192", "ADC US MUX6"}, + + {"CDC_IF TX11 MUX", "DEC_0_5", "CDC_IF TX11 INP1 MUX"}, + {"CDC_IF TX11 MUX", "DEC_9_12", "CDC_IF TX11 INP1 MUX"}, + {"CDC_IF TX11 INP1 MUX", "DEC0", "ADC MUX0"}, + {"CDC_IF TX11 INP1 MUX", "DEC1", "ADC MUX1"}, + {"CDC_IF TX11 INP1 MUX", "DEC2", "ADC MUX2"}, + {"CDC_IF TX11 INP1 MUX", "DEC3", "ADC MUX3"}, + {"CDC_IF TX11 INP1 MUX", "DEC4", "ADC MUX4"}, + {"CDC_IF TX11 INP1 MUX", "DEC5", "ADC MUX5"}, + {"CDC_IF TX11 INP1 MUX", "RX_MIX_TX5", "RX MIX TX5 MUX"}, + + {"CDC_IF TX13 MUX", "MAD_BRDCST", "MAD_BROADCAST"}, + {"CDC_IF TX13 MUX", "CDC_DEC_5", "CDC_IF TX13 INP1 MUX"}, + {"CDC_IF TX13 INP1 MUX", "DEC5", "ADC MUX5"}, + {"CDC_IF TX13 INP1 MUX", "DEC5_192", "ADC US MUX5"}, + + {"RX MIX TX0 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX0 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + + {"RX MIX TX1 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX1 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + + {"RX MIX TX2 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX2 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + + {"RX MIX TX3 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX3 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX3 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX3 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX3 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX3 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX3 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + + {"RX MIX TX4 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX4 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX4 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX4 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX4 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX4 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX4 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + + {"RX MIX TX5 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX5 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX5 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX5 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX5 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX5 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX5 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + + {"RX MIX TX6 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX6 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX6 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX6 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX6 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX6 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX6 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + + {"RX MIX TX7 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX7 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX7 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX7 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX7 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX7 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX7 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + + {"RX MIX TX8 MUX", "RX_MIX0", "RX INT0 SEC MIX"}, + {"RX MIX TX8 MUX", "RX_MIX1", "RX INT1 SEC MIX"}, + {"RX MIX TX8 MUX", "RX_MIX2", "RX INT2 SEC MIX"}, + {"RX MIX TX8 MUX", "RX_MIX3", "RX INT3 SEC MIX"}, + {"RX MIX TX8 MUX", "RX_MIX4", "RX INT4 SEC MIX"}, + {"RX MIX TX8 MUX", "RX_MIX7", "RX INT7 SEC MIX"}, + {"RX MIX TX8 MUX", "RX_MIX8", "RX INT8 SEC MIX"}, + + {"ADC US MUX0", "US_Switch", "ADC MUX0"}, + {"ADC US MUX1", "US_Switch", "ADC MUX1"}, + {"ADC US MUX2", "US_Switch", "ADC MUX2"}, + {"ADC US MUX3", "US_Switch", "ADC MUX3"}, + {"ADC US MUX4", "US_Switch", "ADC MUX4"}, + {"ADC US MUX5", "US_Switch", "ADC MUX5"}, + {"ADC US MUX6", "US_Switch", "ADC MUX6"}, + {"ADC US MUX7", "US_Switch", "ADC MUX7"}, + {"ADC US MUX8", "US_Switch", "ADC MUX8"}, + + {"ADC MUX0", "DMIC", "DMIC MUX0"}, + {"ADC MUX0", "AMIC", "AMIC MUX0"}, + {"ADC MUX1", "DMIC", "DMIC MUX1"}, + {"ADC MUX1", "AMIC", "AMIC MUX1"}, + {"ADC MUX2", "DMIC", "DMIC MUX2"}, + {"ADC MUX2", "AMIC", "AMIC MUX2"}, + {"ADC MUX3", "DMIC", "DMIC MUX3"}, + {"ADC MUX3", "AMIC", "AMIC MUX3"}, + {"ADC MUX4", "DMIC", "DMIC MUX4"}, + {"ADC MUX4", "AMIC", "AMIC MUX4"}, + {"ADC MUX5", "DMIC", "DMIC MUX5"}, + {"ADC MUX5", "AMIC", "AMIC MUX5"}, + {"ADC MUX6", "DMIC", "DMIC MUX6"}, + {"ADC MUX6", "AMIC", "AMIC MUX6"}, + {"ADC MUX7", "DMIC", "DMIC MUX7"}, + {"ADC MUX7", "AMIC", "AMIC MUX7"}, + {"ADC MUX8", "DMIC", "DMIC MUX8"}, + {"ADC MUX8", "AMIC", "AMIC MUX8"}, + {"ADC MUX10", "DMIC", "DMIC MUX10"}, + {"ADC MUX10", "AMIC", "AMIC MUX10"}, + {"ADC MUX11", "DMIC", "DMIC MUX11"}, + {"ADC MUX11", "AMIC", "AMIC MUX11"}, + {"ADC MUX12", "DMIC", "DMIC MUX12"}, + {"ADC MUX12", "AMIC", "AMIC MUX12"}, + {"ADC MUX13", "DMIC", "DMIC MUX13"}, + {"ADC MUX13", "AMIC", "AMIC MUX13"}, + + {"DMIC MUX0", "DMIC0", "DMIC0"}, + {"DMIC MUX0", "DMIC1", "DMIC1"}, + {"DMIC MUX0", "DMIC2", "DMIC2"}, + {"DMIC MUX0", "DMIC3", "DMIC3"}, + {"DMIC MUX0", "DMIC4", "DMIC4"}, + {"DMIC MUX0", "DMIC5", "DMIC5"}, + {"AMIC MUX0", "ADC1", "ADC1"}, + {"AMIC MUX0", "ADC2", "ADC2"}, + {"AMIC MUX0", "ADC3", "ADC3"}, + {"AMIC MUX0", "ADC4", "ADC4"}, + + {"DMIC MUX1", "DMIC0", "DMIC0"}, + {"DMIC MUX1", "DMIC1", "DMIC1"}, + {"DMIC MUX1", "DMIC2", "DMIC2"}, + {"DMIC MUX1", "DMIC3", "DMIC3"}, + {"DMIC MUX1", "DMIC4", "DMIC4"}, + {"DMIC MUX1", "DMIC5", "DMIC5"}, + {"AMIC MUX1", "ADC1", "ADC1"}, + {"AMIC MUX1", "ADC2", "ADC2"}, + {"AMIC MUX1", "ADC3", "ADC3"}, + {"AMIC MUX1", "ADC4", "ADC4"}, + + {"DMIC MUX2", "DMIC0", "DMIC0"}, + {"DMIC MUX2", "DMIC1", "DMIC1"}, + {"DMIC MUX2", "DMIC2", "DMIC2"}, + {"DMIC MUX2", "DMIC3", "DMIC3"}, + {"DMIC MUX2", "DMIC4", "DMIC4"}, + {"DMIC MUX2", "DMIC5", "DMIC5"}, + {"AMIC MUX2", "ADC1", "ADC1"}, + {"AMIC MUX2", "ADC2", "ADC2"}, + {"AMIC MUX2", "ADC3", "ADC3"}, + {"AMIC MUX2", "ADC4", "ADC4"}, + + {"DMIC MUX3", "DMIC0", "DMIC0"}, + {"DMIC MUX3", "DMIC1", "DMIC1"}, + {"DMIC MUX3", "DMIC2", "DMIC2"}, + {"DMIC MUX3", "DMIC3", "DMIC3"}, + {"DMIC MUX3", "DMIC4", "DMIC4"}, + {"DMIC MUX3", "DMIC5", "DMIC5"}, + {"AMIC MUX3", "ADC1", "ADC1"}, + {"AMIC MUX3", "ADC2", "ADC2"}, + {"AMIC MUX3", "ADC3", "ADC3"}, + {"AMIC MUX3", "ADC4", "ADC4"}, + + {"DMIC MUX4", "DMIC0", "DMIC0"}, + {"DMIC MUX4", "DMIC1", "DMIC1"}, + {"DMIC MUX4", "DMIC2", "DMIC2"}, + {"DMIC MUX4", "DMIC3", "DMIC3"}, + {"DMIC MUX4", "DMIC4", "DMIC4"}, + {"DMIC MUX4", "DMIC5", "DMIC5"}, + {"AMIC MUX4", "ADC1", "ADC1"}, + {"AMIC MUX4", "ADC2", "ADC2"}, + {"AMIC MUX4", "ADC3", "ADC3"}, + {"AMIC MUX4", "ADC4", "ADC4"}, + + {"DMIC MUX5", "DMIC0", "DMIC0"}, + {"DMIC MUX5", "DMIC1", "DMIC1"}, + {"DMIC MUX5", "DMIC2", "DMIC2"}, + {"DMIC MUX5", "DMIC3", "DMIC3"}, + {"DMIC MUX5", "DMIC4", "DMIC4"}, + {"DMIC MUX5", "DMIC5", "DMIC5"}, + {"AMIC MUX5", "ADC1", "ADC1"}, + {"AMIC MUX5", "ADC2", "ADC2"}, + {"AMIC MUX5", "ADC3", "ADC3"}, + {"AMIC MUX5", "ADC4", "ADC4"}, + + {"DMIC MUX6", "DMIC0", "DMIC0"}, + {"DMIC MUX6", "DMIC1", "DMIC1"}, + {"DMIC MUX6", "DMIC2", "DMIC2"}, + {"DMIC MUX6", "DMIC3", "DMIC3"}, + {"DMIC MUX6", "DMIC4", "DMIC4"}, + {"DMIC MUX6", "DMIC5", "DMIC5"}, + {"AMIC MUX6", "ADC1", "ADC1"}, + {"AMIC MUX6", "ADC2", "ADC2"}, + {"AMIC MUX6", "ADC3", "ADC3"}, + {"AMIC MUX6", "ADC4", "ADC4"}, + + {"DMIC MUX7", "DMIC0", "DMIC0"}, + {"DMIC MUX7", "DMIC1", "DMIC1"}, + {"DMIC MUX7", "DMIC2", "DMIC2"}, + {"DMIC MUX7", "DMIC3", "DMIC3"}, + {"DMIC MUX7", "DMIC4", "DMIC4"}, + {"DMIC MUX7", "DMIC5", "DMIC5"}, + {"AMIC MUX7", "ADC1", "ADC1"}, + {"AMIC MUX7", "ADC2", "ADC2"}, + {"AMIC MUX7", "ADC3", "ADC3"}, + {"AMIC MUX7", "ADC4", "ADC4"}, + + {"DMIC MUX8", "DMIC0", "DMIC0"}, + {"DMIC MUX8", "DMIC1", "DMIC1"}, + {"DMIC MUX8", "DMIC2", "DMIC2"}, + {"DMIC MUX8", "DMIC3", "DMIC3"}, + {"DMIC MUX8", "DMIC4", "DMIC4"}, + {"DMIC MUX8", "DMIC5", "DMIC5"}, + {"AMIC MUX8", "ADC1", "ADC1"}, + {"AMIC MUX8", "ADC2", "ADC2"}, + {"AMIC MUX8", "ADC3", "ADC3"}, + {"AMIC MUX8", "ADC4", "ADC4"}, + + {"DMIC MUX10", "DMIC0", "DMIC0"}, + {"DMIC MUX10", "DMIC1", "DMIC1"}, + {"DMIC MUX10", "DMIC2", "DMIC2"}, + {"DMIC MUX10", "DMIC3", "DMIC3"}, + {"DMIC MUX10", "DMIC4", "DMIC4"}, + {"DMIC MUX10", "DMIC5", "DMIC5"}, + {"AMIC MUX10", "ADC1", "ADC1"}, + {"AMIC MUX10", "ADC2", "ADC2"}, + {"AMIC MUX10", "ADC3", "ADC3"}, + {"AMIC MUX10", "ADC4", "ADC4"}, + + {"DMIC MUX11", "DMIC0", "DMIC0"}, + {"DMIC MUX11", "DMIC1", "DMIC1"}, + {"DMIC MUX11", "DMIC2", "DMIC2"}, + {"DMIC MUX11", "DMIC3", "DMIC3"}, + {"DMIC MUX11", "DMIC4", "DMIC4"}, + {"DMIC MUX11", "DMIC5", "DMIC5"}, + {"AMIC MUX11", "ADC1", "ADC1"}, + {"AMIC MUX11", "ADC2", "ADC2"}, + {"AMIC MUX11", "ADC3", "ADC3"}, + {"AMIC MUX11", "ADC4", "ADC4"}, + + {"DMIC MUX12", "DMIC0", "DMIC0"}, + {"DMIC MUX12", "DMIC1", "DMIC1"}, + {"DMIC MUX12", "DMIC2", "DMIC2"}, + {"DMIC MUX12", "DMIC3", "DMIC3"}, + {"DMIC MUX12", "DMIC4", "DMIC4"}, + {"DMIC MUX12", "DMIC5", "DMIC5"}, + {"AMIC MUX12", "ADC1", "ADC1"}, + {"AMIC MUX12", "ADC2", "ADC2"}, + {"AMIC MUX12", "ADC3", "ADC3"}, + {"AMIC MUX12", "ADC4", "ADC4"}, + + {"DMIC MUX13", "DMIC0", "DMIC0"}, + {"DMIC MUX13", "DMIC1", "DMIC1"}, + {"DMIC MUX13", "DMIC2", "DMIC2"}, + {"DMIC MUX13", "DMIC3", "DMIC3"}, + {"DMIC MUX13", "DMIC4", "DMIC4"}, + {"DMIC MUX13", "DMIC5", "DMIC5"}, + {"AMIC MUX13", "ADC1", "ADC1"}, + {"AMIC MUX13", "ADC2", "ADC2"}, + {"AMIC MUX13", "ADC3", "ADC3"}, + {"AMIC MUX13", "ADC4", "ADC4"}, + + {"AMIC4_5 SEL", "AMIC4", "AMIC4"}, + {"AMIC4_5 SEL", "AMIC5", "AMIC5"}, + + {"ADC1", NULL, "AMIC1"}, + {"ADC2", NULL, "AMIC2"}, + {"ADC3", NULL, "AMIC3"}, + {"ADC4", NULL, "AMIC4_5 SEL"}, + + /* CDC Rx interface with SLIMBUS */ + {"CDC_IF RX0 MUX", "SLIM RX0", "SLIM RX0"}, + {"CDC_IF RX1 MUX", "SLIM RX1", "SLIM RX1"}, + {"CDC_IF RX2 MUX", "SLIM RX2", "SLIM RX2"}, + {"CDC_IF RX3 MUX", "SLIM RX3", "SLIM RX3"}, + {"CDC_IF RX4 MUX", "SLIM RX4", "SLIM RX4"}, + {"CDC_IF RX5 MUX", "SLIM RX5", "SLIM RX5"}, + {"CDC_IF RX6 MUX", "SLIM RX6", "SLIM RX6"}, + {"CDC_IF RX7 MUX", "SLIM RX7", "SLIM RX7"}, + + {"RX INT0_1 MIX1 INP0", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT0_1 MIX1 INP0", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT0_1 MIX1 INP0", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT0_1 MIX1 INP0", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT0_1 MIX1 INP0", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT0_1 MIX1 INP0", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT0_1 MIX1 INP0", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT0_1 MIX1 INP0", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT0_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT0_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT0_1 MIX1 INP1", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT0_1 MIX1 INP1", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT0_1 MIX1 INP1", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT0_1 MIX1 INP1", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT0_1 MIX1 INP1", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT0_1 MIX1 INP1", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT0_1 MIX1 INP1", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT0_1 MIX1 INP1", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT0_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT0_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT0_1 MIX1 INP2", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT0_1 MIX1 INP2", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT0_1 MIX1 INP2", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT0_1 MIX1 INP2", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT0_1 MIX1 INP2", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT0_1 MIX1 INP2", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT0_1 MIX1 INP2", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT0_1 MIX1 INP2", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT0_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT0_1 MIX1 INP2", "IIR1", "IIR1"}, + + {"RX INT1_1 MIX1 INP0", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT1_1 MIX1 INP0", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT1_1 MIX1 INP0", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT1_1 MIX1 INP0", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT1_1 MIX1 INP0", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT1_1 MIX1 INP0", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT1_1 MIX1 INP0", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT1_1 MIX1 INP0", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT1_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT1_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT1_1 MIX1 INP1", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT1_1 MIX1 INP1", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT1_1 MIX1 INP1", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT1_1 MIX1 INP1", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT1_1 MIX1 INP1", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT1_1 MIX1 INP1", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT1_1 MIX1 INP1", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT1_1 MIX1 INP1", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT1_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT1_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT1_1 MIX1 INP2", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT1_1 MIX1 INP2", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT1_1 MIX1 INP2", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT1_1 MIX1 INP2", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT1_1 MIX1 INP2", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT1_1 MIX1 INP2", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT1_1 MIX1 INP2", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT1_1 MIX1 INP2", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT1_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT1_1 MIX1 INP2", "IIR1", "IIR1"}, + {"RX INT2_1 MIX1 INP0", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT2_1 MIX1 INP0", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT2_1 MIX1 INP0", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT2_1 MIX1 INP0", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT2_1 MIX1 INP0", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT2_1 MIX1 INP0", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT2_1 MIX1 INP0", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT2_1 MIX1 INP0", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT2_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT2_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT2_1 MIX1 INP1", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT2_1 MIX1 INP1", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT2_1 MIX1 INP1", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT2_1 MIX1 INP1", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT2_1 MIX1 INP1", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT2_1 MIX1 INP1", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT2_1 MIX1 INP1", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT2_1 MIX1 INP1", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT2_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT2_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT2_1 MIX1 INP2", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT2_1 MIX1 INP2", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT2_1 MIX1 INP2", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT2_1 MIX1 INP2", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT2_1 MIX1 INP2", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT2_1 MIX1 INP2", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT2_1 MIX1 INP2", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT2_1 MIX1 INP2", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT2_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT2_1 MIX1 INP2", "IIR1", "IIR1"}, + + {"RX INT3_1 MIX1 INP0", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT3_1 MIX1 INP0", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT3_1 MIX1 INP0", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT3_1 MIX1 INP0", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT3_1 MIX1 INP0", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT3_1 MIX1 INP0", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT3_1 MIX1 INP0", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT3_1 MIX1 INP0", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT3_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT3_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT3_1 MIX1 INP1", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT3_1 MIX1 INP1", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT3_1 MIX1 INP1", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT3_1 MIX1 INP1", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT3_1 MIX1 INP1", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT3_1 MIX1 INP1", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT3_1 MIX1 INP1", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT3_1 MIX1 INP1", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT3_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT3_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT3_1 MIX1 INP2", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT3_1 MIX1 INP2", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT3_1 MIX1 INP2", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT3_1 MIX1 INP2", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT3_1 MIX1 INP2", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT3_1 MIX1 INP2", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT3_1 MIX1 INP2", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT3_1 MIX1 INP2", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT3_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT3_1 MIX1 INP2", "IIR1", "IIR1"}, + + {"RX INT4_1 MIX1 INP0", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT4_1 MIX1 INP0", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT4_1 MIX1 INP0", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT4_1 MIX1 INP0", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT4_1 MIX1 INP0", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT4_1 MIX1 INP0", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT4_1 MIX1 INP0", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT4_1 MIX1 INP0", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT4_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT4_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT4_1 MIX1 INP1", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT4_1 MIX1 INP1", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT4_1 MIX1 INP1", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT4_1 MIX1 INP1", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT4_1 MIX1 INP1", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT4_1 MIX1 INP1", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT4_1 MIX1 INP1", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT4_1 MIX1 INP1", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT4_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT4_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT4_1 MIX1 INP2", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT4_1 MIX1 INP2", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT4_1 MIX1 INP2", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT4_1 MIX1 INP2", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT4_1 MIX1 INP2", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT4_1 MIX1 INP2", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT4_1 MIX1 INP2", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT4_1 MIX1 INP2", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT4_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT4_1 MIX1 INP2", "IIR1", "IIR1"}, + + {"RX INT7_1 MIX1 INP0", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT7_1 MIX1 INP0", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT7_1 MIX1 INP0", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT7_1 MIX1 INP0", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT7_1 MIX1 INP0", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT7_1 MIX1 INP0", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT7_1 MIX1 INP0", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT7_1 MIX1 INP0", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT7_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT7_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT7_1 MIX1 INP1", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT7_1 MIX1 INP1", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT7_1 MIX1 INP1", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT7_1 MIX1 INP1", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT7_1 MIX1 INP1", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT7_1 MIX1 INP1", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT7_1 MIX1 INP1", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT7_1 MIX1 INP1", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT7_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT7_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT7_1 MIX1 INP2", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT7_1 MIX1 INP2", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT7_1 MIX1 INP2", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT7_1 MIX1 INP2", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT7_1 MIX1 INP2", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT7_1 MIX1 INP2", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT7_1 MIX1 INP2", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT7_1 MIX1 INP2", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT7_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT7_1 MIX1 INP2", "IIR1", "IIR1"}, + + {"RX INT8_1 MIX1 INP0", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT8_1 MIX1 INP0", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT8_1 MIX1 INP0", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT8_1 MIX1 INP0", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT8_1 MIX1 INP0", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT8_1 MIX1 INP0", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT8_1 MIX1 INP0", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT8_1 MIX1 INP0", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT8_1 MIX1 INP0", "IIR0", "IIR0"}, + {"RX INT8_1 MIX1 INP0", "IIR1", "IIR1"}, + {"RX INT8_1 MIX1 INP1", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT8_1 MIX1 INP1", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT8_1 MIX1 INP1", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT8_1 MIX1 INP1", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT8_1 MIX1 INP1", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT8_1 MIX1 INP1", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT8_1 MIX1 INP1", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT8_1 MIX1 INP1", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT8_1 MIX1 INP1", "IIR0", "IIR0"}, + {"RX INT8_1 MIX1 INP1", "IIR1", "IIR1"}, + {"RX INT8_1 MIX1 INP2", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT8_1 MIX1 INP2", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT8_1 MIX1 INP2", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT8_1 MIX1 INP2", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT8_1 MIX1 INP2", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT8_1 MIX1 INP2", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT8_1 MIX1 INP2", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT8_1 MIX1 INP2", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT8_1 MIX1 INP2", "IIR0", "IIR0"}, + {"RX INT8_1 MIX1 INP2", "IIR1", "IIR1"}, + + {"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP0"}, + {"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP1"}, + {"RX INT0_1 MIX1", NULL, "RX INT0_1 MIX1 INP2"}, + {"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP0"}, + {"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP1"}, + {"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP2"}, + {"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP0"}, + {"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP1"}, + {"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP2"}, + {"RX INT3_1 MIX1", NULL, "RX INT3_1 MIX1 INP0"}, + {"RX INT3_1 MIX1", NULL, "RX INT3_1 MIX1 INP1"}, + {"RX INT3_1 MIX1", NULL, "RX INT3_1 MIX1 INP2"}, + {"RX INT4_1 MIX1", NULL, "RX INT4_1 MIX1 INP0"}, + {"RX INT4_1 MIX1", NULL, "RX INT4_1 MIX1 INP1"}, + {"RX INT4_1 MIX1", NULL, "RX INT4_1 MIX1 INP2"}, + {"RX INT7_1 MIX1", NULL, "RX INT7_1 MIX1 INP0"}, + {"RX INT7_1 MIX1", NULL, "RX INT7_1 MIX1 INP1"}, + {"RX INT7_1 MIX1", NULL, "RX INT7_1 MIX1 INP2"}, + {"RX INT8_1 MIX1", NULL, "RX INT8_1 MIX1 INP0"}, + {"RX INT8_1 MIX1", NULL, "RX INT8_1 MIX1 INP1"}, + {"RX INT8_1 MIX1", NULL, "RX INT8_1 MIX1 INP2"}, + + /* Mixing path INT0 */ + {"RX INT0_2 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT0_2 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT0_2 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT0_2 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT0_2 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT0_2 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT0_2 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT0_2 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT0 SEC MIX", NULL, "RX INT0_2 MUX"}, + + /* Mixing path INT1 */ + {"RX INT1_2 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT1_2 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT1_2 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT1_2 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT1_2 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT1_2 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT1_2 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT1_2 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT1 SEC MIX", NULL, "RX INT1_2 MUX"}, + + /* Mixing path INT2 */ + {"RX INT2_2 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT2_2 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT2_2 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT2_2 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT2_2 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT2_2 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT2_2 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT2_2 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT2 SEC MIX", NULL, "RX INT2_2 MUX"}, + + /* Mixing path INT3 */ + {"RX INT3_2 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT3_2 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT3_2 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT3_2 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT3_2 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT3_2 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT3_2 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT3_2 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT3 SEC MIX", NULL, "RX INT3_2 MUX"}, + + /* Mixing path INT4 */ + {"RX INT4_2 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT4_2 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT4_2 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT4_2 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT4_2 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT4_2 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT4_2 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT4_2 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT4 SEC MIX", NULL, "RX INT4_2 MUX"}, + + /* Mixing path INT7 */ + {"RX INT7_2 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT7_2 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT7_2 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT7_2 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT7_2 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT7_2 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT7_2 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT7_2 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT7 SEC MIX", NULL, "RX INT7_2 MUX"}, + + /* Mixing path INT8 */ + {"RX INT8_2 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"RX INT8_2 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"RX INT8_2 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"RX INT8_2 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"RX INT8_2 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"RX INT8_2 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"RX INT8_2 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"RX INT8_2 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"RX INT8 SEC MIX", NULL, "RX INT8_2 MUX"}, + + {"RX INT0 SEC MIX", NULL, "RX INT0_1 MIX1"}, + {"RX INT0 MIX2", NULL, "RX INT0 SEC MIX"}, + {"RX INT0 MIX2", NULL, "RX INT0 MIX2 INP"}, + {"RX INT0 INTERP", NULL, "RX INT0 MIX2"}, + {"RX INT0 DEM MUX", "CLSH_DSM_OUT", "RX INT0 INTERP"}, + {"RX INT0 DAC", NULL, "RX INT0 DEM MUX"}, + {"RX INT0 DAC", NULL, "RX_BIAS"}, + {"EAR PA", NULL, "RX INT0 DAC"}, + {"EAR", NULL, "EAR PA"}, + + {"RX INT1 SEC MIX", NULL, "RX INT1_1 MIX1"}, + {"RX INT1 MIX2", NULL, "RX INT1 SEC MIX"}, + {"RX INT1 MIX2", NULL, "RX INT1 MIX2 INP"}, + {"RX INT1 INTERP", NULL, "RX INT1 MIX2"}, + {"RX INT1 DEM MUX", "CLSH_DSM_OUT", "RX INT1 INTERP"}, + {"RX INT1 DAC", NULL, "RX INT1 DEM MUX"}, + {"RX INT1 DAC", NULL, "RX_BIAS"}, + {"HPHL PA", NULL, "RX INT1 DAC"}, + {"HPHL", NULL, "HPHL PA"}, + + {"RX INT2 SEC MIX", NULL, "RX INT2_1 MIX1"}, + {"RX INT2 MIX2", NULL, "RX INT2 SEC MIX"}, + {"RX INT2 MIX2", NULL, "RX INT2 MIX2 INP"}, + {"RX INT2 INTERP", NULL, "RX INT2 MIX2"}, + {"RX INT2 DEM MUX", "CLSH_DSM_OUT", "RX INT2 INTERP"}, + {"RX INT2 DAC", NULL, "RX INT2 DEM MUX"}, + {"RX INT2 DAC", NULL, "RX_BIAS"}, + {"HPHR PA", NULL, "RX INT2 DAC"}, + {"HPHR", NULL, "HPHR PA"}, + + {"RX INT3 SEC MIX", NULL, "RX INT3_1 MIX1"}, + {"RX INT3 MIX2", NULL, "RX INT3 SEC MIX"}, + {"RX INT3 MIX2", NULL, "RX INT3 MIX2 INP"}, + {"RX INT3 INTERP", NULL, "RX INT3 MIX2"}, + {"RX INT3 DAC", NULL, "RX INT3 INTERP"}, + {"RX INT3 DAC", NULL, "RX_BIAS"}, + {"LINEOUT1 PA", NULL, "RX INT3 DAC"}, + {"LINEOUT1", NULL, "LINEOUT1 PA"}, + + {"RX INT4 SEC MIX", NULL, "RX INT4_1 MIX1"}, + {"RX INT4 MIX2", NULL, "RX INT4 SEC MIX"}, + {"RX INT4 MIX2", NULL, "RX INT4 MIX2 INP"}, + {"RX INT4 INTERP", NULL, "RX INT4 MIX2"}, + {"RX INT4 DAC", NULL, "RX INT4 INTERP"}, + {"RX INT4 DAC", NULL, "RX_BIAS"}, + {"LINEOUT2 PA", NULL, "RX INT4 DAC"}, + {"LINEOUT2", NULL, "LINEOUT2 PA"}, + + {"RX INT7 SEC MIX", NULL, "RX INT7_1 MIX1"}, + {"RX INT7 MIX2", NULL, "RX INT7 SEC MIX"}, + {"RX INT7 MIX2", NULL, "RX INT7 MIX2 INP"}, + {"RX INT7 INTERP", NULL, "RX INT7 MIX2"}, + {"RX INT7 CHAIN", NULL, "RX INT7 INTERP"}, + {"RX INT7 CHAIN", NULL, "RX_BIAS"}, + {"SPK1 OUT", NULL, "RX INT7 CHAIN"}, + + {"RX INT8 SEC MIX", NULL, "RX INT8_1 MIX1"}, + {"RX INT8 INTERP", NULL, "RX INT8 SEC MIX"}, + {"RX INT8 CHAIN", NULL, "RX INT8 INTERP"}, + {"RX INT8 CHAIN", NULL, "RX_BIAS"}, + {"SPK2 OUT", NULL, "RX INT8 CHAIN"}, + + /* + * SRC0, SRC1 inputs to Sidetone RX Mixer + * on RX0, RX1, RX2, RX3, RX4 and RX7 chains + */ + {"IIR0", NULL, "IIR0 INP0 MUX"}, + {"IIR0 INP0 MUX", "DEC0", "ADC MUX0"}, + {"IIR0 INP0 MUX", "DEC1", "ADC MUX1"}, + {"IIR0 INP0 MUX", "DEC2", "ADC MUX2"}, + {"IIR0 INP0 MUX", "DEC3", "ADC MUX3"}, + {"IIR0 INP0 MUX", "DEC4", "ADC MUX4"}, + {"IIR0 INP0 MUX", "DEC5", "ADC MUX5"}, + {"IIR0 INP0 MUX", "DEC6", "ADC MUX6"}, + {"IIR0 INP0 MUX", "DEC7", "ADC MUX7"}, + {"IIR0 INP0 MUX", "DEC8", "ADC MUX8"}, + {"IIR0 INP0 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"IIR0 INP0 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"IIR0 INP0 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"IIR0 INP0 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"IIR0 INP0 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"IIR0 INP0 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"IIR0 INP0 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"IIR0 INP0 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"IIR0", NULL, "IIR0 INP1 MUX"}, + {"IIR0 INP1 MUX", "DEC0", "ADC MUX0"}, + {"IIR0 INP1 MUX", "DEC1", "ADC MUX1"}, + {"IIR0 INP1 MUX", "DEC2", "ADC MUX2"}, + {"IIR0 INP1 MUX", "DEC3", "ADC MUX3"}, + {"IIR0 INP1 MUX", "DEC4", "ADC MUX4"}, + {"IIR0 INP1 MUX", "DEC5", "ADC MUX5"}, + {"IIR0 INP1 MUX", "DEC6", "ADC MUX6"}, + {"IIR0 INP1 MUX", "DEC7", "ADC MUX7"}, + {"IIR0 INP1 MUX", "DEC8", "ADC MUX8"}, + {"IIR0 INP1 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"IIR0 INP1 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"IIR0 INP1 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"IIR0 INP1 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"IIR0 INP1 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"IIR0 INP1 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"IIR0 INP1 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"IIR0 INP1 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"IIR0", NULL, "IIR0 INP2 MUX"}, + {"IIR0 INP2 MUX", "DEC0", "ADC MUX0"}, + {"IIR0 INP2 MUX", "DEC1", "ADC MUX1"}, + {"IIR0 INP2 MUX", "DEC2", "ADC MUX2"}, + {"IIR0 INP2 MUX", "DEC3", "ADC MUX3"}, + {"IIR0 INP2 MUX", "DEC4", "ADC MUX4"}, + {"IIR0 INP2 MUX", "DEC5", "ADC MUX5"}, + {"IIR0 INP2 MUX", "DEC6", "ADC MUX6"}, + {"IIR0 INP2 MUX", "DEC7", "ADC MUX7"}, + {"IIR0 INP2 MUX", "DEC8", "ADC MUX8"}, + {"IIR0 INP2 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"IIR0 INP2 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"IIR0 INP2 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"IIR0 INP2 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"IIR0 INP2 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"IIR0 INP2 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"IIR0 INP2 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"IIR0 INP2 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"IIR0", NULL, "IIR0 INP3 MUX"}, + {"IIR0 INP3 MUX", "DEC0", "ADC MUX0"}, + {"IIR0 INP3 MUX", "DEC1", "ADC MUX1"}, + {"IIR0 INP3 MUX", "DEC2", "ADC MUX2"}, + {"IIR0 INP3 MUX", "DEC3", "ADC MUX3"}, + {"IIR0 INP3 MUX", "DEC4", "ADC MUX4"}, + {"IIR0 INP3 MUX", "DEC5", "ADC MUX5"}, + {"IIR0 INP3 MUX", "DEC6", "ADC MUX6"}, + {"IIR0 INP3 MUX", "DEC7", "ADC MUX7"}, + {"IIR0 INP3 MUX", "DEC8", "ADC MUX8"}, + {"IIR0 INP3 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"IIR0 INP3 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"IIR0 INP3 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"IIR0 INP3 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"IIR0 INP3 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"IIR0 INP3 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"IIR0 INP3 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"IIR0 INP3 MUX", "RX7", "CDC_IF RX7 MUX"}, + + {"IIR1", NULL, "IIR1 INP0 MUX"}, + {"IIR1 INP0 MUX", "DEC0", "ADC MUX0"}, + {"IIR1 INP0 MUX", "DEC1", "ADC MUX1"}, + {"IIR1 INP0 MUX", "DEC2", "ADC MUX2"}, + {"IIR1 INP0 MUX", "DEC3", "ADC MUX3"}, + {"IIR1 INP0 MUX", "DEC4", "ADC MUX4"}, + {"IIR1 INP0 MUX", "DEC5", "ADC MUX5"}, + {"IIR1 INP0 MUX", "DEC6", "ADC MUX6"}, + {"IIR1 INP0 MUX", "DEC7", "ADC MUX7"}, + {"IIR1 INP0 MUX", "DEC8", "ADC MUX8"}, + {"IIR1 INP0 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"IIR1 INP0 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"IIR1 INP0 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"IIR1 INP0 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"IIR1 INP0 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"IIR1 INP0 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"IIR1 INP0 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"IIR1 INP0 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"IIR1", NULL, "IIR1 INP1 MUX"}, + {"IIR1 INP1 MUX", "DEC0", "ADC MUX0"}, + {"IIR1 INP1 MUX", "DEC1", "ADC MUX1"}, + {"IIR1 INP1 MUX", "DEC2", "ADC MUX2"}, + {"IIR1 INP1 MUX", "DEC3", "ADC MUX3"}, + {"IIR1 INP1 MUX", "DEC4", "ADC MUX4"}, + {"IIR1 INP1 MUX", "DEC5", "ADC MUX5"}, + {"IIR1 INP1 MUX", "DEC6", "ADC MUX6"}, + {"IIR1 INP1 MUX", "DEC7", "ADC MUX7"}, + {"IIR1 INP1 MUX", "DEC8", "ADC MUX8"}, + {"IIR1 INP1 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"IIR1 INP1 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"IIR1 INP1 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"IIR1 INP1 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"IIR1 INP1 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"IIR1 INP1 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"IIR1 INP1 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"IIR1 INP1 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"IIR1", NULL, "IIR1 INP2 MUX"}, + {"IIR1 INP2 MUX", "DEC0", "ADC MUX0"}, + {"IIR1 INP2 MUX", "DEC1", "ADC MUX1"}, + {"IIR1 INP2 MUX", "DEC2", "ADC MUX2"}, + {"IIR1 INP2 MUX", "DEC3", "ADC MUX3"}, + {"IIR1 INP2 MUX", "DEC4", "ADC MUX4"}, + {"IIR1 INP2 MUX", "DEC5", "ADC MUX5"}, + {"IIR1 INP2 MUX", "DEC6", "ADC MUX6"}, + {"IIR1 INP2 MUX", "DEC7", "ADC MUX7"}, + {"IIR1 INP2 MUX", "DEC8", "ADC MUX8"}, + {"IIR1 INP2 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"IIR1 INP2 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"IIR1 INP2 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"IIR1 INP2 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"IIR1 INP2 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"IIR1 INP2 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"IIR1 INP2 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"IIR1 INP2 MUX", "RX7", "CDC_IF RX7 MUX"}, + {"IIR1", NULL, "IIR1 INP3 MUX"}, + {"IIR1 INP3 MUX", "DEC0", "ADC MUX0"}, + {"IIR1 INP3 MUX", "DEC1", "ADC MUX1"}, + {"IIR1 INP3 MUX", "DEC2", "ADC MUX2"}, + {"IIR1 INP3 MUX", "DEC3", "ADC MUX3"}, + {"IIR1 INP3 MUX", "DEC4", "ADC MUX4"}, + {"IIR1 INP3 MUX", "DEC5", "ADC MUX5"}, + {"IIR1 INP3 MUX", "DEC6", "ADC MUX6"}, + {"IIR1 INP3 MUX", "DEC7", "ADC MUX7"}, + {"IIR1 INP3 MUX", "DEC8", "ADC MUX8"}, + {"IIR1 INP3 MUX", "RX0", "CDC_IF RX0 MUX"}, + {"IIR1 INP3 MUX", "RX1", "CDC_IF RX1 MUX"}, + {"IIR1 INP3 MUX", "RX2", "CDC_IF RX2 MUX"}, + {"IIR1 INP3 MUX", "RX3", "CDC_IF RX3 MUX"}, + {"IIR1 INP3 MUX", "RX4", "CDC_IF RX4 MUX"}, + {"IIR1 INP3 MUX", "RX5", "CDC_IF RX5 MUX"}, + {"IIR1 INP3 MUX", "RX6", "CDC_IF RX6 MUX"}, + {"IIR1 INP3 MUX", "RX7", "CDC_IF RX7 MUX"}, + + {"SRC0", NULL, "IIR0"}, + {"SRC1", NULL, "IIR1"}, + {"RX INT0 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT0 MIX2 INP", "SRC1", "SRC1"}, + {"RX INT1 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT1 MIX2 INP", "SRC1", "SRC1"}, + {"RX INT2 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT2 MIX2 INP", "SRC1", "SRC1"}, + {"RX INT3 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT3 MIX2 INP", "SRC1", "SRC1"}, + {"RX INT4 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT4 MIX2 INP", "SRC1", "SRC1"}, + {"RX INT7 MIX2 INP", "SRC0", "SRC0"}, + {"RX INT7 MIX2 INP", "SRC1", "SRC1"}, +}; + +#endif diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c new file mode 100644 index 000000000000..75387b7c2069 --- /dev/null +++ b/sound/soc/codecs/wcd934x/wcd934x.c @@ -0,0 +1,5809 @@ +/* + * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/firmware.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <linux/printk.h> +#include <linux/ratelimit.h> +#include <linux/debugfs.h> +#include <linux/wait.h> +#include <linux/bitops.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/pm_runtime.h> +#include <linux/kernel.h> +#include <linux/gpio.h> +#include <linux/regmap.h> +#include <linux/mfd/wcd9xxx/core.h> +#include <linux/mfd/wcd9xxx/wcd9xxx-irq.h> +#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h> +#include <linux/mfd/wcd934x/registers.h> +#include <linux/mfd/wcd9xxx/pdata.h> +#include <linux/regulator/consumer.h> +#include <linux/soundwire/swr-wcd.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/tlv.h> +#include <sound/info.h> +#include "wcd934x.h" +#include "wcd934x-routing.h" +#include "../wcd9xxx-common-v2.h" +#include "../wcd9xxx-resmgr-v2.h" + +#define WCD934X_RX_PORT_START_NUMBER 16 + +#define WCD934X_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\ + SNDRV_PCM_RATE_384000) +/* Fractional Rates */ +#define WCD934X_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_176400) + +#define WCD934X_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +#define WCD934X_FORMATS_S16_S24_S32_LE (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +#define WCD934X_FORMATS_S16_LE (SNDRV_PCM_FMTBIT_S16_LE) + +#define STRING(name) #name +#define WCD_DAPM_ENUM(name, reg, offset, text) \ +static SOC_ENUM_SINGLE_DECL(name##_enum, reg, offset, text); \ +static const struct snd_kcontrol_new name##_mux = \ + SOC_DAPM_ENUM(STRING(name), name##_enum) + +#define WCD_DAPM_ENUM_EXT(name, reg, offset, text, getname, putname) \ +static SOC_ENUM_SINGLE_DECL(name##_enum, reg, offset, text); \ +static const struct snd_kcontrol_new name##_mux = \ + SOC_DAPM_ENUM_EXT(STRING(name), name##_enum, getname, putname) + +#define WCD_DAPM_MUX(name, shift, kctl) \ + SND_SOC_DAPM_MUX(name, SND_SOC_NOPM, shift, 0, &kctl##_mux) + +/* + * Timeout in milli seconds and it is the wait time for + * slim channel removal interrupt to receive. + */ +#define WCD934X_SLIM_CLOSE_TIMEOUT 1000 +#define WCD934X_SLIM_IRQ_OVERFLOW (1 << 0) +#define WCD934X_SLIM_IRQ_UNDERFLOW (1 << 1) +#define WCD934X_SLIM_IRQ_PORT_CLOSED (1 << 2) +#define WCD934X_MCLK_CLK_12P288MHZ 12288000 +#define WCD934X_MCLK_CLK_9P6MHZ 9600000 + +#define WCD934X_NUM_INTERPOLATORS 9 +#define WCD934X_NUM_DECIMATORS 9 + +#define BYTE_BIT_MASK(nr) (1 << ((nr) % BITS_PER_BYTE)) + +#define WCD934X_REG_BITS 8 +#define WCD934X_MAX_VALID_ADC_MUX 13 +#define WCD934X_INVALID_ADC_MUX 9 + +#define WCD934X_AMIC_PWR_LEVEL_LP 0 +#define WCD934X_AMIC_PWR_LEVEL_DEFAULT 1 +#define WCD934X_AMIC_PWR_LEVEL_HP 2 +#define WCD934X_AMIC_PWR_LVL_MASK 0x60 +#define WCD934X_AMIC_PWR_LVL_SHIFT 0x5 + +#define WCD934X_DEC_PWR_LVL_MASK 0x06 +#define WCD934X_DEC_PWR_LVL_LP 0x02 +#define WCD934X_DEC_PWR_LVL_HP 0x04 +#define WCD934X_DEC_PWR_LVL_DF 0x00 +#define WCD934X_STRING_LEN 100 + +#define WCD934X_MAX_MICBIAS 4 +#define DAPM_MICBIAS1_STANDALONE "MIC BIAS1 Standalone" +#define DAPM_MICBIAS2_STANDALONE "MIC BIAS2 Standalone" +#define DAPM_MICBIAS3_STANDALONE "MIC BIAS3 Standalone" +#define DAPM_MICBIAS4_STANDALONE "MIC BIAS4 Standalone" + +#define TX_HPF_CUT_OFF_FREQ_MASK 0x60 +#define CF_MIN_3DB_4HZ 0x0 +#define CF_MIN_3DB_75HZ 0x1 +#define CF_MIN_3DB_150HZ 0x2 + +enum { + AUDIO_NOMINAL, + HPH_PA_DELAY, +}; + +enum { + MIC_BIAS_1 = 1, + MIC_BIAS_2, + MIC_BIAS_3, + MIC_BIAS_4 +}; + +enum { + MICB_PULLUP_ENABLE, + MICB_PULLUP_DISABLE, + MICB_ENABLE, + MICB_DISABLE, +}; + +enum { + AIF1_PB = 0, + AIF1_CAP, + AIF2_PB, + AIF2_CAP, + AIF3_PB, + AIF3_CAP, + AIF4_PB, + NUM_CODEC_DAIS, +}; + +enum { + INTn_1_INP_SEL_ZERO = 0, + INTn_1_INP_SEL_DEC0, + INTn_1_INP_SEL_DEC1, + INTn_1_INP_SEL_IIR0, + INTn_1_INP_SEL_IIR1, + INTn_1_INP_SEL_RX0, + INTn_1_INP_SEL_RX1, + INTn_1_INP_SEL_RX2, + INTn_1_INP_SEL_RX3, + INTn_1_INP_SEL_RX4, + INTn_1_INP_SEL_RX5, + INTn_1_INP_SEL_RX6, + INTn_1_INP_SEL_RX7, +}; + +enum { + INTn_2_INP_SEL_ZERO = 0, + INTn_2_INP_SEL_RX0, + INTn_2_INP_SEL_RX1, + INTn_2_INP_SEL_RX2, + INTn_2_INP_SEL_RX3, + INTn_2_INP_SEL_RX4, + INTn_2_INP_SEL_RX5, + INTn_2_INP_SEL_RX6, + INTn_2_INP_SEL_RX7, + INTn_2_INP_SEL_PROXIMITY, +}; + +enum { + INTERP_EAR = 0, + INTERP_HPHL, + INTERP_HPHR, + INTERP_LO1, + INTERP_LO2, + INTERP_LO3_NA, /* LO3 not avalible in Tavil*/ + INTERP_LO4_NA, + INTERP_SPKR1, + INTERP_SPKR2, +}; + +static const struct intr_data wcd934x_intr_table[] = { + {WCD9XXX_IRQ_SLIMBUS, false}, + {WCD934X_IRQ_MBHC_SW_DET, true}, + {WCD934X_IRQ_MBHC_BUTTON_PRESS_DET, true}, + {WCD934X_IRQ_MBHC_BUTTON_RELEASE_DET, true}, + {WCD934X_IRQ_MBHC_ELECT_INS_REM_DET, true}, + {WCD934X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, true}, + {WCD934X_IRQ_FLL_LOCK_LOSS, false}, + {WCD934X_IRQ_HPH_PA_CNPL_COMPLETE, false}, + {WCD934X_IRQ_HPH_PA_CNPR_COMPLETE, false}, + {WCD934X_IRQ_EAR_PA_CNP_COMPLETE, false}, + {WCD934X_IRQ_LINE_PA1_CNP_COMPLETE, false}, + {WCD934X_IRQ_LINE_PA2_CNP_COMPLETE, false}, + {WCD934X_IRQ_SLNQ_ANALOG_ERROR, false}, + {WCD934X_IRQ_RESERVED_3, false}, + {WCD934X_IRQ_HPH_PA_OCPL_FAULT, false}, + {WCD934X_IRQ_HPH_PA_OCPR_FAULT, false}, + {WCD934X_IRQ_EAR_PA_OCP_FAULT, false}, + {WCD934X_IRQ_SOUNDWIRE, false}, + {WCD934X_IRQ_VDD_DIG_RAMP_COMPLETE, false}, + {WCD934X_IRQ_RCO_ERROR, false}, + {WCD934X_IRQ_CPE_ERROR, false}, + {WCD934X_IRQ_MAD_AUDIO, false}, + {WCD934X_IRQ_MAD_BEACON, false}, + {WCD934X_IRQ_CPE1_INTR, true}, + {WCD934X_IRQ_RESERVED_4, false}, + {WCD934X_IRQ_MAD_ULTRASOUND, false}, + {WCD934X_IRQ_VBAT_ATTACK, false}, + {WCD934X_IRQ_VBAT_RESTORE, false}, +}; + +struct interp_sample_rate { + int sample_rate; + int rate_val; +}; + +static struct interp_sample_rate sr_val_tbl[] = { + {8000, 0x0}, {16000, 0x1}, {32000, 0x3}, {48000, 0x4}, {96000, 0x5}, + {192000, 0x6}, {384000, 0x7}, {44100, 0x9}, {88200, 0xA}, + {176400, 0xB}, {352800, 0xC}, +}; + +static const struct wcd9xxx_ch tavil_rx_chs[WCD934X_RX_MAX] = { + WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER, 0), + WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER + 1, 1), + WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER + 2, 2), + WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER + 3, 3), + WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER + 4, 4), + WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER + 5, 5), + WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER + 6, 6), + WCD9XXX_CH(WCD934X_RX_PORT_START_NUMBER + 7, 7), +}; + +static const struct wcd9xxx_ch tavil_tx_chs[WCD934X_TX_MAX] = { + WCD9XXX_CH(0, 0), + WCD9XXX_CH(1, 1), + WCD9XXX_CH(2, 2), + WCD9XXX_CH(3, 3), + WCD9XXX_CH(4, 4), + WCD9XXX_CH(5, 5), + WCD9XXX_CH(6, 6), + WCD9XXX_CH(7, 7), + WCD9XXX_CH(8, 8), + WCD9XXX_CH(9, 9), + WCD9XXX_CH(10, 10), + WCD9XXX_CH(11, 11), + WCD9XXX_CH(12, 12), + WCD9XXX_CH(13, 13), + WCD9XXX_CH(14, 14), + WCD9XXX_CH(15, 15), +}; + +static const u32 vport_slim_check_table[NUM_CODEC_DAIS] = { + 0, /* AIF1_PB */ + BIT(AIF2_CAP) | BIT(AIF3_CAP), /* AIF1_CAP */ + 0, /* AIF2_PB */ + BIT(AIF1_CAP) | BIT(AIF3_CAP), /* AIF2_CAP */ + 0, /* AIF3_PB */ + BIT(AIF1_CAP) | BIT(AIF2_CAP), /* AIF3_CAP */ + 0, /* AIF4_PB */ +}; + +/* Codec supports 2 IIR filters */ +enum { + IIR0 = 0, + IIR1, + IIR_MAX, +}; + +/* Each IIR has 5 Filter Stages */ +enum { + BAND1 = 0, + BAND2, + BAND3, + BAND4, + BAND5, + BAND_MAX, +}; + +enum { + COMPANDER_1, /* HPH_L */ + COMPANDER_2, /* HPH_R */ + COMPANDER_3, /* LO1_DIFF */ + COMPANDER_4, /* LO2_DIFF */ + COMPANDER_5, /* LO3_SE - not used in Tavil */ + COMPANDER_6, /* LO4_SE - not used in Tavil */ + COMPANDER_7, /* SWR SPK CH1 */ + COMPANDER_8, /* SWR SPK CH2 */ + COMPANDER_MAX, +}; + +static struct afe_param_slimbus_slave_port_cfg tavil_slimbus_slave_port_cfg = { + .minor_version = 1, + .slimbus_dev_id = AFE_SLIMBUS_DEVICE_1, + .slave_dev_pgd_la = 0, + .slave_dev_intfdev_la = 0, + .bit_width = 16, + .data_format = 0, + .num_channels = 1 +}; + +static struct afe_param_cdc_reg_page_cfg tavil_cdc_reg_page_cfg = { + .minor_version = AFE_API_VERSION_CDC_REG_PAGE_CFG, + .enable = 1, + .proc_id = AFE_CDC_REG_PAGE_ASSIGN_PROC_ID_1, +}; + +static struct afe_param_cdc_reg_cfg audio_reg_cfg[] = { + { + 1, + (WCD934X_REGISTER_START_OFFSET + WCD934X_SOC_MAD_MAIN_CTL_1), + HW_MAD_AUDIO_ENABLE, 0x1, WCD934X_REG_BITS, 0 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + WCD934X_SOC_MAD_AUDIO_CTL_3), + HW_MAD_AUDIO_SLEEP_TIME, 0xF, WCD934X_REG_BITS, 0 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + WCD934X_SOC_MAD_AUDIO_CTL_4), + HW_MAD_TX_AUDIO_SWITCH_OFF, 0x1, WCD934X_REG_BITS, 0 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + WCD934X_INTR_CFG), + MAD_AUDIO_INT_DEST_SELECT_REG, 0x2, WCD934X_REG_BITS, 0 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + WCD934X_INTR_PIN2_MASK3), + MAD_AUDIO_INT_MASK_REG, 0x1, WCD934X_REG_BITS, 0 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + WCD934X_INTR_PIN2_STATUS3), + MAD_AUDIO_INT_STATUS_REG, 0x1, WCD934X_REG_BITS, 0 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + WCD934X_INTR_PIN2_CLEAR3), + MAD_AUDIO_INT_CLEAR_REG, 0x1, WCD934X_REG_BITS, 0 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + WCD934X_SB_PGD_PORT_TX_BASE), + SB_PGD_PORT_TX_WATERMARK_N, 0x1E, WCD934X_REG_BITS, 0x1 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + WCD934X_SB_PGD_PORT_TX_BASE), + SB_PGD_PORT_TX_ENABLE_N, 0x1, WCD934X_REG_BITS, 0x1 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + WCD934X_SB_PGD_PORT_RX_BASE), + SB_PGD_PORT_RX_WATERMARK_N, 0x1E, WCD934X_REG_BITS, 0x1 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + WCD934X_SB_PGD_PORT_RX_BASE), + SB_PGD_PORT_RX_ENABLE_N, 0x1, WCD934X_REG_BITS, 0x1 + }, +}; + +static struct afe_param_cdc_reg_cfg_data tavil_audio_reg_cfg = { + .num_registers = ARRAY_SIZE(audio_reg_cfg), + .reg_data = audio_reg_cfg, +}; + +static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); +static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); +static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); + +#define WCD934X_TX_UNMUTE_DELAY_MS 25 + +static int tx_unmute_delay = WCD934X_TX_UNMUTE_DELAY_MS; +module_param(tx_unmute_delay, int, + S_IRUGO | S_IWUSR | S_IWGRP); +MODULE_PARM_DESC(tx_unmute_delay, "delay to unmute the tx path"); + + +/* Hold instance to soundwire platform device */ +struct tavil_swr_ctrl_data { + struct platform_device *swr_pdev; +}; + +struct wcd_swr_ctrl_platform_data { + void *handle; /* holds codec private data */ + int (*read)(void *handle, int reg); + int (*write)(void *handle, int reg, int val); + int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len); + int (*clk)(void *handle, bool enable); + int (*handle_irq)(void *handle, + irqreturn_t (*swrm_irq_handler)(int irq, void *data), + void *swrm_handle, int action); +}; + +/* Holds all Soundwire and speaker related information */ +struct wcd934x_swr { + struct tavil_swr_ctrl_data *ctrl_data; + struct wcd_swr_ctrl_platform_data plat_data; + struct mutex read_mutex; + struct mutex write_mutex; + struct mutex clk_mutex; + int spkr_gain_offset; + int spkr_mode; + int clk_users; + int rx_7_count; + int rx_8_count; +}; + +struct tx_mute_work { + struct tavil_priv *tavil; + u8 decimator; + struct delayed_work dwork; +}; + +struct hpf_work { + struct tavil_priv *tavil; + u8 decimator; + u8 hpf_cut_off_freq; + struct delayed_work dwork; +}; + +struct tavil_priv { + struct device *dev; + struct wcd9xxx *wcd9xxx; + struct snd_soc_codec *codec; + u32 rx_bias_count; + s32 dmic_0_1_clk_cnt; + s32 dmic_2_3_clk_cnt; + s32 dmic_4_5_clk_cnt; + + /* compander */ + int comp_enabled[COMPANDER_MAX]; + /* class h specific data */ + struct wcd_clsh_cdc_data clsh_d; + /* Tavil Interpolator Mode Select for EAR, HPH_L and HPH_R */ + u32 hph_mode; + + u16 prim_int_users[WCD934X_NUM_INTERPOLATORS]; + /* to track the status */ + unsigned long status_mask; + + struct afe_param_cdc_slimbus_slave_cfg slimbus_slave_cfg; + + /* num of slim ports required */ + struct wcd9xxx_codec_dai_data dai[NUM_CODEC_DAIS]; + /* Port values for Rx and Tx codec_dai */ + unsigned int rx_port_value; + unsigned int tx_port_value; + + struct wcd9xxx_resmgr_v2 *resmgr; + struct wcd934x_swr swr; + + struct clk *wcd_ext_clk; + + struct mutex codec_mutex; + struct work_struct tavil_add_child_devices_work; + struct hpf_work tx_hpf_work[WCD934X_NUM_DECIMATORS]; + struct tx_mute_work tx_mute_dwork[WCD934X_NUM_DECIMATORS]; +}; + +static const struct tavil_reg_mask_val tavil_spkr_default[] = { + {WCD934X_CDC_COMPANDER7_CTL3, 0x80, 0x80}, + {WCD934X_CDC_COMPANDER8_CTL3, 0x80, 0x80}, + {WCD934X_CDC_COMPANDER7_CTL7, 0x01, 0x01}, + {WCD934X_CDC_COMPANDER8_CTL7, 0x01, 0x01}, + {WCD934X_CDC_BOOST0_BOOST_CTL, 0x7C, 0x50}, + {WCD934X_CDC_BOOST1_BOOST_CTL, 0x7C, 0x50}, +}; + +static const struct tavil_reg_mask_val tavil_spkr_mode1[] = { + {WCD934X_CDC_COMPANDER7_CTL3, 0x80, 0x00}, + {WCD934X_CDC_COMPANDER8_CTL3, 0x80, 0x00}, + {WCD934X_CDC_COMPANDER7_CTL7, 0x01, 0x00}, + {WCD934X_CDC_COMPANDER8_CTL7, 0x01, 0x00}, + {WCD934X_CDC_BOOST0_BOOST_CTL, 0x7C, 0x44}, + {WCD934X_CDC_BOOST1_BOOST_CTL, 0x7C, 0x44}, +}; + +/* + * wcd934x_get_codec_info: Get codec specific information + * + * @wcd9xxx: pointer to wcd9xxx structure + * @wcd_type: pointer to wcd9xxx_codec_type structure + * + * Returns 0 for success or negative error code for failure + */ +int wcd934x_get_codec_info(struct wcd9xxx *wcd9xxx, + struct wcd9xxx_codec_type *wcd_type) +{ + u16 id_minor, id_major; + struct regmap *wcd_regmap; + int rc, version = 0; + + if (!wcd9xxx || !wcd_type) + return -EINVAL; + + if (!wcd9xxx->regmap) { + dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null\n", __func__); + return -EINVAL; + } + wcd_regmap = wcd9xxx->regmap; + + rc = regmap_bulk_read(wcd_regmap, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0, + (u8 *)&id_minor, sizeof(u16)); + if (rc) + return -EINVAL; + + rc = regmap_bulk_read(wcd_regmap, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE2, + (u8 *)&id_major, sizeof(u16)); + if (rc) + return -EINVAL; + + dev_info(wcd9xxx->dev, "%s: wcd9xxx chip id major 0x%x, minor 0x%x\n", + __func__, id_major, id_minor); + + /* Version detection */ + version = 1.0; + + /* Fill codec type info */ + wcd_type->id_major = id_major; + wcd_type->id_minor = id_minor; + wcd_type->num_irqs = WCD934X_NUM_IRQS; + wcd_type->version = version; + wcd_type->slim_slave_type = WCD9XXX_SLIM_SLAVE_ADDR_TYPE_1; + wcd_type->i2c_chip_status = 0x01; + wcd_type->intr_tbl = wcd934x_intr_table; + wcd_type->intr_tbl_size = ARRAY_SIZE(wcd934x_intr_table); + + wcd_type->intr_reg[WCD9XXX_INTR_STATUS_BASE] = + WCD934X_INTR_PIN1_STATUS0; + wcd_type->intr_reg[WCD9XXX_INTR_CLEAR_BASE] = + WCD934X_INTR_PIN1_CLEAR0; + wcd_type->intr_reg[WCD9XXX_INTR_MASK_BASE] = + WCD934X_INTR_PIN1_MASK0; + wcd_type->intr_reg[WCD9XXX_INTR_LEVEL_BASE] = + WCD934X_INTR_LEVEL0; + wcd_type->intr_reg[WCD9XXX_INTR_CLR_COMMIT] = + WCD934X_INTR_CLR_COMMIT; + + return rc; +} +EXPORT_SYMBOL(wcd934x_get_codec_info); + +/* + * wcd934x_bringdown: Bringdown WCD Codec + * + * @wcd9xxx: Pointer to wcd9xxx structure + * + * Returns 0 for success or negative error code for failure + */ +int wcd934x_bringdown(struct wcd9xxx *wcd9xxx) +{ + if (!wcd9xxx || !wcd9xxx->regmap) + return -EINVAL; + + regmap_write(wcd9xxx->regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, + 0x04); + + return 0; +} +EXPORT_SYMBOL(wcd934x_bringdown); + +/* + * wcd934x_bringup: Bringup WCD Codec + * + * @wcd9xxx: Pointer to the wcd9xxx structure + * + * Returns 0 for success or negative error code for failure + */ +int wcd934x_bringup(struct wcd9xxx *wcd9xxx) +{ + struct regmap *wcd_regmap; + + if (!wcd9xxx) + return -EINVAL; + + if (!wcd9xxx->regmap) { + dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null!\n", + __func__); + return -EINVAL; + } + wcd_regmap = wcd9xxx->regmap; + + regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x01); + regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_A_STARTUP, 0x19); + regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_D_STARTUP, 0x15); + regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5); + regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7); + regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3); + regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x3); + + return 0; +} +EXPORT_SYMBOL(wcd934x_bringup); + +/** + * tavil_set_spkr_gain_offset - offset the speaker path + * gain with the given offset value. + * + * @codec: codec instance + * @offset: Indicates speaker path gain offset value. + * + * Returns 0 on success or -EINVAL on error. + */ +int tavil_set_spkr_gain_offset(struct snd_soc_codec *codec, int offset) +{ + struct tavil_priv *priv = snd_soc_codec_get_drvdata(codec); + + if (!priv) + return -EINVAL; + + priv->swr.spkr_gain_offset = offset; + return 0; +} +EXPORT_SYMBOL(tavil_set_spkr_gain_offset); + +/** + * tavil_set_spkr_mode - Configures speaker compander and smartboost + * settings based on speaker mode. + * + * @codec: codec instance + * @mode: Indicates speaker configuration mode. + * + * Returns 0 on success or -EINVAL on error. + */ +int tavil_set_spkr_mode(struct snd_soc_codec *codec, int mode) +{ + struct tavil_priv *priv = snd_soc_codec_get_drvdata(codec); + int i; + const struct tavil_reg_mask_val *regs; + int size; + + if (!priv) + return -EINVAL; + + switch (mode) { + case WCD934X_SPKR_MODE_1: + regs = tavil_spkr_mode1; + size = ARRAY_SIZE(tavil_spkr_mode1); + break; + default: + regs = tavil_spkr_default; + size = ARRAY_SIZE(tavil_spkr_default); + break; + } + + priv->swr.spkr_mode = mode; + for (i = 0; i < size; i++) + snd_soc_update_bits(codec, regs[i].reg, + regs[i].mask, regs[i].val); + return 0; +} +EXPORT_SYMBOL(tavil_set_spkr_mode); + +/** + * tavil_get_afe_config - returns specific codec configuration to afe to write + * + * @codec: codec instance + * @config_type: Indicates type of configuration to write. + */ +void *tavil_get_afe_config(struct snd_soc_codec *codec, + enum afe_config_type config_type) +{ + struct tavil_priv *priv = snd_soc_codec_get_drvdata(codec); + + switch (config_type) { + case AFE_SLIMBUS_SLAVE_CONFIG: + return &priv->slimbus_slave_cfg; + case AFE_CDC_REGISTERS_CONFIG: + return &tavil_audio_reg_cfg; + case AFE_SLIMBUS_SLAVE_PORT_CONFIG: + return &tavil_slimbus_slave_port_cfg; + case AFE_AANC_VERSION: + return NULL; + case AFE_CDC_REGISTER_PAGE_CONFIG: + return &tavil_cdc_reg_page_cfg; + default: + dev_info(codec->dev, "%s: Unknown config_type 0x%x\n", + __func__, config_type); + return NULL; + } +} +EXPORT_SYMBOL(tavil_get_afe_config); + +static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget_list *wlist = + dapm_kcontrol_get_wlist(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm); + struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = tavil_p->tx_port_value; + return 0; +} + +static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget_list *wlist = + dapm_kcontrol_get_wlist(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm); + struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec); + struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent); + struct snd_soc_dapm_update *update = NULL; + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 dai_id = widget->shift; + u32 port_id = mixer->shift; + u32 enable = ucontrol->value.integer.value[0]; + u32 vtable; + + dev_dbg(codec->dev, "%s: wname %s cname %s value %u shift %d item %ld\n", + __func__, + widget->name, ucontrol->id.name, tavil_p->tx_port_value, + widget->shift, ucontrol->value.integer.value[0]); + + mutex_lock(&tavil_p->codec_mutex); + if (dai_id >= ARRAY_SIZE(vport_slim_check_table)) { + dev_err(codec->dev, "%s: dai_id: %d, out of bounds\n", + __func__, dai_id); + mutex_unlock(&tavil_p->codec_mutex); + return -EINVAL; + } + vtable = vport_slim_check_table[dai_id]; + + switch (dai_id) { + case AIF1_CAP: + case AIF2_CAP: + case AIF3_CAP: + /* only add to the list if value not set */ + if (enable && !(tavil_p->tx_port_value & 1 << port_id)) { + if (wcd9xxx_tx_vport_validation(vtable, port_id, + tavil_p->dai, NUM_CODEC_DAIS)) { + dev_dbg(codec->dev, "%s: TX%u is used by other virtual port\n", + __func__, port_id); + mutex_unlock(&tavil_p->codec_mutex); + return 0; + } + tavil_p->tx_port_value |= 1 << port_id; + list_add_tail(&core->tx_chs[port_id].list, + &tavil_p->dai[dai_id].wcd9xxx_ch_list); + } else if (!enable && (tavil_p->tx_port_value & + 1 << port_id)) { + tavil_p->tx_port_value &= ~(1 << port_id); + list_del_init(&core->tx_chs[port_id].list); + } else { + if (enable) + dev_dbg(codec->dev, "%s: TX%u port is used by\n" + "this virtual port\n", + __func__, port_id); + else + dev_dbg(codec->dev, "%s: TX%u port is not used by\n" + "this virtual port\n", + __func__, port_id); + /* avoid update power function */ + mutex_unlock(&tavil_p->codec_mutex); + return 0; + } + break; + default: + dev_err(codec->dev, "Unknown AIF %d\n", dai_id); + mutex_unlock(&tavil_p->codec_mutex); + return -EINVAL; + } + dev_dbg(codec->dev, "%s: name %s sname %s updated value %u shift %d\n", + __func__, widget->name, widget->sname, tavil_p->tx_port_value, + widget->shift); + + mutex_unlock(&tavil_p->codec_mutex); + snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, update); + + return 0; +} + +static int slim_rx_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget_list *wlist = + dapm_kcontrol_get_wlist(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm); + struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.enumerated.item[0] = tavil_p->rx_port_value; + return 0; +} + +static int slim_rx_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget_list *wlist = + dapm_kcontrol_get_wlist(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm); + struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec); + struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + struct snd_soc_dapm_update *update = NULL; + u32 port_id = widget->shift; + + mutex_lock(&tavil_p->codec_mutex); + tavil_p->rx_port_value = ucontrol->value.enumerated.item[0]; + dev_dbg(codec->dev, "%s: wname %s cname %s value %u shift %d item %ld\n", + __func__, widget->name, ucontrol->id.name, + tavil_p->rx_port_value, widget->shift, + ucontrol->value.integer.value[0]); + + /* value need to match the Virtual port and AIF number */ + switch (tavil_p->rx_port_value) { + case 0: + list_del_init(&core->rx_chs[port_id].list); + break; + case 1: + if (wcd9xxx_rx_vport_validation(port_id + + WCD934X_RX_PORT_START_NUMBER, + &tavil_p->dai[AIF1_PB].wcd9xxx_ch_list)) { + dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n", + __func__, port_id); + goto rtn; + } + list_add_tail(&core->rx_chs[port_id].list, + &tavil_p->dai[AIF1_PB].wcd9xxx_ch_list); + break; + case 2: + if (wcd9xxx_rx_vport_validation(port_id + + WCD934X_RX_PORT_START_NUMBER, + &tavil_p->dai[AIF2_PB].wcd9xxx_ch_list)) { + dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n", + __func__, port_id); + goto rtn; + } + list_add_tail(&core->rx_chs[port_id].list, + &tavil_p->dai[AIF2_PB].wcd9xxx_ch_list); + break; + case 3: + if (wcd9xxx_rx_vport_validation(port_id + + WCD934X_RX_PORT_START_NUMBER, + &tavil_p->dai[AIF3_PB].wcd9xxx_ch_list)) { + dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n", + __func__, port_id); + goto rtn; + } + list_add_tail(&core->rx_chs[port_id].list, + &tavil_p->dai[AIF3_PB].wcd9xxx_ch_list); + break; + case 4: + if (wcd9xxx_rx_vport_validation(port_id + + WCD934X_RX_PORT_START_NUMBER, + &tavil_p->dai[AIF4_PB].wcd9xxx_ch_list)) { + dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n", + __func__, port_id); + goto rtn; + } + list_add_tail(&core->rx_chs[port_id].list, + &tavil_p->dai[AIF4_PB].wcd9xxx_ch_list); + break; + default: + dev_err(codec->dev, "Unknown AIF %d\n", tavil_p->rx_port_value); + goto err; + } +rtn: + mutex_unlock(&tavil_p->codec_mutex); + snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, + tavil_p->rx_port_value, e, update); + + return 0; +err: + mutex_unlock(&tavil_p->codec_mutex); + return -EINVAL; +} + +static void tavil_codec_enable_slim_port_intr( + struct wcd9xxx_codec_dai_data *dai, + struct snd_soc_codec *codec) +{ + struct wcd9xxx_ch *ch; + int port_num = 0; + unsigned short reg = 0; + u8 val = 0; + struct tavil_priv *tavil_p; + + if (!dai || !codec) { + pr_err("%s: Invalid params\n", __func__); + return; + } + + tavil_p = snd_soc_codec_get_drvdata(codec); + list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) { + if (ch->port >= WCD934X_RX_PORT_START_NUMBER) { + port_num = ch->port - WCD934X_RX_PORT_START_NUMBER; + reg = WCD934X_SLIM_PGD_PORT_INT_RX_EN0 + (port_num / 8); + val = wcd9xxx_interface_reg_read(tavil_p->wcd9xxx, + reg); + if (!(val & BYTE_BIT_MASK(port_num))) { + val |= BYTE_BIT_MASK(port_num); + wcd9xxx_interface_reg_write( + tavil_p->wcd9xxx, reg, val); + val = wcd9xxx_interface_reg_read( + tavil_p->wcd9xxx, reg); + } + } else { + port_num = ch->port; + reg = WCD934X_SLIM_PGD_PORT_INT_TX_EN0 + (port_num / 8); + val = wcd9xxx_interface_reg_read(tavil_p->wcd9xxx, + reg); + if (!(val & BYTE_BIT_MASK(port_num))) { + val |= BYTE_BIT_MASK(port_num); + wcd9xxx_interface_reg_write(tavil_p->wcd9xxx, + reg, val); + val = wcd9xxx_interface_reg_read( + tavil_p->wcd9xxx, reg); + } + } + } +} + +static int tavil_codec_enable_slim_chmask(struct wcd9xxx_codec_dai_data *dai, + bool up) +{ + int ret = 0; + struct wcd9xxx_ch *ch; + + if (up) { + list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) { + ret = wcd9xxx_get_slave_port(ch->ch_num); + if (ret < 0) { + pr_err("%s: Invalid slave port ID: %d\n", + __func__, ret); + ret = -EINVAL; + } else { + set_bit(ret, &dai->ch_mask); + } + } + } else { + ret = wait_event_timeout(dai->dai_wait, (dai->ch_mask == 0), + msecs_to_jiffies( + WCD934X_SLIM_CLOSE_TIMEOUT)); + if (!ret) { + pr_err("%s: Slim close tx/rx wait timeout, ch_mask:0x%lx\n", + __func__, dai->ch_mask); + ret = -ETIMEDOUT; + } else { + ret = 0; + } + } + return ret; +} + +static int tavil_codec_enable_slimrx(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct wcd9xxx *core; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec); + int ret = 0; + struct wcd9xxx_codec_dai_data *dai; + + core = dev_get_drvdata(codec->dev->parent); + + dev_dbg(codec->dev, "%s: event called! codec name %s num_dai %d\n" + "stream name %s event %d\n", + __func__, codec->component.name, + codec->component.num_dai, w->sname, event); + + dai = &tavil_p->dai[w->shift]; + dev_dbg(codec->dev, "%s: w->name %s w->shift %d event %d\n", + __func__, w->name, w->shift, event); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + dai->bus_down_in_recovery = false; + tavil_codec_enable_slim_port_intr(dai, codec); + (void) tavil_codec_enable_slim_chmask(dai, true); + ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list, + dai->rate, dai->bit_width, + &dai->grph); + break; + case SND_SOC_DAPM_POST_PMD: + ret = wcd9xxx_disconnect_port(core, &dai->wcd9xxx_ch_list, + dai->grph); + dev_dbg(codec->dev, "%s: Disconnect RX port, ret = %d\n", + __func__, ret); + + if (!dai->bus_down_in_recovery) + ret = tavil_codec_enable_slim_chmask(dai, false); + else + dev_dbg(codec->dev, + "%s: bus in recovery skip enable slim_chmask", + __func__); + ret = wcd9xxx_close_slim_sch_rx(core, &dai->wcd9xxx_ch_list, + dai->grph); + break; + } + return ret; +} + +static int tavil_codec_enable_slimtx(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec); + struct wcd9xxx_codec_dai_data *dai; + struct wcd9xxx *core; + int ret = 0; + + dev_dbg(codec->dev, + "%s: w->name %s, w->shift = %d, num_dai %d stream name %s\n", + __func__, w->name, w->shift, + codec->component.num_dai, w->sname); + + dai = &tavil_p->dai[w->shift]; + core = dev_get_drvdata(codec->dev->parent); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + dai->bus_down_in_recovery = false; + tavil_codec_enable_slim_port_intr(dai, codec); + (void) tavil_codec_enable_slim_chmask(dai, true); + ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list, + dai->rate, dai->bit_width, + &dai->grph); + break; + case SND_SOC_DAPM_POST_PMD: + ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list, + dai->grph); + if (!dai->bus_down_in_recovery) + ret = tavil_codec_enable_slim_chmask(dai, false); + if (ret < 0) { + ret = wcd9xxx_disconnect_port(core, + &dai->wcd9xxx_ch_list, + dai->grph); + dev_dbg(codec->dev, "%s: Disconnect RX port, ret = %d\n", + __func__, ret); + } + break; + } + return ret; +} + +static int tavil_codec_enable_rx_bias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + tavil->rx_bias_count++; + if (tavil->rx_bias_count == 1) { + snd_soc_update_bits(codec, WCD934X_ANA_RX_SUPPLIES, + 0x01, 0x01); + } + break; + case SND_SOC_DAPM_POST_PMD: + tavil->rx_bias_count--; + if (!tavil->rx_bias_count) + snd_soc_update_bits(codec, WCD934X_ANA_RX_SUPPLIES, + 0x01, 0x00); + break; + }; + dev_dbg(codec->dev, "%s: Current RX BIAS user count: %d\n", __func__, + tavil->rx_bias_count); + + return 0; +} + +static int tavil_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* + * 5ms sleep is required after PA is enabled as per + * HW requirement + */ + usleep_range(5000, 5500); + snd_soc_update_bits(codec, WCD934X_CDC_RX0_RX_PATH_CTL, + 0x10, 0x00); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_read(codec, WCD934X_CDC_RX0_RX_PATH_MIX_CTL)) & + 0x10) + snd_soc_update_bits(codec, + WCD934X_CDC_RX0_RX_PATH_MIX_CTL, + 0x10, 0x00); + break; + default: + break; + }; + + return 0; +} + +static int tavil_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + set_bit(HPH_PA_DELAY, &tavil->status_mask); + break; + case SND_SOC_DAPM_POST_PMU: + /* + * 7ms sleep is required after PA is enabled as per + * HW requirement + */ + if (test_bit(HPH_PA_DELAY, &tavil->status_mask)) { + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &tavil->status_mask); + } + /* Remove mute */ + snd_soc_update_bits(codec, WCD934X_CDC_RX2_RX_PATH_CTL, + 0x10, 0x00); + /* Enable AutoChop timer at the end of power up */ + snd_soc_update_bits(codec, WCD934X_HPH_NEW_INT_HPH_TIMER1, + 0x02, 0x02); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_read(codec, WCD934X_CDC_RX2_RX_PATH_MIX_CTL)) & + 0x10) + snd_soc_update_bits(codec, + WCD934X_CDC_RX2_RX_PATH_MIX_CTL, + 0x10, 0x00); + break; + default: + break; + }; + + return 0; +} + +static int tavil_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + set_bit(HPH_PA_DELAY, &tavil->status_mask); + break; + case SND_SOC_DAPM_POST_PMU: + /* + * 7ms sleep is required after PA is enabled as per + * HW requirement + */ + if (test_bit(HPH_PA_DELAY, &tavil->status_mask)) { + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &tavil->status_mask); + } + /* Remove Mute on primary path */ + snd_soc_update_bits(codec, WCD934X_CDC_RX1_RX_PATH_CTL, + 0x10, 0x00); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_read(codec, WCD934X_CDC_RX1_RX_PATH_MIX_CTL)) & + 0x10) + snd_soc_update_bits(codec, + WCD934X_CDC_RX1_RX_PATH_MIX_CTL, + 0x10, 0x00); + break; + default: + break; + }; + + return 0; +} + +static int tavil_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + u16 lineout_vol_reg = 0, lineout_mix_vol_reg = 0; + + dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event); + + if (w->reg == WCD934X_ANA_LO_1_2) { + if (w->shift == 7) { + lineout_vol_reg = WCD934X_CDC_RX3_RX_PATH_CTL; + lineout_mix_vol_reg = WCD934X_CDC_RX3_RX_PATH_MIX_CTL; + } else if (w->shift == 6) { + lineout_vol_reg = WCD934X_CDC_RX4_RX_PATH_CTL; + lineout_mix_vol_reg = WCD934X_CDC_RX4_RX_PATH_MIX_CTL; + } + } else { + dev_err(codec->dev, "%s: Error enabling lineout PA\n", + __func__); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* + * 5ms sleep is required after PA is enabled as per + * HW requirement + */ + usleep_range(5000, 5500); + snd_soc_update_bits(codec, lineout_vol_reg, + 0x10, 0x00); + /* Remove mix path mute if it is enabled */ + if ((snd_soc_read(codec, lineout_mix_vol_reg)) & 0x10) + snd_soc_update_bits(codec, + lineout_mix_vol_reg, + 0x10, 0x00); + break; + default: + break; + }; + + return 0; +} + +static int tavil_codec_ear_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Disable AutoChop timer during power up */ + snd_soc_update_bits(codec, WCD934X_HPH_NEW_INT_HPH_TIMER1, + 0x02, 0x00); + wcd_clsh_fsm(codec, &tavil->clsh_d, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_EAR, + CLS_H_NORMAL); + break; + case SND_SOC_DAPM_POST_PMD: + wcd_clsh_fsm(codec, &tavil->clsh_d, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_EAR, + CLS_H_NORMAL); + break; + default: + break; + }; + + return 0; +} + +static int tavil_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + int hph_mode = tavil->hph_mode; + u8 dem_inp; + + dev_dbg(codec->dev, "%s wname: %s event: %d hph_mode: %d\n", __func__, + w->name, event, hph_mode); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Read DEM INP Select */ + dem_inp = snd_soc_read(codec, WCD934X_CDC_RX2_RX_PATH_SEC0) & + 0x03; + if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) || + (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) { + dev_err(codec->dev, "%s: DEM Input not set correctly, hph_mode: %d\n", + __func__, hph_mode); + return -EINVAL; + } + /* Disable AutoChop timer during power up */ + snd_soc_update_bits(codec, WCD934X_HPH_NEW_INT_HPH_TIMER1, + 0x02, 0x00); + wcd_clsh_fsm(codec, &tavil->clsh_d, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHR, + ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); + break; + case SND_SOC_DAPM_POST_PMD: + /* 1000us required as per HW requirement */ + usleep_range(1000, 1100); + wcd_clsh_fsm(codec, &tavil->clsh_d, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHR, + ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); + break; + default: + break; + }; + + return 0; +} + +static int tavil_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + int hph_mode = tavil->hph_mode; + u8 dem_inp; + int ret = 0; + + dev_dbg(codec->dev, "%s wname: %s event: %d hph_mode: %d\n", __func__, + w->name, event, hph_mode); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Read DEM INP Select */ + dem_inp = snd_soc_read(codec, WCD934X_CDC_RX1_RX_PATH_SEC0) & + 0x03; + if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) || + (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) { + dev_err(codec->dev, "%s: DEM Input not set correctly, hph_mode: %d\n", + __func__, hph_mode); + return -EINVAL; + } + wcd_clsh_fsm(codec, &tavil->clsh_d, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHL, + ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); + break; + case SND_SOC_DAPM_POST_PMD: + /* 1000us required as per HW requirement */ + usleep_range(1000, 1100); + wcd_clsh_fsm(codec, &tavil->clsh_d, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHL, + ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); + break; + default: + break; + }; + + return ret; +} + +static int tavil_codec_lineout_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd_clsh_fsm(codec, &tavil->clsh_d, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_LO, + CLS_AB); + break; + case SND_SOC_DAPM_POST_PMD: + wcd_clsh_fsm(codec, &tavil->clsh_d, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_LO, + CLS_AB); + break; + } + + return 0; +} + +static int tavil_codec_spk_boost_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + u16 boost_path_ctl, boost_path_cfg1; + u16 reg, reg_mix; + + dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event); + + if (!strcmp(w->name, "RX INT7 CHAIN")) { + boost_path_ctl = WCD934X_CDC_BOOST0_BOOST_PATH_CTL; + boost_path_cfg1 = WCD934X_CDC_RX7_RX_PATH_CFG1; + reg = WCD934X_CDC_RX7_RX_PATH_CTL; + reg_mix = WCD934X_CDC_RX7_RX_PATH_MIX_CTL; + } else if (!strcmp(w->name, "RX INT8 CHAIN")) { + boost_path_ctl = WCD934X_CDC_BOOST1_BOOST_PATH_CTL; + boost_path_cfg1 = WCD934X_CDC_RX8_RX_PATH_CFG1; + reg = WCD934X_CDC_RX8_RX_PATH_CTL; + reg_mix = WCD934X_CDC_RX8_RX_PATH_MIX_CTL; + } else { + dev_err(codec->dev, "%s: unknown widget: %s\n", + __func__, w->name); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, boost_path_cfg1, 0x01, 0x01); + snd_soc_update_bits(codec, boost_path_ctl, 0x10, 0x10); + snd_soc_update_bits(codec, reg, 0x10, 0x00); + if ((snd_soc_read(codec, reg_mix)) & 0x10) + snd_soc_update_bits(codec, reg_mix, 0x10, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, boost_path_ctl, 0x10, 0x00); + snd_soc_update_bits(codec, boost_path_cfg1, 0x01, 0x00); + break; + }; + + return 0; +} + +static int __tavil_codec_enable_swr(struct snd_soc_dapm_widget *w, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct tavil_priv *tavil; + int ch_cnt; + + tavil = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if ((strnstr(w->name, "INT7_", sizeof("RX INT7_"))) && + !tavil->swr.rx_7_count) + tavil->swr.rx_7_count++; + if ((strnstr(w->name, "INT8_", sizeof("RX INT8_"))) && + !tavil->swr.rx_8_count) + tavil->swr.rx_8_count++; + ch_cnt = tavil->swr.rx_7_count + tavil->swr.rx_8_count; + + swrm_wcd_notify(tavil->swr.ctrl_data[0].swr_pdev, + SWR_DEVICE_UP, NULL); + swrm_wcd_notify(tavil->swr.ctrl_data[0].swr_pdev, + SWR_SET_NUM_RX_CH, &ch_cnt); + break; + case SND_SOC_DAPM_POST_PMD: + if ((strnstr(w->name, "INT7_", sizeof("RX INT7_"))) && + tavil->swr.rx_7_count) + tavil->swr.rx_7_count--; + if ((strnstr(w->name, "INT8_", sizeof("RX INT8_"))) && + tavil->swr.rx_8_count) + tavil->swr.rx_8_count--; + ch_cnt = tavil->swr.rx_7_count + tavil->swr.rx_8_count; + + swrm_wcd_notify(tavil->swr.ctrl_data[0].swr_pdev, + SWR_SET_NUM_RX_CH, &ch_cnt); + + break; + } + dev_dbg(tavil->dev, "%s: current swr ch cnt: %d\n", + __func__, tavil->swr.rx_7_count + tavil->swr.rx_8_count); + + return 0; +} + +static int tavil_codec_enable_swr(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + return __tavil_codec_enable_swr(w, event); +} + +static u16 tavil_interp_get_primary_reg(u16 reg, u16 *ind) +{ + u16 prim_int_reg = 0; + + switch (reg) { + case WCD934X_CDC_RX0_RX_PATH_CTL: + case WCD934X_CDC_RX0_RX_PATH_MIX_CTL: + prim_int_reg = WCD934X_CDC_RX0_RX_PATH_CTL; + *ind = 0; + break; + case WCD934X_CDC_RX1_RX_PATH_CTL: + case WCD934X_CDC_RX1_RX_PATH_MIX_CTL: + prim_int_reg = WCD934X_CDC_RX1_RX_PATH_CTL; + *ind = 1; + break; + case WCD934X_CDC_RX2_RX_PATH_CTL: + case WCD934X_CDC_RX2_RX_PATH_MIX_CTL: + prim_int_reg = WCD934X_CDC_RX2_RX_PATH_CTL; + *ind = 2; + break; + case WCD934X_CDC_RX3_RX_PATH_CTL: + case WCD934X_CDC_RX3_RX_PATH_MIX_CTL: + prim_int_reg = WCD934X_CDC_RX3_RX_PATH_CTL; + *ind = 3; + break; + case WCD934X_CDC_RX4_RX_PATH_CTL: + case WCD934X_CDC_RX4_RX_PATH_MIX_CTL: + prim_int_reg = WCD934X_CDC_RX4_RX_PATH_CTL; + *ind = 4; + break; + case WCD934X_CDC_RX7_RX_PATH_CTL: + case WCD934X_CDC_RX7_RX_PATH_MIX_CTL: + prim_int_reg = WCD934X_CDC_RX7_RX_PATH_CTL; + *ind = 7; + break; + case WCD934X_CDC_RX8_RX_PATH_CTL: + case WCD934X_CDC_RX8_RX_PATH_MIX_CTL: + prim_int_reg = WCD934X_CDC_RX8_RX_PATH_CTL; + *ind = 8; + break; + }; + + return prim_int_reg; +} + +static void tavil_codec_hd2_control(struct snd_soc_codec *codec, + u16 prim_int_reg, int event) +{ + u16 hd2_scale_reg; + u16 hd2_enable_reg = 0; + + if (prim_int_reg == WCD934X_CDC_RX1_RX_PATH_CTL) { + hd2_scale_reg = WCD934X_CDC_RX1_RX_PATH_SEC3; + hd2_enable_reg = WCD934X_CDC_RX1_RX_PATH_CFG0; + } + if (prim_int_reg == WCD934X_CDC_RX2_RX_PATH_CTL) { + hd2_scale_reg = WCD934X_CDC_RX2_RX_PATH_SEC3; + hd2_enable_reg = WCD934X_CDC_RX2_RX_PATH_CFG0; + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_update_bits(codec, hd2_scale_reg, 0x3C, 0x10); + snd_soc_update_bits(codec, hd2_scale_reg, 0x03, 0x01); + snd_soc_update_bits(codec, hd2_enable_reg, 0x04, 0x04); + } + + if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_update_bits(codec, hd2_enable_reg, 0x04, 0x00); + snd_soc_update_bits(codec, hd2_scale_reg, 0x03, 0x00); + snd_soc_update_bits(codec, hd2_scale_reg, 0x3C, 0x00); + } +} + +static int tavil_codec_enable_prim_interpolator(struct snd_soc_codec *codec, + u16 reg, int event) +{ + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + u16 prim_int_reg; + u16 ind = 0; + + prim_int_reg = tavil_interp_get_primary_reg(reg, &ind); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + tavil->prim_int_users[ind]++; + if (tavil->prim_int_users[ind] == 1) { + /* PGA Mute enable */ + snd_soc_update_bits(codec, prim_int_reg, + 0x10, 0x10); + tavil_codec_hd2_control(codec, prim_int_reg, event); + /* RX path CLK enable */ + snd_soc_update_bits(codec, prim_int_reg, + 1 << 0x5, 1 << 0x5); + } + if ((reg != prim_int_reg) && + ((snd_soc_read(codec, prim_int_reg)) & 0x10)) + snd_soc_update_bits(codec, reg, 0x10, 0x10); + break; + case SND_SOC_DAPM_POST_PMD: + tavil->prim_int_users[ind]--; + if (tavil->prim_int_users[ind] == 0) { + snd_soc_update_bits(codec, prim_int_reg, + 1 << 0x5, 0 << 0x5); + snd_soc_update_bits(codec, prim_int_reg, + 0x40, 0x40); + snd_soc_update_bits(codec, prim_int_reg, + 0x40, 0x00); + tavil_codec_hd2_control(codec, prim_int_reg, event); + } + break; + }; + + dev_dbg(codec->dev, "%s: primary interpolator: INT%d, users: %d\n", + __func__, ind, tavil->prim_int_users[ind]); + return 0; +} + +static int tavil_codec_enable_mix_path(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + u16 gain_reg; + int offset_val = 0; + int val = 0; + + dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name); + + switch (w->reg) { + case WCD934X_CDC_RX0_RX_PATH_MIX_CTL: + gain_reg = WCD934X_CDC_RX0_RX_VOL_MIX_CTL; + break; + case WCD934X_CDC_RX1_RX_PATH_MIX_CTL: + gain_reg = WCD934X_CDC_RX1_RX_VOL_MIX_CTL; + break; + case WCD934X_CDC_RX2_RX_PATH_MIX_CTL: + gain_reg = WCD934X_CDC_RX2_RX_VOL_MIX_CTL; + break; + case WCD934X_CDC_RX3_RX_PATH_MIX_CTL: + gain_reg = WCD934X_CDC_RX3_RX_VOL_MIX_CTL; + break; + case WCD934X_CDC_RX4_RX_PATH_MIX_CTL: + gain_reg = WCD934X_CDC_RX4_RX_VOL_MIX_CTL; + break; + case WCD934X_CDC_RX7_RX_PATH_MIX_CTL: + __tavil_codec_enable_swr(w, event); + gain_reg = WCD934X_CDC_RX7_RX_VOL_MIX_CTL; + break; + case WCD934X_CDC_RX8_RX_PATH_MIX_CTL: + __tavil_codec_enable_swr(w, event); + gain_reg = WCD934X_CDC_RX8_RX_VOL_MIX_CTL; + break; + default: + dev_err(codec->dev, "%s: No gain register avail for %s\n", + __func__, w->name); + return 0; + }; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if ((tavil->swr.spkr_gain_offset == + WCD934X_RX_GAIN_OFFSET_M1P5_DB) && + (tavil->comp_enabled[COMPANDER_7] || + tavil->comp_enabled[COMPANDER_8]) && + (gain_reg == WCD934X_CDC_RX7_RX_VOL_MIX_CTL || + gain_reg == WCD934X_CDC_RX8_RX_VOL_MIX_CTL)) { + snd_soc_update_bits(codec, WCD934X_CDC_RX7_RX_PATH_SEC1, + 0x01, 0x01); + snd_soc_update_bits(codec, + WCD934X_CDC_RX7_RX_PATH_MIX_SEC0, + 0x01, 0x01); + snd_soc_update_bits(codec, WCD934X_CDC_RX8_RX_PATH_SEC1, + 0x01, 0x01); + snd_soc_update_bits(codec, + WCD934X_CDC_RX8_RX_PATH_MIX_SEC0, + 0x01, 0x01); + offset_val = -2; + } + val = snd_soc_read(codec, gain_reg); + val += offset_val; + snd_soc_write(codec, gain_reg, val); + break; + case SND_SOC_DAPM_POST_PMD: + if ((tavil->swr.spkr_gain_offset == + WCD934X_RX_GAIN_OFFSET_M1P5_DB) && + (tavil->comp_enabled[COMPANDER_7] || + tavil->comp_enabled[COMPANDER_8]) && + (gain_reg == WCD934X_CDC_RX7_RX_VOL_MIX_CTL || + gain_reg == WCD934X_CDC_RX8_RX_VOL_MIX_CTL)) { + snd_soc_update_bits(codec, WCD934X_CDC_RX7_RX_PATH_SEC1, + 0x01, 0x00); + snd_soc_update_bits(codec, + WCD934X_CDC_RX7_RX_PATH_MIX_SEC0, + 0x01, 0x00); + snd_soc_update_bits(codec, WCD934X_CDC_RX8_RX_PATH_SEC1, + 0x01, 0x00); + snd_soc_update_bits(codec, + WCD934X_CDC_RX8_RX_PATH_MIX_SEC0, + 0x01, 0x00); + offset_val = 2; + val = snd_soc_read(codec, gain_reg); + val += offset_val; + snd_soc_write(codec, gain_reg, val); + } + break; + }; + + return 0; +} + +static int tavil_config_compander(struct snd_soc_codec *codec, int interp_n, + int event) +{ + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + int comp; + u16 comp_ctl0_reg, rx_path_cfg0_reg; + + /* EAR does not have compander */ + if (!interp_n) + return 0; + + comp = interp_n - 1; + dev_dbg(codec->dev, "%s: event %d compander %d, enabled %d\n", + __func__, event, comp + 1, tavil->comp_enabled[comp]); + + if (!tavil->comp_enabled[comp]) + return 0; + + comp_ctl0_reg = WCD934X_CDC_COMPANDER1_CTL0 + (comp * 8); + rx_path_cfg0_reg = WCD934X_CDC_RX1_RX_PATH_CFG0 + (comp * 20); + + if (SND_SOC_DAPM_EVENT_ON(event)) { + /* Enable Compander Clock */ + snd_soc_update_bits(codec, comp_ctl0_reg, 0x01, 0x01); + snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x02); + snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x00); + snd_soc_update_bits(codec, rx_path_cfg0_reg, 0x02, 0x02); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_update_bits(codec, comp_ctl0_reg, 0x04, 0x04); + snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x00); + snd_soc_update_bits(codec, comp_ctl0_reg, 0x01, 0x00); + snd_soc_update_bits(codec, comp_ctl0_reg, 0x04, 0x00); + } + + return 0; +} + +static int tavil_codec_enable_interpolator(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + u16 gain_reg; + u16 reg; + int val; + int offset_val = 0; + + dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name); + + if (!(strcmp(w->name, "RX INT0 INTERP"))) { + reg = WCD934X_CDC_RX0_RX_PATH_CTL; + gain_reg = WCD934X_CDC_RX0_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT1 INTERP"))) { + reg = WCD934X_CDC_RX1_RX_PATH_CTL; + gain_reg = WCD934X_CDC_RX1_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT2 INTERP"))) { + reg = WCD934X_CDC_RX2_RX_PATH_CTL; + gain_reg = WCD934X_CDC_RX2_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT3 INTERP"))) { + reg = WCD934X_CDC_RX3_RX_PATH_CTL; + gain_reg = WCD934X_CDC_RX3_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT4 INTERP"))) { + reg = WCD934X_CDC_RX4_RX_PATH_CTL; + gain_reg = WCD934X_CDC_RX4_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT7 INTERP"))) { + reg = WCD934X_CDC_RX7_RX_PATH_CTL; + gain_reg = WCD934X_CDC_RX7_RX_VOL_CTL; + } else if (!(strcmp(w->name, "RX INT8 INTERP"))) { + reg = WCD934X_CDC_RX8_RX_PATH_CTL; + gain_reg = WCD934X_CDC_RX8_RX_VOL_CTL; + } else { + dev_err(codec->dev, "%s: Interpolator reg not found\n", + __func__); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Reset if needed */ + tavil_codec_enable_prim_interpolator(codec, reg, event); + break; + case SND_SOC_DAPM_POST_PMU: + tavil_config_compander(codec, w->shift, event); + /* apply gain after int clk is enabled */ + if ((tavil->swr.spkr_gain_offset == + WCD934X_RX_GAIN_OFFSET_M1P5_DB) && + (tavil->comp_enabled[COMPANDER_7] || + tavil->comp_enabled[COMPANDER_8]) && + (gain_reg == WCD934X_CDC_RX7_RX_VOL_CTL || + gain_reg == WCD934X_CDC_RX8_RX_VOL_CTL)) { + snd_soc_update_bits(codec, WCD934X_CDC_RX7_RX_PATH_SEC1, + 0x01, 0x01); + snd_soc_update_bits(codec, + WCD934X_CDC_RX7_RX_PATH_MIX_SEC0, + 0x01, 0x01); + snd_soc_update_bits(codec, WCD934X_CDC_RX8_RX_PATH_SEC1, + 0x01, 0x01); + snd_soc_update_bits(codec, + WCD934X_CDC_RX8_RX_PATH_MIX_SEC0, + 0x01, 0x01); + offset_val = -2; + } + val = snd_soc_read(codec, gain_reg); + val += offset_val; + snd_soc_write(codec, gain_reg, val); + break; + case SND_SOC_DAPM_POST_PMD: + tavil_config_compander(codec, w->shift, event); + tavil_codec_enable_prim_interpolator(codec, reg, event); + if ((tavil->swr.spkr_gain_offset == + WCD934X_RX_GAIN_OFFSET_M1P5_DB) && + (tavil->comp_enabled[COMPANDER_7] || + tavil->comp_enabled[COMPANDER_8]) && + (gain_reg == WCD934X_CDC_RX7_RX_VOL_CTL || + gain_reg == WCD934X_CDC_RX8_RX_VOL_CTL)) { + snd_soc_update_bits(codec, WCD934X_CDC_RX7_RX_PATH_SEC1, + 0x01, 0x00); + snd_soc_update_bits(codec, + WCD934X_CDC_RX7_RX_PATH_MIX_SEC0, + 0x01, 0x00); + snd_soc_update_bits(codec, WCD934X_CDC_RX8_RX_PATH_SEC1, + 0x01, 0x00); + snd_soc_update_bits(codec, + WCD934X_CDC_RX8_RX_PATH_MIX_SEC0, + 0x01, 0x00); + offset_val = 2; + val = snd_soc_read(codec, gain_reg); + val += offset_val; + snd_soc_write(codec, gain_reg, val); + } + break; + }; + + return 0; +} + +static int tavil_codec_set_iir_gain(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + dev_dbg(codec->dev, "%s: event = %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: /* fall through */ + case SND_SOC_DAPM_PRE_PMD: + if (strnstr(w->name, "IIR0", sizeof("IIR0"))) { + snd_soc_write(codec, + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL, + snd_soc_read(codec, + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL)); + snd_soc_write(codec, + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL, + snd_soc_read(codec, + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL)); + snd_soc_write(codec, + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL, + snd_soc_read(codec, + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL)); + snd_soc_write(codec, + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL, + snd_soc_read(codec, + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL)); + } else { + snd_soc_write(codec, + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL, + snd_soc_read(codec, + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL)); + snd_soc_write(codec, + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL, + snd_soc_read(codec, + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL)); + snd_soc_write(codec, + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL, + snd_soc_read(codec, + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL)); + } + break; + } + return 0; +} + +static int tavil_codec_find_amic_input(struct snd_soc_codec *codec, + int adc_mux_n) +{ + u16 mask, shift, adc_mux_in_reg; + u16 amic_mux_sel_reg; + bool is_amic; + + if (adc_mux_n < 0 || adc_mux_n > WCD934X_MAX_VALID_ADC_MUX || + adc_mux_n == WCD934X_INVALID_ADC_MUX) + return 0; + + if (adc_mux_n < 3) { + adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1 + + adc_mux_n; + mask = 0x03; + shift = 0; + amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0 + + 2 * adc_mux_n; + } else if (adc_mux_n < 4) { + adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1; + mask = 0x03; + shift = 0; + amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0 + + 2 * adc_mux_n; + } else if (adc_mux_n < 7) { + adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1 + + (adc_mux_n - 4); + mask = 0x0C; + shift = 2; + amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 + + adc_mux_n - 4; + } else if (adc_mux_n < 8) { + adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1; + mask = 0x0C; + shift = 2; + amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 + + adc_mux_n - 4; + } else if (adc_mux_n < 12) { + adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1 + + ((adc_mux_n == 8) ? (adc_mux_n - 8) : + (adc_mux_n - 9)); + mask = 0x30; + shift = 4; + amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 + + adc_mux_n - 4; + } else if (adc_mux_n < 13) { + adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1; + mask = 0x30; + shift = 4; + amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 + + adc_mux_n - 4; + } else { + adc_mux_in_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1; + mask = 0xC0; + shift = 6; + amic_mux_sel_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0 + + adc_mux_n - 4; + } + + is_amic = (((snd_soc_read(codec, adc_mux_in_reg) & mask) >> shift) + == 1); + if (!is_amic) + return 0; + + return snd_soc_read(codec, amic_mux_sel_reg) & 0x07; +} + +static void tavil_codec_set_tx_hold(struct snd_soc_codec *codec, + u16 amic_reg, bool set) +{ + u8 mask = 0x20; + u8 val; + + if (amic_reg == WCD934X_ANA_AMIC1 || + amic_reg == WCD934X_ANA_AMIC3) + mask = 0x40; + + val = set ? mask : 0x00; + + switch (amic_reg) { + case WCD934X_ANA_AMIC1: + case WCD934X_ANA_AMIC2: + snd_soc_update_bits(codec, WCD934X_ANA_AMIC2, mask, val); + break; + case WCD934X_ANA_AMIC3: + case WCD934X_ANA_AMIC4: + snd_soc_update_bits(codec, WCD934X_ANA_AMIC4, mask, val); + break; + default: + dev_dbg(codec->dev, "%s: invalid amic: %d\n", + __func__, amic_reg); + break; + } +} + +static int tavil_codec_tx_adc_cfg(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + int adc_mux_n = w->shift; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + int amic_n; + u16 amic_reg; + + dev_dbg(codec->dev, "%s: event: %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + amic_n = tavil_codec_find_amic_input(codec, adc_mux_n); + if (amic_n) { + amic_reg = WCD934X_ANA_AMIC1 + amic_n - 1; + tavil_codec_set_tx_hold(codec, amic_reg, false); + } + break; + default: + break; + } + + return 0; +} + +static u16 tavil_codec_get_amic_pwlvl_reg(struct snd_soc_codec *codec, int amic) +{ + u16 pwr_level_reg = 0; + + switch (amic) { + case 1: + case 2: + pwr_level_reg = WCD934X_ANA_AMIC1; + break; + + case 3: + case 4: + pwr_level_reg = WCD934X_ANA_AMIC3; + break; + default: + dev_dbg(codec->dev, "%s: invalid amic: %d\n", + __func__, amic); + break; + } + + return pwr_level_reg; +} + +#define TX_HPF_CUT_OFF_FREQ_MASK 0x60 +#define CF_MIN_3DB_4HZ 0x0 +#define CF_MIN_3DB_75HZ 0x1 +#define CF_MIN_3DB_150HZ 0x2 + +static void tavil_tx_hpf_corner_freq_callback(struct work_struct *work) +{ + struct delayed_work *hpf_delayed_work; + struct hpf_work *hpf_work; + struct tavil_priv *tavil; + struct snd_soc_codec *codec; + u16 dec_cfg_reg, amic_reg; + u8 hpf_cut_off_freq; + int amic_n; + + hpf_delayed_work = to_delayed_work(work); + hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork); + tavil = hpf_work->tavil; + codec = tavil->codec; + hpf_cut_off_freq = hpf_work->hpf_cut_off_freq; + + dec_cfg_reg = WCD934X_CDC_TX0_TX_PATH_CFG0 + 16 * hpf_work->decimator; + + dev_dbg(codec->dev, "%s: decimator %u hpf_cut_of_freq 0x%x\n", + __func__, hpf_work->decimator, hpf_cut_off_freq); + + amic_n = tavil_codec_find_amic_input(codec, hpf_work->decimator); + if (amic_n) { + amic_reg = WCD934X_ANA_AMIC1 + amic_n - 1; + tavil_codec_set_tx_hold(codec, amic_reg, false); + } + snd_soc_update_bits(codec, dec_cfg_reg, TX_HPF_CUT_OFF_FREQ_MASK, + hpf_cut_off_freq << 5); +} + +static void tavil_tx_mute_update_callback(struct work_struct *work) +{ + struct tx_mute_work *tx_mute_dwork; + struct tavil_priv *tavil; + struct delayed_work *delayed_work; + struct snd_soc_codec *codec; + u16 tx_vol_ctl_reg, hpf_gate_reg; + + delayed_work = to_delayed_work(work); + tx_mute_dwork = container_of(delayed_work, struct tx_mute_work, dwork); + tavil = tx_mute_dwork->tavil; + codec = tavil->codec; + + tx_vol_ctl_reg = WCD934X_CDC_TX0_TX_PATH_CTL + + 16 * tx_mute_dwork->decimator; + hpf_gate_reg = WCD934X_CDC_TX0_TX_PATH_SEC2 + + 16 * tx_mute_dwork->decimator; + snd_soc_update_bits(codec, hpf_gate_reg, 0x01, 0x01); + snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x10, 0x00); +} + +static int tavil_codec_enable_dec(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + unsigned int decimator; + char *dec_adc_mux_name = NULL; + char *widget_name = NULL; + char *wname; + int ret = 0, amic_n; + u16 tx_vol_ctl_reg, pwr_level_reg = 0, dec_cfg_reg, hpf_gate_reg; + char *dec; + u8 hpf_cut_off_freq; + + dev_dbg(codec->dev, "%s %d\n", __func__, event); + + widget_name = kstrndup(w->name, 15, GFP_KERNEL); + if (!widget_name) + return -ENOMEM; + + wname = widget_name; + dec_adc_mux_name = strsep(&widget_name, " "); + if (!dec_adc_mux_name) { + dev_err(codec->dev, "%s: Invalid decimator = %s\n", + __func__, w->name); + ret = -EINVAL; + goto out; + } + dec_adc_mux_name = widget_name; + + dec = strpbrk(dec_adc_mux_name, "012345678"); + if (!dec) { + dev_err(codec->dev, "%s: decimator index not found\n", + __func__); + ret = -EINVAL; + goto out; + } + + ret = kstrtouint(dec, 10, &decimator); + if (ret < 0) { + dev_err(codec->dev, "%s: Invalid decimator = %s\n", + __func__, wname); + ret = -EINVAL; + goto out; + } + + dev_dbg(codec->dev, "%s(): widget = %s decimator = %u\n", __func__, + w->name, decimator); + + tx_vol_ctl_reg = WCD934X_CDC_TX0_TX_PATH_CTL + 16 * decimator; + hpf_gate_reg = WCD934X_CDC_TX0_TX_PATH_SEC2 + 16 * decimator; + dec_cfg_reg = WCD934X_CDC_TX0_TX_PATH_CFG0 + 16 * decimator; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + amic_n = tavil_codec_find_amic_input(codec, decimator); + if (amic_n) + pwr_level_reg = tavil_codec_get_amic_pwlvl_reg(codec, + amic_n); + + if (pwr_level_reg) { + switch ((snd_soc_read(codec, pwr_level_reg) & + WCD934X_AMIC_PWR_LVL_MASK) >> + WCD934X_AMIC_PWR_LVL_SHIFT) { + case WCD934X_AMIC_PWR_LEVEL_LP: + snd_soc_update_bits(codec, dec_cfg_reg, + WCD934X_DEC_PWR_LVL_MASK, + WCD934X_DEC_PWR_LVL_LP); + break; + + case WCD934X_AMIC_PWR_LEVEL_HP: + snd_soc_update_bits(codec, dec_cfg_reg, + WCD934X_DEC_PWR_LVL_MASK, + WCD934X_DEC_PWR_LVL_HP); + break; + case WCD934X_AMIC_PWR_LEVEL_DEFAULT: + default: + snd_soc_update_bits(codec, dec_cfg_reg, + WCD934X_DEC_PWR_LVL_MASK, + WCD934X_DEC_PWR_LVL_DF); + break; + } + } + hpf_cut_off_freq = (snd_soc_read(codec, dec_cfg_reg) & + TX_HPF_CUT_OFF_FREQ_MASK) >> 5; + + tavil->tx_hpf_work[decimator].hpf_cut_off_freq = + hpf_cut_off_freq; + if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) + snd_soc_update_bits(codec, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + CF_MIN_3DB_150HZ << 5); + /* Enable TX PGA Mute */ + snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x10, 0x10); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, hpf_gate_reg, 0x01, 0x00); + /* schedule work queue to Remove Mute */ + schedule_delayed_work(&tavil->tx_mute_dwork[decimator].dwork, + msecs_to_jiffies(tx_unmute_delay)); + if (tavil->tx_hpf_work[decimator].hpf_cut_off_freq != + CF_MIN_3DB_150HZ) + schedule_delayed_work( + &tavil->tx_hpf_work[decimator].dwork, + msecs_to_jiffies(300)); + + break; + case SND_SOC_DAPM_PRE_PMD: + hpf_cut_off_freq = + tavil->tx_hpf_work[decimator].hpf_cut_off_freq; + snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x10, 0x10); + if (cancel_delayed_work_sync( + &tavil->tx_hpf_work[decimator].dwork)) { + if (hpf_cut_off_freq != CF_MIN_3DB_150HZ) + snd_soc_update_bits(codec, dec_cfg_reg, + TX_HPF_CUT_OFF_FREQ_MASK, + hpf_cut_off_freq << 5); + } + cancel_delayed_work_sync( + &tavil->tx_mute_dwork[decimator].dwork); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x10, 0x00); + break; + }; +out: + kfree(wname); + return ret; +} + +static u8 tavil_get_dmic_clk_val(struct snd_soc_codec *codec, + u32 mclk_rate, u32 dmic_clk_rate) +{ + u32 div_factor; + u8 dmic_ctl_val; + + dev_dbg(codec->dev, + "%s: mclk_rate = %d, dmic_sample_rate = %d\n", + __func__, mclk_rate, dmic_clk_rate); + + /* Default value to return in case of error */ + if (mclk_rate == WCD934X_MCLK_CLK_9P6MHZ) + dmic_ctl_val = WCD934X_DMIC_CLK_DIV_2; + else + dmic_ctl_val = WCD934X_DMIC_CLK_DIV_3; + + if (dmic_clk_rate == 0) { + dev_err(codec->dev, + "%s: dmic_sample_rate cannot be 0\n", + __func__); + goto done; + } + + div_factor = mclk_rate / dmic_clk_rate; + switch (div_factor) { + case 2: + dmic_ctl_val = WCD934X_DMIC_CLK_DIV_2; + break; + case 3: + dmic_ctl_val = WCD934X_DMIC_CLK_DIV_3; + break; + case 4: + dmic_ctl_val = WCD934X_DMIC_CLK_DIV_4; + break; + case 6: + dmic_ctl_val = WCD934X_DMIC_CLK_DIV_6; + break; + case 8: + dmic_ctl_val = WCD934X_DMIC_CLK_DIV_8; + break; + case 16: + dmic_ctl_val = WCD934X_DMIC_CLK_DIV_16; + break; + default: + dev_err(codec->dev, + "%s: Invalid div_factor %u, clk_rate(%u), dmic_rate(%u)\n", + __func__, div_factor, mclk_rate, dmic_clk_rate); + break; + } + +done: + return dmic_ctl_val; +} + +static int tavil_codec_enable_adc(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + dev_dbg(codec->dev, "%s: event:%d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + tavil_codec_set_tx_hold(codec, w->reg, true); + break; + default: + break; + } + + return 0; +} + +static int tavil_codec_enable_dmic(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + struct wcd9xxx_pdata *pdata = dev_get_platdata(codec->dev->parent); + u8 dmic_clk_en = 0x01; + u16 dmic_clk_reg; + s32 *dmic_clk_cnt; + u8 dmic_rate_val, dmic_rate_shift = 1; + unsigned int dmic; + int ret; + char *wname; + + wname = strpbrk(w->name, "012345"); + if (!wname) { + dev_err(codec->dev, "%s: widget not found\n", __func__); + return -EINVAL; + } + + ret = kstrtouint(wname, 10, &dmic); + if (ret < 0) { + dev_err(codec->dev, "%s: Invalid DMIC line on the codec\n", + __func__); + return -EINVAL; + } + + switch (dmic) { + case 0: + case 1: + dmic_clk_cnt = &(tavil->dmic_0_1_clk_cnt); + dmic_clk_reg = WCD934X_CPE_SS_DMIC0_CTL; + break; + case 2: + case 3: + dmic_clk_cnt = &(tavil->dmic_2_3_clk_cnt); + dmic_clk_reg = WCD934X_CPE_SS_DMIC1_CTL; + break; + case 4: + case 5: + dmic_clk_cnt = &(tavil->dmic_4_5_clk_cnt); + dmic_clk_reg = WCD934X_CPE_SS_DMIC2_CTL; + break; + default: + dev_err(codec->dev, "%s: Invalid DMIC Selection\n", + __func__); + return -EINVAL; + }; + dev_dbg(codec->dev, "%s: event %d DMIC%d dmic_clk_cnt %d\n", + __func__, event, dmic, *dmic_clk_cnt); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + dmic_rate_val = + tavil_get_dmic_clk_val(codec, + pdata->mclk_rate, + pdata->dmic_sample_rate); + + (*dmic_clk_cnt)++; + if (*dmic_clk_cnt == 1) { + snd_soc_update_bits(codec, dmic_clk_reg, + 0x07 << dmic_rate_shift, + dmic_rate_val << dmic_rate_shift); + snd_soc_update_bits(codec, dmic_clk_reg, + dmic_clk_en, dmic_clk_en); + } + + break; + case SND_SOC_DAPM_POST_PMD: + dmic_rate_val = + tavil_get_dmic_clk_val(codec, + pdata->mclk_rate, + pdata->mad_dmic_sample_rate); + (*dmic_clk_cnt)--; + if (*dmic_clk_cnt == 0) { + snd_soc_update_bits(codec, dmic_clk_reg, + dmic_clk_en, 0); + snd_soc_update_bits(codec, dmic_clk_reg, + 0x07 << dmic_rate_shift, + dmic_rate_val << dmic_rate_shift); + } + break; + }; + + return 0; +} + +static int tavil_micbias_control(struct snd_soc_codec *codec, + int micb_num, + int req, bool is_dapm) +{ + + + u16 micb_reg; + + switch (micb_num) { + case MIC_BIAS_1: + micb_reg = WCD934X_ANA_MICB1; + break; + case MIC_BIAS_2: + micb_reg = WCD934X_ANA_MICB2; + break; + case MIC_BIAS_3: + micb_reg = WCD934X_ANA_MICB3; + break; + case MIC_BIAS_4: + micb_reg = WCD934X_ANA_MICB4; + break; + default: + dev_err(codec->dev, "%s: Invalid micbias number: %d\n", + __func__, micb_num); + return -EINVAL; + } + + switch (req) { + case MICB_ENABLE: + snd_soc_update_bits(codec, micb_reg, 0xC0, 0x40); + break; + case MICB_DISABLE: + snd_soc_update_bits(codec, micb_reg, 0xC0, 0x80); + }; + + return 0; +} + +static int __tavil_codec_enable_micbias(struct snd_soc_dapm_widget *w, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + int micb_num; + + dev_dbg(codec->dev, "%s: wname: %s, event: %d\n", + __func__, w->name, event); + + if (strnstr(w->name, "MIC BIAS1", sizeof("MIC BIAS1"))) + micb_num = MIC_BIAS_1; + else if (strnstr(w->name, "MIC BIAS2", sizeof("MIC BIAS2"))) + micb_num = MIC_BIAS_2; + else if (strnstr(w->name, "MIC BIAS3", sizeof("MIC BIAS3"))) + micb_num = MIC_BIAS_3; + else if (strnstr(w->name, "MIC BIAS4", sizeof("MIC BIAS4"))) + micb_num = MIC_BIAS_4; + else + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* + * MIC BIAS can also be requested by MBHC, + * so use ref count to handle micbias pullup + * and enable requests + */ + tavil_micbias_control(codec, micb_num, MICB_ENABLE, true); + break; + case SND_SOC_DAPM_POST_PMU: + /* wait for cnp time */ + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_POST_PMD: + tavil_micbias_control(codec, micb_num, MICB_DISABLE, true); + break; + }; + + return 0; +} + +static int tavil_codec_force_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + int ret = 0; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd_resmgr_enable_master_bias(tavil->resmgr); + tavil_cdc_mclk_enable(codec, true); + ret = __tavil_codec_enable_micbias(w, SND_SOC_DAPM_PRE_PMU); + /* Wait for 1ms for better cnp */ + usleep_range(1000, 1100); + tavil_cdc_mclk_enable(codec, false); + break; + case SND_SOC_DAPM_POST_PMD: + ret = __tavil_codec_enable_micbias(w, SND_SOC_DAPM_POST_PMD); + wcd_resmgr_disable_master_bias(tavil->resmgr); + break; + } + + return ret; +} + +static int tavil_codec_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + return __tavil_codec_enable_micbias(w, event); +} + +static int tavil_iir_enable_audio_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + int iir_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + /* IIR filter band registers are at integer multiples of 16 */ + u16 iir_reg = WCD934X_CDC_SIDETONE_IIR0_IIR_CTL + 16 * iir_idx; + + ucontrol->value.integer.value[0] = (snd_soc_read(codec, iir_reg) & + (1 << band_idx)) != 0; + + dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__, + iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[0]); + return 0; +} + +static int tavil_iir_enable_audio_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + int iir_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + bool iir_band_en_status; + int value = ucontrol->value.integer.value[0]; + u16 iir_reg = WCD934X_CDC_SIDETONE_IIR0_IIR_CTL + 16 * iir_idx; + + /* Mask first 5 bits, 6-8 are reserved */ + snd_soc_update_bits(codec, iir_reg, (1 << band_idx), + (value << band_idx)); + + iir_band_en_status = ((snd_soc_read(codec, iir_reg) & + (1 << band_idx)) != 0); + dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__, + iir_idx, band_idx, iir_band_en_status); + return 0; +} + +static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec, + int iir_idx, int band_idx, + int coeff_idx) +{ + uint32_t value = 0; + + /* Address does not automatically update if reading */ + snd_soc_write(codec, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t)) & 0x7F); + + value |= snd_soc_read(codec, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx)); + + snd_soc_write(codec, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 1) & 0x7F); + + value |= (snd_soc_read(codec, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + + 16 * iir_idx)) << 8); + + snd_soc_write(codec, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 2) & 0x7F); + + value |= (snd_soc_read(codec, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + + 16 * iir_idx)) << 16); + + snd_soc_write(codec, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx), + ((band_idx * BAND_MAX + coeff_idx) + * sizeof(uint32_t) + 3) & 0x7F); + + /* Mask bits top 2 bits since they are reserved */ + value |= ((snd_soc_read(codec, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + + 16 * iir_idx)) & 0x3F) << 24); + + return value; +} + +static int tavil_iir_band_audio_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + int iir_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + ucontrol->value.integer.value[0] = + get_iir_band_coeff(codec, iir_idx, band_idx, 0); + ucontrol->value.integer.value[1] = + get_iir_band_coeff(codec, iir_idx, band_idx, 1); + ucontrol->value.integer.value[2] = + get_iir_band_coeff(codec, iir_idx, band_idx, 2); + ucontrol->value.integer.value[3] = + get_iir_band_coeff(codec, iir_idx, band_idx, 3); + ucontrol->value.integer.value[4] = + get_iir_band_coeff(codec, iir_idx, band_idx, 4); + + dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n" + "%s: IIR #%d band #%d b1 = 0x%x\n" + "%s: IIR #%d band #%d b2 = 0x%x\n" + "%s: IIR #%d band #%d a1 = 0x%x\n" + "%s: IIR #%d band #%d a2 = 0x%x\n", + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[0], + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[1], + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[2], + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[3], + __func__, iir_idx, band_idx, + (uint32_t)ucontrol->value.integer.value[4]); + return 0; +} + +static void set_iir_band_coeff(struct snd_soc_codec *codec, + int iir_idx, int band_idx, + uint32_t value) +{ + snd_soc_write(codec, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx), + (value & 0xFF)); + + snd_soc_write(codec, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx), + (value >> 8) & 0xFF); + + snd_soc_write(codec, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx), + (value >> 16) & 0xFF); + + /* Mask top 2 bits, 7-8 are reserved */ + snd_soc_write(codec, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx), + (value >> 24) & 0x3F); +} + +static int tavil_iir_band_audio_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + int iir_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->reg; + int band_idx = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + /* + * Mask top bit it is reserved + * Updates addr automatically for each B2 write + */ + snd_soc_write(codec, + (WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx), + (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F); + + set_iir_band_coeff(codec, iir_idx, band_idx, + ucontrol->value.integer.value[0]); + set_iir_band_coeff(codec, iir_idx, band_idx, + ucontrol->value.integer.value[1]); + set_iir_band_coeff(codec, iir_idx, band_idx, + ucontrol->value.integer.value[2]); + set_iir_band_coeff(codec, iir_idx, band_idx, + ucontrol->value.integer.value[3]); + set_iir_band_coeff(codec, iir_idx, band_idx, + ucontrol->value.integer.value[4]); + + pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n" + "%s: IIR #%d band #%d b1 = 0x%x\n" + "%s: IIR #%d band #%d b2 = 0x%x\n" + "%s: IIR #%d band #%d a1 = 0x%x\n" + "%s: IIR #%d band #%d a2 = 0x%x\n", + __func__, iir_idx, band_idx, + get_iir_band_coeff(codec, iir_idx, band_idx, 0), + __func__, iir_idx, band_idx, + get_iir_band_coeff(codec, iir_idx, band_idx, 1), + __func__, iir_idx, band_idx, + get_iir_band_coeff(codec, iir_idx, band_idx, 2), + __func__, iir_idx, band_idx, + get_iir_band_coeff(codec, iir_idx, band_idx, 3), + __func__, iir_idx, band_idx, + get_iir_band_coeff(codec, iir_idx, band_idx, 4)); + return 0; +} + +static int tavil_compander_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + int comp = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = tavil->comp_enabled[comp]; + return 0; +} + +static int tavil_compander_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + int comp = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + int value = ucontrol->value.integer.value[0]; + + dev_dbg(codec->dev, "%s: Compander %d enable current %d, new %d\n", + __func__, comp + 1, tavil->comp_enabled[comp], value); + tavil->comp_enabled[comp] = value; + + /* Any specific register configuration for compander */ + switch (comp) { + case COMPANDER_1: + /* Set Gain Source Select based on compander enable/disable */ + snd_soc_update_bits(codec, WCD934X_HPH_L_EN, 0x20, + (value ? 0x00:0x20)); + break; + case COMPANDER_2: + snd_soc_update_bits(codec, WCD934X_HPH_R_EN, 0x20, + (value ? 0x00:0x20)); + break; + case COMPANDER_3: + case COMPANDER_4: + case COMPANDER_7: + case COMPANDER_8: + break; + default: + /* + * if compander is not enabled for any interpolator, + * it does not cause any audio failure, so do not + * return error in this case, but just print a log + */ + dev_warn(codec->dev, "%s: unknown compander: %d\n", + __func__, comp); + }; + return 0; +} + +static int tavil_dmic_pin_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + u16 ctl_reg; + u8 reg_val, pinctl_position; + + pinctl_position = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + switch (pinctl_position >> 3) { + case 0: + ctl_reg = WCD934X_TEST_DEBUG_PIN_CTL_OE_0; + break; + case 1: + ctl_reg = WCD934X_TEST_DEBUG_PIN_CTL_OE_1; + break; + case 2: + ctl_reg = WCD934X_TEST_DEBUG_PIN_CTL_OE_2; + break; + case 3: + ctl_reg = WCD934X_TEST_DEBUG_PIN_CTL_OE_3; + break; + default: + dev_err(codec->dev, "%s: Invalid pinctl position = %d\n", + __func__, pinctl_position); + return -EINVAL; + } + + reg_val = snd_soc_read(codec, ctl_reg); + reg_val = (reg_val >> (pinctl_position & 0x07)) & 0x1; + ucontrol->value.integer.value[0] = reg_val; + + return 0; +} + +static int tavil_dmic_pin_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + u16 ctl_reg, cfg_reg; + u8 ctl_val, cfg_val, pinctl_position, pinctl_mode, mask; + + /* 1- high or low; 0- high Z */ + pinctl_mode = ucontrol->value.integer.value[0]; + pinctl_position = ((struct soc_multi_mixer_control *) + kcontrol->private_value)->shift; + + switch (pinctl_position >> 3) { + case 0: + ctl_reg = WCD934X_TEST_DEBUG_PIN_CTL_OE_0; + break; + case 1: + ctl_reg = WCD934X_TEST_DEBUG_PIN_CTL_OE_1; + break; + case 2: + ctl_reg = WCD934X_TEST_DEBUG_PIN_CTL_OE_2; + break; + case 3: + ctl_reg = WCD934X_TEST_DEBUG_PIN_CTL_OE_3; + break; + default: + dev_err(codec->dev, "%s: Invalid pinctl position = %d\n", + __func__, pinctl_position); + return -EINVAL; + } + + ctl_val = pinctl_mode << (pinctl_position & 0x07); + mask = 1 << (pinctl_position & 0x07); + snd_soc_update_bits(codec, ctl_reg, mask, ctl_val); + + cfg_reg = WCD934X_TLMM_BIST_MODE_PINCFG + pinctl_position; + if (!pinctl_mode) + cfg_val = 0x4; + else + cfg_val = 0; + snd_soc_update_bits(codec, cfg_reg, 0x07, cfg_val); + + dev_dbg(codec->dev, "%s: reg=0x%x mask=0x%x val=%d reg=0x%x val=%d\n", + __func__, ctl_reg, mask, ctl_val, cfg_reg, cfg_val); + + return 0; +} + +static int tavil_amic_pwr_lvl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + u16 amic_reg; + + if (!strcmp(kcontrol->id.name, "AMIC_1_2 PWR MODE")) + amic_reg = WCD934X_ANA_AMIC1; + if (!strcmp(kcontrol->id.name, "AMIC_3_4 PWR MODE")) + amic_reg = WCD934X_ANA_AMIC3; + else + goto ret; + + ucontrol->value.integer.value[0] = + (snd_soc_read(codec, amic_reg) & WCD934X_AMIC_PWR_LVL_MASK) >> + WCD934X_AMIC_PWR_LVL_SHIFT; +ret: + return 0; +} + +static int tavil_amic_pwr_lvl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + u32 mode_val; + u16 amic_reg; + + mode_val = ucontrol->value.enumerated.item[0]; + + dev_dbg(codec->dev, "%s: mode: %d\n", __func__, mode_val); + + if (!strcmp(kcontrol->id.name, "AMIC_1_2 PWR MODE")) + amic_reg = WCD934X_ANA_AMIC1; + if (!strcmp(kcontrol->id.name, "AMIC_3_4 PWR MODE")) + amic_reg = WCD934X_ANA_AMIC3; + else + goto ret; + + snd_soc_update_bits(codec, amic_reg, WCD934X_AMIC_PWR_LVL_MASK, + mode_val << WCD934X_AMIC_PWR_LVL_SHIFT); + +ret: + return 0; +} + +static int tavil_ear_pa_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 ear_pa_gain; + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + + ear_pa_gain = snd_soc_read(codec, WCD934X_ANA_EAR); + + ear_pa_gain = (ear_pa_gain & 0x70) >> 4; + + ucontrol->value.integer.value[0] = ear_pa_gain; + + dev_dbg(codec->dev, "%s: ear_pa_gain = 0x%x\n", __func__, + ear_pa_gain); + + return 0; +} + +static int tavil_ear_pa_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + u8 ear_pa_gain; + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + + dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + ear_pa_gain = ucontrol->value.integer.value[0] << 4; + + snd_soc_update_bits(codec, WCD934X_ANA_EAR, 0x70, ear_pa_gain); + return 0; +} + +/* Cutoff frequency for high pass filter */ +static const char * const cf_text[] = { + "CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ" +}; + +static const char * const rx_cf_text[] = { + "CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ", + "CF_NEG_3DB_0P48HZ" +}; + +static const char * const amic_pwr_lvl_text[] = { + "LOW_PWR", "DEFAULT", "HIGH_PERF" +}; + +static const char * const tavil_ear_pa_gain_text[] = { + "G_6_DB", "G_4P5_DB", "G_3_DB", "G_1P5_DB", + "G_0_DB", "G_M2P5_DB", "UNDEFINED", "G_M12_DB" +}; + +static SOC_ENUM_SINGLE_EXT_DECL(tavil_ear_pa_gain_enum, tavil_ear_pa_gain_text); +static SOC_ENUM_SINGLE_EXT_DECL(amic_pwr_lvl_enum, amic_pwr_lvl_text); +static SOC_ENUM_SINGLE_DECL(cf_dec0_enum, WCD934X_CDC_TX0_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec1_enum, WCD934X_CDC_TX1_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec2_enum, WCD934X_CDC_TX2_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec3_enum, WCD934X_CDC_TX3_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec4_enum, WCD934X_CDC_TX4_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec5_enum, WCD934X_CDC_TX5_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec6_enum, WCD934X_CDC_TX6_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec7_enum, WCD934X_CDC_TX7_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_dec8_enum, WCD934X_CDC_TX8_TX_PATH_CFG0, 5, + cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int0_1_enum, WCD934X_CDC_RX0_RX_PATH_CFG2, 0, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int0_2_enum, WCD934X_CDC_RX0_RX_PATH_MIX_CFG, 2, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int1_1_enum, WCD934X_CDC_RX1_RX_PATH_CFG2, 0, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int1_2_enum, WCD934X_CDC_RX1_RX_PATH_MIX_CFG, 2, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int2_1_enum, WCD934X_CDC_RX2_RX_PATH_CFG2, 0, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int2_2_enum, WCD934X_CDC_RX2_RX_PATH_MIX_CFG, 2, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int3_1_enum, WCD934X_CDC_RX3_RX_PATH_CFG2, 0, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int3_2_enum, WCD934X_CDC_RX3_RX_PATH_MIX_CFG, 2, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int4_1_enum, WCD934X_CDC_RX4_RX_PATH_CFG2, 0, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int4_2_enum, WCD934X_CDC_RX4_RX_PATH_MIX_CFG, 2, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int7_1_enum, WCD934X_CDC_RX7_RX_PATH_CFG2, 0, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int7_2_enum, WCD934X_CDC_RX7_RX_PATH_MIX_CFG, 2, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int8_1_enum, WCD934X_CDC_RX8_RX_PATH_CFG2, 0, + rx_cf_text); +static SOC_ENUM_SINGLE_DECL(cf_int8_2_enum, WCD934X_CDC_RX8_RX_PATH_MIX_CFG, 2, + rx_cf_text); + +static const struct snd_kcontrol_new tavil_snd_controls[] = { + SOC_ENUM_EXT("EAR PA Gain", tavil_ear_pa_gain_enum, + tavil_ear_pa_gain_get, tavil_ear_pa_gain_put), + SOC_SINGLE_TLV("HPHL Volume", WCD934X_HPH_L_EN, 0, 20, 1, line_gain), + SOC_SINGLE_TLV("HPHR Volume", WCD934X_HPH_R_EN, 0, 20, 1, line_gain), + SOC_SINGLE_TLV("LINEOUT1 Volume", WCD934X_DIFF_LO_LO1_COMPANDER, + 3, 16, 1, line_gain), + SOC_SINGLE_TLV("LINEOUT2 Volume", WCD934X_DIFF_LO_LO2_COMPANDER, + 3, 16, 1, line_gain), + SOC_SINGLE_TLV("ADC1 Volume", WCD934X_ANA_AMIC1, 0, 20, 0, analog_gain), + SOC_SINGLE_TLV("ADC2 Volume", WCD934X_ANA_AMIC2, 0, 20, 0, analog_gain), + SOC_SINGLE_TLV("ADC3 Volume", WCD934X_ANA_AMIC3, 0, 20, 0, analog_gain), + SOC_SINGLE_TLV("ADC4 Volume", WCD934X_ANA_AMIC4, 0, 20, 0, analog_gain), + + SOC_SINGLE_SX_TLV("RX0 Digital Volume", WCD934X_CDC_RX0_RX_VOL_CTL, + 0, -84, 40, digital_gain), /* -84dB min - 40dB max */ + SOC_SINGLE_SX_TLV("RX1 Digital Volume", WCD934X_CDC_RX1_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX2 Digital Volume", WCD934X_CDC_RX2_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX3 Digital Volume", WCD934X_CDC_RX3_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX4 Digital Volume", WCD934X_CDC_RX4_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX7 Digital Volume", WCD934X_CDC_RX7_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX8 Digital Volume", WCD934X_CDC_RX8_RX_VOL_CTL, + 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX0 Mix Digital Volume", + WCD934X_CDC_RX0_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX1 Mix Digital Volume", + WCD934X_CDC_RX1_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX2 Mix Digital Volume", + WCD934X_CDC_RX2_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX3 Mix Digital Volume", + WCD934X_CDC_RX3_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX4 Mix Digital Volume", + WCD934X_CDC_RX4_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX7 Mix Digital Volume", + WCD934X_CDC_RX7_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("RX8 Mix Digital Volume", + WCD934X_CDC_RX8_RX_VOL_MIX_CTL, 0, -84, 40, digital_gain), + + SOC_SINGLE_SX_TLV("DEC0 Volume", WCD934X_CDC_TX0_TX_VOL_CTL, 0, + -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("DEC1 Volume", WCD934X_CDC_TX1_TX_VOL_CTL, 0, + -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("DEC2 Volume", WCD934X_CDC_TX2_TX_VOL_CTL, 0, + -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("DEC3 Volume", WCD934X_CDC_TX3_TX_VOL_CTL, 0, + -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("DEC4 Volume", WCD934X_CDC_TX4_TX_VOL_CTL, 0, + -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("DEC7 Volume", WCD934X_CDC_TX7_TX_VOL_CTL, 0, + -84, 40, digital_gain), + SOC_SINGLE_SX_TLV("DEC8 Volume", WCD934X_CDC_TX8_TX_VOL_CTL, 0, + -84, 40, digital_gain), + + SOC_SINGLE_SX_TLV("IIR0 INP0 Volume", + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL, 0, -84, 40, + digital_gain), + SOC_SINGLE_SX_TLV("IIR0 INP1 Volume", + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL, 0, -84, 40, + digital_gain), + SOC_SINGLE_SX_TLV("IIR0 INP2 Volume", + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL, 0, -84, 40, + digital_gain), + SOC_SINGLE_SX_TLV("IIR0 INP3 Volume", + WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL, 0, -84, 40, + digital_gain), + SOC_SINGLE_SX_TLV("IIR1 INP0 Volume", + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL, 0, -84, 40, + digital_gain), + SOC_SINGLE_SX_TLV("IIR1 INP1 Volume", + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL, 0, -84, 40, + digital_gain), + SOC_SINGLE_SX_TLV("IIR1 INP2 Volume", + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL, 0, -84, 40, + digital_gain), + SOC_SINGLE_SX_TLV("IIR1 INP3 Volume", + WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL, 0, -84, 40, + digital_gain), + + SOC_ENUM("TX0 HPF cut off", cf_dec0_enum), + SOC_ENUM("TX1 HPF cut off", cf_dec1_enum), + SOC_ENUM("TX2 HPF cut off", cf_dec2_enum), + SOC_ENUM("TX3 HPF cut off", cf_dec3_enum), + SOC_ENUM("TX4 HPF cut off", cf_dec4_enum), + SOC_ENUM("TX5 HPF cut off", cf_dec5_enum), + SOC_ENUM("TX6 HPF cut off", cf_dec6_enum), + SOC_ENUM("TX7 HPF cut off", cf_dec7_enum), + SOC_ENUM("TX8 HPF cut off", cf_dec8_enum), + + SOC_ENUM("RX INT0_1 HPF cut off", cf_int0_1_enum), + SOC_ENUM("RX INT0_2 HPF cut off", cf_int0_2_enum), + SOC_ENUM("RX INT1_1 HPF cut off", cf_int1_1_enum), + SOC_ENUM("RX INT1_2 HPF cut off", cf_int1_2_enum), + SOC_ENUM("RX INT2_1 HPF cut off", cf_int2_1_enum), + SOC_ENUM("RX INT2_2 HPF cut off", cf_int2_2_enum), + SOC_ENUM("RX INT3_1 HPF cut off", cf_int3_1_enum), + SOC_ENUM("RX INT3_2 HPF cut off", cf_int3_2_enum), + SOC_ENUM("RX INT4_1 HPF cut off", cf_int4_1_enum), + SOC_ENUM("RX INT4_2 HPF cut off", cf_int4_2_enum), + SOC_ENUM("RX INT7_1 HPF cut off", cf_int7_1_enum), + SOC_ENUM("RX INT7_2 HPF cut off", cf_int7_2_enum), + SOC_ENUM("RX INT8_1 HPF cut off", cf_int8_1_enum), + SOC_ENUM("RX INT8_2 HPF cut off", cf_int8_2_enum), + + SOC_SINGLE_EXT("IIR0 Enable Band1", IIR0, BAND1, 1, 0, + tavil_iir_enable_audio_mixer_get, + tavil_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR0 Enable Band2", IIR0, BAND2, 1, 0, + tavil_iir_enable_audio_mixer_get, + tavil_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR0 Enable Band3", IIR0, BAND3, 1, 0, + tavil_iir_enable_audio_mixer_get, + tavil_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR0 Enable Band4", IIR0, BAND4, 1, 0, + tavil_iir_enable_audio_mixer_get, + tavil_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR0 Enable Band5", IIR0, BAND5, 1, 0, + tavil_iir_enable_audio_mixer_get, + tavil_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0, + tavil_iir_enable_audio_mixer_get, + tavil_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0, + tavil_iir_enable_audio_mixer_get, + tavil_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0, + tavil_iir_enable_audio_mixer_get, + tavil_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0, + tavil_iir_enable_audio_mixer_get, + tavil_iir_enable_audio_mixer_put), + SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0, + tavil_iir_enable_audio_mixer_get, + tavil_iir_enable_audio_mixer_put), + + SOC_SINGLE_MULTI_EXT("IIR0 Band1", IIR0, BAND1, 255, 0, 5, + tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR0 Band2", IIR0, BAND2, 255, 0, 5, + tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR0 Band3", IIR0, BAND3, 255, 0, 5, + tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR0 Band4", IIR0, BAND4, 255, 0, 5, + tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR0 Band5", IIR0, BAND5, 255, 0, 5, + tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5, + tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5, + tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5, + tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5, + tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put), + SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5, + tavil_iir_band_audio_mixer_get, tavil_iir_band_audio_mixer_put), + + SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMPANDER_1, 1, 0, + tavil_compander_get, tavil_compander_put), + SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0, + tavil_compander_get, tavil_compander_put), + SOC_SINGLE_EXT("COMP3 Switch", SND_SOC_NOPM, COMPANDER_3, 1, 0, + tavil_compander_get, tavil_compander_put), + SOC_SINGLE_EXT("COMP4 Switch", SND_SOC_NOPM, COMPANDER_4, 1, 0, + tavil_compander_get, tavil_compander_put), + SOC_SINGLE_EXT("COMP7 Switch", SND_SOC_NOPM, COMPANDER_7, 1, 0, + tavil_compander_get, tavil_compander_put), + SOC_SINGLE_EXT("COMP8 Switch", SND_SOC_NOPM, COMPANDER_8, 1, 0, + tavil_compander_get, tavil_compander_put), + + SOC_SINGLE_EXT("DMIC1_CLK_PIN_MODE", SND_SOC_NOPM, 17, 1, 0, + tavil_dmic_pin_mode_get, tavil_dmic_pin_mode_put), + + SOC_SINGLE_EXT("DMIC1_DATA_PIN_MODE", SND_SOC_NOPM, 18, 1, 0, + tavil_dmic_pin_mode_get, tavil_dmic_pin_mode_put), + + SOC_SINGLE_EXT("DMIC2_CLK_PIN_MODE", SND_SOC_NOPM, 19, 1, 0, + tavil_dmic_pin_mode_get, tavil_dmic_pin_mode_put), + + SOC_SINGLE_EXT("DMIC2_DATA_PIN_MODE", SND_SOC_NOPM, 20, 1, 0, + tavil_dmic_pin_mode_get, tavil_dmic_pin_mode_put), + + SOC_SINGLE_EXT("DMIC3_CLK_PIN_MODE", SND_SOC_NOPM, 21, 1, 0, + tavil_dmic_pin_mode_get, tavil_dmic_pin_mode_put), + + SOC_SINGLE_EXT("DMIC3_DATA_PIN_MODE", SND_SOC_NOPM, 22, 1, 0, + tavil_dmic_pin_mode_get, tavil_dmic_pin_mode_put), + SOC_ENUM_EXT("AMIC_1_2 PWR MODE", amic_pwr_lvl_enum, + tavil_amic_pwr_lvl_get, tavil_amic_pwr_lvl_put), + SOC_ENUM_EXT("AMIC_3_4 PWR MODE", amic_pwr_lvl_enum, + tavil_amic_pwr_lvl_get, tavil_amic_pwr_lvl_put), + SOC_ENUM_EXT("AMIC_5_6 PWR MODE", amic_pwr_lvl_enum, + tavil_amic_pwr_lvl_get, tavil_amic_pwr_lvl_put), +}; + +static int tavil_dec_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget_list *wlist = + dapm_kcontrol_get_wlist(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int val; + u16 mic_sel_reg = 0; + u8 mic_sel; + + val = ucontrol->value.enumerated.item[0]; + if (val > e->items - 1) + return -EINVAL; + + dev_dbg(codec->dev, "%s: wname: %s, val: 0x%x\n", __func__, + widget->name, val); + + switch (e->reg) { + case WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1: + if (e->shift_l == 0) + mic_sel_reg = WCD934X_CDC_TX0_TX_PATH_CFG0; + else if (e->shift_l == 2) + mic_sel_reg = WCD934X_CDC_TX4_TX_PATH_CFG0; + else if (e->shift_l == 4) + mic_sel_reg = WCD934X_CDC_TX8_TX_PATH_CFG0; + break; + case WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1: + if (e->shift_l == 0) + mic_sel_reg = WCD934X_CDC_TX1_TX_PATH_CFG0; + else if (e->shift_l == 2) + mic_sel_reg = WCD934X_CDC_TX5_TX_PATH_CFG0; + break; + case WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG1: + if (e->shift_l == 0) + mic_sel_reg = WCD934X_CDC_TX2_TX_PATH_CFG0; + else if (e->shift_l == 2) + mic_sel_reg = WCD934X_CDC_TX6_TX_PATH_CFG0; + break; + case WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1: + if (e->shift_l == 0) + mic_sel_reg = WCD934X_CDC_TX3_TX_PATH_CFG0; + else if (e->shift_l == 2) + mic_sel_reg = WCD934X_CDC_TX7_TX_PATH_CFG0; + break; + default: + dev_err(codec->dev, "%s: e->reg: 0x%x not expected\n", + __func__, e->reg); + return -EINVAL; + } + + /* ADC: 0, DMIC: 1 */ + mic_sel = val ? 0x0 : 0x1; + if (mic_sel_reg) + snd_soc_update_bits(codec, mic_sel_reg, 1 << 7, mic_sel << 7); + + return snd_soc_dapm_put_enum_double(kcontrol, ucontrol); +} + +static int tavil_int_dem_inp_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget_list *wlist = + dapm_kcontrol_get_wlist(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int val; + unsigned short look_ahead_dly_reg = WCD934X_CDC_RX0_RX_PATH_CFG0; + + val = ucontrol->value.enumerated.item[0]; + if (val >= e->items) + return -EINVAL; + + dev_dbg(codec->dev, "%s: wname: %s, val: 0x%x\n", __func__, + widget->name, val); + + if (e->reg == WCD934X_CDC_RX0_RX_PATH_SEC0) + look_ahead_dly_reg = WCD934X_CDC_RX0_RX_PATH_CFG0; + else if (e->reg == WCD934X_CDC_RX1_RX_PATH_SEC0) + look_ahead_dly_reg = WCD934X_CDC_RX1_RX_PATH_CFG0; + else if (e->reg == WCD934X_CDC_RX2_RX_PATH_SEC0) + look_ahead_dly_reg = WCD934X_CDC_RX2_RX_PATH_CFG0; + + /* Set Look Ahead Delay */ + snd_soc_update_bits(codec, look_ahead_dly_reg, + 0x08, (val ? 0x08 : 0x00)); + /* Set DEM INP Select */ + return snd_soc_dapm_put_enum_double(kcontrol, ucontrol); +} + +static const char * const rx_int0_7_mix_mux_text[] = { + "ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", + "RX6", "RX7", "PROXIMITY" +}; + +static const char * const rx_int_mix_mux_text[] = { + "ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", + "RX6", "RX7" +}; + +static const char * const rx_prim_mix_text[] = { + "ZERO", "DEC0", "DEC1", "IIR0", "IIR1", "RX0", "RX1", "RX2", + "RX3", "RX4", "RX5", "RX6", "RX7" +}; + +static const char * const rx_sidetone_mix_text[] = { + "ZERO", "SRC0", "SRC1", "SRC_SUM" +}; + +static const char * const cdc_if_tx0_mux_text[] = { + "ZERO", "RX_MIX_TX0", "DEC0", "DEC0_192" +}; +static const char * const cdc_if_tx1_mux_text[] = { + "ZERO", "RX_MIX_TX1", "DEC1", "DEC1_192" +}; +static const char * const cdc_if_tx2_mux_text[] = { + "ZERO", "RX_MIX_TX2", "DEC2", "DEC2_192" +}; +static const char * const cdc_if_tx3_mux_text[] = { + "ZERO", "RX_MIX_TX3", "DEC3", "DEC3_192" +}; +static const char * const cdc_if_tx4_mux_text[] = { + "ZERO", "RX_MIX_TX4", "DEC4", "DEC4_192" +}; +static const char * const cdc_if_tx5_mux_text[] = { + "ZERO", "RX_MIX_TX5", "DEC5", "DEC5_192" +}; +static const char * const cdc_if_tx6_mux_text[] = { + "ZERO", "RX_MIX_TX6", "DEC6", "DEC6_192" +}; +static const char * const cdc_if_tx7_mux_text[] = { + "ZERO", "RX_MIX_TX7", "DEC7", "DEC7_192" +}; +static const char * const cdc_if_tx8_mux_text[] = { + "ZERO", "RX_MIX_TX8", "DEC8", "DEC8_192" +}; +static const char * const cdc_if_tx9_mux_text[] = { + "ZERO", "DEC7", "DEC7_192" +}; +static const char * const cdc_if_tx10_mux_text[] = { + "ZERO", "DEC6", "DEC6_192" +}; +static const char * const cdc_if_tx11_mux_text[] = { + "DEC_0_5", "DEC_9_12", "MAD_AUDIO", "MAD_BRDCST" +}; +static const char * const cdc_if_tx11_inp1_mux_text[] = { + "ZERO", "DEC0", "DEC1", "DEC2", "DEC3", "DEC4", + "DEC5", "RX_MIX_TX5", "DEC9_10", "DEC11_12" +}; +static const char * const cdc_if_tx13_mux_text[] = { + "CDC_DEC_5", "MAD_BRDCST" +}; +static const char * const cdc_if_tx13_inp1_mux_text[] = { + "ZERO", "DEC5", "DEC5_192" +}; + +static const char * const iir_inp_mux_text[] = { + "ZERO", "DEC0", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", + "DEC7", "DEC8", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7" +}; + +static const char * const rx_int_dem_inp_mux_text[] = { + "NORMAL_DSM_OUT", "CLSH_DSM_OUT", +}; + +static const char * const rx_int0_interp_mux_text[] = { + "ZERO", "RX INT0 MIX2", +}; + +static const char * const rx_int1_interp_mux_text[] = { + "ZERO", "RX INT1 MIX2", +}; + +static const char * const rx_int2_interp_mux_text[] = { + "ZERO", "RX INT2 MIX2", +}; + +static const char * const rx_int3_interp_mux_text[] = { + "ZERO", "RX INT3 MIX2", +}; + +static const char * const rx_int4_interp_mux_text[] = { + "ZERO", "RX INT4 MIX2", +}; + +static const char * const rx_int7_interp_mux_text[] = { + "ZERO", "RX INT7 MIX2", +}; + +static const char * const rx_int8_interp_mux_text[] = { + "ZERO", "RX INT8 SEC MIX" +}; + +static const char * const adc_mux_text[] = { + "DMIC", "AMIC", "ANC_FB_TUNE1", "ANC_FB_TUNE2" +}; + +static const char * const dmic_mux_text[] = { + "ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5" +}; + +static const char * const amic_mux_text[] = { + "ZERO", "ADC1", "ADC2", "ADC3", "ADC4" +}; + +static const char * const amic4_5_sel_text[] = { + "AMIC4", "AMIC5" +}; + +static const char * const rx_echo_mux_text[] = { + "ZERO", "RX_MIX0", "RX_MIX1", "RX_MIX2", "RX_MIX3", "RX_MIX4", + "RX_MIX5", "RX_MIX6", "RX_MIX7", "RX_MIX8" +}; + +static const char *const slim_rx_mux_text[] = { + "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB", "AIF4_PB" +}; + +static const char *const cdc_if_rx0_mux_text[] = { + "SLIM RX0", "I2S_0 RX0" +}; +static const char *const cdc_if_rx1_mux_text[] = { + "SLIM RX1", "I2S_0 RX1" +}; +static const char *const cdc_if_rx2_mux_text[] = { + "SLIM RX2", "I2S_0 RX2" +}; +static const char *const cdc_if_rx3_mux_text[] = { + "SLIM RX3", "I2S_0 RX3" +}; +static const char *const cdc_if_rx4_mux_text[] = { + "SLIM RX4", "I2S_0 RX4" +}; +static const char *const cdc_if_rx5_mux_text[] = { + "SLIM RX5", "I2S_0 RX5" +}; +static const char *const cdc_if_rx6_mux_text[] = { + "SLIM RX6", "I2S_0 RX6" +}; +static const char *const cdc_if_rx7_mux_text[] = { + "SLIM RX7", "I2S_0 RX7" +}; + +static const struct snd_kcontrol_new aif1_cap_mixer[] = { + SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD934X_TX0, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD934X_TX1, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD934X_TX2, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD934X_TX3, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD934X_TX4, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD934X_TX5, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD934X_TX6, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD934X_TX7, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD934X_TX8, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, WCD934X_TX9, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, WCD934X_TX10, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, WCD934X_TX11, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, WCD934X_TX13, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), +}; + +static const struct snd_kcontrol_new aif2_cap_mixer[] = { + SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD934X_TX0, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD934X_TX1, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD934X_TX2, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD934X_TX3, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD934X_TX4, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD934X_TX5, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD934X_TX6, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD934X_TX7, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD934X_TX8, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, WCD934X_TX9, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, WCD934X_TX10, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, WCD934X_TX11, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, WCD934X_TX13, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), +}; + +static const struct snd_kcontrol_new aif3_cap_mixer[] = { + SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD934X_TX0, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD934X_TX1, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD934X_TX2, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD934X_TX3, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD934X_TX4, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD934X_TX5, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD934X_TX6, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD934X_TX7, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD934X_TX8, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, WCD934X_TX9, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, WCD934X_TX10, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, WCD934X_TX11, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), + SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, WCD934X_TX13, 1, 0, + slim_tx_mixer_get, slim_tx_mixer_put), +}; + +WCD_DAPM_ENUM_EXT(slim_rx0, SND_SOC_NOPM, 0, slim_rx_mux_text, + slim_rx_mux_get, slim_rx_mux_put); +WCD_DAPM_ENUM_EXT(slim_rx1, SND_SOC_NOPM, 0, slim_rx_mux_text, + slim_rx_mux_get, slim_rx_mux_put); +WCD_DAPM_ENUM_EXT(slim_rx2, SND_SOC_NOPM, 0, slim_rx_mux_text, + slim_rx_mux_get, slim_rx_mux_put); +WCD_DAPM_ENUM_EXT(slim_rx3, SND_SOC_NOPM, 0, slim_rx_mux_text, + slim_rx_mux_get, slim_rx_mux_put); +WCD_DAPM_ENUM_EXT(slim_rx4, SND_SOC_NOPM, 0, slim_rx_mux_text, + slim_rx_mux_get, slim_rx_mux_put); +WCD_DAPM_ENUM_EXT(slim_rx5, SND_SOC_NOPM, 0, slim_rx_mux_text, + slim_rx_mux_get, slim_rx_mux_put); +WCD_DAPM_ENUM_EXT(slim_rx6, SND_SOC_NOPM, 0, slim_rx_mux_text, + slim_rx_mux_get, slim_rx_mux_put); +WCD_DAPM_ENUM_EXT(slim_rx7, SND_SOC_NOPM, 0, slim_rx_mux_text, + slim_rx_mux_get, slim_rx_mux_put); + +WCD_DAPM_ENUM(cdc_if_rx0, SND_SOC_NOPM, 0, cdc_if_rx0_mux_text); +WCD_DAPM_ENUM(cdc_if_rx1, SND_SOC_NOPM, 0, cdc_if_rx1_mux_text); +WCD_DAPM_ENUM(cdc_if_rx2, SND_SOC_NOPM, 0, cdc_if_rx2_mux_text); +WCD_DAPM_ENUM(cdc_if_rx3, SND_SOC_NOPM, 0, cdc_if_rx3_mux_text); +WCD_DAPM_ENUM(cdc_if_rx4, SND_SOC_NOPM, 0, cdc_if_rx4_mux_text); +WCD_DAPM_ENUM(cdc_if_rx5, SND_SOC_NOPM, 0, cdc_if_rx5_mux_text); +WCD_DAPM_ENUM(cdc_if_rx6, SND_SOC_NOPM, 0, cdc_if_rx6_mux_text); +WCD_DAPM_ENUM(cdc_if_rx7, SND_SOC_NOPM, 0, cdc_if_rx7_mux_text); + +WCD_DAPM_ENUM(rx_int0_2, WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG1, 0, + rx_int0_7_mix_mux_text); +WCD_DAPM_ENUM(rx_int1_2, WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG1, 0, + rx_int_mix_mux_text); +WCD_DAPM_ENUM(rx_int2_2, WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG1, 0, + rx_int_mix_mux_text); +WCD_DAPM_ENUM(rx_int3_2, WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG1, 0, + rx_int_mix_mux_text); +WCD_DAPM_ENUM(rx_int4_2, WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG1, 0, + rx_int_mix_mux_text); +WCD_DAPM_ENUM(rx_int7_2, WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG1, 0, + rx_int0_7_mix_mux_text); +WCD_DAPM_ENUM(rx_int8_2, WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG1, 0, + rx_int_mix_mux_text); + +WCD_DAPM_ENUM(rx_int0_1_mix_inp0, WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG0, 0, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int0_1_mix_inp1, WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG0, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int0_1_mix_inp2, WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG1, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int1_1_mix_inp0, WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG0, 0, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int1_1_mix_inp1, WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG0, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int1_1_mix_inp2, WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG1, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int2_1_mix_inp0, WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG0, 0, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int2_1_mix_inp1, WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG0, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int2_1_mix_inp2, WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG1, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int3_1_mix_inp0, WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG0, 0, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int3_1_mix_inp1, WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG0, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int3_1_mix_inp2, WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG1, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int4_1_mix_inp0, WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG0, 0, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int4_1_mix_inp1, WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG0, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int4_1_mix_inp2, WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG1, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int7_1_mix_inp0, WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG0, 0, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int7_1_mix_inp1, WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG0, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int7_1_mix_inp2, WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG1, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int8_1_mix_inp0, WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG0, 0, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int8_1_mix_inp1, WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG0, 4, + rx_prim_mix_text); +WCD_DAPM_ENUM(rx_int8_1_mix_inp2, WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG1, 4, + rx_prim_mix_text); + +WCD_DAPM_ENUM(rx_int0_mix2_inp, WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 0, + rx_sidetone_mix_text); +WCD_DAPM_ENUM(rx_int1_mix2_inp, WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 2, + rx_sidetone_mix_text); +WCD_DAPM_ENUM(rx_int2_mix2_inp, WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 4, + rx_sidetone_mix_text); +WCD_DAPM_ENUM(rx_int3_mix2_inp, WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0, 6, + rx_sidetone_mix_text); +WCD_DAPM_ENUM(rx_int4_mix2_inp, WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1, 0, + rx_sidetone_mix_text); +WCD_DAPM_ENUM(rx_int7_mix2_inp, WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1, 2, + rx_sidetone_mix_text); + +WCD_DAPM_ENUM(tx_adc_mux10, WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 4, + adc_mux_text); +WCD_DAPM_ENUM(tx_adc_mux11, WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 4, + adc_mux_text); +WCD_DAPM_ENUM(tx_adc_mux12, WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1, 4, + adc_mux_text); +WCD_DAPM_ENUM(tx_adc_mux13, WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 6, + adc_mux_text); + + +WCD_DAPM_ENUM(tx_dmic_mux0, WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux1, WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux2, WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux3, WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux4, WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux5, WCD934X_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux6, WCD934X_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux7, WCD934X_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux8, WCD934X_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux10, WCD934X_CDC_TX_INP_MUX_ADC_MUX10_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux11, WCD934X_CDC_TX_INP_MUX_ADC_MUX11_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux12, WCD934X_CDC_TX_INP_MUX_ADC_MUX12_CFG0, 3, + dmic_mux_text); +WCD_DAPM_ENUM(tx_dmic_mux13, WCD934X_CDC_TX_INP_MUX_ADC_MUX13_CFG0, 3, + dmic_mux_text); + + +WCD_DAPM_ENUM(tx_amic_mux0, WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux1, WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux2, WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux3, WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux4, WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux5, WCD934X_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux6, WCD934X_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux7, WCD934X_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux8, WCD934X_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux10, WCD934X_CDC_TX_INP_MUX_ADC_MUX10_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux11, WCD934X_CDC_TX_INP_MUX_ADC_MUX11_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux12, WCD934X_CDC_TX_INP_MUX_ADC_MUX12_CFG0, 0, + amic_mux_text); +WCD_DAPM_ENUM(tx_amic_mux13, WCD934X_CDC_TX_INP_MUX_ADC_MUX13_CFG0, 0, + amic_mux_text); + +WCD_DAPM_ENUM(tx_amic4_5, WCD934X_TX_NEW_AMIC_4_5_SEL, 7, amic4_5_sel_text); + +WCD_DAPM_ENUM(cdc_if_tx0, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0, 0, + cdc_if_tx0_mux_text); +WCD_DAPM_ENUM(cdc_if_tx1, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0, 2, + cdc_if_tx1_mux_text); +WCD_DAPM_ENUM(cdc_if_tx2, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0, 4, + cdc_if_tx2_mux_text); +WCD_DAPM_ENUM(cdc_if_tx3, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0, 6, + cdc_if_tx3_mux_text); +WCD_DAPM_ENUM(cdc_if_tx4, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1, 0, + cdc_if_tx4_mux_text); +WCD_DAPM_ENUM(cdc_if_tx5, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1, 2, + cdc_if_tx5_mux_text); +WCD_DAPM_ENUM(cdc_if_tx6, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1, 4, + cdc_if_tx6_mux_text); +WCD_DAPM_ENUM(cdc_if_tx7, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1, 6, + cdc_if_tx7_mux_text); +WCD_DAPM_ENUM(cdc_if_tx8, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2, 0, + cdc_if_tx8_mux_text); +WCD_DAPM_ENUM(cdc_if_tx9, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2, 2, + cdc_if_tx9_mux_text); +WCD_DAPM_ENUM(cdc_if_tx10, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2, 4, + cdc_if_tx10_mux_text); +WCD_DAPM_ENUM(cdc_if_tx11_inp1, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3, 0, + cdc_if_tx11_inp1_mux_text); +WCD_DAPM_ENUM(cdc_if_tx11, WCD934X_DATA_HUB_SB_TX11_INP_CFG, 0, + cdc_if_tx11_mux_text); +WCD_DAPM_ENUM(cdc_if_tx13_inp1, WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3, 4, + cdc_if_tx13_inp1_mux_text); +WCD_DAPM_ENUM(cdc_if_tx13, WCD934X_DATA_HUB_SB_TX13_INP_CFG, 0, + cdc_if_tx13_mux_text); + +WCD_DAPM_ENUM(rx_mix_tx0, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG0, 0, + rx_echo_mux_text); +WCD_DAPM_ENUM(rx_mix_tx1, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG0, 4, + rx_echo_mux_text); +WCD_DAPM_ENUM(rx_mix_tx2, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG1, 0, + rx_echo_mux_text); +WCD_DAPM_ENUM(rx_mix_tx3, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG1, 4, + rx_echo_mux_text); +WCD_DAPM_ENUM(rx_mix_tx4, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG2, 0, + rx_echo_mux_text); +WCD_DAPM_ENUM(rx_mix_tx5, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG2, 4, + rx_echo_mux_text); +WCD_DAPM_ENUM(rx_mix_tx6, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG3, 0, + rx_echo_mux_text); +WCD_DAPM_ENUM(rx_mix_tx7, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG3, 4, + rx_echo_mux_text); +WCD_DAPM_ENUM(rx_mix_tx8, WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG4, 0, + rx_echo_mux_text); + +WCD_DAPM_ENUM(iir0_inp0, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0, 0, + iir_inp_mux_text); +WCD_DAPM_ENUM(iir0_inp1, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG1, 0, + iir_inp_mux_text); +WCD_DAPM_ENUM(iir0_inp2, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG2, 0, + iir_inp_mux_text); +WCD_DAPM_ENUM(iir0_inp3, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG3, 0, + iir_inp_mux_text); +WCD_DAPM_ENUM(iir1_inp0, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG0, 0, + iir_inp_mux_text); +WCD_DAPM_ENUM(iir1_inp1, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG1, 0, + iir_inp_mux_text); +WCD_DAPM_ENUM(iir1_inp2, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG2, 0, + iir_inp_mux_text); +WCD_DAPM_ENUM(iir1_inp3, WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG3, 0, + iir_inp_mux_text); + +WCD_DAPM_ENUM(rx_int0_interp, WCD934X_CDC_RX0_RX_PATH_CTL, 5, + rx_int0_interp_mux_text); +WCD_DAPM_ENUM(rx_int1_interp, WCD934X_CDC_RX1_RX_PATH_CTL, 5, + rx_int1_interp_mux_text); +WCD_DAPM_ENUM(rx_int2_interp, WCD934X_CDC_RX2_RX_PATH_CTL, 5, + rx_int2_interp_mux_text); +WCD_DAPM_ENUM(rx_int3_interp, WCD934X_CDC_RX3_RX_PATH_CTL, 5, + rx_int3_interp_mux_text); +WCD_DAPM_ENUM(rx_int4_interp, WCD934X_CDC_RX4_RX_PATH_CTL, 5, + rx_int4_interp_mux_text); +WCD_DAPM_ENUM(rx_int7_interp, WCD934X_CDC_RX7_RX_PATH_CTL, 5, + rx_int7_interp_mux_text); +WCD_DAPM_ENUM(rx_int8_interp, WCD934X_CDC_RX8_RX_PATH_CTL, 5, + rx_int8_interp_mux_text); + +WCD_DAPM_ENUM_EXT(rx_int0_dem_inp, WCD934X_CDC_RX0_RX_PATH_SEC0, 0, + rx_int_dem_inp_mux_text, snd_soc_dapm_get_enum_double, + tavil_int_dem_inp_mux_put); +WCD_DAPM_ENUM_EXT(rx_int1_dem_inp, WCD934X_CDC_RX1_RX_PATH_SEC0, 0, + rx_int_dem_inp_mux_text, snd_soc_dapm_get_enum_double, + tavil_int_dem_inp_mux_put); +WCD_DAPM_ENUM_EXT(rx_int2_dem_inp, WCD934X_CDC_RX2_RX_PATH_SEC0, 0, + rx_int_dem_inp_mux_text, snd_soc_dapm_get_enum_double, + tavil_int_dem_inp_mux_put); + +WCD_DAPM_ENUM_EXT(tx_adc_mux0, WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 0, + adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put); +WCD_DAPM_ENUM_EXT(tx_adc_mux1, WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 0, + adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put); +WCD_DAPM_ENUM_EXT(tx_adc_mux2, WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 0, + adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put); +WCD_DAPM_ENUM_EXT(tx_adc_mux3, WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1, 0, + adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put); +WCD_DAPM_ENUM_EXT(tx_adc_mux4, WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 2, + adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put); +WCD_DAPM_ENUM_EXT(tx_adc_mux5, WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 2, + adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put); +WCD_DAPM_ENUM_EXT(tx_adc_mux6, WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 2, + adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put); +WCD_DAPM_ENUM_EXT(tx_adc_mux7, WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1, 2, + adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put); +WCD_DAPM_ENUM_EXT(tx_adc_mux8, WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 4, + adc_mux_text, snd_soc_dapm_get_enum_double, tavil_dec_enum_put); + +static const struct snd_kcontrol_new adc_us_mux0_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux1_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux2_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux3_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux4_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux5_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux6_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux7_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new adc_us_mux8_switch = + SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_soc_dapm_widget tavil_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM, + AIF1_PB, 0, tavil_codec_enable_slimrx, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_IN_E("AIF2 PB", "AIF2 Playback", 0, SND_SOC_NOPM, + AIF2_PB, 0, tavil_codec_enable_slimrx, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_IN_E("AIF3 PB", "AIF3 Playback", 0, SND_SOC_NOPM, + AIF3_PB, 0, tavil_codec_enable_slimrx, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_IN_E("AIF4 PB", "AIF4 Playback", 0, SND_SOC_NOPM, + AIF4_PB, 0, tavil_codec_enable_slimrx, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + WCD_DAPM_MUX("SLIM RX0 MUX", WCD934X_RX0, slim_rx0), + WCD_DAPM_MUX("SLIM RX1 MUX", WCD934X_RX1, slim_rx1), + WCD_DAPM_MUX("SLIM RX2 MUX", WCD934X_RX2, slim_rx2), + WCD_DAPM_MUX("SLIM RX3 MUX", WCD934X_RX3, slim_rx3), + WCD_DAPM_MUX("SLIM RX4 MUX", WCD934X_RX4, slim_rx4), + WCD_DAPM_MUX("SLIM RX5 MUX", WCD934X_RX5, slim_rx5), + WCD_DAPM_MUX("SLIM RX6 MUX", WCD934X_RX6, slim_rx6), + WCD_DAPM_MUX("SLIM RX7 MUX", WCD934X_RX7, slim_rx7), + + SND_SOC_DAPM_MIXER("SLIM RX0", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX6", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM RX7", SND_SOC_NOPM, 0, 0, NULL, 0), + + WCD_DAPM_MUX("CDC_IF RX0 MUX", WCD934X_RX0, cdc_if_rx0), + WCD_DAPM_MUX("CDC_IF RX1 MUX", WCD934X_RX1, cdc_if_rx1), + WCD_DAPM_MUX("CDC_IF RX2 MUX", WCD934X_RX2, cdc_if_rx2), + WCD_DAPM_MUX("CDC_IF RX3 MUX", WCD934X_RX3, cdc_if_rx3), + WCD_DAPM_MUX("CDC_IF RX4 MUX", WCD934X_RX4, cdc_if_rx4), + WCD_DAPM_MUX("CDC_IF RX5 MUX", WCD934X_RX5, cdc_if_rx5), + WCD_DAPM_MUX("CDC_IF RX6 MUX", WCD934X_RX6, cdc_if_rx6), + WCD_DAPM_MUX("CDC_IF RX7 MUX", WCD934X_RX7, cdc_if_rx7), + + SND_SOC_DAPM_MUX_E("RX INT0_2 MUX", WCD934X_CDC_RX0_RX_PATH_MIX_CTL, + 5, 0, &rx_int0_2_mux, tavil_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT1_2 MUX", WCD934X_CDC_RX1_RX_PATH_MIX_CTL, + 5, 0, &rx_int1_2_mux, tavil_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT2_2 MUX", WCD934X_CDC_RX2_RX_PATH_MIX_CTL, + 5, 0, &rx_int2_2_mux, tavil_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT3_2 MUX", WCD934X_CDC_RX3_RX_PATH_MIX_CTL, + 5, 0, &rx_int3_2_mux, tavil_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT4_2 MUX", WCD934X_CDC_RX4_RX_PATH_MIX_CTL, + 5, 0, &rx_int4_2_mux, tavil_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT7_2 MUX", WCD934X_CDC_RX7_RX_PATH_MIX_CTL, + 5, 0, &rx_int7_2_mux, tavil_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("RX INT8_2 MUX", WCD934X_CDC_RX8_RX_PATH_MIX_CTL, + 5, 0, &rx_int8_2_mux, tavil_codec_enable_mix_path, + SND_SOC_DAPM_POST_PMU), + + WCD_DAPM_MUX("RX INT0_1 MIX1 INP0", 0, rx_int0_1_mix_inp0), + WCD_DAPM_MUX("RX INT0_1 MIX1 INP1", 0, rx_int0_1_mix_inp1), + WCD_DAPM_MUX("RX INT0_1 MIX1 INP2", 0, rx_int0_1_mix_inp2), + WCD_DAPM_MUX("RX INT1_1 MIX1 INP0", 0, rx_int1_1_mix_inp0), + WCD_DAPM_MUX("RX INT1_1 MIX1 INP1", 0, rx_int1_1_mix_inp1), + WCD_DAPM_MUX("RX INT1_1 MIX1 INP2", 0, rx_int1_1_mix_inp2), + WCD_DAPM_MUX("RX INT2_1 MIX1 INP0", 0, rx_int2_1_mix_inp0), + WCD_DAPM_MUX("RX INT2_1 MIX1 INP1", 0, rx_int2_1_mix_inp1), + WCD_DAPM_MUX("RX INT2_1 MIX1 INP2", 0, rx_int2_1_mix_inp2), + WCD_DAPM_MUX("RX INT3_1 MIX1 INP0", 0, rx_int3_1_mix_inp0), + WCD_DAPM_MUX("RX INT3_1 MIX1 INP1", 0, rx_int3_1_mix_inp1), + WCD_DAPM_MUX("RX INT3_1 MIX1 INP2", 0, rx_int3_1_mix_inp2), + WCD_DAPM_MUX("RX INT4_1 MIX1 INP0", 0, rx_int4_1_mix_inp0), + WCD_DAPM_MUX("RX INT4_1 MIX1 INP1", 0, rx_int4_1_mix_inp1), + WCD_DAPM_MUX("RX INT4_1 MIX1 INP2", 0, rx_int4_1_mix_inp2), + + SND_SOC_DAPM_MUX_E("RX INT7_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int7_1_mix_inp0_mux, tavil_codec_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT7_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int7_1_mix_inp1_mux, tavil_codec_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT7_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int7_1_mix_inp2_mux, tavil_codec_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT8_1 MIX1 INP0", SND_SOC_NOPM, 0, 0, + &rx_int8_1_mix_inp0_mux, tavil_codec_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT8_1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_int8_1_mix_inp1_mux, tavil_codec_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT8_1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_int8_1_mix_inp2_mux, tavil_codec_enable_swr, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER("RX INT0_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT2_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT2 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT3_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT3 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT4_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT4 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT7_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT7 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT8_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT8 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("RX INT0 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT1 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT2 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT3 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT4 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX INT7 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER_E("RX INT7 CHAIN", SND_SOC_NOPM, 0, 0, + NULL, 0, tavil_codec_spk_boost_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("RX INT8 CHAIN", SND_SOC_NOPM, 0, 0, + NULL, 0, tavil_codec_spk_boost_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("RX INT0 MIX2 INP", WCD934X_CDC_RX0_RX_PATH_CFG1, 4, + 0, &rx_int0_mix2_inp_mux), + SND_SOC_DAPM_MUX("RX INT1 MIX2 INP", WCD934X_CDC_RX1_RX_PATH_CFG1, 4, + 0, &rx_int1_mix2_inp_mux), + SND_SOC_DAPM_MUX("RX INT2 MIX2 INP", WCD934X_CDC_RX2_RX_PATH_CFG1, 4, + 0, &rx_int2_mix2_inp_mux), + SND_SOC_DAPM_MUX("RX INT3 MIX2 INP", WCD934X_CDC_RX3_RX_PATH_CFG1, 4, + 0, &rx_int3_mix2_inp_mux), + SND_SOC_DAPM_MUX("RX INT4 MIX2 INP", WCD934X_CDC_RX4_RX_PATH_CFG1, 4, + 0, &rx_int4_mix2_inp_mux), + SND_SOC_DAPM_MUX("RX INT7 MIX2 INP", WCD934X_CDC_RX7_RX_PATH_CFG1, 4, + 0, &rx_int7_mix2_inp_mux), + + WCD_DAPM_MUX("CDC_IF TX0 MUX", WCD934X_TX0, cdc_if_tx0), + WCD_DAPM_MUX("CDC_IF TX1 MUX", WCD934X_TX1, cdc_if_tx1), + WCD_DAPM_MUX("CDC_IF TX2 MUX", WCD934X_TX2, cdc_if_tx2), + WCD_DAPM_MUX("CDC_IF TX3 MUX", WCD934X_TX3, cdc_if_tx3), + WCD_DAPM_MUX("CDC_IF TX4 MUX", WCD934X_TX4, cdc_if_tx4), + WCD_DAPM_MUX("CDC_IF TX5 MUX", WCD934X_TX5, cdc_if_tx5), + WCD_DAPM_MUX("CDC_IF TX6 MUX", WCD934X_TX6, cdc_if_tx6), + WCD_DAPM_MUX("CDC_IF TX7 MUX", WCD934X_TX7, cdc_if_tx7), + WCD_DAPM_MUX("CDC_IF TX8 MUX", WCD934X_TX8, cdc_if_tx8), + WCD_DAPM_MUX("CDC_IF TX9 MUX", WCD934X_TX9, cdc_if_tx9), + WCD_DAPM_MUX("CDC_IF TX10 MUX", WCD934X_TX10, cdc_if_tx10), + WCD_DAPM_MUX("CDC_IF TX11 MUX", WCD934X_TX11, cdc_if_tx11), + WCD_DAPM_MUX("CDC_IF TX11 INP1 MUX", WCD934X_TX11, cdc_if_tx11_inp1), + WCD_DAPM_MUX("CDC_IF TX13 MUX", WCD934X_TX13, cdc_if_tx13), + WCD_DAPM_MUX("CDC_IF TX13 INP1 MUX", WCD934X_TX13, cdc_if_tx13_inp1), + + SND_SOC_DAPM_MUX_E("ADC MUX0", WCD934X_CDC_TX0_TX_PATH_CTL, 5, 0, + &tx_adc_mux0_mux, tavil_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX1", WCD934X_CDC_TX1_TX_PATH_CTL, 5, 0, + &tx_adc_mux1_mux, tavil_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX2", WCD934X_CDC_TX2_TX_PATH_CTL, 5, 0, + &tx_adc_mux2_mux, tavil_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX3", WCD934X_CDC_TX3_TX_PATH_CTL, 5, 0, + &tx_adc_mux3_mux, tavil_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX4", WCD934X_CDC_TX4_TX_PATH_CTL, 5, 0, + &tx_adc_mux4_mux, tavil_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX5", WCD934X_CDC_TX5_TX_PATH_CTL, 5, 0, + &tx_adc_mux5_mux, tavil_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX6", WCD934X_CDC_TX6_TX_PATH_CTL, 5, 0, + &tx_adc_mux6_mux, tavil_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX7", WCD934X_CDC_TX7_TX_PATH_CTL, 5, 0, + &tx_adc_mux7_mux, tavil_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX8", WCD934X_CDC_TX8_TX_PATH_CTL, 5, 0, + &tx_adc_mux8_mux, tavil_codec_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX_E("ADC MUX10", SND_SOC_NOPM, 10, 0, &tx_adc_mux10_mux, + tavil_codec_tx_adc_cfg, SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_MUX_E("ADC MUX11", SND_SOC_NOPM, 11, 0, &tx_adc_mux11_mux, + tavil_codec_tx_adc_cfg, SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_MUX_E("ADC MUX12", SND_SOC_NOPM, 12, 0, &tx_adc_mux12_mux, + tavil_codec_tx_adc_cfg, SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_MUX_E("ADC MUX13", SND_SOC_NOPM, 13, 0, &tx_adc_mux13_mux, + tavil_codec_tx_adc_cfg, SND_SOC_DAPM_POST_PMU), + + WCD_DAPM_MUX("DMIC MUX0", 0, tx_dmic_mux0), + WCD_DAPM_MUX("DMIC MUX1", 0, tx_dmic_mux1), + WCD_DAPM_MUX("DMIC MUX2", 0, tx_dmic_mux2), + WCD_DAPM_MUX("DMIC MUX3", 0, tx_dmic_mux3), + WCD_DAPM_MUX("DMIC MUX4", 0, tx_dmic_mux4), + WCD_DAPM_MUX("DMIC MUX5", 0, tx_dmic_mux5), + WCD_DAPM_MUX("DMIC MUX6", 0, tx_dmic_mux6), + WCD_DAPM_MUX("DMIC MUX7", 0, tx_dmic_mux7), + WCD_DAPM_MUX("DMIC MUX8", 0, tx_dmic_mux8), + WCD_DAPM_MUX("DMIC MUX10", 0, tx_dmic_mux10), + WCD_DAPM_MUX("DMIC MUX11", 0, tx_dmic_mux11), + WCD_DAPM_MUX("DMIC MUX12", 0, tx_dmic_mux12), + WCD_DAPM_MUX("DMIC MUX13", 0, tx_dmic_mux13), + + WCD_DAPM_MUX("AMIC MUX0", 0, tx_amic_mux0), + WCD_DAPM_MUX("AMIC MUX1", 0, tx_amic_mux1), + WCD_DAPM_MUX("AMIC MUX2", 0, tx_amic_mux2), + WCD_DAPM_MUX("AMIC MUX3", 0, tx_amic_mux3), + WCD_DAPM_MUX("AMIC MUX4", 0, tx_amic_mux4), + WCD_DAPM_MUX("AMIC MUX5", 0, tx_amic_mux5), + WCD_DAPM_MUX("AMIC MUX6", 0, tx_amic_mux6), + WCD_DAPM_MUX("AMIC MUX7", 0, tx_amic_mux7), + WCD_DAPM_MUX("AMIC MUX8", 0, tx_amic_mux8), + WCD_DAPM_MUX("AMIC MUX10", 0, tx_amic_mux10), + WCD_DAPM_MUX("AMIC MUX11", 0, tx_amic_mux11), + WCD_DAPM_MUX("AMIC MUX12", 0, tx_amic_mux12), + WCD_DAPM_MUX("AMIC MUX13", 0, tx_amic_mux13), + + SND_SOC_DAPM_ADC_E("ADC1", NULL, WCD934X_ANA_AMIC1, 7, 0, + tavil_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC2", NULL, WCD934X_ANA_AMIC2, 7, 0, + tavil_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC3", NULL, WCD934X_ANA_AMIC3, 7, 0, + tavil_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_ADC_E("ADC4", NULL, WCD934X_ANA_AMIC4, 7, 0, + tavil_codec_enable_adc, SND_SOC_DAPM_PRE_PMU), + + WCD_DAPM_MUX("AMIC4_5 SEL", 0, tx_amic4_5), + + SND_SOC_DAPM_INPUT("AMIC1"), + SND_SOC_DAPM_INPUT("AMIC2"), + SND_SOC_DAPM_INPUT("AMIC3"), + SND_SOC_DAPM_INPUT("AMIC4"), + SND_SOC_DAPM_INPUT("AMIC5"), + + SND_SOC_DAPM_MICBIAS_E("MIC BIAS1", SND_SOC_NOPM, 0, 0, + tavil_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MICBIAS_E("MIC BIAS2", SND_SOC_NOPM, 0, 0, + tavil_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MICBIAS_E("MIC BIAS3", SND_SOC_NOPM, 0, 0, + tavil_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MICBIAS_E("MIC BIAS4", SND_SOC_NOPM, 0, 0, + tavil_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS1_STANDALONE, SND_SOC_NOPM, 0, 0, + tavil_codec_force_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS2_STANDALONE, SND_SOC_NOPM, 0, 0, + tavil_codec_force_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS3_STANDALONE, SND_SOC_NOPM, 0, 0, + tavil_codec_force_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS4_STANDALONE, SND_SOC_NOPM, 0, 0, + tavil_codec_force_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM, + AIF1_CAP, 0, tavil_codec_enable_slimtx, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_OUT_E("AIF2 CAP", "AIF2 Capture", 0, SND_SOC_NOPM, + AIF2_CAP, 0, tavil_codec_enable_slimtx, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_OUT_E("AIF3 CAP", "AIF3 Capture", 0, SND_SOC_NOPM, + AIF3_CAP, 0, tavil_codec_enable_slimtx, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0, + aif1_cap_mixer, ARRAY_SIZE(aif1_cap_mixer)), + SND_SOC_DAPM_MIXER("AIF2_CAP Mixer", SND_SOC_NOPM, AIF2_CAP, 0, + aif2_cap_mixer, ARRAY_SIZE(aif2_cap_mixer)), + SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0, + aif3_cap_mixer, ARRAY_SIZE(aif3_cap_mixer)), + + SND_SOC_DAPM_MIXER("SLIM TX0", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX4", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX5", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX6", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX7", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX8", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX9", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX10", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX11", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SLIM TX13", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Digital Mic Inputs */ + SND_SOC_DAPM_ADC_E("DMIC0", NULL, SND_SOC_NOPM, 0, 0, + tavil_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0, + tavil_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0, + tavil_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0, + tavil_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0, + tavil_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0, + tavil_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + WCD_DAPM_MUX("IIR0 INP0 MUX", 0, iir0_inp0), + WCD_DAPM_MUX("IIR0 INP1 MUX", 0, iir0_inp1), + WCD_DAPM_MUX("IIR0 INP2 MUX", 0, iir0_inp2), + WCD_DAPM_MUX("IIR0 INP3 MUX", 0, iir0_inp3), + WCD_DAPM_MUX("IIR1 INP0 MUX", 0, iir1_inp0), + WCD_DAPM_MUX("IIR1 INP1 MUX", 0, iir1_inp1), + WCD_DAPM_MUX("IIR1 INP2 MUX", 0, iir1_inp2), + WCD_DAPM_MUX("IIR1 INP3 MUX", 0, iir1_inp3), + + SND_SOC_DAPM_MIXER_E("IIR0", WCD934X_CDC_SIDETONE_IIR0_IIR_PATH_CTL, + 4, 0, NULL, 0, tavil_codec_set_iir_gain, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MIXER_E("IIR1", WCD934X_CDC_SIDETONE_IIR1_IIR_PATH_CTL, + 4, 0, NULL, 0, tavil_codec_set_iir_gain, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MIXER("SRC0", WCD934X_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL, + 4, 0, NULL, 0), + SND_SOC_DAPM_MIXER("SRC1", WCD934X_CDC_SIDETONE_SRC1_ST_SRC_PATH_CTL, + 4, 0, NULL, 0), + + WCD_DAPM_MUX("RX MIX TX0 MUX", 0, rx_mix_tx0), + WCD_DAPM_MUX("RX MIX TX1 MUX", 0, rx_mix_tx1), + WCD_DAPM_MUX("RX MIX TX2 MUX", 0, rx_mix_tx2), + WCD_DAPM_MUX("RX MIX TX3 MUX", 0, rx_mix_tx3), + WCD_DAPM_MUX("RX MIX TX4 MUX", 0, rx_mix_tx4), + WCD_DAPM_MUX("RX MIX TX5 MUX", 0, rx_mix_tx5), + WCD_DAPM_MUX("RX MIX TX6 MUX", 0, rx_mix_tx6), + WCD_DAPM_MUX("RX MIX TX7 MUX", 0, rx_mix_tx7), + WCD_DAPM_MUX("RX MIX TX8 MUX", 0, rx_mix_tx8), + WCD_DAPM_MUX("RX INT0 DEM MUX", 0, rx_int0_dem_inp), + WCD_DAPM_MUX("RX INT1 DEM MUX", 0, rx_int1_dem_inp), + WCD_DAPM_MUX("RX INT2 DEM MUX", 0, rx_int2_dem_inp), + + SND_SOC_DAPM_MUX_E("RX INT0 INTERP", SND_SOC_NOPM, INTERP_EAR, 0, + &rx_int0_interp_mux, tavil_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT1 INTERP", SND_SOC_NOPM, INTERP_HPHL, 0, + &rx_int1_interp_mux, tavil_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT2 INTERP", SND_SOC_NOPM, INTERP_HPHR, 0, + &rx_int2_interp_mux, tavil_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT3 INTERP", SND_SOC_NOPM, INTERP_LO1, 0, + &rx_int3_interp_mux, tavil_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT4 INTERP", SND_SOC_NOPM, INTERP_LO2, 0, + &rx_int4_interp_mux, tavil_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT7 INTERP", SND_SOC_NOPM, INTERP_SPKR1, 0, + &rx_int7_interp_mux, tavil_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("RX INT8 INTERP", SND_SOC_NOPM, INTERP_SPKR2, 0, + &rx_int8_interp_mux, tavil_codec_enable_interpolator, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SWITCH("ADC US MUX0", WCD934X_CDC_TX0_TX_PATH_192_CTL, 0, + 0, &adc_us_mux0_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX1", WCD934X_CDC_TX1_TX_PATH_192_CTL, 0, + 0, &adc_us_mux1_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX2", WCD934X_CDC_TX2_TX_PATH_192_CTL, 0, + 0, &adc_us_mux2_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX3", WCD934X_CDC_TX3_TX_PATH_192_CTL, 0, + 0, &adc_us_mux3_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX4", WCD934X_CDC_TX4_TX_PATH_192_CTL, 0, + 0, &adc_us_mux4_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX5", WCD934X_CDC_TX5_TX_PATH_192_CTL, 0, + 0, &adc_us_mux5_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX6", WCD934X_CDC_TX6_TX_PATH_192_CTL, 0, + 0, &adc_us_mux6_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX7", WCD934X_CDC_TX7_TX_PATH_192_CTL, 0, + 0, &adc_us_mux7_switch), + SND_SOC_DAPM_SWITCH("ADC US MUX8", WCD934X_CDC_TX8_TX_PATH_192_CTL, 0, + 0, &adc_us_mux8_switch), + + SND_SOC_DAPM_DAC_E("RX INT0 DAC", NULL, SND_SOC_NOPM, + 0, 0, tavil_codec_ear_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT1 DAC", NULL, WCD934X_ANA_HPH, + 5, 0, tavil_codec_hphl_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT2 DAC", NULL, WCD934X_ANA_HPH, + 4, 0, tavil_codec_hphr_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT3 DAC", NULL, SND_SOC_NOPM, + 0, 0, tavil_codec_lineout_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RX INT4 DAC", NULL, SND_SOC_NOPM, + 0, 0, tavil_codec_lineout_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_PGA_E("EAR PA", WCD934X_ANA_EAR, 7, 0, NULL, 0, + tavil_codec_enable_ear_pa, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHL PA", WCD934X_ANA_HPH, 7, 0, NULL, 0, + tavil_codec_enable_hphl_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHR PA", WCD934X_ANA_HPH, 6, 0, NULL, 0, + tavil_codec_enable_hphr_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("LINEOUT1 PA", WCD934X_ANA_LO_1_2, 7, 0, NULL, 0, + tavil_codec_enable_lineout_pa, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("LINEOUT2 PA", WCD934X_ANA_LO_1_2, 6, 0, NULL, 0, + tavil_codec_enable_lineout_pa, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_OUTPUT("EAR"), + SND_SOC_DAPM_OUTPUT("HPHL"), + SND_SOC_DAPM_OUTPUT("HPHR"), + SND_SOC_DAPM_OUTPUT("LINEOUT1"), + SND_SOC_DAPM_OUTPUT("LINEOUT2"), + SND_SOC_DAPM_OUTPUT("SPK1 OUT"), + SND_SOC_DAPM_OUTPUT("SPK2 OUT"), + + SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0, + tavil_codec_enable_rx_bias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +}; + +static int tavil_get_channel_map(struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(dai->codec); + u32 i = 0; + struct wcd9xxx_ch *ch; + int ret = 0; + + switch (dai->id) { + case AIF1_PB: + case AIF2_PB: + case AIF3_PB: + case AIF4_PB: + if (!rx_slot || !rx_num) { + dev_err(tavil->dev, "%s: Invalid rx_slot 0x%pK or rx_num 0x%pK\n", + __func__, rx_slot, rx_num); + ret = -EINVAL; + break; + } + list_for_each_entry(ch, &tavil->dai[dai->id].wcd9xxx_ch_list, + list) { + dev_dbg(tavil->dev, "%s: slot_num %u ch->ch_num %d\n", + __func__, i, ch->ch_num); + rx_slot[i++] = ch->ch_num; + } + *rx_num = i; + dev_dbg(tavil->dev, "%s: dai_name = %s dai_id = %x rx_num = %d\n", + __func__, dai->name, dai->id, i); + if (*rx_num == 0) { + dev_err(tavil->dev, "%s: Channel list empty for dai_name = %s dai_id = %x\n", + __func__, dai->name, dai->id); + ret = -EINVAL; + } + break; + case AIF1_CAP: + case AIF2_CAP: + case AIF3_CAP: + if (!tx_slot || !tx_num) { + dev_err(tavil->dev, "%s: Invalid tx_slot 0x%pK or tx_num 0x%pK\n", + __func__, tx_slot, tx_num); + ret = -EINVAL; + break; + } + list_for_each_entry(ch, &tavil->dai[dai->id].wcd9xxx_ch_list, + list) { + dev_dbg(tavil->dev, "%s: slot_num %u ch->ch_num %d\n", + __func__, i, ch->ch_num); + tx_slot[i++] = ch->ch_num; + } + *tx_num = i; + dev_dbg(tavil->dev, "%s: dai_name = %s dai_id = %x tx_num = %d\n", + __func__, dai->name, dai->id, i); + if (*tx_num == 0) { + dev_err(tavil->dev, "%s: Channel list empty for dai_name = %s dai_id = %x\n", + __func__, dai->name, dai->id); + ret = -EINVAL; + } + break; + default: + dev_err(tavil->dev, "%s: Invalid DAI ID %x\n", + __func__, dai->id); + ret = -EINVAL; + break; + } + + return ret; +} + +static int tavil_set_channel_map(struct snd_soc_dai *dai, + unsigned int tx_num, unsigned int *tx_slot, + unsigned int rx_num, unsigned int *rx_slot) +{ + struct tavil_priv *tavil; + struct wcd9xxx *core; + + tavil = snd_soc_codec_get_drvdata(dai->codec); + core = dev_get_drvdata(dai->codec->dev->parent); + + if (!tx_slot || !rx_slot) { + dev_err(tavil->dev, "%s: Invalid tx_slot 0x%pK, rx_slot 0x%pK\n", + __func__, tx_slot, rx_slot); + return -EINVAL; + } + dev_dbg(tavil->dev, "%s(): dai_name = %s DAI-ID %x tx_ch %d rx_ch %d\n", + __func__, dai->name, dai->id, tx_num, rx_num); + + wcd9xxx_init_slimslave(core, core->slim->laddr, + tx_num, tx_slot, rx_num, rx_slot); + return 0; +} + +static int tavil_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + + return 0; +} + +static void tavil_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); +} + +static int tavil_set_decimator_rate(struct snd_soc_dai *dai, + u32 sample_rate) +{ + struct snd_soc_codec *codec = dai->codec; + struct wcd9xxx_ch *ch; + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + u32 tx_port = 0, tx_fs_rate = 0; + u8 shift = 0, shift_val = 0, tx_mux_sel = 0; + int decimator = -1; + u16 tx_port_reg = 0, tx_fs_reg = 0; + + switch (sample_rate) { + case 8000: + tx_fs_rate = 0; + break; + case 16000: + tx_fs_rate = 1; + break; + case 32000: + tx_fs_rate = 3; + break; + case 48000: + tx_fs_rate = 4; + break; + case 96000: + tx_fs_rate = 5; + break; + case 192000: + tx_fs_rate = 6; + break; + default: + dev_err(tavil->dev, "%s: Invalid TX sample rate: %d\n", + __func__, sample_rate); + return -EINVAL; + + }; + + list_for_each_entry(ch, &tavil->dai[dai->id].wcd9xxx_ch_list, list) { + tx_port = ch->port; + dev_dbg(codec->dev, "%s: dai->id = %d, tx_port = %d", + __func__, dai->id, tx_port); + + if ((tx_port < 0) || (tx_port == 12) || (tx_port >= 14)) { + dev_err(codec->dev, "%s: Invalid SLIM TX%u port. DAI ID: %d\n", + __func__, tx_port, dai->id); + return -EINVAL; + } + /* Find the SB TX MUX input - which decimator is connected */ + if (tx_port < 4) { + tx_port_reg = WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0; + shift = (tx_port << 1); + shift_val = 0x03; + } else if ((tx_port >= 4) && (tx_port < 8)) { + tx_port_reg = WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1; + shift = ((tx_port - 4) << 1); + shift_val = 0x03; + } else if ((tx_port >= 8) && (tx_port < 11)) { + tx_port_reg = WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2; + shift = ((tx_port - 8) << 1); + shift_val = 0x03; + } else if (tx_port == 11) { + tx_port_reg = WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3; + shift = 0; + shift_val = 0x0F; + } else if (tx_port == 13) { + tx_port_reg = WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3; + shift = 4; + shift_val = 0x03; + } + tx_mux_sel = snd_soc_read(codec, tx_port_reg) & + (shift_val << shift); + tx_mux_sel = tx_mux_sel >> shift; + + if (tx_port <= 8) { + if ((tx_mux_sel == 0x2) || (tx_mux_sel == 0x3)) + decimator = tx_port; + } else if (tx_port <= 10) { + if ((tx_mux_sel == 0x1) || (tx_mux_sel == 0x2)) + decimator = ((tx_port == 9) ? 7 : 6); + } else if (tx_port == 11) { + if ((tx_mux_sel >= 1) && (tx_mux_sel < 7)) + decimator = tx_mux_sel - 1; + } else if (tx_port == 13) { + if ((tx_mux_sel == 0x1) || (tx_mux_sel == 0x2)) + decimator = 5; + } + + if (decimator >= 0) { + tx_fs_reg = WCD934X_CDC_TX0_TX_PATH_CTL + + 16 * decimator; + dev_dbg(codec->dev, "%s: set DEC%u (-> SLIM_TX%u) rate to %u\n", + __func__, decimator, tx_port, sample_rate); + snd_soc_update_bits(codec, tx_fs_reg, 0x0F, tx_fs_rate); + } else if ((tx_port <= 8) && (tx_mux_sel == 0x01)) { + /* Check if the TX Mux input is RX MIX TXn */ + dev_dbg(codec->dev, "%s: RX_MIX_TX%u going to CDC_IF TX%u\n", + __func__, tx_port, tx_port); + } else { + dev_err(codec->dev, "%s: ERROR: Invalid decimator: %d\n", + __func__, decimator); + return -EINVAL; + } + } + return 0; +} + +static int tavil_set_mix_interpolator_rate(struct snd_soc_dai *dai, + u8 rate_reg_val, + u32 sample_rate) +{ + u8 int_2_inp; + u32 j; + u16 int_mux_cfg1, int_fs_reg; + u8 int_mux_cfg1_val; + struct snd_soc_codec *codec = dai->codec; + struct wcd9xxx_ch *ch; + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + + list_for_each_entry(ch, &tavil->dai[dai->id].wcd9xxx_ch_list, list) { + int_2_inp = INTn_2_INP_SEL_RX0 + ch->port - + WCD934X_RX_PORT_START_NUMBER; + if ((int_2_inp < INTn_2_INP_SEL_RX0) || + (int_2_inp > INTn_2_INP_SEL_RX7)) { + dev_err(codec->dev, "%s: Invalid RX%u port, Dai ID is %d\n", + __func__, + (ch->port - WCD934X_RX_PORT_START_NUMBER), + dai->id); + return -EINVAL; + } + + int_mux_cfg1 = WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG1; + for (j = 0; j < WCD934X_NUM_INTERPOLATORS; j++) { + /* Interpolators 5 and 6 are not aviliable in Tavil */ + if (j == INTERP_LO3_NA || j == INTERP_LO4_NA) { + int_mux_cfg1 += 2; + continue; + } + int_mux_cfg1_val = snd_soc_read(codec, int_mux_cfg1) & + 0x0F; + if (int_mux_cfg1_val == int_2_inp) { + /* + * Ear mix path supports only 48, 96, 192, + * 384KHz only + */ + if ((j == INTERP_EAR) && + (rate_reg_val < 0x4 || + rate_reg_val > 0x7)) { + dev_err_ratelimited(codec->dev, + "%s: Invalid rate for AIF_PB DAI(%d)\n", + __func__, dai->id); + return -EINVAL; + } + + int_fs_reg = WCD934X_CDC_RX0_RX_PATH_MIX_CTL + + 20 * j; + dev_dbg(codec->dev, "%s: AIF_PB DAI(%d) connected to INT%u_2\n", + __func__, dai->id, j); + dev_dbg(codec->dev, "%s: set INT%u_2 sample rate to %u\n", + __func__, j, sample_rate); + snd_soc_update_bits(codec, int_fs_reg, 0x0F, + rate_reg_val); + } + int_mux_cfg1 += 2; + } + } + return 0; +} + +static int tavil_set_prim_interpolator_rate(struct snd_soc_dai *dai, + u8 rate_reg_val, + u32 sample_rate) +{ + u8 int_1_mix1_inp; + u32 j; + u16 int_mux_cfg0, int_mux_cfg1; + u16 int_fs_reg; + u8 int_mux_cfg0_val, int_mux_cfg1_val; + u8 inp0_sel, inp1_sel, inp2_sel; + struct snd_soc_codec *codec = dai->codec; + struct wcd9xxx_ch *ch; + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + + list_for_each_entry(ch, &tavil->dai[dai->id].wcd9xxx_ch_list, list) { + int_1_mix1_inp = INTn_1_INP_SEL_RX0 + ch->port - + WCD934X_RX_PORT_START_NUMBER; + if ((int_1_mix1_inp < INTn_1_INP_SEL_RX0) || + (int_1_mix1_inp > INTn_1_INP_SEL_RX7)) { + dev_err(codec->dev, "%s: Invalid RX%u port, Dai ID is %d\n", + __func__, + (ch->port - WCD934X_RX_PORT_START_NUMBER), + dai->id); + return -EINVAL; + } + + int_mux_cfg0 = WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG0; + + /* + * Loop through all interpolator MUX inputs and find out + * to which interpolator input, the slim rx port + * is connected + */ + for (j = 0; j < WCD934X_NUM_INTERPOLATORS; j++) { + /* Interpolators 5 and 6 are not aviliable in Tavil */ + if (j == INTERP_LO3_NA || j == INTERP_LO4_NA) { + int_mux_cfg0 += 2; + continue; + } + int_mux_cfg1 = int_mux_cfg0 + 1; + + int_mux_cfg0_val = snd_soc_read(codec, int_mux_cfg0); + int_mux_cfg1_val = snd_soc_read(codec, int_mux_cfg1); + inp0_sel = int_mux_cfg0_val & 0x0F; + inp1_sel = (int_mux_cfg0_val >> 4) & 0x0F; + inp2_sel = (int_mux_cfg1_val >> 4) & 0x0F; + if ((inp0_sel == int_1_mix1_inp) || + (inp1_sel == int_1_mix1_inp) || + (inp2_sel == int_1_mix1_inp)) { + /* + * Ear and speaker primary path does not support + * native sample rates + */ + if ((j == INTERP_EAR || j == INTERP_SPKR1 || + j == INTERP_SPKR2) && + (rate_reg_val > 0x7)) { + dev_err_ratelimited(codec->dev, + "%s: Invalid rate for AIF_PB DAI(%d)\n", + __func__, dai->id); + return -EINVAL; + } + + int_fs_reg = WCD934X_CDC_RX0_RX_PATH_CTL + + 20 * j; + dev_dbg(codec->dev, + "%s: AIF_PB DAI(%d) connected to INT%u_1\n", + __func__, dai->id, j); + dev_dbg(codec->dev, + "%s: set INT%u_1 sample rate to %u\n", + __func__, j, sample_rate); + snd_soc_update_bits(codec, int_fs_reg, 0x0F, + rate_reg_val); + } + int_mux_cfg0 += 2; + } + } + + return 0; +} + + +static int tavil_set_interpolator_rate(struct snd_soc_dai *dai, + u32 sample_rate) +{ + struct snd_soc_codec *codec = dai->codec; + int rate_val = 0; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(sr_val_tbl); i++) { + if (sample_rate == sr_val_tbl[i].sample_rate) { + rate_val = sr_val_tbl[i].rate_val; + break; + } + } + if ((i == ARRAY_SIZE(sr_val_tbl)) || (rate_val < 0)) { + dev_err(codec->dev, "%s: Unsupported sample rate: %d\n", + __func__, sample_rate); + return -EINVAL; + } + + ret = tavil_set_prim_interpolator_rate(dai, (u8)rate_val, sample_rate); + if (ret) + return ret; + ret = tavil_set_mix_interpolator_rate(dai, (u8)rate_val, sample_rate); + if (ret) + return ret; + + return ret; +} + +static int tavil_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + return 0; +} + +static int tavil_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(dai->codec); + int ret; + + dev_dbg(tavil->dev, "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", + __func__, dai->name, dai->id, params_rate(params), + params_channels(params)); + + switch (substream->stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + ret = tavil_set_interpolator_rate(dai, params_rate(params)); + if (ret) { + dev_err(tavil->dev, "%s: cannot set sample rate: %u\n", + __func__, params_rate(params)); + return ret; + } + switch (params_width(params)) { + case 16: + tavil->dai[dai->id].bit_width = 16; + break; + case 24: + tavil->dai[dai->id].bit_width = 24; + break; + case 32: + tavil->dai[dai->id].bit_width = 32; + break; + default: + return -EINVAL; + } + tavil->dai[dai->id].rate = params_rate(params); + break; + case SNDRV_PCM_STREAM_CAPTURE: + ret = tavil_set_decimator_rate(dai, params_rate(params)); + if (ret) { + dev_err(tavil->dev, "%s: cannot set TX Decimator rate: %d\n", + __func__, ret); + return ret; + } + switch (params_width(params)) { + case 16: + tavil->dai[dai->id].bit_width = 16; + break; + case 24: + tavil->dai[dai->id].bit_width = 24; + break; + default: + dev_err(tavil->dev, "%s: Invalid format 0x%x\n", + __func__, params_width(params)); + return -EINVAL; + }; + tavil->dai[dai->id].rate = params_rate(params); + break; + default: + dev_err(tavil->dev, "%s: Invalid stream type %d\n", __func__, + substream->stream); + return -EINVAL; + }; + + return 0; +} + +static struct snd_soc_dai_ops tavil_dai_ops = { + .startup = tavil_startup, + .shutdown = tavil_shutdown, + .hw_params = tavil_hw_params, + .prepare = tavil_prepare, + .set_channel_map = tavil_set_channel_map, + .get_channel_map = tavil_get_channel_map, +}; + +static struct snd_soc_dai_driver tavil_dai[] = { + { + .name = "tavil_rx1", + .id = AIF1_PB, + .playback = { + .stream_name = "AIF1 Playback", + .rates = WCD934X_RATES_MASK | WCD934X_FRAC_RATES_MASK, + .formats = WCD934X_FORMATS_S16_S24_S32_LE, + .rate_min = 8000, + .rate_max = 384000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tavil_dai_ops, + }, + { + .name = "tavil_tx1", + .id = AIF1_CAP, + .capture = { + .stream_name = "AIF1 Capture", + .rates = WCD934X_RATES_MASK, + .formats = WCD934X_FORMATS_S16_S24_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &tavil_dai_ops, + }, + { + .name = "tavil_rx2", + .id = AIF2_PB, + .playback = { + .stream_name = "AIF2 Playback", + .rates = WCD934X_RATES_MASK | WCD934X_FRAC_RATES_MASK, + .formats = WCD934X_FORMATS_S16_S24_S32_LE, + .rate_min = 8000, + .rate_max = 384000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tavil_dai_ops, + }, + { + .name = "tavil_tx2", + .id = AIF2_CAP, + .capture = { + .stream_name = "AIF2 Capture", + .rates = WCD934X_RATES_MASK, + .formats = WCD934X_FORMATS_S16_S24_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &tavil_dai_ops, + }, + { + .name = "tavil_rx3", + .id = AIF3_PB, + .playback = { + .stream_name = "AIF3 Playback", + .rates = WCD934X_RATES_MASK | WCD934X_FRAC_RATES_MASK, + .formats = WCD934X_FORMATS_S16_S24_S32_LE, + .rate_min = 8000, + .rate_max = 384000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tavil_dai_ops, + }, + { + .name = "tavil_tx3", + .id = AIF3_CAP, + .capture = { + .stream_name = "AIF3 Capture", + .rates = WCD934X_RATES_MASK, + .formats = WCD934X_FORMATS_S16_S24_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &tavil_dai_ops, + }, + { + .name = "tavil_rx4", + .id = AIF4_PB, + .playback = { + .stream_name = "AIF4 Playback", + .rates = WCD934X_RATES_MASK | WCD934X_FRAC_RATES_MASK, + .formats = WCD934X_FORMATS_S16_S24_S32_LE, + .rate_min = 8000, + .rate_max = 384000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &tavil_dai_ops, + }, +}; + +static int tavil_cdc_req_mclk_enable(struct tavil_priv *tavil, + bool enable) +{ + int ret = 0; + + if (enable) { + ret = clk_prepare_enable(tavil->wcd_ext_clk); + if (ret) { + dev_err(tavil->dev, "%s: ext clk enable failed\n", + __func__); + goto done; + } + /* get BG */ + wcd_resmgr_enable_master_bias(tavil->resmgr); + /* get MCLK */ + wcd_resmgr_enable_clk_block(tavil->resmgr, WCD_CLK_MCLK); + } else { + /* put MCLK */ + wcd_resmgr_disable_clk_block(tavil->resmgr, WCD_CLK_MCLK); + /* put BG */ + wcd_resmgr_disable_master_bias(tavil->resmgr); + clk_disable_unprepare(tavil->wcd_ext_clk); + } + +done: + return ret; +} + +static int __tavil_cdc_mclk_enable_locked(struct tavil_priv *tavil, + bool enable) +{ + int ret = 0; + + if (!tavil->wcd_ext_clk) { + dev_err(tavil->dev, "%s: wcd ext clock is NULL\n", __func__); + return -EINVAL; + } + + dev_dbg(tavil->dev, "%s: mclk_enable = %u\n", __func__, enable); + + if (enable) { + ret = tavil_cdc_req_mclk_enable(tavil, true); + if (ret) + goto done; + + set_bit(AUDIO_NOMINAL, &tavil->status_mask); + } else { + tavil_cdc_req_mclk_enable(tavil, false); + } + +done: + return ret; +} + +static int __tavil_cdc_mclk_enable(struct tavil_priv *tavil, + bool enable) +{ + int ret; + + WCD9XXX_V2_BG_CLK_LOCK(tavil->resmgr); + ret = __tavil_cdc_mclk_enable_locked(tavil, enable); + WCD9XXX_V2_BG_CLK_UNLOCK(tavil->resmgr); + + return ret; +} + +/** + * tavil_cdc_mclk_enable - Enable/disable codec mclk + * + * @codec: codec instance + * @enable: Indicates clk enable or disable + * + * Returns 0 on Success and error on failure + */ +int tavil_cdc_mclk_enable(struct snd_soc_codec *codec, bool enable) +{ + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + + return __tavil_cdc_mclk_enable(tavil, enable); +} +EXPORT_SYMBOL(tavil_cdc_mclk_enable); + +static const struct tavil_reg_mask_val tavil_codec_reg_defaults[] = { + {WCD934X_BIAS_VBG_FINE_ADJ, 0xFF, 0x75}, + {WCD934X_CODEC_CPR_SVS_CX_VDD, 0xFF, 0x7C}, /* value in svs mode */ + {WCD934X_CODEC_CPR_SVS2_CX_VDD, 0xFF, 0x58}, /* value in svs2 mode */ + {WCD934X_SIDO_NEW_VOUT_D_FREQ2, 0x01, 0x01}, + {WCD934X_CDC_RX0_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, + {WCD934X_CDC_RX1_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, + {WCD934X_CDC_RX2_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, + {WCD934X_CDC_RX7_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, + {WCD934X_CDC_RX8_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, + {WCD934X_CDC_COMPANDER8_CTL7, 0x1E, 0x18}, + {WCD934X_CDC_COMPANDER7_CTL7, 0x1E, 0x18}, + {WCD934X_CDC_RX0_RX_PATH_SEC0, 0x08, 0x0}, + {WCD934X_CDC_CLSH_DECAY_CTRL, 0x03, 0x0}, + {WCD934X_MICB1_TEST_CTL_2, 0x07, 0x01}, +}; + +static const struct tavil_reg_mask_val tavil_codec_reg_init_common_val[] = { + {WCD934X_CDC_CLSH_K2_MSB, 0x0F, 0x00}, + {WCD934X_CDC_CLSH_K2_LSB, 0xFF, 0x60}, + {WCD934X_CPE_SS_DMIC_CFG, 0x80, 0x00}, + {WCD934X_CDC_BOOST0_BOOST_CTL, 0x70, 0x40}, + {WCD934X_CDC_BOOST1_BOOST_CTL, 0x70, 0x40}, + {WCD934X_CDC_RX7_RX_PATH_CFG1, 0x08, 0x08}, + {WCD934X_CDC_RX8_RX_PATH_CFG1, 0x08, 0x08}, + {WCD934X_CDC_TOP_TOP_CFG1, 0x02, 0x02}, + {WCD934X_CDC_TOP_TOP_CFG1, 0x01, 0x01}, + {WCD934X_CDC_TX9_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD934X_CDC_TX10_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD934X_CDC_TX11_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD934X_CDC_TX12_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, + {WCD934X_CDC_RX0_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD934X_CDC_RX1_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD934X_CDC_RX2_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD934X_CDC_RX3_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD934X_CDC_RX4_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD934X_CDC_RX7_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD934X_CDC_RX8_RX_PATH_MIX_CFG, 0x01, 0x01}, + {WCD934X_DATA_HUB_SB_TX11_INP_CFG, 0x01, 0x01}, + {WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, 0x01, 0x01}, +}; + +static void tavil_codec_init_reg(struct snd_soc_codec *codec) +{ + u32 i; + + for (i = 0; i < ARRAY_SIZE(tavil_codec_reg_init_common_val); i++) + snd_soc_update_bits(codec, + tavil_codec_reg_init_common_val[i].reg, + tavil_codec_reg_init_common_val[i].mask, + tavil_codec_reg_init_common_val[i].val); +} + +static void tavil_update_reg_defaults(struct tavil_priv *tavil) +{ + u32 i; + struct wcd9xxx *wcd9xxx; + + wcd9xxx = tavil->wcd9xxx; + for (i = 0; i < ARRAY_SIZE(tavil_codec_reg_defaults); i++) + regmap_update_bits(wcd9xxx->regmap, + tavil_codec_reg_defaults[i].reg, + tavil_codec_reg_defaults[i].mask, + tavil_codec_reg_defaults[i].val); +} + +static void tavil_slim_interface_init_reg(struct snd_soc_codec *codec) +{ + int i; + struct tavil_priv *priv = snd_soc_codec_get_drvdata(codec); + + for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) + wcd9xxx_interface_reg_write(priv->wcd9xxx, + WCD934X_SLIM_PGD_PORT_INT_RX_EN0 + i, + 0xFF); +} + +static irqreturn_t tavil_slimbus_irq(int irq, void *data) +{ + struct tavil_priv *tavil = data; + unsigned long status = 0; + int i, j, port_id, k; + u32 bit; + u8 val, int_val = 0; + bool tx, cleared; + unsigned short reg = 0; + + for (i = WCD934X_SLIM_PGD_PORT_INT_STATUS_RX_0, j = 0; + i <= WCD934X_SLIM_PGD_PORT_INT_STATUS_TX_1; i++, j++) { + val = wcd9xxx_interface_reg_read(tavil->wcd9xxx, i); + status |= ((u32)val << (8 * j)); + } + + for_each_set_bit(j, &status, 32) { + tx = (j >= 16 ? true : false); + port_id = (tx ? j - 16 : j); + val = wcd9xxx_interface_reg_read(tavil->wcd9xxx, + WCD934X_SLIM_PGD_PORT_INT_RX_SOURCE0 + j); + if (val) { + if (!tx) + reg = WCD934X_SLIM_PGD_PORT_INT_RX_EN0 + + (port_id / 8); + else + reg = WCD934X_SLIM_PGD_PORT_INT_TX_EN0 + + (port_id / 8); + int_val = wcd9xxx_interface_reg_read( + tavil->wcd9xxx, reg); + /* + * Ignore interrupts for ports for which the + * interrupts are not specifically enabled. + */ + if (!(int_val & (1 << (port_id % 8)))) + continue; + } + if (val & WCD934X_SLIM_IRQ_OVERFLOW) + dev_err_ratelimited(tavil->dev, "%s: overflow error on %s port %d, value %x\n", + __func__, (tx ? "TX" : "RX"), port_id, val); + if (val & WCD934X_SLIM_IRQ_UNDERFLOW) + dev_err_ratelimited(tavil->dev, "%s: underflow error on %s port %d, value %x\n", + __func__, (tx ? "TX" : "RX"), port_id, val); + if ((val & WCD934X_SLIM_IRQ_OVERFLOW) || + (val & WCD934X_SLIM_IRQ_UNDERFLOW)) { + if (!tx) + reg = WCD934X_SLIM_PGD_PORT_INT_RX_EN0 + + (port_id / 8); + else + reg = WCD934X_SLIM_PGD_PORT_INT_TX_EN0 + + (port_id / 8); + int_val = wcd9xxx_interface_reg_read( + tavil->wcd9xxx, reg); + if (int_val & (1 << (port_id % 8))) { + int_val = int_val ^ (1 << (port_id % 8)); + wcd9xxx_interface_reg_write(tavil->wcd9xxx, + reg, int_val); + } + } + if (val & WCD934X_SLIM_IRQ_PORT_CLOSED) { + /* + * INT SOURCE register starts from RX to TX + * but port number in the ch_mask is in opposite way + */ + bit = (tx ? j - 16 : j + 16); + dev_dbg(tavil->dev, "%s: %s port %d closed value %x, bit %u\n", + __func__, (tx ? "TX" : "RX"), port_id, val, + bit); + for (k = 0, cleared = false; k < NUM_CODEC_DAIS; k++) { + dev_dbg(tavil->dev, "%s: tavil->dai[%d].ch_mask = 0x%lx\n", + __func__, k, tavil->dai[k].ch_mask); + if (test_and_clear_bit(bit, + &tavil->dai[k].ch_mask)) { + cleared = true; + if (!tavil->dai[k].ch_mask) + wake_up( + &tavil->dai[k].dai_wait); + /* + * There are cases when multiple DAIs + * might be using the same slimbus + * channel. Hence don't break here. + */ + } + } + WARN(!cleared, + "Couldn't find slimbus %s port %d for closing\n", + (tx ? "TX" : "RX"), port_id); + } + wcd9xxx_interface_reg_write(tavil->wcd9xxx, + WCD934X_SLIM_PGD_PORT_INT_CLR_RX_0 + + (j / 8), + 1 << (j % 8)); + } + + return IRQ_HANDLED; +} + +static int tavil_setup_irqs(struct tavil_priv *tavil) +{ + int ret = 0; + struct snd_soc_codec *codec = tavil->codec; + struct wcd9xxx *wcd9xxx = tavil->wcd9xxx; + struct wcd9xxx_core_resource *core_res = + &wcd9xxx->core_res; + + ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_SLIMBUS, + tavil_slimbus_irq, "SLIMBUS Slave", tavil); + if (ret) + dev_err(codec->dev, "%s: Failed to request irq %d\n", __func__, + WCD9XXX_IRQ_SLIMBUS); + else + tavil_slim_interface_init_reg(codec); + + return ret; +} + +static void tavil_init_slim_slave_cfg(struct snd_soc_codec *codec) +{ + struct tavil_priv *priv = snd_soc_codec_get_drvdata(codec); + struct afe_param_cdc_slimbus_slave_cfg *cfg; + struct wcd9xxx *wcd9xxx = priv->wcd9xxx; + uint64_t eaddr = 0; + + cfg = &priv->slimbus_slave_cfg; + cfg->minor_version = 1; + cfg->tx_slave_port_offset = 0; + cfg->rx_slave_port_offset = 16; + + memcpy(&eaddr, &wcd9xxx->slim->e_addr, sizeof(wcd9xxx->slim->e_addr)); + WARN_ON(sizeof(wcd9xxx->slim->e_addr) != 6); + cfg->device_enum_addr_lsw = eaddr & 0xFFFFFFFF; + cfg->device_enum_addr_msw = eaddr >> 32; + + dev_dbg(codec->dev, "%s: slimbus logical address 0x%llx\n", + __func__, eaddr); +} + +static void tavil_cleanup_irqs(struct tavil_priv *tavil) +{ + struct wcd9xxx *wcd9xxx = tavil->wcd9xxx; + struct wcd9xxx_core_resource *core_res = + &wcd9xxx->core_res; + + wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, tavil); +} + +static int wcd934x_get_micb_vout_ctl_val(u32 micb_mv) +{ + /* min micbias voltage is 1V and maximum is 2.85V */ + if (micb_mv < 1000 || micb_mv > 2850) { + pr_err("%s: unsupported micbias voltage\n", __func__); + return -EINVAL; + } + + return (micb_mv - 1000) / 50; +} + +static int tavil_handle_pdata(struct tavil_priv *tavil, + struct wcd9xxx_pdata *pdata) +{ + struct snd_soc_codec *codec = tavil->codec; + int vout_ctl_1, vout_ctl_2, vout_ctl_3, vout_ctl_4; + int rc = 0; + + if (!pdata) { + dev_err(codec->dev, "%s: NULL pdata\n", __func__); + return -ENODEV; + } + + /* set micbias voltage */ + vout_ctl_1 = wcd934x_get_micb_vout_ctl_val(pdata->micbias.micb1_mv); + vout_ctl_2 = wcd934x_get_micb_vout_ctl_val(pdata->micbias.micb2_mv); + vout_ctl_3 = wcd934x_get_micb_vout_ctl_val(pdata->micbias.micb3_mv); + vout_ctl_4 = wcd934x_get_micb_vout_ctl_val(pdata->micbias.micb4_mv); + + if (IS_ERR_VALUE(vout_ctl_1) || IS_ERR_VALUE(vout_ctl_2) || + IS_ERR_VALUE(vout_ctl_3) || IS_ERR_VALUE(vout_ctl_4)) { + rc = -EINVAL; + goto done; + } + snd_soc_update_bits(codec, WCD934X_ANA_MICB1, 0x3F, vout_ctl_1); + snd_soc_update_bits(codec, WCD934X_ANA_MICB2, 0x3F, vout_ctl_2); + snd_soc_update_bits(codec, WCD934X_ANA_MICB3, 0x3F, vout_ctl_3); + snd_soc_update_bits(codec, WCD934X_ANA_MICB4, 0x3F, vout_ctl_4); + +done: + return rc; +} + +static void tavil_enable_sido_buck(struct snd_soc_codec *codec) +{ + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + + snd_soc_update_bits(codec, WCD934X_ANA_RCO, 0x80, 0x80); + usleep_range(100, 110); + snd_soc_update_bits(codec, WCD934X_ANA_BUCK_CTL, 0x02, 0x02); + usleep_range(100, 110); + snd_soc_update_bits(codec, WCD934X_ANA_BUCK_CTL, 0x01, 0x01); + usleep_range(100, 110); + snd_soc_update_bits(codec, WCD934X_ANA_BUCK_CTL, 0x04, 0x04); + usleep_range(100, 110); + tavil->resmgr->sido_input_src = SIDO_SOURCE_RCO_BG; +} + +static int tavil_soc_codec_probe(struct snd_soc_codec *codec) +{ + struct wcd9xxx *control; + struct tavil_priv *tavil; + struct wcd9xxx_pdata *pdata; + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + int i, ret; + void *ptr = NULL; + + control = dev_get_drvdata(codec->dev->parent); + + dev_info(codec->dev, "%s()\n", __func__); + tavil = snd_soc_codec_get_drvdata(codec); + + /* Resource Manager post Init */ + ret = wcd_resmgr_post_init(tavil->resmgr, NULL, codec); + if (ret) { + dev_err(codec->dev, "%s: wcd resmgr post init failed\n", + __func__); + goto err; + } + /* Class-H Init */ + wcd_clsh_init(&tavil->clsh_d); + /* Default HPH Mode to Class-H HiFi */ + tavil->hph_mode = CLS_H_HIFI; + + tavil->codec = codec; + for (i = 0; i < COMPANDER_MAX; i++) + tavil->comp_enabled[i] = 0; + + dev_dbg(codec->dev, "%s: MCLK Rate = %x\n", __func__, + control->mclk_rate); + if (control->mclk_rate == WCD934X_MCLK_CLK_12P288MHZ) + snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_MCLK_CFG, + 0x03, 0x00); + else if (control->mclk_rate == WCD934X_MCLK_CLK_9P6MHZ) + snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_MCLK_CFG, + 0x03, 0x01); + tavil_codec_init_reg(codec); + tavil_enable_sido_buck(codec); + + pdata = dev_get_platdata(codec->dev->parent); + ret = tavil_handle_pdata(tavil, pdata); + if (IS_ERR_VALUE(ret)) { + dev_err(codec->dev, "%s: bad pdata\n", __func__); + goto err; + } + + ptr = devm_kzalloc(codec->dev, (sizeof(tavil_rx_chs) + + sizeof(tavil_tx_chs)), GFP_KERNEL); + if (!ptr) { + ret = -ENOMEM; + goto err; + } + + snd_soc_dapm_add_routes(dapm, tavil_slim_audio_map, + ARRAY_SIZE(tavil_slim_audio_map)); + for (i = 0; i < NUM_CODEC_DAIS; i++) { + INIT_LIST_HEAD(&tavil->dai[i].wcd9xxx_ch_list); + init_waitqueue_head(&tavil->dai[i].dai_wait); + } + tavil_slimbus_slave_port_cfg.slave_dev_intfdev_la = + control->slim_slave->laddr; + tavil_slimbus_slave_port_cfg.slave_dev_pgd_la = + control->slim->laddr; + tavil_slimbus_slave_port_cfg.slave_port_mapping[0] = + WCD934X_TX13; + tavil_init_slim_slave_cfg(codec); + + control->num_rx_port = WCD934X_RX_MAX; + control->rx_chs = ptr; + memcpy(control->rx_chs, tavil_rx_chs, sizeof(tavil_rx_chs)); + control->num_tx_port = WCD934X_TX_MAX; + control->tx_chs = ptr + sizeof(tavil_rx_chs); + memcpy(control->tx_chs, tavil_tx_chs, sizeof(tavil_tx_chs)); + + ret = tavil_setup_irqs(tavil); + if (ret) { + dev_err(tavil->dev, "%s: tavil irq setup failed %d\n", + __func__, ret); + goto err_pdata; + } + + for (i = 0; i < WCD934X_NUM_DECIMATORS; i++) { + tavil->tx_hpf_work[i].tavil = tavil; + tavil->tx_hpf_work[i].decimator = i; + INIT_DELAYED_WORK(&tavil->tx_hpf_work[i].dwork, + tavil_tx_hpf_corner_freq_callback); + + tavil->tx_mute_dwork[i].tavil = tavil; + tavil->tx_mute_dwork[i].decimator = i; + INIT_DELAYED_WORK(&tavil->tx_mute_dwork[i].dwork, + tavil_tx_mute_update_callback); + } + snd_soc_dapm_sync(dapm); + return ret; + +err_pdata: + devm_kfree(codec->dev, ptr); +err: + return ret; +} + +static int tavil_soc_codec_remove(struct snd_soc_codec *codec) +{ + struct wcd9xxx *control; + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + + control = dev_get_drvdata(codec->dev->parent); + devm_kfree(codec->dev, control->rx_chs); + tavil_cleanup_irqs(tavil); + + return 0; +} + +static struct regmap *tavil_get_regmap(struct device *dev) +{ + struct wcd9xxx *control = dev_get_drvdata(dev->parent); + + return control->regmap; +} + +static struct snd_soc_codec_driver soc_codec_dev_tavil = { + .probe = tavil_soc_codec_probe, + .remove = tavil_soc_codec_remove, + .controls = tavil_snd_controls, + .num_controls = ARRAY_SIZE(tavil_snd_controls), + .dapm_widgets = tavil_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tavil_dapm_widgets), + .dapm_routes = tavil_audio_map, + .num_dapm_routes = ARRAY_SIZE(tavil_audio_map), + .get_regmap = tavil_get_regmap, +}; + +#ifdef CONFIG_PM +static int tavil_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct tavil_priv *tavil = platform_get_drvdata(pdev); + + if (!tavil) { + dev_err(dev, "%s: tavil private data is NULL\n", __func__); + return -EINVAL; + } + dev_dbg(dev, "%s: system suspend\n", __func__); + return 0; +} + +static int tavil_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct tavil_priv *tavil = platform_get_drvdata(pdev); + + if (!tavil) { + dev_err(dev, "%s: tavil private data is NULL\n", __func__); + return -EINVAL; + } + dev_dbg(dev, "%s: system resume\n", __func__); + return 0; +} + +static const struct dev_pm_ops tavil_pm_ops = { + .suspend = tavil_suspend, + .resume = tavil_resume, +}; +#endif + +static int tavil_swrm_read(void *handle, int reg) +{ + struct tavil_priv *tavil; + struct wcd9xxx *wcd9xxx; + unsigned short swr_rd_addr_base; + unsigned short swr_rd_data_base; + int val, ret; + + if (!handle) { + pr_err("%s: NULL handle\n", __func__); + return -EINVAL; + } + tavil = (struct tavil_priv *)handle; + wcd9xxx = tavil->wcd9xxx; + + dev_dbg(tavil->dev, "%s: Reading soundwire register, 0x%x\n", + __func__, reg); + swr_rd_addr_base = WCD934X_SWR_AHB_BRIDGE_RD_ADDR_0; + swr_rd_data_base = WCD934X_SWR_AHB_BRIDGE_RD_DATA_0; + + mutex_lock(&tavil->swr.read_mutex); + ret = regmap_bulk_write(wcd9xxx->regmap, swr_rd_addr_base, + (u8 *)®, 4); + if (ret < 0) { + dev_err(tavil->dev, "%s: RD Addr Failure\n", __func__); + goto done; + } + ret = regmap_bulk_read(wcd9xxx->regmap, swr_rd_data_base, + (u8 *)&val, 4); + if (ret < 0) { + dev_err(tavil->dev, "%s: RD Data Failure\n", __func__); + goto done; + } + ret = val; +done: + mutex_unlock(&tavil->swr.read_mutex); + + return ret; +} + +static int tavil_swrm_bulk_write(void *handle, u32 *reg, u32 *val, size_t len) +{ + struct tavil_priv *tavil; + struct wcd9xxx *wcd9xxx; + struct wcd9xxx_reg_val *bulk_reg; + unsigned short swr_wr_addr_base; + unsigned short swr_wr_data_base; + int i, j, ret; + + if (!handle || !reg || !val) { + pr_err("%s: NULL parameter\n", __func__); + return -EINVAL; + } + if (len <= 0) { + pr_err("%s: Invalid size: %zu\n", __func__, len); + return -EINVAL; + } + tavil = (struct tavil_priv *)handle; + wcd9xxx = tavil->wcd9xxx; + + swr_wr_addr_base = WCD934X_SWR_AHB_BRIDGE_WR_ADDR_0; + swr_wr_data_base = WCD934X_SWR_AHB_BRIDGE_WR_DATA_0; + + bulk_reg = kzalloc((2 * len * sizeof(struct wcd9xxx_reg_val)), + GFP_KERNEL); + if (!bulk_reg) + return -ENOMEM; + + for (i = 0, j = 0; i < (len * 2); i += 2, j++) { + bulk_reg[i].reg = swr_wr_data_base; + bulk_reg[i].buf = (u8 *)(&val[j]); + bulk_reg[i].bytes = 4; + bulk_reg[i+1].reg = swr_wr_addr_base; + bulk_reg[i+1].buf = (u8 *)(®[j]); + bulk_reg[i+1].bytes = 4; + } + + mutex_lock(&tavil->swr.write_mutex); + ret = wcd9xxx_slim_bulk_write(wcd9xxx, bulk_reg, + (len * 2), false); + if (ret) { + dev_err(tavil->dev, "%s: swrm bulk write failed, ret: %d\n", + __func__, ret); + } + mutex_unlock(&tavil->swr.write_mutex); + + kfree(bulk_reg); + return ret; +} + +static int tavil_swrm_write(void *handle, int reg, int val) +{ + struct tavil_priv *tavil; + struct wcd9xxx *wcd9xxx; + unsigned short swr_wr_addr_base; + unsigned short swr_wr_data_base; + struct wcd9xxx_reg_val bulk_reg[2]; + int ret; + + if (!handle) { + pr_err("%s: NULL handle\n", __func__); + return -EINVAL; + } + tavil = (struct tavil_priv *)handle; + wcd9xxx = tavil->wcd9xxx; + + swr_wr_addr_base = WCD934X_SWR_AHB_BRIDGE_WR_ADDR_0; + swr_wr_data_base = WCD934X_SWR_AHB_BRIDGE_WR_DATA_0; + + /* First Write the Data to register */ + bulk_reg[0].reg = swr_wr_data_base; + bulk_reg[0].buf = (u8 *)(&val); + bulk_reg[0].bytes = 4; + bulk_reg[1].reg = swr_wr_addr_base; + bulk_reg[1].buf = (u8 *)(®); + bulk_reg[1].bytes = 4; + + mutex_lock(&tavil->swr.write_mutex); + ret = wcd9xxx_slim_bulk_write(wcd9xxx, bulk_reg, 2, false); + if (ret < 0) + dev_err(tavil->dev, "%s: WR Data Failure\n", __func__); + mutex_unlock(&tavil->swr.write_mutex); + + return ret; +} + +static int tavil_swrm_clock(void *handle, bool enable) +{ + struct tavil_priv *tavil; + + if (!handle) { + pr_err("%s: NULL handle\n", __func__); + return -EINVAL; + } + tavil = (struct tavil_priv *)handle; + + mutex_lock(&tavil->swr.clk_mutex); + dev_dbg(tavil->dev, "%s: swrm clock %s\n", + __func__, (enable?"enable" : "disable")); + if (enable) { + tavil->swr.clk_users++; + if (tavil->swr.clk_users == 1) { + __tavil_cdc_mclk_enable(tavil, true); + regmap_update_bits(tavil->wcd9xxx->regmap, + WCD934X_CDC_CLK_RST_CTRL_SWR_CONTROL, + 0x01, 0x01); + } + } else { + tavil->swr.clk_users--; + if (tavil->swr.clk_users == 0) { + regmap_update_bits(tavil->wcd9xxx->regmap, + WCD934X_CDC_CLK_RST_CTRL_SWR_CONTROL, + 0x01, 0x00); + __tavil_cdc_mclk_enable(tavil, false); + } + } + dev_dbg(tavil->dev, "%s: swrm clock users %d\n", + __func__, tavil->swr.clk_users); + mutex_unlock(&tavil->swr.clk_mutex); + + return 0; +} + +static int tavil_swrm_handle_irq(void *handle, + irqreturn_t (*swrm_irq_handler)(int irq, + void *data), + void *swrm_handle, + int action) +{ + struct tavil_priv *tavil; + int ret = 0; + struct wcd9xxx *wcd9xxx; + + if (!handle) { + pr_err("%s: NULL handle\n", __func__); + return -EINVAL; + } + tavil = (struct tavil_priv *) handle; + wcd9xxx = tavil->wcd9xxx; + + if (action) { + ret = wcd9xxx_request_irq(&wcd9xxx->core_res, + WCD934X_IRQ_SOUNDWIRE, + swrm_irq_handler, + "Tavil SWR Master", swrm_handle); + if (ret) + dev_err(tavil->dev, "%s: Failed to request irq %d\n", + __func__, WCD934X_IRQ_SOUNDWIRE); + } else + wcd9xxx_free_irq(&wcd9xxx->core_res, WCD934X_IRQ_SOUNDWIRE, + swrm_handle); + + return ret; +} + +static void tavil_add_child_devices(struct work_struct *work) +{ + struct tavil_priv *tavil; + struct platform_device *pdev; + struct device_node *node; + struct wcd9xxx *wcd9xxx; + struct tavil_swr_ctrl_data *swr_ctrl_data = NULL, *temp; + int ret, ctrl_num = 0; + struct wcd_swr_ctrl_platform_data *platdata; + char plat_dev_name[WCD934X_STRING_LEN]; + + tavil = container_of(work, struct tavil_priv, + tavil_add_child_devices_work); + if (!tavil) { + pr_err("%s: Memory for WCD934X does not exist\n", + __func__); + return; + } + wcd9xxx = tavil->wcd9xxx; + if (!wcd9xxx) { + pr_err("%s: Memory for WCD9XXX does not exist\n", + __func__); + return; + } + if (!wcd9xxx->dev->of_node) { + dev_err(wcd9xxx->dev, "%s: DT node for wcd9xxx does not exist\n", + __func__); + return; + } + + platdata = &tavil->swr.plat_data; + + for_each_child_of_node(wcd9xxx->dev->of_node, node) { + if (!strcmp(node->name, "swr_master")) + strlcpy(plat_dev_name, "tavil_swr_ctrl", + (WCD934X_STRING_LEN - 1)); + else if (strnstr(node->name, "msm_cdc_pinctrl", + strlen("msm_cdc_pinctrl")) != NULL) + strlcpy(plat_dev_name, node->name, + (WCD934X_STRING_LEN - 1)); + else + continue; + + pdev = platform_device_alloc(plat_dev_name, -1); + if (!pdev) { + dev_err(wcd9xxx->dev, "%s: pdev memory alloc failed\n", + __func__); + ret = -ENOMEM; + goto err_mem; + } + pdev->dev.parent = tavil->dev; + pdev->dev.of_node = node; + + if (strcmp(node->name, "swr_master") == 0) { + ret = platform_device_add_data(pdev, platdata, + sizeof(*platdata)); + if (ret) { + dev_err(&pdev->dev, + "%s: cannot add plat data ctrl:%d\n", + __func__, ctrl_num); + goto err_pdev_add; + } + } + + ret = platform_device_add(pdev); + if (ret) { + dev_err(&pdev->dev, + "%s: Cannot add platform device\n", + __func__); + goto err_pdev_add; + } + + if (strcmp(node->name, "swr_master") == 0) { + temp = krealloc(swr_ctrl_data, + (ctrl_num + 1) * sizeof( + struct tavil_swr_ctrl_data), + GFP_KERNEL); + if (!temp) { + dev_err(wcd9xxx->dev, "out of memory\n"); + ret = -ENOMEM; + goto err_pdev_add; + } + swr_ctrl_data = temp; + swr_ctrl_data[ctrl_num].swr_pdev = pdev; + ctrl_num++; + dev_dbg(&pdev->dev, + "%s: Added soundwire ctrl device(s)\n", + __func__); + tavil->swr.ctrl_data = swr_ctrl_data; + } + } + + return; + +err_pdev_add: + platform_device_put(pdev); +err_mem: + return; +} + +static int __tavil_enable_efuse_sensing(struct tavil_priv *tavil) +{ + int val, rc; + + __tavil_cdc_mclk_enable(tavil, true); + + regmap_update_bits(tavil->wcd9xxx->regmap, + WCD934X_CHIP_TIER_CTRL_EFUSE_CTL, 0x1E, 0x10); + regmap_update_bits(tavil->wcd9xxx->regmap, + WCD934X_CHIP_TIER_CTRL_EFUSE_CTL, 0x01, 0x01); + + /* + * 5ms sleep required after enabling efuse control + * before checking the status. + */ + usleep_range(5000, 5500); + rc = regmap_read(tavil->wcd9xxx->regmap, + WCD934X_CHIP_TIER_CTRL_EFUSE_STATUS, &val); + if (rc || (!(val & 0x01))) + WARN(1, "%s: Efuse sense is not complete\n", __func__); + + __tavil_cdc_mclk_enable(tavil, false); + + return rc; +} + +static int tavil_probe(struct platform_device *pdev) +{ + int ret = 0; + struct tavil_priv *tavil; + struct clk *wcd_ext_clk; + struct wcd9xxx_resmgr_v2 *resmgr; + int val1, val2, val3, val4; + + tavil = devm_kzalloc(&pdev->dev, sizeof(struct tavil_priv), + GFP_KERNEL); + if (!tavil) + return -ENOMEM; + + platform_set_drvdata(pdev, tavil); + + tavil->wcd9xxx = dev_get_drvdata(pdev->dev.parent); + tavil->dev = &pdev->dev; + INIT_WORK(&tavil->tavil_add_child_devices_work, + tavil_add_child_devices); + mutex_init(&tavil->swr.read_mutex); + mutex_init(&tavil->swr.write_mutex); + mutex_init(&tavil->swr.clk_mutex); + mutex_init(&tavil->codec_mutex); + + /* + * Init resource manager so that if child nodes such as SoundWire + * requests for clock, resource manager can honor the request + */ + resmgr = wcd_resmgr_init(&tavil->wcd9xxx->core_res, NULL); + if (IS_ERR(resmgr)) { + ret = PTR_ERR(resmgr); + dev_err(&pdev->dev, "%s: Failed to initialize wcd resmgr\n", + __func__); + goto err_resmgr; + } + tavil->resmgr = resmgr; + tavil->swr.plat_data.handle = (void *) tavil; + tavil->swr.plat_data.read = tavil_swrm_read; + tavil->swr.plat_data.write = tavil_swrm_write; + tavil->swr.plat_data.bulk_write = tavil_swrm_bulk_write; + tavil->swr.plat_data.clk = tavil_swrm_clock; + tavil->swr.plat_data.handle_irq = tavil_swrm_handle_irq; + + /* Register for Clock */ + wcd_ext_clk = clk_get(tavil->wcd9xxx->dev, "wcd_clk"); + if (IS_ERR(wcd_ext_clk)) { + dev_err(tavil->wcd9xxx->dev, "%s: clk get %s failed\n", + __func__, "wcd_ext_clk"); + goto err_clk; + } + tavil->wcd_ext_clk = wcd_ext_clk; + set_bit(AUDIO_NOMINAL, &tavil->status_mask); + /* Update codec register default values */ + tavil_update_reg_defaults(tavil); + __tavil_enable_efuse_sensing(tavil); + + regmap_read(tavil->wcd9xxx->regmap, + WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT0, &val1); + regmap_read(tavil->wcd9xxx->regmap, + WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT14, &val2); + regmap_read(tavil->wcd9xxx->regmap, + WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT15, &val3); + regmap_read(tavil->wcd9xxx->regmap, + WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT9, &val4); + dev_dbg(&pdev->dev, "%s: chip version :0x%x 0x:%x 0x:%x 0x:%x\n", + __func__, val1, val2, val3, val4); + + /* Register with soc framework */ + ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tavil, + tavil_dai, ARRAY_SIZE(tavil_dai)); + if (ret) { + dev_err(&pdev->dev, "%s: Codec registration failed\n", + __func__); + goto err_cdc_reg; + } + schedule_work(&tavil->tavil_add_child_devices_work); + + return ret; + +err_cdc_reg: + clk_put(tavil->wcd_ext_clk); +err_clk: + wcd_resmgr_remove(tavil->resmgr); +err_resmgr: + mutex_destroy(&tavil->codec_mutex); + mutex_destroy(&tavil->swr.read_mutex); + mutex_destroy(&tavil->swr.write_mutex); + mutex_destroy(&tavil->swr.clk_mutex); + devm_kfree(&pdev->dev, tavil); + + return ret; +} + +static int tavil_remove(struct platform_device *pdev) +{ + struct tavil_priv *tavil; + + tavil = platform_get_drvdata(pdev); + if (!tavil) + return -EINVAL; + + mutex_destroy(&tavil->codec_mutex); + mutex_destroy(&tavil->swr.read_mutex); + mutex_destroy(&tavil->swr.write_mutex); + mutex_destroy(&tavil->swr.clk_mutex); + + snd_soc_unregister_codec(&pdev->dev); + clk_put(tavil->wcd_ext_clk); + wcd_resmgr_remove(tavil->resmgr); + devm_kfree(&pdev->dev, tavil); + return 0; +} + +static struct platform_driver tavil_codec_driver = { + .probe = tavil_probe, + .remove = tavil_remove, + .driver = { + .name = "tavil_codec", + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &tavil_pm_ops, +#endif + }, +}; + +module_platform_driver(tavil_codec_driver); + +MODULE_DESCRIPTION("Tavil Codec driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/wcd934x/wcd934x.h b/sound/soc/codecs/wcd934x/wcd934x.h new file mode 100644 index 000000000000..f21b72d71ddb --- /dev/null +++ b/sound/soc/codecs/wcd934x/wcd934x.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef WCD934X_H +#define WCD934X_H + +#include <sound/apr_audio-v2.h> +#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h> + +#define WCD934X_REGISTER_START_OFFSET 0x800 +#define WCD934X_SB_PGD_PORT_RX_BASE 0x40 +#define WCD934X_SB_PGD_PORT_TX_BASE 0x50 + +#define WCD934X_DMIC_CLK_DIV_2 0x0 +#define WCD934X_DMIC_CLK_DIV_3 0x1 +#define WCD934X_DMIC_CLK_DIV_4 0x2 +#define WCD934X_DMIC_CLK_DIV_6 0x3 +#define WCD934X_DMIC_CLK_DIV_8 0x4 +#define WCD934X_DMIC_CLK_DIV_16 0x5 +#define WCD934X_DMIC_CLK_DRIVE_DEFAULT 0x02 + +/* Number of input and output Slimbus port */ +enum { + WCD934X_RX0 = 0, + WCD934X_RX1, + WCD934X_RX2, + WCD934X_RX3, + WCD934X_RX4, + WCD934X_RX5, + WCD934X_RX6, + WCD934X_RX7, + WCD934X_RX_MAX, +}; + +enum { + WCD934X_TX0 = 0, + WCD934X_TX1, + WCD934X_TX2, + WCD934X_TX3, + WCD934X_TX4, + WCD934X_TX5, + WCD934X_TX6, + WCD934X_TX7, + WCD934X_TX8, + WCD934X_TX9, + WCD934X_TX10, + WCD934X_TX11, + WCD934X_TX12, + WCD934X_TX13, + WCD934X_TX14, + WCD934X_TX15, + WCD934X_TX_MAX, +}; + +enum { + /* INTR_REG 0 */ + WCD934X_IRQ_FLL_LOCK_LOSS = 1, + WCD934X_IRQ_HPH_PA_OCPL_FAULT, + WCD934X_IRQ_HPH_PA_OCPR_FAULT, + WCD934X_IRQ_EAR_PA_OCP_FAULT, + WCD934X_IRQ_HPH_PA_CNPL_COMPLETE, + WCD934X_IRQ_HPH_PA_CNPR_COMPLETE, + WCD934X_IRQ_EAR_PA_CNP_COMPLETE, + /* INTR_REG 1 */ + WCD934X_IRQ_MBHC_SW_DET, + WCD934X_IRQ_MBHC_ELECT_INS_REM_DET, + WCD934X_IRQ_MBHC_BUTTON_PRESS_DET, + WCD934X_IRQ_MBHC_BUTTON_RELEASE_DET, + WCD934X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, + WCD934X_IRQ_RESERVED_0, + WCD934X_IRQ_RESERVED_1, + WCD934X_IRQ_RESERVED_2, + /* INTR_REG 2 */ + WCD934X_IRQ_LINE_PA1_CNP_COMPLETE, + WCD934X_IRQ_LINE_PA2_CNP_COMPLETE, + WCD934X_IRQ_SLNQ_ANALOG_ERROR, + WCD934X_IRQ_RESERVED_3, + WCD934X_IRQ_SOUNDWIRE, + WCD934X_IRQ_VDD_DIG_RAMP_COMPLETE, + WCD934X_IRQ_RCO_ERROR, + WCD934X_IRQ_CPE_ERROR, + /* INTR_REG 3 */ + WCD934X_IRQ_MAD_AUDIO, + WCD934X_IRQ_MAD_BEACON, + WCD934X_IRQ_MAD_ULTRASOUND, + WCD934X_IRQ_VBAT_ATTACK, + WCD934X_IRQ_VBAT_RESTORE, + WCD934X_IRQ_CPE1_INTR, + WCD934X_IRQ_RESERVED_4, + WCD934X_IRQ_SLNQ_DIGITAL, + WCD934X_NUM_IRQS, +}; + +/* + * Selects compander and smart boost settings + * for a given speaker mode + */ +enum { + WCD934X_SPKR_MODE_DEFAULT, + WCD934X_SPKR_MODE_1, /* COMP Gain = 12dB, Smartboost Max = 5.5V */ +}; + +/* + * Rx path gain offsets + */ +enum { + WCD934X_RX_GAIN_OFFSET_M1P5_DB, + WCD934X_RX_GAIN_OFFSET_0_DB, +}; + +/* + * Dai data structure holds the + * dai specific info like rate, + * channel number etc. + */ +struct tavil_codec_dai_data { + u32 rate; + u32 *ch_num; + u32 ch_act; + u32 ch_tot; +}; + +/* + * Structure used to update codec + * register defaults after reset + */ +struct tavil_reg_mask_val { + u16 reg; + u8 mask; + u8 val; +}; + +extern void *tavil_get_afe_config(struct snd_soc_codec *codec, + enum afe_config_type config_type); +extern int tavil_cdc_mclk_enable(struct snd_soc_codec *codec, bool enable); +extern int tavil_set_spkr_mode(struct snd_soc_codec *codec, int mode); +extern int tavil_set_spkr_gain_offset(struct snd_soc_codec *codec, int offset); +#endif diff --git a/sound/soc/codecs/wcd9xxx-resmgr-v2.c b/sound/soc/codecs/wcd9xxx-resmgr-v2.c index 9cd9736dc850..7ea1a93d7fb7 100644 --- a/sound/soc/codecs/wcd9xxx-resmgr-v2.c +++ b/sound/soc/codecs/wcd9xxx-resmgr-v2.c @@ -14,11 +14,16 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/delay.h> +#include <linux/mfd/wcd9xxx/core.h> #include <linux/mfd/wcd9335/registers.h> +#include <linux/mfd/wcd934x/registers.h> #include <sound/soc.h> #include "wcd9xxx-resmgr-v2.h" #define WCD9XXX_RCO_CALIBRATION_DELAY_INC_US 5000 +#define WCD93XX_ANA_BIAS 0x0601 +#define WCD93XX_CDC_CLK_RST_CTRL_MCLK_CONTROL 0x0d41 +#define WCD93XX_CDC_CLK_RST_CTRL_FS_CNT_CONTROL 0x0d42 static const char *wcd_resmgr_clk_type_to_str(enum wcd_clock_type clk_type) { @@ -38,6 +43,15 @@ static int wcd_resmgr_codec_reg_update_bits(struct wcd9xxx_resmgr_v2 *resmgr, bool change; int ret; + if (resmgr->codec_type == WCD934X) { + /* Tavil does not support ANA_CLK_TOP register */ + if (reg == WCD9335_ANA_CLK_TOP) + return 0; + } else { + /* Tasha does not support CLK_SYS_MCLK_PRG register */ + if (reg == WCD934X_CLK_SYS_MCLK_PRG) + return 0; + } if (resmgr->codec) { ret = snd_soc_update_bits(resmgr->codec, reg, mask, val); } else if (resmgr->core_res->wcd_core_regmap) { @@ -59,6 +73,13 @@ static int wcd_resmgr_codec_reg_read(struct wcd9xxx_resmgr_v2 *resmgr, { int val, ret; + if (resmgr->codec_type == WCD934X) { + if (reg == WCD9335_ANA_CLK_TOP) + return 0; + } else { + if (reg == WCD934X_CLK_SYS_MCLK_PRG) + return 0; + } if (resmgr->codec) { val = snd_soc_read(resmgr->codec, reg); } else if (resmgr->core_res->wcd_core_regmap) { @@ -147,19 +168,19 @@ int wcd_resmgr_enable_master_bias(struct wcd9xxx_resmgr_v2 *resmgr) resmgr->master_bias_users++; if (resmgr->master_bias_users == 1) { - wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_BIAS, + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_BIAS, 0x80, 0x80); - wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_BIAS, + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_BIAS, 0x40, 0x40); /* * 1ms delay is required after pre-charge is enabled * as per HW requirement */ usleep_range(1000, 1100); - wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_BIAS, + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_BIAS, 0x40, 0x00); - wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_BIAS, - 0x20, 0x00); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_ANA_BIAS, 0x20, 0x00); } pr_debug("%s: current master bias users: %d\n", __func__, @@ -183,10 +204,10 @@ int wcd_resmgr_disable_master_bias(struct wcd9xxx_resmgr_v2 *resmgr) resmgr->master_bias_users--; if (resmgr->master_bias_users == 0) { - wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_BIAS, + wcd_resmgr_codec_reg_update_bits(resmgr, WCD93XX_ANA_BIAS, 0x80, 0x00); - wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_BIAS, - 0x20, 0x00); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_ANA_BIAS, 0x20, 0x00); } mutex_unlock(&resmgr->master_bias_lock); return 0; @@ -212,19 +233,41 @@ static int wcd_resmgr_enable_clk_mclk(struct wcd9xxx_resmgr_v2 *resmgr) } if (++resmgr->clk_mclk_users == 1) { - - wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_CLK_TOP, - 0x80, 0x80); - wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_CLK_TOP, - 0x08, 0x00); - wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_CLK_TOP, - 0x04, 0x04); wcd_resmgr_codec_reg_update_bits(resmgr, - WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, - 0x01, 0x01); + WCD9335_ANA_CLK_TOP, 0x80, 0x80); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD9335_ANA_CLK_TOP, 0x08, 0x00); wcd_resmgr_codec_reg_update_bits(resmgr, - WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL, + WCD9335_ANA_CLK_TOP, 0x04, 0x04); + if (resmgr->codec_type == WCD934X) { + /* + * In tavil clock contrl register is changed + * to CLK_SYS_MCLK_PRG + */ + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD934X_CLK_SYS_MCLK_PRG, 0x91, 0x91); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, 0x01, 0x01); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_CDC_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x01); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD934X_CODEC_RPM_CLK_MCLK_CFG, + 0x04, 0x04); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_CDC_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x01); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD934X_CODEC_RPM_CLK_GATE, 0x03, 0x00); + } else { + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, + 0x01, 0x01); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD93XX_CDC_CLK_RST_CTRL_MCLK_CONTROL, + 0x01, 0x01); + } /* * 10us sleep is required after clock is enabled * as per HW requirement @@ -259,6 +302,8 @@ static int wcd_resmgr_disable_clk_mclk(struct wcd9xxx_resmgr_v2 *resmgr) wcd_resmgr_codec_reg_update_bits(resmgr, WCD9335_ANA_CLK_TOP, 0x04, 0x00); + wcd_resmgr_codec_reg_update_bits(resmgr, + WCD934X_CLK_SYS_MCLK_PRG, 0x01, 0x0); resmgr->clk_type = WCD_CLK_OFF; } @@ -447,6 +492,7 @@ struct wcd9xxx_resmgr_v2 *wcd_resmgr_init( struct snd_soc_codec *codec) { struct wcd9xxx_resmgr_v2 *resmgr; + struct wcd9xxx *wcd9xxx; resmgr = kzalloc(sizeof(struct wcd9xxx_resmgr_v2), GFP_KERNEL); if (!resmgr) { @@ -454,6 +500,13 @@ struct wcd9xxx_resmgr_v2 *wcd_resmgr_init( return ERR_PTR(-ENOMEM); } + wcd9xxx = container_of(core_res, struct wcd9xxx, core_res); + if (!wcd9xxx) { + kfree(resmgr); + pr_err("%s: Cannot get wcd9xx pointer\n", __func__); + return ERR_PTR(-EINVAL); + } + mutex_init(&resmgr->codec_bg_clk_lock); mutex_init(&resmgr->master_bias_lock); resmgr->master_bias_users = 0; @@ -463,6 +516,7 @@ struct wcd9xxx_resmgr_v2 *wcd_resmgr_init( resmgr->codec = codec; resmgr->core_res = core_res; resmgr->sido_input_src = SIDO_SOURCE_INTERNAL; + resmgr->codec_type = wcd9xxx->type; return resmgr; } diff --git a/sound/soc/codecs/wcd9xxx-resmgr-v2.h b/sound/soc/codecs/wcd9xxx-resmgr-v2.h index 61e242d52c1e..c1955d31889f 100644 --- a/sound/soc/codecs/wcd9xxx-resmgr-v2.h +++ b/sound/soc/codecs/wcd9xxx-resmgr-v2.h @@ -42,6 +42,7 @@ struct wcd9xxx_resmgr_v2 { struct mutex codec_bg_clk_lock; struct mutex master_bias_lock; + enum codec_variant codec_type; enum wcd_clock_type clk_type; const struct wcd_resmgr_cb *resmgr_cb; diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c index 803e39e9afa9..1f11725e8843 100644 --- a/sound/soc/codecs/wcd9xxx-resmgr.c +++ b/sound/soc/codecs/wcd9xxx-resmgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -430,15 +430,22 @@ int wcd9xxx_resmgr_enable_config_mode(struct wcd9xxx_resmgr *resmgr, int enable) if (enable) { snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_FREQ, 0x10, 0); /* bandgap mode to fast */ - snd_soc_write(codec, WCD9XXX_A_BIAS_OSC_BG_CTL, 0x17); + if (resmgr->pdata->mclk_rate == WCD9XXX_MCLK_CLK_12P288MHZ) + /* Set current value to 200nA for 12.288MHz clock */ + snd_soc_write(codec, WCD9XXX_A_BIAS_OSC_BG_CTL, 0x37); + else + snd_soc_write(codec, WCD9XXX_A_BIAS_OSC_BG_CTL, 0x17); + usleep_range(5, 10); snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_FREQ, 0x80, 0x80); snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_TEST, 0x80, 0x80); usleep_range(10, 20); snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_TEST, 0x80, 0); usleep_range(10000, 10100); - snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, - 0x08, 0x08); + + if (resmgr->pdata->mclk_rate != WCD9XXX_MCLK_CLK_12P288MHZ) + snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, + 0x08, 0x08); } else { snd_soc_update_bits(codec, WCD9XXX_A_BIAS_OSC_BG_CTL, 0x1, 0); snd_soc_update_bits(codec, WCD9XXX_A_RC_OSC_FREQ, 0x80, 0); @@ -476,13 +483,24 @@ static void wcd9xxx_enable_clock_block(struct wcd9xxx_resmgr *resmgr, /* 1ms sleep required after BG enabled */ usleep_range(1000, 1100); - snd_soc_update_bits(codec, TOMTOM_A_RCO_CTRL, 0x18, 0x10); - valr = snd_soc_read(codec, TOMTOM_A_QFUSE_DATA_OUT0) & (0x04); - valr1 = snd_soc_read(codec, TOMTOM_A_QFUSE_DATA_OUT1) & (0x08); - valr = (valr >> 1) | (valr1 >> 3); - snd_soc_update_bits(codec, TOMTOM_A_RCO_CTRL, 0x60, - valw[valr] << 5); - + if (resmgr->pdata->mclk_rate == WCD9XXX_MCLK_CLK_12P288MHZ) { + /* + * Set RCO clock rate as 12.288MHz rate explicitly + * as the Qfuse values are incorrect for this rate + */ + snd_soc_update_bits(codec, TOMTOM_A_RCO_CTRL, + 0x50, 0x50); + } else { + snd_soc_update_bits(codec, TOMTOM_A_RCO_CTRL, + 0x18, 0x10); + valr = snd_soc_read(codec, + TOMTOM_A_QFUSE_DATA_OUT0) & (0x04); + valr1 = snd_soc_read(codec, + TOMTOM_A_QFUSE_DATA_OUT1) & (0x08); + valr = (valr >> 1) | (valr1 >> 3); + snd_soc_update_bits(codec, TOMTOM_A_RCO_CTRL, 0x60, + valw[valr] << 5); + } snd_soc_update_bits(codec, TOMTOM_A_RCO_CTRL, 0x80, 0x80); do { @@ -611,9 +629,11 @@ void wcd9xxx_resmgr_get_clk_block(struct wcd9xxx_resmgr *resmgr, wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_PRE_RCO_ON); /* CLK MUX to RCO */ - snd_soc_update_bits(codec, - WCD9XXX_A_CLK_BUFF_EN1, - 0x08, 0x08); + if (resmgr->pdata->mclk_rate != + WCD9XXX_MCLK_CLK_12P288MHZ) + snd_soc_update_bits(codec, + WCD9XXX_A_CLK_BUFF_EN1, + 0x08, 0x08); resmgr->clk_type = WCD9XXX_CLK_RCO; wcd9xxx_resmgr_notifier_call(resmgr, WCD9XXX_EVENT_POST_RCO_ON); diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index c799cca5abeb..6b864c0fc2b6 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c @@ -459,7 +459,7 @@ static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; - int value = ucontrol->value.integer.value[0]; + int value = ucontrol->value.enumerated.item[0]; int reg; /* Don't allow on the fly reconfiguration */ @@ -549,7 +549,7 @@ static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; - int value = ucontrol->value.integer.value[0]; + int value = ucontrol->value.enumerated.item[0]; int reg; /* Don't allow on the fly reconfiguration */ @@ -582,7 +582,7 @@ static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; - int value = ucontrol->value.integer.value[0]; + int value = ucontrol->value.enumerated.item[0]; int reg; /* Don't allow on the fly reconfiguration */ @@ -749,7 +749,7 @@ static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994 *control = wm8994->wm8994; - int value = ucontrol->value.integer.value[0]; + int value = ucontrol->value.enumerated.item[0]; int reg; /* Don't allow on the fly reconfiguration */ diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 2ccbb322df77..a18aecb49935 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -362,7 +362,7 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol, struct wm8994 *control = wm8994->wm8994; struct wm8994_pdata *pdata = &control->pdata; int drc = wm8994_get_drc(kcontrol->id.name); - int value = ucontrol->value.integer.value[0]; + int value = ucontrol->value.enumerated.item[0]; if (drc < 0) return drc; @@ -469,7 +469,7 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol, struct wm8994 *control = wm8994->wm8994; struct wm8994_pdata *pdata = &control->pdata; int block = wm8994_get_retune_mobile_block(kcontrol->id.name); - int value = ucontrol->value.integer.value[0]; + int value = ucontrol->value.enumerated.item[0]; if (block < 0) return block; diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig index 82d0737dfb30..759716199224 100644 --- a/sound/soc/msm/Kconfig +++ b/sound/soc/msm/Kconfig @@ -126,6 +126,7 @@ config SND_SOC_MSMCOBALT select MSM_QDSP6_APRV2_GLINK select MSM_QDSP6V2_CODECS select SND_SOC_WCD9335 + select SND_SOC_WCD934X select SND_SOC_WSA881X select SND_SOC_MSM_HDMI_CODEC_RX select DTS_SRS_TM diff --git a/sound/soc/msm/msm8996.c b/sound/soc/msm/msm8996.c index d8e897fafb51..1d4f723dd572 100644 --- a/sound/soc/msm/msm8996.c +++ b/sound/soc/msm/msm8996.c @@ -103,9 +103,9 @@ static const char *const slim0_tx_ch_text[] = {"One", "Two", "Three", "Four", static const char *const vi_feed_ch_text[] = {"One", "Two"}; static char const *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five", "Six", "Seven", "Eight"}; -static char const *rx_bit_format_text[] = {"S16_LE", "S24_LE"}; -static char const *slim5_rx_bit_format_text[] = {"S16_LE", "S24_LE"}; -static char const *slim6_rx_bit_format_text[] = {"S16_LE", "S24_LE"}; +static char const *rx_bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"}; +static char const *slim5_rx_bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"}; +static char const *slim6_rx_bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE"}; static char const *slim0_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96", "KHZ_192", "KHZ_44P1", "KHZ_8", "KHZ_16", "KHZ_32"}; @@ -682,6 +682,9 @@ static int slim0_tx_bit_format_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { switch (slim0_tx_bit_format) { + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; case SNDRV_PCM_FORMAT_S24_LE: ucontrol->value.integer.value[0] = 1; break; @@ -703,6 +706,9 @@ static int slim0_tx_bit_format_put(struct snd_kcontrol *kcontrol, int rc = 0; switch (ucontrol->value.integer.value[0]) { + case 2: + slim0_tx_bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; case 1: slim0_tx_bit_format = SNDRV_PCM_FORMAT_S24_LE; break; @@ -716,6 +722,10 @@ static int slim0_tx_bit_format_put(struct snd_kcontrol *kcontrol, break; } + pr_debug("%s: ucontrol value = %ld, slim0_tx_bit_format = %d\n", + __func__, ucontrol->value.integer.value[0], + slim0_tx_bit_format); + return rc; } @@ -856,6 +866,10 @@ static int slim5_rx_bit_format_get(struct snd_kcontrol *kcontrol, { switch (slim5_rx_bit_format) { + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: ucontrol->value.integer.value[0] = 1; break; @@ -877,6 +891,9 @@ static int slim5_rx_bit_format_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { switch (ucontrol->value.integer.value[0]) { + case 2: + slim5_rx_bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; case 1: slim5_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE; break; @@ -893,6 +910,10 @@ static int slim6_rx_bit_format_get(struct snd_kcontrol *kcontrol, { switch (slim6_rx_bit_format) { + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: ucontrol->value.integer.value[0] = 1; break; @@ -914,6 +935,9 @@ static int slim6_rx_bit_format_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { switch (ucontrol->value.integer.value[0]) { + case 2: + slim6_rx_bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; case 1: slim6_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE; break; @@ -930,6 +954,10 @@ static int slim0_rx_bit_format_get(struct snd_kcontrol *kcontrol, { switch (slim0_rx_bit_format) { + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: ucontrol->value.integer.value[0] = 1; break; @@ -951,6 +979,9 @@ static int slim0_rx_bit_format_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { switch (ucontrol->value.integer.value[0]) { + case 2: + slim0_rx_bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; case 1: slim0_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE; break; @@ -1074,6 +1105,10 @@ static int hdmi_rx_bit_format_get(struct snd_kcontrol *kcontrol, { switch (hdmi_rx_bit_format) { + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: ucontrol->value.integer.value[0] = 1; break; @@ -1095,6 +1130,9 @@ static int hdmi_rx_bit_format_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { switch (ucontrol->value.integer.value[0]) { + case 2: + hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; case 1: hdmi_rx_bit_format = SNDRV_PCM_FORMAT_S24_LE; break; @@ -1499,18 +1537,21 @@ static const struct soc_enum msm_snd_enum[] = { SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text), SOC_ENUM_SINGLE_EXT(8, slim0_tx_ch_text), SOC_ENUM_SINGLE_EXT(7, hdmi_rx_ch_text), - SOC_ENUM_SINGLE_EXT(2, rx_bit_format_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_bit_format_text), + rx_bit_format_text), SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim0_rx_sample_rate_text), slim0_rx_sample_rate_text), SOC_ENUM_SINGLE_EXT(8, proxy_rx_ch_text), SOC_ENUM_SINGLE_EXT(3, hdmi_rx_sample_rate_text), SOC_ENUM_SINGLE_EXT(4, slim5_rx_sample_rate_text), - SOC_ENUM_SINGLE_EXT(2, slim5_rx_bit_format_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim5_rx_bit_format_text), + slim5_rx_bit_format_text), SOC_ENUM_SINGLE_EXT(2, slim5_rx_ch_text), SOC_ENUM_SINGLE_EXT(2, hifi_function), SOC_ENUM_SINGLE_EXT(2, vi_feed_ch_text), SOC_ENUM_SINGLE_EXT(4, slim6_rx_sample_rate_text), - SOC_ENUM_SINGLE_EXT(2, slim6_rx_bit_format_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim6_rx_bit_format_text), + slim6_rx_bit_format_text), SOC_ENUM_SINGLE_EXT(2, slim6_rx_ch_text), }; diff --git a/sound/soc/msm/msmcobalt.c b/sound/soc/msm/msmcobalt.c index 88225e8a4861..706a9aec6a89 100644 --- a/sound/soc/msm/msmcobalt.c +++ b/sound/soc/msm/msmcobalt.c @@ -35,6 +35,7 @@ #include <device_event.h> #include "qdsp6v2/msm-pcm-routing-v2.h" #include "../codecs/wcd9335.h" +#include "../codecs/wcd934x/wcd934x.h" #include "../codecs/wsa881x.h" #define DRV_NAME "msmcobalt-asoc-snd" @@ -89,13 +90,7 @@ enum { SLIM_TX_MAX, }; -struct slim_ch_config { - u32 sample_rate; - u32 bit_format; - u32 channels; -}; - -struct usb_be_config { +struct dev_config { u32 sample_rate; u32 bit_format; u32 channels; @@ -122,7 +117,7 @@ struct msm_asoc_wcd93xx_codec { }; /* Default configuration of slimbus channels */ -static struct slim_ch_config slim_rx_cfg[] = { +static struct dev_config slim_rx_cfg[] = { [SLIM_RX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, [SLIM_RX_1] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, [SLIM_RX_2] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, @@ -133,7 +128,7 @@ static struct slim_ch_config slim_rx_cfg[] = { [SLIM_RX_7] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, }; -static struct slim_ch_config slim_tx_cfg[] = { +static struct dev_config slim_tx_cfg[] = { [SLIM_TX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, [SLIM_TX_1] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, [SLIM_TX_2] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, @@ -145,18 +140,30 @@ static struct slim_ch_config slim_tx_cfg[] = { [SLIM_TX_8] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, }; -static struct usb_be_config usb_rx_cfg = { +static struct dev_config usb_rx_cfg = { .sample_rate = SAMPLING_RATE_48KHZ, .bit_format = SNDRV_PCM_FORMAT_S16_LE, .channels = 2, }; -static struct usb_be_config usb_tx_cfg = { +static struct dev_config usb_tx_cfg = { .sample_rate = SAMPLING_RATE_48KHZ, .bit_format = SNDRV_PCM_FORMAT_S16_LE, .channels = 1, }; +static struct dev_config hdmi_rx_cfg = { + .sample_rate = SAMPLING_RATE_48KHZ, + .bit_format = SNDRV_PCM_FORMAT_S16_LE, + .channels = 2, +}; + +static struct dev_config proxy_rx_cfg = { + .sample_rate = SAMPLING_RATE_48KHZ, + .bit_format = SNDRV_PCM_FORMAT_S16_LE, + .channels = 2, +}; + static int msm_vi_feed_tx_ch = 2; static const char *const slim_rx_ch_text[] = {"One", "Two"}; static const char *const slim_tx_ch_text[] = {"One", "Two", "Three", "Four", @@ -169,10 +176,14 @@ static char const *slim_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_96", "KHZ_192"}; static char const *bt_sco_sample_rate_text[] = {"KHZ_8", "KHZ_16"}; static const char *const usb_ch_text[] = {"One", "Two"}; +static char const *ch_text[] = {"Two", "Three", "Four", "Five", + "Six", "Seven", "Eight"}; static char const *usb_sample_rate_text[] = {"KHZ_8", "KHZ_11P025", "KHZ_16", "KHZ_22P05", "KHZ_32", "KHZ_44P1", "KHZ_48", "KHZ_96", "KHZ_192"}; +static char const *hdmi_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96", + "KHZ_192"}; static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_chs, slim_rx_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_chs, slim_tx_ch_text); @@ -182,12 +193,15 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_chs, slim_rx_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_chs, usb_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_chs, usb_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(vi_feed_tx_chs, vi_feed_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(hdmi_rx_chs, ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(proxy_rx_chs, ch_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(hdmi_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_sample_rate, slim_sample_rate_text); @@ -195,6 +209,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(bt_sco_sample_rate, bt_sco_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_sample_rate, usb_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_sample_rate, usb_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(hdmi_rx_sample_rate, hdmi_rx_sample_rate_text); static struct platform_device *spdev; @@ -232,7 +247,7 @@ static struct wcd_mbhc_config wcd_mbhc_cfg = { .moist_cfg = { V_45_MV, I_3P0_UA }, }; -static struct snd_soc_dapm_route wcd9335_audio_paths[] = { +static struct snd_soc_dapm_route wcd_audio_paths[] = { {"MIC BIAS1", NULL, "MCLK"}, {"MIC BIAS2", NULL, "MCLK"}, {"MIC BIAS3", NULL, "MCLK"}, @@ -347,6 +362,8 @@ static int slim_get_port_idx(struct snd_kcontrol *kcontrol) port_id = SLIM_RX_0; else if (strnstr(kcontrol->id.name, "SLIM_5_RX", sizeof("SLIM_5_RX"))) port_id = SLIM_RX_5; + else if (strnstr(kcontrol->id.name, "SLIM_6_RX", sizeof("SLIM_6_RX"))) + port_id = SLIM_RX_6; else if (strnstr(kcontrol->id.name, "SLIM_0_TX", sizeof("SLIM_0_TX"))) port_id = SLIM_TX_0; else if (strnstr(kcontrol->id.name, "SLIM_1_TX", sizeof("SLIM_1_TX"))) @@ -563,9 +580,9 @@ static int msm_slim_tx_ch_put(struct snd_kcontrol *kcontrol, if (ch_num < 0) return ch_num; - slim_rx_cfg[ch_num].channels = ucontrol->value.enumerated.item[0] + 1; + slim_tx_cfg[ch_num].channels = ucontrol->value.enumerated.item[0] + 1; pr_debug("%s: msm_slim_[%d]_tx_ch = %d\n", __func__, - ch_num, slim_rx_cfg[ch_num].channels); + ch_num, slim_tx_cfg[ch_num].channels); return 1; } @@ -912,6 +929,150 @@ static int usb_audio_tx_format_put(struct snd_kcontrol *kcontrol, return rc; } +static int hdmi_rx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + switch (hdmi_rx_cfg.bit_format) { + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + + pr_debug("%s: hdmi_rx_cfg = %d, ucontrol value = %ld\n", + __func__, hdmi_rx_cfg.bit_format, + ucontrol->value.integer.value[0]); + + return 0; +} + +static int hdmi_rx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 2: + hdmi_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + hdmi_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + hdmi_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: hdmi_rx_cfg.bit_format = %d, ucontrol value = %ld\n", + __func__, hdmi_rx_cfg.bit_format, + ucontrol->value.integer.value[0]); + + return 0; +} + +static int hdmi_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: hdmi_rx_cfg.channels = %d\n", __func__, + hdmi_rx_cfg.channels); + ucontrol->value.integer.value[0] = hdmi_rx_cfg.channels - 2; + + return 0; +} + +static int hdmi_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + hdmi_rx_cfg.channels = ucontrol->value.integer.value[0] + 2; + if (hdmi_rx_cfg.channels > 8) { + pr_err("%s: channels %d exceeded 8.Limiting to max chs-8\n", + __func__, hdmi_rx_cfg.channels); + hdmi_rx_cfg.channels = 8; + } + pr_debug("%s: hdmi_rx_cfg.channels = %d\n", __func__, + hdmi_rx_cfg.channels); + + return 1; +} + +static int hdmi_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int sample_rate_val = 0; + + switch (hdmi_rx_cfg.sample_rate) { + case SAMPLING_RATE_192KHZ: + sample_rate_val = 2; + break; + + case SAMPLING_RATE_96KHZ: + sample_rate_val = 1; + break; + + case SAMPLING_RATE_48KHZ: + default: + sample_rate_val = 0; + break; + } + + ucontrol->value.integer.value[0] = sample_rate_val; + pr_debug("%s: hdmi_rx_sample_rate = %d\n", __func__, + hdmi_rx_cfg.sample_rate); + + return 0; +} + +static int hdmi_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: ucontrol value = %ld\n", __func__, + ucontrol->value.integer.value[0]); + + switch (ucontrol->value.integer.value[0]) { + case 2: + hdmi_rx_cfg.sample_rate = SAMPLING_RATE_192KHZ; + break; + case 1: + hdmi_rx_cfg.sample_rate = SAMPLING_RATE_96KHZ; + break; + case 0: + default: + hdmi_rx_cfg.sample_rate = SAMPLING_RATE_48KHZ; + } + + pr_debug("%s: hdmi_rx_cfg.sample_rate = %d\n", __func__, + hdmi_rx_cfg.sample_rate); + + return 0; +} + +static int proxy_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: proxy_rx channels = %d\n", + __func__, proxy_rx_cfg.channels); + ucontrol->value.integer.value[0] = proxy_rx_cfg.channels - 1; + + return 0; +} + +static int proxy_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + proxy_rx_cfg.channels = ucontrol->value.integer.value[0] + 1; + pr_debug("%s: proxy_rx channels = %d\n", + __func__, proxy_rx_cfg.channels); + + return 1; +} + static const struct snd_kcontrol_new msm_snd_controls[] = { SOC_ENUM_EXT("SLIM_0_RX Channels", slim_0_rx_chs, msm_slim_rx_ch_get, msm_slim_rx_ch_put), @@ -929,6 +1090,10 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { usb_audio_rx_ch_get, usb_audio_rx_ch_put), SOC_ENUM_EXT("USB_AUDIO_TX Channels", usb_tx_chs, usb_audio_tx_ch_get, usb_audio_tx_ch_put), + SOC_ENUM_EXT("HDMI_RX Channels", hdmi_rx_chs, + hdmi_rx_ch_get, hdmi_rx_ch_put), + SOC_ENUM_EXT("PROXY_RX Channels", proxy_rx_chs, + proxy_rx_ch_get, proxy_rx_ch_put), SOC_ENUM_EXT("SLIM_0_RX Format", slim_0_rx_format, slim_rx_bit_format_get, slim_rx_bit_format_put), SOC_ENUM_EXT("SLIM_5_RX Format", slim_5_rx_format, @@ -941,6 +1106,8 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { usb_audio_rx_format_get, usb_audio_rx_format_put), SOC_ENUM_EXT("USB_AUDIO_TX Format", usb_tx_format, usb_audio_tx_format_get, usb_audio_tx_format_put), + SOC_ENUM_EXT("HDMI_RX Bit Format", hdmi_rx_format, + hdmi_rx_format_get, hdmi_rx_format_put), SOC_ENUM_EXT("SLIM_0_RX SampleRate", slim_0_rx_sample_rate, slim_rx_sample_rate_get, slim_rx_sample_rate_put), SOC_ENUM_EXT("SLIM_0_TX SampleRate", slim_0_tx_sample_rate, @@ -958,6 +1125,9 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { SOC_ENUM_EXT("USB_AUDIO_TX SampleRate", usb_tx_sample_rate, usb_audio_tx_sample_rate_get, usb_audio_tx_sample_rate_put), + SOC_ENUM_EXT("HDMI_RX SampleRate", hdmi_rx_sample_rate, + hdmi_rx_sample_rate_get, + hdmi_rx_sample_rate_put), }; static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, @@ -967,6 +1137,8 @@ static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, if (!strcmp(dev_name(codec->dev), "tasha_codec")) ret = tasha_cdc_mclk_enable(codec, enable, dapm); + else if (!strcmp(dev_name(codec->dev), "tavil_codec")) + ret = tavil_cdc_mclk_enable(codec, enable); else { dev_err(codec->dev, "%s: unknown codec to enable ext clk\n", __func__); @@ -1145,6 +1317,22 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = channels->max = usb_tx_cfg.channels; break; + case MSM_BACKEND_DAI_HDMI_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + hdmi_rx_cfg.bit_format); + if (channels->max < 2) + channels->min = channels->max = 2; + rate->min = rate->max = hdmi_rx_cfg.sample_rate; + channels->min = channels->max = hdmi_rx_cfg.channels; + break; + + case MSM_BACKEND_DAI_AFE_PCM_RX: + if (channels->max < 2) + channels->min = channels->max = 2; + channels->min = channels->max = proxy_rx_cfg.channels; + rate->min = rate->max = SAMPLING_RATE_48KHZ; + break; + default: rate->min = rate->max = SAMPLING_RATE_48KHZ; break; @@ -1244,6 +1432,13 @@ static int msm_adsp_power_up_config(struct snd_soc_codec *codec) pr_debug("%s: ADSP Audio is ready\n", __func__); adsp_ready = 1; break; + } else { + /* + * ADSP will be coming up after subsystem restart and + * it might not be fully up when the control reaches + * here. So, wait for 50msec before checking ADSP state + */ + msleep(50); } } while (time_after(timeout, jiffies)); @@ -1372,8 +1567,8 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_new_controls(dapm, msm_dapm_widgets, ARRAY_SIZE(msm_dapm_widgets)); - snd_soc_dapm_add_routes(dapm, wcd9335_audio_paths, - ARRAY_SIZE(wcd9335_audio_paths)); + snd_soc_dapm_add_routes(dapm, wcd_audio_paths, + ARRAY_SIZE(wcd_audio_paths)); snd_soc_dapm_ignore_suspend(dapm, "Handset Mic"); snd_soc_dapm_ignore_suspend(dapm, "Headset Mic"); @@ -1411,8 +1606,12 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch), tx_ch, ARRAY_SIZE(rx_ch), rx_ch); - msm_codec_fn.get_afe_config_fn = tasha_get_afe_config; - msm_codec_fn.mbhc_hs_detect_exit = tasha_mbhc_hs_detect_exit; + if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) { + msm_codec_fn.get_afe_config_fn = tavil_get_afe_config; + } else { + msm_codec_fn.get_afe_config_fn = tasha_get_afe_config; + msm_codec_fn.mbhc_hs_detect_exit = tasha_mbhc_hs_detect_exit; + } ret = msm_adsp_power_up_config(codec); if (ret) { @@ -1420,35 +1619,37 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) goto err_afe_cfg; } - config_data = msm_codec_fn.get_afe_config_fn(codec, - AFE_AANC_VERSION); - if (config_data) { - ret = afe_set_config(AFE_AANC_VERSION, config_data, 0); - if (ret) { - pr_err("%s: Failed to set aanc version %d\n", - __func__, ret); - goto err_afe_cfg; + if (!strcmp(dev_name(codec_dai->dev), "tasha_codec")) { + config_data = msm_codec_fn.get_afe_config_fn(codec, + AFE_AANC_VERSION); + if (config_data) { + ret = afe_set_config(AFE_AANC_VERSION, config_data, 0); + if (ret) { + pr_err("%s: Failed to set aanc version %d\n", + __func__, ret); + goto err_afe_cfg; + } } - } - config_data = msm_codec_fn.get_afe_config_fn(codec, - AFE_CDC_CLIP_REGISTERS_CONFIG); - if (config_data) { - ret = afe_set_config(AFE_CDC_CLIP_REGISTERS_CONFIG, - config_data, 0); - if (ret) { - pr_err("%s: Failed to set clip registers %d\n", - __func__, ret); - goto err_afe_cfg; + config_data = msm_codec_fn.get_afe_config_fn(codec, + AFE_CDC_CLIP_REGISTERS_CONFIG); + if (config_data) { + ret = afe_set_config(AFE_CDC_CLIP_REGISTERS_CONFIG, + config_data, 0); + if (ret) { + pr_err("%s: Failed to set clip registers %d\n", + __func__, ret); + goto err_afe_cfg; + } } - } - config_data = msm_codec_fn.get_afe_config_fn(codec, - AFE_CLIP_BANK_SEL); - if (config_data) { - ret = afe_set_config(AFE_CLIP_BANK_SEL, config_data, 0); - if (ret) { - pr_err("%s: Failed to set AFE bank selection %d\n", - __func__, ret); - goto err_afe_cfg; + config_data = msm_codec_fn.get_afe_config_fn(codec, + AFE_CLIP_BANK_SEL); + if (config_data) { + ret = afe_set_config(AFE_CLIP_BANK_SEL, config_data, 0); + if (ret) { + pr_err("%s: Failed to set AFE bank selection %d\n", + __func__, ret); + goto err_afe_cfg; + } } } adsp_state_notifier = subsys_notif_register_notifier("adsp", @@ -1463,27 +1664,35 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) * Send speaker configuration only for WSA8810. * Defalut configuration is for WSA8815. */ - if (rtd_aux && rtd_aux->component) - if (!strcmp(rtd_aux->component->name, WSA8810_NAME_1) || - !strcmp(rtd_aux->component->name, WSA8810_NAME_2)) { - tasha_set_spkr_mode(rtd->codec, SPKR_MODE_1); - tasha_set_spkr_gain_offset(rtd->codec, - RX_GAIN_OFFSET_M1P5_DB); + if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) { + if (rtd_aux && rtd_aux->component) + if (!strcmp(rtd_aux->component->name, WSA8810_NAME_1) || + !strcmp(rtd_aux->component->name, WSA8810_NAME_2)) { + tavil_set_spkr_mode(rtd->codec, SPKR_MODE_1); + tavil_set_spkr_gain_offset(rtd->codec, + RX_GAIN_OFFSET_M1P5_DB); + } + } else { + if (rtd_aux && rtd_aux->component) + if (!strcmp(rtd_aux->component->name, WSA8810_NAME_1) || + !strcmp(rtd_aux->component->name, WSA8810_NAME_2)) { + tasha_set_spkr_mode(rtd->codec, SPKR_MODE_1); + tasha_set_spkr_gain_offset(rtd->codec, + RX_GAIN_OFFSET_M1P5_DB); + } + card = rtd->card->snd_card; + entry = snd_register_module_info(card->module, "codecs", + card->proc_root); + if (!entry) { + pr_debug("%s: Cannot create codecs module entry\n", + __func__); + ret = 0; + goto err_snd_module; + } + pdata->codec_root = entry; + tasha_codec_info_create_codec_entry(pdata->codec_root, codec); } codec_reg_done = true; - - card = rtd->card->snd_card; - entry = snd_register_module_info(card->module, "codecs", - card->proc_root); - if (!entry) { - pr_debug("%s: Cannot create codecs module entry\n", - __func__); - ret = 0; - goto err_snd_module; - } - pdata->codec_root = entry; - tasha_codec_info_create_codec_entry(pdata->codec_root, codec); - return 0; err_snd_module: @@ -2439,6 +2648,33 @@ static struct snd_soc_dai_link msm_tasha_fe_dai_links[] = { }, }; +static struct snd_soc_dai_link msm_tavil_fe_dai_links[] = { + /* Ultrasound RX DAI Link */ + { + .name = "SLIMBUS_2 Hostless Playback", + .stream_name = "SLIMBUS_2 Hostless Playback", + .cpu_dai_name = "msm-dai-q6-dev.16388", + .platform_name = "msm-pcm-hostless", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_rx2", + .ignore_suspend = 1, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ops = &msm_slimbus_2_be_ops, + }, + /* Ultrasound TX DAI Link */ + { + .name = "SLIMBUS_2 Hostless Capture", + .stream_name = "SLIMBUS_2 Hostless Capture", + .cpu_dai_name = "msm-dai-q6-dev.16389", + .platform_name = "msm-pcm-hostless", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_tx2", + .ignore_suspend = 1, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ops = &msm_slimbus_2_be_ops, + }, +}; + static struct snd_soc_dai_link msm_common_be_dai_links[] = { /* Backend AFE DAI Links */ { @@ -2711,6 +2947,132 @@ static struct snd_soc_dai_link msm_tasha_be_dai_links[] = { }, }; +static struct snd_soc_dai_link msm_tavil_be_dai_links[] = { + { + .name = LPASS_BE_SLIMBUS_0_RX, + .stream_name = "Slimbus Playback", + .cpu_dai_name = "msm-dai-q6-dev.16384", + .platform_name = "msm-pcm-routing", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_rx1", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX, + .init = &msm_audrx_init, + .be_hw_params_fixup = msm_be_hw_params_fixup, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + .ops = &msm_be_ops, + }, + { + .name = LPASS_BE_SLIMBUS_0_TX, + .stream_name = "Slimbus Capture", + .cpu_dai_name = "msm-dai-q6-dev.16385", + .platform_name = "msm-pcm-routing", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_tx1", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + .ops = &msm_be_ops, + }, + { + .name = LPASS_BE_SLIMBUS_1_RX, + .stream_name = "Slimbus1 Playback", + .cpu_dai_name = "msm-dai-q6-dev.16386", + .platform_name = "msm-pcm-routing", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_rx1", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_1_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + /* dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_1_TX, + .stream_name = "Slimbus1 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16387", + .platform_name = "msm-pcm-routing", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_tx3", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_3_RX, + .stream_name = "Slimbus3 Playback", + .cpu_dai_name = "msm-dai-q6-dev.16390", + .platform_name = "msm-pcm-routing", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_rx1", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_3_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + /* dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_3_TX, + .stream_name = "Slimbus3 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16391", + .platform_name = "msm-pcm-routing", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_tx1", + .no_pcm = 1, + .dpcm_capture = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_4_RX, + .stream_name = "Slimbus4 Playback", + .cpu_dai_name = "msm-dai-q6-dev.16392", + .platform_name = "msm-pcm-routing", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_rx1", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_4_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + /* dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_5_RX, + .stream_name = "Slimbus5 Playback", + .cpu_dai_name = "msm-dai-q6-dev.16394", + .platform_name = "msm-pcm-routing", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_rx3", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_SLIMBUS_5_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + /* dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, +}; + static struct snd_soc_dai_link msm_wcn_be_dai_links[] = { { .name = LPASS_BE_SLIMBUS_7_RX, @@ -2759,12 +3121,39 @@ static struct snd_soc_dai_link msm_wcn_be_dai_links[] = { }, }; +static struct snd_soc_dai_link hdmi_be_dai_link[] = { + /* HDMI BACK END DAI Link */ + { + .name = LPASS_BE_HDMI, + .stream_name = "HDMI Playback", + .cpu_dai_name = "msm-dai-q6-hdmi.8", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-hdmi-audio-codec-rx", + .codec_dai_name = "msm_hdmi_audio_codec_rx_dai", + .no_pcm = 1, + .dpcm_playback = 1, + .be_id = MSM_BACKEND_DAI_HDMI_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, +}; + static struct snd_soc_dai_link msm_tasha_dai_links[ ARRAY_SIZE(msm_common_dai_links) + ARRAY_SIZE(msm_tasha_fe_dai_links) + ARRAY_SIZE(msm_common_be_dai_links) + ARRAY_SIZE(msm_tasha_be_dai_links) + - ARRAY_SIZE(msm_wcn_be_dai_links)]; + ARRAY_SIZE(msm_wcn_be_dai_links) + + ARRAY_SIZE(hdmi_be_dai_link)]; + +static struct snd_soc_dai_link msm_tavil_dai_links[ + ARRAY_SIZE(msm_common_dai_links) + + ARRAY_SIZE(msm_tavil_fe_dai_links) + + ARRAY_SIZE(msm_common_be_dai_links) + + ARRAY_SIZE(msm_tavil_be_dai_links) + + ARRAY_SIZE(msm_wcn_be_dai_links) + + ARRAY_SIZE(hdmi_be_dai_link)]; static int msm_snd_card_late_probe(struct snd_soc_card *card) { @@ -2810,6 +3199,10 @@ struct snd_soc_card snd_soc_card_tasha_msm = { .late_probe = msm_snd_card_late_probe, }; +struct snd_soc_card snd_soc_card_tavil_msm = { + .name = "msmcobalt-tavil-snd-card", +}; + static int msm_populate_dai_link_component_of_node( struct snd_soc_card *card) { @@ -3072,6 +3465,8 @@ struct snd_soc_card snd_soc_card_stub_msm = { static const struct of_device_id msmcobalt_asoc_machine_of_match[] = { { .compatible = "qcom,msmcobalt-asoc-snd-tasha", .data = "tasha_codec"}, + { .compatible = "qcom,msmcobalt-asoc-snd-tavil", + .data = "tavil_codec"}, { .compatible = "qcom,msmcobalt-asoc-snd-stub", .data = "stub_codec"}, {}, @@ -3081,10 +3476,9 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) { struct snd_soc_card *card = NULL; struct snd_soc_dai_link *dailink; - int len_1, len_2, len_3, len_4; + int len_1, len_2, len_3; int total_links; const struct of_device_id *match; - bool use_wcn_btfm = false; match = of_match_node(msmcobalt_asoc_machine_of_match, dev->of_node); if (!match) { @@ -3093,26 +3487,12 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) return NULL; } - if (of_property_read_bool(dev->of_node, "qcom,wcn-btfm")) { - use_wcn_btfm = true; - dev_dbg(dev, "%s(): WCN BTFM support present\n", __func__); - } else { - dev_dbg(dev, "%s(): No WCN BTFM support\n", __func__); - } - if (!strcmp(match->data, "tasha_codec")) { card = &snd_soc_card_tasha_msm; len_1 = ARRAY_SIZE(msm_common_dai_links); len_2 = len_1 + ARRAY_SIZE(msm_tasha_fe_dai_links); len_3 = len_2 + ARRAY_SIZE(msm_common_be_dai_links); - len_4 = len_3 + ARRAY_SIZE(msm_tasha_be_dai_links); - if (use_wcn_btfm) { - total_links = len_4 + - ARRAY_SIZE(msm_wcn_be_dai_links); - } else { - total_links = len_4; - } - + total_links = len_3 + ARRAY_SIZE(msm_tasha_be_dai_links); memcpy(msm_tasha_dai_links, msm_common_dai_links, sizeof(msm_common_dai_links)); @@ -3125,12 +3505,62 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) memcpy(msm_tasha_dai_links + len_3, msm_tasha_be_dai_links, sizeof(msm_tasha_be_dai_links)); - if (use_wcn_btfm) - memcpy(msm_tasha_dai_links + len_4, + + if (of_property_read_bool(dev->of_node, "qcom,wcn-btfm")) { + dev_dbg(dev, "%s(): WCN BTFM support present\n", + __func__); + memcpy(msm_tasha_dai_links + total_links, msm_wcn_be_dai_links, sizeof(msm_wcn_be_dai_links)); + total_links += ARRAY_SIZE(msm_wcn_be_dai_links); + } + + if (of_property_read_bool(dev->of_node, "qcom,hdmi-audio-rx")) { + dev_dbg(dev, "%s(): HDMI support present\n", __func__); + memcpy(msm_tasha_dai_links + total_links, + hdmi_be_dai_link, + sizeof(hdmi_be_dai_link)); + total_links += ARRAY_SIZE(hdmi_be_dai_link); + } dailink = msm_tasha_dai_links; + } else if (!strcmp(match->data, "tavil_codec")) { + card = &snd_soc_card_tavil_msm; + len_1 = ARRAY_SIZE(msm_common_dai_links); + len_2 = len_1 + ARRAY_SIZE(msm_tavil_fe_dai_links); + len_3 = len_2 + ARRAY_SIZE(msm_common_be_dai_links); + total_links = len_3 + ARRAY_SIZE(msm_tavil_be_dai_links); + memcpy(msm_tavil_dai_links, + msm_common_dai_links, + sizeof(msm_common_dai_links)); + memcpy(msm_tavil_dai_links + len_1, + msm_tavil_fe_dai_links, + sizeof(msm_tavil_fe_dai_links)); + memcpy(msm_tavil_dai_links + len_2, + msm_common_be_dai_links, + sizeof(msm_common_be_dai_links)); + memcpy(msm_tavil_dai_links + len_3, + msm_tavil_be_dai_links, + sizeof(msm_tavil_be_dai_links)); + + if (of_property_read_bool(dev->of_node, "qcom,wcn-btfm")) { + dev_dbg(dev, "%s(): WCN BTFM support present\n", + __func__); + memcpy(msm_tavil_dai_links + total_links, + msm_wcn_be_dai_links, + sizeof(msm_wcn_be_dai_links)); + total_links += ARRAY_SIZE(msm_wcn_be_dai_links); + } + + if (of_property_read_bool(dev->of_node, "qcom,hdmi-audio-rx")) { + dev_dbg(dev, "%s(): HDMI support present\n", __func__); + memcpy(msm_tavil_dai_links + total_links, + hdmi_be_dai_link, + sizeof(hdmi_be_dai_link)); + total_links += ARRAY_SIZE(hdmi_be_dai_link); + } + + dailink = msm_tavil_dai_links; } else if (!strcmp(match->data, "stub_codec")) { card = &snd_soc_card_stub_msm; len_1 = ARRAY_SIZE(msm_stub_fe_dai_links); @@ -3447,7 +3877,10 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) goto err; } - mclk_freq_prop_name = "qcom,tasha-mclk-clk-freq"; + if (!strcmp(match->data, "tasha_codec")) + mclk_freq_prop_name = "qcom,tasha-mclk-clk-freq"; + else + mclk_freq_prop_name = "qcom,tavil-mclk-clk-freq"; ret = of_property_read_u32(pdev->dev.of_node, mclk_freq_prop_name, &pdata->mclk_freq); diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index 1115b13c233c..0af4b336acd7 100755 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -2749,7 +2749,35 @@ static int msm_compr_app_type_cfg_put(struct snd_kcontrol *kcontrol, static int msm_compr_app_type_cfg_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - return 0; + u64 fe_id = kcontrol->private_value; + int ret = 0; + int app_type; + int acdb_dev_id; + int sample_rate; + + pr_debug("%s: fe_id- %llu\n", __func__, fe_id); + if (fe_id >= MSM_FRONTEND_DAI_MAX) { + pr_err("%s Received out of bounds fe_id %llu\n", + __func__, fe_id); + ret = -EINVAL; + goto done; + } + + ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, &app_type, + &acdb_dev_id, &sample_rate); + if (ret < 0) { + pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n", + __func__, ret); + goto done; + } + + ucontrol->value.integer.value[0] = app_type; + ucontrol->value.integer.value[1] = acdb_dev_id; + ucontrol->value.integer.value[2] = sample_rate; + pr_debug("%s: fedai_id %llu, app_type %d, acdb_dev_id %d, sample_rate %d\n", + __func__, fe_id, app_type, acdb_dev_id, sample_rate); +done: + return ret; } static int msm_compr_channel_map_put(struct snd_kcontrol *kcontrol, diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c index 615f7dc2e8d5..7684d27d60a0 100644 --- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c @@ -3505,10 +3505,11 @@ static struct snd_soc_dai_driver msm_dai_q6_mi2s_dai[] = { .stream_name = "Secondary MI2S Playback", .aif_name = "SEC_MI2S_RX", .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | - SNDRV_PCM_RATE_16000, + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE, .rate_min = 8000, - .rate_max = 48000, + .rate_max = 192000, }, .capture = { .stream_name = "Secondary MI2S Capture", @@ -3553,10 +3554,11 @@ static struct snd_soc_dai_driver msm_dai_q6_mi2s_dai[] = { .stream_name = "Quaternary MI2S Playback", .aif_name = "QUAT_MI2S_RX", .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | - SNDRV_PCM_RATE_16000, + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE, .rate_min = 8000, - .rate_max = 48000, + .rate_max = 192000, }, .capture = { .stream_name = "Quaternary MI2S Capture", @@ -3589,10 +3591,11 @@ static struct snd_soc_dai_driver msm_dai_q6_mi2s_dai[] = { .stream_name = "Quinary MI2S Playback", .aif_name = "QUIN_MI2S_RX", .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | - SNDRV_PCM_RATE_16000, + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE, .rate_min = 8000, - .rate_max = 48000, + .rate_max = 192000, }, .capture = { .stream_name = "Quinary MI2S Capture", diff --git a/sound/soc/msm/qdsp6v2/msm-dolby-common.h b/sound/soc/msm/qdsp6v2/msm-dolby-common.h index aab6dc825a23..f14e42e3faa0 100644 --- a/sound/soc/msm/qdsp6v2/msm-dolby-common.h +++ b/sound/soc/msm/qdsp6v2/msm-dolby-common.h @@ -1,5 +1,5 @@ -/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved. * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. @@ -232,6 +232,7 @@ #define TOTAL_LENGTH_DOLBY_PARAM 745 #define DOLBY_VIS_PARAM_HEADER_SIZE 25 +#define DOLBY_PARAM_VCNB_MAX_LENGTH 40 #define DOLBY_INVALID_PORT_ID -1 diff --git a/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c index 379062eee285..48180cf5e337 100644 --- a/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c +++ b/sound/soc/msm/qdsp6v2/msm-ds2-dap-config.c @@ -1554,7 +1554,8 @@ static int msm_ds2_dap_get_param(u32 cmd, void *arg) pr_debug("%s: port_id 0x%x, copp_idx %d, dev_map[i].device_id %x\n", __func__, port_id, copp_idx, dev_map[i].device_id); - params_value = kzalloc(params_length, GFP_KERNEL); + params_value = kzalloc(params_length + param_payload_len, + GFP_KERNEL); if (!params_value) { pr_err("%s: params memory alloc failed\n", __func__); rc = -ENOMEM; @@ -1578,9 +1579,9 @@ static int msm_ds2_dap_get_param(u32 cmd, void *arg) rc = -EINVAL; goto end; } else { - params_length = (ds2_dap_params_length[i] + - DOLBY_PARAM_PAYLOAD_SIZE) * - sizeof(uint32_t); + params_length = + ds2_dap_params_length[i] * sizeof(uint32_t); + rc = adm_get_params(port_id, copp_idx, DOLBY_BUNDLE_MODULE_ID, ds2_dap_params_id[i], @@ -1635,6 +1636,13 @@ static int msm_ds2_dap_param_visualizer_control_get(u32 cmd, void *arg) } length = ds2_dap_params[cache_dev].params_val[DOLBY_PARAM_VCNB_OFFSET]; + + if (length > DOLBY_PARAM_VCNB_MAX_LENGTH || length <= 0) { + ret = 0; + dolby_data->length = 0; + pr_err("%s Incorrect VCNB length", __func__); + } + params_length = (2*length + DOLBY_VIS_PARAM_HEADER_SIZE) * sizeof(uint32_t); diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c index 9b2ef351e4f2..3c75e30fb419 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -29,7 +29,9 @@ #include "msm-pcm-routing-v2.h" #define LOOPBACK_VOL_MAX_STEPS 0x2000 +#define LOOPBACK_SESSION_MAX 4 +static DEFINE_MUTEX(loopback_session_lock); static const DECLARE_TLV_DB_LINEAR(loopback_rx_vol_gain, 0, LOOPBACK_VOL_MAX_STEPS); @@ -51,7 +53,21 @@ struct msm_pcm_loopback { int volume; }; +struct fe_dai_session_map { + char stream_name[32]; + struct msm_pcm_loopback *loopback_priv; +}; + +static struct fe_dai_session_map session_map[LOOPBACK_SESSION_MAX] = { + { {}, NULL}, + { {}, NULL}, + { {}, NULL}, + { {}, NULL}, +}; + static void stop_pcm(struct msm_pcm_loopback *pcm); +static int msm_pcm_loopback_get_session(struct snd_soc_pcm_runtime *rtd, + struct msm_pcm_loopback **pcm); static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event, void *priv_data) @@ -93,6 +109,47 @@ static void msm_pcm_loopback_event_handler(uint32_t opcode, uint32_t token, } } +static int msm_loopback_session_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret = 0, n = 0; + int mute = ucontrol->value.integer.value[0]; + struct msm_pcm_loopback *pcm = NULL; + + if ((mute < 0) || (mute > 1)) { + pr_err(" %s Invalid arguments", __func__); + ret = -EINVAL; + goto done; + } + + pr_debug("%s: mute=%d\n", __func__, mute); + + for (n = 0; n < LOOPBACK_SESSION_MAX; n++) { + if (!strcmp(session_map[n].stream_name, "MultiMedia6")) + pcm = session_map[n].loopback_priv; + } + if (pcm && pcm->audio_client) { + ret = q6asm_set_mute(pcm->audio_client, mute); + if (ret < 0) + pr_err("%s: Send mute command failed rc=%d\n", + __func__, ret); + } +done: + return ret; +} + +static struct snd_kcontrol_new msm_loopback_controls[] = { + SOC_SINGLE_EXT("HFP TX Mute", SND_SOC_NOPM, 0, 1, 0, + NULL, msm_loopback_session_mute_put), +}; + +static int msm_pcm_loopback_probe(struct snd_soc_platform *platform) +{ + snd_soc_add_platform_controls(platform, msm_loopback_controls, + ARRAY_SIZE(msm_loopback_controls)); + + return 0; +} static int pcm_loopback_set_volume(struct msm_pcm_loopback *prtd, int volume) { int rc = -EINVAL; @@ -111,18 +168,76 @@ static int pcm_loopback_set_volume(struct msm_pcm_loopback *prtd, int volume) return rc; } +static int msm_pcm_loopback_get_session(struct snd_soc_pcm_runtime *rtd, + struct msm_pcm_loopback **pcm) +{ + int ret = 0; + int n, index = -1; + + dev_dbg(rtd->platform->dev, "%s: stream %s\n", __func__, + rtd->dai_link->stream_name); + + mutex_lock(&loopback_session_lock); + for (n = 0; n < LOOPBACK_SESSION_MAX; n++) { + if (!strcmp(rtd->dai_link->stream_name, + session_map[n].stream_name)) { + *pcm = session_map[n].loopback_priv; + goto exit; + } + /* + * Store the min index value for allocating a new session. + * Here, if session stream name is not found in the + * existing entries after the loop iteration, then this + * index will be used to allocate the new session. + * This index variable is expected to point to the topmost + * available free session. + */ + if (!(session_map[n].stream_name[0]) && (index < 0)) + index = n; + } + + if (index < 0) { + dev_err(rtd->platform->dev, "%s: Max Sessions allocated\n", + __func__); + ret = -EAGAIN; + goto exit; + } + + session_map[index].loopback_priv = kzalloc( + sizeof(struct msm_pcm_loopback), GFP_KERNEL); + if (!session_map[index].loopback_priv) { + ret = -ENOMEM; + goto exit; + } + + strlcpy(session_map[index].stream_name, + rtd->dai_link->stream_name, + sizeof(session_map[index].stream_name)); + dev_dbg(rtd->platform->dev, "%s: stream %s index %d\n", + __func__, session_map[index].stream_name, index); + + mutex_init(&session_map[index].loopback_priv->lock); + *pcm = session_map[index].loopback_priv; +exit: + mutex_unlock(&loopback_session_lock); + return ret; +} + static int msm_pcm_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct msm_pcm_loopback *pcm; + struct msm_pcm_loopback *pcm = NULL; int ret = 0; uint16_t bits_per_sample = 16; struct msm_pcm_routing_evt event; struct asm_session_mtmx_strtr_param_window_v2_t asm_mtmx_strtr_window; uint32_t param_id; - pcm = dev_get_drvdata(rtd->platform->dev); + ret = msm_pcm_loopback_get_session(rtd, &pcm); + if (ret) + return ret; + mutex_lock(&pcm->lock); pcm->volume = 0x2000; @@ -230,7 +345,8 @@ static int msm_pcm_close(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct msm_pcm_loopback *pcm = runtime->private_data; struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - int ret = 0; + int ret = 0, n; + bool found = false; mutex_lock(&pcm->lock); @@ -247,6 +363,29 @@ static int msm_pcm_close(struct snd_pcm_substream *substream) stop_pcm(pcm); } + if (!pcm->instance) { + mutex_lock(&loopback_session_lock); + for (n = 0; n < LOOPBACK_SESSION_MAX; n++) { + if (!strcmp(rtd->dai_link->stream_name, + session_map[n].stream_name)) { + found = true; + break; + } + } + if (found) { + memset(session_map[n].stream_name, 0, + sizeof(session_map[n].stream_name)); + mutex_unlock(&pcm->lock); + mutex_destroy(&session_map[n].loopback_priv->lock); + session_map[n].loopback_priv = NULL; + kfree(pcm); + dev_dbg(rtd->platform->dev, "%s: stream freed %s\n", + __func__, rtd->dai_link->stream_name); + mutex_unlock(&loopback_session_lock); + return 0; + } + mutex_unlock(&loopback_session_lock); + } mutex_unlock(&pcm->lock); return ret; } @@ -364,37 +503,20 @@ static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd) static struct snd_soc_platform_driver msm_soc_platform = { .ops = &msm_pcm_ops, .pcm_new = msm_asoc_pcm_new, + .probe = msm_pcm_loopback_probe, }; static int msm_pcm_probe(struct platform_device *pdev) { - struct msm_pcm_loopback *pcm; - - dev_dbg(&pdev->dev, "%s: dev name %s\n", __func__, dev_name(&pdev->dev)); - pcm = kzalloc(sizeof(struct msm_pcm_loopback), GFP_KERNEL); - if (!pcm) { - dev_err(&pdev->dev, "%s Failed to allocate memory for pcm\n", - __func__); - return -ENOMEM; - } else { - mutex_init(&pcm->lock); - dev_set_drvdata(&pdev->dev, pcm); - } return snd_soc_register_platform(&pdev->dev, &msm_soc_platform); } static int msm_pcm_remove(struct platform_device *pdev) { - struct msm_pcm_loopback *pcm; - - pcm = dev_get_drvdata(&pdev->dev); - mutex_destroy(&pcm->lock); - kfree(pcm); - snd_soc_unregister_platform(&pdev->dev); return 0; } diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c index cf40f07a9f23..4e3745d4d976 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c @@ -1174,7 +1174,35 @@ static int msm_pcm_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol, static int msm_pcm_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - return 0; + u64 fe_id = kcontrol->private_value; + int ret = 0; + int app_type; + int acdb_dev_id; + int sample_rate; + + pr_debug("%s: fe_id- %llu\n", __func__, fe_id); + if (fe_id >= MSM_FRONTEND_DAI_MAX) { + pr_err("%s Received out of bounds fe_id %llu\n", + __func__, fe_id); + ret = -EINVAL; + goto done; + } + + ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, &app_type, + &acdb_dev_id, &sample_rate); + if (ret < 0) { + pr_err("%s: msm_pcm_routing_get_stream_app_type_cfg failed returned %d\n", + __func__, ret); + goto done; + } + + ucontrol->value.integer.value[0] = app_type; + ucontrol->value.integer.value[1] = acdb_dev_id; + ucontrol->value.integer.value[2] = sample_rate; + pr_debug("%s: fedai_id %llu, app_type %d, acdb_dev_id %d, sample_rate %d\n", + __func__, fe_id, app_type, acdb_dev_id, sample_rate); +done: + return ret; } static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd) diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h index 06a7b2ab88d5..72418ea56bb9 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2008 Google, Inc. * Copyright (C) 2008 HTC Corporation - * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -63,7 +63,7 @@ struct msm_audio_in_frame_info { #define PLAYBACK_MIN_PERIOD_SIZE 128 #define CAPTURE_MIN_NUM_PERIODS 2 #define CAPTURE_MAX_NUM_PERIODS 8 -#define CAPTURE_MAX_PERIOD_SIZE 16384 +#define CAPTURE_MAX_PERIOD_SIZE 61440 #define CAPTURE_MIN_PERIOD_SIZE 320 struct msm_audio { diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 05b29d88e1e5..8ca9bb7b2ad8 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -551,8 +551,8 @@ void msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int app_type, pr_debug("%s: fedai_id %d, app_type %d, sample_rate %d\n", __func__, fedai_id, app_type, sample_rate); if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) { - /* bad ID assigned in machine driver */ - pr_err("%s: bad MM ID %d\n", __func__, fedai_id); + pr_err("%s: Invalid machine driver ID %d\n", + __func__, fedai_id); return; } fe_dai_app_type_cfg[fedai_id].app_type = app_type; @@ -560,6 +560,51 @@ void msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int app_type, fe_dai_app_type_cfg[fedai_id].sample_rate = sample_rate; } +/** + * msm_pcm_routing_get_stream_app_type_cfg + * + * Receives fedai_id and populates app_type, acdb_dev_id, & + * sample rate. Returns 0 on success. On failure returns + * -EINVAL and does not alter passed values. + * + * fedai_id - Passed value, front end ID for which app type config is wanted + * app_type - Returned value, app type used by app type config + * acdb_dev_id - Returned value, ACDB device ID used by app type config + * sample_rate - Returned value, sample rate used by app type config + */ +int msm_pcm_routing_get_stream_app_type_cfg(int fedai_id, int *app_type, + int *acdb_dev_id, int *sample_rate) +{ + int ret = 0; + + if (app_type == NULL) { + pr_err("%s: NULL pointer sent for app_type\n", __func__); + ret = -EINVAL; + goto done; + } else if (acdb_dev_id == NULL) { + pr_err("%s: NULL pointer sent for acdb_dev_id\n", __func__); + ret = -EINVAL; + goto done; + } else if (sample_rate == NULL) { + pr_err("%s: NULL pointer sent for sample rate\n", __func__); + ret = -EINVAL; + goto done; + } else if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) { + pr_err("%s: Invalid FE ID %d\n", + __func__, fedai_id); + ret = -EINVAL; + goto done; + } + *app_type = fe_dai_app_type_cfg[fedai_id].app_type; + *acdb_dev_id = fe_dai_app_type_cfg[fedai_id].acdb_dev_id; + *sample_rate = fe_dai_app_type_cfg[fedai_id].sample_rate; + + pr_debug("%s: fedai_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n", + __func__, fedai_id, *app_type, *acdb_dev_id, *sample_rate); +done: + return ret; +} +EXPORT_SYMBOL(msm_pcm_routing_get_stream_app_type_cfg); static struct cal_block_data *msm_routing_find_topology_by_path(int path) { @@ -5339,6 +5384,12 @@ static const struct snd_kcontrol_new sbus_6_rx_port_mixer_controls[] = { SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), + SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX, + MSM_BACKEND_DAI_SLIMBUS_7_TX, 1, 0, msm_routing_get_port_mixer, + msm_routing_put_port_mixer), + SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX, + MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer, + msm_routing_put_port_mixer), SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), @@ -9286,6 +9337,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"SLIMBUS_6_RX Port Mixer", "INTERNAL_FM_TX", "INT_FM_TX"}, {"SLIMBUS_6_RX Port Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"}, {"SLIMBUS_6_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"}, + {"SLIMBUS_6_RX Port Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"}, + {"SLIMBUS_6_RX Port Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"}, {"SLIMBUS_6_RX Port Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"}, {"SLIMBUS_6_RX Port Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"}, {"SLIMBUS_6_RX Port Mixer", "MI2S_TX", "MI2S_TX"}, @@ -9920,7 +9973,7 @@ static struct platform_driver msm_routing_pcm_driver = { int msm_routing_check_backend_enabled(int fedai_id) { int i; - if (fedai_id >= MSM_FRONTEND_DAI_MM_MAX_ID) { + if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) { /* bad ID assigned in machine driver */ pr_err("%s: bad MM ID\n", __func__); return 0; diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h index 6d1109f0bc6d..992d0d48e999 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h @@ -414,4 +414,6 @@ void msm_pcm_routing_release_lock(void); void msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int app_type, int acdb_dev_id, int sample_rate); +int msm_pcm_routing_get_stream_app_type_cfg(int fedai_id, int *app_type, + int *acdb_dev_id, int *sample_rate); #endif /*_MSM_PCM_H*/ diff --git a/sound/soc/msm/qdsp6v2/q6core.c b/sound/soc/msm/qdsp6v2/q6core.c index cc26af528aba..cc7616f1d897 100644 --- a/sound/soc/msm/qdsp6v2/q6core.c +++ b/sound/soc/msm/qdsp6v2/q6core.c @@ -357,14 +357,14 @@ int core_dts_eagle_set(int size, char *data) } size_aligned4byte = (size+3) & 0xFFFFFFFC; + mutex_lock(&(q6core_lcl.cmd_lock)); ocm_core_open(); if (q6core_lcl.core_handle_q) { payload = kzalloc(sizeof(struct adsp_dts_eagle) + size_aligned4byte, GFP_KERNEL); if (!payload) { - pr_err("DTS_EAGLE_CORE - %s: out of memory (aligned size %i).\n", - __func__, size_aligned4byte); - return -ENOMEM; + rc = -ENOMEM; + goto exit; } payload->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT, APR_HDR_LEN(APR_HDR_SIZE), @@ -387,6 +387,9 @@ int core_dts_eagle_set(int size, char *data) } kfree(payload); } + +exit: + mutex_unlock(&(q6core_lcl.cmd_lock)); return rc; } @@ -401,6 +404,7 @@ int core_dts_eagle_get(int id, int size, char *data) __func__, size, data); return -EINVAL; } + mutex_lock(&(q6core_lcl.cmd_lock)); ocm_core_open(); if (q6core_lcl.core_handle_q) { ah.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT, @@ -415,9 +419,8 @@ int core_dts_eagle_get(int id, int size, char *data) generic_get_data = kzalloc(sizeof(struct generic_get_data_) + size, GFP_KERNEL); if (!generic_get_data) { - pr_err("DTS_EAGLE_CORE - %s: error allocating memory of size %i\n", - __func__, size); - return -ENOMEM; + rc = -ENOMEM; + goto exit; } rc = apr_send_pkt(q6core_lcl.core_handle_q, @@ -425,7 +428,7 @@ int core_dts_eagle_get(int id, int size, char *data) if (rc < 0) { pr_err("DTS_EAGLE_CORE - %s: failed op[0x%x]rc[%d]\n", __func__, ah.opcode, rc); - goto fail_cmd_2; + goto exit; } rc = wait_event_timeout(q6core_lcl.bus_bw_req_wait, @@ -435,7 +438,7 @@ int core_dts_eagle_get(int id, int size, char *data) pr_err("DTS_EAGLE_CORE - %s: EAGLE get params timed out\n", __func__); rc = -EINVAL; - goto fail_cmd_2; + goto exit; } if (generic_get_data->valid) { rc = 0; @@ -447,9 +450,10 @@ int core_dts_eagle_get(int id, int size, char *data) } } -fail_cmd_2: +exit: kfree(generic_get_data); generic_get_data = NULL; + mutex_unlock(&(q6core_lcl.cmd_lock)); return rc; } @@ -496,6 +500,7 @@ bool q6core_is_adsp_ready(void) hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE, 0); hdr.opcode = AVCS_CMD_ADSP_EVENT_GET_STATE; + mutex_lock(&(q6core_lcl.cmd_lock)); ocm_core_open(); q6core_lcl.bus_bw_resp_received = 0; rc = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)&hdr); @@ -515,6 +520,7 @@ bool q6core_is_adsp_ready(void) } bail: pr_debug("%s: leave, rc %d, adsp ready %d\n", __func__, rc, ret); + mutex_unlock(&(q6core_lcl.cmd_lock)); return ret; } @@ -692,6 +698,11 @@ static int q6core_send_custom_topologies(void) struct cal_block_data *cal_block = NULL; struct avcs_cmd_register_topologies reg_top; + if (!q6core_is_adsp_ready()) { + pr_err("%s: ADSP is not ready!\n", __func__); + return -ENODEV; + } + memset(®_top, 0, sizeof(reg_top)); mutex_lock(&q6core_lcl.cal_data[CUST_TOP_CAL]->lock); mutex_lock(&q6core_lcl.cmd_lock); @@ -708,12 +719,6 @@ static int q6core_send_custom_topologies(void) goto unlock; } - if (!q6core_is_adsp_ready()) { - pr_err("%s: ADSP is not ready!\n", __func__); - ret = -ENODEV; - goto unlock; - } - q6core_dereg_all_custom_topologies(); ret = q6core_map_memory_regions(&cal_block->cal_data.paddr, 0, diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index ea4ab374a223..7dbf899b2af2 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -480,10 +480,11 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, unsigned int cdcon_mask = 1 << i2s_regs->cdclkcon_off; unsigned int rsrc_mask = 1 << i2s_regs->rclksrc_off; u32 mod, mask, val = 0; + unsigned long flags; - spin_lock(i2s->lock); + spin_lock_irqsave(i2s->lock, flags); mod = readl(i2s->addr + I2SMOD); - spin_unlock(i2s->lock); + spin_unlock_irqrestore(i2s->lock, flags); switch (clk_id) { case SAMSUNG_I2S_OPCLK: @@ -574,11 +575,11 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, return -EINVAL; } - spin_lock(i2s->lock); + spin_lock_irqsave(i2s->lock, flags); mod = readl(i2s->addr + I2SMOD); mod = (mod & ~mask) | val; writel(mod, i2s->addr + I2SMOD); - spin_unlock(i2s->lock); + spin_unlock_irqrestore(i2s->lock, flags); return 0; } @@ -589,6 +590,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, struct i2s_dai *i2s = to_info(dai); int lrp_shift, sdf_shift, sdf_mask, lrp_rlow, mod_slave; u32 mod, tmp = 0; + unsigned long flags; lrp_shift = i2s->variant_regs->lrp_off; sdf_shift = i2s->variant_regs->sdf_off; @@ -648,7 +650,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, return -EINVAL; } - spin_lock(i2s->lock); + spin_lock_irqsave(i2s->lock, flags); mod = readl(i2s->addr + I2SMOD); /* * Don't change the I2S mode if any controller is active on this @@ -656,7 +658,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, */ if (any_active(i2s) && ((mod & (sdf_mask | lrp_rlow | mod_slave)) != tmp)) { - spin_unlock(i2s->lock); + spin_unlock_irqrestore(i2s->lock, flags); dev_err(&i2s->pdev->dev, "%s:%d Other DAI busy\n", __func__, __LINE__); return -EAGAIN; @@ -665,7 +667,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, mod &= ~(sdf_mask | lrp_rlow | mod_slave); mod |= tmp; writel(mod, i2s->addr + I2SMOD); - spin_unlock(i2s->lock); + spin_unlock_irqrestore(i2s->lock, flags); return 0; } @@ -675,6 +677,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, { struct i2s_dai *i2s = to_info(dai); u32 mod, mask = 0, val = 0; + unsigned long flags; if (!is_secondary(i2s)) mask |= (MOD_DC2_EN | MOD_DC1_EN); @@ -743,11 +746,11 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - spin_lock(i2s->lock); + spin_lock_irqsave(i2s->lock, flags); mod = readl(i2s->addr + I2SMOD); mod = (mod & ~mask) | val; writel(mod, i2s->addr + I2SMOD); - spin_unlock(i2s->lock); + spin_unlock_irqrestore(i2s->lock, flags); samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c9e54acb06ec..cac2d4975a15 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -876,6 +876,12 @@ struct snd_soc_component *soc_find_component( { struct snd_soc_component *component; + if (!of_node && !name) { + pr_err("%s: Either of_node or name must be valid\n", + __func__); + return NULL; + } + lockdep_assert_held(&client_mutex); list_for_each_entry(component, &component_list, list) { diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index c16df0a70b11..94806ad6437b 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3584,7 +3584,7 @@ static int snd_soc_dapm_dai_link_get(struct snd_kcontrol *kcontrol, { struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = w->params_select; + ucontrol->value.enumerated.item[0] = w->params_select; return 0; } @@ -3598,13 +3598,13 @@ static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol, if (w->power) return -EBUSY; - if (ucontrol->value.integer.value[0] == w->params_select) + if (ucontrol->value.enumerated.item[0] == w->params_select) return 0; - if (ucontrol->value.integer.value[0] >= w->num_params) + if (ucontrol->value.enumerated.item[0] >= w->num_params) return -EINVAL; - w->params_select = ucontrol->value.integer.value[0]; + w->params_select = ucontrol->value.enumerated.item[0]; return 0; } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index b4ffe3904dcc..4ef20ba02cb4 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -698,6 +698,20 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) snd_soc_dai_digital_mute(cpu_dai, 1, substream->stream); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (snd_soc_runtime_ignore_pmdown_time(rtd)) { + /* powered down playback stream now */ + snd_soc_dapm_stream_event(rtd, + SNDRV_PCM_STREAM_PLAYBACK, + SND_SOC_DAPM_STREAM_STOP); + } else { + /* start delayed pop wq here for playback streams */ + rtd->pop_wait = 1; + queue_delayed_work(system_power_efficient_wq, + &rtd->delayed_work, + msecs_to_jiffies(rtd->pmdown_time)); + } + } if (cpu_dai->driver->ops->shutdown) cpu_dai->driver->ops->shutdown(substream, cpu_dai); @@ -713,20 +727,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) if (platform->driver->ops && platform->driver->ops->close) platform->driver->ops->close(substream); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - if (snd_soc_runtime_ignore_pmdown_time(rtd)) { - /* powered down playback stream now */ - snd_soc_dapm_stream_event(rtd, - SNDRV_PCM_STREAM_PLAYBACK, - SND_SOC_DAPM_STREAM_STOP); - } else { - /* start delayed pop wq here for playback streams */ - rtd->pop_wait = 1; - queue_delayed_work(system_power_efficient_wq, - &rtd->delayed_work, - msecs_to_jiffies(rtd->pmdown_time)); - } - } else { + if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) { /* capture streams can be powered down now */ snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE, SND_SOC_DAPM_STREAM_STOP); diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index a452ad7cec40..f32cfa40c192 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -162,5 +162,13 @@ config SND_BCD2000 source "sound/usb/line6/Kconfig" +config SND_USB_AUDIO_QMI + tristate "USB Audio QMI Service driver" + depends on MSM_QMI_INTERFACE + help + Starts USB Audio QMI server to communicate with remote entity + to perform operations like enable or disable particular audio + stream on a connected USB device. + endif # SND_USB diff --git a/sound/usb/Makefile b/sound/usb/Makefile index 2d2d122b069f..d2ac0386d3da 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -26,3 +26,4 @@ obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/ bcd2000/ obj-$(CONFIG_SND_USB_LINE6) += line6/ +obj-$(CONFIG_SND_USB_AUDIO_QMI) += usb_audio_qmi_v01.o usb_audio_qmi_svc.o diff --git a/sound/usb/card.c b/sound/usb/card.c index 7e1001c1cf1e..e94f4d2f2620 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -110,6 +110,71 @@ static DEFINE_MUTEX(register_mutex); static struct snd_usb_audio *usb_chip[SNDRV_CARDS]; static struct usb_driver usb_audio_driver; +struct snd_usb_substream *find_snd_usb_substream(unsigned int card_num, + unsigned int pcm_idx, unsigned int direction, struct snd_usb_audio + **uchip, void (*disconnect_cb)(struct snd_usb_audio *chip)) +{ + int idx; + struct snd_usb_stream *as; + struct snd_usb_substream *subs = NULL; + struct snd_usb_audio *chip = NULL; + + mutex_lock(®ister_mutex); + /* + * legacy audio snd card number assignment is dynamic. Hence + * search using chip->card->number + */ + for (idx = 0; idx < SNDRV_CARDS; idx++) { + if (!usb_chip[idx]) + continue; + if (usb_chip[idx]->card->number == card_num) { + chip = usb_chip[idx]; + break; + } + } + + if (!chip || atomic_read(&chip->shutdown)) { + pr_debug("%s: instance of usb crad # %d does not exist\n", + __func__, card_num); + goto err; + } + + if (pcm_idx >= chip->pcm_devs) { + pr_err("%s: invalid pcm dev number %u > %d\n", __func__, + pcm_idx, chip->pcm_devs); + goto err; + } + + if (direction > SNDRV_PCM_STREAM_CAPTURE) { + pr_err("%s: invalid direction %u\n", __func__, direction); + goto err; + } + + list_for_each_entry(as, &chip->pcm_list, list) { + if (as->pcm_index == pcm_idx) { + subs = &as->substream[direction]; + if (subs->interface < 0 && !subs->data_endpoint && + !subs->sync_endpoint) { + pr_debug("%s: stream disconnected, bail out\n", + __func__); + subs = NULL; + goto err; + } + goto done; + } + } + +done: + chip->card_num = card_num; + chip->disconnect_cb = disconnect_cb; +err: + *uchip = chip; + if (!subs) + pr_debug("%s: substream instance not found\n", __func__); + mutex_unlock(®ister_mutex); + return subs; +} + /* * disconnect streams * called from usb_audio_disconnect() @@ -322,6 +387,7 @@ static int snd_usb_audio_free(struct snd_usb_audio *chip) list_for_each_entry_safe(ep, n, &chip->ep_list, list) snd_usb_endpoint_free(ep); + mutex_destroy(&chip->dev_lock); mutex_destroy(&chip->mutex); kfree(chip); return 0; @@ -377,6 +443,7 @@ static int snd_usb_audio_create(struct usb_interface *intf, } mutex_init(&chip->mutex); + mutex_init(&chip->dev_lock); init_waitqueue_head(&chip->shutdown_wait); chip->index = idx; chip->dev = dev; @@ -639,6 +706,8 @@ static void usb_audio_disconnect(struct usb_interface *intf) if (chip->num_interfaces <= 0) { usb_chip[chip->index] = NULL; mutex_unlock(®ister_mutex); + if (chip->disconnect_cb) + chip->disconnect_cb(chip); snd_card_free_when_closed(card); } else { mutex_unlock(®ister_mutex); diff --git a/sound/usb/card.h b/sound/usb/card.h index 71778ca4b26a..7421ee53c29f 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -167,4 +167,8 @@ struct snd_usb_stream { struct list_head list; }; +struct snd_usb_substream *find_snd_usb_substream(unsigned int card_num, + unsigned int pcm_idx, unsigned int direction, struct snd_usb_audio + **uchip, void (*disconnect_cb)(struct snd_usb_audio *chip)); + #endif /* __USBAUDIO_CARD_H */ diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 9245f52d43bd..9a9b789a56ef 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -552,6 +552,64 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) return 0; } +int snd_usb_enable_audio_stream(struct snd_usb_substream *subs, + bool enable) +{ + struct audioformat *fmt; + struct usb_host_interface *alts; + struct usb_interface *iface; + int ret; + + if (!enable) { + if (subs->interface >= 0) { + usb_set_interface(subs->dev, subs->interface, 0); + subs->altset_idx = 0; + subs->interface = -1; + subs->cur_audiofmt = NULL; + } + + snd_usb_autosuspend(subs->stream->chip); + return 0; + } + + snd_usb_autoresume(subs->stream->chip); + fmt = find_format(subs); + if (!fmt) { + dev_dbg(&subs->dev->dev, + "cannot set format: format = %#x, rate = %d, channels = %d\n", + subs->pcm_format, subs->cur_rate, subs->channels); + return -EINVAL; + } + + subs->altset_idx = 0; + subs->interface = -1; + if (atomic_read(&subs->stream->chip->shutdown)) { + ret = -ENODEV; + } else { + ret = set_format(subs, fmt); + if (ret < 0) + return ret; + + iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface); + alts = &iface->altsetting[subs->cur_audiofmt->altset_idx]; + ret = snd_usb_init_sample_rate(subs->stream->chip, + subs->cur_audiofmt->iface, + alts, + subs->cur_audiofmt, + subs->cur_rate); + if (ret < 0) { + dev_err(&subs->dev->dev, "failed to set rate %d\n", + subs->cur_rate); + return ret; + } + } + + subs->interface = fmt->iface; + subs->altset_idx = fmt->altset_idx; + + return 0; +} + /* * Return the score of matching two audioformats. * Veto the audioformat if: diff --git a/sound/usb/pcm.h b/sound/usb/pcm.h index df7a003682ad..d581f94b3fbf 100644 --- a/sound/usb/pcm.h +++ b/sound/usb/pcm.h @@ -9,6 +9,7 @@ void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream); int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, struct usb_host_interface *alts, struct audioformat *fmt); - +int snd_usb_enable_audio_stream(struct snd_usb_substream *subs, + bool enable); #endif /* __USBAUDIO_PCM_H */ diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 4f6ce1cac8e2..c458d60d5030 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1124,6 +1124,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) case USB_ID(0x045E, 0x076F): /* MS Lifecam HD-6000 */ case USB_ID(0x045E, 0x0772): /* MS Lifecam Studio */ case USB_ID(0x045E, 0x0779): /* MS Lifecam HD-3000 */ + case USB_ID(0x047F, 0xAA05): /* Plantronics DA45 */ case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */ case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */ case USB_ID(0x21B4, 0x0081): /* AudioQuest DragonFly */ diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 8ee14f2365e7..81172a395e55 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -69,9 +69,14 @@ static void snd_usb_audio_stream_free(struct snd_usb_stream *stream) static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) { struct snd_usb_stream *stream = pcm->private_data; + struct snd_usb_audio *chip; + if (stream) { + mutex_lock(&stream->chip->dev_lock); + chip = stream->chip; stream->pcm = NULL; snd_usb_audio_stream_free(stream); + mutex_unlock(&chip->dev_lock); } } diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c new file mode 100644 index 000000000000..9d2b75876bfe --- /dev/null +++ b/sound/usb/usb_audio_qmi_svc.c @@ -0,0 +1,1122 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/debugfs.h> +#include <linux/usb/audio.h> +#include <linux/uaccess.h> +#include <sound/pcm.h> +#include <sound/core.h> +#include <sound/asound.h> +#include <linux/usb.h> +#include <linux/qmi_encdec.h> +#include <soc/qcom/msm_qmi_interface.h> +#include <linux/iommu.h> +#include <linux/qcom_iommu.h> +#include <linux/platform_device.h> + +#include "usbaudio.h" +#include "card.h" +#include "helper.h" +#include "pcm.h" +#include "usb_audio_qmi_v01.h" + +#define SND_PCM_CARD_NUM_MASK 0xffff0000 +#define SND_PCM_DEV_NUM_MASK 0xff00 +#define SND_PCM_STREAM_DIRECTION 0xff + +#define PREPEND_SID_TO_IOVA(iova, sid) (u64)(((u64)(iova)) | \ + (((u64)sid) << 32)) + +/* event ring iova base address */ +#define IOVA_BASE 0x1000 + +#define IOVA_DCBA_BASE 0x2000 +#define IOVA_XFER_RING_BASE (IOVA_DCBA_BASE + PAGE_SIZE * (SNDRV_CARDS + 1)) +#define IOVA_XFER_BUF_BASE (IOVA_XFER_RING_BASE + PAGE_SIZE * SNDRV_CARDS * 32) +#define IOVA_XFER_RING_MAX (IOVA_XFER_BUF_BASE - PAGE_SIZE) +#define IOVA_XFER_BUF_MAX (0xfffff000 - PAGE_SIZE) + +#define MAX_XFER_BUFF_LEN (2 * PAGE_SIZE) + +struct iova_info { + struct list_head list; + unsigned long start_iova; + size_t size; + bool in_use; +}; + +struct intf_info { + unsigned long data_xfer_ring_va; + size_t data_xfer_ring_size; + unsigned long sync_xfer_ring_va; + size_t sync_xfer_ring_size; + unsigned long xfer_buf_va; + size_t xfer_buf_size; + phys_addr_t xfer_buf_pa; + u8 *xfer_buf; + bool in_use; +}; + +struct uaudio_dev { + struct usb_device *udev; + unsigned int card_num; + atomic_t in_use; + struct kref kref; + unsigned long dcba_iova; + size_t dcba_size; + wait_queue_head_t disconnect_wq; + + /* interface specific */ + int num_intf; + struct intf_info *info; +}; + +static struct uaudio_dev uadev[SNDRV_CARDS]; + +struct uaudio_qmi_dev { + struct device *dev; + u32 sid; + u32 intr_num; + struct iommu_domain *domain; + + /* list to keep track of available iova */ + struct list_head dcba_list; + size_t dcba_iova_size; + unsigned long curr_dcba_iova; + struct list_head xfer_ring_list; + size_t xfer_ring_iova_size; + unsigned long curr_xfer_ring_iova; + struct list_head xfer_buf_list; + size_t xfer_buf_iova_size; + unsigned long curr_xfer_buf_iova; + /* bit fields representing pcm card enabled */ + unsigned long card_slot; + /* cache event ring phys addr */ + u64 er_phys_addr; +}; + +static struct uaudio_qmi_dev *uaudio_qdev; + +struct uaudio_qmi_svc { + struct qmi_handle *uaudio_svc_hdl; + void *curr_conn; + struct work_struct recv_msg_work; + struct workqueue_struct *uaudio_wq; + ktime_t t_request_recvd; + ktime_t t_resp_sent; +}; + +static struct uaudio_qmi_svc *uaudio_svc; + +static struct msg_desc uaudio_stream_req_desc = { + .max_msg_len = QMI_UAUDIO_STREAM_REQ_MSG_V01_MAX_MSG_LEN, + .msg_id = QMI_UAUDIO_STREAM_REQ_V01, + .ei_array = qmi_uaudio_stream_req_msg_v01_ei, +}; + +static struct msg_desc uaudio_stream_resp_desc = { + .max_msg_len = QMI_UAUDIO_STREAM_RESP_MSG_V01_MAX_MSG_LEN, + .msg_id = QMI_UAUDIO_STREAM_RESP_V01, + .ei_array = qmi_uaudio_stream_resp_msg_v01_ei, +}; + +enum mem_type { + MEM_EVENT_RING, + MEM_DCBA, + MEM_XFER_RING, + MEM_XFER_BUF, +}; + +static unsigned long uaudio_get_iova(unsigned long *curr_iova, + size_t *curr_iova_size, struct list_head *head, size_t size) +{ + struct iova_info *info, *new_info = NULL; + struct list_head *curr_head; + unsigned long va = 0; + size_t tmp_size = size; + bool found = false; + + if (size % PAGE_SIZE) { + pr_err("%s: size %zu is not page size multiple\n", __func__, + size); + goto done; + } + + if (size > *curr_iova_size) { + pr_err("%s: size %zu > curr size %zu\n", __func__, size, + *curr_iova_size); + goto done; + } + if (*curr_iova_size == 0) { + pr_err("%s: iova mapping is full\n", __func__); + goto done; + } + + list_for_each_entry(info, head, list) { + /* exact size iova_info */ + if (!info->in_use && info->size == size) { + info->in_use = true; + va = info->start_iova; + *curr_iova_size -= size; + found = true; + pr_debug("%s: exact size :%zu found\n", __func__, size); + goto done; + } else if (!info->in_use && tmp_size >= info->size) { + if (!new_info) + new_info = info; + pr_debug("%s: partial size: %zu found\n", __func__, + info->size); + tmp_size -= info->size; + if (tmp_size) + continue; + + va = new_info->start_iova; + for (curr_head = &new_info->list; curr_head != + &info->list; curr_head = curr_head->next) { + new_info = list_entry(curr_head, struct + iova_info, list); + new_info->in_use = true; + } + info->in_use = true; + *curr_iova_size -= size; + found = true; + goto done; + } else { + /* iova region in use */ + new_info = NULL; + tmp_size = size; + } + } + + info = kzalloc(sizeof(struct iova_info), GFP_KERNEL); + if (!info) { + va = 0; + goto done; + } + + va = info->start_iova = *curr_iova; + info->size = size; + info->in_use = true; + *curr_iova += size; + *curr_iova_size -= size; + found = true; + list_add_tail(&info->list, head); + +done: + if (!found) + pr_err("%s: unable to find %zu size iova\n", __func__, size); + else + pr_debug("%s: va:%lu curr_iova:%lu curr_iova_size:%zu\n", + __func__, va, *curr_iova, *curr_iova_size); + + return va; +} + +static unsigned long uaudio_iommu_map(enum mem_type mtype, phys_addr_t pa, + size_t size) +{ + unsigned long va = 0; + bool map = true; + int ret; + + switch (mtype) { + case MEM_EVENT_RING: + va = IOVA_BASE; + /* er already mapped */ + if (uaudio_qdev->er_phys_addr == pa) + map = false; + break; + case MEM_DCBA: + va = uaudio_get_iova(&uaudio_qdev->curr_dcba_iova, + &uaudio_qdev->dcba_iova_size, &uaudio_qdev->dcba_list, size); + break; + case MEM_XFER_RING: + va = uaudio_get_iova(&uaudio_qdev->curr_xfer_ring_iova, + &uaudio_qdev->xfer_ring_iova_size, &uaudio_qdev->xfer_ring_list, + size); + break; + case MEM_XFER_BUF: + va = uaudio_get_iova(&uaudio_qdev->curr_xfer_buf_iova, + &uaudio_qdev->xfer_buf_iova_size, &uaudio_qdev->xfer_buf_list, + size); + break; + default: + pr_err("%s: unknown mem type %d\n", __func__, mtype); + } + + if (!va) + map = false; + + if (!map) + goto done; + + pr_debug("%s: map pa %pa to iova %lu for memtype %d\n", __func__, &pa, + va, mtype); + ret = iommu_map(uaudio_qdev->domain, va, pa, size, + IOMMU_READ | IOMMU_WRITE | IOMMU_DEVICE); + if (ret) + pr_err("%s:failed to map pa:%pa iova:%lu memtype:%d ret:%d\n", + __func__, &pa, va, mtype, ret); +done: + return va; +} + +static void uaudio_put_iova(unsigned long va, size_t size, struct list_head + *head, size_t *curr_iova_size) +{ + struct iova_info *info; + size_t tmp_size = size; + bool found = false; + + list_for_each_entry(info, head, list) { + if (info->start_iova == va) { + if (!info->in_use) { + pr_err("%s: va %lu is not in use\n", __func__, + va); + return; + } + found = true; + info->in_use = false; + if (info->size == size) + goto done; + } + + if (found && tmp_size >= info->size) { + info->in_use = false; + tmp_size -= info->size; + if (!tmp_size) + goto done; + } + } + + if (!found) { + pr_err("%s: unable to find the va %lu\n", __func__, va); + return; + } +done: + *curr_iova_size += size; + pr_debug("%s: curr_iova_size %zu\n", __func__, *curr_iova_size); +} + +static void uaudio_iommu_unmap(enum mem_type mtype, unsigned long va, + size_t size) +{ + size_t umap_size; + bool unmap = true; + + if (!va || !size) + return; + + switch (mtype) { + case MEM_EVENT_RING: + if (uaudio_qdev->er_phys_addr) + uaudio_qdev->er_phys_addr = 0; + else + unmap = false; + break; + case MEM_DCBA: + uaudio_put_iova(va, size, &uaudio_qdev->dcba_list, + &uaudio_qdev->dcba_iova_size); + break; + case MEM_XFER_RING: + uaudio_put_iova(va, size, &uaudio_qdev->xfer_ring_list, + &uaudio_qdev->xfer_ring_iova_size); + break; + case MEM_XFER_BUF: + uaudio_put_iova(va, size, &uaudio_qdev->xfer_buf_list, + &uaudio_qdev->xfer_buf_iova_size); + break; + default: + pr_err("%s: unknown mem type %d\n", __func__, mtype); + unmap = false; + } + + if (!unmap) + return; + + pr_debug("%s: unmap iova %lu for memtype %d\n", __func__, va, mtype); + + umap_size = iommu_unmap(uaudio_qdev->domain, va, size); + if (umap_size != size) + pr_err("%s: unmapped size %zu for iova %lu\n", __func__, + umap_size, va); +} + +static int prepare_qmi_response(struct snd_usb_substream *subs, + struct qmi_uaudio_stream_resp_msg_v01 *resp, u32 xfer_buf_len, + int card_num) +{ + int ret = -ENODEV; + struct usb_interface *iface; + struct usb_host_interface *alts; + struct usb_interface_descriptor *altsd; + struct usb_host_endpoint *ep; + struct uac_format_type_i_continuous_descriptor *fmt; + struct uac_format_type_i_discrete_descriptor *fmt_v1; + struct uac_format_type_i_ext_descriptor *fmt_v2; + struct uac1_as_header_descriptor *as; + struct uac1_ac_header_descriptor *ac; + int protocol; + u8 *xfer_buf; + u32 len, mult, remainder; + unsigned long va, tr_data_va = 0, tr_sync_va = 0, dcba_va = 0, + xfer_buf_va = 0; + phys_addr_t xhci_pa, xfer_buf_pa; + + iface = usb_ifnum_to_if(subs->dev, subs->interface); + if (!iface) { + pr_err("%s: interface # %d does not exist\n", __func__, + subs->interface); + goto err; + } + + alts = &iface->altsetting[subs->altset_idx]; + altsd = get_iface_desc(alts); + protocol = altsd->bInterfaceProtocol; + + /* get format type */ + fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, + UAC_FORMAT_TYPE); + if (!fmt) { + pr_err("%s: %u:%d : no UAC_FORMAT_TYPE desc\n", __func__, + subs->interface, subs->altset_idx); + goto err; + } + + if (protocol == UAC_VERSION_1) { + as = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, + UAC_AS_GENERAL); + if (!as) { + pr_err("%s: %u:%d : no UAC_AS_GENERAL desc\n", __func__, + subs->interface, subs->altset_idx); + goto err; + } + resp->bDelay = as->bDelay; + fmt_v1 = (struct uac_format_type_i_discrete_descriptor *)fmt; + resp->bSubslotSize = fmt_v1->bSubframeSize; + } else if (protocol == UAC_VERSION_2) { + fmt_v2 = (struct uac_format_type_i_ext_descriptor *)fmt; + resp->bSubslotSize = fmt_v2->bSubslotSize; + } else { + pr_err("%s: unknown protocol version %x\n", __func__, protocol); + goto err; + } + + ac = snd_usb_find_csint_desc(alts->extra, + alts->extralen, + NULL, UAC_HEADER); + if (!ac) { + pr_err("%s: %u:%d : no UAC_HEADER desc\n", __func__, + subs->interface, subs->altset_idx); + goto err; + } + resp->bcdADC = ac->bcdADC; + + resp->slot_id = subs->dev->slot_id; + + memcpy(&resp->std_as_opr_intf_desc, &alts->desc, sizeof(alts->desc)); + + ep = usb_pipe_endpoint(subs->dev, subs->data_endpoint->pipe); + if (!ep) { + pr_err("%s: data ep # %d context is null\n", __func__, + subs->data_endpoint->ep_num); + goto err; + } + memcpy(&resp->std_as_data_ep_desc, &ep->desc, sizeof(ep->desc)); + + xhci_pa = usb_get_xfer_ring_dma_addr(subs->dev, ep); + if (!xhci_pa) { + pr_err("%s:failed to get data ep ring dma address\n", __func__); + goto err; + } + + resp->xhci_mem_info.tr_data.pa = xhci_pa; + + if (subs->sync_endpoint) { + ep = usb_pipe_endpoint(subs->dev, subs->sync_endpoint->pipe); + if (!ep) { + pr_err("%s: sync ep # %d context is null\n", __func__, + subs->sync_endpoint->ep_num); + goto err; + } + memcpy(&resp->std_as_sync_ep_desc, &ep->desc, sizeof(ep->desc)); + xhci_pa = usb_get_xfer_ring_dma_addr(subs->dev, ep); + if (!xhci_pa) { + pr_err("%s:failed to get sync ep ring dma address\n", + __func__); + goto err; + } + resp->xhci_mem_info.tr_sync.pa = xhci_pa; + } + + resp->interrupter_num = uaudio_qdev->intr_num; + + /* map xhci data structures PA memory to iova */ + + /* event ring */ + ret = usb_sec_event_ring_setup(subs->dev, resp->interrupter_num); + if (ret) { + pr_err("%s: failed to setup sec event ring ret %d\n", __func__, + ret); + goto err; + } + xhci_pa = usb_get_sec_event_ring_dma_addr(subs->dev, + resp->interrupter_num); + if (!xhci_pa) { + pr_err("%s: failed to get sec event ring dma address\n", + __func__); + goto err; + } + + va = uaudio_iommu_map(MEM_EVENT_RING, xhci_pa, PAGE_SIZE); + if (!va) + goto err; + + resp->xhci_mem_info.evt_ring.va = PREPEND_SID_TO_IOVA(va, + uaudio_qdev->sid); + resp->xhci_mem_info.evt_ring.pa = xhci_pa; + resp->xhci_mem_info.evt_ring.size = PAGE_SIZE; + uaudio_qdev->er_phys_addr = xhci_pa; + + /* dcba */ + xhci_pa = usb_get_dcba_dma_addr(subs->dev); + if (!xhci_pa) { + pr_err("%s:failed to get dcba dma address\n", __func__); + goto unmap_er; + } + + if (!uadev[card_num].dcba_iova) { /* mappped per usb device */ + va = uaudio_iommu_map(MEM_DCBA, xhci_pa, PAGE_SIZE); + if (!va) + goto unmap_er; + + uadev[card_num].dcba_iova = va; + uadev[card_num].dcba_size = PAGE_SIZE; + } + + dcba_va = uadev[card_num].dcba_iova; + resp->xhci_mem_info.dcba.va = PREPEND_SID_TO_IOVA(dcba_va, + uaudio_qdev->sid); + resp->xhci_mem_info.dcba.pa = xhci_pa; + resp->xhci_mem_info.dcba.size = PAGE_SIZE; + + /* data transfer ring */ + xhci_pa = resp->xhci_mem_info.tr_data.pa; + va = uaudio_iommu_map(MEM_XFER_RING, xhci_pa, PAGE_SIZE); + if (!va) + goto unmap_dcba; + + tr_data_va = va; + resp->xhci_mem_info.tr_data.va = PREPEND_SID_TO_IOVA(va, + uaudio_qdev->sid); + resp->xhci_mem_info.tr_data.size = PAGE_SIZE; + + /* sync transfer ring */ + if (!resp->xhci_mem_info.tr_sync.pa) + goto skip_sync; + + xhci_pa = resp->xhci_mem_info.tr_sync.pa; + va = uaudio_iommu_map(MEM_XFER_RING, xhci_pa, PAGE_SIZE); + if (!va) + goto unmap_data; + + tr_sync_va = va; + resp->xhci_mem_info.tr_sync.va = PREPEND_SID_TO_IOVA(va, + uaudio_qdev->sid); + resp->xhci_mem_info.tr_sync.size = PAGE_SIZE; + +skip_sync: + /* xfer buffer, multiple of 4K only */ + if (!xfer_buf_len) + xfer_buf_len = PAGE_SIZE; + + mult = xfer_buf_len / PAGE_SIZE; + remainder = xfer_buf_len % PAGE_SIZE; + len = mult * PAGE_SIZE; + len += remainder ? PAGE_SIZE : 0; + + if (len > MAX_XFER_BUFF_LEN) { + pr_err("%s: req buf len %d > max buf len %lu, setting %lu\n", + __func__, len, MAX_XFER_BUFF_LEN, MAX_XFER_BUFF_LEN); + len = MAX_XFER_BUFF_LEN; + } + + xfer_buf = usb_alloc_coherent(subs->dev, len, GFP_KERNEL, &xfer_buf_pa); + if (!xfer_buf) + goto unmap_sync; + + resp->xhci_mem_info.xfer_buff.pa = xfer_buf_pa; + resp->xhci_mem_info.xfer_buff.size = len; + + va = uaudio_iommu_map(MEM_XFER_BUF, xfer_buf_pa, len); + if (!va) + goto unmap_sync; + + xfer_buf_va = va; + resp->xhci_mem_info.xfer_buff.va = PREPEND_SID_TO_IOVA(va, + uaudio_qdev->sid); + + if (!atomic_read(&uadev[card_num].in_use)) { + kref_init(&uadev[card_num].kref); + init_waitqueue_head(&uadev[card_num].disconnect_wq); + uadev[card_num].num_intf = + subs->dev->config->desc.bNumInterfaces; + uadev[card_num].info = + kzalloc(sizeof(struct intf_info) * + uadev[card_num].num_intf, GFP_KERNEL); + if (!uadev[card_num].info) { + ret = -ENOMEM; + goto unmap_xfer_buf; + } + uadev[card_num].udev = subs->dev; + atomic_set(&uadev[card_num].in_use, 1); + } else { + kref_get(&uadev[card_num].kref); + } + + if (uadev[card_num].info[subs->interface].in_use) { + pr_err("%s interface# %d already in use card# %d\n", __func__, + subs->interface, card_num); + goto unmap_xfer_buf; + } + + uadev[card_num].card_num = card_num; + + /* cache intf specific info to use it for unmap and free xfer buf */ + uadev[card_num].info[subs->interface].data_xfer_ring_va = tr_data_va; + uadev[card_num].info[subs->interface].data_xfer_ring_size = PAGE_SIZE; + uadev[card_num].info[subs->interface].sync_xfer_ring_va = tr_sync_va; + uadev[card_num].info[subs->interface].sync_xfer_ring_size = PAGE_SIZE; + uadev[card_num].info[subs->interface].xfer_buf_va = xfer_buf_va; + uadev[card_num].info[subs->interface].xfer_buf_pa = xfer_buf_pa; + uadev[card_num].info[subs->interface].xfer_buf_size = len; + uadev[card_num].info[subs->interface].xfer_buf = xfer_buf; + uadev[card_num].info[subs->interface].in_use = true; + + set_bit(card_num, &uaudio_qdev->card_slot); + + return 0; + +unmap_xfer_buf: + uaudio_iommu_unmap(MEM_XFER_BUF, xfer_buf_va, len); +unmap_sync: + usb_free_coherent(subs->dev, len, xfer_buf, xfer_buf_pa); + uaudio_iommu_unmap(MEM_XFER_RING, tr_sync_va, PAGE_SIZE); +unmap_data: + uaudio_iommu_unmap(MEM_XFER_RING, tr_data_va, PAGE_SIZE); +unmap_dcba: + uaudio_iommu_unmap(MEM_DCBA, dcba_va, PAGE_SIZE); +unmap_er: + uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE); +err: + return ret; +} + +void uaudio_disconnect_cb(struct snd_usb_audio *chip) +{ + int ret, if_idx; + struct uaudio_dev *dev; + int card_num = chip->card_num; + + pr_debug("%s: for card# %d\n", __func__, card_num); + + mutex_lock(&chip->dev_lock); + if (card_num >= SNDRV_CARDS) { + pr_err("%s: invalid card number\n", __func__); + goto done; + } + + dev = &uadev[card_num]; + if (atomic_read(&dev->in_use)) { + ret = wait_event_interruptible(dev->disconnect_wq, + !atomic_read(&dev->in_use)); + if (ret < 0) { + pr_debug("%s: failed with ret %d\n", __func__, ret); + goto done; + } + } + + /* clean up */ + if (!dev->udev) { + pr_debug("%s: no clean up required\n", __func__); + goto done; + } + + /* free xfer buffer and unmap xfer ring and buf per interface */ + for (if_idx = 0; if_idx < dev->num_intf; if_idx++) { + if (!dev->info[if_idx].in_use) + continue; + usb_free_coherent(dev->udev, + dev->info[if_idx].xfer_buf_size, + dev->info[if_idx].xfer_buf, + dev->info[if_idx].xfer_buf_pa); + + uaudio_iommu_unmap(MEM_XFER_RING, + dev->info[if_idx].data_xfer_ring_va, + dev->info[if_idx].data_xfer_ring_size); + dev->info[if_idx].data_xfer_ring_va = 0; + dev->info[if_idx].data_xfer_ring_size = 0; + + uaudio_iommu_unmap(MEM_XFER_RING, + dev->info[if_idx].sync_xfer_ring_va, + dev->info[if_idx].sync_xfer_ring_size); + dev->info[if_idx].sync_xfer_ring_va = 0; + dev->info[if_idx].sync_xfer_ring_size = 0; + + uaudio_iommu_unmap(MEM_XFER_BUF, + dev->info[if_idx].xfer_buf_va, + dev->info[if_idx].xfer_buf_size); + dev->info[if_idx].xfer_buf_va = 0; + dev->info[if_idx].xfer_buf_size = 0; + pr_debug("%s: release resources: intf# %d card# %d\n", __func__, + if_idx, card_num); + } + + /* iommu_unmap dcba iova for a usb device */ + uaudio_iommu_unmap(MEM_DCBA, dev->dcba_iova, dev->dcba_size); + + dev->dcba_iova = 0; + dev->dcba_size = 0; + dev->num_intf = 0; + + /* free interface info */ + kfree(dev->info); + dev->info = NULL; + + clear_bit(card_num, &uaudio_qdev->card_slot); + + /* all audio devices are disconnected */ + if (!uaudio_qdev->card_slot) { + uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE); + usb_sec_event_ring_cleanup(dev->udev, uaudio_qdev->intr_num); + pr_debug("%s: all audio devices disconnected\n", __func__); + } + + dev->udev = NULL; +done: + mutex_unlock(&chip->dev_lock); +} + +static void uaudio_dev_release(struct kref *kref) +{ + struct uaudio_dev *dev = container_of(kref, struct uaudio_dev, kref); + + pr_debug("%s for dev %p\n", __func__, dev); + + atomic_set(&dev->in_use, 0); + + clear_bit(dev->card_num, &uaudio_qdev->card_slot); + + /* all audio devices are disconnected */ + if (!uaudio_qdev->card_slot) { + usb_sec_event_ring_cleanup(dev->udev, uaudio_qdev->intr_num); + uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE); + pr_debug("%s: all audio devices disconnected\n", __func__); + } + + wake_up(&dev->disconnect_wq); +} + +static int handle_uaudio_stream_req(void *req_h, void *req) +{ + struct qmi_uaudio_stream_req_msg_v01 *req_msg; + struct qmi_uaudio_stream_resp_msg_v01 resp = {0}; + struct snd_usb_substream *subs; + struct snd_usb_audio *chip = NULL; + struct uaudio_qmi_svc *svc = uaudio_svc; + struct intf_info *info; + u8 pcm_card_num, pcm_dev_num, direction; + int intf_num = -1, ret = 0; + + req_msg = (struct qmi_uaudio_stream_req_msg_v01 *)req; + + direction = req_msg->usb_token & SND_PCM_STREAM_DIRECTION; + pcm_dev_num = (req_msg->usb_token & SND_PCM_DEV_NUM_MASK) >> 8; + pcm_card_num = (req_msg->usb_token & SND_PCM_CARD_NUM_MASK) >> 16; + + pr_debug("%s:card#:%d dev#:%d dir:%d en:%d fmt:%d rate:%d #ch:%d\n", + __func__, pcm_card_num, pcm_dev_num, direction, req_msg->enable, + req_msg->audio_format, req_msg->bit_rate, + req_msg->number_of_ch); + + if (pcm_card_num >= SNDRV_CARDS) { + pr_err("%s: invalid card # %u", __func__, pcm_card_num); + ret = -EINVAL; + goto response; + } + + subs = find_snd_usb_substream(pcm_card_num, pcm_dev_num, direction, + &chip, uaudio_disconnect_cb); + if (!subs || !chip || atomic_read(&chip->shutdown)) { + pr_err("%s: can't find substream for card# %u, dev# %u dir%u\n", + __func__, pcm_card_num, pcm_dev_num, direction); + ret = -ENODEV; + goto response; + } + + mutex_lock(&chip->dev_lock); + intf_num = subs->interface; + if (atomic_read(&chip->shutdown) || !subs->stream || !subs->stream->pcm + || !subs->stream->chip) { + ret = -ENODEV; + mutex_unlock(&chip->dev_lock); + goto response; + } + + subs->pcm_format = req_msg->audio_format; + subs->channels = req_msg->number_of_ch; + subs->cur_rate = req_msg->bit_rate; + + ret = snd_usb_enable_audio_stream(subs, req_msg->enable); + + if (!ret && req_msg->enable) + ret = prepare_qmi_response(subs, &resp, req_msg->xfer_buff_size, + pcm_card_num); + + mutex_unlock(&chip->dev_lock); + +response: + if (!req_msg->enable && ret != -EINVAL) { + if (intf_num >= 0) { + mutex_lock(&chip->dev_lock); + info = &uadev[pcm_card_num].info[intf_num]; + uaudio_iommu_unmap(MEM_XFER_RING, + info->data_xfer_ring_va, + info->data_xfer_ring_size); + info->data_xfer_ring_va = 0; + info->data_xfer_ring_size = 0; + + uaudio_iommu_unmap(MEM_XFER_RING, + info->sync_xfer_ring_va, + info->sync_xfer_ring_size); + info->sync_xfer_ring_va = 0; + info->sync_xfer_ring_size = 0; + + uaudio_iommu_unmap(MEM_XFER_BUF, + info->xfer_buf_va, + info->xfer_buf_size); + info->xfer_buf_va = 0; + + usb_free_coherent(uadev[pcm_card_num].udev, + info->xfer_buf_size, + info->xfer_buf, + info->xfer_buf_pa); + info->xfer_buf_size = 0; + info->xfer_buf = NULL; + info->xfer_buf_pa = 0; + info->in_use = false; + pr_debug("%s:release resources: intf# %d card# %d\n", + __func__, intf_num, pcm_card_num); + mutex_unlock(&chip->dev_lock); + } + if (atomic_read(&uadev[pcm_card_num].in_use)) + kref_put(&uadev[pcm_card_num].kref, + uaudio_dev_release); + } + + resp.status = ret; + ret = qmi_send_resp_from_cb(svc->uaudio_svc_hdl, svc->curr_conn, req_h, + &uaudio_stream_resp_desc, &resp, sizeof(resp)); + + svc->t_resp_sent = ktime_get(); + + pr_debug("%s: t_resp sent - t_req recvd (in ms) %lld\n", __func__, + ktime_to_ms(ktime_sub(svc->t_resp_sent, svc->t_request_recvd))); + + return ret; +} + +static int uaudio_qmi_svc_connect_cb(struct qmi_handle *handle, + void *conn_h) +{ + struct uaudio_qmi_svc *svc = uaudio_svc; + + if (svc->uaudio_svc_hdl != handle || !conn_h) { + pr_err("%s: handle mismatch\n", __func__); + return -EINVAL; + } + if (svc->curr_conn) { + pr_err("%s: Service is busy\n", __func__); + return -ECONNREFUSED; + } + svc->curr_conn = conn_h; + return 0; +} + +static int uaudio_qmi_svc_disconnect_cb(struct qmi_handle *handle, + void *conn_h) +{ + struct uaudio_qmi_svc *svc = uaudio_svc; + + if (svc->uaudio_svc_hdl != handle || svc->curr_conn != conn_h) { + pr_err("%s: handle mismatch\n", __func__); + return -EINVAL; + } + + svc->curr_conn = NULL; + return 0; +} + +static int uaudio_qmi_svc_req_cb(struct qmi_handle *handle, void *conn_h, + void *req_h, unsigned int msg_id, void *req) +{ + int ret; + struct uaudio_qmi_svc *svc = uaudio_svc; + + if (svc->uaudio_svc_hdl != handle || svc->curr_conn != conn_h) { + pr_err("%s: handle mismatch\n", __func__); + return -EINVAL; + } + + switch (msg_id) { + case QMI_UAUDIO_STREAM_REQ_V01: + ret = handle_uaudio_stream_req(req_h, req); + break; + + default: + ret = -ENOTSUPP; + break; + } + return ret; +} + +static int uaudio_qmi_svc_req_desc_cb(unsigned int msg_id, + struct msg_desc **req_desc) +{ + int ret; + + pr_debug("%s: msg_id %d\n", __func__, msg_id); + + switch (msg_id) { + case QMI_UAUDIO_STREAM_REQ_V01: + *req_desc = &uaudio_stream_req_desc; + ret = sizeof(struct qmi_uaudio_stream_req_msg_v01); + break; + + default: + ret = -ENOTSUPP; + break; + } + return ret; +} + +static void uaudio_qmi_svc_recv_msg(struct work_struct *w) +{ + int ret; + struct uaudio_qmi_svc *svc = container_of(w, struct uaudio_qmi_svc, + recv_msg_work); + + do { + pr_debug("%s: Notified about a Receive Event", __func__); + } while ((ret = qmi_recv_msg(svc->uaudio_svc_hdl)) == 0); + + if (ret != -ENOMSG) + pr_err("%s: Error receiving message\n", __func__); +} + +static void uaudio_qmi_svc_ntfy(struct qmi_handle *handle, + enum qmi_event_type event, void *priv) +{ + struct uaudio_qmi_svc *svc = uaudio_svc; + + pr_debug("%s: event %d", __func__, event); + + svc->t_request_recvd = ktime_get(); + + switch (event) { + case QMI_RECV_MSG: + queue_work(svc->uaudio_wq, &svc->recv_msg_work); + break; + default: + break; + } +} + +static struct qmi_svc_ops_options uaudio_svc_ops_options = { + .version = 1, + .service_id = UAUDIO_STREAM_SERVICE_ID_V01, + .service_vers = UAUDIO_STREAM_SERVICE_VERS_V01, + .connect_cb = uaudio_qmi_svc_connect_cb, + .disconnect_cb = uaudio_qmi_svc_disconnect_cb, + .req_desc_cb = uaudio_qmi_svc_req_desc_cb, + .req_cb = uaudio_qmi_svc_req_cb, +}; + +static int uaudio_qmi_plat_probe(struct platform_device *pdev) +{ + int ret; + struct device_node *node = pdev->dev.of_node; + + uaudio_qdev = devm_kzalloc(&pdev->dev, sizeof(struct uaudio_qmi_dev), + GFP_KERNEL); + if (!uaudio_qdev) + return -ENOMEM; + + uaudio_qdev->dev = &pdev->dev; + + ret = of_property_read_u32(node, "qcom,usb-audio-stream-id", + &uaudio_qdev->sid); + if (ret) { + dev_err(&pdev->dev, "failed to read sid.\n"); + return -ENODEV; + } + + ret = of_property_read_u32(node, "qcom,usb-audio-intr-num", + &uaudio_qdev->intr_num); + if (ret) { + dev_err(&pdev->dev, "failed to read intr num.\n"); + return -ENODEV; + } + + uaudio_qdev->domain = iommu_domain_alloc(msm_iommu_get_bus(&pdev->dev)); + if (!uaudio_qdev) { + dev_err(&pdev->dev, "failed to callocate iommu domin\n"); + return -ENODEV; + } + + /* attach to external processor iommu */ + ret = iommu_attach_device(uaudio_qdev->domain, &pdev->dev); + if (ret) { + dev_err(&pdev->dev, "failed to attach device ret = %d\n", ret); + goto free_domain; + } + + /* initialize dcba, xfer ring and xfer buf iova list */ + INIT_LIST_HEAD(&uaudio_qdev->dcba_list); + uaudio_qdev->curr_dcba_iova = IOVA_DCBA_BASE; + uaudio_qdev->dcba_iova_size = SNDRV_CARDS * PAGE_SIZE; + + INIT_LIST_HEAD(&uaudio_qdev->xfer_ring_list); + uaudio_qdev->curr_xfer_ring_iova = IOVA_XFER_RING_BASE; + uaudio_qdev->xfer_ring_iova_size = + IOVA_XFER_RING_MAX - IOVA_XFER_RING_BASE; + + INIT_LIST_HEAD(&uaudio_qdev->xfer_buf_list); + uaudio_qdev->curr_xfer_buf_iova = IOVA_XFER_BUF_BASE; + uaudio_qdev->xfer_buf_iova_size = + IOVA_XFER_BUF_MAX - IOVA_XFER_BUF_BASE; + + return 0; + +free_domain: + iommu_domain_free(uaudio_qdev->domain); + return ret; +} + +static int uaudio_qmi_plat_remove(struct platform_device *pdev) +{ + iommu_detach_device(uaudio_qdev->domain, &pdev->dev); + iommu_domain_free(uaudio_qdev->domain); + uaudio_qdev->domain = NULL; + + return 0; +} + +static const struct of_device_id of_uaudio_matach[] = { + { + .compatible = "qcom,usb-audio-qmi-dev", + }, + { }, +}; +MODULE_DEVICE_TABLE(of, of_uaudio_matach); + +static struct platform_driver uaudio_qmi_driver = { + .probe = uaudio_qmi_plat_probe, + .remove = uaudio_qmi_plat_remove, + .driver = { + .name = "uaudio-qmi", + .of_match_table = of_uaudio_matach, + }, +}; + +static int uaudio_qmi_svc_init(void) +{ + int ret; + struct uaudio_qmi_svc *svc; + + svc = kzalloc(sizeof(struct uaudio_qmi_svc), GFP_KERNEL); + if (!svc) + return -ENOMEM; + + svc->uaudio_wq = create_singlethread_workqueue("uaudio_svc"); + if (!svc->uaudio_wq) { + ret = -ENOMEM; + goto free_svc; + } + + svc->uaudio_svc_hdl = qmi_handle_create(uaudio_qmi_svc_ntfy, NULL); + if (!svc->uaudio_svc_hdl) { + pr_err("%s: Error creating svc_hdl\n", __func__); + ret = -EFAULT; + goto destroy_uaudio_wq; + } + + ret = qmi_svc_register(svc->uaudio_svc_hdl, &uaudio_svc_ops_options); + if (ret < 0) { + pr_err("%s:Error registering uaudio svc %d\n", __func__, ret); + goto destroy_svc_handle; + } + + INIT_WORK(&svc->recv_msg_work, uaudio_qmi_svc_recv_msg); + + uaudio_svc = svc; + + return 0; + +destroy_svc_handle: + qmi_handle_destroy(svc->uaudio_svc_hdl); +destroy_uaudio_wq: + destroy_workqueue(svc->uaudio_wq); +free_svc: + kfree(svc); + return ret; +} + +static void uaudio_qmi_svc_exit(void) +{ + struct uaudio_qmi_svc *svc = uaudio_svc; + + qmi_svc_unregister(svc->uaudio_svc_hdl); + flush_workqueue(svc->uaudio_wq); + qmi_handle_destroy(svc->uaudio_svc_hdl); + destroy_workqueue(svc->uaudio_wq); + kfree(svc); + uaudio_svc = NULL; +} + +static int __init uaudio_qmi_plat_init(void) +{ + int ret; + + ret = platform_driver_register(&uaudio_qmi_driver); + if (ret) + return ret; + + return uaudio_qmi_svc_init(); +} + +static void __exit uaudio_qmi_plat_exit(void) +{ + uaudio_qmi_svc_exit(); + platform_driver_unregister(&uaudio_qmi_driver); +} + +module_init(uaudio_qmi_plat_init); +module_exit(uaudio_qmi_plat_exit); + +MODULE_DESCRIPTION("USB AUDIO QMI Service Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/usb/usb_audio_qmi_v01.c b/sound/usb/usb_audio_qmi_v01.c new file mode 100644 index 000000000000..31b1ba74d5c7 --- /dev/null +++ b/sound/usb/usb_audio_qmi_v01.c @@ -0,0 +1,565 @@ + /* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include <linux/qmi_encdec.h> + +#include <soc/qcom/msm_qmi_interface.h> + +#include "usb_audio_qmi_v01.h" + +static struct elem_info mem_info_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint64_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct mem_info_v01, + va), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint64_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct mem_info_v01, + pa), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct mem_info_v01, + size), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct elem_info apps_mem_info_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct mem_info_v01), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct apps_mem_info_v01, + evt_ring), + .ei_array = mem_info_v01_ei, + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct mem_info_v01), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct apps_mem_info_v01, + tr_data), + .ei_array = mem_info_v01_ei, + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct mem_info_v01), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct apps_mem_info_v01, + tr_sync), + .ei_array = mem_info_v01_ei, + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct mem_info_v01), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct apps_mem_info_v01, + xfer_buff), + .ei_array = mem_info_v01_ei, + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct mem_info_v01), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct apps_mem_info_v01, + dcba), + .ei_array = mem_info_v01_ei, + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct elem_info usb_endpoint_descriptor_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + bLength), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + bDescriptorType), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + bEndpointAddress), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + bmAttributes), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint16_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + wMaxPacketSize), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + bInterval), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + bRefresh), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_endpoint_descriptor_v01, + bSynchAddress), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct elem_info usb_interface_descriptor_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bLength), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bDescriptorType), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bInterfaceNumber), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bAlternateSetting), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bNumEndpoints), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bInterfaceClass), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bInterfaceSubClass), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + bInterfaceProtocol), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct usb_interface_descriptor_v01, + iInterface), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info qmi_uaudio_stream_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + priv_data), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + enable), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x03, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + usb_token), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x04, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + audio_format), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x05, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + number_of_ch), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x06, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + bit_rate), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x07, + .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01, + xfer_buff_size), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info qmi_uaudio_stream_resp_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + priv_data), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + status), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x03, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + slot_id), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x04, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + bSubslotSize), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct usb_interface_descriptor_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x05, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + std_as_opr_intf_desc), + .ei_array = usb_interface_descriptor_v01_ei, + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct usb_endpoint_descriptor_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x06, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + std_as_data_ep_desc), + .ei_array = usb_endpoint_descriptor_v01_ei, + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct usb_endpoint_descriptor_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x07, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + std_as_sync_ep_desc), + .ei_array = usb_endpoint_descriptor_v01_ei, + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x08, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + bDelay), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint16_t), + .is_array = NO_ARRAY, + .tlv_type = 0x09, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + bcdADC), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct apps_mem_info_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x0A, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + xhci_mem_info), + .ei_array = apps_mem_info_v01_ei, + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x0B, + .offset = offsetof( + struct qmi_uaudio_stream_resp_msg_v01, + interrupter_num), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info qmi_uaudio_stream_ind_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + usb_token), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + priv_data), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x03, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + status), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x04, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + slot_id), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x05, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + bSubslotSize), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct usb_interface_descriptor_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x06, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + std_as_opr_intf_desc), + .ei_array = usb_interface_descriptor_v01_ei, + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct usb_endpoint_descriptor_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x07, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + std_as_data_ep_desc), + .ei_array = usb_endpoint_descriptor_v01_ei, + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct usb_endpoint_descriptor_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x08, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + std_as_sync_ep_desc), + .ei_array = usb_endpoint_descriptor_v01_ei, + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct apps_mem_info_v01), + .is_array = NO_ARRAY, + .tlv_type = 0x09, + .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01, + xhci_mem_info), + .ei_array = apps_mem_info_v01_ei, + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .is_array = QMI_COMMON_TLV_TYPE, + }, +}; diff --git a/sound/usb/usb_audio_qmi_v01.h b/sound/usb/usb_audio_qmi_v01.h new file mode 100644 index 000000000000..7ad1ab8a61a9 --- /dev/null +++ b/sound/usb/usb_audio_qmi_v01.h @@ -0,0 +1,103 @@ + /* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef USB_QMI_V01_H +#define USB_QMI_V01_H + +#define UAUDIO_STREAM_SERVICE_ID_V01 0x41C +#define UAUDIO_STREAM_SERVICE_VERS_V01 0x01 + +#define QMI_UAUDIO_STREAM_RESP_V01 0x0001 +#define QMI_UAUDIO_STREAM_REQ_V01 0x0001 +#define QMI_UADUIO_STREAM_IND_V01 0x0001 + + +struct mem_info_v01 { + uint64_t va; + uint64_t pa; + uint32_t size; +}; + +struct apps_mem_info_v01 { + struct mem_info_v01 evt_ring; + struct mem_info_v01 tr_data; + struct mem_info_v01 tr_sync; + struct mem_info_v01 xfer_buff; + struct mem_info_v01 dcba; +}; + +struct usb_endpoint_descriptor_v01 { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint16_t wMaxPacketSize; + uint8_t bInterval; + uint8_t bRefresh; + uint8_t bSynchAddress; +}; + +struct usb_interface_descriptor_v01 { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; +}; + +struct qmi_uaudio_stream_req_msg_v01 { + uint32_t priv_data; + uint8_t enable; + uint32_t usb_token; + uint32_t audio_format; + uint32_t number_of_ch; + uint32_t bit_rate; + uint32_t xfer_buff_size; +}; +#define QMI_UAUDIO_STREAM_REQ_MSG_V01_MAX_MSG_LEN 46 +extern struct elem_info qmi_uaudio_stream_req_msg_v01_ei[]; + +struct qmi_uaudio_stream_resp_msg_v01 { + uint32_t priv_data; + uint32_t status; + uint32_t slot_id; + uint8_t bSubslotSize; + struct usb_interface_descriptor_v01 std_as_opr_intf_desc; + struct usb_endpoint_descriptor_v01 std_as_data_ep_desc; + struct usb_endpoint_descriptor_v01 std_as_sync_ep_desc; + uint8_t bDelay; + uint16_t bcdADC; + struct apps_mem_info_v01 xhci_mem_info; + uint8_t interrupter_num; +}; +#define QMI_UAUDIO_STREAM_RESP_MSG_V01_MAX_MSG_LEN 177 +extern struct elem_info qmi_uaudio_stream_resp_msg_v01_ei[]; + +struct qmi_uaudio_stream_ind_msg_v01 { + uint32_t usb_token; + uint32_t priv_data; + uint32_t status; + uint32_t slot_id; + uint8_t bSubslotSize; + struct usb_interface_descriptor_v01 std_as_opr_intf_desc; + struct usb_endpoint_descriptor_v01 std_as_data_ep_desc; + struct usb_endpoint_descriptor_v01 std_as_sync_ep_desc; + struct apps_mem_info_v01 xhci_mem_info; +}; +#define QMI_UAUDIO_STREAM_IND_MSG_V01_MAX_MSG_LEN 171 +extern struct elem_info qmi_uaudio_stream_ind_msg_v01_ei[]; + +#endif diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index b665d85555cb..b776122d0ca9 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -60,6 +60,10 @@ struct snd_usb_audio { bool autoclock; /* from the 'autoclock' module param */ struct usb_host_interface *ctrl_intf; /* the audio control interface */ + + struct mutex dev_lock; /* to protect any race with disconnect */ + int card_num; /* cache pcm card number to use upon disconnect */ + void (*disconnect_cb)(struct snd_usb_audio *chip); }; #define usb_audio_err(chip, fmt, args...) \ diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c index 96234b638249..5d51d6ff08e6 100644 --- a/tools/hv/hv_vss_daemon.c +++ b/tools/hv/hv_vss_daemon.c @@ -254,7 +254,7 @@ int main(int argc, char *argv[]) syslog(LOG_ERR, "Illegal op:%d\n", op); } vss_msg->error = error; - len = write(vss_fd, &error, sizeof(struct hv_vss_msg)); + len = write(vss_fd, vss_msg, sizeof(struct hv_vss_msg)); if (len != sizeof(struct hv_vss_msg)) { syslog(LOG_ERR, "write failed; error: %d %s", errno, strerror(errno)); diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 2d9d8306dbd3..4a3a72cb5805 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -310,7 +310,6 @@ int perf_stat_process_counter(struct perf_stat_config *config, int i, ret; aggr->val = aggr->ena = aggr->run = 0; - init_stats(ps->res_stats); if (counter->per_pkg) zero_per_pkg(counter); diff --git a/tools/testing/selftests/efivarfs/efivarfs.sh b/tools/testing/selftests/efivarfs/efivarfs.sh index 77edcdcc016b..057278448515 100755 --- a/tools/testing/selftests/efivarfs/efivarfs.sh +++ b/tools/testing/selftests/efivarfs/efivarfs.sh @@ -88,7 +88,11 @@ test_delete() exit 1 fi - rm $file + rm $file 2>/dev/null + if [ $? -ne 0 ]; then + chattr -i $file + rm $file + fi if [ -e $file ]; then echo "$file couldn't be deleted" >&2 @@ -111,6 +115,7 @@ test_zero_size_delete() exit 1 fi + chattr -i $file printf "$attrs" > $file if [ -e $file ]; then @@ -141,7 +146,11 @@ test_valid_filenames() echo "$file could not be created" >&2 ret=1 else - rm $file + rm $file 2>/dev/null + if [ $? -ne 0 ]; then + chattr -i $file + rm $file + fi fi done @@ -174,7 +183,11 @@ test_invalid_filenames() if [ -e $file ]; then echo "Creating $file should have failed" >&2 - rm $file + rm $file 2>/dev/null + if [ $? -ne 0 ]; then + chattr -i $file + rm $file + fi ret=1 fi done diff --git a/tools/testing/selftests/efivarfs/open-unlink.c b/tools/testing/selftests/efivarfs/open-unlink.c index 8c0764407b3c..4af74f733036 100644 --- a/tools/testing/selftests/efivarfs/open-unlink.c +++ b/tools/testing/selftests/efivarfs/open-unlink.c @@ -1,10 +1,68 @@ +#include <errno.h> #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <unistd.h> +#include <sys/ioctl.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> +#include <linux/fs.h> + +static int set_immutable(const char *path, int immutable) +{ + unsigned int flags; + int fd; + int rc; + int error; + + fd = open(path, O_RDONLY); + if (fd < 0) + return fd; + + rc = ioctl(fd, FS_IOC_GETFLAGS, &flags); + if (rc < 0) { + error = errno; + close(fd); + errno = error; + return rc; + } + + if (immutable) + flags |= FS_IMMUTABLE_FL; + else + flags &= ~FS_IMMUTABLE_FL; + + rc = ioctl(fd, FS_IOC_SETFLAGS, &flags); + error = errno; + close(fd); + errno = error; + return rc; +} + +static int get_immutable(const char *path) +{ + unsigned int flags; + int fd; + int rc; + int error; + + fd = open(path, O_RDONLY); + if (fd < 0) + return fd; + + rc = ioctl(fd, FS_IOC_GETFLAGS, &flags); + if (rc < 0) { + error = errno; + close(fd); + errno = error; + return rc; + } + close(fd); + if (flags & FS_IMMUTABLE_FL) + return 1; + return 0; +} int main(int argc, char **argv) { @@ -27,7 +85,7 @@ int main(int argc, char **argv) buf[4] = 0; /* create a test variable */ - fd = open(path, O_WRONLY | O_CREAT); + fd = open(path, O_WRONLY | O_CREAT, 0600); if (fd < 0) { perror("open(O_WRONLY)"); return EXIT_FAILURE; @@ -41,6 +99,18 @@ int main(int argc, char **argv) close(fd); + rc = get_immutable(path); + if (rc < 0) { + perror("ioctl(FS_IOC_GETFLAGS)"); + return EXIT_FAILURE; + } else if (rc) { + rc = set_immutable(path, 0); + if (rc < 0) { + perror("ioctl(FS_IOC_SETFLAGS)"); + return EXIT_FAILURE; + } + } + fd = open(path, O_RDONLY); if (fd < 0) { perror("open"); diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 7a2f449bd85d..5d10f104f3eb 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -1875,8 +1875,8 @@ void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu) static int vgic_vcpu_init_maps(struct kvm_vcpu *vcpu, int nr_irqs) { struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; - - int sz = (nr_irqs - VGIC_NR_PRIVATE_IRQS) / 8; + int nr_longs = BITS_TO_LONGS(nr_irqs - VGIC_NR_PRIVATE_IRQS); + int sz = nr_longs * sizeof(unsigned long); vgic_cpu->pending_shared = kzalloc(sz, GFP_KERNEL); vgic_cpu->active_shared = kzalloc(sz, GFP_KERNEL); vgic_cpu->pend_act_shared = kzalloc(sz, GFP_KERNEL); diff --git a/virt/kvm/async_pf.c b/virt/kvm/async_pf.c index 77d42be6970e..4f70d12e392d 100644 --- a/virt/kvm/async_pf.c +++ b/virt/kvm/async_pf.c @@ -173,7 +173,7 @@ int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, unsigned long hva, * do alloc nowait since if we are going to sleep anyway we * may as well sleep faulting in page */ - work = kmem_cache_zalloc(async_pf_cache, GFP_NOWAIT); + work = kmem_cache_zalloc(async_pf_cache, GFP_NOWAIT | __GFP_NOWARN); if (!work) return 0; diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 484079efea5b..7338e30421d8 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1961,6 +1961,9 @@ static void grow_halt_poll_ns(struct kvm_vcpu *vcpu) else val *= halt_poll_ns_grow; + if (val > halt_poll_ns) + val = halt_poll_ns; + vcpu->halt_poll_ns = val; trace_kvm_halt_poll_ns_grow(vcpu->vcpu_id, val, old); } |
