]> rtime.felk.cvut.cz Git - hercules2020/nv-tegra/linux-4.4.git/blob - drivers/platform/tegra/powergate/powergate-t21x.c
platform: powergate: correct sclg clock names for APE
[hercules2020/nv-tegra/linux-4.4.git] / drivers / platform / tegra / powergate / powergate-t21x.c
1 /*
2  * Copyright (c) 2014-2016, 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/spinlock.h>
17 #include <linux/delay.h>
18 #include <linux/regulator/consumer.h>
19 #include <linux/tegra-powergate.h>
20 #include <linux/tegra-soc.h>
21 #include <linux/tegra_soctherm.h>
22 #include <soc/tegra/tegra-dvfs.h>
23 #include <trace/events/power.h>
24
25 #include "powergate-priv.h"
26 #include "powergate-ops-t1xx.h"
27
28 #define EMULATION_MC_FLUSH_TIMEOUT 100
29
30 enum mc_client {
31         MC_CLIENT_AFI           = 0,
32         MC_CLIENT_AVPC          = 1,
33         MC_CLIENT_DC            = 2,
34         MC_CLIENT_DCB           = 3,
35         MC_CLIENT_HC            = 6,
36         MC_CLIENT_HDA           = 7,
37         MC_CLIENT_ISP2          = 8,
38         MC_CLIENT_NVENC         = 11,
39         MC_CLIENT_SATA          = 15,
40         MC_CLIENT_VI            = 17,
41         MC_CLIENT_VIC           = 18,
42         MC_CLIENT_XUSB_HOST     = 19,
43         MC_CLIENT_XUSB_DEV      = 20,
44         MC_CLIENT_BPMP          = 21,
45         MC_CLIENT_TSEC          = 22,
46         MC_CLIENT_SDMMC1        = 29,
47         MC_CLIENT_SDMMC2        = 30,
48         MC_CLIENT_SDMMC3        = 31,
49         MC_CLIENT_SDMMC4        = 32,
50         MC_CLIENT_ISP2B         = 33,
51         MC_CLIENT_GPU           = 34,
52         MC_CLIENT_NVDEC         = 37,
53         MC_CLIENT_APE           = 38,
54         MC_CLIENT_SE            = 39,
55         MC_CLIENT_NVJPG         = 40,
56         MC_CLIENT_TSECB         = 45,
57         MC_CLIENT_LAST          = -1,
58 };
59
60 struct tegra210_mc_client_info {
61         enum mc_client  hot_reset_clients[MAX_HOTRESET_CLIENT_NUM];
62 };
63
64 static struct tegra210_mc_client_info tegra210_pg_mc_info[] = {
65         [TEGRA_POWERGATE_CRAIL] = {
66                 .hot_reset_clients = {
67                         [0] = MC_CLIENT_LAST,
68                 },
69         },
70         [TEGRA_POWERGATE_VE] = {
71                 .hot_reset_clients = {
72                         [0] = MC_CLIENT_ISP2,
73                         [1] = MC_CLIENT_VI,
74                         [2] = MC_CLIENT_LAST,
75                 },
76         },
77 #ifdef CONFIG_ARCH_TEGRA_HAS_PCIE
78         [TEGRA_POWERGATE_PCIE] = {
79                 .hot_reset_clients = {
80                         [0] = MC_CLIENT_AFI,
81                         [1] = MC_CLIENT_LAST,
82                 },
83         },
84 #endif
85 #ifdef CONFIG_ARCH_TEGRA_HAS_SATA
86         [TEGRA_POWERGATE_SATA] = {
87                 .hot_reset_clients = {
88                         [0] = MC_CLIENT_SATA,
89                         [1] = MC_CLIENT_LAST,
90                 },
91         },
92 #endif
93         [TEGRA_POWERGATE_NVENC] = {
94                 .hot_reset_clients = {
95                         [0] = MC_CLIENT_NVENC,
96                         [1] = MC_CLIENT_LAST,
97                 },
98         },
99         [TEGRA_POWERGATE_SOR] = {
100                 .hot_reset_clients = {
101                         [0] = MC_CLIENT_LAST,
102                 },
103         },
104         [TEGRA_POWERGATE_DISA] = {
105                 .hot_reset_clients = {
106                         [0] = MC_CLIENT_DC,
107                         [1] = MC_CLIENT_LAST,
108                 },
109         },
110         [TEGRA_POWERGATE_DISB] = {
111                 .hot_reset_clients = {
112                         [0] = MC_CLIENT_DCB,
113                         [1] = MC_CLIENT_LAST,
114                 },
115         },
116         [TEGRA_POWERGATE_XUSBA] = {
117                 .hot_reset_clients = {
118                         [0] = MC_CLIENT_LAST,
119                 },
120         },
121         [TEGRA_POWERGATE_XUSBB] = {
122                 .hot_reset_clients = {
123                         [0] = MC_CLIENT_XUSB_DEV,
124                         [1] = MC_CLIENT_LAST,
125                 },
126         },
127         [TEGRA_POWERGATE_XUSBC] = {
128                 .hot_reset_clients = {
129                         [0] = MC_CLIENT_XUSB_HOST,
130                         [1] = MC_CLIENT_LAST,
131                 },
132         },
133 #ifdef CONFIG_ARCH_TEGRA_VIC
134         [TEGRA_POWERGATE_VIC] = {
135                 .hot_reset_clients = {
136                         [0] = MC_CLIENT_VIC,
137                         [1] = MC_CLIENT_LAST,
138                 },
139         },
140 #endif
141         [TEGRA_POWERGATE_NVDEC] = {
142                 .hot_reset_clients = {
143                         [0] = MC_CLIENT_NVDEC,
144                         [1] = MC_CLIENT_LAST,
145                 },
146         },
147         [TEGRA_POWERGATE_NVJPG] = {
148                 .hot_reset_clients = {
149                         [0] = MC_CLIENT_NVJPG,
150                         [1] = MC_CLIENT_LAST,
151                 },
152         },
153         [TEGRA_POWERGATE_APE] = {
154                 .hot_reset_clients = {
155                         [0] = MC_CLIENT_APE,
156                         [1] = MC_CLIENT_LAST,
157                 },
158         },
159         [TEGRA_POWERGATE_VE2] = {
160                 .hot_reset_clients = {
161                         [0] = MC_CLIENT_ISP2B,
162                         [1] = MC_CLIENT_LAST,
163                 },
164         },
165         [TEGRA_POWERGATE_GPU] = {
166                 .hot_reset_clients = {
167                         [0] = MC_CLIENT_GPU,
168                         [1] = MC_CLIENT_LAST,
169                 },
170         },
171 };
172
173 static struct powergate_partition_info tegra210_pg_partition_info[] = {
174         [TEGRA_POWERGATE_VE] = {
175                 .name = "ve",
176                 .clk_info = {
177                         [0] = { .clk_name = "isp", .clk_type = CLK_ONLY },
178                         [1] = { .clk_name = "vi", .clk_type = CLK_ONLY },
179                         [2] = { .clk_name = "csi", .clk_type = CLK_ONLY },
180                         [3] = { .clk_name = "vii2c", .clk_type = CLK_ONLY },
181                         [4] = { .clk_name = "cilab", .clk_type = CLK_ONLY },
182                         [5] = { .clk_name = "cilcd", .clk_type = CLK_ONLY },
183                         [6] = { .clk_name = "cile", .clk_type = CLK_ONLY },
184                 },
185                 .slcg_info = {
186                         [0] = { .clk_name = "mc_capa" },
187                         [1] = { .clk_name = "mc_cbpa" },
188                         [2] = { .clk_name = "mc_ccpa" },
189                         [3] = { .clk_name = "mc_cdpa" },
190                         [4] = { .clk_name = "host1x" },
191                         [5] = { .clk_name = "vi_slcg_ovr" },
192                         [6] = { .clk_name = "ispa_slcg_ovr" },
193                 },
194                 .reset_id = { TEGRA210_CLK_ISP, TEGRA210_CLK_VI,
195                               TEGRA210_CLK_CSI, TEGRA210_CLK_VI_I2C },
196                 .reset_id_num = 4,
197         },
198 #ifdef CONFIG_ARCH_TEGRA_HAS_PCIE
199         [TEGRA_POWERGATE_PCIE] = {
200                 .name = "pcie",
201                 .clk_info = {
202                         [0] = { .clk_name = "afi", .clk_type = CLK_ONLY },
203                         [1] = { .clk_name = "pcie", .clk_type = CLK_ONLY },
204                 },
205                 .reset_id = { TEGRA210_CLK_AFI, TEGRA210_CLK_PCIE,
206                               TEGRA210_CLK_PCIEX },
207                 .reset_id_num = 3,
208                 .skip_reset = true,
209         },
210 #endif
211 #ifdef CONFIG_ARCH_TEGRA_HAS_SATA
212         [TEGRA_POWERGATE_SATA] = {
213                 .name = "sata",
214                 .disable_after_boot = false,
215                 .clk_info = {
216                         [0] = { .clk_name = "sata_oob", .clk_type = CLK_ONLY },
217                         [1] = { .clk_name = "cml1", .clk_type = CLK_ONLY },
218                         [3] = { .clk_name = "sata_aux", .clk_type = CLK_ONLY },
219                         [4] = { .clk_name = "sata", .clk_type = CLK_ONLY },
220                 },
221                 .slcg_info = {
222                         [0] = { .clk_name = "mc_capa" },
223                         [1] = { .clk_name = "mc_cbpa" },
224                         [2] = { .clk_name = "mc_ccpa" },
225                         [3] = { .clk_name = "mc_cdpa" },
226                         [4] = { .clk_name = "sata_slcg_fpci" },
227                         [5] = { .clk_name = "sata_slcg_ipfs" },
228                         [6] = { .clk_name = "sata_slcg_ovr" },
229                 },
230                 .reset_id = { TEGRA210_CLK_SATA_OOB, TEGRA210_CLK_SATA_COLD,
231                               TEGRA210_CLK_SATA },
232                 .reset_id_num = 3,
233         },
234 #endif
235         [TEGRA_POWERGATE_NVENC] = {
236                 .name = "nvenc",
237                 .clk_info = {
238                         [0] = { .clk_name = "nvenc.cbus", .clk_type = CLK_ONLY },
239                 },
240                 .slcg_info = {
241                         [0] = { .clk_name = "mc_capa" },
242                         [1] = { .clk_name = "mc_cbpa" },
243                         [2] = { .clk_name = "mc_ccpa" },
244                         [3] = { .clk_name = "mc_cdpa" },
245                         [4] = { .clk_name = "nvenc_slcg_ovr" },
246                 },
247                 .reset_id = { TEGRA210_CLK_NVENC },
248                 .reset_id_num = 1,
249         },
250         [TEGRA_POWERGATE_SOR] = {
251                 .name = "sor",
252                 .clk_info = {
253                         [0] = { .clk_name = "sor0", .clk_type = CLK_ONLY },
254                         [1] = { .clk_name = "dsia", .clk_type = CLK_ONLY },
255                         [2] = { .clk_name = "dsib", .clk_type = CLK_ONLY },
256                         [3] = { .clk_name = "sor1", .clk_type = CLK_ONLY },
257                         [4] = { .clk_name = "mipi-cal", .clk_type = CLK_ONLY },
258                         [5] = { .clk_name = "dpaux", .clk_type = CLK_ONLY },
259                         [6] = { .clk_name = "dpaux1", .clk_type = CLK_ONLY },
260                 },
261                 .slcg_info = {
262                         [0] = { .clk_name = "mc_capa" },
263                         [1] = { .clk_name = "mc_cbpa" },
264                         [2] = { .clk_name = "mc_ccpa" },
265                         [3] = { .clk_name = "mc_cdpa" },
266                         [4] = { .clk_name = "hda2hdmi" },
267                         [5] = { .clk_name = "hda2codec_2x" },
268                         [6] = { .clk_name = "disp1" },
269                         [7] = { .clk_name = "disp2" },
270                         [8] = { .clk_name = "disp1_slcg_ovr" },
271                         [9] = { .clk_name = "disp2_slcg_ovr" },
272                 },
273                 .reset_id = { TEGRA210_CLK_SOR0, TEGRA210_CLK_DISP1,
274                               TEGRA210_CLK_DSIB, TEGRA210_CLK_SOR1,
275                               TEGRA210_CLK_MIPI_CAL },
276                 .reset_id_num = 5,
277         },
278         [TEGRA_POWERGATE_DISA] = {
279                 .name = "disa",
280                 .clk_info = {
281                         [0] = { .clk_name = "disp1", .clk_type = CLK_ONLY },
282                 },
283                 .slcg_info = {
284                         [0] = { .clk_name = "mc_capa" },
285                         [1] = { .clk_name = "mc_cbpa" },
286                         [2] = { .clk_name = "mc_ccpa" },
287                         [3] = { .clk_name = "mc_cdpa" },
288                         [4] = { .clk_name = "la" },
289                         [5] = { .clk_name = "host1x" },
290                         [6] = { .clk_name = "disp1_slcg_ovr" },
291                 },
292                 .reset_id = { TEGRA210_CLK_DISP1 },
293                 .reset_id_num = 1,
294         },
295         [TEGRA_POWERGATE_DISB] = {
296                 .name = "disb",
297                 .disable_after_boot = true,
298                 .clk_info = {
299                         [0] = { .clk_name = "disp2", .clk_type = CLK_ONLY },
300                 },
301                 .slcg_info = {
302                         [0] = { .clk_name = "mc_capa" },
303                         [1] = { .clk_name = "mc_cbpa" },
304                         [2] = { .clk_name = "mc_ccpa" },
305                         [3] = { .clk_name = "mc_cdpa" },
306                         [4] = { .clk_name = "la" },
307                         [5] = { .clk_name = "host1x" },
308                         [6] = { .clk_name = "disp2_slcg_ovr" },
309                 },
310                 .reset_id = { TEGRA210_CLK_DISP2 },
311                 .reset_id_num = 1,
312         },
313         [TEGRA_POWERGATE_XUSBA] = {
314                 .name = "xusba",
315                 .clk_info = {
316                         [0] = { .clk_name = "xusb_ss", .clk_type = CLK_ONLY },
317                         [1] = { .clk_name = "xusb_ssp_src", .clk_type = CLK_ONLY },
318                         [2] = { .clk_name = "xusb_hs_src", .clk_type = CLK_ONLY },
319                         [3] = { .clk_name = "xusb_fs_src", .clk_type = CLK_ONLY },
320                         [4] = { .clk_name = "xusb_dev_src", .clk_type = CLK_ONLY },
321                 },
322                 .slcg_info = {
323                         [0] = { .clk_name = "mc_capa" },
324                         [1] = { .clk_name = "mc_cbpa" },
325                         [2] = { .clk_name = "mc_ccpa" },
326                         [3] = { .clk_name = "mc_cdpa" },
327                         [4] = { .clk_name = "xusb_host" },
328                         [5] = { .clk_name = "xusb_dev" },
329                         [6] = { .clk_name = "xusb_host_slcg" },
330                         [7] = { .clk_name = "xusb_dev_slcg" },
331                 },
332                 .reset_id = { TEGRA210_CLK_XUSB_SS },
333                 .reset_id_num = 1,
334         },
335         [TEGRA_POWERGATE_XUSBB] = {
336                 .name = "xusbb",
337                 .clk_info = {
338                         [0] = { .clk_name = "xusb_dev", .clk_type = CLK_ONLY },
339                 },
340                 .slcg_info = {
341                         [0] = { .clk_name = "mc_capa" },
342                         [1] = { .clk_name = "mc_cbpa" },
343                         [2] = { .clk_name = "mc_ccpa" },
344                         [3] = { .clk_name = "mc_cdpa" },
345                         [4] = { .clk_name = "xusb_ss" },
346                         [5] = { .clk_name = "xusb_host" },
347                         [6] = { .clk_name = "xusb_host_slcg" },
348                         [7] = { .clk_name = "xusb_dev_slcg" },
349                 },
350                 .reset_id = { 95 },
351                 .reset_id_num = 1,
352         },
353         [TEGRA_POWERGATE_XUSBC] = {
354                 .name = "xusbc",
355                 .clk_info = {
356                         [0] = { .clk_name = "xusb_host", .clk_type = CLK_ONLY },
357                 },
358                 .slcg_info = {
359                         [0] = { .clk_name = "mc_capa" },
360                         [1] = { .clk_name = "mc_cbpa" },
361                         [2] = { .clk_name = "mc_ccpa" },
362                         [3] = { .clk_name = "mc_cdpa" },
363                         [4] = { .clk_name = "xusb_ss" },
364                         [5] = { .clk_name = "xusb_dev" },
365                         [6] = { .clk_name = "xusb_dev_slcg" },
366                         [7] = { .clk_name = "xusb_host_slcg" },
367                 },
368                 .reset_id = { TEGRA210_CLK_XUSB_HOST },
369                 .reset_id_num = 1,
370         },
371 #ifdef CONFIG_ARCH_TEGRA_VIC
372         [TEGRA_POWERGATE_VIC] = {
373                 .name = "vic",
374                 .clk_info = {
375                         [0] = { .clk_name = "vic03.cbus", .clk_type = CLK_ONLY },
376                 },
377                 .slcg_info = {
378                         [0] = { .clk_name = "mc_capa" },
379                         [1] = { .clk_name = "mc_cbpa" },
380                         [2] = { .clk_name = "mc_ccpa" },
381                         [3] = { .clk_name = "mc_cdpa" },
382                         [4] = { .clk_name = "vic03_slcg_ovr" },
383                         [5] = { .clk_name = "host1x" },
384                 },
385                 .reset_id = { TEGRA210_CLK_VIC03 },
386                 .reset_id_num = 1,
387         },
388 #endif
389         [TEGRA_POWERGATE_NVDEC] = {
390                 .name = "nvdec",
391                 .clk_info = {
392                         [0] = { .clk_name = "nvdec", .clk_type = CLK_ONLY },
393                 },
394                 .slcg_info = {
395                         [0] = { .clk_name = "mc_capa" },
396                         [1] = { .clk_name = "mc_cbpa" },
397                         [2] = { .clk_name = "mc_ccpa" },
398                         [3] = { .clk_name = "mc_cdpa" },
399                         [4] = { .clk_name = "nvdec_slcg_ovr" },
400                         [5] = { .clk_name = "nvjpg" },
401                         [6] = { .clk_name = "nvjpg_slcg_ovr" },
402                 },
403                 .reset_id = { TEGRA210_CLK_NVDEC },
404                 .reset_id_num = 1,
405         },
406         [TEGRA_POWERGATE_NVJPG] = {
407                 .name = "nvjpg",
408                 .clk_info = {
409                         [0] = { .clk_name = "nvjpg", .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 = "nvjpg_slcg_ovr" },
417                         [5] = { .clk_name = "nvdec" },
418                         [6] = { .clk_name = "nvdec_slcg_ovr" },
419                 },
420                 .reset_id = { TEGRA210_CLK_NVJPG },
421                 .reset_id_num = 1,
422         },
423         [TEGRA_POWERGATE_APE] = {
424                 .name = "ape",
425                 .clk_info = {
426                         [0] = { .clk_name = "ape", .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 = "aclk" },
434                         [5] = { .clk_name = "i2s0" },
435                         [6] = { .clk_name = "i2s1" },
436                         [7] = { .clk_name = "i2s2" },
437                         [8] = { .clk_name = "i2s3" },
438                         [9] = { .clk_name = "i2s4" },
439                         [10] = { .clk_name = "spdif_out" },
440                         [11] = { .clk_name = "d_audio" },
441                         [12] = { .clk_name = "ape_slcg_ovr" },
442                         [13] = { .clk_name = "aclk_slcg_ovr" },
443                         [14] = { .clk_name = "daudio_slcg_ovr" },
444
445                 },
446                 .reset_id = { TEGRA210_CLK_APE },
447                 .reset_id_num = 1,
448         },
449         [TEGRA_POWERGATE_VE2] = {
450                 .name = "ve2",
451                 .clk_info = {
452                         [0] = { .clk_name = "ispb", .clk_type = CLK_ONLY },
453                 },
454                 .slcg_info = {
455                         [0] = { .clk_name = "mc_capa" },
456                         [1] = { .clk_name = "mc_cbpa" },
457                         [2] = { .clk_name = "mc_ccpa" },
458                         [3] = { .clk_name = "mc_cdpa" },
459                         [4] = { .clk_name = "ispb_slcg_ovr" },
460                 },
461                 .reset_id = { TEGRA210_CLK_ISPB },
462                 .reset_id_num = 1,
463         },
464         [TEGRA_POWERGATE_GPU] = {
465                 .name = "gpu",
466                 .clk_info = {
467                         [0] = { .clk_name = "gpu_gate", .clk_type = CLK_AND_RST },
468                         [1] = { .clk_name = "gpu_ref", .clk_type = CLK_ONLY },
469                         [2] = { .clk_name = "pll_p_out5", .clk_type = CLK_ONLY },
470                 },
471         },
472 };
473
474 struct mc_client_hotreset_reg {
475         u32 control_reg;
476         u32 status_reg;
477 };
478
479 static struct mc_client_hotreset_reg tegra210_mc_reg[] = {
480         [0] = { .control_reg = 0x200, .status_reg = 0x204 },
481         [1] = { .control_reg = 0x970, .status_reg = 0x974 },
482 };
483
484 #define PMC_GPU_RG_CONTROL              0x2d4
485
486 static DEFINE_SPINLOCK(tegra210_pg_lock);
487
488 static struct dvfs_rail *gpu_rail;
489
490 #define HOTRESET_READ_COUNTS            5
491
492 static bool tegra210_pg_hotreset_check(u32 status_reg, u32 *status)
493 {
494         int i;
495         u32 curr_status;
496         u32 prev_status;
497         unsigned long flags;
498
499         spin_lock_irqsave(&tegra210_pg_lock, flags);
500         prev_status = mc_read(status_reg);
501         for (i = 0; i < HOTRESET_READ_COUNTS; i++) {
502                 curr_status = mc_read(status_reg);
503                 if (curr_status != prev_status) {
504                         spin_unlock_irqrestore(&tegra210_pg_lock, flags);
505                         return false;
506                 }
507         }
508         *status = curr_status;
509         spin_unlock_irqrestore(&tegra210_pg_lock, flags);
510
511         return true;
512 }
513
514 static int tegra210_pg_mc_flush(int id)
515 {
516         u32 idx, rst_control, rst_status;
517         u32 rst_control_reg, rst_status_reg;
518         enum mc_client mc_client_bit;
519         unsigned long flags;
520         unsigned int timeout;
521         bool ret;
522         int reg_idx;
523
524         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
525                 mc_client_bit = tegra210_pg_mc_info[id].hot_reset_clients[idx];
526                 if (mc_client_bit == MC_CLIENT_LAST)
527                         break;
528
529                 reg_idx = mc_client_bit / 32;
530                 mc_client_bit %= 32;
531                 rst_control_reg = tegra210_mc_reg[reg_idx].control_reg;
532                 rst_status_reg = tegra210_mc_reg[reg_idx].status_reg;
533
534                 spin_lock_irqsave(&tegra210_pg_lock, flags);
535                 rst_control = mc_read(rst_control_reg);
536                 rst_control |= (1 << mc_client_bit);
537                 mc_write(rst_control, rst_control_reg);
538                 spin_unlock_irqrestore(&tegra210_pg_lock, flags);
539
540                 timeout = 0;
541                 do {
542                         udelay(10);
543                         rst_status = 0;
544                         ret = tegra210_pg_hotreset_check(rst_status_reg,
545                                                                 &rst_status);
546                         if ((timeout++ > EMULATION_MC_FLUSH_TIMEOUT) &&
547                                 (tegra_platform_is_qt() ||
548                                 tegra_platform_is_fpga())) {
549                                 pr_warn("%s flush %d timeout\n", __func__, id);
550                                 break;
551                         }
552                         if (!ret)
553                                 continue;
554                 } while (!(rst_status & (1 << mc_client_bit)));
555         }
556
557         return 0;
558 }
559
560 static int tegra210_pg_mc_flush_done(int id)
561 {
562         u32 idx, rst_control, rst_control_reg;
563         enum mc_client mc_client_bit;
564         unsigned long flags;
565         int reg_idx;
566
567         for (idx = 0; idx < MAX_HOTRESET_CLIENT_NUM; idx++) {
568                 mc_client_bit = tegra210_pg_mc_info[id].hot_reset_clients[idx];
569                 if (mc_client_bit == MC_CLIENT_LAST)
570                         break;
571
572                 reg_idx = mc_client_bit / 32;
573                 mc_client_bit %= 32;
574                 rst_control_reg = tegra210_mc_reg[reg_idx].control_reg;
575
576                 spin_lock_irqsave(&tegra210_pg_lock, flags);
577                 rst_control = mc_read(rst_control_reg);
578                 rst_control &= ~(1 << mc_client_bit);
579                 mc_write(rst_control, rst_control_reg);
580                 spin_unlock_irqrestore(&tegra210_pg_lock, flags);
581
582         }
583         wmb();
584
585         return 0;
586 }
587
588 static const char *tegra210_pg_get_name(int id)
589 {
590         return tegra210_pg_partition_info[id].name;
591 }
592
593 static int tegra210_pg_powergate(int id)
594 {
595         struct powergate_partition_info *partition =
596                                 &tegra210_pg_partition_info[id];
597         int ret = 0;
598
599         trace_powergate(__func__, tegra210_pg_get_name(id), id, 1, 0);
600         mutex_lock(&partition->pg_mutex);
601
602         if (--partition->refcount > 0)
603                 goto exit_unlock;
604
605         if ((partition->refcount < 0) || !tegra_powergate_is_powered(id)) {
606                 WARN(1, "Partition %s already powergated, refcount and status mismatch\n",
607                      partition->name);
608                 goto exit_unlock;
609         }
610
611         ret = tegra1xx_powergate(id, partition);
612
613 exit_unlock:
614         mutex_unlock(&partition->pg_mutex);
615         trace_powergate(__func__, tegra210_pg_get_name(id), id, 0, ret);
616         return ret;
617 }
618
619 static int tegra210_pg_unpowergate(int id)
620 {
621         struct powergate_partition_info *partition =
622                                 &tegra210_pg_partition_info[id];
623         int ret = 0;
624
625         trace_powergate(__func__, tegra210_pg_get_name(id), id, 1, 0);
626         mutex_lock(&partition->pg_mutex);
627
628         if (partition->refcount++ > 0)
629                 goto exit_unlock;
630
631         if (tegra_powergate_is_powered(id)) {
632                 WARN(1, "Partition %s is already unpowergated, refcount and status mismatch\n",
633                      partition->name);
634                 goto exit_unlock;
635         }
636
637         ret = tegra1xx_unpowergate(id, partition);
638
639 exit_unlock:
640         mutex_unlock(&partition->pg_mutex);
641         trace_powergate(__func__, tegra210_pg_get_name(id), id, 0, ret);
642         return ret;
643 }
644
645 static int tegra210_pg_gpu_powergate(int id)
646 {
647         int ret = 0;
648         struct powergate_partition_info *partition =
649                                 &tegra210_pg_partition_info[id];
650
651         trace_powergate(__func__, tegra210_pg_get_name(id), id, 1, 0);
652         mutex_lock(&partition->pg_mutex);
653
654         if (--partition->refcount > 0)
655                 goto exit_unlock;
656
657         if (!tegra_powergate_is_powered(id)) {
658                 WARN(1, "GPU rail is already off, refcount and status mismatch\n");
659                 goto exit_unlock;
660         }
661
662         if (!partition->clk_info[0].clk_ptr)
663                 get_clk_info(partition);
664
665         tegra_powergate_mc_flush(id);
666
667         udelay(10);
668
669         powergate_partition_assert_reset(partition);
670
671         udelay(10);
672
673         pmc_write(0x1, PMC_GPU_RG_CONTROL);
674         pmc_read(PMC_GPU_RG_CONTROL);
675
676         udelay(10);
677
678         partition_clk_disable(partition);
679
680         udelay(10);
681
682         tegra_soctherm_gpu_tsens_invalidate(1);
683
684         if (gpu_rail) {
685                 ret = tegra_dvfs_rail_power_down(gpu_rail);
686                 if (ret) {
687                         WARN(1, "Could not power down GPU rail\n");
688                         goto exit_unlock;
689                 }
690         } else {
691                 pr_info("No GPU regulator?\n");
692         }
693
694 exit_unlock:
695         mutex_unlock(&partition->pg_mutex);
696         trace_powergate(__func__, tegra210_pg_get_name(id), id, 0, ret);
697         return ret;
698 }
699
700 static int tegra210_pg_gpu_unpowergate(int id)
701 {
702         int ret = 0;
703         bool first = false;
704         struct powergate_partition_info *partition =
705                                 &tegra210_pg_partition_info[id];
706
707         trace_powergate(__func__, tegra210_pg_get_name(id), id, 1, 0);
708         mutex_lock(&partition->pg_mutex);
709
710         if (partition->refcount++ > 0)
711                 goto exit_unlock;
712
713         if (!gpu_rail) {
714                 gpu_rail = tegra_dvfs_get_rail_by_name("vdd_gpu");
715                 if (IS_ERR_OR_NULL(gpu_rail)) {
716                         WARN(1, "No GPU regulator?\n");
717                         goto err_power;
718                 }
719                 first = true;
720         }
721
722         if (tegra_powergate_is_powered(id)) {
723                 WARN(1, "GPU rail is already on, refcount and status mismatch\n");
724                 goto exit_unlock;
725         }
726
727         ret = tegra_dvfs_rail_power_up(gpu_rail);
728         if (ret) {
729                 WARN(1, "Could not turn on GPU rail\n");
730                 goto err_power;
731         }
732
733         tegra_soctherm_gpu_tsens_invalidate(0);
734
735         if (!partition->clk_info[0].clk_ptr)
736                 get_clk_info(partition);
737
738         if (!first) {
739                 ret = partition_clk_enable(partition);
740                 if (ret) {
741                         WARN(1, "Could not turn on partition clocks\n");
742                         goto err_clk_on;
743                 }
744         }
745
746         udelay(10);
747
748         powergate_partition_assert_reset(partition);
749
750         udelay(10);
751
752         pmc_write(0, PMC_GPU_RG_CONTROL);
753         pmc_read(PMC_GPU_RG_CONTROL);
754
755         udelay(10);
756
757         /*
758          * Make sure all clok branches into GPU, except reference clock are
759          * gated across resert de-assertion.
760          */
761         clk_disable_unprepare(partition->clk_info[0].clk_ptr);
762         powergate_partition_deassert_reset(partition);
763         clk_prepare_enable(partition->clk_info[0].clk_ptr);
764
765         /* Flush MC after boot/railgate/SC7 */
766         tegra_powergate_mc_flush(id);
767
768         udelay(10);
769
770         tegra_powergate_mc_flush_done(id);
771
772         udelay(10);
773
774 exit_unlock:
775         mutex_unlock(&partition->pg_mutex);
776         trace_powergate(__func__, tegra210_pg_get_name(id), id, 0, ret);
777         return ret;
778
779 err_clk_on:
780         powergate_module(id);
781 err_power:
782         mutex_unlock(&partition->pg_mutex);
783
784         trace_powergate(__func__, tegra210_pg_get_name(id), id, 0, ret);
785         return ret;
786 }
787
788 static int tegra210_pg_powergate_sor(int id)
789 {
790         int ret;
791
792         ret = tegra210_pg_powergate(id);
793         if (ret)
794                 return ret;
795
796         ret = tegra_powergate_partition(TEGRA_POWERGATE_SOR);
797         if (ret)
798                 return ret;
799
800         return 0;
801 }
802
803 static int tegra210_pg_unpowergate_sor(int id)
804 {
805         int ret;
806
807         ret = tegra_unpowergate_partition(TEGRA_POWERGATE_SOR);
808         if (ret)
809                 return ret;
810
811         ret = tegra210_pg_unpowergate(id);
812         if (ret) {
813                 tegra_powergate_partition(TEGRA_POWERGATE_SOR);
814                 return ret;
815         }
816
817         return 0;
818 }
819
820 static int tegra210_pg_nvdec_powergate(int id)
821 {
822         tegra210_pg_powergate(TEGRA_POWERGATE_NVDEC);
823         tegra_powergate_partition(TEGRA_POWERGATE_NVJPG);
824
825         return 0;
826 }
827
828 static int tegra210_pg_nvdec_unpowergate(int id)
829 {
830         tegra_unpowergate_partition(TEGRA_POWERGATE_NVJPG);
831         tegra210_pg_unpowergate(TEGRA_POWERGATE_NVDEC);
832
833         return 0;
834 }
835
836 static int tegra210_pg_sata_powergate(int id)
837 {
838         tegra210_set_sata_pll_seq_sw(true);
839         tegra210_pg_powergate(TEGRA_POWERGATE_SATA);
840
841         return 0;
842 }
843
844 static int tegra210_pg_sata_unpowergate(int id)
845 {
846         tegra210_pg_unpowergate(TEGRA_POWERGATE_SATA);
847         tegra210_set_sata_pll_seq_sw(false);
848
849         return 0;
850 }
851
852 static int tegra210_pg_powergate_partition(int id)
853 {
854         int ret;
855
856         switch (id) {
857                 case TEGRA_POWERGATE_GPU:
858                         ret = tegra210_pg_gpu_powergate(id);
859                         break;
860                 case TEGRA_POWERGATE_DISA:
861                 case TEGRA_POWERGATE_DISB:
862                 case TEGRA_POWERGATE_VE:
863                         ret = tegra210_pg_powergate_sor(id);
864                         break;
865                 case TEGRA_POWERGATE_NVDEC:
866                         ret = tegra210_pg_nvdec_powergate(id);
867                         break;
868                 case TEGRA_POWERGATE_SATA:
869                         ret = tegra210_pg_sata_powergate(id);
870                         break;
871                 default:
872                         ret = tegra210_pg_powergate(id);
873         }
874
875         return ret;
876 }
877
878 static int tegra210_pg_unpowergate_partition(int id)
879 {
880         int ret;
881
882         switch (id) {
883                 case TEGRA_POWERGATE_GPU:
884                         ret = tegra210_pg_gpu_unpowergate(id);
885                         break;
886                 case TEGRA_POWERGATE_DISA:
887                 case TEGRA_POWERGATE_DISB:
888                 case TEGRA_POWERGATE_VE:
889                         ret = tegra210_pg_unpowergate_sor(id);
890                         break;
891                 case TEGRA_POWERGATE_NVDEC:
892                         ret = tegra210_pg_nvdec_unpowergate(id);
893                         break;
894                 case TEGRA_POWERGATE_SATA:
895                         ret = tegra210_pg_sata_unpowergate(id);
896                         break;
897                 default:
898                         ret = tegra210_pg_unpowergate(id);
899         }
900
901         return ret;
902 }
903
904 static int tegra210_pg_powergate_clk_off(int id)
905 {
906         int ret = 0;
907         struct powergate_partition_info *partition =
908                                 &tegra210_pg_partition_info[id];
909
910         BUG_ON(TEGRA_IS_GPU_POWERGATE_ID(id));
911
912         trace_powergate(__func__, tegra210_pg_get_name(id), id, 1, 0);
913         mutex_lock(&partition->pg_mutex);
914
915         if (--partition->refcount > 0)
916                 goto exit_unlock;
917
918         if ((partition->refcount < 0) || !tegra_powergate_is_powered(id)) {
919                 WARN(1, "Partition %s already powergated, refcount and status mismatch\n",
920                      partition->name);
921                 goto exit_unlock;
922         }
923
924         if (id == TEGRA_POWERGATE_SATA)
925                 tegra210_set_sata_pll_seq_sw(true);
926
927         ret = tegra1xx_powergate_partition_with_clk_off(id,
928                         &tegra210_pg_partition_info[id]);
929
930 exit_unlock:
931         mutex_unlock(&partition->pg_mutex);
932         trace_powergate(__func__, tegra210_pg_get_name(id), id, 0, ret);
933
934         return ret;
935 }
936
937 static int tegra210_pg_unpowergate_clk_on(int id)
938 {
939         int ret = 0;
940         struct powergate_partition_info *partition =
941                                 &tegra210_pg_partition_info[id];
942
943         BUG_ON(TEGRA_IS_GPU_POWERGATE_ID(id));
944         trace_powergate(__func__, tegra210_pg_get_name(id), id, 1, 0);
945         mutex_lock(&partition->pg_mutex);
946
947         if (partition->refcount++ > 0)
948                 goto exit_unlock;
949
950         ret = tegra1xx_unpowergate_partition_with_clk_on(id,
951                         &tegra210_pg_partition_info[id]);
952
953         if (id == TEGRA_POWERGATE_SATA)
954                 tegra210_set_sata_pll_seq_sw(false);
955
956 exit_unlock:
957         mutex_unlock(&partition->pg_mutex);
958         trace_powergate(__func__, tegra210_pg_get_name(id), id, 0, ret);
959
960         return ret;
961 }
962
963 static spinlock_t *tegra210_pg_get_lock(void)
964 {
965         return &tegra210_pg_lock;
966 }
967
968 static bool tegra210_pg_skip(int id)
969 {
970         switch (id) {
971         case TEGRA_POWERGATE_GPU:
972                 return true;
973         default:
974                 return false;
975         }
976 }
977
978 static bool tegra210_pg_is_powered(int id)
979 {
980         u32 status = 0;
981
982         if (TEGRA_IS_GPU_POWERGATE_ID(id)) {
983                 if (gpu_rail)
984                         status = tegra_dvfs_is_rail_up(gpu_rail);
985         } else {
986                 status = pmc_read(PWRGATE_STATUS) & (1 << id);
987         }
988
989         return !!status;
990 }
991
992 static int tegra210_pg_init_refcount(void)
993 {
994         int i;
995
996         for (i = 0; i < TEGRA_NUM_POWERGATE; i++) {
997                 if (tegra_powergate_is_powered(i))
998                         tegra210_pg_partition_info[i].refcount = 1;
999                 else
1000                         tegra210_pg_partition_info[i].disable_after_boot = 0;
1001
1002                 mutex_init(&tegra210_pg_partition_info[i].pg_mutex);
1003         }
1004
1005         /* SOR refcount depends on other units */
1006         tegra210_pg_partition_info[TEGRA_POWERGATE_SOR].refcount =
1007                 (tegra_powergate_is_powered(TEGRA_POWERGATE_DISA) ? 1 : 0) +
1008                 (tegra_powergate_is_powered(TEGRA_POWERGATE_DISB) ? 1 : 0) +
1009                 (tegra_powergate_is_powered(TEGRA_POWERGATE_VE) ? 1 : 0);
1010
1011         tegra_powergate_partition(TEGRA_POWERGATE_XUSBA);
1012         tegra_powergate_partition(TEGRA_POWERGATE_XUSBB);
1013         tegra_powergate_partition(TEGRA_POWERGATE_XUSBC);
1014
1015         return 0;
1016 }
1017
1018 static struct powergate_ops tegra210_pg_ops = {
1019         .soc_name = "tegra210",
1020
1021         .num_powerdomains = TEGRA_NUM_POWERGATE,
1022
1023         .get_powergate_lock = tegra210_pg_get_lock,
1024         .get_powergate_domain_name = tegra210_pg_get_name,
1025
1026         .powergate_partition = tegra210_pg_powergate_partition,
1027         .unpowergate_partition = tegra210_pg_unpowergate_partition,
1028
1029         .powergate_partition_with_clk_off = tegra210_pg_powergate_clk_off,
1030         .unpowergate_partition_with_clk_on = tegra210_pg_unpowergate_clk_on,
1031
1032         .powergate_mc_flush = tegra210_pg_mc_flush,
1033         .powergate_mc_flush_done = tegra210_pg_mc_flush_done,
1034
1035         .powergate_skip = tegra210_pg_skip,
1036
1037         .powergate_is_powered = tegra210_pg_is_powered,
1038
1039         .powergate_init_refcount = tegra210_pg_init_refcount,
1040 };
1041
1042 struct powergate_ops *tegra210_powergate_init_chip_support(void)
1043 {
1044         if (tegra_platform_is_linsim())
1045                 return NULL;
1046
1047         return &tegra210_pg_ops;
1048 }
1049
1050 int slcg_register_notifier(int id, struct notifier_block *nb)
1051 {
1052         struct powergate_partition_info *pg_info = &tegra210_pg_partition_info[id];
1053
1054         if (!pg_info || !nb)
1055                 return -EINVAL;
1056
1057         return raw_notifier_chain_register(&pg_info->slcg_notifier, nb);
1058 }
1059 EXPORT_SYMBOL(slcg_register_notifier);
1060
1061 int slcg_unregister_notifier(int id, struct notifier_block *nb)
1062 {
1063         struct powergate_partition_info *pg_info =
1064                         &tegra210_pg_partition_info[id];
1065
1066         if (!pg_info || !nb)
1067                 return -EINVAL;
1068
1069         return raw_notifier_chain_unregister(&pg_info->slcg_notifier, nb);
1070 }
1071 EXPORT_SYMBOL(slcg_unregister_notifier);
1072
1073 static int __init tegra210_disable_boot_partitions(void)
1074 {
1075         int i;
1076
1077         pr_info("Disable partitions left on by BL\n");
1078         for (i = 0; i < TEGRA_NUM_POWERGATE; i++)
1079                 if (tegra210_pg_partition_info[i].disable_after_boot &&
1080                         (i != TEGRA_POWERGATE_GPU)) {
1081                         pr_info("    %s\n", tegra210_pg_partition_info[i].name);
1082                         tegra_powergate_partition(i);
1083                 }
1084
1085         return 0;
1086 }
1087 late_initcall(tegra210_disable_boot_partitions);