platform: tegra: powergate: disable powergate for SE2 on T214
[linux-4.9.git] / drivers / platform / tegra / powergate / powergate-t21x.c
1 /*
2  * Copyright (c) 2014-2017, NVIDIA CORPORATION.  All rights reserved.
3  *
4  * This software is licensed under the terms of the GNU General Public
5  * License version 2, as published by the Free Software Foundation, and
6  * may be copied, distributed, and modified under those terms.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  */
14
15 #include <dt-bindings/clock/tegra210-car.h>
16 #include <linux/err.h>
17 #include <linux/spinlock.h>
18 #include <linux/delay.h>
19 #include <linux/io.h>
20 #include <linux/regulator/consumer.h>
21 #include <soc/tegra/tegra_powergate.h>
22 #include <soc/tegra/tegra-powergate-driver.h>
23 #include <soc/tegra/chip-id.h>
24 #include <linux/tegra_soctherm.h>
25 #include <soc/tegra/tegra-dvfs.h>
26 #include <trace/events/power.h>
27 #include <linux/clk.h>
28 #include <linux/clk-provider.h>
29 #include <linux/clk/tegra.h>
30 #include <soc/tegra/reset.h>
31 #include <soc/tegra/common.h>
32
33 #define MAX_CLK_EN_NUM                  15
34 #define MAX_HOTRESET_CLIENT_NUM         4
35
36 enum clk_type {
37         CLK_AND_RST,
38         RST_ONLY,
39         CLK_ONLY,
40 };
41
42 struct partition_clk_info {
43         const char *clk_name;
44         enum clk_type clk_type;
45         struct clk *clk_ptr;
46 };
47
48 struct powergate_partition_info {
49         const char *name;
50         struct partition_clk_info clk_info[MAX_CLK_EN_NUM];
51         struct partition_clk_info slcg_info[MAX_CLK_EN_NUM];
52         unsigned long reset_id[MAX_CLK_EN_NUM];
53         int reset_id_num;
54         struct raw_notifier_head slcg_notifier;
55         int refcount;
56         bool disable_after_boot;
57         struct mutex pg_mutex;
58         bool skip_reset;
59 };
60
61 #define EMULATION_MC_FLUSH_TIMEOUT 100
62 #define TEGRA210_POWER_DOMAIN_NVENC TEGRA210_POWER_DOMAIN_MPE
63
64 enum mc_client {
65         MC_CLIENT_AFI           = 0,
66         MC_CLIENT_AVPC          = 1,
67         MC_CLIENT_DC            = 2,
68         MC_CLIENT_DCB           = 3,
69         MC_CLIENT_HC            = 6,
70         MC_CLIENT_HDA           = 7,
71         MC_CLIENT_ISP2          = 8,
72         MC_CLIENT_NVENC         = 11,
73         MC_CLIENT_SATA          = 15,
74         MC_CLIENT_VI            = 17,
75         MC_CLIENT_VIC           = 18,
76         MC_CLIENT_XUSB_HOST     = 19,
77         MC_CLIENT_XUSB_DEV      = 20,
78         MC_CLIENT_BPMP          = 21,
79         MC_CLIENT_TSEC          = 22,
80         MC_CLIENT_SDMMC1        = 29,
81         MC_CLIENT_SDMMC2        = 30,
82         MC_CLIENT_SDMMC3        = 31,
83         MC_CLIENT_SDMMC4        = 32,
84         MC_CLIENT_ISP2B         = 33,
85         MC_CLIENT_GPU           = 34,
86         MC_CLIENT_NVDEC         = 37,
87         MC_CLIENT_APE           = 38,
88         MC_CLIENT_SE            = 39,
89         MC_CLIENT_NVJPG         = 40,
90         MC_CLIENT_TSECB         = 45,
91         MC_CLIENT_LAST          = -1,
92 };
93
94 struct tegra210_mc_client_info {
95         enum mc_client  hot_reset_clients[MAX_HOTRESET_CLIENT_NUM];
96 };
97
98 static struct tegra210_mc_client_info tegra210_pg_mc_info[] = {
99         [TEGRA210_POWER_DOMAIN_CRAIL] = {
100                 .hot_reset_clients = {
101                         [0] = MC_CLIENT_LAST,
102                 },
103         },
104         [TEGRA210_POWER_DOMAIN_VENC] = {
105                 .hot_reset_clients = {
106                         [0] = MC_CLIENT_ISP2,
107                         [1] = MC_CLIENT_VI,
108                         [2] = MC_CLIENT_LAST,
109                 },
110         },
111 #ifdef CONFIG_ARCH_TEGRA_HAS_PCIE
112         [TEGRA210_POWER_DOMAIN_PCIE] = {
113                 .hot_reset_clients = {
114                         [0] = MC_CLIENT_AFI,
115                         [1] = MC_CLIENT_LAST,
116                 },
117         },
118 #endif
119 #ifdef CONFIG_ARCH_TEGRA_HAS_SATA
120         [TEGRA210_POWER_DOMAIN_SATA] = {
121                 .hot_reset_clients = {
122                         [0] = MC_CLIENT_SATA,
123                         [1] = MC_CLIENT_LAST,
124                 },
125         },
126 #endif
127         [TEGRA210_POWER_DOMAIN_NVENC] = {
128                 .hot_reset_clients = {
129                         [0] = MC_CLIENT_NVENC,
130                         [1] = MC_CLIENT_LAST,
131                 },
132         },
133         [TEGRA210_POWER_DOMAIN_SOR] = {
134                 .hot_reset_clients = {
135                         [0] = MC_CLIENT_LAST,
136                 },
137         },
138         [TEGRA210_POWER_DOMAIN_DISA] = {
139                 .hot_reset_clients = {
140                         [0] = MC_CLIENT_DC,
141                         [1] = MC_CLIENT_LAST,
142                 },
143         },
144         [TEGRA210_POWER_DOMAIN_DISB] = {
145                 .hot_reset_clients = {
146                         [0] = MC_CLIENT_DCB,
147                         [1] = MC_CLIENT_LAST,
148                 },
149         },
150         [TEGRA210_POWER_DOMAIN_XUSBA] = {
151                 .hot_reset_clients = {
152                         [0] = MC_CLIENT_LAST,
153                 },
154         },
155         [TEGRA210_POWER_DOMAIN_XUSBB] = {
156                 .hot_reset_clients = {
157                         [0] = MC_CLIENT_XUSB_DEV,
158                         [1] = MC_CLIENT_LAST,
159                 },
160         },
161         [TEGRA210_POWER_DOMAIN_XUSBC] = {
162                 .hot_reset_clients = {
163                         [0] = MC_CLIENT_XUSB_HOST,
164                         [1] = MC_CLIENT_LAST,
165                 },
166         },
167 #ifdef CONFIG_ARCH_TEGRA_VIC
168         [TEGRA210_POWER_DOMAIN_VIC] = {
169                 .hot_reset_clients = {
170                         [0] = MC_CLIENT_VIC,
171                         [1] = MC_CLIENT_LAST,
172                 },
173         },
174 #endif
175         [TEGRA210_POWER_DOMAIN_NVDEC] = {
176                 .hot_reset_clients = {
177                         [0] = MC_CLIENT_NVDEC,
178                         [1] = MC_CLIENT_LAST,
179                 },
180         },
181         [TEGRA210_POWER_DOMAIN_NVJPG] = {
182                 .hot_reset_clients = {
183                         [0] = MC_CLIENT_NVJPG,
184                         [1] = MC_CLIENT_LAST,
185                 },
186         },
187         [TEGRA210_POWER_DOMAIN_APE] = {
188                 .hot_reset_clients = {
189                         [0] = MC_CLIENT_APE,
190                         [1] = MC_CLIENT_LAST,
191                 },
192         },
193         [TEGRA210_POWER_DOMAIN_VE2] = {
194                 .hot_reset_clients = {
195                         [0] = MC_CLIENT_ISP2B,
196                         [1] = MC_CLIENT_LAST,
197                 },
198         },
199         [TEGRA210_POWER_DOMAIN_GPU] = {
200                 .hot_reset_clients = {
201                         [0] = MC_CLIENT_GPU,
202                         [1] = MC_CLIENT_LAST,
203                 },
204         },
205 };
206
207 static struct powergate_partition_info tegra210_pg_partition_info[] = {
208         [TEGRA210_POWER_DOMAIN_VENC] = {
209                 .name = "ve",
210                 .clk_info = {
211                         [0] = { .clk_name = "ispa", .clk_type = CLK_ONLY },
212                         [1] = { .clk_name = "vi", .clk_type = CLK_ONLY },
213                         [2] = { .clk_name = "csi", .clk_type = CLK_ONLY },
214                         [3] = { .clk_name = "vii2c", .clk_type = CLK_ONLY },
215                         [4] = { .clk_name = "cilab", .clk_type = CLK_ONLY },
216                         [5] = { .clk_name = "cilcd", .clk_type = CLK_ONLY },
217                         [6] = { .clk_name = "cile", .clk_type = CLK_ONLY },
218                 },
219                 .slcg_info = {
220                         [0] = { .clk_name = "mc_capa" },
221                         [1] = { .clk_name = "mc_cbpa" },
222                         [2] = { .clk_name = "mc_ccpa" },
223                         [3] = { .clk_name = "mc_cdpa" },
224                         [4] = { .clk_name = "host1x" },
225                         [5] = { .clk_name = "vi_slcg_ovr" },
226                         [6] = { .clk_name = "ispa_slcg_ovr" },
227                 },
228                 .reset_id = { TEGRA210_CLK_ISPA, TEGRA210_CLK_VI,
229                               TEGRA210_CLK_CSI, TEGRA210_CLK_VI_I2C },
230                 .reset_id_num = 4,
231         },
232 #ifdef CONFIG_ARCH_TEGRA_HAS_PCIE
233         [TEGRA210_POWER_DOMAIN_PCIE] = {
234                 .name = "pcie",
235                 .clk_info = {
236                         [0] = { .clk_name = "afi", .clk_type = CLK_ONLY },
237                         [1] = { .clk_name = "pcie", .clk_type = CLK_ONLY },
238                 },
239                 .reset_id = { TEGRA210_CLK_AFI, TEGRA210_CLK_PCIE,
240                               TEGRA210_CLK_PCIEX },
241                 .reset_id_num = 3,
242                 .skip_reset = true,
243         },
244 #endif
245 #ifdef CONFIG_ARCH_TEGRA_HAS_SATA
246         [TEGRA210_POWER_DOMAIN_SATA] = {
247                 .name = "sata",
248                 .disable_after_boot = false,
249                 .clk_info = {
250                         [0] = { .clk_name = "sata_oob", .clk_type = CLK_ONLY },
251                         [1] = { .clk_name = "cml1", .clk_type = CLK_ONLY },
252                         [3] = { .clk_name = "sata_aux", .clk_type = CLK_ONLY },
253                         [4] = { .clk_name = "sata", .clk_type = CLK_ONLY },
254                 },
255                 .slcg_info = {
256                         [0] = { .clk_name = "mc_capa" },
257                         [1] = { .clk_name = "mc_cbpa" },
258                         [2] = { .clk_name = "mc_ccpa" },
259                         [3] = { .clk_name = "mc_cdpa" },
260                         [4] = { .clk_name = "sata_slcg_fpci" },
261                         [5] = { .clk_name = "sata_slcg_ipfs" },
262                         [6] = { .clk_name = "sata_slcg_ovr" },
263                 },
264                 .reset_id = { TEGRA210_CLK_SATA_OOB, TEGRA210_CLK_SATA_COLD,
265                               TEGRA210_CLK_SATA },
266                 .reset_id_num = 3,
267         },
268 #endif
269         [TEGRA210_POWER_DOMAIN_NVENC] = {
270                 .name = "nvenc",
271                 .clk_info = {
272                         [0] = { .clk_name = "nvenc.cbus", .clk_type = CLK_ONLY },
273                 },
274                 .slcg_info = {
275                         [0] = { .clk_name = "mc_capa" },
276                         [1] = { .clk_name = "mc_cbpa" },
277                         [2] = { .clk_name = "mc_ccpa" },
278                         [3] = { .clk_name = "mc_cdpa" },
279                         [4] = { .clk_name = "nvenc_slcg_ovr" },
280                 },
281                 .reset_id = { TEGRA210_CLK_NVENC },
282                 .reset_id_num = 1,
283         },
284         [TEGRA210_POWER_DOMAIN_SOR] = {
285                 .name = "sor",
286                 .clk_info = {
287                         [0] = { .clk_name = "sor0", .clk_type = CLK_ONLY },
288                         [1] = { .clk_name = "dsia", .clk_type = CLK_ONLY },
289                         [2] = { .clk_name = "dsib", .clk_type = CLK_ONLY },
290                         [3] = { .clk_name = "sor1", .clk_type = CLK_ONLY },
291                         [4] = { .clk_name = "mipi-cal", .clk_type = CLK_ONLY },
292                         [5] = { .clk_name = "dpaux", .clk_type = CLK_ONLY },
293                         [6] = { .clk_name = "dpaux1", .clk_type = CLK_ONLY },
294                 },
295                 .slcg_info = {
296                         [0] = { .clk_name = "mc_capa" },
297                         [1] = { .clk_name = "mc_cbpa" },
298                         [2] = { .clk_name = "mc_ccpa" },
299                         [3] = { .clk_name = "mc_cdpa" },
300                         [4] = { .clk_name = "hda2hdmi" },
301                         [5] = { .clk_name = "hda2codec_2x" },
302                         [6] = { .clk_name = "disp1" },
303                         [7] = { .clk_name = "disp2" },
304                         [8] = { .clk_name = "disp1_slcg_ovr" },
305                         [9] = { .clk_name = "disp2_slcg_ovr" },
306                 },
307                 .reset_id = { TEGRA210_CLK_SOR0, TEGRA210_CLK_DISP1,
308                               TEGRA210_CLK_DSIB, TEGRA210_CLK_SOR1,
309                               TEGRA210_CLK_MIPI_CAL },
310                 .reset_id_num = 5,
311         },
312         [TEGRA210_POWER_DOMAIN_DISA] = {
313                 .name = "disa",
314                 .clk_info = {
315                         [0] = { .clk_name = "disp1", .clk_type = CLK_ONLY },
316                 },
317                 .slcg_info = {
318                         [0] = { .clk_name = "mc_capa" },
319                         [1] = { .clk_name = "mc_cbpa" },
320                         [2] = { .clk_name = "mc_ccpa" },
321                         [3] = { .clk_name = "mc_cdpa" },
322                         [4] = { .clk_name = "la" },
323                         [5] = { .clk_name = "host1x" },
324                         [6] = { .clk_name = "disp1_slcg_ovr" },
325                 },
326                 .reset_id = { TEGRA210_CLK_DISP1 },
327                 .reset_id_num = 1,
328         },
329         [TEGRA210_POWER_DOMAIN_DISB] = {
330                 .name = "disb",
331                 .disable_after_boot = true,
332                 .clk_info = {
333                         [0] = { .clk_name = "disp2", .clk_type = CLK_ONLY },
334                 },
335                 .slcg_info = {
336                         [0] = { .clk_name = "mc_capa" },
337                         [1] = { .clk_name = "mc_cbpa" },
338                         [2] = { .clk_name = "mc_ccpa" },
339                         [3] = { .clk_name = "mc_cdpa" },
340                         [4] = { .clk_name = "la" },
341                         [5] = { .clk_name = "host1x" },
342                         [6] = { .clk_name = "disp2_slcg_ovr" },
343                 },
344                 .reset_id = { TEGRA210_CLK_DISP2 },
345                 .reset_id_num = 1,
346         },
347         [TEGRA210_POWER_DOMAIN_XUSBA] = {
348                 .name = "xusba",
349                 .clk_info = {
350                         [0] = { .clk_name = "xusb_ss", .clk_type = CLK_ONLY },
351                         [1] = { .clk_name = "xusb_ssp_src", .clk_type = CLK_ONLY },
352                         [2] = { .clk_name = "xusb_hs_src", .clk_type = CLK_ONLY },
353                         [3] = { .clk_name = "xusb_fs_src", .clk_type = CLK_ONLY },
354                         [4] = { .clk_name = "xusb_dev_src", .clk_type = CLK_ONLY },
355                 },
356                 .slcg_info = {
357                         [0] = { .clk_name = "mc_capa" },
358                         [1] = { .clk_name = "mc_cbpa" },
359                         [2] = { .clk_name = "mc_ccpa" },
360                         [3] = { .clk_name = "mc_cdpa" },
361                         [4] = { .clk_name = "xusb_host" },
362                         [5] = { .clk_name = "xusb_dev" },
363                         [6] = { .clk_name = "xusb_host_slcg" },
364                         [7] = { .clk_name = "xusb_dev_slcg" },
365                 },
366                 .reset_id = { TEGRA210_CLK_XUSB_SS },
367                 .reset_id_num = 1,
368         },
369         [TEGRA210_POWER_DOMAIN_XUSBB] = {
370                 .name = "xusbb",
371                 .clk_info = {
372                         [0] = { .clk_name = "xusb_dev", .clk_type = CLK_ONLY },
373                 },
374                 .slcg_info = {
375                         [0] = { .clk_name = "mc_capa" },
376                         [1] = { .clk_name = "mc_cbpa" },
377                         [2] = { .clk_name = "mc_ccpa" },
378                         [3] = { .clk_name = "mc_cdpa" },
379                         [4] = { .clk_name = "xusb_ss" },
380                         [5] = { .clk_name = "xusb_host" },
381                         [6] = { .clk_name = "xusb_host_slcg" },
382                         [7] = { .clk_name = "xusb_dev_slcg" },
383                 },
384                 .reset_id = { 95 },
385                 .reset_id_num = 1,
386         },
387         [TEGRA210_POWER_DOMAIN_XUSBC] = {
388                 .name = "xusbc",
389                 .clk_info = {
390                         [0] = { .clk_name = "xusb_host", .clk_type = CLK_ONLY },
391                 },
392                 .slcg_info = {
393                         [0] = { .clk_name = "mc_capa" },
394                         [1] = { .clk_name = "mc_cbpa" },
395                         [2] = { .clk_name = "mc_ccpa" },
396                         [3] = { .clk_name = "mc_cdpa" },
397                         [4] = { .clk_name = "xusb_ss" },
398                         [5] = { .clk_name = "xusb_dev" },
399                         [6] = { .clk_name = "xusb_dev_slcg" },
400                         [7] = { .clk_name = "xusb_host_slcg" },
401                 },
402                 .reset_id = { TEGRA210_CLK_XUSB_HOST },
403                 .reset_id_num = 1,
404         },
405 #ifdef CONFIG_ARCH_TEGRA_VIC
406         [TEGRA210_POWER_DOMAIN_VIC] = {
407                 .name = "vic",
408                 .clk_info = {
409                         [0] = { .clk_name = "vic03.cbus", .clk_type = CLK_ONLY },
410                 },
411                 .slcg_info = {
412                         [0] = { .clk_name = "mc_capa" },
413                         [1] = { .clk_name = "mc_cbpa" },
414                         [2] = { .clk_name = "mc_ccpa" },
415                         [3] = { .clk_name = "mc_cdpa" },
416                         [4] = { .clk_name = "vic03_slcg_ovr" },
417                         [5] = { .clk_name = "host1x" },
418                 },
419                 .reset_id = { TEGRA210_CLK_VIC03 },
420                 .reset_id_num = 1,
421         },
422 #endif
423         [TEGRA210_POWER_DOMAIN_NVDEC] = {
424                 .name = "nvdec",
425                 .clk_info = {
426                         [0] = { .clk_name = "nvdec", .clk_type = CLK_ONLY },
427                 },
428                 .slcg_info = {
429                         [0] = { .clk_name = "mc_capa" },
430                         [1] = { .clk_name = "mc_cbpa" },
431                         [2] = { .clk_name = "mc_ccpa" },
432                         [3] = { .clk_name = "mc_cdpa" },
433                         [4] = { .clk_name = "nvdec_slcg_ovr" },
434                         [5] = { .clk_name = "nvjpg" },
435                         [6] = { .clk_name = "nvjpg_slcg_ovr" },
436                 },
437                 .reset_id = { TEGRA210_CLK_NVDEC },
438                 .reset_id_num = 1,
439         },
440         [TEGRA210_POWER_DOMAIN_NVJPG] = {
441                 .name = "nvjpg",
442                 .clk_info = {
443                         [0] = { .clk_name = "nvjpg", .clk_type = CLK_ONLY },
444                 },
445                 .slcg_info = {
446                         [0] = { .clk_name = "mc_capa" },
447                         [1] = { .clk_name = "mc_cbpa" },
448                         [2] = { .clk_name = "mc_ccpa" },
449                         [3] = { .clk_name = "mc_cdpa" },
450                         [4] = { .clk_name = "nvjpg_slcg_ovr" },
451                         [5] = { .clk_name = "nvdec" },
452                         [6] = { .clk_name = "nvdec_slcg_ovr" },
453                 },
454                 .reset_id = { TEGRA210_CLK_NVJPG },
455                 .reset_id_num = 1,
456         },
457         [TEGRA210_POWER_DOMAIN_APE] = {
458                 .name = "ape",
459                 .clk_info = {
460                         [0] = { .clk_name = "ape", .clk_type = CLK_ONLY },
461                 },
462                 .slcg_info = {
463                         [0] = { .clk_name = "mc_capa" },
464                         [1] = { .clk_name = "mc_cbpa" },
465                         [2] = { .clk_name = "mc_ccpa" },
466                         [3] = { .clk_name = "mc_cdpa" },
467                         [4] = { .clk_name = "aclk" },
468                         [5] = { .clk_name = "i2s0" },
469                         [6] = { .clk_name = "i2s1" },
470                         [7] = { .clk_name = "i2s2" },
471                         [8] = { .clk_name = "i2s3" },
472                         [9] = { .clk_name = "i2s4" },
473                         [10] = { .clk_name = "spdif_out" },
474                         [11] = { .clk_name = "d_audio" },
475                         [12] = { .clk_name = "ape_slcg_ovr" },
476                         [13] = { .clk_name = "aclk_slcg_ovr" },
477                         [14] = { .clk_name = "daudio_slcg_ovr" },
478
479                 },
480                 .reset_id = { TEGRA210_CLK_APE },
481                 .reset_id_num = 1,
482         },
483         [TEGRA210_POWER_DOMAIN_VE2] = {
484                 .name = "ve2",
485                 .clk_info = {
486                         [0] = { .clk_name = "ispb", .clk_type = CLK_ONLY },
487                 },
488                 .slcg_info = {
489                         [0] = { .clk_name = "mc_capa" },
490                         [1] = { .clk_name = "mc_cbpa" },
491                         [2] = { .clk_name = "mc_ccpa" },
492                         [3] = { .clk_name = "mc_cdpa" },
493                         [4] = { .clk_name = "ispb_slcg_ovr" },
494                 },
495                 .reset_id = { TEGRA210_CLK_ISPB },
496                 .reset_id_num = 1,
497         },
498         [TEGRA210_POWER_DOMAIN_GPU] = {
499                 .name = "gpu",
500                 .clk_info = {
501                         [0] = { .clk_name = "gpu_gate", .clk_type = CLK_AND_RST },
502                         [1] = { .clk_name = "gpu_ref", .clk_type = CLK_ONLY },
503                         [2] = { .clk_name = "pll_p_out5", .clk_type = CLK_ONLY },
504                 },
505         },
506 };
507
508 struct mc_client_hotreset_reg {
509         u32 control_reg;
510         u32 status_reg;
511 };
512
513 static struct mc_client_hotreset_reg tegra210_mc_reg[] = {
514         [0] = { .control_reg = 0x200, .status_reg = 0x204 },
515         [1] = { .control_reg = 0x970, .status_reg = 0x974 },
516 };
517
518 struct tegra210_powergate_info {
519         bool valid;
520         unsigned int mask;
521         int part_id;
522         struct tegra210_mc_client_info *mc_info;
523         struct powergate_partition_info *part_info;
524 };
525
526 #define T210_POWERGATE_INFO(_pg_id, _pg_bit, _part_id, _mc_id)          \
527 [TEGRA210_POWER_DOMAIN_##_pg_id] = {                                            \
528         .valid = true,                                                  \
529         .mask = BIT(_pg_bit),                                           \
530         .part_id = TEGRA210_POWER_DOMAIN_##_part_id,                            \
531         .mc_info = &tegra210_pg_mc_info[TEGRA210_POWER_DOMAIN_##_mc_id],        \
532         .part_info = &tegra210_pg_partition_info[TEGRA210_POWER_DOMAIN_##_part_id], \
533 }
534
535 static struct tegra210_powergate_info t210_pg_info[TEGRA210_POWER_DOMAIN_MAX] = {
536         T210_POWERGATE_INFO(CRAIL, 0, CRAIL, CRAIL),
537         T210_POWERGATE_INFO(GPU, 1, GPU, GPU),
538         T210_POWERGATE_INFO(VENC, 2, VENC, VENC),
539         T210_POWERGATE_INFO(PCIE, 3, PCIE, PCIE),
540         T210_POWERGATE_INFO(VDEC, 4, VDEC, VDEC),
541         T210_POWERGATE_INFO(L2, 5, L2, L2),
542         T210_POWERGATE_INFO(MPE, 6, MPE, MPE),
543         T210_POWERGATE_INFO(HEG, 7, HEG, HEG),
544         T210_POWERGATE_INFO(SATA, 8, SATA, SATA),
545         T210_POWERGATE_INFO(CPU1, 9, CPU1, CPU1),
546         T210_POWERGATE_INFO(CPU2, 10, CPU2, CPU2),
547         T210_POWERGATE_INFO(CPU3, 11, CPU3, CPU3),
548         T210_POWERGATE_INFO(CELP, 12, CELP, CELP),
549         T210_POWERGATE_INFO(3D1, 13, 3D1, 3D1),
550         T210_POWERGATE_INFO(CPU0, 14, CPU0, CPU0),
551         T210_POWERGATE_INFO(C0NC, 15, C0NC, C0NC),
552         T210_POWERGATE_INFO(C1NC, 16, C1NC, C1NC),
553         T210_POWERGATE_INFO(SOR, 17, SOR, SOR),
554         T210_POWERGATE_INFO(DISA, 18, DISA, DISA),
555         T210_POWERGATE_INFO(DISB, 19, DISB, DISB),
556         T210_POWERGATE_INFO(XUSBA, 20, XUSBA, XUSBA),
557         T210_POWERGATE_INFO(XUSBB, 21, XUSBB, XUSBB),
558         T210_POWERGATE_INFO(XUSBC, 22, XUSBC, XUSBC),
559         T210_POWERGATE_INFO(VIC, 23, VIC, VIC),
560         T210_POWERGATE_INFO(NVDEC, 25, NVDEC, NVDEC),
561         T210_POWERGATE_INFO(NVJPG, 26, NVJPG, NVJPG),
562         T210_POWERGATE_INFO(APE, 27, APE, APE),
563         T210_POWERGATE_INFO(VE2, 29, VE2, VE2),
564 };
565
566 #define PMC_GPU_RG_CONTROL              0x2d4
567
568 #define PWRGATE_CLAMP_STATUS            0x2c
569 #define PWRGATE_TOGGLE                  0x30
570 #define PWRGATE_TOGGLE_START            (1 << 8)
571 #define REMOVE_CLAMPING                 0x34
572 #define PWRGATE_STATUS                  0x38
573
574 static DEFINE_SPINLOCK(tegra210_pg_lock);
575
576 static struct dvfs_rail *gpu_rail;
577 static void __iomem *tegra_mc;
578 static void __iomem *tegra_pmc;
579
580 static int tegra210_pg_powergate_partition(int id);
581 static int tegra210_pg_unpowergate_partition(int id);
582 static int tegra210_pg_mc_flush(int id);
583 static int tegra210_pg_mc_flush_done(int id);
584
585 static u32 mc_read(unsigned long reg)
586 {
587         return readl(tegra_mc + reg);
588 }
589
590 static void mc_write(u32 val, unsigned long reg)
591 {
592         writel_relaxed(val, tegra_mc + reg);
593 }
594
595 /* PMC register read/write */
596 static u32 pmc_read(unsigned long reg)
597 {
598         return readl(tegra_pmc + reg);
599 }
600
601 static void pmc_write(u32 val, unsigned long reg)
602 {
603         writel_relaxed(val, tegra_pmc + reg);
604 }
605
606 #define HOTRESET_READ_COUNTS            5
607
608 static const char *tegra210_pg_get_name(int id)
609 {
610         return t210_pg_info[id].part_info->name;
611 }
612
613 static spinlock_t *tegra210_pg_get_lock(void)
614 {
615         return &tegra210_pg_lock;
616 }
617
618 static bool tegra210_pg_skip(int id)
619 {
620         u32 hid, chipid, major;
621
622         hid = tegra_read_chipid();
623         chipid = tegra_hidrev_get_chipid(hid);
624         major = tegra_hidrev_get_majorrev(hid);
625
626         switch (t210_pg_info[id].part_id) {
627         case TEGRA210_POWER_DOMAIN_GPU:
628                 return true;
629         case TEGRA210_POWER_DOMAIN_VENC:
630         case TEGRA210_POWER_DOMAIN_VE2:
631                 /* T214 has SE2 in place of ISP2 and powergate
632                  * is not supported for SE2.
633                  */
634                 if (chipid == TEGRA210B01 && major >= 2)
635                         return true;
636         default:
637                 return false;
638         }
639 }
640
641 static bool tegra210_pg_is_powered(int id)
642 {
643         u32 status = 0;
644
645         if (id == TEGRA210_POWER_DOMAIN_GPU) {
646                 if (gpu_rail)
647                         status = tegra_dvfs_is_rail_up(gpu_rail);
648         } else {
649                 status = pmc_read(PWRGATE_STATUS) & t210_pg_info[id].mask;
650         }
651
652         return !!status;
653 }
654
655 static int tegra_powergate_set(int id, bool new_state)
656 {
657         bool status;
658         unsigned long flags;
659         spinlock_t *lock;
660         u32 reg;
661
662         /* 10us timeout for toggle operation if it takes affect*/
663         int toggle_timeout = 10;
664
665         /* 100 * 10 = 1000us timeout for toggle command to take affect in case
666            of contention with h/w initiated CPU power gating */
667         int contention_timeout = 100;
668
669         if (tegra_cpu_is_asim())
670                 return 0;
671
672         lock = tegra210_pg_get_lock();
673
674         spin_lock_irqsave(lock, flags);
675
676         status = !!(pmc_read(PWRGATE_STATUS) & t210_pg_info[id].mask);
677
678         if (status == new_state) {
679                 spin_unlock_irqrestore(lock, flags);
680                 return 0;
681         }
682
683         switch (id) {
684         case TEGRA210_POWER_DOMAIN_CPU0:
685         case TEGRA210_POWER_DOMAIN_CPU1:
686         case TEGRA210_POWER_DOMAIN_CPU2:
687         case TEGRA210_POWER_DOMAIN_CPU3:
688                 /* CPU ungated in s/w only during boot/resume with outer
689                    waiting loop and no contention from other CPUs */
690                 pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
691                 pmc_read(PWRGATE_TOGGLE);
692                 spin_unlock_irqrestore(lock, flags);
693                 return 0;
694
695         default:
696                 break;
697         }
698
699         /* Wait if PMC is already processing some other power gating request */
700         do {
701                 udelay(1);
702                 reg = pmc_read(PWRGATE_TOGGLE);
703                 contention_timeout--;
704         } while ((contention_timeout > 0) && (reg & PWRGATE_TOGGLE_START));
705
706         if (contention_timeout <= 0)
707                 pr_err(" Timed out waiting for PMC to submit \
708                                 new power gate request \n");
709         contention_timeout = 100;
710
711         /* Submit power gate request */
712         pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
713
714         /* Wait while PMC accepts the request */
715         do {
716                 udelay(1);
717                 reg = pmc_read(PWRGATE_TOGGLE);
718                 contention_timeout--;
719         } while ((contention_timeout > 0) && (reg & PWRGATE_TOGGLE_START));
720
721         if (contention_timeout <= 0)
722                 pr_err(" Timed out waiting for PMC to accept \
723                                 new power gate request \n");
724         contention_timeout = 100;
725
726         /* Check power gate status */
727         do {
728                 do {
729                         udelay(1);
730                         status = !!(pmc_read(PWRGATE_STATUS) &
731                                     t210_pg_info[id].mask);
732
733                         toggle_timeout--;
734                 } while ((status != new_state) && (toggle_timeout > 0));
735
736                 toggle_timeout = 10;
737                 contention_timeout--;
738         } while ((status != new_state) && (contention_timeout > 0));
739
740         spin_unlock_irqrestore(lock, flags);
741
742         if (status != new_state) {
743                 WARN(1, "Could not set powergate %d to %d", id, new_state);
744                 return -EBUSY;
745         }
746
747         trace_power_domain_target(tegra210_pg_get_name(id), new_state,
748                         raw_smp_processor_id());
749
750         return 0;
751 }
752
753 static const char *clk_get_name(struct clk *clk)
754 {
755         return __clk_get_name(clk);
756 }
757
758 static int powergate_module(int id)
759 {
760         tegra210_pg_mc_flush(id);
761
762         return tegra_powergate_set(id, false);
763 }
764
765 static int partition_clk_enable(struct powergate_partition_info *pg_info)
766 {
767         int ret;
768         u32 idx;
769         struct clk *clk;
770         struct partition_clk_info *clk_info;
771
772         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
773                 clk_info = &pg_info->clk_info[idx];
774                 clk = clk_info->clk_ptr;
775                 if (IS_ERR(clk) || !clk)
776                         break;
777
778                 if (clk_info->clk_type != RST_ONLY) {
779                         ret = clk_prepare_enable(clk);
780                         if (ret)
781                                 goto err_clk_en;
782                 }
783         }
784
785         return 0;
786
787 err_clk_en:
788         WARN(1, "Could not enable clk %s, error %d", clk_get_name(clk), ret);
789         while (idx--) {
790                 clk_info = &pg_info->clk_info[idx];
791                 if (clk_info->clk_type != RST_ONLY)
792                         clk_disable_unprepare(clk_info->clk_ptr);
793         }
794
795         return ret;
796 }
797
798 static void partition_clk_disable(struct powergate_partition_info *pg_info)
799 {
800         u32 idx;
801         struct clk *clk;
802         struct partition_clk_info *clk_info;
803
804         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
805                 clk_info = &pg_info->clk_info[idx];
806                 clk = clk_info->clk_ptr;
807
808                 if (IS_ERR(clk) || !clk)
809                         break;
810
811                 if (clk_info->clk_type != RST_ONLY)
812                         clk_disable_unprepare(clk);
813         }
814 }
815
816 static void get_clk_info(struct powergate_partition_info *pg_info)
817 {
818         int idx;
819
820         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
821                 if (!pg_info->clk_info[idx].clk_name)
822                         break;
823
824                 pg_info->clk_info[idx].clk_ptr =
825                         clk_get_sys(NULL, pg_info->clk_info[idx].clk_name);
826
827                 if (IS_ERR_OR_NULL(pg_info->clk_info[idx].clk_ptr))
828                         WARN(1, "Could not find clock %s for %s partition\n",
829                                 pg_info->clk_info[idx].clk_name,
830                                 pg_info->name);
831         }
832 }
833
834 static void powergate_partition_assert_reset(struct powergate_partition_info *pg_info)
835 {
836         tegra_rst_assertv(&pg_info->reset_id[0], pg_info->reset_id_num);
837 }
838
839 static void powergate_partition_deassert_reset(struct powergate_partition_info *pg_info)
840 {
841         tegra_rst_deassertv(&pg_info->reset_id[0], pg_info->reset_id_num);
842 }
843
844 static int slcg_clk_enable(struct powergate_partition_info *pg_info)
845 {
846         int ret;
847         u32 idx;
848         struct clk *clk;
849         struct partition_clk_info *slcg_info;
850
851         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
852                 slcg_info = &pg_info->slcg_info[idx];
853                 clk = slcg_info->clk_ptr;
854                 if (IS_ERR(clk) || !clk)
855                         break;
856
857                 ret = clk_prepare_enable(clk);
858                 if (ret)
859                         goto err_clk_en;
860         }
861
862         return 0;
863
864 err_clk_en:
865         WARN(1, "Could not enable clk %s, error %d", __clk_get_name(clk), ret);
866         while (idx--) {
867                 slcg_info = &pg_info->slcg_info[idx];
868                 clk_disable_unprepare(slcg_info->clk_ptr);
869         }
870
871         return ret;
872 }
873
874 static void slcg_clk_disable(struct powergate_partition_info *pg_info)
875 {
876         u32 idx;
877         struct clk *clk;
878         struct partition_clk_info *slcg_info;
879
880         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
881                 slcg_info = &pg_info->slcg_info[idx];
882                 clk = slcg_info->clk_ptr;
883
884                 if (IS_ERR(clk) || !clk)
885                         break;
886
887                 clk_disable_unprepare(clk);
888         }
889 }
890
891 static void get_slcg_info(struct powergate_partition_info *pg_info)
892 {
893         int idx;
894
895         for (idx = 0; idx < MAX_CLK_EN_NUM; idx++) {
896                 if (!pg_info->slcg_info[idx].clk_name)
897                         break;
898
899                 pg_info->slcg_info[idx].clk_ptr =
900                         clk_get_sys(NULL, pg_info->slcg_info[idx].clk_name);
901
902                 if (IS_ERR_OR_NULL(pg_info->slcg_info[idx].clk_ptr))
903                         pr_err("### Could not find clock %s for %s partition\n",
904                                 pg_info->slcg_info[idx].clk_name,
905                                 pg_info->name);
906         }
907 }
908
909 static int tegra210_slcg_register_notifier(int id, struct notifier_block *nb)
910 {
911         struct powergate_partition_info *pg_info = t210_pg_info[id].part_info;
912
913         if (!pg_info || !nb)
914                 return -EINVAL;
915
916         return raw_notifier_chain_register(&pg_info->slcg_notifier, nb);
917 }
918
919 static int tegra210_slcg_unregister_notifier(int id, struct notifier_block *nb)
920 {
921         struct powergate_partition_info *pg_info = t210_pg_info[id].part_info;
922
923         if (!pg_info || !nb)
924                 return -EINVAL;
925
926         return raw_notifier_chain_unregister(&pg_info->slcg_notifier, nb);
927 }
928
929 static int tegra210_powergate_remove_clamping(int id)
930 {
931         u32 mask;
932         int contention_timeout = 100;
933
934         /*
935          * PCIE and VDE clamping masks are swapped with respect to their
936          * partition ids
937          */
938         if (id ==  TEGRA210_POWER_DOMAIN_VDEC)
939                 mask = t210_pg_info[TEGRA210_POWER_DOMAIN_PCIE].mask;
940         else if (id == TEGRA210_POWER_DOMAIN_PCIE)
941                 mask = t210_pg_info[TEGRA210_POWER_DOMAIN_VDEC].mask;
942         else
943                 mask = t210_pg_info[id].mask;
944
945         pmc_write(mask, REMOVE_CLAMPING);
946         /* Wait until clamp is removed */
947         do {
948                 udelay(1);
949                 contention_timeout--;
950         } while ((contention_timeout > 0)
951                         && (pmc_read(PWRGATE_CLAMP_STATUS) & BIT(id)));
952
953         WARN(contention_timeout <= 0, "Couldn't remove clamping");
954
955         return 0;
956 }
957
958 static int __tegra1xx_powergate(int id, struct powergate_partition_info *pg_info,
959                                 bool clk_enable)
960 {
961         int ret;
962
963         /* If first clk_ptr is null, fill clk info for the partition */
964         if (!pg_info->clk_info[0].clk_ptr)
965                 get_clk_info(pg_info);
966
967         if (clk_enable) {
968                 /*
969                  * Enable clocks only if clocks are not expected to
970                  * be off when power gating is done
971                  */
972                 ret = partition_clk_enable(pg_info);
973                 if (ret) {
974                         WARN(1, "Couldn't enable clock");
975                         return ret;
976                 }
977
978                 udelay(10);
979         }
980
981         tegra210_pg_mc_flush(id);
982
983         udelay(10);
984
985         powergate_partition_assert_reset(pg_info);
986
987         udelay(10);
988
989         /* Powergating is done only if refcnt of all clks is 0 */
990         partition_clk_disable(pg_info);
991
992         udelay(10);
993
994         ret = tegra_powergate_set(id, false);
995         if (ret)
996                 goto err_power_off;
997
998         return 0;
999
1000 err_power_off:
1001         WARN(1, "Could not Powergate Partition %d", id);
1002         return ret;
1003 }
1004
1005 static int tegra1xx_powergate(int id, struct powergate_partition_info *pg_info)
1006 {
1007         return __tegra1xx_powergate(id, pg_info, true);
1008 }
1009
1010 static int __tegra1xx_unpowergate(int id, struct powergate_partition_info *pg_info,
1011                                 bool clk_disable)
1012 {
1013         int ret;
1014
1015         /* If first clk_ptr is null, fill clk info for the partition */
1016         if (!pg_info->clk_info[0].clk_ptr)
1017                 get_clk_info(pg_info);
1018
1019         if (!pg_info->slcg_info[0].clk_ptr)
1020                 get_slcg_info(pg_info);
1021
1022         if (tegra210_pg_is_powered(id)) {
1023                 if (!clk_disable) {
1024                         ret = partition_clk_enable(pg_info);
1025                         if (ret)
1026                                 return ret;
1027                         if (!pg_info->skip_reset) {
1028                                 powergate_partition_assert_reset(pg_info);
1029                                 udelay(10);
1030                                 powergate_partition_deassert_reset(pg_info);
1031                         }
1032                 }
1033                 return 0;
1034         }
1035
1036         ret = tegra_powergate_set(id, true);
1037         if (ret)
1038                 goto err_power;
1039
1040         udelay(10);
1041
1042         /* Un-Powergating fails if all clks are not enabled */
1043         ret = partition_clk_enable(pg_info);
1044         if (ret)
1045                 goto err_clk_on;
1046
1047         powergate_partition_assert_reset(pg_info);
1048
1049         udelay(10);
1050
1051         ret = tegra210_powergate_remove_clamping(id);
1052         if (ret)
1053                 goto err_clamp;
1054
1055         udelay(10);
1056
1057         if (!pg_info->skip_reset) {
1058                 powergate_partition_deassert_reset(pg_info);
1059
1060                 udelay(10);
1061         }
1062
1063         tegra210_pg_mc_flush_done(id);
1064
1065         udelay(10);
1066
1067         slcg_clk_enable(pg_info);
1068
1069         raw_notifier_call_chain(&pg_info->slcg_notifier, 0, NULL);
1070
1071         slcg_clk_disable(pg_info);
1072
1073         /* Disable all clks enabled earlier. Drivers should enable clks */
1074         if (clk_disable)
1075                 partition_clk_disable(pg_info);
1076
1077         return 0;
1078
1079 err_clamp:
1080         partition_clk_disable(pg_info);
1081 err_clk_on:
1082         powergate_module(id);
1083 err_power:
1084         WARN(1, "Could not Un-Powergate %d", id);
1085         return ret;
1086 }
1087
1088 static int tegra1xx_unpowergate(int id,
1089                                 struct powergate_partition_info *pg_info)
1090 {
1091         return __tegra1xx_unpowergate(id, pg_info, true);
1092 }
1093
1094 static int tegra1xx_powergate_partition_with_clk_off(int id,
1095                 struct powergate_partition_info *pg_info)
1096 {
1097         int ret = 0;
1098
1099         ret = __tegra1xx_powergate(id, pg_info, false);
1100         if (ret)
1101                 WARN(1, "Could not Powergate Partition %d", id);
1102
1103         return ret;
1104 }
1105
1106 static int tegra1xx_unpowergate_partition_with_clk_on(int id,
1107         struct powergate_partition_info *pg_info)
1108 {
1109         int ret = 0;
1110
1111         ret = __tegra1xx_unpowergate(id, pg_info, false);
1112         if (ret)
1113                 WARN(1, "Could not Un-Powergate %d", id);
1114
1115         return ret;
1116 }
1117
1118
1119 static bool tegra210_pg_hotreset_check(u32 status_reg, u32 *status)
1120 {
1121         int i;
1122         u32 curr_status;
1123         u32 prev_status;
1124         unsigned long flags;
1125
1126         spin_lock_irqsave(&tegra210_pg_lock, flags);
1127         prev_status = mc_read(status_reg);
1128         for (i = 0; i < HOTRESET_READ_COUNTS; i++) {
1129                 curr_status = mc_read(status_reg);
1130                 if (curr_status != prev_status) {
1131                         spin_unlock_irqrestore(&tegra210_pg_lock, flags);
1132                         return false;
1133                 }
1134         }
1135         *status = curr_status;
1136         spin_unlock_irqrestore(&tegra210_pg_lock, flags);
1137
1138         return true;
1139 }
1140
1141 static int tegra210_pg_mc_flush(int id)
1142 {
1143         u32 idx, rst_control, rst_status;
1144         u32 rst_control_reg, rst_status_reg;
1145         enum mc_client mc_client_bit;
1146         unsigned long flags;
1147         unsigned int timeout;
1148         bool ret;
1149         int reg_idx;
1150
1151         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
1152                 mc_client_bit =
1153                         t210_pg_info[id].mc_info->hot_reset_clients[idx];
1154                 if (mc_client_bit == MC_CLIENT_LAST)
1155                         break;
1156
1157                 reg_idx = mc_client_bit / 32;
1158                 mc_client_bit %= 32;
1159                 rst_control_reg = tegra210_mc_reg[reg_idx].control_reg;
1160                 rst_status_reg = tegra210_mc_reg[reg_idx].status_reg;
1161
1162                 spin_lock_irqsave(&tegra210_pg_lock, flags);
1163                 rst_control = mc_read(rst_control_reg);
1164                 rst_control |= (1 << mc_client_bit);
1165                 mc_write(rst_control, rst_control_reg);
1166                 spin_unlock_irqrestore(&tegra210_pg_lock, flags);
1167
1168                 timeout = 0;
1169                 do {
1170                         udelay(10);
1171                         rst_status = 0;
1172                         ret = tegra210_pg_hotreset_check(rst_status_reg,
1173                                                                 &rst_status);
1174                         if ((timeout++ > EMULATION_MC_FLUSH_TIMEOUT) &&
1175                                 (tegra_platform_is_qt() ||
1176                                 tegra_platform_is_fpga())) {
1177                                 pr_warn("%s flush %d timeout\n", __func__, id);
1178                                 break;
1179                         }
1180                         if (!ret)
1181                                 continue;
1182                 } while (!(rst_status & (1 << mc_client_bit)));
1183         }
1184
1185         return 0;
1186 }
1187
1188 static int tegra210_pg_mc_flush_done(int id)
1189 {
1190         u32 idx, rst_control, rst_control_reg;
1191         enum mc_client mc_client_bit;
1192         unsigned long flags;
1193         int reg_idx;
1194
1195         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
1196                 mc_client_bit =
1197                         t210_pg_info[id].mc_info->hot_reset_clients[idx];
1198                 if (mc_client_bit == MC_CLIENT_LAST)
1199                         break;
1200
1201                 reg_idx = mc_client_bit / 32;
1202                 mc_client_bit %= 32;
1203                 rst_control_reg = tegra210_mc_reg[reg_idx].control_reg;
1204
1205                 spin_lock_irqsave(&tegra210_pg_lock, flags);
1206                 rst_control = mc_read(rst_control_reg);
1207                 rst_control &= ~(1 << mc_client_bit);
1208                 mc_write(rst_control, rst_control_reg);
1209                 spin_unlock_irqrestore(&tegra210_pg_lock, flags);
1210
1211         }
1212         wmb();
1213
1214         return 0;
1215 }
1216
1217 static int tegra210_pg_powergate(int id)
1218 {
1219         struct powergate_partition_info *partition = t210_pg_info[id].part_info;
1220         int ret = 0;
1221
1222         trace_powergate(__func__, tegra210_pg_get_name(id), id, 1, 0);
1223         mutex_lock(&partition->pg_mutex);
1224
1225         if (--partition->refcount > 0)
1226                 goto exit_unlock;
1227
1228         if ((partition->refcount < 0) || !tegra210_pg_is_powered(id)) {
1229                 WARN(1, "Partition %s already powergated, refcount and status mismatch\n",
1230                      partition->name);
1231                 goto exit_unlock;
1232         }
1233
1234         ret = tegra1xx_powergate(id, partition);
1235
1236 exit_unlock:
1237         mutex_unlock(&partition->pg_mutex);
1238         trace_powergate(__func__, tegra210_pg_get_name(id), id, 0, ret);
1239         return ret;
1240 }
1241
1242 static int tegra210_pg_unpowergate(int id)
1243 {
1244         struct powergate_partition_info *partition = t210_pg_info[id].part_info;
1245         int ret = 0;
1246
1247         trace_powergate(__func__, tegra210_pg_get_name(id), id, 1, 0);
1248         mutex_lock(&partition->pg_mutex);
1249
1250         if (partition->refcount++ > 0)
1251                 goto exit_unlock;
1252
1253         if (tegra210_pg_is_powered(id)) {
1254                 WARN(1, "Partition %s is already unpowergated, refcount and status mismatch\n",
1255                      partition->name);
1256                 goto exit_unlock;
1257         }
1258
1259         ret = tegra1xx_unpowergate(id, partition);
1260
1261 exit_unlock:
1262         mutex_unlock(&partition->pg_mutex);
1263         trace_powergate(__func__, tegra210_pg_get_name(id), id, 0, ret);
1264         return ret;
1265 }
1266
1267 static int tegra210_pg_gpu_powergate(int id)
1268 {
1269         int ret = 0;
1270         struct powergate_partition_info *partition = t210_pg_info[id].part_info;
1271
1272         trace_powergate(__func__, tegra210_pg_get_name(id), id, 1, 0);
1273         mutex_lock(&partition->pg_mutex);
1274
1275         if (--partition->refcount > 0)
1276                 goto exit_unlock;
1277
1278         if (!tegra210_pg_is_powered(id)) {
1279                 WARN(1, "GPU rail is already off, refcount and status mismatch\n");
1280                 goto exit_unlock;
1281         }
1282
1283         if (!partition->clk_info[0].clk_ptr)
1284                 get_clk_info(partition);
1285
1286         tegra210_pg_mc_flush(id);
1287
1288         udelay(10);
1289
1290         powergate_partition_assert_reset(partition);
1291
1292         udelay(10);
1293
1294         pmc_write(0x1, PMC_GPU_RG_CONTROL);
1295         pmc_read(PMC_GPU_RG_CONTROL);
1296
1297         udelay(10);
1298
1299         partition_clk_disable(partition);
1300
1301         udelay(10);
1302
1303         tegra_soctherm_gpu_tsens_invalidate(1);
1304
1305         if (gpu_rail) {
1306                 ret = tegra_dvfs_rail_power_down(gpu_rail);
1307                 if (ret) {
1308                         WARN(1, "Could not power down GPU rail\n");
1309                         goto exit_unlock;
1310                 }
1311         } else {
1312                 pr_info("No GPU regulator?\n");
1313         }
1314
1315 exit_unlock:
1316         mutex_unlock(&partition->pg_mutex);
1317         trace_powergate(__func__, tegra210_pg_get_name(id), id, 0, ret);
1318         return ret;
1319 }
1320
1321 static int tegra210_pg_gpu_unpowergate(int id)
1322 {
1323         int ret = 0;
1324         bool first = false;
1325         struct powergate_partition_info *partition = t210_pg_info[id].part_info;
1326
1327         trace_powergate(__func__, tegra210_pg_get_name(id), id, 1, 0);
1328         mutex_lock(&partition->pg_mutex);
1329
1330         if (partition->refcount++ > 0)
1331                 goto exit_unlock;
1332
1333         if (!gpu_rail) {
1334                 gpu_rail = tegra_dvfs_get_rail_by_name("vdd_gpu");
1335                 if (IS_ERR_OR_NULL(gpu_rail)) {
1336                         WARN(1, "No GPU regulator?\n");
1337                         goto err_power;
1338                 }
1339                 first = true;
1340         }
1341
1342         if (tegra210_pg_is_powered(id)) {
1343                 WARN(1, "GPU rail is already on, refcount and status mismatch\n");
1344                 goto exit_unlock;
1345         }
1346
1347         ret = tegra_dvfs_rail_power_up(gpu_rail);
1348         if (ret) {
1349                 WARN(1, "Could not turn on GPU rail\n");
1350                 goto err_power;
1351         }
1352
1353         tegra_soctherm_gpu_tsens_invalidate(0);
1354
1355         if (!partition->clk_info[0].clk_ptr)
1356                 get_clk_info(partition);
1357
1358         if (!first) {
1359                 ret = partition_clk_enable(partition);
1360                 if (ret) {
1361                         WARN(1, "Could not turn on partition clocks\n");
1362                         goto err_clk_on;
1363                 }
1364         }
1365
1366         udelay(10);
1367
1368         powergate_partition_assert_reset(partition);
1369
1370         udelay(10);
1371
1372         pmc_write(0, PMC_GPU_RG_CONTROL);
1373         pmc_read(PMC_GPU_RG_CONTROL);
1374
1375         udelay(10);
1376
1377         /*
1378          * Make sure all clok branches into GPU, except reference clock are
1379          * gated across resert de-assertion.
1380          */
1381         clk_disable_unprepare(partition->clk_info[0].clk_ptr);
1382         powergate_partition_deassert_reset(partition);
1383         clk_prepare_enable(partition->clk_info[0].clk_ptr);
1384
1385         /* Flush MC after boot/railgate/SC7 */
1386         tegra210_pg_mc_flush(id);
1387
1388         udelay(10);
1389
1390         tegra210_pg_mc_flush_done(id);
1391
1392         udelay(10);
1393
1394 exit_unlock:
1395         mutex_unlock(&partition->pg_mutex);
1396         trace_powergate(__func__, tegra210_pg_get_name(id), id, 0, ret);
1397         return ret;
1398
1399 err_clk_on:
1400         powergate_module(id);
1401 err_power:
1402         mutex_unlock(&partition->pg_mutex);
1403
1404         trace_powergate(__func__, tegra210_pg_get_name(id), id, 0, ret);
1405         return ret;
1406 }
1407
1408 static int tegra210_pg_powergate_sor(int id)
1409 {
1410         int ret;
1411
1412         ret = tegra210_pg_powergate(id);
1413         if (ret)
1414                 return ret;
1415
1416         ret = tegra210_pg_powergate_partition(TEGRA210_POWER_DOMAIN_SOR);
1417         if (ret)
1418                 return ret;
1419
1420         return 0;
1421 }
1422
1423 static int tegra210_pg_unpowergate_sor(int id)
1424 {
1425         int ret;
1426
1427         ret = tegra210_pg_unpowergate_partition(TEGRA210_POWER_DOMAIN_SOR);
1428         if (ret)
1429                 return ret;
1430
1431         ret = tegra210_pg_unpowergate(id);
1432         if (ret) {
1433                 tegra210_pg_powergate_partition(TEGRA210_POWER_DOMAIN_SOR);
1434                 return ret;
1435         }
1436
1437         return 0;
1438 }
1439
1440 static int tegra210_pg_nvdec_powergate(int id)
1441 {
1442         tegra210_pg_powergate(TEGRA210_POWER_DOMAIN_NVDEC);
1443         tegra210_pg_powergate_partition(TEGRA210_POWER_DOMAIN_NVJPG);
1444
1445         return 0;
1446 }
1447
1448 static int tegra210_pg_nvdec_unpowergate(int id)
1449 {
1450         tegra210_pg_unpowergate_partition(TEGRA210_POWER_DOMAIN_NVJPG);
1451         tegra210_pg_unpowergate(TEGRA210_POWER_DOMAIN_NVDEC);
1452
1453         return 0;
1454 }
1455
1456 static int tegra210_pg_sata_powergate(int id)
1457 {
1458         tegra210_set_sata_pll_seq_sw(true);
1459         tegra210_pg_powergate(TEGRA210_POWER_DOMAIN_SATA);
1460
1461         return 0;
1462 }
1463
1464 static int tegra210_pg_sata_unpowergate(int id)
1465 {
1466         tegra210_pg_unpowergate(TEGRA210_POWER_DOMAIN_SATA);
1467         tegra210_set_sata_pll_seq_sw(false);
1468
1469         return 0;
1470 }
1471
1472 static int tegra210_pg_powergate_partition(int id)
1473 {
1474         int ret;
1475
1476         switch (t210_pg_info[id].part_id) {
1477                 case TEGRA210_POWER_DOMAIN_GPU:
1478                         ret = tegra210_pg_gpu_powergate(id);
1479                         break;
1480                 case TEGRA210_POWER_DOMAIN_DISA:
1481                 case TEGRA210_POWER_DOMAIN_DISB:
1482                 case TEGRA210_POWER_DOMAIN_VENC:
1483                         ret = tegra210_pg_powergate_sor(id);
1484                         break;
1485                 case TEGRA210_POWER_DOMAIN_NVDEC:
1486                         ret = tegra210_pg_nvdec_powergate(id);
1487                         break;
1488                 case TEGRA210_POWER_DOMAIN_SATA:
1489                         ret = tegra210_pg_sata_powergate(id);
1490                         break;
1491                 default:
1492                         ret = tegra210_pg_powergate(id);
1493         }
1494
1495         return ret;
1496 }
1497
1498 static int tegra210_pg_unpowergate_partition(int id)
1499 {
1500         int ret;
1501
1502         switch (t210_pg_info[id].part_id) {
1503                 case TEGRA210_POWER_DOMAIN_GPU:
1504                         ret = tegra210_pg_gpu_unpowergate(id);
1505                         break;
1506                 case TEGRA210_POWER_DOMAIN_DISA:
1507                 case TEGRA210_POWER_DOMAIN_DISB:
1508                 case TEGRA210_POWER_DOMAIN_VENC:
1509                         ret = tegra210_pg_unpowergate_sor(id);
1510                         break;
1511                 case TEGRA210_POWER_DOMAIN_NVDEC:
1512                         ret = tegra210_pg_nvdec_unpowergate(id);
1513                         break;
1514                 case TEGRA210_POWER_DOMAIN_SATA:
1515                         ret = tegra210_pg_sata_unpowergate(id);
1516                         break;
1517                 default:
1518                         ret = tegra210_pg_unpowergate(id);
1519         }
1520
1521         return ret;
1522 }
1523
1524 static int tegra210_pg_powergate_clk_off(int id)
1525 {
1526         int ret = 0;
1527         struct powergate_partition_info *partition = t210_pg_info[id].part_info;
1528
1529         BUG_ON(id == TEGRA210_POWER_DOMAIN_GPU);
1530
1531         trace_powergate(__func__, tegra210_pg_get_name(id), id, 1, 0);
1532         mutex_lock(&partition->pg_mutex);
1533
1534         if (--partition->refcount > 0)
1535                 goto exit_unlock;
1536
1537         if ((partition->refcount < 0) || !tegra210_pg_is_powered(id)) {
1538                 WARN(1, "Partition %s already powergated, refcount and status mismatch\n",
1539                      partition->name);
1540                 goto exit_unlock;
1541         }
1542
1543         if (t210_pg_info[id].part_id == TEGRA210_POWER_DOMAIN_SATA)
1544                 tegra210_set_sata_pll_seq_sw(true);
1545
1546         ret = tegra1xx_powergate_partition_with_clk_off(id,
1547                         t210_pg_info[id].part_info);
1548
1549 exit_unlock:
1550         mutex_unlock(&partition->pg_mutex);
1551         trace_powergate(__func__, tegra210_pg_get_name(id), id, 0, ret);
1552
1553         return ret;
1554 }
1555
1556 static int tegra210_pg_unpowergate_clk_on(int id)
1557 {
1558         int ret = 0;
1559         struct powergate_partition_info *partition = t210_pg_info[id].part_info;
1560
1561         BUG_ON(id == TEGRA210_POWER_DOMAIN_GPU);
1562         trace_powergate(__func__, tegra210_pg_get_name(id), id, 1, 0);
1563         mutex_lock(&partition->pg_mutex);
1564
1565         if (partition->refcount++ > 0)
1566                 goto exit_unlock;
1567
1568         ret = tegra1xx_unpowergate_partition_with_clk_on(id,
1569                         t210_pg_info[id].part_info);
1570
1571         if (t210_pg_info[id].part_id == TEGRA210_POWER_DOMAIN_SATA)
1572                 tegra210_set_sata_pll_seq_sw(false);
1573
1574 exit_unlock:
1575         mutex_unlock(&partition->pg_mutex);
1576         trace_powergate(__func__, tegra210_pg_get_name(id), id, 0, ret);
1577
1578         return ret;
1579 }
1580
1581 static int tegra210_pg_init_refcount(void)
1582 {
1583         int i;
1584
1585         for (i = 0; i < TEGRA210_POWER_DOMAIN_MAX; i++) {
1586                 if (!t210_pg_info[i].valid)
1587                         continue;
1588
1589                 /* Consider main partion ID only */
1590                 if (i != t210_pg_info[i].part_id)
1591                         continue;
1592
1593                 if (tegra210_pg_is_powered(i))
1594                         t210_pg_info[i].part_info->refcount = 1;
1595                 else
1596                         t210_pg_info[i].part_info->disable_after_boot = 0;
1597
1598                 mutex_init(&t210_pg_info[i].part_info->pg_mutex);
1599         }
1600
1601         /* SOR refcount depends on other units */
1602         t210_pg_info[TEGRA210_POWER_DOMAIN_SOR].part_info->refcount =
1603                 (tegra210_pg_is_powered(TEGRA210_POWER_DOMAIN_DISA) ? 1 : 0) +
1604                 (tegra210_pg_is_powered(TEGRA210_POWER_DOMAIN_DISB) ? 1 : 0) +
1605                 (tegra210_pg_is_powered(TEGRA210_POWER_DOMAIN_VENC) ? 1 : 0);
1606
1607         tegra210_pg_powergate_partition(TEGRA210_POWER_DOMAIN_XUSBA);
1608         tegra210_pg_powergate_partition(TEGRA210_POWER_DOMAIN_XUSBB);
1609         tegra210_pg_powergate_partition(TEGRA210_POWER_DOMAIN_XUSBC);
1610
1611         return 0;
1612 }
1613
1614 static bool tegra210_powergate_id_is_valid(int id)
1615 {
1616         if ((id < 0) || (id >= TEGRA210_POWER_DOMAIN_MAX))
1617                 return false;
1618
1619         return t210_pg_info[id].valid;
1620 }
1621
1622 static int tegra210_powergate_cpuid_to_powergate_id(int cpu)
1623 {
1624         switch (cpu) {
1625         case 0:
1626                 return TEGRA210_POWER_DOMAIN_CPU0;
1627         case 1:
1628                 return TEGRA210_POWER_DOMAIN_CPU1;
1629         case 2:
1630                 return TEGRA210_POWER_DOMAIN_CPU2;
1631         case 3:
1632                 return TEGRA210_POWER_DOMAIN_CPU3;
1633         default:
1634                 return -1;
1635         }
1636
1637         return -1;
1638 }
1639
1640 static struct tegra_powergate_driver_ops tegra210_pg_ops = {
1641         .soc_name = "tegra210",
1642
1643         .num_powerdomains = TEGRA210_POWER_DOMAIN_MAX,
1644         .powergate_id_is_soc_valid = tegra210_powergate_id_is_valid,
1645         .powergate_cpuid_to_powergate_id =
1646                                 tegra210_powergate_cpuid_to_powergate_id,
1647
1648         .get_powergate_lock = tegra210_pg_get_lock,
1649         .get_powergate_domain_name = tegra210_pg_get_name,
1650
1651         .powergate_partition = tegra210_pg_powergate_partition,
1652         .unpowergate_partition = tegra210_pg_unpowergate_partition,
1653
1654         .powergate_partition_with_clk_off = tegra210_pg_powergate_clk_off,
1655         .unpowergate_partition_with_clk_on = tegra210_pg_unpowergate_clk_on,
1656
1657         .powergate_mc_flush = tegra210_pg_mc_flush,
1658         .powergate_mc_flush_done = tegra210_pg_mc_flush_done,
1659
1660         .powergate_skip = tegra210_pg_skip,
1661
1662         .powergate_is_powered = tegra210_pg_is_powered,
1663
1664         .powergate_init_refcount = tegra210_pg_init_refcount,
1665         .powergate_remove_clamping = tegra210_powergate_remove_clamping,
1666         .slcg_register_notifier = tegra210_slcg_register_notifier,
1667         .slcg_unregister_notifier = tegra210_slcg_unregister_notifier,
1668 };
1669
1670 #define TEGRA_PMC_BASE  0x7000E400
1671 #define TEGRA_MC_BASE   0x70019000
1672 struct tegra_powergate_driver_ops *tegra210_powergate_init_chip_support(void)
1673 {
1674         tegra_pmc = ioremap(TEGRA_PMC_BASE, 4096);
1675         tegra_mc = ioremap(TEGRA_MC_BASE, 4096);
1676
1677         if (tegra_platform_is_linsim())
1678                 return NULL;
1679
1680         return &tegra210_pg_ops;
1681 }
1682
1683 static int __init tegra210_disable_boot_partitions(void)
1684 {
1685         int i;
1686
1687         if (!soc_is_tegra210_n_before())
1688                 return 0;
1689
1690         pr_info("Disable partitions left on by BL\n");
1691         for (i = 0; i < TEGRA210_POWER_DOMAIN_MAX; i++) {
1692                 if (!t210_pg_info[i].valid)
1693                         continue;
1694
1695                 /* consider main partion ID only */
1696                 if (i != t210_pg_info[i].part_id)
1697                         continue;
1698
1699                 if (t210_pg_info[i].part_info->disable_after_boot &&
1700                         (t210_pg_info[i].part_id != TEGRA210_POWER_DOMAIN_GPU)) {
1701                         pr_info("  %s\n", t210_pg_info[i].part_info->name);
1702                         tegra210_pg_powergate_partition(i);
1703                 }
1704         }
1705
1706         return 0;
1707 }
1708 late_initcall(tegra210_disable_boot_partitions);