Skip to content

Commit a4d86e5

Browse files
committed
Merge tag 'tegra-for-3.14-powergate' into drm/for-next
ARM: tegra: powergate driver changes This branch includes all the changes to Tegra's powergate driver for 3.14. These are separate out, since the Tegra DRM changes for 3.14 rely on the new APIs introduced here. A few cleanups and fixes are included, plus additions of Tegra124 SoC support, and a new API for manipulating Tegra's IO rail deep power down states. This branch is based on tag tegra-for-3.14-dmas-resets-rework, in order to avoid conflicts with the addition of common reset controller support to the powergate driver.
2 parents b03bb79 + 9d4450a commit a4d86e5

File tree

2 files changed

+240
-3
lines changed

2 files changed

+240
-3
lines changed

arch/arm/mach-tegra/powergate.c

Lines changed: 192 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,30 @@
3434
#include "fuse.h"
3535
#include "iomap.h"
3636

37+
#define DPD_SAMPLE 0x020
38+
#define DPD_SAMPLE_ENABLE (1 << 0)
39+
#define DPD_SAMPLE_DISABLE (0 << 0)
40+
3741
#define PWRGATE_TOGGLE 0x30
3842
#define PWRGATE_TOGGLE_START (1 << 8)
3943

4044
#define REMOVE_CLAMPING 0x34
4145

4246
#define PWRGATE_STATUS 0x38
4347

48+
#define IO_DPD_REQ 0x1b8
49+
#define IO_DPD_REQ_CODE_IDLE (0 << 30)
50+
#define IO_DPD_REQ_CODE_OFF (1 << 30)
51+
#define IO_DPD_REQ_CODE_ON (2 << 30)
52+
#define IO_DPD_REQ_CODE_MASK (3 << 30)
53+
54+
#define IO_DPD_STATUS 0x1bc
55+
#define IO_DPD2_REQ 0x1c0
56+
#define IO_DPD2_STATUS 0x1c4
57+
#define SEL_DPD_TIM 0x1c8
58+
59+
#define GPU_RG_CNTRL 0x2d4
60+
4461
static int tegra_num_powerdomains;
4562
static int tegra_num_cpu_domains;
4663
static const u8 *tegra_cpu_domains;
@@ -59,6 +76,13 @@ static const u8 tegra114_cpu_domains[] = {
5976
TEGRA_POWERGATE_CPU3,
6077
};
6178

79+
static const u8 tegra124_cpu_domains[] = {
80+
TEGRA_POWERGATE_CPU0,
81+
TEGRA_POWERGATE_CPU1,
82+
TEGRA_POWERGATE_CPU2,
83+
TEGRA_POWERGATE_CPU3,
84+
};
85+
6286
static DEFINE_SPINLOCK(tegra_powergate_lock);
6387

6488
static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
@@ -109,6 +133,7 @@ int tegra_powergate_power_off(int id)
109133

110134
return tegra_powergate_set(id, false);
111135
}
136+
EXPORT_SYMBOL(tegra_powergate_power_off);
112137

113138
int tegra_powergate_is_powered(int id)
114139
{
@@ -128,13 +153,24 @@ int tegra_powergate_remove_clamping(int id)
128153
if (id < 0 || id >= tegra_num_powerdomains)
129154
return -EINVAL;
130155

156+
/*
157+
* The Tegra124 GPU has a separate register (with different semantics)
158+
* to remove clamps.
159+
*/
160+
if (tegra_chip_id == TEGRA124) {
161+
if (id == TEGRA_POWERGATE_3D) {
162+
pmc_write(0, GPU_RG_CNTRL);
163+
return 0;
164+
}
165+
}
166+
131167
/*
132168
* Tegra 2 has a bug where PCIE and VDE clamping masks are
133169
* swapped relatively to the partition ids
134170
*/
135-
if (id == TEGRA_POWERGATE_VDEC)
171+
if (id == TEGRA_POWERGATE_VDEC)
136172
mask = (1 << TEGRA_POWERGATE_PCIE);
137-
else if (id == TEGRA_POWERGATE_PCIE)
173+
else if (id == TEGRA_POWERGATE_PCIE)
138174
mask = (1 << TEGRA_POWERGATE_VDEC);
139175
else
140176
mask = (1 << id);
@@ -143,6 +179,7 @@ int tegra_powergate_remove_clamping(int id)
143179

144180
return 0;
145181
}
182+
EXPORT_SYMBOL(tegra_powergate_remove_clamping);
146183

