- 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
Родитель b2776bf714 33d73935e4
Коммит f2fb38049c
71 изменённых файлов: 2458 добавлений и 1238 удалений

Просмотреть файл

@ -18,6 +18,10 @@ Required Properties:
specific extensions. specific extensions.
- "samsung,exynos5420-dw-mshc": for controllers with Samsung Exynos5420 - "samsung,exynos5420-dw-mshc": for controllers with Samsung Exynos5420
specific extensions. 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 * 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 unit (ciu) clock. This property is applicable only for Exynos5 SoC's and

Просмотреть файл

@ -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;
};

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -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, * 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. * 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) if (power_on)
omap_mux_write_array(partition, rx51_mmc2_on_mux); omap_mux_write_array(partition, rx51_mmc2_on_mux);
@ -500,7 +500,6 @@ static struct omap2_hsmmc_info mmc[] __initdata = {
.cover_only = true, .cover_only = true,
.gpio_cd = 160, .gpio_cd = 160,
.gpio_wp = -EINVAL, .gpio_wp = -EINVAL,
.power_saving = true,
}, },
{ {
.name = "internal", .name = "internal",
@ -510,7 +509,6 @@ static struct omap2_hsmmc_info mmc[] __initdata = {
.gpio_cd = -EINVAL, .gpio_cd = -EINVAL,
.gpio_wp = -EINVAL, .gpio_wp = -EINVAL,
.nonremovable = true, .nonremovable = true,
.power_saving = true,
.remux = rx51_mmc2_remux, .remux = rx51_mmc2_remux,
}, },
{} /* Terminator */ {} /* Terminator */

Просмотреть файл

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

Просмотреть файл

@ -12,25 +12,18 @@ struct omap2_hsmmc_info {
u8 mmc; /* controller 1/2/3 */ u8 mmc; /* controller 1/2/3 */
u32 caps; /* 4/8 wires and any additional host u32 caps; /* 4/8 wires and any additional host
* capabilities OR'd (ref. linux/mmc/host.h) */ * capabilities OR'd (ref. linux/mmc/host.h) */
u32 pm_caps; /* PM capabilities */
bool transceiver; /* MMC-2 option */ bool transceiver; /* MMC-2 option */
bool ext_clock; /* use external pin for input clock */ bool ext_clock; /* use external pin for input clock */
bool cover_only; /* No card detect - just cover switch */ bool cover_only; /* No card detect - just cover switch */
bool nonremovable; /* Nonremovable e.g. eMMC */ 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 */ bool deferred; /* mmc needs a deferred probe */
int gpio_cd; /* or -EINVAL */ int gpio_cd; /* or -EINVAL */
int gpio_wp; /* or -EINVAL */ int gpio_wp; /* or -EINVAL */
char *name; /* or NULL for default */ char *name; /* or NULL for default */
struct platform_device *pdev; /* mmc controller instance */ struct platform_device *pdev; /* mmc controller instance */
int ocr_mask; /* temporary HACK */ 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 */ /* 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 */ /* init some special card */
void (*init_card)(struct mmc_card *card); void (*init_card)(struct mmc_card *card);
}; };

Просмотреть файл

@ -1,5 +1,3 @@
#include <linux/mmc/host.h>
#include <linux/platform_data/mmc-omap.h>
#define OMAP24XX_NR_MMC 2 #define OMAP24XX_NR_MMC 2
#define OMAP2420_MMC_SIZE OMAP1_MMC_SIZE #define OMAP2420_MMC_SIZE OMAP1_MMC_SIZE
@ -7,14 +5,6 @@
#define OMAP4_MMC_REG_OFFSET 0x100 #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; struct omap_hwmod;
int omap_msdi_reset(struct omap_hwmod *oh); int omap_msdi_reset(struct omap_hwmod *oh);

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -22,6 +22,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/platform_data/gpio-omap.h> #include <linux/platform_data/gpio-omap.h>
#include <linux/platform_data/hsmmc-omap.h>
#include <linux/power/smartreflex.h> #include <linux/power/smartreflex.h>
#include <linux/i2c-omap.h> #include <linux/i2c-omap.h>
@ -39,7 +40,6 @@
#include "prm44xx.h" #include "prm44xx.h"
#include "prm-regbits-44xx.h" #include "prm-regbits-44xx.h"
#include "i2c.h" #include "i2c.h"
#include "mmc.h"
#include "wd_timer.h" #include "wd_timer.h"
/* Base offset for all OMAP4 interrupts external to MPUSS */ /* 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 */ /* 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, .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
}; };

Просмотреть файл

@ -19,6 +19,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/platform_data/gpio-omap.h> #include <linux/platform_data/gpio-omap.h>
#include <linux/platform_data/hsmmc-omap.h>
#include <linux/power/smartreflex.h> #include <linux/power/smartreflex.h>
#include <linux/i2c-omap.h> #include <linux/i2c-omap.h>
@ -33,7 +34,6 @@
#include "cm2_54xx.h" #include "cm2_54xx.h"
#include "prm54xx.h" #include "prm54xx.h"
#include "i2c.h" #include "i2c.h"
#include "mmc.h"
#include "wd_timer.h" #include "wd_timer.h"
/* Base offset for all OMAP5 interrupts external to MPUSS */ /* 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 */ /* 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, .flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
}; };

Просмотреть файл

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

Просмотреть файл

@ -17,7 +17,7 @@
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/usb/atmel_usba_udc.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 <linux/atmel-mci.h>
#include <asm/io.h> #include <asm/io.h>

Просмотреть файл

@ -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 */

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -149,6 +149,14 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
led_trigger_event(host->led, LED_OFF); 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", pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n",
mmc_hostname(host), cmd->opcode, err, mmc_hostname(host), cmd->opcode, err,
cmd->resp[0], cmd->resp[1], 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->error = 0;
mrq->cmd->mrq = mrq; mrq->cmd->mrq = mrq;
if (mrq->sbc) {
mrq->sbc->error = 0;
mrq->sbc->mrq = mrq;
}
if (mrq->data) { if (mrq->data) {
BUG_ON(mrq->data->blksz > host->max_blk_size); BUG_ON(mrq->data->blksz > host->max_blk_size);
BUG_ON(mrq->data->blocks > host->max_blk_count); 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) && 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_R1) ||
(mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1B)) && (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); mmc_start_bkops(host->card, true);
/* prepare the request again */
if (areq)
mmc_pre_req(host, areq->mrq, !host->areq);
}
} }
if (!err && areq) if (!err && areq)
@ -709,27 +731,16 @@ int mmc_read_bkops_status(struct mmc_card *card)
int err; int err;
u8 *ext_csd; 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); 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); mmc_release_host(card->host);
if (err) if (err)
goto out; return err;
card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS]; 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]; card->ext_csd.raw_exception_status = ext_csd[EXT_CSD_EXP_EVENTS_STATUS];
out:
kfree(ext_csd); kfree(ext_csd);
return err; return 0;
} }
EXPORT_SYMBOL(mmc_read_bkops_status); 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); 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 * mmc_vdd_to_ocrbitnum - Convert a voltage to the OCR bit number
* @vdd: voltage (mV) * @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", pr_warn("%s: cannot verify signal voltage switch\n",
mmc_hostname(host)); mmc_hostname(host));
mmc_host_clk_hold(host);
cmd.opcode = SD_SWITCH_VOLTAGE; cmd.opcode = SD_SWITCH_VOLTAGE;
cmd.arg = 0; cmd.arg = 0;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(host, &cmd, 0); err = mmc_wait_for_cmd(host, &cmd, 0);
if (err) if (err)
return err; goto err_command;
if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR)) if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR)) {
return -EIO; err = -EIO;
goto err_command;
mmc_host_clk_hold(host); }
/* /*
* The card should drive cmd and dat[0:3] low immediately * The card should drive cmd and dat[0:3] low immediately
* after the response of cmd11, but wait 1 ms to be sure * after the response of cmd11, but wait 1 ms to be sure
@ -1480,6 +1509,7 @@ power_cycle:
mmc_power_cycle(host, ocr); mmc_power_cycle(host, ocr);
} }
err_command:
mmc_host_clk_release(host); mmc_host_clk_release(host);
return err; return err;
@ -1526,15 +1556,9 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
mmc_host_clk_hold(host); mmc_host_clk_hold(host);
host->ios.vdd = fls(ocr) - 1; 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.power_mode = MMC_POWER_UP;
host->ios.bus_width = MMC_BUS_WIDTH_1; /* Set initial state and call mmc_set_ios */
host->ios.timing = MMC_TIMING_LEGACY; mmc_set_initial_state(host);
mmc_set_ios(host);
/* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */ /* 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) 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.clock = 0;
host->ios.vdd = 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.power_mode = MMC_POWER_OFF;
host->ios.bus_width = MMC_BUS_WIDTH_1; /* Set initial state and call mmc_set_ios */
host->ios.timing = MMC_TIMING_LEGACY; mmc_set_initial_state(host);
mmc_set_ios(host);
/* /*
* Some configurations, such as the 802.11 SDIO card in the OLPC * 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 the reset has happened, then a status command will fail */
if (check) { if (check) {
struct mmc_command cmd = {0}; u32 status;
int err;
cmd.opcode = MMC_SEND_STATUS; if (!mmc_send_status(card, &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) {
mmc_host_clk_release(host); mmc_host_clk_release(host);
return -ENOSYS; return -ENOSYS;
} }
} }
if (mmc_host_is_spi(host)) { /* Set initial state and call mmc_set_ios */
host->ios.chip_select = MMC_CS_HIGH; mmc_set_initial_state(host);
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);
mmc_host_clk_release(host); mmc_host_clk_release(host);

Просмотреть файл

