aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlek Du <alek.du@intel.com>2008-05-06 09:31:41 -0400
committerJeff Garzik <jgarzik@redhat.com>2008-05-06 11:33:58 -0400
commit07ab85de4d960b6f39395e51c1853485ad120de5 (patch)
tree9b467ccf719845ab606b5e207d9783975ede6f77
parentcb6716c879ecf49e2af344926c6a476821812061 (diff)
libata: Add Intel SCH PATA driver
This patch adds Intel SCH chipsets (AF82US15W, AF82US15L, AF82UL11L) PATA controller support. Signed-off-by: Alek Du <alek.du@intel.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
-rw-r--r--drivers/ata/Kconfig9
-rw-r--r--drivers/ata/Makefile1
-rw-r--r--drivers/ata/pata_sch.c206
3 files changed, 216 insertions, 0 deletions
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 1c11df9a5f32..1a59f305f7db 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -697,6 +697,15 @@ config PATA_SCC
697 697
698 If unsure, say N. 698 If unsure, say N.
699 699
700config PATA_SCH
701 tristate "Intel SCH PATA support"
702 depends on PCI
703 help
704 This option enables support for Intel SCH PATA on the Intel
705 SCH (US15W, US15L, UL11L) series host controllers.
706
707 If unsure, say N.
708
700config PATA_BF54X 709config PATA_BF54X
701 tristate "Blackfin 54x ATAPI support" 710 tristate "Blackfin 54x ATAPI support"
702 depends on BF542 || BF548 || BF549 711 depends on BF542 || BF548 || BF549
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index b693d829383a..674965fa326d 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_PATA_SIS) += pata_sis.o
67obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o 67obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o
68obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o 68obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o
69obj-$(CONFIG_PATA_SCC) += pata_scc.o 69obj-$(CONFIG_PATA_SCC) += pata_scc.o
70obj-$(CONFIG_PATA_SCH) += pata_sch.o
70obj-$(CONFIG_PATA_BF54X) += pata_bf54x.o 71obj-$(CONFIG_PATA_BF54X) += pata_bf54x.o
71obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o 72obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o
72obj-$(CONFIG_PATA_OF_PLATFORM) += pata_of_platform.o 73obj-$(CONFIG_PATA_OF_PLATFORM) += pata_of_platform.o
diff --git a/drivers/ata/pata_sch.c b/drivers/ata/pata_sch.c
new file mode 100644
index 000000000000..c8cc027789fe
--- /dev/null
+++ b/drivers/ata/pata_sch.c
@@ -0,0 +1,206 @@
1/*
2 * pata_sch.c - Intel SCH PATA controllers
3 *
4 * Copyright (c) 2008 Alek Du <alek.du@intel.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License 2 as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 */
20
21/*
22 * Supports:
23 * Intel SCH (AF82US15W, AF82US15L, AF82UL11L) chipsets -- see spec at:
24 * http://download.intel.com/design/chipsets/embedded/datashts/319537.pdf
25 */
26
27#include <linux/kernel.h>
28#include <linux/module.h>
29#include <linux/pci.h>
30#include <linux/init.h>
31#include <linux/blkdev.h>
32#include <linux/delay.h>
33#include <linux/device.h>
34#include <scsi/scsi_host.h>
35#include <linux/libata.h>
36#include <linux/dmi.h>
37
38#define DRV_NAME "pata_sch"
39#define DRV_VERSION "0.2"
40
41/* see SCH datasheet page 351 */
42enum {
43 D0TIM = 0x80, /* Device 0 Timing Register */
44 D1TIM = 0x84, /* Device 1 Timing Register */
45 PM = 0x07, /* PIO Mode Bit Mask */
46 MDM = (0x03 << 8), /* Multi-word DMA Mode Bit Mask */
47 UDM = (0x07 << 16), /* Ultra DMA Mode Bit Mask */
48 PPE = (1 << 30), /* Prefetch/Post Enable */
49 USD = (1 << 31), /* Use Synchronous DMA */
50};
51
52static int sch_init_one(struct pci_dev *pdev,
53 const struct pci_device_id *ent);
54static void sch_set_piomode(struct ata_port *ap, struct ata_device *adev);
55static void sch_set_dmamode(struct ata_port *ap, struct ata_device *adev);
56
57static const struct pci_device_id sch_pci_tbl[] = {
58 /* Intel SCH PATA Controller */
59 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SCH_IDE), 0 },
60 { } /* terminate list */
61};
62
63static struct pci_driver sch_pci_driver = {
64 .name = DRV_NAME,
65 .id_table = sch_pci_tbl,
66 .probe = sch_init_one,
67 .remove = ata_pci_remove_one,
68#ifdef CONFIG_PM
69 .suspend = ata_pci_device_suspend,
70 .resume = ata_pci_device_resume,
71#endif
72};
73
74static struct scsi_host_template sch_sht = {
75 ATA_BMDMA_SHT(DRV_NAME),
76};
77
78static struct ata_port_operations sch_pata_ops = {
79 .inherits = &ata_bmdma_port_ops,
80 .cable_detect = ata_cable_unknown,
81 .set_piomode = sch_set_piomode,
82 .set_dmamode = sch_set_dmamode,
83};
84
85static struct ata_port_info sch_port_info = {
86 .flags = 0,
87 .pio_mask = ATA_PIO4, /* pio0-4 */
88 .mwdma_mask = ATA_MWDMA2, /* mwdma0-2 */
89 .udma_mask = ATA_UDMA5, /* udma0-5 */
90 .port_ops = &sch_pata_ops,
91};
92
93MODULE_AUTHOR("Alek Du <alek.du@intel.com>");
94MODULE_DESCRIPTION("SCSI low-level driver for Intel SCH PATA controllers");
95MODULE_LICENSE("GPL");
96MODULE_DEVICE_TABLE(pci, sch_pci_tbl);
97MODULE_VERSION(DRV_VERSION);
98
99/**
100 * sch_set_piomode - Initialize host controller PATA PIO timings
101 * @ap: Port whose timings we are configuring
102 * @adev: ATA device
103 *
104 * Set PIO mode for device, in host controller PCI config space.
105 *
106 * LOCKING:
107 * None (inherited from caller).
108 */
109
110static void sch_set_piomode(struct ata_port *ap, struct ata_device *adev)
111{
112 unsigned int pio = adev->pio_mode - XFER_PIO_0;
113 struct pci_dev *dev = to_pci_dev(ap->host->dev);
114 unsigned int port = adev->devno ? D1TIM : D0TIM;
115 unsigned int data;
116
117 pci_read_config_dword(dev, port, &data);
118 /* see SCH datasheet page 351 */
119 /* set PIO mode */
120 data &= ~(PM | PPE);
121 data |= pio;
122 /* enable PPE for block device */
123 if (adev->class == ATA_DEV_ATA)
124 data |= PPE;
125 pci_write_config_dword(dev, port, data);
126}
127
128/**
129 * sch_set_dmamode - Initialize host controller PATA DMA timings
130 * @ap: Port whose timings we are configuring
131 * @adev: ATA device
132 *
133 * Set MW/UDMA mode for device, in host controller PCI config space.
134 *
135 * LOCKING:
136 * None (inherited from caller).
137 */
138
139static void sch_set_dmamode(struct ata_port *ap, struct ata_device *adev)
140{
141 unsigned int dma_mode = adev->dma_mode;
142 struct pci_dev *dev = to_pci_dev(ap->host->dev);
143 unsigned int port = adev->devno ? D1TIM : D0TIM;
144 unsigned int data;
145
146 pci_read_config_dword(dev, port, &data);
147 /* see SCH datasheet page 351 */
148 if (dma_mode >= XFER_UDMA_0) {
149 /* enable Synchronous DMA mode */
150 data |= USD;
151 data &= ~UDM;
152 data |= (dma_mode - XFER_UDMA_0) << 16;
153 } else { /* must be MWDMA mode, since we masked SWDMA already */
154 data &= ~(USD | MDM);
155 data |= (dma_mode - XFER_MW_DMA_0) << 8;
156 }
157 pci_write_config_dword(dev, port, data);
158}
159
160/**
161 * sch_init_one - Register SCH ATA PCI device with kernel services
162 * @pdev: PCI device to register
163 * @ent: Entry in sch_pci_tbl matching with @pdev
164 *
165 * LOCKING:
166 * Inherited from PCI layer (may sleep).
167 *
168 * RETURNS:
169 * Zero on success, or -ERRNO value.
170 */
171
172static int __devinit sch_init_one(struct pci_dev *pdev,
173 const struct pci_device_id *ent)
174{
175 static int printed_version;
176 const struct ata_port_info *ppi[] = { &sch_port_info, NULL };
177 struct ata_host *host;
178 int rc;
179
180 if (!printed_version++)
181 dev_printk(KERN_DEBUG, &pdev->dev,
182 "version " DRV_VERSION "\n");
183
184 /* enable device and prepare host */
185 rc = pcim_enable_device(pdev);
186 if (rc)
187 return rc;
188 rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
189 if (rc)
190 return rc;
191 pci_set_master(pdev);
192 return ata_pci_sff_activate_host(host, ata_sff_interrupt, &sch_sht);
193}
194
195static int __init sch_init(void)
196{
197 return pci_register_driver(&sch_pci_driver);
198}
199
200static void __exit sch_exit(void)
201{
202 pci_unregister_driver(&sch_pci_driver);
203}
204
205module_init(sch_init);
206module_exit(sch_exit);