|
| 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