[U-Boot] [PATCH 0/8] Add Highbank platform

From: Rob Herring rob.herring@calxeda.com
This series enables AHCI on non-PCI platforms, converts Samsung mmc to a common SDHCI implementation, and adds basic support for the Calxeda highbank platform which uses AHCI and SDHCI drivers.
Rob
Rob Herring (8): mmc: copy s5p to sdhci mmc: sdhci: rework Samsung specfic code mmc: sdhci: exit cmd on error status arm: add __ilog2 function scsi/ahci: ata id little endian fix scsi/ahci: add support for non-PCI controllers ARM: add missing CONFIG_SKIP_LOWLEVEL_INIT for armv7 ARM: Add Calxeda Highbank platform
arch/arm/cpu/armv7/highbank/Makefile | 46 +++ arch/arm/cpu/armv7/highbank/config.mk | 4 + arch/arm/cpu/armv7/highbank/timer.c | 124 +++++++ arch/arm/cpu/armv7/start.S | 2 + arch/arm/include/asm/arch-highbank/clk.h | 22 ++ arch/arm/include/asm/arch-s5pc1xx/mmc.h | 73 ---- arch/arm/include/asm/arch-s5pc2xx/mmc.h | 73 ---- arch/arm/include/asm/bitops.h | 9 + board/highbank/Makefile | 49 +++ board/highbank/highbank.c | 57 ++++ board/samsung/goni/goni.c | 4 +- board/samsung/universal_c210/universal.c | 8 +- boards.cfg | 1 + common/cmd_scsi.c | 6 +- drivers/block/ahci.c | 72 ++++- drivers/mmc/Makefile | 3 +- drivers/mmc/s5p_mmc.c | 482 --------------------------- drivers/mmc/sdhci.c | 532 ++++++++++++++++++++++++++++++ include/ahci.h | 4 + include/configs/highbank.h | 117 +++++++ include/scsi.h | 1 + include/sdhci.h | 18 + 22 files changed, 1061 insertions(+), 646 deletions(-) create mode 100644 arch/arm/cpu/armv7/highbank/Makefile create mode 100644 arch/arm/cpu/armv7/highbank/config.mk create mode 100644 arch/arm/cpu/armv7/highbank/timer.c create mode 100644 arch/arm/include/asm/arch-highbank/clk.h 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 board/highbank/Makefile create mode 100644 board/highbank/highbank.c delete mode 100644 drivers/mmc/s5p_mmc.c create mode 100644 drivers/mmc/sdhci.c create mode 100644 include/configs/highbank.h 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 | 482 ------------------------------------------------- drivers/mmc/sdhci.c | 482 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 484 insertions(+), 483 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 280738f..0000000 --- a/drivers/mmc/s5p_mmc.c +++ /dev/null @@ -1,482 +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> -#include <asm/arch/clk.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); - - set_mmc_clk(host->dev_index, div); - - /* 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].dev_index = dev_index; - mmc_host[dev_index].clock = 0; - mmc_host[dev_index].reg = s5p_get_base_mmc(dev_index); - mmc->b_max = 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..280738f --- /dev/null +++ b/drivers/mmc/sdhci.c @@ -0,0 +1,482 @@ +/* + * (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> +#include <asm/arch/clk.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); + + set_mmc_clk(host->dev_index, div); + + /* 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].dev_index = dev_index; + mmc_host[dev_index].clock = 0; + mmc_host[dev_index].reg = s5p_get_base_mmc(dev_index); + mmc->b_max = 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 | 73 -------------------------- arch/arm/include/asm/arch-s5pc2xx/mmc.h | 73 -------------------------- board/samsung/goni/goni.c | 4 +- board/samsung/universal_c210/universal.c | 8 ++- drivers/mmc/sdhci.c | 82 +++++++++++++++++++++++------- include/sdhci.h | 18 +++++++ 6 files changed, 89 insertions(+), 169 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 adef4ee..0000000 --- a/arch/arm/include/asm/arch-s5pc1xx/mmc.h +++ /dev/null @@ -1,73 +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 dev_index; -}; - -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 30f82b8..0000000 --- a/arch/arm/include/asm/arch-s5pc2xx/mmc.h +++ /dev/null @@ -1,73 +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 dev_index; -}; - -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..b0e76e8 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;
@@ -151,6 +151,7 @@ int checkboard(void) int board_mmc_init(bd_t *bis) { int i, err; + u32 base;
switch (get_hwrev()) { case 0: @@ -217,7 +218,8 @@ int board_mmc_init(bd_t *bis) * mmc0 : eMMC (8-bit buswidth) * mmc2 : SD card (4-bit buswidth) */ - err = s5p_mmc_init(0, 8); + base = samsung_get_base_mmc(); + err = sdhci_mmc_init((void *)base, 8);
/* * Check the T-flash detect pin @@ -241,7 +243,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 *)(base + 0x20000), 4); }
return err; diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 280738f..c82bde0 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -21,18 +21,56 @@ #include <common.h> #include <mmc.h> #include <asm/io.h> -#include <asm/arch/mmc.h> #include <asm/arch/clk.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) */ + int dev_index; +}; + /* 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) { @@ -255,6 +293,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 @@ -265,7 +304,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 */ @@ -320,6 +359,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 @@ -349,7 +389,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); @@ -445,14 +485,21 @@ 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]; + host->dev_index = 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; @@ -467,16 +514,15 @@ static int s5p_mmc_initialize(int dev_index, int bus_width) mmc->f_min = 400000; mmc->f_max = 52000000;
- mmc_host[dev_index].dev_index = dev_index; - mmc_host[dev_index].clock = 0; - mmc_host[dev_index].reg = s5p_get_base_mmc(dev_index); + host->clock = 0; + host->reg = base; mmc->b_max = 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,
On 12 June 2011 06:46, Rob Herring robherring2@gmail.com 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
arch/arm/include/asm/arch-s5pc1xx/mmc.h | 73 -------------------------- arch/arm/include/asm/arch-s5pc2xx/mmc.h | 73 -------------------------- board/samsung/goni/goni.c | 4 +- board/samsung/universal_c210/universal.c | 8 ++- drivers/mmc/sdhci.c | 82 +++++++++++++++++++++++------- include/sdhci.h | 18 +++++++ 6 files changed, 89 insertions(+), 169 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/board/samsung/universal_c210/universal.c b/board/samsung/universal_c210/universal.c index b65bc6e..b0e76e8 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;
@@ -151,6 +151,7 @@ int checkboard(void) int board_mmc_init(bd_t *bis) { int i, err;
- u32 base;
switch (get_hwrev()) { case 0: @@ -217,7 +218,8 @@ int board_mmc_init(bd_t *bis) * mmc0 : eMMC (8-bit buswidth) * mmc2 : SD card (4-bit buswidth) */
- err = s5p_mmc_init(0, 8);
- base = samsung_get_base_mmc();
- err = sdhci_mmc_init((void *)base, 8);
/* * Check the T-flash detect pin @@ -241,7 +243,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 *)(base + 0x20000), 4);
No, please use the macro instead of constant. (pass the device number to macro)
}
return err; diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 280738f..c82bde0 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -21,18 +21,56 @@ #include <common.h> #include <mmc.h> #include <asm/io.h> -#include <asm/arch/mmc.h> #include <asm/arch/clk.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) */
- int dev_index;
+};
Please move this structures to header file.
/* 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) { @@ -255,6 +293,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 @@ -265,7 +304,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 */ @@ -320,6 +359,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 @@ -349,7 +389,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); @@ -445,14 +485,21 @@ 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];
- host->dev_index = dev_count;
- dev_count++;
NAK. dev_index is not a count number, it's a h/w device number. This change is wrong. (Maybe you misunderstood this concept) Please keep the dev_index.
- 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; @@ -467,16 +514,15 @@ static int s5p_mmc_initialize(int dev_index, int bus_width) mmc->f_min = 400000; mmc->f_max = 52000000;
- mmc_host[dev_index].dev_index = dev_index;
Ditto. Please keep the dev_index.
- mmc_host[dev_index].clock = 0;
- mmc_host[dev_index].reg = s5p_get_base_mmc(dev_index);
- host->clock = 0;
- host->reg = base;
mmc->b_max = 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);
}
Thanks Minkyu Kang

