Skip to content

Commit 593e53d

Browse files
committed
add sdhost.c
1 parent a036975 commit 593e53d

File tree

1 file changed

+243
-0
lines changed

1 file changed

+243
-0
lines changed

supplement/sdhost.c

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
// mmio
2+
#define KVA 0xffff000000000000
3+
#define MMIO_BASE (KVA + 0x3f000000)
4+
5+
// SD card command
6+
#define GO_IDLE_STATE 0
7+
#define SEND_OP_CMD 1
8+
#define ALL_SEND_CID 2
9+
#define SEND_RELATIVE_ADDR 3
10+
#define SELECT_CARD 7
11+
#define SEND_IF_COND 8
12+
#define VOLTAGE_CHECK_PATTERN 0x1aa
13+
#define STOP_TRANSMISSION 12
14+
#define SET_BLOCKLEN 16
15+
#define READ_SINGLE_BLOCK 17
16+
#define WRITE_SINGLE_BLOCK 24
17+
#define SD_APP_OP_COND 41
18+
#define SDCARD_3_3V (1 << 21)
19+
#define SDCARD_ISHCS (1 << 30)
20+
#define SDCARD_READY (1 << 31)
21+
#define APP_CMD 55
22+
23+
// gpio
24+
#define GPIO_BASE (MMIO_BASE + 0x200000)
25+
#define GPIO_GPFSEL4 (GPIO_BASE + 0x10)
26+
#define GPIO_GPFSEL5 (GPIO_BASE + 0x14)
27+
#define GPIO_GPPUD (GPIO_BASE + 0x94)
28+
#define GPIO_GPPUDCLK1 (GPIO_BASE + 0x9c)
29+
30+
// sdhost
31+
#define SDHOST_BASE (MMIO_BASE + 0x202000)
32+
#define SDHOST_CMD (SDHOST_BASE + 0)
33+
#define SDHOST_READ 0x40
34+
#define SDHOST_WRITE 0x80
35+
#define SDHOST_LONG_RESPONSE 0x200
36+
#define SDHOST_NO_REPONSE 0x400
37+
#define SDHOST_BUSY 0x800
38+
#define SDHOST_NEW_CMD 0x8000
39+
#define SDHOST_ARG (SDHOST_BASE + 0x4)
40+
#define SDHOST_TOUT (SDHOST_BASE + 0x8)
41+
#define SDHOST_TOUT_DEFAULT 0xf00000
42+
#define SDHOST_CDIV (SDHOST_BASE + 0xc)
43+
#define SDHOST_CDIV_MAXDIV 0x7ff
44+
#define SDHOST_CDIV_DEFAULT 0x148
45+
#define SDHOST_RESP0 (SDHOST_BASE + 0x10)
46+
#define SDHOST_RESP1 (SDHOST_BASE + 0x14)
47+
#define SDHOST_RESP2 (SDHOST_BASE + 0x18)
48+
#define SDHOST_RESP3 (SDHOST_BASE + 0x1c)
49+
#define SDHOST_HSTS (SDHOST_BASE + 0x20)
50+
#define SDHOST_HSTS_MASK (0x7f8)
51+
#define SDHOST_HSTS_ERR_MASK (0xf8)
52+
#define SDHOST_HSTS_DATA (1 << 0)
53+
#define SDHOST_PWR (SDHOST_BASE + 0x30)
54+
#define SDHOST_DBG (SDHOST_BASE + 0x34)
55+
#define SDHOST_DBG_FSM_DATA 1
56+
#define SDHOST_DBG_FSM_MASK 0xf
57+
#define SDHOST_DBG_MASK (0x1f << 14 | 0x1f << 9)
58+
#define SDHOST_DBG_FIFO (0x4 << 14 | 0x4 << 9)
59+
#define SDHOST_CFG (SDHOST_BASE + 0x38)
60+
#define SDHOST_CFG_DATA_EN (1 << 4)
61+
#define SDHOST_CFG_SLOW (1 << 3)
62+
#define SDHOST_CFG_INTBUS (1 << 1)
63+
#define SDHOST_SIZE (SDHOST_BASE + 0x3c)
64+
#define SDHOST_DATA (SDHOST_BASE + 0x40)
65+
#define SDHOST_CNT (SDHOST_BASE + 0x50)
66+
67+
// helper
68+
#define set(io_addr, val) \
69+
asm volatile("str %w1, [%0]" ::"r"(io_addr), "r"(val) : "memory");
70+
71+
#define get(io_addr, val) \
72+
asm volatile("ldr %w0, [%1]" : "=r"(val) : "r"(io_addr) : "memory");
73+
74+
static inline void delay(unsigned long tick) {
75+
while (tick--) {
76+
asm volatile("nop");
77+
}
78+
}
79+
80+
static int is_hcs; // high capcacity(SDHC)
81+
82+
static void pin_setup() {
83+
set(GPIO_GPFSEL4, 0x24000000);
84+
set(GPIO_GPFSEL5, 0x924);
85+
set(GPIO_GPPUD, 0);
86+
delay(15000);
87+
set(GPIO_GPPUDCLK1, 0xffffffff);
88+
delay(15000);
89+
set(GPIO_GPPUDCLK1, 0);
90+
}
91+
92+
static void sdhost_setup() {
93+
unsigned int tmp;
94+
set(SDHOST_PWR, 0);
95+
set(SDHOST_CMD, 0);
96+
set(SDHOST_ARG, 0);
97+
set(SDHOST_TOUT, SDHOST_TOUT_DEFAULT);
98+
set(SDHOST_CDIV, 0);
99+
set(SDHOST_HSTS, SDHOST_HSTS_MASK);
100+
set(SDHOST_CFG, 0);
101+
set(SDHOST_CNT, 0);
102+
set(SDHOST_SIZE, 0);
103+
get(SDHOST_DBG, tmp);
104+
tmp &= ~SDHOST_DBG_MASK;
105+
tmp |= SDHOST_DBG_FIFO;
106+
set(SDHOST_DBG, tmp);
107+
delay(250000);
108+
set(SDHOST_PWR, 1);
109+
delay(250000);
110+
set(SDHOST_CFG, SDHOST_CFG_SLOW | SDHOST_CFG_INTBUS | SDHOST_CFG_DATA_EN);
111+
set(SDHOST_CDIV, SDHOST_CDIV_DEFAULT);
112+
}
113+
114+
static int wait_sd() {
115+
int cnt = 1000000;
116+
unsigned int cmd;
117+
do {
118+
if (cnt == 0) {
119+
return -1;
120+
}
121+
get(SDHOST_CMD, cmd);
122+
--cnt;
123+
} while (cmd & SDHOST_NEW_CMD);
124+
return 0;
125+
}
126+
127+
static int sd_cmd(unsigned cmd, unsigned int arg) {
128+
set(SDHOST_ARG, arg);
129+
set(SDHOST_CMD, cmd | SDHOST_NEW_CMD);
130+
return wait_sd();
131+
}
132+
133+
static int sdcard_setup() {
134+
unsigned int tmp;
135+
sd_cmd(GO_IDLE_STATE | SDHOST_NO_REPONSE, 0);
136+
sd_cmd(SEND_IF_COND, VOLTAGE_CHECK_PATTERN);
137+
get(SDHOST_RESP0, tmp);
138+
if (tmp != VOLTAGE_CHECK_PATTERN) {
139+
return -1;
140+
}
141+
while (1) {
142+
if (sd_cmd(APP_CMD, 0) == -1) {
143+
// MMC card or invalid card status
144+
// currently not support
145+
continue;
146+
}
147+
sd_cmd(SD_APP_OP_COND, SDCARD_3_3V | SDCARD_ISHCS);
148+
get(SDHOST_RESP0, tmp);
149+
if (tmp & SDCARD_READY) {
150+
break;
151+
}
152+
delay(1000000);
153+
}
154+
155+
is_hcs = tmp & SDCARD_ISHCS;
156+
sd_cmd(ALL_SEND_CID | SDHOST_LONG_RESPONSE, 0);
157+
sd_cmd(SEND_RELATIVE_ADDR, 0);
158+
get(SDHOST_RESP0, tmp);
159+
sd_cmd(SELECT_CARD, tmp);
160+
sd_cmd(SET_BLOCKLEN, 512);
161+
return 0;
162+
}
163+
164+
static int wait_fifo() {
165+
int cnt = 1000000;
166+
unsigned int hsts;
167+
do {
168+
if (cnt == 0) {
169+
return -1;
170+
}
171+
get(SDHOST_HSTS, hsts);
172+
--cnt;
173+
} while ((hsts & SDHOST_HSTS_DATA) == 0);
174+
return 0;
175+
}
176+
177+
static void set_block(int size, int cnt) {
178+
set(SDHOST_SIZE, size);
179+
set(SDHOST_CNT, cnt);
180+
}
181+
182+
static void wait_finish() {
183+
unsigned int dbg;
184+
do {
185+
get(SDHOST_DBG, dbg);
186+
} while ((dbg & SDHOST_DBG_FSM_MASK) != SDHOST_HSTS_DATA);
187+
}
188+
189+
void readblock(int block_idx, void* buf) {
190+
unsigned int* buf_u = (unsigned int*)buf;
191+
int succ = 0;
192+
if (!is_hcs) {
193+
block_idx <<= 9;
194+
}
195+
do{
196+
set_block(512, 1);
197+
sd_cmd(READ_SINGLE_BLOCK | SDHOST_READ, block_idx);
198+
for (int i = 0; i < 128; ++i) {
199+
wait_fifo();
200+
get(SDHOST_DATA, buf_u[i]);
201+
}
202+
unsigned int hsts;
203+
get(SDHOST_HSTS, hsts);
204+
if (hsts & SDHOST_HSTS_ERR_MASK) {
205+
set(SDHOST_HSTS, SDHOST_HSTS_ERR_MASK);
206+
sd_cmd(STOP_TRANSMISSION | SDHOST_BUSY, 0);
207+
} else {
208+
succ = 1;
209+
}
210+
} while(!succ);
211+
wait_finish();
212+
}
213+
214+
void writeblock(int block_idx, void* buf) {
215+
unsigned int* buf_u = (unsigned int*)buf;
216+
int succ = 0;
217+
if (!is_hcs) {
218+
block_idx <<= 9;
219+
}
220+
do{
221+
set_block(512, 1);
222+
sd_cmd(WRITE_SINGLE_BLOCK | SDHOST_WRITE, block_idx);
223+
for (int i = 0; i < 128; ++i) {
224+
wait_fifo();
225+
set(SDHOST_DATA, buf_u[i]);
226+
}
227+
unsigned int hsts;
228+
get(SDHOST_HSTS, hsts);
229+
if (hsts & SDHOST_HSTS_ERR_MASK) {
230+
set(SDHOST_HSTS, SDHOST_HSTS_ERR_MASK);
231+
sd_cmd(STOP_TRANSMISSION | SDHOST_BUSY, 0);
232+
} else {
233+
succ = 1;
234+
}
235+
} while(!succ);
236+
wait_finish();
237+
}
238+
239+
void sd_init() {
240+
pin_setup();
241+
sdhost_setup();
242+
sdcard_setup();
243+
}

0 commit comments

Comments
 (0)