1 /* $NetBSD: kirkwood.c,v 1.11 2021/08/30 00:04:30 rin Exp $ */
2 /*
3 * Copyright (c) 2010 KIYOHARA Takashi
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: kirkwood.c,v 1.11 2021/08/30 00:04:30 rin Exp $");
30
31 #define _INTR_PRIVATE
32
33 #include "mvsocgpp.h"
34
35 #include <sys/param.h>
36 #include <sys/bus.h>
37
38 #include <machine/intr.h>
39
40 #include <arm/pic/picvar.h>
41 #include <arm/pic/picvar.h>
42
43 #include <arm/marvell/mvsocreg.h>
44 #include <arm/marvell/mvsocvar.h>
45 #include <arm/marvell/kirkwoodreg.h>
46
47 #include <dev/marvell/marvellreg.h>
48
49
50 static void kirkwood_intr_init(void);
51
52 static void kirkwood_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
53 static void kirkwood_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
54 static void kirkwood_pic_establish_irq(struct pic_softc *, struct intrsource *);
55 static void kirkwood_pic_source_name(struct pic_softc *, int, char *, size_t);
56
57 static int kirkwood_find_pending_irqs(void);
58
59 static void kirkwood_getclks(vaddr_t);
60 static int kirkwood_clkgating(struct marvell_attach_args *);
61
62 static const char * const sources[64] = {
63 "MainHighSum(0)", "Bridge(1)", "Host2CPU DB(2)", "CPU2Host DB(3)",
64 "Reserved_4(4)", "Xor0Chan0(5)", "Xor0Chan1(6)", "Xor1Chan0(7)",
65 "Xor1Chan1(8)", "PEX0INT(9)", "Reserved(10)", "GbE0Sum(11)",
66 "GbE0Rx(12)", "GbE0Tx(13)", "GbE0Misc(14)", "GbE1Sum(15)",
67 "GbE1Rx(16)", "GbE1Tx(17)", "GbE1Misc(18)", "USB0Cnt(19)",
68 "Reserved(20)", "Sata(21)", "SecurityInt(22)", "SPIInt(23)",
69 "AudioINT(24)", "Reserved(25)", "TS0Int(26)", "Reserved(27)",
70 "SDIOInt(28)", "TWSI(29)", "AVBInt(30)", "TDMInt(31)",
71
72 "Reserved(32)", "Uart0Int(33)", "Uart1Int(34)", "GPIOLo7_0(35)",
73 "GPIOLo8_15(36)", "GPIOLo16_23(37)", "GPIOLo24_31(38)", "GPIOHi7_0(39)",
74 "GPIOHi8_15(40)", "GPIOHi16_23(41)", "XOR0Err(42)", "XOR1Err(43)",
75 "PEX0Err(44)", "Reserved(45)", "GbE0Err(46)", "GbE1Err(47)",
76 "USBErr(48)", "SecurityErr(49)", "AudioErr(50)", "Reserved(51)",
77 "Reserved(52)", "RTCInt(53)", "Reserved(54)", "Reserved(55)",
78 "Reserved(56)", "Reserved(57)", "Reserved(58)", "Reserved(59)",
79 "Reserved(60)", "Reserved(61)", "Reserved(62)", "Reserved(63)"
80 };
81
82 static struct pic_ops kirkwood_picops = {
83 .pic_unblock_irqs = kirkwood_pic_unblock_irqs,
84 .pic_block_irqs = kirkwood_pic_block_irqs,
85 .pic_establish_irq = kirkwood_pic_establish_irq,
86 .pic_source_name = kirkwood_pic_source_name,
87 };
88 static struct pic_softc kirkwood_pic = {
89 .pic_ops = &kirkwood_picops,
90 .pic_maxsources = 64,
91 .pic_name = "kirkwood",
92 };
93
94 static struct {
95 bus_size_t offset;
96 uint32_t bits;
97 } clkgatings[]= {
98 { KIRKWOOD_GBE0_BASE, (1 << 0) },
99 { MVSOC_PEX_BASE, (1 << 2) },
100 { KIRKWOOD_USB_BASE, (1 << 3) },
101 { KIRKWOOD_SDIO_BASE, (1 << 4) },
102 { KIRKWOOD_MTS_BASE, (1 << 5) },
103 #if 0
104 { Dunit, (1 << 6) }, /* SDRAM Unit Clock */
105 { Runit, (1 << 7) }, /* Runit Clock */
106 #endif
107 { KIRKWOOD_IDMAC_BASE, (1 << 8) | (1 << 16) },
108 { KIRKWOOD_AUDIO_BASE, (1 << 9) },
109 { KIRKWOOD_SATAHC_BASE, (1 << 14) | (1 << 15) },
110 { KIRKWOOD_CESA_BASE, (1 << 17) },
111 { KIRKWOOD_GBE1_BASE, (1 << 19) },
112 { KIRKWOOD_TDM_BASE, (1 << 20) },
113 };
114
115
116 /*
117 * kirkwood_bootstrap:
118 *
119 * Initialize the rest of the Kirkwood dependencies, making it
120 * ready to handle interrupts from devices.
121 */
122 void
kirkwood_bootstrap(vaddr_t iobase)123 kirkwood_bootstrap(vaddr_t iobase)
124 {
125
126 /* disable all interrupts */
127 write_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR, 0);
128 write_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR, 0);
129
130 /* disable all bridge interrupts */
131 write_mlmbreg(MVSOC_MLMB_MLMBIMR, 0);
132
133 mvsoc_intr_init = kirkwood_intr_init;
134
135 #if NMVSOCGPP > 0
136 switch (mvsoc_model()) {
137 case MARVELL_KIRKWOOD_88F6180: gpp_npins = 30; break;
138 case MARVELL_KIRKWOOD_88F6192: gpp_npins = 36; break;
139 case MARVELL_KIRKWOOD_88F6281: gpp_npins = 50; break;
140 case MARVELL_KIRKWOOD_88F6282: gpp_npins = 50; break;
141 }
142 gpp_irqbase = 96; /* Main Low(32) + High(32) + Bridge(32) */
143 #endif
144
145 kirkwood_getclks(iobase);
146 mvsoc_clkgating = kirkwood_clkgating;
147 }
148
149 static void
kirkwood_intr_init(void)150 kirkwood_intr_init(void)
151 {
152 extern struct pic_softc mvsoc_bridge_pic;
153 void *ih __diagused;
154
155 pic_add(&kirkwood_pic, 0);
156
157 pic_add(&mvsoc_bridge_pic, 64);
158 ih = intr_establish(KIRKWOOD_IRQ_BRIDGE, IPL_HIGH, IST_LEVEL_HIGH,
159 pic_handle_intr, &mvsoc_bridge_pic);
160 KASSERT(ih != NULL);
161
162 find_pending_irqs = kirkwood_find_pending_irqs;
163 }
164
165 /* ARGSUSED */
166 static void
kirkwood_pic_unblock_irqs(struct pic_softc * pic,size_t irqbase,uint32_t irq_mask)167 kirkwood_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
168 uint32_t irq_mask)
169 {
170 const size_t reg = KIRKWOOD_MLMB_MIRQIMLR
171 + irqbase * (KIRKWOOD_MLMB_MIRQIMHR - KIRKWOOD_MLMB_MIRQIMLR) / 32;
172
173 KASSERT(irqbase < 64);
174 write_mlmbreg(reg, read_mlmbreg(reg) | irq_mask);
175 }
176
177 /* ARGSUSED */
178 static void
kirkwood_pic_block_irqs(struct pic_softc * pic,size_t irqbase,uint32_t irq_mask)179 kirkwood_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
180 uint32_t irq_mask)
181 {
182 const size_t reg = KIRKWOOD_MLMB_MIRQIMLR
183 + irqbase * (KIRKWOOD_MLMB_MIRQIMHR - KIRKWOOD_MLMB_MIRQIMLR) / 32;
184
185 KASSERT(irqbase < 64);
186 write_mlmbreg(reg, read_mlmbreg(reg) & ~irq_mask);
187 }
188
189 /* ARGSUSED */
190 static void
kirkwood_pic_establish_irq(struct pic_softc * pic,struct intrsource * is)191 kirkwood_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
192 {
193 /* Nothing */
194 }
195
196 static void
kirkwood_pic_source_name(struct pic_softc * pic,int irq,char * buf,size_t len)197 kirkwood_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
198 {
199
200 strlcpy(buf, sources[pic->pic_irqbase + irq], len);
201 }
202
203 /*
204 * Called with interrupts disabled
205 */
206 static int
kirkwood_find_pending_irqs(void)207 kirkwood_find_pending_irqs(void)
208 {
209 int ipl = 0;
210
211 uint32_t causelow = read_mlmbreg(KIRKWOOD_MLMB_MICLR);
212 uint32_t pendinglow = read_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR);
213
214 pendinglow &= causelow;
215 if (pendinglow != 0)
216 ipl |= pic_mark_pending_sources(&kirkwood_pic, 0, pendinglow);
217
218 if ((causelow & (1 << KIRKWOOD_IRQ_HIGH)) == (1 << KIRKWOOD_IRQ_HIGH)) {
219 uint32_t causehigh = read_mlmbreg(KIRKWOOD_MLMB_MICHR);
220 uint32_t pendinghigh = read_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR);
221 pendinghigh &= causehigh;
222 ipl |= pic_mark_pending_sources(&kirkwood_pic, 32, pendinghigh);
223 }
224
225 return ipl;
226 }
227
228 /*
229 * Clock functions
230 */
231
232 static void
kirkwood_getclks(vaddr_t iobase)233 kirkwood_getclks(vaddr_t iobase)
234 {
235 uint32_t reg;
236 uint16_t model;
237
238 #define MHz * 1000 * 1000
239
240 model = mvsoc_model();
241 if (model == MARVELL_KIRKWOOD_88F6281 ||
242 model == MARVELL_KIRKWOOD_88F6282)
243 mvTclk = 200 MHz;
244 else /* 166MHz */
245 mvTclk = 166666667;
246
247 reg = le32toh(*(volatile uint32_t *)(iobase + KIRKWOOD_MPP_BASE +
248 KIRKWOOD_MPP_SAMPLE_AT_RESET));
249 if (model == MARVELL_KIRKWOOD_88F6180) {
250 switch (reg & 0x0000001c) {
251 case 0x00000014: mvPclk = 600 MHz; break;
252 case 0x00000018: mvPclk = 800 MHz; break;
253 default:
254 panic("unknown mvPclk\n");
255 }
256 mvSysclk = 200 MHz;
257 } else {
258 switch (reg & 0x0040001a) {
259 case 0x00000002: mvPclk = 400 MHz; break;
260 case 0x00000008: mvPclk = 600 MHz; break;
261 case 0x00400008: mvPclk = 800 MHz; break;
262 case 0x0040000a: mvPclk = 1000 MHz; break;
263 case 0x00000012: mvPclk = 1200 MHz; break;
264 case 0x00000018: mvPclk = 1500 MHz; break;
265 case 0x0000001a: mvPclk = 1600 MHz; break;
266 case 0x00400018: mvPclk = 1800 MHz; break;
267 case 0x0040001a: mvPclk = 2000 MHz; break;
268 default:
269 panic("unknown mvPclk\n");
270 }
271
272 switch (reg & 0x000001e0) {
273 case 0x00000000: mvSysclk = mvPclk * 1 / 1; break;
274 case 0x00000040: mvSysclk = mvPclk * 1 / 2; break;
275 case 0x00000060: mvSysclk = mvPclk * 2 / 5; break;
276 case 0x00000080: mvSysclk = mvPclk * 1 / 3; break;
277 case 0x000000c0: mvSysclk = mvPclk * 1 / 4; break;
278 case 0x000000e0: mvSysclk = mvPclk * 2 / 9; break;
279 case 0x00000100: mvSysclk = mvPclk * 1 / 5; break;
280 case 0x00000120: mvSysclk = mvPclk * 1 / 6; break;
281 default:
282 panic("unknown mvSysclk\n");
283 }
284 }
285
286 #undef MHz
287
288 }
289
290 static int
kirkwood_clkgating(struct marvell_attach_args * mva)291 kirkwood_clkgating(struct marvell_attach_args *mva)
292 {
293 uint32_t val;
294 int i;
295
296 for (i = 0; i < __arraycount(clkgatings); i++) {
297 if (clkgatings[i].offset == mva->mva_offset) {
298 val = read_mlmbreg(MVSOC_MLMB_CLKGATING);
299 if ((val & clkgatings[i].bits) == clkgatings[i].bits)
300 /* Clock enabled */
301 return 0;
302 return 1;
303 }
304 }
305 /* Clock Gating not support */
306 return 0;
307 }
308