Commit 89181f54 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull MMC updates from Ulf Hansson:
 "MMC core:
   - Allow synchronous detection of (e)MMC/SD/SDIO cards
   - Fixup error check for ioctls for SPI hosts
   - Disable broken SD-Cache support for Kingston Canvas Go Plus from 2019
   - Disable broken eMMC-Trim support for Kingston EMMC04G-M627
   - Disable broken eMMC-Trim support for Micron MTFC4GACAJCN-1M

  MMC host:
   - bcm2835: Convert DT bindings to YAML
   - mmci:
      - Enable asynchronous probe
      - Transform the ux500 HW-busy detection into a proper state machine
      - Add support for SW busy-end timeouts for the ux500 variants
   - mmci_stm32:
      - Add support for sdm32 variant revision v3.0 used on STM32MP25
      - Improve the tuning sequence
   - mtk-sd: Tune polling-period to improve performance
   - sdhci: Fixup DMA configuration for 64-bit DMA mode
   - sdhci-bcm-kona: Convert DT bindings to YAML
   - sdhci-msm:
      - Switch to use the new ICE API
      - Add support for the SC8280XP/IPQ6018/QDU1000/QRU1000 variants
   - sdhci-pci-gli:
      - Add support SD Express cards for GL9767
      - Add support for the Genesys Logic GL9767 variant"

* tag 'mmc-v6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (42 commits)
  dt-bindings: mmc: fsl-imx-esdhc: Add imx6ul support
  mmc: mmci: Add support for SW busy-end timeouts
  mmc: Add MMC_QUIRK_BROKEN_SD_CACHE for Kingston Canvas Go Plus from 11/2019
  mmc: core: disable TRIM on Kingston EMMC04G-M627
  mmc: mmci: stm32: add delay block support for STM32MP25
  mmc: mmci: stm32: prepare other delay block support
  mmc: mmci: stm32: manage block gap hardware flow control
  mmc: mmci: Add support for sdmmc variant revision v3.0
  mmc: mmci: add stm32_idmabsize_align parameter
  dt-bindings: mmc: mmci: Add st,stm32mp25-sdmmc2 compatible
  mmc: core: disable TRIM on Micron MTFC4GACAJCN-1M
  mmc: mmci: Break out a helper function
  mmc: mmci: Use a switch statement machine
  mmc: mmci: Use state machine state as exit condition
  mmc: mmci: Retry the busy start condition
  mmc: mmci: Make busy complete state machine explicit
  mmc: mmci: Break out error check in busy detect
  mmc: mmci: Stash status while waiting for busy
  mmc: mmci: Unwind big if() clause
  mmc: mmci: Clear busy_status when starting command
  ...
