MMC core:

- Increase the timeout period of the ACMD41 command
  - Add card entry for quirks to debugfs
  - Add mmc_gpiod_set_cd_config() function
  - Store owner from SDIO modules with sdio_register_driver()
 
 MMC host:
  - atmel-mci: Some cleanups and a switch to use dev_err_probe()
  - renesas_sdhi: Add support for RZ/G2L, RZ/G3S and RZ/V2M variants
  - renesas_sdhi: Set the SDBUF after reset
  - sdhci: Add support for "Tuning Error" interrupts
  - sdhci-acpi: Add quirk to enable pull-up on the card-detect GPIO on Asus T100TA
  - sdhci-acpi: Disable write protect detection on Toshiba WT10-A
  - sdhci-acpi: Fix Lenovo Yoga Tablet 2 Pro 1380 sdcard slot not working
  - sdhci_am654: Re-work and fix the tuning support for multiple speed-modes
  - sdhci_am654: Add tuning algorithm for delay chain
  - sdhci-esdhc-imx: Add NXP S32G3 support
  - sdhci-of-dwcmshc: Add tuning support for Sophgo CV1800B and SG200X
  - sdhci-of-dwcmshc: Implement SDHCI CQE support
  - sdhci-pci-gli: Use the proper pci_set_power_state() instead of PMCSR writes
 
 MEMSTICK:
  - Convert a couple of drivers to use the ->remove_new() callback
 -----BEGIN PGP SIGNATURE-----
 
 iQJLBAABCgA1FiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAmZGI0UXHHVsZi5oYW5z
 c29uQGxpbmFyby5vcmcACgkQ/iaEJXNYjCk0Bw//cSgatLPu9ypQv8N2pIL9FTBR
 0Y7cwoQmEp35WArHUl+ouqN9It8FHKUB55jmBTv1STd9Rf+VMKlCCRODYjVZwcTV
 cQRlIx6iAwvVyNr8JY1V9nfpgYnHCtd1uJJXqBm1d3p7cU3RQl6Bnn/0WxOgcCxT
 jUwR4VeMj6m+g9q9vck5+PFVZ4plznygzcJ6mIBtWSiQj8/XpYS1TaoYX4bxCfB7
 vESICzp4+VpK8SbJzxtfcLL+SGU2HIpHhFOW7vsI2pY+Tf4wu2QDyB/6od5RxfDY
 xC8mCRFp+WpG5Txvb0kbbf9munFCTl+xiXemqIlCZ4gsmjPNhtPhp2xeJhL1e9yI
 s9C20SCABgS0AbV0AmS+vQNe9cEL1/rFOjaNZi1scseVTSxsDr7YHTp3bPs8C/rs
 JZgjmxBmnQfmSwKjRuv9Rj77L3VD4RcMzrc0SQ0PjXEivtf/m636AVlbiytCRrTo
 BlqoIOoWBXUkoKiFCJn5ne63jGRRjYv5BhZaVmeaYVvbooQhaFpzBRkozoExm8Mk
 ZiY2HdUY5uDdwWVPyldP/f9PHIJAAKdzbPf0K6sQBDJgzzH5OMT39SdxDQ9rAAUl
 RO03A2Ntkx9eFZOo/4TjShI1rCKOVXytoB3sjONSCBFg+teYUdpmDvbZXtAcqJWV
 Sowz+pVjVkiefXBLGgg=
 =I2JP
 -----END PGP SIGNATURE-----

Merge tag 'mmc-v6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc

Pull MMC updates from Ulf Hansson:
 "MMC core:
   - Increase the timeout period of the ACMD41 command
   - Add card entry for quirks to debugfs
   - Add mmc_gpiod_set_cd_config() function
   - Store owner from SDIO modules with sdio_register_driver()

  MMC host:
   - atmel-mci: Some cleanups and a switch to use dev_err_probe()
   - renesas_sdhi:
      - Add support for RZ/G2L, RZ/G3S and RZ/V2M variants
      - Set the SDBUF after reset
   - sdhci: Add support for "Tuning Error" interrupts
   - sdhci-acpi:
      - Add quirk to enable pull-up on the card-detect GPIO on Asus
        T100TA
      - Disable write protect detection on Toshiba WT10-A
      - Fix Lenovo Yoga Tablet 2 Pro 1380 sdcard slot not working
   - sdhci_am654:
      - Re-work and fix the tuning support for multiple speed-modes
      - Add tuning algorithm for delay chain
   - sdhci-esdhc-imx: Add NXP S32G3 support
   - sdhci-of-dwcmshc:
      - Add tuning support for Sophgo CV1800B and SG200X
      - Implement SDHCI CQE support
   - sdhci-pci-gli: Use the proper pci_set_power_state() instead of
     PMCSR writes"

  MEMSTICK:
   - Convert a couple of drivers to use the ->remove_new() callback"

* tag 'mmc-v6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (59 commits)
  mmc: renesas_sdhi: Add compatible string for RZ/G2L family, RZ/G3S, and RZ/V2M SoCs
  dt-bindings: mmc: renesas,sdhi: Document RZ/G2L family compatibility
  dt-bindings: mmc: renesas,sdhi: Group single const value items into an enum list
  mmc: renesas_sdhi: Set the SDBUF after reset
  mmc: core: Increase the timeout period of the ACMD41 command
  mmc: core: Convert to use __mmc_poll_for_busy() SD_APP_OP_COND too
  mmc: atmel-mci: Switch to use dev_err_probe()
  mmc: atmel-mci: Incapsulate used to be a platform data into host structure
  mmc: atmel-mci: Replace platform device pointer by generic one
  mmc: atmel-mci: Use temporary variable for struct device
  mmc: atmel-mci: Get rid of platform data leftovers
  mmc: sdhci-of-dwcmshc: Add tuning support for Sophgo CV1800B and SG200X
  mmc: sdhci-of-dwcmshc: Remove useless "&" of th1520_execute_tuning
  mmc: sdhci-s3c: Choose sdhci_ops based on variant
  mmc: sdhci_am654: Constify struct sdhci_ops
  mmc: sdhci-sprd: Constify struct sdhci_ops
  mmc: sdhci-omap: Constify struct sdhci_ops
  mmc: sdhci-esdhc-mcf: Constify struct sdhci_ops
  mmc: slot-gpio: Use irq_handler_t type
  mmc: sdhci-acpi: Add quirk to enable pull-up on the card-detect GPIO on Asus T100TA
  ...
This commit is contained in:
Linus Torvalds 2024-05-16 08:56:49 -07:00
commit 8b06f7538a
39 changed files with 826 additions and 396 deletions

View File

@ -91,6 +91,9 @@ properties:
- enum:
- fsl,imxrt1170-usdhc
- const: fsl,imxrt1050-usdhc
- items:
- const: nxp,s32g3-usdhc
- const: nxp,s32g2-usdhc
reg:
maxItems: 1

View File

@ -12,16 +12,13 @@ maintainers:
properties:
compatible:
oneOf:
- items:
- const: renesas,sdhi-sh73a0 # R-Mobile APE6
- items:
- const: renesas,sdhi-r7s72100 # RZ/A1H
- items:
- const: renesas,sdhi-r7s9210 # SH-Mobile AG5
- items:
- const: renesas,sdhi-r8a73a4 # R-Mobile APE6
- items:
- const: renesas,sdhi-r8a7740 # R-Mobile A1
- enum:
- renesas,sdhi-mmc-r8a77470 # RZ/G1C
- renesas,sdhi-r7s72100 # RZ/A1H
- renesas,sdhi-r7s9210 # SH-Mobile AG5
- renesas,sdhi-r8a73a4 # R-Mobile APE6
- renesas,sdhi-r8a7740 # R-Mobile A1
- renesas,sdhi-sh73a0 # R-Mobile APE6
- items:
- enum:
- renesas,sdhi-r8a7778 # R-Car M1
@ -40,8 +37,6 @@ properties:
- renesas,sdhi-r8a7793 # R-Car M2-N
- renesas,sdhi-r8a7794 # R-Car E2
- const: renesas,rcar-gen2-sdhi # R-Car Gen2 and RZ/G1
- items:
- const: renesas,sdhi-mmc-r8a77470 # RZ/G1C (SDHI/MMC IP)
- items:
- enum:
- renesas,sdhi-r8a774a1 # RZ/G2M
@ -56,11 +51,6 @@ properties:
- renesas,sdhi-r8a77980 # R-Car V3H
- renesas,sdhi-r8a77990 # R-Car E3
- renesas,sdhi-r8a77995 # R-Car D3
- renesas,sdhi-r9a07g043 # RZ/G2UL and RZ/Five
- renesas,sdhi-r9a07g044 # RZ/G2{L,LC}
- renesas,sdhi-r9a07g054 # RZ/V2L
- renesas,sdhi-r9a08g045 # RZ/G3S
- renesas,sdhi-r9a09g011 # RZ/V2M
- const: renesas,rcar-gen3-sdhi # R-Car Gen3 or RZ/G2
- items:
- enum:
@ -69,6 +59,14 @@ properties:
- renesas,sdhi-r8a779g0 # R-Car V4H
- renesas,sdhi-r8a779h0 # R-Car V4M
- const: renesas,rcar-gen4-sdhi # R-Car Gen4
- items:
- enum:
- renesas,sdhi-r9a07g043 # RZ/G2UL and RZ/Five
- renesas,sdhi-r9a07g044 # RZ/G2{L,LC}
- renesas,sdhi-r9a07g054 # RZ/V2L
- renesas,sdhi-r9a08g045 # RZ/G3S
- renesas,sdhi-r9a09g011 # RZ/V2M
- const: renesas,rzg2l-sdhi
reg:
maxItems: 1
@ -120,12 +118,7 @@ allOf:
properties:
compatible:
contains:
enum:
- renesas,sdhi-r9a07g043
- renesas,sdhi-r9a07g044
- renesas,sdhi-r9a07g054
- renesas,sdhi-r9a08g045
- renesas,sdhi-r9a09g011
const: renesas,rzg2l-sdhi
then:
properties:
clocks:

View File

@ -8616,7 +8616,7 @@ F: Documentation/devicetree/bindings/crypto/fsl,sec-v4.0*
F: drivers/crypto/caam/
FREESCALE COLDFIRE M5441X MMC DRIVER
M: Angelo Dureghello <angelo.dureghello@timesys.com>
M: Angelo Dureghello <adureghello@baylibre.com>
L: linux-mmc@vger.kernel.org
S: Maintained
F: drivers/mmc/host/sdhci-esdhc-mcf.c

View File

