[U-Boot] [PATCH 0/5] Common AHCI and SDHCI drivers

From: Rob Herring rob.herring@calxeda.com
This patch series enables common SDHCI and AHCI drivers for other platforms to use.
The AHCI driver is modified to support non-PCI versions of the controller.
The Samsung s5p mmc driver appears to be the cleanest implementation of an SDHCI controller based on reviewing various Linux SDHCI drivers. The FSL ESDHCI controller is also, but has quite a few quirks. IIRC, the omap HSMMC block is also based on SDHCI.
Rob
Rob Herring (5): mmc: copy s5p to sdhci mmc: sdhci: rework Samsung specfic code mmc: sdhci: exit cmd on error status scsi/ahci: ata id little endian fix scsi/ahci: add support for non-PCI controllers
arch/arm/include/asm/arch-s5pc1xx/mmc.h | 72 ---- arch/arm/include/asm/arch-s5pc2xx/mmc.h | 72 ---- board/samsung/goni/goni.c | 4 +- board/samsung/universal_c210/universal.c | 6 +- common/cmd_scsi.c | 6 +- drivers/block/ahci.c | 64 ++++- drivers/mmc/Makefile | 3 +- drivers/mmc/s5p_mmc.c | 478 --------------------------- drivers/mmc/sdhci.c | 527 ++++++++++++++++++++++++++++++ include/sdhci.h | 18 + 10 files changed, 613 insertions(+), 637 deletions(-) delete mode 100644 arch/arm/include/asm/arch-s5pc1xx/mmc.h delete mode 100644 arch/arm/include/asm/arch-s5pc2xx/mmc.h delete mode 100644 drivers/mmc/s5p_mmc.c create mode 100644 drivers/mmc/sdhci.c create mode 100644 include/sdhci.h