147184
/* Must be called with clk disabled, and returns with clk enabled */
148185
int tegra_powergate_sequence_power_up(int id, struct clk *clk,
@@ -204,6 +241,11 @@ int __init tegra_powergate_init(void)
204241
tegra_num_cpu_domains = 4;
205242
tegra_cpu_domains = tegra114_cpu_domains;
206243
break;
244+
case TEGRA124:
245+
tegra_num_powerdomains = 25;
246+
tegra_num_cpu_domains = 4;
247+
tegra_cpu_domains = tegra124_cpu_domains;
248+
break;
207249
default:
208250
/* Unknown Tegra variant. Disable powergating */
209251
tegra_num_powerdomains = 0;
@@ -245,24 +287,51 @@ static const char * const powergate_name_t30[] = {
245287
};
246288

247289
static const char * const powergate_name_t114[] = {
248-
[TEGRA_POWERGATE_CPU] = "cpu0",
290+
[TEGRA_POWERGATE_CPU] = "crail",
291+
[TEGRA_POWERGATE_3D] = "3d",
292+
[TEGRA_POWERGATE_VENC] = "venc",
293+
[TEGRA_POWERGATE_VDEC] = "vdec",
294+
[TEGRA_POWERGATE_MPE] = "mpe",
295+
[TEGRA_POWERGATE_HEG] = "heg",
296+
[TEGRA_POWERGATE_CPU1] = "cpu1",
297+
[TEGRA_POWERGATE_CPU2] = "cpu2",
298+
[TEGRA_POWERGATE_CPU3] = "cpu3",
299+
[TEGRA_POWERGATE_CELP] = "celp",
300+
[TEGRA_POWERGATE_CPU0] = "cpu0",
301+
[TEGRA_POWERGATE_C0NC] = "c0nc",
302+
[TEGRA_POWERGATE_C1NC] = "c1nc",
303+
[TEGRA_POWERGATE_DIS] = "dis",
304+
[TEGRA_POWERGATE_DISB] = "disb",
305+
[TEGRA_POWERGATE_XUSBA] = "xusba",
306+
[TEGRA_POWERGATE_XUSBB] = "xusbb",
307+
[TEGRA_POWERGATE_XUSBC] = "xusbc",
308+
};
309+
310+
static const char * const powergate_name_t124[] = {
311+
[TEGRA_POWERGATE_CPU] = "crail",
249312
[TEGRA_POWERGATE_3D] = "3d",
250313
[TEGRA_POWERGATE_VENC] = "venc",
314+
[TEGRA_POWERGATE_PCIE] = "pcie",
251315
[TEGRA_POWERGATE_VDEC] = "vdec",
316+
[TEGRA_POWERGATE_L2] = "l2",
252317
[TEGRA_POWERGATE_MPE] = "mpe",
253318
[TEGRA_POWERGATE_HEG] = "heg",
319+
[TEGRA_POWERGATE_SATA] = "sata",
254320
[TEGRA_POWERGATE_CPU1] = "cpu1",
255321
[TEGRA_POWERGATE_CPU2] = "cpu2",
256322
[TEGRA_POWERGATE_CPU3] = "cpu3",
257323
[TEGRA_POWERGATE_CELP] = "celp",
258324
[TEGRA_POWERGATE_CPU0] = "cpu0",
259325
[TEGRA_POWERGATE_C0NC] = "c0nc",
260326
[TEGRA_POWERGATE_C1NC] = "c1nc",
327+
[TEGRA_POWERGATE_SOR] = "sor",
261328
[TEGRA_POWERGATE_DIS] = "dis",
262329
[TEGRA_POWERGATE_DISB] = "disb",
263330
[TEGRA_POWERGATE_XUSBA] = "xusba",
264331
[TEGRA_POWERGATE_XUSBB] = "xusbb",
265332
[TEGRA_POWERGATE_XUSBC] = "xusbc",
333+
[TEGRA_POWERGATE_VIC] = "vic",
334+
[TEGRA_POWERGATE_IRAM] = "iram",
266335
};
267336

268337
static int powergate_show(struct seq_file *s, void *data)
@@ -309,6 +378,9 @@ int __init tegra_powergate_debugfs_init(void)
309378
case TEGRA114:
310379
powergate_name = powergate_name_t114;
311380
break;
381+
case TEGRA124:
382+
powergate_name = powergate_name_t124;
383+
break;
312384
}
313385

