| /* SPDX-License-Identifier: GPL-2.0-only */ |
| |
| /* Function unit addresses. */ |
| enum { |
| UP_TAG_BASE = 0x60000000, |
| TIMER_BASE = 0x60005000, |
| CLK_RST_BASE = 0x60006000, |
| FLOW_CTLR_BASE = 0x60007000, |
| SECURE_BOOT_BASE = 0x6000C200, |
| TEGRA_EVP_BASE = 0x6000f000, |
| APB_MISC_BASE = 0x70000000, |
| PINMUX_BASE = 0x70003000, |
| PMC_CTLR_BASE = 0x7000e400, |
| MC_CTLR_BASE = 0x70019000, |
| FUSE_BASE = 0x7000F800, |
| TEGRA_SDMMC1_BASE = 0x700b0000, |
| TEGRA_SDMMC3_BASE = 0x700b0400, |
| EMC_BASE = 0x7001B000, |
| I2C5_BASE = 0x7000D000, |
| I2S_BASE = 0x702d1000 |
| }; |
| |
| /* UP tag registers. */ |
| static uint32_t *up_tag_ptr = (void *)(UP_TAG_BASE + 0x0); |
| enum { |
| UP_TAG_AVP = 0xaaaaaaaa |
| }; |
| |
| /* APB Misc JTAG Configuration Register */ |
| static uint32_t *misc_pp_config_ctl_ptr = (void *)(APB_MISC_BASE + 0x24); |
| enum { |
| PP_CONFIG_CTL_TBE = 0x1 << 7, |
| PP_CONFIG_CTL_JTAG = 0x1 << 6 |
| }; |
| |
| static uint32_t *misc_gp_asdbgreg_ptr = (void *)(APB_MISC_BASE + 0x810); |
| enum { |
| CFG2TMC_RAM_SVOP_PDP_MASK = 0x3 << 24, |
| CFG2TMC_RAM_SVOP_PDP_VAL_2 = 0x2 << 24, |
| }; |
| |
| /* PINMUX registers. */ |
| static uint32_t *pinmux_pwr_i2c_scl_ptr = (void *)(PINMUX_BASE + 0xdc); |
| static uint32_t *pinmux_pwr_i2c_sda_ptr = (void *)(PINMUX_BASE + 0xe0); |
| static uint32_t *pinmux_dvfs_pwm_ptr = (void *)(PINMUX_BASE + 0x184); |
| static uint32_t *pinmux_gpio_pa6_ptr = (void *)(PINMUX_BASE + 0x244); |
| enum { |
| E_INPUT = 1 << 6, |
| TRISTATE = 1 << 4, |
| PM_CLDVFS = 1, |
| PM_I2CPMU = 0 |
| }; |
| |
| /* Timer registers. */ |
| static uint32_t *timer_us_ptr = (void *)(TIMER_BASE + 0x10); |
| static uint32_t *timer_us_cfg_ptr = (void *)(TIMER_BASE + 0x14); |
| |
| /* Clock and reset controller registers. */ |
| static uint32_t *clk_rst_rst_devices_l_ptr = (void *)(CLK_RST_BASE + 0x4); |
| enum { |
| SWR_TRIG_SYS_RST = 0x1 << 2 |
| }; |
| |
| static uint32_t *clk_rst_rst_devices_u_ptr = (void *)(CLK_RST_BASE + 0xc); |
| |
| static uint32_t *clk_rst_cclkg_burst_policy_ptr = (void *)(CLK_RST_BASE + 0x368); |
| enum { |
| CCLKG_PLLP_BURST_POLICY = 0x20004444 |
| }; |
| |
| static uint32_t *clk_rst_cclklp_burst_policy_ptr = (void *)(CLK_RST_BASE + 0x370); |
| enum { |
| CCLKLP_PLLP_BURST_POLICY = 0x20004444 |
| }; |
| |
| static uint32_t *clk_rst_super_cclkg_div_ptr = (void *)(CLK_RST_BASE + 0x36c); |
| static uint32_t *clk_rst_super_cclklp_div_ptr = (void *)(CLK_RST_BASE + 0x374); |
| enum { |
| SUPER_CDIV_ENB = 0x1 << 31 |
| }; |
| |
| static uint32_t *clk_rst_osc_ctrl_ptr = (void *)(CLK_RST_BASE + 0x50); |
| enum { |
| OSC_XOE = 0x1 << 0, |
| OSC_XOFS_SHIFT = 4, |
| OSC_XOFS_MASK = 0x3f << OSC_XOFS_SHIFT, |
| OSC_FREQ_SHIFT = 28, |
| OSC_FREQ_MASK = 0xf << OSC_FREQ_SHIFT |
| }; |
| |
| static uint32_t *clk_rst_pllx_base_ptr = (void *)(CLK_RST_BASE + 0xe0); |
| enum { |
| PLLX_ENABLE = 0x1 << 30 |
| }; |
| |
| static uint32_t *clk_rst_clk_source_i2c5_ptr = (void *)(CLK_RST_BASE + 0x128); |
| enum { |
| I2C5_CLK_DIVISOR = 4 |
| }; |
| |
| static uint32_t *clk_rst_rst_dev_h_set_ptr = (void *)(CLK_RST_BASE + 0x308); |
| enum { |
| I2C5_RST = 0x1 << 15 |
| }; |
| |
| static uint32_t *clk_rst_rst_dev_h_clr_ptr = (void *)(CLK_RST_BASE + 0x30c); |
| |
| static uint32_t *clk_rst_rst_dev_u_clr_ptr = (void *)(CLK_RST_BASE + 0x314); |
| enum { |
| SWR_CSITE_RST = 0x1 << 9 |
| }; |
| |
| static uint32_t *clk_rst_rst_dev_v_clr_ptr = (void *)(CLK_RST_BASE + 0x434); |
| enum { |
| MSELECT_RST = 0x1 << 3 |
| }; |
| |
| static uint32_t *clk_rst_clk_enb_l_set_ptr = (void *)(CLK_RST_BASE + 0x320); |
| enum { |
| CLK_ENB_CPU = 0x1 << 0 |
| }; |
| |
| static uint32_t *clk_rst_clk_enb_h_set_ptr = (void *)(CLK_RST_BASE + 0x328); |
| enum { |
| CLK_ENB_I2C5 = 0x1 << 15 |
| }; |
| |
| static uint32_t *clk_rst_clk_out_enb_u_set_ptr = |
| (void *)(CLK_RST_BASE + 0x330); |
| enum { |
| CLK_ENB_CSITE = 0x1 << 9 |
| }; |
| |
| static uint32_t *clk_rst_cpu_softrst_ctrl2_ptr = |
| (void *)(CLK_RST_BASE + 0x388); |
| enum { |
| CAR2PMC_CPU_ACK_WIDTH_SHIFT = 0, |
| CAR2PMC_CPU_ACK_WIDTH_MASK = 0xfff << CAR2PMC_CPU_ACK_WIDTH_SHIFT |
| }; |
| |
| static uint32_t *clk_rst_clk_enb_v_set_ptr = (void *)(CLK_RST_BASE + 0x440); |
| enum { |
| CLK_ENB_CPUG = 0x1 << 0, |
| }; |
| |
| static uint32_t *clk_rst_clk_enb_y_set_ptr = (void *)(CLK_RST_BASE + 0x29c); |
| enum { |
| CLK_ENB_PLLP_OUT_CPU = 0x1 << 31 |
| }; |
| |
| static uint32_t *clk_rst_cpug_cmplx_clr_ptr = |
| (void *)(CLK_RST_BASE + 0x454); |
| enum { |
| CLR_CPURESET0 = 0x1 << 0, |
| CLR_CPURESET1 = 0x1 << 1, |
| CLR_CPURESET2 = 0x1 << 2, |
| CLR_CPURESET3 = 0x1 << 3, |
| CLR_DBGRESET0 = 0x1 << 12, |
| CLR_DBGRESET1 = 0x1 << 13, |
| CLR_DBGRESET2 = 0x1 << 14, |
| CLR_DBGRESET3 = 0x1 << 15, |
| CLR_CORERESET0 = 0x1 << 16, |
| CLR_CORERESET1 = 0x1 << 17, |
| CLR_CORERESET2 = 0x1 << 18, |
| CLR_CORERESET3 = 0x1 << 19, |
| CLR_CXRESET0 = 0x1 << 20, |
| CLR_CXRESET1 = 0x1 << 21, |
| CLR_CXRESET2 = 0x1 << 22, |
| CLR_CXRESET3 = 0x1 << 23, |
| CLR_L2RESET = 0x1 << 24, |
| CLR_NONCPURESET = 0x1 << 29, |
| CLR_PRESETDBG = 0x1 << 30 |
| }; |
| |
| static uint32_t *clk_rst_spare_reg0_ptr = |
| (void *)(CLK_RST_BASE + 0x55c); |
| enum { |
| CLK_M_DIVISOR_MASK = 0x3 << 2, |
| CLK_M_DIVISOR_BY_2 = 0x1 << 2 |
| }; |
| |
| static uint32_t *clk_rst_lvl2_clk_gate_ovra_ptr = (void *)(CLK_RST_BASE + 0xf8); |
| static uint32_t *clk_rst_lvl2_clk_gate_ovrb_ptr = (void *)(CLK_RST_BASE + 0xfc); |
| static uint32_t *clk_rst_lvl2_clk_gate_ovrc_ptr = (void *)(CLK_RST_BASE + 0x3a0); |
| static uint32_t *clk_rst_lvl2_clk_gate_ovrd_ptr = (void *)(CLK_RST_BASE + 0x3a4); |
| static uint32_t *clk_rst_lvl2_clk_gate_ovre_ptr = (void *)(CLK_RST_BASE + 0x554); |
| |
| static uint32_t *clk_rst_clk_out_enb_l_ptr = (void *)(CLK_RST_BASE + 0x10); |
| static uint32_t *clk_rst_clk_out_enb_h_ptr = (void *)(CLK_RST_BASE + 0x14); |
| static uint32_t *clk_rst_clk_out_enb_u_ptr = (void *)(CLK_RST_BASE + 0x18); |
| static uint32_t *clk_rst_clk_out_enb_v_ptr = (void *)(CLK_RST_BASE + 0x360); |
| static uint32_t *clk_rst_clk_out_enb_w_ptr = (void *)(CLK_RST_BASE + 0x364); |
| static uint32_t *clk_rst_clk_out_enb_x_ptr = (void *)(CLK_RST_BASE + 0x280); |
| static uint32_t *clk_rst_clk_out_enb_y_ptr = (void *)(CLK_RST_BASE + 0x298); |
| |
| static uint32_t *clk_rst_clk_enb_l_clr_ptr = (void *)(CLK_RST_BASE + 0x324); |
| static uint32_t *clk_rst_clk_enb_h_clr_ptr = (void *)(CLK_RST_BASE + 0x32c); |
| static uint32_t *clk_rst_clk_enb_u_clr_ptr = (void *)(CLK_RST_BASE + 0x334); |
| static uint32_t *clk_rst_clk_enb_v_clr_ptr = (void *)(CLK_RST_BASE + 0x444); |
| static uint32_t *clk_rst_clk_enb_w_clr_ptr = (void *)(CLK_RST_BASE + 0x44c); |
| static uint32_t *clk_rst_clk_enb_x_clr_ptr = (void *)(CLK_RST_BASE + 0x288); |
| static uint32_t *clk_rst_clk_enb_y_clr_ptr = (void *)(CLK_RST_BASE + 0x2a0); |
| |
| #define MBIST_CLK_ENB_L_0 0x80000130 |
| #define MBIST_CLK_ENB_H_0 0x020000C1 |
| #define MBIST_CLK_ENB_U_0 0x01F00200 |
| #define MBIST_CLK_ENB_V_0 0x80400008 |
| #define MBIST_CLK_ENB_W_0 0x002000FC |
| #define MBIST_CLK_ENB_X_0 0x23004780 |
| #define MBIST_CLK_ENB_Y_0 0x00000300 |
| |
| static uint32_t *clk_rst_clk_enb_v_ptr = (void *)(CLK_RST_BASE + 0x440); |
| enum { |
| CLK_ENB_MSELECT = 0x1 << 3 |
| }; |
| |
| static uint32_t *clk_rst_clk_enb_w_set_ptr = (void *)(CLK_RST_BASE + 0x448); |
| enum { |
| CLK_ENB_MC1 = 0x1 << 30, |
| CLK_ENB_DVFS = 0x1 << 27 |
| }; |
| |
| static uint32_t *clk_rst_clk_source_mselect_ptr = (void *)(CLK_RST_BASE + 0x3b4); |
| enum { |
| CLK_SRC_PLLP_OUT0 = (0x0 << 29), |
| MSELECT_CLK_DIVISOR_4 = 6 |
| }; |
| |
| static uint32_t *clk_rst_clk_dvfs_ref_ptr = (void *)(CLK_RST_BASE + 0x62c); |
| enum { |
| DVFS_REF_CLK_DIVISOR = 0xe |
| }; |
| |
| static uint32_t *clk_rst_clk_dvfs_soc_ptr = (void *)(CLK_RST_BASE + 0x630); |
| enum { |
| DVFS_SOC_CLK_DIVISOR = 0xe |
| }; |
| |
| /* Flow controller registers. */ |
| static uint32_t *flow_ctlr_halt_cop_events_ptr = |
| (void *)(FLOW_CTLR_BASE + 0x4); |
| enum { |
| EVENT_MSEC = 0x1 << 24, |
| EVENT_JTAG = 0x1 << 28, |
| FLOW_MODE_SHIFT = 29, |
| FLOW_MODE_STOP = 2 << FLOW_MODE_SHIFT, |
| }; |
| |
| static uint32_t *flow_ctlr_ram_repair_ptr = |
| (void *)(FLOW_CTLR_BASE + 0x40); |
| static uint32_t *flow_ctlr_ram_repair_cluster1_ptr = |
| (void *)(FLOW_CTLR_BASE + 0x58); |
| enum { |
| RAM_REPAIR_REQ = 0x1 << 0, |
| RAM_REPAIR_STS = 0x1 << 1, |
| }; |
| |
| static uint32_t *flow_ctlr_bpmp_cluster_control_ptr = |
| (void *)(FLOW_CTLR_BASE + 0x98); |
| enum { |
| ACTIVE_SLOW = 0x1 << 0 |
| }; |
| |
| /* Power management controller registers. */ |
| enum { |
| PARTID_CRAIL = 0, |
| PARTID_CE1 = 9, |
| PARTID_CE2 = 10, |
| PARTID_CE3 = 11, |
| PARTID_CE0 = 14, |
| PARTID_C0NC = 15, |
| }; |
| |
| static uint32_t *pmc_dpd_sample_ptr = (void *)(PMC_CTLR_BASE + 0x20); |
| static uint32_t *pmc_clamp_status_ptr = (void *)(PMC_CTLR_BASE + 0x2c); |
| |
| static uint32_t *pmc_pwrgate_toggle_ptr = (void *)(PMC_CTLR_BASE + 0x30); |
| enum { |
| PWRGATE_TOGGLE_START = 0x1 << 8 |
| }; |
| |
| static uint32_t *pmc_remove_clamping_cmd_ptr = (void *)(PMC_CTLR_BASE + 0x34); |
| |
| static uint32_t *pmc_pwrgate_status_ptr = (void *)(PMC_CTLR_BASE + 0x38); |
| |
| static uint32_t *pmc_cpupwrgood_timer_ptr = (void *)(PMC_CTLR_BASE + 0xc8); |
| |
| static uint32_t *pmc_odmdata_ptr = (void *)(PMC_CTLR_BASE + 0xa0); |
| |
| static uint32_t *pmc_scratch4_ptr = (void *)(PMC_CTLR_BASE + 0x60); |
| enum { |
| PMC_WAKEUP_CLUSTER_LPCPU = 1 << 31 |
| }; |
| |
| static uint32_t *pmc_scratch190_ptr = (void *)(PMC_CTLR_BASE + 0x818); |
| |
| /* SCRATCH201 bit 1 is used to designate 77621 PMIC for CPU rail. */ |
| static uint32_t *pmc_scratch201_ptr = (void *)(PMC_CTLR_BASE + 0x844); |
| enum { |
| PMIC_77621 = 0x1 << 1 |
| }; |
| |
| static uint32_t *pmc_secure_scratch34_ptr = (void *)(PMC_CTLR_BASE + 0x368); |
| static uint32_t *pmc_secure_scratch35_ptr = (void *)(PMC_CTLR_BASE + 0x36c); |
| |
| static uint32_t *pmc_osc_edpd_over_ptr = (void *)(PMC_CTLR_BASE + 0x1a4); |
| enum { |
| PMC_XOFS_SHIFT = 1, |
| PMC_XOFS_MASK = 0x3f << PMC_XOFS_SHIFT |
| }; |
| |
| static uint32_t *pmc_sticky_bits_ptr = (void *)(PMC_CTLR_BASE + 0x2c0); |
| enum { |
| HDA_LPBK_DIS = 1 << 0, |
| }; |
| |
| static uint32_t *pmc_set_sw_clamp_ptr = (void *)(PMC_CTLR_BASE + 0x47c); |
| |
| /* Memory controller registers. */ |
| static uint32_t *mc_intstatus_ptr = (void *)(MC_CTLR_BASE); |
| static uint32_t *mc_intmask_ptr = (void *)(MC_CTLR_BASE + 0x4); |
| static uint32_t *mc_video_protect_size_mb_ptr = (void *)(MC_CTLR_BASE + 0x64c); |
| |
| static uint32_t *mc_video_protect_reg_ctrl_ptr = |
| (void *)(MC_CTLR_BASE + 0x650); |
| enum { |
| VPR_WR_ACCESS_DISABLE = 0x1 << 0, |
| VPR_ALLOW_TZ_WR_ACCESS = 0x1 << 1 |
| }; |
| /* FUSE registers */ |
| static uint32_t *fuse_security_mode_ptr = (void *)(FUSE_BASE + 0x1a0); |
| enum { |
| SECURITY_MODE = 0x1 << 0 |
| }; |
| |
| /* SECURE_BOOT registers */ |
| static uint32_t *sb_pfcfg_ptr = (void *)(SECURE_BOOT_BASE + 0x8); |
| enum { |
| SECURE_BOOT_DEBUG_CONFIG = 0x1 << 3 |
| }; |
| |
| static uint32_t *sb_aa64_reset_low = (void *)(SECURE_BOOT_BASE + 0x30); |
| static uint32_t *sb_aa64_reset_high = (void *)(SECURE_BOOT_BASE + 0x34); |
| |
| /* EMC registers */ |
| static uint32_t *pmacro_cfg_pm_global = (void *)(EMC_BASE + 0xc30); |
| enum { |
| DISABLE_CFG_BYTE0 = 0x1 << 16, |
| DISABLE_CFG_BYTE1 = 0x1 << 17, |
| DISABLE_CFG_BYTE2 = 0x1 << 18, |
| DISABLE_CFG_BYTE3 = 0x1 << 19, |
| DISABLE_CFG_BYTE4 = 0x1 << 20, |
| DISABLE_CFG_BYTE5 = 0x1 << 21, |
| DISABLE_CFG_BYTE6 = 0x1 << 22, |
| DISABLE_CFG_BYTE7 = 0x1 << 23, |
| DISABLE_CFG_BYTES = 0xff << 16, |
| ENABLE_CFG_BYTES = 0 << 16, |
| DISABLE_CFG_CMD0 = 0x1 << 24, |
| DISABLE_CFG_CMD1 = 0x1 << 25, |
| DISABLE_CFG_CMD2 = 0x1 << 26, |
| DISABLE_CFG_CMD3 = 0x1 << 27, |
| }; |
| |
| static uint32_t *pmacro_training_ctrl_0_ptr = (void *)(EMC_BASE + 0xcf8); |
| static uint32_t *pmacro_training_ctrl_1_ptr = (void *)(EMC_BASE + 0xcfc); |
| enum { |
| TRAINING_E_WRPTR = 0x1 << 3 |
| }; |
| |
| static uint32_t *fbio_cfg7_ptr = (void *)(EMC_BASE + 0x584); |
| enum { |
| CH1_ENABLE = 0x1 << 2 |
| }; |
| |
| /* I2C5 registers */ |
| static uint32_t *i2c5_cnfg_ptr = (void *)(I2C5_BASE + 0x0); |
| enum { |
| I2C_DEBOUNCE_CNT_4 = 2 << 12, |
| I2C_NEW_MASTER_FSM = 1 << 11, |
| I2C_SEND = 1 << 9, |
| I2C_LENGTH_2_BYTES = 1 << 1 |
| }; |
| |
| static uint32_t *i2c5_cmd_addr0_ptr = (void *)(I2C5_BASE + 0x4); |
| static uint32_t *i2c5_cmd_data1_ptr = (void *)(I2C5_BASE + 0xc); |
| static uint32_t *i2c5_status_ptr = (void *)(I2C5_BASE + 0x1c); |
| enum { |
| I2C_STATUS_BUSY = 1 << 8, |
| I2C_STATUS_CMD1_STAT_MASK = 0xf << 0, |
| I2C_STATUS_CMD1_XFER_SUCCESS = 0 << 0 |
| }; |
| |
| static uint32_t *i2c5_config_load_ptr = (void *)(I2C5_BASE + 0x8c); |
| enum { |
| MSTR_CONFIG_LOAD = 1 << 0 |
| }; |
| |
| #define MAX77620_I2C_ADDR (0x3c << 1) |
| #define MAX77620_GPIO5_DATA (0x3b | (0x9 << 8)) |
| |
| #define MAX77621_I2C_ADDR (0x1b << 1) |
| #define MAX77621_VOUT_REG 0x0 |
| #define MAX77621_VOUT_VAL (0x80 | 0x27) |
| #define MAX77621_VOUT_DATA (MAX77621_VOUT_REG | (MAX77621_VOUT_VAL << 8)) |
| |
| /* Utility functions. */ |
| |
| static __always_inline void __noreturn halt(void) |
| { |
| for (;;); |
| } |
| |
| static inline uint32_t read32(const void *addr) |
| { |
| return *(volatile uint32_t *)addr; |
| } |
| |
| static inline void write32(void *addr, uint32_t val) |
| { |
| *(volatile uint32_t *)addr = val; |
| } |
| |
| static inline void setbits32(uint32_t bits, void *addr) |
| { |
| write32(addr, read32(addr) | bits); |
| } |
| |
| static inline void clrbits32(uint32_t bits, void *addr) |
| { |
| write32(addr, read32(addr) & ~bits); |
| } |
| |
| static void __noreturn reset(void) |
| { |
| write32(clk_rst_rst_devices_l_ptr, SWR_TRIG_SYS_RST); |
| halt(); |
| } |
| |
| static void udelay(unsigned int usecs) |
| { |
| uint32_t start = read32(timer_us_ptr); |
| while (read32(timer_us_ptr) - start < usecs) |
| ; |
| } |
| |
| /* UART related defines */ |
| static uint32_t *uart_clk_out_enb_regs[4] = { |
| (uint32_t *)0x60006010, |
| (uint32_t *)0x60006010, |
| (uint32_t *)0x60006014, |
| (uint32_t *)0x60006018 |
| }; |
| |
| static uint32_t *uart_rst_devices_regs[4] = { |
| (uint32_t *)0x60006004, |
| (uint32_t *)0x60006004, |
| (uint32_t *)0x60006008, |
| (uint32_t *)0x6000600c |
| }; |
| |
| static uint32_t uart_enable_mask[4] = { |
| 1 << 6, |
| 1 << 7, |
| 1 << 23, |
| 1 << 1 |
| }; |
| |
| static uint32_t *uart_clk_source_regs[4] = { |
| (uint32_t *)0x60006178, |
| (uint32_t *)0x6000617c, |
| (uint32_t *)0x600061a0, |
| (uint32_t *)0x600061c0 |
| }; |
| |
| static uint32_t *uart_base_regs[4] = { |
| (uint32_t *)0x70006000, |
| (uint32_t *)0x70006040, |
| (uint32_t *)0x70006200, |
| (uint32_t *)0x70006300 |
| }; |
| |
| enum { |
| UART_THR_DLAB = 0x0, |
| UART_IER_DLAB = 0x1, |
| UART_IIR_FCR = 0x2, |
| UART_LCR = 0x3 |
| }; |
| enum { |
| UART_RATE_115200 = (408000000/115200/16), /* based on 408000000 PLLP */ |
| FCR_TX_CLR = 0x4, /* bit 2 of FCR : clear TX FIFO */ |
| FCR_RX_CLR = 0x2, /* bit 1 of FCR : clear RX FIFO */ |
| FCR_EN_FIFO = 0x1, /* bit 0 of FCR : enable TX & RX FIFO */ |
| LCR_DLAB = 0x80, /* bit 7 of LCR : Divisor Latch Access Bit */ |
| LCR_WD_SIZE_8 = 0x3 /* bit 1:0 of LCR : word length of 8 */ |
| }; |
| |
| static void enable_uart(void) |
| { |
| uint32_t *uart_clk_enb_reg; |
| uint32_t *uart_rst_reg; |
| uint32_t *uart_clk_source; |
| uint32_t uart_port; |
| uint32_t uart_mask; |
| uint32_t *uart_base; |
| |
| /* |
| * Read odmdata (stored in pmc->odmdata) to determine debug uart port. |
| * |
| * Bits 15-17 of odmdata contains debug uart port. |
| * 0 : UARTA |
| * 1 : UARTB |
| * 2 : UARTC |
| * 3 : UARTD |
| */ |
| uart_port = (read32(pmc_odmdata_ptr) >> 15) & 0x7; |
| |
| /* Default to UARTA if uart_port is out of range */ |
| if (uart_port >= 4) |
| uart_port = 0; |
| |
| uart_clk_enb_reg = uart_clk_out_enb_regs[uart_port]; |
| uart_rst_reg = uart_rst_devices_regs[uart_port]; |
| uart_mask = uart_enable_mask[uart_port]; |
| uart_clk_source = uart_clk_source_regs[uart_port]; |
| uart_base = uart_base_regs[uart_port]; |
| |
| /* Enable UART clock */ |
| setbits32(uart_mask, uart_clk_enb_reg); |
| |
| /* Reset and unreset UART */ |
| setbits32(uart_mask, uart_rst_reg); |
| clrbits32(uart_mask, uart_rst_reg); |
| |
| /* Program UART clock source: PLLP (408000000) */ |
| write32(uart_clk_source, 0); |
| |
| /* Program 115200n8 to the uart port */ |
| /* baud-rate of 115200 */ |
| write32((uart_base + UART_LCR), LCR_DLAB); |
| write32((uart_base + UART_THR_DLAB), (UART_RATE_115200 & 0xff)); |
| write32((uart_base + UART_IER_DLAB), (UART_RATE_115200 >> 8)); |
| /* 8-bit and no parity */ |
| write32((uart_base + UART_LCR), LCR_WD_SIZE_8); |
| /* enable and clear RX/TX FIFO */ |
| write32((uart_base + UART_IIR_FCR), |
| (FCR_TX_CLR + FCR_RX_CLR + FCR_EN_FIFO)); |
| } |
| |
| /* Accessors. */ |
| |
| /* Jtag configuration. */ |
| |
| static void enable_jtag(void) |
| { |
| write32(misc_pp_config_ctl_ptr, PP_CONFIG_CTL_JTAG); |
| } |
| |
| /* Clock configuration. */ |
| |
| static void config_oscillator(void) |
| { |
| /* |
| * Read oscillator drive strength from OSC_EDPD_OVER.XOFS and copy |
| * to OSC_CTRL.XOFS and set XOE. |
| */ |
| uint32_t xofs = (read32(pmc_osc_edpd_over_ptr) & |
| PMC_XOFS_MASK) >> PMC_XOFS_SHIFT; |
| |
| uint32_t osc_ctrl = read32(clk_rst_osc_ctrl_ptr); |
| osc_ctrl &= ~OSC_XOFS_MASK; |
| osc_ctrl |= (xofs << OSC_XOFS_SHIFT); |
| osc_ctrl |= OSC_XOE; |
| write32(clk_rst_osc_ctrl_ptr, osc_ctrl); |
| } |
| |
| static void enable_select_cpu_clocks(void) |
| { |
| /* Enable the CPU complex clock. */ |
| write32(clk_rst_clk_enb_l_set_ptr, CLK_ENB_CPU); |
| write32(clk_rst_clk_enb_v_set_ptr, CLK_ENB_CPUG); |
| udelay(10); |
| |
| /* Select CPU complex clock source. */ |
| write32(clk_rst_cclkg_burst_policy_ptr, CCLKG_PLLP_BURST_POLICY); |
| write32(clk_rst_cclklp_burst_policy_ptr, CCLKLP_PLLP_BURST_POLICY); |
| udelay(10); |
| } |
| |
| /* Function unit configuration. */ |
| |
| static void config_core_sight(void) |
| { |
| /* Enable the CoreSight clock. */ |
| write32(clk_rst_clk_out_enb_u_set_ptr, CLK_ENB_CSITE); |
| |
| /* |
| * De-assert CoreSight reset. |
| * NOTE: We're leaving the CoreSight clock on the oscillator for |
| * now. It will be restored to its original clock source |
| * when the CPU-side restoration code runs. |
| */ |
| write32(clk_rst_rst_dev_u_clr_ptr, SWR_CSITE_RST); |
| } |
| |
| /* RAM repair */ |
| |
| void ram_repair(void) |
| { |
| /* Request Cluster0 RAM repair. */ |
| setbits32(RAM_REPAIR_REQ, flow_ctlr_ram_repair_ptr); |
| /* Poll for Cluster0 RAM repair status. */ |
| while (!(read32(flow_ctlr_ram_repair_ptr) & RAM_REPAIR_STS)) |
| ; |
| } |
| |
| /* Power. */ |
| |
| static void power_on_partition(unsigned int id) |
| { |
| uint32_t bit = 0x1 << id; |
| if (!(read32(pmc_pwrgate_status_ptr) & bit)) { |
| /* Partition is not on. Turn it on. */ |
| write32(pmc_pwrgate_toggle_ptr, id | PWRGATE_TOGGLE_START); |
| |
| /* Wait until the partition is powerd on. */ |
| while (!(read32(pmc_pwrgate_status_ptr) & bit)) |
| ; |
| |
| /* Wait until clamp is off. */ |
| while (read32(pmc_clamp_status_ptr) & bit) |
| ; |
| } |
| } |
| |
| static void config_hda_lpbk_dis(void) |
| { |
| /* Set HDA_LPBK_DIS bit in APBDEV_PMC_STICKY_BITS_0 register */ |
| if (read32(fuse_security_mode_ptr) & SECURITY_MODE) |
| setbits32(HDA_LPBK_DIS, pmc_sticky_bits_ptr); |
| } |
| |
| static void set_gpio_pa6_input_mode(void) |
| { |
| setbits32(E_INPUT, pinmux_gpio_pa6_ptr); |
| } |
| |
| static void set_clk_m(void) |
| { |
| uint32_t spare; |
| |
| /* set clk_m frequency to 19.2MHz: set divisor to 2. */ |
| spare = read32(clk_rst_spare_reg0_ptr); |
| spare &= ~CLK_M_DIVISOR_MASK; |
| spare |= CLK_M_DIVISOR_BY_2; |
| write32(clk_rst_spare_reg0_ptr, spare); |
| |
| /* |
| * Restore TIMERUS config for 19.2MHz. (19.2 = 96/5 = 0x60/5) |
| * USEC_DIVIDEND(15:8) = 5-1; USEC_DIVISOR(7:0) = 0x60-1 |
| */ |
| write32(timer_us_cfg_ptr, 0x045f); |
| } |
| |
| static void restore_ram_svop(void) |
| { |
| uint32_t asdbgreg; |
| |
| asdbgreg = read32(misc_gp_asdbgreg_ptr); |
| asdbgreg &= ~CFG2TMC_RAM_SVOP_PDP_MASK; |
| asdbgreg |= CFG2TMC_RAM_SVOP_PDP_VAL_2; |
| write32(misc_gp_asdbgreg_ptr, asdbgreg); |
| } |
| |
| static void set_pmacro_training_wrptr(void) |
| { |
| /* disable writes to BYTES 7-0 of pad macro */ |
| write32(pmacro_cfg_pm_global, DISABLE_CFG_BYTES); |
| |
| /* Set E_WRPTR mode on Channel 0 and 1 */ |
| write32(pmacro_training_ctrl_0_ptr, TRAINING_E_WRPTR); |
| write32(pmacro_training_ctrl_1_ptr, TRAINING_E_WRPTR); |
| |
| /* Re-enable writes to BYTE0-7 */ |
| write32(pmacro_cfg_pm_global, ENABLE_CFG_BYTES); |
| } |
| |
| static uint32_t *i2s_0_master = (void *)(I2S_BASE + 0x0a0); |
| static uint32_t *i2s_1_master = (void *)(I2S_BASE + 0x1a0); |
| static uint32_t *i2s_2_master = (void *)(I2S_BASE + 0x2a0); |
| static uint32_t *i2s_3_master = (void *)(I2S_BASE + 0x3a0); |
| static uint32_t *i2s_4_master = (void *)(I2S_BASE + 0x4a0); |
| |
| static uint32_t *i2s_0_slcg = (void *)(I2S_BASE + 0x088); |
| static uint32_t *i2s_1_slcg = (void *)(I2S_BASE + 0x188); |
| static uint32_t *i2s_2_slcg = (void *)(I2S_BASE + 0x288); |
| static uint32_t *i2s_3_slcg = (void *)(I2S_BASE + 0x388); |
| static uint32_t *i2s_4_slcg = (void *)(I2S_BASE + 0x488); |
| |
| static uint32_t *clk_rst_ape_clear = (void *)(CLK_RST_BASE + 0x2ac); |
| static uint32_t *clk_rst_ape_set = (void *)(CLK_RST_BASE + 0x2a8); |
| |
| static void mbist_workaround(void) |
| { |
| uint32_t clks_to_be_cleared; |
| uint32_t i2s_read; |
| |
| write32(clk_rst_ape_clear, 0x40); |
| udelay(2); |
| |
| i2s_read = read32(i2s_0_master); |
| i2s_read |= 0x400; |
| write32(i2s_0_master, i2s_read); |
| |
| i2s_read = read32(i2s_0_slcg); |
| i2s_read &= ~1; |
| write32(i2s_0_slcg, i2s_read); |
| |
| i2s_read = read32(i2s_1_master); |
| i2s_read |= 0x400; |
| write32(i2s_1_master, i2s_read); |
| |
| i2s_read = read32(i2s_1_slcg); |
| i2s_read &= ~1; |
| write32(i2s_1_slcg, i2s_read); |
| |
| i2s_read = read32(i2s_2_master); |
| i2s_read |= 0x400; |
| write32(i2s_2_master, i2s_read); |
| |
| i2s_read = read32(i2s_2_slcg); |
| i2s_read &= ~1; |
| write32(i2s_2_slcg, i2s_read); |
| |
| i2s_read = read32(i2s_3_master); |
| i2s_read |= 0x400; |
| write32(i2s_3_master, i2s_read); |
| |
| i2s_read = read32(i2s_3_slcg); |
| i2s_read &= ~1; |
| write32(i2s_3_slcg, i2s_read); |
| |
| i2s_read = read32(i2s_4_master); |
| i2s_read |= 0x400; |
| write32(i2s_4_master, i2s_read); |
| |
| i2s_read = read32(i2s_4_slcg); |
| i2s_read &= ~1; |
| write32(i2s_4_slcg, i2s_read); |
| |
| udelay(2); |
| |
| write32(clk_rst_lvl2_clk_gate_ovra_ptr, 0); |
| write32(clk_rst_lvl2_clk_gate_ovrb_ptr, 0); |
| write32(clk_rst_lvl2_clk_gate_ovrc_ptr, 0x00000002); |
| write32(clk_rst_lvl2_clk_gate_ovrd_ptr, 0x01000000); /* QSPI OVR=1 */ |
| write32(clk_rst_lvl2_clk_gate_ovre_ptr, 0x00000c00); |
| |
| clks_to_be_cleared = read32(clk_rst_clk_out_enb_l_ptr); |
| clks_to_be_cleared &= ~MBIST_CLK_ENB_L_0; |
| write32(clk_rst_clk_enb_l_clr_ptr, clks_to_be_cleared); |
| |
| clks_to_be_cleared = read32(clk_rst_clk_out_enb_h_ptr); |
| clks_to_be_cleared &= ~MBIST_CLK_ENB_H_0; |
| write32(clk_rst_clk_enb_h_clr_ptr, clks_to_be_cleared); |
| |
| clks_to_be_cleared = read32(clk_rst_clk_out_enb_u_ptr); |
| clks_to_be_cleared &= ~MBIST_CLK_ENB_U_0; |
| write32(clk_rst_clk_enb_u_clr_ptr, clks_to_be_cleared); |
| |
| clks_to_be_cleared = read32(clk_rst_clk_out_enb_v_ptr); |
| clks_to_be_cleared &= ~MBIST_CLK_ENB_V_0; |
| write32(clk_rst_clk_enb_v_clr_ptr, clks_to_be_cleared); |
| |
| clks_to_be_cleared = read32(clk_rst_clk_out_enb_w_ptr); |
| clks_to_be_cleared &= ~MBIST_CLK_ENB_W_0; |
| write32(clk_rst_clk_enb_w_clr_ptr, clks_to_be_cleared); |
| |
| clks_to_be_cleared = read32(clk_rst_clk_out_enb_x_ptr); |
| clks_to_be_cleared &= ~MBIST_CLK_ENB_X_0; |
| write32(clk_rst_clk_enb_x_clr_ptr, clks_to_be_cleared); |
| |
| clks_to_be_cleared = read32(clk_rst_clk_out_enb_y_ptr); |
| clks_to_be_cleared &= ~MBIST_CLK_ENB_Y_0; |
| write32(clk_rst_clk_enb_y_clr_ptr, clks_to_be_cleared); |
| |
| if (read32(fbio_cfg7_ptr) & CH1_ENABLE) |
| /* if Dual Channel enable MC1 clock */ |
| write32(clk_rst_clk_enb_w_set_ptr, CLK_ENB_MC1); |
| } |
| |
| static uint32_t *sdmmc1_vendor_io_trim = (void *)(TEGRA_SDMMC1_BASE + 0x1ac); |
| static uint32_t *sdmmc3_vendor_io_trim = (void *)(TEGRA_SDMMC3_BASE + 0x1ac); |
| static uint32_t *sdmmc1_comppadctrl = (void *)(TEGRA_SDMMC1_BASE + 0x1e0); |
| static uint32_t *sdmmc3_comppadctrl = (void *)(TEGRA_SDMMC3_BASE + 0x1e0); |
| |
| enum { |
| SDMMC1_DEV_L = 0x1 << 14, |
| SDMMC3_DEV_U = 0x1 << 5, |
| PAD_E_INPUT_COMPPADCTRL = 0x1 << 31, |
| SEL_VREG_VENDOR_IO_TRIM = 0x1 << 2 |
| }; |
| |
| static void low_power_sdmmc_pads(void) |
| { |
| /* Enable SDMMC1 clock */ |
| setbits32(SDMMC1_DEV_L, clk_rst_clk_out_enb_l_ptr); |
| udelay(2); |
| /* Unreset SDMMC1 */ |
| clrbits32(SDMMC1_DEV_L, clk_rst_rst_devices_l_ptr); |
| |
| /* Clear SEL_VREG bit and PAD_E_INPUT bit of SDMMC1 */ |
| clrbits32(SEL_VREG_VENDOR_IO_TRIM, sdmmc1_vendor_io_trim); |
| clrbits32(PAD_E_INPUT_COMPPADCTRL, sdmmc1_comppadctrl); |
| /* Read the last accessed SDMMC1 register then disable SDMMC1 clock */ |
| read32(sdmmc1_comppadctrl); |
| /* Disable SDMMC1 clock, but keep SDMMC1 un-reset */ |
| clrbits32(SDMMC1_DEV_L, clk_rst_clk_out_enb_l_ptr); |
| |
| /* Enable SDMMC3 clock */ |
| setbits32(SDMMC3_DEV_U, clk_rst_clk_out_enb_u_ptr); |
| udelay(2); |
| /* Unreset SDMMC3 */ |
| clrbits32(SDMMC3_DEV_U, clk_rst_rst_devices_u_ptr); |
| |
| /* Clear SEL_VREG bit and PAD_E_INPUT bit of SDMMC3 */ |
| clrbits32(SEL_VREG_VENDOR_IO_TRIM, sdmmc3_vendor_io_trim); |
| clrbits32(PAD_E_INPUT_COMPPADCTRL, sdmmc3_comppadctrl); |
| /* Read the last accessed SDMMC3 register then disable SDMMC3 clock */ |
| read32(sdmmc3_comppadctrl); |
| /* Disable SDMMC3 clock, but keep SDMMC3 un-reset */ |
| clrbits32(SDMMC3_DEV_U, clk_rst_clk_out_enb_u_ptr); |
| } |
| |
| static void config_mselect(void) |
| { |
| /* Set MSELECT clock source to PLL_P with 1:4 divider */ |
| write32(clk_rst_clk_source_mselect_ptr, |
| (CLK_SRC_PLLP_OUT0 | MSELECT_CLK_DIVISOR_4)); |
| /* Enable clock to MSELECT */ |
| write32(clk_rst_clk_enb_v_ptr, CLK_ENB_MSELECT); |
| /* Bring MSELECT out of reset, after 2 microsecond wait */ |
| udelay(2); |
| write32(clk_rst_rst_dev_v_clr_ptr, MSELECT_RST); |
| } |
| |
| /* Routine to do i2c send of 'data' to 'addr' */ |
| static void i2c_send(uint32_t addr, uint32_t data) |
| { |
| uint32_t delay; |
| |
| write32(i2c5_cmd_addr0_ptr, addr); |
| write32(i2c5_cmd_data1_ptr, data); |
| |
| write32(i2c5_cnfg_ptr, (I2C_DEBOUNCE_CNT_4 | I2C_NEW_MASTER_FSM | |
| I2C_LENGTH_2_BYTES)); |
| |
| write32(i2c5_config_load_ptr, MSTR_CONFIG_LOAD); |
| delay = 0; |
| while (read32(i2c5_config_load_ptr) & MSTR_CONFIG_LOAD) { |
| udelay(1); |
| if (++delay > 100) |
| reset(); |
| } |
| |
| write32(i2c5_cnfg_ptr, (I2C_DEBOUNCE_CNT_4 | I2C_NEW_MASTER_FSM | |
| I2C_SEND | I2C_LENGTH_2_BYTES)); |
| |
| /* Check busy */ |
| delay = 0; |
| while (read32(i2c5_status_ptr) & I2C_STATUS_BUSY) { |
| udelay(1); |
| if (++delay > 1000) |
| reset(); |
| } |
| |
| /* Check xfer successful; */ |
| if (read32(i2c5_status_ptr) & I2C_STATUS_CMD1_STAT_MASK) |
| reset(); |
| } |
| |
| /* Entry point. */ |
| |
| void lp0_resume(void) |
| { |
| uint32_t orig_timer; |
| |
| /* If not on the AVP, reset. */ |
| if (read32(up_tag_ptr) != UP_TAG_AVP) |
| reset(); |
| |
| /* Enable JTAG */ |
| enable_jtag(); |
| |
| /* Set HDA_LPBK_DIS bit in APBDEV_PMC_STICKY_BITS_0 register */ |
| config_hda_lpbk_dis(); |
| |
| /* |
| * From T210 TRM: |
| * 8.9.1.2 Deep Sleep Exit: |
| * 5.a: Set the E_INPUT bit of the PINMUX_AUX_GPIO_PA6_0 register |
| * to Logic 1. |
| */ |
| set_gpio_pa6_input_mode(); |
| |
| config_oscillator(); |
| |
| /* set clk_m frequency to 19.2MHz */ |
| set_clk_m(); |
| |
| /* Restore RAM SVOP setting */ |
| restore_ram_svop(); |
| |
| /* Bad qpop value on cmd pad macros removes clock gating from IB path */ |
| set_pmacro_training_wrptr(); |
| |
| /* Restore CAR CE's, SLCG overrides */ |
| mbist_workaround(); |
| |
| /* Configure unused SDMMC1/3 pads for low power leakage */ |
| low_power_sdmmc_pads(); |
| |
| /* |
| * Find out which CPU (slow or fast) to wake up. The default setting |
| * in flow controller is to wake up GCPU |
| */ |
| if (read32(pmc_scratch4_ptr) & PMC_WAKEUP_CLUSTER_LPCPU) { |
| setbits32(ACTIVE_SLOW, flow_ctlr_bpmp_cluster_control_ptr); |
| } |
| |
| /* Set the CPU reset vector */ |
| write32(sb_aa64_reset_low, (read32(pmc_secure_scratch34_ptr) | 1)); |
| write32(sb_aa64_reset_high, read32(pmc_secure_scratch35_ptr)); |
| |
| /* Program SUPER_CCLK_DIVIDER. */ |
| write32(clk_rst_super_cclkg_div_ptr, SUPER_CDIV_ENB); |
| write32(clk_rst_super_cclklp_div_ptr, SUPER_CDIV_ENB); |
| |
| config_core_sight(); |
| |
| /* Set MSELECT clock source to PLL_P with 1:4 divider */ |
| config_mselect(); |
| |
| /* Enable UART */ |
| enable_uart(); |
| |
| /* Disable PLLX since it isn't used in the kernel as CPU clk source. */ |
| clrbits32(PLLX_ENABLE, clk_rst_pllx_base_ptr); |
| |
| /* Set CAR2PMC_CPU_ACK_WIDTH to 0 */ |
| clrbits32(CAR2PMC_CPU_ACK_WIDTH_MASK, clk_rst_cpu_softrst_ctrl2_ptr); |
| |
| /* Clear PMC_SCRATCH190 */ |
| clrbits32(1, pmc_scratch190_ptr); |
| |
| /* Clear PMC_DPD_SAMPLE */ |
| write32(pmc_dpd_sample_ptr, 0); |
| udelay(10); |
| |
| /* Clear the MC_INTSTATUS if MC_INTMASK was 0. */ |
| if (!read32(mc_intmask_ptr)) { |
| uint32_t mc_intst_val = read32(mc_intstatus_ptr); |
| if (mc_intst_val) |
| write32(mc_intstatus_ptr, mc_intst_val); |
| } |
| |
| /* |
| * Set both _ACCESS bits so that kernel/secure code |
| * can reconfig VPR careveout as needed from the TrustZone. |
| */ |
| write32(mc_video_protect_size_mb_ptr, 0); |
| write32(mc_video_protect_reg_ctrl_ptr, |
| VPR_WR_ACCESS_DISABLE | VPR_ALLOW_TZ_WR_ACCESS); |
| |
| /* Tristate CLDVFS PWM */ |
| write32(pinmux_dvfs_pwm_ptr, (TRISTATE | PM_CLDVFS)); |
| |
| /* Restore PWR I2C pinmux configuration */ |
| write32(pinmux_pwr_i2c_scl_ptr, (E_INPUT | PM_I2CPMU)); |
| write32(pinmux_pwr_i2c_sda_ptr, (E_INPUT | PM_I2CPMU)); |
| |
| /* Enable CLDVFS clock */ |
| write32(clk_rst_clk_enb_w_set_ptr, CLK_ENB_DVFS); |
| |
| /* Set CLDVFS clock source and divider */ |
| write32(clk_rst_clk_dvfs_ref_ptr, DVFS_REF_CLK_DIVISOR); |
| write32(clk_rst_clk_dvfs_soc_ptr, DVFS_SOC_CLK_DIVISOR); |
| |
| /* Enable PWR I2C controller */ |
| write32(clk_rst_clk_enb_h_set_ptr, CLK_ENB_I2C5); |
| write32(clk_rst_rst_dev_h_set_ptr, I2C5_RST); |
| udelay(5); |
| write32(clk_rst_clk_source_i2c5_ptr, CLK_SRC_PLLP_OUT0 | I2C5_CLK_DIVISOR); |
| write32(clk_rst_rst_dev_h_clr_ptr, I2C5_RST); |
| |
| /* |
| * Turn on CPU rail: |
| * SCRATCH201[1] is being used to identify CPU PMIC in warmboot code. |
| * 0 : OVR2 |
| * 1 : MAX77621 |
| */ |
| if (read32(pmc_scratch201_ptr) & PMIC_77621) |
| /* Set CPU rail 0.85V */ |
| i2c_send(MAX77621_I2C_ADDR, MAX77621_VOUT_DATA); |
| else |
| /* Enable GPIO5 on MAX77620 PMIC */ |
| i2c_send(MAX77620_I2C_ADDR, MAX77620_GPIO5_DATA); |
| |
| /* Disable PWR I2C */ |
| write32(clk_rst_rst_dev_h_set_ptr, I2C5_RST); |
| write32(clk_rst_clk_enb_h_clr_ptr, CLK_ENB_I2C5); |
| |
| /* Delay before removing clamp */ |
| udelay(2000); |
| |
| /* |
| * Reprogram PMC_CPUPWRGOOD_TIMER register: |
| * |
| * XXX This is a fragile assumption. XXX |
| * The kernel prepares PMC_CPUPWRGOOD_TIMER based on a 32768Hz clock. |
| * Note that PMC_CPUPWRGOOD_TIMER is running at pclk. |
| * |
| * We need to reprogram PMC_CPUPWRGOOD_TIMER based on the current pclk |
| * which is at 204Mhz (pclk = sclk = pllp_out2) after BootROM. Multiply |
| * PMC_CPUPWRGOOD_TIMER by 204M / 32K. |
| * |
| * Save the original PMC_CPUPWRGOOD_TIMER register which we need to |
| * restore after the CPU is powered up. |
| */ |
| orig_timer = read32(pmc_cpupwrgood_timer_ptr); |
| write32(pmc_cpupwrgood_timer_ptr, orig_timer * (204000000 / 32768)); |
| |
| /* Power on CRAIL in PMC */ |
| power_on_partition(PARTID_CRAIL); |
| |
| /* Remove SW controlled clamp */ |
| write32(pmc_set_sw_clamp_ptr, 0); |
| write32(pmc_remove_clamping_cmd_ptr, (1 << PARTID_CRAIL)); |
| /* Wait until clamp is off. */ |
| while (read32(pmc_clamp_status_ptr) & (1 << PARTID_CRAIL)) |
| ; |
| |
| /* Disable CLDVFS clock */ |
| write32(clk_rst_clk_enb_w_clr_ptr, CLK_ENB_DVFS); |
| |
| /* Perform fast cluster RAM repair. */ |
| if (!(read32(flow_ctlr_bpmp_cluster_control_ptr) & ACTIVE_SLOW)) |
| ram_repair(); |
| |
| /* Power up the non-CPU partition. */ |
| power_on_partition(PARTID_C0NC); |
| |
| /* Enable PLLP branch going to CPU */ |
| write32(clk_rst_clk_enb_y_set_ptr, CLK_ENB_PLLP_OUT_CPU); |
| udelay(2); |
| |
| /* Enable the CPU complex clocks */ |
| enable_select_cpu_clocks(); |
| udelay(10); |
| |
| /* Take non-cpu OUT of reset */ |
| write32(clk_rst_cpug_cmplx_clr_ptr, CLR_NONCPURESET); |
| |
| /* Power up the CPU0 partition. */ |
| power_on_partition(PARTID_CE0); |
| |
| /* Restore the original PMC_CPUPWRGOOD_TIMER. */ |
| write32(pmc_cpupwrgood_timer_ptr, orig_timer); |
| |
| /* Clear software controlled reset */ |
| write32(clk_rst_cpug_cmplx_clr_ptr, (CLR_CPURESET0 | CLR_CORERESET0)); |
| |
| /* Halt the AVP. */ |
| while (1) |
| write32(flow_ctlr_halt_cop_events_ptr, |
| FLOW_MODE_STOP | EVENT_JTAG); |
| } |
| |
| /* Header. */ |
| |
| extern uint8_t blob_data; |
| extern uint8_t blob_data_size; |
| extern uint8_t blob_total_size; |
| |
| struct lp0_header { |
| uint32_t length_insecure; // Insecure total length. |
| uint32_t reserved[3]; |
| uint8_t rsa_modulus[256]; // RSA key modulus. |
| uint8_t aes_signature[16]; // AES signature. |
| uint8_t rsa_signature[256]; // RSA-PSS signature. |
| uint8_t random_aes_block[16]; // Random data, may be zero. |
| uint32_t length_secure; // Secure total length. |
| uint32_t destination; // Where to load the blob in iRAM. |
| uint32_t entry_point; // Entry point for the blob. |
| uint32_t code_length; // Length of just the data. |
| } __packed; |
| |
| struct lp0_header header __attribute__((section(".header"))) = |
| { |
| .length_insecure = (uintptr_t)&blob_total_size, |
| .length_secure = (uintptr_t)&blob_total_size, |
| .destination = (uintptr_t)&blob_data, |
| .entry_point = (uintptr_t)&lp0_resume, |
| .code_length = (uintptr_t)&blob_data_size |
| }; |