]>
Commit | Line | Data |
---|---|---|
07ab85de AD |
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 */ | |
42 | enum { | |
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 | ||
52 | static int sch_init_one(struct pci_dev *pdev, | |
53 | const struct pci_device_id *ent); | |
54 | static void sch_set_piomode(struct ata_port *ap, struct ata_device *adev); | |
55 | static void sch_set_dmamode(struct ata_port *ap, struct ata_device *adev); | |
56 | ||
57 | static 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 | ||
63 | static 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 | ||
74 | static struct scsi_host_template sch_sht = { | |
75 | ATA_BMDMA_SHT(DRV_NAME), | |
76 | }; | |
77 | ||
78 | static 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 | ||
85 | static struct ata_port_info sch_port_info = { | |
bc170e65 | 86 | .flags = ATA_FLAG_SLAVE_POSS, |
14bdef98 EIB |
87 | .pio_mask = ATA_PIO4, |
88 | .mwdma_mask = ATA_MWDMA2, | |
89 | .udma_mask = ATA_UDMA5, | |
07ab85de AD |
90 | .port_ops = &sch_pata_ops, |
91 | }; | |
92 | ||
93 | MODULE_AUTHOR("Alek Du <alek.du@intel.com>"); | |
94 | MODULE_DESCRIPTION("SCSI low-level driver for Intel SCH PATA controllers"); | |
95 | MODULE_LICENSE("GPL"); | |
96 | MODULE_DEVICE_TABLE(pci, sch_pci_tbl); | |
97 | MODULE_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 | ||
110 | static 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 | ||
139 | static 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 | ||
172 | static int __devinit sch_init_one(struct pci_dev *pdev, | |
173 | const struct pci_device_id *ent) | |
174 | { | |
07ab85de | 175 | const struct ata_port_info *ppi[] = { &sch_port_info, NULL }; |
07ab85de | 176 | |
06296a1e | 177 | ata_print_version_once(&pdev->dev, DRV_VERSION); |
07ab85de | 178 | |
1c5afdf7 | 179 | return ata_pci_bmdma_init_one(pdev, ppi, &sch_sht, NULL, 0); |
07ab85de AD |
180 | } |
181 | ||
2fc75da0 | 182 | module_pci_driver(sch_pci_driver); |