2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright 2004 by Peter Grehan. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
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,
22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
32 * Mac 'Kauai' PCI ATA controller
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/module.h>
39 #include <sys/malloc.h>
41 #include <sys/taskqueue.h>
43 #include <machine/stdarg.h>
44 #include <machine/resource.h>
45 #include <machine/bus.h>
48 #include <dev/ata/ata-all.h>
51 #include <dev/ofw/openfirm.h>
52 #include <dev/ofw/ofw_bus.h>
53 #include <machine/intr_machdep.h>
55 #include <dev/pci/pcivar.h>
56 #include <dev/pci/pcireg.h>
58 #include "ata_dbdma.h"
60 #define ATA_KAUAI_REGOFFSET 0x2000
61 #define ATA_KAUAI_DBDMAOFFSET 0x1000
64 * Offset to alt-control register from base
66 #define ATA_KAUAI_ALTOFFSET (ATA_KAUAI_REGOFFSET + 0x160)
69 * Define the gap between registers
71 #define ATA_KAUAI_REGGAP 16
74 * PIO and DMA access registers
76 #define PIO_CONFIG_REG (ATA_KAUAI_REGOFFSET + 0x200)
77 #define UDMA_CONFIG_REG (ATA_KAUAI_REGOFFSET + 0x210)
78 #define DMA_IRQ_REG (ATA_KAUAI_REGOFFSET + 0x300)
80 #define USE_DBDMA_IRQ 0
83 * Define the kauai pci bus attachment.
85 static int ata_kauai_probe(device_t dev
);
86 static int ata_kauai_attach(device_t dev
);
87 static int ata_kauai_setmode(device_t dev
, int target
, int mode
);
88 static int ata_kauai_begin_transaction(struct ata_request
*request
);
90 static device_method_t ata_kauai_methods
[] = {
91 /* Device interface */
92 DEVMETHOD(device_probe
, ata_kauai_probe
),
93 DEVMETHOD(device_attach
, ata_kauai_attach
),
94 DEVMETHOD(device_detach
, bus_generic_detach
),
95 DEVMETHOD(device_shutdown
, bus_generic_shutdown
),
96 DEVMETHOD(device_suspend
, bus_generic_suspend
),
97 DEVMETHOD(device_resume
, bus_generic_resume
),
100 DEVMETHOD(ata_setmode
, ata_kauai_setmode
),
104 struct ata_kauai_softc
{
105 struct ata_dbdma_channel sc_ch
;
107 struct resource
*sc_memr
;
111 uint32_t udmaconf
[2];
112 uint32_t wdmaconf
[2];
116 static driver_t ata_kauai_driver
= {
119 sizeof(struct ata_kauai_softc
),
122 DRIVER_MODULE(ata
, pci
, ata_kauai_driver
, NULL
, NULL
);
123 MODULE_DEPEND(ata
, ata
, 1, 1, 1);
126 * PCI ID search table
128 static const struct kauai_pci_dev
{
130 const char *kpd_desc
;
131 } kauai_pci_devlist
[] = {
132 { 0x0033106b, "Uninorth2 Kauai ATA Controller" },
133 { 0x003b106b, "Intrepid Kauai ATA Controller" },
134 { 0x0043106b, "K2 Kauai ATA Controller" },
135 { 0x0050106b, "Shasta Kauai ATA Controller" },
136 { 0x0069106b, "Intrepid-2 Kauai ATA Controller" },
141 * IDE transfer timings
143 #define KAUAI_PIO_MASK 0xff000fff
144 #define KAUAI_DMA_MASK 0x00fff000
145 #define KAUAI_UDMA_MASK 0x0000ffff
147 static const u_int pio_timing_kauai
[] = {
148 0x08000a92, /* PIO0 */
149 0x0800060f, /* PIO1 */
150 0x0800038b, /* PIO2 */
151 0x05000249, /* PIO3 */
152 0x04000148 /* PIO4 */
155 static const u_int pio_timing_shasta
[] = {
156 0x0a000c97, /* PIO0 */
157 0x07000712, /* PIO1 */
158 0x040003cd, /* PIO2 */
159 0x0400028b, /* PIO3 */
160 0x0400010a /* PIO4 */
163 static const u_int dma_timing_kauai
[] = {
164 0x00618000, /* WDMA0 */
165 0x00209000, /* WDMA1 */
166 0x00148000 /* WDMA2 */
169 static const u_int dma_timing_shasta
[] = {
170 0x00820800, /* WDMA0 */
171 0x0028b000, /* WDMA1 */
172 0x001ca000 /* WDMA2 */
175 static const u_int udma_timing_kauai
[] = {
176 0x000070c1, /* UDMA0 */
177 0x00005d81, /* UDMA1 */
178 0x00004a61, /* UDMA2 */
179 0x00003a51, /* UDMA3 */
180 0x00002a31, /* UDMA4 */
181 0x00002921 /* UDMA5 */
184 static const u_int udma_timing_shasta
[] = {
185 0x00035901, /* UDMA0 */
186 0x000348b1, /* UDMA1 */
187 0x00033881, /* UDMA2 */
188 0x00033861, /* UDMA3 */
189 0x00033841, /* UDMA4 */
190 0x00033031, /* UDMA5 */
191 0x00033021 /* UDMA6 */
195 ata_kauai_probe(device_t dev
)
201 devid
= pci_get_devid(dev
);
202 for (i
= 0; kauai_pci_devlist
[i
].kpd_desc
!= NULL
; i
++) {
203 if (devid
== kauai_pci_devlist
[i
].kpd_devid
) {
205 device_set_desc(dev
, kauai_pci_devlist
[i
].kpd_desc
);
212 return (ata_probe(dev
));
217 ata_kauai_dma_interrupt(struct ata_kauai_softc
*sc
)
219 /* Clear the DMA interrupt bits */
221 bus_write_4(sc
->sc_memr
, DMA_IRQ_REG
, 0x80000000);
223 return ata_interrupt(sc
);
228 ata_kauai_attach(device_t dev
)
230 struct ata_kauai_softc
*sc
= device_get_softc(dev
);
231 struct ata_channel
*ch
;
232 const char *compatstring
;
235 int dbdma_irq_rid
= 1;
236 struct resource
*dbdma_irq
;
240 compatstring
= ofw_bus_get_compat(dev
);
241 if (compatstring
!= NULL
&& strcmp(compatstring
,"shasta-ata") == 0)
244 /* Pre-K2 controllers apparently need this hack */
246 (compatstring
== NULL
|| strcmp(compatstring
, "K2-UATA") != 0))
247 bus_set_resource(dev
, SYS_RES_IRQ
, 0, 39, 1);
249 ch
= &sc
->sc_ch
.sc_ch
;
252 sc
->sc_memr
= bus_alloc_resource_any(dev
, SYS_RES_MEMORY
, &rid
,
254 if (sc
->sc_memr
== NULL
) {
255 device_printf(dev
, "could not allocate memory\n");
260 * Set up the resource vectors
262 for (i
= ATA_DATA
; i
<= ATA_COMMAND
; i
++) {
263 ch
->r_io
[i
].res
= sc
->sc_memr
;
264 ch
->r_io
[i
].offset
= i
*ATA_KAUAI_REGGAP
+ ATA_KAUAI_REGOFFSET
;
266 ch
->r_io
[ATA_CONTROL
].res
= sc
->sc_memr
;
267 ch
->r_io
[ATA_CONTROL
].offset
= ATA_KAUAI_ALTOFFSET
;
268 ata_default_registers(dev
);
271 ch
->flags
|= ATA_USE_16BIT
;
273 /* XXX: ATAPI DMA is unreliable. We should find out why. */
274 ch
->flags
|= ATA_NO_ATAPI_DMA
;
277 pci_enable_busmaster(dev
);
279 /* Init DMA engine */
281 sc
->sc_ch
.dbdma_rid
= 1;
282 sc
->sc_ch
.dbdma_regs
= sc
->sc_memr
;
283 sc
->sc_ch
.dbdma_offset
= ATA_KAUAI_DBDMAOFFSET
;
285 ata_dbdma_dmainit(dev
);
288 /* Bind to DBDMA interrupt as well */
289 if ((dbdma_irq
= bus_alloc_resource_any(dev
, SYS_RES_IRQ
,
290 &dbdma_irq_rid
, RF_SHAREABLE
| RF_ACTIVE
)) != NULL
) {
291 bus_setup_intr(dev
, dbdma_irq
, ATA_INTR_FLAGS
, NULL
,
292 (driver_intr_t
*)ata_kauai_dma_interrupt
, sc
,&cookie
);
296 /* Set up initial mode */
297 sc
->pioconf
[0] = sc
->pioconf
[1] =
298 bus_read_4(sc
->sc_memr
, PIO_CONFIG_REG
) & 0x0f000fff;
300 sc
->udmaconf
[0] = sc
->udmaconf
[1] = 0;
301 sc
->wdmaconf
[0] = sc
->wdmaconf
[1] = 0;
303 /* Magic FCR value from Apple */
304 bus_write_4(sc
->sc_memr
, 0, 0x00000007);
306 /* Set begin_transaction */
307 sc
->sc_ch
.sc_ch
.hw
.begin_transaction
= ata_kauai_begin_transaction
;
309 return ata_attach(dev
);
313 ata_kauai_setmode(device_t dev
, int target
, int mode
)
315 struct ata_kauai_softc
*sc
= device_get_softc(dev
);
317 mode
= min(mode
,sc
->shasta
? ATA_UDMA6
: ATA_UDMA5
);
320 switch (mode
& ATA_DMA_MASK
) {
323 = udma_timing_shasta
[mode
& ATA_MODE_MASK
];
326 sc
->udmaconf
[target
] = 0;
328 = dma_timing_shasta
[mode
& ATA_MODE_MASK
];
332 = pio_timing_shasta
[(mode
& ATA_MODE_MASK
) -
337 switch (mode
& ATA_DMA_MASK
) {
340 = udma_timing_kauai
[mode
& ATA_MODE_MASK
];
343 sc
->udmaconf
[target
] = 0;
345 = dma_timing_kauai
[mode
& ATA_MODE_MASK
];
349 = pio_timing_kauai
[(mode
& ATA_MODE_MASK
)
359 ata_kauai_begin_transaction(struct ata_request
*request
)
361 struct ata_kauai_softc
*sc
= device_get_softc(request
->parent
);
363 bus_write_4(sc
->sc_memr
, UDMA_CONFIG_REG
, sc
->udmaconf
[request
->unit
]);
364 bus_write_4(sc
->sc_memr
, PIO_CONFIG_REG
,
365 sc
->wdmaconf
[request
->unit
] | sc
->pioconf
[request
->unit
]);
367 return ata_begin_transaction(request
);