<div dir="ltr">From fa9dc2154278b428af16899e1688b3e1b1aabcf7 Mon Sep 17 00:00:00 2001<br>From: David Babich <<a href="mailto:david.babich@se-eng.com">david.babich@se-eng.com</a>><br>Date: Thu, 22 May 2014 16:14:29 -0600<br>
Subject: [PATCH] Add SD card support<br><br>Updated initial commit of SD card boot support.  This has been tested<br>with SDHC cards booting Puppy linux.  SDSC and SDXC cards may<br>not work.  SD cards pre 1.01 of the SD spec are not supported<br>
if they use byte addressing and/or block addressing with<br>a block size not equal to 512 Bytes.  Also, the drivers are<br>written to support boot, but not necessarily for optimal<br>speed.  The driver supports read and not write, and only<br>
implements functions that are required for boot. Some of the<br>source is refactored FreeBSD code.<br><br>Signed-off-by: David Babich <<a href="mailto:david.babich@se-eng.com">david.babich@se-eng.com</a>><br>---<br>
 Makefile              |   3 +-<br> src/Kconfig           |  10 +<br> src/block.c           |  33 ++-<br> src/block.h           |   2 +<br> src/config.h          |   1 +<br> src/hw/bar.h          |  65 +++++<br> src/hw/sd.c           | 613 ++++++++++++++++++++++++++++++++++++++++++++<br>
 src/hw/sd.h           | 275 ++++++++++++++++++++<br> src/hw/sd_if.c        | 413 ++++++++++++++++++++++++++++++<br> src/hw/sd_if.h        |  49 ++++<br> src/hw/sd_utils.c     | 190 ++++++++++++++<br> src/hw/sd_utils.h     | 108 ++++++++<br>
 src/hw/sdhc_generic.c | 697 ++++++++++++++++++++++++++++++++++++++++++++++++++<br> src/hw/sdhc_generic.h |  41 +++<br> src/hw/sdhci.h        | 207 +++++++++++++++<br> src/post.c            |   3 +<br> src/stdbool.h         |  29 +++<br>
 src/stdint.h          |  41 +++<br> 18 files changed, 2778 insertions(+), 2 deletions(-)<br> create mode 100644 src/hw/bar.h<br> create mode 100644 src/hw/sd.c<br> create mode 100644 src/hw/sd.h<br> create mode 100644 src/hw/sd_if.c<br>
 create mode 100644 src/hw/sd_if.h<br> create mode 100644 src/hw/sd_utils.c<br> create mode 100644 src/hw/sd_utils.h<br> create mode 100644 src/hw/sdhc_generic.c<br> create mode 100644 src/hw/sdhc_generic.h<br> create mode 100644 src/hw/sdhci.h<br>
 create mode 100644 src/stdbool.h<br> create mode 100644 src/stdint.h<br><br>diff --git a/Makefile b/Makefile<br>index 78b598e..02266ce 100644<br>--- a/Makefile<br>+++ b/Makefile<br>@@ -35,7 +35,8 @@ SRCBOTH=misc.c stacks.c output.c string.c x86.c block.c cdrom.c mouse.c kbd.c \<br>
     hw/usb-hid.c hw/usb-msc.c hw/usb-uas.c \<br>     hw/blockcmd.c hw/floppy.c hw/ata.c hw/ramdisk.c \<br>     hw/virtio-ring.c hw/virtio-pci.c hw/virtio-blk.c hw/virtio-scsi.c \<br>-    hw/lsi-scsi.c hw/esp-scsi.c hw/megasas.c<br>
+    hw/lsi-scsi.c hw/esp-scsi.c hw/megasas.c \<br>+    hw/sdhc_generic.c hw/sd.c hw/sd_if.c hw/sd_utils.c<br> SRC16=$(SRCBOTH) system.c disk.c font.c<br> SRC32FLAT=$(SRCBOTH) post.c memmap.c malloc.c pmm.c romfile.c optionroms.c \<br>
     boot.c bootsplash.c jpeg.c bmp.c \<br>diff --git a/src/Kconfig b/src/Kconfig<br>index a863866..432eca5 100644<br>--- a/src/Kconfig<br>+++ b/src/Kconfig<br>@@ -1,4 +1,5 @@<br> # Kconfig SeaBIOS configuration<br>+# Copyright (C) 2013-2014 Sage Electronic Engineering, LLC<br>
 <br> mainmenu "SeaBIOS Configuration"<br> <br>@@ -207,6 +208,15 @@ menu "Hardware support"<br>         default y<br>         help<br>             Support floppy drive access.<br>+    config SD<br>+        depends on DRIVES<br>
+        bool "SD controller"<br>+        default n<br>+        help<br>+            Support SD card boot. This is a development feature.<br>+            Select this option ONLY if you know that your hardware<br>
+            will support booting from SD card.<br>+            If unsure, say n.<br> <br>     config PS2PORT<br>         depends on KEYBOARD || MOUSE<br>diff --git a/src/block.c b/src/block.c<br>index 264f376..615edd1 100644<br>
--- a/src/block.c<br>+++ b/src/block.c<br>@@ -2,6 +2,7 @@<br> //<br> // Copyright (C) 2008,2009  Kevin O'Connor <<a href="mailto:kevin@koconnor.net">kevin@koconnor.net</a>><br> // Copyright (C) 2002  MandrakeSoft S.A.<br>
+// Copyright (C) 2013 Sage Electronic Engineering, LLC<br> //<br> // This file may be distributed under the terms of the GNU LGPLv3 license.<br> <br>@@ -13,6 +14,7 @@<br> #include "hw/blockcmd.h" // cdb_*<br> #include "hw/rtc.h" // rtc_read<br>
 #include "hw/virtio-blk.h" // process_virtio_blk_op<br>+#include "hw/sd_if.h" // process_sd_op<br> #include "malloc.h" // malloc_low<br> #include "output.h" // dprintf<br> #include "stacks.h" // stack_hop<br>
@@ -20,9 +22,12 @@<br> #include "string.h" // checksum<br> #include "util.h" // process_floppy_op<br> <br>+#define MAX_DRIVE_TYPES 4<br>+<br> u8 FloppyCount VARFSEG;<br> u8 CDCount;<br>-struct drive_s *IDMap[3][BUILD_MAX_EXTDRIVE] VARFSEG;<br>
+<br>+struct drive_s *IDMap[MAX_DRIVE_TYPES][BUILD_MAX_EXTDRIVE] VARFSEG;<br> u8 *bounce_buf_fl VARFSEG;<br> struct dpte_s DefaultDPTE VARLOW;<br> <br>@@ -278,6 +283,27 @@ map_floppy_drive(struct drive_s *drive)<br>     }<br>
 }<br> <br>+// Map a SD card<br>+void<br>+map_sd_drive(struct drive_s *drive_g)<br>+{<br>+    ASSERT32FLAT();<br>+    struct bios_data_area_s *bda = MAKE_FLATPTR(SEG_BDA, 0);<br>+    int sdid = bda->hdcount;<br>+    printf("Mapping sd/mmc drive 0x%08x\n", (unsigned int)drive_g);<br>
