Home | History | Annotate | Download | only in mmc
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * Copyright 2013 Broadcom Corporation.
      4  */
      5 
      6 #include <common.h>
      7 #include <malloc.h>
      8 #include <sdhci.h>
      9 #include <linux/errno.h>
     10 #include <asm/kona-common/clk.h>
     11 
     12 #define SDHCI_CORECTRL_OFFSET		0x00008000
     13 #define SDHCI_CORECTRL_EN		0x01
     14 #define SDHCI_CORECTRL_RESET		0x02
     15 
     16 #define SDHCI_CORESTAT_OFFSET		0x00008004
     17 #define SDHCI_CORESTAT_CD_SW		0x01
     18 
     19 #define SDHCI_COREIMR_OFFSET		0x00008008
     20 #define SDHCI_COREIMR_IP		0x01
     21 
     22 static int init_kona_mmc_core(struct sdhci_host *host)
     23 {
     24 	unsigned int mask;
     25 	unsigned int timeout;
     26 
     27 	if (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & SDHCI_RESET_ALL) {
     28 		printf("%s: sd host controller reset error\n", __func__);
     29 		return -EBUSY;
     30 	}
     31 
     32 	/* For kona a hardware reset before anything else. */
     33 	mask = sdhci_readl(host, SDHCI_CORECTRL_OFFSET) | SDHCI_CORECTRL_RESET;
     34 	sdhci_writel(host, mask, SDHCI_CORECTRL_OFFSET);
     35 
     36 	/* Wait max 100 ms */
     37 	timeout = 1000;
     38 	do {
     39 		if (timeout == 0) {
     40 			printf("%s: reset timeout error\n", __func__);
     41 			return -ETIMEDOUT;
     42 		}
     43 		timeout--;
     44 		udelay(100);
     45 	} while (0 ==
     46 		 (sdhci_readl(host, SDHCI_CORECTRL_OFFSET) &
     47 		  SDHCI_CORECTRL_RESET));
     48 
     49 	/* Clear the reset bit. */
     50 	mask = mask & ~SDHCI_CORECTRL_RESET;
     51 	sdhci_writel(host, mask, SDHCI_CORECTRL_OFFSET);
     52 
     53 	/* Enable AHB clock */
     54 	mask = sdhci_readl(host, SDHCI_CORECTRL_OFFSET);
     55 	sdhci_writel(host, mask | SDHCI_CORECTRL_EN, SDHCI_CORECTRL_OFFSET);
     56 
     57 	/* Enable interrupts */
     58 	sdhci_writel(host, SDHCI_COREIMR_IP, SDHCI_COREIMR_OFFSET);
     59 
     60 	/* Make sure Card is detected in controller */
     61 	mask = sdhci_readl(host, SDHCI_CORESTAT_OFFSET);
     62 	sdhci_writel(host, mask | SDHCI_CORESTAT_CD_SW, SDHCI_CORESTAT_OFFSET);
     63 
     64 	/* Wait max 100 ms */
     65 	timeout = 1000;
     66 	while (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
     67 		if (timeout == 0) {
     68 			printf("%s: CARD DETECT timeout error\n", __func__);
     69 			return -ETIMEDOUT;
     70 		}
     71 		timeout--;
     72 		udelay(100);
     73 	}
     74 	return 0;
     75 }
     76 
     77 int kona_sdhci_init(int dev_index, u32 min_clk, u32 quirks)
     78 {
     79 	int ret = 0;
     80 	u32 max_clk;
     81 	void *reg_base;
     82 	struct sdhci_host *host = NULL;
     83 
     84 	host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host));
     85 	if (!host) {
     86 		printf("%s: sdhci host malloc fail!\n", __func__);
     87 		return -ENOMEM;
     88 	}
     89 	switch (dev_index) {
     90 	case 0:
     91 		reg_base = (void *)CONFIG_SYS_SDIO_BASE0;
     92 		ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO0_MAX_CLK,
     93 				      &max_clk);
     94 		break;
     95 	case 1:
     96 		reg_base = (void *)CONFIG_SYS_SDIO_BASE1;
     97 		ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO1_MAX_CLK,
     98 				      &max_clk);
     99 		break;
    100 	case 2:
    101 		reg_base = (void *)CONFIG_SYS_SDIO_BASE2;
    102 		ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO2_MAX_CLK,
    103 				      &max_clk);
    104 		break;
    105 	case 3:
    106 		reg_base = (void *)CONFIG_SYS_SDIO_BASE3;
    107 		ret = clk_sdio_enable(reg_base, CONFIG_SYS_SDIO3_MAX_CLK,
    108 				      &max_clk);
    109 		break;
    110 	default:
    111 		printf("%s: sdio dev index %d not supported\n",
    112 		       __func__, dev_index);
    113 		ret = -EINVAL;
    114 	}
    115 	if (ret) {
    116 		free(host);
    117 		return ret;
    118 	}
    119 
    120 	host->name = "kona-sdhci";
    121 	host->ioaddr = reg_base;
    122 	host->quirks = quirks;
    123 	host->max_clk = max_clk;
    124 
    125 	if (init_kona_mmc_core(host)) {
    126 		free(host);
    127 		return -EINVAL;
    128 	}
    129 
    130 	add_sdhci(host, 0, min_clk);
    131 	return ret;
    132 }
    133