@ -1736,7 +1736,6 @@ static struct sdio_driver bt_mrvl_sdio = {
.probe = btmrvl_sdio_probe,
.remove = btmrvl_sdio_remove,
.drv = {
.owner = THIS_MODULE,
.coredump = btmrvl_sdio_coredump,
.pm = &btmrvl_sdio_pm_ops,
}

View File

@ -1519,7 +1519,6 @@ static struct sdio_driver btmtksdio_driver = {
.remove = btmtksdio_remove,
.id_table = btmtksdio_table,
.drv = {
.owner = THIS_MODULE,
.pm = BTMTKSDIO_PM_OPS,
}
};

View File

@ -574,16 +574,13 @@ static int rtsx_pci_ms_drv_probe(struct platform_device *pdev)
return 0;
}
static int rtsx_pci_ms_drv_remove(struct platform_device *pdev)
static void rtsx_pci_ms_drv_remove(struct platform_device *pdev)
{
struct realtek_pci_ms *host = platform_get_drvdata(pdev);
struct rtsx_pcr *pcr;
struct memstick_host *msh;
int rc;
if (!host)
return 0;
pcr = host->pcr;
pcr->slots[RTSX_MS_CARD].p_dev = NULL;
pcr->slots[RTSX_MS_CARD].card_event = NULL;
@ -613,8 +610,6 @@ static int rtsx_pci_ms_drv_remove(struct platform_device *pdev)
dev_dbg(&(pdev->dev),
": Realtek PCI-E Memstick controller has been removed\n");
return 0;
}
static struct platform_device_id rtsx_pci_ms_ids[] = {
@ -628,7 +623,7 @@ MODULE_DEVICE_TABLE(platform, rtsx_pci_ms_ids);
static struct platform_driver rtsx_pci_ms_driver = {
.probe = rtsx_pci_ms_drv_probe,
.remove = rtsx_pci_ms_drv_remove,
.remove_new = rtsx_pci_ms_drv_remove,
.id_table = rtsx_pci_ms_ids,
.suspend = rtsx_pci_ms_suspend,
.resume = rtsx_pci_ms_resume,

View File

@ -805,7 +805,7 @@ err_out:
return err;
}
static int rtsx_usb_ms_drv_remove(struct platform_device *pdev)
static void rtsx_usb_ms_drv_remove(struct platform_device *pdev)
{
struct rtsx_usb_ms *host = platform_get_drvdata(pdev);
struct memstick_host *msh = host->msh;
@ -840,8 +840,6 @@ static int rtsx_usb_ms_drv_remove(struct platform_device *pdev)
": Realtek USB Memstick controller has been removed\n");
memstick_free_host(msh);
platform_set_drvdata(pdev, NULL);
return 0;
}
static struct platform_device_id rtsx_usb_ms_ids[] = {
@ -855,7 +853,7 @@ MODULE_DEVICE_TABLE(platform, rtsx_usb_ms_ids);
static struct platform_driver rtsx_usb_ms_driver = {
.probe = rtsx_usb_ms_drv_probe,
.remove = rtsx_usb_ms_drv_remove,
.remove_new = rtsx_usb_ms_drv_remove,
.id_table = rtsx_usb_ms_ids,
.driver = {
.name = "rtsx_usb_ms",

View File

@ -234,7 +234,7 @@ static ssize_t power_ro_lock_show(struct device *dev,
else if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_EN)
locked = 1;
ret = snprintf(buf, PAGE_SIZE, "%d\n", locked);
ret = sysfs_emit(buf, "%d\n", locked);
mmc_blk_put(md);
@ -296,9 +296,9 @@ static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,
int ret;
struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
ret = snprintf(buf, PAGE_SIZE, "%d\n",
get_disk_ro(dev_to_disk(dev)) ^
md->read_only);
ret = sysfs_emit(buf, "%d\n",
get_disk_ro(dev_to_disk(dev)) ^
md->read_only);
mmc_blk_put(md);
return ret;
}

View File

@ -351,11 +351,11 @@ void mmc_add_host_debugfs(struct mmc_host *host)
root = debugfs_create_dir(mmc_hostname(host), NULL);
host->debugfs_root = root;
debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops);
debugfs_create_file("ios", 0400, root, host, &mmc_ios_fops);
debugfs_create_file("caps", 0600, root, &host->caps, &mmc_caps_fops);
debugfs_create_file("caps2", 0600, root, &host->caps2,
&mmc_caps2_fops);
debugfs_create_file_unsafe("clock", S_IRUSR | S_IWUSR, root, host,
debugfs_create_file_unsafe("clock", 0600, root, host,
&mmc_clock_fops);
debugfs_create_file_unsafe("err_state", 0600, root, host,
@ -388,7 +388,8 @@ void mmc_add_card_debugfs(struct mmc_card *card)
root = debugfs_create_dir(mmc_card_id(card), host->debugfs_root);
card->debugfs_root = root;
debugfs_create_x32("state", S_IRUSR, root, &card->state);
debugfs_create_x32("state", 0400, root, &card->state);
debugfs_create_x32("quirks", 0400, root, &card->quirks);
}
void mmc_remove_card_debugfs(struct mmc_card *card)

View File

@ -13,7 +13,6 @@
#include <linux/err.h>
#include <linux/idr.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/pagemap.h>
#include <linux/pm_wakeup.h>
#include <linux/export.h>

View File

@ -19,6 +19,20 @@
#include "sd_ops.h"
#include "mmc_ops.h"
/*
* Extensive testing has shown that some specific SD cards
* require an increased command timeout to be successfully
* initialized.
*/
#define SD_APP_OP_COND_PERIOD_US (10 * 1000) /* 10ms */
#define SD_APP_OP_COND_TIMEOUT_MS 2000 /* 2s */
struct sd_app_op_cond_busy_data {
struct mmc_host *host;
u32 ocr;
struct mmc_command *cmd;
};
int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
{
int err;
@ -115,10 +129,45 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width)
return mmc_wait_for_app_cmd(card->host, card, &cmd);
}
static int sd_app_op_cond_cb(void *cb_data, bool *busy)
{
struct sd_app_op_cond_busy_data *data = cb_data;
struct mmc_host *host = data->host;
struct mmc_command *cmd = data->cmd;
u32 ocr = data->ocr;
int err;
*busy = false;
err = mmc_wait_for_app_cmd(host, NULL, cmd);
if (err)
return err;
/* If we're just probing, do a single pass. */
if (ocr == 0)
return 0;
/* Wait until reset completes. */
if (mmc_host_is_spi(host)) {
if (!(cmd->resp[0] & R1_SPI_IDLE))
return 0;
} else if (cmd->resp[0] & MMC_CARD_BUSY) {
return 0;
}
*busy = true;
return 0;
}
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
{
struct mmc_command cmd = {};
int i, err = 0;
struct sd_app_op_cond_busy_data cb_data = {
.host = host,
.ocr = ocr,
.cmd = &cmd
};
int err;
cmd.opcode = SD_APP_OP_COND;
if (mmc_host_is_spi(host))
@ -127,36 +176,16 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
cmd.arg = ocr;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
for (i = 100; i; i--) {
err = mmc_wait_for_app_cmd(host, NULL, &cmd);
if (err)
break;
/* if we're just probing, do a single pass */
if (ocr == 0)
break;
/* otherwise wait until reset completes */
if (mmc_host_is_spi(host)) {
if (!(cmd.resp[0] & R1_SPI_IDLE))
break;
} else {
if (cmd.resp[0] & MMC_CARD_BUSY)
break;
}
err = -ETIMEDOUT;
mmc_delay(10);
}
if (!i)
pr_err("%s: card never left busy state\n", mmc_hostname(host));
err = __mmc_poll_for_busy(host, SD_APP_OP_COND_PERIOD_US,
SD_APP_OP_COND_TIMEOUT_MS, &sd_app_op_cond_cb,
&cb_data);
if (err)
return err;
if (rocr && !mmc_host_is_spi(host))
*rocr = cmd.resp[0];
return err;
return 0;
}
static int __mmc_send_if_cond(struct mmc_host *host, u32 ocr, u8 pcie_bits,

View File

@ -265,16 +265,19 @@ void sdio_unregister_bus(void)
}
/**
* sdio_register_driver - register a function driver
* __sdio_register_driver - register a function driver
* @drv: SDIO function driver
* @owner: owning module/driver
*/
int sdio_register_driver(struct sdio_driver *drv)
int __sdio_register_driver(struct sdio_driver *drv, struct module *owner)
{
drv->drv.name = drv->name;
drv->drv.bus = &sdio_bus_type;
drv->drv.owner = owner;
return driver_register(&drv->drv);
}
EXPORT_SYMBOL_GPL(sdio_register_driver);
EXPORT_SYMBOL_GPL(__sdio_register_driver);
/**
* sdio_unregister_driver - unregister a function driver

View File

@ -19,7 +19,7 @@
struct mmc_gpio {
struct gpio_desc *ro_gpio;
struct gpio_desc *cd_gpio;
irqreturn_t (*cd_gpio_isr)(int irq, void *dev_id);
irq_handler_t cd_gpio_isr;
char *ro_label;
char *cd_label;
u32 cd_debounce_delay_ms;
@ -162,8 +162,7 @@ EXPORT_SYMBOL(mmc_gpio_set_cd_wake);
/* Register an alternate interrupt service routine for
* the card-detect GPIO.
*/
void mmc_gpio_set_cd_isr(struct mmc_host *host,
irqreturn_t (*isr)(int irq, void *dev_id))
void mmc_gpio_set_cd_isr(struct mmc_host *host, irq_handler_t isr)
{
struct mmc_gpio *ctx = host->slot.handler_priv;
@ -221,6 +220,26 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
}
EXPORT_SYMBOL(mmc_gpiod_request_cd);
/**
* mmc_gpiod_set_cd_config - set config for card-detection GPIO
* @host: mmc host
* @config: Generic pinconf config (from pinconf_to_config_packed())
*
* This can be used by mmc host drivers to fixup a card-detection GPIO's config
* (e.g. set PIN_CONFIG_BIAS_PULL_UP) after acquiring the GPIO descriptor
* through mmc_gpiod_request_cd().
*
* Returns:
* 0 on success, or a negative errno value on error.
*/
int mmc_gpiod_set_cd_config(struct mmc_host *host, unsigned long config)
{
struct mmc_gpio *ctx = host->slot.handler_priv;
return gpiod_set_config(ctx->cd_gpio, config);
}
EXPORT_SYMBOL(mmc_gpiod_set_cd_config);
bool mmc_can_gpio_cd(struct mmc_host *host)
{
struct mmc_gpio *ctx = host->slot.handler_priv;

View File

@ -233,6 +233,7 @@ config MMC_SDHCI_OF_DWCMSHC
depends on MMC_SDHCI_PLTFM
depends on OF
depends on COMMON_CLK
select MMC_CQHCI
help
This selects Synopsys DesignWare Cores Mobile Storage Controller
support.

View File

@ -224,18 +224,6 @@ struct mci_slot_pdata {
bool non_removable;
};
/**
* struct mci_platform_data - board-specific MMC/SDcard configuration
* @dma_slave: DMA slave interface to use in data transfers.
* @dma_filter: Filtering function to filter the DMA channel
* @slot: Per-slot configuration data.
*/
struct mci_platform_data {
void *dma_slave;
dma_filter_fn dma_filter;
struct mci_slot_pdata slot[ATMCI_MAX_NR_SLOTS];
};
struct atmel_mci_caps {
bool has_dma_conf_reg;
bool has_pdc;
@ -300,7 +288,8 @@ struct atmel_mci_dma {
* rate and timeout calculations.
* @mapbase: Physical address of the MMIO registers.
* @mck: The peripheral bus clock hooked up to the MMC controller.
* @pdev: Platform device associated with the MMC controller.
* @dev: Device associated with the MMC controller.
* @pdata: Per-slot configuration data.
* @slot: Slots sharing this MMC controller.
* @caps: MCI capabilities depending on MCI version.
* @prepare_data: function to setup MCI before data transfer which
@ -377,8 +366,9 @@ struct atmel_mci {
unsigned long bus_hz;
unsigned long mapbase;
struct clk *mck;
struct platform_device *pdev;
struct device *dev;
struct mci_slot_pdata pdata[ATMCI_MAX_NR_SLOTS];
struct atmel_mci_slot *slot[ATMCI_MAX_NR_SLOTS];
struct atmel_mci_caps caps;
@ -530,6 +520,7 @@ static void atmci_show_status_reg(struct seq_file *s,
static int atmci_regs_show(struct seq_file *s, void *v)
{
struct atmel_mci *host = s->private;
struct device *dev = host->dev;
u32 *buf;
int ret = 0;
@ -538,7 +529,7 @@ static int atmci_regs_show(struct seq_file *s, void *v)
if (!buf)
return -ENOMEM;
pm_runtime_get_sync(&host->pdev->dev);
pm_runtime_get_sync(dev);
/*
* Grab a more or less consistent snapshot. Note that we're
@ -549,8 +540,8 @@ static int atmci_regs_show(struct seq_file *s, void *v)
memcpy_fromio(buf, host->regs, ATMCI_REGS_SIZE);
spin_unlock_bh(&host->lock);
pm_runtime_mark_last_busy(&host->pdev->dev);
pm_runtime_put_autosuspend(&host->pdev->dev);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
seq_printf(s, "MR:\t0x%08x%s%s ",
buf[ATMCI_MR / 4],
@ -626,7 +617,6 @@ static void atmci_init_debugfs(struct atmel_mci_slot *slot)
&host->completed_events);
}
#if defined(CONFIG_OF)
static const struct of_device_id atmci_dt_ids[] = {
{ .compatible = "atmel,hsmci" },
{ /* sentinel */ }
@ -634,79 +624,64 @@ static const struct of_device_id atmci_dt_ids[] = {
MODULE_DEVICE_TABLE(of, atmci_dt_ids);
static struct mci_platform_data*
atmci_of_init(struct platform_device *pdev)
static int atmci_of_init(struct atmel_mci *host)
{
struct device_node *np = pdev->dev.of_node;
struct device *dev = host->dev;
struct device_node *np = dev->of_node;
struct device_node *cnp;
struct mci_platform_data *pdata;
u32 slot_id;
int err;
if (!np) {
dev_err(&pdev->dev, "device node not found\n");
return ERR_PTR(-EINVAL);
}
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return ERR_PTR(-ENOMEM);
if (!np)
return dev_err_probe(dev, -EINVAL, "device node not found\n");
for_each_child_of_node(np, cnp) {
if (of_property_read_u32(cnp, "reg", &slot_id)) {
dev_warn(&pdev->dev, "reg property is missing for %pOF\n",
cnp);
dev_warn(dev, "reg property is missing for %pOF\n", cnp);
continue;
}
if (slot_id >= ATMCI_MAX_NR_SLOTS) {
dev_warn(&pdev->dev, "can't have more than %d slots\n",
dev_warn(dev, "can't have more than %d slots\n",
ATMCI_MAX_NR_SLOTS);
of_node_put(cnp);
break;
}
if (of_property_read_u32(cnp, "bus-width",
&pdata->slot[slot_id].bus_width))
pdata->slot[slot_id].bus_width = 1;
&host->pdata[slot_id].bus_width))
host->pdata[slot_id].bus_width = 1;
pdata->slot[slot_id].detect_pin =
devm_fwnode_gpiod_get(&pdev->dev, of_fwnode_handle(cnp),
host->pdata[slot_id].detect_pin =
devm_fwnode_gpiod_get(dev, of_fwnode_handle(cnp),
"cd", GPIOD_IN, "cd-gpios");
err = PTR_ERR_OR_ZERO(pdata->slot[slot_id].detect_pin);
err = PTR_ERR_OR_ZERO(host->pdata[slot_id].detect_pin);
if (err) {
if (err != -ENOENT) {
of_node_put(cnp);
return ERR_PTR(err);
return err;
}
pdata->slot[slot_id].detect_pin = NULL;
host->pdata[slot_id].detect_pin = NULL;
}
pdata->slot[slot_id].non_removable =
host->pdata[slot_id].non_removable =
of_property_read_bool(cnp, "non-removable");
pdata->slot[slot_id].wp_pin =
devm_fwnode_gpiod_get(&pdev->dev, of_fwnode_handle(cnp),
host->pdata[slot_id].wp_pin =
devm_fwnode_gpiod_get(dev, of_fwnode_handle(cnp),
"wp", GPIOD_IN, "wp-gpios");
err = PTR_ERR_OR_ZERO(pdata->slot[slot_id].wp_pin);
err = PTR_ERR_OR_ZERO(host->pdata[slot_id].wp_pin);
if (err) {
if (err != -ENOENT) {
of_node_put(cnp);
return ERR_PTR(err);
return err;
}
pdata->slot[slot_id].wp_pin = NULL;
host->pdata[slot_id].wp_pin = NULL;
}
}
return pdata;
return 0;
}
#else /* CONFIG_OF */
static inline struct mci_platform_data*
atmci_of_init(struct platform_device *dev)
{
return ERR_PTR(-EINVAL);
}
#endif
static inline unsigned int atmci_get_version(struct atmel_mci *host)
{
@ -738,11 +713,10 @@ static inline unsigned int atmci_convert_chksize(struct atmel_mci *host,
static void atmci_timeout_timer(struct timer_list *t)
{
struct atmel_mci *host;
struct atmel_mci *host = from_timer(host, t, timer);
struct device *dev = host->dev;
host = from_timer(host, t, timer);
dev_dbg(&host->pdev->dev, "software timeout\n");
dev_dbg(dev, "software timeout\n");
if (host->mrq->cmd->data) {
host->mrq->cmd->data->error = -ETIMEDOUT;
@ -860,15 +834,14 @@ static u32 atmci_prepare_command(struct mmc_host *mmc,
static void atmci_send_command(struct atmel_mci *host,
struct mmc_command *cmd, u32 cmd_flags)
{
struct device *dev = host->dev;
unsigned int timeout_ms = cmd->busy_timeout ? cmd->busy_timeout :
ATMCI_CMD_TIMEOUT_MS;
WARN_ON(host->cmd);
host->cmd = cmd;
dev_vdbg(&host->pdev->dev,
"start command: ARGR=0x%08x CMDR=0x%08x\n",
cmd->arg, cmd_flags);
dev_vdbg(dev, "start command: ARGR=0x%08x CMDR=0x%08x\n", cmd->arg, cmd_flags);
atmci_writel(host, ATMCI_ARGR, cmd->arg);
atmci_writel(host, ATMCI_CMDR, cmd_flags);
@ -878,7 +851,9 @@ static void atmci_send_command(struct atmel_mci *host,
static void atmci_send_stop_cmd(struct atmel_mci *host, struct mmc_data *data)
{
dev_dbg(&host->pdev->dev, "send stop command\n");
struct device *dev = host->dev;
dev_dbg(dev, "send stop command\n");
atmci_send_command(host, data->stop, host->stop_cmdr);
atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY);
}
@ -951,11 +926,10 @@ static void atmci_pdc_set_both_buf(struct atmel_mci *host, int dir)
static void atmci_pdc_cleanup(struct atmel_mci *host)
{
struct mmc_data *data = host->data;
struct device *dev = host->dev;
if (data)
dma_unmap_sg(&host->pdev->dev,
data->sg, data->sg_len,
mmc_get_dma_dir(data));
dma_unmap_sg(dev, data->sg, data->sg_len, mmc_get_dma_dir(data));
}
/*
@ -965,6 +939,7 @@ static void atmci_pdc_cleanup(struct atmel_mci *host)
*/
static void atmci_pdc_complete(struct atmel_mci *host)
{
struct device *dev = host->dev;
int transfer_size = host->data->blocks * host->data->blksz;
int i;
@ -981,7 +956,7 @@ static void atmci_pdc_complete(struct atmel_mci *host)
atmci_pdc_cleanup(host);
dev_dbg(&host->pdev->dev, "(%s) set pending xfer complete\n", __func__);
dev_dbg(dev, "(%s) set pending xfer complete\n", __func__);
atmci_set_pending(host, EVENT_XFER_COMPLETE);
tasklet_schedule(&host->tasklet);
}
@ -1003,8 +978,9 @@ static void atmci_dma_complete(void *arg)
{
struct atmel_mci *host = arg;
struct mmc_data *data = host->data;
struct device *dev = host->dev;
dev_vdbg(&host->pdev->dev, "DMA complete\n");
dev_vdbg(dev, "DMA complete\n");
if (host->caps.has_dma_conf_reg)
/* Disable DMA hardware handshaking on MCI */
@ -1017,8 +993,7 @@ static void atmci_dma_complete(void *arg)
* to send the stop command or waiting for NBUSY in this case.
*/
if (data) {
dev_dbg(&host->pdev->dev,
"(%s) set pending xfer complete\n", __func__);
dev_dbg(dev, "(%s) set pending xfer complete\n", __func__);
atmci_set_pending(host, EVENT_XFER_COMPLETE);
tasklet_schedule(&host->tasklet);
@ -1092,6 +1067,7 @@ static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data)
static u32
atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
{
struct device *dev = host->dev;
u32 iflags, tmp;
int i;
@ -1117,8 +1093,7 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
/* Configure PDC */
host->data_size = data->blocks * data->blksz;
dma_map_sg(&host->pdev->dev, data->sg, data->sg_len,
mmc_get_dma_dir(data));
dma_map_sg(dev, data->sg, data->sg_len, mmc_get_dma_dir(data));
if ((!host->caps.has_rwproof)
&& (host->data->flags & MMC_DATA_WRITE)) {
@ -1244,8 +1219,9 @@ atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data)
static void atmci_stop_transfer(struct atmel_mci *host)
{
dev_dbg(&host->pdev->dev,
"(%s) set pending xfer complete\n", __func__);
struct device *dev = host->dev;
dev_dbg(dev, "(%s) set pending xfer complete\n", __func__);
atmci_set_pending(host, EVENT_XFER_COMPLETE);
atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
}
@ -1261,14 +1237,14 @@ static void atmci_stop_transfer_pdc(struct atmel_mci *host)
static void atmci_stop_transfer_dma(struct atmel_mci *host)
{
struct dma_chan *chan = host->data_chan;
struct device *dev = host->dev;
if (chan) {
dmaengine_terminate_all(chan);
atmci_dma_cleanup(host);
} else {
/* Data transfer was stopped by the interrupt handler */
dev_dbg(&host->pdev->dev,
"(%s) set pending xfer complete\n", __func__);
dev_dbg(dev, "(%s) set pending xfer complete\n", __func__);
atmci_set_pending(host, EVENT_XFER_COMPLETE);
atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
}
@ -1281,6 +1257,7 @@ static void atmci_stop_transfer_dma(struct atmel_mci *host)
static void atmci_start_request(struct atmel_mci *host,
struct atmel_mci_slot *slot)
{
struct device *dev = host->dev;
struct mmc_request *mrq;
struct mmc_command *cmd;
struct mmc_data *data;
@ -1296,7 +1273,7 @@ static void atmci_start_request(struct atmel_mci *host,
host->cmd_status = 0;
host->data_status = 0;
dev_dbg(&host->pdev->dev, "start request: cmd %u\n", mrq->cmd->opcode);
dev_dbg(dev, "start request: cmd %u\n", mrq->cmd->opcode);
if (host->need_reset || host->caps.need_reset_after_xfer) {
iflags = atmci_readl(host, ATMCI_IMR);
@ -1375,6 +1352,8 @@ static void atmci_start_request(struct atmel_mci *host,
static void atmci_queue_request(struct atmel_mci *host,
struct atmel_mci_slot *slot, struct mmc_request *mrq)
{
struct device *dev = host->dev;
dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n",
host->state);
@ -1384,7 +1363,7 @@ static void atmci_queue_request(struct atmel_mci *host,
host->state = STATE_SENDING_CMD;
atmci_start_request(host, slot);
} else {
dev_dbg(&host->pdev->dev, "queue request\n");
dev_dbg(dev, "queue request\n");
list_add_tail(&slot->queue_node, &host->queue);
}
spin_unlock_bh(&host->lock);
@ -1394,10 +1373,11 @@ static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct atmel_mci_slot *slot = mmc_priv(mmc);
struct atmel_mci *host = slot->host;
struct device *dev = host->dev;
struct mmc_data *data;
WARN_ON(slot->mrq);
dev_dbg(&host->pdev->dev, "MRQ: cmd %u\n", mrq->cmd->opcode);
dev_dbg(dev, "MRQ: cmd %u\n", mrq->cmd->opcode);
/*
* We may "know" the card is gone even though there's still an
@ -1607,6 +1587,7 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq)
{
struct atmel_mci_slot *slot = NULL;
struct mmc_host *prev_mmc = host->cur_slot->mmc;
struct device *dev = host->dev;
WARN_ON(host->cmd || host->data);
@ -1629,12 +1610,11 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq)
slot = list_entry(host->queue.next,
struct atmel_mci_slot, queue_node);
list_del(&slot->queue_node);
dev_vdbg(&host->pdev->dev, "list not empty: %s is next\n",
mmc_hostname(slot->mmc));
dev_vdbg(dev, "list not empty: %s is next\n", mmc_hostname(slot->mmc));
host->state = STATE_SENDING_CMD;
atmci_start_request(host, slot);
} else {
dev_vdbg(&host->pdev->dev, "list empty\n");
dev_vdbg(dev, "list empty\n");
host->state = STATE_IDLE;
}
@ -1770,6 +1750,7 @@ static void atmci_tasklet_func(struct tasklet_struct *t)
struct atmel_mci *host = from_tasklet(host, t, tasklet);
struct mmc_request *mrq = host->mrq;
struct mmc_data *data = host->data;
struct device *dev = host->dev;
enum atmel_mci_state state = host->state;
enum atmel_mci_state prev_state;
u32 status;
@ -1778,14 +1759,13 @@ static void atmci_tasklet_func(struct tasklet_struct *t)
state = host->state;
dev_vdbg(&host->pdev->dev,
"tasklet: state %u pending/completed/mask %lx/%lx/%x\n",
dev_vdbg(dev, "tasklet: state %u pending/completed/mask %lx/%lx/%x\n",
state, host->pending_events, host->completed_events,
atmci_readl(host, ATMCI_IMR));
do {
prev_state = state;
dev_dbg(&host->pdev->dev, "FSM: state=%d\n", state);
dev_dbg(dev, "FSM: state=%d\n", state);
switch (state) {
case STATE_IDLE:
@ -1798,18 +1778,17 @@ static void atmci_tasklet_func(struct tasklet_struct *t)
* END_REQUEST by default, WAITING_NOTBUSY if it's a
* command needing it or DATA_XFER if there is data.
*/
dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n");
dev_dbg(dev, "FSM: cmd ready?\n");
if (!atmci_test_and_clear_pending(host,
EVENT_CMD_RDY))
break;
dev_dbg(&host->pdev->dev, "set completed cmd ready\n");
dev_dbg(dev, "set completed cmd ready\n");
host->cmd = NULL;
atmci_set_completed(host, EVENT_CMD_RDY);
atmci_command_complete(host, mrq->cmd);
if (mrq->data) {
dev_dbg(&host->pdev->dev,
"command with data transfer");
dev_dbg(dev, "command with data transfer\n");
/*
* If there is a command error don't start
* data transfer.
@ -1824,8 +1803,7 @@ static void atmci_tasklet_func(struct tasklet_struct *t)
} else
state = STATE_DATA_XFER;
} else if ((!mrq->data) && (mrq->cmd->flags & MMC_RSP_BUSY)) {
dev_dbg(&host->pdev->dev,
"command response need waiting notbusy");
dev_dbg(dev, "command response need waiting notbusy\n");
atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
state = STATE_WAITING_NOTBUSY;
} else
@ -1836,7 +1814,7 @@ static void atmci_tasklet_func(struct tasklet_struct *t)
case STATE_DATA_XFER:
if (atmci_test_and_clear_pending(host,
EVENT_DATA_ERROR)) {
dev_dbg(&host->pdev->dev, "set completed data error\n");
dev_dbg(dev, "set completed data error\n");
atmci_set_completed(host, EVENT_DATA_ERROR);
state = STATE_END_REQUEST;
break;
@ -1849,14 +1827,12 @@ static void atmci_tasklet_func(struct tasklet_struct *t)
* to the next step which is WAITING_NOTBUSY in write
* case and directly SENDING_STOP in read case.
*/
dev_dbg(&host->pdev->dev, "FSM: xfer complete?\n");
dev_dbg(dev, "FSM: xfer complete?\n");
if (!atmci_test_and_clear_pending(host,
EVENT_XFER_COMPLETE))
break;
dev_dbg(&host->pdev->dev,
"(%s) set completed xfer complete\n",
__func__);
dev_dbg(dev, "(%s) set completed xfer complete\n", __func__);
atmci_set_completed(host, EVENT_XFER_COMPLETE);
if (host->caps.need_notbusy_for_read_ops ||
@ -1881,12 +1857,12 @@ static void atmci_tasklet_func(struct tasklet_struct *t)
* included) or a write operation. In the latest case,
* we need to send a stop command.
*/
dev_dbg(&host->pdev->dev, "FSM: not busy?\n");
dev_dbg(dev, "FSM: not busy?\n");
if (!atmci_test_and_clear_pending(host,
EVENT_NOTBUSY))
break;
dev_dbg(&host->pdev->dev, "set completed not busy\n");
dev_dbg(dev, "set completed not busy\n");
atmci_set_completed(host, EVENT_NOTBUSY);
if (host->data) {
@ -1916,12 +1892,12 @@ static void atmci_tasklet_func(struct tasklet_struct *t)
* in order to go to the end request state instead of
* sending stop again.
*/
dev_dbg(&host->pdev->dev, "FSM: cmd ready?\n");
dev_dbg(dev, "FSM: cmd ready?\n");
if (!atmci_test_and_clear_pending(host,
EVENT_CMD_RDY))
break;
dev_dbg(&host->pdev->dev, "FSM: cmd ready\n");
dev_dbg(dev, "FSM: cmd ready\n");
host->cmd = NULL;
data->bytes_xfered = data->blocks * data->blksz;
data->error = 0;
@ -2120,6 +2096,7 @@ static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status)
static irqreturn_t atmci_interrupt(int irq, void *dev_id)
{
struct atmel_mci *host = dev_id;
struct device *dev = host->dev;
u32 status, mask, pending;
unsigned int pass_count = 0;
@ -2131,21 +2108,21 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
break;
if (pending & ATMCI_DATA_ERROR_FLAGS) {
dev_dbg(&host->pdev->dev, "IRQ: data error\n");
dev_dbg(dev, "IRQ: data error\n");
atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS
| ATMCI_RXRDY | ATMCI_TXRDY
| ATMCI_ENDRX | ATMCI_ENDTX
| ATMCI_RXBUFF | ATMCI_TXBUFE);
host->data_status = status;
dev_dbg(&host->pdev->dev, "set pending data error\n");
dev_dbg(dev, "set pending data error\n");
smp_wmb();
atmci_set_pending(host, EVENT_DATA_ERROR);
tasklet_schedule(&host->tasklet);
}
if (pending & ATMCI_TXBUFE) {
dev_dbg(&host->pdev->dev, "IRQ: tx buffer empty\n");
dev_dbg(dev, "IRQ: tx buffer empty\n");
atmci_writel(host, ATMCI_IDR, ATMCI_TXBUFE);
atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX);
/*
@ -2161,7 +2138,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
atmci_pdc_complete(host);
}
} else if (pending & ATMCI_ENDTX) {
dev_dbg(&host->pdev->dev, "IRQ: end of tx buffer\n");
dev_dbg(dev, "IRQ: end of tx buffer\n");
atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX);
if (host->data_size) {
@ -2172,7 +2149,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
}
if (pending & ATMCI_RXBUFF) {
dev_dbg(&host->pdev->dev, "IRQ: rx buffer full\n");
dev_dbg(dev, "IRQ: rx buffer full\n");
atmci_writel(host, ATMCI_IDR, ATMCI_RXBUFF);
atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX);
/*
@ -2188,7 +2165,7 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
atmci_pdc_complete(host);
}
} else if (pending & ATMCI_ENDRX) {
dev_dbg(&host->pdev->dev, "IRQ: end of rx buffer\n");
dev_dbg(dev, "IRQ: end of rx buffer\n");
atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX);
if (host->data_size) {
@ -2205,19 +2182,19 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
* The appropriate workaround is to use the BLKE signal.
*/
if (pending & ATMCI_BLKE) {
dev_dbg(&host->pdev->dev, "IRQ: blke\n");
dev_dbg(dev, "IRQ: blke\n");
atmci_writel(host, ATMCI_IDR, ATMCI_BLKE);
smp_wmb();
dev_dbg(&host->pdev->dev, "set pending notbusy\n");
dev_dbg(dev, "set pending notbusy\n");
atmci_set_pending(host, EVENT_NOTBUSY);
tasklet_schedule(&host->tasklet);
}
if (pending & ATMCI_NOTBUSY) {
dev_dbg(&host->pdev->dev, "IRQ: not_busy\n");
dev_dbg(dev, "IRQ: not_busy\n");
atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY);
smp_wmb();
dev_dbg(&host->pdev->dev, "set pending notbusy\n");
dev_dbg(dev, "set pending notbusy\n");
atmci_set_pending(host, EVENT_NOTBUSY);
tasklet_schedule(&host->tasklet);
}
@ -2228,11 +2205,11 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
atmci_write_data_pio(host);
if (pending & ATMCI_CMDRDY) {
dev_dbg(&host->pdev->dev, "IRQ: cmd ready\n");
dev_dbg(dev, "IRQ: cmd ready\n");
atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY);
host->cmd_status = status;
smp_wmb();
dev_dbg(&host->pdev->dev, "set pending cmd rdy\n");
dev_dbg(dev, "set pending cmd rdy\n");
atmci_set_pending(host, EVENT_CMD_RDY);
tasklet_schedule(&host->tasklet);
}
@ -2264,11 +2241,12 @@ static int atmci_init_slot(struct atmel_mci *host,
struct mci_slot_pdata *slot_data, unsigned int id,
u32 sdc_reg, u32 sdio_irq)
{
struct device *dev = host->dev;
struct mmc_host *mmc;
struct atmel_mci_slot *slot;
int ret;
mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), &host->pdev->dev);
mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), dev);
if (!mmc)
return -ENOMEM;
@ -2387,29 +2365,13 @@ static void atmci_cleanup_slot(struct atmel_mci_slot *slot,
static int atmci_configure_dma(struct atmel_mci *host)
{
host->dma.chan = dma_request_chan(&host->pdev->dev, "rxtx");
if (PTR_ERR(host->dma.chan) == -ENODEV) {
struct mci_platform_data *pdata = host->pdev->dev.platform_data;
dma_cap_mask_t mask;
if (!pdata || !pdata->dma_filter)
return -ENODEV;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
host->dma.chan = dma_request_channel(mask, pdata->dma_filter,
pdata->dma_slave);
if (!host->dma.chan)
host->dma.chan = ERR_PTR(-ENODEV);
}
struct device *dev = host->dev;
host->dma.chan = dma_request_chan(dev, "rxtx");
if (IS_ERR(host->dma.chan))
return PTR_ERR(host->dma.chan);
dev_info(&host->pdev->dev, "using %s for DMA transfers\n",
dma_chan_name(host->dma.chan));
dev_info(dev, "using %s for DMA transfers\n", dma_chan_name(host->dma.chan));
host->dma_conf.src_addr = host->mapbase + ATMCI_RDR;
host->dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
@ -2429,11 +2391,11 @@ static int atmci_configure_dma(struct atmel_mci *host)
*/
static void atmci_get_cap(struct atmel_mci *host)
{
struct device *dev = host->dev;
unsigned int version;
version = atmci_get_version(host);
dev_info(&host->pdev->dev,
"version: 0x%x\n", version);
dev_info(dev, "version: 0x%x\n", version);
host->caps.has_dma_conf_reg = false;
host->caps.has_pdc = true;
@ -2474,15 +2436,14 @@ static void atmci_get_cap(struct atmel_mci *host)
break;
default:
host->caps.has_pdc = false;
dev_warn(&host->pdev->dev,
"Unmanaged mci version, set minimum capabilities\n");
dev_warn(dev, "Unmanaged mci version, set minimum capabilities\n");
break;
}
}
static int atmci_probe(struct platform_device *pdev)
{
struct mci_platform_data *pdata;
struct device *dev = &pdev->dev;
struct atmel_mci *host;
struct resource *regs;
unsigned int nr_slots;
@ -2492,32 +2453,28 @@ static int atmci_probe(struct platform_device *pdev)
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs)
return -ENXIO;
pdata = pdev->dev.platform_data;
if (!pdata) {
pdata = atmci_of_init(pdev);
if (IS_ERR(pdata)) {
dev_err(&pdev->dev, "platform data not available\n");
return PTR_ERR(pdata);
}
}
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
if (!host)
return -ENOMEM;
host->pdev = pdev;
host->dev = dev;
spin_lock_init(&host->lock);
INIT_LIST_HEAD(&host->queue);
host->mck = devm_clk_get(&pdev->dev, "mci_clk");
ret = atmci_of_init(host);
if (ret)
return dev_err_probe(dev, ret, "Slot information not available\n");
host->mck = devm_clk_get(dev, "mci_clk");
if (IS_ERR(host->mck))
return PTR_ERR(host->mck);
host->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
host->regs = devm_ioremap(dev, regs->start, resource_size(regs));
if (!host->regs)
return -ENOMEM;
@ -2532,7 +2489,7 @@ static int atmci_probe(struct platform_device *pdev)
tasklet_setup(&host->tasklet, atmci_tasklet_func);
ret = request_irq(irq, atmci_interrupt, 0, dev_name(&pdev->dev), host);
ret = request_irq(irq, atmci_interrupt, 0, dev_name(dev), host);
if (ret) {
clk_disable_unprepare(host->mck);
return ret;
@ -2548,12 +2505,12 @@ static int atmci_probe(struct platform_device *pdev)
host->submit_data = &atmci_submit_data_dma;
host->stop_transfer = &atmci_stop_transfer_dma;
} else if (host->caps.has_pdc) {
dev_info(&pdev->dev, "using PDC\n");
dev_info(dev, "using PDC\n");
host->prepare_data = &atmci_prepare_data_pdc;
host->submit_data = &atmci_submit_data_pdc;
host->stop_transfer = &atmci_stop_transfer_pdc;
} else {
dev_info(&pdev->dev, "using PIO\n");
dev_info(dev, "using PIO\n");
host->prepare_data = &atmci_prepare_data;
host->submit_data = &atmci_submit_data;
host->stop_transfer = &atmci_stop_transfer;
@ -2563,25 +2520,25 @@ static int atmci_probe(struct platform_device *pdev)
timer_setup(&host->timer, atmci_timeout_timer, 0);
pm_runtime_get_noresume(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_DELAY);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_enable(&pdev->dev);
pm_runtime_get_noresume(dev);
pm_runtime_set_active(dev);
pm_runtime_set_autosuspend_delay(dev, AUTOSUSPEND_DELAY);
pm_runtime_use_autosuspend(dev);
pm_runtime_enable(dev);
/* We need at least one slot to succeed */
nr_slots = 0;
ret = -ENODEV;
if (pdata->slot[0].bus_width) {
ret = atmci_init_slot(host, &pdata->slot[0],
if (host->pdata[0].bus_width) {
ret = atmci_init_slot(host, &host->pdata[0],
0, ATMCI_SDCSEL_SLOT_A, ATMCI_SDIOIRQA);
if (!ret) {
nr_slots++;
host->buf_size = host->slot[0]->mmc->max_req_size;
}
}
if (pdata->slot[1].bus_width) {
ret = atmci_init_slot(host, &pdata->slot[1],
if (host->pdata[1].bus_width) {
ret = atmci_init_slot(host, &host->pdata[1],
1, ATMCI_SDCSEL_SLOT_B, ATMCI_SDIOIRQB);
if (!ret) {
nr_slots++;
@ -2592,27 +2549,25 @@ static int atmci_probe(struct platform_device *pdev)
}
if (!nr_slots) {
dev_err(&pdev->dev, "init failed: no slot defined\n");
dev_err_probe(dev, ret, "init failed: no slot defined\n");
goto err_init_slot;
}
if (!host->caps.has_rwproof) {
host->buffer = dma_alloc_coherent(&pdev->dev, host->buf_size,
host->buffer = dma_alloc_coherent(dev, host->buf_size,
&host->buf_phys_addr,
GFP_KERNEL);
if (!host->buffer) {
ret = -ENOMEM;
dev_err(&pdev->dev, "buffer allocation failed\n");
ret = dev_err_probe(dev, -ENOMEM, "buffer allocation failed\n");
goto err_dma_alloc;
}
}
dev_info(&pdev->dev,
"Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
host->mapbase, irq, nr_slots);
dev_info(dev, "Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
host->mapbase, irq, nr_slots);
pm_runtime_mark_last_busy(&host->pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
@ -2624,8 +2579,8 @@ err_dma_alloc:
err_init_slot:
clk_disable_unprepare(host->mck);
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(dev);
pm_runtime_put_noidle(dev);
del_timer_sync(&host->timer);
if (!IS_ERR(host->dma.chan))
@ -2638,13 +2593,13 @@ err_dma_probe_defer:
static void atmci_remove(struct platform_device *pdev)
{
struct atmel_mci *host = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
unsigned int i;
pm_runtime_get_sync(&pdev->dev);
pm_runtime_get_sync(dev);
if (host->buffer)
dma_free_coherent(&pdev->dev, host->buf_size,
host->buffer, host->buf_phys_addr);
dma_free_coherent(dev, host->buf_size, host->buffer, host->buf_phys_addr);
for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
if (host->slot[i])
@ -2663,8 +2618,8 @@ static void atmci_remove(struct platform_device *pdev)
clk_disable_unprepare(host->mck);
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(dev);
pm_runtime_put_noidle(dev);
}
#ifdef CONFIG_PM
@ -2701,7 +2656,7 @@ static struct platform_driver atmci_driver = {
.driver = {
.name = "atmel_mci",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(atmci_dt_ids),
.of_match_table = atmci_dt_ids,
.pm = &atmci_dev_pm_ops,
},
};

View File

@ -474,8 +474,8 @@ static int cqhci_dma_map(struct mmc_host *host, struct mmc_request *mrq)
return sg_count;
}
static void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end,
bool dma64)
void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end,
bool dma64)
{
__le32 *attr = (__le32 __force *)desc;
@ -495,6 +495,7 @@ static void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end,
dataddr[0] = cpu_to_le32(addr);
}
}
EXPORT_SYMBOL(cqhci_set_tran_desc);
static int cqhci_prep_tran_desc(struct mmc_request *mrq,
struct cqhci_host *cq_host, int tag)
@ -522,7 +523,11 @@ static int cqhci_prep_tran_desc(struct mmc_request *mrq,
if ((i+1) == sg_count)
end = true;
cqhci_set_tran_desc(desc, addr, len, end, dma64);
if (cq_host->ops->set_tran_desc)
cq_host->ops->set_tran_desc(cq_host, &desc, addr, len, end, dma64);
else
cqhci_set_tran_desc(desc, addr, len, end, dma64);
desc += cq_host->trans_desc_len;
}

View File

@ -293,6 +293,9 @@ struct cqhci_host_ops {
int (*program_key)(struct cqhci_host *cq_host,
const union cqhci_crypto_cfg_entry *cfg, int slot);
#endif
void (*set_tran_desc)(struct cqhci_host *cq_host, u8 **desc,
dma_addr_t addr, int len, bool end, bool dma64);
};
static inline void cqhci_writel(struct cqhci_host *host, u32 val, int reg)
@ -318,6 +321,7 @@ irqreturn_t cqhci_irq(struct mmc_host *mmc, u32 intmask, int cmd_error,
int cqhci_init(struct cqhci_host *cq_host, struct mmc_host *mmc, bool dma64);
struct cqhci_host *cqhci_pltfm_init(struct platform_device *pdev);
int cqhci_deactivate(struct mmc_host *mmc);
void cqhci_set_tran_desc(u8 *desc, dma_addr_t addr, int len, bool end, bool dma64);
static inline int cqhci_suspend(struct mmc_host *mmc)
{
return cqhci_deactivate(mmc);

View File

@ -1337,7 +1337,7 @@ ioremap_fail:
return ret;
}
static void __exit davinci_mmcsd_remove(struct platform_device *pdev)
static void davinci_mmcsd_remove(struct platform_device *pdev)
{
struct mmc_davinci_host *host = platform_get_drvdata(pdev);
@ -1392,7 +1392,7 @@ static struct platform_driver davinci_mmcsd_driver = {
.of_match_table = davinci_mmc_dt_ids,
},
.probe = davinci_mmcsd_probe,
.remove_new = __exit_p(davinci_mmcsd_remove),
.remove_new = davinci_mmcsd_remove,
.id_table = davinci_mmc_devtype,
};

View File

@ -87,7 +87,6 @@ static int dw_mci_hi3798cv200_execute_tuning(struct dw_mci_slot *slot,
goto tuning_out;
prev_err = err;
err = 0;
}
tuning_out:

View File

@ -133,7 +133,6 @@ static int dw_mci_hi3798mv200_execute_tuning_mix_mode(struct dw_mci_slot *slot,
goto tuning_out;
prev_err = err;
err = 0;
}
tuning_out:

View File

@ -13,7 +13,6 @@
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/pm.h>

View File

@ -589,6 +589,9 @@ static void renesas_sdhi_reset(struct tmio_mmc_host *host, bool preserve)
sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
priv->needs_adjust_hs400 = false;
renesas_sdhi_set_clock(host, host->clk_cache);
/* Ensure default value for this driver. */
renesas_sdhi_sdbuf_width(host, 16);
} else if (priv->scc_ctl) {
renesas_sdhi_scc_reset(host, priv);
}

View File

@ -210,7 +210,7 @@ static const struct renesas_sdhi_quirks sdhi_quirks_r8a77990 = {
.manual_tap_correction = true,
};
static const struct renesas_sdhi_quirks sdhi_quirks_r9a09g011 = {
static const struct renesas_sdhi_quirks sdhi_quirks_rzg2l = {
.fixed_addr_mode = true,
.hs400_disabled = true,
};
@ -255,9 +255,9 @@ static const struct renesas_sdhi_of_data_with_quirks of_r8a77990_compatible = {
.quirks = &sdhi_quirks_r8a77990,
};
static const struct renesas_sdhi_of_data_with_quirks of_r9a09g011_compatible = {
static const struct renesas_sdhi_of_data_with_quirks of_rzg2l_compatible = {
.of_data = &of_data_rcar_gen3,
.quirks = &sdhi_quirks_r9a09g011,
.quirks = &sdhi_quirks_rzg2l,
};
static const struct renesas_sdhi_of_data_with_quirks of_rcar_gen3_compatible = {
@ -283,7 +283,8 @@ static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
{ .compatible = "renesas,sdhi-r8a77970", .data = &of_r8a77970_compatible, },
{ .compatible = "renesas,sdhi-r8a77990", .data = &of_r8a77990_compatible, },
{ .compatible = "renesas,sdhi-r8a77995", .data = &of_rcar_gen3_nohs400_compatible, },
{ .compatible = "renesas,sdhi-r9a09g011", .data = &of_r9a09g011_compatible, },
{ .compatible = "renesas,sdhi-r9a09g011", .data = &of_rzg2l_compatible, },
{ .compatible = "renesas,rzg2l-sdhi", .data = &of_rzg2l_compatible, },
{ .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, },
{ .compatible = "renesas,rcar-gen4-sdhi", .data = &of_rcar_gen3_compatible, },
{},

View File

@ -10,6 +10,7 @@
#include <linux/export.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include <linux/io.h>
@ -80,6 +81,8 @@ struct sdhci_acpi_host {
enum {
DMI_QUIRK_RESET_SD_SIGNAL_VOLT_ON_SUSP = BIT(0),
DMI_QUIRK_SD_NO_WRITE_PROTECT = BIT(1),
DMI_QUIRK_SD_CD_ACTIVE_HIGH = BIT(2),
DMI_QUIRK_SD_CD_ENABLE_PULL_UP = BIT(3),
};
static inline void *sdhci_acpi_priv(struct sdhci_acpi_host *c)
@ -719,7 +722,28 @@ static const struct acpi_device_id sdhci_acpi_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids);
/* Please keep this list sorted alphabetically */
static const struct dmi_system_id sdhci_acpi_quirks[] = {
{
/*
* The Acer Aspire Switch 10 (SW5-012) microSD slot always
* reports the card being write-protected even though microSD
* cards do not have a write-protect switch at all.
*/
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"),
},
.driver_data = (void *)DMI_QUIRK_SD_NO_WRITE_PROTECT,
},
{
/* Asus T100TA, needs pull-up for cd but DSDT GpioInt has NoPull set */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"),
},
.driver_data = (void *)DMI_QUIRK_SD_CD_ENABLE_PULL_UP,
},
{
/*
* The Lenovo Miix 320-10ICR has a bug in the _PS0 method of
@ -736,15 +760,23 @@ static const struct dmi_system_id sdhci_acpi_quirks[] = {
},
{
/*
* The Acer Aspire Switch 10 (SW5-012) microSD slot always
* reports the card being write-protected even though microSD
* cards do not have a write-protect switch at all.
* Lenovo Yoga Tablet 2 Pro 1380F/L (13" Android version) this
* has broken WP reporting and an inverted CD signal.
* Note this has more or less the same BIOS as the Lenovo Yoga
* Tablet 2 830F/L or 1050F/L (8" and 10" Android), but unlike
* the 830 / 1050 models which share the same mainboard this
* model has a different mainboard and the inverted CD and
* broken WP are unique to this board.
*/
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"),
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."),
DMI_MATCH(DMI_PRODUCT_NAME, "VALLEYVIEW C0 PLATFORM"),
DMI_MATCH(DMI_BOARD_NAME, "BYT-T FFD8"),
/* Full match so as to NOT match the 830/1050 BIOS */
DMI_MATCH(DMI_BIOS_VERSION, "BLADE_21.X64.0005.R00.1504101516"),
},
.driver_data = (void *)DMI_QUIRK_SD_NO_WRITE_PROTECT,
.driver_data = (void *)(DMI_QUIRK_SD_NO_WRITE_PROTECT |
DMI_QUIRK_SD_CD_ACTIVE_HIGH),
},
{
/*
@ -757,6 +789,17 @@ static const struct dmi_system_id sdhci_acpi_quirks[] = {
},
.driver_data = (void *)DMI_QUIRK_SD_NO_WRITE_PROTECT,
},
{
/*
* The Toshiba WT10-A's microSD slot always reports the card being
* write-protected.
*/
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_PRODUCT_NAME, "TOSHIBA WT10-A"),
},
.driver_data = (void *)DMI_QUIRK_SD_NO_WRITE_PROTECT,
},
{} /* Terminating entry */
};
@ -866,12 +909,18 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
if (sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD)) {
bool v = sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL);
if (quirks & DMI_QUIRK_SD_CD_ACTIVE_HIGH)
host->mmc->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
err = mmc_gpiod_request_cd(host->mmc, NULL, 0, v, 0);
if (err) {
if (err == -EPROBE_DEFER)
goto err_free;
dev_warn(dev, "failed to setup card detect gpio\n");
c->use_runtime_pm = false;
} else if (quirks & DMI_QUIRK_SD_CD_ENABLE_PULL_UP) {
mmc_gpiod_set_cd_config(host->mmc,
PIN_CONF_PACKED(PIN_CONFIG_BIAS_PULL_UP, 20000));
}
if (quirks & DMI_QUIRK_RESET_SD_SIGNAL_VOLT_ON_SUSP)

View File

@ -335,7 +335,7 @@ static void esdhc_mcf_copy_to_bounce_buffer(struct sdhci_host *host,
data->blksz * data->blocks);
}
static struct sdhci_ops sdhci_esdhc_ops = {
static const struct sdhci_ops sdhci_esdhc_ops = {
.reset = esdhc_mcf_reset,
.set_clock = esdhc_mcf_pltfm_set_clock,
.get_max_clock = esdhc_mcf_pltfm_get_max_clock,

View File

@ -21,6 +21,7 @@
#include <linux/sizes.h>
#include "sdhci-pltfm.h"
#include "cqhci.h"
#define SDHCI_DWCMSHC_ARG2_STUFF GENMASK(31, 16)
@ -52,6 +53,9 @@
#define AT_CTRL_SWIN_TH_VAL_MASK GENMASK(31, 24) /* bits [31:24] */
#define AT_CTRL_SWIN_TH_VAL 0x9 /* sampling window threshold */
/* DWC IP vendor area 2 pointer */
#define DWCMSHC_P_VENDOR_AREA2 0xea
/* Sophgo CV18XX specific Registers */
#define CV18XX_SDHCI_MSHC_CTRL 0x00
#define CV18XX_EMMC_FUNC_EN BIT(0)
@ -66,6 +70,10 @@
#define CV18XX_SDHCI_PHY_CONFIG 0x4c
#define CV18XX_PHY_TX_BPS BIT(0)
#define CV18XX_TUNE_MAX 128
#define CV18XX_TUNE_STEP 1
#define CV18XX_RETRY_TUNING_MAX 50
/* Rockchip specific Registers */
#define DWCMSHC_EMMC_DLL_CTRL 0x800
#define DWCMSHC_EMMC_DLL_RXCLK 0x804
@ -181,6 +189,10 @@
#define BOUNDARY_OK(addr, len) \
((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1)))
#define DWCMSHC_SDHCI_CQE_TRNS_MODE (SDHCI_TRNS_MULTI | \
SDHCI_TRNS_BLK_CNT_EN | \
SDHCI_TRNS_DMA)
enum dwcmshc_rk_type {
DWCMSHC_RK3568,
DWCMSHC_RK3588,
@ -196,7 +208,9 @@ struct rk35xx_priv {
struct dwcmshc_priv {
struct clk *bus_clk;
int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA reg */
int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA1 reg */
int vendor_specific_area2; /* P_VENDOR_SPECIFIC_AREA2 reg */
void *priv; /* pointer to SoC private stuff */
u16 delay_line;
u16 flags;
@ -455,6 +469,90 @@ static void dwcmshc_hs400_enhanced_strobe(struct mmc_host *mmc,
sdhci_writel(host, vendor, reg);
}
static int dwcmshc_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
int err = sdhci_execute_tuning(mmc, opcode);
struct sdhci_host *host = mmc_priv(mmc);
if (err)
return err;
/*
* Tuning can leave the IP in an active state (Buffer Read Enable bit
* set) which prevents the entry to low power states (i.e. S0i3). Data
* reset will clear it.
*/
sdhci_reset(host, SDHCI_RESET_DATA);
return 0;
}
static u32 dwcmshc_cqe_irq_handler(struct sdhci_host *host, u32 intmask)
{
int cmd_error = 0;
int data_error = 0;
if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error))
return intmask;
cqhci_irq(host->mmc, intmask, cmd_error, data_error);
return 0;
}
static void dwcmshc_sdhci_cqe_enable(struct mmc_host *mmc)
{
struct sdhci_host *host = mmc_priv(mmc);
u8 ctrl;
sdhci_writew(host, DWCMSHC_SDHCI_CQE_TRNS_MODE, SDHCI_TRANSFER_MODE);
sdhci_cqe_enable(mmc);
/*
* The "DesignWare Cores Mobile Storage Host Controller
* DWC_mshc / DWC_mshc_lite Databook" says:
* when Host Version 4 Enable" is 1 in Host Control 2 register,
* SDHCI_CTRL_ADMA32 bit means ADMA2 is selected.
* Selection of 32-bit/64-bit System Addressing:
* either 32-bit or 64-bit system addressing is selected by
* 64-bit Addressing bit in Host Control 2 register.
*
* On the other hand the "DesignWare Cores Mobile Storage Host
* Controller DWC_mshc / DWC_mshc_lite User Guide" says, that we have to
* set DMA_SEL to ADMA2 _only_ mode in the Host Control 2 register.
*/
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
ctrl &= ~SDHCI_CTRL_DMA_MASK;
ctrl |= SDHCI_CTRL_ADMA32;
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}
static void dwcmshc_set_tran_desc(struct cqhci_host *cq_host, u8 **desc,
dma_addr_t addr, int len, bool end, bool dma64)
{
int tmplen, offset;
if (likely(!len || BOUNDARY_OK(addr, len))) {
cqhci_set_tran_desc(*desc, addr, len, end, dma64);
return;
}
offset = addr & (SZ_128M - 1);
tmplen = SZ_128M - offset;
cqhci_set_tran_desc(*desc, addr, tmplen, false, dma64);
addr += tmplen;
len -= tmplen;
*desc += cq_host->trans_desc_len;
cqhci_set_tran_desc(*desc, addr, len, end, dma64);
}
static void dwcmshc_cqhci_dumpregs(struct mmc_host *mmc)
{
sdhci_dumpregs(mmc_priv(mmc));
}
static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@ -686,6 +784,113 @@ static void cv18xx_sdhci_reset(struct sdhci_host *host, u8 mask)
sdhci_writel(host, val, priv->vendor_specific_area1 + CV18XX_SDHCI_PHY_TX_RX_DLY);
}
static void cv18xx_sdhci_set_tap(struct sdhci_host *host, int tap)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
u16 clk;
u32 val;
clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
clk &= ~SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
val = sdhci_readl(host, priv->vendor_specific_area1 + CV18XX_SDHCI_MSHC_CTRL);
val &= ~CV18XX_LATANCY_1T;
sdhci_writel(host, val, priv->vendor_specific_area1 + CV18XX_SDHCI_MSHC_CTRL);
val = (FIELD_PREP(CV18XX_PHY_TX_DLY_MSK, 0) |
FIELD_PREP(CV18XX_PHY_TX_SRC_MSK, CV18XX_PHY_TX_SRC_INVERT_CLK_TX) |
FIELD_PREP(CV18XX_PHY_RX_DLY_MSK, tap));
sdhci_writel(host, val, priv->vendor_specific_area1 + CV18XX_SDHCI_PHY_TX_RX_DLY);
sdhci_writel(host, 0, priv->vendor_specific_area1 + CV18XX_SDHCI_PHY_CONFIG);
clk |= SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
usleep_range(1000, 2000);
}
static int cv18xx_retry_tuning(struct mmc_host *mmc, u32 opcode, int *cmd_error)
{
int ret, retry = 0;
while (retry < CV18XX_RETRY_TUNING_MAX) {
ret = mmc_send_tuning(mmc, opcode, NULL);
if (ret)
return ret;
retry++;
}
return 0;
}
static void cv18xx_sdhci_post_tuning(struct sdhci_host *host)
{
u32 val;
val = sdhci_readl(host, SDHCI_INT_STATUS);
val |= SDHCI_INT_DATA_AVAIL;
sdhci_writel(host, val, SDHCI_INT_STATUS);
sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
}
static int cv18xx_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
{
int min, max, avg, ret;
int win_length, target_min, target_max, target_win_length;
min = max = 0;
target_win_length = 0;
sdhci_reset_tuning(host);
while (max < CV18XX_TUNE_MAX) {
/* find the mininum delay first which can pass tuning */
while (min < CV18XX_TUNE_MAX) {
cv18xx_sdhci_set_tap(host, min);
if (!cv18xx_retry_tuning(host->mmc, opcode, NULL))
break;
min += CV18XX_TUNE_STEP;
}
/* find the maxinum delay which can not pass tuning */
max = min + CV18XX_TUNE_STEP;
while (max < CV18XX_TUNE_MAX) {
cv18xx_sdhci_set_tap(host, max);
if (cv18xx_retry_tuning(host->mmc, opcode, NULL)) {
max -= CV18XX_TUNE_STEP;
break;
}
max += CV18XX_TUNE_STEP;
}
win_length = max - min + 1;
/* get the largest pass window */
if (win_length > target_win_length) {
target_win_length = win_length;
target_min = min;
target_max = max;
}
/* continue to find the next pass window */
min = max + CV18XX_TUNE_STEP;
}
cv18xx_sdhci_post_tuning(host);
/* use average delay to get the best timing */
avg = (target_min + target_max) / 2;
cv18xx_sdhci_set_tap(host, avg);
ret = mmc_send_tuning(host->mmc, opcode, NULL);
dev_dbg(mmc_dev(host->mmc), "tuning %s at 0x%x ret %d\n",
ret ? "failed" : "passed", avg, ret);
return ret;
}
static const struct sdhci_ops sdhci_dwcmshc_ops = {
.set_clock = sdhci_set_clock,
.set_bus_width = sdhci_set_bus_width,
@ -693,6 +898,7 @@ static const struct sdhci_ops sdhci_dwcmshc_ops = {
.get_max_clock = dwcmshc_get_max_clock,
.reset = sdhci_reset,
.adma_write_desc = dwcmshc_adma_write_desc,
.irq = dwcmshc_cqe_irq_handler,
};
static const struct sdhci_ops sdhci_dwcmshc_rk35xx_ops = {
@ -712,7 +918,7 @@ static const struct sdhci_ops sdhci_dwcmshc_th1520_ops = {
.reset = th1520_sdhci_reset,
.adma_write_desc = dwcmshc_adma_write_desc,
.voltage_switch = dwcmshc_phy_1_8v_init,
.platform_execute_tuning = &th1520_execute_tuning,
.platform_execute_tuning = th1520_execute_tuning,
};
static const struct sdhci_ops sdhci_dwcmshc_cv18xx_ops = {
@ -722,6 +928,7 @@ static const struct sdhci_ops sdhci_dwcmshc_cv18xx_ops = {
.get_max_clock = dwcmshc_get_max_clock,
.reset = cv18xx_sdhci_reset,
.adma_write_desc = dwcmshc_adma_write_desc,
.platform_execute_tuning = cv18xx_sdhci_execute_tuning,
};
static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = {
@ -759,6 +966,73 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_cv18xx_pdata = {
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
};
static const struct cqhci_host_ops dwcmshc_cqhci_ops = {
.enable = dwcmshc_sdhci_cqe_enable,
.disable = sdhci_cqe_disable,
.dumpregs = dwcmshc_cqhci_dumpregs,
.set_tran_desc = dwcmshc_set_tran_desc,
};
static void dwcmshc_cqhci_init(struct sdhci_host *host, struct platform_device *pdev)
{
struct cqhci_host *cq_host;
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
bool dma64 = false;
u16 clk;
int err;
host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD;
cq_host = devm_kzalloc(&pdev->dev, sizeof(*cq_host), GFP_KERNEL);
if (!cq_host) {
dev_err(mmc_dev(host->mmc), "Unable to setup CQE: not enough memory\n");
goto dsbl_cqe_caps;
}
/*
* For dwcmshc host controller we have to enable internal clock
* before access to some registers from Vendor Specific Area 2.
*/
clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
clk |= SDHCI_CLOCK_INT_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
if (!(clk & SDHCI_CLOCK_INT_EN)) {
dev_err(mmc_dev(host->mmc), "Unable to setup CQE: internal clock enable error\n");
goto free_cq_host;
}
cq_host->mmio = host->ioaddr + priv->vendor_specific_area2;
cq_host->ops = &dwcmshc_cqhci_ops;
/* Enable using of 128-bit task descriptors */
dma64 = host->flags & SDHCI_USE_64_BIT_DMA;
if (dma64) {
dev_dbg(mmc_dev(host->mmc), "128-bit task descriptors\n");
cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
}
err = cqhci_init(cq_host, host->mmc, dma64);
if (err) {
dev_err(mmc_dev(host->mmc), "Unable to setup CQE: error %d\n", err);
goto int_clock_disable;
}
dev_dbg(mmc_dev(host->mmc), "CQE init done\n");
return;
int_clock_disable:
clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
clk &= ~SDHCI_CLOCK_INT_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
free_cq_host:
devm_kfree(&pdev->dev, cq_host);
dsbl_cqe_caps:
host->mmc->caps2 &= ~(MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD);
}
static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)
{
int err;
@ -863,7 +1137,7 @@ static int dwcmshc_probe(struct platform_device *pdev)
struct rk35xx_priv *rk_priv = NULL;
const struct sdhci_pltfm_data *pltfm_data;
int err;
u32 extra;
u32 extra, caps;
pltfm_data = device_get_match_data(&pdev->dev);
if (!pltfm_data) {
@ -914,6 +1188,7 @@ static int dwcmshc_probe(struct platform_device *pdev)
host->mmc_host_ops.request = dwcmshc_request;
host->mmc_host_ops.hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe;
host->mmc_host_ops.execute_tuning = dwcmshc_execute_tuning;
if (pltfm_data == &sdhci_dwcmshc_rk35xx_pdata) {
rk_priv = devm_kzalloc(&pdev->dev, sizeof(struct rk35xx_priv), GFP_KERNEL);
@ -963,6 +1238,10 @@ static int dwcmshc_probe(struct platform_device *pdev)
sdhci_enable_v4_mode(host);
#endif
caps = sdhci_readl(host, SDHCI_CAPABILITIES);
if (caps & SDHCI_CAN_64BIT_V4)
sdhci_enable_v4_mode(host);
host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
pm_runtime_get_noresume(dev);
@ -973,6 +1252,14 @@ static int dwcmshc_probe(struct platform_device *pdev)
if (err)
goto err_rpm;
/* Setup Command Queue Engine if enabled */
if (device_property_read_bool(&pdev->dev, "supports-cqe")) {
priv->vendor_specific_area2 =
sdhci_readw(host, DWCMSHC_P_VENDOR_AREA2);
dwcmshc_cqhci_init(host, pdev);
}
if (rk_priv)
dwcmshc_rk35xx_postinit(host, priv);
@ -1045,6 +1332,12 @@ static int dwcmshc_suspend(struct device *dev)
pm_runtime_resume(dev);
if (host->mmc->caps2 & MMC_CAP2_CQE) {
ret = cqhci_suspend(host->mmc);
if (ret)
return ret;
}
ret = sdhci_suspend_host(host);
if (ret)
return ret;
@ -1089,6 +1382,12 @@ static int dwcmshc_resume(struct device *dev)
if (ret)
goto disable_rockchip_clks;
if (host->mmc->caps2 & MMC_CAP2_CQE) {
ret = cqhci_resume(host->mmc);
if (ret)
goto disable_rockchip_clks;
}
return 0;
disable_rockchip_clks:

View File

@ -925,7 +925,7 @@ static void sdhci_omap_set_timeout(struct sdhci_host *host,
__sdhci_set_timeout(host, cmd);
}
static struct sdhci_ops sdhci_omap_ops = {
static const struct sdhci_ops sdhci_omap_ops = {
.set_clock = sdhci_omap_set_clock,
.set_power = sdhci_omap_set_power,
.enable_dma = sdhci_omap_enable_dma,

View File

@ -25,12 +25,6 @@
#define GLI_9750_WT_EN_ON 0x1
#define GLI_9750_WT_EN_OFF 0x0
#define PCI_GLI_9750_PM_CTRL 0xFC
#define PCI_GLI_9750_PM_STATE GENMASK(1, 0)
#define PCI_GLI_9750_CORRERR_MASK 0x214
#define PCI_GLI_9750_CORRERR_MASK_REPLAY_TIMER_TIMEOUT BIT(12)
#define SDHCI_GLI_9750_CFG2 0x848
#define SDHCI_GLI_9750_CFG2_L1DLY GENMASK(28, 24)
#define GLI_9750_CFG2_L1DLY_VALUE 0x1F
@ -152,12 +146,6 @@
#define PCI_GLI_9755_MISC 0x78
#define PCI_GLI_9755_MISC_SSC_OFF BIT(26)
#define PCI_GLI_9755_PM_CTRL 0xFC
#define PCI_GLI_9755_PM_STATE GENMASK(1, 0)
#define PCI_GLI_9755_CORRERR_MASK 0x214
#define PCI_GLI_9755_CORRERR_MASK_REPLAY_TIMER_TIMEOUT BIT(12)
#define SDHCI_GLI_9767_GM_BURST_SIZE 0x510
#define SDHCI_GLI_9767_GM_BURST_SIZE_AXI_ALWAYS_SET BIT(8)
@ -547,6 +535,7 @@ static void gl9750_hw_setting(struct sdhci_host *host)
{
struct sdhci_pci_slot *slot = sdhci_priv(host);
struct pci_dev *pdev;
int aer;
u32 value;
pdev = slot->chip->pdev;
@ -561,16 +550,16 @@ static void gl9750_hw_setting(struct sdhci_host *host)
sdhci_writel(host, value, SDHCI_GLI_9750_CFG2);
/* toggle PM state to allow GL9750 to enter ASPM L1.2 */
pci_read_config_dword(pdev, PCI_GLI_9750_PM_CTRL, &value);
value |= PCI_GLI_9750_PM_STATE;
pci_write_config_dword(pdev, PCI_GLI_9750_PM_CTRL, value);
value &= ~PCI_GLI_9750_PM_STATE;
pci_write_config_dword(pdev, PCI_GLI_9750_PM_CTRL, value);
pci_set_power_state(pdev, PCI_D3hot);
pci_set_power_state(pdev, PCI_D0);
/* mask the replay timer timeout of AER */
pci_read_config_dword(pdev, PCI_GLI_9750_CORRERR_MASK, &value);
value |= PCI_GLI_9750_CORRERR_MASK_REPLAY_TIMER_TIMEOUT;
pci_write_config_dword(pdev, PCI_GLI_9750_CORRERR_MASK, value);
aer = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
if (aer) {
pci_read_config_dword(pdev, aer + PCI_ERR_COR_MASK, &value);
value |= PCI_ERR_COR_REP_TIMER;
pci_write_config_dword(pdev, aer + PCI_ERR_COR_MASK, value);
}
gl9750_wt_off(host);
}
@ -745,6 +734,7 @@ static void sdhci_gl9755_set_clock(struct sdhci_host *host, unsigned int clock)
static void gl9755_hw_setting(struct sdhci_pci_slot *slot)
{
struct pci_dev *pdev = slot->chip->pdev;
int aer;
u32 value;
gl9755_wt_on(pdev);
@ -775,16 +765,16 @@ static void gl9755_hw_setting(struct sdhci_pci_slot *slot)
pci_write_config_dword(pdev, PCI_GLI_9755_CFG2, value);
/* toggle PM state to allow GL9755 to enter ASPM L1.2 */
pci_read_config_dword(pdev, PCI_GLI_9755_PM_CTRL, &value);
value |= PCI_GLI_9755_PM_STATE;
pci_write_config_dword(pdev, PCI_GLI_9755_PM_CTRL, value);
value &= ~PCI_GLI_9755_PM_STATE;
pci_write_config_dword(pdev, PCI_GLI_9755_PM_CTRL, value);
pci_set_power_state(pdev, PCI_D3hot);
pci_set_power_state(pdev, PCI_D0);
/* mask the replay timer timeout of AER */
pci_read_config_dword(pdev, PCI_GLI_9755_CORRERR_MASK, &value);
value |= PCI_GLI_9755_CORRERR_MASK_REPLAY_TIMER_TIMEOUT;
pci_write_config_dword(pdev, PCI_GLI_9755_CORRERR_MASK, value);
aer = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
if (aer) {
pci_read_config_dword(pdev, aer + PCI_ERR_COR_MASK, &value);
value |= PCI_ERR_COR_REP_TIMER;
pci_write_config_dword(pdev, aer + PCI_ERR_COR_MASK, value);
}
gl9755_wt_off(pdev);
}

View File

@ -17,10 +17,8 @@
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
@ -132,14 +130,16 @@ struct sdhci_s3c {
* struct sdhci_s3c_drv_data - S3C SDHCI platform specific driver data
* @sdhci_quirks: sdhci host specific quirks.
* @no_divider: no or non-standard internal clock divider.
* @ops: sdhci_ops to use for this variant
*
* Specifies platform specific configuration of sdhci controller.
* Note: A structure for driver specific platform data is used for future
* expansion of its usage.
*/
struct sdhci_s3c_drv_data {
unsigned int sdhci_quirks;
bool no_divider;
unsigned int sdhci_quirks;
bool no_divider;
const struct sdhci_ops *ops;
};
static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host)
@ -414,7 +414,7 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
}
static struct sdhci_ops sdhci_s3c_ops = {
static const struct sdhci_ops sdhci_s3c_ops_s3c6410 = {
.get_max_clock = sdhci_s3c_get_max_clk,
.set_clock = sdhci_s3c_set_clock,
.get_min_clock = sdhci_s3c_get_min_clock,
@ -423,6 +423,15 @@ static struct sdhci_ops sdhci_s3c_ops = {
.set_uhs_signaling = sdhci_set_uhs_signaling,
};
static const struct sdhci_ops sdhci_s3c_ops_exynos4 __maybe_unused = {
.get_max_clock = sdhci_cmu_get_max_clock,
.set_clock = sdhci_cmu_set_clock,
.get_min_clock = sdhci_cmu_get_min_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
};
#ifdef CONFIG_OF
static int sdhci_s3c_parse_dt(struct device *dev,
struct sdhci_host *host, struct s3c_sdhci_platdata *pdata)
@ -446,7 +455,7 @@ static int sdhci_s3c_parse_dt(struct device *dev,
return 0;
}
if (of_get_named_gpio(node, "cd-gpios", 0))
if (of_property_present(node, "cd-gpios"))
return 0;
/* assuming internal card detect that will be configured by pinctrl */
@ -562,7 +571,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
pdata->cfg_gpio(pdev, pdata->max_width);
host->hw_name = "samsung-hsmmc";
host->ops = &sdhci_s3c_ops;
host->ops = &sdhci_s3c_ops_s3c6410;
host->quirks = 0;
host->quirks2 = 0;
host->irq = irq;
@ -572,6 +581,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT;
if (drv_data) {
host->quirks |= drv_data->sdhci_quirks;
host->ops = drv_data->ops;
sc->no_divider = drv_data->no_divider;
}
@ -619,16 +629,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
/* HSMMC on Samsung SoCs uses SDCLK as timeout clock */
host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK;
/*
* If controller does not have internal clock divider,
* we can use overriding functions instead of default.
*/
if (sc->no_divider) {
sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock;
sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock;
sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock;
}
/* It supports additional host capabilities if needed */
if (pdata->host_caps)
host->mmc->caps |= pdata->host_caps;
@ -760,6 +760,7 @@ MODULE_DEVICE_TABLE(platform, sdhci_s3c_driver_ids);
#ifdef CONFIG_OF
static const struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = {
.no_divider = true,
.ops = &sdhci_s3c_ops_exynos4,
};
static const struct of_device_id sdhci_s3c_dt_match[] = {

View File

@ -13,7 +13,6 @@
#include <linux/mmc/mmc.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@ -440,7 +439,7 @@ static void sdhci_sprd_set_power(struct sdhci_host *host, unsigned char mode,
}
}
static struct sdhci_ops sdhci_sprd_ops = {
static const struct sdhci_ops sdhci_sprd_ops = {
.read_l = sdhci_sprd_readl,
.write_l = sdhci_sprd_writel,
.write_w = sdhci_sprd_writew,

View File

@ -3439,12 +3439,18 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
host->data->error = -EILSEQ;
if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
sdhci_err_stats_inc(host, DAT_CRC);
} else if ((intmask & SDHCI_INT_DATA_CRC) &&
} else if ((intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_TUNING_ERROR)) &&
SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))
!= MMC_BUS_TEST_R) {
host->data->error = -EILSEQ;
if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
sdhci_err_stats_inc(host, DAT_CRC);
if (intmask & SDHCI_INT_TUNING_ERROR) {
u16 ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
ctrl2 &= ~SDHCI_CTRL_TUNED_CLK;
sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2);
}
} else if (intmask & SDHCI_INT_ADMA_ERROR) {
pr_err("%s: ADMA error: 0x%08x\n", mmc_hostname(host->mmc),
intmask);
@ -3979,7 +3985,7 @@ bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error,
} else
*cmd_error = 0;
if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC)) {
if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC | SDHCI_INT_TUNING_ERROR)) {
*data_error = -EILSEQ;
if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))))
sdhci_err_stats_inc(host, DAT_CRC);

View File

@ -158,6 +158,7 @@
#define SDHCI_INT_BUS_POWER 0x00800000
#define SDHCI_INT_AUTO_CMD_ERR 0x01000000
#define SDHCI_INT_ADMA_ERROR 0x02000000
#define SDHCI_INT_TUNING_ERROR 0x04000000
#define SDHCI_INT_NORMAL_MASK 0x00007FFF
#define SDHCI_INT_ERROR_MASK 0xFFFF8000
@ -169,7 +170,7 @@
SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR | \
SDHCI_INT_BLK_GAP)
SDHCI_INT_BLK_GAP | SDHCI_INT_TUNING_ERROR)
#define SDHCI_INT_ALL_MASK ((unsigned int)-1)
#define SDHCI_CQE_INT_ERR_MASK ( \

View File

@ -141,18 +141,26 @@ static const struct timing_data td[] = {
struct sdhci_am654_data {
struct regmap *base;
int otap_del_sel[ARRAY_SIZE(td)];
int itap_del_sel[ARRAY_SIZE(td)];
u32 otap_del_sel[ARRAY_SIZE(td)];
u32 itap_del_sel[ARRAY_SIZE(td)];
u32 itap_del_ena[ARRAY_SIZE(td)];
int clkbuf_sel;
int trm_icp;
int drv_strength;
int strb_sel;
u32 flags;
u32 quirks;
bool dll_enable;
#define SDHCI_AM654_QUIRK_FORCE_CDTEST BIT(0)
};
struct window {
u8 start;
u8 end;
u8 length;
};
struct sdhci_am654_driver_data {
const struct sdhci_pltfm_data *pdata;
u32 flags;
@ -232,11 +240,13 @@ static void sdhci_am654_setup_dll(struct sdhci_host *host, unsigned int clock)
}
static void sdhci_am654_write_itapdly(struct sdhci_am654_data *sdhci_am654,
u32 itapdly)
u32 itapdly, u32 enable)
{
/* Set ITAPCHGWIN before writing to ITAPDLY */
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK,
1 << ITAPCHGWIN_SHIFT);
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPDLYENA_MASK,
enable << ITAPDLYENA_SHIFT);
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPDLYSEL_MASK,
itapdly << ITAPDLYSEL_SHIFT);
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0);
@ -253,8 +263,8 @@ static void sdhci_am654_setup_delay_chain(struct sdhci_am654_data *sdhci_am654,
mask = SELDLYTXCLK_MASK | SELDLYRXCLK_MASK;
regmap_update_bits(sdhci_am654->base, PHY_CTRL5, mask, val);
sdhci_am654_write_itapdly(sdhci_am654,
sdhci_am654->itap_del_sel[timing]);
sdhci_am654_write_itapdly(sdhci_am654, sdhci_am654->itap_del_sel[timing],
sdhci_am654->itap_del_ena[timing]);
}
static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
@ -263,19 +273,17 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
unsigned char timing = host->mmc->ios.timing;
u32 otap_del_sel;
u32 otap_del_ena;
u32 mask, val;
regmap_update_bits(sdhci_am654->base, PHY_CTRL1, ENDLL_MASK, 0);
sdhci_set_clock(host, clock);
/* Setup DLL Output TAP delay */
/* Setup Output TAP delay */
otap_del_sel = sdhci_am654->otap_del_sel[timing];
otap_del_ena = (timing > MMC_TIMING_UHS_SDR25) ? 1 : 0;
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
val = (otap_del_ena << OTAPDLYENA_SHIFT) |
val = (0x1 << OTAPDLYENA_SHIFT) |
(otap_del_sel << OTAPDLYSEL_SHIFT);
/* Write to STRBSEL for HS400 speed mode */
@ -290,10 +298,21 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);
if (timing > MMC_TIMING_UHS_SDR25 && clock >= CLOCK_TOO_SLOW_HZ)
if (timing > MMC_TIMING_UHS_SDR25 && clock >= CLOCK_TOO_SLOW_HZ) {
sdhci_am654_setup_dll(host, clock);
else
sdhci_am654->dll_enable = true;
if (timing == MMC_TIMING_MMC_HS400) {
sdhci_am654->itap_del_ena[timing] = 0x1;
sdhci_am654->itap_del_sel[timing] = sdhci_am654->itap_del_sel[timing - 1];
}
sdhci_am654_write_itapdly(sdhci_am654, sdhci_am654->itap_del_sel[timing],
sdhci_am654->itap_del_ena[timing]);
} else {
sdhci_am654_setup_delay_chain(sdhci_am654, timing);
sdhci_am654->dll_enable = false;
}
regmap_update_bits(sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK,
sdhci_am654->clkbuf_sel);
@ -306,16 +325,29 @@ static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host,
struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
unsigned char timing = host->mmc->ios.timing;
u32 otap_del_sel;
u32 itap_del_ena;
u32 itap_del_sel;
u32 mask, val;
/* Setup DLL Output TAP delay */
/* Setup Output TAP delay */
otap_del_sel = sdhci_am654->otap_del_sel[timing];
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
val = (0x1 << OTAPDLYENA_SHIFT) |
(otap_del_sel << OTAPDLYSEL_SHIFT);
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);
/* Setup Input TAP delay */
itap_del_ena = sdhci_am654->itap_del_ena[timing];
itap_del_sel = sdhci_am654->itap_del_sel[timing];
mask |= ITAPDLYENA_MASK | ITAPDLYSEL_MASK;
val |= (itap_del_ena << ITAPDLYENA_SHIFT) |
(itap_del_sel << ITAPDLYSEL_SHIFT);
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK,
1 << ITAPCHGWIN_SHIFT);
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, mask, val);
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPCHGWIN_MASK, 0);
regmap_update_bits(sdhci_am654->base, PHY_CTRL5, CLKBUFSEL_MASK,
sdhci_am654->clkbuf_sel);
@ -408,45 +440,110 @@ static u32 sdhci_am654_cqhci_irq(struct sdhci_host *host, u32 intmask)
return 0;
}
#define ITAP_MAX 32
#define ITAPDLY_LENGTH 32
#define ITAPDLY_LAST_INDEX (ITAPDLY_LENGTH - 1)
static u32 sdhci_am654_calculate_itap(struct sdhci_host *host, struct window
*fail_window, u8 num_fails, bool circular_buffer)
{
u8 itap = 0, start_fail = 0, end_fail = 0, pass_length = 0;
u8 first_fail_start = 0, last_fail_end = 0;
struct device *dev = mmc_dev(host->mmc);
struct window pass_window = {0, 0, 0};
int prev_fail_end = -1;
u8 i;
if (!num_fails)
return ITAPDLY_LAST_INDEX >> 1;
if (fail_window->length == ITAPDLY_LENGTH) {
dev_err(dev, "No passing ITAPDLY, return 0\n");
return 0;
}
first_fail_start = fail_window->start;
last_fail_end = fail_window[num_fails - 1].end;
for (i = 0; i < num_fails; i++) {
start_fail = fail_window[i].start;
end_fail = fail_window[i].end;
pass_length = start_fail - (prev_fail_end + 1);
if (pass_length > pass_window.length) {
pass_window.start = prev_fail_end + 1;
pass_window.length = pass_length;
}
prev_fail_end = end_fail;
}
if (!circular_buffer)
pass_length = ITAPDLY_LAST_INDEX - last_fail_end;
else
pass_length = ITAPDLY_LAST_INDEX - last_fail_end + first_fail_start;
if (pass_length > pass_window.length) {
pass_window.start = last_fail_end + 1;
pass_window.length = pass_length;
}
if (!circular_buffer)
itap = pass_window.start + (pass_window.length >> 1);
else
itap = (pass_window.start + (pass_window.length >> 1)) % ITAPDLY_LENGTH;
return (itap > ITAPDLY_LAST_INDEX) ? ITAPDLY_LAST_INDEX >> 1 : itap;
}
static int sdhci_am654_platform_execute_tuning(struct sdhci_host *host,
u32 opcode)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
int cur_val, prev_val = 1, fail_len = 0, pass_window = 0, pass_len;
u32 itap;
unsigned char timing = host->mmc->ios.timing;
struct window fail_window[ITAPDLY_LENGTH];
u8 curr_pass, itap;
u8 fail_index = 0;
u8 prev_pass = 1;
memset(fail_window, 0, sizeof(fail_window));
/* Enable ITAPDLY */
regmap_update_bits(sdhci_am654->base, PHY_CTRL4, ITAPDLYENA_MASK,
1 << ITAPDLYENA_SHIFT);
sdhci_am654->itap_del_ena[timing] = 0x1;
for (itap = 0; itap < ITAP_MAX; itap++) {
sdhci_am654_write_itapdly(sdhci_am654, itap);
for (itap = 0; itap < ITAPDLY_LENGTH; itap++) {
sdhci_am654_write_itapdly(sdhci_am654, itap, sdhci_am654->itap_del_ena[timing]);
cur_val = !mmc_send_tuning(host->mmc, opcode, NULL);
if (cur_val && !prev_val)
pass_window = itap;
curr_pass = !mmc_send_tuning(host->mmc, opcode, NULL);
if (!cur_val)
fail_len++;
if (!curr_pass && prev_pass)
fail_window[fail_index].start = itap;
prev_val = cur_val;
if (!curr_pass) {
fail_window[fail_index].end = itap;
fail_window[fail_index].length++;
}
if (curr_pass && !prev_pass)
fail_index++;
prev_pass = curr_pass;
}
/*
* Having determined the length of the failing window and start of
* the passing window calculate the length of the passing window and
* set the final value halfway through it considering the range as a
* circular buffer
*/
pass_len = ITAP_MAX - fail_len;
itap = (pass_window + (pass_len >> 1)) % ITAP_MAX;
sdhci_am654_write_itapdly(sdhci_am654, itap);
if (fail_window[fail_index].length != 0)
fail_index++;
itap = sdhci_am654_calculate_itap(host, fail_window, fail_index,
sdhci_am654->dll_enable);
sdhci_am654_write_itapdly(sdhci_am654, itap, sdhci_am654->itap_del_ena[timing]);
/* Save ITAPDLY */
sdhci_am654->itap_del_sel[timing] = itap;
return 0;
}
static struct sdhci_ops sdhci_am654_ops = {
static const struct sdhci_ops sdhci_am654_ops = {
.platform_execute_tuning = sdhci_am654_platform_execute_tuning,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
@ -476,7 +573,7 @@ static const struct sdhci_am654_driver_data sdhci_am654_drvdata = {
.flags = IOMUX_PRESENT | FREQSEL_2_BIT | STRBSEL_4_BIT | DLL_PRESENT,
};
static struct sdhci_ops sdhci_j721e_8bit_ops = {
static const struct sdhci_ops sdhci_j721e_8bit_ops = {
.platform_execute_tuning = sdhci_am654_platform_execute_tuning,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
@ -500,7 +597,7 @@ static const struct sdhci_am654_driver_data sdhci_j721e_8bit_drvdata = {
.flags = DLL_PRESENT | DLL_CALIB,
};
static struct sdhci_ops sdhci_j721e_4bit_ops = {
static const struct sdhci_ops sdhci_j721e_4bit_ops = {
.platform_execute_tuning = sdhci_am654_platform_execute_tuning,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
@ -590,9 +687,12 @@ static int sdhci_am654_get_otap_delay(struct sdhci_host *host,
host->mmc->caps2 &= ~td[i].capability;
}
if (td[i].itap_binding)
device_property_read_u32(dev, td[i].itap_binding,
&sdhci_am654->itap_del_sel[i]);
if (td[i].itap_binding) {
ret = device_property_read_u32(dev, td[i].itap_binding,
&sdhci_am654->itap_del_sel[i]);
if (!ret)
sdhci_am654->itap_del_ena[i] = 0x1;
}
}
return 0;

View File

@ -2667,29 +2667,10 @@ static struct sdio_driver ath10k_sdio_driver = {
.probe = ath10k_sdio_probe,
.remove = ath10k_sdio_remove,
.drv = {
.owner = THIS_MODULE,
.pm = ATH10K_SDIO_PM_OPS,
},
};
static int __init ath10k_sdio_init(void)
{
int ret;
ret = sdio_register_driver(&ath10k_sdio_driver);
if (ret)
pr_err("sdio driver registration failed: %d\n", ret);
return ret;
}
static void __exit ath10k_sdio_exit(void)
{
sdio_unregister_driver(&ath10k_sdio_driver);
}
module_init(ath10k_sdio_init);
module_exit(ath10k_sdio_exit);
module_sdio_driver(ath10k_sdio_driver);
MODULE_AUTHOR("Qualcomm Atheros");
MODULE_DESCRIPTION("Driver support for Qualcomm Atheros 802.11ac WLAN SDIO devices");

View File

@ -1238,7 +1238,6 @@ static struct sdio_driver brcmf_sdmmc_driver = {
.name = KBUILD_MODNAME,
.id_table = brcmf_sdmmc_ids,
.drv = {
.owner = THIS_MODULE,
.pm = pm_sleep_ptr(&brcmf_sdio_pm_ops),
.coredump = brcmf_dev_coredump,
},

View File

@ -979,7 +979,6 @@ static struct sdio_driver mwifiex_sdio = {
.probe = mwifiex_sdio_probe,
.remove = mwifiex_sdio_remove,
.drv = {
.owner = THIS_MODULE,
.coredump = mwifiex_sdio_coredump,
.pm = &mwifiex_sdio_pm_ops,
}

View File

@ -267,7 +267,6 @@ struct sdio_driver wfx_sdio_driver = {
.probe = wfx_sdio_probe,
.remove = wfx_sdio_remove,
.drv = {
.owner = THIS_MODULE,
.of_match_table = wfx_sdio_of_match,
}
};

View File

@ -106,7 +106,10 @@ struct sdio_driver {
.class = (dev_class), \
.vendor = SDIO_ANY_ID, .device = SDIO_ANY_ID
extern int sdio_register_driver(struct sdio_driver *);
/* use a macro to avoid include chaining to get THIS_MODULE */
#define sdio_register_driver(drv) \
__sdio_register_driver(drv, THIS_MODULE)
extern int __sdio_register_driver(struct sdio_driver *, struct module *);
extern void sdio_unregister_driver(struct sdio_driver *);
/**

View File

@ -8,8 +8,8 @@
#ifndef MMC_SLOT_GPIO_H
#define MMC_SLOT_GPIO_H
#include <linux/interrupt.h>
#include <linux/types.h>
#include <linux/irqreturn.h>
struct mmc_host;
@ -21,8 +21,8 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
unsigned int debounce);
int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id,
unsigned int idx, unsigned int debounce);
void mmc_gpio_set_cd_isr(struct mmc_host *host,
irqreturn_t (*isr)(int irq, void *dev_id));
int mmc_gpiod_set_cd_config(struct mmc_host *host, unsigned long config);
void mmc_gpio_set_cd_isr(struct mmc_host *host, irq_handler_t isr);
int mmc_gpio_set_cd_wake(struct mmc_host *host, bool on);
void mmc_gpiod_request_cd_irq(struct mmc_host *host);
bool mmc_can_gpio_cd(struct mmc_host *host);