+    add_drive(IDMap[EXTTYPE_HD], &bda->hdcount, drive_g);<br>+<br>+    // Setup disk geometry translation.<br>+    setup_translation(drive_g);<br>+<br>+    //@NOTE:  This step appears to be unnecessary for booting from the sd card as the pchs info does not get used...<br>
+    drive_g->pchs.head = drive_g->lchs.head;<br>+    drive_g->pchs.cylinder = drive_g->lchs.cylinder;<br>+    drive_g->pchs.sector = drive_g->lchs.sector;<br>+<br>+    // Fill "fdpt" structure.<br>
+    fill_fdpt(drive_g, sdid);<br>+}<br> <br> /****************************************************************<br>  * Return status functions<br>@@ -395,6 +421,11 @@ process_op(struct disk_op_s *op)<br>         ret = call32(_cfunc32flat_process_scsi_op<br>
                      , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM);<br>         break;<br>+    case DTYPE_SD: ;<br>+        extern void _cfunc32flat_process_sd_op(void);<br>+        ret = call32(_cfunc32flat_process_sd_op<br>
+                      , (u32)MAKE_FLATPTR(GET_SEG(SS), op), DISK_RET_EPARAM);<br>+    break;<br>     default:<br>         ret = DISK_RET_EPARAM;<br>         break;<br>diff --git a/src/block.h b/src/block.h<br>index 5d0afb5..ee20218 100644<br>
--- a/src/block.h<br>+++ b/src/block.h<br>@@ -86,6 +86,7 @@ struct drive_s {<br> #define DTYPE_ESP_SCSI     0x81<br> #define DTYPE_MEGASAS      0x82<br> #define DTYPE_PVSCSI       0x83<br>+#define DTYPE_SD           0x90<br>
 <br> #define MAXDESCSIZE 80<br> <br>@@ -115,6 +116,7 @@ int getDriveId(u8 exttype, struct drive_s *drive);<br> void map_floppy_drive(struct drive_s *drive);<br> void map_hd_drive(struct drive_s *drive);<br> void map_cd_drive(struct drive_s *drive);<br>
+void map_sd_drive(struct drive_s *drive);<br> struct bregs;<br> void __disk_ret(struct bregs *regs, u32 linecode, const char *fname);<br> void __disk_ret_unimplemented(struct bregs *regs, u32 linecode<br>diff --git a/src/config.h b/src/config.h<br>
index d705615..73fbffe 100644<br>--- a/src/config.h<br>+++ b/src/config.h<br>@@ -99,6 +99,7 @@<br> #define DEBUG_HDL_pmm 1<br> #define DEBUG_HDL_pcibios 9<br> #define DEBUG_HDL_apm 9<br>+#define DEBUG_HDL_SD 6<br> <br> #define DEBUG_unimplemented 2<br>
 #define DEBUG_invalid 3<br>diff --git a/src/hw/bar.h b/src/hw/bar.h<br>new file mode 100644<br>index 0000000..171525b<br>--- /dev/null<br>+++ b/src/hw/bar.h<br>@@ -0,0 +1,65 @@<br>+ /*****************************************************************************<br>
+ *<br>+ * Copyright (c) 2012-2014 Sage Electronic Engineering.  All rights reserved.<br>+ *<br>+ * Software License Agreement<br>+ * Redistribution and use in source and binary forms, with or without<br>+ * modification, are permitted provided that the following conditions<br>
+ * are met:<br>+ * 1. Redistributions of source code must retain the above copyright<br>+ *    notice, this list of conditions and the following disclaimer.<br>+ * 2. Redistributions in binary form must reproduce the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer in the<br>+ *    documentation and/or other materials provided with the distribution.<br>+ *<br>+ * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED<br>
+ * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF<br>+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.<br>+ * Sage Electronic Engineering SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR<br>
+ * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.<br>+ *****************************************************************************/<br>+<br>+#ifndef __BAR_H<br>+#define __BAR_H<br>+<br>+#include <stdint.h><br>
+<br>+// write functions<br>+static inline void barWrite8( uint32_t bar, uint32_t offset, uint8_t value )<br>+{<br>+    volatile uint8_t* pReg = (volatile uint8_t*)(bar | ( offset & 0xFF ) );<br>+    *pReg = value;<br>
+}<br>+<br>+static inline void barWrite16( uint32_t bar, uint32_t offset, uint16_t value )<br>+{<br>+    volatile uint16_t* pReg = (volatile uint16_t*)(bar | ( offset & 0xFF ) );<br>+    *pReg = value;<br>+}<br>+<br>+static inline void barWrite32( uint32_t bar, uint32_t offset, uint32_t value )<br>
+{<br>+    volatile uint32_t* pReg = (volatile uint32_t*)(bar | ( offset & 0xFF ) );<br>+    *pReg = value;<br>+}<br>+<br>+// read functions<br>+static inline uint8_t barRead8( uint32_t bar, uint32_t offset )<br>+{<br>
+    volatile uint8_t* pReg = (volatile uint8_t*)(bar | ( offset & 0xFF ) );<br>+    return( *pReg );<br>+}<br>+<br>+static inline uint16_t barRead16( uint32_t bar, uint32_t offset )<br>+{<br>+    volatile uint16_t* pReg = (volatile uint16_t*)(bar | ( offset & 0xFF ) );<br>
+    return( *pReg );<br>+}<br>+<br>+static inline uint32_t barRead32( uint32_t bar, uint32_t offset )<br>+{<br>+    volatile uint32_t* pReg = (volatile uint32_t*)(bar | ( offset & 0xFF ) );<br>+    return( *pReg );<br>
+}<br>+<br>+#endif /* __BAR_H */<br>diff --git a/src/hw/sd.c b/src/hw/sd.c<br>new file mode 100644<br>index 0000000..ac4c3b3<br>--- /dev/null<br>+++ b/src/hw/sd.c<br>@@ -0,0 +1,613 @@<br>+ /*****************************************************************************<br>
+ *<br>+ * Copyright (c) 2012-2014 Sage Electronic Engineering.  All rights reserved.<br>+ *<br>+ * Software License Agreement<br>+ * Redistribution and use in source and binary forms, with or without<br>+ * modification, are permitted provided that the following conditions<br>
+ * are met:<br>+ * 1. Redistributions of source code must retain the above copyright<br>+ *    notice, this list of conditions and the following disclaimer.<br>+ * 2. Redistributions in binary form must reproduce the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer in the<br>+ *    documentation and/or other materials provided with the distribution.<br>+ *<br>+ * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED<br>
+ * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF<br>+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.<br>+ * Sage Electronic Engineering SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR<br>
+ * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.<br>+ *****************************************************************************/<br>+<br>+#include <stdint.h><br>+#include <stdbool.h><br>
+#include "string.h"<br>+#include "util.h"<br>+#include "malloc.h"<br>+#include "output.h"<br>+#include "config.h"<br>+#include "sd.h"<br>+<br>+// Host controller access functions cmd/data and acmd<br>
+static bool sdHostXfer( sdHc_t* pHost, sdXfer_t* pXfer );<br>+static bool sdAppSpecificHostXfer( sdHc_t* pHost, sdXfer_t* pXfer );<br>+<br>+// Card control functions<br>+static bool sdSelectDeselectCard( sdCard_t* pCard );<br>
+<br>+// Card intialization functions<br>+static bool sdIdle( sdCard_t* pCard );<br>+static bool sdSendIfCond( sdCard_t* pCard );<br>+static bool sdSendOpCond( sdCard_t* pCard );<br>+static bool sdSendCSD( sdCard_t* pCard );<br>
+static bool sdAllSendCID( sdCard_t* pCard );<br>+static bool sdSendRelativeAddr( sdCard_t* pCard );<br>+static bool sdCardIdentificationMode( sdCard_t* pCard );<br>+<br>+<br>+/**<br>+ * @brief     sdHostXfer - execute the host controller callback to perform<br>
+ *                 a transfer from the host to the card and read responses and<br>+ *                 data from the card<br>+ *<br>+ * @param     sdHc_t* pHost - pointer to the host controller abstraction structure<br>+ * @param     sdXfer_t* pXfer - pointer to the host style transfer structure<br>
+ *<br>+ * @return    bool - true if successful, false otherwise<br>+ */<br>+static bool sdHostXfer( sdHc_t* pHost, sdXfer_t* pXfer )<br>+{<br>+    bool status = false;<br>+<br>+    dprintf( DEBUG_HDL_SD,<br>+            "SD card: Sending CMD%u with arg1 0x%08x\n", pXfer->cmdIdx, pXfer->arg1 );<br>
+<br>+    status = pHost->sdhcCmd( pHost, pXfer );<br>+    if( status )<br>+    {<br>+        switch( pXfer->rspType )<br>+        {<br>+            case eRsp136:<br>+                dprintf( DEBUG_HDL_SD,<br>+                        "SD card: Response 136: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",<br>
+                        pXfer->response[0],<br>+                        pXfer->response[1],<br>+                        pXfer->response[2],<br>+                        pXfer->response[3] );<br>+                break;<br>
+<br>+            case eRsp48:<br>+                dprintf( DEBUG_HDL_SD, "SD card: Response 48: 0x%08x\n",<br>+                        pXfer->response[0] );<br>+                break;<br>+<br>+            case eRsp48_busy:<br>
+                dprintf( DEBUG_HDL_SD, "SD card: Response 48 with busy signal: 0x%08x\n",<br>+                        pXfer->response[0] );<br>+                break;<br>+<br>+            case eRspNone:<br>+            default:<br>
+                break;<br>+<br>+        }<br>+    }<br>+    else<br>+    {<br>+        dprintf( DEBUG_HDL_SD, "SD card:  Failed to respond to CMD%u\n", pXfer->cmdIdx );<br>+    }<br>+<br>+    return status;<br>
+}<br>+<br>+/**<br>+ * @brief    sdAppSpecificHostXfer - this function performs the necessary steps to<br>+ *                 allow the sd card to accept application specific commands (namely, it<br>+ *                 sends CMD55 prior to sending the ACMD<XX>.  CMD55 puts the card into<br>
+ *                 application specific mode.<br>+ *<br>+ * @param     sdHc_t* pHost - pointer to the host controller abstraction structure<br>+ * @param     sdXfer_t* pXfer - pointer to the host style transfer structure<br>
+ *<br>+ * @return    bool - true if successful, false otherwise<br>+ */<br>+static bool sdAppSpecificHostXfer( sdHc_t* pHost, sdXfer_t* pXfer )<br>+{<br>+    bool status = false;<br>+    sdXfer_t xfer;<br>+<br>+    memset( &xfer, 0, sizeof( sdXfer_t ) );<br>
+    xfer.cmdIdx = MMC_APP_CMD55;<br>+    xfer.arg1 = 0;<br>+    xfer.cmdType = eCmdNormal;<br>+    xfer.rspType = eRsp48;<br>+    xfer.xferType = eWrXfer;<br>+    xfer.pData = NULL;<br>+<br>+    // send CMD55 to place card in APP specific mode<br>
+    status = sdHostXfer( pHost, &xfer );<br>+    if( status )<br>+    {<br>+        // send APP specific cmd<br>+        status = sdHostXfer( pHost, pXfer );<br>+    }<br>+<br>+    return status;<br>+}<br>+<br>+/**<br>
+ * @brief    sdSelectDeselectCard - this function impelements CMD7 SELECT/DESELECT_CARD<br>+ *                 to toggle a card between standby and transfer state<br>+ *<br>+ * @param    sdCard_t* pCard - pointer to the sd card abstraction structure<br>
+ *<br>+ * @return   bool - true if successful, false otherwise<br>+ */<br>+static bool sdSelectDeselectCard( sdCard_t* pCard )<br>+{<br>+    bool status = false;<br>+    sdXfer_t xfer;<br>+<br>+    // set up a transaction structure<br>
+    memset( &xfer, 0, sizeof( sdXfer_t ) );<br>+    xfer.cmdIdx = MMC_SELECT_CARD_CMD7;<br>+    xfer.arg1 = (uint32_t)(pCard->rca) << 16;<br>+    xfer.cmdType = eCmdNormal;<br>+    xfer.rspType = eRsp48_busy;<br>
+    xfer.xferType = eWrXfer;<br>+    xfer.pData = NULL;<br>+<br>+    // invoke the host controller callback<br>+    status = sdHostXfer( pCard->pHost, &xfer );<br>+<br>+    if(status)<br>+    {<br>+        pCard->isSelected = pCard->isSelected == true ? false : true;<br>
+    }<br>+<br>+    return status;<br>+}<br>+<br>+/**<br>+ * @brief    sdReadSingleBlock - read a single block from the card<br>+ *<br>+ * @param    sdCard_t* pCard - pointer to the sd card abstraction structure<br>+ * @param    uint8_t* pData - pointer to the data buffer to read into<br>
+ * @param    uint32_t addr - logical block address to read<br>+ *<br>+ * @return   bool - true on success false otherwise<br>+ */<br>+bool sdReadSingleBlock( sdCard_t* pCard, uint8_t* pData, uint32_t addr )<br>+{<br>+    bool status = false;<br>
+    sdXfer_t xfer;<br>+<br>+    if( !pCard->isSelected )<br>+    {<br>+        // select the card (CMD7)<br>+        sdSelectDeselectCard( pCard );<br>+    }<br>+<br>+    // set up a transaction structure<br>+    memset( &xfer, 0, sizeof( sdXfer_t ) );<br>
+    xfer.cmdIdx = MMC_READ_SINGLE_BLOCK_CMD17;<br>+    xfer.arg1 = addr;<br>+    xfer.cmdType = eCmdNormal;<br>+    xfer.rspType = eRsp48;<br>+    xfer.xferType = eRdXfer;<br>+    xfer.pData = pData;<br>+    dprintf( DEBUG_HDL_SD, "---- pData address: 0x%08x ----\n", (uint32_t)pData);<br>
+<br>+    // invoke the host controller callback<br>+    status = sdHostXfer( pCard->pHost, &xfer );<br>+<br>+    return status;<br>+}<br>+<br>+bool sdReadMultipleBlock( sdCard_t* pCard )<br>+{<br>+    bool status = false;<br>
+    // stub<br>+    return status;<br>+}<br>+<br>+bool sdStopTransmission( sdCard_t* pCard )<br>+{<br>+    bool status = false;<br>+    // stub<br>+    return status;<br>+}<br>+<br>+/**<br>+ * @brief    sdIdle - this function implements the CMD0 GO_IDLE_MODE,<br>
+ *                 which resets the sd card and prepares it for intalization<br>+ *<br>+ * @param    sdCard_t* pCard - pointer to the sd card abstraction structure<br>+ *<br>+ * @return   bool - true if successful, false otherwise<br>
+ */<br>+static bool sdIdle( sdCard_t* pCard )<br>+{<br>+    bool status = false;<br>+    sdXfer_t xfer;<br>+<br>+    // set up a transaction structure<br>+    memset( &xfer, 0, sizeof( sdXfer_t ) );<br>+    xfer.cmdIdx = MMC_GO_IDLE_STATE_CMD0;<br>
+    xfer.arg1 = 0;<br>+    xfer.cmdType = eCmdNormal;<br>+    xfer.rspType = eRspNone;<br>+    xfer.xferType = eWrXfer;<br>+    xfer.pData = NULL;<br>+<br>+    // invoke the host controller callback<br>+    status = sdHostXfer( pCard->pHost, &xfer );<br>
+<br>+    return status;<br>+}<br>+<br>+/**<br>+ * @brief    sdSendIfCond - this function executes CMD8 SEND_IF_COND, to determine<br>+ *                 whether or not the host controller is compatible with the sd card.<br>
+ *<br>+ * @param    sdCard_t* pCard - pointer to the sd card abstraction structure<br>+ *<br>+ * @return   bool - true if successful, false otherwise<br>+ */<br>+static bool sdSendIfCond( sdCard_t* pCard )<br>+{<br>+    bool status = false;<br>
+    sdXfer_t xfer;<br>+    uint32_t cycleTries = 1;<br>+<br>+    /* Send CMD8 to determine whether or not the host controller's voltage setting<br>+     * is correct for the card<br>+     * NOTE: it should always be correct for SD cards, as there is really only one<br>
+     * voltage range currently supported as of 2013.  This may change in the future<br>+     * though.  If this fails, the card is not an SD, SDCH or SDXC card and the card<br>+     * is unusable, or the host controller is not setup correctly for the card.<br>
+     */<br>+    // set up a transaction structure<br>+    memset( &xfer, 0, sizeof( sdXfer_t ) );<br>+    xfer.cmdIdx = SD_SEND_IF_COND_CMD8;<br>+<br>+    // voltage range 2.7 to 3.6 v and test pattern = 0xAA<br>+    xfer.arg1 = SD_VOLTAGE_RANGE_270_360 | SD_IF_COND_ECHO;<br>
+    xfer.cmdType = eCmdNormal;<br>+    xfer.rspType = eRsp48;<br>+    xfer.xferType = eWrXfer;<br>+    xfer.pData = NULL;<br>+<br>+    // check the echo response<br>+    while( cycleTries-- )<br>+    {<br>+        if( sdHostXfer( pCard->pHost, &xfer ) )<br>
+        {<br>+            if( xfer.response[0] == xfer.arg1 )<br>+            {<br>+                status = true;<br>+                break;<br>+            }<br>+            usleep(100);<br>+        }<br>+    }<br>+    if( !status )<br>
+    {<br>+        dprintf( 6, "SD: card not present or not supported in the present operating conditions\n" );<br>+    }<br>+    return status;<br>+}<br>+<br>+/**<br>+ * @brief    sdSendOpCond - this function executes the ACMD41 SEND_OP_COND, this function<br>
+ *                 transitions the card from the idle state to the ready state.  This transition<br>+ *                 requires a minimum of one second to complete, and is required for sdxc and sdhc<br>+ *                 card enumeration.<br>
+ *<br>+ * @param    sdCard_t* pCard - pointer to the sd card abstraction structure<br>+ *<br>+ * @return   bool - true if successful, false otherwise<br>+ */<br>+static bool sdSendOpCond( sdCard_t* pCard )<br>+{<br>+    bool status = false;<br>
+    sdXfer_t xfer;<br>+    uint32_t cycleTries = SD_STATE_CHANGE_ATTEMPTS;<br>+<br>+    // Send Application specific command ACMD41 in inquiry mode<br>+    // (no voltage bits set) to read the OCR<br>+    memset( &xfer, 0, sizeof( sdXfer_t ) );<br>
+    xfer.cmdIdx = SD_APP_SEND_OP_COND_CMD41;<br>+    xfer.cmdType = eCmdNormal;<br>+    xfer.rspType = eRsp48;<br>+    xfer.xferType = eWrXfer;<br>+    xfer.pData = NULL;<br>+<br>+    // setup the voltages based on what is supported by the host<br>
+    xfer.arg1 |= pCard->pHost->cardCapabilities.cap1 & SDHCI_CAN_VDD_180 ? VDD_S18A : 0;<br>+    xfer.arg1 |= pCard->pHost->cardCapabilities.cap1 & SDHCI_CAN_VDD_300 ? VDD_RANGE_27_30 : 0;<br>+    xfer.arg1 |= pCard->pHost->cardCapabilities.cap1 & SDHCI_CAN_VDD_330 ? VDD_RANGE_30_33 : 0;<br>
+<br>+    // normal sd cards ignore the HCS bit, so set it for hcxc types<br>+    xfer.arg1 |= HCS;<br>+<br>+    while( cycleTries-- )<br>+    {<br>+        status = sdAppSpecificHostXfer( pCard->pHost, &xfer );<br>
+        if( status )<br>+        {<br>+            // initialization takes 1 second to complete, and we query the busy bit<br>+            // in the response to know when to stop<br>+            if( xfer.response[0] & OCR_DONE_BSY_N )<br>
+            {<br>+                pCard->ocr = xfer.response[0];<br>+                pCard->xchcCard = (HCS == (pCard->ocr & HCS));<br>+                break;<br>+            }<br>+            else<br>+            {<br>
+                udelay(100);<br>+            }<br>+        }<br>+    }<br>+    return status;<br>+}<br>+<br>+/**<br>+ * @brief    sdSendCSD - request the values from CSD register<br>+ *<br>+ * @param    sdCard_t* pCard - pointer to the sd card abstraction structure<br>
+ *<br>+ * @return   bool - true if successful, false otherwise<br>+ */<br>+static bool sdSendCSD( sdCard_t* pCard )<br>+{<br>+    bool status = false;<br>+    sdXfer_t xfer;<br>+    uint32_t cycleTries = SD_TRY_AGAIN;<br>
+<br>+    memset( &xfer, 0, sizeof( sdXfer_t ) );<br>+    xfer.cmdIdx = MMC_SEND_CSD_CMD9;<br>+    xfer.arg1 =  (uint32_t)(pCard->rca) << 16;<br>+    xfer.cmdType = eCmdNormal;<br>+    xfer.rspType = eRsp136;<br>
+    xfer.xferType = eWrXfer;<br>+    xfer.pData = NULL;<br>+    while( cycleTries-- )<br>+    {<br>+        status = sdHostXfer( pCard->pHost, &xfer );<br>+        if( status )<br>+        {<br>+            // The Host Response places bits [127:8] in bits [119:0] of the response (hence the shift)<br>
+            memmove( xfer.response, (void*)(((uint8_t*)(xfer.response)) - 1), sizeof(xfer.response ) );<br>+            pCard->csd[0] = xfer.response[3];<br>+            pCard->csd[1] = xfer.response[2];<br>+            pCard->csd[2] = xfer.response[1];<br>
+            pCard->csd[3] = xfer.response[0];<br>+            decode_csd_sd( pCard->csd, &pCard->decode.csdDecode );<br>+            break;<br>+        }<br>+<br>+    }<br>+    return status;<br>+}<br>+<br>+/**<br>
+ * @brief    sdAllSendCID - this function executes CMD2 ALL_SEND_CID, this transitions<br>+ *                 the card from the ready state to the identification state, and allows the<br>+ *                 card to transmit the contents of the CID register<br>
+ *<br>+ * @param    sdCard_t* pCard - pointer to the sd card abstraction structure<br>+ *<br>+ * @return   bool - true if successful, false otherwise<br>+ */<br>+static bool sdAllSendCID( sdCard_t* pCard )<br>+{<br>+    bool status = false;<br>
+    sdXfer_t xfer;<br>+    uint32_t cycleTries = SD_TRY_AGAIN;<br>+<br>+    memset( &xfer, 0, sizeof( sdXfer_t ) );<br>+    xfer.cmdIdx = MMC_ALL_SEND_CID_CMD2;<br>+    xfer.cmdType = eCmdNormal;<br>+    xfer.rspType = eRsp136;<br>
+    xfer.xferType = eWrXfer;<br>+    xfer.pData = NULL;<br>+    while( cycleTries-- )<br>+    {<br>+        status = sdHostXfer( pCard->pHost, &xfer );<br>+        if( status )<br>+        {<br>+            // The Host Response places bits [127:8] in bits [119:0] of the response (hence the shift)<br>
+            memmove( xfer.response, (void*)(((uint8_t*)(xfer.response)) - 1), sizeof(xfer.response ) );<br>+<br>+            // the utility functions swap the result prior to use<br>+            pCard->cid[0] = xfer.response[3];<br>
+            pCard->cid[1] = xfer.response[2];<br>+            pCard->cid[2] = xfer.response[1];<br>+            pCard->cid[3] = xfer.response[0];<br>+            decode_cid_sd( pCard->cid, &pCard->decode.cidDecode );<br>
+            break;<br>+        }<br>+<br>+    }<br>+    return status;<br>+<br>+}<br>+<br>+/**<br>+ * @brief    sdSendRelativeAddr - this function executes CMD3 - SEND_RELATIVE_ADDRESS, of the<br>+ *                 card initialization sequence.  After successful completion, the relative card<br>
+ *                 address (RCA) of the card is known, and the SD card enters standby mode from<br>+ *                 card identification mode<br>+ *<br>+ * @param    sdCard_t* pCard - pointer to the sd card abstraction structure<br>
+ *<br>+ * @return   bool - true if successful, false otherwise<br>+ */<br>+static bool sdSendRelativeAddr( sdCard_t* pCard )<br>+{<br>+    bool status = false;<br>+    sdXfer_t xfer;<br>+    uint32_t cycleTries = SD_TRY_AGAIN;<br>
+    sdCardState_e currentState = eInvalid;<br>+<br>+    memset( &xfer, 0, sizeof( sdXfer_t ) );<br>+    xfer.cmdIdx = MMC_SET_RELATIVE_ADDR_CMD3;<br>+    xfer.cmdType = eCmdNormal;<br>+    xfer.rspType = eRsp48;<br>+    xfer.xferType = eWrXfer;<br>
+    xfer.pData = NULL;<br>+    while( cycleTries-- )<br>+    {<br>+        status = sdHostXfer( pCard->pHost, &xfer );<br>+        if( status )<br>+        {<br>+            // the response is the R6 response containing the relative card<br>
+            // address, and current status info<br>+            pCard->rca = (uint16_t)(xfer.response[0] >> 16);<br>+            if( xfer.response[0] & RCAERROR_MSK )<br>+            {<br>+                dprintf( DEBUG_HDL_SD,<br>
+                        "SD card: RCA request responded with error status: 0x%08x\n",<br>+                        xfer.response[0] & RCAERROR_MSK );<br>+                status = false;<br>+                // here there should probably be a full status check<br>
+            }<br>+<br>+            // now the card should be in stby mode (this might not be reflected until<br>+            // the next command (the offset is bit 9 : 12 for state info)<br>+            currentState = (sdCardState_e)((xfer.response[0] & RCASTATUS_CURRENT_STATE) >> 9);<br>
+            if( currentState == eStby )<br>+            {<br>+                dprintf( DEBUG_HDL_SD, "SD card: Current state is stby: 0x%02x - \n", currentState );<br>+                break;<br>+            }<br>
+        }<br>+    }<br>+    return status;<br>+<br>+}<br>+<br>+/**<br>+ * @brief    sdCardIdentificationMode - this function executes the call sequence/state<br>+ *                 machine outlined in section 4.2 of "Physical Layer Simplified Specification<br>
+ *                 Version 4.10"<br>+ *<br>+ * @param    sdCard_t* pCard - pointer to the sd card abstraction structure<br>+ *<br>+ * @return   bool - true if successful, false otherwise<br>+ */<br>+static bool sdCardIdentificationMode( sdCard_t* pCard )<br>
+{<br>+    bool status = false;<br>+    uint32_t cycleTries = NUM_INIT_ATTEMPTS;<br>+<br>+    ASSERT32FLAT();<br>+     while( cycleTries-- )<br>+     {<br>+        // CMD8 - SEND_IF_COND<br>+        if( !(status = sdSendIfCond( pCard )) )<br>
+            continue;<br>+<br>+        // ACMD41 - SEND_OP_COND to properly initialize SDHC and SDXC cards...<br>+        if( !(status = sdSendOpCond( pCard )) )<br>+            continue;<br>+<br>+        // If the voltage needs to change based on the response for ACMD41, change it using CMD11<br>
+        // @TODO: implement CMD11 voltage switch if necessary... probably don't need to support this<br>+        // for a while<br>+<br>+        // Else Send CMD2 to get the CID, the card should be in identification state<br>
+        if( !(status = sdAllSendCID( pCard )) )<br>+            continue;<br>+<br>+        // Send CMD3 to get the relative card address (RCA) used for broad cast commands<br>+        if( !(status = sdSendRelativeAddr( pCard )) )<br>
+            continue;<br>+<br>+        // Send CMD9 to get the CSD register info<br>+        if( !(status = sdSendCSD( pCard )) )<br>+            continue;<br>+<br>+        // the card will now be in standby state, and is ready for data transfers<br>
+        if( status == true )<br>+        {<br>+            dprintf( DEBUG_HDL_SD, "SD card: Initialization of sd card is complete:\n" );<br>+            dprintf( DEBUG_HDL_SD, "  - currrent card state:  standby\n");<br>
+            dprintf( DEBUG_HDL_SD, "  - RCA: 0x%04x\n", pCard->rca );<br>+            dprintf( DEBUG_HDL_SD, "  - OCR: 0x%08x\n", pCard->ocr );<br>+            dprintf( DEBUG_HDL_SD,<br>+                    "  - CID: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",<br>
+                    pCard->cid[0], pCard->cid[1], pCard->cid[2], pCard->cid[3] );<br>+            dprintf( DEBUG_HDL_SD,<br>+                    "  - CSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",<br>+                    pCard->csd[0], pCard->csd[1], pCard->csd[2], pCard->csd[3] );<br>
+            dprintf( DEBUG_HDL_SD, "  - card type is ");<br>+            if( pCard->xchcCard )<br>+            {<br>+                dprintf( DEBUG_HDL_SD, "SDXC/SDHC\n" );<br>+            }<br>+            else<br>
+            {<br>+                dprintf( DEBUG_HDL_SD, "Normal SD\n" );<br>+            }<br>+<br>+<br>+            break;<br>+        }<br>+     }<br>+    return status;<br>+}<br>+<br>+/**<br>+ * @brief    sdCardBusInit - public function to initialize the SD card-bus.<br>
+ *                 This function is called by the host controller after the host<br>+ *                 controller has completed its initial "pessimistic" configuration.<br>+ *                 This function implements the steps in the sequence diagram of figure<br>
+ *                 4-1 of the "Physical Layer Simplified Specification Version 4.10" of the<br>+ *                 SD card specification documents.<br>+ *<br>+ * @param    sdHc_t* hc - pointer to the host controller structure<br>
+ *<br>+ * @return   bool - status, true = success, false = failure of the card bus initialization<br>+ */<br>+bool sdCardBusInit( sdHc_t* pHc )<br>+{<br>+    bool status = false;<br>+<br>+    // allocate the card<br>+    sdCard_t* pCard = malloc_fseg( sizeof( sdCard_t ) );<br>
+    if( !pCard )<br>+    {<br>+        dprintf( DEBUG_HDL_SD, "SD: card failed to allocate\n" );<br>+        return status;<br>+    }<br>+    dprintf( DEBUG_HDL_SD, "SD:  pCard address: 0x%08x\n", (uint32_t)pCard);<br>
+<br>+    // set the host pointer<br>+    pCard->pHost = pHc;<br>+<br>+    // Set Idle Mode with CMD0<br>+    status = sdIdle( pCard );<br>+<br>+    if( status )<br>+    {<br>+        // execute the initialization/identification procedure<br>
+        pCard->cardInitialized = sdCardIdentificationMode( pCard );<br>+    }<br>+<br>+    if( !pCard->cardInitialized )<br>+    {<br>+        dprintf( DEBUG_HDL_SD, "SD: Card init failed, check card...\n");<br>
+        status = pCard->cardInitialized;<br>+        free( pCard );<br>+    }<br>+    else<br>+    {<br>+        // If we get here, the card is in standby mode, so give a<br>+        // reference to the host controller<br>
+        pHc->pCard = pCard;<br>+    }<br>+    return status;<br>+}<br>diff --git a/src/hw/sd.h b/src/hw/sd.h<br>new file mode 100644<br>index 0000000..bcf4d94<br>--- /dev/null<br>+++ b/src/hw/sd.h<br>@@ -0,0 +1,275 @@<br>
+ /*****************************************************************************<br>+ *<br>+ * Copyright (c) 2012-2014 Sage Electronic Engineering.  All rights reserved.<br>+ *<br>+ * Software License Agreement<br>+ * Redistribution and use in source and binary forms, with or without<br>
+ * modification, are permitted provided that the following conditions<br>+ * are met:<br>+ * 1. Redistributions of source code must retain the above copyright<br>+ *    notice, this list of conditions and the following disclaimer.<br>
+ * 2. Redistributions in binary form must reproduce the above copyright<br>+ *    notice, this list of conditions and the following disclaimer in the<br>+ *    documentation and/or other materials provided with the distribution.<br>
+ *<br>+ * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED<br>+ * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF<br>+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.<br>
+ * Sage Electronic Engineering SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR<br>+ * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.<br>+ *****************************************************************************/<br>
+<br>+#ifndef __SD_H<br>+#define __SD_H<br>+<br>+#include <stdint.h><br>+#include <stdbool.h><br>+#include "sd_utils.h"<br>+<br>+/** @file sd.h */<br>+<br>+#include "sdhci.h"<br>+<br>+/** @brief sd host capabilities registers */<br>
+typedef struct<br>+{<br>+    uint32_t cap1;<br>+    uint32_t cap2;<br>+}capabilities_t;<br>+<br>+typedef enum<br>+{<br>+    eCmdNormal = SDHCI_CMD_TYPE_NORMAL,<br>+    eCmdSuspend = SDHCI_CMD_TYPE_SUSPEND,<br>+    eCmdResume = SDHCI_CMD_TYPE_RESUME,<br>
+    eCmdAbort = SDHCI_CMD_TYPE_ABORT<br>+}sdCmdType_e;<br>+<br>+typedef enum<br>+{<br>+    eRspNone = SDHCI_CMD_RESP_NONE,<br>+    eRsp136 = SDHCI_CMD_RESP_LONG,<br>+    eRsp48 = SDHCI_CMD_RESP_SHORT,<br>+    eRsp48_busy = SDHCI_CMD_RESP_SHORT_BUSY<br>
+}sdRspType_e;<br>+<br>+typedef enum<br>+{<br>+    eSdSpecV_1_00 = 0,<br>+    eSdSpecV_2_00,<br>+    eSdSpecV_3_00<br>+}sdSpecVer_e;<br>+<br>+typedef enum<br>+{<br>+    eRdXfer = 0,<br>+    eWrXfer<br>+}sdXferType_e;<br>+<br>
+typedef struct<br>+{<br>+    bool idxChkEn;<br>+    bool crcChkEn;<br>+}sdXferFlags_t;<br>+<br>+/** @brief struct used for host to card and card to host transfers */<br>+typedef struct<br>+{<br>+    uint8_t                     cmdIdx;<br>
+    uint32_t                    arg1;<br>+    sdCmdType_e                 cmdType;<br>+    sdRspType_e                 rspType;<br>+    sdXferType_e                xferType;<br>+    uint32_t                    response[4];<br>
+    bool                        rspValid;<br>+    void*                       pData;<br>+}sdXfer_t;<br>+<br>+/** @brief struct to hold decoded CID and CSD registers (see SD Specification) */<br>+typedef struct<br>+{<br>+    sd_cid_t                    cidDecode;<br>
+    sd_csd_t                    csdDecode;<br>+}sdRegDecode_t;<br>+<br>+// resolve forward declarations<br>+struct sdCard_t;<br>+typedef struct sdCard_t sdCard_t;<br>+<br>+typedef struct sdHc_t<br>+{<br>+    uint32_t                 barAddress;<br>
+    capabilities_t           cardCapabilities;<br>+    uint32_t                 maxClk;<br>+    uint32_t                 tmoClk;<br>+    uint32_t                 curClk;<br>+    uint32_t                 blkSize;<br>+    uint32_t                 pwrMode;<br>
+    bool                     crcCheckEnable;<br>+    bool                     indexCheckEnable;<br>+    bool                     xchcSupported;<br>+    bool                     isInitialized;<br>+    uint8_t                  hostVendorId;<br>
+    uint8_t                  hostSpecId;<br>+    sdCard_t*                pCard;<br>+<br>+    // call back to host for sending commands to the card via the host controller interface<br>+    bool (*sdhcCmd)( struct sdHc_t* pSdCtrl, sdXfer_t* xfer );<br>
+}sdHc_t;<br>+<br>+/**<br>+ * SD Memory Card Registers<br>+ */<br>+typedef struct sdCard_t<br>+{<br>+    sdHc_t*                 pHost;<br>+    uint32_t                cid[4];<br>+    uint16_t                rca;<br>+    uint16_t                dsr;<br>
+    uint32_t                csd[4];<br>+    uint32_t                scr[2];<br>+    uint32_t                ocr;<br>+    uint32_t                ssr[16];<br>+    uint32_t                csr;<br>+    sdRegDecode_t           decode;<br>
+    bool                    xchcCard;<br>+    bool                    cardInitialized;<br>+    bool                    isSelected;<br>+}sdCard_t;<br>+<br>+#define BLOCK_SIZE8      512<br>+#define MHZ 1000000<br>+#define KHZ 1000<br>
+#define BLOCK_MASK 0x00000FFF<br>+<br>+// MMC Card Commands that mostly overlap with the SD specification, some have slightly different meaning or results<br>+#define MMC_GO_IDLE_STATE_CMD0            0<br>+#define MMC_SEND_OP_COND_CMD1             1<br>
+#define MMC_ALL_SEND_CID_CMD2             2<br>+#define MMC_SET_RELATIVE_ADDR_CMD3        3<br>+#define MMC_SET_DSR_CMD4                  4<br>+#define MMC_SWITCH_CMD6                   6<br>+#define MMC_SELECT_CARD_CMD7              7<br>
+#define MMC_SEND_EXT_CSD_CMD8             8<br>+#define MMC_SEND_CSD_CMD9                 9<br>+#define MMC_SEND_CID_CMD10                10<br>+#define MMC_STOP_TRANSMISSION_CMD12       12<br>+#define MMC_SEND_STATUS_CMD13             13<br>
+#define MMC_SET_BLOCKLEN_CMD16            16<br>+#define MMC_READ_SINGLE_BLOCK_CMD17       17<br>+#define MMC_READ_MULTIPLE_BLOCK_CMD18     18<br>+#define MMC_WRITE_SINGLE_BLOCK_CMD24      24<br>+#define MMC_WRITE_MULTIPLE_BLOCK_CMD25    25<br>
+#define MMC_ERASE_GROUP_START_CMD35       35<br>+#define MMC_ERASE_GROUP_END_CMD36         36<br>+#define MMC_ERASE_CMD38                   38<br>+#define MMC_APP_CMD55                     55<br>+#define MMC_SPI_READ_OCR_CMD58            58<br>
+#define MMC_SPI_CRC_ON_OFF_CMD59          59<br>+<br>+// SD card specific commands<br>+#define SD_SEND_RELATIVE_ADDR_CMD3        3<br>+#define SD_SWITCH_FUNC_CMD6               6<br>+#define SD_SEND_IF_COND_CMD8              8<br>
+#define SD_APP_SET_BUS_WIDTH_CMD6         6<br>+#define SD_ERASE_WR_BLK_START_CMD32       32<br>+#define SD_ERASE_WR_BLK_END_CMD33         33<br>+#define SD_APP_SEND_OP_COND_CMD41         41<br>+#define SD_APP_SEND_SCR_CMD51             51<br>
+<br>+// other useful defines<br>+#define SD_VOLTAGE_RANGE_270_360          0x00000100<br>+#define SD_IF_COND_ECHO                   0x000000AA<br>+#define SD_STATE_CHANGE_ATTEMPTS          1000<br>+#define SD_TRY_AGAIN                      10<br>
+<br>+<br>+// ACMD41 bit shifts and masks<br>+#define OCR_DONE_BSY_N        (1 << 31)<br>+#define HCS_SHIFT 30<br>+#define HCS  (1 << HCS_SHIFT)<br>+#define XPC_SHIFT 28<br>+#define XPC  (1 << XPC_SHIFT)<br>
+#define S18R_SHIFT 24<br>+#define S18R (1 << S18R_SHIFT)<br>+#define OCR_SHIFT 8<br>+#define OCR  (0xFF << OCR_SHIFT)<br>+<br>+// OCR register voltage ranges<br>+#define VDD_27_28    (1 << 15)<br>+#define VDD_28_29    (1 << 16)<br>
+#define VDD_29_30    (1 << 17)<br>+#define VDD_30_31    (1 << 18)<br>+#define VDD_31_32    (1 << 19)<br>+#define VDD_32_33    (1 << 20)<br>+#define VDD 33_34    (1 << 21)<br>+#define VDD_34_35    (1 << 22)<br>
+#define VDD_35_36    (1 << 23)<br>+#define VDD_S18A     (1 << 24)<br>+<br>+<br>+#define VDD_MASK        ( VDD_27_28 | VDD_28_29 | VDD_29_30 | VDD_30_31 | VDD_31_32 | VDD_32_33 | VDD 33_34 | VDD_34_35 | VDD_35_36 )<br>
+#define VDD_RANGE_27_30 ( VDD_27_28 | VDD_28_29 | VDD_29_30 )<br>+#define VDD_RANGE_30_33 ( VDD_30_31 | VDD_31_32 | VDD_32_33 )<br>+#define VDD_RANGE_33_36 ( VDD 33_34 | VDD_34_35 | VDD_35_36 )<br>+<br>+#define CARD_UHS_II_STATUS          (1 << 29)<br>
+#define CARD_CAPACITY_STATUS        (1 << 30)<br>+#define CARD_POWER_UP_BUSY          (1 << 31)<br>+<br>+//! Physical Layer Simplified Specification Version 4.10 "Card Status" bits from Table 4-41<br>
+#define SDCARD_OUT_OF_RANGE         (1 << 31)<br>+#define SDCARD_ADDRESS_ERROR        (1 << 30)<br>+#define SDCARD_BLOCK_LEN_ERROR      (1 << 29)<br>+#define SDCARD_ERASE_SEQ_ERROR      (1 << 28)<br>
+#define SDCARD_ERASE_PARAM          (1 << 27)<br>+#define SDCARD_WP_VIOLATION         (1 << 26)<br>+#define SDCARD_CARD_IS_LOCKED       (1 << 25)<br>+#define SDCARD_LOCK_UNLOCK_FAILED   (1 << 24)<br>
+#define SDCARD_COM_CRC_ERROR        (1 << 23)<br>+#define SDCARD_ILLEGAL_COMMAND      (1 << 22)<br>+#define SDCARD_CARD_ECC_FAILED      (1 << 21)<br>+#define SDCARD_CC_ERROR             (1 << 20)<br>
+#define SDCARD_ERROR                (1 << 19)<br>+#define SDCARD_CSD_OVERWRITE        (1 << 16)<br>+#define SDCARD_WP_ERASE_SKIP        (1 << 15)<br>+#define SDCARD_CARD_ECC_DISABLED    (1 << 14)<br>
+#define SDCARD_ERASE_RESET          (1 << 13)<br>+#define SDCARD_CURRENT_STATE        (0xF << 9)<br>+#define SDCARD_READY_FOR_DATA       (1 << 8)<br>+#define SDCARD_APP_CMD              (1 << 5)<br>
+#define SDCARD_AKE_SEQ_ERROR        (1 << 3)<br>+<br>+// RCA RESPONSE STATUS BITS<br>+#define RCASTATUS_COM_CRC_ERROR     (1 << 15)<br>+#define RCASTATUS_ILLEGAL_COMMAND   (1 << 14)<br>+#define RCASTATUS_ERROR             (1 << 13)<br>
+#define RCASTATUS_CURRENT_STATE     (SDCARD_CURRENT_STATE)<br>+#define RCASTATUS_READY_FOR_DATA    (SDCARD_READY_FOR_DATA)<br>+#define RCASTATUS_APP_CMD           (SDCARD_APP_CMD)<br>+#define RCASTATUS_AKE_SEQ_ERROR     (SDCARD_AKE_SEQ_ERROR)<br>
+<br>+#define RCAERROR_MSK    (RCASTATUS_COM_CRC_ERROR | RCASTATUS_ILLEGAL_COMMAND | RCASTATUS_ERROR)<br>+<br>+typedef enum<br>+{<br>+    eIdle = 0,<br>+    eReady,<br>+    eIdent,<br>+    eStby,<br>+    eTran,<br>+    eData,<br>
+    eRcv,<br>+    ePrg,<br>+    eDis,<br>+    eInvalid<br>+}sdCardState_e;<br>+<br>+#define NUM_INIT_ATTEMPTS 2<br>+<br>+bool sdCardBusInit( sdHc_t* pHc );<br>+bool sdReadSingleBlock( sdCard_t* pCard, uint8_t* pData, uint32_t addr );<br>
+bool sdReadMultipleBlock( sdCard_t* pCard );<br>+bool sdStopTransmission( sdCard_t* pCard );<br>+<br>+#endif // __SD_H<br>diff --git a/src/hw/sd_if.c b/src/hw/sd_if.c<br>new file mode 100644<br>index 0000000..0d00b3c<br>
--- /dev/null<br>+++ b/src/hw/sd_if.c<br>@@ -0,0 +1,413 @@<br>+ /*****************************************************************************<br>+ *<br>+ * Copyright (c) 2012-2014 Sage Electronic Engineering.  All rights reserved.<br>
+ *<br>+ * Software License Agreement<br>+ * Redistribution and use in source and binary forms, with or without<br>+ * modification, are permitted provided that the following conditions<br>+ * are met:<br>+ * 1. Redistributions of source code must retain the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer.<br>+ * 2. Redistributions in binary form must reproduce the above copyright<br>+ *    notice, this list of conditions and the following disclaimer in the<br>
+ *    documentation and/or other materials provided with the distribution.<br>+ *<br>+ * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED<br>+ * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF<br>
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.<br>+ * Sage Electronic Engineering SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR<br>+ * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.<br>
+ *****************************************************************************/<br>+<br>+#include "stacks.h"<br>+#include "string.h"<br>+#include "malloc.h"<br>+#include "util.h"<br>
+#include "output.h"<br>+#include "biosvar.h"<br>+#include "pci.h"<br>+#include "pci_ids.h"<br>+#include "std/disk.h"<br>+#include "bar.h"<br>+#include "sdhci.h"<br>
+#include "sdhc_generic.h"<br>+#include "sd_if.h"<br>+<br>+sdDiskIf_t* g_pDev;<br>+<br>+static int sd_disk_read( struct disk_op_s* op );<br>+static int sd_disk_read_aligned( struct disk_op_s* op );<br>
+<br>+/**<br>+ * @brief    sd_disk_init - finalize the SeaBIOS drive initialization and register the drive<br>+ *<br>+ * @param    sdDiskIf_t* pSdIf - pointer to sd disk interface structure<br>+ *<br>+ * @return   none<br>
+ */<br>+static void sd_disk_init( sdDiskIf_t* pSdIf )<br>+{<br>+    pSdIf->drive.blksize = pSdIf->pHostCtrl->blkSize;<br>+    pSdIf->drive.type = DTYPE_SD;<br>+    pSdIf->drive.cntl_id = 0;  // @TODO: Presently only one SD card is supported at a time!<br>
+    pSdIf->drive.removable = false;<br>+    pSdIf->drive.translation = TRANSLATION_LBA;<br>+    // shift by 9 (divide by 512 block size)<br>+    pSdIf->drive.sectors = pSdIf->pHostCtrl->pCard->decode.csdDecode.capacity >> 9;<br>
+    dprintf( DEBUG_HDL_SD, "SD: num sectors: %d\n", (uint32_t)pSdIf->drive.sectors );<br>+<br>+    // generate host vendor/spec string<br>+    pSdIf->desc = znprintf( MAXDESCSIZE,<br>+                          "SD Card Vendor ID: %d",<br>
+                          pSdIf->pHostCtrl->hostVendorId );<br>+<br>+    pSdIf->bootPriority = bootprio_find_pci_device( (struct pci_device*)pSdIf->pPci );<br>+    dprintf( DEBUG_HDL_SD, "SD card boot priority: 0x%08x\n", pSdIf->bootPriority );<br>
+<br>+    // register the device as a hard disk<br>+    boot_add_hd(&pSdIf->drive, pSdIf->desc, (int)pSdIf->bootPriority );<br>+}<br>+<br>+/**<br>+ * @brief    sd_host_setup - setup the host controller driver, if the host<br>
+ *                 is successfully initialized, setup the sd card initialization<br>+ *<br>+ * @param    sdDiskIf_t* pSdIf - pointer to sd disk interface structure<br>+ *<br>+ * @return   bool true if the card was successfully initialized and prepared for boot<br>
+ *                  fasle otherwise<br>+ */<br>+static bool sd_host_setup( sdDiskIf_t* pSdIf)<br>+{<br>+    bool status = false;<br>+<br>+    // perform the sd card initialization sequence<br>+    if( sdhc_init( pSdIf->pHostCtrl ) )<br>
+    {<br>+        // if the card passes initialization and goes to standby mode, it is ready for boot, so setup the disk info<br>+        if( sdCardBusInit( pSdIf->pHostCtrl ) )<br>+        {<br>+            sd_disk_init( pSdIf );<br>
+<br>+            // the card is now enumerated, prepare it for boot (operational mode)<br>+            sdhc_prepBoot( pSdIf->pHostCtrl );<br>+            status = true;<br>+        }<br>+    }<br>+    return status;<br>
+}<br>+<br>+/**<br>+ * @brief    sd_card_detect - check to see if the card detect indicates that a card is present<br>+ *                 if there is a card, setup the host and intialize the underlying card<br>+ *<br>+ * @param    sdDiskIf_t* pSdIf - pointer to sd disk interface structure<br>
+ *<br>+ * @return   bool status of the card detect bit<br>+ */<br>+static bool sd_card_detect( sdDiskIf_t* pSdIf )<br>+{<br>+    bool status = false;<br>+    uint32_t regVal32 = 0;<br>+<br>+    // check to see if the card is present<br>
+    regVal32 = barRead32(pSdIf->pHostCtrl->barAddress, SDHCI_PRESENT_STATE);<br>+    status = (regVal32 & SDHCI_CARD_PRESENT) == SDHCI_CARD_PRESENT ? true : false;<br>+<br>+    // if the card is present, register it in the boot sequence<br>
+    if( status )<br>+    {<br>+        status = sd_host_setup( pSdIf );<br>+    }<br>+<br>+    return status;<br>+}<br>+<br>+<br>+/**<br>+ * @brief    sd_config_setup - setup the sd host controller driver and allocate resources.<br>
+ *<br>+ * @param    struct pci_device* pci - pointer to the sdhci controller pci device.<br>+ *<br>+ * @return   none<br>+ */<br>+static void sd_config_setup(struct pci_device* pci)<br>+{<br>+    dprintf(6, "sd_config_setup: 0x%04x\n", pci->bdf );<br>
+<br>+    // allocate the pci to sd interface structure<br>+    g_pDev = (sdDiskIf_t*)malloc_fseg( sizeof(*g_pDev) );<br>+    if( !g_pDev )<br>+    {<br>+        warn_noalloc();<br>+        return;<br>+    }<br>+    memset( g_pDev, 0, sizeof( *g_pDev ) );<br>
+<br>+    // allocate the host controller<br>+    g_pDev->pHostCtrl = (sdHc_t*)malloc_fseg( sizeof(*g_pDev->pHostCtrl) );<br>+    if( !(g_pDev->pHostCtrl) )<br>+    {<br>+        warn_noalloc();<br>+        free(g_pDev);<br>
+        return;<br>+    }<br>+    memset( g_pDev->pHostCtrl, 0, sizeof( *g_pDev->pHostCtrl) );<br>+    g_pDev->pHostCtrl->isInitialized = false;<br>+<br>+    // assign the pci device and set up the host controller<br>
+    g_pDev->pPci = pci;<br>+<br>+    // setup bar0<br>+    g_pDev->pHostCtrl->barAddress = pci_config_readl(g_pDev->pPci->bdf, 0x10) & 0xFFFFFF00;<br>+<br>+    // check for card detect<br>+    if( !sd_card_detect(g_pDev) )<br>
+    {<br>+        dprintf( DEBUG_HDL_SD, "No SD card detected\n");<br>+        free( g_pDev->pHostCtrl );<br>+        free( g_pDev );<br>+    }<br>+<br>+    else<br>+    {<br>+        dprintf( DEBUG_HDL_SD, "SD card is inserted\n");<br>
+<br>+        // initialize bounce buffer<br>+        if( create_bounce_buf() < 0 )<br>+        {<br>+            warn_noalloc();<br>+            free( g_pDev);<br>+        }<br>+    }<br>+}<br>+<br>+<br>+/**<br>+ * @brief    sd_scan - seabios function to scan for the sd conroller on the pci bus<br>
+ *<br>+ * @param    none<br>+ *<br>+ * @return   none<br>+ */<br>+static void sd_scan(void)<br>+{<br>+    struct pci_device *pci = NULL;<br>+    dprintf(6, "SD: Scanning for SD Host controllers\n" );<br>+<br>+    // Scan PCI bus for sd_mmc host controllers<br>
+    foreachpci(pci)<br>+    {<br>+        if( pci->class != PCI_CLASS_SYSTEM_SDHCI )<br>+        {<br>+            continue;<br>+        }<br>+<br>+        if( pci->prog_if != 1 )<br>+        {<br>+            continue;<br>
+        }<br>+        dprintf(6, "Found PCI SDHCI controller\n");<br>+<br>+        // setup the sd host controller hardware<br>+        sd_config_setup(pci);<br>+    }<br>+}<br>+<br>+<br>+<br>+/**<br>+ * @brief    sd_setup - seabios function<br>
+ *<br>+ * @param    none<br>+ *<br>+ * @return   none<br>+ */<br>+void sd_setup( void )<br>+{<br>+    ASSERT32FLAT();<br>+    if( CONFIG_SD )<br>+    {<br>+        dprintf(3, "init SD drives\n");<br>+        sd_scan();<br>
+    }<br>+}<br>+<br>+/**<br>+ * @brief    sd_cmd_data - seabios entry point for command/data disk transactions<br>+ *<br>+ * @param    struct disk_op_s *op - pointer to the disk operations structure<br>+ * @param    uint16_t blocksize - the size of the blocks for the block device transactions<br>
+ *<br>+ * @return   int disk operation status<br>+ */<br>+int sd_cmd_data( struct disk_op_s *op, void *cdbcmd, uint16_t blocksize )<br>+{<br>+    int retVal = DISK_RET_EPARAM;<br>+    dprintf(3, "sd_cmd_data\n");<br>
+<br>+    switch( op->command )<br>+    {<br>+        case CMD_READ:<br>+            retVal = sd_disk_read( op );<br>+            break;<br>+        case CMD_WRITE:<br>+            break;<br>+        case CMD_RESET:<br>
+        case CMD_ISREADY:<br>+        case CMD_FORMAT:<br>+        case CMD_VERIFY:<br>+        case CMD_SEEK:<br>+            retVal = DISK_RET_SUCCESS;<br>+            break;<br>+        default:<br>+            retVal = DISK_RET_EPARAM;<br>
+            break;<br>+    }<br>+    return retVal;<br>+}<br>+<br>+<br>+/**<br>+ * @brief    sd_disk_read_aligned - read into an aligned buffer a block of data from the sd card<br>+ *<br>+ * @param    struct disk_op_s* op - pointer to the disk operation request<br>
+ *<br>+ * @return   int - disk operation status<br>+ */<br>+static int sd_disk_read_aligned( struct disk_op_s* op )<br>+{<br>+    int retVal = DISK_RET_SUCCESS;<br>+    sdDiskIf_t* pSdIf = GET_GLOBAL( g_pDev );<br>+    uint16_t i = 0;<br>
+    uint8_t* curPosition = (uint8_t*)op->buf_fl;<br>+<br>+    for( i = 0; i < op->count; i++ )<br>+    {<br>+        if( !sdReadSingleBlock( pSdIf->pHostCtrl->pCard, curPosition, (uint32_t)(op->lba + i)) )<br>
+        {<br>+            dprintf( DEBUG_HDL_SD, "SD Read Fail\n");<br>+            retVal = DISK_RET_EPARAM;<br>+            break;<br>+        }<br>+        else<br>+        {<br>+            dprintf( DEBUG_HDL_SD, "sd disk %s, lba %6x, count %3x, buf %p, rc %d\n",<br>
+                           "read", (u32)op->lba + i, op->count - i, curPosition, retVal);<br>+            curPosition += BLOCK_SIZE8;<br>+        }<br>+    }<br>+    dprintf( DEBUG_HDL_SD, "return from read retval = %u\n", retVal );<br>
+    return retVal;<br>+}<br>+<br>+/**<br>+ * @brief    sd_disk_read - if the requested buffer is word aligned, performs the disk read operation<br>+ *<br>+ * @param    struct disk_op_s* op - pointer to the disk operation request<br>
+ *<br>+ * @return   int - disk operation status<br>+ */<br>+static int sd_disk_read( struct disk_op_s* op )<br>+{<br>+    int retVal = DISK_RET_EPARAM;<br>+    struct disk_op_s localOp;<br>+    uint8_t* alignedBuf = NULL;<br>
+    uint8_t* curPosition = NULL;<br>+    uint16_t i = 0;<br>+<br>+    // check if the callers buffer is word aligned, if so use it directly<br>+    if( ( (uint32_t)op->buf_fl & 1 ) == 0 )<br>+    {<br>+        dprintf( DEBUG_HDL_SD, "sd read: buffer already alligned\n");<br>
+        retVal = sd_disk_read_aligned( op );<br>+    }<br>+    else<br>+    {<br>+        dprintf( DEBUG_HDL_SD, "sd read: unaligned buffer, performing realligend read\n");<br>+        // get access to an aligned buffer for the disk operation<br>
+        localOp = *op;<br>+        alignedBuf = GET_GLOBAL( bounce_buf_fl );<br>+        curPosition = op->buf_fl;<br>+<br>+        // execute the aligned to unaligned access one operation at a time<br>+        localOp.buf_fl = alignedBuf;<br>
+        localOp.count = 1;<br>+<br>+        for( i = 0; i < op->count; i++ )<br>+        {<br>+            retVal = sd_disk_read_aligned( &localOp );<br>+            if( retVal )<br>+            {<br>+                dprintf( DEBUG_HDL_SD, "  - aligned read fail\n");<br>
+                break;<br>+            }<br>+            memcpy_fl( curPosition, alignedBuf, BLOCK_SIZE8 );<br>+            curPosition += BLOCK_SIZE8;<br>+            localOp.lba++;<br>+        }<br>+<br>+    }<br>+    return retVal;<br>
+}<br>+<br>+/**<br>+ * @brief    process_sd_op - entry point for disk io operations for sea bios<br>+ *<br>+ * @param    struct disk_op_s *op - disk io functions<br>+ *<br>+ * @return   int - disk return value from disk.h<br>
+ *<br>+ * @NOTE:    The macro VISIBLE32FLAT is indicitave of a call to 32 bit mode from 16-bit mode it forces the compiler<br>+ *             to prepend the <function name> with <_cfunc32flat_><funciton name>, so in this case if you were to perform<br>
+ *             a search for the caller of process_sd_op, you may not find it unless you search for _cfunc32flat_process_sd_op<br>+ */<br>+<br>+int VISIBLE32FLAT process_sd_op( struct disk_op_s *op  )<br>+{<br>+    int retVal = DISK_RET_EPARAM;<br>
+<br>+    // ensure the configuration exists<br>+    if (!CONFIG_SD)<br>+        return 0;<br>+<br>+    dprintf( DEBUG_HDL_SD, "Executing SD disk transaction:  %d\r\n", op->command );<br>+    // execute a command<br>
+    switch( op->command )<br>+    {<br>+        case CMD_READ:<br>+            dprintf( DEBUG_HDL_SD,<br>+                    "SD CMD_READ: lba: 0x%08x%08x\n", (uint32_t)(op->lba >> 32), (uint32_t)(op->lba) );<br>
+            dprintf( DEBUG_HDL_SD, "  op->count = %d\n", op->count );<br>+            retVal = sd_disk_read( op );<br>+            break;<br>+        case CMD_WRITE:<br>+            break;<br>+        case CMD_RESET:<br>
+        case CMD_ISREADY:<br>+        case CMD_FORMAT:<br>+        case CMD_VERIFY:<br>+        case CMD_SEEK:<br>+            retVal = DISK_RET_SUCCESS;<br>+            break;<br>+        default:<br>+            op->count = 0;<br>
+            retVal = DISK_RET_EPARAM;<br>+            break;<br>+<br>+    }<br>+    return retVal;<br>+}<br>+<br>+void SD_DEBUG( const char* func, unsigned int line )<br>+{<br>+    volatile uint8_t exit = 0;<br>+    volatile uint32_t i = 0;<br>
+<br>+    dprintf( DEBUG_HDL_SD, "%s, %d\n", func, line );<br>+<br>+    while( !exit )<br>+    {<br>+        i++;<br>+    }<br>+}<br>diff --git a/src/hw/sd_if.h b/src/hw/sd_if.h<br>new file mode 100644<br>index 0000000..af2e626<br>
--- /dev/null<br>+++ b/src/hw/sd_if.h<br>@@ -0,0 +1,49 @@<br>+ /*****************************************************************************<br>+ *<br>+ * Copyright (c) 2012-2014 Sage Electronic Engineering.  All rights reserved.<br>
+ *<br>+ * Software License Agreement<br>+ * Redistribution and use in source and binary forms, with or without<br>+ * modification, are permitted provided that the following conditions<br>+ * are met:<br>+ * 1. Redistributions of source code must retain the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer.<br>+ * 2. Redistributions in binary form must reproduce the above copyright<br>+ *    notice, this list of conditions and the following disclaimer in the<br>
+ *    documentation and/or other materials provided with the distribution.<br>+ *<br>+ * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED<br>+ * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF<br>
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.<br>+ * Sage Electronic Engineering SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR<br>+ * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.<br>
+ *****************************************************************************/<br>+<br>+#ifndef __SD_IF_H<br>+#define __SD_IF_H<br>+<br>+#include <stdint.h><br>+#include "block.h"<br>+#include "config.h"<br>
+#include "pci.h"<br>+#include "sd.h"<br>+<br>+/** @file sd_if.h*/<br>+<br>+// SeaBIOS to SD driver interface (to allow portability for reuse of sd driver<br>+<br>+typedef struct<br>+{<br>+    struct drive_s          drive;<br>
+    int32_t                 bootPriority;<br>+    const char*             desc;<br>+    struct pci_device*      pPci;<br>+    sdHc_t*                 pHostCtrl;<br>+}sdDiskIf_t;<br>+<br>+void sd_setup (void );<br>+int sd_cmd_data( struct disk_op_s *op, void *cdbcmd, uint16_t blocksize );<br>
+int process_sd_op( struct disk_op_s *op );<br>+void SD_DEBUG(const char* func, unsigned int line);<br>+#define SD_STOP( ) SD_DEBUG( __FUNCTION__, __LINE__ )<br>+#endif // __SD_IF_H<br>diff --git a/src/hw/sd_utils.c b/src/hw/sd_utils.c<br>
new file mode 100644<br>index 0000000..6920cb1<br>--- /dev/null<br>+++ b/src/hw/sd_utils.c<br>@@ -0,0 +1,190 @@<br>+/*-<br>+ * Copyright (c) 2006 Bernd Walter.  All rights reserved.<br>+ * Copyright (c) 2006 M. Warner Losh.  All rights reserved.<br>
+ * Copyright (C) 2013-2104 Sage Electronic Engineering, LLC<br>+ *<br>+ *<br>+ * Redistribution and use in source and binary forms, with or without<br>+ * modification, are permitted provided that the following conditions<br>
+ * are met:<br>+ * 1. Redistributions of source code must retain the above copyright<br>+ *    notice, this list of conditions and the following disclaimer.<br>+ * 2. Redistributions in binary form must reproduce the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer in the<br>+ *    documentation and/or other materials provided with the distribution.<br>+ *<br>+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR<br>
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES<br>+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.<br>+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,<br>
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT<br>+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,<br>+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY<br>
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT<br>+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF<br>+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.<br>
+ *<br>+ * Portions of this software may have been developed with reference to<br>+ * the SD Simplified Specification.  The following disclaimer may apply:<br>+ *<br>+ * The following conditions apply to the release of the simplified<br>
+ * specification ("Simplified Specification") by the SD Card Association and<br>+ * the SD Group. The Simplified Specification is a subset of the complete SD<br>+ * Specification which is owned by the SD Card Association and the SD<br>
+ * Group. This Simplified Specification is provided on a non-confidential<br>+ * basis subject to the disclaimers below. Any implementation of the<br>+ * Simplified Specification may require a license from the SD Card<br>
+ * Association, SD Group, SD-3C LLC or other third parties.<br>+ *<br>+ * Disclaimers:<br>+ *<br>+ * The information contained in the Simplified Specification is presented only<br>+ * as a standard specification for SD Cards and SD Host/Ancillary products and<br>
+ * is provided "AS-IS" without any representations or warranties of any<br>+ * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD<br>+ * Card Association for any damages, any infringements of patents or other<br>
+ * right of the SD Group, SD-3C LLC, the SD Card Association or any third<br>+ * parties, which may result from its use. No license is granted by<br>+ * implication, estoppel or otherwise under any patent or other rights of the<br>
+ * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing<br>+ * herein shall be construed as an obligation by the SD Group, the SD-3C LLC<br>+ * or the SD Card Association to disclose or distribute any technical<br>
+ * information, know-how or other confidential information to any third party.<br>+ */<br>+<br>+/*<br>+ * NOTE:  This is refactored code from FreeBSD modified to be OS agnostic and<br>+ *           independent for use in bootloading.<br>
+ */<br>+<br>+#include "config.h"<br>+#include "string.h"<br>+#include "output.h"<br>+#include "sd_utils.h"<br>+<br>+static uint32_t get_bits(uint32_t *bits, int bit_len, int start, int size);<br>
+<br>+static const int exp[8] = {<br>+    1, 10, 100, 1000, 10000, 100000, 1000000, 10000000<br>+};<br>+<br>+static const int mant[16] = {<br>+    0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80<br>+};<br>+<br>
+static const int cur_min[8] = {<br>+    500, 1000, 5000, 10000, 25000, 35000, 60000, 100000<br>+};<br>+<br>+static const int cur_max[8] = {<br>+    1000, 5000, 10000, 25000, 35000, 45000, 800000, 200000<br>+};<br>+<br>+static uint32_t get_bits(uint32_t *bits, int bit_len, int start, int size)<br>
+{<br>+    const int i = (bit_len / 32) - (start / 32) - 1;<br>+    const int shift = start & 31;<br>+    uint32_t retval = bits[i] >> shift;<br>+    if (size + shift > 32)<br>+        retval |= bits[i - 1] << (32 - shift);<br>
+    return (retval & ((1llu << size) - 1));<br>+}<br>+<br>+void decode_cid_sd(uint32_t *raw_cid, sd_cid_t* cid)<br>+{<br>+    int i;<br>+<br>+    /* There's no version info, so we take it on faith */<br>+    memset(cid, 0, sizeof(*cid));<br>
+    cid->mid = get_bits(raw_cid, 128, 120, 8);<br>+    cid->oid = get_bits(raw_cid, 128, 104, 16);<br>+    for (i = 0; i < 5; i++)<br>+        cid->pnm[i] = get_bits(raw_cid, 128, 96 - i * 8, 8);<br>+    cid->pnm[5] = 0;<br>
+    cid->prv = get_bits(raw_cid, 128, 56, 8);<br>+    cid->psn = get_bits(raw_cid, 128, 24, 32);<br>+    cid->mdt_year = get_bits(raw_cid, 128, 12, 8) + 2000;<br>+    cid->mdt_month = get_bits(raw_cid, 128, 8, 4);<br>
+}<br>+<br>+void decode_csd_sd(uint32_t *raw_csd, sd_csd_t* csd)<br>+{<br>+    int v;<br>+    int m;<br>+    int e;<br>+    int tst;<br>+<br>+    memset(csd, 0, sizeof(*csd));<br>+    csd->csd_structure = v = get_bits(raw_csd, 128, 126, 2);<br>
+    dprintf( DEBUG_HDL_SD, "CSD Register Info:\n" );<br>+    if (v == 0) {<br>+        dprintf( DEBUG_HDL_SD, "  CSD Version 1.0\n");<br>+        m = get_bits(raw_csd, 128, 115, 4);<br>+        e = get_bits(raw_csd, 128, 112, 3);<br>
+<br>+        tst = get_bits(raw_csd, 128, 112, 8 );<br>+        dprintf( DEBUG_HDL_SD, "  RAW TAAC: 0x%02x\n", (uint8_t)tst );<br>+<br>+        csd->tacc = (exp[e] * mant[m] + 9) / 10;<br>+        csd->nsac = get_bits(raw_csd, 128, 104, 8) * 100;<br>
+        m = get_bits(raw_csd, 128, 99, 4);<br>+        e = get_bits(raw_csd, 128, 96, 3);<br>+        csd->tran_speed = exp[e] * 10000 * mant[m];<br>+        csd->ccc = get_bits(raw_csd, 128, 84, 12);<br>+        csd->read_bl_len = 1 << get_bits(raw_csd, 128, 80, 4);<br>
+        csd->read_bl_partial = get_bits(raw_csd, 128, 79, 1);<br>+        csd->write_blk_misalign = get_bits(raw_csd, 128, 78, 1);<br>+        csd->read_blk_misalign = get_bits(raw_csd, 128, 77, 1);<br>+        csd->dsr_imp = get_bits(raw_csd, 128, 76, 1);<br>
+        csd->vdd_r_curr_min = cur_min[get_bits(raw_csd, 128, 59, 3)];<br>+        csd->vdd_r_curr_max = cur_max[get_bits(raw_csd, 128, 56, 3)];<br>+        csd->vdd_w_curr_min = cur_min[get_bits(raw_csd, 128, 53, 3)];<br>
+        csd->vdd_w_curr_max = cur_max[get_bits(raw_csd, 128, 50, 3)];<br>+        m = get_bits(raw_csd, 128, 62, 12);<br>+        e = get_bits(raw_csd, 128, 47, 3);<br>+        csd->capacity = ((1 + m) << (e + 2)) * csd->read_bl_len;<br>
+        csd->erase_blk_en = get_bits(raw_csd, 128, 46, 1);<br>+        csd->erase_sector = get_bits(raw_csd, 128, 39, 7) + 1;<br>+        csd->wp_grp_size = get_bits(raw_csd, 128, 32, 7);<br>+        csd->wp_grp_enable = get_bits(raw_csd, 128, 31, 1);<br>
+        csd->r2w_factor = 1 << get_bits(raw_csd, 128, 26, 3);<br>+        csd->write_bl_len = 1 << get_bits(raw_csd, 128, 22, 4);<br>+        csd->write_bl_partial = get_bits(raw_csd, 128, 21, 1);<br>
+    } else if (v == 1) {<br>+        dprintf( DEBUG_HDL_SD, "CSD Version 2.0\n");<br>+        m = get_bits(raw_csd, 128, 115, 4);<br>+        e = get_bits(raw_csd, 128, 112, 3);<br>+<br>+        tst = get_bits(raw_csd, 128, 112, 8 );<br>
+        dprintf( DEBUG_HDL_SD, "  RAW TAAC: 0x%02x\n", (uint8_t)tst );<br>+<br>+        csd->tacc = (exp[e] * mant[m] + 9) / 10;<br>+        csd->nsac = get_bits(raw_csd, 128, 104, 8) * 100;<br>+        m = get_bits(raw_csd, 128, 99, 4);<br>
+        e = get_bits(raw_csd, 128, 96, 3);<br>+        csd->tran_speed = exp[e] * 10000 * mant[m];<br>+        csd->ccc = get_bits(raw_csd, 128, 84, 12);<br>+        csd->read_bl_len = 1 << get_bits(raw_csd, 128, 80, 4);<br>
+        csd->read_bl_partial = get_bits(raw_csd, 128, 79, 1);<br>+        csd->write_blk_misalign = get_bits(raw_csd, 128, 78, 1);<br>+        csd->read_blk_misalign = get_bits(raw_csd, 128, 77, 1);<br>+        csd->dsr_imp = get_bits(raw_csd, 128, 76, 1);<br>
+        csd->capacity = ((uint64_t)get_bits(raw_csd, 128, 48, 22) + 1) *<br>+            512 * 1024;<br>+        dprintf( DEBUG_HDL_SD, " C_SIZE: 0x%08x\n", get_bits(raw_csd, 128, 48, 22) );<br>+        csd->erase_blk_en = get_bits(raw_csd, 128, 46, 1);<br>
+        csd->erase_sector = get_bits(raw_csd, 128, 39, 7) + 1;<br>+        csd->wp_grp_size = get_bits(raw_csd, 128, 32, 7);<br>+        csd->wp_grp_enable = get_bits(raw_csd, 128, 31, 1);<br>+        csd->r2w_factor = 1 << get_bits(raw_csd, 128, 26, 3);<br>
+        csd->write_bl_len = 1 << get_bits(raw_csd, 128, 22, 4);<br>+        csd->write_bl_partial = get_bits(raw_csd, 128, 21, 1);<br>+    } else<br>+    {<br>+        dprintf( DEBUG_HDL_SD, "unknown SD CSD version\n");<br>
+    }<br>+<br>+    dprintf( DEBUG_HDL_SD, "  READ_BL_LEN: %d\n", csd->read_bl_len );<br>+<br>+    dprintf( DEBUG_HDL_SD, "  CAPACITY: 0x%08x%08x\n", (uint32_t)( csd->capacity >> 32), (uint32_t)(csd->capacity) );<br>
+}<br>diff --git a/src/hw/sd_utils.h b/src/hw/sd_utils.h<br>new file mode 100644<br>index 0000000..56d0d97<br>--- /dev/null<br>+++ b/src/hw/sd_utils.h<br>@@ -0,0 +1,108 @@<br>+/*-<br>+ * Copyright (c) 2006 Bernd Walter.  All rights reserved.<br>
+ * Copyright (c) 2006 M. Warner Losh.  All rights reserved.<br>+ * Copyright (C) 2013-2104 Sage Electronic Engineering, LLC<br>+ *<br>+ * Redistribution and use in source and binary forms, with or without<br>+ * modification, are permitted provided that the following conditions<br>
+ * are met:<br>+ * 1. Redistributions of source code must retain the above copyright<br>+ *    notice, this list of conditions and the following disclaimer.<br>+ * 2. Redistributions in binary form must reproduce the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer in the<br>+ *    documentation and/or other materials provided with the distribution.<br>+ *<br>+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR<br>
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES<br>+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.<br>+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,<br>
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT<br>+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,<br>+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY<br>
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT<br>+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF<br>+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.<br>
+ *<br>+ * Portions of this software may have been developed with reference to<br>+ * the SD Simplified Specification.  The following disclaimer may apply:<br>+ *<br>+ * The following conditions apply to the release of the simplified<br>
+ * specification ("Simplified Specification") by the SD Card Association and<br>+ * the SD Group. The Simplified Specification is a subset of the complete SD<br>+ * Specification which is owned by the SD Card Association and the SD<br>
+ * Group. This Simplified Specification is provided on a non-confidential<br>+ * basis subject to the disclaimers below. Any implementation of the<br>+ * Simplified Specification may require a license from the SD Card<br>
+ * Association, SD Group, SD-3C LLC or other third parties.<br>+ *<br>+ * Disclaimers:<br>+ *<br>+ * The information contained in the Simplified Specification is presented only<br>+ * as a standard specification for SD Cards and SD Host/Ancillary products and<br>
+ * is provided "AS-IS" without any representations or warranties of any<br>+ * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD<br>+ * Card Association for any damages, any infringements of patents or other<br>
+ * right of the SD Group, SD-3C LLC, the SD Card Association or any third<br>+ * parties, which may result from its use. No license is granted by<br>+ * implication, estoppel or otherwise under any patent or other rights of the<br>
+ * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing<br>+ * herein shall be construed as an obligation by the SD Group, the SD-3C LLC<br>+ * or the SD Card Association to disclose or distribute any technical<br>
+ * information, know-how or other confidential information to any third party.<br>+ */<br>+<br>+/*<br>+ * NOTE:  This is refactored code from FreeBSD modified to be OS agnostic and<br>+ *           independent for use in bootloading.<br>
+ */<br>+<br>+#ifndef __SD_UTILS_H<br>+#define __SD_UTILS_H<br>+<br>+#include <stdint.h><br>+<br>+/* CSD -- decoded structure */<br>+typedef struct<br>+{<br>+    uint32_t mid;<br>+    char pnm[8];<br>+    uint32_t psn;<br>
+    uint16_t oid;<br>+    uint16_t mdt_year;<br>+    uint8_t mdt_month;<br>+    uint8_t prv;<br>+    uint8_t fwrev;<br>+}sd_cid_t;<br>+<br>+typedef struct<br>+{<br>+    uint8_t csd_structure;<br>+    uint8_t spec_vers;<br>
+    uint16_t ccc;<br>+    uint16_t tacc;<br>+    uint32_t nsac;<br>+    uint32_t r2w_factor;<br>+    uint32_t tran_speed;<br>+    uint32_t read_bl_len;<br>+    uint32_t write_bl_len;<br>+    uint32_t vdd_r_curr_min;<br>+    uint32_t vdd_r_curr_max;<br>
+    uint32_t vdd_w_curr_min;<br>+    uint32_t vdd_w_curr_max;<br>+    uint32_t wp_grp_size;<br>+    uint32_t erase_sector;<br>+    uint64_t capacity;<br>+    unsigned int read_bl_partial:1,<br>+        read_blk_misalign:1,<br>
+        write_bl_partial:1,<br>+        write_blk_misalign:1,<br>+        dsr_imp:1,<br>+        erase_blk_en:1,<br>+        wp_grp_enable:1;<br>+}sd_csd_t;<br>+<br>+<br>+void decode_cid_sd(uint32_t *raw_cid, sd_cid_t* cid);<br>
+void decode_csd_sd(uint32_t *raw_csd, sd_csd_t* csd);<br>+<br>+#endif<br>diff --git a/src/hw/sdhc_generic.c b/src/hw/sdhc_generic.c<br>new file mode 100644<br>index 0000000..6c675e1<br>--- /dev/null<br>+++ b/src/hw/sdhc_generic.c<br>
@@ -0,0 +1,697 @@<br>+ /*****************************************************************************<br>+ *<br>+ * Copyright (c) 2012-2014 Sage Electronic Engineering.  All rights reserved.<br>+ *<br>+ * Software License Agreement<br>
+ * Redistribution and use in source and binary forms, with or without<br>+ * modification, are permitted provided that the following conditions<br>+ * are met:<br>+ * 1. Redistributions of source code must retain the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer.<br>+ * 2. Redistributions in binary form must reproduce the above copyright<br>+ *    notice, this list of conditions and the following disclaimer in the<br>
+ *    documentation and/or other materials provided with the distribution.<br>+ *<br>+ * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED<br>+ * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF<br>
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.<br>+ * Sage Electronic Engineering SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR<br>+ * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.<br>
+ *****************************************************************************/<br>+<br>+#include <stdint.h><br>+#include <stdbool.h><br>+#include "string.h"<br>+#include "malloc.h"<br>+#include "util.h"<br>
+#include "output.h"<br>+#include "biosvar.h"<br>+#include "pci.h"<br>+#include "pci_ids.h"<br>+#include "std/disk.h"<br>+#include "bar.h"<br>+#include "sdhci.h"<br>
+#include "sd.h"<br>+#include "sdhc_generic.h"<br>+<br>+// host controller functions<br>+static void sdhc_readResponse( sdHc_t* pSdCtrl, sdXfer_t* pXfer );<br>+static bool sdhc_pollIntrStatus( sdHc_t* pSdCtrl, sdXfer_t* pXfer, uint32_t intrNum, uint32_t pollCnt, uint32_t uSecTmo );<br>
+static void sdhc_getVerInfo( sdHc_t* pSdCtrl );<br>+static void sdhc_setClock( sdHc_t* pSdCtrl, uint32_t clockVal );<br>+static void sdhc_setPower( sdHc_t* pSdCtrl, uint32_t pwrMode );<br>+static bool sdhc_reset( sdHc_t* pSdCtrl, uint8_t resetFlags );<br>
+static void sdhc_readBlock( sdHc_t* pSdCtrl, uint8_t* pBuf, uint32_t count );<br>+<br>+// callback function for performing command/response transactions<br>+static bool sdhc_Cmd( sdHc_t* pSdCtrl, sdXfer_t* pXfer );<br>+<br>
+<br>+/**<br>+ * @brief    sdhc_readResponse - helper function to read different response types<br>+ *              based on a transfer request<br>+ *<br>+ * @param    sdHc_t* pSdCtrl - pointer to the host controller abstraction structure<br>
+ * @param    sdXfer_t* pXfer - pointer to the host style transfer structure<br>+ *<br>+ * @return   none<br>+ */<br>+static void sdhc_readResponse( sdHc_t* pSdCtrl, sdXfer_t* pXfer )<br>+{<br>+    memset( pXfer->response, 0, sizeof( pXfer->response[0] * 4 ) );<br>
+    pXfer->rspValid = false;<br>+<br>+    switch( pXfer->rspType )<br>+    {<br>+        case eRsp136:<br>+            pXfer->response[0] = barRead32(pSdCtrl->barAddress, SDHCI_RESPONSE );<br>+            pXfer->response[1] = barRead32(pSdCtrl->barAddress, SDHCI_RESPONSE + 0x04 );<br>
+            pXfer->response[2] = barRead32(pSdCtrl->barAddress, SDHCI_RESPONSE + 0x08 );<br>+            pXfer->response[3] = barRead32(pSdCtrl->barAddress, SDHCI_RESPONSE + 0x0C );<br>+            pXfer->rspValid = true;<br>
+            break;<br>+<br>+        case eRsp48:<br>+            pXfer->response[0] = barRead32(pSdCtrl->barAddress, SDHCI_RESPONSE );<br>+            pXfer->rspValid = true;<br>+            break;<br>+<br>+        case eRsp48_busy:<br>
+            pXfer->response[0] = barRead32(pSdCtrl->barAddress, SDHCI_RESPONSE + 0x0C );<br>+            pXfer->rspValid = true;<br>+            break;<br>+<br>+        case eRspNone:<br>+        default:<br>+            break;<br>
+    }<br>+}<br>+<br>+/**<br>+ * @brief    sdhc_pollIntrStatus - interrupt status polling routine<br>+ *<br>+ * @param    sdHc_t* pSdCtrll - pointer to the host controller struct<br>+ * @param    uint32_t intrNum - the requested interrupt number(s) to check<br>
+ * @param    uint32_t pollCnt - the number of iterations to poll<br>+ * @param    uint32_t uSecTmo - microsecond delay per polling iteration<br>+ *<br>+ * @return   bool - true if the requested interrupt was set during this<br>
+ *              request cycle, false otherwise<br>+ */<br>+static bool sdhc_pollIntrStatus( sdHc_t* pSdCtrl, sdXfer_t* pXfer, uint32_t intrNum, uint32_t pollCnt, uint32_t uSecTmo )<br>+{<br>+    bool status = false;<br>+    uint32_t regVal32= 0;<br>
+<br>+    // check at least once<br>+    if( !pollCnt )<br>+    {<br>+        pollCnt = 1;<br>+    }<br>+<br>+    // check for the interrupt flag<br>+    while( pollCnt-- )<br>+    {<br>+        regVal32 = barRead32(pSdCtrl->barAddress, SDHCI_INT_STATUS );<br>
+        // check that all requested interrupts were set<br>+        if( ( intrNum & regVal32 ) == intrNum )<br>+        {<br>+            // in the case of response to command, save the response<br>+            if( intrNum == SDHCI_INT_RESPONSE )<br>
+            {<br>+                sdhc_readResponse( pSdCtrl, pXfer);<br>+            }<br>+<br>+            // clear the interrupt flag(s)<br>+            // @NOTE: some interrupts will not be cleared by writing them to 0<br>
+            regVal32 &= ~intrNum;<br>+            barWrite32( pSdCtrl->barAddress, SDHCI_INT_STATUS, regVal32 );<br>+            status = true;<br>+            dprintf( DEBUG_HDL_SD, "SD: requested interrupt occured: %u\n", intrNum );<br>
+            break;<br>+        }<br>+        else if( regVal32 & SDHCI_INT_ERROR_MASK )<br>+        {<br>+            // notify debug of timeout error<br>+            if( regVal32 & SDHCI_INT_TIMEOUT )<br>+            {<br>
+                dprintf( DEBUG_HDL_SD, "SD: ERROR Timeout\n" );<br>+            }<br>+            // reset the card on fatal errors<br>+            else<br>+            {<br>+                dprintf( DEBUG_HDL_SD,<br>
+                    "SD: ERROR interrupt occured, clearing interrupt and resetting card\n" );<br>+                    sdhc_reset( pSdCtrl, SDHCI_RESET_CMD | SDHCI_RESET_DATA );<br>+            }<br>+            barWrite32( pSdCtrl->barAddress, SDHCI_INT_STATUS, ~SDHCI_INT_ERROR_MASK );<br>
+            status = false;<br>+            break;<br>+        }<br>+<br>+        udelay( uSecTmo );<br>+    }<br>+    // in the case of errors, reset the card and clear out the error interrupts<br>+    dprintf( DEBUG_HDL_SD, "SD: Current interrupt status register: 0x%08x\n", regVal32 );<br>
+<br>+    return status;<br>+}<br>+<br>+/**<br>+ * @brief    sdhc_getVerInfo - read the host controller vendor specific id and host<br>+ *                 sd specification supported by the controller<br>+ *<br>+ * @param    sdHc_t* pSdCtrll - pointer to the host controller struct<br>
+ *<br>+ * @return   none<br>+ */<br>+static void sdhc_getVerInfo( sdHc_t* pSdCtrl )<br>+{<br>+    uint16_t regVal16 = 0;<br>+<br>+    regVal16 = barRead16( pSdCtrl->barAddress, SDHCI_HOST_VERSION );<br>+    pSdCtrl->hostVendorId =<br>
+            (uint8_t)( ( regVal16 & SDHCI_VENDOR_VER_MASK ) >> SDHCI_VENDOR_VER_SHIFT );<br>+    pSdCtrl->hostSpecId =<br>+            (uint8_t)( ( regVal16 & SDHCI_SPEC_VER_MASK ) >> SDHCI_SPEC_VER_SHIFT );<br>
+}<br>+<br>+/**<br>+ * @brief    sdhc_setPower - setup the power state of the host controller based on its<br>+ *                 reported capabilities.  The first time this is called, the power is setup<br>+ *                 in the highest condition to support all types of cards.  After card enumeration<br>
+ *                 the voltage can be lowered.<br>+ *<br>+ * @param     sdHc_t* pSdCtrll - pointer to the host controller abstraction structure<br>+ * @param     uint32_t pwrMode - the requested voltage setting for the power<br>
+ *<br>+ * @return    none<br>+ */<br>+static void sdhc_setPower( sdHc_t* pSdCtrl, uint32_t pwrMode )<br>+{<br>+    uint8_t pwr = 0;<br>+<br>+    pSdCtrl->pwrMode = pwrMode;<br>+<br>+    /* Turn off the POWER. */<br>+    barWrite8(pSdCtrl->barAddress, SDHCI_POWER_CONTROL, pwr);<br>
+<br>+    if (pwrMode == 0)<br>+        return;<br>+<br>+    /* Set voltage. */<br>+    switch( pwrMode )<br>+    {<br>+        case SDHCI_CAN_VDD_180:<br>+            pwr |= SDHCI_POWER_180;<br>+            break;<br>+        case SDHCI_CAN_VDD_300:<br>
+            pwr |= SDHCI_POWER_300;<br>+            break;<br>+        case SDHCI_CAN_VDD_330:<br>+            pwr |= SDHCI_POWER_330;<br>+            break;<br>+    }<br>+<br>+    barWrite8(pSdCtrl->barAddress, SDHCI_POWER_CONTROL, pwr);<br>
+    /* Turn on the POWER. */<br>+    pwr |= SDHCI_POWER_ON;<br>+    barWrite8(pSdCtrl->barAddress, SDHCI_POWER_CONTROL, pwr);<br>+}<br>+<br>+/**<br>+ * @brief    sdhc_setClock - set the clock of the host controller.  This function executes the<br>
+ *                 clock divisor algorithm described in the "SD Host Controller Simplified<br>+ *                 Specification Version 3.00" to generate the highest clock frequency that the<br>+ *                 card host can handle based on the requested clock.<br>
+ *<br>+ * @param    sdHc_t* pSdCtrll - pointer to the host controller abstraction structure<br>+ * @param    uint32_t clockVal - desired clock frequency<br>+ *<br>+ * @return   none.<br>+ */<br>+static void sdhc_setClock( sdHc_t* pSdCtrl, uint32_t clockVal )<br>
+{<br>+    uint32_t res = 0;<br>+    uint16_t clk = 0;<br>+    int32_t timeout = 0;<br>+<br>+    pSdCtrl->curClk = clockVal;<br>+<br>+    // disable the clock<br>+    barWrite16(pSdCtrl->barAddress, SDHCI_CLOCK_CONTROL, 0 );<br>
+<br>+    // calculate the highest possible frequency <= the maximum clock frequency reported by the card<br>+    res = pSdCtrl->maxClk;<br>+    for (clk = 1; clk < 256; clk <<= 1)<br>+    {<br>+        if( res <= clockVal )<br>
+        {<br>+            break;<br>+        }<br>+        res >>= 1;<br>+    }<br>+<br>+    // adjust the Divider, 1:1 is 0x00, 2:1 is 0x01, 256:1 is 0x80 ...<br>+    clk >>= 1;<br>+    clk <<= SDHCI_DIVIDER_SHIFT;<br>
+    clk |= SDHCI_CLOCK_INT_EN;<br>+    barWrite16( pSdCtrl->barAddress, SDHCI_CLOCK_CONTROL, clk);<br>+<br>+    // Wait up to 10 ms until it stabilizes<br>+    timeout = 10;<br>+    while( !((clk = barRead16(pSdCtrl->barAddress, SDHCI_CLOCK_CONTROL) )<br>
+            & SDHCI_CLOCK_INT_STABLE) )<br>+    {<br>+        if( timeout == 0 )<br>+        {<br>+            dprintf( DEBUG_HDL_SD, "SD: card internal clock never stabilized\n");<br>+            break;<br>
+        }<br>+        timeout--;<br>+        udelay(1000);<br>+    }<br>+<br>+    if( timeout > 0)<br>+    {<br>+        // clock is stable so enable the clock signal for the card bus<br>+        dprintf( DEBUG_HDL_SD, "SD: card internal clock stabilized at %u Hz\n", pSdCtrl->curClk );<br>
+        clk |= SDHCI_CLOCK_CARD_EN;<br>+        barWrite16( pSdCtrl->barAddress, SDHCI_CLOCK_CONTROL, clk );<br>+    }<br>+}<br>+<br>+/**<br>+ * @brief    sdhc_reset - issue the SD reset sequence described in the SD Host Controller Spec V3.00<br>
+ *<br>+ * @param    sdHc_t* pSdCtrl - pointer to the host controller struct<br>+ * @param    uint8_t resetFlags - a logical OR mask of the three possible reset types:<br>+ *                                     SDHCI_RESET_ALL - reset entire host controller<br>
+ *                                     SDHCI_RESET_CMD - reset command circuit<br>+ *                                     SDHCI_RESET_DATA - reset data & dma circuit<br>+ *<br>+ * @return   bool - true if the request did not timeout, false otherwise<br>
+ */<br>+static bool sdhc_reset( sdHc_t* pSdCtrl, uint8_t resetFlags )<br>+{<br>+    uint8_t resetResult = 0;<br>+    uint32_t timeout = 0;<br>+    bool status = false;<br>+<br>+    // send the reset command<br>+    barWrite8( (uint32_t)pSdCtrl->barAddress, SDHCI_SOFTWARE_RESET, resetFlags );<br>
+<br>+    // wait for all of the requested reset flags to clear until the timeout occurs<br>+    timeout = 10;<br>+    while( ( resetResult = barRead8( pSdCtrl->barAddress, SDHCI_SOFTWARE_RESET) & resetFlags ) )<br>
+    {<br>+        if( timeout == 0 )<br>+        {<br>+            dprintf( DEBUG_HDL_SD,<br>+                    "SDHC Reset Timeout for reset request type: 0x%02x\n", resetFlags );<br>+        }<br>+        timeout--;<br>
+        udelay(100);<br>+    }<br>+    if( timeout > 0)<br>+    {<br>+        dprintf( DEBUG_HDL_SD,<br>+                    "SDHC Reset Successful for reset request type: 0x%02x\n", resetFlags );<br>+        status = true;<br>
+    }<br>+    return status;<br>+}<br>+<br>+/**<br>+ * @brief    sdhc_Cmd - This is the call-back entry point for the card bus driver to access<br>+ *                 the bus via the host controller.  This function must be registered with the<br>
+ *                 card-bus driver in order for it to be able to function properly.  It is the<br>+ *                 entry point for both command and data transfers.<br>+ *<br>+ * @param    sdHc_t* pSdCtrl - pointer to the host controller abstraction<br>
+ * @param    sdXfer_t* pXfer - pointer to the command/data transfer, filled out by the<br>+ *                 card-bus driver.<br>+ * @return   bool true on success, false otherwise<br>+ */<br>+static bool sdhc_Cmd( sdHc_t* pSdCtrl, sdXfer_t* pXfer )<br>
+{<br>+    uint32_t curState = 0;<br>+    uint32_t stateMsk = 0;<br>+    uint8_t regVal8 = 0;<br>+    uint8_t tmo = 10;<br>+    uint16_t mode = 0;<br>+    bool status = false;<br>+    uint32_t intFlags = 0;<br>+<br>+    // setup the state mask for the transfer<br>
+    stateMsk = SDHCI_CMD_INHIBIT;<br>+    if( pXfer->rspType == eRsp48_busy )<br>+    {<br>+        stateMsk |= SDHCI_DAT_INHIBIT;<br>+    }<br>+<br>+    // wait for the state mask to clear<br>+    while( curState & stateMsk )<br>
+    {<br>+        if( tmo == 0 )<br>+        {<br>+            dprintf( DEBUG_HDL_SD,<br>+                    "SD: unable to access cmd bus, its always busy\n");<br>+            break;<br>+        }<br>+        tmo--;<br>
+        udelay(1000);<br>+        curState = barRead32( pSdCtrl->barAddress, SDHCI_PRESENT_STATE );<br>+    }<br>+<br>+    if( tmo > 0 )<br>+    {<br>+        //Set command argument<br>+        barWrite32(pSdCtrl->barAddress, SDHCI_ARGUMENT, pXfer->arg1);<br>
+<br>+        if( pXfer->pData && pXfer->xferType == eRdXfer )<br>+        {<br>+            //Set data transfer mode for reading data<br>+            mode = barRead16( pSdCtrl->barAddress, SDHCI_TRANSFER_MODE );<br>
+            mode |= ( SDHCI_TRNS_READ );<br>+            mode &= ~( SDHCI_TRNS_MULTI | SDHCI_TRNS_DMA );<br>+            barWrite16(pSdCtrl->barAddress, SDHCI_TRANSFER_MODE, mode );<br>+        }<br>+        else<br>
+        {<br>+            //Set data transfer mode for commanding<br>+            mode = barRead16( pSdCtrl->barAddress, SDHCI_TRANSFER_MODE );<br>+            mode &= ~( SDHCI_TRNS_READ | SDHCI_TRNS_MULTI | SDHCI_TRNS_DMA );<br>
+            barWrite16(pSdCtrl->barAddress, SDHCI_TRANSFER_MODE, mode );<br>+        }<br>+<br>+        // build the command transaction type<br>+        regVal8 = (pSdCtrl->crcCheckEnable) ? SDHCI_CMD_CRC : 0;<br>
+        regVal8 |= (pSdCtrl->indexCheckEnable) ? SDHCI_CMD_INDEX : 0;<br>+        regVal8 |= (pXfer->pData != NULL) ? SDHCI_CMD_DATA : 0;<br>+        regVal8 |= (uint8_t)(pXfer->cmdType);<br>+        regVal8 |= (uint8_t)(pXfer->rspType);<br>
+        barWrite8( pSdCtrl->barAddress, SDHCI_COMMAND_FLAGS, regVal8 );<br>+<br>+        // initiate the transfer<br>+        barWrite8(pSdCtrl->barAddress, SDHCI_COMMAND, pXfer->cmdIdx);<br>+<br>+        tmo = 10;<br>
+        if( pXfer->rspType != eRspNone )<br>+        {<br>+            intFlags = SDHCI_INT_RESPONSE;<br>+            if( (pXfer->pData) && (pXfer->xferType == eRdXfer) )<br>+            {<br>+                // wait for the transfer to be complete in the case of a read command<br>
+                intFlags |= SDHCI_INT_DATA_AVAIL;<br>+            }<br>+<br>+            while( !sdhc_pollIntrStatus( pSdCtrl, pXfer, intFlags, 100, 1000) )<br>+            {<br>+                if( tmo == 0 )<br>+                {<br>
+                    dprintf( DEBUG_HDL_SD, "SD: failed to receive response to command\n");<br>+                    break;<br>+                }<br>+                tmo--;<br>+            }<br>+<br>+            // if this is a read block transaction break out here to get the data<br>
+            if( (pXfer->pData) && (pXfer->xferType == eRdXfer) )<br>+            {<br>+                sdhc_readBlock( pSdCtrl, pXfer->pData, BLOCK_SIZE8 );<br>+            }<br>+        }<br>+<br>+    }<br>
+<br>+    status = (tmo > 0);<br>+    return status;<br>+}<br>+<br>+/**<br>+ * @brief    sdhc_readBlock - read a block from the SD card, this function is only<br>+ *                 executed if the data pointer and read flag are set in the sdhc_Cmd<br>
+ *                 request<br>+ *<br>+ * @param    sdHc_t* pSdCtrl - pointer to the host controller abstraction<br>+ * @param    uint8_t* pBuf - buffer to fill in with data (typically a block)<br>+ * @param    uint32_t count - number of bytes to read in the transaction<br>
+ *<br>+ * @return   none<br>+ */<br>+static void sdhc_readBlock( sdHc_t* pSdCtrl, uint8_t* pBuf, uint32_t count )<br>+{<br>+    uint32_t lim = 0;<br>+    uint32_t dataReg = 0;<br>+    uint8_t* pBufLocal = NULL;<br>+<br>+    pBufLocal = pBuf;<br>
+<br>+    //lim = min(BLOCK_SIZE8, count);<br>+    lim = BLOCK_SIZE8;<br>+<br>+    // ensure that there is data available<br>+    //usleep(10000);<br>+    // @NOTE: This usleep call was to throttle transactions during development,<br>
+    //        it can be commented back in to throttle block read transactions<br>+    //        while modifying the driver<br>+    if( barRead32( pSdCtrl->barAddress, SDHCI_PRESENT_STATE ) & SDHCI_DATA_AVAILABLE )<br>
+    {<br>+        dprintf( DEBUG_HDL_SD, "SD: reading %d bytes of data\n", lim );<br>+<br>+        // calculate the number of 32 bit values to read by converting the limit to<br>+        // dwords (additional bytes handled later)<br>
+        lim >>= 2;<br>+        while( lim > 0 )<br>+        {<br>+            dataReg = barRead32(pSdCtrl->barAddress, SDHCI_BUFFER);<br>+            pBufLocal[0] = (uint8_t)(dataReg);<br>+            pBufLocal[1] = (uint8_t)(dataReg >> 8);<br>
+            pBufLocal[2] = (uint8_t)(dataReg >> 16);<br>+            pBufLocal[3] = (uint8_t)(dataReg >> 24);<br>+            pBufLocal += 4;<br>+            lim--;<br>+        }<br>+<br>+        // handle the remainder<br>
+        lim = count & 0x03;<br>+        if( lim > 0 )<br>+        {<br>+            dataReg = barRead32(pSdCtrl->barAddress, SDHCI_BUFFER);<br>+            while( lim > 0 )<br>+            {<br>+                *(pBufLocal++) = (uint8_t)dataReg;<br>
+                dataReg >>= 8;<br>+                lim--;<br>+            }<br>+        }<br>+    }<br>+#if( CONFIG_DEBUG_LEVEL > 9 )<br>+    hexdump( pBuf, BLOCK_SIZE8 );<br>+#endif<br>+<br>+}<br>+<br>+/**<br>+ * @brief    sdhc_prepBoot - post initialization function to perform changes<br>
+ *                 to the operating mode of the card prior to boot, and to<br>+ *                 take it out of enumeration mode.<br>+ *<br>+ * @param    sdHc_t* pSdCtrl - pointer to the host controller struct<br>+ *<br>
+ * @return   none<br>+ */<br>+void sdhc_prepBoot( sdHc_t* pSdCtrl )<br>+{<br>+    // boost the clock speed for boot<br>+    //@TODO:  should check if this speed is supported first, (most newer cards do)<br>+    sdhc_setClock( pSdCtrl, 25 * MHZ );<br>
+<br>+    //@TODO: do other changes to card operating mode here<br>+}<br>+<br>+/**<br>+ * @brief   sdhc_isInitialized - check to see if the host controller is initialized<br>+ *<br>+ * @param   sdHc_t* pSdCtrl - pointerto the host controller sturcture<br>
+ *<br>+ * @return  bool true if host initialized, false otherwise<br>+ */<br>+bool sdhc_isInitialized( sdHc_t* pSdCtrl )<br>+{<br>+    return pSdCtrl->isInitialized;<br>+}<br>+<br>+/**<br>+ * @brief    sdhc_init - performs the minimum necessary steps outlined in the SD<br>
+ *                 host controller specification to prepare the sd card/host<br>+ *                 controller for use<br>+ *<br>+ * @param    sdHc_t* pSdCtrl - pointer to the host controller struct<br>+ *<br>+ * @return   bool true if reset succeeded, false otherwise<br>
+ */<br>+bool sdhc_init( sdHc_t* pSdCtrl )<br>+{<br>+    uint32_t regVal32 = 0;<br>+    uint8_t regVal8 = 0;<br>+<br>+    // reset the the host controller<br>+    if( sdhc_reset( pSdCtrl, SDHCI_RESET_ALL ) )<br>+    {<br>
+        // read the capabilities register<br>+        pSdCtrl->cardCapabilities.cap1 =<br>+                barRead32( pSdCtrl->barAddress, SDHCI_CAPABILITIES );<br>+        pSdCtrl->cardCapabilities.cap2 =<br>+                barRead32( pSdCtrl->barAddress, (SDHCI_CAPABILITIES + 4) );<br>
+<br>+        regVal8 = barRead8(pSdCtrl->barAddress, SDHCI_HOST_CONTROL );<br>+        dprintf( DEBUG_HDL_SD, "SD: Host Control register: 0x%02x\n", regVal8 );<br>+<br>+        // check the power<br>+        regVal8 = barRead8(pSdCtrl->barAddress, SDHCI_POWER_CONTROL );<br>
+        if( !(regVal8 & SDHCI_POWER_ON) )<br>+        {<br>+            dprintf( DEBUG_HDL_SD, "SD: card currently not powered, power on to");<br>+            // setup the power for the card<br>+            if( pSdCtrl->cardCapabilities.cap1 & SDHCI_CAN_VDD_330 )<br>
+            {<br>+                sdhc_setPower( pSdCtrl, SDHCI_CAN_VDD_330 );<br>+                dprintf( DEBUG_HDL_SD, ": 3.3V\n");<br>+            }<br>+            else if( pSdCtrl->cardCapabilities.cap1 & SDHCI_CAN_VDD_300 )<br>
+            {<br>+                sdhc_setPower( pSdCtrl, SDHCI_CAN_VDD_300 );<br>+                dprintf( DEBUG_HDL_SD, ": 3.0V\n");<br>+            }<br>+            else if( pSdCtrl->cardCapabilities.cap1 & SDHCI_CAN_VDD_180 )<br>
+            {<br>+                sdhc_setPower( pSdCtrl, SDHCI_CAN_VDD_180 );<br>+                dprintf( DEBUG_HDL_SD, ": 1.8V\n");<br>+            }<br>+        }<br>+        else<br>+        {<br>+            dprintf(6, "SD: card bus is powered on\n");<br>
+        }<br>+<br>+        // determine the base clock frequency reported by the card<br>+        pSdCtrl->maxClk =<br>+                (pSdCtrl->cardCapabilities.cap1 & SDHCI_CLOCK_BASE_MASK)<br>+                >> SDHCI_CLOCK_BASE_SHIFT;<br>
+        if( pSdCtrl->maxClk == 0 )<br>+        {<br>+            dprintf( DEBUG_HDL_SD,<br>+                    "SD: no base clock frequency specified by card capabilities\n");<br>+<br>+            // @TODO:  If the clock was not set, need to set it ?<br>
+        }<br>+        else<br>+        {<br>+            pSdCtrl->maxClk *= MHZ;<br>+            dprintf( DEBUG_HDL_SD, "SD: base clock frequency %u Hz\n", pSdCtrl->maxClk );<br>+        }<br>+<br>+        // setup the cards internal clock to always be normal speed mode to blanket support all card types<br>
+        // the sd spec defines normal speed mode as 25MHz, and enumeration at 400KHz<br>+        sdhc_setClock( pSdCtrl, 400000 );<br>+<br>+        // determine the base timeout frequency<br>+        pSdCtrl->tmoClk = (pSdCtrl->cardCapabilities.cap1 & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;<br>
+        if( pSdCtrl->tmoClk == 0 )<br>+        {<br>+            dprintf( DEBUG_HDL_SD, "SD: no timeout clock frequency specified by card capabilities\n");<br>+        }<br>+        else<br>+        {<br>+            // if the units are specified in MHz adjust the frequency to reflect that<br>
+            pSdCtrl->tmoClk =<br>+                    (pSdCtrl->cardCapabilities.cap1 & SDHCI_TIMEOUT_CLK_UNIT)<br>+                    ? pSdCtrl->tmoClk * MHZ : pSdCtrl->tmoClk * KHZ;<br>+            dprintf( DEBUG_HDL_SD, "SD: timeout frequency clock %u\n", pSdCtrl->tmoClk );<br>
+<br>+            // test max timeout<br>+            barWrite8( pSdCtrl->barAddress, SDHCI_TIMEOUT_CONTROL, 0x0E );<br>+        }<br>+<br>+        // the "always supported" block size is 512, so force it<br>
+        regVal32 = barRead32( pSdCtrl->barAddress, SDHCI_BLOCK_SIZE );<br>+<br>+        // mask off the block bits<br>+        pSdCtrl->blkSize &= BLOCK_MASK;<br>+        if( pSdCtrl->blkSize == 0 )<br>+        {<br>
+            dprintf( DEBUG_HDL_SD, "SD: no block size set...\n");<br>+        }<br>+        else<br>+        {<br>+            dprintf( DEBUG_HDL_SD, "SD: current block size: %u\n", pSdCtrl->blkSize );<br>
+        }<br>+<br>+        // if necessary set the block size to the default<br>+        if( pSdCtrl->blkSize != BLOCK_SIZE8 )<br>+        {<br>+            pSdCtrl->blkSize = BLOCK_SIZE8;<br>+            dprintf( DEBUG_HDL_SD, "  - setting new block size to 512 bytes\n");<br>
+<br>+            // clear the current block size bits<br>+            regVal32 &= ~BLOCK_MASK;<br>+            regVal32 |= pSdCtrl->blkSize;<br>+            barWrite32( pSdCtrl->barAddress, SDHCI_BLOCK_SIZE, regVal32 );<br>
+<br>+            // check that the new value was written<br>+            regVal32 = barRead32( pSdCtrl->barAddress, SDHCI_BLOCK_SIZE ) & BLOCK_MASK;<br>+            if( regVal32 != BLOCK_SIZE8 )<br>+            {<br>
+                dprintf( DEBUG_HDL_SD, "  - set new block size failed!");<br>+                //@TODO: Probably should fail now?<br>+            }<br>+            else<br>+            {<br>+                dprintf( DEBUG_HDL_SD, "  - new block size set to: %u\n", pSdCtrl->blkSize );<br>
+            }<br>+        }<br>+<br>+        // test reset after config<br>+        sdhc_reset( pSdCtrl, SDHCI_RESET_CMD | SDHCI_RESET_DATA );<br>+<br>+        // setup the interrupts<br>+        barWrite32( pSdCtrl->barAddress, SDHCI_INT_ENABLE, SDHCI_INT_BUS_POWER |<br>
+        SDHCI_INT_DATA_END_BIT |<br>+        SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |<br>+        SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |<br>+        SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT |<br>
+        SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL |<br>+        SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE |<br>+        SDHCI_INT_ACMD12ERR );<br>+<br>+        // and signals<br>+        barWrite32( pSdCtrl->barAddress, SDHCI_SIGNAL_ENABLE, SDHCI_INT_BUS_POWER |<br>
+        SDHCI_INT_DATA_END_BIT |<br>+        SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |<br>+        SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |<br>+        SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT |<br>
+        SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL |<br>+        SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE |<br>+        SDHCI_INT_ACMD12ERR );<br>+<br>+        regVal32 = barRead32( pSdCtrl->barAddress, SDHCI_INT_ENABLE );<br>
+        dprintf(6, "SD: interrupts enabled to: 0x%08x\n", regVal32 );<br>+<br>+        regVal32 = barRead32( pSdCtrl->barAddress, SDHCI_INT_STATUS );<br>+        dprintf(6, "SD: Current interrupt status: 0x%08x\n", regVal32 );<br>
+<br>+        regVal32 = barRead32( pSdCtrl->barAddress, SDHCI_PRESENT_STATE );<br>+        dprintf(6, "SD: Present State: 0x%08x\n", regVal32 );<br>+<br>+        // record the vendor and sd spec info of the host controller<br>
+        sdhc_getVerInfo( pSdCtrl );<br>+<br>+        // setup the callback(s) for the underlying card bus<br>+        pSdCtrl->sdhcCmd = &sdhc_Cmd;<br>+<br>+        pSdCtrl->isInitialized = true;<br>+    }<br>+    return( pSdCtrl->isInitialized );<br>
+}<br>diff --git a/src/hw/sdhc_generic.h b/src/hw/sdhc_generic.h<br>new file mode 100644<br>index 0000000..4797cc6<br>--- /dev/null<br>+++ b/src/hw/sdhc_generic.h<br>@@ -0,0 +1,41 @@<br>+ /*****************************************************************************<br>
+ *<br>+ * Copyright (c) 2012-2014 Sage Electronic Engineering.  All rights reserved.<br>+ *<br>+ * Software License Agreement<br>+ * Redistribution and use in source and binary forms, with or without<br>+ * modification, are permitted provided that the following conditions<br>
+ * are met:<br>+ * 1. Redistributions of source code must retain the above copyright<br>+ *    notice, this list of conditions and the following disclaimer.<br>+ * 2. Redistributions in binary form must reproduce the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer in the<br>+ *    documentation and/or other materials provided with the distribution.<br>+ *<br>+ * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED<br>
+ * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF<br>+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.<br>+ * Sage Electronic Engineering SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR<br>
+ * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.<br>+ *****************************************************************************/<br>+<br>+#ifndef __SDHC_GENERIC_H<br>+#define __SDHC_GENERIC_H<br>
+<br>+/** @file sdhc_generic.h */<br>+/*<br>+ * @brief SD PCI host controller driver header file.  This driver is intended<br>+ *           to be a generic driver for use with booting from SD cards. It<br>+ *           only supports the minimum controls necessary to boot.<br>
+ */<br>+#include <stdint.h><br>+#include "block.h"<br>+#include "config.h"<br>+#include "sd.h"<br>+<br>+<br>+bool sdhc_init( sdHc_t* pSdCtrl );<br>+void sdhc_prepBoot( sdHc_t* pSdCtrl );<br>
+bool sdhc_isInitialized( sdHc_t* pSdCtrl );<br>+<br>+#endif /* __SDHC_GENERIC_H */<br>diff --git a/src/hw/sdhci.h b/src/hw/sdhci.h<br>new file mode 100644<br>index 0000000..93ecd67<br>--- /dev/null<br>+++ b/src/hw/sdhci.h<br>
@@ -0,0 +1,207 @@<br>+/*-<br>+ * Copyright (c) 2008 Alexander Motin <mav@FreeBSD.org><br>+ * Copyright (C) 2013-2014 Sage Electronic Engineering, LLC<br>+ *<br>+ * All rights reserved.<br>+ *<br>+ * Redistribution and use in source and binary forms, with or without<br>
+ * modification, are permitted provided that the following conditions<br>+ * are met:<br>+ * 1. Redistributions of source code must retain the above copyright<br>+ *    notice, this list of conditions and the following disclaimer.<br>
+ * 2. Redistributions in binary form must reproduce the above copyright<br>+ *    notice, this list of conditions and the following disclaimer in the<br>+ *    documentation and/or other materials provided with the distribution.<br>
+ *<br>+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR<br>+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES<br>+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.<br>
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,<br>+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT<br>+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,<br>
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY<br>+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT<br>+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF<br>
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.<br>+ *<br>+ * $FreeBSD$<br>+ */<br>+/*<br>+ * NOTE:  This is from FreeBSD<br>+ */<br>+/*<br>+ * PCI registers<br>+ */<br>+<br>+<br>+<br>+<br>+#define PCI_SDHCI_IFPIO            0x00<br>
+#define PCI_SDHCI_IFDMA            0x01<br>+#define PCI_SDHCI_IFVENDOR        0x02<br>+<br>+#define PCI_SLOT_INFO            0x40    /* 8 bits */<br>+#define  PCI_SLOT_INFO_SLOTS(x)        (((x >> 4) & 7) + 1)<br>
+#define  PCI_SLOT_INFO_FIRST_BAR(x)    ((x) & 7)<br>+<br>+/*<br>+ * RICOH specific PCI registers<br>+ */<br>+#define    SDHC_PCI_MODE_KEY        0xf9<br>+#define    SDHC_PCI_MODE            0x150<br>+#define    SDHC_PCI_MODE_SD20        0x10<br>
+#define    SDHC_PCI_BASE_FREQ_KEY        0xfc<br>+#define    SDHC_PCI_BASE_FREQ        0xe1<br>+<br>+/*<br>+ * Controller registers<br>+ */<br>+<br>+#define SDHCI_DMA_ADDRESS    0x00<br>+<br>+#define SDHCI_BLOCK_SIZE    0x04<br>
+#define  SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))<br>+<br>+#define SDHCI_BLOCK_COUNT    0x06<br>+<br>+#define SDHCI_ARGUMENT        0x08<br>+<br>+#define SDHCI_TRANSFER_MODE    0x0C<br>
+#define  SDHCI_TRNS_DMA        0x01<br>+#define  SDHCI_TRNS_BLK_CNT_EN    0x02<br>+#define  SDHCI_TRNS_ACMD12    0x04<br>+#define  SDHCI_TRNS_READ    0x10<br>+#define  SDHCI_TRNS_MULTI    0x20<br>+<br>+#define SDHCI_COMMAND_FLAGS    0x0E<br>
+#define  SDHCI_CMD_RESP_NONE    0x00<br>+#define  SDHCI_CMD_RESP_LONG    0x01<br>+#define  SDHCI_CMD_RESP_SHORT    0x02<br>+#define  SDHCI_CMD_RESP_SHORT_BUSY 0x03<br>+#define  SDHCI_CMD_RESP_MASK    0x03<br>+#define  SDHCI_CMD_CRC        0x08<br>
+#define  SDHCI_CMD_INDEX    0x10<br>+#define  SDHCI_CMD_DATA        0x20<br>+#define  SDHCI_CMD_TYPE_NORMAL    0x00<br>+#define  SDHCI_CMD_TYPE_SUSPEND    0x40<br>+#define  SDHCI_CMD_TYPE_RESUME    0x80<br>+#define  SDHCI_CMD_TYPE_ABORT    0xc0<br>
+#define  SDHCI_CMD_TYPE_MASK    0xc0<br>+<br>+#define SDHCI_COMMAND        0x0F<br>+<br>+#define SDHCI_RESPONSE        0x10<br>+<br>+#define SDHCI_BUFFER        0x20<br>+<br>+#define SDHCI_PRESENT_STATE    0x24<br>+#define  SDHCI_CMD_INHIBIT    0x00000001<br>
+#define  SDHCI_DAT_INHIBIT    0x00000002<br>+#define  SDHCI_DAT_ACTIVE    0x00000004<br>+#define  SDHCI_DOING_WRITE    0x00000100<br>+#define  SDHCI_DOING_READ    0x00000200<br>+#define  SDHCI_SPACE_AVAILABLE    0x00000400<br>
+#define  SDHCI_DATA_AVAILABLE    0x00000800<br>+#define  SDHCI_CARD_PRESENT    0x00010000<br>+#define  SDHCI_CARD_STABLE    0x00020000<br>+#define  SDHCI_CARD_PIN        0x00040000<br>+#define  SDHCI_WRITE_PROTECT    0x00080000<br>
+#define  SDHCI_STATE_DAT    0x00700000<br>+#define  SDHCI_STATE_CMD    0x00800000<br>+<br>+#define SDHCI_HOST_CONTROL     0x28<br>+#define  SDHCI_CTRL_LED        0x01<br>+#define  SDHCI_CTRL_4BITBUS    0x02<br>+#define  SDHCI_CTRL_HISPD    0x04<br>
+#define  SDHCI_CTRL_SDMA    0x08<br>+#define  SDHCI_CTRL_ADMA2    0x10<br>+#define  SDHCI_CTRL_ADMA264    0x18<br>+#define  SDHCI_CTRL_CARD_DET    0x40<br>+#define  SDHCI_CTRL_FORCE_CARD    0x80<br>+<br>+#define SDHCI_POWER_CONTROL    0x29<br>
+#define  SDHCI_POWER_ON        0x01<br>+#define  SDHCI_POWER_180    0x0A<br>+#define  SDHCI_POWER_300    0x0C<br>+#define  SDHCI_POWER_330    0x0E<br>+<br>+#define SDHCI_BLOCK_GAP_CONTROL    0x2A<br>+<br>+#define SDHCI_WAKE_UP_CONTROL    0x2B<br>
+<br>+<br>+#define SDHCI_CLOCK_CONTROL    0x2C<br>+#define  SDHCI_DIVIDER_SHIFT    8<br>+#define  SDHCI_CLOCK_CARD_EN    0x0004<br>+#define  SDHCI_CLOCK_INT_STABLE    0x0002<br>+#define  SDHCI_CLOCK_INT_EN    0x0001<br>+<br>
+#define SDHCI_TIMEOUT_CONTROL    0x2E<br>+<br>+#define SDHCI_SOFTWARE_RESET    0x2F<br>+#define  SDHCI_RESET_ALL    0x01<br>+#define  SDHCI_RESET_CMD    0x02<br>+#define  SDHCI_RESET_DATA    0x04<br>+<br>+#define SDHCI_INT_STATUS    0x30<br>
+#define SDHCI_INT_ENABLE    0x34<br>+#define SDHCI_SIGNAL_ENABLE    0x38<br>+#define  SDHCI_INT_RESPONSE    0x00000001<br>+#define  SDHCI_INT_DATA_END    0x00000002<br>+#define  SDHCI_INT_BLOCK_GAP    0x00000004<br>+#define  SDHCI_INT_DMA_END    0x00000008<br>
+#define  SDHCI_INT_SPACE_AVAIL    0x00000010<br>+#define  SDHCI_INT_DATA_AVAIL    0x00000020<br>+#define  SDHCI_INT_CARD_INSERT    0x00000040<br>+#define  SDHCI_INT_CARD_REMOVE    0x00000080<br>+#define  SDHCI_INT_CARD_INT    0x00000100<br>
+#define  SDHCI_INT_ERROR    0x00008000<br>+#define  SDHCI_INT_TIMEOUT    0x00010000<br>+#define  SDHCI_INT_CRC        0x00020000<br>+#define  SDHCI_INT_END_BIT    0x00040000<br>+#define  SDHCI_INT_INDEX    0x00080000<br>
+#define  SDHCI_INT_DATA_TIMEOUT    0x00100000<br>+#define  SDHCI_INT_DATA_CRC    0x00200000<br>+#define  SDHCI_INT_DATA_END_BIT    0x00400000<br>+#define  SDHCI_INT_BUS_POWER    0x00800000<br>+#define  SDHCI_INT_ACMD12ERR    0x01000000<br>
+#define  SDHCI_INT_ADMAERR    0x02000000<br>+<br>+#define  SDHCI_INT_NORMAL_MASK    0x00007FFF<br>+#define  SDHCI_INT_ERROR_MASK    0xFFFF8000<br>+<br>+#define  SDHCI_INT_CMD_MASK    (SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \<br>
+        SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX)<br>+#define  SDHCI_INT_DATA_MASK    (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \<br>+        SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \<br>+        SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \<br>
+        SDHCI_INT_DATA_END_BIT)<br>+<br>+#define SDHCI_ACMD12_ERR    0x3C<br>+<br>+#define SDHCI_CAPABILITIES    0x40<br>+#define  SDHCI_TIMEOUT_CLK_MASK    0x0000003F<br>+#define  SDHCI_TIMEOUT_CLK_SHIFT 0<br>+#define  SDHCI_TIMEOUT_CLK_UNIT    0x00000080<br>
+#define  SDHCI_CLOCK_BASE_MASK    0x00003F00<br>+#define  SDHCI_CLOCK_BASE_SHIFT    8<br>+#define  SDHCI_MAX_BLOCK_MASK    0x00030000<br>+#define  SDHCI_MAX_BLOCK_SHIFT  16<br>+#define  SDHCI_CAN_DO_ADMA2    0x00080000<br>
+#define  SDHCI_CAN_DO_HISPD    0x00200000<br>+#define  SDHCI_CAN_DO_DMA    0x00400000<br>+#define  SDHCI_CAN_DO_SUSPEND    0x00800000<br>+#define  SDHCI_CAN_VDD_330    0x01000000<br>+#define  SDHCI_CAN_VDD_300    0x02000000<br>
+#define  SDHCI_CAN_VDD_180    0x04000000<br>+#define  SDHCI_CAN_DO_64BIT    0x10000000<br>+<br>+#define SDHCI_MAX_CURRENT    0x48<br>+<br>+#define SDHCI_SLOT_INT_STATUS    0xFC<br>+<br>+#define SDHCI_HOST_VERSION    0xFE<br>
+#define  SDHCI_VENDOR_VER_MASK    0xFF00<br>+#define  SDHCI_VENDOR_VER_SHIFT    8<br>+#define  SDHCI_SPEC_VER_MASK    0x00FF<br>+#define  SDHCI_SPEC_VER_SHIFT    0<br>diff --git a/src/post.c b/src/post.c<br>index 0fdd28e..556ff47 100644<br>
--- a/src/post.c<br>+++ b/src/post.c<br>@@ -2,6 +2,7 @@<br> //<br> // Copyright (C) 2008-2013  Kevin O'Connor <<a href="mailto:kevin@koconnor.net">kevin@koconnor.net</a>><br> // Copyright (C) 2002  MandrakeSoft S.A.<br>
+// Copyright (C) 2013-2014 Sage Electronic Engineering, LLC<br> //<br> // This file may be distributed under the terms of the GNU LGPLv3 license.<br> <br>@@ -14,6 +15,7 @@<br> #include "hw/ata.h" // ata_setup<br>
 #include "hw/esp-scsi.h" // esp_scsi_setup<br> #include "hw/lsi-scsi.h" // lsi_scsi_setup<br>+#include "hw/sd_if.h" // sd_setup<br> #include "hw/megasas.h" // megasas_setup<br> #include "hw/pvscsi.h" // pvscsi_setup<br>
 #include "hw/pic.h" // pic_setup<br>@@ -143,6 +145,7 @@ device_hardware_setup(void)<br>     floppy_setup();<br>     ata_setup();<br>     ahci_setup();<br>+    sd_setup();<br>     cbfs_payload_setup();<br>     ramdisk_setup();<br>
     virtio_blk_setup();<br>diff --git a/src/stdbool.h b/src/stdbool.h<br>new file mode 100644<br>index 0000000..71f75b0<br>--- /dev/null<br>+++ b/src/stdbool.h<br>@@ -0,0 +1,29 @@<br>+ /*****************************************************************************<br>
+ *<br>+ * Copyright (c) 2012-2014 Sage Electronic Engineering.  All rights reserved.<br>+ *<br>+ * Software License Agreement<br>+ * Redistribution and use in source and binary forms, with or without<br>+ * modification, are permitted provided that the following conditions<br>
+ * are met:<br>+ * 1. Redistributions of source code must retain the above copyright<br>+ *    notice, this list of conditions and the following disclaimer.<br>+ * 2. Redistributions in binary form must reproduce the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer in the<br>+ *    documentation and/or other materials provided with the distribution.<br>+ *<br>+ * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED<br>
+ * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF<br>+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.<br>+ * Sage Electronic Engineering SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR<br>
+ * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.<br>+ *****************************************************************************/<br>+<br>+#ifndef __SEABIOS_STDBOOL_H<br>+#define __SEABIOS_STDBOOL_H<br>
+<br>+typedef int bool;<br>+#define true 1<br>+#define false 0<br>+<br>+#endif /* __SEABIOS_STDBOOL_H */<br>diff --git a/src/stdint.h b/src/stdint.h<br>new file mode 100644<br>index 0000000..276119b<br>--- /dev/null<br>+++ b/src/stdint.h<br>
@@ -0,0 +1,41 @@<br>+ /*****************************************************************************<br>+ *<br>+ * Copyright (c) 2012-2014 Sage Electronic Engineering.  All rights reserved.<br>+ *<br>+ * Software License Agreement<br>
+ * Redistribution and use in source and binary forms, with or without<br>+ * modification, are permitted provided that the following conditions<br>+ * are met:<br>+ * 1. Redistributions of source code must retain the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer.<br>+ * 2. Redistributions in binary form must reproduce the above copyright<br>+ *    notice, this list of conditions and the following disclaimer in the<br>
+ *    documentation and/or other materials provided with the distribution.<br>+ *<br>+ * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED<br>+ * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF<br>
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.<br>+ * Sage Electronic Engineering SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR<br>+ * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.<br>
+ *****************************************************************************/<br>+<br>+#ifndef __SEABIOS_STDINT_H<br>+#define __SEABIOS_STDINT_H<br>+<br>+#include "types.h"<br>+<br>+/* minimal stdint types for seabios non-specific portability */<br>
+<br>+typedef u8       uint8_t;<br>+typedef s8       int8_t;<br>+<br>+typedef u16      uint16_t;<br>+typedef s16      int16_t;<br>+<br>+typedef u32      uint32_t;<br>+typedef s32      int32_t;<br>+<br>+typedef u64      uint64_t;<br>
+typedef s64      int64_t;<br>+<br>+#endif /* __SEABIOS_STDINT_H */<br>-- <br>1.9.1<br><br><br></div>