iBoot/platform/t8002/pmgr/pmgr.c

1676 lines
55 KiB
C
Raw Permalink Normal View History

2023-07-08 13:03:17 -07:00
/*
* Copyright (C) 2013-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/tunables.h>
#include <platform/soc/chipid.h>
#include <platform/soc/hwclocks.h>
#include <platform/soc/miu.h>
#include <platform/soc/pmgr.h>
#include <platform/int.h>
#include <sys/boot.h>
#include <target.h>
#include <drivers/aic/aic.h>
extern const struct tunable_chip_struct tunables_pmgr[];
extern const struct tunable_filtered_chip_struct tunables_filtered_pmgr[];
#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))
static uint32_t perf_level = kPerformanceMemoryLow;
#if APPLICATION_SECUREROM
#define SOC_PERF_STATE_ACTIVE kSOC_PERF_STATE_SECUREROM
#endif
#if APPLICATION_IBOOT
#define SOC_PERF_STATE_ACTIVE kSOC_PERF_STATE_VMIN
#endif
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[8]; // List of sources
};
struct clock_config_active {
uint32_t clk;
uint32_t clock_reg_val;
};
struct device_config {
volatile uint32_t *ps_reg; // PS Register
};
/* ******************************************************************************** */
#if APPLICATION_IBOOT
/* LPO @192MHz */
#define LPPLL_T LPPLL_FREQ
/* PLL0 @1065.6MHz */
#define PLL0 0
#define PLL0_P 5
#define PLL0_M 111
#define PLL0_S 0
#define PLL0_T PLL_FREQ_TARGET(PLL0)
#define PLL0_VCO_OUT true
/* PLL1 @480MHz */
#define PLL1 1
#define PLL1_P 1
#define PLL1_M 40
#define PLL1_S 1
#define PLL1_T PLL_FREQ_TARGET(PLL1)
#define PLL1_VCO_OUT false
static const struct clock_config_active clk_configs_active[] = {
{PMGR_CLK_AOP, 0x81100000}, // minipmgr_aop on 96MHz
{PMGR_CLK_UART0, 0x83100000}, // minipmgr_uart0 on 24MHz
{PMGR_CLK_UART1, 0x83100000}, // minipmgr_uart1 on 24MHz
{PMGR_CLK_UART2, 0x83100000}, // minipmgr_uart2 on 24MHz
{PMGR_CLK_SENSE_X2, 0x81100000}, // minipmgr_sense_x2 on 48MHz
{PMGR_CLK_DETECT, 0x81100000}, // minipmgr_detect on 96MHz
{PMGR_CLK_I2CM, 0x81100000}, // minipmgr_i2cm on 24MHz
{PMGR_CLK_I2CM1, 0x81100000}, // minipmgr_i2cm1 on 24MHz
{PMGR_CLK_PROXY_FABRIC, 0x81100000}, // minipmgr_proxy_fabric on 96MHz
{PMGR_CLK_PROXY_MCU_REF, 0x81100000}, // minipmgr_proxy_mcu_ref on 96MHz
{PMGR_CLK_GPIO, 0x80100000}, // gpio on 24MHz
{PMGR_CLK_MCU_REF, 0x83100000}, // mcu_ref on SOC_PERF_STATE
{PMGR_CLK_CPU, 0x83100000}, // cpu on SOC_PERF_STATE
{PMGR_CLK_GFX, 0x83100000}, // gfx on 133.25MHz
{PMGR_CLK_MEDIA_FAB, 0x83100000}, // media_fab on SOC_PERF_STATE
{PMGR_CLK_PIO, 0x83100000}, // pio on SOC_PERF_STATE
{PMGR_CLK_SDIO, 0x83100000}, // sdio on SOC_PERF_STATE
{PMGR_CLK_LIO, 0x83100000}, // lio on SOC_PERF_STATE
{PMGR_CLK_AES, 0x83100000}, // aes on SOC_PERF_STATE
{PMGR_CLK_AUE, 0x83100000}, // aue on 53.3MHz
{PMGR_CLK_SPI0_N, 0x83100000}, // spi0_n on 53.3MHz
{PMGR_CLK_SPI1_N, 0x83100000}, // spi1_n on 53.3MHz
{PMGR_CLK_NCO_REF0, 0x83100000}, // nco_ref0 on 266.5MHz
{PMGR_CLK_NCO_REF1, 0x83100000}, // nco_ref1 on 266.5MHz
{PMGR_CLK_NCO_ALG0, 0x83100000}, // nco_alg0 on 133.25MHz
{PMGR_CLK_NCO_ALG1, 0x83100000}, // nco_alg1 on 133.25MHz
{PMGR_CLK_MCA0_M, 0x83100000}, // mca0_m on 133.25MHz
{PMGR_CLK_MCA1_M, 0x84100000}, // mca1_m on 133.25MHz
{PMGR_CLK_MCA2_M, 0x84100000}, // mca2_m on 133.25MHz
{PMGR_CLK_TMPS, 0x83100000}, // tmps on 1.2MHz
{PMGR_CLK_UVD, 0x83100000}, // uvd on 266.5MHz
{PMGR_CLK_ISP_C, 0x83100000}, // isp_c on 480MHz
{PMGR_CLK_ISP, 0x83100000}, // isp on 160MHz
{PMGR_CLK_RT_FAB, 0x83100000}, // rt_fab on 266.5MHz
{PMGR_CLK_ISP_SENSOR0, 0x81100000}, // isp_sensor0_ref on 48MHz
{PMGR_CLK_VENC, 0x83100000}, // venc_clk on 160MHz
{PMGR_CLK_SEP, 0x83100000}, // sep_clk on 355.33MHz
{PMGR_CLK_SEP_FAB, 0x83100000}, // sep_fab_clk on 177.7MHz
{PMGR_CLK_ANS, 0x83100000}, // ans_c_clk on 106.6MHz
{PMGR_CLK_ANC_LINK, 0x83100000}, // anc_link_clk on 106.6MHz
{PMGR_CLK_VDEC, 0x83100000}, // vdec_clk on 266.5MHz
{PMGR_CLK_MSR, 0x83100000}, // msr_clk on 133.25MHz
{PMGR_CLK_AJPEG_IP, 0x83100000}, // ajpeg_ip_clk on 106.6MHz
{PMGR_CLK_AJPEG_WRAP, 0x83100000}, // ajpeg_wrap_clk on 133.25MHz
{PMGR_CLK_DISP, 0x83100000}, // disp_clk on 106.6MHz
{PMGR_CLK_MIPI_DSI, 0x83100000}, // mipi_dsi_clk on 533MHz
{PMGR_CLK_VID, 0x80100000}, // vid_clk on 24MHz
{PMGR_CLK_HFD, 0x83100000}, // hfd_clk on 106.6MHz
{PMGR_CLK_HSICPHY_REF_12M, 0x83100000}, // hsicphy_ref_12M_clk on 12MHz
{PMGR_CLK_USB480_0, 0x83100000}, // usb480_0_clk on 480MHz
{PMGR_CLK_USB_EHCI, 0x83100000}, // usb_ehci_clk on 106.6MHz
};
static const struct clock_config_active spare_clock_configs_active[] = {
{PMGR_CLK_S0, 0x00000000}, // s0 off
{PMGR_CLK_S1, 0x00000000}, // s1 off
{PMGR_CLK_ISP_REF0, 0x83000005}, // isp_ref0 on 48MHz
};
#endif /* APPLICATION_IBOOT */
struct pmgr_soc_perf_state {
uint32_t entry[1];
};
static struct pmgr_soc_perf_state pmgr_soc_perf_states[] = {
[kSOC_PERF_STATE_BYPASS] = {{ 0x00000000 }},
#if APPLICATION_SECUREROM
[kSOC_PERF_STATE_SECUREROM] = {
// PIO = 106.6 / 2
// SDIO = 24
// MEDIA_FAB = 24
// CPU = 533 / 2
// AES = 24
// LIO = 24
// MCU_REF_CFG_SEL = 0
// MCU_REF = 24
{ 0x30030000 }
},
#endif
#if APPLICATION_IBOOT
[kSOC_PERF_STATE_VMIN] = {
// PIO = 106.6
// SDIO = 106.6
// MEDIA_FAB = 266.5
// CPU = 533
// AES = 266.5
// LIO = 106.6
// MCU_REF_CFG_SEL = 48
// MCU_REF = 48
{ 0x33333334 }
},
#endif
};
/* ******************************************************************************** */
#if APPLICATION_SECUREROM
/* PLL0 @532.8MHz */
#define PLL0 0
#define PLL0_P 5
#define PLL0_M 222
#define PLL0_S 1
#define PLL0_T PLL_FREQ_TARGET(PLL0)
#define PLL0_VCO_OUT false
// TODO: Figure out which ones aren't necessary during SecureROM
// We won't touch the clk gen's that aren't necessary during SecureROM.
static const struct clock_config_active clk_configs_active[] = {
{PMGR_CLK_AOP, 0x80100000}, // minipmgr_aop on 24MHz
{PMGR_CLK_UART0, 0x80100000}, // minipmgr_uart0 on 24MHz
{PMGR_CLK_UART1, 0x80100000}, // minipmgr_uart1 on 24MHz
{PMGR_CLK_UART2, 0x80100000}, // minipmgr_uart2 on 24MHz
{PMGR_CLK_SENSE_X2, 0x80100000}, // minipmgr_sense_x2 on 24MHz
{PMGR_CLK_DETECT, 0x80100000}, // minipmgr_detect on 24MHz
{PMGR_CLK_I2CM, 0x80100000}, // minipmgr_i2cm on 24MHz
{PMGR_CLK_I2CM1, 0x80100000}, // minipmgr_i2cm1 on 24MHz
{PMGR_CLK_PROXY_FABRIC, 0x80100000}, // minipmgr_proxy_fabric on 24MHz
{PMGR_CLK_PROXY_MCU_REF, 0x80100000}, // minipmgr_proxy_mcu_ref on 24MHz
{PMGR_CLK_GPIO, 0x80100000}, // gpio on 24MHz
{PMGR_CLK_MCU_REF, 0x83100000}, // mcu_ref on SOC_PERF_STATE
{PMGR_CLK_CPU, 0x83100000}, // cpu on SOC_PERF_STATE
{PMGR_CLK_GFX, 0x80100000}, // gfx on 24MHz
{PMGR_CLK_MEDIA_FAB, 0x80100000}, // media_fab on SOC_PERF_STATE
{PMGR_CLK_PIO, 0x83100000}, // pio on SOC_PERF_STATE
{PMGR_CLK_SDIO, 0x80100000}, // sdio on SOC_PERF_STATE
{PMGR_CLK_LIO, 0x80100000}, // lio on SOC_PERF_STATE
{PMGR_CLK_AES, 0x80100000}, // aes on SOC_PERF_STATE
{PMGR_CLK_AUE, 0x80100000}, // aue on 24MHz
{PMGR_CLK_SPI0_N, 0x80100000}, // spi0_n on 24MHz
{PMGR_CLK_SPI1_N, 0x80100000}, // spi1_n on 24MHz
{PMGR_CLK_NCO_REF0, 0x80100000}, // nco_ref0 on 24MHz
{PMGR_CLK_NCO_REF1, 0x80100000}, // nco_ref1 on 24MHz
{PMGR_CLK_NCO_ALG0, 0x80100000}, // nco_alg0 on 24MHz
{PMGR_CLK_NCO_ALG1, 0x80100000}, // nco_alg1 on 24MHz
{PMGR_CLK_MCA0_M, 0x80100000}, // mca0_m on 24MHz
{PMGR_CLK_MCA1_M, 0x80100000}, // mca1_m on 24MHz
{PMGR_CLK_MCA2_M, 0x80100000}, // mca2_m on 24MHz
{PMGR_CLK_TMPS, 0x83100000}, // tmps on 1.2MHz
{PMGR_CLK_UVD, 0x80100000}, // uvd on 24MHz
{PMGR_CLK_ISP_C, 0x80100000}, // isp_c on 24MHz
{PMGR_CLK_ISP, 0x80100000}, // isp on 24MHz
{PMGR_CLK_RT_FAB, 0x80100000}, // rt_fab on 24MHz
{PMGR_CLK_ISP_SENSOR0, 0x80100000}, // isp_sensor0_ref on 24MHz
{PMGR_CLK_VENC, 0x80100000}, // venc_clk on 24MHz
{PMGR_CLK_SEP, 0x83100000}, // sep_clk on 177.67MHz
{PMGR_CLK_SEP_FAB, 0x83100000}, // sep_fab_clk on 88.85MHz
{PMGR_CLK_ANS, 0x83100000}, // ans_c_clk on 53.3MHz
{PMGR_CLK_ANC_LINK, 0x83100000}, // anc_link_clk on 53.3MHz
{PMGR_CLK_VDEC, 0x80100000}, // vdec_clk on 24MHz
{PMGR_CLK_MSR, 0x80100000}, // msr_clk on 24MHz
{PMGR_CLK_AJPEG_IP, 0x80100000}, // ajpeg_ip_clk on 24MHz
{PMGR_CLK_AJPEG_WRAP, 0x80100000}, // ajpeg_wrap_clk on 24MHz
{PMGR_CLK_DISP, 0x80100000}, // disp_clk on 24MHz
{PMGR_CLK_MIPI_DSI, 0x80100000}, // mipi_dsi_clk on 24MHz
{PMGR_CLK_VID, 0x80100000}, // vid_clk on 24MHz
{PMGR_CLK_HFD, 0x80100000}, // hfd_clk on 24MHz
{PMGR_CLK_HSICPHY_REF_12M, 0x80100000}, // hsicphy_ref_12M_clk on 24MHz
{PMGR_CLK_USB480_0, 0x80100000}, // usb480_0_clk on 24MHz
{PMGR_CLK_USB_EHCI, 0x80100000}, // usb_ehci_clk on 24MHz
};
static const struct clock_config_active spare_clock_configs_active[] = {
{PMGR_CLK_S0, 0x80000001}, // s0 on 266.4MHz
{PMGR_CLK_S1, 0x80000001}, // s1 on 266.4MHz
{PMGR_CLK_ISP_REF0, 0x81000006}, // isp_ref0 on 22.2MHz // Should be less than 24 MHz
};
#endif /* APPLICATION_SECUREROM */
/* ******************************************************************************** */
#define CLOCK_SOURCES_MAX 8
static const struct clock_config clk_configs[PMGR_CLK_COUNT] = {
[PMGR_CLK_GPIO] = {
&rPMGR_CLK_CFG(GPIO),
{
{PMGR_CLK_OSC, 1}
}
},
[PMGR_CLK_MCU_REF] = {
&rPMGR_CLK_CFG(MCU_REF),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 12},
{PMGR_CLK_PLL1, 10},
{PMGR_CLK_PROXY_MCU_REF, 1},
}
},
[PMGR_CLK_CPU] = {
&rPMGR_CLK_CFG(CPU),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 2},
{PMGR_CLK_PLL0, 4},
{PMGR_CLK_PLL0, 8},
{PMGR_CLK_PLL0, 10},
}
},
[PMGR_CLK_GFX] = {
&rPMGR_CLK_CFG(GFX),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 8},
{PMGR_CLK_PLL0, 10},
{PMGR_CLK_PLL0, 12},
}
},
[PMGR_CLK_MEDIA_FAB] = {
&rPMGR_CLK_CFG(MEDIA_FAB),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 4},
{PMGR_CLK_PLL1, 3},
{PMGR_CLK_PLL0, 8},
{PMGR_CLK_PLL0, 10},
}
},
[PMGR_CLK_PIO] = {
&rPMGR_CLK_CFG(PIO),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 10},
{PMGR_CLK_PROXY_FABRIC, 1},
{PMGR_CLK_PLL1, 5},
}
},
[PMGR_CLK_SDIO] = {
&rPMGR_CLK_CFG(SDIO),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 10},
{PMGR_CLK_PLL0, 12},
{PMGR_CLK_PLL0, 16},
{PMGR_CLK_PLL0, 20},
}
},
[PMGR_CLK_LIO] = {
&rPMGR_CLK_CFG(LIO),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 10},
{PMGR_CLK_PLL0, 12},
{PMGR_CLK_PLL0, 20},
{PMGR_CLK_OSC, 4},
}
},
[PMGR_CLK_AES] = {
&rPMGR_CLK_CFG(AES),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 4},
{PMGR_CLK_PLL0, 8},
{PMGR_CLK_PLL0, 10},
{PMGR_CLK_PLL0, 12},
}
},
[PMGR_CLK_AUE] = {
&rPMGR_CLK_CFG(AUE),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 20},
{PMGR_CLK_PLL1, 8},
}
},
[PMGR_CLK_SPI0_N] = {
&rPMGR_CLK_CFG(SPI0_N),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 20},
{PMGR_CLK_PLL0, 40},
}
},
[PMGR_CLK_SPI1_N] = {
&rPMGR_CLK_CFG(SPI1_N),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 20},
{PMGR_CLK_PLL0, 40},
}
},
[PMGR_CLK_NCO_REF0] = {
&rPMGR_CLK_CFG(NCO_REF0),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 4},
{PMGR_CLK_PLL0, 8},
}
},
[PMGR_CLK_NCO_REF1] = {
&rPMGR_CLK_CFG(NCO_REF1),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 4},
{PMGR_CLK_PLL0, 8},
}
},
[PMGR_CLK_NCO_ALG0] = {
&rPMGR_CLK_CFG(NCO_ALG0),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 8},
{PMGR_CLK_PLL0, 10},
{PMGR_CLK_PLL0, 20},
}
},
[PMGR_CLK_NCO_ALG1] = {
&rPMGR_CLK_CFG(NCO_ALG1),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 8},
{PMGR_CLK_PLL0, 10},
{PMGR_CLK_PLL0, 20},
}
},
[PMGR_CLK_MCA0_M] = {
&rPMGR_CLK_CFG(MCA0_M),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_NCO_REF0, 1},
{PMGR_CLK_NCO_REF1, 1},
{PMGR_CLK_OSC, 2},
{PMGR_CLK_OSC, 4},
}
},
[PMGR_CLK_MCA1_M] = {
&rPMGR_CLK_CFG(MCA1_M),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_NCO_REF0, 1},
{PMGR_CLK_NCO_REF1, 1},
{PMGR_CLK_OSC, 2},
{PMGR_CLK_OSC, 4},
}
},
[PMGR_CLK_MCA2_M] = {
&rPMGR_CLK_CFG(MCA2_M),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_NCO_REF0, 1},
{PMGR_CLK_NCO_REF1, 1},
{PMGR_CLK_OSC, 2},
{PMGR_CLK_OSC, 4},
}
},
[PMGR_CLK_TMPS] = {
&rPMGR_CLK_CFG(TMPS),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_OSC, 20},
}
},
[PMGR_CLK_UVD] = {
&rPMGR_CLK_CFG(UVD),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 4},
}
},
[PMGR_CLK_ISP_C] = {
&rPMGR_CLK_CFG(ISP_C),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL1, 1},
{PMGR_CLK_PLL0, 4},
{PMGR_CLK_PLL1, 2},
{PMGR_CLK_PLL0, 8},
{PMGR_CLK_PLL1, 4},
}
},
[PMGR_CLK_ISP] = {
&rPMGR_CLK_CFG(ISP),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL1, 3},
{PMGR_CLK_PLL0, 8},
{PMGR_CLK_PLL0, 10},
{PMGR_CLK_PLL0, 16},
}
},
[PMGR_CLK_RT_FAB] = {
&rPMGR_CLK_CFG(RT_FAB),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 4},
{PMGR_CLK_PLL1, 3},
{PMGR_CLK_PLL0, 8},
{PMGR_CLK_PLL0, 10},
{PMGR_CLK_PLL0, 16},
}
},
[PMGR_CLK_ISP_SENSOR0] = {
&rPMGR_CLK_CFG(ISP_SENSOR0_REF),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_ISP_REF0, 1},
}
},
[PMGR_CLK_VENC] = {
&rPMGR_CLK_CFG(VENC),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL1, 3},
{PMGR_CLK_PLL0, 8},
}
},
[PMGR_CLK_SEP] = {
&rPMGR_CLK_CFG(SEP),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 3},
{PMGR_CLK_PLL0, 4},
{PMGR_CLK_PLL0, 6},
{PMGR_CLK_PLL0, 8},
}
},
[PMGR_CLK_SEP_FAB] = {
&rPMGR_CLK_CFG(SEP_FAB),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 6},
{PMGR_CLK_PLL0, 8},
{PMGR_CLK_PLL0, 12},
{PMGR_CLK_PLL0, 16},
}
},
[PMGR_CLK_ANS] = {
&rPMGR_CLK_CFG(ANS_C),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 10},
{PMGR_CLK_PLL0, 12},
{PMGR_CLK_PLL0, 16},
{PMGR_CLK_PLL0, 20},
}
},
[PMGR_CLK_ANC_LINK] = {
&rPMGR_CLK_CFG(ANC_LINK),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 10},
{PMGR_CLK_PLL0, 12},
{PMGR_CLK_PLL0, 16},
{PMGR_CLK_PLL0, 20},
}
},
[PMGR_CLK_VDEC] = {
&rPMGR_CLK_CFG(VDEC),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 4},
{PMGR_CLK_PLL0, 8},
{PMGR_CLK_PLL0, 10},
{PMGR_CLK_PLL0, 12},
{PMGR_CLK_PLL0, 16},
}
},
[PMGR_CLK_MSR] = {
&rPMGR_CLK_CFG(MSR),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 8},
{PMGR_CLK_PLL0, 10},
{PMGR_CLK_PLL0, 12},
{PMGR_CLK_PLL0, 16},
{PMGR_CLK_PLL0, 20},
}
},
[PMGR_CLK_AJPEG_IP] = {
&rPMGR_CLK_CFG(AJPEG_IP),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 10},
{PMGR_CLK_PLL0, 12},
{PMGR_CLK_PLL0, 16},
{PMGR_CLK_PLL0, 20},
}
},
[PMGR_CLK_AJPEG_WRAP] = {
&rPMGR_CLK_CFG(AJPEG_WRAP),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 8},
{PMGR_CLK_PLL0, 10},
{PMGR_CLK_PLL0, 12},
{PMGR_CLK_PLL0, 16},
{PMGR_CLK_PLL0, 20},
}
},
[PMGR_CLK_DISP] = {
&rPMGR_CLK_CFG(DISP),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 10},
{PMGR_CLK_PLL0, 12},
{PMGR_CLK_PLL0, 16},
{PMGR_CLK_PLL0, 20},
}
},
[PMGR_CLK_MIPI_DSI] = {
&rPMGR_CLK_CFG(MIPI_DSI),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 2},
{PMGR_CLK_PLL0, 4},
{PMGR_CLK_PLL0, 10},
{PMGR_CLK_PLL0, 12},
}
},
[PMGR_CLK_VID] = {
&rPMGR_CLK_CFG(VID),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 48},
{PMGR_CLK_OSC, 2},
{PMGR_CLK_OSC, 3},
{PMGR_CLK_OSC, 4},
}
},
[PMGR_CLK_HFD] = {
&rPMGR_CLK_CFG(HFD),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 10},
{PMGR_CLK_PLL0, 20},
{PMGR_CLK_PLL0, 32},
{PMGR_CLK_OSC, 1},
}
},
[PMGR_CLK_HSICPHY_REF_12M] = {
&rPMGR_CLK_CFG(HSICPHY_REF_12M),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_OSC, 2},
}
},
[PMGR_CLK_USB_EHCI] = {
&rPMGR_CLK_CFG(USB_EHCI),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL0, 10},
{PMGR_CLK_PLL0, 20},
}
},
[PMGR_CLK_USB480_0] = {
&rPMGR_CLK_CFG(USB480_0),
{
{PMGR_CLK_OSC, 1},
{PMGR_CLK_S0, 1},
{PMGR_CLK_S1, 1},
{PMGR_CLK_PLL1, 1},
}
},
[PMGR_CLK_S0] = {
&rPMGR_CLK_CFG(S0),
{
{PMGR_CLK_PLL0, 2},
{PMGR_CLK_PLL0, 4},
{PMGR_CLK_PLL1, 1},
{PMGR_CLK_PLL1, 2},
}
},
[PMGR_CLK_S1] = {
&rPMGR_CLK_CFG(S1),
{
{PMGR_CLK_PLL0, 2},
{PMGR_CLK_PLL0, 4},
{PMGR_CLK_PLL1, 1},
{PMGR_CLK_PLL1, 2},
}
},
[PMGR_CLK_ISP_REF0] = {
&rPMGR_CLK_CFG(ISP_REF0),
{
{PMGR_CLK_PLL0, 2},
{PMGR_CLK_PLL0, 4},
{PMGR_CLK_PLL1, 1},
{PMGR_CLK_PLL1, 2},
}
},
[PMGR_CLK_AOP] = {
&rMINIPMGR_CLK_CFG(AOP),
{
{ PMGR_CLK_OSC, 1 },
{ PMGR_CLK_LPPLL, 1 },
{ PMGR_CLK_LPPLL, 2 },
{ PMGR_CLK_LPPLL, 4 },
}
},
[PMGR_CLK_UART0] = {
&rMINIPMGR_CLK_CFG(UART0),
{
{ PMGR_CLK_OSC, 1 },
{ PMGR_CLK_LPPLL, 1 },
{ PMGR_CLK_LPPLL, 2 },
{ PMGR_CLK_LPPLL, 4 },
}
},
[PMGR_CLK_UART1] = {
&rMINIPMGR_CLK_CFG(UART1),
{
{ PMGR_CLK_OSC, 1 },
{ PMGR_CLK_LPPLL, 1 },
{ PMGR_CLK_LPPLL, 2 },
{ PMGR_CLK_LPPLL, 4 },
}
},
[PMGR_CLK_UART2] = {
&rMINIPMGR_CLK_CFG(UART2),
{
{ PMGR_CLK_OSC, 1 },
{ PMGR_CLK_LPPLL, 1 },
{ PMGR_CLK_LPPLL, 2 },
{ PMGR_CLK_LPPLL, 4 },
}
},
[PMGR_CLK_SENSE_X2] = {
&rMINIPMGR_CLK_CFG(SENSE_X2),
{
{ PMGR_CLK_OSC, 1 },
{ PMGR_CLK_LPPLL, 2 },
{ PMGR_CLK_LPPLL, 4 },
{ PMGR_CLK_LPPLL, 7 },
{ PMGR_CLK_LPPLL, 14 },
}
},
[PMGR_CLK_DETECT] = {
&rMINIPMGR_CLK_CFG(DETECT),
{
{ PMGR_CLK_OSC, 1 },
{ PMGR_CLK_LPPLL, 1 },
{ PMGR_CLK_LPPLL, 2 },
{ PMGR_CLK_LPPLL, 4 },
}
},
[PMGR_CLK_I2CM] = {
&rMINIPMGR_CLK_CFG(I2CM),
{
{ PMGR_CLK_OSC, 1 },
{ PMGR_CLK_LPPLL, 4 },
{ PMGR_CLK_LPPLL, 8 },
}
},
[PMGR_CLK_I2CM1] = {
&rMINIPMGR_CLK_CFG(I2CM1),
{
{ PMGR_CLK_OSC, 1 },
{ PMGR_CLK_LPPLL, 4 },
{ PMGR_CLK_LPPLL, 8 },
}
},
[PMGR_CLK_PROXY_FABRIC] = {
&rMINIPMGR_CLK_CFG(PROXY_FABRIC),
{
{ PMGR_CLK_OSC, 1 },
{ PMGR_CLK_LPPLL, 1 },
{ PMGR_CLK_LPPLL, 2 },
{ PMGR_CLK_LPPLL, 4 },
}
},
[PMGR_CLK_PROXY_MCU_REF] = {
&rMINIPMGR_CLK_CFG(PROXY_MCU_REF),
{
{ PMGR_CLK_OSC, 1 },
{ PMGR_CLK_LPPLL, 1 },
{ PMGR_CLK_LPPLL, 2 },
{ PMGR_CLK_LPPLL, 4 },
}
},
};
static const struct device_config device_configs[PMGR_DEVICE_COUNT] = {
// Mini PMGR
[PMGR_DEVICE_INDEX(CLK_AOP)] = {&rMINIPMGR_PS(AOP)},
[PMGR_DEVICE_INDEX(CLK_DEBUG)] = {&rMINIPMGR_PS(DEBUG)},
[PMGR_DEVICE_INDEX(CLK_AOP_GPIO)] = {&rMINIPMGR_PS(AOP_GPIO)},
[PMGR_DEVICE_INDEX(CLK_AOP_I2CM1)] = {&rMINIPMGR_PS(AOP_I2CM1)},
[PMGR_DEVICE_INDEX(CLK_AOP_CPU)] = {&rMINIPMGR_PS(AOP_CPU)},
[PMGR_DEVICE_INDEX(CLK_AOP_RTCPU)] = {&rMINIPMGR_PS(AOP_RTCPU)},
[PMGR_DEVICE_INDEX(CLK_AOP_FILTER)] = {&rMINIPMGR_PS(AOP_FILTER)},
[PMGR_DEVICE_INDEX(CLK_AOP_UART0)] = {&rMINIPMGR_PS(AOP_UART0)},
[PMGR_DEVICE_INDEX(CLK_AOP_UART1)] = {&rMINIPMGR_PS(AOP_UART1)},
[PMGR_DEVICE_INDEX(CLK_AOP_UART2)] = {&rMINIPMGR_PS(AOP_UART2)},
[PMGR_DEVICE_INDEX(CLK_AOP_I2CM)] = {&rMINIPMGR_PS(AOP_I2CM)},
[PMGR_DEVICE_INDEX(CLK_AOP_FILTER_DMA)] = {&rMINIPMGR_PS(AOP_FILTER_DMA)},
[PMGR_DEVICE_INDEX(CLK_AOP_LPD0)] = {&rMINIPMGR_PS(AOP_LPD0)},
[PMGR_DEVICE_INDEX(CLK_AOP_HPDS)] = {&rMINIPMGR_PS(AOP_HPDS)},
[PMGR_DEVICE_INDEX(CLK_AOP_HPDSC)] = {&rMINIPMGR_PS(AOP_HPDSC)},
[PMGR_DEVICE_INDEX(CLK_AOP_HPDD)] = {&rMINIPMGR_PS(AOP_HPDD)},
[PMGR_DEVICE_INDEX(CLK_MARCONI)] = {&rMINIPMGR_PS(MARCONI)},
// PMGR
[PMGR_DEVICE_INDEX(CLK_SCU)] = {&rPMGR_PS(SCU)},
[PMGR_DEVICE_INDEX(CLK_CPU0)] = {&rPMGR_PS(CPU0)},
[PMGR_DEVICE_INDEX(CLK_CPU1)] = {&rPMGR_PS(CPU1)},
[PMGR_DEVICE_INDEX(CLK_PIO)] = {&rPMGR_PS(PIO)},
[PMGR_DEVICE_INDEX(CLK_CPU_FAB)] = {&rPMGR_PS(CPU_FAB)},
[PMGR_DEVICE_INDEX(CLK_NRT_FAB)] = {&rPMGR_PS(NRT_FAB)},
[PMGR_DEVICE_INDEX(CLK_RT_FAB)] = {&rPMGR_PS(RT_FAB)},
[PMGR_DEVICE_INDEX(CLK_AIC)] = {&rPMGR_PS(AIC)},
[PMGR_DEVICE_INDEX(CLK_GPIO)] = {&rPMGR_PS(GPIO)},
[PMGR_DEVICE_INDEX(CLK_ISPSENS0)] = {&rPMGR_PS(ISPSENS0)},
[PMGR_DEVICE_INDEX(CLK_UVD)] = {&rPMGR_PS(UVD)},
[PMGR_DEVICE_INDEX(CLK_HSIC0PHY)] = {&rPMGR_PS(HSIC0PHY)},
[PMGR_DEVICE_INDEX(CLK_AMC)] = {&rPMGR_PS(AMC)},
[PMGR_DEVICE_INDEX(CLK_LIO_FAB)] = {&rPMGR_PS(LIO_FAB)},
[PMGR_DEVICE_INDEX(CLK_LIO_LOGIC)] = {&rPMGR_PS(LIO_LOGIC)},
[PMGR_DEVICE_INDEX(CLK_LIO)] = {&rPMGR_PS(LIO)},
[PMGR_DEVICE_INDEX(CLK_AES0)] = {&rPMGR_PS(AES)},
[PMGR_DEVICE_INDEX(CLK_MCA0)] = {&rPMGR_PS(MCA0)},
[PMGR_DEVICE_INDEX(CLK_MCA1)] = {&rPMGR_PS(MCA1)},
[PMGR_DEVICE_INDEX(CLK_MCA2)] = {&rPMGR_PS(MCA2)},
[PMGR_DEVICE_INDEX(CLK_HFD)] = {&rPMGR_PS(HFD)},
[PMGR_DEVICE_INDEX(CLK_SPI0)] = {&rPMGR_PS(SPI0)},
[PMGR_DEVICE_INDEX(CLK_SPI1)] = {&rPMGR_PS(SPI1)},
[PMGR_DEVICE_INDEX(CLK_UART0)] = {&rPMGR_PS(UART0)},
[PMGR_DEVICE_INDEX(CLK_UART1)] = {&rPMGR_PS(UART1)},
[PMGR_DEVICE_INDEX(CLK_UART2)] = {&rPMGR_PS(UART2)},
[PMGR_DEVICE_INDEX(CLK_UART3)] = {&rPMGR_PS(UART3)},
[PMGR_DEVICE_INDEX(CLK_UART4)] = {&rPMGR_PS(UART4)},
[PMGR_DEVICE_INDEX(CLK_UART5)] = {&rPMGR_PS(UART5)},
[PMGR_DEVICE_INDEX(CLK_UART6)] = {&rPMGR_PS(UART6)},
[PMGR_DEVICE_INDEX(CLK_UART7)] = {&rPMGR_PS(UART7)},
[PMGR_DEVICE_INDEX(CLK_I2C0)] = {&rPMGR_PS(I2C0)},
[PMGR_DEVICE_INDEX(CLK_I2C1)] = {&rPMGR_PS(I2C1)},
[PMGR_DEVICE_INDEX(CLK_I2C2)] = {&rPMGR_PS(I2C2)},
[PMGR_DEVICE_INDEX(CLK_PWM0)] = {&rPMGR_PS(PWM0)},
[PMGR_DEVICE_INDEX(CLK_USB)] = {&rPMGR_PS(USB)},
[PMGR_DEVICE_INDEX(CLK_ETH)] = {&rPMGR_PS(ETH)},
[PMGR_DEVICE_INDEX(CLK_ANS)] = {&rPMGR_PS(ANS)},
[PMGR_DEVICE_INDEX(CLK_SDIO)] = {&rPMGR_PS(SDIO)},
[PMGR_DEVICE_INDEX(CLK_DISP)] = {&rPMGR_PS(DISP)},
[PMGR_DEVICE_INDEX(CLK_MIPI_DSI)] = {&rPMGR_PS(MIPI_DSI)},
[PMGR_DEVICE_INDEX(CLK_ISP)] = {&rPMGR_PS(ISP)},
[PMGR_DEVICE_INDEX(CLK_GFX)] = {&rPMGR_PS(GFX)},
[PMGR_DEVICE_INDEX(CLK_MEDIA_FAB)] = {&rPMGR_PS(MEDIA_FAB)},
[PMGR_DEVICE_INDEX(CLK_MSR)] = {&rPMGR_PS(MSR)},
[PMGR_DEVICE_INDEX(CLK_VDEC)] = {&rPMGR_PS(VDEC)},
[PMGR_DEVICE_INDEX(CLK_JPG)] = {&rPMGR_PS(JPG)},
[PMGR_DEVICE_INDEX(CLK_VENC_CPU)] = {&rPMGR_PS(VENC_CPU)},
[PMGR_DEVICE_INDEX(CLK_USB2HOST1)] = {&rPMGR_PS(USB2HOST1)},
[PMGR_DEVICE_INDEX(CLK_SEP)] = {&rPMGR_PS(SEP)},
[PMGR_DEVICE_INDEX(CLK_VENC_PIPE)] = {&rPMGR_PS(VENC_PIPE)},
[PMGR_DEVICE_INDEX(CLK_VENC_ME)] = {&rPMGR_PS(VENC_ME)},
};
/* ******************************************************************************** */
static void set_pll(uint32_t pll, uint32_t p, uint32_t m, uint32_t s, bool vco_out);
static uint32_t get_pll_frequency(uint32_t pll);
static uint32_t get_spare_frequency(uint32_t cnt);
static void clocks_get_frequencies(void);
static void clocks_get_frequencies_range(uint32_t start_clk, uint32_t end_clk);
static void clocks_quiesce_internal(void);
static void apply_tunables(void);
static void power_on_sep(void);
static void update_memory_clk_config(uint32_t performance_level);
static void config_soc_perf_state(uint32_t state);
static void set_soc_perf_state(uint32_t target_state);
static void set_lppll(void);
static void clock_update_range(uint32_t first, uint32_t last, const uint32_t clkdata);
// current clock frequencies
static uint32_t clks[PMGR_CLK_COUNT + 1];
/* ******************************************************************************** */
static void set_pll(uint32_t pll, uint32_t p, uint32_t m, uint32_t s, bool vco_out)
{
if (pll >= PMGR_PLL_COUNT)
panic("Invalid PLL %u", pll);
rPMGR_PLL_CFG(pll) |= PMGR_PLL_CFG_VCO_OUT_SEL_INSRT(vco_out ? 1 : 0);
rPMGR_PLL_CTL(pll) = (PMGR_PLL_CTL_PRE_DIVN_INSRT(p) | PMGR_PLL_CTL_FB_DIVN_INSRT(m) | PMGR_PLL_CTL_OP_DIVN_INSRT(s) | PMGR_PLL_CTL_LOAD_INSRT(1));
while (PMGR_PLL_CTL_PENDING_XTRCT(rPMGR_PLL_CTL(pll)));
rPMGR_PLL_CTL(pll) |= PMGR_PLL_CTL_ENABLE_INSRT(1);
while (PMGR_PLL_CTL_PENDING_XTRCT(rPMGR_PLL_CTL(pll)));
}
static uint32_t get_pll_frequency(uint32_t pll)
{
uint32_t pllctl, pllcfg;
uint64_t freq = OSC_FREQ;
if (pll >= PMGR_PLL_COUNT)
panic("Invalid PLL %u", pll);
pllctl = rPMGR_PLL_CTL(pll);
pllcfg = rPMGR_PLL_CFG(pll);
if (PMGR_PLL_CTL_ENABLE_XTRCT(pllctl) == 0) {
return 0;
}
else if (PMGR_PLL_CTL_BYPASS_XTRCT(pllctl)) {
return freq;
}
if (PMGR_PLL_CFG_VCO_OUT_SEL_XTRCT(pllcfg)) {
// F_out = F_vco = ((24 / P) * M) * 2
freq /= PMGR_PLL_CTL_PRE_DIVN_XTRCT(pllctl);
freq *= PMGR_PLL_CTL_FB_DIVN_XTRCT(pllctl);
freq *= 2;
}
else {
// F_out = ((24 / P) * M) / (S + 1)
freq /= PMGR_PLL_CTL_PRE_DIVN_XTRCT(pllctl);
freq *= PMGR_PLL_CTL_FB_DIVN_XTRCT(pllctl);
freq /= (1 + PMGR_PLL_CTL_OP_DIVN_XTRCT(pllctl));
}
#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_frequency(uint32_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 = PMGR_CLKCFG_DIVISOR_XTRCT(reg_val);
if ((PMGR_CLKCFG_ENABLE_XTRCT(reg_val) == 0) || div == 0)
return 0;
src_idx = PMGR_CLKCFG_SRC_SEL_XTRCT(reg_val);
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_range(uint32_t start_clk, uint32_t end_clk)
{
volatile uint32_t *reg;
uint32_t cnt, val, src_idx, src_clk, src_factor;
if ((start_clk >= PMGR_CLK_SOURCE_FIRST && end_clk <= PMGR_CLK_SOURCE_LAST) ||
(start_clk >= PMGR_CLK_MINI_FIRST && end_clk <= PMGR_CLK_MINI_LAST)) {
for (cnt = start_clk; cnt <= end_clk; cnt++) {
reg = clk_configs[cnt].clock_reg;
val = *reg;
if (PMGR_CLKCFG_ENABLE_XTRCT(val) == 0) {
clks[cnt] = 0;
continue;
}
src_idx = PMGR_CLKCFG_SRC_SEL_XTRCT(val);
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;
}
}
}
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_MCU_REF] = 10000000;
//clks[PMGR_CLK_MCU_FIXED]= 10000000;
//clks[PMGR_CLK_USB] = 12000000;
#elif CONFIG_SIM
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_frequency() to establish the frequency (unconfigured PLLs will bypass OSC)
for (cnt = 0; cnt < PMGR_PLL_COUNT; cnt++)
clks[PMGR_CLK_PLL0 + cnt] = get_pll_frequency(cnt);
// Use get_spare_frequencies() to establish the frequencies for spare clocks (unconfigured will be skipped)
for (cnt = 0; cnt < sizeof(spare_clock_configs_active) / sizeof(spare_clock_configs_active[0]); cnt++)
clks[PMGR_CLK_S0 + cnt] = get_spare_frequency(cnt);
clocks_get_frequencies_range(PMGR_CLK_MINI_FIRST, PMGR_CLK_MINI_LAST);
clocks_get_frequencies_range(PMGR_CLK_SOURCE_FIRST, PMGR_CLK_SOURCE_LAST);
#endif
}
int clocks_init(void)
{
#if (APPLICATION_IBOOT && (PRODUCT_IBOOT || PRODUCT_IBEC || WITH_RECOVERY_MODE_IBSS))
clocks_get_frequencies();
#endif
return 0;
}
void clock_gate(int device, bool enable)
{
volatile uint32_t *reg;
// Make sure we are within limits
if (!PMGR_VALID_DEVICE(device))
return;
reg = device_configs[PMGR_DEVICE_INDEX(device)].ps_reg;
// Set the PS field to the requested level
if (enable) {
*reg |= PMGR_PS_MANUAL_PS_INSRT(PMGR_PS_RUN_MAX);
} else {
*reg &= ~PMGR_PS_MANUAL_PS_INSRT(PMGR_PS_RUN_MAX);
}
// Wait for the MANUAL_PS and ACTUAL_PS fields to be equal
while (PMGR_PS_MANUAL_PS_XTRCT(*reg) != PMGR_PS_ACTUAL_PS_XTRCT(*reg));
}
static void restore_clock_config_reset_state(void)
{
uint32_t current_select, entry_a;
uint32_t cnt;
// 1. Restore PWR_*_CFG* registers to their reset defaults
rPMGR_CLK_POWER_CONFIG = 0;
// 2. Write reset value to ACG, CLK_DIVIDER_ACG_CFG, CLK_DIVIDER_ACG_CFG1, and PLL_ACG_CFG
rPMGR_MISC_CFG_ACG = 0;
rPMGR_CLK_DIVIDER_ACG_CFG = 0;
// 5a. Write reset value for all mux clock configs (excluding spares)
clock_update_range(PMGR_CLK_SOURCE_FIRST, PMGR_CLK_TMPS - 1, 0x80100000);
clock_update_range(PMGR_CLK_TMPS, PMGR_CLK_TMPS, 0x83100000);
clock_update_range(PMGR_CLK_TMPS + 1, PMGR_CLK_SOURCE_LAST, 0x80100000);
// 5b. Write the desired DRAM clock configuration state into the SOC_PERF_STATE ENTRY_0A register, MCU_REF_CFG_SEL,
// MCU_REF_SRC_SEL fields; Write the reset value to all other fields in ENTRY_0
current_select = PMGR_SOC_PERF_STATE_CTL_CURRENT_SELECT_XTRCT(rPMGR_SOC_PERF_STATE_CTL);
entry_a = pmgr_soc_perf_states[kSOC_PERF_STATE_BYPASS].entry[0];
entry_a &= ~PMGR_SOC_PERF_STATE_ENTRY_MCU_REF_MASK;
entry_a |= rPMGR_SOC_PERF_STATE_ENTRY_A(current_select) & PMGR_SOC_PERF_STATE_ENTRY_MCU_REF_MASK;
rPMGR_SOC_PERF_STATE_ENTRY_A(PMGR_SOC_PERF_STATE_TO_ENTRY(kSOC_PERF_STATE_BYPASS)) = entry_a;
// 6. Write the reset value to the SOC_PERF_STATE_CTL register
rPMGR_SOC_PERF_STATE_CTL = 0;
while (PMGR_SOC_PERF_STATE_CTL_PENDING_XTRCT(rPMGR_SOC_PERF_STATE_CTL));
// 7. Write the reset values to the SOC_PERF_STATE entry registers, except for BYPASS ENTRY_A
for (cnt = PMGR_SOC_PERF_STATE_FIRST_ENTRY; cnt < PMGR_SOC_PERF_STATE_ENTRY_COUNT; cnt++) {
if (cnt == PMGR_SOC_PERF_STATE_TO_ENTRY(kSOC_PERF_STATE_BYPASS))
continue;
rPMGR_SOC_PERF_STATE_ENTRY_A(cnt) = 0;
}
// 11. Write reset value to all PLLx_CTL, except for PLL0
for (cnt = 0; cnt < PMGR_PLL_COUNT; cnt++) {
if (cnt == 0)
continue;
rPMGR_PLL_CTL(cnt) = PMGR_PLL_CTL_ENABLE_INSRT(1) | PMGR_PLL_CTL_BYPASS_INSRT(1) | PMGR_PLL_CTL_FB_DIVN_INSRT(1) | PMGR_PLL_CTL_PRE_DIVN_INSRT(1);
while (PMGR_PLL_CTL_PENDING_XTRCT(rPMGR_PLL_CTL(cnt)));
}
// 12. Write reset value to all other PLL registers, except for PLL0
for (cnt = 0; cnt < PMGR_PLL_COUNT; cnt++) {
if (cnt == 0)
continue;
rPMGR_PLL_CFG(cnt) = PMGR_PLL_CFG_OFF_MODE_INSRT(PMGR_PLL_OFF_MODE_POWER_DOWN) |
PMGR_PLL_CFG_FRAC_LOCK_TIME_INSRT(0x48) | PMGR_PLL_CFG_LOCK_TIME_INSRT(0x348);
}
// 13. Write reset value to spare and ISP_REF0
clock_update_range(PMGR_CLK_SPARE_FIRST, PMGR_CLK_SPARE_LAST, 0x80000001);
// Mini-PMGR
// 2. Write the reset value to the CLK_DIVIDER_ACG_CFG register
rMINIPMGR_CLK_DIVIDER_ACG_CFG = 0;
// 3. Write the reset value to all mux clock config registers
clock_update_range(PMGR_CLK_MINI_FIRST, PMGR_CLK_MINI_LAST, 0x80100000);
// 4. Write the reset value to LPPLL_CTL register
rMINIPMGR_LPPLL_CTL = MINIPMGR_LPPLL_CTL_ENABLE_INSRT(1) | MINIPMGR_LPPLL_CTL_BYPASS_INSRT(1);
while (MINIPMGR_LPPLL_CTL_PENDING_XTRCT(rMINIPMGR_LPPLL_CTL));
// 5. Write the reset value to LPPLL_CFG register
rMINIPMGR_LPPLL_CFG = 0x00000010;
// 6. Write the reset value to the MISC_CFG_ACG register
rMINIPMGR_MISC_CFG_ACG = 0;
}
static void clocks_quiesce_internal(void)
{
#if APPLICATION_SECUREROM
// Workaround for <rdar://problem/19158202> M8: Set ASYNC_XOVER_ACG.GLOBAL_ENABLE at boot before other PS registers
rPMGR_MISC_CFG_ASYNC_XOVER_ACG = PMGR_MISC_CFG_ASYNC_XOVER_ACG_GLOBAL_ENABLE_INSRT(1);
#endif
// Turn on these domains
clock_gate(CLK_AOP, 1);
clock_gate(CLK_DEBUG, 1);
clock_gate(CLK_AOP_GPIO, 1);
clock_gate(CLK_AOP_CPU, 1);
clock_gate(CLK_AOP_FILTER, 1);
clock_gate(CLK_AOP_FILTER_DMA, 1); // PL080 DMA to zero out memory - rdar://problem/19986351
clock_gate(CLK_SCU, 1);
clock_gate(CLK_CPU0, 1);
clock_gate(CLK_PIO, 1);
clock_gate(CLK_CPU_FAB, 1);
clock_gate(CLK_NRT_FAB, 1);
clock_gate(CLK_AIC, 1);
clock_gate(CLK_AMC, 1);
clock_gate(CLK_LIO_FAB, 1);
clock_gate(CLK_LIO_LOGIC, 1);
clock_gate(CLK_LIO, 1);
clock_gate(CLK_GPIO, 1);
clock_gate(CLK_AES0, 1);
clock_gate(CLK_USB, 1);
clock_gate(CLK_ETH, 1);
clock_gate(CLK_ANS, 1);
// Turn off these domains
clock_gate(CLK_AOP_I2CM1, 0);
clock_gate(CLK_AOP_RTCPU, 0);
clock_gate(CLK_AOP_UART0, 0);
clock_gate(CLK_AOP_UART1, 0);
clock_gate(CLK_AOP_UART2, 0);
clock_gate(CLK_AOP_I2CM, 0);
clock_gate(CLK_AOP_LPD0, 0);
clock_gate(CLK_AOP_HPDS, 0);
clock_gate(CLK_AOP_HPDSC, 0);
clock_gate(CLK_AOP_HPDD, 0);
clock_gate(CLK_CPU1, 0);
clock_gate(CLK_RT_FAB, 0);
clock_gate(CLK_ISPSENS0, 0);
clock_gate(CLK_UVD, 0);
clock_gate(CLK_HSIC0PHY, 0);
clock_gate(CLK_MCA0, 0);
clock_gate(CLK_MCA1, 0);
clock_gate(CLK_MCA2, 0);
clock_gate(CLK_HFD, 0);
clock_gate(CLK_SPI0, 0);
clock_gate(CLK_SPI1, 0);
clock_gate(CLK_UART0, 0);
clock_gate(CLK_UART1, 0);
clock_gate(CLK_UART2, 0);
clock_gate(CLK_UART3, 0);
clock_gate(CLK_UART4, 0);
clock_gate(CLK_UART5, 0);
clock_gate(CLK_UART6, 0);
clock_gate(CLK_UART7, 0);
clock_gate(CLK_I2C0, 0);
clock_gate(CLK_I2C1, 0);
clock_gate(CLK_I2C2, 0);
clock_gate(CLK_PWM0, 0);
clock_gate(CLK_SDIO, 0);
clock_gate(CLK_DISP, 0);
clock_gate(CLK_MIPI_DSI, 0);
clock_gate(CLK_ISP, 0);
clock_gate(CLK_GFX, 0);
clock_gate(CLK_MEDIA_FAB, 0);
clock_gate(CLK_MSR, 0);
clock_gate(CLK_VDEC, 0);
clock_gate(CLK_JPG, 0);
clock_gate(CLK_VENC_CPU, 0);
clock_gate(CLK_USB2HOST1, 0);
restore_clock_config_reset_state();
}
static void enable_bira_work_around(void)
{
// Workaround for <rdar://problem/20253847> M8: DFT logic isn't reset when a partition powers up while another one is repaired
// Note: The reconfig part of this workaround is not done by pmgr driver.
static const uint32_t domain[] = {
CLK_SDIO,
CLK_DISP,
CLK_MIPI_DSI,
CLK_ISP,
CLK_GFX,
CLK_MSR,
CLK_VDEC,
CLK_JPG,
CLK_VENC_CPU,
CLK_VENC_PIPE,
CLK_VENC_ME,
};
// Turn on the blocks
for (uint32_t i = 0; i < sizeof(domain)/sizeof(domain[0]); i++) {
clock_gate(domain[i], true);
}
// Turn off the blocks
for (uint32_t i = sizeof(domain)/sizeof(domain[0]); i > 0; i--) {
clock_gate(domain[i - 1], false);
}
}
static void apply_tunables(void)
{
uint32_t i, j;
for (i = 0; tunables_pmgr[i].chip_rev < UINT32_MAX; i++) {
const struct tunable_struct *tunable_chip = tunables_pmgr[i].tunable;
void *tunable_base = (void *)tunables_pmgr[i].base_address;
uint32_t tunable_index;
if (tunables_pmgr[i].chip_rev > chipid_get_chip_revision()) {
continue;
}
for (tunable_index = 0; tunable_chip[tunable_index].offset != -1; tunable_index++) {
uint32_t val;
bool filtered = false;
// Skip filtered cold boot tunables
for (j = 0; tunables_filtered_pmgr[j].chip_rev < UINT32_MAX; j++) {
if (tunables_pmgr[i].chip_rev == tunables_filtered_pmgr[j].chip_rev &&
tunables_pmgr[i].base_address + tunable_chip[tunable_index].offset >= tunables_filtered_pmgr[j].starting_address &&
tunables_pmgr[i].base_address + tunable_chip[tunable_index].offset <= tunables_filtered_pmgr[j].ending_address &&
tunables_filtered_pmgr[j].cold_boot) {
filtered = true;
break;
}
}
if (filtered)
continue;
// TODO: Handle reconfig tunables and filtered reconfig tunables
val = *((volatile uint32_t *)(tunable_base + tunable_chip[tunable_index].offset));
if ((val & tunable_chip[tunable_index].mask) == tunable_chip[tunable_index].value) {
// Tunable already applied. No need to apply it again
continue;
}
val &= ~tunable_chip[tunable_index].mask;
val |= tunable_chip[tunable_index].value;
*((volatile uint32_t *)(tunable_base + tunable_chip[tunable_index].offset)) = (uint32_t)val;
}
}
}
static void set_nco_clocks(void)
{
// Enable this NCO with alg_ref0_clk and nco_ref0_clk.
// Note: clk_configs assumes all NCOs use nco_ref0_clk
rPMGR_NCO_CLK_CFG(0) |= (PMGR_CLKCFG_NCO_REF0_CLK_CFG_ENABLE_INSRT(1));
rPMGR_NCO_CLK_CFG(1) |= (PMGR_CLKCFG_NCO_REF1_CLK_CFG_ENABLE_INSRT(1));
}
static void set_clkcfg(volatile uint32_t *clkcfg, uint32_t value)
{
uint32_t val;
// Modify only the fields in mask
uint32_t mask = PMGR_CLKCFG_ENABLE_UMASK | PMGR_CLKCFG_SRC_SEL_UMASK |
PMGR_CLKCFG_DIVISOR_UMASK | PMGR_CLKCFG_WAIT_COUNTER_UMASK;
if (value & ~mask)
panic("Fields mismatch with mask for value %#u in CLK_CFG %#u", value, (uint32_t) clkcfg);
val = (*clkcfg) & ~mask;
val |= value & mask;
*clkcfg = val;
while (PMGR_CLKCFG_PENDING_XTRCT(*clkcfg));
}
/*
* 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;
volatile uint32_t *clkcfg;
#if (APPLICATION_IBOOT && !PRODUCT_IBOOT && !PRODUCT_IBEC) || APPLICATION_OSV
enable_bira_work_around();
#endif
clks[PMGR_CLK_OSC] = OSC_FREQ;
// Change all clocks to something safe
clocks_quiesce_internal();
#if (APPLICATION_IBOOT && !PRODUCT_IBOOT && !PRODUCT_IBEC) || APPLICATION_OSV
apply_tunables();
#endif
// Setup active DVFM and SOC PERF states for the stage of boot.
#if APPLICATION_SECUREROM
config_soc_perf_state(kSOC_PERF_STATE_SECUREROM);
#endif
config_soc_perf_state(kSOC_PERF_STATE_VMIN);
#ifdef LPPLL_T
set_lppll();
#endif
#ifdef PLL0_T
set_pll(PLL0, PLL0_P, PLL0_M, PLL0_S, PLL0_VCO_OUT);
#endif
#ifdef PLL1_T
set_pll(PLL1, PLL1_P, PLL1_M, PLL1_S, PLL1_VCO_OUT);
#endif
#if (APPLICATION_IBOOT && !PRODUCT_IBOOT && !PRODUCT_IBEC)
// Turn on NCO clocks before enabling MCA clocks.
set_nco_clocks();
#endif
set_soc_perf_state(SOC_PERF_STATE_ACTIVE);
// Set all spare clock divs to their active values
for (cnt = 0; cnt < sizeof(spare_clock_configs_active) / sizeof(spare_clock_configs_active[0]); cnt++) {
clkcfg = clk_configs[spare_clock_configs_active[cnt].clk].clock_reg;
set_clkcfg(clkcfg, spare_clock_configs_active[cnt].clock_reg_val);
}
// Set all non-spare clock divs to their active values
for (cnt = 0; cnt < sizeof(clk_configs_active) / sizeof(clk_configs_active[0]); cnt++) {
clkcfg = clk_configs[clk_configs_active[cnt].clk].clock_reg;
set_clkcfg(clkcfg, clk_configs_active[cnt].clock_reg_val);
}
power_on_sep();
clocks_get_frequencies();
return 0;
}
void clocks_quiesce(void)
{
clocks_quiesce_internal();
}
uint32_t clocks_set_performance(uint32_t performance_level)
{
uint32_t old_perf_level = perf_level;
#if APPLICATION_IBOOT
uint32_t entry_a;
switch (performance_level) {
case kPerformanceMemoryLow:
case kPerformanceMemoryMid:
case kPerformanceMemoryFull:
entry_a = rPMGR_SOC_PERF_STATE_ENTRY_A(PMGR_SOC_PERF_STATE_TO_ENTRY(kSOC_PERF_STATE_VMIN));
entry_a &= ~PMGR_SOC_PERF_STATE_ENTRY_MCU_REF_MASK;
if (performance_level == kPerformanceMemoryLow)
entry_a |= PMGR_SOC_PERF_STATE_ENTRY_MCU_REF(0x3, 0x4); // 48 MHz MCU_REF_CLK, 48 MHz bin
else
entry_a |= PMGR_SOC_PERF_STATE_ENTRY_MCU_REF(0x0, 0x3); // 88.8 MHz MCU_REF_CLK, 1600 MHz bin
rPMGR_SOC_PERF_STATE_ENTRY_A(PMGR_SOC_PERF_STATE_TO_ENTRY(kSOC_PERF_STATE_VMIN)) = entry_a;
set_soc_perf_state(kSOC_PERF_STATE_VMIN);
perf_level = performance_level;
break;
default:
break;
}
clocks_get_frequencies_range(PMGR_CLK_MCU_REF, PMGR_CLK_MCU_REF);
#endif
return old_perf_level;
}
void clock_get_frequencies(uint32_t *clocks, uint32_t count)
{
uint32_t cnt = PMGR_CLK_COUNT;
if (cnt > count) cnt = count;
memcpy(clocks, clks, cnt * sizeof(uint32_t));
}
uint32_t clock_get_frequency(int clock)
{
uint32_t freq = OSC_FREQ;
switch (clock) {
case CLK_NCLK:
case CLK_FIXED:
case CLK_TIMEBASE:
freq = clks[PMGR_CLK_OSC];
break;
case CLK_ANS_LINK:
freq = clks[PMGR_CLK_ANS];
break;
case CLK_BUS:
case CLK_PCLK:
case CLK_PERIPH:
freq = clks[PMGR_CLK_LIO];
break;
case CLK_MEM:
freq = clks[PMGR_CLK_MCU_REF];
break;
case CLK_CPU:
freq = clks[PMGR_CLK_MCU_REF];
break;
case CLK_AOP:
freq = clks[PMGR_CLK_AOP];
break;
default:
break;
}
return freq;
}
static void clock_update_frequency(uint32_t clk, uint32_t freq)
{
uint32_t src_idx, src_clk, src_factor, reg;
bool freq_supported = false;
volatile uint32_t *clkcfg = clk_configs[clk].clock_reg;
if (freq == 0)
{
return;
}
for (src_idx = 0; src_idx < CLOCK_SOURCES_MAX && clk_configs[clk].sources[src_idx].factor != 0; src_idx++)
{
src_clk = clk_configs[clk].sources[src_idx].src_clk;
src_factor = clk_configs[clk].sources[src_idx].factor;
// Round the requested frequency to closest MHz value and check if we have a match
if ((freq / 1000000) == ((clks[src_clk] / src_factor) / 1000000))
{
freq_supported = true;
break;
}
}
if (freq_supported)
{
// Configure clock
reg = *clkcfg;
reg &= ~(PMGR_CLKCFG_SRC_SEL_UMASK);
reg |= PMGR_CLKCFG_SRC_SEL_INSRT(src_idx);
set_clkcfg(clkcfg, reg);
}
}
void clock_set_frequency(int clock, uint32_t divider, uint32_t pll_p, uint32_t pll_m, uint32_t pll_s, uint32_t pll_t)
{
uint32_t clk = PMGR_CLK_OSC;
switch (clock) {
case CLK_VCLK0:
clk = PMGR_CLK_VID;
break;
default:
break;
}
if (clk >= PMGR_CLK_SOURCE_FIRST && clk <= PMGR_CLK_SOURCE_LAST) {
clock_update_frequency(clk, pll_t);
clocks_get_frequencies_range(clk, clk);
}
}
void clock_reset_device(int device)
{
volatile uint32_t *reg;
// Make sure we are within limits.
if (!PMGR_VALID_DEVICE(device))
return;
reg = device_configs[PMGR_DEVICE_INDEX(device)].ps_reg;
switch (device) {
case CLK_AMC:
default:
*reg |= PMGR_PS_RESET_INSRT(1);
spin(1);
*reg &= ~PMGR_PS_RESET_INSRT(1);
break;
}
}
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)
{
}
void platform_power_spin(uint32_t usecs)
{
extern void aic_spin(uint32_t usecs);
aic_spin(usecs);
}
#if WITH_DEVICETREE
void pmgr_update_device_tree(DTNode *pmgr_node)
{
}
#endif
static void config_soc_perf_state(uint32_t state)
{
uint32_t index = state;
#if APPLICATION_IBOOT
if (index >= kSOC_PERF_STATE_IBOOT_CNT)
index = kSOC_PERF_STATE_VMIN;
#endif
rPMGR_SOC_PERF_STATE_ENTRY_A(PMGR_SOC_PERF_STATE_TO_ENTRY(state)) = pmgr_soc_perf_states[index].entry[0];
}
static void set_soc_perf_state(uint32_t target_state)
{
rPMGR_SOC_PERF_STATE_CTL = PMGR_SOC_PERF_STATE_TO_ENTRY(target_state);
while (PMGR_SOC_PERF_STATE_CTL_PENDING_XTRCT(rPMGR_SOC_PERF_STATE_CTL));
}
static void set_lppll(void)
{
rMINIPMGR_LPPLL_CTL = MINIPMGR_LPPLL_CTL_ENABLE_INSRT(1);
while (MINIPMGR_LPPLL_CTL_PENDING_XTRCT(rMINIPMGR_LPPLL_CTL));
}
static void clock_update_range(uint32_t first, uint32_t last, const uint32_t clkdata)
{
volatile uint32_t *reg;
uint32_t cnt;
for (cnt = first; cnt <= last; cnt++) {
reg = clk_configs[cnt].clock_reg;
set_clkcfg(reg, clkdata);
}
}
static void power_on_sep(void)
{
volatile uint32_t *reg;
uint32_t val;
reg = device_configs[PMGR_DEVICE_INDEX(CLK_SEP)].ps_reg;
val = *reg;
val &= ~(PMGR_PS_SEP_PS_AUTO_PM_EN_INSRT(1) | PMGR_PS_SEP_PS_FORCE_NOACCESS_INSRT(1));
*reg = val;
while (PMGR_PS_SEP_PS_ACTUAL_PS_XTRCT(*reg) != PMGR_PS_RUN_MAX); // Wait for SEP to turn on.
return;
}