Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2013 - 2015 Fujitsu Semiconductor, Ltd
0004  *              Vincent Yang <vincent.yang@tw.fujitsu.com>
0005  * Copyright (C) 2015 Linaro Ltd  Andy Green <andy.green@linaro.org>
0006  * Copyright (C) 2019 Socionext Inc.
0007  *              Takao Orito <orito.takao@socionext.com>
0008  */
0009 
0010 #include <linux/bits.h>
0011 #include <linux/clk.h>
0012 #include <linux/delay.h>
0013 #include <linux/err.h>
0014 #include <linux/gpio/consumer.h>
0015 #include <linux/module.h>
0016 #include <linux/of.h>
0017 #include <linux/property.h>
0018 
0019 #include "sdhci-pltfm.h"
0020 #include "sdhci_f_sdh30.h"
0021 
0022 /* milbeaut bridge controller register */
0023 #define MLB_SOFT_RESET      0x0200
0024 #define  MLB_SOFT_RESET_RSTX        BIT(0)
0025 
0026 #define MLB_WP_CD_LED_SET   0x0210
0027 #define  MLB_WP_CD_LED_SET_LED_INV  BIT(2)
0028 
0029 #define MLB_CR_SET          0x0220
0030 #define  MLB_CR_SET_CR_TOCLKUNIT       BIT(24)
0031 #define  MLB_CR_SET_CR_TOCLKFREQ_SFT   (16)
0032 #define  MLB_CR_SET_CR_TOCLKFREQ_MASK  (0x3F << MLB_CR_SET_CR_TOCLKFREQ_SFT)
0033 #define  MLB_CR_SET_CR_BCLKFREQ_SFT    (8)
0034 #define  MLB_CR_SET_CR_BCLKFREQ_MASK   (0xFF << MLB_CR_SET_CR_BCLKFREQ_SFT)
0035 #define  MLB_CR_SET_CR_RTUNTIMER_SFT   (4)
0036 #define  MLB_CR_SET_CR_RTUNTIMER_MASK  (0xF << MLB_CR_SET_CR_RTUNTIMER_SFT)
0037 
0038 #define MLB_SD_TOCLK_I_DIV  16
0039 #define MLB_TOCLKFREQ_UNIT_THRES    16000000
0040 #define MLB_CAL_TOCLKFREQ_MHZ(rate) (rate / MLB_SD_TOCLK_I_DIV / 1000000)
0041 #define MLB_CAL_TOCLKFREQ_KHZ(rate) (rate / MLB_SD_TOCLK_I_DIV / 1000)
0042 #define MLB_TOCLKFREQ_MAX   63
0043 #define MLB_TOCLKFREQ_MIN    1
0044 
0045 #define MLB_SD_BCLK_I_DIV   4
0046 #define MLB_CAL_BCLKFREQ(rate)  (rate / MLB_SD_BCLK_I_DIV / 1000000)
0047 #define MLB_BCLKFREQ_MAX        255
0048 #define MLB_BCLKFREQ_MIN          1
0049 
0050 #define MLB_CDR_SET         0x0230
0051 #define MLB_CDR_SET_CLK2POW16   3
0052 
0053 struct f_sdhost_priv {
0054     struct clk *clk_iface;
0055     struct clk *clk;
0056     struct device *dev;
0057     bool enable_cmd_dat_delay;
0058 };
0059 
0060 static void sdhci_milbeaut_soft_voltage_switch(struct sdhci_host *host)
0061 {
0062     u32 ctrl = 0;
0063 
0064     usleep_range(2500, 3000);
0065     ctrl = sdhci_readl(host, F_SDH30_IO_CONTROL2);
0066     ctrl |= F_SDH30_CRES_O_DN;
0067     sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2);
0068     ctrl |= F_SDH30_MSEL_O_1_8;
0069     sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2);
0070 
0071     ctrl &= ~F_SDH30_CRES_O_DN;
0072     sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2);
0073     usleep_range(2500, 3000);
0074 
0075     ctrl = sdhci_readl(host, F_SDH30_TUNING_SETTING);
0076     ctrl |= F_SDH30_CMD_CHK_DIS;
0077     sdhci_writel(host, ctrl, F_SDH30_TUNING_SETTING);
0078 }
0079 
0080 static unsigned int sdhci_milbeaut_get_min_clock(struct sdhci_host *host)
0081 {
0082     return F_SDH30_MIN_CLOCK;
0083 }
0084 
0085 static void sdhci_milbeaut_reset(struct sdhci_host *host, u8 mask)
0086 {
0087     struct f_sdhost_priv *priv = sdhci_priv(host);
0088     u16 clk;
0089     u32 ctl;
0090     ktime_t timeout;
0091 
0092     clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
0093     clk = (clk & ~SDHCI_CLOCK_CARD_EN) | SDHCI_CLOCK_INT_EN;
0094     sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
0095 
0096     sdhci_reset(host, mask);
0097 
0098     clk |= SDHCI_CLOCK_CARD_EN;
0099     sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
0100 
0101     timeout = ktime_add_ms(ktime_get(), 10);
0102     while (1) {
0103         bool timedout = ktime_after(ktime_get(), timeout);
0104 
0105         clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
0106         if (clk & SDHCI_CLOCK_INT_STABLE)
0107             break;
0108         if (timedout) {
0109             pr_err("%s: Internal clock never stabilised.\n",
0110                 mmc_hostname(host->mmc));
0111             sdhci_dumpregs(host);
0112             return;
0113         }
0114         udelay(10);
0115     }
0116 
0117     if (priv->enable_cmd_dat_delay) {
0118         ctl = sdhci_readl(host, F_SDH30_ESD_CONTROL);
0119         ctl |= F_SDH30_CMD_DAT_DELAY;
0120         sdhci_writel(host, ctl, F_SDH30_ESD_CONTROL);
0121     }
0122 }
0123 
0124 static const struct sdhci_ops sdhci_milbeaut_ops = {
0125     .voltage_switch = sdhci_milbeaut_soft_voltage_switch,
0126     .get_min_clock = sdhci_milbeaut_get_min_clock,
0127     .reset = sdhci_milbeaut_reset,
0128     .set_clock = sdhci_set_clock,
0129     .set_bus_width = sdhci_set_bus_width,
0130     .set_uhs_signaling = sdhci_set_uhs_signaling,
0131     .set_power = sdhci_set_power_and_bus_voltage,
0132 };
0133 
0134 static void sdhci_milbeaut_bridge_reset(struct sdhci_host *host,
0135                         int reset_flag)
0136 {
0137     if (reset_flag)
0138         sdhci_writel(host, 0, MLB_SOFT_RESET);
0139     else
0140         sdhci_writel(host, MLB_SOFT_RESET_RSTX, MLB_SOFT_RESET);
0141 }
0142 
0143 static void sdhci_milbeaut_bridge_init(struct sdhci_host *host,
0144                         int rate)
0145 {
0146     u32 val, clk;
0147 
0148     /* IO_SDIO_CR_SET should be set while reset */
0149     val = sdhci_readl(host, MLB_CR_SET);
0150     val &= ~(MLB_CR_SET_CR_TOCLKFREQ_MASK | MLB_CR_SET_CR_TOCLKUNIT |
0151             MLB_CR_SET_CR_BCLKFREQ_MASK);
0152     if (rate >= MLB_TOCLKFREQ_UNIT_THRES) {
0153         clk = MLB_CAL_TOCLKFREQ_MHZ(rate);
0154         clk = min_t(u32, MLB_TOCLKFREQ_MAX, clk);
0155         val |= MLB_CR_SET_CR_TOCLKUNIT |
0156             (clk << MLB_CR_SET_CR_TOCLKFREQ_SFT);
0157     } else {
0158         clk = MLB_CAL_TOCLKFREQ_KHZ(rate);
0159         clk = min_t(u32, MLB_TOCLKFREQ_MAX, clk);
0160         clk = max_t(u32, MLB_TOCLKFREQ_MIN, clk);
0161         val |= clk << MLB_CR_SET_CR_TOCLKFREQ_SFT;
0162     }
0163 
0164     clk = MLB_CAL_BCLKFREQ(rate);
0165     clk = min_t(u32, MLB_BCLKFREQ_MAX, clk);
0166     clk = max_t(u32, MLB_BCLKFREQ_MIN, clk);
0167     val |=  clk << MLB_CR_SET_CR_BCLKFREQ_SFT;
0168     val &= ~MLB_CR_SET_CR_RTUNTIMER_MASK;
0169     sdhci_writel(host, val, MLB_CR_SET);
0170 
0171     sdhci_writel(host, MLB_CDR_SET_CLK2POW16, MLB_CDR_SET);
0172 
0173     sdhci_writel(host, MLB_WP_CD_LED_SET_LED_INV, MLB_WP_CD_LED_SET);
0174 }
0175 
0176 static void sdhci_milbeaut_vendor_init(struct sdhci_host *host)
0177 {
0178     struct f_sdhost_priv *priv = sdhci_priv(host);
0179     u32 ctl;
0180 
0181     ctl = sdhci_readl(host, F_SDH30_IO_CONTROL2);
0182     ctl |= F_SDH30_CRES_O_DN;
0183     sdhci_writel(host, ctl, F_SDH30_IO_CONTROL2);
0184     ctl &= ~F_SDH30_MSEL_O_1_8;
0185     sdhci_writel(host, ctl, F_SDH30_IO_CONTROL2);
0186     ctl &= ~F_SDH30_CRES_O_DN;
0187     sdhci_writel(host, ctl, F_SDH30_IO_CONTROL2);
0188 
0189     ctl = sdhci_readw(host, F_SDH30_AHB_CONFIG);
0190     ctl |= F_SDH30_SIN | F_SDH30_AHB_INCR_16 | F_SDH30_AHB_INCR_8 |
0191            F_SDH30_AHB_INCR_4;
0192     ctl &= ~(F_SDH30_AHB_BIGED | F_SDH30_BUSLOCK_EN);
0193     sdhci_writew(host, ctl, F_SDH30_AHB_CONFIG);
0194 
0195     if (priv->enable_cmd_dat_delay) {
0196         ctl = sdhci_readl(host, F_SDH30_ESD_CONTROL);
0197         ctl |= F_SDH30_CMD_DAT_DELAY;
0198         sdhci_writel(host, ctl, F_SDH30_ESD_CONTROL);
0199     }
0200 }
0201 
0202 static const struct of_device_id mlb_dt_ids[] = {
0203     {
0204         .compatible = "socionext,milbeaut-m10v-sdhci-3.0",
0205     },
0206     { /* sentinel */ }
0207 };
0208 MODULE_DEVICE_TABLE(of, mlb_dt_ids);
0209 
0210 static void sdhci_milbeaut_init(struct sdhci_host *host)
0211 {
0212     struct f_sdhost_priv *priv = sdhci_priv(host);
0213     int rate = clk_get_rate(priv->clk);
0214     u16 ctl;
0215 
0216     sdhci_milbeaut_bridge_reset(host, 0);
0217 
0218     ctl = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
0219     ctl &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN);
0220     sdhci_writew(host, ctl, SDHCI_CLOCK_CONTROL);
0221 
0222     sdhci_milbeaut_bridge_reset(host, 1);
0223 
0224     sdhci_milbeaut_bridge_init(host, rate);
0225     sdhci_milbeaut_bridge_reset(host, 0);
0226 
0227     sdhci_milbeaut_vendor_init(host);
0228 }
0229 
0230 static int sdhci_milbeaut_probe(struct platform_device *pdev)
0231 {
0232     struct sdhci_host *host;
0233     struct device *dev = &pdev->dev;
0234     int irq, ret = 0;
0235     struct f_sdhost_priv *priv;
0236 
0237     irq = platform_get_irq(pdev, 0);
0238     if (irq < 0)
0239         return irq;
0240 
0241     host = sdhci_alloc_host(dev, sizeof(struct f_sdhost_priv));
0242     if (IS_ERR(host))
0243         return PTR_ERR(host);
0244 
0245     priv = sdhci_priv(host);
0246     priv->dev = dev;
0247 
0248     host->quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
0249                SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
0250                SDHCI_QUIRK_CLOCK_BEFORE_RESET |
0251                SDHCI_QUIRK_DELAY_AFTER_POWER;
0252     host->quirks2 = SDHCI_QUIRK2_SUPPORT_SINGLE |
0253             SDHCI_QUIRK2_TUNING_WORK_AROUND |
0254             SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
0255 
0256     priv->enable_cmd_dat_delay = device_property_read_bool(dev,
0257                         "fujitsu,cmd-dat-delay-select");
0258 
0259     ret = mmc_of_parse(host->mmc);
0260     if (ret)
0261         goto err;
0262 
0263     platform_set_drvdata(pdev, host);
0264 
0265     host->hw_name = "f_sdh30";
0266     host->ops = &sdhci_milbeaut_ops;
0267     host->irq = irq;
0268 
0269     host->ioaddr = devm_platform_ioremap_resource(pdev, 0);
0270     if (IS_ERR(host->ioaddr)) {
0271         ret = PTR_ERR(host->ioaddr);
0272         goto err;
0273     }
0274 
0275     if (dev_of_node(dev)) {
0276         sdhci_get_of_property(pdev);
0277 
0278         priv->clk_iface = devm_clk_get(&pdev->dev, "iface");
0279         if (IS_ERR(priv->clk_iface)) {
0280             ret = PTR_ERR(priv->clk_iface);
0281             goto err;
0282         }
0283 
0284         ret = clk_prepare_enable(priv->clk_iface);
0285         if (ret)
0286             goto err;
0287 
0288         priv->clk = devm_clk_get(&pdev->dev, "core");
0289         if (IS_ERR(priv->clk)) {
0290             ret = PTR_ERR(priv->clk);
0291             goto err_clk;
0292         }
0293 
0294         ret = clk_prepare_enable(priv->clk);
0295         if (ret)
0296             goto err_clk;
0297     }
0298 
0299     sdhci_milbeaut_init(host);
0300 
0301     ret = sdhci_add_host(host);
0302     if (ret)
0303         goto err_add_host;
0304 
0305     return 0;
0306 
0307 err_add_host:
0308     clk_disable_unprepare(priv->clk);
0309 err_clk:
0310     clk_disable_unprepare(priv->clk_iface);
0311 err:
0312     sdhci_free_host(host);
0313     return ret;
0314 }
0315 
0316 static int sdhci_milbeaut_remove(struct platform_device *pdev)
0317 {
0318     struct sdhci_host *host = platform_get_drvdata(pdev);
0319     struct f_sdhost_priv *priv = sdhci_priv(host);
0320 
0321     sdhci_remove_host(host, readl(host->ioaddr + SDHCI_INT_STATUS) ==
0322               0xffffffff);
0323 
0324     clk_disable_unprepare(priv->clk_iface);
0325     clk_disable_unprepare(priv->clk);
0326 
0327     sdhci_free_host(host);
0328     platform_set_drvdata(pdev, NULL);
0329 
0330     return 0;
0331 }
0332 
0333 static struct platform_driver sdhci_milbeaut_driver = {
0334     .driver = {
0335         .name = "sdhci-milbeaut",
0336         .probe_type = PROBE_PREFER_ASYNCHRONOUS,
0337         .of_match_table = of_match_ptr(mlb_dt_ids),
0338     },
0339     .probe  = sdhci_milbeaut_probe,
0340     .remove = sdhci_milbeaut_remove,
0341 };
0342 
0343 module_platform_driver(sdhci_milbeaut_driver);
0344 
0345 MODULE_DESCRIPTION("MILBEAUT SD Card Controller driver");
0346 MODULE_AUTHOR("Takao Orito <orito.takao@socionext.com>");
0347 MODULE_LICENSE("GPL v2");
0348 MODULE_ALIAS("platform:sdhci-milbeaut");