Blame view

drivers/ata/pata_icside.c 17.3 KB
73b6a2be8   Russell King   [ARM] Add support...
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
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/blkdev.h>
  #include <scsi/scsi_host.h>
  #include <linux/ata.h>
  #include <linux/libata.h>
  
  #include <asm/dma.h>
  #include <asm/ecard.h>
  
  #define DRV_NAME	"pata_icside"
  
  #define ICS_IDENT_OFFSET		0x2280
  
  #define ICS_ARCIN_V5_INTRSTAT		0x0000
  #define ICS_ARCIN_V5_INTROFFSET		0x0004
  
  #define ICS_ARCIN_V6_INTROFFSET_1	0x2200
  #define ICS_ARCIN_V6_INTRSTAT_1		0x2290
  #define ICS_ARCIN_V6_INTROFFSET_2	0x3200
  #define ICS_ARCIN_V6_INTRSTAT_2		0x3290
  
  struct portinfo {
  	unsigned int dataoffset;
  	unsigned int ctrloffset;
  	unsigned int stepping;
  };
  
  static const struct portinfo pata_icside_portinfo_v5 = {
  	.dataoffset	= 0x2800,
  	.ctrloffset	= 0x2b80,
  	.stepping	= 6,
  };
  
  static const struct portinfo pata_icside_portinfo_v6_1 = {
  	.dataoffset	= 0x2000,
  	.ctrloffset	= 0x2380,
  	.stepping	= 6,
  };
  
  static const struct portinfo pata_icside_portinfo_v6_2 = {
  	.dataoffset	= 0x3000,
  	.ctrloffset	= 0x3380,
  	.stepping	= 6,
  };
  
  #define PATA_ICSIDE_MAX_SG	128
  
  struct pata_icside_state {
  	void __iomem *irq_port;
  	void __iomem *ioc_base;
  	unsigned int type;
  	unsigned int dma;
  	struct {
  		u8 port_sel;
  		u8 disabled;
  		unsigned int speed[ATA_MAX_DEVICES];
  	} port[2];
  	struct scatterlist sg[PATA_ICSIDE_MAX_SG];
  };
f95637d2c   Russell King   [ARM] pata_icside...
62
63
64
65
66
67
68
69
70
71
72
  struct pata_icside_info {
  	struct pata_icside_state *state;
  	struct expansion_card	*ec;
  	void __iomem		*base;
  	void __iomem		*irqaddr;
  	unsigned int		irqmask;
  	const expansioncard_ops_t *irqops;
  	unsigned int		mwdma_mask;
  	unsigned int		nr_ports;
  	const struct portinfo	*port[2];
  };
