MMC core:

- Fix ABI regression of MMC BLK ioctl
  - Remove the unused MMC_DATA_STREAM flag
  - Enable asynchronous system PM for the host device
  - Minor fixes and clean-ups
 
 SDHCI host:
 Throughout the years, the numbers of SDHCI variants have increased and so
 has also the numbers of SDHCI callbacks/quirks. The purpose of these
 callbacks/quirks were to enable SDHCI to deal with variant specific
 requirements, but unfortunate this method didn't scale. Instead we have
 ended up with a mess. Not only did the code become suboptimal but also
 highly fragile.
 
 Lately many discussions of how to move forward with SDHCI has taken place
 at the MMC mailing list. Step by step, we aim to turn SDHCI's common code
 into a set of library functions. This will enable for optimizations and
 allow some of the existing callbacks/quirks to be removed, which also
 should help to make the code less fragile.
 
 Therefore I am also really pleased to announce that Adrian Hunter (Intel)
 has volunteered to step in as the maintainer for SDHCI.
 
 Future wise, I hope the community around SDHCI will continue to grow and
 that this release cycle can be the starting point of moving SDHCI into a
 better shape. As a matter of fact, already in this cycle the re-factoring
 has begun, but of course there are also fixes and new features included.
 Some highlights:
 
  - sdhci-iproc: Add support for Broadcom's BCM2835 eMMC IP
  - sdhci-acpi: Add support for QCOM controllers
  - sdhci-pic32: Add new SDHCI variant for PIC32MZDA
 
 Other hosts:
  - atmel-mci: Fix a NULL pointer dereference
  - mediatek: Add SD write-protect support
  - mmc_spi: Fix card detect in GPIO case
  - tmio/sdhi: Add r8a7795 support
  - tmio/sdhi: Some fixes and clean-ups
  - dw_mmc: Add HW reset support
  - dw_mmc: Some fixes and clean-ups
  - sunxi: Add support for MMC DDR52 mode
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJW7+1kAAoJEP4mhCVzWIwpFREP+wcm8CLPoIz0VamZ8wocU5/S
 NK+EINCrVF4AbvcTj78A/FE099P5e3kXW84cZP5fCGSk7MvTizlIP0kDT73XkYbf
 FV1xQYAq5E9PtWfswyLqEiYcHVFzwhxwHRy8pXnJ7bummM8OvZYSnao4kdxzW3Mr
 j2lELoUVYma5hnoXBMrq04kjwPukdrFXYMz4BulE0aoCrfp2+CoKcDbykh97zWbu
 B7ta2NG5EuszXepgsAPSGbFDuFXJ4EeDtZNzowom6ifkKusNa+42lOyBA+WiHBZ6
 kfSOyRHJ/URuGifir7hCXLvr2GVpFF3d399olDawCXEVCIhkrZ4SKJ25kLdABz9E
 IrikhpBlRIhquAW4clNnPNYWqGTsOT1Coj+6E/9XUHa8C8gGEV7W3j8nNzMCT2O4
 GMynfyXKIJ6JnuM03qqv3kmATmbRI3fulR6OTNObgAWSGeZLuxa1bIYDVXhtr2nQ
 Spl4nViOnZdfdNz4LkqS6vuGKscKViWFtt/wLi+gnKtbGfffb8CGrucd13vQ7fiK
 OP9WZoWLQ+YlItXDee02vn4ccH463KjIIKJdLsvmSHz+lfPnXRI2KR37+j7sczvo
 V3msYYkbjB1hghAunR94Zc3RXwV28R1/mqcOGzXv2A+Q1J4g//Q+gS8DGzXzlaRV
 58OJRqiyTWMktZ0TZM0V
 =MFMb
 -----END PGP SIGNATURE-----

Merge tag 'mmc-v4.6' of git://git.linaro.org/people/ulf.hansson/mmc

Pull MMC updates from Ulf Hansson:
 "MMC core:
      - Fix ABI regression of MMC BLK ioctl
      - Remove the unused MMC_DATA_STREAM flag
      - Enable asynchronous system PM for the host device
      - Minor fixes and clean-ups

  SDHCI host:
     Throughout the years, the numbers of SDHCI variants have increased
     and so has also the numbers of SDHCI callbacks/quirks.  The purpose
     of these callbacks/quirks were to enable SDHCI to deal with variant
     specific requirements, but unfortunate this method didn't scale.
     Instead we have ended up with a mess.  Not only did the code become
     suboptimal but also highly fragile.

     Lately many discussions of how to move forward with SDHCI has taken
     place at the MMC mailing list.  Step by step, we aim to turn
     SDHCI's common code into a set of library functions.  This will
     enable for optimizations and allow some of the existing callbacks
     and quirks to be removed, which also should help to make the code
     less fragile.

     Therefore I am also really pleased to announce that Adrian Hunter
     (Intel) has volunteered to step in as the maintainer for SDHCI.

     Future wise, I hope the community around SDHCI will continue to
     grow and that this release cycle can be the starting point of
     moving SDHCI into a better shape.  As a matter of fact, already in
     this cycle the re-factoring has begun, but of course there are also
     fixes and new features included.  Some highlights:

      - sdhci-iproc: Add support for Broadcom's BCM2835 eMMC IP
      - sdhci-acpi: Add support for QCOM controllers
      - sdhci-pic32: Add new SDHCI variant for PIC32MZDA

  Other hosts:
      - atmel-mci: Fix a NULL pointer dereference
      - mediatek: Add SD write-protect support
      - mmc_spi: Fix card detect in GPIO case
      - tmio/sdhi: Add r8a7795 support
      - tmio/sdhi: Some fixes and clean-ups
      - dw_mmc: Add HW reset support
      - dw_mmc: Some fixes and clean-ups
      - sunxi: Add support for MMC DDR52 mode"

* tag 'mmc-v4.6' of git://git.linaro.org/people/ulf.hansson/mmc: (123 commits)
  mmc: sdhci-of-at91: fix wake-up issue when using runtime pm
  mmc: sdhci-pci: Do not set DMA mask in enable_dma()
  mmc: sdhci-acpi: Remove enable_dma() hook
  mmc: sdhci: Set DMA mask when adding host
  mmc: block: fix ABI regression of mmc_blk_ioctl
  mmc: atmel-mci: Check pdata for NULL before dereferencing it at DMA config
  mmc: core: remove redundant memset of sdio_read_cccr
  mmc: core: remove redundant memset of mmc_decode_cid
  mmc: of_mmc_spi: fix unused warning
  mmc: sdhci-of-arasan: add phy support for sdhci-of-arasan
  mmc: sdhci-of-arasan: fix missing sdhci_pltfm_free for err handling
  mmc: sdhci-of-arasan: remove disable clk_ahb from sdhci_arasan_resume
  Documentation: bindings: add description of phy for sdhci-of-arasan
  mmc: sdhci: Fix override of timeout clk wrt max_busy_timeout
  mmc: mmci: Remove unnecessary header file
  mmc: sdhci-acpi: add QCOM controllers
  mmc: tegra: implement memcomp pad calibration
  mmc: mediatek: Use mmc_regulator_set_vqmmc in start_signal_voltage_switch
  mmc: mediatek: Change signal voltage error to dev_dbg()
  mmc: sh_mmcif, tmio: Use ARCH_RENESAS
  ...
This commit is contained in:
Linus Torvalds 2016-03-21 14:35:52 -07:00
commit e531cdf50a
64 changed files with 1173 additions and 779 deletions

View File

@ -1,11 +1,12 @@
Device Tree Bindings for the Arasan SDHCI Controller Device Tree Bindings for the Arasan SDHCI Controller
The bindings follow the mmc[1], clock[2] and interrupt[3] bindings. Only The bindings follow the mmc[1], clock[2], interrupt[3] and phy[4] bindings.
deviations are documented here. Only deviations are documented here.
[1] Documentation/devicetree/bindings/mmc/mmc.txt [1] Documentation/devicetree/bindings/mmc/mmc.txt
[2] Documentation/devicetree/bindings/clock/clock-bindings.txt [2] Documentation/devicetree/bindings/clock/clock-bindings.txt
[3] Documentation/devicetree/bindings/interrupt-controller/interrupts.txt [3] Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
[4] Documentation/devicetree/bindings/phy/phy-bindings.txt
Required Properties: Required Properties:
- compatible: Compatibility string. Must be 'arasan,sdhci-8.9a' or - compatible: Compatibility string. Must be 'arasan,sdhci-8.9a' or
@ -17,6 +18,10 @@ Required Properties:
- interrupt-parent: Phandle for the interrupt controller that services - interrupt-parent: Phandle for the interrupt controller that services
interrupts for this device. interrupts for this device.
Required Properties for "arasan,sdhci-5.1":
- phys: From PHY bindings: Phandle for the Generic PHY for arasan.
- phy-names: MUST be "phy_arasan".
Example: Example:
sdhci@e0100000 { sdhci@e0100000 {
compatible = "arasan,sdhci-8.9a"; compatible = "arasan,sdhci-8.9a";
@ -26,3 +31,14 @@ Example:
interrupt-parent = <&gic>; interrupt-parent = <&gic>;
interrupts = <0 24 4>; interrupts = <0 24 4>;
} ; } ;
sdhci@e2800000 {
compatible = "arasan,sdhci-5.1";
reg = <0xe2800000 0x1000>;
clock-names = "clk_xin", "clk_ahb";
clocks = <&cru 8>, <&cru 18>;
interrupt-parent = <&gic>;
interrupts = <0 24 4>;
phys = <&emmc_phy>;
phy-names = "phy_arasan";
} ;

View File

@ -4,7 +4,10 @@ This file documents differences between the core properties described
by mmc.txt and the properties that represent the IPROC SDHCI controller. by mmc.txt and the properties that represent the IPROC SDHCI controller.
Required properties: Required properties:
- compatible : Should be "brcm,sdhci-iproc-cygnus". - compatible : Should be one of the following
"brcm,bcm2835-sdhci"
"brcm,sdhci-iproc-cygnus"
- clocks : The clock feeding the SDHCI controller. - clocks : The clock feeding the SDHCI controller.
Optional properties: Optional properties:

View File

@ -0,0 +1,29 @@
* Microchip PIC32 SDHCI Controller
This file documents differences between the core properties in mmc.txt
and the properties used by the sdhci-pic32 driver.
Required properties:
- compatible: Should be "microchip,pic32mzda-sdhci"
- interrupts: Should contain interrupt
- clock-names: Should be "base_clk", "sys_clk".
See: Documentation/devicetree/bindings/resource-names.txt
- clocks: Phandle to the clock.
See: Documentation/devicetree/bindings/clock/clock-bindings.txt
- pinctrl-names: A pinctrl state names "default" must be defined.
- pinctrl-0: Phandle referencing pin configuration of the SDHCI controller.
See: Documentation/devicetree/bindings/pinctrl/pinctrl-binding.txt
Example:
sdhci@1f8ec000 {
compatible = "microchip,pic32mzda-sdhci";
reg = <0x1f8ec000 0x100>;
interrupts = <191 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&REFCLKO4>, <&PBCLK5>;
clock-names = "base_clk", "sys_clk";
bus-width = <4>;
cap-sd-highspeed;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_sdhc1>;
};

View File

@ -22,6 +22,7 @@ Required properties:
"renesas,sdhi-r8a7792" - SDHI IP on R8A7792 SoC "renesas,sdhi-r8a7792" - SDHI IP on R8A7792 SoC
"renesas,sdhi-r8a7793" - SDHI IP on R8A7793 SoC "renesas,sdhi-r8a7793" - SDHI IP on R8A7793 SoC
"renesas,sdhi-r8a7794" - SDHI IP on R8A7794 SoC "renesas,sdhi-r8a7794" - SDHI IP on R8A7794 SoC
"renesas,sdhi-r8a7795" - SDHI IP on R8A7795 SoC
Optional properties: Optional properties:
- toshiba,mmc-wrprotect-disable: write-protect detection is unavailable - toshiba,mmc-wrprotect-disable: write-protect detection is unavailable

View File

@ -9836,10 +9836,12 @@ S: Maintained
F: drivers/mmc/host/sdricoh_cs.c F: drivers/mmc/host/sdricoh_cs.c
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER
M: Adrian Hunter <adrian.hunter@intel.com>
L: linux-mmc@vger.kernel.org L: linux-mmc@vger.kernel.org
S: Orphan T: git git://git.infradead.org/users/ahunter/linux-sdhci.git
F: drivers/mmc/host/sdhci.* S: Maintained
F: drivers/mmc/host/sdhci-pltfm.[ch] F: drivers/mmc/host/sdhci*
F: include/linux/mmc/sdhci*
SECURE COMPUTING SECURE COMPUTING
M: Kees Cook <keescook@chromium.org> M: Kees Cook <keescook@chromium.org>

View File

@ -589,6 +589,14 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
struct mmc_card *card; struct mmc_card *card;
int err = 0, ioc_err = 0; int err = 0, ioc_err = 0;
/*
* The caller must have CAP_SYS_RAWIO, and must be calling this on the
* whole block device, not on a partition. This prevents overspray
* between sibling partitions.
*/
if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains))
return -EPERM;
idata = mmc_blk_ioctl_copy_from_user(ic_ptr); idata = mmc_blk_ioctl_copy_from_user(ic_ptr);
if (IS_ERR(idata)) if (IS_ERR(idata))
return PTR_ERR(idata); return PTR_ERR(idata);
@ -631,6 +639,14 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev,
int i, err = 0, ioc_err = 0; int i, err = 0, ioc_err = 0;
__u64 num_of_cmds; __u64 num_of_cmds;
/*
* The caller must have CAP_SYS_RAWIO, and must be calling this on the
* whole block device, not on a partition. This prevents overspray
* between sibling partitions.
*/
if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains))
return -EPERM;
if (copy_from_user(&num_of_cmds, &user->num_of_cmds, if (copy_from_user(&num_of_cmds, &user->num_of_cmds,
sizeof(num_of_cmds))) sizeof(num_of_cmds)))
return -EFAULT; return -EFAULT;
@ -688,14 +704,6 @@ cmd_err:
static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode, static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
/*
* The caller must have CAP_SYS_RAWIO, and must be calling this on the
* whole block device, not on a partition. This prevents overspray
* between sibling partitions.
*/
if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains))
return -EPERM;
switch (cmd) { switch (cmd) {
case MMC_IOC_CMD: case MMC_IOC_CMD:
return mmc_blk_ioctl_cmd(bdev, return mmc_blk_ioctl_cmd(bdev,
@ -1362,8 +1370,8 @@ static int mmc_blk_err_check(struct mmc_card *card,
if (brq->data.error) { if (brq->data.error) {
if (need_retune && !brq->retune_retry_done) { if (need_retune && !brq->retune_retry_done) {
pr_info("%s: retrying because a re-tune was needed\n", pr_debug("%s: retrying because a re-tune was needed\n",
req->rq_disk->disk_name); req->rq_disk->disk_name);
brq->retune_retry_done = 1; brq->retune_retry_done = 1;
return MMC_BLK_RETRY; return MMC_BLK_RETRY;
} }
@ -1524,13 +1532,13 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
} }
if (rq_data_dir(req) == READ) { if (rq_data_dir(req) == READ) {
brq->cmd.opcode = readcmd; brq->cmd.opcode = readcmd;
brq->data.flags |= MMC_DATA_READ; brq->data.flags = MMC_DATA_READ;
if (brq->mrq.stop) if (brq->mrq.stop)
brq->stop.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | brq->stop.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 |
MMC_CMD_AC; MMC_CMD_AC;
} else { } else {
brq->cmd.opcode = writecmd; brq->cmd.opcode = writecmd;
brq->data.flags |= MMC_DATA_WRITE; brq->data.flags = MMC_DATA_WRITE;
if (brq->mrq.stop) if (brq->mrq.stop)
brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B |
MMC_CMD_AC; MMC_CMD_AC;
@ -1799,7 +1807,7 @@ static void mmc_blk_packed_hdr_wrq_prep(struct mmc_queue_req *mqrq,
brq->data.blksz = 512; brq->data.blksz = 512;
brq->data.blocks = packed->blocks + hdr_blocks; brq->data.blocks = packed->blocks + hdr_blocks;
brq->data.flags |= MMC_DATA_WRITE; brq->data.flags = MMC_DATA_WRITE;
brq->stop.opcode = MMC_STOP_TRANSMISSION; brq->stop.opcode = MMC_STOP_TRANSMISSION;
brq->stop.arg = 0; brq->stop.arg = 0;

View File

@ -2829,6 +2829,7 @@ static int mtf_testlist_show(struct seq_file *sf, void *data)
mutex_lock(&mmc_test_lock); mutex_lock(&mmc_test_lock);
seq_printf(sf, "0:\tRun all tests\n");
for (i = 0; i < ARRAY_SIZE(mmc_test_cases); i++) for (i = 0; i < ARRAY_SIZE(mmc_test_cases); i++)
seq_printf(sf, "%d:\t%s\n", i+1, mmc_test_cases[i].name); seq_printf(sf, "%d:\t%s\n", i+1, mmc_test_cases[i].name);

View File

@ -1033,7 +1033,7 @@ static inline void mmc_set_ios(struct mmc_host *host)
"width %u timing %u\n", "width %u timing %u\n",
mmc_hostname(host), ios->clock, ios->bus_mode, mmc_hostname(host), ios->clock, ios->bus_mode,
ios->power_mode, ios->chip_select, ios->vdd, ios->power_mode, ios->chip_select, ios->vdd,
ios->bus_width, ios->timing); 1 << ios->bus_width, ios->timing);
host->ops->set_ios(host, ios); host->ops->set_ios(host, ios);
} }
@ -1079,7 +1079,8 @@ int mmc_execute_tuning(struct mmc_card *card)
err = host->ops->execute_tuning(host, opcode); err = host->ops->execute_tuning(host, opcode);
if (err) if (err)
pr_err("%s: tuning execution failed\n", mmc_hostname(host)); pr_err("%s: tuning execution failed: %d\n",
mmc_hostname(host), err);
else else
mmc_retune_enable(host); mmc_retune_enable(host);
@ -1204,8 +1205,9 @@ EXPORT_SYMBOL(mmc_vddrange_to_ocrmask);
* @np: The device node need to be parsed. * @np: The device node need to be parsed.
* @mask: mask of voltages available for MMC/SD/SDIO * @mask: mask of voltages available for MMC/SD/SDIO
* *
* 1. Return zero on success. * Parse the "voltage-ranges" DT property, returning zero if it is not
* 2. Return negative errno: voltage-range is invalid. * found, negative errno if the voltage-range specification is invalid,
* or one if the voltage-range is specified and successfully parsed.
*/ */
int mmc_of_parse_voltage(struct device_node *np, u32 *mask) int mmc_of_parse_voltage(struct device_node *np, u32 *mask)
{ {
@ -1214,8 +1216,12 @@ int mmc_of_parse_voltage(struct device_node *np, u32 *mask)
voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges); voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges);
num_ranges = num_ranges / sizeof(*voltage_ranges) / 2; num_ranges = num_ranges / sizeof(*voltage_ranges) / 2;
if (!voltage_ranges || !num_ranges) { if (!voltage_ranges) {
pr_info("%s: voltage-ranges unspecified\n", np->full_name); pr_debug("%s: voltage-ranges unspecified\n", np->full_name);
return 0;
}
if (!num_ranges) {
pr_err("%s: voltage-ranges empty\n", np->full_name);
return -EINVAL; return -EINVAL;
} }
@ -1234,7 +1240,7 @@ int mmc_of_parse_voltage(struct device_node *np, u32 *mask)
*mask |= ocr_mask; *mask |= ocr_mask;
} }
return 0; return 1;
} }
EXPORT_SYMBOL(mmc_of_parse_voltage); EXPORT_SYMBOL(mmc_of_parse_voltage);
@ -2532,7 +2538,7 @@ int mmc_detect_card_removed(struct mmc_host *host)
if (!card) if (!card)
return 1; return 1;
if (host->caps & MMC_CAP_NONREMOVABLE) if (!mmc_card_is_removable(host))
return 0; return 0;
ret = mmc_card_removed(card); ret = mmc_card_removed(card);
@ -2570,7 +2576,7 @@ void mmc_rescan(struct work_struct *work)
return; return;
/* If there is a non-removable card registered, only scan once */ /* If there is a non-removable card registered, only scan once */
if ((host->caps & MMC_CAP_NONREMOVABLE) && host->rescan_entered) if (!mmc_card_is_removable(host) && host->rescan_entered)
return; return;
host->rescan_entered = 1; host->rescan_entered = 1;
@ -2587,8 +2593,7 @@ void mmc_rescan(struct work_struct *work)
* if there is a _removable_ card registered, check whether it is * if there is a _removable_ card registered, check whether it is
* still present * still present
*/ */
if (host->bus_ops && !host->bus_dead if (host->bus_ops && !host->bus_dead && mmc_card_is_removable(host))
&& !(host->caps & MMC_CAP_NONREMOVABLE))
host->bus_ops->detect(host); host->bus_ops->detect(host);
host->detect_change = 0; host->detect_change = 0;
@ -2613,7 +2618,7 @@ void mmc_rescan(struct work_struct *work)
mmc_bus_put(host); mmc_bus_put(host);
mmc_claim_host(host); mmc_claim_host(host);
if (!(host->caps & MMC_CAP_NONREMOVABLE) && host->ops->get_cd && if (mmc_card_is_removable(host) && host->ops->get_cd &&
host->ops->get_cd(host) == 0) { host->ops->get_cd(host) == 0) {
mmc_power_off(host); mmc_power_off(host);
mmc_release_host(host); mmc_release_host(host);

View File

@ -220,7 +220,7 @@ static int mmc_clock_opt_set(void *data, u64 val)
struct mmc_host *host = data; struct mmc_host *host = data;
/* We need this check due to input value is u64 */ /* We need this check due to input value is u64 */
if (val > host->f_max) if (val != 0 && (val > host->f_max || val < host->f_min))
return -EINVAL; return -EINVAL;
mmc_claim_host(host); mmc_claim_host(host);

View File

@ -339,6 +339,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
host->class_dev.parent = dev; host->class_dev.parent = dev;
host->class_dev.class = &mmc_host_class; host->class_dev.class = &mmc_host_class;
device_initialize(&host->class_dev); device_initialize(&host->class_dev);
device_enable_async_suspend(&host->class_dev);
if (mmc_gpio_alloc(host)) { if (mmc_gpio_alloc(host)) {
put_device(&host->class_dev); put_device(&host->class_dev);

View File

@ -501,7 +501,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
card->ext_csd.raw_bkops_status = card->ext_csd.raw_bkops_status =
ext_csd[EXT_CSD_BKOPS_STATUS]; ext_csd[EXT_CSD_BKOPS_STATUS];
if (!card->ext_csd.man_bkops_en) if (!card->ext_csd.man_bkops_en)
pr_info("%s: MAN_BKOPS_EN bit is not set\n", pr_debug("%s: MAN_BKOPS_EN bit is not set\n",
mmc_hostname(card->host)); mmc_hostname(card->host));
} }
@ -945,7 +945,7 @@ static int mmc_select_bus_width(struct mmc_card *card)
break; break;
} else { } else {
pr_warn("%s: switch to bus width %d failed\n", pr_warn("%s: switch to bus width %d failed\n",
mmc_hostname(host), ext_csd_bits[idx]); mmc_hostname(host), 1 << bus_width);
} }
} }