From: Rob Herring rob.herring@calxeda.com
The s5p mmc controller is a standard SDHCI controller with a few extra registers. So rename it to reflect that and so other platforms can use it.
Signed-off-by: Rob Herring rob.herring@calxeda.com --- drivers/mmc/Makefile | 3 +- drivers/mmc/s5p_mmc.c | 478 ------------------------------------------------- drivers/mmc/sdhci.c | 478 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 480 insertions(+), 479 deletions(-) delete mode 100644 drivers/mmc/s5p_mmc.c create mode 100644 drivers/mmc/sdhci.c
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index a8fe17a..a9f6921 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -37,7 +37,8 @@ COBJS-$(CONFIG_MXC_MMC) += mxcmmc.o 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_S5P_MMC) += sdhci.o +COBJS-$(CONFIG_SDHCI) += sdhci.o
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/mmc/s5p_mmc.c b/drivers/mmc/s5p_mmc.c deleted file mode 100644 index 668c28b..0000000 --- a/drivers/mmc/s5p_mmc.c +++ /dev/null @@ -1,478 +0,0 @@ -/* - * (C) Copyright 2009 SAMSUNG Electronics - * Minkyu Kang mk7.kang@samsung.com - * Jaehoon Chung jh80.chung@samsung.com - * - * 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 - */ - -#include <common.h> -#include <mmc.h> -#include <asm/io.h> -#include <asm/arch/mmc.h> - -/* support 4 mmc hosts */ -struct mmc mmc_dev[4]; -struct mmc_host mmc_host[4]; - -static inline struct s5p_mmc *s5p_get_base_mmc(int dev_index) -{ - unsigned long offset = dev_index * sizeof(struct s5p_mmc); - return (struct s5p_mmc *)(samsung_get_base_mmc() + offset); -} - -static void mmc_prepare_data(struct mmc_host *host, struct mmc_data *data) -{ - unsigned char ctrl; - - debug("data->dest: %08x\n", (u32)data->dest); - writel((u32)data->dest, &host->reg->sysad); - /* - * DMASEL[4:3] - * 00 = Selects SDMA - * 01 = Reserved - * 10 = Selects 32-bit Address ADMA2 - * 11 = Selects 64-bit Address ADMA2 - */ - ctrl = readb(&host->reg->hostctl); - ctrl &= ~(3 << 3); - writeb(ctrl, &host->reg->hostctl); - - /* We do not handle DMA boundaries, so set it to max (512 KiB) */ - writew((7 << 12) | (data->blocksize & 0xFFF), &host->reg->blksize); - writew(data->blocks, &host->reg->blkcnt); -} - -static void mmc_set_transfer_mode(struct mmc_host *host, struct mmc_data *data) -{ - unsigned short mode; - - /* - * TRNMOD - * MUL1SIN0[5] : Multi/Single Block Select - * RD1WT0[4] : Data Transfer Direction Select - * 1 = read - * 0 = write - * ENACMD12[2] : Auto CMD12 Enable - * ENBLKCNT[1] : Block Count Enable - * ENDMA[0] : DMA Enable - */ - mode = (1 << 1) | (1 << 0); - if (data->blocks > 1) - mode |= (1 << 5); - if (data->flags & MMC_DATA_READ) - mode |= (1 << 4); - - writew(mode, &host->reg->trnmod); -} - -static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, - struct mmc_data *data) -{ - struct mmc_host *host = (struct mmc_host *)mmc->priv; - int flags, i; - unsigned int timeout; - unsigned int mask; - unsigned int retry = 0x100000; - - /* Wait max 10 ms */ - timeout = 10; - - /* - * PRNSTS - * CMDINHDAT[1] : Command Inhibit (DAT) - * CMDINHCMD[0] : Command Inhibit (CMD) - */ - mask = (1 << 0); - if ((data != NULL) || (cmd->resp_type & MMC_RSP_BUSY)) - mask |= (1 << 1); - - /* - * We shouldn't wait for data inihibit for stop commands, even - * though they might use busy signaling - */ - if (data) - mask &= ~(1 << 1); - - while (readl(&host->reg->prnsts) & mask) { - if (timeout == 0) { - printf("%s: timeout error\n", __func__); - return -1; - } - timeout--; - udelay(1000); - } - - if (data) - mmc_prepare_data(host, data); - - debug("cmd->arg: %08x\n", cmd->cmdarg); - writel(cmd->cmdarg, &host->reg->argument); - - if (data) - mmc_set_transfer_mode(host, data); - - if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY)) - return -1; - - /* - * CMDREG - * CMDIDX[13:8] : Command index - * DATAPRNT[5] : Data Present Select - * ENCMDIDX[4] : Command Index Check Enable - * ENCMDCRC[3] : Command CRC Check Enable - * RSPTYP[1:0] - * 00 = No Response - * 01 = Length 136 - * 10 = Length 48 - * 11 = Length 48 Check busy after response - */ - if (!(cmd->resp_type & MMC_RSP_PRESENT)) - flags = 0; - else if (cmd->resp_type & MMC_RSP_136) - flags = (1 << 0); - else if (cmd->resp_type & MMC_RSP_BUSY) - flags = (3 << 0); - else - flags = (2 << 0); - - if (cmd->resp_type & MMC_RSP_CRC) - flags |= (1 << 3); - if (cmd->resp_type & MMC_RSP_OPCODE) - flags |= (1 << 4); - if (data) - flags |= (1 << 5); - - debug("cmd: %d\n", cmd->cmdidx); - - writew((cmd->cmdidx << 8) | flags, &host->reg->cmdreg); - - for (i = 0; i < retry; i++) { - mask = readl(&host->reg->norintsts); - /* Command Complete */ - if (mask & (1 << 0)) { - if (!data) - writel(mask, &host->reg->norintsts); - break; - } - } - - if (i == retry) { - printf("%s: waiting for status update\n", __func__); - return TIMEOUT; - } - - if (mask & (1 << 16)) { - /* Timeout Error */ - debug("timeout: %08x cmd %d\n", mask, cmd->cmdidx); - return TIMEOUT; - } else if (mask & (1 << 15)) { - /* Error Interrupt */ - debug("error: %08x cmd %d\n", mask, cmd->cmdidx); - return -1; - } - - if (cmd->resp_type & MMC_RSP_PRESENT) { - if (cmd->resp_type & MMC_RSP_136) { - /* CRC is stripped so we need to do some shifting. */ - for (i = 0; i < 4; i++) { - unsigned int offset = - (unsigned int)(&host->reg->rspreg3 - i); - cmd->response[i] = readl(offset) << 8; - - if (i != 3) { - cmd->response[i] |= - readb(offset - 1); - } - debug("cmd->resp[%d]: %08x\n", - i, cmd->response[i]); - } - } else if (cmd->resp_type & MMC_RSP_BUSY) { - for (i = 0; i < retry; i++) { - /* PRNTDATA[23:20] : DAT[3:0] Line Signal */ - if (readl(&host->reg->prnsts) - & (1 << 20)) /* DAT[0] */ - break; - } - - if (i == retry) { - printf("%s: card is still busy\n", __func__); - return TIMEOUT; - } - - cmd->response[0] = readl(&host->reg->rspreg0); - debug("cmd->resp[0]: %08x\n", cmd->response[0]); - } else { - cmd->response[0] = readl(&host->reg->rspreg0); - debug("cmd->resp[0]: %08x\n", cmd->response[0]); - } - } - - if (data) { - while (1) { - mask = readl(&host->reg->norintsts); - - if (mask & (1 << 15)) { - /* Error Interrupt */ - writel(mask, &host->reg->norintsts); - printf("%s: error during transfer: 0x%08x\n", - __func__, mask); - return -1; - } else if (mask & (1 << 3)) { - /* DMA Interrupt */ - debug("DMA end\n"); - break; - } else if (mask & (1 << 1)) { - /* Transfer Complete */ - debug("r/w is done\n"); - break; - } - } - writel(mask, &host->reg->norintsts); - } - - udelay(1000); - return 0; -} - -static void mmc_change_clock(struct mmc_host *host, uint clock) -{ - int div; - unsigned short clk; - unsigned long timeout; - unsigned long ctrl2; - - /* - * SELBASECLK[5:4] - * 00/01 = HCLK - * 10 = EPLL - * 11 = XTI or XEXTCLK - */ - ctrl2 = readl(&host->reg->control2); - ctrl2 &= ~(3 << 4); - ctrl2 |= (2 << 4); - writel(ctrl2, &host->reg->control2); - - writew(0, &host->reg->clkcon); - - /* XXX: we assume that clock is between 40MHz and 50MHz */ - if (clock == 0) - goto out; - else if (clock <= 400000) - div = 0x100; - else if (clock <= 20000000) - div = 4; - else if (clock <= 26000000) - div = 2; - else - div = 1; - debug("div: %d\n", div); - - div >>= 1; - /* - * CLKCON - * SELFREQ[15:8] : base clock divied by value - * ENSDCLK[2] : SD Clock Enable - * STBLINTCLK[1] : Internal Clock Stable - * ENINTCLK[0] : Internal Clock Enable - */ - clk = (div << 8) | (1 << 0); - writew(clk, &host->reg->clkcon); - - /* Wait max 10 ms */ - timeout = 10; - while (!(readw(&host->reg->clkcon) & (1 << 1))) { - if (timeout == 0) { - printf("%s: timeout error\n", __func__); - return; - } - timeout--; - udelay(1000); - } - - clk |= (1 << 2); - writew(clk, &host->reg->clkcon); - -out: - host->clock = clock; -} - -static void mmc_set_ios(struct mmc *mmc) -{ - struct mmc_host *host = mmc->priv; - unsigned char ctrl; - unsigned long val; - - debug("bus_width: %x, clock: %d\n", mmc->bus_width, mmc->clock); - - /* - * SELCLKPADDS[17:16] - * 00 = 2mA - * 01 = 4mA - * 10 = 7mA - * 11 = 9mA - */ - writel(0x3 << 16, &host->reg->control4); - - val = readl(&host->reg->control2); - val &= (0x3 << 4); - - val |= (1 << 31) | /* write status clear async mode enable */ - (1 << 30) | /* command conflict mask enable */ - (1 << 14) | /* Feedback Clock Enable for Rx Clock */ - (1 << 8); /* SDCLK hold enable */ - - writel(val, &host->reg->control2); - - /* - * FCSEL1[15] FCSEL0[7] - * FCSel[1:0] : Rx Feedback Clock Delay Control - * Inverter delay means10ns delay if SDCLK 50MHz setting - * 01 = Delay1 (basic delay) - * 11 = Delay2 (basic delay + 2ns) - * 00 = Delay3 (inverter delay) - * 10 = Delay4 (inverter delay + 2ns) - */ - writel(0x8080, &host->reg->control3); - - mmc_change_clock(host, mmc->clock); - - ctrl = readb(&host->reg->hostctl); - - /* - * WIDE8[5] - * 0 = Depend on WIDE4 - * 1 = 8-bit mode - * WIDE4[1] - * 1 = 4-bit mode - * 0 = 1-bit mode - */ - if (mmc->bus_width == 8) - ctrl |= (1 << 5); - else if (mmc->bus_width == 4) - ctrl |= (1 << 1); - else - ctrl &= ~(1 << 1); - - /* - * OUTEDGEINV[2] - * 1 = Riging edge output - * 0 = Falling edge output - */ - ctrl &= ~(1 << 2); - - writeb(ctrl, &host->reg->hostctl); -} - -static void mmc_reset(struct mmc_host *host) -{ - unsigned int timeout; - - /* - * RSTALL[0] : Software reset for all - * 1 = reset - * 0 = work - */ - writeb((1 << 0), &host->reg->swrst); - - host->clock = 0; - - /* Wait max 100 ms */ - timeout = 100; - - /* hw clears the bit when it's done */ - while (readb(&host->reg->swrst) & (1 << 0)) { - if (timeout == 0) { - printf("%s: timeout error\n", __func__); - return; - } - timeout--; - udelay(1000); - } -} - -static int mmc_core_init(struct mmc *mmc) -{ - struct mmc_host *host = (struct mmc_host *)mmc->priv; - unsigned int mask; - - mmc_reset(host); - - host->version = readw(&host->reg->hcver); - - /* mask all */ - writel(0xffffffff, &host->reg->norintstsen); - writel(0xffffffff, &host->reg->norintsigen); - - writeb(0xe, &host->reg->timeoutcon); /* TMCLK * 2^27 */ - - /* - * NORMAL Interrupt Status Enable Register init - * [5] ENSTABUFRDRDY : Buffer Read Ready Status Enable - * [4] ENSTABUFWTRDY : Buffer write Ready Status Enable - * [1] ENSTASTANSCMPLT : Transfre Complete Status Enable - * [0] ENSTACMDCMPLT : Command Complete Status Enable - */ - mask = readl(&host->reg->norintstsen); - mask &= ~(0xffff); - mask |= (1 << 5) | (1 << 4) | (1 << 1) | (1 << 0); - writel(mask, &host->reg->norintstsen); - - /* - * NORMAL Interrupt Signal Enable Register init - * [1] ENSTACMDCMPLT : Transfer Complete Signal Enable - */ - mask = readl(&host->reg->norintsigen); - mask &= ~(0xffff); - mask |= (1 << 1); - writel(mask, &host->reg->norintsigen); - - return 0; -} - -static int s5p_mmc_initialize(int dev_index, int bus_width) -{ - struct mmc *mmc; - - mmc = &mmc_dev[dev_index]; - - sprintf(mmc->name, "SAMSUNG SD/MMC"); - mmc->priv = &mmc_host[dev_index]; - mmc->send_cmd = mmc_send_cmd; - mmc->set_ios = mmc_set_ios; - mmc->init = mmc_core_init; - - mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; - if (bus_width == 8) - mmc->host_caps = MMC_MODE_8BIT; - else - mmc->host_caps = MMC_MODE_4BIT; - mmc->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; - - mmc->f_min = 400000; - mmc->f_max = 52000000; - - mmc_host[dev_index].clock = 0; - mmc_host[dev_index].reg = s5p_get_base_mmc(dev_index); - mmc->m_bmax = 0; - mmc_register(mmc); - - return 0; -} - -int s5p_mmc_init(int dev_index, int bus_width) -{ - return s5p_mmc_initialize(dev_index, bus_width); -} diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c new file mode 100644 index 0000000..668c28b --- /dev/null +++ b/drivers/mmc/sdhci.c @@ -0,0 +1,478 @@ +/* + * (C) Copyright 2009 SAMSUNG Electronics + * Minkyu Kang mk7.kang@samsung.com + * Jaehoon Chung jh80.chung@samsung.com + * + * 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 + */ + +#include <common.h> +#include <mmc.h> +#include <asm/io.h> +#include <asm/arch/mmc.h> + +/* support 4 mmc hosts */ +struct mmc mmc_dev[4]; +struct mmc_host mmc_host[4]; + +static inline struct s5p_mmc *s5p_get_base_mmc(int dev_index) +{ + unsigned long offset = dev_index * sizeof(struct s5p_mmc); + return (struct s5p_mmc *)(samsung_get_base_mmc() + offset); +} + +static void mmc_prepare_data(struct mmc_host *host, struct mmc_data *data) +{ + unsigned char ctrl; + + debug("data->dest: %08x\n", (u32)data->dest); + writel((u32)data->dest, &host->reg->sysad); + /* + * DMASEL[4:3] + * 00 = Selects SDMA + * 01 = Reserved + * 10 = Selects 32-bit Address ADMA2 + * 11 = Selects 64-bit Address ADMA2 + */ + ctrl = readb(&host->reg->hostctl); + ctrl &= ~(3 << 3); + writeb(ctrl, &host->reg->hostctl); + + /* We do not handle DMA boundaries, so set it to max (512 KiB) */ + writew((7 << 12) | (data->blocksize & 0xFFF), &host->reg->blksize); + writew(data->blocks, &host->reg->blkcnt); +} + +static void mmc_set_transfer_mode(struct mmc_host *host, struct mmc_data *data) +{ + unsigned short mode; + + /* + * TRNMOD + * MUL1SIN0[5] : Multi/Single Block Select + * RD1WT0[4] : Data Transfer Direction Select + * 1 = read + * 0 = write + * ENACMD12[2] : Auto CMD12 Enable + * ENBLKCNT[1] : Block Count Enable + * ENDMA[0] : DMA Enable + */ + mode = (1 << 1) | (1 << 0); + if (data->blocks > 1) + mode |= (1 << 5); + if (data->flags & MMC_DATA_READ) + mode |= (1 << 4); + + writew(mode, &host->reg->trnmod); +} + +static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, + struct mmc_data *data) +{ + struct mmc_host *host = (struct mmc_host *)mmc->priv; + int flags, i; + unsigned int timeout; + unsigned int mask; + unsigned int retry = 0x100000; + + /* Wait max 10 ms */ + timeout = 10; + + /* + * PRNSTS + * CMDINHDAT[1] : Command Inhibit (DAT) + * CMDINHCMD[0] : Command Inhibit (CMD) + */ + mask = (1 << 0); + if ((data != NULL) || (cmd->resp_type & MMC_RSP_BUSY)) + mask |= (1 << 1); + + /* + * We shouldn't wait for data inihibit for stop commands, even + * though they might use busy signaling + */ + if (data) + mask &= ~(1 << 1); + + while (readl(&host->reg->prnsts) & mask) { + if (timeout == 0) { + printf("%s: timeout error\n", __func__); + return -1; + } + timeout--; + udelay(1000); + } + + if (data) + mmc_prepare_data(host, data); + + debug("cmd->arg: %08x\n", cmd->cmdarg); + writel(cmd->cmdarg, &host->reg->argument); + + if (data) + mmc_set_transfer_mode(host, data); + + if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY)) + return -1; + + /* + * CMDREG + * CMDIDX[13:8] : Command index + * DATAPRNT[5] : Data Present Select + * ENCMDIDX[4] : Command Index Check Enable + * ENCMDCRC[3] : Command CRC Check Enable + * RSPTYP[1:0] + * 00 = No Response + * 01 = Length 136 + * 10 = Length 48 + * 11 = Length 48 Check busy after response + */ + if (!(cmd->resp_type & MMC_RSP_PRESENT)) + flags = 0; + else if (cmd->resp_type & MMC_RSP_136) + flags = (1 << 0); + else if (cmd->resp_type & MMC_RSP_BUSY) + flags = (3 << 0); + else + flags = (2 << 0); + + if (cmd->resp_type & MMC_RSP_CRC) + flags |= (1 << 3); + if (cmd->resp_type & MMC_RSP_OPCODE) + flags |= (1 << 4); + if (data) + flags |= (1 << 5); + + debug("cmd: %d\n", cmd->cmdidx); + + writew((cmd->cmdidx << 8) | flags, &host->reg->cmdreg); + + for (i = 0; i < retry; i++) { + mask = readl(&host->reg->norintsts); + /* Command Complete */ + if (mask & (1 << 0)) { + if (!data) + writel(mask, &host->reg->norintsts); + break; + } + } + + if (i == retry) { + printf("%s: waiting for status update\n", __func__); + return TIMEOUT; + } + + if (mask & (1 << 16)) { + /* Timeout Error */ + debug("timeout: %08x cmd %d\n", mask, cmd->cmdidx); + return TIMEOUT; + } else if (mask & (1 << 15)) { + /* Error Interrupt */ + debug("error: %08x cmd %d\n", mask, cmd->cmdidx); + return -1; + } + + if (cmd->resp_type & MMC_RSP_PRESENT) { + if (cmd->resp_type & MMC_RSP_136) { + /* CRC is stripped so we need to do some shifting. */ + for (i = 0; i < 4; i++) { + unsigned int offset = + (unsigned int)(&host->reg->rspreg3 - i); + cmd->response[i] = readl(offset) << 8; + + if (i != 3) { + cmd->response[i] |= + readb(offset - 1); + } + debug("cmd->resp[%d]: %08x\n", + i, cmd->response[i]); + } + } else if (cmd->resp_type & MMC_RSP_BUSY) { + for (i = 0; i < retry; i++) { + /* PRNTDATA[23:20] : DAT[3:0] Line Signal */ + if (readl(&host->reg->prnsts) + & (1 << 20)) /* DAT[0] */ + break; + } + + if (i == retry) { + printf("%s: card is still busy\n", __func__); + return TIMEOUT; + } + + cmd->response[0] = readl(&host->reg->rspreg0); + debug("cmd->resp[0]: %08x\n", cmd->response[0]); + } else { + cmd->response[0] = readl(&host->reg->rspreg0); + debug("cmd->resp[0]: %08x\n", cmd->response[0]); + } + } + + if (data) { + while (1) { + mask = readl(&host->reg->norintsts); + + if (mask & (1 << 15)) { + /* Error Interrupt */ + writel(mask, &host->reg->norintsts); + printf("%s: error during transfer: 0x%08x\n", + __func__, mask); + return -1; + } else if (mask & (1 << 3)) { + /* DMA Interrupt */ + debug("DMA end\n"); + break; + } else if (mask & (1 << 1)) { + /* Transfer Complete */ + debug("r/w is done\n"); + break; + } + } + writel(mask, &host->reg->norintsts); + } + + udelay(1000); + return 0; +} + +static void mmc_change_clock(struct mmc_host *host, uint clock) +{ + int div; + unsigned short clk; + unsigned long timeout; + unsigned long ctrl2; + + /* + * SELBASECLK[5:4] + * 00/01 = HCLK + * 10 = EPLL + * 11 = XTI or XEXTCLK + */ + ctrl2 = readl(&host->reg->control2); + ctrl2 &= ~(3 << 4); + ctrl2 |= (2 << 4); + writel(ctrl2, &host->reg->control2); + + writew(0, &host->reg->clkcon); + + /* XXX: we assume that clock is between 40MHz and 50MHz */ + if (clock == 0) + goto out; + else if (clock <= 400000) + div = 0x100; + else if (clock <= 20000000) + div = 4; + else if (clock <= 26000000) + div = 2; + else + div = 1; + debug("div: %d\n", div); + + div >>= 1; + /* + * CLKCON + * SELFREQ[15:8] : base clock divied by value + * ENSDCLK[2] : SD Clock Enable + * STBLINTCLK[1] : Internal Clock Stable + * ENINTCLK[0] : Internal Clock Enable + */ + clk = (div << 8) | (1 << 0); + writew(clk, &host->reg->clkcon); + + /* Wait max 10 ms */ + timeout = 10; + while (!(readw(&host->reg->clkcon) & (1 << 1))) { + if (timeout == 0) { + printf("%s: timeout error\n", __func__); + return; + } + timeout--; + udelay(1000); + } + + clk |= (1 << 2); + writew(clk, &host->reg->clkcon); + +out: + host->clock = clock; +} + +static void mmc_set_ios(struct mmc *mmc) +{ + struct mmc_host *host = mmc->priv; + unsigned char ctrl; + unsigned long val; + + debug("bus_width: %x, clock: %d\n", mmc->bus_width, mmc->clock); + + /* + * SELCLKPADDS[17:16] + * 00 = 2mA + * 01 = 4mA + * 10 = 7mA + * 11 = 9mA + */ + writel(0x3 << 16, &host->reg->control4); + + val = readl(&host->reg->control2); + val &= (0x3 << 4); + + val |= (1 << 31) | /* write status clear async mode enable */ + (1 << 30) | /* command conflict mask enable */ + (1 << 14) | /* Feedback Clock Enable for Rx Clock */ + (1 << 8); /* SDCLK hold enable */ + + writel(val, &host->reg->control2); + + /* + * FCSEL1[15] FCSEL0[7] + * FCSel[1:0] : Rx Feedback Clock Delay Control + * Inverter delay means10ns delay if SDCLK 50MHz setting + * 01 = Delay1 (basic delay) + * 11 = Delay2 (basic delay + 2ns) + * 00 = Delay3 (inverter delay) + * 10 = Delay4 (inverter delay + 2ns) + */ + writel(0x8080, &host->reg->control3); + + mmc_change_clock(host, mmc->clock); + + ctrl = readb(&host->reg->hostctl); + + /* + * WIDE8[5] + * 0 = Depend on WIDE4 + * 1 = 8-bit mode + * WIDE4[1] + * 1 = 4-bit mode + * 0 = 1-bit mode + */ + if (mmc->bus_width == 8) + ctrl |= (1 << 5); + else if (mmc->bus_width == 4) + ctrl |= (1 << 1); + else + ctrl &= ~(1 << 1); + + /* + * OUTEDGEINV[2] + * 1 = Riging edge output + * 0 = Falling edge output + */ + ctrl &= ~(1 << 2); + + writeb(ctrl, &host->reg->hostctl); +} + +static void mmc_reset(struct mmc_host *host) +{ + unsigned int timeout; + + /* + * RSTALL[0] : Software reset for all + * 1 = reset + * 0 = work + */ + writeb((1 << 0), &host->reg->swrst); + + host->clock = 0; + + /* Wait max 100 ms */ + timeout = 100; + + /* hw clears the bit when it's done */ + while (readb(&host->reg->swrst) & (1 << 0)) { + if (timeout == 0) { + printf("%s: timeout error\n", __func__); + return; + } + timeout--; + udelay(1000); + } +} + +static int mmc_core_init(struct mmc *mmc) +{ + struct mmc_host *host = (struct mmc_host *)mmc->priv; + unsigned int mask; + + mmc_reset(host); + + host->version = readw(&host->reg->hcver); + + /* mask all */ + writel(0xffffffff, &host->reg->norintstsen); + writel(0xffffffff, &host->reg->norintsigen); + + writeb(0xe, &host->reg->timeoutcon); /* TMCLK * 2^27 */ + + /* + * NORMAL Interrupt Status Enable Register init + * [5] ENSTABUFRDRDY : Buffer Read Ready Status Enable + * [4] ENSTABUFWTRDY : Buffer write Ready Status Enable + * [1] ENSTASTANSCMPLT : Transfre Complete Status Enable + * [0] ENSTACMDCMPLT : Command Complete Status Enable + */ + mask = readl(&host->reg->norintstsen); + mask &= ~(0xffff); + mask |= (1 << 5) | (1 << 4) | (1 << 1) | (1 << 0); + writel(mask, &host->reg->norintstsen); + + /* + * NORMAL Interrupt Signal Enable Register init + * [1] ENSTACMDCMPLT : Transfer Complete Signal Enable + */ + mask = readl(&host->reg->norintsigen); + mask &= ~(0xffff); + mask |= (1 << 1); + writel(mask, &host->reg->norintsigen); + + return 0; +} + +static int s5p_mmc_initialize(int dev_index, int bus_width) +{ + struct mmc *mmc; + + mmc = &mmc_dev[dev_index]; + + sprintf(mmc->name, "SAMSUNG SD/MMC"); + mmc->priv = &mmc_host[dev_index]; + mmc->send_cmd = mmc_send_cmd; + mmc->set_ios = mmc_set_ios; + mmc->init = mmc_core_init; + + mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; + if (bus_width == 8) + mmc->host_caps = MMC_MODE_8BIT; + else + mmc->host_caps = MMC_MODE_4BIT; + mmc->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; + + mmc->f_min = 400000; + mmc->f_max = 52000000; + + mmc_host[dev_index].clock = 0; + mmc_host[dev_index].reg = s5p_get_base_mmc(dev_index); + mmc->m_bmax = 0; + mmc_register(mmc); + + return 0; +} + +int s5p_mmc_init(int dev_index, int bus_width) +{ + return s5p_mmc_initialize(dev_index, bus_width); +}

