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+
4461static int tegra_num_powerdomains ;
4562static int tegra_num_cpu_domains ;
4663static 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+
6286static DEFINE_SPINLOCK (tegra_powergate_lock );
6387
6488static 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
113138int 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 */
148185int 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
247289static 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
268337static 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+ }
0 commit comments