1184299Snwhitehorn/*-
2184299Snwhitehorn * Copyright (c) 2006 Michael Lorenz
3184299Snwhitehorn * Copyright 2008 by Nathan Whitehorn
4184299Snwhitehorn * All rights reserved.
5184299Snwhitehorn *
6184299Snwhitehorn * Redistribution and use in source and binary forms, with or without
7184299Snwhitehorn * modification, are permitted provided that the following conditions
8184299Snwhitehorn * are met:
9184299Snwhitehorn * 1. Redistributions of source code must retain the above copyright
10184299Snwhitehorn *    notice, this list of conditions and the following disclaimer.
11184299Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright
12184299Snwhitehorn *    notice, this list of conditions and the following disclaimer in the
13184299Snwhitehorn *    documentation and/or other materials provided with the distribution.
14184299Snwhitehorn * 3. The name of the author may not be used to endorse or promote products
15184299Snwhitehorn *    derived from this software without specific prior written permission.
16184299Snwhitehorn *
17184299Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18184299Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19184299Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20184299Snwhitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21184299Snwhitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22184299Snwhitehorn * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23184299Snwhitehorn * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24184299Snwhitehorn * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25184299Snwhitehorn * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26184299Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27184299Snwhitehorn * SUCH DAMAGE.
28184299Snwhitehorn *
29184299Snwhitehorn */
30184299Snwhitehorn
31184299Snwhitehorn#include <sys/cdefs.h>
32184299Snwhitehorn__FBSDID("$FreeBSD$");
33184299Snwhitehorn
34184299Snwhitehorn#include <sys/param.h>
35184299Snwhitehorn#include <sys/systm.h>
36184299Snwhitehorn#include <sys/module.h>
37184299Snwhitehorn#include <sys/bus.h>
38184299Snwhitehorn#include <sys/conf.h>
39184299Snwhitehorn#include <sys/kernel.h>
40205506Snwhitehorn#include <sys/clock.h>
41212054Snwhitehorn#include <sys/reboot.h>
42184299Snwhitehorn
43184299Snwhitehorn#include <dev/ofw/ofw_bus.h>
44184299Snwhitehorn#include <dev/ofw/openfirm.h>
45184299Snwhitehorn
46184299Snwhitehorn#include <machine/bus.h>
47184299Snwhitehorn#include <machine/intr_machdep.h>
48184299Snwhitehorn#include <machine/md_var.h>
49184299Snwhitehorn#include <machine/pio.h>
50184299Snwhitehorn#include <machine/resource.h>
51184299Snwhitehorn
52184299Snwhitehorn#include <vm/vm.h>
53184299Snwhitehorn#include <vm/pmap.h>
54184299Snwhitehorn
55184299Snwhitehorn#include <sys/rman.h>
56184299Snwhitehorn
57184299Snwhitehorn#include <dev/adb/adb.h>
58184299Snwhitehorn
59205506Snwhitehorn#include "clock_if.h"
60184299Snwhitehorn#include "cudavar.h"
61184299Snwhitehorn#include "viareg.h"
62184299Snwhitehorn
63184299Snwhitehorn/*
64184299Snwhitehorn * MacIO interface
65184299Snwhitehorn */
66184299Snwhitehornstatic int	cuda_probe(device_t);
67184299Snwhitehornstatic int	cuda_attach(device_t);
68184299Snwhitehornstatic int	cuda_detach(device_t);
69184299Snwhitehorn
70185724Snwhitehornstatic u_int	cuda_adb_send(device_t dev, u_char command_byte, int len,
71184299Snwhitehorn    u_char *data, u_char poll);
72185724Snwhitehornstatic u_int	cuda_adb_autopoll(device_t dev, uint16_t mask);
73194027Savgstatic u_int	cuda_poll(device_t dev);
74185724Snwhitehornstatic void	cuda_send_inbound(struct cuda_softc *sc);
75185724Snwhitehornstatic void	cuda_send_outbound(struct cuda_softc *sc);
76212054Snwhitehornstatic void	cuda_shutdown(void *xsc, int howto);
77184299Snwhitehorn
78205506Snwhitehorn/*
79205506Snwhitehorn * Clock interface
80205506Snwhitehorn */
81205506Snwhitehornstatic int cuda_gettime(device_t dev, struct timespec *ts);
82205506Snwhitehornstatic int cuda_settime(device_t dev, struct timespec *ts);
83205506Snwhitehorn
84184299Snwhitehornstatic device_method_t  cuda_methods[] = {
85184299Snwhitehorn	/* Device interface */
86184299Snwhitehorn	DEVMETHOD(device_probe,		cuda_probe),
87184299Snwhitehorn	DEVMETHOD(device_attach,	cuda_attach),
88184299Snwhitehorn        DEVMETHOD(device_detach,        cuda_detach),
89184299Snwhitehorn        DEVMETHOD(device_shutdown,      bus_generic_shutdown),
90184299Snwhitehorn        DEVMETHOD(device_suspend,       bus_generic_suspend),
91184299Snwhitehorn        DEVMETHOD(device_resume,        bus_generic_resume),
92184299Snwhitehorn
93184299Snwhitehorn	/* ADB bus interface */
94184299Snwhitehorn	DEVMETHOD(adb_hb_send_raw_packet,	cuda_adb_send),
95184299Snwhitehorn	DEVMETHOD(adb_hb_controller_poll,	cuda_poll),
96184299Snwhitehorn	DEVMETHOD(adb_hb_set_autopoll_mask,	cuda_adb_autopoll),
97184299Snwhitehorn
98205506Snwhitehorn	/* Clock interface */
99205506Snwhitehorn	DEVMETHOD(clock_gettime,	cuda_gettime),
100205506Snwhitehorn	DEVMETHOD(clock_settime,	cuda_settime),
101205506Snwhitehorn
102227843Smarius	DEVMETHOD_END
103184299Snwhitehorn};
104184299Snwhitehorn
105184299Snwhitehornstatic driver_t cuda_driver = {
106184299Snwhitehorn	"cuda",
107184299Snwhitehorn	cuda_methods,
108184299Snwhitehorn	sizeof(struct cuda_softc),
109184299Snwhitehorn};
110184299Snwhitehorn
111184299Snwhitehornstatic devclass_t cuda_devclass;
112184299Snwhitehorn
113184299SnwhitehornDRIVER_MODULE(cuda, macio, cuda_driver, cuda_devclass, 0, 0);
114184299SnwhitehornDRIVER_MODULE(adb, cuda, adb_driver, adb_devclass, 0, 0);
115184299Snwhitehorn
116184299Snwhitehornstatic void cuda_intr(void *arg);
117184299Snwhitehornstatic uint8_t cuda_read_reg(struct cuda_softc *sc, u_int offset);
118184299Snwhitehornstatic void cuda_write_reg(struct cuda_softc *sc, u_int offset, uint8_t value);
119184299Snwhitehornstatic void cuda_idle(struct cuda_softc *);
120184299Snwhitehornstatic void cuda_tip(struct cuda_softc *);
121184299Snwhitehornstatic void cuda_clear_tip(struct cuda_softc *);
122184299Snwhitehornstatic void cuda_in(struct cuda_softc *);
123184299Snwhitehornstatic void cuda_out(struct cuda_softc *);
124184299Snwhitehornstatic void cuda_toggle_ack(struct cuda_softc *);
125184299Snwhitehornstatic void cuda_ack_off(struct cuda_softc *);
126184299Snwhitehornstatic int cuda_intr_state(struct cuda_softc *);
127184299Snwhitehorn
128184299Snwhitehornstatic int
129184299Snwhitehorncuda_probe(device_t dev)
130184299Snwhitehorn{
131184299Snwhitehorn	const char *type = ofw_bus_get_type(dev);
132184299Snwhitehorn
133184299Snwhitehorn	if (strcmp(type, "via-cuda") != 0)
134184299Snwhitehorn                return (ENXIO);
135184299Snwhitehorn
136184299Snwhitehorn	device_set_desc(dev, CUDA_DEVSTR);
137184299Snwhitehorn	return (0);
138184299Snwhitehorn}
139184299Snwhitehorn
140184299Snwhitehornstatic int
141184299Snwhitehorncuda_attach(device_t dev)
142184299Snwhitehorn{
143184299Snwhitehorn	struct cuda_softc *sc;
144184299Snwhitehorn
145184299Snwhitehorn	volatile int i;
146184299Snwhitehorn	uint8_t reg;
147184299Snwhitehorn	phandle_t node,child;
148184299Snwhitehorn
149184299Snwhitehorn	sc = device_get_softc(dev);
150184299Snwhitehorn	sc->sc_dev = dev;
151184299Snwhitehorn
152184299Snwhitehorn	sc->sc_memrid = 0;
153184299Snwhitehorn	sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
154184299Snwhitehorn	    &sc->sc_memrid, RF_ACTIVE);
155184299Snwhitehorn
156184299Snwhitehorn	if (sc->sc_memr == NULL) {
157184299Snwhitehorn		device_printf(dev, "Could not alloc mem resource!\n");
158184299Snwhitehorn		return (ENXIO);
159184299Snwhitehorn	}
160184299Snwhitehorn
161184299Snwhitehorn	sc->sc_irqrid = 0;
162184299Snwhitehorn	sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqrid,
163184299Snwhitehorn            	RF_ACTIVE);
164184299Snwhitehorn        if (sc->sc_irq == NULL) {
165184299Snwhitehorn                device_printf(dev, "could not allocate interrupt\n");
166184299Snwhitehorn                return (ENXIO);
167184299Snwhitehorn        }
168184299Snwhitehorn
169184299Snwhitehorn	if (bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE
170184299Snwhitehorn	    | INTR_ENTROPY, NULL, cuda_intr, dev, &sc->sc_ih) != 0) {
171184299Snwhitehorn                device_printf(dev, "could not setup interrupt\n");
172184299Snwhitehorn                bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqrid,
173184299Snwhitehorn                    sc->sc_irq);
174184299Snwhitehorn                return (ENXIO);
175184299Snwhitehorn        }
176184299Snwhitehorn
177184299Snwhitehorn	mtx_init(&sc->sc_mutex,"cuda",NULL,MTX_DEF | MTX_RECURSE);
178184299Snwhitehorn
179184299Snwhitehorn	sc->sc_sent = 0;
180184299Snwhitehorn	sc->sc_received = 0;
181184299Snwhitehorn	sc->sc_waiting = 0;
182184299Snwhitehorn	sc->sc_polling = 0;
183184299Snwhitehorn	sc->sc_state = CUDA_NOTREADY;
184184299Snwhitehorn	sc->sc_autopoll = 0;
185205506Snwhitehorn	sc->sc_rtc = -1;
186184299Snwhitehorn
187185724Snwhitehorn	STAILQ_INIT(&sc->sc_inq);
188185724Snwhitehorn	STAILQ_INIT(&sc->sc_outq);
189186046Snwhitehorn	STAILQ_INIT(&sc->sc_freeq);
190185724Snwhitehorn
191186046Snwhitehorn	for (i = 0; i < CUDA_MAXPACKETS; i++)
192186046Snwhitehorn		STAILQ_INSERT_TAIL(&sc->sc_freeq, &sc->sc_pkts[i], pkt_q);
193186046Snwhitehorn
194184299Snwhitehorn	/* Init CUDA */
195184299Snwhitehorn
196184299Snwhitehorn	reg = cuda_read_reg(sc, vDirB);
197184299Snwhitehorn	reg |= 0x30;	/* register B bits 4 and 5: outputs */
198184299Snwhitehorn	cuda_write_reg(sc, vDirB, reg);
199184299Snwhitehorn
200184299Snwhitehorn	reg = cuda_read_reg(sc, vDirB);
201184299Snwhitehorn	reg &= 0xf7;	/* register B bit 3: input */
202184299Snwhitehorn	cuda_write_reg(sc, vDirB, reg);
203184299Snwhitehorn
204184299Snwhitehorn	reg = cuda_read_reg(sc, vACR);
205184299Snwhitehorn	reg &= ~vSR_OUT;	/* make sure SR is set to IN */
206184299Snwhitehorn	cuda_write_reg(sc, vACR, reg);
207184299Snwhitehorn
208184299Snwhitehorn	cuda_write_reg(sc, vACR, (cuda_read_reg(sc, vACR) | 0x0c) & ~0x10);
209184299Snwhitehorn
210184299Snwhitehorn	sc->sc_state = CUDA_IDLE;	/* used by all types of hardware */
211184299Snwhitehorn
212184299Snwhitehorn	cuda_write_reg(sc, vIER, 0x84); /* make sure VIA interrupts are on */
213184299Snwhitehorn
214184299Snwhitehorn	cuda_idle(sc);	/* reset ADB */
215184299Snwhitehorn
216184299Snwhitehorn	/* Reset CUDA */
217184299Snwhitehorn
218184299Snwhitehorn	i = cuda_read_reg(sc, vSR);	/* clear interrupt */
219184299Snwhitehorn	cuda_write_reg(sc, vIER, 0x04); /* no interrupts while clearing */
220184299Snwhitehorn	cuda_idle(sc);	/* reset state to idle */
221184299Snwhitehorn	DELAY(150);
222184299Snwhitehorn	cuda_tip(sc);	/* signal start of frame */
223184299Snwhitehorn	DELAY(150);
224184299Snwhitehorn	cuda_toggle_ack(sc);
225184299Snwhitehorn	DELAY(150);
226184299Snwhitehorn	cuda_clear_tip(sc);
227184299Snwhitehorn	DELAY(150);
228184299Snwhitehorn	cuda_idle(sc);	/* back to idle state */
229184299Snwhitehorn	i = cuda_read_reg(sc, vSR);	/* clear interrupt */
230184299Snwhitehorn	cuda_write_reg(sc, vIER, 0x84);	/* ints ok now */
231184299Snwhitehorn
232184299Snwhitehorn	/* Initialize child buses (ADB) */
233184299Snwhitehorn	node = ofw_bus_get_node(dev);
234184299Snwhitehorn
235184299Snwhitehorn	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
236184299Snwhitehorn		char name[32];
237184299Snwhitehorn
238184299Snwhitehorn		memset(name, 0, sizeof(name));
239184299Snwhitehorn		OF_getprop(child, "name", name, sizeof(name));
240184299Snwhitehorn
241184299Snwhitehorn		if (bootverbose)
242184299Snwhitehorn			device_printf(dev, "CUDA child <%s>\n",name);
243184299Snwhitehorn
244184299Snwhitehorn		if (strncmp(name, "adb", 4) == 0) {
245184299Snwhitehorn			sc->adb_bus = device_add_child(dev,"adb",-1);
246184299Snwhitehorn		}
247184299Snwhitehorn	}
248184299Snwhitehorn
249205506Snwhitehorn	clock_register(dev, 1000);
250212054Snwhitehorn	EVENTHANDLER_REGISTER(shutdown_final, cuda_shutdown, sc,
251212054Snwhitehorn	    SHUTDOWN_PRI_LAST);
252205506Snwhitehorn
253184299Snwhitehorn	return (bus_generic_attach(dev));
254184299Snwhitehorn}
255184299Snwhitehorn
256184299Snwhitehornstatic int cuda_detach(device_t dev) {
257184299Snwhitehorn	struct cuda_softc *sc;
258184299Snwhitehorn
259184299Snwhitehorn	sc = device_get_softc(dev);
260184299Snwhitehorn
261184299Snwhitehorn	bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih);
262184299Snwhitehorn	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqrid, sc->sc_irq);
263184299Snwhitehorn	bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_memrid, sc->sc_memr);
264184299Snwhitehorn	mtx_destroy(&sc->sc_mutex);
265184299Snwhitehorn
266184299Snwhitehorn	return (bus_generic_detach(dev));
267184299Snwhitehorn}
268184299Snwhitehorn
269184299Snwhitehornstatic uint8_t
270184299Snwhitehorncuda_read_reg(struct cuda_softc *sc, u_int offset) {
271184299Snwhitehorn	return (bus_read_1(sc->sc_memr, offset));
272184299Snwhitehorn}
273184299Snwhitehorn
274184299Snwhitehornstatic void
275184299Snwhitehorncuda_write_reg(struct cuda_softc *sc, u_int offset, uint8_t value) {
276184299Snwhitehorn	bus_write_1(sc->sc_memr, offset, value);
277184299Snwhitehorn}
278184299Snwhitehorn
279184299Snwhitehornstatic void
280184299Snwhitehorncuda_idle(struct cuda_softc *sc)
281184299Snwhitehorn{
282184299Snwhitehorn	uint8_t reg;
283184299Snwhitehorn
284184299Snwhitehorn	reg = cuda_read_reg(sc, vBufB);
285184299Snwhitehorn	reg |= (vPB4 | vPB5);
286184299Snwhitehorn	cuda_write_reg(sc, vBufB, reg);
287184299Snwhitehorn}
288184299Snwhitehorn
289184299Snwhitehornstatic void
290184299Snwhitehorncuda_tip(struct cuda_softc *sc)
291184299Snwhitehorn{
292184299Snwhitehorn	uint8_t reg;
293184299Snwhitehorn
294184299Snwhitehorn	reg = cuda_read_reg(sc, vBufB);
295184299Snwhitehorn	reg &= ~vPB5;
296184299Snwhitehorn	cuda_write_reg(sc, vBufB, reg);
297184299Snwhitehorn}
298184299Snwhitehorn
299184299Snwhitehornstatic void
300184299Snwhitehorncuda_clear_tip(struct cuda_softc *sc)
301184299Snwhitehorn{
302184299Snwhitehorn	uint8_t reg;
303184299Snwhitehorn
304184299Snwhitehorn	reg = cuda_read_reg(sc, vBufB);
305184299Snwhitehorn	reg |= vPB5;
306184299Snwhitehorn	cuda_write_reg(sc, vBufB, reg);
307184299Snwhitehorn}
308184299Snwhitehorn
309184299Snwhitehornstatic void
310184299Snwhitehorncuda_in(struct cuda_softc *sc)
311184299Snwhitehorn{
312184299Snwhitehorn	uint8_t reg;
313184299Snwhitehorn
314184299Snwhitehorn	reg = cuda_read_reg(sc, vACR);
315184299Snwhitehorn	reg &= ~vSR_OUT;
316184299Snwhitehorn	cuda_write_reg(sc, vACR, reg);
317184299Snwhitehorn}
318184299Snwhitehorn
319184299Snwhitehornstatic void
320184299Snwhitehorncuda_out(struct cuda_softc *sc)
321184299Snwhitehorn{
322184299Snwhitehorn	uint8_t reg;
323184299Snwhitehorn
324184299Snwhitehorn	reg = cuda_read_reg(sc, vACR);
325184299Snwhitehorn	reg |= vSR_OUT;
326184299Snwhitehorn	cuda_write_reg(sc, vACR, reg);
327184299Snwhitehorn}
328184299Snwhitehorn
329184299Snwhitehornstatic void
330184299Snwhitehorncuda_toggle_ack(struct cuda_softc *sc)
331184299Snwhitehorn{
332184299Snwhitehorn	uint8_t reg;
333184299Snwhitehorn
334184299Snwhitehorn	reg = cuda_read_reg(sc, vBufB);
335184299Snwhitehorn	reg ^= vPB4;
336184299Snwhitehorn	cuda_write_reg(sc, vBufB, reg);
337184299Snwhitehorn}
338184299Snwhitehorn
339184299Snwhitehornstatic void
340184299Snwhitehorncuda_ack_off(struct cuda_softc *sc)
341184299Snwhitehorn{
342184299Snwhitehorn	uint8_t reg;
343184299Snwhitehorn
344184299Snwhitehorn	reg = cuda_read_reg(sc, vBufB);
345184299Snwhitehorn	reg |= vPB4;
346184299Snwhitehorn	cuda_write_reg(sc, vBufB, reg);
347184299Snwhitehorn}
348184299Snwhitehorn
349184299Snwhitehornstatic int
350184299Snwhitehorncuda_intr_state(struct cuda_softc *sc)
351184299Snwhitehorn{
352184299Snwhitehorn	return ((cuda_read_reg(sc, vBufB) & vPB3) == 0);
353184299Snwhitehorn}
354184299Snwhitehorn
355184299Snwhitehornstatic int
356184299Snwhitehorncuda_send(void *cookie, int poll, int length, uint8_t *msg)
357184299Snwhitehorn{
358184299Snwhitehorn	struct cuda_softc *sc = cookie;
359184299Snwhitehorn	device_t dev = sc->sc_dev;
360185724Snwhitehorn	struct cuda_packet *pkt;
361184299Snwhitehorn
362184299Snwhitehorn	if (sc->sc_state == CUDA_NOTREADY)
363185724Snwhitehorn		return (-1);
364184299Snwhitehorn
365184299Snwhitehorn	mtx_lock(&sc->sc_mutex);
366184299Snwhitehorn
367186046Snwhitehorn	pkt = STAILQ_FIRST(&sc->sc_freeq);
368186046Snwhitehorn	if (pkt == NULL) {
369186046Snwhitehorn		mtx_unlock(&sc->sc_mutex);
370186046Snwhitehorn		return (-1);
371186046Snwhitehorn	}
372186046Snwhitehorn
373185724Snwhitehorn	pkt->len = length - 1;
374185724Snwhitehorn	pkt->type = msg[0];
375185724Snwhitehorn	memcpy(pkt->data, &msg[1], pkt->len);
376185724Snwhitehorn
377186046Snwhitehorn	STAILQ_REMOVE_HEAD(&sc->sc_freeq, pkt_q);
378185724Snwhitehorn	STAILQ_INSERT_TAIL(&sc->sc_outq, pkt, pkt_q);
379185724Snwhitehorn
380185724Snwhitehorn	/*
381185724Snwhitehorn	 * If we already are sending a packet, we should bail now that this
382185724Snwhitehorn	 * one has been added to the queue.
383185724Snwhitehorn	 */
384185724Snwhitehorn
385185724Snwhitehorn	if (sc->sc_waiting) {
386185724Snwhitehorn		mtx_unlock(&sc->sc_mutex);
387185724Snwhitehorn		return (0);
388184299Snwhitehorn	}
389184299Snwhitehorn
390185724Snwhitehorn	cuda_send_outbound(sc);
391185724Snwhitehorn	mtx_unlock(&sc->sc_mutex);
392185724Snwhitehorn
393185724Snwhitehorn	if (sc->sc_polling || poll || cold)
394185724Snwhitehorn		cuda_poll(dev);
395185724Snwhitehorn
396185724Snwhitehorn	return (0);
397185724Snwhitehorn}
398185724Snwhitehorn
399185724Snwhitehornstatic void
400185724Snwhitehorncuda_send_outbound(struct cuda_softc *sc)
401185724Snwhitehorn{
402185724Snwhitehorn	struct cuda_packet *pkt;
403185724Snwhitehorn
404185724Snwhitehorn	mtx_assert(&sc->sc_mutex, MA_OWNED);
405185724Snwhitehorn
406185724Snwhitehorn	pkt = STAILQ_FIRST(&sc->sc_outq);
407185724Snwhitehorn	if (pkt == NULL)
408185724Snwhitehorn		return;
409185724Snwhitehorn
410185724Snwhitehorn	sc->sc_out_length = pkt->len + 1;
411185724Snwhitehorn	memcpy(sc->sc_out, &pkt->type, pkt->len + 1);
412184299Snwhitehorn	sc->sc_sent = 0;
413184299Snwhitehorn
414185724Snwhitehorn	STAILQ_REMOVE_HEAD(&sc->sc_outq, pkt_q);
415186046Snwhitehorn	STAILQ_INSERT_TAIL(&sc->sc_freeq, pkt, pkt_q);
416185724Snwhitehorn
417185724Snwhitehorn	sc->sc_waiting = 1;
418185724Snwhitehorn
419185724Snwhitehorn	cuda_poll(sc->sc_dev);
420185724Snwhitehorn
421185724Snwhitehorn	DELAY(150);
422185724Snwhitehorn
423185724Snwhitehorn	if (sc->sc_state == CUDA_IDLE && !cuda_intr_state(sc)) {
424184299Snwhitehorn		sc->sc_state = CUDA_OUT;
425184299Snwhitehorn		cuda_out(sc);
426184299Snwhitehorn		cuda_write_reg(sc, vSR, sc->sc_out[0]);
427184299Snwhitehorn		cuda_ack_off(sc);
428184299Snwhitehorn		cuda_tip(sc);
429184299Snwhitehorn	}
430185724Snwhitehorn}
431184299Snwhitehorn
432185724Snwhitehornstatic void
433185724Snwhitehorncuda_send_inbound(struct cuda_softc *sc)
434185724Snwhitehorn{
435185724Snwhitehorn	device_t dev;
436185724Snwhitehorn	struct cuda_packet *pkt;
437185724Snwhitehorn
438185724Snwhitehorn	dev = sc->sc_dev;
439185724Snwhitehorn
440185724Snwhitehorn	mtx_lock(&sc->sc_mutex);
441185724Snwhitehorn
442185724Snwhitehorn	while ((pkt = STAILQ_FIRST(&sc->sc_inq)) != NULL) {
443185724Snwhitehorn		STAILQ_REMOVE_HEAD(&sc->sc_inq, pkt_q);
444185724Snwhitehorn
445185724Snwhitehorn		mtx_unlock(&sc->sc_mutex);
446185724Snwhitehorn
447185724Snwhitehorn		/* check if we have a handler for this message */
448185724Snwhitehorn		switch (pkt->type) {
449185724Snwhitehorn		   case CUDA_ADB:
450185724Snwhitehorn			if (pkt->len > 2) {
451185724Snwhitehorn				adb_receive_raw_packet(sc->adb_bus,
452185724Snwhitehorn				    pkt->data[0],pkt->data[1],
453185724Snwhitehorn				    pkt->len - 2,&pkt->data[2]);
454185724Snwhitehorn			} else {
455185724Snwhitehorn				adb_receive_raw_packet(sc->adb_bus,
456185724Snwhitehorn				    pkt->data[0],pkt->data[1],0,NULL);
457185724Snwhitehorn			}
458185724Snwhitehorn			break;
459185724Snwhitehorn		   case CUDA_PSEUDO:
460185724Snwhitehorn			mtx_lock(&sc->sc_mutex);
461205506Snwhitehorn			switch (pkt->data[1]) {
462205506Snwhitehorn			case CMD_AUTOPOLL:
463185724Snwhitehorn				sc->sc_autopoll = 1;
464205506Snwhitehorn				break;
465205506Snwhitehorn			case CMD_READ_RTC:
466205506Snwhitehorn				memcpy(&sc->sc_rtc, &pkt->data[2],
467205506Snwhitehorn				    sizeof(sc->sc_rtc));
468205506Snwhitehorn				wakeup(&sc->sc_rtc);
469205506Snwhitehorn				break;
470205506Snwhitehorn			case CMD_WRITE_RTC:
471205506Snwhitehorn				break;
472205506Snwhitehorn			}
473185724Snwhitehorn			mtx_unlock(&sc->sc_mutex);
474185724Snwhitehorn			break;
475185724Snwhitehorn		   case CUDA_ERROR:
476185724Snwhitehorn			/*
477185724Snwhitehorn			 * CUDA will throw errors if we miss a race between
478185724Snwhitehorn			 * sending and receiving packets. This is already
479185724Snwhitehorn			 * handled when we abort packet output to handle
480185724Snwhitehorn			 * this packet in cuda_intr(). Thus, we ignore
481185724Snwhitehorn			 * these messages.
482185724Snwhitehorn			 */
483185724Snwhitehorn			break;
484185724Snwhitehorn		   default:
485185724Snwhitehorn			device_printf(dev,"unknown CUDA command %d\n",
486185724Snwhitehorn			    pkt->type);
487185724Snwhitehorn			break;
488185724Snwhitehorn		}
489185724Snwhitehorn
490186046Snwhitehorn		mtx_lock(&sc->sc_mutex);
491185724Snwhitehorn
492186046Snwhitehorn		STAILQ_INSERT_TAIL(&sc->sc_freeq, pkt, pkt_q);
493184299Snwhitehorn	}
494184299Snwhitehorn
495185724Snwhitehorn	mtx_unlock(&sc->sc_mutex);
496184299Snwhitehorn}
497184299Snwhitehorn
498194027Savgstatic u_int
499184299Snwhitehorncuda_poll(device_t dev)
500184299Snwhitehorn{
501184299Snwhitehorn	struct cuda_softc *sc = device_get_softc(dev);
502184299Snwhitehorn
503184473Snwhitehorn	if (sc->sc_state == CUDA_IDLE && !cuda_intr_state(sc) &&
504184473Snwhitehorn	    !sc->sc_waiting)
505194027Savg		return (0);
506184473Snwhitehorn
507185724Snwhitehorn	cuda_intr(dev);
508194027Savg	return (0);
509184299Snwhitehorn}
510184299Snwhitehorn
511184299Snwhitehornstatic void
512184299Snwhitehorncuda_intr(void *arg)
513184299Snwhitehorn{
514184299Snwhitehorn	device_t        dev;
515184299Snwhitehorn	struct cuda_softc *sc;
516184299Snwhitehorn
517185724Snwhitehorn	int i, ending, restart_send, process_inbound;
518184299Snwhitehorn	uint8_t reg;
519184299Snwhitehorn
520184299Snwhitehorn        dev = (device_t)arg;
521184299Snwhitehorn	sc = device_get_softc(dev);
522184299Snwhitehorn
523184299Snwhitehorn	mtx_lock(&sc->sc_mutex);
524184299Snwhitehorn
525184299Snwhitehorn	restart_send = 0;
526185724Snwhitehorn	process_inbound = 0;
527184299Snwhitehorn	reg = cuda_read_reg(sc, vIFR);
528185724Snwhitehorn	if ((reg & vSR_INT) != vSR_INT) {
529185724Snwhitehorn		mtx_unlock(&sc->sc_mutex);
530185724Snwhitehorn		return;
531185724Snwhitehorn	}
532185724Snwhitehorn
533184299Snwhitehorn	cuda_write_reg(sc, vIFR, 0x7f);	/* Clear interrupt */
534184299Snwhitehorn
535184299Snwhitehornswitch_start:
536184299Snwhitehorn	switch (sc->sc_state) {
537184299Snwhitehorn	case CUDA_IDLE:
538184299Snwhitehorn		/*
539184299Snwhitehorn		 * This is an unexpected packet, so grab the first (dummy)
540184299Snwhitehorn		 * byte, set up the proper vars, and tell the chip we are
541184299Snwhitehorn		 * starting to receive the packet by setting the TIP bit.
542184299Snwhitehorn		 */
543184299Snwhitehorn		sc->sc_in[1] = cuda_read_reg(sc, vSR);
544184299Snwhitehorn
545184299Snwhitehorn		if (cuda_intr_state(sc) == 0) {
546184299Snwhitehorn			/* must have been a fake start */
547184299Snwhitehorn
548184299Snwhitehorn			if (sc->sc_waiting) {
549184299Snwhitehorn				/* start over */
550184299Snwhitehorn				DELAY(150);
551184299Snwhitehorn				sc->sc_state = CUDA_OUT;
552184299Snwhitehorn				sc->sc_sent = 0;
553184299Snwhitehorn				cuda_out(sc);
554184299Snwhitehorn				cuda_write_reg(sc, vSR, sc->sc_out[1]);
555184299Snwhitehorn				cuda_ack_off(sc);
556184299Snwhitehorn				cuda_tip(sc);
557184299Snwhitehorn			}
558184299Snwhitehorn			break;
559184299Snwhitehorn		}
560184299Snwhitehorn
561184299Snwhitehorn		cuda_in(sc);
562184299Snwhitehorn		cuda_tip(sc);
563184299Snwhitehorn
564184299Snwhitehorn		sc->sc_received = 1;
565184299Snwhitehorn		sc->sc_state = CUDA_IN;
566184299Snwhitehorn		break;
567184299Snwhitehorn
568184299Snwhitehorn	case CUDA_IN:
569184299Snwhitehorn		sc->sc_in[sc->sc_received] = cuda_read_reg(sc, vSR);
570184299Snwhitehorn		ending = 0;
571184299Snwhitehorn
572184299Snwhitehorn		if (sc->sc_received > 255) {
573184299Snwhitehorn			/* bitch only once */
574184299Snwhitehorn			if (sc->sc_received == 256) {
575184299Snwhitehorn				device_printf(dev,"input overflow\n");
576184299Snwhitehorn				ending = 1;
577184299Snwhitehorn			}
578184299Snwhitehorn		} else
579184299Snwhitehorn			sc->sc_received++;
580184299Snwhitehorn
581184299Snwhitehorn		/* intr off means this is the last byte (end of frame) */
582184299Snwhitehorn		if (cuda_intr_state(sc) == 0) {
583184299Snwhitehorn			ending = 1;
584184299Snwhitehorn		} else {
585184299Snwhitehorn			cuda_toggle_ack(sc);
586184299Snwhitehorn		}
587184299Snwhitehorn
588184299Snwhitehorn		if (ending == 1) {	/* end of message? */
589185724Snwhitehorn			struct cuda_packet *pkt;
590184299Snwhitehorn
591184299Snwhitehorn			/* reset vars and signal the end of this frame */
592184299Snwhitehorn			cuda_idle(sc);
593184299Snwhitehorn
594185724Snwhitehorn			/* Queue up the packet */
595186046Snwhitehorn			pkt = STAILQ_FIRST(&sc->sc_freeq);
596186046Snwhitehorn			if (pkt != NULL) {
597186046Snwhitehorn				/* If we have a free packet, process it */
598184299Snwhitehorn
599186046Snwhitehorn				pkt->len = sc->sc_received - 2;
600186046Snwhitehorn				pkt->type = sc->sc_in[1];
601186046Snwhitehorn				memcpy(pkt->data, &sc->sc_in[2], pkt->len);
602184299Snwhitehorn
603186046Snwhitehorn				STAILQ_REMOVE_HEAD(&sc->sc_freeq, pkt_q);
604186046Snwhitehorn				STAILQ_INSERT_TAIL(&sc->sc_inq, pkt, pkt_q);
605185724Snwhitehorn
606186046Snwhitehorn				process_inbound = 1;
607186046Snwhitehorn			}
608186046Snwhitehorn
609184299Snwhitehorn			sc->sc_state = CUDA_IDLE;
610184299Snwhitehorn			sc->sc_received = 0;
611184299Snwhitehorn
612184299Snwhitehorn			/*
613184299Snwhitehorn			 * If there is something waiting to be sent out,
614184299Snwhitehorn			 * set everything up and send the first byte.
615184299Snwhitehorn			 */
616184299Snwhitehorn			if (sc->sc_waiting == 1) {
617184299Snwhitehorn				DELAY(1500);	/* required */
618184299Snwhitehorn				sc->sc_sent = 0;
619184299Snwhitehorn				sc->sc_state = CUDA_OUT;
620184299Snwhitehorn
621184299Snwhitehorn				/*
622184299Snwhitehorn				 * If the interrupt is on, we were too slow
623184299Snwhitehorn				 * and the chip has already started to send
624184299Snwhitehorn				 * something to us, so back out of the write
625184299Snwhitehorn				 * and start a read cycle.
626184299Snwhitehorn				 */
627184299Snwhitehorn				if (cuda_intr_state(sc)) {
628184299Snwhitehorn					cuda_in(sc);
629184299Snwhitehorn					cuda_idle(sc);
630184299Snwhitehorn					sc->sc_sent = 0;
631184299Snwhitehorn					sc->sc_state = CUDA_IDLE;
632184299Snwhitehorn					sc->sc_received = 0;
633184299Snwhitehorn					DELAY(150);
634184299Snwhitehorn					goto switch_start;
635184299Snwhitehorn				}
636185724Snwhitehorn
637184299Snwhitehorn				/*
638184299Snwhitehorn				 * If we got here, it's ok to start sending
639184299Snwhitehorn				 * so load the first byte and tell the chip
640184299Snwhitehorn				 * we want to send.
641184299Snwhitehorn				 */
642184299Snwhitehorn				cuda_out(sc);
643184299Snwhitehorn				cuda_write_reg(sc, vSR,
644184299Snwhitehorn				    sc->sc_out[sc->sc_sent]);
645184299Snwhitehorn				cuda_ack_off(sc);
646184299Snwhitehorn				cuda_tip(sc);
647184299Snwhitehorn			}
648184299Snwhitehorn		}
649184299Snwhitehorn		break;
650184299Snwhitehorn
651184299Snwhitehorn	case CUDA_OUT:
652184299Snwhitehorn		i = cuda_read_reg(sc, vSR);	/* reset SR-intr in IFR */
653184299Snwhitehorn
654184299Snwhitehorn		sc->sc_sent++;
655184299Snwhitehorn		if (cuda_intr_state(sc)) {	/* ADB intr low during write */
656184299Snwhitehorn			cuda_in(sc);	/* make sure SR is set to IN */
657184299Snwhitehorn			cuda_idle(sc);
658184299Snwhitehorn			sc->sc_sent = 0;	/* must start all over */
659184299Snwhitehorn			sc->sc_state = CUDA_IDLE;	/* new state */
660184299Snwhitehorn			sc->sc_received = 0;
661184299Snwhitehorn			sc->sc_waiting = 1;	/* must retry when done with
662184299Snwhitehorn						 * read */
663184299Snwhitehorn			DELAY(150);
664184299Snwhitehorn			goto switch_start;	/* process next state right
665184299Snwhitehorn						 * now */
666184299Snwhitehorn			break;
667184299Snwhitehorn		}
668184299Snwhitehorn		if (sc->sc_out_length == sc->sc_sent) {	/* check for done */
669184299Snwhitehorn			sc->sc_waiting = 0;	/* done writing */
670184299Snwhitehorn			sc->sc_state = CUDA_IDLE;	/* signal bus is idle */
671184299Snwhitehorn			cuda_in(sc);
672184299Snwhitehorn			cuda_idle(sc);
673184299Snwhitehorn		} else {
674184299Snwhitehorn			/* send next byte */
675184299Snwhitehorn			cuda_write_reg(sc, vSR, sc->sc_out[sc->sc_sent]);
676184299Snwhitehorn			cuda_toggle_ack(sc);	/* signal byte ready to
677184299Snwhitehorn							 * shift */
678184299Snwhitehorn		}
679184299Snwhitehorn		break;
680184299Snwhitehorn
681184299Snwhitehorn	case CUDA_NOTREADY:
682184299Snwhitehorn		break;
683184299Snwhitehorn
684184299Snwhitehorn	default:
685184299Snwhitehorn		break;
686184299Snwhitehorn	}
687184299Snwhitehorn
688184299Snwhitehorn	mtx_unlock(&sc->sc_mutex);
689185724Snwhitehorn
690185724Snwhitehorn	if (process_inbound)
691185724Snwhitehorn		cuda_send_inbound(sc);
692185724Snwhitehorn
693185724Snwhitehorn	mtx_lock(&sc->sc_mutex);
694185724Snwhitehorn	/* If we have another packet waiting, set it up */
695185724Snwhitehorn	if (!sc->sc_waiting && sc->sc_state == CUDA_IDLE)
696185724Snwhitehorn		cuda_send_outbound(sc);
697185724Snwhitehorn
698185724Snwhitehorn	mtx_unlock(&sc->sc_mutex);
699185724Snwhitehorn
700184299Snwhitehorn}
701184299Snwhitehorn
702184299Snwhitehornstatic u_int
703185724Snwhitehorncuda_adb_send(device_t dev, u_char command_byte, int len, u_char *data,
704185724Snwhitehorn    u_char poll)
705184299Snwhitehorn{
706184299Snwhitehorn	struct cuda_softc *sc = device_get_softc(dev);
707185724Snwhitehorn	uint8_t packet[16];
708184299Snwhitehorn	int i;
709184299Snwhitehorn
710184299Snwhitehorn	/* construct an ADB command packet and send it */
711184299Snwhitehorn	packet[0] = CUDA_ADB;
712184299Snwhitehorn	packet[1] = command_byte;
713184299Snwhitehorn	for (i = 0; i < len; i++)
714184299Snwhitehorn		packet[i + 2] = data[i];
715184299Snwhitehorn
716184299Snwhitehorn	cuda_send(sc, poll, len + 2, packet);
717184299Snwhitehorn
718185724Snwhitehorn	return (0);
719184299Snwhitehorn}
720184299Snwhitehorn
721184299Snwhitehornstatic u_int
722184299Snwhitehorncuda_adb_autopoll(device_t dev, uint16_t mask) {
723184299Snwhitehorn	struct cuda_softc *sc = device_get_softc(dev);
724184299Snwhitehorn
725184299Snwhitehorn	uint8_t cmd[] = {CUDA_PSEUDO, CMD_AUTOPOLL, mask != 0};
726184299Snwhitehorn
727184299Snwhitehorn	mtx_lock(&sc->sc_mutex);
728184473Snwhitehorn
729184299Snwhitehorn	if (cmd[2] == sc->sc_autopoll) {
730184299Snwhitehorn		mtx_unlock(&sc->sc_mutex);
731185724Snwhitehorn		return (0);
732184299Snwhitehorn	}
733184299Snwhitehorn
734184299Snwhitehorn	sc->sc_autopoll = -1;
735185724Snwhitehorn	cuda_send(sc, 1, 3, cmd);
736184299Snwhitehorn
737184299Snwhitehorn	mtx_unlock(&sc->sc_mutex);
738185724Snwhitehorn
739185724Snwhitehorn	return (0);
740184299Snwhitehorn}
741184299Snwhitehorn
742212054Snwhitehornstatic void
743212054Snwhitehorncuda_shutdown(void *xsc, int howto)
744212054Snwhitehorn{
745212054Snwhitehorn	struct cuda_softc *sc = xsc;
746212054Snwhitehorn	uint8_t cmd[] = {CUDA_PSEUDO, 0};
747212054Snwhitehorn
748212054Snwhitehorn	cmd[1] = (howto & RB_HALT) ? CMD_POWEROFF : CMD_RESET;
749212054Snwhitehorn	cuda_poll(sc->sc_dev);
750212054Snwhitehorn	cuda_send(sc, 1, 2, cmd);
751212054Snwhitehorn
752212054Snwhitehorn	while (1)
753212054Snwhitehorn		cuda_poll(sc->sc_dev);
754212054Snwhitehorn}
755212054Snwhitehorn
756205506Snwhitehorn#define DIFF19041970	2082844800
757205506Snwhitehorn
758205506Snwhitehornstatic int
759205506Snwhitehorncuda_gettime(device_t dev, struct timespec *ts)
760205506Snwhitehorn{
761205506Snwhitehorn	struct cuda_softc *sc = device_get_softc(dev);
762205506Snwhitehorn	uint8_t cmd[] = {CUDA_PSEUDO, CMD_READ_RTC};
763205506Snwhitehorn
764205506Snwhitehorn	mtx_lock(&sc->sc_mutex);
765205506Snwhitehorn	sc->sc_rtc = -1;
766205506Snwhitehorn	cuda_send(sc, 1, 2, cmd);
767205506Snwhitehorn	if (sc->sc_rtc == -1)
768205506Snwhitehorn		mtx_sleep(&sc->sc_rtc, &sc->sc_mutex, 0, "rtc", 100);
769205506Snwhitehorn
770205506Snwhitehorn	ts->tv_sec = sc->sc_rtc - DIFF19041970;
771205506Snwhitehorn	ts->tv_nsec = 0;
772205506Snwhitehorn	mtx_unlock(&sc->sc_mutex);
773205506Snwhitehorn
774205506Snwhitehorn	return (0);
775205506Snwhitehorn}
776205506Snwhitehorn
777205506Snwhitehornstatic int
778205506Snwhitehorncuda_settime(device_t dev, struct timespec *ts)
779205506Snwhitehorn{
780205506Snwhitehorn	struct cuda_softc *sc = device_get_softc(dev);
781205506Snwhitehorn	uint8_t cmd[] = {CUDA_PSEUDO, CMD_WRITE_RTC, 0, 0, 0, 0};
782205506Snwhitehorn	uint32_t sec;
783205506Snwhitehorn
784205506Snwhitehorn	sec = ts->tv_sec + DIFF19041970;
785205506Snwhitehorn	memcpy(&cmd[2], &sec, sizeof(sec));
786205506Snwhitehorn
787205506Snwhitehorn	mtx_lock(&sc->sc_mutex);
788205506Snwhitehorn	cuda_send(sc, 0, 6, cmd);
789205506Snwhitehorn	mtx_unlock(&sc->sc_mutex);
790205506Snwhitehorn
791205506Snwhitehorn	return (0);
792205506Snwhitehorn}
793205506Snwhitehorn
794