buddha.c 5.48 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
26
27
28
29
30
31
32
33
34
35
36
37
38
 *
 *	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>

#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

39
40
#define MAX_NUM_HWIFS		3

Linus Torvalds's avatar
Linus Torvalds committed
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
    /*
     *  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;

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

    /*
     *  Check and acknowledge the interrupt status
     */

static int buddha_ack_intr(ide_hwif_t *hwif)
{
    unsigned char ch;

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

112
static void xsurf_clear_irq(ide_drive_t *drive)
Linus Torvalds's avatar
Linus Torvalds committed
113
{
114
115
116
117
    /*
     * 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
118
119
}

120
static void __init buddha_setup_ports(struct ide_hw *hw, unsigned long base,
121
122
123
124
125
126
127
				      unsigned long ctl, unsigned long irq_port,
				      ide_ack_intr_t *ack_intr)
{
	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
139

	hw->irq = IRQ_AMIGA_PORTS;
	hw->ack_intr = ack_intr;
}

140
141
142
143
static const struct ide_port_ops xsurf_port_ops = {
	.clear_irq		= xsurf_clear_irq,
};

144
static const struct ide_port_info buddha_port_info = {
145
	.host_flags		= IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
146
	.irq_flags		= IRQF_SHARED,
147
	.chipset		= ide_generic,
148
149
};

Linus Torvalds's avatar
Linus Torvalds committed
150
151
152
153
    /*
     *  Probe for a Buddha or Catweasel IDE interface
     */

154
static int __init buddha_init(void)
Linus Torvalds's avatar
Linus Torvalds committed
155
156
157
158
{
	struct zorro_dev *z = NULL;
	u_long buddha_board = 0;
	BuddhaType type;
159
	int buddha_num_hwifs, i;
Linus Torvalds's avatar
Linus Torvalds committed
160
161
162

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

Linus Torvalds's avatar
Linus Torvalds committed
166
167
168
169
170
171
172
173
174
		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;
175
			d.port_ops = &xsurf_port_ops;
Linus Torvalds's avatar
Linus Torvalds committed
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
		} 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);
202
203
204
205

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

206
207
208
209
210
211
212
		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
213
			} else {
214
215
216
217
218
219
				base = buddha_board + xsurf_bases[i];
				/* X-Surf has no CS1* (Control/AltStat) */
				ctl = 0;
				irq_port = buddha_board + xsurf_irqports[i];
			}

220
			buddha_setup_ports(&hw[i], base, ctl, irq_port,
221
					   buddha_ack_intr);
222

223
			hws[i] = &hw[i];
Linus Torvalds's avatar
Linus Torvalds committed
224
		}
225

226
		ide_host_add(&d, hws, i, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
227
	}
228
229

	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
230
}
231
232

module_init(buddha_init);
233
234

MODULE_LICENSE("GPL");