/* * Copyright (C) 2009-2012 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 !APPLICATION_EMBEDDEDIOP #define PLL_VCO_TARGET(pllx) (2ULL * pllx##_O * pllx##_M / pllx##_P) #define PLL_FREQ_TARGET(pllx) (2ULL * pllx##_O * pllx##_M / pllx##_P / (1 << pllx##_S)) static u_int32_t clk_divs_bypass[PMGR_CLK_CFG_COUNT] = { 0x80008421, 0x80000000, 0x80000001, 0x80000001, // cpu, mcu_fixed, mcu, pclk1 0x80000001, 0x80000001, 0x80000001, 0x80000001, // prediv0, prediv1, prediv2, prediv3 0x80000001, 0x80000001, 0x80000001, 0x80000000, // prediv4, prediv5, prediv6, managed0 0x80000000, 0x80000000, 0x80000000, 0x80000000, // managed1, managed2, managed3, managed4 0x80000001, 0x80000001, 0x80000001, 0xB0000001, // vid1, medium0, vid0, i2c 0x80000001, 0x80000001, 0x80000001, 0x80000001, // sdio, mipi_dsi, audio, hpark_pclk0 0x80000001, 0x80000001, 0x80000001, 0x80000001, // hpark_tclk, uperf, debug, hperf_rt 0x80000001, 0x80000001, 0x80000001, 0x80000001, // gfx, gfx_slc, hperf_nrt, isp 0x80000001, 0x80000001, 0x80000001, 0x80000001, // iop, cdio, lperfs, pclk0 0x80000001, 0x80000001, 0x8000001f, 0x80000001, // pclk2, pclk3, medium1, spi0 0x80000001, 0x80000001, 0x80000001, 0x80000001, // spi1, spi2, spi3, spi4 0x80000021, 0x80000001, 0x80000001, 0x80000001, // sleep, usbphy, usbohci, usb12 0x80000001, 0x80000001, 0x80000000, 0x80000001, // nco_ref0, nco_ref1, venc_mtx, venc }; static u_int32_t perf_state_bypass[3] = { 0x01010101, 0x03010101, 0x00000001, // defaults, slow mcu_cfg }; struct perf_info { u_int8_t perf_state; u_int8_t perf_div; }; #if APPLICATION_IBOOT #ifndef TARGET_EMA_CTL_CPU_SEL #define TARGET_EMA_CTL_CPU_SEL 1 #endif #ifndef TARGET_CPU_SOURCE #define TARGET_CPU_SOURCE 1 #endif #ifndef TARGET_SPI2_SOURCE #define TARGET_SPI2_SOURCE 3 #endif #ifndef TARGET_MIPI_DSI_SOURCE #error TARGET_MIPI_DSI_SOURCE undefined #endif #ifndef TARGET_MANAGED2H_SOURCE #error TARGET_MANAGED2H_SOURCE undefined #endif #ifndef TARGET_MANAGED2L_SOURCE #error TARGET_MANAGED2L_SOURCE undefined #endif #ifndef TARGET_MANAGED2H_DIV #error TARGET_MANAGED2H_DIV undefined #endif #ifndef TARGET_MANAGED2L_DIV #error TARGET_MANAGED2L_DIV undefined #endif #ifndef TARGET_GFX_SOURCE #error TARGET_GFX_SOURCE undefined #endif #ifndef TARGET_GFX_SLC_SOURCE #error TARGET_GFX_SLC_SOURCE undefined #endif #ifndef TARGET_CPU_850M #define PLL0 0 #define PLL0_O OSC_FREQ #define PLL0_P 6 #define PLL0_M 250 #define PLL0_S 1 #define PLL0_V PLL_VCO_TARGET(PLL0) #define PLL0_T PLL_FREQ_TARGET(PLL0) #endif #if TARGET_CPU_SOURCE == 2 #if TARGET_CPU_850M #define PLL1 1 #define PLL1_O OSC_FREQ #define PLL1_P 12 #define PLL1_M 425 #define PLL1_S 1 #define PLL1_V PLL_VCO_TARGET(PLL1) #define PLL1_T PLL_FREQ_TARGET(PLL1) #else /* ! TARGET_CPU_850M */ #define PLL1 1 #define PLL1_O OSC_FREQ #define PLL1_P 6 #define PLL1_M 200 #define PLL1_S 1 #define PLL1_V PLL_VCO_TARGET(PLL1) #define PLL1_T PLL_FREQ_TARGET(PLL1) #endif /* TARGET_CPU_850M */ #endif #if TARGET_DDR_533M // Defined for SUB_PLATFORM_S5L8947X // Radar - PR-12088495 PR-12142624 PR-12073123 (P & M values changed) #define PLL2 2 #define PLL2_O OSC_FREQ #define PLL2_P 14 #define PLL2_M 311 #define PLL2_S 1 #define PLL2_V PLL_VCO_TARGET(PLL2) #define PLL2_T PLL_FREQ_TARGET(PLL2) #else /* TARGET_DDR_533M */ #define PLL2 2 #define PLL2_O OSC_FREQ #define PLL2_P 6 #define PLL2_M 200 #define PLL2_S 2 #define PLL2_V PLL_VCO_TARGET(PLL2) #define PLL2_T PLL_FREQ_TARGET(PLL2) #endif /* TARGET_DDR_533M */ #define PLL3 3 #define PLL3_O OSC_FREQ #define PLL3_P 4 #define PLL3_M 171 #define PLL3_S 1 #define PLL3_V PLL_VCO_TARGET(PLL3) #define PLL3_T PLL_FREQ_TARGET(PLL3) #if (TARGET_CPU_850M && TARGET_DDR_533M) #define PLL4 4 #define PLL4_O OSC_FREQ #define PLL4_P 5 #define PLL4_M 130 #define PLL4_S 1 #define PLL4_V PLL_VCO_TARGET(PLL4) #define PLL4_T PLL_FREQ_TARGET(PLL4) #endif #if TARGET_USE_HSIC #if TARGET_DDR_533M #define PLLUSB USB #define PLLUSB_O OSC_FREQ #define PLLUSB_P 5 #define PLLUSB_M 200 #define PLLUSB_S 2 #define PLLUSB_V PLL_VCO_TARGET(PLLUSB) #define PLLUSB_T PLL_FREQ_TARGET(PLLUSB) #else #define PLLUSB USB #define PLLUSB_O OSC_FREQ #define PLLUSB_P 4 #define PLLUSB_M 160 #define PLLUSB_S 2 #define PLLUSB_V PLL_VCO_TARGET(PLLUSB) #define PLLUSB_T PLL_FREQ_TARGET(PLLUSB) #endif #define OHCI_SOURCE (0) #define D_MEDIUM1 (0x8000000A) #else /* ! TARGET_USE_HSIC */ #define OHCI_SOURCE (1) #define D_MEDIUM1 (0x00000000) #endif /* TARGET_USE_HSIC */ #ifndef TARGET_CPU_SOURCE #error TARGET_CPU_SOURCE undefined #else #define D_CPU (0x80011041 | ((TARGET_CPU_SOURCE) << 28)) #endif #define D_CLK_DOUBLER (0x8000001F) #ifndef TARGET_MIPI_DSI_SOURCE #error TARGET_MIPI_DSI_SOURCE undefined #else #define D_MIPI_DSI (0x80000001 | ((TARGET_MIPI_DSI_SOURCE) << 28)) #endif #ifndef TARGET_SPI2_SOURCE #error TARGET_SPI2_SOURCE undefined #else #define D_SPI2 (0x80000001 | ((TARGET_SPI2_SOURCE) << 28)) #endif #ifndef TARGET_IOP_SOURCE #error TARGET_IOP_SOURCE undefined #else #define D_IOP (0x80000001 | ((TARGET_IOP_SOURCE) << 28)) #endif #ifndef TARGET_LPERFS_SOURCE #error TARGET_LPERFS_SOURCE undefined #else #define D_LPERFS (0x80000002 | ((TARGET_LPERFS_SOURCE) << 28)) #endif #ifndef TARGET_HPERFNRT_SOURCE #error TARGET_HPERFNRT_SOURCE undefined #else #define D_HPERFNRT (0x80000001 | ((TARGET_HPERFNRT_SOURCE) << 28)) #endif #if TARGET_USE_PREDIV4 #define D_PREDIV4 (0x80000000 | (((TARGET_PREDIV4_SOURCE) << 28) | ((TARGET_PREDIV4_DIV) << 0))) #else #define D_PREDIV4 (0x00000000) #endif #define D_GFX (0x80000001 | ((TARGET_GFX_SOURCE) << 28)) #define D_GFX_SLC (0x80000001 | ((TARGET_GFX_SLC_SOURCE) << 28)) #define D_OHCI (0x80000001 | ((OHCI_SOURCE) << 28)) #ifndef TARGET_PCLK1_SOURCE #error TARGET_PCLK1_SOURCE undefined #else #define D_PCLK1 (0x80000000 | (((TARGET_PCLK1_SOURCE) << 28) | ((TARGET_PCLK1_DIV) << 0))) #endif static u_int32_t clk_divs_active[PMGR_CLK_CFG_COUNT] = { D_CPU, 0x80000000, 0x80000001, D_PCLK1, // cpu, mcu_fixed, mcu, pclk1 0xA0000005, 0xA0000002, 0xA0000003, 0x00000000, // prediv0, prediv1, prediv2, prediv3 D_PREDIV4, 0x00000000, 0xA0000014, 0x80000000, // prediv4, prediv5, prediv6, managed0 0x00000000, 0x80000000, 0x80000000, 0x80000000, // managed1, managed2, managed3, managed4 0xA0000013, 0x80000004, 0xB0000001, 0x80000008, // vid1, medium0, vid0, i2c 0x80000004, D_MIPI_DSI, 0xA0000002, 0x90000004, // sdio, mipi_dsi, audio, hpark_pclk0 0xA0000002, 0xA0000007, 0x80000008, 0x80000001, // hpark_tclk, uperf, debug, hperf_rt D_GFX, D_GFX_SLC, D_HPERFNRT, 0x80000001, // gfx, gfx_slc, hperf_nrt, isp D_IOP, 0xB0000001, D_LPERFS, 0x80000001, // iop, cdio, lperfs, pclk0 0x80000001, 0x80000001, D_MEDIUM1, 0xB0000001, // pclk2, pclk3, medium1, spi0 0xB0000001, D_SPI2, 0xB0000001, 0xB0000001, // spi1, spi2, spi3, spi4 0x80000314, 0x80000001, D_OHCI, 0x80000002, // sleep, usbphy, usbohci, usb12 0xA0000001, 0x00000000, 0x80000000, 0x80000002, // nco_ref0, nco_ref1, venc_mtx, venc }; #define PLL_GATES_ACTIVE (1 << 3) static struct perf_info perf_levels[] = { [kPerformanceHigh] = { kPERF_STATE_IBOOT+0, 1 }, [kPerformanceMedium] = { kPERF_STATE_IBOOT+1, 2 }, [kPerformanceLow] = { kPERF_STATE_IBOOT+2, 4 }, [kPerformanceMemory] = { kPERF_STATE_IBOOT+4, 4 }, }; // Configure Full Performance MANAGED2 based on TARGET defines // TARGETS: n78, n94, k93a, ipad2, j33, s5l8940xfpga, s5l8947xfpga, s5l8942xfpga #define M_PERF_A0 (0x01000001 | ((((TARGET_MANAGED2H_SOURCE) << 5) | ((TARGET_MANAGED2H_DIV) << 0)) << 16)) // managed3 divide by 1 #define M_PERF_A1 (0x02000002 | ((((TARGET_MANAGED2L_SOURCE) << 5) | ((TARGET_MANAGED2L_DIV) << 0)) << 16)) // managed3 divide by 2 #define M_PERF_A2 (0x04000002 | ((((TARGET_MANAGED2L_SOURCE) << 5) | ((TARGET_MANAGED2L_DIV) << 0)) << 16)) // managed3 divide by 4 #define M_PERF_A3 (0x1F000002 | ((((TARGET_MANAGED2L_SOURCE) << 5) | ((TARGET_MANAGED2L_DIV) << 0)) << 16)) // managed3 divide by 31 #define PERF_STATE_ACTIVE kPERF_STATE_IBOOT // perf_state_active : These 5 performance state definitions are used in iBoot and as templates // to then generate the OS Performance Controller states in kext's function // AppleS5L8940XPerformanceController::generatePerformanceStates // // state 0 : High voltage PERF_STATE template // state 1 : Low voltage PERF_STATE template // state 2 : Used in iBoot only // state 3 : Frequency managed clocks template // (dividers of frequency managed clocks must be set to 0x1F) // state 4 : Used in iBoot only for memory calibration #if SUPPORT_FPGA static u_int32_t perf_state_active[kPERF_STATE_IBOOT_CNT*3] = { // mcu_cfg=3, mcu_clk and mcu_fixed_clk always divide by 1 M_PERF_A0, 0x03210122, 0x00000021, // divide by 1 M_PERF_A1, 0x03210124, 0x00000022, // divide by 2 M_PERF_A2, 0x03210124, 0x00000022, // divide by 4 M_PERF_A3, 0x03210124, 0x00000022, // divide by 31 M_PERF_A2, 0x03210124, 0x00000022, // divide by 4 }; #else static u_int32_t perf_state_active[kPERF_STATE_IBOOT_CNT*3] = { //PERF_STATE_xA, PERF_STATE_xB, PERF_STATE_xC #if (TARGET_CPU_850M && TARGET_DDR_533M) M_PERF_A0, 0x00210141, 0x00000021, // managed3 divide by 1, mcu_clk / 1, mcu_cfg=0 //533 Mhz M_PERF_A1, 0x00210141, 0x00000022, // managed3 divide by 2, mcu_clk / 1, mcu_cfg=0 //533 Mhz M_PERF_A2, 0x02210541, 0x00000022, // managed3 divide by 4, mcu_clk / 5, mcu_cfg=2 //106 Mhz M_PERF_A3, 0x03210A41, 0x00000022, // managed3 divide by 31, mcu_clk / 10, mcu_cfg=3 //53 Mhz M_PERF_A2, 0x00210141, 0x00000022, // managed3 divide by 4, mcu_clk / 1, mcu_cfg=0 //533 Mhz #elif TARGET_DDR_256M M_PERF_A0, 0x00440122, 0x00000021, // managed3 divide by 1, mcu_clk / 1, mcu_cfg=0 M_PERF_A1, 0x01440224, 0x00000022, // managed3 divide by 2, mcu_clk / 2, mcu_cfg=1 M_PERF_A2, 0x02440424, 0x00000022, // managed3 divide by 4, mcu_clk / 4, mcu_cfg=2 M_PERF_A3, 0x03440824, 0x00000022, // managed3 divide by 31, mcu_clk / 8, mcu_cfg=3 M_PERF_A2, 0x00440124, 0x00000022, // managed3 divide by 4, mcu_clk / 1, mcu_cfg=0 #else M_PERF_A0, 0x00210122, 0x00000021, // managed3 divide by 1, mcu_clk / 1, mcu_cfg=0 M_PERF_A1, 0x01210224, 0x00000022, // managed3 divide by 2, mcu_clk / 2, mcu_cfg=1 M_PERF_A2, 0x02210424, 0x00000022, // managed3 divide by 4, mcu_clk / 4, mcu_cfg=2 M_PERF_A3, 0x03210824, 0x00000022, // managed3 divide by 31, mcu_clk / 8, mcu_cfg=3 M_PERF_A2, 0x00210124, 0x00000022, // managed3 divide by 4, mcu_clk / 1, mcu_cfg=0 #endif /* (TARGET_CPU_850M && TARGET_DDR_533M) */ }; #endif #endif #if APPLICATION_SECUREROM #define PLL0 0 #define PLL0_O OSC_FREQ #define PLL0_P 6 #define PLL0_M 125 #define PLL0_S 2 #define PLL0_V PLL_VCO_TARGET(PLL0) #define PLL0_T PLL_FREQ_TARGET(PLL0) #define PLL3 3 #define PLL3_O OSC_FREQ #define PLL3_P 4 #define PLL3_M 171 #define PLL3_S 3 #define PLL3_V PLL_VCO_TARGET(PLL3) #define PLL3_T PLL_FREQ_TARGET(PLL3) static u_int32_t clk_divs_active[PMGR_CLK_CFG_COUNT] = { 0x90021041, 0x80000001, 0x80000001, 0xA0000003, // cpu, mcu_fixed, mcu, pclk1 0xA0000001, 0x00000000, 0x00000000, 0x00000000, // prediv0, prediv1, prediv2, prediv3 0x00000000, 0x00000000, 0x00000000, 0x80000001, // prediv4, prediv5, prediv6, managed0 0x80000001, 0x80000001, 0x80000001, 0x80000001, // managed1, managed2, managed3, managed4 0x00000000, 0x00000000, 0x00000000, 0x00000000, // vid1, medium0, vid0, i2c 0x00000000, 0x00000000, 0x80000002, 0x00000000, // sdio, mipi_dsi, audio, hpark_pclk0 0x00000000, 0x80000008, 0x80000008, 0x00000000, // hpark_tclk, uperf, debug, hperf_rt 0x00000000, 0x00000000, 0x00000000, 0x00000000, // gfx, gfx_slc, hperf_nrt, isp 0x00000000, 0x80000001, 0x80000001, 0x80000001, // iop, cdio, lperfs, pclk0 0x80000001, 0x80000001, 0x00000000, 0xB0000001, // pclk2, pclk3, medium1, spi0 0x80000001, 0x80000001, 0xB0000001, 0x80000001, // spi1, spi2, spi3, spi4 0x80000314, 0x80000001, 0x80000001, 0x80000002, // sleep, usbphy, usbohci, usb12 0x80000001, 0x80000001, 0x80000001, 0x00000000, // nco_ref0, nco_ref1, venc_mtx, venc }; #define PLL_GATES_ACTIVE (1 << 3) #define PERF_STATE_ACTIVE kPERF_STATE_SECUREROM static u_int32_t perf_state_active[3] = { 0x00000004, 0x03010100, 0x00000000, // managed0, slow mcu_cfg }; static struct perf_info perf_levels[] = { [kPerformanceHigh] = { kPERF_STATE_SECUREROM, 1 }, [kPerformanceMedium] = { kPERF_STATE_SECUREROM, 1 }, [kPerformanceLow] = { kPERF_STATE_SECUREROM, 1 }, [kPerformanceMemory] = { kPERF_STATE_SECUREROM, 1 }, }; #endif /* current clock speeds */ static u_int32_t clks[PMGR_CLK_COUNT]; static u_int32_t *plls = &clks[PMGR_CLK_PLL0]; static u_int32_t perf_level; static u_int32_t perf_div; struct clk_parent { volatile u_int32_t *divider_reg; u_int32_t divider_slot; u_int8_t parents[4]; }; /* Based on PMGR 1.10 */ static const struct clk_parent clk_parents[PMGR_CLK_COUNT] = { [PMGR_CLK_OSC] = { 0, 0, { 0, 0, 0, 0 } }, [PMGR_CLK_PLL0] = { 0, 0, { 0, 0, 0, 0 } }, [PMGR_CLK_PLL1] = { 0, 0, { 0, 0, 0, 0 } }, [PMGR_CLK_PLL2] = { 0, 0, { 0, 0, 0, 0 } }, [PMGR_CLK_PLL3] = { 0, 0, { 0, 0, 0, 0 } }, [PMGR_CLK_PLL4] = { 0, 0, { 0, 0, 0, 0 } }, [PMGR_CLK_PLLUSB] = { 0, 0, { 0, 0, 0, 0 } }, [PMGR_CLK_DOUBLER] = { &rPMGR_DOUBLER_CTL, 0, { PMGR_CLK_OSC, 0, 0, 0 } }, [PMGR_CLK_CPU] = { &rPMGR_CPU_CLK_CFG, 1, { PMGR_CLK_OSC, PMGR_CLK_PLL0, PMGR_CLK_PLL1, 0 } }, [PMGR_CLK_MEM] = { &rPMGR_CPU_CLK_CFG, 2, { PMGR_CLK_CPU, PMGR_CLK_CPU, PMGR_CLK_CPU, PMGR_CLK_CPU } }, [PMGR_CLK_PIO] = { &rPMGR_CPU_CLK_CFG, 3, { PMGR_CLK_CPU, PMGR_CLK_CPU, PMGR_CLK_CPU, PMGR_CLK_CPU } }, [PMGR_CLK_ACP] = { &rPMGR_CPU_CLK_CFG, 4, { PMGR_CLK_CPU, PMGR_CLK_CPU, PMGR_CLK_CPU, PMGR_CLK_CPU } }, [PMGR_CLK_MCU_FIXED] = { &rPMGR_MCU_FIXED_CLK_CFG, 1, { PMGR_CLK_OSC, PMGR_CLK_PLL2, PMGR_CLK_PLL3, PMGR_CLK_PLL4 } }, [PMGR_CLK_MCU] = { &rPMGR_MCU_CLK_CFG, 1, { PMGR_CLK_MCU_FIXED, 0, 0, 0 } }, [PMGR_CLK_PREDIV0] = { &rPMGR_PREDIV0_CLK_CFG, 1, { PMGR_CLK_OSC, PMGR_CLK_PLL2, PMGR_CLK_PLL3, PMGR_CLK_PLL4 } }, [PMGR_CLK_PREDIV1] = { &rPMGR_PREDIV1_CLK_CFG, 1, { PMGR_CLK_OSC, PMGR_CLK_PLL2, PMGR_CLK_PLL3, PMGR_CLK_PLL4 } }, [PMGR_CLK_PREDIV2] = { &rPMGR_PREDIV2_CLK_CFG, 1, { PMGR_CLK_OSC, PMGR_CLK_PLL2, PMGR_CLK_PLL3, PMGR_CLK_PLL4 } }, [PMGR_CLK_PREDIV3] = { &rPMGR_PREDIV3_CLK_CFG, 1, { PMGR_CLK_OSC, PMGR_CLK_PLL2, PMGR_CLK_PLL3, PMGR_CLK_PLL4 } }, [PMGR_CLK_PREDIV4] = { &rPMGR_PREDIV4_CLK_CFG, 1, { PMGR_CLK_OSC, PMGR_CLK_PLL2, PMGR_CLK_PLL3, PMGR_CLK_PLL4 } }, [PMGR_CLK_PREDIV5] = { &rPMGR_PREDIV5_CLK_CFG, 1, { PMGR_CLK_OSC, PMGR_CLK_PLL2, PMGR_CLK_PLL3, PMGR_CLK_PLL4 } }, [PMGR_CLK_PREDIV6] = { &rPMGR_PREDIV6_CLK_CFG, 1, { PMGR_CLK_OSC, PMGR_CLK_PLL2, PMGR_CLK_PLL3, PMGR_CLK_PLL4 } }, [PMGR_CLK_MANAGED0] = { &rPMGR_MANAGED0_CLK_CFG, 1, { PMGR_CLK_PREDIV0, PMGR_CLK_PREDIV1, PMGR_CLK_PREDIV4, PMGR_CLK_PREDIV5 } }, [PMGR_CLK_MANAGED1] = { &rPMGR_MANAGED1_CLK_CFG, 1, { PMGR_CLK_PREDIV0, PMGR_CLK_PREDIV1, PMGR_CLK_PREDIV2, PMGR_CLK_PREDIV3 } }, [PMGR_CLK_MANAGED2] = { &rPMGR_MANAGED2_CLK_CFG, 1, { PMGR_CLK_PREDIV0, PMGR_CLK_PREDIV1, PMGR_CLK_PREDIV2, PMGR_CLK_PREDIV3 } }, [PMGR_CLK_MANAGED3] = { &rPMGR_MANAGED3_CLK_CFG, 1, { PMGR_CLK_PREDIV0, PMGR_CLK_PREDIV1, PMGR_CLK_PREDIV2, PMGR_CLK_PREDIV3 } }, [PMGR_CLK_MANAGED4] = { &rPMGR_MANAGED4_CLK_CFG, 1, { PMGR_CLK_PREDIV0, PMGR_CLK_PREDIV1, PMGR_CLK_PREDIV4, PMGR_CLK_PREDIV5 } }, [PMGR_CLK_MEDIUM0] = { &rPMGR_MEDIUM0_CLK_CFG, 1, { PMGR_CLK_PREDIV0, PMGR_CLK_PREDIV1, PMGR_CLK_PREDIV2, PMGR_CLK_PREDIV3 } }, [PMGR_CLK_MEDIUM1] = { &rPMGR_MEDIUM1_CLK_CFG, 1, { PMGR_CLK_PLLUSB, 0, 0, 0 } }, [PMGR_CLK_VID0] = { &rPMGR_VID0_CLK_CFG, 1, { PMGR_CLK_PREDIV0, PMGR_CLK_PREDIV1, PMGR_CLK_PREDIV2, PMGR_CLK_PREDIV6 } }, [PMGR_CLK_VID1] = { &rPMGR_VID1_CLK_CFG, 1, { PMGR_CLK_OSC, PMGR_CLK_PLL2, PMGR_CLK_PLL3, PMGR_CLK_PLL4 } }, [PMGR_CLK_I2C] = { &rPMGR_I2C_CLK_CFG, 1, { PMGR_CLK_PREDIV0, PMGR_CLK_PREDIV1, PMGR_CLK_PREDIV2, PMGR_CLK_OSC } }, [PMGR_CLK_SDIO] = { &rPMGR_SDIO_CLK_CFG, 1, { PMGR_CLK_PREDIV0, PMGR_CLK_PREDIV1, PMGR_CLK_PREDIV2, PMGR_CLK_PREDIV3 } }, [PMGR_CLK_MIPI_DSI] = { &rPMGR_MIPI_DSI_CLK_CFG, 1, { PMGR_CLK_PREDIV0, PMGR_CLK_PREDIV1, PMGR_CLK_PREDIV2, PMGR_CLK_PREDIV3 } }, [PMGR_CLK_AUDIO] = { &rPMGR_AUDIO_CLK_CFG, 1, { PMGR_CLK_PREDIV0, PMGR_CLK_PREDIV1, PMGR_CLK_PREDIV2, PMGR_CLK_PREDIV3 } }, [PMGR_CLK_HPARK_PCLK] = { &rPMGR_HPARK_PCLK0_CLK_CFG, 1, { PMGR_CLK_PREDIV0, PMGR_CLK_PREDIV1, PMGR_CLK_PREDIV2, PMGR_CLK_PREDIV3 } }, [PMGR_CLK_HPARK_TCLK] = { &rPMGR_HPARK_TCLK_CLK_CFG, 1, { PMGR_CLK_PREDIV0, PMGR_CLK_PREDIV1, PMGR_CLK_PREDIV2, PMGR_CLK_PREDIV3 } }, [PMGR_CLK_UPERF] = { &rPMGR_UPERF_CLK_CFG, 1, { PMGR_CLK_PREDIV0, PMGR_CLK_PREDIV1, PMGR_CLK_PREDIV2, PMGR_CLK_PREDIV3 } }, [PMGR_CLK_DEBUG] = { &rPMGR_DEBUG_CLK_CFG, 1, { PMGR_CLK_PREDIV0, PMGR_CLK_PREDIV1, PMGR_CLK_PREDIV2, PMGR_CLK_OSC } }, [PMGR_CLK_GFX] = { &rPMGR_GFX_CLK_CFG, 1, { PMGR_CLK_MANAGED0, PMGR_CLK_MANAGED1, PMGR_CLK_MANAGED2, PMGR_CLK_MANAGED4 } }, [PMGR_CLK_GFX_SLC] = { &rPMGR_GFX_SLC_CLK_CFG, 1, { PMGR_CLK_MANAGED0, PMGR_CLK_MANAGED1, PMGR_CLK_MANAGED2, PMGR_CLK_MANAGED4 } }, [PMGR_CLK_HPERFNRT] = { &rPMGR_HPERFNRT_CLK_CFG, 1, { PMGR_CLK_MANAGED0, PMGR_CLK_MANAGED1, PMGR_CLK_MANAGED2, PMGR_CLK_MANAGED3 } }, [PMGR_CLK_HPERFRT] = { &rPMGR_HPERFRT_CLK_CFG, 1, { PMGR_CLK_MANAGED0, PMGR_CLK_MANAGED1, PMGR_CLK_MANAGED2, PMGR_CLK_MANAGED3 } }, [PMGR_CLK_ISP] = { &rPMGR_ISP_CLK_CFG, 1, { PMGR_CLK_MANAGED0, PMGR_CLK_MANAGED1, PMGR_CLK_MANAGED2, PMGR_CLK_MANAGED3 } }, [PMGR_CLK_IOP] = { &rPMGR_IOP_CLK_CFG, 1, { PMGR_CLK_MANAGED0, PMGR_CLK_MANAGED1, PMGR_CLK_MANAGED2, PMGR_CLK_MANAGED3 } }, [PMGR_CLK_CDIO] = { &rPMGR_CDIO_CLK_CFG, 1, { PMGR_CLK_MANAGED0, PMGR_CLK_MANAGED1, PMGR_CLK_MANAGED2, PMGR_CLK_MANAGED3 } }, [PMGR_CLK_LPERFS] = { &rPMGR_LPERFS_CLK_CFG, 1, { PMGR_CLK_MANAGED0, PMGR_CLK_MANAGED1, PMGR_CLK_MANAGED2, PMGR_CLK_MANAGED3 } }, [PMGR_CLK_PCLK0] = { &rPMGR_PCLK0_CLK_CFG, 0, { PMGR_CLK_LPERFS, 0, 0, 0 } }, [PMGR_CLK_PCLK1] = { &rPMGR_PCLK1_CLK_CFG, 1, { PMGR_CLK_OSC, PMGR_CLK_PLL2, PMGR_CLK_PLL3, PMGR_CLK_PLL4 } }, [PMGR_CLK_PCLK2] = { &rPMGR_PCLK2_CLK_CFG, 0, { PMGR_CLK_LPERFS, 0, 0, 0 } }, [PMGR_CLK_PCLK3] = { &rPMGR_PCLK3_CLK_CFG, 0, { PMGR_CLK_LPERFS, 0, 0, 0 } }, [PMGR_CLK_SPI0] = { &rPMGR_SPI0_CLK_CFG, 0, { PMGR_CLK_MEDIUM0, PMGR_CLK_MEDIUM1, 0, PMGR_CLK_OSC } }, [PMGR_CLK_SPI1] = { &rPMGR_SPI1_CLK_CFG, 0, { PMGR_CLK_MEDIUM0, PMGR_CLK_MEDIUM1, 0, PMGR_CLK_OSC } }, [PMGR_CLK_SPI2] = { &rPMGR_SPI2_CLK_CFG, 0, { PMGR_CLK_MEDIUM0, PMGR_CLK_MEDIUM1, 0, PMGR_CLK_OSC } }, [PMGR_CLK_SPI3] = { &rPMGR_SPI3_CLK_CFG, 0, { PMGR_CLK_MEDIUM0, PMGR_CLK_MEDIUM1, 0, PMGR_CLK_OSC } }, [PMGR_CLK_SPI4] = { &rPMGR_SPI4_CLK_CFG, 0, { PMGR_CLK_MEDIUM0, PMGR_CLK_MEDIUM1, 0, PMGR_CLK_OSC } }, [PMGR_CLK_SLOW] = { &rPMGR_SLEEP_CLK_CFG, 2, { PMGR_CLK_OSC, 0, 0, 0 } }, [PMGR_CLK_SLEEP] = { &rPMGR_SLEEP_CLK_CFG, 1, { PMGR_CLK_SLOW, 0, 0, 0 } }, [PMGR_CLK_USBPHY] = { &rPMGR_USBPHY_CLK_CFG, 0, { PMGR_CLK_PLLUSB, 0, 0, 0 } }, [PMGR_CLK_USBOHCI] = { &rPMGR_USBOHCI_CLK_CFG, 0, { PMGR_CLK_MEDIUM1, PMGR_CLK_DOUBLER, 0, 0 } }, [PMGR_CLK_USB12] = { &rPMGR_USB12_CLK_CFG, 1, { PMGR_CLK_OSC, 0, 0, 0 } }, [PMGR_CLK_NCO_REF0] = { &rPMGR_NCO_REF0_CLK_CFG, 1, { PMGR_CLK_PREDIV0, PMGR_CLK_PREDIV1, PMGR_CLK_PREDIV2, PMGR_CLK_PREDIV3 } }, [PMGR_CLK_NCO_REF1] = { &rPMGR_NCO_REF1_CLK_CFG, 1, { PMGR_CLK_PREDIV0, PMGR_CLK_PREDIV1, PMGR_CLK_PREDIV2, PMGR_CLK_PREDIV3 } }, [PMGR_CLK_VENC_MTX] = { &rPMGR_VENC_MTX_CLK_CFG, 1, { PMGR_CLK_OSC, PMGR_CLK_PLL2, PMGR_CLK_PLL3, PMGR_CLK_PLL4 } }, [PMGR_CLK_VENC] = { &rPMGR_VENC_CLK_CFG, 1, { PMGR_CLK_VENC_MTX, 0, 0, 0 } }, }; static void clocks_get_frequencies(void); static u_int32_t get_pll(int pll); static void set_pll(int pll, u_int32_t p, u_int32_t m, u_int32_t s, u_int32_t v); static void clocks_set_gates(u_int64_t *devices, bool enable); static void clocks_quiesce_internal(void); static void update_perf_state(u_int32_t new_perf_state); void platform_power_init(void) { #if (!SUB_PLATFORM_S5L8947X) // Set Power Gating Parameters for all the power domains rPMGR_PWR_GATE_TIME_A(1) = (208 << 16); // CPU0 rPMGR_PWR_GATE_TIME_B(1) = (32 << 26); rPMGR_PWR_GATE_TIME_A(2) = (208 << 16); // CPU1 rPMGR_PWR_GATE_TIME_B(2) = (32 << 26); rPMGR_PWR_GATE_TIME_A(3) = (54 << 16); // SCU rPMGR_PWR_GATE_TIME_A(4) = (36 << 16); // L2RAM0 rPMGR_PWR_GATE_TIME_A(5) = (36 << 16); // L2RAM1 rPMGR_PWR_GATE_TIME_A(6) = (192 << 16) | (2 << 0); // IOP rPMGR_PWR_GATE_TIME_B(6) = (32 << 26) | (2 << 16) | (2 << 8) | (4 << 0); rPMGR_PWR_GATE_TIME_A(7) = (568 << 16) | (7 << 0); // GFX rPMGR_PWR_GATE_TIME_B(7) = (2 << 16) | (2 << 8) | (4 << 0); rPMGR_PWR_GATE_TIME_A(8) = (621 << 16) | (6 << 0); // HPERF-RT rPMGR_PWR_GATE_TIME_B(8) = (2 << 16) | (2 << 8) | (9 << 0); rPMGR_PWR_GATE_TIME_A(9) = (605 << 16) | (9 << 0); // ISP rPMGR_PWR_GATE_TIME_B(9) = (2 << 16) | (2 << 8) | (4 << 0); rPMGR_PWR_GATE_TIME_A(10) = (366 << 16) | (4 << 0); // HPERF-NRT rPMGR_PWR_GATE_TIME_B(10) = (2 << 16) | (2 << 8) | (4 << 0); rPMGR_PWR_GATE_TIME_A(11) = (472 << 16) | (6 << 0); // VDEC rPMGR_PWR_GATE_TIME_B(11) = (2 << 16) | (2 << 8) | (4 << 0); rPMGR_PWR_GATE_TIME_A(12) = (529 << 16) | (8 << 0); // VENC rPMGR_PWR_GATE_TIME_B(12) = (2 << 16) | (2 << 8) | (4 << 0); rPMGR_PWR_GATE_TIME_A(13) = (275 << 16) | (4 << 0); // FMI rPMGR_PWR_GATE_TIME_B(13) = (2 << 16) | (2 << 8) | (4 << 0); rPMGR_PWR_GATE_TIME_A(14) = (149 << 16) | (1 << 0); // HPARK rPMGR_PWR_GATE_TIME_B(14) = (2 << 16) | (2 << 8) | (4 << 0); #else // Set Power Gating Parameters for all the power domains rPMGR_PWR_GATE_TIME_A(1) = (180 << 16); // CPU0 rPMGR_PWR_GATE_TIME_B(1) = (32 << 26); rPMGR_PWR_GATE_TIME_A(3) = (36 << 16); // SCU rPMGR_PWR_GATE_TIME_A(4) = (15 << 16); // L2RAM0 rPMGR_PWR_GATE_TIME_A(6) = (35 << 16) | (1 << 0); // IOP rPMGR_PWR_GATE_TIME_B(6) = (32 << 26) | (2 << 16) | (2 << 8) | (4 << 0); rPMGR_PWR_GATE_TIME_A(7) = (160 << 16) | (3 << 0); // GFX rPMGR_PWR_GATE_TIME_B(7) = (2 << 16) | (2 << 8) | (4 << 0); rPMGR_PWR_GATE_TIME_A(8) = (126 << 16) | (3 << 0); // HPERF-RT rPMGR_PWR_GATE_TIME_B(8) = (2 << 16) | (2 << 8) | (9 << 0); rPMGR_PWR_GATE_TIME_A(10) = (76 << 16) | (2 << 0); // HPERF-NRT rPMGR_PWR_GATE_TIME_B(10) = (2 << 16) | (2 << 8) | (4 << 0); rPMGR_PWR_GATE_TIME_A(11) = (78 << 16) | (2 << 0); // VDEC rPMGR_PWR_GATE_TIME_B(11) = (2 << 16) | (2 << 8) | (4 << 0); rPMGR_PWR_GATE_TIME_A(13) = (33 << 16) | (1 << 0); // FMI rPMGR_PWR_GATE_TIME_B(13) = (2 << 16) | (2 << 8) | (4 << 0); #endif #if APPLICATION_IBOOT /* clear CPU1's reset; it will still be powered down */ clock_reset_device(CLK_CPU1); #endif } extern void aic_spin(u_int32_t usecs); void platform_power_spin(u_int32_t usecs) { aic_spin(usecs); } int clocks_init(void) { #if APPLICATION_IBOOT && (PRODUCT_IBOOT || PRODUCT_IBEC) u_int32_t cnt; clks[PMGR_CLK_OSC] = OSC_FREQ; for (cnt = 0; cnt < 6; cnt++) plls[cnt] = get_pll(cnt); /* Calculate our initial performance divider based on CPU_DIVISOR */ perf_div = (rPMGR_CPU_CLK_CFG & rPMGR_CLK_CFG_DIV_MASK) / (clk_divs_active[0] & rPMGR_CLK_CFG_DIV_MASK); /* Match the divider to one of the performance levels */ if (perf_div == perf_levels[kPerformanceHigh].perf_div) perf_level = kPerformanceHigh; else if (perf_div == perf_levels[kPerformanceMedium].perf_div) perf_level = kPerformanceMedium; else if (perf_div == perf_levels[kPerformanceLow].perf_div) perf_level = kPerformanceLow; clocks_get_frequencies(); #endif /* APPLICATION_IBOOT && (PRODUCT_IBOOT || PRODUCT_IBEC) */ 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) { u_int32_t cnt, reg, val, cpu_div; volatile u_int32_t *clkcfgs = PMGR_FIRST_CLK_CFG; /* Be sure the bypass performance state is set up */ rPMGR_PERF_STATE_A(kPERF_STATE_BYPASS) = perf_state_bypass[0]; rPMGR_PERF_STATE_B(kPERF_STATE_BYPASS) = perf_state_bypass[1]; rPMGR_PERF_STATE_C(kPERF_STATE_BYPASS) = perf_state_bypass[2]; #if APPLICATION_SECUREROM rPMGR_PERF_STATE_A(kPERF_STATE_SECUREROM) = perf_state_active[0]; rPMGR_PERF_STATE_B(kPERF_STATE_SECUREROM) = perf_state_active[1]; rPMGR_PERF_STATE_C(kPERF_STATE_SECUREROM) = perf_state_active[2]; #endif #if APPLICATION_IBOOT for (cnt = 0; cnt < kPERF_STATE_IBOOT_CNT; cnt++) { rPMGR_PERF_STATE_A(kPERF_STATE_IBOOT + cnt) = perf_state_active[(cnt*3) + 0]; rPMGR_PERF_STATE_B(kPERF_STATE_IBOOT + cnt) = perf_state_active[(cnt*3) + 1]; rPMGR_PERF_STATE_C(kPERF_STATE_IBOOT + cnt) = perf_state_active[(cnt*3) + 2]; } // Save the PERF_STATE configuration in rPMGR_SCRATCH1 rPMGR_SCRATCH1 |= PGMR_SET_PERF_STATE_INDEX(PMGR_PERF_STATE_V(0), kPERF_STATE_IBOOT + 0); rPMGR_SCRATCH1 |= PGMR_SET_PERF_STATE_INDEX(PMGR_PERF_STATE_V(1), kPERF_STATE_IBOOT + 1); rPMGR_SCRATCH1 |= PGMR_SET_PERF_STATE_INDEX(PMGR_PERF_STATE_P, kPERF_STATE_IBOOT + 3); rPMGR_SCRATCH1 |= PGMR_SET_PERF_STATE_INDEX(PMGR_PERF_STATE_M(0), kPERF_STATE_IBOOT + 0); rPMGR_SCRATCH1 |= PGMR_SET_PERF_STATE_INDEX(PMGR_PERF_STATE_M(1), kPERF_STATE_IBOOT + 1); rPMGR_SCRATCH1 |= PGMR_SET_PERF_STATE_INDEX(PMGR_PERF_STATE_M(2), kPERF_STATE_IBOOT + 2); rPMGR_SCRATCH1 |= PGMR_SET_PERF_STATE_INDEX(PMGR_PERF_STATE_M(3), kPERF_STATE_IBOOT + 3); #endif /* Change all the clocks to something safe */ clocks_quiesce_internal(); #if APPLICATION_IBOOT && !SUPPORT_FPGA // We must be running at Vnom or greater at this point. Move to the fast EMA bank // so we can update the incorrect reset values in the slow bank. The fast bank is // safe as long as we stay above Vmin. rPMGR_EMA_CTL_CPU = TARGET_EMA_CTL_CPU_SEL; while (rPMGR_EMA_CTL_CPU & rPMGR_EMA_CTL_CPU_SPIN) ; rPMGR_EMA_CTL_SOC = rPMGR_EMA_CTL_SOC_SEL; while (rPMGR_EMA_CTL_SOC & rPMGR_EMA_CTL_SOC_SPIN) ; #endif /* APPLICATION_IBOOT && !SUPPORT_FPGA*/ clks[PMGR_CLK_OSC] = OSC_FREQ; #ifdef PLL0_T set_pll(0, PLL0_P, PLL0_M, PLL0_S, PLL0_V); #endif #ifdef PLL1_T set_pll(1, PLL1_P, PLL1_M, PLL1_S, PLL1_V); #endif #ifdef PLL2_T set_pll(2, PLL2_P, PLL2_M, PLL2_S, PLL2_V); #endif #ifdef PLL3_T set_pll(3, PLL3_P, PLL3_M, PLL3_S, PLL3_V); #endif #ifdef PLL4_T set_pll(4, PLL4_P, PLL4_M, PLL4_S, PLL4_V); #endif #ifdef PLLUSB_T set_pll(5, PLLUSB_P, PLLUSB_M, PLLUSB_S, PLLUSB_V); #endif // Use get_pll() to establish the frequencies (unconfigured PLLs will bypass OSC) for (cnt = 0; cnt < 6; cnt++) plls[cnt] = get_pll(cnt); #if APPLICATION_IBOOT && !TARGET_USE_HSIC // turn on clock doubler rPMGR_DOUBLER_CTL = D_CLK_DOUBLER; #if !SUPPORT_FPGA while (!(rPMGR_DOUBLER_DEBUG & rPMGR_PLL_DEBUG_ENABLED)) ; #endif #endif // perf_div needs to be established before touching PMGR_CPU_CLK_CFG perf_level = kPerformanceLow; perf_div = perf_levels[perf_level].perf_div; // Open the active PLL gates rPMGR_PLL_GATES = PLL_GATES_ACTIVE; // Set all clock dividers to their active values // Start with CPU then work backwards for (cnt = 0; cnt < PMGR_CLK_CFG_COUNT; cnt++) { reg = PMGR_CLK_CFG_COUNT - cnt; if (reg == PMGR_CLK_CFG_COUNT) reg = 0; // Take care of managed clocks before predivs if (reg == PMGR_CLK_NUM(MANAGED0)) update_perf_state(kPerformanceLow); val = clk_divs_active[reg]; // Factor perf_div into PMGR_CPU_CLK_CFG if (reg == PMGR_CLK_NUM(CPU)) { cpu_div = val & rPMGR_CLK_CFG_DIV_MASK; val &= ~rPMGR_CLK_CFG_DIV_MASK; val |= cpu_div * perf_div; } clkcfgs[reg] = val; // Sleep clock needs special attention: // instead, we just make sure not to disable it. while (clkcfgs[reg] & rPMGR_CLK_CFG_PENDING); } clocks_get_frequencies(); return 0; } static void update_perf_state(u_int32_t new_perf_level) { u_int32_t val, cpu_div; /* Change the CPU speed (factor old perf_div out, multiple new one in) */ if (perf_levels[new_perf_level].perf_div != perf_div) { val = rPMGR_CPU_CLK_CFG; cpu_div = val & rPMGR_CLK_CFG_DIV_MASK; cpu_div = (cpu_div / perf_div) * perf_levels[new_perf_level].perf_div; val = (val & ~rPMGR_CLK_CFG_DIV_MASK) | cpu_div; rPMGR_CPU_CLK_CFG = val; while (rPMGR_CPU_CLK_CFG & rPMGR_CLK_CFG_PENDING); perf_div = perf_levels[new_perf_level].perf_div; } /* Write the new select value */ rPMGR_PERF_STATE_CTL = PMGR_PERF_STATE_SEL(perf_levels[new_perf_level].perf_state); /* Spin while any pending bits are asserted */ while (rPMGR_PERF_STATE_CTL & PMGR_PERF_STATE_PENDING); } void clocks_quiesce(void) { /* mcu_clk will be changed to bypass clock */ clks[PMGR_CLK_MCU] = OSC_FREQ; /* Change all the clocks to something safe */ clocks_quiesce_internal(); /* effectively full performance */ perf_level = kPerformanceHigh; perf_div = perf_levels[kPerformanceHigh].perf_div; } static void clock_update_range(u_int32_t first, u_int32_t last, u_int32_t clkdata[]) { volatile u_int32_t *clkcfgs = PMGR_FIRST_CLK_CFG; u_int32_t val, reg; reg = first; while (reg <= last) { val = clkdata[reg]; clkcfgs[reg] = val; while (clkcfgs[reg] & rPMGR_CLK_CFG_PENDING); reg++; } } static void clocks_quiesce_internal(void) { u_int64_t devices[2]; // Critical: AIC, Debug, DWI, GPIO, AUDIO, UPERF, CDMA, CDIO, // MCU, L2RAM, SCU, CPU0 devices[0] = 0x000000205800005DULL; devices[1] = 0x0000000000003A00ULL; // Turn on critical device clocks clocks_set_gates(devices, true); // Turn off non-critical device clocks clocks_set_gates(devices, false); // Simplified from PMGR Spec 1.10 Section 3.13.6 (plus changes from Erik) // Reset top-level dividers to bypass clock_update_range(PMGR_CLK_NUM(PCLK1), PMGR_CLK_NUM(PREDIV6), clk_divs_bypass); clock_update_range(PMGR_CLK_NUM(VID1), PMGR_CLK_NUM(VID1), clk_divs_bypass); #if APPLICATION_IBOOT // Prepare to move memory to bypass clock (ensure not high frequency, enable DLL force mode) rPMGR_PERF_STATE_CTL = PMGR_PERF_STATE_SEL(perf_levels[kPerformanceMedium].perf_state); while (rPMGR_PERF_STATE_CTL & PMGR_PERF_STATE_PENDING); miu_bypass_prep(); #endif // Reset managed clocks and mcu, venc_mtx rPMGR_PERF_STATE_CTL = PMGR_PERF_STATE_SEL(kPERF_STATE_BYPASS); while (rPMGR_PERF_STATE_CTL & PMGR_PERF_STATE_PENDING); // Reset PLLs and Doubler rPMGR_PLL0_CTL = rPMGR_PLL_EXT_BYPASS; rPMGR_PLL1_CTL = rPMGR_PLL_EXT_BYPASS; rPMGR_PLL2_CTL = rPMGR_PLL_EXT_BYPASS; rPMGR_PLL3_CTL = rPMGR_PLL_EXT_BYPASS; rPMGR_PLL4_CTL = rPMGR_PLL_EXT_BYPASS; rPMGR_PLLUSB_CTL = rPMGR_PLL_EXT_BYPASS; rPMGR_DOUBLER_CTL = (rPMGR_PLL_ENABLE | rPMGR_PLL_EXT_BYPASS); #if !SUPPORT_FPGA while (!(rPMGR_PLL0_DEBUG & rPMGR_PLL_DEBUG_BYP_ENABLED)) ; while (!(rPMGR_PLL1_DEBUG & rPMGR_PLL_DEBUG_BYP_ENABLED)) ; while (!(rPMGR_PLL2_DEBUG & rPMGR_PLL_DEBUG_BYP_ENABLED)) ; while (!(rPMGR_PLL3_DEBUG & rPMGR_PLL_DEBUG_BYP_ENABLED)) ; while (!(rPMGR_PLL4_DEBUG & rPMGR_PLL_DEBUG_BYP_ENABLED)) ; while (!(rPMGR_PLLUSB_DEBUG & rPMGR_PLL_DEBUG_BYP_ENABLED)) ; while (!(rPMGR_DOUBLER_DEBUG & rPMGR_PLL_DEBUG_BYP_ENABLED)) ; #endif // Doubler external bypass uses gated version of 24 MHz // Leave Doubler Enable bit set (for OHCI) // Open the PLL Gates rPMGR_PLL_GATES = (1 << 4) | (1 << 3) | (1 << 2); // Reset the lower-level clocks clock_update_range(PMGR_CLK_NUM(MANAGED0), PMGR_CLK_NUM(VENC), clk_divs_bypass); // Clear Enable bit, Doubler will still remain in bypass mode rPMGR_DOUBLER_CTL &= ~rPMGR_PLL_ENABLE; // Reset the CPU clocks clock_update_range(PMGR_CLK_NUM(CPU), PMGR_CLK_NUM(MCU), clk_divs_bypass); } u_int32_t clocks_set_performance(u_int32_t performance_level) { u_int32_t old_perf_level = perf_level; update_perf_state(performance_level); perf_level = performance_level; return old_perf_level; } void clock_get_frequencies(u_int32_t *clocks, u_int32_t count) { u_int32_t cnt = PMGR_CLK_COUNT; if (cnt > count) cnt = count; memcpy(clocks, clks, cnt * sizeof(u_int32_t)); } u_int32_t clock_get_frequency(int clock) { switch (clock) { case CLK_CPU: case CLK_FCLK: return clks[PMGR_CLK_CPU]; case CLK_ACLK: case CLK_MEM: return clks[PMGR_CLK_MCU]; case CLK_HCLK: case CLK_BUS: return clks[PMGR_CLK_PIO]; case CLK_PERIPH: case CLK_PCLK: return clks[PMGR_CLK_PCLK0]; case CLK_FMI: return clks[PMGR_CLK_PCLK1]; case CLK_NCLK: case CLK_FIXED: case CLK_TIMEBASE: return clks[PMGR_CLK_OSC]; case CLK_USBPHYCLK: #if SUPPORT_FPGA return clks[PMGR_CLK_USBPHY]; /* The reference is special on FPGA */ #else return clks[PMGR_CLK_OSC]; /* This is ref_24_clk, not usb_phy_clk */ #endif case CLK_NCOREF: return clks[PMGR_CLK_NCO_REF0]; case CLK_VCLK0: return clks[PMGR_CLK_VID0]; case CLK_I2C0: case CLK_I2C1: case CLK_I2C2: return clks[PMGR_CLK_I2C]; case CLK_MIPI: return clks[PMGR_CLK_MIPI_DSI]; case CLK_MCLK: default: return 0; } } void clock_set_frequency(int clock, u_int32_t divider, u_int32_t pll_p, u_int32_t pll_m, u_int32_t pll_s, u_int32_t pll_t) { u_int32_t total_div, prediv6_div, vid0_div; switch (clock) { case CLK_VCLK0: // Calculate the total divider required total_div = clks[PMGR_CLK_PLL3] / pll_t; // Find the largest prediv6_div that will // produce the correct total_div for (prediv6_div = 31; prediv6_div > 1; prediv6_div--) { if ((total_div % prediv6_div) == 0) break; } // Calculate vid0_div based on the part of // total_div not in prediv6_div vid0_div = total_div / prediv6_div; // Set the clock dividers to their new values rPMGR_PREDIV6_CLK_CFG = (rPMGR_PREDIV6_CLK_CFG & ~0x1f) | prediv6_div; rPMGR_VID0_CLK_CFG = (rPMGR_VID0_CLK_CFG & ~0x1f) | vid0_div; // Update the list of frequencies clks[PMGR_CLK_PREDIV6] = clks[PMGR_CLK_PLL3] / prediv6_div; clks[PMGR_CLK_VID0] = clks[PMGR_CLK_PREDIV6] / vid0_div; break; default: break; } } void clock_gate(int device, bool enable) { volatile u_int32_t *reg = PMGR_FIRST_PS + device; if (reg > PMGR_LAST_PS) return; // Set the PS field to the requested level if (enable) *reg |= 0xF; else *reg &= ~0xF; // Wait for the PS and ACTUAL_PS fields to be equal while ((*reg & 0xF) != ((*reg >> 4) & 0xF)); } static void clocks_set_gates(u_int64_t *devices, bool enable) { u_int32_t dev, index; volatile u_int32_t *devpss = PMGR_FIRST_PS; u_int64_t mask = 1, devmask = 0; for (dev = 0, index = -1; dev < PMGR_DEV_PS_COUNT; dev++, mask <<= 1) { if ((dev % 64) == 0) { devmask = devices[++index]; if (enable == false) devmask ^= -1ULL; mask = 1; } // Skip CPUs if (dev < PMGR_PS_NUM(SCU)) continue; if ((devmask & mask) != 0) { if (enable) devpss[dev] |= 0xF; else devpss[dev] &= ~0xF; // Wait for the PS and ACTUAL_PS fields to be equal while ((devpss[dev] & 0xF) != ((devpss[dev] >> 4) & 0xF)); } } } void platform_diag_gate_clocks(void) { } void platform_system_reset(bool panic) { #if WITH_BOOT_STAGE if (!panic) boot_set_stage(kPowerNVRAMiBootStageOff); #endif // Use WDOG pin to cause a PMU reset gpio_configure_out(GPIO_SYSTEM_RESET, 1); 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_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(); } static const u_int32_t divider_slot_table[8 * 2] = { 0x00000000, 0, 0x0000001F, 0, 0x000003E0, 5, 0x00007C00, 10, 0x000F8000, 15, 0x00001F00, 8, 0x001F0000, 16, 0x1F000000, 24 }; static void clocks_get_frequencies(void) { #if SUPPORT_FPGA u_int32_t cnt; u_int32_t freq = OSC_FREQ; for (cnt = 0; cnt < PMGR_CLK_COUNT; cnt++) clks[cnt] = freq; clks[PMGR_CLK_CPU] = 15000000; clks[PMGR_CLK_MCU] = 10000000; clks[PMGR_CLK_MCU_FIXED]= 10000000; clks[PMGR_CLK_USBPHY] = 12000000; // keep compiler happy cnt = (u_int32_t)clk_parents; cnt = (u_int32_t)divider_slot_table; #else volatile u_int32_t *reg; u_int32_t cnt, val, src_shift, parent_idx, slot, mask, shift, divider, perf_div_tmp; u_int64_t freq; for (cnt = 0; cnt < PMGR_CLK_COUNT; cnt++) { reg = clk_parents[cnt].divider_reg; if (reg == 0) continue; switch (cnt) { case PMGR_CLK_MANAGED0 : src_shift = 5; slot = 1; val = (*reg & rPMGR_CLK_CFG_ENABLE) | (perf_state_active[0] & ~rPMGR_CLK_CFG_ENABLE); break; case PMGR_CLK_MANAGED1 : src_shift = 13; slot = 5; val = (*reg & rPMGR_CLK_CFG_ENABLE) | (perf_state_active[0] & ~rPMGR_CLK_CFG_ENABLE); break; case PMGR_CLK_MANAGED2 : src_shift = 21; slot = 6; val = (*reg & rPMGR_CLK_CFG_ENABLE) | (perf_state_active[0] & ~rPMGR_CLK_CFG_ENABLE); break; case PMGR_CLK_MANAGED3 : src_shift = 29; slot = 7; val = (*reg & rPMGR_CLK_CFG_ENABLE) | (perf_state_active[0] & ~rPMGR_CLK_CFG_ENABLE); break; case PMGR_CLK_MANAGED4 : src_shift = 5; slot = 1; val = (*reg & rPMGR_CLK_CFG_ENABLE) | (perf_state_active[1] & ~rPMGR_CLK_CFG_ENABLE); break; case PMGR_CLK_MCU : src_shift = 32; slot = 5; val = (*reg & rPMGR_CLK_CFG_ENABLE) | (perf_state_active[1] & ~rPMGR_CLK_CFG_ENABLE); break; case PMGR_CLK_MCU_FIXED : src_shift = 21; slot = 6; val = (*reg & rPMGR_CLK_CFG_ENABLE) | (perf_state_active[1] & ~rPMGR_CLK_CFG_ENABLE); break; case PMGR_CLK_VENC_MTX : src_shift = 5; slot = 1; val = (*reg & rPMGR_CLK_CFG_ENABLE) | (perf_state_active[2] & ~rPMGR_CLK_CFG_ENABLE); break; default : src_shift = 28; slot = clk_parents[cnt].divider_slot; val = *reg; break; } if ((val & rPMGR_CLK_CFG_ENABLE) == 0) continue; parent_idx = clk_parents[cnt].parents[(val >> src_shift) & 3]; freq = clks[parent_idx]; if ((cnt == PMGR_CLK_DOUBLER) && !(val & rPMGR_DOUBLER_EXT_BYPASS)) freq *= 2; if (slot != 0) { mask = divider_slot_table[slot * 2]; shift = divider_slot_table[slot * 2 + 1]; divider = (val & mask) >> shift; if (divider == 0) continue; switch (cnt) { case PMGR_CLK_CPU : perf_div_tmp = perf_div; break; default : perf_div_tmp = 1; break; } freq *= perf_div_tmp; freq /= divider; } clks[cnt] = freq; } #endif } static u_int32_t get_pll(int pll) { u_int32_t pllctl; u_int64_t freq = 0; switch (pll) { case 0: pllctl = rPMGR_PLL0_CTL; break; case 1: pllctl = rPMGR_PLL1_CTL; break; case 2: pllctl = rPMGR_PLL2_CTL; break; case 3: pllctl = rPMGR_PLL3_CTL; break; case 4: pllctl = rPMGR_PLL4_CTL; break; case 5: pllctl = rPMGR_PLLUSB_CTL; break; default: goto exit; break; } if ((pllctl & rPMGR_PLL_ENABLE) == 0) goto exit; if ((pllctl & (rPMGR_PLL_EXT_BYPASS | rPMGR_PLL_BYPASS))) { freq = OSC_FREQ; } else { freq = OSC_FREQ * 2; freq *= (pllctl >> 3) & 0x3FF; // *M freq /= (pllctl >> 14) & 0x3F; // /P freq /= 1 << ((pllctl >> 0) & 0x07); // /2^S } exit: return freq; } static void set_pll(int pll, u_int32_t p, u_int32_t m, u_int32_t s, u_int32_t vco) { volatile u_int32_t *pllctl, *pllparam; #if (SUB_PLATFORM_S5L8942X || SUB_PLATFORM_S5L8947X) u_int32_t vsel; #else u_int32_t afc; #endif switch (pll) { case 0: pllctl = &rPMGR_PLL0_CTL; pllparam = &rPMGR_PLL0_PARAM; break; case 1: pllctl = &rPMGR_PLL1_CTL; pllparam = &rPMGR_PLL1_PARAM; break; case 2: pllctl = &rPMGR_PLL2_CTL; pllparam = &rPMGR_PLL2_PARAM; break; case 3: pllctl = &rPMGR_PLL3_CTL; pllparam = &rPMGR_PLL3_PARAM; break; case 4: pllctl = &rPMGR_PLL4_CTL; pllparam = &rPMGR_PLL4_PARAM; break; case 5: pllctl = &rPMGR_PLLUSB_CTL; pllparam = &rPMGR_PLLUSB_PARAM; break; default: return; break; } #if (SUB_PLATFORM_S5L8942X || SUB_PLATFORM_S5L8947X) // Find the VSEL setting for the desired VCO frequency if (vco < 1400000000UL) vsel = 0; // 960MHz <= VCO <= 1400MHz else vsel = 1; // 1400MHz <= VCO <= 2060MHz // Set the default lock time (2400 cycles), and enable AFC // Note: 2400 requires Fref>=2MHz (P<=12) on H4A. *pllparam = rPMGR_PARAM_AFC_EN | rPMGR_PARAM_LOCK_TIME(2400); *pllctl = (rPMGR_PLL_ENABLE | rPMGR_PLL_LOAD | rPMGR_PLL_P(p) | rPMGR_PLL_M(m) | rPMGR_PLL_S(s) | rPMGR_PLL_VSEL(vsel)); #else // Find the AFC setting for the desired VCO frequency afc = 13; if (vco < 1100000000UL) afc = 5; if (vco > 1500000000UL) afc = 28; // Set the default lock time (2400 cycles), and disable AFC and use EXT AFC // Note: 2400 requires Fref>=1MHz (P<=24) on H4P/H4G *pllparam = rPMGR_PARAM_EXT_AFC(afc) | rPMGR_PARAM_LOCK_TIME(2400); *pllctl = (rPMGR_PLL_ENABLE | rPMGR_PLL_LOAD | rPMGR_PLL_P(p) | rPMGR_PLL_M(m) | rPMGR_PLL_S(s)); #endif #if !SUPPORT_FPGA while ((*pllctl & rPMGR_PLL_REAL_LOCK) == 0); // wait for pll to lock #endif /* ! SUPPORT_FPGA */ } #endif void clock_reset_device(int device) { volatile u_int32_t *reg = PMGR_FIRST_PS + device; switch (device) { case CLK_CPU1 : case CLK_FMI0 : case CLK_FMI1 : case CLK_FMI2 : case CLK_FMI3 : case CLK_IOP : case CLK_SDIO : #if SUB_PLATFORM_S5L8947X case CLK_HDMI : #endif *reg |= rPMGR_PS_RESET; spin(1); *reg &= ~rPMGR_PS_RESET; break; case CLK_MCU: // Make sure resets are asserted/deasserted to gfx0, gfx1, hperfrt, hperfnrt // rPMGR_GFX_SYS_PS |= rPMGR_PS_RESET; rPMGR_GFX_CORES_PS |= rPMGR_PS_RESET; rPMGR_HPERFNRT_PS |= rPMGR_PS_RESET; rPMGR_HPERFRT_PS |= rPMGR_PS_RESET; *reg |= rPMGR_PS_RESET; spin(1); *reg &= ~rPMGR_PS_RESET; rPMGR_GFX_SYS_PS &= ~rPMGR_PS_RESET; rPMGR_GFX_CORES_PS &= ~rPMGR_PS_RESET; rPMGR_HPERFNRT_PS &= ~rPMGR_PS_RESET; rPMGR_HPERFRT_PS &= ~rPMGR_PS_RESET; break; default : break; } } #if WITH_DEVICETREE static const u_int32_t cpu_srcs[] = { 1, 2, 1 }; static const u_int32_t cpu_divs[] = { 2, 1, 1 }; void pmgr_update_device_tree(DTNode *pmgr_node) { u_int32_t cnt, tmp, propSize, propSize2, perf_state_config; u_int32_t *states, *configs; u_int64_t pll_freq, period_ns; u_int32_t cpu_volt; char *propName; void *propData; // Fill in the voltage1-states and cpu-clk-cfgs properties propName = "voltage-states1"; if (!FindProperty(pmgr_node, &propName, (void *)&states, &propSize)) { panic("pmgr property voltage-states1 is missing"); } propName = "cpu-clk-cfgs"; if (!FindProperty(pmgr_node, &propName, (void *)&configs, &propSize2)) { panic("pmgr property cpu-clk-cfgs is missing"); } if (propSize != (propSize2 * 2)) { panic("pmgr properties voltage-states1 (vsPerformanceLimit) and cpu-clk-cfgs are not the same size"); } if (propSize < (3 * 2 * sizeof(u_int32_t))) { panic("pmgr property voltage-states1 is too small"); } // Creat a template for the CPU_CLK_CFG values tmp = rPMGR_CPU_CLK_CFG & ~(rPMGR_CLK_CFG_SRC_SEL_MASK | rPMGR_CLK_CFG_DIV_MASK); // Attempt to create voltage states for each of the possible CPU_CLK_CFGs for (cnt = 0; cnt < 3; cnt++) { // Get the PLL frequency for this CPU_CLK_CFG pll_freq = plls[cpu_srcs[cnt] - 1]; cpu_volt = chipid_get_cpu_voltage(cnt); if (pll_freq == 0) continue; // Calculate the period is ns as a 16.16 fixed point number period_ns = cpu_divs[cnt] * 1000000000ULL << 16; period_ns /= pll_freq; // Save the period for this voltage state *(states++) = period_ns; *(states++) = cpu_volt; // Save the CPU_CLK_CFG for this voltage state *(configs++) = tmp | rPMGR_CLK_CFG_SRC_SEL(cpu_srcs[cnt]) | rPMGR_CLK_CFG_DIVIDER(cpu_divs[cnt]); } // Get the PERF_STATE configuration generated at hardware init perf_state_config = rPMGR_SCRATCH1; if (perf_state_config == 0) return; // Fill in the firmware-v-perf-states property propName = "firmware-v-perf-states"; if (FindProperty(pmgr_node, &propName, &propData, &propSize)) { if (propSize != (2 * sizeof(u_int32_t))) { panic("pmgr property firmware-v-perf-states is the wrong size"); } // Voltage states are in reverse order ((u_int32_t *)propData)[0] = PGMR_GET_PERF_STATE_INDEX(PMGR_PERF_STATE_V(1), perf_state_config); ((u_int32_t *)propData)[1] = PGMR_GET_PERF_STATE_INDEX(PMGR_PERF_STATE_V(0), perf_state_config); } // Fill in the firmware-p-perf-state property propName = "firmware-p-perf-state"; if (FindProperty(pmgr_node, &propName, &propData, &propSize)) { if (propSize != (1 * sizeof(u_int32_t))) { panic("pmgr property firmware-p-perf-states is the wrong size"); } // There is only one Frequency Managed / Performance state ((u_int32_t *)propData)[0] = PGMR_GET_PERF_STATE_INDEX(PMGR_PERF_STATE_P, perf_state_config); } // Fill in the firmware-m-perf-states property propName = "firmware-m-perf-states"; if (FindProperty(pmgr_node, &propName, &propData, &propSize)) { if (propSize != (4 * sizeof(u_int32_t))) { panic("pmgr property firmware-m-perf-states is the wrong size"); } // Memory states are in the same order ((u_int32_t *)propData)[0] = PGMR_GET_PERF_STATE_INDEX(PMGR_PERF_STATE_M(0), perf_state_config); ((u_int32_t *)propData)[1] = PGMR_GET_PERF_STATE_INDEX(PMGR_PERF_STATE_M(1), perf_state_config); ((u_int32_t *)propData)[2] = PGMR_GET_PERF_STATE_INDEX(PMGR_PERF_STATE_M(2), perf_state_config); ((u_int32_t *)propData)[3] = PGMR_GET_PERF_STATE_INDEX(PMGR_PERF_STATE_M(3), perf_state_config); } } #endif