X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=drivers%2Fmmc%2Ftegra_mmc.c;h=3d0845e31735acc0bb83fa973908ca7d876c529a;hb=da968c7bfa4cc1203a4f9f61a97f55c85dfbb3b6;hp=2cd8cf10aec557cc3a3579f3e292d9ee3f686e90;hpb=358b8bc204f365be28fed94f23e53e04183a8c7f;p=karo-tx-uboot.git diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c index 2cd8cf10ae..3d0845e317 100644 --- a/drivers/mmc/tegra_mmc.c +++ b/drivers/mmc/tegra_mmc.c @@ -2,26 +2,39 @@ * (C) Copyright 2009 SAMSUNG Electronics * Minkyu Kang * Jaehoon Chung - * Portions Copyright 2011-2013 NVIDIA Corporation + * Portions Copyright 2011-2015 NVIDIA Corporation * * SPDX-License-Identifier: GPL-2.0+ */ #include #include +#include +#include #include #include +#ifndef CONFIG_TEGRA186 #include #include +#endif #include #include #include +/* + * FIXME: TODO: This driver contains a number of ifdef CONFIG_TEGRA186 that + * should not be present. These are needed because newer Tegra SoCs support + * only the standard clock/reset APIs, whereas older Tegra SoCs support only + * a custom Tegra-specific API. ASAP the older Tegra SoCs' code should be + * fixed to implement the standard APIs, and all drivers converted to solely + * use the new standard APIs, with no ifdefs. + */ + DECLARE_GLOBAL_DATA_PTR; struct mmc_host mmc_host[CONFIG_SYS_MMC_MAX_DEVICE]; -#ifndef CONFIG_OF_CONTROL +#if !CONFIG_IS_ENABLED(OF_CONTROL) #error "Please enable device tree support to use this driver" #endif @@ -67,7 +80,7 @@ static void mmc_prepare_data(struct mmc_host *host, struct mmc_data *data, bbstate->bounce_buffer, bbstate->user_buffer, data->blocks, data->blocksize); - writel((u32)bbstate->bounce_buffer, &host->reg->sysad); + writel((u32)(unsigned long)bbstate->bounce_buffer, &host->reg->sysad); /* * DMASEL[4:3] * 00 = Selects SDMA @@ -214,14 +227,14 @@ static int mmc_send_cmd_bounced(struct mmc *mmc, struct mmc_cmd *cmd, if (i == retry) { printf("%s: waiting for status update\n", __func__); writel(mask, &host->reg->norintsts); - return TIMEOUT; + return -ETIMEDOUT; } if (mask & TEGRA_MMC_NORINTSTS_CMD_TIMEOUT) { /* Timeout Error */ debug("timeout: %08x cmd %d\n", mask, cmd->cmdidx); writel(mask, &host->reg->norintsts); - return TIMEOUT; + return -ETIMEDOUT; } else if (mask & TEGRA_MMC_NORINTSTS_ERR_INTERRUPT) { /* Error Interrupt */ debug("error: %08x cmd %d\n", mask, cmd->cmdidx); @@ -233,8 +246,8 @@ static int mmc_send_cmd_bounced(struct mmc *mmc, struct mmc_cmd *cmd, 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); + unsigned long offset = + (unsigned long)(&host->reg->rspreg3 - i); cmd->response[i] = readl(offset) << 8; if (i != 3) { @@ -255,7 +268,7 @@ static int mmc_send_cmd_bounced(struct mmc *mmc, struct mmc_cmd *cmd, if (i == retry) { printf("%s: card is still busy\n", __func__); writel(mask, &host->reg->norintsts); - return TIMEOUT; + return -ETIMEDOUT; } cmd->response[0] = readl(&host->reg->rspreg0); @@ -357,8 +370,15 @@ static void mmc_change_clock(struct mmc_host *host, uint clock) */ if (clock == 0) goto out; +#ifdef CONFIG_TEGRA186 + { + ulong rate = clk_set_rate(&host->clk, clock); + div = (rate + clock - 1) / clock; + } +#else clock_adjust_periph_pll_div(host->mmc_id, CLOCK_ID_PERIPH, clock, &div); +#endif debug("div = %d\n", div); writew(0, &host->reg->clkcon); @@ -528,10 +548,13 @@ static const struct mmc_ops tegra_mmc_ops = { .getcd = tegra_mmc_getcd, }; -static int do_mmc_init(int dev_index) +static int do_mmc_init(int dev_index, bool removable) { struct mmc_host *host; struct mmc *mmc; +#ifdef CONFIG_TEGRA186 + int ret; +#endif /* DT should have been read & host config filled in */ host = &mmc_host[dev_index]; @@ -543,7 +566,23 @@ static int do_mmc_init(int dev_index) gpio_get_number(&host->cd_gpio)); host->clock = 0; + +#ifdef CONFIG_TEGRA186 + ret = reset_assert(&host->reset_ctl); + if (ret) + return ret; + ret = clk_enable(&host->clk); + if (ret) + return ret; + ret = clk_set_rate(&host->clk, 20000000); + if (IS_ERR_VALUE(ret)) + return ret; + ret = reset_deassert(&host->reset_ctl); + if (ret) + return ret; +#else clock_start_periph_pll(host->mmc_id, CLOCK_ID_PERIPH, 20000000); +#endif if (dm_gpio_is_valid(&host->pwr_gpio)) dm_gpio_set_value(&host->pwr_gpio, 1); @@ -559,7 +598,7 @@ static int do_mmc_init(int dev_index) host->cfg.host_caps |= MMC_MODE_8BIT; if (host->width >= 4) host->cfg.host_caps |= MMC_MODE_4BIT; - host->cfg.host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS | MMC_MODE_HC; + host->cfg.host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; /* * min freq is for card identification, and is the highest @@ -573,6 +612,7 @@ static int do_mmc_init(int dev_index) host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; mmc = mmc_create(&host->cfg, host); + mmc->block_dev.removable = removable; if (mmc == NULL) return -1; @@ -586,7 +626,8 @@ static int do_mmc_init(int dev_index) * @param node Device index (0-3) * @param host Structure to fill in (reg, width, mmc_id) */ -static int mmc_get_config(const void *blob, int node, struct mmc_host *host) +static int mmc_get_config(const void *blob, int node, struct mmc_host *host, + bool *removablep) { debug("%s: node = %d\n", __func__, node); @@ -598,11 +639,33 @@ static int mmc_get_config(const void *blob, int node, struct mmc_host *host) return -FDT_ERR_NOTFOUND; } +#ifdef CONFIG_TEGRA186 + { + /* + * FIXME: This variable should go away when the MMC device + * actually is a udevice. + */ + struct udevice dev; + int ret; + dev.of_offset = node; + ret = reset_get_by_name(&dev, "sdhci", &host->reset_ctl); + if (ret) { + debug("reset_get_by_name() failed: %d\n", ret); + return ret; + } + ret = clk_get_by_index(&dev, 0, &host->clk); + if (ret) { + debug("clk_get_by_index() failed: %d\n", ret); + return ret; + } + } +#else host->mmc_id = clock_decode_periph_id(blob, node); if (host->mmc_id == PERIPH_ID_NONE) { debug("%s: could not decode periph id\n", __func__); return -FDT_ERR_NOTFOUND; } +#endif /* * NOTE: mmc->bus_width is determined by mmc.c dynamically. @@ -619,9 +682,16 @@ static int mmc_get_config(const void *blob, int node, struct mmc_host *host) GPIOD_IS_IN); gpio_request_by_name_nodev(blob, node, "power-gpios", 0, &host->pwr_gpio, GPIOD_IS_OUT); + *removablep = !fdtdec_get_bool(blob, node, "non-removable"); debug("%s: found controller at %p, width = %d, periph_id = %d\n", - __func__, host->reg, host->width, host->mmc_id); + __func__, host->reg, host->width, +#ifndef CONFIG_TEGRA186 + host->mmc_id +#else + -1 +#endif + ); return 0; } @@ -636,6 +706,7 @@ static int mmc_get_config(const void *blob, int node, struct mmc_host *host) static int process_nodes(const void *blob, int node_list[], int count) { struct mmc_host *host; + bool removable; int i, node; debug("%s: count = %d\n", __func__, count); @@ -649,11 +720,11 @@ static int process_nodes(const void *blob, int node_list[], int count) host = &mmc_host[i]; host->id = i; - if (mmc_get_config(blob, node, host)) { + if (mmc_get_config(blob, node, host, &removable)) { printf("%s: failed to decode dev %d\n", __func__, i); return -1; } - do_mmc_init(i); + do_mmc_init(i, removable); } return 0; } @@ -664,13 +735,33 @@ void tegra_mmc_init(void) const void *blob = gd->fdt_blob; debug("%s entry\n", __func__); + /* See if any Tegra186 MMC controllers are present */ + count = fdtdec_find_aliases_for_id(blob, "sdhci", + COMPAT_NVIDIA_TEGRA186_SDMMC, node_list, + CONFIG_SYS_MMC_MAX_DEVICE); + debug("%s: count of Tegra186 sdhci nodes is %d\n", __func__, count); + if (process_nodes(blob, node_list, count)) { + printf("%s: Error processing T186 mmc node(s)!\n", __func__); + return; + } + + /* See if any Tegra210 MMC controllers are present */ + count = fdtdec_find_aliases_for_id(blob, "sdhci", + COMPAT_NVIDIA_TEGRA210_SDMMC, node_list, + CONFIG_SYS_MMC_MAX_DEVICE); + debug("%s: count of Tegra210 sdhci nodes is %d\n", __func__, count); + if (process_nodes(blob, node_list, count)) { + printf("%s: Error processing T210 mmc node(s)!\n", __func__); + return; + } + /* See if any Tegra124 MMC controllers are present */ count = fdtdec_find_aliases_for_id(blob, "sdhci", COMPAT_NVIDIA_TEGRA124_SDMMC, node_list, CONFIG_SYS_MMC_MAX_DEVICE); debug("%s: count of Tegra124 sdhci nodes is %d\n", __func__, count); if (process_nodes(blob, node_list, count)) { - printf("%s: Error processing T30 mmc node(s)!\n", __func__); + printf("%s: Error processing T124 mmc node(s)!\n", __func__); return; }