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
134
135
136
|
/*
* Andestech ATFSDC010 SD/MMC driver
*
* (C) Copyright 2017
* Rick Chen, NDS32 Software Engineering, rick@andestech.com
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <dt-structs.h>
#include <errno.h>
#include <mapmem.h>
#include <mmc.h>
#include <pwrseq.h>
#include <syscon.h>
#include <linux/err.h>
#include <faraday/ftsdc010.h>
#include "ftsdc010_mci.h"
DECLARE_GLOBAL_DATA_PTR;
#if CONFIG_IS_ENABLED(OF_PLATDATA)
struct nds_mmc {
fdt32_t bus_width;
bool cap_mmc_highspeed;
bool cap_sd_highspeed;
fdt32_t clock_freq_min_max[2];
struct phandle_2_cell clocks[4];
fdt32_t fifo_depth;
fdt32_t reg[2];
};
#endif
struct nds_mmc_plat {
#if CONFIG_IS_ENABLED(OF_PLATDATA)
struct nds_mmc dtplat;
#endif
struct mmc_config cfg;
struct mmc mmc;
};
struct ftsdc_priv {
struct clk clk;
struct ftsdc010_chip chip;
int fifo_depth;
bool fifo_mode;
u32 minmax[2];
};
static int nds32_mmc_ofdata_to_platdata(struct udevice *dev)
{
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
struct ftsdc_priv *priv = dev_get_priv(dev);
struct ftsdc010_chip *chip = &priv->chip;
chip->name = dev->name;
chip->ioaddr = (void *)devfdt_get_addr(dev);
chip->buswidth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
"bus-width", 4);
chip->priv = dev;
priv->fifo_depth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
"fifo-depth", 0);
priv->fifo_mode = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
"fifo-mode");
if (fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev),
"clock-freq-min-max", priv->minmax, 2)) {
int val = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
"max-frequency", -EINVAL);
if (val < 0)
return val;
priv->minmax[0] = 400000; /* 400 kHz */
priv->minmax[1] = val;
} else {
debug("%s: 'clock-freq-min-max' property was deprecated.\n",
__func__);
}
#endif
chip->sclk = priv->minmax[1];
chip->regs = chip->ioaddr;
return 0;
}
static int nds32_mmc_probe(struct udevice *dev)
{
struct nds_mmc_plat *plat = dev_get_platdata(dev);
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
struct ftsdc_priv *priv = dev_get_priv(dev);
struct ftsdc010_chip *chip = &priv->chip;
struct udevice *pwr_dev __maybe_unused;
#if CONFIG_IS_ENABLED(OF_PLATDATA)
int ret;
struct nds_mmc *dtplat = &plat->dtplat;
chip->name = dev->name;
chip->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]);
chip->buswidth = dtplat->bus_width;
chip->priv = dev;
chip->dev_index = 1;
memcpy(priv->minmax, dtplat->clock_freq_min_max, sizeof(priv->minmax));
ret = clk_get_by_index_platdata(dev, 0, dtplat->clocks, &priv->clk);
if (ret < 0)
return ret;
#endif
ftsdc_setup_cfg(&plat->cfg, dev->name, chip->buswidth, chip->caps,
priv->minmax[1] , priv->minmax[0]);
chip->mmc = &plat->mmc;
chip->mmc->priv = &priv->chip;
chip->mmc->dev = dev;
upriv->mmc = chip->mmc;
return ftsdc010_probe(dev);
}
static int nds32_mmc_bind(struct udevice *dev)
{
struct nds_mmc_plat *plat = dev_get_platdata(dev);
return ftsdc010_bind(dev, &plat->mmc, &plat->cfg);
}
static const struct udevice_id nds32_mmc_ids[] = {
{ .compatible = "andestech,atsdc010" },
{ }
};
U_BOOT_DRIVER(nds32_mmc_drv) = {
.name = "nds32_mmc",
.id = UCLASS_MMC,
.of_match = nds32_mmc_ids,
.ofdata_to_platdata = nds32_mmc_ofdata_to_platdata,
.ops = &dm_ftsdc010_ops,
.bind = nds32_mmc_bind,
.probe = nds32_mmc_probe,
.priv_auto_alloc_size = sizeof(struct ftsdc_priv),
.platdata_auto_alloc_size = sizeof(struct nds_mmc_plat),
};
|