ata-marvell.c revision 198718
1210008Srdivacky/*-
2210008Srdivacky * Copyright (c) 1998 - 2008 S�ren Schmidt <sos@FreeBSD.org>
3210008Srdivacky * All rights reserved.
4210008Srdivacky *
5210008Srdivacky * Redistribution and use in source and binary forms, with or without
6210008Srdivacky * modification, are permitted provided that the following conditions
7210008Srdivacky * are met:
8210008Srdivacky * 1. Redistributions of source code must retain the above copyright
9210008Srdivacky *    notice, this list of conditions and the following disclaimer,
10210008Srdivacky *    without modification, immediately at the beginning of the file.
11210008Srdivacky * 2. Redistributions in binary form must reproduce the above copyright
12249423Sdim *    notice, this list of conditions and the following disclaimer in the
13210008Srdivacky *    documentation and/or other materials provided with the distribution.
14210008Srdivacky *
15210008Srdivacky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16226633Sdim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17210008Srdivacky * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18210008Srdivacky * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19210008Srdivacky * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20210008Srdivacky * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21249423Sdim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22249423Sdim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23224145Sdim * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24249423Sdim * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25210008Srdivacky */
26210008Srdivacky
27210008Srdivacky#include <sys/cdefs.h>
28226633Sdim__FBSDID("$FreeBSD: head/sys/dev/ata/chipsets/ata-marvell.c 198718 2009-10-31 14:19:50Z mav $");
29210008Srdivacky
30210008Srdivacky#include "opt_ata.h"
31226633Sdim#include <sys/param.h>
32210008Srdivacky#include <sys/module.h>
33210008Srdivacky#include <sys/systm.h>
34226633Sdim#include <sys/kernel.h>
35226633Sdim#include <sys/ata.h>
36249423Sdim#include <sys/bus.h>
37249423Sdim#include <sys/endian.h>
38226633Sdim#include <sys/malloc.h>
39210008Srdivacky#include <sys/lock.h>
40210008Srdivacky#include <sys/mutex.h>
41210008Srdivacky#include <sys/sema.h>
42210008Srdivacky#include <sys/taskqueue.h>
43210008Srdivacky#include <vm/uma.h>
44210008Srdivacky#include <machine/stdarg.h>
45226633Sdim#include <machine/resource.h>
46210008Srdivacky#include <machine/bus.h>
47234353Sdim#include <sys/rman.h>
48224145Sdim#include <dev/pci/pcivar.h>
49210008Srdivacky#include <dev/pci/pcireg.h>
50210008Srdivacky#include <dev/ata/ata-all.h>
51210008Srdivacky#include <dev/ata/ata-pci.h>
52210008Srdivacky#include <ata_if.h>
53218893Sdim
54210008Srdivacky/* local prototypes */
55210008Srdivackystatic int ata_marvell_pata_chipinit(device_t dev);
56210008Srdivackystatic int ata_marvell_pata_ch_attach(device_t dev);
57210008Srdivackystatic void ata_marvell_pata_setmode(device_t dev, int mode);
58243830Sdimstatic int ata_marvell_edma_ch_attach(device_t dev);
59210008Srdivackystatic int ata_marvell_edma_ch_detach(device_t dev);
60218893Sdimstatic int ata_marvell_edma_status(device_t dev);
61243830Sdimstatic int ata_marvell_edma_begin_transaction(struct ata_request *request);
62249423Sdimstatic int ata_marvell_edma_end_transaction(struct ata_request *request);
63249423Sdimstatic void ata_marvell_edma_reset(device_t dev);
64210008Srdivackystatic void ata_marvell_edma_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error);
65210008Srdivackystatic void ata_marvell_edma_dmainit(device_t dev);
66210008Srdivacky
67210008Srdivacky/* misc defines */
68243830Sdim#define MV_50XX		50
69210008Srdivacky#define MV_60XX		60
70210008Srdivacky#define MV_6042		62
71243830Sdim#define MV_7042		72
72249423Sdim#define MV_61XX		61
73249423Sdim
74210008Srdivacky
75210008Srdivacky/*
76210008Srdivacky * Marvell chipset support functions
77210008Srdivacky */
78243830Sdim#define ATA_MV_HOST_BASE(ch) \
79210008Srdivacky	((ch->unit & 3) * 0x0100) + (ch->unit > 3 ? 0x30000 : 0x20000)
80210008Srdivacky#define ATA_MV_EDMA_BASE(ch) \
81243830Sdim	((ch->unit & 3) * 0x2000) + (ch->unit > 3 ? 0x30000 : 0x20000)
82249423Sdim
83249423Sdimstruct ata_marvell_response {
84210008Srdivacky    u_int16_t   tag;
85210008Srdivacky    u_int8_t    edma_status;
86210008Srdivacky    u_int8_t    dev_status;
87210008Srdivacky    u_int32_t   timestamp;
88210008Srdivacky};
89243830Sdim
90243830Sdimstruct ata_marvell_dma_prdentry {
91243830Sdim    u_int32_t addrlo;
92243830Sdim    u_int32_t count;
93243830Sdim    u_int32_t addrhi;
94243830Sdim    u_int32_t reserved;
95243830Sdim};
96243830Sdim
97243830Sdimstatic int
98243830Sdimata_marvell_probe(device_t dev)
99243830Sdim{
100243830Sdim    struct ata_pci_controller *ctlr = device_get_softc(dev);
101210008Srdivacky    static struct ata_chip_id ids[] =
102210008Srdivacky    {{ ATA_M88SX5040, 0, 4, MV_50XX, ATA_SA150, "88SX5040" },
103210008Srdivacky     { ATA_M88SX5041, 0, 4, MV_50XX, ATA_SA150, "88SX5041" },
104243830Sdim     { ATA_M88SX5080, 0, 8, MV_50XX, ATA_SA150, "88SX5080" },
105243830Sdim     { ATA_M88SX5081, 0, 8, MV_50XX, ATA_SA150, "88SX5081" },
106210008Srdivacky     { ATA_M88SX6041, 0, 4, MV_60XX, ATA_SA300, "88SX6041" },
107210008Srdivacky     { ATA_M88SX6042, 0, 4, MV_6042, ATA_SA300, "88SX6042" },
108226633Sdim     { ATA_M88SX6081, 0, 8, MV_60XX, ATA_SA300, "88SX6081" },
109234353Sdim     { ATA_M88SX7042, 0, 4, MV_7042, ATA_SA300, "88SX7042" },
110234353Sdim     { ATA_M88SX6101, 0, 1, MV_61XX, ATA_UDMA6, "88SX6101" },
111224145Sdim     { ATA_M88SX6121, 0, 1, MV_61XX, ATA_UDMA6, "88SX6121" },
112210008Srdivacky     { ATA_M88SX6145, 0, 2, MV_61XX, ATA_UDMA6, "88SX6145" },
113224145Sdim     { 0, 0, 0, 0, 0, 0}};
114210008Srdivacky
115210008Srdivacky    if (pci_get_vendor(dev) != ATA_MARVELL_ID)
116210008Srdivacky	return ENXIO;
117210008Srdivacky
118210008Srdivacky    if (!(ctlr->chip = ata_match_chip(dev, ids)))
119210008Srdivacky	return ENXIO;
120210008Srdivacky
121210008Srdivacky    ata_set_desc(dev);
122210008Srdivacky
123210008Srdivacky    switch (ctlr->chip->cfg2) {
124210008Srdivacky    case MV_50XX:
125210008Srdivacky    case MV_60XX:
126249423Sdim    case MV_6042:
127249423Sdim    case MV_7042:
128249423Sdim	ctlr->chipinit = ata_marvell_edma_chipinit;
129249423Sdim	break;
130249423Sdim    case MV_61XX:
131249423Sdim	ctlr->chipinit = ata_marvell_pata_chipinit;
132249423Sdim	break;
133249423Sdim    }
134249423Sdim    return (BUS_PROBE_DEFAULT);
135249423Sdim}
136249423Sdim
137249423Sdimstatic int
138249423Sdimata_marvell_pata_chipinit(device_t dev)
139249423Sdim{
140210008Srdivacky    struct ata_pci_controller *ctlr = device_get_softc(dev);
141210008Srdivacky
142234353Sdim    if (ata_setup_interrupt(dev, ata_generic_intr))
143234353Sdim	return ENXIO;
144234353Sdim
145234353Sdim    ctlr->ch_attach = ata_marvell_pata_ch_attach;
146234353Sdim    ctlr->ch_detach = ata_pci_ch_detach;
147224145Sdim    ctlr->setmode = ata_marvell_pata_setmode;
148224145Sdim    ctlr->channels = ctlr->chip->cfg1;
149224145Sdim    return 0;
150224145Sdim}
151224145Sdim
152224145Sdimstatic int
153224145Sdimata_marvell_pata_ch_attach(device_t dev)
154224145Sdim{
155224145Sdim    struct ata_channel *ch = device_get_softc(dev);
156224145Sdim
157239462Sdim    /* setup the usual register normal pci style */
158239462Sdim    if (ata_pci_ch_attach(dev))
159249423Sdim	return ENXIO;
160239462Sdim
161239462Sdim    /* dont use 32 bit PIO transfers */
162249423Sdim	ch->flags |= ATA_USE_16BIT;
163249423Sdim
164249423Sdim    return 0;
165249423Sdim}
166249423Sdim
167249423Sdimstatic void
168249423Sdimata_marvell_pata_setmode(device_t dev, int mode)
169249423Sdim{
170249423Sdim    device_t gparent = GRANDPARENT(dev);
171249423Sdim    struct ata_pci_controller *ctlr = device_get_softc(gparent);
172249423Sdim    struct ata_device *atadev = device_get_softc(dev);
173249423Sdim
174249423Sdim    mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma);
175249423Sdim    mode = ata_check_80pin(dev, mode);
176249423Sdim    if (!ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode))
177249423Sdim	atadev->mode = mode;
178234353Sdim}
179234353Sdim
180249423Sdimint
181249423Sdimata_marvell_edma_chipinit(device_t dev)
182249423Sdim{
183249423Sdim    struct ata_pci_controller *ctlr = device_get_softc(dev);
184249423Sdim
185249423Sdim    if (ata_setup_interrupt(dev, ata_generic_intr))
186249423Sdim	return ENXIO;
187249423Sdim
188249423Sdim    ctlr->r_type1 = SYS_RES_MEMORY;
189249423Sdim    ctlr->r_rid1 = PCIR_BAR(0);
190249423Sdim    if (!(ctlr->r_res1 = bus_alloc_resource_any(dev, ctlr->r_type1,
191249423Sdim						&ctlr->r_rid1, RF_ACTIVE)))
192249423Sdim	return ENXIO;
193249423Sdim
194249423Sdim    /* mask all host controller interrupts */
195249423Sdim    ATA_OUTL(ctlr->r_res1, 0x01d64, 0x00000000);
196249423Sdim
197249423Sdim    /* mask all PCI interrupts */
198249423Sdim    ATA_OUTL(ctlr->r_res1, 0x01d5c, 0x00000000);
199249423Sdim
200249423Sdim    ctlr->ch_attach = ata_marvell_edma_ch_attach;
201234353Sdim    ctlr->ch_detach = ata_marvell_edma_ch_detach;
202234353Sdim    ctlr->reset = ata_marvell_edma_reset;
203249423Sdim    ctlr->setmode = ata_sata_setmode;
204249423Sdim    ctlr->channels = ctlr->chip->cfg1;
205249423Sdim
206249423Sdim    /* clear host controller interrupts */
207234353Sdim    ATA_OUTL(ctlr->r_res1, 0x20014, 0x00000000);
208234353Sdim    if (ctlr->chip->cfg1 > 4)
209243830Sdim	ATA_OUTL(ctlr->r_res1, 0x30014, 0x00000000);
210210008Srdivacky
211243830Sdim    /* clear PCI interrupts */
212210008Srdivacky    ATA_OUTL(ctlr->r_res1, 0x01d58, 0x00000000);
213210008Srdivacky
214210008Srdivacky    /* unmask PCI interrupts we want */
215210008Srdivacky    ATA_OUTL(ctlr->r_res1, 0x01d5c, 0x007fffff);
216210008Srdivacky
217210008Srdivacky    /* unmask host controller interrupts we want */
218210008Srdivacky    ATA_OUTL(ctlr->r_res1, 0x01d64, 0x000000ff/*HC0*/ | 0x0001fe00/*HC1*/ |
219249423Sdim	     /*(1<<19) | (1<<20) | (1<<21) |*/(1<<22) | (1<<24) | (0x7f << 25));
220249423Sdim
221223017Sdim    return 0;
222223017Sdim}
223221345Sdim
224223017Sdimstatic int
225223017Sdimata_marvell_edma_ch_attach(device_t dev)
226223017Sdim{
227224145Sdim    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
228224145Sdim    struct ata_channel *ch = device_get_softc(dev);
229224145Sdim    u_int64_t work;
230224145Sdim    int i;
231224145Sdim
232234353Sdim    ata_marvell_edma_dmainit(dev);
233234353Sdim    work = ch->dma.work_bus;
234224145Sdim    /* clear work area */
235224145Sdim    bzero(ch->dma.work, 1024+256);
236224145Sdim    bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map,
237234353Sdim	BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
238249423Sdim
239239462Sdim    /* set legacy ATA resources */
240239462Sdim    for (i = ATA_DATA; i <= ATA_COMMAND; i++) {
241239462Sdim	ch->r_io[i].res = ctlr->r_res1;
242239462Sdim	ch->r_io[i].offset = 0x02100 + (i << 2) + ATA_MV_EDMA_BASE(ch);
243239462Sdim    }
244239462Sdim    ch->r_io[ATA_CONTROL].res = ctlr->r_res1;
245249423Sdim    ch->r_io[ATA_CONTROL].offset = 0x02120 + ATA_MV_EDMA_BASE(ch);
246243830Sdim    ch->r_io[ATA_IDX_ADDR].res = ctlr->r_res1;
247249423Sdim    ata_default_registers(dev);
248234353Sdim
249249423Sdim    /* set SATA resources */
250234353Sdim    switch (ctlr->chip->cfg2) {
251234353Sdim    case MV_50XX:
252249423Sdim	ch->r_io[ATA_SSTATUS].res = ctlr->r_res1;
253234353Sdim	ch->r_io[ATA_SSTATUS].offset =  0x00100 + ATA_MV_HOST_BASE(ch);
254249423Sdim	ch->r_io[ATA_SERROR].res = ctlr->r_res1;
255249423Sdim	ch->r_io[ATA_SERROR].offset = 0x00104 + ATA_MV_HOST_BASE(ch);
256249423Sdim	ch->r_io[ATA_SCONTROL].res = ctlr->r_res1;
257249423Sdim	ch->r_io[ATA_SCONTROL].offset = 0x00108 + ATA_MV_HOST_BASE(ch);
258249423Sdim	break;
259249423Sdim    case MV_60XX:
260249423Sdim    case MV_6042:
261234353Sdim    case MV_7042:
262234353Sdim	ch->r_io[ATA_SSTATUS].res = ctlr->r_res1;
263234353Sdim	ch->r_io[ATA_SSTATUS].offset =  0x02300 + ATA_MV_EDMA_BASE(ch);
264234353Sdim	ch->r_io[ATA_SERROR].res = ctlr->r_res1;
265234353Sdim	ch->r_io[ATA_SERROR].offset = 0x02304 + ATA_MV_EDMA_BASE(ch);
266223017Sdim	ch->r_io[ATA_SCONTROL].res = ctlr->r_res1;
267223017Sdim	ch->r_io[ATA_SCONTROL].offset = 0x02308 + ATA_MV_EDMA_BASE(ch);
268223017Sdim	ch->r_io[ATA_SACTIVE].res = ctlr->r_res1;
269218893Sdim	ch->r_io[ATA_SACTIVE].offset = 0x02350 + ATA_MV_EDMA_BASE(ch);
270223017Sdim	break;
271223017Sdim    }
272210008Srdivacky
273210008Srdivacky    ch->flags |= ATA_NO_SLAVE;
274210008Srdivacky    ch->flags |= ATA_USE_16BIT; /* XXX SOS needed ? */
275210008Srdivacky    ata_generic_hw(dev);
276210008Srdivacky    ch->hw.begin_transaction = ata_marvell_edma_begin_transaction;
277223017Sdim    ch->hw.end_transaction = ata_marvell_edma_end_transaction;
278210008Srdivacky    ch->hw.status = ata_marvell_edma_status;
279223017Sdim
280221345Sdim    /* disable the EDMA machinery */
281210008Srdivacky    ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000002);
282210008Srdivacky    DELAY(100000);       /* SOS should poll for disabled */
283223017Sdim
284210008Srdivacky    /* set configuration to non-queued 128b read transfers stop on error */
285210008Srdivacky    ATA_OUTL(ctlr->r_res1, 0x02000 + ATA_MV_EDMA_BASE(ch), (1<<11) | (1<<13));
286210008Srdivacky
287223017Sdim    /* request queue base high */
288234353Sdim    ATA_OUTL(ctlr->r_res1, 0x02010 + ATA_MV_EDMA_BASE(ch), work >> 32);
289234353Sdim
290234353Sdim    /* request queue in ptr */
291234353Sdim    ATA_OUTL(ctlr->r_res1, 0x02014 + ATA_MV_EDMA_BASE(ch), work & 0xffffffff);
292234353Sdim
293210008Srdivacky    /* request queue out ptr */
294210008Srdivacky    ATA_OUTL(ctlr->r_res1, 0x02018 + ATA_MV_EDMA_BASE(ch), 0x0);
295210008Srdivacky
296223017Sdim    /* response queue base high */
297243830Sdim    work += 1024;
298223017Sdim    ATA_OUTL(ctlr->r_res1, 0x0201c + ATA_MV_EDMA_BASE(ch), work >> 32);
299223017Sdim
300223017Sdim    /* response queue in ptr */
301223017Sdim    ATA_OUTL(ctlr->r_res1, 0x02020 + ATA_MV_EDMA_BASE(ch), 0x0);
302223017Sdim
303243830Sdim    /* response queue out ptr */
304221345Sdim    ATA_OUTL(ctlr->r_res1, 0x02024 + ATA_MV_EDMA_BASE(ch), work & 0xffffffff);
305249423Sdim
306249423Sdim    /* clear SATA error register */
307249423Sdim    ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR));
308249423Sdim
309249423Sdim    /* clear any outstanding error interrupts */
310249423Sdim    ATA_OUTL(ctlr->r_res1, 0x02008 + ATA_MV_EDMA_BASE(ch), 0x0);
311249423Sdim
312249423Sdim    /* unmask all error interrupts */
313249423Sdim    ATA_OUTL(ctlr->r_res1, 0x0200c + ATA_MV_EDMA_BASE(ch), ~0x0);
314249423Sdim
315249423Sdim    /* enable EDMA machinery */
316249423Sdim    ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000001);
317249423Sdim    return 0;
318243830Sdim}
319221345Sdim
320221345Sdimstatic int
321243830Sdimata_marvell_edma_ch_detach(device_t dev)
322223017Sdim{
323210008Srdivacky    struct ata_channel *ch = device_get_softc(dev);
324210008Srdivacky
325243830Sdim    if (ch->dma.work_tag && ch->dma.work_map)
326210008Srdivacky	bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map,
327210008Srdivacky	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
328210008Srdivacky    ata_dmafini(dev);
329210008Srdivacky    return (0);
330210008Srdivacky}
331243830Sdim
332243830Sdimstatic int
333243830Sdimata_marvell_edma_status(device_t dev)
334210008Srdivacky{
335210008Srdivacky    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
336210008Srdivacky    struct ata_channel *ch = device_get_softc(dev);
337210008Srdivacky    u_int32_t cause = ATA_INL(ctlr->r_res1, 0x01d60);
338210008Srdivacky    int shift = (ch->unit << 1) + (ch->unit > 3);
339210008Srdivacky
340210008Srdivacky    if (cause & (1 << shift)) {
341210008Srdivacky
342210008Srdivacky	/* clear interrupt(s) */
343210008Srdivacky	ATA_OUTL(ctlr->r_res1, 0x02008 + ATA_MV_EDMA_BASE(ch), 0x0);
344210008Srdivacky
345210008Srdivacky	/* do we have any PHY events ? */
346226633Sdim	ata_sata_phy_check_events(dev);
347210008Srdivacky    }
348226633Sdim
349210008Srdivacky    /* do we have any device action ? */
350226633Sdim    return (cause & (2 << shift));
351210008Srdivacky}
352226633Sdim
353210008Srdivacky/* must be called with ATA channel locked and state_mtx held */
354226633Sdimstatic int
355210008Srdivackyata_marvell_edma_begin_transaction(struct ata_request *request)
356210008Srdivacky{
357226633Sdim    struct ata_pci_controller *ctlr=device_get_softc(device_get_parent(request->parent));
358210008Srdivacky    struct ata_channel *ch = device_get_softc(request->parent);
359210008Srdivacky    u_int32_t req_in;
360234353Sdim    u_int8_t *bytep;
361210008Srdivacky    int i;
362210008Srdivacky    int error, slot;
363210008Srdivacky
364210008Srdivacky    /* only DMA R/W goes through the EMDA machine */
365210008Srdivacky    if (request->u.ata.command != ATA_READ_DMA &&
366210008Srdivacky	request->u.ata.command != ATA_WRITE_DMA &&
367210008Srdivacky	request->u.ata.command != ATA_READ_DMA48 &&
368210008Srdivacky	request->u.ata.command != ATA_WRITE_DMA48) {
369210008Srdivacky
370210008Srdivacky	/* disable the EDMA machinery */
371210008Srdivacky	if (ATA_INL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch)) & 0x00000001)
372221345Sdim	    ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000002);
373221345Sdim	return ata_begin_transaction(request);
374226633Sdim    }
375226633Sdim
376210008Srdivacky    /* check sanity, setup SG list and DMA engine */
377210008Srdivacky    if ((error = ch->dma.load(request, NULL, NULL))) {
378234353Sdim	device_printf(request->parent, "setting up DMA failed\n");
379210008Srdivacky	request->result = error;
380210008Srdivacky	return ATA_OP_FINISHED;
381224145Sdim    }
382210008Srdivacky
383210008Srdivacky    /* get next free request queue slot */
384210008Srdivacky    req_in = ATA_INL(ctlr->r_res1, 0x02014 + ATA_MV_EDMA_BASE(ch));
385210008Srdivacky    slot = (((req_in & ~0xfffffc00) >> 5) + 0) & 0x1f;
386210008Srdivacky    bytep = (u_int8_t *)(ch->dma.work);
387210008Srdivacky    bytep += (slot << 5);
388210008Srdivacky
389226633Sdim    /* fill in this request */
390226633Sdim    le32enc(bytep + 0 * sizeof(u_int32_t),
391226633Sdim	request->dma->sg_bus & 0xffffffff);
392226633Sdim    le32enc(bytep + 1 * sizeof(u_int32_t),
393226633Sdim	(u_int64_t)request->dma->sg_bus >> 32);
394226633Sdim    if (ctlr->chip->cfg2 != MV_6042 && ctlr->chip->cfg2 != MV_7042) {
395226633Sdim	    le16enc(bytep + 4 * sizeof(u_int16_t),
396226633Sdim		(request->flags & ATA_R_READ ? 0x01 : 0x00) | (request->tag << 1));
397226633Sdim
398226633Sdim	    i = 10;
399226633Sdim	    bytep[i++] = (request->u.ata.count >> 8) & 0xff;
400226633Sdim	    bytep[i++] = 0x10 | ATA_COUNT;
401234353Sdim	    bytep[i++] = request->u.ata.count & 0xff;
402234353Sdim	    bytep[i++] = 0x10 | ATA_COUNT;
403234353Sdim
404234353Sdim	    bytep[i++] = (request->u.ata.lba >> 24) & 0xff;
405234353Sdim	    bytep[i++] = 0x10 | ATA_SECTOR;
406234353Sdim	    bytep[i++] = request->u.ata.lba & 0xff;
407234353Sdim	    bytep[i++] = 0x10 | ATA_SECTOR;
408234353Sdim
409234353Sdim	    bytep[i++] = (request->u.ata.lba >> 32) & 0xff;
410234353Sdim	    bytep[i++] = 0x10 | ATA_CYL_LSB;
411234353Sdim	    bytep[i++] = (request->u.ata.lba >> 8) & 0xff;
412234353Sdim	    bytep[i++] = 0x10 | ATA_CYL_LSB;
413234353Sdim
414234353Sdim	    bytep[i++] = (request->u.ata.lba >> 40) & 0xff;
415234353Sdim	    bytep[i++] = 0x10 | ATA_CYL_MSB;
416234353Sdim	    bytep[i++] = (request->u.ata.lba >> 16) & 0xff;
417234353Sdim	    bytep[i++] = 0x10 | ATA_CYL_MSB;
418234353Sdim
419234353Sdim	    bytep[i++] = ATA_D_LBA | ATA_D_IBM | ((request->u.ata.lba >> 24) & 0xf);
420234353Sdim	    bytep[i++] = 0x10 | ATA_DRIVE;
421234353Sdim
422239462Sdim	    bytep[i++] = request->u.ata.command;
423239462Sdim	    bytep[i++] = 0x90 | ATA_COMMAND;
424239462Sdim    } else {
425234353Sdim	    le32enc(bytep + 2 * sizeof(u_int32_t),
426234353Sdim		(request->flags & ATA_R_READ ? 0x01 : 0x00) | (request->tag << 1));
427234353Sdim
428234353Sdim	    i = 16;
429234353Sdim	    bytep[i++] = 0;
430234353Sdim	    bytep[i++] = 0;
431234353Sdim	    bytep[i++] = request->u.ata.command;
432234353Sdim	    bytep[i++] = request->u.ata.feature & 0xff;
433234353Sdim
434234353Sdim	    bytep[i++] = request->u.ata.lba & 0xff;
435239462Sdim	    bytep[i++] = (request->u.ata.lba >> 8) & 0xff;
436249423Sdim	    bytep[i++] = (request->u.ata.lba >> 16) & 0xff;
437249423Sdim	    bytep[i++] = ATA_D_LBA | ATA_D_IBM | ((request->u.ata.lba >> 24) & 0x0f);
438239462Sdim
439239462Sdim	    bytep[i++] = (request->u.ata.lba >> 24) & 0xff;
440249423Sdim	    bytep[i++] = (request->u.ata.lba >> 32) & 0xff;
441239462Sdim	    bytep[i++] = (request->u.ata.lba >> 40) & 0xff;
442239462Sdim	    bytep[i++] = (request->u.ata.feature >> 8) & 0xff;
443249423Sdim
444239462Sdim	    bytep[i++] = request->u.ata.count & 0xff;
445243830Sdim	    bytep[i++] = (request->u.ata.count >> 8) & 0xff;
446239462Sdim	    bytep[i++] = 0;
447239462Sdim	    bytep[i++] = 0;
448234353Sdim    }
449234353Sdim
450234353Sdim    bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map,
451234353Sdim	BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
452234353Sdim
453234353Sdim    /* enable EDMA machinery if needed */
454234353Sdim    if (!(ATA_INL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch)) & 0x00000001)) {
455234353Sdim	ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000001);
456234353Sdim	while (!(ATA_INL(ctlr->r_res1,
457234353Sdim			 0x02028 + ATA_MV_EDMA_BASE(ch)) & 0x00000001))
458234353Sdim	    DELAY(10);
459243830Sdim    }
460249423Sdim
461234353Sdim    /* tell EDMA it has a new request */
462224145Sdim    slot = (((req_in & ~0xfffffc00) >> 5) + 1) & 0x1f;
463234353Sdim    req_in &= 0xfffffc00;
464234353Sdim    req_in += (slot << 5);
465210008Srdivacky    ATA_OUTL(ctlr->r_res1, 0x02014 + ATA_MV_EDMA_BASE(ch), req_in);
466210008Srdivacky
467210008Srdivacky    return ATA_OP_CONTINUES;
468221345Sdim}
469221345Sdim
470221345Sdim/* must be called with ATA channel locked and state_mtx held */
471221345Sdimstatic int
472234353Sdimata_marvell_edma_end_transaction(struct ata_request *request)
473234353Sdim{
474224145Sdim    struct ata_pci_controller *ctlr=device_get_softc(device_get_parent(request->parent));
475224145Sdim    struct ata_channel *ch = device_get_softc(request->parent);
476210008Srdivacky    int offset = (ch->unit > 3 ? 0x30014 : 0x20014);
477243830Sdim    u_int32_t icr = ATA_INL(ctlr->r_res1, offset);
478243830Sdim    int res;
479243830Sdim
480243830Sdim    /* EDMA interrupt */
481243830Sdim    if ((icr & (0x0001 << (ch->unit & 3)))) {
482243830Sdim	struct ata_marvell_response *response;
483243830Sdim	u_int32_t rsp_in, rsp_out;
484210008Srdivacky	int slot;
485243830Sdim
486210008Srdivacky	/* stop timeout */
487234353Sdim	callout_stop(&request->callout);
488243830Sdim
489243830Sdim	/* get response ptr's */
490234353Sdim	rsp_in = ATA_INL(ctlr->r_res1, 0x02020 + ATA_MV_EDMA_BASE(ch));
491234353Sdim	rsp_out = ATA_INL(ctlr->r_res1, 0x02024 + ATA_MV_EDMA_BASE(ch));
492234353Sdim	slot = (((rsp_in & ~0xffffff00) >> 3)) & 0x1f;
493210008Srdivacky	rsp_out &= 0xffffff00;
494249423Sdim	rsp_out += (slot << 3);
495249423Sdim	bus_dmamap_sync(ch->dma.work_tag, ch->dma.work_map,
496243830Sdim	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
497210008Srdivacky	response = (struct ata_marvell_response *)
498210008Srdivacky		   (ch->dma.work + 1024 + (slot << 3));
499210008Srdivacky
500210008Srdivacky	/* record status for this request */
501210008Srdivacky	request->status = response->dev_status;
502210008Srdivacky	request->error = 0;
503210008Srdivacky
504210008Srdivacky	/* ack response */
505210008Srdivacky	ATA_OUTL(ctlr->r_res1, 0x02024 + ATA_MV_EDMA_BASE(ch), rsp_out);
506224145Sdim
507224145Sdim	/* update progress */
508224145Sdim	if (!(request->status & ATA_S_ERROR) &&
509224145Sdim	    !(request->flags & ATA_R_TIMEOUT))
510234353Sdim	    request->donecount = request->bytecount;
511234353Sdim
512224145Sdim	/* unload SG list */
513224145Sdim	ch->dma.unload(request);
514234353Sdim
515210008Srdivacky	res = ATA_OP_FINISHED;
516210008Srdivacky    }
517210008Srdivacky
518210008Srdivacky    /* legacy ATA interrupt */
519210008Srdivacky    else {
520210008Srdivacky	res = ata_end_transaction(request);
521210008Srdivacky    }
522210008Srdivacky
523210008Srdivacky    /* ack interrupt */
524210008Srdivacky    ATA_OUTL(ctlr->r_res1, offset, ~(icr & (0x0101 << (ch->unit & 3))));
525210008Srdivacky    return res;
526210008Srdivacky}
527243830Sdim
528243830Sdimstatic void
529243830Sdimata_marvell_edma_reset(device_t dev)
530243830Sdim{
531249423Sdim    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
532243830Sdim    struct ata_channel *ch = device_get_softc(dev);
533243830Sdim
534210008Srdivacky    /* disable the EDMA machinery */
535210008Srdivacky    ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000002);
536210008Srdivacky    while ((ATA_INL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch)) & 0x00000001))
537210008Srdivacky	DELAY(10);
538210008Srdivacky
539243830Sdim    /* clear SATA error register */
540210008Srdivacky    ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR));
541210008Srdivacky
542210008Srdivacky    /* clear any outstanding error interrupts */
543210008Srdivacky    ATA_OUTL(ctlr->r_res1, 0x02008 + ATA_MV_EDMA_BASE(ch), 0x0);
544243830Sdim
545210008Srdivacky    /* unmask all error interrupts */
546210008Srdivacky    ATA_OUTL(ctlr->r_res1, 0x0200c + ATA_MV_EDMA_BASE(ch), ~0x0);
547210008Srdivacky
548210008Srdivacky    /* enable channel and test for devices */
549243830Sdim    if (ata_sata_phy_reset(dev, -1, 1))
550210008Srdivacky	ata_generic_reset(dev);
551210008Srdivacky
552210008Srdivacky    /* enable EDMA machinery */
553221345Sdim    ATA_OUTL(ctlr->r_res1, 0x02028 + ATA_MV_EDMA_BASE(ch), 0x00000001);
554221345Sdim}
555221345Sdim
556210008Srdivackystatic void
557210008Srdivackyata_marvell_edma_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs,
558210008Srdivacky			   int error)
559210008Srdivacky{
560210008Srdivacky    struct ata_dmasetprd_args *args = xsc;
561210008Srdivacky    struct ata_marvell_dma_prdentry *prd = args->dmatab;
562210008Srdivacky    int i;
563210008Srdivacky
564210008Srdivacky    if ((args->error = error))
565210008Srdivacky	return;
566210008Srdivacky
567210008Srdivacky    for (i = 0; i < nsegs; i++) {
568210008Srdivacky	prd[i].addrlo = htole32(segs[i].ds_addr);
569210008Srdivacky	prd[i].count = htole32(segs[i].ds_len);
570210008Srdivacky	prd[i].addrhi = htole32((u_int64_t)segs[i].ds_addr >> 32);
571210008Srdivacky	prd[i].reserved = 0;
572210008Srdivacky    }
573210008Srdivacky    prd[i - 1].count |= htole32(ATA_DMA_EOT);
574210008Srdivacky    KASSERT(nsegs <= ATA_DMA_ENTRIES, ("too many DMA segment entries\n"));
575210008Srdivacky    args->nsegs = nsegs;
576210008Srdivacky}
577218893Sdim
578210008Srdivackystatic void
579210008Srdivackyata_marvell_edma_dmainit(device_t dev)
580210008Srdivacky{
581226633Sdim    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
582226633Sdim    struct ata_channel *ch = device_get_softc(dev);
583234353Sdim
584224145Sdim    ata_dmainit(dev);
585224145Sdim    /* note start and stop are not used here */
586210008Srdivacky    ch->dma.setprd = ata_marvell_edma_dmasetprd;
587224145Sdim
588210008Srdivacky    /* if 64bit support present adjust max address used */
589210008Srdivacky    if (ATA_INL(ctlr->r_res1, 0x00d00) & 0x00000004)
590210008Srdivacky	ch->dma.max_address = BUS_SPACE_MAXADDR;
591
592    /* chip does not reliably do 64K DMA transfers */
593    if (ctlr->chip->cfg2 == MV_50XX || ctlr->chip->cfg2 == MV_60XX)
594	ch->dma.max_iosize = 64 * DEV_BSIZE;
595    else
596	ch->dma.max_iosize = (ATA_DMA_ENTRIES - 1) * PAGE_SIZE;
597}
598
599ATA_DECLARE_DRIVER(ata_marvell);
600