2332 lines
62 KiB
C
2332 lines
62 KiB
C
/*
|
|
* Copyright (C) 2011-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 <debug.h>
|
|
#include <drivers/power.h>
|
|
#include <platform.h>
|
|
#include <platform/clocks.h>
|
|
#include <platform/gpio.h>
|
|
#include <platform/gpiodef.h>
|
|
#include <platform/power.h>
|
|
#include <platform/timer.h>
|
|
#include <platform/soc/chipid.h>
|
|
#include <platform/soc/hwclocks.h>
|
|
#include <platform/soc/miu.h>
|
|
#include <platform/soc/pmgr.h>
|
|
#include <sys/boot.h>
|
|
#include <target.h>
|
|
|
|
extern void arm_no_wfe_spin(uint32_t usecs);
|
|
|
|
struct clock_source {
|
|
uint32_t src_clk;
|
|
uint32_t factor;
|
|
};
|
|
|
|
struct clock_config {
|
|
volatile uint32_t *clock_reg; // CLK_CFG Register
|
|
struct clock_source sources[12]; // 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
|
|
|
|
#if SUB_TARGET_N51 || SUB_TARGET_N53 || SUB_TARGET_J85 || SUB_TARGET_J86 || SUB_TARGET_J87 || SUB_TARGET_J85M || SUB_TARGET_J86M || SUB_TARGET_J87M
|
|
// 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_DVFM_ST_VOLADJ0(0x0) | CCC_DVFM_ST_VOLADJ1(0x6) | CCC_DVFM_ST_VOLADJ2(0xB),
|
|
|
|
// 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_DVFM_ST_VOLADJ0(0x0) | CCC_DVFM_ST_VOLADJ1(0x6) | CCC_DVFM_ST_VOLADJ2(0xB),
|
|
|
|
// 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_DVFM_ST_VOLADJ0(0x0) | CCC_DVFM_ST_VOLADJ1(0x4) | CCC_DVFM_ST_VOLADJ2(0x8),
|
|
|
|
// 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) |
|
|
CCC_DVFM_ST_VOLADJ0(0x0) | CCC_DVFM_ST_VOLADJ1(0x4) | CCC_DVFM_ST_VOLADJ2(0x8),
|
|
|
|
// CCC V4
|
|
// CCC @ 1296 MHz, enable voltage change sequence, Clk src = PLL, BIU div = 2.5
|
|
[kDVFM_STATE_V4] = CCC_DVFM_ST_PLL_P(1) | CCC_DVFM_ST_PLL_M(54) |
|
|
CCC_DVFM_ST_PLL_S(0) | (1ULL << 21) | (5ULL << 18) |
|
|
CCC_DVFM_ST_VOLADJ0(0x0) | CCC_DVFM_ST_VOLADJ1(0x0) | CCC_DVFM_ST_VOLADJ2(0x0)
|
|
|
|
#elif SUB_TARGET_J34 || SUB_TARGET_J34M || SUB_TARGET_J71 || SUB_TARGET_J72 || SUB_TARGET_J73
|
|
// CCC V0
|
|
// CCC @ 600 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(25) |
|
|
CCC_DVFM_ST_PLL_S(0) | (1ULL << 21) | (2ULL << 18) |
|
|
CCC_DVFM_ST_VOLADJ0(0x0) | CCC_DVFM_ST_VOLADJ1(0x6) | CCC_DVFM_ST_VOLADJ2(0xB),
|
|
|
|
// CCC V1
|
|
// CCC @ 840 MHz, enable voltage change sequence, Clk src = PLL, BIU div = 2.
|
|
[kDVFM_STATE_V1] = CCC_DVFM_ST_PLL_P(1) | CCC_DVFM_ST_PLL_M(35) |
|
|
CCC_DVFM_ST_PLL_S(0) | (1ULL << 21) | (4ULL << 18) |
|
|
CCC_DVFM_ST_VOLADJ0(0x0) | CCC_DVFM_ST_VOLADJ1(0x4) | CCC_DVFM_ST_VOLADJ2(0x8),
|
|
|
|
// CCC V2
|
|
// CCC @ 1128 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(47) |
|
|
CCC_DVFM_ST_PLL_S(0) | (1ULL << 21) | (4ULL << 18) |
|
|
CCC_DVFM_ST_VOLADJ0(0x0) | CCC_DVFM_ST_VOLADJ1(0x4) | CCC_DVFM_ST_VOLADJ2(0x8),
|
|
|
|
// CCC V3
|
|
// CCC @ 1296 MHz, enable voltage change sequence, Clk src = PLL, BIU div = 2.5
|
|
[kDVFM_STATE_V3] = CCC_DVFM_ST_PLL_P(1) | CCC_DVFM_ST_PLL_M(54) |
|
|
CCC_DVFM_ST_PLL_S(0) | (1ULL << 21) | (5ULL << 18) |
|
|
CCC_DVFM_ST_VOLADJ0(0x0) | CCC_DVFM_ST_VOLADJ1(0x0) | CCC_DVFM_ST_VOLADJ2(0x0),
|
|
|
|
// CCC V4
|
|
// CCC @ 1392 MHz, enable voltage change sequence, Clk src = PLL, BIU div = 3
|
|
[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) |
|
|
CCC_DVFM_ST_VOLADJ0(0x0) | CCC_DVFM_ST_VOLADJ1(0x0) | CCC_DVFM_ST_VOLADJ2(0x0)
|
|
|
|
#else
|
|
// CCC V0
|
|
// CCC @ 600 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(25) |
|
|
CCC_DVFM_ST_PLL_S(0) | (1ULL << 21) | (2ULL << 18) |
|
|
CCC_DVFM_ST_VOLADJ0(0x0) | CCC_DVFM_ST_VOLADJ1(0x6) | CCC_DVFM_ST_VOLADJ2(0xB),
|
|
|
|
// CCC V1
|
|
// CCC @ 672 MHz, enable voltage change sequence, Clk src = PLL, BIU div = 2.
|
|
[kDVFM_STATE_V1] = CCC_DVFM_ST_PLL_P(1) | CCC_DVFM_ST_PLL_M(28) |
|
|
CCC_DVFM_ST_PLL_S(0) | (1ULL << 21) | (4ULL << 18) |
|
|
CCC_DVFM_ST_VOLADJ0(0x0) | CCC_DVFM_ST_VOLADJ1(0x6) | CCC_DVFM_ST_VOLADJ2(0xB),
|
|
|
|
// CCC V2
|
|
// CCC @ 696 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(29) |
|
|
CCC_DVFM_ST_PLL_S(0) | (1ULL << 21) | (4ULL << 18) |
|
|
CCC_DVFM_ST_VOLADJ0(0x0) | CCC_DVFM_ST_VOLADJ1(0x4) | CCC_DVFM_ST_VOLADJ2(0x8),
|
|
|
|
// CCC V3
|
|
// CCC @ 840 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(35) |
|
|
CCC_DVFM_ST_PLL_S(0) | (1ULL << 21) | (4ULL << 18) |
|
|
CCC_DVFM_ST_VOLADJ0(0x0) | CCC_DVFM_ST_VOLADJ1(0x4) | CCC_DVFM_ST_VOLADJ2(0x8)
|
|
#endif
|
|
|
|
#endif
|
|
};
|
|
|
|
|
|
#if APPLICATION_IBOOT
|
|
|
|
/* PLL0 @840MHz */
|
|
#define PLL0 0
|
|
#define PLL0_O OSC_FREQ
|
|
#define PLL0_P 4
|
|
#define PLL0_M 279
|
|
#define PLL0_S 1
|
|
#define PLL0_V PLL_VCO_TARGET(PLL0)
|
|
#define PLL0_T PLL_FREQ_TARGET(PLL0)
|
|
|
|
#if TARGET_DDR_784M
|
|
#define PLL1 1
|
|
#define PLL1_O OSC_FREQ
|
|
#define PLL1_P 3
|
|
#define PLL1_M 98
|
|
#define PLL1_S 0
|
|
#define PLL1_V PLL_VCO_TARGET(PLL1)
|
|
#define PLL1_T PLL_FREQ_TARGET(PLL1)
|
|
|
|
#elif 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)
|
|
|
|
#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
|
|
|
|
#if SUB_TARGET_J34 || SUB_TARGET_J34M
|
|
/* PLL2 @297MHz */
|
|
#define PLL2 2
|
|
#define PLL2_O OSC_FREQ
|
|
#define PLL2_P 2
|
|
#define PLL2_M 99
|
|
#define PLL2_S 15
|
|
#define PLL2_V PLL_VCO_TARGET(PLL2)
|
|
#define PLL2_T PLL_FREQ_TARGET(PLL2)
|
|
#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 0x00100000
|
|
#endif
|
|
|
|
#define VID0_CLKD TARGET_VID0_CLK_CFG
|
|
|
|
static const uint32_t clk_divs_active[PMGR_CLK_CFG_COUNT] = {
|
|
0x81100000, 0x81100000, 0x80100000, 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, 0x00100000, 0x00100000, 0x00100000, // 0x10030: usb_free_60m, adsp_t, adsp_p, adsp_ts,
|
|
0x85100000, 0x80100000, 0x85100000, 0x85100000, // 0x10040: sio_c, sio_p, isp_c, isp,
|
|
0x81100000, 0x82100000, 0x85100000, 0x85100000, // 0x10050: isp_sensor0_ref, isp_sensor1_ref, vdec, venc,
|
|
VID0_CLKD, 0x85100000, 0x85100000, 0x85100000, // 0x10060: vid0, disp0, disp1, ajpeg_ip,
|
|
0x85100000, 0x85100000, 0x85100000, 0x00100000, // 0x10070: ajpeg_wrap, msr, af, ans_dll,
|
|
0x8A100000, 0x85100000, 0x85100000, 0x85100000, // 0x10080: ans_c, ans_link, lio, mca0_m,
|
|
0x86100000, 0x87100000, 0x88100000, 0x89100000, // 0x10090: mca1_m, mca2_m, mca3_m, mca4_m,
|
|
0x85100000, 0x86100000, 0x85100000, 0x85100000, // 0x100a0: sep, gpio, spi0_n, spi1_n,
|
|
0x85100000, 0x85100000, 0x85100000 // 0x100b0: spi2_n, spi3_n, debug
|
|
};
|
|
|
|
static const uint32_t spare_divs_active[PMGR_SPARE_CLK_CFG_COUNT] = {
|
|
TARGET_SPARE0_CLK_CFG, // 0x10200: spare0
|
|
0x00000000, // 0x10204: spare1
|
|
0x00000000, // 0x10208: spare2
|
|
0x00000000, // 0x1020c: spare3
|
|
0x80100028, // 0x10210: isp_ref0
|
|
0x80100028 // 0x10214: 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;
|
|
};
|
|
|
|
static struct gfx_state_info gfx_states[] = {
|
|
[0] = {0, 0, 0, 0}, /* Power off Rogue state.*/
|
|
[1] = {0, 55, 2, 1}, /* 330 MHz */
|
|
[2] = {0, 65, 2, 1}, /* 390 MHz */
|
|
[3] = {0, 75, 2, 1}, /* 450 MHz */
|
|
[4] = {0, 55, 2, 3}, /* 165 MHz */
|
|
[5] = {0, 65, 2, 3}, /* 195 MHz */
|
|
[6] = {0, 75, 2, 3}, /* 225 MHz */
|
|
#if 0
|
|
[7] = {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);
|
|
static int get_amc_cfg_sel(uint32_t performance_level);
|
|
static void set_amc_clk_config(uint32_t src_index, uint32_t cfg_sel);
|
|
#endif /* APPLICATION_IBOOT */
|
|
|
|
#if APPLICATION_SECUREROM
|
|
|
|
/* We need SoC PLL only. */
|
|
|
|
/* PLL4 @1200MHz (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 0
|
|
|
|
|
|
// We won't touch the clk gen's that aren't necessary during SecureROM.
|
|
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, 0x80100000, 0x80100000, 0x80100000, // 0x10030: usb_free_60m, adsp_t, adsp_p, adsp_ts,
|
|
0x85100000, 0x85100000, 0x80100000, 0x80100000, // 0x10040: sio_c, sio_p, isp_c, isp,
|
|
0x80100000, 0x80100000, 0x80100000, 0x80100000, // 0x10050: isp_sensor0_ref, isp_sensor1_ref, vdec, venc,
|
|
0x80100000, 0x80100000, 0x80100000, 0x80100000, // 0x10060: vid0, disp0, disp1, ajpeg_ip,
|
|
0x80100000, 0x80100000, 0x85100000, 0x80100000, // 0x10070: ajpeg_wrap, msr, af, ans_dll,
|
|
0x85100000, 0x85100000, 0x85100000, 0x80100000, // 0x10080: ans_c, ans_link, lio, mca0_m,
|
|
0x80100000, 0x80100000, 0x80100000, 0x80100000, // 0x10090: mca1_m, mca2_m, mca3_m, mca4_m,
|
|
0x85100000, 0x86100000, 0x80100000, 0x80100000, // 0x100a0: sep, gpio, spi0_n, spi1_n,
|
|
0x80100000, 0x80100000, 0x80100000 // 0x100b0: spi2_n, spi3_n, debug
|
|
};
|
|
|
|
static const uint32_t spare_divs_active[PMGR_SPARE_CLK_CFG_COUNT] = {
|
|
0x80000001, 0x80000001, 0x80000001, 0x80000001, // 0x10200: s0, s1, s2, s3,
|
|
0x80000001, 0x80000001 // 0x10210: isp_ref0, 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_PLL1, 1},
|
|
{PMGR_CLK_PLL1, 2},
|
|
{PMGR_CLK_PLL1, 4},
|
|
{PMGR_CLK_PLL1, 8},
|
|
{PMGR_CLK_PLL1, 16},
|
|
{PMGR_CLK_PLL4, 48}
|
|
}
|
|
},
|
|
|
|
[PMGR_CLK_MIPI_DSI] = {
|
|
&rPMGR_MIPI_DSI_CLK_CFG,
|
|
{
|
|
{PMGR_CLK_PLL0, 1},
|
|
{PMGR_CLK_S0, 1},
|
|
{PMGR_CLK_S1, 1},
|
|
{PMGR_CLK_S2, 1},
|
|
{PMGR_CLK_S3, 1},
|
|
{PMGR_CLK_PLL4, 7},
|
|
{PMGR_CLK_PLL2, 1}
|
|
}
|
|
},
|
|
|
|
[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_ADSP_T] = {
|
|
&rPMGR_ADSP_T_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, 12},
|
|
{PMGR_CLK_PLL4, 11},
|
|
{PMGR_CLK_PLL4, 14},
|
|
{PMGR_CLK_PLL4, 16}
|
|
}
|
|
},
|
|
|
|
[PMGR_CLK_ADSP_P] = {
|
|
&rPMGR_ADSP_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, 18},
|
|
{PMGR_CLK_PLL4, 24}
|
|
}
|
|
},
|
|
|
|
[PMGR_CLK_ADSP_TS] = {
|
|
&rPMGR_ADSP_TS_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_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, 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, 7},
|
|
{PMGR_CLK_PLL4, 6},
|
|
{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, 8},
|
|
{PMGR_CLK_PLL4, 9},
|
|
{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, 7},
|
|
{PMGR_CLK_PLL4, 8},
|
|
{PMGR_CLK_PLL4, 9},
|
|
{PMGR_CLK_PLL4, 12},
|
|
{PMGR_CLK_PLL4, 16},
|
|
{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}
|
|
}
|
|
},
|
|
|
|
[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}
|
|
}
|
|
},
|
|
|
|
[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, 12},
|
|
{PMGR_CLK_PLL4, 11},
|
|
{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, 9},
|
|
{PMGR_CLK_PLL4, 11},
|
|
{PMGR_CLK_PLL4, 12},
|
|
{PMGR_CLK_PLL4, 16},
|
|
{PMGR_CLK_PLL4, 24}
|
|
}
|
|
},
|
|
|
|
[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, 10},
|
|
{PMGR_CLK_PLL4, 12}
|
|
}
|
|
},
|
|
|
|
[PMGR_CLK_ANS_DLL] = {
|
|
&rPMGR_ANS_DLL_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, 6}
|
|
}
|
|
},
|
|
|
|
[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, 7}, // TODO: rdar://problem/10749966
|
|
{PMGR_CLK_PLL4, 8},
|
|
{PMGR_CLK_PLL4, 12},
|
|
{PMGR_CLK_PLL4, 18},
|
|
{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}
|
|
}
|
|
},
|
|
|
|
[PMGR_CLK_S0] = {
|
|
&rPMGR_S0_CLK_CFG,
|
|
{
|
|
{PMGR_CLK_PLL1, 1},
|
|
{PMGR_CLK_PLL2, 1},
|
|
{PMGR_CLK_PLL3, 1},
|
|
{PMGR_CLK_PLL4, 2}
|
|
}
|
|
},
|
|
|
|
[PMGR_CLK_S1] = {
|
|
&rPMGR_S1_CLK_CFG,
|
|
{
|
|
{PMGR_CLK_PLL1, 1},
|
|
{PMGR_CLK_PLL2, 1},
|
|
{PMGR_CLK_PLL3, 1},
|
|
{PMGR_CLK_PLL4, 2}
|
|
}
|
|
},
|
|
|
|
[PMGR_CLK_S2] = {
|
|
&rPMGR_S2_CLK_CFG,
|
|
{
|
|
{PMGR_CLK_PLL1, 1},
|
|
{PMGR_CLK_PLL2, 1},
|
|
{PMGR_CLK_PLL3, 1},
|
|
{PMGR_CLK_PLL4, 2}
|
|
}
|
|
},
|
|
|
|
[PMGR_CLK_S3] = {
|
|
&rPMGR_S3_CLK_CFG,
|
|
{
|
|
{PMGR_CLK_PLL1, 1},
|
|
{PMGR_CLK_PLL2, 1},
|
|
{PMGR_CLK_PLL3, 1},
|
|
{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_thermal_sensors(void);
|
|
static void init_sochot(void);
|
|
static void init_ccc_thermal_sensors(void);
|
|
static void init_ccc_sochot(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 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)
|
|
/*
|
|
* Look into rdar://problem/11647718 for further details.
|
|
* S/W workaround below:
|
|
* We need to turn ON the power partitions once.
|
|
* Note: CCC, GFX are not effected so we won't touch them.
|
|
* ADSP is not used so we leave it that way.
|
|
* After SecureROM hands off control we have the following partitions ON
|
|
* - Always on (Obviously!)
|
|
* - AMC
|
|
* - USB
|
|
* - ACS
|
|
* - ANS
|
|
* So we will power ON
|
|
* - DISP0
|
|
* - DISP1
|
|
* - MEDIA
|
|
* - ISP
|
|
* - VDEC
|
|
* - VENC.
|
|
* and power them down.
|
|
*/
|
|
static void enable_bira_work_around(void)
|
|
{
|
|
|
|
// Turn on the blocks
|
|
clock_gate(CLK_DISP_BUSMUX, true);
|
|
clock_gate(CLK_DISP1, true);
|
|
clock_gate(CLK_MEDIA, true);
|
|
clock_gate(CLK_VDEC, true);
|
|
clock_gate(CLK_VENC, true);
|
|
|
|
// FPGA doesn't have ISP
|
|
#if !SUPPORT_FPGA
|
|
clock_gate(CLK_ISP, true);
|
|
clock_gate(CLK_ISP, false);
|
|
#endif
|
|
|
|
// Power down in reverse order.
|
|
// Note: The PWR_XXX_CFG0 register for these partitions
|
|
// enable power down.
|
|
clock_gate(CLK_VENC, false);
|
|
clock_gate(CLK_VDEC, false);
|
|
clock_gate(CLK_MEDIA, false);
|
|
clock_gate(CLK_DISP1, false);
|
|
clock_gate(CLK_DISP_BUSMUX, false);
|
|
}
|
|
|
|
/*
|
|
* 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 RESET_TIME_MASK (((1 << 8) - 1) << 0)
|
|
#define CLAMP_TIME_MASK (((1 << 8) - 1) << 8)
|
|
#define CLK_EN_TIME_MASK (((1 << 8) - 1) << 16)
|
|
#define _PWRGATE_CFG0(rCFG0, CLK_EN_TIME, CLAMP_TIME, RESET_TIME) \
|
|
regTemp = rCFG0; \
|
|
regTemp &= ~RESET_TIME_MASK; \
|
|
regTemp |= (RESET_TIME << 0); \
|
|
regTemp &= ~CLAMP_TIME_MASK; \
|
|
regTemp |= (CLAMP_TIME << 8); \
|
|
regTemp &= ~CLK_EN_TIME_MASK; \
|
|
regTemp |= (CLK_EN_TIME << 16); \
|
|
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;
|
|
|
|
uint32_t regTemp, i;
|
|
|
|
// B0, B1 tunables.
|
|
|
|
_PWRGATE_CFG0(rPMGR_PWRGATE_AMC_CFG0, 0x2, 0x2, 0x8);
|
|
_PWRGATE_CFG1(rPMGR_PWRGATE_AMC_CFG1, 0x25, 0x0);
|
|
|
|
_PWRGATE_CFG0(rPMGR_PWRGATE_USB_CFG0, 0x3, 0x2, 0x4);
|
|
_PWRGATE_CFG1(rPMGR_PWRGATE_USB_CFG1, 0xd, 0x0);
|
|
|
|
_PWRGATE_CFG0(rPMGR_PWRGATE_ACS_CFG0, 0x2, 0x2, 0x7);
|
|
_PWRGATE_CFG1(rPMGR_PWRGATE_ACS_CFG1, 0x21, 0x0);
|
|
|
|
_PWRGATE_CFG0(rPMGR_PWRGATE_DISP0_CFG0, 0x3, 0x2, 0x4);
|
|
_PWRGATE_CFG1(rPMGR_PWRGATE_DISP0_CFG1, 0x6a, 0x0);
|
|
|
|
_PWRGATE_CFG0(rPMGR_PWRGATE_DISP1_CFG0, 0x3, 0x2, 0x4);
|
|
_PWRGATE_CFG1(rPMGR_PWRGATE_DISP1_CFG1, 0x40, 0x0);
|
|
|
|
_PWRGATE_CFG0(rPMGR_PWRGATE_ISP_CFG0, 0x3, 0x2, 0x4);
|
|
_PWRGATE_CFG1(rPMGR_PWRGATE_ISP_CFG1, 0x63, 0x1);
|
|
|
|
_PWRGATE_CFG0(rPMGR_PWRGATE_MEDIA_CFG0, 0x3, 0x2, 0x4);
|
|
_PWRGATE_CFG1(rPMGR_PWRGATE_MEDIA_CFG1, 0x50, 0x0);
|
|
|
|
_PWRGATE_CFG0(rPMGR_PWRGATE_DEC_CFG0, 0x3, 0x2, 0x4);
|
|
_PWRGATE_CFG1(rPMGR_PWRGATE_DEC_CFG1, 0x5a, 0x0);
|
|
|
|
_PWRGATE_CFG0(rPMGR_PWRGATE_ENC_CFG0, 0x3, 0x2, 0x4);
|
|
_PWRGATE_CFG1(rPMGR_PWRGATE_ENC_CFG1, 0x67, 0x0);
|
|
|
|
_PWRGATE_CFG0(rPMGR_PWRGATE_ANS_CFG0, 0x3, 0x2, 0x4);
|
|
_PWRGATE_CFG1(rPMGR_PWRGATE_ANS_CFG1, 0x49, 0x2);
|
|
|
|
_PWRGATE_CFG0(rPMGR_PWRGATE_ADSP_CFG0, 0x3, 0x2, 0x4);
|
|
_PWRGATE_CFG1(rPMGR_PWRGATE_ADSP_CFG1, 0x1c, 0x0);
|
|
|
|
_PWRGATE_CFG0(rPMGR_PWRGATE_GFX_CFG0, 0x3, 0x2, 0x4);
|
|
_PWRGATE_CFG1(rPMGR_PWRGATE_GFX_CFG1, 0x16, 0x0);
|
|
|
|
_PWRGATE_CFG0(rPMGR_PWRGATE_SEP_CFG0, 0x3, 0x2, 0x4);
|
|
_PWRGATE_CFG1(rPMGR_PWRGATE_SEP_CFG1, 0x3c, 0x0);
|
|
|
|
// 2. Apply MCU Async reset timing.
|
|
|
|
rPMGR_MCU_ASYNC_RESET = (0x1 << 0) | (0x1 << 4) | (0x1 << 8);
|
|
|
|
// 3. Apply VolMan tunables
|
|
|
|
rPMGR_VOLMAN_SOC_DELAY = (0x5 << 0) | (0x6b << 10) | (0xbb8 << 20);
|
|
rPMGR_VOLMAN_SRAM_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 GFX EMA0 & EMA1 tunables.
|
|
|
|
rPMGR_EMA_GFX0 = (0x4 << 0) | (0x4 << 5) | (0x4 << 11) | (0x4 << 16) | (0xa << 22) | (0x7 << 26) | (0x7 << 29);
|
|
rPMGR_EMA_GFX1 = (0x5 << 0) | (0x4 << 3) | (0x1 << 6) | (0x4 << 10) | (0x4 << 13) | (0x5 << 20) | (0x4 << 23) | (0x3 << 29);
|
|
|
|
// 5. PLLx_ANA_PARAMSy tunables
|
|
for (i = 0; i < PMGR_PLL_COUNT; i++) {
|
|
rPMGR_PLL_ANA_PARAMS(0, i) = 0x61a8308;
|
|
rPMGR_PLL_ANA_PARAMS(1, i) = 0xcec0000;
|
|
}
|
|
|
|
// WA for the lack of a clean SW reset of PD_ANS.
|
|
// By enabling power gating we will have a reset when
|
|
// PD_ANS is turned back on.
|
|
// <rdar://problem/13486314>, <rdar://problem/13403412>
|
|
// has further details on this WA.
|
|
rPMGR_PWRGATE_ANS_CFG0 |= (1 << 31);
|
|
return;
|
|
}
|
|
|
|
static void apply_ccc_tunables(void)
|
|
{
|
|
rCCC_PRE_TD_TMR = 0x4;
|
|
rCCC_PRE_FLUSH_TMR = 0x1000;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* 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];
|
|
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];
|
|
|
|
#if (APPLICATION_IBOOT && !PRODUCT_IBOOT && !PRODUCT_IBEC)
|
|
if (platform_get_chip_revision() > CHIP_REVISION_B0) {
|
|
set_ccc_pll_relock_div2();
|
|
}
|
|
#endif
|
|
// Change all clocks to something safe
|
|
clocks_quiesce_internal();
|
|
|
|
// Setup active DVFM state for the stage of boot.
|
|
#if APPLICATION_SECUREROM
|
|
rCCC_DVFM_ST(kDVFM_STATE_SECUREROM) = ccc_dvfm_states[kDVFM_STATE_SECUREROM];
|
|
#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);
|
|
|
|
for (cnt = kDVFM_STATE_IBOOT; cnt < kDVFM_STATE_IBOOT_CNT; cnt++) {
|
|
rCCC_DVFM_ST(cnt) = ccc_dvfm_states[cnt] | ((unsigned long long)cpu_vid[cnt] << CCC_DVFM_ST_SAFE_VOL_SHIFT);
|
|
}
|
|
// APSC sleep state will use the bypass state with V0.
|
|
|
|
rCCC_DVFM_ST(kDVFM_STATE_BYPASS) = ccc_dvfm_states[kDVFM_STATE_BYPASS] | ((unsigned long long)cpu_vid[kDVFM_STATE_V0] << CCC_DVFM_ST_SAFE_VOL_SHIFT);
|
|
|
|
// 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) = ccc_dvfm_states[kDVFM_STATE_IBOOT] |
|
|
((unsigned long long)cpu_vid[kDVFM_STATE_IBOOT] << CCC_DVFM_ST_SAFE_VOL_SHIFT);
|
|
}
|
|
|
|
// Using one point calibration at the lower reading.
|
|
uint32_t tempOffset0 = (rCCC_DVFM_EFUSE_TADC0 & 0x1FF) >> 2;
|
|
uint32_t tempOffset1 = (rCCC_DVFM_EFUSE_TADC1 & 0x1FF) >> 2;
|
|
|
|
// If device is calibrated with DVFM FUSE values, then we need to subtract this offset.
|
|
if (0 != tempOffset0) {
|
|
tempOffset0 = (0x38 - tempOffset0) & 0x7F;
|
|
}
|
|
if (0 != tempOffset1) {
|
|
tempOffset1 = (0x38 - tempOffset1) & 0x7F;
|
|
}
|
|
|
|
// Program TVM thresholds
|
|
rCCC_DVFM_CFG |= CCC_DVFM_CFG_TEMPTHRES0(0x34) | CCC_DVFM_CFG_TEMPTHRES1(0x48) |
|
|
CCC_DVFM_CFG_TEMPOFFST0(tempOffset0) | CCC_DVFM_CFG_TEMPOFFST1(tempOffset1);
|
|
|
|
// Using default programmed value of 1ms.
|
|
// rCCC_DVFM_DLY = 0x180000;
|
|
#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);
|
|
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];
|
|
|
|
set_gfx_perf_state(cnt, gfx_states);
|
|
}
|
|
// As per GFX Performance state software Sequence
|
|
// Clear the bypass bit in PLL5
|
|
rPMGR_PLL_CTL(5) &= ~(1 << 27);
|
|
// PLL5 relock mode is set to 1 to switch to bypass mode while re-locking.
|
|
rPMGR_PLL_CFG(5) |= (1 << 24);
|
|
// 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 //MIPI
|
|
#if WITH_HW_AGC_MIPI
|
|
rPMGR_AGILE_CLK_CTL = (1 << 28);
|
|
rPMGR_PLL_ACG_CFG |= PMGR_ACG_CFG_PLLX_AUTO_DISABLE(0);
|
|
#endif
|
|
set_pll(0, PLL0_P, PLL0_M, PLL0_S, 0);
|
|
#endif
|
|
|
|
#ifdef PLL1_T //Mem
|
|
set_pll(1, PLL1_P, PLL1_M, PLL1_S, 0);
|
|
#endif
|
|
|
|
#ifdef PLL2_T //Unused
|
|
set_pll(2, PLL2_P, PLL2_M, PLL2_S, 0);
|
|
#endif
|
|
|
|
#ifdef PLL3_T //Unused
|
|
set_pll(3, PLL3_P, PLL3_M, PLL3_S, 0);
|
|
#endif
|
|
|
|
#ifdef PLL4_T // SOC
|
|
set_pll(4, PLL4_P, PLL4_M, PLL4_S, PLL4_VCO_ENABLED);
|
|
#endif
|
|
|
|
#ifdef PLL5_T // GFX
|
|
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
|
|
// 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];
|
|
SPIN_W_TMO_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];
|
|
SPIN_W_TMO_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)
|
|
{
|
|
rCCC_APSC_SCR = CCC_APSC_MANUAL_CHANGE(target_state);
|
|
SPIN_W_TMO_WHILE((rCCC_APSC_SCR & CCC_APSC_PENDING) != 0);
|
|
|
|
return;
|
|
}
|
|
|
|
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;
|
|
|
|
if (vco_output) rPMGR_PLL_CFG(pll) |= PMGR_PLL_VCO_OUT_SEL;
|
|
|
|
rPMGR_PLL_CTL(pll) = (PMGR_PLL_P(p) | PMGR_PLL_M(m) | PMGR_PLL_S(s) |
|
|
PMGR_PLL_ENABLE | PMGR_PLL_LOAD);
|
|
|
|
SPIN_W_TMO_WHILE((rPMGR_PLL_CTL(pll) & PMGR_PLL_LOCKED) == 0);
|
|
}
|
|
|
|
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;
|
|
uint64_t freq = 0;
|
|
|
|
pllctl = rPMGR_PLL_CTL(pll);
|
|
|
|
// If PLL is not enabled, check for External Bypass
|
|
if ((pllctl & PMGR_PLL_ENABLE) == 0) {
|
|
if ((pllctl & 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 >> 24) & 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_CYCLONIC
|
|
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_DEBUG);
|
|
#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_MCU_FIXED || end_clk > PMGR_CLK_DEBUG)
|
|
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 >> 24) & 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;
|
|
SPIN_W_TMO_WHILE(clkcfgs[reg] & PMGR_CLK_CFG_PENDING);
|
|
reg++;
|
|
}
|
|
}
|
|
|
|
static void restore_clock_config_state(void)
|
|
{
|
|
uint32_t cnt;
|
|
|
|
// 2. Write reset value to ACG, CLK_DIVIDER_ACG_CFG, CLK_DIVIDER_ACG_CFG1, and PLL_ACG_CFG
|
|
rPMGR_MISC_ACG = 0;
|
|
rPMGR_CLK_DIVIDER_ACG_CFG = 0;
|
|
rPMGR_CLK_DIVIDER_ACG_CFG1 = 0;
|
|
rPMGR_PLL_ACG_CFG = 0;
|
|
|
|
// 5. Write reset value for all mux clock configs (excluding spares, mcu, mcu_fixed)
|
|
clock_update_range(PMGR_CLK_NUM(MIPI_DSI), PMGR_CLK_NUM(DEBUG), 0x80100000);
|
|
|
|
// 6. Write all PLLx_CTL.EXT_BYPASS to 1
|
|
for (cnt = 0; cnt < PMGR_PLL_COUNT; cnt++) {
|
|
if (cnt == 1) continue;
|
|
|
|
rPMGR_PLL_CTL(cnt) |= PMGR_PLL_EXT_BYPASS;
|
|
SPIN_W_TMO_WHILE((rPMGR_PLL_CTL(cnt) & PMGR_PLL_BYP_ENABLED) == 0);
|
|
}
|
|
|
|
// 8. Make sure PLLs OFF mode is set to powered down.
|
|
for (cnt = 0; cnt < PMGR_PLL_COUNT; cnt++) {
|
|
if (cnt == 1) continue; // Mem PLL
|
|
|
|
rPMGR_PLL_CFG(cnt) |= (2 << 30); // PLL.OFF_MODE = Powered down.
|
|
rPMGR_PLL_CTL(cnt) |= (PMGR_PLL_ENABLE | PMGR_PLL_LOAD);
|
|
SPIN_W_TMO_WHILE((rPMGR_PLL_CTL(cnt) & PMGR_PLL_LOCKED) == 0);
|
|
}
|
|
|
|
// 9. 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) = 0x0A001010; // Ext bypass, fb_div = 1, pre_div = 1
|
|
SPIN_W_TMO_WHILE((rPMGR_PLL_CTL(cnt) & PMGR_PLL_BYP_ENABLED) == 0);
|
|
}
|
|
|
|
// 11. Write reset value to spare and ISP_REF0/1
|
|
clock_update_range(PMGR_CLK_NUM(S0), PMGR_CLK_NUM(ISP_REF1), 0x80000001);
|
|
|
|
|
|
// 12. Put CPU clock back into its reset default.
|
|
rCCC_DVFM_SCR = (1 << 2); // CPU PLL goes to reset mode when off.
|
|
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 &= ~(1 << 28); // Clear Auto_PM_EN
|
|
*reg = val;
|
|
SPIN_W_TMO_WHILE(((*reg >> 4) & 0xF) != 0xF); // Wait for SEP to turn on.
|
|
|
|
return;
|
|
}
|
|
|
|
static void clocks_quiesce_internal(void)
|
|
{
|
|
uint64_t devices[2];
|
|
|
|
// Disable all voltage changes everywhere!
|
|
rPMGR_VOLMAN_CTL |= PMGR_VOLMAN_DISABLE_VOL_CHANGE;
|
|
#if APPLICATION_IBOOT
|
|
rPMGR_VOLMAN_CTL |= 1; // Temporary till B0 chip arrives
|
|
#endif
|
|
// We don't touch CPU0, CPU1, CPM
|
|
// Following devices needs to be on:
|
|
// LIO, IOMUX, AIC, DEBUG
|
|
// GPIO, SIO_P, SIO, MCC, MCU,
|
|
// AMP, USB, USBCTRL, USB OTG, SMX, SF, CP
|
|
devices[0] = (0x1ULL << 3) | (0x1ULL << 4) | (0x1ULL << 5) | (0x1ULL << 6) |
|
|
(0x1ULL << 8) | (0x1ULL << 33) | (0x1ULL << 34) | (0x1ULL << 40) | (0x1ULL << 41) |
|
|
(0x1ULL << 42) | (0x1ULL << 43) | (0x1ULL << 44) | (0x1ULL << 49) |
|
|
(0x1ULL << 50) | (0x1ULL << 51) | (0x1ULL << 52);
|
|
|
|
// ANS.
|
|
devices[1] = (0x1ULL << 0);
|
|
|
|
// 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)
|
|
{
|
|
#if APPLICATION_IBOOT
|
|
int cfg_sel = -1;
|
|
uint32_t src_index;
|
|
#endif
|
|
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) {
|
|
cfg_sel = get_amc_cfg_sel(performance_level);
|
|
|
|
if (cfg_sel == -1)
|
|
panic("pmgr:cfg_sel not set correctly for configuring amc clock");
|
|
|
|
src_index = (performance_level == kPerformanceMemoryLow) ? 6 : 1;
|
|
|
|
set_amc_clk_config(src_index, cfg_sel);
|
|
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 kPerformanceHigh;
|
|
}
|
|
|
|
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;
|
|
case CLK_MIPI:
|
|
freq = clks[PMGR_CLK_MIPI_DSI];
|
|
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)
|
|
{
|
|
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. Also we won't touch ADSP.
|
|
if ((reg > PMGR_LAST_PS) || (device == CLK_ADSP))
|
|
return;
|
|
|
|
// 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
|
|
SPIN_W_TMO_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 = 1;
|
|
|
|
// Turn off devices hi to lo order (to meet dependencies).
|
|
for (i = PMGR_LAST_DEVICE - 1; i >= CLK_LIO;) {
|
|
clock_gate(i, ( (devices[idx] >> ((uint64_t) (i % 64)) ) & 0x1) );
|
|
if (i && ((i % 64) == 0))
|
|
idx--;
|
|
|
|
i--;
|
|
}
|
|
|
|
idx = 0;
|
|
|
|
// Turn on devices from lo to hi (to meet dependencies).
|
|
for (i = CLK_LIO; ( (i < 128) && (i < PMGR_LAST_DEVICE) ); ) {
|
|
if (i && ((i % 64) == 0))
|
|
idx++;
|
|
clock_gate(i, ( (devices[idx] >> ((uint64_t) (i % 64)) ) & 0x1) );
|
|
i++;
|
|
}
|
|
|
|
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: <rdar://problem/10869952> Core 0 power gating enabled by default */
|
|
rPMGR_PWRGATE_CPU0_CFG0 &= ~(1UL << 31);
|
|
}
|
|
|
|
void thermal_init(void)
|
|
{
|
|
#if (APPLICATION_IBOOT && !PRODUCT_IBOOT && !PRODUCT_IBEC)
|
|
/* Read thermal fused values and store into thermal registers */
|
|
init_thermal_sensors();
|
|
/* Read thermal fused values and store into thermal registers & init instantenous read for sochot */
|
|
init_ccc_thermal_sensors();
|
|
|
|
/* Setup SoC Sochot 0 & 1 */
|
|
init_sochot();
|
|
/* Setup CCC Sochot 0 & 1 */
|
|
init_ccc_sochot();
|
|
#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);
|
|
|
|
// Make sure we are within limits. Also we won't touch ADSP.
|
|
if ((device >= PMGR_LAST_DEVICE) || (device == CLK_ADSP))
|
|
return;
|
|
|
|
// XXX TODO
|
|
switch(device) {
|
|
case CLK_MCU:
|
|
case CLK_ANS:
|
|
case CLK_SIO:
|
|
*reg |= PMGR_PS_RESET;
|
|
spin(1);
|
|
*reg &= ~PMGR_PS_RESET;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if APPLICATION_IBOOT
|
|
static void set_gfx_perf_state(uint32_t state_num, struct gfx_state_info *gfx_state)
|
|
{
|
|
uint32_t pll_enable = 0;
|
|
|
|
if (state_num >= sizeof(gfx_states)/sizeof(gfx_states[0])) return;
|
|
|
|
// This is deductive. If feedback divider is 0 the PLL shouldn't output anything.
|
|
pll_enable = gfx_state[state_num].fb_div ? 1 : 0;
|
|
|
|
rPMGR_GFX_PERF_STATE_ENTRY(state_num) = ((gfx_state[state_num].dwi_val & 0xFF) << 24) |
|
|
((pll_enable & 0x1) << 21) |
|
|
((gfx_state[state_num].fb_div & 0x1FF) << 12) |
|
|
((gfx_state[state_num].pre_div & 0x1F) << 4) |
|
|
(gfx_state[state_num].op_div & 0xF);
|
|
return;
|
|
}
|
|
|
|
static int get_amc_cfg_sel(uint32_t performance_level)
|
|
{
|
|
int cfg_sel;
|
|
switch(performance_level) {
|
|
case kPerformanceMemoryLow:
|
|
cfg_sel = 3;
|
|
break;
|
|
case kPerformanceMemoryFull:
|
|
cfg_sel = 0;
|
|
break;
|
|
default:
|
|
cfg_sel = -1;
|
|
break;
|
|
}
|
|
return cfg_sel;
|
|
}
|
|
|
|
static void set_amc_clk_config(uint32_t src_index, uint32_t cfg_sel)
|
|
{
|
|
volatile uint32_t *clkcfgs = PMGR_FIRST_CLK_CFG;
|
|
uint32_t mcu_clk_cfg_reg;
|
|
|
|
mcu_clk_cfg_reg = clkcfgs[PMGR_CLK_CFG_INDEX(PMGR_CLK_MCU)];
|
|
|
|
mcu_clk_cfg_reg &= ~(0x7 << PMGR_CLK_CFG_SRC_SEL_SHIFT);
|
|
mcu_clk_cfg_reg &= ~(0x3 << PMGR_CLK_CFG_CFG_SEL_SHIFT);
|
|
mcu_clk_cfg_reg |= ((src_index & 0x7) << PMGR_CLK_CFG_SRC_SEL_SHIFT);
|
|
mcu_clk_cfg_reg |= ((cfg_sel & 0x3) << PMGR_CLK_CFG_CFG_SEL_SHIFT);
|
|
|
|
clkcfgs[PMGR_CLK_CFG_INDEX(PMGR_CLK_MCU)] = mcu_clk_cfg_reg;
|
|
|
|
// Wait for Pending bit to clear.
|
|
SPIN_W_TMO_WHILE((clkcfgs[PMGR_CLK_CFG_INDEX(PMGR_CLK_MCU)] >> PMGR_CLK_CFG_PENDING_SHIFT) & 0x1);
|
|
|
|
return;
|
|
}
|
|
#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;
|
|
uint32_t cpu_vid[kDVFM_STATE_IBOOT_CNT];
|
|
|
|
char *propName;
|
|
void *propData;
|
|
|
|
// 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(ccc_dvfm_states[kDVFM_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(ccc_dvfm_states[kDVFM_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) < kVOLTAGE_STATES1_SIZE) {
|
|
panic("pmgr number of states less than required for voltage-states1");
|
|
}
|
|
num_freqs = kVOLTAGE_STATES1_COUNT;
|
|
platform_get_cpu_voltages(kDVFM_STATE_IBOOT_CNT, cpu_vid);
|
|
for (int32_t i = num_freqs - 1, j = 0; i >= 0; i--, j++) {
|
|
freq = get_freq_from_ccc_state(ccc_dvfm_states[kDVFM_STATE_VMAX - j]);
|
|
volt = cpu_vid[kDVFM_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 == 0)) {
|
|
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 = num_states;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void override_device_tree_property_uint32(DTNode *node, char *propName, uint32_t propValue, bool panicIfMissing)
|
|
{
|
|
void *propData;
|
|
uint32_t propSize;
|
|
|
|
if (FindProperty(node, &propName, &propData, &propSize)) {
|
|
if (propSize != sizeof(uint32_t)) {
|
|
panic("%s property is of wrong size.", propName);
|
|
}
|
|
|
|
((uint32_t *)propData)[0] = propValue;
|
|
} else if (panicIfMissing) {
|
|
panic("%s property not found.", propName);
|
|
}
|
|
}
|
|
|
|
void sochot_pmgr_update_device_tree(DTNode *node)
|
|
{
|
|
}
|
|
|
|
void sochot_ccc_update_device_tree(DTNode *node)
|
|
{
|
|
}
|
|
|
|
void temp_sensor_pmgr_update_device_tree(DTNode *node)
|
|
{
|
|
}
|
|
|
|
void temp_sensor_ccc_update_device_tree(DTNode *node)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
#if (APPLICATION_IBOOT && !PRODUCT_IBOOT && !PRODUCT_IBEC)
|
|
|
|
void init_thermal_sensors(void)
|
|
{
|
|
// Bits [1 - 0] PWRDN Mode and enable.
|
|
// Bits [ 2 ] Reserved.
|
|
// Bits [ 3 ] Stat mode for Avg Max on.
|
|
// Bits [18 - 4] TADC_CFG Tmpsadc configuration bits.
|
|
// Bits [31 - 19] Misc interrupt/Alarm stick bits not used.
|
|
rPMGR_THERMAL0_CTL0 = 0x5278;
|
|
rPMGR_THERMAL1_CTL0 = 0x5278;
|
|
|
|
// Bits [15 - 0] PWRDN_START 20us wait
|
|
// Bits [31 - 16] PWRDN_GAP Gap between two readings.
|
|
rPMGR_THERMAL0_CTL1 = 0x019401E4;
|
|
rPMGR_THERMAL1_CTL1 = 0x03A801E4;
|
|
|
|
// Bits [7 - 0] Conv_Cycle, cycles to wait before data is valid.
|
|
// Bits [15 - 8] Enable_Cycle, cycles to wait before adc_en can be deasserted.
|
|
// Bits [23 - 16] Finish_gap, Cycles to wait before adc_en can be reasserted.
|
|
// Bits [31 - 24] Reserved.
|
|
//
|
|
// Use default
|
|
//
|
|
|
|
for (u_int32_t sensorID = 0; sensorID < 2; sensorID++) {
|
|
u_int32_t fusedTempValueAt70 = chipid_get_fused_pmgr_thermal_sensor_cal_70C(sensorID);
|
|
u_int32_t fusedTempValueAt25 = chipid_get_fused_pmgr_thermal_sensor_cal_25C(sensorID);
|
|
u_int32_t tempSlope = 0x100;
|
|
|
|
if ((fusedTempValueAt25 == 0) || (fusedTempValueAt70 == 0)) {
|
|
if (chipid_valid_thermal_sensor_cal_data_expected()) {
|
|
panic("SoC temperature sensor calibration data not found");
|
|
}
|
|
}
|
|
|
|
// Should probably make sure we don't divide by zero.
|
|
if (fusedTempValueAt25 == fusedTempValueAt70) {
|
|
fusedTempValueAt70 = 70;
|
|
fusedTempValueAt25 = 25;
|
|
dprintf(DEBUG_INFO, "Invalid soc thermal fuse values\n");
|
|
}
|
|
|
|
// 45 = 70 - 25
|
|
tempSlope = (45*256) / (fusedTempValueAt70 - fusedTempValueAt25);
|
|
|
|
// Calculate the real offset.
|
|
u_int32_t realOffset = 25 - ((tempSlope * fusedTempValueAt25) / 256);
|
|
|
|
// Bits 23 16
|
|
// Temp_OFFSET => [8 bit signed integer]
|
|
// Bits 9 0
|
|
// TEMP_SLOPE => [2 bit integer| 8 bit decimal]
|
|
switch (sensorID) {
|
|
case 0:
|
|
rPMGR_THERMAL0_CTL3 = (realOffset & 0xFF) << 16;
|
|
rPMGR_THERMAL0_CTL3 |= tempSlope & 0x3FF;
|
|
break;
|
|
case 1:
|
|
rPMGR_THERMAL1_CTL3 = (realOffset & 0xFF) << 16;
|
|
rPMGR_THERMAL1_CTL3 |= tempSlope & 0x3FF;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Per 13799299, enable the temperature sensors after applying calibration efuse info and before enabling DVTM
|
|
rPMGR_THERMAL0_CTL0 |= 0x01;
|
|
rPMGR_THERMAL1_CTL0 |= 0x01;
|
|
}
|
|
|
|
|
|
void init_sochot(void)
|
|
{
|
|
// Majority of work done in kext with EDT configuration
|
|
// Setup GFX clock divider
|
|
rPMGR_GFX_PERF_STATE_SOCHOT = 0x1;
|
|
}
|
|
|
|
|
|
void init_ccc_thermal_sensors(void)
|
|
{
|
|
// Per 13146352, CCC thermal sensors for B0+ adopt same register interface as PMGR sensors
|
|
rCCC_THRM0_CTL0 |= 0x08;
|
|
rCCC_THRM1_CTL0 |= 0x08;
|
|
|
|
// Bits [15 - 0] PWRDN_START 20us wait
|
|
// Bits [31 - 16] PWRDN_GAP Gap between two readings.
|
|
rCCC_THRM0_CTL1 = 0x019401E4;
|
|
rCCC_THRM1_CTL1 = 0x019401E4;
|
|
|
|
// Bits [7 - 0] Conv_Cycle, cycles to wait before data is valid.
|
|
// Bits [15 - 8] Enable_Cycle, cycles to wait before adc_en can be deasserted.
|
|
// Bits [23 - 16] Finish_gap, Cycles to wait before adc_en can be reasserted.
|
|
// Bits [31 - 24] Reserved.
|
|
//
|
|
// Use default
|
|
//
|
|
|
|
for (u_int32_t sensorID = 0; sensorID < 2; sensorID++) {
|
|
u_int32_t fusedTempValueAt70 = chipid_get_fused_ccc_thermal_sensor_cal_70C(sensorID);
|
|
u_int32_t fusedTempValueAt25 = chipid_get_fused_ccc_thermal_sensor_cal_25C(sensorID);
|
|
u_int32_t tempSlope = 0x100;
|
|
|
|
if ((fusedTempValueAt25 == 0) || (fusedTempValueAt70 == 0)) {
|
|
if (chipid_valid_thermal_sensor_cal_data_expected()) {
|
|
panic("CCC temperature sensor calibration data not found");
|
|
}
|
|
}
|
|
|
|
// Should probably make sure we don't divide by zero.
|
|
if (fusedTempValueAt25 == fusedTempValueAt70) {
|
|
fusedTempValueAt70 = 70;
|
|
fusedTempValueAt25 = 25;
|
|
dprintf(DEBUG_INFO, "Invalid soc thermal fuse values\n");
|
|
}
|
|
|
|
// 45 = 70 - 25
|
|
tempSlope = (45*256) / (fusedTempValueAt70 - fusedTempValueAt25);
|
|
|
|
// Calculate the real offset.
|
|
u_int32_t realOffset = 25 - ((tempSlope * fusedTempValueAt25) / 256);
|
|
|
|
// Bits 23 16
|
|
// Temp_OFFSET => [8 bit signed integer]
|
|
// Bits 9 0
|
|
// TEMP_SLOPE => [2 bit integer| 8 bit decimal]
|
|
switch (sensorID) {
|
|
case 0:
|
|
rCCC_THRM0_CTL3 = (realOffset & 0xFF) << 16;
|
|
rCCC_THRM0_CTL3 |= tempSlope & 0x3FF;
|
|
break;
|
|
case 1:
|
|
rCCC_THRM1_CTL3 = (realOffset & 0xFF) << 16;
|
|
rCCC_THRM1_CTL3 |= tempSlope & 0x3FF;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Per 13799299, enable the temperature sensors after applying calibration efuse info and before enabling DVTM
|
|
rCCC_THRM0_CTL0 |= 0x01;
|
|
rCCC_THRM1_CTL0 |= 0x01;
|
|
|
|
}
|
|
|
|
|
|
void init_ccc_sochot(void)
|
|
{
|
|
// Setup CCC clock frequency by specifying index into DVFM table.
|
|
rCCC_DVFM_FSHOT_IDX = 0x2;
|
|
}
|
|
|
|
#endif
|