Hi All, Any comment to this patch set, could it be merged in this open window?
Thanks, Lei On Thu, Jun 16, 2011 at 11:17 PM, Lei Wen <lei...@marvell.com> wrote: > Nowdays, there are plenty of mmc driver in uboot adopt the sd standard > host design, aka as sdhci. It is better to centralize the common logic > together to better maintenance. > > Signed-off-by: Lei Wen <lei...@marvell.com> > --- > drivers/mmc/Makefile | 1 + > drivers/mmc/sdhci.c | 433 > ++++++++++++++++++++++++++++++++++++++++++++++++++ > include/sdhci.h | 325 +++++++++++++++++++++++++++++++++++++ > 3 files changed, 759 insertions(+), 0 deletions(-) > create mode 100644 drivers/mmc/sdhci.c > create mode 100644 include/sdhci.h > > diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile > index a8fe17a..50b5117 100644 > --- a/drivers/mmc/Makefile > +++ b/drivers/mmc/Makefile > @@ -38,6 +38,7 @@ COBJS-$(CONFIG_OMAP3_MMC) += omap3_mmc.o > COBJS-$(CONFIG_OMAP_HSMMC) += omap_hsmmc.o > COBJS-$(CONFIG_PXA_MMC) += pxa_mmc.o > COBJS-$(CONFIG_S5P_MMC) += s5p_mmc.o > +COBJS-$(CONFIG_SDHCI) += sdhci.o > > COBJS := $(COBJS-y) > SRCS := $(COBJS:.o=.c) > diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c > new file mode 100644 > index 0000000..9ebd33d > --- /dev/null > +++ b/drivers/mmc/sdhci.c > @@ -0,0 +1,433 @@ > +/* > + * Copyright 2011, Marvell Semiconductor Inc. > + * Lei Wen <lei...@marvell.com> > + * > + * See file CREDITS for list of people who contributed to this > + * project. > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, > + * MA 02111-1307 USA > + * > + * Back ported to the 8xx platform (from the 8260 platform) by > + * murray.jen...@cmst.csiro.au, 27-Jan-01. > + */ > + > +#include <common.h> > +#include <malloc.h> > +#include <mmc.h> > +#include <sdhci.h> > + > +void *aligned_buffer; > + > +static void sdhci_reset(struct sdhci_host *host, u8 mask) > +{ > + unsigned long timeout; > + > + /* Wait max 100 ms */ > + timeout = 100; > + sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET); > + while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) { > + if (timeout == 0) { > + printf("Reset 0x%x never completed.\n", (int)mask); > + return; > + } > + timeout--; > + udelay(1000); > + } > +} > + > +static void sdhci_cmd_done(struct sdhci_host *host, struct mmc_cmd *cmd) > +{ > + int i; > + if (cmd->resp_type & MMC_RSP_136) { > + /* CRC is stripped so we need to do some shifting. */ > + for (i = 0; i < 4; i++) { > + cmd->response[i] = sdhci_readl(host, > + SDHCI_RESPONSE + (3-i)*4) << 8; > + if (i != 3) > + cmd->response[i] |= sdhci_readb(host, > + SDHCI_RESPONSE + (3-i)*4-1); > + } > + } else { > + cmd->response[0] = sdhci_readl(host, SDHCI_RESPONSE); > + } > +} > + > +static void sdhci_transfer_pio(struct sdhci_host *host, struct mmc_data > *data) > +{ > + int i; > + char *offs; > + for (i = 0; i < data->blocksize; i += 4) { > + offs = data->dest + i; > + if (data->flags == MMC_DATA_READ) > + *(u32 *)offs = sdhci_readl(host, SDHCI_BUFFER); > + else > + sdhci_writel(host, *(u32 *)offs, SDHCI_BUFFER); > + } > +} > + > +static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data > *data, > + unsigned int start_addr) > +{ > + unsigned int stat, rdy, mask, block = 0; > + > + rdy = SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL; > + mask = SDHCI_DATA_AVAILABLE | SDHCI_SPACE_AVAILABLE; > + do { > + stat = sdhci_readl(host, SDHCI_INT_STATUS); > + if (stat & SDHCI_INT_ERROR) { > + printf("Error detected in status(0x%X)!\n", stat); > + return -1; > + } > + if (stat & rdy) { > + if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & mask)) > + continue; > + sdhci_writel(host, rdy, SDHCI_INT_STATUS); > + sdhci_transfer_pio(host, data); > + data->dest += data->blocksize; > + if (++block >= data->blocks) > + break; > + } > +#ifdef CONFIG_MMC_SDMA > + if (stat & SDHCI_INT_DMA_END) { > + sdhci_writel(host, SDHCI_INT_DMA_END, > SDHCI_INT_STATUS); > + start_addr &= SDHCI_DEFAULT_BOUNDARY_SIZE - 1; > + start_addr += SDHCI_DEFAULT_BOUNDARY_SIZE; > + sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS); > + } > +#endif > + } while (!(stat & SDHCI_INT_DATA_END)); > + return 0; > +} > + > +int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, > + struct mmc_data *data) > +{ > + struct sdhci_host *host = (struct sdhci_host *)mmc->priv; > + unsigned int stat = 0; > + int ret = 0; > + int trans_bytes = 0, is_aligned = 1; > + u32 mask, flags, mode; > + unsigned int timeout, start_addr = 0; > + > + /* Wait max 10 ms */ > + timeout = 10; > + > + sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS); > + mask = SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT; > + > + /* We shouldn't wait for data inihibit for stop commands, even > + though they might use busy signaling */ > + if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) > + mask &= ~SDHCI_DATA_INHIBIT; > + > + while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) { > + if (timeout == 0) { > + printf("Controller never released inhibit bit(s).\n"); > + return COMM_ERR; > + } > + timeout--; > + udelay(1000); > + } > + > + mask = SDHCI_INT_RESPONSE; > + if (!(cmd->resp_type & MMC_RSP_PRESENT)) > + flags = SDHCI_CMD_RESP_NONE; > + else if (cmd->resp_type & MMC_RSP_136) > + flags = SDHCI_CMD_RESP_LONG; > + else if (cmd->resp_type & MMC_RSP_BUSY) { > + flags = SDHCI_CMD_RESP_SHORT_BUSY; > + mask |= SDHCI_INT_DATA_END; > + } else > + flags = SDHCI_CMD_RESP_SHORT; > + > + if (cmd->resp_type & MMC_RSP_CRC) > + flags |= SDHCI_CMD_CRC; > + if (cmd->resp_type & MMC_RSP_OPCODE) > + flags |= SDHCI_CMD_INDEX; > + if (data) > + flags |= SDHCI_CMD_DATA; > + > + /*Set Transfer mode regarding to data flag*/ > + if (data != 0) { > + sdhci_writeb(host, 0xe, SDHCI_TIMEOUT_CONTROL); > + mode = SDHCI_TRNS_BLK_CNT_EN; > + trans_bytes = data->blocks * data->blocksize; > + if (data->blocks > 1) > + mode |= SDHCI_TRNS_MULTI; > + > + if (data->flags == MMC_DATA_READ) > + mode |= SDHCI_TRNS_READ; > + > +#ifdef CONFIG_MMC_SDMA > + if (data->flags == MMC_DATA_READ) > + start_addr = (unsigned int)data->dest; > + else > + start_addr = (unsigned int)data->src; > + if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && > + (start_addr & 0x7) != 0x0) { > + is_aligned = 0; > + start_addr = (unsigned int)aligned_buffer; > + if (data->flags != MMC_DATA_READ) > + memcpy(aligned_buffer, data->src, > trans_bytes); > + } > + > + sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS); > + mode |= SDHCI_TRNS_DMA; > +#endif > + sdhci_writew(host, > SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG, > + data->blocksize), > + SDHCI_BLOCK_SIZE); > + sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT); > + sdhci_writew(host, mode, SDHCI_TRANSFER_MODE); > + } > + > + sdhci_writel(host, cmd->cmdarg, SDHCI_ARGUMENT); > +#ifdef CONFIG_MMC_SDMA > + flush_cache(0, ~0); > +#endif > + sdhci_writew(host, SDHCI_MAKE_CMD(cmd->cmdidx, flags), SDHCI_COMMAND); > + do { > + stat = sdhci_readl(host, SDHCI_INT_STATUS); > + if (stat & SDHCI_INT_ERROR) > + break; > + } while ((stat & mask) != mask); > + > + if ((stat & (SDHCI_INT_ERROR | mask)) == mask) { > + sdhci_cmd_done(host, cmd); > + sdhci_writel(host, mask, SDHCI_INT_STATUS); > + } else > + ret = -1; > + > + if (!ret && data) > + ret = sdhci_transfer_data(host, data, start_addr); > + > + stat = sdhci_readl(host, SDHCI_INT_STATUS); > + sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_STATUS); > + if (!ret) { > + if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && > + !is_aligned && (data->flags == MMC_DATA_READ)) > + memcpy(data->dest, aligned_buffer, trans_bytes); > + return 0; > + } > + > + sdhci_reset(host, SDHCI_RESET_CMD); > + sdhci_reset(host, SDHCI_RESET_DATA); > + if (stat & SDHCI_INT_TIMEOUT) > + return TIMEOUT; > + else > + return COMM_ERR; > +} > + > +static int sdhci_set_clock(struct mmc *mmc, unsigned int clock) > +{ > + struct sdhci_host *host = (struct sdhci_host *)mmc->priv; > + unsigned int div, clk, timeout; > + > + sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); > + > + if (clock == 0) > + return 0; > + > + if (host->version >= SDHCI_SPEC_300) { > + /* Version 3.00 divisors must be a multiple of 2. */ > + if (mmc->f_max <= clock) > + div = 1; > + else { > + for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) > { > + if ((mmc->f_max / div) <= clock) > + break; > + } > + } > + } else { > + /* Version 2.00 divisors must be a power of 2. */ > + for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) { > + if ((mmc->f_max / div) <= clock) > + break; > + } > + } > + div >>= 1; > + > + clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT; > + clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) > + << SDHCI_DIVIDER_HI_SHIFT; > + clk |= SDHCI_CLOCK_INT_EN; > + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); > + > + /* Wait max 20 ms */ > + timeout = 20; > + while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) > + & SDHCI_CLOCK_INT_STABLE)) { > + if (timeout == 0) { > + printf("Internal clock never stabilised.\n"); > + return -1; > + } > + timeout--; > + udelay(1000); > + } > + > + clk |= SDHCI_CLOCK_CARD_EN; > + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); > + return 0; > +} > + > +static void sdhci_set_power(struct sdhci_host *host, unsigned short power) > +{ > + u8 pwr = 0; > + > + if (power != (unsigned short)-1) { > + switch (1 << power) { > + case MMC_VDD_165_195: > + pwr = SDHCI_POWER_180; > + break; > + case MMC_VDD_29_30: > + case MMC_VDD_30_31: > + pwr = SDHCI_POWER_300; > + break; > + case MMC_VDD_32_33: > + case MMC_VDD_33_34: > + pwr = SDHCI_POWER_330; > + break; > + } > + } > + > + if (pwr == 0) { > + sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); > + return; > + } > + > + pwr |= SDHCI_POWER_ON; > + > + sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); > +} > + > +void sdhci_set_ios(struct mmc *mmc) > +{ > + u32 ctrl; > + struct sdhci_host *host = (struct sdhci_host *)mmc->priv; > + > + if (mmc->clock != host->clock) > + sdhci_set_clock(mmc, mmc->clock); > + > + /* Set bus width */ > + ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); > + if (mmc->bus_width == 8) { > + ctrl &= ~SDHCI_CTRL_4BITBUS; > + if (host->version >= SDHCI_SPEC_300) > + ctrl |= SDHCI_CTRL_8BITBUS; > + } else { > + if (host->version >= SDHCI_SPEC_300) > + ctrl &= ~SDHCI_CTRL_8BITBUS; > + if (mmc->bus_width == 4) > + ctrl |= SDHCI_CTRL_4BITBUS; > + else > + ctrl &= ~SDHCI_CTRL_4BITBUS; > + } > + > + if (mmc->clock > 26000000) > + ctrl |= SDHCI_CTRL_HISPD; > + else > + ctrl &= ~SDHCI_CTRL_HISPD; > + > + sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); > +} > + > +int sdhci_init(struct mmc *mmc) > +{ > + struct sdhci_host *host = (struct sdhci_host *)mmc->priv; > + > + if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && !aligned_buffer) { > + aligned_buffer = memalign(8, 512*1024); > + if (!aligned_buffer) { > + printf("Aligned buffer alloc failed!!!"); > + return -1; > + } > + } > + > + /* Eable all state */ > + sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_ENABLE); > + sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_SIGNAL_ENABLE); > + > + sdhci_set_power(host, fls(mmc->voltages) - 1); > + > + return 0; > +} > + > +int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) > +{ > + struct mmc *mmc; > + unsigned int caps; > + > + mmc = malloc(sizeof(struct mmc)); > + if (!mmc) { > + printf("mmc malloc fail!\n"); > + return -1; > + } > + > + mmc->priv = host; > + > + sprintf(mmc->name, "%s", host->name); > + mmc->send_cmd = sdhci_send_command; > + mmc->set_ios = sdhci_set_ios; > + mmc->init = sdhci_init; > + > + caps = sdhci_readl(host, SDHCI_CAPABILITIES); > +#ifdef CONFIG_MMC_SDMA > + if (!(caps & SDHCI_CAN_DO_SDMA)) { > + printf("Your controller don't support sdma!!\n"); > + return -1; > + } > +#endif > + > + if (max_clk) > + mmc->f_max = max_clk; > + else { > + if (host->version >= SDHCI_SPEC_300) > + mmc->f_max = (caps & SDHCI_CLOCK_V3_BASE_MASK) > + >> SDHCI_CLOCK_BASE_SHIFT; > + else > + mmc->f_max = (caps & SDHCI_CLOCK_BASE_MASK) > + >> SDHCI_CLOCK_BASE_SHIFT; > + mmc->f_max *= 1000000; > + } > + if (mmc->f_max == 0) { > + printf("Hardware doesn't specify base clock frequency\n"); > + return -1; > + } > + if (min_clk) > + mmc->f_min = min_clk; > + else { > + if (host->version >= SDHCI_SPEC_300) > + mmc->f_min = mmc->f_max / SDHCI_MAX_DIV_SPEC_300; > + else > + mmc->f_min = mmc->f_max / SDHCI_MAX_DIV_SPEC_200; > + } > + > + mmc->voltages = 0; > + if (caps & SDHCI_CAN_VDD_330) > + mmc->voltages |= MMC_VDD_32_33 | MMC_VDD_33_34; > + if (caps & SDHCI_CAN_VDD_300) > + mmc->voltages |= MMC_VDD_29_30 | MMC_VDD_30_31; > + if (caps & SDHCI_CAN_VDD_180) > + mmc->voltages |= MMC_VDD_165_195; > + mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT; > + if (caps & SDHCI_CAN_DO_8BIT) > + mmc->host_caps |= MMC_MODE_8BIT; > + > + sdhci_reset(host, SDHCI_RESET_ALL); > + mmc_register(mmc); > + > + return 0; > +} > diff --git a/include/sdhci.h b/include/sdhci.h > new file mode 100644 > index 0000000..6d52ce9 > --- /dev/null > +++ b/include/sdhci.h > @@ -0,0 +1,325 @@ > +/* > + * Copyright 2011, Marvell Semiconductor Inc. > + * Lei Wen <lei...@marvell.com> > + * > + * See file CREDITS for list of people who contributed to this > + * project. > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, > + * MA 02111-1307 USA > + * > + * Back ported to the 8xx platform (from the 8260 platform) by > + * murray.jen...@cmst.csiro.au, 27-Jan-01. > + */ > +#ifndef __SDHCI_HW_H > +#define __SDHCI_HW_H > + > +#include <asm/io.h> > +/* > + * Controller registers > + */ > + > +#define SDHCI_DMA_ADDRESS 0x00 > + > +#define SDHCI_BLOCK_SIZE 0x04 > +#define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF)) > + > +#define SDHCI_BLOCK_COUNT 0x06 > + > +#define SDHCI_ARGUMENT 0x08 > + > +#define SDHCI_TRANSFER_MODE 0x0C > +#define SDHCI_TRNS_DMA 0x01 > +#define SDHCI_TRNS_BLK_CNT_EN 0x02 > +#define SDHCI_TRNS_ACMD12 0x04 > +#define SDHCI_TRNS_READ 0x10 > +#define SDHCI_TRNS_MULTI 0x20 > + > +#define SDHCI_COMMAND 0x0E > +#define SDHCI_CMD_RESP_MASK 0x03 > +#define SDHCI_CMD_CRC 0x08 > +#define SDHCI_CMD_INDEX 0x10 > +#define SDHCI_CMD_DATA 0x20 > +#define SDHCI_CMD_ABORTCMD 0xC0 > + > +#define SDHCI_CMD_RESP_NONE 0x00 > +#define SDHCI_CMD_RESP_LONG 0x01 > +#define SDHCI_CMD_RESP_SHORT 0x02 > +#define SDHCI_CMD_RESP_SHORT_BUSY 0x03 > + > +#define SDHCI_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff)) > +#define SDHCI_GET_CMD(c) ((c>>8) & 0x3f) > + > +#define SDHCI_RESPONSE 0x10 > + > +#define SDHCI_BUFFER 0x20 > + > +#define SDHCI_PRESENT_STATE 0x24 > +#define SDHCI_CMD_INHIBIT 0x00000001 > +#define SDHCI_DATA_INHIBIT 0x00000002 > +#define SDHCI_DOING_WRITE 0x00000100 > +#define SDHCI_DOING_READ 0x00000200 > +#define SDHCI_SPACE_AVAILABLE 0x00000400 > +#define SDHCI_DATA_AVAILABLE 0x00000800 > +#define SDHCI_CARD_PRESENT 0x00010000 > +#define SDHCI_WRITE_PROTECT 0x00080000 > + > +#define SDHCI_HOST_CONTROL 0x28 > +#define SDHCI_CTRL_LED 0x01 > +#define SDHCI_CTRL_4BITBUS 0x02 > +#define SDHCI_CTRL_HISPD 0x04 > +#define SDHCI_CTRL_DMA_MASK 0x18 > +#define SDHCI_CTRL_SDMA 0x00 > +#define SDHCI_CTRL_ADMA1 0x08 > +#define SDHCI_CTRL_ADMA32 0x10 > +#define SDHCI_CTRL_ADMA64 0x18 > +#define SDHCI_CTRL_8BITBUS 0x20 > + > +#define SDHCI_POWER_CONTROL 0x29 > +#define SDHCI_POWER_ON 0x01 > +#define SDHCI_POWER_180 0x0A > +#define SDHCI_POWER_300 0x0C > +#define SDHCI_POWER_330 0x0E > + > +#define SDHCI_BLOCK_GAP_CONTROL 0x2A > + > +#define SDHCI_WAKE_UP_CONTROL 0x2B > +#define SDHCI_WAKE_ON_INT 0x01 > +#define SDHCI_WAKE_ON_INSERT 0x02 > +#define SDHCI_WAKE_ON_REMOVE 0x04 > + > +#define SDHCI_CLOCK_CONTROL 0x2C > +#define SDHCI_DIVIDER_SHIFT 8 > +#define SDHCI_DIVIDER_HI_SHIFT 6 > +#define SDHCI_DIV_MASK 0xFF > +#define SDHCI_DIV_MASK_LEN 8 > +#define SDHCI_DIV_HI_MASK 0x300 > +#define SDHCI_CLOCK_CARD_EN 0x0004 > +#define SDHCI_CLOCK_INT_STABLE 0x0002 > +#define SDHCI_CLOCK_INT_EN 0x0001 > + > +#define SDHCI_TIMEOUT_CONTROL 0x2E > + > +#define SDHCI_SOFTWARE_RESET 0x2F > +#define SDHCI_RESET_ALL 0x01 > +#define SDHCI_RESET_CMD 0x02 > +#define SDHCI_RESET_DATA 0x04 > + > +#define SDHCI_INT_STATUS 0x30 > +#define SDHCI_INT_ENABLE 0x34 > +#define SDHCI_SIGNAL_ENABLE 0x38 > +#define SDHCI_INT_RESPONSE 0x00000001 > +#define SDHCI_INT_DATA_END 0x00000002 > +#define SDHCI_INT_DMA_END 0x00000008 > +#define SDHCI_INT_SPACE_AVAIL 0x00000010 > +#define SDHCI_INT_DATA_AVAIL 0x00000020 > +#define SDHCI_INT_CARD_INSERT 0x00000040 > +#define SDHCI_INT_CARD_REMOVE 0x00000080 > +#define SDHCI_INT_CARD_INT 0x00000100 > +#define SDHCI_INT_ERROR 0x00008000 > +#define SDHCI_INT_TIMEOUT 0x00010000 > +#define SDHCI_INT_CRC 0x00020000 > +#define SDHCI_INT_END_BIT 0x00040000 > +#define SDHCI_INT_INDEX 0x00080000 > +#define SDHCI_INT_DATA_TIMEOUT 0x00100000 > +#define SDHCI_INT_DATA_CRC 0x00200000 > +#define SDHCI_INT_DATA_END_BIT 0x00400000 > +#define SDHCI_INT_BUS_POWER 0x00800000 > +#define SDHCI_INT_ACMD12ERR 0x01000000 > +#define SDHCI_INT_ADMA_ERROR 0x02000000 > + > +#define SDHCI_INT_NORMAL_MASK 0x00007FFF > +#define SDHCI_INT_ERROR_MASK 0xFFFF8000 > + > +#define SDHCI_INT_CMD_MASK (SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \ > + SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX) > +#define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \ > + SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \ > + SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \ > + SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR) > +#define SDHCI_INT_ALL_MASK ((unsigned int)-1) > + > +#define SDHCI_ACMD12_ERR 0x3C > + > +/* 3E-3F reserved */ > + > +#define SDHCI_CAPABILITIES 0x40 > +#define SDHCI_TIMEOUT_CLK_MASK 0x0000003F > +#define SDHCI_TIMEOUT_CLK_SHIFT 0 > +#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080 > +#define SDHCI_CLOCK_BASE_MASK 0x00003F00 > +#define SDHCI_CLOCK_V3_BASE_MASK 0x0000FF00 > +#define SDHCI_CLOCK_BASE_SHIFT 8 > +#define SDHCI_MAX_BLOCK_MASK 0x00030000 > +#define SDHCI_MAX_BLOCK_SHIFT 16 > +#define SDHCI_CAN_DO_8BIT 0x00040000 > +#define SDHCI_CAN_DO_ADMA2 0x00080000 > +#define SDHCI_CAN_DO_ADMA1 0x00100000 > +#define SDHCI_CAN_DO_HISPD 0x00200000 > +#define SDHCI_CAN_DO_SDMA 0x00400000 > +#define SDHCI_CAN_VDD_330 0x01000000 > +#define SDHCI_CAN_VDD_300 0x02000000 > +#define SDHCI_CAN_VDD_180 0x04000000 > +#define SDHCI_CAN_64BIT 0x10000000 > + > +#define SDHCI_CAPABILITIES_1 0x44 > + > +#define SDHCI_MAX_CURRENT 0x48 > + > +/* 4C-4F reserved for more max current */ > + > +#define SDHCI_SET_ACMD12_ERROR 0x50 > +#define SDHCI_SET_INT_ERROR 0x52 > + > +#define SDHCI_ADMA_ERROR 0x54 > + > +/* 55-57 reserved */ > + > +#define SDHCI_ADMA_ADDRESS 0x58 > + > +/* 60-FB reserved */ > + > +#define SDHCI_SLOT_INT_STATUS 0xFC > + > +#define SDHCI_HOST_VERSION 0xFE > +#define SDHCI_VENDOR_VER_MASK 0xFF00 > +#define SDHCI_VENDOR_VER_SHIFT 8 > +#define SDHCI_SPEC_VER_MASK 0x00FF > +#define SDHCI_SPEC_VER_SHIFT 0 > +#define SDHCI_SPEC_100 0 > +#define SDHCI_SPEC_200 1 > +#define SDHCI_SPEC_300 2 > + > +/* > + * End of controller registers. > + */ > + > +#define SDHCI_MAX_DIV_SPEC_200 256 > +#define SDHCI_MAX_DIV_SPEC_300 2046 > + > +/* > + * quirks > + */ > +#define SDHCI_QUIRK_32BIT_DMA_ADDR (1 << 0) > + > +/* > + * Host SDMA buffer boundary. Valid values from 4K to 512K in powers of 2. > + */ > +#define SDHCI_DEFAULT_BOUNDARY_SIZE (512 * 1024) > +#define SDHCI_DEFAULT_BOUNDARY_ARG (7) > +struct sdhci_ops { > +#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS > + u32 (*read_l)(struct sdhci_host *host, int reg); > + u16 (*read_w)(struct sdhci_host *host, int reg); > + u8 (*read_b)(struct sdhci_host *host, int reg); > + void (*write_l)(struct sdhci_host *host, u32 val, int reg); > + void (*write_w)(struct sdhci_host *host, u16 val, int reg); > + void (*write_b)(struct sdhci_host *host, u8 val, int reg); > +#endif > +}; > + > +struct sdhci_host { > + char *name; > + void *ioaddr; > + unsigned int quirks; > + unsigned int version; > + unsigned int clock; > + const struct sdhci_ops *ops; > +}; > + > +#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS > + > +static inline void sdhci_writel(struct sdhci_host *host, u32 val, int reg) > +{ > + if (unlikely(host->ops->write_l)) > + host->ops->write_l(host, val, reg); > + else > + writel(val, host->ioaddr + reg); > +} > + > +static inline void sdhci_writew(struct sdhci_host *host, u16 val, int reg) > +{ > + if (unlikely(host->ops->write_w)) > + host->ops->write_w(host, val, reg); > + else > + writew(val, host->ioaddr + reg); > +} > + > +static inline void sdhci_writeb(struct sdhci_host *host, u8 val, int reg) > +{ > + if (unlikely(host->ops->write_b)) > + host->ops->write_b(host, val, reg); > + else > + writeb(val, host->ioaddr + reg); > +} > + > +static inline u32 sdhci_readl(struct sdhci_host *host, int reg) > +{ > + if (unlikely(host->ops->read_l)) > + return host->ops->read_l(host, reg); > + else > + return readl(host->ioaddr + reg); > +} > + > +static inline u16 sdhci_readw(struct sdhci_host *host, int reg) > +{ > + if (unlikely(host->ops->read_w)) > + return host->ops->read_w(host, reg); > + else > + return readw(host->ioaddr + reg); > +} > + > +static inline u8 sdhci_readb(struct sdhci_host *host, int reg) > +{ > + if (unlikely(host->ops->read_b)) > + return host->ops->read_b(host, reg); > + else > + return readb(host->ioaddr + reg); > +} > + > +#else > + > +static inline void sdhci_writel(struct sdhci_host *host, u32 val, int reg) > +{ > + writel(val, host->ioaddr + reg); > +} > + > +static inline void sdhci_writew(struct sdhci_host *host, u16 val, int reg) > +{ > + writew(val, host->ioaddr + reg); > +} > + > +static inline void sdhci_writeb(struct sdhci_host *host, u8 val, int reg) > +{ > + writeb(val, host->ioaddr + reg); > +} > +static inline u32 sdhci_readl(struct sdhci_host *host, int reg) > +{ > + return readl(host->ioaddr + reg); > +} > + > +static inline u16 sdhci_readw(struct sdhci_host *host, int reg) > +{ > + return readw(host->ioaddr + reg); > +} > + > +static inline u8 sdhci_readb(struct sdhci_host *host, int reg) > +{ > + return readb(host->ioaddr + reg); > +} > +#endif > + > +int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk); > +#endif /* __SDHCI_HW_H */ > -- > 1.7.0.4 > > _______________________________________________ > U-Boot mailing list > U-Boot@lists.denx.de > http://lists.denx.de/mailman/listinfo/u-boot > _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot