buddha.c 5.57 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
/*
2
 *  Amiga Buddha, Catweasel and X-Surf IDE Driver
Linus Torvalds's avatar
Linus Torvalds committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 *
 *	Copyright (C) 1997, 2001 by Geert Uytterhoeven and others
 *
 *  This driver was written based on the specifications in README.buddha and
 *  the X-Surf info from Inside_XSurf.txt available at
 *  http://www.jschoenfeld.com
 *
 *  This file is subject to the terms and conditions of the GNU General Public
 *  License.  See the file COPYING in the main directory of this archive for
 *  more details.
 *
 *  TODO:
 *    - test it :-)
 *    - tune the timings using the speed-register
 */

#include <linux/types.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/blkdev.h>
#include <linux/zorro.h>
#include <linux/ide.h>
#include <linux/init.h>
26
#include <linux/module.h>
Linus Torvalds's avatar
Linus Torvalds committed
27
28
29
30
31
32
33
34
35
36
37
38
39

#include <asm/amigahw.h>
#include <asm/amigaints.h>


    /*
     *  The Buddha has 2 IDE interfaces, the Catweasel has 3, X-Surf has 2
     */

#define BUDDHA_NUM_HWIFS	2
#define CATWEASEL_NUM_HWIFS	3
#define XSURF_NUM_HWIFS         2

40
41
#define MAX_NUM_HWIFS		3

Linus Torvalds's avatar
Linus Torvalds committed
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
    /*
     *  Bases of the IDE interfaces (relative to the board address)
     */

#define BUDDHA_BASE1	0x800
#define BUDDHA_BASE2	0xa00
#define BUDDHA_BASE3	0xc00

#define XSURF_BASE1     0xb000 /* 2.5" Interface */
#define XSURF_BASE2     0xd000 /* 3.5" Interface */

static u_int buddha_bases[CATWEASEL_NUM_HWIFS] __initdata = {
    BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3
};

static u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = {
     XSURF_BASE1, XSURF_BASE2
};

    /*
     *  Offsets from one of the above bases
     */

#define BUDDHA_CONTROL	0x11a

    /*
     *  Other registers
     */

#define BUDDHA_IRQ1	0xf00		/* MSB = 1, Harddisk is source of */
#define BUDDHA_IRQ2	0xf40		/* interrupt */
#define BUDDHA_IRQ3	0xf80

#define XSURF_IRQ1      0x7e
#define XSURF_IRQ2      0x7e

static int buddha_irqports[CATWEASEL_NUM_HWIFS] __initdata = {
    BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3
};

static int xsurf_irqports[XSURF_NUM_HWIFS] __initdata = {
    XSURF_IRQ1, XSURF_IRQ2
};

#define BUDDHA_IRQ_MR	0xfc0		/* master interrupt enable */


    /*
     *  Board information
     */

typedef enum BuddhaType_Enum {
    BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF
} BuddhaType;

97
static const char *buddha_board_name[] = { "Buddha", "Catweasel", "X-Surf" };
Linus Torvalds's avatar
Linus Torvalds committed
98
99
100
101
102

    /*
     *  Check and acknowledge the interrupt status
     */

103
static int buddha_test_irq(ide_hwif_t *hwif)
Linus Torvalds's avatar
Linus Torvalds committed
104
105
106
{
    unsigned char ch;

107
    ch = z_readb(hwif->io_ports.irq_addr);
Linus Torvalds's avatar
Linus Torvalds committed
108
109
110
111
112
    if (!(ch & 0x80))
	    return 0;
    return 1;
}

