summaryrefslogtreecommitdiffstats
path: root/drivers/sbus/dvma.c
blob: f4ff7e539ffa11345796f23f67a1432aa9151cba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/* dvma.c:  Routines that are used to access DMA on the Sparc SBus.
 *
 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
 */

#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/malloc.h>
#include <linux/init.h>

#include <asm/oplib.h>
#include <asm/delay.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/sbus.h>

struct Linux_SBus_DMA *dma_chain;

/* Print out the current values in the DMA control registers */
extern __inline__ void
dump_dma_regs(struct sparc_dma_registers *dregs)
{
	printk("DMA CONTROL<%08lx>  ADDR<%08lx> CNT<%08lx> TEST<%08lx>\n",
	       (unsigned long) dregs->cond_reg,
	       (unsigned long) dregs->st_addr,
	       (unsigned long) dregs->cnt,
	       (unsigned long) dregs->dma_test);
	return;
}

__initfunc(void
init_one_dvma(struct Linux_SBus_DMA *dma, int num_dma))
{
	printk("dma%d: ", num_dma);
	
	dma->next = 0;
	dma->running=0;      /* No transfers going on as of yet */
	dma->allocated=0;    /* No one has allocated us yet */
	switch((dma->regs->cond_reg)&DMA_DEVICE_ID) {
	case DMA_VERS0:
		dma->revision=dvmarev0;
		printk("Revision 0 ");
		break;
	case DMA_ESCV1:
		dma->revision=dvmaesc1;
		printk("ESC Revision 1 ");
		break;
	case DMA_VERS1:
		dma->revision=dvmarev1;
		printk("Revision 1 ");
		break;
	case DMA_VERS2:
		dma->revision=dvmarev2;
		printk("Revision 2 ");
		break;
	case DMA_VERHME:
		dma->revision=dvmahme;
		printk("HME DVMA gate array ");
		break;
	case DMA_VERSPLUS:
		dma->revision=dvmarevplus;
		printk("Revision 1 PLUS ");
		break;
	default:
		printk("unknown dma version %x",
		       (dma->regs->cond_reg)&DMA_DEVICE_ID);
		dma->allocated = 1;
		break;
	}
	printk("\n");
#if 0 /* Clutters up the screen */
	dump_dma_regs(dma->regs);
#endif
}

/* Probe this SBus DMA module(s) */
__initfunc(unsigned long
dvma_init(struct linux_sbus *sbus, unsigned long memory_start))
{
	struct linux_sbus_device *this_dev;
	struct Linux_SBus_DMA *dma;
	struct Linux_SBus_DMA *dchain;
	static int num_dma=0;

	for_each_sbusdev(this_dev, sbus) {
		int hme = 0;

		if(!strcmp(this_dev->prom_name, "SUNW,fas"))
			hme = 1;
		else if(strcmp(this_dev->prom_name, "dma") &&
			strcmp(this_dev->prom_name, "ledma") &&
			strcmp(this_dev->prom_name, "espdma"))
			continue;

		/* Found one... */
		dma = (struct Linux_SBus_DMA *) memory_start;
		memory_start += sizeof(struct Linux_SBus_DMA);

		dma->SBus_dev = this_dev;

		/* Put at end of dma chain */
		dchain = dma_chain;
		if(dchain) {
			while(dchain->next) dchain=dchain->next;
			dchain->next=dma;
		} else {
			/* We're the first in line */
			dma_chain=dma;
		}

		/* The constant PAGE_SIZE that is passed to sparc_alloc_io makes the
		 * routine only alloc 1 page, that was what the original code did
		 */
		if(hme) /* On HME cards, dvma lives with esp, 2 reg sets. */
			prom_apply_sbus_ranges(sbus, dma->SBus_dev->reg_addrs,
					       0x2, dma->SBus_dev);
		else    /* All others have only 1 reg set. */
			prom_apply_sbus_ranges(sbus, dma->SBus_dev->reg_addrs,
					       0x1, dma->SBus_dev);
		dma->regs = (struct sparc_dma_registers *)
			sparc_alloc_io (dma->SBus_dev->reg_addrs[0].phys_addr, 0,
					PAGE_SIZE, "dma",
					dma->SBus_dev->reg_addrs[0].which_io, 0x0);

		dma->node = dma->SBus_dev->prom_node;
		
		init_one_dvma(dma, num_dma++);
		
	};  /* while(this_dev) */

	return memory_start;
}

#ifdef CONFIG_SUN4

#include <asm/sun4paddr.h>

__initfunc(unsigned long
sun4_dvma_init(unsigned long memory_start))
{
	struct Linux_SBus_DMA *dma;
	struct Linux_SBus_DMA *dchain;

	dma = (struct Linux_SBus_DMA *) memory_start;
	memory_start += sizeof(struct Linux_SBus_DMA);

	/* No SBUS */
	dma->SBus_dev = 0x0;

	/* Only one DMA device */
	dma_chain=dma;

	dma->regs = (struct sparc_dma_registers *)
		sparc_alloc_io (SUN4_300_DMA_PHYSADDR, 0,
				PAGE_SIZE, "dma", 0x0, 0x0);

	/* No prom node */
	dma->node = 0x0;

	init_one_dvma(dma, 0);
	return memory_start;
}

#endif