314386
if (powergate_name) {
@@ -322,3 +394,120 @@ int __init tegra_powergate_debugfs_init(void)
322394
}
323395

324396
#endif
397+
398+
static int tegra_io_rail_prepare(int id, unsigned long *request,
399+
unsigned long *status, unsigned int *bit)
400+
{
401+
unsigned long rate, value;
402+
struct clk *clk;
403+
404+
*bit = id % 32;
405+
406+
/*
407+
* There are two sets of 30 bits to select IO rails, but bits 30 and
408+
* 31 are control bits rather than IO rail selection bits.
409+
*/
410+
if (id > 63 || *bit == 30 || *bit == 31)
411+
return -EINVAL;
412+
413+
if (id < 32) {
414+
*status = IO_DPD_STATUS;
415+
*request = IO_DPD_REQ;
416+
} else {
417+
*status = IO_DPD2_STATUS;
418+
*request = IO_DPD2_REQ;
419+
}
420+
421+
clk = clk_get_sys(NULL, "pclk");
422+
if (IS_ERR(clk))
423+
return PTR_ERR(clk);
424+
425+
rate = clk_get_rate(clk);
426+
clk_put(clk);
427+
428+
pmc_write(DPD_SAMPLE_ENABLE, DPD_SAMPLE);
429+
430+
/* must be at least 200 ns, in APB (PCLK) clock cycles */
431+
value = DIV_ROUND_UP(1000000000, rate);
432+
value = DIV_ROUND_UP(200, value);
433+
pmc_write(value, SEL_DPD_TIM);
434+
435+
return 0;
436+
}
437+
438+
static int tegra_io_rail_poll(unsigned long offset, unsigned long mask,
439+
unsigned long val, unsigned long timeout)
440+
{
441+
unsigned long value;
442+
443+
timeout = jiffies + msecs_to_jiffies(timeout);
444+
445+
while (time_after(timeout, jiffies)) {
446+
value = pmc_read(offset);
447+
if ((value & mask) == val)
448+
return 0;
449+
450+
usleep_range(250, 1000);
451+
}
452+
453+
return -ETIMEDOUT;
454+
}
455+
456+
static void tegra_io_rail_unprepare(void)
457+
{
458+
pmc_write(DPD_SAMPLE_DISABLE, DPD_SAMPLE);
459+
}
460+
461+
int tegra_io_rail_power_on(int id)
462+
{
463+
unsigned long request, status, value;
464+
unsigned int bit, mask;
465+
int err;
466+
467+
err = tegra_io_rail_prepare(id, &request, &status, &bit);
468+
if (err < 0)
469+
return err;
470+
471+
mask = 1 << bit;
472+
473+
value = pmc_read(request);
474+
value |= mask;
475+
value &= ~IO_DPD_REQ_CODE_MASK;
476+
value |= IO_DPD_REQ_CODE_OFF;
477+
pmc_write(value, request);
478+
479+
err = tegra_io_rail_poll(status, mask, 0, 250);
480+
if (err < 0)
481+
return err;
482+
483+
tegra_io_rail_unprepare();
484+
485+
return 0;
486+
}
487+
488+
int tegra_io_rail_power_off(int id)
489+
{
490+
unsigned long request, status, value;
491+
unsigned int bit, mask;
492+
int err;
493+
494+
err = tegra_io_rail_prepare(id, &request, &status, &bit);
495+
if (err < 0)
496+
return err;
497+
498+
mask = 1 << bit;
499+
500+
value = pmc_read(request);
501+
value |= mask;
502+
value &= ~IO_DPD_REQ_CODE_MASK;
503+
value |= IO_DPD_REQ_CODE_ON;
504+
pmc_write(value, request);
505+
506+
err = tegra_io_rail_poll(status, mask, mask, 250);
507+
if (err < 0)
508+
return err;
509+
510+
tegra_io_rail_unprepare();
511+
512+
return 0;
513+
}

