Sync usage with man page.
[netbsd-mini2440.git] / sys / arch / evbppc / virtex / design_gsrd1.c
blob75d544f706b603247ea03d1e32bf509d7289efb0
1 /* $NetBSD: design_gsrd1.c,v 1.1.20.1 2007/05/28 20:01:42 freza Exp $ */
3 /*
4 * Copyright (c) 2006 Jachym Holecek
5 * All rights reserved.
7 * Written for DFC Design, s.r.o.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
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.
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.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: design_gsrd1.c,v 1.1.20.1 2007/05/28 20:01:42 freza Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/device.h>
38 #include <sys/kernel.h>
39 #include <sys/malloc.h>
41 #include <machine/cpu.h>
42 #include <machine/bus.h>
43 #include <machine/intr.h>
45 #include <powerpc/ibm4xx/dev/plbvar.h>
47 #include <evbppc/virtex/dev/xcvbusvar.h>
49 #include <evbppc/virtex/dev/xlcomreg.h>
50 #include <evbppc/virtex/dev/cdmacreg.h>
51 #include <evbppc/virtex/dev/temacreg.h>
52 #include <evbppc/virtex/dev/tftreg.h>
54 #include <evbppc/virtex/virtex.h>
55 #include <evbppc/virtex/dcr.h>
58 #define DCR_CDMAC_BASE 0x0140
59 #define DCR_XLCOM_BASE 0x0000
60 #define DCR_TEMAC_BASE 0x0030
61 #define DCR_LLFB_BASE 0x0080
63 #define CDMAC_TX0_STAT CDMAC_STAT_BASE(0)
64 #define CDMAC_RX0_STAT CDMAC_STAT_BASE(1)
65 #define CDMAC_TX1_STAT CDMAC_STAT_BASE(2)
66 #define CDMAC_RX1_STAT CDMAC_STAT_BASE(3)
68 #define CDMAC_TX0_BASE CDMAC_CTRL_BASE(0)
69 #define CDMAC_RX0_BASE CDMAC_CTRL_BASE(1)
70 #define CDMAC_TX1_BASE CDMAC_CTRL_BASE(2)
71 #define CDMAC_RX1_BASE CDMAC_CTRL_BASE(3)
73 #define CDMAC_INTR_LINE 2
74 #define CDMAC_NCHAN 4
76 #define IPL_CDMAC IPL_NET
77 #define splcdmac() splnet()
81 * CDMAC per-channel interrupt handler. CDMAC has only one interrupt signal
82 * shared by all channels on GSRD, so we have to dispatch channels manually.
84 * Note: we hardwire priority to IPL_NET, temac(4) is the only device that
85 * needs to service DMA interrupts anyway.
87 struct cdmac_intr_handle {
88 void (*cih_func)(void *);
89 void *cih_arg;
92 static void *cdmac_ih = NULL; /* real CDMAC intr */
93 static struct cdmac_intr_handle *cdmac_intrs[CDMAC_NCHAN];
97 * DCR bus space leaf access routines.
100 static void
101 xlcom0_write_4(bus_space_tag_t t, bus_space_handle_t h, uint32_t addr,
102 uint32_t val)
104 addr += h;
106 switch (addr) {
107 WCASE(DCR_XLCOM_BASE, XLCOM_TX_FIFO);
108 WCASE(DCR_XLCOM_BASE, XLCOM_STAT);
109 WCASE(DCR_XLCOM_BASE, XLCOM_CNTL);
110 WDEAD(addr);
114 static uint32_t
115 xlcom0_read_4(bus_space_tag_t t, bus_space_handle_t h, uint32_t addr)
117 uint32_t val;
119 addr += h;
121 switch (addr) {
122 RCASE(DCR_XLCOM_BASE, XLCOM_RX_FIFO);
123 RCASE(DCR_XLCOM_BASE, XLCOM_STAT);
124 RCASE(DCR_XLCOM_BASE, XLCOM_CNTL);
125 RDEAD(addr);
128 return (val);
131 static void
132 tft0_write_4(bus_space_tag_t t, bus_space_handle_t h, uint32_t addr,
133 uint32_t val)
135 addr += h;
137 switch (addr) {
138 WCASE(DCR_LLFB_BASE, TFT_CTRL);
139 WDEAD(addr);
143 static uint32_t
144 tft0_read_4(bus_space_tag_t t, bus_space_handle_t h, uint32_t addr)
146 uint32_t val;
148 addr += h;
150 switch (addr) {
151 RCASE(DCR_LLFB_BASE, TFT_CTRL);
152 RDEAD(addr);
155 return (val);
158 #define DOCHAN(op, channel) \
159 op(DCR_CDMAC_BASE, channel + CDMAC_NEXT); \
160 op(DCR_CDMAC_BASE, channel + CDMAC_CURADDR); \
161 op(DCR_CDMAC_BASE, channel + CDMAC_CURSIZE); \
162 op(DCR_CDMAC_BASE, channel + CDMAC_CURDESC)
164 static void
165 cdmac0_write_4(bus_space_tag_t t, bus_space_handle_t h, uint32_t addr,
166 uint32_t val)
168 addr += h;
170 switch (addr) {
171 WCASE(DCR_CDMAC_BASE, CDMAC_INTR);
172 WCASE(DCR_CDMAC_BASE, CDMAC_TX0_STAT);
173 WCASE(DCR_CDMAC_BASE, CDMAC_RX0_STAT);
174 WCASE(DCR_CDMAC_BASE, CDMAC_TX1_STAT);
175 WCASE(DCR_CDMAC_BASE, CDMAC_RX1_STAT);
176 DOCHAN(WCASE, CDMAC_TX0_BASE);
177 DOCHAN(WCASE, CDMAC_RX0_BASE);
178 DOCHAN(WCASE, CDMAC_TX1_BASE);
179 DOCHAN(WCASE, CDMAC_RX1_BASE);
180 WDEAD(addr);
184 static uint32_t
185 cdmac0_read_4(bus_space_tag_t t, bus_space_handle_t h, uint32_t addr)
187 uint32_t val;
189 addr += h;
191 switch (addr) {
192 RCASE(DCR_CDMAC_BASE, CDMAC_INTR);
193 RCASE(DCR_CDMAC_BASE, CDMAC_TX0_STAT);
194 RCASE(DCR_CDMAC_BASE, CDMAC_RX0_STAT);
195 RCASE(DCR_CDMAC_BASE, CDMAC_TX1_STAT);
196 RCASE(DCR_CDMAC_BASE, CDMAC_RX1_STAT);
197 DOCHAN(RCASE, CDMAC_TX0_BASE);
198 DOCHAN(RCASE, CDMAC_RX0_BASE);
199 DOCHAN(RCASE, CDMAC_TX1_BASE);
200 DOCHAN(RCASE, CDMAC_RX1_BASE);
201 RDEAD(addr);
204 return (val);
207 #undef DOCHAN
209 static void
210 temac0_write_4(bus_space_tag_t t, bus_space_handle_t h, uint32_t addr,
211 uint32_t val)
213 addr += h;
215 switch (addr) {
216 WCASE(DCR_TEMAC_BASE, TEMAC_RESET);
217 WDEAD(addr);
221 static const struct powerpc_bus_space xlcom_bst = {
222 DCR_BST_BODY(DCR_XLCOM_BASE, xlcom0_read_4, xlcom0_write_4)
225 static const struct powerpc_bus_space cdmac_bst = {
226 DCR_BST_BODY(DCR_CDMAC_BASE, cdmac0_read_4, cdmac0_write_4)
229 static const struct powerpc_bus_space temac_bst = {
230 DCR_BST_BODY(DCR_TEMAC_BASE, NULL, temac0_write_4)
233 static const struct powerpc_bus_space tft_bst = {
234 DCR_BST_BODY(DCR_LLFB_BASE, tft0_read_4, tft0_write_4)
238 * Master device configuration table for GSRD design.
240 static const struct gsrddev {
241 const char *gdv_name;
242 const char *gdv_attr;
243 bus_space_tag_t gdv_bst;
244 bus_addr_t gdv_addr;
245 int gdv_intr;
246 int gdv_rx_dma;
247 int gdv_tx_dma;
248 } gsrd_devices[] = {
249 { /* gsrd_devices[0] */
250 .gdv_name = "xlcom",
251 .gdv_attr = "xcvbus",
252 .gdv_bst = &xlcom_bst,
253 .gdv_addr = 0,
254 .gdv_intr = 0,
255 .gdv_rx_dma = -1,
256 .gdv_tx_dma = -1,
258 { /* gsrd_devices[1] */
259 .gdv_name = "temac",
260 .gdv_attr = "xcvbus",
261 .gdv_bst = &temac_bst,
262 .gdv_addr = 0,
263 .gdv_intr = 1,
264 .gdv_rx_dma = 3,
265 .gdv_tx_dma = 2,
267 { /* gsrd_devices[2] */
268 .gdv_name = "tft",
269 .gdv_attr = "llbus",
270 .gdv_bst = &tft_bst,
271 .gdv_addr = 0,
272 .gdv_intr = -1,
273 .gdv_rx_dma = -1,
274 .gdv_tx_dma = 0,
278 static struct ll_dmac *
279 virtex_mpmc_mapdma(int n, struct ll_dmac *chan)
281 if (n == -1)
282 return (NULL);
284 chan->dmac_iot = &cdmac_bst;
285 chan->dmac_ctrl_addr = CDMAC_CTRL_BASE(n);
286 chan->dmac_stat_addr = CDMAC_STAT_BASE(n);
287 chan->dmac_chan = n;
289 return (chan);
292 static int
293 cdmac_intr(void *arg)
295 uint32_t isr;
296 int i;
297 int did = 0;
299 isr = bus_space_read_4(&cdmac_bst, 0, CDMAC_INTR);
300 bus_space_write_4(&cdmac_bst, 0, CDMAC_INTR, isr); /* ack */
302 for (i = 0; i < CDMAC_NCHAN; i++)
303 if (ISSET(isr, CDMAC_CHAN_INTR(i)) &&
304 cdmac_intrs[i] != NULL) {
305 (cdmac_intrs[i]->cih_func)(cdmac_intrs[i]->cih_arg);
306 did++;
309 /* XXX: This happens all the time under load... bug? */
310 #if 0
311 if (did == 0)
312 aprint_normal("WARNING: stray cdmac isr 0x%x\n", isr);
313 #endif
315 return (0);
319 * Public interface.
322 void
323 virtex_autoconf(device_t self, struct plb_attach_args *paa)
325 struct xcvbus_attach_args vaa;
326 struct ll_dmac rx, tx;
327 int i;
329 /* Reset all CDMAC engines, disable interrupt. */
330 bus_space_write_4(&cdmac_bst, 0, CDMAC_STAT_BASE(0), CDMAC_STAT_RESET);
331 bus_space_write_4(&cdmac_bst, 0, CDMAC_STAT_BASE(1), CDMAC_STAT_RESET);
332 bus_space_write_4(&cdmac_bst, 0, CDMAC_STAT_BASE(2), CDMAC_STAT_RESET);
333 bus_space_write_4(&cdmac_bst, 0, CDMAC_STAT_BASE(3), CDMAC_STAT_RESET);
334 bus_space_write_4(&cdmac_bst, 0, CDMAC_INTR, 0);
336 vaa.vaa_dmat = paa->plb_dmat;
337 vaa._vaa_is_dcr = 1; /* XXX bst flag */
339 /* Attach all we have. */
340 for (i = 0; i < __arraycount(gsrd_devices); i++) {
341 const struct gsrddev *g = &gsrd_devices[i];
343 vaa.vaa_name = g->gdv_name;
344 vaa.vaa_addr = g->gdv_addr;
345 vaa.vaa_intr = g->gdv_intr;
346 vaa.vaa_iot = g->gdv_bst;
348 vaa.vaa_rx_dmac = virtex_mpmc_mapdma(g->gdv_rx_dma, &rx);
349 vaa.vaa_tx_dmac = virtex_mpmc_mapdma(g->gdv_tx_dma, &tx);
351 config_found_ia(self, g->gdv_attr, &vaa, xcvbus_print);
354 /* Setup the dispatch handler. */
355 cdmac_ih = intr_establish(CDMAC_INTR_LINE, IST_LEVEL, IPL_CDMAC,
356 cdmac_intr, NULL);
357 if (cdmac_ih == NULL)
358 panic("virtex_autoconf: could not establish cdmac intr");
360 /* Enable CDMAC interrupt. */
361 bus_space_write_4(&cdmac_bst, 0, CDMAC_INTR, ~CDMAC_INTR_MIE);
362 bus_space_write_4(&cdmac_bst, 0, CDMAC_INTR, CDMAC_INTR_MIE);
365 void *
366 ll_dmac_intr_establish(int chan, void (*func)(void *), void *arg)
368 struct cdmac_intr_handle *ih;
370 KASSERT(chan > 0 && chan < CDMAC_NCHAN);
372 /* We only allow one handler per channel, somewhat arbitrarily. */
373 if (cdmac_intrs[chan] != NULL)
374 return (NULL);
376 ih = malloc(sizeof(struct cdmac_intr_handle), M_DEVBUF,
377 cold ? M_NOWAIT : M_WAITOK);
378 if (ih == NULL)
379 return (NULL);
381 ih->cih_func = func;
382 ih->cih_arg = arg;
384 return (cdmac_intrs[chan] = ih);
387 void
388 ll_dmac_intr_disestablish(int chan, void *handle)
390 int s;
392 KASSERT(chan > 0 && chan < CDMAC_NCHAN);
393 KASSERT(cdmac_intrs[chan] == handle);
395 s = splcdmac();
396 cdmac_intrs[chan] = NULL;
397 splx(s);
399 free(handle, M_DEVBUF);
403 virtex_bus_space_tag(const char *xname, bus_space_tag_t *bst)
405 if (strncmp(xname, "xlcom", 5) == 0) {
406 *bst = &xlcom_bst;
407 return (0);
410 return (ENODEV);
413 void
414 virtex_machdep_init(vaddr_t endva, vsize_t maxsz, struct mem_region *phys,
415 struct mem_region *avail)
417 /* Nothing to do -- no memory-mapped devices. */
420 void
421 device_register(struct device *dev, void *aux)
423 /* Nothing to do -- no property hacks needed. */