162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci// Copyright (C) 2013 Broadcom Corporation 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/kernel.h> 562306a36Sopenharmony_ci#include <linux/module.h> 662306a36Sopenharmony_ci#include <linux/delay.h> 762306a36Sopenharmony_ci#include <linux/highmem.h> 862306a36Sopenharmony_ci#include <linux/platform_device.h> 962306a36Sopenharmony_ci#include <linux/mmc/host.h> 1062306a36Sopenharmony_ci#include <linux/io.h> 1162306a36Sopenharmony_ci#include <linux/clk.h> 1262306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 1362306a36Sopenharmony_ci#include <linux/of.h> 1462306a36Sopenharmony_ci#include <linux/mmc/slot-gpio.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "sdhci-pltfm.h" 1762306a36Sopenharmony_ci#include "sdhci.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define SDHCI_SOFT_RESET 0x01000000 2062306a36Sopenharmony_ci#define KONA_SDHOST_CORECTRL 0x8000 2162306a36Sopenharmony_ci#define KONA_SDHOST_CD_PINCTRL 0x00000008 2262306a36Sopenharmony_ci#define KONA_SDHOST_STOP_HCLK 0x00000004 2362306a36Sopenharmony_ci#define KONA_SDHOST_RESET 0x00000002 2462306a36Sopenharmony_ci#define KONA_SDHOST_EN 0x00000001 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define KONA_SDHOST_CORESTAT 0x8004 2762306a36Sopenharmony_ci#define KONA_SDHOST_WP 0x00000002 2862306a36Sopenharmony_ci#define KONA_SDHOST_CD_SW 0x00000001 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define KONA_SDHOST_COREIMR 0x8008 3162306a36Sopenharmony_ci#define KONA_SDHOST_IP 0x00000001 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define KONA_SDHOST_COREISR 0x800C 3462306a36Sopenharmony_ci#define KONA_SDHOST_COREIMSR 0x8010 3562306a36Sopenharmony_ci#define KONA_SDHOST_COREDBG1 0x8014 3662306a36Sopenharmony_ci#define KONA_SDHOST_COREGPO_MASK 0x8018 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define SD_DETECT_GPIO_DEBOUNCE_128MS 128 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define KONA_MMC_AUTOSUSPEND_DELAY (50) 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistruct sdhci_bcm_kona_dev { 4362306a36Sopenharmony_ci struct mutex write_lock; /* protect back to back writes */ 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic int sdhci_bcm_kona_sd_reset(struct sdhci_host *host) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci unsigned int val; 5062306a36Sopenharmony_ci unsigned long timeout; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci /* This timeout should be sufficent for core to reset */ 5362306a36Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(100); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci /* reset the host using the top level reset */ 5662306a36Sopenharmony_ci val = sdhci_readl(host, KONA_SDHOST_CORECTRL); 5762306a36Sopenharmony_ci val |= KONA_SDHOST_RESET; 5862306a36Sopenharmony_ci sdhci_writel(host, val, KONA_SDHOST_CORECTRL); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci while (!(sdhci_readl(host, KONA_SDHOST_CORECTRL) & KONA_SDHOST_RESET)) { 6162306a36Sopenharmony_ci if (time_is_before_jiffies(timeout)) { 6262306a36Sopenharmony_ci pr_err("Error: sd host is stuck in reset!!!\n"); 6362306a36Sopenharmony_ci return -EFAULT; 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci /* bring the host out of reset */ 6862306a36Sopenharmony_ci val = sdhci_readl(host, KONA_SDHOST_CORECTRL); 6962306a36Sopenharmony_ci val &= ~KONA_SDHOST_RESET; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci /* 7262306a36Sopenharmony_ci * Back-to-Back register write needs a delay of 1ms at bootup (min 10uS) 7362306a36Sopenharmony_ci * Back-to-Back writes to same register needs delay when SD bus clock 7462306a36Sopenharmony_ci * is very low w.r.t AHB clock, mainly during boot-time and during card 7562306a36Sopenharmony_ci * insert-removal. 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_ci usleep_range(1000, 5000); 7862306a36Sopenharmony_ci sdhci_writel(host, val, KONA_SDHOST_CORECTRL); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci return 0; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic void sdhci_bcm_kona_sd_init(struct sdhci_host *host) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci unsigned int val; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci /* enable the interrupt from the IP core */ 8862306a36Sopenharmony_ci val = sdhci_readl(host, KONA_SDHOST_COREIMR); 8962306a36Sopenharmony_ci val |= KONA_SDHOST_IP; 9062306a36Sopenharmony_ci sdhci_writel(host, val, KONA_SDHOST_COREIMR); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci /* Enable the AHB clock gating module to the host */ 9362306a36Sopenharmony_ci val = sdhci_readl(host, KONA_SDHOST_CORECTRL); 9462306a36Sopenharmony_ci val |= KONA_SDHOST_EN; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci /* 9762306a36Sopenharmony_ci * Back-to-Back register write needs a delay of 1ms at bootup (min 10uS) 9862306a36Sopenharmony_ci * Back-to-Back writes to same register needs delay when SD bus clock 9962306a36Sopenharmony_ci * is very low w.r.t AHB clock, mainly during boot-time and during card 10062306a36Sopenharmony_ci * insert-removal. 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_ci usleep_range(1000, 5000); 10362306a36Sopenharmony_ci sdhci_writel(host, val, KONA_SDHOST_CORECTRL); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/* 10762306a36Sopenharmony_ci * Software emulation of the SD card insertion/removal. Set insert=1 for insert 10862306a36Sopenharmony_ci * and insert=0 for removal. The card detection is done by GPIO. For Broadcom 10962306a36Sopenharmony_ci * IP to function properly the bit 0 of CORESTAT register needs to be set/reset 11062306a36Sopenharmony_ci * to generate the CD IRQ handled in sdhci.c which schedules card_tasklet. 11162306a36Sopenharmony_ci */ 11262306a36Sopenharmony_cistatic int sdhci_bcm_kona_sd_card_emulate(struct sdhci_host *host, int insert) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci struct sdhci_pltfm_host *pltfm_priv = sdhci_priv(host); 11562306a36Sopenharmony_ci struct sdhci_bcm_kona_dev *kona_dev = sdhci_pltfm_priv(pltfm_priv); 11662306a36Sopenharmony_ci u32 val; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* 11962306a36Sopenharmony_ci * Back-to-Back register write needs a delay of min 10uS. 12062306a36Sopenharmony_ci * Back-to-Back writes to same register needs delay when SD bus clock 12162306a36Sopenharmony_ci * is very low w.r.t AHB clock, mainly during boot-time and during card 12262306a36Sopenharmony_ci * insert-removal. 12362306a36Sopenharmony_ci * We keep 20uS 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_ci mutex_lock(&kona_dev->write_lock); 12662306a36Sopenharmony_ci udelay(20); 12762306a36Sopenharmony_ci val = sdhci_readl(host, KONA_SDHOST_CORESTAT); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci if (insert) { 13062306a36Sopenharmony_ci int ret; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci ret = mmc_gpio_get_ro(host->mmc); 13362306a36Sopenharmony_ci if (ret >= 0) 13462306a36Sopenharmony_ci val = (val & ~KONA_SDHOST_WP) | 13562306a36Sopenharmony_ci ((ret) ? KONA_SDHOST_WP : 0); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci val |= KONA_SDHOST_CD_SW; 13862306a36Sopenharmony_ci sdhci_writel(host, val, KONA_SDHOST_CORESTAT); 13962306a36Sopenharmony_ci } else { 14062306a36Sopenharmony_ci val &= ~KONA_SDHOST_CD_SW; 14162306a36Sopenharmony_ci sdhci_writel(host, val, KONA_SDHOST_CORESTAT); 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci mutex_unlock(&kona_dev->write_lock); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci return 0; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci/* 14962306a36Sopenharmony_ci * SD card interrupt event callback 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_cistatic void sdhci_bcm_kona_card_event(struct sdhci_host *host) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci if (mmc_gpio_get_cd(host->mmc) > 0) { 15462306a36Sopenharmony_ci dev_dbg(mmc_dev(host->mmc), 15562306a36Sopenharmony_ci "card inserted\n"); 15662306a36Sopenharmony_ci sdhci_bcm_kona_sd_card_emulate(host, 1); 15762306a36Sopenharmony_ci } else { 15862306a36Sopenharmony_ci dev_dbg(mmc_dev(host->mmc), 15962306a36Sopenharmony_ci "card removed\n"); 16062306a36Sopenharmony_ci sdhci_bcm_kona_sd_card_emulate(host, 0); 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host, 16562306a36Sopenharmony_ci u8 power_mode) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci /* 16862306a36Sopenharmony_ci * JEDEC and SD spec specify supplying 74 continuous clocks to 16962306a36Sopenharmony_ci * device after power up. With minimum bus (100KHz) that 17062306a36Sopenharmony_ci * translates to 740us 17162306a36Sopenharmony_ci */ 17262306a36Sopenharmony_ci if (power_mode != MMC_POWER_OFF) 17362306a36Sopenharmony_ci udelay(740); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic const struct sdhci_ops sdhci_bcm_kona_ops = { 17762306a36Sopenharmony_ci .set_clock = sdhci_set_clock, 17862306a36Sopenharmony_ci .get_max_clock = sdhci_pltfm_clk_get_max_clock, 17962306a36Sopenharmony_ci .get_timeout_clock = sdhci_pltfm_clk_get_max_clock, 18062306a36Sopenharmony_ci .platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks, 18162306a36Sopenharmony_ci .set_bus_width = sdhci_set_bus_width, 18262306a36Sopenharmony_ci .reset = sdhci_reset, 18362306a36Sopenharmony_ci .set_uhs_signaling = sdhci_set_uhs_signaling, 18462306a36Sopenharmony_ci .card_event = sdhci_bcm_kona_card_event, 18562306a36Sopenharmony_ci}; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic const struct sdhci_pltfm_data sdhci_pltfm_data_kona = { 18862306a36Sopenharmony_ci .ops = &sdhci_bcm_kona_ops, 18962306a36Sopenharmony_ci .quirks = SDHCI_QUIRK_NO_CARD_NO_RESET | 19062306a36Sopenharmony_ci SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_32BIT_DMA_ADDR | 19162306a36Sopenharmony_ci SDHCI_QUIRK_32BIT_DMA_SIZE | SDHCI_QUIRK_32BIT_ADMA_SIZE | 19262306a36Sopenharmony_ci SDHCI_QUIRK_FORCE_BLK_SZ_2048 | 19362306a36Sopenharmony_ci SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, 19462306a36Sopenharmony_ci}; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic const struct of_device_id sdhci_bcm_kona_of_match[] = { 19762306a36Sopenharmony_ci { .compatible = "brcm,kona-sdhci"}, 19862306a36Sopenharmony_ci { .compatible = "bcm,kona-sdhci"}, /* deprecated name */ 19962306a36Sopenharmony_ci {} 20062306a36Sopenharmony_ci}; 20162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, sdhci_bcm_kona_of_match); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic int sdhci_bcm_kona_probe(struct platform_device *pdev) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci struct sdhci_bcm_kona_dev *kona_dev = NULL; 20662306a36Sopenharmony_ci struct sdhci_pltfm_host *pltfm_priv; 20762306a36Sopenharmony_ci struct device *dev = &pdev->dev; 20862306a36Sopenharmony_ci struct sdhci_host *host; 20962306a36Sopenharmony_ci int ret; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci ret = 0; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci host = sdhci_pltfm_init(pdev, &sdhci_pltfm_data_kona, 21462306a36Sopenharmony_ci sizeof(*kona_dev)); 21562306a36Sopenharmony_ci if (IS_ERR(host)) 21662306a36Sopenharmony_ci return PTR_ERR(host); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci dev_dbg(dev, "%s: inited. IOADDR=%p\n", __func__, host->ioaddr); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci pltfm_priv = sdhci_priv(host); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci kona_dev = sdhci_pltfm_priv(pltfm_priv); 22362306a36Sopenharmony_ci mutex_init(&kona_dev->write_lock); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci ret = mmc_of_parse(host->mmc); 22662306a36Sopenharmony_ci if (ret) 22762306a36Sopenharmony_ci goto err_pltfm_free; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if (!host->mmc->f_max) { 23062306a36Sopenharmony_ci dev_err(&pdev->dev, "Missing max-freq for SDHCI cfg\n"); 23162306a36Sopenharmony_ci ret = -ENXIO; 23262306a36Sopenharmony_ci goto err_pltfm_free; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci /* Get and enable the core clock */ 23662306a36Sopenharmony_ci pltfm_priv->clk = devm_clk_get(dev, NULL); 23762306a36Sopenharmony_ci if (IS_ERR(pltfm_priv->clk)) { 23862306a36Sopenharmony_ci dev_err(dev, "Failed to get core clock\n"); 23962306a36Sopenharmony_ci ret = PTR_ERR(pltfm_priv->clk); 24062306a36Sopenharmony_ci goto err_pltfm_free; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci ret = clk_set_rate(pltfm_priv->clk, host->mmc->f_max); 24462306a36Sopenharmony_ci if (ret) { 24562306a36Sopenharmony_ci dev_err(dev, "Failed to set rate core clock\n"); 24662306a36Sopenharmony_ci goto err_pltfm_free; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci ret = clk_prepare_enable(pltfm_priv->clk); 25062306a36Sopenharmony_ci if (ret) { 25162306a36Sopenharmony_ci dev_err(dev, "Failed to enable core clock\n"); 25262306a36Sopenharmony_ci goto err_pltfm_free; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci dev_dbg(dev, "non-removable=%c\n", 25662306a36Sopenharmony_ci mmc_card_is_removable(host->mmc) ? 'N' : 'Y'); 25762306a36Sopenharmony_ci dev_dbg(dev, "cd_gpio %c, wp_gpio %c\n", 25862306a36Sopenharmony_ci (mmc_gpio_get_cd(host->mmc) != -ENOSYS) ? 'Y' : 'N', 25962306a36Sopenharmony_ci (mmc_gpio_get_ro(host->mmc) != -ENOSYS) ? 'Y' : 'N'); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (!mmc_card_is_removable(host->mmc)) 26262306a36Sopenharmony_ci host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci dev_dbg(dev, "is_8bit=%c\n", 26562306a36Sopenharmony_ci (host->mmc->caps & MMC_CAP_8_BIT_DATA) ? 'Y' : 'N'); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci ret = sdhci_bcm_kona_sd_reset(host); 26862306a36Sopenharmony_ci if (ret) 26962306a36Sopenharmony_ci goto err_clk_disable; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci sdhci_bcm_kona_sd_init(host); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci ret = sdhci_add_host(host); 27462306a36Sopenharmony_ci if (ret) 27562306a36Sopenharmony_ci goto err_reset; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* if device is eMMC, emulate card insert right here */ 27862306a36Sopenharmony_ci if (!mmc_card_is_removable(host->mmc)) { 27962306a36Sopenharmony_ci ret = sdhci_bcm_kona_sd_card_emulate(host, 1); 28062306a36Sopenharmony_ci if (ret) { 28162306a36Sopenharmony_ci dev_err(dev, 28262306a36Sopenharmony_ci "unable to emulate card insertion\n"); 28362306a36Sopenharmony_ci goto err_remove_host; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci /* 28762306a36Sopenharmony_ci * Since the card detection GPIO interrupt is configured to be 28862306a36Sopenharmony_ci * edge sensitive, check the initial GPIO value here, emulate 28962306a36Sopenharmony_ci * only if the card is present 29062306a36Sopenharmony_ci */ 29162306a36Sopenharmony_ci if (mmc_gpio_get_cd(host->mmc) > 0) 29262306a36Sopenharmony_ci sdhci_bcm_kona_sd_card_emulate(host, 1); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci dev_dbg(dev, "initialized properly\n"); 29562306a36Sopenharmony_ci return 0; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cierr_remove_host: 29862306a36Sopenharmony_ci sdhci_remove_host(host, 0); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cierr_reset: 30162306a36Sopenharmony_ci sdhci_bcm_kona_sd_reset(host); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cierr_clk_disable: 30462306a36Sopenharmony_ci clk_disable_unprepare(pltfm_priv->clk); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cierr_pltfm_free: 30762306a36Sopenharmony_ci sdhci_pltfm_free(pdev); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci dev_err(dev, "Probing of sdhci-pltfm failed: %d\n", ret); 31062306a36Sopenharmony_ci return ret; 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic void sdhci_bcm_kona_remove(struct platform_device *pdev) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci struct sdhci_host *host = platform_get_drvdata(pdev); 31662306a36Sopenharmony_ci struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 31762306a36Sopenharmony_ci struct clk *clk = pltfm_host->clk; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci sdhci_pltfm_remove(pdev); 32062306a36Sopenharmony_ci clk_disable_unprepare(clk); 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic struct platform_driver sdhci_bcm_kona_driver = { 32462306a36Sopenharmony_ci .driver = { 32562306a36Sopenharmony_ci .name = "sdhci-kona", 32662306a36Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 32762306a36Sopenharmony_ci .pm = &sdhci_pltfm_pmops, 32862306a36Sopenharmony_ci .of_match_table = sdhci_bcm_kona_of_match, 32962306a36Sopenharmony_ci }, 33062306a36Sopenharmony_ci .probe = sdhci_bcm_kona_probe, 33162306a36Sopenharmony_ci .remove_new = sdhci_bcm_kona_remove, 33262306a36Sopenharmony_ci}; 33362306a36Sopenharmony_cimodule_platform_driver(sdhci_bcm_kona_driver); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ciMODULE_DESCRIPTION("SDHCI driver for Broadcom Kona platform"); 33662306a36Sopenharmony_ciMODULE_AUTHOR("Broadcom"); 33762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 338