diff options
117 files changed, 4112 insertions, 837 deletions
diff --git a/Documentation/arm/msm/msm_smp2p.txt b/Documentation/arm/msm/msm_smp2p.txt index 8332cae6be5d..34d22f0e4635 100644 --- a/Documentation/arm/msm/msm_smp2p.txt +++ b/Documentation/arm/msm/msm_smp2p.txt @@ -181,7 +181,7 @@ added to the end of the list (Table 3). ------------------------------------------------- | Wireless processor | 4 | ------------------------------------------------- - | Modem Fw | 5 | + | CDSP processor | 5 | ------------------------------------------------- | Power processor | 6 | ------------------------------------------------- @@ -206,6 +206,8 @@ Item ID will be 427 + 1 = 428. --------------------------------------------------- | Description | SMEM ID value | --------------------------------------------------- + | CDSP SMEM Item base | 94 | + --------------------------------------------------- | Apps SMP2P SMEM Item base | 427 | --------------------------------------------------- | Modem SMP2P SMEM Item base | 435 | diff --git a/Documentation/devicetree/bindings/arm/msm/sleepstate-smp2p.txt b/Documentation/devicetree/bindings/arm/msm/sleepstate-smp2p.txt index ad1067232870..adfa94f9d1ff 100644 --- a/Documentation/devicetree/bindings/arm/msm/sleepstate-smp2p.txt +++ b/Documentation/devicetree/bindings/arm/msm/sleepstate-smp2p.txt @@ -1,7 +1,9 @@ Qualcomm Technologies, Inc. SMSM Point-to-Point (SMP2P) Sleepstate driver Required properties: --compatible : should be "qcom,smp2pgpio_sleepstate_3_out"; +-compatible : should be one of the following: +- "qcom,smp2pgpio_sleepstate_3_out" - for sensor processor on remote pid 3 +- "qcom,smp2pgpio-sleepstate-out" - for other cases -gpios : the relevant gpio pins of the entry. Example: diff --git a/Documentation/devicetree/bindings/gpio/gpio-smp2p.txt b/Documentation/devicetree/bindings/gpio/gpio-smp2p.txt index c0a51afe18f1..7f5f939afa2d 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-smp2p.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-smp2p.txt @@ -31,6 +31,8 @@ Unit test devices ("smp2p" entries): "qcom,smp2pgpio_test_smp2p_3_in" "qcom,smp2pgpio_test_smp2p_4_out" "qcom,smp2pgpio_test_smp2p_4_in" + "qcom,smp2pgpio_test_smp2p_5_out" + "qcom,smp2pgpio_test_smp2p_5_in" "qcom,smp2pgpio_test_smp2p_7_out" "qcom,smp2pgpio_test_smp2p_7_in" "qcom,smp2pgpio_test_smp2p_15_out" diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt index 06b8c71effcc..92411011ed7a 100644 --- a/Documentation/devicetree/bindings/gpu/adreno.txt +++ b/Documentation/devicetree/bindings/gpu/adreno.txt @@ -152,6 +152,8 @@ GPU Quirks: - qcom,gpu-quirk-fault-detect-mask: Mask out RB1-3 activity signals from HW hang detection logic +- qcom,gpu-quirk-dp2clockgating-disable: + Disable RB sampler data path clock gating optimization The following properties are optional as collecting data via coresight might not be supported for every chipset. The documentation for coresight diff --git a/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt b/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt index 833fb645b92a..b286b0838643 100644 --- a/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/cprh-kbss-regulator.txt @@ -30,7 +30,12 @@ KBSS specific properties: - compatible Usage: required Value type: <string> - Definition: "qcom,cprh-msmcobalt-kbss-regulator". + Definition: should be one of the following: + "qcom,cprh-msmcobalt-v1-kbss-regulator", + "qcom,cprh-msmcobalt-v2-kbss-regulator", + "qcom,cprh-msmcobalt-kbss-regulator". + If the SoC revision is not specified, then it is assumed to + be the most recent revision of MSMCOBALT, i.e. v2. - qcom,cpr-controller-id Usage: required diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi index deccd14d5d85..aa973e4ee3d6 100644 --- a/arch/arm/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996.dtsi @@ -808,6 +808,7 @@ <&mdss_dsi1_pll clk_dsi1pll_byte_clk_mux>, <&mdss_hdmi_pll clk_hdmi_vco_clk>; #clock-cells = <1>; + #reset-cells = <1>; }; clock_gpu: qcom,gpucc@8c0000 { @@ -2514,6 +2515,8 @@ qcom,use-sw-aes-xts-algo; qcom,use-sw-aes-ccm-algo; qcom,use-sw-ahash-algo; + qcom,use-sw-hmac-algo; + qcom,use-sw-aead-algo; }; qcom_cedev: qcedev@660000 { diff --git a/arch/arm/boot/dts/qcom/msmcobalt-bus.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-bus.dtsi index 86decf438430..edf7e7b9cbb0 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-bus.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-bus.dtsi @@ -131,10 +131,6 @@ clock-names = "bus_clk", "bus_a_clk"; clocks = <&clock_gcc clk_mmssnoc_axi_clk>, <&clock_gcc clk_mmssnoc_axi_a_clk>; - clk-mdss-axi-no-rate-supply = - <&gdsc_mdss>; - clk-mdss-ahb-no-rate-supply = - <&gdsc_mdss>; clk-camss-ahb-no-rate-supply = <&gdsc_camss_top>; clk-video-ahb-no-rate-supply = @@ -145,8 +141,6 @@ clock-names = "clk-noc-cfg-ahb-no-rate", "clk-mnoc-ahb-no-rate", - "clk-mdss-ahb-no-rate", - "clk-mdss-axi-no-rate", "clk-camss-ahb-no-rate", "clk-video-ahb-no-rate", "clk-video-axi-no-rate"; @@ -154,8 +148,6 @@ <&clock_gcc clk_mmssnoc_axi_clk>, <&clock_gcc clk_gcc_mmss_noc_cfg_ahb_clk>, <&clock_mmss clk_mmss_mnoc_ahb_clk>, - <&clock_mmss clk_mmss_mdss_ahb_clk>, - <&clock_mmss clk_mmss_mdss_axi_clk>, <&clock_mmss clk_mmss_camss_ahb_clk>, <&clock_mmss clk_mmss_video_ahb_clk>, <&clock_mmss clk_mmss_video_axi_clk>; @@ -535,6 +527,19 @@ qcom,bus-dev = <&fab_mnoc>; qcom,vrail-comp = <25>; qcom,mas-rpm-id = <ICBID_MASTER_MDP0>; + clk-mdss-axi-no-rate-supply = + <&gdsc_mdss>; + clk-mdss-ahb-no-rate-supply = + <&gdsc_mdss>; + qcom,node-qos-clks { + clock-names = + "clk-mdss-ahb-no-rate", + "clk-mdss-axi-no-rate"; + clocks = + <&clock_mmss clk_mmss_mdss_ahb_clk>, + <&clock_mmss clk_mmss_mdss_axi_clk>; + }; + }; mas_mdp_p1: mas-mdp-p1 { diff --git a/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi index b11c68ae543e..def8ed6e07a7 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-camera.dtsi @@ -373,24 +373,24 @@ camss-vdd-supply = <&gdsc_camss_top>; vdd-supply = <&gdsc_cpp>; qcom,vdd-names = "smmu-vdd", "camss-vdd", "vdd"; - clocks = <&clock_mmss clk_mmss_mnoc_maxi_clk>, + clocks = <&clock_gcc clk_mmssnoc_axi_clk>, + <&clock_mmss clk_mmss_mnoc_maxi_clk>, <&clock_mmss clk_mmss_mnoc_ahb_clk>, <&clock_mmss clk_mmss_camss_ahb_clk>, <&clock_mmss clk_mmss_camss_top_ahb_clk>, - <&clock_mmss clk_cpp_clk_src>, + <&clock_mmss clk_mmss_camss_cpp_clk>, <&clock_mmss clk_mmss_camss_cpp_ahb_clk>, <&clock_mmss clk_mmss_camss_cpp_axi_clk>, - <&clock_mmss clk_mmss_camss_cpp_clk>, <&clock_mmss clk_mmss_camss_micro_ahb_clk>, <&clock_mmss clk_mmss_bimc_smmu_axi_clk>, <&clock_mmss clk_mmss_camss_cpp_vbif_ahb_clk>; - clock-names = "mnoc_maxi_clk", "mnoc_ahb_clk", + clock-names = "mmssnoc_axi_clk", + "mnoc_maxi_clk", "mnoc_ahb_clk", "camss_ahb_clk", "camss_top_ahb_clk", "cpp_core_clk", "camss_cpp_ahb_clk", - "camss_cpp_axi_clk", "camss_cpp_clk", - "micro_iface_clk", "mmss_smmu_axi_clk", - "cpp_vbif_ahb_clk"; - qcom,clock-rates = <0 0 0 0 200000000 0 0 200000000 0 0 0>; + "camss_cpp_axi_clk", "micro_iface_clk", + "mmss_smmu_axi_clk", "cpp_vbif_ahb_clk"; + qcom,clock-rates = <0 0 0 0 0 200000000 0 0 0 0 0>; qcom,min-clock-rate = <200000000>; qcom,bus-master = <1>; qcom,vbif-qos-setting = <0x20 0x10000000>, diff --git a/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi index 24e23d00d697..c0f465b0eba5 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi @@ -1778,5 +1778,942 @@ bias-pull-up; }; }; + + pri_aux_pcm_clk { + pri_aux_pcm_clk_sleep: pri_aux_pcm_clk_sleep { + mux { + pins = "gpio65"; + function = "gpio"; + }; + + config { + pins = "gpio65"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_aux_pcm_clk_active: pri_aux_pcm_clk_active { + mux { + pins = "gpio65"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio65"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + pri_aux_pcm_sync { + pri_aux_pcm_sync_sleep: pri_aux_pcm_sync_sleep { + mux { + pins = "gpio66"; + function = "gpio"; + }; + + config { + pins = "gpio66"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_aux_pcm_sync_active: pri_aux_pcm_sync_active { + mux { + pins = "gpio66"; + function = "pri_mi2s_ws"; + }; + + config { + pins = "gpio66"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + pri_aux_pcm_din { + pri_aux_pcm_din_sleep: pri_aux_pcm_din_sleep { + mux { + pins = "gpio67"; + function = "gpio"; + }; + + config { + pins = "gpio67"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_aux_pcm_din_active: pri_aux_pcm_din_active { + mux { + pins = "gpio67"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio67"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + pri_aux_pcm_dout { + pri_aux_pcm_dout_sleep: pri_aux_pcm_dout_sleep { + mux { + pins = "gpio68"; + function = "gpio"; + }; + + config { + pins = "gpio68"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_aux_pcm_dout_active: pri_aux_pcm_dout_active { + mux { + pins = "gpio68"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio68"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + sec_aux_pcm { + sec_aux_pcm_sleep: sec_aux_pcm_sleep { + mux { + pins = "gpio80", "gpio81"; + function = "gpio"; + }; + + config { + pins = "gpio80", "gpio81"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_aux_pcm_active: sec_aux_pcm_active { + mux { + pins = "gpio80", "gpio81"; + function = "sec_mi2s"; + }; + + config { + pins = "gpio80", "gpio81"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + sec_aux_pcm_din { + sec_aux_pcm_din_sleep: sec_aux_pcm_din_sleep { + mux { + pins = "gpio82"; + function = "gpio"; + }; + + config { + pins = "gpio82"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_aux_pcm_din_active: sec_aux_pcm_din_active { + mux { + pins = "gpio82"; + function = "sec_mi2s"; + }; + + config { + pins = "gpio82"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + sec_aux_pcm_dout { + sec_aux_pcm_dout_sleep: sec_aux_pcm_dout_sleep { + mux { + pins = "gpio83"; + function = "gpio"; + }; + + config { + pins = "gpio83"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_aux_pcm_dout_active: sec_aux_pcm_dout_active { + mux { + pins = "gpio83"; + function = "sec_mi2s"; + }; + + config { + pins = "gpio83"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + tert_aux_pcm { + tert_aux_pcm_sleep: tert_aux_pcm_sleep { + mux { + pins = "gpio75", "gpio76"; + function = "gpio"; + }; + + config { + pins = "gpio75", "gpio76"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_aux_pcm_active: tert_aux_pcm_active { + mux { + pins = "gpio75", "gpio76"; + function = "ter_mi2s"; + }; + + config { + pins = "gpio75", "gpio76"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + tert_aux_pcm_din { + tert_aux_pcm_din_sleep: tert_aux_pcm_din_sleep { + mux { + pins = "gpio77"; + function = "gpio"; + }; + + config { + pins = "gpio77"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_aux_pcm_din_active: tert_aux_pcm_din_active { + mux { + pins = "gpio77"; + function = "ter_mi2s"; + }; + + config { + pins = "gpio77"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + tert_aux_pcm_dout { + tert_aux_pcm_dout_sleep: tert_aux_pcm_dout_sleep { + mux { + pins = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_aux_pcm_dout_active: tert_aux_pcm_dout_active { + mux { + pins = "gpio78"; + function = "ter_mi2s"; + }; + + config { + pins = "gpio78"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + quat_aux_pcm { + quat_aux_pcm_sleep: quat_aux_pcm_sleep { + mux { + pins = "gpio58", "gpio59"; + function = "gpio"; + }; + + config { + pins = "gpio58", "gpio59"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_pcm_active: quat_aux_pcm_active { + mux { + pins = "gpio58", "gpio59"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio58", "gpio59"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_pcm_din { + quat_aux_pcm_din_sleep: quat_aux_pcm_din_sleep { + mux { + pins = "gpio60"; + function = "gpio"; + }; + + config { + pins = "gpio60"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_pcm_din_active: quat_aux_pcm_din_active { + mux { + pins = "gpio60"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio60"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + quat_aux_pcm_dout { + quat_aux_pcm_dout_sleep: quat_aux_pcm_dout_sleep { + mux { + pins = "gpio61"; + function = "gpio"; + }; + + config { + pins = "gpio61"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_pcm_dout_active: quat_aux_pcm_dout_active { + mux { + pins = "gpio61"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio61"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + pri_mi2s_mclk { + pri_mi2s_mclk_sleep: pri_mi2s_mclk_sleep { + mux { + pins = "gpio64"; + function = "gpio"; + }; + + config { + pins = "gpio64"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_mi2s_mclk_active: pri_mi2s_mclk_active { + mux { + pins = "gpio64"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio64"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + pri_mi2s_sck { + pri_mi2s_sck_sleep: pri_mi2s_sck_sleep { + mux { + pins = "gpio65"; + function = "gpio"; + }; + + config { + pins = "gpio65"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_mi2s_sck_active: pri_mi2s_sck_active { + mux { + pins = "gpio65"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio65"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + pri_mi2s_ws { + pri_mi2s_ws_sleep: pri_mi2s_ws_sleep { + mux { + pins = "gpio66"; + function = "gpio"; + }; + + config { + pins = "gpio66"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_mi2s_ws_active: pri_mi2s_ws_active { + mux { + pins = "gpio66"; + function = "pri_mi2s_ws"; + }; + + config { + pins = "gpio66"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + pri_mi2s_sd0 { + pri_mi2s_sd0_sleep: pri_mi2s_sd0_sleep { + mux { + pins = "gpio67"; + function = "gpio"; + }; + + config { + pins = "gpio67"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_mi2s_sd0_active: pri_mi2s_sd0_active { + mux { + pins = "gpio67"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio67"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + pri_mi2s_sd1 { + pri_mi2s_sd1_sleep: pri_mi2s_sd1_sleep { + mux { + pins = "gpio68"; + function = "gpio"; + }; + + config { + pins = "gpio68"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_mi2s_sd1_active: pri_mi2s_sd1_active { + mux { + pins = "gpio68"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio68"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + sec_mi2s_mclk { + sec_mi2s_mclk_sleep: sec_mi2s_mclk_sleep { + mux { + pins = "gpio79"; + function = "gpio"; + }; + + config { + pins = "gpio79"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_mi2s_mclk_active: sec_mi2s_mclk_active { + mux { + pins = "gpio79"; + function = "sec_mi2s"; + }; + + config { + pins = "gpio79"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + sec_mi2s { + sec_mi2s_sleep: sec_mi2s_sleep { + mux { + pins = "gpio80", "gpio81"; + function = "gpio"; + }; + + config { + pins = "gpio80", "gpio81"; + drive-strength = <2>; /* 2 mA */ + bias-disable; /* NO PULL */ + input-enable; + }; + }; + + sec_mi2s_active: sec_mi2s_active { + mux { + pins = "gpio80", "gpio81"; + function = "sec_mi2s"; + }; + + config { + pins = "gpio80", "gpio81"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + sec_mi2s_sd0 { + sec_mi2s_sd0_sleep: sec_mi2s_sd0_sleep { + mux { + pins = "gpio82"; + function = "gpio"; + }; + + config { + pins = "gpio82"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_mi2s_sd0_active: sec_mi2s_sd0_active { + mux { + pins = "gpio82"; + function = "sec_mi2s"; + }; + + config { + pins = "gpio82"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + sec_mi2s_sd1 { + sec_mi2s_sd1_sleep: sec_mi2s_sd1_sleep { + mux { + pins = "gpio83"; + function = "gpio"; + }; + + config { + pins = "gpio83"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_mi2s_sd1_active: sec_mi2s_sd1_active { + mux { + pins = "gpio83"; + function = "sec_mi2s"; + }; + + config { + pins = "gpio83"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + tert_mi2s_mclk { + tert_mi2s_mclk_sleep: tert_mi2s_mclk_sleep { + mux { + pins = "gpio74"; + function = "gpio"; + }; + + config { + pins = "gpio74"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_mi2s_mclk_active: tert_mi2s_mclk_active { + mux { + pins = "gpio74"; + function = "ter_mi2s"; + }; + + config { + pins = "gpio74"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + tert_mi2s { + tert_mi2s_sleep: tert_mi2s_sleep { + mux { + pins = "gpio75", "gpio76"; + function = "gpio"; + }; + + config { + pins = "gpio75", "gpio76"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_mi2s_active: tert_mi2s_active { + mux { + pins = "gpio75", "gpio76"; + function = "ter_mi2s"; + }; + + config { + pins = "gpio75", "gpio76"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + tert_mi2s_sd0 { + tert_mi2s_sd0_sleep: tert_mi2s_sd0_sleep { + mux { + pins = "gpio77"; + function = "gpio"; + }; + + config { + pins = "gpio77"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_mi2s_sd0_active: tert_mi2s_sd0_active { + mux { + pins = "gpio77"; + function = "ter_mi2s"; + }; + + config { + pins = "gpio77"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + tert_mi2s_sd1 { + tert_mi2s_sd1_sleep: tert_mi2s_sd1_sleep { + mux { + pins = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_mi2s_sd1_active: tert_mi2s_sd1_active { + mux { + pins = "gpio78"; + function = "ter_mi2s"; + }; + + config { + pins = "gpio78"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + quat_mi2s_mclk { + quat_mi2s_mclk_sleep: quat_mi2s_mclk_sleep { + mux { + pins = "gpio57"; + function = "gpio"; + }; + + config { + pins = "gpio57"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_mclk_active: quat_mi2s_mclk_active { + mux { + pins = "gpio57"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio57"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + quat_mi2s { + quat_mi2s_sleep: quat_mi2s_sleep { + mux { + pins = "gpio58", "gpio59"; + function = "gpio"; + }; + + config { + pins = "gpio58", "gpio59"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_active: quat_mi2s_active { + mux { + pins = "gpio58", "gpio59"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio58", "gpio59"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_sd0 { + quat_mi2s_sd0_sleep: quat_mi2s_sd0_sleep { + mux { + pins = "gpio60"; + function = "gpio"; + }; + + config { + pins = "gpio60"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd0_active: quat_mi2s_sd0_active { + mux { + pins = "gpio60"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio60"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + quat_mi2s_sd1 { + quat_mi2s_sd1_sleep: quat_mi2s_sd1_sleep { + mux { + pins = "gpio61"; + function = "gpio"; + }; + + config { + pins = "gpio61"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd1_active: quat_mi2s_sd1_active { + mux { + pins = "gpio61"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio61"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + quat_mi2s_sd2 { + quat_mi2s_sd2_sleep: quat_mi2s_sd2_sleep { + mux { + pins = "gpio62"; + function = "gpio"; + }; + + config { + pins = "gpio62"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd2_active: quat_mi2s_sd2_active { + mux { + pins = "gpio62"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio62"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + quat_mi2s_sd3 { + quat_mi2s_sd3_sleep: quat_mi2s_sd3_sleep { + mux { + pins = "gpio63"; + function = "gpio"; + }; + + config { + pins = "gpio63"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd3_active: quat_mi2s_sd3_active { + mux { + pins = "gpio63"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio63"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; }; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi index 9f8ecea15568..eaf8f0d6240a 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi @@ -555,7 +555,7 @@ &soc { /* CPR controller regulators */ apc0_cpr: cprh-ctrl@179c8000 { - compatible = "qcom,cprh-msmcobalt-kbss-regulator"; + compatible = "qcom,cprh-msmcobalt-v1-kbss-regulator"; reg = <0x179c8000 0x4000>, <0x00784000 0x1000>; reg-names = "cpr_ctrl", "fuse_base"; clocks = <&clock_gcc clk_gcc_hmss_rbcpr_clk>; @@ -717,7 +717,7 @@ }; apc1_cpr: cprh-ctrl@179c4000{ - compatible = "qcom,cprh-msmcobalt-kbss-regulator"; + compatible = "qcom,cprh-msmcobalt-v1-kbss-regulator"; reg = <0x179c4000 0x4000>, <0x00784000 0x1000>; reg-names = "cpr_ctrl", "fuse_base"; clocks = <&clock_gcc clk_gcc_hmss_rbcpr_clk>; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi index b484b94692b5..c909c23774b5 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi @@ -23,6 +23,132 @@ qcom,msm-id = <292 0x20000>; }; +&clock_cpu { + qcom,pwrcl-speedbin0-v0 = + < 300000000 0x0004000f 0x01200020 0x1 >, + < 364800000 0x05040013 0x01200020 0x1 >, + < 441600000 0x05040017 0x02200020 0x1 >, + < 518400000 0x0504001b 0x02200020 0x1 >, + < 595200000 0x0504001f 0x02200020 0x1 >, + < 672000000 0x05040023 0x03200020 0x1 >, + < 748800000 0x05040027 0x03200020 0x1 >, + < 825600000 0x0404002b 0x03220022 0x1 >, + < 883200000 0x0404002e 0x04250025 0x1 >, + < 960000000 0x04040032 0x04280028 0x1 >, + < 1036800000 0x04040036 0x042b002b 0x1 >, + < 1094400000 0x04040039 0x052e002e 0x2 >, + < 1171200000 0x0404003d 0x05310031 0x2 >, + < 1248000000 0x04040041 0x05340034 0x2 >, + < 1324800000 0x04040045 0x06370037 0x2 >, + < 1401600000 0x04040049 0x063a003a 0x2 >, + < 1478400000 0x0404004d 0x073e003e 0x2 >, + < 1555200000 0x04040051 0x07410041 0x2 >, + < 1670400000 0x04040057 0x08460046 0x2 >, + < 1747200000 0x0404005b 0x08490049 0x2 >, + < 1824000000 0x0404005f 0x084c004c 0x3 >, + < 1900800000 0x04040063 0x094f004f 0x3 >; + + qcom,perfcl-speedbin0-v0 = + < 300000000 0x0004000f 0x01200020 0x1 >, + < 345600000 0x05040012 0x01200020 0x1 >, + < 422400000 0x05040016 0x02200020 0x1 >, + < 499200000 0x0504001a 0x02200020 0x1 >, + < 576000000 0x0504001e 0x02200020 0x1 >, + < 652800000 0x05040022 0x03200020 0x1 >, + < 729600000 0x05040026 0x03200020 0x1 >, + < 806400000 0x0504002a 0x03220022 0x1 >, + < 902400000 0x0404002f 0x04260026 0x1 >, + < 979200000 0x04040033 0x04290029 0x1 >, + < 1056000000 0x04040037 0x052c002c 0x1 >, + < 1132800000 0x0404003b 0x052f002f 0x1 >, + < 1190400000 0x0404003e 0x05320032 0x2 >, + < 1267200000 0x04040042 0x06350035 0x2 >, + < 1344000000 0x04040046 0x06380038 0x2 >, + < 1420800000 0x0404004a 0x063b003b 0x2 >, + < 1497600000 0x0404004e 0x073e003e 0x2 >, + < 1574400000 0x04040052 0x07420042 0x2 >, + < 1651200000 0x04040056 0x07450045 0x2 >, + < 1728000000 0x0404005a 0x08480048 0x2 >, + < 1804800000 0x0404005e 0x084b004b 0x2 >, + < 1881600000 0x04040062 0x094e004e 0x2 >, + < 1958400000 0x04040066 0x09520052 0x2 >, + < 2035200000 0x0404006a 0x09550055 0x3 >, + < 2112000000 0x0404006e 0x0a580058 0x3 >, + < 2188800000 0x04040072 0x0a5b005b 0x3 >, + < 2265600000 0x04040076 0x0a5e005e 0x3 >, + < 2342400000 0x0404007a 0x0a620062 0x3 >, + < 2419200000 0x0404007e 0x0a650065 0x3 >, + < 2496000000 0x04040082 0x0a680068 0x3 >; +}; + +&msm_cpufreq { + qcom,cpufreq-table-0 = + < 300000 >, + < 364800 >, + < 441600 >, + < 518400 >, + < 595200 >, + < 672000 >, + < 748800 >, + < 825600 >, + < 883200 >, + < 960000 >, + < 1036800 >, + < 1094400 >, + < 1171200 >, + < 1248000 >, + < 1324800 >, + < 1401600 >, + < 1478400 >, + < 1555200 >, + < 1670400 >, + < 1747200 >, + < 1824000 >, + < 1900800 >; + + qcom,cpufreq-table-4 = + < 300000 >, + < 345600 >, + < 422400 >, + < 499200 >, + < 576000 >, + < 652800 >, + < 729600 >, + < 806400 >, + < 902400 >, + < 979200 >, + < 1056000 >, + < 1132800 >, + < 1190400 >, + < 1267200 >, + < 1344000 >, + < 1420800 >, + < 1497600 >, + < 1574400 >, + < 1651200 >, + < 1728000 >, + < 1804800 >, + < 1881600 >, + < 1958400 >, + < 2035200 >, + < 2112000 >, + < 2188800 >, + < 2265600 >, + < 2342400 >, + < 2419200 >, + < 2496000 >; +}; + +&devfreq_cpufreq { + mincpubw-cpufreq { + cpu-to-dev-map-0 = + < 1900800 1525 >; + cpu-to-dev-map-4 = + < 2419200 1525 >, + < 2496000 5195 >; + }; +}; + &clock_gcc { compatible = "qcom,gcc-cobalt-v2"; }; @@ -39,21 +165,21 @@ compatible = "qcom,gfxcc-cobalt-v2"; qcom,gfxfreq-speedbin0 = < 0 0 0 >, - < 189000000 1 RPM_SMD_REGULATOR_LEVEL_SVS >, - < 264000000 2 RPM_SMD_REGULATOR_LEVEL_SVS >, + < 180000000 1 RPM_SMD_REGULATOR_LEVEL_SVS >, + < 257000000 2 RPM_SMD_REGULATOR_LEVEL_SVS >, < 342000000 3 RPM_SMD_REGULATOR_LEVEL_SVS >, < 414000000 4 RPM_SMD_REGULATOR_LEVEL_SVS >, - < 520000000 5 RPM_SMD_REGULATOR_LEVEL_NOM >, + < 515000000 5 RPM_SMD_REGULATOR_LEVEL_NOM >, < 596000000 6 RPM_SMD_REGULATOR_LEVEL_NOM >, < 670000000 7 RPM_SMD_REGULATOR_LEVEL_TURBO >, < 710000000 8 RPM_SMD_REGULATOR_LEVEL_TURBO >; qcom,gfxfreq-mx-speedbin0 = < 0 0 >, - < 189000000 RPM_SMD_REGULATOR_LEVEL_SVS >, - < 264000000 RPM_SMD_REGULATOR_LEVEL_SVS >, + < 180000000 RPM_SMD_REGULATOR_LEVEL_SVS >, + < 257000000 RPM_SMD_REGULATOR_LEVEL_SVS >, < 342000000 RPM_SMD_REGULATOR_LEVEL_SVS >, < 414000000 RPM_SMD_REGULATOR_LEVEL_SVS >, - < 520000000 RPM_SMD_REGULATOR_LEVEL_NOM >, + < 515000000 RPM_SMD_REGULATOR_LEVEL_NOM >, < 596000000 RPM_SMD_REGULATOR_LEVEL_NOM >, < 670000000 RPM_SMD_REGULATOR_LEVEL_TURBO >, < 710000000 RPM_SMD_REGULATOR_LEVEL_TURBO >; @@ -65,3 +191,180 @@ qcom,max-bandwidth-high-kbps = <9400000>; qcom,max-bandwidth-per-pipe-kbps = <4700000>; }; + +&apc0_cpr { + compatible = "qcom,cprh-msmcobalt-v2-kbss-regulator"; +}; + +&apc0_pwrcl_vreg { + regulator-max-microvolt = <23>; + qcom,cpr-corners = <22>; + qcom,cpr-corner-fmax-map = <8 11 18 22>; + + qcom,cpr-voltage-ceiling = + <688000 688000 688000 688000 688000 + 688000 688000 688000 756000 756000 + 756000 828000 828000 828000 828000 + 828000 828000 828000 952000 952000 + 1024000 1024000>; + + qcom,cpr-voltage-floor = + <568000 568000 568000 568000 568000 + 568000 568000 568000 568000 568000 + 568000 632000 632000 632000 632000 + 632000 632000 632000 712000 712000 + 756000 756000>; + + qcom,cpr-floor-to-ceiling-max-range = + <55000 55000 55000 55000 + 55000 55000 55000 55000 + 55000 55000 55000 65000 + 65000 65000 65000 65000 + 65000 65000 65000 65000 + 65000 65000>; + + qcom,corner-frequencies = + <300000000 364800000 441600000 + 518400000 595200000 672000000 + 748800000 825600000 883200000 + 960000000 1036800000 1094400000 + 1171200000 1248000000 1324800000 + 1401600000 1478400000 1555200000 + 1670400000 1747200000 1824000000 + 1900800000>; + + qcom,cpr-ro-scaling-factor = + <4001 4019 3747 3758 3564 3480 2336 + 2247 3442 3147 2136 4156 4028 3030 + 3727 3198>, + <4001 4019 3747 3758 3564 3480 2336 + 2247 3442 3147 2136 4156 4028 3030 + 3727 3198>, + <3704 3601 3465 3567 3356 3473 2686 + 2773 3049 2932 2235 3816 3800 3097 + 2966 2808>, + <2974 3092 3288 3329 2905 3096 3119 + 3225 2865 3140 2892 3592 3408 3576 + 1559 1392>; + + qcom,cpr-open-loop-voltage-fuse-adjustment = + <40000 24000 0 0>, + <40000 24000 0 0>, + <40000 24000 0 0>, + <40000 24000 0 0>, + <40000 24000 0 0>, + <40000 24000 0 0>, + <40000 24000 0 0>, + <40000 24000 0 0>; + + qcom,cpr-closed-loop-voltage-fuse-adjustment = + <20000 26000 0 0>, + <20000 26000 0 0>, + <20000 26000 0 0>, + <20000 26000 0 0>, + <20000 26000 0 0>, + <20000 26000 0 0>, + <20000 26000 0 0>, + <20000 26000 0 0>; + + qcom,allow-voltage-interpolation; + qcom,allow-quotient-interpolation; + qcom,cpr-scaled-open-loop-voltage-as-ceiling; +}; + +&apc1_cpr { + compatible = "qcom,cprh-msmcobalt-v2-kbss-regulator"; +}; + +&apc1_perfcl_vreg { + regulator-max-microvolt = <31>; + qcom,cpr-corners = <30>; + qcom,cpr-corner-fmax-map = <8 12 20 30>; + + qcom,cpr-voltage-ceiling = + <688000 688000 688000 688000 688000 + 688000 688000 688000 756000 756000 + 756000 756000 828000 828000 828000 + 828000 828000 828000 828000 828000 + 952000 952000 952000 1024000 1024000 + 1024000 1024000 1024000 1024000 1024000>; + + qcom,cpr-voltage-floor = + <568000 568000 568000 568000 568000 + 568000 568000 568000 568000 568000 + 568000 568000 632000 632000 632000 + 632000 632000 632000 632000 632000 + 712000 712000 712000 756000 756000 + 756000 756000 756000 756000 756000>; + + qcom,cpr-floor-to-ceiling-max-range = + <55000 55000 55000 55000 + 55000 55000 55000 55000 + 55000 55000 55000 55000 + 65000 65000 65000 65000 + 65000 65000 65000 65000 + 65000 65000 65000 65000 + 65000 65000 65000 65000 + 65000 65000>; + + qcom,corner-frequencies = + <300000000 345600000 422400000 + 499200000 576000000 652800000 + 729600000 806400000 902400000 + 979200000 1056000000 1132800000 + 1190400000 1267200000 1344000000 + 1420800000 1497600000 1574400000 + 1651200000 1728000000 1804800000 + 1881600000 1958400000 2035200000 + 2112000000 2188800000 2265600000 + 2342400000 2419200000 2496000000>; + + qcom,cpr-ro-scaling-factor = + <4001 4019 3747 3758 3564 3480 2336 + 2247 3442 3147 2136 4156 4028 3030 + 3727 3190>, + <4001 4019 3747 3758 3564 3480 2336 + 2247 3442 3147 2136 4156 4028 3030 + 3727 3198>, + <3704 3601 3465 3567 3356 3473 2686 + 2773 3049 2932 2235 3816 3800 3097 + 2966 2808>, + <2974 3092 3288 3329 2905 3096 3119 + 3225 2865 3140 2892 3592 3408 3576 + 1559 1392>; + + qcom,cpr-open-loop-voltage-fuse-adjustment = + <8000 0 0 52000>, + <8000 0 0 52000>, + <8000 0 0 52000>, + <8000 0 0 52000>, + <8000 0 0 52000>, + <8000 0 0 52000>, + <8000 0 0 52000>, + <8000 0 0 52000>; + + qcom,cpr-closed-loop-voltage-fuse-adjustment = + <0 0 0 50000>, + <0 0 0 50000>, + <0 0 0 50000>, + <0 0 0 50000>, + <0 0 0 50000>, + <0 0 0 50000>, + <0 0 0 50000>, + <0 0 0 50000>; + + qcom,allow-voltage-interpolation; + qcom,allow-quotient-interpolation; + qcom,cpr-scaled-open-loop-voltage-as-ceiling; +}; + +&qusb_phy0 { + qcom,qusb-phy-init-seq = + /* <value reg_offset> */ + <0x13 0x04 + 0x7c 0x18c + 0x80 0x2c + 0x0a 0x184 + 0x00 0x240 + 0x19 0xb4>; +}; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-vidc.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-vidc.dtsi index 0860139248d1..637698ff759a 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-vidc.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-vidc.dtsi @@ -33,7 +33,8 @@ <0x80568 0x01111111>, <0x80570 0x01111111>, <0x80580 0x01111111>, - <0x80588 0x01111111>; + <0x80588 0x01111111>, + <0xe2010 0x00000000>; qcom,imem-size = <524288>; /* 512 kB */ qcom,max-hw-load = <2563200>; /* Full 4k @ 60 + 1080p @ 60 */ @@ -96,7 +97,7 @@ <&clock_mmss clk_mmss_video_subcore0_clk>, <&clock_mmss clk_mmss_video_subcore1_clk>; qcom,clock-configs = <0x0 0x0 0x0 0x0 0x0 0x0 - 0x1 0x0 0x0 0x0 0x1 0x1>; + 0x3 0x0 0x2 0x2 0x3 0x3>; /* Buses */ bus_cnoc { @@ -233,6 +234,7 @@ <&clock_mmss clk_mmss_vmem_maxi_clk>; clock-names = "mnoc_ahb","mnoc_maxi", "ahb", "maxi"; + clock-config = <0x0 0x0 0x0 0x1>; qcom,msm-bus,name = "vmem"; qcom,msm-bus,num-cases = <2>; diff --git a/arch/arm/boot/dts/qcom/msmcobalt.dtsi b/arch/arm/boot/dts/qcom/msmcobalt.dtsi index 0e2cc7361e1b..683110415d5e 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt.dtsi @@ -2757,13 +2757,15 @@ qcom,icnss@18800000 { compatible = "qcom,icnss"; reg = <0x18800000 0x800000>, - <0x10AC000 0x20>; - reg-names = "membase", "mpm_config"; + <0x10AC000 0x20>, + <0xa0000000 0x10000000>, + <0xb0000000 0x10000>; + reg-names = "membase", "mpm_config", + "smmu_iova_base", "smmu_iova_ipa"; clocks = <&clock_gcc clk_aggre2_noc_clk>; clock-names = "smmu_aggre2_noc_clk"; iommus = <&anoc2_smmu 0x1900>, <&anoc2_smmu 0x1901>; - qcom,wlan-smmu-iova-address = <0xa0000000 0x10000000>; interrupts = <0 413 0 /* CE0 */ >, <0 414 0 /* CE1 */ >, <0 415 0 /* CE2 */ >, diff --git a/arch/arm/boot/dts/qcom/msmfalcon-smp2p.dtsi b/arch/arm/boot/dts/qcom/msmfalcon-smp2p.dtsi new file mode 100644 index 000000000000..bdbcd9d7b6f9 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msmfalcon-smp2p.dtsi @@ -0,0 +1,175 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +&soc { + qcom,smp2p-modem@17911008 { + compatible = "qcom,smp2p"; + reg = <0x17911008 0x4>; + qcom,remote-pid = <1>; + qcom,irq-bitmask = <0x4000>; + interrupts = <0 451 1>; + }; + + qcom,smp2p-adsp@17911008 { + compatible = "qcom,smp2p"; + reg = <0x17911008 0x4>; + qcom,remote-pid = <2>; + qcom,irq-bitmask = <0x400>; + interrupts = <0 158 1>; + }; + + qcom,smp2p-cdsp@17911008 { + compatible = "qcom,smp2p"; + reg = <0x17911008 0x4>; + qcom,remote-pid = <5>; + qcom,irq-bitmask = <0x40000000>; + interrupts = <0 514 1>; + }; + + smp2pgpio_smp2p_15_in: qcom,smp2pgpio-smp2p-15-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <15>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_15_in { + compatible = "qcom,smp2pgpio_test_smp2p_15_in"; + gpios = <&smp2pgpio_smp2p_15_in 0 0>; + }; + + smp2pgpio_smp2p_15_out: qcom,smp2pgpio-smp2p-15-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <15>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_15_out { + compatible = "qcom,smp2pgpio_test_smp2p_15_out"; + gpios = <&smp2pgpio_smp2p_15_out 0 0>; + }; + + smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <1>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_1_in { + compatible = "qcom,smp2pgpio_test_smp2p_1_in"; + gpios = <&smp2pgpio_smp2p_1_in 0 0>; + }; + + smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <1>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_1_out { + compatible = "qcom,smp2pgpio_test_smp2p_1_out"; + gpios = <&smp2pgpio_smp2p_1_out 0 0>; + }; + + smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <2>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_2_in { + compatible = "qcom,smp2pgpio_test_smp2p_2_in"; + gpios = <&smp2pgpio_smp2p_2_in 0 0>; + }; + + smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <2>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_2_out { + compatible = "qcom,smp2pgpio_test_smp2p_2_out"; + gpios = <&smp2pgpio_smp2p_2_out 0 0>; + }; + + smp2pgpio_sleepstate_2_out: qcom,smp2pgpio-sleepstate-gpio-2-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "sleepstate"; + qcom,remote-pid = <2>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio-sleepstate-2-out { + compatible = "qcom,smp2pgpio-sleepstate-out"; + gpios = <&smp2pgpio_sleepstate_2_out 0 0>; + }; + + smp2pgpio_smp2p_5_in: qcom,smp2pgpio-smp2p-5-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <5>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_5_in { + compatible = "qcom,smp2pgpio_test_smp2p_5_in"; + gpios = <&smp2pgpio_smp2p_5_in 0 0>; + }; + + smp2pgpio_smp2p_5_out: qcom,smp2pgpio-smp2p-5-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <5>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_5_out { + compatible = "qcom,smp2pgpio_test_smp2p_5_out"; + gpios = <&smp2pgpio_smp2p_5_out 0 0>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi index 4b3ebd3d1636..e46041cdd501 100644 --- a/arch/arm/boot/dts/qcom/msmfalcon.dtsi +++ b/arch/arm/boot/dts/qcom/msmfalcon.dtsi @@ -30,6 +30,11 @@ stdout-path = "serial0"; }; + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + cpus { #address-cells = <2>; #size-cells = <0>; @@ -194,6 +199,7 @@ }; }; +#include "msmfalcon-smp2p.dtsi" &soc { #address-cells = <1>; #size-cells = <1>; diff --git a/arch/arm/boot/dts/qcom/msmhamster.dtsi b/arch/arm/boot/dts/qcom/msmhamster.dtsi index e87cf7c153ea..4669fa519f5d 100644 --- a/arch/arm/boot/dts/qcom/msmhamster.dtsi +++ b/arch/arm/boot/dts/qcom/msmhamster.dtsi @@ -39,24 +39,24 @@ compatible = "qcom,gfxcc-hamster"; qcom,gfxfreq-speedbin0 = < 0 0 0 >, - < 185000000 1 RPM_SMD_REGULATOR_LEVEL_SVS >, - < 285000000 2 RPM_SMD_REGULATOR_LEVEL_SVS >, + < 180000000 1 RPM_SMD_REGULATOR_LEVEL_SVS >, + < 265000000 2 RPM_SMD_REGULATOR_LEVEL_SVS >, < 358000000 3 RPM_SMD_REGULATOR_LEVEL_SVS >, < 434000000 4 RPM_SMD_REGULATOR_LEVEL_SVS >, < 542000000 5 RPM_SMD_REGULATOR_LEVEL_NOM >, < 630000000 6 RPM_SMD_REGULATOR_LEVEL_NOM >, - < 670000000 7 RPM_SMD_REGULATOR_LEVEL_TURBO >, - < 710000000 8 RPM_SMD_REGULATOR_LEVEL_TURBO >; + < 700000000 7 RPM_SMD_REGULATOR_LEVEL_TURBO >, + < 750000000 8 RPM_SMD_REGULATOR_LEVEL_TURBO >; qcom,gfxfreq-mx-speedbin0 = < 0 0 >, - < 185000000 RPM_SMD_REGULATOR_LEVEL_SVS >, - < 285000000 RPM_SMD_REGULATOR_LEVEL_SVS >, + < 180000000 RPM_SMD_REGULATOR_LEVEL_SVS >, + < 265000000 RPM_SMD_REGULATOR_LEVEL_SVS >, < 358000000 RPM_SMD_REGULATOR_LEVEL_SVS >, < 434000000 RPM_SMD_REGULATOR_LEVEL_SVS >, < 542000000 RPM_SMD_REGULATOR_LEVEL_NOM >, < 630000000 RPM_SMD_REGULATOR_LEVEL_NOM >, - < 670000000 RPM_SMD_REGULATOR_LEVEL_TURBO >, - < 710000000 RPM_SMD_REGULATOR_LEVEL_TURBO >; + < 700000000 RPM_SMD_REGULATOR_LEVEL_TURBO >, + < 750000000 RPM_SMD_REGULATOR_LEVEL_TURBO >; }; &tsens0 { diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index d41957eae6ef..f5dab4e9fb4b 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -2078,7 +2078,7 @@ arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, u64 size) mapping->nr_bitmaps = 1; mapping->extensions = extensions; mapping->base = base; - mapping->bits = BITS_PER_BYTE * bitmap_size; + mapping->bits = bits; spin_lock_init(&mapping->lock); diff --git a/arch/arm64/configs/msm_defconfig b/arch/arm64/configs/msm_defconfig index 3f987b5372c5..f4b10dcd45cb 100644 --- a/arch/arm64/configs/msm_defconfig +++ b/arch/arm64/configs/msm_defconfig @@ -475,6 +475,7 @@ CONFIG_RMNET_IPA=y CONFIG_GSI=y CONFIG_IPA3=y CONFIG_RMNET_IPA3=y +CONFIG_IPA_UT=y CONFIG_GPIO_USB_DETECT=y CONFIG_MSM_MHI=y CONFIG_MSM_MHI_UCI=y diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig index 1f9740b86e43..05f5892831d7 100644 --- a/arch/arm64/configs/msmcortex-perf_defconfig +++ b/arch/arm64/configs/msmcortex-perf_defconfig @@ -537,6 +537,7 @@ CONFIG_IIO=y CONFIG_QCOM_RRADC=y CONFIG_PWM=y CONFIG_PWM_QPNP=y +CONFIG_ARM_GIC_V3_ACL=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y CONFIG_SENSORS_SSC=y diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig index ba867a7573e6..d14e49cb5021 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -621,7 +621,8 @@ CONFIG_IPC_LOGGING=y CONFIG_QCOM_RTB=y CONFIG_QCOM_RTB_SEPARATE_CPUS=y CONFIG_FUNCTION_TRACER=y -CONFIG_TRACER_SNAPSHOT=y +CONFIG_IRQSOFF_TRACER=y +CONFIG_PREEMPT_TRACER=y CONFIG_BLK_DEV_IO_TRACE=y CONFIG_CPU_FREQ_SWITCH_PROFILER=y CONFIG_MEMTEST=y diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 06f9ffccd562..196c73e2cf9c 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -2064,7 +2064,7 @@ arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size) goto err2; mapping->base = base; - mapping->bits = BITS_PER_BYTE * bitmap_size; + mapping->bits = bits; spin_lock_init(&mapping->lock); mapping->domain = iommu_domain_alloc(bus); diff --git a/drivers/base/regmap/regmap-swr.c b/drivers/base/regmap/regmap-swr.c index 5ea67421ed85..027cbfc505ab 100644 --- a/drivers/base/regmap/regmap-swr.c +++ b/drivers/base/regmap/regmap-swr.c @@ -23,15 +23,15 @@ static int regmap_swr_gather_write(void *context, const void *reg, size_t reg_size, - const void *val, size_t val_size) + const void *val, size_t val_len) { struct device *dev = context; struct swr_device *swr = to_swr_device(dev); struct regmap *map = dev_get_regmap(dev, NULL); size_t addr_bytes = map->format.reg_bytes; - int ret = 0; - int i; - u32 reg_addr = 0; + size_t val_bytes; + int i, ret = 0; + u16 reg_addr = 0; if (swr == NULL) { dev_err(dev, "%s: swr device is NULL\n", __func__); @@ -43,12 +43,15 @@ static int regmap_swr_gather_write(void *context, return -EINVAL; } reg_addr = *(u16 *)reg; - for (i = 0; i < val_size; i++) { - ret = swr_write(swr, swr->dev_num, (reg_addr+i), - (u32 *)(val+i)); + val_bytes = map->format.val_bytes; + /* val_len = val_bytes * val_count */ + for (i = 0; i < (val_len / val_bytes); i++) { + reg_addr = reg_addr + i; + val = (u8 *)val + (val_bytes * i); + ret = swr_write(swr, swr->dev_num, reg_addr, val); if (ret < 0) { dev_err(dev, "%s: write reg 0x%x failed, err %d\n", - __func__, (reg_addr+i), ret); + __func__, reg_addr, ret); break; } } @@ -153,7 +156,7 @@ static int regmap_swr_read(void *context, struct regmap *map = dev_get_regmap(dev, NULL); size_t addr_bytes = map->format.reg_bytes; int ret = 0; - u32 reg_addr = 0; + u16 reg_addr = 0; if (swr == NULL) { dev_err(dev, "%s: swr is NULL\n", __func__); @@ -164,7 +167,7 @@ static int regmap_swr_read(void *context, __func__, reg_size); return -EINVAL; } - reg_addr = *(u32 *)reg; + reg_addr = *(u16 *)reg; ret = swr_read(swr, swr->dev_num, reg_addr, val, val_size); if (ret < 0) dev_err(dev, "%s: codec reg 0x%x read failed %d\n", diff --git a/drivers/clk/msm/clock-gpu-cobalt.c b/drivers/clk/msm/clock-gpu-cobalt.c index 7230c7a2bc04..7cec9be1f42c 100644 --- a/drivers/clk/msm/clock-gpu-cobalt.c +++ b/drivers/clk/msm/clock-gpu-cobalt.c @@ -39,8 +39,6 @@ static void __iomem *virt_base_gfx; #define gpucc_gpll0_source_val 5 #define gpu_pll0_pll_out_even_source_val 1 #define gpu_pll0_pll_out_odd_source_val 2 -#define gpu_pll1_pll_out_even_source_val 3 -#define gpu_pll1_pll_out_odd_source_val 4 #define SW_COLLAPSE_MASK BIT(0) #define GPU_CX_GDSCR_OFFSET 0x1004 @@ -157,65 +155,6 @@ static struct div_clk gpu_pll0_pll_out_odd = { }, }; -static struct alpha_pll_clk gpu_pll1_pll = { - .masks = &pll_masks_p, - .base = &virt_base_gfx, - .offset = GPUCC_GPU_PLL1_PLL_MODE, - .enable_config = 0x1, - .is_fabia = true, - .c = { - .rate = 0, - .parent = &gpucc_xo.c, - .dbg_name = "gpu_pll1_pll", - .ops = &clk_ops_fabia_alpha_pll, - VDD_GPU_PLL_FMAX_MAP1(MIN, 1300000500), - CLK_INIT(gpu_pll1_pll.c), - }, -}; - -static struct div_clk gpu_pll1_pll_out_even = { - .base = &virt_base_gfx, - .offset = GPUCC_GPU_PLL1_USER_CTL_MODE, - .mask = 0xf, - .shift = 8, - .data = { - .max_div = 8, - .min_div = 1, - .skip_odd_div = true, - .allow_div_one = true, - .rate_margin = 500, - }, - .ops = &postdiv_reg_ops, - .c = { - .parent = &gpu_pll1_pll.c, - .dbg_name = "gpu_pll1_pll_out_even", - .ops = &clk_ops_div, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(gpu_pll1_pll_out_even.c), - }, -}; - -static struct div_clk gpu_pll1_pll_out_odd = { - .base = &virt_base_gfx, - .offset = GPUCC_GPU_PLL0_USER_CTL_MODE, - .mask = 0xf, - .shift = 12, - .data = { - .max_div = 7, - .min_div = 3, - .skip_even_div = true, - .rate_margin = 500, - }, - .ops = &postdiv_reg_ops, - .c = { - .parent = &gpu_pll1_pll.c, - .dbg_name = "gpu_pll1_pll_out_odd", - .ops = &clk_ops_div, - .flags = CLKFLAG_NO_RATE_CACHE, - CLK_INIT(gpu_pll1_pll_out_odd.c), - }, -}; - static struct clk_freq_tbl ftbl_gfx3d_clk_src[] = { F_SLEW( 171000000, 342000000, gpu_pll0_pll_out_even, 1, 0, 0), F_SLEW( 251000000, 502000000, gpu_pll0_pll_out_even, 1, 0, 0), @@ -227,11 +166,11 @@ static struct clk_freq_tbl ftbl_gfx3d_clk_src[] = { }; static struct clk_freq_tbl ftbl_gfx3d_clk_src_v2[] = { - F_SLEW( 189000000, 378000000, gpu_pll0_pll_out_even, 1, 0, 0), - F_SLEW( 264000000, 528000000, gpu_pll0_pll_out_even, 1, 0, 0), + F_SLEW( 180000000, 360000000, gpu_pll0_pll_out_even, 1, 0, 0), + F_SLEW( 257000000, 514000000, gpu_pll0_pll_out_even, 1, 0, 0), F_SLEW( 342000000, 684000000, gpu_pll0_pll_out_even, 1, 0, 0), F_SLEW( 414000000, 828000000, gpu_pll0_pll_out_even, 1, 0, 0), - F_SLEW( 520000000, 1040000000, gpu_pll0_pll_out_even, 1, 0, 0), + F_SLEW( 515000000, 1030000000, gpu_pll0_pll_out_even, 1, 0, 0), F_SLEW( 596000000, 1192000000, gpu_pll0_pll_out_even, 1, 0, 0), F_SLEW( 670000000, 1340000000, gpu_pll0_pll_out_even, 1, 0, 0), F_SLEW( 710000000, 1420000000, gpu_pll0_pll_out_even, 1, 0, 0), @@ -239,14 +178,14 @@ static struct clk_freq_tbl ftbl_gfx3d_clk_src_v2[] = { }; static struct clk_freq_tbl ftbl_gfx3d_clk_src_vq[] = { - F_SLEW( 185000000, 370000000, gpu_pll0_pll_out_even, 1, 0, 0), - F_SLEW( 285000000, 570000000, gpu_pll0_pll_out_even, 1, 0, 0), + F_SLEW( 180000000, 360000000, gpu_pll0_pll_out_even, 1, 0, 0), + F_SLEW( 265000000, 530000000, gpu_pll0_pll_out_even, 1, 0, 0), F_SLEW( 358000000, 716000000, gpu_pll0_pll_out_even, 1, 0, 0), F_SLEW( 434000000, 868000000, gpu_pll0_pll_out_even, 1, 0, 0), F_SLEW( 542000000, 1084000000, gpu_pll0_pll_out_even, 1, 0, 0), F_SLEW( 630000000, 1260000000, gpu_pll0_pll_out_even, 1, 0, 0), - F_SLEW( 670000000, 1340000000, gpu_pll1_pll_out_even, 1, 0, 0), - F_SLEW( 710000000, 1420000000, gpu_pll1_pll_out_even, 1, 0, 0), + F_SLEW( 700000000, 1400000000, gpu_pll0_pll_out_even, 1, 0, 0), + F_SLEW( 750000000, 1500000000, gpu_pll0_pll_out_even, 1, 0, 0), F_END }; @@ -659,9 +598,6 @@ static struct clk_lookup msm_clocks_gfxcc_cobalt[] = { CLK_LIST(gpu_pll0_pll), CLK_LIST(gpu_pll0_pll_out_even), CLK_LIST(gpu_pll0_pll_out_odd), - CLK_LIST(gpu_pll1_pll), - CLK_LIST(gpu_pll1_pll_out_even), - CLK_LIST(gpu_pll1_pll_out_odd), CLK_LIST(gfx3d_clk_src), CLK_LIST(gpucc_gfx3d_clk), CLK_LIST(gpucc_mx_clk), @@ -671,14 +607,12 @@ static struct clk_lookup msm_clocks_gfxcc_cobalt[] = { static void msm_gfxcc_hamster_fixup(void) { gpu_pll0_pll.c.fmax[VDD_DIG_MIN] = 1420000500; - gpu_pll1_pll.c.fmax[VDD_DIG_MIN] = 1420000500; gfx3d_clk_src.freq_tbl = ftbl_gfx3d_clk_src_vq; } static void msm_gfxcc_cobalt_v2_fixup(void) { gpu_pll0_pll.c.fmax[VDD_DIG_MIN] = 1420000500; - gpu_pll1_pll.c.fmax[VDD_DIG_MIN] = 1420000500; gfx3d_clk_src.freq_tbl = ftbl_gfx3d_clk_src_v2; } diff --git a/drivers/clk/msm/clock-mmss-cobalt.c b/drivers/clk/msm/clock-mmss-cobalt.c index 288abb133743..2da10a2e4780 100644 --- a/drivers/clk/msm/clock-mmss-cobalt.c +++ b/drivers/clk/msm/clock-mmss-cobalt.c @@ -274,7 +274,7 @@ static struct rcg_clk csi0_clk_src = { .c = { .dbg_name = "csi0_clk_src", .ops = &clk_ops_rcg, - VDD_DIG_FMAX_MAP4(LOWER, 164570000, LOW, 256000000, + VDD_DIG_FMAX_MAP4(LOWER, 164571429, LOW, 256000000, NOMINAL, 384000000, HIGH, 576000000), CLK_INIT(csi0_clk_src.c), }, @@ -292,6 +292,9 @@ static struct clk_freq_tbl ftbl_vfe_clk_src[] = { static struct clk_freq_tbl ftbl_vfe_clk_src_vq[] = { F_MM( 200000000, mmsscc_gpll0, 3, 0, 0), + F_MM( 300000000, mmsscc_gpll0, 2, 0, 0), + F_MM( 320000000, mmpll7_pll_out, 3, 0, 0), + F_MM( 384000000, mmpll4_pll_out, 2, 0, 0), F_MM( 404000000, mmpll0_pll_out, 2, 0, 0), F_MM( 480000000, mmpll7_pll_out, 2, 0, 0), F_MM( 576000000, mmpll10_pll_out, 1, 0, 0), @@ -367,16 +370,6 @@ static struct clk_freq_tbl ftbl_maxi_clk_src[] = { F_END }; -static struct clk_freq_tbl ftbl_maxi_clk_src_vq[] = { - F_MM( 19200000, mmsscc_xo, 1, 0, 0), - F_MM( 75000000, mmsscc_gpll0_div, 4, 0, 0), - F_MM( 171428571, mmsscc_gpll0, 3.5, 0, 0), - F_MM( 240000000, mmsscc_gpll0, 2.5, 0, 0), - F_MM( 323200000, mmpll0_pll_out, 2.5, 0, 0), - F_MM( 406000000, mmpll1_pll_out, 2, 0, 0), - F_END -}; - static struct rcg_clk maxi_clk_src = { .cmd_rcgr_reg = MMSS_MAXI_CMD_RCGR, .set_rate = set_rate_hid, @@ -592,18 +585,11 @@ static struct clk_freq_tbl ftbl_fd_core_clk_src[] = { F_END }; -static struct clk_freq_tbl ftbl_fd_core_clk_src_v2[] = { - F_MM( 100000000, mmsscc_gpll0, 6, 0, 0), - F_MM( 404000000, mmpll0_pll_out, 2, 0, 0), - F_MM( 480000000, mmpll7_pll_out, 2, 0, 0), - F_MM( 576000000, mmpll10_pll_out, 1, 0, 0), - F_END -}; - static struct clk_freq_tbl ftbl_fd_core_clk_src_vq[] = { F_MM( 100000000, mmsscc_gpll0, 6, 0, 0), F_MM( 200000000, mmsscc_gpll0, 3, 0, 0), - F_MM( 400000000, mmsscc_gpll0, 1.5, 0, 0), + F_MM( 404000000, mmpll0_pll_out, 2, 0, 0), + F_MM( 480000000, mmpll7_pll_out, 2, 0, 0), F_MM( 576000000, mmpll10_pll_out, 1, 0, 0), F_END }; @@ -2677,60 +2663,81 @@ static void msm_mmsscc_hamster_fixup(void) vfe1_clk_src.c.fmax[VDD_DIG_LOW_L1] = 480000000; csi0_clk_src.freq_tbl = ftbl_csi_clk_src_vq; - csi0_clk_src.c.fmax[VDD_DIG_LOW_L1] = 300000000; + csi0_clk_src.c.fmax[VDD_DIG_LOW] = 274290000; + csi0_clk_src.c.fmax[VDD_DIG_LOW_L1] = 320000000; csi1_clk_src.freq_tbl = ftbl_csi_clk_src_vq; - csi1_clk_src.c.fmax[VDD_DIG_LOW_L1] = 300000000; + csi1_clk_src.c.fmax[VDD_DIG_LOW] = 274290000; + csi1_clk_src.c.fmax[VDD_DIG_LOW_L1] = 320000000; csi2_clk_src.freq_tbl = ftbl_csi_clk_src_vq; - csi2_clk_src.c.fmax[VDD_DIG_LOW_L1] = 300000000; + csi2_clk_src.c.fmax[VDD_DIG_LOW] = 274290000; + csi2_clk_src.c.fmax[VDD_DIG_LOW_L1] = 320000000; csi3_clk_src.freq_tbl = ftbl_csi_clk_src_vq; - csi3_clk_src.c.fmax[VDD_DIG_LOW_L1] = 300000000; + csi3_clk_src.c.fmax[VDD_DIG_LOW] = 274290000; + csi3_clk_src.c.fmax[VDD_DIG_LOW_L1] = 320000000; cpp_clk_src.freq_tbl = ftbl_cpp_clk_src_vq; - cpp_clk_src.c.fmax[VDD_DIG_LOW_L1] = 480000000; + cpp_clk_src.c.fmax[VDD_DIG_LOW] = 384000000; + cpp_clk_src.c.fmax[VDD_DIG_LOW_L1] = 404000000; jpeg0_clk_src.freq_tbl = ftbl_jpeg0_clk_src_vq; jpeg0_clk_src.c.fmax[VDD_DIG_LOW_L1] = 320000000; csiphy_clk_src.freq_tbl = ftbl_csiphy_clk_src_vq; + csiphy_clk_src.c.fmax[VDD_DIG_LOW] = 274290000; csiphy_clk_src.c.fmax[VDD_DIG_LOW_L1] = 300000000; fd_core_clk_src.freq_tbl = ftbl_fd_core_clk_src_vq; - fd_core_clk_src.c.fmax[VDD_DIG_LOW_L1] = 400000000; + fd_core_clk_src.c.fmax[VDD_DIG_LOW] = 404000000; + fd_core_clk_src.c.fmax[VDD_DIG_LOW_L1] = 480000000; csi0phytimer_clk_src.c.fmax[VDD_DIG_LOW_L1] = 269333333; csi1phytimer_clk_src.c.fmax[VDD_DIG_LOW_L1] = 269333333; csi2phytimer_clk_src.c.fmax[VDD_DIG_LOW_L1] = 269333333; mdp_clk_src.c.fmax[VDD_DIG_LOW_L1] = 330000000; + dp_pixel_clk_src.c.fmax[VDD_DIG_LOWER] = 154000000; extpclk_clk_src.c.fmax[VDD_DIG_LOW] = 312500000; extpclk_clk_src.c.fmax[VDD_DIG_LOW_L1] = 375000000; rot_clk_src.c.fmax[VDD_DIG_LOW_L1] = 330000000; - maxi_clk_src.freq_tbl = ftbl_maxi_clk_src_vq; video_core_clk_src.freq_tbl = ftbl_video_core_clk_src_vq; video_core_clk_src.c.fmax[VDD_DIG_LOWER] = 200000000; video_core_clk_src.c.fmax[VDD_DIG_LOW] = 269330000; - video_core_clk_src.c.fmax[VDD_DIG_LOW_L1] = 404000000; + video_core_clk_src.c.fmax[VDD_DIG_LOW_L1] = 355200000; video_core_clk_src.c.fmax[VDD_DIG_NOMINAL] = 444000000; video_core_clk_src.c.fmax[VDD_DIG_HIGH] = 533000000; video_subcore0_clk_src.freq_tbl = ftbl_video_subcore_clk_src_vq; video_subcore0_clk_src.c.fmax[VDD_DIG_LOWER] = 200000000; video_subcore0_clk_src.c.fmax[VDD_DIG_LOW] = 269330000; - video_subcore0_clk_src.c.fmax[VDD_DIG_LOW_L1] = 404000000; + video_subcore0_clk_src.c.fmax[VDD_DIG_LOW_L1] = 355200000; video_subcore0_clk_src.c.fmax[VDD_DIG_NOMINAL] = 444000000; video_subcore0_clk_src.c.fmax[VDD_DIG_HIGH] = 533000000; video_subcore1_clk_src.freq_tbl = ftbl_video_subcore_clk_src_vq; video_subcore1_clk_src.c.fmax[VDD_DIG_LOWER] = 200000000; video_subcore1_clk_src.c.fmax[VDD_DIG_LOW] = 269330000; - video_subcore1_clk_src.c.fmax[VDD_DIG_LOW_L1] = 404000000; + video_subcore1_clk_src.c.fmax[VDD_DIG_LOW_L1] = 355200000; video_subcore1_clk_src.c.fmax[VDD_DIG_NOMINAL] = 444000000; video_subcore1_clk_src.c.fmax[VDD_DIG_HIGH] = 533000000; }; static void msm_mmsscc_v2_fixup(void) { - fd_core_clk_src.freq_tbl = ftbl_fd_core_clk_src_v2; - fd_core_clk_src.c.fmax[VDD_DIG_LOW] = 404000000; - fd_core_clk_src.c.fmax[VDD_DIG_LOW_L1] = 480000000; + cpp_clk_src.c.fmax[VDD_DIG_LOW] = 200000000; + cpp_clk_src.c.fmax[VDD_DIG_LOW_L1] = 480000000; + csi0_clk_src.c.fmax[VDD_DIG_LOW] = 256000000; + csi0_clk_src.c.fmax[VDD_DIG_LOW_L1] = 300000000; + csi1_clk_src.c.fmax[VDD_DIG_LOW] = 256000000; + csi1_clk_src.c.fmax[VDD_DIG_LOW_L1] = 300000000; + csi2_clk_src.c.fmax[VDD_DIG_LOW] = 256000000; + csi2_clk_src.c.fmax[VDD_DIG_LOW_L1] = 300000000; + csi3_clk_src.c.fmax[VDD_DIG_LOW] = 256000000; + csi3_clk_src.c.fmax[VDD_DIG_LOW_L1] = 300000000; + csiphy_clk_src.c.fmax[VDD_DIG_LOW] = 256000000; + + dp_pixel_clk_src.c.fmax[VDD_DIG_LOWER] = 148380000; + + video_subcore0_clk_src.c.fmax[VDD_DIG_LOW_L1] = 355200000; + video_subcore1_clk_src.c.fmax[VDD_DIG_LOW_L1] = 355200000; + video_core_clk_src.c.fmax[VDD_DIG_LOW_L1] = 355200000; } int msm_mmsscc_cobalt_probe(struct platform_device *pdev) diff --git a/drivers/clk/msm/reset.c b/drivers/clk/msm/reset.c index 41e0357aea3e..087e245e18f4 100644 --- a/drivers/clk/msm/reset.c +++ b/drivers/clk/msm/reset.c @@ -40,6 +40,9 @@ msm_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) regval |= BIT(map->bit); writel_relaxed(regval, rst->base + map->reg); + /* Make sure the reset is asserted */ + mb(); + return 0; } @@ -57,6 +60,9 @@ msm_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) regval &= ~BIT(map->bit); writel_relaxed(regval, rst->base + map->reg); + /* Make sure the reset is de-asserted */ + mb(); + return 0; } diff --git a/drivers/firmware/qcom/tz_log.c b/drivers/firmware/qcom/tz_log.c index 7a45142a66c1..bf3a24b3eb01 100644 --- a/drivers/firmware/qcom/tz_log.c +++ b/drivers/firmware/qcom/tz_log.c @@ -54,6 +54,10 @@ */ #define TZBSP_MAX_INT_DESC 16 /* + * TZ 3.X version info + */ +#define QSEE_VERSION_TZ_3_X 0x800000 +/* * VMID Table */ struct tzdbg_vmid_t { @@ -72,6 +76,19 @@ struct tzdbg_boot_info_t { uint32_t spare; /* Reserved for future use. */ }; /* + * Boot Info Table for 64-bit + */ +struct tzdbg_boot_info64_t { + uint32_t wb_entry_cnt; /* Warmboot entry CPU Counter */ + uint32_t wb_exit_cnt; /* Warmboot exit CPU Counter */ + uint32_t pc_entry_cnt; /* Power Collapse entry CPU Counter */ + uint32_t pc_exit_cnt; /* Power Collapse exit CPU counter */ + uint32_t psci_entry_cnt;/* PSCI syscall entry CPU Counter */ + uint32_t psci_exit_cnt; /* PSCI syscall exit CPU Counter */ + uint64_t warm_jmp_addr; /* Last Warmboot Jump Address */ + uint32_t warm_jmp_instr; /* Last Warmboot Jump Address Instruction */ +}; +/* * Reset Info Table */ struct tzdbg_reset_info_t { @@ -318,30 +335,90 @@ static int _disp_tz_boot_stats(void) { int i; int len = 0; - struct tzdbg_boot_info_t *ptr; + struct tzdbg_boot_info_t *ptr = NULL; + struct tzdbg_boot_info64_t *ptr_64 = NULL; + int ret = 0; + uint32_t smc_id = 0; + uint32_t feature = 10; + struct qseecom_command_scm_resp resp = {}; + struct scm_desc desc = {0}; - ptr = (struct tzdbg_boot_info_t *)((unsigned char *)tzdbg.diag_buf + - tzdbg.diag_buf->boot_info_off); + if (!is_scm_armv8()) { + ret = scm_call(SCM_SVC_INFO, SCM_SVC_UTIL, &feature, + sizeof(feature), &resp, sizeof(resp)); + } else { + smc_id = TZ_INFO_GET_FEATURE_VERSION_ID; + desc.arginfo = TZ_INFO_GET_FEATURE_VERSION_ID_PARAM_ID; + desc.args[0] = feature; + ret = scm_call2(smc_id, &desc); + resp.result = desc.ret[0]; + } - for (i = 0; i < tzdbg.diag_buf->cpu_count; i++) { - len += snprintf(tzdbg.disp_buf + len, - (debug_rw_buf_size - 1) - len, - " CPU #: %d\n" - " Warmboot jump address : 0x%x\n" - " Warmboot entry CPU counter: 0x%x\n" - " Warmboot exit CPU counter : 0x%x\n" - " Power Collapse entry CPU counter: 0x%x\n" - " Power Collapse exit CPU counter : 0x%x\n", - i, ptr->warm_jmp_addr, ptr->wb_entry_cnt, - ptr->wb_exit_cnt, ptr->pc_entry_cnt, - ptr->pc_exit_cnt); + if (ret) { + pr_err("%s: scm_call to register log buffer failed\n", + __func__); + return 0; + } + pr_info("qsee_version = 0x%x\n", resp.result); - if (len > (debug_rw_buf_size - 1)) { - pr_warn("%s: Cannot fit all info into the buffer\n", - __func__); - break; + if (resp.result >= QSEE_VERSION_TZ_3_X) { + ptr_64 = (struct tzdbg_boot_info64_t *)((unsigned char *) + tzdbg.diag_buf + tzdbg.diag_buf->boot_info_off); + } else { + ptr = (struct tzdbg_boot_info_t *)((unsigned char *) + tzdbg.diag_buf + tzdbg.diag_buf->boot_info_off); + } + + for (i = 0; i < tzdbg.diag_buf->cpu_count; i++) { + if (resp.result >= QSEE_VERSION_TZ_3_X) { + len += snprintf(tzdbg.disp_buf + len, + (debug_rw_buf_size - 1) - len, + " CPU #: %d\n" + " Warmboot jump address : 0x%llx\n" + " Warmboot entry CPU counter : 0x%x\n" + " Warmboot exit CPU counter : 0x%x\n" + " Power Collapse entry CPU counter : 0x%x\n" + " Power Collapse exit CPU counter : 0x%x\n" + " Psci entry CPU counter : 0x%x\n" + " Psci exit CPU counter : 0x%x\n" + " Warmboot Jump Address Instruction : 0x%x\n", + i, (uint64_t)ptr_64->warm_jmp_addr, + ptr_64->wb_entry_cnt, + ptr_64->wb_exit_cnt, + ptr_64->pc_entry_cnt, + ptr_64->pc_exit_cnt, + ptr_64->psci_entry_cnt, + ptr_64->psci_exit_cnt, + ptr_64->warm_jmp_instr); + + if (len > (debug_rw_buf_size - 1)) { + pr_warn("%s: Cannot fit all info into the buffer\n", + __func__); + break; + } + ptr_64++; + } else { + len += snprintf(tzdbg.disp_buf + len, + (debug_rw_buf_size - 1) - len, + " CPU #: %d\n" + " Warmboot jump address : 0x%x\n" + " Warmboot entry CPU counter: 0x%x\n" + " Warmboot exit CPU counter : 0x%x\n" + " Power Collapse entry CPU counter: 0x%x\n" + " Power Collapse exit CPU counter : 0x%x\n", + i, ptr->warm_jmp_addr, + ptr->wb_entry_cnt, + ptr->wb_exit_cnt, + ptr->pc_entry_cnt, + ptr->pc_exit_cnt); + + if (len > (debug_rw_buf_size - 1)) { + pr_warn("%s: Cannot fit all info into the buffer\n", + __func__); + break; + } + ptr++; } - ptr++; } tzdbg.stat[TZDBG_BOOT].data = tzdbg.disp_buf; return len; diff --git a/drivers/gpio/gpio-msm-smp2p-test.c b/drivers/gpio/gpio-msm-smp2p-test.c index 067735b3026f..5907513b43c0 100644 --- a/drivers/gpio/gpio-msm-smp2p-test.c +++ b/drivers/gpio/gpio-msm-smp2p-test.c @@ -1,6 +1,6 @@ /* drivers/gpio/gpio-msm-smp2p-test.c * - * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -95,6 +95,10 @@ static int smp2p_gpio_test_probe(struct platform_device *pdev) gpio_info_ptr = &gpio_info[SMP2P_WIRELESS_PROC].in; } else if (strcmp("qcom,smp2pgpio_test_smp2p_4_out", node->name) == 0) { gpio_info_ptr = &gpio_info[SMP2P_WIRELESS_PROC].out; + } else if (strcmp("qcom,smp2pgpio_test_smp2p_5_in", node->name) == 0) { + gpio_info_ptr = &gpio_info[SMP2P_CDSP_PROC].in; + } else if (strcmp("qcom,smp2pgpio_test_smp2p_5_out", node->name) == 0) { + gpio_info_ptr = &gpio_info[SMP2P_CDSP_PROC].out; } else if (strcmp("qcom,smp2pgpio_test_smp2p_7_in", node->name) == 0) { gpio_info_ptr = &gpio_info[SMP2P_TZ_PROC].in; } else if (strcmp("qcom,smp2pgpio_test_smp2p_7_out", node->name) == 0) { @@ -148,6 +152,10 @@ static struct of_device_id msm_smp2p_match_table[] = { {.compatible = "qcom,smp2pgpio_test_smp2p_4_out", }, {.compatible = "qcom,smp2pgpio_test_smp2p_4_in", }, + /* CDSP */ + {.compatible = "qcom,smp2pgpio_test_smp2p_5_out", }, + {.compatible = "qcom,smp2pgpio_test_smp2p_5_in", }, + /* TZ */ {.compatible = "qcom,smp2pgpio_test_smp2p_7_out", }, {.compatible = "qcom,smp2pgpio_test_smp2p_7_in", }, diff --git a/drivers/gpu/msm/a5xx_reg.h b/drivers/gpu/msm/a5xx_reg.h index 207588844931..c6dc9032c0bc 100644 --- a/drivers/gpu/msm/a5xx_reg.h +++ b/drivers/gpu/msm/a5xx_reg.h @@ -561,6 +561,7 @@ /* RB registers */ +#define A5XX_RB_DBG_ECO_CNT 0xCC4 #define A5XX_RB_ADDR_MODE_CNTL 0xCC5 #define A5XX_RB_MODE_CNTL 0xCC6 #define A5XX_RB_PERFCTR_RB_SEL_0 0xCD0 diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index b57fe05b21d5..cbeb1a924cc9 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -825,6 +825,8 @@ static struct { { ADRENO_QUIRK_IOMMU_SYNC, "qcom,gpu-quirk-iommu-sync" }, { ADRENO_QUIRK_CRITICAL_PACKETS, "qcom,gpu-quirk-critical-packets" }, { ADRENO_QUIRK_FAULT_DETECT_MASK, "qcom,gpu-quirk-fault-detect-mask" }, + { ADRENO_QUIRK_DISABLE_RB_DP2CLOCKGATING, + "qcom,gpu-quirk-dp2clockgating-disable" }, }; static int adreno_of_get_power(struct adreno_device *adreno_dev, diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index f5fb4e48c3ee..cbbfc57e27f4 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -121,6 +121,8 @@ #define ADRENO_QUIRK_CRITICAL_PACKETS BIT(2) /* Mask out RB1-3 activity signals from HW hang detection logic */ #define ADRENO_QUIRK_FAULT_DETECT_MASK BIT(3) +/* Disable RB sampler datapath clock gating optimization */ +#define ADRENO_QUIRK_DISABLE_RB_DP2CLOCKGATING BIT(4) /* Flags to control command packet settings */ #define KGSL_CMD_FLAGS_NONE 0 diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index 467b385f6d56..61d27ac8061f 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -1836,6 +1836,13 @@ static void a5xx_start(struct adreno_device *adreno_dev) kgsl_regrmw(device, A5XX_PC_DBG_ECO_CNTL, 0, (1 << 8)); } + if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_DISABLE_RB_DP2CLOCKGATING)) { + /* + * Disable RB sampler datapath DP2 clock gating + * optimization for 1-SP GPU's, by default it is enabled. + */ + kgsl_regrmw(device, A5XX_RB_DBG_ECO_CNT, 0, (1 << 9)); + } /* Set the USE_RETENTION_FLOPS chicken bit */ kgsl_regwrite(device, A5XX_CP_CHICKEN_DBG, 0x02000000); diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c index 0160939e97f9..5ffb0b2513f3 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -158,11 +158,18 @@ unsigned int *adreno_ringbuffer_allocspace(struct adreno_ringbuffer *rb, return RB_HOSTPTR(rb, ret); } - cmds = RB_HOSTPTR(rb, rb->_wptr); - *cmds = cp_packet(adreno_dev, CP_NOP, - KGSL_RB_DWORDS - rb->_wptr - 1); - - rb->_wptr = 0; + /* + * There isn't enough space toward the end of ringbuffer. So + * look for space from the beginning of ringbuffer upto the + * read pointer. + */ + if (dwords < rptr) { + cmds = RB_HOSTPTR(rb, rb->_wptr); + *cmds = cp_packet(adreno_dev, CP_NOP, + KGSL_RB_DWORDS - rb->_wptr - 1); + rb->_wptr = dwords; + return RB_HOSTPTR(rb, 0); + } } if (rb->_wptr + dwords < rptr) { diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index c203ac7bfe8c..24005a1fda72 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -78,6 +78,16 @@ struct kgsl_dma_buf_meta { struct sg_table *table; }; +static inline struct kgsl_pagetable *_get_memdesc_pagetable( + struct kgsl_pagetable *pt, struct kgsl_mem_entry *entry) +{ + /* if a secured buffer, map it to secure global pagetable */ + if (kgsl_memdesc_is_secured(&entry->memdesc)) + return pt->mmu->securepagetable; + + return pt; +} + static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry); static const struct file_operations kgsl_fops; @@ -445,14 +455,17 @@ kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry, /* map the memory after unlocking if gpuaddr has been assigned */ if (entry->memdesc.gpuaddr) { - /* if a secured buffer map it to secure global pagetable */ + pagetable = process->pagetable; if (kgsl_memdesc_is_secured(&entry->memdesc)) - pagetable = process->pagetable->mmu->securepagetable; - else - pagetable = process->pagetable; + pagetable = pagetable->mmu->securepagetable; entry->memdesc.pagetable = pagetable; - ret = kgsl_mmu_map(pagetable, &entry->memdesc); + + if (entry->memdesc.flags & KGSL_MEMFLAGS_SPARSE_VIRT) + ret = kgsl_mmu_sparse_dummy_map(pagetable, + &entry->memdesc, 0, entry->memdesc.size); + else if (entry->memdesc.gpuaddr) + ret = kgsl_mmu_map(pagetable, &entry->memdesc); if (ret) kgsl_mem_entry_detach_process(entry); } @@ -1270,6 +1283,24 @@ kgsl_sharedmem_find(struct kgsl_process_private *private, uint64_t gpuaddr) } EXPORT_SYMBOL(kgsl_sharedmem_find); +struct kgsl_mem_entry * __must_check +kgsl_sharedmem_find_id_flags(struct kgsl_process_private *process, + unsigned int id, uint64_t flags) +{ + int count = 0; + struct kgsl_mem_entry *entry; + + spin_lock(&process->mem_lock); + entry = idr_find(&process->mem_idr, id); + if (entry) + if (!entry->pending_free && + (flags & entry->memdesc.flags) == flags) + count = kgsl_mem_entry_get(entry); + spin_unlock(&process->mem_lock); + + return (count == 0) ? NULL : entry; +} + /** * kgsl_sharedmem_find_id() - find a memory entry by id * @process: the owning process @@ -1283,19 +1314,7 @@ EXPORT_SYMBOL(kgsl_sharedmem_find); struct kgsl_mem_entry * __must_check kgsl_sharedmem_find_id(struct kgsl_process_private *process, unsigned int id) { - int result; - struct kgsl_mem_entry *entry; - - drain_workqueue(kgsl_driver.mem_workqueue); - - spin_lock(&process->mem_lock); - entry = idr_find(&process->mem_idr, id); - result = kgsl_mem_entry_get(entry); - spin_unlock(&process->mem_lock); - - if (result == 0) - return NULL; - return entry; + return kgsl_sharedmem_find_id_flags(process, id, 0); } /** @@ -3121,6 +3140,546 @@ long kgsl_ioctl_gpumem_get_info(struct kgsl_device_private *dev_priv, return result; } +static inline int _sparse_alloc_param_sanity_check(uint64_t size, + uint64_t pagesize) +{ + if (size == 0 || pagesize == 0) + return -EINVAL; + + if (pagesize != PAGE_SIZE && pagesize != SZ_64K) + return -EINVAL; + + if (pagesize > size || !IS_ALIGNED(size, pagesize)) + return -EINVAL; + + return 0; +} + +long kgsl_ioctl_sparse_phys_alloc(struct kgsl_device_private *dev_priv, + unsigned int cmd, void *data) +{ + struct kgsl_process_private *process = dev_priv->process_priv; + struct kgsl_sparse_phys_alloc *param = data; + struct kgsl_mem_entry *entry; + int ret; + int id; + + ret = _sparse_alloc_param_sanity_check(param->size, param->pagesize); + if (ret) + return ret; + + entry = kgsl_mem_entry_create(); + if (entry == NULL) + return -ENOMEM; + + ret = kgsl_process_private_get(process); + if (!ret) { + ret = -EBADF; + goto err_free_entry; + } + + idr_preload(GFP_KERNEL); + spin_lock(&process->mem_lock); + /* Allocate the ID but don't attach the pointer just yet */ + id = idr_alloc(&process->mem_idr, NULL, 1, 0, GFP_NOWAIT); + spin_unlock(&process->mem_lock); + idr_preload_end(); + + if (id < 0) { + ret = id; + goto err_put_proc_priv; + } + + entry->id = id; + entry->priv = process; + + entry->memdesc.flags = KGSL_MEMFLAGS_SPARSE_PHYS; + kgsl_memdesc_set_align(&entry->memdesc, ilog2(param->pagesize)); + + ret = kgsl_allocate_user(dev_priv->device, &entry->memdesc, + process->pagetable, param->size, entry->memdesc.flags); + if (ret) + goto err_remove_idr; + + /* Sanity check to verify we got correct pagesize */ + if (param->pagesize != PAGE_SIZE && entry->memdesc.sgt != NULL) { + struct scatterlist *s; + int i; + + for_each_sg(entry->memdesc.sgt->sgl, s, + entry->memdesc.sgt->nents, i) { + if (!IS_ALIGNED(s->length, param->pagesize)) + goto err_invalid_pages; + } + } + + param->id = entry->id; + param->flags = entry->memdesc.flags; + + trace_sparse_phys_alloc(entry->id, param->size, param->pagesize); + kgsl_mem_entry_commit_process(entry); + + return 0; + +err_invalid_pages: + kgsl_sharedmem_free(&entry->memdesc); +err_remove_idr: + spin_lock(&process->mem_lock); + idr_remove(&process->mem_idr, entry->id); + spin_unlock(&process->mem_lock); +err_put_proc_priv: + kgsl_process_private_put(process); +err_free_entry: + kfree(entry); + + return ret; +} + +long kgsl_ioctl_sparse_phys_free(struct kgsl_device_private *dev_priv, + unsigned int cmd, void *data) +{ + struct kgsl_process_private *process = dev_priv->process_priv; + struct kgsl_sparse_phys_free *param = data; + struct kgsl_mem_entry *entry; + + entry = kgsl_sharedmem_find_id_flags(process, param->id, + KGSL_MEMFLAGS_SPARSE_PHYS); + if (entry == NULL) + return -EINVAL; + + if (entry->memdesc.cur_bindings != 0) { + kgsl_mem_entry_put(entry); + return -EINVAL; + } + + trace_sparse_phys_free(entry->id); + + /* One put for find_id(), one put for the kgsl_mem_entry_create() */ + kgsl_mem_entry_put(entry); + kgsl_mem_entry_put(entry); + + return 0; +} + +long kgsl_ioctl_sparse_virt_alloc(struct kgsl_device_private *dev_priv, + unsigned int cmd, void *data) +{ + struct kgsl_sparse_virt_alloc *param = data; + struct kgsl_mem_entry *entry; + int ret; + + ret = _sparse_alloc_param_sanity_check(param->size, param->pagesize); + if (ret) + return ret; + + entry = kgsl_mem_entry_create(); + if (entry == NULL) + return -ENOMEM; + + entry->memdesc.flags = KGSL_MEMFLAGS_SPARSE_VIRT; + entry->memdesc.size = param->size; + entry->memdesc.cur_bindings = 0; + kgsl_memdesc_set_align(&entry->memdesc, ilog2(param->pagesize)); + + spin_lock_init(&entry->bind_lock); + entry->bind_tree = RB_ROOT; + + ret = kgsl_mem_entry_attach_process(entry, dev_priv); + if (ret) { + kfree(entry); + return ret; + } + + param->id = entry->id; + param->gpuaddr = entry->memdesc.gpuaddr; + param->flags = entry->memdesc.flags; + + trace_sparse_virt_alloc(entry->id, param->size, param->pagesize); + kgsl_mem_entry_commit_process(entry); + + return 0; +} + +long kgsl_ioctl_sparse_virt_free(struct kgsl_device_private *dev_priv, + unsigned int cmd, void *data) +{ + struct kgsl_process_private *process = dev_priv->process_priv; + struct kgsl_sparse_virt_free *param = data; + struct kgsl_mem_entry *entry = NULL; + + entry = kgsl_sharedmem_find_id_flags(process, param->id, + KGSL_MEMFLAGS_SPARSE_VIRT); + if (entry == NULL) + return -EINVAL; + + if (entry->bind_tree.rb_node != NULL) { + kgsl_mem_entry_put(entry); + return -EINVAL; + } + + trace_sparse_virt_free(entry->id); + + /* One put for find_id(), one put for the kgsl_mem_entry_create() */ + kgsl_mem_entry_put(entry); + kgsl_mem_entry_put(entry); + + return 0; +} + +static int _sparse_add_to_bind_tree(struct kgsl_mem_entry *entry, + uint64_t v_offset, + struct kgsl_memdesc *memdesc, + uint64_t p_offset, + uint64_t size, + uint64_t flags) +{ + struct sparse_bind_object *new; + struct rb_node **node, *parent = NULL; + + new = kzalloc(sizeof(*new), GFP_KERNEL); + if (new == NULL) + return -ENOMEM; + + new->v_off = v_offset; + new->p_off = p_offset; + new->p_memdesc = memdesc; + new->size = size; + new->flags = flags; + + node = &entry->bind_tree.rb_node; + + while (*node != NULL) { + struct sparse_bind_object *this; + + parent = *node; + this = rb_entry(parent, struct sparse_bind_object, node); + + if (new->v_off < this->v_off) + node = &parent->rb_left; + else if (new->v_off > this->v_off) + node = &parent->rb_right; + } + + rb_link_node(&new->node, parent, node); + rb_insert_color(&new->node, &entry->bind_tree); + + return 0; +} + +static int _sparse_rm_from_bind_tree(struct kgsl_mem_entry *entry, + struct sparse_bind_object *obj, + uint64_t v_offset, uint64_t size) +{ + spin_lock(&entry->bind_lock); + if (v_offset == obj->v_off && size >= obj->size) { + /* + * We are all encompassing, remove the entry and free + * things up + */ + rb_erase(&obj->node, &entry->bind_tree); + kfree(obj); + } else if (v_offset == obj->v_off) { + /* + * We are the front of the node, adjust the front of + * the node + */ + obj->v_off += size; + obj->p_off += size; + obj->size -= size; + } else if ((v_offset + size) == (obj->v_off + obj->size)) { + /* + * We are at the end of the obj, adjust the beginning + * points + */ + obj->size -= size; + } else { + /* + * We are in the middle of a node, split it up and + * create a new mini node. Adjust this node's bounds + * and add the new node to the list. + */ + uint64_t tmp_size = obj->size; + int ret; + + obj->size = v_offset - obj->v_off; + + spin_unlock(&entry->bind_lock); + ret = _sparse_add_to_bind_tree(entry, v_offset + size, + obj->p_memdesc, + obj->p_off + (v_offset - obj->v_off) + size, + tmp_size - (v_offset - obj->v_off) - size, + obj->flags); + + return ret; + } + + spin_unlock(&entry->bind_lock); + + return 0; +} + +static struct sparse_bind_object *_find_containing_bind_obj( + struct kgsl_mem_entry *entry, + uint64_t offset, uint64_t size) +{ + struct sparse_bind_object *obj = NULL; + struct rb_node *node = entry->bind_tree.rb_node; + + spin_lock(&entry->bind_lock); + + while (node != NULL) { + obj = rb_entry(node, struct sparse_bind_object, node); + + if (offset == obj->v_off) { + break; + } else if (offset < obj->v_off) { + if (offset + size > obj->v_off) + break; + node = node->rb_left; + obj = NULL; + } else if (offset > obj->v_off) { + if (offset < obj->v_off + obj->size) + break; + node = node->rb_right; + obj = NULL; + } + } + + spin_unlock(&entry->bind_lock); + + return obj; +} + +static int _sparse_unbind(struct kgsl_mem_entry *entry, + struct sparse_bind_object *bind_obj, + uint64_t offset, uint64_t size) +{ + struct kgsl_memdesc *memdesc = bind_obj->p_memdesc; + struct kgsl_pagetable *pt = memdesc->pagetable; + int ret; + + if (memdesc->cur_bindings < (size / PAGE_SIZE)) + return -EINVAL; + + memdesc->cur_bindings -= size / PAGE_SIZE; + + ret = kgsl_mmu_unmap_offset(pt, memdesc, + entry->memdesc.gpuaddr, offset, size); + if (ret) + return ret; + + ret = kgsl_mmu_sparse_dummy_map(pt, &entry->memdesc, offset, size); + if (ret) + return ret; + + ret = _sparse_rm_from_bind_tree(entry, bind_obj, offset, size); + if (ret == 0) { + atomic_long_sub(size, &kgsl_driver.stats.mapped); + trace_sparse_unbind(entry->id, offset, size); + } + + return ret; +} + +static long sparse_unbind_range(struct kgsl_sparse_binding_object *obj, + struct kgsl_mem_entry *virt_entry) +{ + struct sparse_bind_object *bind_obj; + int ret = 0; + uint64_t size = obj->size; + uint64_t tmp_size = obj->size; + uint64_t offset = obj->virtoffset; + + while (size > 0 && ret == 0) { + tmp_size = size; + bind_obj = _find_containing_bind_obj(virt_entry, offset, size); + if (bind_obj == NULL) + return 0; + + if (bind_obj->v_off > offset) { + tmp_size = size - bind_obj->v_off - offset; + if (tmp_size > bind_obj->size) + tmp_size = bind_obj->size; + offset = bind_obj->v_off; + } else if (bind_obj->v_off < offset) { + uint64_t diff = offset - bind_obj->v_off; + + if (diff + size > bind_obj->size) + tmp_size = bind_obj->size - diff; + } else { + if (tmp_size > bind_obj->size) + tmp_size = bind_obj->size; + } + + ret = _sparse_unbind(virt_entry, bind_obj, offset, tmp_size); + if (ret == 0) { + offset += tmp_size; + size -= tmp_size; + } + } + + return ret; +} + +static inline bool _is_phys_bindable(struct kgsl_mem_entry *phys_entry, + uint64_t offset, uint64_t size, uint64_t flags) +{ + struct kgsl_memdesc *memdesc = &phys_entry->memdesc; + + if (!IS_ALIGNED(offset | size, kgsl_memdesc_get_pagesize(memdesc))) + return false; + + if (!(flags & KGSL_SPARSE_BIND_MULTIPLE_TO_PHYS) && + offset + size > memdesc->size) + return false; + + return true; +} + +static int _sparse_bind(struct kgsl_process_private *process, + struct kgsl_mem_entry *virt_entry, uint64_t v_offset, + struct kgsl_mem_entry *phys_entry, uint64_t p_offset, + uint64_t size, uint64_t flags) +{ + int ret; + struct kgsl_pagetable *pagetable; + struct kgsl_memdesc *memdesc = &phys_entry->memdesc; + + /* map the memory after unlocking if gpuaddr has been assigned */ + if (memdesc->gpuaddr) + return -EINVAL; + + if (memdesc->useraddr != 0) + return -EINVAL; + + pagetable = memdesc->pagetable; + + /* Clear out any mappings */ + ret = kgsl_mmu_unmap_offset(pagetable, &virt_entry->memdesc, + virt_entry->memdesc.gpuaddr, v_offset, size); + if (ret) + return ret; + + ret = kgsl_mmu_map_offset(pagetable, virt_entry->memdesc.gpuaddr, + v_offset, memdesc, p_offset, size, flags); + if (ret) { + /* Try to clean up, but not the end of the world */ + kgsl_mmu_sparse_dummy_map(pagetable, &virt_entry->memdesc, + v_offset, size); + return ret; + } + + ret = _sparse_add_to_bind_tree(virt_entry, v_offset, memdesc, + p_offset, size, flags); + if (ret == 0) + memdesc->cur_bindings += size / PAGE_SIZE; + + return ret; +} + +static long sparse_bind_range(struct kgsl_process_private *private, + struct kgsl_sparse_binding_object *obj, + struct kgsl_mem_entry *virt_entry) +{ + struct kgsl_mem_entry *phys_entry; + int ret; + + phys_entry = kgsl_sharedmem_find_id_flags(private, obj->id, + KGSL_MEMFLAGS_SPARSE_PHYS); + if (phys_entry == NULL) + return -EINVAL; + + if (!_is_phys_bindable(phys_entry, obj->physoffset, obj->size, + obj->flags)) { + kgsl_mem_entry_put(phys_entry); + return -EINVAL; + } + + if (kgsl_memdesc_get_align(&virt_entry->memdesc) != + kgsl_memdesc_get_align(&phys_entry->memdesc)) { + kgsl_mem_entry_put(phys_entry); + return -EINVAL; + } + + ret = sparse_unbind_range(obj, virt_entry); + if (ret) { + kgsl_mem_entry_put(phys_entry); + return -EINVAL; + } + + ret = _sparse_bind(private, virt_entry, obj->virtoffset, + phys_entry, obj->physoffset, obj->size, + obj->flags & KGSL_SPARSE_BIND_MULTIPLE_TO_PHYS); + if (ret == 0) { + KGSL_STATS_ADD(obj->size, &kgsl_driver.stats.mapped, + &kgsl_driver.stats.mapped_max); + + trace_sparse_bind(virt_entry->id, obj->virtoffset, + phys_entry->id, obj->physoffset, + obj->size, obj->flags); + } + + kgsl_mem_entry_put(phys_entry); + + return ret; +} + +long kgsl_ioctl_sparse_bind(struct kgsl_device_private *dev_priv, + unsigned int cmd, void *data) +{ + struct kgsl_process_private *private = dev_priv->process_priv; + struct kgsl_sparse_bind *param = data; + struct kgsl_sparse_binding_object obj; + struct kgsl_mem_entry *virt_entry; + int pg_sz; + void __user *ptr; + int ret = 0; + int i = 0; + + ptr = (void __user *) (uintptr_t) param->list; + + if (param->size > sizeof(struct kgsl_sparse_binding_object) || + param->count == 0 || ptr == NULL) + return -EINVAL; + + virt_entry = kgsl_sharedmem_find_id_flags(private, param->id, + KGSL_MEMFLAGS_SPARSE_VIRT); + if (virt_entry == NULL) + return -EINVAL; + + pg_sz = kgsl_memdesc_get_pagesize(&virt_entry->memdesc); + + for (i = 0; i < param->count; i++) { + memset(&obj, 0, sizeof(obj)); + ret = _copy_from_user(&obj, ptr, sizeof(obj), param->size); + if (ret) + break; + + /* Sanity check initial range */ + if (obj.size == 0 || + obj.virtoffset + obj.size > virt_entry->memdesc.size || + !(IS_ALIGNED(obj.virtoffset | obj.size, pg_sz))) { + ret = -EINVAL; + break; + } + + if (obj.flags & KGSL_SPARSE_BIND) + ret = sparse_bind_range(private, &obj, virt_entry); + else if (obj.flags & KGSL_SPARSE_UNBIND) + ret = sparse_unbind_range(&obj, virt_entry); + else + ret = -EINVAL; + if (ret) + break; + + ptr += sizeof(obj); + } + + kgsl_mem_entry_put(virt_entry); + + return ret; +} + long kgsl_ioctl_gpuobj_info(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data) { @@ -3356,6 +3915,13 @@ get_mmap_entry(struct kgsl_process_private *private, goto err_put; } + if (entry->memdesc.flags & KGSL_MEMFLAGS_SPARSE_PHYS) { + if (len != entry->memdesc.size) { + ret = -EINVAL; + goto err_put; + } + } + if (entry->memdesc.useraddr != 0) { ret = -EBUSY; goto err_put; diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index ee7149e1fd41..25f5de6ce645 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -184,6 +184,7 @@ struct kgsl_memdesc_ops { * @attrs: dma attributes for this memory * @pages: An array of pointers to allocated pages * @page_count: Total number of pages allocated + * @cur_bindings: Number of sparse pages actively bound */ struct kgsl_memdesc { struct kgsl_pagetable *pagetable; @@ -202,6 +203,7 @@ struct kgsl_memdesc { struct dma_attrs attrs; struct page **pages; unsigned int page_count; + unsigned int cur_bindings; }; /* @@ -235,6 +237,8 @@ struct kgsl_memdesc { * @dev_priv: back pointer to the device file that created this entry. * @metadata: String containing user specified metadata for the entry * @work: Work struct used to schedule a kgsl_mem_entry_put in atomic contexts + * @bind_lock: Lock for sparse memory bindings + * @bind_tree: RB Tree for sparse memory bindings */ struct kgsl_mem_entry { struct kref refcount; @@ -246,6 +250,8 @@ struct kgsl_mem_entry { int pending_free; char metadata[KGSL_GPUOBJ_ALLOC_METADATA_MAX + 1]; struct work_struct work; + spinlock_t bind_lock; + struct rb_root bind_tree; }; struct kgsl_device_private; @@ -315,6 +321,24 @@ struct kgsl_protected_registers { int range; }; +/** + * struct sparse_bind_object - Bind metadata + * @node: Node for the rb tree + * @p_memdesc: Physical memdesc bound to + * @v_off: Offset of bind in the virtual entry + * @p_off: Offset of bind in the physical memdesc + * @size: Size of the bind + * @flags: Flags for the bind + */ +struct sparse_bind_object { + struct rb_node node; + struct kgsl_memdesc *p_memdesc; + uint64_t v_off; + uint64_t p_off; + uint64_t size; + uint64_t flags; +}; + long kgsl_ioctl_device_getproperty(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data); long kgsl_ioctl_device_setproperty(struct kgsl_device_private *dev_priv, @@ -377,6 +401,19 @@ long kgsl_ioctl_gpu_command(struct kgsl_device_private *dev_priv, long kgsl_ioctl_gpuobj_set_info(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data); +long kgsl_ioctl_sparse_phys_alloc(struct kgsl_device_private *dev_priv, + unsigned int cmd, void *data); +long kgsl_ioctl_sparse_phys_free(struct kgsl_device_private *dev_priv, + unsigned int cmd, void *data); +long kgsl_ioctl_sparse_virt_alloc(struct kgsl_device_private *dev_priv, + unsigned int cmd, void *data); +long kgsl_ioctl_sparse_virt_free(struct kgsl_device_private *dev_priv, + unsigned int cmd, void *data); +long kgsl_ioctl_sparse_bind(struct kgsl_device_private *dev_priv, + unsigned int cmd, void *data); +long kgsl_ioctl_sparse_unbind(struct kgsl_device_private *dev_priv, + unsigned int cmd, void *data); + void kgsl_mem_entry_destroy(struct kref *kref); struct kgsl_mem_entry * __must_check diff --git a/drivers/gpu/msm/kgsl_compat.c b/drivers/gpu/msm/kgsl_compat.c index 248c78b7e5c4..028a9566fa14 100644 --- a/drivers/gpu/msm/kgsl_compat.c +++ b/drivers/gpu/msm/kgsl_compat.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -372,6 +372,16 @@ static const struct kgsl_ioctl kgsl_compat_ioctl_funcs[] = { kgsl_ioctl_gpu_command), KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUOBJ_SET_INFO, kgsl_ioctl_gpuobj_set_info), + KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_PHYS_ALLOC, + kgsl_ioctl_sparse_phys_alloc), + KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_PHYS_FREE, + kgsl_ioctl_sparse_phys_free), + KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_VIRT_ALLOC, + kgsl_ioctl_sparse_virt_alloc), + KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_VIRT_FREE, + kgsl_ioctl_sparse_virt_free), + KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_BIND, + kgsl_ioctl_sparse_bind), }; long kgsl_compat_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c index 93ac790f3a55..df9eb9ebd779 100644 --- a/drivers/gpu/msm/kgsl_debugfs.c +++ b/drivers/gpu/msm/kgsl_debugfs.c @@ -129,10 +129,13 @@ static int print_mem_entry(int id, void *ptr, void *data) { struct seq_file *s = data; struct kgsl_mem_entry *entry = ptr; - char flags[9]; + char flags[10]; char usage[16]; struct kgsl_memdesc *m = &entry->memdesc; + if (m->flags & KGSL_MEMFLAGS_SPARSE_VIRT) + return 0; + flags[0] = kgsl_memdesc_is_global(m) ? 'g' : '-'; flags[1] = '-'; flags[2] = !(m->flags & KGSL_MEMFLAGS_GPUREADONLY) ? 'w' : '-'; @@ -141,7 +144,8 @@ static int print_mem_entry(int id, void *ptr, void *data) flags[5] = kgsl_memdesc_use_cpu_map(m) ? 'p' : '-'; flags[6] = (m->useraddr) ? 'Y' : 'N'; flags[7] = kgsl_memdesc_is_secured(m) ? 's' : '-'; - flags[8] = '\0'; + flags[8] = m->flags & KGSL_MEMFLAGS_SPARSE_PHYS ? 'P' : '-'; + flags[9] = '\0'; kgsl_get_memory_usage(usage, sizeof(usage), m->flags); @@ -211,6 +215,70 @@ static const struct file_operations process_mem_fops = { .release = process_mem_release, }; +static int print_sparse_mem_entry(int id, void *ptr, void *data) +{ + struct seq_file *s = data; + struct kgsl_mem_entry *entry = ptr; + struct kgsl_memdesc *m = &entry->memdesc; + struct rb_node *node; + + if (!(m->flags & KGSL_MEMFLAGS_SPARSE_VIRT)) + return 0; + + node = rb_first(&entry->bind_tree); + + while (node != NULL) { + struct sparse_bind_object *obj = rb_entry(node, + struct sparse_bind_object, node); + seq_printf(s, "%5d %16llx %16llx %16llx %16llx\n", + entry->id, entry->memdesc.gpuaddr, + obj->v_off, obj->size, obj->p_off); + node = rb_next(node); + } + + seq_putc(s, '\n'); + + return 0; +} + +static int process_sparse_mem_print(struct seq_file *s, void *unused) +{ + struct kgsl_process_private *private = s->private; + + seq_printf(s, "%5s %16s %16s %16s %16s\n", + "v_id", "gpuaddr", "v_offset", "v_size", "p_offset"); + + spin_lock(&private->mem_lock); + idr_for_each(&private->mem_idr, print_sparse_mem_entry, s); + spin_unlock(&private->mem_lock); + + return 0; +} + +static int process_sparse_mem_open(struct inode *inode, struct file *file) +{ + int ret; + pid_t pid = (pid_t) (unsigned long) inode->i_private; + struct kgsl_process_private *private = NULL; + + private = kgsl_process_private_find(pid); + + if (!private) + return -ENODEV; + + ret = single_open(file, process_sparse_mem_print, private); + if (ret) + kgsl_process_private_put(private); + + return ret; +} + +static const struct file_operations process_sparse_mem_fops = { + .open = process_sparse_mem_open, + .read = seq_read, + .llseek = seq_lseek, + .release = process_mem_release, +}; /** * kgsl_process_init_debugfs() - Initialize debugfs for a process @@ -251,6 +319,15 @@ void kgsl_process_init_debugfs(struct kgsl_process_private *private) if (IS_ERR_OR_NULL(dentry)) WARN((dentry == NULL), "Unable to create 'mem' file for %s\n", name); + + dentry = debugfs_create_file("sparse_mem", 0444, private->debug_root, + (void *) ((unsigned long) private->pid), + &process_sparse_mem_fops); + + if (IS_ERR_OR_NULL(dentry)) + WARN((dentry == NULL), + "Unable to create 'sparse_mem' file for %s\n", name); + } void kgsl_core_debugfs_init(void) diff --git a/drivers/gpu/msm/kgsl_ioctl.c b/drivers/gpu/msm/kgsl_ioctl.c index 0802e94f56ad..894e6a4a146b 100644 --- a/drivers/gpu/msm/kgsl_ioctl.c +++ b/drivers/gpu/msm/kgsl_ioctl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -90,6 +90,16 @@ static const struct kgsl_ioctl kgsl_ioctl_funcs[] = { kgsl_ioctl_gpu_command), KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUOBJ_SET_INFO, kgsl_ioctl_gpuobj_set_info), + KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_PHYS_ALLOC, + kgsl_ioctl_sparse_phys_alloc), + KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_PHYS_FREE, + kgsl_ioctl_sparse_phys_free), + KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_VIRT_ALLOC, + kgsl_ioctl_sparse_virt_alloc), + KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_VIRT_FREE, + kgsl_ioctl_sparse_virt_free), + KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_BIND, + kgsl_ioctl_sparse_bind), }; long kgsl_ioctl_copy_in(unsigned int kernel_cmd, unsigned int user_cmd, diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index b467ef81d257..166bb68e64a1 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -323,8 +323,8 @@ static int _iommu_map_sync_pc(struct kgsl_pagetable *pt, _unlock_if_secure_mmu(memdesc, pt->mmu); if (ret) { - KGSL_CORE_ERR("map err: %p, 0x%016llX, 0x%llx, 0x%x, %d\n", - iommu_pt->domain, gpuaddr, size, flags, ret); + KGSL_CORE_ERR("map err: 0x%016llX, 0x%llx, 0x%x, %d\n", + gpuaddr, size, flags, ret); return -ENODEV; } @@ -351,8 +351,8 @@ static int _iommu_unmap_sync_pc(struct kgsl_pagetable *pt, _unlock_if_secure_mmu(memdesc, pt->mmu); if (unmapped != size) { - KGSL_CORE_ERR("unmap err: %p, 0x%016llx, 0x%llx, %zd\n", - iommu_pt->domain, addr, size, unmapped); + KGSL_CORE_ERR("unmap err: 0x%016llx, 0x%llx, %zd\n", + addr, size, unmapped); return -ENODEV; } @@ -421,8 +421,9 @@ static int _iommu_map_sg_offset_sync_pc(struct kgsl_pagetable *pt, if (size != 0) { /* Cleanup on error */ _iommu_unmap_sync_pc(pt, memdesc, addr, mapped); - KGSL_CORE_ERR("map err: %p, 0x%016llX, %d, %x, %zd\n", - iommu_pt->domain, addr, nents, flags, mapped); + KGSL_CORE_ERR( + "map sg offset err: 0x%016llX, %d, %x, %zd\n", + addr, nents, flags, mapped); return -ENODEV; } @@ -451,8 +452,8 @@ static int _iommu_map_sg_sync_pc(struct kgsl_pagetable *pt, _unlock_if_secure_mmu(memdesc, pt->mmu); if (mapped == 0) { - KGSL_CORE_ERR("map err: %p, 0x%016llX, %d, %x, %zd\n", - iommu_pt->domain, addr, nents, flags, mapped); + KGSL_CORE_ERR("map sg err: 0x%016llX, %d, %x, %zd\n", + addr, nents, flags, mapped); return -ENODEV; } @@ -467,6 +468,13 @@ static int _iommu_map_sg_sync_pc(struct kgsl_pagetable *pt, static struct page *kgsl_guard_page; static struct kgsl_memdesc kgsl_secure_guard_page_memdesc; +/* + * The dummy page is a placeholder/extra page to be used for sparse mappings. + * This page will be mapped to all virtual sparse bindings that are not + * physically backed. + */ +static struct page *kgsl_dummy_page; + /* These functions help find the nearest allocated memory entries on either side * of a faulting address. If we know the nearby allocations memory we can * get a better determination of what we think should have been located in the @@ -1309,6 +1317,11 @@ static void kgsl_iommu_close(struct kgsl_mmu *mmu) kgsl_guard_page = NULL; } + if (kgsl_dummy_page != NULL) { + __free_page(kgsl_dummy_page); + kgsl_dummy_page = NULL; + } + kgsl_iommu_remove_global(mmu, &iommu->setstate); kgsl_sharedmem_free(&iommu->setstate); kgsl_cleanup_qdss_desc(mmu); @@ -1523,6 +1536,8 @@ kgsl_iommu_unmap_offset(struct kgsl_pagetable *pt, struct kgsl_memdesc *memdesc, uint64_t addr, uint64_t offset, uint64_t size) { + if (size == 0 || (size + offset) > kgsl_memdesc_footprint(memdesc)) + return -EINVAL; /* * All GPU addresses as assigned are page aligned, but some * functions perturb the gpuaddr with an offset, so apply the @@ -1530,9 +1545,8 @@ kgsl_iommu_unmap_offset(struct kgsl_pagetable *pt, */ addr = PAGE_ALIGN(addr); - - if (size == 0 || addr == 0) - return 0; + if (addr == 0) + return -EINVAL; return _iommu_unmap_sync_pc(pt, memdesc, addr + offset, size); } @@ -1540,13 +1554,11 @@ kgsl_iommu_unmap_offset(struct kgsl_pagetable *pt, static int kgsl_iommu_unmap(struct kgsl_pagetable *pt, struct kgsl_memdesc *memdesc) { - uint64_t size = memdesc->size; - - if (kgsl_memdesc_has_guard_page(memdesc)) - size += kgsl_memdesc_guard_page_size(pt->mmu, memdesc); + if (memdesc->size == 0 || memdesc->gpuaddr == 0) + return -EINVAL; return kgsl_iommu_unmap_offset(pt, memdesc, memdesc->gpuaddr, 0, - size); + kgsl_memdesc_footprint(memdesc)); } /** @@ -1593,7 +1605,7 @@ static int _iommu_map_guard_page(struct kgsl_pagetable *pt, } else { if (kgsl_guard_page == NULL) { kgsl_guard_page = alloc_page(GFP_KERNEL | __GFP_ZERO | - __GFP_HIGHMEM); + __GFP_NORETRY | __GFP_HIGHMEM); if (kgsl_guard_page == NULL) return -ENOMEM; } @@ -1602,7 +1614,7 @@ static int _iommu_map_guard_page(struct kgsl_pagetable *pt, } return _iommu_map_sync_pc(pt, memdesc, gpuaddr, physaddr, - kgsl_memdesc_guard_page_size(pt->mmu, memdesc), + kgsl_memdesc_guard_page_size(memdesc), protflags & ~IOMMU_WRITE); } @@ -1658,6 +1670,100 @@ done: return ret; } +static int kgsl_iommu_sparse_dummy_map(struct kgsl_pagetable *pt, + struct kgsl_memdesc *memdesc, uint64_t offset, uint64_t size) +{ + int ret = 0, i; + struct page **pages = NULL; + struct sg_table sgt; + int count = size >> PAGE_SHIFT; + + /* verify the offset is within our range */ + if (size + offset > memdesc->size) + return -EINVAL; + + if (kgsl_dummy_page == NULL) { + kgsl_dummy_page = alloc_page(GFP_KERNEL | __GFP_ZERO | + __GFP_HIGHMEM); + if (kgsl_dummy_page == NULL) + return -ENOMEM; + } + + pages = kcalloc(count, sizeof(struct page *), GFP_KERNEL); + if (pages == NULL) + return -ENOMEM; + + for (i = 0; i < count; i++) + pages[i] = kgsl_dummy_page; + + ret = sg_alloc_table_from_pages(&sgt, pages, count, + 0, size, GFP_KERNEL); + if (ret == 0) { + ret = _iommu_map_sg_sync_pc(pt, memdesc->gpuaddr + offset, + memdesc, sgt.sgl, sgt.nents, + IOMMU_READ | IOMMU_NOEXEC); + sg_free_table(&sgt); + } + + kfree(pages); + + return ret; +} + +static int _map_to_one_page(struct kgsl_pagetable *pt, uint64_t addr, + struct kgsl_memdesc *memdesc, uint64_t physoffset, + uint64_t size, unsigned int map_flags) +{ + int ret = 0, i; + int pg_sz = kgsl_memdesc_get_pagesize(memdesc); + int count = size >> PAGE_SHIFT; + struct page *page = NULL; + struct page **pages = NULL; + struct sg_page_iter sg_iter; + struct sg_table sgt; + + /* Find our physaddr offset addr */ + if (memdesc->pages != NULL) + page = memdesc->pages[physoffset >> PAGE_SHIFT]; + else { + for_each_sg_page(memdesc->sgt->sgl, &sg_iter, + memdesc->sgt->nents, physoffset >> PAGE_SHIFT) { + page = sg_page_iter_page(&sg_iter); + break; + } + } + + if (page == NULL) + return -EINVAL; + + pages = kcalloc(count, sizeof(struct page *), GFP_KERNEL); + if (pages == NULL) + return -ENOMEM; + + for (i = 0; i < count; i++) { + if (pg_sz != PAGE_SIZE) { + struct page *tmp_page = page; + int j; + + for (j = 0; j < 16; j++, tmp_page += PAGE_SIZE) + pages[i++] = tmp_page; + } else + pages[i] = page; + } + + ret = sg_alloc_table_from_pages(&sgt, pages, count, + 0, size, GFP_KERNEL); + if (ret == 0) { + ret = _iommu_map_sg_sync_pc(pt, addr, memdesc, sgt.sgl, + sgt.nents, map_flags); + sg_free_table(&sgt); + } + + kfree(pages); + + return ret; +} + static int kgsl_iommu_map_offset(struct kgsl_pagetable *pt, uint64_t virtaddr, uint64_t virtoffset, struct kgsl_memdesc *memdesc, uint64_t physoffset, @@ -1668,13 +1774,17 @@ static int kgsl_iommu_map_offset(struct kgsl_pagetable *pt, int ret; struct sg_table *sgt = NULL; - pg_sz = (1 << kgsl_memdesc_get_align(memdesc)); + pg_sz = kgsl_memdesc_get_pagesize(memdesc); if (!IS_ALIGNED(virtaddr | virtoffset | physoffset | size, pg_sz)) return -EINVAL; if (size == 0) return -EINVAL; + if (!(feature_flag & KGSL_SPARSE_BIND_MULTIPLE_TO_PHYS) && + size + physoffset > kgsl_memdesc_footprint(memdesc)) + return -EINVAL; + /* * For paged memory allocated through kgsl, memdesc->pages is not NULL. * Allocate sgt here just for its map operation. Contiguous memory @@ -1688,9 +1798,13 @@ static int kgsl_iommu_map_offset(struct kgsl_pagetable *pt, if (IS_ERR(sgt)) return PTR_ERR(sgt); - ret = _iommu_map_sg_offset_sync_pc(pt, virtaddr + virtoffset, - memdesc, sgt->sgl, sgt->nents, - physoffset, size, protflags); + if (feature_flag & KGSL_SPARSE_BIND_MULTIPLE_TO_PHYS) + ret = _map_to_one_page(pt, virtaddr + virtoffset, + memdesc, physoffset, size, protflags); + else + ret = _iommu_map_sg_offset_sync_pc(pt, virtaddr + virtoffset, + memdesc, sgt->sgl, sgt->nents, + physoffset, size, protflags); if (memdesc->pages != NULL) kgsl_free_sgt(sgt); @@ -2152,8 +2266,7 @@ static int kgsl_iommu_get_gpuaddr(struct kgsl_pagetable *pagetable, { struct kgsl_iommu_pt *pt = pagetable->priv; int ret = 0; - uint64_t addr, start, end; - uint64_t size = memdesc->size; + uint64_t addr, start, end, size; unsigned int align; BUG_ON(kgsl_memdesc_use_cpu_map(memdesc)); @@ -2162,8 +2275,7 @@ static int kgsl_iommu_get_gpuaddr(struct kgsl_pagetable *pagetable, pagetable->name != KGSL_MMU_SECURE_PT) return -EINVAL; - if (kgsl_memdesc_has_guard_page(memdesc)) - size += kgsl_memdesc_guard_page_size(pagetable->mmu, memdesc); + size = kgsl_memdesc_footprint(memdesc); align = 1 << kgsl_memdesc_get_align(memdesc); @@ -2445,4 +2557,5 @@ static struct kgsl_mmu_pt_ops iommu_pt_ops = { .addr_in_range = kgsl_iommu_addr_in_range, .mmu_map_offset = kgsl_iommu_map_offset, .mmu_unmap_offset = kgsl_iommu_unmap_offset, + .mmu_sparse_dummy_map = kgsl_iommu_sparse_dummy_map, }; diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c index 8b0d93fda32c..10f6b8049d36 100644 --- a/drivers/gpu/msm/kgsl_mmu.c +++ b/drivers/gpu/msm/kgsl_mmu.c @@ -386,29 +386,24 @@ int kgsl_mmu_map(struct kgsl_pagetable *pagetable, struct kgsl_memdesc *memdesc) { - int ret = 0; int size; if (!memdesc->gpuaddr) return -EINVAL; - /* Only global mappings should be mapped multiple times */ - if (!kgsl_memdesc_is_global(memdesc) && - (KGSL_MEMDESC_MAPPED & memdesc->priv)) - return -EINVAL; size = kgsl_memdesc_footprint(memdesc); - if (PT_OP_VALID(pagetable, mmu_map)) - ret = pagetable->pt_ops->mmu_map(pagetable, memdesc); - - if (ret) - return ret; + if (PT_OP_VALID(pagetable, mmu_map)) { + int ret; - atomic_inc(&pagetable->stats.entries); - KGSL_STATS_ADD(size, &pagetable->stats.mapped, - &pagetable->stats.max_mapped); + ret = pagetable->pt_ops->mmu_map(pagetable, memdesc); + if (ret) + return ret; - memdesc->priv |= KGSL_MEMDESC_MAPPED; + atomic_inc(&pagetable->stats.entries); + KGSL_STATS_ADD(size, &pagetable->stats.mapped, + &pagetable->stats.max_mapped); + } return 0; } @@ -455,22 +450,22 @@ int kgsl_mmu_unmap(struct kgsl_pagetable *pagetable, struct kgsl_memdesc *memdesc) { - uint64_t size; - - if (memdesc->size == 0 || memdesc->gpuaddr == 0 || - !(KGSL_MEMDESC_MAPPED & memdesc->priv)) + if (memdesc->size == 0) return -EINVAL; - size = kgsl_memdesc_footprint(memdesc); + if (PT_OP_VALID(pagetable, mmu_unmap)) { + int ret; + uint64_t size; - if (PT_OP_VALID(pagetable, mmu_unmap)) - pagetable->pt_ops->mmu_unmap(pagetable, memdesc); + size = kgsl_memdesc_footprint(memdesc); - atomic_dec(&pagetable->stats.entries); - atomic_long_sub(size, &pagetable->stats.mapped); + ret = pagetable->pt_ops->mmu_unmap(pagetable, memdesc); + if (ret) + return ret; - if (!kgsl_memdesc_is_global(memdesc)) - memdesc->priv &= ~KGSL_MEMDESC_MAPPED; + atomic_dec(&pagetable->stats.entries); + atomic_long_sub(size, &pagetable->stats.mapped); + } return 0; } @@ -481,11 +476,20 @@ int kgsl_mmu_map_offset(struct kgsl_pagetable *pagetable, struct kgsl_memdesc *memdesc, uint64_t physoffset, uint64_t size, uint64_t flags) { - if (PT_OP_VALID(pagetable, mmu_map_offset)) - return pagetable->pt_ops->mmu_map_offset(pagetable, virtaddr, + if (PT_OP_VALID(pagetable, mmu_map_offset)) { + int ret; + + ret = pagetable->pt_ops->mmu_map_offset(pagetable, virtaddr, virtoffset, memdesc, physoffset, size, flags); + if (ret) + return ret; + + atomic_inc(&pagetable->stats.entries); + KGSL_STATS_ADD(size, &pagetable->stats.mapped, + &pagetable->stats.max_mapped); + } - return -EINVAL; + return 0; } EXPORT_SYMBOL(kgsl_mmu_map_offset); @@ -493,14 +497,41 @@ int kgsl_mmu_unmap_offset(struct kgsl_pagetable *pagetable, struct kgsl_memdesc *memdesc, uint64_t addr, uint64_t offset, uint64_t size) { - if (PT_OP_VALID(pagetable, mmu_unmap_offset)) - return pagetable->pt_ops->mmu_unmap_offset(pagetable, memdesc, + if (PT_OP_VALID(pagetable, mmu_unmap_offset)) { + int ret; + + ret = pagetable->pt_ops->mmu_unmap_offset(pagetable, memdesc, addr, offset, size); + if (ret) + return ret; + + atomic_dec(&pagetable->stats.entries); + atomic_long_sub(size, &pagetable->stats.mapped); + } - return -EINVAL; + return 0; } EXPORT_SYMBOL(kgsl_mmu_unmap_offset); +int kgsl_mmu_sparse_dummy_map(struct kgsl_pagetable *pagetable, + struct kgsl_memdesc *memdesc, uint64_t offset, uint64_t size) +{ + if (PT_OP_VALID(pagetable, mmu_sparse_dummy_map)) { + int ret; + + ret = pagetable->pt_ops->mmu_sparse_dummy_map(pagetable, + memdesc, offset, size); + if (ret) + return ret; + + atomic_dec(&pagetable->stats.entries); + atomic_long_sub(size, &pagetable->stats.mapped); + } + + return 0; +} +EXPORT_SYMBOL(kgsl_mmu_sparse_dummy_map); + void kgsl_mmu_remove_global(struct kgsl_device *device, struct kgsl_memdesc *memdesc) { diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h index 588777af353f..53645cc1741c 100644 --- a/drivers/gpu/msm/kgsl_mmu.h +++ b/drivers/gpu/msm/kgsl_mmu.h @@ -106,6 +106,9 @@ struct kgsl_mmu_pt_ops { int (*mmu_unmap_offset)(struct kgsl_pagetable *pt, struct kgsl_memdesc *memdesc, uint64_t addr, uint64_t offset, uint64_t size); + int (*mmu_sparse_dummy_map)(struct kgsl_pagetable *pt, + struct kgsl_memdesc *memdesc, uint64_t offset, + uint64_t size); }; /* @@ -230,6 +233,9 @@ int kgsl_mmu_unmap_offset(struct kgsl_pagetable *pagetable, struct kgsl_memdesc *kgsl_mmu_get_qdss_global_entry(struct kgsl_device *device); +int kgsl_mmu_sparse_dummy_map(struct kgsl_pagetable *pagetable, + struct kgsl_memdesc *memdesc, uint64_t offset, uint64_t size); + /* * Static inline functions of MMU that simply call the SMMU specific * function using a function pointer. These functions can be thought diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h index c05aaecb5284..565ae4c39fdd 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.h +++ b/drivers/gpu/msm/kgsl_sharedmem.h @@ -92,6 +92,18 @@ kgsl_memdesc_get_align(const struct kgsl_memdesc *memdesc) } /* + * kgsl_memdesc_get_pagesize - Get pagesize based on alignment + * @memdesc - the memdesc + * + * Returns the pagesize based on memdesc alignment + */ +static inline int +kgsl_memdesc_get_pagesize(const struct kgsl_memdesc *memdesc) +{ + return (1 << kgsl_memdesc_get_align(memdesc)); +} + +/* * kgsl_memdesc_get_cachemode - Get cache mode of a memdesc * @memdesc: the memdesc * @@ -211,12 +223,19 @@ kgsl_memdesc_has_guard_page(const struct kgsl_memdesc *memdesc) * * Returns guard page size */ -static inline int -kgsl_memdesc_guard_page_size(const struct kgsl_mmu *mmu, - const struct kgsl_memdesc *memdesc) +static inline uint64_t +kgsl_memdesc_guard_page_size(const struct kgsl_memdesc *memdesc) { - return kgsl_memdesc_is_secured(memdesc) ? mmu->secure_align_mask + 1 : - PAGE_SIZE; + if (!kgsl_memdesc_has_guard_page(memdesc)) + return 0; + + if (kgsl_memdesc_is_secured(memdesc)) { + if (memdesc->pagetable != NULL && + memdesc->pagetable->mmu != NULL) + return memdesc->pagetable->mmu->secure_align_mask + 1; + } + + return PAGE_SIZE; } /* @@ -241,10 +260,7 @@ kgsl_memdesc_use_cpu_map(const struct kgsl_memdesc *memdesc) static inline uint64_t kgsl_memdesc_footprint(const struct kgsl_memdesc *memdesc) { - uint64_t size = memdesc->size; - if (kgsl_memdesc_has_guard_page(memdesc)) - size += SZ_4K; - return size; + return memdesc->size + kgsl_memdesc_guard_page_size(memdesc); } /* diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c index 69ae2e3fd2d7..f9d3ede718ab 100644 --- a/drivers/gpu/msm/kgsl_snapshot.c +++ b/drivers/gpu/msm/kgsl_snapshot.c @@ -313,6 +313,13 @@ int kgsl_snapshot_get_object(struct kgsl_snapshot *snapshot, goto err_put; } + /* Do not save sparse memory */ + if (entry->memdesc.flags & KGSL_MEMFLAGS_SPARSE_VIRT || + entry->memdesc.flags & KGSL_MEMFLAGS_SPARSE_PHYS) { + ret = 0; + goto err_put; + } + /* * size indicates the number of bytes in the region to save. This might * not always be the entire size of the region because some buffers are diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h index 8988dc12839f..bac09175cf12 100644 --- a/drivers/gpu/msm/kgsl_trace.h +++ b/drivers/gpu/msm/kgsl_trace.h @@ -1102,6 +1102,100 @@ TRACE_EVENT(kgsl_msg, ) ); +DECLARE_EVENT_CLASS(sparse_alloc_template, + TP_PROTO(unsigned int id, uint64_t size, unsigned int pagesize), + TP_ARGS(id, size, pagesize), + TP_STRUCT__entry( + __field(unsigned int, id) + __field(uint64_t, size) + __field(unsigned int, pagesize) + ), + TP_fast_assign( + __entry->id = id; + __entry->size = size; + __entry->pagesize = pagesize; + ), + TP_printk("id=%d size=0x%llX pagesize=0x%X", + __entry->id, __entry->size, __entry->pagesize) +); + +DEFINE_EVENT(sparse_alloc_template, sparse_phys_alloc, + TP_PROTO(unsigned int id, uint64_t size, unsigned int pagesize), + TP_ARGS(id, size, pagesize) +); + +DEFINE_EVENT(sparse_alloc_template, sparse_virt_alloc, + TP_PROTO(unsigned int id, uint64_t size, unsigned int pagesize), + TP_ARGS(id, size, pagesize) +); + +DECLARE_EVENT_CLASS(sparse_free_template, + TP_PROTO(unsigned int id), + TP_ARGS(id), + TP_STRUCT__entry( + __field(unsigned int, id) + ), + TP_fast_assign( + __entry->id = id; + ), + TP_printk("id=%d", __entry->id) +); + +DEFINE_EVENT(sparse_free_template, sparse_phys_free, + TP_PROTO(unsigned int id), + TP_ARGS(id) +); + +DEFINE_EVENT(sparse_free_template, sparse_virt_free, + TP_PROTO(unsigned int id), + TP_ARGS(id) +); + +TRACE_EVENT(sparse_bind, + TP_PROTO(unsigned int v_id, uint64_t v_off, + unsigned int p_id, uint64_t p_off, + uint64_t size, uint64_t flags), + TP_ARGS(v_id, v_off, p_id, p_off, size, flags), + TP_STRUCT__entry( + __field(unsigned int, v_id) + __field(uint64_t, v_off) + __field(unsigned int, p_id) + __field(uint64_t, p_off) + __field(uint64_t, size) + __field(uint64_t, flags) + ), + TP_fast_assign( + __entry->v_id = v_id; + __entry->v_off = v_off; + __entry->p_id = p_id; + __entry->p_off = p_off; + __entry->size = size; + __entry->flags = flags; + ), + TP_printk( + "v_id=%d v_off=0x%llX p_id=%d p_off=0x%llX size=0x%llX flags=0x%llX", + __entry->v_id, __entry->v_off, + __entry->p_id, __entry->p_off, + __entry->size, __entry->flags) +); + +TRACE_EVENT(sparse_unbind, + TP_PROTO(unsigned int v_id, uint64_t v_off, uint64_t size), + TP_ARGS(v_id, v_off, size), + TP_STRUCT__entry( + __field(unsigned int, v_id) + __field(uint64_t, v_off) + __field(uint64_t, size) + ), + TP_fast_assign( + __entry->v_id = v_id; + __entry->v_off = v_off; + __entry->size = size; + ), + TP_printk("v_id=%d v_off=0x%llX size=0x%llX", + __entry->v_id, __entry->v_off, __entry->size) +); + #endif /* _KGSL_TRACE_H */ diff --git a/drivers/iommu/dma-mapping-fast.c b/drivers/iommu/dma-mapping-fast.c index c28b8df4194e..ea8db1a431d0 100644 --- a/drivers/iommu/dma-mapping-fast.c +++ b/drivers/iommu/dma-mapping-fast.c @@ -14,6 +14,7 @@ #include <linux/dma-mapping.h> #include <linux/dma-mapping-fast.h> #include <linux/io-pgtable-fast.h> +#include <linux/vmalloc.h> #include <asm/cacheflush.h> #include <asm/dma-iommu.h> @@ -512,6 +513,33 @@ static void fast_smmu_free(struct device *dev, size_t size, __fast_smmu_free_pages(pages, count); } +static int fast_smmu_mmap_attrs(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, + size_t size, struct dma_attrs *attrs) +{ + struct vm_struct *area; + unsigned long uaddr = vma->vm_start; + struct page **pages; + int i, nr_pages, ret = 0; + + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + + area = find_vm_area(cpu_addr); + if (!area) + return -EINVAL; + + pages = area->pages; + nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; + for (i = vma->vm_pgoff; i < nr_pages && uaddr < vma->vm_end; i++) { + ret = vm_insert_page(vma, uaddr, pages[i]); + if (ret) + break; + uaddr += PAGE_SIZE; + } + + return ret; +} + static int fast_smmu_dma_supported(struct device *dev, u64 mask) { return mask <= 0xffffffff; @@ -559,6 +587,7 @@ static int fast_smmu_notify(struct notifier_block *self, static const struct dma_map_ops fast_smmu_dma_ops = { .alloc = fast_smmu_alloc, .free = fast_smmu_free, + .mmap = fast_smmu_mmap_attrs, .map_page = fast_smmu_map_page, .unmap_page = fast_smmu_unmap_page, .map_sg = fast_smmu_map_sg, diff --git a/drivers/iommu/msm_dma_iommu_mapping.c b/drivers/iommu/msm_dma_iommu_mapping.c index b91c7785df0b..e26b79959b13 100644 --- a/drivers/iommu/msm_dma_iommu_mapping.c +++ b/drivers/iommu/msm_dma_iommu_mapping.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -267,6 +267,7 @@ int msm_dma_map_sg_attrs(struct device *dev, struct scatterlist *sg, int nents, return ret; } +EXPORT_SYMBOL(msm_dma_map_sg_attrs); static void msm_iommu_meta_destroy(struct kref *kref) { @@ -343,6 +344,7 @@ void msm_dma_unmap_sg(struct device *dev, struct scatterlist *sgl, int nents, out: return; } +EXPORT_SYMBOL(msm_dma_unmap_sg); /* * Only to be called by ION code when a buffer is freed diff --git a/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c b/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c index 7f5e49809a26..8da079d9d0c8 100644 --- a/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c +++ b/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c @@ -24,6 +24,7 @@ #include <linux/module.h> #include <linux/of_platform.h> #include <linux/msm-bus.h> +#include <linux/clk/msm-clk.h> #include "cam_soc_api.h" struct msm_cam_bus_pscale_data { @@ -454,6 +455,17 @@ long msm_camera_clk_set_rate(struct device *dev, } EXPORT_SYMBOL(msm_camera_clk_set_rate); +int msm_camera_set_clk_flags(struct clk *clk, unsigned long flags) +{ + if (!clk) + return -EINVAL; + + CDBG("clk : %p, flags : %ld\n", clk, flags); + + return clk_set_flags(clk, flags); +} +EXPORT_SYMBOL(msm_camera_set_clk_flags); + /* release memory allocated for clocks */ static int msm_camera_put_clk_info_internal(struct device *dev, struct msm_cam_clk_info **clk_info, diff --git a/drivers/media/platform/msm/camera_v2/common/cam_soc_api.h b/drivers/media/platform/msm/camera_v2/common/cam_soc_api.h index d1eeab92773f..b4494d4d6bab 100644 --- a/drivers/media/platform/msm/camera_v2/common/cam_soc_api.h +++ b/drivers/media/platform/msm/camera_v2/common/cam_soc_api.h @@ -188,6 +188,18 @@ long msm_camera_clk_set_rate(struct device *dev, struct clk *clk, long clk_rate); /** + * @brief : Sets flags of a clock + * + * This function will set the flags for a specified clock + * + * @param clk : Pointer to clock to set flags for + * @param flags : The flags to set + * + * @return Status of operation. + */ + +int msm_camera_set_clk_flags(struct clk *clk, unsigned long flags); +/** * @brief : Gets regulator info * * This function extracts the regulator information for a specific @@ -200,6 +212,7 @@ long msm_camera_clk_set_rate(struct device *dev, * * @return Status of operation. Negative in case of error. Zero otherwise. */ + int msm_camera_get_regulator_info(struct platform_device *pdev, struct msm_cam_regulator **vdd_info, int *num_reg); /** diff --git a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c index 98afe4cd3074..a56e42dc1c6f 100644 --- a/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c +++ b/drivers/media/platform/msm/camera_v2/fd/msm_fd_dev.c @@ -22,6 +22,7 @@ #include <media/v4l2-ioctl.h> #include <media/v4l2-event.h> #include <media/videobuf2-v4l2.h> +#include <linux/clk/msm-clk.h> #include "msm_fd_dev.h" #include "msm_fd_hw.h" @@ -1203,6 +1204,7 @@ static int fd_probe(struct platform_device *pdev) { struct msm_fd_device *fd; int ret; + int i; /* Face detection device struct */ fd = kzalloc(sizeof(struct msm_fd_device), GFP_KERNEL); @@ -1237,6 +1239,19 @@ static int fd_probe(struct platform_device *pdev) goto error_get_clocks; } + /*set memcore and mem periphery logic flags to 0*/ + for (i = 0; i < fd->clk_num; i++) { + if ((strcmp(fd->clk_info[i].clk_name, + "mmss_fd_core_clk") == 0) || + (strcmp(fd->clk_info[i].clk_name, + "mmss_fd_core_uar_clk") == 0)) { + msm_camera_set_clk_flags(fd->clk[i], + CLKFLAG_NORETAIN_MEM); + msm_camera_set_clk_flags(fd->clk[i], + CLKFLAG_NORETAIN_PERIPH); + } + } + ret = msm_camera_register_bus_client(pdev, CAM_BUS_CLIENT_FD); if (ret < 0) { dev_err(&pdev->dev, "Fail to get bus\n"); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c index ffcd88dc44f3..a792404c243c 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c @@ -12,6 +12,7 @@ #include <linux/module.h> #include <linux/ratelimit.h> +#include <linux/clk/msm-clk.h> #include "msm_isp_util.h" #include "msm_isp_axi_util.h" @@ -198,6 +199,18 @@ static int msm_vfe48_get_clks(struct vfe_device *vfe_dev) if (strcmp(vfe_dev->vfe_clk_info[i].clk_name, "mnoc_maxi_clk") == 0) vfe_dev->vfe_clk_info[i].clk_rate = INIT_RATE; + /* set no memory retention */ + if (strcmp(vfe_dev->vfe_clk_info[i].clk_name, + "camss_vfe_clk") == 0 || + strcmp(vfe_dev->vfe_clk_info[i].clk_name, + "camss_csi_vfe_clk") == 0 || + strcmp(vfe_dev->vfe_clk_info[i].clk_name, + "camss_vfe_vbif_axi_clk") == 0) { + msm_camera_set_clk_flags(vfe_dev->vfe_clk[i], + CLKFLAG_NORETAIN_MEM); + msm_camera_set_clk_flags(vfe_dev->vfe_clk[i], + CLKFLAG_NORETAIN_PERIPH); + } } return 0; } diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index 8721fc18eaa8..ac2d508269a4 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -184,6 +184,7 @@ int msm_isp_validate_axi_request(struct msm_vfe_axi_shared_data *axi_data, case V4L2_PIX_FMT_P16RGGB10: case V4L2_PIX_FMT_JPEG: case V4L2_PIX_FMT_META: + case V4L2_PIX_FMT_META10: case V4L2_PIX_FMT_GREY: stream_info->num_planes = 1; stream_info->format_factor = ISP_Q2; @@ -288,6 +289,7 @@ static uint32_t msm_isp_axi_get_plane_size( case V4L2_PIX_FMT_QGBRG10: case V4L2_PIX_FMT_QGRBG10: case V4L2_PIX_FMT_QRGGB10: + case V4L2_PIX_FMT_META10: /* TODO: fix me */ size = plane_cfg[plane_idx].output_height * plane_cfg[plane_idx].output_width; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c index 5e24b146619d..e47a8de30aa9 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c @@ -1396,6 +1396,7 @@ int msm_isp_cal_word_per_line(uint32_t output_format, case V4L2_PIX_FMT_SGBRG10DPCM8: case V4L2_PIX_FMT_SGRBG10DPCM8: case V4L2_PIX_FMT_SRGGB10DPCM8: + case V4L2_PIX_FMT_META10: val = CAL_WORD(pixel_per_line, 5, 32); break; case V4L2_PIX_FMT_SBGGR12: @@ -1581,6 +1582,8 @@ int msm_isp_get_bit_per_pixel(uint32_t output_format) case V4L2_PIX_FMT_P16GBRG10: case V4L2_PIX_FMT_P16GRBG10: case V4L2_PIX_FMT_P16RGGB10: + case V4L2_PIX_FMT_META10: + case MSM_V4L2_PIX_FMT_META10: return 10; case V4L2_PIX_FMT_SBGGR12: case V4L2_PIX_FMT_SGBRG12: diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c index 266a5a6be2a2..d56d246b3c91 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_platform.c @@ -319,6 +319,7 @@ err_reg_enable: int msm_jpeg_platform_setup(struct msm_jpeg_device *pgmn_dev) { int rc = -1; + int i; struct resource *jpeg_irq_res; void *jpeg_base, *vbif_base; struct platform_device *pdev = pgmn_dev->pdev; @@ -356,6 +357,19 @@ int msm_jpeg_platform_setup(struct msm_jpeg_device *pgmn_dev) goto err_jpeg_clk; } + /*set memcore and mem periphery logic flags to 0*/ + for (i = 0; i < pgmn_dev->num_clk; i++) { + if ((strcmp(pgmn_dev->jpeg_clk_info[i].clk_name, + "core_clk") == 0) || + (strcmp(pgmn_dev->jpeg_clk_info[i].clk_name, + "mmss_camss_jpeg_axi_clk") == 0)) { + msm_camera_set_clk_flags(pgmn_dev->jpeg_clk[i], + CLKFLAG_NORETAIN_MEM); + msm_camera_set_clk_flags(pgmn_dev->jpeg_clk[i], + CLKFLAG_NORETAIN_PERIPH); + } + } + /* get all the regulators information */ rc = msm_camera_get_regulator_info(pdev, &pgmn_dev->jpeg_vdd, &pgmn_dev->num_reg); diff --git a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c index b8840115b674..63d7e715162b 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_dma/msm_jpeg_dma_dev.c @@ -24,6 +24,7 @@ #include <media/videobuf2-core.h> #include <media/v4l2-mem2mem.h> #include <media/msm_jpeg_dma.h> +#include <linux/clk/msm-clk.h> #include "msm_jpeg_dma_dev.h" #include "msm_jpeg_dma_hw.h" @@ -1258,6 +1259,7 @@ static int jpegdma_probe(struct platform_device *pdev) { struct msm_jpegdma_device *jpegdma; int ret; + int i; dev_dbg(&pdev->dev, "jpeg v4l2 DMA probed\n"); /* Jpeg dma device struct */ @@ -1293,6 +1295,19 @@ static int jpegdma_probe(struct platform_device *pdev) if (ret < 0) goto error_get_clocks; + /*set memcore and mem periphery logic flags to 0*/ + for (i = 0; i < jpegdma->num_clk; i++) { + if ((strcmp(jpegdma->jpeg_clk_info[i].clk_name, + "core_clk") == 0) || + (strcmp(jpegdma->jpeg_clk_info[i].clk_name, + "mmss_camss_jpeg_axi_clk") == 0)) { + msm_camera_set_clk_flags(jpegdma->clk[i], + CLKFLAG_NORETAIN_MEM); + msm_camera_set_clk_flags(jpegdma->clk[i], + CLKFLAG_NORETAIN_PERIPH); + } + } + ret = msm_jpegdma_hw_get_qos(jpegdma); if (ret < 0) goto error_qos_get; diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c index 5a1e99adc7f3..f4add41c85c9 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c @@ -25,6 +25,7 @@ #include <linux/timer.h> #include <linux/kernel.h> #include <linux/workqueue.h> +#include <linux/clk/msm-clk.h> #include <media/v4l2-event.h> #include <media/v4l2-ioctl.h> #include <media/msmb_camera.h> @@ -788,13 +789,6 @@ static int cpp_init_hardware(struct cpp_device *cpp_dev) int rc = 0; uint32_t vbif_version; - rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CPP, - CAM_AHB_SVS_VOTE); - if (rc < 0) { - pr_err("%s: failed to vote for AHB\n", __func__); - goto ahb_vote_fail; - } - rc = msm_camera_regulator_enable(cpp_dev->cpp_vdd, cpp_dev->num_reg, true); if (rc < 0) { @@ -817,6 +811,13 @@ static int cpp_init_hardware(struct cpp_device *cpp_dev) goto clk_failed; } + rc = cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CPP, + CAM_AHB_SVS_VOTE); + if (rc < 0) { + pr_err("%s: failed to vote for AHB\n", __func__); + goto ahb_vote_fail; + } + if (cpp_dev->state != CPP_STATE_BOOT) { rc = msm_camera_register_irq(cpp_dev->pdev, cpp_dev->irq, msm_cpp_irq, IRQF_TRIGGER_RISING, "cpp", cpp_dev); @@ -880,16 +881,16 @@ static int cpp_init_hardware(struct cpp_device *cpp_dev) pwr_collapse_reset: msm_cpp_update_gdscr_status(cpp_dev, false); req_irq_fail: + if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CPP, + CAM_AHB_SUSPEND_VOTE) < 0) + pr_err("%s: failed to remove vote for AHB\n", __func__); +ahb_vote_fail: msm_camera_clk_enable(&cpp_dev->pdev->dev, cpp_dev->clk_info, cpp_dev->cpp_clk, cpp_dev->num_clks, false); clk_failed: msm_camera_regulator_enable(cpp_dev->cpp_vdd, cpp_dev->num_reg, false); reg_enable_failed: - if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CPP, - CAM_AHB_SUSPEND_VOTE) < 0) - pr_err("%s: failed to remove vote for AHB\n", __func__); -ahb_vote_fail: return rc; } @@ -903,6 +904,9 @@ static void cpp_release_hardware(struct cpp_device *cpp_dev) } msm_cpp_delete_buff_queue(cpp_dev); msm_cpp_update_gdscr_status(cpp_dev, false); + if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CPP, + CAM_AHB_SUSPEND_VOTE) < 0) + pr_err("%s: failed to remove vote for AHB\n", __func__); msm_camera_clk_enable(&cpp_dev->pdev->dev, cpp_dev->clk_info, cpp_dev->cpp_clk, cpp_dev->num_clks, false); msm_camera_regulator_enable(cpp_dev->cpp_vdd, cpp_dev->num_reg, false); @@ -912,9 +916,6 @@ static void cpp_release_hardware(struct cpp_device *cpp_dev) } cpp_dev->stream_cnt = 0; - if (cam_config_ahb_clk(NULL, 0, CAM_AHB_CLIENT_CPP, - CAM_AHB_SUSPEND_VOTE) < 0) - pr_err("%s: failed to remove vote for AHB\n", __func__); } static int32_t cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin) @@ -3932,6 +3933,7 @@ static int cpp_probe(struct platform_device *pdev) { struct cpp_device *cpp_dev; int rc = 0; + int i = 0; CPP_DBG("E"); cpp_dev = kzalloc(sizeof(struct cpp_device), GFP_KERNEL); @@ -4000,6 +4002,21 @@ static int cpp_probe(struct platform_device *pdev) goto mem_err; } + /* set memcore and mem periphery logic flags to 0 */ + for (i = 0; i < cpp_dev->num_clks; i++) { + if ((strcmp(cpp_dev->clk_info[i].clk_name, + "cpp_core_clk") == 0) || + (strcmp(cpp_dev->clk_info[i].clk_name, + "camss_cpp_axi_clk") == 0) || + (strcmp(cpp_dev->clk_info[i].clk_name, + "micro_iface_clk") == 0)) { + msm_camera_set_clk_flags(cpp_dev->cpp_clk[i], + CLKFLAG_NORETAIN_MEM); + msm_camera_set_clk_flags(cpp_dev->cpp_clk[i], + CLKFLAG_NORETAIN_PERIPH); + } + } + rc = msm_camera_get_regulator_info(pdev, &cpp_dev->cpp_vdd, &cpp_dev->num_reg); if (rc < 0) { diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c index c12e95d3310a..d0ce1de1162a 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c +++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c @@ -846,9 +846,14 @@ static int32_t msm_flash_get_pmic_source_info( "qcom,current", &fctrl->torch_op_current[i]); if (rc < 0) { - pr_err("current: read failed\n"); - of_node_put(torch_src_node); - continue; + rc = of_property_read_u32(torch_src_node, + "qcom,current-ma", + &fctrl->torch_op_current[i]); + if (rc < 0) { + pr_err("current: read failed\n"); + of_node_put(torch_src_node); + continue; + } } /* Read max-current */ @@ -915,6 +920,14 @@ static int32_t msm_flash_get_dt_data(struct device_node *of_node, fctrl->flash_driver_type = FLASH_DRIVER_I2C; } + /* Read the flash and torch source info from device tree node */ + rc = msm_flash_get_pmic_source_info(of_node, fctrl); + if (rc < 0) { + pr_err("%s:%d msm_flash_get_pmic_source_info failed rc %d\n", + __func__, __LINE__, rc); + return rc; + } + /* Read the gpio information from device tree */ rc = msm_sensor_driver_get_gpio_data( &(fctrl->power_info.gpio_conf), of_node); @@ -929,13 +942,6 @@ static int32_t msm_flash_get_dt_data(struct device_node *of_node, CDBG("%s:%d fctrl->flash_driver_type = %d", __func__, __LINE__, fctrl->flash_driver_type); - /* Read the flash and torch source info from device tree node */ - rc = msm_flash_get_pmic_source_info(of_node, fctrl); - if (rc < 0) { - pr_err("%s:%d msm_flash_get_pmic_source_info failed rc %d\n", - __func__, __LINE__, rc); - return rc; - } return rc; } diff --git a/drivers/media/platform/msm/vidc/Kconfig b/drivers/media/platform/msm/vidc/Kconfig index c9773555165e..ae451ff60c54 100644 --- a/drivers/media/platform/msm/vidc/Kconfig +++ b/drivers/media/platform/msm/vidc/Kconfig @@ -3,7 +3,7 @@ # menuconfig MSM_VIDC_V4L2 - bool "Qualcomm MSM V4L2 based video driver" + tristate "Qualcomm MSM V4L2 based video driver" depends on ARCH_QCOM && VIDEO_V4L2 select VIDEOBUF2_CORE diff --git a/drivers/media/platform/msm/vidc/Makefile b/drivers/media/platform/msm/vidc/Makefile index ff355611c0d0..55c2d2e8d30b 100644 --- a/drivers/media/platform/msm/vidc/Makefile +++ b/drivers/media/platform/msm/vidc/Makefile @@ -1,17 +1,21 @@ -obj-$(CONFIG_MSM_VIDC_V4L2) := msm_v4l2_vidc.o \ - msm_vidc_common.o \ - msm_vidc.o \ - msm_vdec.o \ - msm_venc.o \ - msm_smem.o \ - msm_vidc_debug.o \ - msm_vidc_res_parse.o \ - venus_hfi.o \ - hfi_response_handler.o \ - hfi_packetization.o \ - vidc_hfi.o \ - venus_boot.o \ - msm_vidc_dcvs.o +ccflags-y += -I$(srctree)/drivers/media/platform/msm/vidc/ + +msm-vidc-objs := msm_v4l2_vidc.o \ + msm_vidc_common.o \ + msm_vidc.o \ + msm_vdec.o \ + msm_venc.o \ + msm_smem.o \ + msm_vidc_debug.o \ + msm_vidc_res_parse.o \ + venus_hfi.o \ + hfi_response_handler.o \ + hfi_packetization.o \ + vidc_hfi.o \ + venus_boot.o \ + msm_vidc_dcvs.o + +obj-$(CONFIG_MSM_VIDC_V4L2) := msm-vidc.o obj-$(CONFIG_MSM_VIDC_V4L2) += governors/ diff --git a/drivers/media/platform/msm/vidc/governors/Kconfig b/drivers/media/platform/msm/vidc/governors/Kconfig index 32362217e0b9..d667d65d5338 100644 --- a/drivers/media/platform/msm/vidc/governors/Kconfig +++ b/drivers/media/platform/msm/vidc/governors/Kconfig @@ -1,5 +1,5 @@ menuconfig MSM_VIDC_GOVERNORS - bool "Clock and bandwidth governors for QTI MSM V4L2 based video driver" + tristate "Clock and bandwidth governors for QTI MSM V4L2 based video driver" depends on MSM_VIDC_V4L2 && PM_DEVFREQ help Chooses a set of devfreq governors aimed at providing accurate bandwidth diff --git a/drivers/media/platform/msm/vidc/governors/Makefile b/drivers/media/platform/msm/vidc/governors/Makefile index e5b2f9d7a049..06a4d3452f14 100644 --- a/drivers/media/platform/msm/vidc/governors/Makefile +++ b/drivers/media/platform/msm/vidc/governors/Makefile @@ -1,5 +1,9 @@ ccflags-y := -I$(srctree)/drivers/devfreq/ \ - -I$(srctree)/drivers/media/platform/msm/vidc/ + -I$(srctree)/drivers/media/platform/msm/vidc/ \ + -I$(srctree)/drivers/media/platform/msm/vidc/governors/ -obj-$(CONFIG_MSM_VIDC_GOVERNORS) := msm_vidc_dyn_gov.o \ - msm_vidc_table_gov.o +msm-vidc-dyn-gov-objs := msm_vidc_dyn_gov.o + +msm-vidc-table-gov-objs := msm_vidc_table_gov.o + +obj-$(CONFIG_MSM_VIDC_GOVERNORS) := msm-vidc-dyn-gov.o msm-vidc-table-gov.o diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c index 0d6a0caa86c8..58a7d0d0577a 100644 --- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c @@ -781,3 +781,5 @@ static void __exit msm_vidc_exit(void) module_init(msm_vidc_init); module_exit(msm_vidc_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index c08084a54e86..55ee7e02973c 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -2702,7 +2702,7 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) (inst->fmts[CAPTURE_PORT]->fourcc == V4L2_PIX_FMT_HEVC); if (is_cont_intra_supported) { - if (air_mbs || air_ref || cir_mbs) + if (ctrl->val != HAL_INTRA_REFRESH_NONE) enable.enable = true; else enable.enable = false; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c index 7976d6e8a603..1928327b60db 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c @@ -16,7 +16,11 @@ #include "vidc_hfi_api.h" int msm_vidc_debug = VIDC_ERR | VIDC_WARN; +EXPORT_SYMBOL(msm_vidc_debug); + int msm_vidc_debug_out = VIDC_OUT_PRINTK; +EXPORT_SYMBOL(msm_vidc_debug_out); + int msm_vidc_fw_debug = 0x18; int msm_vidc_fw_debug_mode = 1; int msm_vidc_fw_low_power_mode = 1; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c index 2bb91ccc6c26..240dc0caf94d 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c @@ -25,6 +25,7 @@ enum clock_properties { CLOCK_PROP_HAS_SCALING = 1 << 0, + CLOCK_PROP_HAS_MEM_RETENTION = 1 << 1, }; static int msm_vidc_populate_legacy_context_bank( struct msm_vidc_platform_resources *res); @@ -364,6 +365,7 @@ int msm_vidc_load_u32_table(struct platform_device *pdev, return rc; } +EXPORT_SYMBOL(msm_vidc_load_u32_table); static int msm_vidc_load_platform_version_table( struct msm_vidc_platform_resources *res) @@ -943,6 +945,11 @@ static int msm_vidc_load_clock_table( vc->has_scaling = false; } + if (clock_props[c] & CLOCK_PROP_HAS_MEM_RETENTION) + vc->has_mem_retention = true; + else + vc->has_mem_retention = false; + dprintk(VIDC_DBG, "Found clock %s: scale-able = %s\n", vc->name, vc->count ? "yes" : "no"); } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h index c61605c7e405..734586a3f76c 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h @@ -104,6 +104,7 @@ struct clock_info { struct load_freq_table *load_freq_tbl; u32 count; bool has_scaling; + bool has_mem_retention; }; struct clock_set { diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 50c0eb351d4f..217d6a48d17a 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -738,6 +738,7 @@ bool venus_hfi_is_session_supported(unsigned long sessions_supported, { return __is_session_supported(sessions_supported, session_type); } +EXPORT_SYMBOL(venus_hfi_is_session_supported); static int __devfreq_target(struct device *devfreq_dev, unsigned long *freq, u32 flags) @@ -2191,8 +2192,6 @@ static int venus_hfi_core_init(void *device) INIT_LIST_HEAD(&dev->sess_head); - __set_registers(dev); - if (!dev->hal_client) { dev->hal_client = msm_smem_new_client( SMEM_ION, dev->res, MSM_VIDC_UNKNOWN); @@ -3788,6 +3787,22 @@ static inline int __prepare_enable_clks(struct venus_hfi_device *device) if (cl->has_scaling) clk_set_rate(cl->clk, clk_round_rate(cl->clk, 0)); + if (cl->has_mem_retention) { + rc = clk_set_flags(cl->clk, CLKFLAG_NORETAIN_PERIPH); + if (rc) { + dprintk(VIDC_WARN, + "Failed set flag NORETAIN_PERIPH %s\n", + cl->name); + } + + rc = clk_set_flags(cl->clk, CLKFLAG_NORETAIN_MEM); + if (rc) { + dprintk(VIDC_WARN, + "Failed set flag NORETAIN_MEM %s\n", + cl->name); + } + } + rc = clk_prepare_enable(cl->clk); if (rc) { dprintk(VIDC_ERR, "Failed to enable clocks\n"); @@ -4177,6 +4192,13 @@ static int __venus_power_on(struct venus_hfi_device *device) "Failed to scale clocks, performance might be affected\n"); rc = 0; } + + /* + * Re-program all of the registers that get reset as a result of + * regulator_disable() and _enable() + */ + __set_registers(device); + __write_register(device, VIDC_WRAPPER_INTR_MASK, VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK); device->intr_status = 0; @@ -4291,11 +4313,6 @@ static inline int __resume(struct venus_hfi_device *device) goto err_set_video_state; } - /* - * Re-program all of the registers that get reset as a result of - * regulator_disable() and _enable() - */ - __set_registers(device); __setup_ucregion_memory_map(device); /* Wait for boot completion */ rc = __boot_firmware(device); diff --git a/drivers/media/platform/msm/vidc/vmem/Kconfig b/drivers/media/platform/msm/vidc/vmem/Kconfig index e602e52da383..6f54120e2d04 100644 --- a/drivers/media/platform/msm/vidc/vmem/Kconfig +++ b/drivers/media/platform/msm/vidc/vmem/Kconfig @@ -1,3 +1,3 @@ menuconfig MSM_VIDC_VMEM - bool "Qualcomm Technologies Inc MSM VMEM driver" + tristate "Qualcomm Technologies Inc MSM VMEM driver" depends on ARCH_QCOM && MSM_VIDC_V4L2 diff --git a/drivers/media/platform/msm/vidc/vmem/Makefile b/drivers/media/platform/msm/vidc/vmem/Makefile index 713b92e64544..a56ad95f8b71 100644 --- a/drivers/media/platform/msm/vidc/vmem/Makefile +++ b/drivers/media/platform/msm/vidc/vmem/Makefile @@ -1,2 +1,7 @@ -obj-$(CONFIG_MSM_VIDC_VMEM) := vmem.o \ - vmem_debugfs.o +ccflags-y += -I$(srctree)/drivers/media/platform/msm/vidc/ +ccflags-y += -I$(srctree)/drivers/media/platform/msm/vidc/vmem/ + +msm-vidc-vmem-objs := vmem.o \ + vmem_debugfs.o + +obj-$(CONFIG_MSM_VIDC_VMEM) := msm-vidc-vmem.o diff --git a/drivers/media/platform/msm/vidc/vmem/vmem.c b/drivers/media/platform/msm/vidc/vmem/vmem.c index 3a2ac31c6450..165c5c0b4e4b 100644 --- a/drivers/media/platform/msm/vidc/vmem/vmem.c +++ b/drivers/media/platform/msm/vidc/vmem/vmem.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -15,6 +15,7 @@ #include <linux/bitops.h> #include <linux/clk.h> +#include <linux/clk/msm-clk.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/io.h> @@ -111,6 +112,7 @@ struct vmem { struct { const char *name; struct clk *clk; + bool has_mem_retention; } *clocks; int num_clocks; struct { @@ -186,6 +188,21 @@ static inline int __power_on(struct vmem *v) pr_debug("Enabled regulator vdd\n"); for (c = 0; c < v->num_clocks; ++c) { + if (v->clocks[c].has_mem_retention) { + rc = clk_set_flags(v->clocks[c].clk, + CLKFLAG_NORETAIN_PERIPH); + if (rc) { + pr_warn("Failed set flag NORETAIN_PERIPH %s\n", + v->clocks[c].name); + } + rc = clk_set_flags(v->clocks[c].clk, + CLKFLAG_NORETAIN_MEM); + if (rc) { + pr_warn("Failed set flag NORETAIN_MEM %s\n", + v->clocks[c].name); + } + } + rc = clk_prepare_enable(v->clocks[c].clk); if (rc) { pr_err("Failed to enable %s clock (%d)\n", @@ -355,6 +372,7 @@ int vmem_allocate(size_t size, phys_addr_t *addr) exit: return rc; } +EXPORT_SYMBOL(vmem_allocate); /** * vmem_free: - Frees the memory allocated via vmem_allocate. Undefined @@ -384,6 +402,7 @@ void vmem_free(phys_addr_t to_free) __power_off(vmem); atomic_dec(&vmem->alloc_count); } +EXPORT_SYMBOL(vmem_free); struct vmem_interrupt_cookie { struct vmem *vmem; @@ -448,6 +467,7 @@ static inline int __init_resources(struct vmem *v, struct platform_device *pdev) { int rc = 0, c = 0; + int *clock_props = NULL; v->irq = platform_get_irq(pdev, 0); if (v->irq < 0) { @@ -504,6 +524,21 @@ static inline int __init_resources(struct vmem *v, goto exit; } + clock_props = devm_kzalloc(&pdev->dev, + v->num_clocks * sizeof(*clock_props), + GFP_KERNEL); + if (!clock_props) { + pr_err("Failed to allocate clock config table\n"); + goto exit; + } + + rc = of_property_read_u32_array(pdev->dev.of_node, "clock-config", + clock_props, v->num_clocks); + if (rc) { + pr_err("Failed to read clock config\n"); + goto exit; + } + for (c = 0; c < v->num_clocks; ++c) { const char *name = NULL; struct clk *temp = NULL; @@ -519,6 +554,7 @@ static inline int __init_resources(struct vmem *v, v->clocks[c].clk = temp; v->clocks[c].name = name; + v->clocks[c].has_mem_retention = clock_props[c]; } v->vdd = devm_regulator_get(&pdev->dev, "vdd"); @@ -699,3 +735,5 @@ static void __exit vmem_exit(void) module_init(vmem_init); module_exit(vmem_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/msm/vidc/vmem/vmem.h b/drivers/media/platform/msm/vidc/vmem/vmem.h index 751904e00755..2f3a26db086b 100644 --- a/drivers/media/platform/msm/vidc/vmem/vmem.h +++ b/drivers/media/platform/msm/vidc/vmem/vmem.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2014, 2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -14,7 +14,7 @@ #ifndef __VMEM_H__ #define __VMEM_H__ -#ifdef CONFIG_MSM_VIDC_VMEM +#if (defined CONFIG_MSM_VIDC_VMEM) || (defined CONFIG_MSM_VIDC_VMEM_MODULE) int vmem_allocate(size_t size, phys_addr_t *addr); void vmem_free(phys_addr_t to_free); diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c index 1b93c83ae98e..0c5754341991 100644 --- a/drivers/mfd/wcd9xxx-irq.c +++ b/drivers/mfd/wcd9xxx-irq.c @@ -741,6 +741,7 @@ static int wcd9xxx_irq_remove(struct platform_device *pdev) wmb(); irq_domain_remove(data->domain); kfree(data); + domain->host_data = NULL; return 0; } diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 84932513f008..0acebc87ec20 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -796,14 +796,13 @@ static inline void early_init_dt_check_for_initrd(unsigned long node) #endif /* CONFIG_BLK_DEV_INITRD */ #ifdef CONFIG_SERIAL_EARLYCON -extern struct of_device_id __earlycon_of_table[]; static int __init early_init_dt_scan_chosen_serial(void) { int offset; const char *p; int l; - const struct of_device_id *match = __earlycon_of_table; + const struct earlycon_id *match; const void *fdt = initial_boot_params; offset = fdt_path_offset(fdt, "/chosen"); @@ -826,19 +825,20 @@ static int __init early_init_dt_scan_chosen_serial(void) if (offset < 0) return -ENODEV; - while (match->compatible[0]) { + for (match = __earlycon_table; match < __earlycon_table_end; match++) { u64 addr; - if (fdt_node_check_compatible(fdt, offset, match->compatible)) { - match++; + if (!match->compatible[0]) + continue; + + if (fdt_node_check_compatible(fdt, offset, match->compatible)) continue; - } addr = fdt_translate_address(fdt, offset); if (addr == OF_BAD_ADDR) return -ENXIO; - of_setup_earlycon(addr, match->data); + of_setup_earlycon(addr, match->setup); return 0; } return -ENODEV; diff --git a/drivers/regulator/cprh-kbss-regulator.c b/drivers/regulator/cprh-kbss-regulator.c index dfdd6921fed5..1c444d6d2607 100644 --- a/drivers/regulator/cprh-kbss-regulator.c +++ b/drivers/regulator/cprh-kbss-regulator.c @@ -184,13 +184,25 @@ static const struct cpr3_fuse_param msmcobalt_kbss_speed_bin_param[] = { /* * Open loop voltage fuse reference voltages in microvolts for MSMCOBALT v1 */ -static const int msmcobalt_kbss_fuse_ref_volt[MSMCOBALT_KBSS_FUSE_CORNERS] = { +static const int +msmcobalt_v1_kbss_fuse_ref_volt[MSMCOBALT_KBSS_FUSE_CORNERS] = { 696000, 768000, 896000, 1112000, }; +/* + * Open loop voltage fuse reference voltages in microvolts for MSMCOBALT v2 + */ +static const int +msmcobalt_v2_kbss_fuse_ref_volt[MSMCOBALT_KBSS_FUSE_CORNERS] = { + 688000, + 756000, + 828000, + 1056000, +}; + #define MSMCOBALT_KBSS_FUSE_STEP_VOLT 10000 #define MSMCOBALT_KBSS_VOLTAGE_FUSE_SIZE 6 #define MSMCOBALT_KBSS_QUOT_OFFSET_SCALE 5 @@ -357,9 +369,10 @@ static int cprh_msmcobalt_kbss_calculate_open_loop_voltages( { struct device_node *node = vreg->of_node; struct cprh_msmcobalt_kbss_fuses *fuse = vreg->platform_fuses; - int i, j, rc = 0; + int i, j, soc_revision, rc = 0; bool allow_interpolation; u64 freq_low, volt_low, freq_high, volt_high; + const int *ref_volt; int *fuse_volt; int *fmax_corner; @@ -372,9 +385,17 @@ static int cprh_msmcobalt_kbss_calculate_open_loop_voltages( goto done; } + soc_revision = vreg->thread->ctrl->soc_revision; + if (soc_revision == 1) + ref_volt = msmcobalt_v1_kbss_fuse_ref_volt; + else if (soc_revision == 2) + ref_volt = msmcobalt_v2_kbss_fuse_ref_volt; + else + ref_volt = msmcobalt_v2_kbss_fuse_ref_volt; + for (i = 0; i < vreg->fuse_corner_count; i++) { fuse_volt[i] = cpr3_convert_open_loop_voltage_fuse( - msmcobalt_kbss_fuse_ref_volt[i], + ref_volt[i], MSMCOBALT_KBSS_FUSE_STEP_VOLT, fuse->init_voltage[i], MSMCOBALT_KBSS_VOLTAGE_FUSE_SIZE); @@ -1366,14 +1387,27 @@ static int cprh_kbss_regulator_resume(struct platform_device *pdev) return cpr3_regulator_resume(ctrl); } +/* Data corresponds to the SoC revision */ static struct of_device_id cprh_regulator_match_table[] = { - { .compatible = "qcom,cprh-msmcobalt-kbss-regulator", }, + { + .compatible = "qcom,cprh-msmcobalt-v1-kbss-regulator", + .data = (void *)(uintptr_t)1 + }, + { + .compatible = "qcom,cprh-msmcobalt-v2-kbss-regulator", + .data = (void *)(uintptr_t)2 + }, + { + .compatible = "qcom,cprh-msmcobalt-kbss-regulator", + .data = (void *)(uintptr_t)2 + }, {} }; static int cprh_kbss_regulator_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + const struct of_device_id *match; struct cpr3_controller *ctrl; int rc; @@ -1397,6 +1431,12 @@ static int cprh_kbss_regulator_probe(struct platform_device *pdev) return rc; } + match = of_match_node(cprh_regulator_match_table, dev->of_node); + if (match) + ctrl->soc_revision = (uintptr_t)match->data; + else + cpr3_err(ctrl, "could not find compatible string match\n"); + rc = cpr3_map_fuse_base(ctrl, pdev); if (rc) { cpr3_err(ctrl, "could not map fuse base address\n"); diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index e8a9751fa266..16ca3eaee61b 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -201,6 +201,8 @@ static struct icnss_data { struct dma_iommu_mapping *smmu_mapping; dma_addr_t smmu_iova_start; size_t smmu_iova_len; + dma_addr_t smmu_iova_ipa_start; + size_t smmu_iova_ipa_len; struct clk *smmu_clk; struct qmi_handle *wlfw_clnt; struct list_head event_list; @@ -1727,6 +1729,66 @@ int icnss_get_irq(int ce_id) } EXPORT_SYMBOL(icnss_get_irq); +struct dma_iommu_mapping *icnss_smmu_get_mapping(struct device *dev) +{ + struct icnss_data *priv = dev_get_drvdata(dev); + + if (!priv) { + icnss_pr_err("Invalid drvdata: dev %p, data %p\n", + dev, priv); + return NULL; + } + + return priv->smmu_mapping; +} +EXPORT_SYMBOL(icnss_smmu_get_mapping); + +int icnss_smmu_map(struct device *dev, + phys_addr_t paddr, uint32_t *iova_addr, size_t size) +{ + struct icnss_data *priv = dev_get_drvdata(dev); + unsigned long iova; + size_t len; + int ret = 0; + + if (!priv) { + icnss_pr_err("Invalid drvdata: dev %p, data %p\n", + dev, priv); + return -EINVAL; + } + + if (!iova_addr) { + icnss_pr_err("iova_addr is NULL, paddr %pa, size %zu", + &paddr, size); + return -EINVAL; + } + + len = roundup(size + paddr - rounddown(paddr, PAGE_SIZE), PAGE_SIZE); + iova = roundup(penv->smmu_iova_ipa_start, PAGE_SIZE); + + if (iova >= priv->smmu_iova_ipa_start + priv->smmu_iova_ipa_len) { + icnss_pr_err("No IOVA space to map, iova %lx, smmu_iova_ipa_start %pad, smmu_iova_ipa_len %zu", + iova, + &priv->smmu_iova_ipa_start, + priv->smmu_iova_ipa_len); + return -ENOMEM; + } + + ret = iommu_map(priv->smmu_mapping->domain, iova, + rounddown(paddr, PAGE_SIZE), len, + IOMMU_READ | IOMMU_WRITE); + if (ret) { + icnss_pr_err("PA to IOVA mapping failed, ret %d!", ret); + return ret; + } + + priv->smmu_iova_ipa_start = iova + len; + *iova_addr = (uint32_t)(iova + paddr - rounddown(paddr, PAGE_SIZE)); + + return 0; +} +EXPORT_SYMBOL(icnss_smmu_map); + static struct clk *icnss_clock_init(struct device *dev, const char *cname) { struct clk *c; @@ -2272,7 +2334,6 @@ static void icnss_debugfs_destroy(struct icnss_data *priv) static int icnss_probe(struct platform_device *pdev) { int ret = 0; - u32 smmu_iova_address[2]; struct resource *res; int i; struct device *dev = &pdev->dev; @@ -2367,11 +2428,29 @@ static int icnss_probe(struct platform_device *pdev) goto unmap_mpm_config; } - if (of_property_read_u32_array(pdev->dev.of_node, - "qcom,wlan-smmu-iova-address", - smmu_iova_address, 2) == 0) { - penv->smmu_iova_start = smmu_iova_address[0]; - penv->smmu_iova_len = smmu_iova_address[1]; + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "smmu_iova_base"); + if (!res) { + icnss_pr_err("SMMU IOVA base not found\n"); + } else { + penv->smmu_iova_start = res->start; + penv->smmu_iova_len = resource_size(res); + icnss_pr_dbg("smmu_iova_start: %pa, smmu_iova_len: %zu\n", + &penv->smmu_iova_start, + penv->smmu_iova_len); + + res = platform_get_resource_byname(pdev, + IORESOURCE_MEM, + "smmu_iova_ipa"); + if (!res) { + icnss_pr_err("SMMU IOVA IPA not found\n"); + } else { + penv->smmu_iova_ipa_start = res->start; + penv->smmu_iova_ipa_len = resource_size(res); + icnss_pr_dbg("smmu_iova_ipa_start: %pa, smmu_iova_ipa_len: %zu\n", + &penv->smmu_iova_ipa_start, + penv->smmu_iova_ipa_len); + } ret = icnss_smmu_init(&pdev->dev); if (ret < 0) { diff --git a/drivers/soc/qcom/service-locator.c b/drivers/soc/qcom/service-locator.c index 9426e0751c4a..24018c544b06 100644 --- a/drivers/soc/qcom/service-locator.c +++ b/drivers/soc/qcom/service-locator.c @@ -208,8 +208,8 @@ static int servreg_loc_send_msg(struct msg_desc *req_desc, static int service_locator_send_msg(struct pd_qmi_client_data *pd) { struct msg_desc req_desc, resp_desc; - struct qmi_servreg_loc_get_domain_list_resp_msg_v01 *resp; - struct qmi_servreg_loc_get_domain_list_req_msg_v01 *req; + struct qmi_servreg_loc_get_domain_list_resp_msg_v01 *resp = NULL; + struct qmi_servreg_loc_get_domain_list_req_msg_v01 *req = NULL; int rc; int db_rev_count = 0, domains_read = 0; diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c index fc5688b4bc8c..d85046875d7a 100644 --- a/drivers/soc/qcom/smp2p.c +++ b/drivers/soc/qcom/smp2p.c @@ -1,6 +1,6 @@ /* drivers/soc/qcom/smp2p.c * - * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -214,6 +214,7 @@ static struct smp2p_interrupt_config smp2p_int_cfgs[SMP2P_NUM_PROCS] = { [SMP2P_AUDIO_PROC].name = "lpass", [SMP2P_SENSOR_PROC].name = "dsps", [SMP2P_WIRELESS_PROC].name = "wcnss", + [SMP2P_CDSP_PROC].name = "cdsp", [SMP2P_TZ_PROC].name = "tz", [SMP2P_REMOTE_MOCK_PROC].name = "mock", }; @@ -333,6 +334,9 @@ static int smp2p_get_smem_item_id(int write_pid, int read_pid) case SMP2P_WIRELESS_PROC: ret = SMEM_SMP2P_WIRLESS_BASE + read_pid; break; + case SMP2P_CDSP_PROC: + ret = SMEM_SMP2P_CDSP_BASE + read_pid; + break; case SMP2P_POWER_PROC: ret = SMEM_SMP2P_POWER_BASE + read_pid; break; diff --git a/drivers/soc/qcom/smp2p_private_api.h b/drivers/soc/qcom/smp2p_private_api.h index 4223a2e1bc90..5bff32f8c06a 100644 --- a/drivers/soc/qcom/smp2p_private_api.h +++ b/drivers/soc/qcom/smp2p_private_api.h @@ -1,6 +1,6 @@ /* drivers/soc/qcom/smp2p_private_api.h * - * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -31,7 +31,7 @@ enum { SMP2P_AUDIO_PROC = 2, SMP2P_SENSOR_PROC = 3, SMP2P_WIRELESS_PROC = 4, - SMP2P_RESERVED_PROC_2 = 5, + SMP2P_CDSP_PROC = 5, SMP2P_POWER_PROC = 6, SMP2P_TZ_PROC = 7, /* add new processors here */ diff --git a/drivers/soc/qcom/smp2p_sleepstate.c b/drivers/soc/qcom/smp2p_sleepstate.c index dfebd201eeb0..04b043fbd8ec 100644 --- a/drivers/soc/qcom/smp2p_sleepstate.c +++ b/drivers/soc/qcom/smp2p_sleepstate.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -74,6 +74,7 @@ static int smp2p_sleepstate_probe(struct platform_device *pdev) static struct of_device_id msm_smp2p_slst_match_table[] = { {.compatible = "qcom,smp2pgpio_sleepstate_3_out"}, + {.compatible = "qcom,smp2pgpio-sleepstate-out"}, {}, }; diff --git a/drivers/soc/qcom/smp2p_spinlock_test.c b/drivers/soc/qcom/smp2p_spinlock_test.c index d188bf0702c5..74aac52b5285 100644 --- a/drivers/soc/qcom/smp2p_spinlock_test.c +++ b/drivers/soc/qcom/smp2p_spinlock_test.c @@ -373,6 +373,11 @@ static void smp2p_ut_remote_spinlock_wcnss(struct seq_file *s) smp2p_ut_remote_spinlock_pid(s, SMP2P_WIRELESS_PROC, false); } +static void smp2p_ut_remote_spinlock_cdsp(struct seq_file *s) +{ + smp2p_ut_remote_spinlock_pid(s, SMP2P_CDSP_PROC, false); +} + static void smp2p_ut_remote_spinlock_tz(struct seq_file *s) { smp2p_ut_remote_spinlock_pid(s, SMP2P_TZ_PROC, false); @@ -752,6 +757,11 @@ static void smp2p_ut_remote_spinlock_track_wcnss(struct seq_file *s) smp2p_ut_remote_spinlock_track(s, SMP2P_WIRELESS_PROC); } +static void smp2p_ut_remote_spinlock_track_cdsp(struct seq_file *s) +{ + smp2p_ut_remote_spinlock_track(s, SMP2P_CDSP_PROC); +} + static void smp2p_ut_remote_spinlock_track_tz(struct seq_file *s) { smp2p_ut_remote_spinlock_track(s, SMP2P_TZ_PROC); @@ -782,6 +792,8 @@ static int __init smp2p_debugfs_init(void) smp2p_ut_remote_spinlock_dsps); smp2p_debug_create("ut_remote_spinlock_wcnss", smp2p_ut_remote_spinlock_wcnss); + smp2p_debug_create("ut_remote_spinlock_cdsp", + smp2p_ut_remote_spinlock_cdsp); smp2p_debug_create("ut_remote_spinlock_tz", smp2p_ut_remote_spinlock_tz); smp2p_debug_create("ut_remote_spinlock_rpm", @@ -798,6 +810,8 @@ static int __init smp2p_debugfs_init(void) &smp2p_ut_remote_spinlock_track_dsps); smp2p_debug_create("ut_remote_spinlock_track_wcnss", &smp2p_ut_remote_spinlock_track_wcnss); + smp2p_debug_create("ut_remote_spinlock_track_cdsp", + &smp2p_ut_remote_spinlock_track_cdsp); smp2p_debug_create("ut_remote_spinlock_track_tz", &smp2p_ut_remote_spinlock_track_tz); return 0; diff --git a/drivers/soundwire/swr-wcd-ctrl.c b/drivers/soundwire/swr-wcd-ctrl.c index 2cb60c11e212..266091486bf1 100644 --- a/drivers/soundwire/swr-wcd-ctrl.c +++ b/drivers/soundwire/swr-wcd-ctrl.c @@ -325,6 +325,7 @@ static int swrm_set_ch_map(struct swr_mstr_ctrl *swrm, void *data) GFP_KERNEL); if (!swrm->mstr_port->port) { kfree(swrm->mstr_port); + swrm->mstr_port = NULL; return -ENOMEM; } memcpy(swrm->mstr_port->port, pinfo->port, pinfo->num_port); @@ -476,7 +477,7 @@ static int swrm_read(struct swr_master *master, u8 dev_num, u16 reg_addr, { struct swr_mstr_ctrl *swrm = swr_get_ctrl_data(master); int ret = 0; - int val = 0; + int val; u8 *reg_val = (u8 *)buf; if (!swrm) { @@ -1474,7 +1475,9 @@ static int swrm_remove(struct platform_device *pdev) swrm, SWR_IRQ_FREE); if (swrm->mstr_port) { kfree(swrm->mstr_port->port); + swrm->mstr_port->port = NULL; kfree(swrm->mstr_port); + swrm->mstr_port = NULL; } pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); diff --git a/drivers/staging/android/ion/ion_page_pool.c b/drivers/staging/android/ion/ion_page_pool.c index d549d6271d89..513d015a5ace 100644 --- a/drivers/staging/android/ion/ion_page_pool.c +++ b/drivers/staging/android/ion/ion_page_pool.c @@ -54,8 +54,7 @@ static void ion_page_pool_free_pages(struct ion_page_pool *pool, __free_pages(page, pool->order); } -static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page, - bool prefetch) +static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page) { mutex_lock(&pool->mutex); if (PageHighMem(page)) { @@ -65,15 +64,11 @@ static int ion_page_pool_add(struct ion_page_pool *pool, struct page *page, list_add_tail(&page->lru, &pool->low_items); pool->low_count++; } - if (!prefetch) - pool->nr_unreserved++; - mutex_unlock(&pool->mutex); return 0; } -static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high, - bool prefetch) +static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high) { struct page *page; @@ -87,13 +82,6 @@ static struct page *ion_page_pool_remove(struct ion_page_pool *pool, bool high, pool->low_count--; } - if (prefetch) { - BUG_ON(!pool->nr_unreserved); - pool->nr_unreserved--; - } - pool->nr_unreserved = min_t(int, pool->high_count + pool->low_count, - pool->nr_unreserved); - list_del(&page->lru); return page; } @@ -108,9 +96,9 @@ void *ion_page_pool_alloc(struct ion_page_pool *pool, bool *from_pool) if (mutex_trylock(&pool->mutex)) { if (pool->high_count) - page = ion_page_pool_remove(pool, true, false); + page = ion_page_pool_remove(pool, true); else if (pool->low_count) - page = ion_page_pool_remove(pool, false, false); + page = ion_page_pool_remove(pool, false); mutex_unlock(&pool->mutex); } if (!page) { @@ -120,27 +108,6 @@ void *ion_page_pool_alloc(struct ion_page_pool *pool, bool *from_pool) return page; } -void *ion_page_pool_prefetch(struct ion_page_pool *pool, bool *from_pool) -{ - struct page *page = NULL; - - BUG_ON(!pool); - - *from_pool = true; - - if (mutex_trylock(&pool->mutex)) { - if (pool->high_count && pool->nr_unreserved > 0) - page = ion_page_pool_remove(pool, true, true); - else if (pool->low_count && pool->nr_unreserved > 0) - page = ion_page_pool_remove(pool, false, true); - mutex_unlock(&pool->mutex); - } - if (!page) { - page = ion_page_pool_alloc_pages(pool); - *from_pool = false; - } - return page; -} /* * Tries to allocate from only the specified Pool and returns NULL otherwise */ @@ -152,24 +119,20 @@ void *ion_page_pool_alloc_pool_only(struct ion_page_pool *pool) if (mutex_trylock(&pool->mutex)) { if (pool->high_count) - page = ion_page_pool_remove(pool, true, false); + page = ion_page_pool_remove(pool, true); else if (pool->low_count) - page = ion_page_pool_remove(pool, false, false); + page = ion_page_pool_remove(pool, false); mutex_unlock(&pool->mutex); } return page; } -void ion_page_pool_free(struct ion_page_pool *pool, struct page *page, - bool prefetch) +void ion_page_pool_free(struct ion_page_pool *pool, struct page *page) { int ret; - BUG_ON(pool->order != compound_order(page)); - - ret = ion_page_pool_add(pool, page, prefetch); - /* FIXME? For a secure page, not hyp unassigned in this err path */ + ret = ion_page_pool_add(pool, page); if (ret) ion_page_pool_free_pages(pool, page); } @@ -208,9 +171,9 @@ int ion_page_pool_shrink(struct ion_page_pool *pool, gfp_t gfp_mask, mutex_lock(&pool->mutex); if (pool->low_count) { - page = ion_page_pool_remove(pool, false, false); + page = ion_page_pool_remove(pool, false); } else if (high && pool->high_count) { - page = ion_page_pool_remove(pool, true, false); + page = ion_page_pool_remove(pool, true); } else { mutex_unlock(&pool->mutex); break; @@ -233,10 +196,9 @@ struct ion_page_pool *ion_page_pool_create(struct device *dev, gfp_t gfp_mask, pool->dev = dev; pool->high_count = 0; pool->low_count = 0; - pool->nr_unreserved = 0; INIT_LIST_HEAD(&pool->low_items); INIT_LIST_HEAD(&pool->high_items); - pool->gfp_mask = gfp_mask | __GFP_COMP; + pool->gfp_mask = gfp_mask; pool->order = order; mutex_init(&pool->mutex); plist_node_init(&pool->list, order); diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h index 4f383661258a..69da287c064f 100644 --- a/drivers/staging/android/ion/ion_priv.h +++ b/drivers/staging/android/ion/ion_priv.h @@ -415,8 +415,6 @@ void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr, * struct ion_page_pool - pagepool struct * @high_count: number of highmem items in the pool * @low_count: number of lowmem items in the pool - * @nr_unreserved: number of items in the pool which have not been reserved - * by a prefetch allocation * @high_items: list of highmem items * @low_items: list of lowmem items * @mutex: lock protecting this struct and especially the count @@ -433,7 +431,6 @@ void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr, struct ion_page_pool { int high_count; int low_count; - int nr_unreserved; struct list_head high_items; struct list_head low_items; struct mutex mutex; @@ -448,10 +445,9 @@ struct ion_page_pool *ion_page_pool_create(struct device *dev, gfp_t gfp_mask, void ion_page_pool_destroy(struct ion_page_pool *); void *ion_page_pool_alloc(struct ion_page_pool *, bool *from_pool); void *ion_page_pool_alloc_pool_only(struct ion_page_pool *); -void ion_page_pool_free(struct ion_page_pool *, struct page *, bool prefetch); +void ion_page_pool_free(struct ion_page_pool *, struct page *); void ion_page_pool_free_immediate(struct ion_page_pool *, struct page *); int ion_page_pool_total(struct ion_page_pool *pool, bool high); -void *ion_page_pool_prefetch(struct ion_page_pool *pool, bool *from_pool); #ifdef CONFIG_ION_POOL_CACHE_POLICY static inline void ion_page_pool_alloc_set_cache_policy diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index ff75e1690f59..981cb2f622cb 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -63,6 +63,8 @@ struct ion_system_heap { struct ion_page_pool **uncached_pools; struct ion_page_pool **cached_pools; struct ion_page_pool **secure_pools[VMID_LAST]; + /* Prevents unnecessary page splitting */ + struct mutex split_page_mutex; }; struct page_info { @@ -78,7 +80,6 @@ static struct page *alloc_buffer_page(struct ion_system_heap *heap, bool *from_pool) { bool cached = ion_buffer_cached(buffer); - bool prefetch = buffer->flags & ION_FLAG_POOL_PREFETCH; struct page *page; struct ion_page_pool *pool; int vmid = get_secure_vmid(buffer->flags); @@ -92,10 +93,7 @@ static struct page *alloc_buffer_page(struct ion_system_heap *heap, else pool = heap->cached_pools[order_to_index(order)]; - if (prefetch) - page = ion_page_pool_prefetch(pool, from_pool); - else - page = ion_page_pool_alloc(pool, from_pool); + page = ion_page_pool_alloc(pool, from_pool); } else { gfp_t gfp_mask = low_order_gfp_flags; if (order) @@ -119,7 +117,6 @@ static void free_buffer_page(struct ion_system_heap *heap, unsigned int order) { bool cached = ion_buffer_cached(buffer); - bool prefetch = buffer->flags & ION_FLAG_POOL_PREFETCH; int vmid = get_secure_vmid(buffer->flags); if (!(buffer->flags & ION_FLAG_POOL_FORCE_ALLOC)) { @@ -134,12 +131,65 @@ static void free_buffer_page(struct ion_system_heap *heap, if (buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE) ion_page_pool_free_immediate(pool, page); else - ion_page_pool_free(pool, page, prefetch); + ion_page_pool_free(pool, page); } else { __free_pages(page, order); } } +static struct page *alloc_from_secure_pool_order(struct ion_system_heap *heap, + struct ion_buffer *buffer, + unsigned long order) +{ + int vmid = get_secure_vmid(buffer->flags); + struct ion_page_pool *pool; + + if (!is_secure_vmid_valid(vmid)) + return NULL; + + pool = heap->secure_pools[vmid][order_to_index(order)]; + return ion_page_pool_alloc_pool_only(pool); +} + +static struct page *split_page_from_secure_pool(struct ion_system_heap *heap, + struct ion_buffer *buffer) +{ + int i, j; + struct page *page; + unsigned int order; + + mutex_lock(&heap->split_page_mutex); + + /* + * Someone may have just split a page and returned the unused portion + * back to the pool, so try allocating from the pool one more time + * before splitting. We want to maintain large pages sizes when + * possible. + */ + page = alloc_from_secure_pool_order(heap, buffer, 0); + if (page) + goto got_page; + + for (i = num_orders - 2; i >= 0; i--) { + order = orders[i]; + page = alloc_from_secure_pool_order(heap, buffer, order); + if (!page) + continue; + + split_page(page, order); + break; + } + /* Return the remaining order-0 pages to the pool */ + if (page) + for (j = 1; j < (1 << order); j++) + free_buffer_page(heap, buffer, page + j, 0); + +got_page: + mutex_unlock(&heap->split_page_mutex); + + return page; +} + static struct page_info *alloc_largest_available(struct ion_system_heap *heap, struct ion_buffer *buffer, unsigned long size, @@ -174,6 +224,49 @@ static struct page_info *alloc_largest_available(struct ion_system_heap *heap, return NULL; } + +static struct page_info *alloc_from_pool_preferred( + struct ion_system_heap *heap, struct ion_buffer *buffer, + unsigned long size, unsigned int max_order) +{ + struct page *page; + struct page_info *info; + int i; + + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return NULL; + + for (i = 0; i < num_orders; i++) { + if (size < order_to_size(orders[i])) + continue; + if (max_order < orders[i]) + continue; + + page = alloc_from_secure_pool_order(heap, buffer, orders[i]); + if (!page) + continue; + + info->page = page; + info->order = orders[i]; + info->from_pool = true; + INIT_LIST_HEAD(&info->list); + return info; + } + + page = split_page_from_secure_pool(heap, buffer); + if (page) { + info->page = page; + info->order = 0; + info->from_pool = true; + INIT_LIST_HEAD(&info->list); + return info; + } + + kfree(info); + return alloc_largest_available(heap, buffer, size, max_order); +} + static unsigned int process_info(struct page_info *info, struct scatterlist *sg, struct scatterlist *sg_sync, @@ -236,9 +329,17 @@ static int ion_system_heap_allocate(struct ion_heap *heap, data.size = 0; INIT_LIST_HEAD(&pages); INIT_LIST_HEAD(&pages_from_pool); + while (size_remaining > 0) { - info = alloc_largest_available(sys_heap, buffer, size_remaining, - max_order); + if (is_secure_vmid_valid(vmid)) + info = alloc_from_pool_preferred( + sys_heap, buffer, size_remaining, + max_order); + else + info = alloc_largest_available( + sys_heap, buffer, size_remaining, + max_order); + if (!info) goto err; @@ -452,7 +553,7 @@ out1: /* Restore pages to secure pool */ list_for_each_entry_safe(page, tmp, &pages, lru) { list_del(&page->lru); - ion_page_pool_free(pool, page, false); + ion_page_pool_free(pool, page); } return 0; out2: @@ -692,6 +793,8 @@ struct ion_heap *ion_system_heap_create(struct ion_platform_heap *data) if (ion_system_heap_create_pools(dev, heap->cached_pools)) goto err_create_cached_pools; + mutex_init(&heap->split_page_mutex); + heap->heap.debug_show = ion_system_heap_debug_show; return &heap->heap; diff --git a/drivers/staging/android/ion/ion_system_secure_heap.c b/drivers/staging/android/ion/ion_system_secure_heap.c index 5c0225cd4e24..9570ab520ca2 100644 --- a/drivers/staging/android/ion/ion_system_secure_heap.c +++ b/drivers/staging/android/ion/ion_system_secure_heap.c @@ -151,8 +151,7 @@ static void ion_system_secure_heap_prefetch_work(struct work_struct *work) /* buffer->heap used by free() */ buffer->heap = &secure_heap->heap; - buffer->flags = ION_FLAG_POOL_PREFETCH; - buffer->flags |= vmid_flags; + buffer->flags = vmid_flags; ret = sys_heap->ops->allocate(sys_heap, buffer, size, PAGE_SIZE, 0); if (ret) { diff --git a/drivers/staging/android/uapi/msm_ion.h b/drivers/staging/android/uapi/msm_ion.h index 73b4d1edcaad..b3c29826834e 100644 --- a/drivers/staging/android/uapi/msm_ion.h +++ b/drivers/staging/android/uapi/msm_ion.h @@ -110,8 +110,6 @@ enum cp_mem_usage { */ #define ION_FLAG_POOL_FORCE_ALLOC (1 << 16) -#define ION_FLAG_POOL_PREFETCH (1 << 27) - /** * Deprecated! Please use the corresponding ION_FLAG_* */ @@ -176,7 +174,6 @@ struct ion_prefetch_regions { struct ion_prefetch_data { int heap_id; unsigned long len; - /* Is unsigned long bad? 32bit compiler vs 64 bit compiler*/ struct ion_prefetch_regions __user *regions; unsigned int nr_regions; }; diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 899a77187bde..2a2975c352f4 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -2227,7 +2227,6 @@ static int __init pl011_early_console_setup(struct earlycon_device *device, device->con->write = pl011_early_write; return 0; } -EARLYCON_DECLARE(pl011, pl011_early_console_setup); OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup); #else diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 03ebe401fff7..3a1de5c87cb4 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -576,7 +576,6 @@ static int __init arc_early_console_setup(struct earlycon_device *dev, dev->con->write = arc_early_serial_write; return 0; } -EARLYCON_DECLARE(arc_uart, arc_early_console_setup); OF_EARLYCON_DECLARE(arc_uart, "snps,arc-uart", arc_early_console_setup); #endif /* CONFIG_SERIAL_ARC_CONSOLE */ diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index b5b2f2be6be7..4d2e3e7a40bb 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -19,7 +19,6 @@ #include <linux/io.h> #include <linux/serial_core.h> #include <linux/sizes.h> -#include <linux/mod_devicetable.h> #ifdef CONFIG_FIX_EARLYCON_MEM #include <asm/fixmap.h> @@ -37,13 +36,6 @@ static struct earlycon_device early_console_dev = { .con = &early_con, }; -extern struct earlycon_id __earlycon_table[]; -static const struct earlycon_id __earlycon_table_sentinel - __used __section(__earlycon_table_end); - -static const struct of_device_id __earlycon_of_table_sentinel - __used __section(__earlycon_of_table_end); - static void __iomem * __init earlycon_map(unsigned long paddr, size_t size) { void __iomem *base; @@ -159,7 +151,7 @@ int __init setup_earlycon(char *buf) if (early_con.flags & CON_ENABLED) return -EALREADY; - for (match = __earlycon_table; match->name[0]; match++) { + for (match = __earlycon_table; match < __earlycon_table_end; match++) { size_t len = strlen(match->name); if (strncmp(buf, match->name, len)) diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index edd66bb7bd4c..670eda466438 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -19,33 +19,147 @@ # define SUPPORT_SYSRQ #endif +#include <linux/kernel.h> #include <linux/atomic.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> -#include <linux/hrtimer.h> #include <linux/module.h> #include <linux/io.h> #include <linux/ioport.h> -#include <linux/irq.h> +#include <linux/interrupt.h> #include <linux/init.h> #include <linux/console.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/serial_core.h> -#include <linux/serial.h> #include <linux/slab.h> #include <linux/clk.h> #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/of.h> #include <linux/of_device.h> - -#include "msm_serial.h" - -#define UARTDM_BURST_SIZE 16 /* in bytes */ -#define UARTDM_TX_AIGN(x) ((x) & ~0x3) /* valid for > 1p3 */ -#define UARTDM_TX_MAX 256 /* in bytes, valid for <= 1p3 */ -#define UARTDM_RX_SIZE (UART_XMIT_SIZE / 4) +#include <linux/wait.h> + +#define UART_MR1 0x0000 + +#define UART_MR1_AUTO_RFR_LEVEL0 0x3F +#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00 +#define UART_DM_MR1_AUTO_RFR_LEVEL1 0xFFFFFF00 +#define UART_MR1_RX_RDY_CTL BIT(7) +#define UART_MR1_CTS_CTL BIT(6) + +#define UART_MR2 0x0004 +#define UART_MR2_ERROR_MODE BIT(6) +#define UART_MR2_BITS_PER_CHAR 0x30 +#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4) +#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4) +#define UART_MR2_BITS_PER_CHAR_7 (0x2 << 4) +#define UART_MR2_BITS_PER_CHAR_8 (0x3 << 4) +#define UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2) +#define UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2) +#define UART_MR2_PARITY_MODE_NONE 0x0 +#define UART_MR2_PARITY_MODE_ODD 0x1 +#define UART_MR2_PARITY_MODE_EVEN 0x2 +#define UART_MR2_PARITY_MODE_SPACE 0x3 +#define UART_MR2_PARITY_MODE 0x3 + +#define UART_CSR 0x0008 + +#define UART_TF 0x000C +#define UARTDM_TF 0x0070 + +#define UART_CR 0x0010 +#define UART_CR_CMD_NULL (0 << 4) +#define UART_CR_CMD_RESET_RX (1 << 4) +#define UART_CR_CMD_RESET_TX (2 << 4) +#define UART_CR_CMD_RESET_ERR (3 << 4) +#define UART_CR_CMD_RESET_BREAK_INT (4 << 4) +#define UART_CR_CMD_START_BREAK (5 << 4) +#define UART_CR_CMD_STOP_BREAK (6 << 4) +#define UART_CR_CMD_RESET_CTS (7 << 4) +#define UART_CR_CMD_RESET_STALE_INT (8 << 4) +#define UART_CR_CMD_PACKET_MODE (9 << 4) +#define UART_CR_CMD_MODE_RESET (12 << 4) +#define UART_CR_CMD_SET_RFR (13 << 4) +#define UART_CR_CMD_RESET_RFR (14 << 4) +#define UART_CR_CMD_PROTECTION_EN (16 << 4) +#define UART_CR_CMD_STALE_EVENT_DISABLE (6 << 8) +#define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4) +#define UART_CR_CMD_FORCE_STALE (4 << 8) +#define UART_CR_CMD_RESET_TX_READY (3 << 8) +#define UART_CR_TX_DISABLE BIT(3) +#define UART_CR_TX_ENABLE BIT(2) +#define UART_CR_RX_DISABLE BIT(1) +#define UART_CR_RX_ENABLE BIT(0) +#define UART_CR_CMD_RESET_RXBREAK_START ((1 << 11) | (2 << 4)) + +#define UART_IMR 0x0014 +#define UART_IMR_TXLEV BIT(0) +#define UART_IMR_RXSTALE BIT(3) +#define UART_IMR_RXLEV BIT(4) +#define UART_IMR_DELTA_CTS BIT(5) +#define UART_IMR_CURRENT_CTS BIT(6) +#define UART_IMR_RXBREAK_START BIT(10) + +#define UART_IPR_RXSTALE_LAST 0x20 +#define UART_IPR_STALE_LSB 0x1F +#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80 +#define UART_DM_IPR_STALE_TIMEOUT_MSB 0xFFFFFF80 + +#define UART_IPR 0x0018 +#define UART_TFWR 0x001C +#define UART_RFWR 0x0020 +#define UART_HCR 0x0024 + +#define UART_MREG 0x0028 +#define UART_NREG 0x002C +#define UART_DREG 0x0030 +#define UART_MNDREG 0x0034 +#define UART_IRDA 0x0038 +#define UART_MISR_MODE 0x0040 +#define UART_MISR_RESET 0x0044 +#define UART_MISR_EXPORT 0x0048 +#define UART_MISR_VAL 0x004C +#define UART_TEST_CTRL 0x0050 + +#define UART_SR 0x0008 +#define UART_SR_HUNT_CHAR BIT(7) +#define UART_SR_RX_BREAK BIT(6) +#define UART_SR_PAR_FRAME_ERR BIT(5) +#define UART_SR_OVERRUN BIT(4) +#define UART_SR_TX_EMPTY BIT(3) +#define UART_SR_TX_READY BIT(2) +#define UART_SR_RX_FULL BIT(1) +#define UART_SR_RX_READY BIT(0) + +#define UART_RF 0x000C +#define UARTDM_RF 0x0070 +#define UART_MISR 0x0010 +#define UART_ISR 0x0014 +#define UART_ISR_TX_READY BIT(7) + +#define UARTDM_RXFS 0x50 +#define UARTDM_RXFS_BUF_SHIFT 0x7 +#define UARTDM_RXFS_BUF_MASK 0x7 + +#define UARTDM_DMEN 0x3C +#define UARTDM_DMEN_RX_SC_ENABLE BIT(5) +#define UARTDM_DMEN_TX_SC_ENABLE BIT(4) + +#define UARTDM_DMEN_TX_BAM_ENABLE BIT(2) /* UARTDM_1P4 */ +#define UARTDM_DMEN_TX_DM_ENABLE BIT(0) /* < UARTDM_1P4 */ + +#define UARTDM_DMEN_RX_BAM_ENABLE BIT(3) /* UARTDM_1P4 */ +#define UARTDM_DMEN_RX_DM_ENABLE BIT(1) /* < UARTDM_1P4 */ + +#define UARTDM_DMRX 0x34 +#define UARTDM_NCF_TX 0x40 +#define UARTDM_RX_TOTAL_SNAP 0x38 + +#define UARTDM_BURST_SIZE 16 /* in bytes */ +#define UARTDM_TX_AIGN(x) ((x) & ~0x3) /* valid for > 1p3 */ +#define UARTDM_TX_MAX 256 /* in bytes, valid for <= 1p3 */ +#define UARTDM_RX_SIZE (UART_XMIT_SIZE / 4) enum { UARTDM_1P1 = 1, @@ -78,10 +192,65 @@ struct msm_port { struct msm_dma rx_dma; }; +#define UART_TO_MSM(uart_port) container_of(uart_port, struct msm_port, uart) + +static +void msm_write(struct uart_port *port, unsigned int val, unsigned int off) +{ + writel_relaxed(val, port->membase + off); +} + +static +unsigned int msm_read(struct uart_port *port, unsigned int off) +{ + return readl_relaxed(port->membase + off); +} + +/* + * Setup the MND registers to use the TCXO clock. + */ +static void msm_serial_set_mnd_regs_tcxo(struct uart_port *port) +{ + msm_write(port, 0x06, UART_MREG); + msm_write(port, 0xF1, UART_NREG); + msm_write(port, 0x0F, UART_DREG); + msm_write(port, 0x1A, UART_MNDREG); + port->uartclk = 1843200; +} + +/* + * Setup the MND registers to use the TCXO clock divided by 4. + */ +static void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port) +{ + msm_write(port, 0x18, UART_MREG); + msm_write(port, 0xF6, UART_NREG); + msm_write(port, 0x0F, UART_DREG); + msm_write(port, 0x0A, UART_MNDREG); + port->uartclk = 1843200; +} + +static void msm_serial_set_mnd_regs(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + + /* + * These registers don't exist so we change the clk input rate + * on uartdm hardware instead + */ + if (msm_port->is_uartdm) + return; + + if (port->uartclk == 19200000) + msm_serial_set_mnd_regs_tcxo(port); + else if (port->uartclk == 4800000) + msm_serial_set_mnd_regs_tcxoby4(port); +} + static void msm_handle_tx(struct uart_port *port); static void msm_start_rx_dma(struct msm_port *msm_port); -void msm_stop_dma(struct uart_port *port, struct msm_dma *dma) +static void msm_stop_dma(struct uart_port *port, struct msm_dma *dma) { struct device *dev = port->dev; unsigned int mapped; @@ -388,10 +557,6 @@ static void msm_complete_rx_dma(void *args) val &= ~dma->enable_bit; msm_write(port, val, UARTDM_DMEN); - /* Restore interrupts */ - msm_port->imr |= UART_IMR_RXLEV | UART_IMR_RXSTALE; - msm_write(port, msm_port->imr, UART_IMR); - if (msm_read(port, UART_SR) & UART_SR_OVERRUN) { port->icount.overrun++; tty_insert_flip_char(tport, 0, TTY_OVERRUN); @@ -726,7 +891,7 @@ static void msm_handle_tx(struct uart_port *port) return; } - pio_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE); + pio_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); dma_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); dma_min = 1; /* Always DMA */ @@ -861,37 +1026,72 @@ struct msm_baud_map { }; static const struct msm_baud_map * -msm_find_best_baud(struct uart_port *port, unsigned int baud) +msm_find_best_baud(struct uart_port *port, unsigned int baud, + unsigned long *rate) { - unsigned int i, divisor; - const struct msm_baud_map *entry; + struct msm_port *msm_port = UART_TO_MSM(port); + unsigned int divisor, result; + unsigned long target, old, best_rate = 0, diff, best_diff = ULONG_MAX; + const struct msm_baud_map *entry, *end, *best; static const struct msm_baud_map table[] = { - { 1536, 0x00, 1 }, - { 768, 0x11, 1 }, - { 384, 0x22, 1 }, - { 192, 0x33, 1 }, - { 96, 0x44, 1 }, - { 48, 0x55, 1 }, - { 32, 0x66, 1 }, - { 24, 0x77, 1 }, - { 16, 0x88, 1 }, - { 12, 0x99, 6 }, - { 8, 0xaa, 6 }, - { 6, 0xbb, 6 }, - { 4, 0xcc, 6 }, - { 3, 0xdd, 8 }, - { 2, 0xee, 16 }, { 1, 0xff, 31 }, - { 0, 0xff, 31 }, + { 2, 0xee, 16 }, + { 3, 0xdd, 8 }, + { 4, 0xcc, 6 }, + { 6, 0xbb, 6 }, + { 8, 0xaa, 6 }, + { 12, 0x99, 6 }, + { 16, 0x88, 1 }, + { 24, 0x77, 1 }, + { 32, 0x66, 1 }, + { 48, 0x55, 1 }, + { 96, 0x44, 1 }, + { 192, 0x33, 1 }, + { 384, 0x22, 1 }, + { 768, 0x11, 1 }, + { 1536, 0x00, 1 }, }; - divisor = uart_get_divisor(port, baud); + best = table; /* Default to smallest divider */ + target = clk_round_rate(msm_port->clk, 16 * baud); + divisor = DIV_ROUND_CLOSEST(target, 16 * baud); + + end = table + ARRAY_SIZE(table); + entry = table; + while (entry < end) { + if (entry->divisor <= divisor) { + result = target / entry->divisor / 16; + diff = abs(result - baud); + + /* Keep track of best entry */ + if (diff < best_diff) { + best_diff = diff; + best = entry; + best_rate = target; + } - for (i = 0, entry = table; i < ARRAY_SIZE(table); i++, entry++) - if (entry->divisor <= divisor) - break; + if (result == baud) + break; + } else if (entry->divisor > divisor) { + old = target; + target = clk_round_rate(msm_port->clk, old + 1); + /* + * The rate didn't get any faster so we can't do + * better at dividing it down + */ + if (target == old) + break; - return entry; /* Default to smallest divider */ + /* Start the divisor search over at this new rate */ + entry = table; + divisor = DIV_ROUND_CLOSEST(target, 16 * baud); + continue; + } + entry++; + } + + *rate = best_rate; + return best; } static int msm_set_baud_rate(struct uart_port *port, unsigned int baud, @@ -900,22 +1100,20 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud, unsigned int rxstale, watermark, mask; struct msm_port *msm_port = UART_TO_MSM(port); const struct msm_baud_map *entry; - unsigned long flags; - - entry = msm_find_best_baud(port, baud); - - msm_write(port, entry->code, UART_CSR); - - if (baud > 460800) - port->uartclk = baud * 16; + unsigned long flags, rate; flags = *saved_flags; spin_unlock_irqrestore(&port->lock, flags); - clk_set_rate(msm_port->clk, port->uartclk); + entry = msm_find_best_baud(port, baud, &rate); + clk_set_rate(msm_port->clk, rate); + baud = rate / 16 / entry->divisor; spin_lock_irqsave(&port->lock, flags); *saved_flags = flags; + port->uartclk = rate; + + msm_write(port, entry->code, UART_CSR); /* RX stale watermark */ rxstale = entry->rxstale; @@ -1480,7 +1678,6 @@ msm_serial_early_console_setup(struct earlycon_device *device, const char *opt) device->con->write = msm_serial_early_write; return 0; } -EARLYCON_DECLARE(msm_serial, msm_serial_early_console_setup); OF_EARLYCON_DECLARE(msm_serial, "qcom,msm-uart", msm_serial_early_console_setup); @@ -1502,7 +1699,6 @@ msm_serial_early_console_setup_dm(struct earlycon_device *device, device->con->write = msm_serial_early_write_dm; return 0; } -EARLYCON_DECLARE(msm_serial_dm, msm_serial_early_console_setup_dm); OF_EARLYCON_DECLARE(msm_serial_dm, "qcom,msm-uartdm", msm_serial_early_console_setup_dm); @@ -1581,8 +1777,6 @@ static int msm_serial_probe(struct platform_device *pdev) msm_port->pclk = devm_clk_get(&pdev->dev, "iface"); if (IS_ERR(msm_port->pclk)) return PTR_ERR(msm_port->pclk); - - clk_set_rate(msm_port->clk, 1843200); } port->uartclk = clk_get_rate(msm_port->clk); diff --git a/drivers/tty/serial/msm_serial.h b/drivers/tty/serial/msm_serial.h deleted file mode 100644 index dfdf73707e9d..000000000000 --- a/drivers/tty/serial/msm_serial.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2007 Google, Inc. - * Author: Robert Love <rlove@google.com> - * Copyright (c) 2011, Code Aurora Forum. 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 __DRIVERS_SERIAL_MSM_SERIAL_H -#define __DRIVERS_SERIAL_MSM_SERIAL_H - -#define UART_MR1 0x0000 - -#define UART_MR1_AUTO_RFR_LEVEL0 0x3F -#define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00 -#define UART_DM_MR1_AUTO_RFR_LEVEL1 0xFFFFFF00 -#define UART_MR1_RX_RDY_CTL BIT(7) -#define UART_MR1_CTS_CTL BIT(6) - -#define UART_MR2 0x0004 -#define UART_MR2_ERROR_MODE BIT(6) -#define UART_MR2_BITS_PER_CHAR 0x30 -#define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4) -#define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4) -#define UART_MR2_BITS_PER_CHAR_7 (0x2 << 4) -#define UART_MR2_BITS_PER_CHAR_8 (0x3 << 4) -#define UART_MR2_STOP_BIT_LEN_ONE (0x1 << 2) -#define UART_MR2_STOP_BIT_LEN_TWO (0x3 << 2) -#define UART_MR2_PARITY_MODE_NONE 0x0 -#define UART_MR2_PARITY_MODE_ODD 0x1 -#define UART_MR2_PARITY_MODE_EVEN 0x2 -#define UART_MR2_PARITY_MODE_SPACE 0x3 -#define UART_MR2_PARITY_MODE 0x3 - -#define UART_CSR 0x0008 - -#define UART_TF 0x000C -#define UARTDM_TF 0x0070 - -#define UART_CR 0x0010 -#define UART_CR_CMD_NULL (0 << 4) -#define UART_CR_CMD_RESET_RX (1 << 4) -#define UART_CR_CMD_RESET_TX (2 << 4) -#define UART_CR_CMD_RESET_ERR (3 << 4) -#define UART_CR_CMD_RESET_BREAK_INT (4 << 4) -#define UART_CR_CMD_START_BREAK (5 << 4) -#define UART_CR_CMD_STOP_BREAK (6 << 4) -#define UART_CR_CMD_RESET_CTS (7 << 4) -#define UART_CR_CMD_RESET_STALE_INT (8 << 4) -#define UART_CR_CMD_PACKET_MODE (9 << 4) -#define UART_CR_CMD_MODE_RESET (12 << 4) -#define UART_CR_CMD_SET_RFR (13 << 4) -#define UART_CR_CMD_RESET_RFR (14 << 4) -#define UART_CR_CMD_PROTECTION_EN (16 << 4) -#define UART_CR_CMD_STALE_EVENT_DISABLE (6 << 8) -#define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4) -#define UART_CR_CMD_FORCE_STALE (4 << 8) -#define UART_CR_CMD_RESET_TX_READY (3 << 8) -#define UART_CR_TX_DISABLE BIT(3) -#define UART_CR_TX_ENABLE BIT(2) -#define UART_CR_RX_DISABLE BIT(1) -#define UART_CR_RX_ENABLE BIT(0) -#define UART_CR_CMD_RESET_RXBREAK_START ((1 << 11) | (2 << 4)) - -#define UART_IMR 0x0014 -#define UART_IMR_TXLEV BIT(0) -#define UART_IMR_RXSTALE BIT(3) -#define UART_IMR_RXLEV BIT(4) -#define UART_IMR_DELTA_CTS BIT(5) -#define UART_IMR_CURRENT_CTS BIT(6) -#define UART_IMR_RXBREAK_START BIT(10) - -#define UART_IPR_RXSTALE_LAST 0x20 -#define UART_IPR_STALE_LSB 0x1F -#define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80 -#define UART_DM_IPR_STALE_TIMEOUT_MSB 0xFFFFFF80 - -#define UART_IPR 0x0018 -#define UART_TFWR 0x001C -#define UART_RFWR 0x0020 -#define UART_HCR 0x0024 - -#define UART_MREG 0x0028 -#define UART_NREG 0x002C -#define UART_DREG 0x0030 -#define UART_MNDREG 0x0034 -#define UART_IRDA 0x0038 -#define UART_MISR_MODE 0x0040 -#define UART_MISR_RESET 0x0044 -#define UART_MISR_EXPORT 0x0048 -#define UART_MISR_VAL 0x004C -#define UART_TEST_CTRL 0x0050 - -#define UART_SR 0x0008 -#define UART_SR_HUNT_CHAR BIT(7) -#define UART_SR_RX_BREAK BIT(6) -#define UART_SR_PAR_FRAME_ERR BIT(5) -#define UART_SR_OVERRUN BIT(4) -#define UART_SR_TX_EMPTY BIT(3) -#define UART_SR_TX_READY BIT(2) -#define UART_SR_RX_FULL BIT(1) -#define UART_SR_RX_READY BIT(0) - -#define UART_RF 0x000C -#define UARTDM_RF 0x0070 -#define UART_MISR 0x0010 -#define UART_ISR 0x0014 -#define UART_ISR_TX_READY BIT(7) - -#define UARTDM_RXFS 0x50 -#define UARTDM_RXFS_BUF_SHIFT 0x7 -#define UARTDM_RXFS_BUF_MASK 0x7 - -#define UARTDM_DMEN 0x3C -#define UARTDM_DMEN_RX_SC_ENABLE BIT(5) -#define UARTDM_DMEN_TX_SC_ENABLE BIT(4) - -#define UARTDM_DMEN_TX_BAM_ENABLE BIT(2) /* UARTDM_1P4 */ -#define UARTDM_DMEN_TX_DM_ENABLE BIT(0) /* < UARTDM_1P4 */ - -#define UARTDM_DMEN_RX_BAM_ENABLE BIT(3) /* UARTDM_1P4 */ -#define UARTDM_DMEN_RX_DM_ENABLE BIT(1) /* < UARTDM_1P4 */ - -#define UARTDM_DMRX 0x34 -#define UARTDM_NCF_TX 0x40 -#define UARTDM_RX_TOTAL_SNAP 0x38 - -#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port) - -static inline -void msm_write(struct uart_port *port, unsigned int val, unsigned int off) -{ - writel_relaxed_no_log(val, port->membase + off); -} - -static inline -unsigned int msm_read(struct uart_port *port, unsigned int off) -{ - return readl_relaxed_no_log(port->membase + off); -} - -/* - * Setup the MND registers to use the TCXO clock. - */ -static inline void msm_serial_set_mnd_regs_tcxo(struct uart_port *port) -{ - msm_write(port, 0x06, UART_MREG); - msm_write(port, 0xF1, UART_NREG); - msm_write(port, 0x0F, UART_DREG); - msm_write(port, 0x1A, UART_MNDREG); - port->uartclk = 1843200; -} - -/* - * Setup the MND registers to use the TCXO clock divided by 4. - */ -static inline void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port) -{ - msm_write(port, 0x18, UART_MREG); - msm_write(port, 0xF6, UART_NREG); - msm_write(port, 0x0F, UART_DREG); - msm_write(port, 0x0A, UART_MNDREG); - port->uartclk = 1843200; -} - -static inline -void msm_serial_set_mnd_regs_from_uartclk(struct uart_port *port) -{ - if (port->uartclk == 19200000) - msm_serial_set_mnd_regs_tcxo(port); - else if (port->uartclk == 4800000) - msm_serial_set_mnd_regs_tcxoby4(port); -} - -#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_from_uartclk - -#endif /* __DRIVERS_SERIAL_MSM_SERIAL_H */ diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index d72cd736bdc6..fd9c47f2f29f 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -2451,7 +2451,6 @@ static int __init s3c2410_early_console_setup(struct earlycon_device *device, } OF_EARLYCON_DECLARE(s3c2410, "samsung,s3c2410-uart", s3c2410_early_console_setup); -EARLYCON_DECLARE(s3c2410, s3c2410_early_console_setup); /* S3C2412, S3C2440, S3C64xx */ static struct samsung_early_console_data s3c2440_early_console_data = { @@ -2470,9 +2469,6 @@ OF_EARLYCON_DECLARE(s3c2440, "samsung,s3c2440-uart", s3c2440_early_console_setup); OF_EARLYCON_DECLARE(s3c6400, "samsung,s3c6400-uart", s3c2440_early_console_setup); -EARLYCON_DECLARE(s3c2412, s3c2440_early_console_setup); -EARLYCON_DECLARE(s3c2440, s3c2440_early_console_setup); -EARLYCON_DECLARE(s3c6400, s3c2440_early_console_setup); /* S5PV210, EXYNOS */ static struct samsung_early_console_data s5pv210_early_console_data = { @@ -2489,8 +2485,6 @@ OF_EARLYCON_DECLARE(s5pv210, "samsung,s5pv210-uart", s5pv210_early_console_setup); OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart", s5pv210_early_console_setup); -EARLYCON_DECLARE(s5pv210, s5pv210_early_console_setup); -EARLYCON_DECLARE(exynos4210, s5pv210_early_console_setup); #endif MODULE_ALIAS("platform:samsung-uart"); diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index 9dbae01d41ce..9ae182a54784 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -624,8 +624,6 @@ static int __init sprd_early_console_setup( device->con->write = sprd_early_write; return 0; } - -EARLYCON_DECLARE(sprd_serial, sprd_early_console_setup); OF_EARLYCON_DECLARE(sprd_serial, "sprd,sc9836-uart", sprd_early_console_setup); diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index 0ac5ef4f750c..e0dd3f5d5635 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -42,43 +42,6 @@ #define VDDA_UA_ON_LOAD 100000 /* uA units */ #define VDDA_UA_OFF_LOAD 100 /* uA units */ -static char edid_buf1[] = { - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x22, 0xf0, 0x52, 0x29, 0x01, 0x01, 0x01, 0x01, - 0x16, 0x16, 0x01, 0x03, 0x80, 0x30, 0x1b, 0x78, - 0x2e, 0xee, 0x95, 0xa3, 0x54, 0x4c, 0x99, 0x26, - 0x0f, 0x50, 0x54, 0xa1, 0x08, 0x00, 0xd1, 0xc0, - 0x81, 0xc0, 0xa9, 0xc0, 0xb3, 0x00, 0x95, 0x00, - 0x81, 0x40, 0x81, 0x80, 0x01, 0x01, 0x02, 0x3a, - 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c, - 0x45, 0x00, 0xdb, 0x0b, 0x11, 0x00, 0x00, 0x1e, - 0x00, 0x00, 0x00, 0xfd, 0x00, 0x32, 0x4c, 0x18, - 0x5e, 0x11, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x48, - 0x50, 0x20, 0x5a, 0x52, 0x32, 0x32, 0x34, 0x30, - 0x77, 0x0a, 0x20, 0x20, 0x00, 0x00, 0x00, 0xff, - 0x00, 0x43, 0x4e, 0x34, 0x32, 0x32, 0x32, 0x30, - 0x30, 0x33, 0x46, 0x0a, 0x20, 0x20, 0x01, 0xb1, - - 0x02, 0x03, 0x17, 0xb1, 0x4c, 0x90, 0x1f, 0x05, - 0x14, 0x04, 0x13, 0x03, 0x02, 0x07, 0x06, 0x12, - 0x01, 0x65, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x02, - 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, - 0x2c, 0x45, 0x00, 0xdb, 0x0b, 0x11, 0x00, 0x00, - 0x1e, 0x02, 0x3a, 0x80, 0xd0, 0x72, 0x38, 0x2d, - 0x40, 0x10, 0x2c, 0x45, 0x80, 0xdb, 0x0b, 0x11, - 0x00, 0x00, 0x1e, 0x01, 0x1d, 0x00, 0x72, 0x51, - 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00, 0xdb, - 0x0b, 0x11, 0x00, 0x00, 0x1e, 0x01, 0x1d, 0x00, - 0xbc, 0x52, 0xd0, 0x1e, 0x20, 0xb8, 0x28, 0x55, - 0x40, 0xdb, 0x0b, 0x11, 0x00, 0x00, 0x1e, 0x8c, - 0x0a, 0xd0, 0x8a, 0x20, 0xe0, 0x2d, 0x10, 0x10, - 0x3e, 0x96, 0x00, 0xdb, 0x0b, 0x11, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b -}; - - static void mdss_dp_put_dt_clk_data(struct device *dev, struct dss_module_power *module_power) { @@ -945,9 +908,6 @@ int mdss_dp_on(struct mdss_panel_data *pdata) pr_err("Unabled to start core clocks\n"); return ret; } - mdss_dp_phy_reset(&dp_drv->ctrl_io); - mdss_dp_aux_reset(&dp_drv->ctrl_io); - mdss_dp_aux_ctrl(&dp_drv->ctrl_io, true); mdss_dp_hpd_configure(&dp_drv->ctrl_io, true); orientation = usbpd_get_plug_orientation(dp_drv->pd); @@ -971,11 +931,6 @@ int mdss_dp_on(struct mdss_panel_data *pdata) if (dp_drv->new_vic && (dp_drv->new_vic != dp_drv->vic)) dp_init_panel_info(dp_drv, dp_drv->new_vic); - mdss_dp_phy_aux_setup(&dp_drv->phy_io); - - mdss_dp_irq_enable(dp_drv); - pr_debug("irq enabled\n"); - mdss_dp_dpcd_cap_read(dp_drv); dp_drv->link_rate = mdss_dp_gen_link_clk(&dp_drv->panel_data.panel_info, dp_drv->dpcd.max_lane_count); @@ -1143,9 +1098,10 @@ static int mdss_dp_edid_init(struct mdss_panel_data *pdata) return -ENODEV; } - /* Use the existing EDID buffer for 1080p */ - memcpy(edid_init_data.buf, edid_buf1, sizeof(edid_buf1)); dp_drv->panel_data.panel_info.edid_data = edid_data; + /* initialize EDID buffer pointers */ + dp_drv->edid_buf = edid_init_data.buf; + dp_drv->edid_buf_size = edid_init_data.buf_size; return 0; } @@ -1189,17 +1145,30 @@ static int mdss_dp_host_init(struct mdss_panel_data *pdata) mdss_dp_get_ctrl_hw_version(&dp_drv->ctrl_io), mdss_dp_get_phy_hw_version(&dp_drv->phy_io)); + mdss_dp_phy_aux_setup(&dp_drv->phy_io); + + mdss_dp_irq_enable(dp_drv); + pr_debug("irq enabled\n"); + mdss_dp_dpcd_cap_read(dp_drv); + + ret = mdss_dp_edid_read(dp_drv); + if (ret) + goto edid_error; + + pr_debug("edid_read success. buf_size=%d\n", + dp_drv->edid_buf_size); + ret = hdmi_edid_parser(dp_drv->panel_data.panel_info.edid_data); if (ret) { DEV_ERR("%s: edid parse failed\n", __func__); - goto edid_parser_error; + goto edid_error; } mdss_dp_send_cable_notification(dp_drv, true); return ret; -edid_parser_error: +edid_error: mdss_dp_clk_ctrl(dp_drv, DP_CORE_PM, false); clk_error: mdss_dp_regulator_ctrl(dp_drv, false); @@ -1422,7 +1391,7 @@ static void mdss_dp_event_work(struct work_struct *work) switch (todo) { case EV_EDID_READ: - mdss_dp_edid_read(dp, 0); + mdss_dp_edid_read(dp); break; case EV_DPCD_CAP_READ: mdss_dp_dpcd_cap_read(dp); diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h index 03646cd7cc65..a8bb2ab5d343 100644 --- a/drivers/video/fbdev/msm/mdss_dp.h +++ b/drivers/video/fbdev/msm/mdss_dp.h @@ -378,6 +378,8 @@ struct mdss_dp_drv_pdata { char train_link_rate; /* X 27000000 for real rate */ char train_lane_cnt; + u8 *edid_buf; + u32 edid_buf_size; struct edp_edid edid; struct dpcd_cap dpcd; @@ -464,7 +466,7 @@ void mdss_dp_phy_initialize(struct mdss_dp_drv_pdata *dp); void mdss_dp_dpcd_cap_read(struct mdss_dp_drv_pdata *dp); int mdss_dp_dpcd_status_read(struct mdss_dp_drv_pdata *dp); -void mdss_dp_edid_read(struct mdss_dp_drv_pdata *dp, int block); +int mdss_dp_edid_read(struct mdss_dp_drv_pdata *dp); int mdss_dp_link_train(struct mdss_dp_drv_pdata *dp); void dp_aux_i2c_handler(struct mdss_dp_drv_pdata *dp, u32 isr); void dp_aux_native_handler(struct mdss_dp_drv_pdata *dp, u32 isr); diff --git a/drivers/video/fbdev/msm/mdss_dp_aux.c b/drivers/video/fbdev/msm/mdss_dp_aux.c index 7b14a7efb9dc..dfba02871649 100644 --- a/drivers/video/fbdev/msm/mdss_dp_aux.c +++ b/drivers/video/fbdev/msm/mdss_dp_aux.c @@ -665,7 +665,7 @@ static int dp_aux_chan_ready(struct mdss_dp_drv_pdata *ep) char data = 0; for (cnt = 5; cnt; cnt--) { - ret = dp_aux_write_buf(ep, 0x50, &data, 1, 1); + ret = dp_aux_write_buf(ep, EDID_START_ADDRESS, &data, 1, 1); pr_debug("ret=%d\n", ret); if (ret >= 0) break; @@ -680,43 +680,85 @@ static int dp_aux_chan_ready(struct mdss_dp_drv_pdata *ep) return 0; } -static int dp_sink_edid_read(struct mdss_dp_drv_pdata *ep, int block) +int mdss_dp_edid_read(struct mdss_dp_drv_pdata *dp) { struct edp_buf *rp; int cnt, rlen; int ret = 0; + int blk_num = 0; - ret = dp_aux_chan_ready(ep); + ret = dp_aux_chan_ready(dp); if (ret) { pr_err("aux chan NOT ready\n"); return ret; } for (cnt = 5; cnt; cnt--) { - rlen = dp_aux_read_buf(ep, 0x50, 128, 1); + rlen = dp_aux_read_buf + (dp, EDID_START_ADDRESS, EDID_BLOCK_SIZE, 1); if (rlen > 0) { - pr_debug("rlen=%d\n", rlen); + pr_debug("cnt=%d, block=%d, rlen=%d\n", + cnt, blk_num, rlen); - rp = &ep->rxp; + rp = &dp->rxp; if (!dp_edid_buf_error(rp->data, rp->len)) break; } } - if (cnt <= 0) { - pr_err("Failed\n"); + if ((cnt <= 0) && (rlen != EDID_BLOCK_SIZE)) { + pr_err("Read failed. rlen=%d\n", rlen); return -EINVAL; } - dp_extract_edid_manufacturer(&ep->edid, rp->data); - dp_extract_edid_product(&ep->edid, rp->data); - dp_extract_edid_version(&ep->edid, rp->data); - dp_extract_edid_ext_block_cnt(&ep->edid, rp->data); - dp_extract_edid_video_support(&ep->edid, rp->data); - dp_extract_edid_feature(&ep->edid, rp->data); - dp_extract_edid_detailed_timing_description(&ep->edid, rp->data); + rp = &dp->rxp; + + dp_extract_edid_manufacturer(&dp->edid, rp->data); + dp_extract_edid_product(&dp->edid, rp->data); + dp_extract_edid_version(&dp->edid, rp->data); + dp_extract_edid_ext_block_cnt(&dp->edid, rp->data); + dp_extract_edid_video_support(&dp->edid, rp->data); + dp_extract_edid_feature(&dp->edid, rp->data); + dp_extract_edid_detailed_timing_description(&dp->edid, rp->data); + /* for the first block initialize the edid buffer size */ + dp->edid_buf_size = 0; + + pr_debug("edid extension = %d\n", + dp->edid.ext_block_cnt); + + memcpy(dp->edid_buf, rp->data, EDID_BLOCK_SIZE); + dp->edid_buf_size += EDID_BLOCK_SIZE; + + if (!dp->edid.ext_block_cnt) + return 0; - return 128; + for (blk_num = 1; blk_num <= dp->edid.ext_block_cnt; + blk_num++) { + for (cnt = 5; cnt; cnt--) { + rlen = dp_aux_read_buf + (dp, EDID_START_ADDRESS + + (blk_num * EDID_BLOCK_SIZE), + EDID_BLOCK_SIZE, 1); + if (rlen > 0) { + pr_debug("cnt=%d, blk_num=%d, rlen=%d\n", + cnt, blk_num, rlen); + rp = &dp->rxp; + if (!dp_edid_buf_error(rp->data, rp->len)) + break; + } + } + + if ((cnt <= 0) && (rlen != EDID_BLOCK_SIZE)) { + pr_err("Read failed. rlen=%d\n", rlen); + return -EINVAL; + } + + memcpy(dp->edid_buf + (blk_num * EDID_BLOCK_SIZE), + rp->data, EDID_BLOCK_SIZE); + dp->edid_buf_size += EDID_BLOCK_SIZE; + } + + return 0; } static void dp_sink_capability_read(struct mdss_dp_drv_pdata *ep, @@ -1357,11 +1399,6 @@ void mdss_dp_fill_link_cfg(struct mdss_dp_drv_pdata *ep) } -void mdss_dp_edid_read(struct mdss_dp_drv_pdata *ep, int block) -{ - dp_sink_edid_read(ep, block); -} - int mdss_dp_link_train(struct mdss_dp_drv_pdata *ep) { int ret; diff --git a/drivers/video/fbdev/msm/mdss_dp_util.h b/drivers/video/fbdev/msm/mdss_dp_util.h index 8ef00dd7248e..2079dba2a357 100644 --- a/drivers/video/fbdev/msm/mdss_dp_util.h +++ b/drivers/video/fbdev/msm/mdss_dp_util.h @@ -86,6 +86,7 @@ #define TXn_TX_DRV_LVL 0x001C #define TCSR_USB3_DP_PHYMODE 0x48 +#define EDID_START_ADDRESS 0x50 struct lane_mapping { char lane0; diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c index 518b84fbad51..73af16ca6ed4 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -1947,7 +1947,6 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata) mdss_mdp_init_default_prefill_factors(mdata); mdss_set_quirk(mdata, MDSS_QUIRK_DSC_RIGHT_ONLY_PU); mdss_set_quirk(mdata, MDSS_QUIRK_DSC_2SLICE_PU_THRPUT); - mdss_set_quirk(mdata, MDSS_QUIRK_SRC_SPLIT_ALWAYS); mdata->has_wb_ubwc = true; set_bit(MDSS_CAPS_10_BIT_SUPPORTED, mdata->mdss_caps_map); set_bit(MDSS_CAPS_AVR_SUPPORTED, mdata->mdss_caps_map); diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c index 3a39d4fdc895..600701041309 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_layer.c +++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c @@ -347,10 +347,7 @@ static void __update_avr_info(struct mdss_mdp_ctl *ctl, */ static bool __layer_needs_src_split(struct mdp_input_layer *layer) { - struct mdss_data_type *mdata = mdss_mdp_get_mdata(); - - return (layer->flags & MDP_LAYER_ASYNC) || - mdss_has_quirk(mdata, MDSS_QUIRK_SRC_SPLIT_ALWAYS); + return (layer->flags & MDP_LAYER_ASYNC); } static int __async_update_position_check(struct msm_fb_data_type *mfd, diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c index bcb4867b4ffd..8cfb8e46777c 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c @@ -2690,6 +2690,16 @@ int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe, if (pipe->scaler.enable) mdss_mdp_pipe_program_pixel_extn(pipe); + + ret = mdss_mdp_pipe_pp_setup(pipe, &opmode); + if (ret) { + pr_err("pipe pp setup error for pnum=%d\n", pipe->num); + + MDSS_XLOG(pipe->num, pipe->mixer_left->num, + pipe->play_cnt, 0xbad); + + goto done; + } } if ((!(pipe->flags & MDP_VPU_PIPE) && (src_data == NULL)) || @@ -2708,12 +2718,6 @@ int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe, if (params_changed) { pipe->params_changed = 0; - ret = mdss_mdp_pipe_pp_setup(pipe, &opmode); - if (ret) { - pr_err("pipe pp setup error for pnum=%d\n", pipe->num); - goto done; - } - ret = mdss_mdp_image_setup(pipe, src_data); if (ret) { pr_err("image setup error for pnum=%d\n", pipe->num); diff --git a/drivers/video/fbdev/msm/msm_ext_display.c b/drivers/video/fbdev/msm/msm_ext_display.c index 5474df66eefb..a21242870a35 100644 --- a/drivers/video/fbdev/msm/msm_ext_display.c +++ b/drivers/video/fbdev/msm/msm_ext_display.c @@ -360,10 +360,13 @@ static int msm_ext_disp_hpd(struct platform_device *pdev, ext_disp->current_disp = data->type; } else if ((state == EXT_DISPLAY_CABLE_DISCONNECT) && !ext_disp->ack_enabled) { - ext_disp->ops->audio_info_setup = NULL; - ext_disp->ops->get_audio_edid_blk = NULL; - ext_disp->ops->cable_status = NULL; - ext_disp->ops->get_intf_id = NULL; + if (ext_disp->ops) { + ext_disp->ops->audio_info_setup = NULL; + ext_disp->ops->get_audio_edid_blk = NULL; + ext_disp->ops->cable_status = NULL; + ext_disp->ops->get_intf_id = NULL; + } + ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX; } @@ -451,7 +454,7 @@ static int msm_ext_disp_notify(struct platform_device *pdev, if (ret) goto end; - if (new_state == EXT_DISPLAY_CABLE_CONNECT) { + if (new_state == EXT_DISPLAY_CABLE_CONNECT && ext_disp->ops) { ext_disp->ops->audio_info_setup = data->codec_ops.audio_info_setup; ext_disp->ops->get_audio_edid_blk = @@ -524,10 +527,13 @@ static int msm_ext_disp_audio_ack(struct platform_device *pdev, u32 ack) * empty. */ if (!ack_hpd) { - ext_disp->ops->audio_info_setup = NULL; - ext_disp->ops->get_audio_edid_blk = NULL; - ext_disp->ops->cable_status = NULL; - ext_disp->ops->get_intf_id = NULL; + if (ext_disp->ops) { + ext_disp->ops->audio_info_setup = NULL; + ext_disp->ops->get_audio_edid_blk = NULL; + ext_disp->ops->cable_status = NULL; + ext_disp->ops->get_intf_id = NULL; + } + ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX; } diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 772c784ba763..8f5a12ab2f2b 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -157,7 +157,7 @@ #define EARLYCON_TABLE() STRUCT_ALIGN(); \ VMLINUX_SYMBOL(__earlycon_table) = .; \ *(__earlycon_table) \ - *(__earlycon_table_end) + VMLINUX_SYMBOL(__earlycon_table_end) = .; #else #define EARLYCON_TABLE() #endif @@ -179,7 +179,6 @@ #define RESERVEDMEM_OF_TABLES() OF_TABLE(CONFIG_OF_RESERVED_MEM, reservedmem) #define CPU_METHOD_OF_TABLES() OF_TABLE(CONFIG_SMP, cpu_method) #define CPUIDLE_METHOD_OF_TABLES() OF_TABLE(CONFIG_CPU_IDLE, cpuidle_method) -#define EARLYCON_OF_TABLES() OF_TABLE(CONFIG_SERIAL_EARLYCON, earlycon) #ifdef CONFIG_ACPI #define ACPI_PROBE_TABLE(name) \ @@ -527,8 +526,7 @@ IRQCHIP_OF_MATCH_TABLE() \ ACPI_PROBE_TABLE(irqchip) \ ACPI_PROBE_TABLE(clksrc) \ - EARLYCON_TABLE() \ - EARLYCON_OF_TABLES() + EARLYCON_TABLE() #define INIT_TEXT \ *(.init.text) \ diff --git a/include/dt-bindings/clock/msm-clocks-cobalt.h b/include/dt-bindings/clock/msm-clocks-cobalt.h index 28efd55ea8f6..85e28a9edc03 100644 --- a/include/dt-bindings/clock/msm-clocks-cobalt.h +++ b/include/dt-bindings/clock/msm-clocks-cobalt.h @@ -484,10 +484,6 @@ #define clk_gpu_pll0_pll_out_even 0xb0ed5009 #define clk_gpu_pll0_pll_out_odd 0x08c5a8a5 #define clk_gpu_pll0_postdiv_clk 0x76c19f3c -#define clk_gpu_pll1_pll 0x09ac81ef -#define clk_gpu_pll1_pll_out_even 0xa503de04 -#define clk_gpu_pll1_pll_out_odd 0x1c205dfb -#define clk_gpu_pll1_postdiv_clk 0xdf546700 #define clk_gpucc_mx_clk 0x1edbb879 #define clk_gpucc_gcc_dbg_clk 0x9ae8cd3c #define clk_gfxcc_dbg_clk 0x3ed47625 diff --git a/include/dt-bindings/clock/msm-clocks-hwio-cobalt.h b/include/dt-bindings/clock/msm-clocks-hwio-cobalt.h index 7ef57256d8f0..6f0e35511cc9 100644 --- a/include/dt-bindings/clock/msm-clocks-hwio-cobalt.h +++ b/include/dt-bindings/clock/msm-clocks-hwio-cobalt.h @@ -235,8 +235,6 @@ #define GPUCC_GPU_PLL0_PLL_MODE 0x00000 #define GPUCC_GPU_PLL0_USER_CTL_MODE 0x0000C -#define GPUCC_GPU_PLL1_PLL_MODE 0x00040 -#define GPUCC_GPU_PLL1_USER_CTL_MODE 0x0004C #define GPUCC_GFX3D_CMD_RCGR 0x01070 #define GPUCC_RBBMTIMER_CMD_RCGR 0x010B0 #define GPUCC_GFX3D_ISENSE_CMD_RCGR 0x01100 diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 0afc11f8f300..b2c1ea2a4739 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -342,22 +342,26 @@ struct earlycon_device { struct earlycon_id { char name[16]; + char compatible[128]; int (*setup)(struct earlycon_device *, const char *options); } __aligned(32); +extern const struct earlycon_id __earlycon_table[]; +extern const struct earlycon_id __earlycon_table_end[]; + +#define OF_EARLYCON_DECLARE(_name, compat, fn) \ + static const struct earlycon_id __UNIQUE_ID(__earlycon_##_name) \ + __used __section(__earlycon_table) \ + = { .name = __stringify(_name), \ + .compatible = compat, \ + .setup = fn } + +#define EARLYCON_DECLARE(_name, fn) OF_EARLYCON_DECLARE(_name, "", fn) + extern int setup_earlycon(char *buf); extern int of_setup_earlycon(unsigned long addr, int (*setup)(struct earlycon_device *, const char *)); -#define EARLYCON_DECLARE(_name, func) \ - static const struct earlycon_id __earlycon_##_name \ - __used __section(__earlycon_table) \ - = { .name = __stringify(_name), \ - .setup = func } - -#define OF_EARLYCON_DECLARE(name, compat, fn) \ - _OF_DECLARE(earlycon, name, compat, fn, void *) - struct uart_port *uart_get_console(struct uart_port *ports, int nr, struct console *c); int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr, diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h index 6275e4536bc0..62f1ff65f273 100644 --- a/include/soc/qcom/icnss.h +++ b/include/soc/qcom/icnss.h @@ -106,5 +106,8 @@ extern int icnss_set_fw_debug_mode(bool enable_fw_log); extern int icnss_get_irq(int ce_id); extern int icnss_power_on(struct device *dev); extern int icnss_power_off(struct device *dev); +extern struct dma_iommu_mapping *icnss_smmu_get_mapping(struct device *dev); +extern int icnss_smmu_map(struct device *dev, phys_addr_t paddr, + uint32_t *iova_addr, size_t size); #endif /* _ICNSS_WLAN_H_ */ diff --git a/include/soc/qcom/service-locator.h b/include/soc/qcom/service-locator.h index 6bf8ac0be15f..7fa25b90fc12 100644 --- a/include/soc/qcom/service-locator.h +++ b/include/soc/qcom/service-locator.h @@ -80,7 +80,7 @@ int find_subsys(const char *pd_path, char *subsys); #else static inline int get_service_location(char *client_name, - char *service_name, struct notifier_block *locator_nb); + char *service_name, struct notifier_block *locator_nb) { return -ENODEV; } diff --git a/include/soc/qcom/service-notifier.h b/include/soc/qcom/service-notifier.h index be3f134eebe3..90fceba091b9 100644 --- a/include/soc/qcom/service-notifier.h +++ b/include/soc/qcom/service-notifier.h @@ -53,7 +53,7 @@ static void *service_notif_register_notifier(const char *service_path, int instance_id, struct notifier_block *nb, int *curr_state) { - return -ENODEV; + return PTR_ERR(-ENODEV); } static int service_notif_unregister_notifier(void *service_notif_handle, diff --git a/include/soc/qcom/smem.h b/include/soc/qcom/smem.h index 79bcc1b31cf8..c3e9c474ea8b 100644 --- a/include/soc/qcom/smem.h +++ b/include/soc/qcom/smem.h @@ -92,15 +92,8 @@ enum { SMEM_KEYPAD_STATE_UPDATED, SMEM_KEYPAD_STATE_IDX, SMEM_GPIO_INT, - SMEM_MDDI_LCD_IDX, - SMEM_MDDI_HOST_DRIVER_STATE, - SMEM_MDDI_LCD_DISP_STATE, - SMEM_LCD_CUR_PANEL, - SMEM_MARM_BOOT_SEGMENT_INFO, - SMEM_AARM_BOOT_SEGMENT_INFO, - SMEM_SLEEP_STATIC, - SMEM_SCORPION_FREQUENCY, - SMEM_SMD_PROFILES, + SMEM_SMP2P_CDSP_BASE, + SMEM_SMD_PROFILES = SMEM_SMP2P_CDSP_BASE + 8, SMEM_TSSC_BUSY, SMEM_HS_SUSPEND_FILTER_INFO, SMEM_BATT_INFO, diff --git a/include/uapi/linux/msm_kgsl.h b/include/uapi/linux/msm_kgsl.h index a80278954a77..aac11dbe5984 100644 --- a/include/uapi/linux/msm_kgsl.h +++ b/include/uapi/linux/msm_kgsl.h @@ -121,6 +121,11 @@ #define KGSL_MEMFLAGS_GPUWRITEONLY 0x02000000U #define KGSL_MEMFLAGS_FORCE_32BIT 0x100000000ULL +/* Flag for binding all the virt range to single phys data */ +#define KGSL_SPARSE_BIND_MULTIPLE_TO_PHYS 0x400000000ULL +#define KGSL_SPARSE_BIND 0x1ULL +#define KGSL_SPARSE_UNBIND 0x2ULL + /* Memory caching hints */ #define KGSL_CACHEMODE_MASK 0x0C000000U #define KGSL_CACHEMODE_SHIFT 26 @@ -131,6 +136,8 @@ #define KGSL_CACHEMODE_WRITEBACK 3 #define KGSL_MEMFLAGS_USE_CPU_MAP 0x10000000ULL +#define KGSL_MEMFLAGS_SPARSE_PHYS 0x20000000ULL +#define KGSL_MEMFLAGS_SPARSE_VIRT 0x40000000ULL /* Memory types for which allocations are made */ #define KGSL_MEMTYPE_MASK 0x0000FF00 @@ -1457,4 +1464,96 @@ struct kgsl_gpuobj_set_info { #define IOCTL_KGSL_GPUOBJ_SET_INFO \ _IOW(KGSL_IOC_TYPE, 0x4C, struct kgsl_gpuobj_set_info) +/** + * struct kgsl_sparse_phys_alloc - Argument for IOCTL_KGSL_SPARSE_PHYS_ALLOC + * @size: Size in bytes to back + * @pagesize: Pagesize alignment required + * @flags: Flags for this allocation + * @id: Returned ID for this allocation + */ +struct kgsl_sparse_phys_alloc { + uint64_t size; + uint64_t pagesize; + uint64_t flags; + unsigned int id; +}; + +#define IOCTL_KGSL_SPARSE_PHYS_ALLOC \ + _IOWR(KGSL_IOC_TYPE, 0x50, struct kgsl_sparse_phys_alloc) + +/** + * struct kgsl_sparse_phys_free - Argument for IOCTL_KGSL_SPARSE_PHYS_FREE + * @id: ID to free + */ +struct kgsl_sparse_phys_free { + unsigned int id; +}; + +#define IOCTL_KGSL_SPARSE_PHYS_FREE \ + _IOW(KGSL_IOC_TYPE, 0x51, struct kgsl_sparse_phys_free) + +/** + * struct kgsl_sparse_virt_alloc - Argument for IOCTL_KGSL_SPARSE_VIRT_ALLOC + * @size: Size in bytes to reserve + * @pagesize: Pagesize alignment required + * @flags: Flags for this allocation + * @id: Returned ID for this allocation + * @gpuaddr: Returned GPU address for this allocation + */ +struct kgsl_sparse_virt_alloc { + uint64_t size; + uint64_t pagesize; + uint64_t flags; + uint64_t gpuaddr; + unsigned int id; +}; + +#define IOCTL_KGSL_SPARSE_VIRT_ALLOC \ + _IOWR(KGSL_IOC_TYPE, 0x52, struct kgsl_sparse_virt_alloc) + +/** + * struct kgsl_sparse_virt_free - Argument for IOCTL_KGSL_SPARSE_VIRT_FREE + * @id: ID to free + */ +struct kgsl_sparse_virt_free { + unsigned int id; +}; + +#define IOCTL_KGSL_SPARSE_VIRT_FREE \ + _IOW(KGSL_IOC_TYPE, 0x53, struct kgsl_sparse_virt_free) + +/** + * struct kgsl_sparse_binding_object - Argument for kgsl_sparse_bind + * @virtoffset: Offset into the virtual ID + * @physoffset: Offset into the physical ID (bind only) + * @size: Size in bytes to reserve + * @flags: Flags for this kgsl_sparse_binding_object + * @id: Physical ID to bind (bind only) + */ +struct kgsl_sparse_binding_object { + uint64_t virtoffset; + uint64_t physoffset; + uint64_t size; + uint64_t flags; + unsigned int id; +}; + +/** + * struct kgsl_sparse_bind - Argument for IOCTL_KGSL_SPARSE_BIND + * @list: List of kgsl_sparse_bind_objects to bind/unbind + * @id: Virtual ID to bind/unbind + * @size: Size of kgsl_sparse_bind_object + * @count: Number of elements in list + * + */ +struct kgsl_sparse_bind { + uint64_t __user list; + unsigned int id; + unsigned int size; + unsigned int count; +}; + +#define IOCTL_KGSL_SPARSE_BIND \ + _IOW(KGSL_IOC_TYPE, 0x54, struct kgsl_sparse_bind) + #endif /* _UAPI_MSM_KGSL_H */ diff --git a/include/uapi/media/msm_cam_sensor.h b/include/uapi/media/msm_cam_sensor.h index 5d340b9a2523..540a96c57e5b 100644 --- a/include/uapi/media/msm_cam_sensor.h +++ b/include/uapi/media/msm_cam_sensor.h @@ -35,6 +35,7 @@ #define MAX_REGULATOR 5 #define MSM_V4L2_PIX_FMT_META v4l2_fourcc('M', 'E', 'T', 'A') /* META */ +#define MSM_V4L2_PIX_FMT_META10 v4l2_fourcc('M', 'E', '1', '0') /* META10 */ #define MSM_V4L2_PIX_FMT_SBGGR14 v4l2_fourcc('B', 'G', '1', '4') /* 14 BGBG.. GRGR.. */ #define MSM_V4L2_PIX_FMT_SGBRG14 v4l2_fourcc('G', 'B', '1', '4') diff --git a/include/uapi/media/msmb_isp.h b/include/uapi/media/msmb_isp.h index 93613855228e..9f933dc7e84f 100644 --- a/include/uapi/media/msmb_isp.h +++ b/include/uapi/media/msmb_isp.h @@ -802,6 +802,7 @@ struct msm_isp_ahb_clk_cfg { #define V4L2_PIX_FMT_NV14 v4l2_fourcc('N', 'V', '1', '4') #define V4L2_PIX_FMT_NV41 v4l2_fourcc('N', 'V', '4', '1') #define V4L2_PIX_FMT_META v4l2_fourcc('Q', 'M', 'E', 'T') +#define V4L2_PIX_FMT_META10 v4l2_fourcc('Q', 'M', '1', '0') #define V4L2_PIX_FMT_SBGGR14 v4l2_fourcc('B', 'G', '1', '4') /* 14 BGBG.GRGR.*/ #define V4L2_PIX_FMT_SGBRG14 v4l2_fourcc('G', 'B', '1', '4') /* 14 GBGB.RGRG.*/ #define V4L2_PIX_FMT_SGRBG14 v4l2_fourcc('B', 'A', '1', '4') /* 14 GRGR.BGBG.*/ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 958d79e1933c..584cd048c24b 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -4096,7 +4096,8 @@ static inline int migration_needed(struct task_struct *p, int cpu) int nice; struct related_thread_group *grp; - if (!sched_enable_hmp || p->state != TASK_RUNNING) + if (!sched_enable_hmp || p->state != TASK_RUNNING || + p->nr_cpus_allowed == 1) return 0; /* No need to migrate task that is about to be throttled */ diff --git a/sound/soc/codecs/wcd9330.c b/sound/soc/codecs/wcd9330.c index 16a23aa9770c..a8d6e0fa4732 100644 --- a/sound/soc/codecs/wcd9330.c +++ b/sound/soc/codecs/wcd9330.c @@ -8956,8 +8956,11 @@ static int tomtom_codec_probe(struct snd_soc_codec *codec) err_pdata: kfree(ptr); + control->rx_chs = NULL; + control->tx_chs = NULL; err_hwdep: kfree(tomtom->fw_data); + tomtom->fw_data = NULL; err_nomem_slimch: devm_kfree(codec->dev, tomtom); return ret; @@ -8965,12 +8968,17 @@ err_nomem_slimch: static int tomtom_codec_remove(struct snd_soc_codec *codec) { struct tomtom_priv *tomtom = snd_soc_codec_get_drvdata(codec); + struct wcd9xxx *control; WCD9XXX_BG_CLK_LOCK(&tomtom->resmgr); atomic_set(&kp_tomtom_priv, 0); WCD9XXX_BG_CLK_UNLOCK(&tomtom->resmgr); + control = dev_get_drvdata(codec->dev->parent); + control->rx_chs = NULL; + control->tx_chs = NULL; + if (tomtom->wcd_ext_clk) clk_put(tomtom->wcd_ext_clk); tomtom_cleanup_irqs(tomtom); diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index e922a5a0e262..5a52b25764a4 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -13357,8 +13357,11 @@ static int tasha_codec_probe(struct snd_soc_codec *codec) err_pdata: devm_kfree(codec->dev, ptr); + control->rx_chs = NULL; + control->tx_chs = NULL; err_hwdep: devm_kfree(codec->dev, tasha->fw_data); + tasha->fw_data = NULL; err: return ret; } @@ -13366,6 +13369,11 @@ err: static int tasha_codec_remove(struct snd_soc_codec *codec) { struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec); + struct wcd9xxx *control; + + control = dev_get_drvdata(codec->dev->parent); + control->rx_chs = NULL; + control->tx_chs = NULL; tasha_cleanup_irqs(tasha); /* Cleanup MBHC */ diff --git a/sound/soc/codecs/wcd934x/wcd934x-routing.h b/sound/soc/codecs/wcd934x/wcd934x-routing.h index 4735ef9722ed..72976a9ec0fe 100644 --- a/sound/soc/codecs/wcd934x/wcd934x-routing.h +++ b/sound/soc/codecs/wcd934x/wcd934x-routing.h @@ -114,6 +114,11 @@ const struct snd_soc_dapm_route tavil_slim_audio_map[] = { const struct snd_soc_dapm_route tavil_audio_map[] = { + /* VI Feedback */ + {"AIF4_VI Mixer", "SPKR_VI_1", "VIINPUT"}, + {"AIF4_VI Mixer", "SPKR_VI_2", "VIINPUT"}, + {"AIF4 VI", NULL, "AIF4_VI Mixer"}, + /* CDC Tx interface with SLIMBUS */ {"SLIM TX0", NULL, "CDC_IF TX0 MUX"}, {"SLIM TX1", NULL, "CDC_IF TX1 MUX"}, diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c index d7103f1ff00f..8c2387dc194b 100644 --- a/sound/soc/codecs/wcd934x/wcd934x.c +++ b/sound/soc/codecs/wcd934x/wcd934x.c @@ -122,6 +122,8 @@ static const struct snd_kcontrol_new name##_mux = \ #define CF_MIN_3DB_150HZ 0x2 enum { + VI_SENSE_1, + VI_SENSE_2, AUDIO_NOMINAL, HPH_PA_DELAY, }; @@ -148,6 +150,7 @@ enum { AIF3_PB, AIF3_CAP, AIF4_PB, + AIF4_VIFEED, NUM_CODEC_DAIS, }; @@ -474,6 +477,8 @@ struct tavil_priv { struct work_struct tavil_add_child_devices_work; struct hpf_work tx_hpf_work[WCD934X_NUM_DECIMATORS]; struct tx_mute_work tx_mute_dwork[WCD934X_NUM_DECIMATORS]; + + unsigned int vi_feed_value; }; static const struct tavil_reg_mask_val tavil_spkr_default[] = { @@ -700,6 +705,72 @@ void *tavil_get_afe_config(struct snd_soc_codec *codec, } EXPORT_SYMBOL(tavil_get_afe_config); +static int tavil_vi_feed_mixer_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget_list *wlist = + dapm_kcontrol_get_wlist(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm); + struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = tavil_p->vi_feed_value; + + return 0; +} + +static int tavil_vi_feed_mixer_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget_list *wlist = + dapm_kcontrol_get_wlist(kcontrol); + struct snd_soc_dapm_widget *widget = wlist->widgets[0]; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(widget->dapm); + struct tavil_priv *tavil_p = snd_soc_codec_get_drvdata(codec); + struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent); + struct soc_multi_mixer_control *mixer = + ((struct soc_multi_mixer_control *)kcontrol->private_value); + u32 dai_id = widget->shift; + u32 port_id = mixer->shift; + u32 enable = ucontrol->value.integer.value[0]; + + dev_dbg(codec->dev, "%s: enable: %d, port_id:%d, dai_id: %d\n", + __func__, enable, port_id, dai_id); + + tavil_p->vi_feed_value = ucontrol->value.integer.value[0]; + + mutex_lock(&tavil_p->codec_mutex); + if (enable) { + if (port_id == WCD934X_TX14 && !test_bit(VI_SENSE_1, + &tavil_p->status_mask)) { + list_add_tail(&core->tx_chs[WCD934X_TX14].list, + &tavil_p->dai[dai_id].wcd9xxx_ch_list); + set_bit(VI_SENSE_1, &tavil_p->status_mask); + } + if (port_id == WCD934X_TX15 && !test_bit(VI_SENSE_2, + &tavil_p->status_mask)) { + list_add_tail(&core->tx_chs[WCD934X_TX15].list, + &tavil_p->dai[dai_id].wcd9xxx_ch_list); + set_bit(VI_SENSE_2, &tavil_p->status_mask); + } + } else { + if (port_id == WCD934X_TX14 && test_bit(VI_SENSE_1, + &tavil_p->status_mask)) { + list_del_init(&core->tx_chs[WCD934X_TX14].list); + clear_bit(VI_SENSE_1, &tavil_p->status_mask); + } + if (port_id == WCD934X_TX15 && test_bit(VI_SENSE_2, + &tavil_p->status_mask)) { + list_del_init(&core->tx_chs[WCD934X_TX15].list); + clear_bit(VI_SENSE_2, &tavil_p->status_mask); + } + } + mutex_unlock(&tavil_p->codec_mutex); + snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, NULL); + + return 0; +} + static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1060,6 +1131,143 @@ static int tavil_codec_enable_slimtx(struct snd_soc_dapm_widget *w, return ret; } +static int tavil_codec_enable_slimvi_feedback(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct wcd9xxx *core = NULL; + struct snd_soc_codec *codec = NULL; + struct tavil_priv *tavil_p = NULL; + int ret = 0; + struct wcd9xxx_codec_dai_data *dai = NULL; + + codec = snd_soc_dapm_to_codec(w->dapm); + tavil_p = snd_soc_codec_get_drvdata(codec); + core = dev_get_drvdata(codec->dev->parent); + + dev_dbg(codec->dev, + "%s: num_dai %d stream name %s w->name %s event %d shift %d\n", + __func__, codec->component.num_dai, w->sname, + w->name, event, w->shift); + + if (w->shift != AIF4_VIFEED) { + pr_err("%s Error in enabling the tx path\n", __func__); + ret = -EINVAL; + goto done; + } + dai = &tavil_p->dai[w->shift]; + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (test_bit(VI_SENSE_1, &tavil_p->status_mask)) { + dev_dbg(codec->dev, "%s: spkr1 enabled\n", __func__); + /* Enable V&I sensing */ + snd_soc_update_bits(codec, + WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x20); + snd_soc_update_bits(codec, + WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL, 0x20, + 0x20); + snd_soc_update_bits(codec, + WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL, 0x0F, 0x00); + snd_soc_update_bits(codec, + WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL, 0x0F, + 0x00); + snd_soc_update_bits(codec, + WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL, 0x10, 0x10); + snd_soc_update_bits(codec, + WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL, 0x10, + 0x10); + snd_soc_update_bits(codec, + WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x00); + snd_soc_update_bits(codec, + WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL, 0x20, + 0x00); + } + if (test_bit(VI_SENSE_2, &tavil_p->status_mask)) { + pr_debug("%s: spkr2 enabled\n", __func__); + /* Enable V&I sensing */ + snd_soc_update_bits(codec, + WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL, 0x20, + 0x20); + snd_soc_update_bits(codec, + WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL, 0x20, + 0x20); + snd_soc_update_bits(codec, + WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL, 0x0F, + 0x00); + snd_soc_update_bits(codec, + WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL, 0x0F, + 0x00); + snd_soc_update_bits(codec, + WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL, 0x10, + 0x10); + snd_soc_update_bits(codec, + WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL, 0x10, + 0x10); + snd_soc_update_bits(codec, + WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL, 0x20, + 0x00); + snd_soc_update_bits(codec, + WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL, 0x20, + 0x00); + } + dai->bus_down_in_recovery = false; + tavil_codec_enable_slim_port_intr(dai, codec); + (void) tavil_codec_enable_slim_chmask(dai, true); + ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list, + dai->rate, dai->bit_width, + &dai->grph); + break; + case SND_SOC_DAPM_POST_PMD: + ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list, + dai->grph); + if (ret) + dev_err(codec->dev, "%s error in close_slim_sch_tx %d\n", + __func__, ret); + if (!dai->bus_down_in_recovery) + ret = tavil_codec_enable_slim_chmask(dai, false); + if (ret < 0) { + ret = wcd9xxx_disconnect_port(core, + &dai->wcd9xxx_ch_list, + dai->grph); + dev_dbg(codec->dev, "%s: Disconnect TX port, ret = %d\n", + __func__, ret); + } + if (test_bit(VI_SENSE_1, &tavil_p->status_mask)) { + /* Disable V&I sensing */ + dev_dbg(codec->dev, "%s: spkr1 disabled\n", __func__); + snd_soc_update_bits(codec, + WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL, 0x20, 0x20); + snd_soc_update_bits(codec, + WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL, 0x20, + 0x20); + snd_soc_update_bits(codec, + WCD934X_CDC_TX9_SPKR_PROT_PATH_CTL, 0x10, 0x00); + snd_soc_update_bits(codec, + WCD934X_CDC_TX10_SPKR_PROT_PATH_CTL, 0x10, + 0x00); + } + if (test_bit(VI_SENSE_2, &tavil_p->status_mask)) { + /* Disable V&I sensing */ + dev_dbg(codec->dev, "%s: spkr2 disabled\n", __func__); + snd_soc_update_bits(codec, + WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL, 0x20, + 0x20); + snd_soc_update_bits(codec, + WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL, 0x20, + 0x20); + snd_soc_update_bits(codec, + WCD934X_CDC_TX11_SPKR_PROT_PATH_CTL, 0x10, + 0x00); + snd_soc_update_bits(codec, + WCD934X_CDC_TX12_SPKR_PROT_PATH_CTL, 0x10, + 0x00); + } + break; + } +done: + return ret; +} + static int tavil_codec_enable_rx_bias(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -3406,6 +3614,13 @@ static const char *const cdc_if_rx7_mux_text[] = { "SLIM RX7", "I2S_0 RX7" }; +static const struct snd_kcontrol_new aif4_vi_mixer[] = { + SOC_SINGLE_EXT("SPKR_VI_1", SND_SOC_NOPM, WCD934X_TX14, 1, 0, + tavil_vi_feed_mixer_get, tavil_vi_feed_mixer_put), + SOC_SINGLE_EXT("SPKR_VI_2", SND_SOC_NOPM, WCD934X_TX15, 1, 0, + tavil_vi_feed_mixer_get, tavil_vi_feed_mixer_put), +}; + static const struct snd_kcontrol_new aif1_cap_mixer[] = { SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD934X_TX0, 1, 0, slim_tx_mixer_get, slim_tx_mixer_put), @@ -4094,6 +4309,13 @@ static const struct snd_soc_dapm_widget tavil_dapm_widgets[] = { SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0, aif3_cap_mixer, ARRAY_SIZE(aif3_cap_mixer)), + SND_SOC_DAPM_AIF_OUT_E("AIF4 VI", "VIfeed", 0, SND_SOC_NOPM, + AIF4_VIFEED, 0, tavil_codec_enable_slimvi_feedback, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER("AIF4_VI Mixer", SND_SOC_NOPM, AIF4_VIFEED, 0, + aif4_vi_mixer, ARRAY_SIZE(aif4_vi_mixer)), + SND_SOC_DAPM_INPUT("VIINPUT"), + SND_SOC_DAPM_MIXER("SLIM TX0", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("SLIM TX1", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("SLIM TX2", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -4297,6 +4519,7 @@ static int tavil_get_channel_map(struct snd_soc_dai *dai, case AIF1_CAP: case AIF2_CAP: case AIF3_CAP: + case AIF4_VIFEED: if (!tx_slot || !tx_num) { dev_err(tavil->dev, "%s: Invalid tx_slot 0x%pK or tx_num 0x%pK\n", __func__, tx_slot, tx_num); @@ -4653,6 +4876,22 @@ static int tavil_prepare(struct snd_pcm_substream *substream, return 0; } +static int tavil_vi_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(dai->codec); + + dev_dbg(tavil->dev, "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", + __func__, dai->name, dai->id, params_rate(params), + params_channels(params)); + + tavil->dai[dai->id].rate = params_rate(params); + tavil->dai[dai->id].bit_width = 32; + + return 0; +} + static int tavil_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -4726,6 +4965,12 @@ static struct snd_soc_dai_ops tavil_dai_ops = { .get_channel_map = tavil_get_channel_map, }; +static struct snd_soc_dai_ops tavil_vi_dai_ops = { + .hw_params = tavil_vi_hw_params, + .set_channel_map = tavil_set_channel_map, + .get_channel_map = tavil_get_channel_map, +}; + static struct snd_soc_dai_driver tavil_dai[] = { { .name = "tavil_rx1", @@ -4825,6 +5070,20 @@ static struct snd_soc_dai_driver tavil_dai[] = { }, .ops = &tavil_dai_ops, }, + { + .name = "tavil_vifeedback", + .id = AIF4_VIFEED, + .capture = { + .stream_name = "VIfeed", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_48000, + .formats = WCD934X_FORMATS_S16_S24_S32_LE, + .rate_min = 8000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &tavil_vi_dai_ops, + }, }; static int tavil_cdc_req_mclk_enable(struct tavil_priv *tavil, @@ -5297,6 +5556,8 @@ static int tavil_soc_codec_probe(struct snd_soc_codec *codec) err_pdata: devm_kfree(codec->dev, ptr); + control->rx_chs = NULL; + control->tx_chs = NULL; err: return ret; } @@ -5308,6 +5569,8 @@ static int tavil_soc_codec_remove(struct snd_soc_codec *codec) control = dev_get_drvdata(codec->dev->parent); devm_kfree(codec->dev, control->rx_chs); + control->rx_chs = NULL; + control->tx_chs = NULL; tavil_cleanup_irqs(tavil); return 0; diff --git a/sound/soc/msm/msm-audio-pinctrl.c b/sound/soc/msm/msm-audio-pinctrl.c index d30b0c40f993..2b30271500eb 100644 --- a/sound/soc/msm/msm-audio-pinctrl.c +++ b/sound/soc/msm/msm-audio-pinctrl.c @@ -1,4 +1,4 @@ - /* Copyright (c) 2015, The Linux Foundation. All rights reserved. + /* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -200,28 +200,40 @@ int msm_gpioset_initialize(enum pinctrl_client client, err: /* Free up memory allocated for gpio set combinations */ for (i = 0; i < gpioset_info[client].gpiosets_max; i++) { - if (NULL != gpioset_info[client].gpiosets[i]) + if (gpioset_info[client].gpiosets[i] != NULL) { devm_kfree(dev, gpioset_info[client].gpiosets[i]); + gpioset_info[client].gpiosets[i] = NULL; + } } - if (NULL != gpioset_info[client].gpiosets) + if (gpioset_info[client].gpiosets != NULL) { devm_kfree(dev, gpioset_info[client].gpiosets); + gpioset_info[client].gpiosets = NULL; + } /* Free up memory allocated for gpio set combinations */ for (i = 0; i < gpioset_info[client].gpiosets_comb_max; i++) { - if (NULL != gpioset_info[client].gpiosets_comb_names[i]) + if (gpioset_info[client].gpiosets_comb_names[i] != NULL) { devm_kfree(dev, gpioset_info[client].gpiosets_comb_names[i]); + gpioset_info[client].gpiosets_comb_names[i] = NULL; + } } - if (NULL != gpioset_info[client].gpiosets_comb_names) + if (gpioset_info[client].gpiosets_comb_names != NULL) { devm_kfree(dev, gpioset_info[client].gpiosets_comb_names); + gpioset_info[client].gpiosets_comb_names = NULL; + } /* Free up memory allocated for handles to pinctrl states */ - if (NULL != pinctrl_info[client].cdc_lines) + if (pinctrl_info[client].cdc_lines != NULL) { devm_kfree(dev, pinctrl_info[client].cdc_lines); + pinctrl_info[client].cdc_lines = NULL; + } /* Free up memory allocated for counter of gpio sets */ - if (NULL != gpioset_info[client].gpioset_state) + if (gpioset_info[client].gpioset_state != NULL) { devm_kfree(dev, gpioset_info[client].gpioset_state); + gpioset_info[client].gpioset_state = NULL; + } success: return ret; diff --git a/sound/soc/msm/msmcobalt.c b/sound/soc/msm/msmcobalt.c index 763854061966..4d2347aabb25 100644 --- a/sound/soc/msm/msmcobalt.c +++ b/sound/soc/msm/msmcobalt.c @@ -2042,32 +2042,6 @@ static struct snd_soc_ops msm_wcn_ops = { .hw_params = msm_wcn_hw_params, }; -static int msm_get_ll_qos_val(struct snd_pcm_runtime *runtime) -{ - int usecs; - - /* take 10% of period time as the deadline */ - usecs = (100000 / runtime->rate) * runtime->period_size; - usecs += ((100000 % runtime->rate) * runtime->period_size) / - runtime->rate; - - return usecs; -} - -static int msm_mm5_prepare(struct snd_pcm_substream *substream) -{ - if (pm_qos_request_active(&substream->latency_pm_qos_req)) - pm_qos_remove_request(&substream->latency_pm_qos_req); - pm_qos_add_request(&substream->latency_pm_qos_req, - PM_QOS_CPU_DMA_LATENCY, - msm_get_ll_qos_val(substream->runtime)); - return 0; -} - -static struct snd_soc_ops msm_mm5_ops = { - .prepare = msm_mm5_prepare, -}; - /* Digital audio interface glue - connects codec <---> CPU */ static struct snd_soc_dai_link msm_common_dai_links[] = { /* FrontEnd DAI Links */ @@ -2300,7 +2274,6 @@ static struct snd_soc_dai_link msm_common_dai_links[] = { /* this dainlink has playback support */ .ignore_pmdown_time = 1, .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5, - .ops = &msm_mm5_ops, }, { .name = "Listen 1 Audio Service", @@ -2717,6 +2690,19 @@ static struct snd_soc_dai_link msm_tasha_fe_dai_links[] = { }; static struct snd_soc_dai_link msm_tavil_fe_dai_links[] = { + { + .name = LPASS_BE_SLIMBUS_4_TX, + .stream_name = "Slimbus4 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16393", + .platform_name = "msm-pcm-hostless", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_vifeedback", + .be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + }, /* Ultrasound RX DAI Link */ { .name = "SLIMBUS_2 Hostless Playback", |