162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * New ATA layer SC1200 driver		Alan Cox <alan@lxorguk.ukuu.org.uk>
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * TODO: Mode selection filtering
662306a36Sopenharmony_ci * TODO: Needs custom DMA cleanup code
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Based very heavily on
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * linux/drivers/ide/pci/sc1200.c		Version 0.91	28-Jan-2003
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * Copyright (C) 2000-2002		Mark Lord <mlord@pobox.com>
1362306a36Sopenharmony_ci * May be copied or modified under the terms of the GNU General Public License
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * Development of this chipset driver was funded
1662306a36Sopenharmony_ci * by the nice folks at National Semiconductor.
1762306a36Sopenharmony_ci */
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <linux/kernel.h>
2062306a36Sopenharmony_ci#include <linux/module.h>
2162306a36Sopenharmony_ci#include <linux/pci.h>
2262306a36Sopenharmony_ci#include <linux/blkdev.h>
2362306a36Sopenharmony_ci#include <linux/delay.h>
2462306a36Sopenharmony_ci#include <scsi/scsi_host.h>
2562306a36Sopenharmony_ci#include <linux/libata.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define DRV_NAME	"pata_sc1200"
2862306a36Sopenharmony_ci#define DRV_VERSION	"0.2.6"
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define SC1200_REV_A	0x00
3162306a36Sopenharmony_ci#define SC1200_REV_B1	0x01
3262306a36Sopenharmony_ci#define SC1200_REV_B3	0x02
3362306a36Sopenharmony_ci#define SC1200_REV_C1	0x03
3462306a36Sopenharmony_ci#define SC1200_REV_D1	0x04
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/**
3762306a36Sopenharmony_ci *	sc1200_clock	-	PCI clock
3862306a36Sopenharmony_ci *
3962306a36Sopenharmony_ci *	Return the PCI bus clocking for the SC1200 chipset configuration
4062306a36Sopenharmony_ci *	in use. We return 0 for 33MHz 1 for 48MHz and 2 for 66Mhz
4162306a36Sopenharmony_ci */
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic int sc1200_clock(void)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	/* Magic registers that give us the chipset data */
4662306a36Sopenharmony_ci	u8 chip_id = inb(0x903C);
4762306a36Sopenharmony_ci	u8 silicon_rev = inb(0x903D);
4862306a36Sopenharmony_ci	u16 pci_clock;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	if (chip_id == 0x04 && silicon_rev < SC1200_REV_B1)
5162306a36Sopenharmony_ci		return 0;	/* 33 MHz mode */
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	/* Clock generator configuration 0x901E its 8/9 are the PCI clocking
5462306a36Sopenharmony_ci	   0/3 is 33Mhz 1 is 48 2 is 66 */
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	pci_clock = inw(0x901E);
5762306a36Sopenharmony_ci	pci_clock >>= 8;
5862306a36Sopenharmony_ci	pci_clock &= 0x03;
5962306a36Sopenharmony_ci	if (pci_clock == 3)
6062306a36Sopenharmony_ci		pci_clock = 0;
6162306a36Sopenharmony_ci	return pci_clock;
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/**
6562306a36Sopenharmony_ci *	sc1200_set_piomode		-	PIO setup
6662306a36Sopenharmony_ci *	@ap: ATA interface
6762306a36Sopenharmony_ci *	@adev: device on the interface
6862306a36Sopenharmony_ci *
6962306a36Sopenharmony_ci *	Set our PIO requirements. This is fairly simple on the SC1200
7062306a36Sopenharmony_ci */
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic void sc1200_set_piomode(struct ata_port *ap, struct ata_device *adev)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	static const u32 pio_timings[4][5] = {
7562306a36Sopenharmony_ci		/* format0, 33Mhz */
7662306a36Sopenharmony_ci		{ 0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010 },
7762306a36Sopenharmony_ci		/* format1, 33Mhz */
7862306a36Sopenharmony_ci		{ 0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010 },
7962306a36Sopenharmony_ci		/* format1, 48Mhz */
8062306a36Sopenharmony_ci		{ 0xfaa3f4f3, 0xc23232b2, 0x513101c1, 0x31213121, 0x10211021 },
8162306a36Sopenharmony_ci		/* format1, 66Mhz */
8262306a36Sopenharmony_ci		{ 0xfff4fff4, 0xf35353d3, 0x814102f1, 0x42314231, 0x11311131 }
8362306a36Sopenharmony_ci	};
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
8662306a36Sopenharmony_ci	u32 format;
8762306a36Sopenharmony_ci	unsigned int reg = 0x40 + 0x10 * ap->port_no;
8862306a36Sopenharmony_ci	int mode = adev->pio_mode - XFER_PIO_0;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	pci_read_config_dword(pdev, reg + 4, &format);
9162306a36Sopenharmony_ci	format >>= 31;
9262306a36Sopenharmony_ci	format += sc1200_clock();
9362306a36Sopenharmony_ci	pci_write_config_dword(pdev, reg + 8 * adev->devno,
9462306a36Sopenharmony_ci				pio_timings[format][mode]);
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci/**
9862306a36Sopenharmony_ci *	sc1200_set_dmamode		-	DMA timing setup
9962306a36Sopenharmony_ci *	@ap: ATA interface
10062306a36Sopenharmony_ci *	@adev: Device being configured
10162306a36Sopenharmony_ci *
10262306a36Sopenharmony_ci *	We cannot mix MWDMA and UDMA without reloading timings each switch
10362306a36Sopenharmony_ci *	master to slave.
10462306a36Sopenharmony_ci */
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic void sc1200_set_dmamode(struct ata_port *ap, struct ata_device *adev)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	static const u32 udma_timing[3][3] = {
10962306a36Sopenharmony_ci		{ 0x00921250, 0x00911140, 0x00911030 },
11062306a36Sopenharmony_ci		{ 0x00932470, 0x00922260, 0x00922140 },
11162306a36Sopenharmony_ci		{ 0x009436A1, 0x00933481, 0x00923261 }
11262306a36Sopenharmony_ci	};
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	static const u32 mwdma_timing[3][3] = {
11562306a36Sopenharmony_ci		{ 0x00077771, 0x00012121, 0x00002020 },
11662306a36Sopenharmony_ci		{ 0x000BBBB2, 0x00024241, 0x00013131 },
11762306a36Sopenharmony_ci		{ 0x000FFFF3, 0x00035352, 0x00015151 }
11862306a36Sopenharmony_ci	};
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	int clock = sc1200_clock();
12162306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
12262306a36Sopenharmony_ci	unsigned int reg = 0x40 + 0x10 * ap->port_no;
12362306a36Sopenharmony_ci	int mode = adev->dma_mode;
12462306a36Sopenharmony_ci	u32 format;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	if (mode >= XFER_UDMA_0)
12762306a36Sopenharmony_ci		format = udma_timing[clock][mode - XFER_UDMA_0];
12862306a36Sopenharmony_ci	else
12962306a36Sopenharmony_ci		format = mwdma_timing[clock][mode - XFER_MW_DMA_0];
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	if (adev->devno == 0) {
13262306a36Sopenharmony_ci		u32 timings;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci		pci_read_config_dword(pdev, reg + 4, &timings);
13562306a36Sopenharmony_ci		timings &= 0x80000000UL;
13662306a36Sopenharmony_ci		timings |= format;
13762306a36Sopenharmony_ci		pci_write_config_dword(pdev, reg + 4, timings);
13862306a36Sopenharmony_ci	} else
13962306a36Sopenharmony_ci		pci_write_config_dword(pdev, reg + 12, format);
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/**
14362306a36Sopenharmony_ci *	sc1200_qc_issue		-	command issue
14462306a36Sopenharmony_ci *	@qc: command pending
14562306a36Sopenharmony_ci *
14662306a36Sopenharmony_ci *	Called when the libata layer is about to issue a command. We wrap
14762306a36Sopenharmony_ci *	this interface so that we can load the correct ATA timings if
14862306a36Sopenharmony_ci *	necessary.  Specifically we have a problem that there is only
14962306a36Sopenharmony_ci *	one MWDMA/UDMA bit.
15062306a36Sopenharmony_ci */
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic unsigned int sc1200_qc_issue(struct ata_queued_cmd *qc)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	struct ata_port *ap = qc->ap;
15562306a36Sopenharmony_ci	struct ata_device *adev = qc->dev;
15662306a36Sopenharmony_ci	struct ata_device *prev = ap->private_data;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	/* See if the DMA settings could be wrong */
15962306a36Sopenharmony_ci	if (ata_dma_enabled(adev) && adev != prev && prev != NULL) {
16062306a36Sopenharmony_ci		/* Maybe, but do the channels match MWDMA/UDMA ? */
16162306a36Sopenharmony_ci		if ((ata_using_udma(adev) && !ata_using_udma(prev)) ||
16262306a36Sopenharmony_ci		    (ata_using_udma(prev) && !ata_using_udma(adev)))
16362306a36Sopenharmony_ci		    	/* Switch the mode bits */
16462306a36Sopenharmony_ci		    	sc1200_set_dmamode(ap, adev);
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	return ata_bmdma_qc_issue(qc);
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci/**
17162306a36Sopenharmony_ci *	sc1200_qc_defer	-	implement serialization
17262306a36Sopenharmony_ci *	@qc: command
17362306a36Sopenharmony_ci *
17462306a36Sopenharmony_ci *	Serialize command issue on this controller.
17562306a36Sopenharmony_ci */
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic int sc1200_qc_defer(struct ata_queued_cmd *qc)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	struct ata_host *host = qc->ap->host;
18062306a36Sopenharmony_ci	struct ata_port *alt = host->ports[1 ^ qc->ap->port_no];
18162306a36Sopenharmony_ci	int rc;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	/* First apply the usual rules */
18462306a36Sopenharmony_ci	rc = ata_std_qc_defer(qc);
18562306a36Sopenharmony_ci	if (rc != 0)
18662306a36Sopenharmony_ci		return rc;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	/* Now apply serialization rules. Only allow a command if the
18962306a36Sopenharmony_ci	   other channel state machine is idle */
19062306a36Sopenharmony_ci	if (alt && alt->qc_active)
19162306a36Sopenharmony_ci		return	ATA_DEFER_PORT;
19262306a36Sopenharmony_ci	return 0;
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic const struct scsi_host_template sc1200_sht = {
19662306a36Sopenharmony_ci	ATA_BASE_SHT(DRV_NAME),
19762306a36Sopenharmony_ci	.sg_tablesize	= LIBATA_DUMB_MAX_PRD,
19862306a36Sopenharmony_ci	.dma_boundary	= ATA_DMA_BOUNDARY,
19962306a36Sopenharmony_ci};
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cistatic struct ata_port_operations sc1200_port_ops = {
20262306a36Sopenharmony_ci	.inherits	= &ata_bmdma_port_ops,
20362306a36Sopenharmony_ci	.qc_prep 	= ata_bmdma_dumb_qc_prep,
20462306a36Sopenharmony_ci	.qc_issue	= sc1200_qc_issue,
20562306a36Sopenharmony_ci	.qc_defer	= sc1200_qc_defer,
20662306a36Sopenharmony_ci	.cable_detect	= ata_cable_40wire,
20762306a36Sopenharmony_ci	.set_piomode	= sc1200_set_piomode,
20862306a36Sopenharmony_ci	.set_dmamode	= sc1200_set_dmamode,
20962306a36Sopenharmony_ci};
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci/**
21262306a36Sopenharmony_ci *	sc1200_init_one		-	Initialise an SC1200
21362306a36Sopenharmony_ci *	@dev: PCI device
21462306a36Sopenharmony_ci *	@id: Entry in match table
21562306a36Sopenharmony_ci *
21662306a36Sopenharmony_ci *	Just throw the needed data at the libata helper and it does all
21762306a36Sopenharmony_ci *	our work.
21862306a36Sopenharmony_ci */
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	static const struct ata_port_info info = {
22362306a36Sopenharmony_ci		.flags = ATA_FLAG_SLAVE_POSS,
22462306a36Sopenharmony_ci		.pio_mask = ATA_PIO4,
22562306a36Sopenharmony_ci		.mwdma_mask = ATA_MWDMA2,
22662306a36Sopenharmony_ci		.udma_mask = ATA_UDMA2,
22762306a36Sopenharmony_ci		.port_ops = &sc1200_port_ops
22862306a36Sopenharmony_ci	};
22962306a36Sopenharmony_ci	const struct ata_port_info *ppi[] = { &info, NULL };
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	return ata_pci_bmdma_init_one(dev, ppi, &sc1200_sht, NULL, 0);
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic const struct pci_device_id sc1200[] = {
23562306a36Sopenharmony_ci	{ PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SCx200_IDE), },
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	{ },
23862306a36Sopenharmony_ci};
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic struct pci_driver sc1200_pci_driver = {
24162306a36Sopenharmony_ci	.name 		= DRV_NAME,
24262306a36Sopenharmony_ci	.id_table	= sc1200,
24362306a36Sopenharmony_ci	.probe 		= sc1200_init_one,
24462306a36Sopenharmony_ci	.remove		= ata_pci_remove_one,
24562306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
24662306a36Sopenharmony_ci	.suspend	= ata_pci_device_suspend,
24762306a36Sopenharmony_ci	.resume		= ata_pci_device_resume,
24862306a36Sopenharmony_ci#endif
24962306a36Sopenharmony_ci};
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cimodule_pci_driver(sc1200_pci_driver);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ciMODULE_AUTHOR("Alan Cox, Mark Lord");
25462306a36Sopenharmony_ciMODULE_DESCRIPTION("low-level driver for the NS/AMD SC1200");
25562306a36Sopenharmony_ciMODULE_LICENSE("GPL");
25662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, sc1200);
25762306a36Sopenharmony_ciMODULE_VERSION(DRV_VERSION);
258