MMC core:

- Consolidation and cleanups.
 - Some improvements regarding error handling.
 - Increase maximum amount of block devices.
 - Use correct OCR mask for SDIO when restoring power.
 - Fix prepared requests while doing BKOPS.
 - Convert to modern PM ops.
 - Add mmc_send_tuning() API and convert some hosts to use it.
 
 MMC host:
 - toshsd: New Toshiba PCI SD controller driver.
 - sdhci: 64-bit ADMA support.
 - sdhci: Some regulator fixes.
 - sdhci: HS400 support.
 - sdhci: Various fixes cleanups.
 - atmel-mci: Modernization and cleanups.
 - atmel-mci: Runtime PM support.
 - omap_hsmmc: Modernization and cleanups.
 - omap_hsmmc: Fix UHS card with DDR50 support.
 - dw_mmc: Support for ARM64 and Exynos 7 variant.
 - dw_mmc: Add support for IMG Pistachio variant.
 - dw_mmc: Various fixes and cleanups.
 - mvsdio: DMA fixes.
 - mxs-mmc: Modernization and cleanups.
 - mxcmmc: Various fixes.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJUhYTTAAoJEP4mhCVzWIwpRvUP/22/mNJkYg7IEPtzAnPF1YJW
 FKU9LdXLGQhrYR99A4grKJ8XMkqLn1FYQh+6j8rRKwrI0RFjmRyeVHsRKHBy1vV+
 QjY7U2+GOAxoQopGq0HT+lECB6E7A3BQpJDu92HI9/1ambPmChh5at6qByscmpLc
 y4Bs/rNwClWmbDBCZ0hrGNE4iGr3pvnmz1fXE2KwhJA5Jzk70j/p8FTSMiAEdlv5
 8R9Pu3l+eQbsxBH+mQ6F6F4ZcHSc4JjCjL168icEn2b9cuT1Qa7+GqEOktmwelEc
 29gcLgeOuCi5Q5YqxmueC7jJVHQ0hVg46NOb0aivlbSrvhE2Xk5Crj8Ro7rlh7Q4
 s4v6OseYO4zjIx7l27C/B0/iaqwCok1zeNe23voR8ne/6RYYaYK/4IfpZM0fo4u8
 pUlTtY9aqY98BhynJCKFv29z2Ifbo4v8/8FkIWz4FKvCmq27ibXXB7rjx64l1/bR
 4BQp8HzTD254RnT5FhNADG5lnj0EhZtiKli8/vVu+kfao7GAE9M/vd9NxJsQQw//
 LYM4EKTaaT8z7LgHFg2Cs5KMIXxuvgjTj9/SPbILzqyCvnjEZYbJxViH4dkB9IQC
 LoiF8PvKddDUH1Z9+brTg6qrf/C5j/+jHuAWKF61vtdQ6xTzlv/Y6YxKeE0ntSsm
 HAqzQTAPfwr5/Aq9RuBJ
 =ODSj
 -----END PGP SIGNATURE-----

Merge tag 'mmc-v3.19-1' of git://git.linaro.org/people/ulf.hansson/mmc

Pull MMC updates from Ulf Hansson:
 "MMC core:
   - Consolidation and cleanups.
   - Some improvements regarding error handling.
   - Increase maximum amount of block devices.
   - Use correct OCR mask for SDIO when restoring power.
   - Fix prepared requests while doing BKOPS.
   - Convert to modern PM ops.
   - Add mmc_send_tuning() API and convert some hosts to use it.

  MMC host:
   - toshsd: New Toshiba PCI SD controller driver.
   - sdhci: 64-bit ADMA support.
   - sdhci: Some regulator fixes.
   - sdhci: HS400 support.
   - sdhci: Various fixes cleanups.
   - atmel-mci: Modernization and cleanups.
   - atmel-mci: Runtime PM support.
   - omap_hsmmc: Modernization and cleanups.
   - omap_hsmmc: Fix UHS card with DDR50 support.
   - dw_mmc: Support for ARM64 and Exynos 7 variant.
   - dw_mmc: Add support for IMG Pistachio variant.
   - dw_mmc: Various fixes and cleanups.
   - mvsdio: DMA fixes.
   - mxs-mmc: Modernization and cleanups.
   - mxcmmc: Various fixes"

* tag 'mmc-v3.19-1' of git://git.linaro.org/people/ulf.hansson/mmc: (126 commits)
  mmc: sdhci-msm: Convert to mmc_send_tuning()
  mmc: sdhci-esdhc-imx: Convert to mmc_send_tuning()
  mmc: core: Let mmc_send_tuning() to take struct mmc_host* as parameter
  mmc: queue: Improve error handling during allocation of bounce buffers
  mmc: sdhci-acpi: Add two host capabilities for Intel
  mmc: sdhci-pci: Add two host capabilities for BYT
  mmc: sdhci-acpi: Add SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
  mmc: sdhci-pci: Add SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC to BYT
  mmc: atmel-mci: use probe deferring if dma controller is not ready yet
  mmc: atmel-mci: stop using specific initcall
  mmc: atmel-mci: remove __init/__exit attributes
  mmc: atmel-mci: remove useless DMA stuff for non-dt devices
  mmc: omap_hsmmc: Fix UHS card with DDR50 support
  mmc: core: add core-level function for sending tuning commands
  mmc: core: hold SD Clock before CMD11 during Signal
  mmc: mxs-mmc: Check for clk_prepare_enable() error
  mmc: mxs-mmc: Propagate the real error
  mmc: mxs-mmc: No need to do NULL check on 'iores'
  mmc: dw_mmc: Add support for IMG Pistachio
  mmc: mxs-mmc: Simplify PM hooks
  ...
This commit is contained in:
Linus Torvalds 2014-12-08 18:42:44 -08:00
commit f2fb38049c
71 changed files with 2458 additions and 1238 deletions

View File

@ -18,6 +18,10 @@ Required Properties:
specific extensions.
- "samsung,exynos5420-dw-mshc": for controllers with Samsung Exynos5420
specific extensions.
- "samsung,exynos7-dw-mshc": for controllers with Samsung Exynos7
specific extensions.
- "samsung,exynos7-dw-mshc-smu": for controllers with Samsung Exynos7
specific extensions having an SMU.
* samsung,dw-mshc-ciu-div: Specifies the divider value for the card interface
unit (ciu) clock. This property is applicable only for Exynos5 SoC's and

View File

@ -0,0 +1,29 @@
* Imagination specific extensions to the Synopsys Designware Mobile Storage
Host Controller
The Synopsys designware mobile storage host controller is used to interface
a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
differences between the core Synopsys dw mshc controller properties described
by synopsys-dw-mshc.txt and the properties used by the Imagination specific
extensions to the Synopsys Designware Mobile Storage Host Controller.
Required Properties:
* compatible: should be
- "img,pistachio-dw-mshc": for Pistachio SoCs
Example:
mmc@18142000 {
compatible = "img,pistachio-dw-mshc";
reg = <0x18142000 0x400>;
interrupts = <GIC_SHARED 39 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&system_clk>, <&sdhost_clk>;
clock-names = "biu", "ciu";
fifo-depth = <0x20>;
bus-width = <4>;
num-slots = <1>;
disable-wp;
};

View File

@ -12,6 +12,10 @@ Required properties:
* for "marvell,armada-380-sdhci", two register areas. The first one
for the SDHCI registers themselves, and the second one for the
AXI/Mbus bridge registers of the SDHCI unit.
- clocks: Array of clocks required for SDHCI; requires at least one for
I/O clock.
- clock-names: Array of names corresponding to clocks property; shall be
"io" for I/O clock and "core" for optional core clock.
Optional properties:
- mrvl,clk-delay-cycles: Specify a number of cycles to delay for tuning.
@ -23,6 +27,8 @@ sdhci@d4280800 {
reg = <0xd4280800 0x800>;
bus-width = <8>;
interrupts = <27>;
clocks = <&chip CLKID_SDIO1XIN>, <&chip CLKID_SDIO1>;
clock-names = "io", "core";
non-removable;
mrvl,clk-delay-cycles = <31>;
};
@ -32,5 +38,6 @@ sdhci@d8000 {
reg = <0xd8000 0x1000>, <0xdc000 0x100>;
interrupts = <0 25 0x4>;
clocks = <&gateclk 17>;
clock-names = "io";
mrvl,clk-delay-cycles = <0x1F>;
};

View File

@ -19,6 +19,7 @@
#include <linux/i2c-gpio.h>
#include <linux/atmel-mci.h>
#include <linux/platform_data/crypto-atmel.h>
#include <linux/platform_data/mmc-atmel-mci.h>
#include <linux/platform_data/at91_adc.h>
@ -30,7 +31,6 @@
#include <mach/at91_matrix.h>
#include <mach/at91sam9_smc.h>
#include <linux/platform_data/dma-atmel.h>
#include <mach/atmel-mci.h>
#include <mach/hardware.h>
#include <media/atmel-isi.h>

View File

@ -21,8 +21,10 @@
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/usb/musb.h>
#include <linux/mmc/host.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
#include <linux/platform_data/mtd-onenand-omap2.h>
#include <linux/platform_data/mmc-omap.h>
#include <linux/mfd/menelaus.h>
#include <sound/tlv320aic3x.h>

View File