View File

@ -90,7 +90,6 @@ int mmc_send_status(struct mmc_card *card, u32 *status)
static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
{ {
int err;
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
BUG_ON(!host); BUG_ON(!host);
@ -105,11 +104,7 @@ static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
cmd.flags = MMC_RSP_NONE | MMC_CMD_AC; cmd.flags = MMC_RSP_NONE | MMC_CMD_AC;
} }
err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); return mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
if (err)
return err;
return 0;
} }
int mmc_select_card(struct mmc_card *card) int mmc_select_card(struct mmc_card *card)
@ -244,7 +239,6 @@ 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 err;
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
BUG_ON(!card); BUG_ON(!card);
@ -254,11 +248,7 @@ int mmc_set_relative_addr(struct mmc_card *card)
cmd.arg = card->rca << 16; cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); return mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
if (err)
return err;
return 0;
} }
static int static int
@ -743,7 +733,7 @@ mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
int mmc_bus_test(struct mmc_card *card, u8 bus_width) int mmc_bus_test(struct mmc_card *card, u8 bus_width)
{ {
int err, width; int width;
if (bus_width == MMC_BUS_WIDTH_8) if (bus_width == MMC_BUS_WIDTH_8)
width = 8; width = 8;
@ -759,8 +749,7 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width)
* is a problem. This improves chances that the test will work. * is a problem. This improves chances that the test will work.
*/ */
mmc_send_bus_test(card, card->host, MMC_BUS_TEST_W, width); mmc_send_bus_test(card, card->host, MMC_BUS_TEST_W, width);
err = mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width); return mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width);
return err;
} }
int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status) int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)

View File

@ -12,7 +12,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>

View File

@ -74,8 +74,6 @@ void mmc_decode_cid(struct mmc_card *card)
{ {
u32 *resp = card->raw_cid; u32 *resp = card->raw_cid;
memset(&card->cid, 0, sizeof(struct mmc_cid));
/* /*
* SD doesn't currently have a version field so we will * SD doesn't currently have a version field so we will
* have to assume we can parse this. * have to assume we can parse this.

View File

@ -120,7 +120,6 @@ EXPORT_SYMBOL(mmc_wait_for_app_cmd);
int mmc_app_set_bus_width(struct mmc_card *card, int width) int mmc_app_set_bus_width(struct mmc_card *card, int width)
{ {
int err;
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
BUG_ON(!card); BUG_ON(!card);
@ -140,11 +139,7 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width)
return -EINVAL; return -EINVAL;
} }
err = mmc_wait_for_app_cmd(card->host, card, &cmd, MMC_CMD_RETRIES); return mmc_wait_for_app_cmd(card->host, card, &cmd, MMC_CMD_RETRIES);
if (err)
return err;
return 0;
} }
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)

View File

@ -106,8 +106,6 @@ static int sdio_read_cccr(struct mmc_card *card, u32 ocr)
unsigned char data; unsigned char data;
unsigned char speed; unsigned char speed;
memset(&card->cccr, 0, sizeof(struct sdio_cccr));
ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CCCR, 0, &data); ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CCCR, 0, &data);
if (ret) if (ret)
goto out; goto out;

View File

@ -217,7 +217,6 @@ int sdio_reset(struct mmc_host *host)
else else
abort |= 0x08; abort |= 0x08;
ret = mmc_io_rw_direct_host(host, 1, 0, SDIO_CCCR_ABORT, abort, NULL); return mmc_io_rw_direct_host(host, 1, 0, SDIO_CCCR_ABORT, abort, NULL);
return ret;
} }

View File

@ -318,15 +318,15 @@ config MMC_SDHCI_F_SDH30
If unsure, say N. If unsure, say N.
config MMC_SDHCI_IPROC config MMC_SDHCI_IPROC
tristate "SDHCI platform support for the iProc SD/MMC Controller" tristate "SDHCI support for the BCM2835 & iProc SD/MMC Controller"
depends on ARCH_BCM_IPROC || COMPILE_TEST depends on ARCH_BCM2835 || ARCH_BCM_IPROC || COMPILE_TEST
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
default ARCH_BCM_IPROC default ARCH_BCM_IPROC
select MMC_SDHCI_IO_ACCESSORS select MMC_SDHCI_IO_ACCESSORS
help help
This selects the iProc SD/MMC controller. This selects the iProc SD/MMC controller.
If you have an IPROC platform with SD or MMC devices, If you have a BCM2835 or IPROC platform with SD or MMC devices,
say Y or M here. say Y or M here.
If unsure, say N. If unsure, say N.
@ -560,8 +560,8 @@ config MMC_TMIO
config MMC_SDHI config MMC_SDHI
tristate "SH-Mobile SDHI SD/SDIO controller support" tristate "SH-Mobile SDHI SD/SDIO controller support"
depends on SUPERH || ARM depends on SUPERH || ARM || ARM64
depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
select MMC_TMIO_CORE select MMC_TMIO_CORE
help help
This provides support for the SDHI SD/SDIO controller found in This provides support for the SDHI SD/SDIO controller found in
@ -673,8 +673,8 @@ config MMC_DW_ROCKCHIP
config MMC_SH_MMCIF config MMC_SH_MMCIF
tristate "SuperH Internal MMCIF support" tristate "SuperH Internal MMCIF support"
depends on MMC_BLOCK && HAS_DMA depends on HAS_DMA
depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
help help
This selects the MMC Host Interface controller (MMCIF). This selects the MMC Host Interface controller (MMCIF).
@ -786,3 +786,14 @@ config MMC_MTK
If you have a machine with a integrated SD/MMC card reader, say Y or M here. If you have a machine with a integrated SD/MMC card reader, say Y or M here.
This is needed if support for any SD/SDIO/MMC devices is required. This is needed if support for any SD/SDIO/MMC devices is required.
If unsure, say N. If unsure, say N.
config MMC_SDHCI_MICROCHIP_PIC32
tristate "Microchip PIC32MZDA SDHCI support"
depends on MMC_SDHCI && PIC32MZDA && MMC_SDHCI_PLTFM
help
This selects the Secure Digital Host Controller Interface (SDHCI)
for PIC32MZDA platform.
If you have a controller with this interface, say Y or M here.
If unsure, say N.

View File

@ -75,6 +75,7 @@ obj-$(CONFIG_MMC_SDHCI_BCM2835) += sdhci-bcm2835.o
obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o
obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o
obj-$(CONFIG_MMC_SDHCI_ST) += sdhci-st.o obj-$(CONFIG_MMC_SDHCI_ST) += sdhci-st.o
obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32) += sdhci-pic32.o
ifeq ($(CONFIG_CB710_DEBUG),y) ifeq ($(CONFIG_CB710_DEBUG),y)
CFLAGS-cb710-mmc += -DDEBUG CFLAGS-cb710-mmc += -DDEBUG

View File

@ -848,9 +848,7 @@ static u32 atmci_prepare_command(struct mmc_host *mmc,
if (cmd->opcode == SD_IO_RW_EXTENDED) { if (cmd->opcode == SD_IO_RW_EXTENDED) {
cmdr |= ATMCI_CMDR_SDIO_BLOCK; cmdr |= ATMCI_CMDR_SDIO_BLOCK;
} else { } else {
if (data->flags & MMC_DATA_STREAM) if (data->blocks > 1)
cmdr |= ATMCI_CMDR_STREAM;
else if (data->blocks > 1)
cmdr |= ATMCI_CMDR_MULTI_BLOCK; cmdr |= ATMCI_CMDR_MULTI_BLOCK;
else else
cmdr |= ATMCI_CMDR_BLOCK; cmdr |= ATMCI_CMDR_BLOCK;
@ -1371,10 +1369,7 @@ static void atmci_start_request(struct atmel_mci *host,
host->stop_cmdr |= ATMCI_CMDR_STOP_XFER; host->stop_cmdr |= ATMCI_CMDR_STOP_XFER;
if (!(data->flags & MMC_DATA_WRITE)) if (!(data->flags & MMC_DATA_WRITE))
host->stop_cmdr |= ATMCI_CMDR_TRDIR_READ; host->stop_cmdr |= ATMCI_CMDR_TRDIR_READ;
if (data->flags & MMC_DATA_STREAM) host->stop_cmdr |= ATMCI_CMDR_MULTI_BLOCK;
host->stop_cmdr |= ATMCI_CMDR_STREAM;
else
host->stop_cmdr |= ATMCI_CMDR_MULTI_BLOCK;
} }
/* /*
@ -2443,7 +2438,7 @@ static int atmci_configure_dma(struct atmel_mci *host)
struct mci_platform_data *pdata = host->pdev->dev.platform_data; struct mci_platform_data *pdata = host->pdev->dev.platform_data;
dma_cap_mask_t mask; dma_cap_mask_t mask;
if (!pdata->dma_filter) if (!pdata || !pdata->dma_filter)
return -ENODEV; return -ENODEV;
dma_cap_zero(mask); dma_cap_zero(mask);

View File

@ -126,9 +126,6 @@ static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data)
length = data->blksz * data->blocks; length = data->blksz * data->blocks;
bfin_write_SDH_DATA_LGTH(length); bfin_write_SDH_DATA_LGTH(length);
if (data->flags & MMC_DATA_STREAM)
data_ctl |= DTX_MODE;
if (data->flags & MMC_DATA_READ) if (data->flags & MMC_DATA_READ)
data_ctl |= DTX_DIR; data_ctl |= DTX_DIR;
/* Only supports power-of-2 block size */ /* Only supports power-of-2 block size */

View File

@ -346,10 +346,6 @@ static void mmc_davinci_start_command(struct mmc_davinci_host *host,
if (cmd->data) if (cmd->data)
cmd_reg |= MMCCMD_WDATX; cmd_reg |= MMCCMD_WDATX;
/* Setting whether stream or block transfer */
if (cmd->flags & MMC_DATA_STREAM)
cmd_reg |= MMCCMD_STRMTP;
/* Setting whether data read or write */ /* Setting whether data read or write */
if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE)
cmd_reg |= MMCCMD_DTRW; cmd_reg |= MMCCMD_DTRW;
@ -568,8 +564,7 @@ mmc_davinci_prepare_data(struct mmc_davinci_host *host, struct mmc_request *req)
return; return;
} }
dev_dbg(mmc_dev(host->mmc), "%s %s, %d blocks of %d bytes\n", dev_dbg(mmc_dev(host->mmc), "%s, %d blocks of %d bytes\n",
(data->flags & MMC_DATA_STREAM) ? "stream" : "block",
(data->flags & MMC_DATA_WRITE) ? "write" : "read", (data->flags & MMC_DATA_WRITE) ? "write" : "read",
data->blocks, data->blksz); data->blocks, data->blksz);
dev_dbg(mmc_dev(host->mmc), " DTO %d cycles + %d ns\n", dev_dbg(mmc_dev(host->mmc), " DTO %d cycles + %d ns\n",
@ -584,22 +579,18 @@ mmc_davinci_prepare_data(struct mmc_davinci_host *host, struct mmc_request *req)
writel(data->blksz, host->base + DAVINCI_MMCBLEN); writel(data->blksz, host->base + DAVINCI_MMCBLEN);
/* Configure the FIFO */ /* Configure the FIFO */
switch (data->flags & MMC_DATA_WRITE) { if (data->flags & MMC_DATA_WRITE) {
case MMC_DATA_WRITE:
host->data_dir = DAVINCI_MMC_DATADIR_WRITE; host->data_dir = DAVINCI_MMC_DATADIR_WRITE;
writel(fifo_lev | MMCFIFOCTL_FIFODIR_WR | MMCFIFOCTL_FIFORST, writel(fifo_lev | MMCFIFOCTL_FIFODIR_WR | MMCFIFOCTL_FIFORST,
host->base + DAVINCI_MMCFIFOCTL); host->base + DAVINCI_MMCFIFOCTL);
writel(fifo_lev | MMCFIFOCTL_FIFODIR_WR, writel(fifo_lev | MMCFIFOCTL_FIFODIR_WR,
host->base + DAVINCI_MMCFIFOCTL); host->base + DAVINCI_MMCFIFOCTL);
break; } else {
default:
host->data_dir = DAVINCI_MMC_DATADIR_READ; host->data_dir = DAVINCI_MMC_DATADIR_READ;
writel(fifo_lev | MMCFIFOCTL_FIFODIR_RD | MMCFIFOCTL_FIFORST, writel(fifo_lev | MMCFIFOCTL_FIFODIR_RD | MMCFIFOCTL_FIFORST,
host->base + DAVINCI_MMCFIFOCTL); host->base + DAVINCI_MMCFIFOCTL);
writel(fifo_lev | MMCFIFOCTL_FIFODIR_RD, writel(fifo_lev | MMCFIFOCTL_FIFODIR_RD,
host->base + DAVINCI_MMCFIFOCTL); host->base + DAVINCI_MMCFIFOCTL);
break;
} }
host->buffer = NULL; host->buffer = NULL;

View File

@ -145,6 +145,16 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
mci_writel(host, CLKSEL64, clksel); mci_writel(host, CLKSEL64, clksel);
else else
mci_writel(host, CLKSEL, clksel); mci_writel(host, CLKSEL, clksel);
/*
* Exynos4412 and Exynos5250 extends the use of CMD register with the
* use of bit 29 (which is reserved on standard MSHC controllers) for
* optionally bypassing the HOLD register for command and data. The
* HOLD register should be bypassed in case there is no phase shift
* applied on CMD/DATA that is sent to the card.
*/
if (!SDMMC_CLKSEL_GET_DRV_WD3(clksel))
set_bit(DW_MMC_CARD_NO_USE_HOLD, &host->cur_slot->flags);
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
@ -202,26 +212,6 @@ static int dw_mci_exynos_resume_noirq(struct device *dev)
#define dw_mci_exynos_resume_noirq NULL #define dw_mci_exynos_resume_noirq NULL
#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM_SLEEP */
static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr)
{
struct dw_mci_exynos_priv_data *priv = host->priv;
/*
* Exynos4412 and Exynos5250 extends the use of CMD register with the
* use of bit 29 (which is reserved on standard MSHC controllers) for
* optionally bypassing the HOLD register for command and data. The
* HOLD register should be bypassed in case there is no phase shift
* applied on CMD/DATA that is sent to the card.
*/
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) {
if (SDMMC_CLKSEL_GET_DRV_WD3(mci_readl(host, CLKSEL64)))
*cmdr |= SDMMC_CMD_USE_HOLD_REG;
} else {
if (SDMMC_CLKSEL_GET_DRV_WD3(mci_readl(host, CLKSEL)))
*cmdr |= SDMMC_CMD_USE_HOLD_REG;
}
}
static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing) static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
{ {
struct dw_mci_exynos_priv_data *priv = host->priv; struct dw_mci_exynos_priv_data *priv = host->priv;
@ -500,7 +490,6 @@ static const struct dw_mci_drv_data exynos_drv_data = {
.caps = exynos_dwmmc_caps, .caps = exynos_dwmmc_caps,
.init = dw_mci_exynos_priv_init, .init = dw_mci_exynos_priv_init,
.setup_clock = dw_mci_exynos_setup_clock, .setup_clock = dw_mci_exynos_setup_clock,
.prepare_command = dw_mci_exynos_prepare_command,
.set_ios = dw_mci_exynos_set_ios, .set_ios = dw_mci_exynos_set_ios,
.parse_dt = dw_mci_exynos_parse_dt, .parse_dt = dw_mci_exynos_parse_dt,
.execute_tuning = dw_mci_exynos_execute_tuning, .execute_tuning = dw_mci_exynos_execute_tuning,

View File

@ -26,19 +26,6 @@
#include "dw_mmc.h" #include "dw_mmc.h"
#include "dw_mmc-pltfm.h" #include "dw_mmc-pltfm.h"
static void dw_mci_pltfm_prepare_command(struct dw_mci *host, u32 *cmdr)
{
*cmdr |= SDMMC_CMD_USE_HOLD_REG;
}
static const struct dw_mci_drv_data socfpga_drv_data = {
.prepare_command = dw_mci_pltfm_prepare_command,
};
static const struct dw_mci_drv_data pistachio_drv_data = {
.prepare_command = dw_mci_pltfm_prepare_command,
};
int dw_mci_pltfm_register(struct platform_device *pdev, 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)
{ {
@ -94,10 +81,8 @@ EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops);
static const struct of_device_id dw_mci_pltfm_match[] = { 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 }, { .compatible = "img,pistachio-dw-mshc", },
{ .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);

View File

@ -26,11 +26,6 @@ struct dw_mci_rockchip_priv_data {
int default_sample_phase; int default_sample_phase;
}; };
static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr)
{
*cmdr |= SDMMC_CMD_USE_HOLD_REG;
}
static int dw_mci_rk3288_setup_clock(struct dw_mci *host) static int dw_mci_rk3288_setup_clock(struct dw_mci *host)
{ {
host->bus_hz /= RK3288_CLKGEN_DIV; host->bus_hz /= RK3288_CLKGEN_DIV;
@ -240,12 +235,10 @@ static int dw_mci_rockchip_init(struct dw_mci *host)
} }
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,
.init = dw_mci_rockchip_init, .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,
.set_ios = dw_mci_rk3288_set_ios, .set_ios = dw_mci_rk3288_set_ios,
.execute_tuning = dw_mci_rk3288_execute_tuning, .execute_tuning = dw_mci_rk3288_execute_tuning,
.parse_dt = dw_mci_rk3288_parse_dt, .parse_dt = dw_mci_rk3288_parse_dt,

View File

@ -234,7 +234,6 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
struct mmc_data *data; struct mmc_data *data;
struct dw_mci_slot *slot = mmc_priv(mmc); struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci *host = slot->host; struct dw_mci *host = slot->host;
const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
u32 cmdr; u32 cmdr;
cmd->error = -EINPROGRESS; cmd->error = -EINPROGRESS;
@ -290,14 +289,12 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
data = cmd->data; data = cmd->data;
if (data) { if (data) {
cmdr |= SDMMC_CMD_DAT_EXP; cmdr |= SDMMC_CMD_DAT_EXP;
if (data->flags & MMC_DATA_STREAM)
cmdr |= SDMMC_CMD_STRM_MODE;
if (data->flags & MMC_DATA_WRITE) if (data->flags & MMC_DATA_WRITE)
cmdr |= SDMMC_CMD_DAT_WR; cmdr |= SDMMC_CMD_DAT_WR;
} }
if (drv_data && drv_data->prepare_command) if (!test_bit(DW_MMC_CARD_NO_USE_HOLD, &slot->flags))
drv_data->prepare_command(slot->host, &cmdr); cmdr |= SDMMC_CMD_USE_HOLD_REG;
return cmdr; return cmdr;
} }
@ -1450,12 +1447,11 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
{ {
int present; int present;
struct dw_mci_slot *slot = mmc_priv(mmc); struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci_board *brd = slot->host->pdata;
struct dw_mci *host = slot->host; struct dw_mci *host = slot->host;
int gpio_cd = mmc_gpio_get_cd(mmc); int gpio_cd = mmc_gpio_get_cd(mmc);
/* Use platform get_cd function, else try onboard card detect */ /* Use platform get_cd function, else try onboard card detect */
if ((brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) || if ((mmc->caps & MMC_CAP_NEEDS_POLL) ||
(mmc->caps & MMC_CAP_NONREMOVABLE)) (mmc->caps & MMC_CAP_NONREMOVABLE))
present = 1; present = 1;
else if (!IS_ERR_VALUE(gpio_cd)) else if (!IS_ERR_VALUE(gpio_cd))
@ -1477,6 +1473,34 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
return present; return present;
} }
static void dw_mci_hw_reset(struct mmc_host *mmc)
{
struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci *host = slot->host;
int reset;
if (host->use_dma == TRANS_MODE_IDMAC)
dw_mci_idmac_reset(host);
if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_DMA_RESET |
SDMMC_CTRL_FIFO_RESET))
return;
/*
* According to eMMC spec, card reset procedure:
* tRstW >= 1us: RST_n pulse width
* tRSCA >= 200us: RST_n to Command time
* tRSTH >= 1us: RST_n high period
*/
reset = mci_readl(host, RST_N);
reset &= ~(SDMMC_RST_HWACTIVE << slot->id);
mci_writel(host, RST_N, reset);
usleep_range(1, 2);
reset |= SDMMC_RST_HWACTIVE << slot->id;
mci_writel(host, RST_N, reset);
usleep_range(200, 300);
}
static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card) static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card)
{ {
struct dw_mci_slot *slot = mmc_priv(mmc); struct dw_mci_slot *slot = mmc_priv(mmc);
@ -1563,6 +1587,7 @@ static const struct mmc_host_ops dw_mci_ops = {
.set_ios = dw_mci_set_ios, .set_ios = dw_mci_set_ios,
.get_ro = dw_mci_get_ro, .get_ro = dw_mci_get_ro,
.get_cd = dw_mci_get_cd, .get_cd = dw_mci_get_cd,
.hw_reset = dw_mci_hw_reset,
.enable_sdio_irq = dw_mci_enable_sdio_irq, .enable_sdio_irq = dw_mci_enable_sdio_irq,
.execute_tuning = dw_mci_execute_tuning, .execute_tuning = dw_mci_execute_tuning,
.card_busy = dw_mci_card_busy, .card_busy = dw_mci_card_busy,
@ -2840,23 +2865,13 @@ static void dw_mci_dto_timer(unsigned long arg)
} }
#ifdef CONFIG_OF #ifdef CONFIG_OF
static struct dw_mci_of_quirks {
char *quirk;
int id;
} of_quirks[] = {
{
.quirk = "broken-cd",
.id = DW_MCI_QUIRK_BROKEN_CARD_DETECTION,
},
};
static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
{ {
struct dw_mci_board *pdata; struct dw_mci_board *pdata;
struct device *dev = host->dev; struct device *dev = host->dev;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
const struct dw_mci_drv_data *drv_data = host->drv_data; const struct dw_mci_drv_data *drv_data = host->drv_data;
int idx, ret; int ret;
u32 clock_frequency; u32 clock_frequency;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
@ -2864,17 +2879,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
/* find out number of slots supported */ /* find out number of slots supported */
if (of_property_read_u32(dev->of_node, "num-slots", of_property_read_u32(np, "num-slots", &pdata->num_slots);
&pdata->num_slots)) {
dev_info(dev,
"num-slots property not found, assuming 1 slot is available\n");
pdata->num_slots = 1;
}
/* get quirks */
for (idx = 0; idx < ARRAY_SIZE(of_quirks); idx++)
if (of_get_property(np, of_quirks[idx].quirk, NULL))
pdata->quirks |= of_quirks[idx].id;
if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth)) if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
dev_info(dev, dev_info(dev,
@ -2908,18 +2913,19 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
static void dw_mci_enable_cd(struct dw_mci *host) static void dw_mci_enable_cd(struct dw_mci *host)
{ {
struct dw_mci_board *brd = host->pdata;
unsigned long irqflags; unsigned long irqflags;
u32 temp; u32 temp;
int i; int i;
struct dw_mci_slot *slot;
/* No need for CD if broken card detection */ /*
if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) * No need for CD if all slots have a non-error GPIO
return; * as well as broken card detection is found.
*/
/* No need for CD if all slots have a non-error GPIO */
for (i = 0; i < host->num_slots; i++) { for (i = 0; i < host->num_slots; i++) {
struct dw_mci_slot *slot = host->slot[i]; slot = host->slot[i];
if (slot->mmc->caps & MMC_CAP_NEEDS_POLL)
return;
if (IS_ERR_VALUE(mmc_gpio_get_cd(slot->mmc))) if (IS_ERR_VALUE(mmc_gpio_get_cd(slot->mmc)))
break; break;
@ -2949,12 +2955,6 @@ int dw_mci_probe(struct dw_mci *host)
} }
} }
if (host->pdata->num_slots < 1) {
dev_err(host->dev,
"Platform data must supply num_slots.\n");
return -ENODEV;
}
host->biu_clk = devm_clk_get(host->dev, "biu"); host->biu_clk = devm_clk_get(host->dev, "biu");
if (IS_ERR(host->biu_clk)) { if (IS_ERR(host->biu_clk)) {
dev_dbg(host->dev, "biu clock not available\n"); dev_dbg(host->dev, "biu clock not available\n");
@ -3052,8 +3052,10 @@ int dw_mci_probe(struct dw_mci *host)
} }
/* Reset all blocks */ /* Reset all blocks */
if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) if (!dw_mci_ctrl_reset(host, SDMMC_CTRL_ALL_RESET_FLAGS)) {
return -ENODEV; ret = -ENODEV;
goto err_clk_ciu;
}
host->dma_ops = host->pdata->dma_ops; host->dma_ops = host->pdata->dma_ops;
dw_mci_init_dma(host); dw_mci_init_dma(host);
@ -3111,13 +3113,20 @@ int dw_mci_probe(struct dw_mci *host)
if (host->pdata->num_slots) if (host->pdata->num_slots)
host->num_slots = host->pdata->num_slots; host->num_slots = host->pdata->num_slots;
else else
host->num_slots = SDMMC_GET_SLOT_NUM(mci_readl(host, HCON)); host->num_slots = 1;
if (host->num_slots < 1 ||
host->num_slots > SDMMC_GET_SLOT_NUM(mci_readl(host, HCON))) {
dev_err(host->dev,
"Platform data must supply correct num_slots.\n");
ret = -ENODEV;
goto err_clk_ciu;
}
/* /*
* Enable interrupts for command done, data over, data empty, * Enable interrupts for command done, data over, data empty,
* receive ready and error such as transmit, receive timeout, crc error * receive ready and error such as transmit, receive timeout, crc error
*/ */
mci_writel(host, RINTSTS, 0xFFFFFFFF);
mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
SDMMC_INT_TXDR | SDMMC_INT_RXDR | SDMMC_INT_TXDR | SDMMC_INT_RXDR |
DW_MCI_ERROR_FLAGS); DW_MCI_ERROR_FLAGS);

