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