73b6a2be8   Russell King   [ARM] Add support...
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
165
166
167
168
169
170
171
172
173
174
175
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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
  #define ICS_TYPE_A3IN	0
  #define ICS_TYPE_A3USER	1
  #define ICS_TYPE_V6	3
  #define ICS_TYPE_V5	15
  #define ICS_TYPE_NOTYPE	((unsigned int)-1)
  
  /* ---------------- Version 5 PCB Support Functions --------------------- */
  /* Prototype: pata_icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
   * Purpose  : enable interrupts from card
   */
  static void pata_icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
  {
  	struct pata_icside_state *state = ec->irq_data;
  
  	writeb(0, state->irq_port + ICS_ARCIN_V5_INTROFFSET);
  }
  
  /* Prototype: pata_icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
   * Purpose  : disable interrupts from card
   */
  static void pata_icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
  {
  	struct pata_icside_state *state = ec->irq_data;
  
  	readb(state->irq_port + ICS_ARCIN_V5_INTROFFSET);
  }
  
  static const expansioncard_ops_t pata_icside_ops_arcin_v5 = {
  	.irqenable	= pata_icside_irqenable_arcin_v5,
  	.irqdisable	= pata_icside_irqdisable_arcin_v5,
  };
  
  
  /* ---------------- Version 6 PCB Support Functions --------------------- */
  /* Prototype: pata_icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
   * Purpose  : enable interrupts from card
   */
  static void pata_icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
  {
  	struct pata_icside_state *state = ec->irq_data;
  	void __iomem *base = state->irq_port;
  
  	if (!state->port[0].disabled)
  		writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1);
  	if (!state->port[1].disabled)
  		writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2);
  }
  
  /* Prototype: pata_icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
   * Purpose  : disable interrupts from card
   */
  static void pata_icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
  {
  	struct pata_icside_state *state = ec->irq_data;
  
  	readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
  	readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
  }
  
  /* Prototype: pata_icside_irqprobe(struct expansion_card *ec)
   * Purpose  : detect an active interrupt from card
   */
  static int pata_icside_irqpending_arcin_v6(struct expansion_card *ec)
  {
  	struct pata_icside_state *state = ec->irq_data;
  
  	return readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
  	       readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
  }
  
  static const expansioncard_ops_t pata_icside_ops_arcin_v6 = {
  	.irqenable	= pata_icside_irqenable_arcin_v6,
  	.irqdisable	= pata_icside_irqdisable_arcin_v6,
  	.irqpending	= pata_icside_irqpending_arcin_v6,
  };
  
  
  /*
   * SG-DMA support.
   *
   * Similar to the BM-DMA, but we use the RiscPCs IOMD DMA controllers.
   * There is only one DMA controller per card, which means that only
   * one drive can be accessed at one time.  NOTE! We do not enforce that
   * here, but we rely on the main IDE driver spotting that both
   * interfaces use the same IRQ, which should guarantee this.
   */
  
  /*
   * Configure the IOMD to give the appropriate timings for the transfer
   * mode being requested.  We take the advice of the ATA standards, and
   * calculate the cycle time based on the transfer mode, and the EIDE
   * MW DMA specs that the drive provides in the IDENTIFY command.
   *
   * We have the following IOMD DMA modes to choose from:
   *
   *	Type	Active		Recovery	Cycle
   *	A	250 (250)	312 (550)	562 (800)
   *	B	187 (200)	250 (550)	437 (750)
   *	C	125 (125)	125 (375)	250 (500)
   *	D	62  (50)	125 (375)	187 (425)
   *
   * (figures in brackets are actual measured timings on DIOR/DIOW)
   *
   * However, we also need to take care of the read/write active and
   * recovery timings:
   *
   *			Read	Write
   *  	Mode	Active	-- Recovery --	Cycle	IOMD type
   *	MW0	215	50	215	480	A
   *	MW1	80	50	50	150	C
   *	MW2	70	25	25	120	C
   */
  static void pata_icside_set_dmamode(struct ata_port *ap, struct ata_device *adev)
  {
  	struct pata_icside_state *state = ap->host->private_data;
  	struct ata_timing t;
  	unsigned int cycle;
  	char iomd_type;
  
  	/*
  	 * DMA is based on a 16MHz clock
  	 */
  	if (ata_timing_compute(adev, adev->dma_mode, &t, 1000, 1))
  		return;
  
  	/*
  	 * Choose the IOMD cycle timing which ensure that the interface
  	 * satisfies the measured active, recovery and cycle times.
  	 */
  	if (t.active <= 50 && t.recover <= 375 && t.cycle <= 425)
  		iomd_type = 'D', cycle = 187;
  	else if (t.active <= 125 && t.recover <= 375 && t.cycle <= 500)
  		iomd_type = 'C', cycle = 250;
  	else if (t.active <= 200 && t.recover <= 550 && t.cycle <= 750)
  		iomd_type = 'B', cycle = 437;
  	else
  		iomd_type = 'A', cycle = 562;
  
  	ata_dev_printk(adev, KERN_INFO, "timings: act %dns rec %dns cyc %dns (%c)
  ",
  		t.active, t.recover, t.cycle, iomd_type);
  
  	state->port[ap->port_no].speed[adev->devno] = cycle;
  }
  
  static void pata_icside_bmdma_setup(struct ata_queued_cmd *qc)
  {
  	struct ata_port *ap = qc->ap;
  	struct pata_icside_state *state = ap->host->private_data;
  	struct scatterlist *sg, *rsg = state->sg;
  	unsigned int write = qc->tf.flags & ATA_TFLAG_WRITE;
  
  	/*
  	 * We are simplex; BUG if we try to fiddle with DMA
  	 * while it's active.
  	 */
  	BUG_ON(dma_channel_active(state->dma));
  
  	/*
  	 * Copy ATAs scattered sg list into a contiguous array of sg
  	 */
  	ata_for_each_sg(sg, qc) {
  		memcpy(rsg, sg, sizeof(*sg));
  		rsg++;
  	}
  
  	/*
  	 * Route the DMA signals to the correct interface
  	 */
  	writeb(state->port[ap->port_no].port_sel, state->ioc_base);
  
  	set_dma_speed(state->dma, state->port[ap->port_no].speed[qc->dev->devno]);
  	set_dma_sg(state->dma, state->sg, rsg - state->sg);
  	set_dma_mode(state->dma, write ? DMA_MODE_WRITE : DMA_MODE_READ);
  
  	/* issue r/w command */
  	ap->ops->exec_command(ap, &qc->tf);
  }
  
  static void pata_icside_bmdma_start(struct ata_queued_cmd *qc)
  {
  	struct ata_port *ap = qc->ap;
  	struct pata_icside_state *state = ap->host->private_data;
  
  	BUG_ON(dma_channel_active(state->dma));
  	enable_dma(state->dma);
  }
  
  static void pata_icside_bmdma_stop(struct ata_queued_cmd *qc)
  {
  	struct ata_port *ap = qc->ap;
  	struct pata_icside_state *state = ap->host->private_data;
  
  	disable_dma(state->dma);
  
  	/* see ata_bmdma_stop */
  	ata_altstatus(ap);
  }
  
  static u8 pata_icside_bmdma_status(struct ata_port *ap)
  {
  	struct pata_icside_state *state = ap->host->private_data;
  	void __iomem *irq_port;
  
  	irq_port = state->irq_port + (ap->port_no ? ICS_ARCIN_V6_INTRSTAT_2 :
  						    ICS_ARCIN_V6_INTRSTAT_1);
  
  	return readb(irq_port) & 1 ? ATA_DMA_INTR : 0;
  }