View File

@ -46,6 +46,7 @@
#define SDMMC_VERID 0x06c #define SDMMC_VERID 0x06c
#define SDMMC_HCON 0x070 #define SDMMC_HCON 0x070
#define SDMMC_UHS_REG 0x074 #define SDMMC_UHS_REG 0x074
#define SDMMC_RST_N 0x078
#define SDMMC_BMOD 0x080 #define SDMMC_BMOD 0x080
#define SDMMC_PLDMND 0x084 #define SDMMC_PLDMND 0x084
#define SDMMC_DBADDR 0x088 #define SDMMC_DBADDR 0x088
@ -169,6 +170,8 @@
#define SDMMC_IDMAC_ENABLE BIT(7) #define SDMMC_IDMAC_ENABLE BIT(7)
#define SDMMC_IDMAC_FB BIT(1) #define SDMMC_IDMAC_FB BIT(1)
#define SDMMC_IDMAC_SWRESET BIT(0) #define SDMMC_IDMAC_SWRESET BIT(0)
/* H/W reset */
#define SDMMC_RST_HWACTIVE 0x1
/* Version ID register define */ /* Version ID register define */
#define SDMMC_GET_VERID(x) ((x) & 0xFFFF) #define SDMMC_GET_VERID(x) ((x) & 0xFFFF)
/* Card read threshold */ /* Card read threshold */
@ -265,6 +268,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
#define DW_MMC_CARD_NO_LOW_PWR 2 #define DW_MMC_CARD_NO_LOW_PWR 2
#define DW_MMC_CARD_NO_USE_HOLD 3
int id; int id;
int sdio_id; int sdio_id;
}; };
@ -274,7 +278,6 @@ struct dw_mci_slot {
* @caps: mmc subsystem specified capabilities of the controller(s). * @caps: mmc subsystem specified capabilities of the controller(s).
* @init: early implementation specific initialization. * @init: early implementation specific initialization.
* @setup_clock: implementation specific clock configuration. * @setup_clock: implementation specific clock configuration.
* @prepare_command: handle CMD register extensions.
* @set_ios: handle bus specific extensions. * @set_ios: handle bus specific extensions.
* @parse_dt: parse implementation specific device tree properties. * @parse_dt: parse implementation specific device tree properties.
* @execute_tuning: implementation specific tuning procedure. * @execute_tuning: implementation specific tuning procedure.
@ -287,7 +290,6 @@ struct dw_mci_drv_data {
unsigned long *caps; unsigned long *caps;
int (*init)(struct dw_mci *host); int (*init)(struct dw_mci *host);
int (*setup_clock)(struct dw_mci *host); int (*setup_clock)(struct dw_mci *host);
void (*prepare_command)(struct dw_mci *host, u32 *cmdr);
void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios); void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
int (*parse_dt)(struct dw_mci *host); int (*parse_dt)(struct dw_mci *host);
int (*execute_tuning)(struct dw_mci_slot *slot, u32 opcode); int (*execute_tuning)(struct dw_mci_slot *slot, u32 opcode);

View File

@ -660,8 +660,6 @@ static void jz4740_mmc_send_command(struct jz4740_mmc_host *host,
cmdat |= JZ_MMC_CMDAT_DATA_EN; cmdat |= JZ_MMC_CMDAT_DATA_EN;
if (cmd->data->flags & MMC_DATA_WRITE) if (cmd->data->flags & MMC_DATA_WRITE)
cmdat |= JZ_MMC_CMDAT_WRITE; cmdat |= JZ_MMC_CMDAT_WRITE;
if (cmd->data->flags & MMC_DATA_STREAM)
cmdat |= JZ_MMC_CMDAT_STREAM;
if (host->use_dma) if (host->use_dma)
cmdat |= JZ_MMC_CMDAT_DMA_EN; cmdat |= JZ_MMC_CMDAT_DMA_EN;

View File

@ -1442,6 +1442,12 @@ static int mmc_spi_probe(struct spi_device *spi)
host->pdata->cd_debounce); host->pdata->cd_debounce);
if (status != 0) if (status != 0)
goto fail_add_host; goto fail_add_host;
/* The platform has a CD GPIO signal that may support
* interrupts, so let mmc_gpiod_request_cd_irq() decide
* if polling is needed or not.
*/
mmc->caps &= ~MMC_CAP_NEEDS_POLL;
mmc_gpiod_request_cd_irq(mmc); mmc_gpiod_request_cd_irq(mmc);
} }

View File

@ -40,7 +40,6 @@
#include <asm/div64.h> #include <asm/div64.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/sizes.h>
#include "mmci.h" #include "mmci.h"
#include "mmci_qcom_dml.h" #include "mmci_qcom_dml.h"

View File

@ -35,6 +35,7 @@
#include <linux/mmc/mmc.h> #include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h> #include <linux/mmc/sd.h>
#include <linux/mmc/sdio.h> #include <linux/mmc/sdio.h>
#include <linux/mmc/slot-gpio.h>
#define MAX_BD_NUM 1024 #define MAX_BD_NUM 1024
@ -1020,26 +1021,19 @@ static void msdc_set_buswidth(struct msdc_host *host, u32 width)
static int msdc_ops_switch_volt(struct mmc_host *mmc, struct mmc_ios *ios) static int msdc_ops_switch_volt(struct mmc_host *mmc, struct mmc_ios *ios)
{ {
struct msdc_host *host = mmc_priv(mmc); struct msdc_host *host = mmc_priv(mmc);
int min_uv, max_uv;
int ret = 0; int ret = 0;
if (!IS_ERR(mmc->supply.vqmmc)) { if (!IS_ERR(mmc->supply.vqmmc)) {
if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) { if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_330 &&
min_uv = 3300000; ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
max_uv = 3300000;
} else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
min_uv = 1800000;
max_uv = 1800000;
} else {
dev_err(host->dev, "Unsupported signal voltage!\n"); dev_err(host->dev, "Unsupported signal voltage!\n");
return -EINVAL; return -EINVAL;
} }
ret = regulator_set_voltage(mmc->supply.vqmmc, min_uv, max_uv); ret = mmc_regulator_set_vqmmc(mmc, ios);
if (ret) { if (ret) {
dev_err(host->dev, dev_dbg(host->dev, "Regulator set error %d (%d)\n",
"Regulator set error %d: %d - %d\n", ret, ios->signal_voltage);
ret, min_uv, max_uv);
} else { } else {
/* Apply different pinctrl settings for different signal voltage */ /* Apply different pinctrl settings for different signal voltage */
if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180)
@ -1452,6 +1446,7 @@ static struct mmc_host_ops mt_msdc_ops = {
.pre_req = msdc_pre_req, .pre_req = msdc_pre_req,
.request = msdc_ops_request, .request = msdc_ops_request,
.set_ios = msdc_ops_set_ios, .set_ios = msdc_ops_set_ios,
.get_ro = mmc_gpio_get_ro,
.start_signal_voltage_switch = msdc_ops_switch_volt, .start_signal_voltage_switch = msdc_ops_switch_volt,
.card_busy = msdc_card_busy, .card_busy = msdc_card_busy,
.execute_tuning = msdc_execute_tuning, .execute_tuning = msdc_execute_tuning,

View File

@ -307,9 +307,6 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
enum dma_transfer_direction slave_dirn; enum dma_transfer_direction slave_dirn;
int i, nents; int i, nents;
if (data->flags & MMC_DATA_STREAM)
nob = 0xffff;
host->data = data; host->data = data;
data->bytes_xfered = 0; data->bytes_xfered = 0;

View File

@ -74,7 +74,6 @@ struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi)
const u32 *voltage_ranges; const u32 *voltage_ranges;
int num_ranges; int num_ranges;
int i; int i;
int ret = -EINVAL;
if (dev->platform_data || !np) if (dev->platform_data || !np)
return dev->platform_data; return dev->platform_data;
@ -97,7 +96,6 @@ struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi)
mask = mmc_vddrange_to_ocrmask(be32_to_cpu(voltage_ranges[j]), mask = mmc_vddrange_to_ocrmask(be32_to_cpu(voltage_ranges[j]),
be32_to_cpu(voltage_ranges[j + 1])); be32_to_cpu(voltage_ranges[j + 1]));
if (!mask) { if (!mask) {
ret = -EINVAL;
dev_err(dev, "OF: voltage-range #%d is invalid\n", i); dev_err(dev, "OF: voltage-range #%d is invalid\n", i);
goto err_ocr; goto err_ocr;
} }

View File

@ -503,8 +503,11 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
host->pbias = devm_regulator_get_optional(host->dev, "pbias"); host->pbias = devm_regulator_get_optional(host->dev, "pbias");
if (IS_ERR(host->pbias)) { if (IS_ERR(host->pbias)) {
ret = PTR_ERR(host->pbias); ret = PTR_ERR(host->pbias);
if ((ret != -ENODEV) && host->dev->of_node) if ((ret != -ENODEV) && host->dev->of_node) {
dev_err(host->dev,
"SD card detect fail? enable CONFIG_REGULATOR_PBIAS\n");
return ret; return ret;
}
dev_dbg(host->dev, "unable to get pbias regulator %ld\n", dev_dbg(host->dev, "unable to get pbias regulator %ld\n",
PTR_ERR(host->pbias)); PTR_ERR(host->pbias));
host->pbias = NULL; host->pbias = NULL;
@ -2159,7 +2162,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
&rx_req, &pdev->dev, "rx"); &rx_req, &pdev->dev, "rx");
if (!host->rx_chan) { if (!host->rx_chan) {
dev_err(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel %u\n", rx_req); dev_err(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel\n");
ret = -ENXIO; ret = -ENXIO;
goto err_irq; goto err_irq;
} }
@ -2169,7 +2172,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
&tx_req, &pdev->dev, "tx"); &tx_req, &pdev->dev, "tx");
if (!host->tx_chan) { if (!host->tx_chan) {
dev_err(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel %u\n", tx_req); dev_err(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel\n");
ret = -ENXIO; ret = -ENXIO;
goto err_irq; goto err_irq;
} }

View File

@ -191,9 +191,6 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
host->data = data; host->data = data;
if (data->flags & MMC_DATA_STREAM)
nob = 0xffff;
writel(nob, host->base + MMC_NOB); writel(nob, host->base + MMC_NOB);
writel(data->blksz, host->base + MMC_BLKLEN); writel(data->blksz, host->base + MMC_BLKLEN);
@ -443,9 +440,6 @@ static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq)
cmdat |= CMDAT_DATAEN | CMDAT_DMAEN; cmdat |= CMDAT_DATAEN | CMDAT_DMAEN;
if (mrq->data->flags & MMC_DATA_WRITE) if (mrq->data->flags & MMC_DATA_WRITE)
cmdat |= CMDAT_WRITE; cmdat |= CMDAT_WRITE;
if (mrq->data->flags & MMC_DATA_STREAM)
cmdat |= CMDAT_STREAM;
} }
pxamci_start_cmd(host, mrq->cmd, cmdat); pxamci_start_cmd(host, mrq->cmd, cmdat);

View File

