From 83f68fb6103bde1aca21bcf3154de2bb78773d7e Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Thu, 9 Dec 2010 09:29:25 -0700 Subject: [PATCH] Xilinx: ARM: Add initial SecureDigital support. Usage: pele-boot> mmc rescan 0 pele-boot> fatls mmc 0 3025088 vmlinux.bin 1048576 ramdisk1m.image 3145728 ramdisk3m.image 7340032 ramdisk7m.test.image 4 file(s), 0 dir(s) pele-boot> fatload mmc 0 0x8000 vmlinux.bin pele-boot> fatload mmc 0 0x800000 ramdisk3m.image pele-boot> go 0x8000 --- board/xilinx/dfe/Makefile | 1 + board/xilinx/dfe/mmc.c | 321 +++++++++++++++++++++++++++++++++ board/xilinx/dfe/sd_hardware.h | 90 +++++++++ drivers/mmc/mmc.c | 3 + include/configs/xpele.h | 10 + 5 files changed, 425 insertions(+) create mode 100755 board/xilinx/dfe/mmc.c create mode 100644 board/xilinx/dfe/sd_hardware.h diff --git a/board/xilinx/dfe/Makefile b/board/xilinx/dfe/Makefile index 60685221bd7..fd435d58a3b 100644 --- a/board/xilinx/dfe/Makefile +++ b/board/xilinx/dfe/Makefile @@ -34,6 +34,7 @@ COBJS := board.o \ xilinx_nandpss.o \ xilinx_qspipss.o \ pele_qspi.o \ + mmc.o \ ../common/xbasic_types.o SOBJS := lowlevel_init.o diff --git a/board/xilinx/dfe/mmc.c b/board/xilinx/dfe/mmc.c new file mode 100755 index 00000000000..64259b3ef7a --- /dev/null +++ b/board/xilinx/dfe/mmc.c @@ -0,0 +1,321 @@ +#include +#include +#include + +#include "sd_hardware.h" +#include "xparameters.h" + +#define SD_BASEADDR XPSS_SDIO0_BASEADDR + +static u32 *sd_dma_buffer; + +/* Data Memory Barrier */ +#define dmb() __asm__ __volatile__ ("dmb" : : : "memory") +#define SYNCHRONIZE_IO dmb() + +static void sd_out32(u32 OutAddress, u32 Value) +{ + OutAddress += SD_BASEADDR; + *(volatile u32 *) OutAddress = Value; + SYNCHRONIZE_IO; +} +static void sd_out16(u32 OutAddress, u16 Value) +{ + OutAddress += SD_BASEADDR; + *(volatile u16 *) OutAddress = Value; + SYNCHRONIZE_IO; +} +static void sd_out8(u32 OutAddress, u8 Value) +{ + OutAddress += SD_BASEADDR; + *(volatile u8 *) OutAddress = Value; + SYNCHRONIZE_IO; +} + +static u32 sd_in32(u32 InAddress) +{ + SYNCHRONIZE_IO; + InAddress += SD_BASEADDR; + return *(volatile u32 *) InAddress; +} +static u16 sd_in16(u32 InAddress) +{ + SYNCHRONIZE_IO; + InAddress += SD_BASEADDR; + return *(volatile u16 *) InAddress; +} +static u8 sd_in8(u32 InAddress) +{ + SYNCHRONIZE_IO; + InAddress += SD_BASEADDR; + return *(volatile u8 *) InAddress; +} + +/* Initialize the SD controller */ +static void init_port(void) +{ + unsigned clk; + + /* Power off the card */ + sd_out8(SD_PWR_CTRL_R, 0); + + /* Disable interrupts */ + sd_out32(SD_SIG_ENA_R, 0); + + /* Perform soft reset */ + sd_out8(SD_SOFT_RST_R, SD_RST_ALL); + /* Wait for reset to comlete */ + while (sd_in8(SD_SOFT_RST_R)) { + ; + } + + /* Power on the card */ + sd_out8(SD_PWR_CTRL_R, SD_POWER_33|SD_POWER_ON); + + /* Enable Internal clock and wait for it to stablilize */ + clk = (0x40 << SD_DIV_SHIFT) | SD_CLK_INT_EN; + sd_out16(SD_CLK_CTL_R, clk); + do { + clk = sd_in16(SD_CLK_CTL_R); + } while (!(clk & SD_CLK_INT_STABLE)); + + /* Enable SD clock */ + clk |= SD_CLK_SD_EN; + sd_out16(SD_CLK_CTL_R, clk); + + sd_out32(SD_SIG_ENA_R, 0xFFFFFFFF); + sd_out32(SD_INT_ENA_R, 0xFFFFFFFF); +} + +/* MMC/SD command (SPI mode) */ +#define CMD0 (0) /* GO_IDLE_STATE */ +#define CMD1 (1) /* SEND_OP_COND */ +#define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */ +#define CMD2 (2) /* SEND_CID */ +#define CMD3 (3) /* RELATIVE_ADDR */ +#define CMD5 (5) /* SLEEP_WAKE (SDC) */ +#define CMD7 (7) /* SELECT */ +#define CMD8 (8) /* SEND_IF_COND */ +#define CMD9 (9) /* SEND_CSD */ +#define CMD10 (10) /* SEND_CID */ +#define CMD12 (12) /* STOP_TRANSMISSION */ +#define ACMD13 (0x80+13) /* SD_STATUS (SDC) */ +#define CMD16 (16) /* SET_BLOCKLEN */ +#define CMD17 (17) /* READ_SINGLE_BLOCK */ +#define CMD18 (18) /* READ_MULTIPLE_BLOCK */ +#define CMD23 (23) /* SET_BLOCK_COUNT */ +#define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */ +#define CMD24 (24) /* WRITE_BLOCK */ +#define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */ +#define CMD41 (41) /* SEND_OP_COND (ACMD) */ +#define CMD52 (52) /* */ +#define CMD55 (55) /* APP_CMD */ +#define CMD58 (58) /* READ_OCR */ + +/* make_command: + * Determing the proper value for the command register for the indicated + * command index. + */ +static int +make_command (unsigned cmd) +{ + unsigned retval; + + retval = cmd << 8; + +#define RSP_NONE SD_CMD_RESP_NONE +#define RSP_R1 (SD_CMD_INDEX|SD_CMD_RESP_48 |SD_CMD_CRC) +#define RSP_R1b (SD_CMD_INDEX|SD_CMD_RESP_48_BUSY|SD_CMD_CRC) +#define RSP_R2 (SD_CMD_CRC |SD_CMD_RESP_136) +#define RSP_R3 (SD_CMD_RESP_48) +#define RSP_R6 (SD_CMD_INDEX|SD_CMD_RESP_48_BUSY|SD_CMD_CRC) + + switch(cmd) { + case CMD0: + retval |= (SD_CMD_RESP_NONE); + break; + case CMD1: + retval |= RSP_R3; + break; + case CMD2: + retval |= RSP_R2; + break; + case CMD3: + retval |= RSP_R6; + break; + case CMD5: + retval |= RSP_R1b; + break; + case CMD7: + retval |= RSP_R1; + break; + case CMD8: + retval |= RSP_R1; + break; + case CMD9: + retval |= RSP_R2; + break; + case CMD10: + case CMD12: + case ACMD13: + case CMD16: + retval |= RSP_R1; + break; + case CMD17: + retval |= RSP_R1|SD_CMD_DATA; + break; + case CMD18: + case CMD23: + case ACMD23: + case CMD24: + case CMD25: + case CMD41: + retval |= RSP_R3; + break; + case CMD52: + case CMD55: + retval |= RSP_R1; + break; + case CMD58: + break; + } + + return retval; +} + +static int pele_sdh_request(struct mmc *mmc, struct mmc_cmd *cmd, + struct mmc_data *data) +{ + u32 status; + u16 cmdreg; + +#ifdef DEBUG_VERBOSE + printf("pele_sdh_request: cmdidx: %d arg: 0x%x\n", + cmd->cmdidx, cmd->cmdarg); +#endif + + cmd->response[0] = 0; + + /* Wait until the device is willing to accept commands */ + do { + status = sd_in32(SD_PRES_STATE_R); + } while (status & (SD_CMD_INHIBIT|SD_DATA_INHIBIT)); + + /* Set the DMA address to the DMA buffer. + * This is only relevant for data commands. + * u-boot performs a copy rather than DMA directly into the user + * buffer because the controller can't DMA into the first 512K + * of DDR. + */ + sd_out32(SD_DMA_ADDR_R, sd_dma_buffer); + + /* 512 bytes + * This is only relevant for data commands. + */ + sd_out16(SD_BLOCK_SZ_R, 0x200); + sd_out16(SD_BLOCK_CNT_R, 1); + + sd_out8(SD_TIMEOUT_CTL_R, 0xA); + + sd_out32(SD_ARG_R, cmd->cmdarg); + + /* Set the transfer mode to read, simple DMA, single block + * (applicable only to data commands) + * This is all that this software supports. + */ + sd_out16(SD_TRNS_MODE_R, + SD_TRNS_BLK_CNT_EN|SD_TRNS_READ|SD_TRNS_DMA); + + /* Clear all pending interrupt status */ + sd_out32(SD_INT_STAT_R, 0xFFFFFFFF); + + /* Initiate the command */ + cmdreg = make_command(cmd->cmdidx); + sd_out16(SD_CMD_R, cmdreg); + + /* Poll until operation complete */ + while (1) { + status = sd_in32(SD_INT_STAT_R); + if (status & SD_INT_ERROR) { +#ifdef DEBUG + printf("send_cmd: Error: (0x%08x) cmd: %d arg: 0x%x\n", + status, cmd->cmdidx, cmd->cmdarg); +#else + if (cmd->cmdidx == CMD17) { + printf("MMC: Error reading sector %d (0x%08x)\n", + cmd->cmdarg); + } +#endif + sd_out8(SD_SOFT_RST_R, + SD_RST_CMD|SD_RST_DATA); + + if (status & (SD_INT_ERR_CTIMEOUT|SD_INT_ERR_DTIMEOUT)) { + return TIMEOUT; + } else { + return COMM_ERR; + } + } + if (status & SD_INT_CMD_CMPL) { + if (cmdreg & SD_CMD_DATA) { + if (status & (SD_INT_DMA | SD_INT_TRNS_CMPL)) { + break; + } + } else { + break; + } + } + } + + cmd->response[0] = sd_in32(SD_RSP_R); + cmd->response[1] = sd_in32(SD_RSP_R+4); + cmd->response[2] = sd_in32(SD_RSP_R+8); + cmd->response[3] = sd_in32(SD_RSP_R+12); + + if (cmdreg & SD_CMD_DATA) { + memcpy(data->dest, sd_dma_buffer, 512); + } + + return 0; +} + +static void pele_sdh_set_ios(struct mmc *mmc) +{ +} +static int pele_sdh_init(struct mmc *mmc) +{ + init_port(); + return 0; +} + +int board_mmc_init(bd_t *bd) +{ + struct mmc *mmc; + + sd_dma_buffer = malloc(512); + if (!sd_dma_buffer) { + return -ENOMEM; + } + + mmc = malloc(sizeof(struct mmc)); + if (!mmc) { + return -ENOMEM; + } + sprintf(mmc->name, "SDHCI"); + mmc->send_cmd = pele_sdh_request; + mmc->set_ios = pele_sdh_set_ios; + mmc->init = pele_sdh_init; + + mmc->host_caps = MMC_MODE_4BIT; + + mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; +#if 0 + mmc->f_max = get_sclk(); + mmc->f_min = mmc->f_max >> 9; +#endif + mmc->block_dev.part_type = PART_TYPE_DOS; + + mmc_register(mmc); + + return 0; +} + diff --git a/board/xilinx/dfe/sd_hardware.h b/board/xilinx/dfe/sd_hardware.h new file mode 100644 index 00000000000..53f06228410 --- /dev/null +++ b/board/xilinx/dfe/sd_hardware.h @@ -0,0 +1,90 @@ + +#ifndef __SD_H__ +#define __SD_H__ + +/* + * Controller register and bit definitions + */ + +#define SD_DMA_ADDR_R 0x00 + +#define SD_BLOCK_SZ_R 0x04 + +#define SD_BLOCK_CNT_R 0x06 + +#define SD_ARG_R 0x08 + +#define SD_TRNS_MODE_R 0x0C +#define SD_TRNS_DMA 0x01 +#define SD_TRNS_BLK_CNT_EN 0x02 +#define SD_TRNS_ACMD12 0x04 +#define SD_TRNS_READ 0x10 +#define SD_TRNS_MULTI 0x20 + +#define SD_CMD_R 0x0E +#define SD_CMD_RESP_NONE 0x00 +#define SD_CMD_RESP_136 0x01 +#define SD_CMD_RESP_48 0x02 +#define SD_CMD_RESP_48_BUSY 0x03 +#define SD_CMD_CRC 0x08 +#define SD_CMD_INDEX 0x10 +#define SD_CMD_DATA 0x20 + +#define SD_RSP_R 0x10 + +#define SD_BUFF_R 0x20 + +#define SD_PRES_STATE_R 0x24 +#define SD_CMD_INHIBIT 0x00000001 +#define SD_DATA_INHIBIT 0x00000002 +#define SD_WRITE_ACTIVE 0x00000100 +#define SD_READ_ACTIVE 0x00000200 +#define SD_CARD_INS 0x00010000 + +#define SD_HOST_CTRL_R 0x28 + +#define SD_PWR_CTRL_R 0x29 +#define SD_POWER_ON 0x01 +#define SD_POWER_18 0x0A +#define SD_POWER_30 0x0C +#define SD_POWER_33 0x0E + +#define SD_BLCK_GAP_CTL_R 0x2A + +#define SD_WAKE_CTL_R 0x2B + +#define SD_CLK_CTL_R 0x2C +#define SD_DIV_SHIFT 8 +#define SD_CLK_SD_EN 0x0004 +#define SD_CLK_INT_STABLE 0x0002 +#define SD_CLK_INT_EN 0x0001 + +#define SD_TIMEOUT_CTL_R 0x2E + +#define SD_SOFT_RST_R 0x2F +#define SD_RST_ALL 0x01 +#define SD_RST_CMD 0x02 +#define SD_RST_DATA 0x04 + +#define SD_INT_STAT_R 0x30 +#define SD_INT_ENA_R 0x34 +#define SD_SIG_ENA_R 0x38 +#define SD_INT_CMD_CMPL 0x00000001 +#define SD_INT_TRNS_CMPL 0x00000002 +#define SD_INT_DMA 0x00000008 +#define SD_INT_ERROR 0x00008000 +#define SD_INT_ERR_CTIMEOUT 0x00010000 +#define SD_INT_ERR_CCRC 0x00020000 +#define SD_INT_ERR_CEB 0x00040000 +#define SD_INT_ERR_IDX 0x00080000 +#define SD_INT_ERR_DTIMEOUT 0x00100000 +#define SD_INT_ERR_DCRC 0x00200000 +#define SD_INT_ERR_DEB 0x00400000 +#define SD_INT_ERR_CLMT 0x00800000 +#define SD_INT_ERR_ACMD12 0x01000000 +#define SD_INT_ERR_ADMA 0x02000000 +#define SD_INT_ERR_TRESP 0x10000000 + +#define SD_CAPABILITIES_R 0x40 + +#endif diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 80cd9bff9bb..82c131f22c1 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -922,7 +922,10 @@ static int __def_mmc_init(bd_t *bis) } int cpu_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init"))); +/* The Xilinx toolchain doesn't properly override the weak symbol */ +#ifndef CONFIG_PELE int board_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init"))); +#endif void print_mmc_devices(char separator) { diff --git a/include/configs/xpele.h b/include/configs/xpele.h index 3c7879fcc49..6f5b3ae7e25 100644 --- a/include/configs/xpele.h +++ b/include/configs/xpele.h @@ -202,4 +202,14 @@ #endif #endif +/* Secure Digital */ +#define CONFIG_MMC 1 + +#ifdef CONFIG_MMC +#define CONFIG_GENERIC_MMC +#define CONFIG_CMD_MMC +#define CONFIG_CMD_FAT +#define CONFIG_DOS_PARTITION +#endif + #endif /* __CONFIG_H */ -- 2.47.3