xref: /kernel/linux/linux-5.10/drivers/ide/jmicron.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2006		Red Hat
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  May be copied or modified under the terms of the GNU General Public License
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/types.h>
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/pci.h>
118c2ecf20Sopenharmony_ci#include <linux/ide.h>
128c2ecf20Sopenharmony_ci#include <linux/init.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define DRV_NAME "jmicron"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_citypedef enum {
178c2ecf20Sopenharmony_ci	PORT_PATA0 = 0,
188c2ecf20Sopenharmony_ci	PORT_PATA1 = 1,
198c2ecf20Sopenharmony_ci	PORT_SATA = 2,
208c2ecf20Sopenharmony_ci} port_type;
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci/**
238c2ecf20Sopenharmony_ci *	jmicron_cable_detect	-	cable detection
248c2ecf20Sopenharmony_ci *	@hwif: IDE port
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci *	Returns the cable type.
278c2ecf20Sopenharmony_ci */
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic u8 jmicron_cable_detect(ide_hwif_t *hwif)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(hwif->dev);
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	u32 control;
348c2ecf20Sopenharmony_ci	u32 control5;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	int port = hwif->channel;
378c2ecf20Sopenharmony_ci	port_type port_map[2];
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	pci_read_config_dword(pdev, 0x40, &control);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	/* There are two basic mappings. One has the two SATA ports merged
428c2ecf20Sopenharmony_ci	   as master/slave and the secondary as PATA, the other has only the
438c2ecf20Sopenharmony_ci	   SATA port mapped */
448c2ecf20Sopenharmony_ci	if (control & (1 << 23)) {
458c2ecf20Sopenharmony_ci		port_map[0] = PORT_SATA;
468c2ecf20Sopenharmony_ci		port_map[1] = PORT_PATA0;
478c2ecf20Sopenharmony_ci	} else {
488c2ecf20Sopenharmony_ci		port_map[0] = PORT_SATA;
498c2ecf20Sopenharmony_ci		port_map[1] = PORT_SATA;
508c2ecf20Sopenharmony_ci	}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	/* The 365/366 may have this bit set to map the second PATA port
538c2ecf20Sopenharmony_ci	   as the internal primary channel */
548c2ecf20Sopenharmony_ci	pci_read_config_dword(pdev, 0x80, &control5);
558c2ecf20Sopenharmony_ci	if (control5 & (1<<24))
568c2ecf20Sopenharmony_ci		port_map[0] = PORT_PATA1;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	/* The two ports may then be logically swapped by the firmware */
598c2ecf20Sopenharmony_ci	if (control & (1 << 22))
608c2ecf20Sopenharmony_ci		port = port ^ 1;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	/*
638c2ecf20Sopenharmony_ci	 *	Now we know which physical port we are talking about we can
648c2ecf20Sopenharmony_ci	 *	actually do our cable checking etc. Thankfully we don't need
658c2ecf20Sopenharmony_ci	 *	to do the plumbing for other cases.
668c2ecf20Sopenharmony_ci	 */
678c2ecf20Sopenharmony_ci	switch (port_map[port]) {
688c2ecf20Sopenharmony_ci	case PORT_PATA0:
698c2ecf20Sopenharmony_ci		if (control & (1 << 3))	/* 40/80 pin primary */
708c2ecf20Sopenharmony_ci			return ATA_CBL_PATA40;
718c2ecf20Sopenharmony_ci		return ATA_CBL_PATA80;
728c2ecf20Sopenharmony_ci	case PORT_PATA1:
738c2ecf20Sopenharmony_ci		if (control5 & (1 << 19))	/* 40/80 pin secondary */
748c2ecf20Sopenharmony_ci			return ATA_CBL_PATA40;
758c2ecf20Sopenharmony_ci		return ATA_CBL_PATA80;
768c2ecf20Sopenharmony_ci	case PORT_SATA:
778c2ecf20Sopenharmony_ci		break;
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci	/* Avoid bogus "control reaches end of non-void function" */
808c2ecf20Sopenharmony_ci	return ATA_CBL_PATA80;
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic void jmicron_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci/**
888c2ecf20Sopenharmony_ci *	jmicron_set_dma_mode	-	set host controller for DMA mode
898c2ecf20Sopenharmony_ci *	@hwif: port
908c2ecf20Sopenharmony_ci *	@drive: drive
918c2ecf20Sopenharmony_ci *
928c2ecf20Sopenharmony_ci *	As the JMicron snoops for timings we don't need to do anything here.
938c2ecf20Sopenharmony_ci */
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic void jmicron_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic const struct ide_port_ops jmicron_port_ops = {
1008c2ecf20Sopenharmony_ci	.set_pio_mode		= jmicron_set_pio_mode,
1018c2ecf20Sopenharmony_ci	.set_dma_mode		= jmicron_set_dma_mode,
1028c2ecf20Sopenharmony_ci	.cable_detect		= jmicron_cable_detect,
1038c2ecf20Sopenharmony_ci};
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic const struct ide_port_info jmicron_chipset = {
1068c2ecf20Sopenharmony_ci	.name		= DRV_NAME,
1078c2ecf20Sopenharmony_ci	.enablebits	= { { 0x40, 0x01, 0x01 }, { 0x40, 0x10, 0x10 } },
1088c2ecf20Sopenharmony_ci	.port_ops	= &jmicron_port_ops,
1098c2ecf20Sopenharmony_ci	.pio_mask	= ATA_PIO5,
1108c2ecf20Sopenharmony_ci	.mwdma_mask	= ATA_MWDMA2,
1118c2ecf20Sopenharmony_ci	.udma_mask	= ATA_UDMA6,
1128c2ecf20Sopenharmony_ci};
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci/**
1158c2ecf20Sopenharmony_ci *	jmicron_init_one	-	pci layer discovery entry
1168c2ecf20Sopenharmony_ci *	@dev: PCI device
1178c2ecf20Sopenharmony_ci *	@id: ident table entry
1188c2ecf20Sopenharmony_ci *
1198c2ecf20Sopenharmony_ci *	Called by the PCI code when it finds a Jmicron controller.
1208c2ecf20Sopenharmony_ci *	We then use the IDE PCI generic helper to do most of the work.
1218c2ecf20Sopenharmony_ci */
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic int jmicron_init_one(struct pci_dev *dev, const struct pci_device_id *id)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	return ide_pci_init_one(dev, &jmicron_chipset, NULL);
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci/* All JMB PATA controllers have and will continue to have the same
1298c2ecf20Sopenharmony_ci * interface.  Matching vendor and device class is enough for all
1308c2ecf20Sopenharmony_ci * current and future controllers if the controller is programmed
1318c2ecf20Sopenharmony_ci * properly.
1328c2ecf20Sopenharmony_ci *
1338c2ecf20Sopenharmony_ci * If libata is configured, jmicron PCI quirk programs the controller
1348c2ecf20Sopenharmony_ci * into the correct mode.  If libata isn't configured, match known
1358c2ecf20Sopenharmony_ci * device IDs too to maintain backward compatibility.
1368c2ecf20Sopenharmony_ci */
1378c2ecf20Sopenharmony_cistatic struct pci_device_id jmicron_pci_tbl[] = {
1388c2ecf20Sopenharmony_ci#if !defined(CONFIG_ATA) && !defined(CONFIG_ATA_MODULE)
1398c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB361) },
1408c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB363) },
1418c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB365) },
1428c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB366) },
1438c2ecf20Sopenharmony_ci	{ PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB368) },
1448c2ecf20Sopenharmony_ci#endif
1458c2ecf20Sopenharmony_ci	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
1468c2ecf20Sopenharmony_ci	  PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 0 },
1478c2ecf20Sopenharmony_ci	{ 0, },
1488c2ecf20Sopenharmony_ci};
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, jmicron_pci_tbl);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic struct pci_driver jmicron_pci_driver = {
1538c2ecf20Sopenharmony_ci	.name		= "JMicron IDE",
1548c2ecf20Sopenharmony_ci	.id_table	= jmicron_pci_tbl,
1558c2ecf20Sopenharmony_ci	.probe		= jmicron_init_one,
1568c2ecf20Sopenharmony_ci	.remove		= ide_pci_remove,
1578c2ecf20Sopenharmony_ci	.suspend	= ide_pci_suspend,
1588c2ecf20Sopenharmony_ci	.resume		= ide_pci_resume,
1598c2ecf20Sopenharmony_ci};
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic int __init jmicron_ide_init(void)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	return ide_pci_register_driver(&jmicron_pci_driver);
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic void __exit jmicron_ide_exit(void)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	pci_unregister_driver(&jmicron_pci_driver);
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cimodule_init(jmicron_ide_init);
1728c2ecf20Sopenharmony_cimodule_exit(jmicron_ide_exit);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ciMODULE_AUTHOR("Alan Cox");
1758c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PCI driver module for the JMicron in legacy modes");
1768c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
177