@ -1014,8 +1014,7 @@ static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data)
if (host->bus_width == MMC_BUS_WIDTH_4) if (host->bus_width == MMC_BUS_WIDTH_4)
dcon |= S3C2410_SDIDCON_WIDEBUS; dcon |= S3C2410_SDIDCON_WIDEBUS;
if (!(data->flags & MMC_DATA_STREAM)) dcon |= S3C2410_SDIDCON_BLOCKMODE;
dcon |= S3C2410_SDIDCON_BLOCKMODE;
if (data->flags & MMC_DATA_WRITE) { if (data->flags & MMC_DATA_WRITE) {
dcon |= S3C2410_SDIDCON_TXAFTERRESP; dcon |= S3C2410_SDIDCON_TXAFTERRESP;

View File

@ -75,7 +75,6 @@ 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)
@ -83,33 +82,6 @@ static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag)
return c->slot && (c->slot->flags & flag); return c->slot && (c->slot->flags & flag);
} }
static int sdhci_acpi_enable_dma(struct sdhci_host *host)
{
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)
{ {
u8 reg; u8 reg;
@ -127,7 +99,6 @@ static void sdhci_acpi_int_hw_reset(struct sdhci_host *host)
static const struct sdhci_ops sdhci_acpi_ops_dflt = { static const struct sdhci_ops sdhci_acpi_ops_dflt = {
.set_clock = sdhci_set_clock, .set_clock = sdhci_set_clock,
.enable_dma = sdhci_acpi_enable_dma,
.set_bus_width = sdhci_set_bus_width, .set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset, .reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling, .set_uhs_signaling = sdhci_set_uhs_signaling,
@ -135,7 +106,6 @@ static const struct sdhci_ops sdhci_acpi_ops_dflt = {
static const struct sdhci_ops sdhci_acpi_ops_int = { static const struct sdhci_ops sdhci_acpi_ops_int = {
.set_clock = sdhci_set_clock, .set_clock = sdhci_set_clock,
.enable_dma = sdhci_acpi_enable_dma,
.set_bus_width = sdhci_set_bus_width, .set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset, .reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling, .set_uhs_signaling = sdhci_set_uhs_signaling,
@ -264,6 +234,17 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
.probe_slot = sdhci_acpi_sd_probe_slot, .probe_slot = sdhci_acpi_sd_probe_slot,
}; };
static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd_3v = {
.quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION,
.quirks2 = SDHCI_QUIRK2_NO_1_8_V,
.caps = MMC_CAP_NONREMOVABLE,
};
static const struct sdhci_acpi_slot sdhci_acpi_slot_qcom_sd = {
.quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION,
.caps = MMC_CAP_NONREMOVABLE,
};
struct sdhci_acpi_uid_slot { struct sdhci_acpi_uid_slot {
const char *hid; const char *hid;
const char *uid; const char *uid;
@ -284,6 +265,8 @@ static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = {
{ "INT344D" , NULL, &sdhci_acpi_slot_int_sdio }, { "INT344D" , NULL, &sdhci_acpi_slot_int_sdio },
{ "PNP0FFF" , "3" , &sdhci_acpi_slot_int_sd }, { "PNP0FFF" , "3" , &sdhci_acpi_slot_int_sd },
{ "PNP0D40" }, { "PNP0D40" },
{ "QCOM8051", NULL, &sdhci_acpi_slot_qcom_sd_3v },
{ "QCOM8052", NULL, &sdhci_acpi_slot_qcom_sd },
{ }, { },
}; };
@ -298,6 +281,8 @@ static const struct acpi_device_id sdhci_acpi_ids[] = {
{ "INT3436" }, { "INT3436" },
{ "INT344D" }, { "INT344D" },
{ "PNP0D40" }, { "PNP0D40" },
{ "QCOM8051" },
{ "QCOM8052" },
{ }, { },
}; };
MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids); MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids);
@ -418,6 +403,8 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
pm_runtime_enable(dev); pm_runtime_enable(dev);
} }
device_enable_async_suspend(dev);
return 0; return 0;
err_free: err_free:

View File

@ -74,7 +74,7 @@ static inline u32 bcm2835_sdhci_readl(struct sdhci_host *host, int reg)
static void bcm2835_sdhci_writew(struct sdhci_host *host, u16 val, int reg) static void bcm2835_sdhci_writew(struct sdhci_host *host, u16 val, int reg)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct bcm2835_sdhci *bcm2835_host = pltfm_host->priv; struct bcm2835_sdhci *bcm2835_host = sdhci_pltfm_priv(pltfm_host);
u32 oldval = (reg == SDHCI_COMMAND) ? bcm2835_host->shadow : u32 oldval = (reg == SDHCI_COMMAND) ? bcm2835_host->shadow :
bcm2835_sdhci_readl(host, reg & ~3); bcm2835_sdhci_readl(host, reg & ~3);
u32 word_num = (reg >> 1) & 1; u32 word_num = (reg >> 1) & 1;
@ -152,20 +152,12 @@ static int bcm2835_sdhci_probe(struct platform_device *pdev)
struct sdhci_pltfm_host *pltfm_host; struct sdhci_pltfm_host *pltfm_host;
int ret; int ret;
host = sdhci_pltfm_init(pdev, &bcm2835_sdhci_pdata, 0); host = sdhci_pltfm_init(pdev, &bcm2835_sdhci_pdata,
sizeof(*bcm2835_host));
if (IS_ERR(host)) if (IS_ERR(host))
return PTR_ERR(host); return PTR_ERR(host);
bcm2835_host = devm_kzalloc(&pdev->dev, sizeof(*bcm2835_host),
GFP_KERNEL);
if (!bcm2835_host) {
dev_err(mmc_dev(host->mmc),
"failed to allocate bcm2835_sdhci\n");
return -ENOMEM;
}
pltfm_host = sdhci_priv(host); pltfm_host = sdhci_priv(host);
pltfm_host->priv = bcm2835_host;
pltfm_host->clk = devm_clk_get(&pdev->dev, NULL); pltfm_host->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(pltfm_host->clk)) { if (IS_ERR(pltfm_host->clk)) {

View File

@ -260,7 +260,7 @@ static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, i
static u32 esdhc_readl_le(struct sdhci_host *host, int reg) static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv; struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
u32 val = readl(host->ioaddr + reg); u32 val = readl(host->ioaddr + reg);
if (unlikely(reg == SDHCI_PRESENT_STATE)) { if (unlikely(reg == SDHCI_PRESENT_STATE)) {
@ -338,7 +338,7 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv; struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
u32 data; u32 data;
if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) { if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) {
@ -388,7 +388,7 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
static u16 esdhc_readw_le(struct sdhci_host *host, int reg) static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv; struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
u16 ret = 0; u16 ret = 0;
u32 val; u32 val;
@ -448,7 +448,7 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv; struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
u32 new_val = 0; u32 new_val = 0;
switch (reg) { switch (reg) {
@ -556,7 +556,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv; struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
u32 new_val; u32 new_val;
u32 mask; u32 mask;
@ -633,7 +633,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
unsigned int clock) unsigned int clock)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv; struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
unsigned int host_clock = pltfm_host->clock; unsigned int host_clock = pltfm_host->clock;
int pre_div = 2; int pre_div = 2;
int div = 1; int div = 1;
@ -692,7 +692,7 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv; struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
struct esdhc_platform_data *boarddata = &imx_data->boarddata; struct esdhc_platform_data *boarddata = &imx_data->boarddata;
switch (boarddata->wp_type) { switch (boarddata->wp_type) {
@ -794,7 +794,7 @@ static int esdhc_change_pinstate(struct sdhci_host *host,
unsigned int uhs) unsigned int uhs)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv; struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
struct pinctrl_state *pinctrl; struct pinctrl_state *pinctrl;
dev_dbg(mmc_dev(host->mmc), "change pinctrl state for uhs %d\n", uhs); dev_dbg(mmc_dev(host->mmc), "change pinctrl state for uhs %d\n", uhs);
@ -864,7 +864,7 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
{ {
u32 m; u32 m;
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv; struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
struct esdhc_platform_data *boarddata = &imx_data->boarddata; struct esdhc_platform_data *boarddata = &imx_data->boarddata;
/* disable ddr mode and disable HS400 mode */ /* disable ddr mode and disable HS400 mode */
@ -917,7 +917,7 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask)
static unsigned int esdhc_get_max_timeout_count(struct sdhci_host *host) static unsigned int esdhc_get_max_timeout_count(struct sdhci_host *host)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv; struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
return esdhc_is_usdhc(imx_data) ? 1 << 28 : 1 << 27; return esdhc_is_usdhc(imx_data) ? 1 << 28 : 1 << 27;
} }
@ -925,7 +925,7 @@ static unsigned int esdhc_get_max_timeout_count(struct sdhci_host *host)
static void esdhc_set_timeout(struct sdhci_host *host, struct mmc_command *cmd) static void esdhc_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv; struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
/* use maximum timeout counter */ /* use maximum timeout counter */
sdhci_writeb(host, esdhc_is_usdhc(imx_data) ? 0xF : 0xE, sdhci_writeb(host, esdhc_is_usdhc(imx_data) ? 0xF : 0xE,
@ -1100,21 +1100,17 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
int err; int err;
struct pltfm_imx_data *imx_data; struct pltfm_imx_data *imx_data;
host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata, 0); host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata,
sizeof(*imx_data));
if (IS_ERR(host)) if (IS_ERR(host))
return PTR_ERR(host); return PTR_ERR(host);
pltfm_host = sdhci_priv(host); pltfm_host = sdhci_priv(host);
imx_data = devm_kzalloc(&pdev->dev, sizeof(*imx_data), GFP_KERNEL); imx_data = sdhci_pltfm_priv(pltfm_host);
if (!imx_data) {
err = -ENOMEM;
goto free_sdhci;
}
imx_data->socdata = of_id ? of_id->data : (struct esdhc_soc_data *) imx_data->socdata = of_id ? of_id->data : (struct esdhc_soc_data *)
pdev->id_entry->driver_data; pdev->id_entry->driver_data;
pltfm_host->priv = imx_data;
imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(imx_data->clk_ipg)) { if (IS_ERR(imx_data->clk_ipg)) {
@ -1241,7 +1237,7 @@ static int sdhci_esdhc_imx_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 pltfm_imx_data *imx_data = pltfm_host->priv; struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
pm_runtime_get_sync(&pdev->dev); pm_runtime_get_sync(&pdev->dev);
@ -1264,7 +1260,7 @@ static int sdhci_esdhc_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 pltfm_imx_data *imx_data = pltfm_host->priv; struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
int ret; int ret;
ret = sdhci_runtime_suspend_host(host); ret = sdhci_runtime_suspend_host(host);
@ -1282,7 +1278,7 @@ static int sdhci_esdhc_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 pltfm_imx_data *imx_data = pltfm_host->priv; struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
if (!sdhci_sdio_irq_enabled(host)) { if (!sdhci_sdio_irq_enabled(host)) {
clk_prepare_enable(imx_data->clk_per); clk_prepare_enable(imx_data->clk_per);

View File

@ -26,6 +26,7 @@ struct sdhci_iproc_data {
const struct sdhci_pltfm_data *pdata; const struct sdhci_pltfm_data *pdata;
u32 caps; u32 caps;
u32 caps1; u32 caps1;
u32 mmc_caps;
}; };
struct sdhci_iproc_host { struct sdhci_iproc_host {
@ -165,9 +166,25 @@ static const struct sdhci_iproc_data iproc_data = {
.pdata = &sdhci_iproc_pltfm_data, .pdata = &sdhci_iproc_pltfm_data,
.caps = 0x05E90000, .caps = 0x05E90000,
.caps1 = 0x00000064, .caps1 = 0x00000064,
.mmc_caps = MMC_CAP_1_8V_DDR,
};
static const struct sdhci_pltfm_data sdhci_bcm2835_pltfm_data = {
.quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_MISSING_CAPS,
.ops = &sdhci_iproc_ops,
};
static const struct sdhci_iproc_data bcm2835_data = {
.pdata = &sdhci_bcm2835_pltfm_data,
.caps = SDHCI_CAN_VDD_330,
.caps1 = 0x00000000,
.mmc_caps = 0x00000000,
}; };
static const struct of_device_id sdhci_iproc_of_match[] = { static const struct of_device_id sdhci_iproc_of_match[] = {
{ .compatible = "brcm,bcm2835-sdhci", .data = &bcm2835_data },
{ .compatible = "brcm,sdhci-iproc-cygnus", .data = &iproc_data }, { .compatible = "brcm,sdhci-iproc-cygnus", .data = &iproc_data },
{ } { }
}; };
@ -199,32 +216,37 @@ static int sdhci_iproc_probe(struct platform_device *pdev)
mmc_of_parse(host->mmc); mmc_of_parse(host->mmc);
sdhci_get_of_property(pdev); sdhci_get_of_property(pdev);
/* Enable EMMC 1/8V DDR capable */ host->mmc->caps |= iproc_host->data->mmc_caps;
host->mmc->caps |= MMC_CAP_1_8V_DDR;
pltfm_host->clk = devm_clk_get(&pdev->dev, NULL); pltfm_host->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(pltfm_host->clk)) { if (IS_ERR(pltfm_host->clk)) {
ret = PTR_ERR(pltfm_host->clk); ret = PTR_ERR(pltfm_host->clk);
goto err; goto err;
} }
ret = clk_prepare_enable(pltfm_host->clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable host clk\n");
goto err;
}
if (iproc_host->data->pdata->quirks & SDHCI_QUIRK_MISSING_CAPS) { if (iproc_host->data->pdata->quirks & SDHCI_QUIRK_MISSING_CAPS) {
host->caps = iproc_host->data->caps; host->caps = iproc_host->data->caps;
host->caps1 = iproc_host->data->caps1; host->caps1 = iproc_host->data->caps1;
} }
return sdhci_add_host(host); ret = sdhci_add_host(host);
if (ret)
goto err_clk;
return 0;
err_clk:
clk_disable_unprepare(pltfm_host->clk);
err: err:
sdhci_pltfm_free(pdev); sdhci_pltfm_free(pdev);
return ret; return ret;
} }
static int sdhci_iproc_remove(struct platform_device *pdev)
{
return sdhci_pltfm_unregister(pdev);
}
static struct platform_driver sdhci_iproc_driver = { static struct platform_driver sdhci_iproc_driver = {
.driver = { .driver = {
.name = "sdhci-iproc", .name = "sdhci-iproc",
@ -232,7 +254,7 @@ static struct platform_driver sdhci_iproc_driver = {
.pm = SDHCI_PLTFM_PMOPS, .pm = SDHCI_PLTFM_PMOPS,
}, },
.probe = sdhci_iproc_probe, .probe = sdhci_iproc_probe,
.remove = sdhci_iproc_remove, .remove = sdhci_pltfm_unregister,
}; };
module_platform_driver(sdhci_iproc_driver); module_platform_driver(sdhci_iproc_driver);

View File

@ -60,7 +60,6 @@ struct sdhci_msm_host {
struct clk *pclk; /* SDHC peripheral bus clock */ struct clk *pclk; /* SDHC peripheral bus clock */
struct clk *bus_clk; /* SDHC bus voter clock */ struct clk *bus_clk; /* SDHC bus voter clock */
struct mmc_host *mmc; struct mmc_host *mmc;
struct sdhci_pltfm_data sdhci_msm_pdata;
}; };
/* Platform specific tuning */ /* Platform specific tuning */
@ -418,7 +417,7 @@ static const struct of_device_id sdhci_msm_dt_match[] = {
MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match); MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
static struct sdhci_ops sdhci_msm_ops = { static const struct sdhci_ops sdhci_msm_ops = {
.platform_execute_tuning = sdhci_msm_execute_tuning, .platform_execute_tuning = sdhci_msm_execute_tuning,
.reset = sdhci_reset, .reset = sdhci_reset,
.set_clock = sdhci_set_clock, .set_clock = sdhci_set_clock,
@ -426,6 +425,12 @@ static struct sdhci_ops sdhci_msm_ops = {
.set_uhs_signaling = sdhci_set_uhs_signaling, .set_uhs_signaling = sdhci_set_uhs_signaling,
}; };
static const struct sdhci_pltfm_data sdhci_msm_pdata = {
.quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
SDHCI_QUIRK_SINGLE_POWER_WRITE,
.ops = &sdhci_msm_ops,
};
static int sdhci_msm_probe(struct platform_device *pdev) static int sdhci_msm_probe(struct platform_device *pdev)
{ {
struct sdhci_host *host; struct sdhci_host *host;
@ -437,17 +442,12 @@ static int sdhci_msm_probe(struct platform_device *pdev)
u32 core_version, caps; u32 core_version, caps;
u8 core_major; u8 core_major;
msm_host = devm_kzalloc(&pdev->dev, sizeof(*msm_host), GFP_KERNEL); host = sdhci_pltfm_init(pdev, &sdhci_msm_pdata, sizeof(*msm_host));
if (!msm_host)
return -ENOMEM;
msm_host->sdhci_msm_pdata.ops = &sdhci_msm_ops;
host = sdhci_pltfm_init(pdev, &msm_host->sdhci_msm_pdata, 0);
if (IS_ERR(host)) if (IS_ERR(host))
return PTR_ERR(host); return PTR_ERR(host);
pltfm_host = sdhci_priv(host); pltfm_host = sdhci_priv(host);
pltfm_host->priv = msm_host; msm_host = sdhci_pltfm_priv(pltfm_host);
msm_host->mmc = host->mmc; msm_host->mmc = host->mmc;
msm_host->pdev = pdev; msm_host->pdev = pdev;
@ -522,9 +522,6 @@ static int sdhci_msm_probe(struct platform_device *pdev)
/* Set HC_MODE_EN bit in HC_MODE register */ /* Set HC_MODE_EN bit in HC_MODE register */
writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE)); writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
host->quirks |= SDHCI_QUIRK_SINGLE_POWER_WRITE;
host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION)); host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION));
dev_dbg(&pdev->dev, "Host Version: 0x%x Vendor Version 0x%x\n", dev_dbg(&pdev->dev, "Host Version: 0x%x Vendor Version 0x%x\n",
host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >> host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >>
@ -570,16 +567,16 @@ static int sdhci_msm_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_msm_host *msm_host = pltfm_host->priv; struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) == int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) ==
0xffffffff); 0xffffffff);
sdhci_remove_host(host, dead); sdhci_remove_host(host, dead);
sdhci_pltfm_free(pdev);
clk_disable_unprepare(msm_host->clk); clk_disable_unprepare(msm_host->clk);
clk_disable_unprepare(msm_host->pclk); clk_disable_unprepare(msm_host->pclk);
if (!IS_ERR(msm_host->bus_clk)) if (!IS_ERR(msm_host->bus_clk))
clk_disable_unprepare(msm_host->bus_clk); clk_disable_unprepare(msm_host->bus_clk);
sdhci_pltfm_free(pdev);
return 0; return 0;
} }

View File

@ -21,6 +21,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/phy/phy.h>
#include "sdhci-pltfm.h" #include "sdhci-pltfm.h"
#define SDHCI_ARASAN_CLK_CTRL_OFFSET 0x2c #define SDHCI_ARASAN_CLK_CTRL_OFFSET 0x2c
@ -32,9 +33,11 @@
/** /**
* struct sdhci_arasan_data * struct sdhci_arasan_data
* @clk_ahb: Pointer to the AHB clock * @clk_ahb: Pointer to the AHB clock
* @phy: Pointer to the generic phy
*/ */
struct sdhci_arasan_data { struct sdhci_arasan_data {
struct clk *clk_ahb; struct clk *clk_ahb;
struct phy *phy;
}; };
static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host) static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host)
@ -81,13 +84,22 @@ static int sdhci_arasan_suspend(struct device *dev)
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
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_arasan_data *sdhci_arasan = pltfm_host->priv; struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
int ret; int ret;
ret = sdhci_suspend_host(host); ret = sdhci_suspend_host(host);
if (ret) if (ret)
return ret; return ret;
if (!IS_ERR(sdhci_arasan->phy)) {
ret = phy_power_off(sdhci_arasan->phy);
if (ret) {
dev_err(dev, "Cannot power off phy.\n");
sdhci_resume_host(host);
return ret;
}
}
clk_disable(pltfm_host->clk); clk_disable(pltfm_host->clk);
clk_disable(sdhci_arasan->clk_ahb); clk_disable(sdhci_arasan->clk_ahb);
@ -106,7 +118,7 @@ static int sdhci_arasan_resume(struct device *dev)
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
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_arasan_data *sdhci_arasan = pltfm_host->priv; struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
int ret; int ret;
ret = clk_enable(sdhci_arasan->clk_ahb); ret = clk_enable(sdhci_arasan->clk_ahb);
@ -118,10 +130,17 @@ static int sdhci_arasan_resume(struct device *dev)
ret = clk_enable(pltfm_host->clk); ret = clk_enable(pltfm_host->clk);
if (ret) { if (ret) {
dev_err(dev, "Cannot enable SD clock.\n"); dev_err(dev, "Cannot enable SD clock.\n");
clk_disable(sdhci_arasan->clk_ahb);
return ret; return ret;
} }
if (!IS_ERR(sdhci_arasan->phy)) {
ret = phy_power_on(sdhci_arasan->phy);
if (ret) {
dev_err(dev, "Cannot power on phy.\n");
return ret;
}
}
return sdhci_resume_host(host); return sdhci_resume_host(host);
} }
#endif /* ! CONFIG_PM_SLEEP */ #endif /* ! CONFIG_PM_SLEEP */
@ -137,27 +156,32 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
struct sdhci_pltfm_host *pltfm_host; struct sdhci_pltfm_host *pltfm_host;
struct sdhci_arasan_data *sdhci_arasan; struct sdhci_arasan_data *sdhci_arasan;
sdhci_arasan = devm_kzalloc(&pdev->dev, sizeof(*sdhci_arasan), host = sdhci_pltfm_init(pdev, &sdhci_arasan_pdata,
GFP_KERNEL); sizeof(*sdhci_arasan));
if (!sdhci_arasan) if (IS_ERR(host))
return -ENOMEM; return PTR_ERR(host);
pltfm_host = sdhci_priv(host);
sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
sdhci_arasan->clk_ahb = devm_clk_get(&pdev->dev, "clk_ahb"); sdhci_arasan->clk_ahb = devm_clk_get(&pdev->dev, "clk_ahb");
if (IS_ERR(sdhci_arasan->clk_ahb)) { if (IS_ERR(sdhci_arasan->clk_ahb)) {
dev_err(&pdev->dev, "clk_ahb clock not found.\n"); dev_err(&pdev->dev, "clk_ahb clock not found.\n");
return PTR_ERR(sdhci_arasan->clk_ahb); ret = PTR_ERR(sdhci_arasan->clk_ahb);
goto err_pltfm_free;
} }
clk_xin = devm_clk_get(&pdev->dev, "clk_xin"); clk_xin = devm_clk_get(&pdev->dev, "clk_xin");
if (IS_ERR(clk_xin)) { if (IS_ERR(clk_xin)) {
dev_err(&pdev->dev, "clk_xin clock not found.\n"); dev_err(&pdev->dev, "clk_xin clock not found.\n");
return PTR_ERR(clk_xin); ret = PTR_ERR(clk_xin);
goto err_pltfm_free;
} }
ret = clk_prepare_enable(sdhci_arasan->clk_ahb); ret = clk_prepare_enable(sdhci_arasan->clk_ahb);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Unable to enable AHB clock.\n"); dev_err(&pdev->dev, "Unable to enable AHB clock.\n");
return ret; goto err_pltfm_free;
} }
ret = clk_prepare_enable(clk_xin); ret = clk_prepare_enable(clk_xin);
@ -166,20 +190,7 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
goto clk_dis_ahb; goto clk_dis_ahb;
} }
host = sdhci_pltfm_init(pdev, &sdhci_arasan_pdata, 0);
if (IS_ERR(host)) {
ret = PTR_ERR(host);
goto clk_disable_all;
}
if (of_device_is_compatible(pdev->dev.of_node, "arasan,sdhci-4.9a")) {
host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT;
host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23;
}
sdhci_get_of_property(pdev); sdhci_get_of_property(pdev);
pltfm_host = sdhci_priv(host);
pltfm_host->priv = sdhci_arasan;
pltfm_host->clk = clk_xin; pltfm_host->clk = clk_xin;
ret = mmc_of_parse(host->mmc); ret = mmc_of_parse(host->mmc);
@ -188,31 +199,69 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
goto clk_disable_all; goto clk_disable_all;
} }
sdhci_arasan->phy = ERR_PTR(-ENODEV);
if (of_device_is_compatible(pdev->dev.of_node,
"arasan,sdhci-5.1")) {
sdhci_arasan->phy = devm_phy_get(&pdev->dev,
"phy_arasan");
if (IS_ERR(sdhci_arasan->phy)) {
ret = PTR_ERR(sdhci_arasan->phy);
dev_err(&pdev->dev, "No phy for arasan,sdhci-5.1.\n");
goto clk_disable_all;
}
ret = phy_init(sdhci_arasan->phy);
if (ret < 0) {
dev_err(&pdev->dev, "phy_init err.\n");
goto clk_disable_all;
}
ret = phy_power_on(sdhci_arasan->phy);
if (ret < 0) {
dev_err(&pdev->dev, "phy_power_on err.\n");
goto err_phy_power;
}
}
ret = sdhci_add_host(host); ret = sdhci_add_host(host);
if (ret) if (ret)
goto err_pltfm_free; goto err_add_host;
return 0; return 0;
err_pltfm_free: err_add_host:
sdhci_pltfm_free(pdev); if (!IS_ERR(sdhci_arasan->phy))
phy_power_off(sdhci_arasan->phy);
err_phy_power:
if (!IS_ERR(sdhci_arasan->phy))
phy_exit(sdhci_arasan->phy);
clk_disable_all: clk_disable_all:
clk_disable_unprepare(clk_xin); clk_disable_unprepare(clk_xin);
clk_dis_ahb: clk_dis_ahb:
clk_disable_unprepare(sdhci_arasan->clk_ahb); clk_disable_unprepare(sdhci_arasan->clk_ahb);
err_pltfm_free:
sdhci_pltfm_free(pdev);
return ret; return ret;
} }
static int sdhci_arasan_remove(struct platform_device *pdev) static int sdhci_arasan_remove(struct platform_device *pdev)
{ {
int ret;
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_arasan_data *sdhci_arasan = pltfm_host->priv; struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
struct clk *clk_ahb = sdhci_arasan->clk_ahb;
clk_disable_unprepare(sdhci_arasan->clk_ahb); if (!IS_ERR(sdhci_arasan->phy)) {
phy_power_off(sdhci_arasan->phy);
phy_exit(sdhci_arasan->phy);
}
return sdhci_pltfm_unregister(pdev); ret = sdhci_pltfm_unregister(pdev);
clk_disable_unprepare(clk_ahb);
return ret;
} }
static const struct of_device_id sdhci_arasan_of_match[] = { static const struct of_device_id sdhci_arasan_of_match[] = {

View File

@ -18,6 +18,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
@ -58,7 +59,7 @@ static int sdhci_at91_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_at91_priv *priv = pltfm_host->priv; struct sdhci_at91_priv *priv = sdhci_pltfm_priv(pltfm_host);
int ret; int ret;
ret = sdhci_runtime_suspend_host(host); ret = sdhci_runtime_suspend_host(host);
@ -74,7 +75,7 @@ static int sdhci_at91_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_at91_priv *priv = pltfm_host->priv; struct sdhci_at91_priv *priv = sdhci_pltfm_priv(pltfm_host);
int ret; int ret;
ret = clk_prepare_enable(priv->mainck); ret = clk_prepare_enable(priv->mainck);
@ -124,11 +125,12 @@ static int sdhci_at91_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
soc_data = match->data; soc_data = match->data;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); host = sdhci_pltfm_init(pdev, soc_data, sizeof(*priv));
if (!priv) { if (IS_ERR(host))
dev_err(&pdev->dev, "unable to allocate private data\n"); return PTR_ERR(host);
return -ENOMEM;
} pltfm_host = sdhci_priv(host);
priv = sdhci_pltfm_priv(pltfm_host);
priv->mainck = devm_clk_get(&pdev->dev, "baseclk"); priv->mainck = devm_clk_get(&pdev->dev, "baseclk");
if (IS_ERR(priv->mainck)) { if (IS_ERR(priv->mainck)) {
@ -148,10 +150,6 @@ static int sdhci_at91_probe(struct platform_device *pdev)
return PTR_ERR(priv->gck); return PTR_ERR(priv->gck);
} }
host = sdhci_pltfm_init(pdev, soc_data, 0);
if (IS_ERR(host))
return PTR_ERR(host);
/* /*
* The mult clock is provided by as a generated clock by the PMC * The mult clock is provided by as a generated clock by the PMC
* controller. In order to set the rate of gck, we have to get the * controller. In order to set the rate of gck, we have to get the
@ -191,9 +189,6 @@ static int sdhci_at91_probe(struct platform_device *pdev)
clk_prepare_enable(priv->mainck); clk_prepare_enable(priv->mainck);
clk_prepare_enable(priv->gck); clk_prepare_enable(priv->gck);
pltfm_host = sdhci_priv(host);
pltfm_host->priv = priv;
ret = mmc_of_parse(host->mmc); ret = mmc_of_parse(host->mmc);
if (ret) if (ret)
goto clocks_disable_unprepare; goto clocks_disable_unprepare;
@ -210,6 +205,25 @@ static int sdhci_at91_probe(struct platform_device *pdev)
if (ret) if (ret)
goto pm_runtime_disable; goto pm_runtime_disable;
/*
* When calling sdhci_runtime_suspend_host(), the sdhci layer makes
* the assumption that all the clocks of the controller are disabled.
* It means we can't get irq from it when it is runtime suspended.
* For that reason, it is not planned to wake-up on a card detect irq
* from the controller.
* If we want to use runtime PM and to be able to wake-up on card
* insertion, we have to use a GPIO for the card detection or we can
* use polling. Be aware that using polling will resume/suspend the
* controller between each attempt.
* Disable SDHCI_QUIRK_BROKEN_CARD_DETECTION to be sure nobody tries
* to enable polling via device tree with broken-cd property.
*/
if (!(host->mmc->caps & MMC_CAP_NONREMOVABLE) &&
IS_ERR_VALUE(mmc_gpio_get_cd(host->mmc))) {
host->mmc->caps |= MMC_CAP_NEEDS_POLL;
host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
}
pm_runtime_put_autosuspend(&pdev->dev); pm_runtime_put_autosuspend(&pdev->dev);
return 0; return 0;
@ -231,7 +245,10 @@ static int sdhci_at91_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_at91_priv *priv = pltfm_host->priv; struct sdhci_at91_priv *priv = sdhci_pltfm_priv(pltfm_host);
struct clk *gck = priv->gck;
struct clk *hclock = priv->hclock;
struct clk *mainck = priv->mainck;
pm_runtime_get_sync(&pdev->dev); pm_runtime_get_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
@ -239,9 +256,9 @@ static int sdhci_at91_remove(struct platform_device *pdev)
sdhci_pltfm_unregister(pdev); sdhci_pltfm_unregister(pdev);
clk_disable_unprepare(priv->gck); clk_disable_unprepare(gck);
clk_disable_unprepare(priv->hclock); clk_disable_unprepare(hclock);
clk_disable_unprepare(priv->mainck); clk_disable_unprepare(mainck);
return 0; return 0;
} }

