Commit 40aa597c authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 0364249d 5428a40a
# 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: ...@@ -59,6 +59,7 @@ properties:
- renesas,sdhi-r9a07g043 # RZ/G2UL - renesas,sdhi-r9a07g043 # RZ/G2UL
- renesas,sdhi-r9a07g044 # RZ/G2{L,LC} - renesas,sdhi-r9a07g044 # RZ/G2{L,LC}
- renesas,sdhi-r9a07g054 # RZ/V2L - renesas,sdhi-r9a07g054 # RZ/V2L
- renesas,sdhi-r9a08g045 # RZ/G3S
- renesas,sdhi-r9a09g011 # RZ/V2M - renesas,sdhi-r9a09g011 # RZ/V2M
- const: renesas,rcar-gen3-sdhi # R-Car Gen3 or RZ/G2 - const: renesas,rcar-gen3-sdhi # R-Car Gen3 or RZ/G2
- items: - items:
...@@ -122,6 +123,7 @@ allOf: ...@@ -122,6 +123,7 @@ allOf:
- renesas,sdhi-r9a07g043 - renesas,sdhi-r9a07g043
- renesas,sdhi-r9a07g044 - renesas,sdhi-r9a07g044
- renesas,sdhi-r9a07g054 - renesas,sdhi-r9a07g054
- renesas,sdhi-r9a08g045
- renesas,sdhi-r9a09g011 - renesas,sdhi-r9a09g011
then: then:
properties: properties:
......
...@@ -58,6 +58,7 @@ properties: ...@@ -58,6 +58,7 @@ properties:
- qcom,sm8350-sdhci - qcom,sm8350-sdhci
- qcom,sm8450-sdhci - qcom,sm8450-sdhci
- qcom,sm8550-sdhci - qcom,sm8550-sdhci
- qcom,sm8650-sdhci
- const: qcom,sdhci-msm-v5 # for sdcc version 5.0 - const: qcom,sdhci-msm-v5 # for sdcc version 5.0
reg: reg:
...@@ -85,10 +86,10 @@ properties: ...@@ -85,10 +86,10 @@ properties:
- const: iface - const: iface
- const: core - const: core
- const: xo - const: xo
- const: ice - enum: [ice, bus, cal, sleep]
- const: bus - enum: [ice, bus, cal, sleep]
- const: cal - enum: [ice, bus, cal, sleep]
- const: sleep - enum: [ice, bus, cal, sleep]
dma-coherent: true dma-coherent: true
......
...@@ -55,7 +55,6 @@ required: ...@@ -55,7 +55,6 @@ required:
- clocks - clocks
- clock-names - clock-names
- interrupts - interrupts
- starfive,sysreg
unevaluatedProperties: false unevaluatedProperties: false
...@@ -73,5 +72,4 @@ examples: ...@@ -73,5 +72,4 @@ examples:
fifo-depth = <32>; fifo-depth = <32>;
fifo-watermark-aligned; fifo-watermark-aligned;
data-addr = <0>; data-addr = <0>;
starfive,sysreg = <&sys_syscon 0x14 0x1a 0x7c000000>;
}; };
...@@ -14110,7 +14110,7 @@ F: Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml ...@@ -14110,7 +14110,7 @@ F: Documentation/devicetree/bindings/iio/adc/microchip,mcp3911.yaml
F: drivers/iio/adc/mcp3911.c F: drivers/iio/adc/mcp3911.c
MICROCHIP MMC/SD/SDIO MCI DRIVER MICROCHIP MMC/SD/SDIO MCI DRIVER
M: Ludovic Desroches <ludovic.desroches@microchip.com> M: Aubin Constans <aubin.constans@microchip.com>
S: Maintained S: Maintained
F: drivers/mmc/host/atmel-mci.c F: drivers/mmc/host/atmel-mci.c
...@@ -19335,7 +19335,8 @@ F: Documentation/devicetree/bindings/mmc/sdhci-common.yaml ...@@ -19335,7 +19335,8 @@ F: Documentation/devicetree/bindings/mmc/sdhci-common.yaml
F: drivers/mmc/host/sdhci* F: drivers/mmc/host/sdhci*
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) MICROCHIP DRIVER 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 L: linux-mmc@vger.kernel.org
S: Supported S: Supported
F: drivers/mmc/host/sdhci-of-at91.c F: drivers/mmc/host/sdhci-of-at91.c
......
...@@ -66,7 +66,7 @@ struct jmb38x_ms_host { ...@@ -66,7 +66,7 @@ struct jmb38x_ms_host {
struct jmb38x_ms { struct jmb38x_ms {
struct pci_dev *pdev; struct pci_dev *pdev;
int host_cnt; int host_cnt;
struct memstick_host *hosts[]; struct memstick_host *hosts[] __counted_by(host_cnt);
}; };
#define BLOCK_COUNT_MASK 0xffff0000 #define BLOCK_COUNT_MASK 0xffff0000
......
...@@ -12,9 +12,12 @@ ...@@ -12,9 +12,12 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/fault-inject.h> #include <linux/fault-inject.h>
#include <linux/time.h>
#include <linux/mmc/card.h> #include <linux/mmc/card.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h>
#include "core.h" #include "core.h"
#include "card.h" #include "card.h"
...@@ -298,6 +301,49 @@ static const struct file_operations mmc_err_stats_fops = { ...@@ -298,6 +301,49 @@ static const struct file_operations mmc_err_stats_fops = {
.release = single_release, .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) void mmc_add_host_debugfs(struct mmc_host *host)
{ {
struct dentry *root; struct dentry *root;
...@@ -306,8 +352,9 @@ void mmc_add_host_debugfs(struct mmc_host *host) ...@@ -306,8 +352,9 @@ void mmc_add_host_debugfs(struct mmc_host *host)
host->debugfs_root = root; host->debugfs_root = root;
debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops); debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops);
debugfs_create_x32("caps", S_IRUSR, root, &host->caps); debugfs_create_file("caps", 0600, root, &host->caps, &mmc_caps_fops);
debugfs_create_x32("caps2", S_IRUSR, root, &host->caps2); 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", S_IRUSR | S_IWUSR, root, host,
&mmc_clock_fops); &mmc_clock_fops);
......
...@@ -419,7 +419,6 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) ...@@ -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.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE]; 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_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT];
card->ext_csd.raw_erase_timeout_mult = card->ext_csd.raw_erase_timeout_mult =
...@@ -1732,6 +1731,12 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, ...@@ -1732,6 +1731,12 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
mmc_set_erase_size(card); 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. */ /* Enable ERASE_GRP_DEF. This bit is lost after a reset or power off. */
if (card->ext_csd.rev >= 3) { if (card->ext_csd.rev >= 3) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, 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, ...@@ -260,11 +260,7 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx,
} }
break; break;
case MMC_ISSUE_ASYNC: case MMC_ISSUE_ASYNC:
/* if (host->hsq_enabled && mq->in_flight[issue_type] > host->hsq_depth) {
* 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) {
spin_unlock_irq(&mq->lock); spin_unlock_irq(&mq->lock);
return BLK_STS_RESOURCE; return BLK_STS_RESOURCE;
} }
......
...@@ -429,6 +429,14 @@ config MMC_SDHCI_IPROC ...@@ -429,6 +429,14 @@ config MMC_SDHCI_IPROC
If unsure, say N. 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 config MMC_MESON_GX
tristate "Amlogic S905/GX*/AXG SD/MMC Host Controller support" tristate "Amlogic S905/GX*/AXG SD/MMC Host Controller support"
depends on ARCH_MESON|| COMPILE_TEST depends on ARCH_MESON|| COMPILE_TEST
...@@ -677,9 +685,9 @@ config MMC_SDHI_SYS_DMAC ...@@ -677,9 +685,9 @@ config MMC_SDHI_SYS_DMAC
config MMC_SDHI_INTERNAL_DMAC config MMC_SDHI_INTERNAL_DMAC
tristate "DMA for SDHI SD/SDIO controllers using on-chip bus mastering" 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 depends on MMC_SDHI
default MMC_SDHI if (ARM64 || ARCH_R7S9210 || ARCH_R8A77470) default MMC_SDHI if ARCH_RENESAS
help help
This provides DMA support for SDHI SD/SDIO controllers This provides DMA support for SDHI SD/SDIO controllers
using on-chip bus mastering. This supports the controllers using on-chip bus mastering. This supports the controllers
......
...@@ -89,6 +89,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_DWCMSHC) += sdhci-of-dwcmshc.o ...@@ -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_OF_SPARX5) += sdhci-of-sparx5.o
obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o
obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.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_MSM) += sdhci-msm.o
obj-$(CONFIG_MMC_SDHCI_ST) += sdhci-st.o obj-$(CONFIG_MMC_SDHCI_ST) += sdhci-st.o
obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32) += sdhci-pic32.o obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32) += sdhci-pic32.o
......
...@@ -227,6 +227,7 @@ struct mci_slot_pdata { ...@@ -227,6 +227,7 @@ struct mci_slot_pdata {
/** /**
* struct mci_platform_data - board-specific MMC/SDcard configuration * struct mci_platform_data - board-specific MMC/SDcard configuration
* @dma_slave: DMA slave interface to use in data transfers. * @dma_slave: DMA slave interface to use in data transfers.
* @dma_filter: Filtering function to filter the DMA channel
* @slot: Per-slot configuration data. * @slot: Per-slot configuration data.
*/ */
struct mci_platform_data { struct mci_platform_data {
...@@ -674,8 +675,10 @@ atmci_of_init(struct platform_device *pdev) ...@@ -674,8 +675,10 @@ atmci_of_init(struct platform_device *pdev)
"cd", GPIOD_IN, "cd-gpios"); "cd", GPIOD_IN, "cd-gpios");
err = PTR_ERR_OR_ZERO(pdata->slot[slot_id].detect_pin); err = PTR_ERR_OR_ZERO(pdata->slot[slot_id].detect_pin);
if (err) { if (err) {
if (err != -ENOENT) if (err != -ENOENT) {
of_node_put(cnp);
return ERR_PTR(err); return ERR_PTR(err);
}
pdata->slot[slot_id].detect_pin = NULL; pdata->slot[slot_id].detect_pin = NULL;
} }
...@@ -687,8 +690,10 @@ atmci_of_init(struct platform_device *pdev) ...@@ -687,8 +690,10 @@ atmci_of_init(struct platform_device *pdev)
"wp", GPIOD_IN, "wp-gpios"); "wp", GPIOD_IN, "wp-gpios");
err = PTR_ERR_OR_ZERO(pdata->slot[slot_id].wp_pin); err = PTR_ERR_OR_ZERO(pdata->slot[slot_id].wp_pin);
if (err) { if (err) {
if (err != -ENOENT) if (err != -ENOENT) {
of_node_put(cnp);
return ERR_PTR(err); return ERR_PTR(err);
}
pdata->slot[slot_id].wp_pin = NULL; pdata->slot[slot_id].wp_pin = NULL;
} }
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* Copyright (c) 2022 StarFive Technology Co., Ltd. * Copyright (c) 2022 StarFive Technology Co., Ltd.
*/ */
#include <linux/bitfield.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
...@@ -20,13 +21,7 @@ ...@@ -20,13 +21,7 @@
#define ALL_INT_CLR 0x1ffff #define ALL_INT_CLR 0x1ffff
#define MAX_DELAY_CHAIN 32 #define MAX_DELAY_CHAIN 32
struct starfive_priv { #define STARFIVE_SMPL_PHASE GENMASK(20, 16)
struct device *dev;
struct regmap *reg_syscon;
u32 syscon_offset;
u32 syscon_shift;
u32 syscon_mask;
};
static void dw_mci_starfive_set_ios(struct dw_mci *host, struct mmc_ios *ios) 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) ...@@ -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, static int dw_mci_starfive_execute_tuning(struct dw_mci_slot *slot,
u32 opcode) u32 opcode)
{ {
static const int grade = MAX_DELAY_CHAIN; static const int grade = MAX_DELAY_CHAIN;
struct dw_mci *host = slot->host; struct dw_mci *host = slot->host;
struct starfive_priv *priv = host->priv; int smpl_phase, smpl_raise = -1, smpl_fall = -1;
int rise_point = -1, fall_point = -1; int ret;
int err, prev_err = 0;
int i; for (smpl_phase = 0; smpl_phase < grade; smpl_phase++) {
bool found = 0; dw_mci_starfive_set_sample_phase(host, smpl_phase);
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); mci_writel(host, RINTSTS, ALL_INT_CLR);
err = mmc_send_tuning(slot->mmc, opcode, NULL); ret = mmc_send_tuning(slot->mmc, opcode, NULL);
if (!err)
found = 1;
if (i > 0) { if (!ret && smpl_raise < 0) {
if (err && !prev_err) smpl_raise = smpl_phase;
fall_point = i - 1; } else if (ret && smpl_raise >= 0) {
if (!err && prev_err) smpl_fall = smpl_phase - 1;
rise_point = i; break;
} }
if (rise_point != -1 && fall_point != -1)
goto tuning_out;
prev_err = err;
err = 0;
} }
tuning_out: if (smpl_phase >= grade)
if (found) { smpl_fall = grade - 1;
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); if (smpl_raise < 0) {
} else { smpl_phase = 0;
dev_err(host->dev, "No valid delay chain! use default\n"); dev_err(host->dev, "No valid delay chain! use default\n");
err = -EINVAL; ret = -EINVAL;
goto out;
} }
mci_writel(host, RINTSTS, ALL_INT_CLR); smpl_phase = (smpl_raise + smpl_fall) / 2;
return err; dev_dbg(host->dev, "Found valid delay chain! use it [delay=%d]\n", smpl_phase);
} ret = 0;
static int dw_mci_starfive_parse_dt(struct dw_mci *host)
{
struct of_phandle_args args;
struct starfive_priv *priv;
int ret;
priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
ret = of_parse_phandle_with_fixed_args(host->dev->of_node, out:
"starfive,sysreg", 3, 0, &args); dw_mci_starfive_set_sample_phase(host, smpl_phase);
if (ret) { mci_writel(host, RINTSTS, ALL_INT_CLR);
dev_err(host->dev, "Failed to parse starfive,sysreg\n"); return ret;
return -EINVAL;
}
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);
priv->syscon_offset = args.args[0];
priv->syscon_shift = args.args[1];
priv->syscon_mask = args.args[2];
host->priv = priv;
return 0;
} }
static const struct dw_mci_drv_data starfive_data = { static const struct dw_mci_drv_data starfive_data = {
.common_caps = MMC_CAP_CMD23, .common_caps = MMC_CAP_CMD23,
.set_ios = dw_mci_starfive_set_ios, .set_ios = dw_mci_starfive_set_ios,
.parse_dt = dw_mci_starfive_parse_dt,
.execute_tuning = dw_mci_starfive_execute_tuning, .execute_tuning = dw_mci_starfive_execute_tuning,
}; };
......
...@@ -18,9 +18,10 @@ ...@@ -18,9 +18,10 @@
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/slot-gpio.h> #include <linux/mmc/slot-gpio.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of.h>
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
...@@ -1040,7 +1041,6 @@ static int jz4740_mmc_probe(struct platform_device* pdev) ...@@ -1040,7 +1041,6 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
int ret; int ret;
struct mmc_host *mmc; struct mmc_host *mmc;
struct jz4740_mmc_host *host; struct jz4740_mmc_host *host;
const struct of_device_id *match;
mmc = mmc_alloc_host(sizeof(struct jz4740_mmc_host), &pdev->dev); mmc = mmc_alloc_host(sizeof(struct jz4740_mmc_host), &pdev->dev);
if (!mmc) { if (!mmc) {
...@@ -1050,13 +1050,8 @@ static int jz4740_mmc_probe(struct platform_device* pdev) ...@@ -1050,13 +1050,8 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
host = mmc_priv(mmc); host = mmc_priv(mmc);
match = of_match_device(jz4740_mmc_of_match, &pdev->dev); /* Default if no match is JZ4740 */
if (match) { host->version = (enum jz4740_mmc_version)device_get_match_data(&pdev->dev);
host->version = (enum jz4740_mmc_version)match->data;
} else {
/* JZ4740 should be the only one using legacy probe */
host->version = JZ_MMC_JZ4740;
}
ret = mmc_of_parse(mmc); ret = mmc_of_parse(mmc);
if (ret) { if (ret) {
...@@ -1200,7 +1195,7 @@ static struct platform_driver jz4740_mmc_driver = { ...@@ -1200,7 +1195,7 @@ static struct platform_driver jz4740_mmc_driver = {
.driver = { .driver = {
.name = "jz4740-mmc", .name = "jz4740-mmc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .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), .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) ...@@ -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 |= FIELD_PREP(CMD_CFG_CMD_INDEX_MASK, cmd->opcode);
cmd_cfg |= CMD_CFG_OWNER; /* owned by CPU */ 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); meson_mmc_set_response_bits(cmd, &cmd_cfg);
......
...@@ -21,6 +21,25 @@ static void mmc_hsq_retry_handler(struct work_struct *work) ...@@ -21,6 +21,25 @@ static void mmc_hsq_retry_handler(struct work_struct *work)
mmc->ops->request(mmc, hsq->mrq); 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) static void mmc_hsq_pump_requests(struct mmc_hsq *hsq)
{ {
struct mmc_host *mmc = hsq->mmc; struct mmc_host *mmc = hsq->mmc;
...@@ -42,6 +61,8 @@ static void mmc_hsq_pump_requests(struct mmc_hsq *hsq) ...@@ -42,6 +61,8 @@ static void mmc_hsq_pump_requests(struct mmc_hsq *hsq)
return; return;
} }
mmc_hsq_modify_threshold(hsq);
slot = &hsq->slot[hsq->next_tag]; slot = &hsq->slot[hsq->next_tag];
hsq->mrq = slot->mrq; hsq->mrq = slot->mrq;
hsq->qcnt--; hsq->qcnt--;
...@@ -337,6 +358,7 @@ int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc) ...@@ -337,6 +358,7 @@ int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc)
hsq->mmc = mmc; hsq->mmc = mmc;
hsq->mmc->cqe_private = hsq; hsq->mmc->cqe_private = hsq;
mmc->cqe_ops = &mmc_hsq_ops; mmc->cqe_ops = &mmc_hsq_ops;
mmc->hsq_depth = HSQ_NORMAL_DEPTH;
for (i = 0; i < HSQ_NUM_SLOTS; i++) for (i = 0; i < HSQ_NUM_SLOTS; i++)
hsq->tag_slot[i] = HSQ_INVALID_TAG; hsq->tag_slot[i] = HSQ_INVALID_TAG;
......
...@@ -5,6 +5,17 @@ ...@@ -5,6 +5,17 @@
#define HSQ_NUM_SLOTS 64 #define HSQ_NUM_SLOTS 64
#define HSQ_INVALID_TAG HSQ_NUM_SLOTS #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 hsq_slot {
struct mmc_request *mrq; struct mmc_request *mrq;
}; };
......
...@@ -249,6 +249,7 @@ static struct variant_data variant_stm32 = { ...@@ -249,6 +249,7 @@ static struct variant_data variant_stm32 = {
.f_max = 48000000, .f_max = 48000000,
.pwrreg_clkgate = true, .pwrreg_clkgate = true,
.pwrreg_nopower = true, .pwrreg_nopower = true,
.dma_flow_controller = true,
.init = mmci_variant_init, .init = mmci_variant_init,
}; };
...@@ -1015,7 +1016,7 @@ static int _mmci_dmae_prep_data(struct mmci_host *host, struct mmc_data *data, ...@@ -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, .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
.src_maxburst = variant->fifohalfsize >> 2, /* # of words */ .src_maxburst = variant->fifohalfsize >> 2, /* # of words */
.dst_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_chan *chan;
struct dma_device *device; struct dma_device *device;
......
...@@ -332,6 +332,7 @@ enum mmci_busy_state { ...@@ -332,6 +332,7 @@ enum mmci_busy_state {
* @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register * @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register
* @dma_lli: true if variant has dma link list feature. * @dma_lli: true if variant has dma link list feature.
* @stm32_idmabsize_mask: stm32 sdmmc idma buffer size. * @stm32_idmabsize_mask: stm32 sdmmc idma buffer size.
* @dma_flow_controller: use peripheral as flow controller for DMA.
*/ */
struct variant_data { struct variant_data {
unsigned int clkreg; unsigned int clkreg;
...@@ -378,6 +379,7 @@ struct variant_data { ...@@ -378,6 +379,7 @@ struct variant_data {
u8 dma_lli:1; u8 dma_lli:1;
u32 stm32_idmabsize_mask; u32 stm32_idmabsize_mask;
u32 stm32_idmabsize_align; u32 stm32_idmabsize_align;
bool dma_flow_controller;
void (*init)(struct mmci_host *host); void (*init)(struct mmci_host *host);
}; };
......
...@@ -1154,32 +1154,52 @@ static void esdhc_post_tuning(struct sdhci_host *host) ...@@ -1154,32 +1154,52 @@ static void esdhc_post_tuning(struct sdhci_host *host)
writel(reg, host->ioaddr + ESDHC_MIX_CTRL); 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) static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
{ {
int min, max, avg, ret; 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; min = ESDHC_TUNE_CTRL_MIN;
while (min < ESDHC_TUNE_CTRL_MAX) { max = ESDHC_TUNE_CTRL_MIN;
esdhc_prepare_tuning(host, min); target_win_length = 0;
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;
while (max < ESDHC_TUNE_CTRL_MAX) { while (max < ESDHC_TUNE_CTRL_MAX) {
esdhc_prepare_tuning(host, max); /* find the mininum delay first which can pass tuning */
if (mmc_send_tuning(host->mmc, opcode, NULL)) { while (min < ESDHC_TUNE_CTRL_MAX) {
max -= ESDHC_TUNE_CTRL_STEP; esdhc_prepare_tuning(host, min);
break; 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 */ /* use average delay to get the best timing */
avg = (min + max) / 2; avg = (target_min + target_max) / 2;
esdhc_prepare_tuning(host, avg); esdhc_prepare_tuning(host, avg);
ret = mmc_send_tuning(host->mmc, opcode, NULL); ret = mmc_send_tuning(host->mmc, opcode, NULL);
esdhc_post_tuning(host); esdhc_post_tuning(host);
......
// 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, ...@@ -483,11 +483,12 @@ static int __intel_dsm(struct intel_host *intel_host, struct device *dev,
int err = 0; int err = 0;
size_t len; 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) if (!obj)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (obj->type != ACPI_TYPE_BUFFER || obj->buffer.length < 1) { if (obj->buffer.length < 1) {
err = -EINVAL; err = -EINVAL;
goto out; goto out;
} }
......
...@@ -25,6 +25,9 @@ ...@@ -25,6 +25,9 @@
#define GLI_9750_WT_EN_ON 0x1 #define GLI_9750_WT_EN_ON 0x1
#define GLI_9750_WT_EN_OFF 0x0 #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 0x848
#define SDHCI_GLI_9750_CFG2_L1DLY GENMASK(28, 24) #define SDHCI_GLI_9750_CFG2_L1DLY GENMASK(28, 24)
#define GLI_9750_CFG2_L1DLY_VALUE 0x1F #define GLI_9750_CFG2_L1DLY_VALUE 0x1F
...@@ -536,8 +539,12 @@ static void sdhci_gl9750_set_clock(struct sdhci_host *host, unsigned int clock) ...@@ -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) static void gl9750_hw_setting(struct sdhci_host *host)
{ {
struct sdhci_pci_slot *slot = sdhci_priv(host);
struct pci_dev *pdev;
u32 value; u32 value;
pdev = slot->chip->pdev;
gl9750_wt_on(host); gl9750_wt_on(host);
value = sdhci_readl(host, SDHCI_GLI_9750_CFG2); value = sdhci_readl(host, SDHCI_GLI_9750_CFG2);
...@@ -547,6 +554,13 @@ static void gl9750_hw_setting(struct sdhci_host *host) ...@@ -547,6 +554,13 @@ static void gl9750_hw_setting(struct sdhci_host *host)
GLI_9750_CFG2_L1DLY_VALUE); GLI_9750_CFG2_L1DLY_VALUE);
sdhci_writel(host, value, SDHCI_GLI_9750_CFG2); 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); gl9750_wt_off(host);
} }
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/property.h> #include <linux/property.h>
#include <linux/of.h>
#ifdef CONFIG_PPC #ifdef CONFIG_PPC
#include <asm/machdep.h> #include <asm/machdep.h>
#endif #endif
...@@ -56,19 +55,16 @@ static bool sdhci_wp_inverted(struct device *dev) ...@@ -56,19 +55,16 @@ static bool sdhci_wp_inverted(struct device *dev)
static void sdhci_get_compatibility(struct platform_device *pdev) static void sdhci_get_compatibility(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev;
struct sdhci_host *host = platform_get_drvdata(pdev); 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; host->quirks |= SDHCI_QUIRK_BROKEN_DMA;
if (of_device_is_compatible(np, "fsl,p2020-esdhc") || if (device_is_compatible(dev, "fsl,p2020-esdhc") ||
of_device_is_compatible(np, "fsl,p1010-esdhc") || device_is_compatible(dev, "fsl,p1010-esdhc") ||
of_device_is_compatible(np, "fsl,t4240-esdhc") || device_is_compatible(dev, "fsl,t4240-esdhc") ||
of_device_is_compatible(np, "fsl,mpc8536-esdhc")) device_is_compatible(dev, "fsl,mpc8536-esdhc"))
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
} }
...@@ -115,26 +111,21 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, ...@@ -115,26 +111,21 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
{ {
struct sdhci_host *host; struct sdhci_host *host;
void __iomem *ioaddr; void __iomem *ioaddr;
int irq, ret; int irq;
ioaddr = devm_platform_ioremap_resource(pdev, 0); ioaddr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(ioaddr)) { if (IS_ERR(ioaddr))
ret = PTR_ERR(ioaddr); return ERR_CAST(ioaddr);
goto err;
}
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) { if (irq < 0)
ret = irq; return ERR_PTR(irq);
goto err;
}
host = sdhci_alloc_host(&pdev->dev, host = sdhci_alloc_host(&pdev->dev,
sizeof(struct sdhci_pltfm_host) + priv_size); sizeof(struct sdhci_pltfm_host) + priv_size);
if (IS_ERR(host)) { if (IS_ERR(host)) {
ret = PTR_ERR(host); dev_err(&pdev->dev, "%s failed %pe\n", __func__, host);
goto err; return ERR_CAST(host);
} }
host->ioaddr = ioaddr; host->ioaddr = ioaddr;
...@@ -152,9 +143,6 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, ...@@ -152,9 +143,6 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
platform_set_drvdata(pdev, host); platform_set_drvdata(pdev, host);
return host; return host;
err:
dev_err(&pdev->dev, "%s failed %d\n", __func__, ret);
return ERR_PTR(ret);
} }
EXPORT_SYMBOL_GPL(sdhci_pltfm_init); EXPORT_SYMBOL_GPL(sdhci_pltfm_init);
......
...@@ -512,7 +512,7 @@ static void new_system_port_status(struct vub300_mmc_host *vub300) ...@@ -512,7 +512,7 @@ static void new_system_port_status(struct vub300_mmc_host *vub300)
vub300->card_present = 1; vub300->card_present = 1;
vub300->bus_width = 0; vub300->bus_width = 0;
if (disable_offload_processing) if (disable_offload_processing)
strncpy(vub300->vub_name, "EMPTY Processing Disabled", strscpy(vub300->vub_name, "EMPTY Processing Disabled",
sizeof(vub300->vub_name)); sizeof(vub300->vub_name));
else else
vub300->vub_name[0] = 0; vub300->vub_name[0] = 0;
...@@ -1216,7 +1216,7 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300, ...@@ -1216,7 +1216,7 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300,
dev_err(&vub300->udev->dev, dev_err(&vub300->udev->dev,
"corrupt offload pseudocode in firmware %s\n", "corrupt offload pseudocode in firmware %s\n",
vub300->vub_name); vub300->vub_name);
strncpy(vub300->vub_name, "corrupt offload pseudocode", strscpy(vub300->vub_name, "corrupt offload pseudocode",
sizeof(vub300->vub_name)); sizeof(vub300->vub_name));
return; return;
} }
...@@ -1250,7 +1250,7 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300, ...@@ -1250,7 +1250,7 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300,
"not enough memory for xfer buffer to send" "not enough memory for xfer buffer to send"
" INTERRUPT_PSEUDOCODE for %s %s\n", fw->data, " INTERRUPT_PSEUDOCODE for %s %s\n", fw->data,
vub300->vub_name); vub300->vub_name);
strncpy(vub300->vub_name, strscpy(vub300->vub_name,
"SDIO interrupt pseudocode download failed", "SDIO interrupt pseudocode download failed",
sizeof(vub300->vub_name)); sizeof(vub300->vub_name));
return; return;
...@@ -1259,7 +1259,7 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300, ...@@ -1259,7 +1259,7 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300,
dev_err(&vub300->udev->dev, dev_err(&vub300->udev->dev,
"corrupt interrupt pseudocode in firmware %s %s\n", "corrupt interrupt pseudocode in firmware %s %s\n",
fw->data, vub300->vub_name); fw->data, vub300->vub_name);
strncpy(vub300->vub_name, "corrupt interrupt pseudocode", strscpy(vub300->vub_name, "corrupt interrupt pseudocode",
sizeof(vub300->vub_name)); sizeof(vub300->vub_name));
return; return;
} }
...@@ -1293,7 +1293,7 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300, ...@@ -1293,7 +1293,7 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300,
"not enough memory for xfer buffer to send" "not enough memory for xfer buffer to send"
" TRANSFER_PSEUDOCODE for %s %s\n", fw->data, " TRANSFER_PSEUDOCODE for %s %s\n", fw->data,
vub300->vub_name); vub300->vub_name);
strncpy(vub300->vub_name, strscpy(vub300->vub_name,
"SDIO transfer pseudocode download failed", "SDIO transfer pseudocode download failed",
sizeof(vub300->vub_name)); sizeof(vub300->vub_name));
return; return;
...@@ -1302,7 +1302,7 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300, ...@@ -1302,7 +1302,7 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300,
dev_err(&vub300->udev->dev, dev_err(&vub300->udev->dev,
"corrupt transfer pseudocode in firmware %s %s\n", "corrupt transfer pseudocode in firmware %s %s\n",
fw->data, vub300->vub_name); fw->data, vub300->vub_name);
strncpy(vub300->vub_name, "corrupt transfer pseudocode", strscpy(vub300->vub_name, "corrupt transfer pseudocode",
sizeof(vub300->vub_name)); sizeof(vub300->vub_name));
return; return;
} }
...@@ -1336,13 +1336,13 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300, ...@@ -1336,13 +1336,13 @@ static void __download_offload_pseudocode(struct vub300_mmc_host *vub300,
dev_err(&vub300->udev->dev, dev_err(&vub300->udev->dev,
"corrupt dynamic registers in firmware %s\n", "corrupt dynamic registers in firmware %s\n",
vub300->vub_name); vub300->vub_name);
strncpy(vub300->vub_name, "corrupt dynamic registers", strscpy(vub300->vub_name, "corrupt dynamic registers",
sizeof(vub300->vub_name)); sizeof(vub300->vub_name));
return; return;
} }
copy_error_message: copy_error_message:
strncpy(vub300->vub_name, "SDIO pseudocode download failed", strscpy(vub300->vub_name, "SDIO pseudocode download failed",
sizeof(vub300->vub_name)); sizeof(vub300->vub_name));
} }
...@@ -1370,11 +1370,11 @@ static void download_offload_pseudocode(struct vub300_mmc_host *vub300) ...@@ -1370,11 +1370,11 @@ static void download_offload_pseudocode(struct vub300_mmc_host *vub300)
vub300->vub_name); vub300->vub_name);
retval = request_firmware(&fw, vub300->vub_name, &card->dev); retval = request_firmware(&fw, vub300->vub_name, &card->dev);
if (retval < 0) { if (retval < 0) {
strncpy(vub300->vub_name, "vub_default.bin", strscpy(vub300->vub_name, "vub_default.bin",
sizeof(vub300->vub_name)); sizeof(vub300->vub_name));
retval = request_firmware(&fw, vub300->vub_name, &card->dev); retval = request_firmware(&fw, vub300->vub_name, &card->dev);
if (retval < 0) { if (retval < 0) {
strncpy(vub300->vub_name, strscpy(vub300->vub_name,
"no SDIO offload firmware found", "no SDIO offload firmware found",
sizeof(vub300->vub_name)); sizeof(vub300->vub_name));
} else { } else {
...@@ -1758,7 +1758,7 @@ static void vub300_cmndwork_thread(struct work_struct *work) ...@@ -1758,7 +1758,7 @@ static void vub300_cmndwork_thread(struct work_struct *work)
* has been already downloaded to the VUB300 chip * has been already downloaded to the VUB300 chip
*/ */
} else if (0 == vub300->mmc->card->sdio_funcs) { } 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)); sizeof(vub300->vub_name));
} else { } else {
download_offload_pseudocode(vub300); download_offload_pseudocode(vub300);
......
...@@ -526,6 +526,7 @@ struct mmc_host { ...@@ -526,6 +526,7 @@ struct mmc_host {
/* Host Software Queue support */ /* Host Software Queue support */
bool hsq_enabled; bool hsq_enabled;
int hsq_depth;
u32 err_stats[MMC_ERR_MAX]; u32 err_stats[MMC_ERR_MAX];
unsigned long private[] ____cacheline_aligned; unsigned long private[] ____cacheline_aligned;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment