]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'srini/qcomlt-4.4-wcnss-q6v5-sync' into release/qcomlt-4.4
authorNicolas Dechesne <nicolas.dechesne@linaro.org>
Thu, 23 Jun 2016 13:39:23 +0000 (15:39 +0200)
committerNicolas Dechesne <nicolas.dechesne@linaro.org>
Thu, 23 Jun 2016 13:39:23 +0000 (15:39 +0200)
63 files changed:
Documentation/devicetree/bindings/clock/qcom,rpmcc.txt
arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval-pins.dtsi
arch/arm/boot/dts/qcom-apq8064-arrow-sd-600eval.dts
arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
arch/arm/boot/dts/qcom-apq8064.dtsi
arch/arm/configs/qcom_defconfig
arch/arm64/boot/dts/qcom/msm8916-bus.dtsi
arch/arm64/boot/dts/qcom/msm8916-coresight.dtsi
arch/arm64/boot/dts/qcom/msm8916.dtsi
arch/arm64/configs/defconfig
drivers/bluetooth/Kconfig
drivers/bluetooth/btqcomsmd.c
drivers/clk/qcom/Kconfig
drivers/clk/qcom/Makefile
drivers/clk/qcom/clk-rpm.c
drivers/clk/qcom/clk-rpm.h [deleted file]
drivers/clk/qcom/clk-smd-rpm.c
drivers/clk/qcom/clk-smd-rpm.h [deleted file]
drivers/firmware/qcom_scm-32.c
drivers/firmware/qcom_scm-64.c
drivers/firmware/qcom_scm.c
drivers/firmware/qcom_scm.h
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-qcom-smp2p.c [deleted file]
drivers/gpio/gpio-qcom-smsm.c [deleted file]
drivers/net/wireless/ath/wcn36xx/Kconfig
drivers/net/wireless/ath/wcn36xx/Makefile
drivers/net/wireless/ath/wcn36xx/dxe.c
drivers/net/wireless/ath/wcn36xx/dxe.h
drivers/net/wireless/ath/wcn36xx/hal.h
drivers/net/wireless/ath/wcn36xx/main.c
drivers/net/wireless/ath/wcn36xx/smd.c
drivers/net/wireless/ath/wcn36xx/smd.h
drivers/net/wireless/ath/wcn36xx/txrx.c
drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c [deleted file]
drivers/net/wireless/ath/wcn36xx/wcn36xx.h
drivers/net/wireless/ath/wcn36xx/wcnss_core.c [deleted file]
drivers/net/wireless/ath/wcn36xx/wcnss_core.h [deleted file]
drivers/remoteproc/Kconfig
drivers/remoteproc/Makefile
drivers/remoteproc/qcom_mdt_loader.c [new file with mode: 0644]
drivers/remoteproc/qcom_mdt_loader.h [new file with mode: 0644]
drivers/remoteproc/qcom_q6v5_pil.c
drivers/remoteproc/qcom_tz_pil.c
drivers/remoteproc/qcom_wcnss.c [new file with mode: 0644]
drivers/remoteproc/qcom_wcnss.h [new file with mode: 0644]
drivers/remoteproc/qcom_wcnss_iris.c [new file with mode: 0644]
drivers/remoteproc/remoteproc_debugfs.c
drivers/soc/qcom/Kconfig
drivers/soc/qcom/Makefile
drivers/soc/qcom/ipcrtr_stub.c [deleted file]
drivers/soc/qcom/smd-rpm.c
drivers/soc/qcom/smd.c
drivers/soc/qcom/smem.c
drivers/soc/qcom/wcnss_ctrl.c
include/dt-bindings/clock/qcom,rpmcc.h
include/linux/qcom_scm.h
include/linux/soc/qcom/smd.h
include/linux/soc/qcom/wcnss_ctrl.h [new file with mode: 0644]
include/net/mac80211.h
net/qrtr/smd.c
sound/soc/qcom/qdsp6/core/apr_tal.c

index 5904902862de620696ed2f2998491850660357f9..87d3714b956a281e4e8ea68d086d11a5f9a09516 100644 (file)
@@ -11,9 +11,7 @@ Required properties :
                compatible "qcom,rpmcc" should be also included.
 
                        "qcom,rpmcc-msm8916", "qcom,rpmcc"
-                       "qcom,rpmcc-msm8974", "qcom,rpmcc"
                        "qcom,rpmcc-apq8064", "qcom,rpmcc"
-                       "qcom,rpmcc-apq8084", "qcom,rpmcc"
 
 - #clock-cells : shall contain 1
 
@@ -30,7 +28,7 @@ Example:
                                compatible = "qcom,rpm-msm8916";
                                qcom,smd-channels = "rpm_requests";
 
-                               rpmcc: qcom,rpmcc {
+                               rpmcc: clock-controller {
                                        compatible = "qcom,rpmcc-msm8916", "qcom,rpmcc";
                                        #clock-cells = <1>;
                                };
index a3efb9704fcd964e0eaa1aa6ed0f2f41dac367ee..b6f2444047d23d65729c0ae9837b5ba83613647c 100644 (file)
                        bias-disable;
                };
        };
+
+       wcnss_pin_a: wcnss {
+               bt {
+                       function = "riva_bt";
+                       pins = "gpio16", "gpio17";
+               };
+
+               fm {
+                       function = "riva_fm";
+                       pins = "gpio14", "gpio15";
+               };
+
+               wlan {
+                       function = "riva_wlan";
+                       pins = "gpio64", "gpio65", "gpio66", "gpio67", "gpio68";
+                       drive-strength = <6>;
+                       bias-pull-up;
+               };
+       };
 };
 
 &pm8921_mpps {
index bf6457642776fc71f4e7ce33902c7c79bdae9370..10b7f570a4539b486920c07f7de7568c899c6b17 100644 (file)
 
        };
 
+       smd {
+               q6@1 {
+                       status = "ok";
+               };
+
+               riva@6 {
+                       status = "ok";
+               };
+       };
+
        soc {
                rpm@108000 {
                        regulators {
                                        bias-pull-down;
                                };
 
+                               s2 {
+                                       regulator-min-microvolt = <1300000>;
+                                       regulator-max-microvolt = <1300000>;
+                                       qcom,switch-mode-frequency = <1600000>;
+                                       bias-pull-down;
+                                       regulator-always-on;
+                               };
+
                                s3 {
                                        regulator-min-microvolt = <1000000>;
                                        regulator-max-microvolt = <1400000>;
                                        bias-pull-down;
                                };
 
+                               l26 {
+                                       regulator-min-microvolt = < 375000>;
+                                       regulator-max-microvolt = <1050000>;
+                                       bias-pull-down;
+                               };
                                lvs6 {
                                        bias-pull-down;
                                };
 
                                lvs7 {
                                        bias-pull-down;
+                                       regulator-always-on;
                                };
                        };
                };
                        target-supply   = <&pm8921_lvs7>;
                };
 
+               wcnss@3204000 {
+                       status = "ok";
+
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&wcnss_pin_a>;
+               };
+
                /* OTG */
                phy@12500000 {
                        status          = "okay";
                usb@12530000 {
                        status = "okay";
                };
+               pil_q6v4: pil@28800000 {
+                       qcom,pll-supply = <&pm8921_l26>;
+                       qcom,pll-uV = <1050000>;
+               };
 
                hdmi: qcom,hdmi-tx@4a00000 {
                        status = "okay";
index 91e497adb5bb3fd83441571d2e72aff23ed5269c..5b6d7072acb651f166447a353671c94cf59995fc 100644 (file)
                };
        };
 
+       smd {
+               q6@1 {
+                       status = "okay";
+               };
+       };
+
        soc {
                pinctrl@800000 {
                        card_detect: card_detect {
index dc58c23328053332455a5a662d8212d4cf402a35..ac4e7f91db2dd8430872047b42ef798f72d130ac 100644 (file)
                        reg = <0x80000000 0x200000>;
                        no-map;
                };
+
+               wcnss_mem: wcnss@8f000000 {
+                       reg = <0x8f000000 0x700000>;
+                       no-map;
+               };
        };
 
        cpus {
                };
        };
 
+       smd {
+               compatible = "qcom,smd";
+
+               modem@0 {
+                       interrupts = <0 37 IRQ_TYPE_EDGE_RISING>;
+
+                       qcom,ipc = <&l2cc 8 3>;
+                       qcom,smd-edge = <0>;
+
+                       status = "disabled";
+               };
+
+               q6@1 {
+                       interrupts = <0 90 IRQ_TYPE_EDGE_RISING>;
+
+                       qcom,ipc = <&l2cc 8 15>;
+                       qcom,smd-edge = <1>;
+
+                       status = "disabled";
+
+                       apr {
+                               compatible = "qcom,apr";
+                               qcom,smd-channels = "apr_audio_svc";
+                               rproc = <&pil_q6v4>;
+                       };
+               };
+
+               dsps@3 {
+                       interrupts = <0 138 IRQ_TYPE_EDGE_RISING>;
+
+                       qcom,ipc = <&sps_sic_non_secure 0x4080 0>;
+                       qcom,smd-edge = <3>;
+
+                       status = "disabled";
+               };
+
+               riva@6 {
+                       interrupts = <0 198 IRQ_TYPE_EDGE_RISING>;
+
+                       qcom,ipc = <&l2cc 8 25>;
+                       qcom,smd-edge = <6>;
+
+                       status = "disabled";
+
+                       wcnss {
+                               compatible = "qcom,wcnss";
+                               qcom,smd-channels = "WCNSS_CTRL";
+
+                               qcom,mmio = <&riva>;
+
+                               bt {
+                                       compatible = "qcom,wcnss-bt";
+                               };
+
+                               wifi {
+                                       compatible = "qcom,wcnss-wlan";
+
+                                       interrupts = <0 203 0>, <0 202 0>;
+                                       interrupt-names = "tx", "rx";
+
+                                       qcom,state = <&apps_smsm 10>, <&apps_smsm 9>;
+                                       qcom,state-names = "tx-enable", "tx-rings-empty";
+
+                                       local-mac-address = [ 18 00 2d 88 9c a9 ];
+                               };
+                       };
+               };
+       };
+
+       smsm {
+               compatible = "qcom,smsm";
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               qcom,ipc-1 = <&l2cc 8 4>;
+               qcom,ipc-2 = <&l2cc 8 14>;
+               qcom,ipc-3 = <&l2cc 8 23>;
+               qcom,ipc-4 = <&sps_sic_non_secure 0x4094 0>;
+
+               apps_smsm: apps@0 {
+                       reg = <0>;
+                       #qcom,state-cells = <1>;
+               };
+
+               modem_smsm: modem@1 {
+                       reg = <1>;
+                       interrupts = <0 38 IRQ_TYPE_EDGE_RISING>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               q6_smsm: q6@2 {
+                       reg = <2>;
+                       interrupts = <0 89 IRQ_TYPE_EDGE_RISING>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               wcnss_smsm: wcnss@3 {
+                       reg = <3>;
+                       interrupts = <0 204 IRQ_TYPE_EDGE_RISING>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+
+               dsps_smsm: dsps@4 {
+                       reg = <4>;
+                       interrupts = <0 137 IRQ_TYPE_EDGE_RISING>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+       };
+
        soc: soc {
                #address-cells = <1>;
                #size-cells = <1>;
                        regulator-max-microvolt = <1250000>;
                };
 
+               sps_sic_non_secure: sps-sic-non-secure@12100000 {
+                       compatible      = "syscon";
+                       reg             = <0x12100000 0x10000>;
+               };
+
                gsbi1: gsbi@12440000 {
                        status = "disabled";
                        compatible = "qcom,gsbi-v1.0.0";
                        };
                };
 
+               riva: wcnss@3204000 {
+                       compatible = "qcom,riva-pil", "qcom,riva";
+                       reg = <0x03200800 0x1000>, <0x03202000 0x2000>, <0x03204000 0x100>;
+                       reg-names = "ccu", "dxe", "pmu";
+
+                       interrupts-extended = <&intc 0 199 IRQ_TYPE_EDGE_RISING>,
+                                             <&wcnss_smsm 6 IRQ_TYPE_EDGE_RISING>;
+                       interrupt-names = "wdog", "fatal";
+
+                       memory-region = <&wcnss_mem>;
+
+                       vddcx-supply = <&pm8921_s3>;
+                       vddmx-supply = <&pm8921_l24>;
+                       vddpx-supply = <&pm8921_s4>;
+
+                       status = "disabled";
+
+                       iris {
+                               compatible = "qcom,wcn3660";
+
+                               clocks = <&rpmcc 9>;
+                               clock-names = "xo";
+
+                               vddxo-supply = <&pm8921_l4>;
+                               vddrfa-supply = <&pm8921_s2>;
+                               vddpa-supply = <&pm8921_l10>;
+                               vdddig-supply = <&pm8921_lvs2>;
+                       };
+               };
+
+
                usb1_phy: phy@12500000 {
                        compatible      = "qcom,usb-otg-ci";
                        reg             = <0x12500000 0x400>;
                        qcom,pas-id             = <1>; /* PAS_Q6 */
                };
 
-               smd {
-                       compatible = "qcom,smd";
-                       adsp_a11 {
-                               interrupts = <0 90 IRQ_TYPE_EDGE_RISING>;
-                               qcom,ipc = <&l2cc 8 15>;
-                               qcom,smd-edge = <1>;
-                               qcom,remote-pid = <0x2>;
-                               q6_requests {
-                                       compatible      = "qcom,apr";
-                                       qcom,smd-channels = "apr_audio_svc";
-                                       rproc = <&pil_q6v4>;
-                               };
-                       };
-               };
-
                dai_fe: dai_fe {
                        compatible      = "qcom,msm-dai-fe";
                        #sound-dai-cells = <0>;
index 702e9d189d94b75a653dbbee495d67ce3d6ec20b..92d69dcae6238a05ada79002e90274e2c83ad71a 100644 (file)
@@ -73,6 +73,7 @@ CONFIG_BT_BNEP_PROTO_FILTER=y
 CONFIG_BT_HIDP=y
 CONFIG_BT_HCIUART=y
 CONFIG_BT_HCIUART_ATH3K=y
+CONFIG_BT_QCOMSMD=y
 CONFIG_CFG80211=m
 CONFIG_CFG80211_WEXT=y
 CONFIG_MAC80211=m
@@ -113,6 +114,8 @@ CONFIG_USB_USBNET=y
 CONFIG_ATH_CARDS=m
 CONFIG_ATH6KL=m
 CONFIG_ATH6KL_SDIO=m
+CONFIG_WCN36XX=m
+CONFIG_WCN36XX_DEBUGFS=y
 CONFIG_INPUT_EVDEV=y
 # CONFIG_KEYBOARD_ATKBD is not set
 # CONFIG_MOUSE_PS2 is not set
@@ -277,12 +280,17 @@ CONFIG_KPSS_XCC=y
 CONFIG_KRAITCC=y
 CONFIG_HWSPINLOCK_QCOM=y
 CONFIG_MSM_IOMMU=y
+CONFIG_QCOM_Q6V5_PIL=y
 CONFIG_QCOM_TZ_PIL=y
+CONFIG_QCOM_WCNSS_PIL=y
 CONFIG_QCOM_GSBI=y
 CONFIG_QCOM_PM=y
 CONFIG_QCOM_SMEM=y
 CONFIG_QCOM_SMD=y
 CONFIG_QCOM_SMD_RPM=y
+CONFIG_QCOM_SMP2P=y
+CONFIG_QCOM_SMSM=y
+CONFIG_QCOM_WCNSS_CTRL=y
 CONFIG_PHY_QCOM_APQ8064_SATA=y
 CONFIG_PHY_QCOM_IPQ806X_SATA=y
 CONFIG_NVMEM=y
index 77f76fd37fa4b11b5ad5d292e3e6006cd86eb4a2..11e707cef476f1e7a07556d3a01dd7c06f199f18 100644 (file)
@@ -95,8 +95,8 @@
                qcom,qos-off = <0x1000>;
                qcom,bus-type = <1>;
                clock-names = "bus_clk", "bus_a_clk";
-               clocks = <&rpmcc  RPM_SNOC_CLK>,
-                      <&rpmcc  RPM_SNOC_A_CLK>;
+               clocks = <&rpmcc  RPM_SMD_SNOC_CLK>,
+                      <&rpmcc  RPM_SMD_SNOC_A_CLK>;
        };
 
        fab_bimc: fab-bimc {
                qcom,base-name = "bimc-base";
                qcom,bus-type = <2>;
                clock-names = "bus_clk", "bus_a_clk";
-               clocks = <&rpmcc  RPM_BIMC_CLK>,
-                      <&rpmcc  RPM_BIMC_A_CLK>;
+               clocks = <&rpmcc  RPM_SMD_BIMC_CLK>,
+                      <&rpmcc  RPM_SMD_BIMC_A_CLK>;
        };
 
        fab_pnoc: fab-pnoc {
                qcom,qos-delta = <0x1000>;
                qcom,bus-type = <1>;
                clock-names = "bus_clk", "bus_a_clk";
-               clocks = <&rpmcc  RPM_PCNOC_CLK>,
-                      <&rpmcc  RPM_PCNOC_A_CLK>;
+               clocks = <&rpmcc  RPM_SMD_PCNOC_CLK>,
+                      <&rpmcc  RPM_SMD_PCNOC_A_CLK>;
        };
 
        /* SNOC Devices */
index c008dc7a32bb9495262f004d7162a3f4e310390d..9cac742817aae5024200851ce0cc585d5ae26136 100644 (file)
@@ -17,7 +17,7 @@
                compatible = "arm,coresight-tpiu", "arm,primecell";
                reg = <0x820000 0x1000>;
 
-               clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+               clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                clock-names = "apb_pclk", "atclk";
 
                port {
@@ -32,7 +32,7 @@
                compatible = "arm,coresight-funnel", "arm,primecell";
                reg = <0x821000 0x1000>;
 
-               clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+               clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                clock-names = "apb_pclk", "atclk";
 
                ports {
@@ -69,7 +69,7 @@
                compatible = "qcom,coresight-replicator1x", "arm,primecell";
                reg = <0x824000 0x1000>;
 
-               clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+               clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                clock-names = "apb_pclk", "atclk";
 
                ports {
                compatible = "arm,coresight-tmc", "arm,primecell";
                reg = <0x825000 0x1000>;
 
-               clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+               clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                clock-names = "apb_pclk", "atclk";
 
                ports {
                compatible = "arm,coresight-tmc", "arm,primecell";
                reg = <0x826000 0x1000>;
 
-               clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+               clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                clock-names = "apb_pclk", "atclk";
 
                port {
                compatible = "arm,coresight-funnel", "arm,primecell";
                reg = <0x841000 0x1000>;
 
-               clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+               clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                clock-names = "apb_pclk", "atclk";
 
                ports {
                compatible = "arm,coresight-etm4x", "arm,primecell";
                reg = <0x85c000 0x1000>;
 
-               clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+               clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                clock-names = "apb_pclk", "atclk";
 
                cpu = <&CPU0>;
                compatible = "arm,coresight-etm4x", "arm,primecell";
                reg = <0x85d000 0x1000>;
 
-               clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+               clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                clock-names = "apb_pclk", "atclk";
 
                cpu = <&CPU1>;
                compatible = "arm,coresight-etm4x", "arm,primecell";
                reg = <0x85e000 0x1000>;
 
-               clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+               clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                clock-names = "apb_pclk", "atclk";
 
                cpu = <&CPU2>;
                compatible = "arm,coresight-etm4x", "arm,primecell";
                reg = <0x85f000 0x1000>;
 
-               clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>;
+               clocks = <&rpmcc RPM_SMD_QDSS_CLK>, <&rpmcc RPM_SMD_QDSS_A_CLK>;
                clock-names = "apb_pclk", "atclk";
 
                cpu = <&CPU3>;
index 42d83fb56f4d69844b42c80a9f46c11dee9560c7..ab39e3a3272a16919da701caa432bc406cf1aca7 100644 (file)
                         reg = <0x0 0x8b600000 0x0 0x0600000>;
                 };
 
+               wcnss_mem: wcnss@89300000 {
+                       reg = <0x0 0x89300000 0x0 0x600000>;
+                       no-map;
+               };
+
                vidc_mem: vidc_region@8f800000 {
                        no-map;
                        reg = <0 0x8f800000 0 0x800000>;
                };
+
+               mba_mem: mba@8ea00000 {
+                       no-map;
+                       reg = <0 0x8ea00000 0 0x100000>;
+               };
        };
 
        cpus {
        firmware {
                compatible = "simple-bus";
 
-               scm {
+               scm: scm {
                        compatible = "qcom,scm";
                        clocks = <&gcc GCC_CRYPTO_CLK> , <&gcc GCC_CRYPTO_AXI_CLK>, <&gcc GCC_CRYPTO_AHB_CLK>;
                        clock-names = "core", "bus", "iface";
+                       #reset-cells = <1>;
                };
        };
 
                        #thermal-sensor-cells = <1>;
                };
 
-               q6-smp2p {
-                       compatible = "qcom,smp2p";
-                       qcom,smem = <435>, <428>;
-                       interrupts = <0 27 1>;
-                       qcom,ipc = <&apcs 8 14>;
-
-                       qcom,local-pid = <0>;
-                       qcom,remote-pid = <1>;
-
-                       q6_smp2p_out: master-kernel {
-                               qcom,entry-name = "master-kernel";
-                               qcom,outbound;
-
-                               gpio-controller;
-                               #gpio-cells = <2>;
-                       };
+               hexagon@4080000 {
+                       compatible = "qcom,pil-q6v56-mss", "qcom,q6v5-pil";
+                       reg = <0x04080000 0x100>,
+                             <0x04020000 0x040>;
 
-                       q6_smp2p_in: slave-kernel {
-                               qcom,entry-name = "slave-kernel";
-                               qcom,inbound;
+                       reg-names = "qdsp6", "rmb";
 
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
-                       };
-               };
+                       interrupts-extended = <&intc 0 24 1>,
+                                             <&hexagon_smp2p_in 0 0>,
+                                             <&hexagon_smp2p_in 1 0>,
+                                             <&hexagon_smp2p_in 2 0>,
+                                             <&hexagon_smp2p_in 3 0>;
+                       interrupt-names = "wdog", "fatal", "ready", "handover", "stop-ack";
 
-               wcnss-smp2p {
-                       compatible = "qcom,smp2p";
-                       qcom,smem = <451>, <431>;
+                       clocks = <&gcc GCC_MSS_CFG_AHB_CLK>, <&gcc GCC_MSS_Q6_BIMC_AXI_CLK>, <&gcc GCC_BOOT_ROM_AHB_CLK>;
+                       clock-names = "iface", "bus", "mem";
 
-                       interrupts = <0 143 1>;
+                       qcom,state = <&hexagon_smp2p_out 0>;
+                       qcom,state-names = "stop";
 
-                       qcom,ipc = <&apcs 8 18>;
+                       resets = <&scm 0>;
+                       reset-names = "mss_restart";
 
-                       qcom,local-pid = <0>;
-                       qcom,remote-pid = <4>;
+                       mx-supply = <&pm8916_l3>;
+                       pll-supply = <&pm8916_l7>;
 
-                       wcnss_smp2p_out: master-kernel {
-                               qcom,entry-name = "master-kernel";
-                               qcom,outbound;
+                       qcom,halt-regs = <&tcsr 0x18000 0x19000 0x1a000>;
 
-                               gpio-controller;
-                               #gpio-cells = <2>;
+                       mba {
+                               memory-region = <&mba_mem>;
                        };
 
-                       wcnss_smp2p_in: slave-kernel {
-                               qcom,entry-name = "slave-kernel";
-                               qcom,inbound;
-
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
+                       mpss {
+                               memory-region = <&modem_adsp_mem>;
                        };
                };
 
-               qcom,mss@4080000 {
-                       compatible = "qcom,pil-q6v56-mss", "qcom,q6v5-pil";
-                       reg = <0x04080000 0x100>,
-                             <0x04020000 0x040>,
-                             <0x01810000 0x004>,
-                             <0x01810000 0x004>,
-                             <0x0194f000 0x010>,
-                             <0x01950000 0x008>,
-                             <0x01951000 0x008>;
-       
-                       reg-names = "qdsp6_base", "rmb_base", "restart_reg_sec",
-                                       "halt_q6", "halt_modem", "halt_nc";
-       
-                       interrupts-extended = <&intc 0 24 1>,
-                                             <&q6_smp2p_in 0 0>,
-                                             <&q6_smp2p_in 1 0>,
-                                             <&q6_smp2p_in 2 0>,
-                                             <&q6_smp2p_in 3 0>;
-                       interrupt-names = "wdog", "fatal", "ready", "handover", "stop-ack";
-       
-                       clocks = <&gcc GCC_MSS_CFG_AHB_CLK>, <&gcc GCC_MSS_Q6_BIMC_AXI_CLK>, <&gcc GCC_BOOT_ROM_AHB_CLK>;
-                       
-                       clock-names = "iface", "bus", "mem";
+               pronto: wcnss@a21b000 {
+                       compatible = "qcom,pronto-v2-pil", "qcom,pronto";
+                       reg = <0x0a204000 0x2000>, <0x0a202000 0x1000>, <0x0a21b000 0x3000>;
+                       reg-names = "ccu", "dxe", "pmu";
 
-                       qcom,mx-supply = <&pm8916_l3>;
-                       qcom,mx-uV = <1050000>;
-                       qcom,pll-supply = <&pm8916_l7>;
-                       qcom,pll-uV = <1800000>;
-                       qcom,proxy-clock-names = "xo";
-                       qcom,active-clock-names = "iface_clk", "bus_clk", "mem_clk";
-                       qcom,is-loadable;
-                       qcom,firmware-name = "modem";
-                       qcom,pil-self-auth;
-                       
-       
-                       /* GPIO inputs from mss */
-                       qcom,gpio-err-fatal = <&q6_smp2p_in 0 0>;
-                       qcom,gpio-err-ready = <&q6_smp2p_in 1 0>;
-                       qcom,gpio-proxy-unvote = <&q6_smp2p_in 2 0>;
-                       qcom,gpio-stop-ack = <&q6_smp2p_in 3 0>;
-                       qcom,gpio-ramdump-disable = <&q6_smp2p_in 15 0>;
-                       /* GPIO output to mss */
-                       qcom,gpio-force-stop = <&q6_smp2p_out 0 0>;
-                       qcom,stop-gpio = <&q6_smp2p_out 0 0>;
-                       memory-region = <&modem_adsp_mem>;
-               };
-
-               pronto_rproc:pronto_rproc {
-                       compatible = "qcom,tz-pil";
+                       memory-region = <&wcnss_mem>;
 
-                       interrupts-extended = <&intc 0 149 1>,
-                                             <&wcnss_smp2p_in 0 0>,
-                                             <&wcnss_smp2p_in 1 0>,
-                                             <&wcnss_smp2p_in 2 0>,
-                                             <&wcnss_smp2p_in 3 0>;
+                       interrupts-extended = <&intc 0 149 IRQ_TYPE_EDGE_RISING>,
+                               <&wcnss_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
+                               <&wcnss_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
+                               <&wcnss_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
+                               <&wcnss_smp2p_in 3 IRQ_TYPE_EDGE_RISING>;
                        interrupt-names = "wdog", "fatal", "ready", "handover", "stop-ack";
 
-                       clocks = <&gcc GCC_CRYPTO_CLK>,
-                                <&gcc GCC_CRYPTO_AHB_CLK>,
-                                <&gcc GCC_CRYPTO_AXI_CLK>,
-                                <&gcc CRYPTO_CLK_SRC>;
-                       clock-names = "scm_core_clk", "scm_iface_clk", "scm_bus_clk", "scm_src_clk";
-
-                       qcom,firmware-name = "wcnss";
-                       qcom,pas-id = <6>;
+                       vddmx-supply = <&pm8916_l3>;
+                       vddpx-supply = <&pm8916_l7>;
 
-                       qcom,crash-reason = <422>;
-                       qcom,smd-edges = <&pronto_smd_edge>;
-
-                       qcom,pll-supply = <&pm8916_l7>;
-                       qcom,pll-uV = <1800000>;
-                       qcom,pll-uA = <18000>;
-
-                       qcom,stop-gpio = <&wcnss_smp2p_out 0 0>;
+                       qcom,state = <&wcnss_smp2p_out 0>;
+                       qcom,state-names = "stop";
 
                        pinctrl-names = "default";
                        pinctrl-0 = <&wcnss_default>;
 
-                       memory-region = <&peripheral_mem>;
-               };
-
-                qcom,wcn36xx@0a000000 {
-                        compatible = "qcom,wcn3620";
-                        reg = <0x0a000000 0x280000>,
-                                <0xb011008 0x04>,
-                                <0x0a21b000 0x3000>,
-                                <0x03204000 0x00000100>,
-                                <0x03200800 0x00000200>,
-                                <0x0A100400 0x00000200>,
-                                <0x0A205050 0x00000200>,
-                                <0x0A219000 0x00000020>,
-                                <0x0A080488 0x00000008>,
-                                <0x0A080fb0 0x00000008>,
-                                <0x0A08040c 0x00000008>,
-                                <0x0A0120a8 0x00000008>,
-                                <0x0A012448 0x00000008>,
-                                <0x0A080c00 0x00000001>;
-
-                        reg-names = "wcnss_mmio", "wcnss_fiq",
-                                    "pronto_phy_base", "riva_phy_base",
-                                    "riva_ccu_base", "pronto_a2xb_base",
-                                    "pronto_ccpu_base", "pronto_saw2_base",
-                                    "wlan_tx_phy_aborts","wlan_brdg_err_source",
-                                    "wlan_tx_status", "alarms_txctl",
-                                    "alarms_tactl", "pronto_mcu_base";
-
-                        interrupts = <0 145 0 0 146 0>;
-                        interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
-
-                        // qcom,pronto-vddmx-supply = <&pm8916_l3>;
-                        // qcom,pronto-vddcx-supply = <&pm8916_s1_corner>;
-                        // qcom,pronto-vddpx-supply = <&pm8916_l7>;
-                        // qcom,iris-vddxo-supply   = <&pm8916_l7>;
-                        // qcom,iris-vddrfa-supply  = <&pm8916_s3>;
-                        // qcom,iris-vddpa-supply   = <&pm8916_l9>;
-                        // qcom,iris-vdddig-supply  = <&pm8916_l5>;
-
-                        pinctrl-names = "wcnss_default";
-                        // pinctrl-names = "wcnss_default", "wcnss_sleep",
-                        //                                "wcnss_gpio_default";
-                        pinctrl-0 = <&wcnss_default>;
-                        // pinctrl-1 = <&wcnss_sleep>;
-                        // pinctrl-2 = <&wcnss_gpio_default>;
-
-                        // clocks = <&rpmcc RPM_XO_CLK_SRC>,
-                        //         <&rpmcc RPM_RF_CLK2>;
-                        //clock-names = "xo", "rf_clk";
-
-                       rproc = <&pronto_rproc>;
-                        qcom,has-autodetect-xo;
-                        qcom,wlan-rx-buff-count = <512>;
-                        qcom,is-pronto-vt;
-                        qcom,has-pronto-hw;
-                        // qcom,wcnss-adc_tm = <&pm8916_adc_tm>;
-                };
+                       iris {
+                               compatible = "qcom,wcn3620";
 
+                               clocks = <&rpmcc RPM_SMD_RF_CLK2>;
+                               clock-names = "xo";
 
+                               vddxo-supply = <&pm8916_l7>;
+                               vddrfa-supply = <&pm8916_s3>;
+                               vddpa-supply = <&pm8916_l9>;
+                               vdddig-supply = <&pm8916_l5>;
+                       };
+               };
 
                qcom,rpm-log@29dc00 {
                        compatible = "qcom,rpm-log";
                                compatible = "qcom,rpm-msm8916";
                                qcom,smd-channels = "rpm_requests";
                                rpmcc: qcom,rpmcc {
-                                       compatible = "qcom,rpmcc-msm8916", "qcom,rpmcc";
+                                       compatible = "qcom,rpmcc-msm8916";
                                        #clock-cells = <1>;
                                };
 
                        };
                };
 
-               pronto_smd_edge: pronto {
+               pronto {
                        interrupts = <0 142 1>;
 
                        qcom,ipc = <&apcs 8 17>;
                        qcom,smd-edge = <6>;
                        qcom,remote-pid = <4>;
 
-                               bt {
-                               compatible = "qcom,hci-smd";
-                               qcom,smd-channels = "APPS_RIVA_BT_CMD", "APPS_RIVA_BT_ACL";
-                               qcom,smd-channel-names = "event", "data";
-                       };
+                       wcnss {
+                               compatible = "qcom,wcnss";
+                               qcom,smd-channels = "WCNSS_CTRL";
 
-                       ipcrtr {
-                               compatible = "qcom,ipcrtr";
-                               qcom,smd-channels = "IPCRTR";
-                       };
+                               qcom,mmio = <&pronto>;
 
-                       wifi {
-                               compatible = "qcom,wlan-ctrl";
-                               qcom,smd-channels = "WLAN_CTRL";
+                               bt {
+                                       compatible = "qcom,wcnss-bt";
+                               };
 
-                               interrupts = <0 145 0>, <0 146 0>;
-                               interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq";
+                               wifi {
+                                       compatible = "qcom,wcnss-wlan";
 
-                               qcom,wcnss_mmio = <0xfb000000 0x21b000>;
+                                       interrupts = <0 145 0>, <0 146 0>;
+                                       interrupt-names = "tx", "rx";
 
-                               // qcom,tx-enable-gpios = <&apps_smsm 10 0>;
-                               // qcom,tx-rings-empty-gpios = <&apps_smsm 9 0>;
+                                       qcom,state = <&apps_smsm 10>, <&apps_smsm 9>;
+                                       qcom,state-names = "tx-enable", "tx-rings-empty";
+                               };
                        };
+               };
+       };
 
-                       wcnss_ctrl {
-                               compatible = "qcom,wcnss-ctrl";
-                               qcom,smd-channels = "WCNSS_CTRL";
+       hexagon-smp2p {
+               compatible = "qcom,smp2p";
+               qcom,smem = <435>, <428>;
 
-                               qcom,wcnss_mmio = <0xfb21b000 0x3000>;
-                       };
+               interrupts = <0 27 IRQ_TYPE_EDGE_RISING>;
+
+               qcom,ipc = <&apcs 8 14>;
+
+               qcom,local-pid = <0>;
+               qcom,remote-pid = <1>;
+
+               hexagon_smp2p_out: master-kernel {
+                       qcom,entry-name = "master-kernel";
+
+                       #qcom,state-cells = <1>;
+               };
+
+               hexagon_smp2p_in: slave-kernel {
+                       qcom,entry-name = "slave-kernel";
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+       };
+
+       wcnss-smp2p {
+               compatible = "qcom,smp2p";
+               qcom,smem = <451>, <431>;
+
+               interrupts = <0 143 IRQ_TYPE_EDGE_RISING>;
+
+               qcom,ipc = <&apcs 8 18>;
+
+               qcom,local-pid = <0>;
+               qcom,remote-pid = <4>;
+
+               wcnss_smp2p_out: master-kernel {
+                       qcom,entry-name = "master-kernel";
+
+                       #qcom,state-cells = <1>;
+               };
+
+               wcnss_smp2p_in: slave-kernel {
+                       qcom,entry-name = "slave-kernel";
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
                };
        };
 
+       smsm {
+               compatible = "qcom,smsm";
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               qcom,ipc-1 = <&apcs 0 13>;
+               qcom,ipc-6 = <&apcs 0 19>;
+
+               apps_smsm: apps@0 {
+                       reg = <0>;
+
+                       #qcom,state-cells = <1>;
+               };
+
+               hexagon_smsm: hexagon@1 {
+                       reg = <1>;
+                       interrupts = <0 26 IRQ_TYPE_EDGE_RISING>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
 
+               wcnss_smsm: wcnss@6 {
+                       reg = <6>;
+                       interrupts = <0 144 IRQ_TYPE_EDGE_RISING>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+               };
+       };
 };
 
 #include "msm8916-pins.dtsi"
index f018cbeab84916005405ed1bd4f2d2161a79a6b2..9f3814df880305bc71dada959270f2bef3c5969c 100644 (file)
@@ -156,8 +156,6 @@ CONFIG_SPMI=y
 CONFIG_PINCTRL_MSM8916=y
 CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
 CONFIG_GPIO_PL061=y
-CONFIG_GPIO_QCOM_SMSM=y
-CONFIG_GPIO_QCOM_SMP2P=y
 CONFIG_GPIO_XGENE=y
 CONFIG_POWER_RESET_MSM=y
 CONFIG_POWER_RESET_XGENE=y
@@ -255,10 +253,14 @@ CONFIG_HWSPINLOCK_QCOM=y
 CONFIG_QCOM_IOMMU_V1=y
 CONFIG_QCOM_Q6V5_PIL=y
 CONFIG_QCOM_TZ_PIL=y
+CONFIG_QCOM_WCNSS_PIL=y
 CONFIG_QCOM_GSBI=y
 CONFIG_QCOM_SMEM=y
 CONFIG_QCOM_SMD=y
 CONFIG_QCOM_SMD_RPM=y
+CONFIG_QCOM_SMP2P=y
+CONFIG_QCOM_SMSM=y
+CONFIG_QCOM_WCNSS_CTRL=y
 CONFIG_MSM_BUS_SCALING=y
 CONFIG_QTI_LNX_GPS_PROXY=y
 CONFIG_BUS_TOPOLOGY_ADHOC=y
index bd2aba113cfcc253be2ca058d4df624f55418d66..ab8951c40fee8859fecce2e887208853ef2643a9 100644 (file)
@@ -172,6 +172,7 @@ config BT_HCIUART_QCA
 config BT_QCOMSMD
        tristate "Qualcomm SMD based HCI support"
        depends on QCOM_SMD
+       select BT_QCA
        help
          Qualcomm SMD based HCI driver.
          This driver is used to bridge HCI data onto the shared memory
index 4b91c830531ea921ba6aab02d0f76e0c1ff5fe94..0cf759b208f28cfaf2b85e74c6fc6533f879c2be 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2016, Linaro Ltd.
  * Copyright (c) 2015, Sony Mobile Communications Inc.
  *
  * This program is free software; you can redistribute it and/or modify
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/soc/qcom/smd.h>
+#include <linux/soc/qcom/wcnss_ctrl.h>
+#include <linux/platform_device.h>
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/hci.h>
-
-#define EDL_NVM_ACCESS_SET_REQ_CMD     0x01
-#define EDL_NVM_ACCESS_OPCODE          0xfc0b
+#include "btqca.h"
 
 struct btqcomsmd {
+       struct hci_dev *hdev;
+
        struct qcom_smd_channel *acl_channel;
        struct qcom_smd_channel *cmd_channel;
 };
 
-static int btqcomsmd_recv(struct hci_dev *hdev,
-                         unsigned type,
-                         const void *data,
+static int btqcomsmd_recv(struct hci_dev *hdev, unsigned type, const void *data,
                          size_t count)
 {
        struct sk_buff *skb;
-       void *buf;
 
        /* Use GFP_ATOMIC as we're in IRQ context */
        skb = bt_skb_alloc(count, GFP_ATOMIC);
-       if (!skb)
+       if (!skb) {
+               hdev->stat.err_rx++;
                return -ENOMEM;
+       }
 
        bt_cb(skb)->pkt_type = type;
-
-       /* Use io accessor as data might be ioremapped */
-       buf = skb_put(skb, count);
-       memcpy_fromio(buf, data, count);
+       memcpy(skb_put(skb, count), data, count);
 
        return hci_recv_frame(hdev, skb);
 }
 
-static int btqcomsmd_acl_callback(struct qcom_smd_device *qsdev,
+static int btqcomsmd_acl_callback(struct qcom_smd_channel *channel,
                                  const void *data,
                                  size_t count)
 {
-       struct hci_dev *hdev = dev_get_drvdata(&qsdev->dev);
+       struct btqcomsmd *btq = qcom_smd_get_drvdata(channel);
 
-       return btqcomsmd_recv(hdev, HCI_ACLDATA_PKT, data, count);
+       btq->hdev->stat.byte_rx += count;
+       return btqcomsmd_recv(btq->hdev, HCI_ACLDATA_PKT, data, count);
 }
 
-static int btqcomsmd_cmd_callback(struct qcom_smd_device *qsdev,
+static int btqcomsmd_cmd_callback(struct qcom_smd_channel *channel,
                                  const void *data,
                                  size_t count)
 {
-       struct hci_dev *hdev = dev_get_drvdata(&qsdev->dev);
+       struct btqcomsmd *btq = qcom_smd_get_drvdata(channel);
 
-       return btqcomsmd_recv(hdev, HCI_EVENT_PKT, data, count);
+       return btqcomsmd_recv(btq->hdev, HCI_EVENT_PKT, data, count);
 }
 
 static int btqcomsmd_send(struct hci_dev *hdev, struct sk_buff *skb)
@@ -73,14 +73,16 @@ static int btqcomsmd_send(struct hci_dev *hdev, struct sk_buff *skb)
 
        switch (bt_cb(skb)->pkt_type) {
        case HCI_ACLDATA_PKT:
-       case HCI_SCODATA_PKT:
                ret = qcom_smd_send(btq->acl_channel, skb->data, skb->len);
+               hdev->stat.acl_tx++;
+               hdev->stat.byte_tx += skb->len;
                break;
        case HCI_COMMAND_PKT:
                ret = qcom_smd_send(btq->cmd_channel, skb->data, skb->len);
+               hdev->stat.cmd_tx++;
                break;
        default:
-               ret = -ENODEV;
+               ret = -EILSEQ;
                break;
        }
 
@@ -89,72 +91,53 @@ static int btqcomsmd_send(struct hci_dev *hdev, struct sk_buff *skb)
 
 static int btqcomsmd_open(struct hci_dev *hdev)
 {
-       set_bit(HCI_RUNNING, &hdev->flags);
        return 0;
 }
 
 static int btqcomsmd_close(struct hci_dev *hdev)
 {
-       clear_bit(HCI_RUNNING, &hdev->flags);
-       return 0;
-}
-
-static int btqcomsmd_set_bdaddr(struct hci_dev *hdev,
-                             const bdaddr_t *bdaddr)
-{
-       struct sk_buff *skb;
-       u8 cmd[9];
-       int err;
-
-       cmd[0] = EDL_NVM_ACCESS_SET_REQ_CMD;
-       cmd[1] = 0x02;                  /* TAG ID */
-       cmd[2] = sizeof(bdaddr_t);      /* size */
-       memcpy(cmd + 3, bdaddr, sizeof(bdaddr_t));
-       skb = __hci_cmd_sync_ev(hdev,
-                               EDL_NVM_ACCESS_OPCODE,
-                               sizeof(cmd), cmd,
-                               HCI_VENDOR_PKT, HCI_INIT_TIMEOUT);
-       if (IS_ERR(skb)) {
-               err = PTR_ERR(skb);
-               BT_ERR("%s: Change address command failed (%d)",
-                      hdev->name, err);
-               return err;
-       }
-
-       kfree_skb(skb);
-
        return 0;
 }
 
-static int btqcomsmd_probe(struct qcom_smd_device *sdev)
+static int btqcomsmd_probe(struct platform_device *pdev)
 {
-       struct qcom_smd_channel *acl;
        struct btqcomsmd *btq;
        struct hci_dev *hdev;
+       void *wcnss;
        int ret;
 
-       acl = qcom_smd_open_channel(sdev,
-                                   "APPS_RIVA_BT_ACL",
-                                   btqcomsmd_acl_callback);
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
-
-       btq = devm_kzalloc(&sdev->dev, sizeof(*btq), GFP_KERNEL);
+       btq = devm_kzalloc(&pdev->dev, sizeof(*btq), GFP_KERNEL);
        if (!btq)
                return -ENOMEM;
 
-       btq->acl_channel = acl;
-       btq->cmd_channel = sdev->channel;
+       wcnss = dev_get_drvdata(pdev->dev.parent);
+
+       btq->acl_channel = qcom_wcnss_open_channel(wcnss, "APPS_RIVA_BT_ACL",
+                                                  btqcomsmd_acl_callback);
+       if (IS_ERR(btq->acl_channel))
+               return PTR_ERR(btq->acl_channel);
+
+       btq->cmd_channel = qcom_wcnss_open_channel(wcnss, "APPS_RIVA_BT_CMD",
+                                                  btqcomsmd_cmd_callback);
+       if (IS_ERR(btq->cmd_channel))
+               return PTR_ERR(btq->cmd_channel);
+
+       qcom_smd_set_drvdata(btq->acl_channel, btq);
+       qcom_smd_set_drvdata(btq->cmd_channel, btq);
 
        hdev = hci_alloc_dev();
        if (!hdev)
                return -ENOMEM;
 
+       hci_set_drvdata(hdev, btq);
+       btq->hdev = hdev;
+       SET_HCIDEV_DEV(hdev, &pdev->dev);
+
        hdev->bus = HCI_SMD;
        hdev->open = btqcomsmd_open;
        hdev->close = btqcomsmd_close;
        hdev->send = btqcomsmd_send;
-       hdev->set_bdaddr = btqcomsmd_set_bdaddr;
+       hdev->set_bdaddr = qca_set_bdaddr_rome;
 
        ret = hci_register_dev(hdev);
        if (ret < 0) {
@@ -162,37 +145,37 @@ static int btqcomsmd_probe(struct qcom_smd_device *sdev)
                return ret;
        }
 
-       hci_set_drvdata(hdev, btq);
-       dev_set_drvdata(&sdev->dev, hdev);
+       platform_set_drvdata(pdev, btq);
 
        return 0;
 }
 
-static void btqcomsmd_remove(struct qcom_smd_device *sdev)
+static int btqcomsmd_remove(struct platform_device *pdev)
 {
-       struct hci_dev *hdev = dev_get_drvdata(&sdev->dev);;
+       struct btqcomsmd *btq = platform_get_drvdata(pdev);
 
-       hci_unregister_dev(hdev);
-       hci_free_dev(hdev);
+       hci_unregister_dev(btq->hdev);
+       hci_free_dev(btq->hdev);
+
+       return 0;
 }
 
-static const struct qcom_smd_id btqcomsmd_match[] = {
-       { .name = "APPS_RIVA_BT_CMD" },
-       {}
+static const struct of_device_id btqcomsmd_of_match[] = {
+       { .compatible = "qcom,wcnss-bt", },
+       { },
 };
 
-static struct qcom_smd_driver btqcomsmd_cmd_driver = {
+static struct platform_driver btqcomsmd_driver = {
        .probe = btqcomsmd_probe,
        .remove = btqcomsmd_remove,
-       .callback = btqcomsmd_cmd_callback,
-       .smd_match_table = btqcomsmd_match,
        .driver  = {
                .name  = "btqcomsmd",
-               .owner = THIS_MODULE,
+               .of_match_table = btqcomsmd_of_match,
        },
 };
 
-module_qcom_smd_driver(btqcomsmd_cmd_driver);
+module_platform_driver(btqcomsmd_driver);
 
+MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@sonymobile.com>");
 MODULE_DESCRIPTION("Qualcomm SMD HCI driver");
 MODULE_LICENSE("GPL v2");
index 9e850a5392d1ac46001215aad8cd232e5f0a5bfc..12fea623c189da6b8c9881c2c889bf39439960e1 100644 (file)
@@ -12,21 +12,31 @@ config COMMON_CLK_QCOM
        select REGMAP_MMIO
        select RESET_CONTROLLER
 
-config QCOM_CLK_SMD_RPM
-       tristate "RPM over SMD based Clock Controller"
-       depends on COMMON_CLK_QCOM && QCOM_SMD_RPM
-       select QCOM_RPMCC
-       help
-         Support for the clocks exposed by the Resource Power Manager
-         processor on devices like apq8016, apq8084 and msm8974.
-
 config QCOM_CLK_RPM
        tristate "RPM based Clock Controller"
        depends on COMMON_CLK_QCOM && MFD_QCOM_RPM
        select QCOM_RPMCC
        help
-         Support for the clocks exposed by the Resource Power Manager
-         processor on devices like apq8064.
+         The RPM (Resource Power Manager) is a dedicated hardware engine for
+         managing the shared SoC resources in order to keep the lowest power
+         profile. It communicates with other hardware subsystems via shared
+         memory and accepts clock requests, aggregates the requests and turns
+         the clocks on/off or scales them on demand.
+         Say Y if you want to support the clocks exposed by the RPM on
+         platforms such as apq8064, msm8660, msm8960 etc.
+
+config QCOM_CLK_SMD_RPM
+       tristate "RPM over SMD based Clock Controller"
+       depends on COMMON_CLK_QCOM && QCOM_SMD_RPM
+       select QCOM_RPMCC
+       help
+         The RPM (Resource Power Manager) is a dedicated hardware engine for
+         managing the shared SoC resources in order to keep the lowest power
+         profile. It communicates with other hardware subsystems via shared
+         memory and accepts clock requests, aggregates the requests and turns
+         the clocks on/off or scales them on demand.
+         Say Y if you want to support the clocks exposed by the RPM on
+         platforms such as apq8016, apq8084, msm8974 etc.
 
 config APQ_GCC_8084
        tristate "APQ8084 Global Clock Controller"
index 400007b13f27819a42981b881e5d3eadf2647857..93e127bca238936ef99ce55b253bcca350aa05cd 100644 (file)
@@ -12,8 +12,6 @@ clk-qcom-y += clk-regmap-mux-div.o
 clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-krait.o
 clk-qcom-y += clk-hfpll.o
 clk-qcom-y += reset.o
-clk-qcom-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
-clk-qcom-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
 clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
 
 obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
@@ -31,3 +29,6 @@ obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o
 obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
 obj-$(CONFIG_KRAITCC) += krait-cc.o
 obj-$(CONFIG_QCOM_A53) += clk-a53.o
+obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o
+obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
+obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
index 416aa68339d82fe23ed54365dc00e0f2a9a0eb91..05cf83c2ca833c492f52b9a721840dd2521279a7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Linaro Limited
+ * Copyright (c) 2016, Linaro Limited
  * Copyright (c) 2014, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
@@ -12,7 +12,6 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/err.h>
 #include <linux/export.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 
-#include "clk-rpm.h"
 #include <dt-bindings/mfd/qcom-rpm.h>
+#include <dt-bindings/clock/qcom,rpmcc.h>
+
+#define QCOM_RPM_MISC_CLK_TYPE                         0x306b6c63
+#define QCOM_RPM_SCALING_ENABLE_ID                     0x2
+
+#define DEFINE_CLK_RPM(_platform, _name, _active, r_id)                              \
+       static struct clk_rpm _platform##_##_active;                          \
+       static struct clk_rpm _platform##_##_name = {                         \
+               .rpm_clk_id = (r_id),                                         \
+               .peer = &_platform##_##_active,                               \
+               .rate = INT_MAX,                                              \
+               .hw.init = &(struct clk_init_data){                           \
+                       .ops = &clk_rpm_ops,                                  \
+                       .name = #_name,                                       \
+                       .parent_names = (const char *[]){ "pxo_board" },      \
+                       .num_parents = 1,                                     \
+               },                                                            \
+       };                                                                    \
+       static struct clk_rpm _platform##_##_active = {                       \
+               .rpm_clk_id = (r_id),                                         \
+               .peer = &_platform##_##_name,                                 \
+               .active_only = true,                                          \
+               .rate = INT_MAX,                                              \
+               .hw.init = &(struct clk_init_data){                           \
+                       .ops = &clk_rpm_ops,                                  \
+                       .name = #_active,                                     \
+                       .parent_names = (const char *[]){ "pxo_board" },      \
+                       .num_parents = 1,                                     \
+               },                                                            \
+       }
+
+#define DEFINE_CLK_RPM_PXO_BRANCH(_platform, _name, _active, r_id, r)        \
+       static struct clk_rpm _platform##_##_active;                          \
+       static struct clk_rpm _platform##_##_name = {                         \
+               .rpm_clk_id = (r_id),                                         \
+               .active_only = true,                                          \
+               .peer = &_platform##_##_active,                               \
+               .rate = (r),                                                  \
+               .branch = true,                                               \
+               .hw.init = &(struct clk_init_data){                           \
+                       .ops = &clk_rpm_branch_ops,                           \
+                       .name = #_name,                                       \
+                       .parent_names = (const char *[]){ "pxo_board" },      \
+                       .num_parents = 1,                                     \
+               },                                                            \
+       };                                                                    \
+       static struct clk_rpm _platform##_##_active = {                       \
+               .rpm_clk_id = (r_id),                                         \
+               .peer = &_platform##_##_name,                                 \
+               .rate = (r),                                                  \
+               .branch = true,                                               \
+               .hw.init = &(struct clk_init_data){                           \
+                       .ops = &clk_rpm_branch_ops,                           \
+                       .name = #_active,                                     \
+                       .parent_names = (const char *[]){ "pxo_board" },      \
+                       .num_parents = 1,                                     \
+               },                                                            \
+       }
+
+#define DEFINE_CLK_RPM_CXO_BRANCH(_platform, _name, _active, r_id, r)        \
+       static struct clk_rpm _platform##_##_active;                          \
+       static struct clk_rpm _platform##_##_name = {                         \
+               .rpm_clk_id = (r_id),                                         \
+               .peer = &_platform##_##_active,                               \
+               .rate = (r),                                                  \
+               .branch = true,                                               \
+               .hw.init = &(struct clk_init_data){                           \
+                       .ops = &clk_rpm_branch_ops,                           \
+                       .name = #_name,                                       \
+                       .parent_names = (const char *[]){ "cxo_board" },      \
+                       .num_parents = 1,                                     \
+               },                                                            \
+       };                                                                    \
+       static struct clk_rpm _platform##_##_active = {                       \
+               .rpm_clk_id = (r_id),                                         \
+               .active_only = true,                                          \
+               .peer = &_platform##_##_name,                                 \
+               .rate = (r),                                                  \
+               .branch = true,                                               \
+               .hw.init = &(struct clk_init_data){                           \
+                       .ops = &clk_rpm_branch_ops,                           \
+                       .name = #_active,                                     \
+                       .parent_names = (const char *[]){ "cxo_board" },      \
+                       .num_parents = 1,                                     \
+               },                                                            \
+       }
 
 #define to_clk_rpm(_hw) container_of(_hw, struct clk_rpm, hw)
 
+struct clk_rpm {
+       const int rpm_clk_id;
+       const bool active_only;
+       unsigned long rate;
+       bool enabled;
+       bool branch;
+       struct clk_rpm *peer;
+       struct clk_hw hw;
+       struct qcom_rpm *rpm;
+};
+
+struct rpm_cc {
+       struct qcom_rpm *rpm;
+       struct clk_onecell_data data;
+       struct clk *clks[];
+};
+
+struct rpm_clk_desc {
+       struct clk_rpm **clks;
+       size_t num_clks;
+};
+
 static DEFINE_MUTEX(rpm_clk_lock);
 
+static int clk_rpm_handoff(struct clk_rpm *r)
+{
+       int ret;
+       u32 value = INT_MAX;
+
+       ret = qcom_rpm_write(r->rpm, QCOM_RPM_ACTIVE_STATE,
+                            r->rpm_clk_id, &value, 1);
+       if (ret)
+               return ret;
+       ret = qcom_rpm_write(r->rpm, QCOM_RPM_SLEEP_STATE,
+                            r->rpm_clk_id, &value, 1);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
 static int clk_rpm_set_rate_active(struct clk_rpm *r, unsigned long rate)
 {
        u32 value = DIV_ROUND_UP(rate, 1000); /* to kHz */
@@ -40,25 +163,69 @@ static int clk_rpm_set_rate_active(struct clk_rpm *r, unsigned long rate)
                              r->rpm_clk_id, &value, 1);
 }
 
+static int clk_rpm_set_rate_sleep(struct clk_rpm *r, unsigned long rate)
+{
+       u32 value = DIV_ROUND_UP(rate, 1000); /* to kHz */
+
+       return qcom_rpm_write(r->rpm, QCOM_RPM_SLEEP_STATE,
+                             r->rpm_clk_id, &value, 1);
+}
+
+static void to_active_sleep(struct clk_rpm *r, unsigned long rate,
+                           unsigned long *active, unsigned long *sleep)
+{
+       *active = rate;
+
+       /*
+        * Active-only clocks don't care what the rate is during sleep. So,
+        * they vote for zero.
+        */
+       if (r->active_only)
+               *sleep = 0;
+       else
+               *sleep = *active;
+}
+
 static int clk_rpm_prepare(struct clk_hw *hw)
 {
        struct clk_rpm *r = to_clk_rpm(hw);
-       unsigned long rate = r->rate;
+       struct clk_rpm *peer = r->peer;
+       unsigned long this_rate = 0, this_sleep_rate = 0;
+       unsigned long peer_rate = 0, peer_sleep_rate = 0;
+       unsigned long active_rate, sleep_rate;
        int ret = 0;
 
        mutex_lock(&rpm_clk_lock);
 
-       if (!rate)
+       /* Don't send requests to the RPM if the rate has not been set. */
+       if (!r->rate)
                goto out;
 
-       if (r->branch)
-               rate = !!rate;
+       to_active_sleep(r, r->rate, &this_rate, &this_sleep_rate);
+
+       /* Take peer clock's rate into account only if it's enabled. */
+       if (peer->enabled)
+               to_active_sleep(peer, peer->rate,
+                               &peer_rate, &peer_sleep_rate);
 
-       ret = clk_rpm_set_rate_active(r, rate);
+       active_rate = max(this_rate, peer_rate);
+
+       if (r->branch)
+               active_rate = !!active_rate;
 
+       ret = clk_rpm_set_rate_active(r, active_rate);
        if (ret)
                goto out;
 
+       sleep_rate = max(this_sleep_rate, peer_sleep_rate);
+       if (r->branch)
+               sleep_rate = !!sleep_rate;
+
+       ret = clk_rpm_set_rate_sleep(r, sleep_rate);
+       if (ret)
+               /* Undo the active set vote and restore it */
+               ret = clk_rpm_set_rate_active(r, peer_rate);
+
 out:
        if (!ret)
                r->enabled = true;
@@ -71,6 +238,9 @@ out:
 static void clk_rpm_unprepare(struct clk_hw *hw)
 {
        struct clk_rpm *r = to_clk_rpm(hw);
+       struct clk_rpm *peer = r->peer;
+       unsigned long peer_rate = 0, peer_sleep_rate = 0;
+       unsigned long active_rate, sleep_rate;
        int ret;
 
        mutex_lock(&rpm_clk_lock);
@@ -78,7 +248,18 @@ static void clk_rpm_unprepare(struct clk_hw *hw)
        if (!r->rate)
                goto out;
 
-       ret = clk_rpm_set_rate_active(r, r->rate);
+       /* Take peer clock's rate into account only if it's enabled. */
+       if (peer->enabled)
+               to_active_sleep(peer, peer->rate, &peer_rate,
+                               &peer_sleep_rate);
+
+       active_rate = r->branch ? !!peer_rate : peer_rate;
+       ret = clk_rpm_set_rate_active(r, active_rate);
+       if (ret)
+               goto out;
+
+       sleep_rate = r->branch ? !!peer_sleep_rate : peer_sleep_rate;
+       ret = clk_rpm_set_rate_sleep(r, sleep_rate);
        if (ret)
                goto out;
 
@@ -89,23 +270,45 @@ out:
 }
 
 static int clk_rpm_set_rate(struct clk_hw *hw,
-                    unsigned long rate, unsigned long parent_rate)
+                           unsigned long rate, unsigned long parent_rate)
 {
        struct clk_rpm *r = to_clk_rpm(hw);
+       struct clk_rpm *peer = r->peer;
+       unsigned long active_rate, sleep_rate;
+       unsigned long this_rate = 0, this_sleep_rate = 0;
+       unsigned long peer_rate = 0, peer_sleep_rate = 0;
        int ret = 0;
 
        mutex_lock(&rpm_clk_lock);
 
-       if (r->enabled)
-               ret = clk_rpm_set_rate_active(r, rate);
+       if (!r->enabled)
+               goto out;
+
+       to_active_sleep(r, rate, &this_rate, &this_sleep_rate);
 
-       if (!ret)
-               r->rate = rate;
+       /* Take peer clock's rate into account only if it's enabled. */
+       if (peer->enabled)
+               to_active_sleep(peer, peer->rate,
+                               &peer_rate, &peer_sleep_rate);
 
+       active_rate = max(this_rate, peer_rate);
+       ret = clk_rpm_set_rate_active(r, active_rate);
+       if (ret)
+               goto out;
+
+       sleep_rate = max(this_sleep_rate, peer_sleep_rate);
+       ret = clk_rpm_set_rate_sleep(r, sleep_rate);
+       if (ret)
+               goto out;
+
+       r->rate = rate;
+
+out:
        mutex_unlock(&rpm_clk_lock);
 
        return ret;
 }
+
 static long clk_rpm_round_rate(struct clk_hw *hw, unsigned long rate,
                               unsigned long *parent_rate)
 {
@@ -130,59 +333,57 @@ static unsigned long clk_rpm_recalc_rate(struct clk_hw *hw,
        return r->rate;
 }
 
-const struct clk_ops clk_rpm_ops = {
+static const struct clk_ops clk_rpm_ops = {
        .prepare        = clk_rpm_prepare,
        .unprepare      = clk_rpm_unprepare,
        .set_rate       = clk_rpm_set_rate,
        .round_rate     = clk_rpm_round_rate,
        .recalc_rate    = clk_rpm_recalc_rate,
 };
-EXPORT_SYMBOL_GPL(clk_rpm_ops);
 
-const struct clk_ops clk_rpm_branch_ops = {
+static const struct clk_ops clk_rpm_branch_ops = {
        .prepare        = clk_rpm_prepare,
        .unprepare      = clk_rpm_unprepare,
        .round_rate     = clk_rpm_round_rate,
        .recalc_rate    = clk_rpm_recalc_rate,
 };
-EXPORT_SYMBOL_GPL(clk_rpm_branch_ops);
-
-struct rpm_cc {
-       struct qcom_rpm *rpm;
-       struct clk_onecell_data data;
-       struct clk *clks[];
-};
-
-struct rpm_clk_desc {
-       struct clk_rpm **clks;
-       size_t num_clks;
-};
 
 /* apq8064 */
-DEFINE_CLK_RPM_PXO_BRANCH(apq8064, pxo, QCOM_RPM_PXO_CLK, 27000000);
-DEFINE_CLK_RPM_CXO_BRANCH(apq8064, cxo, QCOM_RPM_CXO_CLK, 19200000);
-DEFINE_CLK_RPM(apq8064, afab_clk, QCOM_RPM_APPS_FABRIC_CLK);
-DEFINE_CLK_RPM(apq8064, cfpb_clk, QCOM_RPM_CFPB_CLK);
-DEFINE_CLK_RPM(apq8064, daytona_clk, QCOM_RPM_DAYTONA_FABRIC_CLK);
-DEFINE_CLK_RPM(apq8064, ebi1_clk, QCOM_RPM_EBI1_CLK);
-DEFINE_CLK_RPM(apq8064, mmfab_clk, QCOM_RPM_MM_FABRIC_CLK);
-DEFINE_CLK_RPM(apq8064, mmfpb_clk, QCOM_RPM_MMFPB_CLK);
-DEFINE_CLK_RPM(apq8064, sfab_clk, QCOM_RPM_SYS_FABRIC_CLK);
-DEFINE_CLK_RPM(apq8064, sfpb_clk, QCOM_RPM_SFPB_CLK);
-DEFINE_CLK_RPM(apq8064, qdss_clk, QCOM_RPM_QDSS_CLK);
+DEFINE_CLK_RPM_PXO_BRANCH(apq8064, pxo, pxo_a_clk, QCOM_RPM_PXO_CLK, 27000000);
+DEFINE_CLK_RPM_CXO_BRANCH(apq8064, cxo, cxo_a_clk, QCOM_RPM_CXO_CLK, 19200000);
+DEFINE_CLK_RPM(apq8064, afab_clk, afab_a_clk, QCOM_RPM_APPS_FABRIC_CLK);
+DEFINE_CLK_RPM(apq8064, cfpb_clk, cfpb_a_clk, QCOM_RPM_CFPB_CLK);
+DEFINE_CLK_RPM(apq8064, daytona_clk, daytona_a_clk, QCOM_RPM_DAYTONA_FABRIC_CLK);
+DEFINE_CLK_RPM(apq8064, ebi1_clk, ebi1_a_clk, QCOM_RPM_EBI1_CLK);
+DEFINE_CLK_RPM(apq8064, mmfab_clk, mmfab_a_clk, QCOM_RPM_MM_FABRIC_CLK);
+DEFINE_CLK_RPM(apq8064, mmfpb_clk, mmfpb_a_clk, QCOM_RPM_MMFPB_CLK);
+DEFINE_CLK_RPM(apq8064, sfab_clk, sfab_a_clk, QCOM_RPM_SYS_FABRIC_CLK);
+DEFINE_CLK_RPM(apq8064, sfpb_clk, sfpb_a_clk, QCOM_RPM_SFPB_CLK);
+DEFINE_CLK_RPM(apq8064, qdss_clk, qdss_a_clk, QCOM_RPM_QDSS_CLK);
 
 static struct clk_rpm *apq8064_clks[] = {
-       [QCOM_RPM_PXO_CLK] = &apq8064_pxo,
-       [QCOM_RPM_CXO_CLK] = &apq8064_cxo,
-       [QCOM_RPM_APPS_FABRIC_CLK] = &apq8064_afab_clk,
-       [QCOM_RPM_CFPB_CLK] = &apq8064_cfpb_clk,
-       [QCOM_RPM_DAYTONA_FABRIC_CLK] = &apq8064_daytona_clk,
-       [QCOM_RPM_EBI1_CLK] = &apq8064_ebi1_clk,
-       [QCOM_RPM_MM_FABRIC_CLK] = &apq8064_mmfab_clk,
-       [QCOM_RPM_MMFPB_CLK] = &apq8064_mmfpb_clk,
-       [QCOM_RPM_SYS_FABRIC_CLK] = &apq8064_sfab_clk,
-       [QCOM_RPM_SFPB_CLK] = &apq8064_sfpb_clk,
-       [QCOM_RPM_QDSS_CLK] = &apq8064_qdss_clk,
+       [RPM_PXO_CLK] = &apq8064_pxo,
+       [RPM_PXO_A_CLK] = &apq8064_pxo_a_clk,
+       [RPM_CXO_CLK] = &apq8064_cxo,
+       [RPM_CXO_A_CLK] = &apq8064_cxo_a_clk,
+       [RPM_APPS_FABRIC_CLK] = &apq8064_afab_clk,
+       [RPM_APPS_FABRIC_A_CLK] = &apq8064_afab_a_clk,
+       [RPM_CFPB_CLK] = &apq8064_cfpb_clk,
+       [RPM_CFPB_A_CLK] = &apq8064_cfpb_a_clk,
+       [RPM_DAYTONA_FABRIC_CLK] = &apq8064_daytona_clk,
+       [RPM_DAYTONA_FABRIC_A_CLK] = &apq8064_daytona_a_clk,
+       [RPM_EBI1_CLK] = &apq8064_ebi1_clk,
+       [RPM_EBI1_A_CLK] = &apq8064_ebi1_a_clk,
+       [RPM_MM_FABRIC_CLK] = &apq8064_mmfab_clk,
+       [RPM_MM_FABRIC_A_CLK] = &apq8064_mmfab_a_clk,
+       [RPM_MMFPB_CLK] = &apq8064_mmfpb_clk,
+       [RPM_MMFPB_A_CLK] = &apq8064_mmfpb_a_clk,
+       [RPM_SYS_FABRIC_CLK] = &apq8064_sfab_clk,
+       [RPM_SYS_FABRIC_A_CLK] = &apq8064_sfab_a_clk,
+       [RPM_SFPB_CLK] = &apq8064_sfpb_clk,
+       [RPM_SFPB_A_CLK] = &apq8064_sfpb_a_clk,
+       [RPM_QDSS_CLK] = &apq8064_qdss_clk,
+       [RPM_QDSS_A_CLK] = &apq8064_qdss_a_clk,
 };
 
 static const struct rpm_clk_desc rpm_clk_apq8064 = {
@@ -202,10 +403,10 @@ static int rpm_clk_probe(struct platform_device *pdev)
        struct clk *clk;
        struct rpm_cc *rcc;
        struct clk_onecell_data *data;
-       int ret, i;
-       size_t num_clks;
+       int ret;
+       size_t num_clks, i;
        struct qcom_rpm *rpm;
-       struct clk_rpm  **rpm_clks;
+       struct clk_rpm **rpm_clks;
        const struct rpm_clk_desc *desc;
 
        rpm = dev_get_drvdata(pdev->dev.parent);
@@ -238,6 +439,18 @@ static int rpm_clk_probe(struct platform_device *pdev)
                }
 
                rpm_clks[i]->rpm = rpm;
+
+               ret = clk_rpm_handoff(rpm_clks[i]);
+               if (ret)
+                       goto err;
+       }
+
+       for (i = 0; i < num_clks; i++) {
+               if (!rpm_clks[i]) {
+                       clks[i] = ERR_PTR(-ENOENT);
+                       continue;
+               }
+
                clk = devm_clk_register(&pdev->dev, &rpm_clks[i]->hw);
                if (IS_ERR(clk)) {
                        ret = PTR_ERR(clk);
@@ -252,10 +465,7 @@ static int rpm_clk_probe(struct platform_device *pdev)
        if (ret)
                goto err;
 
-       clk_prepare_enable(apq8064_afab_clk.hw.clk);
-
        return 0;
-
 err:
        dev_err(&pdev->dev, "Error registering RPM Clock driver (%d)\n", ret);
        return ret;
diff --git a/drivers/clk/qcom/clk-rpm.h b/drivers/clk/qcom/clk-rpm.h
deleted file mode 100644 (file)
index c0ac30f..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2015, Linaro Limited
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef __QCOM_CLK_RPM_H__
-#define __QCOM_CLK_RPM_H__
-
-#include <linux/clk-provider.h>
-
-struct qcom_rpm;
-
-struct clk_rpm {
-       const int rpm_clk_id;
-       unsigned long rate;
-       bool enabled;
-       bool branch;
-       struct clk_hw hw;
-       struct qcom_rpm *rpm;
-};
-
-extern const struct clk_ops clk_rpm_ops;
-extern const struct clk_ops clk_rpm_branch_ops;
-
-#define DEFINE_CLK_RPM(_platform, _name, r_id)                              \
-       static struct clk_rpm _platform##_##_name = {                        \
-               .rpm_clk_id = (r_id),                                        \
-               .rate = INT_MAX,                                             \
-               .hw.init = &(struct clk_init_data){                          \
-                       .name = #_name,                                      \
-                       .parent_names = (const char *[]){ "pxo_board" },     \
-                       .num_parents = 1,                                    \
-                       .ops = &clk_rpm_ops,                                 \
-               },                                                           \
-       }
-
-#define DEFINE_CLK_RPM_PXO_BRANCH(_platform, _name, r_id, r)                \
-       static struct clk_rpm _platform##_##_name = {                        \
-               .rpm_clk_id = (r_id),                                        \
-               .branch = true,                                              \
-               .rate = (r),                                                 \
-               .hw.init = &(struct clk_init_data){                          \
-                       .name = #_name,                                      \
-                       .parent_names = (const char *[]){ "pxo_board" },     \
-                       .num_parents = 1,                                    \
-                       .ops = &clk_rpm_branch_ops,                          \
-               },                                                           \
-       }
-
-#define DEFINE_CLK_RPM_CXO_BRANCH(_platform, _name, r_id, r)                \
-       static struct clk_rpm _platform##_##_name = {                        \
-               .rpm_clk_id = (r_id),                                        \
-               .branch = true,                                              \
-               .rate = (r),                                                 \
-               .hw.init = &(struct clk_init_data){                          \
-                       .name = #_name,                                      \
-                       .parent_names = (const char *[]){ "cxo_board" },     \
-                       .num_parents = 1,                                    \
-                       .ops = &clk_rpm_branch_ops,                          \
-               },                                                           \
-       }
-#endif
index 749798207bb81f5825467cc29a558b8c59996657..adfb58f5135161835d4fcb23dfc701f144007e40 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Linaro Limited
+ * Copyright (c) 2016, Linaro Limited
  * Copyright (c) 2014, The Linux Foundation. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
 #include <linux/platform_device.h>
 #include <linux/soc/qcom/smd-rpm.h>
 
-#include "clk-smd-rpm.h"
 #include <dt-bindings/clock/qcom,rpmcc.h>
+#include <dt-bindings/mfd/qcom-rpm.h>
+
+#define QCOM_RPM_KEY_SOFTWARE_ENABLE                   0x6e657773
+#define QCOM_RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY    0x62636370
+#define QCOM_RPM_SMD_KEY_RATE                          0x007a484b
+#define QCOM_RPM_SMD_KEY_ENABLE                                0x62616e45
+#define QCOM_RPM_SMD_KEY_STATE                         0x54415453
+#define QCOM_RPM_SCALING_ENABLE_ID                     0x2
+
+#define __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id, stat_id,  \
+                            key)                                             \
+       static struct clk_smd_rpm _platform##_##_active;                      \
+       static struct clk_smd_rpm _platform##_##_name = {                     \
+               .rpm_res_type = (type),                                       \
+               .rpm_clk_id = (r_id),                                         \
+               .rpm_status_id = (stat_id),                                   \
+               .rpm_key = (key),                                             \
+               .peer = &_platform##_##_active,                               \
+               .rate = INT_MAX,                                              \
+               .hw.init = &(struct clk_init_data){                           \
+                       .ops = &clk_smd_rpm_ops,                              \
+                       .name = #_name,                                       \
+                       .parent_names = (const char *[]){ "xo_board" },       \
+                       .num_parents = 1,                                     \
+               },                                                            \
+       };                                                                    \
+       static struct clk_smd_rpm _platform##_##_active = {                   \
+               .rpm_res_type = (type),                                       \
+               .rpm_clk_id = (r_id),                                         \
+               .rpm_status_id = (stat_id),                                   \
+               .active_only = true,                                          \
+               .rpm_key = (key),                                             \
+               .peer = &_platform##_##_name,                                 \
+               .rate = INT_MAX,                                              \
+               .hw.init = &(struct clk_init_data){                           \
+                       .ops = &clk_smd_rpm_ops,                              \
+                       .name = #_active,                                     \
+                       .parent_names = (const char *[]){ "xo_board" },       \
+                       .num_parents = 1,                                     \
+               },                                                            \
+       }
+
+#define __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type, r_id,    \
+                                   stat_id, r, key)                          \
+       static struct clk_smd_rpm _platform##_##_active;                      \
+       static struct clk_smd_rpm _platform##_##_name = {                     \
+               .rpm_res_type = (type),                                       \
+               .rpm_clk_id = (r_id),                                         \
+               .rpm_status_id = (stat_id),                                   \
+               .rpm_key = (key),                                             \
+               .branch = true,                                               \
+               .peer = &_platform##_##_active,                               \
+               .rate = (r),                                                  \
+               .hw.init = &(struct clk_init_data){                           \
+                       .ops = &clk_smd_rpm_branch_ops,                       \
+                       .name = #_name,                                       \
+                       .parent_names = (const char *[]){ "xo_board" },       \
+                       .num_parents = 1,                                     \
+               },                                                            \
+       };                                                                    \
+       static struct clk_smd_rpm _platform##_##_active = {                   \
+               .rpm_res_type = (type),                                       \
+               .rpm_clk_id = (r_id),                                         \
+               .rpm_status_id = (stat_id),                                   \
+               .active_only = true,                                          \
+               .rpm_key = (key),                                             \
+               .branch = true,                                               \
+               .peer = &_platform##_##_name,                                 \
+               .rate = (r),                                                  \
+               .hw.init = &(struct clk_init_data){                           \
+                       .ops = &clk_smd_rpm_branch_ops,                       \
+                       .name = #_active,                                     \
+                       .parent_names = (const char *[]){ "xo_board" },       \
+                       .num_parents = 1,                                     \
+               },                                                            \
+       }
+
+#define DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id)            \
+               __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id,   \
+               0, QCOM_RPM_SMD_KEY_RATE)
+
+#define DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type, r_id, r)   \
+               __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type,  \
+               r_id, 0, r, QCOM_RPM_SMD_KEY_ENABLE)
+
+#define DEFINE_CLK_SMD_RPM_QDSS(_platform, _name, _active, type, r_id)       \
+               __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id,   \
+               0, QCOM_RPM_SMD_KEY_STATE)
+
+#define DEFINE_CLK_SMD_RPM_XO_BUFFER(_platform, _name, _active, r_id)        \
+               __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active,        \
+               QCOM_SMD_RPM_CLK_BUF_A, r_id, 0, 1000,                        \
+               QCOM_RPM_KEY_SOFTWARE_ENABLE)
+
+#define DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(_platform, _name, _active, r_id) \
+               __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active,        \
+               QCOM_SMD_RPM_CLK_BUF_A, r_id, 0, 1000,                        \
+               QCOM_RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY)
 
 #define to_clk_smd_rpm(_hw) container_of(_hw, struct clk_smd_rpm, hw)
 
+struct clk_smd_rpm {
+       const int rpm_res_type;
+       const int rpm_key;
+       const int rpm_clk_id;
+       const int rpm_status_id;
+       const bool active_only;
+       bool enabled;
+       bool branch;
+       struct clk_smd_rpm *peer;
+       struct clk_hw hw;
+       unsigned long rate;
+       struct qcom_smd_rpm *rpm;
+};
+
+struct clk_smd_rpm_req {
+       __le32 key;
+       __le32 nbytes;
+       __le32 value;
+};
+
+struct rpm_cc {
+       struct qcom_rpm *rpm;
+       struct clk_onecell_data data;
+       struct clk *clks[];
+};
+
+struct rpm_smd_clk_desc {
+       struct clk_smd_rpm **clks;
+       size_t num_clks;
+};
+
 static DEFINE_MUTEX(rpm_smd_clk_lock);
 
+static int clk_smd_rpm_handoff(struct clk_smd_rpm *r)
+{
+       int ret;
+       struct clk_smd_rpm_req req = {
+               .key = cpu_to_le32(r->rpm_key),
+               .nbytes = cpu_to_le32(sizeof(u32)),
+               .value = cpu_to_le32(INT_MAX),
+       };
+
+       ret = qcom_rpm_smd_write(r->rpm, QCOM_SMD_RPM_ACTIVE_STATE,
+                                r->rpm_res_type, r->rpm_clk_id, &req,
+                                sizeof(req));
+       if (ret)
+               return ret;
+       ret = qcom_rpm_smd_write(r->rpm, QCOM_SMD_RPM_SLEEP_STATE,
+                                r->rpm_res_type, r->rpm_clk_id, &req,
+                                sizeof(req));
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
 static int clk_smd_rpm_set_rate_active(struct clk_smd_rpm *r,
                                       unsigned long rate)
 {
@@ -250,39 +401,25 @@ static int clk_smd_rpm_enable_scaling(struct qcom_smd_rpm *rpm)
        return 0;
 }
 
-const struct clk_ops clk_smd_rpm_ops = {
+static const struct clk_ops clk_smd_rpm_ops = {
        .prepare        = clk_smd_rpm_prepare,
        .unprepare      = clk_smd_rpm_unprepare,
        .set_rate       = clk_smd_rpm_set_rate,
        .round_rate     = clk_smd_rpm_round_rate,
        .recalc_rate    = clk_smd_rpm_recalc_rate,
 };
-EXPORT_SYMBOL_GPL(clk_smd_rpm_ops);
 
-const struct clk_ops clk_smd_rpm_branch_ops = {
+static const struct clk_ops clk_smd_rpm_branch_ops = {
        .prepare        = clk_smd_rpm_prepare,
        .unprepare      = clk_smd_rpm_unprepare,
        .round_rate     = clk_smd_rpm_round_rate,
        .recalc_rate    = clk_smd_rpm_recalc_rate,
 };
-EXPORT_SYMBOL_GPL(clk_smd_rpm_branch_ops);
-
-struct rpm_cc {
-       struct qcom_rpm *rpm;
-       struct clk_onecell_data data;
-       struct clk *clks[];
-};
-
-struct rpm_smd_clk_desc {
-       struct clk_smd_rpm **clks;
-       size_t num_clks;
-};
 
 /* msm8916 */
 DEFINE_CLK_SMD_RPM(msm8916, pcnoc_clk, pcnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
 DEFINE_CLK_SMD_RPM(msm8916, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
 DEFINE_CLK_SMD_RPM(msm8916, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
-DEFINE_CLK_SMD_RPM_BRANCH(msm8916, xo, xo_a, QCOM_SMD_RPM_MISC_CLK, 0, 19200000);
 DEFINE_CLK_SMD_RPM_QDSS(msm8916, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1);
 DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8916, bb_clk1, bb_clk1_a, 1);
 DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8916, bb_clk2, bb_clk2_a, 2);
@@ -294,32 +431,30 @@ DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8916, rf_clk1_pin, rf_clk1_a_pin, 4);
 DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8916, rf_clk2_pin, rf_clk2_a_pin, 5);
 
 static struct clk_smd_rpm *msm8916_clks[] = {
-       [RPM_XO_CLK_SRC]        = &msm8916_xo,
-       [RPM_XO_A_CLK_SRC]      = &msm8916_xo_a,
-       [RPM_PCNOC_CLK]         = &msm8916_pcnoc_clk,
-       [RPM_PCNOC_A_CLK]       = &msm8916_pcnoc_a_clk,
-       [RPM_SNOC_CLK]          = &msm8916_snoc_clk,
-       [RPM_SNOC_A_CLK]        = &msm8916_snoc_a_clk,
-       [RPM_BIMC_CLK]          = &msm8916_bimc_clk,
-       [RPM_BIMC_A_CLK]        = &msm8916_bimc_a_clk,
-       [RPM_QDSS_CLK]          = &msm8916_qdss_clk,
-       [RPM_QDSS_A_CLK]        = &msm8916_qdss_a_clk,
-       [RPM_BB_CLK1]           = &msm8916_bb_clk1,
-       [RPM_BB_CLK1_A]         = &msm8916_bb_clk1_a,
-       [RPM_BB_CLK2]           = &msm8916_bb_clk2,
-       [RPM_BB_CLK2_A]         = &msm8916_bb_clk2_a,
-       [RPM_RF_CLK1]           = &msm8916_rf_clk1,
-       [RPM_RF_CLK1_A]         = &msm8916_rf_clk1_a,
-       [RPM_RF_CLK2]           = &msm8916_rf_clk2,
-       [RPM_RF_CLK2_A]         = &msm8916_rf_clk2_a,
-       [RPM_BB_CLK1_PIN]       = &msm8916_bb_clk1_pin,
-       [RPM_BB_CLK1_A_PIN]     = &msm8916_bb_clk1_a_pin,
-       [RPM_BB_CLK2_PIN]       = &msm8916_bb_clk2_pin,
-       [RPM_BB_CLK2_A_PIN]     = &msm8916_bb_clk2_a_pin,
-       [RPM_RF_CLK1_PIN]       = &msm8916_rf_clk1_pin,
-       [RPM_RF_CLK1_A_PIN]     = &msm8916_rf_clk1_a_pin,
-       [RPM_RF_CLK2_PIN]       = &msm8916_rf_clk2_pin,
-       [RPM_RF_CLK2_A_PIN]     = &msm8916_rf_clk2_a_pin,
+       [RPM_SMD_PCNOC_CLK]             = &msm8916_pcnoc_clk,
+       [RPM_SMD_PCNOC_A_CLK]           = &msm8916_pcnoc_a_clk,
+       [RPM_SMD_SNOC_CLK]              = &msm8916_snoc_clk,
+       [RPM_SMD_SNOC_A_CLK]            = &msm8916_snoc_a_clk,
+       [RPM_SMD_BIMC_CLK]              = &msm8916_bimc_clk,
+       [RPM_SMD_BIMC_A_CLK]            = &msm8916_bimc_a_clk,
+       [RPM_SMD_QDSS_CLK]              = &msm8916_qdss_clk,
+       [RPM_SMD_QDSS_A_CLK]            = &msm8916_qdss_a_clk,
+       [RPM_SMD_BB_CLK1]               = &msm8916_bb_clk1,
+       [RPM_SMD_BB_CLK1_A]             = &msm8916_bb_clk1_a,
+       [RPM_SMD_BB_CLK2]               = &msm8916_bb_clk2,
+       [RPM_SMD_BB_CLK2_A]             = &msm8916_bb_clk2_a,
+       [RPM_SMD_RF_CLK1]               = &msm8916_rf_clk1,
+       [RPM_SMD_RF_CLK1_A]             = &msm8916_rf_clk1_a,
+       [RPM_SMD_RF_CLK2]               = &msm8916_rf_clk2,
+       [RPM_SMD_RF_CLK2_A]             = &msm8916_rf_clk2_a,
+       [RPM_SMD_BB_CLK1_PIN]           = &msm8916_bb_clk1_pin,
+       [RPM_SMD_BB_CLK1_A_PIN]         = &msm8916_bb_clk1_a_pin,
+       [RPM_SMD_BB_CLK2_PIN]           = &msm8916_bb_clk2_pin,
+       [RPM_SMD_BB_CLK2_A_PIN]         = &msm8916_bb_clk2_a_pin,
+       [RPM_SMD_RF_CLK1_PIN]           = &msm8916_rf_clk1_pin,
+       [RPM_SMD_RF_CLK1_A_PIN]         = &msm8916_rf_clk1_a_pin,
+       [RPM_SMD_RF_CLK2_PIN]           = &msm8916_rf_clk2_pin,
+       [RPM_SMD_RF_CLK2_A_PIN]         = &msm8916_rf_clk2_a_pin,
 };
 
 static const struct rpm_smd_clk_desc rpm_clk_msm8916 = {
@@ -327,167 +462,8 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8916 = {
        .num_clks = ARRAY_SIZE(msm8916_clks),
 };
 
-/* msm8974 */
-DEFINE_CLK_SMD_RPM(msm8974, pnoc_clk, pnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
-DEFINE_CLK_SMD_RPM(msm8974, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
-DEFINE_CLK_SMD_RPM(msm8974, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
-DEFINE_CLK_SMD_RPM(msm8974, mmssnoc_ahb_clk, mmssnoc_ahb_a_clk, QCOM_SMD_RPM_BUS_CLK, 3);
-DEFINE_CLK_SMD_RPM(msm8974, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
-DEFINE_CLK_SMD_RPM(msm8974, ocmemgx_clk, ocmemgx_a_clk, QCOM_SMD_RPM_MEM_CLK, 2);
-DEFINE_CLK_SMD_RPM(msm8974, gfx3d_clk_src, gfx3d_a_clk_src, QCOM_SMD_RPM_MEM_CLK, 1);
-DEFINE_CLK_SMD_RPM_BRANCH(msm8974, cxo_clk_src, cxo_a_clk_src, QCOM_SMD_RPM_MISC_CLK, 0, 19200000);
-DEFINE_CLK_SMD_RPM_QDSS(msm8974, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_d0, cxo_d0_a, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_d1, cxo_d1_a, 2);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_a0, cxo_a0_a, 4);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_a1, cxo_a1_a, 5);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, cxo_a2, cxo_a2_a, 6);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, div_clk1, div_a_clk1, 11);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, div_clk2, div_a_clk2, 12);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8974, diff_clk, diff_a_clk, 7);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_d0_pin, cxo_d0_a_pin, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_d1_pin, cxo_d1_a_pin, 2);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_a0_pin, cxo_a0_a_pin, 4);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_a1_pin, cxo_a1_a_pin, 5);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8974, cxo_a2_pin, cxo_a2_a_pin, 6);
-
-static struct clk_smd_rpm *msm8974_clks[] = {
-       [RPM_CXO_CLK_SRC]       = &msm8974_cxo_clk_src,
-       [RPM_CXO_A_CLK_SRC]     = &msm8974_cxo_a_clk_src,
-       [RPM_PNOC_CLK]          = &msm8974_pnoc_clk,
-       [RPM_PNOC_A_CLK]        = &msm8974_pnoc_a_clk,
-       [RPM_SNOC_CLK]          = &msm8974_snoc_clk,
-       [RPM_SNOC_A_CLK]        = &msm8974_snoc_a_clk,
-       [RPM_BIMC_CLK]          = &msm8974_bimc_clk,
-       [RPM_BIMC_A_CLK]        = &msm8974_bimc_a_clk,
-       [RPM_QDSS_CLK]          = &msm8974_qdss_clk,
-       [RPM_QDSS_A_CLK]        = &msm8974_qdss_a_clk,
-       [RPM_CNOC_CLK]          = &msm8974_cnoc_clk,
-       [RPM_CNOC_A_CLK]        = &msm8974_cnoc_a_clk,
-       [RPM_MMSSNOC_AHB_CLK]   = &msm8974_mmssnoc_ahb_clk,
-       [RPM_MMSSNOC_AHB_A_CLK] = &msm8974_mmssnoc_ahb_a_clk,
-       [RPM_OCMEMGX_CLK]       = &msm8974_ocmemgx_clk,
-       [RPM_OCMEMGX_A_CLK]     = &msm8974_ocmemgx_a_clk,
-       [RPM_GFX3D_CLK_SRC]     = &msm8974_gfx3d_clk_src,
-       [RPM_GFX3D_A_CLK_SRC]   = &msm8974_gfx3d_a_clk_src,
-       [RPM_CXO_D0]            = &msm8974_cxo_d0,
-       [RPM_CXO_D0_A]          = &msm8974_cxo_d0_a,
-       [RPM_CXO_D1]            = &msm8974_cxo_d1,
-       [RPM_CXO_D1_A]          = &msm8974_cxo_d1_a,
-       [RPM_CXO_A0]            = &msm8974_cxo_a0,
-       [RPM_CXO_A0_A]          = &msm8974_cxo_a0_a,
-       [RPM_CXO_A1]            = &msm8974_cxo_a1,
-       [RPM_CXO_A1_A]          = &msm8974_cxo_a1_a,
-       [RPM_CXO_A2]            = &msm8974_cxo_a2,
-       [RPM_CXO_A2_A]          = &msm8974_cxo_a2_a,
-       [RPM_DIV_CLK1]          = &msm8974_div_clk1,
-       [RPM_DIV_A_CLK1]        = &msm8974_div_a_clk1,
-       [RPM_DIV_CLK2]          = &msm8974_div_clk2,
-       [RPM_DIV_A_CLK2]        = &msm8974_div_a_clk2,
-       [RPM_DIFF_CLK]          = &msm8974_diff_clk,
-       [RPM_DIFF_A_CLK]        = &msm8974_diff_a_clk,
-       [RPM_CXO_D0_PIN]        = &msm8974_cxo_d0_pin,
-       [RPM_CXO_D0_A_PIN]      = &msm8974_cxo_d0_a_pin,
-       [RPM_CXO_D1_PIN]        = &msm8974_cxo_d1_pin,
-       [RPM_CXO_D1_A_PIN]      = &msm8974_cxo_d1_a_pin,
-       [RPM_CXO_A0_PIN]        = &msm8974_cxo_a0_pin,
-       [RPM_CXO_A0_A_PIN]      = &msm8974_cxo_a0_a_pin,
-       [RPM_CXO_A1_PIN]        = &msm8974_cxo_a1_pin,
-       [RPM_CXO_A1_A_PIN]      = &msm8974_cxo_a1_a_pin,
-       [RPM_CXO_A2_PIN]        = &msm8974_cxo_a2_pin,
-       [RPM_CXO_A2_A_PIN]      = &msm8974_cxo_a2_a_pin,
-};
-
-static const struct rpm_smd_clk_desc rpm_clk_msm8974 = {
-       .clks = msm8974_clks,
-       .num_clks = ARRAY_SIZE(msm8974_clks),
-};
-
-/* apq8084 */
-DEFINE_CLK_SMD_RPM(apq8084, pnoc_clk, pnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0);
-DEFINE_CLK_SMD_RPM(apq8084, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1);
-DEFINE_CLK_SMD_RPM(apq8084, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2);
-DEFINE_CLK_SMD_RPM(apq8084, mmssnoc_ahb_clk, mmssnoc_ahb_a_clk, QCOM_SMD_RPM_BUS_CLK, 3);
-DEFINE_CLK_SMD_RPM(apq8084, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0);
-DEFINE_CLK_SMD_RPM(apq8084, ocmemgx_clk, ocmemgx_a_clk, QCOM_SMD_RPM_MEM_CLK, 2);
-DEFINE_CLK_SMD_RPM(apq8084, gfx3d_clk_src, gfx3d_a_clk_src, QCOM_SMD_RPM_MEM_CLK, 1);
-DEFINE_CLK_SMD_RPM_BRANCH(apq8084, xo_clk_src, xo_a_clk_src, QCOM_SMD_RPM_MISC_CLK, 0, 19200000);
-DEFINE_CLK_SMD_RPM_QDSS(apq8084, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1);
-
-DEFINE_CLK_SMD_RPM_XO_BUFFER(apq8084, bb_clk1, bb_clk1_a, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(apq8084, bb_clk2, bb_clk2_a, 2);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(apq8084, rf_clk1, rf_clk1_a, 4);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(apq8084, rf_clk2, rf_clk2_a, 5);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(apq8084, rf_clk3, rf_clk3_a, 6);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(apq8084, diff_clk1, diff_clk1_a, 7);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(apq8084, div_clk1, div_clk1_a, 11);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(apq8084, div_clk2, div_clk2_a, 12);
-DEFINE_CLK_SMD_RPM_XO_BUFFER(apq8084, div_clk3, div_clk3_a, 13);
-
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(apq8084, bb_clk1_pin, bb_clk1_a_pin, 1);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(apq8084, bb_clk2_pin, bb_clk2_a_pin, 2);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(apq8084, rf_clk1_pin, rf_clk1_a_pin, 4);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(apq8084, rf_clk2_pin, rf_clk2_a_pin, 5);
-DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(apq8084, rf_clk3_pin, rf_clk3_a_pin, 6);
-
-static struct clk_smd_rpm *apq8084_clks[] = {
-       [RPM_XO_CLK_SRC]        = &apq8084_xo_clk_src,
-       [RPM_XO_A_CLK_SRC]      = &apq8084_xo_a_clk_src,
-       [RPM_PNOC_CLK]          = &apq8084_pnoc_clk,
-       [RPM_PNOC_A_CLK]        = &apq8084_pnoc_a_clk,
-       [RPM_SNOC_CLK]          = &apq8084_snoc_clk,
-       [RPM_SNOC_A_CLK]        = &apq8084_snoc_a_clk,
-       [RPM_BIMC_CLK]          = &apq8084_bimc_clk,
-       [RPM_BIMC_A_CLK]        = &apq8084_bimc_a_clk,
-       [RPM_QDSS_CLK]          = &apq8084_qdss_clk,
-       [RPM_QDSS_A_CLK]        = &apq8084_qdss_a_clk,
-       [RPM_CNOC_CLK]          = &apq8084_cnoc_clk,
-       [RPM_CNOC_A_CLK]        = &apq8084_cnoc_a_clk,
-       [RPM_MMSSNOC_AHB_CLK]   = &apq8084_mmssnoc_ahb_clk,
-       [RPM_MMSSNOC_AHB_A_CLK] = &apq8084_mmssnoc_ahb_a_clk,
-       [RPM_OCMEMGX_CLK]       = &apq8084_ocmemgx_clk,
-       [RPM_OCMEMGX_A_CLK]     = &apq8084_ocmemgx_a_clk,
-       [RPM_GFX3D_CLK_SRC]     = &apq8084_gfx3d_clk_src,
-       [RPM_GFX3D_A_CLK_SRC]   = &apq8084_gfx3d_a_clk_src,
-       [RPM_BB_CLK1]           = &apq8084_bb_clk1,
-       [RPM_BB_CLK1_A]         = &apq8084_bb_clk1_a,
-       [RPM_BB_CLK2]           = &apq8084_bb_clk2,
-       [RPM_BB_CLK2_A]         = &apq8084_bb_clk2_a,
-       [RPM_RF_CLK1]           = &apq8084_rf_clk1,
-       [RPM_RF_CLK1_A]         = &apq8084_rf_clk1_a,
-       [RPM_RF_CLK2]           = &apq8084_rf_clk2,
-       [RPM_RF_CLK2_A]         = &apq8084_rf_clk2_a,
-       [RPM_RF_CLK3]           = &apq8084_rf_clk3,
-       [RPM_RF_CLK3_A]         = &apq8084_rf_clk3_a,
-       [RPM_DIFF_CLK1]         = &apq8084_diff_clk1,
-       [RPM_DIFF_CLK1_A]       = &apq8084_diff_clk1_a,
-       [RPM_DIV_CLK1]          = &apq8084_div_clk1,
-       [RPM_DIV_CLK1_A]        = &apq8084_div_clk1_a,
-       [RPM_DIV_CLK2]          = &apq8084_div_clk2,
-       [RPM_DIV_CLK2_A]        = &apq8084_div_clk2_a,
-       [RPM_DIV_CLK3]          = &apq8084_div_clk3,
-       [RPM_DIV_CLK3_A]        = &apq8084_div_clk3_a,
-       [RPM_BB_CLK1_PIN]       = &apq8084_bb_clk1_pin,
-       [RPM_BB_CLK1_A_PIN]     = &apq8084_bb_clk1_a_pin,
-       [RPM_BB_CLK2_PIN]       = &apq8084_bb_clk2_pin,
-       [RPM_BB_CLK2_A_PIN]     = &apq8084_bb_clk2_a_pin,
-       [RPM_RF_CLK1_PIN]       = &apq8084_rf_clk1_pin,
-       [RPM_RF_CLK1_A_PIN]     = &apq8084_rf_clk1_a_pin,
-       [RPM_RF_CLK2_PIN]       = &apq8084_rf_clk2_pin,
-       [RPM_RF_CLK2_A_PIN]     = &apq8084_rf_clk2_a_pin,
-       [RPM_RF_CLK3_PIN]       = &apq8084_rf_clk3_pin,
-       [RPM_RF_CLK3_A_PIN]     = &apq8084_rf_clk3_a_pin,
-};
-
-static const struct rpm_smd_clk_desc rpm_clk_apq8084 = {
-       .clks = apq8084_clks,
-       .num_clks = ARRAY_SIZE(apq8084_clks),
-};
-
 static const struct of_device_id rpm_smd_clk_match_table[] = {
        { .compatible = "qcom,rpmcc-msm8916", .data = &rpm_clk_msm8916},
-       { .compatible = "qcom,rpmcc-msm8974", .data = &rpm_clk_msm8974},
-       { .compatible = "qcom,rpmcc-apq8084", .data = &rpm_clk_apq8084},
        { }
 };
 MODULE_DEVICE_TABLE(of, rpm_smd_clk_match_table);
@@ -498,8 +474,8 @@ static int rpm_smd_clk_probe(struct platform_device *pdev)
        struct clk *clk;
        struct rpm_cc *rcc;
        struct clk_onecell_data *data;
-       int ret, i;
-       size_t num_clks;
+       int ret;
+       size_t num_clks, i;
        struct qcom_smd_rpm *rpm;
        struct clk_smd_rpm **rpm_smd_clks;
        const struct rpm_smd_clk_desc *desc;
@@ -534,6 +510,22 @@ static int rpm_smd_clk_probe(struct platform_device *pdev)
                }
 
                rpm_smd_clks[i]->rpm = rpm;
+
+               ret = clk_smd_rpm_handoff(rpm_smd_clks[i]);
+               if (ret)
+                       goto err;
+       }
+
+       ret = clk_smd_rpm_enable_scaling(rpm);
+       if (ret)
+               goto err;
+
+       for (i = 0; i < num_clks; i++) {
+               if (!rpm_smd_clks[i]) {
+                       clks[i] = ERR_PTR(-ENOENT);
+                       continue;
+               }
+
                clk = devm_clk_register(&pdev->dev, &rpm_smd_clks[i]->hw);
                if (IS_ERR(clk)) {
                        ret = PTR_ERR(clk);
@@ -548,12 +540,6 @@ static int rpm_smd_clk_probe(struct platform_device *pdev)
        if (ret)
                goto err;
 
-       ret = clk_smd_rpm_enable_scaling(rpm);
-       if (ret) {
-               of_clk_del_provider(pdev->dev.of_node);
-               goto err;
-       }
-
        return 0;
 err:
        dev_err(&pdev->dev, "Error registering SMD clock driver (%d)\n", ret);
diff --git a/drivers/clk/qcom/clk-smd-rpm.h b/drivers/clk/qcom/clk-smd-rpm.h
deleted file mode 100644 (file)
index 7ac5829..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (c) 2015, Linaro Limited
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef __QCOM_CLK_SMD_RPM_H__
-#define __QCOM_CLK_SMD_RPM_H__
-
-#include <linux/clk-provider.h>
-
-#define QCOM_RPM_KEY_SOFTWARE_ENABLE                   0x6e657773
-#define QCOM_RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY    0x62636370
-#define QCOM_RPM_SMD_KEY_RATE                          0x007a484b
-#define QCOM_RPM_SMD_KEY_ENABLE                                0x62616e45
-#define QCOM_RPM_SMD_KEY_STATE                         0x54415453
-#define QCOM_RPM_SCALING_ENABLE_ID                     0x2
-
-struct qcom_smd_rpm;
-
-struct clk_smd_rpm {
-       const int rpm_res_type;
-       const int rpm_key;
-       const int rpm_clk_id;
-       const int rpm_status_id;
-       const bool active_only;
-       bool enabled;
-       bool branch;
-       struct clk_smd_rpm *peer;
-       struct clk_hw hw;
-       unsigned long rate;
-       struct qcom_smd_rpm *rpm;
-};
-
-struct clk_smd_rpm_req {
-       __le32 key;
-       __le32 nbytes;
-       __le32 value;
-};
-
-extern const struct clk_ops clk_smd_rpm_ops;
-extern const struct clk_ops clk_smd_rpm_branch_ops;
-
-#define __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id, stat_id,  \
-                            key)                                             \
-       static struct clk_smd_rpm _platform##_##_active;                      \
-       static struct clk_smd_rpm _platform##_##_name = {                     \
-               .rpm_res_type = (type),                                       \
-               .rpm_clk_id = (r_id),                                         \
-               .rpm_status_id = (stat_id),                                   \
-               .rpm_key = (key),                                             \
-               .peer = &_platform##_##_active,                               \
-               .rate = INT_MAX,                                              \
-               .hw.init = &(struct clk_init_data){                           \
-                       .ops = &clk_smd_rpm_ops,                              \
-                       .name = #_name,                                       \
-                       .parent_names = (const char *[]){ "xo_board" },       \
-                       .num_parents = 1,                                     \
-               },                                                            \
-       };                                                                    \
-       static struct clk_smd_rpm _platform##_##_active = {                   \
-               .rpm_res_type = (type),                                       \
-               .rpm_clk_id = (r_id),                                         \
-               .rpm_status_id = (stat_id),                                   \
-               .rpm_key = (key),                                             \
-               .peer = &_platform##_##_name,                                 \
-               .active_only = true,                                          \
-               .rate = INT_MAX,                                              \
-               .hw.init = &(struct clk_init_data){                           \
-                       .ops = &clk_smd_rpm_ops,                              \
-                       .name = #_active,                                     \
-                       .parent_names = (const char *[]){ "xo_board" },       \
-                       .num_parents = 1,                                     \
-               },                                                            \
-       }
-
-#define __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type, r_id,    \
-                                   stat_id, r, key)                          \
-       static struct clk_smd_rpm _platform##_##_active;                      \
-       static struct clk_smd_rpm _platform##_##_name = {                     \
-               .rpm_res_type = (type),                                       \
-               .rpm_clk_id = (r_id),                                         \
-               .rpm_status_id = (stat_id),                                   \
-               .rpm_key = (key),                                             \
-               .peer = &_platform##_##_active,                               \
-               .branch = true,                                               \
-               .rate = (r),                                                  \
-               .hw.init = &(struct clk_init_data){                           \
-                       .ops = &clk_smd_rpm_branch_ops,                       \
-                       .name = #_name,                                       \
-                       .parent_names = (const char *[]){ "xo_board" },       \
-                       .num_parents = 1,                                     \
-               },                                                            \
-       };                                                                    \
-       static struct clk_smd_rpm _platform##_##_active = {                   \
-               .rpm_res_type = (type),                                       \
-               .rpm_clk_id = (r_id),                                         \
-               .rpm_status_id = (stat_id),                                   \
-               .rpm_key = (key),                                             \
-               .peer = &_platform##_##_name,                                 \
-               .active_only = true,                                          \
-               .branch = true,                                               \
-               .rate = (r),                                                  \
-               .hw.init = &(struct clk_init_data){                           \
-                       .ops = &clk_smd_rpm_branch_ops,                       \
-                       .name = #_active,                                     \
-                       .parent_names = (const char *[]){ "xo_board" },       \
-                       .num_parents = 1,                                     \
-               },                                                            \
-       }
-
-#define DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id)            \
-               __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id,   \
-               0, QCOM_RPM_SMD_KEY_RATE)
-
-#define DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type, r_id, r)   \
-               __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active, type,  \
-               r_id, 0, r, QCOM_RPM_SMD_KEY_ENABLE)
-
-#define DEFINE_CLK_SMD_RPM_QDSS(_platform, _name, _active, type, r_id)       \
-               __DEFINE_CLK_SMD_RPM(_platform, _name, _active, type, r_id,   \
-               0, QCOM_RPM_SMD_KEY_STATE)
-
-#define DEFINE_CLK_SMD_RPM_XO_BUFFER(_platform, _name, _active, r_id)        \
-               __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active,        \
-               QCOM_SMD_RPM_CLK_BUF_A, r_id, 0, 1000,                        \
-               QCOM_RPM_KEY_SOFTWARE_ENABLE)
-
-#define DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(_platform, _name, _active, r_id) \
-               __DEFINE_CLK_SMD_RPM_BRANCH(_platform, _name, _active,        \
-               QCOM_SMD_RPM_CLK_BUF_A, r_id, 0, 1000,                        \
-               QCOM_RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY)
-
-#endif
index cabbe1f7e397d54d38f2061510411f22a75207c6..ca24cb6bf012bd3b71ef2946ec39e4d54a67a7f2 100644 (file)
@@ -501,11 +501,13 @@ int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
                req, req_cnt * sizeof(*req), resp, sizeof(*resp));
 }
 
-int __qcom_scm_restart_proc(u32 proc_id, int restart, u32 *resp)
+int __qcom_scm_pas_mss_reset(bool reset)
 {
+       __le32 val = cpu_to_le32(reset);
+       __le32 resp;
 
-       return qcom_scm_call(QCOM_SCM_SVC_PIL, proc_id,
-                               &restart, sizeof(restart),
+       return qcom_scm_call(QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MSS_RESET,
+                               &val, sizeof(val),
                                &resp, sizeof(resp));
 }
 
@@ -521,39 +523,23 @@ bool __qcom_scm_pas_supported(u32 peripheral)
        return ret ? false : !!ret_val;
 }
 
-int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral, const void *metadata, size_t size)
+int __qcom_scm_pas_init_image(u32 peripheral, dma_addr_t metadata_phys)
 {
-       dma_addr_t mdata_phys;
-       void *mdata_buf;
-       u32 scm_ret;
+       __le32 scm_ret;
        int ret;
-       struct pas_init_image_req {
-               u32 proc;
-               u32 image_addr;
+       struct {
+               __le32 proc;
+               __le32 image_addr;
        } request;
 
-       /*
-        * During the scm call memory protection will be enabled for the meta
-        * data blob, so make sure it's physically contiguous, 4K aligned and
-        * non-cachable to avoid XPU violations.
-        */
-       mdata_buf = dma_alloc_coherent(dev, size, &mdata_phys, GFP_KERNEL);
-       if (!mdata_buf) {
-               pr_err("Allocation of metadata buffer failed.\n");
-               return -ENOMEM;
-       }
-       memcpy(mdata_buf, metadata, size);
-
-       request.proc = peripheral;
-       request.image_addr = mdata_phys;
+       request.proc = cpu_to_le32(peripheral);
+       request.image_addr = cpu_to_le32(metadata_phys);
 
        ret = qcom_scm_call(QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_INIT_IMAGE_CMD,
                            &request, sizeof(request),
                            &scm_ret, sizeof(scm_ret));
 
-       dma_free_coherent(dev, size, mdata_buf, mdata_phys);
-
-       return ret ? : scm_ret;
+       return ret ? : le32_to_cpu(scm_ret);
 }
 
 int __qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size)
index dc64858935fa7f977ef624e382691783fc7b6aba..7784f1dc8977feb7817ae8961ebbdef31a1dedd0 100644 (file)
@@ -472,20 +472,15 @@ int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
        return ret;
 }
 
-int __qcom_scm_restart_proc(u32 proc_id, int restart, u32 *resp)
+int __qcom_scm_pas_mss_reset(bool reset)
 {
-       int ret;
        struct qcom_scm_desc desc = {0};
 
-       desc.args[0] = restart;
+       desc.args[0] = reset;
        desc.args[1] = 0;
        desc.arginfo = QCOM_SCM_ARGS(2);
 
-       ret = qcom_scm_call(QCOM_SCM_SVC_PIL, proc_id,
-                               &desc);
-       *resp = desc.ret[0];
-
-       return ret;
+       return qcom_scm_call(QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_MSS_RESET, &desc);
 }
 
 bool __qcom_scm_pas_supported(u32 peripheral)
@@ -502,37 +497,20 @@ bool __qcom_scm_pas_supported(u32 peripheral)
        return ret ? false : !!desc.ret[0];
 }
 
-int __qcom_scm_pas_init_image(struct device *dev, u32 peripheral, const void *metadata, size_t size)
+int __qcom_scm_pas_init_image(u32 peripheral, dma_addr_t metadata_phys)
 {
        int ret;
        struct qcom_scm_desc desc = {0};
        u32 scm_ret;
-       dma_addr_t mdata_phys;
-       void *mdata_buf;
-
-dev->coherent_dma_mask = DMA_BIT_MASK(sizeof(dma_addr_t) * 8);
-
-       /*
-        * During the scm call memory protection will be enabled for the meta
-        * data blob, so make sure it's physically contiguous, 4K aligned and
-        * non-cachable to avoid XPU violations.
-        */
-       mdata_buf = dma_alloc_coherent(dev, size, &mdata_phys, GFP_KERNEL);
-       if (!mdata_buf) {
-               pr_err("Allocation of metadata buffer failed.\n");
-               return -ENOMEM;
-       }
-       memcpy(mdata_buf, metadata, size);
 
        desc.args[0] = peripheral;
-       desc.args[1] = mdata_phys;
+       desc.args[1] = metadata_phys;
        desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW);
 
        ret = qcom_scm_call(QCOM_SCM_SVC_PIL, QCOM_SCM_PAS_INIT_IMAGE_CMD,
                                &desc);
        scm_ret = desc.ret[0];
 
-       dma_free_coherent(dev, size, mdata_buf, mdata_phys);
        return ret ? : scm_ret;
 }
 
index a1a25185a867e786c4dace4cb693d0051a53b628..b760fae77d194d0d6eed716068d058e06813fe52 100644 (file)
 #include <linux/module.h>
 #include <linux/cpumask.h>
 #include <linux/export.h>
+#include <linux/dma-mapping.h>
 #include <linux/types.h>
 #include <linux/qcom_scm.h>
 #include <linux/of.h>
 #include <linux/clk.h>
+#include <linux/reset-controller.h>
 
 #include "qcom_scm.h"
 
 struct qcom_scm {
+       struct device *dev;
        struct clk *core_clk;
        struct clk *iface_clk;
        struct clk *bus_clk;
+
+       struct reset_controller_dev reset;
 };
 
 static struct qcom_scm *__scm;
@@ -34,44 +39,31 @@ static int qcom_scm_clk_enable(void)
 {
        int ret;
 
-       if(__scm->core_clk) {
-               ret = clk_prepare_enable(__scm->core_clk);
-               if (ret)
-                       goto bail;
-       }
-
-       if(__scm->iface_clk) {
-               ret = clk_prepare_enable(__scm->iface_clk);
-               if (ret)
-                       goto disable_core;
-       }
-
-       if(__scm->bus_clk) {
-               ret = clk_prepare_enable(__scm->bus_clk);
-               if (ret)
-                       goto disable_iface;
-       }
+       ret = clk_prepare_enable(__scm->core_clk);
+       if (ret)
+               goto bail;
+       ret = clk_prepare_enable(__scm->iface_clk);
+       if (ret)
+               goto disable_core;
+       ret = clk_prepare_enable(__scm->bus_clk);
+       if (ret)
+               goto disable_iface;
 
        return 0;
 
 disable_iface:
-       if(__scm->iface_clk)
-               clk_disable_unprepare(__scm->iface_clk);
+       clk_disable_unprepare(__scm->iface_clk);
 disable_core:
-       if(__scm->core_clk)
-               clk_disable_unprepare(__scm->core_clk);
+       clk_disable_unprepare(__scm->core_clk);
 bail:
        return ret;
 }
 
 static void qcom_scm_clk_disable(void)
 {
-       if(__scm->core_clk)
-               clk_disable_unprepare(__scm->core_clk);
-       if(__scm->iface_clk)
-               clk_disable_unprepare(__scm->iface_clk);
-       if(__scm->bus_clk)
-               clk_disable_unprepare(__scm->bus_clk);
+       clk_disable_unprepare(__scm->core_clk);
+       clk_disable_unprepare(__scm->iface_clk);
+       clk_disable_unprepare(__scm->bus_clk);
 }
 
 /**
@@ -159,11 +151,6 @@ int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
 }
 EXPORT_SYMBOL(qcom_scm_hdcp_req);
 
-int qcom_scm_restart_proc(u32 pid, int restart, u32 *resp)
-{
-       return __qcom_scm_restart_proc(pid, restart, resp);
-}
-EXPORT_SYMBOL(qcom_scm_restart_proc);
 /**
  * qcom_scm_pas_supported() - Check if the peripheral authentication service is
  *                           available for the given peripherial
@@ -196,9 +183,36 @@ EXPORT_SYMBOL(qcom_scm_pas_supported);
  *
  * Returns 0 on success.
  */
-int qcom_scm_pas_init_image(struct device *dev, u32 peripheral, const void *metadata, size_t size)
+int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size)
 {
-       return __qcom_scm_pas_init_image(dev, peripheral, metadata, size);
+       dma_addr_t mdata_phys;
+       void *mdata_buf;
+       int ret;
+
+       /*
+        * During the scm call memory protection will be enabled for the meta
+        * data blob, so make sure it's physically contiguous, 4K aligned and
+        * non-cachable to avoid XPU violations.
+        */
+       mdata_buf = dma_alloc_coherent(__scm->dev, size, &mdata_phys, GFP_KERNEL);
+       if (!mdata_buf) {
+               dev_err(__scm->dev, "Allocation of metadata buffer failed.\n");
+               return -ENOMEM;
+       }
+       memcpy(mdata_buf, metadata, size);
+
+       ret = qcom_scm_clk_enable();
+       if (ret)
+               goto free_metadata;
+
+       ret = __qcom_scm_pas_init_image(peripheral, mdata_phys);
+
+       qcom_scm_clk_disable();
+
+free_metadata:
+       dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys);
+
+       return ret;
 }
 EXPORT_SYMBOL(qcom_scm_pas_init_image);
 
@@ -213,7 +227,16 @@ EXPORT_SYMBOL(qcom_scm_pas_init_image);
  */
 int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size)
 {
-       return __qcom_scm_pas_mem_setup(peripheral, addr, size);
+       int ret;
+
+       ret = qcom_scm_clk_enable();
+       if (ret)
+               return ret;
+
+       ret = __qcom_scm_pas_mem_setup(peripheral, addr, size);
+       qcom_scm_clk_disable();
+
+       return ret;
 }
 EXPORT_SYMBOL(qcom_scm_pas_mem_setup);
 
@@ -226,7 +249,16 @@ EXPORT_SYMBOL(qcom_scm_pas_mem_setup);
  */
 int qcom_scm_pas_auth_and_reset(u32 peripheral)
 {
-       return __qcom_scm_pas_auth_and_reset(peripheral);
+       int ret;
+
+       ret = qcom_scm_clk_enable();
+       if (ret)
+               return ret;
+
+       ret = __qcom_scm_pas_auth_and_reset(peripheral);
+       qcom_scm_clk_disable();
+
+       return ret;
 }
 EXPORT_SYMBOL(qcom_scm_pas_auth_and_reset);
 
@@ -238,7 +270,16 @@ EXPORT_SYMBOL(qcom_scm_pas_auth_and_reset);
  */
 int qcom_scm_pas_shutdown(u32 peripheral)
 {
-       return __qcom_scm_pas_shutdown(peripheral);
+       int ret;
+
+       ret = qcom_scm_clk_enable();
+       if (ret)
+               return ret;
+
+       ret = __qcom_scm_pas_shutdown(peripheral);
+       qcom_scm_clk_disable();
+
+       return ret;
 }
 EXPORT_SYMBOL(qcom_scm_pas_shutdown);
 
@@ -351,6 +392,21 @@ static int __init qcom_scm_init(void)
        return __qcom_scm_init();
 }
 
+static int qcom_scm_reset_assert(struct reset_controller_dev *rcdev, unsigned long idx)
+{
+       return __qcom_scm_pas_mss_reset(1);
+}
+
+static int qcom_scm_reset_deassert(struct reset_controller_dev *rcdev, unsigned long idx)
+{
+       return __qcom_scm_pas_mss_reset(0);
+}
+
+static struct reset_control_ops scm_reset_ops = {
+       .assert = qcom_scm_reset_assert,
+       .deassert = qcom_scm_reset_deassert,
+};
+
 static int qcom_scm_probe(struct platform_device *pdev)
 {
        struct qcom_scm *scm;
@@ -365,35 +421,45 @@ static int qcom_scm_probe(struct platform_device *pdev)
        if (!scm)
                return -ENOMEM;
 
+       scm->dev = &pdev->dev;
+
        scm->core_clk = devm_clk_get(&pdev->dev, "core");
        if (IS_ERR(scm->core_clk)) {
-               if (PTR_ERR(scm->core_clk) != -EPROBE_DEFER)
-                       dev_err(&pdev->dev, "failed to acquire core clk\n");
+               if (PTR_ERR(scm->core_clk) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+
+               dev_err(&pdev->dev, "failed to acquire core clk\n");
                scm->core_clk = NULL;
        }
 
        scm->iface_clk = devm_clk_get(&pdev->dev, "iface");
        if (IS_ERR(scm->iface_clk)) {
-               if (PTR_ERR(scm->iface_clk) != -EPROBE_DEFER)
-                       dev_err(&pdev->dev, "failed to acquire iface clk\n");
+               if (PTR_ERR(scm->iface_clk) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+
+               dev_err(&pdev->dev, "failed to acquire iface clk\n");
                scm->iface_clk = NULL;
        }
 
        scm->bus_clk = devm_clk_get(&pdev->dev, "bus");
        if (IS_ERR(scm->bus_clk)) {
-               if (PTR_ERR(scm->bus_clk) != -EPROBE_DEFER)
-                       dev_err(&pdev->dev, "failed to acquire bus clk\n");
+               if (PTR_ERR(scm->bus_clk) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
 
+               dev_err(&pdev->dev, "failed to acquire bus clk\n");
                scm->bus_clk = NULL;
        }
 
-       if (scm->core_clk) {
+       scm->reset.ops = &scm_reset_ops;
+       scm->reset.nr_resets = 1;
+       scm->reset.of_node = pdev->dev.of_node;
+       reset_controller_register(&scm->reset);
+
        /* vote for max clk rate for highest performance */
-               rate = clk_round_rate(scm->core_clk, INT_MAX);
-               ret = clk_set_rate(scm->core_clk, rate);
-               if (ret)
-                       return ret;
-       }
+       rate = clk_round_rate(scm->core_clk, INT_MAX);
+       ret = clk_set_rate(scm->core_clk, rate);
+       if (ret)
+               return ret;
 
        __scm = scm;
 
index 93b94c9ad34f05eb6e41067f5bf12fe10925c9af..e1d6a42ba466e6b38f28b1cb753941513a1d33e6 100644 (file)
@@ -42,11 +42,13 @@ extern int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
 #define QCOM_SCM_PAS_AUTH_AND_RESET_CMD        0x5
 #define QCOM_SCM_PAS_SHUTDOWN_CMD      0x6
 #define QCOM_SCM_PAS_IS_SUPPORTED_CMD  0x7
+#define QCOM_SCM_PAS_MSS_RESET         0xa
 extern bool __qcom_scm_pas_supported(u32 peripheral);
-extern int  __qcom_scm_pas_init_image(struct device *dev, u32 peripheral, const void *metadata, size_t size);
+extern int  __qcom_scm_pas_init_image(u32 peripheral, dma_addr_t metadata_phys);
 extern int  __qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size);
 extern int  __qcom_scm_pas_auth_and_reset(u32 peripheral);
 extern int  __qcom_scm_pas_shutdown(u32 peripheral);
+extern int  __qcom_scm_pas_mss_reset(bool reset);
 
 /* common error codes */
 #define QCOM_SCM_ENOMEM                -5
@@ -111,7 +113,6 @@ extern int __qcom_scm_iommu_secure_unmap(u32 id, u32 ctx_id, u64 va,
 extern int __qcom_scm_is_call_available(u32 svc_id, u32 cmd_id);
 extern int __qcom_scm_get_feat_version(u32 feat);
 extern int __qcom_scm_restore_sec_cfg(u32 device_id, u32 spare);
-extern int __qcom_scm_restart_proc(u32 proc_id, int restart, u32 *resp);
 
 extern int __qcom_scm_set_video_state(u32 state, u32 spare);
 extern int __qcom_scm_mem_protect_video_var(u32 start, u32 size,
index caf36519f410b838e3c1c1ae93ca4318d23f2a5c..b18bea08ff253398db70846445dca4ee3ea0eafc 100644 (file)
@@ -337,21 +337,6 @@ config GPIO_PXA
        help
          Say yes here to support the PXA GPIO device
 
-config GPIO_QCOM_SMSM
-       bool "Qualcomm Shared Memory State Machine"
-       depends on QCOM_SMEM
-       help
-         Say yes here to support the Qualcomm Shared Memory State Machine.
-         The state machine is represented by bits in shared memory and is
-         exposed to the system as GPIOs.
-
-config GPIO_QCOM_SMP2P
-       bool "Qualcomm Shared Memory Point to Point support"
-       depends on QCOM_SMEM
-       help
-         Say yes here to support the Qualcomm Shared Memory Point to Point
-         protocol, exposed to the system as GPIOs.
-
 config GPIO_RCAR
        tristate "Renesas R-Car GPIO"
        depends on ARCH_SHMOBILE || COMPILE_TEST
index 6c9d22e86b315fcafc06be41ba967a01edae0d54..986dbd838ceaceb03c42ffc15a704bf5f180b09d 100644 (file)
@@ -76,8 +76,6 @@ obj-$(CONFIG_GPIO_PCF857X)    += gpio-pcf857x.o
 obj-$(CONFIG_GPIO_PCH)         += gpio-pch.o
 obj-$(CONFIG_GPIO_PL061)       += gpio-pl061.o
 obj-$(CONFIG_GPIO_PXA)         += gpio-pxa.o
-obj-$(CONFIG_GPIO_QCOM_SMSM)   += gpio-qcom-smsm.o
-obj-$(CONFIG_GPIO_QCOM_SMP2P)  += gpio-qcom-smp2p.o
 obj-$(CONFIG_GPIO_RC5T583)     += gpio-rc5t583.o
 obj-$(CONFIG_GPIO_RDC321X)     += gpio-rdc321x.o
 obj-$(CONFIG_GPIO_RCAR)                += gpio-rcar.o
diff --git a/drivers/gpio/gpio-qcom-smp2p.c b/drivers/gpio/gpio-qcom-smp2p.c
deleted file mode 100644 (file)
index 164f39a..0000000
+++ /dev/null
@@ -1,590 +0,0 @@
-/*
- * Copyright (c) 2015, Sony Mobile Communications AB.
- * Copyright (c) 2012-2013, 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/platform_device.h>
-#include <linux/of_platform.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/memblock.h>
-#include <linux/slab.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/regmap.h>
-#include <linux/list.h>
-#include <linux/gpio.h>
-#include <linux/mfd/syscon.h>
-
-#include <linux/delay.h>
-
-#include <linux/soc/qcom/smem.h>
-
-/*
- * The Shared Memory Point to Point (SMP2P) protocol facilitates communication
- * of a single 32-bit value between two processors.  Each value has a single
- * writer (the local side) and a single reader (the remote side). Values are
- * uniquely identified in the system by the directed edge (local processor ID
- * to remote processor ID) and a string identifier.
- *
- * Each processor is responsible for creating the outgoing SMEM items and each
- * item is writable by the local processor and readable by the remote
- * processor.  By using two separate SMEM items that are single-reader and
- * single-writer, SMP2P does not require any remote locking mechanisms.
- *
- * The driver uses the Linux GPIO and interrupt framework to expose a virtual
- * GPIO for each outbound entry and a virtual interrupt controller for each
- * inbound entry.
- */
-
-#define SMP2P_MAX_ENTRY 16
-#define SMP2P_MAX_ENTRY_NAME 16
-
-#define SMP2P_FEATURE_SSR_ACK 0x1
-
-#define SMP2P_MAGIC 0x504d5324
-
-/**
- * struct smp2p_smem_item - in memory communication structure
- * @magic:             magic number
- * @version:           version - must be 1
- * @features:          features flag - currently unused
- * @local_pid:         processor id of sending end
- * @remote_pid:                processor id of receiving end
- * @total_entries:     number of entries - always SMP2P_MAX_ENTRY
- * @valid_entries:     number of allocated entries
- * @flags:
- * @entries:           individual communication entries
- *     @name:          name of the entry
- *     @value:         content of the entry
- */
-struct smp2p_smem_item {
-       u32 magic;
-       u8 version;
-       unsigned features:24;
-       u16 local_pid;
-       u16 remote_pid;
-       u16 total_entries;
-       u16 valid_entries;
-       u32 flags;
-
-       struct {
-               u8 name[SMP2P_MAX_ENTRY_NAME];
-               u32 value;
-       } entries[SMP2P_MAX_ENTRY];
-} __packed;
-
-/**
- * struct smp2p_entry - driver context matching one entry
- * @node:      list entry to keep track of allocated entries
- * @smp2p:     reference to the device driver context
- * @name:      name of the entry, to match against smp2p_smem_item
- * @value:     pointer to smp2p_smem_item entry value
- * @last_value:        last handled value
- * @domain:    irq_domain for inbound entries
- * @irq_enabled:bitmap to track enabled irq bits
- * @irq_rising:        bitmap to mark irq bits for rising detection
- * @irq_falling:bitmap to mark irq bits for falling detection
- * @chip:      gpio_chip for outbound entries
- */
-struct smp2p_entry {
-       struct list_head node;
-       struct qcom_smp2p *smp2p;
-
-       const char *name;
-       u32 *value;
-       u32 last_value;
-
-       struct irq_domain *domain;
-       DECLARE_BITMAP(irq_enabled, 32);
-       DECLARE_BITMAP(irq_rising, 32);
-       DECLARE_BITMAP(irq_falling, 32);
-
-       struct gpio_chip chip;
-};
-
-#define SMP2P_INBOUND  0
-#define SMP2P_OUTBOUND 1
-
-/**
- * struct qcom_smp2p - device driver context
- * @dev:       device driver handle
- * @in:                pointer to the inbound smem item
- * @smem_items:        ids of the two smem items
- * @valid_entries: already scanned inbound entries
- * @local_pid: processor id of the inbound edge
- * @remote_pid:        processor id of the outbound edge
- * @ipc_regmap:        regmap for the outbound ipc
- * @ipc_offset:        offset within the regmap
- * @ipc_bit:   bit in regmap@offset to kick to signal remote processor
- * @inbound:   list of inbound entries
- * @outbound:  list of outbound entries
- */
-struct qcom_smp2p {
-       struct device *dev;
-
-       struct smp2p_smem_item *in;
-       struct smp2p_smem_item *out;
-
-       unsigned smem_items[SMP2P_OUTBOUND + 1];
-
-       unsigned valid_entries;
-
-       unsigned local_pid;
-       unsigned remote_pid;
-
-       struct regmap *ipc_regmap;
-       int ipc_offset;
-       int ipc_bit;
-
-       struct list_head inbound;
-       struct list_head outbound;
-};
-
-static void qcom_smp2p_kick(struct qcom_smp2p *smp2p)
-{
-       /* Make sure any updated data is written before the kick */
-       wmb();
-       regmap_write(smp2p->ipc_regmap, smp2p->ipc_offset, BIT(smp2p->ipc_bit));
-}
-
-static irqreturn_t qcom_smp2p_intr(int irq, void *data)
-{
-       struct smp2p_smem_item *in;
-       struct smp2p_entry *entry;
-       struct qcom_smp2p *smp2p = data;
-       unsigned smem_id = smp2p->smem_items[SMP2P_INBOUND];
-       unsigned pid = smp2p->remote_pid;
-       size_t size;
-       int irq_pin;
-       u32 status;
-       u32 val;
-       int i;
-       u8 tmp_name[SMP2P_MAX_ENTRY_NAME];
-
-       in = smp2p->in;
-
-       /* Acquire smem item, if not already found */
-       if (!in) {
-               in = qcom_smem_get(pid, smem_id, &size);
-               if (IS_ERR(in)) {
-                       dev_err(smp2p->dev,
-                                       "Unable to acquire remote smp2p item\n");
-                       return IRQ_HANDLED;
-               }
-
-               smp2p->in = in;
-       }
-
-       /* Match newly created entries */
-       for (i = smp2p->valid_entries; i < in->valid_entries; i++) {
-               list_for_each_entry(entry, &smp2p->inbound, node) {
-                       memcpy_fromio(tmp_name, in->entries[i].name,
-                                       SMP2P_MAX_ENTRY_NAME);
-                       if (!strcmp(tmp_name, entry->name)) {
-                               entry->value = &in->entries[i].value;
-                               break;
-                       }
-               }
-       }
-       smp2p->valid_entries = i;
-
-       /* Fire interrupts based on any value changes */
-       list_for_each_entry(entry, &smp2p->inbound, node) {
-               /* Ignore entries not yet allocated by the remote side */
-               if (!entry->value)
-                       continue;
-
-               val = *entry->value;
-
-               status = val ^ entry->last_value;
-               entry->last_value = val;
-
-               /* No changes of this entry? */
-               if (!status)
-                       continue;
-
-               for_each_set_bit(i, entry->irq_enabled, 32) {
-                       if (!(status & BIT(i)))
-                               continue;
-
-                       if (val & BIT(i)) {
-                               if (test_bit(i, entry->irq_rising)) {
-                                       irq_pin = irq_find_mapping(entry->domain, i);
-                                       handle_nested_irq(irq_pin);
-                               }
-                       } else {
-                               if (test_bit(i, entry->irq_falling)) {
-                                       irq_pin = irq_find_mapping(entry->domain, i);
-                                       handle_nested_irq(irq_pin);
-                               }
-                       }
-
-               }
-       }
-
-       return IRQ_HANDLED;
-}
-
-static void smp2p_mask_irq(struct irq_data *irqd)
-{
-       struct smp2p_entry *entry = irq_data_get_irq_chip_data(irqd);
-       irq_hw_number_t irq = irqd_to_hwirq(irqd);
-
-       clear_bit(irq, entry->irq_enabled);
-}
-
-static void smp2p_unmask_irq(struct irq_data *irqd)
-{
-       struct smp2p_entry *entry = irq_data_get_irq_chip_data(irqd);
-       irq_hw_number_t irq = irqd_to_hwirq(irqd);
-
-       set_bit(irq, entry->irq_enabled);
-}
-
-static int smp2p_set_irq_type(struct irq_data *irqd, unsigned int type)
-{
-       struct smp2p_entry *entry = irq_data_get_irq_chip_data(irqd);
-       irq_hw_number_t irq = irqd_to_hwirq(irqd);
-
-       if (!(type & IRQ_TYPE_EDGE_BOTH))
-               return -EINVAL;
-
-       if (type & IRQ_TYPE_EDGE_RISING)
-               set_bit(irq, entry->irq_rising);
-       else
-               clear_bit(irq, entry->irq_rising);
-
-       if (type & IRQ_TYPE_EDGE_FALLING)
-               set_bit(irq, entry->irq_falling);
-       else
-               clear_bit(irq, entry->irq_falling);
-
-       return 0;
-}
-
-static struct irq_chip smp2p_irq_chip = {
-       .name           = "smp2p",
-       .irq_mask       = smp2p_mask_irq,
-       .irq_unmask     = smp2p_unmask_irq,
-       .irq_set_type   = smp2p_set_irq_type,
-};
-
-static int smp2p_irq_map(struct irq_domain *d,
-                        unsigned int irq,
-                        irq_hw_number_t hw)
-{
-       struct smp2p_entry *entry = d->host_data;
-
-       irq_set_chip_and_handler(irq, &smp2p_irq_chip, handle_level_irq);
-       irq_set_chip_data(irq, entry);
-       irq_set_nested_thread(irq, 1);
-
-       irq_set_noprobe(irq);
-
-       return 0;
-}
-
-static const struct irq_domain_ops smp2p_irq_ops = {
-       .map = smp2p_irq_map,
-       .xlate = irq_domain_xlate_twocell,
-};
-
-static int smp2p_gpio_direction_output(struct gpio_chip *chip,
-                                      unsigned offset,
-                                      int value)
-{
-       struct smp2p_entry *entry = container_of(chip, struct smp2p_entry, chip);
-
-       if (value)
-               *entry->value |= BIT(offset);
-       else
-               *entry->value &= ~BIT(offset);
-
-       qcom_smp2p_kick(entry->smp2p);
-
-       return 0;
-}
-
-static void smp2p_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
-       smp2p_gpio_direction_output(chip, offset, value);
-}
-
-static int qcom_smp2p_inbound_entry(struct qcom_smp2p *smp2p,
-                                   struct smp2p_entry *entry,
-                                   struct device_node *node)
-{
-       entry->domain = irq_domain_add_linear(node, 32, &smp2p_irq_ops, entry);
-       if (!entry->domain) {
-               dev_err(smp2p->dev, "failed to add irq_domain\n");
-               return -ENOMEM;
-       }
-
-       return 0;
-}
-
-static int qcom_smp2p_outbound_entry(struct qcom_smp2p *smp2p,
-                                    struct smp2p_entry *entry,
-                                    struct device_node *node)
-{
-       struct smp2p_smem_item *out = smp2p->out;
-       struct gpio_chip *chip;
-       int ret;
-
-       /* Allocate an entry from the smem item */
-       memcpy_toio(out->entries[out->valid_entries].name, entry->name, SMP2P_MAX_ENTRY_NAME);
-       out->valid_entries++;
-
-       /* Make the logical entry reference the physical value */
-       entry->value = &out->entries[out->valid_entries].value;
-
-       chip = &entry->chip;
-       chip->base = -1;
-       chip->ngpio = 32;
-       chip->label = entry->name;
-       chip->dev = smp2p->dev;
-       chip->owner = THIS_MODULE;
-       chip->of_node = node;
-
-       chip->set = smp2p_gpio_set;
-       chip->direction_output = smp2p_gpio_direction_output;
-
-       ret = gpiochip_add(chip);
-       if (ret)
-               dev_err(smp2p->dev, "failed register gpiochip\n");
-
-       return 0;
-}
-
-static int qcom_smp2p_alloc_outbound_item(struct qcom_smp2p *smp2p)
-{
-       struct smp2p_smem_item *out;
-       unsigned smem_id = smp2p->smem_items[SMP2P_OUTBOUND];
-       unsigned pid = smp2p->remote_pid;
-       int ret;
-
-       ret = qcom_smem_alloc(pid, smem_id, sizeof(*out));
-       if (ret < 0 && ret != -EEXIST) {
-               if (ret != -EPROBE_DEFER)
-                       dev_err(smp2p->dev,
-                               "unable to allocate local smp2p item\n");
-               return ret;
-       }
-
-       out = qcom_smem_get(pid, smem_id, NULL);
-       if (IS_ERR(out)) {
-               dev_err(smp2p->dev, "Unable to acquire local smp2p item\n");
-               return PTR_ERR(out);
-       }
-
-       memset_io(out, 0, sizeof(*out));
-       out->magic = SMP2P_MAGIC;
-       out->local_pid = smp2p->local_pid;
-       out->remote_pid = smp2p->remote_pid;
-       out->total_entries = SMP2P_MAX_ENTRY;
-       out->valid_entries = 0;
-
-       /*
-        * Make sure the rest of the header is written before we validate the
-        * item by writing a valid version number.
-        */
-       wmb();
-       out->version = 1;
-
-       qcom_smp2p_kick(smp2p);
-
-       smp2p->out = out;
-
-       return 0;
-}
-
-static int smp2p_parse_ipc(struct qcom_smp2p *smp2p)
-{
-       struct device_node *syscon;
-       struct device *dev = smp2p->dev;
-       const char *key;
-       int ret;
-
-       syscon = of_parse_phandle(dev->of_node, "qcom,ipc", 0);
-       if (!syscon) {
-               dev_err(dev, "no qcom,ipc node\n");
-               return -ENODEV;
-       }
-
-       smp2p->ipc_regmap = syscon_node_to_regmap(syscon);
-       if (IS_ERR(smp2p->ipc_regmap))
-               return PTR_ERR(smp2p->ipc_regmap);
-
-       key = "qcom,ipc";
-       ret = of_property_read_u32_index(dev->of_node, key, 1, &smp2p->ipc_offset);
-       if (ret < 0) {
-               dev_err(dev, "no offset in %s\n", key);
-               return -EINVAL;
-       }
-
-       ret = of_property_read_u32_index(dev->of_node, key, 2, &smp2p->ipc_bit);
-       if (ret < 0) {
-               dev_err(dev, "no bit in %s\n", key);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int qcom_smp2p_probe(struct platform_device *pdev)
-{
-       struct smp2p_entry *entry;
-       struct device_node *node;
-       struct qcom_smp2p *smp2p;
-       const char *key;
-       int irq;
-       int ret;
-
-       smp2p = devm_kzalloc(&pdev->dev, sizeof(*smp2p), GFP_KERNEL);
-       if (!smp2p)
-               return -ENOMEM;
-
-       smp2p->dev = &pdev->dev;
-       INIT_LIST_HEAD(&smp2p->inbound);
-       INIT_LIST_HEAD(&smp2p->outbound);
-
-       platform_set_drvdata(pdev, smp2p);
-
-       ret = smp2p_parse_ipc(smp2p);
-       if (ret)
-               return ret;
-
-       key = "qcom,smem";
-       ret = of_property_read_u32_array(pdev->dev.of_node, key,
-                                        smp2p->smem_items, 2);
-       if (ret)
-               return ret;
-
-       key = "qcom,local-pid";
-       ret = of_property_read_u32(pdev->dev.of_node, key, &smp2p->local_pid);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to read %s\n", key);
-               return -EINVAL;
-       }
-
-       key = "qcom,remote-pid";
-       ret = of_property_read_u32(pdev->dev.of_node, key, &smp2p->remote_pid);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "failed to read %s\n", key);
-               return -EINVAL;
-       }
-
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(&pdev->dev, "unable to acquire smp2p interrupt\n");
-               return irq;
-       }
-
-       ret = qcom_smp2p_alloc_outbound_item(smp2p);
-       if (ret < 0)
-               return ret;
-
-       for_each_available_child_of_node(pdev->dev.of_node, node) {
-               entry = devm_kzalloc(&pdev->dev, sizeof(*entry), GFP_KERNEL);
-               if (!entry) {
-                       ret = -ENOMEM;
-                       goto unwind_interfaces;
-               }
-
-               entry->smp2p = smp2p;
-
-               ret = of_property_read_string(node, "qcom,entry-name", &entry->name);
-               if (ret < 0)
-                       goto unwind_interfaces;
-
-               if (of_property_read_bool(node, "qcom,inbound")) {
-                       ret = qcom_smp2p_inbound_entry(smp2p, entry, node);
-                       if (ret < 0)
-                               goto unwind_interfaces;
-
-                       list_add(&entry->node, &smp2p->inbound);
-               } else if (of_property_read_bool(node, "qcom,outbound")) {
-                       ret = qcom_smp2p_outbound_entry(smp2p, entry, node);
-                       if (ret < 0)
-                               goto unwind_interfaces;
-
-                       list_add(&entry->node, &smp2p->outbound);
-               } else {
-                       dev_err(&pdev->dev, "neither inbound nor outbound\n");
-                       ret = -EINVAL;
-                       goto unwind_interfaces;
-               }
-       }
-
-       /* Kick the outgoing edge after allocating entries */
-       qcom_smp2p_kick(smp2p);
-
-       ret = devm_request_threaded_irq(&pdev->dev, irq,
-                                       NULL, qcom_smp2p_intr,
-                                       IRQF_ONESHOT,
-                                       "smp2p", (void *)smp2p);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to request interrupt\n");
-               goto unwind_interfaces;
-       }
-
-
-       return 0;
-
-unwind_interfaces:
-       list_for_each_entry(entry, &smp2p->inbound, node)
-               irq_domain_remove(entry->domain);
-
-       list_for_each_entry(entry, &smp2p->outbound, node)
-               gpiochip_remove(&entry->chip);
-
-       smp2p->out->valid_entries = 0;
-
-       return ret;
-}
-
-static int qcom_smp2p_remove(struct platform_device *pdev)
-{
-       struct qcom_smp2p *smp2p = platform_get_drvdata(pdev);
-       struct smp2p_entry *entry;
-
-       list_for_each_entry(entry, &smp2p->inbound, node)
-               irq_domain_remove(entry->domain);
-
-       list_for_each_entry(entry, &smp2p->outbound, node)
-               gpiochip_remove(&entry->chip);
-
-       smp2p->out->valid_entries = 0;
-
-       return 0;
-}
-
-static const struct of_device_id qcom_smp2p_of_match[] = {
-       { .compatible = "qcom,smp2p" },
-       {}
-};
-MODULE_DEVICE_TABLE(of, qcom_smp2p_of_match);
-
-static struct platform_driver qcom_smp2p_driver = {
-       .probe = qcom_smp2p_probe,
-       .remove = qcom_smp2p_remove,
-       .driver  = {
-               .name  = "qcom_smp2p",
-               .of_match_table = qcom_smp2p_of_match,
-       },
-};
-module_platform_driver(qcom_smp2p_driver);
-
-MODULE_DESCRIPTION("Qualcomm Shared Memory Point to Point driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-qcom-smsm.c b/drivers/gpio/gpio-qcom-smsm.c
deleted file mode 100644 (file)
index c3e5103..0000000
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Copyright (c) 2014, Sony Mobile Communications AB.
- * Copyright (c) 2012-2013, 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/platform_device.h>
-#include <linux/of_platform.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/memblock.h>
-#include <linux/slab.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/hwspinlock.h>
-#include <linux/regmap.h>
-#include <linux/gpio.h>
-#include <linux/mfd/syscon.h>
-
-#include <linux/delay.h>
-
-#include <linux/soc/qcom/smem.h>
-
-#define SMSM_APPS_STATE 0
-#define SMEM_SMSM_SHARED_STATE 85
-
-#define SMSM_MAX_STATES 8
-
-struct qcom_smsm_state {
-       unsigned state_id;
-       struct gpio_chip chip;
-
-       int irq;
-
-       struct regmap *ipc_regmap;
-       int ipc_bit;
-       int ipc_offset;
-};
-
-struct qcom_smsm {
-       struct device *dev;
-
-       u32 *shared_state;
-       size_t shared_state_size;
-
-       struct qcom_smsm_state states[SMSM_MAX_STATES];
-};
-
-#if 0
-int qcom_smsm_change_state(struct qcom_smsm *smsm, u32 clear_mask, u32 set_mask)
-{
-       u32 state;
-
-       dev_dbg(smsm->dev, "SMSM_APPS_STATE clear 0x%x set 0x%x\n", clear_mask, set_mask);
-       print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_OFFSET, 16, 1, smsm->shared_state, smsm->shared_state_size, true);
-
-       state = readl(&smsm->shared_state[SMSM_APPS_STATE]);
-       state &= ~clear_mask;
-       state |= set_mask;
-       writel(state, &smsm->shared_state[SMSM_APPS_STATE]);
-
-       print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_OFFSET, 16, 1, smsm->shared_state, smsm->shared_state_size, true);
-
-       // qcom_smem_signal(-1, smsm->smem, smsm->signal_offset, smsm->signal_bit);
-
-       return 0;
-}
-EXPORT_SYMBOL(qcom_smsm_change_state);
-#endif
-
-static struct qcom_smsm_state *to_smsm_state(struct gpio_chip *chip)
-{
-       return container_of(chip, struct qcom_smsm_state, chip);
-}
-
-static struct qcom_smsm *to_smsm(struct qcom_smsm_state *state)
-{
-       return container_of(state, struct qcom_smsm, states[state->state_id]);
-}
-
-static int smsm_gpio_direction_input(struct gpio_chip *chip,
-                                    unsigned offset)
-{
-       struct qcom_smsm_state *state = to_smsm_state(chip);
-
-       if (state->state_id == SMSM_APPS_STATE)
-               return -EINVAL;
-       return 0;
-}
-
-static int smsm_gpio_direction_output(struct gpio_chip *chip,
-                                     unsigned offset,
-                                     int value)
-{
-       struct qcom_smsm_state *ipc_state;
-       struct qcom_smsm_state *state = to_smsm_state(chip);
-       struct qcom_smsm *smsm = to_smsm(state);
-       unsigned word;
-       unsigned bit;
-       u32 val;
-       int i;
-
-       /* Only SMSM_APPS_STATE supports writing */
-       if (state->state_id != SMSM_APPS_STATE)
-               return -EINVAL;
-
-       offset += state->state_id * 32;
-
-       word = ALIGN(offset / 32, 4);
-       bit = offset % 32;
-
-       val = readl(smsm->shared_state + word);
-       if (value)
-               val |= BIT(bit);
-       else
-               val &= ~BIT(bit);
-       writel(val, smsm->shared_state + word);
-
-       /* XXX: send out interrupts */
-       for (i = 0; i < SMSM_MAX_STATES; i++) {
-               ipc_state = &smsm->states[i];
-               if (!ipc_state->ipc_regmap)
-                       continue;
-
-               regmap_write(ipc_state->ipc_regmap, ipc_state->ipc_offset, BIT(ipc_state->ipc_bit));
-       }
-
-       dev_err(smsm->dev, "set %d %d\n", offset, value);
-
-       return 0;
-}
-
-static int smsm_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
-       struct qcom_smsm_state *state = to_smsm_state(chip);
-       struct qcom_smsm *smsm = to_smsm(state);
-       unsigned word;
-       unsigned bit;
-       u32 val;
-
-       offset += state->state_id * 32;
-
-       word = ALIGN(offset / 32, 4);
-       bit = offset % 32;
-
-       val = readl(smsm->shared_state + word);
-
-       return !!(val & BIT(bit));
-}
-
-static void smsm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
-       smsm_gpio_direction_output(chip, offset, value);
-}
-
-static int smsm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
-       return -EINVAL;
-}
-
-#ifdef CONFIG_DEBUG_FS
-#include <linux/seq_file.h>
-
-static void smsm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
-{
-       struct qcom_smsm_state *state = to_smsm_state(chip);
-       struct qcom_smsm *smsm = to_smsm(state);
-       unsigned i;
-       u32 val;
-
-       val = readl(smsm->shared_state + state->state_id * 4);
-
-       for (i = 0; i < 32; i++) {
-               if (val & BIT(i))
-                       seq_puts(s, "1");
-               else
-                       seq_puts(s, "0");
-
-               if (i == 7 || i == 15 || i == 23)
-                       seq_puts(s, " ");
-       }
-       seq_puts(s, "\n");
-}
-
-#else
-#define smsm_gpio_dbg_show NULL
-#endif
-
-static struct gpio_chip smsm_gpio_template = {
-       .direction_input = smsm_gpio_direction_input,
-       .direction_output = smsm_gpio_direction_output,
-       .get = smsm_gpio_get,
-       .set = smsm_gpio_set,
-       .to_irq = smsm_gpio_to_irq,
-       .dbg_show = smsm_gpio_dbg_show,
-       .owner = THIS_MODULE,
-};
-
-static int qcom_smsm_probe(struct platform_device *pdev)
-{
-       struct qcom_smsm_state *state;
-       struct device_node *syscon_np;
-       struct device_node *node;
-       struct qcom_smsm *smsm;
-       char *key;
-       u32 sid;
-       int ret;
-
-       smsm = devm_kzalloc(&pdev->dev, sizeof(*smsm), GFP_KERNEL);
-       if (!smsm)
-               return -ENOMEM;
-       smsm->dev = &pdev->dev;
-
-       ret = qcom_smem_alloc(-1, SMEM_SMSM_SHARED_STATE, 8 * sizeof(uint32_t));
-       if (ret < 0 && ret != -EEXIST) {
-               dev_err(&pdev->dev, "unable to allocate shared state entry\n");
-               return ret;
-       }
-
-       smsm->shared_state = qcom_smem_get(-1, SMEM_SMSM_SHARED_STATE,
-                           &smsm->shared_state_size);
-       if (IS_ERR(smsm->shared_state)) {
-               dev_err(&pdev->dev, "Unable to acquire shared state entry\n");
-               return PTR_ERR(smsm->shared_state);
-       }
-
-       dev_err(smsm->dev, "SMEM_SMSM_SHARED_STATE: %d, %zu\n", ret, smsm->shared_state_size);
-       print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_OFFSET, 16, 1, smsm->shared_state, smsm->shared_state_size, true);
-
-       for_each_child_of_node(pdev->dev.of_node, node) {
-               key = "reg";
-               ret = of_property_read_u32(node, key, &sid);
-               if (ret || sid >= SMSM_MAX_STATES) {
-                       dev_err(&pdev->dev, "smsm state missing %s\n", key);
-                       return -EINVAL;
-               }
-               state = &smsm->states[sid];
-               state->state_id = sid;
-
-               state->chip = smsm_gpio_template;
-               state->chip.base = -1;
-               state->chip.dev = &pdev->dev;
-               state->chip.of_node = node;
-               state->chip.label = node->name;
-               state->chip.ngpio = 8 * sizeof(u32);
-               ret = gpiochip_add(&state->chip);
-               if (ret) {
-                       dev_err(&pdev->dev, "failed register gpiochip\n");
-                       // goto wooha;
-               }
-
-               /* The remaining properties are only for non-apps state */
-               if (sid == SMSM_APPS_STATE)
-                       continue;
-
-               state->irq = irq_of_parse_and_map(node, 0);
-               if (state->irq < 0 && state->irq != -EINVAL) {
-                       dev_err(&pdev->dev, "failed to parse smsm interrupt\n");
-                       return -EINVAL;
-               }
-
-               syscon_np = of_parse_phandle(node, "qcom,ipc", 0);
-               if (!syscon_np) {
-                       dev_err(&pdev->dev, "no qcom,ipc node\n");
-                       return -ENODEV;
-               }
-
-               state->ipc_regmap = syscon_node_to_regmap(syscon_np);
-               if (IS_ERR(state->ipc_regmap))
-                       return PTR_ERR(state->ipc_regmap);
-
-               key = "qcom,ipc";
-               ret = of_property_read_u32_index(node, key, 1, &state->ipc_offset);
-               if (ret < 0) {
-                       dev_err(&pdev->dev, "no offset in %s\n", key);
-                       return -EINVAL;
-               }
-
-               ret = of_property_read_u32_index(node, key, 2, &state->ipc_bit);
-               if (ret < 0) {
-                       dev_err(&pdev->dev, "no bit in %s\n", key);
-                       return -EINVAL;
-               }
-
-       }
-
-       return 0;
-}
-
-static const struct of_device_id qcom_smsm_of_match[] = {
-       { .compatible = "qcom,smsm" },
-       {}
-};
-MODULE_DEVICE_TABLE(of, qcom_smsm_of_match);
-
-static struct platform_driver qcom_smsm_driver = {
-       .probe          = qcom_smsm_probe,
-       .driver  = {
-               .name  = "qcom_smsm",
-               .owner = THIS_MODULE,
-               .of_match_table = qcom_smsm_of_match,
-       },
-};
-
-static int __init qcom_smsm_init(void)
-{
-       return platform_driver_register(&qcom_smsm_driver);
-}
-arch_initcall(qcom_smsm_init);
-
-static void __exit qcom_smsm_exit(void)
-{
-       platform_driver_unregister(&qcom_smsm_driver);
-}
-module_exit(qcom_smsm_exit)
-
-MODULE_DESCRIPTION("Qualcomm Shared Memory Signaling Mechanism");
-MODULE_LICENSE("GPLv2");
index 591ebaea826564bf339f82b8152394dca022b5e8..394fe5b77c904b92fcd494e86eaad7863a49fe72 100644 (file)
@@ -1,6 +1,6 @@
 config WCN36XX
        tristate "Qualcomm Atheros WCN3660/3680 support"
-       depends on MAC80211 && HAS_DMA
+       depends on MAC80211 && HAS_DMA && QCOM_SMD
        ---help---
          This module adds support for wireless adapters based on
          Qualcomm Atheros WCN3660 and WCN3680 mobile chipsets.
index 9f6370f0cabc199234128a9693f586d0202beeaf..50c43b4382bacd91c9ff8380a1af0eaaafea5ba1 100644 (file)
@@ -1,10 +1,7 @@
-obj-$(CONFIG_WCN36XX) := wcn36xx.o wcn36xx-platform.o
+obj-$(CONFIG_WCN36XX) := wcn36xx.o
 wcn36xx-y +=   main.o \
                dxe.o \
                txrx.o \
                smd.o \
                pmc.o \
                debug.o
-
-wcn36xx-platform-y     += wcn36xx-msm.o\
-       wcnss_core.o
index af0e515f634da99f002c07c859a9822b5818a34f..87dfdaf9044cdf8b41aba6b8345e9d2f9dd325a6 100644 (file)
@@ -23,6 +23,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/interrupt.h>
+#include <linux/soc/qcom/smem_state.h>
 #include "wcn36xx.h"
 #include "txrx.h"
 
@@ -35,26 +36,27 @@ void *wcn36xx_dxe_get_next_bd(struct wcn36xx *wcn, bool is_low)
        return ch->head_blk_ctl->bd_cpu_addr;
 }
 
+static void wcn36xx_ccu_write_register(struct wcn36xx *wcn, int addr, int data)
+{
+       wcn36xx_dbg(WCN36XX_DBG_DXE,
+                   "wcn36xx_ccu_write_register: addr=%x, data=%x\n",
+                   addr, data);
+
+       writel(data, wcn->ccu_base + addr);
+}
+
 static void wcn36xx_dxe_write_register(struct wcn36xx *wcn, int addr, int data)
 {
        wcn36xx_dbg(WCN36XX_DBG_DXE,
                    "wcn36xx_dxe_write_register: addr=%x, data=%x\n",
                    addr, data);
 
-       writel(data, wcn->mmio + addr);
+       writel(data, wcn->dxe_base + addr);
 }
 
-#define wcn36xx_dxe_write_register_x(wcn, reg, reg_data)                \
-do {                                                                    \
-       if (wcn->chip_version != WCN36XX_CHIP_3660)                      \
-               wcn36xx_dxe_write_register(wcn, reg ## _3680, reg_data); \
-       else                                                             \
-               wcn36xx_dxe_write_register(wcn, reg ## _3660, reg_data); \
-} while (0)                                                             \
-
 static void wcn36xx_dxe_read_register(struct wcn36xx *wcn, int addr, int *data)
 {
-       *data = readl(wcn->mmio + addr);
+       *data = readl(wcn->dxe_base + addr);
 
        wcn36xx_dbg(WCN36XX_DBG_DXE,
                    "wcn36xx_dxe_read_register: addr=%x, data=%x\n",
@@ -150,9 +152,12 @@ int wcn36xx_dxe_alloc_ctl_blks(struct wcn36xx *wcn)
                goto out_err;
 
        /* Initialize SMSM state  Clear TX Enable RING EMPTY STATE */
-       ret = wcn->ctrl_ops->smsm_change_state(
-               WCN36XX_SMSM_WLAN_TX_ENABLE,
-               WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY);
+       ret = qcom_smem_state_update_bits(wcn->tx_enable_state,
+                                         WCN36XX_SMSM_WLAN_TX_ENABLE |
+                                         WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY,
+                                         WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY);
+       if (ret)
+               goto out_err;
 
        return 0;
 
@@ -677,9 +682,9 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
         * notify chip about new frame through SMSM bus.
         */
        if (is_low &&  vif_priv->pw_state == WCN36XX_BMPS) {
-               wcn->ctrl_ops->smsm_change_state(
-                                 0,
-                                 WCN36XX_SMSM_WLAN_TX_ENABLE);
+               qcom_smem_state_update_bits(wcn->tx_rings_empty_state,
+                                           WCN36XX_SMSM_WLAN_TX_ENABLE,
+                                           WCN36XX_SMSM_WLAN_TX_ENABLE);
        } else {
                /* indicate End Of Packet and generate interrupt on descriptor
                 * done.
@@ -701,9 +706,13 @@ int wcn36xx_dxe_init(struct wcn36xx *wcn)
        reg_data = WCN36XX_DXE_REG_RESET;
        wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_REG_CSR_RESET, reg_data);
 
-       /* Setting interrupt path */
-       reg_data = WCN36XX_DXE_CCU_INT;
-       wcn36xx_dxe_write_register_x(wcn, WCN36XX_DXE_REG_CCU_INT, reg_data);
+       /* Select channels for rx avail and xfer done interrupts... */
+       reg_data = (WCN36XX_DXE_INT_CH3_MASK | WCN36XX_DXE_INT_CH1_MASK) << 16 |
+                   WCN36XX_DXE_INT_CH0_MASK | WCN36XX_DXE_INT_CH4_MASK;
+       if (wcn->is_pronto)
+               wcn36xx_ccu_write_register(wcn, WCN36XX_CCU_DXE_INT_SELECT_PRONTO, reg_data);
+       else
+               wcn36xx_ccu_write_register(wcn, WCN36XX_CCU_DXE_INT_SELECT_RIVA, reg_data);
 
        /***************************************/
        /* Init descriptors for TX LOW channel */
index 3eca4f9594f2a3a3c638996fd13daae66e473283..c012e807753b763112a1be05b046b71f2d51087f 100644 (file)
@@ -28,11 +28,10 @@ H2H_TEST_RX_TX = DMA2
 */
 
 /* DXE registers */
-#define WCN36XX_DXE_MEM_REG                    0x202000
+#define WCN36XX_DXE_MEM_REG                    0
 
-#define WCN36XX_DXE_CCU_INT                    0xA0011
-#define WCN36XX_DXE_REG_CCU_INT_3660           0x200b10
-#define WCN36XX_DXE_REG_CCU_INT_3680           0x2050dc
+#define WCN36XX_CCU_DXE_INT_SELECT_RIVA                0x310
+#define WCN36XX_CCU_DXE_INT_SELECT_PRONTO      0x10dc
 
 /* TODO This must calculated properly but not hardcoded */
 #define WCN36XX_DXE_CTRL_TX_L                  0x328a44
index dbf1769a969920875e198436214eff8906c0a59d..4f87ef1e1eb866808ecc0b071b28d7bd4bbaeff1 100644 (file)
@@ -51,7 +51,7 @@
 #define WCN36XX_HAL_STA_INVALID_IDX 0xFF
 #define WCN36XX_HAL_BSS_INVALID_IDX 0xFF
 
-/* Default Beacon template size. */
+/* Default Beacon template size */
 #define BEACON_TEMPLATE_SIZE 0x180
 
 /* Minimum PVM size that the FW expects. See comment in smd.c for details. */
@@ -350,8 +350,6 @@ enum wcn36xx_hal_host_msg_type {
 
        WCN36XX_HAL_AVOID_FREQ_RANGE_IND = 233,
 
-       WCN36XX_HAL_PRINT_REG_INFO_IND = 259,
-
        WCN36XX_HAL_MSG_MAX = WCN36XX_HAL_MSG_TYPE_MAX_ENUM_SIZE
 };
 
@@ -2889,11 +2887,13 @@ struct update_beacon_rsp_msg {
 struct wcn36xx_hal_send_beacon_req_msg {
        struct wcn36xx_hal_msg_header header;
 
-       /* length of the template + sizeof(beacon_length) */
-       u32 template_length;
+       /* length of the template + 6. Only qcom knows why */
+       u32 beacon_length6;
 
-       /* Beacon data. */
+       /* length of the template. */
        u32 beacon_length;
+
+       /* Beacon data. */
        u8 beacon[BEACON_TEMPLATE_SIZE - sizeof(u32)];
 
        u8 bssid[ETH_ALEN];
@@ -4123,7 +4123,7 @@ struct wcn36xx_hal_update_scan_params_req {
 
 /* Update scan params - sent from host to PNO to be used during PNO
  * scanningx */
-struct update_scan_params_req_ex {
+struct wcn36xx_hal_update_scan_params_req_ex {
 
        struct wcn36xx_hal_msg_header header;
 
@@ -4151,7 +4151,7 @@ struct update_scan_params_req_ex {
 
        /* Cb State */
        enum phy_chan_bond_state state;
-};
+} __packed;
 
 /* Update scan params - sent from host to PNO to be used during PNO
  * scanningx */
index cc4903cdc666b0cf16553d9dc9764dd7de5c0854..2d9402e718fc6aafd4bda5787e5ad2cded519e50 100644 (file)
 #include <linux/module.h>
 #include <linux/firmware.h>
 #include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/soc/qcom/smd.h>
+#include <linux/soc/qcom/smem_state.h>
+#include <linux/soc/qcom/wcnss_ctrl.h>
 #include "wcn36xx.h"
 
 unsigned int wcn36xx_dbg_mask;
@@ -26,14 +32,14 @@ module_param_named(debug_mask, wcn36xx_dbg_mask, uint, 0644);
 MODULE_PARM_DESC(debug_mask, "Debugging mask");
 
 #define CHAN2G(_freq, _idx) { \
-       .band = IEEE80211_BAND_2GHZ, \
+       .band = NL80211_BAND_2GHZ, \
        .center_freq = (_freq), \
        .hw_value = (_idx), \
        .max_power = 25, \
 }
 
 #define CHAN5G(_freq, _idx) { \
-       .band = IEEE80211_BAND_5GHZ, \
+       .band = NL80211_BAND_5GHZ, \
        .center_freq = (_freq), \
        .hw_value = (_idx), \
        .max_power = 25, \
@@ -313,8 +319,6 @@ static int wcn36xx_start(struct ieee80211_hw *hw)
                        wcn36xx_feat_caps_info(wcn);
        }
 
-       wcn36xx_smd_update_cfg(wcn, WCN36XX_HAL_CFG_ENABLE_MC_ADDR_LIST, 1);
-
        /* DMA channel initialization */
        ret = wcn36xx_dxe_init(wcn);
        if (ret) {
@@ -381,8 +385,6 @@ static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed)
        return 0;
 }
 
-#define WCN36XX_SUPPORTED_FILTERS (FIF_ALLMULTI)
-
 static void wcn36xx_configure_filter(struct ieee80211_hw *hw,
                                     unsigned int changed,
                                     unsigned int *total, u64 multicast)
@@ -394,7 +396,7 @@ static void wcn36xx_configure_filter(struct ieee80211_hw *hw,
 
        wcn36xx_dbg(WCN36XX_DBG_MAC, "mac configure filter\n");
 
-       *total &= WCN36XX_SUPPORTED_FILTERS;
+       *total &= FIF_ALLMULTI;
 
        fp = (void *)(unsigned long)multicast;
        list_for_each_entry(tmp, &wcn->vif_list, list) {
@@ -566,27 +568,61 @@ out:
        return ret;
 }
 
-static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw,
-                                 struct ieee80211_vif *vif,
-                                 const u8 *mac_addr)
+static void wcn36xx_hw_scan_worker(struct work_struct *work)
 {
-       struct wcn36xx *wcn = hw->priv;
+       struct wcn36xx *wcn = container_of(work, struct wcn36xx, scan_work);
+       struct cfg80211_scan_request *req = wcn->scan_req;
+       u8 channels[WCN36XX_HAL_PNO_MAX_NETW_CHANNELS_EX];
+       int i;
+
+       wcn36xx_dbg(WCN36XX_DBG_MAC, "mac80211 scan %d channels worker\n", req->n_channels);
+
+       for (i = 0; i < req->n_channels; i++)
+               channels[i] = req->channels[i]->hw_value;
+
+       wcn36xx_smd_update_scan_params(wcn, channels, req->n_channels);
 
        wcn36xx_smd_init_scan(wcn, HAL_SYS_MODE_SCAN);
-       wcn36xx_smd_start_scan(wcn);
+       for (i = 0; i < req->n_channels; i++) {
+               wcn->scan_freq = req->channels[i]->center_freq;
+               wcn->scan_band = req->channels[i]->band;
+
+               wcn36xx_smd_start_scan(wcn, req->channels[i]->hw_value);
+               msleep(30);
+               wcn36xx_smd_end_scan(wcn, req->channels[i]->hw_value);
+
+               wcn->scan_freq = 0;
+       }
+       wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN);
+
+       ieee80211_scan_completed(wcn->hw, false);
+
+       mutex_lock(&wcn->scan_lock);
+       wcn->scan_req = NULL;
+       mutex_unlock(&wcn->scan_lock);
 }
 
-static void wcn36xx_sw_scan_complete(struct ieee80211_hw *hw,
-                                    struct ieee80211_vif *vif)
+static int wcn36xx_hw_scan(struct ieee80211_hw *hw,
+                          struct ieee80211_vif *vif,
+                          struct ieee80211_scan_request *hw_req)
 {
        struct wcn36xx *wcn = hw->priv;
 
-       wcn36xx_smd_end_scan(wcn);
-       wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN);
+       mutex_lock(&wcn->scan_lock);
+       if (wcn->scan_req) {
+               mutex_unlock(&wcn->scan_lock);
+               return -EBUSY;
+       }
+       wcn->scan_req = &hw_req->req;
+       mutex_unlock(&wcn->scan_lock);
+
+       schedule_work(&wcn->scan_work);
+
+       return 0;
 }
 
 static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta,
-                                        enum ieee80211_band band)
+                                        enum nl80211_band band)
 {
        int i, size;
        u16 *rates_table;
@@ -599,7 +635,7 @@ static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta,
 
        size = ARRAY_SIZE(sta_priv->supported_rates.dsss_rates);
        rates_table = sta_priv->supported_rates.dsss_rates;
-       if (band == IEEE80211_BAND_2GHZ) {
+       if (band == NL80211_BAND_2GHZ) {
                for (i = 0; i < size; i++) {
                        if (rates & 0x01) {
                                rates_table[i] = wcn_2ghz_rates[i].hw_value;
@@ -993,8 +1029,7 @@ static const struct ieee80211_ops wcn36xx_ops = {
        .configure_filter       = wcn36xx_configure_filter,
        .tx                     = wcn36xx_tx,
        .set_key                = wcn36xx_set_key,
-       .sw_scan_start          = wcn36xx_sw_scan_start,
-       .sw_scan_complete       = wcn36xx_sw_scan_complete,
+       .hw_scan                = wcn36xx_hw_scan,
        .bss_info_changed       = wcn36xx_bss_info_changed,
        .set_rts_threshold      = wcn36xx_set_rts_threshold,
        .sta_add                = wcn36xx_sta_add,
@@ -1019,18 +1054,18 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
        ieee80211_hw_set(wcn->hw, SUPPORTS_PS);
        ieee80211_hw_set(wcn->hw, SIGNAL_DBM);
        ieee80211_hw_set(wcn->hw, HAS_RATE_CONTROL);
-
-       /* 3620 powersaving currently unstable */
-       if (wcn->chip_version == WCN36XX_CHIP_3620)
-               __clear_bit(IEEE80211_HW_SUPPORTS_PS, wcn->hw->flags);
+       ieee80211_hw_set(wcn->hw, SINGLE_SCAN_ON_ALL_BANDS);
 
        wcn->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
                BIT(NL80211_IFTYPE_AP) |
                BIT(NL80211_IFTYPE_ADHOC) |
                BIT(NL80211_IFTYPE_MESH_POINT);
 
-       wcn->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wcn_band_2ghz;
-       wcn->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wcn_band_5ghz;
+       wcn->hw->wiphy->bands[NL80211_BAND_2GHZ] = &wcn_band_2ghz;
+       wcn->hw->wiphy->bands[NL80211_BAND_5GHZ] = &wcn_band_5ghz;
+
+       wcn->hw->wiphy->max_scan_ssids = WCN36XX_MAX_SCAN_SSIDS;
+       wcn->hw->wiphy->max_scan_ie_len = WCN36XX_MAX_SCAN_IE_LEN;
 
        wcn->hw->wiphy->cipher_suites = cipher_suites;
        wcn->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
@@ -1059,10 +1094,13 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
 static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
                                          struct platform_device *pdev)
 {
+       struct device_node *mmio_node;
        struct resource *res;
+       int index;
+       int ret;
+
        /* Set TX IRQ */
-       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
-                                          "wcnss_wlantx_irq");
+       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "tx");
        if (!res) {
                wcn36xx_err("failed to get tx_irq\n");
                return -ENOENT;
@@ -1070,38 +1108,77 @@ static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
        wcn->tx_irq = res->start;
 
        /* Set RX IRQ */
-       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
-                                          "wcnss_wlanrx_irq");
+       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "rx");
        if (!res) {
                wcn36xx_err("failed to get rx_irq\n");
                return -ENOENT;
        }
        wcn->rx_irq = res->start;
 
-       /* Map the memory */
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-                                                "wcnss_mmio");
-       if (!res) {
-               wcn36xx_err("failed to get mmio\n");
+       /* Acquire SMSM tx enable handle */
+       wcn->tx_enable_state = qcom_smem_state_get(&pdev->dev,
+                       "tx-enable", &wcn->tx_enable_state_bit);
+       if (IS_ERR(wcn->tx_enable_state)) {
+               wcn36xx_err("failed to get tx-enable state\n");
                return -ENOENT;
        }
-       wcn->mmio = ioremap(res->start, resource_size(res));
-       if (!wcn->mmio) {
-               wcn36xx_err("failed to map io memory\n");
-               return -ENOMEM;
+
+       /* Acquire SMSM tx rings empty handle */
+       wcn->tx_rings_empty_state = qcom_smem_state_get(&pdev->dev,
+                       "tx-rings-empty", &wcn->tx_rings_empty_state_bit);
+       if (IS_ERR(wcn->tx_rings_empty_state)) {
+               wcn36xx_err("failed to get tx-rings-empty state\n");
+               return -ENOENT;
+       }
+
+       mmio_node = of_parse_phandle(pdev->dev.parent->of_node, "qcom,mmio", 0);
+       if (!mmio_node) {
+               wcn36xx_err("failed to acquire qcom,mmio reference\n");
+               return -EINVAL;
+       }
+
+       wcn->is_pronto = !!of_device_is_compatible(mmio_node, "qcom,pronto");
+
+       /* Map the CCU memory */
+       index = of_property_match_string(mmio_node, "reg-names", "ccu");
+       wcn->ccu_base = of_iomap(mmio_node, index);
+       if (!wcn->ccu_base) {
+               wcn36xx_err("failed to map ccu memory\n");
+               ret = -ENOMEM;
+               goto put_mmio_node;
+       }
+
+       /* Map the DXE memory */
+       index = of_property_match_string(mmio_node, "reg-names", "dxe");
+       wcn->dxe_base = of_iomap(mmio_node, index);
+       if (!wcn->dxe_base) {
+               wcn36xx_err("failed to map dxe memory\n");
+               ret = -ENOMEM;
+               goto unmap_ccu;
        }
+
+       of_node_put(mmio_node);
        return 0;
+
+unmap_ccu:
+       iounmap(wcn->ccu_base);
+put_mmio_node:
+       of_node_put(mmio_node);
+       return ret;
 }
 
 static int wcn36xx_probe(struct platform_device *pdev)
 {
        struct ieee80211_hw *hw;
        struct wcn36xx *wcn;
+       void *wcnss;
        int ret;
-       u8 addr[ETH_ALEN];
+       const u8 *addr;
 
        wcn36xx_dbg(WCN36XX_DBG_MAC, "platform probe\n");
 
+       wcnss = dev_get_drvdata(pdev->dev.parent);
+
        hw = ieee80211_alloc_hw(sizeof(struct wcn36xx), &wcn36xx_ops);
        if (!hw) {
                wcn36xx_err("failed to alloc hw\n");
@@ -1112,25 +1189,26 @@ static int wcn36xx_probe(struct platform_device *pdev)
        wcn = hw->priv;
        wcn->hw = hw;
        wcn->dev = &pdev->dev;
-       wcn->dev->dma_mask = kzalloc(sizeof(*wcn->dev->dma_mask), GFP_KERNEL);
-       if (!wcn->dev->dma_mask) {
-               ret = -ENOMEM;
-               goto dma_mask_err;
-       }
-       dma_set_mask_and_coherent(wcn->dev, DMA_BIT_MASK(32));
-       wcn->wcn36xx_data = pdev->dev.platform_data;
-       wcn->ctrl_ops = &wcn->wcn36xx_data->ctrl_ops;
-       wcn->wcn36xx_data->wcn = wcn;
-       if (!wcn->ctrl_ops->get_chip_type) {
-               dev_err(&pdev->dev, "Missing ops->get_chip_type\n");
-               ret = -EINVAL;
+       mutex_init(&wcn->hal_mutex);
+       mutex_init(&wcn->scan_lock);
+
+       INIT_WORK(&wcn->scan_work, wcn36xx_hw_scan_worker);
+
+       wcn->smd_channel = qcom_wcnss_open_channel(wcnss, "WLAN_CTRL", wcn36xx_smd_rsp_process);
+       if (IS_ERR(wcn->smd_channel)) {
+               wcn36xx_err("failed to open WLAN_CTRL channel\n");
+               ret = PTR_ERR(wcn->smd_channel);
                goto out_wq;
        }
-       wcn->chip_version = wcn->ctrl_ops->get_chip_type(wcn);
 
-       mutex_init(&wcn->hal_mutex);
+       qcom_smd_set_drvdata(wcn->smd_channel, hw);
 
-       if (!wcn->ctrl_ops->get_hw_mac(wcn, addr)) {
+       addr = of_get_property(pdev->dev.of_node, "local-mac-address", &ret);
+       if (addr && ret != ETH_ALEN) {
+               wcn36xx_err("invalid local-mac-address\n");
+               ret = -EINVAL;
+               goto out_wq;
+       } else if (addr) {
                wcn36xx_info("mac address: %pM\n", addr);
                SET_IEEE80211_PERM_ADDR(wcn->hw, addr);
        }
@@ -1147,14 +1225,14 @@ static int wcn36xx_probe(struct platform_device *pdev)
        return 0;
 
 out_unmap:
-       iounmap(wcn->mmio);
+       iounmap(wcn->ccu_base);
+       iounmap(wcn->dxe_base);
 out_wq:
-       kfree(wcn->dev->dma_mask);
-dma_mask_err:
        ieee80211_free_hw(hw);
 out_err:
        return ret;
 }
+
 static int wcn36xx_remove(struct platform_device *pdev)
 {
        struct ieee80211_hw *hw = platform_get_drvdata(pdev);
@@ -1165,41 +1243,33 @@ static int wcn36xx_remove(struct platform_device *pdev)
        mutex_destroy(&wcn->hal_mutex);
 
        ieee80211_unregister_hw(hw);
-       iounmap(wcn->mmio);
+
+       qcom_smem_state_put(wcn->tx_enable_state);
+       qcom_smem_state_put(wcn->tx_rings_empty_state);
+
+       iounmap(wcn->dxe_base);
+       iounmap(wcn->ccu_base);
        ieee80211_free_hw(hw);
 
        return 0;
 }
-static const struct platform_device_id wcn36xx_platform_id_table[] = {
-       {
-               .name = "wcn36xx",
-               .driver_data = 0
-       },
+
+static const struct of_device_id wcn36xx_of_match[] = {
+       { .compatible = "qcom,wcnss-wlan" },
        {}
 };
-MODULE_DEVICE_TABLE(platform, wcn36xx_platform_id_table);
+MODULE_DEVICE_TABLE(of, wcn36xx_of_match);
 
 static struct platform_driver wcn36xx_driver = {
        .probe      = wcn36xx_probe,
        .remove     = wcn36xx_remove,
        .driver         = {
                .name   = "wcn36xx",
+               .of_match_table = wcn36xx_of_match,
        },
-       .id_table    = wcn36xx_platform_id_table,
 };
 
-static int __init wcn36xx_init(void)
-{
-       platform_driver_register(&wcn36xx_driver);
-       return 0;
-}
-module_init(wcn36xx_init);
-
-static void __exit wcn36xx_exit(void)
-{
-       platform_driver_unregister(&wcn36xx_driver);
-}
-module_exit(wcn36xx_exit);
+module_platform_driver(wcn36xx_driver);
 
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com");
index 61754967e2effc5429515ffc35ca25ba4f5cde01..87a62eb6228cab3352e79f166e5824e5f478426e 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/etherdevice.h>
 #include <linux/firmware.h>
 #include <linux/bitops.h>
+#include <linux/soc/qcom/smd.h>
 #include "smd.h"
 
 struct wcn36xx_cfg_val {
@@ -104,11 +105,11 @@ static void wcn36xx_smd_set_bss_nw_type(struct wcn36xx *wcn,
                struct ieee80211_sta *sta,
                struct wcn36xx_hal_config_bss_params *bss_params)
 {
-       if (IEEE80211_BAND_5GHZ == WCN36XX_BAND(wcn))
+       if (NL80211_BAND_5GHZ == WCN36XX_BAND(wcn))
                bss_params->nw_type = WCN36XX_HAL_11A_NW_TYPE;
        else if (sta && sta->ht_cap.ht_supported)
                bss_params->nw_type = WCN36XX_HAL_11N_NW_TYPE;
-       else if (sta && (sta->supp_rates[IEEE80211_BAND_2GHZ] & 0x7f))
+       else if (sta && (sta->supp_rates[NL80211_BAND_2GHZ] & 0x7f))
                bss_params->nw_type = WCN36XX_HAL_11G_NW_TYPE;
        else
                bss_params->nw_type = WCN36XX_HAL_11B_NW_TYPE;
@@ -253,7 +254,7 @@ static int wcn36xx_smd_send_and_wait(struct wcn36xx *wcn, size_t len)
 
        init_completion(&wcn->hal_rsp_compl);
        start = jiffies;
-       ret = wcn->ctrl_ops->tx(wcn, wcn->hal_buf, len);
+       ret = qcom_smd_send(wcn->smd_channel, wcn->hal_buf, len);
        if (ret) {
                wcn36xx_err("HAL TX failed\n");
                goto out;
@@ -521,7 +522,7 @@ out:
        return ret;
 }
 
-int wcn36xx_smd_start_scan(struct wcn36xx *wcn)
+int wcn36xx_smd_start_scan(struct wcn36xx *wcn, u8 scan_channel)
 {
        struct wcn36xx_hal_start_scan_req_msg msg_body;
        int ret = 0;
@@ -529,7 +530,7 @@ int wcn36xx_smd_start_scan(struct wcn36xx *wcn)
        mutex_lock(&wcn->hal_mutex);
        INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_SCAN_REQ);
 
-       msg_body.scan_channel = WCN36XX_HW_CHANNEL(wcn);
+       msg_body.scan_channel = scan_channel;
 
        PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
 
@@ -551,7 +552,7 @@ out:
        return ret;
 }
 
-int wcn36xx_smd_end_scan(struct wcn36xx *wcn)
+int wcn36xx_smd_end_scan(struct wcn36xx *wcn, u8 scan_channel)
 {
        struct wcn36xx_hal_end_scan_req_msg msg_body;
        int ret = 0;
@@ -559,7 +560,7 @@ int wcn36xx_smd_end_scan(struct wcn36xx *wcn)
        mutex_lock(&wcn->hal_mutex);
        INIT_HAL_MSG(msg_body, WCN36XX_HAL_END_SCAN_REQ);
 
-       msg_body.scan_channel = WCN36XX_HW_CHANNEL(wcn);
+       msg_body.scan_channel = scan_channel;
 
        PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
 
@@ -674,22 +675,25 @@ static int wcn36xx_smd_update_scan_params_rsp(void *buf, size_t len)
        return 0;
 }
 
-int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn)
+int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn,
+                                  u8 *channels, size_t channel_count)
 {
-       struct wcn36xx_hal_update_scan_params_req msg_body;
+       struct wcn36xx_hal_update_scan_params_req_ex msg_body;
        int ret = 0;
 
        mutex_lock(&wcn->hal_mutex);
        INIT_HAL_MSG(msg_body, WCN36XX_HAL_UPDATE_SCAN_PARAM_REQ);
 
-       msg_body.dot11d_enabled = 0;
-       msg_body.dot11d_resolved = 0;
-       msg_body.channel_count = 26;
+       msg_body.dot11d_enabled = false;
+       msg_body.dot11d_resolved = true;
+
+       msg_body.channel_count = channel_count;
+       memcpy(msg_body.channels, channels, channel_count);
        msg_body.active_min_ch_time = 60;
        msg_body.active_max_ch_time = 120;
        msg_body.passive_min_ch_time = 60;
        msg_body.passive_max_ch_time = 110;
-       msg_body.state = 0;
+       msg_body.state = PHY_SINGLE_CHANNEL_CENTERED;
 
        PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
 
@@ -1388,7 +1392,6 @@ int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct ieee80211_vif *vif,
 {
        struct wcn36xx_hal_send_beacon_req_msg msg_body;
        int ret = 0, pad, pvm_len;
-       u32 beacon_length;
 
        mutex_lock(&wcn->hal_mutex);
        INIT_HAL_MSG(msg_body, WCN36XX_HAL_SEND_BEACON_REQ);
@@ -1400,16 +1403,16 @@ int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct ieee80211_vif *vif,
        if (vif->type == NL80211_IFTYPE_MESH_POINT)
                pad = 0;
 
-       beacon_length = skb_beacon->len + pad;
-       msg_body.template_length = beacon_length + sizeof(beacon_length);
+       msg_body.beacon_length = skb_beacon->len + pad;
+       /* TODO need to find out why + 6 is needed */
+       msg_body.beacon_length6 = msg_body.beacon_length + 6;
 
-       if (msg_body.template_length > BEACON_TEMPLATE_SIZE) {
+       if (msg_body.beacon_length > BEACON_TEMPLATE_SIZE) {
                wcn36xx_err("Beacon is to big: beacon size=%d\n",
-                             msg_body.template_length);
+                             msg_body.beacon_length);
                ret = -ENOMEM;
                goto out;
        }
-       msg_body.beacon_length = beacon_length;
        memcpy(msg_body.beacon, skb_beacon->data, skb_beacon->len);
        memcpy(msg_body.bssid, vif->addr, ETH_ALEN);
 
@@ -2178,13 +2181,18 @@ out:
        return ret;
 }
 
-static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
+int wcn36xx_smd_rsp_process(struct qcom_smd_channel *channel,
+                           const void *buf, size_t len)
 {
-       struct wcn36xx_hal_msg_header *msg_header = buf;
+       struct wcn36xx_hal_msg_header msg_header;
+       struct ieee80211_hw *hw = qcom_smd_get_drvdata(channel);
+       struct wcn36xx *wcn = hw->priv;
        struct wcn36xx_hal_ind_msg *msg_ind;
        wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "SMD <<< ", buf, len);
 
-       switch (msg_header->msg_type) {
+       memcpy_fromio(&msg_header, buf, sizeof(struct wcn36xx_hal_msg_header));
+
+       switch (msg_header.msg_type) {
        case WCN36XX_HAL_START_RSP:
        case WCN36XX_HAL_CONFIG_STA_RSP:
        case WCN36XX_HAL_CONFIG_BSS_RSP:
@@ -2220,44 +2228,42 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
        case WCN36XX_HAL_CH_SWITCH_RSP:
        case WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_RSP:
        case WCN36XX_HAL_8023_MULTICAST_LIST_RSP:
-               memcpy(wcn->hal_buf, buf, len);
+               memcpy_fromio(wcn->hal_buf, buf, len);
                wcn->hal_rsp_len = len;
                complete(&wcn->hal_rsp_compl);
                break;
 
-       case WCN36XX_HAL_DEL_BA_IND:
-       case WCN36XX_HAL_PRINT_REG_INFO_IND:
        case WCN36XX_HAL_COEX_IND:
        case WCN36XX_HAL_AVOID_FREQ_RANGE_IND:
        case WCN36XX_HAL_OTA_TX_COMPL_IND:
        case WCN36XX_HAL_MISSED_BEACON_IND:
        case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
-               msg_ind = kmalloc(sizeof(*msg_ind), GFP_KERNEL);
-               if (!msg_ind)
-                       goto nomem;
-               msg_ind->msg_len = len;
-               msg_ind->msg = kmemdup(buf, len, GFP_KERNEL);
-               if (!msg_ind->msg) {
-                       kfree(msg_ind);
-nomem:
+               msg_ind = kmalloc(sizeof(*msg_ind) + len, GFP_ATOMIC);
+               if (!msg_ind) {
                        /*
                         * FIXME: Do something smarter then just
                         * printing an error.
                         */
                        wcn36xx_err("Run out of memory while handling SMD_EVENT (%d)\n",
-                                   msg_header->msg_type);
+                                   msg_header.msg_type);
                        break;
                }
-               mutex_lock(&wcn->hal_ind_mutex);
+
+               msg_ind->msg_len = len;
+               memcpy_fromio(msg_ind->msg, buf, len);
+
+               spin_lock(&wcn->hal_ind_lock);
                list_add_tail(&msg_ind->list, &wcn->hal_ind_queue);
                queue_work(wcn->hal_ind_wq, &wcn->hal_ind_work);
-               mutex_unlock(&wcn->hal_ind_mutex);
+               spin_unlock(&wcn->hal_ind_lock);
                wcn36xx_dbg(WCN36XX_DBG_HAL, "indication arrived\n");
                break;
        default:
                wcn36xx_err("SMD_EVENT (%d) not supported\n",
-                             msg_header->msg_type);
+                             msg_header.msg_type);
        }
+
+       return 0;
 }
 static void wcn36xx_ind_smd_work(struct work_struct *work)
 {
@@ -2265,8 +2271,9 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
                container_of(work, struct wcn36xx, hal_ind_work);
        struct wcn36xx_hal_msg_header *msg_header;
        struct wcn36xx_hal_ind_msg *hal_ind_msg;
+       unsigned long flags;
 
-       mutex_lock(&wcn->hal_ind_mutex);
+       spin_lock_irqsave(&wcn->hal_ind_lock, flags);
 
        hal_ind_msg = list_first_entry(&wcn->hal_ind_queue,
                                       struct wcn36xx_hal_ind_msg,
@@ -2275,8 +2282,6 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
        msg_header = (struct wcn36xx_hal_msg_header *)hal_ind_msg->msg;
 
        switch (msg_header->msg_type) {
-       case WCN36XX_HAL_DEL_BA_IND:
-       case WCN36XX_HAL_PRINT_REG_INFO_IND:
        case WCN36XX_HAL_COEX_IND:
        case WCN36XX_HAL_AVOID_FREQ_RANGE_IND:
                break;
@@ -2300,9 +2305,8 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
                              msg_header->msg_type);
        }
        list_del(wcn->hal_ind_queue.next);
-       kfree(hal_ind_msg->msg);
+       spin_unlock_irqrestore(&wcn->hal_ind_lock, flags);
        kfree(hal_ind_msg);
-       mutex_unlock(&wcn->hal_ind_mutex);
 }
 int wcn36xx_smd_open(struct wcn36xx *wcn)
 {
@@ -2315,25 +2319,15 @@ int wcn36xx_smd_open(struct wcn36xx *wcn)
        }
        INIT_WORK(&wcn->hal_ind_work, wcn36xx_ind_smd_work);
        INIT_LIST_HEAD(&wcn->hal_ind_queue);
-       mutex_init(&wcn->hal_ind_mutex);
-
-       ret = wcn->ctrl_ops->open(wcn, wcn36xx_smd_rsp_process);
-       if (ret) {
-               wcn36xx_err("failed to open control channel\n");
-               goto free_wq;
-       }
+       spin_lock_init(&wcn->hal_ind_lock);
 
-       return ret;
+       return 0;
 
-free_wq:
-       destroy_workqueue(wcn->hal_ind_wq);
 out:
        return ret;
 }
 
 void wcn36xx_smd_close(struct wcn36xx *wcn)
 {
-       wcn->ctrl_ops->close(wcn);
        destroy_workqueue(wcn->hal_ind_wq);
-       mutex_destroy(&wcn->hal_ind_mutex);
 }
index d93e3fd73831c98b67ddf32c1cf436d32a34d20e..8892ccd67b144903ae25cde3287e79f951e5a8c6 100644 (file)
@@ -46,11 +46,12 @@ struct wcn36xx_fw_msg_status_rsp {
 
 struct wcn36xx_hal_ind_msg {
        struct list_head list;
-       u8 *msg;
        size_t msg_len;
+       u8 msg[];
 };
 
 struct wcn36xx;
+struct qcom_smd_channel;
 
 int wcn36xx_smd_open(struct wcn36xx *wcn);
 void wcn36xx_smd_close(struct wcn36xx *wcn);
@@ -59,11 +60,11 @@ int wcn36xx_smd_load_nv(struct wcn36xx *wcn);
 int wcn36xx_smd_start(struct wcn36xx *wcn);
 int wcn36xx_smd_stop(struct wcn36xx *wcn);
 int wcn36xx_smd_init_scan(struct wcn36xx *wcn, enum wcn36xx_hal_sys_mode mode);
-int wcn36xx_smd_start_scan(struct wcn36xx *wcn);
-int wcn36xx_smd_end_scan(struct wcn36xx *wcn);
+int wcn36xx_smd_start_scan(struct wcn36xx *wcn, u8 scan_channel);
+int wcn36xx_smd_end_scan(struct wcn36xx *wcn, u8 scan_channel);
 int wcn36xx_smd_finish_scan(struct wcn36xx *wcn,
                            enum wcn36xx_hal_sys_mode mode);
-int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn);
+int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn, u8 *channels, size_t channel_count);
 int wcn36xx_smd_add_sta_self(struct wcn36xx *wcn, struct ieee80211_vif *vif);
 int wcn36xx_smd_delete_sta_self(struct wcn36xx *wcn, u8 *addr);
 int wcn36xx_smd_delete_sta(struct wcn36xx *wcn, u8 sta_index);
@@ -127,6 +128,10 @@ int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 sta_index);
 int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index);
 
 int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value);
+
+int wcn36xx_smd_rsp_process(struct qcom_smd_channel *channel,
+                           const void *buf, size_t len);
+
 int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn,
                            struct ieee80211_vif *vif,
                            struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp);
index 37f13410e6339c38a656be6a67aacd54418e1194..8c387a0a3c091c474e8f7dd948dc31b9060c0813 100644 (file)
@@ -45,9 +45,20 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb)
        skb_put(skb, bd->pdu.mpdu_header_off + bd->pdu.mpdu_len);
        skb_pull(skb, bd->pdu.mpdu_header_off);
 
+       hdr = (struct ieee80211_hdr *) skb->data;
+       fc = __le16_to_cpu(hdr->frame_control);
+       sn = IEEE80211_SEQ_TO_SN(__le16_to_cpu(hdr->seq_ctrl));
+
+       /* When scanning associate beacons to this */
+       if (ieee80211_is_beacon(hdr->frame_control) && wcn->scan_freq) {
+               status.freq = wcn->scan_freq;
+               status.band = wcn->scan_band;
+       } else {
+               status.freq = WCN36XX_CENTER_FREQ(wcn);
+               status.band = WCN36XX_BAND(wcn);
+       }
+
        status.mactime = 10;
-       status.freq = WCN36XX_CENTER_FREQ(wcn);
-       status.band = WCN36XX_BAND(wcn);
        status.signal = -get_rssi0(bd);
        status.antenna = 1;
        status.rate_idx = 1;
@@ -57,14 +68,10 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb)
                       RX_FLAG_MMIC_STRIPPED |
                       RX_FLAG_DECRYPTED;
 
-       wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%x\n", status.flag);
+       wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%llx\n", status.flag);
 
        memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
 
-       hdr = (struct ieee80211_hdr *) skb->data;
-       fc = __le16_to_cpu(hdr->frame_control);
-       sn = IEEE80211_SEQ_TO_SN(__le16_to_cpu(hdr->seq_ctrl));
-
        if (ieee80211_is_beacon(hdr->frame_control)) {
                wcn36xx_dbg(WCN36XX_DBG_BEACON, "beacon skb %p len %d fc %04x sn %d\n",
                            skb, skb->len, fc, sn);
@@ -221,7 +228,7 @@ static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd,
 
        /* default rate for unicast */
        if (ieee80211_is_mgmt(hdr->frame_control))
-               bd->bd_rate = (WCN36XX_BAND(wcn) == IEEE80211_BAND_5GHZ) ?
+               bd->bd_rate = (WCN36XX_BAND(wcn) == NL80211_BAND_5GHZ) ?
                        WCN36XX_BD_RATE_CTRL :
                        WCN36XX_BD_RATE_MGMT;
        else if (ieee80211_is_ctl(hdr->frame_control))
diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c b/drivers/net/wireless/ath/wcn36xx/wcn36xx-msm.c
deleted file mode 100644 (file)
index 647f623..0000000
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com>
- * Copyright (c) 2013 Qualcomm Atheros, Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <linux/completion.h>
-#include <linux/firmware.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/consumer.h>
-#include <linux/workqueue.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/clk.h>
-#include <linux/remoteproc.h>
-#include <linux/soc/qcom/smd.h>
-#include "wcn36xx.h"
-#include "wcnss_core.h"
-
-#define MAC_ADDR_0 "wlan/macaddr0"
-
-struct smd_packet_item {
-       struct list_head list;
-       void *buf;
-       size_t count;
-};
-
-static int wcn36xx_msm_smsm_change_state(u32 clear_mask, u32 set_mask)
-{
-       return 0;
-}
-
-static int wcn36xx_msm_get_hw_mac(struct wcn36xx *wcn, u8 *addr)
-{
-       const struct firmware *addr_file = NULL;
-       int status;
-       u8 tmp[18];
-       static const u8 qcom_oui[3] = {0x00, 0x0A, 0xF5};
-       static const char *files = {MAC_ADDR_0};
-       struct wcn36xx_platform_data *pdata = wcn->wcn36xx_data;
-
-       status = request_firmware(&addr_file, files, &pdata->core->dev);
-
-       if (status < 0) {
-               /* Assign a random mac with Qualcomm oui */
-               dev_err(&pdata->core->dev, "Failed (%d) to read macaddress"
-                       "file %s, using a random address instead", status, files);
-               memcpy(addr, qcom_oui, 3);
-               get_random_bytes(addr + 3, 3);
-       } else {
-               memset(tmp, 0, sizeof(tmp));
-               memcpy(tmp, addr_file->data, sizeof(tmp) - 1);
-               sscanf(tmp, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
-                      &addr[0],
-                      &addr[1],
-                      &addr[2],
-                      &addr[3],
-                      &addr[4],
-                      &addr[5]);
-
-               release_firmware(addr_file);
-       }
-
-       return 0;
-}
-
-static int wcn36xx_msm_smd_send_and_wait(struct wcn36xx *wcn, char *buf, size_t len)
-{
-       int ret = 0;
-       struct wcn36xx_platform_data *pdata = wcn->wcn36xx_data;
-
-       mutex_lock(&pdata->wlan_ctrl_lock);
-       ret = qcom_smd_send(pdata->wlan_ctrl_channel, buf, len);
-       if (ret) {
-               dev_err(wcn->dev, "wlan ctrl channel tx failed\n");
-       }
-       mutex_unlock(&pdata->wlan_ctrl_lock);
-
-       return ret;
-}
-
-static int wcn36xx_msm_smd_open(struct wcn36xx *wcn, void *rsp_cb)
-{
-       struct wcn36xx_platform_data *pdata = wcn->wcn36xx_data;
-
-       pdata->cb = rsp_cb;
-       return 0;
-}
-
-static void wcn36xx_msm_smd_close(struct wcn36xx *wcn)
-{
-       return;
-}
-
-static int wcn36xx_msm_get_chip_type(struct wcn36xx *wcn)
-{
-       struct wcn36xx_platform_data *pdata = wcn->wcn36xx_data;
-       return pdata->chip_type;
-}
-
-static struct wcn36xx_platform_data wcn36xx_data = {
-       .ctrl_ops = {
-               .open = wcn36xx_msm_smd_open,
-               .close = wcn36xx_msm_smd_close,
-               .tx = wcn36xx_msm_smd_send_and_wait,
-               .get_hw_mac = wcn36xx_msm_get_hw_mac,
-               .smsm_change_state = wcn36xx_msm_smsm_change_state,
-               .get_chip_type = wcn36xx_msm_get_chip_type,
-       },
-};
-
-static void wlan_ctrl_smd_process(struct work_struct *worker)
-{
-       unsigned long flags;
-       struct wcn36xx_platform_data *pdata =
-               container_of(worker,
-                       struct wcn36xx_platform_data, packet_process_work);
-
-       spin_lock_irqsave(&pdata->packet_lock, flags);
-       while (!list_empty(&pdata->packet_list)) {
-               struct smd_packet_item *packet;
-
-               packet = list_first_entry(&pdata->packet_list,
-                               struct smd_packet_item, list);
-               list_del(&packet->list);
-               spin_unlock_irqrestore(&pdata->packet_lock, flags);
-               pdata->cb(pdata->wcn, packet->buf, packet->count);
-               kfree(packet->buf);
-               spin_lock_irqsave(&pdata->packet_lock, flags);
-       }
-       spin_unlock_irqrestore(&pdata->packet_lock, flags);
-}
-
-static int qcom_smd_wlan_ctrl_probe(struct qcom_smd_device *sdev)
-{
-       pr_info("%s: enter\n", __func__);
-        mutex_init(&wcn36xx_data.wlan_ctrl_lock);
-        init_completion(&wcn36xx_data.wlan_ctrl_ack);
-
-       wcn36xx_data.sdev = sdev;
-       spin_lock_init(&wcn36xx_data.packet_lock);
-       INIT_LIST_HEAD(&wcn36xx_data.packet_list);
-       INIT_WORK(&wcn36xx_data.packet_process_work, wlan_ctrl_smd_process);
-
-        dev_set_drvdata(&sdev->dev, &wcn36xx_data);
-       wcn36xx_data.wlan_ctrl_channel = sdev->channel;
-
-       of_platform_populate(sdev->dev.of_node, NULL, NULL, &sdev->dev);
-
-        return 0;
-}
-
-static void qcom_smd_wlan_ctrl_remove(struct qcom_smd_device *sdev)
-{
-        of_platform_depopulate(&sdev->dev);
-}
-
-static int qcom_smd_wlan_ctrl_callback(struct qcom_smd_device *qsdev,
-                                 const void *data,
-                                 size_t count)
-{
-       unsigned long flags;
-       struct smd_packet_item *packet = NULL;
-       struct wcn36xx_platform_data *pdata = dev_get_drvdata(&qsdev->dev);
-       void *buf = kzalloc(count + sizeof(struct smd_packet_item),
-                               GFP_ATOMIC);
-       if (!buf) {
-               dev_err(&pdata->core->dev, "can't allocate buffer\n");
-               return -ENOMEM;
-       }
-
-       memcpy_fromio(buf, data, count);
-       packet = buf + count;
-       packet->buf = buf;
-       packet->count = count;
-
-       spin_lock_irqsave(&pdata->packet_lock, flags);
-       list_add_tail(&packet->list, &pdata->packet_list);
-       spin_unlock_irqrestore(&pdata->packet_lock, flags);
-       schedule_work(&pdata->packet_process_work);
-
-       /* buf will be freed in workqueue */
-
-       return 0;
-}
-
-static const struct qcom_smd_id qcom_smd_wlan_ctrl_match[] = {
-       { .name = "WLAN_CTRL" },
-       {}
-};
-
-static struct qcom_smd_driver qcom_smd_wlan_ctrl_driver = {
-       .probe = qcom_smd_wlan_ctrl_probe,
-       .remove = qcom_smd_wlan_ctrl_remove,
-       .callback = qcom_smd_wlan_ctrl_callback,
-       .smd_match_table = qcom_smd_wlan_ctrl_match,
-       .driver  = {
-               .name  = "qcom_smd_wlan_ctrl",
-               .owner = THIS_MODULE,
-       },
-};
-
-static const struct of_device_id wcn36xx_msm_match_table[] = {
-       { .compatible = "qcom,wcn3660", .data = (void *)WCN36XX_CHIP_3660 },
-       { .compatible = "qcom,wcn3680", .data = (void *)WCN36XX_CHIP_3680 },
-       { .compatible = "qcom,wcn3620", .data = (void *)WCN36XX_CHIP_3620 },
-       { }
-};
-MODULE_DEVICE_TABLE(of, wcn36xx_msm_match_table);
-
-static int wcn36xx_msm_probe(struct platform_device *pdev)
-{
-       int ret;
-       const struct of_device_id *of_id;
-       struct resource *r;
-       struct resource res[3];
-       static const char const *rnames[] = {
-               "wcnss_mmio", "wcnss_wlantx_irq", "wcnss_wlanrx_irq" };
-       static const int rtype[] = {
-               IORESOURCE_MEM, IORESOURCE_IRQ, IORESOURCE_IRQ };
-       struct device_node *dn;
-       int n;
-
-       wcnss_core_prepare(pdev);
-
-       dn = of_parse_phandle(pdev->dev.of_node, "rproc", 0);
-       if (!dn) {
-               dev_err(&pdev->dev, "No rproc specified in DT\n");
-       } else {
-               struct rproc *rproc= rproc_get_by_phandle(dn->phandle);
-               if (rproc)
-                       rproc_boot(rproc);
-               else {
-                       dev_err(&pdev->dev, "No rproc registered\n");
-               }
-       }
-
-       qcom_smd_driver_register(&qcom_smd_wlan_ctrl_driver);
-       wcnss_core_init();
-
-       of_id = of_match_node(wcn36xx_msm_match_table, pdev->dev.of_node);
-       if (!of_id)
-               return -EINVAL;
-
-       wcn36xx_data.chip_type = (enum wcn36xx_chip_type)of_id->data;
-
-       wcn36xx_data.core = platform_device_alloc("wcn36xx", -1);
-
-       for (n = 0; n < ARRAY_SIZE(rnames); n++) {
-               r = platform_get_resource_byname(pdev, rtype[n], rnames[n]);
-               if (!r) {
-                       dev_err(&wcn36xx_data.core->dev,
-                               "Missing resource %s'\n", rnames[n]);
-                       ret = -ENOMEM;
-                       return ret;
-               }
-               res[n] = *r;
-       }
-
-       platform_device_add_resources(wcn36xx_data.core, res, n);
-       wcn36xx_data.core->dev.platform_data = &wcn36xx_data;
-
-       platform_device_add(wcn36xx_data.core);
-
-       dev_info(&pdev->dev, "%s initialized\n", __func__);
-
-       return 0;
-}
-
-static int wcn36xx_msm_remove(struct platform_device *pdev)
-{
-       platform_device_del(wcn36xx_data.core);
-       platform_device_put(wcn36xx_data.core);
-       return 0;
-}
-
-static struct platform_driver wcn36xx_msm_driver = {
-       .probe          = wcn36xx_msm_probe,
-       .remove         = wcn36xx_msm_remove,
-       .driver         = {
-               .name   = "wcn36xx-msm",
-               .owner  = THIS_MODULE,
-               .of_match_table = wcn36xx_msm_match_table,
-       },
-};
-
-static int __init wcn36xx_msm_init(void)
-{
-       return platform_driver_register(&wcn36xx_msm_driver);
-}
-module_init(wcn36xx_msm_init);
-
-static void __exit wcn36xx_msm_exit(void)
-{
-       platform_driver_unregister(&wcn36xx_msm_driver);
-}
-module_exit(wcn36xx_msm_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com");
-MODULE_FIRMWARE(MAC_ADDR_0);
-
index b17d284a69c9850758464a5d1569d69384aac994..35a6590c3ee51db0c5f9f2e3e1aa927e1b0531c8 100644 (file)
@@ -35,6 +35,9 @@
 /* How many frames until we start a-mpdu TX session */
 #define WCN36XX_AMPDU_START_THRESH     20
 
+#define WCN36XX_MAX_SCAN_SSIDS         9
+#define WCN36XX_MAX_SCAN_IE_LEN                500
+
 extern unsigned int wcn36xx_dbg_mask;
 
 enum wcn36xx_debug_mask {
@@ -103,49 +106,6 @@ struct nv_data {
        u8      table;
 };
 
-enum wcn36xx_chip_type {
-       WCN36XX_CHIP_UNKNOWN,
-       WCN36XX_CHIP_3660,
-       WCN36XX_CHIP_3680,
-       WCN36XX_CHIP_3620,
-};
-
-/* Interface for platform control path
- *
- * @open: hook must be called when wcn36xx wants to open control channel.
- * @tx: sends a buffer.
- */
-struct wcn36xx_platform_ctrl_ops {
-       int (*open)(struct wcn36xx *wcn, void *rsp_cb);
-       void (*close)(struct wcn36xx *wcn);
-       int (*tx)(struct wcn36xx *wcn, char *buf, size_t len);
-       int (*get_hw_mac)(struct wcn36xx *wcn, u8 *addr);
-       int (*get_chip_type)(struct wcn36xx *wcn);
-       int (*smsm_change_state)(u32 clear_mask, u32 set_mask);
-};
-
-struct wcn36xx_platform_data {
-       enum wcn36xx_chip_type chip_type;
-
-       struct platform_device *core;
-
-       struct qcom_smd_device *sdev;
-        struct qcom_smd_channel *wlan_ctrl_channel;
-        struct completion wlan_ctrl_ack;
-        struct mutex wlan_ctrl_lock;
-
-       struct pinctrl *pinctrl;
-
-       struct wcn36xx *wcn;
-
-       void (*cb)(struct wcn36xx *wcn, void *buf, size_t len);
-       struct wcn36xx_platform_ctrl_ops ctrl_ops;
-
-       struct work_struct packet_process_work;
-       spinlock_t packet_lock;
-       struct list_head packet_list;
-};
-
 /**
  * struct wcn36xx_vif - holds VIF related fields
  *
@@ -223,7 +183,7 @@ struct wcn36xx {
        u8                      fw_minor;
        u8                      fw_major;
        u32                     fw_feat_caps[WCN36XX_HAL_CAPS_SIZE];
-       enum wcn36xx_chip_type  chip_version;
+       bool                    is_pronto;
 
        /* extra byte for the NULL termination */
        u8                      crm_version[WCN36XX_HAL_VERSION_LENGTH + 1];
@@ -232,10 +192,16 @@ struct wcn36xx {
        /* IRQs */
        int                     tx_irq;
        int                     rx_irq;
-       void __iomem            *mmio;
+       void __iomem            *ccu_base;
+       void __iomem            *dxe_base;
+
+       struct qcom_smd_channel *smd_channel;
+
+       struct qcom_smem_state  *tx_enable_state;
+       unsigned                tx_enable_state_bit;
+       struct qcom_smem_state  *tx_rings_empty_state;
+       unsigned                tx_rings_empty_state_bit;
 
-       struct wcn36xx_platform_data *wcn36xx_data;
-       struct wcn36xx_platform_ctrl_ops *ctrl_ops;
        /*
         * smd_buf must be protected with smd_mutex to garantee
         * that all messages are sent one after another
@@ -246,9 +212,15 @@ struct wcn36xx {
        struct completion       hal_rsp_compl;
        struct workqueue_struct *hal_ind_wq;
        struct work_struct      hal_ind_work;
-       struct mutex            hal_ind_mutex;
+       spinlock_t              hal_ind_lock;
        struct list_head        hal_ind_queue;
 
+       struct work_struct      scan_work;
+       struct cfg80211_scan_request *scan_req;
+       int                     scan_freq;
+       int                     scan_band;
+       struct mutex            scan_lock;
+
        /* DXE channels */
        struct wcn36xx_dxe_ch   dxe_tx_l_ch;    /* TX low */
        struct wcn36xx_dxe_ch   dxe_tx_h_ch;    /* TX high */
diff --git a/drivers/net/wireless/ath/wcn36xx/wcnss_core.c b/drivers/net/wireless/ath/wcn36xx/wcnss_core.c
deleted file mode 100644 (file)
index e7d389e..0000000
+++ /dev/null
@@ -1,295 +0,0 @@
-#include <linux/completion.h>
-#include <linux/firmware.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/consumer.h>
-#include <linux/workqueue.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/clk.h>
-#include <linux/soc/qcom/smd.h>
-#include "wcn36xx.h"
-#include "wcnss_core.h"
-
-#define        WCNSS_CTRL_TIMEOUT      (msecs_to_jiffies(500))
-
-static int wcnss_core_config(struct platform_device *pdev, void __iomem *base)
-{
-       int ret = 0;
-       u32 value, iris_read_v = INVALID_IRIS_REG;
-       int clk_48m = 0;
-
-       value = readl_relaxed(base + SPARE_OFFSET);
-       value |= WCNSS_FW_DOWNLOAD_ENABLE;
-       writel_relaxed(value, base + SPARE_OFFSET);
-
-       writel_relaxed(0, base + PMU_OFFSET);
-       value = readl_relaxed(base + PMU_OFFSET);
-       value |= WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP |
-               WCNSS_PMU_CFG_IRIS_XO_EN;
-       writel_relaxed(value, base + PMU_OFFSET);
-
-       iris_read_v = readl_relaxed(base + IRIS_REG_OFFSET);
-       pr_info("iris_read_v: 0x%x\n", iris_read_v);
-
-       iris_read_v &= 0xffff;
-       iris_read_v |= 0x04;
-       writel_relaxed(iris_read_v, base + IRIS_REG_OFFSET);
-
-       value = readl_relaxed(base + PMU_OFFSET);
-       value |= WCNSS_PMU_CFG_IRIS_XO_READ;
-       writel_relaxed(value, base + PMU_OFFSET);
-
-       while (readl_relaxed(base + PMU_OFFSET) &
-                       WCNSS_PMU_CFG_IRIS_XO_READ_STS)
-               cpu_relax();
-
-       iris_read_v = readl_relaxed(base + 0x1134);
-       pr_info("wcnss: IRIS Reg: 0x%08x\n", iris_read_v);
-       clk_48m = (iris_read_v >> 30) ? 0 : 1;
-       value &= ~WCNSS_PMU_CFG_IRIS_XO_READ;
-
-       /* XO_MODE[b2:b1]. Clear implies 19.2MHz */
-       value &= ~WCNSS_PMU_CFG_IRIS_XO_MODE;
-
-       if (clk_48m)
-               value |= WCNSS_PMU_CFG_IRIS_XO_MODE_48;
-
-       writel_relaxed(value, base + PMU_OFFSET);
-
-       /* Reset IRIS */
-       value |= WCNSS_PMU_CFG_IRIS_RESET;
-       writel_relaxed(value, base + PMU_OFFSET);
-
-       while (readl_relaxed(base + PMU_OFFSET) &
-                       WCNSS_PMU_CFG_IRIS_RESET_STS)
-               cpu_relax();
-
-       /* reset IRIS reset bit */
-       value &= ~WCNSS_PMU_CFG_IRIS_RESET;
-       writel_relaxed(value, base + PMU_OFFSET);
-
-       /* start IRIS XO configuration */
-       value |= WCNSS_PMU_CFG_IRIS_XO_CFG;
-       writel_relaxed(value, base + PMU_OFFSET);
-
-       /* Wait for XO configuration to finish */
-       while (readl_relaxed(base + PMU_OFFSET) &
-                       WCNSS_PMU_CFG_IRIS_XO_CFG_STS)
-               cpu_relax();
-
-       /* Stop IRIS XO configuration */
-       value &= ~(WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP |
-                       WCNSS_PMU_CFG_IRIS_XO_CFG);
-       writel_relaxed(value, base + PMU_OFFSET);
-
-        msleep(200);
-
-       return ret;
-}
-
-int wcnss_core_prepare(struct platform_device *pdev)
-{
-       int ret = 0;
-       struct resource *res;
-       void __iomem *wcnss_base;
-
-       res = platform_get_resource_byname(pdev,
-                        IORESOURCE_MEM, "pronto_phy_base");
-       if (!res) {
-               ret = -EIO;
-               dev_err(&pdev->dev, "resource pronto_phy_base failed\n");
-               return ret;
-       }
-
-       wcnss_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(wcnss_base)) {
-               dev_err(&pdev->dev, "pronto_phy_base map failed\n");
-               return PTR_ERR(wcnss_base);
-       }
-
-       ret = wcnss_core_config(pdev, wcnss_base);
-       return ret;
-}
-
-struct wcnss_platform_data {
-        struct qcom_smd_channel        *channel;
-        struct completion      ack;
-        struct mutex           lock;
-
-       struct work_struct      rx_work;
-       struct work_struct      download_work;
-
-       struct qcom_smd_device  *sdev;
-};
-
-static struct completion fw_ready_compl;
-#define        NV_FILE_NAME    "wlan/prima/WCNSS_qcom_wlan_nv.bin"
-static void wcn36xx_nv_download_work(struct work_struct *worker)
-{
-       int ret = 0, i;
-       const struct firmware *nv = NULL;
-       struct wcnss_platform_data *wcnss_data =
-               container_of(worker, struct wcnss_platform_data, download_work);
-       struct device *dev = &wcnss_data->sdev->dev;
-
-       struct nvbin_dnld_req_msg *msg;
-       const void *nv_blob_start;
-       char *pkt = NULL;
-       int nv_blob_size = 0, fragments;
-
-       ret = request_firmware(&nv, NV_FILE_NAME, dev);
-       if (ret || !nv || !nv->data || !nv->size) {
-               dev_err(dev, "request firmware for %s (ret = %d)\n",
-                       NV_FILE_NAME, ret);
-               return;
-       }
-
-       nv_blob_start = nv->data + 4;
-       nv_blob_size = nv->size -4;
-
-       fragments = (nv_blob_size + NV_FRAGMENT_SIZE - 1)/NV_FRAGMENT_SIZE;
-
-       pkt = kzalloc(sizeof(struct nvbin_dnld_req_msg) + NV_FRAGMENT_SIZE,
-                       GFP_KERNEL);
-       if (!pkt) {
-               dev_err(dev, "allocation packet for nv download failed\n");
-               release_firmware(nv);
-       }
-
-       msg = (struct nvbin_dnld_req_msg *)pkt;
-       msg->hdr.msg_type = WCNSS_NV_DOWNLOAD_REQ;
-       msg->dnld_req_params.msg_flags = 0;
-
-       i = 0;
-       do {
-               int pkt_len = 0;
-
-               msg->dnld_req_params.frag_number = i;
-               if (nv_blob_size > NV_FRAGMENT_SIZE) {
-                       msg->dnld_req_params.msg_flags &=
-                               ~LAST_FRAGMENT;
-                       pkt_len = NV_FRAGMENT_SIZE;
-               } else {
-                       pkt_len = nv_blob_size;
-                       msg->dnld_req_params.msg_flags |=
-                               LAST_FRAGMENT | CAN_RECEIVE_CALDATA;
-               }
-
-               msg->dnld_req_params.nvbin_buffer_size = pkt_len;
-               msg->hdr.msg_len =
-                       sizeof(struct nvbin_dnld_req_msg) + pkt_len;
-
-               memcpy(pkt + sizeof(struct nvbin_dnld_req_msg),
-                       nv_blob_start + i * NV_FRAGMENT_SIZE, pkt_len);
-
-               ret = qcom_smd_send(wcnss_data->channel, pkt, msg->hdr.msg_len);
-               if (ret) {
-                       dev_err(dev, "nv download failed\n");
-                       goto out;
-               }
-
-               i++;
-               nv_blob_size -= NV_FRAGMENT_SIZE;
-               msleep(100);
-       } while (nv_blob_size > 0);
-
-out:
-       kfree(pkt);
-       release_firmware(nv);
-       return;
-}
-
-static int qcom_smd_wcnss_ctrl_callback(struct qcom_smd_device *qsdev,
-                                 const void *data,
-                                 size_t count)
-{
-       struct wcnss_platform_data *wcnss_data = dev_get_drvdata(&qsdev->dev);
-       struct smd_msg_hdr phdr;
-       const unsigned char *tmp = data;
-
-       memcpy_fromio(&phdr, data, sizeof(struct smd_msg_hdr));
-
-       switch (phdr.msg_type) {
-       /* CBC COMPLETE means firmware ready for go */
-        case WCNSS_CBC_COMPLETE_IND:
-                complete(&fw_ready_compl);
-                pr_info("wcnss: received WCNSS_CBC_COMPLETE_IND from FW\n");
-                break;
-
-       case WCNSS_NV_DOWNLOAD_RSP:
-               pr_info("fw_status: %d\n", tmp[sizeof(struct smd_msg_hdr)]);
-               break;
-       }
-
-       complete(&wcnss_data->ack);
-       return 0;
-}
-
-static int qcom_smd_wcnss_ctrl_probe(struct qcom_smd_device *sdev)
-{
-       struct wcnss_platform_data *wcnss_data;
-
-        wcnss_data = devm_kzalloc(&sdev->dev, sizeof(*wcnss_data), GFP_KERNEL);
-        if (!wcnss_data)
-                return -ENOMEM;
-
-        mutex_init(&wcnss_data->lock);
-        init_completion(&wcnss_data->ack);
-
-       wcnss_data->sdev = sdev;
-
-        dev_set_drvdata(&sdev->dev, wcnss_data);
-       wcnss_data->channel = sdev->channel;
-
-       INIT_WORK(&wcnss_data->download_work, wcn36xx_nv_download_work);
-
-       of_platform_populate(sdev->dev.of_node, NULL, NULL, &sdev->dev);
-
-       /* We are ready for download here */
-       schedule_work(&wcnss_data->download_work);
-        return 0;
-}
-
-static void qcom_smd_wcnss_ctrl_remove(struct qcom_smd_device *sdev)
-{
-        of_platform_depopulate(&sdev->dev);
-}
-
-static const struct qcom_smd_id qcom_smd_wcnss_ctrl_match[] = {
-       { .name = "WCNSS_CTRL" },
-       {}
-};
-
-static struct qcom_smd_driver qcom_smd_wcnss_ctrl_driver = {
-       .probe = qcom_smd_wcnss_ctrl_probe,
-       .remove = qcom_smd_wcnss_ctrl_remove,
-       .callback = qcom_smd_wcnss_ctrl_callback,
-       .smd_match_table = qcom_smd_wcnss_ctrl_match,
-       .driver  = {
-               .name  = "qcom_smd_wcnss_ctrl",
-               .owner = THIS_MODULE,
-       },
-};
-
-void wcnss_core_init(void)
-{
-       int ret = 0;
-
-       init_completion(&fw_ready_compl);
-       qcom_smd_driver_register(&qcom_smd_wcnss_ctrl_driver);
-
-       ret = wait_for_completion_interruptible_timeout(
-               &fw_ready_compl, msecs_to_jiffies(FW_READY_TIMEOUT));
-       if (ret <= 0) {
-                pr_err("timeout waiting for wcnss firmware ready indicator\n");
-               return;
-        }
-
-       return;
-}
-
-void wcnss_core_deinit(void)
-{
-       qcom_smd_driver_unregister(&qcom_smd_wcnss_ctrl_driver);
-}
diff --git a/drivers/net/wireless/ath/wcn36xx/wcnss_core.h b/drivers/net/wireless/ath/wcn36xx/wcnss_core.h
deleted file mode 100644 (file)
index 49524c8..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-#ifndef        _WCNSS_CORE_H_
-#define        _WCNSS_CORE_H_
-
-#define        PMU_OFFSET      0x1004
-#define        SPARE_OFFSET    0x1088
-#define IRIS_REG_OFFSET 0x1134
-
-#define INVALID_IRIS_REG        0xbaadbaad
-
-#define WCNSS_PMU_CFG_IRIS_XO_CFG          BIT(3)
-#define WCNSS_PMU_CFG_IRIS_XO_EN           BIT(4)
-#define WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP   BIT(5)
-#define WCNSS_PMU_CFG_IRIS_XO_CFG_STS      BIT(6) /* 1: in progress, 0: done */
-
-#define WCNSS_PMU_CFG_IRIS_RESET           BIT(7)
-#define WCNSS_PMU_CFG_IRIS_RESET_STS       BIT(8) /* 1: in progress, 0: done */
-#define WCNSS_PMU_CFG_IRIS_XO_READ         BIT(9)
-#define WCNSS_PMU_CFG_IRIS_XO_READ_STS     BIT(10)
-#define        WCNSS_FW_DOWNLOAD_ENABLE           BIT(25)
-
-#define WCNSS_PMU_CFG_IRIS_XO_MODE         0x6
-#define WCNSS_PMU_CFG_IRIS_XO_MODE_48      (3 << 1)
-
-#define        NV_DOWNLOAD_TIMEOUT     500
-#define        NV_FRAGMENT_SIZE        3072
-#define MAX_CALIBRATED_DATA_SIZE  (64*1024)
-#define LAST_FRAGMENT        (1 << 0)
-#define MESSAGE_TO_FOLLOW    (1 << 1)
-#define CAN_RECEIVE_CALDATA  (1 << 15)
-#define WCNSS_RESP_SUCCESS   1
-#define WCNSS_RESP_FAIL      0
-
-
-#define        WCNSS_NV_DOWNLOAD_REQ   0x01000002
-#define        WCNSS_NV_DOWNLOAD_RSP   0x01000003
-#define WCNSS_CBC_COMPLETE_IND  0x0100000C
-
-/*time out 10s for the firmware status ready indicator */
-#define FW_READY_TIMEOUT        (10000)
-
-
-struct smd_msg_hdr {
-       unsigned int msg_type;
-       unsigned int msg_len;
-};
-
-struct nvbin_dnld_req_params {
-       /* Fragment sequence number of the NV bin Image. NV Bin Image
-        * might not fit into one message due to size limitation of
-        * the SMD channel FIFO so entire NV blob is chopped into
-        * multiple fragments starting with seqeunce number 0. The
-        * last fragment is indicated by marking is_last_fragment field
-        * to 1. At receiving side, NV blobs would be concatenated
-        * together without any padding bytes in between.
-        */
-       unsigned short frag_number;
-
-       /* bit 0: When set to 1 it indicates that no more fragments will
-        * be sent.
-        * bit 1: When set, a new message will be followed by this message
-        * bit 2- bit 14:  Reserved
-        * bit 15: when set, it indicates that the sender is capable of
-        * receiving Calibrated data.
-        */
-       unsigned short msg_flags;
-
-       /* NV Image size (number of bytes) */
-       unsigned int nvbin_buffer_size;
-
-       /* Following the 'nvbin_buffer_size', there should be
-        * nvbin_buffer_size bytes of NV bin Image i.e.
-        * uint8[nvbin_buffer_size].
-        */
-};
-
-struct nvbin_dnld_req_msg {
-       /* Note: The length specified in nvbin_dnld_req_msg messages
-        * should be hdr.msg_len = sizeof(nvbin_dnld_req_msg) +
-        * nvbin_buffer_size.
-        */
-       struct smd_msg_hdr hdr;
-       struct nvbin_dnld_req_params dnld_req_params;
-};
-
-struct wcnss_version {
-       struct smd_msg_hdr hdr;
-       unsigned char  major;
-       unsigned char  minor;
-       unsigned char  version;
-       unsigned char  revision;
-};
-
-
-int wcnss_core_prepare(struct platform_device *pdev);
-void wcnss_core_init(void);
-void wcnss_core_deinit(void);
-
-#endif
-
index 54d5b637d14caf6aa7e2ef6512631e5ad06bcad1..ff61075a97557fc15b99800c1fad00d2637682ea 100644 (file)
@@ -81,6 +81,7 @@ config QCOM_Q6V5_PIL
        tristate "Qualcomm Hexagon V5 Peripherial Image Loader"
        depends on OF && ARCH_QCOM
        select REMOTEPROC
+       select QCOM_MDT_LOADER
        help
          Say y here to support the Qualcomm Peripherial Image Loader for the
          Hexagon V5 based remote processors.
@@ -93,4 +94,16 @@ config QCOM_TZ_PIL
          Say y here to support the TrustZone based Qualcomm Peripherial Image
          Loader.
 
+config QCOM_MDT_LOADER
+       tristate
+
+config QCOM_WCNSS_PIL
+       tristate "Qualcomm WCNSS Peripheral Image Loader"
+       depends on OF && ARCH_QCOM
+       select REMOTEPROC
+       select QCOM_MDT_LOADER
+       select QCOM_SCM
+       help
+         Peripherial Image Loader for the WCNSS block.
+
 endmenu
index 4351f2e462adddae74ddaff149d896e091dc39bd..1ce1b0a269aba02d82bab1129a8b1ec846ba308f 100644 (file)
@@ -13,3 +13,6 @@ obj-$(CONFIG_WKUP_M3_RPROC)           += wkup_m3_rproc.o
 obj-$(CONFIG_DA8XX_REMOTEPROC)         += da8xx_remoteproc.o
 obj-$(CONFIG_QCOM_Q6V5_PIL)            += qcom_q6v5_pil.o
 obj-$(CONFIG_QCOM_TZ_PIL)              += qcom_tz_pil.o
+obj-$(CONFIG_QCOM_MDT_LOADER)          += qcom_mdt_loader.o
+obj-$(CONFIG_QCOM_WCNSS_PIL)           += qcom_wcnss.o qcom_wcnss_iris.o
+obj-$(CONFIG_QCOM_Q6V5_PIL)            += qcom_q6v5_pil.o
diff --git a/drivers/remoteproc/qcom_mdt_loader.c b/drivers/remoteproc/qcom_mdt_loader.c
new file mode 100644 (file)
index 0000000..4efeda9
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Qualcomm Peripheral Image Loader
+ *
+ * Copyright (C) 2016 Linaro Ltd
+ * Copyright (C) 2015 Sony Mobile Communications Inc
+ * Copyright (c) 2012-2013, 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 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/elf.h>
+#include <linux/firmware.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/qcom_scm.h>
+#include <linux/remoteproc.h>
+#include <linux/slab.h>
+
+#include "remoteproc_internal.h"
+#include "qcom_mdt_loader.h"
+
+/**
+ * qcom_mdt_find_rsc_table() - provide dummy resource table for remoteproc
+ * @rproc:     remoteproc handle
+ * @fw:                firmware header
+ * @tablesz:   outgoing size of the table
+ *
+ * Returns a dummy table.
+ */
+struct resource_table *qcom_mdt_find_rsc_table(struct rproc *rproc,
+                                              const struct firmware *fw,
+                                              int *tablesz)
+{
+       static struct resource_table table = { .ver = 1, };
+
+       *tablesz = sizeof(table);
+       return &table;
+}
+EXPORT_SYMBOL_GPL(qcom_mdt_find_rsc_table);
+
+int qcom_mdt_parse(const struct firmware *fw, phys_addr_t *fw_addr, size_t *fw_size, bool *fw_relocate)
+{
+       const struct elf32_phdr *phdrs;
+       const struct elf32_phdr *phdr;
+       const struct elf32_hdr *ehdr;
+       phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX;
+       phys_addr_t max_addr = 0;
+       bool relocate = false;
+       int i;
+
+       ehdr = (struct elf32_hdr *)fw->data;
+       phdrs = (struct elf32_phdr *)(ehdr + 1);
+
+       for (i = 0; i < ehdr->e_phnum; i++) {
+               phdr = &phdrs[i];
+
+               if (phdr->p_type != PT_LOAD)
+                       continue;
+
+               if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
+                       continue;
+
+               if (!phdr->p_memsz)
+                       continue;
+
+               if (phdr->p_flags & QCOM_MDT_RELOCATABLE)
+                       relocate = true;
+
+               if (phdr->p_paddr < min_addr)
+                       min_addr = phdr->p_paddr;
+
+               if (phdr->p_paddr + phdr->p_memsz > max_addr)
+                       max_addr = round_up(phdr->p_paddr + phdr->p_memsz, SZ_4K);
+       }
+
+       if (fw_addr)
+               *fw_addr = min_addr;
+       if (fw_size)
+               *fw_size = max_addr - min_addr;
+       if (fw_relocate)
+               *fw_relocate = relocate;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(qcom_mdt_parse);
+
+/**
+ * qcom_mdt_load() - load the firmware which header is defined in fw
+ * @rproc:     rproc handle
+ * @pas_id:    PAS identifier to load this firmware into
+ * @fw:                frimware object for the header
+ *
+ * Returns 0 on success, negative errno otherwise.
+ */
+int qcom_mdt_load(struct rproc *rproc,
+                 const struct firmware *fw,
+                 const char *firmware)
+{
+       const struct elf32_phdr *phdrs;
+       const struct elf32_phdr *phdr;
+       const struct elf32_hdr *ehdr;
+       unsigned fw_name_len;
+       char *fw_name;
+       void *ptr;
+       int ret;
+       int i;
+
+       ehdr = (struct elf32_hdr *)fw->data;
+       phdrs = (struct elf32_phdr *)(ehdr + 1);
+
+       fw_name_len = strlen(firmware);
+       if (fw_name_len <= 4)
+               return -EINVAL;
+
+       fw_name = kstrdup(firmware, GFP_KERNEL);
+       if (!fw_name)
+               return -ENOMEM;
+
+       for (i = 0; i < ehdr->e_phnum; i++) {
+               phdr = &phdrs[i];
+
+               if (phdr->p_type != PT_LOAD)
+                       continue;
+
+               if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
+                       continue;
+
+               if (!phdr->p_memsz)
+                       continue;
+
+               ptr = rproc_da_to_va(rproc, phdr->p_paddr, phdr->p_memsz);
+               if (!ptr) {
+                       dev_err(&rproc->dev, "segment outside memory range\n");
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if (phdr->p_filesz) {
+                       sprintf(fw_name + fw_name_len - 3, "b%02d", i);
+                       ret = request_firmware(&fw, fw_name, &rproc->dev);
+                       if (ret) {
+                               dev_err(&rproc->dev, "failed to load %s\n", fw_name);
+                               break;
+                       }
+
+                       memcpy(ptr, fw->data, fw->size);
+
+                       release_firmware(fw);
+               }
+
+               if (phdr->p_memsz > phdr->p_filesz)
+                       memset(ptr + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz);
+       }
+
+       kfree(fw_name);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(qcom_mdt_load);
diff --git a/drivers/remoteproc/qcom_mdt_loader.h b/drivers/remoteproc/qcom_mdt_loader.h
new file mode 100644 (file)
index 0000000..c5d7122
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __QCOM_MDT_LOADER_H__
+#define __QCOM_MDT_LOADER_H__
+
+#define QCOM_MDT_TYPE_MASK     (7 << 24)
+#define QCOM_MDT_TYPE_HASH     (2 << 24)
+#define QCOM_MDT_RELOCATABLE   BIT(27)
+
+struct resource_table * qcom_mdt_find_rsc_table(struct rproc *rproc, const struct firmware *fw, int *tablesz);
+int qcom_mdt_load(struct rproc *rproc, const struct firmware *fw, const char *fw_name);
+
+int qcom_mdt_parse(const struct firmware *fw, phys_addr_t *fw_addr, size_t *fw_size, bool *fw_relocate);
+
+#endif
index ec4333ed791eb63c1a7202aa5a74a125eeca1c1f..5d3372feb095eda82f208b9e2b361eae2034a88b 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Qualcomm Peripheral Image Loader
  *
+ * Copyright (C) 2016 Linaro Ltd.
  * Copyright (C) 2014 Sony Mobile Communications AB
  * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
  *
  * GNU General Public License for more details.
  */
 
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/dma-mapping.h>
-#include <linux/firmware.h>
-#include <linux/remoteproc.h>
+#include <linux/io.h>
 #include <linux/interrupt.h>
-#include <linux/memblock.h>
-#include <linux/gpio/consumer.h>
-#include <linux/of.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
 #include <linux/of_address.h>
-#include <linux/elf.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
-#include <linux/soc/qcom/smem.h>
+#include <linux/remoteproc.h>
 #include <linux/reset.h>
-#include <linux/qcom_scm.h>
+#include <linux/soc/qcom/smem.h>
+#include <linux/soc/qcom/smem_state.h>
 
 #include "remoteproc_internal.h"
+#include "qcom_mdt_loader.h"
 
 #include <linux/qcom_scm.h>
 
-#define SCM_SVC_PIL                    0x2
+#define MBA_FIRMWARE_NAME              "mba.mbn"
+#define MPSS_FIRMWARE_NAME             "modem.mdt"
 
-struct mdt_hdr {
-       struct elf32_hdr hdr;
-       struct elf32_phdr phdr[];
-};
+#define MPSS_CRASH_REASON_SMEM         421
+
+/* RMB Status Register Values */
+#define RMB_PBL_SUCCESS                        0x1
+
+#define RMB_MBA_XPU_UNLOCKED           0x1
+#define RMB_MBA_XPU_UNLOCKED_SCRIBBLED 0x2
+#define RMB_MBA_META_DATA_AUTH_SUCCESS 0x3
+#define RMB_MBA_AUTH_COMPLETE          0x4
+
+/* PBL/MBA interface registers */
+#define RMB_MBA_IMAGE_REG              0x00
+#define RMB_PBL_STATUS_REG             0x04
+#define RMB_MBA_COMMAND_REG            0x08
+#define RMB_MBA_STATUS_REG             0x0C
+#define RMB_PMI_META_DATA_REG          0x10
+#define RMB_PMI_CODE_START_REG         0x14
+#define RMB_PMI_CODE_LENGTH_REG                0x18
+
+#define RMB_CMD_META_DATA_READY                0x1
+#define RMB_CMD_LOAD_READY             0x2
+
+/* QDSP6SS Register Offsets */
+#define QDSP6SS_RESET_REG              0x014
+#define QDSP6SS_GFMUX_CTL_REG          0x020
+#define QDSP6SS_PWR_CTL_REG            0x030
+
+/* AXI Halt Register Offsets */
+#define AXI_HALTREQ_REG                        0x0
+#define AXI_HALTACK_REG                        0x4
+#define AXI_IDLE_REG                   0x8
+
+#define HALT_ACK_TIMEOUT_MS            100
 
-struct qproc {
+/* QDSP6SS_RESET */
+#define Q6SS_STOP_CORE                 BIT(0)
+#define Q6SS_CORE_ARES                 BIT(1)
+#define Q6SS_BUS_ARES_ENABLE           BIT(2)
+
+/* QDSP6SS_GFMUX_CTL */
+#define Q6SS_CLK_ENABLE                        BIT(1)
+
+/* QDSP6SS_PWR_CTL */
+#define Q6SS_L2DATA_SLP_NRET_N_0       BIT(0)
+#define Q6SS_L2DATA_SLP_NRET_N_1       BIT(1)
+#define Q6SS_L2DATA_SLP_NRET_N_2       BIT(2)
+#define Q6SS_L2TAG_SLP_NRET_N          BIT(16)
+#define Q6SS_ETB_SLP_NRET_N            BIT(17)
+#define Q6SS_L2DATA_STBY_N             BIT(18)
+#define Q6SS_SLP_RET_N                 BIT(19)
+#define Q6SS_CLAMP_IO                  BIT(20)
+#define QDSS_BHS_ON                    BIT(21)
+#define QDSS_LDO_BYP                   BIT(22)
+
+struct q6v5 {
        struct device *dev;
        struct rproc *rproc;
 
        void __iomem *reg_base;
-       void __iomem *halt_base;
-       void __iomem *halt_q6;
-       void __iomem *halt_modem;
-       void __iomem *halt_nc;
        void __iomem *rmb_base;
-       void __iomem *restart_sec_base;
 
-       struct reset_control *mss_restart;
+       struct regmap *halt_map;
+       u32 halt_q6;
+       u32 halt_modem;
+       u32 halt_nc;
 
-       int wdog_irq;
-       int fatal_irq;
-       int ready_irq;
-       int handover_irq;
-       int stop_ack_irq;
+       struct reset_control *mss_restart;
 
-       struct gpio_desc *stop_gpio;
+       struct qcom_smem_state *state;
+       unsigned stop_bit;
 
-       struct regulator *vdd;
-       struct regulator *cx;
-       struct regulator *mx;
-       struct regulator *pll;
+       struct regulator_bulk_data supply[4];
 
        struct clk *ahb_clk;
        struct clk *axi_clk;
        struct clk *rom_clk;
 
        struct completion start_done;
+       struct completion stop_done;
+       bool running;
 
-       void                    *mba_va;
-       dma_addr_t              mba_da;
-       size_t                  mba_size;
-       struct dma_attrs        mba_attrs;
+       phys_addr_t mba_phys;
+       void *mba_region;
+       size_t mba_size;
 
-       phys_addr_t reloc_phys;
-       size_t reloc_size;
+       phys_addr_t mpss_phys;
+       phys_addr_t mpss_reloc;
+       void *mpss_region;
+       size_t mpss_size;
 };
 
-#define VDD_MSS_UV     1000000
-#define VDD_MSS_UV_MAX 1150000
-#define VDD_MSS_UA     100000
-
-/* Q6 Register Offsets */
-#define QDSP6SS_RST_EVB                 0x010
-
-/* AXI Halting Registers */
-#define MSS_Q6_HALT_BASE                0x180
-#define MSS_MODEM_HALT_BASE             0x200
-#define MSS_NC_HALT_BASE                0x280
-
-/* RMB Status Register Values */
-#define STATUS_PBL_SUCCESS              0x1
-#define STATUS_XPU_UNLOCKED             0x1
-#define STATUS_XPU_UNLOCKED_SCRIBBLED   0x2
-
-/* PBL/MBA interface registers */
-#define RMB_MBA_IMAGE                   0x00
-#define RMB_PBL_STATUS                  0x04
-#define RMB_MBA_COMMAND                 0x08
-#define RMB_MBA_STATUS                  0x0C
-#define RMB_PMI_META_DATA               0x10
-#define RMB_PMI_CODE_START              0x14
-#define RMB_PMI_CODE_LENGTH             0x18
-
-#define POLL_INTERVAL_US                50
-
-#define CMD_META_DATA_READY             0x1
-#define CMD_LOAD_READY                  0x2
+enum {
+       Q6V5_SUPPLY_CX,
+       Q6V5_SUPPLY_MX,
+       Q6V5_SUPPLY_MSS,
+       Q6V5_SUPPLY_PLL,
+};
 
-#define STATUS_META_DATA_AUTH_SUCCESS   0x3
-#define STATUS_AUTH_COMPLETE            0x4
+static int q6v5_regulator_init(struct q6v5 *qproc)
+{
+       int ret;
 
-/* External BHS */
-#define EXTERNAL_BHS_ON                 BIT(0)
-#define EXTERNAL_BHS_STATUS             BIT(4)
-#define BHS_TIMEOUT_US                  50
+       qproc->supply[Q6V5_SUPPLY_CX].supply = "cx";
+       qproc->supply[Q6V5_SUPPLY_MX].supply = "mx";
+       qproc->supply[Q6V5_SUPPLY_MSS].supply = "mss";
+       qproc->supply[Q6V5_SUPPLY_PLL].supply = "pll";
 
-#define MSS_RESTART_ID                  0xA
+       ret = devm_regulator_bulk_get(qproc->dev,
+                                     ARRAY_SIZE(qproc->supply), qproc->supply);
+       if (ret < 0) {
+               dev_err(qproc->dev, "failed to get supplies\n");
+               return ret;
+       }
 
-/* QDSP6SS Register Offsets */
-#define QDSP6SS_RESET                   0x014
-#define QDSP6SS_GFMUX_CTL               0x020
-#define QDSP6SS_PWR_CTL                 0x030
-#define QDSP6SS_STRAP_ACC               0x110
+       regulator_set_load(qproc->supply[Q6V5_SUPPLY_CX].consumer, 100000);
+       regulator_set_load(qproc->supply[Q6V5_SUPPLY_MSS].consumer, 100000);
+       regulator_set_load(qproc->supply[Q6V5_SUPPLY_PLL].consumer, 10000);
 
-/* AXI Halt Register Offsets */
-#define AXI_HALTREQ                     0x0
-#define AXI_HALTACK                     0x4
-#define AXI_IDLE                        0x8
+       return 0;
+}
 
-#define HALT_ACK_TIMEOUT_US             100000
+static int q6v5_regulator_enable(struct q6v5 *qproc)
+{
+       int ret;
 
-/* QDSP6SS_RESET */
-#define Q6SS_STOP_CORE                  BIT(0)
-#define Q6SS_CORE_ARES                  BIT(1)
-#define Q6SS_BUS_ARES_ENA               BIT(2)
+       /* TODO: Q6V5_SUPPLY_CX is supposed to be set to super-turbo here */
+       ret = regulator_set_voltage(qproc->supply[Q6V5_SUPPLY_MX].consumer,
+                                   1050000, INT_MAX);
+       if (ret)
+               return ret;
 
-/* QDSP6SS_GFMUX_CTL */
-#define Q6SS_CLK_ENA                    BIT(1)
-#define Q6SS_CLK_SRC_SEL_C              BIT(3)
-#define Q6SS_CLK_SRC_SEL_FIELD          0xC
-#define Q6SS_CLK_SRC_SWITCH_CLK_OVR     BIT(8)
+       regulator_set_voltage(qproc->supply[Q6V5_SUPPLY_MSS].consumer,
+                             1000000, 1150000);
 
-/* QDSP6SS_PWR_CTL */
-#define Q6SS_L2DATA_SLP_NRET_N_0        BIT(0)
-#define Q6SS_L2DATA_SLP_NRET_N_1        BIT(1)
-#define Q6SS_L2DATA_SLP_NRET_N_2        BIT(2)
-#define Q6SS_L2TAG_SLP_NRET_N           BIT(16)
-#define Q6SS_ETB_SLP_NRET_N             BIT(17)
-#define Q6SS_L2DATA_STBY_N              BIT(18)
-#define Q6SS_SLP_RET_N                  BIT(19)
-#define Q6SS_CLAMP_IO                   BIT(20)
-#define QDSS_BHS_ON                     BIT(21)
-#define QDSS_LDO_BYP                    BIT(22)
-
-/* QDSP6v55 parameters */
-#define QDSP6v55_LDO_ON                 BIT(26)
-#define QDSP6v55_LDO_BYP                BIT(25)
-#define QDSP6v55_BHS_ON                 BIT(24)
-#define QDSP6v55_CLAMP_WL               BIT(21)
-#define L1IU_SLP_NRET_N                 BIT(15)
-#define L1DU_SLP_NRET_N                 BIT(14)
-#define L2PLRU_SLP_NRET_N               BIT(13)
-
-#define HALT_CHECK_MAX_LOOPS            (200)
-#define QDSP6SS_XO_CBCR                 (0x0038)
-
-#define QDSP6SS_ACC_OVERRIDE_VAL        0x20
-
-#define segment_is_hash(flag) (((flag) & (0x7 << 24)) == (0x2 << 24))
-static int segment_is_loadable(const struct elf32_phdr *p)
-{
-       return (p->p_type == PT_LOAD) &&
-              !segment_is_hash(p->p_flags) &&
-              p->p_memsz;
+       return regulator_bulk_enable(ARRAY_SIZE(qproc->supply), qproc->supply);
 }
 
-static bool segment_is_relocatable(const struct elf32_phdr *p)
+static void q6v5_regulator_disable(struct q6v5 *qproc)
 {
-       return !!(p->p_flags & BIT(27));
+       regulator_bulk_disable(ARRAY_SIZE(qproc->supply), qproc->supply);
+       regulator_set_voltage(qproc->supply[Q6V5_SUPPLY_CX].consumer, 0, INT_MAX);
+       regulator_set_voltage(qproc->supply[Q6V5_SUPPLY_MX].consumer, 0, INT_MAX);
+       regulator_set_voltage(qproc->supply[Q6V5_SUPPLY_MSS].consumer, 0, 1150000);
 }
 
-static int qproc_sanity_check(struct rproc *rproc,
-                                 const struct firmware *fw)
+static int q6v5_load(struct rproc *rproc, const struct firmware *fw)
 {
-       if (!fw) {
-               dev_err(&rproc->dev, "failed to load %s\n", rproc->name);
-               return -EINVAL;
-       }
+       struct q6v5 *qproc = rproc->priv;
 
-       /* XXX: ??? */
+       memcpy(qproc->mba_region, fw->data, fw->size);
 
        return 0;
 }
 
-static struct resource_table * qproc_find_rsc_table(struct rproc *rproc,
-                                                   const struct firmware *fw,
-                                                   int *tablesz)
+static const struct rproc_fw_ops q6v5_fw_ops = {
+       .find_rsc_table = qcom_mdt_find_rsc_table,
+       .load = q6v5_load,
+};
+
+static int q6v5_rmb_pbl_wait(struct q6v5 *qproc, int ms)
 {
-       static struct resource_table table = { .ver = 1, };
+       unsigned long timeout;
+       s32 val;
 
-       *tablesz = sizeof(table);
-       return &table;
+       timeout = jiffies + msecs_to_jiffies(ms);
+       for (;;) {
+               val = readl(qproc->rmb_base + RMB_PBL_STATUS_REG);
+               if (val)
+                       break;
+
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+
+               msleep(1);
+       }
+
+       return val;
 }
 
-static int qproc_load(struct rproc *rproc, const struct firmware *fw)
+static int q6v5_rmb_mba_wait(struct q6v5 *qproc, u32 status, int ms)
 {
-       struct qproc *qproc = rproc->priv;
-       DEFINE_DMA_ATTRS(attrs);
-       dma_addr_t phys;
-       dma_addr_t end;
-       void *ptr;
 
-       dma_set_mask(qproc->dev, DMA_BIT_MASK(32));
-       dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &attrs);
+       unsigned long timeout;
+       s32 val;
 
-       ptr = dma_alloc_attrs(qproc->dev, fw->size, &phys, GFP_KERNEL, &attrs);
-       if (!ptr) {
-               dev_err(qproc->dev, "failed to allocate mba metadata buffer\n");
-               return -ENOMEM;
-       }
+       timeout = jiffies + msecs_to_jiffies(ms);
+       for (;;) {
+               val = readl(qproc->rmb_base + RMB_MBA_STATUS_REG);
+               if (val < 0)
+                       break;
 
-       end = phys + fw->size;
-       dev_info(qproc->dev, "loading MBA from %pa to %pa\n", &phys, &end);
+               if (!status && val)
+                       break;
+               else if (status && val == status)
+                       break;
 
-       memcpy(ptr, fw->data, fw->size);
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
 
-       qproc->mba_va = ptr;
-       qproc->mba_da = phys;
-       qproc->mba_size = fw->size;
-       qproc->mba_attrs = attrs;
+               msleep(1);
+       }
 
-       return 0;
+       return val;
 }
 
-static const struct rproc_fw_ops qproc_fw_ops = {
-       .find_rsc_table = qproc_find_rsc_table,
-       .load = qproc_load,
-       .sanity_check = qproc_sanity_check,
-};
-
-static void q6v5proc_reset(struct qproc *qproc)
+static void q6v5proc_reset(struct q6v5 *qproc)
 {
        u32 val;
 
        /* Assert resets, stop core */
-       val = readl_relaxed(qproc->reg_base + QDSP6SS_RESET);
-       val |= (Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENA | Q6SS_STOP_CORE);
-       writel_relaxed(val, qproc->reg_base + QDSP6SS_RESET);
+       val = readl(qproc->reg_base + QDSP6SS_RESET_REG);
+       val |= (Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE);
+       writel(val, qproc->reg_base + QDSP6SS_RESET_REG);
 
        /* Enable power block headswitch, and wait for it to stabilize */
-       val = readl_relaxed(qproc->reg_base + QDSP6SS_PWR_CTL);
+       val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG);
        val |= QDSS_BHS_ON | QDSS_LDO_BYP;
-       writel_relaxed(val, qproc->reg_base + QDSP6SS_PWR_CTL);
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
        mb();
        udelay(1);
 
@@ -270,604 +265,214 @@ static void q6v5proc_reset(struct qproc *qproc)
         * Turn on memories. L2 banks should be done individually
         * to minimize inrush current.
         */
-       val = readl_relaxed(qproc->reg_base + QDSP6SS_PWR_CTL);
+       val = readl(qproc->reg_base + QDSP6SS_PWR_CTL_REG);
        val |= Q6SS_SLP_RET_N | Q6SS_L2TAG_SLP_NRET_N |
                Q6SS_ETB_SLP_NRET_N | Q6SS_L2DATA_STBY_N;
-       writel_relaxed(val, qproc->reg_base + QDSP6SS_PWR_CTL);
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
        val |= Q6SS_L2DATA_SLP_NRET_N_2;
-       writel_relaxed(val, qproc->reg_base + QDSP6SS_PWR_CTL);
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
        val |= Q6SS_L2DATA_SLP_NRET_N_1;
-       writel_relaxed(val, qproc->reg_base + QDSP6SS_PWR_CTL);
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
        val |= Q6SS_L2DATA_SLP_NRET_N_0;
-       writel_relaxed(val, qproc->reg_base + QDSP6SS_PWR_CTL);
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
 
        /* Remove IO clamp */
        val &= ~Q6SS_CLAMP_IO;
-       writel_relaxed(val, qproc->reg_base + QDSP6SS_PWR_CTL);
+       writel(val, qproc->reg_base + QDSP6SS_PWR_CTL_REG);
 
        /* Bring core out of reset */
-       val = readl_relaxed(qproc->reg_base + QDSP6SS_RESET);
+       val = readl(qproc->reg_base + QDSP6SS_RESET_REG);
        val &= ~Q6SS_CORE_ARES;
-       writel_relaxed(val, qproc->reg_base + QDSP6SS_RESET);
+       writel(val, qproc->reg_base + QDSP6SS_RESET_REG);
 
        /* Turn on core clock */
-       val = readl_relaxed(qproc->reg_base + QDSP6SS_GFMUX_CTL);
-       val |= Q6SS_CLK_ENA;
-
-#if 0
-       /* Need a different clock source for v5.2.0 */
-       if (qproc->qdsp6v5_2_0) {
-               val &= ~Q6SS_CLK_SRC_SEL_FIELD;
-               val |= Q6SS_CLK_SRC_SEL_C;
-       }
-
-#endif
-       /* force clock on during source switch */
-//     if (qproc->qdsp6v56)
-               val |= Q6SS_CLK_SRC_SWITCH_CLK_OVR;
-
-       writel_relaxed(val, qproc->reg_base + QDSP6SS_GFMUX_CTL);
+       val = readl(qproc->reg_base + QDSP6SS_GFMUX_CTL_REG);
+       val |= Q6SS_CLK_ENABLE;
+       writel(val, qproc->reg_base + QDSP6SS_GFMUX_CTL_REG);
 
        /* Start core execution */
-       val = readl_relaxed(qproc->reg_base + QDSP6SS_RESET);
+       val = readl(qproc->reg_base + QDSP6SS_RESET_REG);
        val &= ~Q6SS_STOP_CORE;
-       writel_relaxed(val, qproc->reg_base + QDSP6SS_RESET);
+       writel(val, qproc->reg_base + QDSP6SS_RESET_REG);
 }
 
-static void q6v5proc_halt_axi_port(struct qproc *qproc, void __iomem *halt)
+static void q6v5proc_halt_axi_port(struct q6v5 *qproc,
+                                  struct regmap *halt_map,
+                                  u32 offset)
 {
        unsigned long timeout;
+       unsigned int val;
+       int ret;
 
-       if (readl_relaxed(halt + AXI_IDLE))
+       /* Check if we're already idle */
+       ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val);
+       if (!ret && val)
                return;
 
-        /* Assert halt request */
-        writel_relaxed(1, halt + AXI_HALTREQ);
+       /* Assert halt request */
+       regmap_write(halt_map, offset + AXI_HALTREQ_REG, 1);
 
-        /* Wait for halt */
-       timeout = jiffies + 10 * HZ;
+       /* Wait for halt */
+       timeout = jiffies + msecs_to_jiffies(HALT_ACK_TIMEOUT_MS);
        for (;;) {
-               if (readl(halt + AXI_HALTACK) || time_after(jiffies, timeout))
+               ret = regmap_read(halt_map, offset + AXI_HALTACK_REG, &val);
+               if (ret || val || time_after(jiffies, timeout))
                        break;
 
                msleep(1);
        }
 
-       if (!readl_relaxed(halt + AXI_IDLE))
-               dev_err(qproc->dev, "port %pa failed halt\n", &halt);
+       ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val);
+       if (ret || !val)
+               dev_err(qproc->dev, "port failed halt\n");
 
-        /* Clear halt request (port will remain halted until reset) */
-        writel_relaxed(0, halt + AXI_HALTREQ);
+       /* Clear halt request (port will remain halted until reset) */
+       regmap_write(halt_map, offset + AXI_HALTREQ_REG, 0);
 }
 
-static int qproc_mba_load_mdt(struct qproc *qproc, const struct firmware *fw)
+static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
 {
        DEFINE_DMA_ATTRS(attrs);
-       unsigned long timeout;
        dma_addr_t phys;
-       dma_addr_t end;
        void *ptr;
        int ret;
-       s32 val;
 
-       dma_set_mask(qproc->dev, DMA_BIT_MASK(32));
        dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &attrs);
-
        ptr = dma_alloc_attrs(qproc->dev, fw->size, &phys, GFP_KERNEL, &attrs);
        if (!ptr) {
-               dev_err(qproc->dev, "failed to allocate mba metadata buffer\n");
+               dev_err(qproc->dev, "failed to allocate mdt buffer\n");
                return -ENOMEM;
        }
 
-       end = phys + fw->size;
-       dev_info(qproc->dev, "loading mdt header from %pa to %pa\n", &phys, &end);
-
        memcpy(ptr, fw->data, fw->size);
 
-       writel_relaxed(0, qproc->rmb_base + RMB_PMI_CODE_LENGTH);
+       writel(phys, qproc->rmb_base + RMB_PMI_META_DATA_REG);
+       writel(RMB_CMD_META_DATA_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG);
 
-       writel_relaxed(phys, qproc->rmb_base + RMB_PMI_META_DATA);
-       writel(CMD_META_DATA_READY, qproc->rmb_base + RMB_MBA_COMMAND);
+       ret = q6v5_rmb_mba_wait(qproc, RMB_MBA_META_DATA_AUTH_SUCCESS, 1000);
+       if (ret == -ETIMEDOUT)
+               dev_err(qproc->dev, "MBA header authentication timed out\n");
+       else if (ret < 0)
+               dev_err(qproc->dev, "MBA returned error %d for MDT header\n", ret);
 
-       timeout = jiffies + HZ;
-       for (;;) {
-               msleep(1);
-
-               val = readl(qproc->rmb_base + RMB_MBA_STATUS);
-               if (val == STATUS_META_DATA_AUTH_SUCCESS || val < 0)
-                       break;
-
-               if (time_after(jiffies, timeout))
-                       break;
-       }
-       if (val == 0) {
-               dev_err(qproc->dev, "MBA authentication of headers timed out\n");
-               ret = -ETIMEDOUT;
-               goto out;
-       } else if (val < 0) {
-               dev_err(qproc->dev, "MBA returned error %d for headers\n", val);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       dev_err(qproc->dev, "mdt authenticated\n");
-
-       ret = 0;
-out:
        dma_free_attrs(qproc->dev, fw->size, ptr, phys, &attrs);
 
-       return ret;
+       return ret < 0 ? ret : 0;
 }
 
-
-static int
-old_qproc_load_segments(struct qproc *qproc, const struct firmware *fw)
+static int q6v5_mpss_validate(struct q6v5 *qproc, const struct firmware *fw)
 {
-       struct device *dev = qproc->dev;
+       const struct elf32_phdr *phdrs;
+       const struct elf32_phdr *phdr;
        struct elf32_hdr *ehdr;
-       struct elf32_phdr *phdr;
-       int i, ret = 0;
-       const u8 *elf_data = fw->data;
-       const struct firmware *seg_fw;
-       char fw_name[20];
-
-       ehdr = (struct elf32_hdr *)elf_data;
-       phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
-
-
-
-       /* go through the available ELF segments */
-       for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
-               u32 da = phdr->p_paddr;
-               u32 memsz = phdr->p_memsz;
-               u32 filesz = phdr->p_filesz;
-               void *ptr;
-
-               if (!segment_is_loadable(phdr))
-                       continue;
-               /*
-               if (phdr->p_type != PT_LOAD)
-                       continue;
-
-               if (segment_is_hash(phdr->p_flags))
-                       continue;
-
-               if (filesz == 0)
-                       continue;
-*/
-               //dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
-               pr_emerg("phdr(%d): type %d da 0x%x memsz 0x%x filesz 0x%x\n",
-                                       i, phdr->p_type, da, memsz, filesz);
-
-               if (filesz > memsz) {
-                       dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
-                                                       filesz, memsz);
-                       ret = -EINVAL;
-                       break;
-               }
-
-               ptr = ioremap(da, memsz);
-               if (!ptr) {
-                       dev_err(qproc->dev, "failed to allocate mba metadata buffer\n");
-                       ret = -ENOMEM;
-                       break;
-               }
-
-               if (filesz) {
-                       snprintf(fw_name, sizeof(fw_name), "modem.b%02d", i);
-                       ret = request_firmware(&seg_fw, fw_name, qproc->dev);
-                       if (ret) {
-                               iounmap(ptr);
-                               break;
-                       }
-
-                       memcpy(ptr, seg_fw->data, filesz);
-
-                       release_firmware(seg_fw);
-               }
-
-               if (memsz > filesz)
-                       memset(ptr + filesz, 0, memsz - filesz);
-
-
-
-               wmb();
-               iounmap(ptr);
-       }
-
-       return ret;
-}
-
-static int qproc_verify_segment(struct qproc *qproc, phys_addr_t paddr, size_t size)
-{
-       s32 status;
-       u32 img_length;
-
-       img_length = readl_relaxed(qproc->rmb_base + RMB_PMI_CODE_LENGTH);
-       dev_err(qproc->dev, "RMB_PMI_CODE_LENGTH: %x\n", img_length);
-
-       msleep(1);
-       img_length = readl_relaxed(qproc->rmb_base + RMB_PMI_CODE_LENGTH);
-       dev_err(qproc->dev, "RMB_PMI_CODE_LENGTH: %x\n", img_length);
-
-
-       if (img_length == 0) {
-               writel_relaxed(paddr, qproc->rmb_base + RMB_PMI_CODE_START);
-               writel(CMD_LOAD_READY, qproc->rmb_base + RMB_MBA_COMMAND);
-       }
-       img_length += size;
-       writel(img_length, qproc->rmb_base + RMB_PMI_CODE_LENGTH);
-
-       img_length = readl_relaxed(qproc->rmb_base + RMB_PMI_CODE_LENGTH);
-       dev_err(qproc->dev, "RMB_PMI_CODE_LENGTH: %x\n", img_length);
-       
-       status = readl_relaxed(qproc->rmb_base + RMB_MBA_STATUS);
-
-
-       if (status < 0) {
-               dev_err(qproc->dev, "MBA returned error %d\n", status);
-       }
-
-       printk("DEBUG:pil: status... %08x\n", readl_relaxed(qproc->rmb_base + RMB_MBA_STATUS));
-
-       return 0;
-}
-
-static int qproc_load_segment(struct qproc *rproc, const char *fw_name,
-                               const struct elf32_phdr *phdr, phys_addr_t paddr)
-{
-       const struct firmware *fw;
-       void *ptr;
-       int ret = 0;
-
-       ptr = ioremap_nocache(paddr, phdr->p_memsz);
-       if (!ptr) {
-               dev_err(rproc->dev, "failed to ioremap segment area (%pa+0x%x)\n", &paddr, phdr->p_memsz);
-               return -EBUSY;
-       }
-
-       if (phdr->p_filesz) {
-               ret = request_firmware(&fw, fw_name, rproc->dev);
-               if (ret) {
-                       dev_err(rproc->dev, "failed to load %s\n", fw_name);
-                       goto out;
-               }
-
-               memcpy_toio(ptr, fw->data, fw->size);
+       phys_addr_t boot_addr;
+       phys_addr_t fw_addr;
+       bool relocate;
+       size_t size;
+       u32 val;
+       int ret;
+       int i;
 
-               release_firmware(fw);
+       ret = qcom_mdt_parse(fw, &fw_addr, NULL, &relocate);
+       if (ret) {
+               dev_err(qproc->dev, "failed to parse mdt header\n");
+               return ret;
        }
 
-       if (phdr->p_memsz > phdr->p_filesz)
-               memset_io(ptr + phdr->p_filesz, 0,
-                         phdr->p_memsz - phdr->p_filesz);
-
-       printk("DEBUG:pil: verifing %s size: %x\n",fw_name, phdr->p_memsz);
-       qproc_verify_segment(rproc, paddr, phdr->p_memsz);
-
-out:
-       iounmap(ptr);
-       return ret;
-}
-
-static int
-qproc_load_segments(struct qproc *qproc, const struct firmware *fw)
-{
-       struct device *dev = qproc->dev;
-       struct elf32_hdr *ehdr;
-       struct elf32_phdr *phdr;
-       int i, ret = 0;
-       const u8 *elf_data = fw->data;
-       const struct firmware *seg_fw;
-       char fw_name[20];
-
-       const struct mdt_hdr *mdt;
-       phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX;
-       phys_addr_t max_addr = 0;
-       size_t align = 0;
-       bool relocatable = false;
-       phys_addr_t paddr;
-
-
-       ehdr = (struct elf32_hdr *)elf_data;
-       phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
-
-
-       mdt = (struct mdt_hdr *)fw->data;
-       ehdr = &mdt->hdr;
-
-       for (i = 0; i < ehdr->e_phnum; i++) {
-               phdr = &mdt->phdr[i];
-
-               if (!segment_is_loadable(phdr))
-                       continue;
-
-               if (phdr->p_paddr < min_addr) {
-                       min_addr = phdr->p_paddr;
-
-                       if (segment_is_relocatable(phdr)) {
-                               align = phdr->p_align;
-                               relocatable = true;
-                       }
-               }
-
-               if (phdr->p_paddr + phdr->p_memsz > max_addr)
-                       max_addr = round_up(phdr->p_paddr + phdr->p_memsz, SZ_4K);
-       }
+       if (relocate)
+               boot_addr = qproc->mpss_phys;
+       else
+               boot_addr = fw_addr;
 
-       ehdr = (struct elf32_hdr *)elf_data;
-       phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
-       /* go through the available ELF segments */
+       ehdr = (struct elf32_hdr *)fw->data;
+       phdrs = (struct elf32_phdr *)(ehdr + 1);
        for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
-               u32 da = phdr->p_paddr;
-               u32 paddr = phdr->p_paddr;
-               u32 memsz = phdr->p_memsz;
-               u32 filesz = phdr->p_filesz;
-               void *ptr;
+               phdr = &phdrs[i];
 
-               if (!segment_is_loadable(phdr))
-                       continue;
-               /*
                if (phdr->p_type != PT_LOAD)
                        continue;
 
-               if (segment_is_hash(phdr->p_flags))
+               if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH)
                        continue;
 
-               if (filesz == 0)
+               if (!phdr->p_memsz)
                        continue;
-*/
-               //dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
-               pr_emerg("phdr(%d): type %d paddr 0x%x memsz 0x%x filesz 0x%x\n",
-                                       i, phdr->p_type, paddr, memsz, filesz);
-
-               if (filesz > memsz) {
-                       dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
-                                                       filesz, memsz);
-                       ret = -EINVAL;
-                       break;
-               }
 
-               paddr = relocatable ?
-                               (phdr->p_paddr - min_addr + qproc->reloc_phys) :
-                               phdr->p_paddr;
-
-               pr_emerg("Relocated-phdr(%d): type %d paddr 0x%x memsz 0x%x filesz 0x%x\n",
-                                       i, phdr->p_type, paddr, memsz, filesz);
-//             if (filesz) {
-                       snprintf(fw_name, sizeof(fw_name), "modem.b%02d", i);
-                       ret = qproc_load_segment(qproc, fw_name, phdr, paddr);
-//             }
-#if 0
-
-               ptr = ioremap(da, memsz);
-               if (!ptr) {
-                       dev_err(qproc->dev, "failed to allocate mba metadata buffer\n");
-                       ret = -ENOMEM;
-                       break;
+               size = readl(qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
+               if (!size) {
+                       writel(boot_addr, qproc->rmb_base + RMB_PMI_CODE_START_REG);
+                       writel(RMB_CMD_LOAD_READY, qproc->rmb_base + RMB_MBA_COMMAND_REG);
                }
 
-               if (filesz) {
-                       snprintf(fw_name, sizeof(fw_name), "modem.b%02d", i);
-                       ret = request_firmware(&seg_fw, fw_name, qproc->dev);
-                       if (ret) {
-                               iounmap(ptr);
-                               break;
-                       }
-
-                       memcpy(ptr, seg_fw->data, filesz);
-
-                       release_firmware(seg_fw);
-               }
-
-               if (memsz > filesz)
-                       memset(ptr + filesz, 0, memsz - filesz);
-
-
-
-               wmb();
-               iounmap(ptr);
-#endif
+               size += phdr->p_memsz;
+               writel(size, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
        }
 
-       return ret;
+       val = readl(qproc->rmb_base + RMB_MBA_STATUS_REG);
+       return val < 0 ? val : 0;
 }
 
-static int qproc_verify_segments(struct qproc *qproc, const struct firmware *fw)
+static int q6v5_mpss_load(struct q6v5 *qproc)
 {
-       struct elf32_hdr *ehdr;
-       struct elf32_phdr *phdr;
-       const u8 *elf_data = fw->data;
-       unsigned long timeout;
-       phys_addr_t min_addr = (phys_addr_t)ULLONG_MAX;
-       u32 size = 0;
-       s32 val;
+       const struct firmware *fw;
+       phys_addr_t fw_addr;
+       bool relocate;
        int ret;
-       int i;
-       u32 v;
-
-       ehdr = (struct elf32_hdr *)elf_data;
-       phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
-
-       v = readl_relaxed(qproc->rmb_base + RMB_PMI_CODE_LENGTH);
-       dev_err(qproc->dev, "RMB_PMI_CODE_LENGTH: %pa\n", &v);
-
-       msleep(1);
-
-
-#if 1
-       for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
-               phys_addr_t da = phdr->p_paddr;
-               u32 memsz = phdr->p_memsz;
-
-
-               if (!segment_is_loadable(phdr))
-                       continue;
-               /*
-               if (phdr->p_type != PT_LOAD)
-                       continue;
-*/
-               dev_err(qproc->dev, "0x%x %d %d\n", phdr->p_paddr, segment_is_hash(phdr->p_flags), !!(phdr->p_flags & BIT(27)));
-
-               /*
-               if (segment_is_hash(phdr->p_flags))
-                       continue;
-
-               if (memsz == 0)
-                       continue;
-               */
-               if (da < min_addr)
-                       min_addr = da;
-
-               size += memsz;
-       }
-
-       dev_err(qproc->dev, "verify: %pa:%pa\n", &min_addr, &size);
-       v = readl_relaxed(qproc->rmb_base + RMB_PMI_CODE_LENGTH);
-       dev_err(qproc->dev, "RMB_PMI_CODE_LENGTH: %pa\n", &v);
-#if 0
-if (v == 0) {
-       writel_relaxed(min_addr, qproc->rmb_base + RMB_PMI_CODE_START);
-       writel(CMD_LOAD_READY, qproc->rmb_base + RMB_MBA_COMMAND);
-}
-       writel(size, qproc->rmb_base + RMB_PMI_CODE_LENGTH);
-#endif
-#endif
-
-       v = readl_relaxed(qproc->rmb_base + RMB_PMI_CODE_LENGTH);
-       dev_err(qproc->dev, "RMB_PMI_CODE_LENGTH: %pa\n", &v);
-       
-       printk("DEBUG:pil: status... %08x\n", readl_relaxed(qproc->rmb_base + RMB_MBA_STATUS));
 
-       timeout = jiffies + 10 * HZ;
-       for (;;) {
-               msleep(1);
-
-               val = readl(qproc->rmb_base + RMB_MBA_STATUS);
-               if (val == STATUS_AUTH_COMPLETE || val < 0)
-                       break;
-
-               if (time_after(jiffies, timeout))
-                       break;
-       }
-       if (val == 0) {
-               dev_err(qproc->dev, "MBA authentication of headers timed out\n");
-               ret = -ETIMEDOUT;
-               goto out;
-       } else if (val < 0) {
-               dev_err(qproc->dev, "MBA returned error %d for segments\n", val);
-               ret = -EINVAL;
-               goto out;
+       ret = request_firmware(&fw, MPSS_FIRMWARE_NAME, qproc->dev);
+       if (ret < 0) {
+               dev_err(qproc->dev, "unable to load " MPSS_FIRMWARE_NAME "\n");
+               return ret;
        }
 
-       ret = 0;
-out:
-       return ret;
-
-
-}
-
-static int qproc_msa_mba_auth(struct qproc *qproc)
-{
-       unsigned long timeout;
-       s32 val;
-       int ret;
-       int i;
-       u32 v;
-
-       timeout = jiffies + 10 * HZ;
-       for (;;) {
-               msleep(1);
-
-               val = readl(qproc->rmb_base + RMB_MBA_STATUS);
-               if (val == STATUS_AUTH_COMPLETE || val < 0)
-                       break;
-
-               if (time_after(jiffies, timeout))
-                       break;
-       }
-       if (val == 0) {
-               dev_err(qproc->dev, "MBA authentication of headers timed out\n");
-               ret = -ETIMEDOUT;
-//             goto out;
-       } else if (val < 0) {
-               dev_err(qproc->dev, "MBA returned error %d for segments\n", val);
-               ret = -EINVAL;
-//             goto out;
+       ret = qcom_mdt_parse(fw, &fw_addr, NULL, &relocate);
+       if (ret) {
+               dev_err(qproc->dev, "failed to parse mdt header\n");
+               goto release_firmware;
        }
-       printk("DEBUG:pil: status auth... %08x\n", readl_relaxed(qproc->rmb_base + RMB_MBA_STATUS));
-
-       return 0;
-}
 
-static int qproc_load_modem(struct qproc *qproc)
-{
-       const struct firmware *fw;
-       int ret;
+       if (relocate)
+               qproc->mpss_reloc = fw_addr;
 
-       ret = request_firmware(&fw, "modem.mdt", qproc->dev);
-       if (ret < 0) {
-               dev_err(qproc->dev, "unable to load modem.mdt\n");
-               return ret;
-       }
+       /* Initialize the RMB validator */
+       writel(0, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
 
-       dev_err(qproc->dev, "Loading mba\n");
-       ret = qproc_mba_load_mdt(qproc, fw);
+       ret = q6v5_mpss_init_image(qproc, fw);
        if (ret)
-               goto out;
+               goto release_firmware;
 
-       dev_err(qproc->dev, "Loading segments\n");
-       ret = qproc_load_segments(qproc, fw);
+       ret = qcom_mdt_load(qproc->rproc, fw, MPSS_FIRMWARE_NAME);
        if (ret)
-               goto out;
+               goto release_firmware;
 
-       ret = qproc_msa_mba_auth(qproc);
-//     dev_err(qproc->dev, "Verifying segments\n");
-//     ret = qproc_verify_segments(qproc, fw);
-//     if (ret)
-//             goto out;
-       return 0;
-out:
-       release_firmware(fw);
+       ret = q6v5_mpss_validate(qproc, fw);
+       if (ret)
+               goto release_firmware;
 
-       return ret;
-}
+       ret = q6v5_rmb_mba_wait(qproc, RMB_MBA_AUTH_COMPLETE, 10000);
+       if (ret == -ETIMEDOUT)
+               dev_err(qproc->dev, "MBA authentication timed out\n");
+       else if (ret < 0)
+               dev_err(qproc->dev, "MBA returned error %d\n", ret);
 
-static int pil_mss_restart_reg(struct qproc *qproc, int mss_restart)
-{
-       int ret = 0;
-       unsigned int resp;
-       ret = qcom_scm_restart_proc(MSS_RESTART_ID, mss_restart, &resp);
-       if (ret || resp)
-               pr_err("Secure MSS restart failed\n");
+release_firmware:
+       release_firmware(fw);
 
-       return ret;
+       return ret < 0 ? ret : 0;
 }
 
-static int qproc_start(struct rproc *rproc)
+static int q6v5_start(struct rproc *rproc)
 {
-       struct qproc *qproc = (struct qproc *)rproc->priv;
-       unsigned long timeout;
+       struct q6v5 *qproc = (struct q6v5 *)rproc->priv;
        int ret;
-       u32 val;
-
-       printk("DEBUG::: pill................... %s \n", __func__);
-//     ret = regulator_enable(qproc->vdd);
-//     if (ret) {
-//             dev_err(qproc->dev, "failed to enable mss vdd\n");
-//             return ret;
-//     }
 
-       ret = regulator_enable(qproc->pll);
+       ret = q6v5_regulator_enable(qproc);
        if (ret) {
-               dev_err(qproc->dev, "failed to enable mss vdd pll\n");
+               dev_err(qproc->dev, "failed to enable supplies\n");
                return ret;
        }
 
-
-       ret = pil_mss_restart_reg(qproc, 0);
-       //FIXME
-       //ret = reset_control_deassert(qproc->mss_restart);
+       ret = reset_control_deassert(qproc->mss_restart);
        if (ret) {
                dev_err(qproc->dev, "failed to deassert mss restart\n");
                goto disable_vdd;
@@ -885,61 +490,54 @@ static int qproc_start(struct rproc *rproc)
        if (ret)
                goto disable_axi_clk;
 
-       writel_relaxed(qproc->mba_da, qproc->rmb_base + RMB_MBA_IMAGE);
-
-       /* Ensure order of data/entry point and the following reset release */
-       wmb();
+       writel(qproc->mba_phys, qproc->rmb_base + RMB_MBA_IMAGE_REG);
 
        q6v5proc_reset(qproc);
 
-       timeout = jiffies + HZ;
-       for (;;) {
-               msleep(1);
-
-               val = readl(qproc->rmb_base + RMB_PBL_STATUS);
-               if (val || time_after(jiffies, timeout))
-                       break;
-       }
-       if (val == 0) {
+       ret = q6v5_rmb_pbl_wait(qproc, 1000);
+       if (ret == -ETIMEDOUT) {
                dev_err(qproc->dev, "PBL boot timed out\n");
-               ret = -ETIMEDOUT;
                goto halt_axi_ports;
-       } else if (val != STATUS_PBL_SUCCESS) {
-               dev_err(qproc->dev, "PBL returned unexpected status %d\n", val);
+       } else if (ret != RMB_PBL_SUCCESS) {
+               dev_err(qproc->dev, "PBL returned unexpected status %d\n", ret);
                ret = -EINVAL;
                goto halt_axi_ports;
        }
 
-       timeout = jiffies + HZ;
-       for (;;) {
-               msleep(1);
-
-               val = readl(qproc->rmb_base + RMB_MBA_STATUS);
-               if (val || time_after(jiffies, timeout))
-                       break;
-       }
-       if (val == 0) {
+       ret = q6v5_rmb_mba_wait(qproc, 0, 5000);
+       if (ret == -ETIMEDOUT) {
                dev_err(qproc->dev, "MBA boot timed out\n");
-               ret = -ETIMEDOUT;
                goto halt_axi_ports;
-       } else if (val != STATUS_XPU_UNLOCKED && val != STATUS_XPU_UNLOCKED_SCRIBBLED) {
-               dev_err(qproc->dev, "MBA returned unexpected status %d\n", val);
+       } else if (ret != RMB_MBA_XPU_UNLOCKED && ret != RMB_MBA_XPU_UNLOCKED_SCRIBBLED) {
+               dev_err(qproc->dev, "MBA returned unexpected status %d\n", ret);
                ret = -EINVAL;
                goto halt_axi_ports;
        }
 
-       dev_info(qproc->dev, "MBA boot done\n");
+       dev_info(qproc->dev, "MBA booted, loading mpss\n");
 
-       ret = qproc_load_modem(qproc);
+       ret = q6v5_mpss_load(qproc);
        if (ret)
                goto halt_axi_ports;
 
+       ret = wait_for_completion_timeout(&qproc->start_done,
+                                         msecs_to_jiffies(5000));
+       if (ret == 0) {
+               dev_err(qproc->dev, "start timed out\n");
+               ret = -ETIMEDOUT;
+               goto halt_axi_ports;
+       }
+
+       qproc->running = true;
+
+       /* All done, release the handover resources */
+
        return 0;
 
 halt_axi_ports:
-       q6v5proc_halt_axi_port(qproc, qproc->halt_base + MSS_Q6_HALT_BASE);
-       q6v5proc_halt_axi_port(qproc, qproc->halt_base + MSS_MODEM_HALT_BASE);
-       q6v5proc_halt_axi_port(qproc, qproc->halt_base + MSS_NC_HALT_BASE);
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6);
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem);
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc);
 disable_axi_clk:
        clk_disable_unprepare(qproc->axi_clk);
 disable_ahb_clk:
@@ -947,215 +545,199 @@ disable_ahb_clk:
 assert_reset:
        reset_control_assert(qproc->mss_restart);
 disable_vdd:
-//     regulator_disable(qproc->vdd);
+       q6v5_regulator_disable(qproc);
 
-       dma_free_attrs(qproc->dev, qproc->mba_size, qproc->mba_va, qproc->mba_da, &qproc->mba_attrs);
        return ret;
 }
 
-static int qproc_stop(struct rproc *rproc)
+static int q6v5_stop(struct rproc *rproc)
 {
-       struct qproc *qproc = (struct qproc *)rproc->priv;
+       struct q6v5 *qproc = (struct q6v5 *)rproc->priv;
+       int ret;
+
+       qproc->running = false;
+
+       qcom_smem_state_update_bits(qproc->state,
+                                   BIT(qproc->stop_bit), BIT(qproc->stop_bit));
+
+       ret = wait_for_completion_timeout(&qproc->stop_done,
+                                         msecs_to_jiffies(5000));
+       if (ret == 0)
+               dev_err(qproc->dev, "timed out on wait\n");
 
-       q6v5proc_halt_axi_port(qproc, qproc->halt_base + MSS_Q6_HALT_BASE);
-       q6v5proc_halt_axi_port(qproc, qproc->halt_base + MSS_MODEM_HALT_BASE);
-       q6v5proc_halt_axi_port(qproc, qproc->halt_base + MSS_NC_HALT_BASE);
+       qcom_smem_state_update_bits(qproc->state, BIT(qproc->stop_bit), 0);
+
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6);
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem);
+       q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc);
 
        reset_control_assert(qproc->mss_restart);
        clk_disable_unprepare(qproc->axi_clk);
        clk_disable_unprepare(qproc->ahb_clk);
-//     regulator_disable(qproc->vdd);
-
-       dma_free_attrs(qproc->dev, qproc->mba_size, qproc->mba_va, qproc->mba_da, &qproc->mba_attrs);
+       q6v5_regulator_disable(qproc);
 
        return 0;
 }
 
-static const struct rproc_ops qproc_ops = {
-       .start = qproc_start,
-       .stop = qproc_stop,
-};
-
-static irqreturn_t qproc_wdog_interrupt(int irq, void *dev)
+static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
 {
-       struct qproc *qproc = dev;
+       struct q6v5 *qproc = rproc->priv;
+       int offset;
 
-       dev_err(qproc->dev, "                                                            WATCHDOG\n");
+       offset = da - qproc->mpss_reloc;
+       if (offset < 0 || offset + len > qproc->mpss_size)
+               return NULL;
 
-       rproc_report_crash(qproc->rproc, RPROC_WATCHDOG);
-       return IRQ_HANDLED;
+       return qproc->mpss_region + offset;
 }
 
-static irqreturn_t qproc_fatal_interrupt(int irq, void *dev)
-{
-       struct qproc *qproc = dev;
-
-       dev_err(qproc->dev, "                                                            FATAL\n");
+static const struct rproc_ops q6v5_ops = {
+       .start = q6v5_start,
+       .stop = q6v5_stop,
+       .da_to_va = q6v5_da_to_va,
+};
 
-       rproc_report_crash(qproc->rproc, RPROC_FATAL_ERROR);
+static irqreturn_t q6v5_wdog_interrupt(int irq, void *dev)
+{
+       struct q6v5 *qproc = dev;
+       size_t len;
+       char *msg;
 
-       return IRQ_HANDLED;
-}
+       /* Sometimes the stop triggers a watchdog rather than a stop-ack */
+       if (!qproc->running) {
+               complete(&qproc->stop_done);
+               return IRQ_HANDLED;
+       }
 
-static irqreturn_t qproc_ready_interrupt(int irq, void *dev)
-{
-       struct qproc *qproc = dev;
+       msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, MPSS_CRASH_REASON_SMEM, &len);
+       if (!IS_ERR(msg) && len > 0 && msg[0])
+               dev_err(qproc->dev, "watchdog received: %s\n", msg);
+       else
+               dev_err(qproc->dev, "watchdog without message\n");
 
-       dev_err(qproc->dev, "                                                            READY\n");
+       rproc_report_crash(qproc->rproc, RPROC_WATCHDOG);
 
-       complete(&qproc->start_done);
+       if (!IS_ERR(msg))
+               msg[0] = '\0';
 
        return IRQ_HANDLED;
 }
 
-static irqreturn_t qproc_handover_interrupt(int irq, void *dev)
+static irqreturn_t q6v5_fatal_interrupt(int irq, void *dev)
 {
-       struct qproc *qproc = dev;
+       struct q6v5 *qproc = dev;
+       size_t len;
+       char *msg;
 
-       dev_err(qproc->dev, "                                                            HANDOVER\n");
-
-       return IRQ_HANDLED;
-}
+       msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, MPSS_CRASH_REASON_SMEM, &len);
+       if (!IS_ERR(msg) && len > 0 && msg[0])
+               dev_err(qproc->dev, "fatal error received: %s\n", msg);
+       else
+               dev_err(qproc->dev, "fatal error without message\n");
 
-static irqreturn_t qproc_stop_ack_interrupt(int irq, void *dev)
-{
-       struct qproc *qproc = dev;
+       rproc_report_crash(qproc->rproc, RPROC_FATAL_ERROR);
 
-       dev_err(qproc->dev, "                                                            STOP-ACK\n");
+       if (!IS_ERR(msg))
+               msg[0] = '\0';
 
        return IRQ_HANDLED;
 }
 
-static ssize_t qproc_boot_store(struct device *dev,
-                               struct device_attribute *attr,
-                               const char *buf, size_t size)
+static irqreturn_t q6v5_handover_interrupt(int irq, void *dev)
 {
-       struct qproc *qproc = dev_get_drvdata(dev);
-       int ret;
+       struct q6v5 *qproc = dev;
 
-       ret = rproc_boot(qproc->rproc);
-       return ret ? : size;
+       complete(&qproc->start_done);
+       return IRQ_HANDLED;
 }
 
-static ssize_t qproc_shutdown_store(struct device *dev,
-                                   struct device_attribute *attr,
-                                   const char *buf, size_t size)
+static irqreturn_t q6v5_stop_ack_interrupt(int irq, void *dev)
 {
-       struct qproc *qproc = dev_get_drvdata(dev);
+       struct q6v5 *qproc = dev;
 
-       rproc_shutdown(qproc->rproc);
-       return size;
+       complete(&qproc->stop_done);
+       return IRQ_HANDLED;
 }
 
-static const struct device_attribute qproc_attrs[] = {
-       __ATTR(boot, S_IWUSR, 0, qproc_boot_store),
-       __ATTR(shutdown, S_IWUSR, 0, qproc_shutdown_store),
-};
-
-static int qproc_init_mem(struct qproc *qproc, struct platform_device *pdev)
+static int q6v5_init_mem(struct q6v5 *qproc, struct platform_device *pdev)
 {
+       struct device_node *halt_np;
        struct resource *res;
+       int ret;
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6_base");
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6");
        qproc->reg_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(qproc->reg_base))
+       if (IS_ERR(qproc->reg_base)) {
+               dev_err(qproc->dev, "failed to get qdsp6_base\n");
                return PTR_ERR(qproc->reg_base);
+       }
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "halt_base");
-       qproc->halt_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(qproc->halt_base)) {
-#if 0
-               //return PTR_ERR(qproc->halt_base);
-
-               res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "halt_q6");
-               qproc->halt_q6 = devm_ioremap_resource(&pdev->dev, res);
-               if (IS_ERR(qproc->halt_q6))
-                       return PTR_ERR(qproc->halt_q6);
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb");
+       qproc->rmb_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(qproc->rmb_base)) {
+               dev_err(qproc->dev, "failed to get rmb_base\n");
+               return PTR_ERR(qproc->rmb_base);
+       }
 
+       halt_np = of_parse_phandle(pdev->dev.of_node, "qcom,halt-regs", 0);
+       if (!halt_np) {
+               dev_err(&pdev->dev, "no qcom,halt-regs node\n");
+               return -ENODEV;
+       }
 
-               res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "halt_modem");
-               qproc->halt_modem = devm_ioremap_resource(&pdev->dev, res);
-               if (IS_ERR(qproc->halt_modem))
-                       return PTR_ERR(qproc->halt_modem);
+       qproc->halt_map = syscon_node_to_regmap(halt_np);
+       if (IS_ERR(qproc->halt_map))
+               return PTR_ERR(qproc->halt_map);
 
-               res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "halt_nc");
-               qproc->halt_nc = devm_ioremap_resource(&pdev->dev, res);
-               if (IS_ERR(qproc->halt_nc))
-                       return PTR_ERR(qproc->halt_nc);
-#endif
+       ret = of_property_read_u32_index(pdev->dev.of_node, "qcom,halt-regs",
+                                        1, &qproc->halt_q6);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "no q6 halt offset\n");
+               return -EINVAL;
+       }
 
+       ret = of_property_read_u32_index(pdev->dev.of_node, "qcom,halt-regs",
+                                        2, &qproc->halt_modem);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "no modem halt offset\n");
+               return -EINVAL;
        }
-//Only required if self auth is set???
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb_base");
-       qproc->rmb_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(qproc->rmb_base))
-               return PTR_ERR(qproc->rmb_base);
 
-//     res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "restart_reg_sec");
-//     qproc->restart_sec_base = devm_ioremap_resource(&pdev->dev, res);
-//     if (IS_ERR(qproc->restart_sec_base))
-//             return PTR_ERR(qproc->restart_sec_base);
+       ret = of_property_read_u32_index(pdev->dev.of_node, "qcom,halt-regs",
+                                        3, &qproc->halt_nc);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "no nc halt offset\n");
+               return -EINVAL;
+       }
 
        return 0;
 }
 
-static int qproc_init_clocks(struct qproc *qproc)
+static int q6v5_init_clocks(struct q6v5 *qproc)
 {
        qproc->ahb_clk = devm_clk_get(qproc->dev, "iface");
-       if (IS_ERR(qproc->ahb_clk))
+       if (IS_ERR(qproc->ahb_clk)) {
+               dev_err(qproc->dev, "failed to get iface clock\n");
                return PTR_ERR(qproc->ahb_clk);
+       }
 
        qproc->axi_clk = devm_clk_get(qproc->dev, "bus");
-       if (IS_ERR(qproc->axi_clk))
+       if (IS_ERR(qproc->axi_clk)) {
+               dev_err(qproc->dev, "failed to get bus clock\n");
                return PTR_ERR(qproc->axi_clk);
+       }
 
        qproc->rom_clk = devm_clk_get(qproc->dev, "mem");
-       if (IS_ERR(qproc->rom_clk))
+       if (IS_ERR(qproc->rom_clk)) {
+               dev_err(qproc->dev, "failed to get mem clock\n");
                return PTR_ERR(qproc->rom_clk);
+       }
 
        return 0;
 }
 
-static int qproc_init_regulators(struct qproc *qproc)
-{
-       int ret;
-       u32 uV;
-
-       printk("DEBUG:pil: starting vdd\n");
-//     qproc->vdd = devm_regulator_get_optional(qproc->dev, "qcom,vdd");
-//     if (IS_ERR(qproc->vdd))
-//             return PTR_ERR(qproc->vdd);
-
-//     regulator_set_voltage(qproc->vdd, VDD_MSS_UV, VDD_MSS_UV_MAX);
-//     regulator_set_load(qproc->vdd, VDD_MSS_UA);
-
-       printk("DEBUG:pil: done vdd\n");
-//     qproc->cx = devm_regulator_get(qproc->dev, "qcom,cx");
-//     if (IS_ERR(qproc->cx))
-//             return PTR_ERR(qproc->cx);
-
-       qproc->mx = devm_regulator_get(qproc->dev, "qcom,mx");
-       if (IS_ERR(qproc->mx))
-               return PTR_ERR(qproc->mx);
-
-       ret = of_property_read_u32(qproc->dev->of_node, "qcom,mx-uV", &uV);
-       if (!ret)
-               regulator_set_voltage(qproc->mx, uV, uV);
-
-       qproc->pll = devm_regulator_get(qproc->dev, "qcom,pll");
-       if (IS_ERR(qproc->pll))
-               return PTR_ERR(qproc->pll);
-
-       ret = of_property_read_u32(qproc->dev->of_node, "qcom,pll-uV", &uV);
-       if (!ret)
-               regulator_set_voltage(qproc->pll, uV, uV);
-
-       return 0;
-}
-
-static int qproc_init_reset(struct qproc *qproc)
+static int q6v5_init_reset(struct q6v5 *qproc)
 {
-       //FIXME 
        qproc->mss_restart = devm_reset_control_get(qproc->dev, NULL);
        if (IS_ERR(qproc->mss_restart)) {
                dev_err(qproc->dev, "failed to acquire mss restart\n");
@@ -1165,7 +747,7 @@ static int qproc_init_reset(struct qproc *qproc)
        return 0;
 }
 
-static int qproc_request_irq(struct qproc *qproc,
+static int q6v5_request_irq(struct q6v5 *qproc,
                             struct platform_device *pdev,
                             const char *name,
                             irq_handler_t thread_fn)
@@ -1181,150 +763,153 @@ static int qproc_request_irq(struct qproc *qproc,
        ret = devm_request_threaded_irq(&pdev->dev, ret,
                                        NULL, thread_fn,
                                        IRQF_TRIGGER_RISING | IRQF_ONESHOT,
-                                       "qproc", qproc);
+                                       "q6v5", qproc);
        if (ret)
                dev_err(&pdev->dev, "request %s IRQ failed\n", name);
        return ret;
 }
 
-static int qproc_probe(struct platform_device *pdev)
+static int q6v5_alloc_memory_region(struct q6v5 *qproc)
+{
+       struct device_node *child;
+       struct device_node *node;
+       struct resource r;
+       int ret;
+
+       child = of_get_child_by_name(qproc->dev->of_node, "mba");
+       node = of_parse_phandle(child, "memory-region", 0);
+       ret = of_address_to_resource(node, 0, &r);
+       if (ret) {
+               dev_err(qproc->dev, "unable to resolve mba region\n");
+               return ret;
+       }
+
+       qproc->mba_phys = r.start;
+       qproc->mba_size = resource_size(&r);
+       qproc->mba_region = devm_ioremap_wc(qproc->dev, qproc->mba_phys, qproc->mba_size);
+       if (!qproc->mba_region) {
+               dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n",
+                       &r.start, qproc->mba_size);
+               return -EBUSY;
+       }
+
+       child = of_get_child_by_name(qproc->dev->of_node, "mpss");
+       node = of_parse_phandle(child, "memory-region", 0);
+       ret = of_address_to_resource(node, 0, &r);
+       if (ret) {
+               dev_err(qproc->dev, "unable to resolve mpss region\n");
+               return ret;
+       }
+
+       qproc->mpss_phys = qproc->mpss_reloc = r.start;
+       qproc->mpss_size = resource_size(&r);
+       qproc->mpss_region = devm_ioremap_wc(qproc->dev, qproc->mpss_phys, qproc->mpss_size);
+       if (!qproc->mpss_region) {
+               dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n",
+                       &r.start, qproc->mpss_size);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int q6v5_probe(struct platform_device *pdev)
 {
-       struct qproc *qproc;
+       struct q6v5 *qproc;
        struct rproc *rproc;
        int ret;
-       int i;
-       struct device_node *np;
-       struct resource r;
 
-       rproc = rproc_alloc(&pdev->dev, pdev->name, &qproc_ops,
-                           "mba.mbn", sizeof(*qproc));
-       if (!rproc)
+       rproc = rproc_alloc(&pdev->dev, pdev->name, &q6v5_ops,
+                           MBA_FIRMWARE_NAME, sizeof(*qproc));
+       if (!rproc) {
+               dev_err(&pdev->dev, "failed to allocate rproc\n");
                return -ENOMEM;
+       }
 
-       rproc->fw_ops = &qproc_fw_ops;
+       rproc->fw_ops = &q6v5_fw_ops;
 
-       qproc = (struct qproc *)rproc->priv;
+       qproc = (struct q6v5 *)rproc->priv;
        qproc->dev = &pdev->dev;
        qproc->rproc = rproc;
        platform_set_drvdata(pdev, qproc);
 
        init_completion(&qproc->start_done);
+       init_completion(&qproc->stop_done);
 
-       ret = qproc_init_mem(qproc, pdev);
+       ret = q6v5_init_mem(qproc, pdev);
        if (ret)
                goto free_rproc;
 
-       ret = qproc_init_clocks(qproc);
+       ret = q6v5_alloc_memory_region(qproc);
        if (ret)
                goto free_rproc;
 
-       ret = qproc_init_regulators(qproc);
+       ret = q6v5_init_clocks(qproc);
        if (ret)
                goto free_rproc;
 
-       //FIXME need to convert this to a proper reset... 
-//     ret = qproc_init_reset(qproc);
-//     if (ret)
-//             goto free_rproc;
+       ret = q6v5_regulator_init(qproc);
+       if (ret)
+               goto free_rproc;
 
-       ret = qproc_request_irq(qproc, pdev, "wdog", qproc_wdog_interrupt);
-       if (ret < 0)
+       ret = q6v5_init_reset(qproc);
+       if (ret)
                goto free_rproc;
-       qproc->wdog_irq = ret;
 
-       ret = qproc_request_irq(qproc, pdev, "fatal", qproc_fatal_interrupt);
+       ret = q6v5_request_irq(qproc, pdev, "wdog", q6v5_wdog_interrupt);
        if (ret < 0)
                goto free_rproc;
-       qproc->fatal_irq = ret;
 
-       ret = qproc_request_irq(qproc, pdev, "ready", qproc_ready_interrupt);
+       ret = q6v5_request_irq(qproc, pdev, "fatal", q6v5_fatal_interrupt);
        if (ret < 0)
                goto free_rproc;
-       qproc->ready_irq = ret;
 
-       ret = qproc_request_irq(qproc, pdev, "handover", qproc_handover_interrupt);
+       ret = q6v5_request_irq(qproc, pdev, "handover", q6v5_handover_interrupt);
        if (ret < 0)
                goto free_rproc;
-       qproc->handover_irq = ret;
 
-       ret = qproc_request_irq(qproc, pdev, "stop-ack", qproc_stop_ack_interrupt);
+       ret = q6v5_request_irq(qproc, pdev, "stop-ack", q6v5_stop_ack_interrupt);
        if (ret < 0)
                goto free_rproc;
-       qproc->stop_ack_irq = ret;
-
-       qproc->stop_gpio = devm_gpiod_get(&pdev->dev, "qcom,stop", GPIOD_OUT_LOW);
-       if (IS_ERR(qproc->stop_gpio)) {
-               dev_err(&pdev->dev, "failed to acquire stop gpio\n");
-               return PTR_ERR(qproc->stop_gpio);
-       }
-
-       for (i = 0; i < ARRAY_SIZE(qproc_attrs); i++) {
-               ret = device_create_file(&pdev->dev, &qproc_attrs[i]);
-               if (ret) {
-                       dev_err(&pdev->dev, "unable to create sysfs file\n");
-                       goto remove_device_files;
-               }
-       }
-
-       np = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
-       if (!np) {
-               dev_err(&pdev->dev, "No memory region specified\n");
-       } else {
-
-               ret = of_address_to_resource(np, 0, &r);
-               of_node_put(np);
-               if (ret)
-                       return ret;
-
-               qproc->reloc_phys = r.start;
-               qproc->reloc_size = resource_size(&r);
-
-               dev_info(&pdev->dev, "Found relocation area %lu@%pad\n",
-                               qproc->reloc_size, &qproc->reloc_phys);
-       }
 
+       qproc->state = qcom_smem_state_get(&pdev->dev, "stop", &qproc->stop_bit);
+       if (IS_ERR(qproc->state))
+               goto free_rproc;
 
        ret = rproc_add(rproc);
        if (ret)
-               goto remove_device_files;
+               goto free_rproc;
 
        return 0;
 
-remove_device_files:
-       for (i--; i >= 0; i--)
-               device_remove_file(&pdev->dev, &qproc_attrs[i]);
-
 free_rproc:
        rproc_put(rproc);
 
        return ret;
 }
 
-static int qproc_remove(struct platform_device *pdev)
+static int q6v5_remove(struct platform_device *pdev)
 {
-       struct qproc *qproc = platform_get_drvdata(pdev);
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(qproc_attrs); i++)
-               device_remove_file(&pdev->dev, &qproc_attrs[i]);
+       struct q6v5 *qproc = platform_get_drvdata(pdev);
 
+       rproc_del(qproc->rproc);
        rproc_put(qproc->rproc);
 
        return 0;
 }
 
-static const struct of_device_id qproc_of_match[] = {
+static const struct of_device_id q6v5_of_match[] = {
        { .compatible = "qcom,q6v5-pil", },
        { },
 };
 
-static struct platform_driver qproc_driver = {
-       .probe = qproc_probe,
-       .remove = qproc_remove,
+static struct platform_driver q6v5_driver = {
+       .probe = q6v5_probe,
+       .remove = q6v5_remove,
        .driver = {
                .name = "qcom-q6v5-pil",
-               .of_match_table = qproc_of_match,
+               .of_match_table = q6v5_of_match,
        },
 };
 
-module_platform_driver(qproc_driver);
+module_platform_driver(q6v5_driver);
index ae361fc26dd10ca3530e91f2aea9fcf04a1bdd33..6de08442f57f7089a63b544d4379374239183020 100644 (file)
@@ -276,8 +276,7 @@ static int qproc_load(struct rproc *rproc, const struct firmware *fw)
                        max_addr = round_up(phdr->p_paddr + phdr->p_memsz, SZ_4K);
        }
 
-       ret = qcom_scm_pas_init_image(qproc->dev,
-                               qproc->pas_id, fw->data, fw->size);
+       ret = qcom_scm_pas_init_image(qproc->pas_id, fw->data, fw->size);
        if (ret) {
                dev_err(qproc->dev, "Invalid firmware metadata\n");
                return -EINVAL;
diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
new file mode 100644 (file)
index 0000000..648afdb
--- /dev/null
@@ -0,0 +1,620 @@
+/*
+ * Qualcomm Peripheral Image Loader
+ *
+ * Copyright (C) 2016 Linaro Ltd
+ * Copyright (C) 2014 Sony Mobile Communications AB
+ * Copyright (c) 2012-2013, 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 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.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/qcom_scm.h>
+#include <linux/regulator/consumer.h>
+#include <linux/remoteproc.h>
+#include <linux/soc/qcom/smem.h>
+#include <linux/soc/qcom/smem_state.h>
+
+#include "qcom_mdt_loader.h"
+#include "remoteproc_internal.h"
+#include "qcom_wcnss.h"
+
+#define WCNSS_CRASH_REASON_SMEM                422
+#define WCNSS_FIRMWARE_NAME            "wcnss.mdt"
+#define WCNSS_PAS_ID                   6
+
+#define WCNSS_SPARE_NVBIN_DLND         BIT(25)
+
+#define WCNSS_PMU_IRIS_XO_CFG          BIT(3)
+#define WCNSS_PMU_IRIS_XO_EN           BIT(4)
+#define WCNSS_PMU_GC_BUS_MUX_SEL_TOP   BIT(5)
+#define WCNSS_PMU_IRIS_XO_CFG_STS      BIT(6) /* 1: in progress, 0: done */
+
+#define WCNSS_PMU_IRIS_RESET           BIT(7)
+#define WCNSS_PMU_IRIS_RESET_STS       BIT(8) /* 1: in progress, 0: done */
+#define WCNSS_PMU_IRIS_XO_READ         BIT(9)
+#define WCNSS_PMU_IRIS_XO_READ_STS     BIT(10)
+
+#define WCNSS_PMU_XO_MODE_MASK         GENMASK(2, 1)
+#define WCNSS_PMU_XO_MODE_19p2         0
+#define WCNSS_PMU_XO_MODE_48           3
+
+static const struct rproc_ops wcnss_ops;
+
+struct wcnss_data {
+       size_t pmu_offset;
+       size_t spare_offset;
+
+       const struct wcnss_vreg_info *vregs;
+       size_t num_vregs;
+};
+
+struct qcom_wcnss {
+       struct device *dev;
+       struct rproc *rproc;
+
+       void __iomem *pmu_cfg;
+       void __iomem *spare_out;
+
+       bool use_48mhz_xo;
+
+       int wdog_irq;
+       int fatal_irq;
+       int ready_irq;
+       int handover_irq;
+       int stop_ack_irq;
+
+       struct qcom_smem_state *state;
+       unsigned stop_bit;
+
+       struct mutex iris_lock;
+       struct qcom_iris *iris;
+
+       struct regulator_bulk_data *vregs;
+       size_t num_vregs;
+
+       struct completion start_done;
+       struct completion stop_done;
+
+       phys_addr_t mem_phys;
+       phys_addr_t mem_reloc;
+       void *mem_region;
+       size_t mem_size;
+};
+
+static const struct wcnss_data riva_data = {
+       .pmu_offset = 0x28,
+       .spare_offset = 0xb4,
+
+       .vregs = (struct wcnss_vreg_info[]) {
+               { "vddmx",  1050000, 1150000, 0 },
+               { "vddcx",  1050000, 1150000, 0 },
+               { "vddpx",  1800000, 1800000, 0 },
+       },
+       .num_vregs = 3,
+};
+
+static const struct wcnss_data pronto_v1_data = {
+       .pmu_offset = 0x1004,
+       .spare_offset = 0x1088,
+
+       .vregs = (struct wcnss_vreg_info[]) {
+               { "vddmx", 950000, 1150000, 0 },
+               { "vddcx", .super_turbo = true},
+               { "vddpx", 1800000, 1800000, 0 },
+       },
+       .num_vregs = 3,
+};
+
+static const struct wcnss_data pronto_v2_data = {
+       .pmu_offset = 0x1004,
+       .spare_offset = 0x1088,
+
+       .vregs = (struct wcnss_vreg_info[]) {
+               { "vddmx", 1287500, 1287500, 0 },
+               { "vddcx", .super_turbo = true },
+               { "vddpx", 1800000, 1800000, 0 },
+       },
+       .num_vregs = 3,
+};
+
+void qcom_wcnss_assign_iris(struct qcom_wcnss *wcnss,
+                           struct qcom_iris *iris,
+                           bool use_48mhz_xo)
+{
+       mutex_lock(&wcnss->iris_lock);
+
+       wcnss->iris = iris;
+       wcnss->use_48mhz_xo = use_48mhz_xo;
+
+       mutex_unlock(&wcnss->iris_lock);
+}
+
+static int wcnss_load(struct rproc *rproc, const struct firmware *fw)
+{
+       struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
+       phys_addr_t fw_addr;
+       size_t fw_size;
+       bool relocate;
+       int ret;
+
+       ret = qcom_scm_pas_init_image(WCNSS_PAS_ID, fw->data, fw->size);
+       if (ret) {
+               dev_err(&rproc->dev, "invalid firmware metadata\n");
+               return -EINVAL;
+       }
+
+       ret = qcom_mdt_parse(fw, &fw_addr, &fw_size, &relocate);
+       if (ret) {
+               dev_err(&rproc->dev, "failed to parse mdt header\n");
+               return ret;
+       }
+
+       if (relocate) {
+               wcnss->mem_reloc = fw_addr;
+
+               ret = qcom_scm_pas_mem_setup(WCNSS_PAS_ID, wcnss->mem_phys, fw_size);
+               if (ret) {
+                       dev_err(&rproc->dev, "unable to setup memory for image\n");
+                       return -EINVAL;
+               }
+       }
+
+       return qcom_mdt_load(rproc, fw, rproc->firmware);
+}
+
+static const struct rproc_fw_ops wcnss_fw_ops = {
+       .find_rsc_table = qcom_mdt_find_rsc_table,
+       .load = wcnss_load,
+};
+
+static void wcnss_indicate_nv_download(struct qcom_wcnss *wcnss)
+{
+       u32 val;
+
+       /* Indicate NV download capability */
+       val = readl(wcnss->spare_out);
+       val |= WCNSS_SPARE_NVBIN_DLND;
+       writel(val, wcnss->spare_out);
+}
+
+static void wcnss_configure_iris(struct qcom_wcnss *wcnss)
+{
+       u32 val;
+
+       /* Clear PMU cfg register */
+       writel(0, wcnss->pmu_cfg);
+
+       val = WCNSS_PMU_GC_BUS_MUX_SEL_TOP | WCNSS_PMU_IRIS_XO_EN;
+       writel(val, wcnss->pmu_cfg);
+
+       /* Clear XO_MODE */
+       val &= ~WCNSS_PMU_XO_MODE_MASK;
+       if (wcnss->use_48mhz_xo)
+               val |= WCNSS_PMU_XO_MODE_48 << 1;
+       else
+               val |= WCNSS_PMU_XO_MODE_19p2 << 1;
+       writel(val, wcnss->pmu_cfg);
+
+       /* Reset IRIS */
+       val |= WCNSS_PMU_IRIS_RESET;
+       writel(val, wcnss->pmu_cfg);
+
+       /* Wait for PMU.iris_reg_reset_sts */
+       while (readl(wcnss->pmu_cfg) & WCNSS_PMU_IRIS_RESET_STS)
+               cpu_relax();
+
+       /* Clear IRIS reset */
+       val &= ~WCNSS_PMU_IRIS_RESET;
+       writel(val, wcnss->pmu_cfg);
+
+       /* Start IRIS XO configuration */
+       val |= WCNSS_PMU_IRIS_XO_CFG;
+       writel(val, wcnss->pmu_cfg);
+
+       /* Wait for XO configuration to finish */
+       while (readl(wcnss->pmu_cfg) & WCNSS_PMU_IRIS_XO_CFG_STS)
+               cpu_relax();
+
+       /* Stop IRIS XO configuration */
+       val &= ~WCNSS_PMU_GC_BUS_MUX_SEL_TOP;
+       val &= ~WCNSS_PMU_IRIS_XO_CFG;
+       writel(val, wcnss->pmu_cfg);
+
+       /* Add some delay for XO to settle */
+       msleep(20);
+}
+
+static int wcnss_start(struct rproc *rproc)
+{
+       struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
+       int ret;
+
+       mutex_lock(&wcnss->iris_lock);
+       if (!wcnss->iris) {
+               dev_err(wcnss->dev, "no iris registered\n");
+               ret = -EINVAL;
+               goto release_iris_lock;
+       }
+
+       ret = regulator_bulk_enable(wcnss->num_vregs, wcnss->vregs);
+       if (ret)
+               goto release_iris_lock;
+
+       ret = qcom_iris_enable(wcnss->iris);
+       if (ret)
+               goto disable_regulators;
+
+       wcnss_indicate_nv_download(wcnss);
+       wcnss_configure_iris(wcnss);
+
+       ret = qcom_scm_pas_auth_and_reset(WCNSS_PAS_ID);
+       if (ret) {
+               dev_err(wcnss->dev,
+                       "failed to authenticate image and release reset\n");
+               goto disable_iris;
+       }
+
+       ret = wait_for_completion_timeout(&wcnss->start_done,
+                                         msecs_to_jiffies(5000));
+       if (wcnss->ready_irq > 0 && ret == 0) {
+               /* We have a ready_irq, but it didn't fire in time. */
+               dev_err(wcnss->dev, "start timed out\n");
+               qcom_scm_pas_shutdown(WCNSS_PAS_ID);
+               ret = -ETIMEDOUT;
+               goto disable_iris;
+       }
+
+       ret = 0;
+
+disable_iris:
+       qcom_iris_disable(wcnss->iris);
+disable_regulators:
+       regulator_bulk_disable(wcnss->num_vregs, wcnss->vregs);
+release_iris_lock:
+       mutex_unlock(&wcnss->iris_lock);
+
+       return ret;
+}
+
+static int wcnss_stop(struct rproc *rproc)
+{
+       struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
+       int ret;
+
+       if (wcnss->state) {
+               qcom_smem_state_update_bits(wcnss->state,
+                                           BIT(wcnss->stop_bit),
+                                           BIT(wcnss->stop_bit));
+
+               ret = wait_for_completion_timeout(&wcnss->stop_done,
+                                                 msecs_to_jiffies(5000));
+               if (ret == 0)
+                       dev_err(wcnss->dev, "timed out on wait\n");
+
+               qcom_smem_state_update_bits(wcnss->state,
+                                           BIT(wcnss->stop_bit),
+                                           0);
+       }
+
+       ret = qcom_scm_pas_shutdown(WCNSS_PAS_ID);
+       if (ret)
+               dev_err(wcnss->dev, "failed to shutdown: %d\n", ret);
+
+       return ret;
+}
+
+static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len)
+{
+       struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
+       int offset;
+
+       offset = da - wcnss->mem_reloc;
+       if (offset < 0 || offset + len > wcnss->mem_size)
+               return NULL;
+
+       return wcnss->mem_region + offset;
+}
+
+static const struct rproc_ops wcnss_ops = {
+       .start = wcnss_start,
+       .stop = wcnss_stop,
+       .da_to_va = wcnss_da_to_va,
+};
+
+static irqreturn_t wcnss_wdog_interrupt(int irq, void *dev)
+{
+       struct qcom_wcnss *wcnss = dev;
+
+       rproc_report_crash(wcnss->rproc, RPROC_WATCHDOG);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t wcnss_fatal_interrupt(int irq, void *dev)
+{
+       struct qcom_wcnss *wcnss = dev;
+       size_t len;
+       char *msg;
+
+       msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, WCNSS_CRASH_REASON_SMEM, &len);
+       if (!IS_ERR(msg) && len > 0 && msg[0])
+               dev_err(wcnss->dev, "fatal error received: %s\n", msg);
+
+       rproc_report_crash(wcnss->rproc, RPROC_FATAL_ERROR);
+
+       if (!IS_ERR(msg))
+               msg[0] = '\0';
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t wcnss_ready_interrupt(int irq, void *dev)
+{
+       struct qcom_wcnss *wcnss = dev;
+
+       complete(&wcnss->start_done);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t wcnss_handover_interrupt(int irq, void *dev)
+{
+       /*
+        * XXX: At this point we're supposed to release the resources that we
+        * have been holding on behalf of the WCNSS. Unfortunately this
+        * interrupt comes way before the other side seems to be done.
+        *
+        * So we're currently relying on the ready interrupt firing later then
+        * this and we just disable the resources at the end of wcnss_start().
+        */
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t wcnss_stop_ack_interrupt(int irq, void *dev)
+{
+       struct qcom_wcnss *wcnss = dev;
+
+       complete(&wcnss->stop_done);
+       return IRQ_HANDLED;
+}
+
+static int wcnss_init_regulators(struct qcom_wcnss *wcnss,
+                                const struct wcnss_vreg_info *info,
+                                int num_vregs)
+{
+       struct regulator_bulk_data *bulk;
+       int ret;
+       int i;
+
+       bulk = devm_kcalloc(wcnss->dev,
+                           num_vregs, sizeof(struct regulator_bulk_data),
+                           GFP_KERNEL);
+       if (!bulk)
+               return -ENOMEM;
+
+       for (i = 0; i < num_vregs; i++)
+               bulk[i].supply = info[i].name;
+
+       ret = devm_regulator_bulk_get(wcnss->dev, num_vregs, bulk);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < num_vregs; i++) {
+               if (info[i].max_voltage)
+                       regulator_set_voltage(bulk[i].consumer,
+                                             info[i].min_voltage,
+                                             info[i].max_voltage);
+
+               if (info[i].load_uA)
+                       regulator_set_load(bulk[i].consumer, info[i].load_uA);
+       }
+
+       wcnss->vregs = bulk;
+       wcnss->num_vregs = num_vregs;
+
+       return 0;
+}
+
+static int wcnss_request_irq(struct qcom_wcnss *wcnss,
+                            struct platform_device *pdev,
+                            const char *name,
+                            bool optional,
+                            irq_handler_t thread_fn)
+{
+       int ret;
+
+       ret = platform_get_irq_byname(pdev, name);
+       if (ret < 0 && optional) {
+               dev_dbg(&pdev->dev, "no %s IRQ defined, ignoring\n", name);
+               return 0;
+       } else if (ret < 0) {
+               dev_err(&pdev->dev, "no %s IRQ defined\n", name);
+               return ret;
+       }
+
+       ret = devm_request_threaded_irq(&pdev->dev, ret,
+                                       NULL, thread_fn,
+                                       IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                                       "wcnss", wcnss);
+       if (ret)
+               dev_err(&pdev->dev, "request %s IRQ failed\n", name);
+       return ret;
+}
+
+static int wcnss_alloc_memory_region(struct qcom_wcnss *wcnss)
+{
+       struct device_node *node;
+       struct resource r;
+       int ret;
+
+       node = of_parse_phandle(wcnss->dev->of_node, "memory-region", 0);
+       if (!node) {
+               dev_err(wcnss->dev, "no memory-region specified\n");
+               return -EINVAL;
+       }
+
+       ret = of_address_to_resource(node, 0, &r);
+       if (ret)
+               return ret;
+
+       wcnss->mem_phys = wcnss->mem_reloc = r.start;
+       wcnss->mem_size = resource_size(&r);
+       wcnss->mem_region = devm_ioremap_wc(wcnss->dev, wcnss->mem_phys, wcnss->mem_size);
+       if (!wcnss->mem_region) {
+               dev_err(wcnss->dev, "unable to map memory region: %pa+%zx\n",
+                       &r.start, wcnss->mem_size);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int wcnss_probe(struct platform_device *pdev)
+{
+       const struct wcnss_data *data;
+       struct qcom_wcnss *wcnss;
+       struct resource *res;
+       struct rproc *rproc;
+       void __iomem *mmio;
+       int ret;
+
+       data = of_device_get_match_data(&pdev->dev);
+
+       if (!qcom_scm_is_available())
+               return -EPROBE_DEFER;
+
+       if (!qcom_scm_pas_supported(WCNSS_PAS_ID)) {
+               dev_err(&pdev->dev, "PAS is not available for WCNSS\n");
+               return -ENXIO;
+       }
+
+       rproc = rproc_alloc(&pdev->dev, pdev->name, &wcnss_ops,
+                           WCNSS_FIRMWARE_NAME, sizeof(*wcnss));
+       if (!rproc) {
+               dev_err(&pdev->dev, "unable to allocate remoteproc\n");
+               return -ENOMEM;
+       }
+
+       rproc->fw_ops = &wcnss_fw_ops;
+
+       wcnss = (struct qcom_wcnss *)rproc->priv;
+       wcnss->dev = &pdev->dev;
+       wcnss->rproc = rproc;
+       platform_set_drvdata(pdev, wcnss);
+
+       init_completion(&wcnss->start_done);
+       init_completion(&wcnss->stop_done);
+
+       mutex_init(&wcnss->iris_lock);
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pmu");
+       mmio = devm_ioremap_resource(&pdev->dev, res);
+       if (!mmio) {
+               ret = -ENOMEM;
+               goto free_rproc;
+       };
+
+       ret = wcnss_alloc_memory_region(wcnss);
+       if (ret)
+               goto free_rproc;
+
+       wcnss->pmu_cfg = mmio + data->pmu_offset;
+       wcnss->spare_out = mmio + data->spare_offset;
+
+       ret = wcnss_init_regulators(wcnss, data->vregs, data->num_vregs);
+       if (ret)
+               goto free_rproc;
+
+       ret = wcnss_request_irq(wcnss, pdev, "wdog", false, wcnss_wdog_interrupt);
+       if (ret < 0)
+               goto free_rproc;
+       wcnss->wdog_irq = ret;
+
+       ret = wcnss_request_irq(wcnss, pdev, "fatal", false, wcnss_fatal_interrupt);
+       if (ret < 0)
+               goto free_rproc;
+       wcnss->fatal_irq = ret;
+
+       ret = wcnss_request_irq(wcnss, pdev, "ready", true, wcnss_ready_interrupt);
+       if (ret < 0)
+               goto free_rproc;
+       wcnss->ready_irq = ret;
+
+       ret = wcnss_request_irq(wcnss, pdev, "handover", true, wcnss_handover_interrupt);
+       if (ret < 0)
+               goto free_rproc;
+       wcnss->handover_irq = ret;
+
+       ret = wcnss_request_irq(wcnss, pdev, "stop-ack", true, wcnss_stop_ack_interrupt);
+       if (ret < 0)
+               goto free_rproc;
+       wcnss->stop_ack_irq = ret;
+
+       if (wcnss->stop_ack_irq) {
+               wcnss->state = qcom_smem_state_get(&pdev->dev, "stop",
+                                                  &wcnss->stop_bit);
+               if (IS_ERR(wcnss->state)) {
+                       ret = PTR_ERR(wcnss->state);
+                       goto free_rproc;
+               }
+       }
+
+       ret = rproc_add(rproc);
+       if (ret)
+               goto free_rproc;
+
+       return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+
+free_rproc:
+       rproc_put(rproc);
+
+       return ret;
+}
+
+static int wcnss_remove(struct platform_device *pdev)
+{
+       struct qcom_wcnss *wcnss = platform_get_drvdata(pdev);
+
+       of_platform_depopulate(&pdev->dev);
+
+       qcom_smem_state_put(wcnss->state);
+       rproc_del(wcnss->rproc);
+       rproc_put(wcnss->rproc);
+
+       return 0;
+}
+
+static const struct of_device_id wcnss_of_match[] = {
+       { .compatible = "qcom,riva-pil", &riva_data },
+       { .compatible = "qcom,pronto-v1-pil", &pronto_v1_data },
+       { .compatible = "qcom,pronto-v2-pil", &pronto_v2_data },
+       { },
+};
+
+static struct platform_driver wcnss_driver = {
+       .probe = wcnss_probe,
+       .remove = wcnss_remove,
+       .driver = {
+               .name = "qcom-wcnss-pil",
+               .of_match_table = wcnss_of_match,
+       },
+};
+
+module_platform_driver(wcnss_driver);
diff --git a/drivers/remoteproc/qcom_wcnss.h b/drivers/remoteproc/qcom_wcnss.h
new file mode 100644 (file)
index 0000000..9dc4a9f
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef __QCOM_WNCSS_H__
+#define __QCOM_WNCSS_H__
+
+struct qcom_iris;
+struct qcom_wcnss;
+
+struct wcnss_vreg_info {
+       const char * const name;
+       int min_voltage;
+       int max_voltage;
+
+       int load_uA;
+
+       bool super_turbo;
+};
+
+int qcom_iris_enable(struct qcom_iris *iris);
+void qcom_iris_disable(struct qcom_iris *iris);
+
+void qcom_wcnss_assign_iris(struct qcom_wcnss *wcnss, struct qcom_iris *iris, bool use_48mhz_xo);
+
+#endif
diff --git a/drivers/remoteproc/qcom_wcnss_iris.c b/drivers/remoteproc/qcom_wcnss_iris.c
new file mode 100644 (file)
index 0000000..62a3758
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Qualcomm Peripheral Image Loader
+ *
+ * Copyright (C) 2016 Linaro Ltd
+ * Copyright (C) 2014 Sony Mobile Communications AB
+ * Copyright (c) 2012-2013, 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 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.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/qcom_scm.h>
+#include <linux/regulator/consumer.h>
+
+#include "qcom_wcnss.h"
+
+struct qcom_iris {
+       struct device *dev;
+
+       struct clk *xo_clk;
+
+       struct regulator_bulk_data *vregs;
+       size_t num_vregs;
+};
+
+struct iris_data {
+       const struct wcnss_vreg_info *vregs;
+       size_t num_vregs;
+
+       bool use_48mhz_xo;
+};
+
+static const struct iris_data wcn3620_data = {
+       .vregs = (struct wcnss_vreg_info[]) {
+               { "vddxo",  1800000, 1800000, 10000 },
+               { "vddrfa", 1300000, 1300000, 100000 },
+               { "vddpa",  3300000, 3300000, 515000 },
+               { "vdddig", 1800000, 1800000, 10000 },
+       },
+       .num_vregs = 4,
+       .use_48mhz_xo = false,
+};
+
+static const struct iris_data wcn3660_data = {
+       .vregs = (struct wcnss_vreg_info[]) {
+               { "vddxo",  1800000, 1800000, 10000 },
+               { "vddrfa", 1300000, 1300000, 100000 },
+               { "vddpa",  2900000, 3000000, 515000 },
+               { "vdddig", 1200000, 1225000, 10000 },
+       },
+       .num_vregs = 4,
+       .use_48mhz_xo = true,
+};
+
+static const struct iris_data wcn3680_data = {
+       .vregs = (struct wcnss_vreg_info[]) {
+               { "vddxo",  1800000, 1800000, 10000 },
+               { "vddrfa", 1300000, 1300000, 100000 },
+               { "vddpa",  3300000, 3300000, 515000 },
+               { "vdddig", 1800000, 1800000, 10000 },
+       },
+       .num_vregs = 4,
+       .use_48mhz_xo = true,
+};
+
+int qcom_iris_enable(struct qcom_iris *iris)
+{
+       int ret;
+
+       ret = regulator_bulk_enable(iris->num_vregs, iris->vregs);
+       if (ret)
+               return ret;
+
+       ret = clk_prepare_enable(iris->xo_clk);
+       if (ret) {
+               dev_err(iris->dev, "failed to enable xo clk\n");
+               goto disable_regulators;
+       }
+
+       return 0;
+
+disable_regulators:
+       regulator_bulk_disable(iris->num_vregs, iris->vregs);
+
+       return ret;
+}
+
+void qcom_iris_disable(struct qcom_iris *iris)
+{
+       clk_disable_unprepare(iris->xo_clk);
+       regulator_bulk_disable(iris->num_vregs, iris->vregs);
+}
+
+static int qcom_iris_probe(struct platform_device *pdev)
+{
+       const struct iris_data *data;
+       struct qcom_wcnss *wcnss;
+       struct qcom_iris *iris;
+       int ret;
+       int i;
+
+       iris = devm_kzalloc(&pdev->dev, sizeof(struct qcom_iris), GFP_KERNEL);
+       if (!iris)
+               return -ENOMEM;
+
+       data = of_device_get_match_data(&pdev->dev);
+       wcnss = dev_get_drvdata(pdev->dev.parent);
+
+       iris->xo_clk = devm_clk_get(&pdev->dev, "xo");
+       if (IS_ERR(iris->xo_clk)) {
+               if (PTR_ERR(iris->xo_clk) != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "failed to acquire xo clk\n");
+               return PTR_ERR(iris->xo_clk);
+       }
+
+       iris->num_vregs = data->num_vregs;
+       iris->vregs = devm_kcalloc(&pdev->dev,
+                                  iris->num_vregs,
+                                  sizeof(struct regulator_bulk_data),
+                                  GFP_KERNEL);
+       if (!iris->vregs)
+               return -ENOMEM;
+
+       for (i = 0; i < iris->num_vregs; i++)
+               iris->vregs[i].supply = data->vregs[i].name;
+
+       ret = devm_regulator_bulk_get(&pdev->dev, iris->num_vregs, iris->vregs);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to get regulators\n");
+               return ret;
+       }
+
+       for (i = 0; i < iris->num_vregs; i++) {
+               if (data->vregs[i].max_voltage)
+                       regulator_set_voltage(iris->vregs[i].consumer,
+                                             data->vregs[i].min_voltage,
+                                             data->vregs[i].max_voltage);
+
+               if (data->vregs[i].load_uA)
+                       regulator_set_load(iris->vregs[i].consumer,
+                                          data->vregs[i].load_uA);
+       }
+
+       qcom_wcnss_assign_iris(wcnss, iris, data->use_48mhz_xo);
+
+       return 0;
+}
+
+static int qcom_iris_remove(struct platform_device *pdev)
+{
+       struct qcom_wcnss *wcnss = dev_get_drvdata(pdev->dev.parent);
+
+       qcom_wcnss_assign_iris(wcnss, NULL, false);
+
+       return 0;
+}
+
+static const struct of_device_id iris_of_match[] = {
+       { .compatible = "qcom,wcn3620", .data = &wcn3620_data },
+       { .compatible = "qcom,wcn3660", .data = &wcn3660_data },
+       { .compatible = "qcom,wcn3680", .data = &wcn3680_data },
+       {}
+};
+
+static struct platform_driver wcnss_driver = {
+       .probe = qcom_iris_probe,
+       .remove = qcom_iris_remove,
+       .driver = {
+               .name = "qcom-iris",
+               .of_match_table = iris_of_match,
+       },
+};
+
+module_platform_driver(wcnss_driver);
index 916af5096f57b93b7f7e148d28716329b31c7be6..9ef9f47b28e2e6354c2183a073f4a6cdc25b4ce6 100644 (file)
@@ -88,8 +88,42 @@ static ssize_t rproc_state_read(struct file *filp, char __user *userbuf,
        return simple_read_from_buffer(userbuf, count, ppos, buf, i);
 }
 
+static ssize_t rproc_state_write(struct file *filp, const char __user *userbuf,
+                                size_t count, loff_t *ppos)
+{
+       struct rproc *rproc = filp->private_data;
+       char buf[10];
+       int ret;
+
+       if (count > sizeof(buf) || count <= 0)
+               return -EINVAL;
+
+       ret = copy_from_user(buf, userbuf, count);
+       if (ret)
+               return -EFAULT;
+
+       if (buf[count - 1] == '\n')
+               buf[count - 1] = '\0';
+
+       if (!strncmp(buf, "start", count)) {
+               ret = rproc_boot(rproc);
+               if (ret) {
+                       dev_err(&rproc->dev, "Boot failed: %d\n", ret);
+                       return ret;
+               }
+       } else if (!strncmp(buf, "stop", count)) {
+               rproc_shutdown(rproc);
+       } else {
+               dev_err(&rproc->dev, "Unrecognised option: %s\n", buf);
+               return -EINVAL;
+       }
+
+       return count;
+}
+
 static const struct file_operations rproc_state_ops = {
        .read = rproc_state_read,
+       .write = rproc_state_write,
        .open = simple_open,
        .llseek = generic_file_llseek,
 };
index 4138de6da18b3724cc8a8b4aff236c88279c71e7..35fa84660dee638936921656a428e23d52c9274c 100644 (file)
@@ -117,8 +117,3 @@ config BUS_TOPOLOGY_ADHOC
                directionality of connections by explicitly listing device connections
                thus avoiding illegal routes.
 
-config QCOM_IPCRTR_STUB
-       tristate "Qualcomm IPCRTR stub driver"
-       depends on QCOM_SMD
-       help
-         Stub driver to bring the IPCRTR channel up.
index bf6f22a47a2b6db5520e2e56148606137aab60a2..56da0a585cfd5d6c39c609d3f2bbf11f4a17ba61 100644 (file)
@@ -12,6 +12,4 @@ obj-$(CONFIG_MFD_QCOM_SMD_RPM) += rpm_log.o
 
 obj-$(CONFIG_MSM_BUS_SCALING) += msm_bus/
 obj-$(CONFIG_BUS_TOPOLOGY_ADHOC) += msm_bus/
-obj-$(CONFIG_QCOM_IPCRTR_STUB) += ipcrtr_stub.o
-
 obj-$(CONFIG_QTI_LNX_GPS_PROXY) += gps_proxy.o
diff --git a/drivers/soc/qcom/ipcrtr_stub.c b/drivers/soc/qcom/ipcrtr_stub.c
deleted file mode 100644 (file)
index 6f8d724..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2014, Sony Mobile Communications AB.
- *
- * 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/platform_device.h>
-#include <linux/of_platform.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/firmware.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-
-#include <linux/soc/qcom/smd.h>
-
-static int ipcrtr_stub_callback(struct qcom_smd_device *qsdev,
-                               const void *data,
-                                size_t count)
-{
-       print_hex_dump(KERN_DEBUG, "IPCRTR <<<: ", DUMP_PREFIX_OFFSET, 16, 1, data, count, true);
-
-       return 0;
-}
-
-static int ipcrtr_stub_probe(struct qcom_smd_device *sdev)
-{
-       dev_err(&sdev->dev, "ipcrtr initialized\n");
-
-       return 0;
-}
-
-static const struct of_device_id ipcrtr_stub_of_match[] = {
-       { .compatible = "qcom,ipcrtr" },
-       {}
-};
-MODULE_DEVICE_TABLE(of, ipcrtr_stub_of_match);
-
-static struct qcom_smd_driver ipcrtr_stub_driver = {
-       .probe = ipcrtr_stub_probe,
-       .callback = ipcrtr_stub_callback,
-       .driver  = {
-               .name  = "ipcrtr_stub",
-               .owner = THIS_MODULE,
-               .of_match_table = ipcrtr_stub_of_match,
-       },
-};
-
-module_qcom_smd_driver(ipcrtr_stub_driver);
-
-MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@sonymobile.com>");
-MODULE_DESCRIPTION("Qualcomm IPCRTR stub driver");
-MODULE_LICENSE("GPLv2");
-
index af3152c733998935bbda347def7b204ecff2772a..abb32001ff3a82dd444b2d0ec156235fdd58eeac 100644 (file)
@@ -33,6 +33,7 @@
  */
 struct qcom_smd_rpm {
        struct qcom_smd_channel *rpm_channel;
+       struct device *dev;
 
        struct completion ack;
        struct mutex lock;
@@ -149,14 +150,14 @@ out:
 }
 EXPORT_SYMBOL(qcom_rpm_smd_write);
 
-static int qcom_smd_rpm_callback(struct qcom_smd_device *qsdev,
+static int qcom_smd_rpm_callback(struct qcom_smd_channel *channel,
                                 const void *data,
                                 size_t count)
 {
        const struct qcom_rpm_header *hdr = data;
        size_t hdr_length = le32_to_cpu(hdr->length);
        const struct qcom_rpm_message *msg;
-       struct qcom_smd_rpm *rpm = dev_get_drvdata(&qsdev->dev);
+       struct qcom_smd_rpm *rpm = qcom_smd_get_drvdata(channel);
        const u8 *buf = data + sizeof(struct qcom_rpm_header);
        const u8 *end = buf + hdr_length;
        char msgbuf[32];
@@ -165,7 +166,7 @@ static int qcom_smd_rpm_callback(struct qcom_smd_device *qsdev,
 
        if (le32_to_cpu(hdr->service_type) != RPM_SERVICE_TYPE_REQUEST ||
            hdr_length < sizeof(struct qcom_rpm_message)) {
-               dev_err(&qsdev->dev, "invalid request\n");
+               dev_err(rpm->dev, "invalid request\n");
                return 0;
        }
 
@@ -206,7 +207,9 @@ static int qcom_smd_rpm_probe(struct qcom_smd_device *sdev)
        mutex_init(&rpm->lock);
        init_completion(&rpm->ack);
 
+       rpm->dev = &sdev->dev;
        rpm->rpm_channel = sdev->channel;
+       qcom_smd_set_drvdata(sdev->channel, rpm);
 
        dev_set_drvdata(&sdev->dev, rpm);
 
index 1ef645a785404bf5d1829816b7ac03dd66865c2b..0b08b9dc8005840932243352655930f8992e1c5c 100644 (file)
@@ -123,7 +123,7 @@ struct qcom_smd_edge {
        int ipc_bit;
 
        struct list_head channels;
-       rwlock_t channels_lock;
+       spinlock_t channels_lock;
 
        DECLARE_BITMAP(allocated[SMD_ALLOC_TBL_COUNT], SMD_ALLOC_TBL_SIZE);
 
@@ -135,6 +135,70 @@ struct qcom_smd_edge {
        struct work_struct state_work;
 };
 
+/*
+ * SMD channel states.
+ */
+enum smd_channel_state {
+       SMD_CHANNEL_CLOSED,
+       SMD_CHANNEL_OPENING,
+       SMD_CHANNEL_OPENED,
+       SMD_CHANNEL_FLUSHING,
+       SMD_CHANNEL_CLOSING,
+       SMD_CHANNEL_RESET,
+       SMD_CHANNEL_RESET_OPENING
+};
+
+/**
+ * struct qcom_smd_channel - smd channel struct
+ * @edge:              qcom_smd_edge this channel is living on
+ * @qsdev:             reference to a associated smd client device
+ * @name:              name of the channel
+ * @state:             local state of the channel
+ * @remote_state:      remote state of the channel
+ * @info:              byte aligned outgoing/incoming channel info
+ * @info_word:         word aligned outgoing/incoming channel info
+ * @tx_lock:           lock to make writes to the channel mutually exclusive
+ * @fblockread_event:  wakeup event tied to tx fBLOCKREADINTR
+ * @tx_fifo:           pointer to the outgoing ring buffer
+ * @rx_fifo:           pointer to the incoming ring buffer
+ * @fifo_size:         size of each ring buffer
+ * @bounce_buffer:     bounce buffer for reading wrapped packets
+ * @cb:                        callback function registered for this channel
+ * @recv_lock:         guard for rx info modifications and cb pointer
+ * @pkt_size:          size of the currently handled packet
+ * @list:              lite entry for @channels in qcom_smd_edge
+ */
+struct qcom_smd_channel {
+       struct qcom_smd_edge *edge;
+
+       struct qcom_smd_device *qsdev;
+
+       char *name;
+       enum smd_channel_state state;
+       enum smd_channel_state remote_state;
+
+       struct smd_channel_info_pair *info;
+       struct smd_channel_info_word_pair *info_word;
+
+       struct mutex tx_lock;
+       wait_queue_head_t fblockread_event;
+
+       void *tx_fifo;
+       void *rx_fifo;
+       int fifo_size;
+
+       void *bounce_buffer;
+       qcom_smd_cb_t cb;
+
+       spinlock_t recv_lock;
+
+       int pkt_size;
+
+       void *drvdata;
+
+       struct list_head list;
+       struct list_head dev_list;
+};
 
 /**
  * struct qcom_smd - smd struct
@@ -453,7 +517,6 @@ static void qcom_smd_channel_advance(struct qcom_smd_channel *channel,
  */
 static int qcom_smd_channel_recv_single(struct qcom_smd_channel *channel)
 {
-       struct qcom_smd_device *qsdev = channel->qsdev;
        unsigned tail;
        size_t len;
        void *ptr;
@@ -473,7 +536,7 @@ static int qcom_smd_channel_recv_single(struct qcom_smd_channel *channel)
                len = channel->pkt_size;
        }
 
-       ret = channel->cb(qsdev, ptr, len);
+       ret = channel->cb(channel, ptr, len);
        if (ret < 0)
                return ret;
 
@@ -557,18 +620,19 @@ static irqreturn_t qcom_smd_edge_intr(int irq, void *data)
        struct qcom_smd_edge *edge = data;
        struct qcom_smd_channel *channel;
        unsigned available;
-       bool kick_worker = false;
+       bool kick_scanner = false;
+       bool kick_state = false;
 
        /*
         * Handle state changes or data on each of the channels on this edge
         */
-       read_lock(&edge->channels_lock);
+       spin_lock(&edge->channels_lock);
        list_for_each_entry(channel, &edge->channels, list) {
                spin_lock(&channel->recv_lock);
-               kick_worker |= qcom_smd_channel_intr(channel);
+               kick_state |= qcom_smd_channel_intr(channel);
                spin_unlock(&channel->recv_lock);
        }
-       read_unlock(&edge->channels_lock);
+       spin_unlock(&edge->channels_lock);
 
        /*
         * Creating a new channel requires allocating an smem entry, so we only
@@ -578,11 +642,13 @@ static irqreturn_t qcom_smd_edge_intr(int irq, void *data)
        available = qcom_smem_get_free_space(edge->remote_pid);
        if (available != edge->smem_available) {
                edge->smem_available = available;
-               kick_worker = true;
+               kick_scanner = true;
        }
 
-       if (kick_worker)
+       if (kick_scanner)
                schedule_work(&edge->scan_work);
+       if (kick_state)
+               schedule_work(&edge->state_work);
 
        return IRQ_HANDLED;
 }
@@ -667,7 +733,7 @@ int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len)
 {
        __le32 hdr[5] = { cpu_to_le32(len), };
        int tlen = sizeof(hdr) + len;
-       int ret, length;
+       int ret;
 
        /* Word aligned channels only accept word size aligned data */
        if (channel->info_word && len % 4)
@@ -677,13 +743,10 @@ int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len)
        if (tlen >= channel->fifo_size)
                return -EINVAL;
 
-       length = qcom_smd_get_tx_avail(channel);
-
        ret = mutex_lock_interruptible(&channel->tx_lock);
        if (ret)
                return ret;
 
-       length = qcom_smd_get_tx_avail(channel);
        while (qcom_smd_get_tx_avail(channel) < tlen) {
                if (channel->state != SMD_CHANNEL_OPENED) {
                        ret = -EPIPE;
@@ -703,7 +766,6 @@ int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len)
 
        SET_TX_CHANNEL_FLAG(channel, fTAIL, 0);
 
-       length = qcom_smd_get_tx_avail(channel);
        qcom_smd_write_fifo(channel, hdr, sizeof(hdr));
        qcom_smd_write_fifo(channel, data, len);
 
@@ -975,6 +1037,18 @@ int qcom_smd_driver_register(struct qcom_smd_driver *qsdrv)
 }
 EXPORT_SYMBOL(qcom_smd_driver_register);
 
+void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel)
+{
+       return channel->drvdata;
+}
+EXPORT_SYMBOL(qcom_smd_get_drvdata);
+
+void qcom_smd_set_drvdata(struct qcom_smd_channel *channel, void *data)
+{
+       channel->drvdata = data;
+}
+EXPORT_SYMBOL(qcom_smd_set_drvdata);
+
 /**
  * qcom_smd_driver_unregister - unregister a smd driver
  * @qsdrv:     qcom_smd_driver struct
@@ -990,9 +1064,10 @@ qcom_smd_find_channel(struct qcom_smd_edge *edge, const char *name)
 {
        struct qcom_smd_channel *channel;
        struct qcom_smd_channel *ret = NULL;
+       unsigned long flags;
        unsigned state;
 
-       read_lock(&edge->channels_lock);
+       spin_lock_irqsave(&edge->channels_lock, flags);
        list_for_each_entry(channel, &edge->channels, list) {
                if (strcmp(channel->name, name))
                        continue;
@@ -1005,7 +1080,7 @@ qcom_smd_find_channel(struct qcom_smd_edge *edge, const char *name)
                ret = channel;
                break;
        }
-       read_unlock(&edge->channels_lock);
+       spin_unlock_irqrestore(&edge->channels_lock, flags);
 
        return ret;
 }
@@ -1019,12 +1094,13 @@ qcom_smd_find_channel(struct qcom_smd_edge *edge, const char *name)
  * Returns a channel handle on success, or -EPROBE_DEFER if the channel isn't
  * ready.
  */
-struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_device *sdev,
+struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *parent,
                                               const char *name,
                                               qcom_smd_cb_t cb)
 {
        struct qcom_smd_channel *channel;
-       struct qcom_smd_edge *edge = sdev->channel->edge;
+       struct qcom_smd_device *sdev = parent->qsdev;
+       struct qcom_smd_edge *edge = parent->edge;
        int ret;
 
        /* Wait up to HZ for the channel to appear */
@@ -1116,7 +1192,7 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed
        /* The channel consist of a rx and tx fifo of equal size */
        fifo_size /= 2;
 
-       dev_err(smd->dev, "new channel '%s' info-size: %zu fifo-size: %zu\n",
+       dev_dbg(smd->dev, "new channel '%s' info-size: %zu fifo-size: %zu\n",
                          name, info_size, fifo_size);
 
        channel->tx_fifo = fifo_base;
@@ -1185,9 +1261,9 @@ static void qcom_channel_scan_worker(struct work_struct *work)
                        if (IS_ERR(channel))
                                continue;
 
-                       write_lock_irqsave(&edge->channels_lock, flags);
+                       spin_lock_irqsave(&edge->channels_lock, flags);
                        list_add(&channel->list, &edge->channels);
-                       write_unlock_irqrestore(&edge->channels_lock, flags);
+                       spin_unlock_irqrestore(&edge->channels_lock, flags);
 
                        dev_dbg(smd->dev, "new channel found: '%s'\n", channel->name);
                        set_bit(i, edge->allocated[tbl]);
@@ -1214,12 +1290,13 @@ static void qcom_channel_state_worker(struct work_struct *work)
                                                  struct qcom_smd_edge,
                                                  state_work);
        unsigned remote_state;
+       unsigned long flags;
 
        /*
         * Register a device for any closed channel where the remote processor
         * is showing interest in opening the channel.
         */
-       read_lock(&edge->channels_lock);
+       spin_lock_irqsave(&edge->channels_lock, flags);
        list_for_each_entry(channel, &edge->channels, list) {
                if (channel->state != SMD_CHANNEL_CLOSED)
                        continue;
@@ -1229,9 +1306,9 @@ static void qcom_channel_state_worker(struct work_struct *work)
                    remote_state != SMD_CHANNEL_OPENED)
                        continue;
 
-               read_unlock(&edge->channels_lock);
+               spin_unlock_irqrestore(&edge->channels_lock, flags);
                qcom_smd_create_device(channel);
-               read_lock(&edge->channels_lock);
+               spin_lock_irqsave(&edge->channels_lock, flags);
        }
 
        /*
@@ -1248,11 +1325,11 @@ static void qcom_channel_state_worker(struct work_struct *work)
                    remote_state == SMD_CHANNEL_OPENED)
                        continue;
 
-               read_unlock(&edge->channels_lock);
+               spin_unlock_irqrestore(&edge->channels_lock, flags);
                qcom_smd_destroy_device(channel);
-               read_lock(&edge->channels_lock);
+               spin_lock_irqsave(&edge->channels_lock, flags);
        }
-       read_unlock(&edge->channels_lock);
+       spin_unlock_irqrestore(&edge->channels_lock, flags);
 }
 
 /*
@@ -1268,7 +1345,7 @@ static int qcom_smd_parse_edge(struct device *dev,
        int ret;
 
        INIT_LIST_HEAD(&edge->channels);
-       rwlock_init(&edge->channels_lock);
+       spin_lock_init(&edge->channels_lock);
 
        INIT_WORK(&edge->scan_work, qcom_channel_scan_worker);
        INIT_WORK(&edge->state_work, qcom_channel_state_worker);
index 5290bb02c5476a4582d89a7c3d197df218152a46..8b9bfe912f8635a79cfe096c20ac234340ab2686 100644 (file)
@@ -690,8 +690,7 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev,
 
        smem->regions[i].aux_base = (u32)r.start;
        smem->regions[i].size = resource_size(&r);
-       smem->regions[i].virt_base = devm_ioremap_nocache(dev, r.start,
-                                                         resource_size(&r));
+       smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, resource_size(&r));
        if (!smem->regions[i].virt_base)
                return -ENOMEM;
 
index 7a986f881d5c860df19614c4ca781bce69d2d296..00538a1a961774730387c885d1b9512952757d04 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2016, Linaro Ltd.
  * Copyright (c) 2015, Sony Mobile Communications Inc.
  *
  * This program is free software; you can redistribute it and/or modify
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/soc/qcom/smd.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/soc/qcom/wcnss_ctrl.h>
 
 #define WCNSS_REQUEST_TIMEOUT  (5 * HZ)
+#define WCNSS_CBC_TIMEOUT      (10 * HZ)
+
+#define WCNSS_ACK_DONE_BOOTING 1
+#define WCNSS_ACK_COLD_BOOTING 2
 
 #define NV_FRAGMENT_SIZE       3072
 #define NVBIN_FILE             "wlan/prima/WCNSS_qcom_wlan_nv.bin"
  * @dev:       device handle
  * @channel:   SMD channel handle
  * @ack:       completion for outstanding requests
+ * @cbc:       completion for cbc complete indication
  * @ack_status:        status of the outstanding request
- * @download_nv_work: worker for uploading nv binary
+ * @probe_work: worker for uploading nv binary
  */
 struct wcnss_ctrl {
        struct device *dev;
        struct qcom_smd_channel *channel;
 
        struct completion ack;
+       struct completion cbc;
        int ack_status;
 
-       struct work_struct download_nv_work;
+       struct work_struct probe_work;
 };
 
 /* message types */
@@ -48,6 +59,11 @@ enum {
        WCNSS_UPLOAD_CAL_RESP,
        WCNSS_DOWNLOAD_CAL_REQ,
        WCNSS_DOWNLOAD_CAL_RESP,
+       WCNSS_VBAT_LEVEL_IND,
+       WCNSS_BUILD_VERSION_REQ,
+       WCNSS_BUILD_VERSION_RESP,
+       WCNSS_PM_CONFIG_REQ,
+       WCNSS_CBC_COMPLETE_IND,
 };
 
 /**
@@ -100,17 +116,17 @@ struct wcnss_download_nv_resp {
 
 /**
  * wcnss_ctrl_smd_callback() - handler from SMD responses
- * @qsdev:     smd device handle
+ * @channel:   smd channel handle
  * @data:      pointer to the incoming data packet
  * @count:     size of the incoming data packet
  *
  * Handles any incoming packets from the remote WCNSS_CTRL service.
  */
-static int wcnss_ctrl_smd_callback(struct qcom_smd_device *qsdev,
+static int wcnss_ctrl_smd_callback(struct qcom_smd_channel *channel,
                                   const void *data,
                                   size_t count)
 {
-       struct wcnss_ctrl *wcnss = dev_get_drvdata(&qsdev->dev);
+       struct wcnss_ctrl *wcnss = qcom_smd_get_drvdata(channel);
        const struct wcnss_download_nv_resp *nvresp;
        const struct wcnss_version_resp *version;
        const struct wcnss_msg_hdr *hdr = data;
@@ -128,7 +144,7 @@ static int wcnss_ctrl_smd_callback(struct qcom_smd_device *qsdev,
                         version->major, version->minor,
                         version->version, version->revision);
 
-               schedule_work(&wcnss->download_nv_work);
+               complete(&wcnss->ack);
                break;
        case WCNSS_DOWNLOAD_NV_RESP:
                if (count != sizeof(*nvresp)) {
@@ -141,6 +157,10 @@ static int wcnss_ctrl_smd_callback(struct qcom_smd_device *qsdev,
                wcnss->ack_status = nvresp->status;
                complete(&wcnss->ack);
                break;
+       case WCNSS_CBC_COMPLETE_IND:
+               dev_dbg(wcnss->dev, "cold boot complete\n");
+               complete(&wcnss->cbc);
+               break;
        default:
                dev_info(wcnss->dev, "unknown message type %d\n", hdr->type);
                break;
@@ -156,20 +176,32 @@ static int wcnss_ctrl_smd_callback(struct qcom_smd_device *qsdev,
 static int wcnss_request_version(struct wcnss_ctrl *wcnss)
 {
        struct wcnss_msg_hdr msg;
+       int ret;
 
        msg.type = WCNSS_VERSION_REQ;
        msg.len = sizeof(msg);
+       ret = qcom_smd_send(wcnss->channel, &msg, sizeof(msg));
+       if (ret < 0)
+               return ret;
+
+       ret = wait_for_completion_timeout(&wcnss->ack, WCNSS_CBC_TIMEOUT);
+       if (!ret) {
+               dev_err(wcnss->dev, "timeout waiting for version response\n");
+               return -ETIMEDOUT;
+       }
 
-       return qcom_smd_send(wcnss->channel, &msg, sizeof(msg));
+       return 0;
 }
 
 /**
  * wcnss_download_nv() - send nv binary to WCNSS
- * @work:      work struct to acquire wcnss context
+ * @wcnss:     wcnss_ctrl state handle
+ * @expect_cbc:        indicator to caller that an cbc event is expected
+ *
+ * Returns 0 on success. Negative errno on failure.
  */
-static void wcnss_download_nv(struct work_struct *work)
+static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc)
 {
-       struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, download_nv_work);
        struct wcnss_download_nv_req *req;
        const struct firmware *fw;
        const void *data;
@@ -178,10 +210,10 @@ static void wcnss_download_nv(struct work_struct *work)
 
        req = kzalloc(sizeof(*req) + NV_FRAGMENT_SIZE, GFP_KERNEL);
        if (!req)
-               return;
+               return -ENOMEM;
 
        ret = request_firmware(&fw, NVBIN_FILE, wcnss->dev);
-       if (ret) {
+       if (ret < 0) {
                dev_err(wcnss->dev, "Failed to load nv file %s: %d\n",
                        NVBIN_FILE, ret);
                goto free_req;
@@ -207,7 +239,7 @@ static void wcnss_download_nv(struct work_struct *work)
                memcpy(req->fragment, data, req->frag_size);
 
                ret = qcom_smd_send(wcnss->channel, req, req->hdr.len);
-               if (ret) {
+               if (ret < 0) {
                        dev_err(wcnss->dev, "failed to send smd packet\n");
                        goto release_fw;
                }
@@ -220,16 +252,63 @@ static void wcnss_download_nv(struct work_struct *work)
        } while (left > 0);
 
        ret = wait_for_completion_timeout(&wcnss->ack, WCNSS_REQUEST_TIMEOUT);
-       if (!ret)
+       if (!ret) {
                dev_err(wcnss->dev, "timeout waiting for nv upload ack\n");
-       else if (wcnss->ack_status != 1)
-               dev_err(wcnss->dev, "nv upload response failed err: %d\n",
-                       wcnss->ack_status);
+               ret = -ETIMEDOUT;
+       } else {
+               *expect_cbc = wcnss->ack_status == WCNSS_ACK_COLD_BOOTING;
+               ret = 0;
+       }
 
 release_fw:
        release_firmware(fw);
 free_req:
        kfree(req);
+
+       return ret;
+}
+
+int wcnss_ctrl_done_loading_nv;
+EXPORT_SYMBOL(wcnss_ctrl_done_loading_nv);
+
+/**
+ * qcom_wcnss_open_channel() - open additional SMD channel to WCNSS
+ * @wcnss:     wcnss handle, retrieved from drvdata
+ * @name:      SMD channel name
+ * @cb:                callback to handle incoming data on the channel
+ */
+struct qcom_smd_channel *qcom_wcnss_open_channel(void *wcnss, const char *name, qcom_smd_cb_t cb)
+{
+       struct wcnss_ctrl *_wcnss = wcnss;
+
+       return qcom_smd_open_channel(_wcnss->channel, name, cb);
+}
+EXPORT_SYMBOL(qcom_wcnss_open_channel);
+
+static void wcnss_async_probe(struct work_struct *work)
+{
+       struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, probe_work);
+       bool expect_cbc;
+       int ret;
+
+       ret = wcnss_request_version(wcnss);
+       if (ret < 0)
+               return;
+
+       ret = wcnss_download_nv(wcnss, &expect_cbc);
+       if (ret < 0)
+               return;
+
+       /* Wait for pending cold boot completion if indicated by the nv downloader */
+       if (expect_cbc) {
+               ret = wait_for_completion_timeout(&wcnss->cbc, WCNSS_REQUEST_TIMEOUT);
+               if (!ret)
+                       dev_err(wcnss->dev, "expected cold boot completion\n");
+       }
+
+       wcnss_ctrl_done_loading_nv = 1;
+
+       of_platform_populate(wcnss->dev->of_node, NULL, NULL, wcnss->dev);
 }
 
 static int wcnss_ctrl_probe(struct qcom_smd_device *sdev)
@@ -244,25 +323,40 @@ static int wcnss_ctrl_probe(struct qcom_smd_device *sdev)
        wcnss->channel = sdev->channel;
 
        init_completion(&wcnss->ack);
-       INIT_WORK(&wcnss->download_nv_work, wcnss_download_nv);
+       init_completion(&wcnss->cbc);
+       INIT_WORK(&wcnss->probe_work, wcnss_async_probe);
 
+       qcom_smd_set_drvdata(sdev->channel, wcnss);
        dev_set_drvdata(&sdev->dev, wcnss);
 
-       return wcnss_request_version(wcnss);
+       qcom_smd_set_drvdata(sdev->channel, wcnss);
+
+       schedule_work(&wcnss->probe_work);
+
+       return 0;
+}
+
+static void wcnss_ctrl_remove(struct qcom_smd_device *sdev)
+{
+       struct wcnss_ctrl *wcnss = qcom_smd_get_drvdata(sdev->channel);
+
+       cancel_work_sync(&wcnss->probe_work);
+       of_platform_depopulate(&sdev->dev);
 }
 
-static const struct qcom_smd_id wcnss_ctrl_smd_match[] = {
-       { .name = "WCNSS_CTRL" },
+static const struct of_device_id wcnss_ctrl_of_match[] = {
+       { .compatible = "qcom,wcnss", },
        {}
 };
 
 static struct qcom_smd_driver wcnss_ctrl_driver = {
        .probe = wcnss_ctrl_probe,
+       .remove = wcnss_ctrl_remove,
        .callback = wcnss_ctrl_smd_callback,
-       .smd_match_table = wcnss_ctrl_smd_match,
        .driver  = {
                .name  = "qcom_wcnss_ctrl",
                .owner = THIS_MODULE,
+               .of_match_table = wcnss_ctrl_of_match,
        },
 };
 
index 81ae6c956eb815229b3e1531dbcf678a4e582463..5924cdb7133621f0e4a4427c1208b8cc6fbc0d80 100644 (file)
 #ifndef _DT_BINDINGS_CLK_MSM_RPMCC_H
 #define _DT_BINDINGS_CLK_MSM_RPMCC_H
 
-/* msm8916 */
-#define RPM_XO_CLK_SRC                         0
-#define RPM_XO_A_CLK_SRC                       1
-#define RPM_PCNOC_CLK                          2
-#define RPM_PCNOC_A_CLK                                3
-#define RPM_SNOC_CLK                           4
-#define RPM_SNOC_A_CLK                         5
-#define RPM_BIMC_CLK                           6
-#define RPM_BIMC_A_CLK                         7
-#define RPM_QDSS_CLK                           8
-#define RPM_QDSS_A_CLK                         9
-#define RPM_BB_CLK1                            10
-#define RPM_BB_CLK1_A                          11
-#define RPM_BB_CLK2                            12
-#define RPM_BB_CLK2_A                          13
-#define RPM_RF_CLK1                            14
-#define RPM_RF_CLK1_A                          15
-#define RPM_RF_CLK2                            16
-#define RPM_RF_CLK2_A                          17
-#define RPM_BB_CLK1_PIN                                18
-#define RPM_BB_CLK1_A_PIN                      19
-#define RPM_BB_CLK2_PIN                                20
-#define RPM_BB_CLK2_A_PIN                      21
-#define RPM_RF_CLK1_PIN                                22
-#define RPM_RF_CLK1_A_PIN                      23
-#define RPM_RF_CLK2_PIN                                24
-#define RPM_RF_CLK2_A_PIN                      25
-
-/* msm8974 */
-#define RPM_CXO_CLK_SRC                                0
-#define RPM_CXO_A_CLK_SRC                      1
-#define RPM_PNOC_CLK                           2
-#define RPM_PNOC_A_CLK                         3
-#define RPM_SNOC_CLK                           4
-#define RPM_SNOC_A_CLK                         5
-#define RPM_BIMC_CLK                           6
-#define RPM_BIMC_A_CLK                         7
+/* apq8064 */
+#define RPM_PXO_CLK                            0
+#define RPM_PXO_A_CLK                          1
+#define RPM_CXO_CLK                            2
+#define RPM_CXO_A_CLK                          3
+#define RPM_APPS_FABRIC_CLK                    4
+#define RPM_APPS_FABRIC_A_CLK                  5
+#define RPM_CFPB_CLK                           6
+#define RPM_CFPB_A_CLK                         7
 #define RPM_QDSS_CLK                           8
 #define RPM_QDSS_A_CLK                         9
-#define RPM_CXO_D0                             10
-#define RPM_CXO_D0_A                           11
-#define RPM_CXO_D1                             12
-#define RPM_CXO_D1_A                           13
-#define RPM_CXO_A0                             14
-#define RPM_CXO_A0_A                           15
-#define RPM_CXO_A1                             16
-#define RPM_CXO_A1_A                           17
-#define RPM_CXO_A2                             18
-#define RPM_CXO_A2_A                           19
-#define RPM_CXO_D0_PIN                         20
-#define RPM_CXO_D0_A_PIN                       21
-#define RPM_CXO_A2_PIN                         22
-#define RPM_CXO_A2_A_PIN                       23
-#define RPM_CXO_A1_PIN                         24
-#define RPM_CXO_A1_A_PIN                       25
-#define RPM_DIFF_CLK                           26
-#define RPM_DIFF_A_CLK                         27
-#define RPM_CNOC_CLK                           28
-#define RPM_CNOC_A_CLK                         29
-#define RPM_MMSSNOC_AHB_CLK                    30
-#define RPM_MMSSNOC_AHB_A_CLK                  31
-#define RPM_OCMEMGX_CLK                                32
-#define RPM_OCMEMGX_A_CLK                      33
-#define RPM_GFX3D_CLK_SRC                      34
-#define RPM_GFX3D_A_CLK_SRC                    35
-#define RPM_DIV_CLK1                           36
-#define RPM_DIV_A_CLK1                         37
-#define RPM_DIV_CLK2                           38
-#define RPM_DIV_A_CLK2                         39
-#define RPM_CXO_D1_PIN                         40
-#define RPM_CXO_D1_A_PIN                       41
-#define RPM_CXO_A0_PIN                         42
-#define RPM_CXO_A0_A_PIN                       43
+#define RPM_DAYTONA_FABRIC_CLK                 10
+#define RPM_DAYTONA_FABRIC_A_CLK               11
+#define RPM_EBI1_CLK                           12
+#define RPM_EBI1_A_CLK                         13
+#define RPM_MM_FABRIC_CLK                      14
+#define RPM_MM_FABRIC_A_CLK                    15
+#define RPM_MMFPB_CLK                          16
+#define RPM_MMFPB_A_CLK                                17
+#define RPM_SYS_FABRIC_CLK                     18
+#define RPM_SYS_FABRIC_A_CLK                   19
+#define RPM_SFPB_CLK                           20
+#define RPM_SFPB_A_CLK                         21
 
-/* apq8084 */
-#define RPM_XO_CLK_SRC                         0
-#define RPM_XO_A_CLK_SRC                       1
-#define RPM_PNOC_CLK                           2
-#define RPM_PNOC_A_CLK                         3
-#define RPM_SNOC_CLK                           4
-#define RPM_SNOC_A_CLK                         5
-#define RPM_BIMC_CLK                           6
-#define RPM_BIMC_A_CLK                         7
-#define RPM_QDSS_CLK                           8
-#define RPM_QDSS_A_CLK                         9
-#define RPM_BB_CLK1                            10
-#define RPM_BB_CLK1_A                          11
-#define RPM_BB_CLK2                            12
-#define RPM_BB_CLK2_A                          13
-#define RPM_RF_CLK1                            14
-#define RPM_RF_CLK1_A                          15
-#define RPM_RF_CLK2                            16
-#define RPM_RF_CLK2_A                          17
-#define RPM_BB_CLK1_PIN                                18
-#define RPM_BB_CLK1_A_PIN                      19
-#define RPM_BB_CLK2_PIN                                20
-#define RPM_BB_CLK2_A_PIN                      21
-#define RPM_RF_CLK1_PIN                                22
-#define RPM_RF_CLK1_A_PIN                      23
-#define RPM_RF_CLK2_PIN                                24
-#define RPM_RF_CLK2_A_PIN                      25
-#define RPM_DIFF_CLK1                          26
-#define RPM_DIFF_CLK1_A                                27
-#define RPM_CNOC_CLK                           28
-#define RPM_CNOC_A_CLK                         29
-#define RPM_MMSSNOC_AHB_CLK                    30
-#define RPM_MMSSNOC_AHB_A_CLK                  31
-#define RPM_OCMEMGX_CLK                                32
-#define RPM_OCMEMGX_A_CLK                      33
-#define RPM_GFX3D_CLK_SRC                      34
-#define RPM_GFX3D_A_CLK_SRC                    35
-#define RPM_DIV_CLK1                           36
-#define RPM_DIV_CLK1_A                         37
-#define RPM_DIV_CLK2                           38
-#define RPM_DIV_CLK2_A                         39
-#define RPM_DIV_CLK3                           40
-#define RPM_DIV_CLK3_A                         41
-#define RPM_RF_CLK3_PIN                                44
-#define RPM_RF_CLK3_A_PIN                      45
-#define RPM_RF_CLK3                            46
-#define RPM_RF_CLK3_A                          47
+/* msm8916 */
+#define RPM_SMD_XO_CLK_SRC                             0
+#define RPM_SMD_XO_A_CLK_SRC                   1
+#define RPM_SMD_PCNOC_CLK                              2
+#define RPM_SMD_PCNOC_A_CLK                            3
+#define RPM_SMD_SNOC_CLK                               4
+#define RPM_SMD_SNOC_A_CLK                             5
+#define RPM_SMD_BIMC_CLK                               6
+#define RPM_SMD_BIMC_A_CLK                             7
+#define RPM_SMD_QDSS_CLK                               8
+#define RPM_SMD_QDSS_A_CLK                             9
+#define RPM_SMD_BB_CLK1                                10
+#define RPM_SMD_BB_CLK1_A                              11
+#define RPM_SMD_BB_CLK2                                12
+#define RPM_SMD_BB_CLK2_A                              13
+#define RPM_SMD_RF_CLK1                                14
+#define RPM_SMD_RF_CLK1_A                              15
+#define RPM_SMD_RF_CLK2                                16
+#define RPM_SMD_RF_CLK2_A                              17
+#define RPM_SMD_BB_CLK1_PIN                            18
+#define RPM_SMD_BB_CLK1_A_PIN                  19
+#define RPM_SMD_BB_CLK2_PIN                            20
+#define RPM_SMD_BB_CLK2_A_PIN                  21
+#define RPM_SMD_RF_CLK1_PIN                            22
+#define RPM_SMD_RF_CLK1_A_PIN                  23
+#define RPM_SMD_RF_CLK2_PIN                            24
+#define RPM_SMD_RF_CLK2_A_PIN                  25
 
 #endif
index 0b9f01b489cb2d70c53a3d4471918bc4efb0daf2..93819720e2a4bb1f677ed10d033ed553bbbc838c 100644 (file)
@@ -32,8 +32,7 @@ extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
                u32 *resp);
 
 extern bool qcom_scm_pas_supported(u32 peripheral);
-extern int qcom_scm_restart_proc(u32 pid, int restart, u32 *resp);
-extern int qcom_scm_pas_init_image(struct device *dev, u32 peripheral, const void *metadata, size_t size);
+extern int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size);
 extern int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size);
 extern int qcom_scm_pas_auth_and_reset(u32 peripheral);
 extern int qcom_scm_pas_shutdown(u32 peripheral);
index 49764d94ef4f74349737f6e5406f427a92e2b3d1..cbb0f06c41b21866385882d85e6954d70b77b1a4 100644 (file)
@@ -5,74 +5,8 @@
 #include <linux/mod_devicetable.h>
 
 struct qcom_smd;
+struct qcom_smd_channel;
 struct qcom_smd_lookup;
-struct qcom_smd_device;
-
-typedef int (*qcom_smd_cb_t)(struct qcom_smd_device *, const void *, size_t);
-
-/*
- * SMD channel states.
- */
-enum smd_channel_state {
-       SMD_CHANNEL_CLOSED,
-       SMD_CHANNEL_OPENING,
-       SMD_CHANNEL_OPENED,
-       SMD_CHANNEL_FLUSHING,
-       SMD_CHANNEL_CLOSING,
-       SMD_CHANNEL_RESET,
-       SMD_CHANNEL_RESET_OPENING
-};
-
-/**
- * struct qcom_smd_channel - smd channel struct
- * @edge:              qcom_smd_edge this channel is living on
- * @qsdev:             reference to a associated smd client device
- * @name:              name of the channel
- * @state:             local state of the channel
- * @remote_state:      remote state of the channel
- * @info:              byte aligned outgoing/incoming channel info
- * @info_word:         word aligned outgoing/incoming channel info
- * @tx_lock:           lock to make writes to the channel mutually exclusive
- * @fblockread_event:  wakeup event tied to tx fBLOCKREADINTR
- * @tx_fifo:           pointer to the outgoing ring buffer
- * @rx_fifo:           pointer to the incoming ring buffer
- * @fifo_size:         size of each ring buffer
- * @bounce_buffer:     bounce buffer for reading wrapped packets
- * @cb:                        callback function registered for this channel
- * @recv_lock:         guard for rx info modifications and cb pointer
- * @pkt_size:          size of the currently handled packet
- * @list:              lite entry for @channels in qcom_smd_edge
- */
-
-struct qcom_smd_channel {
-       struct qcom_smd_edge *edge;
-
-       struct qcom_smd_device *qsdev;
-
-       char *name;
-       enum smd_channel_state state;
-       enum smd_channel_state remote_state;
-
-       struct smd_channel_info_pair *info;
-       struct smd_channel_info_word_pair *info_word;
-
-       struct mutex tx_lock;
-       wait_queue_head_t fblockread_event;
-
-       void *tx_fifo;
-       void *rx_fifo;
-       int fifo_size;
-
-       void *bounce_buffer;
-       qcom_smd_cb_t cb;
-
-       spinlock_t recv_lock;
-
-       int pkt_size;
-
-       struct list_head list;
-       struct list_head dev_list;
-};
 
 /**
  * struct qcom_smd_id - struct used for matching a smd device
@@ -92,6 +26,8 @@ struct qcom_smd_device {
        struct qcom_smd_channel *channel;
 };
 
+typedef int (*qcom_smd_cb_t)(struct qcom_smd_channel *, const void *, size_t);
+
 /**
  * struct qcom_smd_driver - smd driver struct
  * @driver:    underlying device driver
@@ -111,17 +47,68 @@ struct qcom_smd_driver {
        qcom_smd_cb_t callback;
 };
 
+#if IS_ENABLED(CONFIG_QCOM_SMD)
+
 int qcom_smd_driver_register(struct qcom_smd_driver *drv);
 void qcom_smd_driver_unregister(struct qcom_smd_driver *drv);
 
+struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_channel *channel,
+                                              const char *name,
+                                              qcom_smd_cb_t cb);
+void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel);
+void qcom_smd_set_drvdata(struct qcom_smd_channel *channel, void *data);
+int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len);
+
+
+#else
+
+static inline int qcom_smd_driver_register(struct qcom_smd_driver *drv)
+{
+       return -ENXIO;
+}
+
+static inline void qcom_smd_driver_unregister(struct qcom_smd_driver *drv)
+{
+       /* This shouldn't be possible */
+       WARN_ON(1);
+}
+
+static inline struct qcom_smd_channel *
+qcom_smd_open_channel(struct qcom_smd_channel *channel,
+                     const char *name,
+                     qcom_smd_cb_t cb)
+{
+       /* This shouldn't be possible */
+       WARN_ON(1);
+       return NULL;
+}
+
+void *qcom_smd_get_drvdata(struct qcom_smd_channel *channel)
+{
+       /* This shouldn't be possible */
+       WARN_ON(1);
+       return NULL;
+}
+
+void qcom_smd_set_drvdata(struct qcom_smd_channel *channel, void *data)
+{
+       /* This shouldn't be possible */
+       WARN_ON(1);
+}
+
+static inline int qcom_smd_send(struct qcom_smd_channel *channel,
+                               const void *data, int len)
+{
+       /* This shouldn't be possible */
+       WARN_ON(1);
+       return -ENXIO;
+}
+
+#endif
+
 #define module_qcom_smd_driver(__smd_driver) \
        module_driver(__smd_driver, qcom_smd_driver_register, \
                      qcom_smd_driver_unregister)
 
-int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len);
-
-struct qcom_smd_channel *qcom_smd_open_channel(struct qcom_smd_device *sdev,
-                                              const char *name,
-                                              qcom_smd_cb_t cb);
 
 #endif
diff --git a/include/linux/soc/qcom/wcnss_ctrl.h b/include/linux/soc/qcom/wcnss_ctrl.h
new file mode 100644 (file)
index 0000000..a37bc55
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef __WCNSS_CTRL_H__
+#define __WCNSS_CTRL_H__
+
+#include <linux/soc/qcom/smd.h>
+
+struct qcom_smd_channel *qcom_wcnss_open_channel(void *wcnss, const char *name, qcom_smd_cb_t cb);
+
+#endif
index 760bc4d5a2cfe87aadd2e96a98292855cf2eb050..323237e5bf368bbe855cf18c617f4b52d711652a 100644 (file)
@@ -2157,7 +2157,7 @@ static inline void SET_IEEE80211_DEV(struct ieee80211_hw *hw, struct device *dev
  * @hw: the &struct ieee80211_hw to set the MAC address for
  * @addr: the address to set
  */
-static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr)
+static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, const u8 *addr)
 {
        memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN);
 }
index 84ebce73aa2323d7631cf1bfdd584ebd9e9a7b2c..0d11132b3370a4024be644dede74a77d188a4f64 100644 (file)
 struct qrtr_smd_dev {
        struct qrtr_endpoint ep;
        struct qcom_smd_channel *channel;
+       struct device *dev;
 };
 
 /* from smd to qrtr */
-static int qcom_smd_qrtr_callback(struct qcom_smd_device *sdev,
+static int qcom_smd_qrtr_callback(struct qcom_smd_channel *channel,
                                  const void *data, size_t len)
 {
-       struct qrtr_smd_dev *qdev = dev_get_drvdata(&sdev->dev);
+       struct qrtr_smd_dev *qdev = qcom_smd_get_drvdata(channel);
        int rc;
 
        if (!qdev)
@@ -35,7 +36,7 @@ static int qcom_smd_qrtr_callback(struct qcom_smd_device *sdev,
 
        rc = qrtr_endpoint_post(&qdev->ep, data, len);
        if (rc == -EINVAL) {
-               dev_err(&sdev->dev, "invalid ipcrouter packet\n");
+               dev_err(qdev->dev, "invalid ipcrouter packet\n");
                /* return 0 to let smd drop the packet */
                rc = 0;
        }
@@ -73,12 +74,14 @@ static int qcom_smd_qrtr_probe(struct qcom_smd_device *sdev)
                return -ENOMEM;
 
        qdev->channel = sdev->channel;
+       qdev->dev = &sdev->dev;
        qdev->ep.xmit = qcom_smd_qrtr_send;
 
        rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO);
        if (rc)
                return rc;
 
+       qcom_smd_set_drvdata(sdev->channel, qdev);
        dev_set_drvdata(&sdev->dev, qdev);
 
        dev_dbg(&sdev->dev, "Qualcomm SMD QRTR driver probed\n");
index cca94c69554f73a6789bf335ef11ee5b456b83ff..db115ce34541ffaa40032f7286d47405769975db 100644 (file)
@@ -64,25 +64,11 @@ struct apr_svc_ch_dev *apr_tal_open(uint32_t svc, uint32_t dest,
                        return NULL;
                }
                pr_info("apr_tal:Wakeup done\n");
-               apr_svc_ch[dl][dest][svc].dest_state = 0;
-       }
-
-       rc = wait_event_timeout(apr_svc_ch[dl][dest][svc].wait,
-               (apr_svc_ch[dl][dest][svc].ch->state == SMD_CHANNEL_OPENED), 5 * HZ);
-       if (rc == 0) {
-               pr_err("apr_tal:TIMEOUT for OPEN event\n");
-               apr_tal_close(&apr_svc_ch[dl][dest][svc]);
-               return NULL;
-       }
-       if (!apr_svc_ch[dl][dest][svc].dest_state) {
-               apr_svc_ch[dl][dest][svc].dest_state = 1;
-               pr_info("apr_tal:Waiting for apr svc init\n");
-               msleep(200);
-               pr_info("apr_tal:apr svc init done\n");
        }
        apr_svc_ch[dl][dest][svc].func = func;
        apr_svc_ch[dl][dest][svc].priv = priv;
 
+       pr_info("apr_tal:apr svc init done\n");
 
        return &apr_svc_ch[dl][dest][svc];
 }
@@ -99,13 +85,13 @@ int apr_tal_close(struct apr_svc_ch_dev *apr_ch)
 }
 
 
-static int qcom_smd_q6_callback(struct qcom_smd_device *sdev,
+static int qcom_smd_q6_callback(struct qcom_smd_channel *channel,
                                 const void *data,
                                 size_t count)
 {
-       struct apr_svc_ch_dev *apr_ch = dev_get_drvdata(&sdev->dev);
+       struct apr_svc_ch_dev *apr_ch = qcom_smd_get_drvdata(channel);
 
-       memcpy_fromio(apr_ch->data, data, count);
+       memcpy(apr_ch->data, data, count);
 
        if (apr_ch->func)
                apr_ch->func(apr_ch->data, count, apr_ch->priv);
@@ -115,22 +101,25 @@ static int qcom_smd_q6_callback(struct qcom_smd_device *sdev,
 
 static int qcom_smd_q6_probe(struct qcom_smd_device *sdev)
 {
-       int dest = APR_DEST_QDSP6;
-       int clnt = APR_CLIENT_AUDIO;
-
-       apr_svc_ch[APR_DL_SMD][APR_DEST_QDSP6][APR_CLIENT_AUDIO].ch = sdev->channel;
+       struct apr_svc_ch_dev *apr = &apr_svc_ch[APR_DL_SMD][APR_DEST_QDSP6][APR_CLIENT_AUDIO];
 
        pr_info("apr_tal:Q6 Is Up\n");
-       apr_svc_ch[APR_DL_SMD][dest][clnt].dest_state = 1;
-       wake_up(&apr_svc_ch[APR_DL_SMD][dest][clnt].dest);
 
-       dev_set_drvdata(&sdev->dev, &apr_svc_ch[APR_DL_SMD][APR_DEST_QDSP6][APR_CLIENT_AUDIO]);
+       qcom_smd_set_drvdata(sdev->channel, apr);
+
+       apr->ch = sdev->channel;
+       apr->dest_state = 1;
+       wake_up(&apr->dest);
 
        return 0;
 }
 
 static void qcom_smd_q6_remove(struct qcom_smd_device *sdev)
 {
+       struct apr_svc_ch_dev *apr = &apr_svc_ch[APR_DL_SMD][APR_DEST_QDSP6][APR_CLIENT_AUDIO];
+
+       apr->ch = NULL;
+       apr->dest_state = 0;
 }