brintos

brintos / linux-shallow public Read only

0
0
Text · 16.0 KiB · 61d8760 Raw
632 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2#include <linux/kernel.h>3#include <linux/module.h>4#include <linux/init.h>5#include <linux/blkdev.h>6#include <linux/gfp.h>7#include <scsi/scsi_host.h>8#include <linux/ata.h>9#include <linux/libata.h>10 11#include <asm/dma.h>12#include <asm/ecard.h>13 14#define DRV_NAME	"pata_icside"15 16#define ICS_IDENT_OFFSET		0x228017 18#define ICS_ARCIN_V5_INTRSTAT		0x000019#define ICS_ARCIN_V5_INTROFFSET		0x000420 21#define ICS_ARCIN_V6_INTROFFSET_1	0x220022#define ICS_ARCIN_V6_INTRSTAT_1		0x229023#define ICS_ARCIN_V6_INTROFFSET_2	0x320024#define ICS_ARCIN_V6_INTRSTAT_2		0x329025 26struct portinfo {27	unsigned int dataoffset;28	unsigned int ctrloffset;29	unsigned int stepping;30};31 32static const struct portinfo pata_icside_portinfo_v5 = {33	.dataoffset	= 0x2800,34	.ctrloffset	= 0x2b80,35	.stepping	= 6,36};37 38static const struct portinfo pata_icside_portinfo_v6_1 = {39	.dataoffset	= 0x2000,40	.ctrloffset	= 0x2380,41	.stepping	= 6,42};43 44static const struct portinfo pata_icside_portinfo_v6_2 = {45	.dataoffset	= 0x3000,46	.ctrloffset	= 0x3380,47	.stepping	= 6,48};49 50struct pata_icside_state {51	void __iomem *irq_port;52	void __iomem *ioc_base;53	unsigned int type;54	unsigned int dma;55	struct {56		u8 port_sel;57		u8 disabled;58		unsigned int speed[ATA_MAX_DEVICES];59	} port[2];60};61 62struct pata_icside_info {63	struct pata_icside_state *state;64	struct expansion_card	*ec;65	void __iomem		*base;66	void __iomem		*irqaddr;67	unsigned int		irqmask;68	const expansioncard_ops_t *irqops;69	unsigned int		mwdma_mask;70	unsigned int		nr_ports;71	const struct portinfo	*port[2];72	unsigned long		raw_base;73	unsigned long		raw_ioc_base;74};75 76#define ICS_TYPE_A3IN	077#define ICS_TYPE_A3USER	178#define ICS_TYPE_V6	379#define ICS_TYPE_V5	1580#define ICS_TYPE_NOTYPE	((unsigned int)-1)81 82/* ---------------- Version 5 PCB Support Functions --------------------- */83/* Prototype: pata_icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)84 * Purpose  : enable interrupts from card85 */86static void pata_icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)87{88	struct pata_icside_state *state = ec->irq_data;89 90	writeb(0, state->irq_port + ICS_ARCIN_V5_INTROFFSET);91}92 93/* Prototype: pata_icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)94 * Purpose  : disable interrupts from card95 */96static void pata_icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)97{98	struct pata_icside_state *state = ec->irq_data;99 100	readb(state->irq_port + ICS_ARCIN_V5_INTROFFSET);101}102 103static const expansioncard_ops_t pata_icside_ops_arcin_v5 = {104	.irqenable	= pata_icside_irqenable_arcin_v5,105	.irqdisable	= pata_icside_irqdisable_arcin_v5,106};107 108 109/* ---------------- Version 6 PCB Support Functions --------------------- */110/* Prototype: pata_icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)111 * Purpose  : enable interrupts from card112 */113static void pata_icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)114{115	struct pata_icside_state *state = ec->irq_data;116	void __iomem *base = state->irq_port;117 118	if (!state->port[0].disabled)119		writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1);120	if (!state->port[1].disabled)121		writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2);122}123 124/* Prototype: pata_icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)125 * Purpose  : disable interrupts from card126 */127static void pata_icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)128{129	struct pata_icside_state *state = ec->irq_data;130 131	readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);132	readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);133}134 135/* Prototype: pata_icside_irqprobe(struct expansion_card *ec)136 * Purpose  : detect an active interrupt from card137 */138static int pata_icside_irqpending_arcin_v6(struct expansion_card *ec)139{140	struct pata_icside_state *state = ec->irq_data;141 142	return readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||143	       readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;144}145 146static const expansioncard_ops_t pata_icside_ops_arcin_v6 = {147	.irqenable	= pata_icside_irqenable_arcin_v6,148	.irqdisable	= pata_icside_irqdisable_arcin_v6,149	.irqpending	= pata_icside_irqpending_arcin_v6,150};151 152 153/*154 * SG-DMA support.155 *156 * Similar to the BM-DMA, but we use the RiscPCs IOMD DMA controllers.157 * There is only one DMA controller per card, which means that only158 * one drive can be accessed at one time.  NOTE! We do not enforce that159 * here, but we rely on the main IDE driver spotting that both160 * interfaces use the same IRQ, which should guarantee this.161 */162 163/*164 * Configure the IOMD to give the appropriate timings for the transfer165 * mode being requested.  We take the advice of the ATA standards, and166 * calculate the cycle time based on the transfer mode, and the EIDE167 * MW DMA specs that the drive provides in the IDENTIFY command.168 *169 * We have the following IOMD DMA modes to choose from:170 *171 *	Type	Active		Recovery	Cycle172 *	A	250 (250)	312 (550)	562 (800)173 *	B	187 (200)	250 (550)	437 (750)174 *	C	125 (125)	125 (375)	250 (500)175 *	D	62  (50)	125 (375)	187 (425)176 *177 * (figures in brackets are actual measured timings on DIOR/DIOW)178 *179 * However, we also need to take care of the read/write active and180 * recovery timings:181 *182 *			Read	Write183 *  	Mode	Active	-- Recovery --	Cycle	IOMD type184 *	MW0	215	50	215	480	A185 *	MW1	80	50	50	150	C186 *	MW2	70	25	25	120	C187 */188static void pata_icside_set_dmamode(struct ata_port *ap, struct ata_device *adev)189{190	struct pata_icside_state *state = ap->host->private_data;191	struct ata_timing t;192	unsigned int cycle;193	char iomd_type;194 195	/*196	 * DMA is based on a 16MHz clock197	 */198	if (ata_timing_compute(adev, adev->dma_mode, &t, 1000, 1))199		return;200 201	/*202	 * Choose the IOMD cycle timing which ensure that the interface203	 * satisfies the measured active, recovery and cycle times.204	 */205	if (t.active <= 50 && t.recover <= 375 && t.cycle <= 425) {206		iomd_type = 'D';207		cycle = 187;208	} else if (t.active <= 125 && t.recover <= 375 && t.cycle <= 500) {209		iomd_type = 'C';210		cycle = 250;211	} else if (t.active <= 200 && t.recover <= 550 && t.cycle <= 750) {212		iomd_type = 'B';213		cycle = 437;214	} else {215		iomd_type = 'A';216		cycle = 562;217	}218 219	ata_dev_info(adev, "timings: act %dns rec %dns cyc %dns (%c)\n",220		     t.active, t.recover, t.cycle, iomd_type);221 222	state->port[ap->port_no].speed[adev->devno] = cycle;223}224 225static void pata_icside_bmdma_setup(struct ata_queued_cmd *qc)226{227	struct ata_port *ap = qc->ap;228	struct pata_icside_state *state = ap->host->private_data;229	unsigned int write = qc->tf.flags & ATA_TFLAG_WRITE;230 231	/*232	 * We are simplex; BUG if we try to fiddle with DMA233	 * while it's active.234	 */235	BUG_ON(dma_channel_active(state->dma));236 237	/*238	 * Route the DMA signals to the correct interface239	 */240	writeb(state->port[ap->port_no].port_sel, state->ioc_base);241 242	set_dma_speed(state->dma, state->port[ap->port_no].speed[qc->dev->devno]);243	set_dma_sg(state->dma, qc->sg, qc->n_elem);244	set_dma_mode(state->dma, write ? DMA_MODE_WRITE : DMA_MODE_READ);245 246	/* issue r/w command */247	ap->ops->sff_exec_command(ap, &qc->tf);248}249 250static void pata_icside_bmdma_start(struct ata_queued_cmd *qc)251{252	struct ata_port *ap = qc->ap;253	struct pata_icside_state *state = ap->host->private_data;254 255	BUG_ON(dma_channel_active(state->dma));256	enable_dma(state->dma);257}258 259static void pata_icside_bmdma_stop(struct ata_queued_cmd *qc)260{261	struct ata_port *ap = qc->ap;262	struct pata_icside_state *state = ap->host->private_data;263 264	disable_dma(state->dma);265 266	/* see ata_bmdma_stop */267	ata_sff_dma_pause(ap);268}269 270static u8 pata_icside_bmdma_status(struct ata_port *ap)271{272	struct pata_icside_state *state = ap->host->private_data;273	void __iomem *irq_port;274 275	irq_port = state->irq_port + (ap->port_no ? ICS_ARCIN_V6_INTRSTAT_2 :276						    ICS_ARCIN_V6_INTRSTAT_1);277 278	return readb(irq_port) & 1 ? ATA_DMA_INTR : 0;279}280 281static int icside_dma_init(struct pata_icside_info *info)282{283	struct pata_icside_state *state = info->state;284	struct expansion_card *ec = info->ec;285	int i;286 287	for (i = 0; i < ATA_MAX_DEVICES; i++) {288		state->port[0].speed[i] = 480;289		state->port[1].speed[i] = 480;290	}291 292	if (ec->dma != NO_DMA && !request_dma(ec->dma, DRV_NAME)) {293		state->dma = ec->dma;294		info->mwdma_mask = ATA_MWDMA2;295	}296 297	return 0;298}299 300 301static const struct scsi_host_template pata_icside_sht = {302	ATA_BASE_SHT(DRV_NAME),303	.sg_tablesize		= SG_MAX_SEGMENTS,304	.dma_boundary		= IOMD_DMA_BOUNDARY,305};306 307static void pata_icside_postreset(struct ata_link *link, unsigned int *classes)308{309	struct ata_port *ap = link->ap;310	struct pata_icside_state *state = ap->host->private_data;311 312	if (classes[0] != ATA_DEV_NONE || classes[1] != ATA_DEV_NONE)313		return ata_sff_postreset(link, classes);314 315	state->port[ap->port_no].disabled = 1;316 317	if (state->type == ICS_TYPE_V6) {318		/*319		 * Disable interrupts from this port, otherwise we320		 * receive spurious interrupts from the floating321		 * interrupt line.322		 */323		void __iomem *irq_port = state->irq_port +324				(ap->port_no ? ICS_ARCIN_V6_INTROFFSET_2 : ICS_ARCIN_V6_INTROFFSET_1);325		readb(irq_port);326	}327}328 329static struct ata_port_operations pata_icside_port_ops = {330	.inherits		= &ata_bmdma_port_ops,331	.sff_data_xfer		= ata_sff_data_xfer32,332	.bmdma_setup		= pata_icside_bmdma_setup,333	.bmdma_start		= pata_icside_bmdma_start,334	.bmdma_stop		= pata_icside_bmdma_stop,335	.bmdma_status		= pata_icside_bmdma_status,336 337	.cable_detect		= ata_cable_40wire,338	.set_dmamode		= pata_icside_set_dmamode,339	.postreset		= pata_icside_postreset,340 341	.port_start		= ATA_OP_NULL,	/* don't need PRD table */342};343 344static void pata_icside_setup_ioaddr(struct ata_port *ap, void __iomem *base,345				     struct pata_icside_info *info,346				     const struct portinfo *port)347{348	struct ata_ioports *ioaddr = &ap->ioaddr;349	void __iomem *cmd = base + port->dataoffset;350 351	ioaddr->cmd_addr	= cmd;352	ioaddr->data_addr	= cmd + (ATA_REG_DATA    << port->stepping);353	ioaddr->error_addr	= cmd + (ATA_REG_ERR     << port->stepping);354	ioaddr->feature_addr	= cmd + (ATA_REG_FEATURE << port->stepping);355	ioaddr->nsect_addr	= cmd + (ATA_REG_NSECT   << port->stepping);356	ioaddr->lbal_addr	= cmd + (ATA_REG_LBAL    << port->stepping);357	ioaddr->lbam_addr	= cmd + (ATA_REG_LBAM    << port->stepping);358	ioaddr->lbah_addr	= cmd + (ATA_REG_LBAH    << port->stepping);359	ioaddr->device_addr	= cmd + (ATA_REG_DEVICE  << port->stepping);360	ioaddr->status_addr	= cmd + (ATA_REG_STATUS  << port->stepping);361	ioaddr->command_addr	= cmd + (ATA_REG_CMD     << port->stepping);362 363	ioaddr->ctl_addr	= base + port->ctrloffset;364	ioaddr->altstatus_addr	= ioaddr->ctl_addr;365 366	ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx",367		      info->raw_base + port->dataoffset,368		      info->raw_base + port->ctrloffset);369 370	if (info->raw_ioc_base)371		ata_port_desc(ap, "iocbase 0x%lx", info->raw_ioc_base);372}373 374static int pata_icside_register_v5(struct pata_icside_info *info)375{376	struct pata_icside_state *state = info->state;377	void __iomem *base;378 379	base = ecardm_iomap(info->ec, ECARD_RES_MEMC, 0, 0);380	if (!base)381		return -ENOMEM;382 383	state->irq_port = base;384 385	info->base = base;386	info->irqaddr = base + ICS_ARCIN_V5_INTRSTAT;387	info->irqmask = 1;388	info->irqops = &pata_icside_ops_arcin_v5;389	info->nr_ports = 1;390	info->port[0] = &pata_icside_portinfo_v5;391 392	info->raw_base = ecard_resource_start(info->ec, ECARD_RES_MEMC);393 394	return 0;395}396 397static int pata_icside_register_v6(struct pata_icside_info *info)398{399	struct pata_icside_state *state = info->state;400	struct expansion_card *ec = info->ec;401	void __iomem *ioc_base, *easi_base;402	unsigned int sel = 0;403 404	ioc_base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);405	if (!ioc_base)406		return -ENOMEM;407 408	easi_base = ioc_base;409 410	if (ecard_resource_flags(ec, ECARD_RES_EASI)) {411		easi_base = ecardm_iomap(ec, ECARD_RES_EASI, 0, 0);412		if (!easi_base)413			return -ENOMEM;414 415		/*416		 * Enable access to the EASI region.417		 */418		sel = 1 << 5;419	}420 421	writeb(sel, ioc_base);422 423	state->irq_port = easi_base;424	state->ioc_base = ioc_base;425	state->port[0].port_sel = sel;426	state->port[1].port_sel = sel | 1;427 428	info->base = easi_base;429	info->irqops = &pata_icside_ops_arcin_v6;430	info->nr_ports = 2;431	info->port[0] = &pata_icside_portinfo_v6_1;432	info->port[1] = &pata_icside_portinfo_v6_2;433 434	info->raw_base = ecard_resource_start(ec, ECARD_RES_EASI);435	info->raw_ioc_base = ecard_resource_start(ec, ECARD_RES_IOCFAST);436 437	return icside_dma_init(info);438}439 440static int pata_icside_add_ports(struct pata_icside_info *info)441{442	struct expansion_card *ec = info->ec;443	struct ata_host *host;444	int i;445 446	if (info->irqaddr) {447		ec->irqaddr = info->irqaddr;448		ec->irqmask = info->irqmask;449	}450	if (info->irqops)451		ecard_setirq(ec, info->irqops, info->state);452 453	/*454	 * Be on the safe side - disable interrupts455	 */456	ec->ops->irqdisable(ec, ec->irq);457 458	host = ata_host_alloc(&ec->dev, info->nr_ports);459	if (!host)460		return -ENOMEM;461 462	host->private_data = info->state;463	host->flags = ATA_HOST_SIMPLEX;464 465	for (i = 0; i < info->nr_ports; i++) {466		struct ata_port *ap = host->ports[i];467 468		ap->pio_mask = ATA_PIO4;469		ap->mwdma_mask = info->mwdma_mask;470		ap->flags |= ATA_FLAG_SLAVE_POSS;471		ap->ops = &pata_icside_port_ops;472 473		pata_icside_setup_ioaddr(ap, info->base, info, info->port[i]);474	}475 476	return ata_host_activate(host, ec->irq, ata_bmdma_interrupt, 0,477				 &pata_icside_sht);478}479 480static int pata_icside_probe(struct expansion_card *ec,481			     const struct ecard_id *id)482{483	struct pata_icside_state *state;484	struct pata_icside_info info;485	void __iomem *idmem;486	int ret;487 488	ret = ecard_request_resources(ec);489	if (ret)490		goto out;491 492	state = devm_kzalloc(&ec->dev, sizeof(*state), GFP_KERNEL);493	if (!state) {494		ret = -ENOMEM;495		goto release;496	}497 498	state->type = ICS_TYPE_NOTYPE;499	state->dma = NO_DMA;500 501	idmem = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);502	if (idmem) {503		unsigned int type;504 505		type = readb(idmem + ICS_IDENT_OFFSET) & 1;506		type |= (readb(idmem + ICS_IDENT_OFFSET + 4) & 1) << 1;507		type |= (readb(idmem + ICS_IDENT_OFFSET + 8) & 1) << 2;508		type |= (readb(idmem + ICS_IDENT_OFFSET + 12) & 1) << 3;509		ecardm_iounmap(ec, idmem);510 511		state->type = type;512	}513 514	memset(&info, 0, sizeof(info));515	info.state = state;516	info.ec = ec;517 518	switch (state->type) {519	case ICS_TYPE_A3IN:520		dev_warn(&ec->dev, "A3IN unsupported\n");521		ret = -ENODEV;522		break;523 524	case ICS_TYPE_A3USER:525		dev_warn(&ec->dev, "A3USER unsupported\n");526		ret = -ENODEV;527		break;528 529	case ICS_TYPE_V5:530		ret = pata_icside_register_v5(&info);531		break;532 533	case ICS_TYPE_V6:534		ret = pata_icside_register_v6(&info);535		break;536 537	default:538		dev_warn(&ec->dev, "unknown interface type\n");539		ret = -ENODEV;540		break;541	}542 543	if (ret == 0)544		ret = pata_icside_add_ports(&info);545 546	if (ret == 0)547		goto out;548 549 release:550	ecard_release_resources(ec);551 out:552	return ret;553}554 555static void pata_icside_shutdown(struct expansion_card *ec)556{557	struct ata_host *host = ecard_get_drvdata(ec);558	unsigned long flags;559 560	/*561	 * Disable interrupts from this card.  We need to do562	 * this before disabling EASI since we may be accessing563	 * this register via that region.564	 */565	local_irq_save(flags);566	ec->ops->irqdisable(ec, ec->irq);567	local_irq_restore(flags);568 569	/*570	 * Reset the ROM pointer so that we can read the ROM571	 * after a soft reboot.  This also disables access to572	 * the IDE taskfile via the EASI region.573	 */574	if (host) {575		struct pata_icside_state *state = host->private_data;576		if (state->ioc_base)577			writeb(0, state->ioc_base);578	}579}580 581static void pata_icside_remove(struct expansion_card *ec)582{583	struct ata_host *host = ecard_get_drvdata(ec);584	struct pata_icside_state *state = host->private_data;585 586	ata_host_detach(host);587 588	pata_icside_shutdown(ec);589 590	/*591	 * don't NULL out the drvdata - devres/libata wants it592	 * to free the ata_host structure.593	 */594	if (state->dma != NO_DMA)595		free_dma(state->dma);596 597	ecard_release_resources(ec);598}599 600static const struct ecard_id pata_icside_ids[] = {601	{ MANU_ICS,  PROD_ICS_IDE  },602	{ MANU_ICS2, PROD_ICS2_IDE },603	{ 0xffff, 0xffff }604};605 606static struct ecard_driver pata_icside_driver = {607	.probe		= pata_icside_probe,608	.remove 	= pata_icside_remove,609	.shutdown	= pata_icside_shutdown,610	.id_table	= pata_icside_ids,611	.drv = {612		.name	= DRV_NAME,613	},614};615 616static int __init pata_icside_init(void)617{618	return ecard_register_driver(&pata_icside_driver);619}620 621static void __exit pata_icside_exit(void)622{623	ecard_remove_driver(&pata_icside_driver);624}625 626MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");627MODULE_LICENSE("GPL");628MODULE_DESCRIPTION("ICS PATA driver");629 630module_init(pata_icside_init);631module_exit(pata_icside_exit);632