Loading drivers/mmc/host/sh_mobile_sdhi.c +65 −52 Original line number Diff line number Diff line Loading @@ -35,10 +35,13 @@ #define EXT_ACC 0xe4 #define host_to_priv(host) container_of((host)->pdata, struct sh_mobile_sdhi, mmc_data) struct sh_mobile_sdhi_of_data { unsigned long tmio_flags; unsigned long capabilities; unsigned long capabilities2; enum dma_slave_buswidth dma_buswidth; dma_addr_t dma_rx_offset; }; Loading @@ -58,6 +61,7 @@ static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = { .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | TMIO_MMC_CLK_ACTUAL, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, .dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES, .dma_rx_offset = 0x2000, }; Loading @@ -84,16 +88,43 @@ struct sh_mobile_sdhi { struct tmio_mmc_dma dma_priv; }; static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width) { u32 val; /* * see also * sh_mobile_sdhi_of_data :: dma_buswidth */ switch (sd_ctrl_read16(host, CTL_VERSION)) { case 0x490C: val = (width == 32) ? 0x0001 : 0x0000; break; case 0xCB0D: val = (width == 32) ? 0x0000 : 0x0001; break; default: /* nothing to do */ return; } sd_ctrl_write16(host, EXT_ACC, val); } static int sh_mobile_sdhi_clk_enable(struct platform_device *pdev, unsigned int *f) { struct mmc_host *mmc = platform_get_drvdata(pdev); struct tmio_mmc_host *host = mmc_priv(mmc); struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data); struct sh_mobile_sdhi *priv = host_to_priv(host); int ret = clk_prepare_enable(priv->clk); if (ret < 0) return ret; *f = clk_get_rate(priv->clk); /* enable 16bit data access on SDBUF as default */ sh_mobile_sdhi_sdbuf_width(host, 16); return 0; } Loading @@ -101,7 +132,7 @@ static void sh_mobile_sdhi_clk_disable(struct platform_device *pdev) { struct mmc_host *mmc = platform_get_drvdata(pdev); struct tmio_mmc_host *host = mmc_priv(mmc); struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data); struct sh_mobile_sdhi *priv = host_to_priv(host); clk_disable_unprepare(priv->clk); } Loading @@ -113,7 +144,7 @@ static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host) udelay(1); if (!timeout) { dev_warn(host->pdata->dev, "timeout waiting for SD bus idle\n"); dev_warn(&host->pdev->dev, "timeout waiting for SD bus idle\n"); return -EBUSY; } Loading Loading @@ -156,14 +187,13 @@ static int sh_mobile_sdhi_multi_io_quirk(struct mmc_card *card, return blk_size; } static void sh_mobile_sdhi_cd_wakeup(const struct platform_device *pdev) static void sh_mobile_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable) { mmc_detect_change(platform_get_drvdata(pdev), msecs_to_jiffies(100)); } sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0); static const struct sh_mobile_sdhi_ops sdhi_ops = { .cd_wakeup = sh_mobile_sdhi_cd_wakeup, }; /* enable 32bit access if DMA mode if possibile */ sh_mobile_sdhi_sdbuf_width(host, enable ? 32 : 16); } static int sh_mobile_sdhi_probe(struct platform_device *pdev) { Loading @@ -177,7 +207,6 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) int irq, ret, i = 0; bool multiplexed_isr = true; struct tmio_mmc_dma *dma_priv; u16 ver; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) Loading @@ -192,26 +221,31 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) mmc_data = &priv->mmc_data; dma_priv = &priv->dma_priv; if (p) { if (p->init) { ret = p->init(pdev, &sdhi_ops); if (ret) return ret; } } priv->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(priv->clk)) { ret = PTR_ERR(priv->clk); dev_err(&pdev->dev, "cannot get clock: %d\n", ret); goto eclkget; goto eprobe; } host = tmio_mmc_host_alloc(pdev); if (!host) { ret = -ENOMEM; goto eprobe; } mmc_data->clk_enable = sh_mobile_sdhi_clk_enable; mmc_data->clk_disable = sh_mobile_sdhi_clk_disable; host->dma = dma_priv; host->write16_hook = sh_mobile_sdhi_write16_hook; host->clk_enable = sh_mobile_sdhi_clk_enable; host->clk_disable = sh_mobile_sdhi_clk_disable; host->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk; /* SD control register space size is 0x100, 0x200 for bus_shift=1 */ if (resource_size(res) > 0x100) host->bus_shift = 1; else host->bus_shift = 0; mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED; mmc_data->write16_hook = sh_mobile_sdhi_write16_hook; mmc_data->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk; if (p) { mmc_data->flags = p->tmio_flags; mmc_data->ocr_mask = p->tmio_ocr_mask; Loading @@ -231,11 +265,10 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) dma_priv->slave_id_rx = p->dma_slave_rx; } } dma_priv->alignment_shift = 1; /* 2-byte alignment */ dma_priv->filter = shdma_chan_filter; dma_priv->enable = sh_mobile_sdhi_enable_dma; mmc_data->dma = dma_priv; mmc_data->alignment_shift = 1; /* 2-byte alignment */ /* * All SDHI blocks support 2-byte and larger block sizes in 4-bit Loading @@ -258,33 +291,18 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) */ mmc_data->flags |= TMIO_MMC_SDIO_STATUS_QUIRK; /* * All SDHI have DMA control register */ mmc_data->flags |= TMIO_MMC_HAVE_CTL_DMA_REG; if (of_id && of_id->data) { const struct sh_mobile_sdhi_of_data *of_data = of_id->data; mmc_data->flags |= of_data->tmio_flags; mmc_data->capabilities |= of_data->capabilities; mmc_data->capabilities2 |= of_data->capabilities2; dma_priv->dma_rx_offset = of_data->dma_rx_offset; mmc_data->dma_rx_offset = of_data->dma_rx_offset; dma_priv->dma_buswidth = of_data->dma_buswidth; } /* SD control register space size is 0x100, 0x200 for bus_shift=1 */ mmc_data->bus_shift = resource_size(res) >> 9; ret = tmio_mmc_host_probe(&host, pdev, mmc_data); ret = tmio_mmc_host_probe(host, mmc_data); if (ret < 0) goto eprobe; /* * FIXME: * this Workaround can be more clever method */ ver = sd_ctrl_read16(host, CTL_VERSION); if (ver == 0xCB0D) sd_ctrl_write16(host, EXT_ACC, 1); goto efree; /* * Allow one or more specific (named) ISRs or Loading Loading @@ -351,10 +369,9 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) eirq: tmio_mmc_host_remove(host); efree: tmio_mmc_host_free(host); eprobe: eclkget: if (p && p->cleanup) p->cleanup(pdev); return ret; } Loading @@ -362,13 +379,9 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev) { struct mmc_host *mmc = platform_get_drvdata(pdev); struct tmio_mmc_host *host = mmc_priv(mmc); struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; tmio_mmc_host_remove(host); if (p && p->cleanup) p->cleanup(pdev); return 0; } Loading drivers/mmc/host/tmio_mmc.c +11 −4 Original line number Diff line number Diff line Loading @@ -88,14 +88,19 @@ static int tmio_mmc_probe(struct platform_device *pdev) if (!res) return -EINVAL; /* SD control register space size is 0x200, 0x400 for bus_shift=1 */ pdata->bus_shift = resource_size(res) >> 10; pdata->flags |= TMIO_MMC_HAVE_HIGH_REG; ret = tmio_mmc_host_probe(&host, pdev, pdata); if (ret) host = tmio_mmc_host_alloc(pdev); if (!host) goto cell_disable; /* SD control register space size is 0x200, 0x400 for bus_shift=1 */ host->bus_shift = resource_size(res) >> 10; ret = tmio_mmc_host_probe(host, pdata); if (ret) goto host_free; ret = request_irq(irq, tmio_mmc_irq, IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), host); if (ret) Loading @@ -108,6 +113,8 @@ static int tmio_mmc_probe(struct platform_device *pdev) host_remove: tmio_mmc_host_remove(host); host_free: tmio_mmc_host_free(host); cell_disable: if (cell->disable) cell->disable(pdev); Loading drivers/mmc/host/tmio_mmc.h +32 −11 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #ifndef TMIO_MMC_H #define TMIO_MMC_H #include <linux/dmaengine.h> #include <linux/highmem.h> #include <linux/mmc/tmio.h> #include <linux/mutex.h> Loading @@ -39,6 +40,17 @@ #define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD) struct tmio_mmc_data; struct tmio_mmc_host; struct tmio_mmc_dma { void *chan_priv_tx; void *chan_priv_rx; int slave_id_tx; int slave_id_rx; enum dma_slave_buswidth dma_buswidth; bool (*filter)(struct dma_chan *chan, void *arg); void (*enable)(struct tmio_mmc_host *host, bool enable); }; struct tmio_mmc_host { void __iomem *ctl; Loading @@ -56,9 +68,11 @@ struct tmio_mmc_host { struct scatterlist *sg_orig; unsigned int sg_len; unsigned int sg_off; unsigned long bus_shift; struct platform_device *pdev; struct tmio_mmc_data *pdata; struct tmio_mmc_dma *dma; /* DMA support */ bool force_pio; Loading @@ -83,10 +97,17 @@ struct tmio_mmc_host { struct mutex ios_lock; /* protect set_ios() context */ bool native_hotplug; bool sdio_irq_enabled; int (*write16_hook)(struct tmio_mmc_host *host, int addr); int (*clk_enable)(struct platform_device *pdev, unsigned int *f); void (*clk_disable)(struct platform_device *pdev); int (*multi_io_quirk)(struct mmc_card *card, unsigned int direction, int blk_size); }; int tmio_mmc_host_probe(struct tmio_mmc_host **host, struct platform_device *pdev, struct tmio_mmc_host *tmio_mmc_host_alloc(struct platform_device *pdev); void tmio_mmc_host_free(struct tmio_mmc_host *host); int tmio_mmc_host_probe(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata); void tmio_mmc_host_remove(struct tmio_mmc_host *host); void tmio_mmc_do_data_irq(struct tmio_mmc_host *host); Loading Loading @@ -151,19 +172,19 @@ int tmio_mmc_host_runtime_resume(struct device *dev); static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr) { return readw(host->ctl + (addr << host->pdata->bus_shift)); return readw(host->ctl + (addr << host->bus_shift)); } static inline void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr, u16 *buf, int count) { readsw(host->ctl + (addr << host->pdata->bus_shift), buf, count); readsw(host->ctl + (addr << host->bus_shift), buf, count); } static inline u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr) { return readw(host->ctl + (addr << host->pdata->bus_shift)) | readw(host->ctl + ((addr + 2) << host->pdata->bus_shift)) << 16; return readw(host->ctl + (addr << host->bus_shift)) | readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16; } static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val) Loading @@ -171,21 +192,21 @@ static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val /* If there is a hook and it returns non-zero then there * is an error and the write should be skipped */ if (host->pdata->write16_hook && host->pdata->write16_hook(host, addr)) if (host->write16_hook && host->write16_hook(host, addr)) return; writew(val, host->ctl + (addr << host->pdata->bus_shift)); writew(val, host->ctl + (addr << host->bus_shift)); } static inline void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr, u16 *buf, int count) { writesw(host->ctl + (addr << host->pdata->bus_shift), buf, count); writesw(host->ctl + (addr << host->bus_shift), buf, count); } static inline void sd_ctrl_write32(struct tmio_mmc_host *host, int addr, u32 val) { writew(val, host->ctl + (addr << host->pdata->bus_shift)); writew(val >> 16, host->ctl + ((addr + 2) << host->pdata->bus_shift)); writew(val, host->ctl + (addr << host->bus_shift)); writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift)); } Loading drivers/mmc/host/tmio_mmc_dma.c +20 −18 Original line number Diff line number Diff line Loading @@ -28,8 +28,8 @@ void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable) if (!host->chan_tx || !host->chan_rx) return; if (host->pdata->flags & TMIO_MMC_HAVE_CTL_DMA_REG) sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0); if (host->dma->enable) host->dma->enable(host, enable); } void tmio_mmc_abort_dma(struct tmio_mmc_host *host) Loading @@ -49,11 +49,10 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) struct scatterlist *sg = host->sg_ptr, *sg_tmp; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *chan = host->chan_rx; struct tmio_mmc_data *pdata = host->pdata; dma_cookie_t cookie; int ret, i; bool aligned = true, multiple = true; unsigned int align = (1 << pdata->dma->alignment_shift) - 1; unsigned int align = (1 << host->pdata->alignment_shift) - 1; for_each_sg(sg, sg_tmp, host->sg_len, i) { if (sg_tmp->offset & align) Loading Loading @@ -126,11 +125,10 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) struct scatterlist *sg = host->sg_ptr, *sg_tmp; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *chan = host->chan_tx; struct tmio_mmc_data *pdata = host->pdata; dma_cookie_t cookie; int ret, i; bool aligned = true, multiple = true; unsigned int align = (1 << pdata->dma->alignment_shift) - 1; unsigned int align = (1 << host->pdata->alignment_shift) - 1; for_each_sg(sg, sg_tmp, host->sg_len, i) { if (sg_tmp->offset & align) Loading Loading @@ -262,8 +260,8 @@ static void tmio_mmc_tasklet_fn(unsigned long arg) void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata) { /* We can only either use DMA for both Tx and Rx or not use it at all */ if (!pdata->dma || (!host->pdev->dev.of_node && (!pdata->dma->chan_priv_tx || !pdata->dma->chan_priv_rx))) if (!host->dma || (!host->pdev->dev.of_node && (!host->dma->chan_priv_tx || !host->dma->chan_priv_rx))) return; if (!host->chan_tx && !host->chan_rx) { Loading @@ -280,7 +278,7 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat dma_cap_set(DMA_SLAVE, mask); host->chan_tx = dma_request_slave_channel_compat(mask, pdata->dma->filter, pdata->dma->chan_priv_tx, host->dma->filter, host->dma->chan_priv_tx, &host->pdev->dev, "tx"); dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__, host->chan_tx); Loading @@ -288,10 +286,12 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat if (!host->chan_tx) return; if (pdata->dma->chan_priv_tx) cfg.slave_id = pdata->dma->slave_id_tx; if (host->dma->chan_priv_tx) cfg.slave_id = host->dma->slave_id_tx; cfg.direction = DMA_MEM_TO_DEV; cfg.dst_addr = res->start + (CTL_SD_DATA_PORT << host->pdata->bus_shift); cfg.dst_addr = res->start + (CTL_SD_DATA_PORT << host->bus_shift); cfg.dst_addr_width = host->dma->dma_buswidth; if (!cfg.dst_addr_width) cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; cfg.src_addr = 0; ret = dmaengine_slave_config(host->chan_tx, &cfg); Loading @@ -299,7 +299,7 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat goto ecfgtx; host->chan_rx = dma_request_slave_channel_compat(mask, pdata->dma->filter, pdata->dma->chan_priv_rx, host->dma->filter, host->dma->chan_priv_rx, &host->pdev->dev, "rx"); dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__, host->chan_rx); Loading @@ -307,10 +307,12 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat if (!host->chan_rx) goto ereqrx; if (pdata->dma->chan_priv_rx) cfg.slave_id = pdata->dma->slave_id_rx; if (host->dma->chan_priv_rx) cfg.slave_id = host->dma->slave_id_rx; cfg.direction = DMA_DEV_TO_MEM; cfg.src_addr = cfg.dst_addr + pdata->dma->dma_rx_offset; cfg.src_addr = cfg.dst_addr + host->pdata->dma_rx_offset; cfg.src_addr_width = host->dma->dma_buswidth; if (!cfg.src_addr_width) cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; cfg.dst_addr = 0; ret = dmaengine_slave_config(host->chan_rx, &cfg); Loading drivers/mmc/host/tmio_mmc_pio.c +36 −25 Original line number Diff line number Diff line Loading @@ -835,13 +835,12 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) static int tmio_mmc_clk_update(struct tmio_mmc_host *host) { struct mmc_host *mmc = host->mmc; struct tmio_mmc_data *pdata = host->pdata; int ret; if (!pdata->clk_enable) if (!host->clk_enable) return -ENOTSUPP; ret = pdata->clk_enable(host->pdev, &mmc->f_max); ret = host->clk_enable(host->pdev, &mmc->f_max); if (!ret) mmc->f_min = mmc->f_max / 512; Loading Loading @@ -1005,10 +1004,9 @@ static int tmio_multi_io_quirk(struct mmc_card *card, unsigned int direction, int blk_size) { struct tmio_mmc_host *host = mmc_priv(card->host); struct tmio_mmc_data *pdata = host->pdata; if (pdata->multi_io_quirk) return pdata->multi_io_quirk(card, direction, blk_size); if (host->multi_io_quirk) return host->multi_io_quirk(card, direction, blk_size); return blk_size; } Loading Loading @@ -1054,12 +1052,37 @@ static void tmio_mmc_of_parse(struct platform_device *pdev, pdata->flags |= TMIO_MMC_WRPROTECT_DISABLE; } int tmio_mmc_host_probe(struct tmio_mmc_host **host, struct platform_device *pdev, struct tmio_mmc_data *pdata) struct tmio_mmc_host* tmio_mmc_host_alloc(struct platform_device *pdev) { struct tmio_mmc_host *_host; struct tmio_mmc_host *host; struct mmc_host *mmc; mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &pdev->dev); if (!mmc) return NULL; host = mmc_priv(mmc); host->mmc = mmc; host->pdev = pdev; return host; } EXPORT_SYMBOL(tmio_mmc_host_alloc); void tmio_mmc_host_free(struct tmio_mmc_host *host) { mmc_free_host(host->mmc); host->mmc = NULL; } EXPORT_SYMBOL(tmio_mmc_host_free); int tmio_mmc_host_probe(struct tmio_mmc_host *_host, struct tmio_mmc_data *pdata) { struct platform_device *pdev = _host->pdev; struct mmc_host *mmc = _host->mmc; struct resource *res_ctl; int ret; u32 irq_mask = TMIO_MASK_CMD; Loading @@ -1067,25 +1090,17 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host, tmio_mmc_of_parse(pdev, pdata); if (!(pdata->flags & TMIO_MMC_HAS_IDLE_WAIT)) pdata->write16_hook = NULL; _host->write16_hook = NULL; res_ctl = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res_ctl) return -EINVAL; mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &pdev->dev); if (!mmc) return -ENOMEM; ret = mmc_of_parse(mmc); if (ret < 0) goto host_free; pdata->dev = &pdev->dev; _host = mmc_priv(mmc); _host->pdata = pdata; _host->mmc = mmc; _host->pdev = pdev; platform_set_drvdata(pdev, mmc); _host->set_pwr = pdata->set_pwr; Loading Loading @@ -1192,12 +1207,9 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host, mmc_gpiod_request_cd_irq(mmc); } *host = _host; return 0; host_free: mmc_free_host(mmc); return ret; } Loading @@ -1222,7 +1234,6 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host) pm_runtime_disable(&pdev->dev); iounmap(host->ctl); mmc_free_host(mmc); } EXPORT_SYMBOL(tmio_mmc_host_remove); Loading @@ -1237,8 +1248,8 @@ int tmio_mmc_host_runtime_suspend(struct device *dev) if (host->clk_cache) tmio_mmc_clk_stop(host); if (host->pdata->clk_disable) host->pdata->clk_disable(host->pdev); if (host->clk_disable) host->clk_disable(host->pdev); return 0; } Loading Loading
drivers/mmc/host/sh_mobile_sdhi.c +65 −52 Original line number Diff line number Diff line Loading @@ -35,10 +35,13 @@ #define EXT_ACC 0xe4 #define host_to_priv(host) container_of((host)->pdata, struct sh_mobile_sdhi, mmc_data) struct sh_mobile_sdhi_of_data { unsigned long tmio_flags; unsigned long capabilities; unsigned long capabilities2; enum dma_slave_buswidth dma_buswidth; dma_addr_t dma_rx_offset; }; Loading @@ -58,6 +61,7 @@ static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = { .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | TMIO_MMC_CLK_ACTUAL, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, .dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES, .dma_rx_offset = 0x2000, }; Loading @@ -84,16 +88,43 @@ struct sh_mobile_sdhi { struct tmio_mmc_dma dma_priv; }; static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width) { u32 val; /* * see also * sh_mobile_sdhi_of_data :: dma_buswidth */ switch (sd_ctrl_read16(host, CTL_VERSION)) { case 0x490C: val = (width == 32) ? 0x0001 : 0x0000; break; case 0xCB0D: val = (width == 32) ? 0x0000 : 0x0001; break; default: /* nothing to do */ return; } sd_ctrl_write16(host, EXT_ACC, val); } static int sh_mobile_sdhi_clk_enable(struct platform_device *pdev, unsigned int *f) { struct mmc_host *mmc = platform_get_drvdata(pdev); struct tmio_mmc_host *host = mmc_priv(mmc); struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data); struct sh_mobile_sdhi *priv = host_to_priv(host); int ret = clk_prepare_enable(priv->clk); if (ret < 0) return ret; *f = clk_get_rate(priv->clk); /* enable 16bit data access on SDBUF as default */ sh_mobile_sdhi_sdbuf_width(host, 16); return 0; } Loading @@ -101,7 +132,7 @@ static void sh_mobile_sdhi_clk_disable(struct platform_device *pdev) { struct mmc_host *mmc = platform_get_drvdata(pdev); struct tmio_mmc_host *host = mmc_priv(mmc); struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data); struct sh_mobile_sdhi *priv = host_to_priv(host); clk_disable_unprepare(priv->clk); } Loading @@ -113,7 +144,7 @@ static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host) udelay(1); if (!timeout) { dev_warn(host->pdata->dev, "timeout waiting for SD bus idle\n"); dev_warn(&host->pdev->dev, "timeout waiting for SD bus idle\n"); return -EBUSY; } Loading Loading @@ -156,14 +187,13 @@ static int sh_mobile_sdhi_multi_io_quirk(struct mmc_card *card, return blk_size; } static void sh_mobile_sdhi_cd_wakeup(const struct platform_device *pdev) static void sh_mobile_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable) { mmc_detect_change(platform_get_drvdata(pdev), msecs_to_jiffies(100)); } sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0); static const struct sh_mobile_sdhi_ops sdhi_ops = { .cd_wakeup = sh_mobile_sdhi_cd_wakeup, }; /* enable 32bit access if DMA mode if possibile */ sh_mobile_sdhi_sdbuf_width(host, enable ? 32 : 16); } static int sh_mobile_sdhi_probe(struct platform_device *pdev) { Loading @@ -177,7 +207,6 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) int irq, ret, i = 0; bool multiplexed_isr = true; struct tmio_mmc_dma *dma_priv; u16 ver; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) Loading @@ -192,26 +221,31 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) mmc_data = &priv->mmc_data; dma_priv = &priv->dma_priv; if (p) { if (p->init) { ret = p->init(pdev, &sdhi_ops); if (ret) return ret; } } priv->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(priv->clk)) { ret = PTR_ERR(priv->clk); dev_err(&pdev->dev, "cannot get clock: %d\n", ret); goto eclkget; goto eprobe; } host = tmio_mmc_host_alloc(pdev); if (!host) { ret = -ENOMEM; goto eprobe; } mmc_data->clk_enable = sh_mobile_sdhi_clk_enable; mmc_data->clk_disable = sh_mobile_sdhi_clk_disable; host->dma = dma_priv; host->write16_hook = sh_mobile_sdhi_write16_hook; host->clk_enable = sh_mobile_sdhi_clk_enable; host->clk_disable = sh_mobile_sdhi_clk_disable; host->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk; /* SD control register space size is 0x100, 0x200 for bus_shift=1 */ if (resource_size(res) > 0x100) host->bus_shift = 1; else host->bus_shift = 0; mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED; mmc_data->write16_hook = sh_mobile_sdhi_write16_hook; mmc_data->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk; if (p) { mmc_data->flags = p->tmio_flags; mmc_data->ocr_mask = p->tmio_ocr_mask; Loading @@ -231,11 +265,10 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) dma_priv->slave_id_rx = p->dma_slave_rx; } } dma_priv->alignment_shift = 1; /* 2-byte alignment */ dma_priv->filter = shdma_chan_filter; dma_priv->enable = sh_mobile_sdhi_enable_dma; mmc_data->dma = dma_priv; mmc_data->alignment_shift = 1; /* 2-byte alignment */ /* * All SDHI blocks support 2-byte and larger block sizes in 4-bit Loading @@ -258,33 +291,18 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) */ mmc_data->flags |= TMIO_MMC_SDIO_STATUS_QUIRK; /* * All SDHI have DMA control register */ mmc_data->flags |= TMIO_MMC_HAVE_CTL_DMA_REG; if (of_id && of_id->data) { const struct sh_mobile_sdhi_of_data *of_data = of_id->data; mmc_data->flags |= of_data->tmio_flags; mmc_data->capabilities |= of_data->capabilities; mmc_data->capabilities2 |= of_data->capabilities2; dma_priv->dma_rx_offset = of_data->dma_rx_offset; mmc_data->dma_rx_offset = of_data->dma_rx_offset; dma_priv->dma_buswidth = of_data->dma_buswidth; } /* SD control register space size is 0x100, 0x200 for bus_shift=1 */ mmc_data->bus_shift = resource_size(res) >> 9; ret = tmio_mmc_host_probe(&host, pdev, mmc_data); ret = tmio_mmc_host_probe(host, mmc_data); if (ret < 0) goto eprobe; /* * FIXME: * this Workaround can be more clever method */ ver = sd_ctrl_read16(host, CTL_VERSION); if (ver == 0xCB0D) sd_ctrl_write16(host, EXT_ACC, 1); goto efree; /* * Allow one or more specific (named) ISRs or Loading Loading @@ -351,10 +369,9 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) eirq: tmio_mmc_host_remove(host); efree: tmio_mmc_host_free(host); eprobe: eclkget: if (p && p->cleanup) p->cleanup(pdev); return ret; } Loading @@ -362,13 +379,9 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev) { struct mmc_host *mmc = platform_get_drvdata(pdev); struct tmio_mmc_host *host = mmc_priv(mmc); struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; tmio_mmc_host_remove(host); if (p && p->cleanup) p->cleanup(pdev); return 0; } Loading
drivers/mmc/host/tmio_mmc.c +11 −4 Original line number Diff line number Diff line Loading @@ -88,14 +88,19 @@ static int tmio_mmc_probe(struct platform_device *pdev) if (!res) return -EINVAL; /* SD control register space size is 0x200, 0x400 for bus_shift=1 */ pdata->bus_shift = resource_size(res) >> 10; pdata->flags |= TMIO_MMC_HAVE_HIGH_REG; ret = tmio_mmc_host_probe(&host, pdev, pdata); if (ret) host = tmio_mmc_host_alloc(pdev); if (!host) goto cell_disable; /* SD control register space size is 0x200, 0x400 for bus_shift=1 */ host->bus_shift = resource_size(res) >> 10; ret = tmio_mmc_host_probe(host, pdata); if (ret) goto host_free; ret = request_irq(irq, tmio_mmc_irq, IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), host); if (ret) Loading @@ -108,6 +113,8 @@ static int tmio_mmc_probe(struct platform_device *pdev) host_remove: tmio_mmc_host_remove(host); host_free: tmio_mmc_host_free(host); cell_disable: if (cell->disable) cell->disable(pdev); Loading
drivers/mmc/host/tmio_mmc.h +32 −11 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #ifndef TMIO_MMC_H #define TMIO_MMC_H #include <linux/dmaengine.h> #include <linux/highmem.h> #include <linux/mmc/tmio.h> #include <linux/mutex.h> Loading @@ -39,6 +40,17 @@ #define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD) struct tmio_mmc_data; struct tmio_mmc_host; struct tmio_mmc_dma { void *chan_priv_tx; void *chan_priv_rx; int slave_id_tx; int slave_id_rx; enum dma_slave_buswidth dma_buswidth; bool (*filter)(struct dma_chan *chan, void *arg); void (*enable)(struct tmio_mmc_host *host, bool enable); }; struct tmio_mmc_host { void __iomem *ctl; Loading @@ -56,9 +68,11 @@ struct tmio_mmc_host { struct scatterlist *sg_orig; unsigned int sg_len; unsigned int sg_off; unsigned long bus_shift; struct platform_device *pdev; struct tmio_mmc_data *pdata; struct tmio_mmc_dma *dma; /* DMA support */ bool force_pio; Loading @@ -83,10 +97,17 @@ struct tmio_mmc_host { struct mutex ios_lock; /* protect set_ios() context */ bool native_hotplug; bool sdio_irq_enabled; int (*write16_hook)(struct tmio_mmc_host *host, int addr); int (*clk_enable)(struct platform_device *pdev, unsigned int *f); void (*clk_disable)(struct platform_device *pdev); int (*multi_io_quirk)(struct mmc_card *card, unsigned int direction, int blk_size); }; int tmio_mmc_host_probe(struct tmio_mmc_host **host, struct platform_device *pdev, struct tmio_mmc_host *tmio_mmc_host_alloc(struct platform_device *pdev); void tmio_mmc_host_free(struct tmio_mmc_host *host); int tmio_mmc_host_probe(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata); void tmio_mmc_host_remove(struct tmio_mmc_host *host); void tmio_mmc_do_data_irq(struct tmio_mmc_host *host); Loading Loading @@ -151,19 +172,19 @@ int tmio_mmc_host_runtime_resume(struct device *dev); static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr) { return readw(host->ctl + (addr << host->pdata->bus_shift)); return readw(host->ctl + (addr << host->bus_shift)); } static inline void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr, u16 *buf, int count) { readsw(host->ctl + (addr << host->pdata->bus_shift), buf, count); readsw(host->ctl + (addr << host->bus_shift), buf, count); } static inline u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr) { return readw(host->ctl + (addr << host->pdata->bus_shift)) | readw(host->ctl + ((addr + 2) << host->pdata->bus_shift)) << 16; return readw(host->ctl + (addr << host->bus_shift)) | readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16; } static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val) Loading @@ -171,21 +192,21 @@ static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val /* If there is a hook and it returns non-zero then there * is an error and the write should be skipped */ if (host->pdata->write16_hook && host->pdata->write16_hook(host, addr)) if (host->write16_hook && host->write16_hook(host, addr)) return; writew(val, host->ctl + (addr << host->pdata->bus_shift)); writew(val, host->ctl + (addr << host->bus_shift)); } static inline void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr, u16 *buf, int count) { writesw(host->ctl + (addr << host->pdata->bus_shift), buf, count); writesw(host->ctl + (addr << host->bus_shift), buf, count); } static inline void sd_ctrl_write32(struct tmio_mmc_host *host, int addr, u32 val) { writew(val, host->ctl + (addr << host->pdata->bus_shift)); writew(val >> 16, host->ctl + ((addr + 2) << host->pdata->bus_shift)); writew(val, host->ctl + (addr << host->bus_shift)); writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift)); } Loading
drivers/mmc/host/tmio_mmc_dma.c +20 −18 Original line number Diff line number Diff line Loading @@ -28,8 +28,8 @@ void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable) if (!host->chan_tx || !host->chan_rx) return; if (host->pdata->flags & TMIO_MMC_HAVE_CTL_DMA_REG) sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0); if (host->dma->enable) host->dma->enable(host, enable); } void tmio_mmc_abort_dma(struct tmio_mmc_host *host) Loading @@ -49,11 +49,10 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) struct scatterlist *sg = host->sg_ptr, *sg_tmp; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *chan = host->chan_rx; struct tmio_mmc_data *pdata = host->pdata; dma_cookie_t cookie; int ret, i; bool aligned = true, multiple = true; unsigned int align = (1 << pdata->dma->alignment_shift) - 1; unsigned int align = (1 << host->pdata->alignment_shift) - 1; for_each_sg(sg, sg_tmp, host->sg_len, i) { if (sg_tmp->offset & align) Loading Loading @@ -126,11 +125,10 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) struct scatterlist *sg = host->sg_ptr, *sg_tmp; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *chan = host->chan_tx; struct tmio_mmc_data *pdata = host->pdata; dma_cookie_t cookie; int ret, i; bool aligned = true, multiple = true; unsigned int align = (1 << pdata->dma->alignment_shift) - 1; unsigned int align = (1 << host->pdata->alignment_shift) - 1; for_each_sg(sg, sg_tmp, host->sg_len, i) { if (sg_tmp->offset & align) Loading Loading @@ -262,8 +260,8 @@ static void tmio_mmc_tasklet_fn(unsigned long arg) void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata) { /* We can only either use DMA for both Tx and Rx or not use it at all */ if (!pdata->dma || (!host->pdev->dev.of_node && (!pdata->dma->chan_priv_tx || !pdata->dma->chan_priv_rx))) if (!host->dma || (!host->pdev->dev.of_node && (!host->dma->chan_priv_tx || !host->dma->chan_priv_rx))) return; if (!host->chan_tx && !host->chan_rx) { Loading @@ -280,7 +278,7 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat dma_cap_set(DMA_SLAVE, mask); host->chan_tx = dma_request_slave_channel_compat(mask, pdata->dma->filter, pdata->dma->chan_priv_tx, host->dma->filter, host->dma->chan_priv_tx, &host->pdev->dev, "tx"); dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__, host->chan_tx); Loading @@ -288,10 +286,12 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat if (!host->chan_tx) return; if (pdata->dma->chan_priv_tx) cfg.slave_id = pdata->dma->slave_id_tx; if (host->dma->chan_priv_tx) cfg.slave_id = host->dma->slave_id_tx; cfg.direction = DMA_MEM_TO_DEV; cfg.dst_addr = res->start + (CTL_SD_DATA_PORT << host->pdata->bus_shift); cfg.dst_addr = res->start + (CTL_SD_DATA_PORT << host->bus_shift); cfg.dst_addr_width = host->dma->dma_buswidth; if (!cfg.dst_addr_width) cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; cfg.src_addr = 0; ret = dmaengine_slave_config(host->chan_tx, &cfg); Loading @@ -299,7 +299,7 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat goto ecfgtx; host->chan_rx = dma_request_slave_channel_compat(mask, pdata->dma->filter, pdata->dma->chan_priv_rx, host->dma->filter, host->dma->chan_priv_rx, &host->pdev->dev, "rx"); dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__, host->chan_rx); Loading @@ -307,10 +307,12 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat if (!host->chan_rx) goto ereqrx; if (pdata->dma->chan_priv_rx) cfg.slave_id = pdata->dma->slave_id_rx; if (host->dma->chan_priv_rx) cfg.slave_id = host->dma->slave_id_rx; cfg.direction = DMA_DEV_TO_MEM; cfg.src_addr = cfg.dst_addr + pdata->dma->dma_rx_offset; cfg.src_addr = cfg.dst_addr + host->pdata->dma_rx_offset; cfg.src_addr_width = host->dma->dma_buswidth; if (!cfg.src_addr_width) cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; cfg.dst_addr = 0; ret = dmaengine_slave_config(host->chan_rx, &cfg); Loading
drivers/mmc/host/tmio_mmc_pio.c +36 −25 Original line number Diff line number Diff line Loading @@ -835,13 +835,12 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) static int tmio_mmc_clk_update(struct tmio_mmc_host *host) { struct mmc_host *mmc = host->mmc; struct tmio_mmc_data *pdata = host->pdata; int ret; if (!pdata->clk_enable) if (!host->clk_enable) return -ENOTSUPP; ret = pdata->clk_enable(host->pdev, &mmc->f_max); ret = host->clk_enable(host->pdev, &mmc->f_max); if (!ret) mmc->f_min = mmc->f_max / 512; Loading Loading @@ -1005,10 +1004,9 @@ static int tmio_multi_io_quirk(struct mmc_card *card, unsigned int direction, int blk_size) { struct tmio_mmc_host *host = mmc_priv(card->host); struct tmio_mmc_data *pdata = host->pdata; if (pdata->multi_io_quirk) return pdata->multi_io_quirk(card, direction, blk_size); if (host->multi_io_quirk) return host->multi_io_quirk(card, direction, blk_size); return blk_size; } Loading Loading @@ -1054,12 +1052,37 @@ static void tmio_mmc_of_parse(struct platform_device *pdev, pdata->flags |= TMIO_MMC_WRPROTECT_DISABLE; } int tmio_mmc_host_probe(struct tmio_mmc_host **host, struct platform_device *pdev, struct tmio_mmc_data *pdata) struct tmio_mmc_host* tmio_mmc_host_alloc(struct platform_device *pdev) { struct tmio_mmc_host *_host; struct tmio_mmc_host *host; struct mmc_host *mmc; mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &pdev->dev); if (!mmc) return NULL; host = mmc_priv(mmc); host->mmc = mmc; host->pdev = pdev; return host; } EXPORT_SYMBOL(tmio_mmc_host_alloc); void tmio_mmc_host_free(struct tmio_mmc_host *host) { mmc_free_host(host->mmc); host->mmc = NULL; } EXPORT_SYMBOL(tmio_mmc_host_free); int tmio_mmc_host_probe(struct tmio_mmc_host *_host, struct tmio_mmc_data *pdata) { struct platform_device *pdev = _host->pdev; struct mmc_host *mmc = _host->mmc; struct resource *res_ctl; int ret; u32 irq_mask = TMIO_MASK_CMD; Loading @@ -1067,25 +1090,17 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host, tmio_mmc_of_parse(pdev, pdata); if (!(pdata->flags & TMIO_MMC_HAS_IDLE_WAIT)) pdata->write16_hook = NULL; _host->write16_hook = NULL; res_ctl = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res_ctl) return -EINVAL; mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &pdev->dev); if (!mmc) return -ENOMEM; ret = mmc_of_parse(mmc); if (ret < 0) goto host_free; pdata->dev = &pdev->dev; _host = mmc_priv(mmc); _host->pdata = pdata; _host->mmc = mmc; _host->pdev = pdev; platform_set_drvdata(pdev, mmc); _host->set_pwr = pdata->set_pwr; Loading Loading @@ -1192,12 +1207,9 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host, mmc_gpiod_request_cd_irq(mmc); } *host = _host; return 0; host_free: mmc_free_host(mmc); return ret; } Loading @@ -1222,7 +1234,6 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host) pm_runtime_disable(&pdev->dev); iounmap(host->ctl); mmc_free_host(mmc); } EXPORT_SYMBOL(tmio_mmc_host_remove); Loading @@ -1237,8 +1248,8 @@ int tmio_mmc_host_runtime_suspend(struct device *dev) if (host->clk_cache) tmio_mmc_clk_stop(host); if (host->pdata->clk_disable) host->pdata->clk_disable(host->pdev); if (host->clk_disable) host->clk_disable(host->pdev); return 0; } Loading