@ -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_up(struct mmc_host *host, u32 ocr);
void mmc_power_off(struct mmc_host *host); void mmc_power_off(struct mmc_host *host);
void mmc_power_cycle(struct mmc_host *host, u32 ocr); 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) static inline void mmc_delay(unsigned int ms)
{ {

Просмотреть файл

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

Просмотреть файл

@ -177,65 +177,6 @@ static int mmc_decode_csd(struct mmc_card *card)
return 0; 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) static void mmc_select_card_type(struct mmc_card *card)
{ {
struct mmc_host *host = card->host; 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. * 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; int err = 0, idx;
unsigned int part_size; 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 */ /* 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]; card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE];
if (card->csd.structure == 3) { 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; 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: out:
return err; 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) 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; return 0;
err = mmc_get_ext_csd(card, &bw_ext_csd); err = mmc_get_ext_csd(card, &bw_ext_csd);
if (err)
if (err || bw_ext_csd == NULL) { return err;
err = -EINVAL;
goto out;
}
/* only compare read only fields */ /* only compare read only fields */
err = !((card->ext_csd.raw_partition_support == 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) if (err)
err = -EINVAL; err = -EINVAL;
out: kfree(bw_ext_csd);
mmc_free_ext_csd(bw_ext_csd);
return err; 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(date, "%02d/%04d\n", card->cid.month, card->cid.year);
MMC_DEV_ATTR(erase_size, "%u\n", card->erase_size << 9); 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(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(hwrev, "0x%x\n", card->cid.hwrev);
MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid); MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name); MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
@ -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(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); 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[] = { static struct attribute *mmc_std_attrs[] = {
&dev_attr_cid.attr, &dev_attr_cid.attr,
&dev_attr_csd.attr, &dev_attr_csd.attr,
@ -742,6 +730,7 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_erase_size.attr, &dev_attr_erase_size.attr,
&dev_attr_preferred_erase_size.attr, &dev_attr_preferred_erase_size.attr,
&dev_attr_fwrev.attr, &dev_attr_fwrev.attr,
&dev_attr_ffu_capable.attr,
&dev_attr_hwrev.attr, &dev_attr_hwrev.attr,
&dev_attr_manfid.attr, &dev_attr_manfid.attr,
&dev_attr_name.attr, &dev_attr_name.attr,
@ -774,14 +763,6 @@ static int __mmc_select_powerclass(struct mmc_card *card,
unsigned int pwrclass_val = 0; unsigned int pwrclass_val = 0;
int err = 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) { switch (1 << host->ios.vdd) {
case MMC_VDD_165_195: case MMC_VDD_165_195:
if (host->ios.clock <= MMC_HIGH_26_MAX_DTR) 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; int err, ddr;
/* Power class selection is supported for versions >= 4.0 */ /* 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; return 0;
bus_width = host->ios.bus_width; 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; unsigned idx, bus_width = 0;
int err = 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))) !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))
return 0; return 0;
@ -998,7 +979,7 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
ext_csd_bits, ext_csd_bits,
card->ext_csd.generic_cmd6_time); card->ext_csd.generic_cmd6_time);
if (err) { 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); mmc_hostname(host), 1 << bus_width);
return err; return err;
} }
@ -1069,7 +1050,7 @@ static int mmc_select_hs400(struct mmc_card *card)
card->ext_csd.generic_cmd6_time, card->ext_csd.generic_cmd6_time,
true, true, true); true, true, true);
if (err) { 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); mmc_hostname(host), err);
return err; return err;
} }
@ -1079,7 +1060,7 @@ static int mmc_select_hs400(struct mmc_card *card)
EXT_CSD_DDR_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8,
card->ext_csd.generic_cmd6_time); card->ext_csd.generic_cmd6_time);
if (err) { 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); mmc_hostname(host), err);
return err; return err;
} }
@ -1089,7 +1070,7 @@ static int mmc_select_hs400(struct mmc_card *card)
card->ext_csd.generic_cmd6_time, card->ext_csd.generic_cmd6_time,
true, true, true); true, true, true);
if (err) { 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); mmc_hostname(host), err);
return err; return err;
} }
@ -1146,8 +1127,7 @@ static int mmc_select_timing(struct mmc_card *card)
{ {
int err = 0; int err = 0;
if ((card->csd.mmca_vsn < CSD_SPEC_VER_4 && if (!mmc_can_ext_csd(card))
card->ext_csd.hs_max_dtr == 0))
goto bus_speed; goto bus_speed;
if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200) 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); mmc_host_clk_release(host);
if (err) if (err)
pr_warn("%s: tuning execution failed\n", pr_err("%s: tuning execution failed\n",
mmc_hostname(host)); mmc_hostname(host));
} }
@ -1252,7 +1232,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
int err; int err;
u32 cid[4]; u32 cid[4];
u32 rocr; u32 rocr;
u8 *ext_csd = NULL;
BUG_ON(!host); BUG_ON(!host);
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
@ -1361,14 +1340,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
} }
if (!oldcard) { if (!oldcard) {
/* /* Read extended CSD. */
* Fetch and process extended CSD. err = mmc_read_ext_csd(card);
*/
err = mmc_get_ext_csd(card, &ext_csd);
if (err)
goto free_card;
err = mmc_read_ext_csd(card, ext_csd);
if (err) if (err)
goto free_card; goto free_card;
@ -1458,18 +1431,18 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
if (mmc_card_hs200(card)) { if (mmc_card_hs200(card)) {
err = mmc_hs200_tuning(card); err = mmc_hs200_tuning(card);
if (err) if (err)
goto err; goto free_card;
err = mmc_select_hs400(card); err = mmc_select_hs400(card);
if (err) if (err)
goto err; goto free_card;
} else if (mmc_card_hs(card)) { } else if (mmc_card_hs(card)) {
/* Select the desired bus width optionally */ /* Select the desired bus width optionally */
err = mmc_select_bus_width(card); err = mmc_select_bus_width(card);
if (!IS_ERR_VALUE(err)) { if (!IS_ERR_VALUE(err)) {
err = mmc_select_hs_ddr(card); err = mmc_select_hs_ddr(card);
if (err) if (err)
goto err; goto free_card;
} }
} }
@ -1545,15 +1518,12 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
if (!oldcard) if (!oldcard)
host->card = card; host->card = card;
mmc_free_ext_csd(ext_csd);
return 0; return 0;
free_card: free_card:
if (!oldcard) if (!oldcard)
mmc_remove_card(card); mmc_remove_card(card);
err: err:
mmc_free_ext_csd(ext_csd);
return err; return err;
} }

Просмотреть файл

@ -264,20 +264,6 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
struct mmc_data data = {0}; struct mmc_data data = {0};
struct scatterlist sg; 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.cmd = &cmd;
mrq.data = &data; mrq.data = &data;
@ -298,7 +284,7 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
data.sg = &sg; data.sg = &sg;
data.sg_len = 1; 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) { 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); mmc_wait_for_req(host, &mrq);
if (is_on_stack) {
memcpy(buf, data_buf, len);
kfree(data_buf);
}
if (cmd.error) if (cmd.error)
return cmd.error; return cmd.error;
if (data.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, return mmc_send_cxd_native(card->host, card->rca << 16,
csd, MMC_SEND_CSD); csd, MMC_SEND_CSD);
csd_tmp = kmalloc(16, GFP_KERNEL); csd_tmp = kzalloc(16, GFP_KERNEL);
if (!csd_tmp) if (!csd_tmp)
return -ENOMEM; return -ENOMEM;
@ -362,7 +343,7 @@ int mmc_send_cid(struct mmc_host *host, u32 *cid)
cid, MMC_SEND_CID); cid, MMC_SEND_CID);
} }
cid_tmp = kmalloc(16, GFP_KERNEL); cid_tmp = kzalloc(16, GFP_KERNEL);
if (!cid_tmp) if (!cid_tmp)
return -ENOMEM; return -ENOMEM;
@ -378,12 +359,35 @@ err:
return ret; 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, int err;
ext_csd, 512); 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) 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); 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 static int
mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode, mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
u8 len) u8 len)
@ -675,3 +748,8 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
return 0; return 0;
} }
int mmc_can_ext_csd(struct mmc_card *card)
{
return (card && card->csd.mmca_vsn > CSD_SPEC_VER_3);
}

Просмотреть файл

@ -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_all_send_cid(struct mmc_host *host, u32 *cid);
int mmc_set_relative_addr(struct mmc_card *card); int mmc_set_relative_addr(struct mmc_card *card);
int mmc_send_csd(struct mmc_card *card, u32 *csd); 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_status(struct mmc_card *card, u32 *status);
int mmc_send_cid(struct mmc_host *host, u32 *cid); 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_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
int mmc_spi_set_crc(struct mmc_host *host, int use_crc); 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_bus_test(struct mmc_card *card, u8 bus_width);
int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status); int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status);
int mmc_can_ext_csd(struct mmc_card *card);
#endif #endif

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -30,13 +30,16 @@
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/platform_data/atmel.h> #include <linux/platform_data/atmel.h>
#include <linux/platform_data/mmc-atmel-mci.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/sdio.h> #include <linux/mmc/sdio.h>
#include <mach/atmel-mci.h>
#include <linux/atmel-mci.h> #include <linux/atmel-mci.h>
#include <linux/atmel_pdc.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/cacheflush.h>
#include <asm/io.h> #include <asm/io.h>
@ -44,6 +47,8 @@
#include "atmel-mci-regs.h" #include "atmel-mci-regs.h"
#define AUTOSUSPEND_DELAY 50
#define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE) #define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE)
#define ATMCI_DMA_THRESHOLD 16 #define ATMCI_DMA_THRESHOLD 16
@ -386,20 +391,19 @@ static int atmci_regs_show(struct seq_file *s, void *v)
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
pm_runtime_get_sync(&host->pdev->dev);
/* /*
* Grab a more or less consistent snapshot. Note that we're * Grab a more or less consistent snapshot. Note that we're
* not disabling interrupts, so IMR and SR may not be * not disabling interrupts, so IMR and SR may not be
* consistent. * consistent.
*/ */
ret = clk_prepare_enable(host->mck);
if (ret)
goto out;
spin_lock_bh(&host->lock); spin_lock_bh(&host->lock);
memcpy_fromio(buf, host->regs, ATMCI_REGS_SIZE); memcpy_fromio(buf, host->regs, ATMCI_REGS_SIZE);
spin_unlock_bh(&host->lock); 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 ", seq_printf(s, "MR:\t0x%08x%s%s ",
buf[ATMCI_MR / 4], buf[ATMCI_MR / 4],
@ -449,7 +453,6 @@ static int atmci_regs_show(struct seq_file *s, void *v)
val & ATMCI_CFG_LSYNC ? " LSYNC" : ""); val & ATMCI_CFG_LSYNC ? " LSYNC" : "");
} }
out:
kfree(buf); kfree(buf);
return ret; return ret;
@ -560,6 +563,9 @@ atmci_of_init(struct platform_device *pdev)
pdata->slot[slot_id].detect_is_active_high = pdata->slot[slot_id].detect_is_active_high =
of_property_read_bool(cnp, "cd-inverted"); 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 = pdata->slot[slot_id].wp_pin =
of_get_named_gpio(cnp, "wp-gpios", 0); 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); WARN_ON(slot->mrq);
dev_dbg(&host->pdev->dev, "MRQ: cmd %u\n", mrq->cmd->opcode); 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 * We may "know" the card is gone even though there's still an
* electrical connection. If so, we really need to communicate * 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_slot *slot = mmc_priv(mmc);
struct atmel_mci *host = slot->host; struct atmel_mci *host = slot->host;
unsigned int i; unsigned int i;
bool unprepare_clk;
pm_runtime_get_sync(&host->pdev->dev);
slot->sdc_reg &= ~ATMCI_SDCBUS_MASK; slot->sdc_reg &= ~ATMCI_SDCBUS_MASK;
switch (ios->bus_width) { 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; unsigned int clock_min = ~0U;
u32 clkdiv; u32 clkdiv;
clk_prepare(host->mck);
unprepare_clk = true;
spin_lock_bh(&host->lock); spin_lock_bh(&host->lock);
if (!host->mode_reg) { 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_SWRST);
atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN);
if (host->caps.has_cfg_reg) if (host->caps.has_cfg_reg)
@ -1371,8 +1375,6 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
} else { } else {
bool any_slot_active = false; bool any_slot_active = false;
unprepare_clk = false;
spin_lock_bh(&host->lock); spin_lock_bh(&host->lock);
slot->clock = 0; slot->clock = 0;
for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { 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); atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS);
if (host->mode_reg) { if (host->mode_reg) {
atmci_readl(host, ATMCI_MR); atmci_readl(host, ATMCI_MR);
clk_disable(host->mck);
unprepare_clk = true;
} }
host->mode_reg = 0; host->mode_reg = 0;
} }
spin_unlock_bh(&host->lock); spin_unlock_bh(&host->lock);
} }
if (unprepare_clk)
clk_unprepare(host->mck);
switch (ios->power_mode) { switch (ios->power_mode) {
case MMC_POWER_OFF: case MMC_POWER_OFF:
if (!IS_ERR(mmc->supply.vmmc)) if (!IS_ERR(mmc->supply.vmmc))
@ -1421,6 +1418,9 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
*/ */
break; 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) 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); spin_unlock(&host->lock);
mmc_request_done(prev_mmc, mrq); mmc_request_done(prev_mmc, mrq);
spin_lock(&host->lock); 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, 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; 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, struct mci_slot_pdata *slot_data, unsigned int id,
u32 sdc_reg, u32 sdio_irq) 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)) if (!gpio_is_valid(slot->detect_pin)) {
mmc->caps |= MMC_CAP_NEEDS_POLL; 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 (gpio_is_valid(slot->wp_pin)) {
if (devm_gpio_request(&host->pdev->dev, 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); 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; host->dma.chan = dma_request_slave_channel_reason(&host->pdev->dev,
struct mci_dma_data *sl; "rxtx");
if (IS_ERR(host->dma.chan))
return PTR_ERR(host->dma.chan);
if (!sl_pdata) dev_info(&host->pdev->dev, "using %s for DMA transfers\n",
return false; dma_chan_name(host->dma.chan));
sl = sl_pdata->dma_slave; host->dma_conf.src_addr = host->mapbase + ATMCI_RDR;
if (sl && find_slave_dev(sl) == chan->device->dev) { host->dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
chan->private = slave_data_ptr(sl); host->dma_conf.src_maxburst = 1;
return true; host->dma_conf.dst_addr = host->mapbase + ATMCI_TDR;
} else { host->dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
return false; host->dma_conf.dst_maxburst = 1;
} host->dma_conf.device_fc = false;
}
static bool atmci_configure_dma(struct atmel_mci *host) return 0;
{
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;
}
} }
/* /*
@ -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 * HSMCI provides DMA support and a new config register but no more supports
* PDC. * PDC.
*/ */
static void __init atmci_get_cap(struct atmel_mci *host) static void atmci_get_cap(struct atmel_mci *host)
{ {
unsigned int version; 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 mci_platform_data *pdata;
struct atmel_mci *host; 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); atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);
host->bus_hz = clk_get_rate(host->mck); host->bus_hz = clk_get_rate(host->mck);
clk_disable_unprepare(host->mck);
host->mapbase = regs->start; host->mapbase = regs->start;
tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host); tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host);
ret = request_irq(irq, atmci_interrupt, 0, dev_name(&pdev->dev), host); ret = request_irq(irq, atmci_interrupt, 0, dev_name(&pdev->dev), host);
if (ret) if (ret) {
clk_disable_unprepare(host->mck);
return ret; return ret;
}
/* Get MCI capabilities and set operations according to it */ /* Get MCI capabilities and set operations according to it */
atmci_get_cap(host); 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->prepare_data = &atmci_prepare_data_dma;
host->submit_data = &atmci_submit_data_dma; host->submit_data = &atmci_submit_data_dma;
host->stop_transfer = &atmci_stop_transfer_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); 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 */ /* We need at least one slot to succeed */
nr_slots = 0; nr_slots = 0;
ret = -ENODEV; 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", "Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
host->mapbase, irq, nr_slots); host->mapbase, irq, nr_slots);
pm_runtime_mark_last_busy(&host->pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
return 0; return 0;
err_dma_alloc: err_dma_alloc:
@ -2499,18 +2489,26 @@ err_dma_alloc:
atmci_cleanup_slot(host->slot[i], i); atmci_cleanup_slot(host->slot[i], i);
} }
err_init_slot: err_init_slot:
clk_disable_unprepare(host->mck);
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
del_timer_sync(&host->timer); del_timer_sync(&host->timer);
if (host->dma.chan) if (!IS_ERR(host->dma.chan))
dma_release_channel(host->dma.chan); dma_release_channel(host->dma.chan);
err_dma_probe_defer:
free_irq(irq, host); free_irq(irq, host);
return ret; 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); struct atmel_mci *host = platform_get_drvdata(pdev);
unsigned int i; unsigned int i;
pm_runtime_get_sync(&pdev->dev);
if (host->buffer) if (host->buffer)
dma_free_coherent(&pdev->dev, host->buf_size, dma_free_coherent(&pdev->dev, host->buf_size,
host->buffer, host->buf_phys_addr); 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); atmci_cleanup_slot(host->slot[i], i);
} }
clk_prepare_enable(host->mck);
atmci_writel(host, ATMCI_IDR, ~0UL); atmci_writel(host, ATMCI_IDR, ~0UL);
atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS); atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS);
atmci_readl(host, ATMCI_SR); atmci_readl(host, ATMCI_SR);
clk_disable_unprepare(host->mck);
del_timer_sync(&host->timer); del_timer_sync(&host->timer);
if (host->dma.chan) if (!IS_ERR(host->dma.chan))
dma_release_channel(host->dma.chan); dma_release_channel(host->dma.chan);
free_irq(platform_get_irq(pdev, 0), host); 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; 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 = { static struct platform_driver atmci_driver = {
.remove = __exit_p(atmci_remove), .probe = atmci_probe,
.remove = atmci_remove,
.driver = { .driver = {
.name = "atmel_mci", .name = "atmel_mci",
.of_match_table = of_match_ptr(atmci_dt_ids), .of_match_table = of_match_ptr(atmci_dt_ids),
.pm = &atmci_dev_pm_ops,
}, },
}; };
module_platform_driver(atmci_driver);
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_DESCRIPTION("Atmel Multimedia Card Interface driver"); MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver");
MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");

