1/* 2 * BCM43XX Sonics SiliconBackplane ARM core routines 3 * 4 * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * 18 * $Id: hndarm.c 328955 2012-04-23 09:06:12Z $ 19 */ 20 21#include <typedefs.h> 22#include <bcmutils.h> 23#include <siutils.h> 24#include <hndsoc.h> 25#include <sbchipc.h> 26#include <bcmdevs.h> 27#include <hndpmu.h> 28#include <chipcommonb.h> 29#include <armca9_core.h> 30#include <ddr_core.h> 31 32#define PLL_SUP_4708 0x00000001 33#define PLL_SUP_4709 0x00000002 34#define PLL_SUP_47092 0x00000004 35#define PLL_SUP_47094 0x00000008 36#define PLL_SUP_NS_ALL (PLL_SUP_4708 | PLL_SUP_4709 | PLL_SUP_47092 | PLL_SUP_47094) 37#define PLL_SUP_DDR2 0x00000001 38#define PLL_SUP_DDR3 0x00000002 39 40struct arm_pll { 41 uint32 clk; 42 uint32 reg_val; 43 uint32 flag; 44}; 45 46struct ddr_clk { 47 uint32 clk; 48 uint32 pll_ctrl_1; 49 uint32 pll_ctrl_2; 50 uint32 type_flag; 51 uint32 flag; 52}; 53 54static struct arm_pll arm_pll_table[] = { 55 { 600, 0x1003001, PLL_SUP_NS_ALL}, 56 { 800, 0x1004001, PLL_SUP_NS_ALL}, 57 { 1000, 0x1005001, PLL_SUP_4709 | PLL_SUP_47092 | PLL_SUP_47094}, 58 { 1200, 0x1006001, PLL_SUP_47094}, 59 { 1400, 0x1007001, PLL_SUP_47094}, 60 {0} 61}; 62 63static struct ddr_clk ddr_clock_pll_table[] = { 64 { 333, 0x17800000, 0x1e0f1219, PLL_SUP_DDR2 | PLL_SUP_DDR3, PLL_SUP_NS_ALL}, 65 { 389, 0x18c00000, 0x23121219, PLL_SUP_DDR2 | PLL_SUP_DDR3, PLL_SUP_NS_ALL}, 66 { 400, 0x18000000, 0x20101019, PLL_SUP_DDR2 | PLL_SUP_DDR3, PLL_SUP_NS_ALL}, 67 { 533, 0x18000000, 0x20100c19, PLL_SUP_DDR3, PLL_SUP_NS_ALL}, 68 { 666, 0x17800000, 0x1e0f0919, PLL_SUP_DDR3, PLL_SUP_4709 | PLL_SUP_47094}, 69 { 775, 0x17c00000, 0x20100819, PLL_SUP_DDR3, PLL_SUP_4709 | PLL_SUP_47094}, 70 { 800, 0x18000000, 0x20100819, PLL_SUP_DDR3, PLL_SUP_4709 | PLL_SUP_47094}, 71 {0} 72}; 73 74uint 75BCMINITFN(si_irq)(si_t *sih) 76{ 77 return 0; 78} 79 80/* 81 * Initializes clocks and interrupts. SB and NVRAM access must be 82 * initialized prior to calling. 83 */ 84void 85BCMATTACHFN(si_arm_init)(si_t *sih) 86{ 87 return; 88} 89 90uint32 91BCMINITFN(si_cpu_clock)(si_t *sih) 92{ 93 uint32 val; 94 osl_t *osh; 95 osh = si_osh(sih); 96 97 if (BCM4707_CHIP(CHIPID(sih->chip))) { 98 /* Return 100 MHz if we are in default value policy 2 */ 99 val = (uint32)R_REG(osh, (uint32 *)IHOST_PROC_CLK_POLICY_FREQ); 100 if ((val & 0x7070707) == 0x2020202) 101 return 100000000; 102 103 val = (uint32)R_REG(osh, (uint32 *)IHOST_PROC_CLK_PLLARMA); 104 val = (val >> 8) & 0x2ff; 105 val = (val * 25 * 1000000) / 2; 106 107 return val; 108 } 109 110 return si_clock(sih); 111} 112 113uint32 114BCMINITFN(si_mem_clock)(si_t *sih) 115{ 116 osl_t *osh; 117 uint idx; 118 chipcommonbregs_t *chipcb; 119 uint32 control1, control2, val; 120 121 osh = si_osh(sih); 122 123 if (BCM4707_CHIP(CHIPID(sih->chip))) { 124 chipcb = si_setcore(sih, NS_CCB_CORE_ID, 0); 125 if (chipcb) { 126 control1 = R_REG(osh, &chipcb->cru_lcpll_control1); 127 control2 = R_REG(osh, &chipcb->cru_lcpll_control2); 128 for (idx = 0; ddr_clock_pll_table[idx].clk != 0; idx++) { 129 if ((control1 == ddr_clock_pll_table[idx].pll_ctrl_1) && 130 (control2 == ddr_clock_pll_table[idx].pll_ctrl_2)) { 131 val = ddr_clock_pll_table[idx].clk; 132 return (val * 1000000); 133 } 134 } 135 } 136 137 } 138 139 return si_clock(sih); 140} 141 142bool 143BCMINITFN(si_arm_setclock)(si_t *sih, uint32 armclock, uint32 ddrclock, uint32 axiclock) 144{ 145 osl_t *osh; 146 uint32 val; 147 bool ret = TRUE; 148 int idx; 149 int bootdev; 150 uint32 *ddrclk; 151 osh = si_osh(sih); 152 153 if (BCM4707_CHIP(CHIPID(sih->chip))) { 154 uint32 platform_flag = 0, ddr_flag = 0; 155 void *regs = (void *)si_setcore(sih, NS_DDR23_CORE_ID, 0); 156 if (regs) { 157 ddr_flag = ((si_core_sflags(sih, 0, 0) & DDR_TYPE_MASK) 158 == DDR_STAT_DDR3)? PLL_SUP_DDR3 : PLL_SUP_DDR2; 159 } 160 161 switch (sih->chippkg) { 162 case BCM4708_PKG_ID: 163 if (CHIPID(sih->chip) == BCM47094_CHIP_ID) { 164 platform_flag = PLL_SUP_47092; 165 } else { 166 platform_flag = PLL_SUP_4708; 167 } 168 break; 169 case BCM4709_PKG_ID: 170 if (CHIPID(sih->chip) == BCM47094_CHIP_ID) { 171 platform_flag = PLL_SUP_47094; 172 } else { 173 platform_flag = PLL_SUP_4709; 174 } 175 break; 176 } 177 178 /* Check CPU CLK table */ 179 for (idx = 0; arm_pll_table[idx].clk != 0; idx++) { 180 if ((arm_pll_table[idx].flag & platform_flag) == 0) 181 arm_pll_table[idx].clk = 0; 182 } 183 184 /* Check DDR CLK table */ 185 for (idx = 0; ddr_clock_pll_table[idx].clk != 0; idx++) { 186 if ((ddr_clock_pll_table[idx].type_flag & ddr_flag) == 0 || 187 (ddr_clock_pll_table[idx].flag & platform_flag) == 0) { 188 ddr_clock_pll_table[idx].clk = 0; 189 break; 190 } 191 } 192 193 /* Check DDR clock */ 194 if (ddrclock && si_mem_clock(sih) != ddrclock) { 195 ddrclock /= 1000000; 196 for (idx = 0; ddr_clock_pll_table[idx].clk != 0; idx ++) { 197 if (ddrclock == ddr_clock_pll_table[idx].clk) 198 break; 199 } 200 if (ddr_clock_pll_table[idx].clk != 0) { 201 ddrclk = (uint32 *)(0x1000 + BISZ_OFFSET - 4); 202 *ddrclk = ddrclock; 203 bootdev = soc_boot_dev((void *)sih); 204 if (bootdev == SOC_BOOTDEV_NANDFLASH) { 205 __asm__ __volatile__("ldr\tpc,=0x1c000000\n\t"); 206 } else if (bootdev == SOC_BOOTDEV_SFLASH) { 207 __asm__ __volatile__("ldr\tpc,=0x1e000000\n\t"); 208 } 209 } 210 } 211 212 /* Set CPU clock */ 213 armclock /= 1000000; 214 215 /* The password */ 216 W_REG(osh, (uint32 *)IHOST_PROC_CLK_WR_ACCESS, 0xa5a501); 217 218 /* ndiv_int */ 219 for (idx = 0; arm_pll_table[idx].clk != 0; idx++) { 220 if (armclock <= arm_pll_table[idx].clk) 221 break; 222 } 223 if (arm_pll_table[idx].clk == 0) { 224 ret = FALSE; 225 goto done; 226 } 227 val = arm_pll_table[idx].reg_val; 228 W_REG(osh, (uint32 *)IHOST_PROC_CLK_PLLARMA, val); 229 230 do { 231 val = (uint32)R_REG(osh, (uint32 *)IHOST_PROC_CLK_PLLARMA); 232 if (val & (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK)) 233 break; 234 } while (1); 235 236 237 val |= (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_POST_RESETB); 238 W_REG(osh, (uint32 *)IHOST_PROC_CLK_PLLARMA, val); 239 240 W_REG(osh, (uint32 *)IHOST_PROC_CLK_POLICY_FREQ, 0x87070707); 241 W_REG(osh, (uint32 *)IHOST_PROC_CLK_CORE0_CLKGATE, 0x00010303); 242 W_REG(osh, (uint32 *)IHOST_PROC_CLK_CORE1_CLKGATE, 0x00000303); 243 W_REG(osh, (uint32 *)IHOST_PROC_CLK_ARM_SWITCH_CLKGATE, 0x00010303); 244 W_REG(osh, (uint32 *)IHOST_PROC_CLK_ARM_PERIPH_CLKGATE, 0x00010303); 245 W_REG(osh, (uint32 *)IHOST_PROC_CLK_APB0_CLKGATE, 0x00010303); 246 247 val = (1 << IHOST_PROC_CLK_POLICY_CTL__GO) | 248 (1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC); 249 W_REG(osh, (uint32 *)IHOST_PROC_CLK_POLICY_CTL, val); 250 251 do { 252 val = R_REG(osh, (uint32 *)IHOST_PROC_CLK_POLICY_CTL); 253 if ((val & (1 << IHOST_PROC_CLK_POLICY_CTL__GO)) == 0) 254 break; 255 } while (1); 256 } 257done: 258 return (ret); 259} 260 261void si_mem_setclock(si_t *sih, uint32 ddrclock) 262{ 263 osl_t *osh; 264 chipcommonbregs_t *chipcb; 265 uint32 val; 266 int idx; 267 268 for (idx = 0; ddr_clock_pll_table[idx].clk != 0; idx++) { 269 if (ddr_clock_pll_table[idx].clk == ddrclock) 270 break; 271 } 272 if (ddr_clock_pll_table[idx].clk == 0) 273 return; 274 275 osh = si_osh(sih); 276 chipcb = (chipcommonbregs_t *)si_setcore(sih, NS_CCB_CORE_ID, 0); 277 if (chipcb) { 278 val = 0xea68; 279 W_REG(osh, &chipcb->cru_clkset_key, val); 280 val = R_REG(osh, &chipcb->cru_lcpll_control1); 281 val &= ~0x0ff00000; 282 val |= (ddr_clock_pll_table[idx].pll_ctrl_1 & 0x0ff00000); 283 W_REG(osh, &chipcb->cru_lcpll_control1, val); 284 285 val = R_REG(osh, &chipcb->cru_lcpll_control2); 286 val &= ~0xffffff00; 287 val |= (ddr_clock_pll_table[idx].pll_ctrl_2 & 0xffffff00); 288 W_REG(osh, &chipcb->cru_lcpll_control2, val); 289 /* Enable change */ 290 val = R_REG(osh, &chipcb->cru_lcpll_control0); 291 val |= 0x7; 292 W_REG(osh, &chipcb->cru_lcpll_control0, val); 293 val &= ~0x7; 294 W_REG(osh, &chipcb->cru_lcpll_control0, val); 295 val = 0; 296 W_REG(osh, &chipcb->cru_clkset_key, val); 297 } 298} 299 300/* Start chipc watchdog timer and wait till reset */ 301void 302hnd_cpu_reset(si_t *sih) 303{ 304 si_watchdog(sih, 1); 305 while (1); 306} 307 308void 309hnd_cpu_jumpto(void *addr) 310{ 311 void (*jumpto)(void) = addr; 312 313 (jumpto)(); 314} 315