f95637d2c   Russell King   [ARM] pata_icside...
282
  static int icside_dma_init(struct pata_icside_info *info)
73b6a2be8   Russell King   [ARM] Add support...
283
  {
f95637d2c   Russell King   [ARM] pata_icside...
284
285
  	struct pata_icside_state *state = info->state;
  	struct expansion_card *ec = info->ec;
73b6a2be8   Russell King   [ARM] Add support...
286
287
288
289
290
291
292
293
294
  	int i;
  
  	for (i = 0; i < ATA_MAX_DEVICES; i++) {
  		state->port[0].speed[i] = 480;
  		state->port[1].speed[i] = 480;
  	}
  
  	if (ec->dma != NO_DMA && !request_dma(ec->dma, DRV_NAME)) {
  		state->dma = ec->dma;
f95637d2c   Russell King   [ARM] pata_icside...
295
  		info->mwdma_mask = 0x07;	/* MW0..2 */
73b6a2be8   Russell King   [ARM] Add support...
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
  	}
  
  	return 0;
  }
  
  
  static int pata_icside_port_start(struct ata_port *ap)
  {
  	/* No PRD to alloc */
  	return ata_pad_alloc(ap, ap->dev);
  }
  
  static struct scsi_host_template pata_icside_sht = {
  	.module			= THIS_MODULE,
  	.name			= DRV_NAME,
  	.ioctl			= ata_scsi_ioctl,
  	.queuecommand		= ata_scsi_queuecmd,
  	.can_queue		= ATA_DEF_QUEUE,
  	.this_id		= ATA_SHT_THIS_ID,
  	.sg_tablesize		= PATA_ICSIDE_MAX_SG,
  	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
  	.emulated		= ATA_SHT_EMULATED,
  	.use_clustering		= ATA_SHT_USE_CLUSTERING,
  	.proc_name		= DRV_NAME,
  	.dma_boundary		= ~0, /* no dma boundaries */
  	.slave_configure	= ata_scsi_slave_config,
  	.slave_destroy		= ata_scsi_slave_destroy,
  	.bios_param		= ata_std_bios_param,
  };
  
  /* wish this was exported from libata-core */
  static void ata_dummy_noret(struct ata_port *port)
  {
  }