Просмотреть файл

@ -25,6 +25,7 @@
#define NUM_PINS(x) (x + 2) #define NUM_PINS(x) (x + 2)
#define SDMMC_CLKSEL 0x09C #define SDMMC_CLKSEL 0x09C
#define SDMMC_CLKSEL64 0x0A8
#define SDMMC_CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0) #define SDMMC_CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0)
#define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16) #define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16)
#define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24) #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_EXYNOS5250,
DW_MCI_TYPE_EXYNOS5420, DW_MCI_TYPE_EXYNOS5420,
DW_MCI_TYPE_EXYNOS5420_SMU, DW_MCI_TYPE_EXYNOS5420_SMU,
DW_MCI_TYPE_EXYNOS7,
DW_MCI_TYPE_EXYNOS7_SMU,
}; };
/* Exynos implementation specific driver private data */ /* Exynos implementation specific driver private data */
@ -95,6 +98,12 @@ static struct dw_mci_exynos_compatible {
}, { }, {
.compatible = "samsung,exynos5420-dw-mshc-smu", .compatible = "samsung,exynos5420-dw-mshc-smu",
.ctrl_type = DW_MCI_TYPE_EXYNOS5420_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; 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, MPSBEGIN0, 0);
mci_writel(host, MPSEND0, DWMCI_BLOCK_NUM); mci_writel(host, MPSEND0, DWMCI_BLOCK_NUM);
mci_writel(host, MPSCTRL0, DWMCI_MPSCTRL_SECURE_WRITE_BIT | 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) static int dw_mci_exynos_resume_noirq(struct device *dev)
{ {
struct dw_mci *host = dev_get_drvdata(dev); struct dw_mci *host = dev_get_drvdata(dev);
struct dw_mci_exynos_priv_data *priv = host->priv;
u32 clksel; u32 clksel;
clksel = mci_readl(host, CLKSEL); if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
if (clksel & SDMMC_CLKSEL_WAKEUP_INT) priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
mci_writel(host, CLKSEL, clksel); 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; 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) 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 * Exynos4412 and Exynos5250 extends the use of CMD register with the
* use of bit 29 (which is reserved on standard MSHC controllers) for * 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 * HOLD register should be bypassed in case there is no phase shift
* applied on CMD/DATA that is sent to the card. * applied on CMD/DATA that is sent to the card.
*/ */
if (SDMMC_CLKSEL_GET_DRV_WD3(mci_readl(host, CLKSEL))) if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
*cmdr |= SDMMC_CMD_USE_HOLD_REG; 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) 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; u8 div = priv->ciu_div + 1;
if (ios->timing == MMC_TIMING_MMC_DDR52) { 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 */ /* Should be double rate for DDR mode */
if (ios->bus_width == MMC_BUS_WIDTH_8) if (ios->bus_width == MMC_BUS_WIDTH_8)
wanted <<= 1; wanted <<= 1;
} else { } 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 */ /* 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) 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) static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)
{ {
u32 clksel; 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); 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) static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
{ {
struct dw_mci_exynos_priv_data *priv = host->priv;
u32 clksel; u32 clksel;
u8 sample; 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; sample = (clksel + 1) & 0x7;
clksel = (clksel & ~0x7) | sample; 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; return sample;
} }
@ -411,6 +472,10 @@ static const struct of_device_id dw_mci_exynos_match[] = {
.data = &exynos_drv_data, }, .data = &exynos_drv_data, },
{ .compatible = "samsung,exynos5420-dw-mshc-smu", { .compatible = "samsung,exynos5420-dw-mshc-smu",
.data = &exynos_drv_data, }, .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); MODULE_DEVICE_TABLE(of, dw_mci_exynos_match);

Просмотреть файл

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

Просмотреть файл

@ -37,6 +37,9 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
unsigned int cclkin; unsigned int cclkin;
u32 bus_hz; u32 bus_hz;
if (ios->clock == 0)
return;
/* /*
* cclkin: source clock of mmc controller * cclkin: source clock of mmc controller
* bus_hz: card interface clock generated by CLKGEN * 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 = { static const struct dw_mci_drv_data rk2928_drv_data = {
.prepare_command = dw_mci_rockchip_prepare_command, .prepare_command = dw_mci_rockchip_prepare_command,
.init = dw_mci_rockchip_init,
}; };
static const struct dw_mci_drv_data rk3288_drv_data = { static const struct dw_mci_drv_data rk3288_drv_data = {
.prepare_command = dw_mci_rockchip_prepare_command, .prepare_command = dw_mci_rockchip_prepare_command,
.set_ios = dw_mci_rk3288_set_ios, .set_ios = dw_mci_rk3288_set_ios,
.setup_clock = dw_mci_rk3288_setup_clock, .setup_clock = dw_mci_rk3288_setup_clock,
.init = dw_mci_rockchip_init,
}; };
static const struct of_device_id dw_mci_rockchip_match[] = { static const struct of_device_id dw_mci_rockchip_match[] = {

Просмотреть файл

@ -34,7 +34,6 @@
#include <linux/mmc/dw_mmc.h> #include <linux/mmc/dw_mmc.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/workqueue.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/mmc/slot-gpio.h> #include <linux/mmc/slot-gpio.h>
@ -62,6 +61,24 @@
SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \ SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \
SDMMC_IDMAC_INT_TI) 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 { struct idmac_desc {
u32 des0; /* Control Descriptor */ u32 des0; /* Control Descriptor */
#define IDMAC_DES0_DIC BIT(1) #define IDMAC_DES0_DIC BIT(1)
@ -83,6 +100,7 @@ struct idmac_desc {
#endif /* CONFIG_MMC_DW_IDMAC */ #endif /* CONFIG_MMC_DW_IDMAC */
static bool dw_mci_reset(struct dw_mci *host); 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) #if defined(CONFIG_DEBUG_FS)
static int dw_mci_req_show(struct seq_file *s, void *v) 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) unsigned int sg_len)
{ {
int i; 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++) { for (i = 0; i < sg_len; i++, desc++) {
unsigned int length = sg_dma_len(&data->sg[i]); unsigned int length = sg_dma_len(&data->sg[i]);
u32 mem_addr = sg_dma_address(&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 */ /* Physical address to DMA to/from */
IDMAC_SET_BUFFER1_SIZE(desc, length); desc->des4 = mem_addr & 0xffffffff;
desc->des5 = mem_addr >> 32;
}
/* Physical address to DMA to/from */ /* Set first descriptor */
desc->des2 = mem_addr; 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(); 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); 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 */ /* Select IDMAC interface */
temp = mci_readl(host, CTRL); temp = mci_readl(host, CTRL);
temp |= SDMMC_CTRL_USE_IDMAC; 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) static int dw_mci_idmac_init(struct dw_mci *host)
{ {
struct idmac_desc *p;
int i; int i;
/* Number of descriptors in the ring buffer */ if (host->dma_64bit_address == 1) {
host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc); 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 */ /* Forward link the descriptor list */
for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++) for (i = 0, p = host->sg_cpu; i < host->ring_size - 1;
p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 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->des7 = (u64)(host->sg_dma +
p->des3 = host->sg_dma; (sizeof(struct idmac_desc_64addr) *
p->des0 = IDMAC_DES0_ER; (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); dw_mci_idmac_reset(host);
/* Mask out interrupts - get Tx & Rx complete only */ if (host->dma_64bit_address == 1) {
mci_writel(host, IDSTS, IDMAC_INT_CLR); /* Mask out interrupts - get Tx & Rx complete only */
mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI | mci_writel(host, IDSTS64, IDMAC_INT_CLR);
SDMMC_IDMAC_INT_TI); 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; 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)); 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 && if (host->timing != MMC_TIMING_MMC_HS200 &&
host->timing != MMC_TIMING_UHS_SDR104) host->timing != MMC_TIMING_UHS_SDR104)
goto disable; 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 */ /* enable clock; only low power if no SDIO */
clk_en_a = SDMMC_CLKEN_ENABLE << slot->id; 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; clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id;
mci_writel(host, CLKENA, clk_en_a); 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); ret = regulator_set_voltage(mmc->supply.vqmmc, min_uv, max_uv);
if (ret) { if (ret) {
dev_err(&mmc->class_dev, dev_dbg(&mmc->class_dev,
"Regulator set error %d: %d - %d\n", "Regulator set error %d: %d - %d\n",
ret, min_uv, max_uv); ret, min_uv, max_uv);
return ret; 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); dw_mci_disable_low_power(slot);
mci_writel(host, INTMASK, mci_writel(host, INTMASK,
(int_mask | SDMMC_INT_SDIO(slot->id))); (int_mask | SDMMC_INT_SDIO(slot->sdio_id)));
} else { } else {
mci_writel(host, INTMASK, 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); 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) static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
{ {
struct dw_mci *host = 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) { if (pending & SDMMC_INT_CD) {
mci_writel(host, RINTSTS, 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 */ /* Handle SDIO Interrupts */
for (i = 0; i < host->num_slots; i++) { for (i = 0; i < host->num_slots; i++) {
struct dw_mci_slot *slot = host->slot[i]; struct dw_mci_slot *slot = host->slot[i];
if (pending & SDMMC_INT_SDIO(i)) { if (pending & SDMMC_INT_SDIO(slot->sdio_id)) {
mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i)); mci_writel(host, RINTSTS,
SDMMC_INT_SDIO(slot->sdio_id));
mmc_signal_sdio_irq(slot->mmc); 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 #ifdef CONFIG_MMC_DW_IDMAC
/* Handle DMA interrupts */ /* Handle DMA interrupts */
pending = mci_readl(host, IDSTS); if (host->dma_64bit_address == 1) {
if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) { pending = mci_readl(host, IDSTS64);
mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI); if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI); mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_TI |
host->dma_ops->complete(host); 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 #endif
return IRQ_HANDLED; 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 #ifdef CONFIG_OF
/* given a slot id, find out the device node representing that slot */ /* 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) 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 = mmc_priv(mmc);
slot->id = id; slot->id = id;
slot->sdio_id = host->sdio_id0 + id;
slot->mmc = mmc; slot->mmc = mmc;
slot->host = host; slot->host = host;
host->slot[id] = slot; 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); dw_mci_init_debugfs(slot);
#endif #endif
/* Card initially undetected */
slot->last_detect_state = 0;
return 0; return 0;
err_host_allocated: 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) 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 */ /* Alloc memory for sg translation */
host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE, host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,
&host->sg_dma, GFP_KERNEL); &host->sg_dma, GFP_KERNEL);
@ -2672,17 +2740,10 @@ int dw_mci_probe(struct dw_mci *host)
host->data_offset = DATA_240A_OFFSET; host->data_offset = DATA_240A_OFFSET;
tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host); 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, ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt,
host->irq_flags, "dw-mci", host); host->irq_flags, "dw-mci", host);
if (ret) if (ret)
goto err_workqueue; goto err_dmaunmap;
if (host->pdata->num_slots) if (host->pdata->num_slots)
host->num_slots = host->pdata->num_slots; host->num_slots = host->pdata->num_slots;
@ -2718,7 +2779,7 @@ int dw_mci_probe(struct dw_mci *host)
} else { } else {
dev_dbg(host->dev, "attempted to initialize %d slots, " dev_dbg(host->dev, "attempted to initialize %d slots, "
"but failed on all\n", host->num_slots); "but failed on all\n", host->num_slots);
goto err_workqueue; goto err_dmaunmap;
} }
if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
@ -2726,9 +2787,6 @@ int dw_mci_probe(struct dw_mci *host)
return 0; return 0;
err_workqueue:
destroy_workqueue(host->card_workqueue);
err_dmaunmap: err_dmaunmap:
if (host->use_dma && host->dma_ops->exit) if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host); 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, CLKENA, 0);
mci_writel(host, CLKSRC, 0); mci_writel(host, CLKSRC, 0);
destroy_workqueue(host->card_workqueue);
if (host->use_dma && host->dma_ops->exit) if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host); host->dma_ops->exit(host);