parents 1364b406 06b5d4fe
...@@ -53,10 +53,11 @@ properties: ...@@ -53,10 +53,11 @@ properties:
items: items:
- const: arm,pl18x - const: arm,pl18x
- const: arm,primecell - const: arm,primecell
- description: Entry for STMicroelectronics variant of PL18x. - description: Entries for STMicroelectronics variant of PL18x.
This dedicated compatible is used by bootloaders.
items: items:
- const: st,stm32-sdmmc2 - enum:
- st,stm32-sdmmc2
- st,stm32mp25-sdmmc2
- const: arm,pl18x - const: arm,pl18x
- const: arm,primecell - const: arm,primecell
......
Broadcom BCM2835 SDHOST controller
This file documents differences between the core properties described
by mmc.txt and the properties that represent the BCM2835 controller.
Required properties:
- compatible: Should be "brcm,bcm2835-sdhost".
- clocks: The clock feeding the SDHOST controller.
Optional properties:
- dmas: DMA channel for read and write.
See Documentation/devicetree/bindings/dma/dma.txt for details
Example:
sdhost: mmc@7e202000 {
compatible = "brcm,bcm2835-sdhost";
reg = <0x7e202000 0x100>;
interrupts = <2 24>;
clocks = <&clocks BCM2835_CLOCK_VPU>;
dmas = <&dma 13>;
dma-names = "rx-tx";
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/mmc/brcm,bcm2835-sdhost.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Broadcom BCM2835 SDHOST controller
maintainers:
- Stefan Wahren <stefan.wahren@i2se.com>
allOf:
- $ref: mmc-controller.yaml
properties:
compatible:
const: brcm,bcm2835-sdhost
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
dmas:
maxItems: 1
dma-names:
const: rx-tx
required:
- compatible
- reg
- interrupts
- clocks
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/bcm2835.h>
sdhost: mmc@7e202000 {
compatible = "brcm,bcm2835-sdhost";
reg = <0x7e202000 0x100>;
interrupts = <2 24>;
clocks = <&clocks BCM2835_CLOCK_VPU>;
dmas = <&dma 13>;
dma-names = "rx-tx";
bus-width = <4>;
};
Broadcom BCM281xx SDHCI
This file documents differences between the core properties in mmc.txt
and the properties present in the bcm281xx SDHCI
Required properties:
- compatible : Should be "brcm,kona-sdhci"
- DEPRECATED: compatible : Should be "bcm,kona-sdhci"
- clocks: phandle + clock specifier pair of the external clock
Refer to clocks/clock-bindings.txt for generic clock consumer properties.
Example:
sdio2: sdio@3f1a0000 {
compatible = "brcm,kona-sdhci";
reg = <0x3f1a0000 0x10000>;
clocks = <&sdio3_clk>;
interrupts = <0x0 74 0x4>;
};
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/mmc/brcm,kona-sdhci.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Broadcom Kona family SDHCI controller
maintainers:
- Florian Fainelli <f.fainelli@gmail.com>
allOf:
- $ref: sdhci-common.yaml#
properties:
compatible:
const: brcm,kona-sdhci
reg:
maxItems: 1
clocks:
maxItems: 1
interrupts:
maxItems: 1
required:
- compatible
- reg
- clocks
- interrupts
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/clock/bcm281xx.h>
mmc@3f1a0000 {
compatible = "brcm,kona-sdhci";
reg = <0x3f1a0000 0x10000>;
clocks = <&master_ccu BCM281XX_MASTER_CCU_SDIO3>;
interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
};
...
...@@ -42,6 +42,7 @@ properties: ...@@ -42,6 +42,7 @@ properties:
- enum: - enum:
- fsl,imx6sll-usdhc - fsl,imx6sll-usdhc
- fsl,imx6ull-usdhc - fsl,imx6ull-usdhc
- fsl,imx6ul-usdhc
- const: fsl,imx6sx-usdhc - const: fsl,imx6sx-usdhc
- items: - items:
- const: fsl,imx7d-usdhc - const: fsl,imx7d-usdhc
......
...@@ -36,11 +36,14 @@ properties: ...@@ -36,11 +36,14 @@ properties:
- enum: - enum:
- qcom,ipq5018-sdhci - qcom,ipq5018-sdhci
- qcom,ipq5332-sdhci - qcom,ipq5332-sdhci
- qcom,ipq6018-sdhci
- qcom,ipq9574-sdhci - qcom,ipq9574-sdhci
- qcom,qcm2290-sdhci - qcom,qcm2290-sdhci
- qcom,qcs404-sdhci - qcom,qcs404-sdhci
- qcom,qdu1000-sdhci
- qcom,sc7180-sdhci - qcom,sc7180-sdhci
- qcom,sc7280-sdhci - qcom,sc7280-sdhci
- qcom,sc8280xp-sdhci
- qcom,sdm630-sdhci - qcom,sdm630-sdhci
- qcom,sdm670-sdhci - qcom,sdm670-sdhci
- qcom,sdm845-sdhci - qcom,sdm845-sdhci
......
...@@ -44,12 +44,10 @@ static const char *tpc_names[] = { ...@@ -44,12 +44,10 @@ static const char *tpc_names[] = {
* memstick_debug_get_tpc_name - debug helper that returns string for * memstick_debug_get_tpc_name - debug helper that returns string for
* a TPC number * a TPC number
*/ */
const char *memstick_debug_get_tpc_name(int tpc) static __maybe_unused const char *memstick_debug_get_tpc_name(int tpc)
{ {
return tpc_names[tpc-1]; return tpc_names[tpc-1];
} }
EXPORT_SYMBOL(memstick_debug_get_tpc_name);
/* Read a register*/ /* Read a register*/
static inline u32 r592_read_reg(struct r592_device *dev, int address) static inline u32 r592_read_reg(struct r592_device *dev, int address)
......
...@@ -178,6 +178,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, ...@@ -178,6 +178,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
int recovery_mode, int recovery_mode,
struct mmc_queue *mq); struct mmc_queue *mq);
static void mmc_blk_hsq_req_done(struct mmc_request *mrq); static void mmc_blk_hsq_req_done(struct mmc_request *mrq);
static int mmc_spi_err_check(struct mmc_card *card);
static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk) static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
{ {
...@@ -608,6 +609,11 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, ...@@ -608,6 +609,11 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
if ((card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp) if ((card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
return 0; return 0;
if (mmc_host_is_spi(card->host)) {
if (idata->ic.write_flag || r1b_resp || cmd.flags & MMC_RSP_SPI_BUSY)
return mmc_spi_err_check(card);
return err;
}
/* Ensure RPMB/R1B command has completed by polling with CMD13. */ /* Ensure RPMB/R1B command has completed by polling with CMD13. */
if (idata->rpmb || r1b_resp) if (idata->rpmb || r1b_resp)
err = mmc_poll_for_busy(card, busy_timeout_ms, false, err = mmc_poll_for_busy(card, busy_timeout_ms, false,
...@@ -2505,9 +2511,9 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, ...@@ -2505,9 +2511,9 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
string_get_size((u64)size, 512, STRING_UNITS_2, string_get_size((u64)size, 512, STRING_UNITS_2,
cap_str, sizeof(cap_str)); cap_str, sizeof(cap_str));
pr_info("%s: %s %s %s %s\n", pr_info("%s: %s %s %s%s\n",
md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
cap_str, md->read_only ? "(ro)" : ""); cap_str, md->read_only ? " (ro)" : "");
/* used in ->open, must be set before add_disk: */ /* used in ->open, must be set before add_disk: */
if (area_type == MMC_BLK_DATA_AREA_MAIN) if (area_type == MMC_BLK_DATA_AREA_MAIN)
...@@ -2899,12 +2905,12 @@ static const struct file_operations mmc_dbg_ext_csd_fops = { ...@@ -2899,12 +2905,12 @@ static const struct file_operations mmc_dbg_ext_csd_fops = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
static int mmc_blk_add_debugfs(struct mmc_card *card, struct mmc_blk_data *md) static void mmc_blk_add_debugfs(struct mmc_card *card, struct mmc_blk_data *md)
{ {
struct dentry *root; struct dentry *root;
if (!card->debugfs_root) if (!card->debugfs_root)
return 0; return;
root = card->debugfs_root; root = card->debugfs_root;
...@@ -2913,19 +2919,13 @@ static int mmc_blk_add_debugfs(struct mmc_card *card, struct mmc_blk_data *md) ...@@ -2913,19 +2919,13 @@ static int mmc_blk_add_debugfs(struct mmc_card *card, struct mmc_blk_data *md)
debugfs_create_file_unsafe("status", 0400, root, debugfs_create_file_unsafe("status", 0400, root,
card, card,
&mmc_dbg_card_status_fops); &mmc_dbg_card_status_fops);
if (!md->status_dentry)
return -EIO;
} }
if (mmc_card_mmc(card)) { if (mmc_card_mmc(card)) {
md->ext_csd_dentry = md->ext_csd_dentry =
debugfs_create_file("ext_csd", S_IRUSR, root, card, debugfs_create_file("ext_csd", S_IRUSR, root, card,
&mmc_dbg_ext_csd_fops); &mmc_dbg_ext_csd_fops);
if (!md->ext_csd_dentry)
return -EIO;
} }
return 0;
} }
static void mmc_blk_remove_debugfs(struct mmc_card *card, static void mmc_blk_remove_debugfs(struct mmc_card *card,
...@@ -2934,22 +2934,17 @@ static void mmc_blk_remove_debugfs(struct mmc_card *card, ...@@ -2934,22 +2934,17 @@ static void mmc_blk_remove_debugfs(struct mmc_card *card,
if (!card->debugfs_root) if (!card->debugfs_root)
return; return;
if (!IS_ERR_OR_NULL(md->status_dentry)) { debugfs_remove(md->status_dentry);
debugfs_remove(md->status_dentry); md->status_dentry = NULL;
md->status_dentry = NULL;
}
if (!IS_ERR_OR_NULL(md->ext_csd_dentry)) { debugfs_remove(md->ext_csd_dentry);
debugfs_remove(md->ext_csd_dentry); md->ext_csd_dentry = NULL;
md->ext_csd_dentry = NULL;
}
} }
#else #else
static int mmc_blk_add_debugfs(struct mmc_card *card, struct mmc_blk_data *md) static void mmc_blk_add_debugfs(struct mmc_card *card, struct mmc_blk_data *md)
{ {
return 0;
} }
static void mmc_blk_remove_debugfs(struct mmc_card *card, static void mmc_blk_remove_debugfs(struct mmc_card *card,
......
...@@ -53,6 +53,10 @@ struct mmc_fixup { ...@@ -53,6 +53,10 @@ struct mmc_fixup {
unsigned int manfid; unsigned int manfid;
unsigned short oemid; unsigned short oemid;
/* Manufacturing date */
unsigned short year;
unsigned char month;
/* SDIO-specific fields. You can use SDIO_ANY_ID here of course */ /* SDIO-specific fields. You can use SDIO_ANY_ID here of course */
u16 cis_vendor, cis_device; u16 cis_vendor, cis_device;
...@@ -68,6 +72,8 @@ struct mmc_fixup { ...@@ -68,6 +72,8 @@ struct mmc_fixup {
#define CID_MANFID_ANY (-1u) #define CID_MANFID_ANY (-1u)
#define CID_OEMID_ANY ((unsigned short) -1) #define CID_OEMID_ANY ((unsigned short) -1)
#define CID_YEAR_ANY ((unsigned short) -1)
#define CID_MONTH_ANY ((unsigned char) -1)
#define CID_NAME_ANY (NULL) #define CID_NAME_ANY (NULL)
#define EXT_CSD_REV_ANY (-1u) #define EXT_CSD_REV_ANY (-1u)
...@@ -81,17 +87,21 @@ struct mmc_fixup { ...@@ -81,17 +87,21 @@ struct mmc_fixup {
#define CID_MANFID_APACER 0x27 #define CID_MANFID_APACER 0x27
#define CID_MANFID_KINGSTON 0x70 #define CID_MANFID_KINGSTON 0x70
#define CID_MANFID_HYNIX 0x90 #define CID_MANFID_HYNIX 0x90
#define CID_MANFID_KINGSTON_SD 0x9F
#define CID_MANFID_NUMONYX 0xFE #define CID_MANFID_NUMONYX 0xFE
#define END_FIXUP { NULL } #define END_FIXUP { NULL }
#define _FIXUP_EXT(_name, _manfid, _oemid, _rev_start, _rev_end, \ #define _FIXUP_EXT(_name, _manfid, _oemid, _year, _month, \
_cis_vendor, _cis_device, \ _rev_start, _rev_end, \
_fixup, _data, _ext_csd_rev) \ _cis_vendor, _cis_device, \
_fixup, _data, _ext_csd_rev) \
{ \ { \
.name = (_name), \ .name = (_name), \
.manfid = (_manfid), \ .manfid = (_manfid), \
.oemid = (_oemid), \ .oemid = (_oemid), \
.year = (_year), \
.month = (_month), \
.rev_start = (_rev_start), \ .rev_start = (_rev_start), \
.rev_end = (_rev_end), \ .rev_end = (_rev_end), \
.cis_vendor = (_cis_vendor), \ .cis_vendor = (_cis_vendor), \
...@@ -103,8 +113,8 @@ struct mmc_fixup { ...@@ -103,8 +113,8 @@ struct mmc_fixup {
#define MMC_FIXUP_REV(_name, _manfid, _oemid, _rev_start, _rev_end, \ #define MMC_FIXUP_REV(_name, _manfid, _oemid, _rev_start, _rev_end, \
_fixup, _data, _ext_csd_rev) \ _fixup, _data, _ext_csd_rev) \
_FIXUP_EXT(_name, _manfid, \ _FIXUP_EXT(_name, _manfid, _oemid, CID_YEAR_ANY, CID_MONTH_ANY, \
_oemid, _rev_start, _rev_end, \ _rev_start, _rev_end, \
SDIO_ANY_ID, SDIO_ANY_ID, \ SDIO_ANY_ID, SDIO_ANY_ID, \
_fixup, _data, _ext_csd_rev) \ _fixup, _data, _ext_csd_rev) \
...@@ -118,8 +128,9 @@ struct mmc_fixup { ...@@ -118,8 +128,9 @@ struct mmc_fixup {
_ext_csd_rev) _ext_csd_rev)
#define SDIO_FIXUP(_vendor, _device, _fixup, _data) \ #define SDIO_FIXUP(_vendor, _device, _fixup, _data) \
_FIXUP_EXT(CID_NAME_ANY, CID_MANFID_ANY, \ _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_ANY, CID_OEMID_ANY, \
CID_OEMID_ANY, 0, -1ull, \ CID_YEAR_ANY, CID_MONTH_ANY, \
0, -1ull, \
_vendor, _device, \ _vendor, _device, \
_fixup, _data, EXT_CSD_REV_ANY) \ _fixup, _data, EXT_CSD_REV_ANY) \
...@@ -264,4 +275,9 @@ static inline int mmc_card_broken_sd_discard(const struct mmc_card *c) ...@@ -264,4 +275,9 @@ static inline int mmc_card_broken_sd_discard(const struct mmc_card *c)
return c->quirks & MMC_QUIRK_BROKEN_SD_DISCARD; return c->quirks & MMC_QUIRK_BROKEN_SD_DISCARD;
} }
static inline int mmc_card_broken_sd_cache(const struct mmc_card *c)
{
return c->quirks & MMC_QUIRK_BROKEN_SD_CACHE;
}
#endif #endif
...@@ -2199,10 +2199,8 @@ int mmc_card_alternative_gpt_sector(struct mmc_card *card, sector_t *gpt_sector) ...@@ -2199,10 +2199,8 @@ int mmc_card_alternative_gpt_sector(struct mmc_card *card, sector_t *gpt_sector)
} }
EXPORT_SYMBOL(mmc_card_alternative_gpt_sector); EXPORT_SYMBOL(mmc_card_alternative_gpt_sector);
void mmc_rescan(struct work_struct *work) static void __mmc_rescan(struct mmc_host *host)
{ {
struct mmc_host *host =
container_of(work, struct mmc_host, detect.work);
int i; int i;
if (host->rescan_disable) if (host->rescan_disable)
...@@ -2274,6 +2272,14 @@ void mmc_rescan(struct work_struct *work) ...@@ -2274,6 +2272,14 @@ void mmc_rescan(struct work_struct *work)
mmc_schedule_delayed_work(&host->detect, HZ); mmc_schedule_delayed_work(&host->detect, HZ);
} }
void mmc_rescan(struct work_struct *work)
{
struct mmc_host *host =
container_of(work, struct mmc_host, detect.work);
__mmc_rescan(host);
}
void mmc_start_host(struct mmc_host *host) void mmc_start_host(struct mmc_host *host)
{ {
host->f_init = max(min(freqs[0], host->f_max), host->f_min); host->f_init = max(min(freqs[0], host->f_max), host->f_min);
...@@ -2286,7 +2292,8 @@ void mmc_start_host(struct mmc_host *host) ...@@ -2286,7 +2292,8 @@ void mmc_start_host(struct mmc_host *host)
} }
mmc_gpiod_request_cd_irq(host); mmc_gpiod_request_cd_irq(host);
_mmc_detect_change(host, 0, false); host->detect_change = 1;
__mmc_rescan(host);
} }
void __mmc_stop_host(struct mmc_host *host) void __mmc_stop_host(struct mmc_host *host)
......
...@@ -53,6 +53,15 @@ static const struct mmc_fixup __maybe_unused mmc_blk_fixups[] = { ...@@ -53,6 +53,15 @@ static const struct mmc_fixup __maybe_unused mmc_blk_fixups[] = {
MMC_FIXUP("MMC32G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc, MMC_FIXUP("MMC32G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
MMC_QUIRK_BLK_NO_CMD23), MMC_QUIRK_BLK_NO_CMD23),
/*
* Kingston Canvas Go! Plus microSD cards never finish SD cache flush.
* This has so far only been observed on cards from 11/2019, while new
* cards from 2023/05 do not exhibit this behavior.
*/
_FIXUP_EXT("SD64G", CID_MANFID_KINGSTON_SD, 0x5449, 2019, 11,
0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY),
/* /*
* Some SD cards lockup while using CMD23 multiblock transfers. * Some SD cards lockup while using CMD23 multiblock transfers.
*/ */
...@@ -100,6 +109,20 @@ static const struct mmc_fixup __maybe_unused mmc_blk_fixups[] = { ...@@ -100,6 +109,20 @@ static const struct mmc_fixup __maybe_unused mmc_blk_fixups[] = {
MMC_FIXUP("V10016", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc, MMC_FIXUP("V10016", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc,
MMC_QUIRK_TRIM_BROKEN), MMC_QUIRK_TRIM_BROKEN),
/*
* Micron MTFC4GACAJCN-1M advertises TRIM but it does not seems to
* support being used to offload WRITE_ZEROES.
*/
MMC_FIXUP("Q2J54A", CID_MANFID_MICRON, 0x014e, add_quirk_mmc,
MMC_QUIRK_TRIM_BROKEN),
/*
* Kingston EMMC04G-M627 advertises TRIM but it does not seems to
* support being used to offload WRITE_ZEROES.
*/
MMC_FIXUP("M62704", CID_MANFID_KINGSTON, 0x0100, add_quirk_mmc,
MMC_QUIRK_TRIM_BROKEN),
/* /*
* Some SD cards reports discard support while they don't * Some SD cards reports discard support while they don't
*/ */
...@@ -209,6 +232,10 @@ static inline void mmc_fixup_device(struct mmc_card *card, ...@@ -209,6 +232,10 @@ static inline void mmc_fixup_device(struct mmc_card *card,
if (f->of_compatible && if (f->of_compatible &&
!mmc_fixup_of_compatible_match(card, f->of_compatible)) !mmc_fixup_of_compatible_match(card, f->of_compatible))
continue; continue;
if (f->year != CID_YEAR_ANY && f->year != card->cid.year)
continue;
if (f->month != CID_MONTH_ANY && f->month != card->cid.month)
continue;
dev_dbg(&card->dev, "calling %ps\n", f->vendor_fixup); dev_dbg(&card->dev, "calling %ps\n", f->vendor_fixup);
f->vendor_fixup(card, f->data); f->vendor_fixup(card, f->data);
......
...@@ -1170,7 +1170,7 @@ static int sd_parse_ext_reg_perf(struct mmc_card *card, u8 fno, u8 page, ...@@ -1170,7 +1170,7 @@ static int sd_parse_ext_reg_perf(struct mmc_card *card, u8 fno, u8 page,
card->ext_perf.feature_support |= SD_EXT_PERF_HOST_MAINT; card->ext_perf.feature_support |= SD_EXT_PERF_HOST_MAINT;
/* Cache support at bit 0. */ /* Cache support at bit 0. */
if (reg_buf[4] & BIT(0)) if ((reg_buf[4] & BIT(0)) && !mmc_card_broken_sd_cache(card))
card->ext_perf.feature_support |= SD_EXT_PERF_CACHE; card->ext_perf.feature_support |= SD_EXT_PERF_CACHE;
/* Command queue support indicated via queue depth bits (0 to 4). */ /* Command queue support indicated via queue depth bits (0 to 4). */
......
...@@ -550,7 +550,7 @@ config MMC_SDHCI_MSM ...@@ -550,7 +550,7 @@ config MMC_SDHCI_MSM
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS select MMC_SDHCI_IO_ACCESSORS
select MMC_CQHCI select MMC_CQHCI
select QCOM_SCM if MMC_CRYPTO select QCOM_INLINE_CRYPTO_ENGINE if MMC_CRYPTO
help help
This selects the Secure Digital Host Controller Interface (SDHCI) This selects the Secure Digital Host Controller Interface (SDHCI)
support present in Qualcomm SOCs. The controller supports support present in Qualcomm SOCs. The controller supports
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#define LINUX_MMC_CQHCI_H #define LINUX_MMC_CQHCI_H
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/bitfield.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/spinlock_types.h> #include <linux/spinlock_types.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -23,6 +24,8 @@ ...@@ -23,6 +24,8 @@
/* capabilities */ /* capabilities */
#define CQHCI_CAP 0x04 #define CQHCI_CAP 0x04
#define CQHCI_CAP_CS 0x10000000 /* Crypto Support */ #define CQHCI_CAP_CS 0x10000000 /* Crypto Support */
#define CQHCI_CAP_ITCFMUL GENMASK(15, 12)
#define CQHCI_ITCFMUL(x) FIELD_GET(CQHCI_CAP_ITCFMUL, (x))
/* configuration */ /* configuration */
#define CQHCI_CFG 0x08 #define CQHCI_CFG 0x08
......
...@@ -52,7 +52,7 @@ static int dw_mci_bluefield_probe(struct platform_device *pdev) ...@@ -52,7 +52,7 @@ static int dw_mci_bluefield_probe(struct platform_device *pdev)
static struct platform_driver dw_mci_bluefield_pltfm_driver = { static struct platform_driver dw_mci_bluefield_pltfm_driver = {
.probe = dw_mci_bluefield_probe, .probe = dw_mci_bluefield_probe,
.remove = dw_mci_pltfm_remove, .remove_new = dw_mci_pltfm_remove,
.driver = { .driver = {
.name = "dwmmc_bluefield", .name = "dwmmc_bluefield",
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,
......
...@@ -470,7 +470,7 @@ static const struct dev_pm_ops dw_mci_k3_dev_pm_ops = { ...@@ -470,7 +470,7 @@ static const struct dev_pm_ops dw_mci_k3_dev_pm_ops = {
static struct platform_driver dw_mci_k3_pltfm_driver = { static struct platform_driver dw_mci_k3_pltfm_driver = {
.probe = dw_mci_k3_probe, .probe = dw_mci_k3_probe,
.remove = dw_mci_pltfm_remove, .remove_new = dw_mci_pltfm_remove,
.driver = { .driver = {
.name = "dwmmc_k3", .name = "dwmmc_k3",
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,
......
...@@ -121,18 +121,17 @@ static int dw_mci_pltfm_probe(struct platform_device *pdev) ...@@ -121,18 +121,17 @@ static int dw_mci_pltfm_probe(struct platform_device *pdev)
return dw_mci_pltfm_register(pdev, drv_data); return dw_mci_pltfm_register(pdev, drv_data);
} }
int dw_mci_pltfm_remove(struct platform_device *pdev) void dw_mci_pltfm_remove(struct platform_device *pdev)
{ {
struct dw_mci *host = platform_get_drvdata(pdev); struct dw_mci *host = platform_get_drvdata(pdev);
dw_mci_remove(host); dw_mci_remove(host);
return 0;
} }
EXPORT_SYMBOL_GPL(dw_mci_pltfm_remove); EXPORT_SYMBOL_GPL(dw_mci_pltfm_remove);
static struct platform_driver dw_mci_pltfm_driver = { static struct platform_driver dw_mci_pltfm_driver = {
.probe = dw_mci_pltfm_probe, .probe = dw_mci_pltfm_probe,
.remove = dw_mci_pltfm_remove, .remove_new = dw_mci_pltfm_remove,
.driver = { .driver = {
.name = "dw_mmc", .name = "dw_mmc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
extern int dw_mci_pltfm_register(struct platform_device *pdev, extern int dw_mci_pltfm_register(struct platform_device *pdev,
const struct dw_mci_drv_data *drv_data); const struct dw_mci_drv_data *drv_data);
extern int dw_mci_pltfm_remove(struct platform_device *pdev); extern void dw_mci_pltfm_remove(struct platform_device *pdev);
extern const struct dev_pm_ops dw_mci_pltfm_pmops; extern const struct dev_pm_ops dw_mci_pltfm_pmops;
#endif /* _DW_MMC_PLTFM_H_ */ #endif /* _DW_MMC_PLTFM_H_ */
...@@ -172,7 +172,7 @@ static int dw_mci_starfive_probe(struct platform_device *pdev) ...@@ -172,7 +172,7 @@ static int dw_mci_starfive_probe(struct platform_device *pdev)
static struct platform_driver dw_mci_starfive_driver = { static struct platform_driver dw_mci_starfive_driver = {
.probe = dw_mci_starfive_probe, .probe = dw_mci_starfive_probe,
.remove = dw_mci_pltfm_remove, .remove_new = dw_mci_pltfm_remove,
.driver = { .driver = {
.name = "dwmmc_starfive", .name = "dwmmc_starfive",
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,
......
...@@ -776,6 +776,11 @@ static void meson_mx_sdhc_init_hw(struct mmc_host *mmc) ...@@ -776,6 +776,11 @@ static void meson_mx_sdhc_init_hw(struct mmc_host *mmc)
regmap_write(host->regmap, MESON_SDHC_ISTA, MESON_SDHC_ISTA_ALL_IRQS); regmap_write(host->regmap, MESON_SDHC_ISTA, MESON_SDHC_ISTA_ALL_IRQS);
} }
static void meason_mx_mmc_free_host(void *data)
{
mmc_free_host(data);
}
static int meson_mx_sdhc_probe(struct platform_device *pdev) static int meson_mx_sdhc_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -788,8 +793,7 @@ static int meson_mx_sdhc_probe(struct platform_device *pdev) ...@@ -788,8 +793,7 @@ static int meson_mx_sdhc_probe(struct platform_device *pdev)
if (!mmc) if (!mmc)
return -ENOMEM; return -ENOMEM;
ret = devm_add_action_or_reset(dev, (void(*)(void *))mmc_free_host, ret = devm_add_action_or_reset(dev, meason_mx_mmc_free_host, mmc);
mmc);
if (ret) { if (ret) {
dev_err(dev, "Failed to register mmc_free_host action\n"); dev_err(dev, "Failed to register mmc_free_host action\n");
return ret; return ret;
......
This diff is collapsed.
...@@ -218,6 +218,11 @@ ...@@ -218,6 +218,11 @@
#define MCI_STM32_BUSYD0ENDMASK BIT(21) #define MCI_STM32_BUSYD0ENDMASK BIT(21)
#define MMCIMASK1 0x040 #define MMCIMASK1 0x040
/* STM32 sdmmc data FIFO threshold register */
#define MMCI_STM32_FIFOTHRR 0x044
#define MMCI_STM32_THR_MASK GENMASK(3, 0)
#define MMCIFIFOCNT 0x048 #define MMCIFIFOCNT 0x048
#define MMCIFIFO 0x080 /* to 0x0bc */ #define MMCIFIFO 0x080 /* to 0x0bc */
...@@ -227,8 +232,6 @@ ...@@ -227,8 +232,6 @@
#define MMCI_STM32_IDMALLIEN BIT(1) #define MMCI_STM32_IDMALLIEN BIT(1)
#define MMCI_STM32_IDMABSIZER 0x054 #define MMCI_STM32_IDMABSIZER 0x054
#define MMCI_STM32_IDMABNDT_SHIFT 5
#define MMCI_STM32_IDMABNDT_MASK GENMASK(12, 5)
#define MMCI_STM32_IDMABASE0R 0x058 #define MMCI_STM32_IDMABASE0R 0x058
...@@ -261,6 +264,19 @@ struct clk; ...@@ -261,6 +264,19 @@ struct clk;
struct dma_chan; struct dma_chan;
struct mmci_host; struct mmci_host;
/**
* enum mmci_busy_state - enumerate the busy detect wait states
*
* This is used for the state machine waiting for different busy detect
* interrupts on hardware that fire a single IRQ for start and end of
* the busy detect phase on DAT0.
*/
enum mmci_busy_state {
MMCI_BUSY_WAITING_FOR_START_IRQ,
MMCI_BUSY_WAITING_FOR_END_IRQ,
MMCI_BUSY_DONE,
};
/** /**
* struct variant_data - MMCI variant-specific quirks * struct variant_data - MMCI variant-specific quirks
* @clkreg: default value for MCICLOCK register * @clkreg: default value for MCICLOCK register
...@@ -361,6 +377,7 @@ struct variant_data { ...@@ -361,6 +377,7 @@ struct variant_data {
u32 opendrain; u32 opendrain;
u8 dma_lli:1; u8 dma_lli:1;
u32 stm32_idmabsize_mask; u32 stm32_idmabsize_mask;
u32 stm32_idmabsize_align;
void (*init)(struct mmci_host *host); void (*init)(struct mmci_host *host);
}; };
...@@ -380,7 +397,7 @@ struct mmci_host_ops { ...@@ -380,7 +397,7 @@ struct mmci_host_ops {
void (*dma_error)(struct mmci_host *host); void (*dma_error)(struct mmci_host *host);
void (*set_clkreg)(struct mmci_host *host, unsigned int desired); void (*set_clkreg)(struct mmci_host *host, unsigned int desired);
void (*set_pwrreg)(struct mmci_host *host, unsigned int pwr); void (*set_pwrreg)(struct mmci_host *host, unsigned int pwr);
bool (*busy_complete)(struct mmci_host *host, u32 status, u32 err_msk); bool (*busy_complete)(struct mmci_host *host, struct mmc_command *cmd, u32 status, u32 err_msk);
void (*pre_sig_volt_switch)(struct mmci_host *host); void (*pre_sig_volt_switch)(struct mmci_host *host);
int (*post_sig_volt_switch)(struct mmci_host *host, struct mmc_ios *ios); int (*post_sig_volt_switch)(struct mmci_host *host, struct mmc_ios *ios);
}; };
...@@ -409,6 +426,7 @@ struct mmci_host { ...@@ -409,6 +426,7 @@ struct mmci_host {
u32 clk_reg; u32 clk_reg;
u32 clk_reg_add; u32 clk_reg_add;
u32 datactrl_reg; u32 datactrl_reg;
enum mmci_busy_state busy_state;
u32 busy_status; u32 busy_status;
u32 mask1_reg; u32 mask1_reg;
u8 vqmmc_enabled:1; u8 vqmmc_enabled:1;
...@@ -437,6 +455,7 @@ struct mmci_host { ...@@ -437,6 +455,7 @@ struct mmci_host {
void *dma_priv; void *dma_priv;
s32 next_cookie; s32 next_cookie;
struct delayed_work ux500_busy_timeout_work;
}; };
#define dma_inprogress(host) ((host)->dma_in_progress) #define dma_inprogress(host) ((host)->dma_in_progress)
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include "mmci.h" #include "mmci.h"
#define SDMMC_LLI_BUF_LEN PAGE_SIZE #define SDMMC_LLI_BUF_LEN PAGE_SIZE
#define SDMMC_IDMA_BURST BIT(MMCI_STM32_IDMABNDT_SHIFT)
#define DLYB_CR 0x0 #define DLYB_CR 0x0
#define DLYB_CR_DEN BIT(0) #define DLYB_CR_DEN BIT(0)
...@@ -34,6 +33,20 @@ ...@@ -34,6 +33,20 @@
#define DLYB_LNG_TIMEOUT_US 1000 #define DLYB_LNG_TIMEOUT_US 1000
#define SDMMC_VSWEND_TIMEOUT_US 10000 #define SDMMC_VSWEND_TIMEOUT_US 10000
#define SYSCFG_DLYBSD_CR 0x0
#define DLYBSD_CR_EN BIT(0)
#define DLYBSD_CR_RXTAPSEL_MASK GENMASK(6, 1)
#define DLYBSD_TAPSEL_NB 32
#define DLYBSD_BYP_EN BIT(16)
#define DLYBSD_BYP_CMD GENMASK(21, 17)
#define DLYBSD_ANTIGLITCH_EN BIT(22)
#define SYSCFG_DLYBSD_SR 0x4
#define DLYBSD_SR_LOCK BIT(0)
#define DLYBSD_SR_RXTAPSEL_ACK BIT(1)
#define DLYBSD_TIMEOUT_1S_IN_US 1000000
struct sdmmc_lli_desc { struct sdmmc_lli_desc {
u32 idmalar; u32 idmalar;
u32 idmabase; u32 idmabase;
...@@ -48,10 +61,21 @@ struct sdmmc_idma { ...@@ -48,10 +61,21 @@ struct sdmmc_idma {
bool use_bounce_buffer; bool use_bounce_buffer;
}; };
struct sdmmc_dlyb;
struct sdmmc_tuning_ops {
int (*dlyb_enable)(struct sdmmc_dlyb *dlyb);
void (*set_input_ck)(struct sdmmc_dlyb *dlyb);
int (*tuning_prepare)(struct mmci_host *host);
int (*set_cfg)(struct sdmmc_dlyb *dlyb, int unit __maybe_unused,
int phase, bool sampler __maybe_unused);
};
struct sdmmc_dlyb { struct sdmmc_dlyb {
void __iomem *base; void __iomem *base;
u32 unit; u32 unit;
u32 max; u32 max;
struct sdmmc_tuning_ops *ops;
}; };
static int sdmmc_idma_validate_data(struct mmci_host *host, static int sdmmc_idma_validate_data(struct mmci_host *host,
...@@ -69,7 +93,8 @@ static int sdmmc_idma_validate_data(struct mmci_host *host, ...@@ -69,7 +93,8 @@ static int sdmmc_idma_validate_data(struct mmci_host *host,
idma->use_bounce_buffer = false; idma->use_bounce_buffer = false;
for_each_sg(data->sg, sg, data->sg_len - 1, i) { for_each_sg(data->sg, sg, data->sg_len - 1, i) {
if (!IS_ALIGNED(sg->offset, sizeof(u32)) || if (!IS_ALIGNED(sg->offset, sizeof(u32)) ||
!IS_ALIGNED(sg->length, SDMMC_IDMA_BURST)) { !IS_ALIGNED(sg->length,
host->variant->stm32_idmabsize_align)) {
dev_dbg(mmc_dev(host->mmc), dev_dbg(mmc_dev(host->mmc),
"unaligned scatterlist: ofst:%x length:%d\n", "unaligned scatterlist: ofst:%x length:%d\n",
data->sg->offset, data->sg->length); data->sg->offset, data->sg->length);
...@@ -293,23 +318,13 @@ static void mmci_sdmmc_set_clkreg(struct mmci_host *host, unsigned int desired) ...@@ -293,23 +318,13 @@ static void mmci_sdmmc_set_clkreg(struct mmci_host *host, unsigned int desired)
clk |= host->clk_reg_add; clk |= host->clk_reg_add;
clk |= ddr; clk |= ddr;
/* if (host->mmc->ios.timing >= MMC_TIMING_UHS_SDR50)
* SDMMC_FBCK is selected when an external Delay Block is needed
* with SDR104 or HS200.
*/
if (host->mmc->ios.timing >= MMC_TIMING_UHS_SDR50) {
clk |= MCI_STM32_CLK_BUSSPEED; clk |= MCI_STM32_CLK_BUSSPEED;
if (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104 ||
host->mmc->ios.timing == MMC_TIMING_MMC_HS200) {
clk &= ~MCI_STM32_CLK_SEL_MSK;
clk |= MCI_STM32_CLK_SELFBCK;
}
}
mmci_write_clkreg(host, clk); mmci_write_clkreg(host, clk);
} }
static void sdmmc_dlyb_input_ck(struct sdmmc_dlyb *dlyb) static void sdmmc_dlyb_mp15_input_ck(struct sdmmc_dlyb *dlyb)
{ {
if (!dlyb || !dlyb->base) if (!dlyb || !dlyb->base)
return; return;
...@@ -326,7 +341,8 @@ static void mmci_sdmmc_set_pwrreg(struct mmci_host *host, unsigned int pwr) ...@@ -326,7 +341,8 @@ static void mmci_sdmmc_set_pwrreg(struct mmci_host *host, unsigned int pwr)
/* adds OF options */ /* adds OF options */
pwr = host->pwr_reg_add; pwr = host->pwr_reg_add;
sdmmc_dlyb_input_ck(dlyb); if (dlyb && dlyb->ops->set_input_ck)
dlyb->ops->set_input_ck(dlyb);
if (ios.power_mode == MMC_POWER_OFF) { if (ios.power_mode == MMC_POWER_OFF) {
/* Only a reset could power-off sdmmc */ /* Only a reset could power-off sdmmc */
...@@ -371,6 +387,19 @@ static u32 sdmmc_get_dctrl_cfg(struct mmci_host *host) ...@@ -371,6 +387,19 @@ static u32 sdmmc_get_dctrl_cfg(struct mmci_host *host)
datactrl = mmci_dctrl_blksz(host); datactrl = mmci_dctrl_blksz(host);
if (host->hw_revision >= 3) {
u32 thr = 0;
if (host->mmc->ios.timing == MMC_TIMING_UHS_SDR104 ||
host->mmc->ios.timing == MMC_TIMING_MMC_HS200) {
thr = ffs(min_t(unsigned int, host->data->blksz,
host->variant->fifosize));
thr = min_t(u32, thr, MMCI_STM32_THR_MASK);
}
writel_relaxed(thr, host->base + MMCI_STM32_FIFOTHRR);
}
if (host->mmc->card && mmc_card_sdio(host->mmc->card) && if (host->mmc->card && mmc_card_sdio(host->mmc->card) &&
host->data->blocks == 1) host->data->blocks == 1)
datactrl |= MCI_DPSM_STM32_MODE_SDIO; datactrl |= MCI_DPSM_STM32_MODE_SDIO;
...@@ -382,7 +411,8 @@ static u32 sdmmc_get_dctrl_cfg(struct mmci_host *host) ...@@ -382,7 +411,8 @@ static u32 sdmmc_get_dctrl_cfg(struct mmci_host *host)
return datactrl; return datactrl;
} }
static bool sdmmc_busy_complete(struct mmci_host *host, u32 status, u32 err_msk) static bool sdmmc_busy_complete(struct mmci_host *host, struct mmc_command *cmd,
u32 status, u32 err_msk)
{ {
void __iomem *base = host->base; void __iomem *base = host->base;
u32 busy_d0, busy_d0end, mask, sdmmc_status; u32 busy_d0, busy_d0end, mask, sdmmc_status;
...@@ -423,8 +453,15 @@ static bool sdmmc_busy_complete(struct mmci_host *host, u32 status, u32 err_msk) ...@@ -423,8 +453,15 @@ static bool sdmmc_busy_complete(struct mmci_host *host, u32 status, u32 err_msk)
return true; return true;
} }
static void sdmmc_dlyb_set_cfgr(struct sdmmc_dlyb *dlyb, static int sdmmc_dlyb_mp15_enable(struct sdmmc_dlyb *dlyb)
int unit, int phase, bool sampler) {
writel_relaxed(DLYB_CR_DEN, dlyb->base + DLYB_CR);
return 0;
}
static int sdmmc_dlyb_mp15_set_cfg(struct sdmmc_dlyb *dlyb,
int unit, int phase, bool sampler)
{ {
u32 cfgr; u32 cfgr;
...@@ -436,16 +473,18 @@ static void sdmmc_dlyb_set_cfgr(struct sdmmc_dlyb *dlyb, ...@@ -436,16 +473,18 @@ static void sdmmc_dlyb_set_cfgr(struct sdmmc_dlyb *dlyb,
if (!sampler) if (!sampler)
writel_relaxed(DLYB_CR_DEN, dlyb->base + DLYB_CR); writel_relaxed(DLYB_CR_DEN, dlyb->base + DLYB_CR);
return 0;
} }
static int sdmmc_dlyb_lng_tuning(struct mmci_host *host) static int sdmmc_dlyb_mp15_prepare(struct mmci_host *host)
{ {
struct sdmmc_dlyb *dlyb = host->variant_priv; struct sdmmc_dlyb *dlyb = host->variant_priv;
u32 cfgr; u32 cfgr;
int i, lng, ret; int i, lng, ret;
for (i = 0; i <= DLYB_CFGR_UNIT_MAX; i++) { for (i = 0; i <= DLYB_CFGR_UNIT_MAX; i++) {
sdmmc_dlyb_set_cfgr(dlyb, i, DLYB_CFGR_SEL_MAX, true); dlyb->ops->set_cfg(dlyb, i, DLYB_CFGR_SEL_MAX, true);
ret = readl_relaxed_poll_timeout(dlyb->base + DLYB_CFGR, cfgr, ret = readl_relaxed_poll_timeout(dlyb->base + DLYB_CFGR, cfgr,
(cfgr & DLYB_CFGR_LNGF), (cfgr & DLYB_CFGR_LNGF),
...@@ -471,14 +510,58 @@ static int sdmmc_dlyb_lng_tuning(struct mmci_host *host) ...@@ -471,14 +510,58 @@ static int sdmmc_dlyb_lng_tuning(struct mmci_host *host)
return 0; return 0;
} }
static int sdmmc_dlyb_mp25_enable(struct sdmmc_dlyb *dlyb)
{
u32 cr, sr;
cr = readl_relaxed(dlyb->base + SYSCFG_DLYBSD_CR);
cr |= DLYBSD_CR_EN;
writel_relaxed(cr, dlyb->base + SYSCFG_DLYBSD_CR);
return readl_relaxed_poll_timeout(dlyb->base + SYSCFG_DLYBSD_SR,
sr, sr & DLYBSD_SR_LOCK, 1,
DLYBSD_TIMEOUT_1S_IN_US);
}
static int sdmmc_dlyb_mp25_set_cfg(struct sdmmc_dlyb *dlyb,
int unit __maybe_unused, int phase,
bool sampler __maybe_unused)
{
u32 cr, sr;
cr = readl_relaxed(dlyb->base + SYSCFG_DLYBSD_CR);
cr &= ~DLYBSD_CR_RXTAPSEL_MASK;
cr |= FIELD_PREP(DLYBSD_CR_RXTAPSEL_MASK, phase);
writel_relaxed(cr, dlyb->base + SYSCFG_DLYBSD_CR);
return readl_relaxed_poll_timeout(dlyb->base + SYSCFG_DLYBSD_SR,
sr, sr & DLYBSD_SR_RXTAPSEL_ACK, 1,
DLYBSD_TIMEOUT_1S_IN_US);
}
static int sdmmc_dlyb_mp25_prepare(struct mmci_host *host)
{
struct sdmmc_dlyb *dlyb = host->variant_priv;
dlyb->max = DLYBSD_TAPSEL_NB;
return 0;
}
static int sdmmc_dlyb_phase_tuning(struct mmci_host *host, u32 opcode) static int sdmmc_dlyb_phase_tuning(struct mmci_host *host, u32 opcode)
{ {
struct sdmmc_dlyb *dlyb = host->variant_priv; struct sdmmc_dlyb *dlyb = host->variant_priv;
int cur_len = 0, max_len = 0, end_of_len = 0; int cur_len = 0, max_len = 0, end_of_len = 0;
int phase; int phase, ret;
for (phase = 0; phase <= dlyb->max; phase++) { for (phase = 0; phase <= dlyb->max; phase++) {
sdmmc_dlyb_set_cfgr(dlyb, dlyb->unit, phase, false); ret = dlyb->ops->set_cfg(dlyb, dlyb->unit, phase, false);
if (ret) {
dev_err(mmc_dev(host->mmc), "tuning config failed\n");
return ret;
}
if (mmc_send_tuning(host->mmc, opcode, NULL)) { if (mmc_send_tuning(host->mmc, opcode, NULL)) {
cur_len = 0; cur_len = 0;
...@@ -496,10 +579,15 @@ static int sdmmc_dlyb_phase_tuning(struct mmci_host *host, u32 opcode) ...@@ -496,10 +579,15 @@ static int sdmmc_dlyb_phase_tuning(struct mmci_host *host, u32 opcode)
return -EINVAL; return -EINVAL;
} }
writel_relaxed(0, dlyb->base + DLYB_CR); if (dlyb->ops->set_input_ck)
dlyb->ops->set_input_ck(dlyb);
phase = end_of_len - max_len / 2; phase = end_of_len - max_len / 2;
sdmmc_dlyb_set_cfgr(dlyb, dlyb->unit, phase, false); ret = dlyb->ops->set_cfg(dlyb, dlyb->unit, phase, false);
if (ret) {
dev_err(mmc_dev(host->mmc), "tuning reconfig failed\n");
return ret;
}
dev_dbg(mmc_dev(host->mmc), "unit:%d max_dly:%d phase:%d\n", dev_dbg(mmc_dev(host->mmc), "unit:%d max_dly:%d phase:%d\n",
dlyb->unit, dlyb->max, phase); dlyb->unit, dlyb->max, phase);
...@@ -511,12 +599,33 @@ static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode) ...@@ -511,12 +599,33 @@ static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
{ {
struct mmci_host *host = mmc_priv(mmc); struct mmci_host *host = mmc_priv(mmc);
struct sdmmc_dlyb *dlyb = host->variant_priv; struct sdmmc_dlyb *dlyb = host->variant_priv;
u32 clk;
int ret;
if ((host->mmc->ios.timing != MMC_TIMING_UHS_SDR104 &&
host->mmc->ios.timing != MMC_TIMING_MMC_HS200) ||
host->mmc->actual_clock <= 50000000)
return 0;
if (!dlyb || !dlyb->base) if (!dlyb || !dlyb->base)
return -EINVAL; return -EINVAL;
if (sdmmc_dlyb_lng_tuning(host)) ret = dlyb->ops->dlyb_enable(dlyb);
return -EINVAL; if (ret)
return ret;
/*
* SDMMC_FBCK is selected when an external Delay Block is needed
* with SDR104 or HS200.
*/
clk = host->clk_reg;
clk &= ~MCI_STM32_CLK_SEL_MSK;
clk |= MCI_STM32_CLK_SELFBCK;
mmci_write_clkreg(host, clk);
ret = dlyb->ops->tuning_prepare(host);
if (ret)
return ret;
return sdmmc_dlyb_phase_tuning(host, opcode); return sdmmc_dlyb_phase_tuning(host, opcode);
} }
...@@ -574,6 +683,19 @@ static struct mmci_host_ops sdmmc_variant_ops = { ...@@ -574,6 +683,19 @@ static struct mmci_host_ops sdmmc_variant_ops = {
.post_sig_volt_switch = sdmmc_post_sig_volt_switch, .post_sig_volt_switch = sdmmc_post_sig_volt_switch,
}; };
static struct sdmmc_tuning_ops dlyb_tuning_mp15_ops = {
.dlyb_enable = sdmmc_dlyb_mp15_enable,
.set_input_ck = sdmmc_dlyb_mp15_input_ck,
.tuning_prepare = sdmmc_dlyb_mp15_prepare,
.set_cfg = sdmmc_dlyb_mp15_set_cfg,
};
static struct sdmmc_tuning_ops dlyb_tuning_mp25_ops = {
.dlyb_enable = sdmmc_dlyb_mp25_enable,
.tuning_prepare = sdmmc_dlyb_mp25_prepare,
.set_cfg = sdmmc_dlyb_mp25_set_cfg,
};
void sdmmc_variant_init(struct mmci_host *host) void sdmmc_variant_init(struct mmci_host *host)
{ {
struct device_node *np = host->mmc->parent->of_node; struct device_node *np = host->mmc->parent->of_node;
...@@ -592,6 +714,11 @@ void sdmmc_variant_init(struct mmci_host *host) ...@@ -592,6 +714,11 @@ void sdmmc_variant_init(struct mmci_host *host)
return; return;
dlyb->base = base_dlyb; dlyb->base = base_dlyb;
if (of_device_is_compatible(np, "st,stm32mp25-sdmmc2"))
dlyb->ops = &dlyb_tuning_mp25_ops;
else
dlyb->ops = &dlyb_tuning_mp15_ops;
host->variant_priv = dlyb; host->variant_priv = dlyb;
host->mmc_ops->execute_tuning = sdmmc_execute_tuning; host->mmc_ops->execute_tuning = sdmmc_execute_tuning;
} }
...@@ -473,6 +473,7 @@ struct msdc_host { ...@@ -473,6 +473,7 @@ struct msdc_host {
struct msdc_tune_para def_tune_para; /* default tune setting */ struct msdc_tune_para def_tune_para; /* default tune setting */
struct msdc_tune_para saved_tune_para; /* tune result of CMD21/CMD19 */ struct msdc_tune_para saved_tune_para; /* tune result of CMD21/CMD19 */
struct cqhci_host *cq_host; struct cqhci_host *cq_host;
u32 cq_ssc1_time;
}; };
static const struct mtk_mmc_compatible mt2701_compat = { static const struct mtk_mmc_compatible mt2701_compat = {
...@@ -2450,9 +2451,49 @@ static void msdc_hs400_enhanced_strobe(struct mmc_host *mmc, ...@@ -2450,9 +2451,49 @@ static void msdc_hs400_enhanced_strobe(struct mmc_host *mmc,
} }
} }
static void msdc_cqe_cit_cal(struct msdc_host *host, u64 timer_ns)
{
struct mmc_host *mmc = mmc_from_priv(host);
struct cqhci_host *cq_host = mmc->cqe_private;
u8 itcfmul;
u64 hclk_freq, value;
/*
* On MediaTek SoCs the MSDC controller's CQE uses msdc_hclk as ITCFVAL
* so we multiply/divide the HCLK frequency by ITCFMUL to calculate the
* Send Status Command Idle Timer (CIT) value.
*/
hclk_freq = (u64)clk_get_rate(host->h_clk);
itcfmul = CQHCI_ITCFMUL(cqhci_readl(cq_host, CQHCI_CAP));
switch (itcfmul) {
case 0x0:
do_div(hclk_freq, 1000);
break;
case 0x1:
do_div(hclk_freq, 100);
break;
case 0x2:
do_div(hclk_freq, 10);
break;
case 0x3:
break;
case 0x4:
hclk_freq = hclk_freq * 10;
break;
default:
host->cq_ssc1_time = 0x40;
return;
}
value = hclk_freq * timer_ns;
do_div(value, 1000000000);
host->cq_ssc1_time = value;
}
static void msdc_cqe_enable(struct mmc_host *mmc) static void msdc_cqe_enable(struct mmc_host *mmc)
{ {
struct msdc_host *host = mmc_priv(mmc); struct msdc_host *host = mmc_priv(mmc);
struct cqhci_host *cq_host = mmc->cqe_private;
/* enable cmdq irq */ /* enable cmdq irq */
writel(MSDC_INT_CMDQ, host->base + MSDC_INTEN); writel(MSDC_INT_CMDQ, host->base + MSDC_INTEN);
...@@ -2462,6 +2503,9 @@ static void msdc_cqe_enable(struct mmc_host *mmc) ...@@ -2462,6 +2503,9 @@ static void msdc_cqe_enable(struct mmc_host *mmc)
msdc_set_busy_timeout(host, 20 * 1000000000ULL, 0); msdc_set_busy_timeout(host, 20 * 1000000000ULL, 0);
/* default read data timeout 1s */ /* default read data timeout 1s */
msdc_set_timeout(host, 1000000000ULL, 0); msdc_set_timeout(host, 1000000000ULL, 0);
/* Set the send status command idle timer */
cqhci_writel(cq_host, host->cq_ssc1_time, CQHCI_SSC1);
} }
static void msdc_cqe_disable(struct mmc_host *mmc, bool recovery) static void msdc_cqe_disable(struct mmc_host *mmc, bool recovery)
...@@ -2707,7 +2751,7 @@ static int msdc_drv_probe(struct platform_device *pdev) ...@@ -2707,7 +2751,7 @@ static int msdc_drv_probe(struct platform_device *pdev)
/* Support for SDIO eint irq ? */ /* Support for SDIO eint irq ? */
if ((mmc->pm_caps & MMC_PM_WAKE_SDIO_IRQ) && (mmc->pm_caps & MMC_PM_KEEP_POWER)) { if ((mmc->pm_caps & MMC_PM_WAKE_SDIO_IRQ) && (mmc->pm_caps & MMC_PM_KEEP_POWER)) {
host->eint_irq = platform_get_irq_byname(pdev, "sdio_wakeup"); host->eint_irq = platform_get_irq_byname_optional(pdev, "sdio_wakeup");
if (host->eint_irq > 0) { if (host->eint_irq > 0) {
host->pins_eint = pinctrl_lookup_state(host->pinctrl, "state_eint"); host->pins_eint = pinctrl_lookup_state(host->pinctrl, "state_eint");
if (IS_ERR(host->pins_eint)) { if (IS_ERR(host->pins_eint)) {
...@@ -2803,6 +2847,8 @@ static int msdc_drv_probe(struct platform_device *pdev) ...@@ -2803,6 +2847,8 @@ static int msdc_drv_probe(struct platform_device *pdev)
/* cqhci 16bit length */ /* cqhci 16bit length */
/* 0 size, means 65536 so we don't have to -1 here */ /* 0 size, means 65536 so we don't have to -1 here */
mmc->max_seg_size = 64 * 1024; mmc->max_seg_size = 64 * 1024;
/* Reduce CIT to 0x40 that corresponds to 2.35us */
msdc_cqe_cit_cal(host, 2350);
} }
ret = devm_request_irq(&pdev->dev, host->irq, msdc_irq, ret = devm_request_irq(&pdev->dev, host->irq, msdc_irq,
......
...@@ -13,12 +13,13 @@ ...@@ -13,12 +13,13 @@
#include <linux/pm_opp.h> #include <linux/pm_opp.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/interconnect.h> #include <linux/interconnect.h>
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include <linux/reset.h> #include <linux/reset.h>
#include <soc/qcom/ice.h>
#include "sdhci-cqhci.h" #include "sdhci-cqhci.h"
#include "sdhci-pltfm.h" #include "sdhci-pltfm.h"
#include "cqhci.h" #include "cqhci.h"
...@@ -258,12 +259,14 @@ struct sdhci_msm_variant_info { ...@@ -258,12 +259,14 @@ struct sdhci_msm_variant_info {
struct sdhci_msm_host { struct sdhci_msm_host {
struct platform_device *pdev; struct platform_device *pdev;
void __iomem *core_mem; /* MSM SDCC mapped address */ void __iomem *core_mem; /* MSM SDCC mapped address */
void __iomem *ice_mem; /* MSM ICE mapped address (if available) */
int pwr_irq; /* power irq */ int pwr_irq; /* power irq */
struct clk *bus_clk; /* SDHC bus voter clock */ struct clk *bus_clk; /* SDHC bus voter clock */
struct clk *xo_clk; /* TCXO clk needed for FLL feature of cm_dll*/ struct clk *xo_clk; /* TCXO clk needed for FLL feature of cm_dll*/
/* core, iface, cal, sleep, and ice clocks */ /* core, iface, cal and sleep clocks */
struct clk_bulk_data bulk_clks[5]; struct clk_bulk_data bulk_clks[4];
#ifdef CONFIG_MMC_CRYPTO
struct qcom_ice *ice;
#endif
unsigned long clk_rate; unsigned long clk_rate;
struct mmc_host *mmc; struct mmc_host *mmc;
bool use_14lpp_dll_reset; bool use_14lpp_dll_reset;
...@@ -1804,164 +1807,51 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) ...@@ -1804,164 +1807,51 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
#ifdef CONFIG_MMC_CRYPTO #ifdef CONFIG_MMC_CRYPTO
#define AES_256_XTS_KEY_SIZE 64
/* QCOM ICE registers */
#define QCOM_ICE_REG_VERSION 0x0008
#define QCOM_ICE_REG_FUSE_SETTING 0x0010
#define QCOM_ICE_FUSE_SETTING_MASK 0x1
#define QCOM_ICE_FORCE_HW_KEY0_SETTING_MASK 0x2
#define QCOM_ICE_FORCE_HW_KEY1_SETTING_MASK 0x4
#define QCOM_ICE_REG_BIST_STATUS 0x0070
#define QCOM_ICE_BIST_STATUS_MASK 0xF0000000
#define QCOM_ICE_REG_ADVANCED_CONTROL 0x1000
#define sdhci_msm_ice_writel(host, val, reg) \
writel((val), (host)->ice_mem + (reg))
#define sdhci_msm_ice_readl(host, reg) \
readl((host)->ice_mem + (reg))
static bool sdhci_msm_ice_supported(struct sdhci_msm_host *msm_host)
{
struct device *dev = mmc_dev(msm_host->mmc);
u32 regval = sdhci_msm_ice_readl(msm_host, QCOM_ICE_REG_VERSION);
int major = regval >> 24;
int minor = (regval >> 16) & 0xFF;
int step = regval & 0xFFFF;
/* For now this driver only supports ICE version 3. */
if (major != 3) {
dev_warn(dev, "Unsupported ICE version: v%d.%d.%d\n",
major, minor, step);
return false;
}
dev_info(dev, "Found QC Inline Crypto Engine (ICE) v%d.%d.%d\n",
major, minor, step);
/* If fuses are blown, ICE might not work in the standard way. */
regval = sdhci_msm_ice_readl(msm_host, QCOM_ICE_REG_FUSE_SETTING);
if (regval & (QCOM_ICE_FUSE_SETTING_MASK |
QCOM_ICE_FORCE_HW_KEY0_SETTING_MASK |
QCOM_ICE_FORCE_HW_KEY1_SETTING_MASK)) {
dev_warn(dev, "Fuses are blown; ICE is unusable!\n");
return false;
}
return true;
}
static inline struct clk *sdhci_msm_ice_get_clk(struct device *dev)
{
return devm_clk_get(dev, "ice");
}
static int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host, static int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host,
struct cqhci_host *cq_host) struct cqhci_host *cq_host)
{ {
struct mmc_host *mmc = msm_host->mmc; struct mmc_host *mmc = msm_host->mmc;
struct device *dev = mmc_dev(mmc); struct device *dev = mmc_dev(mmc);
struct resource *res; struct qcom_ice *ice;
if (!(cqhci_readl(cq_host, CQHCI_CAP) & CQHCI_CAP_CS)) if (!(cqhci_readl(cq_host, CQHCI_CAP) & CQHCI_CAP_CS))
return 0; return 0;
res = platform_get_resource_byname(msm_host->pdev, IORESOURCE_MEM, ice = of_qcom_ice_get(dev);
"ice"); if (ice == ERR_PTR(-EOPNOTSUPP)) {
if (!res) { dev_warn(dev, "Disabling inline encryption support\n");
dev_warn(dev, "ICE registers not found\n"); ice = NULL;
goto disable;
}
if (!qcom_scm_ice_available()) {
dev_warn(dev, "ICE SCM interface not found\n");
goto disable;
} }
msm_host->ice_mem = devm_ioremap_resource(dev, res); if (IS_ERR_OR_NULL(ice))
if (IS_ERR(msm_host->ice_mem)) return PTR_ERR_OR_ZERO(ice);
return PTR_ERR(msm_host->ice_mem);
if (!sdhci_msm_ice_supported(msm_host))
goto disable;
msm_host->ice = ice;
mmc->caps2 |= MMC_CAP2_CRYPTO; mmc->caps2 |= MMC_CAP2_CRYPTO;
return 0;
disable:
dev_warn(dev, "Disabling inline encryption support\n");
return 0; return 0;
} }
static void sdhci_msm_ice_low_power_mode_enable(struct sdhci_msm_host *msm_host) static void sdhci_msm_ice_enable(struct sdhci_msm_host *msm_host)
{
u32 regval;
regval = sdhci_msm_ice_readl(msm_host, QCOM_ICE_REG_ADVANCED_CONTROL);
/*
* Enable low power mode sequence
* [0]-0, [1]-0, [2]-0, [3]-E, [4]-0, [5]-0, [6]-0, [7]-0
*/
regval |= 0x7000;
sdhci_msm_ice_writel(msm_host, regval, QCOM_ICE_REG_ADVANCED_CONTROL);
}
static void sdhci_msm_ice_optimization_enable(struct sdhci_msm_host *msm_host)
{ {
u32 regval; if (msm_host->mmc->caps2 & MMC_CAP2_CRYPTO)
qcom_ice_enable(msm_host->ice);
/* ICE Optimizations Enable Sequence */
regval = sdhci_msm_ice_readl(msm_host, QCOM_ICE_REG_ADVANCED_CONTROL);
regval |= 0xD807100;
/* ICE HPG requires delay before writing */
udelay(5);
sdhci_msm_ice_writel(msm_host, regval, QCOM_ICE_REG_ADVANCED_CONTROL);
udelay(5);
} }
/* static __maybe_unused int sdhci_msm_ice_resume(struct sdhci_msm_host *msm_host)
* Wait until the ICE BIST (built-in self-test) has completed.
*
* This may be necessary before ICE can be used.
*
* Note that we don't really care whether the BIST passed or failed; we really
* just want to make sure that it isn't still running. This is because (a) the
* BIST is a FIPS compliance thing that never fails in practice, (b) ICE is
* documented to reject crypto requests if the BIST fails, so we needn't do it
* in software too, and (c) properly testing storage encryption requires testing
* the full storage stack anyway, and not relying on hardware-level self-tests.
*/
static int sdhci_msm_ice_wait_bist_status(struct sdhci_msm_host *msm_host)
{ {
u32 regval; if (msm_host->mmc->caps2 & MMC_CAP2_CRYPTO)
int err; return qcom_ice_resume(msm_host->ice);
err = readl_poll_timeout(msm_host->ice_mem + QCOM_ICE_REG_BIST_STATUS, return 0;
regval, !(regval & QCOM_ICE_BIST_STATUS_MASK),
50, 5000);
if (err)
dev_err(mmc_dev(msm_host->mmc),
"Timed out waiting for ICE self-test to complete\n");
return err;
} }
static void sdhci_msm_ice_enable(struct sdhci_msm_host *msm_host) static __maybe_unused int sdhci_msm_ice_suspend(struct sdhci_msm_host *msm_host)
{ {
if (!(msm_host->mmc->caps2 & MMC_CAP2_CRYPTO)) if (msm_host->mmc->caps2 & MMC_CAP2_CRYPTO)
return; return qcom_ice_suspend(msm_host->ice);
sdhci_msm_ice_low_power_mode_enable(msm_host);
sdhci_msm_ice_optimization_enable(msm_host);
sdhci_msm_ice_wait_bist_status(msm_host);
}
static int __maybe_unused sdhci_msm_ice_resume(struct sdhci_msm_host *msm_host) return 0;
{
if (!(msm_host->mmc->caps2 & MMC_CAP2_CRYPTO))
return 0;
return sdhci_msm_ice_wait_bist_status(msm_host);
} }
/* /*
...@@ -1972,48 +1862,28 @@ static int sdhci_msm_program_key(struct cqhci_host *cq_host, ...@@ -1972,48 +1862,28 @@ static int sdhci_msm_program_key(struct cqhci_host *cq_host,
const union cqhci_crypto_cfg_entry *cfg, const union cqhci_crypto_cfg_entry *cfg,
int slot) int slot)
{ {
struct device *dev = mmc_dev(cq_host->mmc); struct sdhci_host *host = mmc_priv(cq_host->mmc);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
union cqhci_crypto_cap_entry cap; union cqhci_crypto_cap_entry cap;
union {
u8 bytes[AES_256_XTS_KEY_SIZE];
u32 words[AES_256_XTS_KEY_SIZE / sizeof(u32)];
} key;
int i;
int err;
if (!(cfg->config_enable & CQHCI_CRYPTO_CONFIGURATION_ENABLE))
return qcom_scm_ice_invalidate_key(slot);
/* Only AES-256-XTS has been tested so far. */ /* Only AES-256-XTS has been tested so far. */
cap = cq_host->crypto_cap_array[cfg->crypto_cap_idx]; cap = cq_host->crypto_cap_array[cfg->crypto_cap_idx];
if (cap.algorithm_id != CQHCI_CRYPTO_ALG_AES_XTS || if (cap.algorithm_id != CQHCI_CRYPTO_ALG_AES_XTS ||
cap.key_size != CQHCI_CRYPTO_KEY_SIZE_256) { cap.key_size != CQHCI_CRYPTO_KEY_SIZE_256)
dev_err_ratelimited(dev,
"Unhandled crypto capability; algorithm_id=%d, key_size=%d\n",
cap.algorithm_id, cap.key_size);
return -EINVAL; return -EINVAL;
}
memcpy(key.bytes, cfg->crypto_key, AES_256_XTS_KEY_SIZE); if (cfg->config_enable & CQHCI_CRYPTO_CONFIGURATION_ENABLE)
return qcom_ice_program_key(msm_host->ice,
/* QCOM_ICE_CRYPTO_ALG_AES_XTS,
* The SCM call byte-swaps the 32-bit words of the key. So we have to QCOM_ICE_CRYPTO_KEY_SIZE_256,
* do the same, in order for the final key be correct. cfg->crypto_key,
*/ cfg->data_unit_size, slot);
for (i = 0; i < ARRAY_SIZE(key.words); i++) else
__cpu_to_be32s(&key.words[i]); return qcom_ice_evict_key(msm_host->ice, slot);
err = qcom_scm_ice_set_key(slot, key.bytes, AES_256_XTS_KEY_SIZE,
QCOM_SCM_ICE_CIPHER_AES_256_XTS,
cfg->data_unit_size);
memzero_explicit(&key, sizeof(key));
return err;
} }
#else /* CONFIG_MMC_CRYPTO */ #else /* CONFIG_MMC_CRYPTO */
static inline struct clk *sdhci_msm_ice_get_clk(struct device *dev)
{
return NULL;
}
static inline int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host, static inline int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host,
struct cqhci_host *cq_host) struct cqhci_host *cq_host)
...@@ -2025,11 +1895,17 @@ static inline void sdhci_msm_ice_enable(struct sdhci_msm_host *msm_host) ...@@ -2025,11 +1895,17 @@ static inline void sdhci_msm_ice_enable(struct sdhci_msm_host *msm_host)
{ {
} }
static inline int __maybe_unused static inline __maybe_unused int
sdhci_msm_ice_resume(struct sdhci_msm_host *msm_host) sdhci_msm_ice_resume(struct sdhci_msm_host *msm_host)
{ {
return 0; return 0;
} }
static inline __maybe_unused int
sdhci_msm_ice_suspend(struct sdhci_msm_host *msm_host)
{
return 0;
}
#endif /* !CONFIG_MMC_CRYPTO */ #endif /* !CONFIG_MMC_CRYPTO */
/*****************************************************************************\ /*****************************************************************************\
...@@ -2633,11 +2509,6 @@ static int sdhci_msm_probe(struct platform_device *pdev) ...@@ -2633,11 +2509,6 @@ static int sdhci_msm_probe(struct platform_device *pdev)
clk = NULL; clk = NULL;
msm_host->bulk_clks[3].clk = clk; msm_host->bulk_clks[3].clk = clk;
clk = sdhci_msm_ice_get_clk(&pdev->dev);
if (IS_ERR(clk))
clk = NULL;
msm_host->bulk_clks[4].clk = clk;
ret = clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks), ret = clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks),
msm_host->bulk_clks); msm_host->bulk_clks);
if (ret) if (ret)
...@@ -2830,7 +2701,7 @@ static __maybe_unused int sdhci_msm_runtime_suspend(struct device *dev) ...@@ -2830,7 +2701,7 @@ static __maybe_unused int sdhci_msm_runtime_suspend(struct device *dev)
clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks), clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks),
msm_host->bulk_clks); msm_host->bulk_clks);
return 0; return sdhci_msm_ice_suspend(msm_host);
} }
static __maybe_unused int sdhci_msm_runtime_resume(struct device *dev) static __maybe_unused int sdhci_msm_runtime_resume(struct device *dev)
......
...@@ -1903,6 +1903,7 @@ static const struct pci_device_id pci_ids[] = { ...@@ -1903,6 +1903,7 @@ static const struct pci_device_id pci_ids[] = {
SDHCI_PCI_DEVICE(GLI, 9750, gl9750), SDHCI_PCI_DEVICE(GLI, 9750, gl9750),
SDHCI_PCI_DEVICE(GLI, 9755, gl9755), SDHCI_PCI_DEVICE(GLI, 9755, gl9755),
SDHCI_PCI_DEVICE(GLI, 9763E, gl9763e), SDHCI_PCI_DEVICE(GLI, 9763E, gl9763e),
SDHCI_PCI_DEVICE(GLI, 9767, gl9767),
SDHCI_PCI_DEVICE_CLASS(AMD, SYSTEM_SDHCI, PCI_CLASS_MASK, amd), SDHCI_PCI_DEVICE_CLASS(AMD, SYSTEM_SDHCI, PCI_CLASS_MASK, amd),
/* Generic SD host controller */ /* Generic SD host controller */
{PCI_DEVICE_CLASS(SYSTEM_SDHCI, PCI_CLASS_MASK)}, {PCI_DEVICE_CLASS(SYSTEM_SDHCI, PCI_CLASS_MASK)},
......
This diff is collapsed.
...@@ -76,6 +76,7 @@ ...@@ -76,6 +76,7 @@
#define PCI_DEVICE_ID_GLI_9755 0x9755 #define PCI_DEVICE_ID_GLI_9755 0x9755
#define PCI_DEVICE_ID_GLI_9750 0x9750 #define PCI_DEVICE_ID_GLI_9750 0x9750
#define PCI_DEVICE_ID_GLI_9763E 0xe763 #define PCI_DEVICE_ID_GLI_9763E 0xe763
#define PCI_DEVICE_ID_GLI_9767 0x9767
/* /*
* PCI device class and mask * PCI device class and mask
...@@ -195,5 +196,6 @@ extern const struct sdhci_pci_fixes sdhci_o2; ...@@ -195,5 +196,6 @@ extern const struct sdhci_pci_fixes sdhci_o2;
extern const struct sdhci_pci_fixes sdhci_gl9750; extern const struct sdhci_pci_fixes sdhci_gl9750;
extern const struct sdhci_pci_fixes sdhci_gl9755; extern const struct sdhci_pci_fixes sdhci_gl9755;
extern const struct sdhci_pci_fixes sdhci_gl9763e; extern const struct sdhci_pci_fixes sdhci_gl9763e;
extern const struct sdhci_pci_fixes sdhci_gl9767;
#endif /* __SDHCI_PCI_H */ #endif /* __SDHCI_PCI_H */
...@@ -1167,6 +1167,8 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) ...@@ -1167,6 +1167,8 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
} }
} }
sdhci_config_dma(host);
if (host->flags & SDHCI_REQ_USE_DMA) { if (host->flags & SDHCI_REQ_USE_DMA) {
int sg_cnt = sdhci_pre_dma_transfer(host, data, COOKIE_MAPPED); int sg_cnt = sdhci_pre_dma_transfer(host, data, COOKIE_MAPPED);
...@@ -1186,8 +1188,6 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) ...@@ -1186,8 +1188,6 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
} }
} }
sdhci_config_dma(host);
if (!(host->flags & SDHCI_REQ_USE_DMA)) { if (!(host->flags & SDHCI_REQ_USE_DMA)) {
int flags; int flags;
......
...@@ -99,6 +99,13 @@ ...@@ -99,6 +99,13 @@
#define SDHCI_POWER_180 0x0A #define SDHCI_POWER_180 0x0A
#define SDHCI_POWER_300 0x0C #define SDHCI_POWER_300 0x0C
#define SDHCI_POWER_330 0x0E #define SDHCI_POWER_330 0x0E
/*
* VDD2 - UHS2 or PCIe/NVMe
* VDD2 power on/off and voltage select
*/
#define SDHCI_VDD2_POWER_ON 0x10
#define SDHCI_VDD2_POWER_120 0x80
#define SDHCI_VDD2_POWER_180 0xA0
#define SDHCI_BLOCK_GAP_CONTROL 0x2A #define SDHCI_BLOCK_GAP_CONTROL 0x2A
......
...@@ -294,6 +294,7 @@ struct mmc_card { ...@@ -294,6 +294,7 @@ struct mmc_card {
#define MMC_QUIRK_TRIM_BROKEN (1<<12) /* Skip trim */ #define MMC_QUIRK_TRIM_BROKEN (1<<12) /* Skip trim */
#define MMC_QUIRK_BROKEN_HPI (1<<13) /* Disable broken HPI support */ #define MMC_QUIRK_BROKEN_HPI (1<<13) /* Disable broken HPI support */
#define MMC_QUIRK_BROKEN_SD_DISCARD (1<<14) /* Disable broken SD discard support */ #define MMC_QUIRK_BROKEN_SD_DISCARD (1<<14) /* Disable broken SD discard support */
#define MMC_QUIRK_BROKEN_SD_CACHE (1<<15) /* Disable broken SD cache support */
bool reenable_cmdq; /* Re-enable Command Queue */ bool reenable_cmdq; /* Re-enable Command Queue */
......
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