1/** 2 * \file 3 * \brief OMAP44xx MMC Controller driver implementation 4 */ 5/* 6 * Copyright (c) 2013, ETH Zurich. 7 * All rights reserved. 8 * 9 * This file is distributed under the terms in the attached LICENSE file. 10 * If you do not find this file, copies can be found by writing to: 11 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 12 */ 13 14#include <barrelfish/barrelfish.h> 15#include <barrelfish/inthandler.h> 16 17#include <maps/omap44xx_map.h> 18 19#include <driverkit/driverkit.h> 20#include <arch/arm/omap44xx/device_registers.h> 21#include <if/cm2_defs.h> 22 23#include "mmchs.h" 24#include "cap_slots.h" 25 26static void mmchs_soft_reset(struct mmchs_driver_state* st) 27{ 28 MMCHS_DEBUG("%s:%d\n", __FUNCTION__, __LINE__); 29 omap44xx_mmchs1_mmchs_sysconfig_softreset_wrf(&st->mmchs, 0x1); 30 while (omap44xx_mmchs1_mmchs_sysstatus_resetdone_rdf(&st->mmchs) != 0x1); 31 32 MMCHS_DEBUG("%s:%d: sysctl reset\n", __FUNCTION__, __LINE__); 33 omap44xx_mmchs1_mmchs_sysctl_sra_wrf(&st->mmchs, 0x1); 34 while (omap44xx_mmchs1_mmchs_sysctl_sra_rdf(&st->mmchs) != 0x0); 35} 36 37static void set_hardware_capabilities(struct mmchs_driver_state* st) 38{ 39 omap44xx_mmchs1_mmchs_capa_vs18_wrf(&st->mmchs, 0x1); 40 omap44xx_mmchs1_mmchs_capa_vs30_wrf(&st->mmchs, 0x1); 41} 42 43static void set_wake_up_configuration(struct mmchs_driver_state* st) 44{ 45 omap44xx_mmchs1_mmchs_sysconfig_enawakeup_wrf(&st->mmchs, 0x1); 46 omap44xx_mmchs1_mmchs_hctl_iwe_wrf(&st->mmchs, 0x1); 47} 48 49/** 50 * \see TRM rev Z, Section 24.5.1.2.1.7.2 51 */ 52static void change_clock_frequency_to_fit_protocol(struct mmchs_driver_state* st, uint32_t clock) 53{ 54 omap44xx_mmchs1_mmchs_sysctl_cen_wrf(&st->mmchs, 0x0); 55 omap44xx_mmchs1_mmchs_sysctl_clkd_wrf(&st->mmchs, clock); 56 57 MMCHS_DEBUG("%s:%d: Wait until clock is stable.\n", __FUNCTION__, __LINE__); 58 while (omap44xx_mmchs1_mmchs_sysctl_ics_rdf(&st->mmchs) != 0x1); 59 60 omap44xx_mmchs1_mmchs_sysctl_cen_wrf(&st->mmchs, 0x1); 61} 62 63static void mmc_host_and_bus_configuration(struct mmchs_driver_state* st) 64{ 65 omap44xx_mmchs1_mmchs_con_od_wrf(&st->mmchs, 0x0); 66 omap44xx_mmchs1_mmchs_con_dw8_wrf(&st->mmchs, 0x0); 67 omap44xx_mmchs1_mmchs_con_ceata_wrf(&st->mmchs, 0x0); 68 69 omap44xx_mmchs1_mmchs_hctl_sdvs_wrf(&st->mmchs, 0x6); 70 omap44xx_mmchs1_mmchs_hctl_sdbp_wrf(&st->mmchs, 0x0); 71 omap44xx_mmchs1_mmchs_hctl_dtw_wrf(&st->mmchs, 0x0); 72 73 omap44xx_mmchs1_mmchs_sysctl_cen_wrf(&st->mmchs, 0x0); 74 omap44xx_mmchs1_mmchs_sysctl_ice_wrf(&st->mmchs, 0x1); 75 76 uint32_t clock = 0; 77 st->cm2_binding->rpc_tx_vtbl.get_hsmmc1_base_clock(st->cm2_binding, &clock); 78 MMCHS_DEBUG("%s:%d: clksel = %u\n", __FUNCTION__, __LINE__, clock); 79 change_clock_frequency_to_fit_protocol(st, 0x258); 80 81 MMCHS_DEBUG("%s:%d: Wait until internal clock is stable.\n", __FUNCTION__, __LINE__); 82 while (omap44xx_mmchs1_mmchs_sysctl_ics_rdf(&st->mmchs) != 0x1); 83 84 omap44xx_mmchs1_mmchs_hctl_sdbp_wrf(&st->mmchs, 0x1); 85 assert(omap44xx_mmchs1_mmchs_hctl_sdbp_rdf(&st->mmchs) == 0x1); 86 87 // Pessimistic settings, we want to have this thing always ON for testing 88 omap44xx_mmchs1_mmchs_sysconfig_clockactivity_wrf(&st->mmchs, 0x3); 89 omap44xx_mmchs1_mmchs_sysconfig_standbymode_wrf(&st->mmchs, 0x1); 90 omap44xx_mmchs1_mmchs_sysconfig_sidlemode_wrf(&st->mmchs, 0x1); 91 omap44xx_mmchs1_mmchs_sysconfig_autoidle_wrf(&st->mmchs, 0x0); 92} 93 94/** 95 * \see TRM rev Z, Section 24.5.1.2.1.1.1 96 */ 97static void cmd_line_reset(struct mmchs_driver_state* st) 98{ 99 MMCHS_DEBUG("%s:%d\n", __FUNCTION__, __LINE__); 100 101 omap44xx_mmchs1_mmchs_sysctl_src_wrf(&st->mmchs, 0x1); 102 while (omap44xx_mmchs1_mmchs_sysctl_src_rdf(&st->mmchs) != 0x1); 103 while (omap44xx_mmchs1_mmchs_sysctl_src_rdf(&st->mmchs) != 0x0); 104} 105 106/** 107 * \see TRM rev Z, Section 24.5.1.2.1.2.1 108 */ 109static void dat_line_reset(struct mmchs_driver_state* st) 110{ 111 MMCHS_DEBUG("%s:%d\n", __FUNCTION__, __LINE__); 112 113 omap44xx_mmchs1_mmchs_sysctl_srd_wrf(&st->mmchs, 0x1); 114 while (omap44xx_mmchs1_mmchs_sysctl_srd_rdf(&st->mmchs) != 0x1); 115 while (omap44xx_mmchs1_mmchs_sysctl_srd_rdf(&st->mmchs) != 0x0); 116} 117 118 119// TODO(gz): Got this from old mmchs code, its ugly and should 120// go away with a proper sleep functionality 121volatile uint32_t dummy = 0; 122static void wait_msec(long msec) 123{ 124 int i = 0, sum = 0; 125 long end = (1200000 * msec / 8); 126 127 // Cannot use volatile variables in loop 128 while (++i < end) { 129 sum += i + end; 130 } 131 132 dummy += sum; 133} 134 135 136/** 137 * \see TRM rev Z, Section 24.5.1.2.1.7.1 138 */ 139static void send_command(struct mmchs_driver_state* st, omap44xx_mmchs1_indx_status_t cmd, uint32_t arg) 140{ 141 MMCHS_DEBUG("%s:%d: cmd = 0x%x arg=0x%x\n", __FUNCTION__, __LINE__, cmd, arg); 142 143 MMCHS_DEBUG("%s:%d: Wait until command line is free.\n", __FUNCTION__, __LINE__); 144 while (omap44xx_mmchs1_mmchs_pstate_cmdi_rdf(&st->mmchs) != 0x0); 145 MMCHS_DEBUG("%s:%d: \n", __FUNCTION__, __LINE__); 146 147 omap44xx_mmchs1_mmchs_stat_rawwr(&st->mmchs, ~0x0); 148 149 // Only for MMC cards 150 omap44xx_mmchs1_mmchs_con_mit_wrf(&st->mmchs, 0x0); 151 omap44xx_mmchs1_mmchs_con_str_wrf(&st->mmchs, 0x0); 152 153 omap44xx_mmchs1_mmchs_csre_rawwr(&st->mmchs, 0x0); 154 155 omap44xx_mmchs1_mmchs_blk_blen_wrf(&st->mmchs, 512); 156 omap44xx_mmchs1_mmchs_blk_nblk_wrf(&st->mmchs, 0x1); 157 158 omap44xx_mmchs1_mmchs_sysctl_dto_wrf(&st->mmchs, 0xE); // omapconf 159 160 omap44xx_mmchs1_mmchs_arg_rawwr(&st->mmchs, arg); 161 162 // Enable interrupts 163 omap44xx_mmchs1_mmchs_ie_rawwr(&st->mmchs, ~0x0); 164 //omap44xx_mmchs1_mmchs_ise_rawwr(&st->mmchs, ~0x0); 165 166 omap44xx_mmchs1_mmchs_cmd_t cmdreg = omap44xx_mmchs1_mmchs_cmd_default; 167 168 // see TRM rev Z, Table 24-4 169 // and Physical Layer Simplified Spec 3.01, Section 4.7.4 170 switch (cmd) { 171 // R2 172 case omap44xx_mmchs1_INDX_2: 173 case omap44xx_mmchs1_INDX_9: 174 cmdreg = omap44xx_mmchs1_mmchs_cmd_rsp_type_insert(cmdreg, 0x1); 175 cmdreg = omap44xx_mmchs1_mmchs_cmd_ccce_insert(cmdreg, 0x1); 176 break; 177 // R1, R6, R5, R7 178 case omap44xx_mmchs1_INDX_17: 179 cmdreg = omap44xx_mmchs1_mmchs_cmd_ddir_insert(cmdreg, 0x1); 180 case omap44xx_mmchs1_INDX_24: 181 cmdreg = omap44xx_mmchs1_mmchs_cmd_dp_insert(cmdreg, 0x1); 182 cmdreg = omap44xx_mmchs1_mmchs_cmd_acen_insert(cmdreg, 0x1); 183 // Fallthrough desired! 184 case omap44xx_mmchs1_INDX_0: 185 case omap44xx_mmchs1_INDX_3: 186 case omap44xx_mmchs1_INDX_5: 187 case omap44xx_mmchs1_INDX_8: 188 case omap44xx_mmchs1_INDX_16: 189 case omap44xx_mmchs1_INDX_41: 190 case omap44xx_mmchs1_INDX_55: 191 cmdreg = omap44xx_mmchs1_mmchs_cmd_rsp_type_insert(cmdreg, 0x2); 192 cmdreg = omap44xx_mmchs1_mmchs_cmd_ccce_insert(cmdreg, 0x1); 193 cmdreg = omap44xx_mmchs1_mmchs_cmd_cice_insert(cmdreg, 0x1); 194 break; 195 // R1b, R5b 196 case omap44xx_mmchs1_INDX_7: 197 case omap44xx_mmchs1_INDX_12: 198 cmdreg = omap44xx_mmchs1_mmchs_cmd_rsp_type_insert(cmdreg, 0x3); 199 cmdreg = omap44xx_mmchs1_mmchs_cmd_ccce_insert(cmdreg, 0x1); 200 cmdreg = omap44xx_mmchs1_mmchs_cmd_cice_insert(cmdreg, 0x1); 201 break; 202 default: 203 assert(!"Unsupported command\n"); 204 break; 205 } 206 207 cmdreg = omap44xx_mmchs1_mmchs_cmd_indx_insert(cmdreg, cmd); 208 omap44xx_mmchs1_mmchs_cmd_wr(&st->mmchs, cmdreg); 209 210 MMCHS_DEBUG("%s:%d: Wait until mmchs_stat.cc == 0x1\n", __FUNCTION__, __LINE__); 211 uint32_t cc = 0; 212 size_t i = 0; 213 do { 214 uint32_t cto = omap44xx_mmchs1_mmchs_stat_cto_rdf(&st->mmchs); 215 uint32_t ccrc = omap44xx_mmchs1_mmchs_stat_ccrc_rdf(&st->mmchs); 216 cc = omap44xx_mmchs1_mmchs_stat_cc_rdf(&st->mmchs); 217 218 if (cto == 0x1 && ccrc == 0x1) { 219 MMCHS_DEBUG("%s:%d: cto = 1 ccrc = 1: Conflict on cmd line.\n", __FUNCTION__, __LINE__); 220 cmd_line_reset(st); 221 return; 222 } 223 if (cto == 0x1 && ccrc == 0x0) { 224 MMCHS_DEBUG("%s:%d: cto = 1 ccrc = 0: Abort.\n", __FUNCTION__, __LINE__); 225 cmd_line_reset(st); 226 return; 227 } 228 229 if (i++ > 1000) { 230 omap44xx_mmchs1_mmchs_stat_pr(st->dbuf, DBUF_SIZE, &st->mmchs); 231 MMCHS_DEBUG("%s:%d: %s\n", __FUNCTION__, __LINE__, st->dbuf); 232 USER_PANIC("Command not Ackd?"); 233 } 234 wait_msec(1); 235 } while (cc != 0x1); 236 237 238 /*omap44xx_mmchs1_mmchs_pstate_pr(dbuf, DBUF_SIZE, &mmchs); 239 MMCHS_DEBUG("%s:%d: \n%s\n", __FUNCTION__, __LINE__, st->dbuf); 240 MMCHS_DEBUG("%s:%d: mmchs_rsp10 = 0x%x\n", __FUNCTION__, __LINE__, 241 omap44xx_mmchs1_mmchs_rsp10_rd(&st->mmchs)); 242 MMCHS_DEBUG("%s:%d: mmchs_rsp32 = 0x%x\n", __FUNCTION__, __LINE__, 243 omap44xx_mmchs1_mmchs_rsp32_rd(&st->mmchs)); 244 MMCHS_DEBUG("%s:%d: mmchs_rsp54 = 0x%x\n", __FUNCTION__, __LINE__, 245 omap44xx_mmchs1_mmchs_rsp54_rd(&st->mmchs)); 246 MMCHS_DEBUG("%s:%d: mmchs_rsp76 = 0x%x\n", __FUNCTION__, __LINE__, 247 omap44xx_mmchs1_mmchs_rsp76_rd(&st->mmchs));*/ 248 249 250 uint32_t resp_type = omap44xx_mmchs1_mmchs_cmd_rsp_type_rdf(&st->mmchs); 251 if (resp_type == 0x0) { 252 MMCHS_DEBUG("%s:%d: No response.\n", __FUNCTION__, __LINE__); 253 return; 254 } 255} 256 257 258/** 259 * \see TRM rev Z, Figure 24-38 260 */ 261static void mmchs_identify_card(struct mmchs_driver_state* st) 262{ 263 // Module Initialization is done in mmchs_init() 264 omap44xx_mmchs1_mmchs_ie_rawwr(&st->mmchs, 0xFFFFFFFF); 265 266 omap44xx_mmchs1_mmchs_con_init_wrf(&st->mmchs, 0x1); 267 268 omap44xx_mmchs1_mmchs_cmd_rawwr(&st->mmchs, 0x0); 269 while (omap44xx_mmchs1_mmchs_stat_cc_rdf(&st->mmchs) != 0x1); 270 271 wait_msec(10); 272 omap44xx_mmchs1_mmchs_stat_cc_wrf(&st->mmchs, 0x1); 273 274 omap44xx_mmchs1_mmchs_cmd_rawwr(&st->mmchs, 0x0); 275 while (omap44xx_mmchs1_mmchs_stat_cc_rdf(&st->mmchs) != 0x1); 276 277 omap44xx_mmchs1_mmchs_stat_cc_wrf(&st->mmchs, 0x1); 278 omap44xx_mmchs1_mmchs_con_init_wrf(&st->mmchs, 0x0); 279 280 //omap44xx_mmchs1_mmchs_stat_rawwr(&st->mmchs, 0xFFFFFFFF); 281 282 omap44xx_mmchs1_mmchs_hctl_sdbp_wrf(&st->mmchs, 0x1); 283 change_clock_frequency_to_fit_protocol(st, 0xF0UL); 284 285 send_command(st, 0, 0x0); 286 287 uint32_t arg8 = (0x1 << 8) | 0b10101010; 288 send_command(st, 8, arg8); 289 assert(omap44xx_mmchs1_mmchs_stat_cc_rdf(&st->mmchs) == 0x1); 290 291 send_command(st, 55, 0x0); 292 uint32_t ocrdata = 0; 293 do { 294 send_command(st, 55, 0x0); 295 MMCHS_DEBUG("%s:%d: ACMD41\n", __FUNCTION__, __LINE__); 296 uint32_t arg41 = 0x1 << 30 | ocrdata; 297 send_command(st, 41, arg41); 298 wait_msec(10); 299 ocrdata = omap44xx_mmchs1_mmchs_rsp10_rd(&st->mmchs); 300 } while ((omap44xx_mmchs1_mmchs_rsp10_rd(&st->mmchs) & (1 << 31)) == 0); 301 302 MMCHS_DEBUG("%s:%d: CMD2\n", __FUNCTION__, __LINE__); 303 send_command(st, 2, 0x0); 304 305 MMCHS_DEBUG("%s:%d: CMD3\n", __FUNCTION__, __LINE__); 306 send_command(st, 3, 0x1); 307 uint32_t rca = omap44xx_mmchs1_mmchs_rsp10_rd(&st->mmchs) >> 16; 308 MMCHS_DEBUG("Status: 0x%X\n", rca & 0xFFFF); 309 MMCHS_DEBUG("RCA: 0x%X\n", (rca >> 16) & 0xFFFF); 310 311 MMCHS_DEBUG("%s:%d: CMD9\n", __FUNCTION__, __LINE__); 312 send_command(st, 9, rca << 16); 313 314 MMCHS_DEBUG("%s:%d: CMD7\n", __FUNCTION__, __LINE__); 315 send_command(st, 7, rca << 16); 316 317 MMCHS_DEBUG("%s:%d: CMD16\n", __FUNCTION__, __LINE__); 318 send_command(st, 16, 512); 319} 320 321static errval_t complete_card_transaction(struct mmchs_driver_state* st) 322{ 323 size_t i = 0; 324 do { 325 if ( omap44xx_mmchs1_mmchs_stat_tc_rdf(&st->mmchs) == 0x1 ) { 326 //send_command(12, 0); 327 return SYS_ERR_OK; // Fine as long as we support only finite transfers 328 } else { 329 bool deb = omap44xx_mmchs1_mmchs_stat_deb_rdf(&st->mmchs); 330 bool dcrc = omap44xx_mmchs1_mmchs_stat_dcrc_rdf(&st->mmchs); 331 bool dto = omap44xx_mmchs1_mmchs_stat_dto_rdf(&st->mmchs); 332 333 if (deb || dcrc || dto) { 334 MMCHS_DEBUG("%s:%d: Error interrupt during transfer: deb=%d dcrc=%d dto=%d.\n", 335 __FUNCTION__, __LINE__, deb, dcrc, dto); 336 dat_line_reset(st); 337 return MMC_ERR_TRANSFER; 338 } 339 } 340 341 wait_msec(10); 342 } while (i++ < 1000); 343 344 MMCHS_DEBUG("%s:%d: No transfer complete interrupt?\n", __FUNCTION__, __LINE__); 345 return MMC_ERR_TRANSFER; 346} 347 348/** 349 * \brief Reads a 512-byte block on the card. 350 * 351 * \param block_nr Index number of block to read. 352 * \param buffer Non-null buffer with a size of at least 512 bytes. 353 * 354 * \retval SYS_ERR_OK Block successfully written in buffer. 355 * \retval MMC_ERR_TRANSFER Error interrupt or no transfer complete interrupt. 356 * \retval MMC_ERR_READ_READY Card not ready to read. 357 */ 358errval_t mmchs_read_block(struct mmchs_driver_state* st, size_t block_nr, void *buffer) 359{ 360 MMCHS_DEBUG("%s:%d: Wait for free data lines.\n", __FUNCTION__, __LINE__); 361 while (omap44xx_mmchs1_mmchs_pstate_dati_rdf(&st->mmchs) != 0x0); 362 363 // Send data command 364 send_command(st, 17, block_nr); 365 // TODO(gz): Check for errors 366 367 for (size_t i = 0; i < (omap44xx_mmchs1_mmchs_blk_blen_rdf(&st->mmchs) + 3) / 4; i++) { 368 size_t timeout = 1000; 369 while (omap44xx_mmchs1_mmchs_stat_brr_rdf(&st->mmchs) == 0x0 && timeout--) { 370 wait_msec(1); 371 } 372 if (timeout == 0) { 373 return MMC_ERR_READ_READY; 374 } 375 376 ((uint32_t *) buffer)[i] = omap44xx_mmchs1_mmchs_data_rd(&st->mmchs); 377 } 378 379 return complete_card_transaction(st); 380} 381 382/** 383 * \brief Write a 512-byte block in the card. 384 * 385 * \param block_nr Index number of block to write. 386 * \param buffer Data to write (must be at least 512 bytes in size). 387 * 388 * \retval SYS_ERR_OK Block written to card. 389 * \retval MMC_ERR_TRANSFER Error interrupt or no transfer complete interrupt. 390 * \retval MMC_ERR_WRITE_READY Card not ready to write. 391 */ 392errval_t mmchs_write_block(struct mmchs_driver_state* st, size_t block_nr, void *buffer) 393{ 394 MMCHS_DEBUG("%s:%d: Wait for free data lines.\n", __FUNCTION__, __LINE__); 395 size_t timeout = 1000; 396 while (omap44xx_mmchs1_mmchs_pstate_dati_rdf(&st->mmchs) != 0x0 && timeout--) { 397 wait_msec(1); 398 } 399 if (timeout == 0) { 400 return MMC_ERR_WRITE_READY; 401 } 402 403 // Send data command 404 send_command(st, 24, block_nr); 405 // TODO(gz): Check for errors 406 407 for (size_t i = 0; i < (omap44xx_mmchs1_mmchs_blk_blen_rdf(&st->mmchs) + 3) / 4; i++) { 408 while (omap44xx_mmchs1_mmchs_stat_bwr_rdf(&st->mmchs) == 0x0); 409 omap44xx_mmchs1_mmchs_data_wr(&st->mmchs, ((uint32_t *) buffer)[i]); 410 } 411 412 return complete_card_transaction(st); 413} 414 415/** 416 * MMC Initialization 417 * 418 * \see TRM rev Z, 24.5.1.1.2 419 */ 420void mmchs_init(struct mmchs_driver_state* st) 421{ 422 lvaddr_t mmchs_vaddr; 423 errval_t err = map_device_cap(st->caps[L4_PER_HSMMC1_SLOT], &mmchs_vaddr); 424 assert(err_is_ok(err)); 425 426 omap44xx_mmchs1_initialize(&st->mmchs, (mackerel_addr_t)mmchs_vaddr); 427 428 mmchs_soft_reset(st); 429 set_hardware_capabilities(st); 430 set_wake_up_configuration(st); 431 mmc_host_and_bus_configuration(st); 432 433 mmchs_identify_card(st); 434} 435