include/linux/tegra-powergate.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,49 @@ struct reset_control;
3838
#define TEGRA_POWERGATE_CPU0 14
3939
#define TEGRA_POWERGATE_C0NC 15
4040
#define TEGRA_POWERGATE_C1NC 16
41+
#define TEGRA_POWERGATE_SOR 17
4142
#define TEGRA_POWERGATE_DIS 18
4243
#define TEGRA_POWERGATE_DISB 19
4344
#define TEGRA_POWERGATE_XUSBA 20
4445
#define TEGRA_POWERGATE_XUSBB 21
4546
#define TEGRA_POWERGATE_XUSBC 22
47+
#define TEGRA_POWERGATE_VIC 23
48+
#define TEGRA_POWERGATE_IRAM 24
4649

4750
#define TEGRA_POWERGATE_3D0 TEGRA_POWERGATE_3D
4851

52+
#define TEGRA_IO_RAIL_CSIA 0
53+
#define TEGRA_IO_RAIL_CSIB 1
54+
#define TEGRA_IO_RAIL_DSI 2
55+
#define TEGRA_IO_RAIL_MIPI_BIAS 3
56+
#define TEGRA_IO_RAIL_PEX_BIAS 4
57+
#define TEGRA_IO_RAIL_PEX_CLK1 5
58+
#define TEGRA_IO_RAIL_PEX_CLK2 6
59+
#define TEGRA_IO_RAIL_USB0 9
60+
#define TEGRA_IO_RAIL_USB1 10
61+
#define TEGRA_IO_RAIL_USB2 11
62+
#define TEGRA_IO_RAIL_USB_BIAS 12
63+
#define TEGRA_IO_RAIL_NAND 13
64+
#define TEGRA_IO_RAIL_UART 14
65+
#define TEGRA_IO_RAIL_BB 15
66+
#define TEGRA_IO_RAIL_AUDIO 17
67+
#define TEGRA_IO_RAIL_HSIC 19
68+
#define TEGRA_IO_RAIL_COMP 22
69+
#define TEGRA_IO_RAIL_HDMI 28
70+
#define TEGRA_IO_RAIL_PEX_CNTRL 32
71+
#define TEGRA_IO_RAIL_SDMMC1 33
72+
#define TEGRA_IO_RAIL_SDMMC3 34
73+
#define TEGRA_IO_RAIL_SDMMC4 35
74+
#define TEGRA_IO_RAIL_CAM 36
75+
#define TEGRA_IO_RAIL_RES 37
76+
#define TEGRA_IO_RAIL_HV 38
77+
#define TEGRA_IO_RAIL_DSIB 39
78+
#define TEGRA_IO_RAIL_DSIC 40
79+
#define TEGRA_IO_RAIL_DSID 41
80+
#define TEGRA_IO_RAIL_CSIE 44
81+
#define TEGRA_IO_RAIL_LVDS 57
82+
#define TEGRA_IO_RAIL_SYS_DDC 58
83+
4984
#ifdef CONFIG_ARCH_TEGRA
5085
int tegra_powergate_is_powered(int id);
5186
int tegra_powergate_power_on(int id);
@@ -55,6 +90,9 @@ int tegra_powergate_remove_clamping(int id);
5590
/* Must be called with clk disabled, and returns with clk enabled */
5691
int tegra_powergate_sequence_power_up(int id, struct clk *clk,
5792
struct reset_control *rst);
93+
94+
int tegra_io_rail_power_on(int id);
95+
int tegra_io_rail_power_off(int id);
5896
#else
5997
static inline int tegra_powergate_is_powered(int id)
6098
{
@@ -81,6 +119,16 @@ static inline int tegra_powergate_sequence_power_up(int id, struct clk *clk,
81119
{
82120
return -ENOSYS;
83121
}
122+
123+
static inline int tegra_io_rail_power_on(int id)
124+
{
125+
return -ENOSYS;
126+
}
127+
128+
static inline int tegra_io_rail_power_off(int id)
129+
{
130+
return -ENOSYS;
131+
}
84132
#endif
85133

86134
#endif /* _MACH_TEGRA_POWERGATE_H_ */

0 commit comments

Comments
 (0)