From patchwork Mon Jun 18 16:25:34 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mathieu Poirier X-Patchwork-Id: 9397 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 8AD6F23EB4 for ; Mon, 18 Jun 2012 16:25:57 +0000 (UTC) Received: from mail-gg0-f180.google.com (mail-gg0-f180.google.com [209.85.161.180]) by fiordland.canonical.com (Postfix) with ESMTP id 45549A184D2 for ; Mon, 18 Jun 2012 16:25:57 +0000 (UTC) Received: by mail-gg0-f180.google.com with SMTP id f1so4159723ggn.11 for ; Mon, 18 Jun 2012 09:25:57 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf:from:to:cc :subject:date:message-id:x-mailer:in-reply-to:references :x-gm-message-state; bh=lVUkVqA/e7/WZq8/2cayejm0aZe9ON3FruxgCawbVpI=; b=XIPd3Lq2UX9GJp0Jot2+b6CUfPPCvKkNkAt6Jr5DNX4i9k0v4y1VtSVxTyup8QK1kM ORD8QBBx7pc2k2eEt8QwmWQvLM35XHy+QaLY4DgNzEYMKvnIl+oKQbuhCfPifqBgAh6O sf2K7qOkSbHh5Jc1F0FksjCsAl/loBBiEYbivt/FfxUeDHWFbB69JkTHhXcXIXnWqGdC ZDHFg12w705djWtVEiaZJwyyG1c1tW66nLGHAtuThBMd1sEeW/3Iv03cr777vX2LNIP2 p4u7KCRETttPk1UEWksGMNKcGUMR6n6CVxUOW2kbTP/bG6XqcJa3T6Swse/SwgAVjZEL lhoA== Received: by 10.50.40.193 with SMTP id z1mr5935731igk.0.1340036756778; Mon, 18 Jun 2012 09:25:56 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.231.24.148 with SMTP id v20csp77289ibb; Mon, 18 Jun 2012 09:25:56 -0700 (PDT) Received: by 10.68.136.229 with SMTP id qd5mr54484865pbb.2.1340036755822; Mon, 18 Jun 2012 09:25:55 -0700 (PDT) Received: from mail-pb0-f50.google.com (mail-pb0-f50.google.com [209.85.160.50]) by mx.google.com with ESMTPS id tx7si25801141pbc.119.2012.06.18.09.25.55 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 18 Jun 2012 09:25:55 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.160.50 is neither permitted nor denied by best guess record for domain of mathieu.poirier@linaro.org) client-ip=209.85.160.50; Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.160.50 is neither permitted nor denied by best guess record for domain of mathieu.poirier@linaro.org) smtp.mail=mathieu.poirier@linaro.org Received: by mail-pb0-f50.google.com with SMTP id rr4so9722070pbb.37 for ; Mon, 18 Jun 2012 09:25:55 -0700 (PDT) Received: by 10.68.216.2 with SMTP id om2mr53861175pbc.26.1340036755540; Mon, 18 Jun 2012 09:25:55 -0700 (PDT) Received: from localhost.localdomain (S0106002369de4dac.cg.shawcable.net. [70.73.24.112]) by mx.google.com with ESMTPS id mq8sm51844pbb.64.2012.06.18.09.25.54 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 18 Jun 2012 09:25:55 -0700 (PDT) From: mathieu.poirier@linaro.org To: u-boot@lists.denx.de Cc: patches@linaro.org, mathieu.poirier@linaro.org, lee.jones@linaro.org Subject: [PATCH 09/11] u8500: Separating mmc config parameters from driver Date: Mon, 18 Jun 2012 10:25:34 -0600 Message-Id: <1340036736-2436-10-git-send-email-mathieu.poirier@linaro.org> X-Mailer: git-send-email 1.7.5.4 In-Reply-To: <1340036736-2436-1-git-send-email-mathieu.poirier@linaro.org> References: <1340036736-2436-1-git-send-email-mathieu.poirier@linaro.org> X-Gm-Message-State: ALoCoQmtXw2f6nCGdAZfKHvpUwx0NX5ZWhxKpOoIbpLFOKICMvHnzCcTZfsARmu2p/DNwRIxgPsK From: John Rigby Configuration in vexpress and u8500.v1 is different from what is needed in u8500.v2. As such, card configuration specifics need to reside in the board file rather than the driver. Signed-off-by: John Rigby Signed-off-by: Mathieu Poirier --- board/armltd/vexpress/ca9x4_ct_vxp.c | 21 +++++- board/st-ericsson/snowball/snowball.c | 92 ++++++++++++++++++++++- board/st-ericsson/u8500/u8500_href.c | 22 +++++- drivers/mmc/arm_pl180_mmci.c | 132 +++++++++++++-------------------- drivers/mmc/arm_pl180_mmci.h | 27 ++++++- include/configs/snowball.h | 8 ++ 6 files changed, 214 insertions(+), 88 deletions(-) diff --git a/board/armltd/vexpress/ca9x4_ct_vxp.c b/board/armltd/vexpress/ca9x4_ct_vxp.c index 0b36d12..d5e109e 100644 --- a/board/armltd/vexpress/ca9x4_ct_vxp.c +++ b/board/armltd/vexpress/ca9x4_ct_vxp.c @@ -33,6 +33,8 @@ * MA 02111-1307 USA */ #include +#include +#include #include #include #include @@ -90,8 +92,25 @@ int board_eth_init(bd_t *bis) int cpu_mmc_init(bd_t *bis) { int rc = 0; + (void) bis; #ifdef CONFIG_ARM_PL180_MMCI - rc = arm_pl180_mmci_init(); + struct pl180_mmc_host *host; + + host = malloc(sizeof(struct pl180_mmc_host)); + if (!host) + return -ENOMEM; + memset(host, 0, sizeof(*host)); + + strcpy(host->name, "MMC"); + host->base = (struct sdi_registers *)CONFIG_ARM_PL180_MMCI_BASE; + host->pwr_init = INIT_PWR; + host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V1 | SDI_CLKCR_CLKEN; + host->voltages = VOLTAGE_WINDOW_MMC; + host->caps = 0; + host->clock_in = ARM_MCLK; + host->clock_min = ARM_MCLK / (2 * (SDI_CLKCR_CLKDIV_INIT_V1 + 1)); + host->clock_max = CONFIG_ARM_PL180_MMCI_CLOCK_FREQ; + rc = arm_pl180_mmci_init(host); #endif return rc; } diff --git a/board/st-ericsson/snowball/snowball.c b/board/st-ericsson/snowball/snowball.c index 2c01bc1..a44847c 100644 --- a/board/st-ericsson/snowball/snowball.c +++ b/board/st-ericsson/snowball/snowball.c @@ -29,6 +29,9 @@ #include #include +#ifdef CONFIG_MMC +#include "../../../drivers/mmc/arm_pl180_mmci.h" +#endif #include "db8500_pins.h" /* @@ -269,9 +272,96 @@ int board_late_init(void) if ((raise_ab8500_gpio16() < 0)) printf("error: cant' raise GPIO16\n"); + return 0; +} + #ifdef CONFIG_MMC +/* + * emmc_host_init - initialize the emmc controller. + * Configure GPIO settings, set initial clock and power for emmc slot. + * Initialize mmc struct and register with mmc framework. + */ +static int emmc_host_init(void) +{ + struct pl180_mmc_host *host; + + host = malloc(sizeof(struct pl180_mmc_host)); + if (!host) + return -ENOMEM; + memset(host, 0, sizeof(*host)); + + host->base = (struct sdi_registers *)CFG_EMMC_BASE; + host->pwr_init = SDI_PWR_OPD | SDI_PWR_PWRCTRL_ON; + host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V2 | + SDI_CLKCR_CLKEN | SDI_CLKCR_HWFC_EN; + strcpy(host->name, "EMMC"); + host->caps = MMC_MODE_8BIT | MMC_MODE_HS | MMC_MODE_HS_52MHz; + host->voltages = VOLTAGE_WINDOW_MMC; + host->clock_min = ARM_MCLK / (2 + SDI_CLKCR_CLKDIV_INIT_V2); + host->clock_max = ARM_MCLK / 2; + host->clock_in = ARM_MCLK; + host->version2 = 1; + + return arm_pl180_mmci_init(host); +} + +/* + * mmc_host_init - initialize the external mmc controller. + * Configure GPIO settings, set initial clock and power for mmc slot. + * Initialize mmc struct and register with mmc framework. + */ +static int mmc_host_init(void) +{ + struct pl180_mmc_host *host; + u32 sdi_u32; + + host = malloc(sizeof(struct pl180_mmc_host)); + if (!host) + return -ENOMEM; + memset(host, 0, sizeof(*host)); + + host->base = (struct sdi_registers *)CFG_MMC_BASE; + sdi_u32 = 0xBF; + writel(sdi_u32, &host->base->power); + host->pwr_init = 0xBF; + host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V2 | + SDI_CLKCR_CLKEN | SDI_CLKCR_HWFC_EN; + strcpy(host->name, "MMC"); + host->caps = MMC_MODE_8BIT; + host->b_max = 0; + host->voltages = VOLTAGE_WINDOW_SD; + host->clock_min = ARM_MCLK / (2 + SDI_CLKCR_CLKDIV_INIT_V2); + host->clock_max = ARM_MCLK / 2; + host->clock_in = ARM_MCLK; + host->version2 = 1; + + return arm_pl180_mmci_init(host); +} + +/* + * board_mmc_init - initialize all the mmc/sd host controllers. + * Called by generic mmc framework. + */ +int board_mmc_init(bd_t *bis) +{ + int error; + + (void) bis; + + error = emmc_host_init(); + if (error) { + printf("emmc_host_init() %d\n", error); + return -1; + } + u8500_mmc_power_init(); -#endif /* CONFIG_MMC */ + + error = mmc_host_init(); + if (error) { + printf("mmc_host_init() %d\n", error); + return -1; + } return 0; } +#endif /* CONFIG_MMC */ diff --git a/board/st-ericsson/u8500/u8500_href.c b/board/st-ericsson/u8500/u8500_href.c index e75f8b4..f06120c 100644 --- a/board/st-ericsson/u8500/u8500_href.c +++ b/board/st-ericsson/u8500/u8500_href.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -375,12 +376,27 @@ static int u8500_mmci_board_init(void) int board_mmc_init(bd_t *bd) { + struct pl180_mmc_host *host; + if (u8500_mmci_board_init()) return -ENODEV; - if (arm_pl180_mmci_init()) - return -ENODEV; - return 0; + host = malloc(sizeof(struct pl180_mmc_host)); + if (!host) + return -ENOMEM; + memset(host, 0, sizeof(*host)); + + strcpy(host->name, "MMC"); + host->base = (struct sdi_registers *)CONFIG_ARM_PL180_MMCI_BASE; + host->pwr_init = INIT_PWR; + host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V1 | SDI_CLKCR_CLKEN; + host->voltages = VOLTAGE_WINDOW_MMC; + host->caps = 0; + host->clock_in = ARM_MCLK; + host->clock_min = ARM_MCLK / (2 * (SDI_CLKCR_CLKDIV_INIT_V1 + 1)); + host->clock_max = CONFIG_ARM_PL180_MMCI_CLOCK_FREQ; + + return arm_pl180_mmci_init(host); } #endif diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c index 09d443e..2966520 100644 --- a/drivers/mmc/arm_pl180_mmci.c +++ b/drivers/mmc/arm_pl180_mmci.c @@ -32,14 +32,10 @@ #include "arm_pl180_mmci.h" #include -struct mmc_host { - struct sdi_registers *base; -}; - static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd) { u32 hoststatus, statusmask; - struct mmc_host *host = dev->priv; + struct pl180_mmc_host *host = dev->priv; statusmask = SDI_STA_CTIMEOUT | SDI_STA_CCRCFAIL; if ((cmd->resp_type & MMC_RSP_PRESENT)) @@ -53,8 +49,8 @@ static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd) writel(statusmask, &host->base->status_clear); if (hoststatus & SDI_STA_CTIMEOUT) { - printf("CMD%d time out\n", cmd->cmdidx); - return -ETIMEDOUT; + debug("CMD%d time out\n", cmd->cmdidx); + return TIMEOUT; } else if ((hoststatus & SDI_STA_CCRCFAIL) && (cmd->flags & MMC_RSP_CRC)) { printf("CMD%d CRC error\n", cmd->cmdidx); @@ -80,7 +76,8 @@ static int do_command(struct mmc *dev, struct mmc_cmd *cmd) { int result; u32 sdi_cmd = 0; - struct mmc_host *host = dev->priv; + struct pl180_mmc_host *host = dev->priv; + u32 lap = 0; sdi_cmd = ((cmd->cmdidx & SDI_CMD_CMDINDEX_MASK) | SDI_CMD_CPSMEN); @@ -112,7 +109,7 @@ static int read_bytes(struct mmc *dev, u32 *dest, u32 blkcount, u32 blksize) { u32 *tempbuff = dest; u64 xfercount = blkcount * blksize; - struct mmc_host *host = dev->priv; + struct pl180_mmc_host *host = dev->priv; u32 status, status_err; debug("read_bytes: blkcount=%u blksize=%u\n", blkcount, blksize); @@ -168,7 +165,7 @@ static int write_bytes(struct mmc *dev, u32 *src, u32 blkcount, u32 blksize) u32 *tempbuff = src; int i; u64 xfercount = blkcount * blksize; - struct mmc_host *host = dev->priv; + struct pl180_mmc_host *host = dev->priv; u32 status, status_err; debug("write_bytes: blkcount=%u blksize=%u\n", blkcount, blksize); @@ -227,14 +224,19 @@ static int do_data_transfer(struct mmc *dev, struct mmc_data *data) { int error = -ETIMEDOUT; - struct mmc_host *host = dev->priv; + struct pl180_mmc_host *host = dev->priv; u32 blksz = 0; u32 data_ctrl = 0; u32 data_len = (u32) (data->blocks * data->blocksize); - blksz = (ffs(data->blocksize) - 1); - data_ctrl |= ((blksz << 4) & SDI_DCTRL_DBLKSIZE_MASK); - data_ctrl |= SDI_DCTRL_DTEN; + if (!host->version2) { + blksz = (ffs(data->blocksize) - 1); + data_ctrl |= ((blksz << 4) & SDI_DCTRL_DBLKSIZE_MASK); + } else { + blksz = data->blocksize; + data_ctrl |= (blksz << SDI_DCTRL_DBLOCKSIZE_V2_SHIFT); + } + data_ctrl |= SDI_DCTRL_DTEN | SDI_DCTRL_BUSYMODE; writel(SDI_DTIMER_DEFAULT, &host->base->datatimer); writel(data_len, &host->base->datalength); @@ -257,7 +259,7 @@ static int do_data_transfer(struct mmc *dev, writel(data_ctrl, &host->base->datactrl); error = write_bytes(dev, (u32 *)data->src, (u32)data->blocks, - (u32)data->blocksize); + (u32)data->blocksize); } return error; @@ -280,17 +282,16 @@ static int host_request(struct mmc *dev, /* MMC uses open drain drivers in the enumeration phase */ static int mmc_host_reset(struct mmc *dev) { - struct mmc_host *host = dev->priv; - u32 sdi_u32 = SDI_PWR_OPD | SDI_PWR_PWRCTRL_ON; + struct pl180_mmc_host *host = dev->priv; - writel(sdi_u32, &host->base->power); + writel(host->pwr_init, &host->base->power); return 0; } static void host_set_ios(struct mmc *dev) { - struct mmc_host *host = dev->priv; + struct pl180_mmc_host *host = dev->priv; u32 sdi_clkcr; sdi_clkcr = readl(&host->base->clock); @@ -298,15 +299,26 @@ static void host_set_ios(struct mmc *dev) /* Ramp up the clock rate */ if (dev->clock) { u32 clkdiv = 0; + u32 tmp_clock; - if (dev->clock >= dev->f_max) + if (dev->clock >= dev->f_max) { + clkdiv = 0; dev->clock = dev->f_max; + } else { + clkdiv = (host->clock_in / dev->clock) - 2; + } - clkdiv = ((ARM_MCLK / dev->clock) / 2) - 1; + tmp_clock = host->clock_in / (clkdiv + 2); + while (tmp_clock > dev->clock) { + clkdiv++; + tmp_clock = host->clock_in / (clkdiv + 2); + } if (clkdiv > SDI_CLKCR_CLKDIV_MASK) clkdiv = SDI_CLKCR_CLKDIV_MASK; + tmp_clock = host->clock_in / (clkdiv + 2); + dev->clock = tmp_clock; sdi_clkcr &= ~(SDI_CLKCR_CLKDIV_MASK); sdi_clkcr |= clkdiv; } @@ -322,8 +334,11 @@ static void host_set_ios(struct mmc *dev) case 4: buswidth |= SDI_CLKCR_WIDBUS_4; break; + case 8: + buswidth |= SDI_CLKCR_WIDBUS_8; + break; default: - printf("Invalid bus width\n"); + printf("Invalid bus width: %d\n", dev->bus_width); break; } sdi_clkcr &= ~(SDI_CLKCR_WIDBUS_MASK); @@ -334,83 +349,40 @@ static void host_set_ios(struct mmc *dev) udelay(CLK_CHANGE_DELAY); } -struct mmc *alloc_mmc_struct(void) -{ - struct mmc_host *host = NULL; - struct mmc *mmc_device = NULL; - - host = malloc(sizeof(struct mmc_host)); - if (!host) - return NULL; - - mmc_device = malloc(sizeof(struct mmc)); - if (!mmc_device) - goto err; - - mmc_device->priv = host; - return mmc_device; - -err: - free(host); - return NULL; -} - /* * mmc_host_init - initialize the mmc controller. * Set initial clock and power for mmc slot. * Initialize mmc struct and register with mmc framework. */ -static int arm_pl180_mmci_host_init(struct mmc *dev) +int arm_pl180_mmci_init(struct pl180_mmc_host *host) { - struct mmc_host *host = dev->priv; + struct mmc *dev; u32 sdi_u32; - host->base = (struct sdi_registers *)CONFIG_ARM_PL180_MMCI_BASE; + dev = malloc(sizeof(struct mmc)); + if (!dev) + return -ENOMEM; - /* Initially set power-on, full voltage & MMCI read */ - sdi_u32 = INIT_PWR; - writel(sdi_u32, &host->base->power); + memset(dev, 0, sizeof(struct mmc)); + dev->priv = host; - /* setting clk freq 505KHz */ - sdi_u32 = SDI_CLKCR_CLKDIV_INIT | SDI_CLKCR_CLKEN; - writel(sdi_u32, &host->base->clock); + writel(host->pwr_init, &host->base->power); + writel(host->clkdiv_init, &host->base->clock); udelay(CLK_CHANGE_DELAY); /* Disable mmc interrupts */ sdi_u32 = readl(&host->base->mask0) & ~SDI_MASK0_MASK; writel(sdi_u32, &host->base->mask0); - - sprintf(dev->name, "MMC"); - dev->clock = ARM_MCLK / (2 * (SDI_CLKCR_CLKDIV_INIT + 1)); + strncpy(dev->name, host->name, sizeof(dev->name)); dev->send_cmd = host_request; dev->set_ios = host_set_ios; dev->init = mmc_host_reset; dev->getcd = NULL; - dev->host_caps = 0; - dev->voltages = VOLTAGE_WINDOW_MMC; - dev->f_min = dev->clock; - dev->f_max = CONFIG_ARM_PL180_MMCI_CLOCK_FREQ; - - return 0; -} - -int arm_pl180_mmci_init(void) -{ - int error; - struct mmc *dev; - - dev = alloc_mmc_struct(); - if (!dev) - return -1; - - error = arm_pl180_mmci_host_init(dev); - if (error) { - printf("mmci_host_init error - %d\n", error); - return -1; - } - - dev->b_max = 0; - + dev->host_caps = host->caps; + dev->voltages = host->voltages; + dev->f_min = host->clock_min; + dev->f_max = host->clock_max; + dev->b_max = host->b_max; mmc_register(dev); debug("registered mmc interface number is:%d\n", dev->block_dev.dev); diff --git a/drivers/mmc/arm_pl180_mmci.h b/drivers/mmc/arm_pl180_mmci.h index 42fbe3e..06709ed 100644 --- a/drivers/mmc/arm_pl180_mmci.h +++ b/drivers/mmc/arm_pl180_mmci.h @@ -26,8 +26,6 @@ #ifndef __ARM_PL180_MMCI_H__ #define __ARM_PL180_MMCI_H__ -int arm_pl180_mmci_init(void); - #define COMMAND_REG_DELAY 300 #define DATA_REG_DELAY 1000 #define CLK_CHANGE_DELAY 2000 @@ -59,8 +57,13 @@ int arm_pl180_mmci_init(void); #define SDI_CLKCR_WIDBUS_MASK 0x00001800 #define SDI_CLKCR_WIDBUS_1 0x00000000 #define SDI_CLKCR_WIDBUS_4 0x00000800 +/* V2 only */ +#define SDI_CLKCR_WIDBUS_8 0x00001000 +#define SDI_CLKCR_NEDGE 0x00002000 +#define SDI_CLKCR_HWFC_EN 0x00004000 -#define SDI_CLKCR_CLKDIV_INIT 0x000000C6 /* MCLK/(2*(0xC6+1)) => 505KHz */ +#define SDI_CLKCR_CLKDIV_INIT_V1 0x000000C6 /* MCLK/(2*(0xC6+1)) => 505KHz */ +#define SDI_CLKCR_CLKDIV_INIT_V2 0x000000FD /* SDI command register bits */ #define SDI_CMD_CMDINDEX_MASK 0x000000FF @@ -144,6 +147,8 @@ int arm_pl180_mmci_init(void); #define SDI_DCTRL_DBOOTMODEEN 0x00002000 #define SDI_DCTRL_BUSYMODE 0x00004000 #define SDI_DCTRL_DDR_MODE 0x00008000 +#define SDI_DCTRL_DBLOCKSIZE_V2_MASK 0x7fff0000 +#define SDI_DCTRL_DBLOCKSIZE_V2_SHIFT 16 #define SDI_FIFO_BURST_SIZE 8 @@ -180,4 +185,20 @@ struct sdi_registers { u32 pcell_id3; /* 0xFFC*/ }; +struct pl180_mmc_host { + struct sdi_registers *base; + char name[32]; + unsigned int b_max; + unsigned int voltages; + unsigned int caps; + unsigned int clock_in; + unsigned int clock_min; + unsigned int clock_max; + unsigned int clkdiv_init; + unsigned int pwr_init; + int version2; +}; + +int arm_pl180_mmci_init(struct pl180_mmc_host *); + #endif diff --git a/include/configs/snowball.h b/include/configs/snowball.h index e9f4fb1..605ba0e 100644 --- a/include/configs/snowball.h +++ b/include/configs/snowball.h @@ -246,6 +246,14 @@ #endif /* + * MMC related configs + */ +#define CONFIG_ARM_PL180_MMCI +#define MMC_BLOCK_SIZE 512 +#define CFG_EMMC_BASE 0x80114000 +#define CFG_MMC_BASE 0x80126000 + +/* * FLASH and environment organization */ #define CONFIG_SYS_NO_FLASH