1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2016-2020, Broadcom 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <stdint.h> 8*91f16700Schasinglulu 9*91f16700Schasinglulu #include <common/debug.h> 10*91f16700Schasinglulu #include <lib/mmio.h> 11*91f16700Schasinglulu 12*91f16700Schasinglulu #include <dmu.h> 13*91f16700Schasinglulu 14*91f16700Schasinglulu #define IHOST0_CONFIG_ROOT 0x66000000 15*91f16700Schasinglulu #define IHOST1_CONFIG_ROOT 0x66002000 16*91f16700Schasinglulu #define IHOST2_CONFIG_ROOT 0x66004000 17*91f16700Schasinglulu #define IHOST3_CONFIG_ROOT 0x66006000 18*91f16700Schasinglulu #define A72_CRM_PLL_PWR_ON 0x00000070 19*91f16700Schasinglulu #define A72_CRM_PLL_PWR_ON__PLL0_RESETB_R 4 20*91f16700Schasinglulu #define A72_CRM_PLL_PWR_ON__PLL0_POST_RESETB_R 5 21*91f16700Schasinglulu #define A72_CRM_PLL_CHNL_BYPS_EN 0x000000ac 22*91f16700Schasinglulu #define A72_CRM_PLL_CHNL_BYPS_EN__PLL_0_CHNL_0_BYPS_EN_R 0 23*91f16700Schasinglulu #define A72_CRM_PLL_CHNL_BYPS_EN_DATAMASK 0x0000ec1f 24*91f16700Schasinglulu #define A72_CRM_PLL_CMD 0x00000080 25*91f16700Schasinglulu #define A72_CRM_PLL_CMD__UPDATE_PLL0_FREQUENCY_VCO_R 0 26*91f16700Schasinglulu #define A72_CRM_PLL_CMD__UPDATE_PLL0_FREQUENCY_POST_R 1 27*91f16700Schasinglulu #define A72_CRM_PLL_STATUS 0x00000084 28*91f16700Schasinglulu #define A72_CRM_PLL_STATUS__PLL0_LOCK_R 9 29*91f16700Schasinglulu #define A72_CRM_PLL0_CTRL1 0x00000100 30*91f16700Schasinglulu #define A72_CRM_PLL0_CTRL2 0x00000104 31*91f16700Schasinglulu #define A72_CRM_PLL0_CTRL3 0x00000108 32*91f16700Schasinglulu #define A72_CRM_PLL0_CTRL3__PLL0_PDIV_R 12 33*91f16700Schasinglulu #define A72_CRM_PLL0_CTRL4 0x0000010c 34*91f16700Schasinglulu #define A72_CRM_PLL0_CTRL4__PLL0_KP_R 0 35*91f16700Schasinglulu #define A72_CRM_PLL0_CTRL4__PLL0_KI_R 4 36*91f16700Schasinglulu #define A72_CRM_PLL0_CTRL4__PLL0_KA_R 7 37*91f16700Schasinglulu #define A72_CRM_PLL0_CTRL4__PLL0_FREFEFF_INFO_R 10 38*91f16700Schasinglulu 39*91f16700Schasinglulu #define PLL_MODE_VCO 0x0 40*91f16700Schasinglulu #define PLL_MODE_BYPASS 0x1 41*91f16700Schasinglulu #define PLL_RESET_TYPE_PLL 0x1 42*91f16700Schasinglulu #define PLL_RESET_TYPE_POST 0x2 43*91f16700Schasinglulu #define PLL_VCO 0x1 44*91f16700Schasinglulu #define PLL_POSTDIV 0x2 45*91f16700Schasinglulu #define ARM_FREQ_3G PLL_FREQ_FULL 46*91f16700Schasinglulu #define ARM_FREQ_1P5G PLL_FREQ_HALF 47*91f16700Schasinglulu #define ARM_FREQ_750M PLL_FREQ_QRTR 48*91f16700Schasinglulu 49*91f16700Schasinglulu static unsigned int ARMCOE_crm_getBaseAddress(unsigned int cluster_num) 50*91f16700Schasinglulu { 51*91f16700Schasinglulu unsigned int ihostx_config_root; 52*91f16700Schasinglulu 53*91f16700Schasinglulu switch (cluster_num) { 54*91f16700Schasinglulu case 0: 55*91f16700Schasinglulu default: 56*91f16700Schasinglulu ihostx_config_root = IHOST0_CONFIG_ROOT; 57*91f16700Schasinglulu break; 58*91f16700Schasinglulu case 1: 59*91f16700Schasinglulu ihostx_config_root = IHOST1_CONFIG_ROOT; 60*91f16700Schasinglulu break; 61*91f16700Schasinglulu case 2: 62*91f16700Schasinglulu ihostx_config_root = IHOST2_CONFIG_ROOT; 63*91f16700Schasinglulu break; 64*91f16700Schasinglulu case 3: 65*91f16700Schasinglulu ihostx_config_root = IHOST3_CONFIG_ROOT; 66*91f16700Schasinglulu break; 67*91f16700Schasinglulu } 68*91f16700Schasinglulu 69*91f16700Schasinglulu return ihostx_config_root; 70*91f16700Schasinglulu } 71*91f16700Schasinglulu 72*91f16700Schasinglulu static void ARMCOE_crm_pllAssertReset(unsigned int cluster_num, 73*91f16700Schasinglulu unsigned int reset_type) 74*91f16700Schasinglulu { 75*91f16700Schasinglulu unsigned long ihostx_config_root; 76*91f16700Schasinglulu unsigned int pll_rst_ctrl; 77*91f16700Schasinglulu 78*91f16700Schasinglulu ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num); 79*91f16700Schasinglulu pll_rst_ctrl = mmio_read_32(ihostx_config_root + A72_CRM_PLL_PWR_ON); 80*91f16700Schasinglulu 81*91f16700Schasinglulu // PLL reset 82*91f16700Schasinglulu if (reset_type & PLL_RESET_TYPE_PLL) { 83*91f16700Schasinglulu pll_rst_ctrl &= ~(0x1<<A72_CRM_PLL_PWR_ON__PLL0_RESETB_R); 84*91f16700Schasinglulu } 85*91f16700Schasinglulu // post-div channel reset 86*91f16700Schasinglulu if (reset_type & PLL_RESET_TYPE_POST) { 87*91f16700Schasinglulu pll_rst_ctrl &= ~(0x1<<A72_CRM_PLL_PWR_ON__PLL0_POST_RESETB_R); 88*91f16700Schasinglulu } 89*91f16700Schasinglulu 90*91f16700Schasinglulu mmio_write_32(ihostx_config_root + A72_CRM_PLL_PWR_ON, pll_rst_ctrl); 91*91f16700Schasinglulu } 92*91f16700Schasinglulu 93*91f16700Schasinglulu static void ARMCOE_crm_pllSetMode(unsigned int cluster_num, unsigned int mode) 94*91f16700Schasinglulu { 95*91f16700Schasinglulu unsigned long ihostx_config_root; 96*91f16700Schasinglulu unsigned int pll_byp_ctrl; 97*91f16700Schasinglulu 98*91f16700Schasinglulu ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num); 99*91f16700Schasinglulu pll_byp_ctrl = mmio_read_32(ihostx_config_root + 100*91f16700Schasinglulu A72_CRM_PLL_CHNL_BYPS_EN); 101*91f16700Schasinglulu 102*91f16700Schasinglulu if (mode == PLL_MODE_VCO) { 103*91f16700Schasinglulu // use PLL DCO output 104*91f16700Schasinglulu pll_byp_ctrl &= 105*91f16700Schasinglulu ~BIT(A72_CRM_PLL_CHNL_BYPS_EN__PLL_0_CHNL_0_BYPS_EN_R); 106*91f16700Schasinglulu } else { 107*91f16700Schasinglulu // use PLL bypass sources 108*91f16700Schasinglulu pll_byp_ctrl |= 109*91f16700Schasinglulu BIT(A72_CRM_PLL_CHNL_BYPS_EN__PLL_0_CHNL_0_BYPS_EN_R); 110*91f16700Schasinglulu } 111*91f16700Schasinglulu 112*91f16700Schasinglulu mmio_write_32(ihostx_config_root + A72_CRM_PLL_CHNL_BYPS_EN, 113*91f16700Schasinglulu pll_byp_ctrl); 114*91f16700Schasinglulu } 115*91f16700Schasinglulu 116*91f16700Schasinglulu static void ARMCOE_crm_pllFreqSet(unsigned int cluster_num, 117*91f16700Schasinglulu unsigned int ihost_pll_freq_sel, 118*91f16700Schasinglulu unsigned int pdiv) 119*91f16700Schasinglulu { 120*91f16700Schasinglulu unsigned int ndiv_int; 121*91f16700Schasinglulu unsigned int ndiv_frac_low, ndiv_frac_high; 122*91f16700Schasinglulu unsigned long ihostx_config_root; 123*91f16700Schasinglulu 124*91f16700Schasinglulu ndiv_frac_low = 0x0; 125*91f16700Schasinglulu ndiv_frac_high = 0x0; 126*91f16700Schasinglulu 127*91f16700Schasinglulu if (ihost_pll_freq_sel == ARM_FREQ_3G) { 128*91f16700Schasinglulu ndiv_int = 0x78; 129*91f16700Schasinglulu } else if (ihost_pll_freq_sel == ARM_FREQ_1P5G) { 130*91f16700Schasinglulu ndiv_int = 0x3c; 131*91f16700Schasinglulu } else if (ihost_pll_freq_sel == ARM_FREQ_750M) { 132*91f16700Schasinglulu ndiv_int = 0x1e; 133*91f16700Schasinglulu } else { 134*91f16700Schasinglulu return; 135*91f16700Schasinglulu } 136*91f16700Schasinglulu 137*91f16700Schasinglulu ndiv_int &= 0x3FF; // low 10 bits 138*91f16700Schasinglulu ndiv_frac_low &= 0x3FF; 139*91f16700Schasinglulu ndiv_frac_high &= 0x3FF; 140*91f16700Schasinglulu 141*91f16700Schasinglulu ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num); 142*91f16700Schasinglulu 143*91f16700Schasinglulu mmio_write_32(ihostx_config_root+A72_CRM_PLL0_CTRL1, ndiv_frac_low); 144*91f16700Schasinglulu mmio_write_32(ihostx_config_root+A72_CRM_PLL0_CTRL2, ndiv_frac_high); 145*91f16700Schasinglulu mmio_write_32(ihostx_config_root+A72_CRM_PLL0_CTRL3, 146*91f16700Schasinglulu ndiv_int | 147*91f16700Schasinglulu ((pdiv << A72_CRM_PLL0_CTRL3__PLL0_PDIV_R & 0xF000))); 148*91f16700Schasinglulu 149*91f16700Schasinglulu mmio_write_32(ihostx_config_root + A72_CRM_PLL0_CTRL4, 150*91f16700Schasinglulu /* From Section 10 of PLL spec */ 151*91f16700Schasinglulu (3 << A72_CRM_PLL0_CTRL4__PLL0_KP_R) | 152*91f16700Schasinglulu /* From Section 10 of PLL spec */ 153*91f16700Schasinglulu (2 << A72_CRM_PLL0_CTRL4__PLL0_KI_R) | 154*91f16700Schasinglulu /* Normal mode (i.e. not fast-locking) */ 155*91f16700Schasinglulu (0 << A72_CRM_PLL0_CTRL4__PLL0_KA_R) | 156*91f16700Schasinglulu /* 50 MHz */ 157*91f16700Schasinglulu (50 << A72_CRM_PLL0_CTRL4__PLL0_FREFEFF_INFO_R)); 158*91f16700Schasinglulu } 159*91f16700Schasinglulu 160*91f16700Schasinglulu static void ARMCOE_crm_pllDeassertReset(unsigned int cluster_num, 161*91f16700Schasinglulu unsigned int reset_type) 162*91f16700Schasinglulu { 163*91f16700Schasinglulu unsigned long ihostx_config_root; 164*91f16700Schasinglulu unsigned int pll_rst_ctrl; 165*91f16700Schasinglulu 166*91f16700Schasinglulu ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num); 167*91f16700Schasinglulu pll_rst_ctrl = mmio_read_32(ihostx_config_root + A72_CRM_PLL_PWR_ON); 168*91f16700Schasinglulu 169*91f16700Schasinglulu // PLL reset 170*91f16700Schasinglulu if (reset_type & PLL_RESET_TYPE_PLL) { 171*91f16700Schasinglulu pll_rst_ctrl |= (0x1 << A72_CRM_PLL_PWR_ON__PLL0_RESETB_R); 172*91f16700Schasinglulu } 173*91f16700Schasinglulu 174*91f16700Schasinglulu // post-div channel reset 175*91f16700Schasinglulu if (reset_type & PLL_RESET_TYPE_POST) { 176*91f16700Schasinglulu pll_rst_ctrl |= (0x1 << A72_CRM_PLL_PWR_ON__PLL0_POST_RESETB_R); 177*91f16700Schasinglulu } 178*91f16700Schasinglulu 179*91f16700Schasinglulu mmio_write_32(ihostx_config_root + A72_CRM_PLL_PWR_ON, pll_rst_ctrl); 180*91f16700Schasinglulu } 181*91f16700Schasinglulu 182*91f16700Schasinglulu static void ARMCOE_crm_pllUpdate(unsigned int cluster_num, unsigned int type) 183*91f16700Schasinglulu { 184*91f16700Schasinglulu unsigned long ihostx_config_root; 185*91f16700Schasinglulu unsigned int pll_cmd; 186*91f16700Schasinglulu 187*91f16700Schasinglulu ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num); 188*91f16700Schasinglulu pll_cmd = mmio_read_32(ihostx_config_root + A72_CRM_PLL_CMD); 189*91f16700Schasinglulu 190*91f16700Schasinglulu // VCO update 191*91f16700Schasinglulu if (type & PLL_VCO) { 192*91f16700Schasinglulu pll_cmd |= BIT(A72_CRM_PLL_CMD__UPDATE_PLL0_FREQUENCY_VCO_R); 193*91f16700Schasinglulu } 194*91f16700Schasinglulu // post-div channel update 195*91f16700Schasinglulu if (type & PLL_POSTDIV) { 196*91f16700Schasinglulu pll_cmd |= BIT(A72_CRM_PLL_CMD__UPDATE_PLL0_FREQUENCY_POST_R); 197*91f16700Schasinglulu } 198*91f16700Schasinglulu 199*91f16700Schasinglulu mmio_write_32(ihostx_config_root+A72_CRM_PLL_CMD, pll_cmd); 200*91f16700Schasinglulu } 201*91f16700Schasinglulu 202*91f16700Schasinglulu static void insert_delay(unsigned int delay) 203*91f16700Schasinglulu { 204*91f16700Schasinglulu volatile unsigned int index; 205*91f16700Schasinglulu 206*91f16700Schasinglulu for (index = 0; index < delay; index++) 207*91f16700Schasinglulu ; 208*91f16700Schasinglulu } 209*91f16700Schasinglulu 210*91f16700Schasinglulu 211*91f16700Schasinglulu /* 212*91f16700Schasinglulu * Returns 1 if PLL locked within certain interval 213*91f16700Schasinglulu */ 214*91f16700Schasinglulu static unsigned int ARMCOE_crm_pllIsLocked(unsigned int cluster_num) 215*91f16700Schasinglulu { 216*91f16700Schasinglulu unsigned long ihostx_config_root; 217*91f16700Schasinglulu unsigned int lock_status; 218*91f16700Schasinglulu unsigned int i; 219*91f16700Schasinglulu 220*91f16700Schasinglulu ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num); 221*91f16700Schasinglulu 222*91f16700Schasinglulu /* wait a while for pll to lock before returning from this function */ 223*91f16700Schasinglulu for (i = 0; i < 1500; i++) { 224*91f16700Schasinglulu insert_delay(256); 225*91f16700Schasinglulu lock_status = mmio_read_32(ihostx_config_root + 226*91f16700Schasinglulu A72_CRM_PLL_STATUS); 227*91f16700Schasinglulu if (lock_status & BIT(A72_CRM_PLL_STATUS__PLL0_LOCK_R)) 228*91f16700Schasinglulu return 1; 229*91f16700Schasinglulu } 230*91f16700Schasinglulu 231*91f16700Schasinglulu ERROR("PLL of Cluster #%u failed to lock\n", cluster_num); 232*91f16700Schasinglulu return 0; 233*91f16700Schasinglulu } 234*91f16700Schasinglulu 235*91f16700Schasinglulu /* 236*91f16700Schasinglulu * ihost PLL Variable Frequency Configuration 237*91f16700Schasinglulu * 238*91f16700Schasinglulu * Frequency Limit {VCO,ARM} (GHz): 239*91f16700Schasinglulu * 0 - no limit, 240*91f16700Schasinglulu * 1 - {3.0,1.5}, 241*91f16700Schasinglulu * 2 - {4.0,2.0}, 242*91f16700Schasinglulu * 3 - {5.0,2.5} 243*91f16700Schasinglulu */ 244*91f16700Schasinglulu uint32_t bcm_set_ihost_pll_freq(uint32_t cluster_num, int ihost_pll_freq_sel) 245*91f16700Schasinglulu { 246*91f16700Schasinglulu NOTICE("cluster: %u, freq_sel:0x%x\n", cluster_num, ihost_pll_freq_sel); 247*91f16700Schasinglulu 248*91f16700Schasinglulu //bypass PLL 249*91f16700Schasinglulu ARMCOE_crm_pllSetMode(cluster_num, PLL_MODE_BYPASS); 250*91f16700Schasinglulu //assert reset 251*91f16700Schasinglulu ARMCOE_crm_pllAssertReset(cluster_num, 252*91f16700Schasinglulu PLL_RESET_TYPE_PLL | PLL_RESET_TYPE_POST); 253*91f16700Schasinglulu //set ndiv_int for different freq 254*91f16700Schasinglulu ARMCOE_crm_pllFreqSet(cluster_num, ihost_pll_freq_sel, 0x1); 255*91f16700Schasinglulu //de-assert reset 256*91f16700Schasinglulu ARMCOE_crm_pllDeassertReset(cluster_num, PLL_RESET_TYPE_PLL); 257*91f16700Schasinglulu ARMCOE_crm_pllUpdate(cluster_num, PLL_VCO); 258*91f16700Schasinglulu //waiting for PLL lock 259*91f16700Schasinglulu ARMCOE_crm_pllIsLocked(cluster_num); 260*91f16700Schasinglulu ARMCOE_crm_pllDeassertReset(cluster_num, PLL_RESET_TYPE_POST); 261*91f16700Schasinglulu //disable bypass PLL 262*91f16700Schasinglulu ARMCOE_crm_pllSetMode(cluster_num, PLL_MODE_VCO); 263*91f16700Schasinglulu 264*91f16700Schasinglulu return 0; 265*91f16700Schasinglulu } 266*91f16700Schasinglulu 267*91f16700Schasinglulu uint32_t bcm_get_ihost_pll_freq(uint32_t cluster_num) 268*91f16700Schasinglulu { 269*91f16700Schasinglulu unsigned long ihostx_config_root; 270*91f16700Schasinglulu uint32_t ndiv_int; 271*91f16700Schasinglulu uint32_t ihost_pll_freq_sel; 272*91f16700Schasinglulu 273*91f16700Schasinglulu ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num); 274*91f16700Schasinglulu ndiv_int = mmio_read_32(ihostx_config_root+A72_CRM_PLL0_CTRL3) & 0x3FF; 275*91f16700Schasinglulu 276*91f16700Schasinglulu if (ndiv_int == 0x78) { 277*91f16700Schasinglulu ihost_pll_freq_sel = ARM_FREQ_3G; 278*91f16700Schasinglulu } else if (ndiv_int == 0x3c) { 279*91f16700Schasinglulu ihost_pll_freq_sel = ARM_FREQ_1P5G; 280*91f16700Schasinglulu } else if (ndiv_int == 0x1e) { 281*91f16700Schasinglulu ihost_pll_freq_sel = ARM_FREQ_750M; 282*91f16700Schasinglulu } else { 283*91f16700Schasinglulu /* return unlimit otherwise*/ 284*91f16700Schasinglulu ihost_pll_freq_sel = 0; 285*91f16700Schasinglulu } 286*91f16700Schasinglulu return ihost_pll_freq_sel; 287*91f16700Schasinglulu } 288