@ -484,7 +484,7 @@ static struct omap_mux_partition *partition;
* Current flows to eMMC when eMMC is off and the data lines are pulled up,
* so pull them down. N.B. we pull 8 lines because we are using 8 lines.
*/
static void rx51_mmc2_remux(struct device *dev, int slot, int power_on)
static void rx51_mmc2_remux(struct device *dev, int power_on)
{
if (power_on)
omap_mux_write_array(partition, rx51_mmc2_on_mux);
@ -500,7 +500,6 @@ static struct omap2_hsmmc_info mmc[] __initdata = {
.cover_only = true,
.gpio_cd = 160,
.gpio_wp = -EINVAL,
.power_saving = true,
},
{
.name = "internal",
@ -510,7 +509,6 @@ static struct omap2_hsmmc_info mmc[] __initdata = {
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
.nonremovable = true,
.power_saving = true,
.remux = rx51_mmc2_remux,
},
{} /* Terminator */

View File

@ -14,14 +14,15 @@
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/mmc/host.h>
#include <linux/platform_data/gpio-omap.h>
#include <linux/platform_data/hsmmc-omap.h>
#include "soc.h"
#include "omap_device.h"
#include "omap-pm.h"
#include "mux.h"
#include "mmc.h"
#include "hsmmc.h"
#include "control.h"
@ -32,25 +33,14 @@ static u16 control_devconf1_offset;
#define HSMMC_NAME_LEN 9
#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
static int hsmmc_get_context_loss(struct device *dev)
{
return omap_pm_get_dev_context_loss_count(dev);
}
#else
#define hsmmc_get_context_loss NULL
#endif
static void omap_hsmmc1_before_set_reg(struct device *dev, int slot,
int power_on, int vdd)
static void omap_hsmmc1_before_set_reg(struct device *dev,
int power_on, int vdd)
{
u32 reg, prog_io;
struct omap_mmc_platform_data *mmc = dev->platform_data;
struct omap_hsmmc_platform_data *mmc = dev->platform_data;
if (mmc->slots[0].remux)
mmc->slots[0].remux(dev, slot, power_on);
if (mmc->remux)
mmc->remux(dev, power_on);
/*
* Assume we power both OMAP VMMC1 (for CMD, CLK, DAT0..3) and the
@ -72,7 +62,7 @@ static void omap_hsmmc1_before_set_reg(struct device *dev, int slot,
omap_ctrl_writel(reg, OMAP243X_CONTROL_DEVCONF1);
}
if (mmc->slots[0].internal_clock) {
if (mmc->internal_clock) {
reg = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
reg |= OMAP2_MMCSDIO1ADPCLKISEL;
omap_ctrl_writel(reg, OMAP2_CONTROL_DEVCONF0);
@ -96,8 +86,7 @@ static void omap_hsmmc1_before_set_reg(struct device *dev, int slot,
}
}
static void omap_hsmmc1_after_set_reg(struct device *dev, int slot,
int power_on, int vdd)
static void omap_hsmmc1_after_set_reg(struct device *dev, int power_on, int vdd)
{
u32 reg;
@ -120,34 +109,32 @@ static void omap_hsmmc1_after_set_reg(struct device *dev, int slot,
}
}
static void hsmmc2_select_input_clk_src(struct omap_mmc_platform_data *mmc)
static void hsmmc2_select_input_clk_src(struct omap_hsmmc_platform_data *mmc)
{
u32 reg;
reg = omap_ctrl_readl(control_devconf1_offset);
if (mmc->slots[0].internal_clock)
if (mmc->internal_clock)
reg |= OMAP2_MMCSDIO2ADPCLKISEL;
else
reg &= ~OMAP2_MMCSDIO2ADPCLKISEL;
omap_ctrl_writel(reg, control_devconf1_offset);
}
static void hsmmc2_before_set_reg(struct device *dev, int slot,
int power_on, int vdd)
static void hsmmc2_before_set_reg(struct device *dev, int power_on, int vdd)
{
struct omap_mmc_platform_data *mmc = dev->platform_data;
struct omap_hsmmc_platform_data *mmc = dev->platform_data;
if (mmc->slots[0].remux)
mmc->slots[0].remux(dev, slot, power_on);
if (mmc->remux)
mmc->remux(dev, power_on);
if (power_on)
hsmmc2_select_input_clk_src(mmc);
}
static int am35x_hsmmc2_set_power(struct device *dev, int slot,
int power_on, int vdd)
static int am35x_hsmmc2_set_power(struct device *dev, int power_on, int vdd)
{
struct omap_mmc_platform_data *mmc = dev->platform_data;
struct omap_hsmmc_platform_data *mmc = dev->platform_data;
if (power_on)
hsmmc2_select_input_clk_src(mmc);
@ -155,23 +142,22 @@ static int am35x_hsmmc2_set_power(struct device *dev, int slot,
return 0;
}
static int nop_mmc_set_power(struct device *dev, int slot, int power_on,
int vdd)
static int nop_mmc_set_power(struct device *dev, int power_on, int vdd)
{
return 0;
}
static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller,
int controller_nr)
static inline void omap_hsmmc_mux(struct omap_hsmmc_platform_data
*mmc_controller, int controller_nr)
{
if (gpio_is_valid(mmc_controller->slots[0].switch_pin) &&
(mmc_controller->slots[0].switch_pin < OMAP_MAX_GPIO_LINES))
omap_mux_init_gpio(mmc_controller->slots[0].switch_pin,
OMAP_PIN_INPUT_PULLUP);
if (gpio_is_valid(mmc_controller->slots[0].gpio_wp) &&
(mmc_controller->slots[0].gpio_wp < OMAP_MAX_GPIO_LINES))
omap_mux_init_gpio(mmc_controller->slots[0].gpio_wp,
OMAP_PIN_INPUT_PULLUP);
if (gpio_is_valid(mmc_controller->switch_pin) &&
(mmc_controller->switch_pin < OMAP_MAX_GPIO_LINES))
omap_mux_init_gpio(mmc_controller->switch_pin,
OMAP_PIN_INPUT_PULLUP);
if (gpio_is_valid(mmc_controller->gpio_wp) &&
(mmc_controller->gpio_wp < OMAP_MAX_GPIO_LINES))
omap_mux_init_gpio(mmc_controller->gpio_wp,
OMAP_PIN_INPUT_PULLUP);
if (cpu_is_omap34xx()) {
if (controller_nr == 0) {
omap_mux_init_signal("sdmmc1_clk",
@ -180,7 +166,7 @@ static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller,
OMAP_PIN_INPUT_PULLUP);
omap_mux_init_signal("sdmmc1_dat0",
OMAP_PIN_INPUT_PULLUP);
if (mmc_controller->slots[0].caps &
if (mmc_controller->caps &
(MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) {
omap_mux_init_signal("sdmmc1_dat1",
OMAP_PIN_INPUT_PULLUP);
@ -189,7 +175,7 @@ static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller,
omap_mux_init_signal("sdmmc1_dat3",
OMAP_PIN_INPUT_PULLUP);
}
if (mmc_controller->slots[0].caps &
if (mmc_controller->caps &
MMC_CAP_8_BIT_DATA) {
omap_mux_init_signal("sdmmc1_dat4",
OMAP_PIN_INPUT_PULLUP);
@ -214,7 +200,7 @@ static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller,
* For 8 wire configurations, Lines DAT4, 5, 6 and 7
* need to be muxed in the board-*.c files
*/
if (mmc_controller->slots[0].caps &
if (mmc_controller->caps &
(MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) {
omap_mux_init_signal("sdmmc2_dat1",
OMAP_PIN_INPUT_PULLUP);
@ -223,7 +209,7 @@ static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller,
omap_mux_init_signal("sdmmc2_dat3",
OMAP_PIN_INPUT_PULLUP);
}
if (mmc_controller->slots[0].caps &
if (mmc_controller->caps &
MMC_CAP_8_BIT_DATA) {
omap_mux_init_signal("sdmmc2_dat4.sdmmc2_dat4",
OMAP_PIN_INPUT_PULLUP);
@ -243,7 +229,7 @@ static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller,
}
static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c,
struct omap_mmc_platform_data *mmc)
struct omap_hsmmc_platform_data *mmc)
{
char *hc_name;
@ -259,38 +245,22 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c,
else
snprintf(hc_name, (HSMMC_NAME_LEN + 1), "mmc%islot%i",
c->mmc, 1);
mmc->slots[0].name = hc_name;
mmc->nr_slots = 1;
mmc->slots[0].caps = c->caps;
mmc->slots[0].pm_caps = c->pm_caps;
mmc->slots[0].internal_clock = !c->ext_clock;
mmc->max_freq = c->max_freq;
mmc->name = hc_name;
mmc->caps = c->caps;
mmc->internal_clock = !c->ext_clock;
mmc->reg_offset = 0;
mmc->get_context_loss_count = hsmmc_get_context_loss;
mmc->slots[0].switch_pin = c->gpio_cd;
mmc->slots[0].gpio_wp = c->gpio_wp;
mmc->switch_pin = c->gpio_cd;
mmc->gpio_wp = c->gpio_wp;
mmc->slots[0].remux = c->remux;
mmc->slots[0].init_card = c->init_card;
mmc->remux = c->remux;
mmc->init_card = c->init_card;
if (c->cover_only)
mmc->slots[0].cover = 1;
mmc->cover = 1;
if (c->nonremovable)
mmc->slots[0].nonremovable = 1;
if (c->power_saving)
mmc->slots[0].power_saving = 1;
if (c->no_off)
mmc->slots[0].no_off = 1;
if (c->no_off_init)
mmc->slots[0].no_regulator_off_init = c->no_off_init;
if (c->vcc_aux_disable_is_sleep)
mmc->slots[0].vcc_aux_disable_is_sleep = 1;
mmc->nonremovable = 1;
/*
* NOTE: MMC slots should have a Vcc regulator set up.
@ -300,42 +270,42 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c,
* temporary HACK: ocr_mask instead of fixed supply
*/
if (soc_is_am35xx())
mmc->slots[0].ocr_mask = MMC_VDD_165_195 |
mmc->ocr_mask = MMC_VDD_165_195 |
MMC_VDD_26_27 |
MMC_VDD_27_28 |
MMC_VDD_29_30 |
MMC_VDD_30_31 |
MMC_VDD_31_32;
else
mmc->slots[0].ocr_mask = c->ocr_mask;
mmc->ocr_mask = c->ocr_mask;
if (!soc_is_am35xx())
mmc->slots[0].features |= HSMMC_HAS_PBIAS;
mmc->features |= HSMMC_HAS_PBIAS;
switch (c->mmc) {
case 1:
if (mmc->slots[0].features & HSMMC_HAS_PBIAS) {
if (mmc->features & HSMMC_HAS_PBIAS) {
/* on-chip level shifting via PBIAS0/PBIAS1 */
mmc->slots[0].before_set_reg =
mmc->before_set_reg =
omap_hsmmc1_before_set_reg;
mmc->slots[0].after_set_reg =
mmc->after_set_reg =
omap_hsmmc1_after_set_reg;
}
if (soc_is_am35xx())
mmc->slots[0].set_power = nop_mmc_set_power;
mmc->set_power = nop_mmc_set_power;
/* OMAP3630 HSMMC1 supports only 4-bit */
if (cpu_is_omap3630() &&
(c->caps & MMC_CAP_8_BIT_DATA)) {
c->caps &= ~MMC_CAP_8_BIT_DATA;
c->caps |= MMC_CAP_4_BIT_DATA;
mmc->slots[0].caps = c->caps;
mmc->caps = c->caps;
}
break;
case 2:
if (soc_is_am35xx())
mmc->slots[0].set_power = am35x_hsmmc2_set_power;
mmc->set_power = am35x_hsmmc2_set_power;
if (c->ext_clock)
c->transceiver = 1;
@ -343,17 +313,17 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c,
c->caps &= ~MMC_CAP_8_BIT_DATA;
c->caps |= MMC_CAP_4_BIT_DATA;
}
if (mmc->slots[0].features & HSMMC_HAS_PBIAS) {
if (mmc->features & HSMMC_HAS_PBIAS) {
/* off-chip level shifting, or none */
mmc->slots[0].before_set_reg = hsmmc2_before_set_reg;
mmc->slots[0].after_set_reg = NULL;
mmc->before_set_reg = hsmmc2_before_set_reg;
mmc->after_set_reg = NULL;
}
break;
case 3:
case 4:
case 5:
mmc->slots[0].before_set_reg = NULL;
mmc->slots[0].after_set_reg = NULL;
mmc->before_set_reg = NULL;
mmc->after_set_reg = NULL;
break;
default:
pr_err("MMC%d configuration not supported!\n", c->mmc);
@ -368,7 +338,7 @@ static int omap_hsmmc_done;
void omap_hsmmc_late_init(struct omap2_hsmmc_info *c)
{
struct platform_device *pdev;
struct omap_mmc_platform_data *mmc_pdata;
struct omap_hsmmc_platform_data *mmc_pdata;
int res;
if (omap_hsmmc_done != 1)
@ -388,8 +358,8 @@ void omap_hsmmc_late_init(struct omap2_hsmmc_info *c)
if (!mmc_pdata)
continue;
mmc_pdata->slots[0].switch_pin = c->gpio_cd;
mmc_pdata->slots[0].gpio_wp = c->gpio_wp;
mmc_pdata->switch_pin = c->gpio_cd;
mmc_pdata->gpio_wp = c->gpio_wp;
res = omap_device_register(pdev);
if (res)
@ -408,12 +378,12 @@ static void __init omap_hsmmc_init_one(struct omap2_hsmmc_info *hsmmcinfo,
struct omap_device *od;
struct platform_device *pdev;
char oh_name[MAX_OMAP_MMC_HWMOD_NAME_LEN];
struct omap_mmc_platform_data *mmc_data;
struct omap_mmc_dev_attr *mmc_dev_attr;
struct omap_hsmmc_platform_data *mmc_data;
struct omap_hsmmc_dev_attr *mmc_dev_attr;
char *name;
int res;
mmc_data = kzalloc(sizeof(struct omap_mmc_platform_data), GFP_KERNEL);
mmc_data = kzalloc(sizeof(*mmc_data), GFP_KERNEL);
if (!mmc_data) {
pr_err("Cannot allocate memory for mmc device!\n");
return;
@ -463,7 +433,7 @@ static void __init omap_hsmmc_init_one(struct omap2_hsmmc_info *hsmmcinfo,
}
res = platform_device_add_data(pdev, mmc_data,
sizeof(struct omap_mmc_platform_data));
sizeof(struct omap_hsmmc_platform_data));
if (res) {
pr_err("Could not add pdata for %s\n", name);
goto put_pdev;
@ -489,7 +459,7 @@ put_pdev:
platform_device_put(pdev);
free_name:
kfree(mmc_data->slots[0].name);
kfree(mmc_data->name);
free_mmc:
kfree(mmc_data);

View File

@ -12,25 +12,18 @@ struct omap2_hsmmc_info {
u8 mmc; /* controller 1/2/3 */
u32 caps; /* 4/8 wires and any additional host
* capabilities OR'd (ref. linux/mmc/host.h) */
u32 pm_caps; /* PM capabilities */
bool transceiver; /* MMC-2 option */
bool ext_clock; /* use external pin for input clock */
bool cover_only; /* No card detect - just cover switch */
bool nonremovable; /* Nonremovable e.g. eMMC */
bool power_saving; /* Try to sleep or power off when possible */
bool no_off; /* power_saving and power is not to go off */
bool no_off_init; /* no power off when not in MMC sleep state */
bool vcc_aux_disable_is_sleep; /* Regulator off remapped to sleep */
bool deferred; /* mmc needs a deferred probe */
int gpio_cd; /* or -EINVAL */
int gpio_wp; /* or -EINVAL */
char *name; /* or NULL for default */
struct platform_device *pdev; /* mmc controller instance */
int ocr_mask; /* temporary HACK */
int max_freq; /* maximum clock, if constrained by external
* circuitry, or 0 for default */
/* Remux (pad configuration) when powering on/off */
void (*remux)(struct device *dev, int slot, int power_on);
void (*remux)(struct device *dev, int power_on);
/* init some special card */
void (*init_card)(struct mmc_card *card);
};

View File

@ -1,5 +1,3 @@
#include <linux/mmc/host.h>
#include <linux/platform_data/mmc-omap.h>
#define OMAP24XX_NR_MMC 2
#define OMAP2420_MMC_SIZE OMAP1_MMC_SIZE
@ -7,14 +5,6 @@
#define OMAP4_MMC_REG_OFFSET 0x100
#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
void omap242x_init_mmc(struct omap_mmc_platform_data **mmc_data);
#else
static inline void omap242x_init_mmc(struct omap_mmc_platform_data **mmc_data)
{
}
#endif
struct omap_hwmod;
int omap_msdi_reset(struct omap_hwmod *oh);

View File

@ -36,7 +36,6 @@
#include "soc.h"
#include "iomap.h"
#include "common.h"
#include "mmc.h"
#include "prminst44xx.h"
#include "prcm_mpu44xx.h"
#include "omap4-sar-layout.h"

View File

@ -15,12 +15,12 @@
#include <linux/i2c-omap.h>
#include <linux/platform_data/asoc-ti-mcbsp.h>
#include <linux/platform_data/hsmmc-omap.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
#include <linux/omap-dma.h>
#include <plat/dmtimer.h>
#include "omap_hwmod.h"
#include "mmc.h"
#include "l3_2xxx.h"
#include "soc.h"
@ -372,7 +372,7 @@ static struct omap_hwmod_opt_clk omap2430_mmc1_opt_clks[] = {
{ .role = "dbck", .clk = "mmchsdb1_fck" },
};
static struct omap_mmc_dev_attr mmc1_dev_attr = {
static struct omap_hsmmc_dev_attr mmc1_dev_attr = {
.flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
};

View File

@ -15,10 +15,10 @@
*/
#include <linux/platform_data/gpio-omap.h>
#include <linux/platform_data/hsmmc-omap.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
#include "omap_hwmod.h"
#include "i2c.h"
#include "mmc.h"
#include "wd_timer.h"
#include "cm33xx.h"
#include "prm33xx.h"
@ -836,7 +836,7 @@ static struct omap_hwmod_class am33xx_mmc_hwmod_class = {
};
/* mmc0 */
static struct omap_mmc_dev_attr am33xx_mmc0_dev_attr = {
static struct omap_hsmmc_dev_attr am33xx_mmc0_dev_attr = {
.flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
};
@ -854,7 +854,7 @@ struct omap_hwmod am33xx_mmc0_hwmod = {
};
/* mmc1 */
static struct omap_mmc_dev_attr am33xx_mmc1_dev_attr = {
static struct omap_hsmmc_dev_attr am33xx_mmc1_dev_attr = {
.flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
};
@ -872,7 +872,7 @@ struct omap_hwmod am33xx_mmc1_hwmod = {
};
/* mmc2 */
static struct omap_mmc_dev_attr am33xx_mmc2_dev_attr = {
static struct omap_hsmmc_dev_attr am33xx_mmc2_dev_attr = {
.flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
};
struct omap_hwmod am33xx_mmc2_hwmod = {

View File

@ -27,7 +27,6 @@
#include "prm33xx.h"
#include "prm-regbits-33xx.h"
#include "i2c.h"
#include "mmc.h"
#include "wd_timer.h"
#include "omap_hwmod_33xx_43xx_common_data.h"

View File

@ -18,6 +18,7 @@
#include <linux/i2c-omap.h>
#include <linux/power/smartreflex.h>
#include <linux/platform_data/gpio-omap.h>
#include <linux/platform_data/hsmmc-omap.h>
#include <linux/omap-dma.h>
#include "l3_3xxx.h"
@ -37,7 +38,6 @@
#include "cm-regbits-34xx.h"
#include "i2c.h"
#include "mmc.h"
#include "wd_timer.h"
#include "serial.h"
@ -1786,12 +1786,12 @@ static struct omap_hwmod_opt_clk omap34xx_mmc1_opt_clks[] = {
{ .role = "dbck", .clk = "omap_32k_fck", },
};
static struct omap_mmc_dev_attr mmc1_dev_attr = {
static struct omap_hsmmc_dev_attr mmc1_dev_attr = {
.flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
};
/* See 35xx errata 2.1.1.128 in SPRZ278F */
static struct omap_mmc_dev_attr mmc1_pre_es3_dev_attr = {
static struct omap_hsmmc_dev_attr mmc1_pre_es3_dev_attr = {
.flags = (OMAP_HSMMC_SUPPORTS_DUAL_VOLT |
OMAP_HSMMC_BROKEN_MULTIBLOCK_READ),
};
@ -1854,7 +1854,7 @@ static struct omap_hwmod_opt_clk omap34xx_mmc2_opt_clks[] = {
};
/* See 35xx errata 2.1.1.128 in SPRZ278F */
static struct omap_mmc_dev_attr mmc2_pre_es3_dev_attr = {
static struct omap_hsmmc_dev_attr mmc2_pre_es3_dev_attr = {
.flags = OMAP_HSMMC_BROKEN_MULTIBLOCK_READ,
};

View File

@ -22,6 +22,7 @@
#include <linux/io.h>
#include <linux/platform_data/gpio-omap.h>
#include <linux/platform_data/hsmmc-omap.h>
#include <linux/power/smartreflex.h>
#include <linux/i2c-omap.h>
@ -39,7 +40,6 @@
#include "prm44xx.h"
#include "prm-regbits-44xx.h"
#include "i2c.h"
#include "mmc.h"
#include "wd_timer.h"
/* Base offset for all OMAP4 interrupts external to MPUSS */
@ -1952,7 +1952,7 @@ static struct omap_hwmod_dma_info omap44xx_mmc1_sdma_reqs[] = {
};
/* mmc1 dev_attr */
static struct omap_mmc_dev_attr mmc1_dev_attr = {
static struct omap_hsmmc_dev_attr mmc1_dev_attr = {
.flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
};

View File

@ -19,6 +19,7 @@
#include <linux/io.h>
#include <linux/platform_data/gpio-omap.h>
#include <linux/platform_data/hsmmc-omap.h>
#include <linux/power/smartreflex.h>
#include <linux/i2c-omap.h>
@ -33,7 +34,6 @@
#include "cm2_54xx.h"
#include "prm54xx.h"
#include "i2c.h"
#include "mmc.h"
#include "wd_timer.h"
/* Base offset for all OMAP5 interrupts external to MPUSS */
@ -1269,7 +1269,7 @@ static struct omap_hwmod_opt_clk mmc1_opt_clks[] = {
};
/* mmc1 dev_attr */
static struct omap_mmc_dev_attr mmc1_dev_attr = {
static struct omap_hsmmc_dev_attr mmc1_dev_attr = {
.flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
};

View File

@ -19,6 +19,7 @@
#include <linux/io.h>
#include <linux/platform_data/gpio-omap.h>
#include <linux/platform_data/hsmmc-omap.h>
#include <linux/power/smartreflex.h>
#include <linux/i2c-omap.h>
@ -33,7 +34,6 @@
#include "cm2_7xx.h"
#include "prm7xx.h"
#include "i2c.h"
#include "mmc.h"
#include "wd_timer.h"
#include "soc.h"
@ -1301,7 +1301,7 @@ static struct omap_hwmod_opt_clk mmc1_opt_clks[] = {
};
/* mmc1 dev_attr */
static struct omap_mmc_dev_attr mmc1_dev_attr = {
static struct omap_hsmmc_dev_attr mmc1_dev_attr = {
.flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
};

View File

@ -17,7 +17,7 @@
#include <linux/spi/spi.h>
#include <linux/usb/atmel_usba_udc.h>
#include <mach/atmel-mci.h>
#include <linux/platform_data/mmc-atmel-mci.h>
#include <linux/atmel-mci.h>
#include <asm/io.h>

View File

@ -1,17 +0,0 @@
#ifndef __MACH_ATMEL_MCI_H
#define __MACH_ATMEL_MCI_H
#include <linux/platform_data/dma-dw.h>
/**
* struct mci_dma_data - DMA data for MCI interface
*/
struct mci_dma_data {
struct dw_dma_slave sdata;
};
/* accessor macros */
#define slave_data_ptr(s) (&(s)->sdata)
#define find_slave_dev(s) ((s)->sdata.dma_dev)
#endif /* __MACH_ATMEL_MCI_H */

View File

@ -78,13 +78,16 @@ static int perdev_minors = CONFIG_MMC_BLOCK_MINORS;
/*
* We've only got one major, so number of mmcblk devices is
* limited to 256 / number of minors per device.
* limited to (1 << 20) / number of minors per device. It is also
* currently limited by the size of the static bitmaps below.
*/
static int max_devices;
/* 256 minors, so at most 256 separate devices */
static DECLARE_BITMAP(dev_use, 256);
static DECLARE_BITMAP(name_use, 256);
#define MAX_DEVICES 256
/* TODO: Replace these with struct ida */
static DECLARE_BITMAP(dev_use, MAX_DEVICES);
static DECLARE_BITMAP(name_use, MAX_DEVICES);
/*
* There is one mmc_blk_data per slot.
@ -112,7 +115,7 @@ struct mmc_blk_data {
/*
* Only set in main mmc_blk_data associated
* with mmc_card with mmc_set_drvdata, and keeps
* with mmc_card with dev_set_drvdata, and keeps
* track of the current selected device partition.
*/
unsigned int part_curr;
@ -260,7 +263,7 @@ static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,
int ret;
struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
ret = snprintf(buf, PAGE_SIZE, "%d",
ret = snprintf(buf, PAGE_SIZE, "%d\n",
get_disk_ro(dev_to_disk(dev)) ^
md->read_only);
mmc_blk_put(md);
@ -642,7 +645,7 @@ static inline int mmc_blk_part_switch(struct mmc_card *card,
struct mmc_blk_data *md)
{
int ret;
struct mmc_blk_data *main_md = mmc_get_drvdata(card);
struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev);
if (main_md->part_curr == md->part_type)
return 0;
@ -1004,7 +1007,8 @@ static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host,
err = mmc_hw_reset(host);
/* Ensure we switch back to the correct partition */
if (err != -EOPNOTSUPP) {
struct mmc_blk_data *main_md = mmc_get_drvdata(host->card);
struct mmc_blk_data *main_md =
dev_get_drvdata(&host->card->dev);
int part_err;
main_md->part_curr = main_md->part_type;
@ -1308,19 +1312,11 @@ static int mmc_blk_packed_err_check(struct mmc_card *card,
}
if (status & R1_EXCEPTION_EVENT) {
ext_csd = kzalloc(512, GFP_KERNEL);
if (!ext_csd) {
pr_err("%s: unable to allocate buffer for ext_csd\n",
req->rq_disk->disk_name);
return -ENOMEM;
}
err = mmc_send_ext_csd(card, ext_csd);
err = mmc_get_ext_csd(card, &ext_csd);
if (err) {
pr_err("%s: error %d sending ext_csd\n",
req->rq_disk->disk_name, err);
check = MMC_BLK_ABORT;
goto free;
return MMC_BLK_ABORT;
}
if ((ext_csd[EXT_CSD_EXP_EVENTS_STATUS] &
@ -1338,7 +1334,6 @@ static int mmc_blk_packed_err_check(struct mmc_card *card,
req->rq_disk->disk_name, packed->nr_entries,
packed->blocks, packed->idx_failure);
}
free:
kfree(ext_csd);
}
@ -2093,7 +2088,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
/*
* !subname implies we are creating main mmc_blk_data that will be
* associated with mmc_card with mmc_set_drvdata. Due to device
* associated with mmc_card with dev_set_drvdata. Due to device
* partitions, devidx will not coincide with a per-physical card
* index anymore so we keep track of a name index.
*/
@ -2425,8 +2420,9 @@ static const struct mmc_fixup blk_fixups[] =
END_FIXUP
};
static int mmc_blk_probe(struct mmc_card *card)
static int mmc_blk_probe(struct device *dev)
{
struct mmc_card *card = mmc_dev_to_card(dev);
struct mmc_blk_data *md, *part_md;
char cap_str[10];
@ -2451,7 +2447,7 @@ static int mmc_blk_probe(struct mmc_card *card)
if (mmc_blk_alloc_parts(card, md))
goto out;
mmc_set_drvdata(card, md);
dev_set_drvdata(dev, md);
if (mmc_add_disk(md))
goto out;
@ -2481,9 +2477,10 @@ static int mmc_blk_probe(struct mmc_card *card)
return 0;
}
static void mmc_blk_remove(struct mmc_card *card)
static int mmc_blk_remove(struct device *dev)
{
struct mmc_blk_data *md = mmc_get_drvdata(card);
struct mmc_card *card = mmc_dev_to_card(dev);
struct mmc_blk_data *md = dev_get_drvdata(dev);
mmc_blk_remove_parts(card, md);
pm_runtime_get_sync(&card->dev);
@ -2494,13 +2491,15 @@ static void mmc_blk_remove(struct mmc_card *card)
pm_runtime_disable(&card->dev);
pm_runtime_put_noidle(&card->dev);
mmc_blk_remove_req(md);
mmc_set_drvdata(card, NULL);
dev_set_drvdata(dev, NULL);
return 0;
}
static int _mmc_blk_suspend(struct mmc_card *card)
static int _mmc_blk_suspend(struct device *dev)
{
struct mmc_blk_data *part_md;
struct mmc_blk_data *md = mmc_get_drvdata(card);
struct mmc_blk_data *md = dev_get_drvdata(dev);
if (md) {
mmc_queue_suspend(&md->queue);
@ -2511,21 +2510,21 @@ static int _mmc_blk_suspend(struct mmc_card *card)
return 0;
}
static void mmc_blk_shutdown(struct mmc_card *card)
static void mmc_blk_shutdown(struct device *dev)
{
_mmc_blk_suspend(card);
_mmc_blk_suspend(dev);
}
#ifdef CONFIG_PM
static int mmc_blk_suspend(struct mmc_card *card)
#ifdef CONFIG_PM_SLEEP
static int mmc_blk_suspend(struct device *dev)
{
return _mmc_blk_suspend(card);
return _mmc_blk_suspend(dev);
}
static int mmc_blk_resume(struct mmc_card *card)
static int mmc_blk_resume(struct device *dev)
{
struct mmc_blk_data *part_md;
struct mmc_blk_data *md = mmc_get_drvdata(card);
struct mmc_blk_data *md = dev_get_drvdata(dev);
if (md) {
/*
@ -2540,19 +2539,15 @@ static int mmc_blk_resume(struct mmc_card *card)
}
return 0;
}
#else
#define mmc_blk_suspend NULL
#define mmc_blk_resume NULL
#endif
static struct mmc_driver mmc_driver = {
.drv = {
.name = "mmcblk",
},
static SIMPLE_DEV_PM_OPS(mmc_blk_pm_ops, mmc_blk_suspend, mmc_blk_resume);
static struct device_driver mmc_driver = {
.name = "mmcblk",
.pm = &mmc_blk_pm_ops,
.probe = mmc_blk_probe,
.remove = mmc_blk_remove,
.suspend = mmc_blk_suspend,
.resume = mmc_blk_resume,
.shutdown = mmc_blk_shutdown,
};
@ -2563,7 +2558,7 @@ static int __init mmc_blk_init(void)
if (perdev_minors != CONFIG_MMC_BLOCK_MINORS)
pr_info("mmcblk: using %d minors per device\n", perdev_minors);
max_devices = 256 / perdev_minors;
max_devices = min(MAX_DEVICES, (1 << MINORBITS) / perdev_minors);
res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");
if (res)

View File

@ -14,6 +14,7 @@
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/scatterlist.h>
#include <linux/swap.h> /* For nr_free_buffer_pages() */
@ -32,6 +33,8 @@
#define BUFFER_ORDER 2
#define BUFFER_SIZE (PAGE_SIZE << BUFFER_ORDER)
#define TEST_ALIGN_END 8
/*
* Limit the test area size to the maximum MMC HC erase group size. Note that
* the maximum SD allocation unit size is just 4MiB.
@ -1174,7 +1177,7 @@ static int mmc_test_align_write(struct mmc_test_card *test)
int ret, i;
struct scatterlist sg;
for (i = 1;i < 4;i++) {
for (i = 1; i < TEST_ALIGN_END; i++) {
sg_init_one(&sg, test->buffer + i, 512);
ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1);
if (ret)
@ -1189,7 +1192,7 @@ static int mmc_test_align_read(struct mmc_test_card *test)
int ret, i;
struct scatterlist sg;
for (i = 1;i < 4;i++) {
for (i = 1; i < TEST_ALIGN_END; i++) {
sg_init_one(&sg, test->buffer + i, 512);
ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0);
if (ret)
@ -1216,7 +1219,7 @@ static int mmc_test_align_multi_write(struct mmc_test_card *test)
if (size < 1024)
return RESULT_UNSUP_HOST;
for (i = 1;i < 4;i++) {
for (i = 1; i < TEST_ALIGN_END; i++) {
sg_init_one(&sg, test->buffer + i, size);
ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
if (ret)
@ -1243,7 +1246,7 @@ static int mmc_test_align_multi_read(struct mmc_test_card *test)
if (size < 1024)
return RESULT_UNSUP_HOST;
for (i = 1;i < 4;i++) {
for (i = 1; i < TEST_ALIGN_END; i++) {
sg_init_one(&sg, test->buffer + i, size);
ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
if (ret)
@ -2997,8 +3000,9 @@ err:
return ret;
}
static int mmc_test_probe(struct mmc_card *card)
static int mmc_test_probe(struct device *dev)
{
struct mmc_card *card = mmc_dev_to_card(dev);
int ret;
if (!mmc_card_mmc(card) && !mmc_card_sd(card))
@ -3013,20 +3017,22 @@ static int mmc_test_probe(struct mmc_card *card)
return 0;
}
static void mmc_test_remove(struct mmc_card *card)
static int mmc_test_remove(struct device *dev)
{
struct mmc_card *card = mmc_dev_to_card(dev);
mmc_test_free_result(card);
mmc_test_free_dbgfs_file(card);
return 0;
}
static void mmc_test_shutdown(struct mmc_card *card)
static void mmc_test_shutdown(struct device *dev)
{
}
static struct mmc_driver mmc_driver = {
.drv = {
.name = "mmc_test",
},
static struct device_driver mmc_driver = {
.name = "mmc_test",
.probe = mmc_test_probe,
.remove = mmc_test_remove,
.shutdown = mmc_test_shutdown,

View File

@ -232,13 +232,15 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
if (!mqrq_cur->bounce_buf) {
pr_warn("%s: unable to allocate bounce cur buffer\n",
mmc_card_name(card));
}
mqrq_prev->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
if (!mqrq_prev->bounce_buf) {
pr_warn("%s: unable to allocate bounce prev buffer\n",
mmc_card_name(card));
kfree(mqrq_cur->bounce_buf);
mqrq_cur->bounce_buf = NULL;
} else {
mqrq_prev->bounce_buf =
kmalloc(bouncesz, GFP_KERNEL);
if (!mqrq_prev->bounce_buf) {
pr_warn("%s: unable to allocate bounce prev buffer\n",
mmc_card_name(card));
kfree(mqrq_cur->bounce_buf);
mqrq_cur->bounce_buf = NULL;
}
}
}

View File

@ -25,8 +25,6 @@
#include "sdio_cis.h"
#include "bus.h"
#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)
static ssize_t type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@ -106,33 +104,14 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
return retval;
}
static int mmc_bus_probe(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev);
return drv->probe(card);
}
static int mmc_bus_remove(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev);
drv->remove(card);
return 0;
}
static void mmc_bus_shutdown(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev);
struct mmc_host *host = card->host;
int ret;
if (dev->driver && drv->shutdown)
drv->shutdown(card);
if (dev->driver && dev->driver->shutdown)
dev->driver->shutdown(dev);
if (host->bus_ops->shutdown) {
ret = host->bus_ops->shutdown(host);
@ -145,16 +124,13 @@ static void mmc_bus_shutdown(struct device *dev)
#ifdef CONFIG_PM_SLEEP
static int mmc_bus_suspend(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev);
struct mmc_host *host = card->host;
int ret;
if (dev->driver && drv->suspend) {
ret = drv->suspend(card);
if (ret)
return ret;
}
ret = pm_generic_suspend(dev);
if (ret)
return ret;
ret = host->bus_ops->suspend(host);
return ret;
@ -162,7 +138,6 @@ static int mmc_bus_suspend(struct device *dev)
static int mmc_bus_resume(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev);
struct mmc_host *host = card->host;
int ret;
@ -172,9 +147,7 @@ static int mmc_bus_resume(struct device *dev)
pr_warn("%s: error %d during resume (card was removed?)\n",
mmc_hostname(host), ret);
if (dev->driver && drv->resume)
ret = drv->resume(card);
ret = pm_generic_resume(dev);
return ret;
}
#endif
@ -207,8 +180,6 @@ static struct bus_type mmc_bus_type = {
.dev_groups = mmc_dev_groups,
.match = mmc_bus_match,
.uevent = mmc_bus_uevent,
.probe = mmc_bus_probe,
.remove = mmc_bus_remove,
.shutdown = mmc_bus_shutdown,
.pm = &mmc_bus_pm_ops,
};
@ -227,24 +198,22 @@ void mmc_unregister_bus(void)
* mmc_register_driver - register a media driver
* @drv: MMC media driver
*/
int mmc_register_driver(struct mmc_driver *drv)
int mmc_register_driver(struct device_driver *drv)
{
drv->drv.bus = &mmc_bus_type;
return driver_register(&drv->drv);
drv->bus = &mmc_bus_type;
return driver_register(drv);
}
EXPORT_SYMBOL(mmc_register_driver);
/**
* mmc_unregister_driver - unregister a media driver
* @drv: MMC media driver
*/
void mmc_unregister_driver(struct mmc_driver *drv)
void mmc_unregister_driver(struct device_driver *drv)
{
drv->drv.bus = &mmc_bus_type;
driver_unregister(&drv->drv);
drv->bus = &mmc_bus_type;
driver_unregister(drv);
}
EXPORT_SYMBOL(mmc_unregister_driver);
static void mmc_release_card(struct device *dev)

View File

@ -149,6 +149,14 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
led_trigger_event(host->led, LED_OFF);
if (mrq->sbc) {
pr_debug("%s: req done <CMD%u>: %d: %08x %08x %08x %08x\n",
mmc_hostname(host), mrq->sbc->opcode,
mrq->sbc->error,
mrq->sbc->resp[0], mrq->sbc->resp[1],
mrq->sbc->resp[2], mrq->sbc->resp[3]);
}
pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n",
mmc_hostname(host), cmd->opcode, err,
cmd->resp[0], cmd->resp[1],
@ -214,6 +222,10 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mrq->cmd->error = 0;
mrq->cmd->mrq = mrq;
if (mrq->sbc) {
mrq->sbc->error = 0;
mrq->sbc->mrq = mrq;
}
if (mrq->data) {
BUG_ON(mrq->data->blksz > host->max_blk_size);
BUG_ON(mrq->data->blocks > host->max_blk_count);
@ -538,8 +550,18 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
if (host->card && mmc_card_mmc(host->card) &&
((mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1) ||
(mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1B)) &&
(host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT))
(host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT)) {
/* Cancel the prepared request */
if (areq)
mmc_post_req(host, areq->mrq, -EINVAL);
mmc_start_bkops(host->card, true);
/* prepare the request again */
if (areq)
mmc_pre_req(host, areq->mrq, !host->areq);
}
}
if (!err && areq)
@ -709,27 +731,16 @@ int mmc_read_bkops_status(struct mmc_card *card)
int err;
u8 *ext_csd;
/*
* In future work, we should consider storing the entire ext_csd.
*/
ext_csd = kmalloc(512, GFP_KERNEL);
if (!ext_csd) {
pr_err("%s: could not allocate buffer to receive the ext_csd.\n",
mmc_hostname(card->host));
return -ENOMEM;
}
mmc_claim_host(card->host);
err = mmc_send_ext_csd(card, ext_csd);
err = mmc_get_ext_csd(card, &ext_csd);
mmc_release_host(card->host);
if (err)
goto out;
return err;
card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS];
card->ext_csd.raw_exception_status = ext_csd[EXT_CSD_EXP_EVENTS_STATUS];
out:
kfree(ext_csd);
return err;
return 0;
}
EXPORT_SYMBOL(mmc_read_bkops_status);
@ -1088,6 +1099,22 @@ void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
mmc_host_clk_release(host);
}
/*
* Set initial state after a power cycle or a hw_reset.
*/
void mmc_set_initial_state(struct mmc_host *host)
{
if (mmc_host_is_spi(host))
host->ios.chip_select = MMC_CS_HIGH;
else
host->ios.chip_select = MMC_CS_DONTCARE;
host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ios.timing = MMC_TIMING_LEGACY;
mmc_set_ios(host);
}
/**
* mmc_vdd_to_ocrbitnum - Convert a voltage to the OCR bit number
* @vdd: voltage (mV)
@ -1420,18 +1447,20 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
pr_warn("%s: cannot verify signal voltage switch\n",
mmc_hostname(host));
mmc_host_clk_hold(host);
cmd.opcode = SD_SWITCH_VOLTAGE;
cmd.arg = 0;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(host, &cmd, 0);
if (err)
return err;
goto err_command;
if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
return -EIO;
mmc_host_clk_hold(host);
if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR)) {
err = -EIO;
goto err_command;
}
/*
* The card should drive cmd and dat[0:3] low immediately
* after the response of cmd11, but wait 1 ms to be sure
@ -1480,6 +1509,7 @@ power_cycle:
mmc_power_cycle(host, ocr);
}
err_command:
mmc_host_clk_release(host);
return err;
@ -1526,15 +1556,9 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
mmc_host_clk_hold(host);
host->ios.vdd = fls(ocr) - 1;
if (mmc_host_is_spi(host))
host->ios.chip_select = MMC_CS_HIGH;
else
host->ios.chip_select = MMC_CS_DONTCARE;
host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
host->ios.power_mode = MMC_POWER_UP;
host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ios.timing = MMC_TIMING_LEGACY;
mmc_set_ios(host);
/* Set initial state and call mmc_set_ios */
mmc_set_initial_state(host);
/* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */
if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330) == 0)
@ -1574,14 +1598,9 @@ void mmc_power_off(struct mmc_host *host)
host->ios.clock = 0;
host->ios.vdd = 0;
if (!mmc_host_is_spi(host)) {
host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
host->ios.chip_select = MMC_CS_DONTCARE;
}
host->ios.power_mode = MMC_POWER_OFF;
host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ios.timing = MMC_TIMING_LEGACY;
mmc_set_ios(host);
/* Set initial state and call mmc_set_ios */
mmc_set_initial_state(host);
/*
* Some configurations, such as the 802.11 SDIO card in the OLPC
@ -2259,30 +2278,16 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
/* If the reset has happened, then a status command will fail */
if (check) {
struct mmc_command cmd = {0};
int err;
u32 status;
cmd.opcode = MMC_SEND_STATUS;
if (!mmc_host_is_spi(card->host))
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 0);
if (!err) {
if (!mmc_send_status(card, &status)) {
mmc_host_clk_release(host);
return -ENOSYS;
}
}
if (mmc_host_is_spi(host)) {
host->ios.chip_select = MMC_CS_HIGH;
host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
} else {
host->ios.chip_select = MMC_CS_DONTCARE;
host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
}
host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ios.timing = MMC_TIMING_LEGACY;
mmc_set_ios(host);
/* Set initial state and call mmc_set_ios */
mmc_set_initial_state(host);
mmc_host_clk_release(host);

View File

@ -49,6 +49,7 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
void mmc_power_up(struct mmc_host *host, u32 ocr);
void mmc_power_off(struct mmc_host *host);
void mmc_power_cycle(struct mmc_host *host, u32 ocr);
void mmc_set_initial_state(struct mmc_host *host);
static inline void mmc_delay(unsigned int ms)
{

View File

@ -291,14 +291,8 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
if (!buf)
return -ENOMEM;
ext_csd = kmalloc(512, GFP_KERNEL);
if (!ext_csd) {
err = -ENOMEM;
goto out_free;
}
mmc_get_card(card);
err = mmc_send_ext_csd(card, ext_csd);
err = mmc_get_ext_csd(card, &ext_csd);
mmc_put_card(card);
if (err)
goto out_free;
@ -314,7 +308,6 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
out_free:
kfree(buf);
kfree(ext_csd);
return err;
}

View File

@ -177,65 +177,6 @@ static int mmc_decode_csd(struct mmc_card *card)
return 0;
}
/*
* Read extended CSD.
*/
static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
{
int err;
u8 *ext_csd;
BUG_ON(!card);
BUG_ON(!new_ext_csd);
*new_ext_csd = NULL;
if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
return 0;
/*
* As the ext_csd is so large and mostly unused, we don't store the
* raw block in mmc_card.
*/
ext_csd = kmalloc(512, GFP_KERNEL);
if (!ext_csd) {
pr_err("%s: could not allocate a buffer to "
"receive the ext_csd.\n", mmc_hostname(card->host));
return -ENOMEM;
}
err = mmc_send_ext_csd(card, ext_csd);
if (err) {
kfree(ext_csd);
*new_ext_csd = NULL;
/* If the host or the card can't do the switch,
* fail more gracefully. */
if ((err != -EINVAL)
&& (err != -ENOSYS)
&& (err != -EFAULT))
return err;
/*
* High capacity cards should have this "magic" size
* stored in their CSD.
*/
if (card->csd.capacity == (4096 * 512)) {
pr_err("%s: unable to read EXT_CSD "
"on a possible high capacity card. "
"Card will be ignored.\n",
mmc_hostname(card->host));
} else {
pr_warn("%s: unable to read EXT_CSD, performance might suffer\n",
mmc_hostname(card->host));
err = 0;
}
} else
*new_ext_csd = ext_csd;
return err;
}
static void mmc_select_card_type(struct mmc_card *card)
{
struct mmc_host *host = card->host;
@ -391,16 +332,11 @@ static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd)
/*
* Decode extended CSD.
*/
static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
{
int err = 0, idx;
unsigned int part_size;
BUG_ON(!card);
if (!ext_csd)
return 0;
/* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */
card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE];
if (card->csd.structure == 3) {
@ -628,15 +564,55 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
card->ext_csd.data_sector_size = 512;
}
/* eMMC v5 or later */
if (card->ext_csd.rev >= 7) {
memcpy(card->ext_csd.fwrev, &ext_csd[EXT_CSD_FIRMWARE_VERSION],
MMC_FIRMWARE_LEN);
card->ext_csd.ffu_capable =
(ext_csd[EXT_CSD_SUPPORTED_MODE] & 0x1) &&
!(ext_csd[EXT_CSD_FW_CONFIG] & 0x1);
}
out:
return err;
}
static inline void mmc_free_ext_csd(u8 *ext_csd)
static int mmc_read_ext_csd(struct mmc_card *card)
{
kfree(ext_csd);
}
u8 *ext_csd;
int err;
if (!mmc_can_ext_csd(card))
return 0;
err = mmc_get_ext_csd(card, &ext_csd);
if (err) {
/* If the host or the card can't do the switch,
* fail more gracefully. */
if ((err != -EINVAL)
&& (err != -ENOSYS)
&& (err != -EFAULT))
return err;
/*
* High capacity cards should have this "magic" size
* stored in their CSD.
*/
if (card->csd.capacity == (4096 * 512)) {
pr_err("%s: unable to read EXT_CSD on a possible high capacity card. Card will be ignored.\n",
mmc_hostname(card->host));
} else {
pr_warn("%s: unable to read EXT_CSD, performance might suffer\n",
mmc_hostname(card->host));
err = 0;
}
return err;
}
err = mmc_decode_ext_csd(card, ext_csd);
kfree(ext_csd);
return err;
}
static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
{
@ -647,11 +623,8 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
return 0;
err = mmc_get_ext_csd(card, &bw_ext_csd);
if (err || bw_ext_csd == NULL) {
err = -EINVAL;
goto out;
}
if (err)
return err;
/* only compare read only fields */
err = !((card->ext_csd.raw_partition_support ==
@ -710,8 +683,7 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
if (err)
err = -EINVAL;
out:
mmc_free_ext_csd(bw_ext_csd);
kfree(bw_ext_csd);
return err;
}
@ -722,7 +694,7 @@ MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
MMC_DEV_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
MMC_DEV_ATTR(erase_size, "%u\n", card->erase_size << 9);
MMC_DEV_ATTR(preferred_erase_size, "%u\n", card->pref_erase << 9);
MMC_DEV_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
MMC_DEV_ATTR(ffu_capable, "%d\n", card->ext_csd.ffu_capable);
MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
@ -735,6 +707,22 @@ MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size);
MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult);
MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors);
static ssize_t mmc_fwrev_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct mmc_card *card = mmc_dev_to_card(dev);
if (card->ext_csd.rev < 7) {
return sprintf(buf, "0x%x\n", card->cid.fwrev);
} else {
return sprintf(buf, "0x%*phN\n", MMC_FIRMWARE_LEN,
card->ext_csd.fwrev);
}
}
static DEVICE_ATTR(fwrev, S_IRUGO, mmc_fwrev_show, NULL);
static struct attribute *mmc_std_attrs[] = {
&dev_attr_cid.attr,
&dev_attr_csd.attr,
@ -742,6 +730,7 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_erase_size.attr,
&dev_attr_preferred_erase_size.attr,
&dev_attr_fwrev.attr,
&dev_attr_ffu_capable.attr,
&dev_attr_hwrev.attr,
&dev_attr_manfid.attr,
&dev_attr_name.attr,
@ -774,14 +763,6 @@ static int __mmc_select_powerclass(struct mmc_card *card,
unsigned int pwrclass_val = 0;
int err = 0;
/* Power class selection is supported for versions >= 4.0 */
if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
return 0;
/* Power class values are defined only for 4/8 bit bus */
if (bus_width == EXT_CSD_BUS_WIDTH_1)
return 0;
switch (1 << host->ios.vdd) {
case MMC_VDD_165_195:
if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
@ -844,7 +825,7 @@ static int mmc_select_powerclass(struct mmc_card *card)
int err, ddr;
/* Power class selection is supported for versions >= 4.0 */
if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
if (!mmc_can_ext_csd(card))
return 0;
bus_width = host->ios.bus_width;
@ -905,7 +886,7 @@ static int mmc_select_bus_width(struct mmc_card *card)
unsigned idx, bus_width = 0;
int err = 0;
if ((card->csd.mmca_vsn < CSD_SPEC_VER_4) &&
if (!mmc_can_ext_csd(card) &&
!(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))
return 0;
@ -998,7 +979,7 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
ext_csd_bits,
card->ext_csd.generic_cmd6_time);
if (err) {
pr_warn("%s: switch to bus width %d ddr failed\n",
pr_err("%s: switch to bus width %d ddr failed\n",
mmc_hostname(host), 1 << bus_width);
return err;
}
@ -1069,7 +1050,7 @@ static int mmc_select_hs400(struct mmc_card *card)
card->ext_csd.generic_cmd6_time,
true, true, true);
if (err) {
pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
pr_err("%s: switch to high-speed from hs200 failed, err:%d\n",
mmc_hostname(host), err);
return err;
}
@ -1079,7 +1060,7 @@ static int mmc_select_hs400(struct mmc_card *card)
EXT_CSD_DDR_BUS_WIDTH_8,
card->ext_csd.generic_cmd6_time);
if (err) {
pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
pr_err("%s: switch to bus width for hs400 failed, err:%d\n",
mmc_hostname(host), err);
return err;
}
@ -1089,7 +1070,7 @@ static int mmc_select_hs400(struct mmc_card *card)
card->ext_csd.generic_cmd6_time,
true, true, true);
if (err) {
pr_warn("%s: switch to hs400 failed, err:%d\n",
pr_err("%s: switch to hs400 failed, err:%d\n",
mmc_hostname(host), err);
return err;
}
@ -1146,8 +1127,7 @@ static int mmc_select_timing(struct mmc_card *card)
{
int err = 0;
if ((card->csd.mmca_vsn < CSD_SPEC_VER_4 &&
card->ext_csd.hs_max_dtr == 0))
if (!mmc_can_ext_csd(card))
goto bus_speed;
if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
@ -1232,7 +1212,7 @@ static int mmc_hs200_tuning(struct mmc_card *card)
mmc_host_clk_release(host);
if (err)
pr_warn("%s: tuning execution failed\n",
pr_err("%s: tuning execution failed\n",
mmc_hostname(host));
}
@ -1252,7 +1232,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
int err;
u32 cid[4];
u32 rocr;
u8 *ext_csd = NULL;
BUG_ON(!host);
WARN_ON(!host->claimed);
@ -1361,14 +1340,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
}
if (!oldcard) {
/*
* Fetch and process extended CSD.
*/
err = mmc_get_ext_csd(card, &ext_csd);
if (err)
goto free_card;
err = mmc_read_ext_csd(card, ext_csd);
/* Read extended CSD. */
err = mmc_read_ext_csd(card);
if (err)
goto free_card;
@ -1458,18 +1431,18 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
if (mmc_card_hs200(card)) {
err = mmc_hs200_tuning(card);
if (err)
goto err;
goto free_card;
err = mmc_select_hs400(card);
if (err)
goto err;
goto free_card;
} else if (mmc_card_hs(card)) {
/* Select the desired bus width optionally */
err = mmc_select_bus_width(card);
if (!IS_ERR_VALUE(err)) {
err = mmc_select_hs_ddr(card);
if (err)
goto err;
goto free_card;
}
}
@ -1545,15 +1518,12 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
if (!oldcard)
host->card = card;
mmc_free_ext_csd(ext_csd);
return 0;
free_card:
if (!oldcard)
mmc_remove_card(card);
err:
mmc_free_ext_csd(ext_csd);
return err;
}

View File

@ -264,20 +264,6 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
struct mmc_command cmd = {0};
struct mmc_data data = {0};
struct scatterlist sg;
void *data_buf;
int is_on_stack;
is_on_stack = object_is_on_stack(buf);
if (is_on_stack) {
/*
* dma onto stack is unsafe/nonportable, but callers to this
* routine normally provide temporary on-stack buffers ...
*/
data_buf = kmalloc(len, GFP_KERNEL);
if (!data_buf)
return -ENOMEM;
} else
data_buf = buf;
mrq.cmd = &cmd;
mrq.data = &data;
@ -298,7 +284,7 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
data.sg = &sg;
data.sg_len = 1;
sg_init_one(&sg, data_buf, len);
sg_init_one(&sg, buf, len);
if (opcode == MMC_SEND_CSD || opcode == MMC_SEND_CID) {
/*
@ -312,11 +298,6 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
mmc_wait_for_req(host, &mrq);
if (is_on_stack) {
memcpy(buf, data_buf, len);
kfree(data_buf);
}
if (cmd.error)
return cmd.error;
if (data.error)
@ -334,7 +315,7 @@ int mmc_send_csd(struct mmc_card *card, u32 *csd)
return mmc_send_cxd_native(card->host, card->rca << 16,
csd, MMC_SEND_CSD);
csd_tmp = kmalloc(16, GFP_KERNEL);
csd_tmp = kzalloc(16, GFP_KERNEL);
if (!csd_tmp)
return -ENOMEM;
@ -362,7 +343,7 @@ int mmc_send_cid(struct mmc_host *host, u32 *cid)
cid, MMC_SEND_CID);
}
cid_tmp = kmalloc(16, GFP_KERNEL);
cid_tmp = kzalloc(16, GFP_KERNEL);
if (!cid_tmp)
return -ENOMEM;
@ -378,12 +359,35 @@ err:
return ret;
}
int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
{
return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD,
ext_csd, 512);
int err;
u8 *ext_csd;
if (!card || !new_ext_csd)
return -EINVAL;
if (!mmc_can_ext_csd(card))
return -EOPNOTSUPP;
/*
* As the ext_csd is so large and mostly unused, we don't store the
* raw block in mmc_card.
*/
ext_csd = kzalloc(512, GFP_KERNEL);
if (!ext_csd)
return -ENOMEM;
err = mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD, ext_csd,
512);
if (err)
kfree(ext_csd);
else
*new_ext_csd = ext_csd;
return err;
}
EXPORT_SYMBOL_GPL(mmc_send_ext_csd);
EXPORT_SYMBOL_GPL(mmc_get_ext_csd);
int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
{
@ -543,6 +547,75 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
}
EXPORT_SYMBOL_GPL(mmc_switch);
int mmc_send_tuning(struct mmc_host *host)
{
struct mmc_request mrq = {NULL};
struct mmc_command cmd = {0};
struct mmc_data data = {0};
struct scatterlist sg;
struct mmc_ios *ios = &host->ios;
const u8 *tuning_block_pattern;
int size, err = 0;
u8 *data_buf;
u32 opcode;
if (ios->bus_width == MMC_BUS_WIDTH_8) {
tuning_block_pattern = tuning_blk_pattern_8bit;
size = sizeof(tuning_blk_pattern_8bit);
opcode = MMC_SEND_TUNING_BLOCK_HS200;
} else if (ios->bus_width == MMC_BUS_WIDTH_4) {
tuning_block_pattern = tuning_blk_pattern_4bit;
size = sizeof(tuning_blk_pattern_4bit);
opcode = MMC_SEND_TUNING_BLOCK;
} else
return -EINVAL;
data_buf = kzalloc(size, GFP_KERNEL);
if (!data_buf)
return -ENOMEM;
mrq.cmd = &cmd;
mrq.data = &data;
cmd.opcode = opcode;
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
data.blksz = size;
data.blocks = 1;
data.flags = MMC_DATA_READ;
/*
* According to the tuning specs, Tuning process
* is normally shorter 40 executions of CMD19,
* and timeout value should be shorter than 150 ms
*/
data.timeout_ns = 150 * NSEC_PER_MSEC;
data.sg = &sg;
data.sg_len = 1;
sg_init_one(&sg, data_buf, size);
mmc_wait_for_req(host, &mrq);
if (cmd.error) {
err = cmd.error;
goto out;
}
if (data.error) {
err = data.error;
goto out;
}
if (memcmp(data_buf, tuning_block_pattern, size))
err = -EIO;
out:
kfree(data_buf);
return err;
}
EXPORT_SYMBOL_GPL(mmc_send_tuning);
static int
mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
u8 len)
@ -675,3 +748,8 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
return 0;
}
int mmc_can_ext_csd(struct mmc_card *card)
{
return (card && card->csd.mmca_vsn > CSD_SPEC_VER_3);
}

View File

@ -20,13 +20,13 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
int mmc_all_send_cid(struct mmc_host *host, u32 *cid);
int mmc_set_relative_addr(struct mmc_card *card);
int mmc_send_csd(struct mmc_card *card, u32 *csd);
int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
int mmc_send_status(struct mmc_card *card, u32 *status);
int mmc_send_cid(struct mmc_host *host, u32 *cid);
int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
int mmc_bus_test(struct mmc_card *card, u8 bus_width);
int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status);
int mmc_can_ext_csd(struct mmc_card *card);
#endif

View File

@ -980,8 +980,12 @@ static int mmc_sdio_resume(struct mmc_host *host)
if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
sdio_reset(host);
mmc_go_idle(host);
err = mmc_sdio_init_card(host, host->card->ocr, host->card,
mmc_card_keep_power(host));
mmc_send_if_cond(host, host->card->ocr);
err = mmc_send_io_op_cond(host, 0, NULL);
if (!err)
err = mmc_sdio_init_card(host, host->card->ocr,
host->card,
mmc_card_keep_power(host));
} else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
/* We may have switched to 1-bit mode during suspend */
err = sdio_enable_4bit_bus(host->card);
@ -1035,7 +1039,7 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
sdio_reset(host);
mmc_go_idle(host);
mmc_send_if_cond(host, host->ocr_avail);
mmc_send_if_cond(host, host->card->ocr);
ret = mmc_send_io_op_cond(host, 0, NULL);
if (ret)

View File

@ -26,6 +26,8 @@
#include "sdio_cis.h"
#include "sdio_bus.h"
#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv)
/* show configuration fields */
#define sdio_config_attr(field, format_string) \
static ssize_t \
@ -196,8 +198,6 @@ static int sdio_bus_remove(struct device *dev)
return ret;
}
#ifdef CONFIG_PM
static const struct dev_pm_ops sdio_bus_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_generic_suspend, pm_generic_resume)
SET_RUNTIME_PM_OPS(
@ -207,14 +207,6 @@ static const struct dev_pm_ops sdio_bus_pm_ops = {
)
};
#define SDIO_PM_OPS_PTR (&sdio_bus_pm_ops)
#else /* !CONFIG_PM */
#define SDIO_PM_OPS_PTR NULL
#endif /* !CONFIG_PM */
static struct bus_type sdio_bus_type = {
.name = "sdio",
.dev_groups = sdio_dev_groups,
@ -222,7 +214,7 @@ static struct bus_type sdio_bus_type = {
.uevent = sdio_bus_uevent,
.probe = sdio_bus_probe,
.remove = sdio_bus_remove,
.pm = SDIO_PM_OPS_PTR,
.pm = &sdio_bus_pm_ops,
};
int sdio_register_bus(void)
@ -295,7 +287,7 @@ struct sdio_func *sdio_alloc_func(struct mmc_card *card)
static void sdio_acpi_set_handle(struct sdio_func *func)
{
struct mmc_host *host = func->card->host;
u64 addr = (host->slotno << 16) | func->num;
u64 addr = ((u64)host->slotno << 16) | func->num;
acpi_preset_companion(&func->dev, ACPI_COMPANION(host->parent), addr);
}

View File

@ -580,7 +580,7 @@ config SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND
config MMC_DW
tristate "Synopsys DesignWare Memory Card Interface"
depends on HAS_DMA
depends on ARC || ARM || MIPS || COMPILE_TEST
depends on ARC || ARM || ARM64 || MIPS || COMPILE_TEST
help
This selects support for the Synopsys DesignWare Mobile Storage IP
block, this provides host support for SD and MMC interfaces, in both
@ -748,3 +748,8 @@ config MMC_SUNXI
help
This selects support for the SD/MMC Host Controller on
Allwinner sunxi SoCs.
config MMC_TOSHIBA_PCI
tristate "Toshiba Type A SD/MMC Card Interface Driver"
depends on PCI
help

View File

@ -55,6 +55,7 @@ obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o
obj-$(CONFIG_MMC_MOXART) += moxart-mmc.o
obj-$(CONFIG_MMC_SUNXI) += sunxi-mmc.o
obj-$(CONFIG_MMC_USDHI6ROL0) += usdhi6rol0.o
obj-$(CONFIG_MMC_TOSHIBA_PCI) += toshsd.o
obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o
obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o

View File

@ -30,13 +30,16 @@
#include <linux/stat.h>
#include <linux/types.h>
#include <linux/platform_data/atmel.h>
#include <linux/platform_data/mmc-atmel-mci.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdio.h>
#include <mach/atmel-mci.h>
#include <linux/atmel-mci.h>
#include <linux/atmel_pdc.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/pinctrl/consumer.h>
#include <asm/cacheflush.h>
#include <asm/io.h>
@ -44,6 +47,8 @@
#include "atmel-mci-regs.h"
#define AUTOSUSPEND_DELAY 50
#define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE)
#define ATMCI_DMA_THRESHOLD 16
@ -386,20 +391,19 @@ static int atmci_regs_show(struct seq_file *s, void *v)
if (!buf)
return -ENOMEM;
pm_runtime_get_sync(&host->pdev->dev);
/*
* Grab a more or less consistent snapshot. Note that we're
* not disabling interrupts, so IMR and SR may not be
* consistent.
*/
ret = clk_prepare_enable(host->mck);
if (ret)
goto out;
spin_lock_bh(&host->lock);
memcpy_fromio(buf, host->regs, ATMCI_REGS_SIZE);
spin_unlock_bh(&host->lock);
clk_disable_unprepare(host->mck);
pm_runtime_mark_last_busy(&host->pdev->dev);
pm_runtime_put_autosuspend(&host->pdev->dev);
seq_printf(s, "MR:\t0x%08x%s%s ",
buf[ATMCI_MR / 4],
@ -449,7 +453,6 @@ static int atmci_regs_show(struct seq_file *s, void *v)
val & ATMCI_CFG_LSYNC ? " LSYNC" : "");
}
out:
kfree(buf);
return ret;
@ -560,6 +563,9 @@ atmci_of_init(struct platform_device *pdev)
pdata->slot[slot_id].detect_is_active_high =
of_property_read_bool(cnp, "cd-inverted");
pdata->slot[slot_id].non_removable =
of_property_read_bool(cnp, "non-removable");
pdata->slot[slot_id].wp_pin =
of_get_named_gpio(cnp, "wp-gpios", 0);
}
@ -1252,6 +1258,8 @@ static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
WARN_ON(slot->mrq);
dev_dbg(&host->pdev->dev, "MRQ: cmd %u\n", mrq->cmd->opcode);
pm_runtime_get_sync(&host->pdev->dev);
/*
* We may "know" the card is gone even though there's still an
* electrical connection. If so, we really need to communicate
@ -1281,7 +1289,8 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
struct atmel_mci_slot *slot = mmc_priv(mmc);
struct atmel_mci *host = slot->host;
unsigned int i;
bool unprepare_clk;
pm_runtime_get_sync(&host->pdev->dev);
slot->sdc_reg &= ~ATMCI_SDCBUS_MASK;
switch (ios->bus_width) {
@ -1297,13 +1306,8 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
unsigned int clock_min = ~0U;
u32 clkdiv;
clk_prepare(host->mck);
unprepare_clk = true;
spin_lock_bh(&host->lock);
if (!host->mode_reg) {
clk_enable(host->mck);
unprepare_clk = false;
atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);
atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN);
if (host->caps.has_cfg_reg)
@ -1371,8 +1375,6 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
} else {
bool any_slot_active = false;
unprepare_clk = false;
spin_lock_bh(&host->lock);
slot->clock = 0;
for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
@ -1385,17 +1387,12 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS);
if (host->mode_reg) {
atmci_readl(host, ATMCI_MR);
clk_disable(host->mck);
unprepare_clk = true;
}
host->mode_reg = 0;
}
spin_unlock_bh(&host->lock);
}
if (unprepare_clk)
clk_unprepare(host->mck);
switch (ios->power_mode) {
case MMC_POWER_OFF:
if (!IS_ERR(mmc->supply.vmmc))
@ -1421,6 +1418,9 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
*/
break;
}
pm_runtime_mark_last_busy(&host->pdev->dev);
pm_runtime_put_autosuspend(&host->pdev->dev);
}
static int atmci_get_ro(struct mmc_host *mmc)
@ -1512,6 +1512,9 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq)
spin_unlock(&host->lock);
mmc_request_done(prev_mmc, mrq);
spin_lock(&host->lock);
pm_runtime_mark_last_busy(&host->pdev->dev);
pm_runtime_put_autosuspend(&host->pdev->dev);
}
static void atmci_command_complete(struct atmel_mci *host,
@ -2137,7 +2140,7 @@ static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
static int __init atmci_init_slot(struct atmel_mci *host,
static int atmci_init_slot(struct atmel_mci *host,
struct mci_slot_pdata *slot_data, unsigned int id,
u32 sdc_reg, u32 sdio_irq)
{
@ -2206,8 +2209,12 @@ static int __init atmci_init_slot(struct atmel_mci *host,
}
}
if (!gpio_is_valid(slot->detect_pin))
mmc->caps |= MMC_CAP_NEEDS_POLL;
if (!gpio_is_valid(slot->detect_pin)) {
if (slot_data->non_removable)
mmc->caps |= MMC_CAP_NONREMOVABLE;
else
mmc->caps |= MMC_CAP_NEEDS_POLL;
}
if (gpio_is_valid(slot->wp_pin)) {
if (devm_gpio_request(&host->pdev->dev, slot->wp_pin,
@ -2265,55 +2272,25 @@ static void atmci_cleanup_slot(struct atmel_mci_slot *slot,
mmc_free_host(slot->mmc);
}
static bool atmci_filter(struct dma_chan *chan, void *pdata)
static int atmci_configure_dma(struct atmel_mci *host)
{
struct mci_platform_data *sl_pdata = pdata;
struct mci_dma_data *sl;
host->dma.chan = dma_request_slave_channel_reason(&host->pdev->dev,
"rxtx");
if (IS_ERR(host->dma.chan))
return PTR_ERR(host->dma.chan);
if (!sl_pdata)
return false;
dev_info(&host->pdev->dev, "using %s for DMA transfers\n",
dma_chan_name(host->dma.chan));
sl = sl_pdata->dma_slave;
if (sl && find_slave_dev(sl) == chan->device->dev) {
chan->private = slave_data_ptr(sl);
return true;
} else {
return false;
}
}
host->dma_conf.src_addr = host->mapbase + ATMCI_RDR;
host->dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
host->dma_conf.src_maxburst = 1;
host->dma_conf.dst_addr = host->mapbase + ATMCI_TDR;
host->dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
host->dma_conf.dst_maxburst = 1;
host->dma_conf.device_fc = false;
static bool atmci_configure_dma(struct atmel_mci *host)
{
struct mci_platform_data *pdata;
dma_cap_mask_t mask;
if (host == NULL)
return false;
pdata = host->pdev->dev.platform_data;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
host->dma.chan = dma_request_slave_channel_compat(mask, atmci_filter, pdata,
&host->pdev->dev, "rxtx");
if (!host->dma.chan) {
dev_warn(&host->pdev->dev, "no DMA channel available\n");
return false;
} else {
dev_info(&host->pdev->dev,
"using %s for DMA transfers\n",
dma_chan_name(host->dma.chan));
host->dma_conf.src_addr = host->mapbase + ATMCI_RDR;
host->dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
host->dma_conf.src_maxburst = 1;
host->dma_conf.dst_addr = host->mapbase + ATMCI_TDR;
host->dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
host->dma_conf.dst_maxburst = 1;
host->dma_conf.device_fc = false;
return true;
}
return 0;
}
/*
@ -2321,7 +2298,7 @@ static bool atmci_configure_dma(struct atmel_mci *host)
* HSMCI provides DMA support and a new config register but no more supports
* PDC.
*/
static void __init atmci_get_cap(struct atmel_mci *host)
static void atmci_get_cap(struct atmel_mci *host)
{
unsigned int version;
@ -2370,7 +2347,7 @@ static void __init atmci_get_cap(struct atmel_mci *host)
}
}
static int __init atmci_probe(struct platform_device *pdev)
static int atmci_probe(struct platform_device *pdev)
{
struct mci_platform_data *pdata;
struct atmel_mci *host;
@ -2417,19 +2394,23 @@ static int __init atmci_probe(struct platform_device *pdev)
atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);
host->bus_hz = clk_get_rate(host->mck);
clk_disable_unprepare(host->mck);
host->mapbase = regs->start;
tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host);
ret = request_irq(irq, atmci_interrupt, 0, dev_name(&pdev->dev), host);
if (ret)
if (ret) {
clk_disable_unprepare(host->mck);
return ret;
}
/* Get MCI capabilities and set operations according to it */
atmci_get_cap(host);
if (atmci_configure_dma(host)) {
ret = atmci_configure_dma(host);
if (ret == -EPROBE_DEFER)
goto err_dma_probe_defer;
if (ret == 0) {
host->prepare_data = &atmci_prepare_data_dma;
host->submit_data = &atmci_submit_data_dma;
host->stop_transfer = &atmci_stop_transfer_dma;
@ -2449,6 +2430,12 @@ static int __init atmci_probe(struct platform_device *pdev)
setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host);
pm_runtime_get_noresume(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_DELAY);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_enable(&pdev->dev);
/* We need at least one slot to succeed */
nr_slots = 0;
ret = -ENODEV;
@ -2491,6 +2478,9 @@ static int __init atmci_probe(struct platform_device *pdev)
"Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
host->mapbase, irq, nr_slots);
pm_runtime_mark_last_busy(&host->pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
return 0;
err_dma_alloc:
@ -2499,18 +2489,26 @@ err_dma_alloc:
atmci_cleanup_slot(host->slot[i], i);
}
err_init_slot:
clk_disable_unprepare(host->mck);
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
del_timer_sync(&host->timer);
if (host->dma.chan)
if (!IS_ERR(host->dma.chan))
dma_release_channel(host->dma.chan);
err_dma_probe_defer:
free_irq(irq, host);
return ret;
}
static int __exit atmci_remove(struct platform_device *pdev)
static int atmci_remove(struct platform_device *pdev)
{
struct atmel_mci *host = platform_get_drvdata(pdev);
unsigned int i;
pm_runtime_get_sync(&pdev->dev);
if (host->buffer)
dma_free_coherent(&pdev->dev, host->buf_size,
host->buffer, host->buf_phys_addr);
@ -2520,41 +2518,62 @@ static int __exit atmci_remove(struct platform_device *pdev)
atmci_cleanup_slot(host->slot[i], i);
}
clk_prepare_enable(host->mck);
atmci_writel(host, ATMCI_IDR, ~0UL);
atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS);
atmci_readl(host, ATMCI_SR);
clk_disable_unprepare(host->mck);
del_timer_sync(&host->timer);
if (host->dma.chan)
if (!IS_ERR(host->dma.chan))
dma_release_channel(host->dma.chan);
free_irq(platform_get_irq(pdev, 0), host);
clk_disable_unprepare(host->mck);
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
return 0;
}
#ifdef CONFIG_PM
static int atmci_runtime_suspend(struct device *dev)
{
struct atmel_mci *host = dev_get_drvdata(dev);
clk_disable_unprepare(host->mck);
pinctrl_pm_select_sleep_state(dev);
return 0;
}
static int atmci_runtime_resume(struct device *dev)
{
struct atmel_mci *host = dev_get_drvdata(dev);
pinctrl_pm_select_default_state(dev);
return clk_prepare_enable(host->mck);
}
#endif
static const struct dev_pm_ops atmci_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
SET_PM_RUNTIME_PM_OPS(atmci_runtime_suspend, atmci_runtime_resume, NULL)
};
static struct platform_driver atmci_driver = {
.remove = __exit_p(atmci_remove),
.probe = atmci_probe,
.remove = atmci_remove,
.driver = {
.name = "atmel_mci",
.of_match_table = of_match_ptr(atmci_dt_ids),
.pm = &atmci_dev_pm_ops,
},
};
static int __init atmci_init(void)
{
return platform_driver_probe(&atmci_driver, atmci_probe);
}
static void __exit atmci_exit(void)
{
platform_driver_unregister(&atmci_driver);
}
late_initcall(atmci_init); /* try to load after dma driver when built-in */
module_exit(atmci_exit);
module_platform_driver(atmci_driver);
MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver");
MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");

View File

@ -25,6 +25,7 @@
#define NUM_PINS(x) (x + 2)
#define SDMMC_CLKSEL 0x09C
#define SDMMC_CLKSEL64 0x0A8
#define SDMMC_CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0)
#define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16)
#define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24)
@ -65,6 +66,8 @@ enum dw_mci_exynos_type {
DW_MCI_TYPE_EXYNOS5250,
DW_MCI_TYPE_EXYNOS5420,
DW_MCI_TYPE_EXYNOS5420_SMU,
DW_MCI_TYPE_EXYNOS7,
DW_MCI_TYPE_EXYNOS7_SMU,
};
/* Exynos implementation specific driver private data */
@ -95,6 +98,12 @@ static struct dw_mci_exynos_compatible {
}, {
.compatible = "samsung,exynos5420-dw-mshc-smu",
.ctrl_type = DW_MCI_TYPE_EXYNOS5420_SMU,
}, {
.compatible = "samsung,exynos7-dw-mshc",
.ctrl_type = DW_MCI_TYPE_EXYNOS7,
}, {
.compatible = "samsung,exynos7-dw-mshc-smu",
.ctrl_type = DW_MCI_TYPE_EXYNOS7_SMU,
},
};
@ -102,7 +111,8 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
{
struct dw_mci_exynos_priv_data *priv = host->priv;
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU) {
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) {
mci_writel(host, MPSBEGIN0, 0);
mci_writel(host, MPSEND0, DWMCI_BLOCK_NUM);
mci_writel(host, MPSCTRL0, DWMCI_MPSCTRL_SECURE_WRITE_BIT |
@ -153,11 +163,22 @@ static int dw_mci_exynos_resume(struct device *dev)
static int dw_mci_exynos_resume_noirq(struct device *dev)
{
struct dw_mci *host = dev_get_drvdata(dev);
struct dw_mci_exynos_priv_data *priv = host->priv;
u32 clksel;
clksel = mci_readl(host, CLKSEL);
if (clksel & SDMMC_CLKSEL_WAKEUP_INT)
mci_writel(host, CLKSEL, clksel);
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
clksel = mci_readl(host, CLKSEL64);
else
clksel = mci_readl(host, CLKSEL);
if (clksel & SDMMC_CLKSEL_WAKEUP_INT) {
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
mci_writel(host, CLKSEL64, clksel);
else
mci_writel(host, CLKSEL, clksel);
}
return 0;
}
@ -169,6 +190,7 @@ static int dw_mci_exynos_resume_noirq(struct device *dev)
static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr)
{
struct dw_mci_exynos_priv_data *priv = host->priv;
/*
* Exynos4412 and Exynos5250 extends the use of CMD register with the
* use of bit 29 (which is reserved on standard MSHC controllers) for
@ -176,8 +198,14 @@ static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr)
* HOLD register should be bypassed in case there is no phase shift
* applied on CMD/DATA that is sent to the card.
*/
if (SDMMC_CLKSEL_GET_DRV_WD3(mci_readl(host, CLKSEL)))
*cmdr |= SDMMC_CMD_USE_HOLD_REG;
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) {
if (SDMMC_CLKSEL_GET_DRV_WD3(mci_readl(host, CLKSEL64)))
*cmdr |= SDMMC_CMD_USE_HOLD_REG;
} else {
if (SDMMC_CLKSEL_GET_DRV_WD3(mci_readl(host, CLKSEL)))
*cmdr |= SDMMC_CMD_USE_HOLD_REG;
}
}
static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
@ -188,12 +216,20 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
u8 div = priv->ciu_div + 1;
if (ios->timing == MMC_TIMING_MMC_DDR52) {
mci_writel(host, CLKSEL, priv->ddr_timing);
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
mci_writel(host, CLKSEL64, priv->ddr_timing);
else
mci_writel(host, CLKSEL, priv->ddr_timing);
/* Should be double rate for DDR mode */
if (ios->bus_width == MMC_BUS_WIDTH_8)
wanted <<= 1;
} else {
mci_writel(host, CLKSEL, priv->sdr_timing);
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
mci_writel(host, CLKSEL64, priv->sdr_timing);
else
mci_writel(host, CLKSEL, priv->sdr_timing);
}
/* Don't care if wanted clock is zero */
@ -265,26 +301,51 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
static inline u8 dw_mci_exynos_get_clksmpl(struct dw_mci *host)
{
return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL));
struct dw_mci_exynos_priv_data *priv = host->priv;
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL64));
else
return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL));
}
static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)
{
u32 clksel;
clksel = mci_readl(host, CLKSEL);
struct dw_mci_exynos_priv_data *priv = host->priv;
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
clksel = mci_readl(host, CLKSEL64);
else
clksel = mci_readl(host, CLKSEL);
clksel = (clksel & ~0x7) | SDMMC_CLKSEL_CCLK_SAMPLE(sample);
mci_writel(host, CLKSEL, clksel);
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
mci_writel(host, CLKSEL64, clksel);
else
mci_writel(host, CLKSEL, clksel);
}
static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
{
struct dw_mci_exynos_priv_data *priv = host->priv;
u32 clksel;
u8 sample;
clksel = mci_readl(host, CLKSEL);
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
clksel = mci_readl(host, CLKSEL64);
else
clksel = mci_readl(host, CLKSEL);
sample = (clksel + 1) & 0x7;
clksel = (clksel & ~0x7) | sample;
mci_writel(host, CLKSEL, clksel);
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
mci_writel(host, CLKSEL64, clksel);
else
mci_writel(host, CLKSEL, clksel);
return sample;
}
@ -411,6 +472,10 @@ static const struct of_device_id dw_mci_exynos_match[] = {
.data = &exynos_drv_data, },
{ .compatible = "samsung,exynos5420-dw-mshc-smu",
.data = &exynos_drv_data, },
{ .compatible = "samsung,exynos7-dw-mshc",
.data = &exynos_drv_data, },
{ .compatible = "samsung,exynos7-dw-mshc-smu",
.data = &exynos_drv_data, },
{},
};
MODULE_DEVICE_TABLE(of, dw_mci_exynos_match);

