2 * BCM47XX support code for some chipcommon facilities (uart, jtagm)
4 * Copyright (C) 2009, Broadcom Corporation
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.
12 * $Id: hndchipc.c,v 1.23 2008/03/28 19:30:38 Exp $
27 #define CC_ERROR(args)
31 /* interested chipcommon interrupt source
38 #define MAX_CC_INT_SOURCE 5
40 /* chipc secondary isr info */
42 uint intmask
; /* int mask */
43 cc_isr_fn isr
; /* secondary isr handler */
44 void *cbdata
; /* pointer to private data */
47 static cc_isr_info_t cc_isr_desc
[MAX_CC_INT_SOURCE
];
49 /* chip common intmask */
50 static uint32 cc_intmask
= 0;
53 * Initializes UART access. The callback function will be called once
57 BCMINITFN(si_serial_init
)(si_t
*sih
, si_serial_init_fn add
)
62 uint32 rev
, cap
, pll
, baud_base
, div
;
68 cc
= (chipcregs_t
*)si_setcoreidx(sih
, SI_CC_IDX
);
74 /* Determine core revision and capabilities */
77 pll
= cap
& CC_CAP_PLL_MASK
;
82 if (CCPLL_ENAB(sih
) && pll
== PLL_TYPE1
) {
84 baud_base
= si_clock_rate(pll
,
85 R_REG(osh
, &cc
->clockcontrol_n
),
86 R_REG(osh
, &cc
->clockcontrol_m2
));
89 /* 5354 chip common uart uses a constant clock
90 * frequency of 25MHz */
92 /* Set the override bit so we don't divide it */
93 W_REG(osh
, &cc
->corecontrol
, CC_UARTCLKO
);
95 } else if (rev
>= 11 && rev
!= 15) {
97 baud_base
= si_alp_clock(sih
);
99 /* Turn off UART clock before switching clock source */
101 AND_REG(osh
, &cc
->corecontrol
, ~CC_UARTCLKEN
);
102 /* Set the override bit so we don't divide it */
103 OR_REG(osh
, &cc
->corecontrol
, CC_UARTCLKO
);
105 OR_REG(osh
, &cc
->corecontrol
, CC_UARTCLKEN
);
106 } else if (rev
>= 3) {
107 /* Internal backplane clock */
108 baud_base
= si_clock(sih
);
109 div
= 2; /* Minimum divisor */
110 W_REG(osh
, &cc
->clkdiv
,
111 ((R_REG(osh
, &cc
->clkdiv
) & ~CLKD_UART
) | div
));
113 /* Fixed internal backplane clock */
114 baud_base
= 88000000;
118 /* Clock source depends on strapping if UartClkOverride is unset */
120 ((R_REG(osh
, &cc
->corecontrol
) & CC_UARTCLKO
) == 0)) {
121 if ((cap
& CC_CAP_UCLKSEL
) == CC_CAP_UINTCLK
) {
122 /* Internal divided backplane clock */
125 /* Assume external clock of 1.8432 MHz */
131 /* Add internal UARTs */
132 n
= cap
& CC_CAP_UARTS_MASK
;
133 for (i
= 0; i
< n
; i
++) {
134 /* Register offset changed after revision 0 */
136 regs
= (void *)((ulong
) &cc
->uart0data
+ (i
* 256));
138 regs
= (void *)((ulong
) &cc
->uart0data
+ (i
* 8));
141 add(regs
, irq
, baud_base
, 0);
146 * Initialize jtag master and return handle for
147 * jtag_rwreg. Returns NULL on failure.
150 hnd_jtagm_init(si_t
*sih
, uint clkd
, bool exttap
)
154 if ((regs
= si_setcoreidx(sih
, SI_CC_IDX
)) != NULL
) {
155 chipcregs_t
*cc
= (chipcregs_t
*) regs
;
159 * Determine jtagm availability from
160 * core revision and capabilities.
164 * Corerev 10 has jtagm, but the only chip
165 * with it does not have a mips, and
166 * the layout of the jtagcmd register is
167 * different. We'll only accept >= 11.
172 if ((sih
->cccaps
& CC_CAP_JTAGP
) == 0)
175 /* Set clock divider if requested */
177 tmp
= R_REG(osh
, &cc
->clkdiv
);
178 tmp
= (tmp
& ~CLKD_JTAG
) |
179 ((clkd
<< CLKD_JTAG_SHIFT
) & CLKD_JTAG
);
180 W_REG(osh
, &cc
->clkdiv
, tmp
);
184 tmp
= JCTRL_EN
| (exttap
? JCTRL_EXT_EN
: 0);
185 W_REG(osh
, &cc
->jtagctrl
, tmp
);
192 hnd_jtagm_disable(osl_t
*osh
, void *h
)
194 chipcregs_t
*cc
= (chipcregs_t
*)h
;
196 W_REG(osh
, &cc
->jtagctrl
, R_REG(osh
, &cc
->jtagctrl
) & ~JCTRL_EN
);
200 * Read/write a jtag register. Assumes a target with
201 * 8 bit IR and 32 bit DR.
203 #define IRWIDTH 8 /* Default Instruction Register width */
204 #define DRWIDTH 32 /* Default Data Register width */
207 jtag_rwreg(osl_t
*osh
, void *h
, uint32 ir
, uint32 dr
)
209 chipcregs_t
*cc
= (chipcregs_t
*) h
;
212 W_REG(osh
, &cc
->jtagir
, ir
);
213 W_REG(osh
, &cc
->jtagdr
, dr
);
214 tmp
= JCMD_START
| JCMD_ACC_IRDR
|
215 ((IRWIDTH
- 1) << JCMD_IRW_SHIFT
) |
217 W_REG(osh
, &cc
->jtagcmd
, tmp
);
218 while (((tmp
= R_REG(osh
, &cc
->jtagcmd
)) & JCMD_BUSY
) == JCMD_BUSY
) {
222 tmp
= R_REG(osh
, &cc
->jtagdr
);
228 * Interface to register chipc secondary isr
232 BCMINITFN(si_cc_register_isr
)(si_t
*sih
, cc_isr_fn isr
, uint32 ccintmask
, void *cbdata
)
239 /* Save the current core index */
240 origidx
= si_coreidx(sih
);
241 regs
= si_setcoreidx(sih
, SI_CC_IDX
);
244 for (i
= 0; i
< MAX_CC_INT_SOURCE
; i
++) {
245 if (cc_isr_desc
[i
].isr
== NULL
) {
246 cc_isr_desc
[i
].isr
= isr
;
247 cc_isr_desc
[i
].cbdata
= cbdata
;
248 cc_isr_desc
[i
].intmask
= ccintmask
;
255 cc_intmask
= R_REG(si_osh(sih
), ®s
->intmask
);
256 cc_intmask
|= ccintmask
;
257 W_REG(si_osh(sih
), ®s
->intmask
, cc_intmask
);
260 /* restore original coreidx */
261 si_setcoreidx(sih
, origidx
);
266 * chipc primary interrupt handler
271 si_cc_isr(si_t
*sih
, chipcregs_t
*regs
)
277 /* prior to rev 21 chipc interrupt means uart and gpio */
278 if (sih
->ccrev
>= 21)
279 ccintstatus
= R_REG(si_osh(sih
), ®s
->intstatus
) & cc_intmask
;
281 ccintstatus
= (CI_UART
| CI_GPIO
);
283 for (i
= 0; i
< MAX_CC_INT_SOURCE
; i
++) {
284 if ((cc_isr_desc
[i
].isr
!= NULL
) &&
285 (intstatus
= (cc_isr_desc
[i
].intmask
& ccintstatus
))) {
286 (cc_isr_desc
[i
].isr
)(cc_isr_desc
[i
].cbdata
, intstatus
);