diff options
Diffstat (limited to 'drivers/mci/dove-sdhci.c')
-rw-r--r-- | drivers/mci/dove-sdhci.c | 253 |
1 files changed, 81 insertions, 172 deletions
diff --git a/drivers/mci/dove-sdhci.c b/drivers/mci/dove-sdhci.c index caee4107eb..d37046ad31 100644 --- a/drivers/mci/dove-sdhci.c +++ b/drivers/mci/dove-sdhci.c @@ -1,22 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* * Marvell Dove SDHCI MCI driver * * Pengutronix, Michael Grzeschik <mgr@pengutronix.de> * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include <clock.h> @@ -32,42 +20,12 @@ struct dove_sdhci { struct mci_host mci; - void __iomem *base; + struct sdhci sdhci; }; #define priv_from_mci_host(h) \ container_of(h, struct dove_sdhci, mci); -static inline void dove_sdhci_writel(struct dove_sdhci *p, int reg, u32 val) -{ - writel(val, p->base + reg); -} - -static inline void dove_sdhci_writew(struct dove_sdhci *p, int reg, u16 val) -{ - writew(val, p->base + reg); -} - -static inline void dove_sdhci_writeb(struct dove_sdhci *p, int reg, u8 val) -{ - writeb(val, p->base + reg); -} - -static inline u32 dove_sdhci_readl(struct dove_sdhci *p, int reg) -{ - return readl(p->base + reg); -} - -static inline u16 dove_sdhci_readw(struct dove_sdhci *p, int reg) -{ - return readw(p->base + reg); -} - -static inline u8 dove_sdhci_readb(struct dove_sdhci *p, int reg) -{ - return readb(p->base + reg); -} - static int dove_sdhci_wait_for_done(struct dove_sdhci *host, u16 mask) { u16 status; @@ -75,7 +33,7 @@ static int dove_sdhci_wait_for_done(struct dove_sdhci *host, u16 mask) start = get_time_ns(); while (1) { - status = dove_sdhci_readw(host, SDHCI_INT_NORMAL_STATUS); + status = sdhci_read16(&host->sdhci, SDHCI_INT_NORMAL_STATUS); if (status & SDHCI_INT_ERROR) return -EPERM; /* this special quirk is necessary, as the dma @@ -83,8 +41,8 @@ static int dove_sdhci_wait_for_done(struct dove_sdhci *host, u16 mask) * restart after acknowledging it this way. */ if (status & SDHCI_INT_DMA) { - u32 addr = dove_sdhci_readl(host, SDHCI_DMA_ADDRESS); - dove_sdhci_writel(host, SDHCI_DMA_ADDRESS, addr); + u32 addr = sdhci_read32(&host->sdhci, SDHCI_DMA_ADDRESS); + sdhci_write32(&host->sdhci, SDHCI_DMA_ADDRESS, addr); } if (status & mask) break; @@ -99,130 +57,87 @@ static int dove_sdhci_wait_for_done(struct dove_sdhci *host, u16 mask) static int dove_sdhci_mci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data) { - u16 val; - u64 start; + u32 command, xfer; int ret; - unsigned int num_bytes = data->blocks * data->blocksize; + unsigned int num_bytes = 0; struct dove_sdhci *host = priv_from_mci_host(mci); - dove_sdhci_writel(host, SDHCI_INT_STATUS, ~0); - - /* Do not wait for CMD_INHIBIT_DAT on stop commands */ - if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION) - val = SDHCI_CMD_INHIBIT_CMD; - else - val = SDHCI_CMD_INHIBIT_CMD | SDHCI_CMD_INHIBIT_DATA; + ret = sdhci_wait_idle_data(&host->sdhci, cmd); + if (ret) + return ret; - /* Wait for bus idle */ - start = get_time_ns(); - while (1) { - if (!(dove_sdhci_readw(host, SDHCI_PRESENT_STATE) & val)) - break; - if (is_timeout(start, 10 * MSECOND)) { - dev_err(host->mci.hw_dev, "SDHCI timeout while waiting for idle\n"); - return -ETIMEDOUT; - } - } + sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0); /* setup transfer data */ if (data) { + num_bytes = data->blocks * data->blocksize; if (data->flags & MMC_DATA_READ) - dove_sdhci_writel(host, SDHCI_DMA_ADDRESS, (u32)data->dest); + sdhci_write32(&host->sdhci, SDHCI_DMA_ADDRESS, + lower_32_bits(virt_to_phys(data->dest))); else - dove_sdhci_writel(host, SDHCI_DMA_ADDRESS, (u32)data->src); - dove_sdhci_writew(host, SDHCI_BLOCK_SIZE, SDHCI_DMA_BOUNDARY_512K | + sdhci_write32(&host->sdhci, SDHCI_DMA_ADDRESS, + lower_32_bits(virt_to_phys(data->src))); + sdhci_write16(&host->sdhci, SDHCI_BLOCK_SIZE, SDHCI_DMA_BOUNDARY_512K | SDHCI_TRANSFER_BLOCK_SIZE(data->blocksize)); - dove_sdhci_writew(host, SDHCI_BLOCK_COUNT, data->blocks); - dove_sdhci_writeb(host, SDHCI_TIMEOUT_CONTROL, 0xe); + sdhci_write16(&host->sdhci, SDHCI_BLOCK_COUNT, data->blocks); + sdhci_write8(&host->sdhci, SDHCI_TIMEOUT_CONTROL, 0xe); if (data->flags & MMC_DATA_WRITE) - dma_sync_single_for_device((unsigned long)data->src, + dma_sync_single_for_device(host->mci.hw_dev, + lower_32_bits(virt_to_phys(data->src)), num_bytes, DMA_TO_DEVICE); else - dma_sync_single_for_device((unsigned long)data->dest, + dma_sync_single_for_device(host->mci.hw_dev, + lower_32_bits(virt_to_phys(data->dest)), num_bytes, DMA_FROM_DEVICE); } /* setup transfer mode */ - val = 0; - if (data) { - val |= SDHCI_DMA_EN | SDHCI_BLOCK_COUNT_EN; - if (data->blocks > 1) - val |= SDHCI_MULTIPLE_BLOCKS; - if (data->flags & MMC_DATA_READ) - val |= SDHCI_DATA_TO_HOST; - } - dove_sdhci_writew(host, SDHCI_TRANSFER_MODE, val); - - dove_sdhci_writel(host, SDHCI_ARGUMENT, cmd->cmdarg); + sdhci_set_cmd_xfer_mode(&host->sdhci, cmd, data, true, &command, &xfer); - if (!(cmd->resp_type & MMC_RSP_PRESENT)) - val = SDHCI_RESP_NONE; - else if (cmd->resp_type & MMC_RSP_136) - val = SDHCI_RESP_TYPE_136; - else if (cmd->resp_type & MMC_RSP_BUSY) - val = SDHCI_RESP_TYPE_48_BUSY; - else - val = SDHCI_RESP_TYPE_48; - - if (cmd->resp_type & MMC_RSP_CRC) - val |= SDHCI_CMD_CRC_CHECK_EN; - if (cmd->resp_type & MMC_RSP_OPCODE) - val |= SDHCI_CMD_INDEX_CHECK_EN; - if (data) - val |= SDHCI_DATA_PRESENT; - val |= SDHCI_CMD_INDEX(cmd->cmdidx); - - dove_sdhci_writew(host, SDHCI_COMMAND, val); + sdhci_write16(&host->sdhci, SDHCI_TRANSFER_MODE, xfer); + sdhci_write32(&host->sdhci, SDHCI_ARGUMENT, cmd->cmdarg); + sdhci_write16(&host->sdhci, SDHCI_COMMAND, command); ret = dove_sdhci_wait_for_done(host, SDHCI_INT_CMD_COMPLETE); if (ret) { dev_err(host->mci.hw_dev, "error on command %d\n", cmd->cmdidx); dev_err(host->mci.hw_dev, "state = %04x %04x, interrupt = %04x %04x\n", - dove_sdhci_readw(host, SDHCI_PRESENT_STATE), - dove_sdhci_readw(host, SDHCI_PRESENT_STATE1), - dove_sdhci_readw(host, SDHCI_INT_NORMAL_STATUS), - dove_sdhci_readw(host, SDHCI_INT_ERROR_STATUS)); + sdhci_read16(&host->sdhci, SDHCI_PRESENT_STATE), + sdhci_read16(&host->sdhci, SDHCI_PRESENT_STATE1), + sdhci_read16(&host->sdhci, SDHCI_INT_NORMAL_STATUS), + sdhci_read16(&host->sdhci, SDHCI_INT_ERROR_STATUS)); goto cmd_error; } - /* CRC is stripped so we need to do some shifting. */ - if (cmd->resp_type & MMC_RSP_136) { - int i; - for (i = 0; i < 4; i++) { - cmd->response[i] = dove_sdhci_readl(host, - SDHCI_RESPONSE_0 + 4*(3-i)) << 8; - if (i != 3) - cmd->response[i] |= dove_sdhci_readb(host, - SDHCI_RESPONSE_0 + 4*(3-i) - 1); - } - } else - cmd->response[0] = dove_sdhci_readl(host, SDHCI_RESPONSE_0); - - 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); + sdhci_read_response(&host->sdhci, cmd); if (data) { + if (data->flags & MMC_DATA_WRITE) + dma_sync_single_for_cpu(host->mci.hw_dev, + lower_32_bits(virt_to_phys(data->src)), + num_bytes, DMA_TO_DEVICE); + else + dma_sync_single_for_cpu(host->mci.hw_dev, + lower_32_bits(virt_to_phys(data->dest)), + num_bytes, DMA_FROM_DEVICE); + ret = dove_sdhci_wait_for_done(host, SDHCI_INT_XFER_COMPLETE); if (ret) { dev_err(host->mci.hw_dev, "error while transfering data for command %d\n", cmd->cmdidx); dev_err(host->mci.hw_dev, "state = %04x %04x, interrupt = %04x %04x\n", - dove_sdhci_readw(host, SDHCI_PRESENT_STATE), - dove_sdhci_readw(host, SDHCI_PRESENT_STATE1), - dove_sdhci_readw(host, SDHCI_INT_NORMAL_STATUS), - dove_sdhci_readw(host, SDHCI_INT_ERROR_STATUS)); + sdhci_read16(&host->sdhci, SDHCI_PRESENT_STATE), + sdhci_read16(&host->sdhci, SDHCI_PRESENT_STATE1), + sdhci_read16(&host->sdhci, SDHCI_INT_NORMAL_STATUS), + sdhci_read16(&host->sdhci, SDHCI_INT_ERROR_STATUS)); goto cmd_error; } } cmd_error: - dove_sdhci_writel(host, SDHCI_INT_STATUS, ~0); + sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0); return ret; } @@ -230,7 +145,7 @@ static u16 dove_sdhci_get_clock_divider(struct dove_sdhci *host, u32 reqclk) { u16 div; - for (div = 1; div < SDHCI_SPEC_200_MAX_CLK_DIVIDER; div *= 2) + for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) if ((host->mci.f_max / div) <= reqclk) break; div /= 2; @@ -252,38 +167,40 @@ static void dove_sdhci_mci_set_ios(struct mci_host *mci, struct mci_ios *ios) /* enable bus power */ val = SDHCI_BUS_VOLTAGE_330; - dove_sdhci_writeb(host, SDHCI_POWER_CONTROL, val | SDHCI_BUS_POWER_EN); + sdhci_write8(&host->sdhci, SDHCI_POWER_CONTROL, val | SDHCI_BUS_POWER_EN); udelay(400); /* set bus width */ - val = dove_sdhci_readb(host, SDHCI_HOST_CONTROL) & - ~(SDHCI_DATA_WIDTH_4BIT | SDHCI_DATA_WIDTH_8BIT); + val = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL) & + ~(SDHCI_CTRL_4BITBUS | SDHCI_CTRL_8BITBUS); switch (ios->bus_width) { case MMC_BUS_WIDTH_8: - val |= SDHCI_DATA_WIDTH_8BIT; + val |= SDHCI_CTRL_8BITBUS; break; case MMC_BUS_WIDTH_4: - val |= SDHCI_DATA_WIDTH_4BIT; + val |= SDHCI_CTRL_4BITBUS; + break; + case MMC_BUS_WIDTH_1: break; } if (ios->clock > 26000000) - val |= SDHCI_HIGHSPEED_EN; + val |= SDHCI_CTRL_HISPD; else - val &= ~SDHCI_HIGHSPEED_EN; + val &= ~SDHCI_CTRL_HISPD; - dove_sdhci_writeb(host, SDHCI_HOST_CONTROL, val); + sdhci_write8(&host->sdhci, SDHCI_HOST_CONTROL, val); /* set bus clock */ - dove_sdhci_writew(host, SDHCI_CLOCK_CONTROL, 0); + sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, 0); val = dove_sdhci_get_clock_divider(host, ios->clock); - val = SDHCI_INTCLOCK_EN | SDHCI_FREQ_SEL(val); - dove_sdhci_writew(host, SDHCI_CLOCK_CONTROL, val); + val = SDHCI_CLOCK_INT_EN | SDHCI_FREQ_SEL(val); + sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, val); /* wait for internal clock stable */ start = get_time_ns(); - while (!(dove_sdhci_readw(host, SDHCI_CLOCK_CONTROL) & - SDHCI_INTCLOCK_STABLE)) { + while (!(sdhci_read16(&host->sdhci, SDHCI_CLOCK_CONTROL) & + SDHCI_CLOCK_INT_STABLE)) { if (is_timeout(start, 20 * MSECOND)) { dev_err(host->mci.hw_dev, "SDHCI clock stable timeout\n"); return; @@ -291,21 +208,21 @@ static void dove_sdhci_mci_set_ios(struct mci_host *mci, struct mci_ios *ios) } /* enable bus clock */ - dove_sdhci_writew(host, SDHCI_CLOCK_CONTROL, val | SDHCI_SDCLOCK_EN); + sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, val | SDHCI_CLOCK_CARD_EN); } -static int dove_sdhci_mci_init(struct mci_host *mci, struct device_d *dev) +static int dove_sdhci_mci_init(struct mci_host *mci, struct device *dev) { u64 start; struct dove_sdhci *host = priv_from_mci_host(mci); /* reset sdhci controller */ - dove_sdhci_writeb(host, SDHCI_SOFTWARE_RESET, SDHCI_RESET_ALL); + sdhci_write8(&host->sdhci, SDHCI_SOFTWARE_RESET, SDHCI_RESET_ALL); /* wait for reset completion */ start = get_time_ns(); while (1) { - if ((dove_sdhci_readb(host, SDHCI_SOFTWARE_RESET) & + if ((sdhci_read8(&host->sdhci, SDHCI_SOFTWARE_RESET) & SDHCI_RESET_ALL) == 0) break; if (is_timeout(start, 100 * MSECOND)) { @@ -314,28 +231,27 @@ static int dove_sdhci_mci_init(struct mci_host *mci, struct device_d *dev) } } - dove_sdhci_writel(host, SDHCI_INT_STATUS, ~0); - dove_sdhci_writel(host, SDHCI_INT_ENABLE, ~0); - dove_sdhci_writel(host, SDHCI_SIGNAL_ENABLE, ~0); + sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0); + sdhci_write32(&host->sdhci, SDHCI_INT_ENABLE, ~0); + sdhci_write32(&host->sdhci, SDHCI_SIGNAL_ENABLE, ~0); return 0; } static void dove_sdhci_set_mci_caps(struct dove_sdhci *host) { - u16 caps[2]; + u32 caps; - caps[0] = dove_sdhci_readw(host, SDHCI_CAPABILITIES); - caps[1] = dove_sdhci_readw(host, SDHCI_CAPABILITIES_1); + caps = sdhci_read32(&host->sdhci, SDHCI_CAPABILITIES); - if (caps[1] & SDHCI_HOSTCAP_VOLTAGE_180) + if (caps & SDHCI_CAN_VDD_180) host->mci.voltages |= MMC_VDD_165_195; - if (caps[1] & SDHCI_HOSTCAP_VOLTAGE_300) + if (caps & SDHCI_CAN_VDD_300) host->mci.voltages |= MMC_VDD_29_30 | MMC_VDD_30_31; - if (caps[1] & SDHCI_HOSTCAP_VOLTAGE_330) + if (caps & SDHCI_CAN_VDD_330) host->mci.voltages |= MMC_VDD_32_33 | MMC_VDD_33_34; - if (caps[1] & SDHCI_HOSTCAP_HIGHSPEED) + if (caps & SDHCI_CAN_DO_HISPD) host->mci.host_caps |= (MMC_CAP_MMC_HIGHSPEED_52MHZ | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED); @@ -344,23 +260,17 @@ static void dove_sdhci_set_mci_caps(struct dove_sdhci *host) mci_of_parse(&host->mci); /* limit bus widths to controller capabilities */ - if ((caps[1] & SDHCI_HOSTCAP_8BIT) == 0) + if ((caps & SDHCI_CAN_DO_8BIT) == 0) host->mci.host_caps &= ~MMC_CAP_8_BIT_DATA; } -static int dove_sdhci_detect(struct device_d *dev) -{ - struct dove_sdhci *host = dev->priv; - return mci_detect_card(&host->mci); -} - -static int dove_sdhci_probe(struct device_d *dev) +static int dove_sdhci_probe(struct device *dev) { struct dove_sdhci *host; int ret; host = xzalloc(sizeof(*host)); - host->base = dev_request_mem_region(dev, 0); + host->sdhci.base = dev_request_mem_region(dev, 0); host->mci.max_req_size = 0x8000; host->mci.hw_dev = dev; host->mci.send_cmd = dove_sdhci_mci_send_cmd; @@ -368,8 +278,6 @@ static int dove_sdhci_probe(struct device_d *dev) host->mci.init = dove_sdhci_mci_init; host->mci.f_max = 50000000; host->mci.f_min = host->mci.f_max / 256; - dev->priv = host; - dev->detect = dove_sdhci_detect; dove_sdhci_set_mci_caps(host); @@ -383,8 +291,9 @@ static struct of_device_id dove_sdhci_dt_ids[] = { { .compatible = "marvell,dove-sdhci", }, { } }; +MODULE_DEVICE_TABLE(of, dove_sdhci_dt_ids); -static struct driver_d dove_sdhci_driver = { +static struct driver dove_sdhci_driver = { .name = "dove-sdhci", .probe = dove_sdhci_probe, .of_compatible = DRV_OF_COMPAT(dove_sdhci_dt_ids), |