X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=drivers%2Fmmc%2Ftegra_mmc.c;h=08b4bd48245a3166a982ec974cf9bfa33950d4a1;hb=67748a73b14b239283bc1ace7564a124b714b75e;hp=ca9c4aa15feea77686f8d5e87b7f24bdb8e1be89;hpb=44cfc3a83f2a62963af2de8d983daf4c77e1db0c;p=karo-tx-uboot.git diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c index ca9c4aa15f..08b4bd4824 100644 --- a/drivers/mmc/tegra_mmc.c +++ b/drivers/mmc/tegra_mmc.c @@ -2,25 +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 @@ -66,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 @@ -213,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); @@ -232,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) { @@ -254,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); @@ -292,7 +306,7 @@ static int mmc_send_cmd_bounced(struct mmc *mmc, struct mmc_cmd *cmd, /* Transfer Complete */ debug("r/w is done\n"); break; - } else if (get_timer(start) > 2000UL) { + } else if (get_timer(start) > 8000UL) { writel(mask, &host->reg->norintsts); printf("%s: MMC Timeout\n" " Interrupt status 0x%08x\n" @@ -356,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); @@ -508,14 +529,14 @@ static int tegra_mmc_core_init(struct mmc *mmc) return 0; } -int tegra_mmc_getcd(struct mmc *mmc) +static int tegra_mmc_getcd(struct mmc *mmc) { struct mmc_host *host = mmc->priv; debug("tegra_mmc_getcd called\n"); - if (fdt_gpio_isvalid(&host->cd_gpio)) - return fdtdec_get_gpio(&host->cd_gpio); + if (dm_gpio_is_valid(&host->cd_gpio)) + return dm_gpio_get_value(&host->cd_gpio); return 1; } @@ -527,38 +548,44 @@ 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; - char gpusage[12]; /* "SD/MMCn PWR" or "SD/MMCn CD" */ struct mmc *mmc; +#ifdef CONFIG_TEGRA186 + int ret; +#endif /* DT should have been read & host config filled in */ host = &mmc_host[dev_index]; if (!host->enabled) return -1; - debug(" do_mmc_init: index %d, bus width %d " - "pwr_gpio %d cd_gpio %d\n", - dev_index, host->width, - host->pwr_gpio.gpio, host->cd_gpio.gpio); + debug(" do_mmc_init: index %d, bus width %d pwr_gpio %d cd_gpio %d\n", + dev_index, host->width, gpio_get_number(&host->pwr_gpio), + 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 (fdt_gpio_isvalid(&host->pwr_gpio)) { - sprintf(gpusage, "SD/MMC%d PWR", dev_index); - gpio_request(host->pwr_gpio.gpio, gpusage); - gpio_direction_output(host->pwr_gpio.gpio, 1); - debug(" Power GPIO name = %s\n", host->pwr_gpio.name); - } - - if (fdt_gpio_isvalid(&host->cd_gpio)) { - sprintf(gpusage, "SD/MMC%d CD", dev_index); - gpio_request(host->cd_gpio.gpio, gpusage); - gpio_direction_input(host->cd_gpio.gpio); - debug(" CD GPIO name = %s\n", host->cd_gpio.name); - } + if (dm_gpio_is_valid(&host->pwr_gpio)) + dm_gpio_set_value(&host->pwr_gpio, 1); memset(&host->cfg, 0, sizeof(host->cfg)); @@ -571,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 @@ -585,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; @@ -598,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); @@ -610,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. @@ -625,12 +676,22 @@ static int mmc_get_config(const void *blob, int node, struct mmc_host *host) debug("%s: no sdmmc width found\n", __func__); /* These GPIOs are optional */ - fdtdec_decode_gpio(blob, node, "cd-gpios", &host->cd_gpio); - fdtdec_decode_gpio(blob, node, "wp-gpios", &host->wp_gpio); - fdtdec_decode_gpio(blob, node, "power-gpios", &host->pwr_gpio); + gpio_request_by_name_nodev(blob, node, "cd-gpios", 0, &host->cd_gpio, + GPIOD_IS_IN); + gpio_request_by_name_nodev(blob, node, "wp-gpios", 0, &host->wp_gpio, + 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; } @@ -645,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); @@ -658,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; } @@ -673,18 +735,38 @@ 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, "mmc", + 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, "mmc", + 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", + count = fdtdec_find_aliases_for_id(blob, "mmc", 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; } /* See if any Tegra30 MMC controllers are present */ - count = fdtdec_find_aliases_for_id(blob, "sdhci", + count = fdtdec_find_aliases_for_id(blob, "mmc", COMPAT_NVIDIA_TEGRA30_SDMMC, node_list, CONFIG_SYS_MMC_MAX_DEVICE); debug("%s: count of T30 sdhci nodes is %d\n", __func__, count); @@ -694,7 +776,7 @@ void tegra_mmc_init(void) } /* Now look for any Tegra20 MMC controllers */ - count = fdtdec_find_aliases_for_id(blob, "sdhci", + count = fdtdec_find_aliases_for_id(blob, "mmc", COMPAT_NVIDIA_TEGRA20_SDMMC, node_list, CONFIG_SYS_MMC_MAX_DEVICE); debug("%s: count of T20 sdhci nodes is %d\n", __func__, count);