On 06/13/2011 01:59 AM, Minkyu Kang wrote:
Dear Rob Herring,
On 12 June 2011 06:46, Rob Herringrobherring2@gmail.com wrote:
From: Rob Herringrob.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 Herringrob.herring@calxeda.com
arch/arm/include/asm/arch-s5pc1xx/mmc.h | 73 -------------------------- arch/arm/include/asm/arch-s5pc2xx/mmc.h | 73 -------------------------- board/samsung/goni/goni.c | 4 +- board/samsung/universal_c210/universal.c | 8 ++- drivers/mmc/sdhci.c | 82 +++++++++++++++++++++++------- include/sdhci.h | 18 +++++++ 6 files changed, 89 insertions(+), 169 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/board/samsung/universal_c210/universal.c b/board/samsung/universal_c210/universal.c index b65bc6e..b0e76e8 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;
@@ -151,6 +151,7 @@ int checkboard(void) int board_mmc_init(bd_t *bis) { int i, err;
u32 base; switch (get_hwrev()) { case 0:
@@ -217,7 +218,8 @@ int board_mmc_init(bd_t *bis) * mmc0 : eMMC (8-bit buswidth) * mmc2 : SD card (4-bit buswidth) */
err = s5p_mmc_init(0, 8);
base = samsung_get_base_mmc();
err = sdhci_mmc_init((void *)base, 8); /* * Check the T-flash detect pin
@@ -241,7 +243,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 *)(base + 0x20000), 4);
No, please use the macro instead of constant. (pass the device number to macro)
} return err;
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 280738f..c82bde0 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -21,18 +21,56 @@ #include<common.h> #include<mmc.h> #include<asm/io.h> -#include<asm/arch/mmc.h> #include<asm/arch/clk.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) */
int dev_index;
+};
Please move this structures to header file.
Why? There is no header anymore. These structures are only used within the .c file, so there is no point in having a header. They were almost the same before and just duplicated code. The only difference was padding added to the end of the struct used to calculate base address and the 2nd controller. Using the size of the struct to calculate base addresses doesn't work for all platforms. The fact that there were already 2 structs for 2 platforms is evidence of that.
- /* 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) { @@ -255,6 +293,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 @@ -265,7 +304,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 */
@@ -320,6 +359,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 @@ -349,7 +389,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);
@@ -445,14 +485,21 @@ 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];
host->dev_index = dev_count;
dev_count++;
NAK. dev_index is not a count number, it's a h/w device number. This change is wrong. (Maybe you misunderstood this concept) Please keep the dev_index.
What have I broken? The only thing the index was used for was getting the base address and indexing to driver struct. I've simply pulled out the base address from the driver so the board code can specify it. You still have an index that is controlled by order the board code initializes each controller.
Rob

