xref: /openbmc/linux/drivers/ata/pata_icside.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
273b6a2beSRussell King #include <linux/kernel.h>
373b6a2beSRussell King #include <linux/module.h>
473b6a2beSRussell King #include <linux/init.h>
573b6a2beSRussell King #include <linux/blkdev.h>
65a0e3ad6STejun Heo #include <linux/gfp.h>
773b6a2beSRussell King #include <scsi/scsi_host.h>
873b6a2beSRussell King #include <linux/ata.h>
973b6a2beSRussell King #include <linux/libata.h>
1073b6a2beSRussell King 
1173b6a2beSRussell King #include <asm/dma.h>
1273b6a2beSRussell King #include <asm/ecard.h>
1373b6a2beSRussell King 
1473b6a2beSRussell King #define DRV_NAME	"pata_icside"
1573b6a2beSRussell King 
1673b6a2beSRussell King #define ICS_IDENT_OFFSET		0x2280
1773b6a2beSRussell King 
1873b6a2beSRussell King #define ICS_ARCIN_V5_INTRSTAT		0x0000
1973b6a2beSRussell King #define ICS_ARCIN_V5_INTROFFSET		0x0004
2073b6a2beSRussell King 
2173b6a2beSRussell King #define ICS_ARCIN_V6_INTROFFSET_1	0x2200
2273b6a2beSRussell King #define ICS_ARCIN_V6_INTRSTAT_1		0x2290
2373b6a2beSRussell King #define ICS_ARCIN_V6_INTROFFSET_2	0x3200
2473b6a2beSRussell King #define ICS_ARCIN_V6_INTRSTAT_2		0x3290
2573b6a2beSRussell King 
2673b6a2beSRussell King struct portinfo {
2773b6a2beSRussell King 	unsigned int dataoffset;
2873b6a2beSRussell King 	unsigned int ctrloffset;
2973b6a2beSRussell King 	unsigned int stepping;
3073b6a2beSRussell King };
3173b6a2beSRussell King 
3273b6a2beSRussell King static const struct portinfo pata_icside_portinfo_v5 = {
3373b6a2beSRussell King 	.dataoffset	= 0x2800,
3473b6a2beSRussell King 	.ctrloffset	= 0x2b80,
3573b6a2beSRussell King 	.stepping	= 6,
3673b6a2beSRussell King };
3773b6a2beSRussell King 
3873b6a2beSRussell King static const struct portinfo pata_icside_portinfo_v6_1 = {
3973b6a2beSRussell King 	.dataoffset	= 0x2000,
4073b6a2beSRussell King 	.ctrloffset	= 0x2380,
4173b6a2beSRussell King 	.stepping	= 6,
4273b6a2beSRussell King };
4373b6a2beSRussell King 
4473b6a2beSRussell King static const struct portinfo pata_icside_portinfo_v6_2 = {
4573b6a2beSRussell King 	.dataoffset	= 0x3000,
4673b6a2beSRussell King 	.ctrloffset	= 0x3380,
4773b6a2beSRussell King 	.stepping	= 6,
4873b6a2beSRussell King };
4973b6a2beSRussell King 
5073b6a2beSRussell King struct pata_icside_state {
5173b6a2beSRussell King 	void __iomem *irq_port;
5273b6a2beSRussell King 	void __iomem *ioc_base;
5373b6a2beSRussell King 	unsigned int type;
5473b6a2beSRussell King 	unsigned int dma;
5573b6a2beSRussell King 	struct {
5673b6a2beSRussell King 		u8 port_sel;
5773b6a2beSRussell King 		u8 disabled;
5873b6a2beSRussell King 		unsigned int speed[ATA_MAX_DEVICES];
5973b6a2beSRussell King 	} port[2];
6073b6a2beSRussell King };
6173b6a2beSRussell King 
62f95637d2SRussell King struct pata_icside_info {
63f95637d2SRussell King 	struct pata_icside_state *state;
64f95637d2SRussell King 	struct expansion_card	*ec;
65f95637d2SRussell King 	void __iomem		*base;
66f95637d2SRussell King 	void __iomem		*irqaddr;
67f95637d2SRussell King 	unsigned int		irqmask;
68f95637d2SRussell King 	const expansioncard_ops_t *irqops;
69f95637d2SRussell King 	unsigned int		mwdma_mask;
70f95637d2SRussell King 	unsigned int		nr_ports;
71f95637d2SRussell King 	const struct portinfo	*port[2];
72cbcdd875STejun Heo 	unsigned long		raw_base;
73cbcdd875STejun Heo 	unsigned long		raw_ioc_base;
74f95637d2SRussell King };
75f95637d2SRussell King 
7673b6a2beSRussell King #define ICS_TYPE_A3IN	0
7773b6a2beSRussell King #define ICS_TYPE_A3USER	1
7873b6a2beSRussell King #define ICS_TYPE_V6	3
7973b6a2beSRussell King #define ICS_TYPE_V5	15
8073b6a2beSRussell King #define ICS_TYPE_NOTYPE	((unsigned int)-1)
8173b6a2beSRussell King 
8273b6a2beSRussell King /* ---------------- Version 5 PCB Support Functions --------------------- */
8373b6a2beSRussell King /* Prototype: pata_icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
8473b6a2beSRussell King  * Purpose  : enable interrupts from card
8573b6a2beSRussell King  */
pata_icside_irqenable_arcin_v5(struct expansion_card * ec,int irqnr)8673b6a2beSRussell King static void pata_icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
8773b6a2beSRussell King {
8873b6a2beSRussell King 	struct pata_icside_state *state = ec->irq_data;
8973b6a2beSRussell King 
9073b6a2beSRussell King 	writeb(0, state->irq_port + ICS_ARCIN_V5_INTROFFSET);
9173b6a2beSRussell King }
9273b6a2beSRussell King 
9373b6a2beSRussell King /* Prototype: pata_icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
9473b6a2beSRussell King  * Purpose  : disable interrupts from card
9573b6a2beSRussell King  */
pata_icside_irqdisable_arcin_v5(struct expansion_card * ec,int irqnr)9673b6a2beSRussell King static void pata_icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
9773b6a2beSRussell King {
9873b6a2beSRussell King 	struct pata_icside_state *state = ec->irq_data;
9973b6a2beSRussell King 
10073b6a2beSRussell King 	readb(state->irq_port + ICS_ARCIN_V5_INTROFFSET);
10173b6a2beSRussell King }
10273b6a2beSRussell King 
10373b6a2beSRussell King static const expansioncard_ops_t pata_icside_ops_arcin_v5 = {
10473b6a2beSRussell King 	.irqenable	= pata_icside_irqenable_arcin_v5,
10573b6a2beSRussell King 	.irqdisable	= pata_icside_irqdisable_arcin_v5,
10673b6a2beSRussell King };
10773b6a2beSRussell King 
10873b6a2beSRussell King 
10973b6a2beSRussell King /* ---------------- Version 6 PCB Support Functions --------------------- */
11073b6a2beSRussell King /* Prototype: pata_icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
11173b6a2beSRussell King  * Purpose  : enable interrupts from card
11273b6a2beSRussell King  */
pata_icside_irqenable_arcin_v6(struct expansion_card * ec,int irqnr)11373b6a2beSRussell King static void pata_icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
11473b6a2beSRussell King {
11573b6a2beSRussell King 	struct pata_icside_state *state = ec->irq_data;
11673b6a2beSRussell King 	void __iomem *base = state->irq_port;
11773b6a2beSRussell King 
11873b6a2beSRussell King 	if (!state->port[0].disabled)
11973b6a2beSRussell King 		writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1);
12073b6a2beSRussell King 	if (!state->port[1].disabled)
12173b6a2beSRussell King 		writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2);
12273b6a2beSRussell King }
12373b6a2beSRussell King 
12473b6a2beSRussell King /* Prototype: pata_icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
12573b6a2beSRussell King  * Purpose  : disable interrupts from card
12673b6a2beSRussell King  */
pata_icside_irqdisable_arcin_v6(struct expansion_card * ec,int irqnr)12773b6a2beSRussell King static void pata_icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
12873b6a2beSRussell King {
12973b6a2beSRussell King 	struct pata_icside_state *state = ec->irq_data;
13073b6a2beSRussell King 
13173b6a2beSRussell King 	readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
13273b6a2beSRussell King 	readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
13373b6a2beSRussell King }
13473b6a2beSRussell King 
13573b6a2beSRussell King /* Prototype: pata_icside_irqprobe(struct expansion_card *ec)
13673b6a2beSRussell King  * Purpose  : detect an active interrupt from card
13773b6a2beSRussell King  */
pata_icside_irqpending_arcin_v6(struct expansion_card * ec)13873b6a2beSRussell King static int pata_icside_irqpending_arcin_v6(struct expansion_card *ec)
13973b6a2beSRussell King {
14073b6a2beSRussell King 	struct pata_icside_state *state = ec->irq_data;
14173b6a2beSRussell King 
14273b6a2beSRussell King 	return readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
14373b6a2beSRussell King 	       readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
14473b6a2beSRussell King }
14573b6a2beSRussell King 
14673b6a2beSRussell King static const expansioncard_ops_t pata_icside_ops_arcin_v6 = {
14773b6a2beSRussell King 	.irqenable	= pata_icside_irqenable_arcin_v6,
14873b6a2beSRussell King 	.irqdisable	= pata_icside_irqdisable_arcin_v6,
14973b6a2beSRussell King 	.irqpending	= pata_icside_irqpending_arcin_v6,
15073b6a2beSRussell King };
15173b6a2beSRussell King 
15273b6a2beSRussell King 
15373b6a2beSRussell King /*
15473b6a2beSRussell King  * SG-DMA support.
15573b6a2beSRussell King  *
15673b6a2beSRussell King  * Similar to the BM-DMA, but we use the RiscPCs IOMD DMA controllers.
15773b6a2beSRussell King  * There is only one DMA controller per card, which means that only
15873b6a2beSRussell King  * one drive can be accessed at one time.  NOTE! We do not enforce that
15973b6a2beSRussell King  * here, but we rely on the main IDE driver spotting that both
16073b6a2beSRussell King  * interfaces use the same IRQ, which should guarantee this.
16173b6a2beSRussell King  */
16273b6a2beSRussell King 
16373b6a2beSRussell King /*
16473b6a2beSRussell King  * Configure the IOMD to give the appropriate timings for the transfer
16573b6a2beSRussell King  * mode being requested.  We take the advice of the ATA standards, and
16673b6a2beSRussell King  * calculate the cycle time based on the transfer mode, and the EIDE
16773b6a2beSRussell King  * MW DMA specs that the drive provides in the IDENTIFY command.
16873b6a2beSRussell King  *
16973b6a2beSRussell King  * We have the following IOMD DMA modes to choose from:
17073b6a2beSRussell King  *
17173b6a2beSRussell King  *	Type	Active		Recovery	Cycle
17273b6a2beSRussell King  *	A	250 (250)	312 (550)	562 (800)
17373b6a2beSRussell King  *	B	187 (200)	250 (550)	437 (750)
17473b6a2beSRussell King  *	C	125 (125)	125 (375)	250 (500)
17573b6a2beSRussell King  *	D	62  (50)	125 (375)	187 (425)
17673b6a2beSRussell King  *
17773b6a2beSRussell King  * (figures in brackets are actual measured timings on DIOR/DIOW)
17873b6a2beSRussell King  *
17973b6a2beSRussell King  * However, we also need to take care of the read/write active and
18073b6a2beSRussell King  * recovery timings:
18173b6a2beSRussell King  *
18273b6a2beSRussell King  *			Read	Write
18373b6a2beSRussell King  *  	Mode	Active	-- Recovery --	Cycle	IOMD type
18473b6a2beSRussell King  *	MW0	215	50	215	480	A
18573b6a2beSRussell King  *	MW1	80	50	50	150	C
18673b6a2beSRussell King  *	MW2	70	25	25	120	C
18773b6a2beSRussell King  */
pata_icside_set_dmamode(struct ata_port * ap,struct ata_device * adev)18873b6a2beSRussell King static void pata_icside_set_dmamode(struct ata_port *ap, struct ata_device *adev)
18973b6a2beSRussell King {
19073b6a2beSRussell King 	struct pata_icside_state *state = ap->host->private_data;
19173b6a2beSRussell King 	struct ata_timing t;
19273b6a2beSRussell King 	unsigned int cycle;
19373b6a2beSRussell King 	char iomd_type;
19473b6a2beSRussell King 
19573b6a2beSRussell King 	/*
19673b6a2beSRussell King 	 * DMA is based on a 16MHz clock
19773b6a2beSRussell King 	 */
19873b6a2beSRussell King 	if (ata_timing_compute(adev, adev->dma_mode, &t, 1000, 1))
19973b6a2beSRussell King 		return;
20073b6a2beSRussell King 
20173b6a2beSRussell King 	/*
20273b6a2beSRussell King 	 * Choose the IOMD cycle timing which ensure that the interface
20373b6a2beSRussell King 	 * satisfies the measured active, recovery and cycle times.
20473b6a2beSRussell King 	 */
205e53d76e6SJoe Perches 	if (t.active <= 50 && t.recover <= 375 && t.cycle <= 425) {
206e53d76e6SJoe Perches 		iomd_type = 'D';
207e53d76e6SJoe Perches 		cycle = 187;
208e53d76e6SJoe Perches 	} else if (t.active <= 125 && t.recover <= 375 && t.cycle <= 500) {
209e53d76e6SJoe Perches 		iomd_type = 'C';
210e53d76e6SJoe Perches 		cycle = 250;
211e53d76e6SJoe Perches 	} else if (t.active <= 200 && t.recover <= 550 && t.cycle <= 750) {
212e53d76e6SJoe Perches 		iomd_type = 'B';
213e53d76e6SJoe Perches 		cycle = 437;
214e53d76e6SJoe Perches 	} else {
215e53d76e6SJoe Perches 		iomd_type = 'A';
216e53d76e6SJoe Perches 		cycle = 562;
217e53d76e6SJoe Perches 	}
21873b6a2beSRussell King 
219a9a79dfeSJoe Perches 	ata_dev_info(adev, "timings: act %dns rec %dns cyc %dns (%c)\n",
22073b6a2beSRussell King 		     t.active, t.recover, t.cycle, iomd_type);
22173b6a2beSRussell King 
22273b6a2beSRussell King 	state->port[ap->port_no].speed[adev->devno] = cycle;
22373b6a2beSRussell King }
22473b6a2beSRussell King 
pata_icside_bmdma_setup(struct ata_queued_cmd * qc)22573b6a2beSRussell King static void pata_icside_bmdma_setup(struct ata_queued_cmd *qc)
22673b6a2beSRussell King {
22773b6a2beSRussell King 	struct ata_port *ap = qc->ap;
22873b6a2beSRussell King 	struct pata_icside_state *state = ap->host->private_data;
22973b6a2beSRussell King 	unsigned int write = qc->tf.flags & ATA_TFLAG_WRITE;
23073b6a2beSRussell King 
23173b6a2beSRussell King 	/*
23273b6a2beSRussell King 	 * We are simplex; BUG if we try to fiddle with DMA
23373b6a2beSRussell King 	 * while it's active.
23473b6a2beSRussell King 	 */
23573b6a2beSRussell King 	BUG_ON(dma_channel_active(state->dma));
23673b6a2beSRussell King 
23773b6a2beSRussell King 	/*
23873b6a2beSRussell King 	 * Route the DMA signals to the correct interface
23973b6a2beSRussell King 	 */
24073b6a2beSRussell King 	writeb(state->port[ap->port_no].port_sel, state->ioc_base);
24173b6a2beSRussell King 
24273b6a2beSRussell King 	set_dma_speed(state->dma, state->port[ap->port_no].speed[qc->dev->devno]);
243f6718653SRussell King 	set_dma_sg(state->dma, qc->sg, qc->n_elem);
24473b6a2beSRussell King 	set_dma_mode(state->dma, write ? DMA_MODE_WRITE : DMA_MODE_READ);
24573b6a2beSRussell King 
24673b6a2beSRussell King 	/* issue r/w command */
2475682ed33STejun Heo 	ap->ops->sff_exec_command(ap, &qc->tf);
24873b6a2beSRussell King }
24973b6a2beSRussell King 
pata_icside_bmdma_start(struct ata_queued_cmd * qc)25073b6a2beSRussell King static void pata_icside_bmdma_start(struct ata_queued_cmd *qc)
25173b6a2beSRussell King {
25273b6a2beSRussell King 	struct ata_port *ap = qc->ap;
25373b6a2beSRussell King 	struct pata_icside_state *state = ap->host->private_data;
25473b6a2beSRussell King 
25573b6a2beSRussell King 	BUG_ON(dma_channel_active(state->dma));
25673b6a2beSRussell King 	enable_dma(state->dma);
25773b6a2beSRussell King }
25873b6a2beSRussell King 
pata_icside_bmdma_stop(struct ata_queued_cmd * qc)25973b6a2beSRussell King static void pata_icside_bmdma_stop(struct ata_queued_cmd *qc)
26073b6a2beSRussell King {
26173b6a2beSRussell King 	struct ata_port *ap = qc->ap;
26273b6a2beSRussell King 	struct pata_icside_state *state = ap->host->private_data;
26373b6a2beSRussell King 
26473b6a2beSRussell King 	disable_dma(state->dma);
26573b6a2beSRussell King 
26673b6a2beSRussell King 	/* see ata_bmdma_stop */
267a57c1badSAlan Cox 	ata_sff_dma_pause(ap);
26873b6a2beSRussell King }
26973b6a2beSRussell King 
pata_icside_bmdma_status(struct ata_port * ap)27073b6a2beSRussell King static u8 pata_icside_bmdma_status(struct ata_port *ap)
27173b6a2beSRussell King {
27273b6a2beSRussell King 	struct pata_icside_state *state = ap->host->private_data;
27373b6a2beSRussell King 	void __iomem *irq_port;
27473b6a2beSRussell King 
27573b6a2beSRussell King 	irq_port = state->irq_port + (ap->port_no ? ICS_ARCIN_V6_INTRSTAT_2 :
27673b6a2beSRussell King 						    ICS_ARCIN_V6_INTRSTAT_1);
27773b6a2beSRussell King 
27873b6a2beSRussell King 	return readb(irq_port) & 1 ? ATA_DMA_INTR : 0;
27973b6a2beSRussell King }
28073b6a2beSRussell King 
icside_dma_init(struct pata_icside_info * info)281f95637d2SRussell King static int icside_dma_init(struct pata_icside_info *info)
28273b6a2beSRussell King {
283f95637d2SRussell King 	struct pata_icside_state *state = info->state;
284f95637d2SRussell King 	struct expansion_card *ec = info->ec;
28573b6a2beSRussell King 	int i;
28673b6a2beSRussell King 
28773b6a2beSRussell King 	for (i = 0; i < ATA_MAX_DEVICES; i++) {
28873b6a2beSRussell King 		state->port[0].speed[i] = 480;
28973b6a2beSRussell King 		state->port[1].speed[i] = 480;
29073b6a2beSRussell King 	}
29173b6a2beSRussell King 
29273b6a2beSRussell King 	if (ec->dma != NO_DMA && !request_dma(ec->dma, DRV_NAME)) {
29373b6a2beSRussell King 		state->dma = ec->dma;
29414bdef98SErik Inge Bolsø 		info->mwdma_mask = ATA_MWDMA2;
29573b6a2beSRussell King 	}
29673b6a2beSRussell King 
29773b6a2beSRussell King 	return 0;
29873b6a2beSRussell King }
29973b6a2beSRussell King 
30073b6a2beSRussell King 
301*25df73d9SBart Van Assche static const struct scsi_host_template pata_icside_sht = {
30268d1d07bSTejun Heo 	ATA_BASE_SHT(DRV_NAME),
30365e8617fSMing Lin 	.sg_tablesize		= SG_MAX_SEGMENTS,
3045369bea7SRussell King 	.dma_boundary		= IOMD_DMA_BOUNDARY,
30573b6a2beSRussell King };
30673b6a2beSRussell King 
pata_icside_postreset(struct ata_link * link,unsigned int * classes)307c15fcafeSAl Viro static void pata_icside_postreset(struct ata_link *link, unsigned int *classes)
30873b6a2beSRussell King {
309c15fcafeSAl Viro 	struct ata_port *ap = link->ap;
31073b6a2beSRussell King 	struct pata_icside_state *state = ap->host->private_data;
31173b6a2beSRussell King 
312eba84481SRussell King 	if (classes[0] != ATA_DEV_NONE || classes[1] != ATA_DEV_NONE)
3139363c382STejun Heo 		return ata_sff_postreset(link, classes);
31473b6a2beSRussell King 
31573b6a2beSRussell King 	state->port[ap->port_no].disabled = 1;
31673b6a2beSRussell King 
31773b6a2beSRussell King 	if (state->type == ICS_TYPE_V6) {
31873b6a2beSRussell King 		/*
31973b6a2beSRussell King 		 * Disable interrupts from this port, otherwise we
32073b6a2beSRussell King 		 * receive spurious interrupts from the floating
32173b6a2beSRussell King 		 * interrupt line.
32273b6a2beSRussell King 		 */
32373b6a2beSRussell King 		void __iomem *irq_port = state->irq_port +
32473b6a2beSRussell King 				(ap->port_no ? ICS_ARCIN_V6_INTROFFSET_2 : ICS_ARCIN_V6_INTROFFSET_1);
32573b6a2beSRussell King 		readb(irq_port);
32673b6a2beSRussell King 	}
32773b6a2beSRussell King }
32873b6a2beSRussell King 
32973b6a2beSRussell King static struct ata_port_operations pata_icside_port_ops = {
3308930ff25STejun Heo 	.inherits		= &ata_bmdma_port_ops,
33173b6a2beSRussell King 	/* no need to build any PRD tables for DMA */
33273b6a2beSRussell King 	.qc_prep		= ata_noop_qc_prep,
33323ebda2fSSebastian Andrzej Siewior 	.sff_data_xfer		= ata_sff_data_xfer32,
334029cfd6bSTejun Heo 	.bmdma_setup		= pata_icside_bmdma_setup,
335029cfd6bSTejun Heo 	.bmdma_start		= pata_icside_bmdma_start,
33673b6a2beSRussell King 	.bmdma_stop		= pata_icside_bmdma_stop,
33773b6a2beSRussell King 	.bmdma_status		= pata_icside_bmdma_status,
338029cfd6bSTejun Heo 
339029cfd6bSTejun Heo 	.cable_detect		= ata_cable_40wire,
340029cfd6bSTejun Heo 	.set_dmamode		= pata_icside_set_dmamode,
341a1efdabaSTejun Heo 	.postreset		= pata_icside_postreset,
3428930ff25STejun Heo 
343c7087652STejun Heo 	.port_start		= ATA_OP_NULL,	/* don't need PRD table */
34473b6a2beSRussell King };
34573b6a2beSRussell King 
pata_icside_setup_ioaddr(struct ata_port * ap,void __iomem * base,struct pata_icside_info * info,const struct portinfo * port)3460ec24914SGreg Kroah-Hartman static void pata_icside_setup_ioaddr(struct ata_port *ap, void __iomem *base,
347c15fcafeSAl Viro 				     struct pata_icside_info *info,
348c15fcafeSAl Viro 				     const struct portinfo *port)
34973b6a2beSRussell King {
350cbcdd875STejun Heo 	struct ata_ioports *ioaddr = &ap->ioaddr;
351c15fcafeSAl Viro 	void __iomem *cmd = base + port->dataoffset;
35273b6a2beSRussell King 
35373b6a2beSRussell King 	ioaddr->cmd_addr	= cmd;
354c15fcafeSAl Viro 	ioaddr->data_addr	= cmd + (ATA_REG_DATA    << port->stepping);
355c15fcafeSAl Viro 	ioaddr->error_addr	= cmd + (ATA_REG_ERR     << port->stepping);
356c15fcafeSAl Viro 	ioaddr->feature_addr	= cmd + (ATA_REG_FEATURE << port->stepping);
357c15fcafeSAl Viro 	ioaddr->nsect_addr	= cmd + (ATA_REG_NSECT   << port->stepping);
358c15fcafeSAl Viro 	ioaddr->lbal_addr	= cmd + (ATA_REG_LBAL    << port->stepping);
359c15fcafeSAl Viro 	ioaddr->lbam_addr	= cmd + (ATA_REG_LBAM    << port->stepping);
360c15fcafeSAl Viro 	ioaddr->lbah_addr	= cmd + (ATA_REG_LBAH    << port->stepping);
361c15fcafeSAl Viro 	ioaddr->device_addr	= cmd + (ATA_REG_DEVICE  << port->stepping);
362c15fcafeSAl Viro 	ioaddr->status_addr	= cmd + (ATA_REG_STATUS  << port->stepping);
363c15fcafeSAl Viro 	ioaddr->command_addr	= cmd + (ATA_REG_CMD     << port->stepping);
36473b6a2beSRussell King 
365c15fcafeSAl Viro 	ioaddr->ctl_addr	= base + port->ctrloffset;
36673b6a2beSRussell King 	ioaddr->altstatus_addr	= ioaddr->ctl_addr;
367cbcdd875STejun Heo 
368cbcdd875STejun Heo 	ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx",
369c15fcafeSAl Viro 		      info->raw_base + port->dataoffset,
370c15fcafeSAl Viro 		      info->raw_base + port->ctrloffset);
371cbcdd875STejun Heo 
372cbcdd875STejun Heo 	if (info->raw_ioc_base)
373cbcdd875STejun Heo 		ata_port_desc(ap, "iocbase 0x%lx", info->raw_ioc_base);
37473b6a2beSRussell King }
37573b6a2beSRussell King 
pata_icside_register_v5(struct pata_icside_info * info)3760ec24914SGreg Kroah-Hartman static int pata_icside_register_v5(struct pata_icside_info *info)
37773b6a2beSRussell King {
378f95637d2SRussell King 	struct pata_icside_state *state = info->state;
37973b6a2beSRussell King 	void __iomem *base;
38073b6a2beSRussell King 
38110bdaaa0SRussell King 	base = ecardm_iomap(info->ec, ECARD_RES_MEMC, 0, 0);
38273b6a2beSRussell King 	if (!base)
38373b6a2beSRussell King 		return -ENOMEM;
38473b6a2beSRussell King 
38573b6a2beSRussell King 	state->irq_port = base;
38673b6a2beSRussell King 
387f95637d2SRussell King 	info->base = base;
388f95637d2SRussell King 	info->irqaddr = base + ICS_ARCIN_V5_INTRSTAT;
389f95637d2SRussell King 	info->irqmask = 1;
390f95637d2SRussell King 	info->irqops = &pata_icside_ops_arcin_v5;
391f95637d2SRussell King 	info->nr_ports = 1;
392f95637d2SRussell King 	info->port[0] = &pata_icside_portinfo_v5;
39373b6a2beSRussell King 
394c15fcafeSAl Viro 	info->raw_base = ecard_resource_start(info->ec, ECARD_RES_MEMC);
395cbcdd875STejun Heo 
39673b6a2beSRussell King 	return 0;
39773b6a2beSRussell King }
39873b6a2beSRussell King 
pata_icside_register_v6(struct pata_icside_info * info)3990ec24914SGreg Kroah-Hartman static int pata_icside_register_v6(struct pata_icside_info *info)
40073b6a2beSRussell King {
401f95637d2SRussell King 	struct pata_icside_state *state = info->state;
402f95637d2SRussell King 	struct expansion_card *ec = info->ec;
40373b6a2beSRussell King 	void __iomem *ioc_base, *easi_base;
40473b6a2beSRussell King 	unsigned int sel = 0;
40573b6a2beSRussell King 
40610bdaaa0SRussell King 	ioc_base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
40710bdaaa0SRussell King 	if (!ioc_base)
40810bdaaa0SRussell King 		return -ENOMEM;
40973b6a2beSRussell King 
41073b6a2beSRussell King 	easi_base = ioc_base;
41173b6a2beSRussell King 
41273b6a2beSRussell King 	if (ecard_resource_flags(ec, ECARD_RES_EASI)) {
41310bdaaa0SRussell King 		easi_base = ecardm_iomap(ec, ECARD_RES_EASI, 0, 0);
41410bdaaa0SRussell King 		if (!easi_base)
41510bdaaa0SRussell King 			return -ENOMEM;
41673b6a2beSRussell King 
41773b6a2beSRussell King 		/*
41873b6a2beSRussell King 		 * Enable access to the EASI region.
41973b6a2beSRussell King 		 */
42073b6a2beSRussell King 		sel = 1 << 5;
42173b6a2beSRussell King 	}
42273b6a2beSRussell King 
42373b6a2beSRussell King 	writeb(sel, ioc_base);
42473b6a2beSRussell King 
42573b6a2beSRussell King 	state->irq_port = easi_base;
42673b6a2beSRussell King 	state->ioc_base = ioc_base;
42773b6a2beSRussell King 	state->port[0].port_sel = sel;
42873b6a2beSRussell King 	state->port[1].port_sel = sel | 1;
42973b6a2beSRussell King 
430f95637d2SRussell King 	info->base = easi_base;
431f95637d2SRussell King 	info->irqops = &pata_icside_ops_arcin_v6;
432f95637d2SRussell King 	info->nr_ports = 2;
433f95637d2SRussell King 	info->port[0] = &pata_icside_portinfo_v6_1;
434f95637d2SRussell King 	info->port[1] = &pata_icside_portinfo_v6_2;
43573b6a2beSRussell King 
436cbcdd875STejun Heo 	info->raw_base = ecard_resource_start(ec, ECARD_RES_EASI);
437cbcdd875STejun Heo 	info->raw_ioc_base = ecard_resource_start(ec, ECARD_RES_IOCFAST);
438cbcdd875STejun Heo 
439f95637d2SRussell King 	return icside_dma_init(info);
440f95637d2SRussell King }
441f95637d2SRussell King 
pata_icside_add_ports(struct pata_icside_info * info)4420ec24914SGreg Kroah-Hartman static int pata_icside_add_ports(struct pata_icside_info *info)
443f95637d2SRussell King {
444f95637d2SRussell King 	struct expansion_card *ec = info->ec;
445f95637d2SRussell King 	struct ata_host *host;
446f95637d2SRussell King 	int i;
447f95637d2SRussell King 
448f95637d2SRussell King 	if (info->irqaddr) {
449f95637d2SRussell King 		ec->irqaddr = info->irqaddr;
450f95637d2SRussell King 		ec->irqmask = info->irqmask;
451f95637d2SRussell King 	}
452f95637d2SRussell King 	if (info->irqops)
453f95637d2SRussell King 		ecard_setirq(ec, info->irqops, info->state);
454f95637d2SRussell King 
455f95637d2SRussell King 	/*
456f95637d2SRussell King 	 * Be on the safe side - disable interrupts
457f95637d2SRussell King 	 */
458f95637d2SRussell King 	ec->ops->irqdisable(ec, ec->irq);
459f95637d2SRussell King 
460f95637d2SRussell King 	host = ata_host_alloc(&ec->dev, info->nr_ports);
461f95637d2SRussell King 	if (!host)
462f95637d2SRussell King 		return -ENOMEM;
463f95637d2SRussell King 
464f95637d2SRussell King 	host->private_data = info->state;
465f95637d2SRussell King 	host->flags = ATA_HOST_SIMPLEX;
466f95637d2SRussell King 
467f95637d2SRussell King 	for (i = 0; i < info->nr_ports; i++) {
468f95637d2SRussell King 		struct ata_port *ap = host->ports[i];
469f95637d2SRussell King 
47014bdef98SErik Inge Bolsø 		ap->pio_mask = ATA_PIO4;
471f95637d2SRussell King 		ap->mwdma_mask = info->mwdma_mask;
4721d2808fdSJeff Garzik 		ap->flags |= ATA_FLAG_SLAVE_POSS;
473f95637d2SRussell King 		ap->ops = &pata_icside_port_ops;
474f95637d2SRussell King 
475c15fcafeSAl Viro 		pata_icside_setup_ioaddr(ap, info->base, info, info->port[i]);
476f95637d2SRussell King 	}
477f95637d2SRussell King 
478c3b28894STejun Heo 	return ata_host_activate(host, ec->irq, ata_bmdma_interrupt, 0,
479f95637d2SRussell King 				 &pata_icside_sht);
48073b6a2beSRussell King }
48173b6a2beSRussell King 
pata_icside_probe(struct expansion_card * ec,const struct ecard_id * id)4820ec24914SGreg Kroah-Hartman static int pata_icside_probe(struct expansion_card *ec,
4830ec24914SGreg Kroah-Hartman 			     const struct ecard_id *id)
48473b6a2beSRussell King {
48573b6a2beSRussell King 	struct pata_icside_state *state;
486f95637d2SRussell King 	struct pata_icside_info info;
48773b6a2beSRussell King 	void __iomem *idmem;
48873b6a2beSRussell King 	int ret;
48973b6a2beSRussell King 
49073b6a2beSRussell King 	ret = ecard_request_resources(ec);
49173b6a2beSRussell King 	if (ret)
49273b6a2beSRussell King 		goto out;
49373b6a2beSRussell King 
494f95637d2SRussell King 	state = devm_kzalloc(&ec->dev, sizeof(*state), GFP_KERNEL);
49573b6a2beSRussell King 	if (!state) {
49673b6a2beSRussell King 		ret = -ENOMEM;
49773b6a2beSRussell King 		goto release;
49873b6a2beSRussell King 	}
49973b6a2beSRussell King 
50073b6a2beSRussell King 	state->type = ICS_TYPE_NOTYPE;
50173b6a2beSRussell King 	state->dma = NO_DMA;
50273b6a2beSRussell King 
50310bdaaa0SRussell King 	idmem = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
50473b6a2beSRussell King 	if (idmem) {
50573b6a2beSRussell King 		unsigned int type;
50673b6a2beSRussell King 
50773b6a2beSRussell King 		type = readb(idmem + ICS_IDENT_OFFSET) & 1;
50873b6a2beSRussell King 		type |= (readb(idmem + ICS_IDENT_OFFSET + 4) & 1) << 1;
50973b6a2beSRussell King 		type |= (readb(idmem + ICS_IDENT_OFFSET + 8) & 1) << 2;
51073b6a2beSRussell King 		type |= (readb(idmem + ICS_IDENT_OFFSET + 12) & 1) << 3;
51110bdaaa0SRussell King 		ecardm_iounmap(ec, idmem);
51273b6a2beSRussell King 
51373b6a2beSRussell King 		state->type = type;
51473b6a2beSRussell King 	}
51573b6a2beSRussell King 
516f95637d2SRussell King 	memset(&info, 0, sizeof(info));
517f95637d2SRussell King 	info.state = state;
518f95637d2SRussell King 	info.ec = ec;
51973b6a2beSRussell King 
52073b6a2beSRussell King 	switch (state->type) {
52173b6a2beSRussell King 	case ICS_TYPE_A3IN:
52273b6a2beSRussell King 		dev_warn(&ec->dev, "A3IN unsupported\n");
52373b6a2beSRussell King 		ret = -ENODEV;
52473b6a2beSRussell King 		break;
52573b6a2beSRussell King 
52673b6a2beSRussell King 	case ICS_TYPE_A3USER:
52773b6a2beSRussell King 		dev_warn(&ec->dev, "A3USER unsupported\n");
52873b6a2beSRussell King 		ret = -ENODEV;
52973b6a2beSRussell King 		break;
53073b6a2beSRussell King 
53173b6a2beSRussell King 	case ICS_TYPE_V5:
532f95637d2SRussell King 		ret = pata_icside_register_v5(&info);
53373b6a2beSRussell King 		break;
53473b6a2beSRussell King 
53573b6a2beSRussell King 	case ICS_TYPE_V6:
536f95637d2SRussell King 		ret = pata_icside_register_v6(&info);
53773b6a2beSRussell King 		break;
53873b6a2beSRussell King 
53973b6a2beSRussell King 	default:
54073b6a2beSRussell King 		dev_warn(&ec->dev, "unknown interface type\n");
54173b6a2beSRussell King 		ret = -ENODEV;
54273b6a2beSRussell King 		break;
54373b6a2beSRussell King 	}
54473b6a2beSRussell King 
54573b6a2beSRussell King 	if (ret == 0)
546f95637d2SRussell King 		ret = pata_icside_add_ports(&info);
54773b6a2beSRussell King 
54873b6a2beSRussell King 	if (ret == 0)
54973b6a2beSRussell King 		goto out;
55073b6a2beSRussell King 
55173b6a2beSRussell King  release:
55273b6a2beSRussell King 	ecard_release_resources(ec);
55373b6a2beSRussell King  out:
55473b6a2beSRussell King 	return ret;
55573b6a2beSRussell King }
55673b6a2beSRussell King 
pata_icside_shutdown(struct expansion_card * ec)55773b6a2beSRussell King static void pata_icside_shutdown(struct expansion_card *ec)
55873b6a2beSRussell King {
55973b6a2beSRussell King 	struct ata_host *host = ecard_get_drvdata(ec);
56073b6a2beSRussell King 	unsigned long flags;
56173b6a2beSRussell King 
56273b6a2beSRussell King 	/*
56373b6a2beSRussell King 	 * Disable interrupts from this card.  We need to do
56473b6a2beSRussell King 	 * this before disabling EASI since we may be accessing
56573b6a2beSRussell King 	 * this register via that region.
56673b6a2beSRussell King 	 */
56773b6a2beSRussell King 	local_irq_save(flags);
56873b6a2beSRussell King 	ec->ops->irqdisable(ec, ec->irq);
56973b6a2beSRussell King 	local_irq_restore(flags);
57073b6a2beSRussell King 
57173b6a2beSRussell King 	/*
57273b6a2beSRussell King 	 * Reset the ROM pointer so that we can read the ROM
57373b6a2beSRussell King 	 * after a soft reboot.  This also disables access to
57473b6a2beSRussell King 	 * the IDE taskfile via the EASI region.
57573b6a2beSRussell King 	 */
57673b6a2beSRussell King 	if (host) {
57773b6a2beSRussell King 		struct pata_icside_state *state = host->private_data;
57873b6a2beSRussell King 		if (state->ioc_base)
57973b6a2beSRussell King 			writeb(0, state->ioc_base);
58073b6a2beSRussell King 	}
58173b6a2beSRussell King }
58273b6a2beSRussell King 
pata_icside_remove(struct expansion_card * ec)5830ec24914SGreg Kroah-Hartman static void pata_icside_remove(struct expansion_card *ec)
58473b6a2beSRussell King {
58573b6a2beSRussell King 	struct ata_host *host = ecard_get_drvdata(ec);
58673b6a2beSRussell King 	struct pata_icside_state *state = host->private_data;
58773b6a2beSRussell King 
58873b6a2beSRussell King 	ata_host_detach(host);
58973b6a2beSRussell King 
59073b6a2beSRussell King 	pata_icside_shutdown(ec);
59173b6a2beSRussell King 
59273b6a2beSRussell King 	/*
59373b6a2beSRussell King 	 * don't NULL out the drvdata - devres/libata wants it
59473b6a2beSRussell King 	 * to free the ata_host structure.
59573b6a2beSRussell King 	 */
59673b6a2beSRussell King 	if (state->dma != NO_DMA)
59773b6a2beSRussell King 		free_dma(state->dma);
59873b6a2beSRussell King 
59973b6a2beSRussell King 	ecard_release_resources(ec);
60073b6a2beSRussell King }
60173b6a2beSRussell King 
60273b6a2beSRussell King static const struct ecard_id pata_icside_ids[] = {
60373b6a2beSRussell King 	{ MANU_ICS,  PROD_ICS_IDE  },
60473b6a2beSRussell King 	{ MANU_ICS2, PROD_ICS2_IDE },
60573b6a2beSRussell King 	{ 0xffff, 0xffff }
60673b6a2beSRussell King };
60773b6a2beSRussell King 
60873b6a2beSRussell King static struct ecard_driver pata_icside_driver = {
60973b6a2beSRussell King 	.probe		= pata_icside_probe,
6100ec24914SGreg Kroah-Hartman 	.remove 	= pata_icside_remove,
61173b6a2beSRussell King 	.shutdown	= pata_icside_shutdown,
61273b6a2beSRussell King 	.id_table	= pata_icside_ids,
61373b6a2beSRussell King 	.drv = {
61473b6a2beSRussell King 		.name	= DRV_NAME,
61573b6a2beSRussell King 	},
61673b6a2beSRussell King };
61773b6a2beSRussell King 
pata_icside_init(void)61873b6a2beSRussell King static int __init pata_icside_init(void)
61973b6a2beSRussell King {
62073b6a2beSRussell King 	return ecard_register_driver(&pata_icside_driver);
62173b6a2beSRussell King }
62273b6a2beSRussell King 
pata_icside_exit(void)62373b6a2beSRussell King static void __exit pata_icside_exit(void)
62473b6a2beSRussell King {
62573b6a2beSRussell King 	ecard_remove_driver(&pata_icside_driver);
62673b6a2beSRussell King }
62773b6a2beSRussell King 
62873b6a2beSRussell King MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
62973b6a2beSRussell King MODULE_LICENSE("GPL");
63073b6a2beSRussell King MODULE_DESCRIPTION("ICS PATA driver");
63173b6a2beSRussell King 
63273b6a2beSRussell King module_init(pata_icside_init);
63373b6a2beSRussell King module_exit(pata_icside_exit);
634