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