Dear Rob Herring,
On 13 June 2011 21:45, Rob Herring robherring2@gmail.com wrote:
On 06/13/2011 01:59 AM, Minkyu Kang wrote:
Dear Rob Herring,
On 12 June 2011 06:46, Rob Herringrobherring2@gmail.com wrote:
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 280738f..c82bde0 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -21,18 +21,56 @@ #include<common.h> #include<mmc.h> #include<asm/io.h> -#include<asm/arch/mmc.h> #include<asm/arch/clk.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) */
- int dev_index;
+};
Please move this structures to header file.
Why? There is no header anymore. These structures are only used within the .c file, so there is no point in having a header. They were almost the same before and just duplicated code. The only difference was padding added to the end of the struct used to calculate base address and the 2nd controller. Using the size of the struct to calculate base addresses doesn't work for all platforms. The fact that there were already 2 structs for 2 platforms is evidence of that.
I mean.. move it to include/sdhci.h. There are possibility to use at other files.
-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];
- host->dev_index = dev_count;
- dev_count++;
NAK. dev_index is not a count number, it's a h/w device number. This change is wrong. (Maybe you misunderstood this concept) Please keep the dev_index.
What have I broken? The only thing the index was used for was getting the base address and indexing to driver struct. I've simply pulled out the base address from the driver so the board code can specify it. You still have an index that is controlled by order the board code initializes each controller.
No. Please see the code in detail. dev_index is used by set_mmc_clk in mmc_chage_clock function (line 295). set_mmc_clk need h/w device number.
universal_c210 board have 2 mmc device. device 0 is eMMC and device 2 is SD card. According to your patch, we should register the dummy device for device 1. I can't agree it.
Please don't modify unrelated part of patch.
Thanks Minkyu Kang

From: Rob Herring rob.herring@calxeda.com
Create a common header sdhci.h and move register defintions there. 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 --- Minkyu Kang,
Please take a look at the updated patch. I've implemented most
I moved the register definitions, but kept "struct mmc_host" within the .c file. It is private to the driver.
I'm not sure if other devices have the same offsets. If so, the macro for the device offset could be made more generic. I find the whole use of indexes to calculate the base addresses to be fragile. It will work for some chips, but is easily broken.
Rob
arch/arm/include/asm/arch-s5pc1xx/mmc.h | 73 ------------------------------ arch/arm/include/asm/arch-s5pc2xx/cpu.h | 4 ++ arch/arm/include/asm/arch-s5pc2xx/mmc.h | 73 ------------------------------ board/samsung/goni/goni.c | 4 +- board/samsung/universal_c210/universal.c | 6 +- drivers/mmc/sdhci.c | 31 +++++++------ include/sdhci.h | 62 +++++++++++++++++++++++++ 7 files changed, 88 insertions(+), 165 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 adef4ee..0000000 --- a/arch/arm/include/asm/arch-s5pc1xx/mmc.h +++ /dev/null @@ -1,73 +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 dev_index; -}; - -int s5p_mmc_init(int dev_index, int bus_width); - -#endif /* __ASSEMBLY__ */ -#endif diff --git a/arch/arm/include/asm/arch-s5pc2xx/cpu.h b/arch/arm/include/asm/arch-s5pc2xx/cpu.h index f9015c7..8113c90 100644 --- a/arch/arm/include/asm/arch-s5pc2xx/cpu.h +++ b/arch/arm/include/asm/arch-s5pc2xx/cpu.h @@ -108,6 +108,10 @@ SAMSUNG_BASE(uart, UART_BASE) SAMSUNG_BASE(usb_phy, USBPHY_BASE) SAMSUNG_BASE(usb_otg, USBOTG_BASE) SAMSUNG_BASE(watchdog, WATCHDOG_BASE) + +#define samsung_get_base_mmc_offset(idx) (samsung_get_base_mmc() + \ + 0x10000 * (idx)) + #endif
#endif /* _S5PC2XX_CPU_H */ 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 30f82b8..0000000 --- a/arch/arm/include/asm/arch-s5pc2xx/mmc.h +++ /dev/null @@ -1,73 +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 dev_index; -}; - -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..047300b 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(0, samsung_get_base_mmc(), 4); } #endif diff --git a/board/samsung/universal_c210/universal.c b/board/samsung/universal_c210/universal.c index b65bc6e..cd67d8d 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(0, samsung_get_base_mmc_offset(0), 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(2, samsung_get_base_mmc_offset(2), 4); }
return err; diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 280738f..4bff345 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -20,20 +20,21 @@
#include <common.h> #include <mmc.h> +#include <sdhci.h> #include <asm/io.h> -#include <asm/arch/mmc.h> #include <asm/arch/clk.h>
+struct mmc_host { + struct sdhci_mmc *reg; + unsigned int version; /* SDHCI spec. version */ + unsigned int clock; /* Current clock (MHz) */ + int dev_index; +}; + /* 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; @@ -255,6 +256,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 @@ -265,7 +267,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 */ @@ -320,6 +322,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 @@ -349,7 +352,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); @@ -445,13 +448,13 @@ 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(int dev_index, void *base, int bus_width) { struct mmc *mmc;
mmc = &mmc_dev[dev_index];
- sprintf(mmc->name, "SAMSUNG SD/MMC"); + sprintf(mmc->name, "SDHCI SD/MMC"); mmc->priv = &mmc_host[dev_index]; mmc->send_cmd = mmc_send_cmd; mmc->set_ios = mmc_set_ios; @@ -469,14 +472,14 @@ static int s5p_mmc_initialize(int dev_index, int bus_width)
mmc_host[dev_index].dev_index = dev_index; mmc_host[dev_index].clock = 0; - mmc_host[dev_index].reg = s5p_get_base_mmc(dev_index); + mmc_host[dev_index].reg = base; mmc->b_max = 0; mmc_register(mmc);
return 0; }
-int s5p_mmc_init(int dev_index, int bus_width) +int sdhci_mmc_init(int dev_index, unsigned int base, int bus_width) { - return s5p_mmc_initialize(dev_index, bus_width); + return sdhci_mmc_initialize(dev_index, (void *)base, bus_width); } diff --git a/include/sdhci.h b/include/sdhci.h new file mode 100644 index 0000000..8ef381b --- /dev/null +++ b/include/sdhci.h @@ -0,0 +1,62 @@ +/* + * (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 _SDHCI_H_ +#define _SDHCI_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; +}; + +int sdhci_mmc_init(int dev_index, unsigned int base, int bus_width); + +#endif

Dear Rob Herring,
On 14 June 2011 23:48, Rob Herring robherring2@gmail.com wrote:
arch/arm/include/asm/arch-s5pc1xx/mmc.h | 73 ------------------------------ arch/arm/include/asm/arch-s5pc2xx/cpu.h | 4 ++ arch/arm/include/asm/arch-s5pc2xx/mmc.h | 73 ------------------------------ board/samsung/goni/goni.c | 4 +- board/samsung/universal_c210/universal.c | 6 +- drivers/mmc/sdhci.c | 31 +++++++------ include/sdhci.h | 62 +++++++++++++++++++++++++ 7 files changed, 88 insertions(+), 165 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
--- a/arch/arm/include/asm/arch-s5pc2xx/cpu.h +++ b/arch/arm/include/asm/arch-s5pc2xx/cpu.h @@ -108,6 +108,10 @@ SAMSUNG_BASE(uart, UART_BASE) SAMSUNG_BASE(usb_phy, USBPHY_BASE) SAMSUNG_BASE(usb_otg, USBOTG_BASE) SAMSUNG_BASE(watchdog, WATCHDOG_BASE)
+#define samsung_get_base_mmc_offset(idx) (samsung_get_base_mmc() + \
- 0x10000 * (idx))
#endif
#endif /* _S5PC2XX_CPU_H */
Looks fine. But, missing arch/arm/include/asm/arch-s5pc1xx/cpu.h
Dear Jaehoon,
Please test this patch on s5pc1xx and s5pc2xx.
Thanks Minkyu Kang

