<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>