1// Copyright 2017 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <inttypes.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9
10#include <ddk/device.h>
11#include <ddk/debug.h>
12#include <ddk/protocol/sdmmc.h>
13
14#include <pretty/hexdump.h>
15
16#include "sdmmc.h"
17
18#define FREQ_200MHZ 200000000
19#define FREQ_52MHZ 52000000
20#define FREQ_25MHZ 25000000
21
22#define MMC_SECTOR_SIZE  512ul  // physical sector size
23#define MMC_BLOCK_SIZE   512ul  // block size is 512 bytes always because it is the required
24                                // value if the card is in DDR mode
25
26static zx_status_t mmc_do_switch(sdmmc_device_t* dev, uint8_t index, uint8_t value) {
27    // Send the MMC_SWITCH command
28    zx_status_t st = mmc_switch(dev, index, value);
29    if (st != ZX_OK) {
30        zxlogf(ERROR, "mmc: failed to MMC_SWITCH (0x%x=%d), retcode = %d\n", index, value, st);
31        return st;
32    }
33
34    // Check status after MMC_SWITCH
35    uint32_t resp;
36    st = sdmmc_send_status(dev, &resp);
37    if (st == ZX_OK) {
38        if (resp & MMC_STATUS_SWITCH_ERR) {
39            zxlogf(ERROR, "mmc: mmc status error after MMC_SWITCH (0x%x=%d), status = 0x%08x\n",
40                   index, value, resp);
41            st = ZX_ERR_INTERNAL;
42        }
43    } else {
44        zxlogf(ERROR, "mmc: failed to MMC_SEND_STATUS (%x=%d), retcode = %d\n", index, value, st);
45    }
46
47    return ZX_OK;
48}
49
50static zx_status_t mmc_set_bus_width(sdmmc_device_t* dev, sdmmc_bus_width_t bus_width,
51                                     uint8_t mmc_ext_csd_bus_width) {
52    // Switch the card to the new bus width
53    zx_status_t st = mmc_do_switch(dev, MMC_EXT_CSD_BUS_WIDTH, mmc_ext_csd_bus_width);
54    if (st != ZX_OK) {
55        zxlogf(ERROR, "mmc: failed to switch bus width to EXT_CSD %d, retcode = %d\n",
56               mmc_ext_csd_bus_width, st);
57        return ZX_ERR_INTERNAL;
58    }
59
60    if (bus_width != dev->bus_width) {
61        // Switch the host to the new bus width
62        if ((st = sdmmc_set_bus_width(&dev->host, bus_width)) != ZX_OK) {
63            zxlogf(ERROR, "mmc: failed to switch the host bus width to %d, retcode = %d\n",
64                   bus_width, st);
65            return ZX_ERR_INTERNAL;
66        }
67    }
68    dev->bus_width = bus_width;
69    return ZX_OK;
70}
71
72static uint8_t mmc_select_bus_width(sdmmc_device_t* dev) {
73    // TODO verify host 8-bit support
74    uint8_t bus_widths[] = { SDMMC_BUS_WIDTH_8, MMC_EXT_CSD_BUS_WIDTH_8,
75                             SDMMC_BUS_WIDTH_4, MMC_EXT_CSD_BUS_WIDTH_4,
76                             SDMMC_BUS_WIDTH_1, MMC_EXT_CSD_BUS_WIDTH_1 };
77    for (unsigned i = 0; i < (sizeof(bus_widths)/sizeof(uint8_t)); i += 2) {
78        if (mmc_set_bus_width(dev, bus_widths[i], bus_widths[i+1]) == ZX_OK) {
79            break;
80        }
81    }
82    return dev->bus_width;
83}
84
85static zx_status_t mmc_switch_timing(sdmmc_device_t* dev, sdmmc_timing_t new_timing) {
86    // Switch the device timing
87    uint8_t ext_csd_timing;
88    switch (new_timing) {
89    case SDMMC_TIMING_LEGACY:
90        ext_csd_timing = MMC_EXT_CSD_HS_TIMING_LEGACY;
91        break;
92    case SDMMC_TIMING_HS:
93        ext_csd_timing = MMC_EXT_CSD_HS_TIMING_HS;
94        break;
95    case SDMMC_TIMING_HSDDR:
96        // sdhci has a different timing constant for HSDDR vs HS
97        ext_csd_timing = MMC_EXT_CSD_HS_TIMING_HS;
98        break;
99    case SDMMC_TIMING_HS200:
100        ext_csd_timing = MMC_EXT_CSD_HS_TIMING_HS200;
101        break;
102    case SDMMC_TIMING_HS400:
103        ext_csd_timing = MMC_EXT_CSD_HS_TIMING_HS400;
104        break;
105    default:
106        return ZX_ERR_INVALID_ARGS;
107    };
108
109    zx_status_t st = mmc_do_switch(dev, MMC_EXT_CSD_HS_TIMING, ext_csd_timing);
110    if (st != ZX_OK) {
111        zxlogf(ERROR, "mmc: failed to switch device timing to %d\n", new_timing);
112        return st;
113    }
114
115    // Switch the host timing
116    if ((st = sdmmc_set_timing(&dev->host, new_timing)) != ZX_OK) {
117        zxlogf(ERROR, "mmc: failed to switch host timing to %d\n", new_timing);
118        return st;
119    }
120
121    dev->timing = new_timing;
122    return st;
123}
124
125static zx_status_t mmc_switch_freq(sdmmc_device_t* dev, uint32_t new_freq) {
126    zx_status_t st;
127    if ((st = sdmmc_set_bus_freq(&dev->host, new_freq)) != ZX_OK) {
128        zxlogf(ERROR, "mmc: failed to set host bus frequency, retcode = %d\n", st);
129        return st;
130    }
131    dev->clock_rate = new_freq;
132    return ZX_OK;
133}
134
135static zx_status_t mmc_decode_cid(sdmmc_device_t* dev, const uint8_t* raw_cid) {
136    printf("mmc: product name=%c%c%c%c%c%c\n",
137            raw_cid[MMC_CID_PRODUCT_NAME_START], raw_cid[MMC_CID_PRODUCT_NAME_START + 1],
138            raw_cid[MMC_CID_PRODUCT_NAME_START + 2], raw_cid[MMC_CID_PRODUCT_NAME_START + 3],
139            raw_cid[MMC_CID_PRODUCT_NAME_START + 4], raw_cid[MMC_CID_PRODUCT_NAME_START + 5]);
140    printf("       revision=%u.%u\n", (raw_cid[MMC_CID_REVISION] >> 4) & 0xf,
141            raw_cid[MMC_CID_REVISION] & 0xf);
142    printf("       serial=%u\n", *((uint32_t*)&raw_cid[MMC_CID_SERIAL]));
143    return ZX_OK;
144}
145
146static zx_status_t mmc_decode_csd(sdmmc_device_t* dev, const uint8_t* raw_csd) {
147    uint8_t spec_vrsn = (raw_csd[MMC_CSD_SPEC_VERSION] >> 2) & 0xf;
148    // Only support spec version > 4.0
149    if (spec_vrsn < MMC_CID_SPEC_VRSN_40) {
150        return ZX_ERR_NOT_SUPPORTED;
151    }
152
153    zxlogf(SPEW, "mmc: CSD version %u spec version %u\n",
154           (raw_csd[MMC_CSD_SPEC_VERSION] >> 6) & 0x3, spec_vrsn);
155    if (driver_get_log_flags() & DDK_LOG_SPEW) {
156        zxlogf(SPEW, "CSD:\n");
157        hexdump8_ex(raw_csd, 16, 0);
158    }
159
160    // Only support high capacity (> 2GB) cards
161    uint16_t c_size = ((raw_csd[MMC_CSD_SIZE_START] >> 6) & 0x3) |
162                      (raw_csd[MMC_CSD_SIZE_START + 1] << 2) |
163                      ((raw_csd[MMC_CSD_SIZE_START + 2] & 0x3) << 10);
164    if (c_size != 0xfff) {
165        zxlogf(ERROR, "mmc: unsupported C_SIZE 0x%04x\n", c_size);
166        return ZX_ERR_NOT_SUPPORTED;
167    }
168    return ZX_OK;
169}
170
171static zx_status_t mmc_decode_ext_csd(sdmmc_device_t* dev, const uint8_t* raw_ext_csd) {
172    zxlogf(SPEW, "mmc: EXT_CSD version %u CSD version %u\n", raw_ext_csd[192], raw_ext_csd[194]);
173
174    // Get the capacity for the card
175    uint32_t sectors = (raw_ext_csd[212] << 0) | (raw_ext_csd[213] << 8) |
176                       (raw_ext_csd[214] << 16) | (raw_ext_csd[215] << 24);
177    dev->block_info.block_count = sectors * MMC_SECTOR_SIZE / MMC_BLOCK_SIZE;
178    dev->block_info.block_size = (uint32_t)MMC_BLOCK_SIZE;
179
180    zxlogf(TRACE, "mmc: found card with capacity = %" PRIu64 "B\n",
181           dev->block_info.block_count * dev->block_info.block_size);
182
183    return ZX_OK;
184}
185
186static bool mmc_supports_hs(sdmmc_device_t* dev) {
187    uint8_t device_type = dev->raw_ext_csd[MMC_EXT_CSD_DEVICE_TYPE];
188    return (device_type & (1 << 1));
189}
190
191static bool mmc_supports_hsddr(sdmmc_device_t* dev) {
192    uint8_t device_type = dev->raw_ext_csd[MMC_EXT_CSD_DEVICE_TYPE];
193    // Only support HSDDR @ 1.8V/3V
194    return (device_type & (1 << 2));
195}
196
197static bool mmc_supports_hs200(sdmmc_device_t* dev) {
198    uint8_t device_type = dev->raw_ext_csd[MMC_EXT_CSD_DEVICE_TYPE];
199    // Only support HS200 @ 1.8V
200    return (device_type & (1 << 4));
201}
202
203static bool mmc_supports_hs400(sdmmc_device_t* dev) {
204    uint8_t device_type = dev->raw_ext_csd[MMC_EXT_CSD_DEVICE_TYPE];
205    // Only support HS400 @ 1.8V
206    return (device_type & (1 << 6));
207}
208
209zx_status_t sdmmc_probe_mmc(sdmmc_device_t* dev) {
210    zx_status_t st = ZX_OK;
211
212    // Query OCR
213    uint32_t ocr = 0;
214    if ((st = mmc_send_op_cond(dev, ocr, &ocr)) != ZX_OK) {
215        zxlogf(ERROR, "mmc: MMC_SEND_OP_COND failed, retcode = %d\n", st);
216        goto err;
217    }
218
219    // Indicate sector mode
220    if ((st = mmc_send_op_cond(dev, ocr, &ocr)) != ZX_OK) {
221        zxlogf(ERROR, "mmc: MMC_SEND_OP_COND failed, retcode = %d\n", st);
222        goto err;
223    }
224
225    // Get CID from card
226    // Only supports 1 card currently so no need to loop
227    if ((st = mmc_all_send_cid(dev, dev->raw_cid)) != ZX_OK) {
228        zxlogf(ERROR, "mmc: MMC_ALL_SEND_CID failed, retcode = %d\n", st);
229        goto err;
230    }
231    zxlogf(SPEW, "mmc: MMC_ALL_SEND_CID cid 0x%08x 0x%08x 0x%08x 0x%08x\n",
232        dev->raw_cid[0],
233        dev->raw_cid[1],
234        dev->raw_cid[2],
235        dev->raw_cid[3]);
236
237    mmc_decode_cid(dev, (const uint8_t*)dev->raw_cid);
238
239    // Set relative card address
240    if ((st = mmc_set_relative_addr(dev, 1)) != ZX_OK) {
241        zxlogf(ERROR, "mmc: MMC_SET_RELATIVE_ADDR failed, retcode = %d\n", st);
242        goto err;
243    }
244    dev->rca = 1;
245
246    // Read CSD register
247    if ((st = mmc_send_csd(dev, dev->raw_csd)) != ZX_OK) {
248        zxlogf(ERROR, "mmc: MMC_SEND_CSD failed, retcode = %d\n", st);
249        goto err;
250    }
251
252    if ((st = mmc_decode_csd(dev, (const uint8_t*)dev->raw_csd)) != ZX_OK) {
253        goto err;
254    }
255
256    // Select the card
257    if ((st = mmc_select_card(dev)) != ZX_OK) {
258        zxlogf(ERROR, "mmc: MMC_SELECT_CARD failed, retcode = %d\n", st);
259        goto err;
260    }
261
262    // Read extended CSD register
263    if ((st = mmc_send_ext_csd(dev, dev->raw_ext_csd)) != ZX_OK) {
264        zxlogf(ERROR, "mmc: MMC_SEND_EXT_CSD failed, retcode = %d\n", st);
265        goto err;
266    }
267
268    if ((st = mmc_decode_ext_csd(dev, (const uint8_t*)dev->raw_ext_csd)) != ZX_OK) {
269        goto err;
270    }
271
272    dev->type = SDMMC_TYPE_MMC;
273    dev->bus_width = SDMMC_BUS_WIDTH_1;
274    dev->signal_voltage = SDMMC_VOLTAGE_330;
275
276    // Switch to high-speed timing
277    if (mmc_supports_hs(dev) || mmc_supports_hsddr(dev) || mmc_supports_hs200(dev)) {
278        // Switch to 1.8V signal voltage
279        sdmmc_voltage_t new_voltage = SDMMC_VOLTAGE_180;
280        if ((st = sdmmc_set_signal_voltage(&dev->host, new_voltage)) != ZX_OK) {
281            zxlogf(ERROR, "mmc: failed to switch to 1.8V signalling, retcode = %d\n", st);
282            goto err;
283        }
284        dev->signal_voltage = new_voltage;
285
286        mmc_select_bus_width(dev);
287
288        // Must perform tuning at HS200 first if HS400 is supported
289        if (mmc_supports_hs200(dev) && dev->bus_width != SDMMC_BUS_WIDTH_1 &&
290                !(dev->host_info.prefs & SDMMC_HOST_PREFS_DISABLE_HS200)) {
291            if ((st = mmc_switch_timing(dev, SDMMC_TIMING_HS200)) != ZX_OK) {
292                goto err;
293            }
294
295            if ((st = mmc_switch_freq(dev, FREQ_200MHZ)) != ZX_OK) {
296                goto err;
297            }
298
299            if ((st = sdmmc_perform_tuning(&dev->host, MMC_SEND_TUNING_BLOCK)) != ZX_OK) {
300                zxlogf(ERROR, "mmc: tuning failed %d\n", st);
301                goto err;
302            }
303
304            if (mmc_supports_hs400(dev) && dev->bus_width == SDMMC_BUS_WIDTH_8 &&
305                    !(dev->host_info.prefs & SDMMC_HOST_PREFS_DISABLE_HS400)) {
306                if ((st = mmc_switch_timing(dev, SDMMC_TIMING_HS)) != ZX_OK) {
307                    goto err;
308                }
309
310                if ((st = mmc_switch_freq(dev, FREQ_52MHZ)) != ZX_OK) {
311                    goto err;
312                }
313
314                if ((st = mmc_set_bus_width(dev, SDMMC_BUS_WIDTH_8,
315                                            MMC_EXT_CSD_BUS_WIDTH_8_DDR)) != ZX_OK) {
316                    goto err;
317                }
318
319                if ((st = mmc_switch_timing(dev, SDMMC_TIMING_HS400)) != ZX_OK) {
320                    goto err;
321                }
322
323                if ((st = mmc_switch_freq(dev, FREQ_200MHZ)) != ZX_OK) {
324                    goto err;
325                }
326            }
327        } else {
328            if ((st = mmc_switch_timing(dev, SDMMC_TIMING_HS)) != ZX_OK) {
329                goto err;
330            }
331
332            if (mmc_supports_hsddr(dev) && (dev->bus_width != SDMMC_BUS_WIDTH_1)) {
333                if ((st = mmc_switch_timing(dev, SDMMC_TIMING_HSDDR)) != ZX_OK) {
334                    goto err;
335                }
336
337                uint8_t mmc_bus_width = (dev->bus_width == SDMMC_BUS_WIDTH_4) ?
338                                            MMC_EXT_CSD_BUS_WIDTH_4_DDR :
339                                            MMC_EXT_CSD_BUS_WIDTH_8_DDR;
340                if ((st = mmc_set_bus_width(dev, dev->bus_width, mmc_bus_width)) != ZX_OK) {
341                    goto err;
342                }
343            }
344
345            if ((st = mmc_switch_freq(dev, FREQ_52MHZ)) != ZX_OK) {
346                goto err;
347            }
348        }
349    } else {
350        // Set the bus frequency to legacy timing
351        if ((st = mmc_switch_freq(dev, FREQ_25MHZ)) != ZX_OK) {
352            goto err;
353        }
354        dev->timing = SDMMC_TIMING_LEGACY;
355    }
356
357    zxlogf(INFO, "mmc: initialized mmc @ %u MHz, bus width %d, timing %d\n",
358            dev->clock_rate / 1000000, dev->bus_width, dev->timing);
359
360err:
361    return st;
362}
363