Tested-by: Jaehoon Chung jh80.chung@samsung.com
But Mr.Kang mentioned missing arch/arm/include/asm/arch-s5pc1xx/cpu.h Need the below patch.. (s5pc2xx and s5pc1xx are working well)
diff --git a/arch/arm/include/asm/arch-s5pc1xx/cpu.h b/arch/arm/include/asm/arch-s5pc1xx/cpu.h index e74959f..86b7bd2 100644 --- a/arch/arm/include/asm/arch-s5pc1xx/cpu.h +++ b/arch/arm/include/asm/arch-s5pc1xx/cpu.h @@ -94,6 +94,9 @@ SAMSUNG_BASE(mmc, MMC_BASE) SAMSUNG_BASE(sromc, SROMC_BASE) SAMSUNG_BASE(timer, PWMTIMER_BASE) SAMSUNG_BASE(uart, UART_BASE) + +#define samsung_get_base_mmc_offset(idx) (samsung_get_base_mmc() + \ + 0x10000 * (idx)) #endif
#endif /* _S5PC1XX_CPU_H */
Regards, Jaehoon Chung
Minkyu Kang wrote:
Dear Rob Herring,
On 14 June 2011 23:48, Rob Herring robherring2@gmail.com wrote:
arch/arm/include/asm/arch-s5pc1xx/mmc.h | 73 ------------------------------ arch/arm/include/asm/arch-s5pc2xx/cpu.h | 4 ++ arch/arm/include/asm/arch-s5pc2xx/mmc.h | 73 ------------------------------ board/samsung/goni/goni.c | 4 +- board/samsung/universal_c210/universal.c | 6 +- drivers/mmc/sdhci.c | 31 +++++++------ include/sdhci.h | 62 +++++++++++++++++++++++++ 7 files changed, 88 insertions(+), 165 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
--- a/arch/arm/include/asm/arch-s5pc2xx/cpu.h +++ b/arch/arm/include/asm/arch-s5pc2xx/cpu.h @@ -108,6 +108,10 @@ SAMSUNG_BASE(uart, UART_BASE) SAMSUNG_BASE(usb_phy, USBPHY_BASE) SAMSUNG_BASE(usb_otg, USBOTG_BASE) SAMSUNG_BASE(watchdog, WATCHDOG_BASE)
+#define samsung_get_base_mmc_offset(idx) (samsung_get_base_mmc() + \
0x10000 * (idx))
#endif
#endif /* _S5PC2XX_CPU_H */
Looks fine. But, missing arch/arm/include/asm/arch-s5pc1xx/cpu.h
Dear Jaehoon,
Please test this patch on s5pc1xx and s5pc2xx.
Thanks Minkyu Kang

