xref: /netbsd-src/sys/arch/arm/imx/imx23_icoll.c (revision aed051009e462c140832602a5e91ab5d8eab850b)
1*aed05100Sjmcneill /* $Id: imx23_icoll.c,v 1.4 2022/06/25 12:41:56 jmcneill Exp $ */
2eba5cacbSjkunz 
3eba5cacbSjkunz /*
4eba5cacbSjkunz  * Copyright (c) 2012 The NetBSD Foundation, Inc.
5eba5cacbSjkunz  * All rights reserved.
6eba5cacbSjkunz  *
7eba5cacbSjkunz  * This code is derived from software contributed to The NetBSD Foundation
8eba5cacbSjkunz  * by Petri Laakso.
9eba5cacbSjkunz  *
10eba5cacbSjkunz  * Redistribution and use in source and binary forms, with or without
11eba5cacbSjkunz  * modification, are permitted provided that the following conditions
12eba5cacbSjkunz  * are met:
13eba5cacbSjkunz  * 1. Redistributions of source code must retain the above copyright
14eba5cacbSjkunz  *    notice, this list of conditions and the following disclaimer.
15eba5cacbSjkunz  * 2. Redistributions in binary form must reproduce the above copyright
16eba5cacbSjkunz  *    notice, this list of conditions and the following disclaimer in the
17eba5cacbSjkunz  *    documentation and/or other materials provided with the distribution.
18eba5cacbSjkunz  *
19eba5cacbSjkunz  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20eba5cacbSjkunz  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21eba5cacbSjkunz  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22eba5cacbSjkunz  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23eba5cacbSjkunz  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24eba5cacbSjkunz  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25eba5cacbSjkunz  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26eba5cacbSjkunz  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27eba5cacbSjkunz  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28eba5cacbSjkunz  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29eba5cacbSjkunz  * POSSIBILITY OF SUCH DAMAGE.
30eba5cacbSjkunz  */
31eba5cacbSjkunz 
32eba5cacbSjkunz #include <sys/param.h>
33eba5cacbSjkunz #include <sys/bus.h>
34eba5cacbSjkunz #include <sys/cpu.h>
35eba5cacbSjkunz #include <sys/device.h>
36eba5cacbSjkunz #include <sys/errno.h>
37eba5cacbSjkunz #include <sys/systm.h>
38eba5cacbSjkunz 
3917d96df1Smartin #include <arm/cpufunc.h>
4017d96df1Smartin 
41eba5cacbSjkunz #define _INTR_PRIVATE
42eba5cacbSjkunz #include <arm/pic/picvar.h>
43eba5cacbSjkunz 
44eba5cacbSjkunz #include <arm/imx/imx23_icollreg.h>
45eba5cacbSjkunz #include <arm/imx/imx23var.h>
46eba5cacbSjkunz 
47eba5cacbSjkunz #define ICOLL_SOFT_RST_LOOP 455		/* At least 1 us ... */
48eba5cacbSjkunz #define ICOLL_READ(sc, reg)						\
49eba5cacbSjkunz 	bus_space_read_4(sc->sc_iot, sc->sc_hdl, (reg))
50eba5cacbSjkunz #define ICOLL_WRITE(sc, reg, val)					\
51eba5cacbSjkunz 	bus_space_write_4(sc->sc_iot, sc->sc_hdl, (reg), (val))
52eba5cacbSjkunz 
53eba5cacbSjkunz #define ICOLL_IRQ_REG_SIZE 0x10
54eba5cacbSjkunz #define ICOLL_CLR_IRQ(sc, irq)						\
55eba5cacbSjkunz 	ICOLL_WRITE(sc, HW_ICOLL_INTERRUPT0_CLR +			\
56eba5cacbSjkunz 			(irq) * ICOLL_IRQ_REG_SIZE,			\
57eba5cacbSjkunz 			HW_ICOLL_INTERRUPT_ENABLE)
58eba5cacbSjkunz #define ICOLL_SET_IRQ(sc, irq)						\
59eba5cacbSjkunz 	ICOLL_WRITE(sc, HW_ICOLL_INTERRUPT0_SET +			\
60eba5cacbSjkunz 			(irq) * ICOLL_IRQ_REG_SIZE,			\
61eba5cacbSjkunz 			HW_ICOLL_INTERRUPT_ENABLE)
62eba5cacbSjkunz #define ICOLL_GET_PRIO(sc, irq)						\
63eba5cacbSjkunz 	__SHIFTOUT(ICOLL_READ(sc, HW_ICOLL_INTERRUPT0 +			\
64eba5cacbSjkunz 			(irq) * ICOLL_IRQ_REG_SIZE),			\
65eba5cacbSjkunz 			HW_ICOLL_INTERRUPT_PRIORITY)
66eba5cacbSjkunz 
67eba5cacbSjkunz #define PICTOSOFTC(pic)							\
68eba5cacbSjkunz 	((struct icoll_softc *)((char *)(pic) -				\
69eba5cacbSjkunz 		offsetof(struct icoll_softc, sc_pic)))
70eba5cacbSjkunz 
71eba5cacbSjkunz /*
72eba5cacbSjkunz  * pic callbacks.
73eba5cacbSjkunz  */
74eba5cacbSjkunz static void	icoll_unblock_irqs(struct pic_softc *, size_t, uint32_t);
75eba5cacbSjkunz static void	icoll_block_irqs(struct pic_softc *, size_t, uint32_t);
76eba5cacbSjkunz static int	icoll_find_pending_irqs(struct pic_softc *);
77eba5cacbSjkunz static void	icoll_establish_irq(struct pic_softc *, struct intrsource *);
78eba5cacbSjkunz static void	icoll_source_name(struct pic_softc *, int, char *, size_t);
79eba5cacbSjkunz static void	icoll_set_priority(struct pic_softc *, int);
80eba5cacbSjkunz 
81eba5cacbSjkunz /*
82eba5cacbSjkunz  * autoconf(9) callbacks.
83eba5cacbSjkunz  */
84eba5cacbSjkunz static int	icoll_match(device_t, cfdata_t, void *);
85eba5cacbSjkunz static void	icoll_attach(device_t, device_t, void *);
86eba5cacbSjkunz static int	icoll_activate(device_t, enum devact);
87eba5cacbSjkunz 
88eba5cacbSjkunz /*
89eba5cacbSjkunz  * ARM interrupt handler.
90eba5cacbSjkunz  */
91eba5cacbSjkunz void imx23_intr_dispatch(struct clockframe *);
92eba5cacbSjkunz 
93eba5cacbSjkunz const static struct pic_ops icoll_pic_ops = {
94eba5cacbSjkunz 	.pic_unblock_irqs = icoll_unblock_irqs,
95eba5cacbSjkunz 	.pic_block_irqs = icoll_block_irqs,
96eba5cacbSjkunz 	.pic_find_pending_irqs = icoll_find_pending_irqs,
97eba5cacbSjkunz 	.pic_establish_irq = icoll_establish_irq,
98eba5cacbSjkunz 	.pic_source_name = icoll_source_name,
99eba5cacbSjkunz 	.pic_set_priority = icoll_set_priority
100eba5cacbSjkunz };
101eba5cacbSjkunz 
102eba5cacbSjkunz struct icoll_softc {
103eba5cacbSjkunz 	device_t sc_dev;
104eba5cacbSjkunz 	struct pic_softc sc_pic;
105eba5cacbSjkunz 	bus_space_tag_t sc_iot;
106eba5cacbSjkunz 	bus_space_handle_t sc_hdl;
107eba5cacbSjkunz };
108eba5cacbSjkunz 
109eba5cacbSjkunz /* For IRQ handler. */
110eba5cacbSjkunz static struct icoll_softc *icoll_sc;
111eba5cacbSjkunz 
112eba5cacbSjkunz /*
113eba5cacbSjkunz  * Private to driver.
114eba5cacbSjkunz  */
115eba5cacbSjkunz static void	icoll_reset(struct icoll_softc *);
116eba5cacbSjkunz 
117eba5cacbSjkunz CFATTACH_DECL3_NEW(icoll,
118eba5cacbSjkunz 	sizeof(struct icoll_softc),
119eba5cacbSjkunz 	icoll_match,
120eba5cacbSjkunz 	icoll_attach,
121eba5cacbSjkunz 	NULL,
122eba5cacbSjkunz 	icoll_activate,
123eba5cacbSjkunz 	NULL,
124eba5cacbSjkunz 	NULL,
125eba5cacbSjkunz 	0);
126eba5cacbSjkunz 
127eba5cacbSjkunz /*
128eba5cacbSjkunz  * ARM interrupt handler.
129eba5cacbSjkunz  */
130eba5cacbSjkunz void
imx23_intr_dispatch(struct clockframe * frame)131eba5cacbSjkunz imx23_intr_dispatch(struct clockframe *frame)
132eba5cacbSjkunz {
133eba5cacbSjkunz 	struct cpu_info * const ci = curcpu();
134eba5cacbSjkunz 	struct pic_softc *pic_sc;
135eba5cacbSjkunz 	int saved_spl;
136eba5cacbSjkunz 	uint8_t irq;
137eba5cacbSjkunz 	uint8_t prio;
138eba5cacbSjkunz 
139eba5cacbSjkunz 	pic_sc = &icoll_sc->sc_pic;
140eba5cacbSjkunz 
141eba5cacbSjkunz 	ci->ci_data.cpu_nintr++;
142eba5cacbSjkunz 
143eba5cacbSjkunz 	/* Save current spl. */
144eba5cacbSjkunz 	saved_spl = curcpl();
145eba5cacbSjkunz 
146eba5cacbSjkunz 	/* IRQ to be handled. */
147eba5cacbSjkunz 	irq = __SHIFTOUT(ICOLL_READ(icoll_sc, HW_ICOLL_STAT),
148eba5cacbSjkunz 	    HW_ICOLL_STAT_VECTOR_NUMBER);
149eba5cacbSjkunz 
150eba5cacbSjkunz 	/* Save IRQ's priority. Acknowledge it later. */
151eba5cacbSjkunz 	prio = ICOLL_GET_PRIO(icoll_sc, irq);
152eba5cacbSjkunz 
153eba5cacbSjkunz 	/*
154eba5cacbSjkunz 	 * Notify ICOLL to deassert IRQ before re-enabling the IRQ's.
155eba5cacbSjkunz 	 * This is done by writing anything to HW_ICOLL_VECTOR.
156eba5cacbSjkunz 	 */
157eba5cacbSjkunz 	ICOLL_WRITE(icoll_sc, HW_ICOLL_VECTOR,
158eba5cacbSjkunz 	    __SHIFTIN(0x3fffffff, HW_ICOLL_VECTOR_IRQVECTOR));
159eba5cacbSjkunz 
160eba5cacbSjkunz 	/* Bogus IRQ. */
161eba5cacbSjkunz 	if (irq == 0x7f) {
162eba5cacbSjkunz 		cpsie(I32_bit);
163eba5cacbSjkunz 		ICOLL_WRITE(icoll_sc, HW_ICOLL_LEVELACK, (1<<prio));
164eba5cacbSjkunz 		cpsid(I32_bit);
165eba5cacbSjkunz 		return;
166eba5cacbSjkunz 	}
167eba5cacbSjkunz 
168eba5cacbSjkunz 	/* Raise the spl to the level of the IRQ. */
169eba5cacbSjkunz 	if (pic_sc->pic_sources[irq]->is_ipl > ci->ci_cpl)
170eba5cacbSjkunz 		saved_spl = _splraise(pic_sc->pic_sources[irq]->is_ipl);
171eba5cacbSjkunz 
172eba5cacbSjkunz 	/* Call the handler registered for the IRQ. */
173eba5cacbSjkunz 	cpsie(I32_bit);
174eba5cacbSjkunz 	pic_dispatch(pic_sc->pic_sources[irq], frame);
175eba5cacbSjkunz 
176eba5cacbSjkunz 	/*
177eba5cacbSjkunz 	 * Acknowledge the IRQ by writing its priority to HW_ICOLL_LEVELACK.
178eba5cacbSjkunz 	 * Interrupts should be enabled.
179eba5cacbSjkunz 	 */
180eba5cacbSjkunz 	ICOLL_WRITE(icoll_sc, HW_ICOLL_LEVELACK, (1<<prio));
181eba5cacbSjkunz 	cpsid(I32_bit);
182eba5cacbSjkunz 
183eba5cacbSjkunz 	/* Restore the saved spl. */
184eba5cacbSjkunz 	splx(saved_spl);
185eba5cacbSjkunz 
186eba5cacbSjkunz 	return;
187eba5cacbSjkunz }
188eba5cacbSjkunz 
189eba5cacbSjkunz /*
190eba5cacbSjkunz  * pic callbacks.
191eba5cacbSjkunz  */
192eba5cacbSjkunz static void
icoll_unblock_irqs(struct pic_softc * pic,size_t irq_base,uint32_t irq_mask)193eba5cacbSjkunz icoll_unblock_irqs(struct pic_softc *pic, size_t irq_base, uint32_t irq_mask)
194eba5cacbSjkunz {
195eba5cacbSjkunz 	struct icoll_softc *sc = PICTOSOFTC(pic);
196eba5cacbSjkunz 	uint8_t b;
197eba5cacbSjkunz 
198eba5cacbSjkunz 	for (;;) {
199eba5cacbSjkunz 		b = ffs(irq_mask);
200eba5cacbSjkunz 		if (b == 0) break;
201eba5cacbSjkunz 		b--;	/* Zero based index. */
202eba5cacbSjkunz 		ICOLL_SET_IRQ(sc, irq_base + b);
203eba5cacbSjkunz 		irq_mask &= ~(1<<b);
204eba5cacbSjkunz 	}
205eba5cacbSjkunz 
206eba5cacbSjkunz 	return;
207eba5cacbSjkunz }
208eba5cacbSjkunz 
209eba5cacbSjkunz static void
icoll_block_irqs(struct pic_softc * pic,size_t irq_base,uint32_t irq_mask)210eba5cacbSjkunz icoll_block_irqs(struct pic_softc *pic, size_t irq_base, uint32_t irq_mask)
211eba5cacbSjkunz {
212eba5cacbSjkunz 	struct icoll_softc *sc = PICTOSOFTC(pic);
213eba5cacbSjkunz 	uint8_t b;
214eba5cacbSjkunz 
215eba5cacbSjkunz 	for (;;) {
216eba5cacbSjkunz 		b = ffs(irq_mask);
217eba5cacbSjkunz 		if (b == 0) break;
218eba5cacbSjkunz 		b--;	/* Zero based index. */
219eba5cacbSjkunz 		ICOLL_CLR_IRQ(sc, irq_base + b);
220eba5cacbSjkunz 		irq_mask &= ~(1<<b);
221eba5cacbSjkunz 	}
222eba5cacbSjkunz 
223eba5cacbSjkunz 	return;
224eba5cacbSjkunz }
225eba5cacbSjkunz 
226eba5cacbSjkunz static int
icoll_find_pending_irqs(struct pic_softc * pic)227eba5cacbSjkunz icoll_find_pending_irqs(struct pic_softc *pic)
228eba5cacbSjkunz {
229eba5cacbSjkunz 	return 0; /* ICOLL HW doesn't provide list of pending interrupts. */
230eba5cacbSjkunz }
231eba5cacbSjkunz 
232eba5cacbSjkunz static void
icoll_establish_irq(struct pic_softc * pic,struct intrsource * is)233eba5cacbSjkunz icoll_establish_irq(struct pic_softc *pic, struct intrsource *is)
234eba5cacbSjkunz {
235eba5cacbSjkunz 	return; /* Nothing to establish. */
236eba5cacbSjkunz }
237eba5cacbSjkunz 
238eba5cacbSjkunz static void
icoll_source_name(struct pic_softc * pic,int irq,char * is_source,size_t size)239eba5cacbSjkunz icoll_source_name(struct pic_softc *pic, int irq, char *is_source, size_t size)
240eba5cacbSjkunz {
241eba5cacbSjkunz 	snprintf(is_source, size, "irq %d", irq);
242eba5cacbSjkunz }
243eba5cacbSjkunz 
244eba5cacbSjkunz /*
245eba5cacbSjkunz  * Set new interrupt priority level by enabling or disabling IRQ's.
246eba5cacbSjkunz  */
247eba5cacbSjkunz static void
icoll_set_priority(struct pic_softc * pic,int newipl)248eba5cacbSjkunz icoll_set_priority(struct pic_softc *pic, int newipl)
249eba5cacbSjkunz {
250eba5cacbSjkunz 	struct icoll_softc *sc = PICTOSOFTC(pic);
251eba5cacbSjkunz 	struct intrsource *is;
252eba5cacbSjkunz 	int i;
253eba5cacbSjkunz 
254*aed05100Sjmcneill 	register_t psw = DISABLE_INTERRUPT_SAVE();
255*aed05100Sjmcneill 
256eba5cacbSjkunz 	for (i = 0; i < pic->pic_maxsources; i++) {
257eba5cacbSjkunz 		is = pic->pic_sources[i];
258eba5cacbSjkunz 		if (is == NULL)
259eba5cacbSjkunz 			continue;
260eba5cacbSjkunz 		if (is->is_ipl > newipl)
261eba5cacbSjkunz 			ICOLL_SET_IRQ(sc, pic->pic_irqbase + is->is_irq);
262eba5cacbSjkunz 		else
263eba5cacbSjkunz 			ICOLL_CLR_IRQ(sc, pic->pic_irqbase + is->is_irq);
264eba5cacbSjkunz 	}
265*aed05100Sjmcneill 
266*aed05100Sjmcneill 	curcpu()->ci_cpl = newipl;
267*aed05100Sjmcneill 
268*aed05100Sjmcneill 	if ((psw & I32_bit) == 0) {
269*aed05100Sjmcneill 		ENABLE_INTERRUPT();
270*aed05100Sjmcneill 	}
271eba5cacbSjkunz }
272eba5cacbSjkunz 
273eba5cacbSjkunz /*
274eba5cacbSjkunz  * autoconf(9) callbacks.
275eba5cacbSjkunz  */
276eba5cacbSjkunz static int
icoll_match(device_t parent,cfdata_t match,void * aux)277eba5cacbSjkunz icoll_match(device_t parent, cfdata_t match, void *aux)
278eba5cacbSjkunz {
279eba5cacbSjkunz 	struct apb_attach_args *aa = aux;
280eba5cacbSjkunz 
281eba5cacbSjkunz 	if ((aa->aa_addr == HW_ICOLL_BASE) && (aa->aa_size == HW_ICOLL_SIZE))
282eba5cacbSjkunz 		return 1;
283eba5cacbSjkunz 
284eba5cacbSjkunz 	return 0;
285eba5cacbSjkunz }
286eba5cacbSjkunz 
287eba5cacbSjkunz static void
icoll_attach(device_t parent,device_t self,void * aux)288eba5cacbSjkunz icoll_attach(device_t parent, device_t self, void *aux)
289eba5cacbSjkunz {
290eba5cacbSjkunz 	static int icoll_attached = 0;
291eba5cacbSjkunz 	struct icoll_softc *sc = device_private(self);
292eba5cacbSjkunz 	struct apb_attach_args *aa = aux;
293eba5cacbSjkunz 
294eba5cacbSjkunz 	if (icoll_attached)
295eba5cacbSjkunz 		return;
296eba5cacbSjkunz 
297eba5cacbSjkunz 	icoll_sc = sc;
298eba5cacbSjkunz 
299eba5cacbSjkunz 	sc->sc_dev = self;
300eba5cacbSjkunz 	sc->sc_iot = aa->aa_iot;
301eba5cacbSjkunz 
302eba5cacbSjkunz 	sc->sc_pic.pic_maxsources = IRQ_LAST + 1;
303eba5cacbSjkunz 	sc->sc_pic.pic_ops = &icoll_pic_ops;
304eba5cacbSjkunz 	strlcpy(sc->sc_pic.pic_name, device_xname(self),
305eba5cacbSjkunz 	    sizeof(sc->sc_pic.pic_name));
306eba5cacbSjkunz 
307eba5cacbSjkunz 	if (bus_space_map(sc->sc_iot,
308eba5cacbSjkunz 	    aa->aa_addr, aa->aa_size, 0, &(sc->sc_hdl))) {
309eba5cacbSjkunz 		aprint_error_dev(sc->sc_dev, "unable to map bus space\n");
310eba5cacbSjkunz 		return;
311eba5cacbSjkunz 	}
312eba5cacbSjkunz 
313eba5cacbSjkunz 	icoll_reset(sc);
314eba5cacbSjkunz 	pic_add(&sc->sc_pic, 0);
315eba5cacbSjkunz 	aprint_normal("\n");
316eba5cacbSjkunz 	icoll_attached = 1;
317eba5cacbSjkunz 
318eba5cacbSjkunz 	return;
319eba5cacbSjkunz }
320eba5cacbSjkunz 
321eba5cacbSjkunz static int
icoll_activate(device_t self,enum devact act)322eba5cacbSjkunz icoll_activate(device_t self, enum devact act)
323eba5cacbSjkunz {
324eba5cacbSjkunz 	return EOPNOTSUPP;
325eba5cacbSjkunz }
326eba5cacbSjkunz 
327eba5cacbSjkunz /*
328eba5cacbSjkunz  * Reset the ICOLL block.
329eba5cacbSjkunz  *
3308a7d722dSjkunz  * Inspired by i.MX23 RM "39.3.10 Correct Way to Soft Reset a Block"
331eba5cacbSjkunz  */
332eba5cacbSjkunz static void
icoll_reset(struct icoll_softc * sc)333eba5cacbSjkunz icoll_reset(struct icoll_softc *sc)
334eba5cacbSjkunz {
335eba5cacbSjkunz 	unsigned int loop;
336eba5cacbSjkunz 
337eba5cacbSjkunz 	/*
338eba5cacbSjkunz 	 * Prepare for soft-reset by making sure that SFTRST is not currently
339eba5cacbSjkunz 	 * asserted. Also clear CLKGATE so we can wait for its assertion below.
340eba5cacbSjkunz 	 */
341eba5cacbSjkunz 	ICOLL_WRITE(sc, HW_ICOLL_CTRL_CLR, HW_ICOLL_CTRL_SFTRST);
342eba5cacbSjkunz 
343eba5cacbSjkunz 	/* Wait at least a microsecond for SFTRST to deassert. */
344eba5cacbSjkunz 	loop = 0;
345eba5cacbSjkunz 	while ((ICOLL_READ(sc, HW_ICOLL_CTRL) & HW_ICOLL_CTRL_SFTRST) ||
346eba5cacbSjkunz 	    (loop < ICOLL_SOFT_RST_LOOP)) {
347eba5cacbSjkunz 		loop++;
348eba5cacbSjkunz 	}
349eba5cacbSjkunz 
350eba5cacbSjkunz 	/* Clear CLKGATE so we can wait for its assertion below. */
351eba5cacbSjkunz 	ICOLL_WRITE(sc, HW_ICOLL_CTRL_CLR, HW_ICOLL_CTRL_CLKGATE);
352eba5cacbSjkunz 
353eba5cacbSjkunz 	/* Soft-reset the block. */
354eba5cacbSjkunz 	ICOLL_WRITE(sc, HW_ICOLL_CTRL_SET, HW_ICOLL_CTRL_SFTRST);
355eba5cacbSjkunz 
356eba5cacbSjkunz 	/* Wait until clock is in the gated state. */
357eba5cacbSjkunz 	while (!(ICOLL_READ(sc, HW_ICOLL_CTRL) & HW_ICOLL_CTRL_CLKGATE));
358eba5cacbSjkunz 
359eba5cacbSjkunz 	/* Bring block out of reset. */
360eba5cacbSjkunz 	ICOLL_WRITE(sc, HW_ICOLL_CTRL_CLR, HW_ICOLL_CTRL_SFTRST);
361eba5cacbSjkunz 
362eba5cacbSjkunz 	loop = 0;
363eba5cacbSjkunz 	while ((ICOLL_READ(sc, HW_ICOLL_CTRL) & HW_ICOLL_CTRL_SFTRST) ||
364eba5cacbSjkunz 	    (loop < ICOLL_SOFT_RST_LOOP)) {
365eba5cacbSjkunz 		loop++;
366eba5cacbSjkunz 	}
367eba5cacbSjkunz 
368eba5cacbSjkunz 	ICOLL_WRITE(sc, HW_ICOLL_CTRL_CLR, HW_ICOLL_CTRL_CLKGATE);
369eba5cacbSjkunz 
370eba5cacbSjkunz 	/* Wait until clock is in the NON-gated state. */
371eba5cacbSjkunz 	while (ICOLL_READ(sc, HW_ICOLL_CTRL) & HW_ICOLL_CTRL_CLKGATE);
372eba5cacbSjkunz 
373eba5cacbSjkunz 	return;
374eba5cacbSjkunz }
375