1/* 2 * BCM47XX support code for some chipcommon facilities (uart, jtagm) 3 * 4 * Copyright (C) 2013, 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: hndchipc.c 401759 2013-05-13 16:08:08Z $ 19 */ 20 21#include <bcm_cfg.h> 22#include <typedefs.h> 23#include <bcmdefs.h> 24#include <osl.h> 25#include <bcmutils.h> 26#include <siutils.h> 27#include <bcmnvram.h> 28#include <hndsoc.h> 29#include <sbchipc.h> 30#include <hndchipc.h> 31#include <hndcpu.h> 32 33/* debug/trace */ 34#define CC_ERROR(args) 35 36#define CC_MSG(args) 37 38/* interested chipcommon interrupt source 39 * - GPIO 40 * - EXTIF 41 * - ECI 42 * - PMU 43 * - UART 44 */ 45#define MAX_CC_INT_SOURCE 5 46 47/* chipc secondary isr info */ 48typedef struct { 49 uint intmask; /* int mask */ 50 cc_isr_fn isr; /* secondary isr handler */ 51 void *cbdata; /* pointer to private data */ 52} cc_isr_info_t; 53 54static cc_isr_info_t cc_isr_desc[MAX_CC_INT_SOURCE]; 55 56/* chip common intmask */ 57static uint32 cc_intmask = 0; 58 59/* 60 * ROM accessor to avoid struct in shdat 61 */ 62static cc_isr_info_t * 63get_cc_isr_desc(void) 64{ 65 return cc_isr_desc; 66} 67 68/* 69 * Initializes UART access. The callback function will be called once 70 * per found UART. 71 */ 72void 73BCMATTACHFN(si_serial_init)(si_t *sih, si_serial_init_fn add) 74{ 75 osl_t *osh; 76 void *regs; 77 chipcregs_t *cc; 78 uint32 rev, cap, pll, baud_base, div; 79 uint irq; 80 int i, n; 81 82 osh = si_osh(sih); 83 84 cc = (chipcregs_t *)si_setcoreidx(sih, SI_CC_IDX); 85 ASSERT(cc); 86 87 /* Determine core revision and capabilities */ 88 rev = sih->ccrev; 89 cap = sih->cccaps; 90 pll = cap & CC_CAP_PLL_MASK; 91 92 /* Determine IRQ */ 93 irq = si_irq(sih); 94 95 if (CCPLL_ENAB(sih) && pll == PLL_TYPE1) { 96 /* PLL clock */ 97 baud_base = si_clock_rate(pll, 98 R_REG(osh, &cc->clockcontrol_n), 99 R_REG(osh, &cc->clockcontrol_m2)); 100 div = 1; 101 } else { 102 /* Fixed ALP clock */ 103 if (rev >= 11 && rev != 15) { 104 baud_base = si_alp_clock(sih); 105 div = 1; 106 /* Turn off UART clock before switching clock source */ 107 if (rev >= 21) 108 AND_REG(osh, &cc->corecontrol, ~CC_UARTCLKEN); 109 /* Set the override bit so we don't divide it */ 110 OR_REG(osh, &cc->corecontrol, CC_UARTCLKO); 111 if (rev >= 21) 112 OR_REG(osh, &cc->corecontrol, CC_UARTCLKEN); 113 } else if (rev >= 3) { 114 /* Internal backplane clock */ 115 baud_base = si_clock(sih); 116 div = 2; /* Minimum divisor */ 117 W_REG(osh, &cc->clkdiv, 118 ((R_REG(osh, &cc->clkdiv) & ~CLKD_UART) | div)); 119 } else { 120 /* Fixed internal backplane clock */ 121 baud_base = 88000000; 122 div = 48; 123 } 124 125 /* Clock source depends on strapping if UartClkOverride is unset */ 126 if ((R_REG(osh, &cc->corecontrol) & CC_UARTCLKO) == 0) { 127 if ((cap & CC_CAP_UCLKSEL) == CC_CAP_UINTCLK) { 128 /* Internal divided backplane clock */ 129 baud_base /= div; 130 } else { 131 /* Assume external clock of 1.8432 MHz */ 132 baud_base = 1843200; 133 } 134 } 135 } 136 137 /* Add internal UARTs */ 138 n = cap & CC_CAP_UARTS_MASK; 139 for (i = 0; i < n; i++) { 140 regs = (void *)((ulong) &cc->uart0data + (i * 256)); 141 if (add) 142 add(regs, irq, baud_base, 0); 143 } 144} 145 146#define JTAG_RETRIES 10000 147 148/* 149 * Initialize jtag master and return handle for 150 * jtag_rwreg. Returns NULL on failure. 151 */ 152void * 153hnd_jtagm_init(si_t *sih, uint clkd, bool exttap) 154{ 155 void *regs; 156 157 if ((regs = si_setcoreidx(sih, SI_CC_IDX)) != NULL) { 158 chipcregs_t *cc = (chipcregs_t *) regs; 159 uint32 tmp; 160 161 /* 162 * Determine jtagm availability from 163 * core revision and capabilities. 164 */ 165 166 /* 167 * Corerev 10 has jtagm, but the only chip 168 * with it does not have a mips, and 169 * the layout of the jtagcmd register is 170 * different. We'll only accept >= 11. 171 */ 172 if (sih->ccrev < 11) 173 return (NULL); 174 175 if ((sih->cccaps & CC_CAP_JTAGP) == 0) 176 return (NULL); 177 178 /* Set clock divider if requested */ 179 if (clkd != 0) { 180 tmp = R_REG(NULL, &cc->clkdiv); 181 tmp = (tmp & ~CLKD_JTAG) | 182 ((clkd << CLKD_JTAG_SHIFT) & CLKD_JTAG); 183 W_REG(NULL, &cc->clkdiv, tmp); 184 } 185 186 /* Enable jtagm */ 187 tmp = JCTRL_EN | (exttap ? JCTRL_EXT_EN : 0); 188 W_REG(NULL, &cc->jtagctrl, tmp); 189 } 190 191 return (regs); 192} 193 194void 195hnd_jtagm_disable(si_t *sih, void *h) 196{ 197 chipcregs_t *cc = (chipcregs_t *)h; 198 199 W_REG(NULL, &cc->jtagctrl, R_REG(NULL, &cc->jtagctrl) & ~JCTRL_EN); 200} 201 202 203static uint32 204jtm_wait(chipcregs_t *cc, bool readdr) 205{ 206 uint i; 207 208 i = 0; 209 while (((R_REG(NULL, &cc->jtagcmd) & JCMD_BUSY) == JCMD_BUSY) && 210 (i < JTAG_RETRIES)) { 211 i++; 212 } 213 214 if (i >= JTAG_RETRIES) 215 return 0xbadbad03; 216 217 if (readdr) 218 return R_REG(NULL, &cc->jtagdr); 219 else 220 return 0xffffffff; 221} 222 223/* Read/write a jtag register. Assumes both ir and dr <= 64bits. */ 224 225uint32 226jtag_scan(si_t *sih, void *h, uint irsz, uint32 ir0, uint32 ir1, 227 uint drsz, uint32 dr0, uint32 *dr1, bool rti) 228{ 229 chipcregs_t *cc = (chipcregs_t *) h; 230 uint32 acc_dr, acc_irdr; 231 uint32 tmp; 232 233 if ((irsz > 64) || (drsz > 64)) { 234 return 0xbadbad00; 235 } 236 if (rti) { 237 if (sih->ccrev < 28) 238 return 0xbadbad01; 239 acc_irdr = JCMD_ACC_IRDR_I; 240 acc_dr = JCMD_ACC_DR_I; 241 } else { 242 acc_irdr = JCMD_ACC_IRDR; 243 acc_dr = JCMD_ACC_DR; 244 } 245 if (irsz == 0) { 246 /* scan in the first (or only) DR word with a dr-only command */ 247 W_REG(NULL, &cc->jtagdr, dr0); 248 if (drsz > 32) { 249 W_REG(NULL, &cc->jtagcmd, JCMD_START | JCMD_ACC_PDR | 31); 250 drsz -= 32; 251 } else 252 W_REG(NULL, &cc->jtagcmd, JCMD_START | acc_dr | (drsz - 1)); 253 } else { 254 W_REG(NULL, &cc->jtagir, ir0); 255 if (irsz > 32) { 256 /* Use Partial IR for first IR word */ 257 W_REG(NULL, &cc->jtagcmd, JCMD_START | JCMD_ACC_PIR | 258 (31 << JCMD_IRW_SHIFT)); 259 jtm_wait(cc, FALSE); 260 W_REG(NULL, &cc->jtagir, ir1); 261 irsz -= 32; 262 } 263 if (drsz == 0) { 264 /* If drsz is 0, do an IR-only scan and that's it */ 265 W_REG(NULL, &cc->jtagcmd, JCMD_START | JCMD_ACC_IR | 266 ((irsz - 1) << JCMD_IRW_SHIFT)); 267 return jtm_wait(cc, FALSE); 268 } 269 /* Now scan in the IR word and the first (or only) DR word */ 270 W_REG(NULL, &cc->jtagdr, dr0); 271 if (drsz <= 32) 272 W_REG(NULL, &cc->jtagcmd, JCMD_START | acc_irdr | 273 ((irsz - 1) << JCMD_IRW_SHIFT) | (drsz - 1)); 274 else 275 W_REG(NULL, &cc->jtagcmd, JCMD_START | JCMD_ACC_IRPDR | 276 ((irsz - 1) << JCMD_IRW_SHIFT) | 31); 277 } 278 /* Now scan out the DR and scan in & out the second DR word if needed */ 279 tmp = jtm_wait(cc, TRUE); 280 if (drsz > 32) { 281 if (dr1 == NULL) 282 return 0xbadbad04; 283 W_REG(NULL, &cc->jtagdr, *dr1); 284 W_REG(NULL, &cc->jtagcmd, JCMD_START | acc_dr | (drsz - 33)); 285 *dr1 = jtm_wait(cc, TRUE); 286 } 287 return (tmp); 288} 289 290 291/* 292 * Interface to register chipc secondary isr 293 */ 294 295bool 296BCMATTACHFN(si_cc_register_isr)(si_t *sih, cc_isr_fn isr, uint32 ccintmask, void *cbdata) 297{ 298 bool done = FALSE; 299 chipcregs_t *regs; 300 uint origidx; 301 uint i; 302 303 /* Save the current core index */ 304 origidx = si_coreidx(sih); 305 regs = si_setcoreidx(sih, SI_CC_IDX); 306 ASSERT(regs); 307 308 for (i = 0; i < MAX_CC_INT_SOURCE; i++) { 309 if (cc_isr_desc[i].isr == NULL) { 310 cc_isr_desc[i].isr = isr; 311 cc_isr_desc[i].cbdata = cbdata; 312 cc_isr_desc[i].intmask = ccintmask; 313 done = TRUE; 314 break; 315 } 316 } 317 318 if (done) { 319 cc_intmask = R_REG(si_osh(sih), ®s->intmask); 320 cc_intmask |= ccintmask; 321 W_REG(si_osh(sih), ®s->intmask, cc_intmask); 322 } 323 324 /* restore original coreidx */ 325 si_setcoreidx(sih, origidx); 326 return done; 327} 328 329/* 330 * chipc primary interrupt handler 331 * 332 */ 333 334void 335si_cc_isr(si_t *sih, chipcregs_t *regs) 336{ 337 uint32 ccintstatus; 338 uint32 intstatus; 339 uint32 i; 340 cc_isr_info_t *desc; 341 342 /* prior to rev 21 chipc interrupt means uart and gpio */ 343 if (sih->ccrev >= 21) 344 ccintstatus = R_REG(si_osh(sih), ®s->intstatus) & cc_intmask; 345 else 346 ccintstatus = (CI_UART | CI_GPIO); 347 348 desc = get_cc_isr_desc(); 349 ASSERT(desc); 350 for (i = 0; i < MAX_CC_INT_SOURCE; i++, desc++) { 351 if ((desc->isr != NULL) && 352 (intstatus = (desc->intmask & ccintstatus))) { 353 (desc->isr)(desc->cbdata, intstatus); 354 } 355 } 356} 357