2 * BCM47XX support code for some chipcommon facilities (uart, jtagm)
4 * Copyright (C) 2013, 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 401759 2013-05-13 16:08:08Z $
35 #define CC_ERROR(args) printf args
37 #define CC_ERROR(args)
38 #endif /* BCMDBG_ERR */
41 #define CC_MSG(args) printf args
46 /* interested chipcommon interrupt source
53 #define MAX_CC_INT_SOURCE 5
55 /* chipc secondary isr info */
57 uint intmask
; /* int mask */
58 cc_isr_fn isr
; /* secondary isr handler */
59 void *cbdata
; /* pointer to private data */
62 static cc_isr_info_t cc_isr_desc
[MAX_CC_INT_SOURCE
];
64 /* chip common intmask */
65 static uint32 cc_intmask
= 0;
68 * ROM accessor to avoid struct in shdat
70 static cc_isr_info_t
*
77 * Initializes UART access. The callback function will be called once
81 BCMATTACHFN(si_serial_init
)(si_t
*sih
, si_serial_init_fn add
)
86 uint32 rev
, cap
, pll
, baud_base
, div
;
92 cc
= (chipcregs_t
*)si_setcoreidx(sih
, SI_CC_IDX
);
95 /* Determine core revision and capabilities */
98 pll
= cap
& CC_CAP_PLL_MASK
;
103 if (CCPLL_ENAB(sih
) && pll
== PLL_TYPE1
) {
105 baud_base
= si_clock_rate(pll
,
106 R_REG(osh
, &cc
->clockcontrol_n
),
107 R_REG(osh
, &cc
->clockcontrol_m2
));
110 /* Fixed ALP clock */
111 if (rev
>= 11 && rev
!= 15) {
112 baud_base
= si_alp_clock(sih
);
114 /* Turn off UART clock before switching clock source */
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
);
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
));
128 /* Fixed internal backplane clock */
129 baud_base
= 88000000;
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 */
139 /* Assume external clock of 1.8432 MHz */
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));
150 add(regs
, irq
, baud_base
, 0);
154 #define JTAG_RETRIES 10000
157 * Initialize jtag master and return handle for
158 * jtag_rwreg. Returns NULL on failure.
161 hnd_jtagm_init(si_t
*sih
, uint clkd
, bool exttap
)
165 if ((regs
= si_setcoreidx(sih
, SI_CC_IDX
)) != NULL
) {
166 chipcregs_t
*cc
= (chipcregs_t
*) regs
;
170 * Determine jtagm availability from
171 * core revision and capabilities.
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.
183 if ((sih
->cccaps
& CC_CAP_JTAGP
) == 0)
186 /* Set clock divider if requested */
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
);
195 tmp
= JCTRL_EN
| (exttap
? JCTRL_EXT_EN
: 0);
196 W_REG(NULL
, &cc
->jtagctrl
, tmp
);
203 hnd_jtagm_disable(si_t
*sih
, void *h
)
205 chipcregs_t
*cc
= (chipcregs_t
*)h
;
207 W_REG(NULL
, &cc
->jtagctrl
, R_REG(NULL
, &cc
->jtagctrl
) & ~JCTRL_EN
);
212 jtm_wait(chipcregs_t
*cc
, bool readdr
)
217 while (((R_REG(NULL
, &cc
->jtagcmd
) & JCMD_BUSY
) == JCMD_BUSY
) &&
218 (i
< JTAG_RETRIES
)) {
222 if (i
>= JTAG_RETRIES
)
226 return R_REG(NULL
, &cc
->jtagdr
);
231 /* Read/write a jtag register. Assumes both ir and dr <= 64bits. */
234 jtag_scan(si_t
*sih
, void *h
, uint irsz
, uint32 ir0
, uint32 ir1
,
235 uint drsz
, uint32 dr0
, uint32
*dr1
, bool rti
)
237 chipcregs_t
*cc
= (chipcregs_t
*) h
;
238 uint32 acc_dr
, acc_irdr
;
241 if ((irsz
> 64) || (drsz
> 64)) {
247 acc_irdr
= JCMD_ACC_IRDR_I
;
248 acc_dr
= JCMD_ACC_DR_I
;
250 acc_irdr
= JCMD_ACC_IRDR
;
251 acc_dr
= JCMD_ACC_DR
;
254 /* scan in the first (or only) DR word with a dr-only command */
255 W_REG(NULL
, &cc
->jtagdr
, dr0
);
257 W_REG(NULL
, &cc
->jtagcmd
, JCMD_START
| JCMD_ACC_PDR
| 31);
260 W_REG(NULL
, &cc
->jtagcmd
, JCMD_START
| acc_dr
| (drsz
- 1));
262 W_REG(NULL
, &cc
->jtagir
, ir0
);
264 /* Use Partial IR for first IR word */
265 W_REG(NULL
, &cc
->jtagcmd
, JCMD_START
| JCMD_ACC_PIR
|
266 (31 << JCMD_IRW_SHIFT
));
268 W_REG(NULL
, &cc
->jtagir
, ir1
);
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
);
277 /* Now scan in the IR word and the first (or only) DR word */
278 W_REG(NULL
, &cc
->jtagdr
, dr0
);
280 W_REG(NULL
, &cc
->jtagcmd
, JCMD_START
| acc_irdr
|
281 ((irsz
- 1) << JCMD_IRW_SHIFT
) | (drsz
- 1));
283 W_REG(NULL
, &cc
->jtagcmd
, JCMD_START
| JCMD_ACC_IRPDR
|
284 ((irsz
- 1) << JCMD_IRW_SHIFT
) | 31);
286 /* Now scan out the DR and scan in & out the second DR word if needed */
287 tmp
= jtm_wait(cc
, TRUE
);
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
);
300 * Interface to register chipc secondary isr
304 BCMATTACHFN(si_cc_register_isr
)(si_t
*sih
, cc_isr_fn isr
, uint32 ccintmask
, void *cbdata
)
311 /* Save the current core index */
312 origidx
= si_coreidx(sih
);
313 regs
= si_setcoreidx(sih
, SI_CC_IDX
);
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
;
327 cc_intmask
= R_REG(si_osh(sih
), ®s
->intmask
);
328 cc_intmask
|= ccintmask
;
329 W_REG(si_osh(sih
), ®s
->intmask
, cc_intmask
);
332 /* restore original coreidx */
333 si_setcoreidx(sih
, origidx
);
338 * chipc primary interrupt handler
343 si_cc_isr(si_t
*sih
, chipcregs_t
*regs
)
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
;
354 ccintstatus
= (CI_UART
| CI_GPIO
);
356 desc
= get_cc_isr_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
);