mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-10 07:10:27 +00:00
MMC core:
- Enable host caps to be modified via debugfs to test speed-modes - Improve random I/O writes for 4k buffers for hsq enabled hosts MMC host: - atmel-mci/sdhci-of-at91: Aubin Constans takes over as maintainer - dw_mmc-starfive: Re-work tuning support - meson-gx: Fix bogus IRQ when using CMD_CFG_ERROR - mmci: Use peripheral flow control for the STM32 variant - renesas,sdhi: Add support for the RZ/G3S variant - sdhci-esdhc-imx: Optimize the manual tuning logic - sdhci-msm: Add support for the SM8650 variant - sdhci-npcm: Add driver to support the Nuvoton NPCM BMC variant - sdhci-pci-gli: Add workaround to allow GL9750 to enter ASPM L1.2 -----BEGIN PGP SIGNATURE----- iQJLBAABCgA1FiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAmVCJrIXHHVsZi5oYW5z c29uQGxpbmFyby5vcmcACgkQ/iaEJXNYjCnysBAApP9xUqojSse1lrVxLnAayMlz h7zhkaAlagv4pkUTfYvkUVCJfGs23j7Icdu7+oFyxKBdxHX0hTQqASJJMlXRtObk SIzEBtky3kL3lS2i9FAZ4RKBtZh8palai439Nv15569idiy4vpIFaMUJtTSp/xpm fmloT3Evu3pOFCRFut2mgSIG7S9L4aI/+c5RgWuDQBtirpU7TzgKW4GaPm/sWcrG WfgJ+3tu2/0tZkpuCNf0hYAI7GZUTePZrXuFdZhm0TI32jGY4VBCdJ8HLVmFdnKz JZoGv9fd3JPoMwjR4wEkh41lxcGZpB6DYWi9iQvQPBbHkromhlZwNEJ6xt+j6zOq /T1POAsAc5Tw8bfxqlI0jZFkKhpq5uI8Yg4lWGmR4yOhaaih3wXCVSK4CBETa19O jUSRz5zrfYhbvOIWclHILkYEMlmwUbCjn+3iMrNkINQUkejVdqW8A3o/AyCVgdD/ 6FdQv9IjkdQ1+2JmQB41av3Zb0yJ5j8XcmLQp7WofJpZy0GLdr/JxqXUOSPaR3YY Mz9A0aq8CY9q9PLtEqtIJo66se/fMMMveS/43sHxEmgixjIOBcrN0fap/OSmitEe vhR7X3gglMUq/VEVSxx9A4S/g2Lm60gq0piMRd3TlyL1ZW/7CxCi61rafa6BUMn+ MGDbMnTxZk837fBbaU8= =Qcl9 -----END PGP SIGNATURE----- Merge tag 'mmc-v6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc Pull MMC updates from Ulf Hansson: " MMC core: - Enable host caps to be modified via debugfs to test speed-modes - Improve random I/O writes for 4k buffers for hsq enabled hosts MMC host: - atmel-mci/sdhci-of-at91: Aubin Constans takes over as maintainer - dw_mmc-starfive: Re-work tuning support - meson-gx: Fix bogus IRQ when using CMD_CFG_ERROR - mmci: Use peripheral flow control for the STM32 variant - renesas,sdhi: Add support for the RZ/G3S variant - sdhci-esdhc-imx: Optimize the manual tuning logic - sdhci-msm: Add support for the SM8650 variant - sdhci-npcm: Add driver to support the Nuvoton NPCM BMC variant - sdhci-pci-gli: Add workaround to allow GL9750 to enter ASPM L1.2" * tag 'mmc-v6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (25 commits) dt-bindings: mmc: sdhci-msm: document the SM8650 SDHCI Controller mmc: meson-gx: Remove setting of CMD_CFG_ERROR MAINTAINERS: mmc: take over as maintainer of MCI & SDHCI MICROCHIP DRIVERS mmc: jz4740: Use device_get_match_data() mmc: sdhci-npcm: Add NPCM SDHCI driver dt-bindings: mmc: npcm,sdhci: Document NPCM SDHCI controller mmc: sdhci-pltfm: Make driver OF independent mmc: sdhci-pltfm: Drop unnecessary error messages in sdhci_pltfm_init() mmc: sdhci-pci: Switch to use acpi_evaluate_dsm_typed() mmc: debugfs: Allow host caps to be modified mmc: core: Always reselect card type mmc: mmci: use peripheral flow control for STM32 mmc: vub300: replace deprecated strncpy with strscpy memstick: jmb38x_ms: Annotate struct jmb38x_ms with __counted_by mmc: starfive: Change tuning implementation dt-bindings: mmc: starfive: Remove properties from required mmc: hsq: Improve random I/O write performance for 4k buffers mmc: core: Allow dynamical updates of the number of requests for hsq mmc: sdhci-pci-gli: A workaround to allow GL9750 to enter ASPM L1.2 dt-bindings: mmc: renesas,sdhi: Document RZ/G3S support ...
This commit is contained in:
commit
40aa597c4a
45
Documentation/devicetree/bindings/mmc/npcm,sdhci.yaml
Normal file
45
Documentation/devicetree/bindings/mmc/npcm,sdhci.yaml
Normal file
@ -0,0 +1,45 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mmc/npcm,sdhci.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NPCM SDHCI Controller
|
||||
|
||||
maintainers:
|
||||
- Tomer Maimon <tmaimon77@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: mmc-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- nuvoton,npcm750-sdhci
|
||||
- nuvoton,npcm845-sdhci
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
mmc@f0840000 {
|
||||
compatible = "nuvoton,npcm750-sdhci";
|
||||
reg = <0xf0840000 0x200>;
|
||||
interrupts = <0 27 4>;
|
||||
clocks = <&clk 4>;
|
||||
};
|
@ -59,6 +59,7 @@ properties:
|
||||
- renesas,sdhi-r9a07g043 # RZ/G2UL
|
||||
- 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:
|
||||
@ -122,6 +123,7 @@ allOf:
|
||||
- renesas,sdhi-r9a07g043
|
||||
- renesas,sdhi-r9a07g044
|
||||
- renesas,sdhi-r9a07g054
|
||||
- renesas,sdhi-r9a08g045
|
||||
- renesas,sdhi-r9a09g011
|
||||
then:
|
||||
properties:
|
||||
|
@ -58,6 +58,7 @@ properties:
|
||||
- qcom,sm8350-sdhci
|
||||
- qcom,sm8450-sdhci
|
||||
- qcom,sm8550-sdhci
|
||||
- qcom,sm8650-sdhci
|
||||
- const: qcom,sdhci-msm-v5 # for sdcc version 5.0
|
||||
|
||||
reg:
|
||||
@ -85,10 +86,10 @@ properties:
|
||||
- const: iface
|
||||
- const: core
|
||||
- const: xo
|
||||
- const: ice
|
||||
- const: bus
|
||||
- const: cal
|
||||
- const: sleep
|
||||
- enum: [ice, bus, cal, sleep]
|
||||
- enum: [ice, bus, cal, sleep]
|
||||
- enum: [ice, bus, cal, sleep]
|
||||
- enum: [ice, bus, cal, sleep]
|
||||
|
||||
dma-coherent: true
|
||||
|
||||
|
@ -55,7 +55,6 @@ required:
|
||||
- clocks
|
||||
- clock-names
|
||||
- interrupts
|
||||
- starfive,sysreg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
@ -73,5 +72,4 @@ examples:
|
||||
fifo-depth = <32>;
|
||||
fifo-watermark-aligned;
|
||||
data-addr = <0>;
|
||||
starfive,sysreg = <&sys_syscon 0x14 0x1a 0x7c000000>;
|
||||
};
|
||||
|
@ -14110,7 +14110,7 @@ F: Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml
|
||||
F: drivers/iio/adc/mcp3911.c
|
||||
|
||||
MICROCHIP MMC/SD/SDIO MCI DRIVER
|
||||
M: Ludovic Desroches <ludovic.desroches@microchip.com>
|
||||
M: Aubin Constans <aubin.constans@microchip.com>
|
||||
S: Maintained
|
||||
F: drivers/mmc/host/atmel-mci.c
|
||||
|
||||
@ -19335,7 +19335,8 @@ F: Documentation/devicetree/bindings/mmc/sdhci-common.yaml
|
||||
F: drivers/mmc/host/sdhci*
|
||||
|
||||
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) MICROCHIP DRIVER
|
||||
M: Eugen Hristev <eugen.hristev@microchip.com>
|
||||
M: Aubin Constans <aubin.constans@microchip.com>
|
||||
R: Eugen Hristev <eugen.hristev@collabora.com>
|
||||
L: linux-mmc@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/mmc/host/sdhci-of-at91.c
|
||||
|
@ -66,7 +66,7 @@ struct jmb38x_ms_host {
|
||||
struct jmb38x_ms {
|
||||
struct pci_dev *pdev;
|
||||
int host_cnt;
|
||||
struct memstick_host *hosts[];
|
||||
struct memstick_host *hosts[] __counted_by(host_cnt);
|
||||
};
|
||||
|
||||
#define BLOCK_COUNT_MASK 0xffff0000
|
||||
|
@ -12,9 +12,12 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/fault-inject.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
#include <linux/mmc/card.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/mmc.h>
|
||||
#include <linux/mmc/sd.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "card.h"
|
||||
@ -298,6 +301,49 @@ static const struct file_operations mmc_err_stats_fops = {
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int mmc_caps_get(void *data, u64 *val)
|
||||
{
|
||||
*val = *(u32 *)data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmc_caps_set(void *data, u64 val)
|
||||
{
|
||||
u32 *caps = data;
|
||||
u32 diff = *caps ^ val;
|
||||
u32 allowed = MMC_CAP_AGGRESSIVE_PM |
|
||||
MMC_CAP_SD_HIGHSPEED |
|
||||
MMC_CAP_MMC_HIGHSPEED |
|
||||
MMC_CAP_UHS |
|
||||
MMC_CAP_DDR;
|
||||
|
||||
if (diff & ~allowed)
|
||||
return -EINVAL;
|
||||
|
||||
*caps = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmc_caps2_set(void *data, u64 val)
|
||||
{
|
||||
u32 allowed = MMC_CAP2_HSX00_1_8V | MMC_CAP2_HSX00_1_2V;
|
||||
u32 *caps = data;
|
||||
u32 diff = *caps ^ val;
|
||||
|
||||
if (diff & ~allowed)
|
||||
return -EINVAL;
|
||||
|
||||
*caps = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(mmc_caps_fops, mmc_caps_get, mmc_caps_set,
|
||||
"0x%08llx\n");
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(mmc_caps2_fops, mmc_caps_get, mmc_caps2_set,
|
||||
"0x%08llx\n");
|
||||
|
||||
void mmc_add_host_debugfs(struct mmc_host *host)
|
||||
{
|
||||
struct dentry *root;
|
||||
@ -306,8 +352,9 @@ void mmc_add_host_debugfs(struct mmc_host *host)
|
||||
host->debugfs_root = root;
|
||||
|
||||
debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops);
|
||||
debugfs_create_x32("caps", S_IRUSR, root, &host->caps);
|
||||
debugfs_create_x32("caps2", S_IRUSR, root, &host->caps2);
|
||||
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,
|
||||
&mmc_clock_fops);
|
||||
|
||||
|
@ -419,7 +419,6 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
|
||||
|
||||
card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
|
||||
card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
|
||||
mmc_select_card_type(card);
|
||||
|
||||
card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT];
|
||||
card->ext_csd.raw_erase_timeout_mult =
|
||||
@ -1732,6 +1731,12 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
mmc_set_erase_size(card);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reselect the card type since host caps could have been changed when
|
||||
* debugging even if the card is not new.
|
||||
*/
|
||||
mmc_select_card_type(card);
|
||||
|
||||
/* Enable ERASE_GRP_DEF. This bit is lost after a reset or power off. */
|
||||
if (card->ext_csd.rev >= 3) {
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
|
@ -260,11 +260,7 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx,
|
||||
}
|
||||
break;
|
||||
case MMC_ISSUE_ASYNC:
|
||||
/*
|
||||
* For MMC host software queue, we only allow 2 requests in
|
||||
* flight to avoid a long latency.
|
||||
*/
|
||||
if (host->hsq_enabled && mq->in_flight[issue_type] > 2) {
|
||||
if (host->hsq_enabled && mq->in_flight[issue_type] > host->hsq_depth) {
|
||||
spin_unlock_irq(&mq->lock);
|
||||
return BLK_STS_RESOURCE;
|
||||
}
|
||||
|
@ -429,6 +429,14 @@ config MMC_SDHCI_IPROC
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config MMC_SDHCI_NPCM
|
||||
tristate "Secure Digital Host Controller Interface support for NPCM"
|
||||
depends on ARCH_NPCM || COMPILE_TEST
|
||||
depends on MMC_SDHCI_PLTFM
|
||||
help
|
||||
This provides support for the SD/eMMC controller found in
|
||||
NPCM BMC family SoCs.
|
||||
|
||||
config MMC_MESON_GX
|
||||
tristate "Amlogic S905/GX*/AXG SD/MMC Host Controller support"
|
||||
depends on ARCH_MESON|| COMPILE_TEST
|
||||
@ -677,9 +685,9 @@ config MMC_SDHI_SYS_DMAC
|
||||
|
||||
config MMC_SDHI_INTERNAL_DMAC
|
||||
tristate "DMA for SDHI SD/SDIO controllers using on-chip bus mastering"
|
||||
depends on ARM64 || ARCH_R7S9210 || ARCH_R8A77470 || COMPILE_TEST
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
depends on MMC_SDHI
|
||||
default MMC_SDHI if (ARM64 || ARCH_R7S9210 || ARCH_R8A77470)
|
||||
default MMC_SDHI if ARCH_RENESAS
|
||||
help
|
||||
This provides DMA support for SDHI SD/SDIO controllers
|
||||
using on-chip bus mastering. This supports the controllers
|
||||
|
@ -89,6 +89,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_DWCMSHC) += sdhci-of-dwcmshc.o
|
||||
obj-$(CONFIG_MMC_SDHCI_OF_SPARX5) += sdhci-of-sparx5.o
|
||||
obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o
|
||||
obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o
|
||||
obj-$(CONFIG_MMC_SDHCI_NPCM) += sdhci-npcm.o
|
||||
obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o
|
||||
obj-$(CONFIG_MMC_SDHCI_ST) += sdhci-st.o
|
||||
obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32) += sdhci-pic32.o
|
||||
|
@ -227,6 +227,7 @@ struct mci_slot_pdata {
|
||||
/**
|
||||
* 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 {
|
||||
@ -674,8 +675,10 @@ atmci_of_init(struct platform_device *pdev)
|
||||
"cd", GPIOD_IN, "cd-gpios");
|
||||
err = PTR_ERR_OR_ZERO(pdata->slot[slot_id].detect_pin);
|
||||
if (err) {
|
||||
if (err != -ENOENT)
|
||||
if (err != -ENOENT) {
|
||||
of_node_put(cnp);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
pdata->slot[slot_id].detect_pin = NULL;
|
||||
}
|
||||
|
||||
@ -687,8 +690,10 @@ atmci_of_init(struct platform_device *pdev)
|
||||
"wp", GPIOD_IN, "wp-gpios");
|
||||
err = PTR_ERR_OR_ZERO(pdata->slot[slot_id].wp_pin);
|
||||
if (err) {
|
||||
if (err != -ENOENT)
|
||||
if (err != -ENOENT) {
|
||||
of_node_put(cnp);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
pdata->slot[slot_id].wp_pin = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
* Copyright (c) 2022 StarFive Technology Co., Ltd.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
@ -20,13 +21,7 @@
|
||||
#define ALL_INT_CLR 0x1ffff
|
||||
#define MAX_DELAY_CHAIN 32
|
||||
|
||||
struct starfive_priv {
|
||||
struct device *dev;
|
||||
struct regmap *reg_syscon;
|
||||
u32 syscon_offset;
|
||||
u32 syscon_shift;
|
||||
u32 syscon_mask;
|
||||
};
|
||||
#define STARFIVE_SMPL_PHASE GENMASK(20, 16)
|
||||
|
||||
static void dw_mci_starfive_set_ios(struct dw_mci *host, struct mmc_ios *ios)
|
||||
{
|
||||
@ -44,117 +39,65 @@ static void dw_mci_starfive_set_ios(struct dw_mci *host, struct mmc_ios *ios)
|
||||
}
|
||||
}
|
||||
|
||||
static void dw_mci_starfive_set_sample_phase(struct dw_mci *host, u32 smpl_phase)
|
||||
{
|
||||
/* change driver phase and sample phase */
|
||||
u32 reg_value = mci_readl(host, UHS_REG_EXT);
|
||||
|
||||
/* In UHS_REG_EXT, only 5 bits valid in DRV_PHASE and SMPL_PHASE */
|
||||
reg_value &= ~STARFIVE_SMPL_PHASE;
|
||||
reg_value |= FIELD_PREP(STARFIVE_SMPL_PHASE, smpl_phase);
|
||||
mci_writel(host, UHS_REG_EXT, reg_value);
|
||||
|
||||
/* We should delay 1ms wait for timing setting finished. */
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
static int dw_mci_starfive_execute_tuning(struct dw_mci_slot *slot,
|
||||
u32 opcode)
|
||||
{
|
||||
static const int grade = MAX_DELAY_CHAIN;
|
||||
struct dw_mci *host = slot->host;
|
||||
struct starfive_priv *priv = host->priv;
|
||||
int rise_point = -1, fall_point = -1;
|
||||
int err, prev_err = 0;
|
||||
int i;
|
||||
bool found = 0;
|
||||
u32 regval;
|
||||
|
||||
/*
|
||||
* Use grade as the max delay chain, and use the rise_point and
|
||||
* fall_point to ensure the best sampling point of a data input
|
||||
* signals.
|
||||
*/
|
||||
for (i = 0; i < grade; i++) {
|
||||
regval = i << priv->syscon_shift;
|
||||
err = regmap_update_bits(priv->reg_syscon, priv->syscon_offset,
|
||||
priv->syscon_mask, regval);
|
||||
if (err)
|
||||
return err;
|
||||
mci_writel(host, RINTSTS, ALL_INT_CLR);
|
||||
|
||||
err = mmc_send_tuning(slot->mmc, opcode, NULL);
|
||||
if (!err)
|
||||
found = 1;
|
||||
|
||||
if (i > 0) {
|
||||
if (err && !prev_err)
|
||||
fall_point = i - 1;
|
||||
if (!err && prev_err)
|
||||
rise_point = i;
|
||||
}
|
||||
|
||||
if (rise_point != -1 && fall_point != -1)
|
||||
goto tuning_out;
|
||||
|
||||
prev_err = err;
|
||||
err = 0;
|
||||
}
|
||||
|
||||
tuning_out:
|
||||
if (found) {
|
||||
if (rise_point == -1)
|
||||
rise_point = 0;
|
||||
if (fall_point == -1)
|
||||
fall_point = grade - 1;
|
||||
if (fall_point < rise_point) {
|
||||
if ((rise_point + fall_point) >
|
||||
(grade - 1))
|
||||
i = fall_point / 2;
|
||||
else
|
||||
i = (rise_point + grade - 1) / 2;
|
||||
} else {
|
||||
i = (rise_point + fall_point) / 2;
|
||||
}
|
||||
|
||||
regval = i << priv->syscon_shift;
|
||||
err = regmap_update_bits(priv->reg_syscon, priv->syscon_offset,
|
||||
priv->syscon_mask, regval);
|
||||
if (err)
|
||||
return err;
|
||||
mci_writel(host, RINTSTS, ALL_INT_CLR);
|
||||
|
||||
dev_info(host->dev, "Found valid delay chain! use it [delay=%d]\n", i);
|
||||
} else {
|
||||
dev_err(host->dev, "No valid delay chain! use default\n");
|
||||
err = -EINVAL;
|
||||
}
|
||||
|
||||
mci_writel(host, RINTSTS, ALL_INT_CLR);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int dw_mci_starfive_parse_dt(struct dw_mci *host)
|
||||
{
|
||||
struct of_phandle_args args;
|
||||
struct starfive_priv *priv;
|
||||
int smpl_phase, smpl_raise = -1, smpl_fall = -1;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
for (smpl_phase = 0; smpl_phase < grade; smpl_phase++) {
|
||||
dw_mci_starfive_set_sample_phase(host, smpl_phase);
|
||||
mci_writel(host, RINTSTS, ALL_INT_CLR);
|
||||
|
||||
ret = of_parse_phandle_with_fixed_args(host->dev->of_node,
|
||||
"starfive,sysreg", 3, 0, &args);
|
||||
if (ret) {
|
||||
dev_err(host->dev, "Failed to parse starfive,sysreg\n");
|
||||
return -EINVAL;
|
||||
ret = mmc_send_tuning(slot->mmc, opcode, NULL);
|
||||
|
||||
if (!ret && smpl_raise < 0) {
|
||||
smpl_raise = smpl_phase;
|
||||
} else if (ret && smpl_raise >= 0) {
|
||||
smpl_fall = smpl_phase - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
priv->reg_syscon = syscon_node_to_regmap(args.np);
|
||||
of_node_put(args.np);
|
||||
if (IS_ERR(priv->reg_syscon))
|
||||
return PTR_ERR(priv->reg_syscon);
|
||||
if (smpl_phase >= grade)
|
||||
smpl_fall = grade - 1;
|
||||
|
||||
priv->syscon_offset = args.args[0];
|
||||
priv->syscon_shift = args.args[1];
|
||||
priv->syscon_mask = args.args[2];
|
||||
if (smpl_raise < 0) {
|
||||
smpl_phase = 0;
|
||||
dev_err(host->dev, "No valid delay chain! use default\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
host->priv = priv;
|
||||
smpl_phase = (smpl_raise + smpl_fall) / 2;
|
||||
dev_dbg(host->dev, "Found valid delay chain! use it [delay=%d]\n", smpl_phase);
|
||||
ret = 0;
|
||||
|
||||
return 0;
|
||||
out:
|
||||
dw_mci_starfive_set_sample_phase(host, smpl_phase);
|
||||
mci_writel(host, RINTSTS, ALL_INT_CLR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dw_mci_drv_data starfive_data = {
|
||||
.common_caps = MMC_CAP_CMD23,
|
||||
.set_ios = dw_mci_starfive_set_ios,
|
||||
.parse_dt = dw_mci_starfive_parse_dt,
|
||||
.execute_tuning = dw_mci_starfive_execute_tuning,
|
||||
};
|
||||
|
||||
|
@ -18,9 +18,10 @@
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/slot-gpio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
@ -1040,7 +1041,6 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
|
||||
int ret;
|
||||
struct mmc_host *mmc;
|
||||
struct jz4740_mmc_host *host;
|
||||
const struct of_device_id *match;
|
||||
|
||||
mmc = mmc_alloc_host(sizeof(struct jz4740_mmc_host), &pdev->dev);
|
||||
if (!mmc) {
|
||||
@ -1050,13 +1050,8 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
|
||||
|
||||
host = mmc_priv(mmc);
|
||||
|
||||
match = of_match_device(jz4740_mmc_of_match, &pdev->dev);
|
||||
if (match) {
|
||||
host->version = (enum jz4740_mmc_version)match->data;
|
||||
} else {
|
||||
/* JZ4740 should be the only one using legacy probe */
|
||||
host->version = JZ_MMC_JZ4740;
|
||||
}
|
||||
/* Default if no match is JZ4740 */
|
||||
host->version = (enum jz4740_mmc_version)device_get_match_data(&pdev->dev);
|
||||
|
||||
ret = mmc_of_parse(mmc);
|
||||
if (ret) {
|
||||
@ -1200,7 +1195,7 @@ static struct platform_driver jz4740_mmc_driver = {
|
||||
.driver = {
|
||||
.name = "jz4740-mmc",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.of_match_table = of_match_ptr(jz4740_mmc_of_match),
|
||||
.of_match_table = jz4740_mmc_of_match,
|
||||
.pm = pm_sleep_ptr(&jz4740_mmc_pm_ops),
|
||||
},
|
||||
};
|
||||
|
@ -801,7 +801,6 @@ static void meson_mmc_start_cmd(struct mmc_host *mmc, struct mmc_command *cmd)
|
||||
|
||||
cmd_cfg |= FIELD_PREP(CMD_CFG_CMD_INDEX_MASK, cmd->opcode);
|
||||
cmd_cfg |= CMD_CFG_OWNER; /* owned by CPU */
|
||||
cmd_cfg |= CMD_CFG_ERROR; /* stop in case of error */
|
||||
|
||||
meson_mmc_set_response_bits(cmd, &cmd_cfg);
|
||||
|
||||
|
@ -21,6 +21,25 @@ static void mmc_hsq_retry_handler(struct work_struct *work)
|
||||
mmc->ops->request(mmc, hsq->mrq);
|
||||
}
|
||||
|
||||
static void mmc_hsq_modify_threshold(struct mmc_hsq *hsq)
|
||||
{
|
||||
struct mmc_host *mmc = hsq->mmc;
|
||||
struct mmc_request *mrq;
|
||||
unsigned int tag, need_change = 0;
|
||||
|
||||
mmc->hsq_depth = HSQ_NORMAL_DEPTH;
|
||||
for (tag = 0; tag < HSQ_NUM_SLOTS; tag++) {
|
||||
mrq = hsq->slot[tag].mrq;
|
||||
if (mrq && mrq->data &&
|
||||
(mrq->data->blksz * mrq->data->blocks == 4096) &&
|
||||
(mrq->data->flags & MMC_DATA_WRITE) &&
|
||||
(++need_change == 2)) {
|
||||
mmc->hsq_depth = HSQ_PERFORMANCE_DEPTH;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void mmc_hsq_pump_requests(struct mmc_hsq *hsq)
|
||||
{
|
||||
struct mmc_host *mmc = hsq->mmc;
|
||||
@ -42,6 +61,8 @@ static void mmc_hsq_pump_requests(struct mmc_hsq *hsq)
|
||||
return;
|
||||
}
|
||||
|
||||
mmc_hsq_modify_threshold(hsq);
|
||||
|
||||
slot = &hsq->slot[hsq->next_tag];
|
||||
hsq->mrq = slot->mrq;
|
||||
hsq->qcnt--;
|
||||
@ -337,6 +358,7 @@ int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc)
|
||||
hsq->mmc = mmc;
|
||||
hsq->mmc->cqe_private = hsq;
|
||||
mmc->cqe_ops = &mmc_hsq_ops;
|
||||
mmc->hsq_depth = HSQ_NORMAL_DEPTH;
|
||||
|
||||
for (i = 0; i < HSQ_NUM_SLOTS; i++)
|
||||
hsq->tag_slot[i] = HSQ_INVALID_TAG;
|
||||
|
@ -5,6 +5,17 @@
|
||||
#define HSQ_NUM_SLOTS 64
|
||||
#define HSQ_INVALID_TAG HSQ_NUM_SLOTS
|
||||
|
||||
/*
|
||||
* For MMC host software queue, we only allow 2 requests in
|
||||
* flight to avoid a long latency.
|
||||
*/
|
||||
#define HSQ_NORMAL_DEPTH 2
|
||||
/*
|
||||
* For 4k random writes, we allow hsq_depth to increase to 5
|
||||
* for better performance.
|
||||
*/
|
||||
#define HSQ_PERFORMANCE_DEPTH 5
|
||||
|
||||
struct hsq_slot {
|
||||
struct mmc_request *mrq;
|
||||
};
|
||||
|
@ -249,6 +249,7 @@ static struct variant_data variant_stm32 = {
|
||||
.f_max = 48000000,
|
||||
.pwrreg_clkgate = true,
|
||||
.pwrreg_nopower = true,
|
||||
.dma_flow_controller = true,
|
||||
.init = mmci_variant_init,
|
||||
};
|
||||
|
||||
@ -1015,7 +1016,7 @@ static int _mmci_dmae_prep_data(struct mmci_host *host, struct mmc_data *data,
|
||||
.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
|
||||
.src_maxburst = variant->fifohalfsize >> 2, /* # of words */
|
||||
.dst_maxburst = variant->fifohalfsize >> 2, /* # of words */
|
||||
.device_fc = false,
|
||||
.device_fc = variant->dma_flow_controller,
|
||||
};
|
||||
struct dma_chan *chan;
|
||||
struct dma_device *device;
|
||||
|
@ -332,6 +332,7 @@ enum mmci_busy_state {
|
||||
* @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register
|
||||
* @dma_lli: true if variant has dma link list feature.
|
||||
* @stm32_idmabsize_mask: stm32 sdmmc idma buffer size.
|
||||
* @dma_flow_controller: use peripheral as flow controller for DMA.
|
||||
*/
|
||||
struct variant_data {
|
||||
unsigned int clkreg;
|
||||
@ -378,6 +379,7 @@ struct variant_data {
|
||||
u8 dma_lli:1;
|
||||
u32 stm32_idmabsize_mask;
|
||||
u32 stm32_idmabsize_align;
|
||||
bool dma_flow_controller;
|
||||
void (*init)(struct mmci_host *host);
|
||||
};
|
||||
|
||||
|
@ -1154,32 +1154,52 @@ static void esdhc_post_tuning(struct sdhci_host *host)
|
||||
writel(reg, host->ioaddr + ESDHC_MIX_CTRL);
|
||||
}
|
||||
|
||||
/*
|
||||
* find the largest pass window, and use the average delay of this
|
||||
* largest window to get the best timing.
|
||||
*/
|
||||
static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
|
||||
{
|
||||
int min, max, avg, ret;
|
||||
int win_length, target_min, target_max, target_win_length;
|
||||
|
||||
/* find the mininum delay first which can pass tuning */
|
||||
min = ESDHC_TUNE_CTRL_MIN;
|
||||
while (min < ESDHC_TUNE_CTRL_MAX) {
|
||||
esdhc_prepare_tuning(host, min);
|
||||
if (!mmc_send_tuning(host->mmc, opcode, NULL))
|
||||
break;
|
||||
min += ESDHC_TUNE_CTRL_STEP;
|
||||
}
|
||||
|
||||
/* find the maxinum delay which can not pass tuning */
|
||||
max = min + ESDHC_TUNE_CTRL_STEP;
|
||||
max = ESDHC_TUNE_CTRL_MIN;
|
||||
target_win_length = 0;
|
||||
while (max < ESDHC_TUNE_CTRL_MAX) {
|
||||
esdhc_prepare_tuning(host, max);
|
||||
if (mmc_send_tuning(host->mmc, opcode, NULL)) {
|
||||
max -= ESDHC_TUNE_CTRL_STEP;
|
||||
break;
|
||||
/* find the mininum delay first which can pass tuning */
|
||||
while (min < ESDHC_TUNE_CTRL_MAX) {
|
||||
esdhc_prepare_tuning(host, min);
|
||||
if (!mmc_send_tuning(host->mmc, opcode, NULL))
|
||||
break;
|
||||
min += ESDHC_TUNE_CTRL_STEP;
|
||||
}
|
||||
max += ESDHC_TUNE_CTRL_STEP;
|
||||
|
||||
/* find the maxinum delay which can not pass tuning */
|
||||
max = min + ESDHC_TUNE_CTRL_STEP;
|
||||
while (max < ESDHC_TUNE_CTRL_MAX) {
|
||||
esdhc_prepare_tuning(host, max);
|
||||
if (mmc_send_tuning(host->mmc, opcode, NULL)) {
|
||||
max -= ESDHC_TUNE_CTRL_STEP;
|
||||
break;
|
||||
}
|
||||
max += ESDHC_TUNE_CTRL_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 + ESDHC_TUNE_CTRL_STEP;
|
||||
}
|
||||
|
||||
/* use average delay to get the best timing */
|
||||
avg = (min + max) / 2;
|
||||
avg = (target_min + target_max) / 2;
|
||||
esdhc_prepare_tuning(host, avg);
|
||||
ret = mmc_send_tuning(host->mmc, opcode, NULL);
|
||||
esdhc_post_tuning(host);
|
||||
|
94
drivers/mmc/host/sdhci-npcm.c
Normal file
94
drivers/mmc/host/sdhci-npcm.c
Normal file
@ -0,0 +1,94 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* NPCM SDHC MMC host controller driver.
|
||||
*
|
||||
* Copyright (c) 2023 Nuvoton Technology corporation.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/mmc.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include "sdhci-pltfm.h"
|
||||
|
||||
static const struct sdhci_pltfm_data npcm7xx_sdhci_pdata = {
|
||||
.quirks = SDHCI_QUIRK_DELAY_AFTER_POWER,
|
||||
.quirks2 = SDHCI_QUIRK2_STOP_WITH_TC |
|
||||
SDHCI_QUIRK2_NO_1_8_V,
|
||||
};
|
||||
|
||||
static const struct sdhci_pltfm_data npcm8xx_sdhci_pdata = {
|
||||
.quirks = SDHCI_QUIRK_DELAY_AFTER_POWER,
|
||||
.quirks2 = SDHCI_QUIRK2_STOP_WITH_TC,
|
||||
};
|
||||
|
||||
static int npcm_sdhci_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct sdhci_pltfm_data *data;
|
||||
struct sdhci_pltfm_host *pltfm_host;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct sdhci_host *host;
|
||||
u32 caps;
|
||||
int ret;
|
||||
|
||||
data = of_device_get_match_data(dev);
|
||||
if (!data)
|
||||
return -EINVAL;
|
||||
|
||||
host = sdhci_pltfm_init(pdev, data, 0);
|
||||
if (IS_ERR(host))
|
||||
return PTR_ERR(host);
|
||||
|
||||
pltfm_host = sdhci_priv(host);
|
||||
|
||||
pltfm_host->clk = devm_clk_get_optional_enabled(dev, NULL);
|
||||
if (IS_ERR(pltfm_host->clk)) {
|
||||
ret = PTR_ERR(pltfm_host->clk);
|
||||
goto err_sdhci;
|
||||
}
|
||||
|
||||
caps = sdhci_readl(host, SDHCI_CAPABILITIES);
|
||||
if (caps & SDHCI_CAN_DO_8BIT)
|
||||
host->mmc->caps |= MMC_CAP_8_BIT_DATA;
|
||||
|
||||
ret = mmc_of_parse(host->mmc);
|
||||
if (ret)
|
||||
goto err_sdhci;
|
||||
|
||||
ret = sdhci_add_host(host);
|
||||
if (ret)
|
||||
goto err_sdhci;
|
||||
|
||||
return 0;
|
||||
|
||||
err_sdhci:
|
||||
sdhci_pltfm_free(pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id npcm_sdhci_of_match[] = {
|
||||
{ .compatible = "nuvoton,npcm750-sdhci", .data = &npcm7xx_sdhci_pdata },
|
||||
{ .compatible = "nuvoton,npcm845-sdhci", .data = &npcm8xx_sdhci_pdata },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, npcm_sdhci_of_match);
|
||||
|
||||
static struct platform_driver npcm_sdhci_driver = {
|
||||
.driver = {
|
||||
.name = "npcm-sdhci",
|
||||
.of_match_table = npcm_sdhci_of_match,
|
||||
.pm = &sdhci_pltfm_pmops,
|
||||
},
|
||||
.probe = npcm_sdhci_probe,
|
||||
.remove_new = sdhci_pltfm_remove,
|
||||
};
|
||||
module_platform_driver(npcm_sdhci_driver);
|
||||
|
||||
MODULE_DESCRIPTION("NPCM Secure Digital Host Controller Interface driver");
|
||||
MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
|
||||
MODULE_LICENSE("GPL");
|
@ -483,11 +483,12 @@ static int __intel_dsm(struct intel_host *intel_host, struct device *dev,
|
||||
int err = 0;
|
||||
size_t len;
|
||||
|
||||
obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), &intel_dsm_guid, 0, fn, NULL);
|
||||
obj = acpi_evaluate_dsm_typed(ACPI_HANDLE(dev), &intel_dsm_guid, 0, fn, NULL,
|
||||
ACPI_TYPE_BUFFER);
|
||||
if (!obj)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (obj->type != ACPI_TYPE_BUFFER || obj->buffer.length < 1) {
|
||||
if (obj->buffer.length < 1) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
@ -25,6 +25,9 @@
|
||||
#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 SDHCI_GLI_9750_CFG2 0x848
|
||||
#define SDHCI_GLI_9750_CFG2_L1DLY GENMASK(28, 24)
|
||||
#define GLI_9750_CFG2_L1DLY_VALUE 0x1F
|
||||
@ -536,8 +539,12 @@ static void sdhci_gl9750_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
|
||||
static void gl9750_hw_setting(struct sdhci_host *host)
|
||||
{
|
||||
struct sdhci_pci_slot *slot = sdhci_priv(host);
|
||||
struct pci_dev *pdev;
|
||||
u32 value;
|
||||
|
||||
pdev = slot->chip->pdev;
|
||||
|
||||
gl9750_wt_on(host);
|
||||
|
||||
value = sdhci_readl(host, SDHCI_GLI_9750_CFG2);
|
||||
@ -547,6 +554,13 @@ static void gl9750_hw_setting(struct sdhci_host *host)
|
||||
GLI_9750_CFG2_L1DLY_VALUE);
|
||||
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);
|
||||
|
||||
gl9750_wt_off(host);
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/of.h>
|
||||
#ifdef CONFIG_PPC
|
||||
#include <asm/machdep.h>
|
||||
#endif
|
||||
@ -56,19 +55,16 @@ static bool sdhci_wp_inverted(struct device *dev)
|
||||
|
||||
static void sdhci_get_compatibility(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct sdhci_host *host = platform_get_drvdata(pdev);
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
|
||||
if (!np)
|
||||
return;
|
||||
|
||||
if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc"))
|
||||
if (device_is_compatible(dev, "fsl,p2020-rev1-esdhc"))
|
||||
host->quirks |= SDHCI_QUIRK_BROKEN_DMA;
|
||||
|
||||
if (of_device_is_compatible(np, "fsl,p2020-esdhc") ||
|
||||
of_device_is_compatible(np, "fsl,p1010-esdhc") ||
|
||||
of_device_is_compatible(np, "fsl,t4240-esdhc") ||
|
||||
of_device_is_compatible(np, "fsl,mpc8536-esdhc"))
|
||||
if (device_is_compatible(dev, "fsl,p2020-esdhc") ||
|
||||
device_is_compatible(dev, "fsl,p1010-esdhc") ||
|
||||
device_is_compatible(dev, "fsl,t4240-esdhc") ||
|
||||
device_is_compatible(dev, "fsl,mpc8536-esdhc"))
|
||||
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
|
||||
}
|
||||
|
||||
@ -115,26 +111,21 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
|
||||
{
|
||||
struct sdhci_host *host;
|
||||
void __iomem *ioaddr;
|
||||
int irq, ret;
|
||||
int irq;
|
||||
|
||||
ioaddr = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(ioaddr)) {
|
||||
ret = PTR_ERR(ioaddr);
|
||||
goto err;
|
||||
}
|
||||
if (IS_ERR(ioaddr))
|
||||
return ERR_CAST(ioaddr);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
ret = irq;
|
||||
goto err;
|
||||
}
|
||||
if (irq < 0)
|
||||
return ERR_PTR(irq);
|
||||
|
||||
host = sdhci_alloc_host(&pdev->dev,
|
||||
sizeof(struct sdhci_pltfm_host) + priv_size);
|
||||
|
||||
if (IS_ERR(host)) {
|
||||
ret = PTR_ERR(host);
|
||||
goto err;
|
||||
dev_err(&pdev->dev, "%s failed %pe\n", __func__, host);
|
||||
return ERR_CAST(host);
|
||||
}
|
||||
|
||||
host->ioaddr = ioaddr;
|
||||
@ -152,9 +143,6 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
|
||||
platform_set_drvdata(pdev, host);
|
||||
|
||||
return host;
|
||||
err:
|
||||
dev_err(&pdev->dev, "%s failed %d\n", __func__, ret);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_pltfm_init);
|
||||
|
||||
|
@ -512,7 +512,7 @@ static void new_system_port_status(struct vub300_mmc_host *vub300)
|
||||
vub300->card_present = 1;
|
||||
vub300->bus_width = 0;
|
||||
if (disable_offload_processing)
|
||||
strncpy(vub300->vub_name, "EMPTY Processing Disabled",
|
||||
strscpy(vub300->vub_name, "EMPTY Processing Disabled",
|
||||
sizeof(vub300->vub_name));
|
||||
else
|
||||
vub300->vub_name[0] = 0;
|
||||
@ -1216,7 +1216,7 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300,
|
||||
dev_err(&vub300->udev->dev,
|
||||
"corrupt offload pseudocode in firmware %s\n",
|
||||
vub300->vub_name);
|
||||
strncpy(vub300->vub_name, "corrupt offload pseudocode",
|
||||
strscpy(vub300->vub_name, "corrupt offload pseudocode",
|
||||
sizeof(vub300->vub_name));
|
||||
return;
|
||||
}
|
||||
@ -1250,7 +1250,7 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300,
|
||||
"not enough memory for xfer buffer to send"
|
||||
" INTERRUPT_PSEUDOCODE for %s %s\n", fw->data,
|
||||
vub300->vub_name);
|
||||
strncpy(vub300->vub_name,
|
||||
strscpy(vub300->vub_name,
|
||||
"SDIO interrupt pseudocode download failed",
|
||||
sizeof(vub300->vub_name));
|
||||
return;
|
||||
@ -1259,7 +1259,7 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300,
|
||||
dev_err(&vub300->udev->dev,
|
||||
"corrupt interrupt pseudocode in firmware %s %s\n",
|
||||
fw->data, vub300->vub_name);
|
||||
strncpy(vub300->vub_name, "corrupt interrupt pseudocode",
|
||||
strscpy(vub300->vub_name, "corrupt interrupt pseudocode",
|
||||
sizeof(vub300->vub_name));
|
||||
return;
|
||||
}
|
||||
@ -1293,7 +1293,7 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300,
|
||||
"not enough memory for xfer buffer to send"
|
||||
" TRANSFER_PSEUDOCODE for %s %s\n", fw->data,
|
||||
vub300->vub_name);
|
||||
strncpy(vub300->vub_name,
|
||||
strscpy(vub300->vub_name,
|
||||
"SDIO transfer pseudocode download failed",
|
||||
sizeof(vub300->vub_name));
|
||||
return;
|
||||
@ -1302,7 +1302,7 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300,
|
||||
dev_err(&vub300->udev->dev,
|
||||
"corrupt transfer pseudocode in firmware %s %s\n",
|
||||
fw->data, vub300->vub_name);
|
||||
strncpy(vub300->vub_name, "corrupt transfer pseudocode",
|
||||
strscpy(vub300->vub_name, "corrupt transfer pseudocode",
|
||||
sizeof(vub300->vub_name));
|
||||
return;
|
||||
}
|
||||
@ -1336,13 +1336,13 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300,
|
||||
dev_err(&vub300->udev->dev,
|
||||
"corrupt dynamic registers in firmware %s\n",
|
||||
vub300->vub_name);
|
||||
strncpy(vub300->vub_name, "corrupt dynamic registers",
|
||||
strscpy(vub300->vub_name, "corrupt dynamic registers",
|
||||
sizeof(vub300->vub_name));
|
||||
return;
|
||||
}
|
||||
|
||||
copy_error_message:
|
||||
strncpy(vub300->vub_name, "SDIO pseudocode download failed",
|
||||
strscpy(vub300->vub_name, "SDIO pseudocode download failed",
|
||||
sizeof(vub300->vub_name));
|
||||
}
|
||||
|
||||
@ -1370,11 +1370,11 @@ static void download_offload_pseudocode(struct vub300_mmc_host *vub300)
|
||||
vub300->vub_name);
|
||||
retval = request_firmware(&fw, vub300->vub_name, &card->dev);
|
||||
if (retval < 0) {
|
||||
strncpy(vub300->vub_name, "vub_default.bin",
|
||||
strscpy(vub300->vub_name, "vub_default.bin",
|
||||
sizeof(vub300->vub_name));
|
||||
retval = request_firmware(&fw, vub300->vub_name, &card->dev);
|
||||
if (retval < 0) {
|
||||
strncpy(vub300->vub_name,
|
||||
strscpy(vub300->vub_name,
|
||||
"no SDIO offload firmware found",
|
||||
sizeof(vub300->vub_name));
|
||||
} else {
|
||||
@ -1758,7 +1758,7 @@ static void vub300_cmndwork_thread(struct work_struct *work)
|
||||
* has been already downloaded to the VUB300 chip
|
||||
*/
|
||||
} else if (0 == vub300->mmc->card->sdio_funcs) {
|
||||
strncpy(vub300->vub_name, "SD memory device",
|
||||
strscpy(vub300->vub_name, "SD memory device",
|
||||
sizeof(vub300->vub_name));
|
||||
} else {
|
||||
download_offload_pseudocode(vub300);
|
||||
|
@ -526,6 +526,7 @@ struct mmc_host {
|
||||
|
||||
/* Host Software Queue support */
|
||||
bool hsq_enabled;
|
||||
int hsq_depth;
|
||||
|
||||
u32 err_stats[MMC_ERR_MAX];
|
||||
unsigned long private[] ____cacheline_aligned;
|
||||
|
Loading…
x
Reference in New Issue
Block a user