diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2016-08-17 11:20:38 -0600 |
|---|---|---|
| committer | Linux Build Service Account <lnxbuild@localhost> | 2016-08-17 11:20:39 -0600 |
| commit | d0c25e98778cc543ecbd51e24bd21376ada1466d (patch) | |
| tree | 4b6f5d9e1cd45dae760b6ab6cda5e0e8ca3945d1 | |
| parent | d1a3280d68d7f442142eda95fd2592ff3afada89 (diff) | |
| parent | 008f057bbab6dd6629b7e1a3b8c67b650a6b9ef1 (diff) | |
Promotion of kernel.lnx.4.4-160817.
CRs Change ID Subject
--------------------------------------------------------------------------------------------------------------
1053499 I1c54b6ab1c27c9b1a7601f809184d27b78ac6e8b tty: serial: msm: Move header file into driver
1053499 Ic480a989bb65b1924f3bd6d38927d1fe54eaaeee tty: serial: msm: Support more bauds
1054373 I12d3a22362b965c7d302976c83ab0e757c98d3c6 Revert "arm64: Add support for app specific settings"
1053499 I893ebd28a3e4e7afe8080bcc3e000970fe1fa36b earlycon: Use common framework for earlycon declarations
1049617 I1697139a0c7cf84e20d3a8c3747a1e96f765139a msm: vidc: Delay output buffer setting to FW
1051284 Icd3aedb9efc702d6bec0d4966d87f10c235d83e9 defconfig: msm: enable IRQ off and preempt off tracers
1046094 I521059ab1c1d95df95fdede84512e73c5d9b2329 usb: pd: Always request maximum available current from P
1054373 I8f21787f0a45dd9f7be8986b4f332f498add3203 Revert "arm64: fpsimd: Enable FP(floating-point) setting
886063 I3c56dffb4ca197e8fc23d54a44282a60254dd001 ASoC: soundwire: fix out of boundary access issues
1048345 I5eb1318d1e3a62619869033b36479c4e68f1602f soc: qcom: Fix compilation warning/error
1053499 I0a336cc928bbff5bba253281ff7deca52414ba9d tty: serial: msm: Only configure MND registers on hw tha
1054373 I8d11c596d61f0435f4ee2d1007f4903843650aed Revert "arm64: fpsimd: add support to enable/disable fps
997062 I1fde78158af71d57c958ac9f5668d4b65c9a7a3f ASoC: wcd: set pointer to null after kfree
1053687 Ib704bfa6c6ca9fc3d90ab76a2e4aef02dc48822a msm: mdss: update voltage level configuration for CX sup
1047362 1047365 I632c1dc7136a49c07b587a03181b5b4da42bdd4b ARM: dts: msm: define pinctrl for MI2S and PCM devices f
1050304 I4ef01c7bdb9af770ea3014bd6e63d3c17b0cfa47 msm: mdss: add aux read/write support for hdcp
1052513 I8df74307d4c3461198de0a58f6b8ec7c8bef1f12 ion_page_pool: Remove prealloc tracking
1051156 I15a01a772198e0383b1b73052e2d0c4160bf389f ARM: dts: msm: Add QoS clocks to MDP nodes for msmcobalt
1052513 Ia9030bcb6b404b080cb8bebb91ca7bf03c5f3e05 ion: Remove "FIXME" comment
1054226 I33e5ddb318200535c3563f5670059144e0f5eba8 sched/fair: Don't check for migration for a pinned task
997062 Ifa27a21cb76688101b758a34eddf69b160c27c79 ASoC: msm: set pointer to null after kfree
1028059 I7e57a4d6c67a58728bb3ef7f3ea0312380f84486 msm: camera: sensor: Detect flash_driver_type from dtsi
997062 I18bd73397173187f87af28c78564835eed6d6a10 swr-wcd-ctrl: set pointer to null after kfree
1054474 Iadaafa64d2c1908b04498d0a88dd612dbc36dae8 msm: mdss: remove always source split quirk setting
1054447 Ia0bd3026025c1215c595219a19cc164bc3758363 defconfig: msm: enable GIC_V3_ACL access control on msmc
1053808 I5d0cb3fcc711d22eada0983b6b660da7be1d9a3e ARM: dts: msm: Add PSCI support for msmfalcon
1052513 I5ab82f717bb003e074124e1ffae3f112c405bc2b ion_page_pool: Remove GFP_COMP from page allocation mask
1050517 Ia8f5e0b9e86b49077f15db8da2dc7a3cda6b1748 ARM: dts: msm: Add support for reset clocks for MSM8996
1009284 I4aa64724a912ae1df07d382d3eb346424b50cf36 msm: mdss: validate codec operations during HPD process
1049420 Ifda5783f7bf33ba20a3ee3749410560f7864a4f3 msm: vidc: fix CONSTRAINED_INTRA_PRED setting
1053538 Ic7523e68d65634f28babac6d17e0b02311d7ad79 ARM: dts: msm: Add bus bandwidth entry for ICNSS
1053499 Ib6da8e064171dffe5a8652e49a51c9b7bed96170 tty: serial: msm: Cleanup include usage
1009284 I93b43be6c2ca50796148898f5210c5b4d13b6f24 mdss: display-port: add support for edid read
1051435 I65f854e184606684ce2ca711f19cf61d26c1ecb5 soc: qcom: Initialize message pointer with NULL
1054373 I9464305f6cac6aedb3e5763979dba4cba92e050b Revert "defconfig: arm64: Enable app specific setting on
1048727 I093e494800dacefda447b27da4fc2ea9c0cdeda6 msm: mdss: disable scaler for pipes with solid_fill
1053499 Icea65c8df570eb4d8cb22a421b89fa03dc33f659 tty: serial: msm: fix definition of msm_stop_dma
1050304 I16bf5ecbc237294e99ce6710c6b759e3346011a5 msm: mdss: add display-port hdcp's register set
1053538 I5e300cf81bd8b653e9a5611ed60b2b770e94a863 icnss: Vote aggre2_noc_clk through bus bandwidth framewo
1050304 I62738697e91549fe44ef09b0a3aa905b37c00389 msm: mdss: generalize the hdcp 1.x registers programming
1053499 Ib05d8a73a516d7591868c87fd60ff227835d8609 tty:serial:msm:Do not restore Rx interrupts in DMA
1051287 I99fdc57e1d0cde48ac5192d83ced96848232eb41 defconfig: msmcortex: Enable CONFIG_MSM_AVTIMER
1001194 I52e6978b1c104fd78bc42e4600ceb111b47b3e11 perf: add hotplug support so that perf continues after h
1050304 I8be206dbc53fd7c757f244dc544241f1d8e1dd1c msm: mdss: add support for hdcp 1.x interrupt handler
1053499 I029ac3c7a20fdce9b5dfd0bbde8a049ff47dc4bd tty: msm_serial: remove static clk rate setting in probe
1041251 1050177 I9014831c92a6ba16450f48d7f6eb831e47b5e0ab msm: camera: sensor: Add META10 fourcc
1046456 Ifaa687b036eeab22ab4cf0238abdfbe7b2311ed3 msm: kgsl: Add sparse memory support
1001194 I61f7a7474856abf67ac6dfd9e531702072e108a5 perf: Add support for exclude_idle attribute
1051170 I4d6547d95bd76d8ca6f4d729009d8b4a78716d5b clk: msm: clock: Update clock frequencies on MSMCOBALT
1051959 Id2e764210e3ca9e12a3d8299bf0c585958bbd7c8 ARM: dts: msm: Update qusb2 phy init sequence for msmcob
1048743 Icff3c15a4f1d26f43274465063259f06737fe495 ASoC: msmcobalt: remove custom PM QoS for Low-latency pl
1052522 Ibf1f086be4c6692479c11cb4585954c5d3c91707 iommu: dma-mapping-fast: Add mmap support
1051287 Ia646ddb1ae550a8b604f41545f738771204ac48e soc: qcom: add apr_glink as dependency for AVTimer kconf
1053499 Ia6127c3a18e8909171c4b24c633e361245d1ed72 tty: serial: msm: Don't read off end of tx fifo
1054373 I0d2c9bc8f27c2ac938754ab97b4bdc7feb6325b1 Revert "defconfig: arm64: Enable FP settings for msm8996
1052522 I88ddd98a76b39e3e9126d78da8e725491f2a5b32 arm/arm64: dma-mapping: Fix iova region size
997062 I5dd4a9dd8f757d0850d75575d7e522e2a22f46f3 ASoC: wcd9xxx: set pointer to null after kfree
1052513 I1353c5d9bdfd5c525c0c781c524630577c84b95e ion: system_heap: Add a new allocation method
Change-Id: I46358c9ab9b5e47c56df9998e03f30b851eb318c
CRs-Fixed: 1052522, 1028059, 1009284, 1050177, 1048345, 1054474, 1047362, 1051959, 1054373, 1047365, 1053687, 1051170, 1046094, 1050304, 997062, 1001194, 1051156, 1049617, 886063, 1053499, 1051435, 1052513, 1048743, 1050517, 1046456, 1051287, 1048727, 1053538, 1054447, 1041251, 1049420, 1053808, 1054226, 1051284
97 files changed, 3748 insertions, 1745 deletions
diff --git a/Documentation/devicetree/bindings/fb/mdss-mdp.txt b/Documentation/devicetree/bindings/fb/mdss-mdp.txt index 93cacc07e623..c8cf395d5669 100644 --- a/Documentation/devicetree/bindings/fb/mdss-mdp.txt +++ b/Documentation/devicetree/bindings/fb/mdss-mdp.txt @@ -243,6 +243,12 @@ Bus Scaling Data: Optional properties: - batfet-supply : Phandle for battery FET regulator device node. - vdd-cx-supply : Phandle for vdd CX regulator device node. +- vdd-cx-min-uV : The minimum voltage level in uV for the CX rail + whenever the display is on. If vdd-cx-supply is + specified, then this binding is mandatory. +- vdd-cx-max-uV : The maximum voltage level in uV for the CX rail + whenever the display is on. If vdd-cx-supply is + specified, then this binding is mandatory. - qcom,vbif-settings : Array with key-value pairs of constant VBIF register settings used to setup MDSS QoS for optimum performance. The key used should be offset from "vbif_phys" register diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi index bc8f998d197b..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 { 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-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-v2.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi index 238d68efaba7..c909c23774b5 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi @@ -165,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 >; @@ -357,3 +357,14 @@ 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.dtsi b/arch/arm/boot/dts/qcom/msmcobalt.dtsi index 683110415d5e..4675a374ef01 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt.dtsi @@ -2762,8 +2762,6 @@ <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>; interrupts = <0 413 0 /* CE0 */ >, @@ -2781,6 +2779,11 @@ qcom,wlan-msa-memory = <0x100000>; vdd-io-supply = <&pmcobalt_l5>; qcom,vdd-io-voltage-level = <800000 800000>; + qcom,msm-bus,name = "msm-icnss"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = <81 10065 0 0>, + <81 10065 0 16000>; }; wil6210: qcom,wil6210 { diff --git a/arch/arm/boot/dts/qcom/msmfalcon.dtsi b/arch/arm/boot/dts/qcom/msmfalcon.dtsi index 21fda2e6fce6..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>; 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/Kconfig b/arch/arm64/Kconfig index 69c9b84b367b..0314b80695ca 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -513,37 +513,6 @@ config ARM64_64K_PAGES endchoice -config MSM_APP_API - bool "API support to enable / disable app settings for MSM8996" - depends on ARCH_MSM8996 && (ENABLE_FP_SIMD_SETTINGS || MSM_APP_SETTINGS) - help - Add API support to enable / disable the app settings to be used - at runtime. These APIs are used to enable / disable app setting - when specific aarch32 or aarch64 processes are running. - - If you are not sure what to do, select 'N' here. - -config ENABLE_FP_SIMD_SETTINGS - bool "Enable FP(Floating Point) Settings for Qualcomm MSM8996" - depends on ARCH_MSM8996 - select MSM_APP_API - help - Enable FP(Floating Point) and SIMD settings for the MSM8996 during - the execution of the aarch32 processes and disable these settings - when you switch to the aarch64 processes. - - If you are not sure what to do, select 'N' here. - -config MSM_APP_SETTINGS - bool "Support to enable / disable app settings for MSM8996" - depends on ARCH_MSM8996 - select MSM_APP_API - help - Expose an interface used by the userspace at runtime to - enable / disable the app specific settings. - - If you are not sure what to do, select 'N' here. - choice prompt "Virtual address space size" default ARM64_VA_BITS_39 if ARM64_4K_PAGES diff --git a/arch/arm64/configs/msm-perf_defconfig b/arch/arm64/configs/msm-perf_defconfig index 210017d4467e..9ded3e3d5ff4 100644 --- a/arch/arm64/configs/msm-perf_defconfig +++ b/arch/arm64/configs/msm-perf_defconfig @@ -44,8 +44,6 @@ CONFIG_ARCH_QCOM=y CONFIG_ARCH_MSM8996=y CONFIG_PCI=y CONFIG_PCI_MSM=y -CONFIG_ENABLE_FP_SIMD_SETTINGS=y -CONFIG_MSM_APP_SETTINGS=y CONFIG_SCHED_MC=y CONFIG_NR_CPUS=8 CONFIG_PREEMPT=y diff --git a/arch/arm64/configs/msm_defconfig b/arch/arm64/configs/msm_defconfig index 18a4322d9f9f..f4b10dcd45cb 100644 --- a/arch/arm64/configs/msm_defconfig +++ b/arch/arm64/configs/msm_defconfig @@ -41,8 +41,6 @@ CONFIG_ARCH_QCOM=y CONFIG_ARCH_MSM8996=y CONFIG_PCI=y CONFIG_PCI_MSM=y -CONFIG_ENABLE_FP_SIMD_SETTINGS=y -CONFIG_MSM_APP_SETTINGS=y CONFIG_SCHED_MC=y CONFIG_NR_CPUS=8 CONFIG_PREEMPT=y diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig index 1f9740b86e43..46755ce99619 100644 --- a/arch/arm64/configs/msmcortex-perf_defconfig +++ b/arch/arm64/configs/msmcortex-perf_defconfig @@ -518,6 +518,7 @@ CONFIG_TRACER_PKT=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_MSM_MPM_OF=y CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_AVTIMER=y CONFIG_MSM_CORE_CTL_HELPER=y CONFIG_QCOM_REMOTEQDSS=y CONFIG_MSM_RPM_RBCPR_STATS_V2_LOG=y @@ -537,6 +538,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..fd55c0e72e20 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -538,6 +538,7 @@ CONFIG_TRACER_PKT=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_MSM_MPM_OF=y CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_AVTIMER=y CONFIG_MSM_CORE_CTL_HELPER=y CONFIG_QCOM_REMOTEQDSS=y CONFIG_MSM_SERVICE_NOTIFIER=y @@ -621,7 +622,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/include/asm/app_api.h b/arch/arm64/include/asm/app_api.h deleted file mode 100644 index 2162400fde13..000000000000 --- a/arch/arm64/include/asm/app_api.h +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef __ASM_APP_API_H -#define __ASM_APP_API_H - -#include <linux/types.h> -#include <linux/sched.h> -#include <linux/fs.h> - -#define APP_SETTING_BIT 30 -#define MAX_ENTRIES 10 - -/* - * APIs to set / clear the app setting bits - * in the register. - */ -#ifdef CONFIG_MSM_APP_API -extern void set_app_setting_bit(uint32_t bit); -extern void clear_app_setting_bit(uint32_t bit); -#else -static inline void set_app_setting_bit(uint32_t bit) {} -static inline void clear_app_setting_bit(uint32_t bit) {} -#endif - -#ifdef CONFIG_MSM_APP_SETTINGS -extern void switch_app_setting_bit(struct task_struct *prev, - struct task_struct *next); -extern void apply_app_setting_bit(struct file *file); -extern bool use_app_setting; -#endif - -#endif diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h index 99733665be07..faad6df49e5b 100644 --- a/arch/arm64/include/asm/elf.h +++ b/arch/arm64/include/asm/elf.h @@ -23,7 +23,6 @@ */ #include <asm/ptrace.h> #include <asm/user.h> -#include <asm/fpsimd.h> typedef unsigned long elf_greg_t; @@ -178,11 +177,7 @@ typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_ELF_NGREG]; ((x)->e_flags & EF_ARM_EABI_MASK)) #define compat_start_thread compat_start_thread -#define COMPAT_SET_PERSONALITY(ex) \ -do { \ - set_thread_flag(TIF_32BIT); \ -} while (0) - +#define COMPAT_SET_PERSONALITY(ex) set_thread_flag(TIF_32BIT); #define COMPAT_ARCH_DLINFO extern int aarch32_setup_vectors_page(struct linux_binprm *bprm, int uses_interp); diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h index 3efaa5cebc03..50f559f574fe 100644 --- a/arch/arm64/include/asm/fpsimd.h +++ b/arch/arm64/include/asm/fpsimd.h @@ -81,14 +81,6 @@ extern void fpsimd_save_partial_state(struct fpsimd_partial_state *state, u32 num_regs); extern void fpsimd_load_partial_state(struct fpsimd_partial_state *state); -#ifdef CONFIG_ENABLE_FP_SIMD_SETTINGS -extern void fpsimd_disable_trap(void); -extern void fpsimd_enable_trap(void); -#else -static inline void fpsimd_disable_trap(void) {} -static inline void fpsimd_enable_trap(void) {} -#endif - #endif #endif diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 57e55e4d5fcc..9f7794c5743f 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -43,8 +43,6 @@ arm64-obj-$(CONFIG_EFI) += efi.o efi-entry.stub.o arm64-obj-$(CONFIG_PCI) += pci.o arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o arm64-obj-$(CONFIG_ACPI) += acpi.o -arm64-obj-$(CONFIG_MSM_APP_API) += app_api.o -arm64-obj-$(CONFIG_MSM_APP_SETTINGS) += app_setting.o obj-y += $(arm64-obj-y) vdso/ obj-m += $(arm64-obj-m) diff --git a/arch/arm64/kernel/app_api.c b/arch/arm64/kernel/app_api.c deleted file mode 100644 index 39eeee1a9029..000000000000 --- a/arch/arm64/kernel/app_api.c +++ /dev/null @@ -1,75 +0,0 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/bitops.h> -#include <linux/spinlock.h> -#include <linux/cpu.h> -#include <linux/export.h> - -#include <asm/app_api.h> - -static spinlock_t spinlock; -static DEFINE_PER_CPU(int, app_config_applied); -static unsigned long app_config_set[NR_CPUS]; -static unsigned long app_config_clear[NR_CPUS]; - -void set_app_setting_bit(uint32_t bit) -{ - unsigned long flags; - uint64_t reg; - int cpu; - - spin_lock_irqsave(&spinlock, flags); - asm volatile("mrs %0, S3_1_C15_C15_0" : "=r" (reg)); - reg = reg | BIT(bit); - isb(); - asm volatile("msr S3_1_C15_C15_0, %0" : : "r" (reg)); - isb(); - if (bit == APP_SETTING_BIT) { - cpu = raw_smp_processor_id(); - app_config_set[cpu]++; - - this_cpu_write(app_config_applied, 1); - } - spin_unlock_irqrestore(&spinlock, flags); - -} -EXPORT_SYMBOL(set_app_setting_bit); - -void clear_app_setting_bit(uint32_t bit) -{ - unsigned long flags; - uint64_t reg; - int cpu; - - spin_lock_irqsave(&spinlock, flags); - asm volatile("mrs %0, S3_1_C15_C15_0" : "=r" (reg)); - reg = reg & ~BIT(bit); - isb(); - asm volatile("msr S3_1_C15_C15_0, %0" : : "r" (reg)); - isb(); - if (bit == APP_SETTING_BIT) { - cpu = raw_smp_processor_id(); - app_config_clear[cpu]++; - - this_cpu_write(app_config_applied, 0); - } - spin_unlock_irqrestore(&spinlock, flags); -} -EXPORT_SYMBOL(clear_app_setting_bit); - -static int __init init_app_api(void) -{ - spin_lock_init(&spinlock); - return 0; -} -early_initcall(init_app_api); diff --git a/arch/arm64/kernel/app_setting.c b/arch/arm64/kernel/app_setting.c deleted file mode 100644 index 6b4eb28d0e24..000000000000 --- a/arch/arm64/kernel/app_setting.c +++ /dev/null @@ -1,120 +0,0 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/module.h> -#include <linux/cpu.h> -#include <linux/slab.h> -#include <linux/notifier.h> - -#include <asm/app_api.h> - -#define MAX_LEN 100 - -static char *lib_names[MAX_ENTRIES]; -static unsigned int count; -static struct mutex mutex; - -static char lib_str[MAX_LEN] = ""; -static struct kparam_string kps = { - .string = lib_str, - .maxlen = MAX_LEN, -}; -static int set_name(const char *str, struct kernel_param *kp); -module_param_call(lib_name, set_name, param_get_string, &kps, S_IWUSR); - -bool use_app_setting = true; -module_param(use_app_setting, bool, 0644); -MODULE_PARM_DESC(use_app_setting, "control use of app specific settings"); - -static int set_name(const char *str, struct kernel_param *kp) -{ - int len = strlen(str); - char *name; - - if (len >= MAX_LEN) { - pr_err("app_setting: name string too long\n"); - return -ENOSPC; - } - - /* - * echo adds '\n' which we need to chop off later - */ - name = kzalloc(len + 1, GFP_KERNEL); - if (!name) - return -ENOMEM; - - strlcpy(name, str, len + 1); - - if (name[len - 1] == '\n') - name[len - 1] = '\0'; - - mutex_lock(&mutex); - if (count < MAX_ENTRIES) { - lib_names[count] = name; - /* - * mb to ensure that the new lib_names entry is present - * before updating the view presented by get_lib_names - */ - mb(); - count++; - } else { - pr_err("app_setting: set name failed. Max entries reached\n"); - kfree(name); - mutex_unlock(&mutex); - return -EPERM; - } - mutex_unlock(&mutex); - - return 0; -} - -void switch_app_setting_bit(struct task_struct *prev, struct task_struct *next) -{ - if (prev->mm && unlikely(prev->mm->app_setting)) - clear_app_setting_bit(APP_SETTING_BIT); - - if (next->mm && unlikely(next->mm->app_setting)) - set_app_setting_bit(APP_SETTING_BIT); -} -EXPORT_SYMBOL(switch_app_setting_bit); - -void apply_app_setting_bit(struct file *file) -{ - bool found = false; - int i; - - if (file && file->f_path.dentry) { - const char *name = file->f_path.dentry->d_name.name; - - for (i = 0; i < count; i++) { - if (unlikely(!strcmp(name, lib_names[i]))) { - found = true; - break; - } - } - if (found) { - preempt_disable(); - set_app_setting_bit(APP_SETTING_BIT); - /* This will take care of child processes as well */ - current->mm->app_setting = 1; - preempt_enable(); - } - } -} -EXPORT_SYMBOL(apply_app_setting_bit); - -static int __init app_setting_init(void) -{ - mutex_init(&mutex); - return 0; -} -module_init(app_setting_init); diff --git a/arch/arm64/kernel/entry-fpsimd.S b/arch/arm64/kernel/entry-fpsimd.S index 1ffe15459c92..c44a82f146b1 100644 --- a/arch/arm64/kernel/entry-fpsimd.S +++ b/arch/arm64/kernel/entry-fpsimd.S @@ -64,20 +64,4 @@ ENTRY(fpsimd_load_partial_state) ret ENDPROC(fpsimd_load_partial_state) -#ifdef CONFIG_ENABLE_FP_SIMD_SETTINGS -ENTRY(fpsimd_enable_trap) - mrs x0, cpacr_el1 - bic x0, x0, #(3 << 20) - orr x0, x0, #(1 << 20) - msr cpacr_el1, x0 - ret -ENDPROC(fpsimd_enable_trap) -ENTRY(fpsimd_disable_trap) - mrs x0, cpacr_el1 - orr x0, x0, #(3 << 20) - msr cpacr_el1, x0 - ret -ENDPROC(fpsimd_disable_trap) -#endif - #endif diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 485186bff022..e3131b39fbf2 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -427,7 +427,7 @@ el0_sync_compat: cmp x24, #ESR_ELx_EC_IABT_LOW // instruction abort in EL0 b.eq el0_ia cmp x24, #ESR_ELx_EC_FP_ASIMD // FP/ASIMD access - b.eq el0_fpsimd_acc_compat + b.eq el0_fpsimd_acc cmp x24, #ESR_ELx_EC_FP_EXC32 // FP/ASIMD exception b.eq el0_fpsimd_exc cmp x24, #ESR_ELx_EC_PC_ALIGN // pc alignment exception @@ -498,17 +498,6 @@ el0_fpsimd_acc: mov x1, sp bl do_fpsimd_acc b ret_to_user -el0_fpsimd_acc_compat: - /* - * Floating Point or Advanced SIMD access - */ - enable_dbg - ct_user_exit - mov x0, x25 - mov x1, sp - bl do_fpsimd_acc_compat - b ret_to_user - el0_fpsimd_exc: /* * Floating Point or Advanced SIMD exception diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c index 2ed553f3a4ae..4c46c54a3ad7 100644 --- a/arch/arm64/kernel/fpsimd.c +++ b/arch/arm64/kernel/fpsimd.c @@ -20,7 +20,6 @@ #include <linux/cpu.h> #include <linux/cpu_pm.h> #include <linux/kernel.h> -#include <linux/module.h> #include <linux/init.h> #include <linux/sched.h> #include <linux/signal.h> @@ -28,7 +27,6 @@ #include <asm/fpsimd.h> #include <asm/cputype.h> -#include <asm/app_api.h> #define FPEXC_IOF (1 << 0) #define FPEXC_DZF (1 << 1) @@ -37,8 +35,6 @@ #define FPEXC_IXF (1 << 4) #define FPEXC_IDF (1 << 7) -#define FP_SIMD_BIT 31 - /* * In order to reduce the number of times the FPSIMD state is needlessly saved * and restored, we need to keep track of two things: @@ -92,42 +88,14 @@ * whatever is in the FPSIMD registers is not saved to memory, but discarded. */ static DEFINE_PER_CPU(struct fpsimd_state *, fpsimd_last_state); -static DEFINE_PER_CPU(int, fpsimd_stg_enable); - -static int fpsimd_settings = 0x1; /* default = 0x1 */ -module_param(fpsimd_settings, int, 0644); - -void fpsimd_settings_enable(void) -{ - set_app_setting_bit(FP_SIMD_BIT); -} - -void fpsimd_settings_disable(void) -{ - clear_app_setting_bit(FP_SIMD_BIT); -} /* * Trapped FP/ASIMD access. */ void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs) { - if (!fpsimd_settings) - return; - - fpsimd_disable_trap(); - fpsimd_settings_disable(); - this_cpu_write(fpsimd_stg_enable, 0); -} - -void do_fpsimd_acc_compat(unsigned int esr, struct pt_regs *regs) -{ - if (!fpsimd_settings) - return; - - fpsimd_disable_trap(); - fpsimd_settings_enable(); - this_cpu_write(fpsimd_stg_enable, 1); + /* TODO: implement lazy context saving/restoring */ + WARN_ON(1); } /* @@ -167,11 +135,6 @@ void fpsimd_thread_switch(struct task_struct *next) if (current->mm && !test_thread_flag(TIF_FOREIGN_FPSTATE)) fpsimd_save_state(¤t->thread.fpsimd_state); - if (fpsimd_settings && __this_cpu_read(fpsimd_stg_enable)) { - fpsimd_settings_disable(); - this_cpu_write(fpsimd_stg_enable, 0); - } - if (next->mm) { /* * If we are switching to a task whose most recent userland @@ -189,14 +152,6 @@ void fpsimd_thread_switch(struct task_struct *next) else set_ti_thread_flag(task_thread_info(next), TIF_FOREIGN_FPSTATE); - - if (!fpsimd_settings) - return; - - if (test_ti_thread_flag(task_thread_info(next), TIF_32BIT)) - fpsimd_enable_trap(); - else - fpsimd_disable_trap(); } } diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index 52d046b6a920..10db9cbaf49e 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -232,6 +232,11 @@ static const unsigned armv8_a57_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] #define ARMV8_EXCLUDE_EL0 (1 << 30) #define ARMV8_INCLUDE_EL2 (1 << 27) +struct arm_pmu_and_idle_nb { + struct arm_pmu *cpu_pmu; + struct notifier_block perf_cpu_idle_nb; +}; + static inline u32 armv8pmu_pmcr_read(void) { u32 val; @@ -541,8 +546,6 @@ static int armv8pmu_set_event_filter(struct hw_perf_event *event, { unsigned long config_base = 0; - if (attr->exclude_idle) - return -EPERM; if (attr->exclude_user) config_base |= ARMV8_EXCLUDE_EL0; if (attr->exclude_kernel) @@ -575,6 +578,33 @@ static inline void armv8pmu_init_usermode(void) } #endif + +static void armv8pmu_idle_update(struct arm_pmu *cpu_pmu) +{ + struct pmu_hw_events *hw_events; + struct perf_event *event; + int idx; + + if (!cpu_pmu) + return; + + hw_events = this_cpu_ptr(cpu_pmu->hw_events); + + for (idx = 0; idx < cpu_pmu->num_events; ++idx) { + + if (!test_bit(idx, hw_events->used_mask)) + continue; + + event = hw_events->events[idx]; + + if (!event || !event->attr.exclude_idle || + event->state != PERF_EVENT_STATE_ACTIVE) + continue; + + cpu_pmu->pmu.read(event); + } +} + static void armv8pmu_reset(void *info) { struct arm_pmu *cpu_pmu = (struct arm_pmu *)info; @@ -624,11 +654,40 @@ static void armv8pmu_read_num_pmnc_events(void *info) *nb_cnt += 1; } +static int perf_cpu_idle_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct arm_pmu_and_idle_nb *pmu_nb = container_of(nb, + struct arm_pmu_and_idle_nb, perf_cpu_idle_nb); + + if (action == IDLE_START) + armv8pmu_idle_update(pmu_nb->cpu_pmu); + + return NOTIFY_OK; +} + int armv8pmu_probe_num_events(struct arm_pmu *arm_pmu) { - return smp_call_function_any(&arm_pmu->supported_cpus, + int ret; + struct arm_pmu_and_idle_nb *pmu_idle_nb; + + pmu_idle_nb = devm_kzalloc(&arm_pmu->plat_device->dev, + sizeof(*pmu_idle_nb), GFP_KERNEL); + if (!pmu_idle_nb) + return -ENOMEM; + + pmu_idle_nb->cpu_pmu = arm_pmu; + pmu_idle_nb->perf_cpu_idle_nb.notifier_call = perf_cpu_idle_notifier; + idle_notifier_register(&pmu_idle_nb->perf_cpu_idle_nb); + + ret = smp_call_function_any(&arm_pmu->supported_cpus, armv8pmu_read_num_pmnc_events, &arm_pmu->num_events, 1); + if (!ret) + idle_notifier_unregister(&pmu_idle_nb->perf_cpu_idle_nb); + return ret; + + } void armv8_pmu_init(struct arm_pmu *cpu_pmu) 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/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/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/sensor/flash/msm_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c index 1fc51d900cf8..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 @@ -920,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); @@ -934,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/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index 96fefea39241..ee3df23115a5 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -601,10 +601,6 @@ static struct msm_vidc_ctrl msm_vdec_ctrls[] = { #define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls) -static int set_buffer_size(struct msm_vidc_inst *inst, - u32 buffer_size, enum hal_buffer buffer_type); -static int update_output_buffer_size(struct msm_vidc_inst *inst, - struct v4l2_format *f, int num_planes); static int vdec_hal_to_v4l2(int id, int value); static u32 get_frame_size_nv12(int plane, @@ -1181,13 +1177,6 @@ int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) for (i = 0; i < fmt->num_planes; ++i) inst->bufq[CAPTURE_PORT].vb2_bufq.plane_sizes[i] = f->fmt.pix_mp.plane_fmt[i].sizeimage; - rc = update_output_buffer_size(inst, f, fmt->num_planes); - if (rc) { - dprintk(VIDC_ERR, - "%s - failed to update buffer size: %d\n", - __func__, rc); - goto exit; - } } if (stride && scanlines) { @@ -1220,95 +1209,6 @@ exit: return rc; } -static int set_buffer_size(struct msm_vidc_inst *inst, - u32 buffer_size, enum hal_buffer buffer_type) -{ - int rc = 0; - struct hfi_device *hdev; - struct hal_buffer_size_minimum b; - - if (!inst || !inst->core || !inst->core->device) { - dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); - return -EINVAL; - } - - hdev = inst->core->device; - - dprintk(VIDC_DBG, - "Set minimum buffer size = %d for buffer type %d to fw\n", - buffer_size, buffer_type); - - b.buffer_type = buffer_type; - b.buffer_size = buffer_size; - rc = call_hfi_op(hdev, session_set_property, - inst->session, HAL_PARAM_BUFFER_SIZE_MINIMUM, - &b); - if (rc) - dprintk(VIDC_ERR, - "%s - failed to set actual buffer size %u on firmware\n", - __func__, buffer_size); - return rc; -} - -static int update_output_buffer_size(struct msm_vidc_inst *inst, - struct v4l2_format *f, int num_planes) -{ - int rc = 0, i = 0; - struct hal_buffer_requirements *bufreq; - - if (!inst || !f) - return -EINVAL; - - /* - * Firmware expects driver to always set the minimum buffer - * size negotiated with the v4l2 client. Firmware will use this - * size to check for buffer sufficiency in dynamic buffer mode. - */ - for (i = 0; i < num_planes; ++i) { - enum hal_buffer type = msm_comm_get_hal_output_buffer(inst); - - if (EXTRADATA_IDX(num_planes) && - i == EXTRADATA_IDX(num_planes)) - continue; - - bufreq = get_buff_req_buffer(inst, type); - if (!bufreq) - goto exit; - - if (f->fmt.pix_mp.plane_fmt[i].sizeimage >= - bufreq->buffer_size) { - rc = set_buffer_size(inst, - f->fmt.pix_mp.plane_fmt[i].sizeimage, type); - if (rc) - goto exit; - } - } - - /* - * Set min buffer size for DPB buffers as well. - * Firmware mandates setting of minimum buffer size - * and actual buffer count for both OUTPUT and OUTPUT2. - * Hence we are setting back the same buffer size - * information back to firmware. - */ - if (msm_comm_get_stream_output_mode(inst) == - HAL_VIDEO_DECODER_SECONDARY) { - bufreq = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT); - if (!bufreq) { - rc = -EINVAL; - goto exit; - } - - rc = set_buffer_size(inst, bufreq->buffer_size, - HAL_BUFFER_OUTPUT); - if (rc) - goto exit; - } - -exit: - return rc; -} - static int set_default_properties(struct msm_vidc_inst *inst) { struct hfi_device *hdev; @@ -1370,13 +1270,9 @@ int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width; inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height; - if (msm_comm_get_stream_output_mode(inst) == - HAL_VIDEO_DECODER_PRIMARY) { - inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width; - inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height; - msm_comm_set_color_format(inst, HAL_BUFFER_OUTPUT, + msm_comm_set_color_format(inst, + msm_comm_get_hal_output_buffer(inst), f->fmt.pix_mp.pixelformat); - } inst->fmts[fmt->type] = fmt; if (msm_comm_get_stream_output_mode(inst) == @@ -1384,8 +1280,6 @@ int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) frame_sz.buffer_type = HAL_BUFFER_OUTPUT2; frame_sz.width = inst->prop.width[CAPTURE_PORT]; frame_sz.height = inst->prop.height[CAPTURE_PORT]; - msm_comm_set_color_format(inst, HAL_BUFFER_OUTPUT2, - f->fmt.pix_mp.pixelformat); dprintk(VIDC_DBG, "buffer type = %d width = %d, height = %d\n", frame_sz.buffer_type, frame_sz.width, @@ -1793,12 +1687,28 @@ static inline int start_streaming(struct msm_vidc_inst *inst) int rc = 0; struct hfi_device *hdev; bool slave_side_cp = inst->core->resources.slave_side_cp; + struct hal_buffer_size_minimum b; + unsigned int buffer_size; + struct msm_vidc_format *fmt = NULL; + fmt = inst->fmts[CAPTURE_PORT]; + buffer_size = fmt->get_frame_size(0, + inst->prop.height[CAPTURE_PORT], + inst->prop.width[CAPTURE_PORT]); hdev = inst->core->device; if (msm_comm_get_stream_output_mode(inst) == - HAL_VIDEO_DECODER_SECONDARY) + HAL_VIDEO_DECODER_SECONDARY) { rc = msm_vidc_check_scaling_supported(inst); + b.buffer_type = HAL_BUFFER_OUTPUT2; + } else { + b.buffer_type = HAL_BUFFER_OUTPUT; + } + + b.buffer_size = buffer_size; + rc = call_hfi_op(hdev, session_set_property, + inst->session, HAL_PARAM_BUFFER_SIZE_MINIMUM, + &b); if (rc) { dprintk(VIDC_ERR, "H/w scaling is not in valid range\n"); return -EINVAL; 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_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 1f071ba36ec1..587aa930cf9c 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -3010,6 +3010,7 @@ static int set_output_buffers(struct msm_vidc_inst *inst, struct hal_buffer_requirements *output_buf, *extradata_buf; int i; struct hfi_device *hdev; + struct hal_buffer_size_minimum b; hdev = inst->core->device; @@ -3026,6 +3027,11 @@ static int set_output_buffers(struct msm_vidc_inst *inst, output_buf->buffer_size); buffer_size = output_buf->buffer_size; + b.buffer_type = buffer_type; + b.buffer_size = buffer_size; + rc = call_hfi_op(hdev, session_set_property, + inst->session, HAL_PARAM_BUFFER_SIZE_MINIMUM, + &b); extradata_buf = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_OUTPUT); if (extradata_buf) { 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/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index 53e3af9052a9..71154ec99d3c 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -550,6 +550,7 @@ static void armpmu_init(struct arm_pmu *armpmu) .stop = armpmu_stop, .read = armpmu_read, .filter_match = armpmu_filter_match, + .events_across_hotplug = 1, }; } @@ -686,31 +687,12 @@ static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler) return 0; } -/* - * PMU hardware loses all context when a CPU goes offline. - * When a CPU is hotplugged back in, since some hardware registers are - * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading - * junk values out of them. - */ -static int cpu_pmu_notify(struct notifier_block *b, unsigned long action, - void *hcpu) -{ - int cpu = (unsigned long)hcpu; - struct arm_pmu *pmu = container_of(b, struct arm_pmu, hotplug_nb); - - if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING) - return NOTIFY_DONE; - - if (!cpumask_test_cpu(cpu, &pmu->supported_cpus)) - return NOTIFY_DONE; - - if (pmu->reset) - pmu->reset(pmu); - else - return NOTIFY_DONE; - - return NOTIFY_OK; -} +struct cpu_pm_pmu_args { + struct arm_pmu *armpmu; + unsigned long cmd; + int cpu; + int ret; +}; #ifdef CONFIG_CPU_PM static void cpu_pm_pmu_setup(struct arm_pmu *armpmu, unsigned long cmd) @@ -758,15 +740,19 @@ static void cpu_pm_pmu_setup(struct arm_pmu *armpmu, unsigned long cmd) } } -static int cpu_pm_pmu_notify(struct notifier_block *b, unsigned long cmd, - void *v) +static void cpu_pm_pmu_common(void *info) { - struct arm_pmu *armpmu = container_of(b, struct arm_pmu, cpu_pm_nb); + struct cpu_pm_pmu_args *data = info; + struct arm_pmu *armpmu = data->armpmu; + unsigned long cmd = data->cmd; + int cpu = data->cpu; struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events); int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events); - if (!cpumask_test_cpu(smp_processor_id(), &armpmu->supported_cpus)) - return NOTIFY_DONE; + if (!cpumask_test_cpu(cpu, &armpmu->supported_cpus)) { + data->ret = NOTIFY_DONE; + return; + } /* * Always reset the PMU registers on power-up even if @@ -775,8 +761,12 @@ static int cpu_pm_pmu_notify(struct notifier_block *b, unsigned long cmd, if (cmd == CPU_PM_EXIT && armpmu->reset) armpmu->reset(armpmu); - if (!enabled) - return NOTIFY_OK; + if (!enabled) { + data->ret = NOTIFY_OK; + return; + } + + data->ret = NOTIFY_OK; switch (cmd) { case CPU_PM_ENTER: @@ -784,15 +774,29 @@ static int cpu_pm_pmu_notify(struct notifier_block *b, unsigned long cmd, cpu_pm_pmu_setup(armpmu, cmd); break; case CPU_PM_EXIT: - cpu_pm_pmu_setup(armpmu, cmd); case CPU_PM_ENTER_FAILED: + cpu_pm_pmu_setup(armpmu, cmd); armpmu->start(armpmu); break; default: - return NOTIFY_DONE; + data->ret = NOTIFY_DONE; + break; } - return NOTIFY_OK; + return; +} + +static int cpu_pm_pmu_notify(struct notifier_block *b, unsigned long cmd, + void *v) +{ + struct cpu_pm_pmu_args data = { + .armpmu = container_of(b, struct arm_pmu, cpu_pm_nb), + .cmd = cmd, + .cpu = smp_processor_id(), + }; + + cpu_pm_pmu_common(&data); + return data.ret; } static int cpu_pm_pmu_register(struct arm_pmu *cpu_pmu) @@ -808,8 +812,62 @@ static void cpu_pm_pmu_unregister(struct arm_pmu *cpu_pmu) #else static inline int cpu_pm_pmu_register(struct arm_pmu *cpu_pmu) { return 0; } static inline void cpu_pm_pmu_unregister(struct arm_pmu *cpu_pmu) { } +static inline void cpu_pm_pmu_common(void *info) { } #endif +/* + * PMU hardware loses all context when a CPU goes offline. + * When a CPU is hotplugged back in, since some hardware registers are + * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading + * junk values out of them. + */ +static int cpu_pmu_notify(struct notifier_block *b, unsigned long action, + void *hcpu) +{ + unsigned long masked_action = (action & ~CPU_TASKS_FROZEN); + struct cpu_pm_pmu_args data = { + .armpmu = container_of(b, struct arm_pmu, hotplug_nb), + .cpu = (unsigned long)hcpu, + }; + + if (!cpumask_test_cpu(data.cpu, &data.armpmu->supported_cpus)) + return NOTIFY_DONE; + + switch (masked_action) { + case CPU_STARTING: + data.cmd = CPU_PM_EXIT; + break; + case CPU_DYING: + data.cmd = CPU_PM_ENTER; + break; + case CPU_DOWN_FAILED: + data.cmd = CPU_PM_ENTER_FAILED; + break; + case CPU_ONLINE: + if (data.armpmu->plat_device) { + struct platform_device *pmu_device = + data.armpmu->plat_device; + int irq = platform_get_irq(pmu_device, 0); + + if (irq >= 0 && irq_is_percpu(irq)) { + smp_call_function_single(data.cpu, + cpu_pmu_enable_percpu_irq, &irq, 1); + } + } + return NOTIFY_DONE; + default: + return NOTIFY_DONE; + } + + if (smp_processor_id() == data.cpu) + cpu_pm_pmu_common(&data); + else + smp_call_function_single(data.cpu, + cpu_pm_pmu_common, &data, 1); + + return data.ret; +} + static int cpu_pmu_init(struct arm_pmu *cpu_pmu) { int err; diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index c45cbfa8a786..56555af4c2c6 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -669,7 +669,7 @@ config MSM_EVENT_TIMER config MSM_AVTIMER tristate "Avtimer Driver" - depends on MSM_QDSP6_APRV2 || MSM_QDSP6_APRV3 + depends on MSM_QDSP6_APRV2 || MSM_QDSP6_APRV3 || MSM_QDSP6_APRV2_GLINK help This driver gets the Q6 out of power collapsed state and exposes ioctl control to read avtimer tick. diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 16ca3eaee61b..bfe2072ee554 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -33,6 +33,7 @@ #include <linux/dma-mapping.h> #include <linux/qmi_encdec.h> #include <linux/ipc_logging.h> +#include <linux/msm-bus.h> #include <soc/qcom/memory_dump.h> #include <soc/qcom/icnss.h> #include <soc/qcom/msm_qmi_interface.h> @@ -43,7 +44,6 @@ #define ICNSS_PANIC 1 #define WLFW_TIMEOUT_MS 3000 #define WLFW_SERVICE_INS_ID_V01 0 -#define SMMU_CLOCK_NAME "smmu_aggre2_noc_clk" #define MAX_PROP_SIZE 32 #define MAX_VOLTAGE_LEVEL 2 #define VREG_ON 1 @@ -203,7 +203,8 @@ static struct icnss_data { size_t smmu_iova_len; dma_addr_t smmu_iova_ipa_start; size_t smmu_iova_ipa_len; - struct clk *smmu_clk; + struct msm_bus_scale_pdata *bus_scale_table; + uint32_t bus_client; struct qmi_handle *wlfw_clnt; struct list_head event_list; spinlock_t event_lock; @@ -1789,44 +1790,60 @@ int icnss_smmu_map(struct device *dev, } EXPORT_SYMBOL(icnss_smmu_map); -static struct clk *icnss_clock_init(struct device *dev, const char *cname) +static int icnss_bw_vote(struct icnss_data *priv, int index) { - struct clk *c; - long rate; - - if (of_property_match_string(dev->of_node, "clock-names", cname) < 0) { - icnss_pr_err("Clock %s not found!", cname); - return NULL; - } - - c = devm_clk_get(dev, cname); - if (IS_ERR(c)) { - icnss_pr_err("Couldn't get clock %s!", cname); - return NULL; - } + int ret = 0; - if (clk_get_rate(c) == 0) { - rate = clk_round_rate(c, 1000); - clk_set_rate(c, rate); - } + icnss_pr_dbg("Vote %d for msm_bus, state 0x%lx\n", + index, priv->state); + ret = msm_bus_scale_client_update_request(priv->bus_client, index); + if (ret) + icnss_pr_err("Fail to vote %d: ret %d, state 0x%lx!\n", + index, ret, priv->state); - return c; + return ret; } -static int icnss_clock_enable(struct clk *c) +static int icnss_bw_init(struct icnss_data *priv) { int ret = 0; - ret = clk_prepare_enable(c); + priv->bus_scale_table = msm_bus_cl_get_pdata(priv->pdev); + if (!priv->bus_scale_table) { + icnss_pr_err("Missing entry for msm_bus scale table\n"); + return -EINVAL; + } - if (ret < 0) - icnss_pr_err("Couldn't enable clock: %d!\n", ret); + priv->bus_client = msm_bus_scale_register_client(priv->bus_scale_table); + if (!priv->bus_client) { + icnss_pr_err("Fail to register with bus_scale client\n"); + ret = -EINVAL; + goto out; + } + + ret = icnss_bw_vote(priv, 1); + if (ret) + goto out; + + return 0; + +out: + msm_bus_cl_clear_pdata(priv->bus_scale_table); return ret; } -static void icnss_clock_disable(struct clk *c) +static void icnss_bw_deinit(struct icnss_data *priv) { - clk_disable_unprepare(c); + if (!priv) + return; + + if (priv->bus_client) { + icnss_bw_vote(priv, 0); + msm_bus_scale_unregister_client(priv->bus_client); + } + + if (priv->bus_scale_table) + msm_bus_cl_clear_pdata(priv->bus_scale_table); } static int icnss_smmu_init(struct device *dev) @@ -2460,12 +2477,9 @@ static int icnss_probe(struct platform_device *pdev) goto err_smmu_init; } - penv->smmu_clk = icnss_clock_init(&pdev->dev, SMMU_CLOCK_NAME); - if (penv->smmu_clk) { - ret = icnss_clock_enable(penv->smmu_clk); - if (ret < 0) - goto err_smmu_clock_enable; - } + ret = icnss_bw_init(penv); + if (ret) + goto err_bw_init; } penv->skip_qmi = of_property_read_bool(dev->of_node, @@ -2478,7 +2492,7 @@ static int icnss_probe(struct platform_device *pdev) if (!penv->event_wq) { icnss_pr_err("Workqueue creation failed\n"); ret = -EFAULT; - goto err_smmu_clock_enable; + goto err_alloc_workqueue; } INIT_WORK(&penv->event_work, icnss_driver_event_work); @@ -2503,7 +2517,9 @@ static int icnss_probe(struct platform_device *pdev) err_qmi: if (penv->event_wq) destroy_workqueue(penv->event_wq); -err_smmu_clock_enable: +err_alloc_workqueue: + icnss_bw_deinit(penv); +err_bw_init: if (penv->smmu_mapping) icnss_smmu_remove(&pdev->dev); err_smmu_init: @@ -2538,11 +2554,7 @@ static int icnss_remove(struct platform_device *pdev) if (penv->event_wq) destroy_workqueue(penv->event_wq); - if (penv->smmu_mapping) { - if (penv->smmu_clk) - icnss_clock_disable(penv->smmu_clk); - icnss_smmu_remove(&pdev->dev); - } + icnss_bw_deinit(penv); if (penv->msa_va) dma_free_coherent(&pdev->dev, penv->msa_mem_size, 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/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/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index 7bc6b5340dd7..42ebc60089ba 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -240,9 +240,6 @@ static void *usbpd_ipc_log; static int min_sink_current = 900; module_param(min_sink_current, int, S_IRUSR | S_IWUSR); -static int max_sink_current = 3000; -module_param(max_sink_current, int, S_IRUSR | S_IWUSR); - static const u32 default_src_caps[] = { 0x36019096 }; /* VSafe5V @ 1.5A */ static const u32 default_snk_caps[] = { 0x2601905A, /* 5V @ 900mA */ @@ -406,8 +403,8 @@ static int pd_send_msg(struct usbpd *pd, u8 hdr_type, const u32 *data, static int pd_select_pdo(struct usbpd *pd, int pdo_pos) { - int curr = min_sink_current; - int max_current = max_sink_current; + int curr; + int max_current; bool mismatch = false; u32 pdo = pd->received_pdos[pdo_pos - 1]; @@ -417,18 +414,19 @@ static int pd_select_pdo(struct usbpd *pd, int pdo_pos) return -ENOTSUPP; } + curr = max_current = PD_SRC_PDO_FIXED_MAX_CURR(pdo) * 10; + /* * Check if the PDO has enough current, otherwise set the * Capability Mismatch flag */ - if ((PD_SRC_PDO_FIXED_MAX_CURR(pdo) * 10) < curr) { + if (curr < min_sink_current) { mismatch = true; - max_current = curr; - curr = PD_SRC_PDO_FIXED_MAX_CURR(pdo) * 10; + max_current = min_sink_current; } pd->requested_voltage = PD_SRC_PDO_FIXED_VOLTAGE(pdo) * 50 * 1000; - pd->requested_current = max_current; + pd->requested_current = curr; pd->requested_pdo = pdo_pos; pd->rdo = PD_RDO_FIXED(pdo_pos, 0, mismatch, 1, 1, curr / 10, max_current / 10); diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h index 61e99f47f02f..4724f4378e23 100644 --- a/drivers/video/fbdev/msm/mdss.h +++ b/drivers/video/fbdev/msm/mdss.h @@ -277,6 +277,8 @@ struct mdss_data_type { struct regulator *fs; struct regulator *venus; struct regulator *vdd_cx; + u32 vdd_cx_min_uv; + u32 vdd_cx_max_uv; bool batfet_required; struct regulator *batfet; bool en_svs_high; 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..4a80c25dd157 100644 --- a/drivers/video/fbdev/msm/mdss_dp.h +++ b/drivers/video/fbdev/msm/mdss_dp.h @@ -106,15 +106,6 @@ #define EDP_INTR_MASK2 (EDP_INTR_STATUS2 << 2) -struct edp_cmd { - char read; /* 1 == read, 0 == write */ - char i2c; /* 1 == i2c cmd, 0 == native cmd */ - u32 addr; /* 20 bits */ - char *datap; - int len; /* len to be tx OR len to be rx for read */ - char next; /* next command */ -}; - struct edp_buf { char *start; /* buffer start addr */ char *end; /* buffer end addr */ @@ -378,6 +369,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 +457,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..7e9510cf08c7 100644 --- a/drivers/video/fbdev/msm/mdss_dp_aux.c +++ b/drivers/video/fbdev/msm/mdss_dp_aux.c @@ -228,6 +228,11 @@ static int dp_aux_write_cmds(struct mdss_dp_drv_pdata *ep, return ret; } +int dp_aux_write(void *ep, struct edp_cmd *cmd) +{ + return dp_aux_write_cmds(ep, cmd); +} + static int dp_aux_read_cmds(struct mdss_dp_drv_pdata *ep, struct edp_cmd *cmds) { @@ -275,12 +280,20 @@ static int dp_aux_read_cmds(struct mdss_dp_drv_pdata *ep, else ret = ep->aux_error_num; + if (cmds->out_buf) + memcpy(cmds->out_buf, rp->data, cmds->len); + ep->aux_cmd_busy = 0; mutex_unlock(&ep->aux_mutex); return ret; } +int dp_aux_read(void *ep, struct edp_cmd *cmds) +{ + return dp_aux_read_cmds(ep, cmds); +} + void dp_aux_native_handler(struct mdss_dp_drv_pdata *ep, u32 isr) { @@ -665,7 +678,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 +693,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; - return 128; + if (!dp->edid.ext_block_cnt) + return 0; + + 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 +1412,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..a2649b8c1611 100644 --- a/drivers/video/fbdev/msm/mdss_dp_util.h +++ b/drivers/video/fbdev/msm/mdss_dp_util.h @@ -86,6 +86,33 @@ #define TXn_TX_DRV_LVL 0x001C #define TCSR_USB3_DP_PHYMODE 0x48 +#define EDID_START_ADDRESS 0x50 + +/* DP HDCP 1.3 registers */ +#define DP_HDCP_CTRL (0x0A0) +#define DP_HDCP_STATUS (0x0A4) +#define DP_HDCP_SW_UPPER_AKSV (0x298) +#define DP_HDCP_SW_LOWER_AKSV (0x29C) +#define DP_HDCP_ENTROPY_CTRL0 (0x750) +#define DP_HDCP_ENTROPY_CTRL1 (0x75C) +#define DP_HDCP_SHA_STATUS (0x0C8) +#define DP_HDCP_RCVPORT_DATA2_0 (0x0B0) +#define DP_HDCP_RCVPORT_DATA3 (0x2A4) +#define DP_HDCP_RCVPORT_DATA4 (0x2A8) +#define DP_HDCP_RCVPORT_DATA5 (0x0C0) +#define DP_HDCP_RCVPORT_DATA6 (0x0C4) + +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL (0x024) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0 (0x004) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1 (0x008) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7 (0x00C) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA8 (0x010) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA9 (0x014) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA10 (0x018) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA11 (0x01C) +#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12 (0x020) + +#define DP_INTERRUPT_STATUS_2 (0x024) struct lane_mapping { char lane0; @@ -94,6 +121,18 @@ struct lane_mapping { char lane3; }; +struct edp_cmd { + char read; /* 1 == read, 0 == write */ + char i2c; /* 1 == i2c cmd, 0 == native cmd */ + u32 addr; /* 20 bits */ + char *datap; + char *out_buf; + int len; /* len to be tx OR len to be rx for read */ + char next; /* next command */ +}; + +int dp_aux_read(void *ep, struct edp_cmd *cmds); +int dp_aux_write(void *ep, struct edp_cmd *cmd); void mdss_dp_state_ctrl(struct dss_io_data *ctrl_io, u32 data); u32 mdss_dp_get_ctrl_hw_version(struct dss_io_data *ctrl_io); u32 mdss_dp_get_phy_hw_version(struct dss_io_data *phy_io); diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c index 6256c9a99877..dad089e74934 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.c @@ -15,9 +15,11 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/stat.h> +#include <linux/iopoll.h> #include <soc/qcom/scm.h> #include <linux/hdcp_qseecom.h> #include "mdss_hdmi_hdcp.h" +#include "mdss_dp_util.h" #include "video/msm_hdmi_hdcp_mgr.h" #define HDCP_STATE_NAME (hdcp_state_name(hdcp_ctrl->hdcp_state)) @@ -36,15 +38,188 @@ #define HDCP_REG_ENABLE 0x01 #define HDCP_REG_DISABLE 0x00 -#define HDCP_INT_CLR (BIT(1) | BIT(5) | BIT(7) | BIT(9) | BIT(13)) +#define HDCP_INT_CLR (isr->auth_success_ack | isr->auth_fail_ack | \ + isr->auth_fail_info_ack | isr->tx_req_ack | \ + isr->encryption_ready_ack | \ + isr->encryption_not_ready | isr->tx_req_done_ack) + +#define HDCP_INT_EN (isr->auth_success_mask | isr->auth_fail_mask | \ + isr->encryption_ready_mask | \ + isr->encryption_not_ready_mask) + +#define HDCP_POLL_SLEEP_US (20 * 1000) +#define HDCP_POLL_TIMEOUT_US (HDCP_POLL_SLEEP_US * 1000) + +#define reg_set_data(x) \ + (hdcp_ctrl->init_data.sec_access ? reg_set->sec_data##x : \ + reg_set->data##x) + +struct hdcp_sink_addr { + char *name; + u32 addr; + u32 len; +}; struct hdmi_hdcp_reg_data { u32 reg_id; - u32 off; - char *name; - u32 reg_val; + struct hdcp_sink_addr *sink; +}; + +struct hdcp_sink_addr_map { + /* addresses to read from sink */ + struct hdcp_sink_addr bcaps; + struct hdcp_sink_addr bksv; + struct hdcp_sink_addr r0; + struct hdcp_sink_addr bstatus; + struct hdcp_sink_addr ksv_fifo; + struct hdcp_sink_addr v_h0; + struct hdcp_sink_addr v_h1; + struct hdcp_sink_addr v_h2; + struct hdcp_sink_addr v_h3; + struct hdcp_sink_addr v_h4; + + /* addresses to write to sink */ + struct hdcp_sink_addr an; + struct hdcp_sink_addr aksv; + struct hdcp_sink_addr rep; +}; + +struct hdcp_int_set { + /* interrupt register */ + u32 int_reg; + + /* interrupt enable/disable masks */ + u32 auth_success_mask; + u32 auth_fail_mask; + u32 encryption_ready_mask; + u32 encryption_not_ready_mask; + u32 tx_req_mask; + u32 tx_req_done_mask; + + /* interrupt acknowledgment */ + u32 auth_success_ack; + u32 auth_fail_ack; + u32 auth_fail_info_ack; + u32 encryption_ready_ack; + u32 encryption_not_ready_ack; + u32 tx_req_ack; + u32 tx_req_done_ack; + + /* interrupt status */ + u32 auth_success_int; + u32 auth_fail_int; + u32 encryption_ready; + u32 encryption_not_ready; + u32 tx_req_int; + u32 tx_req_done_int; +}; + +struct hdcp_reg_set { + u32 status; + u32 keys_offset; + u32 r0_offset; + u32 v_offset; + u32 ctrl; + u32 aksv_lsb; + u32 aksv_msb; + u32 entropy_ctrl0; + u32 entropy_ctrl1; + u32 sha_ctrl; + u32 sec_sha_ctrl; + u32 sha_status; + + u32 data0; + u32 data1; + u32 data2_0; + u32 data3; + u32 data4; + u32 data5; + u32 data6; + u32 data7; + u32 data8; + u32 data9; + u32 data10; + u32 data11; + u32 data12; + + u32 sec_data0; + u32 sec_data1; + u32 sec_data7; + u32 sec_data8; + u32 sec_data9; + u32 sec_data10; + u32 sec_data11; + u32 sec_data12; + + u32 reset; }; +#define HDCP_REG_SET_CLIENT_HDMI \ + {HDMI_HDCP_LINK0_STATUS, 28, 24, 20, HDMI_HDCP_CTRL, \ + HDMI_HDCP_SW_LOWER_AKSV, HDMI_HDCP_SW_UPPER_AKSV, \ + HDMI_HDCP_ENTROPY_CTRL0, HDMI_HDCP_ENTROPY_CTRL1, \ + HDMI_HDCP_SHA_CTRL, HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_CTRL, \ + HDMI_HDCP_SHA_STATUS, HDMI_HDCP_RCVPORT_DATA0, \ + HDMI_HDCP_RCVPORT_DATA1, HDMI_HDCP_RCVPORT_DATA2_0, \ + HDMI_HDCP_RCVPORT_DATA3, HDMI_HDCP_RCVPORT_DATA4, \ + HDMI_HDCP_RCVPORT_DATA5, HDMI_HDCP_RCVPORT_DATA6, \ + HDMI_HDCP_RCVPORT_DATA7, HDMI_HDCP_RCVPORT_DATA8, \ + HDMI_HDCP_RCVPORT_DATA9, HDMI_HDCP_RCVPORT_DATA10, \ + HDMI_HDCP_RCVPORT_DATA11, HDMI_HDCP_RCVPORT_DATA12, \ + HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA0, \ + HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA1, \ + HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA7, \ + HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA8, \ + HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA9, \ + HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, \ + HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA11, \ + HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA12, \ + HDMI_HDCP_RESET} + +#define HDCP_REG_SET_CLIENT_DP \ + {DP_HDCP_STATUS, 16, 14, 13, DP_HDCP_CTRL, \ + DP_HDCP_SW_LOWER_AKSV, DP_HDCP_SW_UPPER_AKSV, \ + DP_HDCP_ENTROPY_CTRL0, DP_HDCP_ENTROPY_CTRL1, \ + 0, HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL, \ + DP_HDCP_SHA_STATUS, 0, 0, DP_HDCP_RCVPORT_DATA2_0, \ + DP_HDCP_RCVPORT_DATA3, DP_HDCP_RCVPORT_DATA4, \ + DP_HDCP_RCVPORT_DATA5, DP_HDCP_RCVPORT_DATA6, \ + 0, 0, 0, 0, 0, 0, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA8, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA9, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA11, \ + HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12, 0} + +#define HDCP_HDMI_SINK_ADDR_MAP \ + {{"bcaps", 0x40, 1}, {"bksv", 0x00, 5}, {"r0'", 0x08, 2}, \ + {"bstatus", 0x41, 2}, {"ksv-fifo", 0x43, 0}, {"v_h0", 0x20, 4}, \ + {"v_h1", 0x24, 4}, {"v_h2", 0x28, 4}, {"v_h3", 0x2c, 4}, \ + {"v_h4", 0x30, 4}, {"an", 0x16, 8}, {"aksv", 0x10, 5}, \ + {"repater", 0x00, 0} } + +#define HDCP_DP_SINK_ADDR_MAP \ + {{"bcaps", 0x68028, 1}, {"bksv", 0x68000, 5}, {"r0'", 0x68005, 2}, \ + {"bstatus", 0x6802A, 2}, {"ksv-fifo", 0x6802A, 0}, \ + {"v_h0", 0x68014, 4}, {"v_h1", 0x68018, 4}, {"v_h2", 0x6801C, 4}, \ + {"v_h3", 0x68020, 4}, {"v_h4", 0x68024, 4}, {"an", 0x6800C, 8}, \ + {"aksv", 0x68007, 5}, {"repater", 0x68028, 1} } + +#define HDCP_HDMI_INT_SET \ + {HDMI_HDCP_INT_CTRL, \ + BIT(2), BIT(6), 0, 0, 0, 0, \ + BIT(1), BIT(5), BIT(7), 0, 0, 0, 0, \ + BIT(0), BIT(4), 0, 0, 0, 0} + +#define HDCP_DP_INT_SET \ + {DP_INTERRUPT_STATUS_2, \ + BIT(17), BIT(20), BIT(24), BIT(27), 0, 0, \ + BIT(16), BIT(19), BIT(21), BIT(23), BIT(26), 0, 0, \ + BIT(15), BIT(18), BIT(22), BIT(25), 0, 0} + struct hdmi_hdcp_ctrl { u32 auth_retries; u32 tp_msgid; @@ -57,7 +232,9 @@ struct hdmi_hdcp_ctrl { struct completion r0_checked; struct hdmi_hdcp_init_data init_data; struct hdmi_hdcp_ops *ops; - bool hdmi_tx_ver_4; + struct hdcp_reg_set reg_set; + struct hdcp_int_set int_set; + struct hdcp_sink_addr_map sink_addr; }; const char *hdcp_state_name(enum hdmi_hdcp_state hdcp_state) @@ -256,6 +433,7 @@ static int hdmi_hdcp_load_keys(void *input) struct dss_io_data *io; struct dss_io_data *qfprom_io; struct hdmi_hdcp_ctrl *hdcp_ctrl = input; + struct hdcp_reg_set *reg_set; if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io || !hdcp_ctrl->init_data.qfprom_io) { @@ -274,6 +452,7 @@ static int hdmi_hdcp_load_keys(void *input) io = hdcp_ctrl->init_data.core_io; qfprom_io = hdcp_ctrl->init_data.qfprom_io; + reg_set = &hdcp_ctrl->reg_set; /* On compatible hardware, use SW keys */ reg_val = DSS_REG_R(qfprom_io, SEC_CTRL_HW_VERSION); @@ -297,7 +476,7 @@ static int hdmi_hdcp_load_keys(void *input) ksv_lsb_addr = HDCP_KSV_LSB; ksv_msb_addr = HDCP_KSV_MSB; - if (hdcp_ctrl->hdmi_tx_ver_4) { + if (hdcp_ctrl->init_data.sec_access) { ksv_lsb_addr += HDCP_KSV_VERSION_4_OFFSET; ksv_msb_addr += HDCP_KSV_VERSION_4_OFFSET; } @@ -322,27 +501,121 @@ static int hdmi_hdcp_load_keys(void *input) goto end; } - DSS_REG_W(io, HDMI_HDCP_SW_LOWER_AKSV, aksv_lsb); - DSS_REG_W(io, HDMI_HDCP_SW_UPPER_AKSV, aksv_msb); + DSS_REG_W(io, reg_set->aksv_lsb, aksv_lsb); + DSS_REG_W(io, reg_set->aksv_msb, aksv_msb); /* Setup seed values for random number An */ - DSS_REG_W(io, HDMI_HDCP_ENTROPY_CTRL0, 0xB1FFB0FF); - DSS_REG_W(io, HDMI_HDCP_ENTROPY_CTRL1, 0xF00DFACE); - - /* Disable the RngCipher state */ - DSS_REG_W(io, HDMI_HDCP_DEBUG_CTRL, - DSS_REG_R(io, HDMI_HDCP_DEBUG_CTRL) & ~(BIT(2))); + DSS_REG_W(io, reg_set->entropy_ctrl0, 0xB1FFB0FF); + DSS_REG_W(io, reg_set->entropy_ctrl1, 0xF00DFACE); /* make sure hw is programmed */ wmb(); - DSS_REG_W(io, HDMI_HDCP_CTRL, BIT(0)); + /* enable hdcp engine */ + DSS_REG_W(io, reg_set->ctrl, 0x1); hdcp_ctrl->hdcp_state = HDCP_STATE_AUTHENTICATING; end: return rc; } +static int hdmi_hdcp_read(struct hdmi_hdcp_ctrl *hdcp_ctrl, + struct hdcp_sink_addr *sink, + u8 *buf, bool realign) +{ + u32 rc = 0; + struct hdmi_tx_ddc_data ddc_data; + + if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) { + reset_hdcp_ddc_failures(hdcp_ctrl); + + memset(&ddc_data, 0, sizeof(ddc_data)); + ddc_data.dev_addr = 0x74; + ddc_data.offset = sink->addr; + ddc_data.data_buf = buf; + ddc_data.data_len = sink->len; + ddc_data.request_len = sink->len; + ddc_data.retry = 5; + ddc_data.what = sink->name; + ddc_data.retry_align = realign; + + hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; + + rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl); + if (rc) + DEV_ERR("%s: %s: %s read failed\n", __func__, + HDCP_STATE_NAME, sink->name); + } else if (IS_ENABLED(CONFIG_FB_MSM_MDSS_DP_PANEL) && + hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) { + struct edp_cmd cmd = {0}; + + cmd.read = 1; + cmd.addr = sink->addr; + cmd.out_buf = buf; + cmd.len = sink->len; + + rc = dp_aux_read(hdcp_ctrl->init_data.dp_data, &cmd); + if (rc) + DEV_ERR("%s: %s: %s read failed\n", __func__, + HDCP_STATE_NAME, sink->name); + } + + return rc; +} + +static int hdmi_hdcp_write(struct hdmi_hdcp_ctrl *hdcp_ctrl, + u32 offset, u32 len, u8 *buf, char *name) +{ + int rc = 0; + struct hdmi_tx_ddc_data ddc_data; + + if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) { + memset(&ddc_data, 0, sizeof(ddc_data)); + + ddc_data.dev_addr = 0x74; + ddc_data.offset = offset; + ddc_data.data_buf = buf; + ddc_data.data_len = len; + ddc_data.what = name; + hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; + + rc = hdmi_ddc_write(hdcp_ctrl->init_data.ddc_ctrl); + if (rc) + DEV_ERR("%s: %s: %s write failed\n", __func__, + HDCP_STATE_NAME, name); + } else if (IS_ENABLED(CONFIG_FB_MSM_MDSS_DP_PANEL) && + hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) { + struct edp_cmd cmd = {0}; + + cmd.addr = offset; + cmd.len = len; + cmd.datap = buf; + + rc = dp_aux_write(hdcp_ctrl->init_data.dp_data, &cmd); + if (rc) + DEV_ERR("%s: %s: %s read failed\n", __func__, + HDCP_STATE_NAME, name); + } + + return rc; +} + +static void hdmi_hdcp_enable_interrupts(struct hdmi_hdcp_ctrl *hdcp_ctrl) +{ + u32 intr_reg; + struct dss_io_data *io; + struct hdcp_int_set *isr; + + io = hdcp_ctrl->init_data.core_io; + isr = &hdcp_ctrl->int_set; + + intr_reg = DSS_REG_R(io, isr->int_reg); + + intr_reg |= HDCP_INT_CLR | HDCP_INT_EN; + + DSS_REG_W(io, isr->int_reg, intr_reg); +} + static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) { int rc; @@ -353,13 +626,12 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) bool is_match; struct dss_io_data *io; struct dss_io_data *hdcp_io; + struct hdcp_reg_set *reg_set; u8 aksv[5], *bksv = NULL; u8 an[8]; u8 bcaps; - struct hdmi_tx_ddc_data ddc_data; - u32 link0_status, an_ready, keys_state; + u32 link0_status; u8 buf[0xFF]; - struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG]; u32 phy_addr; u32 ret = 0; @@ -376,6 +648,7 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) bksv = hdcp_ctrl->current_tp.bksv; io = hdcp_ctrl->init_data.core_io; hdcp_io = hdcp_ctrl->init_data.hdcp_io; + reg_set = &hdcp_ctrl->reg_set; if (HDCP_STATE_AUTHENTICATING != hdcp_ctrl->hdcp_state) { DEV_ERR("%s: %s: invalid state. returning\n", __func__, @@ -384,32 +657,14 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) goto error; } - /* Clear any DDC failures from previous tries */ - reset_hdcp_ddc_failures(hdcp_ctrl); - - /* - * Read BCAPS - * We need to first try to read an HDCP register on the sink to see if - * the sink is ready for HDCP authentication - */ - memset(&ddc_data, 0, sizeof(ddc_data)); - ddc_data.dev_addr = 0x74; - ddc_data.offset = 0x40; - ddc_data.data_buf = &bcaps; - ddc_data.data_len = 1; - ddc_data.request_len = 1; - ddc_data.retry = 5; - ddc_data.what = "Bcaps"; - - hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; - - rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl); - if (rc) { - DEV_ERR("%s: %s: BCAPS read failed\n", __func__, - HDCP_STATE_NAME); + rc = hdmi_hdcp_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bcaps, + &bcaps, false); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: error reading bcaps\n", __func__); goto error; } - DEV_DBG("%s: %s: BCAPS=%02x\n", __func__, HDCP_STATE_NAME, bcaps); + + hdmi_hdcp_enable_interrupts(hdcp_ctrl); /* receiver (0), repeater (1) */ hdcp_ctrl->current_tp.ds_type = @@ -419,7 +674,7 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) if (hdcp_ctrl->tz_hdcp) { memset(scm_buf, 0x00, sizeof(scm_buf)); - scm_buf[0].addr = phy_addr + HDMI_HDCP_RCVPORT_DATA12; + scm_buf[0].addr = phy_addr + reg_set->data12; scm_buf[0].val = bcaps; ret = hdcp_scm_call(scm_buf, &resp); @@ -429,30 +684,19 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) rc = -EINVAL; goto error; } - } else if (hdcp_ctrl->hdmi_tx_ver_4) { - DSS_REG_W(hdcp_io, HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA12, - bcaps); + } else if (hdcp_ctrl->init_data.sec_access) { + DSS_REG_W(hdcp_io, reg_set->sec_data12, bcaps); } else { - DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA12, bcaps); + DSS_REG_W(io, reg_set->data12, bcaps); } /* Wait for HDCP keys to be checked and validated */ - timeout_count = 100; - keys_state = (link0_status >> 28) & 0x7; - while ((keys_state != HDCP_KEYS_STATE_VALID) && - --timeout_count) { - link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS); - keys_state = (link0_status >> 28) & 0x7; - DEV_DBG("%s: %s: Keys not ready(%d). s=%d\n, l0=%0x08x", - __func__, HDCP_STATE_NAME, timeout_count, - keys_state, link0_status); - msleep(20); - } - - if (!timeout_count) { - DEV_ERR("%s: %s: Invalid Keys State: %d\n", __func__, - HDCP_STATE_NAME, keys_state); - rc = -EINVAL; + rc = readl_poll_timeout(io->base + reg_set->status, link0_status, + ((link0_status >> reg_set->keys_offset) & 0x7) + == HDCP_KEYS_STATE_VALID, + HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: key not ready\n", __func__); goto error; } @@ -460,39 +704,39 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) * 1.1_Features turned off by default. * No need to write AInfo since 1.1_Features is disabled. */ - DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA4, 0); + DSS_REG_W(io, reg_set->data4, 0); /* Wait for An0 and An1 bit to be ready */ - timeout_count = 100; - do { - link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS); - an_ready = (link0_status & BIT(8)) && (link0_status & BIT(9)); - if (!an_ready) { - DEV_DBG("%s: %s: An not ready(%d). l0_status=0x%08x\n", - __func__, HDCP_STATE_NAME, timeout_count, - link0_status); - msleep(20); - } - } while (!an_ready && --timeout_count); - - if (!timeout_count) { - rc = -ETIMEDOUT; - DEV_ERR("%s: %s: timedout, An0=%ld, An1=%ld\n", __func__, - HDCP_STATE_NAME, (link0_status & BIT(8)) >> 8, - (link0_status & BIT(9)) >> 9); + rc = readl_poll_timeout(io->base + reg_set->status, link0_status, + (link0_status & (BIT(8) | BIT(9))), + HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: An not ready\n", __func__); goto error; } /* As per hardware recommendations, wait before reading An */ msleep(20); - /* Read An0 and An1 */ - link0_an_0 = DSS_REG_R(io, HDMI_HDCP_RCVPORT_DATA5); - link0_an_1 = DSS_REG_R(io, HDMI_HDCP_RCVPORT_DATA6); + /* + * As per hardware recommendation, for DP, read AN0 and AN1 again + * with a delay of 1 micro second each. + */ + link0_an_0 = DSS_REG_R(io, reg_set->data5); + if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) { + udelay(1); + link0_an_0 = DSS_REG_R(io, reg_set->data5); + } + + link0_an_1 = DSS_REG_R(io, reg_set->data6); + if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) { + udelay(1); + link0_an_0 = DSS_REG_R(io, reg_set->data6); + } /* Read AKSV */ - link0_aksv_0 = DSS_REG_R(io, HDMI_HDCP_RCVPORT_DATA3); - link0_aksv_1 = DSS_REG_R(io, HDMI_HDCP_RCVPORT_DATA4); + link0_aksv_0 = DSS_REG_R(io, reg_set->data3); + link0_aksv_1 = DSS_REG_R(io, reg_set->data4); /* Copy An and AKSV to byte arrays for transmission */ aksv[0] = link0_aksv_0 & 0xFF; @@ -510,55 +754,21 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) an[6] = (link0_an_1 >> 16) & 0xFF; an[7] = (link0_an_1 >> 24) & 0xFF; - /* Write An to offset 0x18 */ - memset(&ddc_data, 0, sizeof(ddc_data)); - ddc_data.dev_addr = 0x74; - ddc_data.offset = 0x18; - ddc_data.data_buf = an; - ddc_data.data_len = 8; - ddc_data.what = "An"; - hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; - - rc = hdmi_ddc_write(hdcp_ctrl->init_data.ddc_ctrl); - if (rc) { - DEV_ERR("%s: %s: An write failed\n", __func__, HDCP_STATE_NAME); + rc = hdmi_hdcp_write(hdcp_ctrl, 0x18, 8, an, "an"); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: error writing an to sink\n", __func__); goto error; } - /* Write AKSV to offset 0x10 */ - memset(&ddc_data, 0, sizeof(ddc_data)); - ddc_data.dev_addr = 0x74; - ddc_data.offset = 0x10; - ddc_data.data_buf = aksv; - ddc_data.data_len = 5; - ddc_data.what = "Aksv"; - hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; - - rc = hdmi_ddc_write(hdcp_ctrl->init_data.ddc_ctrl); - if (rc) { - DEV_ERR("%s: %s: AKSV write failed\n", __func__, - HDCP_STATE_NAME); + rc = hdmi_hdcp_write(hdcp_ctrl, 0x10, 5, aksv, "aksv"); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: error writing aksv to sink\n", __func__); goto error; } - DEV_DBG("%s: %s: Link0-AKSV=%02x%08x\n", __func__, - HDCP_STATE_NAME, link0_aksv_1 & 0xFF, link0_aksv_0); - - /* Read BKSV at offset 0x00 */ - memset(&ddc_data, 0, sizeof(ddc_data)); - ddc_data.dev_addr = 0x74; - ddc_data.offset = 0x00; - ddc_data.data_buf = bksv; - ddc_data.data_len = 5; - ddc_data.request_len = 5; - ddc_data.retry = 5; - ddc_data.what = "Bksv"; - - hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; - rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl); - if (rc) { - DEV_ERR("%s: %s: BKSV read failed\n", __func__, - HDCP_STATE_NAME); + rc = hdmi_hdcp_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bksv, bksv, false); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: error reading bksv from sink\n", __func__); goto error; } @@ -584,9 +794,9 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) if (hdcp_ctrl->tz_hdcp) { memset(scm_buf, 0x00, sizeof(scm_buf)); - scm_buf[0].addr = phy_addr + HDMI_HDCP_RCVPORT_DATA0; + scm_buf[0].addr = phy_addr + reg_set->data0; scm_buf[0].val = link0_bksv_0; - scm_buf[1].addr = phy_addr + HDMI_HDCP_RCVPORT_DATA1; + scm_buf[1].addr = phy_addr + reg_set->data1; scm_buf[1].val = link0_bksv_1; ret = hdcp_scm_call(scm_buf, &resp); @@ -597,52 +807,45 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) rc = -EINVAL; goto error; } - } else if (hdcp_ctrl->hdmi_tx_ver_4) { - DSS_REG_W(hdcp_io, HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA0, - link0_bksv_0); - DSS_REG_W(hdcp_io, HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA1, - link0_bksv_1); + } else if (hdcp_ctrl->init_data.sec_access) { + DSS_REG_W(hdcp_io, reg_set->sec_data0, link0_bksv_0); + DSS_REG_W(hdcp_io, reg_set->sec_data1, link0_bksv_1); } else { - DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA0, link0_bksv_0); - DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA1, link0_bksv_1); + DSS_REG_W(io, reg_set->data0, link0_bksv_0); + DSS_REG_W(io, reg_set->data1, link0_bksv_1); } - /* Enable HDCP interrupts and ack/clear any stale interrupts */ - DSS_REG_W(io, HDMI_HDCP_INT_CTRL, 0xE6); - /* * HDCP Compliace Test case 1A-01: * Wait here at least 100ms before reading R0' */ msleep(125); - /* Read R0' at offset 0x08 */ + /* Wait for HDCP R0 computation to be completed */ + rc = readl_poll_timeout(io->base + reg_set->status, link0_status, + link0_status & BIT(reg_set->r0_offset), + HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: R0 not ready\n", __func__); + goto error; + } + memset(buf, 0, sizeof(buf)); - memset(&ddc_data, 0, sizeof(ddc_data)); - ddc_data.dev_addr = 0x74; - ddc_data.offset = 0x08; - ddc_data.data_buf = buf; - ddc_data.data_len = 2; - ddc_data.request_len = 2; - ddc_data.retry = 5; - ddc_data.what = "R0'"; - - hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; - - rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl); - if (rc) { - DEV_ERR("%s: %s: R0' read failed\n", __func__, HDCP_STATE_NAME); + rc = hdmi_hdcp_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.r0, buf, false); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: error reading R0' from sink\n", __func__); goto error; } + DEV_DBG("%s: %s: R0'=%02x%02x\n", __func__, HDCP_STATE_NAME, buf[1], buf[0]); /* Write R0' to HDCP registers and check to see if it is a match */ reinit_completion(&hdcp_ctrl->r0_checked); - DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA2_0, (((u32)buf[1]) << 8) | buf[0]); + DSS_REG_W(io, reg_set->data2_0, (((u32)buf[1]) << 8) | buf[0]); timeout_count = wait_for_completion_timeout( &hdcp_ctrl->r0_checked, HZ*2); - link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS); + link0_status = DSS_REG_R(io, reg_set->status); is_match = link0_status & BIT(12); if (!is_match) { DEV_DBG("%s: %s: Link0_Status=0x%08x\n", __func__, @@ -663,166 +866,108 @@ static int hdmi_hdcp_authentication_part1(struct hdmi_hdcp_ctrl *hdcp_ctrl) } error: - if (rc) { + if (rc) DEV_ERR("%s: %s: Authentication Part I failed\n", __func__, hdcp_ctrl ? HDCP_STATE_NAME : "???"); - } else { - /* Enable HDCP Encryption */ - DSS_REG_W(io, HDMI_HDCP_CTRL, BIT(0) | BIT(8)); + else DEV_INFO("%s: %s: Authentication Part I successful\n", __func__, HDCP_STATE_NAME); - } return rc; } /* hdmi_hdcp_authentication_part1 */ -#define READ_WRITE_V_H(io, off, name, reg, wr) \ -do { \ - ddc_data.offset = (off); \ - memset(what, 0, sizeof(what)); \ - snprintf(what, sizeof(what), (name)); \ - hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; \ - rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl); \ - if (rc) { \ - DEV_ERR("%s: %s: Read %s failed\n", __func__, HDCP_STATE_NAME, \ - what); \ - goto error; \ - } \ - DEV_DBG("%s: %s: %s: buf[0]=%x, buf[1]=%x, buf[2]=%x, buf[3]=%x\n", \ - __func__, HDCP_STATE_NAME, what, buf[0], buf[1], \ - buf[2], buf[3]); \ - if (wr) { \ - DSS_REG_W((io), (reg), \ - (buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0])); \ - } \ -} while (0); +static int hdmi_hdcp_set_v_h(struct hdmi_hdcp_ctrl *hdcp_ctrl, + struct hdmi_hdcp_reg_data *rd, u8 *buf) +{ + int rc; + struct dss_io_data *io; + + if (!hdcp_ctrl->tz_hdcp && hdcp_ctrl->init_data.sec_access) + io = hdcp_ctrl->init_data.hdcp_io; + else + io = hdcp_ctrl->init_data.core_io; + + rc = hdmi_hdcp_read(hdcp_ctrl, rd->sink, buf, false); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: error reading %s\n", __func__, rd->sink->name); + goto end; + } + + DEV_DBG("%s: %s: %s: buf[0]=%x, buf[1]=%x, buf[2]=%x, buf[3]=%x\n", + __func__, HDCP_STATE_NAME, rd->sink->name, buf[0], buf[1], + buf[2], buf[3]); + + if (!hdcp_ctrl->tz_hdcp) + DSS_REG_W(io, rd->reg_id, + (buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0])); +end: + return rc; +} static int hdmi_hdcp_transfer_v_h(struct hdmi_hdcp_ctrl *hdcp_ctrl) { - char what[20]; int rc = 0; u8 buf[4]; - struct hdmi_tx_ddc_data ddc_data; - struct dss_io_data *io; - struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG]; u32 phy_addr; - + struct hdcp_reg_set *reg_set = &hdcp_ctrl->reg_set; struct hdmi_hdcp_reg_data reg_data[] = { - {HDMI_HDCP_RCVPORT_DATA7, 0x20, "V' H0"}, - {HDMI_HDCP_RCVPORT_DATA8, 0x24, "V' H1"}, - {HDMI_HDCP_RCVPORT_DATA9, 0x28, "V' H2"}, - {HDMI_HDCP_RCVPORT_DATA10, 0x2C, "V' H3"}, - {HDMI_HDCP_RCVPORT_DATA11, 0x30, "V' H4"}, + {reg_set_data(7), &hdcp_ctrl->sink_addr.v_h0}, + {reg_set_data(8), &hdcp_ctrl->sink_addr.v_h1}, + {reg_set_data(9), &hdcp_ctrl->sink_addr.v_h2}, + {reg_set_data(10), &hdcp_ctrl->sink_addr.v_h3}, + {reg_set_data(11), &hdcp_ctrl->sink_addr.v_h4}, }; - u32 size = sizeof(reg_data)/sizeof(reg_data[0]); - u32 iter = 0; - u32 ret = 0; - u32 resp = 0; - - if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) { - DEV_ERR("%s: invalid input\n", __func__); - return -EINVAL; - } + u32 size = ARRAY_SIZE(reg_data); + u32 iter = 0, ret = 0, resp = 0; phy_addr = hdcp_ctrl->init_data.phy_addr; - io = hdcp_ctrl->init_data.core_io; - memset(&ddc_data, 0, sizeof(ddc_data)); - ddc_data.dev_addr = 0x74; - ddc_data.data_buf = buf; - ddc_data.data_len = 4; - ddc_data.request_len = 4; - ddc_data.retry = 5; - ddc_data.what = what; - - if (hdcp_ctrl->tz_hdcp) { - memset(scm_buf, 0x00, sizeof(scm_buf)); + memset(scm_buf, 0x00, sizeof(scm_buf)); - for (iter = 0; iter < size && iter < SCM_HDCP_MAX_REG; iter++) { - struct hdmi_hdcp_reg_data *rd = reg_data + iter; + for (iter = 0; iter < size; iter++) { + struct hdmi_hdcp_reg_data *rd = reg_data + iter; - READ_WRITE_V_H(io, rd->off, rd->name, 0, false); + memset(buf, 0, sizeof(buf)); + hdmi_hdcp_set_v_h(hdcp_ctrl, rd, buf); - rd->reg_val = buf[3] << 24 | buf[2] << 16 | + if (hdcp_ctrl->tz_hdcp) { + u32 reg_val = buf[3] << 24 | buf[2] << 16 | buf[1] << 8 | buf[0]; scm_buf[iter].addr = phy_addr + reg_data[iter].reg_id; - scm_buf[iter].val = reg_data[iter].reg_val; - } + scm_buf[iter].val = reg_val; - ret = hdcp_scm_call(scm_buf, &resp); - if (ret || resp) { - DEV_ERR("%s: error: scm_call ret = %d, resp = %d\n", - __func__, ret, resp); - rc = -EINVAL; - goto error; + ret = hdcp_scm_call(scm_buf, &resp); + if (ret || resp) { + DEV_ERR("%s: scm err: ret=%d, resp=%d\n", + __func__, ret, resp); + rc = -EINVAL; + goto error; + } } - } else if (hdcp_ctrl->hdmi_tx_ver_4) { - struct dss_io_data *hdcp_io = hdcp_ctrl->init_data.hdcp_io; - - /* Read V'.HO 4 Byte at offset 0x20 */ - READ_WRITE_V_H(hdcp_io, 0x20, "V' H0", - HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA7, true); - - /* Read V'.H1 4 Byte at offset 0x24 */ - READ_WRITE_V_H(hdcp_io, 0x24, "V' H1", - HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA8, true); - - /* Read V'.H2 4 Byte at offset 0x28 */ - READ_WRITE_V_H(hdcp_io, 0x28, "V' H2", - HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA9, true); - - /* Read V'.H3 4 Byte at offset 0x2C */ - READ_WRITE_V_H(hdcp_io, 0x2C, "V' H3", - HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA10, true); - - /* Read V'.H4 4 Byte at offset 0x30 */ - READ_WRITE_V_H(hdcp_io, 0x30, "V' H4", - HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA11, true); - } else { - /* Read V'.HO 4 Byte at offset 0x20 */ - READ_WRITE_V_H(io, 0x20, "V' H0", HDMI_HDCP_RCVPORT_DATA7, - true); - - /* Read V'.H1 4 Byte at offset 0x24 */ - READ_WRITE_V_H(io, 0x24, "V' H1", HDMI_HDCP_RCVPORT_DATA8, - true); - - /* Read V'.H2 4 Byte at offset 0x28 */ - READ_WRITE_V_H(io, 0x28, "V' H2", HDMI_HDCP_RCVPORT_DATA9, - true); - - /* Read V'.H3 4 Byte at offset 0x2C */ - READ_WRITE_V_H(io, 0x2C, "V' H3", HDMI_HDCP_RCVPORT_DATA10, - true); - - /* Read V'.H4 4 Byte at offset 0x30 */ - READ_WRITE_V_H(io, 0x30, "V' H4", HDMI_HDCP_RCVPORT_DATA11, - true); } - error: return rc; } static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) { - int rc, cnt, i; - struct hdmi_tx_ddc_data ddc_data; + int rc, i; u32 timeout_count, down_stream_devices = 0; u32 repeater_cascade_depth = 0; u8 buf[0xFF]; u8 *ksv_fifo = NULL; - u8 bcaps; - u16 bstatus, max_devs_exceeded = 0, max_cascade_exceeded = 0; - u32 link0_status; + u8 bcaps = 0; + u16 bstatus = 0, max_devs_exceeded = 0, max_cascade_exceeded = 0; + u32 status = 0, sha_status = 0; u32 ksv_bytes; struct dss_io_data *io; - + struct hdcp_reg_set *reg_set; struct scm_hdcp_req scm_buf[SCM_HDCP_MAX_REG]; u32 phy_addr; u32 ret = 0; u32 resp = 0; + u32 ksv_read_retry = 20; if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) { DEV_ERR("%s: invalid input\n", __func__); @@ -831,6 +976,7 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) } phy_addr = hdcp_ctrl->init_data.phy_addr; + reg_set = &hdcp_ctrl->reg_set; if (HDCP_STATE_AUTHENTICATING != hdcp_ctrl->hdcp_state) { DEV_DBG("%s: %s: invalid state. returning\n", __func__, @@ -844,8 +990,7 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) io = hdcp_ctrl->init_data.core_io; memset(buf, 0, sizeof(buf)); - memset(ksv_fifo, 0, - sizeof(hdcp_ctrl->current_tp.ksv_list)); + memset(ksv_fifo, 0, sizeof(hdcp_ctrl->current_tp.ksv_list)); /* * Wait until READY bit is set in BCAPS, as per HDCP specifications @@ -853,48 +998,22 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) */ timeout_count = 50; do { - timeout_count--; - /* Read BCAPS at offset 0x40 */ - memset(&ddc_data, 0, sizeof(ddc_data)); - ddc_data.dev_addr = 0x74; - ddc_data.offset = 0x40; - ddc_data.data_buf = &bcaps; - ddc_data.data_len = 1; - ddc_data.request_len = 1; - ddc_data.retry = 5; - ddc_data.what = "Bcaps"; - ddc_data.retry_align = true; - - hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; - - rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl); - if (rc) { - DEV_ERR("%s: %s: BCAPS read failed\n", __func__, - HDCP_STATE_NAME); + rc = hdmi_hdcp_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bcaps, + &bcaps, true); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: error reading bcaps\n", __func__); goto error; } msleep(100); - } while (!(bcaps & BIT(5)) && timeout_count); - - /* Read BSTATUS at offset 0x41 */ - memset(&ddc_data, 0, sizeof(ddc_data)); - ddc_data.dev_addr = 0x74; - ddc_data.offset = 0x41; - ddc_data.data_buf = buf; - ddc_data.data_len = 2; - ddc_data.request_len = 2; - ddc_data.retry = 5; - ddc_data.what = "Bstatuss"; - ddc_data.retry_align = true; - - hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; - - rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl); - if (rc) { - DEV_ERR("%s: %s: BSTATUS read failed\n", __func__, - HDCP_STATE_NAME); + } while (!(bcaps & BIT(5)) && --timeout_count); + + rc = hdmi_hdcp_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.bstatus, + buf, true); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: error reading bstatus\n", __func__); goto error; } + bstatus = buf[1]; bstatus = (bstatus << 8) | buf[0]; @@ -902,7 +1021,7 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) memset(scm_buf, 0x00, sizeof(scm_buf)); /* Write BSTATUS and BCAPS to HDCP registers */ - scm_buf[0].addr = phy_addr + HDMI_HDCP_RCVPORT_DATA12; + scm_buf[0].addr = phy_addr + reg_set->data12; scm_buf[0].val = bcaps | (bstatus << 8); ret = hdcp_scm_call(scm_buf, &resp); @@ -912,12 +1031,12 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) rc = -EINVAL; goto error; } - } else if (hdcp_ctrl->hdmi_tx_ver_4) { + } else if (hdcp_ctrl->init_data.sec_access) { DSS_REG_W(hdcp_ctrl->init_data.hdcp_io, - HDCP_SEC_TZ_HV_HLOS_HDCP_RCVPORT_DATA12, - bcaps | (bstatus << 8)); + reg_set->sec_data12, + bcaps | (bstatus << 8)); } else { - DSS_REG_W(io, HDMI_HDCP_RCVPORT_DATA12, bcaps | (bstatus << 8)); + DSS_REG_W(io, reg_set->data12, bcaps | (bstatus << 8)); } down_stream_devices = bstatus & 0x7F; @@ -972,37 +1091,28 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) * HDCP Repeaters (REPEATER == 0). */ ksv_bytes = 5 * down_stream_devices; - memset(&ddc_data, 0, sizeof(ddc_data)); - ddc_data.dev_addr = 0x74; - ddc_data.offset = 0x43; - ddc_data.data_buf = ksv_fifo; - ddc_data.data_len = ksv_bytes; - ddc_data.request_len = ksv_bytes; - ddc_data.retry = 5; - ddc_data.what = "KSV FIFO"; - - hdcp_ctrl->init_data.ddc_ctrl->ddc_data = ddc_data; - - cnt = 0; + hdcp_ctrl->sink_addr.ksv_fifo.len = ksv_bytes; + do { - rc = hdmi_ddc_read(hdcp_ctrl->init_data.ddc_ctrl); - if (rc) { - DEV_ERR("%s: %s: KSV FIFO read failed\n", __func__, - HDCP_STATE_NAME); + rc = hdmi_hdcp_read(hdcp_ctrl, &hdcp_ctrl->sink_addr.ksv_fifo, + ksv_fifo, false); + if (IS_ERR_VALUE(rc)) { + DEV_DBG("%s: could not read ksv fifo (%d)\n", + __func__, ksv_read_retry); /* * HDCP Compliace Test case 1B-01: * Wait here until all the ksv bytes have been * read from the KSV FIFO register. */ msleep(25); - } else { - break; + } - cnt++; - } while (cnt != 20); + } while (rc && --ksv_read_retry); - if (cnt == 20) + if (rc) { + DEV_ERR("%s: error reading ksv_fifo\n", __func__); goto error; + } rc = hdmi_hdcp_transfer_v_h(hdcp_ctrl); if (rc) @@ -1019,9 +1129,9 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) if (hdcp_ctrl->tz_hdcp) { memset(scm_buf, 0x00, sizeof(scm_buf)); - scm_buf[0].addr = phy_addr + HDMI_HDCP_SHA_CTRL; + scm_buf[0].addr = phy_addr + reg_set->sha_ctrl; scm_buf[0].val = HDCP_REG_ENABLE; - scm_buf[1].addr = phy_addr + HDMI_HDCP_SHA_CTRL; + scm_buf[1].addr = phy_addr + reg_set->sha_ctrl; scm_buf[1].val = HDCP_REG_DISABLE; ret = hdcp_scm_call(scm_buf, &resp); @@ -1031,16 +1141,16 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) rc = -EINVAL; goto error; } - } else if (hdcp_ctrl->hdmi_tx_ver_4) { + } else if (hdcp_ctrl->init_data.sec_access) { DSS_REG_W(hdcp_ctrl->init_data.hdcp_io, - HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_CTRL, + reg_set->sec_sha_ctrl, HDCP_REG_ENABLE); DSS_REG_W(hdcp_ctrl->init_data.hdcp_io, - HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_CTRL, + reg_set->sec_sha_ctrl, HDCP_REG_DISABLE); } else { - DSS_REG_W(io, HDMI_HDCP_SHA_CTRL, HDCP_REG_ENABLE); - DSS_REG_W(io, HDMI_HDCP_SHA_CTRL, HDCP_REG_DISABLE); + DSS_REG_W(io, reg_set->sha_ctrl, HDCP_REG_ENABLE); + DSS_REG_W(io, reg_set->sha_ctrl, HDCP_REG_DISABLE); } for (i = 0; i < ksv_bytes - 1; i++) { @@ -1048,7 +1158,7 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) if (hdcp_ctrl->tz_hdcp) { memset(scm_buf, 0x00, sizeof(scm_buf)); - scm_buf[0].addr = phy_addr + HDMI_HDCP_SHA_DATA; + scm_buf[0].addr = phy_addr + reg_set->sha_ctrl; scm_buf[0].val = ksv_fifo[i] << 16; ret = hdcp_scm_call(scm_buf, &resp); @@ -1058,12 +1168,12 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) rc = -EINVAL; goto error; } - } else if (hdcp_ctrl->hdmi_tx_ver_4) { + } else if (hdcp_ctrl->init_data.sec_access) { DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io, - HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_DATA, + reg_set->sec_sha_ctrl, ksv_fifo[i] << 16); } else { - DSS_REG_W_ND(io, HDMI_HDCP_SHA_DATA, ksv_fifo[i] << 16); + DSS_REG_W_ND(io, reg_set->sha_ctrl, ksv_fifo[i] << 16); } /* @@ -1071,31 +1181,22 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) * HDCP_SHA_BLOCK_DONE before writing any further */ if (i && !((i + 1) % 64)) { - timeout_count = 100; - while (!(DSS_REG_R(io, HDMI_HDCP_SHA_STATUS) & BIT(0)) - && (--timeout_count)) { - DEV_DBG("%s: %s: Wrote 64 bytes KSV FIFO\n", - __func__, HDCP_STATE_NAME); - DEV_DBG("%s: %s: HDCP_SHA_STATUS=%08x\n", - __func__, HDCP_STATE_NAME, - DSS_REG_R(io, HDMI_HDCP_SHA_STATUS)); - msleep(20); - } - if (!timeout_count) { - rc = -ETIMEDOUT; - DEV_ERR("%s: %s: Write KSV FIFO timedout", - __func__, HDCP_STATE_NAME); + rc = readl_poll_timeout(io->base + reg_set->sha_status, + sha_status, sha_status & BIT(0), + HDCP_POLL_SLEEP_US, + HDCP_POLL_TIMEOUT_US); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: block not done\n", __func__); goto error; } } - } /* Write l to DONE bit[0] */ if (hdcp_ctrl->tz_hdcp) { memset(scm_buf, 0x00, sizeof(scm_buf)); - scm_buf[0].addr = phy_addr + HDMI_HDCP_SHA_DATA; + scm_buf[0].addr = phy_addr + reg_set->sha_ctrl; scm_buf[0].val = (ksv_fifo[ksv_bytes - 1] << 16) | 0x1; ret = hdcp_scm_call(scm_buf, &resp); @@ -1105,43 +1206,32 @@ static int hdmi_hdcp_authentication_part2(struct hdmi_hdcp_ctrl *hdcp_ctrl) rc = -EINVAL; goto error; } - } else if (hdcp_ctrl->hdmi_tx_ver_4) { + } else if (hdcp_ctrl->init_data.sec_access) { DSS_REG_W_ND(hdcp_ctrl->init_data.hdcp_io, - HDCP_SEC_TZ_HV_HLOS_HDCP_SHA_DATA, + reg_set->sec_sha_ctrl, (ksv_fifo[ksv_bytes - 1] << 16) | 0x1); } else { - DSS_REG_W_ND(io, HDMI_HDCP_SHA_DATA, + DSS_REG_W_ND(io, reg_set->sha_ctrl, (ksv_fifo[ksv_bytes - 1] << 16) | 0x1); } /* Now wait for HDCP_SHA_COMP_DONE */ - timeout_count = 100; - while ((0x10 != (DSS_REG_R(io, HDMI_HDCP_SHA_STATUS) - & 0xFFFFFF10)) && --timeout_count) - msleep(20); - if (!timeout_count) { - rc = -ETIMEDOUT; - DEV_ERR("%s: %s: SHA computation timedout", __func__, - HDCP_STATE_NAME); + rc = readl_poll_timeout(io->base + reg_set->sha_status, sha_status, + sha_status & BIT(4), + HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: comp not done\n", __func__); goto error; } /* Wait for V_MATCHES */ - timeout_count = 100; - link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS); - while (((link0_status & BIT(20)) != BIT(20)) && --timeout_count) { - DEV_DBG("%s: %s: Waiting for V_MATCHES(%d). l0_status=0x%08x\n", - __func__, HDCP_STATE_NAME, timeout_count, link0_status); - msleep(20); - link0_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS); - } - if (!timeout_count) { - rc = -ETIMEDOUT; - DEV_ERR("%s: %s: HDCP V Match timedout", __func__, - HDCP_STATE_NAME); + rc = readl_poll_timeout(io->base + reg_set->status, status, + status & BIT(reg_set->v_offset), + HDCP_POLL_SLEEP_US, HDCP_POLL_TIMEOUT_US); + if (IS_ERR_VALUE(rc)) { + DEV_ERR("%s: V not ready\n", __func__); goto error; } - error: if (rc) DEV_ERR("%s: %s: Authentication Part II failed\n", __func__, @@ -1236,7 +1326,8 @@ static void hdmi_hdcp_auth_work(struct work_struct *work) io = hdcp_ctrl->init_data.core_io; /* Enabling Software DDC */ - DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION , DSS_REG_R(io, + if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) + DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION, DSS_REG_R(io, HDMI_DDC_ARBITRATION) & ~(BIT(4))); rc = hdmi_hdcp_authentication_part1(hdcp_ctrl); @@ -1258,7 +1349,8 @@ static void hdmi_hdcp_auth_work(struct work_struct *work) } /* Disabling software DDC before going into part3 to make sure * there is no Arbitration between software and hardware for DDC */ - DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION , DSS_REG_R(io, + if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) + DSS_REG_W_ND(io, HDMI_DDC_ARBITRATION, DSS_REG_R(io, HDMI_DDC_ARBITRATION) | (BIT(4))); error: @@ -1314,12 +1406,17 @@ int hdmi_hdcp_authenticate(void *input) DEV_DBG("%s: %s: Queuing work to start HDCP authentication", __func__, HDCP_STATE_NAME); - if (!hdmi_hdcp_load_keys(input)) + if (!hdmi_hdcp_load_keys(input)) { + flush_delayed_work(&hdcp_ctrl->hdcp_auth_work); + queue_delayed_work(hdcp_ctrl->init_data.workq, &hdcp_ctrl->hdcp_auth_work, HZ/2); - else + } else { + flush_work(&hdcp_ctrl->hdcp_int_work); + queue_work(hdcp_ctrl->init_data.workq, &hdcp_ctrl->hdcp_int_work); + } return 0; } /* hdmi_hdcp_authenticate */ @@ -1328,6 +1425,8 @@ int hdmi_hdcp_reauthenticate(void *input) { struct hdmi_hdcp_ctrl *hdcp_ctrl = (struct hdmi_hdcp_ctrl *)input; struct dss_io_data *io; + struct hdcp_reg_set *reg_set; + struct hdcp_int_set *isr; u32 hdmi_hw_version; u32 ret = 0; @@ -1337,6 +1436,8 @@ int hdmi_hdcp_reauthenticate(void *input) } io = hdcp_ctrl->init_data.core_io; + reg_set = &hdcp_ctrl->reg_set; + isr = &hdcp_ctrl->int_set; if (HDCP_STATE_AUTH_FAIL != hdcp_ctrl->hdcp_state) { DEV_DBG("%s: %s: invalid state. returning\n", __func__, @@ -1344,22 +1445,25 @@ int hdmi_hdcp_reauthenticate(void *input) return 0; } - hdmi_hw_version = DSS_REG_R(io, HDMI_VERSION); - if (hdmi_hw_version >= 0x30030000) { - DSS_REG_W(io, HDMI_CTRL_SW_RESET, BIT(1)); - DSS_REG_W(io, HDMI_CTRL_SW_RESET, 0); + if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) { + hdmi_hw_version = DSS_REG_R(io, HDMI_VERSION); + if (hdmi_hw_version >= 0x30030000) { + DSS_REG_W(io, HDMI_CTRL_SW_RESET, BIT(1)); + DSS_REG_W(io, HDMI_CTRL_SW_RESET, 0); + } + + /* Wait to be clean on DDC HW engine */ + hdmi_hdcp_hw_ddc_clean(hdcp_ctrl); } /* Disable HDCP interrupts */ - DSS_REG_W(io, HDMI_HDCP_INT_CTRL, 0); - - DSS_REG_W(io, HDMI_HDCP_RESET, BIT(0)); + DSS_REG_W(io, isr->int_reg, DSS_REG_R(io, isr->int_reg) & ~HDCP_INT_EN); - /* Wait to be clean on DDC HW engine */ - hdmi_hdcp_hw_ddc_clean(hdcp_ctrl); + if (reg_set->reset) + DSS_REG_W(io, reg_set->reset, BIT(0)); /* Disable encryption and disable the HDCP block */ - DSS_REG_W(io, HDMI_HDCP_CTRL, 0); + DSS_REG_W(io, reg_set->ctrl, 0); if (!hdmi_hdcp_load_keys(input)) queue_delayed_work(hdcp_ctrl->init_data.workq, @@ -1375,6 +1479,8 @@ void hdmi_hdcp_off(void *input) { struct hdmi_hdcp_ctrl *hdcp_ctrl = (struct hdmi_hdcp_ctrl *)input; struct dss_io_data *io; + struct hdcp_reg_set *reg_set; + struct hdcp_int_set *isr; int rc = 0; if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) { @@ -1383,6 +1489,8 @@ void hdmi_hdcp_off(void *input) } io = hdcp_ctrl->init_data.core_io; + reg_set = &hdcp_ctrl->reg_set; + isr = &hdcp_ctrl->int_set; if (HDCP_STATE_INACTIVE == hdcp_ctrl->hdcp_state) { DEV_DBG("%s: %s: inactive. returning\n", __func__, @@ -1396,7 +1504,8 @@ void hdmi_hdcp_off(void *input) * reauth works will know that the HDCP session has been turned off. */ mutex_lock(hdcp_ctrl->init_data.mutex); - DSS_REG_W(io, HDMI_HDCP_INT_CTRL, 0); + DSS_REG_W(io, isr->int_reg, + DSS_REG_R(io, isr->int_reg) & ~HDCP_INT_EN); hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE; mutex_unlock(hdcp_ctrl->init_data.mutex); @@ -1415,10 +1524,11 @@ void hdmi_hdcp_off(void *input) DEV_DBG("%s: %s: Deleted hdcp int work\n", __func__, HDCP_STATE_NAME); - DSS_REG_W(io, HDMI_HDCP_RESET, BIT(0)); + if (reg_set->reset) + DSS_REG_W(io, reg_set->reset, BIT(0)); /* Disable encryption and disable the HDCP block */ - DSS_REG_W(io, HDMI_HDCP_CTRL, 0); + DSS_REG_W(io, reg_set->ctrl, 0); DEV_DBG("%s: %s: HDCP: Off\n", __func__, HDCP_STATE_NAME); } /* hdmi_hdcp_off */ @@ -1429,6 +1539,8 @@ int hdmi_hdcp_isr(void *input) int rc = 0; struct dss_io_data *io; u32 hdcp_int_val; + struct hdcp_reg_set *reg_set; + struct hdcp_int_set *isr; if (!hdcp_ctrl || !hdcp_ctrl->init_data.core_io) { DEV_ERR("%s: invalid input\n", __func__); @@ -1437,28 +1549,33 @@ int hdmi_hdcp_isr(void *input) } io = hdcp_ctrl->init_data.core_io; + reg_set = &hdcp_ctrl->reg_set; + isr = &hdcp_ctrl->int_set; - hdcp_int_val = DSS_REG_R(io, HDMI_HDCP_INT_CTRL); + hdcp_int_val = DSS_REG_R(io, isr->int_reg); /* Ignore HDCP interrupts if HDCP is disabled */ if (HDCP_STATE_INACTIVE == hdcp_ctrl->hdcp_state) { - DSS_REG_W(io, HDMI_HDCP_INT_CTRL, HDCP_INT_CLR); + DSS_REG_W(io, isr->int_reg, hdcp_int_val | HDCP_INT_CLR); return 0; } - if (hdcp_int_val & BIT(0)) { + if (hdcp_int_val & isr->auth_success_int) { /* AUTH_SUCCESS_INT */ - DSS_REG_W(io, HDMI_HDCP_INT_CTRL, (hdcp_int_val | BIT(1))); + DSS_REG_W(io, isr->int_reg, + (hdcp_int_val | isr->auth_success_ack)); DEV_INFO("%s: %s: AUTH_SUCCESS_INT received\n", __func__, HDCP_STATE_NAME); if (HDCP_STATE_AUTHENTICATING == hdcp_ctrl->hdcp_state) complete_all(&hdcp_ctrl->r0_checked); } - if (hdcp_int_val & BIT(4)) { + if (hdcp_int_val & isr->auth_fail_int) { /* AUTH_FAIL_INT */ - u32 link_status = DSS_REG_R(io, HDMI_HDCP_LINK0_STATUS); - DSS_REG_W(io, HDMI_HDCP_INT_CTRL, (hdcp_int_val | BIT(5))); + u32 link_status = DSS_REG_R(io, reg_set->status); + + DSS_REG_W(io, isr->int_reg, + (hdcp_int_val | isr->auth_fail_ack)); DEV_INFO("%s: %s: AUTH_FAIL_INT rcvd, LINK0_STATUS=0x%08x\n", __func__, HDCP_STATE_NAME, link_status); if (HDCP_STATE_AUTHENTICATED == hdcp_ctrl->hdcp_state) { @@ -1471,23 +1588,42 @@ int hdmi_hdcp_isr(void *input) } /* Clear AUTH_FAIL_INFO as well */ - DSS_REG_W(io, HDMI_HDCP_INT_CTRL, (hdcp_int_val | BIT(7))); + DSS_REG_W(io, isr->int_reg, + (hdcp_int_val | isr->auth_fail_info_ack)); } - if (hdcp_int_val & BIT(8)) { + if (hdcp_int_val & isr->tx_req_int) { /* DDC_XFER_REQ_INT */ - DSS_REG_W(io, HDMI_HDCP_INT_CTRL, (hdcp_int_val | BIT(9))); + DSS_REG_W(io, isr->int_reg, + (hdcp_int_val | isr->tx_req_ack)); DEV_INFO("%s: %s: DDC_XFER_REQ_INT received\n", __func__, HDCP_STATE_NAME); } - if (hdcp_int_val & BIT(12)) { + if (hdcp_int_val & isr->tx_req_done_int) { /* DDC_XFER_DONE_INT */ - DSS_REG_W(io, HDMI_HDCP_INT_CTRL, (hdcp_int_val | BIT(13))); + DSS_REG_W(io, isr->int_reg, + (hdcp_int_val | isr->tx_req_done_ack)); DEV_INFO("%s: %s: DDC_XFER_DONE received\n", __func__, HDCP_STATE_NAME); } + if (hdcp_int_val & isr->encryption_ready) { + /* Encryption enabled */ + DSS_REG_W(io, isr->int_reg, + (hdcp_int_val | isr->encryption_ready_ack)); + DEV_INFO("%s: %s: encryption ready received\n", __func__, + HDCP_STATE_NAME); + } + + if (hdcp_int_val & isr->encryption_not_ready) { + /* Encryption enabled */ + DSS_REG_W(io, isr->int_reg, + (hdcp_int_val | isr->encryption_not_ready_ack)); + DEV_INFO("%s: %s: encryption not ready received\n", __func__, + HDCP_STATE_NAME); + } + error: return rc; } /* hdmi_hdcp_isr */ @@ -1605,6 +1741,27 @@ void hdmi_hdcp_deinit(void *input) kfree(hdcp_ctrl); } /* hdmi_hdcp_deinit */ +static void hdmi_hdcp_update_client_reg_set(struct hdmi_hdcp_ctrl *hdcp_ctrl) +{ + if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_HDMI) { + struct hdcp_reg_set reg_set = HDCP_REG_SET_CLIENT_HDMI; + struct hdcp_sink_addr_map sink_addr = HDCP_HDMI_SINK_ADDR_MAP; + struct hdcp_int_set isr = HDCP_HDMI_INT_SET; + + hdcp_ctrl->reg_set = reg_set; + hdcp_ctrl->sink_addr = sink_addr; + hdcp_ctrl->int_set = isr; + } else if (hdcp_ctrl->init_data.client_id == HDCP_CLIENT_DP) { + struct hdcp_reg_set reg_set = HDCP_REG_SET_CLIENT_DP; + struct hdcp_sink_addr_map sink_addr = HDCP_DP_SINK_ADDR_MAP; + struct hdcp_int_set isr = HDCP_DP_INT_SET; + + hdcp_ctrl->reg_set = reg_set; + hdcp_ctrl->sink_addr = sink_addr; + hdcp_ctrl->int_set = isr; + } +} + void *hdmi_hdcp_init(struct hdmi_hdcp_init_data *init_data) { struct hdmi_hdcp_ctrl *hdcp_ctrl = NULL; @@ -1624,9 +1781,8 @@ void *hdmi_hdcp_init(struct hdmi_hdcp_init_data *init_data) goto error; } - if (init_data->hdmi_tx_ver >= HDMI_TX_VERSION_4 - && !init_data->hdcp_io) { - DEV_ERR("%s: hdcp_io required for HDMI Tx Ver 4\n", __func__); + if (init_data->sec_access && !init_data->hdcp_io) { + DEV_ERR("%s: hdcp_io required\n", __func__); goto error; } @@ -1638,8 +1794,8 @@ void *hdmi_hdcp_init(struct hdmi_hdcp_init_data *init_data) hdcp_ctrl->init_data = *init_data; hdcp_ctrl->ops = &ops; - hdcp_ctrl->hdmi_tx_ver_4 = - (init_data->hdmi_tx_ver >= HDMI_TX_VERSION_4); + + hdmi_hdcp_update_client_reg_set(hdcp_ctrl); if (sysfs_create_group(init_data->sysfs_kobj, &hdmi_hdcp_fs_attr_group)) { @@ -1653,7 +1809,7 @@ void *hdmi_hdcp_init(struct hdmi_hdcp_init_data *init_data) hdcp_ctrl->hdcp_state = HDCP_STATE_INACTIVE; init_completion(&hdcp_ctrl->r0_checked); - if (!hdcp_ctrl->hdmi_tx_ver_4) { + if (!hdcp_ctrl->init_data.sec_access) { ret = scm_is_call_available(SCM_SVC_HDCP, SCM_CMD_HDCP); if (ret <= 0) { DEV_ERR("%s: secure hdcp service unavailable, ret = %d", diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h index 7dda3ff5c67d..4f2bdc4bfd3d 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012, 2014-2015 The Linux Foundation. All rights reserved. +/* Copyright (c) 2012, 2014-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -17,6 +17,11 @@ #include <video/msm_hdmi_modes.h> #include <soc/qcom/scm.h> +enum hdcp_client_id { + HDCP_CLIENT_HDMI, + HDCP_CLIENT_DP, +}; + enum hdmi_hdcp_state { HDCP_STATE_INACTIVE, HDCP_STATE_AUTHENTICATING, @@ -37,10 +42,13 @@ struct hdmi_hdcp_init_data { void *cb_data; void (*notify_status)(void *cb_data, enum hdmi_hdcp_state status); struct hdmi_tx_ddc_ctrl *ddc_ctrl; + void *dp_data; u32 phy_addr; u32 hdmi_tx_ver; struct msm_hdmi_mode_timing_info *timing; bool tethered; + bool sec_access; + enum hdcp_client_id client_id; }; struct hdmi_hdcp_ops { diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index cd3017219005..050c4a4cecdf 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -1801,6 +1801,7 @@ static int hdmi_tx_init_hdcp(struct hdmi_tx_ctrl *hdmi_ctrl) hdcp_init_data.notify_status = hdmi_tx_hdcp_cb; hdcp_init_data.cb_data = (void *)hdmi_ctrl; hdcp_init_data.hdmi_tx_ver = hdmi_ctrl->hdmi_tx_major_version; + hdcp_init_data.sec_access = true; hdcp_init_data.timing = &hdmi_ctrl->timing; if (hdmi_ctrl->hdcp14_present) { diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c index 518b84fbad51..a9571a4b8d15 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -1703,6 +1703,24 @@ static int mdss_mdp_irq_clk_setup(struct mdss_data_type *mdata) pr_debug("unable to get CX reg. rc=%d\n", PTR_RET(mdata->vdd_cx)); mdata->vdd_cx = NULL; + } else { + /* Parse CX voltage settings */ + ret = of_property_read_u32(mdata->pdev->dev.of_node, + "vdd-cx-min-uV", &mdata->vdd_cx_min_uv); + if (ret) { + pr_err("min uV for vdd-cx not specified. rc=%d\n", ret); + return ret; + } + + ret = of_property_read_u32(mdata->pdev->dev.of_node, + "vdd-cx-max-uV", &mdata->vdd_cx_max_uv); + if (ret) { + pr_err("max uV for vdd-cx not specified. rc=%d\n", ret); + return ret; + } + + pr_debug("vdd_cx [min_uV, max_uV] = [%d %d]\n", + mdata->vdd_cx_min_uv, mdata->vdd_cx_max_uv); } mdata->reg_bus_clt = mdss_reg_bus_vote_client_create("mdp\0"); @@ -1947,7 +1965,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); @@ -4744,8 +4761,8 @@ static int mdss_mdp_cx_ctrl(struct mdss_data_type *mdata, int enable) if (enable) { rc = regulator_set_voltage( mdata->vdd_cx, - RPM_REGULATOR_CORNER_SVS_SOC, - RPM_REGULATOR_CORNER_SUPER_TURBO); + mdata->vdd_cx_min_uv, + mdata->vdd_cx_max_uv); if (rc < 0) goto vreg_set_voltage_fail; @@ -4764,8 +4781,8 @@ static int mdss_mdp_cx_ctrl(struct mdss_data_type *mdata, int enable) } rc = regulator_set_voltage( mdata->vdd_cx, - RPM_REGULATOR_CORNER_NONE, - RPM_REGULATOR_CORNER_SUPER_TURBO); + 0, + mdata->vdd_cx_max_uv); if (rc < 0) goto vreg_set_voltage_fail; } 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/mm_types.h b/include/linux/mm_types.h index 9f9e60736eba..ea0009064bbc 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -522,10 +522,6 @@ struct mm_struct { #ifdef CONFIG_HUGETLB_PAGE atomic_long_t hugetlb_usage; #endif -#ifdef CONFIG_MSM_APP_SETTINGS - int app_setting; -#endif - }; static inline void mm_init_cpumask(struct mm_struct *mm) 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/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/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/events/core.c b/kernel/events/core.c index 96100cc046c5..32e2617d654f 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -158,6 +158,7 @@ enum event_type_t { struct static_key_deferred perf_sched_events __read_mostly; static DEFINE_PER_CPU(atomic_t, perf_cgroup_events); static DEFINE_PER_CPU(int, perf_sched_cb_usages); +static DEFINE_PER_CPU(bool, is_idle); static atomic_t nr_mmap_events __read_mostly; static atomic_t nr_comm_events __read_mostly; @@ -3388,9 +3389,12 @@ static int perf_event_read(struct perf_event *event, bool group) .group = group, .ret = 0, }; - smp_call_function_single(event->oncpu, - __perf_event_read, &data, 1); - ret = data.ret; + if (!event->attr.exclude_idle || + !per_cpu(is_idle, event->oncpu)) { + smp_call_function_single(event->oncpu, + __perf_event_read, &data, 1); + ret = data.ret; + } } else if (event->state == PERF_EVENT_STATE_INACTIVE) { struct perf_event_context *ctx = event->ctx; unsigned long flags; @@ -9479,6 +9483,25 @@ perf_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) return NOTIFY_OK; } +static int event_idle_notif(struct notifier_block *nb, unsigned long action, + void *data) +{ + switch (action) { + case IDLE_START: + __this_cpu_write(is_idle, true); + break; + case IDLE_END: + __this_cpu_write(is_idle, false); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block perf_event_idle_nb = { + .notifier_call = event_idle_notif, +}; + void __init perf_event_init(void) { int ret; @@ -9492,6 +9515,7 @@ void __init perf_event_init(void) perf_pmu_register(&perf_task_clock, NULL, -1); perf_tp_register(); perf_cpu_notifier(perf_cpu_notify); + idle_notifier_register(&perf_event_idle_nb); register_reboot_notifier(&perf_reboot_notifier); ret = init_hw_breakpoint(); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 58303b3dc356..db0472b37feb 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -85,9 +85,6 @@ #ifdef CONFIG_PARAVIRT #include <asm/paravirt.h> #endif -#ifdef CONFIG_MSM_APP_SETTINGS -#include <asm/app_api.h> -#endif #include "sched.h" #include "../workqueue_internal.h" @@ -5895,11 +5892,6 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev, fire_sched_out_preempt_notifiers(prev, next); prepare_lock_switch(rq, next); prepare_arch_switch(next); - -#ifdef CONFIG_MSM_APP_SETTINGS - if (use_app_setting) - switch_app_setting_bit(prev, next); -#endif } /** 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/mm/mmap.c b/mm/mmap.c index 8b0a0ed2c466..6c561acdca92 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -48,10 +48,6 @@ #include <asm/tlb.h> #include <asm/mmu_context.h> -#ifdef CONFIG_MSM_APP_SETTINGS -#include <asm/app_api.h> -#endif - #include "internal.h" #ifndef arch_mmap_check @@ -1301,11 +1297,6 @@ unsigned long do_mmap(struct file *file, unsigned long addr, if (!len) return -EINVAL; -#ifdef CONFIG_MSM_APP_SETTINGS - if (use_app_setting) - apply_app_setting_bit(file); -#endif - /* * Does the application expect PROT_READ to imply PROT_EXEC? * 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.c b/sound/soc/codecs/wcd934x/wcd934x.c index af3bbafeefe7..8c2387dc194b 100644 --- a/sound/soc/codecs/wcd934x/wcd934x.c +++ b/sound/soc/codecs/wcd934x/wcd934x.c @@ -5556,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; } @@ -5567,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 8ee14eff2d98..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", |