eba84481c   Russell King   [ARM] pata_icside...
330
  static void pata_icside_postreset(struct ata_port *ap, unsigned int *classes)
73b6a2be8   Russell King   [ARM] Add support...
331
332
  {
  	struct pata_icside_state *state = ap->host->private_data;
eba84481c   Russell King   [ARM] pata_icside...
333
334
  	if (classes[0] != ATA_DEV_NONE || classes[1] != ATA_DEV_NONE)
  		return ata_std_postreset(ap, classes);
73b6a2be8   Russell King   [ARM] Add support...
335
336
337
338
339
340
341
342
343
344
345
346
347
348
  
  	state->port[ap->port_no].disabled = 1;
  
  	if (state->type == ICS_TYPE_V6) {
  		/*
  		 * Disable interrupts from this port, otherwise we
  		 * receive spurious interrupts from the floating
  		 * interrupt line.
  		 */
  		void __iomem *irq_port = state->irq_port +
  				(ap->port_no ? ICS_ARCIN_V6_INTROFFSET_2 : ICS_ARCIN_V6_INTROFFSET_1);
  		readb(irq_port);
  	}
  }
eba84481c   Russell King   [ARM] pata_icside...
349
350
351
352
353
  static void pata_icside_error_handler(struct ata_port *ap)
  {
  	ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, NULL,
  			   pata_icside_postreset);
  }
