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