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