static int dwmci_init(struct mci_host *mci, struct device_d *dev) { struct dwmci_host *host = to_dwmci_host(mci); uint32_t fifo_size; dwmci_writel(host, DWMCI_PWREN, host->pwren_value); if (dwmci_wait_reset(host, DWMCI_RESET_ALL)) { dev_err(host->dev, "reset failed\n"); return -EIO; } dwmci_writel(host, DWMCI_RINTSTS, 0xffffffff); dwmci_writel(host, DWMCI_INTMASK, 0); dwmci_writel(host, DWMCI_TMOUT, 0xffffffff); dwmci_writel(host, DWMCI_IDINTEN, 0); dwmci_writel(host, DWMCI_BMOD, 1); fifo_size = dwmci_readl(host, DWMCI_FIFOTH); /* * Use reset default of the rx_wmark field to determine the * fifo depth. */ fifo_size = DWMCI_FIFOTH_FIFO_DEPTH(fifo_size); host->fifo_size_bytes = fifo_size * 4; /* * If fifo-depth property is set, use this value */ if (!of_property_read_u32(host->dev->device_node, "fifo-depth", &fifo_size)) { host->fifo_size_bytes = fifo_size; dev_dbg(host->dev, "Using fifo-depth=%u\n", host->fifo_size_bytes); } host->fifoth_val = DWMCI_FIFOTH_MSIZE(0x2) | DWMCI_FIFOTH_RX_WMARK(fifo_size / 2 - 1) | DWMCI_FIFOTH_TX_WMARK(fifo_size / 2); dwmci_writel(host, DWMCI_FIFOTH, host->fifoth_val); dwmci_writel(host, DWMCI_CLKENA, 0); dwmci_writel(host, DWMCI_CLKSRC, 0); return 0; }
static int dwmci_init(struct mci_host *mci, struct device_d *dev) { struct dwmci_host *host = to_dwmci_host(mci); uint32_t fifo_size, fifoth_val; dwmci_writel(host, DWMCI_PWREN, 1); if (dwmci_wait_reset(host, DWMCI_RESET_ALL)) { dev_err(host->dev, "reset failed\n"); return -EIO; } dwmci_writel(host, DWMCI_RINTSTS, 0xffffffff); dwmci_writel(host, DWMCI_INTMASK, 0); dwmci_writel(host, DWMCI_TMOUT, 0xffffffff); dwmci_writel(host, DWMCI_IDINTEN, 0); dwmci_writel(host, DWMCI_BMOD, 1); fifo_size = dwmci_readl(host, DWMCI_FIFOTH); /* * Use reset default of the rx_wmark field to determine the * fifo depth. */ fifo_size = DWMCI_FIFOTH_FIFO_DEPTH(fifo_size); host->fifo_size_bytes = fifo_size * 4; fifoth_val = DWMCI_FIFOTH_MSIZE(0x2) | DWMCI_FIFOTH_RX_WMARK(fifo_size / 2 - 1) | DWMCI_FIFOTH_TX_WMARK(fifo_size / 2); dwmci_writel(host, DWMCI_FIFOTH, fifoth_val); dwmci_writel(host, DWMCI_CLKENA, 0); dwmci_writel(host, DWMCI_CLKSRC, 0); return 0; }
static void dwmci_set_ios(struct mci_host *mci, struct mci_ios *ios) { struct dwmci_host *host = to_dwmci_host(mci); uint32_t ctype; dev_dbg(host->dev, "Buswidth = %d, clock: %d\n", ios->bus_width, ios->clock); if (ios->clock) dwmci_setup_bus(host, ios->clock); switch (ios->bus_width) { case MMC_BUS_WIDTH_8: ctype = DWMCI_CTYPE_8BIT; break; case MMC_BUS_WIDTH_4: ctype = DWMCI_CTYPE_4BIT; break; default: ctype = DWMCI_CTYPE_1BIT; break; } dwmci_writel(host, DWMCI_CTYPE, ctype); }
static int dwmci_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data) { struct dwmci_host *host = to_dwmci_host(mci); int flags = 0; uint32_t mask; uint32_t ctrl; uint64_t start; int ret; unsigned int num_bytes = 0; start = get_time_ns(); while (1) { if (!(dwmci_readl(host, DWMCI_STATUS) & DWMCI_STATUS_BUSY)) break; if (is_timeout(start, 100 * MSECOND)) { dev_dbg(host->dev, "Timeout on data busy\n"); return -ETIMEDOUT; } } dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL); if (data) { num_bytes = data->blocks * data->blocksize; if (data->flags & MMC_DATA_WRITE) dma_sync_single_for_device((unsigned long)data->src, num_bytes, DMA_TO_DEVICE); else dma_sync_single_for_device((unsigned long)data->dest, num_bytes, DMA_FROM_DEVICE); ret = dwmci_prepare_data(host, data); if (ret) return ret; } dwmci_writel(host, DWMCI_CMDARG, cmd->cmdarg); if (data) flags = dwmci_set_transfer_mode(host, data); if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY)) return -EINVAL; if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) flags |= DWMCI_CMD_ABORT_STOP; else flags |= DWMCI_CMD_PRV_DAT_WAIT; if (cmd->resp_type & MMC_RSP_PRESENT) { flags |= DWMCI_CMD_RESP_EXP; if (cmd->resp_type & MMC_RSP_136) flags |= DWMCI_CMD_RESP_LENGTH; } if (cmd->resp_type & MMC_RSP_CRC) flags |= DWMCI_CMD_CHECK_CRC; flags |= (cmd->cmdidx | DWMCI_CMD_START | DWMCI_CMD_USE_HOLD_REG); dev_dbg(host->dev, "Sending CMD%d\n", cmd->cmdidx); dwmci_writel(host, DWMCI_CMD, flags); start = get_time_ns(); while (1) { mask = dwmci_readl(host, DWMCI_RINTSTS); if (mask & DWMCI_INTMSK_CDONE) { if (!data) dwmci_writel(host, DWMCI_RINTSTS, mask); break; } if (is_timeout(start, 100 * MSECOND)) { dev_dbg(host->dev, "Send command timeout..\n"); return -ETIMEDOUT; } } if (mask & DWMCI_INTMSK_RTO) { dev_dbg(host->dev, "Response Timeout..\n"); return -ETIMEDOUT; } else if (mask & DWMCI_INTMSK_RE) { dev_dbg(host->dev, "Response Error..\n"); return -EIO; } if (cmd->resp_type & MMC_RSP_PRESENT) { if (cmd->resp_type & MMC_RSP_136) { cmd->response[0] = dwmci_readl(host, DWMCI_RESP3); cmd->response[1] = dwmci_readl(host, DWMCI_RESP2); cmd->response[2] = dwmci_readl(host, DWMCI_RESP1); cmd->response[3] = dwmci_readl(host, DWMCI_RESP0); } else { cmd->response[0] = dwmci_readl(host, DWMCI_RESP0); } } if (data) { start = get_time_ns(); do { mask = dwmci_readl(host, DWMCI_RINTSTS); if (mask & (DWMCI_DATA_ERR)) { dev_dbg(host->dev, "DATA ERROR!\n"); return -EIO; } if (!dwmci_use_pio(host) && (mask & DWMCI_DATA_TOUT)) { dev_dbg(host->dev, "DATA TIMEOUT!\n"); return -EIO; } if (is_timeout(start, SECOND * 10)) { dev_dbg(host->dev, "Data timeout\n"); return -ETIMEDOUT; } if (dwmci_use_pio(host) && (mask & DWMCI_INTMSK_RXDR)) { dwmci_read_data_pio(host, data); mask = dwmci_readl(host, DWMCI_RINTSTS); } if (dwmci_use_pio(host) && (mask & DWMCI_INTMSK_TXDR)) { dwmci_write_data_pio(host, data); mask = dwmci_readl(host, DWMCI_RINTSTS); } } while (!(mask & DWMCI_INTMSK_DTO)); dwmci_writel(host, DWMCI_RINTSTS, mask); if (!dwmci_use_pio(host)) { ctrl = dwmci_readl(host, DWMCI_CTRL); ctrl &= ~(DWMCI_DMA_EN); dwmci_writel(host, DWMCI_CTRL, ctrl); if (data->flags & MMC_DATA_WRITE) dma_sync_single_for_cpu((unsigned long)data->src, num_bytes, DMA_TO_DEVICE); else dma_sync_single_for_cpu((unsigned long)data->dest, num_bytes, DMA_FROM_DEVICE); } } udelay(100); return 0; }