2 * BCM47XX support code for some chipcommon facilities (uart, jtagm)
4 * Copyright (C) 2010, Broadcom Corporation. All Rights Reserved.
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.
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.
18 * $Id: hndchipc.c,v 1.26 2010-01-05 19:11:24 Exp $
34 #define CC_ERROR(args) printf args
36 #define CC_ERROR(args)
37 #endif /* BCMDBG_ERR */
40 #define CC_MSG(args) printf args
45 /* interested chipcommon interrupt source
52 #define MAX_CC_INT_SOURCE 5
54 /* chipc secondary isr info */
56 uint intmask
; /* int mask */
57 cc_isr_fn isr
; /* secondary isr handler */
58 void *cbdata
; /* pointer to private data */
61 static cc_isr_info_t cc_isr_desc
[MAX_CC_INT_SOURCE
];
63 /* chip common intmask */
64 static uint32 cc_intmask
= 0;
67 * Initializes UART access. The callback function will be called once
71 BCMATTACHFN(si_serial_init
)(si_t
*sih
, si_serial_init_fn add
)
76 uint32 rev
, cap
, pll
, baud_base
, div
;
82 cc
= (chipcregs_t
*)si_setcoreidx(sih
, SI_CC_IDX
);
88 /* Determine core revision and capabilities */
91 pll
= cap
& CC_CAP_PLL_MASK
;
96 if (CCPLL_ENAB(sih
) && pll
== PLL_TYPE1
) {
98 baud_base
= si_clock_rate(pll
,
99 R_REG(osh
, &cc
->clockcontrol_n
),
100 R_REG(osh
, &cc
->clockcontrol_m2
));
103 /* 5354 chip common uart uses a constant clock
104 * frequency of 25MHz */
106 /* Set the override bit so we don't divide it */
107 W_REG(osh
, &cc
->corecontrol
, CC_UARTCLKO
);
108 baud_base
= 25000000;
109 } else if (rev
>= 11 && rev
!= 15) {
110 /* Fixed ALP clock */
111 baud_base
= si_alp_clock(sih
);
113 /* Turn off UART clock before switching clock source */
115 AND_REG(osh
, &cc
->corecontrol
, ~CC_UARTCLKEN
);
116 /* Set the override bit so we don't divide it */
117 OR_REG(osh
, &cc
->corecontrol
, CC_UARTCLKO
);
119 OR_REG(osh
, &cc
->corecontrol
, CC_UARTCLKEN
);
120 } else if (rev
>= 3) {
121 /* Internal backplane clock */
122 baud_base
= si_clock(sih
);
123 div
= 2; /* Minimum divisor */
124 W_REG(osh
, &cc
->clkdiv
,
125 ((R_REG(osh
, &cc
->clkdiv
) & ~CLKD_UART
) | div
));
127 /* Fixed internal backplane clock */
128 baud_base
= 88000000;
132 /* Clock source depends on strapping if UartClkOverride is unset */
133 if ((R_REG(osh
, &cc
->corecontrol
) & CC_UARTCLKO
) == 0) {
134 if ((cap
& CC_CAP_UCLKSEL
) == CC_CAP_UINTCLK
) {
135 /* Internal divided backplane clock */
138 /* Assume external clock of 1.8432 MHz */
144 /* Add internal UARTs */
145 n
= cap
& CC_CAP_UARTS_MASK
;
146 for (i
= 0; i
< n
; i
++) {
147 regs
= (void *)((ulong
) &cc
->uart0data
+ (i
* 256));
149 add(regs
, irq
, baud_base
, 0);
153 #define JTAG_RETRIES 10000
156 * Initialize jtag master and return handle for
157 * jtag_rwreg. Returns NULL on failure.
160 hnd_jtagm_init(si_t
*sih
, uint clkd
, bool exttap
)
164 if ((regs
= si_setcoreidx(sih
, SI_CC_IDX
)) != NULL
) {
165 chipcregs_t
*cc
= (chipcregs_t
*) regs
;
169 * Determine jtagm availability from
170 * core revision and capabilities.
174 * Corerev 10 has jtagm, but the only chip
175 * with it does not have a mips, and
176 * the layout of the jtagcmd register is
177 * different. We'll only accept >= 11.
182 if ((sih
->cccaps
& CC_CAP_JTAGP
) == 0)
185 /* Set clock divider if requested */
187 tmp
= R_REG(NULL
, &cc
->clkdiv
);
188 tmp
= (tmp
& ~CLKD_JTAG
) |
189 ((clkd
<< CLKD_JTAG_SHIFT
) & CLKD_JTAG
);
190 W_REG(NULL
, &cc
->clkdiv
, tmp
);
194 tmp
= JCTRL_EN
| (exttap
? JCTRL_EXT_EN
: 0);
195 W_REG(NULL
, &cc
->jtagctrl
, tmp
);
202 hnd_jtagm_disable(si_t
*sih
, void *h
)
204 chipcregs_t
*cc
= (chipcregs_t
*)h
;
206 W_REG(NULL
, &cc
->jtagctrl
, R_REG(NULL
, &cc
->jtagctrl
) & ~JCTRL_EN
);
211 jtm_wait(chipcregs_t
*cc
, bool readdr
)
216 while (((R_REG(NULL
, &cc
->jtagcmd
) & JCMD_BUSY
) == JCMD_BUSY
) &&
217 (i
< JTAG_RETRIES
)) {
221 if (i
>= JTAG_RETRIES
)
225 return R_REG(NULL
, &cc
->jtagdr
);
230 /* Read/write a jtag register. Assumes both ir and dr <= 64bits. */
233 jtag_scan(si_t
*sih
, void *h
, uint irsz
, uint32 ir0
, uint32 ir1
,
234 uint drsz
, uint32 dr0
, uint32
*dr1
, bool rti
)
236 chipcregs_t
*cc
= (chipcregs_t
*) h
;
237 uint32 acc_dr
, acc_irdr
;
240 if ((irsz
> 64) || (drsz
> 64)) {
246 acc_irdr
= JCMD_ACC_IRDR_I
;
247 acc_dr
= JCMD_ACC_DR_I
;
249 acc_irdr
= JCMD_ACC_IRDR
;
250 acc_dr
= JCMD_ACC_DR
;
253 /* scan in the first (or only) DR word with a dr-only command */
254 W_REG(NULL
, &cc
->jtagdr
, dr0
);
256 W_REG(NULL
, &cc
->jtagcmd
, JCMD_START
| JCMD_ACC_PDR
| 31);
259 W_REG(NULL
, &cc
->jtagcmd
, JCMD_START
| acc_dr
| (drsz
- 1));
261 W_REG(NULL
, &cc
->jtagir
, ir0
);
263 /* Use Partial IR for first IR word */
264 W_REG(NULL
, &cc
->jtagcmd
, JCMD_START
| JCMD_ACC_PIR
|
265 (31 << JCMD_IRW_SHIFT
));
267 W_REG(NULL
, &cc
->jtagir
, ir1
);
271 /* If drsz is 0, do an IR-only scan and that's it */
272 W_REG(NULL
, &cc
->jtagcmd
, JCMD_START
| JCMD_ACC_IR
|
273 ((irsz
- 1) << JCMD_IRW_SHIFT
));
274 return jtm_wait(cc
, FALSE
);
276 /* Now scan in the IR word and the first (or only) DR word */
277 W_REG(NULL
, &cc
->jtagdr
, dr0
);
279 W_REG(NULL
, &cc
->jtagcmd
, JCMD_START
| acc_irdr
|
280 ((irsz
- 1) << JCMD_IRW_SHIFT
) | (drsz
- 1));
282 W_REG(NULL
, &cc
->jtagcmd
, JCMD_START
| JCMD_ACC_IRPDR
|
283 ((irsz
- 1) << JCMD_IRW_SHIFT
) | 31);
285 /* Now scan out the DR and scan in & out the second DR word if needed */
286 tmp
= jtm_wait(cc
, TRUE
);
290 W_REG(NULL
, &cc
->jtagdr
, *dr1
);
291 W_REG(NULL
, &cc
->jtagcmd
, JCMD_START
| acc_dr
| (drsz
- 33));
292 *dr1
= jtm_wait(cc
, TRUE
);
299 * Interface to register chipc secondary isr
303 BCMATTACHFN(si_cc_register_isr
)(si_t
*sih
, cc_isr_fn isr
, uint32 ccintmask
, void *cbdata
)
310 /* Save the current core index */
311 origidx
= si_coreidx(sih
);
312 regs
= si_setcoreidx(sih
, SI_CC_IDX
);
315 for (i
= 0; i
< MAX_CC_INT_SOURCE
; i
++) {
316 if (cc_isr_desc
[i
].isr
== NULL
) {
317 cc_isr_desc
[i
].isr
= isr
;
318 cc_isr_desc
[i
].cbdata
= cbdata
;
319 cc_isr_desc
[i
].intmask
= ccintmask
;
326 cc_intmask
= R_REG(si_osh(sih
), ®s
->intmask
);
327 cc_intmask
|= ccintmask
;
328 W_REG(si_osh(sih
), ®s
->intmask
, cc_intmask
);
331 /* restore original coreidx */
332 si_setcoreidx(sih
, origidx
);
337 * chipc primary interrupt handler
342 si_cc_isr(si_t
*sih
, chipcregs_t
*regs
)
348 /* prior to rev 21 chipc interrupt means uart and gpio */
349 if (sih
->ccrev
>= 21)
350 ccintstatus
= R_REG(si_osh(sih
), ®s
->intstatus
) & cc_intmask
;
352 ccintstatus
= (CI_UART
| CI_GPIO
);
354 for (i
= 0; i
< MAX_CC_INT_SOURCE
; i
++) {
355 if ((cc_isr_desc
[i
].isr
!= NULL
) &&
356 (intstatus
= (cc_isr_desc
[i
].intmask
& ccintstatus
))) {
357 (cc_isr_desc
[i
].isr
)(cc_isr_desc
[i
].cbdata
, intstatus
);