xref: /netbsd-src/sys/arch/evbppc/virtex/dev/pstwo.c (revision cbab9cadce21ae72fac13910001079fff214cc29)
1 /* 	$NetBSD: pstwo.c,v 1.5 2012/10/27 17:17:51 chs Exp $ */
2 
3 /*
4  * Copyright (c) 2006 Jachym Holecek
5  * All rights reserved.
6  *
7  * Written for DFC Design, s.r.o.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: pstwo.c,v 1.5 2012/10/27 17:17:51 chs Exp $");
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/conf.h>
38 #include <sys/device.h>
39 #include <sys/file.h>
40 #include <sys/ioctl.h>
41 #include <sys/kernel.h>
42 #include <sys/proc.h>
43 #include <sys/time.h>
44 #include <sys/syslog.h>
45 
46 #include <machine/intr.h>
47 #include <sys/bus.h>
48 
49 #include <dev/pckbport/pckbportvar.h>
50 
51 #include <evbppc/virtex/virtex.h>
52 #include <evbppc/virtex/dev/xcvbusvar.h>
53 #include <evbppc/virtex/dev/pstworeg.h>
54 
55 
56 #define PSTWO_RXBUF_SIZE 	32
57 #define NEXT(idx) 		(void)((idx) = ((idx) + 1) % PSTWO_RXBUF_SIZE)
58 
59 struct pstwo_softc {
60 	device_t 		sc_dev;
61 	void 			*sc_ih;
62 
63 	bus_space_tag_t 	sc_iot;
64 	bus_space_handle_t 	sc_ioh;
65 
66 	pckbport_tag_t 		sc_pt;
67 	pckbport_slot_t 	sc_slot;
68 };
69 
70 static int 	pstwo_intr(void *);
71 static void 	pstwo_reset(bus_space_tag_t, bus_space_handle_t, bool);
72 #if 0
73 static void 	pstwo_printreg(struct pstwo_softc *);
74 #endif
75 
76 /* Interface to pckbport. */
77 static int 	pstwo_xt_translation(void *, pckbport_slot_t, int);
78 static int 	pstwo_send_devcmd(void *, pckbport_slot_t, u_char);
79 static int 	pstwo_poll_data1(void *, pckbport_slot_t);
80 static void 	pstwo_slot_enable(void *, pckbport_slot_t, int);
81 static void 	pstwo_intr_establish(void *, pckbport_slot_t);
82 static void 	pstwo_set_poll(void *, pckbport_slot_t, int);
83 
84 /* Generic device. */
85 static void 	pstwo_attach(device_t, device_t, void *);
86 
87 CFATTACH_DECL_NEW(pstwo, sizeof(struct pstwo_softc),
88     xcvbus_child_match, pstwo_attach, NULL, NULL);
89 
90 static struct pckbport_accessops pstwo_ops = {
91 	.t_xt_translation 	= pstwo_xt_translation,
92 	.t_send_devcmd 		= pstwo_send_devcmd,
93 	.t_poll_data1 		= pstwo_poll_data1,
94 	.t_slot_enable 		= pstwo_slot_enable,
95 	.t_intr_establish 	= pstwo_intr_establish,
96 	.t_set_poll 		= pstwo_set_poll,
97 };
98 
99 static void
pstwo_attach(device_t parent,device_t self,void * aux)100 pstwo_attach(device_t parent, device_t self, void *aux)
101 {
102 	struct xcvbus_attach_args 	*vaa = aux;
103 	struct pstwo_softc 		*sc = device_private(self);
104 	int 				i;
105 
106 	aprint_normal(": PS2 port\n");
107 
108 	if ((sc->sc_ih = intr_establish(vaa->vaa_intr, IST_LEVEL, IPL_TTY,
109 	    pstwo_intr, sc)) == NULL) {
110 		aprint_error_dev(self, "could not establish interrupt\n");
111 		return;
112 	}
113 
114 	sc->sc_dev = self;
115 	sc->sc_iot = vaa->vaa_iot;
116 
117 	if (bus_space_map(vaa->vaa_iot, vaa->vaa_addr, PSTWO_SIZE, 0,
118 	    &sc->sc_ioh) != 0) {
119 		aprint_error_dev(self, "could not map registers\n");
120 		return ;
121 	}
122 
123 	pstwo_reset(sc->sc_iot, sc->sc_ioh, 1);
124 
125 	sc->sc_pt = pckbport_attach(sc, &pstwo_ops);
126 
127 	/* Emulate the concept of "slot" to make pms(4)/pckbd(4) happy. */
128 	for (i = 0; i < PCKBPORT_NSLOTS; i++)
129 		if (pckbport_attach_slot(self, sc->sc_pt, i) != NULL) {
130 			sc->sc_slot = i;
131 			break; 			/* only one device allowed */
132 		}
133 }
134 
135 #if 0
136 static void
137 pstwo_printreg(struct pstwo_softc *sc)
138 {
139 #define PRINTREG(name, reg) \
140 	printf("%s: [0x%08x] %s -> 0x%08x\n", device_xname(sc->sc_dev), \
141 	    reg, name, bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg))
142 
143 	PRINTREG("status   ", PSTWO_STAT);
144 	PRINTREG("recv byte", PSTWO_RX_DATA);
145 	PRINTREG("intr stat", PSTWO_INTR_STAT);
146 	PRINTREG("intr mask", PSTWO_INTR_MSET);
147 
148 #undef PRINTREG
149 }
150 #endif
151 
152 static int
pstwo_intr(void * arg)153 pstwo_intr(void *arg)
154 {
155 	struct pstwo_softc 	*sc = arg;
156 	uint32_t 		stat;
157 
158 	stat = bus_space_read_4(sc->sc_iot, sc->sc_ioh, PSTWO_INTR_STAT);
159 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, PSTWO_INTR_ACK, stat);
160 
161 	if (stat & INTR_RX_FULL) {
162 		uint32_t 	val;
163 
164 		val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, PSTWO_RX_DATA);
165 		pckbportintr(sc->sc_pt, sc->sc_slot, DATA_RECV(val));
166 	}
167 	return (0);
168 }
169 
170 static void
pstwo_reset(bus_space_tag_t iot,bus_space_handle_t ioh,bool restart)171 pstwo_reset(bus_space_tag_t iot, bus_space_handle_t ioh, bool restart)
172 {
173 	bus_space_write_4(iot, ioh, PSTWO_CTRL, CTRL_RESET);
174 
175 	delay(10);
176 
177 	if (restart) {
178 		bus_space_write_4(iot, ioh, PSTWO_CTRL, ~CTRL_RESET);
179 		bus_space_write_4(iot, ioh, PSTWO_INTR_MSET, INTR_ANY);
180 	}
181 }
182 
183 /*
184  * pstwo_wait:
185  *
186  * 	Wait while status bits indicated by ${mask} have the value ${set}.
187  * 	Return zero on success, one on timeout.
188  */
189 static int
pstwo_wait(struct pstwo_softc * sc,uint32_t mask,bool set)190 pstwo_wait(struct pstwo_softc *sc, uint32_t mask, bool set)
191 {
192 	uint32_t 		val = (set ? mask : 0);
193 	int 			i = 1000;
194 
195 	while (i--) {
196 		if ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, PSTWO_STAT) &
197 		    mask) == val) {
198 			delay(10);
199 			continue;
200 		}
201 
202 		return (0);
203 	}
204 
205 	return (1);
206 }
207 
208 /*
209  * pckbport
210  */
211 
212 static int
pstwo_xt_translation(void * arg,pckbport_slot_t port,int enable)213 pstwo_xt_translation(void *arg, pckbport_slot_t port, int enable)
214 {
215 	/* Can't do translation, so disable succeeds & enable fails. */
216 	return (!enable);
217 }
218 
219 static int
pstwo_send_devcmd(void * arg,pckbport_slot_t slot,u_char byte)220 pstwo_send_devcmd(void *arg, pckbport_slot_t slot, u_char byte)
221 {
222 	struct pstwo_softc 	*sc = arg;
223 
224 	if (pstwo_wait(sc, STAT_TX_BUSY, 1))
225 		return (0);
226 
227 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, PSTWO_TX_DATA,
228 	    DATA_SEND(byte));
229 	return (1);
230 }
231 
232 static int
pstwo_poll_data1(void * arg,pckbport_slot_t slot)233 pstwo_poll_data1(void *arg, pckbport_slot_t slot)
234 {
235 	struct pstwo_softc 	*sc = arg;
236 	uint32_t 		val;
237 
238 	if (pstwo_wait(sc, STAT_RX_DONE, 0))
239 		return (-1);
240 
241 	val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, PSTWO_RX_DATA);
242 	return DATA_RECV(val);
243 }
244 
245 static void
pstwo_slot_enable(void * arg,pckbport_slot_t slot,int enable)246 pstwo_slot_enable(void *arg, pckbport_slot_t slot, int enable)
247 {
248 	/* Nothing to do */
249 }
250 
251 static void
pstwo_intr_establish(void * arg,pckbport_slot_t slot)252 pstwo_intr_establish(void *arg, pckbport_slot_t slot)
253 {
254 	/* XXX no-op because we don't support polled mode */
255 }
256 
257 static void
pstwo_set_poll(void * arg,pckbport_slot_t slot,int enable)258 pstwo_set_poll(void *arg, pckbport_slot_t slot, int enable)
259 {
260 	/* XXX only needed by console */
261 }
262