On 15 June 2011 17:12, Jaehoon Chung jh80.chung@samsung.com wrote:
Tested-by: Jaehoon Chung jh80.chung@samsung.com
But Mr.Kang mentioned missing arch/arm/include/asm/arch-s5pc1xx/cpu.h Need the below patch.. (s5pc2xx and s5pc1xx are working well)
diff --git a/arch/arm/include/asm/arch-s5pc1xx/cpu.h b/arch/arm/include/asm/arch-s5pc1xx/cpu.h index e74959f..86b7bd2 100644 --- a/arch/arm/include/asm/arch-s5pc1xx/cpu.h +++ b/arch/arm/include/asm/arch-s5pc1xx/cpu.h @@ -94,6 +94,9 @@ SAMSUNG_BASE(mmc, MMC_BASE) SAMSUNG_BASE(sromc, SROMC_BASE) SAMSUNG_BASE(timer, PWMTIMER_BASE) SAMSUNG_BASE(uart, UART_BASE)
+#define samsung_get_base_mmc_offset(idx) (samsung_get_base_mmc() + \
- 0x10000 * (idx))
I think.. offset is wrong. In case of s5pc1xx, 0x10_0000 is right. Please check.
Thanks Minkyu Kang

Minkyu Kang wrote:
On 15 June 2011 17:12, Jaehoon Chung jh80.chung@samsung.com wrote:
Tested-by: Jaehoon Chung jh80.chung@samsung.com
But Mr.Kang mentioned missing arch/arm/include/asm/arch-s5pc1xx/cpu.h Need the below patch.. (s5pc2xx and s5pc1xx are working well)
diff --git a/arch/arm/include/asm/arch-s5pc1xx/cpu.h b/arch/arm/include/asm/arch-s5pc1xx/cpu.h index e74959f..86b7bd2 100644 --- a/arch/arm/include/asm/arch-s5pc1xx/cpu.h +++ b/arch/arm/include/asm/arch-s5pc1xx/cpu.h @@ -94,6 +94,9 @@ SAMSUNG_BASE(mmc, MMC_BASE) SAMSUNG_BASE(sromc, SROMC_BASE) SAMSUNG_BASE(timer, PWMTIMER_BASE) SAMSUNG_BASE(uart, UART_BASE)
+#define samsung_get_base_mmc_offset(idx) (samsung_get_base_mmc() + \
0x10000 * (idx))
I think.. offset is wrong. In case of s5pc1xx, 0x10_0000 is right. Please check.
Sorry..my mistake..you're right. Offset is 0x10_0000
Thanks, Jaehoon chung

On Sat, Jun 11, 2011 at 17:46, Rob Herring wrote:
--- /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);
please add ifdef protection against multiple inclusion -mike

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 c82bde0..0a5b30d 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -206,6 +206,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
Add __ilog2 function for ARM. Needed for ahci.c
Signed-off-by: Rob Herring rob.herring@calxeda.com --- arch/arm/include/asm/bitops.h | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/arch/arm/include/asm/bitops.h b/arch/arm/include/asm/bitops.h index 270f163..0420182 100644 --- a/arch/arm/include/asm/bitops.h +++ b/arch/arm/include/asm/bitops.h @@ -106,6 +106,15 @@ static inline int test_bit(int nr, const void * addr) return ((unsigned char *) addr)[nr >> 3] & (1U << (nr & 7)); }
+extern __inline__ int __ilog2(unsigned int x) +{ + int ret; + + asm("clz\t%0, %1" : "=r" (ret) : "r" (x)); + ret = 31 - ret; + return ret; +} + /* * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first..

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 | 70 +++++++++++++++++++++++++++++++++++++++++++------ include/ahci.h | 4 +++ include/scsi.h | 1 + 4 files changed, 70 insertions(+), 11 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..d12cb71 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -78,13 +78,15 @@ 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; + u16 tmp16; + unsigned short vendor; +#endif volatile u8 *mmio = (volatile u8 *)probe_ent->mmio_base; u32 tmp, cap_save; - u16 tmp16; int i, j; volatile u8 *port_mmio; - unsigned short vendor;
cap_save = readl(mmio + HOST_CAP); cap_save &= ((1 << 28) | (1 << 17)); @@ -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,22 +186,24 @@ 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; }
static void ahci_print_info(struct ahci_probe_ent *probe_ent) { +#ifdef CONFIG_PCI pci_dev_t pdev = probe_ent->dev; + u16 cc; +#endif volatile u8 *mmio = (volatile u8 *)probe_ent->mmio_base; u32 vers, cap, impl, speed; const char *speed_s; - u16 cc; const char *scc_s;
vers = readl(mmio + HOST_VERSION); @@ -212,7 +217,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 +227,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 +256,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 +299,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 +675,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 +692,48 @@ void scsi_low_level_init(int busdevfunc) } }
+int ahci_init(u32 base) +{ + int i, rc = 0; + u32 linkmap; + + memset(ataid, 0, sizeof(ataid)); + + 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) { diff --git a/include/ahci.h b/include/ahci.h index 0c6bbbd..c0a0a47 100644 --- a/include/ahci.h +++ b/include/ahci.h @@ -25,6 +25,8 @@ #ifndef _AHCI_H_ #define _AHCI_H_
+#include <pci.h> + #define AHCI_PCI_BAR 0x24 #define AHCI_MAX_SG 56 /* hardware max is 64K */ #define AHCI_CMD_SLOT_SZ 32 @@ -187,4 +189,6 @@ struct ahci_probe_ent { u32 link_port_map; /*linkup port map*/ };
+int ahci_init(u32 base); + #endif diff --git a/include/scsi.h b/include/scsi.h index aaafc9c..c52759c 100644 --- a/include/scsi.h +++ b/include/scsi.h @@ -185,6 +185,7 @@ void scsi_low_level_init(int busdevfunc); * functions residing inside cmd_scsi.c */ void scsi_init(void); +void scsi_scan(int mode);
#define SCSI_IDENTIFY 0xC0 /* not used */

