]>
Commit | Line | Data |
---|---|---|
9f678ab1 RC |
1 | /* |
2 | * Andestech ATFSDC010 SD/MMC driver | |
3 | * | |
4 | * (C) Copyright 2017 | |
5 | * Rick Chen, NDS32 Software Engineering, rick@andestech.com | |
6 | ||
7 | * SPDX-License-Identifier: GPL-2.0+ | |
8 | */ | |
9 | ||
10 | #include <common.h> | |
11 | #include <clk.h> | |
12 | #include <dm.h> | |
13 | #include <dt-structs.h> | |
14 | #include <errno.h> | |
15 | #include <mapmem.h> | |
16 | #include <mmc.h> | |
17 | #include <pwrseq.h> | |
18 | #include <syscon.h> | |
19 | #include <linux/err.h> | |
20 | #include <faraday/ftsdc010.h> | |
21 | #include "ftsdc010_mci.h" | |
22 | ||
23 | DECLARE_GLOBAL_DATA_PTR; | |
24 | ||
25 | #if CONFIG_IS_ENABLED(OF_PLATDATA) | |
26 | struct nds_mmc { | |
27 | fdt32_t bus_width; | |
28 | bool cap_mmc_highspeed; | |
29 | bool cap_sd_highspeed; | |
30 | fdt32_t clock_freq_min_max[2]; | |
31 | struct phandle_2_cell clocks[4]; | |
32 | fdt32_t fifo_depth; | |
33 | fdt32_t reg[2]; | |
34 | }; | |
35 | #endif | |
36 | ||
37 | struct nds_mmc_plat { | |
38 | #if CONFIG_IS_ENABLED(OF_PLATDATA) | |
39 | struct nds_mmc dtplat; | |
40 | #endif | |
41 | struct mmc_config cfg; | |
42 | struct mmc mmc; | |
43 | }; | |
44 | ||
45 | struct ftsdc_priv { | |
46 | struct clk clk; | |
47 | struct ftsdc010_chip chip; | |
48 | int fifo_depth; | |
49 | bool fifo_mode; | |
50 | u32 minmax[2]; | |
51 | }; | |
52 | ||
53 | static int nds32_mmc_ofdata_to_platdata(struct udevice *dev) | |
54 | { | |
55 | #if !CONFIG_IS_ENABLED(OF_PLATDATA) | |
56 | struct ftsdc_priv *priv = dev_get_priv(dev); | |
57 | struct ftsdc010_chip *chip = &priv->chip; | |
58 | chip->name = dev->name; | |
59 | chip->ioaddr = (void *)devfdt_get_addr(dev); | |
60 | chip->buswidth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), | |
61 | "bus-width", 4); | |
62 | chip->priv = dev; | |
63 | priv->fifo_depth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), | |
64 | "fifo-depth", 0); | |
65 | priv->fifo_mode = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev), | |
66 | "fifo-mode"); | |
67 | if (fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev), | |
68 | "clock-freq-min-max", priv->minmax, 2)) { | |
69 | int val = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), | |
70 | "max-frequency", -EINVAL); | |
71 | if (val < 0) | |
72 | return val; | |
73 | ||
74 | priv->minmax[0] = 400000; /* 400 kHz */ | |
75 | priv->minmax[1] = val; | |
76 | } else { | |
77 | debug("%s: 'clock-freq-min-max' property was deprecated.\n", | |
78 | __func__); | |
79 | } | |
80 | #endif | |
81 | chip->sclk = priv->minmax[1]; | |
82 | chip->regs = chip->ioaddr; | |
83 | return 0; | |
84 | } | |
85 | ||
86 | static int nds32_mmc_probe(struct udevice *dev) | |
87 | { | |
88 | struct nds_mmc_plat *plat = dev_get_platdata(dev); | |
89 | struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); | |
90 | struct ftsdc_priv *priv = dev_get_priv(dev); | |
91 | struct ftsdc010_chip *chip = &priv->chip; | |
92 | struct udevice *pwr_dev __maybe_unused; | |
93 | #if CONFIG_IS_ENABLED(OF_PLATDATA) | |
94 | int ret; | |
95 | struct nds_mmc *dtplat = &plat->dtplat; | |
96 | chip->name = dev->name; | |
97 | chip->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]); | |
98 | chip->buswidth = dtplat->bus_width; | |
99 | chip->priv = dev; | |
100 | chip->dev_index = 1; | |
101 | memcpy(priv->minmax, dtplat->clock_freq_min_max, sizeof(priv->minmax)); | |
102 | ret = clk_get_by_index_platdata(dev, 0, dtplat->clocks, &priv->clk); | |
103 | if (ret < 0) | |
104 | return ret; | |
105 | #endif | |
106 | ftsdc_setup_cfg(&plat->cfg, dev->name, chip->buswidth, chip->caps, | |
107 | priv->minmax[1] , priv->minmax[0]); | |
108 | chip->mmc = &plat->mmc; | |
109 | chip->mmc->priv = &priv->chip; | |
110 | chip->mmc->dev = dev; | |
111 | upriv->mmc = chip->mmc; | |
112 | return ftsdc010_probe(dev); | |
113 | } | |
114 | ||
115 | static int nds32_mmc_bind(struct udevice *dev) | |
116 | { | |
117 | struct nds_mmc_plat *plat = dev_get_platdata(dev); | |
118 | return ftsdc010_bind(dev, &plat->mmc, &plat->cfg); | |
119 | } | |
120 | ||
121 | static const struct udevice_id nds32_mmc_ids[] = { | |
122 | { .compatible = "andestech,atsdc010" }, | |
123 | { } | |
124 | }; | |
125 | ||
126 | U_BOOT_DRIVER(nds32_mmc_drv) = { | |
127 | .name = "nds32_mmc", | |
128 | .id = UCLASS_MMC, | |
129 | .of_match = nds32_mmc_ids, | |
130 | .ofdata_to_platdata = nds32_mmc_ofdata_to_platdata, | |
131 | .ops = &dm_ftsdc010_ops, | |
132 | .bind = nds32_mmc_bind, | |
133 | .probe = nds32_mmc_probe, | |
134 | .priv_auto_alloc_size = sizeof(struct ftsdc_priv), | |
135 | .platdata_auto_alloc_size = sizeof(struct nds_mmc_plat), | |
136 | }; |