View File

@ -35,6 +35,10 @@ static const struct dw_mci_drv_data socfpga_drv_data = {
.prepare_command = dw_mci_pltfm_prepare_command,
};
static const struct dw_mci_drv_data pistachio_drv_data = {
.prepare_command = dw_mci_pltfm_prepare_command,
};
int dw_mci_pltfm_register(struct platform_device *pdev,
const struct dw_mci_drv_data *drv_data)
{
@ -90,6 +94,8 @@ static const struct of_device_id dw_mci_pltfm_match[] = {
{ .compatible = "snps,dw-mshc", },
{ .compatible = "altr,socfpga-dw-mshc",
.data = &socfpga_drv_data },
{ .compatible = "img,pistachio-dw-mshc",
.data = &pistachio_drv_data },
{},
};
MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);

View File

@ -37,6 +37,9 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
unsigned int cclkin;
u32 bus_hz;
if (ios->clock == 0)
return;
/*
* cclkin: source clock of mmc controller
* bus_hz: card interface clock generated by CLKGEN
@ -65,14 +68,24 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
}
}
static int dw_mci_rockchip_init(struct dw_mci *host)
{
/* It is slot 8 on Rockchip SoCs */
host->sdio_id0 = 8;
return 0;
}
static const struct dw_mci_drv_data rk2928_drv_data = {
.prepare_command = dw_mci_rockchip_prepare_command,
.init = dw_mci_rockchip_init,
};
static const struct dw_mci_drv_data rk3288_drv_data = {
.prepare_command = dw_mci_rockchip_prepare_command,
.set_ios = dw_mci_rk3288_set_ios,
.setup_clock = dw_mci_rk3288_setup_clock,
.init = dw_mci_rockchip_init,
};
static const struct of_device_id dw_mci_rockchip_match[] = {

View File

@ -34,7 +34,6 @@
#include <linux/mmc/dw_mmc.h>
#include <linux/bitops.h>
#include <linux/regulator/consumer.h>
#include <linux/workqueue.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/mmc/slot-gpio.h>
@ -62,6 +61,24 @@
SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \
SDMMC_IDMAC_INT_TI)
struct idmac_desc_64addr {
u32 des0; /* Control Descriptor */
u32 des1; /* Reserved */
u32 des2; /*Buffer sizes */
#define IDMAC_64ADDR_SET_BUFFER1_SIZE(d, s) \
((d)->des2 = ((d)->des2 & 0x03ffe000) | ((s) & 0x1fff))
u32 des3; /* Reserved */
u32 des4; /* Lower 32-bits of Buffer Address Pointer 1*/
u32 des5; /* Upper 32-bits of Buffer Address Pointer 1*/
u32 des6; /* Lower 32-bits of Next Descriptor Address */
u32 des7; /* Upper 32-bits of Next Descriptor Address */
};
struct idmac_desc {
u32 des0; /* Control Descriptor */
#define IDMAC_DES0_DIC BIT(1)
@ -83,6 +100,7 @@ struct idmac_desc {
#endif /* CONFIG_MMC_DW_IDMAC */
static bool dw_mci_reset(struct dw_mci *host);
static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);
#if defined(CONFIG_DEBUG_FS)
static int dw_mci_req_show(struct seq_file *s, void *v)
@ -414,31 +432,67 @@ static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
unsigned int sg_len)
{
int i;
struct idmac_desc *desc = host->sg_cpu;
if (host->dma_64bit_address == 1) {
struct idmac_desc_64addr *desc = host->sg_cpu;
for (i = 0; i < sg_len; i++, desc++) {
unsigned int length = sg_dma_len(&data->sg[i]);
u32 mem_addr = sg_dma_address(&data->sg[i]);
for (i = 0; i < sg_len; i++, desc++) {
unsigned int length = sg_dma_len(&data->sg[i]);
u64 mem_addr = sg_dma_address(&data->sg[i]);
/* Set the OWN bit and disable interrupts for this descriptor */
desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH;
/*
* Set the OWN bit and disable interrupts for this
* descriptor
*/
desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC |
IDMAC_DES0_CH;
/* Buffer length */
IDMAC_64ADDR_SET_BUFFER1_SIZE(desc, length);
/* Buffer length */
IDMAC_SET_BUFFER1_SIZE(desc, length);
/* Physical address to DMA to/from */
desc->des4 = mem_addr & 0xffffffff;
desc->des5 = mem_addr >> 32;
}
/* Physical address to DMA to/from */
desc->des2 = mem_addr;
/* Set first descriptor */
desc = host->sg_cpu;
desc->des0 |= IDMAC_DES0_FD;
/* Set last descriptor */
desc = host->sg_cpu + (i - 1) *
sizeof(struct idmac_desc_64addr);
desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
desc->des0 |= IDMAC_DES0_LD;
} else {
struct idmac_desc *desc = host->sg_cpu;
for (i = 0; i < sg_len; i++, desc++) {
unsigned int length = sg_dma_len(&data->sg[i]);
u32 mem_addr = sg_dma_address(&data->sg[i]);
/*
* Set the OWN bit and disable interrupts for this
* descriptor
*/
desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC |
IDMAC_DES0_CH;
/* Buffer length */
IDMAC_SET_BUFFER1_SIZE(desc, length);
/* Physical address to DMA to/from */
desc->des2 = mem_addr;
}
/* Set first descriptor */
desc = host->sg_cpu;
desc->des0 |= IDMAC_DES0_FD;
/* Set last descriptor */
desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
desc->des0 |= IDMAC_DES0_LD;
}
/* Set first descriptor */
desc = host->sg_cpu;
desc->des0 |= IDMAC_DES0_FD;
/* Set last descriptor */
desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
desc->des0 |= IDMAC_DES0_LD;
wmb();
}
@ -448,6 +502,10 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
dw_mci_translate_sglist(host, host->data, sg_len);
/* Make sure to reset DMA in case we did PIO before this */
dw_mci_ctrl_reset(host, SDMMC_CTRL_DMA_RESET);
dw_mci_idmac_reset(host);
/* Select IDMAC interface */
temp = mci_readl(host, CTRL);
temp |= SDMMC_CTRL_USE_IDMAC;
@ -466,29 +524,71 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
static int dw_mci_idmac_init(struct dw_mci *host)
{
struct idmac_desc *p;
int i;
/* Number of descriptors in the ring buffer */
host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
if (host->dma_64bit_address == 1) {
struct idmac_desc_64addr *p;
/* Number of descriptors in the ring buffer */
host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc_64addr);
/* Forward link the descriptor list */
for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1));
/* Forward link the descriptor list */
for (i = 0, p = host->sg_cpu; i < host->ring_size - 1;
i++, p++) {
p->des6 = (host->sg_dma +
(sizeof(struct idmac_desc_64addr) *
(i + 1))) & 0xffffffff;
/* Set the last descriptor as the end-of-ring descriptor */
p->des3 = host->sg_dma;
p->des0 = IDMAC_DES0_ER;
p->des7 = (u64)(host->sg_dma +
(sizeof(struct idmac_desc_64addr) *
(i + 1))) >> 32;
/* Initialize reserved and buffer size fields to "0" */
p->des1 = 0;
p->des2 = 0;
p->des3 = 0;
}
/* Set the last descriptor as the end-of-ring descriptor */
p->des6 = host->sg_dma & 0xffffffff;
p->des7 = (u64)host->sg_dma >> 32;
p->des0 = IDMAC_DES0_ER;
} else {
struct idmac_desc *p;
/* Number of descriptors in the ring buffer */
host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
/* Forward link the descriptor list */
for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
p->des3 = host->sg_dma + (sizeof(struct idmac_desc) *
(i + 1));
/* Set the last descriptor as the end-of-ring descriptor */
p->des3 = host->sg_dma;
p->des0 = IDMAC_DES0_ER;
}
dw_mci_idmac_reset(host);
/* Mask out interrupts - get Tx & Rx complete only */
mci_writel(host, IDSTS, IDMAC_INT_CLR);
mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI |
SDMMC_IDMAC_INT_TI);
if (host->dma_64bit_address == 1) {
/* Mask out interrupts - get Tx & Rx complete only */
mci_writel(host, IDSTS64, IDMAC_INT_CLR);
mci_writel(host, IDINTEN64, SDMMC_IDMAC_INT_NI |
SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI);
/* Set the descriptor base address */
mci_writel(host, DBADDRL, host->sg_dma & 0xffffffff);
mci_writel(host, DBADDRU, (u64)host->sg_dma >> 32);
} else {
/* Mask out interrupts - get Tx & Rx complete only */
mci_writel(host, IDSTS, IDMAC_INT_CLR);
mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI |
SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI);
/* Set the descriptor base address */
mci_writel(host, DBADDR, host->sg_dma);
}
/* Set the descriptor base address */
mci_writel(host, DBADDR, host->sg_dma);
return 0;
}
@ -626,6 +726,13 @@ static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data)
WARN_ON(!(data->flags & MMC_DATA_READ));
/*
* CDTHRCTL doesn't exist prior to 240A (in fact that register offset is
* in the FIFO region, so we really shouldn't access it).
*/
if (host->verid < DW_MMC_240A)
return;
if (host->timing != MMC_TIMING_MMC_HS200 &&
host->timing != MMC_TIMING_UHS_SDR104)
goto disable;
@ -819,7 +926,7 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
/* enable clock; only low power if no SDIO */
clk_en_a = SDMMC_CLKEN_ENABLE << slot->id;
if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->id)))
if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->sdio_id)))
clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id;
mci_writel(host, CLKENA, clk_en_a);
@ -1075,7 +1182,7 @@ static int dw_mci_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
ret = regulator_set_voltage(mmc->supply.vqmmc, min_uv, max_uv);
if (ret) {
dev_err(&mmc->class_dev,
dev_dbg(&mmc->class_dev,
"Regulator set error %d: %d - %d\n",
ret, min_uv, max_uv);
return ret;
@ -1180,10 +1287,10 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
dw_mci_disable_low_power(slot);
mci_writel(host, INTMASK,
(int_mask | SDMMC_INT_SDIO(slot->id)));
(int_mask | SDMMC_INT_SDIO(slot->sdio_id)));
} else {
mci_writel(host, INTMASK,
(int_mask & ~SDMMC_INT_SDIO(slot->id)));
(int_mask & ~SDMMC_INT_SDIO(slot->sdio_id)));
}
}
@ -1954,6 +2061,23 @@ static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status)
tasklet_schedule(&host->tasklet);
}
static void dw_mci_handle_cd(struct dw_mci *host)
{
int i;
for (i = 0; i < host->num_slots; i++) {
struct dw_mci_slot *slot = host->slot[i];
if (!slot)
continue;
if (slot->mmc->ops->card_event)
slot->mmc->ops->card_event(slot->mmc);
mmc_detect_change(slot->mmc,
msecs_to_jiffies(host->pdata->detect_delay_ms));
}
}
static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
{
struct dw_mci *host = dev_id;
@ -2029,14 +2153,15 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
if (pending & SDMMC_INT_CD) {
mci_writel(host, RINTSTS, SDMMC_INT_CD);
queue_work(host->card_workqueue, &host->card_work);
dw_mci_handle_cd(host);
}
/* Handle SDIO Interrupts */
for (i = 0; i < host->num_slots; i++) {
struct dw_mci_slot *slot = host->slot[i];
if (pending & SDMMC_INT_SDIO(i)) {
mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i));
if (pending & SDMMC_INT_SDIO(slot->sdio_id)) {
mci_writel(host, RINTSTS,
SDMMC_INT_SDIO(slot->sdio_id));
mmc_signal_sdio_irq(slot->mmc);
}
}
@ -2045,99 +2170,28 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
#ifdef CONFIG_MMC_DW_IDMAC
/* Handle DMA interrupts */
pending = mci_readl(host, IDSTS);
if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI);
mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
host->dma_ops->complete(host);
if (host->dma_64bit_address == 1) {
pending = mci_readl(host, IDSTS64);
if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_TI |
SDMMC_IDMAC_INT_RI);
mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_NI);
host->dma_ops->complete(host);
}
} else {
pending = mci_readl(host, IDSTS);
if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI |
SDMMC_IDMAC_INT_RI);
mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
host->dma_ops->complete(host);
}
}
#endif
return IRQ_HANDLED;
}
static void dw_mci_work_routine_card(struct work_struct *work)
{
struct dw_mci *host = container_of(work, struct dw_mci, card_work);
int i;
for (i = 0; i < host->num_slots; i++) {
struct dw_mci_slot *slot = host->slot[i];
struct mmc_host *mmc = slot->mmc;
struct mmc_request *mrq;
int present;
present = dw_mci_get_cd(mmc);
while (present != slot->last_detect_state) {
dev_dbg(&slot->mmc->class_dev, "card %s\n",
present ? "inserted" : "removed");
spin_lock_bh(&host->lock);
/* Card change detected */
slot->last_detect_state = present;
/* Clean up queue if present */
mrq = slot->mrq;
if (mrq) {
if (mrq == host->mrq) {
host->data = NULL;
host->cmd = NULL;
switch (host->state) {
case STATE_IDLE:
case STATE_WAITING_CMD11_DONE:
break;
case STATE_SENDING_CMD11:
case STATE_SENDING_CMD:
mrq->cmd->error = -ENOMEDIUM;
if (!mrq->data)
break;
/* fall through */
case STATE_SENDING_DATA:
mrq->data->error = -ENOMEDIUM;
dw_mci_stop_dma(host);
break;
case STATE_DATA_BUSY:
case STATE_DATA_ERROR:
if (mrq->data->error == -EINPROGRESS)
mrq->data->error = -ENOMEDIUM;
/* fall through */
case STATE_SENDING_STOP:
if (mrq->stop)
mrq->stop->error = -ENOMEDIUM;
break;
}
dw_mci_request_end(host, mrq);
} else {
list_del(&slot->queue_node);
mrq->cmd->error = -ENOMEDIUM;
if (mrq->data)
mrq->data->error = -ENOMEDIUM;
if (mrq->stop)
mrq->stop->error = -ENOMEDIUM;
spin_unlock(&host->lock);
mmc_request_done(slot->mmc, mrq);
spin_lock(&host->lock);
}
}
/* Power down slot */
if (present == 0)
dw_mci_reset(host);
spin_unlock_bh(&host->lock);
present = dw_mci_get_cd(mmc);
}
mmc_detect_change(slot->mmc,
msecs_to_jiffies(host->pdata->detect_delay_ms));
}
}
#ifdef CONFIG_OF
/* given a slot id, find out the device node representing that slot */
static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
@ -2206,6 +2260,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
slot = mmc_priv(mmc);
slot->id = id;
slot->sdio_id = host->sdio_id0 + id;
slot->mmc = mmc;
slot->host = host;
host->slot[id] = slot;
@ -2289,9 +2344,6 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
dw_mci_init_debugfs(slot);
#endif
/* Card initially undetected */
slot->last_detect_state = 0;
return 0;
err_host_allocated:
@ -2309,6 +2361,22 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
static void dw_mci_init_dma(struct dw_mci *host)
{
int addr_config;
/* Check ADDR_CONFIG bit in HCON to find IDMAC address bus width */
addr_config = (mci_readl(host, HCON) >> 27) & 0x01;
if (addr_config == 1) {
/* host supports IDMAC in 64-bit address mode */
host->dma_64bit_address = 1;
dev_info(host->dev, "IDMAC supports 64-bit address mode.\n");
if (!dma_set_mask(host->dev, DMA_BIT_MASK(64)))
dma_set_coherent_mask(host->dev, DMA_BIT_MASK(64));
} else {
/* host supports IDMAC in 32-bit address mode */
host->dma_64bit_address = 0;
dev_info(host->dev, "IDMAC supports 32-bit address mode.\n");
}
/* Alloc memory for sg translation */
host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,
&host->sg_dma, GFP_KERNEL);
@ -2672,17 +2740,10 @@ int dw_mci_probe(struct dw_mci *host)
host->data_offset = DATA_240A_OFFSET;
tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);
host->card_workqueue = alloc_workqueue("dw-mci-card",
WQ_MEM_RECLAIM, 1);
if (!host->card_workqueue) {
ret = -ENOMEM;
goto err_dmaunmap;
}
INIT_WORK(&host->card_work, dw_mci_work_routine_card);
ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt,
host->irq_flags, "dw-mci", host);
if (ret)
goto err_workqueue;
goto err_dmaunmap;
if (host->pdata->num_slots)
host->num_slots = host->pdata->num_slots;
@ -2718,7 +2779,7 @@ int dw_mci_probe(struct dw_mci *host)
} else {
dev_dbg(host->dev, "attempted to initialize %d slots, "
"but failed on all\n", host->num_slots);
goto err_workqueue;
goto err_dmaunmap;
}
if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
@ -2726,9 +2787,6 @@ int dw_mci_probe(struct dw_mci *host)
return 0;
err_workqueue:
destroy_workqueue(host->card_workqueue);
err_dmaunmap:
if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host);
@ -2762,8 +2820,6 @@ void dw_mci_remove(struct dw_mci *host)
mci_writel(host, CLKENA, 0);
mci_writel(host, CLKSRC, 0);
destroy_workqueue(host->card_workqueue);
if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host);

