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