diff options
Diffstat (limited to 'drivers/gpu/nvgpu')
-rw-r--r-- | drivers/gpu/nvgpu/gp106/pmu_gp106.c | 165 |
1 files changed, 159 insertions, 6 deletions
diff --git a/drivers/gpu/nvgpu/gp106/pmu_gp106.c b/drivers/gpu/nvgpu/gp106/pmu_gp106.c index 42ed85ec..be3e8c64 100644 --- a/drivers/gpu/nvgpu/gp106/pmu_gp106.c +++ b/drivers/gpu/nvgpu/gp106/pmu_gp106.c | |||
@@ -15,32 +15,185 @@ | |||
15 | #include "gk20a/gk20a.h" | 15 | #include "gk20a/gk20a.h" |
16 | #include "gk20a/pmu_gk20a.h" | 16 | #include "gk20a/pmu_gk20a.h" |
17 | 17 | ||
18 | #include "gm206/pmu_gm206.h" | ||
19 | #include "gm20b/pmu_gm20b.h" | ||
18 | #include "gp10b/pmu_gp10b.h" | 20 | #include "gp10b/pmu_gp10b.h" |
21 | #include "gp106/pmu_gp106.h" | ||
22 | #include "gp106/acr_gp106.h" | ||
23 | #include "gp106/hw_psec_gp106.h" | ||
19 | #include "hw_mc_gp106.h" | 24 | #include "hw_mc_gp106.h" |
20 | #include "hw_pwr_gp106.h" | 25 | #include "hw_pwr_gp106.h" |
21 | 26 | ||
22 | static int gp106_pmu_reset(struct gk20a *g) | 27 | #define PMU_MEM_SCRUBBING_TIMEOUT_MAX 1000 |
28 | #define PMU_MEM_SCRUBBING_TIMEOUT_DEFAULT 10 | ||
29 | |||
30 | int gp106_pmu_enable_hw(struct pmu_gk20a *pmu, bool enable) | ||
23 | { | 31 | { |
32 | struct gk20a *g = gk20a_from_pmu(pmu); | ||
33 | |||
24 | gk20a_dbg_fn(""); | 34 | gk20a_dbg_fn(""); |
25 | 35 | ||
26 | gk20a_reset(g, mc_enable_pwr_enabled_f()); | 36 | /* |
37 | * From GP10X onwards, we are using PPWR_FALCON_ENGINE for reset. And as | ||
38 | * it may come into same behaviour, reading NV_PPWR_FALCON_ENGINE again | ||
39 | * after Reset. | ||
40 | */ | ||
41 | |||
42 | if (enable) { | ||
43 | int retries = PMU_MEM_SCRUBBING_TIMEOUT_MAX / | ||
44 | PMU_MEM_SCRUBBING_TIMEOUT_DEFAULT; | ||
45 | gk20a_writel(g, pwr_falcon_engine_r(), | ||
46 | pwr_falcon_engine_reset_false_f()); | ||
47 | gk20a_readl(g, pwr_falcon_engine_r()); | ||
48 | |||
49 | /* make sure ELPG is in a good state */ | ||
50 | if (g->ops.clock_gating.slcg_pmu_load_gating_prod) | ||
51 | g->ops.clock_gating.slcg_pmu_load_gating_prod(g, | ||
52 | g->slcg_enabled); | ||
53 | if (g->ops.clock_gating.blcg_pmu_load_gating_prod) | ||
54 | g->ops.clock_gating.blcg_pmu_load_gating_prod(g, | ||
55 | g->blcg_enabled); | ||
56 | |||
57 | /* wait for Scrubbing to complete */ | ||
58 | do { | ||
59 | u32 w = gk20a_readl(g, pwr_falcon_dmactl_r()) & | ||
60 | (pwr_falcon_dmactl_dmem_scrubbing_m() | | ||
61 | pwr_falcon_dmactl_imem_scrubbing_m()); | ||
27 | 62 | ||
28 | gk20a_writel(g, pwr_falcon_engine_r(), | 63 | if (!w) { |
64 | gk20a_dbg_fn("done"); | ||
65 | return 0; | ||
66 | } | ||
67 | udelay(PMU_MEM_SCRUBBING_TIMEOUT_DEFAULT); | ||
68 | } while (--retries || !tegra_platform_is_silicon()); | ||
69 | |||
70 | /* If scrubbing timeout, keep PMU in reset state */ | ||
71 | gk20a_writel(g, pwr_falcon_engine_r(), | ||
72 | pwr_falcon_engine_reset_true_f()); | ||
73 | gk20a_readl(g, pwr_falcon_engine_r()); | ||
74 | gk20a_err(dev_from_gk20a(g), "Falcon mem scrubbing timeout"); | ||
75 | return -ETIMEDOUT; | ||
76 | } else { | ||
77 | /* DISBALE */ | ||
78 | gk20a_writel(g, pwr_falcon_engine_r(), | ||
79 | pwr_falcon_engine_reset_true_f()); | ||
80 | gk20a_readl(g, pwr_falcon_engine_r()); | ||
81 | return 0; | ||
82 | } | ||
83 | } | ||
84 | |||
85 | static int pmu_enable(struct pmu_gk20a *pmu, bool enable) | ||
86 | { | ||
87 | struct gk20a *g = gk20a_from_pmu(pmu); | ||
88 | u32 reg_reset; | ||
89 | int err; | ||
90 | |||
91 | gk20a_dbg_fn(""); | ||
92 | |||
93 | if (!enable) { | ||
94 | reg_reset = gk20a_readl(g, pwr_falcon_engine_r()); | ||
95 | if (reg_reset != | ||
96 | pwr_falcon_engine_reset_true_f()) { | ||
97 | |||
98 | pmu_enable_irq(pmu, false); | ||
99 | gp106_pmu_enable_hw(pmu, false); | ||
100 | udelay(10); | ||
101 | } | ||
102 | } else { | ||
103 | gp106_pmu_enable_hw(pmu, true); | ||
104 | /* TBD: post reset */ | ||
105 | |||
106 | /*idle the PMU and enable interrupts on the Falcon*/ | ||
107 | err = pmu_idle(pmu); | ||
108 | if (err) | ||
109 | return err; | ||
110 | udelay(5); | ||
111 | pmu_enable_irq(pmu, true); | ||
112 | } | ||
113 | |||
114 | gk20a_dbg_fn("done"); | ||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | int gp106_pmu_reset(struct gk20a *g) | ||
119 | { | ||
120 | struct pmu_gk20a *pmu = &g->pmu; | ||
121 | int err = 0; | ||
122 | |||
123 | gk20a_dbg_fn(""); | ||
124 | |||
125 | err = pmu_idle(pmu); | ||
126 | if (err) | ||
127 | return err; | ||
128 | |||
129 | /* TBD: release pmu hw mutex */ | ||
130 | |||
131 | err = pmu_enable(pmu, false); | ||
132 | if (err) | ||
133 | return err; | ||
134 | |||
135 | /* TBD: cancel all sequences */ | ||
136 | /* TBD: init all sequences and state tables */ | ||
137 | /* TBD: restore pre-init message handler */ | ||
138 | |||
139 | err = pmu_enable(pmu, true); | ||
140 | if (err) | ||
141 | return err; | ||
142 | |||
143 | return err; | ||
144 | } | ||
145 | |||
146 | int gp106_sec2_reset(struct gk20a *g) | ||
147 | { | ||
148 | gk20a_dbg_fn(""); | ||
149 | //sec2 reset | ||
150 | gk20a_writel(g, psec_falcon_engine_r(), | ||
29 | pwr_falcon_engine_reset_true_f()); | 151 | pwr_falcon_engine_reset_true_f()); |
30 | udelay(10); | 152 | udelay(10); |
31 | gk20a_writel(g, pwr_falcon_engine_r(), | 153 | gk20a_writel(g, psec_falcon_engine_r(), |
32 | pwr_falcon_engine_reset_false_f()); | 154 | pwr_falcon_engine_reset_false_f()); |
33 | 155 | ||
34 | gk20a_dbg_fn("done"); | 156 | gk20a_dbg_fn("done"); |
35 | return 0; | 157 | return 0; |
36 | } | 158 | } |
37 | 159 | ||
160 | static int gp106_falcon_reset(struct gk20a *g) | ||
161 | { | ||
162 | gk20a_dbg_fn(""); | ||
163 | |||
164 | gp106_pmu_reset(g); | ||
165 | gp106_sec2_reset(g); | ||
166 | |||
167 | gk20a_dbg_fn("done"); | ||
168 | return 0; | ||
169 | } | ||
170 | |||
38 | void gp106_init_pmu_ops(struct gpu_ops *gops) | 171 | void gp106_init_pmu_ops(struct gpu_ops *gops) |
39 | { | 172 | { |
40 | gk20a_dbg_fn(""); | 173 | gk20a_dbg_fn(""); |
41 | 174 | ||
42 | gp10b_init_pmu_ops(gops); | 175 | if (gops->privsecurity) { |
43 | gops->pmu.reset = gp106_pmu_reset; | 176 | gp106_init_secure_pmu(gops); |
177 | gops->pmu.init_wpr_region = gm20b_pmu_init_acr; | ||
178 | gops->pmu.load_lsfalcon_ucode = gm206_load_falcon_ucode; | ||
179 | gops->pmu.is_lazy_bootstrap = gm206_is_lazy_bootstrap; | ||
180 | gops->pmu.is_priv_load = gm206_is_priv_load; | ||
181 | } else { | ||
182 | gk20a_init_pmu_ops(gops); | ||
183 | gops->pmu.pmu_setup_hw_and_bootstrap = | ||
184 | gm20b_init_nspmu_setup_hw1; | ||
185 | gops->pmu.load_lsfalcon_ucode = NULL; | ||
186 | gops->pmu.init_wpr_region = NULL; | ||
187 | } | ||
188 | gops->pmu.pmu_setup_elpg = NULL; | ||
189 | gops->pmu.lspmuwprinitdone = 0; | ||
190 | gops->pmu.fecsbootstrapdone = false; | ||
191 | gops->pmu.write_dmatrfbase = gp10b_write_dmatrfbase; | ||
192 | gops->pmu.pmu_elpg_statistics = NULL; | ||
193 | gops->pmu.pmu_pg_grinit_param = NULL; | ||
194 | gops->pmu.send_lrf_tex_ltc_dram_overide_en_dis_cmd = NULL; | ||
195 | gops->pmu.dump_secure_fuses = NULL; | ||
196 | gops->pmu.reset = gp106_falcon_reset; | ||
44 | 197 | ||
45 | gk20a_dbg_fn("done"); | 198 | gk20a_dbg_fn("done"); |
46 | } | 199 | } |