View File

@ -55,6 +55,17 @@
#define SDMMC_BUFADDR 0x098
#define SDMMC_CDTHRCTL 0x100
#define SDMMC_DATA(x) (x)
/*
* Registers to support idmac 64-bit address mode
*/
#define SDMMC_DBADDRL 0x088
#define SDMMC_DBADDRU 0x08c
#define SDMMC_IDSTS64 0x090
#define SDMMC_IDINTEN64 0x094
#define SDMMC_DSCADDRL 0x098
#define SDMMC_DSCADDRU 0x09c
#define SDMMC_BUFADDRL 0x0A0
#define SDMMC_BUFADDRU 0x0A4
/*
* Data offset is difference according to Version
@ -214,7 +225,7 @@ extern int dw_mci_resume(struct dw_mci *host);
* with CONFIG_MMC_CLKGATE.
* @flags: Random state bits associated with the slot.
* @id: Number of this slot.
* @last_detect_state: Most recently observed card detect state.
* @sdio_id: Number of this slot in the SDIO interrupt registers.
*/
struct dw_mci_slot {
struct mmc_host *mmc;
@ -234,7 +245,7 @@ struct dw_mci_slot {
#define DW_MMC_CARD_PRESENT 0
#define DW_MMC_CARD_NEED_INIT 1
int id;
int last_detect_state;
int sdio_id;
};
struct dw_mci_tuning_data {

View File

@ -736,8 +736,15 @@ static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq,
chan = host->dma_tx_channel;
dmaengine_terminate_all(chan);
if (host->dma_desc_current == next->dma_desc)
host->dma_desc_current = NULL;
if (host->dma_current == next->dma_chan)
host->dma_current = NULL;
next->dma_desc = NULL;
next->dma_chan = NULL;
data->host_cookie = 0;
}
}

View File

