/* * Copyright (C) 2012-2014 Apple Inc. All rights reserved. * * This document is the property of Apple Inc. * It is considered confidential and proprietary. * * This document may not be reproduced or transmitted in any form, * in whole or in part, without the express written permission of * Apple Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if SUB_TARGET_J81 || SUB_TARGET_J82 || SUB_TARGET_J96 || SUB_TARGET_J97 || SUB_TARGET_J98 || SUB_TARGET_J99 #include #endif extern void arm_no_wfe_spin(uint32_t usecs); struct clock_source { uint32_t src_clk; uint32_t factor; }; #define CLOCK_SOURCES_MAX 12 struct clock_config { volatile uint32_t *clock_reg; // CLK_CFG Register struct clock_source sources[CLOCK_SOURCES_MAX]; // List of sources }; #define PLL_VCO_TARGET(pllx) ((2ULL * (pllx##_O) * (pllx##_M)) / (pllx##_P)) #define PLL_FREQ_TARGET(pllx) (((pllx##_O) * (pllx##_M)) / (pllx##_P) / ((pllx##_S) + 1)) #if APPLICATION_SECUREROM static uint32_t active_state = kDVFM_STATE_SECUREROM; #endif #if APPLICATION_IBOOT static uint32_t active_state = kDVFM_STATE_IBOOT; #endif static uint64_t ccc_dvfm_states[] = { #if APPLICATION_SECUREROM // BIU div = 1, disable voltage change sequence, Clk src = Ref clk. [kDVFM_STATE_BYPASS] = (2ULL << 18)|(1ULL << 22), // CCC @ 300 MHz, disable voltage change sequence, Clk src = PLL, BIU div = 1. [kDVFM_STATE_SECUREROM] = CCC_DVFM_ST_PLL_P(1) | CCC_DVFM_ST_PLL_M(50) | CCC_DVFM_ST_PLL_S(3) |(1ULL << 22)| (1ULL << 21)|(2ULL << 18), #else // BIU div = 1, Clk src = Ref clk. [kDVFM_STATE_BYPASS] = (2ULL << 18), #endif #if APPLICATION_IBOOT // CCC V0 // CCC @ 396 MHz, enable voltage change sequence, Clk src = PLL, BIU div = 1. [kDVFM_STATE_IBOOT] = CCC_DVFM_ST_PLL_P(1) | CCC_DVFM_ST_PLL_M(33) | CCC_DVFM_ST_PLL_S(1) | (1ULL << 21) | (2ULL << 18), // CCC V1 // CCC @ 600 MHz, enable voltage change sequence, Clk src = PLL, BIU div = 1. [kDVFM_STATE_V1] = CCC_DVFM_ST_PLL_P(1) | CCC_DVFM_ST_PLL_M(25) | CCC_DVFM_ST_PLL_S(0) | (1ULL << 21) | (2ULL << 18), // CCC V2 // CCC @ 840 MHz, enable voltage change sequence, Clk src = PLL, BIU div = 2. [kDVFM_STATE_V2] = CCC_DVFM_ST_PLL_P(1) | CCC_DVFM_ST_PLL_M(35) | CCC_DVFM_ST_PLL_S(0) | (1ULL << 21) | (4ULL << 18), // CCC V3 // CCC @ 1128 MHz, enable voltage change sequence, Clk src = PLL, BIU div = 2 [kDVFM_STATE_V3] = CCC_DVFM_ST_PLL_P(1) | CCC_DVFM_ST_PLL_M(47) | CCC_DVFM_ST_PLL_S(0) | (1ULL << 21) | (4ULL << 18), #if !SUB_TARGET_N102 // CCC V4 // CCC @ 1392 MHz, enable voltage change sequence, Clk src = PLL, BIU div = 3.0 [kDVFM_STATE_V4] = CCC_DVFM_ST_PLL_P(1) | CCC_DVFM_ST_PLL_M(58) | CCC_DVFM_ST_PLL_S(0) | (1ULL << 21) | (6ULL << 18) #endif #if SUB_PLATFORM_T7001 || SUB_TARGET_J96 || SUB_TARGET_J97 // CCC V5 // CCC @ 1512 MHz, enable voltage change sequence, Clk src = PLL, BIU div = 3.0 ,[kDVFM_STATE_V5] = CCC_DVFM_ST_PLL_P(1) | CCC_DVFM_ST_PLL_M(63) | CCC_DVFM_ST_PLL_S(0) | (1ULL << 21) | (6ULL << 18) // CCC V6 (pseudo-state) // CCC @ 1608 MHz, enable voltage change sequence, Clk src = PLL, BIU div = 3.0 ,[kDVFM_STATE_V6] = CCC_DVFM_ST_PLL_P(1) | CCC_DVFM_ST_PLL_M(67) | CCC_DVFM_ST_PLL_S(0) | (1ULL << 21) | (6ULL << 18) // CCC V6 Unbinned (pseudo-state) // CCC @ 1608 MHz, enable voltage change sequence, Clk src = PLL, BIU div = 3.0 ,[kDVFM_STATE_V6_UNBINNED] = CCC_DVFM_ST_PLL_P(1) | CCC_DVFM_ST_PLL_M(67) | CCC_DVFM_ST_PLL_S(0) | (1ULL << 21) | (6ULL << 18) #endif #endif }; #if APPLICATION_SECUREROM #define SOC_PERF_STATE_ACTIVE kSOC_PERF_STATE_SECUREROM #endif #if APPLICATION_IBOOT #define SOC_PERF_STATE_ACTIVE kSOC_PERF_STATE_IBOOT_MEM_FULL_PERF #endif struct pmgr_soc_perf_state { uint32_t entry[3]; }; static struct pmgr_soc_perf_state pmgr_soc_perf_states[] = { [kSOC_PERF_STATE_BYPASS] = { {0x00000000, 0x00000000, #if SUB_PLATFORM_T7000 0x00000070}}, #elif SUB_PLATFORM_T7001 0x00000000}}, #endif #if APPLICATION_SECUREROM [kSOC_PERF_STATE_SECUREROM] = { // af = pll4 div 5 // lio = pll4 div 10 {0x00055000, 0x00000000, #if SUB_PLATFORM_T7000 0x00000070}}, #elif SUB_PLATFORM_T7001 0x00000000}}, #endif #endif #if APPLICATION_IBOOT // Memory Low Performance: [kSOC_PERF_STATE_IBOOT_MEM_LOW_PERF] = { // mcu_fixed = pll1 // mcu = pll1 div 16 // mcu_cfg = 0x3 // af = pll4 div 5 // lio = pll4 div 10 // media_af = pll4 div 6 // isp_af = pll4 div 6 {0x06655361, // isp_c = pll4 div 6 // isp = pll4 div 8 // vdec = pll4 div 10 // venc = pll4 div 7 // ajpeg_ip = pll4 div 14 // ajpeg_wrap = pll4 div 11 // msr = pll4 div 8 0x07887876, 0x00000000}}, // Memory Full Performance / VMIN: [kSOC_PERF_STATE_IBOOT_MEM_FULL_PERF] = { #if !SUPPORT_FPGA // mcu_fixed = pll1 // mcu = pll1 // mcu_cfg = 0x0 // af = pll4 div 5 // lio = pll4 div 10 // media_af = pll4 div 6 // isp_af = pll4 div 6 {0x06655081, #else // mcu_fixed = pll1 // mcu = pll1 div 16 // mcu_cfg = 0x3 // af = pll4 div 5 // lio = pll4 div 10 // media_af = pll4 div 6 // isp_af = pll4 div 6 {0x06655361, #endif // isp_c = pll4 div 6 // isp = pll4 div 8 // vdec = pll4 div 10 // venc = pll4 div 7 // ajpeg_ip = pll4 div 14 // ajpeg_wrap = pll4 div 11 // msr = pll4 div 8 0x07887876, 0x00000000}}, // VNOM: [kSOC_PERF_STATE_VNOM] = { #if !SUPPORT_FPGA // mcu_fixed = pll1 // mcu = pll1 // mcu_cfg = 0x0 // af = pll4 div 5 // lio = pll4 div 10 // media_af = pll4 div 5 // isp_af = pll4 div 5 {0x05555081, #else // mcu_fixed = pll1 // mcu = pll1 div 16 // mcu_cfg = 0x3 // af = pll4 div 5 // lio = pll4 div 10 // media_af = pll4 div 5 // isp_af = pll4 div 5 {0x05555361, #endif // isp_c = pll4 div 5 // isp = pll4 div 7 // vdec = pll4 div 7 // venc = pll4 div 5 // ajpeg_ip = pll4 div 10 // ajpeg_wrap = pll4 div 8 // msr = pll4 div 6 0x05555565, 0x00000000}}, #endif }; #if APPLICATION_SECUREROM static uint32_t perf_level = kPerformanceHigh; #endif #if APPLICATION_IBOOT static uint32_t perf_level = kPerformanceMemoryFull; #endif #if APPLICATION_IBOOT #if SUB_PLATFORM_T7000 && WITH_HW_MIPI /* MIPI: PLL0 @900MHz */ #define PLL0 0 #define PLL0_O OSC_FREQ #define PLL0_P 2 #define PLL0_M 150 #define PLL0_S 1 #define PLL0_V PLL_VCO_TARGET(PLL0) #define PLL0_T PLL_FREQ_TARGET(PLL0) #endif #if TARGET_DDR_740M /* PLL1 @740MHz */ #define PLL1 1 #define PLL1_O OSC_FREQ #define PLL1_P 6 #define PLL1_M 185 #define PLL1_S 0 #define PLL1_V PLL_VCO_TARGET(PLL1) #define PLL1_T PLL_FREQ_TARGET(PLL1) #elif TARGET_DDR_798M /* PLL1 @798MHz */ #define PLL1 1 #define PLL1_O OSC_FREQ #define PLL1_P 4 #define PLL1_M 133 #define PLL1_S 0 #define PLL1_V PLL_VCO_TARGET(PLL1) #define PLL1_T PLL_FREQ_TARGET(PLL1) #elif TARGET_DDR_792M /* PLL1 @792MHz */ #define PLL1 1 #define PLL1_O OSC_FREQ #define PLL1_P 1 #define PLL1_M 66 #define PLL1_S 1 #define PLL1_V PLL_VCO_TARGET(PLL1) #define PLL1_T PLL_FREQ_TARGET(PLL1) #else /* PLL1 @800MHz */ #define PLL1 1 #define PLL1_O OSC_FREQ #define PLL1_P 3 #define PLL1_M 100 #define PLL1_S 0 #define PLL1_V PLL_VCO_TARGET(PLL1) #define PLL1_T PLL_FREQ_TARGET(PLL1) #endif // Support 100 MHz PLL3 on Capri for PCIe #if SUB_PLATFORM_T7001 /* PLL3 @100MHz */ #define PLL3 3 #define PLL3_O OSC_FREQ #define PLL3_P 1 #define PLL3_M 50 #define PLL3_S 11 #define PLL3_V PLL_VCO_TARGET(PLL3) #define PLL3_T PLL_FREQ_TARGET(PLL3) #endif /* PLL4 @2400MHz (VCO output) */ #define PLL4 4 #define PLL4_O OSC_FREQ #define PLL4_P 1 #define PLL4_M 50 #define PLL4_S 0 #define PLL4_V PLL_VCO_TARGET(PLL4) #define PLL4_T PLL_FREQ_TARGET(PLL4) #define PLL4_VCO_ENABLED 1 #ifndef TARGET_SPARE0_CLK_CFG #define TARGET_SPARE0_CLK_CFG 0x00000000 #endif #define VID0_CLKD TARGET_VID0_CLK_CFG #if SUB_PLATFORM_T7000 #if WITH_HW_MIPI #define MIPI_CLKD 0x88100000 #else #define MIPI_CLKD 0x80100000 #endif static const uint32_t clk_divs_active[PMGR_CLK_CFG_COUNT] = { 0x81100000, 0x88100000, MIPI_CLKD, 0x86100000, // 0x10000: mcu_fixed, mcu, mipi_dsi, nco_ref0, 0x85100000, 0x80100000, 0x88100000, 0x85100000, // 0x10010: nco_ref1, nco_alg0, nco_alg1, hsciphy_ref_12m, 0x85100000, 0x85100000, 0x85100000, 0x85100000, // 0x10020: usb480_0, usb480_1, usb_ohci_48m, usb, 0x85100000, 0x85100000, 0x80100000, 0x85100000, // 0x10030: usb_free_60m, sio_c, sio_p, isp_c, 0x86100000, 0x81100000, 0x82100000, 0x85100000, // 0x10040: isp, isp_sensor0_ref, isp_sensor1_ref, vdec, 0x85100000, VID0_CLKD, 0x86100000, 0x86100000, // 0x10050: venc, vid0, disp0, disp1, 0x85100000, 0x85100000, 0x85100000, 0x85100000, // 0x10060: ajpeg_ip, ajpeg_wrap, msr, af, 0x85100000, 0x85100000, 0x86100000, 0x87100000, // 0x10070: lio, mca0_m, mca1_m, mca2_m 0x88100000, 0x89100000, 0x85100000, 0x86100000, // 0x10080: mca3_m, mca4_m, sep, gpio, 0x85100000, 0x85100000, 0x85100000, 0x85100000, // 0x10090: spi0_n, spi1_n, spi2_n, spi3_n 0x80100000, 0x80100000, 0x85100000, 0x85100000, // 0x100A0: debug, pcie_ref, pcie_app, tmps, 0x85100000, 0x85100000, 0x86100000, 0x85100000, // 0x100B0: media_af, isp_af, gfx_af, ans_c 0x85100000 // 0x100C0: anc_link }; #elif SUB_PLATFORM_T7001 static const uint32_t clk_divs_active[PMGR_CLK_CFG_COUNT] = { 0x81100000, 0x88100000, 0x86100000, 0x85100000, // 0x10000: mcu_fixed, mcu, nco_ref0, nco_ref1, 0x80100000, 0x88100000, 0x85100000, 0x85100000, // 0x10010: nco_alg0, nco_alg1, hsciphy_ref_12m, usb480_0, 0x85100000, 0x85100000, 0x85100000, 0x85100000, // 0x10020: usb480_1, usb_ohci_48m, usb, usb_free_60m, 0x85100000, 0x80100000, 0x85100000, 0x86100000, // 0x10030: sio_c, sio_p, isp_c, isp, 0x81100000, 0x82100000, 0x85100000, 0x85100000, // 0x10040: isp_sensor0_ref, isp_sensor1_ref, vdec, venc, VID0_CLKD, 0x85100000, 0x86100000, 0x85100000, // 0x10050: vid0, disp0, disp1, ajpeg_ip, 0x85100000, 0x85100000, 0x85100000, 0x85100000, // 0x10060: ajpeg_wrap, msr, af, lio, 0x85100000, 0x86100000, 0x87100000, 0x88100000, // 0x10070: mca0_m, mca1_m, mca2_m, mca3_m, 0x89100000, 0x85100000, 0x86100000, 0x85100000, // 0x10080: mca4_m, sep, gpio, spi0_n, 0x85100000, 0x85100000, 0x85100000, 0x80100000, // 0x10090: spi1_n, spi2_n, spi3_n, debug, 0x85100000, 0x85100000, 0x85100000, 0x85100000, // 0x100A0: pcie_app, tmps, media_af, isp_af, 0x86100000, 0x85100000, 0x85100000 // 0x100B0: gfx_af, ans_c, anc_link }; #endif static const uint32_t spare_divs_active[PMGR_SPARE_CLK_CFG_COUNT] = { TARGET_SPARE0_CLK_CFG, // 0x10208: spare0 0x00000000, // 0x1020C: spare1 0x00000000, // 0x10210: spare2 0x00000000, // 0x10214: spare3 0x80100028, // 0x10218: isp_ref0 0x80100028 // 0x1021C: isp_ref1 }; /* GFX table. The voltage information is maintained in chipid.c */ struct gfx_state_info { uint32_t dwi_val; /* will be populated by determining the binning info */ uint32_t fb_div; uint32_t pre_div; uint32_t op_div; uint32_t dwi_sram_val; /* Only meaningfull for SUB_PLATFORM_T7001 */ }; static struct gfx_state_info gfx_states[] = { [CHIPID_GPU_VOLTAGE_OFF] = { 0, 0, 0, 0, 0 }, /* Power off Templar4 state.*/ [CHIPID_GPU_VOLTAGE_V0] = { 0, 365, 6, 3, 0 }, /* 365 MHz */ [CHIPID_GPU_VOLTAGE_V1] = { 0, 75, 2, 1, 0 }, /* 450 MHz */ [CHIPID_GPU_VOLTAGE_V2] = { 0, 125, 3, 1, 0 }, /* 500 MHz */ #if SUB_TARGET_N56 || SUB_TARGET_J42 || SUB_TARGET_J42D || SUB_PLATFORM_T7001 || SUB_TARGET_J96 || SUB_TARGET_J97 [CHIPID_GPU_VOLTAGE_V3] = { 0, 275, 6, 1, 0 }, /* 550 MHz */ #endif #if SUB_PLATFORM_T7001 || SUB_TARGET_J96 || SUB_TARGET_J97 [CHIPID_GPU_VOLTAGE_V4] = { 0, 50, 1, 1, 0 }, /* 600 MHz */ [CHIPID_GPU_VOLTAGE_V5] = { 0, 325, 6, 1, 0 }, /* 650 MHz */ #endif [CHIPID_GPU_VOLTAGE_V0_DIDT] = { 0, 365, 6, 7, 0 }, /* 182.5 MHz */ [CHIPID_GPU_VOLTAGE_V1_DIDT] = { 0, 75, 2, 3, 0 }, /* 225 MHz */ [CHIPID_GPU_VOLTAGE_V2_DIDT] = { 0, 125, 3, 3, 0 }, /* 250 MHz */ #if SUB_TARGET_N56 || SUB_TARGET_J42 || SUB_TARGET_J42D || SUB_PLATFORM_T7001 || SUB_TARGET_J96 || SUB_TARGET_J97 [CHIPID_GPU_VOLTAGE_V3_DIDT] = { 0, 275, 6, 3, 0 }, /* 275 MHz */ #endif #if SUB_PLATFORM_T7001 || SUB_TARGET_J96 || SUB_TARGET_J97 [CHIPID_GPU_VOLTAGE_V4_DIDT] = { 0, 50, 1, 3, 0 }, /* 300 MHz */ [CHIPID_GPU_VOLTAGE_V5_DIDT] = { 0, 325, 6, 3, 0 }, /* 325 MHz */ #endif #if 0 [5] = {0, 0, 0, 0}, /* Debug state. chipid.c has a valid voltage for this state. */ #endif }; static void set_gfx_perf_state(uint32_t state_num, struct gfx_state_info *gfx_state); #endif /* APPLICATION_IBOOT */ #if APPLICATION_SECUREROM #if SUB_PLATFORM_T7001 && !SUPPORT_FPGA /* PLL3 @100MHz */ #define PLL3 3 #define PLL3_O OSC_FREQ #define PLL3_P 1 #define PLL3_M 50 #define PLL3_S 11 #define PLL3_V PLL_VCO_TARGET(PLL3) #define PLL3_T PLL_FREQ_TARGET(PLL3) #endif /* PLL4 @1200MHz */ #define PLL4 4 #define PLL4_O OSC_FREQ #define PLL4_P 1 #define PLL4_M 50 #define PLL4_S 0 #define PLL4_V PLL_VCO_TARGET(PLL4) #define PLL4_T PLL_FREQ_TARGET(PLL4) #define PLL4_VCO_ENABLED 0 // We won't touch the clk gen's that aren't necessary during SecureROM. #if SUB_PLATFORM_T7000 static const uint32_t clk_divs_active[PMGR_CLK_CFG_COUNT] = { 0x80100000, 0x80100000, 0x80100000, 0x80100000, // 0x10000: mcu_fixed, mcu, mipi_dsi, nco_ref0, 0x80100000, 0x80100000, 0x80100000, 0x80100000, // 0x10010: nco_ref1, nco_alg0, nco_alg1, hsciphy_ref_12m, 0x80100000, 0x80100000, 0x80100000, 0x86100000, // 0x10020: usb480_0, usb480_1, usb_ohci_48m, usb, 0x80100000, 0x85100000, 0x85100000, 0x80100000, // 0x10030: usb_free_60m, sio_c, sio_p, isp_c 0x80100000, 0x80100000, 0x80100000, 0x80100000, // 0x10040: isp, isp_sensor0_ref, isp_sensor1_ref, vdec 0x80100000, 0x80100000, 0x80100000, 0x80100000, // 0x10050: venc, vid0, disp0, disp1 0x80100000, 0x80100000, 0x80100000, 0x85100000, // 0x10060: ajpeg_ip, ajpeg_wrap, msr, af 0x85100000, 0x80100000, 0x80100000, 0x80100000, // 0x10070: lio, mca0_m, mca1_m, mca2_m 0x80100000, 0x80100000, 0x85100000, 0x86100000, // 0x10080: mca3_m, mca4_m, sep, gpio 0x80100000, 0x80100000, 0x80100000, 0x80100000, // 0x10090: spi0_n, spi1_n, spi2_n, spi3_n 0x80100000, 0x80100000, 0x85100000, 0x80100000, // 0x100a0: debug, pcie_ref, pcie_app, tmps 0x80100000, 0x80100000, 0x80100000, 0x85100000, // 0x100b0: media, isp_af, gfx, ans_c 0x85100000 // 0x100c0: anc_link }; #elif SUB_PLATFORM_T7001 static const uint32_t clk_divs_active[PMGR_CLK_CFG_COUNT] = { 0x80100000, 0x80100000, 0x80100000, 0x80100000, // 0x10000: mcu_fixed, mcu, nco_ref0, nco_ref1, 0x80100000, 0x80100000, 0x80100000, 0x80100000, // 0x10010: nco_alg0, nco_alg1, hsciphy_ref_12m, usb480_0, 0x80100000, 0x80100000, 0x86100000, 0x80100000, // 0x10020: usb480_1, usb_ohci_48m, usb, usb_free_60m, 0x85100000, 0x85100000, 0x80100000, 0x80100000, // 0x10030: sio_c, sio_p, isp_c, isp, 0x80100000, 0x80100000, 0x80100000, 0x80100000, // 0x10040: isp_sensor0_ref, isp_sensor1_ref, vdec, venc, 0x80100000, 0x80100000, 0x80100000, 0x80100000, // 0x10050: vid0, disp0, disp1, ajpeg_ip, 0x80100000, 0x80100000, 0x85100000, 0x85100000, // 0x10060: ajpeg_wrap, msr, af, lio, 0x80100000, 0x80100000, 0x80100000, 0x80100000, // 0x10070: mca0_m, mca1_m, mca2_m, mca3_m, 0x80100000, 0x85100000, 0x86100000, 0x80100000, // 0x10080: mca4_m, sep, gpio, spi0_n, 0x80100000, 0x80100000, 0x80100000, 0x80100000, // 0x10090: spi1_n, spi2_n, spi3_n, debug, 0x85100000, 0x80100000, 0x80100000, 0x80100000, // 0x100a0: pcie_app, tmps, media, isp_af, 0x80100000, 0x85100000, 0x85100000 // 0x100b0: gfx, ans_c, anc_link }; #endif static const uint32_t spare_divs_active[PMGR_SPARE_CLK_CFG_COUNT] = { 0x80000001, // 0x10208: s0 0x80000001, // 0x1020C: s1 0x80000001, // 0x10210: s2 0x80000001, // 0x10214: s3, 0x80000001, // 0x10218: isp_ref0 0x80000001 // 0x1021c: isp_ref1 }; #endif /* APPLICATION_SECUREROM */ static const struct clock_config clk_configs[PMGR_CLK_COUNT] = { [PMGR_CLK_MCU_FIXED] = { &rPMGR_MCU_FIXED_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_PLL1, 1 } } }, [PMGR_CLK_MCU] = { &rPMGR_MCU_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_OSC, 1 }, { PMGR_CLK_OSC, 1 }, { PMGR_CLK_PLL1, 2 }, { PMGR_CLK_PLL1, 4 }, { PMGR_CLK_PLL1, 8 }, { PMGR_CLK_PLL1, 16 }, { PMGR_CLK_PLL4, 48 }, { PMGR_CLK_PLL1, 1 } } }, #if SUB_PLATFORM_T7000 [PMGR_CLK_MIPI_DSI] = { &rPMGR_MIPI_DSI_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_OSC, 1 }, { PMGR_CLK_PLL2, 1 }, { PMGR_CLK_PLL4, 3 }, { PMGR_CLK_PLL0, 1 } } }, #endif [PMGR_CLK_NCO_REF0] = { &rPMGR_NCO_REF0_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 2 }, { PMGR_CLK_PLL4, 7 } } }, [PMGR_CLK_NCO_REF1] = { &rPMGR_NCO_REF1_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 2 }, { PMGR_CLK_PLL4, 7 } } }, [PMGR_CLK_NCO_ALG0] = { &rPMGR_NCO_ALG0_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 10 }, { PMGR_CLK_PLL4, 12 }, { PMGR_CLK_PLL4, 16 }, { PMGR_CLK_PLL4, 24 }, { PMGR_CLK_PLL4, 40 }, { PMGR_CLK_PLL4, 50 } } }, [PMGR_CLK_NCO_ALG1] = { &rPMGR_NCO_ALG1_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 10 }, { PMGR_CLK_PLL4, 12 }, { PMGR_CLK_PLL4, 16 }, { PMGR_CLK_PLL4, 24 }, { PMGR_CLK_PLL4, 40 }, { PMGR_CLK_PLL4, 50 } } }, [PMGR_CLK_HSICPHY_REF_12M] = { &rPMGR_HSICPHY_REF_12M_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_OSC, 2 } } }, [PMGR_CLK_USB480_0] = { &rPMGR_USB480_0_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 5 } } }, [PMGR_CLK_USB480_1] = { &rPMGR_USB480_1_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 5 } } }, [PMGR_CLK_USB_OHCI_48M] = { &rPMGR_USB_OHCI_48M_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 50 } } }, [PMGR_CLK_USB] = { &rPMGR_USB_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 20 }, { PMGR_CLK_PLL4, 24 }, { PMGR_CLK_PLL4, 40 }, { PMGR_CLK_PLL4, 50 }, { PMGR_CLK_PLL4, 72 }, { PMGR_CLK_PLL4, 80 } } }, [PMGR_CLK_USB_FREE_60M] = { &rPMGR_USB_FREE_60M_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 40 } } }, [PMGR_CLK_SIO_C] = { &rPMGR_SIO_C_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 5 }, { PMGR_CLK_PLL4, 6 }, { PMGR_CLK_PLL4, 7 }, { PMGR_CLK_PLL4, 8 }, { PMGR_CLK_PLL4, 9 }, { PMGR_CLK_PLL4, 10 }, { PMGR_CLK_PLL4, 48 } } }, [PMGR_CLK_SIO_P] = { &rPMGR_SIO_P_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 20 }, { PMGR_CLK_PLL4, 24 }, { PMGR_CLK_PLL4, 30 }, { PMGR_CLK_PLL4, 40 }, { PMGR_CLK_PLL4, 48 }, { PMGR_CLK_OSC, 2 }, { PMGR_CLK_OSC, 4 } } }, [PMGR_CLK_ISP_C] = { &rPMGR_ISP_C_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 5 }, { PMGR_CLK_PLL4, 6 }, { PMGR_CLK_PLL4, 7 }, { PMGR_CLK_PLL4, 8 }, { PMGR_CLK_PLL4, 9 }, { PMGR_CLK_PLL4, 10 }, { PMGR_CLK_PLL4, 48 } } }, [PMGR_CLK_ISP] = { &rPMGR_ISP_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 6 }, { PMGR_CLK_PLL4, 7 }, { PMGR_CLK_PLL4, 8 }, { PMGR_CLK_PLL4, 9 }, { PMGR_CLK_PLL4, 10 }, { PMGR_CLK_PLL4, 12 } } }, [PMGR_CLK_ISP_SENSOR0_REF] = { &rPMGR_ISP_SENSOR0_REF_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_ISP_REF0, 1 }, { PMGR_CLK_ISP_REF1, 1 } } }, [PMGR_CLK_ISP_SENSOR1_REF] = { &rPMGR_ISP_SENSOR1_REF_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_ISP_REF0, 1 }, { PMGR_CLK_ISP_REF1, 1 } } }, [PMGR_CLK_VDEC] = { &rPMGR_VDEC_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 7 }, { PMGR_CLK_PLL4, 8 }, { PMGR_CLK_PLL4, 9 }, { PMGR_CLK_PLL4, 10 }, { PMGR_CLK_PLL4, 12 }, { PMGR_CLK_PLL4, 16 }, { PMGR_CLK_PLL4, 24 } } }, [PMGR_CLK_VENC] = { &rPMGR_VENC_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 5 }, { PMGR_CLK_PLL4, 6 }, { PMGR_CLK_PLL4, 7 }, { PMGR_CLK_PLL4, 8 }, { PMGR_CLK_PLL4, 9 }, { PMGR_CLK_PLL4, 12 }, { PMGR_CLK_PLL4, 24 } } }, [PMGR_CLK_VID0] = { &rPMGR_VID0_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 11 }, { PMGR_CLK_PLL4, 39 } #if SUB_PLATFORM_T7001 ,{ PMGR_CLK_PLL4, 30 }, { PMGR_CLK_PLL4, 12 }, { PMGR_CLK_PLL4, 7 } #endif } }, #if SUB_PLATFORM_T7000 [PMGR_CLK_DISP0] = { &rPMGR_DISP0_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 6 }, { PMGR_CLK_PLL4, 7 }, { PMGR_CLK_PLL4, 8 }, { PMGR_CLK_PLL4, 9 }, { PMGR_CLK_PLL4, 12 }, { PMGR_CLK_PLL4, 14 }, { PMGR_CLK_PLL4, 24 } } }, [PMGR_CLK_DISP1] = { &rPMGR_DISP1_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 6 }, { PMGR_CLK_PLL4, 7 }, { PMGR_CLK_PLL4, 8 }, { PMGR_CLK_PLL4, 9 }, { PMGR_CLK_PLL4, 12 }, { PMGR_CLK_PLL4, 14 }, { PMGR_CLK_PLL4, 24 } } }, #elif SUB_PLATFORM_T7001 [PMGR_CLK_DISP0] = { &rPMGR_DISP0_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 5 }, { PMGR_CLK_PLL4, 6 }, { PMGR_CLK_PLL4, 7 }, { PMGR_CLK_PLL4, 8 }, { PMGR_CLK_PLL4, 9 }, { PMGR_CLK_PLL4, 12 }, { PMGR_CLK_PLL4, 14 } } }, [PMGR_CLK_DISP1] = { &rPMGR_DISP1_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 5 }, { PMGR_CLK_PLL4, 6 }, { PMGR_CLK_PLL4, 7 }, { PMGR_CLK_PLL4, 8 }, { PMGR_CLK_PLL4, 9 }, { PMGR_CLK_PLL4, 12 }, { PMGR_CLK_PLL4, 14 } } }, #endif [PMGR_CLK_AJPEG_IP] = { &rPMGR_AJPEG_IP_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 10 }, { PMGR_CLK_PLL4, 11 }, { PMGR_CLK_PLL4, 12 }, { PMGR_CLK_PLL4, 14 }, { PMGR_CLK_PLL4, 16 }, { PMGR_CLK_PLL4, 24 } } }, [PMGR_CLK_AJPEG_WRAP] = { &rPMGR_AJPEG_WRAP_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 8 }, { PMGR_CLK_PLL4, 9 }, { PMGR_CLK_PLL4, 10 }, { PMGR_CLK_PLL4, 11 }, { PMGR_CLK_PLL4, 12 }, { PMGR_CLK_PLL4, 14 }, { PMGR_CLK_PLL4, 16 } } }, [PMGR_CLK_MSR] = { &rPMGR_MSR_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 6 }, { PMGR_CLK_PLL4, 7 }, { PMGR_CLK_PLL4, 8 }, { PMGR_CLK_PLL4, 9 }, { PMGR_CLK_PLL4, 12 }, { PMGR_CLK_PLL4, 16 }, { PMGR_CLK_PLL4, 24 } } }, [PMGR_CLK_AF] = { &rPMGR_AF_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 5 }, { PMGR_CLK_PLL4, 6 }, { PMGR_CLK_PLL4, 7 }, { PMGR_CLK_PLL4, 8 }, { PMGR_CLK_PLL4, 9 }, { PMGR_CLK_PLL4, 12 }, { PMGR_CLK_PLL4, 24 } } }, [PMGR_CLK_LIO] = { &rPMGR_LIO_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 10 }, { PMGR_CLK_PLL4, 12 }, { PMGR_CLK_PLL4, 14 }, { PMGR_CLK_PLL4, 16 }, { PMGR_CLK_PLL4, 18 }, { PMGR_CLK_PLL4, 20 }, { PMGR_CLK_PLL4, 48 } } }, [PMGR_CLK_MCA0_M] = { &rPMGR_NCO_CLK_CFG(0), { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_OSC, 2 }, { PMGR_CLK_OSC, 4 } } }, [PMGR_CLK_MCA1_M] = { &rPMGR_NCO_CLK_CFG(1), { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_OSC, 2 }, { PMGR_CLK_OSC, 4 } } }, [PMGR_CLK_MCA2_M] = { &rPMGR_NCO_CLK_CFG(2), { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_OSC, 2 }, { PMGR_CLK_OSC, 4 } } }, [PMGR_CLK_MCA3_M] = { &rPMGR_NCO_CLK_CFG(3), { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_OSC, 2 }, { PMGR_CLK_OSC, 4 } } }, [PMGR_CLK_MCA4_M] = { &rPMGR_NCO_CLK_CFG(4), { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_NOT_SUPPORTED, 1 }, { PMGR_CLK_OSC, 2 }, { PMGR_CLK_OSC, 4 } } }, [PMGR_CLK_SEP] = { &rPMGR_SEP_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 6 }, { PMGR_CLK_PLL4, 7 }, { PMGR_CLK_PLL4, 12 }, { PMGR_CLK_PLL4, 24 } } }, [PMGR_CLK_GPIO] = { &rPMGR_GPIO_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 100 }, { PMGR_CLK_PLL4, 50 } } }, [PMGR_CLK_SPI0_N] = { &rPMGR_SPI0_N_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 40 }, { PMGR_CLK_PLL4, 48 }, { PMGR_CLK_PLL4, 50 } } }, [PMGR_CLK_SPI1_N] = { &rPMGR_SPI1_N_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 40 }, { PMGR_CLK_PLL4, 48 }, { PMGR_CLK_PLL4, 50 } } }, [PMGR_CLK_SPI2_N] = { &rPMGR_SPI2_N_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 40 }, { PMGR_CLK_PLL4, 48 }, { PMGR_CLK_PLL4, 50 } } }, [PMGR_CLK_SPI3_N] = { &rPMGR_SPI3_N_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 40 }, { PMGR_CLK_PLL4, 48 }, { PMGR_CLK_PLL4, 50 } } }, [PMGR_CLK_DEBUG] = { &rPMGR_DEBUG_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 20 }, { PMGR_CLK_PLL4, 24 }, { PMGR_CLK_PLL4, 30 }, { PMGR_CLK_PLL4, 40 }, { PMGR_CLK_PLL4, 48 } } }, #if SUB_PLATFORM_T7000 [PMGR_CLK_PCIE_REF] = { &rPMGR_PCIE_REF_CLK_CFG, { { PMGR_CLK_PLL4, 24 }, { PMGR_CLK_PLL3, 1 }, } }, #endif [PMGR_CLK_PCIE_APP] = { &rPMGR_PCIE_APP_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 9 }, { PMGR_CLK_PLL4, 10 }, { PMGR_CLK_PLL4, 12 }, { PMGR_CLK_PLL4, 24 } } }, [PMGR_CLK_TMPS] = { &rPMGR_TMPS_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_OSC, 20 }, } }, [PMGR_CLK_MEDIA_AF] = { &rPMGR_MEDIA_AF_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 5 }, { PMGR_CLK_PLL4, 6 }, { PMGR_CLK_PLL4, 7 }, { PMGR_CLK_PLL4, 8 }, { PMGR_CLK_PLL4, 9 }, { PMGR_CLK_PLL4, 12 }, { PMGR_CLK_PLL4, 24 }, } }, [PMGR_CLK_ISP_AF] = { &rPMGR_ISP_AF_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 5 }, { PMGR_CLK_PLL4, 6 }, { PMGR_CLK_PLL4, 7 }, { PMGR_CLK_PLL4, 8 }, { PMGR_CLK_PLL4, 9 }, { PMGR_CLK_PLL4, 12 }, { PMGR_CLK_PLL4, 24 }, } }, [PMGR_CLK_GFX_AF] = { &rPMGR_GFX_AF_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 5 }, { PMGR_CLK_PLL4, 6 }, { PMGR_CLK_PLL4, 7 }, { PMGR_CLK_PLL4, 8 }, { PMGR_CLK_PLL4, 9 }, { PMGR_CLK_PLL4, 12 }, { PMGR_CLK_PLL4, 24 }, } }, [PMGR_CLK_ANS_C] = { &rPMGR_ANS_C_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 5 }, { PMGR_CLK_PLL4, 6 }, { PMGR_CLK_PLL4, 7 }, { PMGR_CLK_PLL4, 8 }, { PMGR_CLK_PLL4, 9 }, { PMGR_CLK_PLL4, 10 }, { PMGR_CLK_PLL4, 48 } } }, [PMGR_CLK_ANC_LINK] = { &rPMGR_ANC_LINK_CLK_CFG, { { PMGR_CLK_OSC, 1 }, { PMGR_CLK_S0, 1 }, { PMGR_CLK_S1, 1 }, { PMGR_CLK_S2, 1 }, { PMGR_CLK_S3, 1 }, { PMGR_CLK_PLL4, 9 }, { PMGR_CLK_PLL4, 7 }, { PMGR_CLK_PLL4, 8 }, { PMGR_CLK_PLL4, 12 }, { PMGR_CLK_PLL4, 18 }, { PMGR_CLK_PLL4, 24 } } }, [PMGR_CLK_S0] = { &rPMGR_S0_CLK_CFG, { { PMGR_CLK_PLL4, 3 }, { PMGR_CLK_PLL2, 1 }, #if SUB_PLATFORM_T7000 { PMGR_CLK_PLL3, 1 }, #elif SUB_PLATFORM_T7001 { PMGR_CLK_PLL0, 1 }, #endif { PMGR_CLK_PLL4, 2 } } }, [PMGR_CLK_S1] = { &rPMGR_S1_CLK_CFG, { { PMGR_CLK_PLL4, 3 }, { PMGR_CLK_PLL2, 1 }, #if SUB_PLATFORM_T7000 { PMGR_CLK_PLL3, 1 }, #elif SUB_PLATFORM_T7001 { PMGR_CLK_PLL0, 1 }, #endif { PMGR_CLK_PLL4, 2 } } }, [PMGR_CLK_S2] = { &rPMGR_S2_CLK_CFG, { { PMGR_CLK_PLL4, 3 }, { PMGR_CLK_PLL2, 1 }, #if SUB_PLATFORM_T7000 { PMGR_CLK_PLL3, 1 }, #elif SUB_PLATFORM_T7001 { PMGR_CLK_PLL0, 1 }, #endif { PMGR_CLK_PLL4, 2 } } }, [PMGR_CLK_S3] = { &rPMGR_S3_CLK_CFG, { { PMGR_CLK_PLL4, 3 }, { PMGR_CLK_PLL2, 1 }, #if SUB_PLATFORM_T7000 { PMGR_CLK_PLL3, 1 }, #elif SUB_PLATFORM_T7001 { PMGR_CLK_PLL0, 1 }, #endif { PMGR_CLK_PLL4, 2 } } }, [PMGR_CLK_ISP_REF0] = { &rPMGR_ISP_REF0_CLK_CFG, { { PMGR_CLK_PLL4, 5 }, { PMGR_CLK_PLL4, 7 }, { PMGR_CLK_PLL4, 8 }, { PMGR_CLK_PLL4, 9 } } }, [PMGR_CLK_ISP_REF1] = { &rPMGR_ISP_REF1_CLK_CFG, { { PMGR_CLK_PLL4, 5 }, { PMGR_CLK_PLL4, 7 }, { PMGR_CLK_PLL4, 8 }, { PMGR_CLK_PLL4, 9 } } }, }; static uint32_t get_apsc_ccc_state(void); static void set_apsc_ccc_state(uint32_t target_state); #if (APPLICATION_IBOOT && !PRODUCT_IBOOT && !PRODUCT_IBEC) static void init_soc_thermal_sensors(void); static void init_soc_sochot(void); static void init_cpu_thermal_sensors(void); static void init_cpu_sochot(void); static void init_soc_tvm_tunables(void); #endif static void clocks_get_frequencies(void); static void clocks_get_frequencies_range(uint32_t start_clk, uint32_t end_clk); static uint32_t get_pll(int32_t pll); static uint32_t get_pll_cpu(void); static void set_pll(int32_t pll, uint32_t p, uint32_t m, uint32_t s, bool vco_output); static uint32_t is_pll_running(int32_t pll); static void set_running_pll(int32_t pll, uint32_t p, uint32_t m, uint32_t s); static uint64_t pmgr_get_offset_from_diff_uV(uint32_t buck, uint32_t uV); static uint32_t get_spare(int32_t spare); static void clocks_set_gates(uint64_t *devices); static void clocks_quiesce_internal(void); static void power_on_sep(void); // current clock frequencies static uint32_t clks[PMGR_CLK_COUNT + 1]; void platform_power_spin(uint32_t usecs) { arm_no_wfe_spin(usecs); } int clocks_init(void) { #if (APPLICATION_IBOOT && (PRODUCT_IBOOT || PRODUCT_IBEC || WITH_RECOVERY_MODE_IBSS)) clks[PMGR_CLK_OSC] = OSC_FREQ; clocks_get_frequencies(); #endif /* (APPLICATION_IBOOT && (PRODUCT_IBOOT || PRODUCT_IBEC || WITH_RECOVERY_MODE_IBSS)) */ return 0; } #if (APPLICATION_IBOOT && !PRODUCT_IBOOT && !PRODUCT_IBEC) /* * To avoid di/dt voltage drop at the end of PLL relock. rdar://problem/13112194. */ static void set_ccc_pll_relock_div2(void) { uint32_t reg; reg = rCCC_PLL_CFG2; reg &= ~CCC_PLL_CFG2_RELOCKBYS2_S4_MASK; reg |= CCC_PLL_CFG2_RELOCKBYS2_S4_DIV2; rCCC_PLL_CFG2 = reg; } static void set_nco_clocks(void) { uint32_t i; // Enable this NCO with alg_ref0_clk and nco_ref0_clk. for (i = 0; i < 5; i++) rPMGR_NCO_CLK_CFG(i) |= (1 << 31); } static void apply_pmgr_tunables() { #define CLAMP_TIME_MASK (((1 << 8) - 1) << 8) #define CLK_EN_TIME_MASK (((1 << 8) - 1) << 16) #define RETN_SAVE_TIME_MASK (((1 << 3) - 1) << 24) #define RETN_RESTORE_TIME_MASK (((1 << 3) - 1) << 27) #define _PWRGATE_CFG0(rCFG0, RETN_RESTORE_TIME, RETN_SAVE_TIME, CLK_EN_TIME, CLAMP_TIME) \ regTemp = rCFG0; \ regTemp &= ~CLAMP_TIME_MASK; \ regTemp |= (CLAMP_TIME << 8); \ regTemp &= ~CLK_EN_TIME_MASK; \ regTemp |= (CLK_EN_TIME << 16); \ regTemp &= ~RETN_SAVE_TIME_MASK; \ regTemp |= (RETN_SAVE_TIME << 24); \ regTemp &= ~RETN_RESTORE_TIME_MASK; \ regTemp |= (RETN_RESTORE_TIME << 27); \ rCFG0 = regTemp; #define RAMP_PRE_TIME_MASK (((1 << 12) - 1) << 0) #define RAMP_ALL_TIME_MASK (((1 << 12) - 1) << 16) #define _PWRGATE_CFG1(rCFG1, RAMP_ALL_TIME, RAMP_PRE_TIME) \ regTemp = rCFG1; \ regTemp &= ~RAMP_PRE_TIME_MASK; \ regTemp |= (RAMP_PRE_TIME << 0); \ regTemp &= ~RAMP_ALL_TIME_MASK; \ regTemp |= (RAMP_ALL_TIME << 16); \ rCFG1 = regTemp; #define RESET_DOWN_TIME_MASK (((1 << 8) - 1) << 0) #define RESET_UP_TIME_MASK (((1 << 8) - 1) << 8) #define RESET_OFF_TIME_MASK (((1 << 8) - 1) << 16) #define _PWRGATE_CFG2(rCFG2, RESET_OFF_TIME, RESET_UP_TIME, RESET_DOWN_TIME) \ regTemp = rCFG2; \ regTemp &= ~RESET_DOWN_TIME_MASK; \ regTemp |= (RESET_DOWN_TIME << 0); \ regTemp &= ~RESET_UP_TIME_MASK; \ regTemp |= (RESET_UP_TIME << 8); \ regTemp &= ~RESET_OFF_TIME_MASK; \ regTemp |= (RESET_OFF_TIME << 16); \ rCFG2 = regTemp; #define DBG_CLK_ON_RAMP_MASK (1 << 4) #define _PWRGATE_DBG(rDBG, DBG_CLK_ON_RAMP) \ regTemp = rDBG; \ regTemp &= ~DBG_CLK_ON_RAMP_MASK; \ regTemp |= (DBG_CLK_ON_RAMP << 4); \ rDBG = regTemp; uint32_t regTemp; // A0 tunables. _PWRGATE_CFG0(rPMGR_PWRGATE_AMC_CFG0, 0x1, 0x1, 0x7, 0x3); #if SUB_PLATFORM_T7000 _PWRGATE_CFG1(rPMGR_PWRGATE_AMC_CFG1, 0x13, 0x1); #elif SUB_PLATFORM_T7001 _PWRGATE_CFG1(rPMGR_PWRGATE_AMC_CFG1, 0x12, 0x1); #endif _PWRGATE_CFG2(rPMGR_PWRGATE_AMC_CFG2, 0x7, 0x7, 0x0); _PWRGATE_CFG0(rPMGR_PWRGATE_USB_CFG0, 0x1, 0x1, 0x4, 0x3); _PWRGATE_CFG1(rPMGR_PWRGATE_USB_CFG1, 0xe, 0x1); _PWRGATE_CFG2(rPMGR_PWRGATE_USB_CFG2, 0x8, 0x8, 0x8); _PWRGATE_CFG0(rPMGR_PWRGATE_ACS_CFG0, 0x1, 0x1, 0x6, 0x3); #if SUB_PLATFORM_T7000 _PWRGATE_CFG1(rPMGR_PWRGATE_ACS_CFG1, 0xe, 0x1); #elif SUB_PLATFORM_T7001 _PWRGATE_CFG1(rPMGR_PWRGATE_ACS_CFG1, 0x12, 0x1); #endif _PWRGATE_CFG2(rPMGR_PWRGATE_ACS_CFG2, 0x6, 0x6, 0x0); _PWRGATE_CFG0(rPMGR_PWRGATE_DISP0_CFG0, 0x1, 0x1, 0x4, 0x3); #if SUB_PLATFORM_T7000 _PWRGATE_CFG1(rPMGR_PWRGATE_DISP0_CFG1, 0x33, 0x2); #elif SUB_PLATFORM_T7001 _PWRGATE_CFG1(rPMGR_PWRGATE_DISP0_CFG1, 0x3b, 0x3); #endif _PWRGATE_CFG2(rPMGR_PWRGATE_DISP0_CFG2, 0x8, 0x8, 0x8); _PWRGATE_CFG0(rPMGR_PWRGATE_DISP1_CFG0, 0x1, 0x1, 0x4, 0x3); #if SUB_PLATFORM_T7000 _PWRGATE_CFG1(rPMGR_PWRGATE_DISP1_CFG1, 0x31, 0x3); #elif SUB_PLATFORM_T7001 _PWRGATE_CFG1(rPMGR_PWRGATE_DISP1_CFG1, 0x38, 0x3); #endif _PWRGATE_CFG2(rPMGR_PWRGATE_DISP1_CFG2, 0x8, 0x8, 0x8); _PWRGATE_CFG0(rPMGR_PWRGATE_ISP_CFG0, 0x1, 0x1, 0x4, 0x3); #if SUB_PLATFORM_T7000 _PWRGATE_CFG1(rPMGR_PWRGATE_ISP_CFG1, 0x78, 0x3); #elif SUB_PLATFORM_T7001 _PWRGATE_CFG1(rPMGR_PWRGATE_ISP_CFG1, 0x5c, 0x2); #endif _PWRGATE_CFG2(rPMGR_PWRGATE_ISP_CFG2, 0x8, 0x8, 0x8); _PWRGATE_DBG(rPMGR_PWRGATE_ISP_DBG, 0x1); _PWRGATE_CFG0(rPMGR_PWRGATE_MEDIA_CFG0, 0x1, 0x1, 0x4, 0x3); #if SUB_PLATFORM_T7000 _PWRGATE_CFG1(rPMGR_PWRGATE_MEDIA_CFG1, 0x95, 0x4); #elif SUB_PLATFORM_T7001 _PWRGATE_CFG1(rPMGR_PWRGATE_MEDIA_CFG1, 0x72, 0x3); #endif _PWRGATE_CFG2(rPMGR_PWRGATE_MEDIA_CFG2, 0x8, 0x8, 0x8); _PWRGATE_CFG0(rPMGR_PWRGATE_VDEC0_CFG0, 0x1, 0x1, 0x4, 0x3); #if SUB_PLATFORM_T7000 _PWRGATE_CFG1(rPMGR_PWRGATE_VDEC0_CFG1, 0x53, 0x2); #elif SUB_PLATFORM_T7001 _PWRGATE_CFG1(rPMGR_PWRGATE_VDEC0_CFG1, 0x36, 0x2); #endif _PWRGATE_CFG2(rPMGR_PWRGATE_VDEC0_CFG2, 0x8, 0x8, 0x8); _PWRGATE_CFG0(rPMGR_PWRGATE_VENC_CPU_CFG0, 0x1, 0x1, 0x4, 0x3); #if SUB_PLATFORM_T7000 _PWRGATE_CFG1(rPMGR_PWRGATE_VENC_CPU_CFG1, 0x65, 0x3); #elif SUB_PLATFORM_T7001 _PWRGATE_CFG1(rPMGR_PWRGATE_VENC_CPU_CFG1, 0x58, 0x2); #endif _PWRGATE_CFG2(rPMGR_PWRGATE_VENC_CPU_CFG2, 0x8, 0x8, 0x8); _PWRGATE_DBG(rPMGR_PWRGATE_VENC_CPU_DBG, 0x1); _PWRGATE_CFG0(rPMGR_PWRGATE_PCIE_CFG0, 0x1, 0x1, 0x4, 0x3); #if SUB_PLATFORM_T7000 _PWRGATE_CFG1(rPMGR_PWRGATE_PCIE_CFG1, 0x2b, 0x2); #elif SUB_PLATFORM_T7001 _PWRGATE_CFG1(rPMGR_PWRGATE_PCIE_CFG1, 0x56, 0x2); #endif _PWRGATE_CFG2(rPMGR_PWRGATE_PCIE_CFG2, 0x8, 0x8, 0x8); _PWRGATE_CFG0(rPMGR_PWRGATE_ANS_CFG0, 0x1, 0x1, 0x4, 0x3); #if SUB_PLATFORM_T7000 _PWRGATE_CFG1(rPMGR_PWRGATE_ANS_CFG1, 0x3a, 0x2); #elif SUB_PLATFORM_T7001 _PWRGATE_CFG1(rPMGR_PWRGATE_ANS_CFG1, 0x2a, 0x2); #endif _PWRGATE_CFG2(rPMGR_PWRGATE_ANS_CFG2, 0x8, 0x8, 0x8); _PWRGATE_CFG0(rPMGR_PWRGATE_GFX_CFG0, 0x1, 0x1, 0x4, 0x3); #if SUB_PLATFORM_T7000 _PWRGATE_CFG1(rPMGR_PWRGATE_GFX_CFG1, 0x13, 0x1); #elif SUB_PLATFORM_T7001 _PWRGATE_CFG1(rPMGR_PWRGATE_GFX_CFG1, 0x1f, 0x1); #endif _PWRGATE_CFG2(rPMGR_PWRGATE_GFX_CFG2, 0x8, 0x8, 0x8); _PWRGATE_CFG0(rPMGR_PWRGATE_VENC_PIPE_CFG0, 0x1, 0x1, 0x4, 0x3); #if SUB_PLATFORM_T7000 _PWRGATE_CFG1(rPMGR_PWRGATE_VENC_PIPE_CFG1, 0x7c, 0x2); #elif SUB_PLATFORM_T7001 _PWRGATE_CFG1(rPMGR_PWRGATE_VENC_PIPE_CFG1, 0x5e, 0x2); #endif _PWRGATE_CFG2(rPMGR_PWRGATE_VENC_PIPE_CFG2, 0x8, 0x8, 0x8); _PWRGATE_DBG(rPMGR_PWRGATE_VENC_PIPE_DBG, 0x1); _PWRGATE_CFG0(rPMGR_PWRGATE_VENC_ME0_CFG0, 0x1, 0x1, 0x4, 0x3); #if SUB_PLATFORM_T7000 _PWRGATE_CFG1(rPMGR_PWRGATE_VENC_ME0_CFG1, 0x55, 0x2); #elif SUB_PLATFORM_T7001 _PWRGATE_CFG1(rPMGR_PWRGATE_VENC_ME0_CFG1, 0x40, 0x2); #endif _PWRGATE_CFG2(rPMGR_PWRGATE_VENC_ME0_CFG2, 0x8, 0x8, 0x8); _PWRGATE_DBG(rPMGR_PWRGATE_VENC_ME0_DBG, 0x1); _PWRGATE_CFG0(rPMGR_PWRGATE_VENC_ME1_CFG0, 0x1, 0x1, 0x4, 0x3); #if SUB_PLATFORM_T7000 _PWRGATE_CFG1(rPMGR_PWRGATE_VENC_ME1_CFG1, 0x55, 0x2); #elif SUB_PLATFORM_T7001 _PWRGATE_CFG1(rPMGR_PWRGATE_VENC_ME1_CFG1, 0x40, 0x2); #endif _PWRGATE_CFG2(rPMGR_PWRGATE_VENC_ME1_CFG2, 0x8, 0x8, 0x8); _PWRGATE_DBG(rPMGR_PWRGATE_VENC_ME1_DBG, 0x1); // 2. Apply MCU Async reset timing. rPMGR_PWRGATE_MCU_ASYNC_RESET = (0x1 << 0) | (0x1 << 4) | (0x1 << 8); // 3. Apply VolMan tunables rPMGR_VOLMAN_VAR_SOC_DELAY = (0x5 << 0) | (0x6b << 10) | (0xbb8 << 20); rPMGR_VOLMAN_FIXED_DELAY = (0x5 << 0) | (0x6b << 10) | (0xbb8 << 20); rPMGR_VOLMAN_GFX_DELAY = (0x5 << 0) | (0x6b << 10) | (0xbb8 << 20); rPMGR_VOLMAN_CPU_DELAY = (0x5 << 0) | (0x6b << 10) | (0xbb8 << 20); // 4. Apply Misc Spare tunable rPMGR_MISC_SPARE0 = 0x100; // 5. Apply PLL4 tunable #if SUB_PLATFORM_T7000 regTemp = rPMGR_PLL_DEBUG1(4); regTemp &= ~(PMGR_PLL_DEBUG1_RESERVE_IN_MASK << PMGR_PLL_DEBUG1_RESERVE_IN_SHIFT); regTemp |= (0x10 << PMGR_PLL_DEBUG1_RESERVE_IN_SHIFT); rPMGR_PLL_DEBUG1(4) = regTemp; #endif return; } static void apply_ccc_tunables(void) { rCCC_PRE_TD_TMR = 0x4; rCCC_PRE_FLUSH_TMR = 0x1000; #if SUB_PLATFORM_T7000 rCCC_PLL_DLY_CFG0 = (0x0 << 10) | 0x5; #else rCCC_PLL_DLY_CFG0 = (0x0 << 10) | 0x5; rCCC_PSW_DLY = (0x7f << 22) | (0x1 << 16) | 0x60; #endif rCCC_DCD_NRG_WGHT = 0x0c803ce24838c28aULL; rCCC_IEX_NRG_WGHT = 0x018a00a90046c597ULL; rCCC_LSU_NRG_WGHT = 0x62d37934a9854c2aULL; rCCC_NEX_NRG_WGHT0 = 0x6666574475795557ULL; rCCC_NEX_NRG_WGHT1 = 0xc6b7b54676896658ULL; rCCC_NEX_NRG_WGHT2 = 0x000000ba787a7aabULL; } #endif struct dvfm_data { uint32_t dvfm_state_vmax; uint32_t dvfm_state_iboot_cnt; uint32_t dvfm_state_vnom; uint32_t dvfm_state_vboost; uint32_t voltage_states1_count; uint32_t voltage_states1_size; }; #if SUB_PLATFORM_T7001 || SUB_TARGET_J96 || SUB_TARGET_J97 #if APPLICATION_IBOOT #if SUB_TARGET_J98 || SUB_TARGET_J99 static bool pmgr_check_use1608MHz_unbinned(uint32_t board_id, uint32_t board_rev) { bool use1608MHz_unbinned = false; switch (board_id & 0xf) { case TARGET_BOARD_ID_J98DEV: case TARGET_BOARD_ID_J99DEV: break; case TARGET_BOARD_ID_J98AP: case TARGET_BOARD_ID_J99AP: if ((board_rev & 0xf) == J99_PROTO3_BOARD_REV) use1608MHz_unbinned = true; break; default: panic("Unknown board id %d\n", board_id); } return use1608MHz_unbinned; } static bool pmgr_check_use1608MHz_binned(uint32_t board_id, uint32_t board_rev) { bool use1608MHz_binned = false; switch (board_id & 0xf) { case TARGET_BOARD_ID_J98DEV: case TARGET_BOARD_ID_J99DEV: break; case TARGET_BOARD_ID_J98AP: case TARGET_BOARD_ID_J99AP: if ((board_rev & 0xf) <= J99_PROTO3_P9_BOARD_REV) use1608MHz_binned = true; break; default: panic("Unknown board id %d\n", board_id); } return use1608MHz_binned; } #endif bool pmgr_check_gpu_use650MHz_unbinned(uint32_t board_id, uint32_t board_rev) { bool use_gpu_650MHz_unbinned = false; switch (board_id & 0xf) { #if SUB_TARGET_J98 || SUB_TARGET_J99 case TARGET_BOARD_ID_J98AP: case TARGET_BOARD_ID_J99AP: if ((board_rev & 0xf) <= J99_EVT_BOARD_REV && chipid_get_fuse_revision() < MINIMUM_BINNED_GPU_P6_REVISION) use_gpu_650MHz_unbinned = true; break; #endif default: break; } return use_gpu_650MHz_unbinned; } bool pmgr_check_gpu_use650MHz_binned(uint32_t board_id, uint32_t board_rev) { bool use_gpu_650MHz_binned = false; switch (board_id & 0xf) { #if SUB_TARGET_J98 || SUB_TARGET_J99 case TARGET_BOARD_ID_J98AP: case TARGET_BOARD_ID_J99AP: if ((board_rev & 0xf) <= J99_EVT_BOARD_REV && chipid_get_fuse_revision() >= MINIMUM_BINNED_GPU_P6_REVISION) use_gpu_650MHz_binned = true; break; #endif default: break; } return use_gpu_650MHz_binned; } bool pmgr_check_gpu_use600MHz_unbinned(uint32_t board_id, uint32_t board_rev) { bool use_gpu_600MHz_unbinned = false; #if SUB_TARGET_J96 || SUB_TARGET_J97 use_gpu_600MHz_unbinned = true; #endif return use_gpu_600MHz_unbinned; } bool pmgr_check_gpu_use600MHz_binned(uint32_t board_id, uint32_t board_rev) { bool use_gpu_600MHz_binned = false; #if SUB_TARGET_J96 || SUB_TARGET_J97 use_gpu_600MHz_binned = false; #endif return use_gpu_600MHz_binned; } static bool pmgr_check_use1512MHz(uint32_t board_id, uint32_t board_rev) { bool use1512MHz = false; switch (board_id & 0xf) { #if SUB_TARGET_J98 || SUB_TARGET_J99 case TARGET_BOARD_ID_J98DEV: case TARGET_BOARD_ID_J99DEV: break; case TARGET_BOARD_ID_J98AP: case TARGET_BOARD_ID_J99AP: if ((board_rev & 0xf) <= J99_PROTO1_BOARD_REV_LOCAL) use1512MHz = true; break; #endif #if SUB_TARGET_J81 || SUB_TARGET_J82 case TARGET_BOARD_ID_J81DEV: case TARGET_BOARD_ID_J82DEV: if ((board_rev & 0xf) == 0x3) use1512MHz = true; case TARGET_BOARD_ID_J81AP: case TARGET_BOARD_ID_J82AP: if ((board_rev & 0xf) >= 0x4) use1512MHz = true; break; #endif #if SUB_TARGET_J96 || SUB_TARGET_J97 case TARGET_BOARD_ID_J96AP: case TARGET_BOARD_ID_J97AP: case TARGET_BOARD_ID_J96DEV: case TARGET_BOARD_ID_J97DEV: use1512MHz = true; break; #endif default: panic("Unknown board id %d\n", board_id); } return use1512MHz; } static void pmgr_get_dvfm_data_from_vmax(struct dvfm_data *dvfm, uint32_t dvfm_state_vmax) { dvfm->dvfm_state_vmax = dvfm_state_vmax; dvfm->voltage_states1_count = dvfm_state_vmax - kDVFM_STATE_V0 + 1; dvfm->voltage_states1_size = dvfm->voltage_states1_count * 2; dvfm->dvfm_state_iboot_cnt = dvfm_state_vmax + 1; dvfm->dvfm_state_vnom = kDVFM_STATE_V2; dvfm->dvfm_state_vboost = dvfm_state_vmax; } static void pmgr_get_dvfm_data(struct dvfm_data *dvfm) { uint32_t dvfm_state_vmax; // DVFM table is filled with kDVFM_STATE_IBOOT copy after the last valid state. Use it to find the last valid state. for (dvfm_state_vmax = CCC_DVFM_STATE_COUNT - 1; dvfm_state_vmax > kDVFM_STATE_IBOOT; dvfm_state_vmax--) if (rCCC_DVFM_ST(dvfm_state_vmax) != rCCC_DVFM_ST(kDVFM_STATE_IBOOT)) break; pmgr_get_dvfm_data_from_vmax(dvfm, dvfm_state_vmax); } void pmgr_update_gfx_states(uint32_t board_id, uint32_t board_rev) { uint32_t states = sizeof(gfx_states) / sizeof(gfx_states[0]); uint32_t cnt, invalid_cnt = 0; bool gpu_use650MHz = pmgr_check_gpu_use650MHz_binned(board_id, board_rev) || pmgr_check_gpu_use650MHz_unbinned(board_id, board_rev); bool gpu_use600MHz = pmgr_check_gpu_use600MHz_binned(board_id, board_rev) || pmgr_check_gpu_use600MHz_unbinned(board_id, board_rev); // Default 365MHz 450MHz 500MHz 550MHz bool states_enable[] = {true, true, true, true, true, false, false, true, true, true, true, false, false}; if (gpu_use650MHz) { // 365MHz 450MHz 550MHz 650MHz states_enable[CHIPID_GPU_VOLTAGE_V2] = false; // 500MHz states_enable[CHIPID_GPU_VOLTAGE_V2_DIDT] = false; states_enable[CHIPID_GPU_VOLTAGE_V5] = true; // 650MHz states_enable[CHIPID_GPU_VOLTAGE_V5_DIDT] = true; } else if (gpu_use600MHz) { // 365MHz 450MHz 550MHz 600MHz states_enable[CHIPID_GPU_VOLTAGE_V2] = false; // 500MHz states_enable[CHIPID_GPU_VOLTAGE_V2_DIDT] = false; states_enable[CHIPID_GPU_VOLTAGE_V4] = true; // 600MHz states_enable[CHIPID_GPU_VOLTAGE_V4_DIDT] = true; } else if ((chipid_get_fuse_revision() < 0x1) && (chipid_get_chip_id() == 0x7001)) { // Capri A0 // 365MHz 450MHz 500MMHz states_enable[CHIPID_GPU_VOLTAGE_V3] = false; // 550MHz states_enable[CHIPID_GPU_VOLTAGE_V3_DIDT] = false; } for (cnt = 1; cnt < states; cnt++) { // The states are in this order: off,V0,V1,..,Vi,V0_DIDT,V1_DIDT,...,Vi_DIDT if (!states_enable[cnt]) invalid_cnt++; else gfx_states[cnt - invalid_cnt] = gfx_states[cnt]; } for (cnt = 1; cnt < states; cnt++) { // Invalidate the GFX states that are now duplicates from the shifting by setting them to 0 if (cnt >= states - invalid_cnt) gfx_states[cnt] = gfx_states[CHIPID_GPU_VOLTAGE_OFF]; set_gfx_perf_state(cnt, &gfx_states[cnt]); } dprintf(DEBUG_CRITICAL, "board_id=0x%x board_rev=0x%x gpu_use650MHz_binned=%d gpu_use650MHz_unbinned=%d gpu_use600MHz_binned=%d gpu_use600MHz_unbinned=%d\n", board_id, board_rev, (int)pmgr_check_gpu_use650MHz_binned(board_id, board_rev), (int)pmgr_check_gpu_use650MHz_unbinned(board_id, board_rev), (int)pmgr_check_gpu_use600MHz_binned(board_id, board_rev), (int)pmgr_check_gpu_use600MHz_unbinned(board_id, board_rev)); } /* * Set-up DVFM table with new states. This will override all previous states. */ void pmgr_update_dvfm(uint32_t board_id, uint32_t board_rev) { bool use1608MHz_binned = false; bool use1608MHz_unbinned = false; bool use1512MHz = pmgr_check_use1512MHz(board_id, board_rev); u_int32_t cpu_vid; #if SUB_PLATFORM_T7001 u_int32_t cpu_sram_vid; u_int64_t cpu_dvfm_sram = 0; #endif u_int32_t dvfm_state; struct chipid_vol_adj adj; uint64_t vol_adj_temp = 0; #if SUB_TARGET_J98 || SUB_TARGET_J99 use1608MHz_binned = pmgr_check_use1608MHz_binned(board_id, board_rev); use1608MHz_unbinned = pmgr_check_use1608MHz_unbinned(board_id, board_rev); #endif dprintf(DEBUG_CRITICAL, "board_id=0x%x board_rev=0x%x fuse_rev=%d use1512MHz=%d use1608MHz_binned=%d use1608MHz_unbinned=%d \n", board_id, board_rev, chipid_get_fuse_revision(), (int)use1512MHz, (int)use1608MHz_binned, (int)use1608MHz_unbinned); if (use1608MHz_unbinned) dvfm_state = kDVFM_STATE_V6_UNBINNED; else if (use1608MHz_binned) dvfm_state = kDVFM_STATE_V6; else if (use1512MHz) return; else { // kDVFM_STATE_V5 and kDVFM_STATE_V0 are the same, so pmgr_get_dvfm_data() will detect that the max state is kDVFM_STATE_V4 rCCC_DVFM_ST(kDVFM_STATE_V5) = rCCC_DVFM_ST(kDVFM_STATE_V0); return; } cpu_vid = chipid_get_cpu_voltage(dvfm_state); platform_convert_voltages(BUCK_CPU, 1, &cpu_vid); chipid_get_vol_adj(CHIPID_VOL_ADJ_CPU, dvfm_state, &adj); vol_adj_temp |= CCC_DVFM_ST_VOLADJ0(pmgr_get_offset_from_diff_uV(BUCK_CPU, adj.region_uV[0])); vol_adj_temp |= CCC_DVFM_ST_VOLADJ1(pmgr_get_offset_from_diff_uV(BUCK_CPU, adj.region_uV[1])); vol_adj_temp |= CCC_DVFM_ST_VOLADJ2(pmgr_get_offset_from_diff_uV(BUCK_CPU, adj.region_uV[2])); vol_adj_temp |= CCC_DVFM_ST_VOLADJ3(pmgr_get_offset_from_diff_uV(BUCK_CPU, adj.region_uV[3])); rCCC_DVFM_ST(kDVFM_STATE_V5) = ccc_dvfm_states[dvfm_state] | CCC_DVFM_ST_SAFEVOL(cpu_vid) | vol_adj_temp; #if SUB_PLATFORM_T7001 cpu_sram_vid = chipid_get_ram_voltage(dvfm_state); platform_convert_voltages(BUCK_RAM, 1, &cpu_sram_vid); cpu_dvfm_sram = CCC_DVFM_SRAM_STATE(cpu_dvfm_sram, kDVFM_STATE_V5, cpu_sram_vid); rCCC_DVFM_SRAM &= ~CCC_DVFM_SRAM_STATE(0ULL, kDVFM_STATE_V5, ~0ULL); rCCC_DVFM_SRAM |= cpu_dvfm_sram; #endif } #endif #endif static uint64_t pmgr_get_offset_from_diff_uV(uint32_t buck, uint32_t uV) { // power API is only able to convert absolute value // So, we need to convert abolute value and do the diff. uint32_t mV_prev = 0; uint32_t mV; uint32_t offset; uint32_t zero_mV; if (platform_get_dwi_to_mv(buck, 1) <= 0) // even if offset 0 is 0mV, offset 1 must be >0 mV. return 0; // This platform doesn't have HW PMU or emulation zero_mV = platform_get_dwi_to_mv(buck, 0); for (offset = 0; offset < 0xff; offset++) { mV = platform_get_dwi_to_mv(buck, offset); if ((mV - zero_mV) * 1000 >= uV) { // We look for the closest offset. // It can be offset or offset -1 if ((uV - (mV_prev - zero_mV) * 1000) < ((mV - zero_mV) * 1000 - uV)) return offset - 1; else return offset; } mV_prev = mV; } panic("No offset for %d uV on buck %d\n", uV, buck); return 0; } /* * clocks_set_default - called by SecureROM, LLB, iBSS main via * platform_init_setup_clocks, so the current state of the chip is * either POR, or whatever 'quiesce' did when leaving SecureROM. */ int clocks_set_default(void) { uint32_t cnt; #if APPLICATION_IBOOT u_int32_t cpu_vid[kDVFM_STATE_IBOOT_CNT]; #if SUB_PLATFORM_T7000 u_int32_t soc_vid[kSOC_PERF_STATE_IBOOT_CNT]; #elif SUB_PLATFORM_T7001 u_int32_t gpu_sram_vid[kPMGR_GFX_STATE_MAX]; u_int32_t cpu_sram_vid[kDVFM_STATE_IBOOT_CNT]; u_int64_t cpu_dvfm_sram = 0; #endif u_int32_t gpu_vid[kPMGR_GFX_STATE_MAX]; #endif clks[PMGR_CLK_OSC] = OSC_FREQ; volatile uint32_t *clkcfgs = PMGR_FIRST_CLK_CFG; volatile uint32_t *spare_clkcfgs = PMGR_FIRST_SPARE_CLK_CFG; // Setup bypass DVFM state rCCC_DVFM_ST(kDVFM_STATE_BYPASS) = ccc_dvfm_states[kDVFM_STATE_BYPASS]; // Begin: Secure ROM PLL calibration sequence changes { uint32_t vco_override = rCFG_FUSE9; // Shift the override value for the CPU PLL to the LSB position. vco_override >>= CFG_FUSE9_PLL_CPU_SHIFT; // Is the override data for this PLL valid? if (vco_override & CFG_FUSE9_PLL_VCO_RCTRL_SEL) { uint32_t reg = rCCC_PLL_CFG1; reg &= ~(CCC_PLL_CFG1_PLL_VCO_RCTRL_OW_MASK << CCC_PLL_CFG1_PLL_VCO_RCTRL_OW_SHIFT); reg |= (vco_override & CFG_FUSE9_PLL_VCO_RCTRL_OW_MASK) << CCC_PLL_CFG1_PLL_VCO_RCTRL_OW_SHIFT; reg |= CCC_PLL_CFG1_PLL_VCO_RCTRL_SEL; rCCC_PLL_CFG1 = reg; } } // End: Secure ROM PLL calibration sequence changes // Change all clocks to something safe clocks_quiesce_internal(); // Setup active DVFM and SOC PERF states for the stage of boot. #if SUB_PLATFORM_T7001 #if APPLICATION_IBOOT /* T7001 doesn't have kSOC_PERF_STATE_VMIN */ pmgr_soc_perf_states[kSOC_PERF_STATE_VMIN] = pmgr_soc_perf_states[kSOC_PERF_STATE_VNOM]; #endif #endif #if APPLICATION_SECUREROM rCCC_DVFM_ST(kDVFM_STATE_SECUREROM) = ccc_dvfm_states[kDVFM_STATE_SECUREROM]; rPMGR_SOC_PERF_STATE_ENTRY_A(kSOC_PERF_STATE_SECUREROM) = pmgr_soc_perf_states[kSOC_PERF_STATE_SECUREROM].entry[0]; rPMGR_SOC_PERF_STATE_ENTRY_B(kSOC_PERF_STATE_SECUREROM) = pmgr_soc_perf_states[kSOC_PERF_STATE_SECUREROM].entry[1]; rPMGR_SOC_PERF_STATE_ENTRY_C(kSOC_PERF_STATE_SECUREROM) = pmgr_soc_perf_states[kSOC_PERF_STATE_SECUREROM].entry[2]; rPMGR_SOC_PERF_STATE_ENTRY_D(kSOC_PERF_STATE_SECUREROM) = 0; #endif #if APPLICATION_IBOOT #ifndef BUCK_CPU #error BUCK_CPU not defined for this platform #endif // Get the binned voltages and update the CCC DVFM state registers. platform_get_cpu_voltages(kDVFM_STATE_IBOOT_CNT, cpu_vid); platform_convert_voltages(BUCK_CPU, kDVFM_STATE_IBOOT_CNT, cpu_vid); #if SUB_PLATFORM_T7001 #ifndef BUCK_RAM #error BUCK_RAM not defined for this platform #endif platform_get_ram_voltages(kDVFM_STATE_IBOOT_CNT, cpu_sram_vid); platform_convert_voltages(BUCK_RAM, kDVFM_STATE_IBOOT_CNT, cpu_sram_vid); #endif for (cnt = kDVFM_STATE_IBOOT; cnt < kDVFM_STATE_IBOOT_CNT; cnt++) { struct chipid_vol_adj adj; uint64_t vol_adj_temp = 0; chipid_get_vol_adj(CHIPID_VOL_ADJ_CPU, cnt, &adj); vol_adj_temp |= CCC_DVFM_ST_VOLADJ0(pmgr_get_offset_from_diff_uV(BUCK_CPU, adj.region_uV[0])); vol_adj_temp |= CCC_DVFM_ST_VOLADJ1(pmgr_get_offset_from_diff_uV(BUCK_CPU, adj.region_uV[1])); vol_adj_temp |= CCC_DVFM_ST_VOLADJ2(pmgr_get_offset_from_diff_uV(BUCK_CPU, adj.region_uV[2])); vol_adj_temp |= CCC_DVFM_ST_VOLADJ3(pmgr_get_offset_from_diff_uV(BUCK_CPU, adj.region_uV[3])); rCCC_DVFM_ST(cnt) = ccc_dvfm_states[cnt] | CCC_DVFM_ST_SAFEVOL(cpu_vid[cnt]) | vol_adj_temp; } #if SUB_PLATFORM_T7001 cpu_dvfm_sram = CCC_DVFM_SRAM_STATE(cpu_dvfm_sram, kDVFM_STATE_BYPASS, cpu_sram_vid[kDVFM_STATE_BYPASS]); for (cnt = kDVFM_STATE_IBOOT; cnt < kDVFM_STATE_IBOOT_CNT; cnt++) { cpu_dvfm_sram = CCC_DVFM_SRAM_STATE(cpu_dvfm_sram, cnt, cpu_sram_vid[cnt]); } #endif // APSC sleep state will use the bypass state with V0. rCCC_DVFM_ST(kDVFM_STATE_BYPASS) = ccc_dvfm_states[kDVFM_STATE_BYPASS] | CCC_DVFM_ST_SAFEVOL(cpu_vid[kDVFM_STATE_V0]); // To prevent crashes/hangs during update install due to // mismatch of CCC clock config info between an old LLB and a new EDT+OS // we can populate the unused entries of the DVFM table with that of // Vmin, Fmin. That way we will always have a workable entry in the DVFM // table. // Assumptions: // There is always a valid state for iBoot and we will use that to populate the // empty table entries. for (cnt = kDVFM_STATE_IBOOT_CNT; cnt < CCC_DVFM_STATE_COUNT; cnt++) { rCCC_DVFM_ST(cnt) = rCCC_DVFM_ST(kDVFM_STATE_IBOOT); } #if SUB_PLATFORM_T7001 for (cnt = kDVFM_STATE_IBOOT_CNT; cnt < CCC_DVFM_STATE_COUNT; cnt++) { cpu_dvfm_sram = CCC_DVFM_SRAM_STATE(cpu_dvfm_sram, cnt, cpu_sram_vid[kDVFM_STATE_IBOOT]); } rCCC_DVFM_SRAM = cpu_dvfm_sram; #endif // Configure temperature ranges and measurement offsets for DVFM/DVTM rCCC_DVFM_CFG = CCC_DVFM_CFG_TEMPTHRESH0(0x8) | CCC_DVFM_CFG_TEMPTHRESH1(0x21) | CCC_DVFM_CFG_TEMPOFFSET0(0) | CCC_DVFM_CFG_TEMPOFFSET1(0); rCCC_DVFM_CFG1 = CCC_DVFM_CFG1_TEMPTHRESH2(0x3A) | CCC_DVFM_CFG1_TEMPOFFSET2(0); #endif #if APPLICATION_IBOOT for (cnt = kSOC_PERF_STATE_IBOOT; cnt < kSOC_PERF_STATE_IBOOT_CNT; cnt++) { uint32_t vol_adj_temp = 0; #if SUB_PLATFORM_T7000 struct chipid_vol_adj adj; chipid_get_vol_adj(CHIPID_VOL_ADJ_SOC, cnt, &adj); vol_adj_temp |= PMGR_SOC_PERF_STATE_VOL_ADJ0(pmgr_get_offset_from_diff_uV(BUCK_CPU, adj.region_uV[0])); vol_adj_temp |= PMGR_SOC_PERF_STATE_VOL_ADJ1(pmgr_get_offset_from_diff_uV(BUCK_CPU, adj.region_uV[1])); vol_adj_temp |= PMGR_SOC_PERF_STATE_VOL_ADJ2(pmgr_get_offset_from_diff_uV(BUCK_CPU, adj.region_uV[2])); vol_adj_temp |= PMGR_SOC_PERF_STATE_VOL_ADJ3(pmgr_get_offset_from_diff_uV(BUCK_CPU, adj.region_uV[3])); #endif rPMGR_SOC_PERF_STATE_ENTRY_A(cnt) = pmgr_soc_perf_states[cnt].entry[0]; rPMGR_SOC_PERF_STATE_ENTRY_B(cnt) = pmgr_soc_perf_states[cnt].entry[1]; rPMGR_SOC_PERF_STATE_ENTRY_C(cnt) = pmgr_soc_perf_states[cnt].entry[2]; rPMGR_SOC_PERF_STATE_ENTRY_D(cnt) = vol_adj_temp; } for (cnt = kSOC_PERF_STATE_IBOOT_CNT; cnt < PMGR_SOC_PERF_STATE_COUNT; cnt++) { rPMGR_SOC_PERF_STATE_ENTRY_A(cnt) = rPMGR_SOC_PERF_STATE_ENTRY_A(kSOC_PERF_STATE_VMIN); rPMGR_SOC_PERF_STATE_ENTRY_B(cnt) = rPMGR_SOC_PERF_STATE_ENTRY_B(kSOC_PERF_STATE_VMIN); rPMGR_SOC_PERF_STATE_ENTRY_C(cnt) = rPMGR_SOC_PERF_STATE_ENTRY_C(kSOC_PERF_STATE_VMIN); rPMGR_SOC_PERF_STATE_ENTRY_D(cnt) = rPMGR_SOC_PERF_STATE_ENTRY_D(kSOC_PERF_STATE_VMIN); } #if SUB_PLATFORM_T7000 #ifndef BUCK_SOC #error BUCK_SOC not defined for this platform #endif platform_get_soc_voltages(kSOC_PERF_STATE_IBOOT_CNT, soc_vid); platform_convert_voltages(BUCK_SOC, kSOC_PERF_STATE_IBOOT_CNT, soc_vid); for (cnt = kSOC_PERF_STATE_IBOOT; cnt < kSOC_PERF_STATE_IBOOT_CNT; cnt++) { rPMGR_SOC_PERF_STATE_ENTRY_C(cnt) = soc_vid[cnt]; } for (cnt = kSOC_PERF_STATE_IBOOT_CNT; cnt < PMGR_SOC_PERF_STATE_COUNT; cnt++) { rPMGR_SOC_PERF_STATE_ENTRY_C(cnt) = soc_vid[kSOC_PERF_STATE_VMIN]; } #endif #endif #if APPLICATION_IBOOT #if WITH_HW_DWI extern int dwi_init(void); dwi_init(); #endif #endif set_apsc_ccc_state(active_state); // CCC clock set for this stage of boot. #if APPLICATION_IBOOT #ifndef BUCK_GPU #error BUCK_GPU not defined for this platform #endif platform_get_gpu_voltages(sizeof(gfx_states) / sizeof(gfx_states[0]), gpu_vid); #if SUB_PLATFORM_T7000 // Workaround T7000 start for (cnt = 2; cnt < sizeof(gfx_states) / sizeof(gfx_states[0]); cnt++) { if (gpu_vid[cnt] < gpu_vid[1]) { gpu_vid[cnt] = gpu_vid[1]; } } // Workaround T7000 end #endif platform_convert_voltages(BUCK_GPU, sizeof(gfx_states) / sizeof(gfx_states[0]), gpu_vid); for (cnt = 0; cnt < sizeof(gfx_states) / sizeof(gfx_states[0]); cnt++) { if (cnt == 0) gfx_states[cnt].dwi_val = 0; else gfx_states[cnt].dwi_val = gpu_vid[cnt]; } #if SUB_PLATFORM_T7001 #ifndef BUCK_RAM #error BUCK_RAM not defined for this platform #endif platform_get_gpu_ram_voltages(sizeof(gfx_states) / sizeof(gfx_states[0]), gpu_sram_vid); platform_convert_voltages(BUCK_RAM, sizeof(gfx_states) / sizeof(gfx_states[0]), gpu_sram_vid); for (cnt = 0; cnt < sizeof(gfx_states) / sizeof(gfx_states[0]); cnt++) { if (cnt == 0) gfx_states[cnt].dwi_sram_val = 0; else gfx_states[cnt].dwi_sram_val = gpu_sram_vid[cnt]; } #endif for (cnt = 0; cnt < sizeof(gfx_states) / sizeof(gfx_states[0]); cnt++) { set_gfx_perf_state(cnt, &gfx_states[cnt]); } // Complete the PERF table with GPU_VOLTAGE_OFF value for (cnt = sizeof(gfx_states) / sizeof(gfx_states[0]); cnt < kPMGR_GFX_STATE_MAX; cnt++) { set_gfx_perf_state(cnt, &gfx_states[CHIPID_GPU_VOLTAGE_OFF]); } // As per GFX Performance state software Sequence // Clear the bypass bit in PLL5 while (rPMGR_PLL_CTL(5) & PMGR_PLL_PENDING); rPMGR_PLL_EXT_BYPASS_CTL(5) &= ~PMGR_PLL_EXT_BYPASS; // PLL5 relock mode is set to 1 to switch to bypass mode while re-locking. rPMGR_PLL_CFG(5) |= (PMGR_PLL_RELOCK_MODE_BYPASS << PMGR_PLL_RELOCK_MODE_SHIFT); // Enable performance state table to control PLL5 rPMGR_GFX_PERF_STATE_CTL |= (1 << 31); // The initial SRAM, SOC, CPU voltages are set by IIC writes to the PMU (in the pmu driver). #endif #ifdef PLL0_T #if WITH_HW_AGC_MIPI rPMGR_AGILE_CLK_CTL &= ~(1 << 29); #endif set_pll(0, PLL0_P, PLL0_M, PLL0_S, 0); #endif #ifdef PLL1_T set_pll(1, PLL1_P, PLL1_M, PLL1_S, 0); #endif #ifdef PLL2_T set_pll(2, PLL2_P, PLL2_M, PLL2_S, 0); #endif #ifdef PLL3_T set_pll(3, PLL3_P, PLL3_M, PLL3_S, 0); #if SUB_PLATFORM_T7001 uint32_t pll_vreg_adj = (rCFG_FUSE8 >> CFG_FUSE8_PCIE_REF_PLL_VREG_ADJ_SHIFT) & CFG_FUSE8_PCIE_REF_PLL_VREG_ADJ_MASK; if (pll_vreg_adj == 5) { uint32_t reg = rPMGR_PLL_ANA_PARAMS0(3); reg &= ~(PMGR_PLL_ANA_PARAMS0_VREG_ADJ_MASK << PMGR_PLL_ANA_PARAMS0_VREG_ADJ_SHIFT); reg |= pll_vreg_adj << PMGR_PLL_ANA_PARAMS0_VREG_ADJ_SHIFT; rPMGR_PLL_ANA_PARAMS0(3) = reg; } #endif #endif #ifdef PLL4_T set_pll(4, PLL4_P, PLL4_M, PLL4_S, PLL4_VCO_ENABLED); #endif #ifdef PLL5_T set_pll(5, PLL5_P, PLL5_M, PLL5_S, 0); #endif #if (APPLICATION_IBOOT && !PRODUCT_IBOOT && !PRODUCT_IBEC) // Turn on NCO clocks before enabling MCA clocks. set_nco_clocks(); #endif rPMGR_SOC_PERF_STATE_CTL = SOC_PERF_STATE_ACTIVE; while (rPMGR_SOC_PERF_STATE_CTL & PMGR_SOC_PERF_STATE_CTL_PENDING_MASK); // Set all spare clock divs to their active values for (cnt = 0; cnt < PMGR_SPARE_CLK_CFG_COUNT; cnt++) { spare_clkcfgs[cnt] = spare_divs_active[cnt]; while ((spare_clkcfgs[cnt] & PMGR_CLK_CFG_PENDING) != 0); } // Set all but the spare clock divs to their active values for (cnt = 0; cnt < PMGR_CLK_CFG_COUNT; cnt++) { clkcfgs[cnt] = clk_divs_active[cnt]; while ((clkcfgs[cnt] & PMGR_CLK_CFG_PENDING) != 0); } power_on_sep(); clocks_get_frequencies(); #if (APPLICATION_IBOOT && !PRODUCT_IBOOT && !PRODUCT_IBEC) apply_pmgr_tunables(); apply_ccc_tunables(); #endif return 0; } static uint32_t get_apsc_ccc_state(void) { return ((rCCC_DVFM_CFG_SEL >> 3) & 0x7); } static void set_apsc_ccc_state(uint32_t target_state) { // DWI clock must be enabled for any state change that has voltage control enabled. rCCC_APSC_SCR = CCC_APSC_MANUAL_CHANGE(target_state); while ((rCCC_APSC_SCR & CCC_APSC_PENDING) != 0); return; } /* * set_pll - called by SecureROM, LLB, iBSS with PLLs in default reset state. * See restore_clock_config_state(). PLL1 is not enabled on entry to LLB or * or iBSS, since not configured by SecureROM. */ static void set_pll(int32_t pll, uint32_t p, uint32_t m, uint32_t s, bool vco_output) { if (pll >= PMGR_PLL_COUNT) return; // Secure ROM PLL calibration sequence changes { uint32_t vco_override = rCFG_FUSE9; // Each PMGR PLL's override values occupy contiguous 4-bit fields. // Shift the override value for this PLL to the LSB position. vco_override >>= (pll * 4); // Is the override data for this PLL valid? if (vco_override & CFG_FUSE9_PLL_VCO_RCTRL_SEL) { uint32_t reg = rPMGR_PLL_ANA_PARAMS1(pll); reg &= ~(PMGR_PLL_ANA_PARAMS1_VCO_RCTRL_OW_MASK << PMGR_PLL_ANA_PARAMS1_VCO_RCTRL_OW_SHIFT); reg |= (vco_override & CFG_FUSE9_PLL_VCO_RCTRL_OW_MASK) << PMGR_PLL_ANA_PARAMS1_VCO_RCTRL_OW_SHIFT; reg |= PMGR_PLL_ANA_PARAMS1_VCO_RCTRL_SEL; rPMGR_PLL_ANA_PARAMS1(pll) = reg; } } if (vco_output) rPMGR_PLL_CFG(pll) |= PMGR_PLL_VCO_OUT_SEL; if (p == 0) // not a PLL setting return; rPMGR_PLL_CTL(pll) = (PMGR_PLL_P(p) | PMGR_PLL_M(m) | PMGR_PLL_S(s) | PMGR_PLL_LOAD); while (rPMGR_PLL_CTL(pll) & PMGR_PLL_PENDING); rPMGR_PLL_EXT_BYPASS_CTL(pll) &= ~PMGR_PLL_EXT_BYPASS; while ((rPMGR_PLL_EXT_BYPASS_CTL(pll) & PMGR_PLL_BYP_ENABLED) != 0); rPMGR_PLL_CTL(pll) |= PMGR_PLL_ENABLE; while (rPMGR_PLL_CTL(pll) & PMGR_PLL_PENDING); } static uint32_t is_pll_running(int32_t pll) { if (pll >= PMGR_PLL_COUNT) return 0; if ((rPMGR_PLL_CTL(pll) & PMGR_PLL_ENABLE) == 0) return 0; else return 1; } /* * set_running_pll - program PLL that is already running. */ static void set_running_pll(int32_t pll, uint32_t p, uint32_t m, uint32_t s) { if (pll >= PMGR_PLL_COUNT) return; if (!is_pll_running(pll)) return; rPMGR_PLL_CTL(pll) = (PMGR_PLL_ENABLE | PMGR_PLL_P(p) | PMGR_PLL_M(m) | PMGR_PLL_S(s) | PMGR_PLL_LOAD); while (rPMGR_PLL_CTL(pll) & PMGR_PLL_PENDING); } static uint32_t get_pll_cpu(void) { uint32_t freq; uint32_t pllctl; pllctl = rCCC_PWRCTRL_PLL_SCR1; // Fcpu <= ((OSC * M) / P / S+1) freq = OSC_FREQ; freq *= (pllctl >> CCC_PLL_M_SHIFT) & CCC_PLL_M_MASK; freq /= (pllctl >> CCC_PLL_P_SHIFT) & CCC_PLL_P_MASK; freq /= 1 + ((pllctl >> CCC_PLL_S_SHIFT) & CCC_PLL_S_MASK); return freq; } static uint32_t get_pll(int32_t pll) { uint32_t pllctl; uint32_t pllbyp; uint64_t freq = 0; pllctl = rPMGR_PLL_CTL(pll); pllbyp = rPMGR_PLL_EXT_BYPASS_CTL(pll); // If PLL is not enabled, check for External Bypass if ((pllctl & PMGR_PLL_ENABLE) == 0) { if ((pllbyp & PMGR_PLL_EXT_BYPASS) == 0) return 0; else return OSC_FREQ; } freq = OSC_FREQ; freq *= ((pllctl >> PMGR_PLL_M_SHIFT) & PMGR_PLL_M_MASK); if ((rPMGR_PLL_CFG(pll) & PMGR_PLL_VCO_OUT_SEL) == 0) { freq /= (1 + ((pllctl >> PMGR_PLL_S_SHIFT) & PMGR_PLL_S_MASK)); } else { freq *= 2; } freq /= ((pllctl >> PMGR_PLL_P_SHIFT) & PMGR_PLL_P_MASK); #if DEBUG_BUILD if (freq > 0xFFFFFFFF) panic("Frequency value does not fit in uint32_t"); #endif return (uint32_t)freq; } static uint32_t get_spare(int32_t spare) { uint32_t reg_val, src_idx, src_clk, src_factor, div; volatile uint32_t *spare_clkcfg = clk_configs[PMGR_CLK_S0 + spare].clock_reg; reg_val = *spare_clkcfg; div = reg_val & 0x3F; if (((reg_val & PMGR_CLK_CFG_ENABLE) == 0) || div == 0) return 0; src_idx = (reg_val >> PMGR_CLK_CFG_SRC_SEL_SHIFT) & PMGR_CLK_CFG_SRC_SEL_MASK; src_clk = clk_configs[PMGR_CLK_S0 + spare].sources[src_idx].src_clk; src_factor = clk_configs[PMGR_CLK_S0 + spare].sources[src_idx].factor; return (clks[src_clk] / src_factor) / div; } static void clocks_get_frequencies(void) { #if SUPPORT_FPGA uint32_t cnt; uint32_t freq = OSC_FREQ; for (cnt = 0; cnt < PMGR_CLK_COUNT; cnt++) clks[cnt] = freq; clks[PMGR_CLK_CPU] = 5000000; clks[PMGR_CLK_MCU] = 10000000; clks[PMGR_CLK_MCU_FIXED] = 10000000; clks[PMGR_CLK_USB] = 12000000; #elif SUB_TARGET_TYPHONIC uint32_t cnt; uint32_t freq = OSC_FREQ; for (cnt = 0; cnt < PMGR_CLK_COUNT; cnt++) clks[cnt] = freq; #else uint32_t cnt; clks[PMGR_CLK_OSC] = OSC_FREQ; // Use get_pll() to establish the frequencies (unconfigured PLLs will bypass OSC) for (cnt = 0; cnt < PMGR_PLL_COUNT; cnt++) clks[PMGR_CLK_PLL0 + cnt] = get_pll(cnt); // Use get_spare() to establish the frequencies for spare clocks (unconfigured will be skipped) for (cnt = 0; cnt < PMGR_SPARE_CLK_CFG_COUNT; cnt++) clks[PMGR_CLK_S0 + cnt] = get_spare(cnt); clks[PMGR_CLK_CPU] = get_pll_cpu(); clocks_get_frequencies_range(PMGR_CLK_MCU_FIXED, PMGR_CLK_ANC_LINK); #endif } static void clocks_get_frequencies_range(uint32_t start_clk, uint32_t end_clk) { volatile uint32_t *reg; uint32_t cnt, val, src_idx, src_clk, src_factor; if (start_clk < PMGR_CLK_SOURCE_FIRST || end_clk > PMGR_CLK_SOURCE_LAST) return; for (cnt = start_clk; cnt <= end_clk; cnt++) { reg = clk_configs[cnt].clock_reg; val = *reg; if ((val & PMGR_CLK_CFG_ENABLE) == 0) { clks[cnt] = 0; continue; } src_idx = (val >> PMGR_CLK_CFG_SRC_SEL_SHIFT) & PMGR_CLK_CFG_SRC_SEL_MASK; src_clk = clk_configs[cnt].sources[src_idx].src_clk; src_factor = clk_configs[cnt].sources[src_idx].factor; clks[cnt] = clks[src_clk] / src_factor; } } void dump_clock_frequencies() { uint32_t i; for (i = 0; i < PMGR_CLK_COUNT; i++) { dprintf(DEBUG_CRITICAL, "clk[%d] -> %u\n", i, clks[i]); } } static void clock_update_range(uint32_t first, uint32_t last, const uint32_t clkdata) { volatile uint32_t *clkcfgs = PMGR_FIRST_CLK_CFG; uint32_t reg; reg = first; while (reg <= last) { clkcfgs[reg] = clkdata; while (clkcfgs[reg] & PMGR_CLK_CFG_PENDING); reg++; } } static void clock_update_frequency(uint32_t clk, uint32_t freq) { #define ROUND_10E4(_x) ((((_x) + 5000) / 10000) * 10000) uint32_t src_idx, src_clk, src_factor, reg; bool freq_supported = false; volatile uint32_t *clkcfg = clk_configs[clk].clock_reg; if (freq == 0) return; for (src_idx = 0; src_idx < CLOCK_SOURCES_MAX && clk_configs[clk].sources[src_idx].factor != 0; src_idx++) { src_clk = clk_configs[clk].sources[src_idx].src_clk; src_factor = clk_configs[clk].sources[src_idx].factor; if (ROUND_10E4(clks[src_clk] / src_factor) == freq) { freq_supported = true; break; } } if (!freq_supported) { // Frequency not supported by CLK_CFG register, try spare uint32_t spare, spare_src_idx, spare_src_freq, spare_div; const struct clock_source *spare_clk_src; volatile uint32_t *spare_clkcfgs = PMGR_FIRST_SPARE_CLK_CFG; switch (clk) { case PMGR_CLK_VID0: // Use spare 0 with PLL4 div 3 as source clock spare = 0; spare_src_idx = 0; // Set VID0 clock source to spare 0 src_idx = 1; break; default: return; } spare_clk_src = &clk_configs[PMGR_CLK_S0 + spare].sources[spare_src_idx]; spare_src_freq = clks[spare_clk_src->src_clk] / spare_clk_src->factor; for (spare_div = 1; spare_div < 16; spare_div++) { if (ROUND_10E4(spare_src_freq / spare_div) == freq) { freq_supported = true; break; } } if (freq_supported) { // Configure spare spare_clkcfgs[spare] = PMGR_CLK_CFG_ENABLE | (spare_src_idx << PMGR_CLK_CFG_SRC_SEL_SHIFT) | PMGR_CLK_CFG_DIVISOR(spare_div); while ((spare_clkcfgs[spare] & PMGR_CLK_CFG_PENDING) != 0); clks[PMGR_CLK_S0 + spare] = get_spare(spare); } } if (freq_supported) { // Configure clock reg = *clkcfg; reg &= ~(PMGR_CLK_CFG_SRC_SEL_MASK << PMGR_CLK_CFG_SRC_SEL_SHIFT); reg |= (src_idx & PMGR_CLK_CFG_SRC_SEL_MASK) << PMGR_CLK_CFG_SRC_SEL_SHIFT; *clkcfg = reg; while (*clkcfg & PMGR_CLK_CFG_PENDING); } } static void restore_clock_config_state(void) { uint32_t cnt; uint32_t soc_perf_state; // 3. Write reset value to ACG, CLK_DIVIDER_ACG_CFG rPMGR_MISC_ACG = 0; rPMGR_CLK_DIVIDER_ACG_CFG = 0; #if (APPLICATION_IBOOT && !PRODUCT_IBOOT && !PRODUCT_IBEC) // 4. Write the reset value to all MCAx_CLK_CFG registers clock_update_range(PMGR_CLK_NUM(MCA0_M), PMGR_CLK_NUM(MCA4_M), 0x80100000); // 5. Put the NCOs in reset state for (cnt = 0; cnt < PMGR_NUM_NCO; cnt++) { rPMGR_NCO_CLK_CFG(cnt) = 0; while (rPMGR_NCO_CLK_CFG(cnt) & PMGR_NCO_CLK_CFG_PENDING); } #endif // 6. Write reset value for all mux clock configs (excluding spares) clock_update_range(PMGR_CLK_NUM(MCU_FIXED), PMGR_CLK_NUM(ANC_LINK), 0x80100000); soc_perf_state = (rPMGR_SOC_PERF_STATE_CTL >> PMGR_SOC_PERF_STATE_CTL_CURRENT_SELECT_SHIFT) & PMGR_SOC_PERF_STATE_CTL_CURRENT_SELECT_MASK; if (soc_perf_state != kSOC_PERF_STATE_BYPASS) { // 7a. Write the desired DRAM clock configuration state into the SOC_PERF_STATE_ENTRY_0A register rPMGR_SOC_PERF_STATE_ENTRY_A(kSOC_PERF_STATE_BYPASS) = (pmgr_soc_perf_states[kSOC_PERF_STATE_BYPASS].entry[0] & ~PMGR_SOC_PERF_STATE_ENTRY_MCU_MASK) | (rPMGR_SOC_PERF_STATE_ENTRY_A(soc_perf_state) & PMGR_SOC_PERF_STATE_ENTRY_MCU_MASK); // 7b. Write the reset value to all other fields in ENTRY_0A rPMGR_SOC_PERF_STATE_ENTRY_B(kSOC_PERF_STATE_BYPASS) = pmgr_soc_perf_states[kSOC_PERF_STATE_BYPASS].entry[1]; rPMGR_SOC_PERF_STATE_ENTRY_C(kSOC_PERF_STATE_BYPASS) = pmgr_soc_perf_states[kSOC_PERF_STATE_BYPASS].entry[2]; rPMGR_SOC_PERF_STATE_ENTRY_D(kSOC_PERF_STATE_BYPASS) = 0; // 8. Write the reset value to the SOC_PERF_STATE_CTL register rPMGR_SOC_PERF_STATE_CTL = kSOC_PERF_STATE_BYPASS; while (rPMGR_SOC_PERF_STATE_CTL & PMGR_SOC_PERF_STATE_CTL_PENDING_MASK); // 9. Write the reset values to the SOC_PERF_STATE entry registers for (cnt = 0; cnt < PMGR_SOC_PERF_STATE_COUNT; cnt++) { if (cnt == kSOC_PERF_STATE_BYPASS) continue; rPMGR_SOC_PERF_STATE_ENTRY_A(cnt) = 0; rPMGR_SOC_PERF_STATE_ENTRY_B(cnt) = 0; rPMGR_SOC_PERF_STATE_ENTRY_C(cnt) = 0; rPMGR_SOC_PERF_STATE_ENTRY_D(cnt) = 0; } } // 11. Write all PLLx_EXT_BYPASS_CTL.EXT_BYPASS to 1 for (cnt = 0; cnt < PMGR_PLL_COUNT; cnt++) { if (cnt == 1) continue; // Mem PLL // Make sure the PLL can accept a bypass state change. while (rPMGR_PLL_CTL(cnt) & PMGR_PLL_PENDING); // Switch to bypass mode. rPMGR_PLL_EXT_BYPASS_CTL(cnt) |= PMGR_PLL_EXT_BYPASS; while ((rPMGR_PLL_EXT_BYPASS_CTL(cnt) & PMGR_PLL_BYP_ENABLED) == 0); } // 14. Write reset value to all PLLx_CTL for (cnt = 0; cnt < PMGR_PLL_COUNT; cnt++) { if (cnt == 1) continue; // Mem PLL rPMGR_PLL_CTL(cnt) = PMGR_PLL_M(1) | PMGR_PLL_P(1); // fb_div = 1, pre_div = 1 while (rPMGR_PLL_CTL(cnt) & PMGR_PLL_PENDING); } // 15. Write reset value to all other PLL registers for (cnt = 0; cnt < PMGR_PLL_COUNT; cnt++) { if (cnt == 1) continue; // Mem PLL rPMGR_PLL_CFG(cnt) = PMGR_PLL_OFF_MODE(PMGR_PLL_OFF_MODE_POWER_DOWN) | PMGR_PLL_FRAC_LOCK_TIME(0x48) | PMGR_PLL_LOCK_TIME(0x348); } // 16. Write reset value to spare and ISP_REF0/1 clock_update_range(PMGR_CLK_NUM(S0), PMGR_CLK_NUM(ISP_REF1), 0x80000001); // 17. Put CPU clock back into its reset default. set_apsc_ccc_state(kDVFM_STATE_BYPASS); } static void power_on_sep(void) { volatile uint32_t *reg = (volatile uint32_t *)((uint64_t *)PMGR_FIRST_PS + CLK_SEP); uint32_t val = *reg; val &= ~(PMGR_PS_AUTO_PM_EN | PMGR_PS_FORCE_NOACCESS); *reg = val; while (((*reg >> 4) & 0xF) != 0xF); // Wait for SEP to turn on. return; } static void set_device(uint64_t *devices, uint64_t device) { #if DEBUG_BUILD if (device >= 128) panic("Invalid device clock index: %llu", device); #endif if (device >= 64) devices[1] |= (0x1ULL << (device - 64)); else devices[0] |= (0x1ULL << device); } static void clocks_quiesce_internal(void) { uint64_t devices[2] = { 0, 0 }; // Disable all voltage changes everywhere! rPMGR_VOLMAN_CTL |= (PMGR_VOLMAN_DISABLE_CPU_VOL_CHANGE | PMGR_VOLMAN_DISABLE_GFX_VOL_CHANGE | PMGR_VOLMAN_DISABLE_FIXED_VOL_CHANGE | PMGR_VOLMAN_DISABLE_VAR_SOC_VOL_CHANGE); // We don't touch CPU0, CPU1, CPM but the following devices need to be on. set_device(devices, CLK_LIO); set_device(devices, CLK_IOMUX); set_device(devices, CLK_AIC); set_device(devices, CLK_DEBUG); set_device(devices, CLK_DWI); set_device(devices, CLK_GPIO); set_device(devices, CLK_SIO); set_device(devices, CLK_SIO_P); set_device(devices, CLK_ANS); set_device(devices, CLK_MCC); set_device(devices, CLK_MCU); set_device(devices, CLK_AMP); set_device(devices, CLK_USB); set_device(devices, CLK_USBCTLREG); set_device(devices, CLK_USB_OTG); set_device(devices, CLK_SMX); set_device(devices, CLK_SF); set_device(devices, CLK_CP); set_device(devices, CLK_PCIE_AUX); // Turn on/off critical device clocks clocks_set_gates(devices); // Disable performance state table to control PLL5 rPMGR_GFX_PERF_STATE_CTL = 0; restore_clock_config_state(); } void clocks_quiesce(void) { clocks_quiesce_internal(); } uint32_t clocks_set_performance(uint32_t performance_level) { uint32_t old_perf_level = perf_level; uint32_t ccc_state = get_apsc_ccc_state(); if (ccc_state != active_state) set_apsc_ccc_state(active_state); #if APPLICATION_IBOOT if (performance_level == kPerformanceMemoryLow || performance_level == kPerformanceMemoryFull) { rPMGR_SOC_PERF_STATE_CTL = (performance_level == kPerformanceMemoryLow) ? kSOC_PERF_STATE_IBOOT_MEM_LOW_PERF : kSOC_PERF_STATE_IBOOT_MEM_FULL_PERF; // Wait for Pending bits to clear. while (rPMGR_SOC_PERF_STATE_CTL & PMGR_SOC_PERF_STATE_CTL_PENDING_MASK); perf_level = performance_level; clocks_get_frequencies_range(PMGR_CLK_MCU_FIXED, PMGR_CLK_MCU); } #endif // At this point we should have CCC clock set for this stage of boot. return old_perf_level; } void clock_get_frequencies(uint32_t *clocks, uint32_t count) { uint32_t cnt = PMGR_CLK_COUNT; if (cnt > count) cnt = count; memcpy(clocks, clks, cnt * sizeof(uint32_t)); } uint32_t clock_get_frequency(int clock) { uint32_t freq = 0; // XXX TODO switch (clock) { case CLK_NCLK: case CLK_FIXED: case CLK_TIMEBASE: freq = clks[PMGR_CLK_OSC]; break; case CLK_PCLK: case CLK_PERIPH: case CLK_I2C0: case CLK_I2C1: case CLK_I2C2: freq = clks[PMGR_CLK_SIO_P]; break; case CLK_MEM: freq = clks[PMGR_CLK_MCU]; break; case CLK_ANS_LINK: freq = clks[PMGR_CLK_ANC_LINK]; break; case CLK_BUS: freq = clks[PMGR_CLK_LIO]; break; case CLK_CPU: freq = clks[PMGR_CLK_CPU]; break; #if SUB_PLATFORM_T7000 case CLK_MIPI: freq = clks[PMGR_CLK_MIPI_DSI]; break; #endif case CLK_VCLK0: freq = clks[PMGR_CLK_VID0]; break; default: break; } return freq; } void clock_set_frequency(int clock, uint32_t divider, uint32_t pll_p, uint32_t pll_m, uint32_t pll_s, uint32_t pll_t) { uint32_t clk = PMGR_CLK_OSC; switch (clock) { case CLK_VCLK0: clk = PMGR_CLK_VID0; break; #if SUB_PLATFORM_T7000 case CLK_MIPI: clk = PMGR_CLK_PLL0; break; #endif default: break; } if (clk >= PMGR_CLK_PLL0 && clk <= PMGR_CLK_PLL5) { int32_t pll = clk - PMGR_CLK_PLL0; if (!is_pll_running(pll)) set_pll(pll, pll_p, pll_m, pll_s, false); else set_running_pll(pll, pll_p, pll_m, pll_s); clks[clk] = get_pll(pll); #if SUB_PLATFORM_T7000 if (clock == CLK_MIPI) { clocks_get_frequencies_range(PMGR_CLK_MIPI_DSI, PMGR_CLK_MIPI_DSI); } #endif } if (clk >= PMGR_CLK_SOURCE_FIRST && clk <= PMGR_CLK_SOURCE_LAST) { clock_update_frequency(clk, pll_t); clocks_get_frequencies_range(clk, clk); } return; } void clock_gate(int device, bool enable) { volatile uint32_t *reg = (volatile uint32_t *)((uint64_t *)PMGR_FIRST_PS + device); // Make sure we are within limits. if (reg > PMGR_LAST_PS) return; #if APPLICATION_IBOOT && SUPPORT_FPGA // Old versions of FPGA Secure ROM set FORCE_NOACCESS bit when powering off a block. Make sure bit is cleared. *reg &= ~PMGR_PS_FORCE_NOACCESS; #endif // Set the PS field to the requested level if (enable) { *reg |= PMGR_PS_RUN_MAX; } else { *reg &= ~PMGR_PS_RUN_MAX; } // Wait for the MANUAL_PS and ACTUAL_PS fields to be equal while ((*reg & PMGR_PS_MANUAL_PS_MASK) != ((*reg >> PMGR_PS_ACTUAL_PS_SHIFT) & PMGR_PS_ACTUAL_PS_MASK)); } static void clocks_set_gates(uint64_t *devices) { uint32_t i, idx; // For future platforms that clone from this. if (PMGR_LAST_DEVICE >= 128) panic("Rewrite this to deal with more than 128 clock ids"); // Make sure SIO_P is on before SIO. clock_gate(CLK_SIO_P, true); // Turn on devices from lo to hi (to meet dependencies). for (idx = 0, i = PMGR_FIRST_DEVICE; i < PMGR_LAST_DEVICE; i++) { if (i && ((i % 64) == 0)) idx++; if ((devices[idx] >> ((uint64_t)(i % 64))) & 0x1) clock_gate(i, true); } // Turn off devices hi to lo order (to meet dependencies). for (idx = 1, i = PMGR_LAST_DEVICE - 1; i >= PMGR_FIRST_DEVICE; i--) { if (!((devices[idx] >> ((uint64_t)(i % 64))) & 0x1)) clock_gate(i, false); if (i && ((i % 64) == 0)) idx--; } return; } void platform_system_reset(bool panic) { #if WITH_BOOT_STAGE if (!panic) boot_set_stage(kPowerNVRAMiBootStageOff); #endif wdt_system_reset(); while (1); } void platform_reset(bool panic) { #if WITH_BOOT_STAGE if (!panic) boot_set_stage(kPowerNVRAMiBootStageOff); #endif wdt_chip_reset(); while (1); } void platform_power_init(void) { /* Disable Power gating for CPU0, this is needed to avoid WFI from powering down the core */ /* Remove this once following is addressed: Core 0 power gating enabled by default */ rPMGR_PWRGATE_CPU0_CFG0 &= ~(1UL << 31); #if (APPLICATION_IBOOT && !PRODUCT_IBOOT && !PRODUCT_IBEC) // Initialize temperature sensors, thermal failsafe blocks, and TVM tunables init_soc_thermal_sensors(); init_cpu_thermal_sensors(); init_soc_sochot(); init_cpu_sochot(); init_soc_tvm_tunables(); #endif } void platform_watchdog_tickle(void) { // Varies by target. This layer between is necessary so that // we don't go straight from generic code to target. target_watchdog_tickle(); } void clock_reset_device(int device) { volatile uint32_t *reg = (volatile uint32_t *)((uint64_t *)PMGR_FIRST_PS + device); uint32_t lpdp_override = 4; bool lpdp_fuse_ow_enable = false; // Make sure we are within limits. if (device >= PMGR_LAST_DEVICE) return; // XXX TODO switch (device) { case CLK_MCU: case CLK_ANS: case CLK_SIO: case CLK_EDPLINK: #if SUB_PLATFORM_T7000 case CLK_MIPI: #endif *reg |= PMGR_PS_FORCE_NOACCESS; spin(1); *reg |= PMGR_PS_RESET; spin(1); *reg &= ~(PMGR_PS_RESET | PMGR_PS_FORCE_NOACCESS); if (device == CLK_EDPLINK) { //Begin : SecureROM PLL calibration sequence changes lpdp_override = rCFG_FUSE9; lpdp_override >>= CFG_FUSE9_PLL_LPDP_SHIFT; lpdp_fuse_ow_enable = lpdp_override & CFG_FUSE9_PLL_VCO_RCTRL_SEL; // Is the override data for this PLL valid? if (lpdp_fuse_ow_enable) { #define rLPDP_PLL_CLK (*(volatile u_int32_t *)(LPDP_PHY_BASE_ADDR + 0x00084)) #define LPDP_PLL_CLK_VCO_RCTRL_OW_SHIFT 2 #define LPDP_PLL_CLK_VCO_RCTRL_OW_MASK 0x7 #define LPDP_PLL_CLK_VCO_RCTRL_SEL_ENABLE 0x1 #define LPDP_PLL_CLK_VCO_RCTRL_SEL_SHIFT 0x5 uint32_t reg = rLPDP_PLL_CLK; reg &= ~(LPDP_PLL_CLK_VCO_RCTRL_OW_MASK << LPDP_PLL_CLK_VCO_RCTRL_OW_SHIFT); reg |= (lpdp_override & LPDP_PLL_CLK_VCO_RCTRL_OW_MASK) << LPDP_PLL_CLK_VCO_RCTRL_OW_SHIFT; reg |= (LPDP_PLL_CLK_VCO_RCTRL_SEL_ENABLE << LPDP_PLL_CLK_VCO_RCTRL_SEL_SHIFT); rLPDP_PLL_CLK = reg; } // End : SecureROM PLL calibration sequence changes } break; default: break; } } void clock_set_device_reset(int device, bool set) { volatile uint32_t *reg = (volatile uint32_t *)((uint64_t *)PMGR_FIRST_PS + device); switch (device) { case CLK_PCIE: if (set) { *reg |= PMGR_PS_FORCE_NOACCESS; spin(1); *reg |= PMGR_PS_RESET; } else { *reg &= ~(PMGR_PS_RESET | PMGR_PS_FORCE_NOACCESS); } } } bool clock_get_pcie_refclk_good(void) { #if SUB_PLATFORM_T7000 return true; #elif SUB_PLATFORM_T7001 return (rPMGR_DEBUG_PMGR_DEBUG18 & (1 << 18)) != 0; #endif } #if APPLICATION_IBOOT static void set_gfx_perf_state(uint32_t state_num, struct gfx_state_info *gfx_state) { uint32_t pll_enable = 0; // This is deductive. If feedback divider is 0 the PLL shouldn't output anything. pll_enable = gfx_state->fb_div ? 1 : 0; rPMGR_GFX_PERF_STATE_ENTRY(state_num) = ((gfx_state->dwi_val & 0xFF) << 24) | ((pll_enable & 0x1) << 21) | ((gfx_state->fb_div & 0x1FF) << 12) | ((gfx_state->pre_div & 0x1F) << 4) | (gfx_state->op_div & 0xF); #if SUB_PLATFORM_T7001 rPMGR_GFX_SRAM_PERF_STATE_ENTRY(state_num) = gfx_state->dwi_sram_val & 0xff; #endif } #endif #if WITH_DEVICETREE static uint64_t get_freq_from_ccc_state(uint64_t state_entry) { // Fcpu <= ((OSC * M) / P / S+1) uint64_t freq = OSC_FREQ; freq *= ((state_entry >> 4) & 0x1FF); freq /= ((state_entry >> 13) & 0x1F) ? ((state_entry >> 13) & 0x1F) : 1; freq /= (1 + ((state_entry >> 0) & 0xF)); return freq; } void pmgr_update_device_tree(DTNode *pmgr_node) { uint32_t num_freqs = 0; uint32_t propSize; uint64_t period_ns; uint64_t freq = 0; uint32_t volt; char *propName; void *propData; struct dvfm_data dvfm = { .dvfm_state_vmax = kDVFM_STATE_VMAX, .dvfm_state_iboot_cnt = kDVFM_STATE_IBOOT_CNT, .dvfm_state_vnom = kDVFM_STATE_VNOM, .dvfm_state_vboost = kDVFM_STATE_VBOOST, .voltage_states1_count = kVOLTAGE_STATES1_COUNT, }; #if SUB_PLATFORM_T7001 pmgr_get_dvfm_data(&dvfm); #endif // Populate the devicetree with relevant values. propName = "nominal-performance1"; if (FindProperty(pmgr_node, &propName, &propData, &propSize)) { if (propSize != sizeof(uint32_t)) panic("pmgr property nominal-performance1 is of wrong size."); freq = get_freq_from_ccc_state(rCCC_DVFM_ST(dvfm.dvfm_state_vnom)); if (freq == 0) panic("pmgr Fnom Operating point not defined correctly"); period_ns = 1000000000ULL << 16; period_ns /= freq; ((uint32_t *)propData)[0] = period_ns; } else { panic("pmgr property nominal-performance1 not found."); } propName = "boost-performance1"; // Note: Boost is not mandatory in all platforms. if (FindProperty(pmgr_node, &propName, &propData, &propSize)) { if (propSize != sizeof(uint32_t)) panic("pmgr property boost-performance1 is of wrong size"); freq = get_freq_from_ccc_state(rCCC_DVFM_ST(dvfm.dvfm_state_vboost)); if (freq == 0) panic("pmgr Fboost Operating point not defined correctly"); period_ns = 1000000000ULL << 16; period_ns /= freq; ((uint32_t *)propData)[0] = period_ns; } propName = "voltage-states1"; if (FindProperty(pmgr_node, &propName, &propData, &propSize)) { if (propSize / sizeof(uint32_t) < dvfm.voltage_states1_size) { panic("pmgr number of states less than required for voltage-states1"); } num_freqs = dvfm.voltage_states1_count; for (int32_t i = num_freqs - 1, j = 0; i >= 0; i--, j++) { // Getting voltage and frequencies directly from rCCC_DVFM_ST allows // including all the changes done before launching the kernel: // - voltage adjusting coming from converting voltage to PMU value, // - voltage knobs from LLB, // - astris changes done while beeing in iBoot console, freq = get_freq_from_ccc_state(rCCC_DVFM_ST(dvfm.dvfm_state_vmax - j)); volt = platform_get_dwi_to_mv(BUCK_CPU, CCC_DVFM_ST_TO_SAFEVOL(rCCC_DVFM_ST(dvfm.dvfm_state_vmax - j))); if (freq != 0) { period_ns = 1000000000ULL << 16; period_ns /= freq; ((uint32_t *)propData)[2*i] = period_ns; ((uint32_t *)propData)[2*i+1] = volt; } } } propName = "total-rails-leakage"; if (FindProperty(pmgr_node, &propName, &propData, &propSize)) { if (propSize >= sizeof(uint32_t)) { *(uint32_t *)propData = chipid_get_total_rails_leakage(); } } return; } void pmgr_gfx_update_device_tree(DTNode *gfx_node) { u_int32_t count, propSize, num_states = 0, state_val; char *propName; void *propData; propName = "perf-states"; if (FindProperty(gfx_node, &propName, &propData, &propSize)) { if (propSize != (2 * sizeof(u_int32_t) * kPMGR_GFX_STATE_MAX)) { panic("gfx property perf-state has wrong size"); } // Read the values programmed into the GFX perf state table // and populate the device tree. for (count = 0; count < kPMGR_GFX_STATE_MAX; count++) { state_val = rPMGR_GFX_PERF_STATE_ENTRY(count); // Any but the first entry with a value of 0 marks the end of the number of valid states. if ((count != 0) && (state_val == rPMGR_GFX_PERF_STATE_ENTRY(CHIPID_GPU_VOLTAGE_OFF))) { num_states = count; break; } ((u_int32_t *)propData)[count * 2 + 0] = PMGR_PLL_FREQ((state_val >> 12) & 0x1FF, (state_val >> 4) & 0x1F, state_val & 0xF); ((u_int32_t *)propData)[count * 2 + 1] = platform_get_dwi_to_mv(BUCK_GPU, (state_val >> 24) & 0xFF); } // If all the entries are valid. if (count == kPMGR_GFX_STATE_MAX) { num_states = kPMGR_GFX_STATE_MAX; } } propName = "perf-state-count"; if (FindProperty(gfx_node, &propName, &propData, &propSize)) { *(u_int32_t *)propData = kPMGR_GFX_STATE_MAX; // This is the value given before } propName = "gpu-num-perf-states"; /* We don't count DIDT states and OFF state */ if (FindProperty(gfx_node, &propName, &propData, &propSize)) { *(u_int32_t *)propData = num_states / 2; } return; } void sochot_pmgr_update_device_tree(DTNode *node) { uint32_t propSize; char *propName; void *propData; propName = "target-dvfm-state-0"; if (FindProperty(node, &propName, &propData, &propSize)) { if (propSize >= sizeof(uint32_t)) { *(uint32_t *)propData = CCC_DFVM_FSHOT_IDX_THERMAL0_STATE; } } propName = "target-dvfm-state-1"; if (FindProperty(node, &propName, &propData, &propSize)) { if (propSize >= sizeof(uint32_t)) { *(uint32_t *)propData = CCC_DFVM_FSHOT_IDX_THERMAL1_STATE; } } } #endif #if (APPLICATION_IBOOT && !PRODUCT_IBOOT && !PRODUCT_IBEC) static void init_soc_thermal_sensors(void) { // Keep sampling rate at default 1 kHz (pending Tune temperature sensor sampling rates for Fiji/Capri) // Define piecewise-linear relationship (start_codes, offsets, slopes) between output and temperature for SOC/PMGR sensors rPMGR_THERMAL0_PIECE0 = PMGR_THERMAL_PIECE(0x000, 0x1d4, 0x036); rPMGR_THERMAL0_PIECE1 = PMGR_THERMAL_PIECE(0x1aa, 0x1e3, 0x02d); rPMGR_THERMAL0_PIECE2 = PMGR_THERMAL_PIECE(0x270, 0x1f9, 0x024); rPMGR_THERMAL1_PIECE0 = PMGR_THERMAL_PIECE(0x000, 0x1d4, 0x036); rPMGR_THERMAL1_PIECE1 = PMGR_THERMAL_PIECE(0x1aa, 0x1e3, 0x02d); rPMGR_THERMAL1_PIECE2 = PMGR_THERMAL_PIECE(0x270, 0x1f9, 0x024); // Read temperature trim values from efuse and write to corresponding registers (CPU sensors handle this step in hardware) rPMGR_THERMAL0_PARAM = PMGR_THERMAL_PARAM_SET_TRIM(rPMGR_THERMAL0_PARAM, chipid_get_soc_temp_sensor_trim(0)); rPMGR_THERMAL1_PARAM = PMGR_THERMAL_PARAM_SET_TRIM(rPMGR_THERMAL1_PARAM, chipid_get_soc_temp_sensor_trim(1)); rPMGR_THERMAL0_CTL1 = 0xea60; rPMGR_THERMAL1_CTL1 = 0xea60; // Enable temperature sensors (need to do this before enabling either DVTM or thermal failsafe) rPMGR_THERMAL0_CTL0_SET = PMGR_THERMAL_CTL0_ENABLE; rPMGR_THERMAL1_CTL0_SET = PMGR_THERMAL_CTL0_ENABLE; } static void init_soc_sochot(void) { // Set target state for when SOCHOT triggers rPMGR_GFX_PERF_STATE_SOCHOT = PMGR_GFX_PERF_STATE_SOCHOT_ENABLE_TRIG0 | PMGR_GFX_PERF_STATE_SOCHOT_TRIG0_SELECT(1); // SOC SOCHOT not supported due to certain media use cases having hard clock requirements } static void init_cpu_thermal_sensors(void) { // Keep sampling rate at default 1 kHz (pending Tune temperature sensor sampling rates for Fiji/Capri) // Define piecewise-linear relationship (start_codes, offsets, slopes) between output and temperature for CPU sensors rCCC_THRM0_PIECE0 = CCC_THRM_PIECE(0x000, 0x0d4, 0x036); rCCC_THRM0_PIECE1 = CCC_THRM_PIECE(0x1aa, 0x0e3, 0x02d); rCCC_THRM0_PIECE2 = CCC_THRM_PIECE(0x270, 0x0f9, 0x024); rCCC_THRM1_PIECE0 = CCC_THRM_PIECE(0x000, 0x0d4, 0x036); rCCC_THRM1_PIECE1 = CCC_THRM_PIECE(0x1aa, 0x0e3, 0x02d); rCCC_THRM1_PIECE2 = CCC_THRM_PIECE(0x270, 0x0f9, 0x024); rCCC_THRM2_PIECE0 = CCC_THRM_PIECE(0x000, 0x0d4, 0x036); rCCC_THRM2_PIECE1 = CCC_THRM_PIECE(0x1aa, 0x0e3, 0x02d); rCCC_THRM2_PIECE2 = CCC_THRM_PIECE(0x270, 0x0f9, 0x024); #if SUB_PLATFORM_T7001 rCCC_THRM3_PIECE0 = CCC_THRM_PIECE(0x000, 0x0d4, 0x036); rCCC_THRM3_PIECE1 = CCC_THRM_PIECE(0x1aa, 0x0e3, 0x02d); rCCC_THRM3_PIECE2 = CCC_THRM_PIECE(0x270, 0x0f9, 0x024); #endif // Per , although the CPU sensors handle the step of reading temperature trim from efuse and writing // this to THRMn_PARAM in hardware, the value doesn't actually take effect until an explicit register write is done -- so the // workaround for this errata is to read out and then write back the contents of each CCC_THRMn_PARAM register, unchanged. rCCC_THRM0_PARAM = rCCC_THRM0_PARAM; rCCC_THRM1_PARAM = rCCC_THRM1_PARAM; rCCC_THRM2_PARAM = rCCC_THRM2_PARAM; #if SUB_PLATFORM_T7001 rCCC_THRM3_PARAM = rCCC_THRM3_PARAM; #endif rCCC_THRM0_CTL1 = 0xea60; rCCC_THRM1_CTL1 = 0xea60; rCCC_THRM2_CTL1 = 0xea60; #if SUB_PLATFORM_T7001 rCCC_THRM3_CTL1 = 0xea60; #endif // Enable temperature sensors (need to do this before enabling either DVTM or thermal failsafe) rCCC_THRM0_CTL0_SET = CCC_THRM_CTL0_ENABLE; rCCC_THRM1_CTL0_SET = CCC_THRM_CTL0_ENABLE; rCCC_THRM2_CTL0_SET = CCC_THRM_CTL0_ENABLE; #if SUB_PLATFORM_T7001 rCCC_THRM3_CTL0_SET = CCC_THRM_CTL0_ENABLE; #endif } static void init_cpu_sochot(void) { // Set target state for when SOCHOT triggers rCCC_DVFM_FSHOT_IDX = CCC_DFVM_FSHOT_IDX_THERMAL0(kDVFM_STATE_V0); } static void init_soc_tvm_tunables(void) { rPMGR_TVM_THRESH0 = PMGR_TVM_THRESH(0x00); rPMGR_TVM_THRESH1 = PMGR_TVM_THRESH(0x19); rPMGR_TVM_THRESH2 = PMGR_TVM_THRESH(0x32); rPMGR_TVM_TEMP0_CFG = PMGR_TVM_TEMP_CFG_MAX_OFFSET(0x5) | PMGR_TVM_TEMP_CFG_MIN_OFFSET(0x1F6); rPMGR_TVM_TEMP1_CFG = PMGR_TVM_TEMP_CFG_MAX_OFFSET(0x5) | PMGR_TVM_TEMP_CFG_MIN_OFFSET(0x1FB); } #endif