brintos

brintos / linux-shallow public Read only

0
0
Text · 7.0 KiB · b811efd Raw
302 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * pata_cs5536.c	- CS5536 PATA for new ATA layer4 *			  (C) 2007 Martin K. Petersen <mkp@mkp.net>5 *			  (C) 2011 Bartlomiej Zolnierkiewicz6 *7 * Documentation:8 *	Available from AMD web site.9 *10 * The IDE timing registers for the CS5536 live in the Geode Machine11 * Specific Register file and not PCI config space.  Most BIOSes12 * virtualize the PCI registers so the chip looks like a standard IDE13 * controller.	Unfortunately not all implementations get this right.14 * In particular some have problems with unaligned accesses to the15 * virtualized PCI registers.  This driver always does full dword16 * writes to work around the issue.  Also, in case of a bad BIOS this17 * driver can be loaded with the "msr=1" parameter which forces using18 * the Machine Specific Registers to configure the device.19 */20 21#include <linux/kernel.h>22#include <linux/module.h>23#include <linux/pci.h>24#include <linux/blkdev.h>25#include <linux/delay.h>26#include <linux/libata.h>27#include <scsi/scsi_host.h>28#include <linux/dmi.h>29 30#ifdef CONFIG_X86_3231#include <asm/msr.h>32static int use_msr;33module_param_named(msr, use_msr, int, 0644);34MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)");35#else36#undef rdmsr	/* avoid accidental MSR usage on, e.g. x86-64 */37#undef wrmsr38#define rdmsr(x, y, z) do { } while (0)39#define wrmsr(x, y, z) do { } while (0)40#define use_msr 041#endif42 43#define DRV_NAME	"pata_cs5536"44#define DRV_VERSION	"0.0.8"45 46enum {47	MSR_IDE_CFG		= 0x51300010,48	PCI_IDE_CFG		= 0x40,49 50	CFG			= 0,51	DTC			= 2,52	CAST			= 3,53	ETC			= 4,54 55	IDE_CFG_CHANEN		= (1 << 1),56	IDE_CFG_CABLE		= (1 << 17) | (1 << 16),57 58	IDE_D0_SHIFT		= 24,59	IDE_D1_SHIFT		= 16,60	IDE_DRV_MASK		= 0xff,61 62	IDE_CAST_D0_SHIFT	= 6,63	IDE_CAST_D1_SHIFT	= 4,64	IDE_CAST_DRV_MASK	= 0x3,65	IDE_CAST_CMD_MASK	= 0xff,66	IDE_CAST_CMD_SHIFT	= 24,67 68	IDE_ETC_UDMA_MASK	= 0xc0,69};70 71/* Some Bachmann OT200 devices have a non working UDMA support due a72 * missing resistor.73 */74static const struct dmi_system_id udma_quirk_dmi_table[] = {75	{76		.ident = "Bachmann electronic OT200",77		.matches = {78			DMI_MATCH(DMI_SYS_VENDOR, "Bachmann electronic"),79			DMI_MATCH(DMI_PRODUCT_NAME, "OT200"),80			DMI_MATCH(DMI_PRODUCT_VERSION, "1")81		},82	},83	{ }84};85 86static int cs5536_read(struct pci_dev *pdev, int reg, u32 *val)87{88	if (unlikely(use_msr)) {89		u32 dummy __maybe_unused;90 91		rdmsr(MSR_IDE_CFG + reg, *val, dummy);92		return 0;93	}94 95	return pci_read_config_dword(pdev, PCI_IDE_CFG + reg * 4, val);96}97 98static int cs5536_write(struct pci_dev *pdev, int reg, int val)99{100	if (unlikely(use_msr)) {101		wrmsr(MSR_IDE_CFG + reg, val, 0);102		return 0;103	}104 105	return pci_write_config_dword(pdev, PCI_IDE_CFG + reg * 4, val);106}107 108static void cs5536_program_dtc(struct ata_device *adev, u8 tim)109{110	struct pci_dev *pdev = to_pci_dev(adev->link->ap->host->dev);111	int dshift = adev->devno ? IDE_D1_SHIFT : IDE_D0_SHIFT;112	u32 dtc;113 114	cs5536_read(pdev, DTC, &dtc);115	dtc &= ~(IDE_DRV_MASK << dshift);116	dtc |= tim << dshift;117	cs5536_write(pdev, DTC, dtc);118}119 120/**121 *	cs5536_cable_detect	-	detect cable type122 *	@ap: Port to detect on123 *124 *	Perform cable detection for ATA66 capable cable.125 *126 *	Returns a cable type.127 */128 129static int cs5536_cable_detect(struct ata_port *ap)130{131	struct pci_dev *pdev = to_pci_dev(ap->host->dev);132	u32 cfg;133 134	cs5536_read(pdev, CFG, &cfg);135 136	if (cfg & IDE_CFG_CABLE)137		return ATA_CBL_PATA80;138	else139		return ATA_CBL_PATA40;140}141 142/**143 *	cs5536_set_piomode		-	PIO setup144 *	@ap: ATA interface145 *	@adev: device on the interface146 */147 148static void cs5536_set_piomode(struct ata_port *ap, struct ata_device *adev)149{150	static const u8 drv_timings[5] = {151		0x98, 0x55, 0x32, 0x21, 0x20,152	};153 154	static const u8 addr_timings[5] = {155		0x2, 0x1, 0x0, 0x0, 0x0,156	};157 158	static const u8 cmd_timings[5] = {159		0x99, 0x92, 0x90, 0x22, 0x20,160	};161 162	struct pci_dev *pdev = to_pci_dev(ap->host->dev);163	struct ata_device *pair = ata_dev_pair(adev);164	int mode = adev->pio_mode - XFER_PIO_0;165	int cmdmode = mode;166	int cshift = adev->devno ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT;167	u32 cast;168 169	if (pair)170		cmdmode = min(mode, pair->pio_mode - XFER_PIO_0);171 172	cs5536_program_dtc(adev, drv_timings[mode]);173 174	cs5536_read(pdev, CAST, &cast);175 176	cast &= ~(IDE_CAST_DRV_MASK << cshift);177	cast |= addr_timings[mode] << cshift;178 179	cast &= ~(IDE_CAST_CMD_MASK << IDE_CAST_CMD_SHIFT);180	cast |= cmd_timings[cmdmode] << IDE_CAST_CMD_SHIFT;181 182	cs5536_write(pdev, CAST, cast);183}184 185/**186 *	cs5536_set_dmamode		-	DMA timing setup187 *	@ap: ATA interface188 *	@adev: Device being configured189 *190 */191 192static void cs5536_set_dmamode(struct ata_port *ap, struct ata_device *adev)193{194	static const u8 udma_timings[6] = {195		0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6,196	};197 198	static const u8 mwdma_timings[3] = {199		0x67, 0x21, 0x20,200	};201 202	struct pci_dev *pdev = to_pci_dev(ap->host->dev);203	u32 etc;204	int mode = adev->dma_mode;205	int dshift = adev->devno ? IDE_D1_SHIFT : IDE_D0_SHIFT;206 207	cs5536_read(pdev, ETC, &etc);208 209	if (mode >= XFER_UDMA_0) {210		etc &= ~(IDE_DRV_MASK << dshift);211		etc |= udma_timings[mode - XFER_UDMA_0] << dshift;212	} else { /* MWDMA */213		etc &= ~(IDE_ETC_UDMA_MASK << dshift);214		cs5536_program_dtc(adev, mwdma_timings[mode - XFER_MW_DMA_0]);215	}216 217	cs5536_write(pdev, ETC, etc);218}219 220static const struct scsi_host_template cs5536_sht = {221	ATA_BMDMA_SHT(DRV_NAME),222};223 224static struct ata_port_operations cs5536_port_ops = {225	.inherits		= &ata_bmdma32_port_ops,226	.cable_detect		= cs5536_cable_detect,227	.set_piomode		= cs5536_set_piomode,228	.set_dmamode		= cs5536_set_dmamode,229};230 231/**232 *	cs5536_init_one233 *	@dev: PCI device234 *	@id: Entry in match table235 *236 */237 238static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id)239{240	static const struct ata_port_info info = {241		.flags = ATA_FLAG_SLAVE_POSS,242		.pio_mask = ATA_PIO4,243		.mwdma_mask = ATA_MWDMA2,244		.udma_mask = ATA_UDMA5,245		.port_ops = &cs5536_port_ops,246	};247 248	static const struct ata_port_info no_udma_info = {249		.flags = ATA_FLAG_SLAVE_POSS,250		.pio_mask = ATA_PIO4,251		.port_ops = &cs5536_port_ops,252	};253 254 255	const struct ata_port_info *ppi[2];256	u32 cfg;257 258	if (dmi_check_system(udma_quirk_dmi_table))259		ppi[0] = &no_udma_info;260	else261		ppi[0] = &info;262 263	ppi[1] = &ata_dummy_port_info;264 265	if (use_msr)266		dev_err(&dev->dev, DRV_NAME ": Using MSR regs instead of PCI\n");267 268	cs5536_read(dev, CFG, &cfg);269 270	if ((cfg & IDE_CFG_CHANEN) == 0) {271		dev_err(&dev->dev, DRV_NAME ": disabled by BIOS\n");272		return -ENODEV;273	}274 275	return ata_pci_bmdma_init_one(dev, ppi, &cs5536_sht, NULL, 0);276}277 278static const struct pci_device_id cs5536[] = {279	{ PCI_VDEVICE(AMD,	PCI_DEVICE_ID_AMD_CS5536_IDE), },280	{ PCI_VDEVICE(AMD,	PCI_DEVICE_ID_AMD_CS5536_DEV_IDE), },281	{ },282};283 284static struct pci_driver cs5536_pci_driver = {285	.name		= DRV_NAME,286	.id_table	= cs5536,287	.probe		= cs5536_init_one,288	.remove		= ata_pci_remove_one,289#ifdef CONFIG_PM_SLEEP290	.suspend	= ata_pci_device_suspend,291	.resume		= ata_pci_device_resume,292#endif293};294 295module_pci_driver(cs5536_pci_driver);296 297MODULE_AUTHOR("Martin K. Petersen");298MODULE_DESCRIPTION("low-level driver for the CS5536 IDE controller");299MODULE_LICENSE("GPL");300MODULE_DEVICE_TABLE(pci, cs5536);301MODULE_VERSION(DRV_VERSION);302