/*===========================================================================* * do_int * *===========================================================================*/ static void do_int(struct port *pp) { int devind, vcc_5v, vcc_3v, vcc_Xv, vcc_Yv, socket_5v, socket_3v, socket_Xv, socket_Yv; spin_t spin; u32_t csr_event, csr_present, csr_control; u8_t v8; u16_t v16; #if USE_INTS int r; #endif devind= pp->p_devind; v8= pci_attr_r8(devind, TI_CARD_CTRL); if (v8 & TI_CCR_IFG) { printf("ti1225: got functional interrupt\n"); pci_attr_w8(devind, TI_CARD_CTRL, v8); } if (debug) { printf("Socket event: 0x%x\n", pp->csr_ptr->csr_event); printf("Socket mask: 0x%x\n", pp->csr_ptr->csr_mask); } csr_present= pp->csr_ptr->csr_present; csr_control= pp->csr_ptr->csr_control; if ((csr_present & (CP_CDETECT1|CP_CDETECT2)) != 0) { if (debug) printf("do_int: no card present\n"); return; } if (csr_present & CP_BADVCCREQ) { printf("do_int: Bad Vcc request\n"); /* return; */ } if (csr_present & CP_DATALOST) { /* Do we care? */ if (debug) printf("do_int: Data lost\n"); /* return; */ } if (csr_present & CP_NOTACARD) { printf("do_int: Not a card\n"); return; } if (debug) { if (csr_present & CP_CBCARD) printf("do_int: Cardbus card detected\n"); if (csr_present & CP_16BITCARD) printf("do_int: 16-bit card detected\n"); } if (csr_present & CP_PWRCYCLE) { if (debug) printf("do_int: powered up\n"); return; } vcc_5v= !!(csr_present & CP_5VCARD); vcc_3v= !!(csr_present & CP_3VCARD); vcc_Xv= !!(csr_present & CP_XVCARD); vcc_Yv= !!(csr_present & CP_YVCARD); if (debug) { printf("do_int: card supports:%s%s%s%s\n", vcc_5v ? " 5V" : "", vcc_3v ? " 3V" : "", vcc_Xv ? " X.X V" : "", vcc_Yv ? " Y.Y V" : ""); } socket_5v= !!(csr_present & CP_5VSOCKET); socket_3v= !!(csr_present & CP_3VSOCKET); socket_Xv= !!(csr_present & CP_XVSOCKET); socket_Yv= !!(csr_present & CP_YVSOCKET); if (debug) { printf("do_int: socket supports:%s%s%s%s\n", socket_5v ? " 5V" : "", socket_3v ? " 3V" : "", socket_Xv ? " X.X V" : "", socket_Yv ? " Y.Y V" : ""); } if (vcc_5v && socket_5v) { csr_control= (csr_control & ~CC_VCCCTRL) | CC_VCC_5V; pp->csr_ptr->csr_control= csr_control; if (debug) printf("do_int: applying 5V\n"); } else if (vcc_3v && socket_3v) { csr_control= (csr_control & ~CC_VCCCTRL) | CC_VCC_3V; pp->csr_ptr->csr_control= csr_control; if (debug) printf("do_int: applying 3V\n"); } else if (vcc_Xv && socket_Xv) { csr_control= (csr_control & ~CC_VCCCTRL) | CC_VCC_XV; pp->csr_ptr->csr_control= csr_control; printf("do_int: applying X.X V\n"); } else if (vcc_Yv && socket_Yv) { csr_control= (csr_control & ~CC_VCCCTRL) | CC_VCC_YV; pp->csr_ptr->csr_control= csr_control; printf("do_int: applying Y.Y V\n"); } else { printf("do_int: socket and card are not compatible\n"); return; } csr_event= pp->csr_ptr->csr_event; if (csr_event) { if (debug) printf("clearing socket event\n"); pp->csr_ptr->csr_event= csr_event; if (debug) { printf("Socket event (cleared): 0x%x\n", pp->csr_ptr->csr_event); } } devind= pp->p_devind; v8= pci_attr_r8(devind, TI_CARD_CTRL); if (v8 & TI_CCR_IFG) { printf("ti1225: got functional interrupt\n"); pci_attr_w8(devind, TI_CARD_CTRL, v8); } if (debug) { v8= pci_attr_r8(devind, TI_CARD_CTRL); printf("TI_CARD_CTRL: 0x%02x\n", v8); } spin_init(&spin, 100000); do { csr_present= pp->csr_ptr->csr_present; if (csr_present & CP_PWRCYCLE) break; } while (spin_check(&spin)); if (!(csr_present & CP_PWRCYCLE)) { printf("do_int: not powered up?\n"); return; } /* Reset device */ v16= pci_attr_r16(devind, CBB_BRIDGECTRL); v16 |= CBB_BC_CRST; pci_attr_w16(devind, CBB_BRIDGECTRL, v16); /* Wait one microsecond. Is this correct? What are the specs? */ micro_delay(1); /* Clear CBB_BC_CRST */ v16= pci_attr_r16(devind, CBB_BRIDGECTRL); v16 &= ~CBB_BC_CRST; pci_attr_w16(devind, CBB_BRIDGECTRL, v16); /* Wait one microsecond after clearing the reset line. Is this * correct? What are the specs? */ micro_delay(1); pci_rescan_bus(pp->p_cb_busnr); #if USE_INTS r= sys_irqenable(&pp->p_hook); if (r != OK) panic("unable enable interrupts: %d", r); #endif }
/* * Initialize the MMC controller given a certain * instance. this driver only handles a single * mmchs controller at a given time. */ int mmchs_init(uint32_t instance) { uint32_t value; value = 0; struct minix_mem_range mr; spin_t spin; mr.mr_base = MMCHS1_REG_BASE; mr.mr_limit = MMCHS1_REG_BASE + 0x400; if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) { panic("Unable to request permission to map memory"); } /* Set the base address to use */ base_address = (uint32_t) vm_map_phys(SELF, (void *) MMCHS1_REG_BASE, 0x400); if (base_address == (uint32_t) MAP_FAILED) panic("Unable to map MMC memory"); #ifdef DM37XX base_address = (unsigned long) base_address - 0x100; #endif /* Soft reset of the controller. This section is documented in the TRM */ /* Write 1 to sysconfig[0] to trigger a reset */ set32(base_address + MMCHS_SD_SYSCONFIG, MMCHS_SD_SYSCONFIG_SOFTRESET, MMCHS_SD_SYSCONFIG_SOFTRESET); /* Read sysstatus to know when it's done */ spin_init(&spin, SANE_TIMEOUT); while (!(read32(base_address + MMCHS_SD_SYSSTATUS) & MMCHS_SD_SYSSTATUS_RESETDONE)) { if (spin_check(&spin) == FALSE) { mmc_log_warn(&log, "mmc init timeout\n"); return 1; } } /* Set SD default capabilities */ set32(base_address + MMCHS_SD_CAPA, MMCHS_SD_CAPA_VS_MASK, MMCHS_SD_CAPA_VS18 | MMCHS_SD_CAPA_VS30); /* TRM mentions MMCHS_SD_CUR_CAPA but does not describe how to limit * the current */ uint32_t mask = MMCHS_SD_SYSCONFIG_AUTOIDLE | MMCHS_SD_SYSCONFIG_ENAWAKEUP | MMCHS_SD_SYSCONFIG_STANDBYMODE | MMCHS_SD_SYSCONFIG_CLOCKACTIVITY | MMCHS_SD_SYSCONFIG_SIDLEMODE; /* Automatic clock gating strategy */ value = MMCHS_SD_SYSCONFIG_AUTOIDLE_EN; /* Enable wake-up capability */ value |= MMCHS_SD_SYSCONFIG_ENAWAKEUP_EN; /* Smart-idle */ value |= MMCHS_SD_SYSCONFIG_SIDLEMODE_IDLE; /* Both the interface and functional can be switched off */ value |= MMCHS_SD_SYSCONFIG_CLOCKACTIVITY_OFF; /* Go into wake-up mode when possible */ value |= MMCHS_SD_SYSCONFIG_STANDBYMODE_WAKEUP_INTERNAL; /* * wake-up configuration */ set32(base_address + MMCHS_SD_SYSCONFIG, mask, value); /* Wake-up on sd interrupt for SDIO */ set32(base_address + MMCHS_SD_HCTL, MMCHS_SD_HCTL_IWE, MMCHS_SD_HCTL_IWE_EN); /* * MMC host and bus configuration */ /* Configure data and command transfer (1 bit mode) */ set32(base_address + MMCHS_SD_CON, MMCHS_SD_CON_DW8, MMCHS_SD_CON_DW8_1BIT); set32(base_address + MMCHS_SD_HCTL, MMCHS_SD_HCTL_DTW, MMCHS_SD_HCTL_DTW_1BIT); /* Configure card voltage to 3.0 volt */ set32(base_address + MMCHS_SD_HCTL, MMCHS_SD_HCTL_SDVS, MMCHS_SD_HCTL_SDVS_VS30); /* Power on the host controller and wait for the * MMCHS_SD_HCTL_SDBP_POWER_ON to be set */ set32(base_address + MMCHS_SD_HCTL, MMCHS_SD_HCTL_SDBP, MMCHS_SD_HCTL_SDBP_ON); // /* TODO: Add padconf/pinmux stuff here as documented in the TRM */ spin_init(&spin, SANE_TIMEOUT); while ((read32(base_address + MMCHS_SD_HCTL) & MMCHS_SD_HCTL_SDBP) != MMCHS_SD_HCTL_SDBP_ON) { if (spin_check(&spin) == FALSE) { mmc_log_warn(&log, "mmc init timeout SDBP not set\n"); return 1; } } /* Enable internal clock and clock to the card */ set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_ICE, MMCHS_SD_SYSCTL_ICE_EN); // @TODO Fix external clock enable , this one is very slow // but we first need faster context switching // set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_CLKD, // (0x20 << 6)); set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_CLKD, (0x5 << 6)); set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_CEN, MMCHS_SD_SYSCTL_CEN_EN); spin_init(&spin, SANE_TIMEOUT); while ((read32(base_address + MMCHS_SD_SYSCTL) & MMCHS_SD_SYSCTL_ICS) != MMCHS_SD_SYSCTL_ICS_STABLE) { if (spin_check(&spin) == FALSE) { mmc_log_warn(&log, "clock not stable\n"); return 1; } } /* * See spruh73e page 3576 Card Detection, Identification, and Selection */ /* Enable command interrupt */ set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_CC_ENABLE, MMCHS_SD_IE_CC_ENABLE_ENABLE); /* Enable transfer complete interrupt */ set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_TC_ENABLE, MMCHS_SD_IE_TC_ENABLE_ENABLE); /* enable error interrupts */ /* NOTE: We are currently skipping the BADA interrupt it does get * raised for unknown reasons */ set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_ERROR_MASK, 0x0fffffffu); /* clear the error interrupts */ set32(base_address + MMCHS_SD_STAT, MMCHS_SD_STAT_ERROR_MASK, 0xffffffffu); /* send a init signal to the host controller. This does not actually * send a command to a card manner */ set32(base_address + MMCHS_SD_CON, MMCHS_SD_CON_INIT, MMCHS_SD_CON_INIT_INIT); /* command 0 , type other commands not response etc) */ write32(base_address + MMCHS_SD_CMD, 0x00); spin_init(&spin, SANE_TIMEOUT); while ((read32(base_address + MMCHS_SD_STAT) & MMCHS_SD_STAT_CC) != MMCHS_SD_STAT_CC_RAISED) { if (read32(base_address + MMCHS_SD_STAT) & 0x8000) { mmc_log_warn(&log, "%s, error stat %x\n", __FUNCTION__, read32(base_address + MMCHS_SD_STAT)); return 1; } if (spin_check(&spin) == FALSE) { mmc_log_warn(&log, "Interrupt not raised during init\n"); return 1; } } /* clear the cc interrupt status */ set32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_CC_ENABLE, MMCHS_SD_IE_CC_ENABLE_ENABLE); /* * Set Set SD_CON[1] INIT bit to 0x0 to end the initialization sequence */ set32(base_address + MMCHS_SD_CON, MMCHS_SD_CON_INIT, MMCHS_SD_CON_INIT_NOINIT); /* Set timeout */ set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_DTO, MMCHS_SD_SYSCTL_DTO_2POW27); /* Clean the MMCHS_SD_STAT register */ write32(base_address + MMCHS_SD_STAT, 0xffffffffu); #ifdef USE_INTR hook_id = 1; if (sys_irqsetpolicy(OMAP3_MMC1_IRQ, 0, &hook_id) != OK) { printf("mmc: couldn't set IRQ policy %d\n", OMAP3_MMC1_IRQ); return 1; } /* enable signaling from MMC controller towards interrupt controller */ write32(base_address + MMCHS_SD_ISE, 0xffffffffu); #endif return 0; }
int card_query_voltage_and_type(struct sd_card_regs *card) { struct mmc_command command; spin_t spin; command.cmd = MMC_APP_CMD; command.resp_type = RESP_LEN_48; command.args = MMC_ARG_RCA(0x0); /* RCA=0000 */ if (mmc_send_cmd(&command)) { return 1; } command.cmd = SD_APP_OP_COND; command.resp_type = RESP_LEN_48; /* 0x1 << 30 == send HCS (Host capacity support) and get OCR register */ command.args = MMC_OCR_3_3V_3_4V | MMC_OCR_3_2V_3_3V | MMC_OCR_3_1V_3_2V | MMC_OCR_3_0V_3_1V | MMC_OCR_2_9V_3_0V | MMC_OCR_2_8V_2_9V | MMC_OCR_2_7V_2_8V; command.args |= MMC_OCR_HCS; /* RCA=0000 */ if (mmc_send_cmd(&command)) { return 1; } /* @todo wait for max 1 ms */ spin_init(&spin, SANE_TIMEOUT); while (!(command.resp[0] & MMC_OCR_MEM_READY)) { command.cmd = MMC_APP_CMD; command.resp_type = RESP_LEN_48; command.args = MMC_ARG_RCA(0x0); /* RCA=0000 */ if (mmc_send_cmd(&command)) { return 1; } /* Send ADMD41 */ /* 0x1 << 30 == send HCS (Host capacity support) and get OCR * register */ command.cmd = SD_APP_OP_COND; command.resp_type = RESP_LEN_48; /* 0x1 << 30 == send HCS (Host capacity support) */ command.args = MMC_OCR_3_3V_3_4V | MMC_OCR_3_2V_3_3V | MMC_OCR_3_1V_3_2V | MMC_OCR_3_0V_3_1V | MMC_OCR_2_9V_3_0V | MMC_OCR_2_8V_2_9V | MMC_OCR_2_7V_2_8V; command.args |= MMC_OCR_HCS; /* RCA=0000 */ if (mmc_send_cmd(&command)) { return 1; } /* if bit 31 is set the response is valid */ if ((command.resp[0] & MMC_OCR_MEM_READY)) { break; } if (spin_check(&spin) == FALSE) { mmc_log_warn(&log, "TIMEOUT waiting for the SD card\n"); } } card->ocr = command.resp[3]; return 0; }
/*===========================================================================* * w_intr_wait * *===========================================================================*/ static int intr_wait(int mask) { long v; #ifdef USE_INTR if (sys_irqenable(&hook_id) != OK) printf("Failed to enable irqenable irq\n"); /* Wait for a task completion interrupt. */ message m; int ipc_status; int ticks = SANE_TIMEOUT * sys_hz() / 1000000; if (ticks <= 0) ticks = 1; while (1) { int rr; sys_setalarm(ticks, 0); if ((rr = driver_receive(ANY, &m, &ipc_status)) != OK) { panic("driver_receive failed: %d", rr); }; if (is_ipc_notify(ipc_status)) { switch (_ENDPOINT_P(m.m_source)) { case CLOCK: /* Timeout. */ // w_timeout(); /* a.o. set w_status */ mmc_log_warn(&log, "TIMEOUT\n"); return 1; break; case HARDWARE: v = read32(base_address + MMCHS_SD_STAT); if (v & mask) { sys_setalarm(0, 0); return 0; } else if (v & (1 << 15)) { return 1; /* error */ } else { mmc_log_debug(&log, "unexpected HW interrupt 0x%08x mask 0X%08x\n", v, mask); if (sys_irqenable(&hook_id) != OK) printf ("Failed to re-enable irqenable irq\n"); continue; // return 1; } default: /* * unhandled message. queue it and * handle it in the blockdriver loop. */ blockdriver_mq_queue(&m, ipc_status); } } else { mmc_log_debug(&log, "Other\n"); /* * unhandled message. queue it and handle it in the * blockdriver loop. */ blockdriver_mq_queue(&m, ipc_status); } } sys_setalarm(0, 0); /* cancel the alarm */ #else spin_t spin; spin_init(&spin, SANE_TIMEOUT); /* Wait for completion */ int counter = 0; while (1 == 1) { counter++; v = read32(base_address + MMCHS_SD_STAT); if (spin_check(&spin) == FALSE) { mmc_log_warn(&log, "Timeout waiting for interrupt (%d) value 0x%08x mask 0x%08x\n", counter, v, mask); return 1; } if (v & mask) { return 0; } else if (v & 0xFF00) { mmc_log_debug(&log, "unexpected HW interrupt (%d) 0x%08x mask 0x%08x\n", v, mask); return 1; } } return 1; /* unreached */ #endif /* USE_INTR */ }