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