From: Rob Herring rob.herring@calxeda.com
cpu_init_crit can be skipped, but the code is still enabled requiring a platform to supply lowlevel_init.
Signed-off-by: Rob Herring rob.herring@calxeda.com --- arch/arm/cpu/armv7/start.S | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S index d91ae12..ec54125 100644 --- a/arch/arm/cpu/armv7/start.S +++ b/arch/arm/cpu/armv7/start.S @@ -275,6 +275,7 @@ _rel_dyn_end_ofs: _dynsym_start_ofs: .word __dynsym_start - _start
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT /************************************************************************* * * CPU_init_critical registers @@ -311,6 +312,7 @@ cpu_init_crit: bl lowlevel_init @ go setup pll,mux,memory mov lr, ip @ restore link mov pc, lr @ back to my caller +#endif /* ************************************************************************* *

Hi Rob,
Le 11/06/2011 23:46, Rob Herring a écrit :
From: Rob Herringrob.herring@calxeda.com
cpu_init_crit can be skipped, but the code is still enabled requiring a platform to supply lowlevel_init.
Signed-off-by: Rob Herringrob.herring@calxeda.com
Applied to u-boot-arm/master, thanks!
Amicalement,

From: Rob Herring rob.herring@calxeda.com
Add basic support for Calxeda Highbank platform. This includes support for serial, mmc, and sata.
Signed-off-by: Jason Hobbs jason.hobbs@calxeda.com Signed-off-by: Rob Herring rob.herring@calxeda.com --- arch/arm/cpu/armv7/highbank/Makefile | 46 +++++++++++ arch/arm/cpu/armv7/highbank/config.mk | 4 + arch/arm/cpu/armv7/highbank/timer.c | 124 ++++++++++++++++++++++++++++++ arch/arm/include/asm/arch-highbank/clk.h | 22 +++++ board/highbank/Makefile | 49 ++++++++++++ board/highbank/highbank.c | 57 ++++++++++++++ boards.cfg | 1 + include/configs/highbank.h | 117 ++++++++++++++++++++++++++++ 8 files changed, 420 insertions(+), 0 deletions(-) create mode 100644 arch/arm/cpu/armv7/highbank/Makefile create mode 100644 arch/arm/cpu/armv7/highbank/config.mk create mode 100644 arch/arm/cpu/armv7/highbank/timer.c create mode 100644 arch/arm/include/asm/arch-highbank/clk.h create mode 100644 board/highbank/Makefile create mode 100644 board/highbank/highbank.c create mode 100644 include/configs/highbank.h
diff --git a/arch/arm/cpu/armv7/highbank/Makefile b/arch/arm/cpu/armv7/highbank/Makefile new file mode 100644 index 0000000..76faeb0 --- /dev/null +++ b/arch/arm/cpu/armv7/highbank/Makefile @@ -0,0 +1,46 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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 +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(SOC).o + +COBJS := timer.o +SOBJS := + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/armv7/highbank/config.mk b/arch/arm/cpu/armv7/highbank/config.mk new file mode 100644 index 0000000..5ed5c39 --- /dev/null +++ b/arch/arm/cpu/armv7/highbank/config.mk @@ -0,0 +1,4 @@ +STANDALONE_LOAD_ADDR = 0x100000 + +PLATFORM_CPPFLAGS += -march=armv7-a + diff --git a/arch/arm/cpu/armv7/highbank/timer.c b/arch/arm/cpu/armv7/highbank/timer.c new file mode 100644 index 0000000..263f11a --- /dev/null +++ b/arch/arm/cpu/armv7/highbank/timer.c @@ -0,0 +1,124 @@ +/* + * Copyright 2010-2011 Calxeda, Inc. + * + * Based on arm926ejs/mx27/timer.c + * + * 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 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/. + */ + +#include <common.h> +#include <div64.h> +#include <linux/types.h> /* for size_t */ +#include <linux/stddef.h> /* for NULL */ +#include <asm/io.h> +#include <asm/arch-armv7/systimer.h> + +#undef SYSTIMER_BASE +#define SYSTIMER_BASE 0xFFF34000 /* Timer 0 and 1 base */ +#define SYSTIMER_RATE 150000000 + +static ulong timestamp; +static ulong lastinc; +static struct systimer *systimer_base = (struct systimer *)SYSTIMER_BASE; + +/* + * Start the timer + */ +int timer_init(void) +{ + /* + * Setup timer0 + */ + writel(SYSTIMER_RELOAD, &systimer_base->timer0load); + writel(SYSTIMER_RELOAD, &systimer_base->timer0value); + writel(SYSTIMER_EN | SYSTIMER_32BIT, &systimer_base->timer0control); + + reset_timer_masked(); + + return 0; + +} + +#define TICK_PER_TIME ((SYSTIMER_RATE + CONFIG_SYS_HZ / 2) / CONFIG_SYS_HZ) +#define NS_PER_TICK (1000000000 / SYSTIMER_RATE) + +static inline unsigned long long tick_to_time(unsigned long long tick) +{ + do_div(tick, TICK_PER_TIME); + return tick; +} + +static inline unsigned long long time_to_tick(unsigned long long time) +{ + return time * TICK_PER_TIME; +} + +static inline unsigned long long us_to_tick(unsigned long long us) +{ + unsigned long long tick = us << 16; + tick += NS_PER_TICK - 1; + do_div(tick, NS_PER_TICK); + return tick >> 16; +} + +unsigned long long get_ticks(void) +{ + ulong now = ~readl(&systimer_base->timer0value); + + if (now >= lastinc) /* normal mode (non roll) */ + /* move stamp forward with absolut diff ticks */ + timestamp += (now - lastinc); + else /* we have rollover of incrementer */ + timestamp += (0xFFFFFFFF - lastinc) + now; + lastinc = now; + return timestamp; +} + +/* + * Delay x useconds AND preserve advance timstamp value + * assumes timer is ticking at 1 msec + */ +void __udelay(ulong usec) +{ + unsigned long long tmp; + ulong tmo; + + tmo = us_to_tick(usec); + tmp = get_ticks() + tmo; /* get current timestamp */ + + while (get_ticks() < tmp) /* loop till event */ + /*NOP*/; +} + +ulong get_timer(ulong base) +{ + return get_timer_masked() - base; +} + +void reset_timer_masked(void) +{ + lastinc = ~readl(&systimer_base->timer0value); + timestamp = 0; +} + +void reset_timer(void) +{ + reset_timer_masked(); +} + +ulong get_timer_masked(void) +{ + return tick_to_time(get_ticks()); +} + diff --git a/arch/arm/include/asm/arch-highbank/clk.h b/arch/arm/include/asm/arch-highbank/clk.h new file mode 100644 index 0000000..1ee7936 --- /dev/null +++ b/arch/arm/include/asm/arch-highbank/clk.h @@ -0,0 +1,22 @@ +/* + * 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/. + */ + +#ifndef __ASM_ARM_ARCH_CLK_H_ +#define __ASM_ARM_ARCH_CLK_H_ + +static inline void set_mmc_clk(int dev_index, unsigned int div) {} + +#endif diff --git a/board/highbank/Makefile b/board/highbank/Makefile new file mode 100644 index 0000000..d5b8362 --- /dev/null +++ b/board/highbank/Makefile @@ -0,0 +1,49 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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 +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(BOARD).o + +COBJS := highbank.o + +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) + +$(LIB): $(obj).depend $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +clean: + rm -f $(OBJS) + +distclean: clean + rm -f $(LIB) core *.bak $(obj).depend + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/board/highbank/highbank.c b/board/highbank/highbank.c new file mode 100644 index 0000000..20abc57 --- /dev/null +++ b/board/highbank/highbank.c @@ -0,0 +1,57 @@ +/* + * Copyright 2010-2011 Calxeda, Inc. + * + * 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 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/. + */ + +#include <common.h> +#include <sdhci.h> +#include <ahci.h> +#include <scsi.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * Miscellaneous platform dependent initialisations + */ +int board_init(void) +{ + icache_enable(); + + return 0; +} + +int board_mmc_init(bd_t *bis) +{ + sdhci_mmc_init((void *)0xffe0e000, 8); + return 0; +} + +int misc_init_r(void) +{ + ahci_init(0xffe08000); + scsi_scan(1); + return 0; +} + +int dram_init(void) +{ + gd->ram_size = PHYS_SDRAM_1_SIZE; + return 0; +} + +void reset_cpu(ulong addr) +{ +} + diff --git a/boards.cfg b/boards.cfg index d2cacc8..7395d9c 100644 --- a/boards.cfg +++ b/boards.cfg @@ -126,6 +126,7 @@ omap5912osk arm arm926ejs - ti edminiv2 arm arm926ejs - LaCie orion5x dkb arm arm926ejs - Marvell pantheon ca9x4_ct_vxp arm armv7 vexpress armltd +highbank arm armv7 highbank - highbank efikamx arm armv7 efikamx - mx5 mx51evk:IMX_CONFIG=board/efikamx/imximage.cfg mx51evk arm armv7 mx51evk freescale mx5 mx51evk:IMX_CONFIG=board/freescale/mx51evk/imximage.cfg mx53evk arm armv7 mx53evk freescale mx5 mx53evk:IMX_CONFIG=board/freescale/mx53evk/imximage.cfg diff --git a/include/configs/highbank.h b/include/configs/highbank.h new file mode 100644 index 0000000..2211fa8 --- /dev/null +++ b/include/configs/highbank.h @@ -0,0 +1,117 @@ +/* + * Copyright 2010-2011 Calxeda, Inc. + * + * 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 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/. + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#define CONFIG_L2_OFF + +#define CONFIG_SYS_NO_FLASH +#define CFG_HZ 1000 +#define CONFIG_SYS_HZ CFG_HZ + +#define CONFIG_MISC_INIT_R /* call misc_init_r during start up */ + +#define CONFIG_OF_LIBFDT +#define CONFIG_FIT +#define CONFIG_SYS_BOOTMAPSZ (16 << 20) + +/* + * Size of malloc() pool + */ +#define CONFIG_SYS_MALLOC_LEN (512 * 1024) + +#define CONFIG_PL011_SERIAL +#define CONFIG_PL011_CLOCK 150000000 +#define CONFIG_PL01x_PORTS { (void *)(0xFFF36000) } +#define CONFIG_CONS_INDEX 0 + +#define CONFIG_BAUDRATE 38400 +#define CONFIG_SYS_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 } + +#define CONFIG_SCSI_AHCI +#define CONFIG_SYS_SCSI_MAX_SCSI_ID 5 +#define CONFIG_SYS_SCSI_MAX_LUN 1 +#define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * \ + CONFIG_SYS_SCSI_MAX_LUN) + +#define CONFIG_MMC +#define CONFIG_GENERIC_MMC +#define CONFIG_SDHCI +#define CONFIG_DOS_PARTITION + +/* + * Command line configuration. + */ +#include <config_cmd_default.h> +#undef CONFIG_CMD_NET +#undef CONFIG_CMD_NFS + +#define CONFIG_CMD_BDI +#define CONFIG_CMD_ELF +#define CONFIG_CMD_MEMORY +#define CONFIG_CMD_MMC +#define CONFIG_CMD_LOADS +#define CONFIG_CMD_SCSI +#define CONFIG_CMD_EXT2 + +#define CONFIG_BOOTDELAY 2 +/* + * Miscellaneous configurable options + */ +#define CONFIG_CMDLINE_EDITING +#define CONFIG_AUTO_COMPLETE +#define CONFIG_SYS_LONGHELP /* undef to save memory */ +#define CONFIG_SYS_CBSIZE 256 /* Console I/O Buffer Size */ +#define CONFIG_SYS_MAXARGS 16 /* max number of cmd args */ +#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE +#define CONFIG_SYS_PROMPT "Highbank #" +/* Print Buffer Size */ +#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \ + sizeof(CONFIG_SYS_PROMPT)+16) + +#define CONFIG_SYS_LOAD_ADDR 0x800000 + +/*----------------------------------------------------------------------- + * Stack sizes + * + * The stack sizes are set up in start.S using the settings below + */ +#define CONFIG_STACKSIZE (128*1024) /* regular stack */ +#ifdef CONFIG_USE_IRQ +#define CONFIG_STACKSIZE_IRQ (4*1024) /* IRQ stack */ +#define CONFIG_STACKSIZE_FIQ (4*1024) /* FIQ stack */ +#endif + +/*----------------------------------------------------------------------- + * Physical Memory Map + */ +#define CONFIG_NR_DRAM_BANKS 1 +#define PHYS_SDRAM_1_SIZE 0x08000000 /* 128 MB */ +#define CONFIG_SYS_MEMTEST_START 0x100000 +#define CONFIG_SYS_MEMTEST_END (PHYS_SDRAM_1_SIZE - 0x100000) + +/* Room required on the stack for the environment data */ +#define CONFIG_ENV_SIZE 0x2000 +#define CONFIG_ENV_IS_NOWHERE + +#define CONFIG_SYS_SDRAM_BASE 0x00000000 +#define CONFIG_SYS_TEXT_BASE 0x00001000 +#define CONFIG_SYS_INIT_SP_ADDR 0x01000000 +#define CONFIG_SKIP_LOWLEVEL_INIT + +#endif

