Author: marius
Date: Sun Apr 22 00:43:32 2012
New Revision: 234560
URL: http://svn.freebsd.org/changeset/base/234560

Log:
  - Add support for MCI1 revision 2xx controllers and a work-around for their
    "Data Write Operation and number of bytes" erratum.
  - Use DEVMETHOD_END.
  - Use NULL instead of 0 for pointers.

Modified:
  head/sys/arm/at91/at91_mci.c
  head/sys/arm/at91/at91_mcireg.h

Modified: head/sys/arm/at91/at91_mci.c
==============================================================================
--- head/sys/arm/at91/at91_mci.c        Sat Apr 21 20:22:02 2012        
(r234559)
+++ head/sys/arm/at91/at91_mci.c        Sun Apr 22 00:43:32 2012        
(r234560)
@@ -113,6 +113,7 @@ static void at91_mci_intr(void *);
 /* helper routines */
 static int at91_mci_activate(device_t dev);
 static void at91_mci_deactivate(device_t dev);
+static int at91_mci_is_mci1rev2xx(void);
 
 #define AT91_MCI_LOCK(_sc)             mtx_lock(&(_sc)->sc_mtx)
 #define        AT91_MCI_UNLOCK(_sc)            mtx_unlock(&(_sc)->sc_mtx)
@@ -141,11 +142,16 @@ static void
 at91_mci_init(device_t dev)
 {
        struct at91_mci_softc *sc = device_get_softc(dev);
+       uint32_t val;
 
        WR4(sc, MCI_CR, MCI_CR_MCIEN);          /* Enable controller */
        WR4(sc, MCI_IDR, 0xffffffff);           /* Turn off interrupts */
        WR4(sc, MCI_DTOR, MCI_DTOR_DTOMUL_1M | 1);
-       WR4(sc, MCI_MR, 0x834a);        // XXX GROSS HACK FROM LINUX
+       val = MCI_MR_PDCMODE;
+       val |= 0x34a;                           /* PWSDIV = 3; CLKDIV = 74 */
+       if (at91_mci_is_mci1rev2xx())
+               val |= MCI_MR_RDPROOF | MCI_MR_WRPROOF;
+       WR4(sc, MCI_MR, val);
 #ifndef  AT91_MCI_SLOT_B
        WR4(sc, MCI_SDCR, 0);                   /* SLOT A, 1 bit bus */
 #else
@@ -303,6 +309,29 @@ at91_mci_deactivate(device_t dev)
        return;
 }
 