@ -1360,7 +1360,7 @@ msmsdcc_probe(struct platform_device *pdev)
if (ret)
goto cmd_irq_free;
mmc_set_drvdata(pdev, mmc);
platform_set_drvdata(pdev, mmc);
mmc_add_host(mmc);
pr_info("%s: Qualcomm MSM SDCC at 0x%016llx irq %d,%d dma %d\n",
@ -1419,7 +1419,7 @@ ioremap_free:
static int
msmsdcc_suspend(struct platform_device *dev, pm_message_t state)
{
struct mmc_host *mmc = mmc_get_drvdata(dev);
struct mmc_host *mmc = platform_get_drvdata(dev);
if (mmc) {
struct msmsdcc_host *host = mmc_priv(mmc);
@ -1437,7 +1437,7 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state)
static int
msmsdcc_resume(struct platform_device *dev)
{
struct mmc_host *mmc = mmc_get_drvdata(dev);
struct mmc_host *mmc = platform_get_drvdata(dev);
if (mmc) {
struct msmsdcc_host *host = mmc_priv(mmc);

View File

@ -111,10 +111,15 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data)
mvsd_write(MVSD_BLK_COUNT, data->blocks);
mvsd_write(MVSD_BLK_SIZE, data->blksz);
if (nodma || (data->blksz | data->sg->offset) & 3) {
if (nodma || (data->blksz | data->sg->offset) & 3 ||
((!(data->flags & MMC_DATA_READ) && data->sg->offset & 0x3f))) {
/*
* We cannot do DMA on a buffer which offset or size
* is not aligned on a 4-byte boundary.
*
* It also appears the host to card DMA can corrupt
* data when the buffer is not aligned on a 64 byte
* boundary.
*/
host->pio_size = data->blocks * data->blksz;
host->pio_ptr = sg_virt(data->sg);

View File

@ -373,13 +373,9 @@ static void mxcmci_dma_callback(void *data)
del_timer(&host->watchdog);
stat = mxcmci_readl(host, MMC_REG_STATUS);
mxcmci_writel(host, stat & ~STATUS_DATA_TRANS_DONE, MMC_REG_STATUS);
dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat);
if (stat & STATUS_READ_OP_DONE)
mxcmci_writel(host, STATUS_READ_OP_DONE, MMC_REG_STATUS);
mxcmci_data_done(host, stat);
}
@ -743,10 +739,8 @@ static irqreturn_t mxcmci_irq(int irq, void *devid)
sdio_irq = (stat & STATUS_SDIO_INT_ACTIVE) && host->use_sdio;
spin_unlock_irqrestore(&host->lock, flags);
if (mxcmci_use_dma(host) &&
(stat & (STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE)))
mxcmci_writel(host, STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE,
MMC_REG_STATUS);
if (mxcmci_use_dma(host) && (stat & (STATUS_WRITE_OP_DONE)))
mxcmci_writel(host, STATUS_WRITE_OP_DONE, MMC_REG_STATUS);
if (sdio_irq) {
mxcmci_writel(host, STATUS_SDIO_INT_ACTIVE, MMC_REG_STATUS);
@ -756,8 +750,7 @@ static irqreturn_t mxcmci_irq(int irq, void *devid)
if (stat & STATUS_END_CMD_RESP)
mxcmci_cmd_done(host, stat);
if (mxcmci_use_dma(host) &&
(stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE))) {
if (mxcmci_use_dma(host) && (stat & STATUS_WRITE_OP_DONE)) {
del_timer(&host->watchdog);
mxcmci_data_done(host, stat);
}
@ -1084,12 +1077,14 @@ static int mxcmci_probe(struct platform_device *pdev)
dat3_card_detect = true;
ret = mmc_regulator_get_supply(mmc);
if (ret) {
if (pdata && ret != -EPROBE_DEFER)
mmc->ocr_avail = pdata->ocr_avail ? :
MMC_VDD_32_33 | MMC_VDD_33_34;
if (ret == -EPROBE_DEFER)
goto out_free;
if (!mmc->ocr_avail) {
if (pdata && pdata->ocr_avail)
mmc->ocr_avail = pdata->ocr_avail;
else
goto out_free;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
}
if (dat3_card_detect)

View File

@ -581,10 +581,9 @@ static int mxs_mmc_probe(struct platform_device *pdev)
struct regulator *reg_vmmc;
struct mxs_ssp *ssp;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq_err = platform_get_irq(pdev, 0);
if (!iores || irq_err < 0)
return -EINVAL;
if (irq_err < 0)
return irq_err;
mmc = mmc_alloc_host(sizeof(struct mxs_mmc_host), &pdev->dev);
if (!mmc)
@ -593,6 +592,7 @@ static int mxs_mmc_probe(struct platform_device *pdev)
host = mmc_priv(mmc);
ssp = &host->ssp;
ssp->dev = &pdev->dev;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ssp->base = devm_ioremap_resource(&pdev->dev, iores);
if (IS_ERR(ssp->base)) {
ret = PTR_ERR(ssp->base);
@ -619,7 +619,9 @@ static int mxs_mmc_probe(struct platform_device *pdev)
ret = PTR_ERR(ssp->clk);
goto out_mmc_free;
}
clk_prepare_enable(ssp->clk);
ret = clk_prepare_enable(ssp->clk);
if (ret)
goto out_mmc_free;
ret = mxs_mmc_reset(host);
if (ret) {
@ -660,7 +662,7 @@ static int mxs_mmc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, mmc);
ret = devm_request_irq(&pdev->dev, irq_err, mxs_mmc_irq_handler, 0,
DRIVER_NAME, host);
dev_name(&pdev->dev), host);
if (ret)
goto out_free_dma;
@ -702,7 +704,7 @@ static int mxs_mmc_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static int mxs_mmc_suspend(struct device *dev)
{
struct mmc_host *mmc = dev_get_drvdata(dev);
@ -719,25 +721,19 @@ static int mxs_mmc_resume(struct device *dev)
struct mxs_mmc_host *host = mmc_priv(mmc);
struct mxs_ssp *ssp = &host->ssp;
clk_prepare_enable(ssp->clk);
return 0;
return clk_prepare_enable(ssp->clk);
}
static const struct dev_pm_ops mxs_mmc_pm_ops = {
.suspend = mxs_mmc_suspend,
.resume = mxs_mmc_resume,
};
#endif
static SIMPLE_DEV_PM_OPS(mxs_mmc_pm_ops, mxs_mmc_suspend, mxs_mmc_resume);
static struct platform_driver mxs_mmc_driver = {
.probe = mxs_mmc_probe,
.remove = mxs_mmc_remove,
.id_table = mxs_ssp_ids,
.driver = {
.name = DRIVER_NAME,
#ifdef CONFIG_PM
.pm = &mxs_mmc_pm_ops,
#endif
.of_match_table = mxs_mmc_dt_ids,
},
};

View File

@ -42,7 +42,7 @@
#include <linux/regulator/consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/platform_data/mmc-omap.h>
#include <linux/platform_data/hsmmc-omap.h>
/* OMAP HSMMC Host Controller Registers */
#define OMAP_HSMMC_SYSSTATUS 0x0014
@ -155,7 +155,7 @@
* omap.c controller driver. Luckily this is not currently done on any known
* omap_hsmmc.c device.
*/
#define mmc_slot(host) (host->pdata->slots[host->slot_id])
#define mmc_pdata(host) host->pdata
/*
* MMC Host controller read/write API's
@ -207,7 +207,6 @@ struct omap_hsmmc_host {
int use_dma, dma_ch;
struct dma_chan *tx_chan;
struct dma_chan *rx_chan;
int slot_id;
int response_busy;
int context_loss;
int protect_card;
@ -220,7 +219,26 @@ struct omap_hsmmc_host {
#define HSMMC_SDIO_IRQ_ENABLED (1 << 1) /* SDIO irq enabled */
#define HSMMC_WAKE_IRQ_ENABLED (1 << 2)
struct omap_hsmmc_next next_data;
struct omap_mmc_platform_data *pdata;
struct omap_hsmmc_platform_data *pdata;
/* To handle board related suspend/resume functionality for MMC */
int (*suspend)(struct device *dev);
int (*resume)(struct device *dev);
/* return MMC cover switch state, can be NULL if not supported.
*
* possible return values:
* 0 - closed
* 1 - open
*/
int (*get_cover_state)(struct device *dev);
/* Card detection IRQs */
int card_detect_irq;
int (*card_detect)(struct device *dev);
int (*get_ro)(struct device *dev);
};
struct omap_mmc_of_data {
@ -230,50 +248,48 @@ struct omap_mmc_of_data {
static void omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host);
static int omap_hsmmc_card_detect(struct device *dev, int slot)
static int omap_hsmmc_card_detect(struct device *dev)
{
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
struct omap_mmc_platform_data *mmc = host->pdata;
struct omap_hsmmc_platform_data *mmc = host->pdata;
/* NOTE: assumes card detect signal is active-low */
return !gpio_get_value_cansleep(mmc->slots[0].switch_pin);
return !gpio_get_value_cansleep(mmc->switch_pin);
}
static int omap_hsmmc_get_wp(struct device *dev, int slot)
static int omap_hsmmc_get_wp(struct device *dev)
{
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
struct omap_mmc_platform_data *mmc = host->pdata;
struct omap_hsmmc_platform_data *mmc = host->pdata;
/* NOTE: assumes write protect signal is active-high */
return gpio_get_value_cansleep(mmc->slots[0].gpio_wp);
return gpio_get_value_cansleep(mmc->gpio_wp);
}
static int omap_hsmmc_get_cover_state(struct device *dev, int slot)
static int omap_hsmmc_get_cover_state(struct device *dev)
{
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
struct omap_mmc_platform_data *mmc = host->pdata;
struct omap_hsmmc_platform_data *mmc = host->pdata;
/* NOTE: assumes card detect signal is active-low */
return !gpio_get_value_cansleep(mmc->slots[0].switch_pin);
return !gpio_get_value_cansleep(mmc->switch_pin);
}
#ifdef CONFIG_PM
static int omap_hsmmc_suspend_cdirq(struct device *dev, int slot)
static int omap_hsmmc_suspend_cdirq(struct device *dev)
{
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
struct omap_mmc_platform_data *mmc = host->pdata;
disable_irq(mmc->slots[0].card_detect_irq);
disable_irq(host->card_detect_irq);
return 0;
}
static int omap_hsmmc_resume_cdirq(struct device *dev, int slot)
static int omap_hsmmc_resume_cdirq(struct device *dev)
{
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
struct omap_mmc_platform_data *mmc = host->pdata;
enable_irq(mmc->slots[0].card_detect_irq);
enable_irq(host->card_detect_irq);
return 0;
}
@ -286,8 +302,7 @@ static int omap_hsmmc_resume_cdirq(struct device *dev, int slot)
#ifdef CONFIG_REGULATOR
static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on,
int vdd)
static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd)
{
struct omap_hsmmc_host *host =
platform_get_drvdata(to_platform_device(dev));
@ -300,8 +315,8 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on,
if (!host->vcc)
return 0;
if (mmc_slot(host).before_set_reg)
mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
if (mmc_pdata(host)->before_set_reg)
mmc_pdata(host)->before_set_reg(dev, power_on, vdd);
if (host->pbias) {
if (host->pbias_enabled == 1) {
@ -363,8 +378,8 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on,
}
}
if (mmc_slot(host).after_set_reg)
mmc_slot(host).after_set_reg(dev, slot, power_on, vdd);
if (mmc_pdata(host)->after_set_reg)
mmc_pdata(host)->after_set_reg(dev, power_on, vdd);
error_set_power:
return ret;
@ -383,18 +398,18 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
} else {
host->vcc = reg;
ocr_value = mmc_regulator_get_ocrmask(reg);
if (!mmc_slot(host).ocr_mask) {
mmc_slot(host).ocr_mask = ocr_value;
if (!mmc_pdata(host)->ocr_mask) {
mmc_pdata(host)->ocr_mask = ocr_value;
} else {
if (!(mmc_slot(host).ocr_mask & ocr_value)) {
if (!(mmc_pdata(host)->ocr_mask & ocr_value)) {
dev_err(host->dev, "ocrmask %x is not supported\n",
mmc_slot(host).ocr_mask);
mmc_slot(host).ocr_mask = 0;
mmc_pdata(host)->ocr_mask);
mmc_pdata(host)->ocr_mask = 0;
return -EINVAL;
}
}
}
mmc_slot(host).set_power = omap_hsmmc_set_power;
mmc_pdata(host)->set_power = omap_hsmmc_set_power;
/* Allow an aux regulator */
reg = devm_regulator_get_optional(host->dev, "vmmc_aux");
@ -404,7 +419,7 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
host->pbias = IS_ERR(reg) ? NULL : reg;
/* For eMMC do not power off when not in sleep state */
if (mmc_slot(host).no_regulator_off_init)
if (mmc_pdata(host)->no_regulator_off_init)
return 0;
/*
* To disable boot_on regulator, enable regulator
@ -412,10 +427,10 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
*/
if ((host->vcc && regulator_is_enabled(host->vcc) > 0) ||
(host->vcc_aux && regulator_is_enabled(host->vcc_aux))) {
int vdd = ffs(mmc_slot(host).ocr_mask) - 1;
int vdd = ffs(mmc_pdata(host)->ocr_mask) - 1;
mmc_slot(host).set_power(host->dev, host->slot_id, 1, vdd);
mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
mmc_pdata(host)->set_power(host->dev, 1, vdd);
mmc_pdata(host)->set_power(host->dev, 0, 0);
}
return 0;
@ -423,7 +438,7 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host)
{
mmc_slot(host).set_power = NULL;
mmc_pdata(host)->set_power = NULL;
}
static inline int omap_hsmmc_have_reg(void)
@ -449,55 +464,59 @@ static inline int omap_hsmmc_have_reg(void)
#endif
static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata)
static int omap_hsmmc_gpio_init(struct omap_hsmmc_host *host,
struct omap_hsmmc_platform_data *pdata)
{
int ret;
if (gpio_is_valid(pdata->slots[0].switch_pin)) {
if (pdata->slots[0].cover)
pdata->slots[0].get_cover_state =
omap_hsmmc_get_cover_state;
if (gpio_is_valid(pdata->switch_pin)) {
if (pdata->cover)
host->get_cover_state =
omap_hsmmc_get_cover_state;
else
pdata->slots[0].card_detect = omap_hsmmc_card_detect;
pdata->slots[0].card_detect_irq =
gpio_to_irq(pdata->slots[0].switch_pin);
ret = gpio_request(pdata->slots[0].switch_pin, "mmc_cd");
host->card_detect = omap_hsmmc_card_detect;
host->card_detect_irq =
gpio_to_irq(pdata->switch_pin);
ret = gpio_request(pdata->switch_pin, "mmc_cd");
if (ret)
return ret;
ret = gpio_direction_input(pdata->slots[0].switch_pin);
ret = gpio_direction_input(pdata->switch_pin);
if (ret)
goto err_free_sp;
} else
pdata->slots[0].switch_pin = -EINVAL;
} else {
pdata->switch_pin = -EINVAL;
}
if (gpio_is_valid(pdata->slots[0].gpio_wp)) {
pdata->slots[0].get_ro = omap_hsmmc_get_wp;
ret = gpio_request(pdata->slots[0].gpio_wp, "mmc_wp");
if (gpio_is_valid(pdata->gpio_wp)) {
host->get_ro = omap_hsmmc_get_wp;
ret = gpio_request(pdata->gpio_wp, "mmc_wp");
if (ret)
goto err_free_cd;
ret = gpio_direction_input(pdata->slots[0].gpio_wp);
ret = gpio_direction_input(pdata->gpio_wp);
if (ret)
goto err_free_wp;
} else
pdata->slots[0].gpio_wp = -EINVAL;
} else {
pdata->gpio_wp = -EINVAL;
}
return 0;
err_free_wp:
gpio_free(pdata->slots[0].gpio_wp);
gpio_free(pdata->gpio_wp);
err_free_cd:
if (gpio_is_valid(pdata->slots[0].switch_pin))
if (gpio_is_valid(pdata->switch_pin))
err_free_sp:
gpio_free(pdata->slots[0].switch_pin);
gpio_free(pdata->switch_pin);
return ret;
}
static void omap_hsmmc_gpio_free(struct omap_mmc_platform_data *pdata)
static void omap_hsmmc_gpio_free(struct omap_hsmmc_host *host,
struct omap_hsmmc_platform_data *pdata)
{
if (gpio_is_valid(pdata->slots[0].gpio_wp))
gpio_free(pdata->slots[0].gpio_wp);
if (gpio_is_valid(pdata->slots[0].switch_pin))
gpio_free(pdata->slots[0].switch_pin);
if (gpio_is_valid(pdata->gpio_wp))
gpio_free(pdata->gpio_wp);
if (gpio_is_valid(pdata->switch_pin))
gpio_free(pdata->switch_pin);
}
/*
@ -607,8 +626,9 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
* in capabilities register
* - MMC/SD clock coming out of controller > 25MHz
*/
if ((mmc_slot(host).features & HSMMC_HAS_HSPE_SUPPORT) &&
if ((mmc_pdata(host)->features & HSMMC_HAS_HSPE_SUPPORT) &&
(ios->timing != MMC_TIMING_MMC_DDR52) &&
(ios->timing != MMC_TIMING_UHS_DDR50) &&
((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) {
regval = OMAP_HSMMC_READ(host->base, HCTL);
if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000)
@ -628,7 +648,8 @@ static void omap_hsmmc_set_bus_width(struct omap_hsmmc_host *host)
u32 con;
con = OMAP_HSMMC_READ(host->base, CON);
if (ios->timing == MMC_TIMING_MMC_DDR52)
if (ios->timing == MMC_TIMING_MMC_DDR52 ||
ios->timing == MMC_TIMING_UHS_DDR50)
con |= DDR; /* configure in DDR mode */
else
con &= ~DDR;
@ -791,8 +812,8 @@ int omap_hsmmc_cover_is_closed(struct omap_hsmmc_host *host)
{
int r = 1;
if (mmc_slot(host).get_cover_state)
r = mmc_slot(host).get_cover_state(host->dev, host->slot_id);
if (host->get_cover_state)
r = host->get_cover_state(host->dev);
return r;
}
@ -816,7 +837,7 @@ omap_hsmmc_show_slot_name(struct device *dev, struct device_attribute *attr,
struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
struct omap_hsmmc_host *host = mmc_priv(mmc);
return sprintf(buf, "%s\n", mmc_slot(host).name);
return sprintf(buf, "%s\n", mmc_pdata(host)->name);
}
static DEVICE_ATTR(slot_name, S_IRUGO, omap_hsmmc_show_slot_name, NULL);
@ -1061,7 +1082,7 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
* OMAP4 ES2 and greater has an updated reset logic.
* Monitor a 0->1 transition first
*/
if (mmc_slot(host).features & HSMMC_HAS_UPDATED_RESET) {
if (mmc_pdata(host)->features & HSMMC_HAS_UPDATED_RESET) {
while ((!(OMAP_HSMMC_READ(host->base, SYSCTL) & bit))
&& (i++ < limit))
udelay(1);
@ -1210,12 +1231,11 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
clk_disable_unprepare(host->dbclk);
/* Turn the power off */
ret = mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
ret = mmc_pdata(host)->set_power(host->dev, 0, 0);
/* Turn the power ON with given VDD 1.8 or 3.0v */
if (!ret)
ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1,
vdd);
ret = mmc_pdata(host)->set_power(host->dev, 1, vdd);
pm_runtime_get_sync(host->dev);
if (host->dbclk)
clk_prepare_enable(host->dbclk);
@ -1259,11 +1279,11 @@ err:
/* Protect the card while the cover is open */
static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host)
{
if (!mmc_slot(host).get_cover_state)
if (!host->get_cover_state)
return;
host->reqs_blocked = 0;
if (mmc_slot(host).get_cover_state(host->dev, host->slot_id)) {
if (host->get_cover_state(host->dev)) {
if (host->protect_card) {
dev_info(host->dev, "%s: cover is closed, "
"card is now accessible\n",
@ -1286,13 +1306,12 @@ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host)
static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id)
{
struct omap_hsmmc_host *host = dev_id;
struct omap_mmc_slot_data *slot = &mmc_slot(host);
int carddetect;
sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
if (slot->card_detect)
carddetect = slot->card_detect(host->dev, host->slot_id);
if (host->card_detect)
carddetect = host->card_detect(host->dev);
else {
omap_hsmmc_protect_card(host);
carddetect = -ENOSYS;
@ -1618,12 +1637,10 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (ios->power_mode != host->power_mode) {
switch (ios->power_mode) {
case MMC_POWER_OFF:
mmc_slot(host).set_power(host->dev, host->slot_id,
0, 0);
mmc_pdata(host)->set_power(host->dev, 0, 0);
break;
case MMC_POWER_UP:
mmc_slot(host).set_power(host->dev, host->slot_id,
1, ios->vdd);
mmc_pdata(host)->set_power(host->dev, 1, ios->vdd);
break;
case MMC_POWER_ON:
do_send_init_stream = 1;
@ -1668,26 +1685,26 @@ static int omap_hsmmc_get_cd(struct mmc_host *mmc)
{
struct omap_hsmmc_host *host = mmc_priv(mmc);
if (!mmc_slot(host).card_detect)
if (!host->card_detect)
return -ENOSYS;
return mmc_slot(host).card_detect(host->dev, host->slot_id);
return host->card_detect(host->dev);
}
static int omap_hsmmc_get_ro(struct mmc_host *mmc)
{
struct omap_hsmmc_host *host = mmc_priv(mmc);
if (!mmc_slot(host).get_ro)
if (!host->get_ro)
return -ENOSYS;
return mmc_slot(host).get_ro(host->dev, 0);
return host->get_ro(host->dev);
}
static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card)
{
struct omap_hsmmc_host *host = mmc_priv(mmc);
if (mmc_slot(host).init_card)
mmc_slot(host).init_card(card);
if (mmc_pdata(host)->init_card)
mmc_pdata(host)->init_card(card);
}
static void omap_hsmmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
@ -1957,9 +1974,9 @@ static const struct of_device_id omap_mmc_of_match[] = {
};
MODULE_DEVICE_TABLE(of, omap_mmc_of_match);
static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
static struct omap_hsmmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
{
struct omap_mmc_platform_data *pdata;
struct omap_hsmmc_platform_data *pdata;
struct device_node *np = dev->of_node;
u32 bus_width, max_freq;
int cd_gpio, wp_gpio;
@ -1976,40 +1993,38 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
if (of_find_property(np, "ti,dual-volt", NULL))
pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT;
/* This driver only supports 1 slot */
pdata->nr_slots = 1;
pdata->slots[0].switch_pin = cd_gpio;
pdata->slots[0].gpio_wp = wp_gpio;
pdata->switch_pin = cd_gpio;
pdata->gpio_wp = wp_gpio;
if (of_find_property(np, "ti,non-removable", NULL)) {
pdata->slots[0].nonremovable = true;
pdata->slots[0].no_regulator_off_init = true;
pdata->nonremovable = true;
pdata->no_regulator_off_init = true;
}
of_property_read_u32(np, "bus-width", &bus_width);
if (bus_width == 4)
pdata->slots[0].caps |= MMC_CAP_4_BIT_DATA;
pdata->caps |= MMC_CAP_4_BIT_DATA;
else if (bus_width == 8)
pdata->slots[0].caps |= MMC_CAP_8_BIT_DATA;
pdata->caps |= MMC_CAP_8_BIT_DATA;
if (of_find_property(np, "ti,needs-special-reset", NULL))
pdata->slots[0].features |= HSMMC_HAS_UPDATED_RESET;
pdata->features |= HSMMC_HAS_UPDATED_RESET;
if (!of_property_read_u32(np, "max-frequency", &max_freq))
pdata->max_freq = max_freq;
if (of_find_property(np, "ti,needs-special-hs-handling", NULL))
pdata->slots[0].features |= HSMMC_HAS_HSPE_SUPPORT;
pdata->features |= HSMMC_HAS_HSPE_SUPPORT;
if (of_find_property(np, "keep-power-in-suspend", NULL))
pdata->slots[0].pm_caps |= MMC_PM_KEEP_POWER;
pdata->pm_caps |= MMC_PM_KEEP_POWER;
if (of_find_property(np, "enable-sdio-wakeup", NULL))
pdata->slots[0].pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
pdata->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
return pdata;
}
#else
static inline struct omap_mmc_platform_data
static inline struct omap_hsmmc_platform_data
*of_get_hsmmc_pdata(struct device *dev)
{
return ERR_PTR(-EINVAL);
@ -2018,7 +2033,7 @@ static inline struct omap_mmc_platform_data
static int omap_hsmmc_probe(struct platform_device *pdev)
{
struct omap_mmc_platform_data *pdata = pdev->dev.platform_data;
struct omap_hsmmc_platform_data *pdata = pdev->dev.platform_data;
struct mmc_host *mmc;
struct omap_hsmmc_host *host = NULL;
struct resource *res;
@ -2048,11 +2063,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
return -ENXIO;
}
if (pdata->nr_slots == 0) {
dev_err(&pdev->dev, "No Slots\n");
return -ENXIO;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (res == NULL || irq < 0)
@ -2062,14 +2072,10 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
if (IS_ERR(base))
return PTR_ERR(base);
ret = omap_hsmmc_gpio_init(pdata);
if (ret)
goto err;
mmc = mmc_alloc_host(sizeof(struct omap_hsmmc_host), &pdev->dev);
if (!mmc) {
ret = -ENOMEM;
goto err_alloc;
goto err;
}
host = mmc_priv(mmc);
@ -2079,13 +2085,16 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
host->use_dma = 1;
host->dma_ch = -1;
host->irq = irq;
host->slot_id = 0;
host->mapbase = res->start + pdata->reg_offset;
host->base = base + pdata->reg_offset;
host->power_mode = MMC_POWER_OFF;
host->next_data.cookie = 1;
host->pbias_enabled = 0;
ret = omap_hsmmc_gpio_init(host, pdata);
if (ret)
goto err_gpio;
platform_set_drvdata(pdev, host);
if (pdev->dev.of_node)
@ -2144,14 +2153,14 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
mmc->caps |= mmc_slot(host).caps;
mmc->caps |= mmc_pdata(host)->caps;
if (mmc->caps & MMC_CAP_8_BIT_DATA)
mmc->caps |= MMC_CAP_4_BIT_DATA;
if (mmc_slot(host).nonremovable)
if (mmc_pdata(host)->nonremovable)
mmc->caps |= MMC_CAP_NONREMOVABLE;
mmc->pm_caps = mmc_slot(host).pm_caps;
mmc->pm_caps = mmc_pdata(host)->pm_caps;
omap_hsmmc_conf_bus_power(host);
@ -2204,27 +2213,19 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
goto err_irq;
}
if (pdata->init != NULL) {
if (pdata->init(&pdev->dev) != 0) {
dev_err(mmc_dev(host->mmc),
"Unable to configure MMC IRQs\n");
goto err_irq;
}
}
if (omap_hsmmc_have_reg() && !mmc_slot(host).set_power) {
if (omap_hsmmc_have_reg() && !mmc_pdata(host)->set_power) {
ret = omap_hsmmc_reg_get(host);
if (ret)
goto err_reg;
goto err_irq;
host->use_reg = 1;
}
mmc->ocr_avail = mmc_slot(host).ocr_mask;
mmc->ocr_avail = mmc_pdata(host)->ocr_mask;
/* Request IRQ for card detect */
if ((mmc_slot(host).card_detect_irq)) {
if (host->card_detect_irq) {
ret = devm_request_threaded_irq(&pdev->dev,
mmc_slot(host).card_detect_irq,
host->card_detect_irq,
NULL, omap_hsmmc_detect,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
mmc_hostname(mmc), host);
@ -2233,8 +2234,8 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
"Unable to grab MMC CD IRQ\n");
goto err_irq_cd;
}
pdata->suspend = omap_hsmmc_suspend_cdirq;
pdata->resume = omap_hsmmc_resume_cdirq;
host->suspend = omap_hsmmc_suspend_cdirq;
host->resume = omap_hsmmc_resume_cdirq;
}
omap_hsmmc_disable_irq(host);
@ -2255,12 +2256,12 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
mmc_add_host(mmc);
if (mmc_slot(host).name != NULL) {
if (mmc_pdata(host)->name != NULL) {
ret = device_create_file(&mmc->class_dev, &dev_attr_slot_name);
if (ret < 0)
goto err_slot_name;
}
if (mmc_slot(host).card_detect_irq && mmc_slot(host).get_cover_state) {
if (host->card_detect_irq && host->get_cover_state) {
ret = device_create_file(&mmc->class_dev,
&dev_attr_cover_switch);
if (ret < 0)
@ -2278,9 +2279,6 @@ err_slot_name:
err_irq_cd:
if (host->use_reg)
omap_hsmmc_reg_put(host);
err_reg:
if (host->pdata->cleanup)
host->pdata->cleanup(&pdev->dev);
err_irq:
if (host->tx_chan)
dma_release_channel(host->tx_chan);
@ -2291,9 +2289,9 @@ err_irq:
if (host->dbclk)
clk_disable_unprepare(host->dbclk);
err1:
omap_hsmmc_gpio_free(host, pdata);
err_gpio:
mmc_free_host(mmc);
err_alloc:
omap_hsmmc_gpio_free(pdata);
err:
return ret;
}
@ -2306,8 +2304,6 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
mmc_remove_host(host->mmc);
if (host->use_reg)
omap_hsmmc_reg_put(host);
if (host->pdata->cleanup)
host->pdata->cleanup(&pdev->dev);
if (host->tx_chan)
dma_release_channel(host->tx_chan);
@ -2319,7 +2315,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
if (host->dbclk)
clk_disable_unprepare(host->dbclk);
omap_hsmmc_gpio_free(host->pdata);
omap_hsmmc_gpio_free(host, host->pdata);
mmc_free_host(host->mmc);
return 0;
@ -2330,8 +2326,8 @@ static int omap_hsmmc_prepare(struct device *dev)
{
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
if (host->pdata->suspend)
return host->pdata->suspend(dev, host->slot_id);
if (host->suspend)
return host->suspend(dev);
return 0;
}
@ -2340,8 +2336,8 @@ static void omap_hsmmc_complete(struct device *dev)
{
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
if (host->pdata->resume)
host->pdata->resume(dev, host->slot_id);
if (host->resume)
host->resume(dev);
}

View File

@ -76,6 +76,7 @@ struct sdhci_acpi_host {
const struct sdhci_acpi_slot *slot;
struct platform_device *pdev;
bool use_runtime_pm;
bool dma_setup;
};
static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag)
@ -85,7 +86,29 @@ static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag)
static int sdhci_acpi_enable_dma(struct sdhci_host *host)
{
return 0;
struct sdhci_acpi_host *c = sdhci_priv(host);
struct device *dev = &c->pdev->dev;
int err = -1;
if (c->dma_setup)
return 0;
if (host->flags & SDHCI_USE_64_BIT_DMA) {
if (host->quirks2 & SDHCI_QUIRK2_BROKEN_64_BIT_DMA) {
host->flags &= ~SDHCI_USE_64_BIT_DMA;
} else {
err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
if (err)
dev_warn(dev, "Failed to set 64-bit DMA mask\n");
}
}
if (err)
err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
c->dma_setup = !err;
return err;
}
static void sdhci_acpi_int_hw_reset(struct sdhci_host *host)
@ -180,17 +203,21 @@ static int sdhci_acpi_sd_probe_slot(struct platform_device *pdev,
static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
.chip = &sdhci_acpi_chip_int,
.caps = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR,
MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR |
MMC_CAP_BUS_WIDTH_TEST | MMC_CAP_WAIT_WHILE_BUSY,
.caps2 = MMC_CAP2_HC_ERASE_SZ,
.flags = SDHCI_ACPI_RUNTIME_PM,
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_STOP_WITH_TC,
.probe_slot = sdhci_acpi_emmc_probe_slot,
};
static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
.quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION,
.quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON,
.caps = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD,
.caps = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD |
MMC_CAP_BUS_WIDTH_TEST | MMC_CAP_WAIT_WHILE_BUSY,
.flags = SDHCI_ACPI_RUNTIME_PM,
.pm_caps = MMC_PM_KEEP_POWER,
.probe_slot = sdhci_acpi_sdio_probe_slot,
@ -199,8 +226,10 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
.flags = SDHCI_ACPI_SD_CD | SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL |
SDHCI_ACPI_RUNTIME_PM,
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |
SDHCI_QUIRK2_STOP_WITH_TC,
.caps = MMC_CAP_BUS_WIDTH_TEST | MMC_CAP_WAIT_WHILE_BUSY,
.probe_slot = sdhci_acpi_sd_probe_slot,
};
@ -305,21 +334,6 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
goto err_free;
}
if (!dev->dma_mask) {
u64 dma_mask;
if (sdhci_readl(host, SDHCI_CAPABILITIES) & SDHCI_CAN_64BIT) {
/* 64-bit DMA is not supported at present */
dma_mask = DMA_BIT_MASK(32);
} else {
dma_mask = DMA_BIT_MASK(32);
}
err = dma_coerce_mask_and_coherent(dev, dma_mask);
if (err)
goto err_free;
}
if (c->slot) {
if (c->slot->probe_slot) {
err = c->slot->probe_slot(pdev, hid, uid);

View File

@ -65,8 +65,6 @@
/* NOTE: the minimum valid tuning start tap for mx6sl is 1 */
#define ESDHC_TUNING_START_TAP 0x1
#define ESDHC_TUNING_BLOCK_PATTERN_LEN 64
/* pinctrl state */
#define ESDHC_PINCTRL_STATE_100MHZ "state_100mhz"
#define ESDHC_PINCTRL_STATE_200MHZ "state_200mhz"
@ -692,8 +690,6 @@ static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
/* FIXME: delay a bit for card to be ready for next tuning due to errors */
mdelay(1);
/* This is balanced by the runtime put in sdhci_tasklet_finish */
pm_runtime_get_sync(host->mmc->parent);
reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL |
ESDHC_MIX_CTRL_FBCLK_SEL;
@ -704,54 +700,6 @@ static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
val, readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS));
}
static void esdhc_request_done(struct mmc_request *mrq)
{
complete(&mrq->completion);
}
static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode,
struct scatterlist *sg)
{
struct mmc_command cmd = {0};
struct mmc_request mrq = {NULL};
struct mmc_data data = {0};
cmd.opcode = opcode;
cmd.arg = 0;
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
data.blksz = ESDHC_TUNING_BLOCK_PATTERN_LEN;
data.blocks = 1;
data.flags = MMC_DATA_READ;
data.sg = sg;
data.sg_len = 1;
mrq.cmd = &cmd;
mrq.cmd->mrq = &mrq;
mrq.data = &data;
mrq.data->mrq = &mrq;
mrq.cmd->data = mrq.data;
mrq.done = esdhc_request_done;
init_completion(&(mrq.completion));
spin_lock_irq(&host->lock);
host->mrq = &mrq;
sdhci_send_command(host, mrq.cmd);
spin_unlock_irq(&host->lock);
wait_for_completion(&mrq.completion);
if (cmd.error)
return cmd.error;
if (data.error)
return data.error;
return 0;
}
static void esdhc_post_tuning(struct sdhci_host *host)
{
u32 reg;
@ -763,21 +711,13 @@ static void esdhc_post_tuning(struct sdhci_host *host)
static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
{
struct scatterlist sg;
char *tuning_pattern;
int min, max, avg, ret;
tuning_pattern = kmalloc(ESDHC_TUNING_BLOCK_PATTERN_LEN, GFP_KERNEL);
if (!tuning_pattern)
return -ENOMEM;
sg_init_one(&sg, tuning_pattern, ESDHC_TUNING_BLOCK_PATTERN_LEN);
/* find the mininum delay first which can pass tuning */
min = ESDHC_TUNE_CTRL_MIN;
while (min < ESDHC_TUNE_CTRL_MAX) {
esdhc_prepare_tuning(host, min);
if (!esdhc_send_tuning_cmd(host, opcode, &sg))
if (!mmc_send_tuning(host->mmc))
break;
min += ESDHC_TUNE_CTRL_STEP;
}
@ -786,7 +726,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
max = min + ESDHC_TUNE_CTRL_STEP;
while (max < ESDHC_TUNE_CTRL_MAX) {
esdhc_prepare_tuning(host, max);
if (esdhc_send_tuning_cmd(host, opcode, &sg)) {
if (mmc_send_tuning(host->mmc)) {
max -= ESDHC_TUNE_CTRL_STEP;
break;
}
@ -796,11 +736,9 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
/* use average delay to get the best timing */
avg = (min + max) / 2;
esdhc_prepare_tuning(host, avg);
ret = esdhc_send_tuning_cmd(host, opcode, &sg);
ret = mmc_send_tuning(host->mmc);
esdhc_post_tuning(host);
kfree(tuning_pattern);
dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n",
ret ? "failed" : "passed", avg, ret);
@ -1031,11 +969,8 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
imx_data->pins_default = pinctrl_lookup_state(imx_data->pinctrl,
PINCTRL_STATE_DEFAULT);
if (IS_ERR(imx_data->pins_default)) {
err = PTR_ERR(imx_data->pins_default);
dev_err(mmc_dev(host->mmc), "could not get default state\n");
goto disable_clk;
}
if (IS_ERR(imx_data->pins_default))
dev_warn(mmc_dev(host->mmc), "could not get default state\n");
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
@ -1123,7 +1058,8 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
}
/* sdr50 and sdr104 needs work on 1.8v signal voltage */
if ((boarddata->support_vsel) && esdhc_is_usdhc(imx_data)) {
if ((boarddata->support_vsel) && esdhc_is_usdhc(imx_data) &&
!IS_ERR(imx_data->pins_default)) {
imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl,
ESDHC_PINCTRL_STATE_100MHZ);
imx_data->pins_200mhz = pinctrl_lookup_state(imx_data->pinctrl,

View File

@ -339,9 +339,7 @@ static int msm_init_cm_dll(struct sdhci_host *host)
static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
{
int tuning_seq_cnt = 3;
u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
const u8 *tuning_block_pattern = tuning_blk_pattern_4bit;
int size = sizeof(tuning_blk_pattern_4bit);
u8 phase, tuned_phases[16], tuned_phase_cnt = 0;
int rc;
struct mmc_host *mmc = host->mmc;
struct mmc_ios ios = host->mmc->ios;
@ -355,53 +353,21 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
(ios.timing == MMC_TIMING_UHS_SDR104)))
return 0;
if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
(mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
tuning_block_pattern = tuning_blk_pattern_8bit;
size = sizeof(tuning_blk_pattern_8bit);
}
data_buf = kmalloc(size, GFP_KERNEL);
if (!data_buf)
return -ENOMEM;
retry:
/* First of all reset the tuning block */
rc = msm_init_cm_dll(host);
if (rc)
goto out;
return rc;
phase = 0;
do {
struct mmc_command cmd = { 0 };
struct mmc_data data = { 0 };
struct mmc_request mrq = {
.cmd = &cmd,
.data = &data
};
struct scatterlist sg;
/* Set the phase in delay line hw block */
rc = msm_config_cm_dll_phase(host, phase);
if (rc)
goto out;
return rc;
cmd.opcode = opcode;
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
data.blksz = size;
data.blocks = 1;
data.flags = MMC_DATA_READ;
data.timeout_ns = NSEC_PER_SEC; /* 1 second */
data.sg = &sg;
data.sg_len = 1;
sg_init_one(&sg, data_buf, size);
memset(data_buf, 0, size);
mmc_wait_for_req(mmc, &mrq);
if (!cmd.error && !data.error &&
!memcmp(data_buf, tuning_block_pattern, size)) {
rc = mmc_send_tuning(mmc);
if (!rc) {
/* Tuning is successful at this tuning point */
tuned_phases[tuned_phase_cnt++] = phase;
dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n",
@ -413,7 +379,7 @@ retry:
rc = msm_find_most_appropriate_phase(host, tuned_phases,
tuned_phase_cnt);
if (rc < 0)
goto out;
return rc;
else
phase = rc;
@ -423,7 +389,7 @@ retry:
*/
rc = msm_config_cm_dll_phase(host, phase);
if (rc)
goto out;
return rc;
dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n",
mmc_hostname(mmc), phase);
} else {
@ -435,8 +401,6 @@ retry:
rc = -EIO;
}
out:
kfree(data_buf);
return rc;
}

View File

@ -165,7 +165,6 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
host = sdhci_pltfm_init(pdev, &sdhci_arasan_pdata, 0);
if (IS_ERR(host)) {
ret = PTR_ERR(host);
dev_err(&pdev->dev, "platform init failed (%u)\n", ret);
goto clk_disable_all;
}
@ -175,10 +174,8 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
pltfm_host->clk = clk_xin;
ret = sdhci_add_host(host);
if (ret) {
dev_err(&pdev->dev, "platform register failed (%u)\n", ret);
if (ret)
goto err_pltfm_free;
}
return 0;

View File

@ -127,8 +127,6 @@ void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip)
return;
scratch_32 &= ~((1 << 21) | (1 << 30));
/* Set RTD3 function disabled */
scratch_32 |= ((1 << 29) | (1 << 28));
pci_write_config_dword(chip->pdev, O2_SD_FUNC_REG3, scratch_32);
/* Set L1 Entrance Timer */

View File

@ -269,7 +269,9 @@ static void sdhci_pci_int_hw_reset(struct sdhci_host *host)
static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
{
slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR;
MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR |
MMC_CAP_BUS_WIDTH_TEST |
MMC_CAP_WAIT_WHILE_BUSY;
slot->host->mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ;
slot->hw_reset = sdhci_pci_int_hw_reset;
if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BSW_EMMC)
@ -279,12 +281,16 @@ static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
{
slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE;
slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE |
MMC_CAP_BUS_WIDTH_TEST |
MMC_CAP_WAIT_WHILE_BUSY;
return 0;
}
static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
{
slot->host->mmc->caps |= MMC_CAP_BUS_WIDTH_TEST |
MMC_CAP_WAIT_WHILE_BUSY;
slot->cd_con_id = NULL;
slot->cd_idx = 0;
slot->cd_override_level = true;
@ -294,11 +300,13 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = {
.allow_runtime_pm = true,
.probe_slot = byt_emmc_probe_slot,
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
SDHCI_QUIRK2_STOP_WITH_TC,
};
static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON |
SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
.allow_runtime_pm = true,
@ -306,6 +314,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
};
static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |
SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
SDHCI_QUIRK2_STOP_WITH_TC,
@ -645,6 +654,25 @@ static const struct sdhci_pci_fixes sdhci_rtsx = {
.probe_slot = rtsx_probe_slot,
};
static int amd_probe(struct sdhci_pci_chip *chip)
{
struct pci_dev *smbus_dev;
smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, NULL);
if (smbus_dev && (smbus_dev->revision < 0x51)) {
chip->quirks2 |= SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD;
chip->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
}
return 0;
}
static const struct sdhci_pci_fixes sdhci_amd = {
.probe = amd_probe,
};
static const struct pci_device_id pci_ids[] = {
{
.vendor = PCI_VENDOR_ID_RICOH,
@ -1044,7 +1072,15 @@ static const struct pci_device_id pci_ids[] = {
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_o2,
},
{
.vendor = PCI_VENDOR_ID_AMD,
.device = PCI_ANY_ID,
.class = PCI_CLASS_SYSTEM_SDHCI << 8,
.class_mask = 0xFFFF00,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_amd,
},
{ /* Generic SD host controller */
PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
},
@ -1064,7 +1100,7 @@ static int sdhci_pci_enable_dma(struct sdhci_host *host)
{
struct sdhci_pci_slot *slot;
struct pci_dev *pdev;
int ret;
int ret = -1;
slot = sdhci_priv(host);
pdev = slot->chip->pdev;
@ -1076,7 +1112,17 @@ static int sdhci_pci_enable_dma(struct sdhci_host *host)
"doesn't fully claim to support it.\n");
}
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (host->flags & SDHCI_USE_64_BIT_DMA) {
if (host->quirks2 & SDHCI_QUIRK2_BROKEN_64_BIT_DMA) {
host->flags &= ~SDHCI_USE_64_BIT_DMA;
} else {
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
if (ret)
dev_warn(&pdev->dev, "Failed to set 64-bit DMA mask\n");
}
}
if (ret)
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret)
return ret;

View File

@ -167,23 +167,17 @@ static int sdhci_pxav2_probe(struct platform_device *pdev)
struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
struct device *dev = &pdev->dev;
struct sdhci_host *host = NULL;
struct sdhci_pxa *pxa = NULL;
const struct of_device_id *match;
int ret;
struct clk *clk;
pxa = kzalloc(sizeof(struct sdhci_pxa), GFP_KERNEL);
if (!pxa)
return -ENOMEM;
host = sdhci_pltfm_init(pdev, NULL, 0);
if (IS_ERR(host)) {
kfree(pxa);
if (IS_ERR(host))
return PTR_ERR(host);
}
pltfm_host = sdhci_priv(host);
pltfm_host->priv = pxa;
pltfm_host->priv = NULL;
clk = clk_get(dev, "PXA-SDHCLK");
if (IS_ERR(clk)) {
@ -238,7 +232,6 @@ err_add_host:
clk_put(clk);
err_clk_get:
sdhci_pltfm_free(pdev);
kfree(pxa);
return ret;
}
@ -246,14 +239,12 @@ static int sdhci_pxav2_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_pxa *pxa = pltfm_host->priv;
sdhci_remove_host(host, 1);
clk_disable_unprepare(pltfm_host->clk);
clk_put(pltfm_host->clk);
sdhci_pltfm_free(pdev);
kfree(pxa);
return 0;
}

View File

@ -58,6 +58,12 @@
#define SDCE_MISC_INT (1<<2)
#define SDCE_MISC_INT_EN (1<<1)
struct sdhci_pxa {
struct clk *clk_core;
struct clk *clk_io;
u8 power_mode;
};
/*
* These registers are relative to the second register region, for the
* MBus bridge.
@ -211,6 +217,7 @@ static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
case MMC_TIMING_UHS_SDR104:
ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180;
break;
case MMC_TIMING_MMC_DDR52:
case MMC_TIMING_UHS_DDR50:
ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180;
break;
@ -283,9 +290,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
struct sdhci_host *host = NULL;
struct sdhci_pxa *pxa = NULL;
const struct of_device_id *match;
int ret;
struct clk *clk;
pxa = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_pxa), GFP_KERNEL);
if (!pxa)
@ -305,14 +310,20 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
pltfm_host = sdhci_priv(host);
pltfm_host->priv = pxa;
clk = devm_clk_get(dev, NULL);
if (IS_ERR(clk)) {
pxa->clk_io = devm_clk_get(dev, "io");
if (IS_ERR(pxa->clk_io))
pxa->clk_io = devm_clk_get(dev, NULL);
if (IS_ERR(pxa->clk_io)) {
dev_err(dev, "failed to get io clock\n");
ret = PTR_ERR(clk);
ret = PTR_ERR(pxa->clk_io);
goto err_clk_get;
}
pltfm_host->clk = clk;
clk_prepare_enable(clk);
pltfm_host->clk = pxa->clk_io;
clk_prepare_enable(pxa->clk_io);
pxa->clk_core = devm_clk_get(dev, "core");
if (!IS_ERR(pxa->clk_core))
clk_prepare_enable(pxa->clk_core);
/* enable 1/8V DDR capable */
host->mmc->caps |= MMC_CAP_1_8V_DDR;
@ -385,7 +396,9 @@ err_add_host:
pm_runtime_disable(&pdev->dev);
err_of_parse:
err_cd_req:
clk_disable_unprepare(clk);
clk_disable_unprepare(pxa->clk_io);
if (!IS_ERR(pxa->clk_core))
clk_disable_unprepare(pxa->clk_core);
err_clk_get:
err_mbus_win:
sdhci_pltfm_free(pdev);
@ -396,12 +409,15 @@ static int sdhci_pxav3_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_pxa *pxa = pltfm_host->priv;
pm_runtime_get_sync(&pdev->dev);
sdhci_remove_host(host, 1);
pm_runtime_disable(&pdev->dev);
clk_disable_unprepare(pltfm_host->clk);
clk_disable_unprepare(pxa->clk_io);
if (!IS_ERR(pxa->clk_core))
clk_disable_unprepare(pxa->clk_core);
sdhci_pltfm_free(pdev);
@ -441,15 +457,16 @@ static int sdhci_pxav3_runtime_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_pxa *pxa = pltfm_host->priv;
unsigned long flags;
if (pltfm_host->clk) {
spin_lock_irqsave(&host->lock, flags);
host->runtime_suspended = true;
spin_unlock_irqrestore(&host->lock, flags);
spin_lock_irqsave(&host->lock, flags);
host->runtime_suspended = true;
spin_unlock_irqrestore(&host->lock, flags);
clk_disable_unprepare(pltfm_host->clk);
}
clk_disable_unprepare(pxa->clk_io);
if (!IS_ERR(pxa->clk_core))
clk_disable_unprepare(pxa->clk_core);
return 0;
}
@ -458,15 +475,16 @@ static int sdhci_pxav3_runtime_resume(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_pxa *pxa = pltfm_host->priv;
unsigned long flags;
if (pltfm_host->clk) {
clk_prepare_enable(pltfm_host->clk);
clk_prepare_enable(pxa->clk_io);
if (!IS_ERR(pxa->clk_core))
clk_prepare_enable(pxa->clk_core);
spin_lock_irqsave(&host->lock, flags);
host->runtime_suspended = false;
spin_unlock_irqrestore(&host->lock, flags);
}
spin_lock_irqsave(&host->lock, flags);
host->runtime_suspended = false;
spin_unlock_irqrestore(&host->lock, flags);
return 0;
}

View File

@ -300,6 +300,7 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
struct device *dev = &ourhost->pdev->dev;
unsigned long timeout;
u16 clk = 0;
int ret;
host->mmc->actual_clock = 0;
@ -311,7 +312,12 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
sdhci_s3c_set_clock(host, clock);
clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock);
ret = clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock);
if (ret != 0) {
dev_err(dev, "%s: failed to set clock rate %uHz\n",
mmc_hostname(host->mmc), clock);
return;
}
clk = SDHCI_CLOCK_INT_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);

View File

@ -44,8 +44,6 @@
#define MAX_TUNING_LOOP 40
#define ADMA_SIZE ((128 * 2 + 1) * 4)
static unsigned int debug_quirks = 0;
static unsigned int debug_quirks2;
@ -119,10 +117,17 @@ static void sdhci_dumpregs(struct sdhci_host *host)
pr_debug(DRIVER_NAME ": Host ctl2: 0x%08x\n",
sdhci_readw(host, SDHCI_HOST_CONTROL2));
if (host->flags & SDHCI_USE_ADMA)
pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
readl(host->ioaddr + SDHCI_ADMA_ERROR),
readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
if (host->flags & SDHCI_USE_ADMA) {
if (host->flags & SDHCI_USE_64_BIT_DMA)
pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x\n",
readl(host->ioaddr + SDHCI_ADMA_ERROR),
readl(host->ioaddr + SDHCI_ADMA_ADDRESS_HI),
readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
else
pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
readl(host->ioaddr + SDHCI_ADMA_ERROR),
readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
}
pr_debug(DRIVER_NAME ": ===========================================\n");
}
@ -448,18 +453,26 @@ static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags)
local_irq_restore(*flags);
}
static void sdhci_set_adma_desc(u8 *desc, u32 addr, int len, unsigned cmd)
static void sdhci_adma_write_desc(struct sdhci_host *host, void *desc,
dma_addr_t addr, int len, unsigned cmd)
{
__le32 *dataddr = (__le32 __force *)(desc + 4);
__le16 *cmdlen = (__le16 __force *)desc;
struct sdhci_adma2_64_desc *dma_desc = desc;
/* SDHCI specification says ADMA descriptors should be 4 byte
* aligned, so using 16 or 32bit operations should be safe. */
/* 32-bit and 64-bit descriptors have these members in same position */
dma_desc->cmd = cpu_to_le16(cmd);
dma_desc->len = cpu_to_le16(len);
dma_desc->addr_lo = cpu_to_le32((u32)addr);
cmdlen[0] = cpu_to_le16(cmd);
cmdlen[1] = cpu_to_le16(len);
if (host->flags & SDHCI_USE_64_BIT_DMA)
dma_desc->addr_hi = cpu_to_le32((u64)addr >> 32);
}
dataddr[0] = cpu_to_le32(addr);
static void sdhci_adma_mark_end(void *desc)
{
struct sdhci_adma2_64_desc *dma_desc = desc;
/* 32-bit and 64-bit descriptors have 'cmd' in same position */
dma_desc->cmd |= cpu_to_le16(ADMA2_END);
}
static int sdhci_adma_table_pre(struct sdhci_host *host,
@ -467,8 +480,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
{
int direction;
u8 *desc;
u8 *align;
void *desc;
void *align;
dma_addr_t addr;
dma_addr_t align_addr;
int len, offset;
@ -489,17 +502,17 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
direction = DMA_TO_DEVICE;
host->align_addr = dma_map_single(mmc_dev(host->mmc),
host->align_buffer, 128 * 4, direction);
host->align_buffer, host->align_buffer_sz, direction);
if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr))
goto fail;
BUG_ON(host->align_addr & 0x3);
BUG_ON(host->align_addr & host->align_mask);
host->sg_count = dma_map_sg(mmc_dev(host->mmc),
data->sg, data->sg_len, direction);
if (host->sg_count == 0)
goto unmap_align;
desc = host->adma_desc;
desc = host->adma_table;
align = host->align_buffer;
align_addr = host->align_addr;
@ -515,24 +528,27 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
* the (up to three) bytes that screw up the
* alignment.
*/
offset = (4 - (addr & 0x3)) & 0x3;
offset = (host->align_sz - (addr & host->align_mask)) &
host->align_mask;
if (offset) {
if (data->flags & MMC_DATA_WRITE) {
buffer = sdhci_kmap_atomic(sg, &flags);
WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - 3));
WARN_ON(((long)buffer & (PAGE_SIZE - 1)) >
(PAGE_SIZE - offset));
memcpy(align, buffer, offset);
sdhci_kunmap_atomic(buffer, &flags);
}
/* tran, valid */
sdhci_set_adma_desc(desc, align_addr, offset, 0x21);
sdhci_adma_write_desc(host, desc, align_addr, offset,
ADMA2_TRAN_VALID);
BUG_ON(offset > 65536);
align += 4;
align_addr += 4;
align += host->align_sz;
align_addr += host->align_sz;
desc += 8;
desc += host->desc_sz;
addr += offset;
len -= offset;
@ -541,23 +557,23 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
BUG_ON(len > 65536);
/* tran, valid */
sdhci_set_adma_desc(desc, addr, len, 0x21);
desc += 8;
sdhci_adma_write_desc(host, desc, addr, len, ADMA2_TRAN_VALID);
desc += host->desc_sz;
/*
* If this triggers then we have a calculation bug
* somewhere. :/
*/
WARN_ON((desc - host->adma_desc) > ADMA_SIZE);
WARN_ON((desc - host->adma_table) >= host->adma_table_sz);
}
if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) {
/*
* Mark the last descriptor as the terminating descriptor
*/
if (desc != host->adma_desc) {
desc -= 8;
desc[0] |= 0x2; /* end */
if (desc != host->adma_table) {
desc -= host->desc_sz;
sdhci_adma_mark_end(desc);
}
} else {
/*
@ -565,7 +581,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
*/
/* nop, end, valid */
sdhci_set_adma_desc(desc, 0, 0, 0x3);
sdhci_adma_write_desc(host, desc, 0, 0, ADMA2_NOP_END_VALID);
}
/*
@ -573,14 +589,14 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
*/
if (data->flags & MMC_DATA_WRITE) {
dma_sync_single_for_device(mmc_dev(host->mmc),
host->align_addr, 128 * 4, direction);
host->align_addr, host->align_buffer_sz, direction);
}
return 0;
unmap_align:
dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
128 * 4, direction);
host->align_buffer_sz, direction);
fail:
return -EINVAL;
}
@ -592,7 +608,7 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
struct scatterlist *sg;
int i, size;
u8 *align;
void *align;
char *buffer;
unsigned long flags;
bool has_unaligned;
@ -603,12 +619,12 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
direction = DMA_TO_DEVICE;
dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
128 * 4, direction);
host->align_buffer_sz, direction);
/* Do a quick scan of the SG list for any unaligned mappings */
has_unaligned = false;
for_each_sg(data->sg, sg, host->sg_count, i)
if (sg_dma_address(sg) & 3) {
if (sg_dma_address(sg) & host->align_mask) {
has_unaligned = true;
break;
}
@ -620,15 +636,17 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
align = host->align_buffer;
for_each_sg(data->sg, sg, host->sg_count, i) {
if (sg_dma_address(sg) & 0x3) {
size = 4 - (sg_dma_address(sg) & 0x3);
if (sg_dma_address(sg) & host->align_mask) {
size = host->align_sz -
(sg_dma_address(sg) & host->align_mask);
buffer = sdhci_kmap_atomic(sg, &flags);
WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - 3));
WARN_ON(((long)buffer & (PAGE_SIZE - 1)) >
(PAGE_SIZE - size));
memcpy(buffer, align, size);
sdhci_kunmap_atomic(buffer, &flags);
align += 4;
align += host->align_sz;
}
}
}
@ -822,6 +840,10 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
} else {
sdhci_writel(host, host->adma_addr,
SDHCI_ADMA_ADDRESS);
if (host->flags & SDHCI_USE_64_BIT_DMA)
sdhci_writel(host,
(u64)host->adma_addr >> 32,
SDHCI_ADMA_ADDRESS_HI);
}
} else {
int sg_cnt;
@ -855,10 +877,14 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
ctrl &= ~SDHCI_CTRL_DMA_MASK;
if ((host->flags & SDHCI_REQ_USE_DMA) &&
(host->flags & SDHCI_USE_ADMA))
ctrl |= SDHCI_CTRL_ADMA32;
else
(host->flags & SDHCI_USE_ADMA)) {
if (host->flags & SDHCI_USE_64_BIT_DMA)
ctrl |= SDHCI_CTRL_ADMA64;
else
ctrl |= SDHCI_CTRL_ADMA32;
} else {
ctrl |= SDHCI_CTRL_SDMA;
}
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}
@ -889,10 +915,15 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
struct mmc_data *data = cmd->data;
if (data == NULL) {
if (host->quirks2 &
SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD) {
sdhci_writew(host, 0x0, SDHCI_TRANSFER_MODE);
} else {
/* clear Auto CMD settings for no data CMDs */
mode = sdhci_readw(host, SDHCI_TRANSFER_MODE);
sdhci_writew(host, mode & ~(SDHCI_TRNS_AUTO_CMD12 |
mode = sdhci_readw(host, SDHCI_TRANSFER_MODE);
sdhci_writew(host, mode & ~(SDHCI_TRNS_AUTO_CMD12 |
SDHCI_TRNS_AUTO_CMD23), SDHCI_TRANSFER_MODE);
}
return;
}
@ -1117,6 +1148,9 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)
case MMC_TIMING_UHS_DDR50:
preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50);
break;
case MMC_TIMING_MMC_HS400:
preset = sdhci_readw(host, SDHCI_PRESET_FOR_HS400);
break;
default:
pr_warn("%s: Invalid UHS-I mode selected\n",
mmc_hostname(host->mmc));
@ -1444,6 +1478,8 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
else if ((timing == MMC_TIMING_UHS_DDR50) ||
(timing == MMC_TIMING_MMC_DDR52))
ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
else if (timing == MMC_TIMING_MMC_HS400)
ctrl_2 |= SDHCI_CTRL_HS400; /* Non-standard */
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
}
EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
@ -1515,7 +1551,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
u16 clk, ctrl_2;
/* In case of UHS-I modes, set High Speed Enable */
if ((ios->timing == MMC_TIMING_MMC_HS200) ||
if ((ios->timing == MMC_TIMING_MMC_HS400) ||
(ios->timing == MMC_TIMING_MMC_HS200) ||
(ios->timing == MMC_TIMING_MMC_DDR52) ||
(ios->timing == MMC_TIMING_UHS_SDR50) ||
(ios->timing == MMC_TIMING_UHS_SDR104) ||
@ -1862,6 +1899,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
* tuning function has to be executed.
*/
switch (host->timing) {
case MMC_TIMING_MMC_HS400:
case MMC_TIMING_MMC_HS200:
case MMC_TIMING_UHS_SDR104:
break;
@ -2144,9 +2182,10 @@ static void sdhci_tasklet_finish(unsigned long param)
*/
if (!(host->flags & SDHCI_DEVICE_DEAD) &&
((mrq->cmd && mrq->cmd->error) ||
(mrq->data && (mrq->data->error ||
(mrq->data->stop && mrq->data->stop->error))) ||
(host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) {
(mrq->sbc && mrq->sbc->error) ||
(mrq->data && ((mrq->data->error && !mrq->data->stop) ||
(mrq->data->stop && mrq->data->stop->error))) ||
(host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) {
/* Some controllers need this kick or reset won't work here */
if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)
@ -2282,32 +2321,36 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask)
}
#ifdef CONFIG_MMC_DEBUG
static void sdhci_show_adma_error(struct sdhci_host *host)
static void sdhci_adma_show_error(struct sdhci_host *host)
{
const char *name = mmc_hostname(host->mmc);
u8 *desc = host->adma_desc;
__le32 *dma;
__le16 *len;
u8 attr;
void *desc = host->adma_table;
sdhci_dumpregs(host);
while (true) {
dma = (__le32 *)(desc + 4);
len = (__le16 *)(desc + 2);
attr = *desc;
struct sdhci_adma2_64_desc *dma_desc = desc;
DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
name, desc, le32_to_cpu(*dma), le16_to_cpu(*len), attr);
if (host->flags & SDHCI_USE_64_BIT_DMA)
DBG("%s: %p: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x\n",
name, desc, le32_to_cpu(dma_desc->addr_hi),
le32_to_cpu(dma_desc->addr_lo),
le16_to_cpu(dma_desc->len),
le16_to_cpu(dma_desc->cmd));
else
DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
name, desc, le32_to_cpu(dma_desc->addr_lo),
le16_to_cpu(dma_desc->len),
le16_to_cpu(dma_desc->cmd));
desc += 8;
desc += host->desc_sz;
if (attr & 2)
if (dma_desc->cmd & cpu_to_le16(ADMA2_END))
break;
}
}
#else
static void sdhci_show_adma_error(struct sdhci_host *host) { }
static void sdhci_adma_show_error(struct sdhci_host *host) { }
#endif
static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
@ -2370,7 +2413,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
host->data->error = -EILSEQ;
else if (intmask & SDHCI_INT_ADMA_ERROR) {
pr_err("%s: ADMA error\n", mmc_hostname(host->mmc));
sdhci_show_adma_error(host);
sdhci_adma_show_error(host);
host->data->error = -EIO;
if (host->ops->adma_workaround)
host->ops->adma_workaround(host, intmask);
@ -2849,6 +2892,16 @@ int sdhci_add_host(struct sdhci_host *host)
host->flags &= ~SDHCI_USE_ADMA;
}
/*
* It is assumed that a 64-bit capable device has set a 64-bit DMA mask
* and *must* do 64-bit DMA. A driver has the opportunity to change
* that during the first call to ->enable_dma(). Similarly
* SDHCI_QUIRK2_BROKEN_64_BIT_DMA must be left to the drivers to
* implement.
*/
if (sdhci_readl(host, SDHCI_CAPABILITIES) & SDHCI_CAN_64BIT)
host->flags |= SDHCI_USE_64_BIT_DMA;
if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
if (host->ops->enable_dma) {
if (host->ops->enable_dma(host)) {
@ -2860,33 +2913,56 @@ int sdhci_add_host(struct sdhci_host *host)
}
}
/* SDMA does not support 64-bit DMA */
if (host->flags & SDHCI_USE_64_BIT_DMA)
host->flags &= ~SDHCI_USE_SDMA;
if (host->flags & SDHCI_USE_ADMA) {
/*
* We need to allocate descriptors for all sg entries
* (128) and potentially one alignment transfer for
* each of those entries.
* The DMA descriptor table size is calculated as the maximum
* number of segments times 2, to allow for an alignment
* descriptor for each segment, plus 1 for a nop end descriptor,
* all multipled by the descriptor size.
*/
host->adma_desc = dma_alloc_coherent(mmc_dev(mmc),
ADMA_SIZE, &host->adma_addr,
GFP_KERNEL);
host->align_buffer = kmalloc(128 * 4, GFP_KERNEL);
if (!host->adma_desc || !host->align_buffer) {
dma_free_coherent(mmc_dev(mmc), ADMA_SIZE,
host->adma_desc, host->adma_addr);
if (host->flags & SDHCI_USE_64_BIT_DMA) {
host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) *
SDHCI_ADMA2_64_DESC_SZ;
host->align_buffer_sz = SDHCI_MAX_SEGS *
SDHCI_ADMA2_64_ALIGN;
host->desc_sz = SDHCI_ADMA2_64_DESC_SZ;
host->align_sz = SDHCI_ADMA2_64_ALIGN;
host->align_mask = SDHCI_ADMA2_64_ALIGN - 1;
} else {
host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) *
SDHCI_ADMA2_32_DESC_SZ;
host->align_buffer_sz = SDHCI_MAX_SEGS *
SDHCI_ADMA2_32_ALIGN;
host->desc_sz = SDHCI_ADMA2_32_DESC_SZ;
host->align_sz = SDHCI_ADMA2_32_ALIGN;
host->align_mask = SDHCI_ADMA2_32_ALIGN - 1;
}
host->adma_table = dma_alloc_coherent(mmc_dev(mmc),
host->adma_table_sz,
&host->adma_addr,
GFP_KERNEL);
host->align_buffer = kmalloc(host->align_buffer_sz, GFP_KERNEL);
if (!host->adma_table || !host->align_buffer) {
dma_free_coherent(mmc_dev(mmc), host->adma_table_sz,
host->adma_table, host->adma_addr);
kfree(host->align_buffer);
pr_warn("%s: Unable to allocate ADMA buffers - falling back to standard DMA\n",
mmc_hostname(mmc));
host->flags &= ~SDHCI_USE_ADMA;
host->adma_desc = NULL;
host->adma_table = NULL;
host->align_buffer = NULL;
} else if (host->adma_addr & 3) {
} else if (host->adma_addr & host->align_mask) {
pr_warn("%s: unable to allocate aligned ADMA descriptor\n",
mmc_hostname(mmc));
host->flags &= ~SDHCI_USE_ADMA;
dma_free_coherent(mmc_dev(mmc), ADMA_SIZE,
host->adma_desc, host->adma_addr);
dma_free_coherent(mmc_dev(mmc), host->adma_table_sz,
host->adma_table, host->adma_addr);
kfree(host->align_buffer);
host->adma_desc = NULL;
host->adma_table = NULL;
host->align_buffer = NULL;
}
}
@ -3027,7 +3103,7 @@ int sdhci_add_host(struct sdhci_host *host)
if (ret) {
pr_warn("%s: Failed to enable vqmmc regulator: %d\n",
mmc_hostname(mmc), ret);
mmc->supply.vqmmc = NULL;
mmc->supply.vqmmc = ERR_PTR(-EINVAL);
}
}
@ -3046,16 +3122,21 @@ int sdhci_add_host(struct sdhci_host *host)
/* SD3.0: SDR104 is supported so (for eMMC) the caps2
* field can be promoted to support HS200.
*/
if (!(host->quirks2 & SDHCI_QUIRK2_BROKEN_HS200)) {
if (!(host->quirks2 & SDHCI_QUIRK2_BROKEN_HS200))
mmc->caps2 |= MMC_CAP2_HS200;
if (IS_ERR(mmc->supply.vqmmc) ||
!regulator_is_supported_voltage
(mmc->supply.vqmmc, 1100000, 1300000))
mmc->caps2 &= ~MMC_CAP2_HS200_1_2V_SDR;
}
} else if (caps[1] & SDHCI_SUPPORT_SDR50)
mmc->caps |= MMC_CAP_UHS_SDR50;
if (host->quirks2 & SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 &&
(caps[1] & SDHCI_SUPPORT_HS400))
mmc->caps2 |= MMC_CAP2_HS400;
if ((mmc->caps2 & MMC_CAP2_HSX00_1_2V) &&
(IS_ERR(mmc->supply.vqmmc) ||
!regulator_is_supported_voltage(mmc->supply.vqmmc, 1100000,
1300000)))
mmc->caps2 &= ~MMC_CAP2_HSX00_1_2V;
if ((caps[1] & SDHCI_SUPPORT_DDR50) &&
!(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50))
mmc->caps |= MMC_CAP_UHS_DDR50;
@ -3175,11 +3256,11 @@ int sdhci_add_host(struct sdhci_host *host)
* can do scatter/gather or not.
*/
if (host->flags & SDHCI_USE_ADMA)
mmc->max_segs = 128;
mmc->max_segs = SDHCI_MAX_SEGS;
else if (host->flags & SDHCI_USE_SDMA)
mmc->max_segs = 1;
else /* PIO */
mmc->max_segs = 128;
mmc->max_segs = SDHCI_MAX_SEGS;
/*
* Maximum number of sectors in one transfer. Limited by DMA boundary
@ -3277,7 +3358,8 @@ int sdhci_add_host(struct sdhci_host *host)
pr_info("%s: SDHCI controller on %s [%s] using %s\n",
mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)),
(host->flags & SDHCI_USE_ADMA) ? "ADMA" :
(host->flags & SDHCI_USE_ADMA) ?
(host->flags & SDHCI_USE_64_BIT_DMA) ? "ADMA 64-bit" : "ADMA" :
(host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO");
sdhci_enable_card_detection(host);
@ -3339,18 +3421,15 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
tasklet_kill(&host->finish_tasklet);
if (!IS_ERR(mmc->supply.vmmc))
regulator_disable(mmc->supply.vmmc);
if (!IS_ERR(mmc->supply.vqmmc))
regulator_disable(mmc->supply.vqmmc);
if (host->adma_desc)
dma_free_coherent(mmc_dev(mmc), ADMA_SIZE,
host->adma_desc, host->adma_addr);
if (host->adma_table)
dma_free_coherent(mmc_dev(mmc), host->adma_table_sz,
host->adma_table, host->adma_addr);
kfree(host->align_buffer);
host->adma_desc = NULL;
host->adma_table = NULL;
host->align_buffer = NULL;
}

View File

@ -161,7 +161,7 @@
#define SDHCI_CTRL_UHS_SDR50 0x0002
#define SDHCI_CTRL_UHS_SDR104 0x0003
#define SDHCI_CTRL_UHS_DDR50 0x0004
#define SDHCI_CTRL_HS_SDR200 0x0005 /* reserved value in SDIO spec */
#define SDHCI_CTRL_HS400 0x0005 /* Non-standard */
#define SDHCI_CTRL_VDD_180 0x0008
#define SDHCI_CTRL_DRV_TYPE_MASK 0x0030
#define SDHCI_CTRL_DRV_TYPE_B 0x0000
@ -204,6 +204,7 @@
#define SDHCI_RETUNING_MODE_SHIFT 14
#define SDHCI_CLOCK_MUL_MASK 0x00FF0000
#define SDHCI_CLOCK_MUL_SHIFT 16
#define SDHCI_SUPPORT_HS400 0x80000000 /* Non-standard */
#define SDHCI_CAPABILITIES_1 0x44
@ -227,6 +228,7 @@
/* 55-57 reserved */
#define SDHCI_ADMA_ADDRESS 0x58
#define SDHCI_ADMA_ADDRESS_HI 0x5C
/* 60-FB reserved */
@ -235,6 +237,7 @@
#define SDHCI_PRESET_FOR_SDR50 0x6A
#define SDHCI_PRESET_FOR_SDR104 0x6C
#define SDHCI_PRESET_FOR_DDR50 0x6E
#define SDHCI_PRESET_FOR_HS400 0x74 /* Non-standard */
#define SDHCI_PRESET_DRV_MASK 0xC000
#define SDHCI_PRESET_DRV_SHIFT 14
#define SDHCI_PRESET_CLKGEN_SEL_MASK 0x400
@ -266,6 +269,46 @@
#define SDHCI_DEFAULT_BOUNDARY_SIZE (512 * 1024)
#define SDHCI_DEFAULT_BOUNDARY_ARG (ilog2(SDHCI_DEFAULT_BOUNDARY_SIZE) - 12)
/* ADMA2 32-bit DMA descriptor size */
#define SDHCI_ADMA2_32_DESC_SZ 8
/* ADMA2 32-bit DMA alignment */
#define SDHCI_ADMA2_32_ALIGN 4
/* ADMA2 32-bit descriptor */
struct sdhci_adma2_32_desc {
__le16 cmd;
__le16 len;
__le32 addr;
} __packed __aligned(SDHCI_ADMA2_32_ALIGN);
/* ADMA2 64-bit DMA descriptor size */
#define SDHCI_ADMA2_64_DESC_SZ 12
/* ADMA2 64-bit DMA alignment */
#define SDHCI_ADMA2_64_ALIGN 8
/*
* ADMA2 64-bit descriptor. Note 12-byte descriptor can't always be 8-byte
* aligned.
*/
struct sdhci_adma2_64_desc {
__le16 cmd;
__le16 len;
__le32 addr_lo;
__le32 addr_hi;
} __packed __aligned(4);
#define ADMA2_TRAN_VALID 0x21
#define ADMA2_NOP_END_VALID 0x3
#define ADMA2_END 0x2
/*
* Maximum segments assuming a 512KiB maximum requisition size and a minimum
* 4KiB page size.
*/
#define SDHCI_MAX_SEGS 128
struct sdhci_ops {
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
u32 (*read_l)(struct sdhci_host *host, int reg);

View File

@ -21,7 +21,6 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/clk-private.h>
#include <linux/clk/sunxi.h>
#include <linux/gpio.h>

717
drivers/mmc/host/toshsd.c Normal file
View File

@ -0,0 +1,717 @@
/*
* Toshiba PCI Secure Digital Host Controller Interface driver
*
* Copyright (C) 2014 Ondrej Zary
* Copyright (C) 2007 Richard Betts, All Rights Reserved.
*
* Based on asic3_mmc.c, copyright (c) 2005 SDG Systems, LLC and,
* sdhci.c, copyright (C) 2005-2006 Pierre Ossman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*/
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/scatterlist.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/pm.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include "toshsd.h"
#define DRIVER_NAME "toshsd"
static const struct pci_device_id pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA, 0x0805) },
{ /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(pci, pci_ids);
static void toshsd_init(struct toshsd_host *host)
{
/* enable clock */
pci_write_config_byte(host->pdev, SD_PCICFG_CLKSTOP,
SD_PCICFG_CLKSTOP_ENABLE_ALL);
pci_write_config_byte(host->pdev, SD_PCICFG_CARDDETECT, 2);
/* reset */
iowrite16(0, host->ioaddr + SD_SOFTWARERESET); /* assert */
mdelay(2);
iowrite16(1, host->ioaddr + SD_SOFTWARERESET); /* deassert */
mdelay(2);
/* Clear card registers */
iowrite16(0, host->ioaddr + SD_CARDCLOCKCTRL);
iowrite32(0, host->ioaddr + SD_CARDSTATUS);
iowrite32(0, host->ioaddr + SD_ERRORSTATUS0);
iowrite16(0, host->ioaddr + SD_STOPINTERNAL);
/* SDIO clock? */
iowrite16(0x100, host->ioaddr + SDIO_BASE + SDIO_CLOCKNWAITCTRL);
/* enable LED */
pci_write_config_byte(host->pdev, SD_PCICFG_SDLED_ENABLE1,
SD_PCICFG_LED_ENABLE1_START);
pci_write_config_byte(host->pdev, SD_PCICFG_SDLED_ENABLE2,
SD_PCICFG_LED_ENABLE2_START);
/* set interrupt masks */
iowrite32(~(u32)(SD_CARD_RESP_END | SD_CARD_RW_END
| SD_CARD_CARD_REMOVED_0 | SD_CARD_CARD_INSERTED_0
| SD_BUF_READ_ENABLE | SD_BUF_WRITE_ENABLE
| SD_BUF_CMD_TIMEOUT),
host->ioaddr + SD_INTMASKCARD);
iowrite16(0x1000, host->ioaddr + SD_TRANSACTIONCTRL);
}
/* Set MMC clock / power.
* Note: This controller uses a simple divider scheme therefore it cannot run
* SD/MMC cards at full speed (24/20MHz). HCLK (=33MHz PCI clock?) is too high
* and the next slowest is 16MHz (div=2).
*/
static void __toshsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct toshsd_host *host = mmc_priv(mmc);
if (ios->clock) {
u16 clk;
int div = 1;
while (ios->clock < HCLK / div)
div *= 2;
clk = div >> 2;
if (div == 1) { /* disable the divider */
pci_write_config_byte(host->pdev, SD_PCICFG_CLKMODE,
SD_PCICFG_CLKMODE_DIV_DISABLE);
clk |= SD_CARDCLK_DIV_DISABLE;
} else
pci_write_config_byte(host->pdev, SD_PCICFG_CLKMODE, 0);
clk |= SD_CARDCLK_ENABLE_CLOCK;
iowrite16(clk, host->ioaddr + SD_CARDCLOCKCTRL);
mdelay(10);
} else
iowrite16(0, host->ioaddr + SD_CARDCLOCKCTRL);
switch (ios->power_mode) {
case MMC_POWER_OFF:
pci_write_config_byte(host->pdev, SD_PCICFG_POWER1,
SD_PCICFG_PWR1_OFF);
mdelay(1);
break;
case MMC_POWER_UP:
break;
case MMC_POWER_ON:
pci_write_config_byte(host->pdev, SD_PCICFG_POWER1,
SD_PCICFG_PWR1_33V);
pci_write_config_byte(host->pdev, SD_PCICFG_POWER2,
SD_PCICFG_PWR2_AUTO);
mdelay(20);
break;
}
switch (ios->bus_width) {
case MMC_BUS_WIDTH_1:
iowrite16(SD_CARDOPT_REQUIRED | SD_CARDOPT_DATA_RESP_TIMEOUT(14)
| SD_CARDOPT_C2_MODULE_ABSENT
| SD_CARDOPT_DATA_XFR_WIDTH_1,
host->ioaddr + SD_CARDOPTIONSETUP);
break;
case MMC_BUS_WIDTH_4:
iowrite16(SD_CARDOPT_REQUIRED | SD_CARDOPT_DATA_RESP_TIMEOUT(14)
| SD_CARDOPT_C2_MODULE_ABSENT
| SD_CARDOPT_DATA_XFR_WIDTH_4,
host->ioaddr + SD_CARDOPTIONSETUP);
break;
}
}
static void toshsd_set_led(struct toshsd_host *host, unsigned char state)
{
iowrite16(state, host->ioaddr + SDIO_BASE + SDIO_LEDCTRL);
}
static void toshsd_finish_request(struct toshsd_host *host)
{
struct mmc_request *mrq = host->mrq;
/* Write something to end the command */
host->mrq = NULL;
host->cmd = NULL;
host->data = NULL;
toshsd_set_led(host, 0);
mmc_request_done(host->mmc, mrq);
}
static irqreturn_t toshsd_thread_irq(int irq, void *dev_id)
{
struct toshsd_host *host = dev_id;
struct mmc_data *data = host->data;
struct sg_mapping_iter *sg_miter = &host->sg_miter;
unsigned short *buf;
int count;
unsigned long flags;
if (!data) {
dev_warn(&host->pdev->dev, "Spurious Data IRQ\n");
if (host->cmd) {
host->cmd->error = -EIO;
toshsd_finish_request(host);
}
return IRQ_NONE;
}
spin_lock_irqsave(&host->lock, flags);
if (!sg_miter_next(sg_miter))
return IRQ_HANDLED;
buf = sg_miter->addr;
/* Ensure we dont read more than one block. The chip will interrupt us
* When the next block is available.
*/
count = sg_miter->length;
if (count > data->blksz)
count = data->blksz;
dev_dbg(&host->pdev->dev, "count: %08x, flags %08x\n", count,
data->flags);
/* Transfer the data */
if (data->flags & MMC_DATA_READ)
ioread32_rep(host->ioaddr + SD_DATAPORT, buf, count >> 2);
else
iowrite32_rep(host->ioaddr + SD_DATAPORT, buf, count >> 2);
sg_miter->consumed = count;
sg_miter_stop(sg_miter);
spin_unlock_irqrestore(&host->lock, flags);
return IRQ_HANDLED;
}
static void toshsd_cmd_irq(struct toshsd_host *host)
{
struct mmc_command *cmd = host->cmd;
u8 *buf;
u16 data;
if (!host->cmd) {
dev_warn(&host->pdev->dev, "Spurious CMD irq\n");
return;
}
buf = (u8 *)cmd->resp;
host->cmd = NULL;
if (cmd->flags & MMC_RSP_PRESENT && cmd->flags & MMC_RSP_136) {
/* R2 */
buf[12] = 0xff;
data = ioread16(host->ioaddr + SD_RESPONSE0);
buf[13] = data & 0xff;
buf[14] = data >> 8;
data = ioread16(host->ioaddr + SD_RESPONSE1);
buf[15] = data & 0xff;
buf[8] = data >> 8;
data = ioread16(host->ioaddr + SD_RESPONSE2);
buf[9] = data & 0xff;
buf[10] = data >> 8;
data = ioread16(host->ioaddr + SD_RESPONSE3);
buf[11] = data & 0xff;
buf[4] = data >> 8;
data = ioread16(host->ioaddr + SD_RESPONSE4);
buf[5] = data & 0xff;
buf[6] = data >> 8;
data = ioread16(host->ioaddr + SD_RESPONSE5);
buf[7] = data & 0xff;
buf[0] = data >> 8;
data = ioread16(host->ioaddr + SD_RESPONSE6);
buf[1] = data & 0xff;
buf[2] = data >> 8;
data = ioread16(host->ioaddr + SD_RESPONSE7);
buf[3] = data & 0xff;
} else if (cmd->flags & MMC_RSP_PRESENT) {
/* R1, R1B, R3, R6, R7 */
data = ioread16(host->ioaddr + SD_RESPONSE0);
buf[0] = data & 0xff;
buf[1] = data >> 8;
data = ioread16(host->ioaddr + SD_RESPONSE1);
buf[2] = data & 0xff;
buf[3] = data >> 8;
}
dev_dbg(&host->pdev->dev, "Command IRQ complete %d %d %x\n",
cmd->opcode, cmd->error, cmd->flags);
/* If there is data to handle we will
* finish the request in the mmc_data_end_irq handler.*/
if (host->data)
return;
toshsd_finish_request(host);
}
static void toshsd_data_end_irq(struct toshsd_host *host)
{
struct mmc_data *data = host->data;
host->data = NULL;
if (!data) {
dev_warn(&host->pdev->dev, "Spurious data end IRQ\n");
return;
}
if (data->error == 0)
data->bytes_xfered = data->blocks * data->blksz;
else
data->bytes_xfered = 0;
dev_dbg(&host->pdev->dev, "Completed data request xfr=%d\n",
data->bytes_xfered);
iowrite16(0, host->ioaddr + SD_STOPINTERNAL);
toshsd_finish_request(host);
}
static irqreturn_t toshsd_irq(int irq, void *dev_id)
{
struct toshsd_host *host = dev_id;
u32 int_reg, int_mask, int_status, detail;
int error = 0, ret = IRQ_HANDLED;
spin_lock(&host->lock);
int_status = ioread32(host->ioaddr + SD_CARDSTATUS);
int_mask = ioread32(host->ioaddr + SD_INTMASKCARD);
int_reg = int_status & ~int_mask & ~IRQ_DONT_CARE_BITS;
dev_dbg(&host->pdev->dev, "IRQ status:%x mask:%x\n",
int_status, int_mask);
/* nothing to do: it's not our IRQ */
if (!int_reg) {
ret = IRQ_NONE;
goto irq_end;
}
if (int_reg & SD_BUF_CMD_TIMEOUT) {
error = -ETIMEDOUT;
dev_dbg(&host->pdev->dev, "Timeout\n");
} else if (int_reg & SD_BUF_CRC_ERR) {
error = -EILSEQ;
dev_err(&host->pdev->dev, "BadCRC\n");
} else if (int_reg & (SD_BUF_ILLEGAL_ACCESS
| SD_BUF_CMD_INDEX_ERR
| SD_BUF_STOP_BIT_END_ERR
| SD_BUF_OVERFLOW
| SD_BUF_UNDERFLOW
| SD_BUF_DATA_TIMEOUT)) {
dev_err(&host->pdev->dev, "Buffer status error: { %s%s%s%s%s%s}\n",
int_reg & SD_BUF_ILLEGAL_ACCESS ? "ILLEGAL_ACC " : "",
int_reg & SD_BUF_CMD_INDEX_ERR ? "CMD_INDEX " : "",
int_reg & SD_BUF_STOP_BIT_END_ERR ? "STOPBIT_END " : "",
int_reg & SD_BUF_OVERFLOW ? "OVERFLOW " : "",
int_reg & SD_BUF_UNDERFLOW ? "UNDERFLOW " : "",
int_reg & SD_BUF_DATA_TIMEOUT ? "DATA_TIMEOUT " : "");
detail = ioread32(host->ioaddr + SD_ERRORSTATUS0);
dev_err(&host->pdev->dev, "detail error status { %s%s%s%s%s%s%s%s%s%s%s%s%s}\n",
detail & SD_ERR0_RESP_CMD_ERR ? "RESP_CMD " : "",
detail & SD_ERR0_RESP_NON_CMD12_END_BIT_ERR ? "RESP_END_BIT " : "",
detail & SD_ERR0_RESP_CMD12_END_BIT_ERR ? "RESP_END_BIT " : "",
detail & SD_ERR0_READ_DATA_END_BIT_ERR ? "READ_DATA_END_BIT " : "",
detail & SD_ERR0_WRITE_CRC_STATUS_END_BIT_ERR ? "WRITE_CMD_END_BIT " : "",
detail & SD_ERR0_RESP_NON_CMD12_CRC_ERR ? "RESP_CRC " : "",
detail & SD_ERR0_RESP_CMD12_CRC_ERR ? "RESP_CRC " : "",
detail & SD_ERR0_READ_DATA_CRC_ERR ? "READ_DATA_CRC " : "",
detail & SD_ERR0_WRITE_CMD_CRC_ERR ? "WRITE_CMD_CRC " : "",
detail & SD_ERR1_NO_CMD_RESP ? "NO_CMD_RESP " : "",
detail & SD_ERR1_TIMEOUT_READ_DATA ? "READ_DATA_TIMEOUT " : "",
detail & SD_ERR1_TIMEOUT_CRS_STATUS ? "CRS_STATUS_TIMEOUT " : "",
detail & SD_ERR1_TIMEOUT_CRC_BUSY ? "CRC_BUSY_TIMEOUT " : "");
error = -EIO;
}
if (error) {
if (host->cmd)
host->cmd->error = error;
if (error == -ETIMEDOUT) {
iowrite32(int_status &
~(SD_BUF_CMD_TIMEOUT | SD_CARD_RESP_END),
host->ioaddr + SD_CARDSTATUS);
} else {
toshsd_init(host);
__toshsd_set_ios(host->mmc, &host->mmc->ios);
goto irq_end;
}
}
/* Card insert/remove. The mmc controlling code is stateless. */
if (int_reg & (SD_CARD_CARD_INSERTED_0 | SD_CARD_CARD_REMOVED_0)) {
iowrite32(int_status &
~(SD_CARD_CARD_REMOVED_0 | SD_CARD_CARD_INSERTED_0),
host->ioaddr + SD_CARDSTATUS);
if (int_reg & SD_CARD_CARD_INSERTED_0)
toshsd_init(host);
mmc_detect_change(host->mmc, 1);
}
/* Data transfer */
if (int_reg & (SD_BUF_READ_ENABLE | SD_BUF_WRITE_ENABLE)) {
iowrite32(int_status &
~(SD_BUF_WRITE_ENABLE | SD_BUF_READ_ENABLE),
host->ioaddr + SD_CARDSTATUS);
ret = IRQ_WAKE_THREAD;
goto irq_end;
}
/* Command completion */
if (int_reg & SD_CARD_RESP_END) {
iowrite32(int_status & ~(SD_CARD_RESP_END),
host->ioaddr + SD_CARDSTATUS);
toshsd_cmd_irq(host);
}
/* Data transfer completion */
if (int_reg & SD_CARD_RW_END) {
iowrite32(int_status & ~(SD_CARD_RW_END),
host->ioaddr + SD_CARDSTATUS);
toshsd_data_end_irq(host);
}
irq_end:
spin_unlock(&host->lock);
return ret;
}
static void toshsd_start_cmd(struct toshsd_host *host, struct mmc_command *cmd)
{
struct mmc_data *data = host->data;
int c = cmd->opcode;
dev_dbg(&host->pdev->dev, "Command opcode: %d\n", cmd->opcode);
if (cmd->opcode == MMC_STOP_TRANSMISSION) {
iowrite16(SD_STOPINT_ISSUE_CMD12,
host->ioaddr + SD_STOPINTERNAL);
cmd->resp[0] = cmd->opcode;
cmd->resp[1] = 0;
cmd->resp[2] = 0;
cmd->resp[3] = 0;
toshsd_finish_request(host);
return;
}
switch (mmc_resp_type(cmd)) {
case MMC_RSP_NONE:
c |= SD_CMD_RESP_TYPE_NONE;
break;
case MMC_RSP_R1:
c |= SD_CMD_RESP_TYPE_EXT_R1;
break;
case MMC_RSP_R1B:
c |= SD_CMD_RESP_TYPE_EXT_R1B;
break;
case MMC_RSP_R2:
c |= SD_CMD_RESP_TYPE_EXT_R2;
break;
case MMC_RSP_R3:
c |= SD_CMD_RESP_TYPE_EXT_R3;
break;
default:
dev_err(&host->pdev->dev, "Unknown response type %d\n",
mmc_resp_type(cmd));
break;
}
host->cmd = cmd;
if (cmd->opcode == MMC_APP_CMD)
c |= SD_CMD_TYPE_ACMD;
if (cmd->opcode == MMC_GO_IDLE_STATE)
c |= (3 << 8); /* removed from ipaq-asic3.h for some reason */
if (data) {
c |= SD_CMD_DATA_PRESENT;
if (data->blocks > 1) {
iowrite16(SD_STOPINT_AUTO_ISSUE_CMD12,
host->ioaddr + SD_STOPINTERNAL);
c |= SD_CMD_MULTI_BLOCK;
}
if (data->flags & MMC_DATA_READ)
c |= SD_CMD_TRANSFER_READ;
/* MMC_DATA_WRITE does not require a bit to be set */
}
/* Send the command */
iowrite32(cmd->arg, host->ioaddr + SD_ARG0);
iowrite16(c, host->ioaddr + SD_CMD);
}
static void toshsd_start_data(struct toshsd_host *host, struct mmc_data *data)
{
unsigned int flags = SG_MITER_ATOMIC;
dev_dbg(&host->pdev->dev, "setup data transfer: blocksize %08x nr_blocks %d, offset: %08x\n",
data->blksz, data->blocks, data->sg->offset);
host->data = data;
if (data->flags & MMC_DATA_READ)
flags |= SG_MITER_TO_SG;
else
flags |= SG_MITER_FROM_SG;
sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
/* Set transfer length and blocksize */
iowrite16(data->blocks, host->ioaddr + SD_BLOCKCOUNT);
iowrite16(data->blksz, host->ioaddr + SD_CARDXFERDATALEN);
}
/* Process requests from the MMC layer */
static void toshsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct toshsd_host *host = mmc_priv(mmc);
unsigned long flags;
/* abort if card not present */
if (!(ioread16(host->ioaddr + SD_CARDSTATUS) & SD_CARD_PRESENT_0)) {
mrq->cmd->error = -ENOMEDIUM;
mmc_request_done(mmc, mrq);
return;
}
spin_lock_irqsave(&host->lock, flags);
WARN_ON(host->mrq != NULL);
host->mrq = mrq;
if (mrq->data)
toshsd_start_data(host, mrq->data);
toshsd_set_led(host, 1);
toshsd_start_cmd(host, mrq->cmd);
spin_unlock_irqrestore(&host->lock, flags);
}
static void toshsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct toshsd_host *host = mmc_priv(mmc);
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
__toshsd_set_ios(mmc, ios);
spin_unlock_irqrestore(&host->lock, flags);
}
static int toshsd_get_ro(struct mmc_host *mmc)
{
struct toshsd_host *host = mmc_priv(mmc);
/* active low */
return !(ioread16(host->ioaddr + SD_CARDSTATUS) & SD_CARD_WRITE_PROTECT);
}
static int toshsd_get_cd(struct mmc_host *mmc)
{
struct toshsd_host *host = mmc_priv(mmc);
return !!(ioread16(host->ioaddr + SD_CARDSTATUS) & SD_CARD_PRESENT_0);
}
static struct mmc_host_ops toshsd_ops = {
.request = toshsd_request,
.set_ios = toshsd_set_ios,
.get_ro = toshsd_get_ro,
.get_cd = toshsd_get_cd,
};
static void toshsd_powerdown(struct toshsd_host *host)
{
/* mask all interrupts */
iowrite32(0xffffffff, host->ioaddr + SD_INTMASKCARD);
/* disable card clock */
iowrite16(0x000, host->ioaddr + SDIO_BASE + SDIO_CLOCKNWAITCTRL);
iowrite16(0, host->ioaddr + SD_CARDCLOCKCTRL);
/* power down card */
pci_write_config_byte(host->pdev, SD_PCICFG_POWER1, SD_PCICFG_PWR1_OFF);
/* disable clock */
pci_write_config_byte(host->pdev, SD_PCICFG_CLKSTOP, 0);
}
#ifdef CONFIG_PM_SLEEP
static int toshsd_pm_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct toshsd_host *host = pci_get_drvdata(pdev);
toshsd_powerdown(host);
pci_save_state(pdev);
pci_enable_wake(pdev, PCI_D3hot, 0);
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
return 0;
}
static int toshsd_pm_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct toshsd_host *host = pci_get_drvdata(pdev);
int ret;
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
ret = pci_enable_device(pdev);
if (ret)
return ret;
toshsd_init(host);
return 0;
}
#endif /* CONFIG_PM_SLEEP */
static int toshsd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int ret;
struct toshsd_host *host;
struct mmc_host *mmc;
resource_size_t base;
ret = pci_enable_device(pdev);
if (ret)
return ret;
mmc = mmc_alloc_host(sizeof(struct toshsd_host), &pdev->dev);
if (!mmc) {
ret = -ENOMEM;
goto err;
}
host = mmc_priv(mmc);
host->mmc = mmc;
host->pdev = pdev;
pci_set_drvdata(pdev, host);
ret = pci_request_regions(pdev, DRIVER_NAME);
if (ret)
goto free;
host->ioaddr = pci_iomap(pdev, 0, 0);
if (!host->ioaddr) {
ret = -ENOMEM;
goto release;
}
/* Set MMC host parameters */
mmc->ops = &toshsd_ops;
mmc->caps = MMC_CAP_4_BIT_DATA;
mmc->ocr_avail = MMC_VDD_32_33;
mmc->f_min = HCLK / 512;
mmc->f_max = HCLK;
spin_lock_init(&host->lock);
toshsd_init(host);
ret = request_threaded_irq(pdev->irq, toshsd_irq, toshsd_thread_irq,
IRQF_SHARED, DRIVER_NAME, host);
if (ret)
goto unmap;
mmc_add_host(mmc);
base = pci_resource_start(pdev, 0);
dev_dbg(&pdev->dev, "MMIO %pa, IRQ %d\n", &base, pdev->irq);
pm_suspend_ignore_children(&pdev->dev, 1);
return 0;
unmap:
pci_iounmap(pdev, host->ioaddr);
release:
pci_release_regions(pdev);
free:
mmc_free_host(mmc);
pci_set_drvdata(pdev, NULL);
err:
pci_disable_device(pdev);
return ret;
}
static void toshsd_remove(struct pci_dev *pdev)
{
struct toshsd_host *host = pci_get_drvdata(pdev);
mmc_remove_host(host->mmc);
toshsd_powerdown(host);
free_irq(pdev->irq, host);
pci_iounmap(pdev, host->ioaddr);
pci_release_regions(pdev);
mmc_free_host(host->mmc);
pci_set_drvdata(pdev, NULL);
pci_disable_device(pdev);
}
static const struct dev_pm_ops toshsd_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(toshsd_pm_suspend, toshsd_pm_resume)
};
static struct pci_driver toshsd_driver = {
.name = DRIVER_NAME,
.id_table = pci_ids,
.probe = toshsd_probe,
.remove = toshsd_remove,
.driver.pm = &toshsd_pm_ops,
};
static int __init toshsd_drv_init(void)
{
return pci_register_driver(&toshsd_driver);
}
static void __exit toshsd_drv_exit(void)
{
pci_unregister_driver(&toshsd_driver);
}
module_init(toshsd_drv_init);
module_exit(toshsd_drv_exit);
MODULE_AUTHOR("Ondrej Zary, Richard Betts");
MODULE_DESCRIPTION("Toshiba PCI Secure Digital Host Controller Interface driver");
MODULE_LICENSE("GPL");