Просмотреть файл

@ -55,6 +55,17 @@
#define SDMMC_BUFADDR 0x098 #define SDMMC_BUFADDR 0x098
#define SDMMC_CDTHRCTL 0x100 #define SDMMC_CDTHRCTL 0x100
#define SDMMC_DATA(x) (x) #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 * Data offset is difference according to Version
@ -214,7 +225,7 @@ extern int dw_mci_resume(struct dw_mci *host);
* with CONFIG_MMC_CLKGATE. * with CONFIG_MMC_CLKGATE.
* @flags: Random state bits associated with the slot. * @flags: Random state bits associated with the slot.
* @id: Number of this 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 dw_mci_slot {
struct mmc_host *mmc; struct mmc_host *mmc;
@ -234,7 +245,7 @@ struct dw_mci_slot {
#define DW_MMC_CARD_PRESENT 0 #define DW_MMC_CARD_PRESENT 0
#define DW_MMC_CARD_NEED_INIT 1 #define DW_MMC_CARD_NEED_INIT 1
int id; int id;
int last_detect_state; int sdio_id;
}; };
struct dw_mci_tuning_data { struct dw_mci_tuning_data {

Просмотреть файл

@ -736,8 +736,15 @@ static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq,
chan = host->dma_tx_channel; chan = host->dma_tx_channel;
dmaengine_terminate_all(chan); 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_desc = NULL;
next->dma_chan = NULL; next->dma_chan = NULL;
data->host_cookie = 0;
} }
} }

Просмотреть файл

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

Просмотреть файл

@ -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_COUNT, data->blocks);
mvsd_write(MVSD_BLK_SIZE, data->blksz); 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 * We cannot do DMA on a buffer which offset or size
* is not aligned on a 4-byte boundary. * 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_size = data->blocks * data->blksz;
host->pio_ptr = sg_virt(data->sg); host->pio_ptr = sg_virt(data->sg);

Просмотреть файл

@ -373,13 +373,9 @@ static void mxcmci_dma_callback(void *data)
del_timer(&host->watchdog); del_timer(&host->watchdog);
stat = mxcmci_readl(host, MMC_REG_STATUS); 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); 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); 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; sdio_irq = (stat & STATUS_SDIO_INT_ACTIVE) && host->use_sdio;
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
if (mxcmci_use_dma(host) && if (mxcmci_use_dma(host) && (stat & (STATUS_WRITE_OP_DONE)))
(stat & (STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE))) mxcmci_writel(host, STATUS_WRITE_OP_DONE, MMC_REG_STATUS);
mxcmci_writel(host, STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE,
MMC_REG_STATUS);
if (sdio_irq) { if (sdio_irq) {
mxcmci_writel(host, STATUS_SDIO_INT_ACTIVE, MMC_REG_STATUS); 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) if (stat & STATUS_END_CMD_RESP)
mxcmci_cmd_done(host, stat); mxcmci_cmd_done(host, stat);
if (mxcmci_use_dma(host) && if (mxcmci_use_dma(host) && (stat & STATUS_WRITE_OP_DONE)) {
(stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE))) {
del_timer(&host->watchdog); del_timer(&host->watchdog);
mxcmci_data_done(host, stat); mxcmci_data_done(host, stat);
} }
@ -1084,12 +1077,14 @@ static int mxcmci_probe(struct platform_device *pdev)
dat3_card_detect = true; dat3_card_detect = true;
ret = mmc_regulator_get_supply(mmc); ret = mmc_regulator_get_supply(mmc);
if (ret) { if (ret == -EPROBE_DEFER)
if (pdata && ret != -EPROBE_DEFER) goto out_free;
mmc->ocr_avail = pdata->ocr_avail ? :
MMC_VDD_32_33 | MMC_VDD_33_34; if (!mmc->ocr_avail) {
if (pdata && pdata->ocr_avail)
mmc->ocr_avail = pdata->ocr_avail;
else else
goto out_free; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
} }
if (dat3_card_detect) if (dat3_card_detect)

Просмотреть файл

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

Просмотреть файл

