Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/ata/chipsets/ata-ati.c
39536 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 1998 - 2008 Søren Schmidt <[email protected]>
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer,
12
* without modification, immediately at the beginning of the file.
13
* 2. Redistributions in binary form must reproduce the above copyright
14
* notice, this list of conditions and the following disclaimer in the
15
* documentation and/or other materials provided with the distribution.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
*/
28
29
#include <sys/param.h>
30
#include <sys/module.h>
31
#include <sys/systm.h>
32
#include <sys/kernel.h>
33
#include <sys/ata.h>
34
#include <sys/bus.h>
35
#include <sys/endian.h>
36
#include <sys/malloc.h>
37
#include <sys/lock.h>
38
#include <sys/mutex.h>
39
#include <sys/sema.h>
40
#include <sys/stdarg.h>
41
#include <sys/taskqueue.h>
42
#include <vm/uma.h>
43
#include <machine/resource.h>
44
#include <machine/bus.h>
45
#include <sys/rman.h>
46
#include <dev/pci/pcivar.h>
47
#include <dev/pci/pcireg.h>
48
#include <dev/ata/ata-all.h>
49
#include <dev/ata/ata-pci.h>
50
#include <ata_if.h>
51
52
/* local prototypes */
53
static int ata_ati_chipinit(device_t dev);
54
static int ata_ati_dumb_ch_attach(device_t dev);
55
static int ata_ati_ixp700_ch_attach(device_t dev);
56
static int ata_ati_setmode(device_t dev, int target, int mode);
57
58
/* misc defines */
59
#define SII_MEMIO 1 /* must match ata_siliconimage.c's definition */
60
#define SII_BUG 0x04 /* must match ata_siliconimage.c's definition */
61
62
#define ATI_SATA SII_MEMIO
63
#define ATI_PATA 0x02
64
#define ATI_AHCI 0x04
65
66
/*
67
* ATI chipset support functions
68
*/
69
static int
70
ata_ati_probe(device_t dev)
71
{
72
struct ata_pci_controller *ctlr = device_get_softc(dev);
73
static const struct ata_chip_id ids[] =
74
{{ ATA_ATI_IXP200, 0x00, ATI_PATA, 0, ATA_UDMA5, "IXP200" },
75
{ ATA_ATI_IXP300, 0x00, ATI_PATA, 0, ATA_UDMA6, "IXP300" },
76
{ ATA_ATI_IXP300_S1, 0x00, ATI_SATA, SII_BUG, ATA_SA150, "IXP300" },
77
{ ATA_ATI_IXP400, 0x00, ATI_PATA, 0, ATA_UDMA6, "IXP400" },
78
{ ATA_ATI_IXP400_S1, 0x00, ATI_SATA, SII_BUG, ATA_SA150, "IXP400" },
79
{ ATA_ATI_IXP400_S2, 0x00, ATI_SATA, SII_BUG, ATA_SA150, "IXP400" },
80
{ ATA_ATI_IXP600, 0x00, ATI_PATA, 0, ATA_UDMA6, "IXP600" },
81
{ ATA_ATI_IXP600_S1, 0x00, ATI_AHCI, 0, ATA_SA300, "IXP600" },
82
{ ATA_ATI_IXP700, 0x00, ATI_PATA, 0, ATA_UDMA6, "IXP700/800" },
83
{ ATA_ATI_IXP700_S1, 0x00, ATI_AHCI, 0, ATA_SA300, "IXP700/800" },
84
{ ATA_ATI_IXP700_S2, 0x00, ATI_AHCI, 0, ATA_SA300, "IXP700/800" },
85
{ ATA_ATI_IXP700_S3, 0x00, ATI_AHCI, 0, ATA_SA300, "IXP700/800" },
86
{ ATA_ATI_IXP700_S4, 0x00, ATI_AHCI, 0, ATA_SA300, "IXP700/800" },
87
{ ATA_ATI_IXP800_S1, 0x00, ATI_AHCI, 0, ATA_SA300, "IXP800" },
88
{ ATA_ATI_IXP800_S2, 0x00, ATI_AHCI, 0, ATA_SA300, "IXP800" },
89
{ ATA_AMD_HUDSON2, 0x00, ATI_PATA, 0, ATA_UDMA6, "Hudson-2" },
90
{ ATA_AMD_HUDSON2_S1, 0x00, ATI_AHCI, 0, ATA_SA300, "Hudson-2" },
91
{ ATA_AMD_HUDSON2_S2, 0x00, ATI_AHCI, 0, ATA_SA300, "Hudson-2" },
92
{ ATA_AMD_HUDSON2_S3, 0x00, ATI_AHCI, 0, ATA_SA300, "Hudson-2" },
93
{ ATA_AMD_HUDSON2_S4, 0x00, ATI_AHCI, 0, ATA_SA300, "Hudson-2" },
94
{ ATA_AMD_HUDSON2_S5, 0x00, ATI_AHCI, 0, ATA_SA300, "Hudson-2" },
95
{ 0, 0, 0, 0, 0, 0}};
96
97
if (pci_get_vendor(dev) != ATA_AMD_ID && pci_get_vendor(dev) != ATA_ATI_ID)
98
return ENXIO;
99
100
if (!(ctlr->chip = ata_match_chip(dev, ids)))
101
return ENXIO;
102
103
switch (ctlr->chip->cfg1) {
104
case ATI_PATA:
105
ctlr->chipinit = ata_ati_chipinit;
106
break;
107
case ATI_SATA:
108
/*
109
* the ATI SATA controller is actually a SiI 3112 controller
110
*/
111
ctlr->chipinit = ata_sii_chipinit;
112
break;
113
case ATI_AHCI:
114
if (pci_get_subclass(dev) != PCIS_STORAGE_IDE)
115
return (ENXIO);
116
ctlr->chipinit = ata_ati_chipinit;
117
break;
118
}
119
120
ata_set_desc(dev);
121
return (BUS_PROBE_LOW_PRIORITY);
122
}
123
124
static int
125
ata_ati_chipinit(device_t dev)
126
{
127
struct ata_pci_controller *ctlr = device_get_softc(dev);
128
device_t smbdev;
129
uint8_t satacfg;
130
131
if (ata_setup_interrupt(dev, ata_generic_intr))
132
return ENXIO;
133
134
if (ctlr->chip->cfg1 == ATI_AHCI) {
135
ctlr->ch_attach = ata_ati_dumb_ch_attach;
136
ctlr->setmode = ata_sata_setmode;
137
return (0);
138
}
139
switch (ctlr->chip->chipid) {
140
case ATA_ATI_IXP600:
141
/* IXP600 only has 1 PATA channel */
142
ctlr->channels = 1;
143
break;
144
case ATA_ATI_IXP700:
145
/*
146
* When "combined mode" is enabled, an additional PATA channel is
147
* emulated with two SATA ports and appears on this device.
148
* This mode can only be detected via SMB controller.
149
*/
150
smbdev = pci_find_device(ATA_ATI_ID, 0x4385);
151
if (smbdev != NULL) {
152
satacfg = pci_read_config(smbdev, 0xad, 1);
153
if (bootverbose)
154
device_printf(dev, "SATA controller %s (%s%s channel)\n",
155
(satacfg & 0x01) == 0 ? "disabled" : "enabled",
156
(satacfg & 0x08) == 0 ? "" : "combined mode, ",
157
(satacfg & 0x10) == 0 ? "primary" : "secondary");
158
ctlr->chipset_data = (void *)(uintptr_t)satacfg;
159
/*
160
* If SATA controller is enabled but combined mode is disabled,
161
* we have only one PATA channel. Ignore a non-existent channel.
162
*/
163
if ((satacfg & 0x09) == 0x01)
164
ctlr->ichannels &= ~(1 << ((satacfg & 0x10) >> 4));
165
else {
166
ctlr->ch_attach = ata_ati_ixp700_ch_attach;
167
}
168
}
169
break;
170
}
171
172
ctlr->setmode = ata_ati_setmode;
173
return 0;
174
}
175
176
static int
177
ata_ati_dumb_ch_attach(device_t dev)
178
{
179
struct ata_channel *ch = device_get_softc(dev);
180
181
if (ata_pci_ch_attach(dev))
182
return ENXIO;
183
ch->flags |= ATA_SATA;
184
return (0);
185
}
186
187
static int
188
ata_ati_ixp700_ch_attach(device_t dev)
189
{
190
struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
191
struct ata_channel *ch = device_get_softc(dev);
192
uint8_t satacfg = (uint8_t)(uintptr_t)ctlr->chipset_data;
193
194
/* Setup the usual register normal pci style. */
195
if (ata_pci_ch_attach(dev))
196
return ENXIO;
197
198
/* One of channels is PATA, another is SATA. */
199
if (ch->unit == ((satacfg & 0x10) >> 4))
200
ch->flags |= ATA_SATA;
201
return (0);
202
}
203
204
static int
205
ata_ati_setmode(device_t dev, int target, int mode)
206
{
207
device_t parent = device_get_parent(dev);
208
struct ata_pci_controller *ctlr = device_get_softc(parent);
209
struct ata_channel *ch = device_get_softc(dev);
210
int devno = (ch->unit << 1) + target;
211
int offset = (devno ^ 0x01) << 3;
212
int piomode;
213
static const uint8_t piotimings[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
214
static const uint8_t dmatimings[] = { 0x77, 0x21, 0x20 };
215
216
mode = min(mode, ctlr->chip->max_dma);
217
if (mode >= ATA_UDMA0) {
218
/* Set UDMA mode, enable UDMA, set WDMA2/PIO4 */
219
pci_write_config(parent, 0x56,
220
(pci_read_config(parent, 0x56, 2) &
221
~(0xf << (devno << 2))) |
222
((mode & ATA_MODE_MASK) << (devno << 2)), 2);
223
pci_write_config(parent, 0x54,
224
pci_read_config(parent, 0x54, 1) |
225
(0x01 << devno), 1);
226
pci_write_config(parent, 0x44,
227
(pci_read_config(parent, 0x44, 4) &
228
~(0xff << offset)) |
229
(dmatimings[2] << offset), 4);
230
piomode = ATA_PIO4;
231
} else if (mode >= ATA_WDMA0) {
232
/* Disable UDMA, set WDMA mode and timings, calculate PIO. */
233
pci_write_config(parent, 0x54,
234
pci_read_config(parent, 0x54, 1) &
235
~(0x01 << devno), 1);
236
pci_write_config(parent, 0x44,
237
(pci_read_config(parent, 0x44, 4) &
238
~(0xff << offset)) |
239
(dmatimings[mode & ATA_MODE_MASK] << offset), 4);
240
piomode = (mode == ATA_WDMA0) ? ATA_PIO0 :
241
(mode == ATA_WDMA1) ? ATA_PIO3 : ATA_PIO4;
242
} else {
243
/* Disable UDMA, set requested PIO. */
244
pci_write_config(parent, 0x54,
245
pci_read_config(parent, 0x54, 1) &
246
~(0x01 << devno), 1);
247
piomode = mode;
248
}
249
/* Set PIO mode and timings, calculated above. */
250
pci_write_config(parent, 0x4a,
251
(pci_read_config(parent, 0x4a, 2) &
252
~(0xf << (devno << 2))) |
253
((piomode - ATA_PIO0) << (devno<<2)),2);
254
pci_write_config(parent, 0x40,
255
(pci_read_config(parent, 0x40, 4) &
256
~(0xff << offset)) |
257
(piotimings[ata_mode2idx(piomode)] << offset), 4);
258
return (mode);
259
}
260
261
ATA_DECLARE_DRIVER(ata_ati);
262
MODULE_DEPEND(ata_ati, ata_sii, 1, 1, 1);
263
264