176
drivers/mmc/host/toshsd.h Normal file
View File

@ -0,0 +1,176 @@
/*
* Toshiba PCI Secure Digital Host Controller Interface driver
*
* Copyright (C) 2014 Ondrej Zary
* Copyright (C) 2007 Richard Betts, All Rights Reserved.
*
* Based on asic3_mmc.c Copyright (c) 2005 SDG Systems, LLC
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*/
#define HCLK 33000000 /* 33 MHz (PCI clock) */
#define SD_PCICFG_CLKSTOP 0x40 /* 0x1f = clock controller, 0 = stop */
#define SD_PCICFG_GATEDCLK 0x41 /* Gated clock */
#define SD_PCICFG_CLKMODE 0x42 /* Control clock of SD controller */
#define SD_PCICFG_PINSTATUS 0x44 /* R/O: read status of SD pins */
#define SD_PCICFG_POWER1 0x48
#define SD_PCICFG_POWER2 0x49
#define SD_PCICFG_POWER3 0x4a
#define SD_PCICFG_CARDDETECT 0x4c
#define SD_PCICFG_SLOTS 0x50 /* R/O: define support slot number */
#define SD_PCICFG_EXTGATECLK1 0xf0 /* Could be used for gated clock */
#define SD_PCICFG_EXTGATECLK2 0xf1 /* Could be used for gated clock */
#define SD_PCICFG_EXTGATECLK3 0xf9 /* Bit 1: double buffer/single buffer */
#define SD_PCICFG_SDLED_ENABLE1 0xfa
#define SD_PCICFG_SDLED_ENABLE2 0xfe
#define SD_PCICFG_CLKMODE_DIV_DISABLE BIT(0)
#define SD_PCICFG_CLKSTOP_ENABLE_ALL 0x1f
#define SD_PCICFG_LED_ENABLE1_START 0x12
#define SD_PCICFG_LED_ENABLE2_START 0x80
#define SD_PCICFG_PWR1_33V 0x08 /* Set for 3.3 volts */
#define SD_PCICFG_PWR1_OFF 0x00 /* Turn off power */
#define SD_PCICFG_PWR2_AUTO 0x02
#define SD_CMD 0x00 /* also for SDIO */
#define SD_ARG0 0x04 /* also for SDIO */
#define SD_ARG1 0x06 /* also for SDIO */
#define SD_STOPINTERNAL 0x08
#define SD_BLOCKCOUNT 0x0a /* also for SDIO */
#define SD_RESPONSE0 0x0c /* also for SDIO */
#define SD_RESPONSE1 0x0e /* also for SDIO */
#define SD_RESPONSE2 0x10 /* also for SDIO */
#define SD_RESPONSE3 0x12 /* also for SDIO */
#define SD_RESPONSE4 0x14 /* also for SDIO */
#define SD_RESPONSE5 0x16 /* also for SDIO */
#define SD_RESPONSE6 0x18 /* also for SDIO */
#define SD_RESPONSE7 0x1a /* also for SDIO */
#define SD_CARDSTATUS 0x1c /* also for SDIO */
#define SD_BUFFERCTRL 0x1e /* also for SDIO */
#define SD_INTMASKCARD 0x20 /* also for SDIO */
#define SD_INTMASKBUFFER 0x22 /* also for SDIO */
#define SD_CARDCLOCKCTRL 0x24
#define SD_CARDXFERDATALEN 0x26 /* also for SDIO */
#define SD_CARDOPTIONSETUP 0x28 /* also for SDIO */
#define SD_ERRORSTATUS0 0x2c /* also for SDIO */
#define SD_ERRORSTATUS1 0x2e /* also for SDIO */
#define SD_DATAPORT 0x30 /* also for SDIO */
#define SD_TRANSACTIONCTRL 0x34 /* also for SDIO */
#define SD_SOFTWARERESET 0xe0 /* also for SDIO */
/* registers above marked "also for SDIO" and all SDIO registers below can be
* accessed at SDIO_BASE + reg address */
#define SDIO_BASE 0x100
#define SDIO_CARDPORTSEL 0x02
#define SDIO_CARDINTCTRL 0x36
#define SDIO_CLOCKNWAITCTRL 0x38
#define SDIO_HOSTINFORMATION 0x3a
#define SDIO_ERRORCTRL 0x3c
#define SDIO_LEDCTRL 0x3e
#define SD_TRANSCTL_SET BIT(8)
#define SD_CARDCLK_DIV_DISABLE BIT(15)
#define SD_CARDCLK_ENABLE_CLOCK BIT(8)
#define SD_CARDCLK_CLK_DIV_512 BIT(7)
#define SD_CARDCLK_CLK_DIV_256 BIT(6)
#define SD_CARDCLK_CLK_DIV_128 BIT(5)
#define SD_CARDCLK_CLK_DIV_64 BIT(4)
#define SD_CARDCLK_CLK_DIV_32 BIT(3)
#define SD_CARDCLK_CLK_DIV_16 BIT(2)
#define SD_CARDCLK_CLK_DIV_8 BIT(1)
#define SD_CARDCLK_CLK_DIV_4 BIT(0)
#define SD_CARDCLK_CLK_DIV_2 0
#define SD_CARDOPT_REQUIRED 0x000e
#define SD_CARDOPT_DATA_RESP_TIMEOUT(x) (((x) & 0x0f) << 4) /* 4 bits */
#define SD_CARDOPT_C2_MODULE_ABSENT BIT(14)
#define SD_CARDOPT_DATA_XFR_WIDTH_1 (1 << 15)
#define SD_CARDOPT_DATA_XFR_WIDTH_4 (0 << 15)
#define SD_CMD_TYPE_CMD (0 << 6)
#define SD_CMD_TYPE_ACMD (1 << 6)
#define SD_CMD_TYPE_AUTHEN (2 << 6)
#define SD_CMD_RESP_TYPE_NONE (3 << 8)
#define SD_CMD_RESP_TYPE_EXT_R1 (4 << 8)
#define SD_CMD_RESP_TYPE_EXT_R1B (5 << 8)
#define SD_CMD_RESP_TYPE_EXT_R2 (6 << 8)
#define SD_CMD_RESP_TYPE_EXT_R3 (7 << 8)
#define SD_CMD_RESP_TYPE_EXT_R6 (4 << 8)
#define SD_CMD_RESP_TYPE_EXT_R7 (4 << 8)
#define SD_CMD_DATA_PRESENT BIT(11)
#define SD_CMD_TRANSFER_READ BIT(12)
#define SD_CMD_MULTI_BLOCK BIT(13)
#define SD_CMD_SECURITY_CMD BIT(14)
#define SD_STOPINT_ISSUE_CMD12 BIT(0)
#define SD_STOPINT_AUTO_ISSUE_CMD12 BIT(8)
#define SD_CARD_RESP_END BIT(0)
#define SD_CARD_RW_END BIT(2)
#define SD_CARD_CARD_REMOVED_0 BIT(3)
#define SD_CARD_CARD_INSERTED_0 BIT(4)
#define SD_CARD_PRESENT_0 BIT(5)
#define SD_CARD_UNK6 BIT(6)
#define SD_CARD_WRITE_PROTECT BIT(7)
#define SD_CARD_CARD_REMOVED_3 BIT(8)
#define SD_CARD_CARD_INSERTED_3 BIT(9)
#define SD_CARD_PRESENT_3 BIT(10)
#define SD_BUF_CMD_INDEX_ERR BIT(16)
#define SD_BUF_CRC_ERR BIT(17)
#define SD_BUF_STOP_BIT_END_ERR BIT(18)
#define SD_BUF_DATA_TIMEOUT BIT(19)
#define SD_BUF_OVERFLOW BIT(20)
#define SD_BUF_UNDERFLOW BIT(21)
#define SD_BUF_CMD_TIMEOUT BIT(22)
#define SD_BUF_UNK7 BIT(23)
#define SD_BUF_READ_ENABLE BIT(24)
#define SD_BUF_WRITE_ENABLE BIT(25)
#define SD_BUF_ILLEGAL_FUNCTION BIT(29)
#define SD_BUF_CMD_BUSY BIT(30)
#define SD_BUF_ILLEGAL_ACCESS BIT(31)
#define SD_ERR0_RESP_CMD_ERR BIT(0)
#define SD_ERR0_RESP_NON_CMD12_END_BIT_ERR BIT(2)
#define SD_ERR0_RESP_CMD12_END_BIT_ERR BIT(3)
#define SD_ERR0_READ_DATA_END_BIT_ERR BIT(4)
#define SD_ERR0_WRITE_CRC_STATUS_END_BIT_ERR BIT(5)
#define SD_ERR0_RESP_NON_CMD12_CRC_ERR BIT(8)
#define SD_ERR0_RESP_CMD12_CRC_ERR BIT(9)
#define SD_ERR0_READ_DATA_CRC_ERR BIT(10)
#define SD_ERR0_WRITE_CMD_CRC_ERR BIT(11)
#define SD_ERR1_NO_CMD_RESP BIT(16)
#define SD_ERR1_TIMEOUT_READ_DATA BIT(20)
#define SD_ERR1_TIMEOUT_CRS_STATUS BIT(21)
#define SD_ERR1_TIMEOUT_CRC_BUSY BIT(22)
#define IRQ_DONT_CARE_BITS (SD_CARD_PRESENT_3 \
| SD_CARD_WRITE_PROTECT \
| SD_CARD_UNK6 \
| SD_CARD_PRESENT_0 \
| SD_BUF_UNK7 \
| SD_BUF_CMD_BUSY)
struct toshsd_host {
struct pci_dev *pdev;
struct mmc_host *mmc;
spinlock_t lock;
struct mmc_request *mrq;/* Current request */
struct mmc_command *cmd;/* Current command */
struct mmc_data *data; /* Current data request */
struct sg_mapping_iter sg_miter; /* for PIO */
void __iomem *ioaddr; /* mapped address */
};

