1/* 2 * BCM47XX support code for some chipcommon facilities (uart, jtagm) 3 * 4 * Copyright 2007, Broadcom Corporation 5 * All Rights Reserved. 6 * 7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY 8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM 9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS 10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. 11 * 12 * $Id: hndchipc.c,v 1.1.1.1 2008/10/15 03:31:34 james26_jang Exp $ 13 */ 14 15#include <typedefs.h> 16#include <bcmdefs.h> 17#include <osl.h> 18#include <bcmutils.h> 19#include <sbutils.h> 20#include <bcmdevs.h> 21#include <bcmnvram.h> 22#include <sbconfig.h> 23#include <sbchipc.h> 24#include <hndchipc.h> 25#include <hndcpu.h> 26 27/* debug/trace */ 28#define CC_ERROR(args) 29 30#define CC_MSG(args) 31 32/* interested chipcommon interrupt source 33 * - GPIO 34 * - EXTIF 35 * - ECI 36 * - PMU 37 * - UART 38 */ 39#define MAX_CC_INT_SOURCE 5 40 41/* chipc secondary isr info */ 42typedef struct { 43 uint intmask; /* int mask */ 44 cc_isr_fn isr; /* secondary isr handler */ 45 void *cbdata; /* pointer to private data */ 46} cc_isr_info_t; 47 48static cc_isr_info_t cc_isr_desc[MAX_CC_INT_SOURCE]; 49 50/* chip common intmask */ 51static uint32 cc_intmask = 0; 52 53/* 54 * Initializes UART access. The callback function will be called once 55 * per found UART. 56 */ 57void 58BCMINITFN(sb_serial_init)(sb_t *sbh, sb_serial_init_fn add) 59{ 60 osl_t *osh; 61 void *regs; 62 chipcregs_t *cc; 63 uint32 rev, cap, pll, baud_base, div; 64 uint irq; 65 int i, n; 66 67 osh = sb_osh(sbh); 68 69 cc = (chipcregs_t *)sb_setcore(sbh, SB_CC, 0); 70 ASSERT(cc); 71 72 /* Determine core revision and capabilities */ 73 rev = sbh->ccrev; 74 cap = sbh->cccaps; 75 pll = cap & CC_CAP_PLL_MASK; 76 77 /* Determine IRQ */ 78 irq = sb_irq(sbh); 79 80 if (pll == PLL_TYPE1) { 81 /* PLL clock */ 82 baud_base = sb_clock_rate(pll, 83 R_REG(osh, &cc->clockcontrol_n), 84 R_REG(osh, &cc->clockcontrol_m2)); 85 div = 1; 86 } else { 87 /* Fixed ALP clock */ 88 if (rev >= 11 && rev != 15) { 89 baud_base = sb_alp_clock(sbh); 90 div = 1; 91 /* Turn off UART clock before switching clock source */ 92 if (rev >= 21) 93 AND_REG(osh, &cc->corecontrol, ~CC_UARTCLKEN); 94 /* Set the override bit so we don't divide it */ 95 OR_REG(osh, &cc->corecontrol, CC_UARTCLKO); 96 if (rev >= 21) 97 OR_REG(osh, &cc->corecontrol, CC_UARTCLKEN); 98 } else if (rev >= 3) { 99 /* Internal backplane clock */ 100 baud_base = sb_clock(sbh); 101 div = 2; /* Minimum divisor */ 102 W_REG(osh, &cc->clkdiv, 103 ((R_REG(osh, &cc->clkdiv) & ~CLKD_UART) | div)); 104 } else { 105 /* Fixed internal backplane clock */ 106 baud_base = 88000000; 107 div = 48; 108 } 109 110 /* Clock source depends on strapping if UartClkOverride is unset */ 111 if ((rev > 0) && 112 ((R_REG(osh, &cc->corecontrol) & CC_UARTCLKO) == 0)) { 113 if ((cap & CC_CAP_UCLKSEL) == CC_CAP_UINTCLK) { 114 /* Internal divided backplane clock */ 115 baud_base /= div; 116 } else { 117 /* Assume external clock of 1.8432 MHz */ 118 baud_base = 1843200; 119 } 120 } 121 } 122 123 /* Add internal UARTs */ 124 n = cap & CC_CAP_UARTS_MASK; 125 for (i = 0; i < n; i++) { 126 /* Register offset changed after revision 0 */ 127 if (rev) 128 regs = (void *)((ulong) &cc->uart0data + (i * 256)); 129 else 130 regs = (void *)((ulong) &cc->uart0data + (i * 8)); 131 132 if (add) 133 add(regs, irq, baud_base, 0); 134 } 135} 136 137/* 138 * Initialize jtag master and return handle for 139 * jtag_rwreg. Returns NULL on failure. 140 */ 141void * 142sb_jtagm_init(sb_t *sbh, uint clkd, bool exttap) 143{ 144 void *regs; 145 146 if ((regs = sb_setcore(sbh, SB_CC, 0)) != NULL) { 147 chipcregs_t *cc = (chipcregs_t *) regs; 148 uint32 tmp; 149 150 /* 151 * Determine jtagm availability from 152 * core revision and capabilities. 153 */ 154 155 /* 156 * Corerev 10 has jtagm, but the only chip 157 * with it does not have a mips, and 158 * the layout of the jtagcmd register is 159 * different. We'll only accept >= 11. 160 */ 161 if (sbh->ccrev < 11) 162 return (NULL); 163 164 if ((sbh->cccaps & CC_CAP_JTAGP) == 0) 165 return (NULL); 166 167 /* Set clock divider if requested */ 168 if (clkd != 0) { 169 tmp = R_REG(osh, &cc->clkdiv); 170 tmp = (tmp & ~CLKD_JTAG) | 171 ((clkd << CLKD_JTAG_SHIFT) & CLKD_JTAG); 172 W_REG(osh, &cc->clkdiv, tmp); 173 } 174 175 /* Enable jtagm */ 176 tmp = JCTRL_EN | (exttap ? JCTRL_EXT_EN : 0); 177 W_REG(osh, &cc->jtagctrl, tmp); 178 } 179 180 return (regs); 181} 182 183void 184sb_jtagm_disable(osl_t *osh, void *h) 185{ 186 chipcregs_t *cc = (chipcregs_t *)h; 187 188 W_REG(osh, &cc->jtagctrl, R_REG(osh, &cc->jtagctrl) & ~JCTRL_EN); 189} 190 191/* 192 * Read/write a jtag register. Assumes a target with 193 * 8 bit IR and 32 bit DR. 194 */ 195#define IRWIDTH 8 /* Default Instruction Register width */ 196#define DRWIDTH 32 /* Default Data Register width */ 197 198uint32 199jtag_rwreg(osl_t *osh, void *h, uint32 ir, uint32 dr) 200{ 201 chipcregs_t *cc = (chipcregs_t *) h; 202 uint32 tmp; 203 204 W_REG(osh, &cc->jtagir, ir); 205 W_REG(osh, &cc->jtagdr, dr); 206 tmp = JCMD_START | JCMD_ACC_IRDR | 207 ((IRWIDTH - 1) << JCMD_IRW_SHIFT) | 208 (DRWIDTH - 1); 209 W_REG(osh, &cc->jtagcmd, tmp); 210 while (((tmp = R_REG(osh, &cc->jtagcmd)) & JCMD_BUSY) == JCMD_BUSY) { 211 /* OSL_DELAY(1); */ 212 } 213 214 tmp = R_REG(osh, &cc->jtagdr); 215 return (tmp); 216} 217 218 219/* 220 * Interface to register chipc secondary isr 221 */ 222 223bool 224BCMINITFN(sb_cc_register_isr)(sb_t *sbh, cc_isr_fn isr, uint32 ccintmask, void *cbdata) 225{ 226 bool done = FALSE; 227 chipcregs_t *regs; 228 uint origidx; 229 uint i; 230 231 /* Save the current core index */ 232 origidx = sb_coreidx(sbh); 233 regs = sb_setcore(sbh, SB_CC, 0); 234 ASSERT(regs); 235 236 for (i = 0; i < MAX_CC_INT_SOURCE; i++) { 237 if (cc_isr_desc[i].isr == NULL) { 238 cc_isr_desc[i].isr = isr; 239 cc_isr_desc[i].cbdata = cbdata; 240 cc_isr_desc[i].intmask = ccintmask; 241 done = TRUE; 242 break; 243 } 244 } 245 246 if (done) { 247 cc_intmask = R_REG(sb_osh(sbh), ®s->intmask); 248 cc_intmask |= ccintmask; 249 W_REG(sb_osh(sbh), ®s->intmask, cc_intmask); 250 } 251 252 /* restore original coreidx */ 253 sb_setcoreidx(sbh, origidx); 254 return done; 255} 256 257/* 258 * chipc primary interrupt handler 259 * 260 */ 261 262void 263sb_cc_isr(sb_t *sbh, chipcregs_t *regs) 264{ 265 uint32 ccintstatus; 266 uint32 intstatus; 267 uint32 i; 268 269 /* prior to rev 21 chipc interrupt means uart and gpio */ 270 if (sbh->ccrev >= 21) 271 ccintstatus = R_REG(sb_osh(sbh), ®s->intstatus) & cc_intmask; 272 else 273 ccintstatus = (CI_UART | CI_GPIO); 274 275 for (i = 0; i < MAX_CC_INT_SOURCE; i ++) { 276 if ((cc_isr_desc[i].isr != NULL) && 277 (intstatus = (cc_isr_desc[i].intmask & ccintstatus))) { 278 (cc_isr_desc[i].isr)(cc_isr_desc[i].cbdata, intstatus); 279 } 280 } 281} 282