提交 dee02770 编写于 作者: L Linus Torvalds

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

Pull MMC updates from Ulf Hansson:
 "MMC core:
   - Introduce host claiming by context to support blkmq
   - Preparations for enabling CQE (eMMC CMDQ) requests
   - Re-factorizations to prepare for blkmq support
   - Re-factorizations to prepare for CQE support
   - Fix signal voltage switch for SD cards without power cycle
   - Convert RPMB to a character device
   - Export eMMC revision via sysfs
   - Support eMMC DT binding for fixed driver type
   - Document mmc_regulator_get_supply() API

 MMC host:
   - omap_hsmmc: Updated regulator management for PBIAS
   - sdhci-omap: Add new OMAP SDHCI driver
   - meson-mx-sdio: New driver for the Amlogic Meson8 and Meson8b SoCs
   - sdhci-pci: Add support for Intel CDF
   - sdhci-acpi: Fix voltage switch for some Intel host controllers
   - sdhci-msm: Enable delay circuit calibration clocks
   - sdhci-msm: Manage power IRQ properly
   - mediatek: Add support of mt2701/mt2712
   - mediatek: Updates management of clocks and tunings
   - mediatek: Upgrade eMMC HS400 support
   - rtsx_pci: Update tuning for gen3 PCI-Express
   - renesas_sdhi: Support R-Car Gen[123] fallback compatibility strings
   - Catch all errors when getting regulators
   - Various additional improvements and cleanups"

* tag 'mmc-v4.15' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (91 commits)
  sdhci-fujitsu: add support for setting the CMD_DAT_DELAY attribute
  dt-bindings: sdhci-fujitsu: document cmd-dat-delay property
  mmc: tmio: Replace msleep() of 20ms or less with usleep_range()
  mmc: dw_mmc: Convert timers to use timer_setup()
  mmc: dw_mmc: Cleanup the DTO timer like the CTO one
  mmc: vub300: Use common code in __download_offload_pseudocode()
  mmc: tmio: Use common error handling code in tmio_mmc_host_probe()
  mmc: Convert timers to use timer_setup()
  mmc: sdhci-acpi: Fix voltage switch for some Intel host controllers
  mmc: sdhci-acpi: Let devices define their own private data
  mmc: mediatek: perfer to use rise edge latching for cmd line
  mmc: mediatek: improve eMMC hs400 mode read performance
  mmc: mediatek: add latch-ck support
  mmc: mediatek: add support of source_cg clock
  mmc: mediatek: add stop_clk fix and enhance_rx support
  mmc: mediatek: add busy_check support
  mmc: mediatek: add async fifo and data tune support
  mmc: mediatek: add pad_tune0 support
  mmc: mediatek: make hs400_tune_response only for mt8173
  arm64: dts: mt8173: remove "mediatek, mt8135-mmc" from mmc nodes
  ...