From: Rob Herring rob.herring@calxeda.com
Move the register definitions into the sdhci.c file. Set the base address from the board init code.
The Samsung SDHCI controller has extra registers. Make them conditional on CONFIG_MMC_S5P.
Signed-off-by: Rob Herring rob.herring@calxeda.com --- arch/arm/include/asm/arch-s5pc1xx/mmc.h | 72 --------------------------- arch/arm/include/asm/arch-s5pc2xx/mmc.h | 72 --------------------------- board/samsung/goni/goni.c | 4 +- board/samsung/universal_c210/universal.c | 6 +- drivers/mmc/sdhci.c | 79 +++++++++++++++++++++++------ include/sdhci.h | 18 +++++++ 6 files changed, 85 insertions(+), 166 deletions(-) delete mode 100644 arch/arm/include/asm/arch-s5pc1xx/mmc.h delete mode 100644 arch/arm/include/asm/arch-s5pc2xx/mmc.h create mode 100644 include/sdhci.h
diff --git a/arch/arm/include/asm/arch-s5pc1xx/mmc.h b/arch/arm/include/asm/arch-s5pc1xx/mmc.h deleted file mode 100644 index d458d3b..0000000 --- a/arch/arm/include/asm/arch-s5pc1xx/mmc.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * (C) Copyright 2009 SAMSUNG Electronics - * Minkyu Kang mk7.kang@samsung.com - * - * 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 - * - */ - -#ifndef __ASM_ARCH_MMC_H_ -#define __ASM_ARCH_MMC_H_ - -#ifndef __ASSEMBLY__ -struct s5p_mmc { - unsigned int sysad; - unsigned short blksize; - unsigned short blkcnt; - unsigned int argument; - unsigned short trnmod; - unsigned short cmdreg; - unsigned int rspreg0; - unsigned int rspreg1; - unsigned int rspreg2; - unsigned int rspreg3; - unsigned int bdata; - unsigned int prnsts; - unsigned char hostctl; - unsigned char pwrcon; - unsigned char blkgap; - unsigned char wakcon; - unsigned short clkcon; - unsigned char timeoutcon; - unsigned char swrst; - unsigned int norintsts; /* errintsts */ - unsigned int norintstsen; /* errintstsen */ - unsigned int norintsigen; /* errintsigen */ - unsigned short acmd12errsts; - unsigned char res1[2]; - unsigned int capareg; - unsigned char res2[4]; - unsigned int maxcurr; - unsigned char res3[0x34]; - unsigned int control2; - unsigned int control3; - unsigned char res4[4]; - unsigned int control4; - unsigned char res5[0x6e]; - unsigned short hcver; - unsigned char res6[0xFFF00]; -}; - -struct mmc_host { - struct s5p_mmc *reg; - unsigned int version; /* SDHCI spec. version */ - unsigned int clock; /* Current clock (MHz) */ -}; - -int s5p_mmc_init(int dev_index, int bus_width); - -#endif /* __ASSEMBLY__ */ -#endif diff --git a/arch/arm/include/asm/arch-s5pc2xx/mmc.h b/arch/arm/include/asm/arch-s5pc2xx/mmc.h deleted file mode 100644 index 04827ca..0000000 --- a/arch/arm/include/asm/arch-s5pc2xx/mmc.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * (C) Copyright 2009 SAMSUNG Electronics - * Minkyu Kang mk7.kang@samsung.com - * - * 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 - * - */ - -#ifndef __ASM_ARCH_MMC_H_ -#define __ASM_ARCH_MMC_H_ - -#ifndef __ASSEMBLY__ -struct s5p_mmc { - unsigned int sysad; - unsigned short blksize; - unsigned short blkcnt; - unsigned int argument; - unsigned short trnmod; - unsigned short cmdreg; - unsigned int rspreg0; - unsigned int rspreg1; - unsigned int rspreg2; - unsigned int rspreg3; - unsigned int bdata; - unsigned int prnsts; - unsigned char hostctl; - unsigned char pwrcon; - unsigned char blkgap; - unsigned char wakcon; - unsigned short clkcon; - unsigned char timeoutcon; - unsigned char swrst; - unsigned int norintsts; /* errintsts */ - unsigned int norintstsen; /* errintstsen */ - unsigned int norintsigen; /* errintsigen */ - unsigned short acmd12errsts; - unsigned char res1[2]; - unsigned int capareg; - unsigned char res2[4]; - unsigned int maxcurr; - unsigned char res3[0x34]; - unsigned int control2; - unsigned int control3; - unsigned char res4[4]; - unsigned int control4; - unsigned char res5[0x6e]; - unsigned short hcver; - unsigned char res6[0xFF00]; -}; - -struct mmc_host { - struct s5p_mmc *reg; - unsigned int version; /* SDHCI spec. version */ - unsigned int clock; /* Current clock (MHz) */ -}; - -int s5p_mmc_init(int dev_index, int bus_width); - -#endif /* __ASSEMBLY__ */ -#endif diff --git a/board/samsung/goni/goni.c b/board/samsung/goni/goni.c index 581935d..8e56f93 100644 --- a/board/samsung/goni/goni.c +++ b/board/samsung/goni/goni.c @@ -23,8 +23,8 @@ */
#include <common.h> +#include <sdhci.h> #include <asm/arch/gpio.h> -#include <asm/arch/mmc.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -93,6 +93,6 @@ int board_mmc_init(bd_t *bis) gpio_set_drv(&s5pc110_gpio->g0, i, GPIO_DRV_4X); }
- return s5p_mmc_init(0, 4); + return sdhci_mmc_init((void *)samsung_get_base_mmc(), 4); } #endif diff --git a/board/samsung/universal_c210/universal.c b/board/samsung/universal_c210/universal.c index b65bc6e..27cdce4 100644 --- a/board/samsung/universal_c210/universal.c +++ b/board/samsung/universal_c210/universal.c @@ -23,10 +23,10 @@ */
#include <common.h> +#include <sdhci.h> #include <asm/io.h> #include <asm/arch/adc.h> #include <asm/arch/gpio.h> -#include <asm/arch/mmc.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -217,7 +217,7 @@ int board_mmc_init(bd_t *bis) * mmc0 : eMMC (8-bit buswidth) * mmc2 : SD card (4-bit buswidth) */ - err = s5p_mmc_init(0, 8); + err = sdhci_mmc_init((void *)samsung_get_base_mmc(), 8);
/* * Check the T-flash detect pin @@ -241,7 +241,7 @@ int board_mmc_init(bd_t *bis) /* GPK2[0:6] drv 4x */ gpio_set_drv(&gpio2->k2, i, GPIO_DRV_4X); } - err = s5p_mmc_init(2, 4); + err = sdhci_mmc_init((void *)(samsung_get_base_mmc() + 0x20000), 4); }
return err; diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 668c28b..f184821 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -21,17 +21,54 @@ #include <common.h> #include <mmc.h> #include <asm/io.h> -#include <asm/arch/mmc.h> + +struct sdhci_mmc { + unsigned int sysad; + unsigned short blksize; + unsigned short blkcnt; + unsigned int argument; + unsigned short trnmod; + unsigned short cmdreg; + unsigned int rspreg0; + unsigned int rspreg1; + unsigned int rspreg2; + unsigned int rspreg3; + unsigned int bdata; + unsigned int prnsts; + unsigned char hostctl; + unsigned char pwrcon; + unsigned char blkgap; + unsigned char wakcon; + unsigned short clkcon; + unsigned char timeoutcon; + unsigned char swrst; + unsigned int norintsts; /* errintsts */ + unsigned int norintstsen; /* errintstsen */ + unsigned int norintsigen; /* errintsigen */ + unsigned short acmd12errsts; + unsigned char res1[2]; + unsigned int capareg; + unsigned char res2[4]; + unsigned int maxcurr; + unsigned char res3[0x34]; + unsigned int control2; + unsigned int control3; + unsigned char res4[4]; + unsigned int control4; + unsigned char res5[0x6e]; + unsigned short hcver; +}; + +struct mmc_host { + struct sdhci_mmc *reg; + unsigned int version; /* SDHCI spec. version */ + unsigned int clock; /* Current clock (MHz) */ +};
/* support 4 mmc hosts */ struct mmc mmc_dev[4]; struct mmc_host mmc_host[4]; - -static inline struct s5p_mmc *s5p_get_base_mmc(int dev_index) -{ - unsigned long offset = dev_index * sizeof(struct s5p_mmc); - return (struct s5p_mmc *)(samsung_get_base_mmc() + offset); -} +int dev_count;
static void mmc_prepare_data(struct mmc_host *host, struct mmc_data *data) { @@ -254,6 +291,7 @@ static void mmc_change_clock(struct mmc_host *host, uint clock) unsigned long timeout; unsigned long ctrl2;
+#ifdef CONFIG_S5P_MMC /* * SELBASECLK[5:4] * 00/01 = HCLK @@ -264,7 +302,7 @@ static void mmc_change_clock(struct mmc_host *host, uint clock) ctrl2 &= ~(3 << 4); ctrl2 |= (2 << 4); writel(ctrl2, &host->reg->control2); - +#endif writew(0, &host->reg->clkcon);
/* XXX: we assume that clock is between 40MHz and 50MHz */ @@ -317,6 +355,7 @@ static void mmc_set_ios(struct mmc *mmc)
debug("bus_width: %x, clock: %d\n", mmc->bus_width, mmc->clock);
+#ifdef CONFIG_S5P_MMC /* * SELCLKPADDS[17:16] * 00 = 2mA @@ -346,7 +385,7 @@ static void mmc_set_ios(struct mmc *mmc) * 10 = Delay4 (inverter delay + 2ns) */ writel(0x8080, &host->reg->control3); - +#endif mmc_change_clock(host, mmc->clock);
ctrl = readb(&host->reg->hostctl); @@ -442,14 +481,20 @@ static int mmc_core_init(struct mmc *mmc) return 0; }
-static int s5p_mmc_initialize(int dev_index, int bus_width) +static int sdhci_mmc_initialize(void *base, int bus_width) { struct mmc *mmc; + struct mmc_host *host; + + if (dev_count >= 4) + return -1;
- mmc = &mmc_dev[dev_index]; + mmc = &mmc_dev[dev_count]; + host = &mmc_host[dev_count]; + dev_count++;
- sprintf(mmc->name, "SAMSUNG SD/MMC"); - mmc->priv = &mmc_host[dev_index]; + sprintf(mmc->name, "SDHCI SD/MMC"); + mmc->priv = host; mmc->send_cmd = mmc_send_cmd; mmc->set_ios = mmc_set_ios; mmc->init = mmc_core_init; @@ -464,15 +509,15 @@ static int s5p_mmc_initialize(int dev_index, int bus_width) mmc->f_min = 400000; mmc->f_max = 52000000;
- mmc_host[dev_index].clock = 0; - mmc_host[dev_index].reg = s5p_get_base_mmc(dev_index); + host->clock = 0; + host->reg = base; mmc->m_bmax = 0; mmc_register(mmc);
return 0; }
-int s5p_mmc_init(int dev_index, int bus_width) +int sdhci_mmc_init(void *base, int bus_width) { - return s5p_mmc_initialize(dev_index, bus_width); + return sdhci_mmc_initialize(base, bus_width); } diff --git a/include/sdhci.h b/include/sdhci.h new file mode 100644 index 0000000..cc29415 --- /dev/null +++ b/include/sdhci.h @@ -0,0 +1,18 @@ +/* + * Copyright 2011 Calxeda, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see http://www.gnu.org/licenses/. + */ + +int sdhci_mmc_init(void *base, int bus_width); +