View File

@ -11,6 +11,7 @@
* @detect_pin: GPIO pin wired to the card detect switch
* @wp_pin: GPIO pin wired to the write protect sensor
* @detect_is_active_high: The state of the detect pin when it is active
* @non_removable: The slot is not removable, only detect once
*
* If a given slot is not present on the board, @bus_width should be
* set to 0. The other fields are ignored in this case.
@ -26,6 +27,7 @@ struct mci_slot_pdata {
int detect_pin;
int wp_pin;
bool detect_is_active_high;
bool non_removable;
};
/**

View File

@ -88,6 +88,9 @@ struct mmc_ext_csd {
unsigned int data_tag_unit_size; /* DATA TAG UNIT size */
unsigned int boot_ro_lock; /* ro lock support */
bool boot_ro_lockable;
bool ffu_capable; /* Firmware upgrade support */
#define MMC_FIRMWARE_LEN 8
u8 fwrev[MMC_FIRMWARE_LEN]; /* FW version */
u8 raw_exception_status; /* 54 */
u8 raw_partition_support; /* 160 */
u8 raw_rpmb_size_mult; /* 168 */
@ -509,24 +512,8 @@ static inline int mmc_card_broken_irq_polling(const struct mmc_card *c)
#define mmc_dev_to_card(d) container_of(d, struct mmc_card, dev)
#define mmc_list_to_card(l) container_of(l, struct mmc_card, node)
#define mmc_get_drvdata(c) dev_get_drvdata(&(c)->dev)
#define mmc_set_drvdata(c,d) dev_set_drvdata(&(c)->dev, d)
/*
* MMC device driver (e.g., Flash card, I/O card...)
*/
struct mmc_driver {
struct device_driver drv;
int (*probe)(struct mmc_card *);
void (*remove)(struct mmc_card *);
int (*suspend)(struct mmc_card *);
int (*resume)(struct mmc_card *);
void (*shutdown)(struct mmc_card *);
};
extern int mmc_register_driver(struct mmc_driver *);
extern void mmc_unregister_driver(struct mmc_driver *);
extern int mmc_register_driver(struct device_driver *);
extern void mmc_unregister_driver(struct device_driver *);
extern void mmc_fixup_device(struct mmc_card *card,
const struct mmc_fixup *table);

