convert brcm-2.4 to the new target structure
[openwrt/staging/yousong.git] / target / linux / brcm-2.4 / files / arch / mips / bcm947xx / hndchipc.c
1 /*
2 * BCM47XX support code for some chipcommon (old extif) facilities (uart)
3 *
4 * Copyright 2006, 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 2006/02/27 03:43:16 honor 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 <sbextif.h>
24 #include <sbchipc.h>
25 #include <hndcpu.h>
26
27 /*
28 * Returns TRUE if an external UART exists at the given base
29 * register.
30 */
31 static bool
32 BCMINITFN(serial_exists)(osl_t *osh, uint8 *regs)
33 {
34 uint8 save_mcr, status1;
35
36 save_mcr = R_REG(osh, &regs[UART_MCR]);
37 W_REG(osh, &regs[UART_MCR], UART_MCR_LOOP | 0x0a);
38 status1 = R_REG(osh, &regs[UART_MSR]) & 0xf0;
39 W_REG(osh, &regs[UART_MCR], save_mcr);
40
41 return (status1 == 0x90);
42 }
43
44 /*
45 * Initializes UART access. The callback function will be called once
46 * per found UART.
47 */
48 void
49 BCMINITFN(sb_serial_init)(sb_t *sbh, void (*add)(void *regs, uint irq, uint baud_base,
50 uint reg_shift))
51 {
52 osl_t *osh;
53 void *regs;
54 ulong base;
55 uint irq;
56 int i, n;
57
58 osh = sb_osh(sbh);
59
60 if ((regs = sb_setcore(sbh, SB_EXTIF, 0))) {
61 extifregs_t *eir = (extifregs_t *) regs;
62 sbconfig_t *sb;
63
64 /* Determine external UART register base */
65 sb = (sbconfig_t *)((ulong) eir + SBCONFIGOFF);
66 base = EXTIF_CFGIF_BASE(sb_base(R_REG(osh, &sb->sbadmatch1)));
67
68 /* Determine IRQ */
69 irq = sb_irq(sbh);
70
71 /* Disable GPIO interrupt initially */
72 W_REG(osh, &eir->gpiointpolarity, 0);
73 W_REG(osh, &eir->gpiointmask, 0);
74
75 /* Search for external UARTs */
76 n = 2;
77 for (i = 0; i < 2; i++) {
78 regs = (void *) REG_MAP(base + (i * 8), 8);
79 if (serial_exists(osh, regs)) {
80 /* Set GPIO 1 to be the external UART IRQ */
81 W_REG(osh, &eir->gpiointmask, 2);
82 /* XXXDetermine external UART clock */
83 if (add)
84 add(regs, irq, 13500000, 0);
85 }
86 }
87
88 /* Add internal UART if enabled */
89 if (R_REG(osh, &eir->corecontrol) & CC_UE)
90 if (add)
91 add((void *) &eir->uartdata, irq, sb_clock(sbh), 2);
92 } else if ((regs = sb_setcore(sbh, SB_CC, 0))) {
93 chipcregs_t *cc = (chipcregs_t *) regs;
94 uint32 rev, cap, pll, baud_base, div;
95
96 /* Determine core revision and capabilities */
97 rev = sb_corerev(sbh);
98 cap = R_REG(osh, &cc->capabilities);
99 pll = cap & CAP_PLL_MASK;
100
101 /* Determine IRQ */
102 irq = sb_irq(sbh);
103
104 if (pll == PLL_TYPE1) {
105 /* PLL clock */
106 baud_base = sb_clock_rate(pll,
107 R_REG(osh, &cc->clockcontrol_n),
108 R_REG(osh, &cc->clockcontrol_m2));
109 div = 1;
110 } else {
111 /* Fixed ALP clock */
112 if (rev >= 11 && rev != 15) {
113 baud_base = 20000000;
114 div = 1;
115 /* Set the override bit so we don't divide it */
116 W_REG(osh, &cc->corecontrol, CC_UARTCLKO);
117 }
118 /* Internal backplane clock */
119 else if (rev >= 3) {
120 baud_base = sb_clock(sbh);
121 div = 2; /* Minimum divisor */
122 W_REG(osh, &cc->clkdiv,
123 ((R_REG(osh, &cc->clkdiv) & ~CLKD_UART) | div));
124 }
125 /* Fixed internal backplane clock */
126 else {
127 baud_base = 88000000;
128 div = 48;
129 }
130
131 /* Clock source depends on strapping if UartClkOverride is unset */
132 if ((rev > 0) &&
133 ((R_REG(osh, &cc->corecontrol) & CC_UARTCLKO) == 0)) {
134 if ((cap & CAP_UCLKSEL) == CAP_UINTCLK) {
135 /* Internal divided backplane clock */
136 baud_base /= div;
137 } else {
138 /* Assume external clock of 1.8432 MHz */
139 baud_base = 1843200;
140 }
141 }
142 }
143
144 /* Add internal UARTs */
145 n = cap & CAP_UARTS_MASK;
146 for (i = 0; i < n; i++) {
147 /* Register offset changed after revision 0 */
148 if (rev)
149 regs = (void *)((ulong) &cc->uart0data + (i * 256));
150 else
151 regs = (void *)((ulong) &cc->uart0data + (i * 8));
152
153 if (add)
154 add(regs, irq, baud_base, 0);
155 }
156 }
157 }
158