+static int
+at91_mci_is_mci1rev2xx(void)
+{
+
+       switch (AT91_CPU(at91_chip_id)) {
+       case AT91_CPU_SAM9260:
+       case AT91_CPU_SAM9263:
+#ifdef notyet
+       case AT91_CPU_CAP9:
+#endif
+       case AT91_CPU_SAM9G10:
+       case AT91_CPU_SAM9G20:
+#ifdef notyet
+       case AT91_CPU_SAM9RL:
+#endif
+       case AT91_CPU_SAM9XE128:
+       case AT91_CPU_SAM9XE256:
+       case AT91_CPU_SAM9XE512:
+               return(1);
+       }
+       return (0);
+}
+
 static void
 at91_mci_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
 {
@@ -346,6 +375,7 @@ at91_mci_update_ios(device_t brdev, devi
 static void
 at91_mci_start_cmd(struct at91_mci_softc *sc, struct mmc_command *cmd)
 {
+       size_t len;
        uint32_t cmdr, ier = 0, mr;
        uint32_t *src, *dst;
        int i;
@@ -397,6 +427,7 @@ at91_mci_start_cmd(struct at91_mci_softc
        WR4(sc, MCI_MR, mr | (data->len << 16) | MCI_MR_PDCMODE);
        WR4(sc, PDC_PTCR, PDC_PTCR_RXTDIS | PDC_PTCR_TXTDIS);
        if (cmdr & MCI_CMDR_TRCMD_START) {
+               len = data->len;
                if (cmdr & MCI_CMDR_TRDIR)
                        vaddr = cmd->data->data;
                else {
@@ -411,6 +442,15 @@ at91_mci_start_cmd(struct at91_mci_softc
                        vaddr = sc->bounce_buffer;
                        src = (uint32_t *)cmd->data->data;
                        dst = (uint32_t *)vaddr;
+                       /*
+                        * If this is MCI1 revision 2xx controller, apply
+                        * a work-around for the "Data Write Operation and
+                        * number of bytes" erratum.
+                        */
+                       if (at91_mci_is_mci1rev2xx() && data->len < 12) {
+                               len = 12;
+                               memset(dst, 0, 12);
+                       }
                        if (sc->sc_cap & CAP_NEEDS_BYTESWAP) {
                                for (i = 0; i < data->len / 4; i++)
                                        dst[i] = bswap32(src[i]);
@@ -418,7 +458,7 @@ at91_mci_start_cmd(struct at91_mci_softc
                                memcpy(dst, src, data->len);
                }
                data->xfer_len = 0;
-               if (bus_dmamap_load(sc->dmatag, sc->map, vaddr, data->len,
+               if (bus_dmamap_load(sc->dmatag, sc->map, vaddr, len,
                    at91_mci_getaddr, &paddr, 0) != 0) {
                        cmd->error = MMC_ERR_NO_MEMORY;
                        sc->req = NULL;
@@ -430,12 +470,12 @@ at91_mci_start_cmd(struct at91_mci_softc
                if (cmdr & MCI_CMDR_TRDIR) {
                        bus_dmamap_sync(sc->dmatag, sc->map, 
BUS_DMASYNC_PREREAD);
                        WR4(sc, PDC_RPR, paddr);
-                       WR4(sc, PDC_RCR, data->len / 4);
+                       WR4(sc, PDC_RCR, len / 4);
                        ier = MCI_SR_ENDRX;
                } else {
                        bus_dmamap_sync(sc->dmatag, sc->map, 
BUS_DMASYNC_PREWRITE);
                        WR4(sc, PDC_TPR, paddr);
-                       WR4(sc, PDC_TCR, data->len / 4);
+                       WR4(sc, PDC_TCR, len / 4);
                        ier = MCI_SR_TXBUFE;
                }
        }
@@ -769,7 +809,7 @@ static device_method_t at91_mci_methods[
        DEVMETHOD(mmcbr_acquire_host, at91_mci_acquire_host),
        DEVMETHOD(mmcbr_release_host, at91_mci_release_host),
 
-       {0, 0},
+       DEVMETHOD_END
 };
 
 static driver_t at91_mci_driver = {
@@ -777,7 +817,8 @@ static driver_t at91_mci_driver = {
        at91_mci_methods,
        sizeof(struct at91_mci_softc),
 };
-static devclass_t at91_mci_devclass;
 
+static devclass_t at91_mci_devclass;
 
-DRIVER_MODULE(at91_mci, atmelarm, at91_mci_driver, at91_mci_devclass, 0, 0);
+DRIVER_MODULE(at91_mci, atmelarm, at91_mci_driver, at91_mci_devclass, NULL,
+    NULL);

Modified: head/sys/arm/at91/at91_mcireg.h
==============================================================================
--- head/sys/arm/at91/at91_mcireg.h     Sat Apr 21 20:22:02 2012        
(r234559)
+++ head/sys/arm/at91/at91_mcireg.h     Sun Apr 22 00:43:32 2012        
(r234560)
@@ -54,6 +54,9 @@
 /* -------- MCI_MR : (MCI Offset: 0x4) MCI Mode Register --------  */
 #define        MCI_MR_CLKDIV      (0xffu <<  0) /* (MCI) Clock Divider */
 #define        MCI_MR_PWSDIV      (0x3fu <<  8) /* (MCI) Power Saving Divider 
*/
+#define        MCI_MR_RDPROOF  (0x1u << 11)    /* (MCI) Read Proof Enable */
+#define        MCI_MR_WRPROOF  (0x1u << 12)    /* (MCI) Write Proof Enable */
+#define        MCI_MR_PDCFBYTE (0x1u << 13)    /* (MCI) PDC Force Byte 
Transfer */
 #define        MCI_MR_PDCPADV     (0x1u << 14) /* (MCI) PDC Padding Value */
 #define        MCI_MR_PDCMODE     (0x1u << 15) /* (MCI) PDC Oriented Mode */
 #define        MCI_MR_BLKLEN      0x3fff0000ul /* (MCI) Data Block Length */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to