View File

@ -49,7 +49,7 @@ static u32 esdhc_readl_fixup(struct sdhci_host *host,
int spec_reg, u32 value) int spec_reg, u32 value)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_esdhc *esdhc = pltfm_host->priv; struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
u32 ret; u32 ret;
/* /*
@ -354,7 +354,7 @@ static void esdhc_le_writeb(struct sdhci_host *host, u8 val, int reg)
static void esdhc_of_adma_workaround(struct sdhci_host *host, u32 intmask) static void esdhc_of_adma_workaround(struct sdhci_host *host, u32 intmask)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_esdhc *esdhc = pltfm_host->priv; struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
bool applicable; bool applicable;
dma_addr_t dmastart; dma_addr_t dmastart;
dma_addr_t dmanow; dma_addr_t dmanow;
@ -404,7 +404,7 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_esdhc *esdhc = pltfm_host->priv; struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
int pre_div = 1; int pre_div = 1;
int div = 1; int div = 1;
u32 temp; u32 temp;
@ -569,15 +569,12 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
u16 host_ver; u16 host_ver;
pltfm_host = sdhci_priv(host); pltfm_host = sdhci_priv(host);
esdhc = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_esdhc), esdhc = sdhci_pltfm_priv(pltfm_host);
GFP_KERNEL);
host_ver = sdhci_readw(host, SDHCI_HOST_VERSION); host_ver = sdhci_readw(host, SDHCI_HOST_VERSION);
esdhc->vendor_ver = (host_ver & SDHCI_VENDOR_VER_MASK) >> esdhc->vendor_ver = (host_ver & SDHCI_VENDOR_VER_MASK) >>
SDHCI_VENDOR_VER_SHIFT; SDHCI_VENDOR_VER_SHIFT;
esdhc->spec_ver = host_ver & SDHCI_SPEC_VER_MASK; esdhc->spec_ver = host_ver & SDHCI_SPEC_VER_MASK;
pltfm_host->priv = esdhc;
} }
static int sdhci_esdhc_probe(struct platform_device *pdev) static int sdhci_esdhc_probe(struct platform_device *pdev)
@ -591,9 +588,11 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
np = pdev->dev.of_node; np = pdev->dev.of_node;
if (of_get_property(np, "little-endian", NULL)) if (of_get_property(np, "little-endian", NULL))
host = sdhci_pltfm_init(pdev, &sdhci_esdhc_le_pdata, 0); host = sdhci_pltfm_init(pdev, &sdhci_esdhc_le_pdata,
sizeof(struct sdhci_esdhc));
else else
host = sdhci_pltfm_init(pdev, &sdhci_esdhc_be_pdata, 0); host = sdhci_pltfm_init(pdev, &sdhci_esdhc_be_pdata,
sizeof(struct sdhci_esdhc));
if (IS_ERR(host)) if (IS_ERR(host))
return PTR_ERR(host); return PTR_ERR(host);
@ -603,7 +602,7 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
sdhci_get_of_property(pdev); sdhci_get_of_property(pdev);
pltfm_host = sdhci_priv(host); pltfm_host = sdhci_priv(host);
esdhc = pltfm_host->priv; esdhc = sdhci_pltfm_priv(pltfm_host);
if (esdhc->vendor_ver == VENDOR_V_22) if (esdhc->vendor_ver == VENDOR_V_22)
host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23; host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23;

View File

@ -1302,7 +1302,6 @@ 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 = -1;
slot = sdhci_priv(host); slot = sdhci_priv(host);
pdev = slot->chip->pdev; pdev = slot->chip->pdev;
@ -1314,20 +1313,6 @@ 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");
} }
if (host->flags & SDHCI_USE_64_BIT_DMA) {
if (host->quirks2 & SDHCI_QUIRK2_BROKEN_64_BIT_DMA) {
host->flags &= ~SDHCI_USE_64_BIT_DMA;
} else {
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
if (ret)
dev_warn(&pdev->dev, "Failed to set 64-bit DMA mask\n");
}
}
if (ret)
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret)
return ret;
pci_set_master(pdev); pci_set_master(pdev);
return 0; return 0;

View File

@ -0,0 +1,257 @@
/*
* Support of SDHCI platform devices for Microchip PIC32.
*
* Copyright (C) 2015 Microchip
* Andrei Pistirica, Paul Thacker
*
* Inspired by sdhci-pltfm.c
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/highmem.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/mmc/host.h>
#include <linux/io.h>
#include "sdhci.h"
#include "sdhci-pltfm.h"
#include <linux/platform_data/sdhci-pic32.h>
#define SDH_SHARED_BUS_CTRL 0x000000E0
#define SDH_SHARED_BUS_NR_CLK_PINS_MASK 0x7
#define SDH_SHARED_BUS_NR_IRQ_PINS_MASK 0x30
#define SDH_SHARED_BUS_CLK_PINS 0x10
#define SDH_SHARED_BUS_IRQ_PINS 0x14
#define SDH_CAPS_SDH_SLOT_TYPE_MASK 0xC0000000
#define SDH_SLOT_TYPE_REMOVABLE 0x0
#define SDH_SLOT_TYPE_EMBEDDED 0x1
#define SDH_SLOT_TYPE_SHARED_BUS 0x2
#define SDHCI_CTRL_CDSSEL 0x80
#define SDHCI_CTRL_CDTLVL 0x40
#define ADMA_FIFO_RD_THSHLD 512
#define ADMA_FIFO_WR_THSHLD 512
struct pic32_sdhci_priv {
struct platform_device *pdev;
struct clk *sys_clk;
struct clk *base_clk;
};
static unsigned int pic32_sdhci_get_max_clock(struct sdhci_host *host)
{
struct pic32_sdhci_priv *sdhci_pdata = sdhci_priv(host);
return clk_get_rate(sdhci_pdata->base_clk);
}
static void pic32_sdhci_set_bus_width(struct sdhci_host *host, int width)
{
u8 ctrl;
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
if (width == MMC_BUS_WIDTH_8) {
ctrl &= ~SDHCI_CTRL_4BITBUS;
if (host->version >= SDHCI_SPEC_300)
ctrl |= SDHCI_CTRL_8BITBUS;
} else {
if (host->version >= SDHCI_SPEC_300)
ctrl &= ~SDHCI_CTRL_8BITBUS;
if (width == MMC_BUS_WIDTH_4)
ctrl |= SDHCI_CTRL_4BITBUS;
else
ctrl &= ~SDHCI_CTRL_4BITBUS;
}
/* CD select and test bits must be set for errata workaround. */
ctrl &= ~SDHCI_CTRL_CDTLVL;
ctrl |= SDHCI_CTRL_CDSSEL;
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}
static unsigned int pic32_sdhci_get_ro(struct sdhci_host *host)
{
/*
* The SDHCI_WRITE_PROTECT bit is unstable on current hardware so we
* can't depend on its value in any way.
*/
return 0;
}
static const struct sdhci_ops pic32_sdhci_ops = {
.get_max_clock = pic32_sdhci_get_max_clock,
.set_clock = sdhci_set_clock,
.set_bus_width = pic32_sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
.get_ro = pic32_sdhci_get_ro,
};
static struct sdhci_pltfm_data sdhci_pic32_pdata = {
.ops = &pic32_sdhci_ops,
.quirks = SDHCI_QUIRK_NO_HISPD_BIT,
.quirks2 = SDHCI_QUIRK2_NO_1_8_V,
};
static void pic32_sdhci_shared_bus(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
u32 bus = readl(host->ioaddr + SDH_SHARED_BUS_CTRL);
u32 clk_pins = (bus & SDH_SHARED_BUS_NR_CLK_PINS_MASK) >> 0;
u32 irq_pins = (bus & SDH_SHARED_BUS_NR_IRQ_PINS_MASK) >> 4;
/* select first clock */
if (clk_pins & 1)
bus |= (1 << SDH_SHARED_BUS_CLK_PINS);
/* select first interrupt */
if (irq_pins & 1)
bus |= (1 << SDH_SHARED_BUS_IRQ_PINS);
writel(bus, host->ioaddr + SDH_SHARED_BUS_CTRL);
}
static int pic32_sdhci_probe_platform(struct platform_device *pdev,
struct pic32_sdhci_priv *pdata)
{
int ret = 0;
u32 caps_slot_type;
struct sdhci_host *host = platform_get_drvdata(pdev);
/* Check card slot connected on shared bus. */
host->caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
caps_slot_type = (host->caps & SDH_CAPS_SDH_SLOT_TYPE_MASK) >> 30;
if (caps_slot_type == SDH_SLOT_TYPE_SHARED_BUS)
pic32_sdhci_shared_bus(pdev);
return ret;
}
static int pic32_sdhci_probe(struct platform_device *pdev)
{
struct sdhci_host *host;
struct sdhci_pltfm_host *pltfm_host;
struct pic32_sdhci_priv *sdhci_pdata;
struct pic32_sdhci_platform_data *plat_data;
int ret;
host = sdhci_pltfm_init(pdev, &sdhci_pic32_pdata,
sizeof(struct pic32_sdhci_priv));
if (IS_ERR(host)) {
ret = PTR_ERR(host);
goto err;
}
pltfm_host = sdhci_priv(host);
sdhci_pdata = sdhci_pltfm_priv(pltfm_host);
plat_data = pdev->dev.platform_data;
if (plat_data && plat_data->setup_dma) {
ret = plat_data->setup_dma(ADMA_FIFO_RD_THSHLD,
ADMA_FIFO_WR_THSHLD);
if (ret)
goto err_host;
}
sdhci_pdata->sys_clk = devm_clk_get(&pdev->dev, "sys_clk");
if (IS_ERR(sdhci_pdata->sys_clk)) {
ret = PTR_ERR(sdhci_pdata->sys_clk);
dev_err(&pdev->dev, "Error getting clock\n");
goto err_host;
}
ret = clk_prepare_enable(sdhci_pdata->sys_clk);
if (ret) {
dev_err(&pdev->dev, "Error enabling clock\n");
goto err_host;
}
sdhci_pdata->base_clk = devm_clk_get(&pdev->dev, "base_clk");
if (IS_ERR(sdhci_pdata->base_clk)) {
ret = PTR_ERR(sdhci_pdata->base_clk);
dev_err(&pdev->dev, "Error getting clock\n");
goto err_sys_clk;
}
ret = clk_prepare_enable(sdhci_pdata->base_clk);
if (ret) {
dev_err(&pdev->dev, "Error enabling clock\n");
goto err_base_clk;
}
ret = mmc_of_parse(host->mmc);
if (ret)
goto err_base_clk;
ret = pic32_sdhci_probe_platform(pdev, sdhci_pdata);
if (ret) {
dev_err(&pdev->dev, "failed to probe platform!\n");
goto err_base_clk;
}
ret = sdhci_add_host(host);
if (ret) {
dev_err(&pdev->dev, "error adding host\n");
goto err_base_clk;
}
dev_info(&pdev->dev, "Successfully added sdhci host\n");
return 0;
err_base_clk:
clk_disable_unprepare(sdhci_pdata->base_clk);
err_sys_clk:
clk_disable_unprepare(sdhci_pdata->sys_clk);
err_host:
sdhci_pltfm_free(pdev);
err:
dev_err(&pdev->dev, "pic32-sdhci probe failed: %d\n", ret);
return ret;
}
static int pic32_sdhci_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct pic32_sdhci_priv *sdhci_pdata = sdhci_priv(host);
u32 scratch;
scratch = readl(host->ioaddr + SDHCI_INT_STATUS);
sdhci_remove_host(host, scratch == (u32)~0);
clk_disable_unprepare(sdhci_pdata->base_clk);
clk_disable_unprepare(sdhci_pdata->sys_clk);
sdhci_pltfm_free(pdev);
return 0;
}
static const struct of_device_id pic32_sdhci_id_table[] = {
{ .compatible = "microchip,pic32mzda-sdhci" },
{}
};
MODULE_DEVICE_TABLE(of, pic32_sdhci_id_table);
static struct platform_driver pic32_sdhci_driver = {
.driver = {
.name = "pic32-sdhci",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(pic32_sdhci_id_table),
},
.probe = pic32_sdhci_probe,
.remove = pic32_sdhci_remove,
};
module_platform_driver(pic32_sdhci_driver);
MODULE_DESCRIPTION("Microchip PIC32 SDHCI driver");
MODULE_AUTHOR("Pistirica Sorin Andrei & Sandeep Sheriker");
MODULE_LICENSE("GPL v2");

View File

