coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
tegra_lp0_resume.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 /* Function unit addresses. */
4 enum {
5  UP_TAG_BASE = 0x60000000,
6  TIMER_BASE = 0x60005000,
7  CLK_RST_BASE = 0x60006000,
8  FLOW_CTLR_BASE = 0x60007000,
9  TEGRA_EVP_BASE = 0x6000f000,
10  PMC_CTLR_BASE = 0x7000e400,
11  MC_CTLR_BASE = 0x70019000,
12  SYSCTR_CTLR_BASE = 0x700f0000
13 };
14 
15 /* UP tag registers. */
16 static uint32_t *up_tag_ptr = (void *)(UP_TAG_BASE + 0x0);
17 enum {
18  UP_TAG_AVP = 0xaaaaaaaa
19 };
20 
21 /* Timer registers. */
22 static uint32_t *timer_us_ptr = (void *)(TIMER_BASE + 0x10);
23 
24 /* Clock and reset controller registers. */
26 enum {
27  SWR_TRIG_SYS_RST = 0x1 << 2
28 };
29 
31 enum {
32  CCLK_PLLP_BURST_POLICY = 0x20004444
33 };
34 
36 enum {
37  SUPER_CDIV_ENB = 0x1 << 31
38 };
39 
40 static uint32_t *clk_rst_osc_ctrl_ptr = (void *)(CLK_RST_BASE + 0x50);
41 enum {
42  OSC_XOE = 0x1 << 0,
47 };
48 enum {
55  OSC_FREQ_26 = 12
56 };
57 
58 static uint32_t *clk_rst_pllu_base_ptr = (void *)(CLK_RST_BASE + 0xc0);
59 enum {
62  PLLU_OVERRIDE = 0x1 << 24,
63  PLLU_ENABLE = 0x1 << 30,
64  PLLU_BYPASS = 0x1 << 31
65 };
66 
67 static uint32_t *clk_rst_pllu_misc_ptr = (void *)(CLK_RST_BASE + 0xcc);
68 enum {
71  PLLU_LOCK_ENABLE = 22
72 };
73 
74 static uint32_t *clk_rst_pllx_base_ptr = (void *)(CLK_RST_BASE + 0xe0);
75 enum {
76  PLLX_ENABLE = 0x1 << 30
77 };
78 
79 static uint32_t *clk_rst_rst_dev_u_clr_ptr = (void *)(CLK_RST_BASE + 0x314);
80 enum {
81  SWR_CSITE_RST = 0x1 << 9
82 };
83 
84 static uint32_t *clk_rst_clk_enb_l_set_ptr = (void *)(CLK_RST_BASE + 0x320);
85 enum {
86  CLK_ENB_CPU = 0x1 << 0
87 };
88 
90  (void *)(CLK_RST_BASE + 0x330);
91 enum {
92  CLK_ENB_CSITE = 0x1 << 9
93 };
94 
96  (void *)(CLK_RST_BASE + 0x388);
97 enum {
100 };
101 
103  (void *)(CLK_RST_BASE + 0x3b4);
104 enum {
111 };
112 
113 static uint32_t *clk_rst_rst_dev_v_clr_ptr = (void *)(CLK_RST_BASE + 0x434);
114 enum {
115  SWR_MSELECT_RST = 0x1 << 3
116 };
117 
118 static uint32_t *clk_rst_clk_enb_v_set_ptr = (void *)(CLK_RST_BASE + 0x440);
119 enum {
120  CLK_ENB_CPUG = 0x1 << 0,
121  CLK_ENB_CPULP = 0x1 << 1,
122  CLK_ENB_MSELECT = 0x1 << 3
123 };
124 
126  (void *)(CLK_RST_BASE + 0x45c);
128  (void *)(CLK_RST_BASE + 0x454);
129 enum {
130  CLR_CPURESET0 = 0x1 << 0,
131  CLR_CPURESET1 = 0x1 << 1,
132  CLR_CPURESET2 = 0x1 << 2,
133  CLR_CPURESET3 = 0x1 << 3,
134  CLR_DBGRESET0 = 0x1 << 12,
135  CLR_DBGRESET1 = 0x1 << 13,
136  CLR_DBGRESET2 = 0x1 << 14,
137  CLR_DBGRESET3 = 0x1 << 15,
138  CLR_CORERESET0 = 0x1 << 16,
139  CLR_CORERESET1 = 0x1 << 17,
140  CLR_CORERESET2 = 0x1 << 18,
141  CLR_CORERESET3 = 0x1 << 19,
142  CLR_CXRESET0 = 0x1 << 20,
143  CLR_CXRESET1 = 0x1 << 21,
144  CLR_CXRESET2 = 0x1 << 22,
145  CLR_CXRESET3 = 0x1 << 23,
146  CLR_NONCPURESET = 0x1 << 29
147 };
148 
149 /* Reset vector. */
150 static uint32_t *evp_cpu_reset_ptr = (void *)(TEGRA_EVP_BASE + 0x100);
151 
152 /* Flow controller registers. */
154  (void *)(FLOW_CTLR_BASE + 0x4);
155 enum {
156  EVENT_MSEC = 0x1 << 24,
157  EVENT_JTAG = 0x1 << 28,
160 };
161 
163  (void *)(FLOW_CTLR_BASE + 0x2c);
164 enum {
165  FLOW_CLUSTER_ACTIVE_LP = 0x1 << 0
166 };
167 
169  (void *)(FLOW_CTLR_BASE + 0x40);
171  (void *)(FLOW_CTLR_BASE + 0x58);
172 enum {
173  RAM_REPAIR_REQ = 0x1 << 0,
174  RAM_REPAIR_STS = 0x1 << 1,
175 };
176 
177 /* Power management controller registers. */
178 enum {
183  PARTID_C1NC = 16
184 };
185 
187 
189 enum {
190  PWRGATE_TOGGLE_START = 0x1 << 8
191 };
192 
194 
195 static uint32_t *pmc_ctlr_scratch4_ptr = (void *)(PMC_CTLR_BASE + 0x60);
196 enum {
197  PMC_SCRATCH4_LP = 0x1 << 31
198 };
199 
201  (void *)(PMC_CTLR_BASE + 0xc8);
202 
203 static uint32_t *pmc_ctlr_scratch41_ptr = (void *)(PMC_CTLR_BASE + 0x140);
204 
206 enum {
208  PMC_XOFS_MASK = 0x3f << PMC_XOFS_SHIFT
209 };
210 
211 /* Memory controller registers. */
213 
215  (void *)(MC_CTLR_BASE + 0x650);
216 enum {
219 };
220 
221 /* System counter registers. */
222 static uint32_t *sysctr_cntcr_ptr = (void *)(SYSCTR_CTLR_BASE + 0x0);
223 enum {
224  TSC_CNTCR_ENABLE = 0x1 << 0,
225  TSC_CNTCR_HDBG = 0x1 << 1
226 };
227 
228 static uint32_t *sysctr_cntfid0_ptr = (void *)(SYSCTR_CTLR_BASE + 0x20);
229 
230 /* Utility functions. */
231 static __always_inline void __noreturn halt(void)
232 {
233  for (;;);
234 }
235 
236 static inline uint32_t read32(const void *addr)
237 {
238  return *(volatile uint32_t *)addr;
239 }
240 
241 static inline void write32(void *addr, uint32_t val)
242 {
243  *(volatile uint32_t *)addr = val;
244 }
245 
246 static inline void setbits32(uint32_t bits, void *addr)
247 {
248  write32(addr, read32(addr) | bits);
249 }
250 
251 static inline void clrbits32(uint32_t bits, void *addr)
252 {
253  write32(addr, read32(addr) & ~bits);
254 }
255 
256 static void __noreturn reset(void)
257 {
259  halt();
260 }
261 
262 static void udelay(unsigned int usecs)
263 {
264  uint32_t start = read32(timer_us_ptr);
265  while (read32(timer_us_ptr) - start < usecs)
266  ;
267 }
268 
269 /* Accessors. */
270 static int wakeup_on_lp(void)
271 {
273 }
274 
276 {
278 }
279 
280 static unsigned int get_osc_freq(void)
281 {
283 }
284 
285 /* Clock configuration. */
286 static void config_oscillator(void)
287 {
288  // Read oscillator drive strength from OSC_EDPD_OVER.XOFS and copy
289  // to OSC_CTRL.XOFS and set XOE.
292 
294  osc_ctrl &= ~OSC_XOFS_MASK;
295  osc_ctrl |= (xofs << OSC_XOFS_SHIFT);
296  osc_ctrl |= OSC_XOE;
297  write32(clk_rst_osc_ctrl_ptr, osc_ctrl);
298 }
299 
300 static void config_pllu(void)
301 {
302  // Figure out what parameters to use for PLLU.
303  uint32_t divm, divn, cpcon, lfcon;
304  switch (get_osc_freq()) {
305  case OSC_FREQ_12:
306  case OSC_FREQ_48:
307  divm = 0x0c;
308  divn = 0x3c0;
309  cpcon = 0x0c;
310  lfcon = 0x02;
311  break;
312  case OSC_FREQ_16P8:
313  divm = 0x07;
314  divn = 0x190;
315  cpcon = 0x05;
316  lfcon = 0x02;
317  break;
318  case OSC_FREQ_19P2:
319  case OSC_FREQ_38P4:
320  divm = 0x04;
321  divn = 0xc8;
322  cpcon = 0x03;
323  lfcon = 0x02;
324  break;
325  case OSC_FREQ_26:
326  divm = 0x1a;
327  divn = 0x3c0;
328  cpcon = 0x0c;
329  lfcon = 0x02;
330  break;
331  default:
332  // Map anything that's not recognized to 13MHz.
333  divm = 0x0d;
334  divn = 0x3c0;
335  cpcon = 0x0c;
336  lfcon = 0x02;
337  }
338 
339  // Configure PLLU.
341  (divn << PLLU_DIVN_SHIFT) | (divm << PLLU_DIVM_SHIFT);
343  uint32_t misc = (cpcon << PLLU_CPCON_SHIFT) |
344  (lfcon << PLLU_LFCON_SHIFT);
346 
347  // Enable PLLU.
348  base &= ~PLLU_BYPASS;
349  base |= PLLU_ENABLE;
353 }
354 
355 static void config_tsc(void)
356 {
357  // Tell the TSC the oscillator frequency.
358  switch (get_osc_freq()) {
359  case OSC_FREQ_12:
360  write32(sysctr_cntfid0_ptr, 12000000);
361  break;
362  case OSC_FREQ_48:
363  write32(sysctr_cntfid0_ptr, 48000000);
364  break;
365  case OSC_FREQ_16P8:
366  write32(sysctr_cntfid0_ptr, 16800000);
367  break;
368  case OSC_FREQ_19P2:
369  write32(sysctr_cntfid0_ptr, 19200000);
370  break;
371  case OSC_FREQ_38P4:
372  write32(sysctr_cntfid0_ptr, 38400000);
373  break;
374  case OSC_FREQ_26:
375  write32(sysctr_cntfid0_ptr, 26000000);
376  break;
377  default:
378  // Default to 13MHz.
379  write32(sysctr_cntfid0_ptr, 13000000);
380  break;
381  }
382 
383  // Enable the TSC.
385 }
386 
387 static void enable_cpu_clocks(void)
388 {
389  // Enable the CPU complex clock.
392 }
393 
394 /* Function unit configuration. */
395 static void config_core_sight(void)
396 {
397  // Enable the CoreSight clock.
399 
400  /*
401  * De-assert CoreSight reset.
402  * NOTE: We're leaving the CoreSight clock on the oscillator for
403  * now. It will be restored to its original clock source
404  * when the CPU-side restoration code runs.
405  */
407 }
408 
409 static void config_mselect(void)
410 {
411  // Set MSELECT clock source to PLLP with 1:4 divider.
414 
415  // Enable clock to MSELECT.
417 
418  udelay(2);
419 
420  // Bring MSELECT out of reset.
422 }
423 
424 /* Resets. */
425 static void clear_cpu_resets(void)
426 {
427  // Take the non-cpu of the G and LP clusters out of reset.
430 
431  // Clear software controlled reset of the slow cluster.
434 
435  // Clear software controlled reset of the fast cluster.
441 }
442 
443 /* RAM repair */
444 void ram_repair(void)
445 {
446  // Request Cluster0 RAM repair.
448  // Poll for Cluster0 RAM repair status.
450  ;
451 
452  // Request Cluster1 RAM repair.
454  // Poll for Cluster1 RAM repair status.
456  ;
457 }
458 
459 /* Power. */
460 static void power_on_partition(unsigned int id)
461 {
462  uint32_t bit = 0x1 << id;
463  if (!(read32(pmc_ctlr_pwrgate_status_ptr) & bit)) {
464  // Partition is not on. Turn it on.
466 
467  // Wait until the partition is powerd on.
468  while (!(read32(pmc_ctlr_pwrgate_status_ptr) & bit))
469  ;
470 
471  // Wait until clamp is off.
472  while (read32(pmc_ctlr_clamp_status_ptr) & bit)
473  ;
474  }
475 }
476 
477 static void power_on_main_cpu(void)
478 {
479  /*
480  * Reprogram PMC_CPUPWRGOOD_TIMER register:
481  *
482  * XXX This is a fragile assumption. XXX
483  * The kernel prepares PMC_CPUPWRGOOD_TIMER based on a 32768Hz clock.
484  * Note that PMC_CPUPWRGOOD_TIMER is running at pclk.
485  *
486  * We need to reprogram PMC_CPUPWRGOOD_TIMER based on the current pclk
487  * which is at 204Mhz (pclk = sclk = pllp_out2) after BootROM. Multiply
488  * PMC_CPUPWRGOOD_TIMER by 204M / 32K.
489  *
490  * Save the original PMC_CPUPWRGOOD_TIMER register which we need to
491  * restore after the CPU is powered up.
492  */
494 
496  orig_timer * (204000000 / 32768));
497 
498  if (wakeup_on_lp()) {
501  } else {
505  }
506 
507  // Restore the original PMC_CPUPWRGOOD_TIMER.
509 }
510 
511 /* Entry point. */
512 void lp0_resume(void)
513 {
514  // If not on the AVP, reset.
515  if (read32(up_tag_ptr) != UP_TAG_AVP)
516  reset();
517 
519 
520  // Tell the flow controller which cluster to wake up. The default is
521  // the fast cluster.
522  if (wakeup_on_lp())
525 
526  // Program SUPER_CCLK_DIVIDER.
528 
530 
531  config_pllu();
532 
533  // Set the CPU reset vector.
535 
536  // Select CPU complex clock source.
538 
539  config_mselect();
540 
541  // Disable PLLX since it isn't used as CPU clock source.
543 
544  // Set CAR2PMC_CPU_ACK_WIDTH to 408.
546  ack_width &= ~CAR2PMC_CPU_ACK_WIDTH_MASK;
547  ack_width |= 408 << CAR2PMC_CPU_ACK_WIDTH_SHIFT;
549 
550  config_tsc();
551 
552  // Disable VPR.
556 
558 
560 
561  // Perform RAM repair after CPU is powered on.
562  ram_repair();
563 
565 
566  // Halt the AVP.
567  while (1)
570 }
571 
572 /* Header. */
573 extern uint8_t blob_data;
574 extern uint8_t blob_data_size;
576 
577 struct lp0_header {
578  uint32_t length_insecure; // Insecure total length.
580  uint8_t rsa_modulus[256]; // RSA key modulus.
581  uint8_t aes_signature[16]; // AES signature.
582  uint8_t rsa_signature[256]; // RSA-PSS signature.
583  uint8_t random_aes_block[16]; // Random data, may be zero.
584  uint32_t length_secure; // Secure total length.
585  uint32_t destination; // Where to load the blob in iRAM.
586  uint32_t entry_point; // Entry point for the blob.
587  uint32_t code_length; // Length of just the data.
589 
590 struct lp0_header header __attribute__((section(".header"))) =
591 {
594  .destination = (uintptr_t)&blob_data,
596  .code_length = (uintptr_t)&blob_data_size
597 };
static struct apbmisc * misc
Definition: apbmisc.c:8
static u32 addr
Definition: cirrus.c:14
#define __noreturn
Definition: compiler.h:31
#define __always_inline
Definition: compiler.h:35
uintptr_t base
Definition: uart.c:17
unsigned int uint32_t
Definition: stdint.h:14
unsigned long uintptr_t
Definition: stdint.h:21
unsigned char uint8_t
Definition: stdint.h:8
uint32_t length_secure
uint32_t reserved[3]
uint32_t length_insecure
uint8_t aes_signature[16]
uint32_t entry_point
uint8_t rsa_modulus[256]
uint8_t rsa_signature[256]
uint32_t destination
uint8_t random_aes_block[16]
uint32_t code_length
u8 val
Definition: sys.c:300
static void power_on_partition(unsigned int id)
static void config_pllu(void)
@ OSC_FREQ_13
@ OSC_FREQ_16P8
@ OSC_FREQ_19P2
@ OSC_FREQ_38P4
@ OSC_FREQ_12
@ OSC_FREQ_48
@ OSC_FREQ_26
static uint32_t * clk_rst_pllu_misc_ptr
static uint32_t * evp_cpu_reset_ptr
static void enable_cpu_clocks(void)
static void config_tsc(void)
static void power_on_main_cpu(void)
@ PMC_XOFS_MASK
@ PMC_XOFS_SHIFT
static uint32_t * timer_us_ptr
static uint32_t * pmc_ctlr_osc_edpd_over_ptr
static uint32_t * clk_rst_osc_ctrl_ptr
@ UP_TAG_AVP
static void write32(void *addr, uint32_t val)
static uint32_t * clk_rst_pllu_base_ptr
@ SWR_CSITE_RST
@ PARTID_C1NC
@ PARTID_CE0
@ PARTID_CELP
@ PARTID_CRAIL
@ PARTID_C0NC
@ SWR_TRIG_SYS_RST
static uint32_t * clk_rst_pllx_base_ptr
static uint32_t * clk_rst_super_cclk_div_ptr
@ PLLX_ENABLE
static uint32_t * flow_ctlr_cluster_control_ptr
static uint32_t * mc_video_protect_size_mb_ptr
static uint32_t * clk_rst_cclk_burst_policy_ptr
@ OSC_XOFS_MASK
@ OSC_XOE
@ OSC_XOFS_SHIFT
@ OSC_FREQ_SHIFT
@ OSC_FREQ_MASK
static __always_inline void __noreturn halt(void)
static void config_oscillator(void)
static uint32_t * clk_rst_clk_enb_l_set_ptr
@ FLOW_CLUSTER_ACTIVE_LP
static void udelay(unsigned int usecs)
static uint32_t * sysctr_cntfid0_ptr
static uint32_t * flow_ctlr_ram_repair_cluster1_ptr
static void config_core_sight(void)
static uint32_t * flow_ctlr_ram_repair_ptr
static int wakeup_on_lp(void)
static uint32_t * clk_rst_rst_cpulp_cmplx_clr_ptr
static uint32_t * pmc_ctlr_clamp_status_ptr
static uint32_t * pmc_ctlr_pwrgate_status_ptr
static uint32_t * sysctr_cntcr_ptr
static void setbits32(uint32_t bits, void *addr)
static uint32_t * clk_rst_rst_dev_u_clr_ptr
@ PMC_SCRATCH4_LP
@ CLR_CORERESET2
@ CLR_CXRESET3
@ CLR_CORERESET0
@ CLR_CPURESET2
@ CLR_NONCPURESET
@ CLR_CORERESET1
@ CLR_DBGRESET2
@ CLR_CPURESET1
@ CLR_DBGRESET3
@ CLR_CXRESET1
@ CLR_DBGRESET0
@ CLR_CPURESET0
@ CLR_CORERESET3
@ CLR_DBGRESET1
@ CLR_CXRESET0
@ CLR_CPURESET3
@ CLR_CXRESET2
static uint32_t * mc_video_protect_reg_ctrl_ptr
static uint32_t read32(const void *addr)
@ PMC_CTLR_BASE
@ MC_CTLR_BASE
@ FLOW_CTLR_BASE
@ TEGRA_EVP_BASE
@ TIMER_BASE
@ SYSCTR_CTLR_BASE
@ CLK_RST_BASE
@ UP_TAG_BASE
void ram_repair(void)
struct lp0_header header
@ CAR2PMC_CPU_ACK_WIDTH_MASK
@ CAR2PMC_CPU_ACK_WIDTH_SHIFT
static void config_mselect(void)
uint8_t blob_data_size
struct lp0_header __packed
static uint32_t * clk_rst_rst_devices_l_ptr
static void clrbits32(uint32_t bits, void *addr)
void lp0_resume(void)
@ SWR_MSELECT_RST
@ PLLU_OVERRIDE
@ PLLU_DIVN_SHIFT
@ PLLU_DIVM_SHIFT
@ PLLU_ENABLE
@ PLLU_BYPASS
static uint32_t * clk_rst_rst_cpug_cmplx_clr_ptr
@ CLK_ENB_CPUG
@ CLK_ENB_CPULP
@ CLK_ENB_MSELECT
uint8_t blob_total_size
uint8_t blob_data
@ CLK_ENB_CSITE
static void clear_cpu_resets(void)
static uint32_t * flow_ctlr_halt_cop_events_ptr
static uint32_t * pmc_ctlr_scratch4_ptr
static uint32_t * pmc_ctlr_scratch41_ptr
@ PWRGATE_TOGGLE_START
static unsigned int get_osc_freq(void)
static void __noreturn reset(void)
@ RAM_REPAIR_REQ
@ RAM_REPAIR_STS
static uint32_t get_wakeup_vector(void)
@ MSELECT_CLK_SRC_PLLC2_OUT0
@ MSELECT_CLK_SRC_PLLC_OUT0
@ MSELECT_CLK_DIV_SHIFT
@ MSELECT_CLK_SRC_PLLC3_OUT0
@ MSELECT_CLK_SRC_SHIFT
@ MSELECT_CLK_SRC_PLLP_OUT0
static uint32_t * pmc_ctlr_pwrgate_toggle_ptr
static uint32_t * clk_rst_clk_out_enb_u_set_ptr
static uint32_t * pmc_ctlr_cpupwrgood_timer_ptr
static uint32_t * up_tag_ptr
static uint32_t * clk_rst_rst_dev_v_clr_ptr
@ CLK_ENB_CPU
static uint32_t * clk_rst_clk_enb_v_set_ptr
@ PLLU_LFCON_SHIFT
@ PLLU_CPCON_SHIFT
@ PLLU_LOCK_ENABLE
@ TSC_CNTCR_ENABLE
@ TSC_CNTCR_HDBG
static uint32_t * clk_rst_cpu_softrst_ctrl2_ptr
@ EVENT_JTAG
@ FLOW_MODE_STOP
@ EVENT_MSEC
@ FLOW_MODE_SHIFT
static uint32_t * clk_rst_clk_src_mselect_ptr
@ SUPER_CDIV_ENB
@ VIDEO_PROTECT_ALLOW_TZ_WRITE_ACCESS
@ VIDEO_PROTECT_WRITE_ACCESS_DISABLE
@ CCLK_PLLP_BURST_POLICY