113
static void xsurf_clear_irq(ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
114
{
115
116
117
118
    /*
     * X-Surf needs 0 written to IRQ register to ensure ISA bit A11 stays at 0
     */
    z_writeb(0, drive->hwif->io_ports.irq_addr);
Linus Torvalds's avatar
Linus Torvalds committed
119
120
}

121
static void __init buddha_setup_ports(struct ide_hw *hw, unsigned long base,
122
				      unsigned long ctl, unsigned long irq_port)
123
124
125
126
127
{
	int i;

	memset(hw, 0, sizeof(*hw));

128
	hw->io_ports.data_addr = base;
129
130

	for (i = 1; i < 8; i++)
131
		hw->io_ports_array[i] = base + 2 + i * 4;
132

133
134
	hw->io_ports.ctl_addr = ctl;
	hw->io_ports.irq_addr = irq_port;
135
136
137
138

	hw->irq = IRQ_AMIGA_PORTS;
}

139
140
141
142
static const struct ide_port_ops buddha_port_ops = {
	.test_irq		= buddha_test_irq,
};

143
144
static const struct ide_port_ops xsurf_port_ops = {
	.clear_irq		= xsurf_clear_irq,
145
	.test_irq		= buddha_test_irq,
146
147
};

148
static const struct ide_port_info buddha_port_info = {
149
	.port_ops		= &buddha_port_ops,
150
	.host_flags		= IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
151
	.irq_flags		= IRQF_SHARED,
152
	.chipset		= ide_generic,
153
154
};

Linus Torvalds's avatar
Linus Torvalds committed
155
156
157
158
    /*
     *  Probe for a Buddha or Catweasel IDE interface
     */

159
static int __init buddha_init(void)
Linus Torvalds's avatar
Linus Torvalds committed
160
161
162
163
{
	struct zorro_dev *z = NULL;
	u_long buddha_board = 0;
	BuddhaType type;
164
	int buddha_num_hwifs, i;
Linus Torvalds's avatar
Linus Torvalds committed
165
166
167

	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
		unsigned long board;
168
		struct ide_hw hw[MAX_NUM_HWIFS], *hws[MAX_NUM_HWIFS];
169
		struct ide_port_info d = buddha_port_info;
170

Linus Torvalds's avatar
Linus Torvalds committed
171
172
173
174
175
176
177
178
179
		if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) {
			buddha_num_hwifs = BUDDHA_NUM_HWIFS;
			type=BOARD_BUDDHA;
		} else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL) {
			buddha_num_hwifs = CATWEASEL_NUM_HWIFS;
			type=BOARD_CATWEASEL;
		} else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF) {
			buddha_num_hwifs = XSURF_NUM_HWIFS;
			type=BOARD_XSURF;
180
			d.port_ops = &xsurf_port_ops;
Linus Torvalds's avatar
Linus Torvalds committed
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
		} else 
			continue;
		
		board = z->resource.start;

		if(type != BOARD_XSURF) {
			if (!request_mem_region(board+BUDDHA_BASE1, 0x800, "IDE"))
				continue;
		} else {
			if (!request_mem_region(board+XSURF_BASE1, 0x1000, "IDE"))
				continue;
			if (!request_mem_region(board+XSURF_BASE2, 0x1000, "IDE"))
				goto fail_base2;
			if (!request_mem_region(board+XSURF_IRQ1, 0x8, "IDE")) {
				release_mem_region(board+XSURF_BASE2, 0x1000);
fail_base2:
				release_mem_region(board+XSURF_BASE1, 0x1000);
				continue;
			}
		}	  
		buddha_board = ZTWO_VADDR(board);
		
		/* write to BUDDHA_IRQ_MR to enable the board IRQ */
		/* X-Surf doesn't have this.  IRQs are always on */
		if (type != BOARD_XSURF)
			z_writeb(0, buddha_board+BUDDHA_IRQ_MR);
207
208
209
210

		printk(KERN_INFO "ide: %s IDE controller\n",
				 buddha_board_name[type]);

211
212
213
214
215
216
217
		for (i = 0; i < buddha_num_hwifs; i++) {
			unsigned long base, ctl, irq_port;

			if (type != BOARD_XSURF) {
				base = buddha_board + buddha_bases[i];
				ctl = base + BUDDHA_CONTROL;
				irq_port = buddha_board + buddha_irqports[i];
Linus Torvalds's avatar
Linus Torvalds committed
218
			} else {
219
220
221
222
223
224
				base = buddha_board + xsurf_bases[i];
				/* X-Surf has no CS1* (Control/AltStat) */
				ctl = 0;
				irq_port = buddha_board + xsurf_irqports[i];
			}

225
			buddha_setup_ports(&hw[i], base, ctl, irq_port);
226

227
			hws[i] = &hw[i];
Linus Torvalds's avatar
Linus Torvalds committed
228
		}
229

230
		ide_host_add(&d, hws, i, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
231
	}
232
233

	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
234
}
235
236

module_init(buddha_init);
237
238

MODULE_LICENSE("GPL");