video/console: Factor out actual character output
[oweals/u-boot.git] / drivers / mmc / davinci_mmc.c
index 5aa218426f4948eb12f686b0b6099ce58ba9d376..0d63279db00afbb31f23149b1ff3285f9211c1cc 100644 (file)
@@ -1,31 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Davinci MMC Controller Driver
  *
  * Copyright (C) 2010 Texas Instruments Incorporated
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <config.h>
 #include <common.h>
-#include <command.h>
+#include <dm.h>
+#include <errno.h>
 #include <mmc.h>
+#include <command.h>
 #include <part.h>
 #include <malloc.h>
 #include <asm/io.h>
 #include <asm/arch/sdmmc_defs.h>
+#include <asm-generic/gpio.h>
 
 #define DAVINCI_MAX_BLOCKS     (32)
 #define WATCHDOG_COUNT         (100000)
 #define set_bit(addr, val)     set_val((addr), (get_val(addr) | (val)))
 #define clear_bit(addr, val)   set_val((addr), (get_val(addr) & ~(val)))
 
+#ifdef CONFIG_DM_MMC
+struct davinci_of_data {
+       const char *name;
+       u8 version;
+};
+
+/* Davinci MMC board definitions */
+struct davinci_mmc_priv {
+       struct davinci_mmc_regs *reg_base;      /* Register base address */
+       uint input_clk;         /* Input clock to MMC controller */
+       uint version;           /* MMC Controller version */
+       struct gpio_desc cd_gpio;       /* Card Detect GPIO */
+       struct gpio_desc wp_gpio;       /* Write Protect GPIO */
+};
+
+struct davinci_mmc_plat
+{
+       struct mmc_config cfg;
+       struct mmc mmc;
+};
+#endif
+
 /* Set davinci clock prescalar value based on the required clock in HZ */
+#if !CONFIG_IS_ENABLED(DM_MMC)
 static void dmmc_set_clock(struct mmc *mmc, uint clock)
 {
        struct davinci_mmc *host = mmc->priv;
+#else
+
+static void davinci_mmc_set_clock(struct udevice *dev, uint clock)
+{
+       struct davinci_mmc_priv *host = dev_get_priv(dev);
+        struct mmc *mmc = mmc_get_mmc_dev(dev);
+#endif
        struct davinci_mmc_regs *regs = host->reg_base;
        uint clkrt, sysclk2, act_clock;
 
-       if (clock < mmc->f_min)
-               clock = mmc->f_min;
-       if (clock > mmc->f_max)
-               clock = mmc->f_max;
+       if (clock < mmc->cfg->f_min)
+               clock = mmc->cfg->f_min;
+       if (clock > mmc->cfg->f_max)
+               clock = mmc->cfg->f_max;
 
        set_val(&regs->mmcclk, 0);
        sysclk2 = host->input_clk;
@@ -78,7 +98,7 @@ dmmc_wait_fifo_status(volatile struct davinci_mmc_regs *regs, uint status)
                udelay(100);
 
        if (wdog == 0)
-               return COMM_ERR;
+               return -ECOMM;
 
        return 0;
 }
@@ -92,7 +112,7 @@ static int dmmc_busy_wait(volatile struct davinci_mmc_regs *regs)
                udelay(10);
 
        if (wdog == 0)
-               return COMM_ERR;
+               return -ECOMM;
 
        return 0;
 }
@@ -111,7 +131,7 @@ static int dmmc_check_status(volatile struct davinci_mmc_regs *regs,
                        return 0;
                } else if (mmcstatus & st_error) {
                        if (mmcstatus & MMCST0_TOUTRS)
-                               return TIMEOUT;
+                               return -ETIMEDOUT;
                        printf("[ ST0 ERROR %x]\n", mmcstatus);
                        /*
                         * Ignore CRC errors as some MMC cards fail to
@@ -119,7 +139,7 @@ static int dmmc_check_status(volatile struct davinci_mmc_regs *regs,
                         */
                        if (mmcstatus & MMCST0_CRCRS)
                                return 0;
-                       return COMM_ERR;
+                       return -ECOMM;
                }
                udelay(10);
 
@@ -128,17 +148,23 @@ static int dmmc_check_status(volatile struct davinci_mmc_regs *regs,
 
        printf("Status %x Timeout ST0:%x ST1:%x\n", st_ready, mmcstatus,
                        get_val(&regs->mmcst1));
-       return COMM_ERR;
+       return -ECOMM;
 }
 
 /*
- * Sends a command out on the bus.  Takes the mmc pointer,
+ * Sends a command out on the bus.  Takes the device pointer,
  * a command pointer, and an optional data pointer.
  */
