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