@ -42,7 +42,7 @@
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.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 */ /* OMAP HSMMC Host Controller Registers */
#define OMAP_HSMMC_SYSSTATUS 0x0014 #define OMAP_HSMMC_SYSSTATUS 0x0014
@ -155,7 +155,7 @@
* omap.c controller driver. Luckily this is not currently done on any known * omap.c controller driver. Luckily this is not currently done on any known
* omap_hsmmc.c device. * 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 * MMC Host controller read/write API's
@ -207,7 +207,6 @@ struct omap_hsmmc_host {
int use_dma, dma_ch; int use_dma, dma_ch;
struct dma_chan *tx_chan; struct dma_chan *tx_chan;
struct dma_chan *rx_chan; struct dma_chan *rx_chan;
int slot_id;
int response_busy; int response_busy;
int context_loss; int context_loss;
int protect_card; int protect_card;
@ -220,7 +219,26 @@ struct omap_hsmmc_host {
#define HSMMC_SDIO_IRQ_ENABLED (1 << 1) /* SDIO irq enabled */ #define HSMMC_SDIO_IRQ_ENABLED (1 << 1) /* SDIO irq enabled */
#define HSMMC_WAKE_IRQ_ENABLED (1 << 2) #define HSMMC_WAKE_IRQ_ENABLED (1 << 2)
struct omap_hsmmc_next next_data; 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 { 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 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_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 */ /* 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_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 */ /* 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_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 */ /* 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 #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_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; 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_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; return 0;
} }
@ -286,8 +302,7 @@ static int omap_hsmmc_resume_cdirq(struct device *dev, int slot)
#ifdef CONFIG_REGULATOR #ifdef CONFIG_REGULATOR
static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on, static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd)
int vdd)
{ {
struct omap_hsmmc_host *host = struct omap_hsmmc_host *host =
platform_get_drvdata(to_platform_device(dev)); 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) if (!host->vcc)
return 0; return 0;
if (mmc_slot(host).before_set_reg) if (mmc_pdata(host)->before_set_reg)
mmc_slot(host).before_set_reg(dev, slot, power_on, vdd); mmc_pdata(host)->before_set_reg(dev, power_on, vdd);
if (host->pbias) { if (host->pbias) {
if (host->pbias_enabled == 1) { 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) if (mmc_pdata(host)->after_set_reg)
mmc_slot(host).after_set_reg(dev, slot, power_on, vdd); mmc_pdata(host)->after_set_reg(dev, power_on, vdd);
error_set_power: error_set_power:
return ret; return ret;
@ -383,18 +398,18 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
} else { } else {
host->vcc = reg; host->vcc = reg;
ocr_value = mmc_regulator_get_ocrmask(reg); ocr_value = mmc_regulator_get_ocrmask(reg);
if (!mmc_slot(host).ocr_mask) { if (!mmc_pdata(host)->ocr_mask) {
mmc_slot(host).ocr_mask = ocr_value; mmc_pdata(host)->ocr_mask = ocr_value;
} else { } 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", dev_err(host->dev, "ocrmask %x is not supported\n",
mmc_slot(host).ocr_mask); mmc_pdata(host)->ocr_mask);
mmc_slot(host).ocr_mask = 0; mmc_pdata(host)->ocr_mask = 0;
return -EINVAL; return -EINVAL;
} }
} }
} }
mmc_slot(host).set_power = omap_hsmmc_set_power; mmc_pdata(host)->set_power = omap_hsmmc_set_power;
/* Allow an aux regulator */ /* Allow an aux regulator */
reg = devm_regulator_get_optional(host->dev, "vmmc_aux"); 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; host->pbias = IS_ERR(reg) ? NULL : reg;
/* For eMMC do not power off when not in sleep state */ /* 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; return 0;
/* /*
* To disable boot_on regulator, enable regulator * 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) || if ((host->vcc && regulator_is_enabled(host->vcc) > 0) ||
(host->vcc_aux && regulator_is_enabled(host->vcc_aux))) { (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_pdata(host)->set_power(host->dev, 1, vdd);
mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0); mmc_pdata(host)->set_power(host->dev, 0, 0);
} }
return 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) 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) static inline int omap_hsmmc_have_reg(void)
@ -449,55 +464,59 @@ static inline int omap_hsmmc_have_reg(void)
#endif #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; int ret;
if (gpio_is_valid(pdata->slots[0].switch_pin)) { if (gpio_is_valid(pdata->switch_pin)) {
if (pdata->slots[0].cover) if (pdata->cover)
pdata->slots[0].get_cover_state = host->get_cover_state =
omap_hsmmc_get_cover_state; omap_hsmmc_get_cover_state;
else else
pdata->slots[0].card_detect = omap_hsmmc_card_detect; host->card_detect = omap_hsmmc_card_detect;
pdata->slots[0].card_detect_irq = host->card_detect_irq =
gpio_to_irq(pdata->slots[0].switch_pin); gpio_to_irq(pdata->switch_pin);
ret = gpio_request(pdata->slots[0].switch_pin, "mmc_cd"); ret = gpio_request(pdata->switch_pin, "mmc_cd");
if (ret) if (ret)
return ret; return ret;
ret = gpio_direction_input(pdata->slots[0].switch_pin); ret = gpio_direction_input(pdata->switch_pin);
if (ret) if (ret)
goto err_free_sp; goto err_free_sp;
} else } else {
pdata->slots[0].switch_pin = -EINVAL; pdata->switch_pin = -EINVAL;
}
if (gpio_is_valid(pdata->slots[0].gpio_wp)) { if (gpio_is_valid(pdata->gpio_wp)) {
pdata->slots[0].get_ro = omap_hsmmc_get_wp; host->get_ro = omap_hsmmc_get_wp;
ret = gpio_request(pdata->slots[0].gpio_wp, "mmc_wp"); ret = gpio_request(pdata->gpio_wp, "mmc_wp");
if (ret) if (ret)
goto err_free_cd; goto err_free_cd;
ret = gpio_direction_input(pdata->slots[0].gpio_wp); ret = gpio_direction_input(pdata->gpio_wp);
if (ret) if (ret)
goto err_free_wp; goto err_free_wp;
} else } else {
pdata->slots[0].gpio_wp = -EINVAL; pdata->gpio_wp = -EINVAL;
}
return 0; return 0;
err_free_wp: err_free_wp:
gpio_free(pdata->slots[0].gpio_wp); gpio_free(pdata->gpio_wp);
err_free_cd: err_free_cd:
if (gpio_is_valid(pdata->slots[0].switch_pin)) if (gpio_is_valid(pdata->switch_pin))
err_free_sp: err_free_sp:
gpio_free(pdata->slots[0].switch_pin); gpio_free(pdata->switch_pin);
return ret; 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)) if (gpio_is_valid(pdata->gpio_wp))
gpio_free(pdata->slots[0].gpio_wp); gpio_free(pdata->gpio_wp);
if (gpio_is_valid(pdata->slots[0].switch_pin)) if (gpio_is_valid(pdata->switch_pin))
gpio_free(pdata->slots[0].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 * in capabilities register
* - MMC/SD clock coming out of controller > 25MHz * - 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_MMC_DDR52) &&
(ios->timing != MMC_TIMING_UHS_DDR50) &&
((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) { ((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) {
regval = OMAP_HSMMC_READ(host->base, HCTL); regval = OMAP_HSMMC_READ(host->base, HCTL);
if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000) 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; u32 con;
con = OMAP_HSMMC_READ(host->base, 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 */ con |= DDR; /* configure in DDR mode */
else else
con &= ~DDR; con &= ~DDR;
@ -791,8 +812,8 @@ int omap_hsmmc_cover_is_closed(struct omap_hsmmc_host *host)
{ {
int r = 1; int r = 1;
if (mmc_slot(host).get_cover_state) if (host->get_cover_state)
r = mmc_slot(host).get_cover_state(host->dev, host->slot_id); r = host->get_cover_state(host->dev);
return r; 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 mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
struct omap_hsmmc_host *host = mmc_priv(mmc); 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); 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. * OMAP4 ES2 and greater has an updated reset logic.
* Monitor a 0->1 transition first * 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)) while ((!(OMAP_HSMMC_READ(host->base, SYSCTL) & bit))
&& (i++ < limit)) && (i++ < limit))
udelay(1); udelay(1);
@ -1210,12 +1231,11 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
clk_disable_unprepare(host->dbclk); clk_disable_unprepare(host->dbclk);
/* Turn the power off */ /* Turn the power off */
ret = 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 */ /* Turn the power ON with given VDD 1.8 or 3.0v */
if (!ret) if (!ret)
ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1, ret = mmc_pdata(host)->set_power(host->dev, 1, vdd);
vdd);
pm_runtime_get_sync(host->dev); pm_runtime_get_sync(host->dev);
if (host->dbclk) if (host->dbclk)
clk_prepare_enable(host->dbclk); clk_prepare_enable(host->dbclk);
@ -1259,11 +1279,11 @@ err:
/* Protect the card while the cover is open */ /* Protect the card while the cover is open */
static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host) static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host)
{ {
if (!mmc_slot(host).get_cover_state) if (!host->get_cover_state)
return; return;
host->reqs_blocked = 0; 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) { if (host->protect_card) {
dev_info(host->dev, "%s: cover is closed, " dev_info(host->dev, "%s: cover is closed, "
"card is now accessible\n", "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) static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id)
{ {
struct omap_hsmmc_host *host = dev_id; struct omap_hsmmc_host *host = dev_id;
struct omap_mmc_slot_data *slot = &mmc_slot(host);
int carddetect; int carddetect;
sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch"); sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
if (slot->card_detect) if (host->card_detect)
carddetect = slot->card_detect(host->dev, host->slot_id); carddetect = host->card_detect(host->dev);
else { else {
omap_hsmmc_protect_card(host); omap_hsmmc_protect_card(host);
carddetect = -ENOSYS; 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) { if (ios->power_mode != host->power_mode) {
switch (ios->power_mode) { switch (ios->power_mode) {
case MMC_POWER_OFF: case MMC_POWER_OFF:
mmc_slot(host).set_power(host->dev, host->slot_id, mmc_pdata(host)->set_power(host->dev, 0, 0);
0, 0);
break; break;
case MMC_POWER_UP: case MMC_POWER_UP:
mmc_slot(host).set_power(host->dev, host->slot_id, mmc_pdata(host)->set_power(host->dev, 1, ios->vdd);
1, ios->vdd);
break; break;
case MMC_POWER_ON: case MMC_POWER_ON:
do_send_init_stream = 1; 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); struct omap_hsmmc_host *host = mmc_priv(mmc);
if (!mmc_slot(host).card_detect) if (!host->card_detect)
return -ENOSYS; 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) static int omap_hsmmc_get_ro(struct mmc_host *mmc)
{ {
struct omap_hsmmc_host *host = mmc_priv(mmc); struct omap_hsmmc_host *host = mmc_priv(mmc);
if (!mmc_slot(host).get_ro) if (!host->get_ro)
return -ENOSYS; 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) static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card)
{ {
struct omap_hsmmc_host *host = mmc_priv(mmc); struct omap_hsmmc_host *host = mmc_priv(mmc);
if (mmc_slot(host).init_card) if (mmc_pdata(host)->init_card)
mmc_slot(host).init_card(card); mmc_pdata(host)->init_card(card);
} }
static void omap_hsmmc_enable_sdio_irq(struct mmc_host *mmc, int enable) 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); 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; struct device_node *np = dev->of_node;
u32 bus_width, max_freq; u32 bus_width, max_freq;
int cd_gpio, wp_gpio; 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)) if (of_find_property(np, "ti,dual-volt", NULL))
pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT; pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT;
/* This driver only supports 1 slot */ pdata->switch_pin = cd_gpio;
pdata->nr_slots = 1; pdata->gpio_wp = wp_gpio;
pdata->slots[0].switch_pin = cd_gpio;
pdata->slots[0].gpio_wp = wp_gpio;
if (of_find_property(np, "ti,non-removable", NULL)) { if (of_find_property(np, "ti,non-removable", NULL)) {
pdata->slots[0].nonremovable = true; pdata->nonremovable = true;
pdata->slots[0].no_regulator_off_init = true; pdata->no_regulator_off_init = true;
} }
of_property_read_u32(np, "bus-width", &bus_width); of_property_read_u32(np, "bus-width", &bus_width);
if (bus_width == 4) 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) 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)) 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)) if (!of_property_read_u32(np, "max-frequency", &max_freq))
pdata->max_freq = max_freq; pdata->max_freq = max_freq;
if (of_find_property(np, "ti,needs-special-hs-handling", NULL)) 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)) 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)) 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; return pdata;
} }
#else #else
static inline struct omap_mmc_platform_data static inline struct omap_hsmmc_platform_data
*of_get_hsmmc_pdata(struct device *dev) *of_get_hsmmc_pdata(struct device *dev)
{ {
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
@ -2018,7 +2033,7 @@ static inline struct omap_mmc_platform_data
static int omap_hsmmc_probe(struct platform_device *pdev) 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 mmc_host *mmc;
struct omap_hsmmc_host *host = NULL; struct omap_hsmmc_host *host = NULL;
struct resource *res; struct resource *res;
@ -2048,11 +2063,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
return -ENXIO; return -ENXIO;
} }
if (pdata->nr_slots == 0) {
dev_err(&pdev->dev, "No Slots\n");
return -ENXIO;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (res == NULL || irq < 0) if (res == NULL || irq < 0)
@ -2062,14 +2072,10 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
if (IS_ERR(base)) if (IS_ERR(base))
return PTR_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); mmc = mmc_alloc_host(sizeof(struct omap_hsmmc_host), &pdev->dev);
if (!mmc) { if (!mmc) {
ret = -ENOMEM; ret = -ENOMEM;
goto err_alloc; goto err;
} }
host = mmc_priv(mmc); host = mmc_priv(mmc);
@ -2079,13 +2085,16 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
host->use_dma = 1; host->use_dma = 1;
host->dma_ch = -1; host->dma_ch = -1;
host->irq = irq; host->irq = irq;
host->slot_id = 0;
host->mapbase = res->start + pdata->reg_offset; host->mapbase = res->start + pdata->reg_offset;
host->base = base + pdata->reg_offset; host->base = base + pdata->reg_offset;
host->power_mode = MMC_POWER_OFF; host->power_mode = MMC_POWER_OFF;
host->next_data.cookie = 1; host->next_data.cookie = 1;
host->pbias_enabled = 0; host->pbias_enabled = 0;
ret = omap_hsmmc_gpio_init(host, pdata);
if (ret)
goto err_gpio;
platform_set_drvdata(pdev, host); platform_set_drvdata(pdev, host);
if (pdev->dev.of_node) 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->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE; 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) if (mmc->caps & MMC_CAP_8_BIT_DATA)
mmc->caps |= MMC_CAP_4_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->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); omap_hsmmc_conf_bus_power(host);
@ -2204,27 +2213,19 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
goto err_irq; goto err_irq;
} }
if (pdata->init != NULL) { if (omap_hsmmc_have_reg() && !mmc_pdata(host)->set_power) {
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) {
ret = omap_hsmmc_reg_get(host); ret = omap_hsmmc_reg_get(host);
if (ret) if (ret)
goto err_reg; goto err_irq;
host->use_reg = 1; 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 */ /* Request IRQ for card detect */
if ((mmc_slot(host).card_detect_irq)) { if (host->card_detect_irq) {
ret = devm_request_threaded_irq(&pdev->dev, ret = devm_request_threaded_irq(&pdev->dev,
mmc_slot(host).card_detect_irq, host->card_detect_irq,
NULL, omap_hsmmc_detect, NULL, omap_hsmmc_detect,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
mmc_hostname(mmc), host); mmc_hostname(mmc), host);
@ -2233,8 +2234,8 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
"Unable to grab MMC CD IRQ\n"); "Unable to grab MMC CD IRQ\n");
goto err_irq_cd; goto err_irq_cd;
} }
pdata->suspend = omap_hsmmc_suspend_cdirq; host->suspend = omap_hsmmc_suspend_cdirq;
pdata->resume = omap_hsmmc_resume_cdirq; host->resume = omap_hsmmc_resume_cdirq;
} }
omap_hsmmc_disable_irq(host); omap_hsmmc_disable_irq(host);
@ -2255,12 +2256,12 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
mmc_add_host(mmc); 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); ret = device_create_file(&mmc->class_dev, &dev_attr_slot_name);
if (ret < 0) if (ret < 0)
goto err_slot_name; 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, ret = device_create_file(&mmc->class_dev,
&dev_attr_cover_switch); &dev_attr_cover_switch);
if (ret < 0) if (ret < 0)
@ -2278,9 +2279,6 @@ err_slot_name:
err_irq_cd: err_irq_cd:
if (host->use_reg) if (host->use_reg)
omap_hsmmc_reg_put(host); omap_hsmmc_reg_put(host);
err_reg:
if (host->pdata->cleanup)
host->pdata->cleanup(&pdev->dev);
err_irq: err_irq:
if (host->tx_chan) if (host->tx_chan)
dma_release_channel(host->tx_chan); dma_release_channel(host->tx_chan);
@ -2291,9 +2289,9 @@ err_irq:
if (host->dbclk) if (host->dbclk)
clk_disable_unprepare(host->dbclk); clk_disable_unprepare(host->dbclk);
err1: err1:
omap_hsmmc_gpio_free(host, pdata);
err_gpio:
mmc_free_host(mmc); mmc_free_host(mmc);
err_alloc:
omap_hsmmc_gpio_free(pdata);
err: err:
return ret; return ret;
} }
@ -2306,8 +2304,6 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
mmc_remove_host(host->mmc); mmc_remove_host(host->mmc);
if (host->use_reg) if (host->use_reg)
omap_hsmmc_reg_put(host); omap_hsmmc_reg_put(host);
if (host->pdata->cleanup)
host->pdata->cleanup(&pdev->dev);
if (host->tx_chan) if (host->tx_chan)
dma_release_channel(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) if (host->dbclk)
clk_disable_unprepare(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); mmc_free_host(host->mmc);
return 0; return 0;
@ -2330,8 +2326,8 @@ static int omap_hsmmc_prepare(struct device *dev)
{ {
struct omap_hsmmc_host *host = dev_get_drvdata(dev); struct omap_hsmmc_host *host = dev_get_drvdata(dev);
if (host->pdata->suspend) if (host->suspend)
return host->pdata->suspend(dev, host->slot_id); return host->suspend(dev);
return 0; return 0;
} }
@ -2340,8 +2336,8 @@ static void omap_hsmmc_complete(struct device *dev)
{ {
struct omap_hsmmc_host *host = dev_get_drvdata(dev); struct omap_hsmmc_host *host = dev_get_drvdata(dev);
if (host->pdata->resume) if (host->resume)
host->pdata->resume(dev, host->slot_id); host->resume(dev);
} }