@ -23,7 +23,6 @@ struct sdhci_pltfm_data {
struct sdhci_pltfm_host { struct sdhci_pltfm_host {
struct clk *clk; struct clk *clk;
void *priv; /* to handle quirks across io-accessor calls */
/* migrate from sdhci_of_host */ /* migrate from sdhci_of_host */
unsigned int clock; unsigned int clock;

View File

@ -177,7 +177,6 @@ static int sdhci_pxav2_probe(struct platform_device *pdev)
return PTR_ERR(host); return PTR_ERR(host);
pltfm_host = sdhci_priv(host); pltfm_host = sdhci_priv(host);
pltfm_host->priv = NULL;
clk = clk_get(dev, "PXA-SDHCLK"); clk = clk_get(dev, "PXA-SDHCLK");
if (IS_ERR(clk)) { if (IS_ERR(clk)) {

View File

@ -132,11 +132,15 @@ static int armada_38x_quirks(struct platform_device *pdev,
{ {
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
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; struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host);
struct resource *res; struct resource *res;
host->quirks &= ~SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN; host->quirks &= ~SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN;
host->quirks |= SDHCI_QUIRK_MISSING_CAPS; host->quirks |= SDHCI_QUIRK_MISSING_CAPS;
host->caps = sdhci_readl(host, SDHCI_CAPABILITIES);
host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"conf-sdio3"); "conf-sdio3");
if (res) { if (res) {
@ -150,7 +154,6 @@ static int armada_38x_quirks(struct platform_device *pdev,
* Configuration register, if the adjustment is not done, * Configuration register, if the adjustment is not done,
* remove them from the capabilities. * remove them from the capabilities.
*/ */
host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50); host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50);
dev_warn(&pdev->dev, "conf-sdio3 register not found: disabling SDR50 and DDR50 modes.\nConsider updating your dtb\n"); dev_warn(&pdev->dev, "conf-sdio3 register not found: disabling SDR50 and DDR50 modes.\nConsider updating your dtb\n");
@ -161,7 +164,6 @@ static int armada_38x_quirks(struct platform_device *pdev,
* controller has different capabilities than the ones shown * controller has different capabilities than the ones shown
* in its registers * in its registers
*/ */
host->caps = sdhci_readl(host, SDHCI_CAPABILITIES);
if (of_property_read_bool(np, "no-1-8-v")) { if (of_property_read_bool(np, "no-1-8-v")) {
host->caps &= ~SDHCI_CAN_VDD_180; host->caps &= ~SDHCI_CAN_VDD_180;
host->mmc->caps &= ~MMC_CAP_1_8V_DDR; host->mmc->caps &= ~MMC_CAP_1_8V_DDR;
@ -201,7 +203,7 @@ static void pxav3_reset(struct sdhci_host *host, u8 mask)
static void pxav3_gen_init_74_clocks(struct sdhci_host *host, u8 power_mode) static void pxav3_gen_init_74_clocks(struct sdhci_host *host, u8 power_mode)
{ {
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; struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host);
u16 tmp; u16 tmp;
int count; int count;
@ -250,7 +252,7 @@ static void pxav3_gen_init_74_clocks(struct sdhci_host *host, u8 power_mode)
static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
{ {
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; struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host);
u16 ctrl_2; u16 ctrl_2;
/* /*
@ -370,16 +372,12 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
const struct of_device_id *match; const struct of_device_id *match;
int ret; int ret;
pxa = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_pxa), GFP_KERNEL); host = sdhci_pltfm_init(pdev, &sdhci_pxav3_pdata, sizeof(*pxa));
if (!pxa)
return -ENOMEM;
host = sdhci_pltfm_init(pdev, &sdhci_pxav3_pdata, 0);
if (IS_ERR(host)) if (IS_ERR(host))
return PTR_ERR(host); return PTR_ERR(host);
pltfm_host = sdhci_priv(host); pltfm_host = sdhci_priv(host);
pltfm_host->priv = pxa; pxa = sdhci_pltfm_priv(pltfm_host);
pxa->clk_io = devm_clk_get(dev, "io"); pxa->clk_io = devm_clk_get(dev, "io");
if (IS_ERR(pxa->clk_io)) if (IS_ERR(pxa->clk_io))
@ -486,7 +484,7 @@ 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; struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host);
pm_runtime_get_sync(&pdev->dev); pm_runtime_get_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
@ -535,7 +533,7 @@ 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; struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host);
int ret; int ret;
ret = sdhci_runtime_suspend_host(host); ret = sdhci_runtime_suspend_host(host);
@ -553,7 +551,7 @@ 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; struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host);
clk_prepare_enable(pxa->clk_io); clk_prepare_enable(pxa->clk_io);
if (!IS_ERR(pxa->clk_core)) if (!IS_ERR(pxa->clk_core))

View File

@ -251,7 +251,7 @@ static int sdhci_st_set_dll_for_clock(struct sdhci_host *host)
{ {
int ret = 0; int ret = 0;
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct st_mmc_platform_data *pdata = pltfm_host->priv; struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host);
if (host->clock > CLK_TO_CHECK_DLL_LOCK) { if (host->clock > CLK_TO_CHECK_DLL_LOCK) {
st_mmcss_set_dll(pdata->top_ioaddr); st_mmcss_set_dll(pdata->top_ioaddr);
@ -265,7 +265,7 @@ static void sdhci_st_set_uhs_signaling(struct sdhci_host *host,
unsigned int uhs) unsigned int uhs)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct st_mmc_platform_data *pdata = pltfm_host->priv; struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host);
u16 ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); u16 ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
int ret = 0; int ret = 0;
@ -357,10 +357,7 @@ static int sdhci_st_probe(struct platform_device *pdev)
int ret = 0; int ret = 0;
u16 host_version; u16 host_version;
struct resource *res; struct resource *res;
struct reset_control *rstc;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
clk = devm_clk_get(&pdev->dev, "mmc"); clk = devm_clk_get(&pdev->dev, "mmc");
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
@ -368,19 +365,23 @@ static int sdhci_st_probe(struct platform_device *pdev)
return PTR_ERR(clk); return PTR_ERR(clk);
} }
pdata->rstc = devm_reset_control_get(&pdev->dev, NULL); rstc = devm_reset_control_get(&pdev->dev, NULL);
if (IS_ERR(pdata->rstc)) if (IS_ERR(rstc))
pdata->rstc = NULL; rstc = NULL;
else else
reset_control_deassert(pdata->rstc); reset_control_deassert(rstc);
host = sdhci_pltfm_init(pdev, &sdhci_st_pdata, 0); host = sdhci_pltfm_init(pdev, &sdhci_st_pdata, sizeof(*pdata));
if (IS_ERR(host)) { if (IS_ERR(host)) {
dev_err(&pdev->dev, "Failed sdhci_pltfm_init\n"); dev_err(&pdev->dev, "Failed sdhci_pltfm_init\n");
ret = PTR_ERR(host); ret = PTR_ERR(host);
goto err_pltfm_init; goto err_pltfm_init;
} }
pltfm_host = sdhci_priv(host);
pdata = sdhci_pltfm_priv(pltfm_host);
pdata->rstc = rstc;
ret = mmc_of_parse(host->mmc); ret = mmc_of_parse(host->mmc);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed mmc_of_parse\n"); dev_err(&pdev->dev, "Failed mmc_of_parse\n");
@ -398,8 +399,6 @@ static int sdhci_st_probe(struct platform_device *pdev)
pdata->top_ioaddr = NULL; pdata->top_ioaddr = NULL;
} }
pltfm_host = sdhci_priv(host);
pltfm_host->priv = pdata;
pltfm_host->clk = clk; pltfm_host->clk = clk;
/* Configure the Arasan HC inside the flashSS */ /* Configure the Arasan HC inside the flashSS */
@ -427,8 +426,8 @@ err_out:
err_of: err_of:
sdhci_pltfm_free(pdev); sdhci_pltfm_free(pdev);
err_pltfm_init: err_pltfm_init:
if (pdata->rstc) if (rstc)
reset_control_assert(pdata->rstc); reset_control_assert(rstc);
return ret; return ret;
} }
@ -437,13 +436,14 @@ static int sdhci_st_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 st_mmc_platform_data *pdata = pltfm_host->priv; struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host);
struct reset_control *rstc = pdata->rstc;
int ret; int ret;
ret = sdhci_pltfm_unregister(pdev); ret = sdhci_pltfm_unregister(pdev);
if (pdata->rstc) if (rstc)
reset_control_assert(pdata->rstc); reset_control_assert(rstc);
return ret; return ret;
} }
@ -453,7 +453,7 @@ static int sdhci_st_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 st_mmc_platform_data *pdata = pltfm_host->priv; struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host);
int ret = sdhci_suspend_host(host); int ret = sdhci_suspend_host(host);
if (ret) if (ret)
@ -471,7 +471,7 @@ static int sdhci_st_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 st_mmc_platform_data *pdata = pltfm_host->priv; struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host);
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
clk_prepare_enable(pltfm_host->clk); clk_prepare_enable(pltfm_host->clk);

View File

@ -12,6 +12,7 @@
* *
*/ */
#include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
@ -42,12 +43,17 @@
#define SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 0x20 #define SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 0x20
#define SDHCI_MISC_CTRL_ENABLE_DDR50 0x200 #define SDHCI_MISC_CTRL_ENABLE_DDR50 0x200
#define SDHCI_TEGRA_AUTO_CAL_CONFIG 0x1e4
#define SDHCI_AUTO_CAL_START BIT(31)
#define SDHCI_AUTO_CAL_ENABLE BIT(29)
#define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0) #define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0)
#define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1) #define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1)
#define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2) #define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2)
#define NVQUIRK_ENABLE_SDR50 BIT(3) #define NVQUIRK_ENABLE_SDR50 BIT(3)
#define NVQUIRK_ENABLE_SDR104 BIT(4) #define NVQUIRK_ENABLE_SDR104 BIT(4)
#define NVQUIRK_ENABLE_DDR50 BIT(5) #define NVQUIRK_ENABLE_DDR50 BIT(5)
#define NVQUIRK_HAS_PADCALIB BIT(6)
struct sdhci_tegra_soc_data { struct sdhci_tegra_soc_data {
const struct sdhci_pltfm_data *pdata; const struct sdhci_pltfm_data *pdata;
@ -58,12 +64,13 @@ struct sdhci_tegra {
const struct sdhci_tegra_soc_data *soc_data; const struct sdhci_tegra_soc_data *soc_data;
struct gpio_desc *power_gpio; struct gpio_desc *power_gpio;
bool ddr_signaling; bool ddr_signaling;
bool pad_calib_required;
}; };
static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_tegra *tegra_host = pltfm_host->priv; struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
if (unlikely((soc_data->nvquirks & NVQUIRK_FORCE_SDHCI_SPEC_200) && if (unlikely((soc_data->nvquirks & NVQUIRK_FORCE_SDHCI_SPEC_200) &&
@ -99,7 +106,7 @@ static void tegra_sdhci_writew(struct sdhci_host *host, u16 val, int reg)
static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg) static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_tegra *tegra_host = pltfm_host->priv; struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
/* Seems like we're getting spurious timeout and crc errors, so /* Seems like we're getting spurious timeout and crc errors, so
@ -131,7 +138,7 @@ static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host)
static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_tegra *tegra_host = pltfm_host->priv; struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
u32 misc_ctrl, clk_ctrl; u32 misc_ctrl, clk_ctrl;
@ -147,10 +154,16 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
/* Advertise UHS modes as supported by host */ /* Advertise UHS modes as supported by host */
if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR50) if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR50)
misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR50; misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR50;
else
misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR50;
if (soc_data->nvquirks & NVQUIRK_ENABLE_DDR50) if (soc_data->nvquirks & NVQUIRK_ENABLE_DDR50)
misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_DDR50; misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_DDR50;
else
misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_DDR50;
if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR104) if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR104)
misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR104; misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR104;
else
misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR104;
sdhci_writel(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL); sdhci_writel(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL);
clk_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); clk_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL);
@ -159,6 +172,9 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE; clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE;
sdhci_writel(host, clk_ctrl, SDHCI_TEGRA_VENDOR_CLOCK_CTRL); sdhci_writel(host, clk_ctrl, SDHCI_TEGRA_VENDOR_CLOCK_CTRL);
if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB)
tegra_host->pad_calib_required = true;
tegra_host->ddr_signaling = false; tegra_host->ddr_signaling = false;
} }
@ -181,27 +197,43 @@ static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width)
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
} }
static void tegra_sdhci_pad_autocalib(struct sdhci_host *host)
{
u32 val;
mdelay(1);
val = sdhci_readl(host, SDHCI_TEGRA_AUTO_CAL_CONFIG);
val |= SDHCI_AUTO_CAL_ENABLE | SDHCI_AUTO_CAL_START;
sdhci_writel(host,val, SDHCI_TEGRA_AUTO_CAL_CONFIG);
}
static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_tegra *tegra_host = pltfm_host->priv; struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
unsigned long host_clk; unsigned long host_clk;
if (!clock) if (!clock)
return; return sdhci_set_clock(host, clock);
host_clk = tegra_host->ddr_signaling ? clock * 2 : clock; host_clk = tegra_host->ddr_signaling ? clock * 2 : clock;
clk_set_rate(pltfm_host->clk, host_clk); clk_set_rate(pltfm_host->clk, host_clk);
host->max_clk = clk_get_rate(pltfm_host->clk); host->max_clk = clk_get_rate(pltfm_host->clk);
return sdhci_set_clock(host, clock); sdhci_set_clock(host, clock);
if (tegra_host->pad_calib_required) {
tegra_sdhci_pad_autocalib(host);
tegra_host->pad_calib_required = false;
}
} }
static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host, static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,
unsigned timing) unsigned timing)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_tegra *tegra_host = pltfm_host->priv; struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
if (timing == MMC_TIMING_UHS_DDR50) if (timing == MMC_TIMING_UHS_DDR50)
tegra_host->ddr_signaling = true; tegra_host->ddr_signaling = true;
@ -264,6 +296,16 @@ static int tegra_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
return mmc_send_tuning(host->mmc, opcode, NULL); return mmc_send_tuning(host->mmc, opcode, NULL);
} }
static void tegra_sdhci_voltage_switch(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host);
const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
if (soc_data->nvquirks & NVQUIRK_HAS_PADCALIB)
tegra_host->pad_calib_required = true;
}
static const struct sdhci_ops tegra_sdhci_ops = { static const struct sdhci_ops tegra_sdhci_ops = {
.get_ro = tegra_sdhci_get_ro, .get_ro = tegra_sdhci_get_ro,
.read_w = tegra_sdhci_readw, .read_w = tegra_sdhci_readw,
@ -273,6 +315,7 @@ static const struct sdhci_ops tegra_sdhci_ops = {
.reset = tegra_sdhci_reset, .reset = tegra_sdhci_reset,
.platform_execute_tuning = tegra_sdhci_execute_tuning, .platform_execute_tuning = tegra_sdhci_execute_tuning,
.set_uhs_signaling = tegra_sdhci_set_uhs_signaling, .set_uhs_signaling = tegra_sdhci_set_uhs_signaling,
.voltage_switch = tegra_sdhci_voltage_switch,
.get_max_clock = tegra_sdhci_get_max_clock, .get_max_clock = tegra_sdhci_get_max_clock,
}; };
@ -306,7 +349,8 @@ static const struct sdhci_tegra_soc_data soc_data_tegra30 = {
.pdata = &sdhci_tegra30_pdata, .pdata = &sdhci_tegra30_pdata,
.nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300 | .nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300 |
NVQUIRK_ENABLE_SDR50 | NVQUIRK_ENABLE_SDR50 |
NVQUIRK_ENABLE_SDR104, NVQUIRK_ENABLE_SDR104 |
NVQUIRK_HAS_PADCALIB,
}; };
static const struct sdhci_ops tegra114_sdhci_ops = { static const struct sdhci_ops tegra114_sdhci_ops = {
@ -319,6 +363,7 @@ static const struct sdhci_ops tegra114_sdhci_ops = {
.reset = tegra_sdhci_reset, .reset = tegra_sdhci_reset,
.platform_execute_tuning = tegra_sdhci_execute_tuning, .platform_execute_tuning = tegra_sdhci_execute_tuning,
.set_uhs_signaling = tegra_sdhci_set_uhs_signaling, .set_uhs_signaling = tegra_sdhci_set_uhs_signaling,
.voltage_switch = tegra_sdhci_voltage_switch,
.get_max_clock = tegra_sdhci_get_max_clock, .get_max_clock = tegra_sdhci_get_max_clock,
}; };
@ -335,9 +380,14 @@ static const struct sdhci_pltfm_data sdhci_tegra114_pdata = {
static const struct sdhci_tegra_soc_data soc_data_tegra114 = { static const struct sdhci_tegra_soc_data soc_data_tegra114 = {
.pdata = &sdhci_tegra114_pdata, .pdata = &sdhci_tegra114_pdata,
};
static const struct sdhci_tegra_soc_data soc_data_tegra124 = {
.pdata = &sdhci_tegra114_pdata,
.nvquirks = NVQUIRK_ENABLE_SDR50 | .nvquirks = NVQUIRK_ENABLE_SDR50 |
NVQUIRK_ENABLE_DDR50 | NVQUIRK_ENABLE_DDR50 |
NVQUIRK_ENABLE_SDR104, NVQUIRK_ENABLE_SDR104 |
NVQUIRK_HAS_PADCALIB,
}; };
static const struct sdhci_pltfm_data sdhci_tegra210_pdata = { static const struct sdhci_pltfm_data sdhci_tegra210_pdata = {
@ -357,7 +407,7 @@ static const struct sdhci_tegra_soc_data soc_data_tegra210 = {
static const struct of_device_id sdhci_tegra_dt_match[] = { static const struct of_device_id sdhci_tegra_dt_match[] = {
{ .compatible = "nvidia,tegra210-sdhci", .data = &soc_data_tegra210 }, { .compatible = "nvidia,tegra210-sdhci", .data = &soc_data_tegra210 },
{ .compatible = "nvidia,tegra124-sdhci", .data = &soc_data_tegra114 }, { .compatible = "nvidia,tegra124-sdhci", .data = &soc_data_tegra124 },
{ .compatible = "nvidia,tegra114-sdhci", .data = &soc_data_tegra114 }, { .compatible = "nvidia,tegra114-sdhci", .data = &soc_data_tegra114 },
{ .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 }, { .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 },
{ .compatible = "nvidia,tegra20-sdhci", .data = &soc_data_tegra20 }, { .compatible = "nvidia,tegra20-sdhci", .data = &soc_data_tegra20 },
@ -380,20 +430,15 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
soc_data = match->data; soc_data = match->data;
host = sdhci_pltfm_init(pdev, soc_data->pdata, 0); host = sdhci_pltfm_init(pdev, soc_data->pdata, sizeof(*tegra_host));
if (IS_ERR(host)) if (IS_ERR(host))
return PTR_ERR(host); return PTR_ERR(host);
pltfm_host = sdhci_priv(host); pltfm_host = sdhci_priv(host);
tegra_host = devm_kzalloc(&pdev->dev, sizeof(*tegra_host), GFP_KERNEL); tegra_host = sdhci_pltfm_priv(pltfm_host);
if (!tegra_host) {
dev_err(mmc_dev(host->mmc), "failed to allocate tegra_host\n");
rc = -ENOMEM;
goto err_alloc_tegra_host;
}
tegra_host->ddr_signaling = false; tegra_host->ddr_signaling = false;
tegra_host->pad_calib_required = false;
tegra_host->soc_data = soc_data; tegra_host->soc_data = soc_data;
pltfm_host->priv = tegra_host;
rc = mmc_of_parse(host->mmc); rc = mmc_of_parse(host->mmc);
if (rc) if (rc)
@ -429,7 +474,6 @@ err_add_host:
err_clk_get: err_clk_get:
err_power_req: err_power_req:
err_parse_dt: err_parse_dt:
err_alloc_tegra_host:
sdhci_pltfm_free(pdev); sdhci_pltfm_free(pdev);
return rc; return rc;
} }

View File

@ -53,8 +53,6 @@ static void sdhci_finish_data(struct sdhci_host *);
static void sdhci_finish_command(struct sdhci_host *); static void sdhci_finish_command(struct sdhci_host *);
static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
static int sdhci_pre_dma_transfer(struct sdhci_host *host,
struct mmc_data *data);
static int sdhci_do_get_cd(struct sdhci_host *host); static int sdhci_do_get_cd(struct sdhci_host *host);
#ifdef CONFIG_PM #ifdef CONFIG_PM
@ -428,6 +426,31 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
DBG("PIO transfer complete.\n"); DBG("PIO transfer complete.\n");
} }
static int sdhci_pre_dma_transfer(struct sdhci_host *host,
struct mmc_data *data, int cookie)
{
int sg_count;
/*
* If the data buffers are already mapped, return the previous
* dma_map_sg() result.
*/
if (data->host_cookie == COOKIE_PRE_MAPPED)
return data->sg_count;
sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
data->flags & MMC_DATA_WRITE ?
DMA_TO_DEVICE : DMA_FROM_DEVICE);
if (sg_count == 0)
return -ENOSPC;
data->sg_count = sg_count;
data->host_cookie = cookie;
return sg_count;
}
static char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags) static char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags)
{ {
local_irq_save(*flags); local_irq_save(*flags);
@ -462,41 +485,22 @@ static void sdhci_adma_mark_end(void *desc)
dma_desc->cmd |= cpu_to_le16(ADMA2_END); dma_desc->cmd |= cpu_to_le16(ADMA2_END);
} }
static int sdhci_adma_table_pre(struct sdhci_host *host, static void sdhci_adma_table_pre(struct sdhci_host *host,
struct mmc_data *data) struct mmc_data *data, int sg_count)
{ {
int direction;
void *desc;
void *align;
dma_addr_t addr;
dma_addr_t align_addr;
int len, offset;
struct scatterlist *sg; struct scatterlist *sg;
int i;
char *buffer;
unsigned long flags; unsigned long flags;
dma_addr_t addr, align_addr;
void *desc, *align;
char *buffer;
int len, offset, i;
/* /*
* The spec does not specify endianness of descriptor table. * The spec does not specify endianness of descriptor table.
* We currently guess that it is LE. * We currently guess that it is LE.
*/ */
if (data->flags & MMC_DATA_READ) host->sg_count = sg_count;
direction = DMA_FROM_DEVICE;
else
direction = DMA_TO_DEVICE;
host->align_addr = dma_map_single(mmc_dev(host->mmc),
host->align_buffer, host->align_buffer_sz, direction);
if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr))
goto fail;
BUG_ON(host->align_addr & SDHCI_ADMA2_MASK);
host->sg_count = sdhci_pre_dma_transfer(host, data);
if (host->sg_count < 0)
goto unmap_align;
desc = host->adma_table; desc = host->adma_table;
align = host->align_buffer; align = host->align_buffer;
@ -508,10 +512,9 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
len = sg_dma_len(sg); len = sg_dma_len(sg);
/* /*
* The SDHCI specification states that ADMA * The SDHCI specification states that ADMA addresses must
* addresses must be 32-bit aligned. If they * be 32-bit aligned. If they aren't, then we use a bounce
* aren't, then we use a bounce buffer for * buffer for the (up to three) bytes that screw up the
* the (up to three) bytes that screw up the
* alignment. * alignment.
*/ */
offset = (SDHCI_ADMA2_ALIGN - (addr & SDHCI_ADMA2_MASK)) & offset = (SDHCI_ADMA2_ALIGN - (addr & SDHCI_ADMA2_MASK)) &
@ -555,92 +558,56 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
} }
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_table) { if (desc != host->adma_table) {
desc -= host->desc_sz; desc -= host->desc_sz;
sdhci_adma_mark_end(desc); sdhci_adma_mark_end(desc);
} }
} else { } else {
/* /* Add a terminating entry - nop, end, valid */
* Add a terminating entry.
*/
/* nop, end, valid */
sdhci_adma_write_desc(host, desc, 0, 0, ADMA2_NOP_END_VALID); sdhci_adma_write_desc(host, desc, 0, 0, ADMA2_NOP_END_VALID);
} }
/*
* Resync align buffer as we might have changed it.
*/
if (data->flags & MMC_DATA_WRITE) {
dma_sync_single_for_device(mmc_dev(host->mmc),
host->align_addr, host->align_buffer_sz, direction);
}
return 0;
unmap_align:
dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
host->align_buffer_sz, direction);
fail:
return -EINVAL;
} }
static void sdhci_adma_table_post(struct sdhci_host *host, static void sdhci_adma_table_post(struct sdhci_host *host,
struct mmc_data *data) struct mmc_data *data)
{ {
int direction;
struct scatterlist *sg; struct scatterlist *sg;
int i, size; int i, size;
void *align; void *align;
char *buffer; char *buffer;
unsigned long flags; unsigned long flags;
bool has_unaligned;
if (data->flags & MMC_DATA_READ) if (data->flags & MMC_DATA_READ) {
direction = DMA_FROM_DEVICE; bool has_unaligned = false;
else
direction = DMA_TO_DEVICE;
dma_unmap_single(mmc_dev(host->mmc), host->align_addr, /* Do a quick scan of the SG list for any unaligned mappings */
host->align_buffer_sz, direction); for_each_sg(data->sg, sg, host->sg_count, i)
/* Do a quick scan of the SG list for any unaligned mappings */
has_unaligned = false;
for_each_sg(data->sg, sg, host->sg_count, i)
if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) {
has_unaligned = true;
break;
}
if (has_unaligned && data->flags & MMC_DATA_READ) {
dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg,
data->sg_len, direction);
align = host->align_buffer;
for_each_sg(data->sg, sg, host->sg_count, i) {
if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) { if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) {
size = SDHCI_ADMA2_ALIGN - has_unaligned = true;
(sg_dma_address(sg) & SDHCI_ADMA2_MASK); break;
}
buffer = sdhci_kmap_atomic(sg, &flags); if (has_unaligned) {
memcpy(buffer, align, size); dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg,
sdhci_kunmap_atomic(buffer, &flags); data->sg_len, DMA_FROM_DEVICE);
align += SDHCI_ADMA2_ALIGN; align = host->align_buffer;
for_each_sg(data->sg, sg, host->sg_count, i) {
if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) {
size = SDHCI_ADMA2_ALIGN -
(sg_dma_address(sg) & SDHCI_ADMA2_MASK);
buffer = sdhci_kmap_atomic(sg, &flags);
memcpy(buffer, align, size);
sdhci_kunmap_atomic(buffer, &flags);
align += SDHCI_ADMA2_ALIGN;
}
} }
} }
} }
if (data->host_cookie == COOKIE_MAPPED) {
dma_unmap_sg(mmc_dev(host->mmc), data->sg,
data->sg_len, direction);
data->host_cookie = COOKIE_UNMAPPED;
}
} }
static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
@ -666,9 +633,20 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
if (!data) if (!data)
target_timeout = cmd->busy_timeout * 1000; target_timeout = cmd->busy_timeout * 1000;
else { else {
target_timeout = data->timeout_ns / 1000; target_timeout = DIV_ROUND_UP(data->timeout_ns, 1000);
if (host->clock) if (host->clock && data->timeout_clks) {
target_timeout += data->timeout_clks / host->clock; unsigned long long val;
/*
* data->timeout_clks is in units of clock cycles.
* host->clock is in Hz. target_timeout is in us.
* Hence, us = 1000000 * cycles / Hz. Round up.
*/
val = 1000000 * data->timeout_clks;
if (do_div(val, host->clock))
target_timeout++;
target_timeout += val;
}
} }
/* /*
@ -729,7 +707,6 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
{ {
u8 ctrl; u8 ctrl;
struct mmc_data *data = cmd->data; struct mmc_data *data = cmd->data;
int ret;
WARN_ON(host->data); WARN_ON(host->data);
@ -748,63 +725,48 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
host->data_early = 0; host->data_early = 0;
host->data->bytes_xfered = 0; host->data->bytes_xfered = 0;
if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
struct scatterlist *sg;
unsigned int length_mask, offset_mask;
int i;
host->flags |= SDHCI_REQ_USE_DMA; host->flags |= SDHCI_REQ_USE_DMA;
/* /*
* FIXME: This doesn't account for merging when mapping the * FIXME: This doesn't account for merging when mapping the
* scatterlist. * scatterlist.
*/ *
if (host->flags & SDHCI_REQ_USE_DMA) { * The assumption here being that alignment and lengths are
int broken, i; * the same after DMA mapping to device address space.
struct scatterlist *sg; */
length_mask = 0;
broken = 0; offset_mask = 0;
if (host->flags & SDHCI_USE_ADMA) { if (host->flags & SDHCI_USE_ADMA) {
if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE) if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE) {
broken = 1; length_mask = 3;
/*
* As we use up to 3 byte chunks to work
* around alignment problems, we need to
* check the offset as well.
*/
offset_mask = 3;
}
} else { } else {
if (host->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE) if (host->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE)
broken = 1; length_mask = 3;
if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR)
offset_mask = 3;
} }
if (unlikely(broken)) { if (unlikely(length_mask | offset_mask)) {
for_each_sg(data->sg, sg, data->sg_len, i) { for_each_sg(data->sg, sg, data->sg_len, i) {
if (sg->length & 0x3) { if (sg->length & length_mask) {
DBG("Reverting to PIO because of transfer size (%d)\n", DBG("Reverting to PIO because of transfer size (%d)\n",
sg->length); sg->length);
host->flags &= ~SDHCI_REQ_USE_DMA; host->flags &= ~SDHCI_REQ_USE_DMA;
break; break;
} }
} if (sg->offset & offset_mask) {
}
}
/*
* The assumption here being that alignment is the same after
* translation to device address space.
*/
if (host->flags & SDHCI_REQ_USE_DMA) {
int broken, i;
struct scatterlist *sg;
broken = 0;
if (host->flags & SDHCI_USE_ADMA) {
/*
* As we use 3 byte chunks to work around
* alignment problems, we need to check this
* quirk.
*/
if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE)
broken = 1;
} else {
if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR)
broken = 1;
}
if (unlikely(broken)) {
for_each_sg(data->sg, sg, data->sg_len, i) {
if (sg->offset & 0x3) {
DBG("Reverting to PIO because of bad alignment\n"); DBG("Reverting to PIO because of bad alignment\n");
host->flags &= ~SDHCI_REQ_USE_DMA; host->flags &= ~SDHCI_REQ_USE_DMA;
break; break;
@ -814,39 +776,27 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
} }
if (host->flags & SDHCI_REQ_USE_DMA) { if (host->flags & SDHCI_REQ_USE_DMA) {
if (host->flags & SDHCI_USE_ADMA) { int sg_cnt = sdhci_pre_dma_transfer(host, data, COOKIE_MAPPED);
ret = sdhci_adma_table_pre(host, data);
if (ret) {
/*
* This only happens when someone fed
* us an invalid request.
*/
WARN_ON(1);
host->flags &= ~SDHCI_REQ_USE_DMA;
} else {
sdhci_writel(host, host->adma_addr,
SDHCI_ADMA_ADDRESS);
if (host->flags & SDHCI_USE_64_BIT_DMA)
sdhci_writel(host,
(u64)host->adma_addr >> 32,
SDHCI_ADMA_ADDRESS_HI);
}
} else {
int sg_cnt;
sg_cnt = sdhci_pre_dma_transfer(host, data); if (sg_cnt <= 0) {
if (sg_cnt <= 0) { /*
/* * This only happens when someone fed
* This only happens when someone fed * us an invalid request.
* us an invalid request. */
*/ WARN_ON(1);
WARN_ON(1); host->flags &= ~SDHCI_REQ_USE_DMA;
host->flags &= ~SDHCI_REQ_USE_DMA; } else if (host->flags & SDHCI_USE_ADMA) {
} else { sdhci_adma_table_pre(host, data, sg_cnt);
WARN_ON(sg_cnt != 1);
sdhci_writel(host, sg_dma_address(data->sg), sdhci_writel(host, host->adma_addr, SDHCI_ADMA_ADDRESS);
SDHCI_DMA_ADDRESS); if (host->flags & SDHCI_USE_64_BIT_DMA)
} sdhci_writel(host,
(u64)host->adma_addr >> 32,
SDHCI_ADMA_ADDRESS_HI);
} else {
WARN_ON(sg_cnt != 1);
sdhci_writel(host, sg_dma_address(data->sg),
SDHCI_DMA_ADDRESS);
} }
} }
@ -946,19 +896,9 @@ static void sdhci_finish_data(struct sdhci_host *host)
data = host->data; data = host->data;
host->data = NULL; host->data = NULL;
if (host->flags & SDHCI_REQ_USE_DMA) { if ((host->flags & (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA)) ==
if (host->flags & SDHCI_USE_ADMA) (SDHCI_REQ_USE_DMA | SDHCI_USE_ADMA))
sdhci_adma_table_post(host, data); sdhci_adma_table_post(host, data);
else {
if (data->host_cookie == COOKIE_MAPPED) {
dma_unmap_sg(mmc_dev(host->mmc),
data->sg, data->sg_len,
(data->flags & MMC_DATA_READ) ?
DMA_FROM_DEVICE : DMA_TO_DEVICE);
data->host_cookie = COOKIE_UNMAPPED;
}
}
}
/* /*
* The specification states that the block count register must * The specification states that the block count register must
@ -1003,6 +943,9 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
WARN_ON(host->cmd); WARN_ON(host->cmd);
/* Initially, a command has no error */
cmd->error = 0;
/* Wait max 10 ms */ /* Wait max 10 ms */
timeout = 10; timeout = 10;
@ -1097,8 +1040,6 @@ static void sdhci_finish_command(struct sdhci_host *host)
} }
} }
host->cmd->error = 0;
/* Finished CMD23, now send actual command. */ /* Finished CMD23, now send actual command. */
if (host->cmd == host->mrq->sbc) { if (host->cmd == host->mrq->sbc) {
host->cmd = NULL; host->cmd = NULL;
@ -2114,39 +2055,12 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
struct sdhci_host *host = mmc_priv(mmc); struct sdhci_host *host = mmc_priv(mmc);
struct mmc_data *data = mrq->data; struct mmc_data *data = mrq->data;
if (host->flags & SDHCI_REQ_USE_DMA) { if (data->host_cookie != COOKIE_UNMAPPED)
if (data->host_cookie == COOKIE_GIVEN || dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
data->host_cookie == COOKIE_MAPPED) data->flags & MMC_DATA_WRITE ?
dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, DMA_TO_DEVICE : DMA_FROM_DEVICE);
data->flags & MMC_DATA_WRITE ?
DMA_TO_DEVICE : DMA_FROM_DEVICE);
data->host_cookie = COOKIE_UNMAPPED;
}
}
static int sdhci_pre_dma_transfer(struct sdhci_host *host, data->host_cookie = COOKIE_UNMAPPED;
struct mmc_data *data)
{
int sg_count;
if (data->host_cookie == COOKIE_MAPPED) {
data->host_cookie = COOKIE_GIVEN;
return data->sg_count;
}
WARN_ON(data->host_cookie == COOKIE_GIVEN);
sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
data->flags & MMC_DATA_WRITE ?
DMA_TO_DEVICE : DMA_FROM_DEVICE);
if (sg_count == 0)
return -ENOSPC;
data->sg_count = sg_count;
data->host_cookie = COOKIE_MAPPED;
return sg_count;
} }
static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
@ -2157,7 +2071,7 @@ static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
mrq->data->host_cookie = COOKIE_UNMAPPED; mrq->data->host_cookie = COOKIE_UNMAPPED;
if (host->flags & SDHCI_REQ_USE_DMA) if (host->flags & SDHCI_REQ_USE_DMA)
sdhci_pre_dma_transfer(host, mrq->data); sdhci_pre_dma_transfer(host, mrq->data, COOKIE_PRE_MAPPED);
} }
static void sdhci_card_event(struct mmc_host *mmc) static void sdhci_card_event(struct mmc_host *mmc)
@ -2237,6 +2151,22 @@ static void sdhci_tasklet_finish(unsigned long param)
mrq = host->mrq; mrq = host->mrq;
/*
* Always unmap the data buffers if they were mapped by
* sdhci_prepare_data() whenever we finish with a request.
* This avoids leaking DMA mappings on error.
*/
if (host->flags & SDHCI_REQ_USE_DMA) {
struct mmc_data *data = mrq->data;
if (data && data->host_cookie == COOKIE_MAPPED) {
dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
(data->flags & MMC_DATA_READ) ?
DMA_FROM_DEVICE : DMA_TO_DEVICE);
data->host_cookie = COOKIE_UNMAPPED;
}
}
/* /*
* The controller needs a reset of internal state machines * The controller needs a reset of internal state machines
* upon error conditions. * upon error conditions.
@ -2322,13 +2252,30 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask)
return; return;
} }
if (intmask & SDHCI_INT_TIMEOUT) if (intmask & (SDHCI_INT_TIMEOUT | SDHCI_INT_CRC |
host->cmd->error = -ETIMEDOUT; SDHCI_INT_END_BIT | SDHCI_INT_INDEX)) {
else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT | if (intmask & SDHCI_INT_TIMEOUT)
SDHCI_INT_INDEX)) host->cmd->error = -ETIMEDOUT;
host->cmd->error = -EILSEQ; else
host->cmd->error = -EILSEQ;
/*
* If this command initiates a data phase and a response
* CRC error is signalled, the card can start transferring
* data - the card may have received the command without
* error. We must not terminate the mmc_request early.
*
* If the card did not receive the command or returned an
* error which prevented it sending data, the data phase
* will time out.
*/
if (host->cmd->data &&
(intmask & (SDHCI_INT_CRC | SDHCI_INT_TIMEOUT)) ==
SDHCI_INT_CRC) {
host->cmd = NULL;
return;
}
if (host->cmd->error) {
tasklet_schedule(&host->finish_tasklet); tasklet_schedule(&host->finish_tasklet);
return; return;
} }
@ -2857,6 +2804,36 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev,
EXPORT_SYMBOL_GPL(sdhci_alloc_host); EXPORT_SYMBOL_GPL(sdhci_alloc_host);
static int sdhci_set_dma_mask(struct sdhci_host *host)
{
struct mmc_host *mmc = host->mmc;
struct device *dev = mmc_dev(mmc);
int ret = -EINVAL;
if (host->quirks2 & SDHCI_QUIRK2_BROKEN_64_BIT_DMA)
host->flags &= ~SDHCI_USE_64_BIT_DMA;
/* Try 64-bit mask if hardware is capable of it */
if (host->flags & SDHCI_USE_64_BIT_DMA) {
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
if (ret) {
pr_warn("%s: Failed to set 64-bit DMA mask.\n",
mmc_hostname(mmc));
host->flags &= ~SDHCI_USE_64_BIT_DMA;
}
}
/* 32-bit mask as default & fallback */
if (ret) {
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
if (ret)
pr_warn("%s: Failed to set 32-bit DMA mask.\n",
mmc_hostname(mmc));
}
return ret;
}
int sdhci_add_host(struct sdhci_host *host) int sdhci_add_host(struct sdhci_host *host)
{ {
struct mmc_host *mmc; struct mmc_host *mmc;
@ -2928,17 +2905,21 @@ int sdhci_add_host(struct sdhci_host *host)
* SDHCI_QUIRK2_BROKEN_64_BIT_DMA must be left to the drivers to * SDHCI_QUIRK2_BROKEN_64_BIT_DMA must be left to the drivers to
* implement. * implement.
*/ */
if (sdhci_readl(host, SDHCI_CAPABILITIES) & SDHCI_CAN_64BIT) if (caps[0] & SDHCI_CAN_64BIT)
host->flags |= SDHCI_USE_64_BIT_DMA; 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) { ret = sdhci_set_dma_mask(host);
if (host->ops->enable_dma(host)) {
pr_warn("%s: No suitable DMA available - falling back to PIO\n", if (!ret && host->ops->enable_dma)
mmc_hostname(mmc)); ret = host->ops->enable_dma(host);
host->flags &=
~(SDHCI_USE_SDMA | SDHCI_USE_ADMA); if (ret) {
} pr_warn("%s: No suitable DMA available - falling back to PIO\n",
mmc_hostname(mmc));
host->flags &= ~(SDHCI_USE_SDMA | SDHCI_USE_ADMA);
ret = 0;
} }
} }
@ -2947,6 +2928,9 @@ int sdhci_add_host(struct sdhci_host *host)
host->flags &= ~SDHCI_USE_SDMA; host->flags &= ~SDHCI_USE_SDMA;
if (host->flags & SDHCI_USE_ADMA) { if (host->flags & SDHCI_USE_ADMA) {
dma_addr_t dma;
void *buf;
/* /*
* The DMA descriptor table size is calculated as the maximum * The DMA descriptor table size is calculated as the maximum
* number of segments times 2, to allow for an alignment * number of segments times 2, to allow for an alignment
@ -2962,33 +2946,27 @@ int sdhci_add_host(struct sdhci_host *host)
SDHCI_ADMA2_32_DESC_SZ; SDHCI_ADMA2_32_DESC_SZ;
host->desc_sz = SDHCI_ADMA2_32_DESC_SZ; host->desc_sz = SDHCI_ADMA2_32_DESC_SZ;
} }
host->adma_table = dma_alloc_coherent(mmc_dev(mmc),
host->adma_table_sz,
&host->adma_addr,
GFP_KERNEL);
host->align_buffer_sz = SDHCI_MAX_SEGS * SDHCI_ADMA2_ALIGN; host->align_buffer_sz = SDHCI_MAX_SEGS * SDHCI_ADMA2_ALIGN;
host->align_buffer = kmalloc(host->align_buffer_sz, GFP_KERNEL); buf = dma_alloc_coherent(mmc_dev(mmc), host->align_buffer_sz +
if (!host->adma_table || !host->align_buffer) { host->adma_table_sz, &dma, GFP_KERNEL);
if (host->adma_table) if (!buf) {
dma_free_coherent(mmc_dev(mmc),
host->adma_table_sz,
host->adma_table,
host->adma_addr);
kfree(host->align_buffer);
pr_warn("%s: Unable to allocate ADMA buffers - falling back to standard DMA\n", 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_table = NULL; } else if ((dma + host->align_buffer_sz) &
host->align_buffer = NULL; (SDHCI_ADMA2_DESC_ALIGN - 1)) {
} else if (host->adma_addr & (SDHCI_ADMA2_DESC_ALIGN - 1)) {
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), host->adma_table_sz, dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz +
host->adma_table, host->adma_addr); host->adma_table_sz, buf, dma);
kfree(host->align_buffer); } else {
host->adma_table = NULL; host->align_buffer = buf;
host->align_buffer = NULL; host->align_addr = dma;
host->adma_table = buf + host->align_buffer_sz;
host->adma_addr = dma + host->align_buffer_sz;
} }
} }
@ -3072,14 +3050,14 @@ int sdhci_add_host(struct sdhci_host *host)
if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT) if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT)
host->timeout_clk *= 1000; host->timeout_clk *= 1000;
if (override_timeout_clk)
host->timeout_clk = override_timeout_clk;
mmc->max_busy_timeout = host->ops->get_max_timeout_count ? mmc->max_busy_timeout = host->ops->get_max_timeout_count ?
host->ops->get_max_timeout_count(host) : 1 << 27; host->ops->get_max_timeout_count(host) : 1 << 27;
mmc->max_busy_timeout /= host->timeout_clk; mmc->max_busy_timeout /= host->timeout_clk;
} }
if (override_timeout_clk)
host->timeout_clk = override_timeout_clk;
mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23; mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
@ -3449,10 +3427,10 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
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_table) if (host->align_buffer)
dma_free_coherent(mmc_dev(mmc), host->adma_table_sz, dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz +
host->adma_table, host->adma_addr); host->adma_table_sz, host->align_buffer,
kfree(host->align_buffer); host->align_addr);
host->adma_table = NULL; host->adma_table = NULL;
host->align_buffer = NULL; host->align_buffer = NULL;

View File

@ -316,8 +316,8 @@ struct sdhci_adma2_64_desc {
enum sdhci_cookie { enum sdhci_cookie {
COOKIE_UNMAPPED, COOKIE_UNMAPPED,
COOKIE_MAPPED, COOKIE_PRE_MAPPED, /* mapped by sdhci_pre_req() */
COOKIE_GIVEN, COOKIE_MAPPED, /* mapped by sdhci_prepare_data() */
}; };
struct sdhci_host { struct sdhci_host {

View File

@ -398,10 +398,10 @@ static struct mmc_host_ops sdricoh_ops = {
static int sdricoh_init_mmc(struct pci_dev *pci_dev, static int sdricoh_init_mmc(struct pci_dev *pci_dev,
struct pcmcia_device *pcmcia_dev) struct pcmcia_device *pcmcia_dev)
{ {
int result = 0; int result;
void __iomem *iobase = NULL; void __iomem *iobase;
struct mmc_host *mmc = NULL; struct mmc_host *mmc;
struct sdricoh_host *host = NULL; struct sdricoh_host *host;
struct device *dev = &pcmcia_dev->dev; struct device *dev = &pcmcia_dev->dev;
/* map iomem */ /* map iomem */
if (pci_resource_len(pci_dev, SDRICOH_PCI_REGION) != if (pci_resource_len(pci_dev, SDRICOH_PCI_REGION) !=
@ -419,7 +419,7 @@ static int sdricoh_init_mmc(struct pci_dev *pci_dev,
if (readl(iobase + R104_VERSION) != 0x4000) { if (readl(iobase + R104_VERSION) != 0x4000) {
dev_dbg(dev, "no supported mmc controller found\n"); dev_dbg(dev, "no supported mmc controller found\n");
result = -ENODEV; result = -ENODEV;
goto err; goto unmap_io;
} }
/* allocate privdata */ /* allocate privdata */
mmc = pcmcia_dev->priv = mmc = pcmcia_dev->priv =
@ -427,7 +427,7 @@ static int sdricoh_init_mmc(struct pci_dev *pci_dev,
if (!mmc) { if (!mmc) {
dev_err(dev, "mmc_alloc_host failed\n"); dev_err(dev, "mmc_alloc_host failed\n");
result = -ENOMEM; result = -ENOMEM;
goto err; goto unmap_io;
} }
host = mmc_priv(mmc); host = mmc_priv(mmc);
@ -451,8 +451,7 @@ static int sdricoh_init_mmc(struct pci_dev *pci_dev,
if (sdricoh_reset(host)) { if (sdricoh_reset(host)) {
dev_dbg(dev, "could not reset\n"); dev_dbg(dev, "could not reset\n");
result = -EIO; result = -EIO;
goto err; goto free_host;
} }
result = mmc_add_host(mmc); result = mmc_add_host(mmc);
@ -461,13 +460,10 @@ static int sdricoh_init_mmc(struct pci_dev *pci_dev,
dev_dbg(dev, "mmc host registered\n"); dev_dbg(dev, "mmc host registered\n");
return 0; return 0;
} }
free_host:
err: mmc_free_host(mmc);
if (iobase) unmap_io:
pci_iounmap(pci_dev, iobase); pci_iounmap(pci_dev, iobase);
if (mmc)
mmc_free_host(mmc);
return result; return result;
} }

View File

@ -1395,7 +1395,7 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
static void sh_mmcif_timeout_work(struct work_struct *work) static void sh_mmcif_timeout_work(struct work_struct *work)
{ {
struct delayed_work *d = container_of(work, struct delayed_work, work); struct delayed_work *d = to_delayed_work(work);
struct sh_mmcif_host *host = container_of(d, struct sh_mmcif_host, timeout_work); struct sh_mmcif_host *host = container_of(d, struct sh_mmcif_host, timeout_work);
struct mmc_request *mrq = host->mrq; struct mmc_request *mrq = host->mrq;
struct device *dev = sh_mmcif_host_to_dev(host); struct device *dev = sh_mmcif_host_to_dev(host);

View File

@ -1,6 +1,8 @@
/* /*
* SuperH Mobile SDHI * SuperH Mobile SDHI
* *
* Copyright (C) 2016 Sang Engineering, Wolfram Sang
* Copyright (C) 2015-16 Renesas Electronics Corporation
* Copyright (C) 2009 Magnus Damm * Copyright (C) 2009 Magnus Damm
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -43,6 +45,7 @@ struct sh_mobile_sdhi_of_data {
unsigned long capabilities2; unsigned long capabilities2;
enum dma_slave_buswidth dma_buswidth; enum dma_slave_buswidth dma_buswidth;
dma_addr_t dma_rx_offset; dma_addr_t dma_rx_offset;
unsigned bus_shift;
}; };
static const struct sh_mobile_sdhi_of_data sh_mobile_sdhi_of_cfg[] = { static const struct sh_mobile_sdhi_of_data sh_mobile_sdhi_of_cfg[] = {
@ -59,12 +62,19 @@ static const struct sh_mobile_sdhi_of_data of_rcar_gen1_compatible = {
static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = { static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = {
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
TMIO_MMC_CLK_ACTUAL, TMIO_MMC_CLK_ACTUAL | TMIO_MMC_FAST_CLK_CHG,
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
.dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES, .dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES,
.dma_rx_offset = 0x2000, .dma_rx_offset = 0x2000,
}; };
static const struct sh_mobile_sdhi_of_data of_rcar_gen3_compatible = {
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
TMIO_MMC_CLK_ACTUAL | TMIO_MMC_FAST_CLK_CHG,
.capabilities = MMC_CAP_SD_HIGHSPEED,
.bus_shift = 2,
};
static const struct of_device_id sh_mobile_sdhi_of_match[] = { static const struct of_device_id sh_mobile_sdhi_of_match[] = {
{ .compatible = "renesas,sdhi-shmobile" }, { .compatible = "renesas,sdhi-shmobile" },
{ .compatible = "renesas,sdhi-sh7372" }, { .compatible = "renesas,sdhi-sh7372" },
@ -78,6 +88,7 @@ static const struct of_device_id sh_mobile_sdhi_of_match[] = {
{ .compatible = "renesas,sdhi-r8a7792", .data = &of_rcar_gen2_compatible, }, { .compatible = "renesas,sdhi-r8a7792", .data = &of_rcar_gen2_compatible, },
{ .compatible = "renesas,sdhi-r8a7793", .data = &of_rcar_gen2_compatible, }, { .compatible = "renesas,sdhi-r8a7793", .data = &of_rcar_gen2_compatible, },
{ .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, }, { .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, },
{ .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match); MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match);
@ -103,6 +114,15 @@ static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width)
case 0xCB0D: case 0xCB0D:
val = (width == 32) ? 0x0000 : 0x0001; val = (width == 32) ? 0x0000 : 0x0001;
break; break;
case 0xCC10: /* Gen3, SD only */
case 0xCD10: /* Gen3, SD + MMC */
if (width == 64)
val = 0x0000;
else if (width == 32)
val = 0x0101;
else
val = 0x0001;
break;
default: default:
/* nothing to do */ /* nothing to do */
return; return;
@ -163,6 +183,7 @@ static int sh_mobile_sdhi_write16_hook(struct tmio_mmc_host *host, int addr)
case CTL_SD_MEM_CARD_OPT: case CTL_SD_MEM_CARD_OPT:
case CTL_TRANSACTION_CTL: case CTL_TRANSACTION_CTL:
case CTL_DMA_ENABLE: case CTL_DMA_ENABLE:
case EXT_ACC:
return sh_mobile_sdhi_wait_idle(host); return sh_mobile_sdhi_wait_idle(host);
} }
@ -213,10 +234,8 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
priv = devm_kzalloc(&pdev->dev, sizeof(struct sh_mobile_sdhi), GFP_KERNEL); priv = devm_kzalloc(&pdev->dev, sizeof(struct sh_mobile_sdhi), GFP_KERNEL);
if (priv == NULL) { if (!priv)
dev_err(&pdev->dev, "kzalloc failed\n");
return -ENOMEM; return -ENOMEM;
}
mmc_data = &priv->mmc_data; mmc_data = &priv->mmc_data;
dma_priv = &priv->dma_priv; dma_priv = &priv->dma_priv;
@ -234,16 +253,26 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
goto eprobe; goto eprobe;
} }
if (of_id && of_id->data) {
const struct sh_mobile_sdhi_of_data *of_data = of_id->data;
mmc_data->flags |= of_data->tmio_flags;
mmc_data->capabilities |= of_data->capabilities;
mmc_data->capabilities2 |= of_data->capabilities2;
mmc_data->dma_rx_offset = of_data->dma_rx_offset;
dma_priv->dma_buswidth = of_data->dma_buswidth;
host->bus_shift = of_data->bus_shift;
}
host->dma = dma_priv; host->dma = dma_priv;
host->write16_hook = sh_mobile_sdhi_write16_hook; host->write16_hook = sh_mobile_sdhi_write16_hook;
host->clk_enable = sh_mobile_sdhi_clk_enable; host->clk_enable = sh_mobile_sdhi_clk_enable;
host->clk_disable = sh_mobile_sdhi_clk_disable; host->clk_disable = sh_mobile_sdhi_clk_disable;
host->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk; host->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk;
/* SD control register space size is 0x100, 0x200 for bus_shift=1 */
if (resource_size(res) > 0x100) /* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */
if (!host->bus_shift && resource_size(res) > 0x100) /* old way to determine the shift */
host->bus_shift = 1; host->bus_shift = 1;
else
host->bus_shift = 0;
if (mmd) if (mmd)
*mmc_data = *mmd; *mmc_data = *mmd;
@ -275,15 +304,6 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
*/ */
mmc_data->flags |= TMIO_MMC_SDIO_STATUS_QUIRK; mmc_data->flags |= TMIO_MMC_SDIO_STATUS_QUIRK;
if (of_id && of_id->data) {
const struct sh_mobile_sdhi_of_data *of_data = of_id->data;
mmc_data->flags |= of_data->tmio_flags;
mmc_data->capabilities |= of_data->capabilities;
mmc_data->capabilities2 |= of_data->capabilities2;
mmc_data->dma_rx_offset = of_data->dma_rx_offset;
dma_priv->dma_buswidth = of_data->dma_buswidth;
}
ret = tmio_mmc_host_probe(host, mmc_data); ret = tmio_mmc_host_probe(host, mmc_data);
if (ret < 0) if (ret < 0)
goto efree; goto efree;

View File

@ -28,6 +28,7 @@
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/reset.h> #include <linux/reset.h>
#include <linux/regulator/consumer.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
@ -214,6 +215,7 @@
#define SDXC_CLK_25M 1 #define SDXC_CLK_25M 1
#define SDXC_CLK_50M 2 #define SDXC_CLK_50M 2
#define SDXC_CLK_50M_DDR 3 #define SDXC_CLK_50M_DDR 3
#define SDXC_CLK_50M_DDR_8BIT 4
struct sunxi_mmc_clk_delay { struct sunxi_mmc_clk_delay {
u32 output; u32 output;
@ -256,6 +258,9 @@ struct sunxi_mmc_host {
struct mmc_request *mrq; struct mmc_request *mrq;
struct mmc_request *manual_stop_mrq; struct mmc_request *manual_stop_mrq;
int ferror; int ferror;
/* vqmmc */
bool vqmmc_enabled;
}; };
static int sunxi_mmc_reset_host(struct sunxi_mmc_host *host) static int sunxi_mmc_reset_host(struct sunxi_mmc_host *host)
@ -284,16 +289,28 @@ static int sunxi_mmc_init_host(struct mmc_host *mmc)
if (sunxi_mmc_reset_host(host)) if (sunxi_mmc_reset_host(host))
return -EIO; return -EIO;
/*
* Burst 8 transfers, RX trigger level: 7, TX trigger level: 8
*
* TODO: sun9i has a larger FIFO and supports higher trigger values
*/
mmc_writel(host, REG_FTRGL, 0x20070008); mmc_writel(host, REG_FTRGL, 0x20070008);
/* Maximum timeout value */
mmc_writel(host, REG_TMOUT, 0xffffffff); mmc_writel(host, REG_TMOUT, 0xffffffff);
/* Unmask SDIO interrupt if needed */
mmc_writel(host, REG_IMASK, host->sdio_imask); mmc_writel(host, REG_IMASK, host->sdio_imask);
/* Clear all pending interrupts */
mmc_writel(host, REG_RINTR, 0xffffffff); mmc_writel(host, REG_RINTR, 0xffffffff);
/* Debug register? undocumented */
mmc_writel(host, REG_DBGC, 0xdeb); mmc_writel(host, REG_DBGC, 0xdeb);
/* Enable CEATA support */
mmc_writel(host, REG_FUNS, SDXC_CEATA_ON); mmc_writel(host, REG_FUNS, SDXC_CEATA_ON);
/* Set DMA descriptor list base address */
mmc_writel(host, REG_DLBA, host->sg_dma); mmc_writel(host, REG_DLBA, host->sg_dma);
rval = mmc_readl(host, REG_GCTRL); rval = mmc_readl(host, REG_GCTRL);
rval |= SDXC_INTERRUPT_ENABLE_BIT; rval |= SDXC_INTERRUPT_ENABLE_BIT;
/* Undocumented, but found in Allwinner code */
rval &= ~SDXC_ACCESS_DONE_DIRECT; rval &= ~SDXC_ACCESS_DONE_DIRECT;
mmc_writel(host, REG_GCTRL, rval); mmc_writel(host, REG_GCTRL, rval);
@ -640,11 +657,17 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
struct mmc_ios *ios) struct mmc_ios *ios)
{ {
u32 rate, oclk_dly, rval, sclk_dly; u32 rate, oclk_dly, rval, sclk_dly;
u32 clock = ios->clock;
int ret; int ret;
rate = clk_round_rate(host->clk_mmc, ios->clock); /* 8 bit DDR requires a higher module clock */
if (ios->timing == MMC_TIMING_MMC_DDR52 &&
ios->bus_width == MMC_BUS_WIDTH_8)
clock <<= 1;
rate = clk_round_rate(host->clk_mmc, clock);
dev_dbg(mmc_dev(host->mmc), "setting clk to %d, rounded %d\n", dev_dbg(mmc_dev(host->mmc), "setting clk to %d, rounded %d\n",
ios->clock, rate); clock, rate);
/* setting clock rate */ /* setting clock rate */
ret = clk_set_rate(host->clk_mmc, rate); ret = clk_set_rate(host->clk_mmc, rate);
@ -661,6 +684,12 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
/* clear internal divider */ /* clear internal divider */
rval = mmc_readl(host, REG_CLKCR); rval = mmc_readl(host, REG_CLKCR);
rval &= ~0xff; rval &= ~0xff;
/* set internal divider for 8 bit eMMC DDR, so card clock is right */
if (ios->timing == MMC_TIMING_MMC_DDR52 &&
ios->bus_width == MMC_BUS_WIDTH_8) {
rval |= 1;
rate >>= 1;
}
mmc_writel(host, REG_CLKCR, rval); mmc_writel(host, REG_CLKCR, rval);
/* determine delays */ /* determine delays */
@ -670,13 +699,17 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
} else if (rate <= 25000000) { } else if (rate <= 25000000) {
oclk_dly = host->clk_delays[SDXC_CLK_25M].output; oclk_dly = host->clk_delays[SDXC_CLK_25M].output;
sclk_dly = host->clk_delays[SDXC_CLK_25M].sample; sclk_dly = host->clk_delays[SDXC_CLK_25M].sample;
} else if (rate <= 50000000) { } else if (rate <= 52000000) {
if (ios->timing == MMC_TIMING_UHS_DDR50) { if (ios->timing != MMC_TIMING_UHS_DDR50 &&
oclk_dly = host->clk_delays[SDXC_CLK_50M_DDR].output; ios->timing != MMC_TIMING_MMC_DDR52) {
sclk_dly = host->clk_delays[SDXC_CLK_50M_DDR].sample;
} else {
oclk_dly = host->clk_delays[SDXC_CLK_50M].output; oclk_dly = host->clk_delays[SDXC_CLK_50M].output;
sclk_dly = host->clk_delays[SDXC_CLK_50M].sample; sclk_dly = host->clk_delays[SDXC_CLK_50M].sample;
} else if (ios->bus_width == MMC_BUS_WIDTH_8) {
oclk_dly = host->clk_delays[SDXC_CLK_50M_DDR_8BIT].output;
sclk_dly = host->clk_delays[SDXC_CLK_50M_DDR_8BIT].sample;
} else {
oclk_dly = host->clk_delays[SDXC_CLK_50M_DDR].output;
sclk_dly = host->clk_delays[SDXC_CLK_50M_DDR].sample;
} }
} else { } else {
return -EINVAL; return -EINVAL;
@ -699,7 +732,20 @@ static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
break; break;
case MMC_POWER_UP: case MMC_POWER_UP:
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); host->ferror = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
ios->vdd);
if (host->ferror)
return;
if (!IS_ERR(mmc->supply.vqmmc)) {
host->ferror = regulator_enable(mmc->supply.vqmmc);
if (host->ferror) {
dev_err(mmc_dev(mmc),
"failed to enable vqmmc\n");
return;
}
host->vqmmc_enabled = true;
}
host->ferror = sunxi_mmc_init_host(mmc); host->ferror = sunxi_mmc_init_host(mmc);
if (host->ferror) if (host->ferror)
@ -712,6 +758,9 @@ static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
dev_dbg(mmc_dev(mmc), "power off!\n"); dev_dbg(mmc_dev(mmc), "power off!\n");
sunxi_mmc_reset_host(host); sunxi_mmc_reset_host(host);
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled)
regulator_disable(mmc->supply.vqmmc);
host->vqmmc_enabled = false;
break; break;
} }
@ -730,7 +779,8 @@ static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
/* set ddr mode */ /* set ddr mode */
rval = mmc_readl(host, REG_GCTRL); rval = mmc_readl(host, REG_GCTRL);
if (ios->timing == MMC_TIMING_UHS_DDR50) if (ios->timing == MMC_TIMING_UHS_DDR50 ||
ios->timing == MMC_TIMING_MMC_DDR52)
rval |= SDXC_DDR_MODE; rval |= SDXC_DDR_MODE;
else else
rval &= ~SDXC_DDR_MODE; rval &= ~SDXC_DDR_MODE;
@ -743,6 +793,19 @@ static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
} }
} }
static int sunxi_mmc_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios)
{
/* vqmmc regulator is available */
if (!IS_ERR(mmc->supply.vqmmc))
return mmc_regulator_set_vqmmc(mmc, ios);
/* no vqmmc regulator, assume fixed regulator at 3/3.3V */
if (mmc->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330)
return 0;
return -EINVAL;
}
static void sunxi_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) static void sunxi_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
{ {
struct sunxi_mmc_host *host = mmc_priv(mmc); struct sunxi_mmc_host *host = mmc_priv(mmc);
@ -815,11 +878,6 @@ static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC) { if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC) {
cmd_val |= SDXC_DATA_EXPIRE | SDXC_WAIT_PRE_OVER; cmd_val |= SDXC_DATA_EXPIRE | SDXC_WAIT_PRE_OVER;
if (cmd->data->flags & MMC_DATA_STREAM) {
imask |= SDXC_AUTO_COMMAND_DONE;
cmd_val |= SDXC_SEQUENCE_MODE |
SDXC_SEND_AUTO_STOP;
}
if (cmd->data->stop) { if (cmd->data->stop) {
imask |= SDXC_AUTO_COMMAND_DONE; imask |= SDXC_AUTO_COMMAND_DONE;
@ -894,6 +952,7 @@ static struct mmc_host_ops sunxi_mmc_ops = {
.get_ro = mmc_gpio_get_ro, .get_ro = mmc_gpio_get_ro,
.get_cd = mmc_gpio_get_cd, .get_cd = mmc_gpio_get_cd,
.enable_sdio_irq = sunxi_mmc_enable_sdio_irq, .enable_sdio_irq = sunxi_mmc_enable_sdio_irq,
.start_signal_voltage_switch = sunxi_mmc_volt_switch,
.hw_reset = sunxi_mmc_hw_reset, .hw_reset = sunxi_mmc_hw_reset,
.card_busy = sunxi_mmc_card_busy, .card_busy = sunxi_mmc_card_busy,
}; };
@ -903,6 +962,8 @@ static const struct sunxi_mmc_clk_delay sunxi_mmc_clk_delays[] = {
[SDXC_CLK_25M] = { .output = 180, .sample = 75 }, [SDXC_CLK_25M] = { .output = 180, .sample = 75 },
[SDXC_CLK_50M] = { .output = 90, .sample = 120 }, [SDXC_CLK_50M] = { .output = 90, .sample = 120 },
[SDXC_CLK_50M_DDR] = { .output = 60, .sample = 120 }, [SDXC_CLK_50M_DDR] = { .output = 60, .sample = 120 },
/* Value from A83T "new timing mode". Works but might not be right. */
[SDXC_CLK_50M_DDR_8BIT] = { .output = 90, .sample = 180 },
}; };
static const struct sunxi_mmc_clk_delay sun9i_mmc_clk_delays[] = { static const struct sunxi_mmc_clk_delay sun9i_mmc_clk_delays[] = {
@ -910,6 +971,7 @@ static const struct sunxi_mmc_clk_delay sun9i_mmc_clk_delays[] = {
[SDXC_CLK_25M] = { .output = 180, .sample = 75 }, [SDXC_CLK_25M] = { .output = 180, .sample = 75 },
[SDXC_CLK_50M] = { .output = 150, .sample = 120 }, [SDXC_CLK_50M] = { .output = 150, .sample = 120 },
[SDXC_CLK_50M_DDR] = { .output = 90, .sample = 120 }, [SDXC_CLK_50M_DDR] = { .output = 90, .sample = 120 },
[SDXC_CLK_50M_DDR_8BIT] = { .output = 90, .sample = 120 },
}; };
static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host, static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
@ -1060,10 +1122,11 @@ static int sunxi_mmc_probe(struct platform_device *pdev)
mmc->max_segs = PAGE_SIZE / sizeof(struct sunxi_idma_des); mmc->max_segs = PAGE_SIZE / sizeof(struct sunxi_idma_des);
mmc->max_seg_size = (1 << host->idma_des_size_bits); mmc->max_seg_size = (1 << host->idma_des_size_bits);
mmc->max_req_size = mmc->max_seg_size * mmc->max_segs; mmc->max_req_size = mmc->max_seg_size * mmc->max_segs;
/* 400kHz ~ 50MHz */ /* 400kHz ~ 52MHz */
mmc->f_min = 400000; mmc->f_min = 400000;
mmc->f_max = 50000000; mmc->f_max = 52000000;
mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
MMC_CAP_1_8V_DDR |
MMC_CAP_ERASE | MMC_CAP_SDIO_IRQ; MMC_CAP_ERASE | MMC_CAP_SDIO_IRQ;
ret = mmc_of_parse(mmc); ret = mmc_of_parse(mmc);

View File

@ -94,10 +94,7 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
desc = NULL; desc = NULL;
ret = cookie; ret = cookie;
} }
dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n",
__func__, host->sg_len, ret, cookie, host->mrq);
} }
pio: pio:
if (!desc) { if (!desc) {
/* DMA failed, fall back to PIO */ /* DMA failed, fall back to PIO */
@ -115,9 +112,6 @@ pio:
dev_warn(&host->pdev->dev, dev_warn(&host->pdev->dev,
"DMA failed: %d, falling back to PIO\n", ret); "DMA failed: %d, falling back to PIO\n", ret);
} }
dev_dbg(&host->pdev->dev, "%s(): desc %p, sg[%d]\n", __func__,
desc, host->sg_len);
} }
static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
@ -174,10 +168,7 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
desc = NULL; desc = NULL;
ret = cookie; ret = cookie;
} }
dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n",
__func__, host->sg_len, ret, cookie, host->mrq);
} }
pio: pio:
if (!desc) { if (!desc) {
/* DMA failed, fall back to PIO */ /* DMA failed, fall back to PIO */
@ -195,8 +186,6 @@ pio:
dev_warn(&host->pdev->dev, dev_warn(&host->pdev->dev,
"DMA failed: %d, falling back to PIO\n", ret); "DMA failed: %d, falling back to PIO\n", ret);
} }
dev_dbg(&host->pdev->dev, "%s(): desc %p\n", __func__, desc);
} }
void tmio_mmc_start_dma(struct tmio_mmc_host *host, void tmio_mmc_start_dma(struct tmio_mmc_host *host,

View File

@ -1,6 +1,8 @@
/* /*
* linux/drivers/mmc/host/tmio_mmc_pio.c * linux/drivers/mmc/host/tmio_mmc_pio.c
* *
* Copyright (C) 2016 Sang Engineering, Wolfram Sang
* Copyright (C) 2015-16 Renesas Electronics Corporation
* Copyright (C) 2011 Guennadi Liakhovetski * Copyright (C) 2011 Guennadi Liakhovetski
* Copyright (C) 2007 Ian Molton * Copyright (C) 2007 Ian Molton
* Copyright (C) 2004 Ian Molton * Copyright (C) 2004 Ian Molton
@ -159,42 +161,44 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host,
if (new_clock) { if (new_clock) {
for (clock = host->mmc->f_min, clk = 0x80000080; for (clock = host->mmc->f_min, clk = 0x80000080;
new_clock >= (clock<<1); clk >>= 1) new_clock >= (clock << 1);
clk >>= 1)
clock <<= 1; clock <<= 1;
/* 1/1 clock is option */ /* 1/1 clock is option */
if ((host->pdata->flags & TMIO_MMC_CLK_ACTUAL) && if ((host->pdata->flags & TMIO_MMC_CLK_ACTUAL) &&
((clk >> 22) & 0x1)) ((clk >> 22) & 0x1))
clk |= 0xff; clk |= 0xff;
} }
if (host->set_clk_div) if (host->set_clk_div)
host->set_clk_div(host->pdev, (clk>>22) & 1); host->set_clk_div(host->pdev, (clk >> 22) & 1);
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & 0x1ff); sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
msleep(10); sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & CLK_CTL_DIV_MASK);
if (!(host->pdata->flags & TMIO_MMC_FAST_CLK_CHG))
msleep(10);
} }
static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
{ {
/* implicit BUG_ON(!res) */
if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) { if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) {
sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000); sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000);
msleep(10); msleep(10);
} }
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 & sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
msleep(10); msleep(host->pdata->flags & TMIO_MMC_FAST_CLK_CHG ? 5 : 10);
} }
static void tmio_mmc_clk_start(struct tmio_mmc_host *host) static void tmio_mmc_clk_start(struct tmio_mmc_host *host)
{ {
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
msleep(10); msleep(host->pdata->flags & TMIO_MMC_FAST_CLK_CHG ? 1 : 10);
/* implicit BUG_ON(!res) */
if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) { if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) {
sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100); sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100);
msleep(10); msleep(10);
@ -205,7 +209,6 @@ static void tmio_mmc_reset(struct tmio_mmc_host *host)
{ {
/* FIXME - should we set stop clock reg here */ /* FIXME - should we set stop clock reg here */
sd_ctrl_write16(host, CTL_RESET_SD, 0x0000); sd_ctrl_write16(host, CTL_RESET_SD, 0x0000);
/* implicit BUG_ON(!res) */
if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG)
sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000); sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000);
msleep(10); msleep(10);

