MMC core:

- Continue to refactor the mmc block code to prepare for blkmq
  - Move mmc block debugfs into block module
  - Next step for eMMC CMDQ by adding a new mmc host interface for it
  - Move Kconfig option MMC_DEBUG from core to host
  - Some additional minor improvements
 
 MMC host:
  - Declare structs as const when applicable
  - Explicitly request exclusive reset control when applicable
  - Improve some error paths and other various cleanups
  - sdhci: Preparations to support SDHCI OMAP
  - sdhci: Improve some PM related code
  - sdhci: Re-factoring and modernizations
  - sdhci-xenon: Add runtime PM and system sleep support
  - sdhci-xenon: Add support for eMMC HS400 Enhanced Strobe
  - sdhci-cadence: Add system sleep support
  - sdhci-of-at91: Improve system sleep support
  - dw_mmc: Add support for Hisilicon hi3660
  - sunxi: Add support for A83T eMMC
  - sunxi: Add support for DDR52 mode
  - meson-gx: Add support for UHS-I SD-cards
  - meson-gx: Cleanups and improvements
  - tmio: Fix CMD12 (STOP) handling
  - tmio: Cleanups and improvements
  - renesas_sdhi: Add r8a7743/5 support
  - renesas-sdhi: Add support for R-Car Gen3 SDHI DMAC
  - renesas_sdhi: Cleanups and improvements
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJZr7CEAAoJEP4mhCVzWIwp5WQQAK9l2Hg1k4tFzxQ5EmKB/9Sm
 r3eS2GrosqrsCffR3vSSKnmva/lOrQuBzhqzx1MvWAByMUc5w8Yc8OowrKGhCWm9
 pAzi/3Tnjf7A9nAq+0NeGhkwybckam9ZpGhMyC1E4bp63g6PCoHjTcqOMVnjYxHz
 cUNNQUz7oCjW6tjtpvdJQWZuIGiScNuyxrTYKi8SUpQZ0LQo8nU9DujKcwsKsZed
 gYEIimqOqZnGz1rWs/EP2Y5TSoPVxvnb6nc90gt8kh0nfXYumxKjEmHZ0PB7K97b
 pioCN/THtkDgdYn8j3gnDXZYYa6JA4fKKOw+S6VZraLoVLeDtLo5zK353Rr3BscI
 SddxLePp5WclRal+WulLLJs1FeY5PN3ji+mxC3FAG6cvCqIyosyU8HKG79Lhwwl6
 7qlaDf27BhK71Sf17jzxtc5OwVTkSsY+9iKzVZAw5tIHSLR+nwhjM2vlAVU+oG2r
 KAsuVO1CVAqYbeIBJ85R6bPzgRGxQ0Kmkqwxe1QDVhgXl3eC5Ot5N/bOifv7HzV+
 m+6W1Wdw6/tUKD5g5c6s2WMijXgTdEnfj7dYXmHHN4q1abAKj0cOVjXtmVb90DHM
 5tvfxNurQZCCLo2A88/BYXRd299vBzOy9HAWvMvt5effQfxgFfpC1gc9NkfUTfkA
 FTOQ96vOpOmAH5uA0Xvm
 =850Z
 -----END PGP SIGNATURE-----

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

Pull MMC updates from Ulf Hansson:
 "MMC core:
   - Continue to refactor the mmc block code to prepare for blkmq
   - Move mmc block debugfs into block module
   - Next step for eMMC CMDQ by adding a new mmc host interface for it
   - Move Kconfig option MMC_DEBUG from core to host
   - Some additional minor improvements

  MMC host:
   - Declare structs as const when applicable
   - Explicitly request exclusive reset control when applicable
   - Improve some error paths and other various cleanups
   - sdhci: Preparations to support SDHCI OMAP
   - sdhci: Improve some PM related code
   - sdhci: Re-factoring and modernizations
   - sdhci-xenon: Add runtime PM and system sleep support
   - sdhci-xenon: Add support for eMMC HS400 Enhanced Strobe
   - sdhci-cadence: Add system sleep support
   - sdhci-of-at91: Improve system sleep support
   - dw_mmc: Add support for Hisilicon hi3660
   - sunxi: Add support for A83T eMMC
   - sunxi: Add support for DDR52 mode
   - meson-gx: Add support for UHS-I SD-cards
   - meson-gx: Cleanups and improvements
   - tmio: Fix CMD12 (STOP) handling
   - tmio: Cleanups and improvements
   - renesas_sdhi: Add r8a7743/5 support
   - renesas-sdhi: Add support for R-Car Gen3 SDHI DMAC
   - renesas_sdhi: Cleanups and improvements"

* tag 'mmc-v4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (145 commits)
  mmc: renesas_sdhi: Add r8a7743/5 support
  mmc: meson-gx: fix __ffsdi2 undefined on arm32
  mmc: sdhci-xenon: add runtime pm support and reimplement standby
  mmc: core: Move mmc_start_areq() declaration
  mmc: mmci: stop building qcom dml as module
  mmc: sunxi: Reset the device at probe time
  clk: sunxi-ng: Provide a default reset hook
  mmc: meson-gx: rework tuning function
  mmc: meson-gx: change default tx phase
  mmc: meson-gx: implement voltage switch callback
  mmc: meson-gx: use CCF to handle the clock phases
  mmc: meson-gx: implement card_busy callback
  mmc: meson-gx: simplify interrupt handler
  mmc: meson-gx: work around clk-stop issue
  mmc: meson-gx: fix dual data rate mode frequencies
  mmc: meson-gx: rework clock init function
  mmc: meson-gx: rework clk_set function
  mmc: meson-gx: rework set_ios function
  mmc: meson-gx: cfg init overwrite values
  mmc: meson-gx: initialize sane clk default before clock register
  ...
This commit is contained in:
Linus Torvalds 2017-09-07 12:24:50 -07:00
commit 15d8ffc964
91 changed files with 2565 additions and 1003 deletions

View File

@ -11,6 +11,8 @@ Required properties:
- "renesas,mmcif-r7s72100" for the MMCIF found in r7s72100 SoCs
- "renesas,mmcif-r8a73a4" for the MMCIF found in r8a73a4 SoCs
- "renesas,mmcif-r8a7740" for the MMCIF found in r8a7740 SoCs
- "renesas,mmcif-r8a7743" for the MMCIF found in r8a7743 SoCs
- "renesas,mmcif-r8a7745" for the MMCIF found in r8a7745 SoCs
- "renesas,mmcif-r8a7778" for the MMCIF found in r8a7778 SoCs
- "renesas,mmcif-r8a7790" for the MMCIF found in r8a7790 SoCs
- "renesas,mmcif-r8a7791" for the MMCIF found in r8a7791 SoCs
@ -21,7 +23,7 @@ Required properties:
- interrupts: Some SoCs have only 1 shared interrupt, while others have either
2 or 3 individual interrupts (error, int, card detect). Below is the number
of interrupts for each SoC:
1: r8a73a4, r8a7778, r8a7790, r8a7791, r8a7793, r8a7794
1: r8a73a4, r8a7743, r8a7745, r8a7778, r8a7790, r8a7791, r8a7793, r8a7794
2: r8a7740, sh73a0
3: r7s72100

View File

@ -15,6 +15,7 @@ Required Properties:
- "rockchip,rk3288-dw-mshc": for Rockchip RK3288
- "rockchip,rv1108-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RV1108
- "rockchip,rk3036-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK3036
- "rockchip,rk3228-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK322x
- "rockchip,rk3328-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK3328
- "rockchip,rk3368-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK3368
- "rockchip,rk3399-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK3399

View File

@ -12,6 +12,7 @@ Required properties:
* "allwinner,sun4i-a10-mmc"
* "allwinner,sun5i-a13-mmc"
* "allwinner,sun7i-a20-mmc"
* "allwinner,sun8i-a83t-emmc"
* "allwinner,sun9i-a80-mmc"
* "allwinner,sun50i-a64-emmc"
* "allwinner,sun50i-a64-mmc"

View File

@ -15,6 +15,8 @@ Required properties:
"renesas,sdhi-r7s72100" - SDHI IP on R7S72100 SoC
"renesas,sdhi-r8a73a4" - SDHI IP on R8A73A4 SoC
"renesas,sdhi-r8a7740" - SDHI IP on R8A7740 SoC
"renesas,sdhi-r8a7743" - SDHI IP on R8A7743 SoC
"renesas,sdhi-r8a7745" - SDHI IP on R8A7745 SoC
"renesas,sdhi-r8a7778" - SDHI IP on R8A7778 SoC
"renesas,sdhi-r8a7779" - SDHI IP on R8A7779 SoC
"renesas,sdhi-r8a7790" - SDHI IP on R8A7790 SoC
@ -33,9 +35,7 @@ Required properties:
If 2 clocks are specified by the hardware, you must name them as
"core" and "cd". If the controller only has 1 clock, naming is not
required.
Below is the number clocks for each supported SoC:
1: SH73A0, R8A73A4, R8A7740, R8A7778, R8A7779, R8A7790
R8A7791, R8A7792, R8A7793, R8A7794, R8A7795, R8A7796
Devices which have more than 1 clock are listed below:
2: R7S72100
Optional properties:

View File

@ -101,7 +101,6 @@
mmc@0x15000 {
compatible = "altr,socfpga-dw-mshc";
reg = < 0x15000 0x400 >;
num-slots = < 1 >;
fifo-depth = < 16 >;
card-detect-delay = < 200 >;
clocks = <&apbclk>, <&mmcclk>;

View File

@ -104,7 +104,6 @@
mmc@0x15000 {
compatible = "snps,dw-mshc";
reg = <0x15000 0x400>;
num-slots = <1>;
fifo-depth = <1024>;
card-detect-delay = <200>;
clocks = <&apbclk>, <&mmcclk>;

View File

@ -1,5 +1,6 @@
# Common objects
lib-$(CONFIG_SUNXI_CCU) += ccu_common.o
lib-$(CONFIG_SUNXI_CCU) += ccu_mmc_timing.o
lib-$(CONFIG_SUNXI_CCU) += ccu_reset.o
# Base clock types

View File

@ -418,14 +418,8 @@ static SUNXI_CCU_PHASE(mmc1_sample_clk, "mmc1-sample", "mmc1",
static SUNXI_CCU_PHASE(mmc1_output_clk, "mmc1-output", "mmc1",
0x08c, 8, 3, 0);
/* TODO Support MMC2 clock's new timing mode. */
static SUNXI_CCU_MP_WITH_MUX_GATE(mmc2_clk, "mmc2", mod0_default_parents,
0x090,
0, 4, /* M */
16, 2, /* P */
24, 2, /* mux */
BIT(31), /* gate */
0);
static SUNXI_CCU_MP_MMC_WITH_MUX_GATE(mmc2_clk, "mmc2", mod0_default_parents,
0x090, 0);
static SUNXI_CCU_PHASE(mmc2_sample_clk, "mmc2-sample", "mmc2",
0x090, 20, 3, 0);

View File

@ -23,6 +23,10 @@
#define CCU_FEATURE_FIXED_POSTDIV BIT(3)
#define CCU_FEATURE_ALL_PREDIV BIT(4)
#define CCU_FEATURE_LOCK_REG BIT(5)
#define CCU_FEATURE_MMC_TIMING_SWITCH BIT(6)
/* MMC timing mode switch bit */
#define CCU_MMC_NEW_TIMING_MODE BIT(30)
struct device_node;

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2017 Chen-Yu Tsai. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/clk-provider.h>
#include <linux/clk/sunxi-ng.h>
#include "ccu_common.h"
/**
* sunxi_ccu_set_mmc_timing_mode: Configure the MMC clock timing mode
* @clk: clock to be configured
* @new_mode: true for new timing mode introduced in A83T and later
*
* Returns 0 on success, -ENOTSUPP if the clock does not support
* switching modes.
*/
int sunxi_ccu_set_mmc_timing_mode(struct clk *clk, bool new_mode)
{
struct clk_hw *hw = __clk_get_hw(clk);
struct ccu_common *cm = hw_to_ccu_common(hw);
unsigned long flags;
u32 val;
if (!(cm->features & CCU_FEATURE_MMC_TIMING_SWITCH))
return -ENOTSUPP;
spin_lock_irqsave(cm->lock, flags);
val = readl(cm->base + cm->reg);
if (new_mode)
val |= CCU_MMC_NEW_TIMING_MODE;
else
val &= ~CCU_MMC_NEW_TIMING_MODE;
writel(val, cm->base + cm->reg);
spin_unlock_irqrestore(cm->lock, flags);
return 0;
}
EXPORT_SYMBOL_GPL(sunxi_ccu_set_mmc_timing_mode);
/**
* sunxi_ccu_set_mmc_timing_mode: Get the current MMC clock timing mode
* @clk: clock to query
*
* Returns 0 if the clock is in old timing mode, > 0 if it is in
* new timing mode, and -ENOTSUPP if the clock does not support
* this function.
*/
int sunxi_ccu_get_mmc_timing_mode(struct clk *clk)
{
struct clk_hw *hw = __clk_get_hw(clk);
struct ccu_common *cm = hw_to_ccu_common(hw);
if (!(cm->features & CCU_FEATURE_MMC_TIMING_SWITCH))
return -ENOTSUPP;
return !!(readl(cm->base + cm->reg) & CCU_MMC_NEW_TIMING_MODE);
}
EXPORT_SYMBOL_GPL(sunxi_ccu_get_mmc_timing_mode);

View File

@ -172,3 +172,83 @@ const struct clk_ops ccu_mp_ops = {
.recalc_rate = ccu_mp_recalc_rate,
.set_rate = ccu_mp_set_rate,
};
/*
* Support for MMC timing mode switching
*
* The MMC clocks on some SoCs support switching between old and
* new timing modes. A platform specific API is provided to query
* and set the timing mode on supported SoCs.
*
* In addition, a special class of ccu_mp_ops is provided, which
* takes in to account the timing mode switch. When the new timing
* mode is active, the clock output rate is halved. This new class
* is a wrapper around the generic ccu_mp_ops. When clock rates
* are passed through to ccu_mp_ops callbacks, they are doubled
* if the new timing mode bit is set, to account for the post
* divider. Conversely, when clock rates are passed back, they
* are halved if the mode bit is set.
*/
static unsigned long ccu_mp_mmc_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
unsigned long rate = ccu_mp_recalc_rate(hw, parent_rate);
struct ccu_common *cm = hw_to_ccu_common(hw);
u32 val = readl(cm->base + cm->reg);
if (val & CCU_MMC_NEW_TIMING_MODE)
return rate / 2;
return rate;
}
static int ccu_mp_mmc_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct ccu_common *cm = hw_to_ccu_common(hw);
u32 val = readl(cm->base + cm->reg);
int ret;
/* adjust the requested clock rate */
if (val & CCU_MMC_NEW_TIMING_MODE) {
req->rate *= 2;
req->min_rate *= 2;
req->max_rate *= 2;
}
ret = ccu_mp_determine_rate(hw, req);
/* re-adjust the requested clock rate back */
if (val & CCU_MMC_NEW_TIMING_MODE) {
req->rate /= 2;
req->min_rate /= 2;
req->max_rate /= 2;
}
return ret;
}
static int ccu_mp_mmc_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct ccu_common *cm = hw_to_ccu_common(hw);
u32 val = readl(cm->base + cm->reg);
if (val & CCU_MMC_NEW_TIMING_MODE)
rate *= 2;
return ccu_mp_set_rate(hw, rate, parent_rate);
}
const struct clk_ops ccu_mp_mmc_ops = {
.disable = ccu_mp_disable,
.enable = ccu_mp_enable,
.is_enabled = ccu_mp_is_enabled,
.get_parent = ccu_mp_get_parent,
.set_parent = ccu_mp_set_parent,
.determine_rate = ccu_mp_mmc_determine_rate,
.recalc_rate = ccu_mp_mmc_recalc_rate,
.set_rate = ccu_mp_mmc_set_rate,
};

View File

@ -14,6 +14,7 @@
#ifndef _CCU_MP_H_
#define _CCU_MP_H_
#include <linux/bitops.h>
#include <linux/clk-provider.h>
#include "ccu_common.h"
@ -74,4 +75,33 @@ static inline struct ccu_mp *hw_to_ccu_mp(struct clk_hw *hw)
extern const struct clk_ops ccu_mp_ops;
/*
* Special class of M-P clock that supports MMC timing modes
*
* Since the MMC clock registers all follow the same layout, we can
* simplify the macro for this particular case. In addition, as
* switching modes also affects the output clock rate, we need to
* have CLK_GET_RATE_NOCACHE for all these types of clocks.
*/
#define SUNXI_CCU_MP_MMC_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
_flags) \
struct ccu_mp _struct = { \
.enable = BIT(31), \
.m = _SUNXI_CCU_DIV(0, 4), \
.p = _SUNXI_CCU_DIV(16, 2), \
.mux = _SUNXI_CCU_MUX(24, 2), \
.common = { \
.reg = _reg, \
.features = CCU_FEATURE_MMC_TIMING_SWITCH, \
.hw.init = CLK_HW_INIT_PARENTS(_name, \
_parents, \
&ccu_mp_mmc_ops, \
CLK_GET_RATE_NOCACHE | \
_flags), \
} \
}
extern const struct clk_ops ccu_mp_mmc_ops;
#endif /* _CCU_MP_H_ */

View File

@ -8,6 +8,7 @@
* the License, or (at your option) any later version.
*/
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/reset-controller.h>
@ -49,7 +50,18 @@ static int ccu_reset_deassert(struct reset_controller_dev *rcdev,
return 0;
}
static int ccu_reset_reset(struct reset_controller_dev *rcdev,
unsigned long id)
{
ccu_reset_assert(rcdev, id);
udelay(10);
ccu_reset_deassert(rcdev, id);
return 0;
}
const struct reset_control_ops ccu_reset_ops = {
.assert = ccu_reset_assert,
.deassert = ccu_reset_deassert,
.reset = ccu_reset_reset,
};

View File

@ -12,13 +12,6 @@ menuconfig MMC
If you want MMC/SD/SDIO support, you should say Y here and
also to your specific host controller driver.
config MMC_DEBUG
bool "MMC debugging"
depends on MMC != n
help
This is an option for use by developers; most people should
say N here. This enables MMC core and driver debugging.
if MMC
source "drivers/mmc/core/Kconfig"

View File

@ -2,7 +2,5 @@
# Makefile for the kernel mmc device drivers.
#
subdir-ccflags-$(CONFIG_MMC_DEBUG) := -DDEBUG
obj-$(CONFIG_MMC) += core/
obj-$(subst m,y,$(CONFIG_MMC)) += host/

View File

