]>
Commit | Line | Data |
---|---|---|
07ab85de AD |
1 | /* |
2 | * pata_sch.c - Intel SCH PATA controllers | |
3 | * | |
4 | * Copyright (c) 2008 Alek Du <[email protected]> | |
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> | |
07ab85de AD |
30 | #include <linux/blkdev.h> |
31 | #include <linux/delay.h> | |
32 | #include <linux/device.h> | |
33 | #include <scsi/scsi_host.h> | |
34 | #include <linux/libata.h> | |
35 | #include <linux/dmi.h> | |
36 | ||
37 | #define DRV_NAME "pata_sch" | |
38 | #define DRV_VERSION "0.2" | |
39 | ||
40 | /* see SCH datasheet page 351 */ | |
41 | enum { | |
42 | D0TIM = 0x80, /* Device 0 Timing Register */ | |
43 | D1TIM = 0x84, /* Device 1 Timing Register */ | |
44 | PM = 0x07, /* PIO Mode Bit Mask */ | |
45 | MDM = (0x03 << 8), /* Multi-word DMA Mode Bit Mask */ | |
46 | UDM = (0x07 << 16), /* Ultra DMA Mode Bit Mask */ | |
47 | PPE = (1 << 30), /* Prefetch/Post Enable */ | |
48 | USD = (1 << 31), /* Use Synchronous DMA */ | |
49 | }; | |
50 | ||
51 | static int sch_init_one(struct pci_dev *pdev, | |
52 | const struct pci_device_id *ent); | |
53 | static void sch_set_piomode(struct ata_port *ap, struct ata_device *adev); | |
54 | static void sch_set_dmamode(struct ata_port *ap, struct ata_device *adev); | |
55 | ||
56 | static const struct pci_device_id sch_pci_tbl[] = { | |
57 | /* Intel SCH PATA Controller */ | |
58 | { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SCH_IDE), 0 }, | |
59 | { } /* terminate list */ | |
60 | }; | |
61 | ||
62 | static struct pci_driver sch_pci_driver = { | |
63 | .name = DRV_NAME, | |
64 | .id_table = sch_pci_tbl, | |
65 | .probe = sch_init_one, | |
66 | .remove = ata_pci_remove_one, | |
58eb8cd5 | 67 | #ifdef CONFIG_PM_SLEEP |
07ab85de AD |
68 | .suspend = ata_pci_device_suspend, |
69 | .resume = ata_pci_device_resume, | |
70 | #endif | |
71 | }; | |
72 | ||
73 | static struct scsi_host_template sch_sht = { | |
74 | ATA_BMDMA_SHT(DRV_NAME), | |
75 | }; | |
76 | ||
77 | static struct ata_port_operations sch_pata_ops = { | |
78 | .inherits = &ata_bmdma_port_ops, | |
79 | .cable_detect = ata_cable_unknown, | |
80 | .set_piomode = sch_set_piomode, | |
81 | .set_dmamode = sch_set_dmamode, | |
82 | }; | |
83 | ||
f356b082 | 84 | static const struct ata_port_info sch_port_info = { |
bc170e65 | 85 | .flags = ATA_FLAG_SLAVE_POSS, |
14bdef98 EIB |
86 | .pio_mask = ATA_PIO4, |
87 | .mwdma_mask = ATA_MWDMA2, | |
88 | .udma_mask = ATA_UDMA5, | |
07ab85de AD |
89 | .port_ops = &sch_pata_ops, |
90 | }; | |
91 | ||
92 | MODULE_AUTHOR("Alek Du <[email protected]>"); | |
93 | MODULE_DESCRIPTION("SCSI low-level driver for Intel SCH PATA controllers"); | |
94 | MODULE_LICENSE("GPL"); | |
95 | MODULE_DEVICE_TABLE(pci, sch_pci_tbl); | |
96 | MODULE_VERSION(DRV_VERSION); | |
97 | ||
98 | /** | |
99 | * sch_set_piomode - Initialize host controller PATA PIO timings | |
100 | * @ap: Port whose timings we are configuring | |
101 | * @adev: ATA device | |
102 | * | |
103 | * Set PIO mode for device, in host controller PCI config space. | |
104 | * | |
105 | * LOCKING: | |
106 | * None (inherited from caller). | |
107 | */ | |
108 | ||
109 | static void sch_set_piomode(struct ata_port *ap, struct ata_device *adev) | |
110 | { | |
111 | unsigned int pio = adev->pio_mode - XFER_PIO_0; | |
112 | struct pci_dev *dev = to_pci_dev(ap->host->dev); | |
113 | unsigned int port = adev->devno ? D1TIM : D0TIM; | |
114 | unsigned int data; | |
115 | ||
116 | pci_read_config_dword(dev, port, &data); | |
117 | /* see SCH datasheet page 351 */ | |
118 | /* set PIO mode */ | |
119 | data &= ~(PM | PPE); | |
120 | data |= pio; | |
121 | /* enable PPE for block device */ | |
122 | if (adev->class == ATA_DEV_ATA) | |
123 | data |= PPE; | |
124 | pci_write_config_dword(dev, port, data); | |
125 | } | |
126 | ||
127 | /** | |
128 | * sch_set_dmamode - Initialize host controller PATA DMA timings | |
129 | * @ap: Port whose timings we are configuring | |
130 | * @adev: ATA device | |
131 | * | |
132 | * Set MW/UDMA mode for device, in host controller PCI config space. | |
133 | * | |
134 | * LOCKING: | |
135 | * None (inherited from caller). | |
136 | */ | |
137 | ||
138 | static void sch_set_dmamode(struct ata_port *ap, struct ata_device *adev) | |
139 | { | |
140 | unsigned int dma_mode = adev->dma_mode; | |
141 | struct pci_dev *dev = to_pci_dev(ap->host->dev); | |
142 | unsigned int port = adev->devno ? D1TIM : D0TIM; | |
143 | unsigned int data; | |
144 | ||
145 | pci_read_config_dword(dev, port, &data); | |
146 | /* see SCH datasheet page 351 */ | |
147 | if (dma_mode >= XFER_UDMA_0) { | |
148 | /* enable Synchronous DMA mode */ | |
149 | data |= USD; | |
150 | data &= ~UDM; | |
151 | data |= (dma_mode - XFER_UDMA_0) << 16; | |
152 | } else { /* must be MWDMA mode, since we masked SWDMA already */ | |
153 | data &= ~(USD | MDM); | |
154 | data |= (dma_mode - XFER_MW_DMA_0) << 8; | |
155 | } | |
156 | pci_write_config_dword(dev, port, data); | |
157 | } | |
158 | ||
159 | /** | |
160 | * sch_init_one - Register SCH ATA PCI device with kernel services | |
161 | * @pdev: PCI device to register | |
162 | * @ent: Entry in sch_pci_tbl matching with @pdev | |
163 | * | |
164 | * LOCKING: | |
165 | * Inherited from PCI layer (may sleep). | |
166 | * | |
167 | * RETURNS: | |
168 | * Zero on success, or -ERRNO value. | |
169 | */ | |
170 | ||
0ec24914 | 171 | static int sch_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) |
07ab85de | 172 | { |
07ab85de | 173 | const struct ata_port_info *ppi[] = { &sch_port_info, NULL }; |
07ab85de | 174 | |
06296a1e | 175 | ata_print_version_once(&pdev->dev, DRV_VERSION); |
07ab85de | 176 | |
1c5afdf7 | 177 | return ata_pci_bmdma_init_one(pdev, ppi, &sch_sht, NULL, 0); |
07ab85de AD |
178 | } |
179 | ||
2fc75da0 | 180 | module_pci_driver(sch_pci_driver); |