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
|
// SPDX-License-Identifier: GPL-2.0-only
#include <common.h>
#include <mach/xload.h>
#include <mci.h>
#include "atmel-mci-regs.h"
#define SECTOR_SIZE 512
#define SUPPORT_MAX_BLOCKS 16U
struct atmel_mci_priv {
struct atmel_mci host;
bool highcapacity_card;
};
static struct atmel_mci_priv atmci_sdcard;
static int atmel_mci_pbl_stop_transmission(struct atmel_mci_priv *priv)
{
struct mci_cmd cmd = {
.cmdidx = MMC_CMD_STOP_TRANSMISSION,
.resp_type = MMC_RSP_R1b,
};
return atmci_common_request(&priv->host, &cmd, NULL);
}
static int at91_mci_sd_cmd_read_multiple_block(struct atmel_mci_priv *priv,
void *buf,
unsigned int start,
unsigned int block_count)
{
u16 block_len = SECTOR_SIZE;
struct mci_data data;
struct mci_cmd cmd = {
.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK,
.resp_type = MMC_RSP_R1,
.cmdarg = start,
};
if (!priv->highcapacity_card)
cmd.cmdarg *= block_len;
data.dest = buf;
data.flags = MMC_DATA_READ;
data.blocksize = block_len;
data.blocks = block_count;
return atmci_common_request(&priv->host, &cmd, &data);
}
static int at91_mci_bio_read(struct pbl_bio *bio, off_t start,
void *buf, unsigned int nblocks)
{
struct atmel_mci_priv *priv = bio->priv;
unsigned int blocks_done = 0;
unsigned int blocks;
unsigned int block_len = SECTOR_SIZE;
unsigned int blocks_read;
int ret;
while (blocks_done < nblocks) {
blocks = min(nblocks - blocks_done, SUPPORT_MAX_BLOCKS);
blocks_read = at91_mci_sd_cmd_read_multiple_block(priv, buf,
start + blocks_done,
blocks);
ret = atmel_mci_pbl_stop_transmission(priv);
if (ret)
return ret;
blocks_done += blocks_read;
if (blocks_read != blocks)
break;
buf += blocks * block_len;
}
return blocks_done;
}
int at91_mci_bio_init(struct pbl_bio *bio, void __iomem *base,
unsigned int clock, unsigned int slot)
{
struct atmel_mci_priv *priv = &atmci_sdcard;
struct atmel_mci *host = &priv->host;
struct mci_ios ios = { .bus_width = MMC_BUS_WIDTH_4, .clock = 25000000 };
/* PBL will get MCI controller in disabled state. We need to reconfigure
* it. */
bio->priv = priv;
bio->read = at91_mci_bio_read;
host->regs = base;
atmci_get_cap(host);
host->bus_hz = clock;
host->slot_b = slot;
if (host->slot_b)
host->sdc_reg = ATMCI_SDCSEL_SLOT_B;
else
host->sdc_reg = ATMCI_SDCSEL_SLOT_A;
atmci_writel(host, ATMCI_DTOR, 0x7f);
atmci_common_set_ios(host, &ios);
priv->highcapacity_card = 1;
return 0;
}
|