static bool wb_sdmmc_enable(struct wb_softc *wb) { int i = 5000; REPORT(wb, "TRACE: enable(wb)\n"); /* put the device in a known state */ wb_idx_write(wb, WB_INDEX_SETUP, WB_SETUP_SOFT_RST); while (--i > 0 && wb_idx_read(wb, WB_INDEX_SETUP) & WB_SETUP_SOFT_RST) delay(10); if (i == 0) { aprint_error_dev(wb->wb_dev, "timeout resetting device\n"); return false; } wb_idx_write(wb, WB_INDEX_CLK, WB_CLK_375K); wb_idx_write(wb, WB_INDEX_FIFOEN, 0); wb_idx_write(wb, WB_INDEX_DMA, 0); wb_idx_write(wb, WB_INDEX_PBSMSB, 0); wb_idx_write(wb, WB_INDEX_PBSLSB, 0); /* drain FIFO */ while ((wb_read(wb, WB_SD_FIFOSTS) & WB_FIFO_EMPTY) == 0) wb_read(wb, WB_SD_FIFO); wb_write(wb, WB_SD_CSR, 0); wb_write(wb, WB_SD_INTCTL, WB_INT_DEFAULT); wb_sdmmc_card_detect(wb); return true; }
void wb_led(struct wb_softc *wb, bool enable) { uint8_t val; val = wb_read(wb, WB_SD_CSR); if (enable) val |= WB_CSR_MS_LED; else val &= ~WB_CSR_MS_LED; wb_write(wb, WB_SD_CSR, val); }
static bool wb_sdmmc_disable(struct wb_softc *wb) { uint8_t val; REPORT(wb, "TRACE: disable(wb)\n"); val = wb_read(wb, WB_SD_CSR); val |= WB_CSR_POWER_N; wb_write(wb, WB_SD_CSR, val); return true; }
static void wb_sdmmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) { static const int opcodes[] = { 11, 17, 18, 20, 24, 25, 26, 27, 30, 42, 51, 56 }; struct wb_softc *wb = sch; uint8_t val; int blklen; int error; int i, retry; int s; REPORT(wb, "TRACE: sdmmc/exec_command(wb, cmd) " "opcode %d flags 0x%x data %p datalen %d\n", cmd->c_opcode, cmd->c_flags, cmd->c_data, cmd->c_datalen); if (cmd->c_datalen > 0) { /* controller only supports a select number of data opcodes */ for (i = 0; i < __arraycount(opcodes); i++) if (opcodes[i] == cmd->c_opcode) break; if (i == __arraycount(opcodes)) { cmd->c_error = EINVAL; goto done; } /* Fragment the data into proper blocks */ blklen = MIN(cmd->c_datalen, cmd->c_blklen); if (cmd->c_datalen % blklen > 0) { aprint_error_dev(wb->wb_dev, "data is not a multiple of %u bytes\n", blklen); cmd->c_error = EINVAL; goto done; } /* setup block size registers */ blklen = blklen + 2 * wb->wb_sdmmc_width; wb_idx_write(wb, WB_INDEX_PBSMSB, ((blklen >> 4) & 0xf0) | (wb->wb_sdmmc_width / 4)); wb_idx_write(wb, WB_INDEX_PBSLSB, blklen & 0xff); /* clear FIFO */ val = wb_idx_read(wb, WB_INDEX_SETUP); val |= WB_SETUP_FIFO_RST; wb_idx_write(wb, WB_INDEX_SETUP, val); while (wb_idx_read(wb, WB_INDEX_SETUP) & WB_SETUP_FIFO_RST) ; cmd->c_resid = cmd->c_datalen; cmd->c_buf = cmd->c_data; /* setup FIFO thresholds */ if (ISSET(cmd->c_flags, SCF_CMD_READ)) wb_idx_write(wb, WB_INDEX_FIFOEN, WB_FIFOEN_FULL | 8); else { wb_idx_write(wb, WB_INDEX_FIFOEN, WB_FIFOEN_EMPTY | 8); /* pre-fill the FIFO on write */ error = wb_sdmmc_transfer_data(wb, cmd); if (error) { cmd->c_error = error; goto done; } } } s = splsdmmc(); wb->wb_sdmmc_intsts = 0; wb_write(wb, WB_SD_COMMAND, cmd->c_opcode); wb_write(wb, WB_SD_COMMAND, (cmd->c_arg >> 24) & 0xff); wb_write(wb, WB_SD_COMMAND, (cmd->c_arg >> 16) & 0xff); wb_write(wb, WB_SD_COMMAND, (cmd->c_arg >> 8) & 0xff); wb_write(wb, WB_SD_COMMAND, (cmd->c_arg >> 0) & 0xff); splx(s); retry = 100000; while (wb_idx_read(wb, WB_INDEX_STATUS) & WB_STATUS_CARD_TRAFFIC) { if (--retry == 0) break; delay(1); } if (wb_idx_read(wb, WB_INDEX_STATUS) & WB_STATUS_CARD_TRAFFIC) { REPORT(wb, "command timed out, WB_INDEX_STATUS = 0x%02x\n", wb_idx_read(wb, WB_INDEX_STATUS)); cmd->c_error = ETIMEDOUT; goto done; } if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) { if (wb->wb_sdmmc_intsts & WB_INT_TIMEOUT) { cmd->c_error = ETIMEDOUT; goto done; } if (ISSET(cmd->c_flags, SCF_RSP_136)) wb_sdmmc_rsp_read_long(wb, cmd); else wb_sdmmc_rsp_read_short(wb, cmd); } if (cmd->c_error == 0 && cmd->c_datalen > 0) { wb_led(wb, true); while (cmd->c_resid > 0) { error = wb_sdmmc_transfer_data(wb, cmd); if (error) { cmd->c_error = error; break; } } wb_led(wb, false); } done: SET(cmd->c_flags, SCF_ITSDONE); if (cmd->c_error) { REPORT(wb, "cmd error = %d, op = %d [%s] " "blklen %d datalen %d resid %d\n", cmd->c_error, cmd->c_opcode, ISSET(cmd->c_flags, SCF_CMD_READ) ? "rd" : "wr", cmd->c_blklen, cmd->c_datalen, cmd->c_resid); } }
void outb (u8 value, unsigned long port) { wb_write(port, value); }