Просмотреть файл

@ -76,6 +76,7 @@ struct sdhci_acpi_host {
const struct sdhci_acpi_slot *slot; const struct sdhci_acpi_slot *slot;
struct platform_device *pdev; struct platform_device *pdev;
bool use_runtime_pm; bool use_runtime_pm;
bool dma_setup;
}; };
static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag) static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag)
@ -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) 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) 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 = { static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
.chip = &sdhci_acpi_chip_int, .chip = &sdhci_acpi_chip_int,
.caps = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE | .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, .caps2 = MMC_CAP2_HC_ERASE_SZ,
.flags = SDHCI_ACPI_RUNTIME_PM, .flags = SDHCI_ACPI_RUNTIME_PM,
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_STOP_WITH_TC, .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_STOP_WITH_TC,
.probe_slot = sdhci_acpi_emmc_probe_slot, .probe_slot = sdhci_acpi_emmc_probe_slot,
}; };
static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = { 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, .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, .flags = SDHCI_ACPI_RUNTIME_PM,
.pm_caps = MMC_PM_KEEP_POWER, .pm_caps = MMC_PM_KEEP_POWER,
.probe_slot = sdhci_acpi_sdio_probe_slot, .probe_slot = 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 = { static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
.flags = SDHCI_ACPI_SD_CD | SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL | .flags = SDHCI_ACPI_SD_CD | SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL |
SDHCI_ACPI_RUNTIME_PM, SDHCI_ACPI_RUNTIME_PM,
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON | .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |
SDHCI_QUIRK2_STOP_WITH_TC, SDHCI_QUIRK2_STOP_WITH_TC,
.caps = MMC_CAP_BUS_WIDTH_TEST | MMC_CAP_WAIT_WHILE_BUSY,
.probe_slot = sdhci_acpi_sd_probe_slot, .probe_slot = sdhci_acpi_sd_probe_slot,
}; };
@ -305,21 +334,6 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
goto err_free; 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) {
if (c->slot->probe_slot) { if (c->slot->probe_slot) {
err = c->slot->probe_slot(pdev, hid, uid); err = c->slot->probe_slot(pdev, hid, uid);

Просмотреть файл

@ -65,8 +65,6 @@
/* NOTE: the minimum valid tuning start tap for mx6sl is 1 */ /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */
#define ESDHC_TUNING_START_TAP 0x1 #define ESDHC_TUNING_START_TAP 0x1
#define ESDHC_TUNING_BLOCK_PATTERN_LEN 64
/* pinctrl state */ /* pinctrl state */
#define ESDHC_PINCTRL_STATE_100MHZ "state_100mhz" #define ESDHC_PINCTRL_STATE_100MHZ "state_100mhz"
#define ESDHC_PINCTRL_STATE_200MHZ "state_200mhz" #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 */ /* FIXME: delay a bit for card to be ready for next tuning due to errors */
mdelay(1); 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 = readl(host->ioaddr + ESDHC_MIX_CTRL);
reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL | reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL |
ESDHC_MIX_CTRL_FBCLK_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)); 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) static void esdhc_post_tuning(struct sdhci_host *host)
{ {
u32 reg; 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) static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
{ {
struct scatterlist sg;
char *tuning_pattern;
int min, max, avg, ret; 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 */ /* find the mininum delay first which can pass tuning */
min = ESDHC_TUNE_CTRL_MIN; min = ESDHC_TUNE_CTRL_MIN;
while (min < ESDHC_TUNE_CTRL_MAX) { while (min < ESDHC_TUNE_CTRL_MAX) {
esdhc_prepare_tuning(host, min); esdhc_prepare_tuning(host, min);
if (!esdhc_send_tuning_cmd(host, opcode, &sg)) if (!mmc_send_tuning(host->mmc))
break; break;
min += ESDHC_TUNE_CTRL_STEP; 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; max = min + ESDHC_TUNE_CTRL_STEP;
while (max < ESDHC_TUNE_CTRL_MAX) { while (max < ESDHC_TUNE_CTRL_MAX) {
esdhc_prepare_tuning(host, 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; max -= ESDHC_TUNE_CTRL_STEP;
break; break;
} }
@ -796,11 +736,9 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
/* use average delay to get the best timing */ /* use average delay to get the best timing */
avg = (min + max) / 2; avg = (min + max) / 2;
esdhc_prepare_tuning(host, avg); esdhc_prepare_tuning(host, avg);
ret = esdhc_send_tuning_cmd(host, opcode, &sg); ret = mmc_send_tuning(host->mmc);
esdhc_post_tuning(host); esdhc_post_tuning(host);
kfree(tuning_pattern);
dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n", dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n",
ret ? "failed" : "passed", avg, ret); 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, imx_data->pins_default = pinctrl_lookup_state(imx_data->pinctrl,
PINCTRL_STATE_DEFAULT); PINCTRL_STATE_DEFAULT);
if (IS_ERR(imx_data->pins_default)) { if (IS_ERR(imx_data->pins_default))
err = PTR_ERR(imx_data->pins_default); dev_warn(mmc_dev(host->mmc), "could not get default state\n");
dev_err(mmc_dev(host->mmc), "could not get default state\n");
goto disable_clk;
}
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; 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 */ /* 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, imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl,
ESDHC_PINCTRL_STATE_100MHZ); ESDHC_PINCTRL_STATE_100MHZ);
imx_data->pins_200mhz = pinctrl_lookup_state(imx_data->pinctrl, imx_data->pins_200mhz = pinctrl_lookup_state(imx_data->pinctrl,

Просмотреть файл

@ -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) static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
{ {
int tuning_seq_cnt = 3; int tuning_seq_cnt = 3;
u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0; u8 phase, tuned_phases[16], tuned_phase_cnt = 0;
const u8 *tuning_block_pattern = tuning_blk_pattern_4bit;
int size = sizeof(tuning_blk_pattern_4bit);
int rc; int rc;
struct mmc_host *mmc = host->mmc; struct mmc_host *mmc = host->mmc;
struct mmc_ios ios = host->mmc->ios; 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))) (ios.timing == MMC_TIMING_UHS_SDR104)))
return 0; 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: retry:
/* First of all reset the tuning block */ /* First of all reset the tuning block */
rc = msm_init_cm_dll(host); rc = msm_init_cm_dll(host);
if (rc) if (rc)
goto out; return rc;
phase = 0; phase = 0;
do { 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 */ /* Set the phase in delay line hw block */
rc = msm_config_cm_dll_phase(host, phase); rc = msm_config_cm_dll_phase(host, phase);
if (rc) if (rc)
goto out; return rc;
cmd.opcode = opcode; rc = mmc_send_tuning(mmc);
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; if (!rc) {
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)) {
/* Tuning is successful at this tuning point */ /* Tuning is successful at this tuning point */
tuned_phases[tuned_phase_cnt++] = phase; tuned_phases[tuned_phase_cnt++] = phase;
dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n", 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, rc = msm_find_most_appropriate_phase(host, tuned_phases,
tuned_phase_cnt); tuned_phase_cnt);
if (rc < 0) if (rc < 0)
goto out; return rc;
else else
phase = rc; phase = rc;
@ -423,7 +389,7 @@ retry:
*/ */
rc = msm_config_cm_dll_phase(host, phase); rc = msm_config_cm_dll_phase(host, phase);
if (rc) if (rc)
goto out; return rc;
dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n", dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n",
mmc_hostname(mmc), phase); mmc_hostname(mmc), phase);
} else { } else {
@ -435,8 +401,6 @@ retry:
rc = -EIO; rc = -EIO;
} }
out:
kfree(data_buf);
return rc; return rc;
} }

Просмотреть файл

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

Просмотреть файл

@ -127,8 +127,6 @@ void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip)
return; return;
scratch_32 &= ~((1 << 21) | (1 << 30)); 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); pci_write_config_dword(chip->pdev, O2_SD_FUNC_REG3, scratch_32);
/* Set L1 Entrance Timer */ /* Set L1 Entrance Timer */

Просмотреть файл

