Module Name: src
Committed By: jakllsch
Date: Sun Feb 10 21:21:30 UTC 2013
Modified Files:
src/sys/conf: files
src/sys/dev/ic: mvsata.c
Log Message:
This change adds SATA port multiplier support to mvsata(4).
To generate a diff of this commit:
cvs rdiff -u -r1.1062 -r1.1063 src/sys/conf/files
cvs rdiff -u -r1.28 -r1.29 src/sys/dev/ic/mvsata.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/conf/files
diff -u src/sys/conf/files:1.1062 src/sys/conf/files:1.1063
--- src/sys/conf/files:1.1062 Wed Jan 9 22:23:45 2013
+++ src/sys/conf/files Sun Feb 10 21:21:29 2013
@@ -1,4 +1,4 @@
-# $NetBSD: files,v 1.1062 2013/01/09 22:23:45 skrll Exp $
+# $NetBSD: files,v 1.1063 2013/02/10 21:21:29 jakllsch Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
version 20100430
@@ -994,7 +994,7 @@ device siisata: ata, ata_dma, ata_udma,
# Marvell Serial-ATA Host Controller
define mvsata
file dev/ic/mvsata.c mvsata
-device mvsata: ata, ata_dma, ata_udma, wdc_common, sata, mvsata
+device mvsata: ata, ata_dma, ata_udma, wdc_common, sata, sata_pmp, mvsata
defflag opt_mvsata.h MVSATA_WITHOUTDMA
# DECchip 21x4x Ethernet controller family, and assorted clones.
Index: src/sys/dev/ic/mvsata.c
diff -u src/sys/dev/ic/mvsata.c:1.28 src/sys/dev/ic/mvsata.c:1.29
--- src/sys/dev/ic/mvsata.c:1.28 Sun Feb 10 20:13:53 2013
+++ src/sys/dev/ic/mvsata.c Sun Feb 10 21:21:29 2013
@@ -1,4 +1,4 @@
-/* $NetBSD: mvsata.c,v 1.28 2013/02/10 20:13:53 jakllsch Exp $ */
+/* $NetBSD: mvsata.c,v 1.29 2013/02/10 21:21:29 jakllsch Exp $ */
/*
* Copyright (c) 2008 KIYOHARA Takashi
* All rights reserved.
@@ -26,7 +26,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.28 2013/02/10 20:13:53 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.29 2013/02/10 21:21:29 jakllsch Exp $");
#include "opt_mvsata.h"
@@ -51,6 +51,7 @@ __KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1
#include <dev/ata/atareg.h>
#include <dev/ata/atavar.h>
#include <dev/ic/wdcvar.h>
+#include <dev/ata/satapmpreg.h>
#include <dev/ata/satareg.h>
#include <dev/ata/satavar.h>
@@ -178,8 +179,8 @@ static inline void mvsata_dma_bufunload(
static void mvsata_hreset_port(struct mvsata_port *);
static void mvsata_reset_port(struct mvsata_port *);
static void mvsata_reset_hc(struct mvsata_hc *);
+static uint32_t mvsata_softreset(struct mvsata_port *, int);
#ifndef MVSATA_WITHOUTDMA
-static void mvsata_softreset(struct mvsata_port *, int);
static void mvsata_edma_reset_qptr(struct mvsata_port *);
static inline void mvsata_edma_enable(struct mvsata_port *);
static int mvsata_edma_disable(struct mvsata_port *, int, int);
@@ -204,6 +205,7 @@ static void mvsata_print_crpb(struct mvs
static void mvsata_print_eprd(struct mvsata_port *, int);
#endif
+static void mvsata_probe_drive(struct ata_channel *);
struct ata_bustype mvsata_ata_bustype = {
SCSIPI_BUSTYPE_ATA,
@@ -229,6 +231,23 @@ static const struct scsipi_bustype mvsat
#endif /* NATAPIBUS */
#endif
+static void
+mvsata_pmp_select(struct mvsata_port *mvport, int pmpport)
+{
+ uint32_t ifctl;
+
+ KASSERT(pmpport < PMP_MAX_DRIVES);
+#if defined(DIAGNOSTIC) || defined(MVSATA_DEBUG)
+ if ((MVSATA_EDMA_READ_4(mvport, EDMA_CMD) & EDMA_CMD_EENEDMA) != 0) {
+ panic("EDMA enabled");
+ }
+#endif
+
+ ifctl = MVSATA_EDMA_READ_4(mvport, SATA_SATAICTL);
+ ifctl &= ~0xf;
+ ifctl |= pmpport;
+ MVSATA_EDMA_WRITE_4(mvport, SATA_SATAICTL, ifctl);
+}
int
mvsata_attach(struct mvsata_softc *sc, struct mvsata_product *product,
@@ -309,7 +328,7 @@ mvsata_attach(struct mvsata_softc *sc, s
#endif
#endif
sc->sc_wdcdev.wdc_maxdrives = 1; /* SATA is always 1 drive */
- sc->sc_wdcdev.sc_atac.atac_probe = wdc_sataprobe;
+ sc->sc_wdcdev.sc_atac.atac_probe = mvsata_probe_drive;
sc->sc_wdcdev.sc_atac.atac_set_modes = mvsata_setup_channel;
sc->sc_wdc_regs =
@@ -415,9 +434,20 @@ mvsata_error(struct mvsata_port *mvport)
{
struct mvsata_softc *sc = device_private(MVSATA_DEV2(mvport));
uint32_t cause;
- int handled = 0;
cause = MVSATA_EDMA_READ_4(mvport, EDMA_IEC);
+ /*
+ * We must ack SATA_SE and SATA_FISIC before acking coresponding bits
+ * in EDMA_IEC.
+ */
+ if (cause & EDMA_IE_SERRINT) {
+ MVSATA_EDMA_WRITE_4(mvport, SATA_SE,
+ MVSATA_EDMA_READ_4(mvport, SATA_SEIM));
+ }
+ if (cause & EDMA_IE_ETRANSINT) {
+ MVSATA_EDMA_WRITE_4(mvport, SATA_FISIC,
+ ~MVSATA_EDMA_READ_4(mvport, SATA_FISIM));
+ }
MVSATA_EDMA_WRITE_4(mvport, EDMA_IEC, ~cause);
DPRINTFN(3, ("%s:%d:%d:"
@@ -430,25 +460,16 @@ mvsata_error(struct mvsata_port *mvport)
if (!cause)
return 0;
- /* If PM connected, connect/disconnect interrupts storm could happen */
- if (MVSATA_EDMA_READ_4(mvport, EDMA_IEC) &
- (EDMA_IE_EDEVDIS | EDMA_IE_EDEVCON))
- if (sc->sc_gen == gen2 || sc->sc_gen == gen2e) {
- delay(20 * 1000);
- cause = MVSATA_EDMA_READ_4(mvport, EDMA_IEC);
- MVSATA_EDMA_WRITE_4(mvport, EDMA_IEC, ~cause);
- }
-
- if (cause & EDMA_IE_EDEVDIS)
+ if (cause & EDMA_IE_EDEVDIS) {
aprint_normal("%s:%d:%d: device disconnect\n",
device_xname(MVSATA_DEV2(mvport)),
mvport->port_hc->hc, mvport->port);
+ }
if (cause & EDMA_IE_EDEVCON) {
if (sc->sc_gen == gen1)
mvsata_devconn_gen1(mvport);
DPRINTFN(3, (" device connected\n"));
- handled = 1;
}
#ifndef MVSATA_WITHOUTDMA
if ((sc->sc_gen == gen1 && cause & EDMA_IE_ETRANSINT) ||
@@ -472,7 +493,6 @@ mvsata_error(struct mvsata_port *mvport)
mvport->port_hc->hc, mvport->port, cause);
break;
}
- handled = 1;
}
#endif
if (cause & EDMA_IE_ETRANSINT) {
@@ -482,7 +502,7 @@ mvsata_error(struct mvsata_port *mvport)
mvport->port_hc->hc, mvport->port);
}
- return handled;
+ return 1;
}
@@ -490,6 +510,25 @@ mvsata_error(struct mvsata_port *mvport)
* ATA callback entry points
*/
+static void
+mvsata_probe_drive(struct ata_channel *chp)
+{
+ struct mvsata_port * const mvport = (struct mvsata_port *)chp;
+ uint32_t sstat, sig;
+
+ sstat = sata_reset_interface(chp, mvport->port_iot,
+ mvport->port_sata_scontrol, mvport->port_sata_sstatus);
+ switch (sstat) {
+ case SStatus_DET_DEV:
+ mvsata_pmp_select(mvport, PMP_PORT_CTL);
+ sig = mvsata_softreset(mvport, AT_WAIT);
+ sata_interpret_sig(chp, 0, sig);
+ break;
+ default:
+ break;
+ }
+}
+
#ifndef MVSATA_WITHOUTDMA
static int
mvsata_bio(struct ata_drive_datas *drvp, struct ata_bio *ata_bio)
@@ -529,8 +568,7 @@ mvsata_reset_drive(struct ata_drive_data
struct ata_channel *chp = drvp->chnl_softc;
struct mvsata_port *mvport = (struct mvsata_port *)chp;
uint32_t edma_c;
-
- KASSERT(sigp == NULL);
+ uint32_t sig;
edma_c = MVSATA_EDMA_READ_4(mvport, EDMA_CMD);
@@ -541,7 +579,12 @@ mvsata_reset_drive(struct ata_drive_data
if (edma_c & EDMA_CMD_EENEDMA)
mvsata_edma_disable(mvport, 10000, flags & AT_WAIT);
- mvsata_softreset(mvport, flags & AT_WAIT);
+ mvsata_pmp_select(mvport, drvp->drive);
+
+ sig = mvsata_softreset(mvport, flags & AT_WAIT);
+
+ if (sigp)
+ *sigp = sig;
if (edma_c & EDMA_CMD_EENEDMA) {
mvsata_edma_reset_qptr(mvport);
@@ -609,11 +652,11 @@ mvsata_exec_command(struct ata_drive_dat
int rv, s;
DPRINTFN(1, ("%s:%d: mvsata_exec_command: drive=%d, bcount=%d,"
- " r_command=0x%x, r_head=0x%x, r_cyl=0x%x, r_sector=0x%x,"
- " r_count=0x%x, r_features=0x%x\n",
+ " r_lba=0x%012"PRIx64", r_count=0x%04x, r_features=0x%04x,"
+ " r_device=0x%02x, r_command=0x%02x\n",
device_xname(MVSATA_DEV2(mvport)), chp->ch_channel,
- drvp->drive, ata_c->bcount, ata_c->r_command, ata_c->r_head,
- ata_c->r_cyl, ata_c->r_sector, ata_c->r_count, ata_c->r_features));
+ drvp->drive, ata_c->bcount, ata_c->r_lba, ata_c->r_count,
+ ata_c->r_features, ata_c->r_device, ata_c->r_command));
xfer = ata_get_xfer(ata_c->flags & AT_WAIT ? ATAXF_CANSLEEP :
ATAXF_NOSLEEP);
@@ -1138,6 +1181,8 @@ do_pio:
if (mvport->port_edmamode != nodma)
mvsata_edma_disable(mvport, 10 /* ms */, wait_flags);
+ mvsata_pmp_select(mvport, xfer->c_drive);
+
/* Do control operations specially. */
if (__predict_false(drvp->state < READY)) {
/*
@@ -1173,10 +1218,10 @@ do_pio:
return;
}
if (ata_bio->flags & ATA_LBA48)
- wdccommandext(chp, xfer->c_drive, atacmd_to48(cmd),
+ wdccommandext(chp, 0, atacmd_to48(cmd),
ata_bio->blkno, nblks, 0, WDSD_LBA);
else
- wdccommand(chp, xfer->c_drive, cmd, cyl,
+ wdccommand(chp, 0, cmd, cyl,
head, sect, nblks,
(ata_bio->lp->d_type == DTYPE_ST506) ?
ata_bio->lp->d_precompcyl / 4 : 0);
@@ -1423,8 +1468,6 @@ mvsata_bio_ready(struct mvsata_port *mvp
struct ata_drive_datas *drvp = &chp->ch_drive[drive];
const char *errstring;
- flags |= AT_POLL; /* XXX */
-
/*
* disable interrupts, all commands here should be quick
* enough to be able to poll, and we don't go here that often
@@ -1435,8 +1478,8 @@ mvsata_bio_ready(struct mvsata_port *mvp
errstring = "wait";
if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, flags))
goto ctrltimeout;
- wdccommandshort(chp, drive, WDCC_RECAL);
- /* Wait for at last 400ns for status bit to be valid */
+ wdccommandshort(chp, 0, WDCC_RECAL);
+ /* Wait for at least 400ns for status bit to be valid */
DELAY(1);
errstring = "recal";
if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, flags))
@@ -1449,7 +1492,7 @@ mvsata_bio_ready(struct mvsata_port *mvp
/* Also don't try if the drive didn't report its mode */
if ((drvp->drive_flags & ATA_DRIVE_MODE) == 0)
goto geometry;
- wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
+ wdccommand(chp, 0, SET_FEATURES, 0, 0, 0,
0x08 | drvp->PIO_mode, WDSF_SET_MODE);
errstring = "piomode";
if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, flags))
@@ -1457,10 +1500,10 @@ mvsata_bio_ready(struct mvsata_port *mvp
if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
goto ctrlerror;
if (drvp->drive_flags & ATA_DRIVE_UDMA)
- wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
+ wdccommand(chp, 0, SET_FEATURES, 0, 0, 0,
0x40 | drvp->UDMA_mode, WDSF_SET_MODE);
else if (drvp->drive_flags & ATA_DRIVE_DMA)
- wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
+ wdccommand(chp, 0, SET_FEATURES, 0, 0, 0,
0x20 | drvp->DMA_mode, WDSF_SET_MODE);
else
goto geometry;
@@ -1472,7 +1515,7 @@ mvsata_bio_ready(struct mvsata_port *mvp
geometry:
if (ata_bio->flags & ATA_LBA)
goto multimode;
- wdccommand(chp, drive, WDCC_IDP, ata_bio->lp->d_ncylinders,
+ wdccommand(chp, 0, WDCC_IDP, ata_bio->lp->d_ncylinders,
ata_bio->lp->d_ntracks - 1, 0, ata_bio->lp->d_nsectors,
(ata_bio->lp->d_type == DTYPE_ST506) ?
ata_bio->lp->d_precompcyl / 4 : 0);
@@ -1484,7 +1527,7 @@ geometry:
multimode:
if (ata_bio->multi == 1)
goto ready;
- wdccommand(chp, drive, WDCC_SETMULTI, 0, 0, 0, ata_bio->multi, 0);
+ wdccommand(chp, 0, WDCC_SETMULTI, 0, 0, 0, ata_bio->multi, 0);
errstring = "setmulti";
if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, flags))
goto ctrltimeout;
@@ -1536,6 +1579,8 @@ mvsata_wdc_cmd_start(struct ata_channel
if (mvport->port_edmamode != nodma)
mvsata_edma_disable(mvport, 10 /* ms */, wait_flags);
+ mvsata_pmp_select(mvport, drive);
+
MVSATA_WDC_WRITE_1(mvport, SRB_H, WDSD_IBM);
switch(wdcwait(chp, ata_c->r_st_bmask | WDCS_DRQ,
ata_c->r_st_bmask, ata_c->timeout, wait_flags)) {
@@ -1552,11 +1597,11 @@ mvsata_wdc_cmd_start(struct ata_channel
/* polled command, disable interrupts */
MVSATA_WDC_WRITE_1(mvport, SRB_CAS, WDCTL_4BIT | WDCTL_IDS);
if ((ata_c->flags & AT_LBA48) != 0) {
- wdccommandext(chp, drive, ata_c->r_command,
+ wdccommandext(chp, 0, ata_c->r_command,
ata_c->r_lba, ata_c->r_count, ata_c->r_features,
ata_c->r_device & ~0x10);
} else {
- wdccommand(chp, drive, ata_c->r_command,
+ wdccommand(chp, 0, ata_c->r_command,
(ata_c->r_lba >> 8) & 0xffff,
(((ata_c->flags & AT_LBA) != 0) ? WDSD_LBA : 0) |
((ata_c->r_lba >> 24) & 0x0f),
@@ -1819,6 +1864,8 @@ mvsata_atapi_start(struct ata_channel *c
if (mvport->port_edmamode != nodma)
mvsata_edma_disable(mvport, 10 /* ms */, wait_flags);
+ mvsata_pmp_select(mvport, xfer->c_drive);
+
if ((xfer->c_flags & C_DMA) && (drvp->n_xfers <= NXFER))
drvp->n_xfers++;
@@ -1846,7 +1893,7 @@ mvsata_atapi_start(struct ata_channel *c
errstring = "unbusy";
if (wdc_wait_for_unbusy(chp, ATAPI_DELAY, wait_flags))
goto timeout;
- wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
+ wdccommand(chp, 0, SET_FEATURES, 0, 0, 0,
0x08 | drvp->PIO_mode, WDSF_SET_MODE);
errstring = "piomode";
if (wdc_wait_for_unbusy(chp, ATAPI_MODE_DELAY, wait_flags))
@@ -1869,11 +1916,11 @@ mvsata_atapi_start(struct ata_channel *c
goto error;
}
if (drvp->drive_flags & ATA_DRIVE_UDMA)
- wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
+ wdccommand(chp, 0, SET_FEATURES, 0, 0, 0,
0x40 | drvp->UDMA_mode, WDSF_SET_MODE);
else
if (drvp->drive_flags & ATA_DRIVE_DMA)
- wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
+ wdccommand(chp, 0, SET_FEATURES, 0, 0, 0,
0x20 | drvp->DMA_mode, WDSF_SET_MODE);
else
goto ready;
@@ -1934,7 +1981,7 @@ ready:
* data is necessary, multiple data transfer phases will be done.
*/
- wdccommand(chp, xfer->c_drive, ATAPI_PKT_CMD,
+ wdccommand(chp, 0, ATAPI_PKT_CMD,
xfer->c_bcount <= 0xffff ? xfer->c_bcount : 0xffff, 0, 0, 0,
(xfer->c_flags & C_DMA) ? ATAPI_PKT_CMD_FTRE_DMA : 0);
@@ -2235,7 +2282,9 @@ mvsata_atapi_reset(struct ata_channel *c
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive];
struct scsipi_xfer *sc_xfer = xfer->c_cmd;
- wdccommandshort(chp, xfer->c_drive, ATAPI_SOFT_RESET);
+ mvsata_pmp_select(mvport, xfer->c_drive);
+
+ wdccommandshort(chp, 0, ATAPI_SOFT_RESET);
drvp->state = 0;
if (wdc_wait_for_unbusy(chp, WDC_RESET_WAIT, AT_POLL) != 0) {
printf("%s:%d:%d: reset failed\n", device_xname(atac->atac_dev),
@@ -3127,6 +3176,9 @@ mvsata_reset_port(struct mvsata_port *mv
MVSATA_EDMA_WRITE_4(mvport, EDMA_CFG,
EDMA_CFG_RESERVED | EDMA_CFG_RESERVED2);
MVSATA_EDMA_WRITE_4(mvport, EDMA_T, 0);
+ MVSATA_EDMA_WRITE_4(mvport, SATA_SEIM, 0x019c0000);
+ MVSATA_EDMA_WRITE_4(mvport, SATA_SE, ~0);
+ MVSATA_EDMA_WRITE_4(mvport, SATA_FISIC, 0);
MVSATA_EDMA_WRITE_4(mvport, EDMA_IEC, 0);
MVSATA_EDMA_WRITE_4(mvport, EDMA_IEM, 0);
MVSATA_EDMA_WRITE_4(mvport, EDMA_REQQBAH, 0);
@@ -3138,8 +3190,6 @@ mvsata_reset_port(struct mvsata_port *mv
MVSATA_EDMA_WRITE_4(mvport, EDMA_CMD, 0);
MVSATA_EDMA_WRITE_4(mvport, EDMA_TC, 0);
MVSATA_EDMA_WRITE_4(mvport, EDMA_IORT, 0xbc);
-
- MVSATA_EDMA_WRITE_4(mvport, SATA_FISIC, 0);
}
static void
@@ -3167,33 +3217,50 @@ mvsata_reset_hc(struct mvsata_hc *mvhc)
#endif
}
-#ifndef MVSATA_WITHOUTDMA
-static void
+#define WDCDELAY 100 /* 100 microseconds */
+#define WDCNDELAY_RST (WDC_RESET_WAIT * 1000 / WDCDELAY)
+
+static uint32_t
mvsata_softreset(struct mvsata_port *mvport, int waitok)
{
- uint32_t stat;
- int i;
+ uint32_t sig0 = ~0;
+ int timeout, nloop;
+ uint8_t st0;
- MVSATA_WDC_WRITE_1(mvport, SRB_CAS, WDCTL_RST | WDCTL_IDS);
+ MVSATA_WDC_WRITE_1(mvport, SRB_CAS, WDCTL_RST | WDCTL_IDS | WDCTL_4BIT);
+ delay(10);
+ (void) MVSATA_WDC_READ_1(mvport, SRB_FE);
+ MVSATA_WDC_WRITE_1(mvport, SRB_CAS, WDCTL_IDS | WDCTL_4BIT);
delay(10);
- MVSATA_WDC_WRITE_1(mvport, SRB_CAS, WDCTL_IDS);
- delay(2000);
- if (waitok) {
- /* wait maximum 31sec */
- for (i = 31000; i > 0; i--) {
- stat = MVSATA_WDC_READ_1(mvport, SRB_CS);
- if (!(stat & WDCS_BSY))
- break;
- delay(1000);
+ if (!waitok)
+ nloop = WDCNDELAY_RST;
+ else
+ nloop = WDC_RESET_WAIT * hz / 1000;
+
+ /* wait for BSY to deassert */
+ for (timeout = 0; timeout < nloop; timeout++) {
+ st0 = MVSATA_WDC_READ_1(mvport, SRB_CS);
+
+ if ((st0 & WDCS_BSY) == 0) {
+ sig0 = MVSATA_WDC_READ_1(mvport, SRB_SC) << 0;
+ sig0 |= MVSATA_WDC_READ_1(mvport, SRB_LBAL) << 8;
+ sig0 |= MVSATA_WDC_READ_1(mvport, SRB_LBAM) << 16;
+ sig0 |= MVSATA_WDC_READ_1(mvport, SRB_LBAH) << 24;
+ goto out;
}
- if (i == 0)
- aprint_error("%s:%d:%d: soft reset failed\n",
- device_xname(MVSATA_DEV2(mvport)),
- mvport->port_hc->hc, mvport->port);
+ if (!waitok)
+ delay(WDCDELAY);
+ else
+ tsleep(&nloop, PRIBIO, "atarst", 1);
}
+
+out:
+ MVSATA_WDC_WRITE_1(mvport, SRB_CAS, WDCTL_4BIT);
+ return sig0;
}
+#ifndef MVSATA_WITHOUTDMA
static void
mvsata_edma_reset_qptr(struct mvsata_port *mvport)
{
@@ -3234,8 +3301,12 @@ mvsata_edma_disable(struct mvsata_port *
else
delay(1000);
}
- if (ms == timeout)
+ if (ms == timeout) {
+ aprint_error("%s:%d:%d: unable to stop EDMA\n",
+ device_xname(MVSATA_DEV2(mvport)),
+ mvport->port_hc->hc, mvport->port);
return EBUSY;
+ }
/* The diable bit (eDsEDMA) is self negated. */
MVSATA_EDMA_WRITE_4(mvport, EDMA_CMD, EDMA_CMD_EDSEDMA);