diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2018-07-09 05:58:28 -0700 |
---|---|---|
committer | Linux Build Service Account <lnxbuild@localhost> | 2018-07-09 05:58:28 -0700 |
commit | 0af07ac8a44d9a4970d1299cefaf235edcbfc148 (patch) | |
tree | fe72492153e6c45147639ed43647e2c607d506fa | |
parent | 404fa617fe7bfd66f0ff0290d1099bb400fa9304 (diff) | |
parent | af6c12919000fc0891eb4347653091bc93bd13fc (diff) |
Merge af6c12919000fc0891eb4347653091bc93bd13fc on remote branchLA.UM.6.3.r6-01900-sdm845.0
Change-Id: I25e45f1d2072d218a8002609d6e3480735b7663a
20 files changed, 202 insertions, 78 deletions
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index 593aad56c0ba..3253a8fdc93f 100644 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -298,6 +298,12 @@ Required properties: Required properties: - compatible : "qcom,msm-audio-apr" + This device is added to represent APR module. + + - qcom,subsys-name: This value provides the subsystem name where codec + is present. It can be "apr_modem" or "apr_adsp". This + property enable apr driver to receive subsystem up/down + notification from modem/adsp. * msm-ocmem-audio @@ -648,6 +654,8 @@ Example: qcom,msm-audio-apr { compatible = "qcom,msm-audio-apr"; + + qcom,subsys-name = "apr_adsp"; }; qcom,msm-ocmem-audio { diff --git a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi index ac205ddc2e6b..a6e47ba6d1a9 100644 --- a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi @@ -299,6 +299,7 @@ audio_apr: qcom,msm-audio-apr { compatible = "qcom,msm-audio-apr"; + qcom,subsys-name = "apr_adsp"; }; dai_pri_auxpcm: qcom,msm-pri-auxpcm { diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi index 025d9a2b61aa..479e8ffa9c59 100644 --- a/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs605-lc-mtp.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, 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 @@ -179,6 +179,10 @@ /delete-property/ parent-supply; }; +&gpu_cx_gdsc { + /delete-property/ parent-supply; +}; + &mdss_dsi_phy0 { /delete-property/ vdda-0p9-supply; }; diff --git a/arch/arm64/boot/dts/qcom/qcs605-pm660-pm8005-regulator.dtsi b/arch/arm64/boot/dts/qcom/qcs605-pm660-pm8005-regulator.dtsi index a881ec408587..f9179cb3af0d 100644 --- a/arch/arm64/boot/dts/qcom/qcs605-pm660-pm8005-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs605-pm660-pm8005-regulator.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, 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 @@ -102,7 +102,8 @@ pm8005_s1_level: regulator-pm8005-s1-level { regulator-name = "pm8005_s1_level"; qcom,set = <RPMH_REGULATOR_SET_ALL>; - regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>; + regulator-min-microvolt + = <RPMH_REGULATOR_LEVEL_RETENTION>; regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>; qcom,min-dropout-voltage-level = <(-1)>; }; @@ -110,7 +111,8 @@ pm8005_s1_level_ao: regulator-pm8005-s1-level-ao { regulator-name = "pm8005_s1_level_ao"; qcom,set = <RPMH_REGULATOR_SET_ACTIVE>; - regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>; + regulator-min-microvolt + = <RPMH_REGULATOR_LEVEL_RETENTION>; regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>; qcom,min-dropout-voltage-level = <(-1)>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi index 9898ada429cc..f4889e0c6c07 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-regulator.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, 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 @@ -133,7 +133,8 @@ pm660l_s3_level: regulator-pm660l-s3-level { regulator-name = "pm660l_s3_level"; qcom,set = <RPMH_REGULATOR_SET_ALL>; - regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>; + regulator-min-microvolt + = <RPMH_REGULATOR_LEVEL_RETENTION>; regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>; qcom,min-dropout-voltage-level = <(-1)>; }; @@ -141,7 +142,8 @@ pm660l_s3_level_ao: regulator-pm660l-s3-level-ao { regulator-name = "pm660l_s3_level_ao"; qcom,set = <RPMH_REGULATOR_SET_ACTIVE>; - regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>; + regulator-min-microvolt + = <RPMH_REGULATOR_LEVEL_RETENTION>; regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>; qcom,min-dropout-voltage-level = <(-1)>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi index 8438f07f82df..4797f0c6fadc 100644 --- a/arch/arm64/boot/dts/qcom/sdm670.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi @@ -2860,6 +2860,7 @@ }; &gpu_cx_gdsc { + parent-supply = <&pm660l_s3_level>; status = "ok"; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi index a5c6d84ccdbe..b5c1ded20fc7 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, 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 @@ -27,7 +27,9 @@ qcom,clk-div = <192>; qcom,clk-mult = <10>; }; +}; +&audio_apr { snd_934x: sound-tavil { compatible = "qcom,sdm845-asoc-snd-tavil"; qcom,model = "sdm845-tavil-snd-card"; @@ -37,15 +39,6 @@ qcom,auxpcm-audio-intf; qcom,msm-mi2s-master = <1>, <1>, <1>, <1>; - reg = <0x1711a000 0x4>, - <0x1711b000 0x4>, - <0x1711c000 0x4>, - <0x1711d000 0x4>; - reg-names = "lpaif_pri_mode_muxsel", - "lpaif_sec_mode_muxsel", - "lpaif_tert_mode_muxsel", - "lpaif_quat_mode_muxsel"; - asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, <&afe>, <&lsm>, <&routing>, <&compr>, diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cdp-audio-overlay.dtsi index 68f2e51fea20..99798ff1c162 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-cdp-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-cdp-audio-overlay.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -13,9 +13,7 @@ #include "sdm845-audio-overlay.dtsi" -&soc { - sound-tavil { - qcom,us-euro-gpios = <&tavil_us_euro_sw>; - }; +&snd_934x { + qcom,us-euro-gpios = <&tavil_us_euro_sw>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi index d6be6d49586e..0a02bfb636f7 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-interposer-pm660.dtsi @@ -265,6 +265,10 @@ /delete-property/ vdd_mx-supply; }; +&gpu_cx_gdsc { + /delete-property/ parent-supply; +}; + &gpu_gx_gdsc { /delete-property/ parent-supply; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd-audio-overlay.dtsi index 361fa2fa9bec..ed7550758a37 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-qrd-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-qrd-audio-overlay.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -13,21 +13,19 @@ #include "sdm845-audio-overlay.dtsi" -&soc { - sound-tavil { - qcom,model = "sdm845-tavil-qrd-snd-card"; +&snd_934x { + qcom,model = "sdm845-tavil-qrd-snd-card"; - qcom,wsa-max-devs = <1>; - qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0213>; - qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrRight"; + qcom,wsa-max-devs = <1>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0213>; + qcom,wsa-aux-dev-prefix = "SpkrRight", "SpkrRight"; - qcom,msm-mbhc-usbc-audio-supported = <1>; + qcom,msm-mbhc-usbc-audio-supported = <1>; - qcom,usbc-analog-en2-gpio = <&tlmm 51 0>; - pinctrl-names = "aud_active", "aud_sleep"; - pinctrl-0 = <&wcd_usbc_analog_en2_active>; - pinctrl-1 = <&wcd_usbc_analog_en2_idle>; - }; + qcom,usbc-analog-en2-gpio = <&tlmm 51 0>; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&wcd_usbc_analog_en2_active>; + pinctrl-1 = <&wcd_usbc_analog_en2_idle>; }; &us_euro_sw_wcd_active { diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi index f215eca36ade..2a6aca0bf6c3 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi @@ -142,7 +142,8 @@ pm8998_s9_level: regulator-s9-level { regulator-name = "pm8998_s9_level"; qcom,set = <RPMH_REGULATOR_SET_ALL>; - regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>; + regulator-min-microvolt + = <RPMH_REGULATOR_LEVEL_RETENTION>; regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>; qcom,min-dropout-voltage-level = <(-1)>; }; @@ -150,7 +151,8 @@ pm8998_s9_level_ao: regulator-s9-level-ao { regulator-name = "pm8998_s9_level_ao"; qcom,set = <RPMH_REGULATOR_SET_ACTIVE>; - regulator-min-microvolt = <RPMH_REGULATOR_LEVEL_OFF>; + regulator-min-microvolt + = <RPMH_REGULATOR_LEVEL_RETENTION>; regulator-max-microvolt = <RPMH_REGULATOR_LEVEL_MAX>; qcom,min-dropout-voltage-level = <(-1)>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi index 05fa2514fc75..a2ab8d70d03a 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi @@ -417,11 +417,11 @@ 652800 31 748800 37 825600 42 - 902400 47 + 864000 47 979200 52 1056000 57 1132800 62 - 1228800 70 + 1248000 70 1324800 78 1420800 89 1516800 103 @@ -442,7 +442,7 @@ 652800 1273 748800 1536 825600 1736 - 902400 1926 + 864000 1926 979200 2108 1056000 2284 1132800 2456 @@ -462,7 +462,7 @@ 2246400 8628 2323200 9344 2400000 10030 - 2476800 10806 + 2496000 10806 2553600 12045 2649600 15686 2745600 25586 @@ -485,11 +485,11 @@ 652800 5 748800 5 825600 6 - 902400 7 + 864000 7 979200 7 1056000 8 1132800 9 - 1228800 9 + 1248000 9 1324800 10 1420800 11 1516800 12 @@ -510,7 +510,7 @@ 652800 26 748800 27 825600 28 - 902400 29 + 864000 29 979200 30 1056000 32 1132800 34 @@ -530,7 +530,7 @@ 2246400 127 2323200 130 2400000 135 - 2476800 140 + 2496000 140 2553600 145 2649600 150 2745600 155 diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 180874fa754b..407c8e1d93ed 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -776,6 +776,7 @@ <0x17a60000 0x100000>; /* GICR * 8 */ interrupts = <1 9 4>; interrupt-parent = <&intc>; + ignored-save-restore-irqs = <38>; }; pdc: interrupt-controller@b220000{ @@ -4050,6 +4051,7 @@ }; &gpu_cx_gdsc { + parent-supply = <&pm8998_s9_level>; status = "ok"; }; diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index ae61bec1f0ab..39c6239a46c1 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2018, 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 @@ -1814,11 +1814,6 @@ error_oob_clear: error_mmu_off: kgsl_mmu_stop(&device->mmu); - if (gpudev->oob_clear && - ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) { - gpudev->oob_clear(adreno_dev, - OOB_BOOT_SLUMBER_CLEAR_MASK); - } error_pwr_off: /* set the state back to original state */ diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index e0f8d5a66030..8b0cf1f638f9 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2018, 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 @@ -1851,8 +1851,11 @@ static inline int adreno_perfcntr_active_oob_get( ret = gpudev->oob_set(adreno_dev, OOB_PERFCNTR_SET_MASK, OOB_PERFCNTR_CHECK_MASK, OOB_PERFCNTR_CLEAR_MASK); - if (ret) + if (ret) { + adreno_set_gpu_fault(adreno_dev, ADRENO_GMU_FAULT); + adreno_dispatcher_schedule(KGSL_DEVICE(adreno_dev)); kgsl_active_count_put(KGSL_DEVICE(adreno_dev)); + } } return ret; diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 18a06a41d371..82b138a72f9b 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -64,6 +64,9 @@ static const struct adreno_vbif_platform a6xx_vbif_platforms[] = { { adreno_is_a615, a615_gbif }, }; + +static unsigned long a6xx_oob_state_bitmask; + struct kgsl_hwcg_reg { unsigned int off; unsigned int val; @@ -1449,7 +1452,7 @@ static int a6xx_oob_set(struct adreno_device *adreno_dev, struct kgsl_device *device = KGSL_DEVICE(adreno_dev); int ret = 0; - if (!kgsl_gmu_isenabled(device)) + if (!kgsl_gmu_isenabled(device) || !clear_mask) return 0; kgsl_gmu_regwrite(device, A6XX_GMU_HOST2GMU_INTR_SET, set_mask); @@ -1465,6 +1468,8 @@ static int a6xx_oob_set(struct adreno_device *adreno_dev, kgsl_gmu_regwrite(device, A6XX_GMU_GMU2HOST_INTR_CLR, clear_mask); + set_bit((fls(clear_mask) - 1), &a6xx_oob_state_bitmask); + trace_kgsl_gmu_oob_set(set_mask); return ret; } @@ -1479,10 +1484,15 @@ static inline void a6xx_oob_clear(struct adreno_device *adreno_dev, { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - if (!kgsl_gmu_isenabled(device)) + if (!kgsl_gmu_isenabled(device) || !clear_mask) return; - kgsl_gmu_regwrite(device, A6XX_GMU_HOST2GMU_INTR_SET, clear_mask); + if (test_and_clear_bit(fls(clear_mask) - 1, + &a6xx_oob_state_bitmask)) + kgsl_gmu_regwrite(device, + A6XX_GMU_HOST2GMU_INTR_SET, + clear_mask); + trace_kgsl_gmu_oob_clear(clear_mask); } @@ -1694,6 +1704,10 @@ static int a6xx_rpmh_power_on_gpu(struct kgsl_device *device) struct device *dev = &gmu->pdev->dev; int val; + /* Only trigger wakeup sequence if sleep sequence was done earlier */ + if (!test_bit(GMU_RSCC_SLEEP_SEQ_DONE, &gmu->flags)) + return 0; + kgsl_gmu_regread(device, A6XX_GPU_CC_GX_DOMAIN_MISC, &val); if (!(val & 0x1)) dev_err_ratelimited(&gmu->pdev->dev, @@ -1723,6 +1737,9 @@ static int a6xx_rpmh_power_on_gpu(struct kgsl_device *device) kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 0); + /* Clear sleep sequence flag as wakeup sequence is successful */ + clear_bit(GMU_RSCC_SLEEP_SEQ_DONE, &gmu->flags); + /* Enable the power counter because it was disabled before slumber */ kgsl_gmu_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 1); @@ -1738,6 +1755,9 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) struct adreno_device *adreno_dev = ADRENO_DEVICE(device); int ret; + if (test_bit(GMU_RSCC_SLEEP_SEQ_DONE, &gmu->flags)) + return 0; + /* RSC sleep sequence is different on v1 */ if (adreno_is_a630v1(adreno_dev)) kgsl_gmu_regwrite(device, A6XX_RSCC_TIMESTAMP_UNIT1_EN_DRV0, 1); @@ -1779,6 +1799,7 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) kgsl_gmu_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 0); + set_bit(GMU_RSCC_SLEEP_SEQ_DONE, &gmu->flags); return 0; } @@ -1797,15 +1818,13 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, unsigned int chipid = 0; switch (boot_state) { - case GMU_RESET: - /* fall through */ case GMU_COLD_BOOT: /* Turn on TCM retention */ kgsl_gmu_regwrite(device, A6XX_GMU_GENERAL_7, 1); if (!test_and_set_bit(GMU_BOOT_INIT_DONE, &gmu->flags)) _load_gmu_rpmh_ucode(device); - else if (boot_state != GMU_RESET) { + else { ret = a6xx_rpmh_power_on_gpu(device); if (ret) return ret; @@ -2306,6 +2325,9 @@ static int a6xx_rpmh_gpu_pwrctrl(struct adreno_device *adreno_dev, ret = a6xx_gmu_suspend(device); break; case GMU_FW_STOP: + if (ADRENO_QUIRK(adreno_dev, ADRENO_QUIRK_HFI_USE_REG)) + a6xx_oob_clear(adreno_dev, + OOB_BOOT_SLUMBER_CLEAR_MASK); ret = a6xx_rpmh_power_off_gpu(device); break; case GMU_DCVS_NOHFI: diff --git a/drivers/gpu/msm/adreno_a6xx_preempt.c b/drivers/gpu/msm/adreno_a6xx_preempt.c index b9dd5f4564b5..28d4005fbc52 100644 --- a/drivers/gpu/msm/adreno_a6xx_preempt.c +++ b/drivers/gpu/msm/adreno_a6xx_preempt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -49,8 +49,13 @@ static void _update_wptr(struct adreno_device *adreno_dev, bool reset_timer) OOB_PREEMPTION_SET_MASK, OOB_PREEMPTION_CHECK_MASK, OOB_PREEMPTION_CLEAR_MASK); - if (status) + if (status) { + adreno_set_gpu_fault(adreno_dev, + ADRENO_GMU_FAULT); + adreno_dispatcher_schedule( + KGSL_DEVICE(adreno_dev)); return; + } } } @@ -227,6 +232,38 @@ static struct adreno_ringbuffer *a6xx_next_ringbuffer( return NULL; } +#define GMU_ACTIVE_STATE_RETRY_MAX 100 + +static int adreno_gmu_wait_for_active(struct adreno_device *adreno_dev) +{ + unsigned int reg, num_retries = 0; + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + + if (!kgsl_gmu_isenabled(device)) + return 0; + + kgsl_gmu_regread(device, + A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE, ®); + + while (reg != GPU_HW_ACTIVE) { + /* Wait for small time before trying again */ + udelay(5); + kgsl_gmu_regread(device, + A6XX_GPU_GMU_CX_GMU_RPMH_POWER_STATE, ®); + + if (num_retries == GMU_ACTIVE_STATE_RETRY_MAX && + reg != GPU_HW_ACTIVE) { + dev_err(adreno_dev->dev.dev, + "GMU failed to move to ACTIVE state: 0x%x\n", + reg); + return -ETIMEDOUT; + } + num_retries++; + } + + return 0; +} + void a6xx_preemption_trigger(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); @@ -356,6 +393,23 @@ void a6xx_preemption_trigger(struct adreno_device *adreno_dev) upper_32_bits(gpuaddr), FENCE_STATUS_WRITEDROPPED1_MASK); + /* + * Above fence writes will make sure GMU comes out of + * IFPC state if its was in IFPC state but it doesn't + * guarantee that GMU FW actually moved to ACTIVE state + * i.e. wake-up from IFPC is complete. + * Wait for GMU to move to ACTIVE state before triggering + * preemption. This is require to make sure CP doesn't + * interrupt GMU during wake-up from IFPC. + */ + if (adreno_gmu_wait_for_active(adreno_dev)) { + adreno_set_preempt_state(adreno_dev, ADRENO_PREEMPT_NONE); + + adreno_set_gpu_fault(adreno_dev, ADRENO_GMU_FAULT); + adreno_dispatcher_schedule(device); + return; + } + adreno_dev->next_rb = next; /* Start the timer to detect a stuck preemption */ @@ -370,14 +424,6 @@ void a6xx_preemption_trigger(struct adreno_device *adreno_dev) /* Trigger the preemption */ adreno_gmu_fenced_write(adreno_dev, ADRENO_REG_CP_PREEMPT, cntl, FENCE_STATUS_WRITEDROPPED1_MASK); - - /* - * Once preemption has been requested with the final register write, - * the preemption process starts and the GPU is considered busy. - * We can now safely clear the preemption keepalive bit, allowing - * power collapse to resume its regular activity. - */ - kgsl_gmu_regrmw(device, A6XX_GMU_AO_SPARE_CNTL, 0x2, 0x0); } void a6xx_preemption_callback(struct adreno_device *adreno_dev, int bit) @@ -405,6 +451,13 @@ void a6xx_preemption_callback(struct adreno_device *adreno_dev, int bit) return; } + /* + * We can now safely clear the preemption keepalive bit, allowing + * power collapse to resume its regular activity. + */ + kgsl_gmu_regrmw(KGSL_DEVICE(adreno_dev), A6XX_GMU_AO_SPARE_CNTL, 0x2, + 0x0); + del_timer(&adreno_dev->preempt.timer); adreno_readreg(adreno_dev, ADRENO_REG_CP_PREEMPT_LEVEL_STATUS, &status); diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index 77edd1e96aba..a7b2e42a5ac5 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -1307,15 +1307,18 @@ static int gmu_disable_gdsc(struct gmu_device *gmu) do { if (!regulator_is_enabled(gmu->cx_gdsc)) return 0; - cond_resched(); + usleep_range(10, 100); } while (!(time_after(jiffies, t))); + if (!regulator_is_enabled(gmu->cx_gdsc)) + return 0; + dev_err(&gmu->pdev->dev, "GMU CX gdsc off timeout"); return -ETIMEDOUT; } -static int gmu_suspend(struct kgsl_device *device) +int gmu_suspend(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); @@ -1401,6 +1404,7 @@ int gmu_start(struct kgsl_device *device) struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct gmu_device *gmu = &device->gmu; + unsigned int boot_state = GMU_WARM_BOOT; switch (device->state) { case KGSL_STATE_INIT: @@ -1437,12 +1441,21 @@ int gmu_start(struct kgsl_device *device) gmu_enable_clks(gmu); gmu_irq_enable(device); + /* + * If unrecovered is set that means last + * wakeup from SLUMBER state failed. Use GMU + * and HFI boot state as COLD as this is a + * boot after RESET. + */ + if (gmu->unrecovered) + boot_state = GMU_COLD_BOOT; + ret = gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_START, - GMU_WARM_BOOT, 0); + boot_state, 0); if (ret) goto error_gmu; - ret = hfi_start(gmu, GMU_WARM_BOOT); + ret = hfi_start(gmu, boot_state); if (ret) goto error_gmu; @@ -1458,7 +1471,7 @@ int gmu_start(struct kgsl_device *device) gmu_irq_enable(device); ret = gpudev->rpmh_gpu_pwrctrl( - adreno_dev, GMU_FW_START, GMU_RESET, 0); + adreno_dev, GMU_FW_START, GMU_COLD_BOOT, 0); if (ret) goto error_gmu; @@ -1475,7 +1488,7 @@ int gmu_start(struct kgsl_device *device) hfi_stop(gmu); ret = gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_START, - GMU_RESET, 0); + GMU_COLD_BOOT, 0); if (ret) goto error_gmu; @@ -1488,6 +1501,8 @@ int gmu_start(struct kgsl_device *device) break; } + /* Clear unrecovered as GMU start is successful */ + gmu->unrecovered = false; return ret; error_gmu: diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h index 19fa9728ca67..130d4004bf77 100644 --- a/drivers/gpu/msm/kgsl_gmu.h +++ b/drivers/gpu/msm/kgsl_gmu.h @@ -102,6 +102,7 @@ enum gmu_flags { GMU_HFI_ON = 2, GMU_FAULT = 3, GMU_DCVS_REPLAY = 4, + GMU_RSCC_SLEEP_SEQ_DONE = 5, }; /** @@ -139,13 +140,11 @@ struct rpmh_votes_t { /* * These are the different ways the GMU can boot. GMU_WARM_BOOT is waking up - * from slumber. GMU_COLD_BOOT is booting for the first time. GMU_RESET - * is a soft reset of the GMU. + * from slumber. GMU_COLD_BOOT is booting for the first time. */ enum gmu_boot { GMU_WARM_BOOT = 0, GMU_COLD_BOOT = 1, - GMU_RESET = 2 }; enum gmu_load_mode { @@ -213,6 +212,7 @@ enum gpu_idle_level { * @ccl: CNOC BW scaling client * @idle_level: Minimal GPU idle power level * @fault_count: GMU fault count + * @unrecovered: Indicates whether GMU recovery failed or not */ struct gmu_device { unsigned int ver; @@ -247,6 +247,7 @@ struct gmu_device { unsigned int ccl; unsigned int idle_level; unsigned int fault_count; + bool unrecovered; }; void gmu_snapshot(struct kgsl_device *device); @@ -256,6 +257,7 @@ void gmu_remove(struct kgsl_device *device); int allocate_gmu_image(struct gmu_device *gmu, unsigned int size); int gmu_start(struct kgsl_device *device); void gmu_stop(struct kgsl_device *device); +int gmu_suspend(struct kgsl_device *device); int gmu_dcvs_set(struct gmu_device *gmu, unsigned int gpu_pwrlevel, unsigned int bus_level); #endif /* __KGSL_GMU_H */ diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 9a735368aa8b..9ebed976beb3 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -2737,6 +2737,25 @@ _aware(struct kgsl_device *device) WARN_ONCE(1, "Failed to recover GMU\n"); if (device->snapshot) device->snapshot->recovered = false; + /* + * On recovery failure, we are clearing + * GMU_FAULT bit and also not keeping + * the state as RESET to make sure any + * attempt to wake GMU/GPU after this + * is treated as a fresh start. But on + * recovery failure, GMU HS, clocks and + * IRQs are still ON/enabled because of + * which next GMU/GPU wakeup results in + * multiple warnings from GMU start as HS, + * clocks and IRQ were ON while doing a + * fresh start i.e. wake from SLUMBER. + * + * Suspend the GMU on recovery failure + * to make sure next attempt to wake up + * GMU/GPU is indeed a fresh start. + */ + gmu_suspend(device); + gmu->unrecovered = true; kgsl_pwrctrl_set_state(device, state); } else { if (device->snapshot) |