Dear Rob Herring,
In message 1306955427-18940-3-git-send-email-robherring2@gmail.com you wrote:
From: Rob Herring rob.herring@calxeda.com
Move the register definitions into the sdhci.c file. Set the base address from the board init code.
The Samsung SDHCI controller has extra registers. Make them conditional on CONFIG_MMC_S5P.
Signed-off-by: Rob Herring rob.herring@calxeda.com
Please run your patches through checkpatch before submittint. This should have shown you this:
...
err = s5p_mmc_init(2, 4);
err = sdhci_mmc_init((void *)(samsung_get_base_mmc() + 0x20000), 4);
Line too long.
Best regards,
Wolfgang Denk

From: Rob Herring rob.herring@calxeda.com
If the controller has an error condition, then stop polling for command complete and exit mmc_send_cmd.
Signed-off-by: Rob Herring rob.herring@calxeda.com --- drivers/mmc/sdhci.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index f184821..b116b8c 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -204,6 +204,10 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, writel(mask, &host->reg->norintsts); break; } + if (mask & (1 << 15)) { + writel(mask, &host->reg->norintsts); + return -1; + } }
if (i == retry) {

From: Rob Herring rob.herring@calxeda.com
The ata id string always needs swapping, not just on BE machines.
Signed-off-by: Rob Herring rob.herring@calxeda.com --- drivers/block/ahci.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index a3ca2dc..d431c5a 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -468,7 +468,7 @@ static char *ata_id_strcpy(u16 *target, u16 *src, int len) { int i; for (i = 0; i < len / 2; i++) - target[i] = le16_to_cpu(src[i]); + target[i] = swab16(src[i]); return (char *)target; }

From: Rob Herring rob.herring@calxeda.com
Add support for AHCI controllers that are not PCI based.
Signed-off-by: Rob Herring rob.herring@calxeda.com --- common/cmd_scsi.c | 6 +++- drivers/block/ahci.c | 62 +++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 60 insertions(+), 8 deletions(-)
diff --git a/common/cmd_scsi.c b/common/cmd_scsi.c index be4fe74..25a8299 100644 --- a/common/cmd_scsi.c +++ b/common/cmd_scsi.c @@ -47,7 +47,8 @@ #define SCSI_DEV_ID 0x5288
#else -#error no scsi device defined +#define SCSI_VEND_ID 0 +#define SCSI_DEV_ID 0 #endif
@@ -174,7 +175,7 @@ removable: scsi_curr_dev = -1; }
- +#ifdef CONFIG_PCI void scsi_init(void) { int busdevfunc; @@ -192,6 +193,7 @@ void scsi_init(void) scsi_low_level_init(busdevfunc); scsi_scan(1); } +#endif
block_dev_desc_t * scsi_get_dev(int dev) { diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index d431c5a..3a69fef 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -78,7 +78,9 @@ static int waiting_for_cmd_completed(volatile u8 *offset,
static int ahci_host_init(struct ahci_probe_ent *probe_ent) { +#ifdef CONFIG_PCI pci_dev_t pdev = probe_ent->dev; +#endif volatile u8 *mmio = (volatile u8 *)probe_ent->mmio_base; u32 tmp, cap_save; u16 tmp16; @@ -110,6 +112,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) writel(cap_save, mmio + HOST_CAP); writel_with_flush(0xf, mmio + HOST_PORTS_IMPL);
+#ifdef CONFIG_PCI pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor);
if (vendor == PCI_VENDOR_ID_INTEL) { @@ -118,7 +121,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) tmp16 |= 0xf; pci_write_config_word(pdev, 0x92, tmp16); } - +#endif probe_ent->cap = readl(mmio + HOST_CAP); probe_ent->port_map = readl(mmio + HOST_PORTS_IMPL); probe_ent->n_ports = (probe_ent->cap & 0x1f) + 1; @@ -183,11 +186,11 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL); tmp = readl(mmio + HOST_CTL); debug("HOST_CTL 0x%x\n", tmp); - +#ifdef CONFIG_PCI pci_read_config_word(pdev, PCI_COMMAND, &tmp16); tmp |= PCI_COMMAND_MASTER; pci_write_config_word(pdev, PCI_COMMAND, tmp16); - +#endif return 0; }
@@ -212,7 +215,7 @@ static void ahci_print_info(struct ahci_probe_ent *probe_ent) speed_s = "3"; else speed_s = "?"; - +#ifdef CONFIG_PCI pci_read_config_word(pdev, 0x0a, &cc); if (cc == 0x0101) scc_s = "IDE"; @@ -222,7 +225,9 @@ static void ahci_print_info(struct ahci_probe_ent *probe_ent) scc_s = "RAID"; else scc_s = "unknown"; - +#else + scc_s = "SATA"; +#endif printf("AHCI %02x%02x.%02x%02x " "%u slots %u ports %s Gbps 0x%x impl %s mode\n", (vers >> 24) & 0xff, @@ -249,6 +254,7 @@ static void ahci_print_info(struct ahci_probe_ent *probe_ent) cap & (1 << 13) ? "part " : ""); }
+#ifdef CONFIG_PCI static int ahci_init_one(pci_dev_t pdev) { u16 vendor; @@ -291,7 +297,7 @@ static int ahci_init_one(pci_dev_t pdev) err_out: return rc; } - +#endif
#define MAX_DATA_BYTE_COUNT (4*1024*1024)
@@ -667,7 +673,9 @@ void scsi_low_level_init(int busdevfunc) int i; u32 linkmap;
+#ifdef CONFIG_PCI ahci_init_one(busdevfunc); +#endif
linkmap = probe_ent->link_port_map;
@@ -682,6 +690,48 @@ void scsi_low_level_init(int busdevfunc) } }
+int ahci_init(u32 base) +{ + int i, rc = 0; + u32 linkmap; + + memset((void *)ataid, 0, sizeof(hd_driveid_t *) * AHCI_MAX_PORTS); + + probe_ent = malloc(sizeof(struct ahci_probe_ent)); + memset(probe_ent, 0, sizeof(struct ahci_probe_ent)); + + probe_ent->host_flags = ATA_FLAG_SATA + | ATA_FLAG_NO_LEGACY + | ATA_FLAG_MMIO + | ATA_FLAG_PIO_DMA + | ATA_FLAG_NO_ATAPI; + probe_ent->pio_mask = 0x1f; + probe_ent->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */ + + probe_ent->mmio_base = base; + + /* initialize adapter */ + rc = ahci_host_init(probe_ent); + if (rc) + goto err_out; + + ahci_print_info(probe_ent); + + linkmap = probe_ent->link_port_map; + + for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { + if (((linkmap >> i) & 0x01)) { + if (ahci_port_start((u8) i)) { + printf("Can not start port %d\n", i); + continue; + } + ahci_set_feature((u8) i); + } + } + err_out: + return rc; +} +
void scsi_bus_reset(void) {

Dear Rob Herring,
In message 1306955427-18940-6-git-send-email-robherring2@gmail.com you wrote:
From: Rob Herring rob.herring@calxeda.com
Add support for AHCI controllers that are not PCI based.
...
- memset((void *)ataid, 0, sizeof(hd_driveid_t *) * AHCI_MAX_PORTS);
This triggers a checkpatch error.
Why don;t you simply write:
memset((void *)ataid, 0, sizeof(ataid)):
?
err_out:
labels should not be indented
Best regards,
Wolfgang Denk

Dear Rob Herring,
In message 1306955427-18940-1-git-send-email-robherring2@gmail.com you wrote:
From: Rob Herring rob.herring@calxeda.com
This patch series enables common SDHCI and AHCI drivers for other platforms to use.
The AHCI driver is modified to support non-PCI versions of the controller.
The Samsung s5p mmc driver appears to be the cleanest implementation of an SDHCI controller based on reviewing various Linux SDHCI drivers. The FSL ESDHCI controller is also, but has quite a few quirks. IIRC, the omap HSMMC block is also based on SDHCI.
Which board(s) is(are) using this driver?
We don't want to add dead code, so we usually don;t add any drivers that have no actual users.
Best regards,
Wolfgang Denk

On 06/01/2011 02:25 PM, Wolfgang Denk wrote:
Dear Rob Herring,
In message1306955427-18940-1-git-send-email-robherring2@gmail.com you wrote:
From: Rob Herringrob.herring@calxeda.com
This patch series enables common SDHCI and AHCI drivers for other platforms to use.
The AHCI driver is modified to support non-PCI versions of the controller.
The Samsung s5p mmc driver appears to be the cleanest implementation of an SDHCI controller based on reviewing various Linux SDHCI drivers. The FSL ESDHCI controller is also, but has quite a few quirks. IIRC, the omap HSMMC block is also based on SDHCI.
Which board(s) is(are) using this driver?
We don't want to add dead code, so we usually don;t add any drivers that have no actual users.
For SDHCI, the Samsung boards will still use the code. It's really a clean-up to reflect that it should be generic code as is the Linux version. It will get used by more boards soon.
For AHCI, I'm not ready to submit the new platform. FSL MX53 can use this code as well, but I don't have h/w to test that.
Rob
participants (2)
-
Rob Herring
-
Wolfgang Denk