forked from Minki/linux
MMC core:
- Fix hanging on I/O during system suspend for removable cards - Set read only for SD cards with permanent write protect bit - Power cycle the SD/SDIO card if CMD11 fails for UHS voltage - Issue a cache flush for eMMC only when it's enabled - Adopt to updated cache ctrl settings for eMMC from MMC ioctls - Use use device property API when parsing voltages - Don't retry eMMC sanitize cmds - Use the timeout from the MMC ioctl for eMMC santize cmds MMC host: - mmc_spi: Make of_mmc_spi.c resource provider agnostic - mmc_spi: Use polling for card detect even without voltage-ranges - sdhci: Check for reset prior to DMA address unmap - sdhci-acpi: Add support for the AMDI0041 eMMC controller variant - sdhci-esdhc-imx: Depending on OF Kconfig and cleanup code - sdhci-pci: Add PCI IDs for Intel LKF - sdhci-pci: Fix initialization of some SD cards for Intel BYT - sdhci-pci-gli: Various improvements for GL97xx variants - sdhci-of-dwcmshc: Enable support for MMC_CAP_WAIT_WHILE_BUSY - sdhci-of-dwcmshc: Add ACPI support for BlueField-3 SoC - sdhci-of-dwcmshc: Add Rockchip platform support - tmio/renesas_sdhi: Extend support for reset and use a reset controller - tmio/renesas_sdhi: Enable support for MMC_CAP_WAIT_WHILE_BUSY - tmio/renesas_sdhi: Various improvements MEMSTICK: - Minor improvements/cleanups. -----BEGIN PGP SIGNATURE----- iQJLBAABCgA1FiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAmCJIGkXHHVsZi5oYW5z c29uQGxpbmFyby5vcmcACgkQ/iaEJXNYjCnX+w//fvTbFsekv/bYZQoiDDGngbg0 LGUfTZPOLWuzHpiQSY5RjRHvt9CFOc07N96RAqxeqgJ3LS2WzIQSn9asK+5EupXH CVnWKcYBs+1KthMCRsXjduXILztSQFJGbgO8DYrqvwu9mg6SU3ExfqNhX0O+D0ed GhzQ55yJTitRpa8S2FYQcirl+clV/5+o3uC82nvaoVR1baE1+catNJ028k/Nd0XE dFboEE6IJ4qndLWAyBnijYMXbLq/HKmqjeNsR5tooAA/QcXf9tQKqHtdim1N1Cac THF3hGHMskw7bM4PoupzeJYHzYmL6UINkw192BLMNsGCHidflWTarjUR/5Y2OEz1 eKG5GX+Ww+fdsupN8h448rI1h3EcKJlQFvit9/OIcHS8r7ZeouWNXElH3WUpc3i4 pb3yHBBNMQ3rn0wUfjZh2sggyy+/pRAY1OPfeDud1wggRjg/xVMY3nxpqQmFRKZM C2/mPUMxaY7zHb9AzCOYCjhgjTPh4HrzIRZeqnZ1FRGuv0yLDG46hc1ufLggCx5P v1RGB2vJ2hGyWIqvBXw1nF8RwiOCXYXPyZjehWU0K6zryGQPq275/6ziFvL+Nh4U 8liwwHeeIQNvPs7HNzSQ1rXo8elNRvWkqZpvCqTWgJCX4/NFYQTj+Lq2T2EiTxWt dlr9RLlARJEeutA07rM= =WL87 -----END PGP SIGNATURE----- Merge tag 'mmc-v5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc Pull MMC and MEMSTICK updates from Ulf Hansson: "MMC core: - Fix hanging on I/O during system suspend for removable cards - Set read only for SD cards with permanent write protect bit - Power cycle the SD/SDIO card if CMD11 fails for UHS voltage - Issue a cache flush for eMMC only when it's enabled - Adopt to updated cache ctrl settings for eMMC from MMC ioctls - Use use device property API when parsing voltages - Don't retry eMMC sanitize cmds - Use the timeout from the MMC ioctl for eMMC santize cmds MMC host: - mmc_spi: Make of_mmc_spi.c resource provider agnostic - mmc_spi: Use polling for card detect even without voltage-ranges - sdhci: Check for reset prior to DMA address unmap - sdhci-acpi: Add support for the AMDI0041 eMMC controller variant - sdhci-esdhc-imx: Depending on OF Kconfig and cleanup code - sdhci-pci: Add PCI IDs for Intel LKF - sdhci-pci: Fix initialization of some SD cards for Intel BYT - sdhci-pci-gli: Various improvements for GL97xx variants - sdhci-of-dwcmshc: Enable support for MMC_CAP_WAIT_WHILE_BUSY - sdhci-of-dwcmshc: Add ACPI support for BlueField-3 SoC - sdhci-of-dwcmshc: Add Rockchip platform support - tmio/renesas_sdhi: Extend support for reset and use a reset controller - tmio/renesas_sdhi: Enable support for MMC_CAP_WAIT_WHILE_BUSY - tmio/renesas_sdhi: Various improvements MEMSTICK: - Minor improvements/cleanups" * tag 'mmc-v5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (79 commits) mmc: block: Issue a cache flush only when it's enabled memstick: r592: ignore kfifo_out() return code again mmc: block: Update ext_csd.cache_ctrl if it was written mmc: mmc_spi: Make of_mmc_spi.c resource provider agnostic mmc: mmc_spi: Use already parsed IRQ mmc: mmc_spi: Drop unused NO_IRQ definition mmc: mmc_spi: Set up polling even if voltage-ranges is not present mmc: core: Convert mmc_of_parse_voltage() to use device property API mmc: core: Correct descriptions in mmc_of_parse() mmc: dw_mmc-rockchip: Just set default sample value for legacy mode mmc: sdhci-s3c: constify uses of driver/match data mmc: sdhci-s3c: correct kerneldoc of sdhci_s3c_drv_data mmc: sdhci-s3c: simplify getting of_device_id match data mmc: tmio: always restore irq register mmc: sdhci-pci-gli: Enlarge ASPM L1 entry delay of GL975x mmc: core: Let eMMC sanitize not retry in case of timeout/failure mmc: core: Add a retries parameter to __mmc_switch function memstick: r592: remove unused variable mmc: sdhci-st: Remove unnecessary error log mmc: sdhci-msm: Remove unnecessary error log ...
This commit is contained in:
commit
be18cd1fca
63
Documentation/devicetree/bindings/mmc/brcm,iproc-sdhci.yaml
Normal file
63
Documentation/devicetree/bindings/mmc/brcm,iproc-sdhci.yaml
Normal file
@ -0,0 +1,63 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mmc/brcm,iproc-sdhci.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Broadcom IPROC SDHCI controller
|
||||
|
||||
maintainers:
|
||||
- Ray Jui <ray.jui@broadcom.com>
|
||||
- Scott Branden <scott.branden@broadcom.com>
|
||||
- Nicolas Saenz Julienne <nsaenz@kernel.org>
|
||||
|
||||
allOf:
|
||||
- $ref: mmc-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- brcm,bcm2835-sdhci
|
||||
- brcm,bcm2711-emmc2
|
||||
- brcm,sdhci-iproc-cygnus
|
||||
- brcm,sdhci-iproc
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
description:
|
||||
Handle to core clock for the sdhci controller.
|
||||
|
||||
sdhci,auto-cmd12:
|
||||
type: boolean
|
||||
description: Specifies that controller should use auto CMD12
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/clock/bcm-cygnus.h>
|
||||
|
||||
mmc@18041000 {
|
||||
compatible = "brcm,sdhci-iproc-cygnus";
|
||||
reg = <0x18041000 0x100>;
|
||||
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&lcpll0_clks BCM_CYGNUS_LCPLL0_SDIO_CLK>;
|
||||
bus-width = <4>;
|
||||
sdhci,auto-cmd12;
|
||||
no-1-8-v;
|
||||
};
|
||||
...
|
@ -1,37 +0,0 @@
|
||||
Broadcom IPROC SDHCI controller
|
||||
|
||||
This file documents differences between the core properties described
|
||||
by mmc.txt and the properties that represent the IPROC SDHCI controller.
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be one of the following
|
||||
"brcm,bcm2835-sdhci"
|
||||
"brcm,bcm2711-emmc2"
|
||||
"brcm,sdhci-iproc-cygnus"
|
||||
"brcm,sdhci-iproc"
|
||||
|
||||
Use brcm2835-sdhci for the eMMC controller on the BCM2835 (Raspberry Pi) and
|
||||
bcm2711-emmc2 for the additional eMMC2 controller on BCM2711.
|
||||
|
||||
Use sdhci-iproc-cygnus for Broadcom SDHCI Controllers
|
||||
restricted to 32bit host accesses to SDHCI registers.
|
||||
|
||||
Use sdhci-iproc for Broadcom SDHCI Controllers that allow standard
|
||||
8, 16, 32-bit host access to SDHCI register.
|
||||
|
||||
- clocks : The clock feeding the SDHCI controller.
|
||||
|
||||
Optional properties:
|
||||
- sdhci,auto-cmd12: specifies that controller should use auto CMD12.
|
||||
|
||||
Example:
|
||||
|
||||
sdhci0: sdhci@18041000 {
|
||||
compatible = "brcm,sdhci-iproc-cygnus";
|
||||
reg = <0x18041000 0x100>;
|
||||
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&lcpll0_clks BCM_CYGNUS_LCPLL0_SDIO_CLK>;
|
||||
bus-width = <4>;
|
||||
sdhci,auto-cmd12;
|
||||
no-1-8-v;
|
||||
};
|
@ -103,6 +103,26 @@ properties:
|
||||
Only eMMC HS400 mode need to take care of this property.
|
||||
default: 0
|
||||
|
||||
clocks:
|
||||
maxItems: 3
|
||||
description:
|
||||
Handle clocks for the sdhc controller.
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ipg
|
||||
- const: ahb
|
||||
- const: per
|
||||
|
||||
pinctrl-names:
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
items:
|
||||
- const: default
|
||||
- const: state_100mhz
|
||||
- const: state_200mhz
|
||||
- const: sleep
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -5,11 +5,11 @@ by mmc.txt and the properties used by the mmc_spi driver.
|
||||
|
||||
Required properties:
|
||||
- spi-max-frequency : maximum frequency for this device (Hz).
|
||||
- voltage-ranges : two cells are required, first cell specifies minimum
|
||||
slot voltage (mV), second cell specifies maximum slot voltage (mV).
|
||||
Several ranges could be specified.
|
||||
|
||||
Optional properties:
|
||||
- voltage-ranges : two cells are required, first cell specifies minimum
|
||||
slot voltage (mV), second cell specifies maximum slot voltage (mV).
|
||||
Several ranges could be specified. If not provided, 3.2v..3.4v is assumed.
|
||||
- gpios : may specify GPIOs in this order: Card-Detect GPIO,
|
||||
Write-Protect GPIO. Note that this does not follow the
|
||||
binding from mmc.txt, for historical reasons.
|
||||
|
@ -31,6 +31,7 @@ properties:
|
||||
- const: mediatek,mt2701-mmc
|
||||
- items:
|
||||
- const: mediatek,mt8192-mmc
|
||||
- const: mediatek,mt8195-mmc
|
||||
- const: mediatek,mt8183-mmc
|
||||
|
||||
clocks:
|
||||
|
@ -1,20 +0,0 @@
|
||||
* Synopsys DesignWare Cores Mobile Storage Host Controller
|
||||
|
||||
Required properties:
|
||||
- compatible: should be one of the following:
|
||||
"snps,dwcmshc-sdhci"
|
||||
- reg: offset and length of the register set for the device.
|
||||
- interrupts: a single interrupt specifier.
|
||||
- clocks: Array of clocks required for SDHCI; requires at least one for
|
||||
core clock.
|
||||
- clock-names: Array of names corresponding to clocks property; shall be
|
||||
"core" for core clock and "bus" for optional bus clock.
|
||||
|
||||
Example:
|
||||
sdhci2: sdhci@aa0000 {
|
||||
compatible = "snps,dwcmshc-sdhci";
|
||||
reg = <0xaa0000 0x1000>;
|
||||
interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&emmcclk>;
|
||||
bus-width = <8>;
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mmc/snps,dwcmshc-sdhci.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Synopsys Designware Mobile Storage Host Controller Binding
|
||||
|
||||
maintainers:
|
||||
- Ulf Hansson <ulf.hansson@linaro.org>
|
||||
- Jisheng Zhang <Jisheng.Zhang@synaptics.com>
|
||||
|
||||
allOf:
|
||||
- $ref: mmc-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- rockchip,rk3568-dwcmshc
|
||||
- snps,dwcmshc-sdhci
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
items:
|
||||
- description: Offset and length of the register set for the device
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
items:
|
||||
- description: core clock
|
||||
- description: bus clock for optional
|
||||
- description: axi clock for rockchip specified
|
||||
- description: block clock for rockchip specified
|
||||
- description: timer clock for rockchip specified
|
||||
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
items:
|
||||
- const: core
|
||||
- const: bus
|
||||
- const: axi
|
||||
- const: block
|
||||
- const: timer
|
||||
|
||||
rockchip,txclk-tapnum:
|
||||
description: Specify the number of delay for tx sampling.
|
||||
$ref: /schemas/types.yaml#/definitions/uint8
|
||||
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
mmc@fe310000 {
|
||||
compatible = "rockchip,rk3568-dwcmshc";
|
||||
reg = <0xfe310000 0x10000>;
|
||||
interrupts = <0 25 0x4>;
|
||||
clocks = <&cru 17>, <&cru 18>, <&cru 19>, <&cru 20>, <&cru 21>;
|
||||
clock-names = "core", "bus", "axi", "block", "timer";
|
||||
bus-width = <8>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
- |
|
||||
mmc@aa0000 {
|
||||
compatible = "snps,dwcmshc-sdhci";
|
||||
reg = <0xaa000 0x1000>;
|
||||
interrupts = <0 25 0x4>;
|
||||
clocks = <&cru 17>, <&cru 18>;
|
||||
clock-names = "core", "bus";
|
||||
bus-width = <8>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
|
||||
...
|
@ -331,18 +331,17 @@ static int h_memstick_read_dev_id(struct memstick_dev *card,
|
||||
sizeof(struct ms_id_register));
|
||||
*mrq = &card->current_mrq;
|
||||
return 0;
|
||||
} else {
|
||||
if (!(*mrq)->error) {
|
||||
memcpy(&id_reg, (*mrq)->data, sizeof(id_reg));
|
||||
card->id.match_flags = MEMSTICK_MATCH_ALL;
|
||||
card->id.type = id_reg.type;
|
||||
card->id.category = id_reg.category;
|
||||
card->id.class = id_reg.class;
|
||||
dev_dbg(&card->dev, "if_mode = %02x\n", id_reg.if_mode);
|
||||
}
|
||||
complete(&card->mrq_complete);
|
||||
return -EAGAIN;
|
||||
}
|
||||
if (!(*mrq)->error) {
|
||||
memcpy(&id_reg, (*mrq)->data, sizeof(id_reg));
|
||||
card->id.match_flags = MEMSTICK_MATCH_ALL;
|
||||
card->id.type = id_reg.type;
|
||||
card->id.category = id_reg.category;
|
||||
card->id.class = id_reg.class;
|
||||
dev_dbg(&card->dev, "if_mode = %02x\n", id_reg.if_mode);
|
||||
}
|
||||
complete(&card->mrq_complete);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
static int h_memstick_set_rw_addr(struct memstick_dev *card,
|
||||
|
@ -1382,7 +1382,8 @@ static int mspro_block_resume(struct memstick_dev *card)
|
||||
|
||||
new_msb->card = card;
|
||||
memstick_set_drvdata(card, new_msb);
|
||||
if (mspro_block_init_card(card))
|
||||
rc = mspro_block_init_card(card);
|
||||
if (rc)
|
||||
goto out_free;
|
||||
|
||||
for (cnt = 0; new_msb->attr_group.attrs[cnt]
|
||||
|
@ -359,13 +359,15 @@ static void r592_write_fifo_pio(struct r592_device *dev,
|
||||
/* Flushes the temporary FIFO used to make aligned DWORD writes */
|
||||
static void r592_flush_fifo_write(struct r592_device *dev)
|
||||
{
|
||||
int ret;
|
||||
u8 buffer[4] = { 0 };
|
||||
int len;
|
||||
|
||||
if (kfifo_is_empty(&dev->pio_fifo))
|
||||
return;
|
||||
|
||||
len = kfifo_out(&dev->pio_fifo, buffer, 4);
|
||||
ret = kfifo_out(&dev->pio_fifo, buffer, 4);
|
||||
/* intentionally ignore __must_check return code */
|
||||
(void)ret;
|
||||
r592_write_reg_raw_be(dev, R592_FIFO_PIO, *(u32 *)buffer);
|
||||
}
|
||||
|
||||
|
@ -539,7 +539,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
|
||||
|
||||
if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_SANITIZE_START) &&
|
||||
(cmd.opcode == MMC_SWITCH))
|
||||
return mmc_sanitize(card);
|
||||
return mmc_sanitize(card, idata->ic.cmd_timeout_ms);
|
||||
|
||||
mmc_wait_for_req(card->host, &mrq);
|
||||
|
||||
@ -572,6 +572,18 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
|
||||
main_md->part_curr = value & EXT_CSD_PART_CONFIG_ACC_MASK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure to update CACHE_CTRL in case it was changed. The cache
|
||||
* will get turned back on if the card is re-initialized, e.g.
|
||||
* suspend/resume or hw reset in recovery.
|
||||
*/
|
||||
if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_CACHE_CTRL) &&
|
||||
(cmd.opcode == MMC_SWITCH)) {
|
||||
u8 value = MMC_EXTRACT_VALUE_FROM_ARG(cmd.arg) & 1;
|
||||
|
||||
card->ext_csd.cache_ctrl = value;
|
||||
}
|
||||
|
||||
/*
|
||||
* According to the SD specs, some commands require a delay after
|
||||
* issuing the command.
|
||||
@ -947,7 +959,7 @@ static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host,
|
||||
md->reset_done |= type;
|
||||
err = mmc_hw_reset(host);
|
||||
/* Ensure we switch back to the correct partition */
|
||||
if (err != -EOPNOTSUPP) {
|
||||
if (err) {
|
||||
struct mmc_blk_data *main_md =
|
||||
dev_get_drvdata(&host->card->dev);
|
||||
int part_err;
|
||||
@ -1933,8 +1945,9 @@ static void mmc_blk_hsq_req_done(struct mmc_request *mrq)
|
||||
void mmc_blk_mq_complete(struct request *req)
|
||||
{
|
||||
struct mmc_queue *mq = req->q->queuedata;
|
||||
struct mmc_host *host = mq->card->host;
|
||||
|
||||
if (mq->use_cqe)
|
||||
if (host->cqe_enabled)
|
||||
mmc_blk_cqe_complete_rq(mq, req);
|
||||
else if (likely(!blk_should_fake_timeout(req->q)))
|
||||
mmc_blk_mq_complete_rq(mq, req);
|
||||
@ -2179,7 +2192,7 @@ out_post_req:
|
||||
|
||||
static int mmc_blk_wait_for_idle(struct mmc_queue *mq, struct mmc_host *host)
|
||||
{
|
||||
if (mq->use_cqe)
|
||||
if (host->cqe_enabled)
|
||||
return host->cqe_ops->cqe_wait_for_idle(host);
|
||||
|
||||
return mmc_blk_rw_wait(mq, NULL);
|
||||
@ -2224,11 +2237,15 @@ enum mmc_issued mmc_blk_mq_issue_rq(struct mmc_queue *mq, struct request *req)
|
||||
case MMC_ISSUE_ASYNC:
|
||||
switch (req_op(req)) {
|
||||
case REQ_OP_FLUSH:
|
||||
if (!mmc_cache_enabled(host)) {
|
||||
blk_mq_end_request(req, BLK_STS_OK);
|
||||
return MMC_REQ_FINISHED;
|
||||
}
|
||||
ret = mmc_blk_cqe_issue_flush(mq, req);
|
||||
break;
|
||||
case REQ_OP_READ:
|
||||
case REQ_OP_WRITE:
|
||||
if (mq->use_cqe)
|
||||
if (host->cqe_enabled)
|
||||
ret = mmc_blk_cqe_issue_rw_rq(mq, req);
|
||||
else
|
||||
ret = mmc_blk_mq_issue_rw_rq(mq, req);
|
||||
@ -2261,6 +2278,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
|
||||
{
|
||||
struct mmc_blk_data *md;
|
||||
int devidx, ret;
|
||||
char cap_str[10];
|
||||
|
||||
devidx = ida_simple_get(&mmc_blk_ida, 0, max_devices, GFP_KERNEL);
|
||||
if (devidx < 0) {
|
||||
@ -2365,6 +2383,12 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
|
||||
blk_queue_write_cache(md->queue.queue, true, true);
|
||||
}
|
||||
|
||||
string_get_size((u64)size, 512, STRING_UNITS_2,
|
||||
cap_str, sizeof(cap_str));
|
||||
pr_info("%s: %s %s %s %s\n",
|
||||
md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
|
||||
cap_str, md->read_only ? "(ro)" : "");
|
||||
|
||||
return md;
|
||||
|
||||
err_putdisk:
|
||||
@ -2407,7 +2431,6 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
|
||||
const char *subname,
|
||||
int area_type)
|
||||
{
|
||||
char cap_str[10];
|
||||
struct mmc_blk_data *part_md;
|
||||
|
||||
part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro,
|
||||
@ -2417,11 +2440,6 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
|
||||
part_md->part_type = part_type;
|
||||
list_add(&part_md->part, &md->part);
|
||||
|
||||
string_get_size((u64)get_capacity(part_md->disk), 512, STRING_UNITS_2,
|
||||
cap_str, sizeof(cap_str));
|
||||
pr_info("%s: %s %s partition %u %s\n",
|
||||
part_md->disk->disk_name, mmc_card_id(card),
|
||||
mmc_card_name(card), part_md->part_type, cap_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2558,9 +2576,8 @@ static int mmc_blk_alloc_rpmb_part(struct mmc_card *card,
|
||||
string_get_size((u64)size, 512, STRING_UNITS_2,
|
||||
cap_str, sizeof(cap_str));
|
||||
|
||||
pr_info("%s: %s %s partition %u %s, chardev (%d:%d)\n",
|
||||
rpmb_name, mmc_card_id(card),
|
||||
mmc_card_name(card), EXT_CSD_PART_CONFIG_ACC_RPMB, cap_str,
|
||||
pr_info("%s: %s %s %s, chardev (%d:%d)\n",
|
||||
rpmb_name, mmc_card_id(card), mmc_card_name(card), cap_str,
|
||||
MAJOR(mmc_rpmb_devt), rpmb->id);
|
||||
|
||||
return 0;
|
||||
@ -2876,7 +2893,7 @@ static void mmc_blk_remove_debugfs(struct mmc_card *card,
|
||||
static int mmc_blk_probe(struct mmc_card *card)
|
||||
{
|
||||
struct mmc_blk_data *md, *part_md;
|
||||
char cap_str[10];
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* Check that the card supports the command class(es) we need.
|
||||
@ -2888,31 +2905,30 @@ static int mmc_blk_probe(struct mmc_card *card)
|
||||
|
||||
card->complete_wq = alloc_workqueue("mmc_complete",
|
||||
WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
|
||||
if (unlikely(!card->complete_wq)) {
|
||||
if (!card->complete_wq) {
|
||||
pr_err("Failed to create mmc completion workqueue");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
md = mmc_blk_alloc(card);
|
||||
if (IS_ERR(md))
|
||||
return PTR_ERR(md);
|
||||
if (IS_ERR(md)) {
|
||||
ret = PTR_ERR(md);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
string_get_size((u64)get_capacity(md->disk), 512, STRING_UNITS_2,
|
||||
cap_str, sizeof(cap_str));
|
||||
pr_info("%s: %s %s %s %s\n",
|
||||
md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
|
||||
cap_str, md->read_only ? "(ro)" : "");
|
||||
|
||||
if (mmc_blk_alloc_parts(card, md))
|
||||
ret = mmc_blk_alloc_parts(card, md);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
dev_set_drvdata(&card->dev, md);
|
||||
|
||||
if (mmc_add_disk(md))
|
||||
ret = mmc_add_disk(md);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
list_for_each_entry(part_md, &md->part, part) {
|
||||
if (mmc_add_disk(part_md))
|
||||
ret = mmc_add_disk(part_md);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -2933,10 +2949,12 @@ static int mmc_blk_probe(struct mmc_card *card)
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
out:
|
||||
mmc_blk_remove_parts(card, md);
|
||||
mmc_blk_remove_req(md);
|
||||
return 0;
|
||||
out_free:
|
||||
destroy_workqueue(card->complete_wq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mmc_blk_remove(struct mmc_card *card)
|
||||
|
@ -1207,7 +1207,7 @@ int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr)
|
||||
|
||||
err = mmc_wait_for_cmd(host, &cmd, 0);
|
||||
if (err)
|
||||
return err;
|
||||
goto power_cycle;
|
||||
|
||||
if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
|
||||
return -EIO;
|
||||
@ -1377,63 +1377,13 @@ void mmc_power_cycle(struct mmc_host *host, u32 ocr)
|
||||
mmc_power_up(host, ocr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup when the last reference to the bus operator is dropped.
|
||||
*/
|
||||
static void __mmc_release_bus(struct mmc_host *host)
|
||||
{
|
||||
WARN_ON(!host->bus_dead);
|
||||
|
||||
host->bus_ops = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Increase reference count of bus operator
|
||||
*/
|
||||
static inline void mmc_bus_get(struct mmc_host *host)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
host->bus_refs++;
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrease reference count of bus operator and free it if
|
||||
* it is the last reference.
|
||||
*/
|
||||
static inline void mmc_bus_put(struct mmc_host *host)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
host->bus_refs--;
|
||||
if ((host->bus_refs == 0) && host->bus_ops)
|
||||
__mmc_release_bus(host);
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Assign a mmc bus handler to a host. Only one bus handler may control a
|
||||
* host at any given time.
|
||||
*/
|
||||
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
WARN_ON(!host->claimed);
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
|
||||
WARN_ON(host->bus_ops);
|
||||
WARN_ON(host->bus_refs);
|
||||
|
||||
host->bus_ops = ops;
|
||||
host->bus_refs = 1;
|
||||
host->bus_dead = 0;
|
||||
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1441,18 +1391,7 @@ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
|
||||
*/
|
||||
void mmc_detach_bus(struct mmc_host *host)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
WARN_ON(!host->claimed);
|
||||
WARN_ON(!host->bus_ops);
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
|
||||
host->bus_dead = 1;
|
||||
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
|
||||
mmc_bus_put(host);
|
||||
host->bus_ops = NULL;
|
||||
}
|
||||
|
||||
void _mmc_detect_change(struct mmc_host *host, unsigned long delay, bool cd_irq)
|
||||
@ -2080,18 +2019,7 @@ int mmc_hw_reset(struct mmc_host *host)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!host->card)
|
||||
return -EINVAL;
|
||||
|
||||
mmc_bus_get(host);
|
||||
if (!host->bus_ops || host->bus_dead || !host->bus_ops->hw_reset) {
|
||||
mmc_bus_put(host);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ret = host->bus_ops->hw_reset(host);
|
||||
mmc_bus_put(host);
|
||||
|
||||
if (ret < 0)
|
||||
pr_warn("%s: tried to HW reset card, got error %d\n",
|
||||
mmc_hostname(host), ret);
|
||||
@ -2104,18 +2032,10 @@ int mmc_sw_reset(struct mmc_host *host)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!host->card)
|
||||
return -EINVAL;
|
||||
|
||||
mmc_bus_get(host);
|
||||
if (!host->bus_ops || host->bus_dead || !host->bus_ops->sw_reset) {
|
||||
mmc_bus_put(host);
|
||||
if (!host->bus_ops->sw_reset)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ret = host->bus_ops->sw_reset(host);
|
||||
mmc_bus_put(host);
|
||||
|
||||
if (ret)
|
||||
pr_warn("%s: tried to SW reset card, got error %d\n",
|
||||
mmc_hostname(host), ret);
|
||||
@ -2263,32 +2183,15 @@ void mmc_rescan(struct work_struct *work)
|
||||
host->trigger_card_event = false;
|
||||
}
|
||||
|
||||
mmc_bus_get(host);
|
||||
|
||||
/* Verify a registered card to be functional, else remove it. */
|
||||
if (host->bus_ops && !host->bus_dead)
|
||||
if (host->bus_ops)
|
||||
host->bus_ops->detect(host);
|
||||
|
||||
host->detect_change = 0;
|
||||
|
||||
/*
|
||||
* Let mmc_bus_put() free the bus/bus_ops if we've found that
|
||||
* the card is no longer present.
|
||||
*/
|
||||
mmc_bus_put(host);
|
||||
mmc_bus_get(host);
|
||||
|
||||
/* if there still is a card present, stop here */
|
||||
if (host->bus_ops != NULL) {
|
||||
mmc_bus_put(host);
|
||||
if (host->bus_ops != NULL)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only we can add a new handler, so it's safe to
|
||||
* release the lock here.
|
||||
*/
|
||||
mmc_bus_put(host);
|
||||
|
||||
mmc_claim_host(host);
|
||||
if (mmc_card_is_removable(host) && host->ops->get_cd &&
|
||||
@ -2351,98 +2254,21 @@ void mmc_stop_host(struct mmc_host *host)
|
||||
/* clear pm flags now and let card drivers set them as needed */
|
||||
host->pm_flags = 0;
|
||||
|
||||
mmc_bus_get(host);
|
||||
if (host->bus_ops && !host->bus_dead) {
|
||||
if (host->bus_ops) {
|
||||
/* Calling bus_ops->remove() with a claimed host can deadlock */
|
||||
host->bus_ops->remove(host);
|
||||
mmc_claim_host(host);
|
||||
mmc_detach_bus(host);
|
||||
mmc_power_off(host);
|
||||
mmc_release_host(host);
|
||||
mmc_bus_put(host);
|
||||
return;
|
||||
}
|
||||
mmc_bus_put(host);
|
||||
|
||||
mmc_claim_host(host);
|
||||
mmc_power_off(host);
|
||||
mmc_release_host(host);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/* Do the card removal on suspend if card is assumed removeable
|
||||
* Do that in pm notifier while userspace isn't yet frozen, so we will be able
|
||||
to sync the card.
|
||||
*/
|
||||
static int mmc_pm_notify(struct notifier_block *notify_block,
|
||||
unsigned long mode, void *unused)
|
||||
{
|
||||
struct mmc_host *host = container_of(
|
||||
notify_block, struct mmc_host, pm_notify);
|
||||
unsigned long flags;
|
||||
int err = 0;
|
||||
|
||||
switch (mode) {
|
||||
case PM_HIBERNATION_PREPARE:
|
||||
case PM_SUSPEND_PREPARE:
|
||||
case PM_RESTORE_PREPARE:
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
host->rescan_disable = 1;
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
cancel_delayed_work_sync(&host->detect);
|
||||
|
||||
if (!host->bus_ops)
|
||||
break;
|
||||
|
||||
/* Validate prerequisites for suspend */
|
||||
if (host->bus_ops->pre_suspend)
|
||||
err = host->bus_ops->pre_suspend(host);
|
||||
if (!err)
|
||||
break;
|
||||
|
||||
if (!mmc_card_is_removable(host)) {
|
||||
dev_warn(mmc_dev(host),
|
||||
"pre_suspend failed for non-removable host: "
|
||||
"%d\n", err);
|
||||
/* Avoid removing non-removable hosts */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Calling bus_ops->remove() with a claimed host can deadlock */
|
||||
host->bus_ops->remove(host);
|
||||
mmc_claim_host(host);
|
||||
mmc_detach_bus(host);
|
||||
mmc_power_off(host);
|
||||
mmc_release_host(host);
|
||||
host->pm_flags = 0;
|
||||
break;
|
||||
|
||||
case PM_POST_SUSPEND:
|
||||
case PM_POST_HIBERNATION:
|
||||
case PM_POST_RESTORE:
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
host->rescan_disable = 0;
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
_mmc_detect_change(host, 0, false);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mmc_register_pm_notifier(struct mmc_host *host)
|
||||
{
|
||||
host->pm_notify.notifier_call = mmc_pm_notify;
|
||||
register_pm_notifier(&host->pm_notify);
|
||||
}
|
||||
|
||||
void mmc_unregister_pm_notifier(struct mmc_host *host)
|
||||
{
|
||||
unregister_pm_notifier(&host->pm_notify);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init mmc_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
@ -29,6 +29,7 @@ struct mmc_bus_ops {
|
||||
int (*shutdown)(struct mmc_host *);
|
||||
int (*hw_reset)(struct mmc_host *);
|
||||
int (*sw_reset)(struct mmc_host *);
|
||||
bool (*cache_enabled)(struct mmc_host *);
|
||||
};
|
||||
|
||||
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
|
||||
@ -93,14 +94,6 @@ int mmc_execute_tuning(struct mmc_card *card);
|
||||
int mmc_hs200_to_hs400(struct mmc_card *card);
|
||||
int mmc_hs400_to_hs200(struct mmc_card *card);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
void mmc_register_pm_notifier(struct mmc_host *host);
|
||||
void mmc_unregister_pm_notifier(struct mmc_host *host);
|
||||
#else
|
||||
static inline void mmc_register_pm_notifier(struct mmc_host *host) { }
|
||||
static inline void mmc_unregister_pm_notifier(struct mmc_host *host) { }
|
||||
#endif
|
||||
|
||||
void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq);
|
||||
bool mmc_is_req_done(struct mmc_host *host, struct mmc_request *mrq);
|
||||
|
||||
@ -171,4 +164,12 @@ static inline void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
|
||||
host->ops->post_req(host, mrq, err);
|
||||
}
|
||||
|
||||
static inline bool mmc_cache_enabled(struct mmc_host *host)
|
||||
{
|
||||
if (host->bus_ops->cache_enabled)
|
||||
return host->bus_ops->cache_enabled(host);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -35,6 +35,42 @@
|
||||
|
||||
static DEFINE_IDA(mmc_host_ida);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int mmc_host_class_prepare(struct device *dev)
|
||||
{
|
||||
struct mmc_host *host = cls_dev_to_mmc_host(dev);
|
||||
|
||||
/*
|
||||
* It's safe to access the bus_ops pointer, as both userspace and the
|
||||
* workqueue for detecting cards are frozen at this point.
|
||||
*/
|
||||
if (!host->bus_ops)
|
||||
return 0;
|
||||
|
||||
/* Validate conditions for system suspend. */
|
||||
if (host->bus_ops->pre_suspend)
|
||||
return host->bus_ops->pre_suspend(host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mmc_host_class_complete(struct device *dev)
|
||||
{
|
||||
struct mmc_host *host = cls_dev_to_mmc_host(dev);
|
||||
|
||||
_mmc_detect_change(host, 0, false);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops mmc_host_class_dev_pm_ops = {
|
||||
.prepare = mmc_host_class_prepare,
|
||||
.complete = mmc_host_class_complete,
|
||||
};
|
||||
|
||||
#define MMC_HOST_CLASS_DEV_PM_OPS (&mmc_host_class_dev_pm_ops)
|
||||
#else
|
||||
#define MMC_HOST_CLASS_DEV_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static void mmc_host_classdev_release(struct device *dev)
|
||||
{
|
||||
struct mmc_host *host = cls_dev_to_mmc_host(dev);
|
||||
@ -46,6 +82,7 @@ static void mmc_host_classdev_release(struct device *dev)
|
||||
static struct class mmc_host_class = {
|
||||
.name = "mmc_host",
|
||||
.dev_release = mmc_host_classdev_release,
|
||||
.pm = MMC_HOST_CLASS_DEV_PM_OPS,
|
||||
};
|
||||
|
||||
int mmc_register_host_class(void)
|
||||
@ -209,8 +246,8 @@ mmc_of_parse_clk_phase(struct mmc_host *host, struct mmc_clk_phase_map *map)
|
||||
EXPORT_SYMBOL(mmc_of_parse_clk_phase);
|
||||
|
||||
/**
|
||||
* mmc_of_parse() - parse host's device-tree node
|
||||
* @host: host whose node should be parsed.
|
||||
* mmc_of_parse() - parse host's device properties
|
||||
* @host: host whose properties should be parsed.
|
||||
*
|
||||
* To keep the rest of the MMC subsystem unaware of whether DT has been
|
||||
* used to to instantiate and configure this host instance or not, we
|
||||
@ -379,44 +416,62 @@ EXPORT_SYMBOL(mmc_of_parse);
|
||||
|
||||
/**
|
||||
* mmc_of_parse_voltage - return mask of supported voltages
|
||||
* @np: The device node need to be parsed.
|
||||
* @host: host whose properties should be parsed.
|
||||
* @mask: mask of voltages available for MMC/SD/SDIO
|
||||
*
|
||||
* Parse the "voltage-ranges" DT property, returning zero if it is not
|
||||
* Parse the "voltage-ranges" property, returning zero if it is not
|
||||
* found, negative errno if the voltage-range specification is invalid,
|
||||
* or one if the voltage-range is specified and successfully parsed.
|
||||
*/
|
||||
int mmc_of_parse_voltage(struct device_node *np, u32 *mask)
|
||||
int mmc_of_parse_voltage(struct mmc_host *host, u32 *mask)
|
||||
{
|
||||
const u32 *voltage_ranges;
|
||||
const char *prop = "voltage-ranges";
|
||||
struct device *dev = host->parent;
|
||||
u32 *voltage_ranges;
|
||||
int num_ranges, i;
|
||||
int ret;
|
||||
|
||||
voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges);
|
||||
if (!voltage_ranges) {
|
||||
pr_debug("%pOF: voltage-ranges unspecified\n", np);
|
||||
if (!device_property_present(dev, prop)) {
|
||||
dev_dbg(dev, "%s unspecified\n", prop);
|
||||
return 0;
|
||||
}
|
||||
num_ranges = num_ranges / sizeof(*voltage_ranges) / 2;
|
||||
|
||||
ret = device_property_count_u32(dev, prop);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
num_ranges = ret / 2;
|
||||
if (!num_ranges) {
|
||||
pr_err("%pOF: voltage-ranges empty\n", np);
|
||||
dev_err(dev, "%s empty\n", prop);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
voltage_ranges = kcalloc(2 * num_ranges, sizeof(*voltage_ranges), GFP_KERNEL);
|
||||
if (!voltage_ranges)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = device_property_read_u32_array(dev, prop, voltage_ranges, 2 * num_ranges);
|
||||
if (ret) {
|
||||
kfree(voltage_ranges);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_ranges; i++) {
|
||||
const int j = i * 2;
|
||||
u32 ocr_mask;
|
||||
|
||||
ocr_mask = mmc_vddrange_to_ocrmask(
|
||||
be32_to_cpu(voltage_ranges[j]),
|
||||
be32_to_cpu(voltage_ranges[j + 1]));
|
||||
ocr_mask = mmc_vddrange_to_ocrmask(voltage_ranges[j + 0],
|
||||
voltage_ranges[j + 1]);
|
||||
if (!ocr_mask) {
|
||||
pr_err("%pOF: voltage-range #%d is invalid\n",
|
||||
np, i);
|
||||
dev_err(dev, "range #%d in %s is invalid\n", i, prop);
|
||||
kfree(voltage_ranges);
|
||||
return -EINVAL;
|
||||
}
|
||||
*mask |= ocr_mask;
|
||||
}
|
||||
|
||||
kfree(voltage_ranges);
|
||||
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_of_parse_voltage);
|
||||
@ -538,8 +593,6 @@ int mmc_add_host(struct mmc_host *host)
|
||||
#endif
|
||||
|
||||
mmc_start_host(host);
|
||||
mmc_register_pm_notifier(host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -555,7 +608,6 @@ EXPORT_SYMBOL(mmc_add_host);
|
||||
*/
|
||||
void mmc_remove_host(struct mmc_host *host)
|
||||
{
|
||||
mmc_unregister_pm_notifier(host);
|
||||
mmc_stop_host(host);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
@ -1068,7 +1068,7 @@ static int mmc_select_hs(struct mmc_card *card)
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
|
||||
card->ext_csd.generic_cmd6_time, MMC_TIMING_MMC_HS,
|
||||
true, true);
|
||||
true, true, MMC_CMD_RETRIES);
|
||||
if (err)
|
||||
pr_warn("%s: switch to high-speed failed, err:%d\n",
|
||||
mmc_hostname(card->host), err);
|
||||
@ -1100,7 +1100,7 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
|
||||
ext_csd_bits,
|
||||
card->ext_csd.generic_cmd6_time,
|
||||
MMC_TIMING_MMC_DDR52,
|
||||
true, true);
|
||||
true, true, MMC_CMD_RETRIES);
|
||||
if (err) {
|
||||
pr_err("%s: switch to bus width %d ddr failed\n",
|
||||
mmc_hostname(host), 1 << bus_width);
|
||||
@ -1168,7 +1168,7 @@ static int mmc_select_hs400(struct mmc_card *card)
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_HS_TIMING, val,
|
||||
card->ext_csd.generic_cmd6_time, 0,
|
||||
false, true);
|
||||
false, true, MMC_CMD_RETRIES);
|
||||
if (err) {
|
||||
pr_err("%s: switch to high-speed from hs200 failed, err:%d\n",
|
||||
mmc_hostname(host), err);
|
||||
@ -1210,7 +1210,7 @@ static int mmc_select_hs400(struct mmc_card *card)
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_HS_TIMING, val,
|
||||
card->ext_csd.generic_cmd6_time, 0,
|
||||
false, true);
|
||||
false, true, MMC_CMD_RETRIES);
|
||||
if (err) {
|
||||
pr_err("%s: switch to hs400 failed, err:%d\n",
|
||||
mmc_hostname(host), err);
|
||||
@ -1256,7 +1256,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
|
||||
val = EXT_CSD_TIMING_HS;
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
|
||||
val, card->ext_csd.generic_cmd6_time, 0,
|
||||
false, true);
|
||||
false, true, MMC_CMD_RETRIES);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
@ -1272,7 +1272,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
|
||||
/* Switch HS DDR to HS */
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH,
|
||||
EXT_CSD_BUS_WIDTH_8, card->ext_csd.generic_cmd6_time,
|
||||
0, false, true);
|
||||
0, false, true, MMC_CMD_RETRIES);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
@ -1287,7 +1287,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
|
||||
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
|
||||
val, card->ext_csd.generic_cmd6_time, 0,
|
||||
false, true);
|
||||
false, true, MMC_CMD_RETRIES);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
@ -1371,7 +1371,7 @@ static int mmc_select_hs400es(struct mmc_card *card)
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
|
||||
card->ext_csd.generic_cmd6_time, 0,
|
||||
false, true);
|
||||
false, true, MMC_CMD_RETRIES);
|
||||
if (err) {
|
||||
pr_err("%s: switch to hs for hs400es failed, err:%d\n",
|
||||
mmc_hostname(host), err);
|
||||
@ -1405,7 +1405,7 @@ static int mmc_select_hs400es(struct mmc_card *card)
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_HS_TIMING, val,
|
||||
card->ext_csd.generic_cmd6_time, 0,
|
||||
false, true);
|
||||
false, true, MMC_CMD_RETRIES);
|
||||
if (err) {
|
||||
pr_err("%s: switch to hs400es failed, err:%d\n",
|
||||
mmc_hostname(host), err);
|
||||
@ -1470,7 +1470,7 @@ static int mmc_select_hs200(struct mmc_card *card)
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_HS_TIMING, val,
|
||||
card->ext_csd.generic_cmd6_time, 0,
|
||||
false, true);
|
||||
false, true, MMC_CMD_RETRIES);
|
||||
if (err)
|
||||
goto err;
|
||||
old_timing = host->ios.timing;
|
||||
@ -1975,7 +1975,7 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type)
|
||||
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_POWER_OFF_NOTIFICATION,
|
||||
notify_type, timeout, 0, false, false);
|
||||
notify_type, timeout, 0, false, false, MMC_CMD_RETRIES);
|
||||
if (err)
|
||||
pr_err("%s: Power Off Notification timed out, %u\n",
|
||||
mmc_hostname(card->host), timeout);
|
||||
@ -2029,6 +2029,12 @@ static void mmc_detect(struct mmc_host *host)
|
||||
}
|
||||
}
|
||||
|
||||
static bool _mmc_cache_enabled(struct mmc_host *host)
|
||||
{
|
||||
return host->card->ext_csd.cache_size > 0 &&
|
||||
host->card->ext_csd.cache_ctrl & 1;
|
||||
}
|
||||
|
||||
static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
|
||||
{
|
||||
int err = 0;
|
||||
@ -2208,6 +2214,7 @@ static const struct mmc_bus_ops mmc_ops = {
|
||||
.alive = mmc_alive,
|
||||
.shutdown = mmc_shutdown,
|
||||
.hw_reset = _mmc_hw_reset,
|
||||
.cache_enabled = _mmc_cache_enabled,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -296,61 +296,40 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmc_spi_send_csd(struct mmc_host *host, u32 *csd)
|
||||
static int mmc_spi_send_cxd(struct mmc_host *host, u32 *cxd, u32 opcode)
|
||||
{
|
||||
int ret, i;
|
||||
__be32 *csd_tmp;
|
||||
__be32 *cxd_tmp;
|
||||
|
||||
csd_tmp = kzalloc(16, GFP_KERNEL);
|
||||
if (!csd_tmp)
|
||||
cxd_tmp = kzalloc(16, GFP_KERNEL);
|
||||
if (!cxd_tmp)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = mmc_send_cxd_data(NULL, host, MMC_SEND_CSD, csd_tmp, 16);
|
||||
ret = mmc_send_cxd_data(NULL, host, opcode, cxd_tmp, 16);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
csd[i] = be32_to_cpu(csd_tmp[i]);
|
||||
cxd[i] = be32_to_cpu(cxd_tmp[i]);
|
||||
|
||||
err:
|
||||
kfree(csd_tmp);
|
||||
kfree(cxd_tmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mmc_send_csd(struct mmc_card *card, u32 *csd)
|
||||
{
|
||||
if (mmc_host_is_spi(card->host))
|
||||
return mmc_spi_send_csd(card->host, csd);
|
||||
return mmc_spi_send_cxd(card->host, csd, MMC_SEND_CSD);
|
||||
|
||||
return mmc_send_cxd_native(card->host, card->rca << 16, csd,
|
||||
MMC_SEND_CSD);
|
||||
}
|
||||
|
||||
static int mmc_spi_send_cid(struct mmc_host *host, u32 *cid)
|
||||
{
|
||||
int ret, i;
|
||||
__be32 *cid_tmp;
|
||||
|
||||
cid_tmp = kzalloc(16, GFP_KERNEL);
|
||||
if (!cid_tmp)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = mmc_send_cxd_data(NULL, host, MMC_SEND_CID, cid_tmp, 16);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
cid[i] = be32_to_cpu(cid_tmp[i]);
|
||||
|
||||
err:
|
||||
kfree(cid_tmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mmc_send_cid(struct mmc_host *host, u32 *cid)
|
||||
{
|
||||
if (mmc_host_is_spi(host))
|
||||
return mmc_spi_send_cid(host, cid);
|
||||
return mmc_spi_send_cxd(host, cid, MMC_SEND_CID);
|
||||
|
||||
return mmc_send_cxd_native(host, 0, cid, MMC_ALL_SEND_CID);
|
||||
}
|
||||
@ -553,12 +532,13 @@ int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
|
||||
* @timing: new timing to change to
|
||||
* @send_status: send status cmd to poll for busy
|
||||
* @retry_crc_err: retry when CRC errors when polling with CMD13 for busy
|
||||
* @retries: number of retries
|
||||
*
|
||||
* Modifies the EXT_CSD register for selected card.
|
||||
*/
|
||||
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
|
||||
unsigned int timeout_ms, unsigned char timing,
|
||||
bool send_status, bool retry_crc_err)
|
||||
bool send_status, bool retry_crc_err, unsigned int retries)
|
||||
{
|
||||
struct mmc_host *host = card->host;
|
||||
int err;
|
||||
@ -598,7 +578,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
|
||||
cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;
|
||||
}
|
||||
|
||||
err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
|
||||
err = mmc_wait_for_cmd(host, &cmd, retries);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -633,7 +613,7 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
|
||||
unsigned int timeout_ms)
|
||||
{
|
||||
return __mmc_switch(card, set, index, value, timeout_ms, 0,
|
||||
true, false);
|
||||
true, false, MMC_CMD_RETRIES);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mmc_switch);
|
||||
|
||||
@ -988,9 +968,7 @@ int mmc_flush_cache(struct mmc_card *card)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (mmc_card_mmc(card) &&
|
||||
(card->ext_csd.cache_size > 0) &&
|
||||
(card->ext_csd.cache_ctrl & 1)) {
|
||||
if (mmc_cache_enabled(card->host)) {
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_FLUSH_CACHE, 1,
|
||||
MMC_CACHE_FLUSH_TIMEOUT_MS);
|
||||
@ -1031,7 +1009,7 @@ int mmc_cmdq_disable(struct mmc_card *card)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mmc_cmdq_disable);
|
||||
|
||||
int mmc_sanitize(struct mmc_card *card)
|
||||
int mmc_sanitize(struct mmc_card *card, unsigned int timeout_ms)
|
||||
{
|
||||
struct mmc_host *host = card->host;
|
||||
int err;
|
||||
@ -1041,12 +1019,15 @@ int mmc_sanitize(struct mmc_card *card)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (!timeout_ms)
|
||||
timeout_ms = MMC_SANITIZE_TIMEOUT_MS;
|
||||
|
||||
pr_debug("%s: Sanitize in progress...\n", mmc_hostname(host));
|
||||
|
||||
mmc_retune_hold(host);
|
||||
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_SANITIZE_START,
|
||||
1, MMC_SANITIZE_TIMEOUT_MS);
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_SANITIZE_START,
|
||||
1, timeout_ms, 0, true, false, 0);
|
||||
if (err)
|
||||
pr_err("%s: Sanitize failed err=%d\n", mmc_hostname(host), err);
|
||||
|
||||
|
@ -39,14 +39,14 @@ int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
|
||||
enum mmc_busy_cmd busy_cmd);
|
||||
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
|
||||
unsigned int timeout_ms, unsigned char timing,
|
||||
bool send_status, bool retry_crc_err);
|
||||
bool send_status, bool retry_crc_err, unsigned int retries);
|
||||
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
|
||||
unsigned int timeout_ms);
|
||||
void mmc_run_bkops(struct mmc_card *card);
|
||||
int mmc_flush_cache(struct mmc_card *card);
|
||||
int mmc_cmdq_enable(struct mmc_card *card);
|
||||
int mmc_cmdq_disable(struct mmc_card *card);
|
||||
int mmc_sanitize(struct mmc_card *card);
|
||||
int mmc_sanitize(struct mmc_card *card, unsigned int timeout_ms);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -60,7 +60,7 @@ enum mmc_issue_type mmc_issue_type(struct mmc_queue *mq, struct request *req)
|
||||
{
|
||||
struct mmc_host *host = mq->card->host;
|
||||
|
||||
if (mq->use_cqe && !host->hsq_enabled)
|
||||
if (host->cqe_enabled && !host->hsq_enabled)
|
||||
return mmc_cqe_issue_type(host, req);
|
||||
|
||||
if (req_op(req) == REQ_OP_READ || req_op(req) == REQ_OP_WRITE)
|
||||
@ -127,7 +127,7 @@ static enum blk_eh_timer_return mmc_mq_timed_out(struct request *req,
|
||||
bool ignore_tout;
|
||||
|
||||
spin_lock_irqsave(&mq->lock, flags);
|
||||
ignore_tout = mq->recovery_needed || !mq->use_cqe || host->hsq_enabled;
|
||||
ignore_tout = mq->recovery_needed || !host->cqe_enabled || host->hsq_enabled;
|
||||
spin_unlock_irqrestore(&mq->lock, flags);
|
||||
|
||||
return ignore_tout ? BLK_EH_RESET_TIMER : mmc_cqe_timed_out(req);
|
||||
@ -144,7 +144,7 @@ static void mmc_mq_recovery_handler(struct work_struct *work)
|
||||
|
||||
mq->in_recovery = true;
|
||||
|
||||
if (mq->use_cqe && !host->hsq_enabled)
|
||||
if (host->cqe_enabled && !host->hsq_enabled)
|
||||
mmc_blk_cqe_recovery(mq);
|
||||
else
|
||||
mmc_blk_mq_recovery(mq);
|
||||
@ -315,7 +315,7 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx,
|
||||
if (get_card)
|
||||
mmc_get_card(card, &mq->ctx);
|
||||
|
||||
if (mq->use_cqe) {
|
||||
if (host->cqe_enabled) {
|
||||
host->retune_now = host->need_retune && cqe_retune_ok &&
|
||||
!host->hold_retune;
|
||||
}
|
||||
@ -430,7 +430,6 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card)
|
||||
int ret;
|
||||
|
||||
mq->card = card;
|
||||
mq->use_cqe = host->cqe_enabled;
|
||||
|
||||
spin_lock_init(&mq->lock);
|
||||
|
||||
@ -440,7 +439,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card)
|
||||
* The queue depth for CQE must match the hardware because the request
|
||||
* tag is used to index the hardware queue.
|
||||
*/
|
||||
if (mq->use_cqe && !host->hsq_enabled)
|
||||
if (host->cqe_enabled && !host->hsq_enabled)
|
||||
mq->tag_set.queue_depth =
|
||||
min_t(int, card->ext_csd.cmdq_depth, host->cqe_qdepth);
|
||||
else
|
||||
|
@ -82,7 +82,6 @@ struct mmc_queue {
|
||||
unsigned int cqe_busy;
|
||||
#define MMC_CQE_DCMD_BUSY BIT(0)
|
||||
bool busy;
|
||||
bool use_cqe;
|
||||
bool recovery_needed;
|
||||
bool in_recovery;
|
||||
bool rw_wait;
|
||||
|
@ -135,6 +135,9 @@ static int mmc_decode_csd(struct mmc_card *card)
|
||||
csd->erase_size = UNSTUFF_BITS(resp, 39, 7) + 1;
|
||||
csd->erase_size <<= csd->write_blkbits - 9;
|
||||
}
|
||||
|
||||
if (UNSTUFF_BITS(resp, 13, 1))
|
||||
mmc_card_set_readonly(card);
|
||||
break;
|
||||
case 1:
|
||||
/*
|
||||
@ -169,6 +172,9 @@ static int mmc_decode_csd(struct mmc_card *card)
|
||||
csd->write_blkbits = 9;
|
||||
csd->write_partial = 0;
|
||||
csd->erase_size = 1;
|
||||
|
||||
if (UNSTUFF_BITS(resp, 13, 1))
|
||||
mmc_card_set_readonly(card);
|
||||
break;
|
||||
default:
|
||||
pr_err("%s: unrecognised CSD structure version %d\n",
|
||||
|
@ -985,21 +985,37 @@ out:
|
||||
*/
|
||||
static int mmc_sdio_pre_suspend(struct mmc_host *host)
|
||||
{
|
||||
int i, err = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < host->card->sdio_funcs; i++) {
|
||||
struct sdio_func *func = host->card->sdio_func[i];
|
||||
if (func && sdio_func_present(func) && func->dev.driver) {
|
||||
const struct dev_pm_ops *pmops = func->dev.driver->pm;
|
||||
if (!pmops || !pmops->suspend || !pmops->resume) {
|
||||
if (!pmops || !pmops->suspend || !pmops->resume)
|
||||
/* force removal of entire card in that case */
|
||||
err = -ENOSYS;
|
||||
break;
|
||||
}
|
||||
goto remove;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
|
||||
remove:
|
||||
if (!mmc_card_is_removable(host)) {
|
||||
dev_warn(mmc_dev(host),
|
||||
"missing suspend/resume ops for non-removable SDIO card\n");
|
||||
/* Don't remove a non-removable card - we can't re-detect it. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remove the SDIO card and let it be re-detected later on. */
|
||||
mmc_sdio_remove(host);
|
||||
mmc_claim_host(host);
|
||||
mmc_detach_bus(host);
|
||||
mmc_power_off(host);
|
||||
mmc_release_host(host);
|
||||
host->pm_flags = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -278,6 +278,7 @@ config MMC_SDHCI_ESDHC_IMX
|
||||
tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX controller"
|
||||
depends on ARCH_MXC || COMPILE_TEST
|
||||
depends on MMC_SDHCI_PLTFM
|
||||
depends on OF
|
||||
select MMC_SDHCI_IO_ACCESSORS
|
||||
select MMC_CQHCI
|
||||
help
|
||||
@ -707,6 +708,7 @@ config MMC_SDHI
|
||||
tristate "Renesas SDHI SD/SDIO controller support"
|
||||
depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
|
||||
select MMC_TMIO_CORE
|
||||
select RESET_CONTROLLER if ARCH_RENESAS
|
||||
help
|
||||
This provides support for the SDHI SD/SDIO controller found in
|
||||
Renesas SuperH, ARM and ARM64 based SoCs
|
||||
|
@ -34,9 +34,7 @@ obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
|
||||
obj-$(CONFIG_MMC_MVSDIO) += mvsdio.o
|
||||
obj-$(CONFIG_MMC_DAVINCI) += davinci_mmc.o
|
||||
obj-$(CONFIG_MMC_SPI) += mmc_spi.o
|
||||
ifeq ($(CONFIG_OF),y)
|
||||
obj-$(CONFIG_MMC_SPI) += of_mmc_spi.o
|
||||
endif
|
||||
obj-$(CONFIG_MMC_S3C) += s3cmci.o
|
||||
obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o
|
||||
obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o
|
||||
|
@ -656,8 +656,7 @@ static void cvm_mmc_dma_request(struct mmc_host *mmc,
|
||||
|
||||
if (!mrq->data || !mrq->data->sg || !mrq->data->sg_len ||
|
||||
!mrq->stop || mrq->stop->opcode != MMC_STOP_TRANSMISSION) {
|
||||
dev_err(&mmc->card->dev,
|
||||
"Error: cmv_mmc_dma_request no data\n");
|
||||
dev_err(&mmc->card->dev, "Error: %s no data\n", __func__);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2013 Linaro Ltd.
|
||||
* Copyright (c) 2013 Hisilicon Limited.
|
||||
* Copyright (c) 2013 HiSilicon Limited.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
|
@ -61,7 +61,7 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
|
||||
}
|
||||
|
||||
/* Make sure we use phases which we can enumerate with */
|
||||
if (!IS_ERR(priv->sample_clk))
|
||||
if (!IS_ERR(priv->sample_clk) && ios->timing <= MMC_TIMING_SD_HS)
|
||||
clk_set_phase(priv->sample_clk, priv->default_sample_phase);
|
||||
|
||||
/*
|
||||
|
@ -2606,8 +2606,6 @@ static void dw_mci_handle_cd(struct dw_mci *host)
|
||||
{
|
||||
struct dw_mci_slot *slot = host->slot;
|
||||
|
||||
if (slot->mmc->ops->card_event)
|
||||
slot->mmc->ops->card_event(slot->mmc);
|
||||
mmc_detect_change(slot->mmc,
|
||||
msecs_to_jiffies(host->pdata->detect_delay_ms));
|
||||
}
|
||||
@ -3095,10 +3093,8 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
|
||||
|
||||
/* find reset controller when exist */
|
||||
pdata->rstc = devm_reset_control_get_optional_exclusive(dev, "reset");
|
||||
if (IS_ERR(pdata->rstc)) {
|
||||
if (PTR_ERR(pdata->rstc) == -EPROBE_DEFER)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
if (IS_ERR(pdata->rstc))
|
||||
return ERR_CAST(pdata->rstc);
|
||||
|
||||
if (device_property_read_u32(dev, "fifo-depth", &pdata->fifo_depth))
|
||||
dev_info(dev,
|
||||
@ -3204,7 +3200,7 @@ int dw_mci_probe(struct dw_mci *host)
|
||||
goto err_clk_ciu;
|
||||
}
|
||||
|
||||
if (!IS_ERR(host->pdata->rstc)) {
|
||||
if (host->pdata->rstc) {
|
||||
reset_control_assert(host->pdata->rstc);
|
||||
usleep_range(10, 50);
|
||||
reset_control_deassert(host->pdata->rstc);
|
||||
@ -3344,8 +3340,7 @@ err_dmaunmap:
|
||||
if (host->use_dma && host->dma_ops->exit)
|
||||
host->dma_ops->exit(host);
|
||||
|
||||
if (!IS_ERR(host->pdata->rstc))
|
||||
reset_control_assert(host->pdata->rstc);
|
||||
reset_control_assert(host->pdata->rstc);
|
||||
|
||||
err_clk_ciu:
|
||||
clk_disable_unprepare(host->ciu_clk);
|
||||
@ -3373,8 +3368,7 @@ void dw_mci_remove(struct dw_mci *host)
|
||||
if (host->use_dma && host->dma_ops->exit)
|
||||
host->dma_ops->exit(host);
|
||||
|
||||
if (!IS_ERR(host->pdata->rstc))
|
||||
reset_control_assert(host->pdata->rstc);
|
||||
reset_control_assert(host->pdata->rstc);
|
||||
|
||||
clk_disable_unprepare(host->ciu_clk);
|
||||
clk_disable_unprepare(host->biu_clk);
|
||||
|
@ -1397,6 +1397,8 @@ static int mmc_spi_probe(struct spi_device *spi)
|
||||
|
||||
host->ones = ones;
|
||||
|
||||
dev_set_drvdata(&spi->dev, mmc);
|
||||
|
||||
/* Platform data is used to hook up things like card sensing
|
||||
* and power switching gpios.
|
||||
*/
|
||||
@ -1413,8 +1415,6 @@ static int mmc_spi_probe(struct spi_device *spi)
|
||||
host->powerup_msecs = 250;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&spi->dev, mmc);
|
||||
|
||||
/* preallocate dma buffers */
|
||||
host->data = kmalloc(sizeof(*host->data), GFP_KERNEL);
|
||||
if (!host->data)
|
||||
@ -1494,8 +1494,8 @@ fail_glue_init:
|
||||
fail_dma:
|
||||
kfree(host->data);
|
||||
fail_nobuf1:
|
||||
mmc_free_host(mmc);
|
||||
mmc_spi_put_pdata(spi);
|
||||
mmc_free_host(mmc);
|
||||
nomem:
|
||||
kfree(ones);
|
||||
return status;
|
||||
@ -1518,8 +1518,8 @@ static int mmc_spi_remove(struct spi_device *spi)
|
||||
kfree(host->ones);
|
||||
|
||||
spi->max_speed_hz = mmc->f_max;
|
||||
mmc_free_host(mmc);
|
||||
mmc_spi_put_pdata(spi);
|
||||
mmc_free_host(mmc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -257,7 +257,6 @@ static void moxart_dma_complete(void *param)
|
||||
static void moxart_transfer_dma(struct mmc_data *data, struct moxart_host *host)
|
||||
{
|
||||
u32 len, dir_slave;
|
||||
long dma_time;
|
||||
struct dma_async_tx_descriptor *desc = NULL;
|
||||
struct dma_chan *dma_chan;
|
||||
|
||||
@ -294,8 +293,8 @@ static void moxart_transfer_dma(struct mmc_data *data, struct moxart_host *host)
|
||||
|
||||
data->bytes_xfered += host->data_remain;
|
||||
|
||||
dma_time = wait_for_completion_interruptible_timeout(
|
||||
&host->dma_complete, host->timeout);
|
||||
wait_for_completion_interruptible_timeout(&host->dma_complete,
|
||||
host->timeout);
|
||||
|
||||
dma_unmap_sg(dma_chan->device->dev,
|
||||
data->sg, data->sg_len,
|
||||
@ -395,7 +394,6 @@ static void moxart_prepare_data(struct moxart_host *host)
|
||||
static void moxart_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||
{
|
||||
struct moxart_host *host = mmc_priv(mmc);
|
||||
long pio_time;
|
||||
unsigned long flags;
|
||||
u32 status;
|
||||
|
||||
@ -431,8 +429,8 @@ static void moxart_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
|
||||
/* PIO transfers start from interrupt. */
|
||||
pio_time = wait_for_completion_interruptible_timeout(
|
||||
&host->pio_complete, host->timeout);
|
||||
wait_for_completion_interruptible_timeout(&host->pio_complete,
|
||||
host->timeout);
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
}
|
||||
|
@ -19,11 +19,6 @@
|
||||
#include <linux/mmc/core.h>
|
||||
#include <linux/mmc/host.h>
|
||||
|
||||
/* For archs that don't support NO_IRQ (such as mips), provide a dummy value */
|
||||
#ifndef NO_IRQ
|
||||
#define NO_IRQ 0
|
||||
#endif
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
struct of_mmc_spi {
|
||||
@ -54,22 +49,22 @@ static void of_mmc_spi_exit(struct device *dev, void *mmc)
|
||||
|
||||
struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi)
|
||||
{
|
||||
struct mmc_host *mmc = dev_get_drvdata(&spi->dev);
|
||||
struct device *dev = &spi->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct of_mmc_spi *oms;
|
||||
|
||||
if (dev->platform_data || !np)
|
||||
if (dev->platform_data || !dev_fwnode(dev))
|
||||
return dev->platform_data;
|
||||
|
||||
oms = kzalloc(sizeof(*oms), GFP_KERNEL);
|
||||
if (!oms)
|
||||
return NULL;
|
||||
|
||||
if (mmc_of_parse_voltage(np, &oms->pdata.ocr_mask) <= 0)
|
||||
if (mmc_of_parse_voltage(mmc, &oms->pdata.ocr_mask) < 0)
|
||||
goto err_ocr;
|
||||
|
||||
oms->detect_irq = irq_of_parse_and_map(np, 0);
|
||||
if (oms->detect_irq != 0) {
|
||||
oms->detect_irq = spi->irq;
|
||||
if (oms->detect_irq > 0) {
|
||||
oms->pdata.init = of_mmc_spi_init;
|
||||
oms->pdata.exit = of_mmc_spi_exit;
|
||||
} else {
|
||||
@ -87,10 +82,9 @@ EXPORT_SYMBOL(mmc_spi_get_pdata);
|
||||
void mmc_spi_put_pdata(struct spi_device *spi)
|
||||
{
|
||||
struct device *dev = &spi->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct of_mmc_spi *oms = to_of_mmc_spi(dev);
|
||||
|
||||
if (!dev->platform_data || !np)
|
||||
if (!dev->platform_data || !dev_fwnode(dev))
|
||||
return;
|
||||
|
||||
kfree(oms);
|
||||
|
@ -581,7 +581,6 @@ static int owl_mmc_probe(struct platform_device *pdev)
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
owl_host->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(owl_host->base)) {
|
||||
dev_err(&pdev->dev, "Failed to remap registers\n");
|
||||
ret = PTR_ERR(owl_host->base);
|
||||
goto err_free_host;
|
||||
}
|
||||
|
@ -70,6 +70,8 @@ struct renesas_sdhi {
|
||||
DECLARE_BITMAP(smpcmp, BITS_PER_LONG);
|
||||
unsigned int tap_num;
|
||||
unsigned int tap_set;
|
||||
|
||||
struct reset_control *rstc;
|
||||
};
|
||||
|
||||
#define host_to_priv(host) \
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/tmio.h>
|
||||
#include <linux/mmc/host.h>
|
||||
@ -32,6 +33,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/sh_dma.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sys_soc.h>
|
||||
@ -557,24 +559,35 @@ static int renesas_sdhi_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_io
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void renesas_sdhi_scc_reset(struct tmio_mmc_host *host, struct renesas_sdhi *priv)
|
||||
{
|
||||
renesas_sdhi_disable_scc(host->mmc);
|
||||
renesas_sdhi_reset_hs400_mode(host, priv);
|
||||
priv->needs_adjust_hs400 = false;
|
||||
|
||||
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL,
|
||||
~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
|
||||
sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
|
||||
}
|
||||
|
||||
/* only populated for TMIO_MMC_MIN_RCAR2 */
|
||||
static void renesas_sdhi_reset(struct tmio_mmc_host *host)
|
||||
{
|
||||
struct renesas_sdhi *priv = host_to_priv(host);
|
||||
int ret;
|
||||
u16 val;
|
||||
|
||||
if (priv->scc_ctl) {
|
||||
renesas_sdhi_disable_scc(host->mmc);
|
||||
renesas_sdhi_reset_hs400_mode(host, priv);
|
||||
if (priv->rstc) {
|
||||
reset_control_reset(priv->rstc);
|
||||
/* Unknown why but without polling reset status, it will hang */
|
||||
read_poll_timeout(reset_control_status, ret, ret == 0, 1, 100,
|
||||
false, priv->rstc);
|
||||
priv->needs_adjust_hs400 = false;
|
||||
|
||||
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL,
|
||||
~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
|
||||
sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
|
||||
renesas_sdhi_set_clock(host, host->clk_cache);
|
||||
} else if (priv->scc_ctl) {
|
||||
renesas_sdhi_scc_reset(host, priv);
|
||||
}
|
||||
|
||||
sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, TMIO_MASK_INIT_RCAR2);
|
||||
|
||||
if (sd_ctrl_read16(host, CTL_VERSION) >= SDHI_VER_GEN3_SD) {
|
||||
val = sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT);
|
||||
val |= CARD_OPT_EXTOP;
|
||||
@ -691,7 +704,7 @@ static int renesas_sdhi_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
||||
|
||||
ret = renesas_sdhi_select_tuning(host);
|
||||
if (ret < 0)
|
||||
renesas_sdhi_reset(host);
|
||||
renesas_sdhi_scc_reset(host, priv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1034,6 +1047,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
|
||||
host->ops.start_signal_voltage_switch =
|
||||
renesas_sdhi_start_signal_voltage_switch;
|
||||
host->sdcard_irq_setbit_mask = TMIO_STAT_ALWAYS_SET_27;
|
||||
host->sdcard_irq_mask_all = TMIO_MASK_ALL_RCAR2;
|
||||
host->reset = renesas_sdhi_reset;
|
||||
}
|
||||
|
||||
@ -1076,6 +1090,10 @@ int renesas_sdhi_probe(struct platform_device *pdev,
|
||||
if (ret)
|
||||
goto efree;
|
||||
|
||||
priv->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
|
||||
if (IS_ERR(priv->rstc))
|
||||
return PTR_ERR(priv->rstc);
|
||||
|
||||
ver = sd_ctrl_read16(host, CTL_VERSION);
|
||||
/* GEN2_SDR104 is first known SDHI to use 32bit block count */
|
||||
if (ver < SDHI_VER_GEN2_SDR104 && mmc_data->max_blk_count > U16_MAX)
|
||||
|
@ -97,7 +97,7 @@ static const struct renesas_sdhi_of_data of_rza2_compatible = {
|
||||
TMIO_MMC_HAVE_CBSY,
|
||||
.tmio_ocr_mask = MMC_VDD_32_33,
|
||||
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
|
||||
MMC_CAP_CMD23,
|
||||
MMC_CAP_CMD23 | MMC_CAP_WAIT_WHILE_BUSY,
|
||||
.bus_shift = 2,
|
||||
.scc_offset = 0 - 0x1000,
|
||||
.taps = rcar_gen3_scc_taps,
|
||||
@ -111,7 +111,7 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
|
||||
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL |
|
||||
TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2,
|
||||
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
|
||||
MMC_CAP_CMD23,
|
||||
MMC_CAP_CMD23 | MMC_CAP_WAIT_WHILE_BUSY,
|
||||
.capabilities2 = MMC_CAP2_NO_WRITE_PROTECT | MMC_CAP2_MERGE_CAPABLE,
|
||||
.bus_shift = 2,
|
||||
.scc_offset = 0x1000,
|
||||
|
@ -33,12 +33,14 @@ static const struct renesas_sdhi_of_data of_rz_compatible = {
|
||||
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_32BIT_DATA_PORT |
|
||||
TMIO_MMC_HAVE_CBSY,
|
||||
.tmio_ocr_mask = MMC_VDD_32_33,
|
||||
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
|
||||
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
|
||||
MMC_CAP_WAIT_WHILE_BUSY,
|
||||
};
|
||||
|
||||
static const struct renesas_sdhi_of_data of_rcar_gen1_compatible = {
|
||||
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL,
|
||||
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
|
||||
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
|
||||
MMC_CAP_WAIT_WHILE_BUSY,
|
||||
.capabilities2 = MMC_CAP2_NO_WRITE_PROTECT,
|
||||
};
|
||||
|
||||
@ -58,7 +60,7 @@ static const struct renesas_sdhi_of_data of_rcar_gen2_compatible = {
|
||||
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL |
|
||||
TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2,
|
||||
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
|
||||
MMC_CAP_CMD23,
|
||||
MMC_CAP_CMD23 | MMC_CAP_WAIT_WHILE_BUSY,
|
||||
.capabilities2 = MMC_CAP2_NO_WRITE_PROTECT,
|
||||
.dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES,
|
||||
.dma_rx_offset = 0x2000,
|
||||
|
@ -772,6 +772,7 @@ static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = {
|
||||
{ "QCOM8051", NULL, &sdhci_acpi_slot_qcom_sd_3v },
|
||||
{ "QCOM8052", NULL, &sdhci_acpi_slot_qcom_sd },
|
||||
{ "AMDI0040", NULL, &sdhci_acpi_slot_amd_emmc },
|
||||
{ "AMDI0041", NULL, &sdhci_acpi_slot_amd_emmc },
|
||||
{ },
|
||||
};
|
||||
|
||||
@ -789,6 +790,7 @@ static const struct acpi_device_id sdhci_acpi_ids[] = {
|
||||
{ "QCOM8051" },
|
||||
{ "QCOM8052" },
|
||||
{ "AMDI0040" },
|
||||
{ "AMDI0041" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids);
|
||||
|
@ -199,7 +199,6 @@ static int sdhci_brcmstb_add_host(struct sdhci_host *host,
|
||||
if (dma64) {
|
||||
dev_dbg(mmc_dev(host->mmc), "Using 64 bit DMA\n");
|
||||
cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
|
||||
cq_host->quirks |= CQHCI_QUIRK_SHORT_TXFR_DESC_SZ;
|
||||
}
|
||||
|
||||
ret = cqhci_init(cq_host, host->mmc, dma64);
|
||||
|
@ -434,10 +434,10 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
|
||||
* Do not advertise faster UHS modes if there are no
|
||||
* pinctrl states for 100MHz/200MHz.
|
||||
*/
|
||||
if (IS_ERR_OR_NULL(imx_data->pins_100mhz) ||
|
||||
IS_ERR_OR_NULL(imx_data->pins_200mhz))
|
||||
val &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50
|
||||
| SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_HS400);
|
||||
if (IS_ERR_OR_NULL(imx_data->pins_100mhz))
|
||||
val &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50);
|
||||
if (IS_ERR_OR_NULL(imx_data->pins_200mhz))
|
||||
val &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_HS400);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1453,7 +1453,6 @@ static const struct cqhci_host_ops esdhc_cqhci_ops = {
|
||||
.dumpregs = esdhc_sdhci_dumpregs,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int
|
||||
sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
|
||||
struct sdhci_host *host,
|
||||
@ -1486,9 +1485,9 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
|
||||
if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line))
|
||||
boarddata->delay_line = 0;
|
||||
|
||||
mmc_of_parse_voltage(np, &host->ocr_mask);
|
||||
mmc_of_parse_voltage(host->mmc, &host->ocr_mask);
|
||||
|
||||
if (esdhc_is_usdhc(imx_data)) {
|
||||
if (esdhc_is_usdhc(imx_data) && !IS_ERR(imx_data->pinctrl)) {
|
||||
imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl,
|
||||
ESDHC_PINCTRL_STATE_100MHZ);
|
||||
imx_data->pins_200mhz = pinctrl_lookup_state(imx_data->pinctrl,
|
||||
@ -1505,20 +1504,9 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline int
|
||||
sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
|
||||
struct sdhci_host *host,
|
||||
struct pltfm_imx_data *imx_data)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *of_id =
|
||||
of_match_device(imx_esdhc_dt_ids, &pdev->dev);
|
||||
struct sdhci_pltfm_host *pltfm_host;
|
||||
struct sdhci_host *host;
|
||||
struct cqhci_host *cq_host;
|
||||
@ -1534,7 +1522,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
|
||||
|
||||
imx_data = sdhci_pltfm_priv(pltfm_host);
|
||||
|
||||
imx_data->socdata = of_id->data;
|
||||
imx_data->socdata = device_get_match_data(&pdev->dev);
|
||||
|
||||
if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
|
||||
cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0);
|
||||
|
@ -367,14 +367,14 @@ static int esdhc_mcf_plat_init(struct sdhci_host *host,
|
||||
struct pltfm_mcf_data *mcf_data)
|
||||
{
|
||||
struct mcf_esdhc_platform_data *plat_data;
|
||||
struct device *dev = mmc_dev(host->mmc);
|
||||
|
||||
if (!host->mmc->parent->platform_data) {
|
||||
dev_err(mmc_dev(host->mmc), "no platform data!\n");
|
||||
if (!dev->platform_data) {
|
||||
dev_err(dev, "no platform data!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
plat_data = (struct mcf_esdhc_platform_data *)
|
||||
host->mmc->parent->platform_data;
|
||||
plat_data = (struct mcf_esdhc_platform_data *)dev->platform_data;
|
||||
|
||||
/* Card_detect */
|
||||
switch (plat_data->cd_type) {
|
||||
|
@ -1863,7 +1863,6 @@ static int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host,
|
||||
struct mmc_host *mmc = msm_host->mmc;
|
||||
struct device *dev = mmc_dev(mmc);
|
||||
struct resource *res;
|
||||
int err;
|
||||
|
||||
if (!(cqhci_readl(cq_host, CQHCI_CAP) & CQHCI_CAP_CS))
|
||||
return 0;
|
||||
@ -1881,11 +1880,8 @@ static int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host,
|
||||
}
|
||||
|
||||
msm_host->ice_mem = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(msm_host->ice_mem)) {
|
||||
err = PTR_ERR(msm_host->ice_mem);
|
||||
dev_err(dev, "Failed to map ICE registers; err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
if (IS_ERR(msm_host->ice_mem))
|
||||
return PTR_ERR(msm_host->ice_mem);
|
||||
|
||||
if (!sdhci_msm_ice_supported(msm_host))
|
||||
goto disable;
|
||||
|
@ -181,7 +181,7 @@ aspeed_sdhci_configure_phase(struct sdhci_host *host, unsigned long rate)
|
||||
struct aspeed_sdhci *sdhci;
|
||||
struct device *dev;
|
||||
|
||||
dev = host->mmc->parent;
|
||||
dev = mmc_dev(host->mmc);
|
||||
sdhci = sdhci_pltfm_priv(sdhci_priv(host));
|
||||
|
||||
if (!sdhci->phase_desc)
|
||||
|
@ -7,11 +7,14 @@
|
||||
* Author: Jisheng Zhang <jszhang@kernel.org>
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
#include "sdhci-pltfm.h"
|
||||
@ -21,11 +24,52 @@
|
||||
/* DWCMSHC specific Mode Select value */
|
||||
#define DWCMSHC_CTRL_HS400 0x7
|
||||
|
||||
/* DWC IP vendor area 1 pointer */
|
||||
#define DWCMSHC_P_VENDOR_AREA1 0xe8
|
||||
#define DWCMSHC_AREA1_MASK GENMASK(11, 0)
|
||||
/* Offset inside the vendor area 1 */
|
||||
#define DWCMSHC_HOST_CTRL3 0x8
|
||||
#define DWCMSHC_EMMC_CONTROL 0x2c
|
||||
#define DWCMSHC_ENHANCED_STROBE BIT(8)
|
||||
#define DWCMSHC_EMMC_ATCTRL 0x40
|
||||
|
||||
/* Rockchip specific Registers */
|
||||
#define DWCMSHC_EMMC_DLL_CTRL 0x800
|
||||
#define DWCMSHC_EMMC_DLL_RXCLK 0x804
|
||||
#define DWCMSHC_EMMC_DLL_TXCLK 0x808
|
||||
#define DWCMSHC_EMMC_DLL_STRBIN 0x80c
|
||||
#define DLL_STRBIN_TAPNUM_FROM_SW BIT(24)
|
||||
#define DWCMSHC_EMMC_DLL_STATUS0 0x840
|
||||
#define DWCMSHC_EMMC_DLL_START BIT(0)
|
||||
#define DWCMSHC_EMMC_DLL_LOCKED BIT(8)
|
||||
#define DWCMSHC_EMMC_DLL_TIMEOUT BIT(9)
|
||||
#define DWCMSHC_EMMC_DLL_RXCLK_SRCSEL 29
|
||||
#define DWCMSHC_EMMC_DLL_START_POINT 16
|
||||
#define DWCMSHC_EMMC_DLL_INC 8
|
||||
#define DWCMSHC_EMMC_DLL_DLYENA BIT(27)
|
||||
#define DLL_TXCLK_TAPNUM_DEFAULT 0x8
|
||||
#define DLL_STRBIN_TAPNUM_DEFAULT 0x8
|
||||
#define DLL_TXCLK_TAPNUM_FROM_SW BIT(24)
|
||||
#define DLL_RXCLK_NO_INVERTER 1
|
||||
#define DLL_RXCLK_INVERTER 0
|
||||
#define DLL_LOCK_WO_TMOUT(x) \
|
||||
((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \
|
||||
(((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0))
|
||||
#define RK3568_MAX_CLKS 3
|
||||
|
||||
#define BOUNDARY_OK(addr, len) \
|
||||
((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1)))
|
||||
|
||||
struct rk3568_priv {
|
||||
/* Rockchip specified optional clocks */
|
||||
struct clk_bulk_data rockchip_clks[RK3568_MAX_CLKS];
|
||||
u8 txclk_tapnum;
|
||||
};
|
||||
|
||||
struct dwcmshc_priv {
|
||||
struct clk *bus_clk;
|
||||
int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA reg */
|
||||
void *priv; /* pointer to SoC private stuff */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -51,6 +95,16 @@ static void dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc,
|
||||
sdhci_adma_write_desc(host, desc, addr, len, cmd);
|
||||
}
|
||||
|
||||
static unsigned int dwcmshc_get_max_clock(struct sdhci_host *host)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
|
||||
if (pltfm_host->clk)
|
||||
return sdhci_pltfm_clk_get_max_clock(host);
|
||||
else
|
||||
return pltfm_host->clock;
|
||||
}
|
||||
|
||||
static void dwcmshc_check_auto_cmd23(struct mmc_host *mmc,
|
||||
struct mmc_request *mrq)
|
||||
{
|
||||
@ -100,10 +154,120 @@ static void dwcmshc_set_uhs_signaling(struct sdhci_host *host,
|
||||
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
|
||||
}
|
||||
|
||||
static void dwcmshc_hs400_enhanced_strobe(struct mmc_host *mmc,
|
||||
struct mmc_ios *ios)
|
||||
{
|
||||
u32 vendor;
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
||||
int reg = priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL;
|
||||
|
||||
vendor = sdhci_readl(host, reg);
|
||||
if (ios->enhanced_strobe)
|
||||
vendor |= DWCMSHC_ENHANCED_STROBE;
|
||||
else
|
||||
vendor &= ~DWCMSHC_ENHANCED_STROBE;
|
||||
|
||||
sdhci_writel(host, vendor, reg);
|
||||
}
|
||||
|
||||
static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host);
|
||||
struct rk3568_priv *priv = dwc_priv->priv;
|
||||
u8 txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT;
|
||||
u32 extra, reg;
|
||||
int err;
|
||||
|
||||
host->mmc->actual_clock = 0;
|
||||
|
||||
/*
|
||||
* DO NOT TOUCH THIS SETTING. RX clk inverter unit is enabled
|
||||
* by default, but it shouldn't be enabled. We should anyway
|
||||
* disable it before issuing any cmds.
|
||||
*/
|
||||
extra = DWCMSHC_EMMC_DLL_DLYENA |
|
||||
DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL;
|
||||
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK);
|
||||
|
||||
if (clock == 0)
|
||||
return;
|
||||
|
||||
/* Rockchip platform only support 375KHz for identify mode */
|
||||
if (clock <= 400000)
|
||||
clock = 375000;
|
||||
|
||||
err = clk_set_rate(pltfm_host->clk, clock);
|
||||
if (err)
|
||||
dev_err(mmc_dev(host->mmc), "fail to set clock %d", clock);
|
||||
|
||||
sdhci_set_clock(host, clock);
|
||||
|
||||
/* Disable cmd conflict check */
|
||||
reg = dwc_priv->vendor_specific_area1 + DWCMSHC_HOST_CTRL3;
|
||||
extra = sdhci_readl(host, reg);
|
||||
extra &= ~BIT(0);
|
||||
sdhci_writel(host, extra, reg);
|
||||
|
||||
if (clock <= 400000) {
|
||||
/* Disable DLL to reset sample clock */
|
||||
sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reset DLL */
|
||||
sdhci_writel(host, BIT(1), DWCMSHC_EMMC_DLL_CTRL);
|
||||
udelay(1);
|
||||
sdhci_writel(host, 0x0, DWCMSHC_EMMC_DLL_CTRL);
|
||||
|
||||
/* Init DLL settings */
|
||||
extra = 0x5 << DWCMSHC_EMMC_DLL_START_POINT |
|
||||
0x2 << DWCMSHC_EMMC_DLL_INC |
|
||||
DWCMSHC_EMMC_DLL_START;
|
||||
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_CTRL);
|
||||
err = readl_poll_timeout(host->ioaddr + DWCMSHC_EMMC_DLL_STATUS0,
|
||||
extra, DLL_LOCK_WO_TMOUT(extra), 1,
|
||||
500 * USEC_PER_MSEC);
|
||||
if (err) {
|
||||
dev_err(mmc_dev(host->mmc), "DLL lock timeout!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
extra = 0x1 << 16 | /* tune clock stop en */
|
||||
0x2 << 17 | /* pre-change delay */
|
||||
0x3 << 19; /* post-change delay */
|
||||
sdhci_writel(host, extra, dwc_priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL);
|
||||
|
||||
if (host->mmc->ios.timing == MMC_TIMING_MMC_HS200 ||
|
||||
host->mmc->ios.timing == MMC_TIMING_MMC_HS400)
|
||||
txclk_tapnum = priv->txclk_tapnum;
|
||||
|
||||
extra = DWCMSHC_EMMC_DLL_DLYENA |
|
||||
DLL_TXCLK_TAPNUM_FROM_SW |
|
||||
txclk_tapnum;
|
||||
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK);
|
||||
|
||||
extra = DWCMSHC_EMMC_DLL_DLYENA |
|
||||
DLL_STRBIN_TAPNUM_DEFAULT |
|
||||
DLL_STRBIN_TAPNUM_FROM_SW;
|
||||
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN);
|
||||
}
|
||||
|
||||
static const struct sdhci_ops sdhci_dwcmshc_ops = {
|
||||
.set_clock = sdhci_set_clock,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
.set_uhs_signaling = dwcmshc_set_uhs_signaling,
|
||||
.get_max_clock = dwcmshc_get_max_clock,
|
||||
.reset = sdhci_reset,
|
||||
.adma_write_desc = dwcmshc_adma_write_desc,
|
||||
};
|
||||
|
||||
static const struct sdhci_ops sdhci_dwcmshc_rk3568_ops = {
|
||||
.set_clock = dwcmshc_rk3568_set_clock,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
.set_uhs_signaling = dwcmshc_set_uhs_signaling,
|
||||
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
|
||||
.reset = sdhci_reset,
|
||||
.adma_write_desc = dwcmshc_adma_write_desc,
|
||||
@ -115,15 +279,86 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = {
|
||||
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
|
||||
};
|
||||
|
||||
static const struct sdhci_pltfm_data sdhci_dwcmshc_rk3568_pdata = {
|
||||
.ops = &sdhci_dwcmshc_rk3568_ops,
|
||||
.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
|
||||
SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
|
||||
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
|
||||
SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
|
||||
};
|
||||
|
||||
static int dwcmshc_rk3568_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)
|
||||
{
|
||||
int err;
|
||||
struct rk3568_priv *priv = dwc_priv->priv;
|
||||
|
||||
priv->rockchip_clks[0].id = "axi";
|
||||
priv->rockchip_clks[1].id = "block";
|
||||
priv->rockchip_clks[2].id = "timer";
|
||||
err = devm_clk_bulk_get_optional(mmc_dev(host->mmc), RK3568_MAX_CLKS,
|
||||
priv->rockchip_clks);
|
||||
if (err) {
|
||||
dev_err(mmc_dev(host->mmc), "failed to get clocks %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = clk_bulk_prepare_enable(RK3568_MAX_CLKS, priv->rockchip_clks);
|
||||
if (err) {
|
||||
dev_err(mmc_dev(host->mmc), "failed to enable clocks %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (of_property_read_u8(mmc_dev(host->mmc)->of_node, "rockchip,txclk-tapnum",
|
||||
&priv->txclk_tapnum))
|
||||
priv->txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT;
|
||||
|
||||
/* Disable cmd conflict check */
|
||||
sdhci_writel(host, 0x0, dwc_priv->vendor_specific_area1 + DWCMSHC_HOST_CTRL3);
|
||||
/* Reset previous settings */
|
||||
sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK);
|
||||
sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_STRBIN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id sdhci_dwcmshc_dt_ids[] = {
|
||||
{
|
||||
.compatible = "rockchip,rk3568-dwcmshc",
|
||||
.data = &sdhci_dwcmshc_rk3568_pdata,
|
||||
},
|
||||
{
|
||||
.compatible = "snps,dwcmshc-sdhci",
|
||||
.data = &sdhci_dwcmshc_pdata,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id sdhci_dwcmshc_acpi_ids[] = {
|
||||
{ .id = "MLNXBF30" },
|
||||
{}
|
||||
};
|
||||
#endif
|
||||
|
||||
static int dwcmshc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct sdhci_pltfm_host *pltfm_host;
|
||||
struct sdhci_host *host;
|
||||
struct dwcmshc_priv *priv;
|
||||
struct rk3568_priv *rk_priv = NULL;
|
||||
const struct sdhci_pltfm_data *pltfm_data;
|
||||
int err;
|
||||
u32 extra;
|
||||
|
||||
host = sdhci_pltfm_init(pdev, &sdhci_dwcmshc_pdata,
|
||||
pltfm_data = of_device_get_match_data(&pdev->dev);
|
||||
if (!pltfm_data) {
|
||||
dev_err(&pdev->dev, "Error: No device match data found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
host = sdhci_pltfm_init(pdev, pltfm_data,
|
||||
sizeof(struct dwcmshc_priv));
|
||||
if (IS_ERR(host))
|
||||
return PTR_ERR(host);
|
||||
@ -131,7 +366,7 @@ static int dwcmshc_probe(struct platform_device *pdev)
|
||||
/*
|
||||
* extra adma table cnt for cross 128M boundary handling.
|
||||
*/
|
||||
extra = DIV_ROUND_UP_ULL(dma_get_required_mask(&pdev->dev), SZ_128M);
|
||||
extra = DIV_ROUND_UP_ULL(dma_get_required_mask(dev), SZ_128M);
|
||||
if (extra > SDHCI_MAX_SEGS)
|
||||
extra = SDHCI_MAX_SEGS;
|
||||
host->adma_table_cnt += extra;
|
||||
@ -139,19 +374,21 @@ static int dwcmshc_probe(struct platform_device *pdev)
|
||||
pltfm_host = sdhci_priv(host);
|
||||
priv = sdhci_pltfm_priv(pltfm_host);
|
||||
|
||||
pltfm_host->clk = devm_clk_get(&pdev->dev, "core");
|
||||
if (IS_ERR(pltfm_host->clk)) {
|
||||
err = PTR_ERR(pltfm_host->clk);
|
||||
dev_err(&pdev->dev, "failed to get core clk: %d\n", err);
|
||||
goto free_pltfm;
|
||||
}
|
||||
err = clk_prepare_enable(pltfm_host->clk);
|
||||
if (err)
|
||||
goto free_pltfm;
|
||||
if (dev->of_node) {
|
||||
pltfm_host->clk = devm_clk_get(dev, "core");
|
||||
if (IS_ERR(pltfm_host->clk)) {
|
||||
err = PTR_ERR(pltfm_host->clk);
|
||||
dev_err(dev, "failed to get core clk: %d\n", err);
|
||||
goto free_pltfm;
|
||||
}
|
||||
err = clk_prepare_enable(pltfm_host->clk);
|
||||
if (err)
|
||||
goto free_pltfm;
|
||||
|
||||
priv->bus_clk = devm_clk_get(&pdev->dev, "bus");
|
||||
if (!IS_ERR(priv->bus_clk))
|
||||
clk_prepare_enable(priv->bus_clk);
|
||||
priv->bus_clk = devm_clk_get(dev, "bus");
|
||||
if (!IS_ERR(priv->bus_clk))
|
||||
clk_prepare_enable(priv->bus_clk);
|
||||
}
|
||||
|
||||
err = mmc_of_parse(host->mmc);
|
||||
if (err)
|
||||
@ -159,7 +396,27 @@ static int dwcmshc_probe(struct platform_device *pdev)
|
||||
|
||||
sdhci_get_of_property(pdev);
|
||||
|
||||
priv->vendor_specific_area1 =
|
||||
sdhci_readl(host, DWCMSHC_P_VENDOR_AREA1) & DWCMSHC_AREA1_MASK;
|
||||
|
||||
host->mmc_host_ops.request = dwcmshc_request;
|
||||
host->mmc_host_ops.hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe;
|
||||
|
||||
if (pltfm_data == &sdhci_dwcmshc_rk3568_pdata) {
|
||||
rk_priv = devm_kzalloc(&pdev->dev, sizeof(struct rk3568_priv), GFP_KERNEL);
|
||||
if (!rk_priv) {
|
||||
err = -ENOMEM;
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
priv->priv = rk_priv;
|
||||
|
||||
err = dwcmshc_rk3568_init(host, priv);
|
||||
if (err)
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
|
||||
|
||||
err = sdhci_add_host(host);
|
||||
if (err)
|
||||
@ -170,6 +427,9 @@ static int dwcmshc_probe(struct platform_device *pdev)
|
||||
err_clk:
|
||||
clk_disable_unprepare(pltfm_host->clk);
|
||||
clk_disable_unprepare(priv->bus_clk);
|
||||
if (rk_priv)
|
||||
clk_bulk_disable_unprepare(RK3568_MAX_CLKS,
|
||||
rk_priv->rockchip_clks);
|
||||
free_pltfm:
|
||||
sdhci_pltfm_free(pdev);
|
||||
return err;
|
||||
@ -180,12 +440,15 @@ static int dwcmshc_remove(struct platform_device *pdev)
|
||||
struct sdhci_host *host = platform_get_drvdata(pdev);
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
||||
struct rk3568_priv *rk_priv = priv->priv;
|
||||
|
||||
sdhci_remove_host(host, 0);
|
||||
|
||||
clk_disable_unprepare(pltfm_host->clk);
|
||||
clk_disable_unprepare(priv->bus_clk);
|
||||
|
||||
if (rk_priv)
|
||||
clk_bulk_disable_unprepare(RK3568_MAX_CLKS,
|
||||
rk_priv->rockchip_clks);
|
||||
sdhci_pltfm_free(pdev);
|
||||
|
||||
return 0;
|
||||
@ -197,6 +460,7 @@ static int dwcmshc_suspend(struct device *dev)
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
||||
struct rk3568_priv *rk_priv = priv->priv;
|
||||
int ret;
|
||||
|
||||
ret = sdhci_suspend_host(host);
|
||||
@ -207,6 +471,10 @@ static int dwcmshc_suspend(struct device *dev)
|
||||
if (!IS_ERR(priv->bus_clk))
|
||||
clk_disable_unprepare(priv->bus_clk);
|
||||
|
||||
if (rk_priv)
|
||||
clk_bulk_disable_unprepare(RK3568_MAX_CLKS,
|
||||
rk_priv->rockchip_clks);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -215,6 +483,7 @@ static int dwcmshc_resume(struct device *dev)
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
||||
struct rk3568_priv *rk_priv = priv->priv;
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(pltfm_host->clk);
|
||||
@ -227,23 +496,25 @@ static int dwcmshc_resume(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (rk_priv) {
|
||||
ret = clk_bulk_prepare_enable(RK3568_MAX_CLKS,
|
||||
rk_priv->rockchip_clks);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return sdhci_resume_host(host);
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(dwcmshc_pmops, dwcmshc_suspend, dwcmshc_resume);
|
||||
|
||||
static const struct of_device_id sdhci_dwcmshc_dt_ids[] = {
|
||||
{ .compatible = "snps,dwcmshc-sdhci" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids);
|
||||
|
||||
static struct platform_driver sdhci_dwcmshc_driver = {
|
||||
.driver = {
|
||||
.name = "sdhci-dwcmshc",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.of_match_table = sdhci_dwcmshc_dt_ids,
|
||||
.acpi_match_table = ACPI_PTR(sdhci_dwcmshc_acpi_ids),
|
||||
.pm = &dwcmshc_pmops,
|
||||
},
|
||||
.probe = dwcmshc_probe,
|
||||
|
@ -1489,7 +1489,7 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
mmc_of_parse_voltage(np, &host->ocr_mask);
|
||||
mmc_of_parse_voltage(host->mmc, &host->ocr_mask);
|
||||
|
||||
ret = sdhci_add_host(host);
|
||||
if (ret)
|
||||
|
@ -516,6 +516,7 @@ struct intel_host {
|
||||
int drv_strength;
|
||||
bool d3_retune;
|
||||
bool rpm_retune_ok;
|
||||
bool needs_pwr_off;
|
||||
u32 glk_rx_ctrl1;
|
||||
u32 glk_tun_val;
|
||||
u32 active_ltr;
|
||||
@ -643,9 +644,25 @@ out:
|
||||
static void sdhci_intel_set_power(struct sdhci_host *host, unsigned char mode,
|
||||
unsigned short vdd)
|
||||
{
|
||||
struct sdhci_pci_slot *slot = sdhci_priv(host);
|
||||
struct intel_host *intel_host = sdhci_pci_priv(slot);
|
||||
int cntr;
|
||||
u8 reg;
|
||||
|
||||
/*
|
||||
* Bus power may control card power, but a full reset still may not
|
||||
* reset the power, whereas a direct write to SDHCI_POWER_CONTROL can.
|
||||
* That might be needed to initialize correctly, if the card was left
|
||||
* powered on previously.
|
||||
*/
|
||||
if (intel_host->needs_pwr_off) {
|
||||
intel_host->needs_pwr_off = false;
|
||||
if (mode != MMC_POWER_OFF) {
|
||||
sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
|
||||
usleep_range(10000, 12500);
|
||||
}
|
||||
}
|
||||
|
||||
sdhci_set_power(host, mode, vdd);
|
||||
|
||||
if (mode == MMC_POWER_OFF)
|
||||
@ -958,7 +975,7 @@ static int glk_emmc_probe_slot(struct sdhci_pci_slot *slot)
|
||||
slot->host->mmc->caps2 |= MMC_CAP2_CQE;
|
||||
|
||||
if (slot->chip->pdev->device != PCI_DEVICE_ID_INTEL_GLK_EMMC) {
|
||||
slot->host->mmc->caps2 |= MMC_CAP2_HS400_ES,
|
||||
slot->host->mmc->caps2 |= MMC_CAP2_HS400_ES;
|
||||
slot->host->mmc_host_ops.hs400_enhanced_strobe =
|
||||
intel_hs400_enhanced_strobe;
|
||||
slot->host->mmc->caps2 |= MMC_CAP2_CQE_DCMD;
|
||||
@ -1135,6 +1152,14 @@ static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void byt_needs_pwr_off(struct sdhci_pci_slot *slot)
|
||||
{
|
||||
struct intel_host *intel_host = sdhci_pci_priv(slot);
|
||||
u8 reg = sdhci_readb(slot->host, SDHCI_POWER_CONTROL);
|
||||
|
||||
intel_host->needs_pwr_off = reg & SDHCI_POWER_ON;
|
||||
}
|
||||
|
||||
static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
|
||||
{
|
||||
byt_probe_slot(slot);
|
||||
@ -1152,6 +1177,8 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
|
||||
slot->chip->pdev->subsystem_device == PCI_SUBDEVICE_ID_NI_78E3)
|
||||
slot->host->mmc->caps2 |= MMC_CAP2_AVOID_3_3V;
|
||||
|
||||
byt_needs_pwr_off(slot);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1903,6 +1930,8 @@ static const struct pci_device_id pci_ids[] = {
|
||||
SDHCI_PCI_DEVICE(INTEL, CMLH_SD, intel_byt_sd),
|
||||
SDHCI_PCI_DEVICE(INTEL, JSL_EMMC, intel_glk_emmc),
|
||||
SDHCI_PCI_DEVICE(INTEL, JSL_SD, intel_byt_sd),
|
||||
SDHCI_PCI_DEVICE(INTEL, LKF_EMMC, intel_glk_emmc),
|
||||
SDHCI_PCI_DEVICE(INTEL, LKF_SD, intel_byt_sd),
|
||||
SDHCI_PCI_DEVICE(O2, 8120, o2),
|
||||
SDHCI_PCI_DEVICE(O2, 8220, o2),
|
||||
SDHCI_PCI_DEVICE(O2, 8221, o2),
|
||||
|
@ -22,6 +22,10 @@
|
||||
#define GLI_9750_WT_EN_ON 0x1
|
||||
#define GLI_9750_WT_EN_OFF 0x0
|
||||
|
||||
#define SDHCI_GLI_9750_CFG2 0x848
|
||||
#define SDHCI_GLI_9750_CFG2_L1DLY GENMASK(28, 24)
|
||||
#define GLI_9750_CFG2_L1DLY_VALUE 0x1F
|
||||
|
||||
#define SDHCI_GLI_9750_DRIVING 0x860
|
||||
#define SDHCI_GLI_9750_DRIVING_1 GENMASK(11, 0)
|
||||
#define SDHCI_GLI_9750_DRIVING_2 GENMASK(27, 26)
|
||||
@ -90,7 +94,7 @@
|
||||
|
||||
#define PCIE_GLI_9763E_CFG2 0x8A4
|
||||
#define GLI_9763E_CFG2_L1DLY GENMASK(28, 19)
|
||||
#define GLI_9763E_CFG2_L1DLY_MAX 0x3FF
|
||||
#define GLI_9763E_CFG2_L1DLY_MID 0x50
|
||||
|
||||
#define PCIE_GLI_9763E_MMC_CTRL 0x960
|
||||
#define GLI_9763E_HS400_SLOW BIT(3)
|
||||
@ -113,6 +117,10 @@
|
||||
#define PCI_GLI_9755_LFCLK GENMASK(14, 12)
|
||||
#define PCI_GLI_9755_DMACLK BIT(29)
|
||||
|
||||
#define PCI_GLI_9755_CFG2 0x48
|
||||
#define PCI_GLI_9755_CFG2_L1DLY GENMASK(28, 24)
|
||||
#define GLI_9755_CFG2_L1DLY_VALUE 0x1F
|
||||
|
||||
#define PCI_GLI_9755_PLL 0x64
|
||||
#define PCI_GLI_9755_PLL_LDIV GENMASK(9, 0)
|
||||
#define PCI_GLI_9755_PLL_PDIV GENMASK(14, 12)
|
||||
@ -123,6 +131,9 @@
|
||||
#define PCI_GLI_9755_PLLSSC 0x68
|
||||
#define PCI_GLI_9755_PLLSSC_PPM GENMASK(15, 0)
|
||||
|
||||
#define PCI_GLI_9755_SerDes 0x70
|
||||
#define PCI_GLI_9755_SCP_DIS BIT(19)
|
||||
|
||||
#define GLI_MAX_TUNING_LOOP 40
|
||||
|
||||
/* Genesys Logic chipset */
|
||||
@ -405,6 +416,22 @@ static void sdhci_gl9750_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
sdhci_enable_clk(host, clk);
|
||||
}
|
||||
|
||||
static void gl9750_hw_setting(struct sdhci_host *host)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
gl9750_wt_on(host);
|
||||
|
||||
value = sdhci_readl(host, SDHCI_GLI_9750_CFG2);
|
||||
value &= ~SDHCI_GLI_9750_CFG2_L1DLY;
|
||||
/* set ASPM L1 entry delay to 7.9us */
|
||||
value |= FIELD_PREP(SDHCI_GLI_9750_CFG2_L1DLY,
|
||||
GLI_9750_CFG2_L1DLY_VALUE);
|
||||
sdhci_writel(host, value, SDHCI_GLI_9750_CFG2);
|
||||
|
||||
gl9750_wt_off(host);
|
||||
}
|
||||
|
||||
static void gli_pcie_enable_msi(struct sdhci_pci_slot *slot)
|
||||
{
|
||||
int ret;
|
||||
@ -547,6 +574,18 @@ static void gl9755_hw_setting(struct sdhci_pci_slot *slot)
|
||||
value &= ~PCI_GLI_9755_DMACLK;
|
||||
pci_write_config_dword(pdev, PCI_GLI_9755_PECONF, value);
|
||||
|
||||
/* enable short circuit protection */
|
||||
pci_read_config_dword(pdev, PCI_GLI_9755_SerDes, &value);
|
||||
value &= ~PCI_GLI_9755_SCP_DIS;
|
||||
pci_write_config_dword(pdev, PCI_GLI_9755_SerDes, value);
|
||||
|
||||
pci_read_config_dword(pdev, PCI_GLI_9755_CFG2, &value);
|
||||
value &= ~PCI_GLI_9755_CFG2_L1DLY;
|
||||
/* set ASPM L1 entry delay to 7.9us */
|
||||
value |= FIELD_PREP(PCI_GLI_9755_CFG2_L1DLY,
|
||||
GLI_9755_CFG2_L1DLY_VALUE);
|
||||
pci_write_config_dword(pdev, PCI_GLI_9755_CFG2, value);
|
||||
|
||||
gl9755_wt_off(pdev);
|
||||
}
|
||||
|
||||
@ -554,6 +593,7 @@ static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot)
|
||||
{
|
||||
struct sdhci_host *host = slot->host;
|
||||
|
||||
gl9750_hw_setting(host);
|
||||
gli_pcie_enable_msi(slot);
|
||||
slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
|
||||
sdhci_enable_v4_mode(host);
|
||||
@ -802,8 +842,8 @@ static void gli_set_gl9763e(struct sdhci_pci_slot *slot)
|
||||
|
||||
pci_read_config_dword(pdev, PCIE_GLI_9763E_CFG2, &value);
|
||||
value &= ~GLI_9763E_CFG2_L1DLY;
|
||||
/* set ASPM L1 entry delay to 260us */
|
||||
value |= FIELD_PREP(GLI_9763E_CFG2_L1DLY, GLI_9763E_CFG2_L1DLY_MAX);
|
||||
/* set ASPM L1 entry delay to 20us */
|
||||
value |= FIELD_PREP(GLI_9763E_CFG2_L1DLY, GLI_9763E_CFG2_L1DLY_MID);
|
||||
pci_write_config_dword(pdev, PCIE_GLI_9763E_CFG2, value);
|
||||
|
||||
pci_read_config_dword(pdev, PCIE_GLI_9763E_CLKRXDLY, &value);
|
||||
|
@ -706,6 +706,8 @@ static int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip)
|
||||
ret = pci_read_config_dword(chip->pdev,
|
||||
O2_SD_FUNC_REG0,
|
||||
&scratch_32);
|
||||
if (ret)
|
||||
return ret;
|
||||
scratch_32 = ((scratch_32 & 0xFF000000) >> 24);
|
||||
|
||||
/* Check Whether subId is 0x11 or 0x12 */
|
||||
@ -716,6 +718,8 @@ static int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip)
|
||||
ret = pci_read_config_dword(chip->pdev,
|
||||
O2_SD_FUNC_REG4,
|
||||
&scratch_32);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enable Base Clk setting change */
|
||||
scratch_32 |= O2_SD_FREG4_ENABLE_CLK_SET;
|
||||
@ -795,6 +799,8 @@ static int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip)
|
||||
|
||||
ret = pci_read_config_dword(chip->pdev,
|
||||
O2_SD_PLL_SETTING, &scratch_32);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if ((scratch_32 & 0xff000000) == 0x01000000) {
|
||||
scratch_32 &= 0x0000FFFF;
|
||||
@ -812,6 +818,8 @@ static int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip)
|
||||
ret = pci_read_config_dword(chip->pdev,
|
||||
O2_SD_FUNC_REG4,
|
||||
&scratch_32);
|
||||
if (ret)
|
||||
return ret;
|
||||
scratch_32 |= (1 << 22);
|
||||
pci_write_config_dword(chip->pdev,
|
||||
O2_SD_FUNC_REG4, scratch_32);
|
||||
|
@ -57,6 +57,8 @@
|
||||
#define PCI_DEVICE_ID_INTEL_CMLH_SD 0x06f5
|
||||
#define PCI_DEVICE_ID_INTEL_JSL_EMMC 0x4dc4
|
||||
#define PCI_DEVICE_ID_INTEL_JSL_SD 0x4df8
|
||||
#define PCI_DEVICE_ID_INTEL_LKF_EMMC 0x98c4
|
||||
#define PCI_DEVICE_ID_INTEL_LKF_SD 0x98f8
|
||||
|
||||
#define PCI_DEVICE_ID_SYSKONNECT_8000 0x8000
|
||||
#define PCI_DEVICE_ID_VIA_95D0 0x95d0
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
@ -129,7 +130,7 @@ struct sdhci_s3c {
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sdhci_s3c_driver_data - S3C SDHCI platform specific driver data
|
||||
* struct sdhci_s3c_drv_data - S3C SDHCI platform specific driver data
|
||||
* @sdhci_quirks: sdhci host specific quirks.
|
||||
* @no_divider: no or non-standard internal clock divider.
|
||||
*
|
||||
@ -461,28 +462,21 @@ static int sdhci_s3c_parse_dt(struct device *dev,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id sdhci_s3c_dt_match[];
|
||||
#endif
|
||||
|
||||
static inline struct sdhci_s3c_drv_data *sdhci_s3c_get_driver_data(
|
||||
static inline const struct sdhci_s3c_drv_data *sdhci_s3c_get_driver_data(
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
#ifdef CONFIG_OF
|
||||
if (pdev->dev.of_node) {
|
||||
const struct of_device_id *match;
|
||||
match = of_match_node(sdhci_s3c_dt_match, pdev->dev.of_node);
|
||||
return (struct sdhci_s3c_drv_data *)match->data;
|
||||
}
|
||||
if (pdev->dev.of_node)
|
||||
return of_device_get_match_data(&pdev->dev);
|
||||
#endif
|
||||
return (struct sdhci_s3c_drv_data *)
|
||||
return (const struct sdhci_s3c_drv_data *)
|
||||
platform_get_device_id(pdev)->driver_data;
|
||||
}
|
||||
|
||||
static int sdhci_s3c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct s3c_sdhci_platdata *pdata;
|
||||
struct sdhci_s3c_drv_data *drv_data;
|
||||
const struct sdhci_s3c_drv_data *drv_data;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct sdhci_host *host;
|
||||
struct sdhci_s3c *sc;
|
||||
@ -767,7 +761,7 @@ static const struct platform_device_id sdhci_s3c_driver_ids[] = {
|
||||
MODULE_DEVICE_TABLE(platform, sdhci_s3c_driver_ids);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = {
|
||||
static const struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = {
|
||||
.no_divider = true,
|
||||
};
|
||||
|
||||
|
@ -362,11 +362,10 @@ static int sdhci_st_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(icnclk))
|
||||
icnclk = NULL;
|
||||
|
||||
rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
|
||||
rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
|
||||
if (IS_ERR(rstc))
|
||||
rstc = NULL;
|
||||
else
|
||||
reset_control_deassert(rstc);
|
||||
return PTR_ERR(rstc);
|
||||
reset_control_deassert(rstc);
|
||||
|
||||
host = sdhci_pltfm_init(pdev, &sdhci_st_pdata, sizeof(*pdata));
|
||||
if (IS_ERR(host)) {
|
||||
@ -401,10 +400,8 @@ static int sdhci_st_probe(struct platform_device *pdev)
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"top-mmc-delay");
|
||||
pdata->top_ioaddr = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(pdata->top_ioaddr)) {
|
||||
dev_warn(&pdev->dev, "FlashSS Top Dly registers not available");
|
||||
if (IS_ERR(pdata->top_ioaddr))
|
||||
pdata->top_ioaddr = NULL;
|
||||
}
|
||||
|
||||
pltfm_host->clk = clk;
|
||||
pdata->icnclk = icnclk;
|
||||
@ -432,8 +429,7 @@ err_icnclk:
|
||||
err_of:
|
||||
sdhci_pltfm_free(pdev);
|
||||
err_pltfm_init:
|
||||
if (rstc)
|
||||
reset_control_assert(rstc);
|
||||
reset_control_assert(rstc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -450,8 +446,7 @@ static int sdhci_st_remove(struct platform_device *pdev)
|
||||
|
||||
clk_disable_unprepare(pdata->icnclk);
|
||||
|
||||
if (rstc)
|
||||
reset_control_assert(rstc);
|
||||
reset_control_assert(rstc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -471,8 +466,7 @@ static int sdhci_st_suspend(struct device *dev)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (pdata->rstc)
|
||||
reset_control_assert(pdata->rstc);
|
||||
reset_control_assert(pdata->rstc);
|
||||
|
||||
clk_disable_unprepare(pdata->icnclk);
|
||||
clk_disable_unprepare(pltfm_host->clk);
|
||||
@ -498,8 +492,7 @@ static int sdhci_st_resume(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pdata->rstc)
|
||||
reset_control_deassert(pdata->rstc);
|
||||
reset_control_deassert(pdata->rstc);
|
||||
|
||||
st_mmcss_cconfig(np, host);
|
||||
|
||||
|
@ -119,6 +119,10 @@
|
||||
/* SDMMC CQE Base Address for Tegra Host Ver 4.1 and Higher */
|
||||
#define SDHCI_TEGRA_CQE_BASE_ADDR 0xF000
|
||||
|
||||
#define SDHCI_TEGRA_CQE_TRNS_MODE (SDHCI_TRNS_MULTI | \
|
||||
SDHCI_TRNS_BLK_CNT_EN | \
|
||||
SDHCI_TRNS_DMA)
|
||||
|
||||
struct sdhci_tegra_soc_data {
|
||||
const struct sdhci_pltfm_data *pdata;
|
||||
u64 dma_mask;
|
||||
@ -596,49 +600,49 @@ static void tegra_sdhci_parse_pad_autocal_dt(struct sdhci_host *host)
|
||||
&tegra_host->autocal_offsets;
|
||||
int err;
|
||||
|
||||
err = device_property_read_u32(host->mmc->parent,
|
||||
err = device_property_read_u32(mmc_dev(host->mmc),
|
||||
"nvidia,pad-autocal-pull-up-offset-3v3",
|
||||
&autocal->pull_up_3v3);
|
||||
if (err)
|
||||
autocal->pull_up_3v3 = 0;
|
||||
|
||||
err = device_property_read_u32(host->mmc->parent,
|
||||
err = device_property_read_u32(mmc_dev(host->mmc),
|
||||
"nvidia,pad-autocal-pull-down-offset-3v3",
|
||||
&autocal->pull_down_3v3);
|
||||
if (err)
|
||||
autocal->pull_down_3v3 = 0;
|
||||
|
||||
err = device_property_read_u32(host->mmc->parent,
|
||||
err = device_property_read_u32(mmc_dev(host->mmc),
|
||||
"nvidia,pad-autocal-pull-up-offset-1v8",
|
||||
&autocal->pull_up_1v8);
|
||||
if (err)
|
||||
autocal->pull_up_1v8 = 0;
|
||||
|
||||
err = device_property_read_u32(host->mmc->parent,
|
||||
err = device_property_read_u32(mmc_dev(host->mmc),
|
||||
"nvidia,pad-autocal-pull-down-offset-1v8",
|
||||
&autocal->pull_down_1v8);
|
||||
if (err)
|
||||
autocal->pull_down_1v8 = 0;
|
||||
|
||||
err = device_property_read_u32(host->mmc->parent,
|
||||
err = device_property_read_u32(mmc_dev(host->mmc),
|
||||
"nvidia,pad-autocal-pull-up-offset-sdr104",
|
||||
&autocal->pull_up_sdr104);
|
||||
if (err)
|
||||
autocal->pull_up_sdr104 = autocal->pull_up_1v8;
|
||||
|
||||
err = device_property_read_u32(host->mmc->parent,
|
||||
err = device_property_read_u32(mmc_dev(host->mmc),
|
||||
"nvidia,pad-autocal-pull-down-offset-sdr104",
|
||||
&autocal->pull_down_sdr104);
|
||||
if (err)
|
||||
autocal->pull_down_sdr104 = autocal->pull_down_1v8;
|
||||
|
||||
err = device_property_read_u32(host->mmc->parent,
|
||||
err = device_property_read_u32(mmc_dev(host->mmc),
|
||||
"nvidia,pad-autocal-pull-up-offset-hs400",
|
||||
&autocal->pull_up_hs400);
|
||||
if (err)
|
||||
autocal->pull_up_hs400 = autocal->pull_up_1v8;
|
||||
|
||||
err = device_property_read_u32(host->mmc->parent,
|
||||
err = device_property_read_u32(mmc_dev(host->mmc),
|
||||
"nvidia,pad-autocal-pull-down-offset-hs400",
|
||||
&autocal->pull_down_hs400);
|
||||
if (err)
|
||||
@ -653,7 +657,7 @@ static void tegra_sdhci_parse_pad_autocal_dt(struct sdhci_host *host)
|
||||
if (!(tegra_host->soc_data->nvquirks & NVQUIRK_NEEDS_PAD_CONTROL))
|
||||
return;
|
||||
|
||||
err = device_property_read_u32(host->mmc->parent,
|
||||
err = device_property_read_u32(mmc_dev(host->mmc),
|
||||
"nvidia,pad-autocal-pull-up-offset-3v3-timeout",
|
||||
&autocal->pull_up_3v3_timeout);
|
||||
if (err) {
|
||||
@ -664,7 +668,7 @@ static void tegra_sdhci_parse_pad_autocal_dt(struct sdhci_host *host)
|
||||
autocal->pull_up_3v3_timeout = 0;
|
||||
}
|
||||
|
||||
err = device_property_read_u32(host->mmc->parent,
|
||||
err = device_property_read_u32(mmc_dev(host->mmc),
|
||||
"nvidia,pad-autocal-pull-down-offset-3v3-timeout",
|
||||
&autocal->pull_down_3v3_timeout);
|
||||
if (err) {
|
||||
@ -675,7 +679,7 @@ static void tegra_sdhci_parse_pad_autocal_dt(struct sdhci_host *host)
|
||||
autocal->pull_down_3v3_timeout = 0;
|
||||
}
|
||||
|
||||
err = device_property_read_u32(host->mmc->parent,
|
||||
err = device_property_read_u32(mmc_dev(host->mmc),
|
||||
"nvidia,pad-autocal-pull-up-offset-1v8-timeout",
|
||||
&autocal->pull_up_1v8_timeout);
|
||||
if (err) {
|
||||
@ -686,7 +690,7 @@ static void tegra_sdhci_parse_pad_autocal_dt(struct sdhci_host *host)
|
||||
autocal->pull_up_1v8_timeout = 0;
|
||||
}
|
||||
|
||||
err = device_property_read_u32(host->mmc->parent,
|
||||
err = device_property_read_u32(mmc_dev(host->mmc),
|
||||
"nvidia,pad-autocal-pull-down-offset-1v8-timeout",
|
||||
&autocal->pull_down_1v8_timeout);
|
||||
if (err) {
|
||||
@ -720,17 +724,17 @@ static void tegra_sdhci_parse_tap_and_trim(struct sdhci_host *host)
|
||||
struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
|
||||
int err;
|
||||
|
||||
err = device_property_read_u32(host->mmc->parent, "nvidia,default-tap",
|
||||
err = device_property_read_u32(mmc_dev(host->mmc), "nvidia,default-tap",
|
||||
&tegra_host->default_tap);
|
||||
if (err)
|
||||
tegra_host->default_tap = 0;
|
||||
|
||||
err = device_property_read_u32(host->mmc->parent, "nvidia,default-trim",
|
||||
err = device_property_read_u32(mmc_dev(host->mmc), "nvidia,default-trim",
|
||||
&tegra_host->default_trim);
|
||||
if (err)
|
||||
tegra_host->default_trim = 0;
|
||||
|
||||
err = device_property_read_u32(host->mmc->parent, "nvidia,dqs-trim",
|
||||
err = device_property_read_u32(mmc_dev(host->mmc), "nvidia,dqs-trim",
|
||||
&tegra_host->dqs_trim);
|
||||
if (err)
|
||||
tegra_host->dqs_trim = 0x11;
|
||||
@ -741,7 +745,7 @@ static void tegra_sdhci_parse_dt(struct sdhci_host *host)
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
|
||||
|
||||
if (device_property_read_bool(host->mmc->parent, "supports-cqe"))
|
||||
if (device_property_read_bool(mmc_dev(host->mmc), "supports-cqe"))
|
||||
tegra_host->enable_hwcq = true;
|
||||
else
|
||||
tegra_host->enable_hwcq = false;
|
||||
@ -1156,6 +1160,7 @@ static void tegra_sdhci_voltage_switch(struct sdhci_host *host)
|
||||
static void tegra_cqhci_writel(struct cqhci_host *cq_host, u32 val, int reg)
|
||||
{
|
||||
struct mmc_host *mmc = cq_host->mmc;
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
u8 ctrl;
|
||||
ktime_t timeout;
|
||||
bool timed_out;
|
||||
@ -1170,6 +1175,7 @@ static void tegra_cqhci_writel(struct cqhci_host *cq_host, u32 val, int reg)
|
||||
*/
|
||||
if (reg == CQHCI_CTL && !(val & CQHCI_HALT) &&
|
||||
cqhci_readl(cq_host, CQHCI_CTL) & CQHCI_HALT) {
|
||||
sdhci_writew(host, SDHCI_TEGRA_CQE_TRNS_MODE, SDHCI_TRANSFER_MODE);
|
||||
sdhci_cqe_enable(mmc);
|
||||
writel(val, cq_host->mmio + reg);
|
||||
timeout = ktime_add_us(ktime_get(), 50);
|
||||
@ -1205,6 +1211,7 @@ static void sdhci_tegra_update_dcmd_desc(struct mmc_host *mmc,
|
||||
static void sdhci_tegra_cqe_enable(struct mmc_host *mmc)
|
||||
{
|
||||
struct cqhci_host *cq_host = mmc->cqe_private;
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
@ -1218,6 +1225,7 @@ static void sdhci_tegra_cqe_enable(struct mmc_host *mmc)
|
||||
if (val & CQHCI_ENABLE)
|
||||
cqhci_writel(cq_host, (val & ~CQHCI_ENABLE),
|
||||
CQHCI_CFG);
|
||||
sdhci_writew(host, SDHCI_TEGRA_CQE_TRNS_MODE, SDHCI_TRANSFER_MODE);
|
||||
sdhci_cqe_enable(mmc);
|
||||
if (val & CQHCI_ENABLE)
|
||||
cqhci_writel(cq_host, val, CQHCI_CFG);
|
||||
@ -1281,12 +1289,36 @@ static void tegra_sdhci_set_timeout(struct sdhci_host *host,
|
||||
__sdhci_set_timeout(host, cmd);
|
||||
}
|
||||
|
||||
static void sdhci_tegra_cqe_pre_enable(struct mmc_host *mmc)
|
||||
{
|
||||
struct cqhci_host *cq_host = mmc->cqe_private;
|
||||
u32 reg;
|
||||
|
||||
reg = cqhci_readl(cq_host, CQHCI_CFG);
|
||||
reg |= CQHCI_ENABLE;
|
||||
cqhci_writel(cq_host, reg, CQHCI_CFG);
|
||||
}
|
||||
|
||||
static void sdhci_tegra_cqe_post_disable(struct mmc_host *mmc)
|
||||
{
|
||||
struct cqhci_host *cq_host = mmc->cqe_private;
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
u32 reg;
|
||||
|
||||
reg = cqhci_readl(cq_host, CQHCI_CFG);
|
||||
reg &= ~CQHCI_ENABLE;
|
||||
cqhci_writel(cq_host, reg, CQHCI_CFG);
|
||||
sdhci_writew(host, 0x0, SDHCI_TRANSFER_MODE);
|
||||
}
|
||||
|
||||
static const struct cqhci_host_ops sdhci_tegra_cqhci_ops = {
|
||||
.write_l = tegra_cqhci_writel,
|
||||
.enable = sdhci_tegra_cqe_enable,
|
||||
.disable = sdhci_cqe_disable,
|
||||
.dumpregs = sdhci_tegra_dumpregs,
|
||||
.update_dcmd_desc = sdhci_tegra_update_dcmd_desc,
|
||||
.pre_enable = sdhci_tegra_cqe_pre_enable,
|
||||
.post_disable = sdhci_tegra_cqe_post_disable,
|
||||
};
|
||||
|
||||
static int tegra_sdhci_set_dma_mask(struct sdhci_host *host)
|
||||
@ -1529,7 +1561,7 @@ static int sdhci_tegra_add_host(struct sdhci_host *host)
|
||||
|
||||
host->mmc->caps2 |= MMC_CAP2_CQE | MMC_CAP2_CQE_DCMD;
|
||||
|
||||
cq_host = devm_kzalloc(host->mmc->parent,
|
||||
cq_host = devm_kzalloc(mmc_dev(host->mmc),
|
||||
sizeof(*cq_host), GFP_KERNEL);
|
||||
if (!cq_host) {
|
||||
ret = -ENOMEM;
|
||||
|
@ -188,7 +188,7 @@ static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
|
||||
if (host->bus_on)
|
||||
return;
|
||||
host->bus_on = true;
|
||||
pm_runtime_get_noresume(host->mmc->parent);
|
||||
pm_runtime_get_noresume(mmc_dev(host->mmc));
|
||||
}
|
||||
|
||||
static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
|
||||
@ -196,7 +196,7 @@ static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
|
||||
if (!host->bus_on)
|
||||
return;
|
||||
host->bus_on = false;
|
||||
pm_runtime_put_noidle(host->mmc->parent);
|
||||
pm_runtime_put_noidle(mmc_dev(host->mmc));
|
||||
}
|
||||
|
||||
void sdhci_reset(struct sdhci_host *host, u8 mask)
|
||||
@ -648,7 +648,7 @@ static int sdhci_pre_dma_transfer(struct sdhci_host *host,
|
||||
}
|
||||
}
|
||||
/* Switch ownership to the DMA */
|
||||
dma_sync_single_for_device(host->mmc->parent,
|
||||
dma_sync_single_for_device(mmc_dev(host->mmc),
|
||||
host->bounce_addr,
|
||||
host->bounce_buffer_size,
|
||||
mmc_get_dma_dir(data));
|
||||
@ -907,7 +907,7 @@ static void sdhci_calc_sw_timeout(struct sdhci_host *host,
|
||||
|
||||
if (data) {
|
||||
blksz = data->blksz;
|
||||
freq = host->mmc->actual_clock ? : host->clock;
|
||||
freq = mmc->actual_clock ? : host->clock;
|
||||
transfer_time = (u64)blksz * NSEC_PER_SEC * (8 / bus_width);
|
||||
do_div(transfer_time, freq);
|
||||
/* multiply by '2' to account for any unknowns */
|
||||
@ -1176,7 +1176,7 @@ static int sdhci_external_dma_init(struct sdhci_host *host)
|
||||
int ret = 0;
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
|
||||
host->tx_chan = dma_request_chan(mmc->parent, "tx");
|
||||
host->tx_chan = dma_request_chan(mmc_dev(mmc), "tx");
|
||||
if (IS_ERR(host->tx_chan)) {
|
||||
ret = PTR_ERR(host->tx_chan);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
@ -1185,7 +1185,7 @@ static int sdhci_external_dma_init(struct sdhci_host *host)
|
||||
return ret;
|
||||
}
|
||||
|
||||
host->rx_chan = dma_request_chan(mmc->parent, "rx");
|
||||
host->rx_chan = dma_request_chan(mmc_dev(mmc), "rx");
|
||||
if (IS_ERR(host->rx_chan)) {
|
||||
if (host->tx_chan) {
|
||||
dma_release_channel(host->tx_chan);
|
||||
@ -2269,14 +2269,14 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
|
||||
if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK &&
|
||||
host->clock) {
|
||||
host->timeout_clk = host->mmc->actual_clock ?
|
||||
host->mmc->actual_clock / 1000 :
|
||||
host->timeout_clk = mmc->actual_clock ?
|
||||
mmc->actual_clock / 1000 :
|
||||
host->clock / 1000;
|
||||
host->mmc->max_busy_timeout =
|
||||
mmc->max_busy_timeout =
|
||||
host->ops->get_max_timeout_count ?
|
||||
host->ops->get_max_timeout_count(host) :
|
||||
1 << 27;
|
||||
host->mmc->max_busy_timeout /= host->timeout_clk;
|
||||
mmc->max_busy_timeout /= host->timeout_clk;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2399,7 +2399,7 @@ static int sdhci_get_cd(struct mmc_host *mmc)
|
||||
return 0;
|
||||
|
||||
/* If nonremovable, assume that the card is always present. */
|
||||
if (!mmc_card_is_removable(host->mmc))
|
||||
if (!mmc_card_is_removable(mmc))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
@ -2489,14 +2489,14 @@ void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
|
||||
unsigned long flags;
|
||||
|
||||
if (enable)
|
||||
pm_runtime_get_noresume(host->mmc->parent);
|
||||
pm_runtime_get_noresume(mmc_dev(mmc));
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
sdhci_enable_sdio_irq_nolock(host, enable);
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
|
||||
if (!enable)
|
||||
pm_runtime_put_noidle(host->mmc->parent);
|
||||
pm_runtime_put_noidle(mmc_dev(mmc));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_enable_sdio_irq);
|
||||
|
||||
@ -2837,7 +2837,7 @@ int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
||||
goto out;
|
||||
}
|
||||
|
||||
host->mmc->retune_period = tuning_count;
|
||||
mmc->retune_period = tuning_count;
|
||||
|
||||
if (host->tuning_delay < 0)
|
||||
host->tuning_delay = opcode == MMC_SEND_TUNING_BLOCK;
|
||||
@ -2886,11 +2886,10 @@ static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
|
||||
static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
|
||||
int err)
|
||||
{
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
struct mmc_data *data = mrq->data;
|
||||
|
||||
if (data->host_cookie != COOKIE_UNMAPPED)
|
||||
dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
|
||||
dma_unmap_sg(mmc_dev(mmc), data->sg, data->sg_len,
|
||||
mmc_get_dma_dir(data));
|
||||
|
||||
data->host_cookie = COOKIE_UNMAPPED;
|
||||
@ -2941,9 +2940,9 @@ static void sdhci_card_event(struct mmc_host *mmc)
|
||||
/* Check sdhci_has_requests() first in case we are runtime suspended */
|
||||
if (sdhci_has_requests(host) && !present) {
|
||||
pr_err("%s: Card removed during transfer!\n",
|
||||
mmc_hostname(host->mmc));
|
||||
mmc_hostname(mmc));
|
||||
pr_err("%s: Resetting controller.\n",
|
||||
mmc_hostname(host->mmc));
|
||||
mmc_hostname(mmc));
|
||||
|
||||
sdhci_do_reset(host, SDHCI_RESET_CMD);
|
||||
sdhci_do_reset(host, SDHCI_RESET_DATA);
|
||||
@ -2996,6 +2995,37 @@ static bool sdhci_request_done(struct sdhci_host *host)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* The controller needs a reset of internal state machines
|
||||
* upon error conditions.
|
||||
*/
|
||||
if (sdhci_needs_reset(host, mrq)) {
|
||||
/*
|
||||
* Do not finish until command and data lines are available for
|
||||
* reset. Note there can only be one other mrq, so it cannot
|
||||
* also be in mrqs_done, otherwise host->cmd and host->data_cmd
|
||||
* would both be null.
|
||||
*/
|
||||
if (host->cmd || host->data_cmd) {
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Some controllers need this kick or reset won't work here */
|
||||
if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)
|
||||
/* This is to force an update */
|
||||
host->ops->set_clock(host, host->clock);
|
||||
|
||||
/*
|
||||
* Spec says we should do both at the same time, but Ricoh
|
||||
* controllers do not like that.
|
||||
*/
|
||||
sdhci_do_reset(host, SDHCI_RESET_CMD);
|
||||
sdhci_do_reset(host, SDHCI_RESET_DATA);
|
||||
|
||||
host->pending_reset = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Always unmap the data buffers if they were mapped by
|
||||
* sdhci_prepare_data() whenever we finish with a request.
|
||||
@ -3033,7 +3063,7 @@ static bool sdhci_request_done(struct sdhci_host *host)
|
||||
length = host->bounce_buffer_size;
|
||||
}
|
||||
dma_sync_single_for_cpu(
|
||||
host->mmc->parent,
|
||||
mmc_dev(host->mmc),
|
||||
host->bounce_addr,
|
||||
host->bounce_buffer_size,
|
||||
DMA_FROM_DEVICE);
|
||||
@ -3044,7 +3074,7 @@ static bool sdhci_request_done(struct sdhci_host *host)
|
||||
} else {
|
||||
/* No copying, just switch ownership */
|
||||
dma_sync_single_for_cpu(
|
||||
host->mmc->parent,
|
||||
mmc_dev(host->mmc),
|
||||
host->bounce_addr,
|
||||
host->bounce_buffer_size,
|
||||
mmc_get_dma_dir(data));
|
||||
@ -3059,35 +3089,6 @@ static bool sdhci_request_done(struct sdhci_host *host)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The controller needs a reset of internal state machines
|
||||
* upon error conditions.
|
||||
*/
|
||||
if (sdhci_needs_reset(host, mrq)) {
|
||||
/*
|
||||
* Do not finish until command and data lines are available for
|
||||
* reset. Note there can only be one other mrq, so it cannot
|
||||
* also be in mrqs_done, otherwise host->cmd and host->data_cmd
|
||||
* would both be null.
|
||||
*/
|
||||
if (host->cmd || host->data_cmd) {
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Some controllers need this kick or reset won't work here */
|
||||
if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)
|
||||
/* This is to force an update */
|
||||
host->ops->set_clock(host, host->clock);
|
||||
|
||||
/* Spec says we should do both at the same time, but Ricoh
|
||||
controllers do not like that. */
|
||||
sdhci_do_reset(host, SDHCI_RESET_CMD);
|
||||
sdhci_do_reset(host, SDHCI_RESET_DATA);
|
||||
|
||||
host->pending_reset = false;
|
||||
}
|
||||
|
||||
host->mrqs_done[i] = NULL;
|
||||
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
@ -3675,7 +3676,7 @@ int sdhci_resume_host(struct sdhci_host *host)
|
||||
host->ops->enable_dma(host);
|
||||
}
|
||||
|
||||
if ((host->mmc->pm_flags & MMC_PM_KEEP_POWER) &&
|
||||
if ((mmc->pm_flags & MMC_PM_KEEP_POWER) &&
|
||||
(host->quirks2 & SDHCI_QUIRK2_HOST_OFF_CARD_ON)) {
|
||||
/* Card keeps power but host controller does not */
|
||||
sdhci_init(host, 0);
|
||||
@ -3683,7 +3684,7 @@ int sdhci_resume_host(struct sdhci_host *host)
|
||||
host->clock = 0;
|
||||
mmc->ops->set_ios(mmc, &mmc->ios);
|
||||
} else {
|
||||
sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER));
|
||||
sdhci_init(host, (mmc->pm_flags & MMC_PM_KEEP_POWER));
|
||||
}
|
||||
|
||||
if (host->irq_wake_enabled) {
|
||||
@ -3691,7 +3692,7 @@ int sdhci_resume_host(struct sdhci_host *host)
|
||||
} else {
|
||||
ret = request_threaded_irq(host->irq, sdhci_irq,
|
||||
sdhci_thread_irq, IRQF_SHARED,
|
||||
mmc_hostname(host->mmc), host);
|
||||
mmc_hostname(mmc), host);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -4052,7 +4053,7 @@ static void sdhci_allocate_bounce_buffer(struct sdhci_host *host)
|
||||
* speedups by the help of a bounce buffer to group scattered
|
||||
* reads/writes together.
|
||||
*/
|
||||
host->bounce_buffer = devm_kmalloc(mmc->parent,
|
||||
host->bounce_buffer = devm_kmalloc(mmc_dev(mmc),
|
||||
bounce_size,
|
||||
GFP_KERNEL);
|
||||
if (!host->bounce_buffer) {
|
||||
@ -4066,11 +4067,11 @@ static void sdhci_allocate_bounce_buffer(struct sdhci_host *host)
|
||||
return;
|
||||
}
|
||||
|
||||
host->bounce_addr = dma_map_single(mmc->parent,
|
||||
host->bounce_addr = dma_map_single(mmc_dev(mmc),
|
||||
host->bounce_buffer,
|
||||
bounce_size,
|
||||
DMA_BIDIRECTIONAL);
|
||||
ret = dma_mapping_error(mmc->parent, host->bounce_addr);
|
||||
ret = dma_mapping_error(mmc_dev(mmc), host->bounce_addr);
|
||||
if (ret)
|
||||
/* Again fall back to max_segs == 1 */
|
||||
return;
|
||||
@ -4378,7 +4379,7 @@ int sdhci_setup_host(struct sdhci_host *host)
|
||||
|
||||
if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
|
||||
mmc_card_is_removable(mmc) &&
|
||||
mmc_gpio_get_cd(host->mmc) < 0)
|
||||
mmc_gpio_get_cd(mmc) < 0)
|
||||
mmc->caps |= MMC_CAP_NEEDS_POLL;
|
||||
|
||||
if (!IS_ERR(mmc->supply.vqmmc)) {
|
||||
|
@ -558,7 +558,7 @@ static int sdhci_am654_cqe_add_host(struct sdhci_host *host)
|
||||
struct cqhci_host *cq_host;
|
||||
int ret;
|
||||
|
||||
cq_host = devm_kzalloc(host->mmc->parent, sizeof(struct cqhci_host),
|
||||
cq_host = devm_kzalloc(mmc_dev(host->mmc), sizeof(struct cqhci_host),
|
||||
GFP_KERNEL);
|
||||
if (!cq_host)
|
||||
return -ENOMEM;
|
||||
|
@ -100,8 +100,8 @@
|
||||
|
||||
/* Define some IRQ masks */
|
||||
/* This is the mask used at reset by the chip */
|
||||
#define TMIO_MASK_INIT_RCAR2 0x8b7f031d /* Initial value for R-Car Gen2+ */
|
||||
#define TMIO_MASK_ALL 0x837f031d
|
||||
#define TMIO_MASK_ALL_RCAR2 0x8b7f031d
|
||||
#define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND)
|
||||
#define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND)
|
||||
#define TMIO_MASK_CMD (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT | \
|
||||
@ -164,6 +164,7 @@ struct tmio_mmc_host {
|
||||
u32 sdio_irq_mask;
|
||||
unsigned int clk_cache;
|
||||
u32 sdcard_irq_setbit_mask;
|
||||
u32 sdcard_irq_mask_all;
|
||||
|
||||
spinlock_t lock; /* protect host private data */
|
||||
unsigned long last_req_ts;
|
||||
|
@ -164,6 +164,21 @@ static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
|
||||
}
|
||||
}
|
||||
|
||||
static void tmio_mmc_set_bus_width(struct tmio_mmc_host *host,
|
||||
unsigned char bus_width)
|
||||
{
|
||||
u16 reg = sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT)
|
||||
& ~(CARD_OPT_WIDTH | CARD_OPT_WIDTH8);
|
||||
|
||||
/* reg now applies to MMC_BUS_WIDTH_4 */
|
||||
if (bus_width == MMC_BUS_WIDTH_1)
|
||||
reg |= CARD_OPT_WIDTH;
|
||||
else if (bus_width == MMC_BUS_WIDTH_8)
|
||||
reg |= CARD_OPT_WIDTH8;
|
||||
|
||||
sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, reg);
|
||||
}
|
||||
|
||||
static void tmio_mmc_reset(struct tmio_mmc_host *host)
|
||||
{
|
||||
/* FIXME - should we set stop clock reg here */
|
||||
@ -172,15 +187,23 @@ static void tmio_mmc_reset(struct tmio_mmc_host *host)
|
||||
sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
|
||||
usleep_range(10000, 11000);
|
||||
|
||||
tmio_mmc_abort_dma(host);
|
||||
|
||||
if (host->reset)
|
||||
host->reset(host);
|
||||
|
||||
tmio_mmc_abort_dma(host);
|
||||
sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, host->sdcard_irq_mask_all);
|
||||
host->sdcard_irq_mask = host->sdcard_irq_mask_all;
|
||||
|
||||
tmio_mmc_set_bus_width(host, host->mmc->ios.bus_width);
|
||||
|
||||
if (host->pdata->flags & TMIO_MMC_SDIO_IRQ) {
|
||||
sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
|
||||
sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
|
||||
}
|
||||
|
||||
if (host->mmc->card)
|
||||
mmc_retune_needed(host->mmc);
|
||||
}
|
||||
|
||||
static void tmio_mmc_reset_work(struct work_struct *work)
|
||||
@ -874,21 +897,6 @@ static void tmio_mmc_power_off(struct tmio_mmc_host *host)
|
||||
host->set_pwr(host->pdev, 0);
|
||||
}
|
||||
|
||||
static void tmio_mmc_set_bus_width(struct tmio_mmc_host *host,
|
||||
unsigned char bus_width)
|
||||
{
|
||||
u16 reg = sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT)
|
||||
& ~(CARD_OPT_WIDTH | CARD_OPT_WIDTH8);
|
||||
|
||||
/* reg now applies to MMC_BUS_WIDTH_4 */
|
||||
if (bus_width == MMC_BUS_WIDTH_1)
|
||||
reg |= CARD_OPT_WIDTH;
|
||||
else if (bus_width == MMC_BUS_WIDTH_8)
|
||||
reg |= CARD_OPT_WIDTH8;
|
||||
|
||||
sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, reg);
|
||||
}
|
||||
|
||||
static unsigned int tmio_mmc_get_timeout_cycles(struct tmio_mmc_host *host)
|
||||
{
|
||||
u16 val = sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT);
|
||||
@ -1160,15 +1168,6 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
|
||||
mmc->caps & MMC_CAP_NEEDS_POLL ||
|
||||
!mmc_card_is_removable(mmc));
|
||||
|
||||
/*
|
||||
* On Gen2+, eMMC with NONREMOVABLE currently fails because native
|
||||
* hotplug gets disabled. It seems RuntimePM related yet we need further
|
||||
* research. Since we are planning a PM overhaul anyway, let's enforce
|
||||
* for now the device being active by enabling native hotplug always.
|
||||
*/
|
||||
if (pdata->flags & TMIO_MMC_MIN_RCAR2)
|
||||
_host->native_hotplug = true;
|
||||
|
||||
/*
|
||||
* While using internal tmio hardware logic for card detection, we need
|
||||
* to ensure it stays powered for it to work.
|
||||
@ -1180,12 +1179,12 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
|
||||
if (pdata->flags & TMIO_MMC_SDIO_IRQ)
|
||||
_host->sdio_irq_mask = TMIO_SDIO_MASK_ALL;
|
||||
|
||||
if (!_host->sdcard_irq_mask_all)
|
||||
_host->sdcard_irq_mask_all = TMIO_MASK_ALL;
|
||||
|
||||
_host->set_clock(_host, 0);
|
||||
tmio_mmc_reset(_host);
|
||||
|
||||
_host->sdcard_irq_mask = sd_ctrl_read16_and_16_as_32(_host, CTL_IRQ_MASK);
|
||||
tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL);
|
||||
|
||||
if (_host->native_hotplug)
|
||||
tmio_mmc_enable_mmc_irqs(_host,
|
||||
TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT);
|
||||
@ -1238,7 +1237,7 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
|
||||
cancel_work_sync(&host->done);
|
||||
cancel_delayed_work_sync(&host->delayed_reset_work);
|
||||
tmio_mmc_release_dma(host);
|
||||
tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL);
|
||||
tmio_mmc_disable_mmc_irqs(host, host->sdcard_irq_mask_all);
|
||||
|
||||
if (host->native_hotplug)
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
@ -1268,7 +1267,7 @@ int tmio_mmc_host_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct tmio_mmc_host *host = dev_get_drvdata(dev);
|
||||
|
||||
tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL);
|
||||
tmio_mmc_disable_mmc_irqs(host, host->sdcard_irq_mask_all);
|
||||
|
||||
if (host->clk_cache)
|
||||
host->set_clock(host, 0);
|
||||
@ -1295,8 +1294,6 @@ int tmio_mmc_host_runtime_resume(struct device *dev)
|
||||
|
||||
tmio_mmc_enable_dma(host, true);
|
||||
|
||||
mmc_retune_needed(host->mmc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tmio_mmc_host_runtime_resume);
|
||||
|
@ -635,7 +635,7 @@ static int uniphier_sd_probe(struct platform_device *pdev)
|
||||
|
||||
ret = tmio_mmc_host_probe(host);
|
||||
if (ret)
|
||||
goto free_host;
|
||||
goto disable_clk;
|
||||
|
||||
ret = devm_request_irq(dev, irq, tmio_mmc_irq, IRQF_SHARED,
|
||||
dev_name(dev), host);
|
||||
@ -646,6 +646,8 @@ static int uniphier_sd_probe(struct platform_device *pdev)
|
||||
|
||||
remove_host:
|
||||
tmio_mmc_host_remove(host);
|
||||
disable_clk:
|
||||
uniphier_sd_clk_disable(host);
|
||||
free_host:
|
||||
tmio_mmc_host_free(host);
|
||||
|
||||
@ -658,6 +660,7 @@ static int uniphier_sd_remove(struct platform_device *pdev)
|
||||
|
||||
tmio_mmc_host_remove(host);
|
||||
uniphier_sd_clk_disable(host);
|
||||
tmio_mmc_host_free(host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1271,7 +1271,6 @@ static int __maybe_unused via_sd_suspend(struct device *dev)
|
||||
static int __maybe_unused via_sd_resume(struct device *dev)
|
||||
{
|
||||
struct via_crdr_mmc_host *sdhost;
|
||||
int ret = 0;
|
||||
u8 gatt;
|
||||
|
||||
sdhost = dev_get_drvdata(dev);
|
||||
@ -1292,7 +1291,7 @@ static int __maybe_unused via_sd_resume(struct device *dev)
|
||||
via_restore_pcictrlreg(sdhost);
|
||||
via_init_sdc_pm(sdhost);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(via_sd_pm_ops, via_sd_suspend, via_sd_resume);
|
||||
|
@ -302,9 +302,6 @@ struct mmc_host {
|
||||
u32 ocr_avail_sdio; /* SDIO-specific OCR */
|
||||
u32 ocr_avail_sd; /* SD-specific OCR */
|
||||
u32 ocr_avail_mmc; /* MMC-specific OCR */
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
struct notifier_block pm_notify;
|
||||
#endif
|
||||
struct wakeup_source *ws; /* Enable consume of uevents */
|
||||
u32 max_current_330;
|
||||
u32 max_current_300;
|
||||
@ -423,7 +420,6 @@ struct mmc_host {
|
||||
/* group bitfields together to minimize padding */
|
||||
unsigned int use_spi_crc:1;
|
||||
unsigned int claimed:1; /* host exclusively claimed */
|
||||
unsigned int bus_dead:1; /* bus has been released */
|
||||
unsigned int doing_init_tune:1; /* initial tuning in progress */
|
||||
unsigned int can_retune:1; /* re-tuning can be used */
|
||||
unsigned int doing_retune:1; /* re-tuning in progress */
|
||||
@ -454,7 +450,6 @@ struct mmc_host {
|
||||
struct mmc_slot slot;
|
||||
|
||||
const struct mmc_bus_ops *bus_ops; /* current bus driver */
|
||||
unsigned int bus_refs; /* reference counter */
|
||||
|
||||
unsigned int sdio_irqs;
|
||||
struct task_struct *sdio_irq_thread;
|
||||
@ -514,7 +509,7 @@ void mmc_free_host(struct mmc_host *);
|
||||
void mmc_of_parse_clk_phase(struct mmc_host *host,
|
||||
struct mmc_clk_phase_map *map);
|
||||
int mmc_of_parse(struct mmc_host *host);
|
||||
int mmc_of_parse_voltage(struct device_node *np, u32 *mask);
|
||||
int mmc_of_parse_voltage(struct mmc_host *host, u32 *mask);
|
||||
|
||||
static inline void *mmc_priv(struct mmc_host *host)
|
||||
{
|
||||
|
@ -82,7 +82,7 @@
|
||||
#define SDIO_SD_REV_1_01 0 /* SD Physical Spec Version 1.01 */
|
||||
#define SDIO_SD_REV_1_10 1 /* SD Physical Spec Version 1.10 */
|
||||
#define SDIO_SD_REV_2_00 2 /* SD Physical Spec Version 2.00 */
|
||||
#define SDIO_SD_REV_3_00 3 /* SD Physical Spev Version 3.00 */
|
||||
#define SDIO_SD_REV_3_00 3 /* SD Physical Spec Version 3.00 */
|
||||
|
||||
#define SDIO_CCCR_IOEx 0x02
|
||||
#define SDIO_CCCR_IORx 0x03
|
||||
|
@ -35,16 +35,7 @@ struct mmc_spi_platform_data {
|
||||
void (*setpower)(struct device *, unsigned int maskval);
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
extern struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi);
|
||||
extern void mmc_spi_put_pdata(struct spi_device *spi);
|
||||
#else
|
||||
static inline struct mmc_spi_platform_data *
|
||||
mmc_spi_get_pdata(struct spi_device *spi)
|
||||
{
|
||||
return spi->dev.platform_data;
|
||||
}
|
||||
static inline void mmc_spi_put_pdata(struct spi_device *spi) {}
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
#endif /* __LINUX_SPI_MMC_SPI_H */
|
||||
|
Loading…
Reference in New Issue
Block a user