-static int
-dmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
+#if !CONFIG_IS_ENABLED(DM_MMC)
+static int dmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
 {
        struct davinci_mmc *host = mmc->priv;
+#else
+static int
+davinci_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, struct mmc_data *data)
+{
+       struct davinci_mmc_priv *host = dev_get_priv(dev);
+#endif
        volatile struct davinci_mmc_regs *regs = host->reg_base;
        uint mmcstatus, status_rdy, status_err;
        uint i, cmddata, bytes_left = 0;
@@ -324,9 +350,15 @@ dmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
 }
 
 /* Initialize Davinci MMC controller */
+#if !CONFIG_IS_ENABLED(DM_MMC)
 static int dmmc_init(struct mmc *mmc)
 {
        struct davinci_mmc *host = mmc->priv;
+#else
+static int davinci_dm_mmc_init(struct udevice *dev)
+{
+       struct davinci_mmc_priv *host = dev_get_priv(dev);
+#endif
        struct davinci_mmc_regs *regs = host->reg_base;
 
        /* Clear status registers explicitly - soft reset doesn't clear it
@@ -358,12 +390,20 @@ static int dmmc_init(struct mmc *mmc)
        return 0;
 }
 
-/* Set buswidth or clock as indicated by the GENERIC_MMC framework */
-static void dmmc_set_ios(struct mmc *mmc)
+/* Set buswidth or clock as indicated by the MMC framework */
+#if !CONFIG_IS_ENABLED(DM_MMC)
+static int dmmc_set_ios(struct mmc *mmc)
 {
        struct davinci_mmc *host = mmc->priv;
        struct davinci_mmc_regs *regs = host->reg_base;
+#else
+static int davinci_mmc_set_ios(struct udevice *dev)
+{
+       struct mmc *mmc = mmc_get_mmc_dev(dev);
 
+       struct davinci_mmc_priv *host = dev_get_priv(dev);
+       struct davinci_mmc_regs *regs = host->reg_base;
+#endif
        /* Set the bus width */
        if (mmc->bus_width == 4)
                set_bit(&regs->mmcctl, MMCCTL_WIDTH_4_BIT);
@@ -371,36 +411,158 @@ static void dmmc_set_ios(struct mmc *mmc)
                clear_bit(&regs->mmcctl, MMCCTL_WIDTH_4_BIT);
 
        /* Set clock speed */
-       if (mmc->clock)
+       if (mmc->clock) {
+#if !CONFIG_IS_ENABLED(DM_MMC)
                dmmc_set_clock(mmc, mmc->clock);
+#else
+               davinci_mmc_set_clock(dev, mmc->clock);
+#endif
+       }
+       return 0;
+}
+
+#if !CONFIG_IS_ENABLED(DM_MMC)
+static const struct mmc_ops dmmc_ops = {
+       .send_cmd       = dmmc_send_cmd,
+       .set_ios        = dmmc_set_ios,
+       .init           = dmmc_init,
+};
+#else
+
+static int davinci_mmc_getcd(struct udevice *dev)
+{
+       int value = -1;
+#if CONFIG_IS_ENABLED(DM_GPIO)
+       struct davinci_mmc_priv *priv = dev_get_priv(dev);
+       value = dm_gpio_get_value(&priv->cd_gpio);
+#endif
+       /* if no CD return as 1 */
+       if (value < 0)
+               return 1;
+
+       return value;
+}
+
+static int davinci_mmc_getwp(struct udevice *dev)
+{
+       int value = -1;
+#if CONFIG_IS_ENABLED(DM_GPIO)
+       struct davinci_mmc_priv *priv = dev_get_priv(dev);
+
+       value = dm_gpio_get_value(&priv->wp_gpio);
+#endif
+       /* if no WP return as 0 */
+       if (value < 0)
+               return 0;
+
+       return value;
 }
 
+static const struct dm_mmc_ops davinci_mmc_ops = {
+       .send_cmd       = davinci_mmc_send_cmd,
+       .set_ios        = davinci_mmc_set_ios,
+       .get_cd         = davinci_mmc_getcd,
+       .get_wp         = davinci_mmc_getwp,
+};
+#endif
+
+#if !CONFIG_IS_ENABLED(DM_MMC)
 /* Called from board_mmc_init during startup. Can be called multiple times
- * depending on the number of slots available on board and controller
- */
+* depending on the number of slots available on board and controller
+*/
 int davinci_mmc_init(bd_t *bis, struct davinci_mmc *host)
 {
-       struct mmc *mmc;
+       host->cfg.name = "davinci";
+       host->cfg.ops = &dmmc_ops;
+       host->cfg.f_min = 200000;
+       host->cfg.f_max = 25000000;
+       host->cfg.voltages = host->voltages;
+       host->cfg.host_caps = host->host_caps;
 
-       mmc = malloc(sizeof(struct mmc));
-       memset(mmc, 0, sizeof(struct mmc));
+       host->cfg.b_max = DAVINCI_MAX_BLOCKS;
 
-       sprintf(mmc->name, "davinci");
-       mmc->priv = host;
-       mmc->send_cmd = dmmc_send_cmd;
-       mmc->set_ios = dmmc_set_ios;
-       mmc->init = dmmc_init;
-       mmc->getcd = NULL;
-       mmc->getwp = NULL;
+       mmc_create(&host->cfg, host);
 
-       mmc->f_min = 200000;
-       mmc->f_max = 25000000;
-       mmc->voltages = host->voltages;
-       mmc->host_caps = host->host_caps;
+       return 0;
+}
+#else
 
-       mmc->b_max = DAVINCI_MAX_BLOCKS;
 
-       mmc_register(mmc);
+static int davinci_mmc_probe(struct udevice *dev)
+{
+       struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+       struct davinci_mmc_plat *plat = dev_get_platdata(dev);
+       struct davinci_mmc_priv *priv = dev_get_priv(dev);
+       struct mmc_config *cfg = &plat->cfg;
+       struct davinci_of_data *data =
+                       (struct davinci_of_data *)dev_get_driver_data(dev);
+       cfg->f_min = 200000;
+       cfg->f_max = 25000000;
+       cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34,
+       cfg->host_caps = MMC_MODE_4BIT, /* DA850 supports only 4-bit SD/MMC */
+       cfg->b_max = DAVINCI_MAX_BLOCKS;
 
-       return 0;
+       if (data) {
+               cfg->name = data->name;
+               priv->version = data->version;
+       }
+
+       priv->reg_base = (struct davinci_mmc_regs *)dev_read_addr(dev);
+       priv->input_clk = clk_get(DAVINCI_MMCSD_CLKID);
+
+#if CONFIG_IS_ENABLED(DM_GPIO)
+       /* These GPIOs are optional */
+       gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio, GPIOD_IS_IN);
+       gpio_request_by_name(dev, "wp-gpios", 0, &priv->wp_gpio, GPIOD_IS_IN);
+#endif
+
+       upriv->mmc = &plat->mmc;
+
+       return davinci_dm_mmc_init(dev);
 }
+
+static int davinci_mmc_bind(struct udevice *dev)
+{
+       struct davinci_mmc_plat *plat = dev_get_platdata(dev);
+
+       return mmc_bind(dev, &plat->mmc, &plat->cfg);
+}
+
+
+const struct davinci_of_data davinci_mmc_host_info[] = {
+       {
+               .name   = "dm6441-mmc",
+               .version = MMC_CTLR_VERSION_1,
+       },
+       {
+               .name   = "da830-mmc",
+               .version = MMC_CTLR_VERSION_2,
+       },
+       {},
+};
+
+static const struct udevice_id davinci_mmc_ids[] = {
+       {
+               .compatible = "ti,dm6441-mmc",
+               .data = (ulong) &davinci_mmc_host_info[MMC_CTLR_VERSION_1]
+       },
+       {
+               .compatible = "ti,da830-mmc",
+               .data = (ulong) &davinci_mmc_host_info[MMC_CTLR_VERSION_2]
+       },
+       {},
+};
+
+U_BOOT_DRIVER(davinci_mmc_drv) = {
+       .name = "davinci_mmc",
+       .id             = UCLASS_MMC,
+       .of_match       = davinci_mmc_ids,
+#if CONFIG_BLK
+       .bind           = davinci_mmc_bind,
+#endif
+       .probe = davinci_mmc_probe,
+       .ops = &davinci_mmc_ops,
+       .platdata_auto_alloc_size = sizeof(struct davinci_mmc_plat),
+       .priv_auto_alloc_size = sizeof(struct davinci_mmc_priv),
+};
+#endif