View File

@ -1630,7 +1630,7 @@ static irqreturn_t usdhi6_cd(int irq, void *dev_id)
*/ */
static void usdhi6_timeout_work(struct work_struct *work) static void usdhi6_timeout_work(struct work_struct *work)
{ {
struct delayed_work *d = container_of(work, struct delayed_work, work); struct delayed_work *d = to_delayed_work(work);
struct usdhi6_host *host = container_of(d, struct usdhi6_host, timeout_work); struct usdhi6_host *host = container_of(d, struct usdhi6_host, timeout_work);
struct mmc_request *mrq = host->mrq; struct mmc_request *mrq = host->mrq;
struct mmc_data *data = mrq ? mrq->data : NULL; struct mmc_data *data = mrq ? mrq->data : NULL;

View File

@ -65,6 +65,10 @@
* Some controllers can support SDIO IRQ signalling. * Some controllers can support SDIO IRQ signalling.
*/ */
#define TMIO_MMC_SDIO_IRQ (1 << 2) #define TMIO_MMC_SDIO_IRQ (1 << 2)
/* Some controllers don't need to wait 10ms for clock changes */
#define TMIO_MMC_FAST_CLK_CHG (1 << 3)
/* /*
* Some controllers require waiting for the SD bus to become * Some controllers require waiting for the SD bus to become
* idle before writing to some registers. * idle before writing to some registers.

View File

@ -113,7 +113,6 @@ struct mmc_data {
#define MMC_DATA_WRITE (1 << 8) #define MMC_DATA_WRITE (1 << 8)
#define MMC_DATA_READ (1 << 9) #define MMC_DATA_READ (1 << 9)
#define MMC_DATA_STREAM (1 << 10)
unsigned int bytes_xfered; unsigned int bytes_xfered;

View File

@ -235,21 +235,11 @@ struct dw_mci_dma_ops {
}; };
/* IP Quirks/flags. */ /* IP Quirks/flags. */
/* Unreliable card detection */
#define DW_MCI_QUIRK_BROKEN_CARD_DETECTION BIT(0)
/* Timer for broken data transfer over scheme */ /* Timer for broken data transfer over scheme */
#define DW_MCI_QUIRK_BROKEN_DTO BIT(1) #define DW_MCI_QUIRK_BROKEN_DTO BIT(0)
struct dma_pdata; struct dma_pdata;
struct block_settings {
unsigned short max_segs; /* see blk_queue_max_segments */
unsigned int max_blk_size; /* maximum size of one mmc block */
unsigned int max_blk_count; /* maximum number of blocks in one req*/
unsigned int max_req_size; /* maximum number of bytes in one req*/
unsigned int max_seg_size; /* see blk_queue_max_segment_size */
};
/* Board platform data */ /* Board platform data */
struct dw_mci_board { struct dw_mci_board {
u32 num_slots; u32 num_slots;

View File

@ -1,6 +1,8 @@
/* /*
* include/linux/mmc/tmio.h * include/linux/mmc/tmio.h
* *
* Copyright (C) 2016 Sang Engineering, Wolfram Sang
* Copyright (C) 2015-16 Renesas Electronics Corporation
* Copyright (C) 2007 Ian Molton * Copyright (C) 2007 Ian Molton
* Copyright (C) 2004 Ian Molton * Copyright (C) 2004 Ian Molton
* *
@ -61,6 +63,9 @@
#define TMIO_STAT_CMD_BUSY 0x40000000 #define TMIO_STAT_CMD_BUSY 0x40000000
#define TMIO_STAT_ILL_ACCESS 0x80000000 #define TMIO_STAT_ILL_ACCESS 0x80000000
#define CLK_CTL_DIV_MASK 0xff
#define CLK_CTL_SCLKEN BIT(8)
#define TMIO_BBS 512 /* Boot block size */ #define TMIO_BBS 512 /* Boot block size */
#endif /* LINUX_MMC_TMIO_H */ #endif /* LINUX_MMC_TMIO_H */