MMC host:
- sdhci-pci: Fixup tuning for AMD for eMMC HS200 mode - renesas_sdhi_internal_dmac: Avoid data corruption by limiting DMA RX -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJa2YzyAAoJEP4mhCVzWIwphfoQAMAVReir4qCfLrdNsMCsbBg/ GIXJajgOYbqX1iwMEjhHAwSxIpk9i2YM/OatcCe1Kru3h0+iuEqs4XhzwbD1w/WP BoSHKUdjocvIzUdD2N1zUf6V/1Qf74xAT9yEqWI0C8A1fhr52BbvaUgxJ9FxbjcD OTEv2CBcyoR9lP0t32K6PzHe/uDsTGwMHa2cXit/ugN7OSM62m9Jy8lm8lcijZsA LV9YMExoNr5T+kVijjRjzZ68z0cf3MtaMWCggO9J3yIKmkGTUYyaj6KgJWfOA+Ey hiObIW61Rdf6npk1ne6wXlzVW1SAxMFhjQYn7zIzPs6iiqYgrNfziL1chQ130Rpl 3LE9Lfb3PIT7lHvAJQQodCYQQddh3MNf5wgnemMY5Cnbnaj50KrX+2PqzOGZsdcr hGe4niq1pNTsgyunkkU2dG9poQjeqOS544S9/PH6VXqXhfrRvgKwJY4QQSEEykDq 3cGArh2YxfIhr/SkNDZsBegmMwW8rm00sKudm810d3q3wS7TN341qSx+no71Ryz7 qpfCZ+VFfus2irnzyV5FViPH+cZ45LUAC6NN9fcksmvEGlMwvX2yYKttSKtxi7ia CRyf5R1rn4DJ0qgIfv+j3pc5KpBhu9EU9QFd2Zi9STs0VUKe48Jmnozck/6pvQp+ 2q1d7X9S+97NJJ04CzbU =jO/Y -----END PGP SIGNATURE----- Merge tag 'mmc-v4.17-3' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc Pull MMC fixes from Ulf Hansson: "A couple of MMC host fixes: - sdhci-pci: Fixup tuning for AMD for eMMC HS200 mode - renesas_sdhi_internal_dmac: Avoid data corruption by limiting DMA RX" * tag 'mmc-v4.17-3' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: mmc: renesas_sdhi_internal_dmac: limit DMA RX for old SoCs mmc: sdhci-pci: Only do AMD tuning for HS200
This commit is contained in:
commit
7e3cb169d3
|
@ -9,6 +9,7 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/io-64-nonatomic-hi-lo.h>
|
||||
|
@ -62,6 +63,17 @@
|
|||
* need a custom accessor.
|
||||
*/
|
||||
|
||||
static unsigned long global_flags;
|
||||
/*
|
||||
* Workaround for avoiding to use RX DMAC by multiple channels.
|
||||
* On R-Car H3 ES1.* and M3-W ES1.0, when multiple SDHI channels use
|
||||
* RX DMAC simultaneously, sometimes hundreds of bytes data are not
|
||||
* stored into the system memory even if the DMAC interrupt happened.
|
||||
* So, this driver then uses one RX DMAC channel only.
|
||||
*/
|
||||
#define SDHI_INTERNAL_DMAC_ONE_RX_ONLY 0
|
||||
#define SDHI_INTERNAL_DMAC_RX_IN_USE 1
|
||||
|
||||
/* Definitions for sampling clocks */
|
||||
static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = {
|
||||
{
|
||||
|
@ -126,6 +138,9 @@ renesas_sdhi_internal_dmac_abort_dma(struct tmio_mmc_host *host) {
|
|||
renesas_sdhi_internal_dmac_dm_write(host, DM_CM_RST,
|
||||
RST_RESERVED_BITS | val);
|
||||
|
||||
if (host->data && host->data->flags & MMC_DATA_READ)
|
||||
clear_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags);
|
||||
|
||||
renesas_sdhi_internal_dmac_enable_dma(host, true);
|
||||
}
|
||||
|
||||
|
@ -155,6 +170,9 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
|
|||
if (data->flags & MMC_DATA_READ) {
|
||||
dtran_mode |= DTRAN_MODE_CH_NUM_CH1;
|
||||
dir = DMA_FROM_DEVICE;
|
||||
if (test_bit(SDHI_INTERNAL_DMAC_ONE_RX_ONLY, &global_flags) &&
|
||||
test_and_set_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags))
|
||||
goto force_pio;
|
||||
} else {
|
||||
dtran_mode |= DTRAN_MODE_CH_NUM_CH0;
|
||||
dir = DMA_TO_DEVICE;
|
||||
|
@ -208,6 +226,9 @@ static void renesas_sdhi_internal_dmac_complete_tasklet_fn(unsigned long arg)
|
|||
renesas_sdhi_internal_dmac_enable_dma(host, false);
|
||||
dma_unmap_sg(&host->pdev->dev, host->sg_ptr, host->sg_len, dir);
|
||||
|
||||
if (dir == DMA_FROM_DEVICE)
|
||||
clear_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags);
|
||||
|
||||
tmio_mmc_do_data_irq(host);
|
||||
out:
|
||||
spin_unlock_irq(&host->lock);
|
||||
|
@ -251,18 +272,24 @@ static const struct tmio_mmc_dma_ops renesas_sdhi_internal_dmac_dma_ops = {
|
|||
* implementation as others may use a different implementation.
|
||||
*/
|
||||
static const struct soc_device_attribute gen3_soc_whitelist[] = {
|
||||
{ .soc_id = "r8a7795", .revision = "ES1.*" },
|
||||
{ .soc_id = "r8a7795", .revision = "ES2.0" },
|
||||
{ .soc_id = "r8a7796", .revision = "ES1.0" },
|
||||
{ .soc_id = "r8a77995", .revision = "ES1.0" },
|
||||
{ /* sentinel */ }
|
||||
{ .soc_id = "r8a7795", .revision = "ES1.*",
|
||||
.data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
|
||||
{ .soc_id = "r8a7795", .revision = "ES2.0" },
|
||||
{ .soc_id = "r8a7796", .revision = "ES1.0",
|
||||
.data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
|
||||
{ .soc_id = "r8a77995", .revision = "ES1.0" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static int renesas_sdhi_internal_dmac_probe(struct platform_device *pdev)
|
||||
{
|
||||
if (!soc_device_match(gen3_soc_whitelist))
|
||||
const struct soc_device_attribute *soc = soc_device_match(gen3_soc_whitelist);
|
||||
|
||||
if (!soc)
|
||||
return -ENODEV;
|
||||
|
||||
global_flags |= (unsigned long)soc->data;
|
||||
|
||||
return renesas_sdhi_probe(pdev, &renesas_sdhi_internal_dmac_dma_ops);
|
||||
}
|
||||
|
||||
|
|
|
@ -1312,7 +1312,7 @@ static void amd_enable_manual_tuning(struct pci_dev *pdev)
|
|||
pci_write_config_dword(pdev, AMD_SD_MISC_CONTROL, val);
|
||||
}
|
||||
|
||||
static int amd_execute_tuning(struct sdhci_host *host, u32 opcode)
|
||||
static int amd_execute_tuning_hs200(struct sdhci_host *host, u32 opcode)
|
||||
{
|
||||
struct sdhci_pci_slot *slot = sdhci_priv(host);
|
||||
struct pci_dev *pdev = slot->chip->pdev;
|
||||
|
@ -1351,6 +1351,27 @@ static int amd_execute_tuning(struct sdhci_host *host, u32 opcode)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int amd_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
||||
{
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
|
||||
/* AMD requires custom HS200 tuning */
|
||||
if (host->timing == MMC_TIMING_MMC_HS200)
|
||||
return amd_execute_tuning_hs200(host, opcode);
|
||||
|
||||
/* Otherwise perform standard SDHCI tuning */
|
||||
return sdhci_execute_tuning(mmc, opcode);
|
||||
}
|
||||
|
||||
static int amd_probe_slot(struct sdhci_pci_slot *slot)
|
||||
{
|
||||
struct mmc_host_ops *ops = &slot->host->mmc_host_ops;
|
||||
|
||||
ops->execute_tuning = amd_execute_tuning;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amd_probe(struct sdhci_pci_chip *chip)
|
||||
{
|
||||
struct pci_dev *smbus_dev;
|
||||
|
@ -1385,12 +1406,12 @@ static const struct sdhci_ops amd_sdhci_pci_ops = {
|
|||
.set_bus_width = sdhci_set_bus_width,
|
||||
.reset = sdhci_reset,
|
||||
.set_uhs_signaling = sdhci_set_uhs_signaling,
|
||||
.platform_execute_tuning = amd_execute_tuning,
|
||||
};
|
||||
|
||||
static const struct sdhci_pci_fixes sdhci_amd = {
|
||||
.probe = amd_probe,
|
||||
.ops = &amd_sdhci_pci_ops,
|
||||
.probe_slot = amd_probe_slot,
|
||||
};
|
||||
|
||||
static const struct pci_device_id pci_ids[] = {
|
||||
|
|
Loading…
Reference in a new issue