Blame view
drivers/mmc/s5p_sdhci.c
5.63 KB
83d290c56 SPDX: Convert all... |
1 |
// SPDX-License-Identifier: GPL-2.0+ |
442d55685 mmc: support the ... |
2 3 4 |
/* * (C) Copyright 2012 SAMSUNG Electronics * Jaehoon Chung <jh80.chung@samsung.com> |
442d55685 mmc: support the ... |
5 6 7 |
*/ #include <common.h> |
7aedafd6b mmc: s5p_sdhci: s... |
8 |
#include <dm.h> |
442d55685 mmc: support the ... |
9 10 |
#include <malloc.h> #include <sdhci.h> |
3577fe8be drivers:mmc:sdhci... |
11 |
#include <fdtdec.h> |
b08c8c487 libfdt: move head... |
12 |
#include <linux/libfdt.h> |
3577fe8be drivers:mmc:sdhci... |
13 |
#include <asm/gpio.h> |
442d55685 mmc: support the ... |
14 |
#include <asm/arch/mmc.h> |
b09ed6e4f mmc: s5p_sdhci: a... |
15 |
#include <asm/arch/clk.h> |
3577fe8be drivers:mmc:sdhci... |
16 |
#include <errno.h> |
3577fe8be drivers:mmc:sdhci... |
17 |
#include <asm/arch/pinmux.h> |
442d55685 mmc: support the ... |
18 |
|
7aedafd6b mmc: s5p_sdhci: s... |
19 20 21 22 23 24 25 26 |
#ifdef CONFIG_DM_MMC struct s5p_sdhci_plat { struct mmc_config cfg; struct mmc mmc; }; DECLARE_GLOBAL_DATA_PTR; #endif |
442d55685 mmc: support the ... |
27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
static char *S5P_NAME = "SAMSUNG SDHCI"; static void s5p_sdhci_set_control_reg(struct sdhci_host *host) { unsigned long val, ctrl; /* * SELCLKPADDS[17:16] * 00 = 2mA * 01 = 4mA * 10 = 7mA * 11 = 9mA */ sdhci_writel(host, SDHCI_CTRL4_DRIVE_MASK(0x3), SDHCI_CONTROL4); val = sdhci_readl(host, SDHCI_CONTROL2); |
8ebde4f0b mmc: s5p: properl... |
41 |
val &= SDHCI_CTRL2_SELBASECLK_MASK(3); |
442d55685 mmc: support the ... |
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
val |= SDHCI_CTRL2_ENSTAASYNCCLR | SDHCI_CTRL2_ENCMDCNFMSK | SDHCI_CTRL2_ENFBCLKRX | SDHCI_CTRL2_ENCLKOUTHOLD; sdhci_writel(host, val, SDHCI_CONTROL2); /* * FCSEL3[31] FCSEL2[23] FCSEL1[15] FCSEL0[7] * FCSel[1:0] : Rx Feedback Clock Delay Control * Inverter delay means10ns delay if SDCLK 50MHz setting * 01 = Delay1 (basic delay) * 11 = Delay2 (basic delay + 2ns) * 00 = Delay3 (inverter delay) * 10 = Delay4 (inverter delay + 2ns) */ |
b268660ce mmc: s5p_sdhci: s... |
59 |
val = SDHCI_CTRL3_FCSEL0 | SDHCI_CTRL3_FCSEL1; |
442d55685 mmc: support the ... |
60 61 62 63 64 65 66 67 68 69 70 71 72 |
sdhci_writel(host, val, SDHCI_CONTROL3); /* * SELBASECLK[5:4] * 00/01 = HCLK * 10 = EPLL * 11 = XTI or XEXTCLK */ ctrl = sdhci_readl(host, SDHCI_CONTROL2); ctrl &= ~SDHCI_CTRL2_SELBASECLK_MASK(0x3); ctrl |= SDHCI_CTRL2_SELBASECLK_MASK(0x2); sdhci_writel(host, ctrl, SDHCI_CONTROL2); } |
f73b33ff9 mmc: s5p_sdhci: a... |
73 74 75 76 77 |
static void s5p_set_clock(struct sdhci_host *host, u32 div) { /* ToDo : Use the Clock Framework */ set_mmc_clk(host->index, div); } |
62226b686 mmc: sdhci: move ... |
78 79 80 81 |
static const struct sdhci_ops s5p_sdhci_ops = { .set_clock = &s5p_set_clock, .set_control_reg = &s5p_sdhci_set_control_reg, }; |
9b8c9a3c0 mmc: s5p_sdhci: a... |
82 |
static int s5p_sdhci_core_init(struct sdhci_host *host) |
442d55685 mmc: support the ... |
83 |
{ |
442d55685 mmc: support the ... |
84 |
host->name = S5P_NAME; |
442d55685 mmc: support the ... |
85 |
|
b268660ce mmc: s5p_sdhci: s... |
86 |
host->quirks = SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE | |
a034ec06f mmc: s5p_sdhci: u... |
87 |
SDHCI_QUIRK_32BIT_DMA_ADDR | |
113e5dfcd mmc: sdhci: use t... |
88 |
SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_USE_WIDE8; |
6d0e34bf4 mmc: sdhci: Disti... |
89 |
host->max_clk = 52000000; |
442d55685 mmc: support the ... |
90 |
host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; |
62226b686 mmc: sdhci: move ... |
91 |
host->ops = &s5p_sdhci_ops; |
442d55685 mmc: support the ... |
92 |
|
9b8c9a3c0 mmc: s5p_sdhci: a... |
93 |
if (host->bus_width == 8) |
113e5dfcd mmc: sdhci: use t... |
94 |
host->host_caps |= MMC_MODE_8BIT; |
442d55685 mmc: support the ... |
95 |
|
7aedafd6b mmc: s5p_sdhci: s... |
96 |
#ifndef CONFIG_BLK |
6d0e34bf4 mmc: sdhci: Disti... |
97 |
return add_sdhci(host, 0, 400000); |
7aedafd6b mmc: s5p_sdhci: s... |
98 99 100 |
#else return 0; #endif |
442d55685 mmc: support the ... |
101 |
} |
3577fe8be drivers:mmc:sdhci... |
102 |
|
9b8c9a3c0 mmc: s5p_sdhci: a... |
103 104 |
int s5p_sdhci_init(u32 regbase, int index, int bus_width) { |
1a9d1731f exynos: Properly ... |
105 |
struct sdhci_host *host = calloc(1, sizeof(struct sdhci_host)); |
9b8c9a3c0 mmc: s5p_sdhci: a... |
106 |
if (!host) { |
1a9d1731f exynos: Properly ... |
107 108 |
printf("sdhci__host allocation fail! "); |
2cb5d67c1 mmc: sdhci: use t... |
109 |
return -ENOMEM; |
9b8c9a3c0 mmc: s5p_sdhci: a... |
110 111 112 113 114 115 116 |
} host->ioaddr = (void *)regbase; host->index = index; host->bus_width = bus_width; return s5p_sdhci_core_init(host); } |
3577fe8be drivers:mmc:sdhci... |
117 118 |
static int do_sdhci_init(struct sdhci_host *host) { |
2308ea7c6 exynos: more debu... |
119 |
int dev_id, flag, ret; |
3577fe8be drivers:mmc:sdhci... |
120 121 122 |
flag = host->bus_width == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE; dev_id = host->index + PERIPH_ID_SDMMC0; |
96094d4c4 s5p sdhci: call p... |
123 124 125 126 127 128 |
ret = exynos_pinmux_config(dev_id, flag); if (ret) { printf("external SD not configured "); return ret; } |
0347960b8 dm: mmc: Remove u... |
129 130 |
if (dm_gpio_is_valid(&host->pwr_gpio)) { dm_gpio_set_value(&host->pwr_gpio, 1); |
2308ea7c6 exynos: more debu... |
131 132 |
ret = exynos_pinmux_config(dev_id, flag); if (ret) { |
3577fe8be drivers:mmc:sdhci... |
133 134 |
debug("MMC not configured "); |
2308ea7c6 exynos: more debu... |
135 |
return ret; |
3577fe8be drivers:mmc:sdhci... |
136 137 |
} } |
0347960b8 dm: mmc: Remove u... |
138 |
if (dm_gpio_is_valid(&host->cd_gpio)) { |
2308ea7c6 exynos: more debu... |
139 140 141 142 |
ret = dm_gpio_get_value(&host->cd_gpio); if (ret) { debug("no SD card detected (%d) ", ret); |
3577fe8be drivers:mmc:sdhci... |
143 |
return -ENODEV; |
2308ea7c6 exynos: more debu... |
144 |
} |
3577fe8be drivers:mmc:sdhci... |
145 |
} |
9b8c9a3c0 mmc: s5p_sdhci: a... |
146 |
return s5p_sdhci_core_init(host); |
3577fe8be drivers:mmc:sdhci... |
147 148 149 150 151 152 153 154 155 |
} static int sdhci_get_config(const void *blob, int node, struct sdhci_host *host) { int bus_width, dev_id; unsigned int base; /* Get device id */ dev_id = pinmux_decode_periph_id(blob, node); |
f0ecfc5e7 mmc: s5p_sdhci: f... |
156 |
if (dev_id < PERIPH_ID_SDMMC0 || dev_id > PERIPH_ID_SDMMC3) { |
3577fe8be drivers:mmc:sdhci... |
157 158 |
debug("MMC: Can't get device id "); |
2cb5d67c1 mmc: sdhci: use t... |
159 |
return -EINVAL; |
3577fe8be drivers:mmc:sdhci... |
160 161 162 163 164 165 166 167 |
} host->index = dev_id - PERIPH_ID_SDMMC0; /* Get bus width */ bus_width = fdtdec_get_int(blob, node, "samsung,bus-width", 0); if (bus_width <= 0) { debug("MMC: Can't get bus-width "); |
2cb5d67c1 mmc: sdhci: use t... |
168 |
return -EINVAL; |
3577fe8be drivers:mmc:sdhci... |
169 170 171 172 173 174 175 176 |
} host->bus_width = bus_width; /* Get the base address from the device node */ base = fdtdec_get_addr(blob, node, "reg"); if (!base) { debug("MMC: Can't get base address "); |
2cb5d67c1 mmc: sdhci: use t... |
177 |
return -EINVAL; |
3577fe8be drivers:mmc:sdhci... |
178 179 |
} host->ioaddr = (void *)base; |
150c5afe5 dm: gpio: Add liv... |
180 181 182 183 |
gpio_request_by_name_nodev(offset_to_ofnode(node), "pwr-gpios", 0, &host->pwr_gpio, GPIOD_IS_OUT); gpio_request_by_name_nodev(offset_to_ofnode(node), "cd-gpios", 0, &host->cd_gpio, GPIOD_IS_IN); |
3577fe8be drivers:mmc:sdhci... |
184 185 186 |
return 0; } |
7aedafd6b mmc: s5p_sdhci: s... |
187 188 189 190 191 192 193 |
#ifdef CONFIG_DM_MMC static int s5p_sdhci_probe(struct udevice *dev) { struct s5p_sdhci_plat *plat = dev_get_platdata(dev); struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct sdhci_host *host = dev_get_priv(dev); int ret; |
e160f7d43 dm: core: Replace... |
194 |
ret = sdhci_get_config(gd->fdt_blob, dev_of_offset(dev), host); |
7aedafd6b mmc: s5p_sdhci: s... |
195 196 197 198 199 200 |
if (ret) return ret; ret = do_sdhci_init(host); if (ret) return ret; |
e27108c43 mmc: s5p_sdhci: R... |
201 202 203 |
ret = mmc_of_parse(dev, &plat->cfg); if (ret) return ret; |
6f16cbe55 mmc: s5p: fix uni... |
204 205 |
host->mmc = &plat->mmc; host->mmc->dev = dev; |
e27108c43 mmc: s5p_sdhci: R... |
206 |
|
6d0e34bf4 mmc: sdhci: Disti... |
207 |
ret = sdhci_setup_cfg(&plat->cfg, host, 0, 400000); |
7aedafd6b mmc: s5p_sdhci: s... |
208 209 |
if (ret) return ret; |
7aedafd6b mmc: s5p_sdhci: s... |
210 |
host->mmc->priv = host; |
7aedafd6b mmc: s5p_sdhci: s... |
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
upriv->mmc = host->mmc; return sdhci_probe(dev); } static int s5p_sdhci_bind(struct udevice *dev) { struct s5p_sdhci_plat *plat = dev_get_platdata(dev); int ret; ret = sdhci_bind(dev, &plat->mmc, &plat->cfg); if (ret) return ret; return 0; } static const struct udevice_id s5p_sdhci_ids[] = { { .compatible = "samsung,exynos4412-sdhci"}, { } }; U_BOOT_DRIVER(s5p_sdhci_drv) = { .name = "s5p_sdhci", .id = UCLASS_MMC, .of_match = s5p_sdhci_ids, .bind = s5p_sdhci_bind, .ops = &sdhci_ops, .probe = s5p_sdhci_probe, .priv_auto_alloc_size = sizeof(struct sdhci_host), .platdata_auto_alloc_size = sizeof(struct s5p_sdhci_plat), }; #endif /* CONFIG_DM_MMC */ |