1/*
2 * BCM47XX support code for some chipcommon facilities (uart, jtagm)
3 *
4 * Copyright 2007, Broadcom Corporation
5 * All Rights Reserved.
6 *
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.
11 *
12 * $Id: hndchipc.c,v 1.1.1.1 2008/10/15 03:31:34 james26_jang Exp $
13 */
14
15#include <typedefs.h>
16#include <bcmdefs.h>
17#include <osl.h>
18#include <bcmutils.h>
19#include <sbutils.h>
20#include <bcmdevs.h>
21#include <bcmnvram.h>
22#include <sbconfig.h>
23#include <sbchipc.h>
24#include <hndchipc.h>
25#include <hndcpu.h>
26
27/* debug/trace */
28#define	CC_ERROR(args)
29
30#define	CC_MSG(args)
31
32/* interested chipcommon interrupt source
33 *  - GPIO
34 *  - EXTIF
35 *  - ECI
36 *  - PMU
37 *  - UART
38 */
39#define	MAX_CC_INT_SOURCE 5
40
41/* chipc secondary isr info */
42typedef struct {
43	uint intmask;		/* int mask */
44	cc_isr_fn isr;		/* secondary isr handler */
45	void *cbdata;		/* pointer to private data */
46} cc_isr_info_t;
47
48static cc_isr_info_t cc_isr_desc[MAX_CC_INT_SOURCE];
49
50/* chip common intmask */
51static uint32 cc_intmask = 0;
52
53/*
54 * Initializes UART access. The callback function will be called once
55 * per found UART.
56 */
57void
58BCMINITFN(sb_serial_init)(sb_t *sbh, sb_serial_init_fn add)
59{
60	osl_t *osh;
61	void *regs;
62	chipcregs_t *cc;
63	uint32 rev, cap, pll, baud_base, div;
64	uint irq;
65	int i, n;
66
67	osh = sb_osh(sbh);
68
69	cc = (chipcregs_t *)sb_setcore(sbh, SB_CC, 0);
70	ASSERT(cc);
71
72	/* Determine core revision and capabilities */
73	rev = sbh->ccrev;
74	cap = sbh->cccaps;
75	pll = cap & CC_CAP_PLL_MASK;
76
77	/* Determine IRQ */
78	irq = sb_irq(sbh);
79
80	if (pll == PLL_TYPE1) {
81		/* PLL clock */
82		baud_base = sb_clock_rate(pll,
83		                          R_REG(osh, &cc->clockcontrol_n),
84		                          R_REG(osh, &cc->clockcontrol_m2));
85		div = 1;
86	} else {
87		/* Fixed ALP clock */
88		if (rev >= 11 && rev != 15) {
89			baud_base = sb_alp_clock(sbh);
90			div = 1;
91			/* Turn off UART clock before switching clock source */
92			if (rev >= 21)
93				AND_REG(osh, &cc->corecontrol, ~CC_UARTCLKEN);
94			/* Set the override bit so we don't divide it */
95			OR_REG(osh, &cc->corecontrol, CC_UARTCLKO);
96			if (rev >= 21)
97				OR_REG(osh, &cc->corecontrol, CC_UARTCLKEN);
98		} else if (rev >= 3) {
99			/* Internal backplane clock */
100			baud_base = sb_clock(sbh);
101			div = 2;	/* Minimum divisor */
102			W_REG(osh, &cc->clkdiv,
103			      ((R_REG(osh, &cc->clkdiv) & ~CLKD_UART) | div));
104		} else {
105			/* Fixed internal backplane clock */
106			baud_base = 88000000;
107			div = 48;
108		}
109
110		/* Clock source depends on strapping if UartClkOverride is unset */
111		if ((rev > 0) &&
112		    ((R_REG(osh, &cc->corecontrol) & CC_UARTCLKO) == 0)) {
113			if ((cap & CC_CAP_UCLKSEL) == CC_CAP_UINTCLK) {
114				/* Internal divided backplane clock */
115				baud_base /= div;
116			} else {
117				/* Assume external clock of 1.8432 MHz */
118				baud_base = 1843200;
119			}
120		}
121	}
122
123	/* Add internal UARTs */
124	n = cap & CC_CAP_UARTS_MASK;
125	for (i = 0; i < n; i++) {
126		/* Register offset changed after revision 0 */
127		if (rev)
128			regs = (void *)((ulong) &cc->uart0data + (i * 256));
129		else
130			regs = (void *)((ulong) &cc->uart0data + (i * 8));
131
132		if (add)
133			add(regs, irq, baud_base, 0);
134	}
135}
136
137/*
138 * Initialize jtag master and return handle for
139 * jtag_rwreg. Returns NULL on failure.
140 */
141void *
142sb_jtagm_init(sb_t *sbh, uint clkd, bool exttap)
143{
144	void *regs;
145
146	if ((regs = sb_setcore(sbh, SB_CC, 0)) != NULL) {
147		chipcregs_t *cc = (chipcregs_t *) regs;
148		uint32 tmp;
149
150		/*
151		 * Determine jtagm availability from
152		 * core revision and capabilities.
153		 */
154
155		/*
156		 * Corerev 10 has jtagm, but the only chip
157		 * with it does not have a mips, and
158		 * the layout of the jtagcmd register is
159		 * different. We'll only accept >= 11.
160		 */
161		if (sbh->ccrev < 11)
162			return (NULL);
163
164		if ((sbh->cccaps & CC_CAP_JTAGP) == 0)
165			return (NULL);
166
167		/* Set clock divider if requested */
168		if (clkd != 0) {
169			tmp = R_REG(osh, &cc->clkdiv);
170			tmp = (tmp & ~CLKD_JTAG) |
171				((clkd << CLKD_JTAG_SHIFT) & CLKD_JTAG);
172			W_REG(osh, &cc->clkdiv, tmp);
173		}
174
175		/* Enable jtagm */
176		tmp = JCTRL_EN | (exttap ? JCTRL_EXT_EN : 0);
177		W_REG(osh, &cc->jtagctrl, tmp);
178	}
179
180	return (regs);
181}
182
183void
184sb_jtagm_disable(osl_t *osh, void *h)
185{
186	chipcregs_t *cc = (chipcregs_t *)h;
187
188	W_REG(osh, &cc->jtagctrl, R_REG(osh, &cc->jtagctrl) & ~JCTRL_EN);
189}
190
191/*
192 * Read/write a jtag register. Assumes a target with
193 * 8 bit IR and 32 bit DR.
194 */
195#define	IRWIDTH		8	/* Default Instruction Register width */
196#define	DRWIDTH		32	/* Default Data Register width */
197
198uint32
199jtag_rwreg(osl_t *osh, void *h, uint32 ir, uint32 dr)
200{
201	chipcregs_t *cc = (chipcregs_t *) h;
202	uint32 tmp;
203
204	W_REG(osh, &cc->jtagir, ir);
205	W_REG(osh, &cc->jtagdr, dr);
206	tmp = JCMD_START | JCMD_ACC_IRDR |
207		((IRWIDTH - 1) << JCMD_IRW_SHIFT) |
208		(DRWIDTH - 1);
209	W_REG(osh, &cc->jtagcmd, tmp);
210	while (((tmp = R_REG(osh, &cc->jtagcmd)) & JCMD_BUSY) == JCMD_BUSY) {
211		/* OSL_DELAY(1); */
212	}
213
214	tmp = R_REG(osh, &cc->jtagdr);
215	return (tmp);
216}
217
218
219/*
220 * Interface to register chipc secondary isr
221 */
222
223bool
224BCMINITFN(sb_cc_register_isr)(sb_t *sbh, cc_isr_fn isr, uint32 ccintmask, void *cbdata)
225{
226	bool done = FALSE;
227	chipcregs_t *regs;
228	uint origidx;
229	uint i;
230
231	/* Save the current core index */
232	origidx = sb_coreidx(sbh);
233	regs = sb_setcore(sbh, SB_CC, 0);
234	ASSERT(regs);
235
236	for (i = 0; i < MAX_CC_INT_SOURCE; i++) {
237		if (cc_isr_desc[i].isr == NULL) {
238			cc_isr_desc[i].isr = isr;
239			cc_isr_desc[i].cbdata = cbdata;
240			cc_isr_desc[i].intmask = ccintmask;
241			done = TRUE;
242			break;
243		}
244	}
245
246	if (done) {
247		cc_intmask = R_REG(sb_osh(sbh), &regs->intmask);
248		cc_intmask |= ccintmask;
249		W_REG(sb_osh(sbh), &regs->intmask, cc_intmask);
250	}
251
252	/* restore original coreidx */
253	sb_setcoreidx(sbh, origidx);
254	return done;
255}
256
257/*
258 * chipc primary interrupt handler
259 *
260 */
261
262void
263sb_cc_isr(sb_t *sbh, chipcregs_t *regs)
264{
265	uint32 ccintstatus;
266	uint32 intstatus;
267	uint32 i;
268
269	/* prior to rev 21 chipc interrupt means uart and gpio */
270	if (sbh->ccrev >= 21)
271		ccintstatus = R_REG(sb_osh(sbh), &regs->intstatus) & cc_intmask;
272	else
273		ccintstatus = (CI_UART | CI_GPIO);
274
275	for (i = 0; i < MAX_CC_INT_SOURCE; i ++) {
276		if ((cc_isr_desc[i].isr != NULL) &&
277		    (intstatus = (cc_isr_desc[i].intmask & ccintstatus))) {
278			(cc_isr_desc[i].isr)(cc_isr_desc[i].cbdata, intstatus);
279		}
280	}
281}
282