@ -36,6 +36,7 @@
#include <linux/compat.h>
#include <linux/pm_runtime.h>
#include <linux/idr.h>
#include <linux/debugfs.h>
#include <linux/mmc/ioctl.h>
#include <linux/mmc/card.h>
@ -126,7 +127,7 @@ module_param(perdev_minors, int, 0444);
MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
static inline int mmc_blk_part_switch(struct mmc_card *card,
struct mmc_blk_data *md);
unsigned int part_type);
static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
{
@ -188,7 +189,6 @@ static ssize_t power_ro_lock_store(struct device *dev,
{
int ret;
struct mmc_blk_data *md, *part_md;
struct mmc_card *card;
struct mmc_queue *mq;
struct request *req;
unsigned long set;
@ -201,7 +201,6 @@ static ssize_t power_ro_lock_store(struct device *dev,
md = mmc_blk_get(dev_to_disk(dev));
mq = &md->queue;
card = md->queue.card;
/* Dispatch locking to the block layer */
req = blk_get_request(mq->queue, REQ_OP_DRV_OUT, __GFP_RECLAIM);
@ -489,7 +488,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
mrq.cmd = &cmd;
err = mmc_blk_part_switch(card, md);
err = mmc_blk_part_switch(card, md->part_type);
if (err)
return err;
@ -554,35 +553,20 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
return err;
}
static int mmc_blk_ioctl_cmd(struct block_device *bdev,
static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md,
struct mmc_ioc_cmd __user *ic_ptr)
{
struct mmc_blk_ioc_data *idata;
struct mmc_blk_ioc_data *idatas[1];
struct mmc_blk_data *md;
struct mmc_queue *mq;
struct mmc_card *card;
int err = 0, ioc_err = 0;
struct request *req;
/*
* 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);
if (IS_ERR(idata))
return PTR_ERR(idata);
md = mmc_blk_get(bdev->bd_disk);
if (!md) {
err = -EINVAL;
goto cmd_err;
}
card = md->queue.card;
if (IS_ERR(card)) {
err = PTR_ERR(card);
@ -598,7 +582,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
__GFP_RECLAIM);
idatas[0] = idata;
req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL;
req_to_mmc_queue_req(req)->idata = idatas;
req_to_mmc_queue_req(req)->drv_op_data = idatas;
req_to_mmc_queue_req(req)->ioc_count = 1;
blk_execute_rq(mq->queue, NULL, req, 0);
ioc_err = req_to_mmc_queue_req(req)->drv_op_result;
@ -606,33 +590,22 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
blk_put_request(req);
cmd_done:
mmc_blk_put(md);
cmd_err:
kfree(idata->buf);
kfree(idata);
return ioc_err ? ioc_err : err;
}
static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev,
static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md,
struct mmc_ioc_multi_cmd __user *user)
{
struct mmc_blk_ioc_data **idata = NULL;
struct mmc_ioc_cmd __user *cmds = user->cmds;
struct mmc_card *card;
struct mmc_blk_data *md;
struct mmc_queue *mq;
int i, err = 0, ioc_err = 0;
__u64 num_of_cmds;
struct request *req;
/*
* 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,
sizeof(num_of_cmds)))
return -EFAULT;
@ -656,16 +629,10 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev,
}
}
md = mmc_blk_get(bdev->bd_disk);
if (!md) {
err = -EINVAL;
goto cmd_err;
}
card = md->queue.card;
if (IS_ERR(card)) {
err = PTR_ERR(card);
goto cmd_done;
goto cmd_err;
}
@ -677,7 +644,7 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev,
idata[0]->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN,
__GFP_RECLAIM);
req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL;
req_to_mmc_queue_req(req)->idata = idata;
req_to_mmc_queue_req(req)->drv_op_data = idata;
req_to_mmc_queue_req(req)->ioc_count = num_of_cmds;
blk_execute_rq(mq->queue, NULL, req, 0);
ioc_err = req_to_mmc_queue_req(req)->drv_op_result;
@ -688,8 +655,6 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev,
blk_put_request(req);
cmd_done:
mmc_blk_put(md);
cmd_err:
for (i = 0; i < num_of_cmds; i++) {
kfree(idata[i]->buf);
@ -699,16 +664,47 @@ cmd_err:
return ioc_err ? ioc_err : err;
}
static int mmc_blk_check_blkdev(struct block_device *bdev)
{
/*
* 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;
return 0;
}
static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
struct mmc_blk_data *md;
int ret;
switch (cmd) {
case MMC_IOC_CMD:
return mmc_blk_ioctl_cmd(bdev,
ret = mmc_blk_check_blkdev(bdev);
if (ret)
return ret;
md = mmc_blk_get(bdev->bd_disk);
if (!md)
return -EINVAL;
ret = mmc_blk_ioctl_cmd(md,
(struct mmc_ioc_cmd __user *)arg);
mmc_blk_put(md);
return ret;
case MMC_IOC_MULTI_CMD:
return mmc_blk_ioctl_multi_cmd(bdev,
ret = mmc_blk_check_blkdev(bdev);
if (ret)
return ret;
md = mmc_blk_get(bdev->bd_disk);
if (!md)
return -EINVAL;
ret = mmc_blk_ioctl_multi_cmd(md,
(struct mmc_ioc_multi_cmd __user *)arg);
mmc_blk_put(md);
return ret;
default:
return -EINVAL;
}
@ -765,29 +761,29 @@ static int mmc_blk_part_switch_post(struct mmc_card *card,
}
static inline int mmc_blk_part_switch(struct mmc_card *card,
struct mmc_blk_data *md)
unsigned int part_type)
{
int ret = 0;
struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev);
if (main_md->part_curr == md->part_type)
if (main_md->part_curr == part_type)
return 0;
if (mmc_card_mmc(card)) {
u8 part_config = card->ext_csd.part_config;
ret = mmc_blk_part_switch_pre(card, md->part_type);
ret = mmc_blk_part_switch_pre(card, part_type);
if (ret)
return ret;
part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
part_config |= md->part_type;
part_config |= part_type;
ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_PART_CONFIG, part_config,
card->ext_csd.part_time);
if (ret) {
mmc_blk_part_switch_post(card, md->part_type);
mmc_blk_part_switch_post(card, part_type);
return ret;
}
@ -796,7 +792,7 @@ static inline int mmc_blk_part_switch(struct mmc_card *card,
ret = mmc_blk_part_switch_post(card, main_md->part_curr);
}
main_md->part_curr = md->part_type;
main_md->part_curr = part_type;
return ret;
}
@ -1139,7 +1135,7 @@ static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host,
int part_err;
main_md->part_curr = main_md->part_type;
part_err = mmc_blk_part_switch(host->card, md);
part_err = mmc_blk_part_switch(host->card, md->part_type);
if (part_err) {
/*
* We have failed to get back into the correct
@ -1178,6 +1174,10 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
struct mmc_queue_req *mq_rq;
struct mmc_card *card = mq->card;
struct mmc_blk_data *md = mq->blkdata;
struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev);
struct mmc_blk_ioc_data **idata;
u8 **ext_csd;
u32 status;
int ret;
int i;
@ -1185,14 +1185,15 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
switch (mq_rq->drv_op) {
case MMC_DRV_OP_IOCTL:
idata = mq_rq->drv_op_data;
for (i = 0, ret = 0; i < mq_rq->ioc_count; i++) {
ret = __mmc_blk_ioctl_cmd(card, md, mq_rq->idata[i]);
ret = __mmc_blk_ioctl_cmd(card, md, idata[i]);
if (ret)
break;
}
/* Always switch back to main area after RPMB access */
if (md->area_type & MMC_BLK_DATA_AREA_RPMB)
mmc_blk_part_switch(card, dev_get_drvdata(&card->dev));
mmc_blk_part_switch(card, main_md->part_type);
break;
case MMC_DRV_OP_BOOT_WP:
ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
@ -1206,6 +1207,15 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
card->ext_csd.boot_ro_lock |=
EXT_CSD_BOOT_WP_B_PWR_WP_EN;
break;
case MMC_DRV_OP_GET_CARD_STATUS:
ret = mmc_send_status(card, &status);
if (!ret)
ret = status;
break;
case MMC_DRV_OP_GET_EXT_CSD:
ext_csd = mq_rq->drv_op_data;
ret = mmc_get_ext_csd(card, ext_csd);
break;
default:
pr_err("%s: unknown driver specific operation\n",
md->disk->disk_name);
@ -1943,7 +1953,7 @@ void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
/* claim host only for the first request */
mmc_get_card(card);
ret = mmc_blk_part_switch(card, md);
ret = mmc_blk_part_switch(card, md->part_type);
if (ret) {
if (req) {
blk_end_request_all(req, BLK_STS_IOERR);
@ -2024,8 +2034,20 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
int devidx, ret;
devidx = ida_simple_get(&mmc_blk_ida, 0, max_devices, GFP_KERNEL);
if (devidx < 0)
if (devidx < 0) {
/*
* We get -ENOSPC because there are no more any available
* devidx. The reason may be that, either userspace haven't yet
* unmounted the partitions, which postpones mmc_blk_release()
* from being called, or the device has more partitions than
* what we support.
*/
if (devidx == -ENOSPC)
dev_err(mmc_dev(card->host),
"no more device IDs available\n");
return ERR_PTR(devidx);
}
md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
if (!md) {
@ -2283,6 +2305,134 @@ force_ro_fail:
return ret;
}
#ifdef CONFIG_DEBUG_FS
static int mmc_dbg_card_status_get(void *data, u64 *val)
{
struct mmc_card *card = data;
struct mmc_blk_data *md = dev_get_drvdata(&card->dev);
struct mmc_queue *mq = &md->queue;
struct request *req;
int ret;
/* Ask the block layer about the card status */
req = blk_get_request(mq->queue, REQ_OP_DRV_IN, __GFP_RECLAIM);
req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_GET_CARD_STATUS;
blk_execute_rq(mq->queue, NULL, req, 0);
ret = req_to_mmc_queue_req(req)->drv_op_result;
if (ret >= 0) {
*val = ret;
ret = 0;
}
return ret;
}
DEFINE_SIMPLE_ATTRIBUTE(mmc_dbg_card_status_fops, mmc_dbg_card_status_get,
NULL, "%08llx\n");
/* That is two digits * 512 + 1 for newline */
#define EXT_CSD_STR_LEN 1025
static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
{
struct mmc_card *card = inode->i_private;
struct mmc_blk_data *md = dev_get_drvdata(&card->dev);
struct mmc_queue *mq = &md->queue;
struct request *req;
char *buf;
ssize_t n = 0;
u8 *ext_csd;
int err, i;
buf = kmalloc(EXT_CSD_STR_LEN + 1, GFP_KERNEL);
if (!buf)
return -ENOMEM;
/* Ask the block layer for the EXT CSD */
req = blk_get_request(mq->queue, REQ_OP_DRV_IN, __GFP_RECLAIM);
req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_GET_EXT_CSD;
req_to_mmc_queue_req(req)->drv_op_data = &ext_csd;
blk_execute_rq(mq->queue, NULL, req, 0);
err = req_to_mmc_queue_req(req)->drv_op_result;
if (err) {
pr_err("FAILED %d\n", err);
goto out_free;
}
for (i = 0; i < 512; i++)
n += sprintf(buf + n, "%02x", ext_csd[i]);
n += sprintf(buf + n, "\n");
if (n != EXT_CSD_STR_LEN) {
err = -EINVAL;
goto out_free;
}
filp->private_data = buf;
kfree(ext_csd);
return 0;
out_free:
kfree(buf);
return err;
}
static ssize_t mmc_ext_csd_read(struct file *filp, char __user *ubuf,
size_t cnt, loff_t *ppos)
{
char *buf = filp->private_data;
return simple_read_from_buffer(ubuf, cnt, ppos,
buf, EXT_CSD_STR_LEN);
}
static int mmc_ext_csd_release(struct inode *inode, struct file *file)
{
kfree(file->private_data);
return 0;
}
static const struct file_operations mmc_dbg_ext_csd_fops = {
.open = mmc_ext_csd_open,
.read = mmc_ext_csd_read,
.release = mmc_ext_csd_release,
.llseek = default_llseek,
};
static int mmc_blk_add_debugfs(struct mmc_card *card)
{
struct dentry *root;
if (!card->debugfs_root)
return 0;
root = card->debugfs_root;
if (mmc_card_mmc(card) || mmc_card_sd(card)) {
if (!debugfs_create_file("status", S_IRUSR, root, card,
&mmc_dbg_card_status_fops))
return -EIO;
}
if (mmc_card_mmc(card)) {
if (!debugfs_create_file("ext_csd", S_IRUSR, root, card,
&mmc_dbg_ext_csd_fops))
return -EIO;
}
return 0;
}
#else
static int mmc_blk_add_debugfs(struct mmc_card *card)
{
return 0;
}
#endif /* CONFIG_DEBUG_FS */
static int mmc_blk_probe(struct mmc_card *card)
{
struct mmc_blk_data *md, *part_md;
@ -2319,6 +2469,9 @@ static int mmc_blk_probe(struct mmc_card *card)
goto out;
}
/* Add two debugfs entries */
mmc_blk_add_debugfs(card);
pm_runtime_set_autosuspend_delay(&card->dev, 3000);
pm_runtime_use_autosuspend(&card->dev);
@ -2346,7 +2499,7 @@ static void mmc_blk_remove(struct mmc_card *card)
mmc_blk_remove_parts(card, md);
pm_runtime_get_sync(&card->dev);
mmc_claim_host(card->host);
mmc_blk_part_switch(card, md);
mmc_blk_part_switch(card, md->part_type);
mmc_release_host(card->host);
if (card->type != MMC_TYPE_SD_COMBO)
pm_runtime_disable(&card->dev);

View File

@ -260,6 +260,9 @@ static void __mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
trace_mmc_request_start(host, mrq);
if (host->cqe_on)
host->cqe_ops->cqe_off(host);
host->ops->request(host, mrq);
}
@ -295,10 +298,8 @@ static void mmc_mrq_pr_debug(struct mmc_host *host, struct mmc_request *mrq)
static int mmc_mrq_prep(struct mmc_host *host, struct mmc_request *mrq)
{
#ifdef CONFIG_MMC_DEBUG
unsigned int i, sz;
unsigned int i, sz = 0;
struct scatterlist *sg;
#endif
if (mrq->cmd) {
mrq->cmd->error = 0;
@ -314,13 +315,12 @@ static int mmc_mrq_prep(struct mmc_host *host, struct mmc_request *mrq)
mrq->data->blocks > host->max_blk_count ||
mrq->data->blocks * mrq->data->blksz > host->max_req_size)
return -EINVAL;
#ifdef CONFIG_MMC_DEBUG
sz = 0;
for_each_sg(mrq->data->sg, sg, mrq->data->sg_len, i)
sz += sg->length;
if (sz != mrq->data->blocks * mrq->data->blksz)
return -EINVAL;
#endif
mrq->data->error = 0;
mrq->data->mrq = mrq;
if (mrq->stop) {
@ -736,8 +736,8 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
if (data->flags & MMC_DATA_WRITE)
mult <<= card->csd.r2w_factor;
data->timeout_ns = card->csd.tacc_ns * mult;
data->timeout_clks = card->csd.tacc_clks * mult;
data->timeout_ns = card->csd.taac_ns * mult;
data->timeout_clks = card->csd.taac_clks * mult;
/*
* SD cards also have an upper limit on the timeout.
@ -766,7 +766,7 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
/*
* SDHC cards always use these fixed values.
*/
if (timeout_us > limit_us || mmc_card_blockaddr(card)) {
if (timeout_us > limit_us) {
data->timeout_ns = limit_us * 1000;
data->timeout_clks = 0;
}
@ -982,6 +982,9 @@ int mmc_execute_tuning(struct mmc_card *card)
if (!host->ops->execute_tuning)
return 0;
if (host->cqe_on)
host->cqe_ops->cqe_off(host);
if (mmc_card_mmc(card))
opcode = MMC_SEND_TUNING_BLOCK_HS200;
else
@ -1021,6 +1024,9 @@ void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
*/
void mmc_set_initial_state(struct mmc_host *host)
{
if (host->cqe_on)
host->cqe_ops->cqe_off(host);
mmc_retune_disable(host);
if (mmc_host_is_spi(host))
@ -1137,11 +1143,11 @@ int mmc_of_parse_voltage(struct device_node *np, u32 *mask)
voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges);
num_ranges = num_ranges / sizeof(*voltage_ranges) / 2;
if (!voltage_ranges) {
pr_debug("%s: voltage-ranges unspecified\n", np->full_name);
pr_debug("%pOF: voltage-ranges unspecified\n", np);
return 0;
}
if (!num_ranges) {
pr_err("%s: voltage-ranges empty\n", np->full_name);
pr_err("%pOF: voltage-ranges empty\n", np);
return -EINVAL;
}
@ -1153,8 +1159,8 @@ int mmc_of_parse_voltage(struct device_node *np, u32 *mask)
be32_to_cpu(voltage_ranges[j]),
be32_to_cpu(voltage_ranges[j + 1]));
if (!ocr_mask) {
pr_err("%s: voltage-range #%d is invalid\n",
np->full_name, i);
pr_err("%pOF: voltage-range #%d is invalid\n",
np, i);
return -EINVAL;
}
*mask |= ocr_mask;
@ -1769,13 +1775,6 @@ void mmc_detach_bus(struct mmc_host *host)
static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
bool cd_irq)
{
#ifdef CONFIG_MMC_DEBUG
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
WARN_ON(host->removed);
spin_unlock_irqrestore(&host->lock, flags);
#endif
/*
* If the device is configured as wakeup, we prevent a new sleep for
* 5 s to give provision for user space to consume the event.
@ -1869,14 +1868,14 @@ static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
} else {
/* CSD Erase Group Size uses write timeout */
unsigned int mult = (10 << card->csd.r2w_factor);
unsigned int timeout_clks = card->csd.tacc_clks * mult;
unsigned int timeout_clks = card->csd.taac_clks * mult;
unsigned int timeout_us;
/* Avoid overflow: e.g. tacc_ns=80000000 mult=1280 */
if (card->csd.tacc_ns < 1000000)
timeout_us = (card->csd.tacc_ns * mult) / 1000;
/* Avoid overflow: e.g. taac_ns=80000000 mult=1280 */
if (card->csd.taac_ns < 1000000)
timeout_us = (card->csd.taac_ns * mult) / 1000;
else
timeout_us = (card->csd.tacc_ns / 1000) * mult;
timeout_us = (card->csd.taac_ns / 1000) * mult;
/*
* ios.clock is only a target. The real clock rate might be
@ -2446,10 +2445,9 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
{
host->f_init = freq;
#ifdef CONFIG_MMC_DEBUG
pr_info("%s: %s: trying to init card at %u Hz\n",
pr_debug("%s: %s: trying to init card at %u Hz\n",
mmc_hostname(host), __func__, host->f_init);
#endif
mmc_power_up(host, host->ocr_avail);
/*
@ -2646,12 +2644,6 @@ void mmc_start_host(struct mmc_host *host)
void mmc_stop_host(struct mmc_host *host)
{
#ifdef CONFIG_MMC_DEBUG
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
host->removed = 1;
spin_unlock_irqrestore(&host->lock, flags);
#endif
if (host->slot.cd_irq >= 0) {
if (host->slot.cd_wake_enabled)
disable_irq_wake(host->slot.cd_irq);
@ -2686,9 +2678,7 @@ int mmc_power_save_host(struct mmc_host *host)
{
int ret = 0;
#ifdef CONFIG_MMC_DEBUG
pr_info("%s: %s: powering down\n", mmc_hostname(host), __func__);
#endif
pr_debug("%s: %s: powering down\n", mmc_hostname(host), __func__);
mmc_bus_get(host);
@ -2712,9 +2702,7 @@ int mmc_power_restore_host(struct mmc_host *host)
{
int ret;
#ifdef CONFIG_MMC_DEBUG
pr_info("%s: %s: powering up\n", mmc_hostname(host), __func__);
#endif
pr_debug("%s: %s: powering up\n", mmc_hostname(host), __func__);
mmc_bus_get(host);

View File

@ -107,6 +107,12 @@ static inline void mmc_unregister_pm_notifier(struct mmc_host *host) { }
void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq);
bool mmc_is_req_done(struct mmc_host *host, struct mmc_request *mrq);
struct mmc_async_req;
struct mmc_async_req *mmc_start_areq(struct mmc_host *host,
struct mmc_async_req *areq,
enum mmc_blk_status *ret_stat);
int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
unsigned int arg);
int mmc_can_erase(struct mmc_card *card);

View File

@ -281,85 +281,6 @@ void mmc_remove_host_debugfs(struct mmc_host *host)
debugfs_remove_recursive(host->debugfs_root);
}
static int mmc_dbg_card_status_get(void *data, u64 *val)
{
struct mmc_card *card = data;
u32 status;
int ret;
mmc_get_card(card);
ret = mmc_send_status(data, &status);
if (!ret)
*val = status;
mmc_put_card(card);
return ret;
}
DEFINE_SIMPLE_ATTRIBUTE(mmc_dbg_card_status_fops, mmc_dbg_card_status_get,
NULL, "%08llx\n");
#define EXT_CSD_STR_LEN 1025
static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
{
struct mmc_card *card = inode->i_private;
char *buf;
ssize_t n = 0;
u8 *ext_csd;
int err, i;
buf = kmalloc(EXT_CSD_STR_LEN + 1, GFP_KERNEL);
if (!buf)
return -ENOMEM;
mmc_get_card(card);
err = mmc_get_ext_csd(card, &ext_csd);
mmc_put_card(card);
if (err)
goto out_free;
for (i = 0; i < 512; i++)
n += sprintf(buf + n, "%02x", ext_csd[i]);
n += sprintf(buf + n, "\n");
if (n != EXT_CSD_STR_LEN) {
err = -EINVAL;
goto out_free;
}
filp->private_data = buf;
kfree(ext_csd);
return 0;
out_free:
kfree(buf);
return err;
}
static ssize_t mmc_ext_csd_read(struct file *filp, char __user *ubuf,
size_t cnt, loff_t *ppos)
{
char *buf = filp->private_data;
return simple_read_from_buffer(ubuf, cnt, ppos,
buf, EXT_CSD_STR_LEN);
}
static int mmc_ext_csd_release(struct inode *inode, struct file *file)
{
kfree(file->private_data);
return 0;
}
static const struct file_operations mmc_dbg_ext_csd_fops = {
.open = mmc_ext_csd_open,
.read = mmc_ext_csd_read,
.release = mmc_ext_csd_release,
.llseek = default_llseek,
};
void mmc_add_card_debugfs(struct mmc_card *card)
{
struct mmc_host *host = card->host;
@ -382,16 +303,6 @@ void mmc_add_card_debugfs(struct mmc_card *card)
if (!debugfs_create_x32("state", S_IRUSR, root, &card->state))
goto err;
if (mmc_card_mmc(card) || mmc_card_sd(card))
if (!debugfs_create_file("status", S_IRUSR, root, card,
&mmc_dbg_card_status_fops))
goto err;
if (mmc_card_mmc(card))
if (!debugfs_create_file("ext_csd", S_IRUSR, root, card,
&mmc_dbg_ext_csd_fops))
goto err;
return;
err:

View File

@ -111,6 +111,12 @@ void mmc_retune_hold(struct mmc_host *host)
host->hold_retune += 1;
}
void mmc_retune_hold_now(struct mmc_host *host)
{
host->retune_now = 0;
host->hold_retune += 1;
}
void mmc_retune_release(struct mmc_host *host)
{
if (host->hold_retune)

View File

@ -19,6 +19,7 @@ void mmc_unregister_host_class(void);
void mmc_retune_enable(struct mmc_host *host);
void mmc_retune_disable(struct mmc_host *host);
void mmc_retune_hold(struct mmc_host *host);
void mmc_retune_hold_now(struct mmc_host *host);
void mmc_retune_release(struct mmc_host *host);
int mmc_retune(struct mmc_host *host);
void mmc_retune_pause(struct mmc_host *host);

View File

@ -41,11 +41,11 @@ static const unsigned char tran_mant[] = {
35, 40, 45, 50, 55, 60, 70, 80,
};
static const unsigned int tacc_exp[] = {
static const unsigned int taac_exp[] = {
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
};
static const unsigned int tacc_mant[] = {
static const unsigned int taac_mant[] = {
0, 10, 12, 13, 15, 20, 25, 30,
35, 40, 45, 50, 55, 60, 70, 80,
};
@ -153,8 +153,8 @@ static int mmc_decode_csd(struct mmc_card *card)
csd->mmca_vsn = UNSTUFF_BITS(resp, 122, 4);
m = UNSTUFF_BITS(resp, 115, 4);
e = UNSTUFF_BITS(resp, 112, 3);
csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
csd->taac_ns = (taac_exp[e] * taac_mant[m] + 9) / 10;
csd->taac_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
m = UNSTUFF_BITS(resp, 99, 4);
e = UNSTUFF_BITS(resp, 96, 3);
@ -1790,29 +1790,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
*/
card->reenable_cmdq = card->ext_csd.cmdq_en;
/*
* The mandatory minimum values are defined for packed command.
* read: 5, write: 3
*/
if (card->ext_csd.max_packed_writes >= 3 &&
card->ext_csd.max_packed_reads >= 5 &&
host->caps2 & MMC_CAP2_PACKED_CMD) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_EXP_EVENTS_CTRL,
EXT_CSD_PACKED_EVENT_EN,
card->ext_csd.generic_cmd6_time);
if (err && err != -EBADMSG)
goto free_card;
if (err) {
pr_warn("%s: Enabling packed event failed\n",
mmc_hostname(card->host));
card->ext_csd.packed_event_en = 0;
err = 0;
} else {
card->ext_csd.packed_event_en = 1;
}
}
if (!oldcard)
host->card = card;

View File

@ -83,6 +83,7 @@ int mmc_send_status(struct mmc_card *card, u32 *status)
{
return __mmc_send_status(card, status, MMC_CMD_RETRIES);
}
EXPORT_SYMBOL_GPL(mmc_send_status);
static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
{
@ -946,7 +947,7 @@ static int mmc_read_bkops_status(struct mmc_card *card)
/**
* mmc_start_bkops - start BKOPS for supported cards
* @card: MMC card to start BKOPS
* @form_exception: A flag to indicate if this function was
* @from_exception: A flag to indicate if this function was
* called due to an exception raised by the card
*
* Start background operations whenever requested.

View File

@ -800,38 +800,44 @@ static int mmc_test_check_broken_result(struct mmc_test_card *test,
return ret;
}
struct mmc_test_req {
struct mmc_request mrq;
struct mmc_command sbc;
struct mmc_command cmd;
struct mmc_command stop;
struct mmc_command status;
struct mmc_data data;
};
/*
* Tests nonblock transfer with certain parameters
*/
static void mmc_test_nonblock_reset(struct mmc_request *mrq,
struct mmc_command *cmd,
struct mmc_command *stop,
struct mmc_data *data)
static void mmc_test_req_reset(struct mmc_test_req *rq)
{
memset(mrq, 0, sizeof(struct mmc_request));
memset(cmd, 0, sizeof(struct mmc_command));
memset(data, 0, sizeof(struct mmc_data));
memset(stop, 0, sizeof(struct mmc_command));
memset(rq, 0, sizeof(struct mmc_test_req));
mrq->cmd = cmd;
mrq->data = data;
mrq->stop = stop;
rq->mrq.cmd = &rq->cmd;
rq->mrq.data = &rq->data;
rq->mrq.stop = &rq->stop;
}
static struct mmc_test_req *mmc_test_req_alloc(void)
{
struct mmc_test_req *rq = kmalloc(sizeof(*rq), GFP_KERNEL);
if (rq)
mmc_test_req_reset(rq);
return rq;
}
static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
struct scatterlist *sg, unsigned sg_len,
unsigned dev_addr, unsigned blocks,
unsigned blksz, int write, int count)
{
struct mmc_request mrq1;
struct mmc_command cmd1;
struct mmc_command stop1;
struct mmc_data data1;
struct mmc_request mrq2;
struct mmc_command cmd2;
struct mmc_command stop2;
struct mmc_data data2;
struct mmc_test_req *rq1, *rq2;
struct mmc_test_async_req test_areq[2];
struct mmc_async_req *done_areq;
struct mmc_async_req *cur_areq = &test_areq[0].areq;
@ -843,12 +849,16 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
test_areq[0].test = test;
test_areq[1].test = test;
mmc_test_nonblock_reset(&mrq1, &cmd1, &stop1, &data1);
mmc_test_nonblock_reset(&mrq2, &cmd2, &stop2, &data2);
rq1 = mmc_test_req_alloc();
rq2 = mmc_test_req_alloc();
if (!rq1 || !rq2) {
ret = RESULT_FAIL;
goto err;
}
cur_areq->mrq = &mrq1;
cur_areq->mrq = &rq1->mrq;
cur_areq->err_check = mmc_test_check_result_async;
other_areq->mrq = &mrq2;
other_areq->mrq = &rq2->mrq;
other_areq->err_check = mmc_test_check_result_async;
for (i = 0; i < count; i++) {
@ -861,14 +871,10 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
goto err;
}
if (done_areq) {
if (done_areq->mrq == &mrq2)
mmc_test_nonblock_reset(&mrq2, &cmd2,
&stop2, &data2);
else
mmc_test_nonblock_reset(&mrq1, &cmd1,
&stop1, &data1);
}
if (done_areq)
mmc_test_req_reset(container_of(done_areq->mrq,
struct mmc_test_req, mrq));
swap(cur_areq, other_areq);
dev_addr += blocks;
}
@ -877,8 +883,9 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
if (status != MMC_BLK_SUCCESS)
ret = RESULT_FAIL;
return ret;
err:
kfree(rq1);
kfree(rq2);
return ret;
}
@ -2329,28 +2336,6 @@ static int mmc_test_reset(struct mmc_test_card *test)
return RESULT_FAIL;
}
struct mmc_test_req {
struct mmc_request mrq;
struct mmc_command sbc;
struct mmc_command cmd;
struct mmc_command stop;
struct mmc_command status;
struct mmc_data data;
};
static struct mmc_test_req *mmc_test_req_alloc(void)
{
struct mmc_test_req *rq = kzalloc(sizeof(*rq), GFP_KERNEL);
if (rq) {
rq->mrq.cmd = &rq->cmd;
rq->mrq.data = &rq->data;
rq->mrq.stop = &rq->stop;
}
return rq;
}
static int mmc_test_send_status(struct mmc_test_card *test,
struct mmc_command *cmd)
{

View File

@ -36,10 +36,14 @@ struct mmc_blk_request {
* enum mmc_drv_op - enumerates the operations in the mmc_queue_req
* @MMC_DRV_OP_IOCTL: ioctl operation
* @MMC_DRV_OP_BOOT_WP: write protect boot partitions
* @MMC_DRV_OP_GET_CARD_STATUS: get card status
* @MMC_DRV_OP_GET_EXT_CSD: get the EXT CSD from an eMMC card
*/
enum mmc_drv_op {
MMC_DRV_OP_IOCTL,
MMC_DRV_OP_BOOT_WP,
MMC_DRV_OP_GET_CARD_STATUS,
MMC_DRV_OP_GET_EXT_CSD,
};
struct mmc_queue_req {
@ -51,7 +55,7 @@ struct mmc_queue_req {
struct mmc_async_req areq;
enum mmc_drv_op drv_op;
int drv_op_result;
struct mmc_blk_ioc_data **idata;
void *drv_op_data;
unsigned int ioc_count;
};

View File

@ -39,11 +39,11 @@ static const unsigned char tran_mant[] = {
35, 40, 45, 50, 55, 60, 70, 80,
};
static const unsigned int tacc_exp[] = {
static const unsigned int taac_exp[] = {
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
};
static const unsigned int tacc_mant[] = {
static const unsigned int taac_mant[] = {
0, 10, 12, 13, 15, 20, 25, 30,
35, 40, 45, 50, 55, 60, 70, 80,
};
@ -111,8 +111,8 @@ static int mmc_decode_csd(struct mmc_card *card)
case 0:
m = UNSTUFF_BITS(resp, 115, 4);
e = UNSTUFF_BITS(resp, 112, 3);
csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
csd->taac_ns = (taac_exp[e] * taac_mant[m] + 9) / 10;
csd->taac_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
m = UNSTUFF_BITS(resp, 99, 4);
e = UNSTUFF_BITS(resp, 96, 3);
@ -148,8 +148,8 @@ static int mmc_decode_csd(struct mmc_card *card)
*/
mmc_card_set_blockaddr(card);
csd->tacc_ns = 0; /* Unused */
csd->tacc_clks = 0; /* Unused */
csd->taac_ns = 0; /* Unused */
csd->taac_clks = 0; /* Unused */
m = UNSTUFF_BITS(resp, 99, 4);
e = UNSTUFF_BITS(resp, 96, 3);

View File

@ -4,6 +4,15 @@
comment "MMC/SD/SDIO Host Controller Drivers"
config MMC_DEBUG
bool "MMC host drivers debugginG"
depends on MMC != n
help
This is an option for use by developers; most people should
say N here. This enables MMC host driver debugging. And further
added host drivers please don't invent their private macro for
debugging.
config MMC_ARMMMCI
tristate "ARM AMBA Multimedia Card Interface support"
depends on ARM_AMBA
@ -15,7 +24,7 @@ config MMC_ARMMMCI
If unsure, say N.
config MMC_QCOM_DML
tristate "Qualcomm Data Mover for SD Card Controller"
bool "Qualcomm Data Mover for SD Card Controller"
depends on MMC_ARMMMCI && QCOM_BAM_DMA
default y
help
@ -354,7 +363,7 @@ config MMC_MOXART
config MMC_SDHCI_ST
tristate "SDHCI support on STMicroelectronics SoC"
depends on ARCH_STI
depends on ARCH_STI || FSP2
depends on MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS
help
@ -494,7 +503,7 @@ config MMC_GOLDFISH
config MMC_SPI
tristate "MMC/SD/SDIO over SPI"
depends on SPI_MASTER && !HIGHMEM && HAS_DMA
depends on SPI_MASTER && HAS_DMA
select CRC7
select CRC_ITU_T
help
@ -575,10 +584,29 @@ config MMC_SDHI
depends on SUPERH || ARM || ARM64
depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
select MMC_TMIO_CORE
select MMC_SDHI_SYS_DMAC if (SUPERH || ARM)
select MMC_SDHI_INTERNAL_DMAC if ARM64
help
This provides support for the SDHI SD/SDIO controller found in
Renesas SuperH, ARM and ARM64 based SoCs
config MMC_SDHI_SYS_DMAC
tristate "DMA for SDHI SD/SDIO controllers using SYS-DMAC"
depends on MMC_SDHI
help
This provides DMA support for SDHI SD/SDIO controllers
using SYS-DMAC via DMA Engine. This supports the controllers
found in SuperH and Renesas ARM based SoCs.
config MMC_SDHI_INTERNAL_DMAC
tristate "DMA for SDHI SD/SDIO controllers using on-chip bus mastering"
depends on ARM64 || COMPILE_TEST
depends on MMC_SDHI
help
This provides DMA support for SDHI SD/SDIO controllers
using on-chip bus mastering. This supports the controllers
found in arm64 based SoCs.
config MMC_CB710
tristate "ENE CB710 MMC/SD Interface support"
depends on PCI

View File

@ -2,8 +2,9 @@
# Makefile for MMC/SD host controller drivers
#
obj-$(CONFIG_MMC_ARMMMCI) += mmci.o
obj-$(CONFIG_MMC_QCOM_DML) += mmci_qcom_dml.o
obj-$(CONFIG_MMC_ARMMMCI) += armmmci.o
armmmci-y := mmci.o
armmmci-$(CONFIG_MMC_QCOM_DML) += mmci_qcom_dml.o
obj-$(CONFIG_MMC_PXA) += pxamci.o
obj-$(CONFIG_MMC_MXC) += mxcmmc.o
obj-$(CONFIG_MMC_MXS) += mxs-mmc.o
@ -36,7 +37,13 @@ obj-$(CONFIG_MMC_S3C) += s3cmci.o
obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o
obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o
obj-$(CONFIG_MMC_TMIO_CORE) += tmio_mmc_core.o
obj-$(CONFIG_MMC_SDHI) += renesas_sdhi_core.o renesas_sdhi_sys_dmac.o
obj-$(CONFIG_MMC_SDHI) += renesas_sdhi_core.o
ifeq ($(subst m,y,$(CONFIG_MMC_SDHI_SYS_DMAC)),y)
obj-$(CONFIG_MMC_SDHI) += renesas_sdhi_sys_dmac.o
endif
ifeq ($(subst m,y,$(CONFIG_MMC_SDHI_INTERNAL_DMAC)),y)
obj-$(CONFIG_MMC_SDHI) += renesas_sdhi_internal_dmac.o
endif
obj-$(CONFIG_MMC_CB710) += cb710-mmc.o
obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o

View File

@ -290,7 +290,6 @@ static irqreturn_t goldfish_mmc_irq(int irq, void *dev_id)
u16 status;
int end_command = 0;
int end_transfer = 0;
int transfer_error = 0;
int state_changed = 0;
int cmd_timeout = 0;
@ -322,9 +321,7 @@ static irqreturn_t goldfish_mmc_irq(int irq, void *dev_id)
if (end_command)
goldfish_mmc_cmd_done(host, host->cmd);
if (transfer_error)
goldfish_mmc_xfer_done(host, host->data);
else if (end_transfer) {
if (end_transfer) {
host->dma_done = 1;
goldfish_mmc_end_of_data(host, host->data);
} else if (host->data != NULL) {
@ -347,8 +344,7 @@ static irqreturn_t goldfish_mmc_irq(int irq, void *dev_id)
mmc_detect_change(host->mmc, 0);
}
if (!end_command && !end_transfer &&
!transfer_error && !state_changed && !cmd_timeout) {
if (!end_command && !end_transfer && !state_changed && !cmd_timeout) {
status = GOLDFISH_MMC_READ(host, MMC_INT_STATUS);
dev_info(mmc_dev(host->mmc),"spurious irq 0x%04x\n", status);
if (status != 0) {

View File

@ -665,14 +665,15 @@ atmci_of_init(struct platform_device *pdev)
for_each_child_of_node(np, cnp) {
if (of_property_read_u32(cnp, "reg", &slot_id)) {
dev_warn(&pdev->dev, "reg property is missing for %s\n",
cnp->full_name);
dev_warn(&pdev->dev, "reg property is missing for %pOF\n",
cnp);
continue;
}
if (slot_id >= ATMCI_MAX_NR_SLOTS) {
dev_warn(&pdev->dev, "can't have more than %d slots\n",
ATMCI_MAX_NR_SLOTS);
of_node_put(cnp);
break;
}
@ -1083,7 +1084,6 @@ static u32
atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
{
u32 iflags, tmp;
unsigned int sg_len;
int i;
data->error = -EINPROGRESS;
@ -1108,7 +1108,7 @@ atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
/* Configure PDC */
host->data_size = data->blocks * data->blksz;
sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len,
dma_map_sg(&host->pdev->dev, data->sg, data->sg_len,
mmc_get_dma_dir(data));
if ((!host->caps.has_rwproof)

View File

@ -1252,7 +1252,7 @@ static void bcm2835_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
mutex_unlock(&host->mutex);
}
static struct mmc_host_ops bcm2835_ops = {
static const struct mmc_host_ops bcm2835_ops = {
.request = bcm2835_request,
.set_ios = bcm2835_set_ios,
.hw_reset = bcm2835_reset,

View File

@ -342,18 +342,7 @@ static struct platform_driver octeon_mmc_driver = {
},
};
static int __init octeon_mmc_init(void)
{
return platform_driver_register(&octeon_mmc_driver);
}
static void __exit octeon_mmc_cleanup(void)
{
platform_driver_unregister(&octeon_mmc_driver);
}
module_init(octeon_mmc_init);
module_exit(octeon_mmc_cleanup);
module_platform_driver(octeon_mmc_driver);
MODULE_AUTHOR("Cavium Inc. <support@cavium.com>");
MODULE_DESCRIPTION("Low-level driver for Cavium OCTEON MMC/SSD card");

View File

@ -957,14 +957,12 @@ static int cvm_mmc_of_parse(struct device *dev, struct cvm_mmc_slot *slot)
ret = of_property_read_u32(node, "reg", &id);
if (ret) {
dev_err(dev, "Missing or invalid reg property on %s\n",
of_node_full_name(node));
dev_err(dev, "Missing or invalid reg property on %pOF\n", node);
return ret;
}
if (id >= CAVIUM_MAX_MMC || slot->host->slot[id]) {
dev_err(dev, "Invalid reg property on %s\n",
of_node_full_name(node));
dev_err(dev, "Invalid reg property on %pOF\n", node);
return -EINVAL;
}

View File

@ -1062,7 +1062,7 @@ static void mmc_davinci_enable_sdio_irq(struct mmc_host *mmc, int enable)
}
}
static struct mmc_host_ops mmc_davinci_ops = {
static const struct mmc_host_ops mmc_davinci_ops = {
.request = mmc_davinci_request,
.set_ios = mmc_davinci_set_ios,
.get_cd = mmc_davinci_get_cd,

View File

@ -8,6 +8,8 @@
* (at your option) any later version.
*/
#include <linux/bitops.h>
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/mfd/syscon.h>
#include <linux/mmc/host.h>
@ -28,7 +30,35 @@
#define AO_SCTRL_SEL18 BIT(10)
#define AO_SCTRL_CTRL3 0x40C
#define DWMMC_SDIO_ID 2
#define SOC_SCTRL_SCPERCTRL5 (0x314)
#define SDCARD_IO_SEL18 BIT(2)
#define SDCARD_RD_THRESHOLD (512)
#define GENCLK_DIV (7)
#define GPIO_CLK_ENABLE BIT(16)
#define GPIO_CLK_DIV_MASK GENMASK(11, 8)
#define GPIO_USE_SAMPLE_DLY_MASK GENMASK(13, 13)
#define UHS_REG_EXT_SAMPLE_PHASE_MASK GENMASK(20, 16)
#define UHS_REG_EXT_SAMPLE_DRVPHASE_MASK GENMASK(25, 21)
#define UHS_REG_EXT_SAMPLE_DLY_MASK GENMASK(30, 26)
#define TIMING_MODE 3
#define TIMING_CFG_NUM 10
#define NUM_PHASES (40)
#define ENABLE_SHIFT_MIN_SMPL (4)
#define ENABLE_SHIFT_MAX_SMPL (12)
#define USE_DLY_MIN_SMPL (11)
#define USE_DLY_MAX_SMPL (14)
struct k3_priv {
int ctrl_id;
u32 cur_speed;
struct regmap *reg;
};
@ -38,6 +68,41 @@ static unsigned long dw_mci_hi6220_caps[] = {
0
};
struct hs_timing {
u32 drv_phase;
u32 smpl_dly;
u32 smpl_phase_max;
u32 smpl_phase_min;
};
struct hs_timing hs_timing_cfg[TIMING_MODE][TIMING_CFG_NUM] = {
{ /* reserved */ },
{ /* SD */
{7, 0, 15, 15,}, /* 0: LEGACY 400k */
{6, 0, 4, 4,}, /* 1: MMC_HS */
{6, 0, 3, 3,}, /* 2: SD_HS */
{6, 0, 15, 15,}, /* 3: SDR12 */
{6, 0, 2, 2,}, /* 4: SDR25 */
{4, 0, 11, 0,}, /* 5: SDR50 */
{6, 4, 15, 0,}, /* 6: SDR104 */
{0}, /* 7: DDR50 */
{0}, /* 8: DDR52 */
{0}, /* 9: HS200 */
},
{ /* SDIO */
{7, 0, 15, 15,}, /* 0: LEGACY 400k */
{0}, /* 1: MMC_HS */
{6, 0, 15, 15,}, /* 2: SD_HS */
{6, 0, 15, 15,}, /* 3: SDR12 */
{6, 0, 0, 0,}, /* 4: SDR25 */
{4, 0, 12, 0,}, /* 5: SDR50 */
{5, 4, 15, 0,}, /* 6: SDR104 */
{0}, /* 7: DDR50 */
{0}, /* 8: DDR52 */
{0}, /* 9: HS200 */
}
};
static void dw_mci_k3_set_ios(struct dw_mci *host, struct mmc_ios *ios)
{
int ret;
@ -66,6 +131,10 @@ static int dw_mci_hi6220_parse_dt(struct dw_mci *host)
if (IS_ERR(priv->reg))
priv->reg = NULL;
priv->ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
if (priv->ctrl_id < 0)
priv->ctrl_id = 0;
host->priv = priv;
return 0;
}
@ -144,7 +213,236 @@ static const struct dw_mci_drv_data hi6220_data = {
.execute_tuning = dw_mci_hi6220_execute_tuning,
};
static void dw_mci_hs_set_timing(struct dw_mci *host, int timing,
int smpl_phase)
{
u32 drv_phase;
u32 smpl_dly;
u32 use_smpl_dly = 0;
u32 enable_shift = 0;
u32 reg_value;
int ctrl_id;
struct k3_priv *priv;
priv = host->priv;
ctrl_id = priv->ctrl_id;
drv_phase = hs_timing_cfg[ctrl_id][timing].drv_phase;
smpl_dly = hs_timing_cfg[ctrl_id][timing].smpl_dly;
if (smpl_phase == -1)
smpl_phase = (hs_timing_cfg[ctrl_id][timing].smpl_phase_max +
hs_timing_cfg[ctrl_id][timing].smpl_phase_min) / 2;
switch (timing) {
case MMC_TIMING_UHS_SDR104:
if (smpl_phase >= USE_DLY_MIN_SMPL &&
smpl_phase <= USE_DLY_MAX_SMPL)
use_smpl_dly = 1;
/* fallthrough */
case MMC_TIMING_UHS_SDR50:
if (smpl_phase >= ENABLE_SHIFT_MIN_SMPL &&
smpl_phase <= ENABLE_SHIFT_MAX_SMPL)
enable_shift = 1;
break;
}
mci_writel(host, GPIO, 0x0);
usleep_range(5, 10);
reg_value = FIELD_PREP(UHS_REG_EXT_SAMPLE_PHASE_MASK, smpl_phase) |
FIELD_PREP(UHS_REG_EXT_SAMPLE_DLY_MASK, smpl_dly) |
FIELD_PREP(UHS_REG_EXT_SAMPLE_DRVPHASE_MASK, drv_phase);
mci_writel(host, UHS_REG_EXT, reg_value);
mci_writel(host, ENABLE_SHIFT, enable_shift);
reg_value = FIELD_PREP(GPIO_CLK_DIV_MASK, GENCLK_DIV) |
FIELD_PREP(GPIO_USE_SAMPLE_DLY_MASK, use_smpl_dly);
mci_writel(host, GPIO, (unsigned int)reg_value | GPIO_CLK_ENABLE);
/* We should delay 1ms wait for timing setting finished. */
usleep_range(1000, 2000);
}
static int dw_mci_hi3660_init(struct dw_mci *host)
{
mci_writel(host, CDTHRCTL, SDMMC_SET_THLD(SDCARD_RD_THRESHOLD,
SDMMC_CARD_RD_THR_EN));
dw_mci_hs_set_timing(host, MMC_TIMING_LEGACY, -1);
host->bus_hz /= (GENCLK_DIV + 1);
return 0;
}
static int dw_mci_set_sel18(struct dw_mci *host, bool set)
{
int ret;
unsigned int val;
struct k3_priv *priv;
priv = host->priv;
val = set ? SDCARD_IO_SEL18 : 0;
ret = regmap_update_bits(priv->reg, SOC_SCTRL_SCPERCTRL5,
SDCARD_IO_SEL18, val);
if (ret) {
dev_err(host->dev, "sel18 %u error\n", val);
return ret;
}
return 0;
}
static void dw_mci_hi3660_set_ios(struct dw_mci *host, struct mmc_ios *ios)
{
int ret;
unsigned long wanted;
unsigned long actual;
struct k3_priv *priv = host->priv;
if (!ios->clock || ios->clock == priv->cur_speed)
return;
wanted = ios->clock * (GENCLK_DIV + 1);
ret = clk_set_rate(host->ciu_clk, wanted);
if (ret) {
dev_err(host->dev, "failed to set rate %luHz\n", wanted);
return;
}
actual = clk_get_rate(host->ciu_clk);
dw_mci_hs_set_timing(host, ios->timing, -1);
host->bus_hz = actual / (GENCLK_DIV + 1);
host->current_speed = 0;
priv->cur_speed = host->bus_hz;
}
static int dw_mci_get_best_clksmpl(unsigned int sample_flag)
{
int i;
int interval;
unsigned int v;
unsigned int len;
unsigned int range_start = 0;
unsigned int range_length = 0;
unsigned int middle_range = 0;
if (!sample_flag)
return -EIO;
if (~sample_flag == 0)
return 0;
i = ffs(sample_flag) - 1;
/*
* A clock cycle is divided into 32 phases,
* each of which is represented by a bit,
* finding the optimal phase.
*/
while (i < 32) {
v = ror32(sample_flag, i);
len = ffs(~v) - 1;
if (len > range_length) {
range_length = len;
range_start = i;
}
interval = ffs(v >> len) - 1;
if (interval < 0)
break;
i += len + interval;
}
middle_range = range_start + range_length / 2;
if (middle_range >= 32)
middle_range %= 32;
return middle_range;
}
static int dw_mci_hi3660_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
{
int i = 0;
struct dw_mci *host = slot->host;
struct mmc_host *mmc = slot->mmc;
int smpl_phase = 0;
u32 tuning_sample_flag = 0;
int best_clksmpl = 0;
for (i = 0; i < NUM_PHASES; ++i, ++smpl_phase) {
smpl_phase %= 32;
mci_writel(host, TMOUT, ~0);
dw_mci_hs_set_timing(host, mmc->ios.timing, smpl_phase);
if (!mmc_send_tuning(mmc, opcode, NULL))
tuning_sample_flag |= (1 << smpl_phase);
else
tuning_sample_flag &= ~(1 << smpl_phase);
}
best_clksmpl = dw_mci_get_best_clksmpl(tuning_sample_flag);
if (best_clksmpl < 0) {
dev_err(host->dev, "All phases bad!\n");
return -EIO;
}
dw_mci_hs_set_timing(host, mmc->ios.timing, best_clksmpl);
dev_info(host->dev, "tuning ok best_clksmpl %u tuning_sample_flag %x\n",
best_clksmpl, tuning_sample_flag);
return 0;
}
static int dw_mci_hi3660_switch_voltage(struct mmc_host *mmc,
struct mmc_ios *ios)
{
int ret = 0;
struct dw_mci_slot *slot = mmc_priv(mmc);
struct k3_priv *priv;
struct dw_mci *host;
host = slot->host;
priv = host->priv;
if (!priv || !priv->reg)
return 0;
if (priv->ctrl_id == DWMMC_SDIO_ID)
return 0;
if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330)
ret = dw_mci_set_sel18(host, 0);
else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180)
ret = dw_mci_set_sel18(host, 1);
if (ret)
return ret;
if (!IS_ERR(mmc->supply.vqmmc)) {
ret = mmc_regulator_set_vqmmc(mmc, ios);
if (ret) {
dev_err(host->dev, "Regulator set error %d\n", ret);
return ret;
}
}
return 0;
}
static const struct dw_mci_drv_data hi3660_data = {
.init = dw_mci_hi3660_init,
.set_ios = dw_mci_hi3660_set_ios,
.parse_dt = dw_mci_hi6220_parse_dt,
.execute_tuning = dw_mci_hi3660_execute_tuning,
.switch_voltage = dw_mci_hi3660_switch_voltage,
};
static const struct of_device_id dw_mci_k3_match[] = {
{ .compatible = "hisilicon,hi3660-dw-mshc", .data = &hi3660_data, },
{ .compatible = "hisilicon,hi4511-dw-mshc", .data = &k3_drv_data, },
{ .compatible = "hisilicon,hi6220-dw-mshc", .data = &hi6220_data, },
{},

View File

@ -398,6 +398,21 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd)
return cmdr;
}
static inline void dw_mci_set_cto(struct dw_mci *host)
{
unsigned int cto_clks;
unsigned int cto_ms;
cto_clks = mci_readl(host, TMOUT) & 0xff;
cto_ms = DIV_ROUND_UP(cto_clks, host->bus_hz / 1000);
/* add a bit spare time */
cto_ms += 10;
mod_timer(&host->cto_timer,
jiffies + msecs_to_jiffies(cto_ms) + 1);
}
static void dw_mci_start_command(struct dw_mci *host,
struct mmc_command *cmd, u32 cmd_flags)
{
@ -410,6 +425,10 @@ static void dw_mci_start_command(struct dw_mci *host,
wmb(); /* drain writebuffer */
dw_mci_wait_while_busy(host, cmd_flags);
/* response expected command only */
if (cmd_flags & SDMMC_CMD_RESP_EXP)
dw_mci_set_cto(host);
mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
}
@ -2599,6 +2618,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
}
if (pending & DW_MCI_CMD_ERROR_FLAGS) {
del_timer(&host->cto_timer);
mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
host->cmd_status = pending;
smp_wmb(); /* drain writebuffer */
@ -2642,6 +2662,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
}
if (pending & SDMMC_INT_CMD_DONE) {
del_timer(&host->cto_timer);
mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE);
dw_mci_cmd_interrupt(host, pending);
}
@ -2914,6 +2935,30 @@ static void dw_mci_cmd11_timer(unsigned long arg)
tasklet_schedule(&host->tasklet);
}
static void dw_mci_cto_timer(unsigned long arg)
{
struct dw_mci *host = (struct dw_mci *)arg;
switch (host->state) {
case STATE_SENDING_CMD11:
case STATE_SENDING_CMD:
case STATE_SENDING_STOP:
/*
* If CMD_DONE interrupt does NOT come in sending command
* state, we should notify the driver to terminate current
* transfer and report a command timeout to the core.
*/
host->cmd_status = SDMMC_INT_RTO;
set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
tasklet_schedule(&host->tasklet);
break;
default:
dev_warn(host->dev, "Unexpected command timeout, state %d\n",
host->state);
break;
}
}
static void dw_mci_dto_timer(unsigned long arg)
{
struct dw_mci *host = (struct dw_mci *)arg;
@ -2950,7 +2995,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
return ERR_PTR(-ENOMEM);
/* find reset controller when exist */
pdata->rstc = devm_reset_control_get_optional(dev, "reset");
pdata->rstc = devm_reset_control_get_optional_exclusive(dev, "reset");
if (IS_ERR(pdata->rstc)) {
if (PTR_ERR(pdata->rstc) == -EPROBE_DEFER)
return ERR_PTR(-EPROBE_DEFER);
@ -3067,6 +3112,12 @@ int dw_mci_probe(struct dw_mci *host)
goto err_clk_ciu;
}
if (!IS_ERR(host->pdata->rstc)) {
reset_control_assert(host->pdata->rstc);
usleep_range(10, 50);
reset_control_deassert(host->pdata->rstc);
}
if (drv_data && drv_data->init) {
ret = drv_data->init(host);
if (ret) {
@ -3076,15 +3127,12 @@ int dw_mci_probe(struct dw_mci *host)
}
}
if (!IS_ERR(host->pdata->rstc)) {
reset_control_assert(host->pdata->rstc);
usleep_range(10, 50);
reset_control_deassert(host->pdata->rstc);
}
setup_timer(&host->cmd11_timer,
dw_mci_cmd11_timer, (unsigned long)host);
setup_timer(&host->cto_timer,
dw_mci_cto_timer, (unsigned long)host);
setup_timer(&host->dto_timer,
dw_mci_dto_timer, (unsigned long)host);

View File

@ -126,6 +126,7 @@ struct dw_mci_dma_slave {
* @irq: The irq value to be passed to request_irq.
* @sdio_id0: Number of slot0 in the SDIO interrupt registers.
* @cmd11_timer: Timer for SD3.0 voltage switch over scheme.
* @cto_timer: Timer for broken command transfer over scheme.
* @dto_timer: Timer for broken data transfer over scheme.
*
* Locking
@ -232,6 +233,7 @@ struct dw_mci {
int sdio_id0;
struct timer_list cmd11_timer;
struct timer_list cto_timer;
struct timer_list dto_timer;
};
@ -314,6 +316,8 @@ struct dw_mci_board {
#define SDMMC_DSCADDR 0x094
#define SDMMC_BUFADDR 0x098
#define SDMMC_CDTHRCTL 0x100
#define SDMMC_UHS_REG_EXT 0x108
#define SDMMC_ENABLE_SHIFT 0x110
#define SDMMC_DATA(x) (x)
/*
* Registers to support idmac 64-bit address mode

View File

@ -42,22 +42,18 @@
#define SD_EMMC_CLOCK 0x0
#define CLK_DIV_MASK GENMASK(5, 0)
#define CLK_DIV_MAX 63
#define CLK_SRC_MASK GENMASK(7, 6)
#define CLK_SRC_XTAL 0 /* external crystal */
#define CLK_SRC_XTAL_RATE 24000000
#define CLK_SRC_PLL 1 /* FCLK_DIV2 */
#define CLK_SRC_PLL_RATE 1000000000
#define CLK_CORE_PHASE_MASK GENMASK(9, 8)
#define CLK_TX_PHASE_MASK GENMASK(11, 10)
#define CLK_RX_PHASE_MASK GENMASK(13, 12)
#define CLK_PHASE_0 0
#define CLK_PHASE_90 1
#define CLK_PHASE_180 2
#define CLK_PHASE_270 3
#define CLK_TX_DELAY_MASK GENMASK(19, 16)
#define CLK_RX_DELAY_MASK GENMASK(23, 20)
#define CLK_DELAY_STEP_PS 200
#define CLK_PHASE_STEP 30
#define CLK_PHASE_POINT_NUM (360 / CLK_PHASE_STEP)
#define CLK_ALWAYS_ON BIT(24)
#define SD_EMMC_DElAY 0x4
#define SD_EMMC_DELAY 0x4
#define SD_EMMC_ADJUST 0x8
#define SD_EMMC_CALOUT 0x10
#define SD_EMMC_START 0x40
@ -81,18 +77,25 @@
#define SD_EMMC_STATUS 0x48
#define STATUS_BUSY BIT(31)
#define STATUS_DATI GENMASK(23, 16)
#define SD_EMMC_IRQ_EN 0x4c
#define IRQ_EN_MASK GENMASK(13, 0)
#define IRQ_RXD_ERR_MASK GENMASK(7, 0)
#define IRQ_TXD_ERR BIT(8)
#define IRQ_DESC_ERR BIT(9)
#define IRQ_RESP_ERR BIT(10)
#define IRQ_CRC_ERR \
(IRQ_RXD_ERR_MASK | IRQ_TXD_ERR | IRQ_DESC_ERR | IRQ_RESP_ERR)
#define IRQ_RESP_TIMEOUT BIT(11)
#define IRQ_DESC_TIMEOUT BIT(12)
#define IRQ_TIMEOUTS \
(IRQ_RESP_TIMEOUT | IRQ_DESC_TIMEOUT)
#define IRQ_END_OF_CHAIN BIT(13)
#define IRQ_RESP_STATUS BIT(14)
#define IRQ_SDIO BIT(15)
#define IRQ_EN_MASK \
(IRQ_CRC_ERR | IRQ_TIMEOUTS | IRQ_END_OF_CHAIN | IRQ_RESP_STATUS |\
IRQ_SDIO)
#define SD_EMMC_CMD_CFG 0x50
#define SD_EMMC_CMD_ARG 0x54
@ -118,12 +121,6 @@
#define MUX_CLK_NUM_PARENTS 2
struct meson_tuning_params {
u8 core_phase;
u8 tx_phase;
u8 rx_phase;
};
struct sd_emmc_desc {
u32 cmd_cfg;
u32 cmd_arg;
@ -139,12 +136,14 @@ struct meson_host {
spinlock_t lock;
void __iomem *regs;
struct clk *core_clk;
struct clk_mux mux;
struct clk *mux_clk;
unsigned long current_clock;
struct clk *mmc_clk;
struct clk *rx_clk;
struct clk *tx_clk;
unsigned long req_rate;
struct clk_divider cfg_div;
struct clk *cfg_div_clk;
struct pinctrl *pinctrl;
struct pinctrl_state *pins_default;
struct pinctrl_state *pins_clk_gate;
unsigned int bounce_buf_size;
void *bounce_buf;
@ -152,7 +151,6 @@ struct meson_host {
struct sd_emmc_desc *descs;
dma_addr_t descs_dma_addr;
struct meson_tuning_params tp;
bool vqmmc_enabled;
};
@ -179,6 +177,90 @@ struct meson_host {
#define CMD_RESP_MASK GENMASK(31, 1)
#define CMD_RESP_SRAM BIT(0)
struct meson_mmc_phase {
struct clk_hw hw;
void __iomem *reg;
unsigned long phase_mask;
unsigned long delay_mask;
unsigned int delay_step_ps;
};
#define to_meson_mmc_phase(_hw) container_of(_hw, struct meson_mmc_phase, hw)
static int meson_mmc_clk_get_phase(struct clk_hw *hw)
{
struct meson_mmc_phase *mmc = to_meson_mmc_phase(hw);
unsigned int phase_num = 1 << hweight_long(mmc->phase_mask);
unsigned long period_ps, p, d;
int degrees;
u32 val;
val = readl(mmc->reg);
p = (val & mmc->phase_mask) >> __ffs(mmc->phase_mask);
degrees = p * 360 / phase_num;
if (mmc->delay_mask) {
period_ps = DIV_ROUND_UP((unsigned long)NSEC_PER_SEC * 1000,
clk_get_rate(hw->clk));
d = (val & mmc->delay_mask) >> __ffs(mmc->delay_mask);
degrees += d * mmc->delay_step_ps * 360 / period_ps;
degrees %= 360;
}
return degrees;
}
static void meson_mmc_apply_phase_delay(struct meson_mmc_phase *mmc,
unsigned int phase,
unsigned int delay)
{
u32 val;
val = readl(mmc->reg);
val &= ~mmc->phase_mask;
val |= phase << __ffs(mmc->phase_mask);
if (mmc->delay_mask) {
val &= ~mmc->delay_mask;
val |= delay << __ffs(mmc->delay_mask);
}
writel(val, mmc->reg);
}
static int meson_mmc_clk_set_phase(struct clk_hw *hw, int degrees)
{
struct meson_mmc_phase *mmc = to_meson_mmc_phase(hw);
unsigned int phase_num = 1 << hweight_long(mmc->phase_mask);
unsigned long period_ps, d = 0, r;
uint64_t p;
p = degrees % 360;
if (!mmc->delay_mask) {
p = DIV_ROUND_CLOSEST_ULL(p, 360 / phase_num);
} else {
period_ps = DIV_ROUND_UP((unsigned long)NSEC_PER_SEC * 1000,
clk_get_rate(hw->clk));
/* First compute the phase index (p), the remainder (r) is the
* part we'll try to acheive using the delays (d).
*/
r = do_div(p, 360 / phase_num);
d = DIV_ROUND_CLOSEST(r * period_ps,
360 * mmc->delay_step_ps);
d = min(d, mmc->delay_mask >> __ffs(mmc->delay_mask));
}
meson_mmc_apply_phase_delay(mmc, p, d);
return 0;
}
static const struct clk_ops meson_mmc_clk_phase_ops = {
.get_phase = meson_mmc_clk_get_phase,
.set_phase = meson_mmc_clk_set_phase,
};
static unsigned int meson_mmc_get_timeout_msecs(struct mmc_data *data)
{
unsigned int timeout = data->timeout_ns / NSEC_PER_MSEC;
@ -271,58 +353,102 @@ static void meson_mmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
mmc_get_dma_dir(data));
}
static int meson_mmc_clk_set(struct meson_host *host, unsigned long clk_rate)
static bool meson_mmc_timing_is_ddr(struct mmc_ios *ios)
{
if (ios->timing == MMC_TIMING_MMC_DDR52 ||
ios->timing == MMC_TIMING_UHS_DDR50 ||
ios->timing == MMC_TIMING_MMC_HS400)
return true;
return false;
}
/*
* Gating the clock on this controller is tricky. It seems the mmc clock
* is also used by the controller. It may crash during some operation if the
* clock is stopped. The safest thing to do, whenever possible, is to keep
* clock running at stop it at the pad using the pinmux.
*/
static void meson_mmc_clk_gate(struct meson_host *host)
{
struct mmc_host *mmc = host->mmc;
int ret;
u32 cfg;
if (clk_rate) {
if (WARN_ON(clk_rate > mmc->f_max))
clk_rate = mmc->f_max;
else if (WARN_ON(clk_rate < mmc->f_min))
clk_rate = mmc->f_min;
}
if (clk_rate == host->current_clock)
return 0;
/* stop clock */
if (host->pins_clk_gate) {
pinctrl_select_state(host->pinctrl, host->pins_clk_gate);
} else {
/*
* If the pinmux is not provided - default to the classic and
* unsafe method
*/
cfg = readl(host->regs + SD_EMMC_CFG);
if (!(cfg & CFG_STOP_CLOCK)) {
cfg |= CFG_STOP_CLOCK;
writel(cfg, host->regs + SD_EMMC_CFG);
}
}
dev_dbg(host->dev, "change clock rate %u -> %lu\n",
mmc->actual_clock, clk_rate);
static void meson_mmc_clk_ungate(struct meson_host *host)
{
u32 cfg;
if (!clk_rate) {
if (host->pins_clk_gate)
pinctrl_select_state(host->pinctrl, host->pins_default);
/* Make sure the clock is not stopped in the controller */
cfg = readl(host->regs + SD_EMMC_CFG);
cfg &= ~CFG_STOP_CLOCK;
writel(cfg, host->regs + SD_EMMC_CFG);
}
static int meson_mmc_clk_set(struct meson_host *host, struct mmc_ios *ios)
{
struct mmc_host *mmc = host->mmc;
unsigned long rate = ios->clock;
int ret;
u32 cfg;
/* DDR modes require higher module clock */
if (meson_mmc_timing_is_ddr(ios))
rate <<= 1;
/* Same request - bail-out */
if (host->req_rate == rate)
return 0;
/* stop clock */
meson_mmc_clk_gate(host);
host->req_rate = 0;
if (!rate) {
mmc->actual_clock = 0;
host->current_clock = 0;
/* return with clock being stopped */
return 0;
}
ret = clk_set_rate(host->cfg_div_clk, clk_rate);
/* Stop the clock during rate change to avoid glitches */
cfg = readl(host->regs + SD_EMMC_CFG);
cfg |= CFG_STOP_CLOCK;
writel(cfg, host->regs + SD_EMMC_CFG);
ret = clk_set_rate(host->mmc_clk, rate);
if (ret) {
dev_err(host->dev, "Unable to set cfg_div_clk to %lu. ret=%d\n",
clk_rate, ret);
rate, ret);
return ret;
}
mmc->actual_clock = clk_get_rate(host->cfg_div_clk);
host->current_clock = clk_rate;
host->req_rate = rate;
mmc->actual_clock = clk_get_rate(host->mmc_clk);
if (clk_rate != mmc->actual_clock)
dev_dbg(host->dev,
"divider requested rate %lu != actual rate %u\n",
clk_rate, mmc->actual_clock);
/* We should report the real output frequency of the controller */
if (meson_mmc_timing_is_ddr(ios))
mmc->actual_clock >>= 1;
dev_dbg(host->dev, "clk rate: %u Hz\n", mmc->actual_clock);
if (ios->clock != mmc->actual_clock)
dev_dbg(host->dev, "requested rate was %u\n", ios->clock);
/* (re)start clock */
cfg = readl(host->regs + SD_EMMC_CFG);
cfg &= ~CFG_STOP_CLOCK;
writel(cfg, host->regs + SD_EMMC_CFG);
meson_mmc_clk_ungate(host);
return 0;
}
@ -335,11 +461,21 @@ static int meson_mmc_clk_set(struct meson_host *host, unsigned long clk_rate)
static int meson_mmc_clk_init(struct meson_host *host)
{
struct clk_init_data init;
struct clk_mux *mux;
struct clk_divider *div;
struct meson_mmc_phase *core, *tx, *rx;
struct clk *clk;
char clk_name[32];
int i, ret = 0;
const char *mux_parent_names[MUX_CLK_NUM_PARENTS];
const char *clk_div_parents[1];
u32 clk_reg, cfg;
const char *clk_parent[1];
u32 clk_reg;
/* init SD_EMMC_CLOCK to sane defaults w/min clock rate */
clk_reg = 0;
clk_reg |= CLK_ALWAYS_ON;
clk_reg |= CLK_DIV_MASK;
writel(clk_reg, host->regs + SD_EMMC_CLOCK);
/* get the mux parents */
for (i = 0; i < MUX_CLK_NUM_PARENTS; i++) {
@ -358,103 +494,238 @@ static int meson_mmc_clk_init(struct meson_host *host)
}
/* create the mux */
mux = devm_kzalloc(host->dev, sizeof(*mux), GFP_KERNEL);
if (!mux)
return -ENOMEM;
snprintf(clk_name, sizeof(clk_name), "%s#mux", dev_name(host->dev));
init.name = clk_name;
init.ops = &clk_mux_ops;
init.flags = 0;
init.parent_names = mux_parent_names;
init.num_parents = MUX_CLK_NUM_PARENTS;
host->mux.reg = host->regs + SD_EMMC_CLOCK;
host->mux.shift = __bf_shf(CLK_SRC_MASK);
host->mux.mask = CLK_SRC_MASK;
host->mux.flags = 0;
host->mux.table = NULL;
host->mux.hw.init = &init;
host->mux_clk = devm_clk_register(host->dev, &host->mux.hw);
if (WARN_ON(IS_ERR(host->mux_clk)))
return PTR_ERR(host->mux_clk);
mux->reg = host->regs + SD_EMMC_CLOCK;
mux->shift = __ffs(CLK_SRC_MASK);
mux->mask = CLK_SRC_MASK >> mux->shift;
mux->hw.init = &init;
clk = devm_clk_register(host->dev, &mux->hw);
if (WARN_ON(IS_ERR(clk)))
return PTR_ERR(clk);
/* create the divider */
div = devm_kzalloc(host->dev, sizeof(*div), GFP_KERNEL);
if (!div)
return -ENOMEM;
snprintf(clk_name, sizeof(clk_name), "%s#div", dev_name(host->dev));
init.name = clk_name;
init.ops = &clk_divider_ops;
init.flags = CLK_SET_RATE_PARENT;
clk_div_parents[0] = __clk_get_name(host->mux_clk);
init.parent_names = clk_div_parents;
init.num_parents = ARRAY_SIZE(clk_div_parents);
clk_parent[0] = __clk_get_name(clk);
init.parent_names = clk_parent;
init.num_parents = 1;
host->cfg_div.reg = host->regs + SD_EMMC_CLOCK;
host->cfg_div.shift = __bf_shf(CLK_DIV_MASK);
host->cfg_div.width = __builtin_popcountl(CLK_DIV_MASK);
host->cfg_div.hw.init = &init;
host->cfg_div.flags = CLK_DIVIDER_ONE_BASED |
CLK_DIVIDER_ROUND_CLOSEST | CLK_DIVIDER_ALLOW_ZERO;
div->reg = host->regs + SD_EMMC_CLOCK;
div->shift = __ffs(CLK_DIV_MASK);
div->width = __builtin_popcountl(CLK_DIV_MASK);
div->hw.init = &init;
div->flags = (CLK_DIVIDER_ONE_BASED |
CLK_DIVIDER_ROUND_CLOSEST);
host->cfg_div_clk = devm_clk_register(host->dev, &host->cfg_div.hw);
if (WARN_ON(PTR_ERR_OR_ZERO(host->cfg_div_clk)))
return PTR_ERR(host->cfg_div_clk);
clk = devm_clk_register(host->dev, &div->hw);
if (WARN_ON(IS_ERR(clk)))
return PTR_ERR(clk);
/* create the mmc core clock */
core = devm_kzalloc(host->dev, sizeof(*core), GFP_KERNEL);
if (!core)
return -ENOMEM;
snprintf(clk_name, sizeof(clk_name), "%s#core", dev_name(host->dev));
init.name = clk_name;
init.ops = &meson_mmc_clk_phase_ops;
init.flags = CLK_SET_RATE_PARENT;
clk_parent[0] = __clk_get_name(clk);
init.parent_names = clk_parent;
init.num_parents = 1;
core->reg = host->regs + SD_EMMC_CLOCK;
core->phase_mask = CLK_CORE_PHASE_MASK;
core->hw.init = &init;
host->mmc_clk = devm_clk_register(host->dev, &core->hw);
if (WARN_ON(PTR_ERR_OR_ZERO(host->mmc_clk)))
return PTR_ERR(host->mmc_clk);
/* create the mmc tx clock */
tx = devm_kzalloc(host->dev, sizeof(*tx), GFP_KERNEL);
if (!tx)
return -ENOMEM;
snprintf(clk_name, sizeof(clk_name), "%s#tx", dev_name(host->dev));
init.name = clk_name;
init.ops = &meson_mmc_clk_phase_ops;
init.flags = 0;
clk_parent[0] = __clk_get_name(host->mmc_clk);
init.parent_names = clk_parent;
init.num_parents = 1;
tx->reg = host->regs + SD_EMMC_CLOCK;
tx->phase_mask = CLK_TX_PHASE_MASK;
tx->delay_mask = CLK_TX_DELAY_MASK;
tx->delay_step_ps = CLK_DELAY_STEP_PS;
tx->hw.init = &init;
host->tx_clk = devm_clk_register(host->dev, &tx->hw);
if (WARN_ON(PTR_ERR_OR_ZERO(host->tx_clk)))
return PTR_ERR(host->tx_clk);
/* create the mmc rx clock */
rx = devm_kzalloc(host->dev, sizeof(*rx), GFP_KERNEL);
if (!rx)
return -ENOMEM;
snprintf(clk_name, sizeof(clk_name), "%s#rx", dev_name(host->dev));
init.name = clk_name;
init.ops = &meson_mmc_clk_phase_ops;
init.flags = 0;
clk_parent[0] = __clk_get_name(host->mmc_clk);
init.parent_names = clk_parent;
init.num_parents = 1;
rx->reg = host->regs + SD_EMMC_CLOCK;
rx->phase_mask = CLK_RX_PHASE_MASK;
rx->delay_mask = CLK_RX_DELAY_MASK;
rx->delay_step_ps = CLK_DELAY_STEP_PS;
rx->hw.init = &init;
host->rx_clk = devm_clk_register(host->dev, &rx->hw);
if (WARN_ON(PTR_ERR_OR_ZERO(host->rx_clk)))
return PTR_ERR(host->rx_clk);
/* init SD_EMMC_CLOCK to sane defaults w/min clock rate */
clk_reg = 0;
clk_reg |= FIELD_PREP(CLK_CORE_PHASE_MASK, host->tp.core_phase);
clk_reg |= FIELD_PREP(CLK_TX_PHASE_MASK, host->tp.tx_phase);
clk_reg |= FIELD_PREP(CLK_RX_PHASE_MASK, host->tp.rx_phase);
clk_reg |= FIELD_PREP(CLK_SRC_MASK, CLK_SRC_XTAL);
clk_reg |= FIELD_PREP(CLK_DIV_MASK, CLK_DIV_MAX);
clk_reg &= ~CLK_ALWAYS_ON;
writel(clk_reg, host->regs + SD_EMMC_CLOCK);
/* Ensure clock starts in "auto" mode, not "always on" */
cfg = readl(host->regs + SD_EMMC_CFG);
cfg &= ~CFG_CLK_ALWAYS_ON;
cfg |= CFG_AUTO_CLK;
writel(cfg, host->regs + SD_EMMC_CFG);
ret = clk_prepare_enable(host->cfg_div_clk);
host->mmc->f_min = clk_round_rate(host->mmc_clk, 400000);
ret = clk_set_rate(host->mmc_clk, host->mmc->f_min);
if (ret)
return ret;
/* Get the nearest minimum clock to 400KHz */
host->mmc->f_min = clk_round_rate(host->cfg_div_clk, 400000);
/*
* Set phases : These values are mostly the datasheet recommended ones
* except for the Tx phase. Datasheet recommends 180 but some cards
* fail at initialisation with it. 270 works just fine, it fixes these
* initialisation issues and enable eMMC DDR52 mode.
*/
clk_set_phase(host->mmc_clk, 180);
clk_set_phase(host->tx_clk, 270);
clk_set_phase(host->rx_clk, 0);
ret = meson_mmc_clk_set(host, host->mmc->f_min);
if (ret)
clk_disable_unprepare(host->cfg_div_clk);
return ret;
return clk_prepare_enable(host->mmc_clk);
}
static void meson_mmc_set_tuning_params(struct mmc_host *mmc)
static void meson_mmc_shift_map(unsigned long *map, unsigned long shift)
{
DECLARE_BITMAP(left, CLK_PHASE_POINT_NUM);
DECLARE_BITMAP(right, CLK_PHASE_POINT_NUM);
/*
* shift the bitmap right and reintroduce the dropped bits on the left
* of the bitmap
*/
bitmap_shift_right(right, map, shift, CLK_PHASE_POINT_NUM);
bitmap_shift_left(left, map, CLK_PHASE_POINT_NUM - shift,
CLK_PHASE_POINT_NUM);
bitmap_or(map, left, right, CLK_PHASE_POINT_NUM);
}
static void meson_mmc_find_next_region(unsigned long *map,
unsigned long *start,
unsigned long *stop)
{
*start = find_next_bit(map, CLK_PHASE_POINT_NUM, *start);
*stop = find_next_zero_bit(map, CLK_PHASE_POINT_NUM, *start);
}
static int meson_mmc_find_tuning_point(unsigned long *test)
{
unsigned long shift, stop, offset = 0, start = 0, size = 0;
/* Get the all good/all bad situation out the way */
if (bitmap_full(test, CLK_PHASE_POINT_NUM))
return 0; /* All points are good so point 0 will do */
else if (bitmap_empty(test, CLK_PHASE_POINT_NUM))
return -EIO; /* No successful tuning point */
/*
* Now we know there is a least one region find. Make sure it does
* not wrap by the shifting the bitmap if necessary
*/
shift = find_first_zero_bit(test, CLK_PHASE_POINT_NUM);
if (shift != 0)
meson_mmc_shift_map(test, shift);
while (start < CLK_PHASE_POINT_NUM) {
meson_mmc_find_next_region(test, &start, &stop);
if ((stop - start) > size) {
offset = start;
size = stop - start;
}
start = stop;
}
/* Get the center point of the region */
offset += (size / 2);
/* Shift the result back */
offset = (offset + shift) % CLK_PHASE_POINT_NUM;
return offset;
}
static int meson_mmc_clk_phase_tuning(struct mmc_host *mmc, u32 opcode,
struct clk *clk)
{
int point, ret;
DECLARE_BITMAP(test, CLK_PHASE_POINT_NUM);
dev_dbg(mmc_dev(mmc), "%s phase/delay tunning...\n",
__clk_get_name(clk));
bitmap_zero(test, CLK_PHASE_POINT_NUM);
/* Explore tuning points */
for (point = 0; point < CLK_PHASE_POINT_NUM; point++) {
clk_set_phase(clk, point * CLK_PHASE_STEP);
ret = mmc_send_tuning(mmc, opcode, NULL);
if (!ret)
set_bit(point, test);
}
/* Find the optimal tuning point and apply it */
point = meson_mmc_find_tuning_point(test);
if (point < 0)
return point; /* tuning failed */
clk_set_phase(clk, point * CLK_PHASE_STEP);
dev_dbg(mmc_dev(mmc), "success with phase: %d\n",
clk_get_phase(clk));
return 0;
}
static int meson_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
struct meson_host *host = mmc_priv(mmc);
u32 regval;
/* stop clock */
regval = readl(host->regs + SD_EMMC_CFG);
regval |= CFG_STOP_CLOCK;
writel(regval, host->regs + SD_EMMC_CFG);
regval = readl(host->regs + SD_EMMC_CLOCK);
regval &= ~CLK_CORE_PHASE_MASK;
regval |= FIELD_PREP(CLK_CORE_PHASE_MASK, host->tp.core_phase);
regval &= ~CLK_TX_PHASE_MASK;
regval |= FIELD_PREP(CLK_TX_PHASE_MASK, host->tp.tx_phase);
regval &= ~CLK_RX_PHASE_MASK;
regval |= FIELD_PREP(CLK_RX_PHASE_MASK, host->tp.rx_phase);
writel(regval, host->regs + SD_EMMC_CLOCK);
/* start clock */
regval = readl(host->regs + SD_EMMC_CFG);
regval &= ~CFG_STOP_CLOCK;
writel(regval, host->regs + SD_EMMC_CFG);
return meson_mmc_clk_phase_tuning(mmc, opcode, host->rx_clk);
}
static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct meson_host *host = mmc_priv(mmc);
u32 bus_width;
u32 val, orig;
u32 bus_width, val;
int err;
/*
* GPIO regulator, only controls switching between 1v8 and
@ -482,18 +753,17 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
int ret = regulator_enable(mmc->supply.vqmmc);
if (ret < 0)
dev_err(mmc_dev(mmc),
dev_err(host->dev,
"failed to enable vqmmc regulator\n");
else
host->vqmmc_enabled = true;
}
/* Reset rx phase */
clk_set_phase(host->rx_clk, 0);
break;
}
meson_mmc_clk_set(host, ios->clock);
/* Bus width */
switch (ios->bus_width) {
case MMC_BUS_WIDTH_1:
@ -512,26 +782,23 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
}
val = readl(host->regs + SD_EMMC_CFG);
orig = val;
val &= ~CFG_BUS_WIDTH_MASK;
val |= FIELD_PREP(CFG_BUS_WIDTH_MASK, bus_width);
val &= ~CFG_DDR;
if (ios->timing == MMC_TIMING_UHS_DDR50 ||
ios->timing == MMC_TIMING_MMC_DDR52 ||
ios->timing == MMC_TIMING_MMC_HS400)
if (meson_mmc_timing_is_ddr(ios))
val |= CFG_DDR;
val &= ~CFG_CHK_DS;
if (ios->timing == MMC_TIMING_MMC_HS400)
val |= CFG_CHK_DS;
if (val != orig) {
err = meson_mmc_clk_set(host, ios);
if (err)
dev_err(host->dev, "Failed to set clock: %d\n,", err);
writel(val, host->regs + SD_EMMC_CFG);
dev_dbg(host->dev, "%s: SD_EMMC_CFG: 0x%08x -> 0x%08x\n",
__func__, orig, val);
}
dev_dbg(host->dev, "SD_EMMC_CFG: 0x%08x\n", val);
}
static void meson_mmc_request_done(struct mmc_host *mmc,
@ -729,57 +996,40 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id)
struct mmc_command *cmd;
struct mmc_data *data;
u32 irq_en, status, raw_status;
irqreturn_t ret = IRQ_HANDLED;
irqreturn_t ret = IRQ_NONE;
if (WARN_ON(!host))
if (WARN_ON(!host) || WARN_ON(!host->cmd))
return IRQ_NONE;
cmd = host->cmd;
if (WARN_ON(!cmd))
return IRQ_NONE;
data = cmd->data;
spin_lock(&host->lock);
cmd = host->cmd;
data = cmd->data;
irq_en = readl(host->regs + SD_EMMC_IRQ_EN);
raw_status = readl(host->regs + SD_EMMC_STATUS);
status = raw_status & irq_en;
if (!status) {
dev_warn(host->dev, "Spurious IRQ! status=0x%08x, irq_en=0x%08x\n",
raw_status, irq_en);
ret = IRQ_NONE;
cmd->error = 0;
if (status & IRQ_CRC_ERR) {
dev_dbg(host->dev, "CRC Error - status 0x%08x\n", status);
cmd->error = -EILSEQ;
ret = IRQ_HANDLED;
goto out;
}
if (status & IRQ_TIMEOUTS) {
dev_dbg(host->dev, "Timeout - status 0x%08x\n", status);
cmd->error = -ETIMEDOUT;
ret = IRQ_HANDLED;
goto out;
}
meson_mmc_read_resp(host->mmc, cmd);
cmd->error = 0;
if (status & IRQ_RXD_ERR_MASK) {
dev_dbg(host->dev, "Unhandled IRQ: RXD error\n");
cmd->error = -EILSEQ;
if (status & IRQ_SDIO) {
dev_dbg(host->dev, "IRQ: SDIO TODO.\n");
ret = IRQ_HANDLED;
}
if (status & IRQ_TXD_ERR) {
dev_dbg(host->dev, "Unhandled IRQ: TXD error\n");
cmd->error = -EILSEQ;
}
if (status & IRQ_DESC_ERR)
dev_dbg(host->dev, "Unhandled IRQ: Descriptor error\n");
if (status & IRQ_RESP_ERR) {
dev_dbg(host->dev, "Unhandled IRQ: Response error\n");
cmd->error = -EILSEQ;
}
if (status & IRQ_RESP_TIMEOUT) {
dev_dbg(host->dev, "Unhandled IRQ: Response timeout\n");
cmd->error = -ETIMEDOUT;
}
if (status & IRQ_DESC_TIMEOUT) {
dev_dbg(host->dev, "Unhandled IRQ: Descriptor timeout\n");
cmd->error = -ETIMEDOUT;
}
if (status & IRQ_SDIO)
dev_dbg(host->dev, "Unhandled IRQ: SDIO.\n");
if (status & (IRQ_END_OF_CHAIN | IRQ_RESP_STATUS)) {
if (data && !cmd->error)
@ -787,26 +1037,20 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id)
if (meson_mmc_bounce_buf_read(data) ||
meson_mmc_get_next_command(cmd))
ret = IRQ_WAKE_THREAD;
} else {
dev_warn(host->dev, "Unknown IRQ! status=0x%04x: MMC CMD%u arg=0x%08x flags=0x%08x stop=%d\n",
status, cmd->opcode, cmd->arg,
cmd->flags, cmd->mrq->stop ? 1 : 0);
if (cmd->data) {
struct mmc_data *data = cmd->data;
dev_warn(host->dev, "\tblksz %u blocks %u flags 0x%08x (%s%s)",
data->blksz, data->blocks, data->flags,
data->flags & MMC_DATA_WRITE ? "write" : "",
data->flags & MMC_DATA_READ ? "read" : "");
}
else
ret = IRQ_HANDLED;
}
out:
/* ack all (enabled) interrupts */
writel(status, host->regs + SD_EMMC_STATUS);
/* ack all enabled interrupts */
writel(irq_en, host->regs + SD_EMMC_STATUS);
if (ret == IRQ_HANDLED)
meson_mmc_request_done(host->mmc, cmd->mrq);
else if (ret == IRQ_NONE)
dev_warn(host->dev,
"Unexpected IRQ! status=0x%08x, irq_en=0x%08x\n",
raw_status, irq_en);
spin_unlock(&host->lock);
return ret;
@ -839,29 +1083,6 @@ static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id)
return IRQ_HANDLED;
}
static int meson_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
struct meson_host *host = mmc_priv(mmc);
struct meson_tuning_params tp_old = host->tp;
int ret = -EINVAL, i, cmd_error;
dev_info(mmc_dev(mmc), "(re)tuning...\n");
for (i = CLK_PHASE_0; i <= CLK_PHASE_270; i++) {
host->tp.rx_phase = i;
/* exclude the active parameter set if retuning */
if (!memcmp(&tp_old, &host->tp, sizeof(tp_old)) &&
mmc->doing_retune)
continue;
meson_mmc_set_tuning_params(mmc);
ret = mmc_send_tuning(mmc, opcode, &cmd_error);
if (!ret)
break;
}
return ret;
}
/*
* NOTE: we only need this until the GPIO/pinctrl driver can handle
* interrupts. For now, the MMC core will use this for polling.
@ -888,6 +1109,38 @@ static void meson_mmc_cfg_init(struct meson_host *host)
writel(cfg, host->regs + SD_EMMC_CFG);
}
static int meson_mmc_card_busy(struct mmc_host *mmc)
{
struct meson_host *host = mmc_priv(mmc);
u32 regval;
regval = readl(host->regs + SD_EMMC_STATUS);
/* We are only interrested in lines 0 to 3, so mask the other ones */
return !(FIELD_GET(STATUS_DATI, regval) & 0xf);
}
static int meson_mmc_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios)
{
/* vqmmc regulator is available */
if (!IS_ERR(mmc->supply.vqmmc)) {
/*
* The usual amlogic setup uses a GPIO to switch from one
* regulator to the other. While the voltage ramp up is
* pretty fast, care must be taken when switching from 3.3v
* to 1.8v. Please make sure the regulator framework is aware
* of your own regulator constraints
*/
return mmc_regulator_set_vqmmc(mmc, ios);
}
/* no vqmmc regulator, assume fixed regulator at 3/3.3V */
if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330)
return 0;
return -EINVAL;
}
static const struct mmc_host_ops meson_mmc_ops = {
.request = meson_mmc_request,
.set_ios = meson_mmc_set_ios,
@ -895,6 +1148,8 @@ static const struct mmc_host_ops meson_mmc_ops = {
.pre_req = meson_mmc_pre_req,
.post_req = meson_mmc_post_req,
.execute_tuning = meson_mmc_execute_tuning,
.card_busy = meson_mmc_card_busy,
.start_signal_voltage_switch = meson_mmc_voltage_switch,
};
static int meson_mmc_probe(struct platform_device *pdev)
@ -941,6 +1196,27 @@ static int meson_mmc_probe(struct platform_device *pdev)
goto free_host;
}
host->pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(host->pinctrl)) {
ret = PTR_ERR(host->pinctrl);
goto free_host;
}
host->pins_default = pinctrl_lookup_state(host->pinctrl,
PINCTRL_STATE_DEFAULT);
if (IS_ERR(host->pins_default)) {
ret = PTR_ERR(host->pins_default);
goto free_host;
}
host->pins_clk_gate = pinctrl_lookup_state(host->pinctrl,
"clk-gate");
if (IS_ERR(host->pins_clk_gate)) {
dev_warn(&pdev->dev,
"can't get clk-gate pinctrl, using clk_stop bit\n");
host->pins_clk_gate = NULL;
}
host->core_clk = devm_clk_get(&pdev->dev, "core");
if (IS_ERR(host->core_clk)) {
ret = PTR_ERR(host->core_clk);
@ -951,30 +1227,28 @@ static int meson_mmc_probe(struct platform_device *pdev)
if (ret)
goto free_host;
host->tp.core_phase = CLK_PHASE_180;
host->tp.tx_phase = CLK_PHASE_0;
host->tp.rx_phase = CLK_PHASE_0;
ret = meson_mmc_clk_init(host);
if (ret)
goto err_core_clk;
/* set config to sane default */
meson_mmc_cfg_init(host);
/* Stop execution */
writel(0, host->regs + SD_EMMC_START);
/* clear, ack, enable all interrupts */
/* clear, ack and enable interrupts */
writel(0, host->regs + SD_EMMC_IRQ_EN);
writel(IRQ_EN_MASK, host->regs + SD_EMMC_STATUS);
writel(IRQ_EN_MASK, host->regs + SD_EMMC_IRQ_EN);
/* set config to sane default */
meson_mmc_cfg_init(host);
writel(IRQ_CRC_ERR | IRQ_TIMEOUTS | IRQ_END_OF_CHAIN,
host->regs + SD_EMMC_STATUS);
writel(IRQ_CRC_ERR | IRQ_TIMEOUTS | IRQ_END_OF_CHAIN,
host->regs + SD_EMMC_IRQ_EN);
ret = devm_request_threaded_irq(&pdev->dev, irq, meson_mmc_irq,
meson_mmc_irq_thread, IRQF_SHARED,
NULL, host);
if (ret)
goto err_div_clk;
goto err_init_clk;
mmc->caps |= MMC_CAP_CMD23;
mmc->max_blk_count = CMD_CFG_LENGTH_MASK;
@ -990,7 +1264,7 @@ static int meson_mmc_probe(struct platform_device *pdev)
if (host->bounce_buf == NULL) {
dev_err(host->dev, "Unable to map allocate DMA bounce buffer.\n");
ret = -ENOMEM;
goto err_div_clk;
goto err_init_clk;
}
host->descs = dma_alloc_coherent(host->dev, SD_EMMC_DESC_BUF_LEN,
@ -1009,8 +1283,8 @@ static int meson_mmc_probe(struct platform_device *pdev)
err_bounce_buf:
dma_free_coherent(host->dev, host->bounce_buf_size,
host->bounce_buf, host->bounce_dma_addr);
err_div_clk:
clk_disable_unprepare(host->cfg_div_clk);
err_init_clk:
clk_disable_unprepare(host->mmc_clk);
err_core_clk:
clk_disable_unprepare(host->core_clk);
free_host:
@ -1032,7 +1306,7 @@ static int meson_mmc_remove(struct platform_device *pdev)
dma_free_coherent(host->dev, host->bounce_buf_size,
host->bounce_buf, host->bounce_dma_addr);
clk_disable_unprepare(host->cfg_div_clk);
clk_disable_unprepare(host->mmc_clk);
clk_disable_unprepare(host->core_clk);
mmc_free_host(host->mmc);

View File

@ -1904,7 +1904,7 @@ static const struct dev_pm_ops mmci_dev_pm_ops = {
SET_RUNTIME_PM_OPS(mmci_runtime_suspend, mmci_runtime_resume, NULL)
};
static struct amba_id mmci_ids[] = {
static const struct amba_id mmci_ids[] = {
{
.id = 0x00041180,
.mask = 0xff0fffff,

View File

@ -546,7 +546,7 @@ static int moxart_get_ro(struct mmc_host *mmc)
return !!(readl(host->base + REG_STATUS) & WRITE_PROT);
}
static struct mmc_host_ops moxart_ops = {
static const struct mmc_host_ops moxart_ops = {
.request = moxart_request,
.set_ios = moxart_set_ios,
.get_ro = moxart_get_ro,

View File

@ -1579,12 +1579,13 @@ static void msdc_hw_reset(struct mmc_host *mmc)
sdr_clr_bits(host->base + EMMC_IOCON, 1);
}
static struct mmc_host_ops mt_msdc_ops = {
static const struct mmc_host_ops mt_msdc_ops = {
.post_req = msdc_post_req,
.pre_req = msdc_pre_req,
.request = msdc_ops_request,
.set_ios = msdc_ops_set_ios,
.get_ro = mmc_gpio_get_ro,
.get_cd = mmc_gpio_get_cd,
.start_signal_voltage_switch = msdc_ops_switch_volt,
.card_busy = msdc_card_busy,
.execute_tuning = msdc_execute_tuning,

View File

@ -681,6 +681,9 @@ static void mxcmci_data_done(struct mxcmci_host *host, unsigned int stat)
spin_unlock_irqrestore(&host->lock, flags);
if (data_error)
return;
mxcmci_read_response(host, stat);
host->cmd = NULL;
@ -1014,8 +1017,10 @@ static int mxcmci_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return -EINVAL;
if (irq < 0) {
dev_err(&pdev->dev, "failed to get IRQ: %d\n", irq);
return irq;
}
mmc = mmc_alloc_host(sizeof(*host), &pdev->dev);
if (!mmc)
@ -1098,8 +1103,13 @@ static int mxcmci_probe(struct platform_device *pdev)
goto out_free;
}
clk_prepare_enable(host->clk_per);
clk_prepare_enable(host->clk_ipg);
ret = clk_prepare_enable(host->clk_per);
if (ret)
goto out_free;
ret = clk_prepare_enable(host->clk_ipg);
if (ret)
goto out_clk_per_put;
mxcmci_softreset(host);
@ -1168,8 +1178,9 @@ out_free_dma:
dma_release_channel(host->dma);
out_clk_put:
clk_disable_unprepare(host->clk_per);
clk_disable_unprepare(host->clk_ipg);
out_clk_per_put:
clk_disable_unprepare(host->clk_per);
out_free:
mmc_free_host(mmc);
@ -1212,10 +1223,17 @@ static int __maybe_unused mxcmci_resume(struct device *dev)
{
struct mmc_host *mmc = dev_get_drvdata(dev);
struct mxcmci_host *host = mmc_priv(mmc);
int ret;
clk_prepare_enable(host->clk_per);
clk_prepare_enable(host->clk_ipg);
return 0;
ret = clk_prepare_enable(host->clk_per);
if (ret)
return ret;
ret = clk_prepare_enable(host->clk_ipg);
if (ret)
clk_disable_unprepare(host->clk_per);
return ret;
}
static SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume);

View File

@ -71,7 +71,7 @@ struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi)
struct device *dev = &spi->dev;
struct device_node *np = dev->of_node;
struct of_mmc_spi *oms;
const u32 *voltage_ranges;
const __be32 *voltage_ranges;
int num_ranges;
int i;

View File

@ -2076,9 +2076,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
host->dbclk = NULL;
}
/* Since we do only SG emulation, we can have as many segs
* as we want. */
mmc->max_segs = 1024;
/* Set this to a value that allows allocating an entire descriptor
* list within a page (zero order allocation). */
mmc->max_segs = 64;
mmc->max_blk_size = 512; /* Block Length at max can be 1024 */
mmc->max_blk_count = 0xFFFF; /* No. of Blocks is 16 bits */
@ -2322,7 +2322,7 @@ static int omap_hsmmc_runtime_resume(struct device *dev)
return 0;
}
static struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
static const struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(omap_hsmmc_suspend, omap_hsmmc_resume)
.runtime_suspend = omap_hsmmc_runtime_suspend,
.runtime_resume = omap_hsmmc_runtime_resume,

View File

@ -31,6 +31,8 @@ struct renesas_sdhi_of_data {
int scc_offset;
struct renesas_sdhi_scc *taps;
int taps_num;
unsigned int max_blk_count;
unsigned short max_segs;
};
int renesas_sdhi_probe(struct platform_device *pdev,

View File

@ -40,6 +40,7 @@
#define EXT_ACC 0xe4
#define SDHI_VER_GEN2_SDR50 0x490c
#define SDHI_VER_RZ_A1 0x820b
/* very old datasheets said 0x490c for SDR104, too. They are wrong! */
#define SDHI_VER_GEN2_SDR104 0xcb0d
#define SDHI_VER_GEN3_SD 0xcc10
@ -398,12 +399,14 @@ static void renesas_sdhi_hw_reset(struct tmio_mmc_host *host)
sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
}
static int renesas_sdhi_wait_idle(struct tmio_mmc_host *host)
static int renesas_sdhi_wait_idle(struct tmio_mmc_host *host, u32 bit)
{
int timeout = 1000;
/* CBSY is set when busy, SCLKDIVEN is cleared when busy */
u32 wait_state = (bit == TMIO_STAT_CMD_BUSY ? TMIO_STAT_CMD_BUSY : 0);
while (--timeout && !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS)
& TMIO_STAT_SCLKDIVEN))
while (--timeout && (sd_ctrl_read16_and_16_as_32(host, CTL_STATUS)
& bit) == wait_state)
udelay(1);
if (!timeout) {
@ -416,17 +419,22 @@ static int renesas_sdhi_wait_idle(struct tmio_mmc_host *host)
static int renesas_sdhi_write16_hook(struct tmio_mmc_host *host, int addr)
{
u32 bit = TMIO_STAT_SCLKDIVEN;
switch (addr) {
case CTL_SD_CMD:
case CTL_STOP_INTERNAL_ACTION:
case CTL_XFER_BLK_COUNT:
case CTL_SD_CARD_CLK_CTL:
case CTL_SD_XFER_LEN:
case CTL_SD_MEM_CARD_OPT:
case CTL_TRANSACTION_CTL:
case CTL_DMA_ENABLE:
case EXT_ACC:
return renesas_sdhi_wait_idle(host);
if (host->pdata->flags & TMIO_MMC_HAVE_CBSY)
bit = TMIO_STAT_CMD_BUSY;
/* fallthrough */
case CTL_SD_CARD_CLK_CTL:
return renesas_sdhi_wait_idle(host, bit);
}
return 0;
@ -452,10 +460,11 @@ static int renesas_sdhi_multi_io_quirk(struct mmc_card *card,
static void renesas_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable)
{
sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0);
/* Iff regs are 8 byte apart, sdbuf is 64 bit. Otherwise always 32. */
int width = (host->bus_shift == 2) ? 64 : 32;
/* enable 32bit access if DMA mode if possibile */
renesas_sdhi_sdbuf_width(host, enable ? 32 : 16);
sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? DMA_ENABLE_DMASDRW : 0);
renesas_sdhi_sdbuf_width(host, enable ? width : 16);
}
int renesas_sdhi_probe(struct platform_device *pdev,
@ -526,6 +535,8 @@ int renesas_sdhi_probe(struct platform_device *pdev,
mmc_data->capabilities |= of_data->capabilities;
mmc_data->capabilities2 |= of_data->capabilities2;
mmc_data->dma_rx_offset = of_data->dma_rx_offset;
mmc_data->max_blk_count = of_data->max_blk_count;
mmc_data->max_segs = of_data->max_segs;
dma_priv->dma_buswidth = of_data->dma_buswidth;
host->bus_shift = of_data->bus_shift;
}
@ -579,6 +590,10 @@ int renesas_sdhi_probe(struct platform_device *pdev,
if (ret < 0)
goto efree;
/* One Gen2 SDHI incarnation does NOT have a CBSY bit */
if (sd_ctrl_read16(host, CTL_VERSION) == SDHI_VER_GEN2_SDR50)
mmc_data->flags &= ~TMIO_MMC_HAVE_CBSY;
/* Enable tuning iff we have an SCC and a supported mode */
if (of_data && of_data->scc_offset &&
(host->mmc->caps & MMC_CAP_UHS_SDR104 ||

View File

@ -0,0 +1,287 @@
/*
* DMA support for Internal DMAC with SDHI SD/SDIO controller
*
* Copyright (C) 2016-17 Renesas Electronics Corporation
* Copyright (C) 2016-17 Horms Solutions, Simon Horman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/io-64-nonatomic-hi-lo.h>
#include <linux/mfd/tmio.h>
#include <linux/mmc/host.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/pagemap.h>
#include <linux/scatterlist.h>
#include <linux/sys_soc.h>
#include "renesas_sdhi.h"
#include "tmio_mmc.h"
#define DM_CM_DTRAN_MODE 0x820
#define DM_CM_DTRAN_CTRL 0x828
#define DM_CM_RST 0x830
#define DM_CM_INFO1 0x840
#define DM_CM_INFO1_MASK 0x848
#define DM_CM_INFO2 0x850
#define DM_CM_INFO2_MASK 0x858
#define DM_DTRAN_ADDR 0x880
/* DM_CM_DTRAN_MODE */
#define DTRAN_MODE_CH_NUM_CH0 0 /* "downstream" = for write commands */
#define DTRAN_MODE_CH_NUM_CH1 BIT(16) /* "uptream" = for read commands */
#define DTRAN_MODE_BUS_WID_TH (BIT(5) | BIT(4))
#define DTRAN_MODE_ADDR_MODE BIT(0) /* 1 = Increment address */
/* DM_CM_DTRAN_CTRL */
#define DTRAN_CTRL_DM_START BIT(0)
/* DM_CM_RST */
#define RST_DTRANRST1 BIT(9)
#define RST_DTRANRST0 BIT(8)
#define RST_RESERVED_BITS GENMASK_ULL(32, 0)
/* DM_CM_INFO1 and DM_CM_INFO1_MASK */
#define INFO1_CLEAR 0
#define INFO1_DTRANEND1 BIT(17)
#define INFO1_DTRANEND0 BIT(16)
/* DM_CM_INFO2 and DM_CM_INFO2_MASK */
#define INFO2_DTRANERR1 BIT(17)
#define INFO2_DTRANERR0 BIT(16)
/*
* Specification of this driver:
* - host->chan_{rx,tx} will be used as a flag of enabling/disabling the dma
* - Since this SDHI DMAC register set has 16 but 32-bit width, we
* need a custom accessor.
*/
/* Definitions for sampling clocks */
static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = {
{
.clk_rate = 0,
.tap = 0x00000300,
},
};
static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
TMIO_MMC_CLK_ACTUAL | TMIO_MMC_HAVE_CBSY |
TMIO_MMC_MIN_RCAR2,
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
MMC_CAP_CMD23,
.bus_shift = 2,
.scc_offset = 0x1000,
.taps = rcar_gen3_scc_taps,
.taps_num = ARRAY_SIZE(rcar_gen3_scc_taps),
/* Gen3 SDHI DMAC can handle 0xffffffff blk count, but seg = 1 */
.max_blk_count = 0xffffffff,
.max_segs = 1,
};
static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
{ .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, },
{ .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, },
{},
};
MODULE_DEVICE_TABLE(of, renesas_sdhi_internal_dmac_of_match);
static void
renesas_sdhi_internal_dmac_dm_write(struct tmio_mmc_host *host,
int addr, u64 val)
{
writeq(val, host->ctl + addr);
}
static void
renesas_sdhi_internal_dmac_enable_dma(struct tmio_mmc_host *host, bool enable)
{
if (!host->chan_tx || !host->chan_rx)
return;
if (!enable)
renesas_sdhi_internal_dmac_dm_write(host, DM_CM_INFO1,
INFO1_CLEAR);
if (host->dma->enable)
host->dma->enable(host, enable);
}
static void
renesas_sdhi_internal_dmac_abort_dma(struct tmio_mmc_host *host) {
u64 val = RST_DTRANRST1 | RST_DTRANRST0;
renesas_sdhi_internal_dmac_enable_dma(host, false);
renesas_sdhi_internal_dmac_dm_write(host, DM_CM_RST,
RST_RESERVED_BITS & ~val);
renesas_sdhi_internal_dmac_dm_write(host, DM_CM_RST,
RST_RESERVED_BITS | val);
renesas_sdhi_internal_dmac_enable_dma(host, true);
}
static void
renesas_sdhi_internal_dmac_dataend_dma(struct tmio_mmc_host *host) {
tasklet_schedule(&host->dma_complete);
}
static void
renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
struct mmc_data *data)
{
struct scatterlist *sg = host->sg_ptr;
u32 dtran_mode = DTRAN_MODE_BUS_WID_TH | DTRAN_MODE_ADDR_MODE;
enum dma_data_direction dir;
int ret;
u32 irq_mask;
/* This DMAC cannot handle if sg_len is not 1 */
WARN_ON(host->sg_len > 1);
/* This DMAC cannot handle if buffer is not 8-bytes alignment */
if (!IS_ALIGNED(sg->offset, 8)) {
host->force_pio = true;
renesas_sdhi_internal_dmac_enable_dma(host, false);
return;
}
if (data->flags & MMC_DATA_READ) {
dtran_mode |= DTRAN_MODE_CH_NUM_CH1;
dir = DMA_FROM_DEVICE;
irq_mask = TMIO_STAT_RXRDY;
} else {
dtran_mode |= DTRAN_MODE_CH_NUM_CH0;
dir = DMA_TO_DEVICE;
irq_mask = TMIO_STAT_TXRQ;
}
ret = dma_map_sg(&host->pdev->dev, sg, host->sg_len, dir);
if (ret < 0)
return;
renesas_sdhi_internal_dmac_enable_dma(host, true);
/* disable PIO irqs to avoid "PIO IRQ in DMA mode!" */
tmio_mmc_disable_mmc_irqs(host, irq_mask);
/* set dma parameters */
renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_MODE,
dtran_mode);
renesas_sdhi_internal_dmac_dm_write(host, DM_DTRAN_ADDR,
sg->dma_address);
}
static void renesas_sdhi_internal_dmac_issue_tasklet_fn(unsigned long arg)
{
struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND);
/* start the DMAC */
renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_CTRL,
DTRAN_CTRL_DM_START);
}
static void renesas_sdhi_internal_dmac_complete_tasklet_fn(unsigned long arg)
{
struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
enum dma_data_direction dir;
spin_lock_irq(&host->lock);
if (!host->data)
goto out;
if (host->data->flags & MMC_DATA_READ)
dir = DMA_FROM_DEVICE;
else
dir = DMA_TO_DEVICE;
renesas_sdhi_internal_dmac_enable_dma(host, false);
dma_unmap_sg(&host->pdev->dev, host->sg_ptr, host->sg_len, dir);
tmio_mmc_do_data_irq(host);
out:
spin_unlock_irq(&host->lock);
}
static void
renesas_sdhi_internal_dmac_request_dma(struct tmio_mmc_host *host,
struct tmio_mmc_data *pdata)
{
/* Each value is set to non-zero to assume "enabling" each DMA */
host->chan_rx = host->chan_tx = (void *)0xdeadbeaf;
tasklet_init(&host->dma_complete,
renesas_sdhi_internal_dmac_complete_tasklet_fn,
(unsigned long)host);
tasklet_init(&host->dma_issue,
renesas_sdhi_internal_dmac_issue_tasklet_fn,
(unsigned long)host);
}
static void
renesas_sdhi_internal_dmac_release_dma(struct tmio_mmc_host *host)
{
/* Each value is set to zero to assume "disabling" each DMA */
host->chan_rx = host->chan_tx = NULL;
}
static const struct tmio_mmc_dma_ops renesas_sdhi_internal_dmac_dma_ops = {
.start = renesas_sdhi_internal_dmac_start_dma,
.enable = renesas_sdhi_internal_dmac_enable_dma,
.request = renesas_sdhi_internal_dmac_request_dma,
.release = renesas_sdhi_internal_dmac_release_dma,
.abort = renesas_sdhi_internal_dmac_abort_dma,
.dataend = renesas_sdhi_internal_dmac_dataend_dma,
};
/*
* Whitelist of specific R-Car Gen3 SoC ES versions to use this DMAC
* implementation as others may use a different implementation.
*/
static const struct soc_device_attribute gen3_soc_whitelist[] = {
{ .soc_id = "r8a7795", .revision = "ES1.*" },
{ .soc_id = "r8a7795", .revision = "ES2.0" },
{ .soc_id = "r8a7796", .revision = "ES1.0" },
{ /* sentinel */ }
};
static int renesas_sdhi_internal_dmac_probe(struct platform_device *pdev)
{
if (!soc_device_match(gen3_soc_whitelist))
return -ENODEV;
return renesas_sdhi_probe(pdev, &renesas_sdhi_internal_dmac_dma_ops);
}
static const struct dev_pm_ops renesas_sdhi_internal_dmac_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
tmio_mmc_host_runtime_resume,
NULL)
};
static struct platform_driver renesas_internal_dmac_sdhi_driver = {
.driver = {
.name = "renesas_sdhi_internal_dmac",
.pm = &renesas_sdhi_internal_dmac_dev_pm_ops,
.of_match_table = renesas_sdhi_internal_dmac_of_match,
},
.probe = renesas_sdhi_internal_dmac_probe,
.remove = renesas_sdhi_remove,
};
module_platform_driver(renesas_internal_dmac_sdhi_driver);
MODULE_DESCRIPTION("Renesas SDHI driver for internal DMAC");
MODULE_AUTHOR("Yoshihiro Shimoda");
MODULE_LICENSE("GPL v2");

View File

@ -1,5 +1,5 @@
/*
* DMA function for TMIO MMC implementations
* DMA support use of SYS DMAC with SDHI SD/SDIO controller
*
* Copyright (C) 2016-17 Renesas Electronics Corporation
* Copyright (C) 2016-17 Sang Engineering, Wolfram Sang
@ -18,8 +18,10 @@
#include <linux/mmc/host.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/pagemap.h>
#include <linux/scatterlist.h>
#include <linux/sys_soc.h>
#include "renesas_sdhi.h"
#include "tmio_mmc.h"
@ -31,7 +33,8 @@ static const struct renesas_sdhi_of_data of_default_cfg = {
};
static const struct renesas_sdhi_of_data of_rz_compatible = {
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_32BIT_DATA_PORT,
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_32BIT_DATA_PORT |
TMIO_MMC_HAVE_CBSY,
.tmio_ocr_mask = MMC_VDD_32_33,
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
};
@ -56,7 +59,8 @@ static struct renesas_sdhi_scc rcar_gen2_scc_taps[] = {
static const struct renesas_sdhi_of_data of_rcar_gen2_compatible = {
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2,
TMIO_MMC_CLK_ACTUAL | TMIO_MMC_HAVE_CBSY |
TMIO_MMC_MIN_RCAR2,
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
MMC_CAP_CMD23,
.dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES,
@ -76,7 +80,8 @@ static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = {
static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2,
TMIO_MMC_CLK_ACTUAL | TMIO_MMC_HAVE_CBSY |
TMIO_MMC_MIN_RCAR2,
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
MMC_CAP_CMD23,
.bus_shift = 2,
@ -93,6 +98,8 @@ static const struct of_device_id renesas_sdhi_sys_dmac_of_match[] = {
{ .compatible = "renesas,sdhi-r7s72100", .data = &of_rz_compatible, },
{ .compatible = "renesas,sdhi-r8a7778", .data = &of_rcar_gen1_compatible, },
{ .compatible = "renesas,sdhi-r8a7779", .data = &of_rcar_gen1_compatible, },
{ .compatible = "renesas,sdhi-r8a7743", .data = &of_rcar_gen2_compatible, },
{ .compatible = "renesas,sdhi-r8a7745", .data = &of_rcar_gen2_compatible, },
{ .compatible = "renesas,sdhi-r8a7790", .data = &of_rcar_gen2_compatible, },
{ .compatible = "renesas,sdhi-r8a7791", .data = &of_rcar_gen2_compatible, },
{ .compatible = "renesas,sdhi-r8a7792", .data = &of_rcar_gen2_compatible, },
@ -126,6 +133,11 @@ static void renesas_sdhi_sys_dmac_abort_dma(struct tmio_mmc_host *host)
renesas_sdhi_sys_dmac_enable_dma(host, true);
}
static void renesas_sdhi_sys_dmac_dataend_dma(struct tmio_mmc_host *host)
{
complete(&host->dma_dataend);
}
static void renesas_sdhi_sys_dmac_dma_callback(void *arg)
{
struct tmio_mmc_host *host = arg;
@ -451,10 +463,24 @@ static const struct tmio_mmc_dma_ops renesas_sdhi_sys_dmac_dma_ops = {
.request = renesas_sdhi_sys_dmac_request_dma,
.release = renesas_sdhi_sys_dmac_release_dma,
.abort = renesas_sdhi_sys_dmac_abort_dma,
.dataend = renesas_sdhi_sys_dmac_dataend_dma,
};
/*
* Whitelist of specific R-Car Gen3 SoC ES versions to use this DMAC
* implementation. Currently empty as all supported ES versions use
* the internal DMAC.
*/
static const struct soc_device_attribute gen3_soc_whitelist[] = {
{ /* sentinel */ }
};
static int renesas_sdhi_sys_dmac_probe(struct platform_device *pdev)
{
if (of_device_get_match_data(&pdev->dev) == &of_rcar_gen3_compatible &&
!soc_device_match(gen3_soc_whitelist))
return -ENODEV;
return renesas_sdhi_probe(pdev, &renesas_sdhi_sys_dmac_dma_ops);
}

View File

@ -909,7 +909,7 @@ static int sd_set_bus_width(struct rtsx_usb_sdmmc *host,
unsigned char bus_width)
{
int err = 0;
u8 width[] = {
static const u8 width[] = {
[MMC_BUS_WIDTH_1] = SD_BUS_WIDTH_1BIT,
[MMC_BUS_WIDTH_4] = SD_BUS_WIDTH_4BIT,
[MMC_BUS_WIDTH_8] = SD_BUS_WIDTH_8BIT,

View File

@ -1313,7 +1313,7 @@ static void s3cmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
s3cmci_check_sdio_irq(host);
}
static struct mmc_host_ops s3cmci_ops = {
static const struct mmc_host_ops s3cmci_ops = {
.request = s3cmci_request,
.set_ios = s3cmci_set_ios,
.get_ro = mmc_gpio_get_ro,

View File

@ -294,13 +294,10 @@ static int sdhci_acpi_sdio_probe_slot(struct platform_device *pdev,
const char *hid, const char *uid)
{
struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
struct sdhci_host *host;
if (!c || !c->host)
return 0;
host = c->host;
/* Platform specific code during sdio probe slot goes here */
return 0;
@ -432,7 +429,6 @@ static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(const char *hid,
static int sdhci_acpi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
acpi_handle handle = ACPI_HANDLE(dev);
struct acpi_device *device, *child;
struct sdhci_acpi_host *c;
struct sdhci_host *host;
@ -442,7 +438,8 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
const char *uid;
int err;
if (acpi_bus_get_device(handle, &device))
device = ACPI_COMPANION(dev);
if (!device)
return -ENODEV;
hid = acpi_device_hid(device);

View File

@ -186,7 +186,7 @@ static void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host,
udelay(740);
}
static struct sdhci_ops sdhci_bcm_kona_ops = {
static const struct sdhci_ops sdhci_bcm_kona_ops = {
.set_clock = sdhci_set_clock,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
@ -197,7 +197,7 @@ static struct sdhci_ops sdhci_bcm_kona_ops = {
.card_event = sdhci_bcm_kona_card_event,
};
static struct sdhci_pltfm_data sdhci_pltfm_data_kona = {
static const struct sdhci_pltfm_data sdhci_pltfm_data_kona = {
.ops = &sdhci_bcm_kona_ops,
.quirks = SDHCI_QUIRK_NO_CARD_NO_RESET |
SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_32BIT_DMA_ADDR |

View File

@ -21,41 +21,6 @@
#include "sdhci-pltfm.h"
#ifdef CONFIG_PM_SLEEP
static int sdhci_brcmstb_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
int res;
if (host->tuning_mode != SDHCI_TUNING_MODE_3)
mmc_retune_needed(host->mmc);
res = sdhci_suspend_host(host);
if (res)
return res;
clk_disable_unprepare(pltfm_host->clk);
return res;
}
static int sdhci_brcmstb_resume(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
int err;
err = clk_prepare_enable(pltfm_host->clk);
if (err)
return err;
return sdhci_resume_host(host);
}
#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(sdhci_brcmstb_pmops, sdhci_brcmstb_suspend,
sdhci_brcmstb_resume);
static const struct sdhci_ops sdhci_brcmstb_ops = {
.set_clock = sdhci_set_clock,
.set_bus_width = sdhci_set_bus_width,
@ -63,7 +28,7 @@ static const struct sdhci_ops sdhci_brcmstb_ops = {
.set_uhs_signaling = sdhci_set_uhs_signaling,
};
static struct sdhci_pltfm_data sdhci_brcmstb_pdata = {
static const struct sdhci_pltfm_data sdhci_brcmstb_pdata = {
.ops = &sdhci_brcmstb_ops,
};
@ -131,7 +96,7 @@ MODULE_DEVICE_TABLE(of, sdhci_brcm_of_match);
static struct platform_driver sdhci_brcmstb_driver = {
.driver = {
.name = "sdhci-brcmstb",
.pm = &sdhci_brcmstb_pmops,
.pm = &sdhci_pltfm_pmops,
.of_match_table = of_match_ptr(sdhci_brcm_of_match),
},
.probe = sdhci_brcmstb_probe,

View File

@ -67,9 +67,16 @@
*/
#define SDHCI_CDNS_MAX_TUNING_LOOP 40
struct sdhci_cdns_phy_param {
u8 addr;
u8 data;
};
struct sdhci_cdns_priv {
void __iomem *hrs_addr;
bool enhanced_strobe;
unsigned int nr_phy_params;
struct sdhci_cdns_phy_param phy_params[0];
};
struct sdhci_cdns_phy_cfg {
@ -115,9 +122,22 @@ static int sdhci_cdns_write_phy_reg(struct sdhci_cdns_priv *priv,
return 0;
}
static int sdhci_cdns_phy_init(struct device_node *np,
static unsigned int sdhci_cdns_phy_param_count(struct device_node *np)
{
unsigned int count = 0;
int i;
for (i = 0; i < ARRAY_SIZE(sdhci_cdns_phy_cfgs); i++)
if (of_property_read_bool(np, sdhci_cdns_phy_cfgs[i].property))
count++;
return count;
}
static void sdhci_cdns_phy_param_parse(struct device_node *np,
struct sdhci_cdns_priv *priv)
{
struct sdhci_cdns_phy_param *p = priv->phy_params;
u32 val;
int ret, i;
@ -127,9 +147,19 @@ static int sdhci_cdns_phy_init(struct device_node *np,
if (ret)
continue;
ret = sdhci_cdns_write_phy_reg(priv,
sdhci_cdns_phy_cfgs[i].addr,
val);
p->addr = sdhci_cdns_phy_cfgs[i].addr;
p->data = val;
p++;
}
}
static int sdhci_cdns_phy_init(struct sdhci_cdns_priv *priv)
{
int ret, i;
for (i = 0; i < priv->nr_phy_params; i++) {
ret = sdhci_cdns_write_phy_reg(priv, priv->phy_params[i].addr,
priv->phy_params[i].data);
if (ret)
return ret;
}
@ -302,6 +332,8 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_cdns_priv *priv;
struct clk *clk;
size_t priv_size;
unsigned int nr_phy_params;
int ret;
struct device *dev = &pdev->dev;
@ -313,7 +345,9 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
if (ret)
return ret;
host = sdhci_pltfm_init(pdev, &sdhci_cdns_pltfm_data, sizeof(*priv));
nr_phy_params = sdhci_cdns_phy_param_count(dev->of_node);
priv_size = sizeof(*priv) + sizeof(priv->phy_params[0]) * nr_phy_params;
host = sdhci_pltfm_init(pdev, &sdhci_cdns_pltfm_data, priv_size);
if (IS_ERR(host)) {
ret = PTR_ERR(host);
goto disable_clk;
@ -322,7 +356,8 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
pltfm_host = sdhci_priv(host);
pltfm_host->clk = clk;
priv = sdhci_cdns_priv(host);
priv = sdhci_pltfm_priv(pltfm_host);
priv->nr_phy_params = nr_phy_params;
priv->hrs_addr = host->ioaddr;
priv->enhanced_strobe = false;
host->ioaddr += SDHCI_CDNS_SRS_BASE;
@ -336,7 +371,9 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
if (ret)
goto free;
ret = sdhci_cdns_phy_init(dev->of_node, priv);
sdhci_cdns_phy_param_parse(dev->of_node, priv);
ret = sdhci_cdns_phy_init(priv);
if (ret)
goto free;
@ -353,6 +390,39 @@ disable_clk:
return ret;
}
#ifdef CONFIG_PM_SLEEP
static int sdhci_cdns_resume(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_cdns_priv *priv = sdhci_pltfm_priv(pltfm_host);
int ret;
ret = clk_prepare_enable(pltfm_host->clk);
if (ret)
return ret;
ret = sdhci_cdns_phy_init(priv);
if (ret)
goto disable_clk;
ret = sdhci_resume_host(host);
if (ret)
goto disable_clk;
return 0;
disable_clk:
clk_disable_unprepare(pltfm_host->clk);
return ret;
}
#endif
static const struct dev_pm_ops sdhci_cdns_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(sdhci_pltfm_suspend, sdhci_cdns_resume)
};
static const struct of_device_id sdhci_cdns_match[] = {
{ .compatible = "socionext,uniphier-sd4hc" },
{ .compatible = "cdns,sd4hc" },
@ -363,7 +433,7 @@ MODULE_DEVICE_TABLE(of, sdhci_cdns_match);
static struct platform_driver sdhci_cdns_driver = {
.driver = {
.name = "sdhci-cdns",
.pm = &sdhci_pltfm_pmops,
.pm = &sdhci_cdns_pm_ops,
.of_match_table = sdhci_cdns_match,
},
.probe = sdhci_cdns_probe,

View File

@ -54,6 +54,9 @@
#define ESDHC_CLOCK_HCKEN 0x00000002
#define ESDHC_CLOCK_IPGEN 0x00000001
/* Host Controller Capabilities Register 2 */
#define ESDHC_CAPABILITIES_1 0x114
/* Tuning Block Control Register */
#define ESDHC_TBCTL 0x120
#define ESDHC_TB_EN 0x00000004

View File

@ -611,7 +611,7 @@ static void msm_hc_select_hs400(struct sdhci_host *host)
* HS400 - divided clock (free running MCLK/2)
* All other modes - default (free running MCLK)
*/
void sdhci_msm_hc_select_mode(struct sdhci_host *host)
static void sdhci_msm_hc_select_mode(struct sdhci_host *host)
{
struct mmc_ios ios = host->mmc->ios;
@ -1049,7 +1049,7 @@ static unsigned int sdhci_msm_get_min_clock(struct sdhci_host *host)
* instead directly control the GCC clock as per
* HW recommendation.
**/
void __sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
static void __sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
{
u16 clk;
/*
@ -1133,6 +1133,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
if (IS_ERR(host))
return PTR_ERR(host);
host->sdma_boundary = 0;
pltfm_host = sdhci_priv(host);
msm_host = sdhci_pltfm_priv(pltfm_host);
msm_host->mmc = host->mmc;

View File

@ -216,13 +216,13 @@ static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc,
u32 vendor;
struct sdhci_host *host = mmc_priv(mmc);
vendor = readl(host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER);
vendor = sdhci_readl(host, SDHCI_ARASAN_VENDOR_REGISTER);
if (ios->enhanced_strobe)
vendor |= VENDOR_ENHANCED_STROBE;
else
vendor &= ~VENDOR_ENHANCED_STROBE;
writel(vendor, host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER);
sdhci_writel(host, vendor, SDHCI_ARASAN_VENDOR_REGISTER);
}
static void sdhci_arasan_reset(struct sdhci_host *host, u8 mask)
@ -262,7 +262,7 @@ static int sdhci_arasan_voltage_switch(struct mmc_host *mmc,
return -EINVAL;
}
static struct sdhci_ops sdhci_arasan_ops = {
static const struct sdhci_ops sdhci_arasan_ops = {
.set_clock = sdhci_arasan_set_clock,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
@ -271,7 +271,7 @@ static struct sdhci_ops sdhci_arasan_ops = {
.set_uhs_signaling = sdhci_set_uhs_signaling,
};
static struct sdhci_pltfm_data sdhci_arasan_pdata = {
static const struct sdhci_pltfm_data sdhci_arasan_pdata = {
.ops = &sdhci_arasan_ops,
.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |

View File

@ -42,6 +42,7 @@ struct sdhci_at91_priv {
struct clk *hclock;
struct clk *gck;
struct clk *mainck;
bool restore_needed;
};
static void sdhci_at91_set_force_card_detect(struct sdhci_host *host)
@ -146,6 +147,100 @@ static const struct of_device_id sdhci_at91_dt_match[] = {
};
MODULE_DEVICE_TABLE(of, sdhci_at91_dt_match);
static int sdhci_at91_set_clks_presets(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_at91_priv *priv = sdhci_pltfm_priv(pltfm_host);
int ret;
unsigned int caps0, caps1;
unsigned int clk_base, clk_mul;
unsigned int gck_rate, real_gck_rate;
unsigned int preset_div;
/*
* 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
* base clock rate and the clock mult from capabilities.
*/
clk_prepare_enable(priv->hclock);
caps0 = readl(host->ioaddr + SDHCI_CAPABILITIES);
caps1 = readl(host->ioaddr + SDHCI_CAPABILITIES_1);
clk_base = (caps0 & SDHCI_CLOCK_V3_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
clk_mul = (caps1 & SDHCI_CLOCK_MUL_MASK) >> SDHCI_CLOCK_MUL_SHIFT;
gck_rate = clk_base * 1000000 * (clk_mul + 1);
ret = clk_set_rate(priv->gck, gck_rate);
if (ret < 0) {
dev_err(dev, "failed to set gck");
clk_disable_unprepare(priv->hclock);
return ret;
}
/*
* We need to check if we have the requested rate for gck because in
* some cases this rate could be not supported. If it happens, the rate
* is the closest one gck can provide. We have to update the value
* of clk mul.
*/
real_gck_rate = clk_get_rate(priv->gck);
if (real_gck_rate != gck_rate) {
clk_mul = real_gck_rate / (clk_base * 1000000) - 1;
caps1 &= (~SDHCI_CLOCK_MUL_MASK);
caps1 |= ((clk_mul << SDHCI_CLOCK_MUL_SHIFT) &
SDHCI_CLOCK_MUL_MASK);
/* Set capabilities in r/w mode. */
writel(SDMMC_CACR_KEY | SDMMC_CACR_CAPWREN,
host->ioaddr + SDMMC_CACR);
writel(caps1, host->ioaddr + SDHCI_CAPABILITIES_1);
/* Set capabilities in ro mode. */
writel(0, host->ioaddr + SDMMC_CACR);
dev_info(dev, "update clk mul to %u as gck rate is %u Hz\n",
clk_mul, real_gck_rate);
}
/*
* We have to set preset values because it depends on the clk_mul
* value. Moreover, SDR104 is supported in a degraded mode since the
* maximum sd clock value is 120 MHz instead of 208 MHz. For that
* reason, we need to use presets to support SDR104.
*/
preset_div = DIV_ROUND_UP(real_gck_rate, 24000000) - 1;
writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div,
host->ioaddr + SDHCI_PRESET_FOR_SDR12);
preset_div = DIV_ROUND_UP(real_gck_rate, 50000000) - 1;
writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div,
host->ioaddr + SDHCI_PRESET_FOR_SDR25);
preset_div = DIV_ROUND_UP(real_gck_rate, 100000000) - 1;
writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div,
host->ioaddr + SDHCI_PRESET_FOR_SDR50);
preset_div = DIV_ROUND_UP(real_gck_rate, 120000000) - 1;
writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div,
host->ioaddr + SDHCI_PRESET_FOR_SDR104);
preset_div = DIV_ROUND_UP(real_gck_rate, 50000000) - 1;
writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div,
host->ioaddr + SDHCI_PRESET_FOR_DDR50);
clk_prepare_enable(priv->mainck);
clk_prepare_enable(priv->gck);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int sdhci_at91_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_at91_priv *priv = sdhci_pltfm_priv(pltfm_host);
int ret;
ret = pm_runtime_force_suspend(dev);
priv->restore_needed = true;
return ret;
}
#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM
static int sdhci_at91_runtime_suspend(struct device *dev)
{
@ -173,6 +268,15 @@ static int sdhci_at91_runtime_resume(struct device *dev)
struct sdhci_at91_priv *priv = sdhci_pltfm_priv(pltfm_host);
int ret;
if (priv->restore_needed) {
ret = sdhci_at91_set_clks_presets(dev);
if (ret)
return ret;
priv->restore_needed = false;
goto out;
}
ret = clk_prepare_enable(priv->mainck);
if (ret) {
dev_err(dev, "can't enable mainck\n");
@ -191,13 +295,13 @@ static int sdhci_at91_runtime_resume(struct device *dev)
return ret;
}
out:
return sdhci_runtime_resume_host(host);
}
#endif /* CONFIG_PM */
static const struct dev_pm_ops sdhci_at91_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
SET_SYSTEM_SLEEP_PM_OPS(sdhci_at91_suspend, pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(sdhci_at91_runtime_suspend,
sdhci_at91_runtime_resume,
NULL)
@ -210,11 +314,7 @@ static int sdhci_at91_probe(struct platform_device *pdev)
struct sdhci_host *host;
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_at91_priv *priv;
unsigned int caps0, caps1;
unsigned int clk_base, clk_mul;
unsigned int gck_rate, real_gck_rate;
int ret;
unsigned int preset_div;
match = of_match_device(sdhci_at91_dt_match, &pdev->dev);
if (!match)
@ -246,66 +346,11 @@ static int sdhci_at91_probe(struct platform_device *pdev)
return PTR_ERR(priv->gck);
}
/*
* 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
* base clock rate and the clock mult from capabilities.
*/
clk_prepare_enable(priv->hclock);
caps0 = readl(host->ioaddr + SDHCI_CAPABILITIES);
caps1 = readl(host->ioaddr + SDHCI_CAPABILITIES_1);
clk_base = (caps0 & SDHCI_CLOCK_V3_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
clk_mul = (caps1 & SDHCI_CLOCK_MUL_MASK) >> SDHCI_CLOCK_MUL_SHIFT;
gck_rate = clk_base * 1000000 * (clk_mul + 1);
ret = clk_set_rate(priv->gck, gck_rate);
if (ret < 0) {
dev_err(&pdev->dev, "failed to set gck");
goto hclock_disable_unprepare;
}
/*
* We need to check if we have the requested rate for gck because in
* some cases this rate could be not supported. If it happens, the rate
* is the closest one gck can provide. We have to update the value
* of clk mul.
*/
real_gck_rate = clk_get_rate(priv->gck);
if (real_gck_rate != gck_rate) {
clk_mul = real_gck_rate / (clk_base * 1000000) - 1;
caps1 &= (~SDHCI_CLOCK_MUL_MASK);
caps1 |= ((clk_mul << SDHCI_CLOCK_MUL_SHIFT) & SDHCI_CLOCK_MUL_MASK);
/* Set capabilities in r/w mode. */
writel(SDMMC_CACR_KEY | SDMMC_CACR_CAPWREN, host->ioaddr + SDMMC_CACR);
writel(caps1, host->ioaddr + SDHCI_CAPABILITIES_1);
/* Set capabilities in ro mode. */
writel(0, host->ioaddr + SDMMC_CACR);
dev_info(&pdev->dev, "update clk mul to %u as gck rate is %u Hz\n",
clk_mul, real_gck_rate);
}
ret = sdhci_at91_set_clks_presets(&pdev->dev);
if (ret)
goto sdhci_pltfm_free;
/*
* We have to set preset values because it depends on the clk_mul
* value. Moreover, SDR104 is supported in a degraded mode since the
* maximum sd clock value is 120 MHz instead of 208 MHz. For that
* reason, we need to use presets to support SDR104.
*/
preset_div = DIV_ROUND_UP(real_gck_rate, 24000000) - 1;
writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div,
host->ioaddr + SDHCI_PRESET_FOR_SDR12);
preset_div = DIV_ROUND_UP(real_gck_rate, 50000000) - 1;
writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div,
host->ioaddr + SDHCI_PRESET_FOR_SDR25);
preset_div = DIV_ROUND_UP(real_gck_rate, 100000000) - 1;
writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div,
host->ioaddr + SDHCI_PRESET_FOR_SDR50);
preset_div = DIV_ROUND_UP(real_gck_rate, 120000000) - 1;
writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div,
host->ioaddr + SDHCI_PRESET_FOR_SDR104);
preset_div = DIV_ROUND_UP(real_gck_rate, 50000000) - 1;
writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div,
host->ioaddr + SDHCI_PRESET_FOR_DDR50);
clk_prepare_enable(priv->mainck);
clk_prepare_enable(priv->gck);
priv->restore_needed = false;
ret = mmc_of_parse(host->mmc);
if (ret)
@ -368,8 +413,8 @@ pm_runtime_disable:
clocks_disable_unprepare:
clk_disable_unprepare(priv->gck);
clk_disable_unprepare(priv->mainck);
hclock_disable_unprepare:
clk_disable_unprepare(priv->hclock);
sdhci_pltfm_free:
sdhci_pltfm_free(pdev);
return ret;
}

View File

@ -86,6 +86,17 @@ static u32 esdhc_readl_fixup(struct sdhci_host *host,
return ret;
}
/*
* DTS properties of mmc host are used to enable each speed mode
* according to soc and board capability. So clean up
* SDR50/SDR104/DDR50 support bits here.
*/
if (spec_reg == SDHCI_CAPABILITIES_1) {
ret = value & ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 |
SDHCI_SUPPORT_DDR50);
return ret;
}
ret = value;
return ret;
}
@ -249,7 +260,11 @@ static u32 esdhc_be_readl(struct sdhci_host *host, int reg)
u32 ret;
u32 value;
if (reg == SDHCI_CAPABILITIES_1)
value = ioread32be(host->ioaddr + ESDHC_CAPABILITIES_1);
else
value = ioread32be(host->ioaddr + reg);
ret = esdhc_readl_fixup(host, reg, value);
return ret;
@ -260,7 +275,11 @@ static u32 esdhc_le_readl(struct sdhci_host *host, int reg)
u32 ret;
u32 value;
if (reg == SDHCI_CAPABILITIES_1)
value = ioread32(host->ioaddr + ESDHC_CAPABILITIES_1);
else
value = ioread32(host->ioaddr + reg);
ret = esdhc_readl_fixup(host, reg, value);
return ret;

View File

@ -35,7 +35,6 @@
#include "sdhci-pci-o2micro.h"
static int sdhci_pci_enable_dma(struct sdhci_host *host);
static void sdhci_pci_set_bus_width(struct sdhci_host *host, int width);
static void sdhci_pci_hw_reset(struct sdhci_host *host);
#ifdef CONFIG_PM_SLEEP
@ -562,7 +561,7 @@ static const struct sdhci_ops sdhci_intel_byt_ops = {
.set_clock = sdhci_set_clock,
.set_power = sdhci_intel_set_power,
.enable_dma = sdhci_pci_enable_dma,
.set_bus_width = sdhci_pci_set_bus_width,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
.hw_reset = sdhci_pci_hw_reset,
@ -730,6 +729,24 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
#define INTEL_MRFLD_SD 2
#define INTEL_MRFLD_SDIO 3
#ifdef CONFIG_ACPI
static void intel_mrfld_mmc_fix_up_power_slot(struct sdhci_pci_slot *slot)
{
struct acpi_device *device, *child;
device = ACPI_COMPANION(&slot->chip->pdev->dev);
if (!device)
return;
acpi_device_fix_up_power(device);
list_for_each_entry(child, &device->children, node)
if (child->status.present && child->status.enabled)
acpi_device_fix_up_power(child);
}
#else
static inline void intel_mrfld_mmc_fix_up_power_slot(struct sdhci_pci_slot *slot) {}
#endif
static int intel_mrfld_mmc_probe_slot(struct sdhci_pci_slot *slot)
{
unsigned int func = PCI_FUNC(slot->chip->pdev->devfn);
@ -751,6 +768,8 @@ static int intel_mrfld_mmc_probe_slot(struct sdhci_pci_slot *slot)
default:
return -ENODEV;
}
intel_mrfld_mmc_fix_up_power_slot(slot);
return 0;
}
@ -1197,7 +1216,7 @@ static int amd_probe(struct sdhci_pci_chip *chip)
static const struct sdhci_ops amd_sdhci_pci_ops = {
.set_clock = sdhci_set_clock,
.enable_dma = sdhci_pci_enable_dma,
.set_bus_width = sdhci_pci_set_bus_width,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
.platform_execute_tuning = amd_execute_tuning,
@ -1313,29 +1332,6 @@ static int sdhci_pci_enable_dma(struct sdhci_host *host)
return 0;
}
static void sdhci_pci_set_bus_width(struct sdhci_host *host, int width)
{
u8 ctrl;
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
switch (width) {
case MMC_BUS_WIDTH_8:
ctrl |= SDHCI_CTRL_8BITBUS;
ctrl &= ~SDHCI_CTRL_4BITBUS;
break;
case MMC_BUS_WIDTH_4:
ctrl |= SDHCI_CTRL_4BITBUS;
ctrl &= ~SDHCI_CTRL_8BITBUS;
break;
default:
ctrl &= ~(SDHCI_CTRL_8BITBUS | SDHCI_CTRL_4BITBUS);
break;
}
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}
static void sdhci_pci_gpio_hw_reset(struct sdhci_host *host)
{
struct sdhci_pci_slot *slot = sdhci_priv(host);
@ -1362,7 +1358,7 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host)
static const struct sdhci_ops sdhci_pci_ops = {
.set_clock = sdhci_set_clock,
.enable_dma = sdhci_pci_enable_dma,
.set_bus_width = sdhci_pci_set_bus_width,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
.hw_reset = sdhci_pci_hw_reset,

View File

@ -97,7 +97,7 @@ static const struct sdhci_ops pic32_sdhci_ops = {
.get_ro = pic32_sdhci_get_ro,
};
static struct sdhci_pltfm_data sdhci_pic32_pdata = {
static const struct sdhci_pltfm_data sdhci_pic32_pdata = {
.ops = &pic32_sdhci_ops,
.quirks = SDHCI_QUIRK_NO_HISPD_BIT,
.quirks2 = SDHCI_QUIRK2_NO_1_8_V,

View File

@ -209,22 +209,42 @@ int sdhci_pltfm_unregister(struct platform_device *pdev)
EXPORT_SYMBOL_GPL(sdhci_pltfm_unregister);
#ifdef CONFIG_PM_SLEEP
static int sdhci_pltfm_suspend(struct device *dev)
int sdhci_pltfm_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
int ret;
if (host->tuning_mode != SDHCI_TUNING_MODE_3)
mmc_retune_needed(host->mmc);
return sdhci_suspend_host(host);
}
ret = sdhci_suspend_host(host);
if (ret)
return ret;
static int sdhci_pltfm_resume(struct device *dev)
clk_disable_unprepare(pltfm_host->clk);
return 0;
}
EXPORT_SYMBOL_GPL(sdhci_pltfm_suspend);
int sdhci_pltfm_resume(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
int ret;
return sdhci_resume_host(host);
ret = clk_prepare_enable(pltfm_host->clk);
if (ret)
return ret;
ret = sdhci_resume_host(host);
if (ret)
clk_disable_unprepare(pltfm_host->clk);
return ret;
}
EXPORT_SYMBOL_GPL(sdhci_pltfm_resume);
#endif
const struct dev_pm_ops sdhci_pltfm_pmops = {

View File

@ -109,6 +109,8 @@ static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host)
return host->private;
}
int sdhci_pltfm_suspend(struct device *dev);
int sdhci_pltfm_resume(struct device *dev);
extern const struct dev_pm_ops sdhci_pltfm_pmops;
#endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */

View File

@ -178,17 +178,17 @@ static int sdhci_pxav2_probe(struct platform_device *pdev)
pltfm_host = sdhci_priv(host);
clk = clk_get(dev, "PXA-SDHCLK");
clk = devm_clk_get(dev, "PXA-SDHCLK");
if (IS_ERR(clk)) {
dev_err(dev, "failed to get io clock\n");
ret = PTR_ERR(clk);
goto err_clk_get;
goto free;
}
pltfm_host->clk = clk;
ret = clk_prepare_enable(clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable io clock\n");
goto err_clk_enable;
goto free;
}
host->quirks = SDHCI_QUIRK_BROKEN_ADMA
@ -223,34 +223,18 @@ static int sdhci_pxav2_probe(struct platform_device *pdev)
ret = sdhci_add_host(host);
if (ret) {
dev_err(&pdev->dev, "failed to add host\n");
goto err_add_host;
goto disable_clk;
}
return 0;
err_add_host:
disable_clk:
clk_disable_unprepare(clk);
err_clk_enable:
clk_put(clk);
err_clk_get:
free:
sdhci_pltfm_free(pdev);
return ret;
}
static int sdhci_pxav2_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
sdhci_remove_host(host, 1);
clk_disable_unprepare(pltfm_host->clk);
clk_put(pltfm_host->clk);
sdhci_pltfm_free(pdev);
return 0;
}
static struct platform_driver sdhci_pxav2_driver = {
.driver = {
.name = "sdhci-pxav2",
@ -258,7 +242,7 @@ static struct platform_driver sdhci_pxav2_driver = {
.pm = &sdhci_pltfm_pmops,
},
.probe = sdhci_pxav2_probe,
.remove = sdhci_pxav2_remove,
.remove = sdhci_pltfm_unregister,
};
module_platform_driver(sdhci_pxav2_driver);

View File

@ -337,7 +337,7 @@ static const struct sdhci_ops pxav3_sdhci_ops = {
.set_uhs_signaling = pxav3_set_uhs_signaling,
};
static struct sdhci_pltfm_data sdhci_pxav3_pdata = {
static const struct sdhci_pltfm_data sdhci_pxav3_pdata = {
.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK
| SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
| SDHCI_QUIRK_32BIT_ADMA_SIZE

View File

@ -414,43 +414,11 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
}
/**
* sdhci_s3c_set_bus_width - support 8bit buswidth
* @host: The SDHCI host being queried
* @width: MMC_BUS_WIDTH_ macro for the bus width being requested
*
* We have 8-bit width support but is not a v3 controller.
* So we add platform_bus_width() and support 8bit width.
*/
static void sdhci_s3c_set_bus_width(struct sdhci_host *host, int width)
{
u8 ctrl;
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
switch (width) {
case MMC_BUS_WIDTH_8:
ctrl |= SDHCI_CTRL_8BITBUS;
ctrl &= ~SDHCI_CTRL_4BITBUS;
break;
case MMC_BUS_WIDTH_4:
ctrl |= SDHCI_CTRL_4BITBUS;
ctrl &= ~SDHCI_CTRL_8BITBUS;
break;
default:
ctrl &= ~SDHCI_CTRL_4BITBUS;
ctrl &= ~SDHCI_CTRL_8BITBUS;
break;
}
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}
static struct sdhci_ops sdhci_s3c_ops = {
.get_max_clock = sdhci_s3c_get_max_clk,
.set_clock = sdhci_s3c_set_clock,
.get_min_clock = sdhci_s3c_get_min_clock,
.set_bus_width = sdhci_s3c_set_bus_width,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
};

View File

@ -146,7 +146,7 @@ retry:
return rc;
}
static struct sdhci_ops sdhci_sirf_ops = {
static const struct sdhci_ops sdhci_sirf_ops = {
.read_l = sdhci_sirf_readl_le,
.read_w = sdhci_sirf_readw_le,
.platform_execute_tuning = sdhci_sirf_execute_tuning,
@ -157,7 +157,7 @@ static struct sdhci_ops sdhci_sirf_ops = {
.set_uhs_signaling = sdhci_set_uhs_signaling,
};
static struct sdhci_pltfm_data sdhci_sirf_pdata = {
static const struct sdhci_pltfm_data sdhci_sirf_pdata = {
.ops = &sdhci_sirf_ops,
.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
@ -230,43 +230,6 @@ err_clk_prepare:
return ret;
}
#ifdef CONFIG_PM_SLEEP
static int sdhci_sirf_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
int ret;
if (host->tuning_mode != SDHCI_TUNING_MODE_3)
mmc_retune_needed(host->mmc);
ret = sdhci_suspend_host(host);
if (ret)
return ret;
clk_disable(pltfm_host->clk);
return 0;
}
static int sdhci_sirf_resume(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
int ret;
ret = clk_enable(pltfm_host->clk);
if (ret) {
dev_dbg(dev, "Resume: Error enabling clock\n");
return ret;
}
return sdhci_resume_host(host);
}
#endif
static SIMPLE_DEV_PM_OPS(sdhci_sirf_pm_ops, sdhci_sirf_suspend, sdhci_sirf_resume);
static const struct of_device_id sdhci_sirf_of_match[] = {
{ .compatible = "sirf,prima2-sdhc" },
{ }
@ -277,7 +240,7 @@ static struct platform_driver sdhci_sirf_driver = {
.driver = {
.name = "sdhci-sirf",
.of_match_table = sdhci_sirf_of_match,
.pm = &sdhci_sirf_pm_ops,
.pm = &sdhci_pltfm_pmops,
},
.probe = sdhci_sirf_probe,
.remove = sdhci_pltfm_unregister,

View File

@ -371,7 +371,7 @@ static int sdhci_st_probe(struct platform_device *pdev)
if (IS_ERR(icnclk))
icnclk = NULL;
rstc = devm_reset_control_get(&pdev->dev, NULL);
rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (IS_ERR(rstc))
rstc = NULL;
else
@ -394,8 +394,17 @@ static int sdhci_st_probe(struct platform_device *pdev)
goto err_of;
}
clk_prepare_enable(clk);
clk_prepare_enable(icnclk);
ret = clk_prepare_enable(clk);
if (ret) {
dev_err(&pdev->dev, "Failed to prepare clock\n");
goto err_of;
}
ret = clk_prepare_enable(icnclk);
if (ret) {
dev_err(&pdev->dev, "Failed to prepare icn clock\n");
goto err_icnclk;
}
/* Configure the FlashSS Top registers for setting eMMC TX/RX delay */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
@ -429,6 +438,7 @@ static int sdhci_st_probe(struct platform_device *pdev)
err_out:
clk_disable_unprepare(icnclk);
err_icnclk:
clk_disable_unprepare(clk);
err_of:
sdhci_pltfm_free(pdev);
@ -487,9 +497,17 @@ static int sdhci_st_resume(struct device *dev)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct st_mmc_platform_data *pdata = sdhci_pltfm_priv(pltfm_host);
struct device_node *np = dev->of_node;
int ret;
clk_prepare_enable(pltfm_host->clk);
clk_prepare_enable(pdata->icnclk);
ret = clk_prepare_enable(pltfm_host->clk);
if (ret)
return ret;
ret = clk_prepare_enable(pdata->icnclk);
if (ret) {
clk_disable_unprepare(pltfm_host->clk);
return ret;
}
if (pdata->rstc)
reset_control_deassert(pdata->rstc);

View File

@ -190,25 +190,6 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
tegra_host->ddr_signaling = false;
}
static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width)
{
u32 ctrl;
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
if ((host->mmc->caps & MMC_CAP_8_BIT_DATA) &&
(bus_width == MMC_BUS_WIDTH_8)) {
ctrl &= ~SDHCI_CTRL_4BITBUS;
ctrl |= SDHCI_CTRL_8BITBUS;
} else {
ctrl &= ~SDHCI_CTRL_8BITBUS;
if (bus_width == MMC_BUS_WIDTH_4)
ctrl |= SDHCI_CTRL_4BITBUS;
else
ctrl &= ~SDHCI_CTRL_4BITBUS;
}
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}
static void tegra_sdhci_pad_autocalib(struct sdhci_host *host)
{
u32 val;
@ -323,7 +304,7 @@ static const struct sdhci_ops tegra_sdhci_ops = {
.read_w = tegra_sdhci_readw,
.write_l = tegra_sdhci_writel,
.set_clock = tegra_sdhci_set_clock,
.set_bus_width = tegra_sdhci_set_bus_width,
.set_bus_width = sdhci_set_bus_width,
.reset = tegra_sdhci_reset,
.platform_execute_tuning = tegra_sdhci_execute_tuning,
.set_uhs_signaling = tegra_sdhci_set_uhs_signaling,
@ -371,7 +352,7 @@ static const struct sdhci_ops tegra114_sdhci_ops = {
.write_w = tegra_sdhci_writew,
.write_l = tegra_sdhci_writel,
.set_clock = tegra_sdhci_set_clock,
.set_bus_width = tegra_sdhci_set_bus_width,
.set_bus_width = sdhci_set_bus_width,
.reset = tegra_sdhci_reset,
.platform_execute_tuning = tegra_sdhci_execute_tuning,
.set_uhs_signaling = tegra_sdhci_set_uhs_signaling,
@ -508,7 +489,8 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
clk_prepare_enable(clk);
pltfm_host->clk = clk;
tegra_host->rst = devm_reset_control_get(&pdev->dev, "sdhci");
tegra_host->rst = devm_reset_control_get_exclusive(&pdev->dev,
"sdhci");
if (IS_ERR(tegra_host->rst)) {
rc = PTR_ERR(tegra_host->rst);
dev_err(&pdev->dev, "failed to get reset control: %d\n", rc);

View File

@ -409,17 +409,30 @@ static int xenon_emmc_phy_config_tuning(struct sdhci_host *host)
return 0;
}
static void xenon_emmc_phy_disable_data_strobe(struct sdhci_host *host)
static void xenon_emmc_phy_disable_strobe(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
u32 reg;
/* Disable SDHC Data Strobe */
/* Disable both SDHC Data Strobe and Enhanced Strobe */
reg = sdhci_readl(host, XENON_SLOT_EMMC_CTRL);
reg &= ~XENON_ENABLE_DATA_STROBE;
reg &= ~(XENON_ENABLE_DATA_STROBE | XENON_ENABLE_RESP_STROBE);
sdhci_writel(host, reg, XENON_SLOT_EMMC_CTRL);
/* Clear Strobe line Pull down or Pull up */
if (priv->phy_type == EMMC_5_0_PHY) {
reg = sdhci_readl(host, XENON_EMMC_5_0_PHY_PAD_CONTROL);
reg &= ~(XENON_EMMC5_FC_QSP_PD | XENON_EMMC5_FC_QSP_PU);
sdhci_writel(host, reg, XENON_EMMC_5_0_PHY_PAD_CONTROL);
} else {
reg = sdhci_readl(host, XENON_EMMC_PHY_PAD_CONTROL1);
reg &= ~(XENON_EMMC5_1_FC_QSP_PD | XENON_EMMC5_1_FC_QSP_PU);
sdhci_writel(host, reg, XENON_EMMC_PHY_PAD_CONTROL1);
}
}
/* Set HS400 Data Strobe */
/* Set HS400 Data Strobe and Enhanced Strobe */
static void xenon_emmc_phy_strobe_delay_adj(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@ -439,6 +452,15 @@ static void xenon_emmc_phy_strobe_delay_adj(struct sdhci_host *host)
/* Enable SDHC Data Strobe */
reg = sdhci_readl(host, XENON_SLOT_EMMC_CTRL);
reg |= XENON_ENABLE_DATA_STROBE;
/*
* Enable SDHC Enhanced Strobe if supported
* Xenon Enhanced Strobe should be enabled only when
* 1. card is in HS400 mode and
* 2. SDCLK is higher than 52MHz
* 3. DLL is enabled
*/
if (host->mmc->ios.enhanced_strobe)
reg |= XENON_ENABLE_RESP_STROBE;
sdhci_writel(host, reg, XENON_SLOT_EMMC_CTRL);
/* Set Data Strobe Pull down */
@ -615,7 +637,7 @@ static void xenon_emmc_phy_set(struct sdhci_host *host,
sdhci_writel(host, phy_regs->logic_timing_val,
phy_regs->logic_timing_adj);
else
xenon_emmc_phy_disable_data_strobe(host);
xenon_emmc_phy_disable_strobe(host);
phy_init:
xenon_emmc_phy_init(host);
@ -705,7 +727,7 @@ void xenon_soc_pad_ctrl(struct sdhci_host *host,
/*
* Setting PHY when card is working in High Speed Mode.
* HS400 set data strobe line.
* HS400 set Data Strobe and Enhanced Strobe if it is supported.
* HS200/SDR104 set tuning config to prepare for tuning.
*/
static int xenon_hs_delay_adj(struct sdhci_host *host)

View File

@ -18,6 +18,8 @@
#include <linux/ktime.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include "sdhci-pltfm.h"
#include "sdhci-xenon.h"
@ -330,7 +332,8 @@ static int xenon_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
struct sdhci_host *host = mmc_priv(mmc);
if (host->timing == MMC_TIMING_UHS_DDR50)
if (host->timing == MMC_TIMING_UHS_DDR50 ||
host->timing == MMC_TIMING_MMC_DDR52)
return 0;
/*
@ -463,7 +466,6 @@ static int xenon_probe(struct platform_device *pdev)
{
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_host *host;
struct xenon_priv *priv;
int err;
host = sdhci_pltfm_init(pdev, &sdhci_xenon_pdata,
@ -472,7 +474,6 @@ static int xenon_probe(struct platform_device *pdev)
return PTR_ERR(host);
pltfm_host = sdhci_priv(host);
priv = sdhci_pltfm_priv(pltfm_host);
/*
* Link Xenon specific mmc_host_ops function,
@ -507,13 +508,24 @@ static int xenon_probe(struct platform_device *pdev)
if (err)
goto err_clk;
pm_runtime_get_noresume(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_enable(&pdev->dev);
pm_suspend_ignore_children(&pdev->dev, 1);
err = sdhci_add_host(host);
if (err)
goto remove_sdhc;
pm_runtime_put_autosuspend(&pdev->dev);
return 0;
remove_sdhc:
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
xenon_sdhc_unprepare(host);
err_clk:
clk_disable_unprepare(pltfm_host->clk);
@ -527,6 +539,10 @@ static int xenon_remove(struct platform_device *pdev)
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
pm_runtime_get_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
sdhci_remove_host(host, 0);
xenon_sdhc_unprepare(host);
@ -538,6 +554,84 @@ static int xenon_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int xenon_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
int ret;
ret = pm_runtime_force_suspend(dev);
priv->restore_needed = true;
return ret;
}
#endif
#ifdef CONFIG_PM
static int xenon_runtime_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
int ret;
ret = sdhci_runtime_suspend_host(host);
if (ret)
return ret;
if (host->tuning_mode != SDHCI_TUNING_MODE_3)
mmc_retune_needed(host->mmc);
clk_disable_unprepare(pltfm_host->clk);
/*
* Need to update the priv->clock here, or when runtime resume
* back, phy don't aware the clock change and won't adjust phy
* which will cause cmd err
*/
priv->clock = 0;
return 0;
}
static int xenon_runtime_resume(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
int ret;
ret = clk_prepare_enable(pltfm_host->clk);
if (ret) {
dev_err(dev, "can't enable mainck\n");
return ret;
}
if (priv->restore_needed) {
ret = xenon_sdhc_prepare(host);
if (ret)
goto out;
priv->restore_needed = false;
}
ret = sdhci_runtime_resume_host(host);
if (ret)
goto out;
return 0;
out:
clk_disable_unprepare(pltfm_host->clk);
return ret;
}
#endif /* CONFIG_PM */
static const struct dev_pm_ops sdhci_xenon_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(xenon_suspend,
pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(xenon_runtime_suspend,
xenon_runtime_resume,
NULL)
};
static const struct of_device_id sdhci_xenon_dt_ids[] = {
{ .compatible = "marvell,armada-ap806-sdhci",},
{ .compatible = "marvell,armada-cp110-sdhci",},
@ -550,7 +644,7 @@ static struct platform_driver sdhci_xenon_driver = {
.driver = {
.name = "xenon-sdhci",
.of_match_table = sdhci_xenon_dt_ids,
.pm = &sdhci_pltfm_pmops,
.pm = &sdhci_xenon_dev_pm_ops,
},
.probe = xenon_probe,
.remove = xenon_remove,

View File

@ -33,6 +33,7 @@
#define XENON_TUNING_STEP_DIVIDER BIT(6)
#define XENON_SLOT_EMMC_CTRL 0x0130
#define XENON_ENABLE_RESP_STROBE BIT(25)
#define XENON_ENABLE_DATA_STROBE BIT(24)
#define XENON_SLOT_RETUNING_REQ_CTRL 0x0144
@ -90,6 +91,7 @@ struct xenon_priv {
*/
void *phy_params;
struct xenon_emmc_phy_regs *emmc_phy_regs;
bool restore_needed;
};
int xenon_phy_adj(struct sdhci_host *host, struct mmc_ios *ios);

View File

@ -897,8 +897,8 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
sdhci_set_transfer_irqs(host);
/* Set the DMA boundary value and block size */
sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
data->blksz), SDHCI_BLOCK_SIZE);
sdhci_writew(host, SDHCI_MAKE_BLKSZ(host->sdma_boundary, data->blksz),
SDHCI_BLOCK_SIZE);
sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
}
@ -1173,24 +1173,35 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
}
EXPORT_SYMBOL_GPL(sdhci_send_command);
static void sdhci_read_rsp_136(struct sdhci_host *host, struct mmc_command *cmd)
{
int i, reg;
for (i = 0; i < 4; i++) {
reg = SDHCI_RESPONSE + (3 - i) * 4;
cmd->resp[i] = sdhci_readl(host, reg);
}
if (host->quirks2 & SDHCI_QUIRK2_RSP_136_HAS_CRC)
return;
/* CRC is stripped so we need to do some shifting */
for (i = 0; i < 4; i++) {
cmd->resp[i] <<= 8;
if (i != 3)
cmd->resp[i] |= cmd->resp[i + 1] >> 24;
}
}
static void sdhci_finish_command(struct sdhci_host *host)
{
struct mmc_command *cmd = host->cmd;
int i;
host->cmd = NULL;
if (cmd->flags & MMC_RSP_PRESENT) {
if (cmd->flags & MMC_RSP_136) {
/* CRC is stripped so we need to do some shifting. */
for (i = 0;i < 4;i++) {
cmd->resp[i] = sdhci_readl(host,
SDHCI_RESPONSE + (3-i)*4) << 8;
if (i != 3)
cmd->resp[i] |=
sdhci_readb(host,
SDHCI_RESPONSE + (3-i)*4-1);
}
sdhci_read_rsp_136(host, cmd);
} else {
cmd->resp[0] = sdhci_readl(host, SDHCI_RESPONSE);
}
@ -1544,10 +1555,9 @@ void sdhci_set_bus_width(struct sdhci_host *host, int width)
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)
if (host->mmc->caps & MMC_CAP_8_BIT_DATA)
ctrl &= ~SDHCI_CTRL_8BITBUS;
if (width == MMC_BUS_WIDTH_4)
ctrl |= SDHCI_CTRL_4BITBUS;
@ -1641,7 +1651,8 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
if ((ios->timing == MMC_TIMING_SD_HS ||
if (!(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)) {
if (ios->timing == MMC_TIMING_SD_HS ||
ios->timing == MMC_TIMING_MMC_HS ||
ios->timing == MMC_TIMING_MMC_HS400 ||
ios->timing == MMC_TIMING_MMC_HS200 ||
@ -1650,10 +1661,10 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
ios->timing == MMC_TIMING_UHS_SDR104 ||
ios->timing == MMC_TIMING_UHS_DDR50 ||
ios->timing == MMC_TIMING_UHS_SDR25)
&& !(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT))
ctrl |= SDHCI_CTRL_HISPD;
else
ctrl &= ~SDHCI_CTRL_HISPD;
}
if (host->version >= SDHCI_SPEC_300) {
u16 clk, ctrl_2;
@ -2037,6 +2048,7 @@ static void sdhci_send_tuning(struct sdhci_host *host, u32 opcode)
struct mmc_command cmd = {};
struct mmc_request mrq = {};
unsigned long flags;
u32 b = host->sdma_boundary;
spin_lock_irqsave(&host->lock, flags);
@ -2052,9 +2064,9 @@ static void sdhci_send_tuning(struct sdhci_host *host, u32 opcode)
*/
if (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200 &&
mmc->ios.bus_width == MMC_BUS_WIDTH_8)
sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128), SDHCI_BLOCK_SIZE);
sdhci_writew(host, SDHCI_MAKE_BLKSZ(b, 128), SDHCI_BLOCK_SIZE);
else
sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), SDHCI_BLOCK_SIZE);
sdhci_writew(host, SDHCI_MAKE_BLKSZ(b, 64), SDHCI_BLOCK_SIZE);
/*
* The tuning block is sent by the card to the host controller.
@ -2502,7 +2514,6 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
sdhci_finish_command(host);
}
#ifdef CONFIG_MMC_DEBUG
static void sdhci_adma_show_error(struct sdhci_host *host)
{
void *desc = host->adma_table;
@ -2530,9 +2541,6 @@ static void sdhci_adma_show_error(struct sdhci_host *host)
break;
}
}
#else
static void sdhci_adma_show_error(struct sdhci_host *host) { }
#endif
static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
{
@ -2938,7 +2946,8 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
sdhci_init(host, 0);
if (mmc->ios.power_mode != MMC_POWER_UNDEFINED) {
if (mmc->ios.power_mode != MMC_POWER_UNDEFINED &&
mmc->ios.power_mode != MMC_POWER_OFF) {
/* Force clock and power re-program */
host->pwr = 0;
host->clock = 0;
@ -2998,7 +3007,7 @@ void sdhci_cqe_enable(struct mmc_host *mmc)
ctrl |= SDHCI_CTRL_ADMA32;
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG, 512),
sdhci_writew(host, SDHCI_MAKE_BLKSZ(host->sdma_boundary, 512),
SDHCI_BLOCK_SIZE);
/* Set maximum timeout */
@ -3119,6 +3128,8 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev,
host->tuning_delay = -1;
host->sdma_boundary = SDHCI_DEFAULT_BOUNDARY_ARG;
return host;
}
@ -3230,6 +3241,13 @@ int sdhci_setup_host(struct sdhci_host *host)
if (ret == -EPROBE_DEFER)
return ret;
DBG("Version: 0x%08x | Present: 0x%08x\n",
sdhci_readw(host, SDHCI_HOST_VERSION),
sdhci_readl(host, SDHCI_PRESENT_STATE));
DBG("Caps: 0x%08x | Caps_1: 0x%08x\n",
sdhci_readl(host, SDHCI_CAPABILITIES),
sdhci_readl(host, SDHCI_CAPABILITIES_1));
sdhci_read_caps(host);
override_timeout_clk = host->timeout_clk;
@ -3747,10 +3765,6 @@ int __sdhci_add_host(struct sdhci_host *host)
goto untasklet;
}
#ifdef CONFIG_MMC_DEBUG
sdhci_dumpregs(host);
#endif
ret = sdhci_led_register(host);
if (ret) {
pr_err("%s: Failed to register LED device: %d\n",

View File

@ -435,6 +435,8 @@ struct sdhci_host {
#define SDHCI_QUIRK2_ACMD23_BROKEN (1<<14)
/* Broken Clock divider zero in controller */
#define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN (1<<15)
/* Controller has CRC in 136 bit Command Response */
#define SDHCI_QUIRK2_RSP_136_HAS_CRC (1<<16)
int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */
@ -541,6 +543,9 @@ struct sdhci_host {
/* Delay (ms) between tuning commands */
int tuning_delay;
/* Host SDMA buffer boundary. */
u32 sdma_boundary;
unsigned long private[0] ____cacheline_aligned;
};

View File

@ -385,7 +385,7 @@ static int sdricoh_get_ro(struct mmc_host *mmc)
return (status & STATUS_CARD_LOCKED);
}
static struct mmc_host_ops sdricoh_ops = {
static const struct mmc_host_ops sdricoh_ops = {
.request = sdricoh_request,
.set_ios = sdricoh_set_ios,
.get_ro = sdricoh_get_ro,

View File

@ -1079,7 +1079,7 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
host->state = STATE_IDLE;
}
static struct mmc_host_ops sh_mmcif_ops = {
static const struct mmc_host_ops sh_mmcif_ops = {
.request = sh_mmcif_request,
.set_ios = sh_mmcif_set_ios,
.get_cd = mmc_gpio_get_cd,

View File

@ -22,6 +22,7 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/clk/sunxi-ng.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
@ -259,7 +260,11 @@ struct sunxi_mmc_cfg {
/* Does DATA0 needs to be masked while the clock is updated */
bool mask_data0;
/* hardware only supports new timing mode */
bool needs_new_timings;
/* hardware can switch between old and new timing modes */
bool has_timings_switch;
};
struct sunxi_mmc_host {
@ -293,6 +298,9 @@ struct sunxi_mmc_host {
/* vqmmc */
bool vqmmc_enabled;
/* timings */
bool use_new_timings;
};
static int sunxi_mmc_reset_host(struct sunxi_mmc_host *host)
@ -714,6 +722,11 @@ static int sunxi_mmc_clk_set_phase(struct sunxi_mmc_host *host,
{
int index;
/* clk controller delays not used under new timings mode */
if (host->use_new_timings)
return 0;
/* some old controllers don't support delays */
if (!host->cfg->clk_delays)
return 0;
@ -747,7 +760,7 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
{
struct mmc_host *mmc = host->mmc;
long rate;
u32 rval, clock = ios->clock;
u32 rval, clock = ios->clock, div = 1;
int ret;
ret = sunxi_mmc_oclk_onoff(host, 0);
@ -760,10 +773,30 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
if (!ios->clock)
return 0;
/* 8 bit DDR requires a higher module clock */
/*
* Under the old timing mode, 8 bit DDR requires the module
* clock to be double the card clock. Under the new timing
* mode, all DDR modes require a doubled module clock.
*
* We currently only support the standard MMC DDR52 mode.
* This block should be updated once support for other DDR
* modes is added.
*/
if (ios->timing == MMC_TIMING_MMC_DDR52 &&
ios->bus_width == MMC_BUS_WIDTH_8)
(host->use_new_timings ||
ios->bus_width == MMC_BUS_WIDTH_8)) {
div = 2;
clock <<= 1;
}
if (host->use_new_timings && host->cfg->has_timings_switch) {
ret = sunxi_ccu_set_mmc_timing_mode(host->clk_mmc, true);
if (ret) {
dev_err(mmc_dev(mmc),
"error setting new timing mode\n");
return ret;
}
}
rate = clk_round_rate(host->clk_mmc, clock);
if (rate < 0) {
@ -782,24 +815,23 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
return ret;
}
/* clear internal divider */
/* set internal divider */
rval = mmc_readl(host, REG_CLKCR);
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;
}
rval |= div - 1;
mmc_writel(host, REG_CLKCR, rval);
if (host->cfg->needs_new_timings) {
/* update card clock rate to account for internal divider */
rate /= div;
if (host->use_new_timings) {
/* Don't touch the delay bits */
rval = mmc_readl(host, REG_SD_NTSR);
rval |= SDXC_2X_TIMING_MODE;
mmc_writel(host, REG_SD_NTSR, rval);
}
/* sunxi_mmc_clk_set_phase expects the actual card clock rate */
ret = sunxi_mmc_clk_set_phase(host, ios, rate);
if (ret)
return ret;
@ -1048,7 +1080,7 @@ static int sunxi_mmc_card_busy(struct mmc_host *mmc)
return !!(mmc_readl(host, REG_STAS) & SDXC_CARD_DATA_BUSY);
}
static struct mmc_host_ops sunxi_mmc_ops = {
static const struct mmc_host_ops sunxi_mmc_ops = {
.request = sunxi_mmc_request,
.set_ios = sunxi_mmc_set_ios,
.get_ro = mmc_gpio_get_ro,
@ -1094,6 +1126,13 @@ static const struct sunxi_mmc_cfg sun7i_a20_cfg = {
.can_calibrate = false,
};
static const struct sunxi_mmc_cfg sun8i_a83t_emmc_cfg = {
.idma_des_size_bits = 16,
.clk_delays = sunxi_mmc_clk_delays,
.can_calibrate = false,
.has_timings_switch = true,
};
static const struct sunxi_mmc_cfg sun9i_a80_cfg = {
.idma_des_size_bits = 16,
.clk_delays = sun9i_mmc_clk_delays,
@ -1118,6 +1157,7 @@ static const struct of_device_id sunxi_mmc_of_match[] = {
{ .compatible = "allwinner,sun4i-a10-mmc", .data = &sun4i_a10_cfg },
{ .compatible = "allwinner,sun5i-a13-mmc", .data = &sun5i_a13_cfg },
{ .compatible = "allwinner,sun7i-a20-mmc", .data = &sun7i_a20_cfg },
{ .compatible = "allwinner,sun8i-a83t-emmc", .data = &sun8i_a83t_emmc_cfg },
{ .compatible = "allwinner,sun9i-a80-mmc", .data = &sun9i_a80_cfg },
{ .compatible = "allwinner,sun50i-a64-mmc", .data = &sun50i_a64_cfg },
{ .compatible = "allwinner,sun50i-a64-emmc", .data = &sun50i_a64_emmc_cfg },
@ -1172,7 +1212,8 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
}
}
host->reset = devm_reset_control_get_optional(&pdev->dev, "ahb");
host->reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
"ahb");
if (PTR_ERR(host->reset) == -EPROBE_DEFER)
return PTR_ERR(host->reset);
@ -1201,7 +1242,7 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
}
if (!IS_ERR(host->reset)) {
ret = reset_control_deassert(host->reset);
ret = reset_control_reset(host->reset);
if (ret) {
dev_err(&pdev->dev, "reset err %d\n", ret);
goto error_disable_clk_sample;
@ -1262,6 +1303,30 @@ static int sunxi_mmc_probe(struct platform_device *pdev)
goto error_free_host;
}
if (host->cfg->has_timings_switch) {
/*
* Supports both old and new timing modes.
* Try setting the clk to new timing mode.
*/
sunxi_ccu_set_mmc_timing_mode(host->clk_mmc, true);
/* And check the result */
ret = sunxi_ccu_get_mmc_timing_mode(host->clk_mmc);
if (ret < 0) {
/*
* For whatever reason we were not able to get
* the current active mode. Default to old mode.
*/
dev_warn(&pdev->dev, "MMC clk timing mode unknown\n");
host->use_new_timings = false;
} else {
host->use_new_timings = !!ret;
}
} else if (host->cfg->needs_new_timings) {
/* Supports new timing mode only */
host->use_new_timings = true;
}
mmc->ops = &sunxi_mmc_ops;
mmc->max_blk_count = 8192;
mmc->max_blk_size = 4096;
@ -1274,7 +1339,7 @@ static int sunxi_mmc_probe(struct platform_device *pdev)
mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
MMC_CAP_ERASE | MMC_CAP_SDIO_IRQ;
if (host->cfg->clk_delays)
if (host->cfg->clk_delays || host->use_new_timings)
mmc->caps |= MMC_CAP_1_8V_DDR;
ret = mmc_of_parse(mmc);

View File

@ -81,14 +81,14 @@
#define TMIO_STAT_CMD_BUSY BIT(30)
#define TMIO_STAT_ILL_ACCESS BIT(31)
/* Definitions for values the CTL_SD_CARD_CLK_CTL register can take */
#define CLK_CTL_DIV_MASK 0xff
#define CLK_CTL_SCLKEN BIT(8)
/* Definitions for values the CTL_SD_MEM_CARD_OPT register can take */
#define CARD_OPT_WIDTH8 BIT(13)
#define CARD_OPT_WIDTH BIT(15)
#define TMIO_BBS 512 /* Boot block size */
/* Definitions for values the CTL_SDIO_STATUS register can take */
#define TMIO_SDIO_STAT_IOIRQ 0x0001
#define TMIO_SDIO_STAT_EXPUB52 0x4000
@ -97,6 +97,9 @@
#define TMIO_SDIO_SETBITS_MASK 0x0006
/* Definitions for values the CTL_DMA_ENABLE register can take */
#define DMA_ENABLE_DMASDRW BIT(1)
/* Define some IRQ masks */
/* This is the mask used at reset by the chip */
#define TMIO_MASK_ALL 0x837f031d
@ -122,6 +125,7 @@ struct tmio_mmc_dma_ops {
struct tmio_mmc_data *pdata);
void (*release)(struct tmio_mmc_host *host);
void (*abort)(struct tmio_mmc_host *host);
void (*dataend)(struct tmio_mmc_host *host);
};
struct tmio_mmc_host {
@ -151,6 +155,7 @@ struct tmio_mmc_host {
struct dma_chan *chan_rx;
struct dma_chan *chan_tx;
struct completion dma_dataend;
struct tasklet_struct dma_complete;
struct tasklet_struct dma_issue;
struct scatterlist bounce_sg;
u8 *bounce_buf;

View File

@ -87,6 +87,12 @@ static inline void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
host->dma_ops->abort(host);
}
static inline void tmio_mmc_dataend_dma(struct tmio_mmc_host *host)
{
if (host->dma_ops)
host->dma_ops->dataend(host);
}
void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i)
{
host->sdcard_irq_mask &= ~(i & TMIO_MASK_IRQ);
@ -201,7 +207,10 @@ static void tmio_mmc_clk_start(struct tmio_mmc_host *host)
{
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
msleep(host->pdata->flags & TMIO_MMC_MIN_RCAR2 ? 1 : 10);
/* HW engineers overrode docs: no sleep needed on R-Car2+ */
if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
msleep(10);
if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) {
sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100);
@ -218,7 +227,10 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
msleep(host->pdata->flags & TMIO_MMC_MIN_RCAR2 ? 5 : 10);
/* HW engineers overrode docs: no sleep needed on R-Car2+ */
if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
msleep(10);
}
static void tmio_mmc_set_clock(struct tmio_mmc_host *host,
@ -343,12 +355,6 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host,
int c = cmd->opcode;
u32 irq_mask = TMIO_MASK_CMD;
/* CMD12 is handled by hardware */
if (cmd->opcode == MMC_STOP_TRANSMISSION && !cmd->arg) {
sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, TMIO_STOP_STP);
return 0;
}
switch (mmc_resp_type(cmd)) {
case MMC_RSP_NONE: c |= RESP_NONE; break;
case MMC_RSP_R1:
@ -605,11 +611,11 @@ static void tmio_mmc_data_irq(struct tmio_mmc_host *host, unsigned int stat)
if (done) {
tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_DATAEND);
complete(&host->dma_dataend);
tmio_mmc_dataend_dma(host);
}
} else if (host->chan_rx && (data->flags & MMC_DATA_READ) && !host->force_pio) {
tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_DATAEND);
complete(&host->dma_dataend);
tmio_mmc_dataend_dma(host);
} else {
tmio_mmc_do_data_irq(host);
tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_READOP | TMIO_MASK_WRITEOP);
@ -1251,10 +1257,10 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
mmc->caps |= MMC_CAP_4_BIT_DATA | pdata->capabilities;
mmc->caps2 |= pdata->capabilities2;
mmc->max_segs = 32;
mmc->max_segs = pdata->max_segs ? : 32;
mmc->max_blk_size = 512;
mmc->max_blk_count = (PAGE_SIZE / mmc->max_blk_size) *
mmc->max_segs;
mmc->max_blk_count = pdata->max_blk_count ? :
(PAGE_SIZE / mmc->max_blk_size) * mmc->max_segs;
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
mmc->max_seg_size = mmc->max_req_size;

View File

@ -550,7 +550,7 @@ static int toshsd_get_cd(struct mmc_host *mmc)
return !!(ioread16(host->ioaddr + SD_CARDSTATUS) & SD_CARD_PRESENT_0);
}
static struct mmc_host_ops toshsd_ops = {
static const struct mmc_host_ops toshsd_ops = {
.request = toshsd_request,
.set_ios = toshsd_set_ios,
.get_ro = toshsd_get_ro,

View File

@ -1185,7 +1185,7 @@ static int usdhi6_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios)
return ret;
}
static struct mmc_host_ops usdhi6_ops = {
static const struct mmc_host_ops usdhi6_ops = {
.request = usdhi6_request,
.set_ios = usdhi6_set_ios,
.get_cd = usdhi6_get_cd,

View File

@ -323,7 +323,7 @@ struct via_crdr_mmc_host {
/* some devices need a very long delay for power to stabilize */
#define VIA_CRDR_QUIRK_300MS_PWRDELAY 0x0001
static struct pci_device_id via_ids[] = {
static const struct pci_device_id via_ids[] = {
{PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_9530,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,},
{0,}

View File

@ -266,7 +266,7 @@ MODULE_PARM_DESC(firmware_rom_wait_states,
#define ELAN_VENDOR_ID 0x2201
#define VUB300_VENDOR_ID 0x0424
#define VUB300_PRODUCT_ID 0x012C
static struct usb_device_id vub300_table[] = {
static const struct usb_device_id vub300_table[] = {
{USB_DEVICE(ELAN_VENDOR_ID, VUB300_PRODUCT_ID)},
{USB_DEVICE(VUB300_VENDOR_ID, VUB300_PRODUCT_ID)},
{} /* Terminating entry */
@ -2079,7 +2079,7 @@ static void vub300_init_card(struct mmc_host *mmc, struct mmc_card *card)
dev_info(&vub300->udev->dev, "NO host QUIRKS for this card\n");
}
static struct mmc_host_ops vub300_mmc_ops = {
static const struct mmc_host_ops vub300_mmc_ops = {
.request = vub300_mmc_request,
.set_ios = vub300_mmc_set_ios,
.get_ro = vub300_mmc_get_ro,

View File

@ -802,10 +802,8 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
break;
default:
#ifdef CONFIG_MMC_DEBUG
pr_warn("%s: Data command %d is not supported by this controller\n",
mmc_hostname(host->mmc), cmd->opcode);
#endif
cmd->error = -EINVAL;
goto done;

View File

@ -726,7 +726,7 @@ static int wmt_mci_get_cd(struct mmc_host *mmc)
return !(cd ^ priv->cd_inverted);
}
static struct mmc_host_ops wmt_mci_ops = {
static const struct mmc_host_ops wmt_mci_ops = {
.request = wmt_mci_request,
.set_ios = wmt_mci_set_ios,
.get_ro = wmt_mci_get_ro,
@ -856,7 +856,9 @@ static int wmt_mci_probe(struct platform_device *pdev)
goto fail5;
}
clk_prepare_enable(priv->clk_sdmmc);
ret = clk_prepare_enable(priv->clk_sdmmc);
if (ret)
goto fail6;
/* configure the controller to a known 'ready' state */
wmt_reset_hardware(mmc);
@ -866,6 +868,8 @@ static int wmt_mci_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "WMT SDHC Controller initialized\n");
return 0;
fail6:
clk_put(priv->clk_sdmmc);
fail5:
free_irq(dma_irq, priv);
fail4:

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2017 Chen-Yu Tsai. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _LINUX_CLK_SUNXI_NG_H_
#define _LINUX_CLK_SUNXI_NG_H_
#include <linux/errno.h>
#ifdef CONFIG_SUNXI_CCU
int sunxi_ccu_set_mmc_timing_mode(struct clk *clk, bool new_mode);
int sunxi_ccu_get_mmc_timing_mode(struct clk *clk);
#else
static inline int sunxi_ccu_set_mmc_timing_mode(struct clk *clk,
bool new_mode)
{
return -ENOTSUPP;
}
static inline int sunxi_ccu_get_mmc_timing_mode(struct clk *clk)
{
return -ENOTSUPP;
}
#endif
#endif

View File

@ -107,6 +107,9 @@
*/
#define TMIO_MMC_CLK_ACTUAL BIT(10)
/* Some controllers have a CBSY bit */
#define TMIO_MMC_HAVE_CBSY BIT(11)
int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base);
int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base);
void tmio_core_mmc_pwr(void __iomem *cnf, int shift, int state);
@ -128,6 +131,8 @@ struct tmio_mmc_data {
unsigned int cd_gpio;
int alignment_shift;
dma_addr_t dma_rx_offset;
unsigned int max_blk_count;
unsigned short max_segs;
void (*set_pwr)(struct platform_device *host, int state);
void (*set_clk_div)(struct platform_device *host, int state);
};

View File

@ -29,8 +29,8 @@ struct mmc_csd {
unsigned char structure;
unsigned char mmca_vsn;
unsigned short cmdclass;
unsigned short tacc_clks;
unsigned int tacc_ns;
unsigned short taac_clks;
unsigned int taac_ns;
unsigned int c_size;
unsigned int r2w_factor;
unsigned int max_dtr;

View File

@ -122,11 +122,18 @@ struct mmc_data {
unsigned int timeout_clks; /* data timeout (in clocks) */
unsigned int blksz; /* data block size */
unsigned int blocks; /* number of blocks */
unsigned int blk_addr; /* block address */
int error; /* data error */
unsigned int flags;
#define MMC_DATA_WRITE (1 << 8)
#define MMC_DATA_READ (1 << 9)
#define MMC_DATA_WRITE BIT(8)
#define MMC_DATA_READ BIT(9)
/* Extra flags used by CQE */
#define MMC_DATA_QBR BIT(10) /* CQE queue barrier*/
#define MMC_DATA_PRIO BIT(11) /* CQE high priority */
#define MMC_DATA_REL_WR BIT(12) /* Reliable write */
#define MMC_DATA_DAT_TAG BIT(13) /* Tag request */
#define MMC_DATA_FORCED_PRG BIT(14) /* Forced programming */
unsigned int bytes_xfered;
@ -149,18 +156,22 @@ struct mmc_request {
struct completion completion;
struct completion cmd_completion;
void (*done)(struct mmc_request *);/* completion function */
/*
* Notify uppers layers (e.g. mmc block driver) that recovery is needed
* due to an error associated with the mmc_request. Currently used only
* by CQE.
*/
void (*recovery_notifier)(struct mmc_request *);
struct mmc_host *host;
/* Allow other commands during this ongoing data transfer or busy wait */
bool cap_cmd_during_tfr;
int tag;
};
struct mmc_card;
struct mmc_async_req;
struct mmc_async_req *mmc_start_areq(struct mmc_host *host,
struct mmc_async_req *areq,
enum mmc_blk_status *ret_stat);
void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq);
int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd,
int retries);

View File

@ -162,6 +162,50 @@ struct mmc_host_ops {
unsigned int direction, int blk_size);
};
struct mmc_cqe_ops {
/* Allocate resources, and make the CQE operational */
int (*cqe_enable)(struct mmc_host *host, struct mmc_card *card);
/* Free resources, and make the CQE non-operational */
void (*cqe_disable)(struct mmc_host *host);
/*
* Issue a read, write or DCMD request to the CQE. Also deal with the
* effect of ->cqe_off().
*/
int (*cqe_request)(struct mmc_host *host, struct mmc_request *mrq);
/* Free resources (e.g. DMA mapping) associated with the request */
void (*cqe_post_req)(struct mmc_host *host, struct mmc_request *mrq);
/*
* Prepare the CQE and host controller to accept non-CQ commands. There
* is no corresponding ->cqe_on(), instead ->cqe_request() is required
* to deal with that.
*/
void (*cqe_off)(struct mmc_host *host);
/*
* Wait for all CQE tasks to complete. Return an error if recovery
* becomes necessary.
*/
int (*cqe_wait_for_idle)(struct mmc_host *host);
/*
* Notify CQE that a request has timed out. Return false if the request
* completed or true if a timeout happened in which case indicate if
* recovery is needed.
*/
bool (*cqe_timeout)(struct mmc_host *host, struct mmc_request *mrq,
bool *recovery_needed);
/*
* Stop all CQE activity and prepare the CQE and host controller to
* accept recovery commands.
*/
void (*cqe_recovery_start)(struct mmc_host *host);
/*
* Clear the queue and call mmc_cqe_request_done() on all requests.
* Requests that errored will have the error set on the mmc_request
* (data->error or cmd->error for DCMD). Requests that did not error
* will have zero data bytes transferred.
*/
void (*cqe_recovery_finish)(struct mmc_host *host);
};
struct mmc_async_req {
/* active mmc request */
struct mmc_request *mrq;
@ -291,10 +335,6 @@ struct mmc_host {
MMC_CAP2_HS200_1_2V_SDR)
#define MMC_CAP2_CD_ACTIVE_HIGH (1 << 10) /* Card-detect signal active high */
#define MMC_CAP2_RO_ACTIVE_HIGH (1 << 11) /* Write-protect signal active high */
#define MMC_CAP2_PACKED_RD (1 << 12) /* Allow packed read */
#define MMC_CAP2_PACKED_WR (1 << 13) /* Allow packed write */
#define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \
MMC_CAP2_PACKED_WR)
#define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14) /* Don't power up before scan */
#define MMC_CAP2_HS400_1_8V (1 << 15) /* Can support HS400 1.8V */
#define MMC_CAP2_HS400_1_2V (1 << 16) /* Can support HS400 1.2V */
@ -307,6 +347,8 @@ struct mmc_host {
#define MMC_CAP2_HS400_ES (1 << 20) /* Host supports enhanced strobe */
#define MMC_CAP2_NO_SD (1 << 21) /* Do not send SD commands during initialization */
#define MMC_CAP2_NO_MMC (1 << 22) /* Do not send (e)MMC commands during initialization */
#define MMC_CAP2_CQE (1 << 23) /* Has eMMC command queue engine */
#define MMC_CAP2_CQE_DCMD (1 << 24) /* CQE can issue a direct command */
mmc_pm_flag_t pm_caps; /* supported pm features */
@ -328,9 +370,6 @@ struct mmc_host {
unsigned int use_spi_crc:1;
unsigned int claimed:1; /* host exclusively claimed */
unsigned int bus_dead:1; /* bus has been released */
#ifdef CONFIG_MMC_DEBUG
unsigned int removed:1; /* host is being removed */
#endif
unsigned int can_retune:1; /* re-tuning can be used */
unsigned int doing_retune:1; /* re-tuning in progress */
unsigned int retune_now:1; /* do re-tuning at next req */
@ -393,6 +432,13 @@ struct mmc_host {
int dsr_req; /* DSR value is valid */
u32 dsr; /* optional driver stage (DSR) value */
/* Command Queue Engine (CQE) support */
const struct mmc_cqe_ops *cqe_ops;
void *cqe_private;
int cqe_qdepth;
bool cqe_enabled;
bool cqe_on;
unsigned long private[0] ____cacheline_aligned;
};

View File

@ -29,8 +29,10 @@ TRACE_EVENT(mmc_request_start,
__field(unsigned int, sbc_flags)
__field(unsigned int, sbc_retries)
__field(unsigned int, blocks)
__field(unsigned int, blk_addr)
__field(unsigned int, blksz)
__field(unsigned int, data_flags)
__field(int, tag)
__field(unsigned int, can_retune)
__field(unsigned int, doing_retune)
__field(unsigned int, retune_now)
@ -42,10 +44,10 @@ TRACE_EVENT(mmc_request_start,
),
TP_fast_assign(
__entry->cmd_opcode = mrq->cmd->opcode;
__entry->cmd_arg = mrq->cmd->arg;
__entry->cmd_flags = mrq->cmd->flags;
__entry->cmd_retries = mrq->cmd->retries;
__entry->cmd_opcode = mrq->cmd ? mrq->cmd->opcode : 0;
__entry->cmd_arg = mrq->cmd ? mrq->cmd->arg : 0;
__entry->cmd_flags = mrq->cmd ? mrq->cmd->flags : 0;
__entry->cmd_retries = mrq->cmd ? mrq->cmd->retries : 0;
__entry->stop_opcode = mrq->stop ? mrq->stop->opcode : 0;
__entry->stop_arg = mrq->stop ? mrq->stop->arg : 0;
__entry->stop_flags = mrq->stop ? mrq->stop->flags : 0;
@ -56,7 +58,9 @@ TRACE_EVENT(mmc_request_start,
__entry->sbc_retries = mrq->sbc ? mrq->sbc->retries : 0;
__entry->blksz = mrq->data ? mrq->data->blksz : 0;
__entry->blocks = mrq->data ? mrq->data->blocks : 0;
__entry->blk_addr = mrq->data ? mrq->data->blk_addr : 0;
__entry->data_flags = mrq->data ? mrq->data->flags : 0;
__entry->tag = mrq->tag;
__entry->can_retune = host->can_retune;
__entry->doing_retune = host->doing_retune;
__entry->retune_now = host->retune_now;
@ -71,8 +75,8 @@ TRACE_EVENT(mmc_request_start,
"cmd_opcode=%u cmd_arg=0x%x cmd_flags=0x%x cmd_retries=%u "
"stop_opcode=%u stop_arg=0x%x stop_flags=0x%x stop_retries=%u "
"sbc_opcode=%u sbc_arg=0x%x sbc_flags=0x%x sbc_retires=%u "
"blocks=%u block_size=%u data_flags=0x%x "
"can_retune=%u doing_retune=%u retune_now=%u "
"blocks=%u block_size=%u blk_addr=%u data_flags=0x%x "
"tag=%d can_retune=%u doing_retune=%u retune_now=%u "
"need_retune=%d hold_retune=%d retune_period=%u",
__get_str(name), __entry->mrq,
__entry->cmd_opcode, __entry->cmd_arg,
@ -81,7 +85,8 @@ TRACE_EVENT(mmc_request_start,
__entry->stop_flags, __entry->stop_retries,
__entry->sbc_opcode, __entry->sbc_arg,
__entry->sbc_flags, __entry->sbc_retries,
__entry->blocks, __entry->blksz, __entry->data_flags,
__entry->blocks, __entry->blk_addr,
__entry->blksz, __entry->data_flags, __entry->tag,
__entry->can_retune, __entry->doing_retune,
__entry->retune_now, __entry->need_retune,
__entry->hold_retune, __entry->retune_period)
@ -108,6 +113,7 @@ TRACE_EVENT(mmc_request_done,
__field(unsigned int, sbc_retries)
__field(unsigned int, bytes_xfered)
__field(int, data_err)
__field(int, tag)
__field(unsigned int, can_retune)
__field(unsigned int, doing_retune)
__field(unsigned int, retune_now)
@ -119,10 +125,13 @@ TRACE_EVENT(mmc_request_done,
),
TP_fast_assign(
__entry->cmd_opcode = mrq->cmd->opcode;
__entry->cmd_err = mrq->cmd->error;
memcpy(__entry->cmd_resp, mrq->cmd->resp, 4);
__entry->cmd_retries = mrq->cmd->retries;
__entry->cmd_opcode = mrq->cmd ? mrq->cmd->opcode : 0;
__entry->cmd_err = mrq->cmd ? mrq->cmd->error : 0;
__entry->cmd_resp[0] = mrq->cmd ? mrq->cmd->resp[0] : 0;
__entry->cmd_resp[1] = mrq->cmd ? mrq->cmd->resp[1] : 0;
__entry->cmd_resp[2] = mrq->cmd ? mrq->cmd->resp[2] : 0;
__entry->cmd_resp[3] = mrq->cmd ? mrq->cmd->resp[3] : 0;
__entry->cmd_retries = mrq->cmd ? mrq->cmd->retries : 0;
__entry->stop_opcode = mrq->stop ? mrq->stop->opcode : 0;
__entry->stop_err = mrq->stop ? mrq->stop->error : 0;
__entry->stop_resp[0] = mrq->stop ? mrq->stop->resp[0] : 0;
@ -139,6 +148,7 @@ TRACE_EVENT(mmc_request_done,
__entry->sbc_retries = mrq->sbc ? mrq->sbc->retries : 0;
__entry->bytes_xfered = mrq->data ? mrq->data->bytes_xfered : 0;
__entry->data_err = mrq->data ? mrq->data->error : 0;
__entry->tag = mrq->tag;
__entry->can_retune = host->can_retune;
__entry->doing_retune = host->doing_retune;
__entry->retune_now = host->retune_now;
@ -154,7 +164,7 @@ TRACE_EVENT(mmc_request_done,
"cmd_retries=%u stop_opcode=%u stop_err=%d "
"stop_resp=0x%x 0x%x 0x%x 0x%x stop_retries=%u "
"sbc_opcode=%u sbc_err=%d sbc_resp=0x%x 0x%x 0x%x 0x%x "
"sbc_retries=%u bytes_xfered=%u data_err=%d "
"sbc_retries=%u bytes_xfered=%u data_err=%d tag=%d "
"can_retune=%u doing_retune=%u retune_now=%u need_retune=%d "
"hold_retune=%d retune_period=%u",
__get_str(name), __entry->mrq,
@ -170,7 +180,7 @@ TRACE_EVENT(mmc_request_done,
__entry->sbc_resp[0], __entry->sbc_resp[1],
__entry->sbc_resp[2], __entry->sbc_resp[3],
__entry->sbc_retries,
__entry->bytes_xfered, __entry->data_err,
__entry->bytes_xfered, __entry->data_err, __entry->tag,
__entry->can_retune, __entry->doing_retune,
__entry->retune_now, __entry->need_retune,
__entry->hold_retune, __entry->retune_period)