View File

@ -154,7 +154,8 @@ extern void mmc_start_bkops(struct mmc_card *card, bool from_exception);
extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool,
bool, bool);
extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
extern int mmc_send_tuning(struct mmc_host *host);
extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
#define MMC_ERASE_ARG 0x00000000
#define MMC_SECURE_ERASE_ARG 0x80000000

View File

@ -54,6 +54,7 @@ struct mmc_data;
* transfer is in progress.
* @use_dma: Whether DMA channel is initialized or not.
* @using_dma: Whether DMA is in use for the current transfer.
* @dma_64bit_address: Whether DMA supports 64-bit address mode or not.
* @sg_dma: Bus address of DMA buffer.
* @sg_cpu: Virtual address of DMA buffer.
* @dma_ops: Pointer to platform-specific DMA callbacks.
@ -96,6 +97,7 @@ struct mmc_data;
* @quirks: Set of quirks that apply to specific versions of the IP.
* @irq_flags: The flags to be passed to request_irq.
* @irq: The irq value to be passed to request_irq.
* @sdio_id0: Number of slot0 in the SDIO interrupt registers.
*
* Locking
* =======
@ -135,11 +137,11 @@ struct dw_mci {
struct mmc_command stop_abort;
unsigned int prev_blksz;
unsigned char timing;
struct workqueue_struct *card_workqueue;
/* DMA interface members*/
int use_dma;
int using_dma;
int dma_64bit_address;
dma_addr_t sg_dma;
void *sg_cpu;
@ -154,7 +156,6 @@ struct dw_mci {
u32 stop_cmdr;
u32 dir_status;
struct tasklet_struct tasklet;
struct work_struct card_work;
unsigned long pending_events;
unsigned long completed_events;
enum dw_mci_state state;
@ -193,6 +194,8 @@ struct dw_mci {
bool vqmmc_enabled;
unsigned long irq_flags; /* IRQ flags */
int irq;
int sdio_id0;
};
/* DMA ops for Internal/External DMAC interface */

View File

@ -289,6 +289,7 @@ struct mmc_host {
#define MMC_CAP2_HS400_1_2V (1 << 16) /* Can support HS400 1.2V */
#define MMC_CAP2_HS400 (MMC_CAP2_HS400_1_8V | \
MMC_CAP2_HS400_1_2V)
#define MMC_CAP2_HSX00_1_2V (MMC_CAP2_HS200_1_2V_SDR | MMC_CAP2_HS400_1_2V)
#define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17)
mmc_pm_flag_t pm_caps; /* supported pm features */

View File

@ -296,6 +296,7 @@ struct _mmc_csd {
#define EXT_CSD_SANITIZE_START 165 /* W */
#define EXT_CSD_WR_REL_PARAM 166 /* RO */
#define EXT_CSD_RPMB_MULT 168 /* RO */
#define EXT_CSD_FW_CONFIG 169 /* R/W */
#define EXT_CSD_BOOT_WP 173 /* R/W */
#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */
#define EXT_CSD_PART_CONFIG 179 /* R/W */
@ -332,6 +333,8 @@ struct _mmc_csd {
#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */
#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */
#define EXT_CSD_PWR_CL_DDR_200_360 253 /* RO */
#define EXT_CSD_FIRMWARE_VERSION 254 /* RO, 8 bytes */
#define EXT_CSD_SUPPORTED_MODE 493 /* RO */
#define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */
#define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */
#define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */

View File

@ -100,6 +100,12 @@ struct sdhci_host {
#define SDHCI_QUIRK2_BROKEN_DDR50 (1<<7)
/* Stop command (CMD12) can set Transfer Complete when not using MMC_RSP_BUSY */
#define SDHCI_QUIRK2_STOP_WITH_TC (1<<8)
/* Controller does not support 64-bit DMA */
#define SDHCI_QUIRK2_BROKEN_64_BIT_DMA (1<<9)
/* need clear transfer mode register before send cmd */
#define SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD (1<<10)
/* Capability register bit-63 indicates HS400 support */
#define SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 (1<<11)
int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */
@ -130,6 +136,7 @@ struct sdhci_host {
#define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */
#define SDHCI_SDR104_NEEDS_TUNING (1<<10) /* SDR104/HS200 needs tuning */
#define SDHCI_USING_RETUNING_TIMER (1<<11) /* Host is using a retuning timer for the card */
#define SDHCI_USE_64_BIT_DMA (1<<12) /* Use 64-bit DMA */
unsigned int version; /* SDHCI spec. version */
@ -155,12 +162,19 @@ struct sdhci_host {
int sg_count; /* Mapped sg entries */
u8 *adma_desc; /* ADMA descriptor table */
u8 *align_buffer; /* Bounce buffer */
void *adma_table; /* ADMA descriptor table */
void *align_buffer; /* Bounce buffer */
size_t adma_table_sz; /* ADMA descriptor table size */
size_t align_buffer_sz; /* Bounce buffer size */
dma_addr_t adma_addr; /* Mapped ADMA descr. table */
dma_addr_t align_addr; /* Mapped bounce buffer */
unsigned int desc_sz; /* ADMA descriptor size */
unsigned int align_sz; /* ADMA alignment */
unsigned int align_mask; /* ADMA alignment mask */
struct tasklet_struct finish_tasklet; /* Tasklet structures */
struct timer_list timer; /* Timer for timeouts */

View File

@ -84,8 +84,6 @@ struct sdio_driver {
struct device_driver drv;
};
#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv)
/**
* SDIO_DEVICE - macro used to describe a specific SDIO device
* @vend: the 16 bit manufacturer code

View File

@ -0,0 +1,90 @@
/*
* MMC definitions for OMAP2
*
* Copyright (C) 2006 Nokia Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* struct omap_hsmmc_dev_attr.flags possibilities
*
* OMAP_HSMMC_SUPPORTS_DUAL_VOLT: Some HSMMC controller instances can
* operate with either 1.8Vdc or 3.0Vdc card voltages; this flag
* should be set if this is the case. See for example Section 22.5.3
* "MMC/SD/SDIO1 Bus Voltage Selection" of the OMAP34xx Multimedia
* Device Silicon Revision 3.1.x Revision ZR (July 2011) (SWPU223R).
*
* OMAP_HSMMC_BROKEN_MULTIBLOCK_READ: Multiple-block read transfers
* don't work correctly on some MMC controller instances on some
* OMAP3 SoCs; this flag should be set if this is the case. See
* for example Advisory 2.1.1.128 "MMC: Multiple Block Read
* Operation Issue" in _OMAP3530/3525/3515/3503 Silicon Errata_
* Revision F (October 2010) (SPRZ278F).
*/
#define OMAP_HSMMC_SUPPORTS_DUAL_VOLT BIT(0)
#define OMAP_HSMMC_BROKEN_MULTIBLOCK_READ BIT(1)
#define OMAP_HSMMC_SWAKEUP_MISSING BIT(2)
struct omap_hsmmc_dev_attr {
u8 flags;
};
struct mmc_card;
struct omap_hsmmc_platform_data {
/* back-link to device */
struct device *dev;
/* set if your board has components or wiring that limits the
* maximum frequency on the MMC bus */
unsigned int max_freq;
/* Integrating attributes from the omap_hwmod layer */
u8 controller_flags;
/* Register offset deviation */
u16 reg_offset;
/*
* 4/8 wires and any additional host capabilities
* need to OR'd all capabilities (ref. linux/mmc/host.h)
*/
u32 caps; /* Used for the MMC driver on 2430 and later */
u32 pm_caps; /* PM capabilities of the mmc */
/* switch pin can be for card detect (default) or card cover */
unsigned cover:1;
/* use the internal clock */
unsigned internal_clock:1;
/* nonremovable e.g. eMMC */
unsigned nonremovable:1;
/* eMMC does not handle power off when not in sleep state */
unsigned no_regulator_off_init:1;
/* we can put the features above into this variable */
#define HSMMC_HAS_PBIAS (1 << 0)
#define HSMMC_HAS_UPDATED_RESET (1 << 1)
#define HSMMC_HAS_HSPE_SUPPORT (1 << 2)
unsigned features;
int switch_pin; /* gpio (card detect) */
int gpio_wp; /* gpio (write protect) */
int (*set_power)(struct device *dev, int power_on, int vdd);
void (*remux)(struct device *dev, int power_on);
/* Call back before enabling / disabling regulators */
void (*before_set_reg)(struct device *dev, int power_on, int vdd);
/* Call back after enabling / disabling regulators */
void (*after_set_reg)(struct device *dev, int power_on, int vdd);
/* if we have special card, init it using this callback */
void (*init_card)(struct mmc_card *card);
const char *name;
u32 ocr_mask;
};

View File

@ -1,17 +1,22 @@
#ifndef __MACH_ATMEL_MCI_H
#define __MACH_ATMEL_MCI_H
#ifndef __MMC_ATMEL_MCI_H
#define __MMC_ATMEL_MCI_H
#include <linux/platform_data/dma-atmel.h>
#include <linux/platform_data/dma-dw.h>
/**
* struct mci_dma_data - DMA data for MCI interface
*/
struct mci_dma_data {
struct at_dma_slave sdata;
#ifdef CONFIG_ARM
struct at_dma_slave sdata;
#else
struct dw_dma_slave sdata;
#endif
};
/* accessor macros */
#define slave_data_ptr(s) (&(s)->sdata)
#define find_slave_dev(s) ((s)->sdata.dma_dev)
#endif /* __MACH_ATMEL_MCI_H */
#endif /* __MMC_ATMEL_MCI_H */

View File

@ -10,32 +10,8 @@
#define OMAP_MMC_MAX_SLOTS 2
/*
* struct omap_mmc_dev_attr.flags possibilities
*
* OMAP_HSMMC_SUPPORTS_DUAL_VOLT: Some HSMMC controller instances can
* operate with either 1.8Vdc or 3.0Vdc card voltages; this flag
* should be set if this is the case. See for example Section 22.5.3
* "MMC/SD/SDIO1 Bus Voltage Selection" of the OMAP34xx Multimedia
* Device Silicon Revision 3.1.x Revision ZR (July 2011) (SWPU223R).
*
* OMAP_HSMMC_BROKEN_MULTIBLOCK_READ: Multiple-block read transfers
* don't work correctly on some MMC controller instances on some
* OMAP3 SoCs; this flag should be set if this is the case. See
* for example Advisory 2.1.1.128 "MMC: Multiple Block Read
* Operation Issue" in _OMAP3530/3525/3515/3503 Silicon Errata_
* Revision F (October 2010) (SPRZ278F).
*/
#define OMAP_HSMMC_SUPPORTS_DUAL_VOLT BIT(0)
#define OMAP_HSMMC_BROKEN_MULTIBLOCK_READ BIT(1)
#define OMAP_HSMMC_SWAKEUP_MISSING BIT(2)
struct mmc_card;
struct omap_mmc_dev_attr {
u8 flags;
};
struct omap_mmc_platform_data {
/* back-link to device */
struct device *dev;
@ -106,9 +82,6 @@ struct omap_mmc_platform_data {
unsigned vcc_aux_disable_is_sleep:1;
/* we can put the features above into this variable */
#define HSMMC_HAS_PBIAS (1 << 0)
#define HSMMC_HAS_UPDATED_RESET (1 << 1)
#define HSMMC_HAS_HSPE_SUPPORT (1 << 2)
#define MMC_OMAP7XX (1 << 3)
#define MMC_OMAP15XX (1 << 4)
#define MMC_OMAP16XX (1 << 5)

View File

@ -55,9 +55,4 @@ struct sdhci_pxa_platdata {
unsigned int quirks2;
unsigned int pm_caps;
};
struct sdhci_pxa {
u8 clk_enable;
u8 power_mode;
};
#endif /* _PXA_SDHCI_H_ */