@ -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) static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
{ {
slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE | 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->host->mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ;
slot->hw_reset = sdhci_pci_int_hw_reset; slot->hw_reset = sdhci_pci_int_hw_reset;
if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BSW_EMMC) 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) 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; return 0;
} }
static int byt_sd_probe_slot(struct sdhci_pci_slot *slot) 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_con_id = NULL;
slot->cd_idx = 0; slot->cd_idx = 0;
slot->cd_override_level = true; 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 = { static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = {
.allow_runtime_pm = true, .allow_runtime_pm = true,
.probe_slot = byt_emmc_probe_slot, .probe_slot = byt_emmc_probe_slot,
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
SDHCI_QUIRK2_STOP_WITH_TC, SDHCI_QUIRK2_STOP_WITH_TC,
}; };
static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = { static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON | .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON |
SDHCI_QUIRK2_PRESET_VALUE_BROKEN, SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
.allow_runtime_pm = true, .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 = { 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 | .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |
SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
SDHCI_QUIRK2_STOP_WITH_TC, SDHCI_QUIRK2_STOP_WITH_TC,
@ -645,6 +654,25 @@ static const struct sdhci_pci_fixes sdhci_rtsx = {
.probe_slot = rtsx_probe_slot, .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[] = { static const struct pci_device_id pci_ids[] = {
{ {
.vendor = PCI_VENDOR_ID_RICOH, .vendor = PCI_VENDOR_ID_RICOH,
@ -1044,7 +1072,15 @@ static const struct pci_device_id pci_ids[] = {
.subdevice = PCI_ANY_ID, .subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_o2, .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 */ { /* Generic SD host controller */
PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00) 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 sdhci_pci_slot *slot;
struct pci_dev *pdev; struct pci_dev *pdev;
int ret; int ret = -1;
slot = sdhci_priv(host); slot = sdhci_priv(host);
pdev = slot->chip->pdev; 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"); "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) if (ret)
return ret; return ret;

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -300,6 +300,7 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
struct device *dev = &ourhost->pdev->dev; struct device *dev = &ourhost->pdev->dev;
unsigned long timeout; unsigned long timeout;
u16 clk = 0; u16 clk = 0;
int ret;
host->mmc->actual_clock = 0; 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); 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; clk = SDHCI_CLOCK_INT_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);

Просмотреть файл

@ -44,8 +44,6 @@
#define MAX_TUNING_LOOP 40 #define MAX_TUNING_LOOP 40
#define ADMA_SIZE ((128 * 2 + 1) * 4)
static unsigned int debug_quirks = 0; static unsigned int debug_quirks = 0;
static unsigned int debug_quirks2; 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", pr_debug(DRIVER_NAME ": Host ctl2: 0x%08x\n",
sdhci_readw(host, SDHCI_HOST_CONTROL2)); sdhci_readw(host, SDHCI_HOST_CONTROL2));
if (host->flags & SDHCI_USE_ADMA) if (host->flags & SDHCI_USE_ADMA) {
pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n", if (host->flags & SDHCI_USE_64_BIT_DMA)
readl(host->ioaddr + SDHCI_ADMA_ERROR), pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x\n",
readl(host->ioaddr + SDHCI_ADMA_ADDRESS)); 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"); pr_debug(DRIVER_NAME ": ===========================================\n");
} }
@ -448,18 +453,26 @@ static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags)
local_irq_restore(*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); struct sdhci_adma2_64_desc *dma_desc = desc;
__le16 *cmdlen = (__le16 __force *)desc;
/* SDHCI specification says ADMA descriptors should be 4 byte /* 32-bit and 64-bit descriptors have these members in same position */
* aligned, so using 16 or 32bit operations should be safe. */ 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); if (host->flags & SDHCI_USE_64_BIT_DMA)
cmdlen[1] = cpu_to_le16(len); 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, 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; int direction;
u8 *desc; void *desc;
u8 *align; void *align;
dma_addr_t addr; dma_addr_t addr;
dma_addr_t align_addr; dma_addr_t align_addr;
int len, offset; int len, offset;
@ -489,17 +502,17 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
direction = DMA_TO_DEVICE; direction = DMA_TO_DEVICE;
host->align_addr = dma_map_single(mmc_dev(host->mmc), 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)) if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr))
goto fail; 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), host->sg_count = dma_map_sg(mmc_dev(host->mmc),
data->sg, data->sg_len, direction); data->sg, data->sg_len, direction);
if (host->sg_count == 0) if (host->sg_count == 0)
goto unmap_align; goto unmap_align;
desc = host->adma_desc; desc = host->adma_table;
align = host->align_buffer; align = host->align_buffer;
align_addr = host->align_addr; 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 * the (up to three) bytes that screw up the
* alignment. * alignment.
*/ */
offset = (4 - (addr & 0x3)) & 0x3; offset = (host->align_sz - (addr & host->align_mask)) &
host->align_mask;
if (offset) { if (offset) {
if (data->flags & MMC_DATA_WRITE) { if (data->flags & MMC_DATA_WRITE) {
buffer = sdhci_kmap_atomic(sg, &flags); 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); memcpy(align, buffer, offset);
sdhci_kunmap_atomic(buffer, &flags); sdhci_kunmap_atomic(buffer, &flags);
} }
/* tran, valid */ /* 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); BUG_ON(offset > 65536);
align += 4; align += host->align_sz;
align_addr += 4; align_addr += host->align_sz;
desc += 8; desc += host->desc_sz;
addr += offset; addr += offset;
len -= offset; len -= offset;
@ -541,23 +557,23 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
BUG_ON(len > 65536); BUG_ON(len > 65536);
/* tran, valid */ /* tran, valid */
sdhci_set_adma_desc(desc, addr, len, 0x21); sdhci_adma_write_desc(host, desc, addr, len, ADMA2_TRAN_VALID);
desc += 8; desc += host->desc_sz;
/* /*
* If this triggers then we have a calculation bug * If this triggers then we have a calculation bug
* somewhere. :/ * 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) { if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) {
/* /*
* Mark the last descriptor as the terminating descriptor * Mark the last descriptor as the terminating descriptor
*/ */
if (desc != host->adma_desc) { if (desc != host->adma_table) {
desc -= 8; desc -= host->desc_sz;
desc[0] |= 0x2; /* end */ sdhci_adma_mark_end(desc);
} }
} else { } else {
/* /*
@ -565,7 +581,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
*/ */
/* nop, end, valid */ /* 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) { if (data->flags & MMC_DATA_WRITE) {
dma_sync_single_for_device(mmc_dev(host->mmc), 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; return 0;
unmap_align: unmap_align:
dma_unmap_single(mmc_dev(host->mmc), host->align_addr, dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
128 * 4, direction); host->align_buffer_sz, direction);
fail: fail:
return -EINVAL; return -EINVAL;
} }
@ -592,7 +608,7 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
struct scatterlist *sg; struct scatterlist *sg;
int i, size; int i, size;
u8 *align; void *align;
char *buffer; char *buffer;
unsigned long flags; unsigned long flags;
bool has_unaligned; bool has_unaligned;
@ -603,12 +619,12 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
direction = DMA_TO_DEVICE; direction = DMA_TO_DEVICE;
dma_unmap_single(mmc_dev(host->mmc), host->align_addr, 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 */ /* Do a quick scan of the SG list for any unaligned mappings */
has_unaligned = false; has_unaligned = false;
for_each_sg(data->sg, sg, host->sg_count, i) 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; has_unaligned = true;
break; break;
} }
@ -620,15 +636,17 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
align = host->align_buffer; align = host->align_buffer;
for_each_sg(data->sg, sg, host->sg_count, i) { for_each_sg(data->sg, sg, host->sg_count, i) {
if (sg_dma_address(sg) & 0x3) { if (sg_dma_address(sg) & host->align_mask) {
size = 4 - (sg_dma_address(sg) & 0x3); size = host->align_sz -
(sg_dma_address(sg) & host->align_mask);
buffer = sdhci_kmap_atomic(sg, &flags); 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); memcpy(buffer, align, size);
sdhci_kunmap_atomic(buffer, &flags); 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 { } else {
sdhci_writel(host, host->adma_addr, sdhci_writel(host, host->adma_addr,
SDHCI_ADMA_ADDRESS); SDHCI_ADMA_ADDRESS);
if (host->flags & SDHCI_USE_64_BIT_DMA)
sdhci_writel(host,
(u64)host->adma_addr >> 32,
SDHCI_ADMA_ADDRESS_HI);
} }
} else { } else {
int sg_cnt; 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_readb(host, SDHCI_HOST_CONTROL);
ctrl &= ~SDHCI_CTRL_DMA_MASK; ctrl &= ~SDHCI_CTRL_DMA_MASK;
if ((host->flags & SDHCI_REQ_USE_DMA) && if ((host->flags & SDHCI_REQ_USE_DMA) &&
(host->flags & SDHCI_USE_ADMA)) (host->flags & SDHCI_USE_ADMA)) {
ctrl |= SDHCI_CTRL_ADMA32; if (host->flags & SDHCI_USE_64_BIT_DMA)
else ctrl |= SDHCI_CTRL_ADMA64;
else
ctrl |= SDHCI_CTRL_ADMA32;
} else {
ctrl |= SDHCI_CTRL_SDMA; ctrl |= SDHCI_CTRL_SDMA;
}
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); 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; struct mmc_data *data = cmd->data;
if (data == NULL) { 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 */ /* clear Auto CMD settings for no data CMDs */
mode = sdhci_readw(host, SDHCI_TRANSFER_MODE); mode = sdhci_readw(host, SDHCI_TRANSFER_MODE);
sdhci_writew(host, mode & ~(SDHCI_TRNS_AUTO_CMD12 | sdhci_writew(host, mode & ~(SDHCI_TRNS_AUTO_CMD12 |
SDHCI_TRNS_AUTO_CMD23), SDHCI_TRANSFER_MODE); SDHCI_TRNS_AUTO_CMD23), SDHCI_TRANSFER_MODE);
}
return; return;
} }
@ -1117,6 +1148,9 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)
case MMC_TIMING_UHS_DDR50: case MMC_TIMING_UHS_DDR50:
preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50); preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50);
break; break;
case MMC_TIMING_MMC_HS400:
preset = sdhci_readw(host, SDHCI_PRESET_FOR_HS400);
break;
default: default:
pr_warn("%s: Invalid UHS-I mode selected\n", pr_warn("%s: Invalid UHS-I mode selected\n",
mmc_hostname(host->mmc)); 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) || else if ((timing == MMC_TIMING_UHS_DDR50) ||
(timing == MMC_TIMING_MMC_DDR52)) (timing == MMC_TIMING_MMC_DDR52))
ctrl_2 |= SDHCI_CTRL_UHS_DDR50; 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); sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
} }
EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling); 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; u16 clk, ctrl_2;
/* In case of UHS-I modes, set High Speed Enable */ /* 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_MMC_DDR52) ||
(ios->timing == MMC_TIMING_UHS_SDR50) || (ios->timing == MMC_TIMING_UHS_SDR50) ||
(ios->timing == MMC_TIMING_UHS_SDR104) || (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. * tuning function has to be executed.
*/ */
switch (host->timing) { switch (host->timing) {
case MMC_TIMING_MMC_HS400:
case MMC_TIMING_MMC_HS200: case MMC_TIMING_MMC_HS200:
case MMC_TIMING_UHS_SDR104: case MMC_TIMING_UHS_SDR104:
break; break;
@ -2144,9 +2182,10 @@ static void sdhci_tasklet_finish(unsigned long param)
*/ */
if (!(host->flags & SDHCI_DEVICE_DEAD) && if (!(host->flags & SDHCI_DEVICE_DEAD) &&
((mrq->cmd && mrq->cmd->error) || ((mrq->cmd && mrq->cmd->error) ||
(mrq->data && (mrq->data->error || (mrq->sbc && mrq->sbc->error) ||
(mrq->data->stop && mrq->data->stop->error))) || (mrq->data && ((mrq->data->error && !mrq->data->stop) ||
(host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) { (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 */ /* Some controllers need this kick or reset won't work here */
if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) 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 #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); const char *name = mmc_hostname(host->mmc);
u8 *desc = host->adma_desc; void *desc = host->adma_table;
__le32 *dma;
__le16 *len;
u8 attr;
sdhci_dumpregs(host); sdhci_dumpregs(host);
while (true) { while (true) {
dma = (__le32 *)(desc + 4); struct sdhci_adma2_64_desc *dma_desc = desc;
len = (__le16 *)(desc + 2);
attr = *desc;
DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n", if (host->flags & SDHCI_USE_64_BIT_DMA)
name, desc, le32_to_cpu(*dma), le16_to_cpu(*len), attr); 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; break;
} }
} }
#else #else
static void sdhci_show_adma_error(struct sdhci_host *host) { } static void sdhci_adma_show_error(struct sdhci_host *host) { }
#endif #endif
static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) 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; host->data->error = -EILSEQ;
else if (intmask & SDHCI_INT_ADMA_ERROR) { else if (intmask & SDHCI_INT_ADMA_ERROR) {
pr_err("%s: ADMA error\n", mmc_hostname(host->mmc)); pr_err("%s: ADMA error\n", mmc_hostname(host->mmc));
sdhci_show_adma_error(host); sdhci_adma_show_error(host);
host->data->error = -EIO; host->data->error = -EIO;
if (host->ops->adma_workaround) if (host->ops->adma_workaround)
host->ops->adma_workaround(host, intmask); host->ops->adma_workaround(host, intmask);
@ -2849,6 +2892,16 @@ int sdhci_add_host(struct sdhci_host *host)
host->flags &= ~SDHCI_USE_ADMA; 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->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
if (host->ops->enable_dma) { if (host->ops->enable_dma) {
if (host->ops->enable_dma(host)) { 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) { if (host->flags & SDHCI_USE_ADMA) {
/* /*
* We need to allocate descriptors for all sg entries * The DMA descriptor table size is calculated as the maximum
* (128) and potentially one alignment transfer for * number of segments times 2, to allow for an alignment
* each of those entries. * 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), if (host->flags & SDHCI_USE_64_BIT_DMA) {
ADMA_SIZE, &host->adma_addr, host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) *
GFP_KERNEL); SDHCI_ADMA2_64_DESC_SZ;
host->align_buffer = kmalloc(128 * 4, GFP_KERNEL); host->align_buffer_sz = SDHCI_MAX_SEGS *
if (!host->adma_desc || !host->align_buffer) { SDHCI_ADMA2_64_ALIGN;
dma_free_coherent(mmc_dev(mmc), ADMA_SIZE, host->desc_sz = SDHCI_ADMA2_64_DESC_SZ;
host->adma_desc, host->adma_addr); 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); kfree(host->align_buffer);
pr_warn("%s: Unable to allocate ADMA buffers - falling back to standard DMA\n", pr_warn("%s: Unable to allocate ADMA buffers - falling back to standard DMA\n",
mmc_hostname(mmc)); mmc_hostname(mmc));
host->flags &= ~SDHCI_USE_ADMA; host->flags &= ~SDHCI_USE_ADMA;
host->adma_desc = NULL; host->adma_table = NULL;
host->align_buffer = 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", pr_warn("%s: unable to allocate aligned ADMA descriptor\n",
mmc_hostname(mmc)); mmc_hostname(mmc));
host->flags &= ~SDHCI_USE_ADMA; host->flags &= ~SDHCI_USE_ADMA;
dma_free_coherent(mmc_dev(mmc), ADMA_SIZE, dma_free_coherent(mmc_dev(mmc), host->adma_table_sz,
host->adma_desc, host->adma_addr); host->adma_table, host->adma_addr);
kfree(host->align_buffer); kfree(host->align_buffer);
host->adma_desc = NULL; host->adma_table = NULL;
host->align_buffer = NULL; host->align_buffer = NULL;
} }
} }
@ -3027,7 +3103,7 @@ int sdhci_add_host(struct sdhci_host *host)
if (ret) { if (ret) {
pr_warn("%s: Failed to enable vqmmc regulator: %d\n", pr_warn("%s: Failed to enable vqmmc regulator: %d\n",
mmc_hostname(mmc), ret); 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 /* SD3.0: SDR104 is supported so (for eMMC) the caps2
* field can be promoted to support HS200. * 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; 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) } else if (caps[1] & SDHCI_SUPPORT_SDR50)
mmc->caps |= MMC_CAP_UHS_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) && if ((caps[1] & SDHCI_SUPPORT_DDR50) &&
!(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50)) !(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50))
mmc->caps |= MMC_CAP_UHS_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. * can do scatter/gather or not.
*/ */
if (host->flags & SDHCI_USE_ADMA) if (host->flags & SDHCI_USE_ADMA)
mmc->max_segs = 128; mmc->max_segs = SDHCI_MAX_SEGS;
else if (host->flags & SDHCI_USE_SDMA) else if (host->flags & SDHCI_USE_SDMA)
mmc->max_segs = 1; mmc->max_segs = 1;
else /* PIO */ else /* PIO */
mmc->max_segs = 128; mmc->max_segs = SDHCI_MAX_SEGS;
/* /*
* Maximum number of sectors in one transfer. Limited by DMA boundary * 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", pr_info("%s: SDHCI controller on %s [%s] using %s\n",
mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)), 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"); (host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO");
sdhci_enable_card_detection(host); sdhci_enable_card_detection(host);
@ -3339,18 +3421,15 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
tasklet_kill(&host->finish_tasklet); tasklet_kill(&host->finish_tasklet);
if (!IS_ERR(mmc->supply.vmmc))
regulator_disable(mmc->supply.vmmc);
if (!IS_ERR(mmc->supply.vqmmc)) if (!IS_ERR(mmc->supply.vqmmc))
regulator_disable(mmc->supply.vqmmc); regulator_disable(mmc->supply.vqmmc);
if (host->adma_desc) if (host->adma_table)
dma_free_coherent(mmc_dev(mmc), ADMA_SIZE, dma_free_coherent(mmc_dev(mmc), host->adma_table_sz,
host->adma_desc, host->adma_addr); host->adma_table, host->adma_addr);
kfree(host->align_buffer); kfree(host->align_buffer);
host->adma_desc = NULL; host->adma_table = NULL;
host->align_buffer = NULL; host->align_buffer = NULL;
} }

Просмотреть файл

@ -161,7 +161,7 @@
#define SDHCI_CTRL_UHS_SDR50 0x0002 #define SDHCI_CTRL_UHS_SDR50 0x0002
#define SDHCI_CTRL_UHS_SDR104 0x0003 #define SDHCI_CTRL_UHS_SDR104 0x0003
#define SDHCI_CTRL_UHS_DDR50 0x0004 #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_VDD_180 0x0008
#define SDHCI_CTRL_DRV_TYPE_MASK 0x0030 #define SDHCI_CTRL_DRV_TYPE_MASK 0x0030
#define SDHCI_CTRL_DRV_TYPE_B 0x0000 #define SDHCI_CTRL_DRV_TYPE_B 0x0000
@ -204,6 +204,7 @@
#define SDHCI_RETUNING_MODE_SHIFT 14 #define SDHCI_RETUNING_MODE_SHIFT 14
#define SDHCI_CLOCK_MUL_MASK 0x00FF0000 #define SDHCI_CLOCK_MUL_MASK 0x00FF0000
#define SDHCI_CLOCK_MUL_SHIFT 16 #define SDHCI_CLOCK_MUL_SHIFT 16
#define SDHCI_SUPPORT_HS400 0x80000000 /* Non-standard */
#define SDHCI_CAPABILITIES_1 0x44 #define SDHCI_CAPABILITIES_1 0x44
@ -227,6 +228,7 @@
/* 55-57 reserved */ /* 55-57 reserved */
#define SDHCI_ADMA_ADDRESS 0x58 #define SDHCI_ADMA_ADDRESS 0x58
#define SDHCI_ADMA_ADDRESS_HI 0x5C
/* 60-FB reserved */ /* 60-FB reserved */
@ -235,6 +237,7 @@
#define SDHCI_PRESET_FOR_SDR50 0x6A #define SDHCI_PRESET_FOR_SDR50 0x6A
#define SDHCI_PRESET_FOR_SDR104 0x6C #define SDHCI_PRESET_FOR_SDR104 0x6C
#define SDHCI_PRESET_FOR_DDR50 0x6E #define SDHCI_PRESET_FOR_DDR50 0x6E
#define SDHCI_PRESET_FOR_HS400 0x74 /* Non-standard */
#define SDHCI_PRESET_DRV_MASK 0xC000 #define SDHCI_PRESET_DRV_MASK 0xC000
#define SDHCI_PRESET_DRV_SHIFT 14 #define SDHCI_PRESET_DRV_SHIFT 14
#define SDHCI_PRESET_CLKGEN_SEL_MASK 0x400 #define SDHCI_PRESET_CLKGEN_SEL_MASK 0x400
@ -266,6 +269,46 @@
#define SDHCI_DEFAULT_BOUNDARY_SIZE (512 * 1024) #define SDHCI_DEFAULT_BOUNDARY_SIZE (512 * 1024)
#define SDHCI_DEFAULT_BOUNDARY_ARG (ilog2(SDHCI_DEFAULT_BOUNDARY_SIZE) - 12) #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 { struct sdhci_ops {
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
u32 (*read_l)(struct sdhci_host *host, int reg); u32 (*read_l)(struct sdhci_host *host, int reg);

Просмотреть файл

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

717
drivers/mmc/host/toshsd.c Normal 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
Просмотреть файл

@ -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 */
};

Просмотреть файл

@ -11,6 +11,7 @@
* @detect_pin: GPIO pin wired to the card detect switch * @detect_pin: GPIO pin wired to the card detect switch
* @wp_pin: GPIO pin wired to the write protect sensor * @wp_pin: GPIO pin wired to the write protect sensor
* @detect_is_active_high: The state of the detect pin when it is active * @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 * 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. * set to 0. The other fields are ignored in this case.
@ -26,6 +27,7 @@ struct mci_slot_pdata {
int detect_pin; int detect_pin;
int wp_pin; int wp_pin;
bool detect_is_active_high; bool detect_is_active_high;
bool non_removable;
}; };
/** /**

Просмотреть файл

@ -88,6 +88,9 @@ struct mmc_ext_csd {
unsigned int data_tag_unit_size; /* DATA TAG UNIT size */ unsigned int data_tag_unit_size; /* DATA TAG UNIT size */
unsigned int boot_ro_lock; /* ro lock support */ unsigned int boot_ro_lock; /* ro lock support */
bool boot_ro_lockable; 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_exception_status; /* 54 */
u8 raw_partition_support; /* 160 */ u8 raw_partition_support; /* 160 */
u8 raw_rpmb_size_mult; /* 168 */ 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_dev_to_card(d) container_of(d, struct mmc_card, dev)
#define mmc_list_to_card(l) container_of(l, struct mmc_card, node) extern int mmc_register_driver(struct device_driver *);
#define mmc_get_drvdata(c) dev_get_drvdata(&(c)->dev) extern void mmc_unregister_driver(struct device_driver *);
#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 void mmc_fixup_device(struct mmc_card *card, extern void mmc_fixup_device(struct mmc_card *card,
const struct mmc_fixup *table); const struct mmc_fixup *table);

Просмотреть файл

@ -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, extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool,
bool, bool); bool, bool);
extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int); 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_ERASE_ARG 0x00000000
#define MMC_SECURE_ERASE_ARG 0x80000000 #define MMC_SECURE_ERASE_ARG 0x80000000

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -296,6 +296,7 @@ struct _mmc_csd {
#define EXT_CSD_SANITIZE_START 165 /* W */ #define EXT_CSD_SANITIZE_START 165 /* W */
#define EXT_CSD_WR_REL_PARAM 166 /* RO */ #define EXT_CSD_WR_REL_PARAM 166 /* RO */
#define EXT_CSD_RPMB_MULT 168 /* 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_BOOT_WP 173 /* R/W */
#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */ #define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */
#define EXT_CSD_PART_CONFIG 179 /* 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_GENERIC_CMD6_TIME 248 /* RO */
#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */ #define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */
#define EXT_CSD_PWR_CL_DDR_200_360 253 /* RO */ #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_TAG_UNIT_SIZE 498 /* RO */
#define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */ #define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */
#define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */ #define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */

Просмотреть файл

@ -100,6 +100,12 @@ struct sdhci_host {
#define SDHCI_QUIRK2_BROKEN_DDR50 (1<<7) #define SDHCI_QUIRK2_BROKEN_DDR50 (1<<7)
/* Stop command (CMD12) can set Transfer Complete when not using MMC_RSP_BUSY */ /* Stop command (CMD12) can set Transfer Complete when not using MMC_RSP_BUSY */
#define SDHCI_QUIRK2_STOP_WITH_TC (1<<8) #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 */ int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */ void __iomem *ioaddr; /* Mapped address */
@ -130,6 +136,7 @@ struct sdhci_host {
#define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */ #define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */
#define SDHCI_SDR104_NEEDS_TUNING (1<<10) /* SDR104/HS200 needs tuning */ #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_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 */ unsigned int version; /* SDHCI spec. version */
@ -155,12 +162,19 @@ struct sdhci_host {
int sg_count; /* Mapped sg entries */ int sg_count; /* Mapped sg entries */
u8 *adma_desc; /* ADMA descriptor table */ void *adma_table; /* ADMA descriptor table */
u8 *align_buffer; /* Bounce buffer */ 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 adma_addr; /* Mapped ADMA descr. table */
dma_addr_t align_addr; /* Mapped bounce buffer */ 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 tasklet_struct finish_tasklet; /* Tasklet structures */
struct timer_list timer; /* Timer for timeouts */ struct timer_list timer; /* Timer for timeouts */

Просмотреть файл

@ -84,8 +84,6 @@ struct sdio_driver {
struct device_driver drv; 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 * SDIO_DEVICE - macro used to describe a specific SDIO device
* @vend: the 16 bit manufacturer code * @vend: the 16 bit manufacturer code

Просмотреть файл

@ -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;
};

Просмотреть файл

@ -1,17 +1,22 @@
#ifndef __MACH_ATMEL_MCI_H #ifndef __MMC_ATMEL_MCI_H
#define __MACH_ATMEL_MCI_H #define __MMC_ATMEL_MCI_H
#include <linux/platform_data/dma-atmel.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 - DMA data for MCI interface
*/ */
struct mci_dma_data { 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 */ /* accessor macros */
#define slave_data_ptr(s) (&(s)->sdata) #define slave_data_ptr(s) (&(s)->sdata)
#define find_slave_dev(s) ((s)->sdata.dma_dev) #define find_slave_dev(s) ((s)->sdata.dma_dev)
#endif /* __MACH_ATMEL_MCI_H */ #endif /* __MMC_ATMEL_MCI_H */

Просмотреть файл

@ -10,32 +10,8 @@
#define OMAP_MMC_MAX_SLOTS 2 #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 mmc_card;
struct omap_mmc_dev_attr {
u8 flags;
};
struct omap_mmc_platform_data { struct omap_mmc_platform_data {
/* back-link to device */ /* back-link to device */
struct device *dev; struct device *dev;
@ -106,9 +82,6 @@ struct omap_mmc_platform_data {
unsigned vcc_aux_disable_is_sleep:1; unsigned vcc_aux_disable_is_sleep:1;
/* we can put the features above into this variable */ /* 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_OMAP7XX (1 << 3)
#define MMC_OMAP15XX (1 << 4) #define MMC_OMAP15XX (1 << 4)
#define MMC_OMAP16XX (1 << 5) #define MMC_OMAP16XX (1 << 5)

Просмотреть файл

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