1/* dvma.c:  Routines that are used to access DMA on the Sparc SBus.
2 *
3 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
4 */
5
6#include <linux/config.h>
7#include <linux/string.h>
8#include <linux/kernel.h>
9#include <linux/slab.h>
10#include <linux/init.h>
11#include <linux/delay.h>
12
13#include <asm/oplib.h>
14#include <asm/io.h>
15#include <asm/dma.h>
16#include <asm/sbus.h>
17
18struct sbus_dma *dma_chain;
19
20/* Print out the current values in the DMA control registers */
21static inline void dump_dma_regs(unsigned long dregs)
22{
23	printk("DMA CONTROL<%08x> ADDR<%08x> CNT<%08x> TEST<%08x>\n",
24	       sbus_readl(dregs + DMA_CSR), sbus_readl(dregs + DMA_ADDR),
25	       sbus_readl(dregs + DMA_COUNT), sbus_readl(dregs + DMA_TEST));
26}
27
28void __init init_one_dvma(struct sbus_dma *dma, int num_dma)
29{
30	printk("dma%d: ", num_dma);
31
32	dma->next = 0;
33	dma->running = 0;      /* No transfers going on as of yet */
34	dma->allocated = 0;    /* No one has allocated us yet */
35	switch(sbus_readl(dma->regs + DMA_CSR)&DMA_DEVICE_ID) {
36	case DMA_VERS0:
37		dma->revision = dvmarev0;
38		printk("Revision 0 ");
39		break;
40	case DMA_ESCV1:
41		dma->revision = dvmaesc1;
42		printk("ESC Revision 1 ");
43		break;
44	case DMA_VERS1:
45		dma->revision = dvmarev1;
46		printk("Revision 1 ");
47		break;
48	case DMA_VERS2:
49		dma->revision = dvmarev2;
50		printk("Revision 2 ");
51		break;
52	case DMA_VERHME:
53		dma->revision = dvmahme;
54		printk("HME DVMA gate array ");
55		break;
56	case DMA_VERSPLUS:
57		dma->revision = dvmarevplus;
58		printk("Revision 1 PLUS ");
59		break;
60	default:
61		printk("unknown dma version %08x",
62		       sbus_readl(dma->regs + DMA_CSR) & DMA_DEVICE_ID);
63		dma->allocated = 1;
64		break;
65	}
66	printk("\n");
67}
68
69/* Probe this SBus DMA module(s) */
70void __init dvma_init(struct sbus_bus *sbus)
71{
72	struct sbus_dev *this_dev;
73	struct sbus_dma *dma;
74	struct sbus_dma *dchain;
75	static int num_dma = 0;
76
77	for_each_sbusdev(this_dev, sbus) {
78		char *name = this_dev->prom_name;
79		int hme = 0;
80
81		if(!strcmp(name, "SUNW,fas"))
82			hme = 1;
83		else if(strcmp(name, "dma") &&
84			strcmp(name, "ledma") &&
85			strcmp(name, "espdma"))
86			continue;
87
88		/* Found one... */
89		dma = kmalloc(sizeof(struct sbus_dma), GFP_ATOMIC);
90
91		dma->sdev = this_dev;
92
93		/* Put at end of dma chain */
94		dchain = dma_chain;
95		if(dchain) {
96			while(dchain->next)
97				dchain = dchain->next;
98			dchain->next = dma;
99		} else {
100			/* We're the first in line */
101			dma_chain = dma;
102		}
103
104		dma->regs = sbus_ioremap(&dma->sdev->resource[0], 0,
105					 dma->sdev->resource[0].end - dma->sdev->resource[0].start + 1,
106					 "dma");
107
108		dma->node = dma->sdev->prom_node;
109
110		init_one_dvma(dma, num_dma++);
111	}
112}
113
114#ifdef CONFIG_SUN4
115
116#include <asm/sun4paddr.h>
117
118void __init sun4_dvma_init(void)
119{
120	struct sbus_dma *dma;
121	struct sbus_dma *dchain;
122	struct resource r;
123
124	if(sun4_dma_physaddr) {
125		dma = kmalloc(sizeof(struct sbus_dma), GFP_ATOMIC);
126
127		/* No SBUS */
128		dma->sdev = NULL;
129
130		/* Only one DMA device */
131		dma_chain = dma;
132
133		memset(&r, 0, sizeof(r));
134		r.start = sun4_dma_physaddr;
135		dma->regs = sbus_ioremap(&r, 0, PAGE_SIZE, "dma");
136
137		/* No prom node */
138		dma->node = 0x0;
139
140		init_one_dvma(dma, 0);
141	} else {
142	  	dma_chain = NULL;
143	}
144}
145
146#endif
147