cuda.c revision 186046
1/*-
2 * Copyright (c) 2006 Michael Lorenz
3 * Copyright 2008 by Nathan Whitehorn
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 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: head/sys/powerpc/powermac/cuda.c 186046 2008-12-13 18:49:01Z nwhitehorn $");
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/module.h>
37#include <sys/bus.h>
38#include <sys/conf.h>
39#include <sys/kernel.h>
40
41#include <dev/ofw/ofw_bus.h>
42#include <dev/ofw/openfirm.h>
43
44#include <machine/bus.h>
45#include <machine/intr.h>
46#include <machine/intr_machdep.h>
47#include <machine/md_var.h>
48#include <machine/pio.h>
49#include <machine/resource.h>
50
51#include <vm/vm.h>
52#include <vm/pmap.h>
53
54#include <sys/rman.h>
55
56#include <dev/adb/adb.h>
57
58#include "cudavar.h"
59#include "viareg.h"
60
61/*
62 * MacIO interface
63 */
64static int	cuda_probe(device_t);
65static int	cuda_attach(device_t);
66static int	cuda_detach(device_t);
67
68static u_int	cuda_adb_send(device_t dev, u_char command_byte, int len,
69    u_char *data, u_char poll);
70static u_int	cuda_adb_autopoll(device_t dev, uint16_t mask);
71static void	cuda_poll(device_t dev);
72static void	cuda_send_inbound(struct cuda_softc *sc);
73static void	cuda_send_outbound(struct cuda_softc *sc);
74
75static device_method_t  cuda_methods[] = {
76	/* Device interface */
77	DEVMETHOD(device_probe,		cuda_probe),
78	DEVMETHOD(device_attach,	cuda_attach),
79        DEVMETHOD(device_detach,        cuda_detach),
80        DEVMETHOD(device_shutdown,      bus_generic_shutdown),
81        DEVMETHOD(device_suspend,       bus_generic_suspend),
82        DEVMETHOD(device_resume,        bus_generic_resume),
83
84	/* bus interface, for ADB root */
85        DEVMETHOD(bus_print_child,      bus_generic_print_child),
86        DEVMETHOD(bus_driver_added,     bus_generic_driver_added),
87
88	/* ADB bus interface */
89	DEVMETHOD(adb_hb_send_raw_packet,	cuda_adb_send),
90	DEVMETHOD(adb_hb_controller_poll,	cuda_poll),
91	DEVMETHOD(adb_hb_set_autopoll_mask,	cuda_adb_autopoll),
92
93	{ 0, 0 },
94};
95
96static driver_t cuda_driver = {
97	"cuda",
98	cuda_methods,
99	sizeof(struct cuda_softc),
100};
101
102static devclass_t cuda_devclass;
103
104DRIVER_MODULE(cuda, macio, cuda_driver, cuda_devclass, 0, 0);
105DRIVER_MODULE(adb, cuda, adb_driver, adb_devclass, 0, 0);
106
107static void cuda_intr(void *arg);
108static uint8_t cuda_read_reg(struct cuda_softc *sc, u_int offset);
109static void cuda_write_reg(struct cuda_softc *sc, u_int offset, uint8_t value);
110static void cuda_idle(struct cuda_softc *);
111static void cuda_tip(struct cuda_softc *);
112static void cuda_clear_tip(struct cuda_softc *);
113static void cuda_in(struct cuda_softc *);
114static void cuda_out(struct cuda_softc *);
115static void cuda_toggle_ack(struct cuda_softc *);
116static void cuda_ack_off(struct cuda_softc *);
117static int cuda_intr_state(struct cuda_softc *);
118
119static int
120cuda_probe(device_t dev)
121{
122	const char *type = ofw_bus_get_type(dev);
123
124	if (strcmp(type, "via-cuda") != 0)
125                return (ENXIO);
126
127	device_set_desc(dev, CUDA_DEVSTR);
128	return (0);
129}
130
131static int
132cuda_attach(device_t dev)
133{
134	struct cuda_softc *sc;
135
136	volatile int i;
137	uint8_t reg;
138	phandle_t node,child;
139
140	sc = device_get_softc(dev);
141	sc->sc_dev = dev;
142
143	sc->sc_memrid = 0;
144	sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
145	    &sc->sc_memrid, RF_ACTIVE);
146
147	if (sc->sc_memr == NULL) {
148		device_printf(dev, "Could not alloc mem resource!\n");
149		return (ENXIO);
150	}
151
152	sc->sc_irqrid = 0;
153	sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irqrid,
154            	RF_ACTIVE);
155        if (sc->sc_irq == NULL) {
156                device_printf(dev, "could not allocate interrupt\n");
157                return (ENXIO);
158        }
159
160	if (bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE
161	    | INTR_ENTROPY, NULL, cuda_intr, dev, &sc->sc_ih) != 0) {
162                device_printf(dev, "could not setup interrupt\n");
163                bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqrid,
164                    sc->sc_irq);
165                return (ENXIO);
166        }
167
168	mtx_init(&sc->sc_mutex,"cuda",NULL,MTX_DEF | MTX_RECURSE);
169
170	sc->sc_sent = 0;
171	sc->sc_received = 0;
172	sc->sc_waiting = 0;
173	sc->sc_polling = 0;
174	sc->sc_state = CUDA_NOTREADY;
175	sc->sc_autopoll = 0;
176
177	STAILQ_INIT(&sc->sc_inq);
178	STAILQ_INIT(&sc->sc_outq);
179	STAILQ_INIT(&sc->sc_freeq);
180
181	for (i = 0; i < CUDA_MAXPACKETS; i++)
182		STAILQ_INSERT_TAIL(&sc->sc_freeq, &sc->sc_pkts[i], pkt_q);
183
184	/* Init CUDA */
185
186	reg = cuda_read_reg(sc, vDirB);
187	reg |= 0x30;	/* register B bits 4 and 5: outputs */
188	cuda_write_reg(sc, vDirB, reg);
189
190	reg = cuda_read_reg(sc, vDirB);
191	reg &= 0xf7;	/* register B bit 3: input */
192	cuda_write_reg(sc, vDirB, reg);
193
194	reg = cuda_read_reg(sc, vACR);
195	reg &= ~vSR_OUT;	/* make sure SR is set to IN */
196	cuda_write_reg(sc, vACR, reg);
197
198	cuda_write_reg(sc, vACR, (cuda_read_reg(sc, vACR) | 0x0c) & ~0x10);
199
200	sc->sc_state = CUDA_IDLE;	/* used by all types of hardware */
201
202	cuda_write_reg(sc, vIER, 0x84); /* make sure VIA interrupts are on */
203
204	cuda_idle(sc);	/* reset ADB */
205
206	/* Reset CUDA */
207
208	i = cuda_read_reg(sc, vSR);	/* clear interrupt */
209	cuda_write_reg(sc, vIER, 0x04); /* no interrupts while clearing */
210	cuda_idle(sc);	/* reset state to idle */
211	DELAY(150);
212	cuda_tip(sc);	/* signal start of frame */
213	DELAY(150);
214	cuda_toggle_ack(sc);
215	DELAY(150);
216	cuda_clear_tip(sc);
217	DELAY(150);
218	cuda_idle(sc);	/* back to idle state */
219	i = cuda_read_reg(sc, vSR);	/* clear interrupt */
220	cuda_write_reg(sc, vIER, 0x84);	/* ints ok now */
221
222	/* Initialize child buses (ADB) */
223	node = ofw_bus_get_node(dev);
224
225	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
226		char name[32];
227
228		memset(name, 0, sizeof(name));
229		OF_getprop(child, "name", name, sizeof(name));
230
231		if (bootverbose)
232			device_printf(dev, "CUDA child <%s>\n",name);
233
234		if (strncmp(name, "adb", 4) == 0) {
235			sc->adb_bus = device_add_child(dev,"adb",-1);
236		}
237	}
238
239	return (bus_generic_attach(dev));
240}
241
242static int cuda_detach(device_t dev) {
243	struct cuda_softc *sc;
244
245	sc = device_get_softc(dev);
246
247	bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih);
248	bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irqrid, sc->sc_irq);
249	bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_memrid, sc->sc_memr);
250	mtx_destroy(&sc->sc_mutex);
251
252	return (bus_generic_detach(dev));
253}
254
255static uint8_t
256cuda_read_reg(struct cuda_softc *sc, u_int offset) {
257	return (bus_read_1(sc->sc_memr, offset));
258}
259
260static void
261cuda_write_reg(struct cuda_softc *sc, u_int offset, uint8_t value) {
262	bus_write_1(sc->sc_memr, offset, value);
263}
264
265static void
266cuda_idle(struct cuda_softc *sc)
267{
268	uint8_t reg;
269
270	reg = cuda_read_reg(sc, vBufB);
271	reg |= (vPB4 | vPB5);
272	cuda_write_reg(sc, vBufB, reg);
273}
274
275static void
276cuda_tip(struct cuda_softc *sc)
277{
278	uint8_t reg;
279
280	reg = cuda_read_reg(sc, vBufB);
281	reg &= ~vPB5;
282	cuda_write_reg(sc, vBufB, reg);
283}
284
285static void
286cuda_clear_tip(struct cuda_softc *sc)
287{
288	uint8_t reg;
289
290	reg = cuda_read_reg(sc, vBufB);
291	reg |= vPB5;
292	cuda_write_reg(sc, vBufB, reg);
293}
294
295static void
296cuda_in(struct cuda_softc *sc)
297{
298	uint8_t reg;
299
300	reg = cuda_read_reg(sc, vACR);
301	reg &= ~vSR_OUT;
302	cuda_write_reg(sc, vACR, reg);
303}
304
305static void
306cuda_out(struct cuda_softc *sc)
307{
308	uint8_t reg;
309
310	reg = cuda_read_reg(sc, vACR);
311	reg |= vSR_OUT;
312	cuda_write_reg(sc, vACR, reg);
313}
314
315static void
316cuda_toggle_ack(struct cuda_softc *sc)
317{
318	uint8_t reg;
319
320	reg = cuda_read_reg(sc, vBufB);
321	reg ^= vPB4;
322	cuda_write_reg(sc, vBufB, reg);
323}
324
325static void
326cuda_ack_off(struct cuda_softc *sc)
327{
328	uint8_t reg;
329
330	reg = cuda_read_reg(sc, vBufB);
331	reg |= vPB4;
332	cuda_write_reg(sc, vBufB, reg);
333}
334
335static int
336cuda_intr_state(struct cuda_softc *sc)
337{
338	return ((cuda_read_reg(sc, vBufB) & vPB3) == 0);
339}
340
341static int
342cuda_send(void *cookie, int poll, int length, uint8_t *msg)
343{
344	struct cuda_softc *sc = cookie;
345	device_t dev = sc->sc_dev;
346	struct cuda_packet *pkt;
347
348	if (sc->sc_state == CUDA_NOTREADY)
349		return (-1);
350
351	mtx_lock(&sc->sc_mutex);
352
353	pkt = STAILQ_FIRST(&sc->sc_freeq);
354	if (pkt == NULL) {
355		mtx_unlock(&sc->sc_mutex);
356		return (-1);
357	}
358
359	pkt->len = length - 1;
360	pkt->type = msg[0];
361	memcpy(pkt->data, &msg[1], pkt->len);
362
363	STAILQ_REMOVE_HEAD(&sc->sc_freeq, pkt_q);
364	STAILQ_INSERT_TAIL(&sc->sc_outq, pkt, pkt_q);
365
366	/*
367	 * If we already are sending a packet, we should bail now that this
368	 * one has been added to the queue.
369	 */
370
371	if (sc->sc_waiting) {
372		mtx_unlock(&sc->sc_mutex);
373		return (0);
374	}
375
376	cuda_send_outbound(sc);
377	mtx_unlock(&sc->sc_mutex);
378
379	if (sc->sc_polling || poll || cold)
380		cuda_poll(dev);
381
382	return (0);
383}
384
385static void
386cuda_send_outbound(struct cuda_softc *sc)
387{
388	struct cuda_packet *pkt;
389
390	mtx_assert(&sc->sc_mutex, MA_OWNED);
391
392	pkt = STAILQ_FIRST(&sc->sc_outq);
393	if (pkt == NULL)
394		return;
395
396	sc->sc_out_length = pkt->len + 1;
397	memcpy(sc->sc_out, &pkt->type, pkt->len + 1);
398	sc->sc_sent = 0;
399
400	STAILQ_REMOVE_HEAD(&sc->sc_outq, pkt_q);
401	STAILQ_INSERT_TAIL(&sc->sc_freeq, pkt, pkt_q);
402
403	sc->sc_waiting = 1;
404
405	cuda_poll(sc->sc_dev);
406
407	DELAY(150);
408
409	if (sc->sc_state == CUDA_IDLE && !cuda_intr_state(sc)) {
410		sc->sc_state = CUDA_OUT;
411		cuda_out(sc);
412		cuda_write_reg(sc, vSR, sc->sc_out[0]);
413		cuda_ack_off(sc);
414		cuda_tip(sc);
415	}
416}
417
418static void
419cuda_send_inbound(struct cuda_softc *sc)
420{
421	device_t dev;
422	struct cuda_packet *pkt;
423
424	dev = sc->sc_dev;
425
426	mtx_lock(&sc->sc_mutex);
427
428	while ((pkt = STAILQ_FIRST(&sc->sc_inq)) != NULL) {
429		STAILQ_REMOVE_HEAD(&sc->sc_inq, pkt_q);
430
431		mtx_unlock(&sc->sc_mutex);
432
433		/* check if we have a handler for this message */
434		switch (pkt->type) {
435		   case CUDA_ADB:
436			if (pkt->len > 2) {
437				adb_receive_raw_packet(sc->adb_bus,
438				    pkt->data[0],pkt->data[1],
439				    pkt->len - 2,&pkt->data[2]);
440			} else {
441				adb_receive_raw_packet(sc->adb_bus,
442				    pkt->data[0],pkt->data[1],0,NULL);
443			}
444			break;
445		   case CUDA_PSEUDO:
446			mtx_lock(&sc->sc_mutex);
447			if (pkt->data[0] == CMD_AUTOPOLL)
448				sc->sc_autopoll = 1;
449			mtx_unlock(&sc->sc_mutex);
450			break;
451		   case CUDA_ERROR:
452			/*
453			 * CUDA will throw errors if we miss a race between
454			 * sending and receiving packets. This is already
455			 * handled when we abort packet output to handle
456			 * this packet in cuda_intr(). Thus, we ignore
457			 * these messages.
458			 */
459			break;
460		   default:
461			device_printf(dev,"unknown CUDA command %d\n",
462			    pkt->type);
463			break;
464		}
465
466		mtx_lock(&sc->sc_mutex);
467
468		STAILQ_INSERT_TAIL(&sc->sc_freeq, pkt, pkt_q);
469	}
470
471	mtx_unlock(&sc->sc_mutex);
472}
473
474static void
475cuda_poll(device_t dev)
476{
477	struct cuda_softc *sc = device_get_softc(dev);
478
479	if (sc->sc_state == CUDA_IDLE && !cuda_intr_state(sc) &&
480	    !sc->sc_waiting)
481		return;
482
483	cuda_intr(dev);
484}
485
486static void
487cuda_intr(void *arg)
488{
489	device_t        dev;
490	struct cuda_softc *sc;
491
492	int i, ending, restart_send, process_inbound;
493	uint8_t reg;
494
495        dev = (device_t)arg;
496	sc = device_get_softc(dev);
497
498	mtx_lock(&sc->sc_mutex);
499
500	restart_send = 0;
501	process_inbound = 0;
502	reg = cuda_read_reg(sc, vIFR);
503	if ((reg & vSR_INT) != vSR_INT) {
504		mtx_unlock(&sc->sc_mutex);
505		return;
506	}
507
508	cuda_write_reg(sc, vIFR, 0x7f);	/* Clear interrupt */
509
510switch_start:
511	switch (sc->sc_state) {
512	case CUDA_IDLE:
513		/*
514		 * This is an unexpected packet, so grab the first (dummy)
515		 * byte, set up the proper vars, and tell the chip we are
516		 * starting to receive the packet by setting the TIP bit.
517		 */
518		sc->sc_in[1] = cuda_read_reg(sc, vSR);
519
520		if (cuda_intr_state(sc) == 0) {
521			/* must have been a fake start */
522
523			if (sc->sc_waiting) {
524				/* start over */
525				DELAY(150);
526				sc->sc_state = CUDA_OUT;
527				sc->sc_sent = 0;
528				cuda_out(sc);
529				cuda_write_reg(sc, vSR, sc->sc_out[1]);
530				cuda_ack_off(sc);
531				cuda_tip(sc);
532			}
533			break;
534		}
535
536		cuda_in(sc);
537		cuda_tip(sc);
538
539		sc->sc_received = 1;
540		sc->sc_state = CUDA_IN;
541		break;
542
543	case CUDA_IN:
544		sc->sc_in[sc->sc_received] = cuda_read_reg(sc, vSR);
545		ending = 0;
546
547		if (sc->sc_received > 255) {
548			/* bitch only once */
549			if (sc->sc_received == 256) {
550				device_printf(dev,"input overflow\n");
551				ending = 1;
552			}
553		} else
554			sc->sc_received++;
555
556		/* intr off means this is the last byte (end of frame) */
557		if (cuda_intr_state(sc) == 0) {
558			ending = 1;
559		} else {
560			cuda_toggle_ack(sc);
561		}
562
563		if (ending == 1) {	/* end of message? */
564			struct cuda_packet *pkt;
565
566			/* reset vars and signal the end of this frame */
567			cuda_idle(sc);
568
569			/* Queue up the packet */
570			pkt = STAILQ_FIRST(&sc->sc_freeq);
571			if (pkt != NULL) {
572				/* If we have a free packet, process it */
573
574				pkt->len = sc->sc_received - 2;
575				pkt->type = sc->sc_in[1];
576				memcpy(pkt->data, &sc->sc_in[2], pkt->len);
577
578				STAILQ_REMOVE_HEAD(&sc->sc_freeq, pkt_q);
579				STAILQ_INSERT_TAIL(&sc->sc_inq, pkt, pkt_q);
580
581				process_inbound = 1;
582			}
583
584			sc->sc_state = CUDA_IDLE;
585			sc->sc_received = 0;
586
587			/*
588			 * If there is something waiting to be sent out,
589			 * set everything up and send the first byte.
590			 */
591			if (sc->sc_waiting == 1) {
592				DELAY(1500);	/* required */
593				sc->sc_sent = 0;
594				sc->sc_state = CUDA_OUT;
595
596				/*
597				 * If the interrupt is on, we were too slow
598				 * and the chip has already started to send
599				 * something to us, so back out of the write
600				 * and start a read cycle.
601				 */
602				if (cuda_intr_state(sc)) {
603					cuda_in(sc);
604					cuda_idle(sc);
605					sc->sc_sent = 0;
606					sc->sc_state = CUDA_IDLE;
607					sc->sc_received = 0;
608					DELAY(150);
609					goto switch_start;
610				}
611
612				/*
613				 * If we got here, it's ok to start sending
614				 * so load the first byte and tell the chip
615				 * we want to send.
616				 */
617				cuda_out(sc);
618				cuda_write_reg(sc, vSR,
619				    sc->sc_out[sc->sc_sent]);
620				cuda_ack_off(sc);
621				cuda_tip(sc);
622			}
623		}
624		break;
625
626	case CUDA_OUT:
627		i = cuda_read_reg(sc, vSR);	/* reset SR-intr in IFR */
628
629		sc->sc_sent++;
630		if (cuda_intr_state(sc)) {	/* ADB intr low during write */
631			cuda_in(sc);	/* make sure SR is set to IN */
632			cuda_idle(sc);
633			sc->sc_sent = 0;	/* must start all over */
634			sc->sc_state = CUDA_IDLE;	/* new state */
635			sc->sc_received = 0;
636			sc->sc_waiting = 1;	/* must retry when done with
637						 * read */
638			DELAY(150);
639			goto switch_start;	/* process next state right
640						 * now */
641			break;
642		}
643		if (sc->sc_out_length == sc->sc_sent) {	/* check for done */
644			sc->sc_waiting = 0;	/* done writing */
645			sc->sc_state = CUDA_IDLE;	/* signal bus is idle */
646			cuda_in(sc);
647			cuda_idle(sc);
648		} else {
649			/* send next byte */
650			cuda_write_reg(sc, vSR, sc->sc_out[sc->sc_sent]);
651			cuda_toggle_ack(sc);	/* signal byte ready to
652							 * shift */
653		}
654		break;
655
656	case CUDA_NOTREADY:
657		break;
658
659	default:
660		break;
661	}
662
663	mtx_unlock(&sc->sc_mutex);
664
665	if (process_inbound)
666		cuda_send_inbound(sc);
667
668	mtx_lock(&sc->sc_mutex);
669	/* If we have another packet waiting, set it up */
670	if (!sc->sc_waiting && sc->sc_state == CUDA_IDLE)
671		cuda_send_outbound(sc);
672
673	mtx_unlock(&sc->sc_mutex);
674
675}
676
677static u_int
678cuda_adb_send(device_t dev, u_char command_byte, int len, u_char *data,
679    u_char poll)
680{
681	struct cuda_softc *sc = device_get_softc(dev);
682	uint8_t packet[16];
683	int i;
684
685	/* construct an ADB command packet and send it */
686	packet[0] = CUDA_ADB;
687	packet[1] = command_byte;
688	for (i = 0; i < len; i++)
689		packet[i + 2] = data[i];
690
691	cuda_send(sc, poll, len + 2, packet);
692
693	return (0);
694}
695
696static u_int
697cuda_adb_autopoll(device_t dev, uint16_t mask) {
698	struct cuda_softc *sc = device_get_softc(dev);
699
700	uint8_t cmd[] = {CUDA_PSEUDO, CMD_AUTOPOLL, mask != 0};
701
702	mtx_lock(&sc->sc_mutex);
703
704	if (cmd[2] == sc->sc_autopoll) {
705		mtx_unlock(&sc->sc_mutex);
706		return (0);
707	}
708
709	sc->sc_autopoll = -1;
710	cuda_send(sc, 1, 3, cmd);
711
712	mtx_unlock(&sc->sc_mutex);
713
714	return (0);
715}
716
717