73b6a2be8   Russell King   [ARM] Add support...
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
  static u8 pata_icside_irq_ack(struct ata_port *ap, unsigned int chk_drq)
  {
  	unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
  	u8 status;
  
  	status = ata_busy_wait(ap, bits, 1000);
  	if (status & bits)
  		if (ata_msg_err(ap))
  			printk(KERN_ERR "abnormal status 0x%X
  ", status);
  
  	if (ata_msg_intr(ap))
  		printk(KERN_INFO "%s: irq ack: drv_stat 0x%X
  ",
  			__FUNCTION__, status);
  
  	return status;
  }
  
  static struct ata_port_operations pata_icside_port_ops = {
eba84481c   Russell King   [ARM] pata_icside...
374
  	.port_disable		= ata_port_disable,
73b6a2be8   Russell King   [ARM] Add support...
375
376
377
378
379
380
381
382
  
  	.set_dmamode		= pata_icside_set_dmamode,
  
  	.tf_load		= ata_tf_load,
  	.tf_read		= ata_tf_read,
  	.exec_command		= ata_exec_command,
  	.check_status		= ata_check_status,
  	.dev_select		= ata_std_dev_select,
f95637d2c   Russell King   [ARM] pata_icside...
383
  	.cable_detect		= ata_cable_40wire,
73b6a2be8   Russell King   [ARM] Add support...
384
385
386
387
388
389
390
391
392
393
394
  	.bmdma_setup		= pata_icside_bmdma_setup,
  	.bmdma_start		= pata_icside_bmdma_start,
  
  	.data_xfer		= ata_data_xfer_noirq,
  
  	/* no need to build any PRD tables for DMA */
  	.qc_prep		= ata_noop_qc_prep,
  	.qc_issue		= ata_qc_issue_prot,
  
  	.freeze			= ata_bmdma_freeze,
  	.thaw			= ata_bmdma_thaw,
eba84481c   Russell King   [ARM] pata_icside...
395
  	.error_handler		= pata_icside_error_handler,
73b6a2be8   Russell King   [ARM] Add support...
396
  	.post_internal_cmd	= pata_icside_bmdma_stop,
73b6a2be8   Russell King   [ARM] Add support...
397
398
399
400
401
402
403
404
405
  	.irq_clear		= ata_dummy_noret,
  	.irq_on			= ata_irq_on,
  	.irq_ack		= pata_icside_irq_ack,
  
  	.port_start		= pata_icside_port_start,
  
  	.bmdma_stop		= pata_icside_bmdma_stop,
  	.bmdma_status		= pata_icside_bmdma_status,
  };
f95637d2c   Russell King   [ARM] pata_icside...
406
407
408
  static void __devinit
  pata_icside_setup_ioaddr(struct ata_ioports *ioaddr, void __iomem *base,
  			 const struct portinfo *info)
73b6a2be8   Russell King   [ARM] Add support...
409
  {
73b6a2be8   Russell King   [ARM] Add support...
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
  	void __iomem *cmd = base + info->dataoffset;
  
  	ioaddr->cmd_addr	= cmd;
  	ioaddr->data_addr	= cmd + (ATA_REG_DATA    << info->stepping);
  	ioaddr->error_addr	= cmd + (ATA_REG_ERR     << info->stepping);
  	ioaddr->feature_addr	= cmd + (ATA_REG_FEATURE << info->stepping);
  	ioaddr->nsect_addr	= cmd + (ATA_REG_NSECT   << info->stepping);
  	ioaddr->lbal_addr	= cmd + (ATA_REG_LBAL    << info->stepping);
  	ioaddr->lbam_addr	= cmd + (ATA_REG_LBAM    << info->stepping);
  	ioaddr->lbah_addr	= cmd + (ATA_REG_LBAH    << info->stepping);
  	ioaddr->device_addr	= cmd + (ATA_REG_DEVICE  << info->stepping);
  	ioaddr->status_addr	= cmd + (ATA_REG_STATUS  << info->stepping);
  	ioaddr->command_addr	= cmd + (ATA_REG_CMD     << info->stepping);
  
  	ioaddr->ctl_addr	= base + info->ctrloffset;
  	ioaddr->altstatus_addr	= ioaddr->ctl_addr;
  }
f95637d2c   Russell King   [ARM] pata_icside...
427
  static int __devinit pata_icside_register_v5(struct pata_icside_info *info)
73b6a2be8   Russell King   [ARM] Add support...
428
  {
f95637d2c   Russell King   [ARM] pata_icside...
429
  	struct pata_icside_state *state = info->state;
73b6a2be8   Russell King   [ARM] Add support...
430
  	void __iomem *base;
10bdaaa0f   Russell King   [ARM] ecard: add ...
431
  	base = ecardm_iomap(info->ec, ECARD_RES_MEMC, 0, 0);
73b6a2be8   Russell King   [ARM] Add support...
432
433
434
435
  	if (!base)
  		return -ENOMEM;
  
  	state->irq_port = base;
f95637d2c   Russell King   [ARM] pata_icside...
436
437
438
439
440
441
  	info->base = base;
  	info->irqaddr = base + ICS_ARCIN_V5_INTRSTAT;
  	info->irqmask = 1;
  	info->irqops = &pata_icside_ops_arcin_v5;
  	info->nr_ports = 1;
  	info->port[0] = &pata_icside_portinfo_v5;
73b6a2be8   Russell King   [ARM] Add support...
442
443
444
  
  	return 0;
  }
f95637d2c   Russell King   [ARM] pata_icside...
445
  static int __devinit pata_icside_register_v6(struct pata_icside_info *info)
73b6a2be8   Russell King   [ARM] Add support...
446
  {
f95637d2c   Russell King   [ARM] pata_icside...
447
448
  	struct pata_icside_state *state = info->state;
  	struct expansion_card *ec = info->ec;
73b6a2be8   Russell King   [ARM] Add support...
449
450
  	void __iomem *ioc_base, *easi_base;
  	unsigned int sel = 0;
73b6a2be8   Russell King   [ARM] Add support...
451

10bdaaa0f   Russell King   [ARM] ecard: add ...
452
453
454
  	ioc_base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
  	if (!ioc_base)
  		return -ENOMEM;
73b6a2be8   Russell King   [ARM] Add support...
455
456
457
458
  
  	easi_base = ioc_base;
  
  	if (ecard_resource_flags(ec, ECARD_RES_EASI)) {
10bdaaa0f   Russell King   [ARM] ecard: add ...
459
460
461
  		easi_base = ecardm_iomap(ec, ECARD_RES_EASI, 0, 0);
  		if (!easi_base)
  			return -ENOMEM;
73b6a2be8   Russell King   [ARM] Add support...
462
463
464
465
466
467
468
469
  
  		/*
  		 * Enable access to the EASI region.
  		 */
  		sel = 1 << 5;
  	}
  
  	writeb(sel, ioc_base);
73b6a2be8   Russell King   [ARM] Add support...
470
471
472
473
  	state->irq_port = easi_base;
  	state->ioc_base = ioc_base;
  	state->port[0].port_sel = sel;
  	state->port[1].port_sel = sel | 1;
f95637d2c   Russell King   [ARM] pata_icside...
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
  	info->base = easi_base;
  	info->irqops = &pata_icside_ops_arcin_v6;
  	info->nr_ports = 2;
  	info->port[0] = &pata_icside_portinfo_v6_1;
  	info->port[1] = &pata_icside_portinfo_v6_2;
  
  	return icside_dma_init(info);
  }
  
  static int __devinit pata_icside_add_ports(struct pata_icside_info *info)
  {
  	struct expansion_card *ec = info->ec;
  	struct ata_host *host;
  	int i;
  
  	if (info->irqaddr) {
  		ec->irqaddr = info->irqaddr;
  		ec->irqmask = info->irqmask;
  	}
  	if (info->irqops)
  		ecard_setirq(ec, info->irqops, info->state);
  
  	/*
  	 * Be on the safe side - disable interrupts
  	 */
  	ec->ops->irqdisable(ec, ec->irq);
  
  	host = ata_host_alloc(&ec->dev, info->nr_ports);
  	if (!host)
  		return -ENOMEM;
  
  	host->private_data = info->state;
  	host->flags = ATA_HOST_SIMPLEX;
  
  	for (i = 0; i < info->nr_ports; i++) {
  		struct ata_port *ap = host->ports[i];
  
  		ap->pio_mask = 0x1f;
  		ap->mwdma_mask = info->mwdma_mask;
1d2808fd3   Jeff Garzik   [libata] PATA dri...
513
  		ap->flags |= ATA_FLAG_SLAVE_POSS;
f95637d2c   Russell King   [ARM] pata_icside...
514
515
516
517
  		ap->ops = &pata_icside_port_ops;
  
  		pata_icside_setup_ioaddr(&ap->ioaddr, info->base, info->port[i]);
  	}
73b6a2be8   Russell King   [ARM] Add support...
518

f95637d2c   Russell King   [ARM] pata_icside...
519
520
  	return ata_host_activate(host, ec->irq, ata_interrupt, 0,
  				 &pata_icside_sht);
73b6a2be8   Russell King   [ARM] Add support...
521
522
523
524
525
526
  }
  
  static int __devinit
  pata_icside_probe(struct expansion_card *ec, const struct ecard_id *id)
  {
  	struct pata_icside_state *state;
f95637d2c   Russell King   [ARM] pata_icside...
527
  	struct pata_icside_info info;
73b6a2be8   Russell King   [ARM] Add support...
528
529
530
531
532
533
  	void __iomem *idmem;
  	int ret;
  
  	ret = ecard_request_resources(ec);
  	if (ret)
  		goto out;
f95637d2c   Russell King   [ARM] pata_icside...
534
  	state = devm_kzalloc(&ec->dev, sizeof(*state), GFP_KERNEL);
73b6a2be8   Russell King   [ARM] Add support...
535
536
537
538
539
540
541
  	if (!state) {
  		ret = -ENOMEM;
  		goto release;
  	}
  
  	state->type = ICS_TYPE_NOTYPE;
  	state->dma = NO_DMA;
10bdaaa0f   Russell King   [ARM] ecard: add ...
542
  	idmem = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
73b6a2be8   Russell King   [ARM] Add support...
543
544
545
546
547
548
549
  	if (idmem) {
  		unsigned int type;
  
  		type = readb(idmem + ICS_IDENT_OFFSET) & 1;
  		type |= (readb(idmem + ICS_IDENT_OFFSET + 4) & 1) << 1;
  		type |= (readb(idmem + ICS_IDENT_OFFSET + 8) & 1) << 2;
  		type |= (readb(idmem + ICS_IDENT_OFFSET + 12) & 1) << 3;
10bdaaa0f   Russell King   [ARM] ecard: add ...
550
  		ecardm_iounmap(ec, idmem);
73b6a2be8   Russell King   [ARM] Add support...
551
552
553
  
  		state->type = type;
  	}
f95637d2c   Russell King   [ARM] pata_icside...
554
555
556
  	memset(&info, 0, sizeof(info));
  	info.state = state;
  	info.ec = ec;
73b6a2be8   Russell King   [ARM] Add support...
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
  
  	switch (state->type) {
  	case ICS_TYPE_A3IN:
  		dev_warn(&ec->dev, "A3IN unsupported
  ");
  		ret = -ENODEV;
  		break;
  
  	case ICS_TYPE_A3USER:
  		dev_warn(&ec->dev, "A3USER unsupported
  ");
  		ret = -ENODEV;
  		break;
  
  	case ICS_TYPE_V5:
f95637d2c   Russell King   [ARM] pata_icside...
572
  		ret = pata_icside_register_v5(&info);
73b6a2be8   Russell King   [ARM] Add support...
573
574
575
  		break;
  
  	case ICS_TYPE_V6:
f95637d2c   Russell King   [ARM] pata_icside...
576
  		ret = pata_icside_register_v6(&info);
73b6a2be8   Russell King   [ARM] Add support...
577
578
579
580
581
582
583
584
585
586
  		break;
  
  	default:
  		dev_warn(&ec->dev, "unknown interface type
  ");
  		ret = -ENODEV;
  		break;
  	}
  
  	if (ret == 0)
f95637d2c   Russell King   [ARM] pata_icside...
587
  		ret = pata_icside_add_ports(&info);
73b6a2be8   Russell King   [ARM] Add support...
588
589
590
  
  	if (ret == 0)
  		goto out;
73b6a2be8   Russell King   [ARM] Add support...
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
   release:
  	ecard_release_resources(ec);
   out:
  	return ret;
  }
  
  static void pata_icside_shutdown(struct expansion_card *ec)
  {
  	struct ata_host *host = ecard_get_drvdata(ec);
  	unsigned long flags;
  
  	/*
  	 * Disable interrupts from this card.  We need to do
  	 * this before disabling EASI since we may be accessing
  	 * this register via that region.
  	 */
  	local_irq_save(flags);
c7b87f3d5   Russell King   [ARM] ecard: add ...
608
  	ec->ops->irqdisable(ec, ec->irq);
73b6a2be8   Russell King   [ARM] Add support...
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
  	local_irq_restore(flags);
  
  	/*
  	 * Reset the ROM pointer so that we can read the ROM
  	 * after a soft reboot.  This also disables access to
  	 * the IDE taskfile via the EASI region.
  	 */
  	if (host) {
  		struct pata_icside_state *state = host->private_data;
  		if (state->ioc_base)
  			writeb(0, state->ioc_base);
  	}
  }
  
  static void __devexit pata_icside_remove(struct expansion_card *ec)
  {
  	struct ata_host *host = ecard_get_drvdata(ec);
  	struct pata_icside_state *state = host->private_data;
  
  	ata_host_detach(host);
  
  	pata_icside_shutdown(ec);
  
  	/*
  	 * don't NULL out the drvdata - devres/libata wants it
  	 * to free the ata_host structure.
  	 */
73b6a2be8   Russell King   [ARM] Add support...
636
637
  	if (state->dma != NO_DMA)
  		free_dma(state->dma);
73b6a2be8   Russell King   [ARM] Add support...
638

73b6a2be8   Russell King   [ARM] Add support...
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
  	ecard_release_resources(ec);
  }
  
  static const struct ecard_id pata_icside_ids[] = {
  	{ MANU_ICS,  PROD_ICS_IDE  },
  	{ MANU_ICS2, PROD_ICS2_IDE },
  	{ 0xffff, 0xffff }
  };
  
  static struct ecard_driver pata_icside_driver = {
  	.probe		= pata_icside_probe,
  	.remove 	= __devexit_p(pata_icside_remove),
  	.shutdown	= pata_icside_shutdown,
  	.id_table	= pata_icside_ids,
  	.drv = {
  		.name	= DRV_NAME,
  	},
  };
  
  static int __init pata_icside_init(void)
  {
  	return ecard_register_driver(&pata_icside_driver);
  }
  
  static void __exit pata_icside_exit(void)
  {
  	ecard_remove_driver(&pata_icside_driver);
  }
  
  MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("ICS PATA driver");
  
  module_init(pata_icside_init);
  module_exit(pata_icside_exit);