Hi Rob,
Le 11/06/2011 23:46, Rob Herring a écrit :
From: Rob Herringrob.herring@calxeda.com
Add basic support for Calxeda Highbank platform. This includes support for serial, mmc, and sata.
Signed-off-by: Jason Hobbsjason.hobbs@calxeda.com Signed-off-by: Rob Herringrob.herring@calxeda.com
This one will get in when all previous ones in the series are applied. Please ping me as a reminder if needed.
Amicalement,

Le 17/07/2011 11:29, Albert ARIBAUD a écrit :
Hi Rob,
Le 11/06/2011 23:46, Rob Herring a écrit :
From: Rob Herringrob.herring@calxeda.com
Add basic support for Calxeda Highbank platform. This includes support for serial, mmc, and sata.
Signed-off-by: Jason Hobbsjason.hobbs@calxeda.com Signed-off-by: Rob Herringrob.herring@calxeda.com
This one will get in when all previous ones in the series are applied. Please ping me as a reminder if needed.
Amicalement,
Sorry -- was a bit quick on this one. I'd forgotten the subsequent changes and issues with numbering. I'll keep the 1/8 because it was inherently OK from day 1 (thus it should not be part of any new patch set) but I'll make sure I get a clean numbered patch for the platform addition patch itself.
Amicalement,
participants (5)
-
Albert ARIBAUD
-
Jaehoon Chung
-
Mike Frysinger
-
Minkyu Kang
-
Rob Herring