What: /sys/bus/mmc/devices/.../rev
Date: October 2017
Contact: Jin Qian <jinqian@android.com>
Description: Extended CSD revision number
* Amlogic Meson6, Meson8 and Meson8b SDIO/MMC controller
The highspeed MMC host controller on Amlogic SoCs provides an interface
for MMC, SD, SDIO and SDHC types of memory cards.
Supported maximum speeds are the ones of the eMMC standard 4.41 as well
as the speed of SD standard 2.0.
The hardware provides an internal "mux" which allows up to three slots
to be controlled. Only one slot can be accessed at a time.
Required properties:
- compatible : must be one of
- "amlogic,meson8-sdio"
- "amlogic,meson8b-sdio"
along with the generic "amlogic,meson-mx-sdio"
- reg : mmc controller base registers
- interrupts : mmc controller interrupt
- #address-cells : must be 1
- size-cells : must be 0
- clocks : phandle to clock providers
- clock-names : must contain "core" and "clkin"
Required child nodes:
A node for each slot provided by the MMC controller is required.
NOTE: due to a driver limitation currently only one slot (= child node)
is supported!
Required properties on each child node (= slot):
- compatible : must be "mmc-slot" (see mmc.txt within this directory)
- reg : the slot (or "port") ID
Optional properties on each child node (= slot):
- bus-width : must be 1 or 4 (8-bit bus is not supported)
- for cd and all other additional generic mmc parameters
please refer to mmc.txt within this directory
Examples:
mmc@c1108c20 {
compatible = "amlogic,meson8-sdio", "amlogic,meson-mx-sdio";
reg = <0xc1108c20 0x20>;
interrupts = <0 28 1>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&clkc CLKID_SDIO>, <&clkc CLKID_CLK81>;
clock-names = "core", "clkin";
slot@1 {
compatible = "mmc-slot";
reg = <1>;
bus-width = <4>;
};
};
...@@ -53,6 +53,9 @@ Optional properties: ...@@ -53,6 +53,9 @@ Optional properties:
- no-sdio: controller is limited to send sdio cmd during initialization - no-sdio: controller is limited to send sdio cmd during initialization
- no-sd: controller is limited to send sd cmd during initialization - no-sd: controller is limited to send sd cmd during initialization
- no-mmc: controller is limited to send mmc cmd during initialization - no-mmc: controller is limited to send mmc cmd during initialization
- fixed-emmc-driver-type: for non-removable eMMC, enforce this driver type.
The value <n> is the driver type as specified in the eMMC specification
(table 206 in spec version 5.1).
*NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
polarity properties, we have to fix the meaning of the "normal" and "inverted" polarity properties, we have to fix the meaning of the "normal" and "inverted"
......
...@@ -7,10 +7,18 @@ This file documents differences between the core properties in mmc.txt ...@@ -7,10 +7,18 @@ This file documents differences between the core properties in mmc.txt
and the properties used by the msdc driver. and the properties used by the msdc driver.
Required properties: Required properties:
- compatible: Should be "mediatek,mt8173-mmc","mediatek,mt8135-mmc" - compatible: value should be either of the following.
"mediatek,mt8135-mmc": for mmc host ip compatible with mt8135
"mediatek,mt8173-mmc": for mmc host ip compatible with mt8173
"mediatek,mt2701-mmc": for mmc host ip compatible with mt2701
"mediatek,mt2712-mmc": for mmc host ip compatible with mt2712
- reg: physical base address of the controller and length
- interrupts: Should contain MSDC interrupt number - interrupts: Should contain MSDC interrupt number
- clocks: MSDC source clock, HCLK - clocks: Should contain phandle for the clock feeding the MMC controller
- clock-names: "source", "hclk" - clock-names: Should contain the following:
"source" - source clock (required)
"hclk" - HCLK which used for host (required)
"source_cg" - independent source clock gate (required for MT2712)
- pinctrl-names: should be "default", "state_uhs" - pinctrl-names: should be "default", "state_uhs"
- pinctrl-0: should contain default/high speed pin ctrl - pinctrl-0: should contain default/high speed pin ctrl
- pinctrl-1: should contain uhs mode pin ctrl - pinctrl-1: should contain uhs mode pin ctrl
...@@ -30,6 +38,10 @@ Optional properties: ...@@ -30,6 +38,10 @@ Optional properties:
- mediatek,hs400-cmd-resp-sel-rising: HS400 command response sample selection - mediatek,hs400-cmd-resp-sel-rising: HS400 command response sample selection
If present,HS400 command responses are sampled on rising edges. If present,HS400 command responses are sampled on rising edges.
If not present,HS400 command responses are sampled on falling edges. If not present,HS400 command responses are sampled on falling edges.
- mediatek,latch-ck: Some SoCs do not support enhance_rx, need set correct latch-ck to avoid data crc
error caused by stop clock(fifo full)
Valid range = [0:0x7]. if not present, default value is 0.
applied to compatible "mediatek,mt2701-mmc".
Examples: Examples:
mmc0: mmc@11230000 { mmc0: mmc@11230000 {
......
...@@ -15,6 +15,8 @@ Required properties: ...@@ -15,6 +15,8 @@ Required properties:
Optional properties: Optional properties:
- vqmmc-supply: phandle to the regulator device tree node, mentioned - vqmmc-supply: phandle to the regulator device tree node, mentioned
as the VCCQ/VDD_IO supply in the eMMC/SD specs. as the VCCQ/VDD_IO supply in the eMMC/SD specs.
- fujitsu,cmd-dat-delay-select: boolean property indicating that this host
requires the CMD_DAT_DELAY control to be enabled.
Example: Example:
......
...@@ -18,6 +18,8 @@ Required properties: ...@@ -18,6 +18,8 @@ Required properties:
"core" - SDC MMC clock (MCLK) (required) "core" - SDC MMC clock (MCLK) (required)
"bus" - SDCC bus voter clock (optional) "bus" - SDCC bus voter clock (optional)
"xo" - TCXO clock (optional) "xo" - TCXO clock (optional)
"cal" - reference clock for RCLK delay calibration (optional)
"sleep" - sleep clock for RCLK delay calibration (optional)
Example: Example:
......
* TI OMAP SDHCI Controller
Refer to mmc.txt for standard MMC bindings.
Required properties:
- compatible: Should be "ti,dra7-sdhci" for DRA7 and DRA72 controllers
- ti,hwmods: Must be "mmc<n>", <n> is controller instance starting 1
Example:
mmc1: mmc@4809c000 {
compatible = "ti,dra7-sdhci";
reg = <0x4809c000 0x400>;
ti,hwmods = "mmc1";
bus-width = <4>;
vmmc-supply = <&vmmc>; /* phandle to regulator node */
};
...@@ -10,7 +10,7 @@ described in mmc.txt, can be used. Additionally the following tmio_mmc-specific ...@@ -10,7 +10,7 @@ described in mmc.txt, can be used. Additionally the following tmio_mmc-specific
optional bindings can be used. optional bindings can be used.
Required properties: Required properties:
- compatible: "renesas,sdhi-shmobile" - a generic sh-mobile SDHI unit - compatible: should contain one or more of the following:
"renesas,sdhi-sh73a0" - SDHI IP on SH73A0 SoC "renesas,sdhi-sh73a0" - SDHI IP on SH73A0 SoC
"renesas,sdhi-r7s72100" - SDHI IP on R7S72100 SoC "renesas,sdhi-r7s72100" - SDHI IP on R7S72100 SoC
"renesas,sdhi-r8a73a4" - SDHI IP on R8A73A4 SoC "renesas,sdhi-r8a73a4" - SDHI IP on R8A73A4 SoC
...@@ -26,6 +26,16 @@ Required properties: ...@@ -26,6 +26,16 @@ Required properties:
"renesas,sdhi-r8a7794" - SDHI IP on R8A7794 SoC "renesas,sdhi-r8a7794" - SDHI IP on R8A7794 SoC
"renesas,sdhi-r8a7795" - SDHI IP on R8A7795 SoC "renesas,sdhi-r8a7795" - SDHI IP on R8A7795 SoC
"renesas,sdhi-r8a7796" - SDHI IP on R8A7796 SoC "renesas,sdhi-r8a7796" - SDHI IP on R8A7796 SoC
"renesas,sdhi-shmobile" - a generic sh-mobile SDHI controller
"renesas,rcar-gen1-sdhi" - a generic R-Car Gen1 SDHI controller
"renesas,rcar-gen2-sdhi" - a generic R-Car Gen2 or RZ/G1
SDHI controller
"renesas,rcar-gen3-sdhi" - a generic R-Car Gen3 SDHI controller
When compatible with the generic version, nodes must list
the SoC-specific version corresponding to the platform
first followed by the generic version.
- clocks: Most controllers only have 1 clock source per channel. However, on - clocks: Most controllers only have 1 clock source per channel. However, on
some variations of this controller, the internal card detection some variations of this controller, the internal card detection
...@@ -43,3 +53,61 @@ Optional properties: ...@@ -43,3 +53,61 @@ Optional properties:
- pinctrl-names: should be "default", "state_uhs" - pinctrl-names: should be "default", "state_uhs"
- pinctrl-0: should contain default/high speed pin ctrl - pinctrl-0: should contain default/high speed pin ctrl
- pinctrl-1: should contain uhs mode pin ctrl - pinctrl-1: should contain uhs mode pin ctrl
Example: R8A7790 (R-Car H2) SDHI controller nodes
sdhi0: sd@ee100000 {
compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
reg = <0 0xee100000 0 0x328>;
interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 314>;
dmas = <&dmac0 0xcd>, <&dmac0 0xce>,
<&dmac1 0xcd>, <&dmac1 0xce>;
dma-names = "tx", "rx", "tx", "rx";
max-frequency = <195000000>;
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
resets = <&cpg 314>;
status = "disabled";
};
sdhi1: sd@ee120000 {
compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
reg = <0 0xee120000 0 0x328>;
interrupts = <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 313>;
dmas = <&dmac0 0xc9>, <&dmac0 0xca>,
<&dmac1 0xc9>, <&dmac1 0xca>;
dma-names = "tx", "rx", "tx", "rx";
max-frequency = <195000000>;
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
resets = <&cpg 313>;
status = "disabled";
};
sdhi2: sd@ee140000 {
compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
reg = <0 0xee140000 0 0x100>;
interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 312>;
dmas = <&dmac0 0xc1>, <&dmac0 0xc2>,
<&dmac1 0xc1>, <&dmac1 0xc2>;
dma-names = "tx", "rx", "tx", "rx";
max-frequency = <97500000>;
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
resets = <&cpg 312>;
status = "disabled";
};
sdhi3: sd@ee160000 {
compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
reg = <0 0xee160000 0 0x100>;
interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 311>;
dmas = <&dmac0 0xd3>, <&dmac0 0xd4>,
<&dmac1 0xd3>, <&dmac1 0xd4>;
dma-names = "tx", "rx", "tx", "rx";
max-frequency = <97500000>;
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
resets = <&cpg 311>;
status = "disabled";
};
...@@ -12067,6 +12067,12 @@ L: linux-mmc@vger.kernel.org ...@@ -12067,6 +12067,12 @@ L: linux-mmc@vger.kernel.org
S: Maintained S: Maintained
F: drivers/mmc/host/sdhci-spear.c F: drivers/mmc/host/sdhci-spear.c
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) TI OMAP DRIVER
M: Kishon Vijay Abraham I <kishon@ti.com>
L: linux-mmc@vger.kernel.org
S: Maintained
F: drivers/mmc/host/sdhci-omap.c
SECURE ENCRYPTING DEVICE (SED) OPAL DRIVER SECURE ENCRYPTING DEVICE (SED) OPAL DRIVER
M: Scott Bauer <scott.bauer@intel.com> M: Scott Bauer <scott.bauer@intel.com>
M: Jonathan Derrick <jonathan.derrick@intel.com> M: Jonathan Derrick <jonathan.derrick@intel.com>
......
...@@ -682,8 +682,7 @@ ...@@ -682,8 +682,7 @@
}; };
mmc0: mmc@11230000 { mmc0: mmc@11230000 {
compatible = "mediatek,mt8173-mmc", compatible = "mediatek,mt8173-mmc";
"mediatek,mt8135-mmc";
reg = <0 0x11230000 0 0x1000>; reg = <0 0x11230000 0 0x1000>;
interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_LOW>; interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_LOW>;
clocks = <&pericfg CLK_PERI_MSDC30_0>, clocks = <&pericfg CLK_PERI_MSDC30_0>,
...@@ -693,8 +692,7 @@ ...@@ -693,8 +692,7 @@
}; };
mmc1: mmc@11240000 { mmc1: mmc@11240000 {
compatible = "mediatek,mt8173-mmc", compatible = "mediatek,mt8173-mmc";
"mediatek,mt8135-mmc";
reg = <0 0x11240000 0 0x1000>; reg = <0 0x11240000 0 0x1000>;
interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_LOW>; interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_LOW>;
clocks = <&pericfg CLK_PERI_MSDC30_1>, clocks = <&pericfg CLK_PERI_MSDC30_1>,
...@@ -704,8 +702,7 @@ ...@@ -704,8 +702,7 @@
}; };
mmc2: mmc@11250000 { mmc2: mmc@11250000 {
compatible = "mediatek,mt8173-mmc", compatible = "mediatek,mt8173-mmc";
"mediatek,mt8135-mmc";
reg = <0 0x11250000 0 0x1000>; reg = <0 0x11250000 0 0x1000>;
interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_LOW>; interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_LOW>;
clocks = <&pericfg CLK_PERI_MSDC30_2>, clocks = <&pericfg CLK_PERI_MSDC30_2>,
...@@ -715,8 +712,7 @@ ...@@ -715,8 +712,7 @@
}; };
mmc3: mmc@11260000 { mmc3: mmc@11260000 {
compatible = "mediatek,mt8173-mmc", compatible = "mediatek,mt8173-mmc";
"mediatek,mt8135-mmc";
reg = <0 0x11260000 0 0x1000>; reg = <0 0x11260000 0 0x1000>;
interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_LOW>; interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_LOW>;
clocks = <&pericfg CLK_PERI_MSDC30_3>, clocks = <&pericfg CLK_PERI_MSDC30_3>,
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/hdreg.h> #include <linux/hdreg.h>
#include <linux/kdev_t.h> #include <linux/kdev_t.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/cdev.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/string_helpers.h> #include <linux/string_helpers.h>
...@@ -86,6 +87,7 @@ static int max_devices; ...@@ -86,6 +87,7 @@ static int max_devices;
#define MAX_DEVICES 256 #define MAX_DEVICES 256
static DEFINE_IDA(mmc_blk_ida); static DEFINE_IDA(mmc_blk_ida);
static DEFINE_IDA(mmc_rpmb_ida);
/* /*
* There is one mmc_blk_data per slot. * There is one mmc_blk_data per slot.
...@@ -96,6 +98,7 @@ struct mmc_blk_data { ...@@ -96,6 +98,7 @@ struct mmc_blk_data {
struct gendisk *disk; struct gendisk *disk;
struct mmc_queue queue; struct mmc_queue queue;
struct list_head part; struct list_head part;
struct list_head rpmbs;
unsigned int flags; unsigned int flags;
#define MMC_BLK_CMD23 (1 << 0) /* Can do SET_BLOCK_COUNT for multiblock */ #define MMC_BLK_CMD23 (1 << 0) /* Can do SET_BLOCK_COUNT for multiblock */
...@@ -121,6 +124,32 @@ struct mmc_blk_data { ...@@ -121,6 +124,32 @@ struct mmc_blk_data {
int area_type; int area_type;
}; };
/* Device type for RPMB character devices */
static dev_t mmc_rpmb_devt;
/* Bus type for RPMB character devices */
static struct bus_type mmc_rpmb_bus_type = {
.name = "mmc_rpmb",
};
/**
* struct mmc_rpmb_data - special RPMB device type for these areas
* @dev: the device for the RPMB area
* @chrdev: character device for the RPMB area
* @id: unique device ID number
* @part_index: partition index (0 on first)
* @md: parent MMC block device
* @node: list item, so we can put this device on a list
*/
struct mmc_rpmb_data {
struct device dev;
struct cdev chrdev;
int id;
unsigned int part_index;
struct mmc_blk_data *md;
struct list_head node;
};
static DEFINE_MUTEX(open_lock); static DEFINE_MUTEX(open_lock);
module_param(perdev_minors, int, 0444); module_param(perdev_minors, int, 0444);
...@@ -299,6 +328,7 @@ struct mmc_blk_ioc_data { ...@@ -299,6 +328,7 @@ struct mmc_blk_ioc_data {
struct mmc_ioc_cmd ic; struct mmc_ioc_cmd ic;
unsigned char *buf; unsigned char *buf;
u64 buf_bytes; u64 buf_bytes;
struct mmc_rpmb_data *rpmb;
}; };
static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user( static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
...@@ -437,14 +467,25 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, ...@@ -437,14 +467,25 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
struct mmc_request mrq = {}; struct mmc_request mrq = {};
struct scatterlist sg; struct scatterlist sg;
int err; int err;
bool is_rpmb = false; unsigned int target_part;
u32 status = 0; u32 status = 0;
if (!card || !md || !idata) if (!card || !md || !idata)
return -EINVAL; return -EINVAL;
if (md->area_type & MMC_BLK_DATA_AREA_RPMB) /*
is_rpmb = true; * The RPMB accesses comes in from the character device, so we
* need to target these explicitly. Else we just target the
* partition type for the block device the ioctl() was issued
* on.
*/
if (idata->rpmb) {
/* Support multiple RPMB partitions */
target_part = idata->rpmb->part_index;
target_part |= EXT_CSD_PART_CONFIG_ACC_RPMB;
} else {
target_part = md->part_type;
}
cmd.opcode = idata->ic.opcode; cmd.opcode = idata->ic.opcode;
cmd.arg = idata->ic.arg; cmd.arg = idata->ic.arg;
...@@ -488,7 +529,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, ...@@ -488,7 +529,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
mrq.cmd = &cmd; mrq.cmd = &cmd;
err = mmc_blk_part_switch(card, md->part_type); err = mmc_blk_part_switch(card, target_part);
if (err) if (err)
return err; return err;
...@@ -498,7 +539,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, ...@@ -498,7 +539,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
return err; return err;
} }
if (is_rpmb) { if (idata->rpmb) {
err = mmc_set_blockcount(card, data.blocks, err = mmc_set_blockcount(card, data.blocks,
idata->ic.write_flag & (1 << 31)); idata->ic.write_flag & (1 << 31));
if (err) if (err)
...@@ -538,7 +579,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, ...@@ -538,7 +579,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
memcpy(&(idata->ic.response), cmd.resp, sizeof(cmd.resp)); memcpy(&(idata->ic.response), cmd.resp, sizeof(cmd.resp));
if (is_rpmb) { if (idata->rpmb) {
/* /*
* Ensure RPMB command has completed by polling CMD13 * Ensure RPMB command has completed by polling CMD13
* "Send Status". * "Send Status".
...@@ -554,7 +595,8 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, ...@@ -554,7 +595,8 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
} }
static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md, static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md,
struct mmc_ioc_cmd __user *ic_ptr) struct mmc_ioc_cmd __user *ic_ptr,
struct mmc_rpmb_data *rpmb)
{ {
struct mmc_blk_ioc_data *idata; struct mmc_blk_ioc_data *idata;
struct mmc_blk_ioc_data *idatas[1]; struct mmc_blk_ioc_data *idatas[1];
...@@ -566,6 +608,8 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md, ...@@ -566,6 +608,8 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md,
idata = mmc_blk_ioctl_copy_from_user(ic_ptr); idata = mmc_blk_ioctl_copy_from_user(ic_ptr);
if (IS_ERR(idata)) if (IS_ERR(idata))
return PTR_ERR(idata); return PTR_ERR(idata);
/* This will be NULL on non-RPMB ioctl():s */
idata->rpmb = rpmb;
card = md->queue.card; card = md->queue.card;
if (IS_ERR(card)) { if (IS_ERR(card)) {
...@@ -581,7 +625,8 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md, ...@@ -581,7 +625,8 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md,
idata->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, idata->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN,
__GFP_RECLAIM); __GFP_RECLAIM);
idatas[0] = idata; idatas[0] = idata;
req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL; req_to_mmc_queue_req(req)->drv_op =
rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL;
req_to_mmc_queue_req(req)->drv_op_data = idatas; req_to_mmc_queue_req(req)->drv_op_data = idatas;
req_to_mmc_queue_req(req)->ioc_count = 1; req_to_mmc_queue_req(req)->ioc_count = 1;
blk_execute_rq(mq->queue, NULL, req, 0); blk_execute_rq(mq->queue, NULL, req, 0);
...@@ -596,7 +641,8 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md, ...@@ -596,7 +641,8 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md,
} }
static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md, static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md,
struct mmc_ioc_multi_cmd __user *user) struct mmc_ioc_multi_cmd __user *user,
struct mmc_rpmb_data *rpmb)
{ {
struct mmc_blk_ioc_data **idata = NULL; struct mmc_blk_ioc_data **idata = NULL;
struct mmc_ioc_cmd __user *cmds = user->cmds; struct mmc_ioc_cmd __user *cmds = user->cmds;
...@@ -627,6 +673,8 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md, ...@@ -627,6 +673,8 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md,
num_of_cmds = i; num_of_cmds = i;
goto cmd_err; goto cmd_err;
} }
/* This will be NULL on non-RPMB ioctl():s */
idata[i]->rpmb = rpmb;
} }
card = md->queue.card; card = md->queue.card;
...@@ -643,7 +691,8 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md, ...@@ -643,7 +691,8 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md,
req = blk_get_request(mq->queue, req = blk_get_request(mq->queue,
idata[0]->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, idata[0]->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN,
__GFP_RECLAIM); __GFP_RECLAIM);
req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL; req_to_mmc_queue_req(req)->drv_op =
rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL;
req_to_mmc_queue_req(req)->drv_op_data = idata; req_to_mmc_queue_req(req)->drv_op_data = idata;
req_to_mmc_queue_req(req)->ioc_count = num_of_cmds; req_to_mmc_queue_req(req)->ioc_count = num_of_cmds;
blk_execute_rq(mq->queue, NULL, req, 0); blk_execute_rq(mq->queue, NULL, req, 0);
...@@ -691,7 +740,8 @@ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode, ...@@ -691,7 +740,8 @@ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
if (!md) if (!md)
return -EINVAL; return -EINVAL;
ret = mmc_blk_ioctl_cmd(md, ret = mmc_blk_ioctl_cmd(md,
(struct mmc_ioc_cmd __user *)arg); (struct mmc_ioc_cmd __user *)arg,
NULL);
mmc_blk_put(md); mmc_blk_put(md);
return ret; return ret;
case MMC_IOC_MULTI_CMD: case MMC_IOC_MULTI_CMD:
...@@ -702,7 +752,8 @@ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode, ...@@ -702,7 +752,8 @@ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
if (!md) if (!md)
return -EINVAL; return -EINVAL;
ret = mmc_blk_ioctl_multi_cmd(md, ret = mmc_blk_ioctl_multi_cmd(md,
(struct mmc_ioc_multi_cmd __user *)arg); (struct mmc_ioc_multi_cmd __user *)arg,
NULL);
mmc_blk_put(md); mmc_blk_put(md);
return ret; return ret;
default: default:
...@@ -1152,18 +1203,6 @@ static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type) ...@@ -1152,18 +1203,6 @@ static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type)
md->reset_done &= ~type; md->reset_done &= ~type;
} }
int mmc_access_rpmb(struct mmc_queue *mq)
{
struct mmc_blk_data *md = mq->blkdata;
/*
* If this is a RPMB partition access, return ture
*/
if (md && md->part_type == EXT_CSD_PART_CONFIG_ACC_RPMB)
return true;
return false;
}
/* /*
* The non-block commands come back from the block layer after it queued it and * The non-block commands come back from the block layer after it queued it and
* processed it with all other requests and then they get issued in this * processed it with all other requests and then they get issued in this
...@@ -1174,17 +1213,19 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req) ...@@ -1174,17 +1213,19 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
struct mmc_queue_req *mq_rq; struct mmc_queue_req *mq_rq;
struct mmc_card *card = mq->card; struct mmc_card *card = mq->card;
struct mmc_blk_data *md = mq->blkdata; struct mmc_blk_data *md = mq->blkdata;
struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev);
struct mmc_blk_ioc_data **idata; struct mmc_blk_ioc_data **idata;
bool rpmb_ioctl;
u8 **ext_csd; u8 **ext_csd;
u32 status; u32 status;
int ret; int ret;
int i; int i;
mq_rq = req_to_mmc_queue_req(req); mq_rq = req_to_mmc_queue_req(req);
rpmb_ioctl = (mq_rq->drv_op == MMC_DRV_OP_IOCTL_RPMB);
switch (mq_rq->drv_op) { switch (mq_rq->drv_op) {
case MMC_DRV_OP_IOCTL: case MMC_DRV_OP_IOCTL:
case MMC_DRV_OP_IOCTL_RPMB:
idata = mq_rq->drv_op_data; idata = mq_rq->drv_op_data;
for (i = 0, ret = 0; i < mq_rq->ioc_count; i++) { for (i = 0, ret = 0; i < mq_rq->ioc_count; i++) {
ret = __mmc_blk_ioctl_cmd(card, md, idata[i]); ret = __mmc_blk_ioctl_cmd(card, md, idata[i]);
...@@ -1192,8 +1233,8 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req) ...@@ -1192,8 +1233,8 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
break; break;
} }
/* Always switch back to main area after RPMB access */ /* Always switch back to main area after RPMB access */
if (md->area_type & MMC_BLK_DATA_AREA_RPMB) if (rpmb_ioctl)
mmc_blk_part_switch(card, main_md->part_type); mmc_blk_part_switch(card, 0);
break; break;
case MMC_DRV_OP_BOOT_WP: case MMC_DRV_OP_BOOT_WP:
ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
...@@ -1534,25 +1575,27 @@ static enum mmc_blk_status mmc_blk_err_check(struct mmc_card *card, ...@@ -1534,25 +1575,27 @@ static enum mmc_blk_status mmc_blk_err_check(struct mmc_card *card,
} }
static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq, static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
int disable_multi, bool *do_rel_wr, int disable_multi, bool *do_rel_wr_p,
bool *do_data_tag) bool *do_data_tag_p)
{ {
struct mmc_blk_data *md = mq->blkdata; struct mmc_blk_data *md = mq->blkdata;
struct mmc_card *card = md->queue.card; struct mmc_card *card = md->queue.card;
struct mmc_blk_request *brq = &mqrq->brq; struct mmc_blk_request *brq = &mqrq->brq;
struct request *req = mmc_queue_req_to_req(mqrq); struct request *req = mmc_queue_req_to_req(mqrq);
bool do_rel_wr, do_data_tag;
/* /*
* Reliable writes are used to implement Forced Unit Access and * Reliable writes are used to implement Forced Unit Access and
* are supported only on MMCs. * are supported only on MMCs.
*/ */
*do_rel_wr = (req->cmd_flags & REQ_FUA) && do_rel_wr = (req->cmd_flags & REQ_FUA) &&
rq_data_dir(req) == WRITE && rq_data_dir(req) == WRITE &&
(md->flags & MMC_BLK_REL_WR); (md->flags & MMC_BLK_REL_WR);
memset(brq, 0, sizeof(struct mmc_blk_request)); memset(brq, 0, sizeof(struct mmc_blk_request));
brq->mrq.data = &brq->data; brq->mrq.data = &brq->data;
brq->mrq.tag = req->tag;
brq->stop.opcode = MMC_STOP_TRANSMISSION; brq->stop.opcode = MMC_STOP_TRANSMISSION;
brq->stop.arg = 0; brq->stop.arg = 0;
...@@ -1567,6 +1610,14 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq, ...@@ -1567,6 +1610,14 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
brq->data.blksz = 512; brq->data.blksz = 512;
brq->data.blocks = blk_rq_sectors(req); brq->data.blocks = blk_rq_sectors(req);
brq->data.blk_addr = blk_rq_pos(req);
/*
* The command queue supports 2 priorities: "high" (1) and "simple" (0).
* The eMMC will give "high" priority tasks priority over "simple"
* priority tasks. Here we always set "simple" priority by not setting
* MMC_DATA_PRIO.
*/
/* /*
* The block layer doesn't support all sector count * The block layer doesn't support all sector count
...@@ -1596,18 +1647,23 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq, ...@@ -1596,18 +1647,23 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
brq->data.blocks); brq->data.blocks);
} }
if (*do_rel_wr) if (do_rel_wr) {
mmc_apply_rel_rw(brq, card, req); mmc_apply_rel_rw(brq, card, req);
brq->data.flags |= MMC_DATA_REL_WR;
}
/* /*
* Data tag is used only during writing meta data to speed * Data tag is used only during writing meta data to speed
* up write and any subsequent read of this meta data * up write and any subsequent read of this meta data
*/ */
*do_data_tag = card->ext_csd.data_tag_unit_size && do_data_tag = card->ext_csd.data_tag_unit_size &&
(req->cmd_flags & REQ_META) && (req->cmd_flags & REQ_META) &&
(rq_data_dir(req) == WRITE) && (rq_data_dir(req) == WRITE) &&
((brq->data.blocks * brq->data.blksz) >= ((brq->data.blocks * brq->data.blksz) >=
card->ext_csd.data_tag_unit_size); card->ext_csd.data_tag_unit_size);
if (do_data_tag)
brq->data.flags |= MMC_DATA_DAT_TAG;
mmc_set_data_timeout(&brq->data, card); mmc_set_data_timeout(&brq->data, card);
...@@ -1634,6 +1690,12 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq, ...@@ -1634,6 +1690,12 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
} }
mqrq->areq.mrq = &brq->mrq; mqrq->areq.mrq = &brq->mrq;
if (do_rel_wr_p)
*do_rel_wr_p = do_rel_wr;
if (do_data_tag_p)
*do_data_tag_p = do_data_tag;
} }
static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
...@@ -1948,7 +2010,7 @@ void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) ...@@ -1948,7 +2010,7 @@ void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
if (req && !mq->qcnt) if (req && !mq->qcnt)
/* claim host only for the first request */ /* claim host only for the first request */
mmc_get_card(card); mmc_get_card(card, NULL);
ret = mmc_blk_part_switch(card, md->part_type); ret = mmc_blk_part_switch(card, md->part_type);
if (ret) { if (ret) {
...@@ -2011,7 +2073,7 @@ void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) ...@@ -2011,7 +2073,7 @@ void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
out: out:
if (!mq->qcnt) if (!mq->qcnt)
mmc_put_card(card); mmc_put_card(card, NULL);
} }
static inline int mmc_blk_readonly(struct mmc_card *card) static inline int mmc_blk_readonly(struct mmc_card *card)
...@@ -2068,6 +2130,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, ...@@ -2068,6 +2130,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
spin_lock_init(&md->lock); spin_lock_init(&md->lock);
INIT_LIST_HEAD(&md->part); INIT_LIST_HEAD(&md->part);
INIT_LIST_HEAD(&md->rpmbs);
md->usage = 1; md->usage = 1;
ret = mmc_init_queue(&md->queue, card, &md->lock, subname); ret = mmc_init_queue(&md->queue, card, &md->lock, subname);
...@@ -2186,6 +2249,158 @@ static int mmc_blk_alloc_part(struct mmc_card *card, ...@@ -2186,6 +2249,158 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
return 0; return 0;
} }
/**
* mmc_rpmb_ioctl() - ioctl handler for the RPMB chardev
* @filp: the character device file
* @cmd: the ioctl() command
* @arg: the argument from userspace
*
* This will essentially just redirect the ioctl()s coming in over to
* the main block device spawning the RPMB character device.
*/
static long mmc_rpmb_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
struct mmc_rpmb_data *rpmb = filp->private_data;
int ret;
switch (cmd) {
case MMC_IOC_CMD:
ret = mmc_blk_ioctl_cmd(rpmb->md,
(struct mmc_ioc_cmd __user *)arg,
rpmb);
break;
case MMC_IOC_MULTI_CMD:
ret = mmc_blk_ioctl_multi_cmd(rpmb->md,
(struct mmc_ioc_multi_cmd __user *)arg,
rpmb);
break;
default:
ret = -EINVAL;
break;
}
return 0;
}
#ifdef CONFIG_COMPAT
static long mmc_rpmb_ioctl_compat(struct file *filp, unsigned int cmd,
unsigned long arg)
{
return mmc_rpmb_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
}
#endif
static int mmc_rpmb_chrdev_open(struct inode *inode, struct file *filp)
{
struct mmc_rpmb_data *rpmb = container_of(inode->i_cdev,
struct mmc_rpmb_data, chrdev);
get_device(&rpmb->dev);
filp->private_data = rpmb;
mmc_blk_get(rpmb->md->disk);
return nonseekable_open(inode, filp);
}
static int mmc_rpmb_chrdev_release(struct inode *inode, struct file *filp)
{
struct mmc_rpmb_data *rpmb = container_of(inode->i_cdev,
struct mmc_rpmb_data, chrdev);
put_device(&rpmb->dev);
mmc_blk_put(rpmb->md);
return 0;
}
static const struct file_operations mmc_rpmb_fileops = {
.release = mmc_rpmb_chrdev_release,
.open = mmc_rpmb_chrdev_open,
.owner = THIS_MODULE,
.llseek = no_llseek,
.unlocked_ioctl = mmc_rpmb_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = mmc_rpmb_ioctl_compat,
#endif
};
static void mmc_blk_rpmb_device_release(struct device *dev)
{
struct mmc_rpmb_data *rpmb = dev_get_drvdata(dev);
ida_simple_remove(&mmc_rpmb_ida, rpmb->id);
kfree(rpmb);
}
static int mmc_blk_alloc_rpmb_part(struct mmc_card *card,
struct mmc_blk_data *md,
unsigned int part_index,
sector_t size,
const char *subname)
{
int devidx, ret;
char rpmb_name[DISK_NAME_LEN];
char cap_str[10];
struct mmc_rpmb_data *rpmb;
/* This creates the minor number for the RPMB char device */
devidx = ida_simple_get(&mmc_rpmb_ida, 0, max_devices, GFP_KERNEL);
if (devidx < 0)
return devidx;
rpmb = kzalloc(sizeof(*rpmb), GFP_KERNEL);
if (!rpmb) {
ida_simple_remove(&mmc_rpmb_ida, devidx);
return -ENOMEM;
}
snprintf(rpmb_name, sizeof(rpmb_name),
"mmcblk%u%s", card->host->index, subname ? subname : "");
rpmb->id = devidx;
rpmb->part_index = part_index;
rpmb->dev.init_name = rpmb_name;
rpmb->dev.bus = &mmc_rpmb_bus_type;
rpmb->dev.devt = MKDEV(MAJOR(mmc_rpmb_devt), rpmb->id);
rpmb->dev.parent = &card->dev;
rpmb->dev.release = mmc_blk_rpmb_device_release;
device_initialize(&rpmb->dev);
dev_set_drvdata(&rpmb->dev, rpmb);
rpmb->md = md;
cdev_init(&rpmb->chrdev, &mmc_rpmb_fileops);
rpmb->chrdev.owner = THIS_MODULE;
ret = cdev_device_add(&rpmb->chrdev, &rpmb->dev);
if (ret) {
pr_err("%s: could not add character device\n", rpmb_name);
goto out_put_device;
}
list_add(&rpmb->node, &md->rpmbs);
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,
MAJOR(mmc_rpmb_devt), rpmb->id);
return 0;
out_put_device:
put_device(&rpmb->dev);
return ret;
}
static void mmc_blk_remove_rpmb_part(struct mmc_rpmb_data *rpmb)
{
cdev_device_del(&rpmb->chrdev, &rpmb->dev);
put_device(&rpmb->dev);
}
/* MMC Physical partitions consist of two boot partitions and /* MMC Physical partitions consist of two boot partitions and
* up to four general purpose partitions. * up to four general purpose partitions.
* For each partition enabled in EXT_CSD a block device will be allocatedi * For each partition enabled in EXT_CSD a block device will be allocatedi
...@@ -2194,13 +2409,26 @@ static int mmc_blk_alloc_part(struct mmc_card *card, ...@@ -2194,13 +2409,26 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md) static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
{ {
int idx, ret = 0; int idx, ret;
if (!mmc_card_mmc(card)) if (!mmc_card_mmc(card))
return 0; return 0;
for (idx = 0; idx < card->nr_parts; idx++) { for (idx = 0; idx < card->nr_parts; idx++) {
if (card->part[idx].size) { if (card->part[idx].area_type & MMC_BLK_DATA_AREA_RPMB) {
/*
* RPMB partitions does not provide block access, they
* are only accessed using ioctl():s. Thus create
* special RPMB block devices that do not have a
* backing block queue for these.
*/
ret = mmc_blk_alloc_rpmb_part(card, md,
card->part[idx].part_cfg,
card->part[idx].size >> 9,
card->part[idx].name);
if (ret)
return ret;
} else if (card->part[idx].size) {
ret = mmc_blk_alloc_part(card, md, ret = mmc_blk_alloc_part(card, md,
card->part[idx].part_cfg, card->part[idx].part_cfg,
card->part[idx].size >> 9, card->part[idx].size >> 9,
...@@ -2212,7 +2440,7 @@ static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md) ...@@ -2212,7 +2440,7 @@ static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
} }
} }
return ret; return 0;
} }
static void mmc_blk_remove_req(struct mmc_blk_data *md) static void mmc_blk_remove_req(struct mmc_blk_data *md)
...@@ -2249,7 +2477,15 @@ static void mmc_blk_remove_parts(struct mmc_card *card, ...@@ -2249,7 +2477,15 @@ static void mmc_blk_remove_parts(struct mmc_card *card,
{ {
struct list_head *pos, *q; struct list_head *pos, *q;
struct mmc_blk_data *part_md; struct mmc_blk_data *part_md;
struct mmc_rpmb_data *rpmb;
/* Remove RPMB partitions */
list_for_each_safe(pos, q, &md->rpmbs) {
rpmb = list_entry(pos, struct mmc_rpmb_data, node);
list_del(pos);
mmc_blk_remove_rpmb_part(rpmb);
}
/* Remove block partitions */
list_for_each_safe(pos, q, &md->part) { list_for_each_safe(pos, q, &md->part) {
part_md = list_entry(pos, struct mmc_blk_data, part); part_md = list_entry(pos, struct mmc_blk_data, part);
list_del(pos); list_del(pos);
...@@ -2568,6 +2804,17 @@ static int __init mmc_blk_init(void) ...@@ -2568,6 +2804,17 @@ static int __init mmc_blk_init(void)
{ {
int res; int res;
res = bus_register(&mmc_rpmb_bus_type);
if (res < 0) {
pr_err("mmcblk: could not register RPMB bus type\n");
return res;
}
res = alloc_chrdev_region(&mmc_rpmb_devt, 0, MAX_DEVICES, "rpmb");
if (res < 0) {
pr_err("mmcblk: failed to allocate rpmb chrdev region\n");
goto out_bus_unreg;
}
if (perdev_minors != CONFIG_MMC_BLOCK_MINORS) if (perdev_minors != CONFIG_MMC_BLOCK_MINORS)
pr_info("mmcblk: using %d minors per device\n", perdev_minors); pr_info("mmcblk: using %d minors per device\n", perdev_minors);
...@@ -2575,16 +2822,20 @@ static int __init mmc_blk_init(void) ...@@ -2575,16 +2822,20 @@ static int __init mmc_blk_init(void)
res = register_blkdev(MMC_BLOCK_MAJOR, "mmc"); res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");
if (res) if (res)
goto out; goto out_chrdev_unreg;
res = mmc_register_driver(&mmc_driver); res = mmc_register_driver(&mmc_driver);
if (res) if (res)
goto out2; goto out_blkdev_unreg;
return 0; return 0;
out2:
out_blkdev_unreg:
unregister_blkdev(MMC_BLOCK_MAJOR, "mmc"); unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
out: out_chrdev_unreg:
unregister_chrdev_region(mmc_rpmb_devt, MAX_DEVICES);
out_bus_unreg:
bus_unregister(&mmc_rpmb_bus_type);
return res; return res;
} }
...@@ -2592,6 +2843,7 @@ static void __exit mmc_blk_exit(void) ...@@ -2592,6 +2843,7 @@ static void __exit mmc_blk_exit(void)
{ {
mmc_unregister_driver(&mmc_driver); mmc_unregister_driver(&mmc_driver);
unregister_blkdev(MMC_BLOCK_MAJOR, "mmc"); unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
unregister_chrdev_region(mmc_rpmb_devt, MAX_DEVICES);
} }
module_init(mmc_blk_init); module_init(mmc_blk_init);
......
...@@ -369,10 +369,17 @@ int mmc_add_card(struct mmc_card *card) ...@@ -369,10 +369,17 @@ int mmc_add_card(struct mmc_card *card)
*/ */
void mmc_remove_card(struct mmc_card *card) void mmc_remove_card(struct mmc_card *card)
{ {
struct mmc_host *host = card->host;
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
mmc_remove_card_debugfs(card); mmc_remove_card_debugfs(card);
#endif #endif
if (host->cqe_enabled) {
host->cqe_ops->cqe_disable(host);
host->cqe_enabled = false;
}
if (mmc_card_present(card)) { if (mmc_card_present(card)) {
if (mmc_host_is_spi(card->host)) { if (mmc_host_is_spi(card->host)) {
pr_info("%s: SPI card removed\n", pr_info("%s: SPI card removed\n",
......
...@@ -266,7 +266,8 @@ static void __mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) ...@@ -266,7 +266,8 @@ static void __mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
host->ops->request(host, mrq); host->ops->request(host, mrq);
} }
static void mmc_mrq_pr_debug(struct mmc_host *host, struct mmc_request *mrq) static void mmc_mrq_pr_debug(struct mmc_host *host, struct mmc_request *mrq,
bool cqe)
{ {
if (mrq->sbc) { if (mrq->sbc) {
pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n", pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n",
...@@ -275,9 +276,12 @@ static void mmc_mrq_pr_debug(struct mmc_host *host, struct mmc_request *mrq) ...@@ -275,9 +276,12 @@ static void mmc_mrq_pr_debug(struct mmc_host *host, struct mmc_request *mrq)
} }
if (mrq->cmd) { if (mrq->cmd) {
pr_debug("%s: starting CMD%u arg %08x flags %08x\n", pr_debug("%s: starting %sCMD%u arg %08x flags %08x\n",
mmc_hostname(host), mrq->cmd->opcode, mrq->cmd->arg, mmc_hostname(host), cqe ? "CQE direct " : "",
mrq->cmd->flags); mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags);
} else if (cqe) {
pr_debug("%s: starting CQE transfer for tag %d blkaddr %u\n",
mmc_hostname(host), mrq->tag, mrq->data->blk_addr);
} }
if (mrq->data) { if (mrq->data) {
...@@ -333,7 +337,7 @@ static int mmc_mrq_prep(struct mmc_host *host, struct mmc_request *mrq) ...@@ -333,7 +337,7 @@ static int mmc_mrq_prep(struct mmc_host *host, struct mmc_request *mrq)
return 0; return 0;
} }
static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
{ {
int err; int err;
...@@ -342,7 +346,7 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) ...@@ -342,7 +346,7 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
if (mmc_card_removed(host->card)) if (mmc_card_removed(host->card))
return -ENOMEDIUM; return -ENOMEDIUM;
mmc_mrq_pr_debug(host, mrq); mmc_mrq_pr_debug(host, mrq, false);
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
...@@ -355,6 +359,7 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) ...@@ -355,6 +359,7 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
return 0; return 0;
} }
EXPORT_SYMBOL(mmc_start_request);
/* /*
* mmc_wait_data_done() - done callback for data request * mmc_wait_data_done() - done callback for data request
...@@ -482,6 +487,155 @@ void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq) ...@@ -482,6 +487,155 @@ void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq)
} }
EXPORT_SYMBOL(mmc_wait_for_req_done); EXPORT_SYMBOL(mmc_wait_for_req_done);
/*
* mmc_cqe_start_req - Start a CQE request.
* @host: MMC host to start the request
* @mrq: request to start
*
* Start the request, re-tuning if needed and it is possible. Returns an error
* code if the request fails to start or -EBUSY if CQE is busy.
*/
int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq)
{
int err;
/*
* CQE cannot process re-tuning commands. Caller must hold retuning
* while CQE is in use. Re-tuning can happen here only when CQE has no
* active requests i.e. this is the first. Note, re-tuning will call
* ->cqe_off().
*/
err = mmc_retune(host);
if (err)
goto out_err;
mrq->host = host;
mmc_mrq_pr_debug(host, mrq, true);
err = mmc_mrq_prep(host, mrq);
if (err)
goto out_err;
err = host->cqe_ops->cqe_request(host, mrq);
if (err)
goto out_err;
trace_mmc_request_start(host, mrq);
return 0;
out_err:
if (mrq->cmd) {
pr_debug("%s: failed to start CQE direct CMD%u, error %d\n",
mmc_hostname(host), mrq->cmd->opcode, err);
} else {
pr_debug("%s: failed to start CQE transfer for tag %d, error %d\n",
mmc_hostname(host), mrq->tag, err);
}
return err;
}
EXPORT_SYMBOL(mmc_cqe_start_req);
/**
* mmc_cqe_request_done - CQE has finished processing an MMC request
* @host: MMC host which completed request
* @mrq: MMC request which completed
*
* CQE drivers should call this function when they have completed
* their processing of a request.
*/
void mmc_cqe_request_done(struct mmc_host *host, struct mmc_request *mrq)
{
mmc_should_fail_request(host, mrq);
/* Flag re-tuning needed on CRC errors */
if ((mrq->cmd && mrq->cmd->error == -EILSEQ) ||
(mrq->data && mrq->data->error == -EILSEQ))
mmc_retune_needed(host);
trace_mmc_request_done(host, mrq);
if (mrq->cmd) {
pr_debug("%s: CQE req done (direct CMD%u): %d\n",
mmc_hostname(host), mrq->cmd->opcode, mrq->cmd->error);
} else {
pr_debug("%s: CQE transfer done tag %d\n",
mmc_hostname(host), mrq->tag);
}
if (mrq->data) {
pr_debug("%s: %d bytes transferred: %d\n",
mmc_hostname(host),
mrq->data->bytes_xfered, mrq->data->error);
}
mrq->done(mrq);
}
EXPORT_SYMBOL(mmc_cqe_request_done);
/**
* mmc_cqe_post_req - CQE post process of a completed MMC request
* @host: MMC host
* @mrq: MMC request to be processed
*/
void mmc_cqe_post_req(struct mmc_host *host, struct mmc_request *mrq)
{
if (host->cqe_ops->cqe_post_req)
host->cqe_ops->cqe_post_req(host, mrq);
}
EXPORT_SYMBOL(mmc_cqe_post_req);
/* Arbitrary 1 second timeout */
#define MMC_CQE_RECOVERY_TIMEOUT 1000
/*
* mmc_cqe_recovery - Recover from CQE errors.
* @host: MMC host to recover
*
* Recovery consists of stopping CQE, stopping eMMC, discarding the queue in
* in eMMC, and discarding the queue in CQE. CQE must call
* mmc_cqe_request_done() on all requests. An error is returned if the eMMC
* fails to discard its queue.
*/
int mmc_cqe_recovery(struct mmc_host *host)
{
struct mmc_command cmd;
int err;
mmc_retune_hold_now(host);
/*
* Recovery is expected seldom, if at all, but it reduces performance,
* so make sure it is not completely silent.
*/
pr_warn("%s: running CQE recovery\n", mmc_hostname(host));
host->cqe_ops->cqe_recovery_start(host);
memset(&cmd, 0, sizeof(cmd));
cmd.opcode = MMC_STOP_TRANSMISSION,
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC,
cmd.flags &= ~MMC_RSP_CRC; /* Ignore CRC */
cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT,
mmc_wait_for_cmd(host, &cmd, 0);
memset(&cmd, 0, sizeof(cmd));
cmd.opcode = MMC_CMDQ_TASK_MGMT;
cmd.arg = 1; /* Discard entire queue */
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
cmd.flags &= ~MMC_RSP_CRC; /* Ignore CRC */
cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT,
err = mmc_wait_for_cmd(host, &cmd, 0);
host->cqe_ops->cqe_recovery_finish(host);
mmc_retune_release(host);
return err;
}
EXPORT_SYMBOL(mmc_cqe_recovery);
/** /**
* mmc_is_req_done - Determine if a 'cap_cmd_during_tfr' request is done * mmc_is_req_done - Determine if a 'cap_cmd_during_tfr' request is done
* @host: MMC host * @host: MMC host
...@@ -832,9 +986,36 @@ unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz) ...@@ -832,9 +986,36 @@ unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz)
} }
EXPORT_SYMBOL(mmc_align_data_size); EXPORT_SYMBOL(mmc_align_data_size);
/*
* Allow claiming an already claimed host if the context is the same or there is
* no context but the task is the same.
*/
static inline bool mmc_ctx_matches(struct mmc_host *host, struct mmc_ctx *ctx,
struct task_struct *task)
{
return host->claimer == ctx ||
(!ctx && task && host->claimer->task == task);
}
static inline void mmc_ctx_set_claimer(struct mmc_host *host,
struct mmc_ctx *ctx,
struct task_struct *task)
{
if (!host->claimer) {
if (ctx)
host->claimer = ctx;
else
host->claimer = &host->default_ctx;
}
if (task)
host->claimer->task = task;
}
/** /**
* __mmc_claim_host - exclusively claim a host * __mmc_claim_host - exclusively claim a host
* @host: mmc host to claim * @host: mmc host to claim
* @ctx: context that claims the host or NULL in which case the default
* context will be used
* @abort: whether or not the operation should be aborted * @abort: whether or not the operation should be aborted
* *
* Claim a host for a set of operations. If @abort is non null and * Claim a host for a set of operations. If @abort is non null and
...@@ -842,8 +1023,10 @@ EXPORT_SYMBOL(mmc_align_data_size); ...@@ -842,8 +1023,10 @@ EXPORT_SYMBOL(mmc_align_data_size);
* that non-zero value without acquiring the lock. Returns zero * that non-zero value without acquiring the lock. Returns zero
* with the lock held otherwise. * with the lock held otherwise.
*/ */
int __mmc_claim_host(struct mmc_host *host, atomic_t *abort) int __mmc_claim_host(struct mmc_host *host, struct mmc_ctx *ctx,
atomic_t *abort)
{ {
struct task_struct *task = ctx ? NULL : current;
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
unsigned long flags; unsigned long flags;
int stop; int stop;
...@@ -856,7 +1039,7 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort) ...@@ -856,7 +1039,7 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
while (1) { while (1) {
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
stop = abort ? atomic_read(abort) : 0; stop = abort ? atomic_read(abort) : 0;
if (stop || !host->claimed || host->claimer == current) if (stop || !host->claimed || mmc_ctx_matches(host, ctx, task))
break; break;
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
schedule(); schedule();
...@@ -865,7 +1048,7 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort) ...@@ -865,7 +1048,7 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
if (!stop) { if (!stop) {
host->claimed = 1; host->claimed = 1;
host->claimer = current; mmc_ctx_set_claimer(host, ctx, task);
host->claim_cnt += 1; host->claim_cnt += 1;
if (host->claim_cnt == 1) if (host->claim_cnt == 1)
pm = true; pm = true;
...@@ -900,6 +1083,7 @@ void mmc_release_host(struct mmc_host *host) ...@@ -900,6 +1083,7 @@ void mmc_release_host(struct mmc_host *host)
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
} else { } else {
host->claimed = 0; host->claimed = 0;
host->claimer->task = NULL;
host->claimer = NULL; host->claimer = NULL;
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
wake_up(&host->wq); wake_up(&host->wq);
...@@ -913,10 +1097,10 @@ EXPORT_SYMBOL(mmc_release_host); ...@@ -913,10 +1097,10 @@ EXPORT_SYMBOL(mmc_release_host);
* This is a helper function, which fetches a runtime pm reference for the * This is a helper function, which fetches a runtime pm reference for the
* card device and also claims the host. * card device and also claims the host.
*/ */
void mmc_get_card(struct mmc_card *card) void mmc_get_card(struct mmc_card *card, struct mmc_ctx *ctx)
{ {
pm_runtime_get_sync(&card->dev); pm_runtime_get_sync(&card->dev);
mmc_claim_host(card->host); __mmc_claim_host(card->host, ctx, NULL);
} }
EXPORT_SYMBOL(mmc_get_card); EXPORT_SYMBOL(mmc_get_card);
...@@ -924,9 +1108,13 @@ EXPORT_SYMBOL(mmc_get_card); ...@@ -924,9 +1108,13 @@ EXPORT_SYMBOL(mmc_get_card);
* This is a helper function, which releases the host and drops the runtime * This is a helper function, which releases the host and drops the runtime
* pm reference for the card device. * pm reference for the card device.
*/ */
void mmc_put_card(struct mmc_card *card) void mmc_put_card(struct mmc_card *card, struct mmc_ctx *ctx)
{ {
mmc_release_host(card->host); struct mmc_host *host = card->host;
WARN_ON(ctx && host->claimer != ctx);
mmc_release_host(host);
pm_runtime_mark_last_busy(&card->dev); pm_runtime_mark_last_busy(&card->dev);
pm_runtime_put_autosuspend(&card->dev); pm_runtime_put_autosuspend(&card->dev);
} }
...@@ -1400,6 +1588,16 @@ EXPORT_SYMBOL_GPL(mmc_regulator_set_vqmmc); ...@@ -1400,6 +1588,16 @@ EXPORT_SYMBOL_GPL(mmc_regulator_set_vqmmc);
#endif /* CONFIG_REGULATOR */ #endif /* CONFIG_REGULATOR */
/**
* mmc_regulator_get_supply - try to get VMMC and VQMMC regulators for a host
* @mmc: the host to regulate
*
* Returns 0 or errno. errno should be handled, it is either a critical error
* or -EPROBE_DEFER. 0 means no critical error but it does not mean all
* regulators have been found because they all are optional. If you require
* certain regulators, you need to check separately in your driver if they got
* populated after calling this function.
*/
int mmc_regulator_get_supply(struct mmc_host *mmc) int mmc_regulator_get_supply(struct mmc_host *mmc)
{ {
struct device *dev = mmc_dev(mmc); struct device *dev = mmc_dev(mmc);
...@@ -1484,11 +1682,33 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage) ...@@ -1484,11 +1682,33 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
} }
int mmc_host_set_uhs_voltage(struct mmc_host *host)
{
u32 clock;
/*
* During a signal voltage level switch, the clock must be gated
* for 5 ms according to the SD spec
*/
clock = host->ios.clock;
host->ios.clock = 0;
mmc_set_ios(host);
if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180))
return -EAGAIN;
/* Keep clock gated for at least 10 ms, though spec only says 5 ms */
mmc_delay(10);
host->ios.clock = clock;
mmc_set_ios(host);
return 0;
}
int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr) int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr)
{ {
struct mmc_command cmd = {}; struct mmc_command cmd = {};
int err = 0; int err = 0;
u32 clock;
/* /*
* If we cannot switch voltages, return failure so the caller * If we cannot switch voltages, return failure so the caller
...@@ -1520,15 +1740,8 @@ int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr) ...@@ -1520,15 +1740,8 @@ int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr)
err = -EAGAIN; err = -EAGAIN;
goto power_cycle; goto power_cycle;
} }
/*
* During a signal voltage level switch, the clock must be gated
* for 5 ms according to the SD spec
*/
clock = host->ios.clock;
host->ios.clock = 0;
mmc_set_ios(host);
if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)) { if (mmc_host_set_uhs_voltage(host)) {
/* /*
* Voltages may not have been switched, but we've already * Voltages may not have been switched, but we've already
* sent CMD11, so a power cycle is required anyway * sent CMD11, so a power cycle is required anyway
...@@ -1537,11 +1750,6 @@ int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr) ...@@ -1537,11 +1750,6 @@ int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr)
goto power_cycle; goto power_cycle;
} }
/* Keep clock gated for at least 10 ms, though spec only says 5 ms */
mmc_delay(10);
host->ios.clock = clock;
mmc_set_ios(host);
/* Wait for at least 1 ms according to spec */ /* Wait for at least 1 ms according to spec */
mmc_delay(1); mmc_delay(1);
......
...@@ -49,6 +49,7 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode); ...@@ -49,6 +49,7 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
void mmc_set_bus_width(struct mmc_host *host, unsigned int width); void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr); u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr); int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr);
int mmc_host_set_uhs_voltage(struct mmc_host *host);
int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage); int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
void mmc_set_timing(struct mmc_host *host, unsigned int timing); void mmc_set_timing(struct mmc_host *host, unsigned int timing);
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type); void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
...@@ -107,6 +108,8 @@ static inline void mmc_unregister_pm_notifier(struct mmc_host *host) { } ...@@ -107,6 +108,8 @@ static inline void mmc_unregister_pm_notifier(struct mmc_host *host) { }
void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq); 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); bool mmc_is_req_done(struct mmc_host *host, struct mmc_request *mrq);
int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq);
struct mmc_async_req; struct mmc_async_req;
struct mmc_async_req *mmc_start_areq(struct mmc_host *host, struct mmc_async_req *mmc_start_areq(struct mmc_host *host,
...@@ -128,10 +131,11 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen); ...@@ -128,10 +131,11 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount, int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
bool is_rel_write); bool is_rel_write);
int __mmc_claim_host(struct mmc_host *host, atomic_t *abort); int __mmc_claim_host(struct mmc_host *host, struct mmc_ctx *ctx,
atomic_t *abort);
void mmc_release_host(struct mmc_host *host); void mmc_release_host(struct mmc_host *host);
void mmc_get_card(struct mmc_card *card); void mmc_get_card(struct mmc_card *card, struct mmc_ctx *ctx);
void mmc_put_card(struct mmc_card *card); void mmc_put_card(struct mmc_card *card, struct mmc_ctx *ctx);
/** /**
* mmc_claim_host - exclusively claim a host * mmc_claim_host - exclusively claim a host
...@@ -141,7 +145,11 @@ void mmc_put_card(struct mmc_card *card); ...@@ -141,7 +145,11 @@ void mmc_put_card(struct mmc_card *card);
*/ */
static inline void mmc_claim_host(struct mmc_host *host) static inline void mmc_claim_host(struct mmc_host *host)
{ {
__mmc_claim_host(host, NULL); __mmc_claim_host(host, NULL, NULL);
} }
int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq);
void mmc_cqe_post_req(struct mmc_host *host, struct mmc_request *mrq);
int mmc_cqe_recovery(struct mmc_host *host);
#endif #endif
...@@ -111,12 +111,6 @@ void mmc_retune_hold(struct mmc_host *host) ...@@ -111,12 +111,6 @@ void mmc_retune_hold(struct mmc_host *host)
host->hold_retune += 1; host->hold_retune += 1;
} }
void mmc_retune_hold_now(struct mmc_host *host)
{
host->retune_now = 0;
host->hold_retune += 1;
}
void mmc_retune_release(struct mmc_host *host) void mmc_retune_release(struct mmc_host *host)
{ {
if (host->hold_retune) if (host->hold_retune)
...@@ -124,6 +118,7 @@ void mmc_retune_release(struct mmc_host *host) ...@@ -124,6 +118,7 @@ void mmc_retune_release(struct mmc_host *host)
else else
WARN_ON(1); WARN_ON(1);
} }
EXPORT_SYMBOL(mmc_retune_release);
int mmc_retune(struct mmc_host *host) int mmc_retune(struct mmc_host *host)
{ {
...@@ -184,7 +179,7 @@ static void mmc_retune_timer(unsigned long data) ...@@ -184,7 +179,7 @@ static void mmc_retune_timer(unsigned long data)
int mmc_of_parse(struct mmc_host *host) int mmc_of_parse(struct mmc_host *host)
{ {
struct device *dev = host->parent; struct device *dev = host->parent;
u32 bus_width; u32 bus_width, drv_type;
int ret; int ret;
bool cd_cap_invert, cd_gpio_invert = false; bool cd_cap_invert, cd_gpio_invert = false;
bool ro_cap_invert, ro_gpio_invert = false; bool ro_cap_invert, ro_gpio_invert = false;
...@@ -326,6 +321,15 @@ int mmc_of_parse(struct mmc_host *host) ...@@ -326,6 +321,15 @@ int mmc_of_parse(struct mmc_host *host)
if (device_property_read_bool(dev, "no-mmc")) if (device_property_read_bool(dev, "no-mmc"))
host->caps2 |= MMC_CAP2_NO_MMC; host->caps2 |= MMC_CAP2_NO_MMC;
/* Must be after "non-removable" check */
if (device_property_read_u32(dev, "fixed-emmc-driver-type", &drv_type) == 0) {
if (host->caps & MMC_CAP_NONREMOVABLE)
host->fixed_drv_type = drv_type;
else
dev_err(host->parent,
"can't use fixed driver type, media is removable\n");
}
host->dsr_req = !device_property_read_u32(dev, "dsr", &host->dsr); host->dsr_req = !device_property_read_u32(dev, "dsr", &host->dsr);
if (host->dsr_req && (host->dsr & ~0xffff)) { if (host->dsr_req && (host->dsr & ~0xffff)) {
dev_err(host->parent, dev_err(host->parent,
...@@ -398,6 +402,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) ...@@ -398,6 +402,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
host->max_blk_size = 512; host->max_blk_size = 512;
host->max_blk_count = PAGE_SIZE / 512; host->max_blk_count = PAGE_SIZE / 512;
host->fixed_drv_type = -EINVAL;
return host; return host;
} }
......
...@@ -19,12 +19,17 @@ void mmc_unregister_host_class(void); ...@@ -19,12 +19,17 @@ void mmc_unregister_host_class(void);
void mmc_retune_enable(struct mmc_host *host); void mmc_retune_enable(struct mmc_host *host);
void mmc_retune_disable(struct mmc_host *host); void mmc_retune_disable(struct mmc_host *host);
void mmc_retune_hold(struct mmc_host *host); void mmc_retune_hold(struct mmc_host *host);
void mmc_retune_hold_now(struct mmc_host *host);
void mmc_retune_release(struct mmc_host *host); void mmc_retune_release(struct mmc_host *host);
int mmc_retune(struct mmc_host *host); int mmc_retune(struct mmc_host *host);
void mmc_retune_pause(struct mmc_host *host); void mmc_retune_pause(struct mmc_host *host);
void mmc_retune_unpause(struct mmc_host *host); void mmc_retune_unpause(struct mmc_host *host);
static inline void mmc_retune_hold_now(struct mmc_host *host)
{
host->retune_now = 0;
host->hold_retune += 1;
}
static inline void mmc_retune_recheck(struct mmc_host *host) static inline void mmc_retune_recheck(struct mmc_host *host)
{ {
if (host->hold_retune <= 1) if (host->hold_retune <= 1)
......
...@@ -780,6 +780,7 @@ MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid); ...@@ -780,6 +780,7 @@ MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name); MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid); MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
MMC_DEV_ATTR(prv, "0x%x\n", card->cid.prv); MMC_DEV_ATTR(prv, "0x%x\n", card->cid.prv);
MMC_DEV_ATTR(rev, "0x%x\n", card->ext_csd.rev);
MMC_DEV_ATTR(pre_eol_info, "%02x\n", card->ext_csd.pre_eol_info); MMC_DEV_ATTR(pre_eol_info, "%02x\n", card->ext_csd.pre_eol_info);
MMC_DEV_ATTR(life_time, "0x%02x 0x%02x\n", MMC_DEV_ATTR(life_time, "0x%02x 0x%02x\n",
card->ext_csd.device_life_time_est_typ_a, card->ext_csd.device_life_time_est_typ_a,
...@@ -838,6 +839,7 @@ static struct attribute *mmc_std_attrs[] = { ...@@ -838,6 +839,7 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_name.attr, &dev_attr_name.attr,
&dev_attr_oemid.attr, &dev_attr_oemid.attr,
&dev_attr_prv.attr, &dev_attr_prv.attr,
&dev_attr_rev.attr,
&dev_attr_pre_eol_info.attr, &dev_attr_pre_eol_info.attr,
&dev_attr_life_time.attr, &dev_attr_life_time.attr,
&dev_attr_serial.attr, &dev_attr_serial.attr,
...@@ -1289,13 +1291,18 @@ int mmc_hs400_to_hs200(struct mmc_card *card) ...@@ -1289,13 +1291,18 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
static void mmc_select_driver_type(struct mmc_card *card) static void mmc_select_driver_type(struct mmc_card *card)
{ {
int card_drv_type, drive_strength, drv_type; int card_drv_type, drive_strength, drv_type;
int fixed_drv_type = card->host->fixed_drv_type;
card_drv_type = card->ext_csd.raw_driver_strength | card_drv_type = card->ext_csd.raw_driver_strength |
mmc_driver_type_mask(0); mmc_driver_type_mask(0);
drive_strength = mmc_select_drive_strength(card, if (fixed_drv_type >= 0)
card->ext_csd.hs200_max_dtr, drive_strength = card_drv_type & mmc_driver_type_mask(fixed_drv_type)
card_drv_type, &drv_type); ? fixed_drv_type : 0;
else
drive_strength = mmc_select_drive_strength(card,
card->ext_csd.hs200_max_dtr,
card_drv_type, &drv_type);
card->drive_strength = drive_strength; card->drive_strength = drive_strength;
...@@ -1785,6 +1792,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, ...@@ -1785,6 +1792,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
} }
} }
/*
* Enable Command Queue if supported. Note that Packed Commands cannot
* be used with Command Queue.
*/
card->ext_csd.cmdq_en = false;
if (card->ext_csd.cmdq_support && host->caps2 & MMC_CAP2_CQE) {
err = mmc_cmdq_enable(card);
if (err && err != -EBADMSG)
goto free_card;
if (err) {
pr_warn("%s: Enabling CMDQ failed\n",
mmc_hostname(card->host));
card->ext_csd.cmdq_support = false;
card->ext_csd.cmdq_depth = 0;
err = 0;
}
}
/* /*
* In some cases (e.g. RPMB or mmc_test), the Command Queue must be * In some cases (e.g. RPMB or mmc_test), the Command Queue must be
* disabled for a time, so a flag is needed to indicate to re-enable the * disabled for a time, so a flag is needed to indicate to re-enable the
...@@ -1792,6 +1816,18 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, ...@@ -1792,6 +1816,18 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
*/ */
card->reenable_cmdq = card->ext_csd.cmdq_en; card->reenable_cmdq = card->ext_csd.cmdq_en;
if (card->ext_csd.cmdq_en && !host->cqe_enabled) {
err = host->cqe_ops->cqe_enable(host, card);
if (err) {
pr_err("%s: Failed to enable CQE, error %d\n",
mmc_hostname(host), err);
} else {
host->cqe_enabled = true;
pr_info("%s: Command Queue Engine enabled\n",
mmc_hostname(host));
}
}
if (!oldcard) if (!oldcard)
host->card = card; host->card = card;
...@@ -1911,14 +1947,14 @@ static void mmc_detect(struct mmc_host *host) ...@@ -1911,14 +1947,14 @@ static void mmc_detect(struct mmc_host *host)
{ {
int err; int err;
mmc_get_card(host->card); mmc_get_card(host->card, NULL);
/* /*
* Just check if our card has been removed. * Just check if our card has been removed.
*/ */
err = _mmc_detect_card_removed(host); err = _mmc_detect_card_removed(host);
mmc_put_card(host->card); mmc_put_card(host->card, NULL);
if (err) { if (err) {
mmc_remove(host); mmc_remove(host);
......
...@@ -977,7 +977,6 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception) ...@@ -977,7 +977,6 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
from_exception) from_exception)
return; return;
mmc_claim_host(card->host);
if (card->ext_csd.raw_bkops_status >= EXT_CSD_BKOPS_LEVEL_2) { if (card->ext_csd.raw_bkops_status >= EXT_CSD_BKOPS_LEVEL_2) {
timeout = MMC_OPS_TIMEOUT_MS; timeout = MMC_OPS_TIMEOUT_MS;
use_busy_signal = true; use_busy_signal = true;
...@@ -995,7 +994,7 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception) ...@@ -995,7 +994,7 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
pr_warn("%s: Error %d starting bkops\n", pr_warn("%s: Error %d starting bkops\n",
mmc_hostname(card->host), err); mmc_hostname(card->host), err);
mmc_retune_release(card->host); mmc_retune_release(card->host);
goto out; return;
} }
/* /*
...@@ -1007,9 +1006,8 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception) ...@@ -1007,9 +1006,8 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
mmc_card_set_doing_bkops(card); mmc_card_set_doing_bkops(card);
else else
mmc_retune_release(card->host); mmc_retune_release(card->host);
out:
mmc_release_host(card->host);
} }
EXPORT_SYMBOL(mmc_start_bkops);
/* /*
* Flush the cache to the non-volatile storage. * Flush the cache to the non-volatile storage.
......
...@@ -30,7 +30,7 @@ static int mmc_prep_request(struct request_queue *q, struct request *req) ...@@ -30,7 +30,7 @@ static int mmc_prep_request(struct request_queue *q, struct request *req)
{ {
struct mmc_queue *mq = q->queuedata; struct mmc_queue *mq = q->queuedata;
if (mq && (mmc_card_removed(mq->card) || mmc_access_rpmb(mq))) if (mq && mmc_card_removed(mq->card))
return BLKPREP_KILL; return BLKPREP_KILL;
req->rq_flags |= RQF_DONTPREP; req->rq_flags |= RQF_DONTPREP;
...@@ -177,6 +177,29 @@ static void mmc_exit_request(struct request_queue *q, struct request *req) ...@@ -177,6 +177,29 @@ static void mmc_exit_request(struct request_queue *q, struct request *req)
mq_rq->sg = NULL; mq_rq->sg = NULL;
} }
static void mmc_setup_queue(struct mmc_queue *mq, struct mmc_card *card)
{
struct mmc_host *host = card->host;
u64 limit = BLK_BOUNCE_HIGH;
if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, mq->queue);
if (mmc_can_erase(card))
mmc_queue_setup_discard(mq->queue, card);
blk_queue_bounce_limit(mq->queue, limit);
blk_queue_max_hw_sectors(mq->queue,
min(host->max_blk_count, host->max_req_size / 512));
blk_queue_max_segments(mq->queue, host->max_segs);
blk_queue_max_segment_size(mq->queue, host->max_seg_size);
/* Initialize thread_sem even if it is not used */
sema_init(&mq->thread_sem, 1);
}
/** /**
* mmc_init_queue - initialise a queue structure. * mmc_init_queue - initialise a queue structure.
* @mq: mmc queue * @mq: mmc queue
...@@ -190,12 +213,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, ...@@ -190,12 +213,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
spinlock_t *lock, const char *subname) spinlock_t *lock, const char *subname)
{ {
struct mmc_host *host = card->host; struct mmc_host *host = card->host;
u64 limit = BLK_BOUNCE_HIGH;
int ret = -ENOMEM; int ret = -ENOMEM;
if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
mq->card = card; mq->card = card;
mq->queue = blk_alloc_queue(GFP_KERNEL); mq->queue = blk_alloc_queue(GFP_KERNEL);
if (!mq->queue) if (!mq->queue)
...@@ -214,18 +233,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, ...@@ -214,18 +233,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
} }
blk_queue_prep_rq(mq->queue, mmc_prep_request); blk_queue_prep_rq(mq->queue, mmc_prep_request);
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, mq->queue);
if (mmc_can_erase(card))
mmc_queue_setup_discard(mq->queue, card);
blk_queue_bounce_limit(mq->queue, limit); mmc_setup_queue(mq, card);
blk_queue_max_hw_sectors(mq->queue,
min(host->max_blk_count, host->max_req_size / 512));
blk_queue_max_segments(mq->queue, host->max_segs);
blk_queue_max_segment_size(mq->queue, host->max_seg_size);
sema_init(&mq->thread_sem, 1);
mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d%s", mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d%s",
host->index, subname ? subname : ""); host->index, subname ? subname : "");
......
...@@ -36,12 +36,14 @@ struct mmc_blk_request { ...@@ -36,12 +36,14 @@ struct mmc_blk_request {
/** /**
* enum mmc_drv_op - enumerates the operations in the mmc_queue_req * enum mmc_drv_op - enumerates the operations in the mmc_queue_req
* @MMC_DRV_OP_IOCTL: ioctl operation * @MMC_DRV_OP_IOCTL: ioctl operation
* @MMC_DRV_OP_IOCTL_RPMB: RPMB-oriented ioctl operation
* @MMC_DRV_OP_BOOT_WP: write protect boot partitions * @MMC_DRV_OP_BOOT_WP: write protect boot partitions
* @MMC_DRV_OP_GET_CARD_STATUS: get card status * @MMC_DRV_OP_GET_CARD_STATUS: get card status
* @MMC_DRV_OP_GET_EXT_CSD: get the EXT CSD from an eMMC card * @MMC_DRV_OP_GET_EXT_CSD: get the EXT CSD from an eMMC card
*/ */
enum mmc_drv_op { enum mmc_drv_op {
MMC_DRV_OP_IOCTL, MMC_DRV_OP_IOCTL,
MMC_DRV_OP_IOCTL_RPMB,
MMC_DRV_OP_BOOT_WP, MMC_DRV_OP_BOOT_WP,
MMC_DRV_OP_GET_CARD_STATUS, MMC_DRV_OP_GET_CARD_STATUS,
MMC_DRV_OP_GET_EXT_CSD, MMC_DRV_OP_GET_EXT_CSD,
...@@ -82,6 +84,4 @@ extern void mmc_queue_resume(struct mmc_queue *); ...@@ -82,6 +84,4 @@ extern void mmc_queue_resume(struct mmc_queue *);
extern unsigned int mmc_queue_map_sg(struct mmc_queue *, extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
struct mmc_queue_req *); struct mmc_queue_req *);
extern int mmc_access_rpmb(struct mmc_queue *);
#endif #endif
...@@ -908,6 +908,18 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card) ...@@ -908,6 +908,18 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
return max_dtr; return max_dtr;
} }
static bool mmc_sd_card_using_v18(struct mmc_card *card)
{
/*
* According to the SD spec., the Bus Speed Mode (function group 1) bits
* 2 to 4 are zero if the card is initialized at 3.3V signal level. Thus
* they can be used to determine if the card has already switched to
* 1.8V signaling.
*/
return card->sw_caps.sd3_bus_mode &
(SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR104 | SD_MODE_UHS_DDR50);
}
/* /*
* Handle the detection and initialisation of a card. * Handle the detection and initialisation of a card.
* *
...@@ -921,9 +933,10 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, ...@@ -921,9 +933,10 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
int err; int err;
u32 cid[4]; u32 cid[4];
u32 rocr = 0; u32 rocr = 0;
bool v18_fixup_failed = false;
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
retry:
err = mmc_sd_get_cid(host, ocr, cid, &rocr); err = mmc_sd_get_cid(host, ocr, cid, &rocr);
if (err) if (err)
return err; return err;
...@@ -989,6 +1002,36 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, ...@@ -989,6 +1002,36 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
if (err) if (err)
goto free_card; goto free_card;
/*
* If the card has not been power cycled, it may still be using 1.8V
* signaling. Detect that situation and try to initialize a UHS-I (1.8V)
* transfer mode.
*/
if (!v18_fixup_failed && !mmc_host_is_spi(host) && mmc_host_uhs(host) &&
mmc_sd_card_using_v18(card) &&
host->ios.signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
/*
* Re-read switch information in case it has changed since
* oldcard was initialized.
*/
if (oldcard) {
err = mmc_read_switch(card);
if (err)
goto free_card;
}
if (mmc_sd_card_using_v18(card)) {
if (mmc_host_set_uhs_voltage(host) ||
mmc_sd_init_uhs_card(card)) {
v18_fixup_failed = true;
mmc_power_cycle(host, ocr);
if (!oldcard)
mmc_remove_card(card);
goto retry;
}
goto done;
}
}
/* Initialization sequence for UHS-I cards */ /* Initialization sequence for UHS-I cards */
if (rocr & SD_ROCR_S18A) { if (rocr & SD_ROCR_S18A) {
err = mmc_sd_init_uhs_card(card); err = mmc_sd_init_uhs_card(card);
...@@ -1021,7 +1064,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, ...@@ -1021,7 +1064,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
mmc_set_bus_width(host, MMC_BUS_WIDTH_4); mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
} }
} }
done:
host->card = card; host->card = card;
return 0; return 0;
...@@ -1056,14 +1099,14 @@ static void mmc_sd_detect(struct mmc_host *host) ...@@ -1056,14 +1099,14 @@ static void mmc_sd_detect(struct mmc_host *host)
{ {
int err; int err;
mmc_get_card(host->card); mmc_get_card(host->card, NULL);
/* /*
* Just check if our card has been removed. * Just check if our card has been removed.
*/ */
err = _mmc_detect_card_removed(host); err = _mmc_detect_card_removed(host);
mmc_put_card(host->card); mmc_put_card(host->card, NULL);
if (err) { if (err) {
mmc_sd_remove(host); mmc_sd_remove(host);
......
...@@ -155,7 +155,8 @@ static int sdio_irq_thread(void *_host) ...@@ -155,7 +155,8 @@ static int sdio_irq_thread(void *_host)
* holding of the host lock does not cover too much work * holding of the host lock does not cover too much work
* that doesn't require that lock to be held. * that doesn't require that lock to be held.
*/ */
ret = __mmc_claim_host(host, &host->sdio_irq_thread_abort); ret = __mmc_claim_host(host, NULL,
&host->sdio_irq_thread_abort);
if (ret) if (ret)
break; break;
ret = process_sdio_pending_irqs(host); ret = process_sdio_pending_irqs(host);
......
...@@ -352,6 +352,19 @@ config MMC_MESON_GX ...@@ -352,6 +352,19 @@ config MMC_MESON_GX
If you have a controller with this interface, say Y here. If you have a controller with this interface, say Y here.
config MMC_MESON_MX_SDIO
tristate "Amlogic Meson6/Meson8/Meson8b SD/MMC Host Controller support"
depends on ARCH_MESON || COMPILE_TEST
depends on COMMON_CLK
depends on HAS_DMA
depends on OF
help
This selects support for the SD/MMC Host Controller on
Amlogic Meson6, Meson8 and Meson8b SoCs.
If you have a controller with this interface, say Y or M here.
If unsure, say N.
config MMC_MOXART config MMC_MOXART
tristate "MOXART SD/MMC Host Controller support" tristate "MOXART SD/MMC Host Controller support"
depends on ARCH_MOXART && MMC depends on ARCH_MOXART && MMC
...@@ -429,6 +442,7 @@ config MMC_SDHCI_MSM ...@@ -429,6 +442,7 @@ config MMC_SDHCI_MSM
tristate "Qualcomm SDHCI Controller Support" tristate "Qualcomm SDHCI Controller Support"
depends on ARCH_QCOM || (ARM && COMPILE_TEST) depends on ARCH_QCOM || (ARM && COMPILE_TEST)
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS
help help
This selects the Secure Digital Host Controller Interface (SDHCI) This selects the Secure Digital Host Controller Interface (SDHCI)
support present in Qualcomm SOCs. The controller supports support present in Qualcomm SOCs. The controller supports
...@@ -663,7 +677,7 @@ config MMC_CAVIUM_OCTEON ...@@ -663,7 +677,7 @@ config MMC_CAVIUM_OCTEON
config MMC_CAVIUM_THUNDERX config MMC_CAVIUM_THUNDERX
tristate "Cavium ThunderX SD/MMC Card Interface support" tristate "Cavium ThunderX SD/MMC Card Interface support"
depends on PCI && 64BIT && (ARM64 || COMPILE_TEST) depends on PCI && 64BIT && (ARM64 || COMPILE_TEST)
depends on GPIOLIB depends on GPIO_THUNDERX
depends on OF_ADDRESS depends on OF_ADDRESS
help help
This selects Cavium ThunderX SD/MMC Card Interface. This selects Cavium ThunderX SD/MMC Card Interface.
...@@ -899,3 +913,15 @@ config MMC_SDHCI_XENON ...@@ -899,3 +913,15 @@ config MMC_SDHCI_XENON
This selects Marvell Xenon eMMC/SD/SDIO SDHCI. This selects Marvell Xenon eMMC/SD/SDIO SDHCI.
If you have a controller with this interface, say Y or M here. If you have a controller with this interface, say Y or M here.
If unsure, say N. If unsure, say N.
config MMC_SDHCI_OMAP
tristate "TI SDHCI Controller Support"
depends on MMC_SDHCI_PLTFM && OF
help
This selects the Secure Digital Host Controller Interface (SDHCI)
support present in TI's DRA7 SOCs. The controller supports
SD/MMC/SDIO devices.
If you have a controller with this interface, say Y or M here.
If unsure, say N.
...@@ -65,6 +65,7 @@ obj-$(CONFIG_MMC_VUB300) += vub300.o ...@@ -65,6 +65,7 @@ obj-$(CONFIG_MMC_VUB300) += vub300.o
obj-$(CONFIG_MMC_USHC) += ushc.o obj-$(CONFIG_MMC_USHC) += ushc.o
obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o
obj-$(CONFIG_MMC_MESON_GX) += meson-gx-mmc.o obj-$(CONFIG_MMC_MESON_GX) += meson-gx-mmc.o
obj-$(CONFIG_MMC_MESON_MX_SDIO) += meson-mx-sdio.o
obj-$(CONFIG_MMC_MOXART) += moxart-mmc.o obj-$(CONFIG_MMC_MOXART) += moxart-mmc.o
obj-$(CONFIG_MMC_SUNXI) += sunxi-mmc.o obj-$(CONFIG_MMC_SUNXI) += sunxi-mmc.o
obj-$(CONFIG_MMC_USDHI6ROL0) += usdhi6rol0.o obj-$(CONFIG_MMC_USDHI6ROL0) += usdhi6rol0.o
...@@ -90,6 +91,7 @@ obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o ...@@ -90,6 +91,7 @@ obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o
obj-$(CONFIG_MMC_SDHCI_ST) += sdhci-st.o obj-$(CONFIG_MMC_SDHCI_ST) += sdhci-st.o
obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32) += sdhci-pic32.o obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32) += sdhci-pic32.o
obj-$(CONFIG_MMC_SDHCI_BRCMSTB) += sdhci-brcmstb.o obj-$(CONFIG_MMC_SDHCI_BRCMSTB) += sdhci-brcmstb.o
obj-$(CONFIG_MMC_SDHCI_OMAP) += sdhci-omap.o
ifeq ($(CONFIG_CB710_DEBUG),y) ifeq ($(CONFIG_CB710_DEBUG),y)
CFLAGS-cb710-mmc += -DDEBUG CFLAGS-cb710-mmc += -DDEBUG
......
...@@ -732,11 +732,11 @@ static inline unsigned int atmci_convert_chksize(struct atmel_mci *host, ...@@ -732,11 +732,11 @@ static inline unsigned int atmci_convert_chksize(struct atmel_mci *host,
return 0; return 0;
} }
static void atmci_timeout_timer(unsigned long data) static void atmci_timeout_timer(struct timer_list *t)
{ {
struct atmel_mci *host; struct atmel_mci *host;
host = (struct atmel_mci *)data; host = from_timer(host, t, timer);
dev_dbg(&host->pdev->dev, "software timeout\n"); dev_dbg(&host->pdev->dev, "software timeout\n");
...@@ -1661,9 +1661,9 @@ static void atmci_command_complete(struct atmel_mci *host, ...@@ -1661,9 +1661,9 @@ static void atmci_command_complete(struct atmel_mci *host,
cmd->error = 0; cmd->error = 0;
} }
static void atmci_detect_change(unsigned long data) static void atmci_detect_change(struct timer_list *t)
{ {
struct atmel_mci_slot *slot = (struct atmel_mci_slot *)data; struct atmel_mci_slot *slot = from_timer(slot, t, detect_timer);
bool present; bool present;
bool present_old; bool present_old;
...@@ -2349,8 +2349,7 @@ static int atmci_init_slot(struct atmel_mci *host, ...@@ -2349,8 +2349,7 @@ static int atmci_init_slot(struct atmel_mci *host,
if (gpio_is_valid(slot->detect_pin)) { if (gpio_is_valid(slot->detect_pin)) {
int ret; int ret;
setup_timer(&slot->detect_timer, atmci_detect_change, timer_setup(&slot->detect_timer, atmci_detect_change, 0);
(unsigned long)slot);
ret = request_irq(gpio_to_irq(slot->detect_pin), ret = request_irq(gpio_to_irq(slot->detect_pin),
atmci_detect_interrupt, atmci_detect_interrupt,
...@@ -2563,7 +2562,7 @@ static int atmci_probe(struct platform_device *pdev) ...@@ -2563,7 +2562,7 @@ static int atmci_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, host); platform_set_drvdata(pdev, host);
setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host); timer_setup(&host->timer, atmci_timeout_timer, 0);
pm_runtime_get_noresume(&pdev->dev); pm_runtime_get_noresume(&pdev->dev);
pm_runtime_set_active(&pdev->dev); pm_runtime_set_active(&pdev->dev);
......
...@@ -967,7 +967,7 @@ static int cvm_mmc_of_parse(struct device *dev, struct cvm_mmc_slot *slot) ...@@ -967,7 +967,7 @@ static int cvm_mmc_of_parse(struct device *dev, struct cvm_mmc_slot *slot)
} }
ret = mmc_regulator_get_supply(mmc); ret = mmc_regulator_get_supply(mmc);
if (ret == -EPROBE_DEFER) if (ret)
return ret; return ret;
/* /*
* Legacy Octeon firmware has no regulator entry, fall-back to * Legacy Octeon firmware has no regulator entry, fall-back to
......
...@@ -75,7 +75,7 @@ struct hs_timing { ...@@ -75,7 +75,7 @@ struct hs_timing {
u32 smpl_phase_min; u32 smpl_phase_min;
}; };
struct hs_timing hs_timing_cfg[TIMING_MODE][TIMING_CFG_NUM] = { static struct hs_timing hs_timing_cfg[TIMING_MODE][TIMING_CFG_NUM] = {
{ /* reserved */ }, { /* reserved */ },
{ /* SD */ { /* SD */
{7, 0, 15, 15,}, /* 0: LEGACY 400k */ {7, 0, 15, 15,}, /* 0: LEGACY 400k */
......
...@@ -817,7 +817,7 @@ static int dw_mci_edmac_start_dma(struct dw_mci *host, ...@@ -817,7 +817,7 @@ static int dw_mci_edmac_start_dma(struct dw_mci *host,
struct dma_slave_config cfg; struct dma_slave_config cfg;
struct dma_async_tx_descriptor *desc = NULL; struct dma_async_tx_descriptor *desc = NULL;
struct scatterlist *sgl = host->data->sg; struct scatterlist *sgl = host->data->sg;
const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256}; static const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256};
u32 sg_elems = host->data->sg_len; u32 sg_elems = host->data->sg_len;
u32 fifoth_val; u32 fifoth_val;
u32 fifo_offset = host->fifo_reg - host->regs; u32 fifo_offset = host->fifo_reg - host->regs;
...@@ -1024,7 +1024,7 @@ static int dw_mci_get_cd(struct mmc_host *mmc) ...@@ -1024,7 +1024,7 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data) static void dw_mci_adjust_fifoth(struct dw_mci *host, struct mmc_data *data)
{ {
unsigned int blksz = data->blksz; unsigned int blksz = data->blksz;
const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256}; static const u32 mszs[] = {1, 4, 8, 16, 32, 64, 128, 256};
u32 fifo_width = 1 << host->data_shift; u32 fifo_width = 1 << host->data_shift;
u32 blksz_depth = blksz / fifo_width, fifoth_val; u32 blksz_depth = blksz / fifo_width, fifoth_val;
u32 msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers; u32 msize = 0, rx_wmark = 1, tx_wmark, tx_wmark_invers;
...@@ -1938,6 +1938,7 @@ static void dw_mci_set_drto(struct dw_mci *host) ...@@ -1938,6 +1938,7 @@ static void dw_mci_set_drto(struct dw_mci *host)
unsigned int drto_clks; unsigned int drto_clks;
unsigned int drto_div; unsigned int drto_div;
unsigned int drto_ms; unsigned int drto_ms;
unsigned long irqflags;
drto_clks = mci_readl(host, TMOUT) >> 8; drto_clks = mci_readl(host, TMOUT) >> 8;
drto_div = (mci_readl(host, CLKDIV) & 0xff) * 2; drto_div = (mci_readl(host, CLKDIV) & 0xff) * 2;
...@@ -1949,7 +1950,11 @@ static void dw_mci_set_drto(struct dw_mci *host) ...@@ -1949,7 +1950,11 @@ static void dw_mci_set_drto(struct dw_mci *host)
/* add a bit spare time */ /* add a bit spare time */
drto_ms += 10; drto_ms += 10;
mod_timer(&host->dto_timer, jiffies + msecs_to_jiffies(drto_ms)); spin_lock_irqsave(&host->irq_lock, irqflags);
if (!test_bit(EVENT_DATA_COMPLETE, &host->pending_events))
mod_timer(&host->dto_timer,
jiffies + msecs_to_jiffies(drto_ms));
spin_unlock_irqrestore(&host->irq_lock, irqflags);
} }
static bool dw_mci_clear_pending_cmd_complete(struct dw_mci *host) static bool dw_mci_clear_pending_cmd_complete(struct dw_mci *host)
...@@ -1970,6 +1975,18 @@ static bool dw_mci_clear_pending_cmd_complete(struct dw_mci *host) ...@@ -1970,6 +1975,18 @@ static bool dw_mci_clear_pending_cmd_complete(struct dw_mci *host)
return true; return true;
} }
static bool dw_mci_clear_pending_data_complete(struct dw_mci *host)
{
if (!test_bit(EVENT_DATA_COMPLETE, &host->pending_events))
return false;
/* Extra paranoia just like dw_mci_clear_pending_cmd_complete() */
WARN_ON(del_timer_sync(&host->dto_timer));
clear_bit(EVENT_DATA_COMPLETE, &host->pending_events);
return true;
}
static void dw_mci_tasklet_func(unsigned long priv) static void dw_mci_tasklet_func(unsigned long priv)
{ {
struct dw_mci *host = (struct dw_mci *)priv; struct dw_mci *host = (struct dw_mci *)priv;
...@@ -2111,8 +2128,7 @@ static void dw_mci_tasklet_func(unsigned long priv) ...@@ -2111,8 +2128,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
/* fall through */ /* fall through */
case STATE_DATA_BUSY: case STATE_DATA_BUSY:
if (!test_and_clear_bit(EVENT_DATA_COMPLETE, if (!dw_mci_clear_pending_data_complete(host)) {
&host->pending_events)) {
/* /*
* If data error interrupt comes but data over * If data error interrupt comes but data over
* interrupt doesn't come within the given time. * interrupt doesn't come within the given time.
...@@ -2682,6 +2698,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) ...@@ -2682,6 +2698,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
} }
if (pending & SDMMC_INT_DATA_OVER) { if (pending & SDMMC_INT_DATA_OVER) {
spin_lock_irqsave(&host->irq_lock, irqflags);
del_timer(&host->dto_timer); del_timer(&host->dto_timer);
mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER); mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
...@@ -2694,6 +2712,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) ...@@ -2694,6 +2712,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
} }
set_bit(EVENT_DATA_COMPLETE, &host->pending_events); set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
tasklet_schedule(&host->tasklet); tasklet_schedule(&host->tasklet);
spin_unlock_irqrestore(&host->irq_lock, irqflags);
} }
if (pending & SDMMC_INT_RXDR) { if (pending & SDMMC_INT_RXDR) {
...@@ -2791,7 +2811,7 @@ static int dw_mci_init_slot(struct dw_mci *host) ...@@ -2791,7 +2811,7 @@ static int dw_mci_init_slot(struct dw_mci *host)
/*if there are external regulators, get them*/ /*if there are external regulators, get them*/
ret = mmc_regulator_get_supply(mmc); ret = mmc_regulator_get_supply(mmc);
if (ret == -EPROBE_DEFER) if (ret)
goto err_host_allocated; goto err_host_allocated;
if (!mmc->ocr_avail) if (!mmc->ocr_avail)
...@@ -2971,9 +2991,9 @@ static void dw_mci_init_dma(struct dw_mci *host) ...@@ -2971,9 +2991,9 @@ static void dw_mci_init_dma(struct dw_mci *host)
host->use_dma = TRANS_MODE_PIO; host->use_dma = TRANS_MODE_PIO;
} }
static void dw_mci_cmd11_timer(unsigned long arg) static void dw_mci_cmd11_timer(struct timer_list *t)
{ {
struct dw_mci *host = (struct dw_mci *)arg; struct dw_mci *host = from_timer(host, t, cmd11_timer);
if (host->state != STATE_SENDING_CMD11) { if (host->state != STATE_SENDING_CMD11) {
dev_warn(host->dev, "Unexpected CMD11 timeout\n"); dev_warn(host->dev, "Unexpected CMD11 timeout\n");
...@@ -2985,9 +3005,9 @@ static void dw_mci_cmd11_timer(unsigned long arg) ...@@ -2985,9 +3005,9 @@ static void dw_mci_cmd11_timer(unsigned long arg)
tasklet_schedule(&host->tasklet); tasklet_schedule(&host->tasklet);
} }
static void dw_mci_cto_timer(unsigned long arg) static void dw_mci_cto_timer(struct timer_list *t)
{ {
struct dw_mci *host = (struct dw_mci *)arg; struct dw_mci *host = from_timer(host, t, cto_timer);
unsigned long irqflags; unsigned long irqflags;
u32 pending; u32 pending;
...@@ -3040,10 +3060,34 @@ static void dw_mci_cto_timer(unsigned long arg) ...@@ -3040,10 +3060,34 @@ static void dw_mci_cto_timer(unsigned long arg)
spin_unlock_irqrestore(&host->irq_lock, irqflags); spin_unlock_irqrestore(&host->irq_lock, irqflags);
} }
static void dw_mci_dto_timer(unsigned long arg) static void dw_mci_dto_timer(struct timer_list *t)
{ {
struct dw_mci *host = (struct dw_mci *)arg; struct dw_mci *host = from_timer(host, t, dto_timer);
unsigned long irqflags;
u32 pending;
spin_lock_irqsave(&host->irq_lock, irqflags);
/*
* The DTO timer is much longer than the CTO timer, so it's even less
* likely that we'll these cases, but it pays to be paranoid.
*/
pending = mci_readl(host, MINTSTS); /* read-only mask reg */
if (pending & SDMMC_INT_DATA_OVER) {
/* The interrupt should fire; no need to act but we can warn */
dev_warn(host->dev, "Unexpected data interrupt latency\n");
goto exit;
}
if (test_bit(EVENT_DATA_COMPLETE, &host->pending_events)) {
/* Presumably interrupt handler couldn't delete the timer */
dev_warn(host->dev, "DTO timeout when already completed\n");
goto exit;
}
/*
* Continued paranoia to make sure we're in the state we expect.
* This paranoia isn't really justified but it seems good to be safe.
*/
switch (host->state) { switch (host->state) {
case STATE_SENDING_DATA: case STATE_SENDING_DATA:
case STATE_DATA_BUSY: case STATE_DATA_BUSY:
...@@ -3058,8 +3102,13 @@ static void dw_mci_dto_timer(unsigned long arg) ...@@ -3058,8 +3102,13 @@ static void dw_mci_dto_timer(unsigned long arg)
tasklet_schedule(&host->tasklet); tasklet_schedule(&host->tasklet);
break; break;
default: default:
dev_warn(host->dev, "Unexpected data timeout, state %d\n",
host->state);
break; break;
} }
exit:
spin_unlock_irqrestore(&host->irq_lock, irqflags);
} }
#ifdef CONFIG_OF #ifdef CONFIG_OF
...@@ -3208,14 +3257,9 @@ int dw_mci_probe(struct dw_mci *host) ...@@ -3208,14 +3257,9 @@ int dw_mci_probe(struct dw_mci *host)
} }
} }
setup_timer(&host->cmd11_timer, timer_setup(&host->cmd11_timer, dw_mci_cmd11_timer, 0);
dw_mci_cmd11_timer, (unsigned long)host); timer_setup(&host->cto_timer, dw_mci_cto_timer, 0);
timer_setup(&host->dto_timer, dw_mci_dto_timer, 0);
setup_timer(&host->cto_timer,
dw_mci_cto_timer, (unsigned long)host);
setup_timer(&host->dto_timer,
dw_mci_dto_timer, (unsigned long)host);
spin_lock_init(&host->lock); spin_lock_init(&host->lock);
spin_lock_init(&host->irq_lock); spin_lock_init(&host->irq_lock);
......
...@@ -74,7 +74,8 @@ struct dw_mci_dma_slave { ...@@ -74,7 +74,8 @@ struct dw_mci_dma_slave {
* @stop_abort: The command currently prepared for stoping transfer. * @stop_abort: The command currently prepared for stoping transfer.
* @prev_blksz: The former transfer blksz record. * @prev_blksz: The former transfer blksz record.
* @timing: Record of current ios timing. * @timing: Record of current ios timing.
* @use_dma: Whether DMA channel is initialized or not. * @use_dma: Which DMA channel is in use for the current transfer, zero
* denotes PIO mode.
* @using_dma: Whether DMA is in use for the current transfer. * @using_dma: Whether DMA is in use for the current transfer.
* @dma_64bit_address: Whether DMA supports 64-bit address mode or not. * @dma_64bit_address: Whether DMA supports 64-bit address mode or not.
* @sg_dma: Bus address of DMA buffer. * @sg_dma: Bus address of DMA buffer.
......
...@@ -586,9 +586,9 @@ static bool jz4740_mmc_read_data(struct jz4740_mmc_host *host, ...@@ -586,9 +586,9 @@ static bool jz4740_mmc_read_data(struct jz4740_mmc_host *host,
return true; return true;
} }
static void jz4740_mmc_timeout(unsigned long data) static void jz4740_mmc_timeout(struct timer_list *t)
{ {
struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)data; struct jz4740_mmc_host *host = from_timer(host, t, timeout_timer);
if (!test_and_clear_bit(0, &host->waiting)) if (!test_and_clear_bit(0, &host->waiting))
return; return;
...@@ -1036,8 +1036,7 @@ static int jz4740_mmc_probe(struct platform_device* pdev) ...@@ -1036,8 +1036,7 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
jz4740_mmc_reset(host); jz4740_mmc_reset(host);
jz4740_mmc_clock_disable(host); jz4740_mmc_clock_disable(host);
setup_timer(&host->timeout_timer, jz4740_mmc_timeout, timer_setup(&host->timeout_timer, jz4740_mmc_timeout, 0);
(unsigned long)host);
host->use_dma = true; host->use_dma = true;
if (host->use_dma && jz4740_mmc_acquire_dma_channels(host) != 0) if (host->use_dma && jz4740_mmc_acquire_dma_channels(host) != 0)
......
...@@ -1190,7 +1190,7 @@ static int meson_mmc_probe(struct platform_device *pdev) ...@@ -1190,7 +1190,7 @@ static int meson_mmc_probe(struct platform_device *pdev)
/* Get regulators and the supported OCR mask */ /* Get regulators and the supported OCR mask */
host->vqmmc_enabled = false; host->vqmmc_enabled = false;
ret = mmc_regulator_get_supply(mmc); ret = mmc_regulator_get_supply(mmc);
if (ret == -EPROBE_DEFER) if (ret)
goto free_host; goto free_host;
ret = mmc_of_parse(mmc); ret = mmc_of_parse(mmc);
......
此差异已折叠。
...@@ -1658,7 +1658,7 @@ static int mmci_probe(struct amba_device *dev, ...@@ -1658,7 +1658,7 @@ static int mmci_probe(struct amba_device *dev,
/* Get regulators and the supported OCR mask */ /* Get regulators and the supported OCR mask */
ret = mmc_regulator_get_supply(mmc); ret = mmc_regulator_get_supply(mmc);
if (ret == -EPROBE_DEFER) if (ret)
goto clk_disable; goto clk_disable;
if (!mmc->ocr_avail) if (!mmc->ocr_avail)
......
此差异已折叠。
...@@ -508,9 +508,9 @@ static irqreturn_t mvsd_irq(int irq, void *dev) ...@@ -508,9 +508,9 @@ static irqreturn_t mvsd_irq(int irq, void *dev)
return IRQ_NONE; return IRQ_NONE;
} }
static void mvsd_timeout_timer(unsigned long data) static void mvsd_timeout_timer(struct timer_list *t)
{ {
struct mvsd_host *host = (struct mvsd_host *)data; struct mvsd_host *host = from_timer(host, t, timer);
void __iomem *iobase = host->base; void __iomem *iobase = host->base;
struct mmc_request *mrq; struct mmc_request *mrq;
unsigned long flags; unsigned long flags;
...@@ -776,7 +776,7 @@ static int mvsd_probe(struct platform_device *pdev) ...@@ -776,7 +776,7 @@ static int mvsd_probe(struct platform_device *pdev)
goto out; goto out;
} }
setup_timer(&host->timer, mvsd_timeout_timer, (unsigned long)host); timer_setup(&host->timer, mvsd_timeout_timer, 0);
platform_set_drvdata(pdev, mmc); platform_set_drvdata(pdev, mmc);
ret = mmc_add_host(mmc); ret = mmc_add_host(mmc);
if (ret) if (ret)
......
...@@ -963,10 +963,9 @@ static bool filter(struct dma_chan *chan, void *param) ...@@ -963,10 +963,9 @@ static bool filter(struct dma_chan *chan, void *param)
return true; return true;
} }
static void mxcmci_watchdog(unsigned long data) static void mxcmci_watchdog(struct timer_list *t)
{ {
struct mmc_host *mmc = (struct mmc_host *)data; struct mxcmci_host *host = from_timer(host, t, watchdog);
struct mxcmci_host *host = mmc_priv(mmc);
struct mmc_request *req = host->req; struct mmc_request *req = host->req;
unsigned int stat = mxcmci_readl(host, MMC_REG_STATUS); unsigned int stat = mxcmci_readl(host, MMC_REG_STATUS);
...@@ -1075,7 +1074,7 @@ static int mxcmci_probe(struct platform_device *pdev) ...@@ -1075,7 +1074,7 @@ static int mxcmci_probe(struct platform_device *pdev)
dat3_card_detect = true; dat3_card_detect = true;
ret = mmc_regulator_get_supply(mmc); ret = mmc_regulator_get_supply(mmc);
if (ret == -EPROBE_DEFER) if (ret)
goto out_free; goto out_free;
if (!mmc->ocr_avail) { if (!mmc->ocr_avail) {
...@@ -1165,9 +1164,7 @@ static int mxcmci_probe(struct platform_device *pdev) ...@@ -1165,9 +1164,7 @@ static int mxcmci_probe(struct platform_device *pdev)
goto out_free_dma; goto out_free_dma;
} }
init_timer(&host->watchdog); timer_setup(&host->watchdog, mxcmci_watchdog, 0);
host->watchdog.function = &mxcmci_watchdog;
host->watchdog.data = (unsigned long)mmc;
mmc_add_host(mmc); mmc_add_host(mmc);
......
...@@ -625,9 +625,9 @@ static void mmc_omap_abort_command(struct work_struct *work) ...@@ -625,9 +625,9 @@ static void mmc_omap_abort_command(struct work_struct *work)
} }
static void static void
mmc_omap_cmd_timer(unsigned long data) mmc_omap_cmd_timer(struct timer_list *t)
{ {
struct mmc_omap_host *host = (struct mmc_omap_host *) data; struct mmc_omap_host *host = from_timer(host, t, cmd_abort_timer);
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&host->slot_lock, flags); spin_lock_irqsave(&host->slot_lock, flags);
...@@ -654,9 +654,9 @@ mmc_omap_sg_to_buf(struct mmc_omap_host *host) ...@@ -654,9 +654,9 @@ mmc_omap_sg_to_buf(struct mmc_omap_host *host)
} }
static void static void
mmc_omap_clk_timer(unsigned long data) mmc_omap_clk_timer(struct timer_list *t)
{ {
struct mmc_omap_host *host = (struct mmc_omap_host *) data; struct mmc_omap_host *host = from_timer(host, t, clk_timer);
mmc_omap_fclk_enable(host, 0); mmc_omap_fclk_enable(host, 0);
} }
...@@ -874,9 +874,9 @@ void omap_mmc_notify_cover_event(struct device *dev, int num, int is_closed) ...@@ -874,9 +874,9 @@ void omap_mmc_notify_cover_event(struct device *dev, int num, int is_closed)
tasklet_hi_schedule(&slot->cover_tasklet); tasklet_hi_schedule(&slot->cover_tasklet);
} }
static void mmc_omap_cover_timer(unsigned long arg) static void mmc_omap_cover_timer(struct timer_list *t)
{ {
struct mmc_omap_slot *slot = (struct mmc_omap_slot *) arg; struct mmc_omap_slot *slot = from_timer(slot, t, cover_timer);
tasklet_schedule(&slot->cover_tasklet); tasklet_schedule(&slot->cover_tasklet);
} }
...@@ -1264,8 +1264,7 @@ static int mmc_omap_new_slot(struct mmc_omap_host *host, int id) ...@@ -1264,8 +1264,7 @@ static int mmc_omap_new_slot(struct mmc_omap_host *host, int id)
mmc->max_seg_size = mmc->max_req_size; mmc->max_seg_size = mmc->max_req_size;
if (slot->pdata->get_cover_state != NULL) { if (slot->pdata->get_cover_state != NULL) {
setup_timer(&slot->cover_timer, mmc_omap_cover_timer, timer_setup(&slot->cover_timer, mmc_omap_cover_timer, 0);
(unsigned long)slot);
tasklet_init(&slot->cover_tasklet, mmc_omap_cover_handler, tasklet_init(&slot->cover_tasklet, mmc_omap_cover_handler,
(unsigned long)slot); (unsigned long)slot);
} }
...@@ -1352,11 +1351,10 @@ static int mmc_omap_probe(struct platform_device *pdev) ...@@ -1352,11 +1351,10 @@ static int mmc_omap_probe(struct platform_device *pdev)
INIT_WORK(&host->send_stop_work, mmc_omap_send_stop_work); INIT_WORK(&host->send_stop_work, mmc_omap_send_stop_work);
INIT_WORK(&host->cmd_abort_work, mmc_omap_abort_command); INIT_WORK(&host->cmd_abort_work, mmc_omap_abort_command);
setup_timer(&host->cmd_abort_timer, mmc_omap_cmd_timer, timer_setup(&host->cmd_abort_timer, mmc_omap_cmd_timer, 0);
(unsigned long) host);
spin_lock_init(&host->clk_lock); spin_lock_init(&host->clk_lock);
setup_timer(&host->clk_timer, mmc_omap_clk_timer, (unsigned long) host); timer_setup(&host->clk_timer, mmc_omap_clk_timer, 0);
spin_lock_init(&host->dma_lock); spin_lock_init(&host->dma_lock);
spin_lock_init(&host->slot_lock); spin_lock_init(&host->slot_lock);
......
...@@ -147,10 +147,6 @@ ...@@ -147,10 +147,6 @@
#define OMAP_MMC_MAX_CLOCK 52000000 #define OMAP_MMC_MAX_CLOCK 52000000
#define DRIVER_NAME "omap_hsmmc" #define DRIVER_NAME "omap_hsmmc"
#define VDD_1V8 1800000 /* 180000 uV */
#define VDD_3V0 3000000 /* 300000 uV */
#define VDD_165_195 (ffs(MMC_VDD_165_195) - 1)
/* /*
* One controller can have multiple slots, like on some omap boards using * One controller can have multiple slots, like on some omap boards using
* omap.c controller driver. Luckily this is not currently done on any known * omap.c controller driver. Luckily this is not currently done on any known
...@@ -308,8 +304,7 @@ static int omap_hsmmc_disable_supply(struct mmc_host *mmc) ...@@ -308,8 +304,7 @@ static int omap_hsmmc_disable_supply(struct mmc_host *mmc)
return ret; return ret;
} }
static int omap_hsmmc_set_pbias(struct omap_hsmmc_host *host, bool power_on, static int omap_hsmmc_set_pbias(struct omap_hsmmc_host *host, bool power_on)
int vdd)
{ {
int ret; int ret;
...@@ -317,17 +312,6 @@ static int omap_hsmmc_set_pbias(struct omap_hsmmc_host *host, bool power_on, ...@@ -317,17 +312,6 @@ static int omap_hsmmc_set_pbias(struct omap_hsmmc_host *host, bool power_on,
return 0; return 0;
if (power_on) { if (power_on) {
if (vdd <= VDD_165_195)
ret = regulator_set_voltage(host->pbias, VDD_1V8,
VDD_1V8);
else
ret = regulator_set_voltage(host->pbias, VDD_3V0,
VDD_3V0);
if (ret < 0) {
dev_err(host->dev, "pbias set voltage fail\n");
return ret;
}
if (host->pbias_enabled == 0) { if (host->pbias_enabled == 0) {
ret = regulator_enable(host->pbias); ret = regulator_enable(host->pbias);
if (ret) { if (ret) {
...@@ -350,8 +334,7 @@ static int omap_hsmmc_set_pbias(struct omap_hsmmc_host *host, bool power_on, ...@@ -350,8 +334,7 @@ static int omap_hsmmc_set_pbias(struct omap_hsmmc_host *host, bool power_on,
return 0; return 0;
} }
static int omap_hsmmc_set_power(struct omap_hsmmc_host *host, int power_on, static int omap_hsmmc_set_power(struct omap_hsmmc_host *host, int power_on)
int vdd)
{ {
struct mmc_host *mmc = host->mmc; struct mmc_host *mmc = host->mmc;
int ret = 0; int ret = 0;
...@@ -363,7 +346,7 @@ static int omap_hsmmc_set_power(struct omap_hsmmc_host *host, int power_on, ...@@ -363,7 +346,7 @@ static int omap_hsmmc_set_power(struct omap_hsmmc_host *host, int power_on,
if (IS_ERR(mmc->supply.vmmc)) if (IS_ERR(mmc->supply.vmmc))
return 0; return 0;
ret = omap_hsmmc_set_pbias(host, false, 0); ret = omap_hsmmc_set_pbias(host, false);
if (ret) if (ret)
return ret; return ret;
...@@ -385,7 +368,7 @@ static int omap_hsmmc_set_power(struct omap_hsmmc_host *host, int power_on, ...@@ -385,7 +368,7 @@ static int omap_hsmmc_set_power(struct omap_hsmmc_host *host, int power_on,
if (ret) if (ret)
return ret; return ret;
ret = omap_hsmmc_set_pbias(host, true, vdd); ret = omap_hsmmc_set_pbias(host, true);
if (ret) if (ret)
goto err_set_voltage; goto err_set_voltage;
} else { } else {
...@@ -462,7 +445,7 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) ...@@ -462,7 +445,7 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
ret = mmc_regulator_get_supply(mmc); ret = mmc_regulator_get_supply(mmc);
if (ret == -EPROBE_DEFER) if (ret)
return ret; return ret;
/* Allow an aux regulator */ /* Allow an aux regulator */
...@@ -1220,11 +1203,11 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd) ...@@ -1220,11 +1203,11 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
clk_disable_unprepare(host->dbclk); clk_disable_unprepare(host->dbclk);
/* Turn the power off */ /* Turn the power off */
ret = omap_hsmmc_set_power(host, 0, 0); ret = omap_hsmmc_set_power(host, 0);
/* Turn the power ON with given VDD 1.8 or 3.0v */ /* Turn the power ON with given VDD 1.8 or 3.0v */
if (!ret) if (!ret)
ret = omap_hsmmc_set_power(host, 1, vdd); ret = omap_hsmmc_set_power(host, 1);
if (host->dbclk) if (host->dbclk)
clk_prepare_enable(host->dbclk); clk_prepare_enable(host->dbclk);
...@@ -1621,10 +1604,10 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -1621,10 +1604,10 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (ios->power_mode != host->power_mode) { if (ios->power_mode != host->power_mode) {
switch (ios->power_mode) { switch (ios->power_mode) {
case MMC_POWER_OFF: case MMC_POWER_OFF:
omap_hsmmc_set_power(host, 0, 0); omap_hsmmc_set_power(host, 0);
break; break;
case MMC_POWER_UP: case MMC_POWER_UP:
omap_hsmmc_set_power(host, 1, ios->vdd); omap_hsmmc_set_power(host, 1);
break; break;
case MMC_POWER_ON: case MMC_POWER_ON:
do_send_init_stream = 1; do_send_init_stream = 1;
......
...@@ -88,6 +88,7 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = { ...@@ -88,6 +88,7 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = { static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
{ .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, }, { .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, },
{ .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, }, { .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, },
{ .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, renesas_sdhi_internal_dmac_of_match); MODULE_DEVICE_TABLE(of, renesas_sdhi_internal_dmac_of_match);
......
...@@ -91,7 +91,6 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = { ...@@ -91,7 +91,6 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
}; };
static const struct of_device_id renesas_sdhi_sys_dmac_of_match[] = { static const struct of_device_id renesas_sdhi_sys_dmac_of_match[] = {
{ .compatible = "renesas,sdhi-shmobile" },
{ .compatible = "renesas,sdhi-sh73a0", .data = &of_default_cfg, }, { .compatible = "renesas,sdhi-sh73a0", .data = &of_default_cfg, },
{ .compatible = "renesas,sdhi-r8a73a4", .data = &of_default_cfg, }, { .compatible = "renesas,sdhi-r8a73a4", .data = &of_default_cfg, },
{ .compatible = "renesas,sdhi-r8a7740", .data = &of_default_cfg, }, { .compatible = "renesas,sdhi-r8a7740", .data = &of_default_cfg, },
...@@ -107,6 +106,10 @@ static const struct of_device_id renesas_sdhi_sys_dmac_of_match[] = { ...@@ -107,6 +106,10 @@ static const struct of_device_id renesas_sdhi_sys_dmac_of_match[] = {
{ .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, }, { .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, },
{ .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, }, { .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, },
{ .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, }, { .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, },
{ .compatible = "renesas,rcar-gen1-sdhi", .data = &of_rcar_gen1_compatible, },
{ .compatible = "renesas,rcar-gen2-sdhi", .data = &of_rcar_gen2_compatible, },
{ .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, },
{ .compatible = "renesas,sdhi-shmobile" },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, renesas_sdhi_sys_dmac_of_match); MODULE_DEVICE_TABLE(of, renesas_sdhi_sys_dmac_of_match);
......
...@@ -618,29 +618,22 @@ static int sd_change_phase(struct realtek_pci_sdmmc *host, ...@@ -618,29 +618,22 @@ static int sd_change_phase(struct realtek_pci_sdmmc *host,
u8 sample_point, bool rx) u8 sample_point, bool rx)
{ {
struct rtsx_pcr *pcr = host->pcr; struct rtsx_pcr *pcr = host->pcr;
int err;
dev_dbg(sdmmc_dev(host), "%s(%s): sample_point = %d\n", dev_dbg(sdmmc_dev(host), "%s(%s): sample_point = %d\n",
__func__, rx ? "RX" : "TX", sample_point); __func__, rx ? "RX" : "TX", sample_point);
rtsx_pci_init_cmd(pcr); rtsx_pci_write_register(pcr, CLK_CTL, CHANGE_CLK, CHANGE_CLK);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CHANGE_CLK, CHANGE_CLK);
if (rx) if (rx)
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, rtsx_pci_write_register(pcr, SD_VPRX_CTL,
SD_VPRX_CTL, 0x1F, sample_point); PHASE_SELECT_MASK, sample_point);
else else
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, rtsx_pci_write_register(pcr, SD_VPTX_CTL,
SD_VPTX_CTL, 0x1F, sample_point); PHASE_SELECT_MASK, sample_point);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0); rtsx_pci_write_register(pcr, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, rtsx_pci_write_register(pcr, SD_VPCLK0_CTL, PHASE_NOT_RESET,
PHASE_NOT_RESET, PHASE_NOT_RESET); PHASE_NOT_RESET);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CHANGE_CLK, 0); rtsx_pci_write_register(pcr, CLK_CTL, CHANGE_CLK, 0);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1, SD_ASYNC_FIFO_NOT_RST, 0); rtsx_pci_write_register(pcr, SD_CFG1, SD_ASYNC_FIFO_NOT_RST, 0);
err = rtsx_pci_send_cmd(pcr, 100);
if (err < 0)
return err;
return 0; return 0;
} }
...@@ -708,10 +701,12 @@ static int sd_tuning_rx_cmd(struct realtek_pci_sdmmc *host, ...@@ -708,10 +701,12 @@ static int sd_tuning_rx_cmd(struct realtek_pci_sdmmc *host,
{ {
int err; int err;
struct mmc_command cmd = {}; struct mmc_command cmd = {};
struct rtsx_pcr *pcr = host->pcr;
err = sd_change_phase(host, sample_point, true); sd_change_phase(host, sample_point, true);
if (err < 0)
return err; rtsx_pci_write_register(pcr, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN,
SD_RSP_80CLK_TIMEOUT_EN);
cmd.opcode = opcode; cmd.opcode = opcode;
err = sd_read_data(host, &cmd, 0x40, NULL, 0, 100); err = sd_read_data(host, &cmd, 0x40, NULL, 0, 100);
...@@ -719,9 +714,12 @@ static int sd_tuning_rx_cmd(struct realtek_pci_sdmmc *host, ...@@ -719,9 +714,12 @@ static int sd_tuning_rx_cmd(struct realtek_pci_sdmmc *host,
/* Wait till SD DATA IDLE */ /* Wait till SD DATA IDLE */
sd_wait_data_idle(host); sd_wait_data_idle(host);
sd_clear_error(host); sd_clear_error(host);
rtsx_pci_write_register(pcr, SD_CFG3,
SD_RSP_80CLK_TIMEOUT_EN, 0);
return err; return err;
} }
rtsx_pci_write_register(pcr, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN, 0);
return 0; return 0;
} }
......
...@@ -73,6 +73,7 @@ struct sdhci_acpi_slot { ...@@ -73,6 +73,7 @@ struct sdhci_acpi_slot {
unsigned int caps2; unsigned int caps2;
mmc_pm_flag_t pm_caps; mmc_pm_flag_t pm_caps;
unsigned int flags; unsigned int flags;
size_t priv_size;
int (*probe_slot)(struct platform_device *, const char *, const char *); int (*probe_slot)(struct platform_device *, const char *, const char *);
int (*remove_slot)(struct platform_device *); int (*remove_slot)(struct platform_device *);
}; };
...@@ -82,13 +83,118 @@ struct sdhci_acpi_host { ...@@ -82,13 +83,118 @@ struct sdhci_acpi_host {
const struct sdhci_acpi_slot *slot; const struct sdhci_acpi_slot *slot;
struct platform_device *pdev; struct platform_device *pdev;
bool use_runtime_pm; bool use_runtime_pm;
unsigned long private[0] ____cacheline_aligned;
}; };
static inline void *sdhci_acpi_priv(struct sdhci_acpi_host *c)
{
return (void *)c->private;
}
static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag) static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag)
{ {
return c->slot && (c->slot->flags & flag); return c->slot && (c->slot->flags & flag);
} }
enum {
INTEL_DSM_FNS = 0,
INTEL_DSM_V18_SWITCH = 3,
INTEL_DSM_V33_SWITCH = 4,
};
struct intel_host {
u32 dsm_fns;
};
static const guid_t intel_dsm_guid =
GUID_INIT(0xF6C13EA5, 0x65CD, 0x461F,
0xAB, 0x7A, 0x29, 0xF7, 0xE8, 0xD5, 0xBD, 0x61);
static int __intel_dsm(struct intel_host *intel_host, struct device *dev,
unsigned int fn, u32 *result)
{
union acpi_object *obj;
int err = 0;
obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), &intel_dsm_guid, 0, fn, NULL);
if (!obj)
return -EOPNOTSUPP;
if (obj->type == ACPI_TYPE_INTEGER) {
*result = obj->integer.value;
} else if (obj->type == ACPI_TYPE_BUFFER && obj->buffer.length > 0) {
size_t len = min_t(size_t, obj->buffer.length, 4);
*result = 0;
memcpy(result, obj->buffer.pointer, len);
} else {
dev_err(dev, "%s DSM fn %u obj->type %d obj->buffer.length %d\n",
__func__, fn, obj->type, obj->buffer.length);
err = -EINVAL;
}
ACPI_FREE(obj);
return err;
}
static int intel_dsm(struct intel_host *intel_host, struct device *dev,
unsigned int fn, u32 *result)
{
if (fn > 31 || !(intel_host->dsm_fns & (1 << fn)))
return -EOPNOTSUPP;
return __intel_dsm(intel_host, dev, fn, result);
}
static void intel_dsm_init(struct intel_host *intel_host, struct device *dev,
struct mmc_host *mmc)
{
int err;
err = __intel_dsm(intel_host, dev, INTEL_DSM_FNS, &intel_host->dsm_fns);
if (err) {
pr_debug("%s: DSM not supported, error %d\n",
mmc_hostname(mmc), err);
return;
}
pr_debug("%s: DSM function mask %#x\n",
mmc_hostname(mmc), intel_host->dsm_fns);
}
static int intel_start_signal_voltage_switch(struct mmc_host *mmc,
struct mmc_ios *ios)
{
struct device *dev = mmc_dev(mmc);
struct sdhci_acpi_host *c = dev_get_drvdata(dev);
struct intel_host *intel_host = sdhci_acpi_priv(c);
unsigned int fn;
u32 result = 0;
int err;
err = sdhci_start_signal_voltage_switch(mmc, ios);
if (err)
return err;
switch (ios->signal_voltage) {
case MMC_SIGNAL_VOLTAGE_330:
fn = INTEL_DSM_V33_SWITCH;
break;
case MMC_SIGNAL_VOLTAGE_180:
fn = INTEL_DSM_V18_SWITCH;
break;
default:
return 0;
}
err = intel_dsm(intel_host, dev, fn, &result);
pr_debug("%s: %s DSM fn %u error %d result %u\n",
mmc_hostname(mmc), __func__, fn, err, result);
return 0;
}
static void sdhci_acpi_int_hw_reset(struct sdhci_host *host) static void sdhci_acpi_int_hw_reset(struct sdhci_host *host)
{ {
u8 reg; u8 reg;
...@@ -269,56 +375,26 @@ static int bxt_get_cd(struct mmc_host *mmc) ...@@ -269,56 +375,26 @@ static int bxt_get_cd(struct mmc_host *mmc)
return ret; return ret;
} }
static int sdhci_acpi_emmc_probe_slot(struct platform_device *pdev, static int intel_probe_slot(struct platform_device *pdev, const char *hid,
const char *hid, const char *uid) const char *uid)
{ {
struct sdhci_acpi_host *c = platform_get_drvdata(pdev); struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
struct sdhci_host *host; struct intel_host *intel_host = sdhci_acpi_priv(c);
struct sdhci_host *host = c->host;
if (!c || !c->host)
return 0;
host = c->host;
/* Platform specific code during emmc probe slot goes here */
if (hid && uid && !strcmp(hid, "80860F14") && !strcmp(uid, "1") && if (hid && uid && !strcmp(hid, "80860F14") && !strcmp(uid, "1") &&
sdhci_readl(host, SDHCI_CAPABILITIES) == 0x446cc8b2 && sdhci_readl(host, SDHCI_CAPABILITIES) == 0x446cc8b2 &&
sdhci_readl(host, SDHCI_CAPABILITIES_1) == 0x00000807) sdhci_readl(host, SDHCI_CAPABILITIES_1) == 0x00000807)
host->timeout_clk = 1000; /* 1000 kHz i.e. 1 MHz */ host->timeout_clk = 1000; /* 1000 kHz i.e. 1 MHz */
return 0;
}
static int sdhci_acpi_sdio_probe_slot(struct platform_device *pdev,
const char *hid, const char *uid)
{
struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
if (!c || !c->host)
return 0;
/* Platform specific code during sdio probe slot goes here */
return 0;
}
static int sdhci_acpi_sd_probe_slot(struct platform_device *pdev,
const char *hid, const char *uid)
{
struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
struct sdhci_host *host;
if (!c || !c->host || !c->slot)
return 0;
host = c->host;
/* Platform specific code during sd probe slot goes here */
if (hid && !strcmp(hid, "80865ACA")) if (hid && !strcmp(hid, "80865ACA"))
host->mmc_host_ops.get_cd = bxt_get_cd; host->mmc_host_ops.get_cd = bxt_get_cd;
intel_dsm_init(intel_host, &pdev->dev, host->mmc);
host->mmc_host_ops.start_signal_voltage_switch =
intel_start_signal_voltage_switch;
return 0; return 0;
} }
...@@ -332,7 +408,8 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = { ...@@ -332,7 +408,8 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
SDHCI_QUIRK2_STOP_WITH_TC | SDHCI_QUIRK2_STOP_WITH_TC |
SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400, SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400,
.probe_slot = sdhci_acpi_emmc_probe_slot, .probe_slot = intel_probe_slot,
.priv_size = sizeof(struct intel_host),
}; };
static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = { static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
...@@ -343,7 +420,8 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = { ...@@ -343,7 +420,8 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
MMC_CAP_WAIT_WHILE_BUSY, MMC_CAP_WAIT_WHILE_BUSY,
.flags = SDHCI_ACPI_RUNTIME_PM, .flags = SDHCI_ACPI_RUNTIME_PM,
.pm_caps = MMC_PM_KEEP_POWER, .pm_caps = MMC_PM_KEEP_POWER,
.probe_slot = sdhci_acpi_sdio_probe_slot, .probe_slot = intel_probe_slot,
.priv_size = sizeof(struct intel_host),
}; };
static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = { static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
...@@ -353,7 +431,8 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = { ...@@ -353,7 +431,8 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
.quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON | .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |
SDHCI_QUIRK2_STOP_WITH_TC, SDHCI_QUIRK2_STOP_WITH_TC,
.caps = MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_AGGRESSIVE_PM, .caps = MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_AGGRESSIVE_PM,
.probe_slot = sdhci_acpi_sd_probe_slot, .probe_slot = intel_probe_slot,
.priv_size = sizeof(struct intel_host),
}; };
static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd_3v = { static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd_3v = {
...@@ -429,11 +508,13 @@ static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(const char *hid, ...@@ -429,11 +508,13 @@ static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(const char *hid,
static int sdhci_acpi_probe(struct platform_device *pdev) static int sdhci_acpi_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
const struct sdhci_acpi_slot *slot;
struct acpi_device *device, *child; struct acpi_device *device, *child;
struct sdhci_acpi_host *c; struct sdhci_acpi_host *c;
struct sdhci_host *host; struct sdhci_host *host;
struct resource *iomem; struct resource *iomem;
resource_size_t len; resource_size_t len;
size_t priv_size;
const char *hid; const char *hid;
const char *uid; const char *uid;
int err; int err;
...@@ -443,7 +524,9 @@ static int sdhci_acpi_probe(struct platform_device *pdev) ...@@ -443,7 +524,9 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
return -ENODEV; return -ENODEV;
hid = acpi_device_hid(device); hid = acpi_device_hid(device);
uid = device->pnp.unique_id; uid = acpi_device_uid(device);
slot = sdhci_acpi_get_slot(hid, uid);
/* Power on the SDHCI controller and its children */ /* Power on the SDHCI controller and its children */
acpi_device_fix_up_power(device); acpi_device_fix_up_power(device);
...@@ -467,13 +550,14 @@ static int sdhci_acpi_probe(struct platform_device *pdev) ...@@ -467,13 +550,14 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
if (!devm_request_mem_region(dev, iomem->start, len, dev_name(dev))) if (!devm_request_mem_region(dev, iomem->start, len, dev_name(dev)))
return -ENOMEM; return -ENOMEM;
host = sdhci_alloc_host(dev, sizeof(struct sdhci_acpi_host)); priv_size = slot ? slot->priv_size : 0;
host = sdhci_alloc_host(dev, sizeof(struct sdhci_acpi_host) + priv_size);
if (IS_ERR(host)) if (IS_ERR(host))
return PTR_ERR(host); return PTR_ERR(host);
c = sdhci_priv(host); c = sdhci_priv(host);
c->host = host; c->host = host;
c->slot = sdhci_acpi_get_slot(hid, uid); c->slot = slot;
c->pdev = pdev; c->pdev = pdev;
c->use_runtime_pm = sdhci_acpi_flag(c, SDHCI_ACPI_RUNTIME_PM); c->use_runtime_pm = sdhci_acpi_flag(c, SDHCI_ACPI_RUNTIME_PM);
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <linux/bitfield.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -27,15 +28,14 @@ ...@@ -27,15 +28,14 @@
#define SDHCI_CDNS_HRS04_ACK BIT(26) #define SDHCI_CDNS_HRS04_ACK BIT(26)
#define SDHCI_CDNS_HRS04_RD BIT(25) #define SDHCI_CDNS_HRS04_RD BIT(25)
#define SDHCI_CDNS_HRS04_WR BIT(24) #define SDHCI_CDNS_HRS04_WR BIT(24)
#define SDHCI_CDNS_HRS04_RDATA_SHIFT 16 #define SDHCI_CDNS_HRS04_RDATA GENMASK(23, 16)
#define SDHCI_CDNS_HRS04_WDATA_SHIFT 8 #define SDHCI_CDNS_HRS04_WDATA GENMASK(15, 8)
#define SDHCI_CDNS_HRS04_ADDR_SHIFT 0 #define SDHCI_CDNS_HRS04_ADDR GENMASK(5, 0)
#define SDHCI_CDNS_HRS06 0x18 /* eMMC control */ #define SDHCI_CDNS_HRS06 0x18 /* eMMC control */
#define SDHCI_CDNS_HRS06_TUNE_UP BIT(15) #define SDHCI_CDNS_HRS06_TUNE_UP BIT(15)
#define SDHCI_CDNS_HRS06_TUNE_SHIFT 8 #define SDHCI_CDNS_HRS06_TUNE GENMASK(13, 8)
#define SDHCI_CDNS_HRS06_TUNE_MASK 0x3f #define SDHCI_CDNS_HRS06_MODE GENMASK(2, 0)
#define SDHCI_CDNS_HRS06_MODE_MASK 0x7
#define SDHCI_CDNS_HRS06_MODE_SD 0x0 #define SDHCI_CDNS_HRS06_MODE_SD 0x0
#define SDHCI_CDNS_HRS06_MODE_MMC_SDR 0x2 #define SDHCI_CDNS_HRS06_MODE_MMC_SDR 0x2
#define SDHCI_CDNS_HRS06_MODE_MMC_DDR 0x3 #define SDHCI_CDNS_HRS06_MODE_MMC_DDR 0x3
...@@ -105,8 +105,8 @@ static int sdhci_cdns_write_phy_reg(struct sdhci_cdns_priv *priv, ...@@ -105,8 +105,8 @@ static int sdhci_cdns_write_phy_reg(struct sdhci_cdns_priv *priv,
u32 tmp; u32 tmp;
int ret; int ret;
tmp = (data << SDHCI_CDNS_HRS04_WDATA_SHIFT) | tmp = FIELD_PREP(SDHCI_CDNS_HRS04_WDATA, data) |
(addr << SDHCI_CDNS_HRS04_ADDR_SHIFT); FIELD_PREP(SDHCI_CDNS_HRS04_ADDR, addr);
writel(tmp, reg); writel(tmp, reg);
tmp |= SDHCI_CDNS_HRS04_WR; tmp |= SDHCI_CDNS_HRS04_WR;
...@@ -189,8 +189,8 @@ static void sdhci_cdns_set_emmc_mode(struct sdhci_cdns_priv *priv, u32 mode) ...@@ -189,8 +189,8 @@ static void sdhci_cdns_set_emmc_mode(struct sdhci_cdns_priv *priv, u32 mode)
/* The speed mode for eMMC is selected by HRS06 register */ /* The speed mode for eMMC is selected by HRS06 register */
tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS06); tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS06);
tmp &= ~SDHCI_CDNS_HRS06_MODE_MASK; tmp &= ~SDHCI_CDNS_HRS06_MODE;
tmp |= mode; tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_MODE, mode);
writel(tmp, priv->hrs_addr + SDHCI_CDNS_HRS06); writel(tmp, priv->hrs_addr + SDHCI_CDNS_HRS06);
} }
...@@ -199,7 +199,7 @@ static u32 sdhci_cdns_get_emmc_mode(struct sdhci_cdns_priv *priv) ...@@ -199,7 +199,7 @@ static u32 sdhci_cdns_get_emmc_mode(struct sdhci_cdns_priv *priv)
u32 tmp; u32 tmp;
tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS06); tmp = readl(priv->hrs_addr + SDHCI_CDNS_HRS06);
return tmp & SDHCI_CDNS_HRS06_MODE_MASK; return FIELD_GET(SDHCI_CDNS_HRS06_MODE, tmp);
} }
static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host, static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host,
...@@ -254,12 +254,12 @@ static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val) ...@@ -254,12 +254,12 @@ static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
void __iomem *reg = priv->hrs_addr + SDHCI_CDNS_HRS06; void __iomem *reg = priv->hrs_addr + SDHCI_CDNS_HRS06;
u32 tmp; u32 tmp;
if (WARN_ON(val > SDHCI_CDNS_HRS06_TUNE_MASK)) if (WARN_ON(!FIELD_FIT(SDHCI_CDNS_HRS06_TUNE, val)))
return -EINVAL; return -EINVAL;
tmp = readl(reg); tmp = readl(reg);
tmp &= ~(SDHCI_CDNS_HRS06_TUNE_MASK << SDHCI_CDNS_HRS06_TUNE_SHIFT); tmp &= ~SDHCI_CDNS_HRS06_TUNE;
tmp |= val << SDHCI_CDNS_HRS06_TUNE_SHIFT; tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_TUNE, val);
tmp |= SDHCI_CDNS_HRS06_TUNE_UP; tmp |= SDHCI_CDNS_HRS06_TUNE_UP;
writel(tmp, reg); writel(tmp, reg);
......
...@@ -123,14 +123,17 @@ ...@@ -123,14 +123,17 @@
#define CMUX_SHIFT_PHASE_MASK (7 << CMUX_SHIFT_PHASE_SHIFT) #define CMUX_SHIFT_PHASE_MASK (7 << CMUX_SHIFT_PHASE_SHIFT)
#define MSM_MMC_AUTOSUSPEND_DELAY_MS 50 #define MSM_MMC_AUTOSUSPEND_DELAY_MS 50
/* Timeout value to avoid infinite waiting for pwr_irq */
#define MSM_PWR_IRQ_TIMEOUT_MS 5000
struct sdhci_msm_host { struct sdhci_msm_host {
struct platform_device *pdev; struct platform_device *pdev;
void __iomem *core_mem; /* MSM SDCC mapped address */ void __iomem *core_mem; /* MSM SDCC mapped address */
int pwr_irq; /* power irq */ int pwr_irq; /* power irq */
struct clk *clk; /* main SD/MMC bus clock */
struct clk *pclk; /* SDHC peripheral bus clock */
struct clk *bus_clk; /* SDHC bus voter clock */ struct clk *bus_clk; /* SDHC bus voter clock */
struct clk *xo_clk; /* TCXO clk needed for FLL feature of cm_dll*/ struct clk *xo_clk; /* TCXO clk needed for FLL feature of cm_dll*/
struct clk_bulk_data bulk_clks[4]; /* core, iface, cal, sleep clocks */
unsigned long clk_rate; unsigned long clk_rate;
struct mmc_host *mmc; struct mmc_host *mmc;
bool use_14lpp_dll_reset; bool use_14lpp_dll_reset;
...@@ -138,6 +141,10 @@ struct sdhci_msm_host { ...@@ -138,6 +141,10 @@ struct sdhci_msm_host {
bool calibration_done; bool calibration_done;
u8 saved_tuning_phase; u8 saved_tuning_phase;
bool use_cdclp533; bool use_cdclp533;
u32 curr_pwr_state;
u32 curr_io_level;
wait_queue_head_t pwr_irq_wait;
bool pwr_irq_flag;
}; };
static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host, static unsigned int msm_get_clock_rate_for_bus_mode(struct sdhci_host *host,
...@@ -164,10 +171,11 @@ static void msm_set_clock_rate_for_bus_mode(struct sdhci_host *host, ...@@ -164,10 +171,11 @@ static void msm_set_clock_rate_for_bus_mode(struct sdhci_host *host,
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
struct mmc_ios curr_ios = host->mmc->ios; struct mmc_ios curr_ios = host->mmc->ios;
struct clk *core_clk = msm_host->bulk_clks[0].clk;
int rc; int rc;
clock = msm_get_clock_rate_for_bus_mode(host, clock); clock = msm_get_clock_rate_for_bus_mode(host, clock);
rc = clk_set_rate(msm_host->clk, clock); rc = clk_set_rate(core_clk, clock);
if (rc) { if (rc) {
pr_err("%s: Failed to set clock at rate %u at timing %d\n", pr_err("%s: Failed to set clock at rate %u at timing %d\n",
mmc_hostname(host->mmc), clock, mmc_hostname(host->mmc), clock,
...@@ -176,7 +184,7 @@ static void msm_set_clock_rate_for_bus_mode(struct sdhci_host *host, ...@@ -176,7 +184,7 @@ static void msm_set_clock_rate_for_bus_mode(struct sdhci_host *host,
} }
msm_host->clk_rate = clock; msm_host->clk_rate = clock;
pr_debug("%s: Setting clock at rate %lu at timing %d\n", pr_debug("%s: Setting clock at rate %lu at timing %d\n",
mmc_hostname(host->mmc), clk_get_rate(msm_host->clk), mmc_hostname(host->mmc), clk_get_rate(core_clk),
curr_ios.timing); curr_ios.timing);
} }
...@@ -995,21 +1003,142 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host, ...@@ -995,21 +1003,142 @@ static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,
sdhci_msm_hs400(host, &mmc->ios); sdhci_msm_hs400(host, &mmc->ios);
} }
static void sdhci_msm_voltage_switch(struct sdhci_host *host) static inline void sdhci_msm_init_pwr_irq_wait(struct sdhci_msm_host *msm_host)
{
init_waitqueue_head(&msm_host->pwr_irq_wait);
}
static inline void sdhci_msm_complete_pwr_irq_wait(
struct sdhci_msm_host *msm_host)
{
wake_up(&msm_host->pwr_irq_wait);
}
/*
* sdhci_msm_check_power_status API should be called when registers writes
* which can toggle sdhci IO bus ON/OFF or change IO lines HIGH/LOW happens.
* To what state the register writes will change the IO lines should be passed
* as the argument req_type. This API will check whether the IO line's state
* is already the expected state and will wait for power irq only if
* power irq is expected to be trigerred based on the current IO line state
* and expected IO line state.
*/
static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
bool done = false;
pr_debug("%s: %s: request %d curr_pwr_state %x curr_io_level %x\n",
mmc_hostname(host->mmc), __func__, req_type,
msm_host->curr_pwr_state, msm_host->curr_io_level);
/*
* The IRQ for request type IO High/LOW will be generated when -
* there is a state change in 1.8V enable bit (bit 3) of
* SDHCI_HOST_CONTROL2 register. The reset state of that bit is 0
* which indicates 3.3V IO voltage. So, when MMC core layer tries
* to set it to 3.3V before card detection happens, the
* IRQ doesn't get triggered as there is no state change in this bit.
* The driver already handles this case by changing the IO voltage
* level to high as part of controller power up sequence. Hence, check
* for host->pwr to handle a case where IO voltage high request is
* issued even before controller power up.
*/
if ((req_type & REQ_IO_HIGH) && !host->pwr) {
pr_debug("%s: do not wait for power IRQ that never comes, req_type: %d\n",
mmc_hostname(host->mmc), req_type);
return;
}
if ((req_type & msm_host->curr_pwr_state) ||
(req_type & msm_host->curr_io_level))
done = true;
/*
* This is needed here to handle cases where register writes will
* not change the current bus state or io level of the controller.
* In this case, no power irq will be triggerred and we should
* not wait.
*/
if (!done) {
if (!wait_event_timeout(msm_host->pwr_irq_wait,
msm_host->pwr_irq_flag,
msecs_to_jiffies(MSM_PWR_IRQ_TIMEOUT_MS)))
dev_warn(&msm_host->pdev->dev,
"%s: pwr_irq for req: (%d) timed out\n",
mmc_hostname(host->mmc), req_type);
}
pr_debug("%s: %s: request %d done\n", mmc_hostname(host->mmc),
__func__, req_type);
}
static void sdhci_msm_dump_pwr_ctrl_regs(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
pr_err("%s: PWRCTL_STATUS: 0x%08x | PWRCTL_MASK: 0x%08x | PWRCTL_CTL: 0x%08x\n",
mmc_hostname(host->mmc),
readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS),
readl_relaxed(msm_host->core_mem + CORE_PWRCTL_MASK),
readl_relaxed(msm_host->core_mem + CORE_PWRCTL_CTL));
}
static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
u32 irq_status, irq_ack = 0; u32 irq_status, irq_ack = 0;
int retry = 10;
int pwr_state = 0, io_level = 0;
irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS); irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
irq_status &= INT_MASK; irq_status &= INT_MASK;
writel_relaxed(irq_status, msm_host->core_mem + CORE_PWRCTL_CLEAR); writel_relaxed(irq_status, msm_host->core_mem + CORE_PWRCTL_CLEAR);
if (irq_status & (CORE_PWRCTL_BUS_ON | CORE_PWRCTL_BUS_OFF)) /*
* There is a rare HW scenario where the first clear pulse could be
* lost when actual reset and clear/read of status register is
* happening at a time. Hence, retry for at least 10 times to make
* sure status register is cleared. Otherwise, this will result in
* a spurious power IRQ resulting in system instability.
*/
while (irq_status & readl_relaxed(msm_host->core_mem +
CORE_PWRCTL_STATUS)) {
if (retry == 0) {
pr_err("%s: Timedout clearing (0x%x) pwrctl status register\n",
mmc_hostname(host->mmc), irq_status);
sdhci_msm_dump_pwr_ctrl_regs(host);
WARN_ON(1);
break;
}
writel_relaxed(irq_status,
msm_host->core_mem + CORE_PWRCTL_CLEAR);
retry--;
udelay(10);
}
/* Handle BUS ON/OFF*/
if (irq_status & CORE_PWRCTL_BUS_ON) {
pwr_state = REQ_BUS_ON;
io_level = REQ_IO_HIGH;
irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
}
if (irq_status & CORE_PWRCTL_BUS_OFF) {
pwr_state = REQ_BUS_OFF;
io_level = REQ_IO_LOW;
irq_ack |= CORE_PWRCTL_BUS_SUCCESS; irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
if (irq_status & (CORE_PWRCTL_IO_LOW | CORE_PWRCTL_IO_HIGH)) }
/* Handle IO LOW/HIGH */
if (irq_status & CORE_PWRCTL_IO_LOW) {
io_level = REQ_IO_LOW;
irq_ack |= CORE_PWRCTL_IO_SUCCESS;
}
if (irq_status & CORE_PWRCTL_IO_HIGH) {
io_level = REQ_IO_HIGH;
irq_ack |= CORE_PWRCTL_IO_SUCCESS; irq_ack |= CORE_PWRCTL_IO_SUCCESS;
}
/* /*
* The driver has to acknowledge the interrupt, switch voltages and * The driver has to acknowledge the interrupt, switch voltages and
...@@ -1017,13 +1146,27 @@ static void sdhci_msm_voltage_switch(struct sdhci_host *host) ...@@ -1017,13 +1146,27 @@ static void sdhci_msm_voltage_switch(struct sdhci_host *host)
* switches are handled by the sdhci core, so just report success. * switches are handled by the sdhci core, so just report success.
*/ */
writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL); writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL);
if (pwr_state)
msm_host->curr_pwr_state = pwr_state;
if (io_level)
msm_host->curr_io_level = io_level;
pr_debug("%s: %s: Handled IRQ(%d), irq_status=0x%x, ack=0x%x\n",
mmc_hostname(msm_host->mmc), __func__, irq, irq_status,
irq_ack);
} }
static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data) static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
{ {
struct sdhci_host *host = (struct sdhci_host *)data; struct sdhci_host *host = (struct sdhci_host *)data;
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
sdhci_msm_handle_pwr_irq(host, irq);
msm_host->pwr_irq_flag = 1;
sdhci_msm_complete_pwr_irq_wait(msm_host);
sdhci_msm_voltage_switch(host);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -1032,8 +1175,9 @@ static unsigned int sdhci_msm_get_max_clock(struct sdhci_host *host) ...@@ -1032,8 +1175,9 @@ static unsigned int sdhci_msm_get_max_clock(struct sdhci_host *host)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
struct clk *core_clk = msm_host->bulk_clks[0].clk;
return clk_round_rate(msm_host->clk, ULONG_MAX); return clk_round_rate(core_clk, ULONG_MAX);
} }
static unsigned int sdhci_msm_get_min_clock(struct sdhci_host *host) static unsigned int sdhci_msm_get_min_clock(struct sdhci_host *host)
...@@ -1092,6 +1236,69 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) ...@@ -1092,6 +1236,69 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
__sdhci_msm_set_clock(host, clock); __sdhci_msm_set_clock(host, clock);
} }
/*
* Platform specific register write functions. This is so that, if any
* register write needs to be followed up by platform specific actions,
* they can be added here. These functions can go to sleep when writes
* to certain registers are done.
* These functions are relying on sdhci_set_ios not using spinlock.
*/
static int __sdhci_msm_check_write(struct sdhci_host *host, u16 val, int reg)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
u32 req_type = 0;
switch (reg) {
case SDHCI_HOST_CONTROL2:
req_type = (val & SDHCI_CTRL_VDD_180) ? REQ_IO_LOW :
REQ_IO_HIGH;
break;
case SDHCI_SOFTWARE_RESET:
if (host->pwr && (val & SDHCI_RESET_ALL))
req_type = REQ_BUS_OFF;
break;
case SDHCI_POWER_CONTROL:
req_type = !val ? REQ_BUS_OFF : REQ_BUS_ON;
break;
}
if (req_type) {
msm_host->pwr_irq_flag = 0;
/*
* Since this register write may trigger a power irq, ensure
* all previous register writes are complete by this point.
*/
mb();
}
return req_type;
}
/* This function may sleep*/
static void sdhci_msm_writew(struct sdhci_host *host, u16 val, int reg)
{
u32 req_type = 0;
req_type = __sdhci_msm_check_write(host, val, reg);
writew_relaxed(val, host->ioaddr + reg);
if (req_type)
sdhci_msm_check_power_status(host, req_type);
}
/* This function may sleep*/
static void sdhci_msm_writeb(struct sdhci_host *host, u8 val, int reg)
{
u32 req_type = 0;
req_type = __sdhci_msm_check_write(host, val, reg);
writeb_relaxed(val, host->ioaddr + reg);
if (req_type)
sdhci_msm_check_power_status(host, req_type);
}
static const struct of_device_id sdhci_msm_dt_match[] = { static const struct of_device_id sdhci_msm_dt_match[] = {
{ .compatible = "qcom,sdhci-msm-v4" }, { .compatible = "qcom,sdhci-msm-v4" },
{}, {},
...@@ -1106,7 +1313,8 @@ static const struct sdhci_ops sdhci_msm_ops = { ...@@ -1106,7 +1313,8 @@ static const struct sdhci_ops sdhci_msm_ops = {
.get_max_clock = sdhci_msm_get_max_clock, .get_max_clock = sdhci_msm_get_max_clock,
.set_bus_width = sdhci_set_bus_width, .set_bus_width = sdhci_set_bus_width,
.set_uhs_signaling = sdhci_msm_set_uhs_signaling, .set_uhs_signaling = sdhci_msm_set_uhs_signaling,
.voltage_switch = sdhci_msm_voltage_switch, .write_w = sdhci_msm_writew,
.write_b = sdhci_msm_writeb,
}; };
static const struct sdhci_pltfm_data sdhci_msm_pdata = { static const struct sdhci_pltfm_data sdhci_msm_pdata = {
...@@ -1124,6 +1332,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) ...@@ -1124,6 +1332,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
struct sdhci_pltfm_host *pltfm_host; struct sdhci_pltfm_host *pltfm_host;
struct sdhci_msm_host *msm_host; struct sdhci_msm_host *msm_host;
struct resource *core_memres; struct resource *core_memres;
struct clk *clk;
int ret; int ret;
u16 host_version, core_minor; u16 host_version, core_minor;
u32 core_version, config; u32 core_version, config;
...@@ -1160,24 +1369,42 @@ static int sdhci_msm_probe(struct platform_device *pdev) ...@@ -1160,24 +1369,42 @@ static int sdhci_msm_probe(struct platform_device *pdev)
} }
/* Setup main peripheral bus clock */ /* Setup main peripheral bus clock */
msm_host->pclk = devm_clk_get(&pdev->dev, "iface"); clk = devm_clk_get(&pdev->dev, "iface");
if (IS_ERR(msm_host->pclk)) { if (IS_ERR(clk)) {
ret = PTR_ERR(msm_host->pclk); ret = PTR_ERR(clk);
dev_err(&pdev->dev, "Peripheral clk setup failed (%d)\n", ret); dev_err(&pdev->dev, "Peripheral clk setup failed (%d)\n", ret);
goto bus_clk_disable; goto bus_clk_disable;
} }
msm_host->bulk_clks[1].clk = clk;
ret = clk_prepare_enable(msm_host->pclk);
if (ret)
goto bus_clk_disable;
/* Setup SDC MMC clock */ /* Setup SDC MMC clock */
msm_host->clk = devm_clk_get(&pdev->dev, "core"); clk = devm_clk_get(&pdev->dev, "core");
if (IS_ERR(msm_host->clk)) { if (IS_ERR(clk)) {
ret = PTR_ERR(msm_host->clk); ret = PTR_ERR(clk);
dev_err(&pdev->dev, "SDC MMC clk setup failed (%d)\n", ret); dev_err(&pdev->dev, "SDC MMC clk setup failed (%d)\n", ret);
goto pclk_disable; goto bus_clk_disable;
} }
msm_host->bulk_clks[0].clk = clk;
/* Vote for maximum clock rate for maximum performance */
ret = clk_set_rate(clk, INT_MAX);
if (ret)
dev_warn(&pdev->dev, "core clock boost failed\n");
clk = devm_clk_get(&pdev->dev, "cal");
if (IS_ERR(clk))
clk = NULL;
msm_host->bulk_clks[2].clk = clk;
clk = devm_clk_get(&pdev->dev, "sleep");
if (IS_ERR(clk))
clk = NULL;
msm_host->bulk_clks[3].clk = clk;
ret = clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks),
msm_host->bulk_clks);
if (ret)
goto bus_clk_disable;
/* /*
* xo clock is needed for FLL feature of cm_dll. * xo clock is needed for FLL feature of cm_dll.
...@@ -1189,15 +1416,6 @@ static int sdhci_msm_probe(struct platform_device *pdev) ...@@ -1189,15 +1416,6 @@ static int sdhci_msm_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "TCXO clk not present (%d)\n", ret); dev_warn(&pdev->dev, "TCXO clk not present (%d)\n", ret);
} }
/* Vote for maximum clock rate for maximum performance */
ret = clk_set_rate(msm_host->clk, INT_MAX);
if (ret)
dev_warn(&pdev->dev, "core clock boost failed\n");
ret = clk_prepare_enable(msm_host->clk);
if (ret)
goto pclk_disable;
core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1); core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
msm_host->core_mem = devm_ioremap_resource(&pdev->dev, core_memres); msm_host->core_mem = devm_ioremap_resource(&pdev->dev, core_memres);
...@@ -1251,6 +1469,21 @@ static int sdhci_msm_probe(struct platform_device *pdev) ...@@ -1251,6 +1469,21 @@ static int sdhci_msm_probe(struct platform_device *pdev)
CORE_VENDOR_SPEC_CAPABILITIES0); CORE_VENDOR_SPEC_CAPABILITIES0);
} }
/*
* Power on reset state may trigger power irq if previous status of
* PWRCTL was either BUS_ON or IO_HIGH_V. So before enabling pwr irq
* interrupt in GIC, any pending power irq interrupt should be
* acknowledged. Otherwise power irq interrupt handler would be
* fired prematurely.
*/
sdhci_msm_handle_pwr_irq(host, 0);
/*
* Ensure that above writes are propogated before interrupt enablement
* in GIC.
*/
mb();
/* Setup IRQ for handling power/voltage tasks with PMIC */ /* Setup IRQ for handling power/voltage tasks with PMIC */
msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq"); msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
if (msm_host->pwr_irq < 0) { if (msm_host->pwr_irq < 0) {
...@@ -1260,6 +1493,10 @@ static int sdhci_msm_probe(struct platform_device *pdev) ...@@ -1260,6 +1493,10 @@ static int sdhci_msm_probe(struct platform_device *pdev)
goto clk_disable; goto clk_disable;
} }
sdhci_msm_init_pwr_irq_wait(msm_host);
/* Enable pwr irq interrupts */
writel_relaxed(INT_MASK, msm_host->core_mem + CORE_PWRCTL_MASK);
ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL, ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL,
sdhci_msm_pwr_irq, IRQF_ONESHOT, sdhci_msm_pwr_irq, IRQF_ONESHOT,
dev_name(&pdev->dev), host); dev_name(&pdev->dev), host);
...@@ -1290,9 +1527,8 @@ static int sdhci_msm_probe(struct platform_device *pdev) ...@@ -1290,9 +1527,8 @@ static int sdhci_msm_probe(struct platform_device *pdev)
pm_runtime_set_suspended(&pdev->dev); pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev); pm_runtime_put_noidle(&pdev->dev);
clk_disable: clk_disable:
clk_disable_unprepare(msm_host->clk); clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks),
pclk_disable: msm_host->bulk_clks);
clk_disable_unprepare(msm_host->pclk);
bus_clk_disable: bus_clk_disable:
if (!IS_ERR(msm_host->bus_clk)) if (!IS_ERR(msm_host->bus_clk))
clk_disable_unprepare(msm_host->bus_clk); clk_disable_unprepare(msm_host->bus_clk);
...@@ -1315,8 +1551,8 @@ static int sdhci_msm_remove(struct platform_device *pdev) ...@@ -1315,8 +1551,8 @@ static int sdhci_msm_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev); pm_runtime_put_noidle(&pdev->dev);
clk_disable_unprepare(msm_host->clk); clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks),
clk_disable_unprepare(msm_host->pclk); msm_host->bulk_clks);
if (!IS_ERR(msm_host->bus_clk)) if (!IS_ERR(msm_host->bus_clk))
clk_disable_unprepare(msm_host->bus_clk); clk_disable_unprepare(msm_host->bus_clk);
sdhci_pltfm_free(pdev); sdhci_pltfm_free(pdev);
...@@ -1330,8 +1566,8 @@ static int sdhci_msm_runtime_suspend(struct device *dev) ...@@ -1330,8 +1566,8 @@ static int sdhci_msm_runtime_suspend(struct device *dev)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
clk_disable_unprepare(msm_host->clk); clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks),
clk_disable_unprepare(msm_host->pclk); msm_host->bulk_clks);
return 0; return 0;
} }
...@@ -1341,21 +1577,9 @@ static int sdhci_msm_runtime_resume(struct device *dev) ...@@ -1341,21 +1577,9 @@ static int sdhci_msm_runtime_resume(struct device *dev)
struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
int ret;
ret = clk_prepare_enable(msm_host->clk); return clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks),
if (ret) { msm_host->bulk_clks);
dev_err(dev, "clk_enable failed for core_clk: %d\n", ret);
return ret;
}
ret = clk_prepare_enable(msm_host->pclk);
if (ret) {
dev_err(dev, "clk_enable failed for iface_clk: %d\n", ret);
clk_disable_unprepare(msm_host->clk);
return ret;
}
return 0;
} }
#endif #endif
......
...@@ -114,7 +114,8 @@ static void sdhci_at91_set_power(struct sdhci_host *host, unsigned char mode, ...@@ -114,7 +114,8 @@ static void sdhci_at91_set_power(struct sdhci_host *host, unsigned char mode,
sdhci_set_power_noreg(host, mode, vdd); sdhci_set_power_noreg(host, mode, vdd);
} }
void sdhci_at91_set_uhs_signaling(struct sdhci_host *host, unsigned int timing) static void sdhci_at91_set_uhs_signaling(struct sdhci_host *host,
unsigned int timing)
{ {
if (timing == MMC_TIMING_MMC_DDR52) if (timing == MMC_TIMING_MMC_DDR52)
sdhci_writeb(host, SDMMC_MC1R_DDR, SDMMC_MC1R); sdhci_writeb(host, SDMMC_MC1R_DDR, SDMMC_MC1R);
......
...@@ -458,6 +458,33 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host) ...@@ -458,6 +458,33 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
return clock / 256 / 16; return clock / 256 / 16;
} }
static void esdhc_clock_enable(struct sdhci_host *host, bool enable)
{
u32 val;
ktime_t timeout;
val = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
if (enable)
val |= ESDHC_CLOCK_SDCLKEN;
else
val &= ~ESDHC_CLOCK_SDCLKEN;
sdhci_writel(host, val, ESDHC_SYSTEM_CONTROL);
/* Wait max 20 ms */
timeout = ktime_add_ms(ktime_get(), 20);
val = ESDHC_CLOCK_STABLE;
while (!(sdhci_readl(host, ESDHC_PRSSTAT) & val)) {
if (ktime_after(ktime_get(), timeout)) {
pr_err("%s: Internal clock never stabilised.\n",
mmc_hostname(host->mmc));
break;
}
udelay(10);
}
}
static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
...@@ -469,8 +496,10 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) ...@@ -469,8 +496,10 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
host->mmc->actual_clock = 0; host->mmc->actual_clock = 0;
if (clock == 0) if (clock == 0) {
esdhc_clock_enable(host, false);
return; return;
}
/* Workaround to start pre_div at 2 for VNN < VENDOR_V_23 */ /* Workaround to start pre_div at 2 for VNN < VENDOR_V_23 */
if (esdhc->vendor_ver < VENDOR_V_23) if (esdhc->vendor_ver < VENDOR_V_23)
...@@ -558,33 +587,6 @@ static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width) ...@@ -558,33 +587,6 @@ static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
sdhci_writel(host, ctrl, ESDHC_PROCTL); sdhci_writel(host, ctrl, ESDHC_PROCTL);
} }
static void esdhc_clock_enable(struct sdhci_host *host, bool enable)
{
u32 val;
ktime_t timeout;
val = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
if (enable)
val |= ESDHC_CLOCK_SDCLKEN;
else
val &= ~ESDHC_CLOCK_SDCLKEN;
sdhci_writel(host, val, ESDHC_SYSTEM_CONTROL);
/* Wait max 20 ms */
timeout = ktime_add_ms(ktime_get(), 20);
val = ESDHC_CLOCK_STABLE;
while (!(sdhci_readl(host, ESDHC_PRSSTAT) & val)) {
if (ktime_after(ktime_get(), timeout)) {
pr_err("%s: Internal clock never stabilised.\n",
mmc_hostname(host->mmc));
break;
}
udelay(10);
}
}
static void esdhc_reset(struct sdhci_host *host, u8 mask) static void esdhc_reset(struct sdhci_host *host, u8 mask)
{ {
sdhci_reset(host, mask); sdhci_reset(host, mask);
......
此差异已折叠。
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
#include "sdhci.h" #include "sdhci.h"
#include "sdhci-pci.h" #include "sdhci-pci.h"
#include "sdhci-pci-o2micro.h"
static int sdhci_pci_enable_dma(struct sdhci_host *host); static int sdhci_pci_enable_dma(struct sdhci_host *host);
static void sdhci_pci_hw_reset(struct sdhci_host *host); static void sdhci_pci_hw_reset(struct sdhci_host *host);
...@@ -798,15 +797,6 @@ static const struct sdhci_pci_fixes sdhci_intel_mrfld_mmc = { ...@@ -798,15 +797,6 @@ static const struct sdhci_pci_fixes sdhci_intel_mrfld_mmc = {
.probe_slot = intel_mrfld_mmc_probe_slot, .probe_slot = intel_mrfld_mmc_probe_slot,
}; };
/* O2Micro extra registers */
#define O2_SD_LOCK_WP 0xD3
#define O2_SD_MULTI_VCC3V 0xEE
#define O2_SD_CLKREQ 0xEC
#define O2_SD_CAPS 0xE0
#define O2_SD_ADMA1 0xE2
#define O2_SD_ADMA2 0xE7
#define O2_SD_INF_MOD 0xF1
static int jmicron_pmos(struct sdhci_pci_chip *chip, int on) static int jmicron_pmos(struct sdhci_pci_chip *chip, int on)
{ {
u8 scratch; u8 scratch;
...@@ -1290,6 +1280,7 @@ static const struct pci_device_id pci_ids[] = { ...@@ -1290,6 +1280,7 @@ static const struct pci_device_id pci_ids[] = {
SDHCI_PCI_DEVICE(INTEL, SPT_SDIO, intel_byt_sdio), SDHCI_PCI_DEVICE(INTEL, SPT_SDIO, intel_byt_sdio),
SDHCI_PCI_DEVICE(INTEL, SPT_SD, intel_byt_sd), SDHCI_PCI_DEVICE(INTEL, SPT_SD, intel_byt_sd),
SDHCI_PCI_DEVICE(INTEL, DNV_EMMC, intel_byt_emmc), SDHCI_PCI_DEVICE(INTEL, DNV_EMMC, intel_byt_emmc),
SDHCI_PCI_DEVICE(INTEL, CDF_EMMC, intel_glk_emmc),
SDHCI_PCI_DEVICE(INTEL, BXT_EMMC, intel_byt_emmc), SDHCI_PCI_DEVICE(INTEL, BXT_EMMC, intel_byt_emmc),
SDHCI_PCI_DEVICE(INTEL, BXT_SDIO, intel_byt_sdio), SDHCI_PCI_DEVICE(INTEL, BXT_SDIO, intel_byt_sdio),
SDHCI_PCI_DEVICE(INTEL, BXT_SD, intel_byt_sd), SDHCI_PCI_DEVICE(INTEL, BXT_SD, intel_byt_sd),
......
...@@ -19,7 +19,40 @@ ...@@ -19,7 +19,40 @@
#include "sdhci.h" #include "sdhci.h"
#include "sdhci-pci.h" #include "sdhci-pci.h"
#include "sdhci-pci-o2micro.h"
/*
* O2Micro device registers
*/
#define O2_SD_MISC_REG5 0x64
#define O2_SD_LD0_CTRL 0x68
#define O2_SD_DEV_CTRL 0x88
#define O2_SD_LOCK_WP 0xD3
#define O2_SD_TEST_REG 0xD4
#define O2_SD_FUNC_REG0 0xDC
#define O2_SD_MULTI_VCC3V 0xEE
#define O2_SD_CLKREQ 0xEC
#define O2_SD_CAPS 0xE0
#define O2_SD_ADMA1 0xE2
#define O2_SD_ADMA2 0xE7
#define O2_SD_INF_MOD 0xF1
#define O2_SD_MISC_CTRL4 0xFC
#define O2_SD_TUNING_CTRL 0x300
#define O2_SD_PLL_SETTING 0x304
#define O2_SD_CLK_SETTING 0x328
#define O2_SD_CAP_REG2 0x330
#define O2_SD_CAP_REG0 0x334
#define O2_SD_UHS1_CAP_SETTING 0x33C
#define O2_SD_DELAY_CTRL 0x350
#define O2_SD_UHS2_L1_CTRL 0x35C
#define O2_SD_FUNC_REG3 0x3E0
#define O2_SD_FUNC_REG4 0x3E4
#define O2_SD_LED_ENABLE BIT(6)
#define O2_SD_FREG0_LEDOFF BIT(13)
#define O2_SD_FREG4_ENABLE_CLK_SET BIT(22)
#define O2_SD_VENDOR_SETTING 0x110
#define O2_SD_VENDOR_SETTING2 0x1C8
static void o2_pci_set_baseclk(struct sdhci_pci_chip *chip, u32 value) static void o2_pci_set_baseclk(struct sdhci_pci_chip *chip, u32 value)
{ {
......
/*
* Copyright (C) 2013 BayHub Technology Ltd.
*
* Authors: Peter Guo <peter.guo@bayhubtech.com>
* Adam Lee <adam.lee@canonical.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __SDHCI_PCI_O2MICRO_H
#define __SDHCI_PCI_O2MICRO_H
#include "sdhci-pci.h"
/*
* O2Micro device IDs
*/
#define PCI_DEVICE_ID_O2_SDS0 0x8420
#define PCI_DEVICE_ID_O2_SDS1 0x8421
#define PCI_DEVICE_ID_O2_FUJIN2 0x8520
#define PCI_DEVICE_ID_O2_SEABIRD0 0x8620
#define PCI_DEVICE_ID_O2_SEABIRD1 0x8621
/*
* O2Micro device registers
*/
#define O2_SD_MISC_REG5 0x64
#define O2_SD_LD0_CTRL 0x68
#define O2_SD_DEV_CTRL 0x88
#define O2_SD_LOCK_WP 0xD3
#define O2_SD_TEST_REG 0xD4
#define O2_SD_FUNC_REG0 0xDC
#define O2_SD_MULTI_VCC3V 0xEE
#define O2_SD_CLKREQ 0xEC
#define O2_SD_CAPS 0xE0
#define O2_SD_ADMA1 0xE2
#define O2_SD_ADMA2 0xE7
#define O2_SD_INF_MOD 0xF1
#define O2_SD_MISC_CTRL4 0xFC
#define O2_SD_TUNING_CTRL 0x300
#define O2_SD_PLL_SETTING 0x304
#define O2_SD_CLK_SETTING 0x328
#define O2_SD_CAP_REG2 0x330
#define O2_SD_CAP_REG0 0x334
#define O2_SD_UHS1_CAP_SETTING 0x33C
#define O2_SD_DELAY_CTRL 0x350
#define O2_SD_UHS2_L1_CTRL 0x35C
#define O2_SD_FUNC_REG3 0x3E0
#define O2_SD_FUNC_REG4 0x3E4
#define O2_SD_LED_ENABLE BIT(6)
#define O2_SD_FREG0_LEDOFF BIT(13)
#define O2_SD_FREG4_ENABLE_CLK_SET BIT(22)
#define O2_SD_VENDOR_SETTING 0x110
#define O2_SD_VENDOR_SETTING2 0x1C8
extern int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot);
extern int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip);
extern int sdhci_pci_o2_resume(struct sdhci_pci_chip *chip);
#endif /* __SDHCI_PCI_O2MICRO_H */
...@@ -6,6 +6,12 @@ ...@@ -6,6 +6,12 @@
* PCI device IDs, sub IDs * PCI device IDs, sub IDs
*/ */
#define PCI_DEVICE_ID_O2_SDS0 0x8420
#define PCI_DEVICE_ID_O2_SDS1 0x8421
#define PCI_DEVICE_ID_O2_FUJIN2 0x8520
#define PCI_DEVICE_ID_O2_SEABIRD0 0x8620
#define PCI_DEVICE_ID_O2_SEABIRD1 0x8621
#define PCI_DEVICE_ID_INTEL_PCH_SDIO0 0x8809 #define PCI_DEVICE_ID_INTEL_PCH_SDIO0 0x8809
#define PCI_DEVICE_ID_INTEL_PCH_SDIO1 0x880a #define PCI_DEVICE_ID_INTEL_PCH_SDIO1 0x880a
#define PCI_DEVICE_ID_INTEL_BYT_EMMC 0x0f14 #define PCI_DEVICE_ID_INTEL_BYT_EMMC 0x0f14
...@@ -26,6 +32,7 @@ ...@@ -26,6 +32,7 @@
#define PCI_DEVICE_ID_INTEL_SPT_SDIO 0x9d2c #define PCI_DEVICE_ID_INTEL_SPT_SDIO 0x9d2c
#define PCI_DEVICE_ID_INTEL_SPT_SD 0x9d2d #define PCI_DEVICE_ID_INTEL_SPT_SD 0x9d2d
#define PCI_DEVICE_ID_INTEL_DNV_EMMC 0x19db #define PCI_DEVICE_ID_INTEL_DNV_EMMC 0x19db
#define PCI_DEVICE_ID_INTEL_CDF_EMMC 0x18db
#define PCI_DEVICE_ID_INTEL_BXT_SD 0x0aca #define PCI_DEVICE_ID_INTEL_BXT_SD 0x0aca
#define PCI_DEVICE_ID_INTEL_BXT_EMMC 0x0acc #define PCI_DEVICE_ID_INTEL_BXT_EMMC 0x0acc
#define PCI_DEVICE_ID_INTEL_BXT_SDIO 0x0ad0 #define PCI_DEVICE_ID_INTEL_BXT_SDIO 0x0ad0
...@@ -164,4 +171,10 @@ static inline void *sdhci_pci_priv(struct sdhci_pci_slot *slot) ...@@ -164,4 +171,10 @@ static inline void *sdhci_pci_priv(struct sdhci_pci_slot *slot)
int sdhci_pci_resume_host(struct sdhci_pci_chip *chip); int sdhci_pci_resume_host(struct sdhci_pci_chip *chip);
#endif #endif
int sdhci_pci_o2_probe_slot(struct sdhci_pci_slot *slot);
int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip);
#ifdef CONFIG_PM_SLEEP
int sdhci_pci_o2_resume(struct sdhci_pci_chip *chip);
#endif
#endif /* __SDHCI_PCI_H */ #endif /* __SDHCI_PCI_H */
...@@ -761,32 +761,24 @@ static const struct dev_pm_ops sdhci_s3c_pmops = { ...@@ -761,32 +761,24 @@ static const struct dev_pm_ops sdhci_s3c_pmops = {
NULL) NULL)
}; };
#if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS4212)
static struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = {
.no_divider = true,
};
#define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)&exynos4_sdhci_drv_data)
#else
#define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)NULL)
#endif
static const struct platform_device_id sdhci_s3c_driver_ids[] = { static const struct platform_device_id sdhci_s3c_driver_ids[] = {
{ {
.name = "s3c-sdhci", .name = "s3c-sdhci",
.driver_data = (kernel_ulong_t)NULL, .driver_data = (kernel_ulong_t)NULL,
}, {
.name = "exynos4-sdhci",
.driver_data = EXYNOS4_SDHCI_DRV_DATA,
}, },
{ } { }
}; };
MODULE_DEVICE_TABLE(platform, sdhci_s3c_driver_ids); MODULE_DEVICE_TABLE(platform, sdhci_s3c_driver_ids);
#ifdef CONFIG_OF #ifdef CONFIG_OF
static struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = {
.no_divider = true,
};
static const struct of_device_id sdhci_s3c_dt_match[] = { static const struct of_device_id sdhci_s3c_dt_match[] = {
{ .compatible = "samsung,s3c6410-sdhci", }, { .compatible = "samsung,s3c6410-sdhci", },
{ .compatible = "samsung,exynos4210-sdhci", { .compatible = "samsung,exynos4210-sdhci",
.data = (void *)EXYNOS4_SDHCI_DRV_DATA }, .data = &exynos4_sdhci_drv_data },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, sdhci_s3c_dt_match); MODULE_DEVICE_TABLE(of, sdhci_s3c_dt_match);
......
...@@ -422,7 +422,15 @@ static const struct sdhci_pltfm_data sdhci_tegra186_pdata = { ...@@ -422,7 +422,15 @@ static const struct sdhci_pltfm_data sdhci_tegra186_pdata = {
SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_NO_HISPD_BIT |
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
/* SDHCI controllers on Tegra186 support 40-bit addressing.
* IOVA addresses are 48-bit wide on Tegra186.
* With 64-bit dma mask used for SDHCI, accesses can
* be broken. Disable 64-bit dma, which would fall back
* to 32-bit dma mask. Ideally 40-bit dma mask would work,
* But it is not supported as of now.
*/
SDHCI_QUIRK2_BROKEN_64_BIT_DMA,
.ops = &tegra114_sdhci_ops, .ops = &tegra114_sdhci_ops,
}; };
......
...@@ -2407,12 +2407,12 @@ static void sdhci_tasklet_finish(unsigned long param) ...@@ -2407,12 +2407,12 @@ static void sdhci_tasklet_finish(unsigned long param)
; ;
} }
static void sdhci_timeout_timer(unsigned long data) static void sdhci_timeout_timer(struct timer_list *t)
{ {
struct sdhci_host *host; struct sdhci_host *host;
unsigned long flags; unsigned long flags;
host = (struct sdhci_host*)data; host = from_timer(host, t, timer);
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
...@@ -2429,12 +2429,12 @@ static void sdhci_timeout_timer(unsigned long data) ...@@ -2429,12 +2429,12 @@ static void sdhci_timeout_timer(unsigned long data)
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
} }
static void sdhci_timeout_data_timer(unsigned long data) static void sdhci_timeout_data_timer(struct timer_list *t)
{ {
struct sdhci_host *host; struct sdhci_host *host;
unsigned long flags; unsigned long flags;
host = (struct sdhci_host *)data; host = from_timer(host, t, data_timer);
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
...@@ -3238,7 +3238,7 @@ int sdhci_setup_host(struct sdhci_host *host) ...@@ -3238,7 +3238,7 @@ int sdhci_setup_host(struct sdhci_host *host)
* available. * available.
*/ */
ret = mmc_regulator_get_supply(mmc); ret = mmc_regulator_get_supply(mmc);
if (ret == -EPROBE_DEFER) if (ret)
return ret; return ret;
DBG("Version: 0x%08x | Present: 0x%08x\n", DBG("Version: 0x%08x | Present: 0x%08x\n",
...@@ -3749,9 +3749,8 @@ int __sdhci_add_host(struct sdhci_host *host) ...@@ -3749,9 +3749,8 @@ int __sdhci_add_host(struct sdhci_host *host)
tasklet_init(&host->finish_tasklet, tasklet_init(&host->finish_tasklet,
sdhci_tasklet_finish, (unsigned long)host); sdhci_tasklet_finish, (unsigned long)host);
setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host); timer_setup(&host->timer, sdhci_timeout_timer, 0);
setup_timer(&host->data_timer, sdhci_timeout_data_timer, timer_setup(&host->data_timer, sdhci_timeout_data_timer, 0);
(unsigned long)host);
init_waitqueue_head(&host->buf_ready_int); init_waitqueue_head(&host->buf_ready_int);
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/property.h>
#include <linux/clk.h> #include <linux/clk.h>
#include "sdhci-pltfm.h" #include "sdhci-pltfm.h"
...@@ -47,6 +48,7 @@ struct f_sdhost_priv { ...@@ -47,6 +48,7 @@ struct f_sdhost_priv {
struct clk *clk; struct clk *clk;
u32 vendor_hs200; u32 vendor_hs200;
struct device *dev; struct device *dev;
bool enable_cmd_dat_delay;
}; };
static void sdhci_f_sdh30_soft_voltage_switch(struct sdhci_host *host) static void sdhci_f_sdh30_soft_voltage_switch(struct sdhci_host *host)
...@@ -84,10 +86,19 @@ static unsigned int sdhci_f_sdh30_get_min_clock(struct sdhci_host *host) ...@@ -84,10 +86,19 @@ static unsigned int sdhci_f_sdh30_get_min_clock(struct sdhci_host *host)
static void sdhci_f_sdh30_reset(struct sdhci_host *host, u8 mask) static void sdhci_f_sdh30_reset(struct sdhci_host *host, u8 mask)
{ {
struct f_sdhost_priv *priv = sdhci_priv(host);
u32 ctl;
if (sdhci_readw(host, SDHCI_CLOCK_CONTROL) == 0) if (sdhci_readw(host, SDHCI_CLOCK_CONTROL) == 0)
sdhci_writew(host, 0xBC01, SDHCI_CLOCK_CONTROL); sdhci_writew(host, 0xBC01, SDHCI_CLOCK_CONTROL);
sdhci_reset(host, mask); sdhci_reset(host, mask);
if (priv->enable_cmd_dat_delay) {
ctl = sdhci_readl(host, F_SDH30_ESD_CONTROL);
ctl |= F_SDH30_CMD_DAT_DELAY;
sdhci_writel(host, ctl, F_SDH30_ESD_CONTROL);
}
} }
static const struct sdhci_ops sdhci_f_sdh30_ops = { static const struct sdhci_ops sdhci_f_sdh30_ops = {
...@@ -126,6 +137,9 @@ static int sdhci_f_sdh30_probe(struct platform_device *pdev) ...@@ -126,6 +137,9 @@ static int sdhci_f_sdh30_probe(struct platform_device *pdev)
host->quirks2 = SDHCI_QUIRK2_SUPPORT_SINGLE | host->quirks2 = SDHCI_QUIRK2_SUPPORT_SINGLE |
SDHCI_QUIRK2_TUNING_WORK_AROUND; SDHCI_QUIRK2_TUNING_WORK_AROUND;
priv->enable_cmd_dat_delay = device_property_read_bool(dev,
"fujitsu,cmd-dat-delay-select");
ret = mmc_of_parse(host->mmc); ret = mmc_of_parse(host->mmc);
if (ret) if (ret)
goto err; goto err;
......
...@@ -1175,11 +1175,8 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host, ...@@ -1175,11 +1175,8 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
return -EINVAL; return -EINVAL;
ret = mmc_regulator_get_supply(host->mmc); ret = mmc_regulator_get_supply(host->mmc);
if (ret) { if (ret)
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "Could not get vmmc supply\n");
return ret; return ret;
}
host->reg_base = devm_ioremap_resource(&pdev->dev, host->reg_base = devm_ioremap_resource(&pdev->dev,
platform_get_resource(pdev, IORESOURCE_MEM, 0)); platform_get_resource(pdev, IORESOURCE_MEM, 0));
......
...@@ -783,9 +783,9 @@ static void tifm_sd_end_cmd(unsigned long data) ...@@ -783,9 +783,9 @@ static void tifm_sd_end_cmd(unsigned long data)
mmc_request_done(mmc, mrq); mmc_request_done(mmc, mrq);
} }
static void tifm_sd_abort(unsigned long data) static void tifm_sd_abort(struct timer_list *t)
{ {
struct tifm_sd *host = (struct tifm_sd*)data; struct tifm_sd *host = from_timer(host, t, timer);
pr_err("%s : card failed to respond for a long period of time " pr_err("%s : card failed to respond for a long period of time "
"(%x, %x)\n", "(%x, %x)\n",
...@@ -968,7 +968,7 @@ static int tifm_sd_probe(struct tifm_dev *sock) ...@@ -968,7 +968,7 @@ static int tifm_sd_probe(struct tifm_dev *sock)
tasklet_init(&host->finish_tasklet, tifm_sd_end_cmd, tasklet_init(&host->finish_tasklet, tifm_sd_end_cmd,
(unsigned long)host); (unsigned long)host);
setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host); timer_setup(&host->timer, tifm_sd_abort, 0);
mmc->ops = &tifm_sd_ops; mmc->ops = &tifm_sd_ops;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
......
...@@ -167,11 +167,11 @@ static void tmio_mmc_clk_start(struct tmio_mmc_host *host) ...@@ -167,11 +167,11 @@ static void tmio_mmc_clk_start(struct tmio_mmc_host *host)
/* HW engineers overrode docs: no sleep needed on R-Car2+ */ /* HW engineers overrode docs: no sleep needed on R-Car2+ */
if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
msleep(10); usleep_range(10000, 11000);
if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) { if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) {
sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100); sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100);
msleep(10); usleep_range(10000, 11000);
} }
} }
...@@ -179,7 +179,7 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) ...@@ -179,7 +179,7 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
{ {
if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) { if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) {
sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000); sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000);
msleep(10); usleep_range(10000, 11000);
} }
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
...@@ -187,7 +187,7 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) ...@@ -187,7 +187,7 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
/* HW engineers overrode docs: no sleep needed on R-Car2+ */ /* HW engineers overrode docs: no sleep needed on R-Car2+ */
if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
msleep(10); usleep_range(10000, 11000);
} }
static void tmio_mmc_set_clock(struct tmio_mmc_host *host, static void tmio_mmc_set_clock(struct tmio_mmc_host *host,
...@@ -219,7 +219,7 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, ...@@ -219,7 +219,7 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host,
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & CLK_CTL_DIV_MASK); sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & CLK_CTL_DIV_MASK);
if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
msleep(10); usleep_range(10000, 11000);
tmio_mmc_clk_start(host); tmio_mmc_clk_start(host);
} }
...@@ -230,11 +230,11 @@ static void tmio_mmc_reset(struct tmio_mmc_host *host) ...@@ -230,11 +230,11 @@ static void tmio_mmc_reset(struct tmio_mmc_host *host)
sd_ctrl_write16(host, CTL_RESET_SD, 0x0000); sd_ctrl_write16(host, CTL_RESET_SD, 0x0000);
if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG)
sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000); sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000);
msleep(10); usleep_range(10000, 11000);
sd_ctrl_write16(host, CTL_RESET_SD, 0x0001); sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG)
sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001); sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001);
msleep(10); usleep_range(10000, 11000);
if (host->pdata->flags & TMIO_MMC_SDIO_IRQ) { 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_SDIO_IRQ_MASK, host->sdio_irq_mask);
...@@ -1113,8 +1113,11 @@ static int tmio_mmc_init_ocr(struct tmio_mmc_host *host) ...@@ -1113,8 +1113,11 @@ static int tmio_mmc_init_ocr(struct tmio_mmc_host *host)
{ {
struct tmio_mmc_data *pdata = host->pdata; struct tmio_mmc_data *pdata = host->pdata;
struct mmc_host *mmc = host->mmc; struct mmc_host *mmc = host->mmc;
int err;
mmc_regulator_get_supply(mmc); err = mmc_regulator_get_supply(mmc);
if (err)
return err;
/* use ocr_mask if no regulator */ /* use ocr_mask if no regulator */
if (!mmc->ocr_avail) if (!mmc->ocr_avail)
...@@ -1299,23 +1302,24 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host, ...@@ -1299,23 +1302,24 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
ret = mmc_add_host(mmc); ret = mmc_add_host(mmc);
if (ret < 0) { if (ret)
tmio_mmc_host_remove(_host); goto remove_host;
return ret;
}
dev_pm_qos_expose_latency_limit(&pdev->dev, 100); dev_pm_qos_expose_latency_limit(&pdev->dev, 100);
if (pdata->flags & TMIO_MMC_USE_GPIO_CD) { if (pdata->flags & TMIO_MMC_USE_GPIO_CD) {
ret = mmc_gpio_request_cd(mmc, pdata->cd_gpio, 0); ret = mmc_gpio_request_cd(mmc, pdata->cd_gpio, 0);
if (ret < 0) { if (ret)
tmio_mmc_host_remove(_host); goto remove_host;
return ret;
}
mmc_gpiod_request_cd_irq(mmc); mmc_gpiod_request_cd_irq(mmc);
} }
return 0; return 0;
remove_host:
tmio_mmc_host_remove(_host);
return ret;
} }
EXPORT_SYMBOL_GPL(tmio_mmc_host_probe); EXPORT_SYMBOL_GPL(tmio_mmc_host_probe);
......
...@@ -1757,7 +1757,7 @@ static int usdhi6_probe(struct platform_device *pdev) ...@@ -1757,7 +1757,7 @@ static int usdhi6_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
ret = mmc_regulator_get_supply(mmc); ret = mmc_regulator_get_supply(mmc);
if (ret == -EPROBE_DEFER) if (ret)
goto e_free_mmc; goto e_free_mmc;
ret = mmc_of_parse(mmc); ret = mmc_of_parse(mmc);
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册