mirror of
https://github.com/t2linux/kernel.git
synced 2026-04-30 13:48:59 -07:00
Merge tag 'mmc-updates-for-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc
Pull MMC update from Chris Ball:
"MMC highlights for 3.9:
Core:
- Support for packed commands in eMMC 4.5. (This requires a host
capability to be turned on. It increases write throughput by 20%+,
but may also increase average write latency; more testing needed.)
- Add DT bindings for capability flags.
- Add mmc_of_parse() for shared DT parsing between drivers.
Drivers:
- android-goldfish: New MMC driver for the Android Goldfish emulator.
- mvsdio: Add DT bindings, pinctrl, use slot-gpio for card detection.
- omap_hsmmc: Fix boot hangs with RPMB partitions.
- sdhci-bcm2835: New driver for controller used by Raspberry Pi.
- sdhci-esdhc-imx: Add 8-bit data, auto CMD23 support, use slot-gpio.
- sh_mmcif: Add support for eMMC DDR, bundled MMCIF IRQs.
- tmio_mmc: Add DT bindings, support for vccq regulator"
* tag 'mmc-updates-for-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (92 commits)
mmc: tegra: assume CONFIG_OF, remove platform data
mmc: add DT bindings for more MMC capability flags
mmc: tmio: add support for the VccQ regulator
mmc: tmio: remove unused and deprecated symbols
mmc: sh_mobile_sdhi: use managed resource allocations
mmc: sh_mobile_sdhi: remove unused .pdata field
mmc: tmio-mmc: parse device-tree bindings
mmc: tmio-mmc: define device-tree bindings
mmc: sh_mmcif: use mmc_of_parse() to parse standard MMC DT bindings
mmc: (cosmetic) remove "extern" from function declarations
mmc: provide a standard MMC device-tree binding parser centrally
mmc: detailed definition of CD and WP MMC line polarities in DT
mmc: sdhi, tmio: only check flags in tmio-mmc driver proper
mmc: sdhci: Fix parameter of sdhci_do_start_signal_voltage_switch()
mmc: sdhci: check voltage range only on regulators aware of voltage value
mmc: bcm2835: set SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK
mmc: support packed write command for eMMC4.5 devices
mmc: add packed command feature of eMMC4.5
mmc: rtsx: remove driving adjustment
mmc: use regulator_can_change_voltage() instead of regulator_count_voltages
...
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
Broadcom BCM2835 SDHCI controller
|
||||
|
||||
This file documents differences between the core properties described
|
||||
by mmc.txt and the properties that represent the BCM2835 controller.
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "brcm,bcm2835-sdhci".
|
||||
- clocks : The clock feeding the SDHCI controller.
|
||||
|
||||
Example:
|
||||
|
||||
sdhci: sdhci {
|
||||
compatible = "brcm,bcm2835-sdhci";
|
||||
reg = <0x7e300000 0x100>;
|
||||
interrupts = <2 30>;
|
||||
clocks = <&clk_mmc>;
|
||||
bus-width = <4>;
|
||||
};
|
||||
@@ -6,23 +6,45 @@ Interpreted by the OF core:
|
||||
- reg: Registers location and length.
|
||||
- interrupts: Interrupts used by the MMC controller.
|
||||
|
||||
Required properties:
|
||||
- bus-width: Number of data lines, can be <1>, <4>, or <8>
|
||||
|
||||
Card detection:
|
||||
If no property below is supplied, standard SDHCI card detect is used.
|
||||
If no property below is supplied, host native card detect is used.
|
||||
Only one of the properties in this section should be supplied:
|
||||
- broken-cd: There is no card detection available; polling must be used.
|
||||
- cd-gpios: Specify GPIOs for card detection, see gpio binding
|
||||
- non-removable: non-removable slot (like eMMC); assume always present.
|
||||
|
||||
Optional properties:
|
||||
- bus-width: Number of data lines, can be <1>, <4>, or <8>. The default
|
||||
will be <1> if the property is absent.
|
||||
- wp-gpios: Specify GPIOs for write protection, see gpio binding
|
||||
- cd-inverted: when present, polarity on the cd gpio line is inverted
|
||||
- wp-inverted: when present, polarity on the wp gpio line is inverted
|
||||
- cd-inverted: when present, polarity on the CD line is inverted. See the note
|
||||
below for the case, when a GPIO is used for the CD line
|
||||
- wp-inverted: when present, polarity on the WP line is inverted. See the note
|
||||
below for the case, when a GPIO is used for the WP line
|
||||
- max-frequency: maximum operating clock frequency
|
||||
- no-1-8-v: when present, denotes that 1.8v card voltage is not supported on
|
||||
this system, even if the controller claims it is.
|
||||
- cap-sd-highspeed: SD high-speed timing is supported
|
||||
- cap-mmc-highspeed: MMC high-speed timing is supported
|
||||
- cap-power-off-card: powering off the card is safe
|
||||
- cap-sdio-irq: enable SDIO IRQ signalling on this interface
|
||||
|
||||
*NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
|
||||
polarity properties, we have to fix the meaning of the "normal" and "inverted"
|
||||
line levels. We choose to follow the SDHCI standard, which specifies both those
|
||||
lines as "active low." Therefore, using the "cd-inverted" property means, that
|
||||
the CD line is active high, i.e. it is high, when a card is inserted. Similar
|
||||
logic applies to the "wp-inverted" property.
|
||||
|
||||
CD and WP lines can be implemented on the hardware in one of two ways: as GPIOs,
|
||||
specified in cd-gpios and wp-gpios properties, or as dedicated pins. Polarity of
|
||||
dedicated pins can be specified, using *-inverted properties. GPIO polarity can
|
||||
also be specified using the OF_GPIO_ACTIVE_LOW flag. This creates an ambiguity
|
||||
in the latter case. We choose to use the XOR logic for GPIO CD and WP lines.
|
||||
This means, the two properties are "superimposed," for example leaving the
|
||||
OF_GPIO_ACTIVE_LOW flag clear and specifying the respective *-inverted
|
||||
property results in a double-inversion and actually means the "normal" line
|
||||
polarity is in effect.
|
||||
|
||||
Optional SDIO properties:
|
||||
- keep-power-in-suspend: Preserves card power during a suspend/resume cycle
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
* Marvell orion-sdio controller
|
||||
|
||||
This file documents differences between the core properties in mmc.txt
|
||||
and the properties used by the orion-sdio driver.
|
||||
|
||||
- compatible: Should be "marvell,orion-sdio"
|
||||
- clocks: reference to the clock of the SDIO interface
|
||||
|
||||
Example:
|
||||
|
||||
mvsdio@d00d4000 {
|
||||
compatible = "marvell,orion-sdio";
|
||||
reg = <0xd00d4000 0x200>;
|
||||
interrupts = <54>;
|
||||
clocks = <&gateclk 17>;
|
||||
status = "disabled";
|
||||
};
|
||||
@@ -26,8 +26,16 @@ Required Properties:
|
||||
* bus-width: as documented in mmc core bindings.
|
||||
|
||||
* wp-gpios: specifies the write protect gpio line. The format of the
|
||||
gpio specifier depends on the gpio controller. If the write-protect
|
||||
line is not available, this property is optional.
|
||||
gpio specifier depends on the gpio controller. If a GPIO is not used
|
||||
for write-protect, this property is optional.
|
||||
|
||||
* disable-wp: If the wp-gpios property isn't present then (by default)
|
||||
we'd assume that the write protect is hooked up directly to the
|
||||
controller's special purpose write protect line (accessible via
|
||||
the WRTPRT register). However, it's possible that we simply don't
|
||||
want write protect. In that case specify 'disable-wp'.
|
||||
NOTE: This property is not required for slots known to always
|
||||
connect to eMMC or SDIO cards.
|
||||
|
||||
Optional properties:
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
* Toshiba Mobile IO SD/MMC controller
|
||||
|
||||
The tmio-mmc driver doesn't probe its devices actively, instead its binding to
|
||||
devices is managed by either MFD drivers or by the sh_mobile_sdhi platform
|
||||
driver. Those drivers supply the tmio-mmc driver with platform data, that either
|
||||
describe hardware capabilities, known to them, or are obtained by them from
|
||||
their own platform data or from their DT information. In the latter case all
|
||||
compulsory and any optional properties, common to all SD/MMC drivers, as
|
||||
described in mmc.txt, can be used. Additionally the following tmio_mmc-specific
|
||||
optional bindings can be used.
|
||||
|
||||
Optional properties:
|
||||
- toshiba,mmc-wrprotect-disable: write-protect detection is unavailable
|
||||
|
||||
When used with Renesas SDHI hardware, the following compatibility strings
|
||||
configure various model-specific properties:
|
||||
|
||||
"renesas,sh7372-sdhi": (default) compatible with SH7372
|
||||
"renesas,r8a7740-sdhi": compatible with R8A7740: certain MMC/SD commands have to
|
||||
wait for the interface to become idle.
|
||||
+9
-1
@@ -5692,7 +5692,7 @@ S: Maintained
|
||||
F: drivers/mmc/host/omap.c
|
||||
|
||||
OMAP HS MMC SUPPORT
|
||||
M: Venkatraman S <svenkatr@ti.com>
|
||||
M: Balaji T K <balajitk@ti.com>
|
||||
L: linux-mmc@vger.kernel.org
|
||||
L: linux-omap@vger.kernel.org
|
||||
S: Maintained
|
||||
@@ -6804,6 +6804,14 @@ F: include/linux/dw_dmac.h
|
||||
F: drivers/dma/dw_dmac_regs.h
|
||||
F: drivers/dma/dw_dmac.c
|
||||
|
||||
SYNOPSYS DESIGNWARE MMC/SD/SDIO DRIVER
|
||||
M: Seungwon Jeon <tgih.jun@samsung.com>
|
||||
M: Jaehoon Chung <jh80.chung@samsung.com>
|
||||
L: linux-mmc@vger.kernel.org
|
||||
S: Maintained
|
||||
F: include/linux/mmc/dw_mmc.h
|
||||
F: drivers/mmc/host/dw_mmc*
|
||||
|
||||
TIMEKEEPING, NTP
|
||||
M: John Stultz <john.stultz@linaro.org>
|
||||
M: Thomas Gleixner <tglx@linutronix.de>
|
||||
|
||||
@@ -151,6 +151,7 @@
|
||||
reg = <0>;
|
||||
bus-width = <4>;
|
||||
samsung,cd-pinmux-gpio = <&gpc3 2 2 3 3>;
|
||||
disable-wp;
|
||||
gpios = <&gpc3 0 2 0 3>, <&gpc3 1 2 0 3>,
|
||||
<&gpc3 3 2 3 3>, <&gpc3 4 2 3 3>,
|
||||
<&gpc3 5 2 3 3>, <&gpc3 6 2 3 3>,
|
||||
|
||||
+464
-27
File diff suppressed because it is too large
Load Diff
+123
-5
@@ -22,7 +22,8 @@
|
||||
|
||||
#define MMC_QUEUE_BOUNCESZ 65536
|
||||
|
||||
#define MMC_QUEUE_SUSPENDED (1 << 0)
|
||||
|
||||
#define MMC_REQ_SPECIAL_MASK (REQ_DISCARD | REQ_FLUSH)
|
||||
|
||||
/*
|
||||
* Prepare a MMC request. This just filters out odd stuff.
|
||||
@@ -58,6 +59,7 @@ static int mmc_queue_thread(void *d)
|
||||
do {
|
||||
struct request *req = NULL;
|
||||
struct mmc_queue_req *tmp;
|
||||
unsigned int cmd_flags = 0;
|
||||
|
||||
spin_lock_irq(q->queue_lock);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
@@ -67,12 +69,23 @@ static int mmc_queue_thread(void *d)
|
||||
|
||||
if (req || mq->mqrq_prev->req) {
|
||||
set_current_state(TASK_RUNNING);
|
||||
cmd_flags = req ? req->cmd_flags : 0;
|
||||
mq->issue_fn(mq, req);
|
||||
if (mq->flags & MMC_QUEUE_NEW_REQUEST) {
|
||||
mq->flags &= ~MMC_QUEUE_NEW_REQUEST;
|
||||
continue; /* fetch again */
|
||||
}
|
||||
|
||||
/*
|
||||
* Current request becomes previous request
|
||||
* and vice versa.
|
||||
* In case of special requests, current request
|
||||
* has been finished. Do not assign it to previous
|
||||
* request.
|
||||
*/
|
||||
if (cmd_flags & MMC_REQ_SPECIAL_MASK)
|
||||
mq->mqrq_cur->req = NULL;
|
||||
|
||||
mq->mqrq_prev->brq.mrq.data = NULL;
|
||||
mq->mqrq_prev->req = NULL;
|
||||
tmp = mq->mqrq_prev;
|
||||
@@ -103,6 +116,8 @@ static void mmc_request_fn(struct request_queue *q)
|
||||
{
|
||||
struct mmc_queue *mq = q->queuedata;
|
||||
struct request *req;
|
||||
unsigned long flags;
|
||||
struct mmc_context_info *cntx;
|
||||
|
||||
if (!mq) {
|
||||
while ((req = blk_fetch_request(q)) != NULL) {
|
||||
@@ -112,7 +127,20 @@ static void mmc_request_fn(struct request_queue *q)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mq->mqrq_cur->req && !mq->mqrq_prev->req)
|
||||
cntx = &mq->card->host->context_info;
|
||||
if (!mq->mqrq_cur->req && mq->mqrq_prev->req) {
|
||||
/*
|
||||
* New MMC request arrived when MMC thread may be
|
||||
* blocked on the previous request to be complete
|
||||
* with no current request fetched
|
||||
*/
|
||||
spin_lock_irqsave(&cntx->lock, flags);
|
||||
if (cntx->is_waiting_last_req) {
|
||||
cntx->is_new_req = true;
|
||||
wake_up_interruptible(&cntx->wait);
|
||||
}
|
||||
spin_unlock_irqrestore(&cntx->lock, flags);
|
||||
} else if (!mq->mqrq_cur->req && !mq->mqrq_prev->req)
|
||||
wake_up_process(mq->thread);
|
||||
}
|
||||
|
||||
@@ -334,6 +362,49 @@ void mmc_cleanup_queue(struct mmc_queue *mq)
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_cleanup_queue);
|
||||
|
||||
int mmc_packed_init(struct mmc_queue *mq, struct mmc_card *card)
|
||||
{
|
||||
struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
|
||||
struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
|
||||
int ret = 0;
|
||||
|
||||
|
||||
mqrq_cur->packed = kzalloc(sizeof(struct mmc_packed), GFP_KERNEL);
|
||||
if (!mqrq_cur->packed) {
|
||||
pr_warn("%s: unable to allocate packed cmd for mqrq_cur\n",
|
||||
mmc_card_name(card));
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mqrq_prev->packed = kzalloc(sizeof(struct mmc_packed), GFP_KERNEL);
|
||||
if (!mqrq_prev->packed) {
|
||||
pr_warn("%s: unable to allocate packed cmd for mqrq_prev\n",
|
||||
mmc_card_name(card));
|
||||
kfree(mqrq_cur->packed);
|
||||
mqrq_cur->packed = NULL;
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&mqrq_cur->packed->list);
|
||||
INIT_LIST_HEAD(&mqrq_prev->packed->list);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mmc_packed_clean(struct mmc_queue *mq)
|
||||
{
|
||||
struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
|
||||
struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
|
||||
|
||||
kfree(mqrq_cur->packed);
|
||||
mqrq_cur->packed = NULL;
|
||||
kfree(mqrq_prev->packed);
|
||||
mqrq_prev->packed = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* mmc_queue_suspend - suspend a MMC request queue
|
||||
* @mq: MMC queue to suspend
|
||||
@@ -378,6 +449,41 @@ void mmc_queue_resume(struct mmc_queue *mq)
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int mmc_queue_packed_map_sg(struct mmc_queue *mq,
|
||||
struct mmc_packed *packed,
|
||||
struct scatterlist *sg,
|
||||
enum mmc_packed_type cmd_type)
|
||||
{
|
||||
struct scatterlist *__sg = sg;
|
||||
unsigned int sg_len = 0;
|
||||
struct request *req;
|
||||
|
||||
if (mmc_packed_wr(cmd_type)) {
|
||||
unsigned int hdr_sz = mmc_large_sector(mq->card) ? 4096 : 512;
|
||||
unsigned int max_seg_sz = queue_max_segment_size(mq->queue);
|
||||
unsigned int len, remain, offset = 0;
|
||||
u8 *buf = (u8 *)packed->cmd_hdr;
|
||||
|
||||
remain = hdr_sz;
|
||||
do {
|
||||
len = min(remain, max_seg_sz);
|
||||
sg_set_buf(__sg, buf + offset, len);
|
||||
offset += len;
|
||||
remain -= len;
|
||||
(__sg++)->page_link &= ~0x02;
|
||||
sg_len++;
|
||||
} while (remain);
|
||||
}
|
||||
|
||||
list_for_each_entry(req, &packed->list, queuelist) {
|
||||
sg_len += blk_rq_map_sg(mq->queue, req, __sg);
|
||||
__sg = sg + (sg_len - 1);
|
||||
(__sg++)->page_link &= ~0x02;
|
||||
}
|
||||
sg_mark_end(sg + (sg_len - 1));
|
||||
return sg_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare the sg list(s) to be handed of to the host driver
|
||||
*/
|
||||
@@ -386,14 +492,26 @@ unsigned int mmc_queue_map_sg(struct mmc_queue *mq, struct mmc_queue_req *mqrq)
|
||||
unsigned int sg_len;
|
||||
size_t buflen;
|
||||
struct scatterlist *sg;
|
||||
enum mmc_packed_type cmd_type;
|
||||
int i;
|
||||
|
||||
if (!mqrq->bounce_buf)
|
||||
return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
|
||||
cmd_type = mqrq->cmd_type;
|
||||
|
||||
if (!mqrq->bounce_buf) {
|
||||
if (mmc_packed_cmd(cmd_type))
|
||||
return mmc_queue_packed_map_sg(mq, mqrq->packed,
|
||||
mqrq->sg, cmd_type);
|
||||
else
|
||||
return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
|
||||
}
|
||||
|
||||
BUG_ON(!mqrq->bounce_sg);
|
||||
|
||||
sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
|
||||
if (mmc_packed_cmd(cmd_type))
|
||||
sg_len = mmc_queue_packed_map_sg(mq, mqrq->packed,
|
||||
mqrq->bounce_sg, cmd_type);
|
||||
else
|
||||
sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
|
||||
|
||||
mqrq->bounce_sg_len = sg_len;
|
||||
|
||||
|
||||
@@ -12,6 +12,23 @@ struct mmc_blk_request {
|
||||
struct mmc_data data;
|
||||
};
|
||||
|
||||
enum mmc_packed_type {
|
||||
MMC_PACKED_NONE = 0,
|
||||
MMC_PACKED_WRITE,
|
||||
};
|
||||
|
||||
#define mmc_packed_cmd(type) ((type) != MMC_PACKED_NONE)
|
||||
#define mmc_packed_wr(type) ((type) == MMC_PACKED_WRITE)
|
||||
|
||||
struct mmc_packed {
|
||||
struct list_head list;
|
||||
u32 cmd_hdr[1024];
|
||||
unsigned int blocks;
|
||||
u8 nr_entries;
|
||||
u8 retries;
|
||||
s16 idx_failure;
|
||||
};
|
||||
|
||||
struct mmc_queue_req {
|
||||
struct request *req;
|
||||
struct mmc_blk_request brq;
|
||||
@@ -20,6 +37,8 @@ struct mmc_queue_req {
|
||||
struct scatterlist *bounce_sg;
|
||||
unsigned int bounce_sg_len;
|
||||
struct mmc_async_req mmc_active;
|
||||
enum mmc_packed_type cmd_type;
|
||||
struct mmc_packed *packed;
|
||||
};
|
||||
|
||||
struct mmc_queue {
|
||||
@@ -27,6 +46,9 @@ struct mmc_queue {
|
||||
struct task_struct *thread;
|
||||
struct semaphore thread_sem;
|
||||
unsigned int flags;
|
||||
#define MMC_QUEUE_SUSPENDED (1 << 0)
|
||||
#define MMC_QUEUE_NEW_REQUEST (1 << 1)
|
||||
|
||||
int (*issue_fn)(struct mmc_queue *, struct request *);
|
||||
void *data;
|
||||
struct request_queue *queue;
|
||||
@@ -46,4 +68,7 @@ extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
|
||||
extern void mmc_queue_bounce_pre(struct mmc_queue_req *);
|
||||
extern void mmc_queue_bounce_post(struct mmc_queue_req *);
|
||||
|
||||
extern int mmc_packed_init(struct mmc_queue *, struct mmc_card *);
|
||||
extern void mmc_packed_clean(struct mmc_queue *);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -321,6 +321,7 @@ int mmc_add_card(struct mmc_card *card)
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
mmc_add_card_debugfs(card);
|
||||
#endif
|
||||
mmc_init_context_info(card->host);
|
||||
|
||||
ret = device_add(&card->dev);
|
||||
if (ret)
|
||||
|
||||
+219
-27
@@ -319,11 +319,45 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_start_bkops);
|
||||
|
||||
/*
|
||||
* mmc_wait_data_done() - done callback for data request
|
||||
* @mrq: done data request
|
||||
*
|
||||
* Wakes up mmc context, passed as a callback to host controller driver
|
||||
*/
|
||||
static void mmc_wait_data_done(struct mmc_request *mrq)
|
||||
{
|
||||
mrq->host->context_info.is_done_rcv = true;
|
||||
wake_up_interruptible(&mrq->host->context_info.wait);
|
||||
}
|
||||
|
||||
static void mmc_wait_done(struct mmc_request *mrq)
|
||||
{
|
||||
complete(&mrq->completion);
|
||||
}
|
||||
|
||||
/*
|
||||
*__mmc_start_data_req() - starts data request
|
||||
* @host: MMC host to start the request
|
||||
* @mrq: data request to start
|
||||
*
|
||||
* Sets the done callback to be called when request is completed by the card.
|
||||
* Starts data mmc request execution
|
||||
*/
|
||||
static int __mmc_start_data_req(struct mmc_host *host, struct mmc_request *mrq)
|
||||
{
|
||||
mrq->done = mmc_wait_data_done;
|
||||
mrq->host = host;
|
||||
if (mmc_card_removed(host->card)) {
|
||||
mrq->cmd->error = -ENOMEDIUM;
|
||||
mmc_wait_data_done(mrq);
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
mmc_start_request(host, mrq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
|
||||
{
|
||||
init_completion(&mrq->completion);
|
||||
@@ -337,6 +371,62 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* mmc_wait_for_data_req_done() - wait for request completed
|
||||
* @host: MMC host to prepare the command.
|
||||
* @mrq: MMC request to wait for
|
||||
*
|
||||
* Blocks MMC context till host controller will ack end of data request
|
||||
* execution or new request notification arrives from the block layer.
|
||||
* Handles command retries.
|
||||
*
|
||||
* Returns enum mmc_blk_status after checking errors.
|
||||
*/
|
||||
static int mmc_wait_for_data_req_done(struct mmc_host *host,
|
||||
struct mmc_request *mrq,
|
||||
struct mmc_async_req *next_req)
|
||||
{
|
||||
struct mmc_command *cmd;
|
||||
struct mmc_context_info *context_info = &host->context_info;
|
||||
int err;
|
||||
unsigned long flags;
|
||||
|
||||
while (1) {
|
||||
wait_event_interruptible(context_info->wait,
|
||||
(context_info->is_done_rcv ||
|
||||
context_info->is_new_req));
|
||||
spin_lock_irqsave(&context_info->lock, flags);
|
||||
context_info->is_waiting_last_req = false;
|
||||
spin_unlock_irqrestore(&context_info->lock, flags);
|
||||
if (context_info->is_done_rcv) {
|
||||
context_info->is_done_rcv = false;
|
||||
context_info->is_new_req = false;
|
||||
cmd = mrq->cmd;
|
||||
if (!cmd->error || !cmd->retries ||
|
||||
mmc_card_removed(host->card)) {
|
||||
err = host->areq->err_check(host->card,
|
||||
host->areq);
|
||||
break; /* return err */
|
||||
} else {
|
||||
pr_info("%s: req failed (CMD%u): %d, retrying...\n",
|
||||
mmc_hostname(host),
|
||||
cmd->opcode, cmd->error);
|
||||
cmd->retries--;
|
||||
cmd->error = 0;
|
||||
host->ops->request(host, mrq);
|
||||
continue; /* wait for done/new event again */
|
||||
}
|
||||
} else if (context_info->is_new_req) {
|
||||
context_info->is_new_req = false;
|
||||
if (!next_req) {
|
||||
err = MMC_BLK_NEW_REQUEST;
|
||||
break; /* return err */
|
||||
}
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static void mmc_wait_for_req_done(struct mmc_host *host,
|
||||
struct mmc_request *mrq)
|
||||
{
|
||||
@@ -426,8 +516,16 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
|
||||
mmc_pre_req(host, areq->mrq, !host->areq);
|
||||
|
||||
if (host->areq) {
|
||||
mmc_wait_for_req_done(host, host->areq->mrq);
|
||||
err = host->areq->err_check(host->card, host->areq);
|
||||
err = mmc_wait_for_data_req_done(host, host->areq->mrq, areq);
|
||||
if (err == MMC_BLK_NEW_REQUEST) {
|
||||
if (error)
|
||||
*error = err;
|
||||
/*
|
||||
* The previous request was not completed,
|
||||
* nothing to return
|
||||
*/
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* Check BKOPS urgency for each R1 response
|
||||
*/
|
||||
@@ -439,14 +537,14 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
|
||||
}
|
||||
|
||||
if (!err && areq)
|
||||
start_err = __mmc_start_req(host, areq->mrq);
|
||||
start_err = __mmc_start_data_req(host, areq->mrq);
|
||||
|
||||
if (host->areq)
|
||||
mmc_post_req(host, host->areq->mrq, 0);
|
||||
|
||||
/* Cancel a prepared request if it was not started. */
|
||||
if ((err || start_err) && areq)
|
||||
mmc_post_req(host, areq->mrq, -EINVAL);
|
||||
mmc_post_req(host, areq->mrq, -EINVAL);
|
||||
|
||||
if (err)
|
||||
host->areq = NULL;
|
||||
@@ -1137,7 +1235,7 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc,
|
||||
*/
|
||||
voltage = regulator_get_voltage(supply);
|
||||
|
||||
if (regulator_count_voltages(supply) == 1)
|
||||
if (!regulator_can_change_voltage(supply))
|
||||
min_uV = max_uV = voltage;
|
||||
|
||||
if (voltage < 0)
|
||||
@@ -1219,10 +1317,30 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
|
||||
return ocr;
|
||||
}
|
||||
|
||||
int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11)
|
||||
int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
|
||||
{
|
||||
int err = 0;
|
||||
int old_signal_voltage = host->ios.signal_voltage;
|
||||
|
||||
host->ios.signal_voltage = signal_voltage;
|
||||
if (host->ops->start_signal_voltage_switch) {
|
||||
mmc_host_clk_hold(host);
|
||||
err = host->ops->start_signal_voltage_switch(host, &host->ios);
|
||||
mmc_host_clk_release(host);
|
||||
}
|
||||
|
||||
if (err)
|
||||
host->ios.signal_voltage = old_signal_voltage;
|
||||
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
|
||||
{
|
||||
struct mmc_command cmd = {0};
|
||||
int err = 0;
|
||||
u32 clock;
|
||||
|
||||
BUG_ON(!host);
|
||||
|
||||
@@ -1230,27 +1348,81 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11
|
||||
* Send CMD11 only if the request is to switch the card to
|
||||
* 1.8V signalling.
|
||||
*/
|
||||
if ((signal_voltage != MMC_SIGNAL_VOLTAGE_330) && cmd11) {
|
||||
cmd.opcode = SD_SWITCH_VOLTAGE;
|
||||
cmd.arg = 0;
|
||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
|
||||
if (signal_voltage == MMC_SIGNAL_VOLTAGE_330)
|
||||
return __mmc_set_signal_voltage(host, signal_voltage);
|
||||
|
||||
err = mmc_wait_for_cmd(host, &cmd, 0);
|
||||
if (err)
|
||||
return err;
|
||||
/*
|
||||
* If we cannot switch voltages, return failure so the caller
|
||||
* can continue without UHS mode
|
||||
*/
|
||||
if (!host->ops->start_signal_voltage_switch)
|
||||
return -EPERM;
|
||||
if (!host->ops->card_busy)
|
||||
pr_warning("%s: cannot verify signal voltage switch\n",
|
||||
mmc_hostname(host));
|
||||
|
||||
if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
|
||||
return -EIO;
|
||||
cmd.opcode = SD_SWITCH_VOLTAGE;
|
||||
cmd.arg = 0;
|
||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
|
||||
|
||||
err = mmc_wait_for_cmd(host, &cmd, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
|
||||
return -EIO;
|
||||
|
||||
mmc_host_clk_hold(host);
|
||||
/*
|
||||
* The card should drive cmd and dat[0:3] low immediately
|
||||
* after the response of cmd11, but wait 1 ms to be sure
|
||||
*/
|
||||
mmc_delay(1);
|
||||
if (host->ops->card_busy && !host->ops->card_busy(host)) {
|
||||
err = -EAGAIN;
|
||||
goto power_cycle;
|
||||
}
|
||||
/*
|
||||
* During a signal voltage level switch, the clock must be gated
|
||||
* for 5 ms according to the SD spec
|
||||
*/
|
||||
clock = host->ios.clock;
|
||||
host->ios.clock = 0;
|
||||
mmc_set_ios(host);
|
||||
|
||||
if (__mmc_set_signal_voltage(host, signal_voltage)) {
|
||||
/*
|
||||
* Voltages may not have been switched, but we've already
|
||||
* sent CMD11, so a power cycle is required anyway
|
||||
*/
|
||||
err = -EAGAIN;
|
||||
goto power_cycle;
|
||||
}
|
||||
|
||||
host->ios.signal_voltage = signal_voltage;
|
||||
/* Keep clock gated for at least 5 ms */
|
||||
mmc_delay(5);
|
||||
host->ios.clock = clock;
|
||||
mmc_set_ios(host);
|
||||
|
||||
if (host->ops->start_signal_voltage_switch) {
|
||||
mmc_host_clk_hold(host);
|
||||
err = host->ops->start_signal_voltage_switch(host, &host->ios);
|
||||
mmc_host_clk_release(host);
|
||||
/* Wait for at least 1 ms according to spec */
|
||||
mmc_delay(1);
|
||||
|
||||
/*
|
||||
* Failure to switch is indicated by the card holding
|
||||
* dat[0:3] low
|
||||
*/
|
||||
if (host->ops->card_busy && host->ops->card_busy(host))
|
||||
err = -EAGAIN;
|
||||
|
||||
power_cycle:
|
||||
if (err) {
|
||||
pr_debug("%s: Signal voltage switch failed, "
|
||||
"power cycling card\n", mmc_hostname(host));
|
||||
mmc_power_cycle(host);
|
||||
}
|
||||
|
||||
mmc_host_clk_release(host);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -1314,7 +1486,7 @@ static void mmc_power_up(struct mmc_host *host)
|
||||
mmc_set_ios(host);
|
||||
|
||||
/* Set signal voltage to 3.3V */
|
||||
mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, false);
|
||||
__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330);
|
||||
|
||||
/*
|
||||
* This delay should be sufficient to allow the power supply
|
||||
@@ -1372,6 +1544,14 @@ void mmc_power_off(struct mmc_host *host)
|
||||
mmc_host_clk_release(host);
|
||||
}
|
||||
|
||||
void mmc_power_cycle(struct mmc_host *host)
|
||||
{
|
||||
mmc_power_off(host);
|
||||
/* Wait at least 1 ms according to SD spec */
|
||||
mmc_delay(1);
|
||||
mmc_power_up(host);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup when the last reference to the bus operator is dropped.
|
||||
*/
|
||||
@@ -2388,6 +2568,7 @@ EXPORT_SYMBOL(mmc_flush_cache);
|
||||
* Turn the cache ON/OFF.
|
||||
* Turning the cache OFF shall trigger flushing of the data
|
||||
* to the non-volatile storage.
|
||||
* This function should be called with host claimed
|
||||
*/
|
||||
int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
|
||||
{
|
||||
@@ -2399,7 +2580,6 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
|
||||
mmc_card_is_removable(host))
|
||||
return err;
|
||||
|
||||
mmc_claim_host(host);
|
||||
if (card && mmc_card_mmc(card) &&
|
||||
(card->ext_csd.cache_size > 0)) {
|
||||
enable = !!enable;
|
||||
@@ -2417,7 +2597,6 @@ int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
|
||||
card->ext_csd.cache_ctrl = enable;
|
||||
}
|
||||
}
|
||||
mmc_release_host(host);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -2436,10 +2615,6 @@ int mmc_suspend_host(struct mmc_host *host)
|
||||
cancel_delayed_work(&host->detect);
|
||||
mmc_flush_scheduled_work();
|
||||
|
||||
err = mmc_cache_ctrl(host, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
mmc_bus_get(host);
|
||||
if (host->bus_ops && !host->bus_dead) {
|
||||
if (host->bus_ops->suspend) {
|
||||
@@ -2581,6 +2756,23 @@ int mmc_pm_notify(struct notifier_block *notify_block,
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* mmc_init_context_info() - init synchronization context
|
||||
* @host: mmc host
|
||||
*
|
||||
* Init struct context_info needed to implement asynchronous
|
||||
* request mechanism, used by mmc core, host driver and mmc requests
|
||||
* supplier.
|
||||
*/
|
||||
void mmc_init_context_info(struct mmc_host *host)
|
||||
{
|
||||
spin_lock_init(&host->context_info.lock);
|
||||
host->context_info.is_new_req = false;
|
||||
host->context_info.is_done_rcv = false;
|
||||
host->context_info.is_waiting_last_req = false;
|
||||
init_waitqueue_head(&host->context_info.wait);
|
||||
}
|
||||
|
||||
static int __init mmc_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -40,11 +40,12 @@ void mmc_set_ungated(struct mmc_host *host);
|
||||
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
|
||||
void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
|
||||
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
|
||||
int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage,
|
||||
bool cmd11);
|
||||
int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
|
||||
int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
|
||||
void mmc_set_timing(struct mmc_host *host, unsigned int timing);
|
||||
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
|
||||
void mmc_power_off(struct mmc_host *host);
|
||||
void mmc_power_cycle(struct mmc_host *host);
|
||||
|
||||
static inline void mmc_delay(unsigned int ms)
|
||||
{
|
||||
@@ -76,5 +77,6 @@ void mmc_remove_host_debugfs(struct mmc_host *host);
|
||||
void mmc_add_card_debugfs(struct mmc_card *card);
|
||||
void mmc_remove_card_debugfs(struct mmc_card *card);
|
||||
|
||||
void mmc_init_context_info(struct mmc_host *host);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/leds.h>
|
||||
@@ -23,6 +25,7 @@
|
||||
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/card.h>
|
||||
#include <linux/mmc/slot-gpio.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "host.h"
|
||||
@@ -294,6 +297,126 @@ static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* mmc_of_parse() - parse host's device-tree node
|
||||
* @host: host whose node should be parsed.
|
||||
*
|
||||
* To keep the rest of the MMC subsystem unaware of whether DT has been
|
||||
* used to to instantiate and configure this host instance or not, we
|
||||
* parse the properties and set respective generic mmc-host flags and
|
||||
* parameters.
|
||||
*/
|
||||
void mmc_of_parse(struct mmc_host *host)
|
||||
{
|
||||
struct device_node *np;
|
||||
u32 bus_width;
|
||||
bool explicit_inv_wp, gpio_inv_wp = false;
|
||||
enum of_gpio_flags flags;
|
||||
int len, ret, gpio;
|
||||
|
||||
if (!host->parent || !host->parent->of_node)
|
||||
return;
|
||||
|
||||
np = host->parent->of_node;
|
||||
|
||||
/* "bus-width" is translated to MMC_CAP_*_BIT_DATA flags */
|
||||
if (of_property_read_u32(np, "bus-width", &bus_width) < 0) {
|
||||
dev_dbg(host->parent,
|
||||
"\"bus-width\" property is missing, assuming 1 bit.\n");
|
||||
bus_width = 1;
|
||||
}
|
||||
|
||||
switch (bus_width) {
|
||||
case 8:
|
||||
host->caps |= MMC_CAP_8_BIT_DATA;
|
||||
/* Hosts capable of 8-bit transfers can also do 4 bits */
|
||||
case 4:
|
||||
host->caps |= MMC_CAP_4_BIT_DATA;
|
||||
break;
|
||||
case 1:
|
||||
break;
|
||||
default:
|
||||
dev_err(host->parent,
|
||||
"Invalid \"bus-width\" value %ud!\n", bus_width);
|
||||
}
|
||||
|
||||
/* f_max is obtained from the optional "max-frequency" property */
|
||||
of_property_read_u32(np, "max-frequency", &host->f_max);
|
||||
|
||||
/*
|
||||
* Configure CD and WP pins. They are both by default active low to
|
||||
* match the SDHCI spec. If GPIOs are provided for CD and / or WP, the
|
||||
* mmc-gpio helpers are used to attach, configure and use them. If
|
||||
* polarity inversion is specified in DT, one of MMC_CAP2_CD_ACTIVE_HIGH
|
||||
* and MMC_CAP2_RO_ACTIVE_HIGH capability-2 flags is set. If the
|
||||
* "broken-cd" property is provided, the MMC_CAP_NEEDS_POLL capability
|
||||
* is set. If the "non-removable" property is found, the
|
||||
* MMC_CAP_NONREMOVABLE capability is set and no card-detection
|
||||
* configuration is performed.
|
||||
*/
|
||||
|
||||
/* Parse Card Detection */
|
||||
if (of_find_property(np, "non-removable", &len)) {
|
||||
host->caps |= MMC_CAP_NONREMOVABLE;
|
||||
} else {
|
||||
bool explicit_inv_cd, gpio_inv_cd = false;
|
||||
|
||||
explicit_inv_cd = of_property_read_bool(np, "cd-inverted");
|
||||
|
||||
if (of_find_property(np, "broken-cd", &len))
|
||||
host->caps |= MMC_CAP_NEEDS_POLL;
|
||||
|
||||
gpio = of_get_named_gpio_flags(np, "cd-gpios", 0, &flags);
|
||||
if (gpio_is_valid(gpio)) {
|
||||
if (!(flags & OF_GPIO_ACTIVE_LOW))
|
||||
gpio_inv_cd = true;
|
||||
|
||||
ret = mmc_gpio_request_cd(host, gpio);
|
||||
if (ret < 0)
|
||||
dev_err(host->parent,
|
||||
"Failed to request CD GPIO #%d: %d!\n",
|
||||
gpio, ret);
|
||||
else
|
||||
dev_info(host->parent, "Got CD GPIO #%d.\n",
|
||||
gpio);
|
||||
}
|
||||
|
||||
if (explicit_inv_cd ^ gpio_inv_cd)
|
||||
host->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
|
||||
}
|
||||
|
||||
/* Parse Write Protection */
|
||||
explicit_inv_wp = of_property_read_bool(np, "wp-inverted");
|
||||
|
||||
gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, &flags);
|
||||
if (gpio_is_valid(gpio)) {
|
||||
if (!(flags & OF_GPIO_ACTIVE_LOW))
|
||||
gpio_inv_wp = true;
|
||||
|
||||
ret = mmc_gpio_request_ro(host, gpio);
|
||||
if (ret < 0)
|
||||
dev_err(host->parent,
|
||||
"Failed to request WP GPIO: %d!\n", ret);
|
||||
}
|
||||
if (explicit_inv_wp ^ gpio_inv_wp)
|
||||
host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
|
||||
|
||||
if (of_find_property(np, "cap-sd-highspeed", &len))
|
||||
host->caps |= MMC_CAP_SD_HIGHSPEED;
|
||||
if (of_find_property(np, "cap-mmc-highspeed", &len))
|
||||
host->caps |= MMC_CAP_MMC_HIGHSPEED;
|
||||
if (of_find_property(np, "cap-power-off-card", &len))
|
||||
host->caps |= MMC_CAP_POWER_OFF_CARD;
|
||||
if (of_find_property(np, "cap-sdio-irq", &len))
|
||||
host->caps |= MMC_CAP_SDIO_IRQ;
|
||||
if (of_find_property(np, "keep-power-in-suspend", &len))
|
||||
host->pm_caps |= MMC_PM_KEEP_POWER;
|
||||
if (of_find_property(np, "enable-sdio-wakeup", &len))
|
||||
host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(mmc_of_parse);
|
||||
|
||||
/**
|
||||
* mmc_alloc_host - initialise the per-host structure.
|
||||
* @extra: sizeof private data structure
|
||||
|
||||
+40
-6
@@ -496,7 +496,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
|
||||
* RPMB regions are defined in multiples of 128K.
|
||||
*/
|
||||
card->ext_csd.raw_rpmb_size_mult = ext_csd[EXT_CSD_RPMB_MULT];
|
||||
if (ext_csd[EXT_CSD_RPMB_MULT]) {
|
||||
if (ext_csd[EXT_CSD_RPMB_MULT] && mmc_host_cmd23(card->host)) {
|
||||
mmc_part_add(card, ext_csd[EXT_CSD_RPMB_MULT] << 17,
|
||||
EXT_CSD_PART_CONFIG_ACC_RPMB,
|
||||
"rpmb", 0, false,
|
||||
@@ -538,6 +538,11 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
|
||||
} else {
|
||||
card->ext_csd.data_tag_unit_size = 0;
|
||||
}
|
||||
|
||||
card->ext_csd.max_packed_writes =
|
||||
ext_csd[EXT_CSD_MAX_PACKED_WRITES];
|
||||
card->ext_csd.max_packed_reads =
|
||||
ext_csd[EXT_CSD_MAX_PACKED_READS];
|
||||
} else {
|
||||
card->ext_csd.data_sector_size = 512;
|
||||
}
|
||||
@@ -769,11 +774,11 @@ static int mmc_select_hs200(struct mmc_card *card)
|
||||
|
||||
if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
|
||||
host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
|
||||
err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0);
|
||||
err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
|
||||
|
||||
if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
|
||||
host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
|
||||
err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, 0);
|
||||
err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
|
||||
|
||||
/* If fails try again during next card power cycle */
|
||||
if (err)
|
||||
@@ -1221,8 +1226,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
* WARNING: eMMC rules are NOT the same as SD DDR
|
||||
*/
|
||||
if (ddr == MMC_1_2V_DDR_MODE) {
|
||||
err = mmc_set_signal_voltage(host,
|
||||
MMC_SIGNAL_VOLTAGE_120, 0);
|
||||
err = __mmc_set_signal_voltage(host,
|
||||
MMC_SIGNAL_VOLTAGE_120);
|
||||
if (err)
|
||||
goto err;
|
||||
}
|
||||
@@ -1275,6 +1280,29 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
@@ -1379,6 +1407,11 @@ static int mmc_suspend(struct mmc_host *host)
|
||||
BUG_ON(!host->card);
|
||||
|
||||
mmc_claim_host(host);
|
||||
|
||||
err = mmc_cache_ctrl(host, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (mmc_can_poweroff_notify(host->card))
|
||||
err = mmc_poweroff_notify(host->card, EXT_CSD_POWER_OFF_SHORT);
|
||||
else if (mmc_card_can_sleep(host))
|
||||
@@ -1386,8 +1419,9 @@ static int mmc_suspend(struct mmc_host *host)
|
||||
else if (!mmc_host_is_spi(host))
|
||||
err = mmc_deselect_cards(host);
|
||||
host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
|
||||
mmc_release_host(host);
|
||||
|
||||
out:
|
||||
mmc_release_host(host);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -363,6 +363,7 @@ int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
|
||||
return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD,
|
||||
ext_csd, 512);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mmc_send_ext_csd);
|
||||
|
||||
int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
|
||||
{
|
||||
|
||||
+18
-26
@@ -444,8 +444,7 @@ static void sd_update_bus_speed_mode(struct mmc_card *card)
|
||||
* If the host doesn't support any of the UHS-I modes, fallback on
|
||||
* default speed.
|
||||
*/
|
||||
if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
|
||||
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))) {
|
||||
if (!mmc_host_uhs(card->host)) {
|
||||
card->sd_bus_speed = 0;
|
||||
return;
|
||||
}
|
||||
@@ -713,6 +712,14 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
|
||||
{
|
||||
int err;
|
||||
u32 max_current;
|
||||
int retries = 10;
|
||||
|
||||
try_again:
|
||||
if (!retries) {
|
||||
ocr &= ~SD_OCR_S18R;
|
||||
pr_warning("%s: Skipping voltage switch\n",
|
||||
mmc_hostname(host));
|
||||
}
|
||||
|
||||
/*
|
||||
* Since we're changing the OCR value, we seem to
|
||||
@@ -734,10 +741,10 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
|
||||
|
||||
/*
|
||||
* If the host supports one of UHS-I modes, request the card
|
||||
* to switch to 1.8V signaling level.
|
||||
* to switch to 1.8V signaling level. If the card has failed
|
||||
* repeatedly to switch however, skip this.
|
||||
*/
|
||||
if (host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
|
||||
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))
|
||||
if (retries && mmc_host_uhs(host))
|
||||
ocr |= SD_OCR_S18R;
|
||||
|
||||
/*
|
||||
@@ -748,7 +755,6 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
|
||||
if (max_current > 150)
|
||||
ocr |= SD_OCR_XPC;
|
||||
|
||||
try_again:
|
||||
err = mmc_send_app_op_cond(host, ocr, rocr);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -759,9 +765,12 @@ try_again:
|
||||
*/
|
||||
if (!mmc_host_is_spi(host) && rocr &&
|
||||
((*rocr & 0x41000000) == 0x41000000)) {
|
||||
err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, true);
|
||||
if (err) {
|
||||
ocr &= ~SD_OCR_S18R;
|
||||
err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
|
||||
if (err == -EAGAIN) {
|
||||
retries--;
|
||||
goto try_again;
|
||||
} else if (err) {
|
||||
retries = 0;
|
||||
goto try_again;
|
||||
}
|
||||
}
|
||||
@@ -960,16 +969,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
|
||||
|
||||
/* Card is an ultra-high-speed card */
|
||||
mmc_card_set_uhs(card);
|
||||
|
||||
/*
|
||||
* Since initialization is now complete, enable preset
|
||||
* value registers for UHS-I cards.
|
||||
*/
|
||||
if (host->ops->enable_preset_value) {
|
||||
mmc_host_clk_hold(card->host);
|
||||
host->ops->enable_preset_value(host, true);
|
||||
mmc_host_clk_release(card->host);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Attempt to change to high-speed (if supported)
|
||||
@@ -1148,13 +1147,6 @@ int mmc_attach_sd(struct mmc_host *host)
|
||||
BUG_ON(!host);
|
||||
WARN_ON(!host->claimed);
|
||||
|
||||
/* Disable preset value enable if already set since last time */
|
||||
if (host->ops->enable_preset_value) {
|
||||
mmc_host_clk_hold(host);
|
||||
host->ops->enable_preset_value(host, false);
|
||||
mmc_host_clk_release(host);
|
||||
}
|
||||
|
||||
err = mmc_send_app_op_cond(host, 0, &ocr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
+38
-16
@@ -157,10 +157,7 @@ static int sdio_read_cccr(struct mmc_card *card, u32 ocr)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (card->host->caps &
|
||||
(MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
|
||||
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
|
||||
MMC_CAP_UHS_DDR50)) {
|
||||
if (mmc_host_uhs(card->host)) {
|
||||
if (data & SDIO_UHS_DDR50)
|
||||
card->sw_caps.sd3_bus_mode
|
||||
|= SD_MODE_UHS_DDR50;
|
||||
@@ -478,8 +475,7 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card)
|
||||
* If the host doesn't support any of the UHS-I modes, fallback on
|
||||
* default speed.
|
||||
*/
|
||||
if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
|
||||
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50)))
|
||||
if (!mmc_host_uhs(card->host))
|
||||
return 0;
|
||||
|
||||
bus_speed = SDIO_SPEED_SDR12;
|
||||
@@ -489,23 +485,27 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card)
|
||||
bus_speed = SDIO_SPEED_SDR104;
|
||||
timing = MMC_TIMING_UHS_SDR104;
|
||||
card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
|
||||
card->sd_bus_speed = UHS_SDR104_BUS_SPEED;
|
||||
} else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
|
||||
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
|
||||
bus_speed = SDIO_SPEED_DDR50;
|
||||
timing = MMC_TIMING_UHS_DDR50;
|
||||
card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
|
||||
card->sd_bus_speed = UHS_DDR50_BUS_SPEED;
|
||||
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
|
||||
MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
|
||||
SD_MODE_UHS_SDR50)) {
|
||||
bus_speed = SDIO_SPEED_SDR50;
|
||||
timing = MMC_TIMING_UHS_SDR50;
|
||||
card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
|
||||
card->sd_bus_speed = UHS_SDR50_BUS_SPEED;
|
||||
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
|
||||
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
|
||||
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
|
||||
bus_speed = SDIO_SPEED_SDR25;
|
||||
timing = MMC_TIMING_UHS_SDR25;
|
||||
card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
|
||||
card->sd_bus_speed = UHS_SDR25_BUS_SPEED;
|
||||
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
|
||||
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
|
||||
MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
|
||||
@@ -513,6 +513,7 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card)
|
||||
bus_speed = SDIO_SPEED_SDR12;
|
||||
timing = MMC_TIMING_UHS_SDR12;
|
||||
card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR;
|
||||
card->sd_bus_speed = UHS_SDR12_BUS_SPEED;
|
||||
}
|
||||
|
||||
err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed);
|
||||
@@ -583,10 +584,19 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
|
||||
{
|
||||
struct mmc_card *card;
|
||||
int err;
|
||||
int retries = 10;
|
||||
|
||||
BUG_ON(!host);
|
||||
WARN_ON(!host->claimed);
|
||||
|
||||
try_again:
|
||||
if (!retries) {
|
||||
pr_warning("%s: Skipping voltage switch\n",
|
||||
mmc_hostname(host));
|
||||
ocr &= ~R4_18V_PRESENT;
|
||||
host->ocr &= ~R4_18V_PRESENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Inform the card of the voltage
|
||||
*/
|
||||
@@ -645,14 +655,16 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
|
||||
* systems that claim 1.8v signalling in fact do not support
|
||||
* it.
|
||||
*/
|
||||
if ((ocr & R4_18V_PRESENT) &&
|
||||
(host->caps &
|
||||
(MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
|
||||
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
|
||||
MMC_CAP_UHS_DDR50))) {
|
||||
err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180,
|
||||
true);
|
||||
if (err) {
|
||||
if (!powered_resume && (ocr & R4_18V_PRESENT) && mmc_host_uhs(host)) {
|
||||
err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
|
||||
if (err == -EAGAIN) {
|
||||
sdio_reset(host);
|
||||
mmc_go_idle(host);
|
||||
mmc_send_if_cond(host, host->ocr_avail);
|
||||
mmc_remove_card(card);
|
||||
retries--;
|
||||
goto try_again;
|
||||
} else if (err) {
|
||||
ocr &= ~R4_18V_PRESENT;
|
||||
host->ocr &= ~R4_18V_PRESENT;
|
||||
}
|
||||
@@ -937,10 +949,12 @@ static int mmc_sdio_resume(struct mmc_host *host)
|
||||
mmc_claim_host(host);
|
||||
|
||||
/* No need to reinitialize powered-resumed nonremovable cards */
|
||||
if (mmc_card_is_removable(host) || !mmc_card_keep_power(host))
|
||||
if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
|
||||
sdio_reset(host);
|
||||
mmc_go_idle(host);
|
||||
err = mmc_sdio_init_card(host, host->ocr, host->card,
|
||||
mmc_card_keep_power(host));
|
||||
else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
|
||||
} else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
|
||||
/* We may have switched to 1-bit mode during suspend */
|
||||
err = sdio_enable_4bit_bus(host->card);
|
||||
if (err > 0) {
|
||||
@@ -1020,6 +1034,10 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (mmc_host_uhs(host))
|
||||
/* to query card if 1.8V signalling is supported */
|
||||
host->ocr |= R4_18V_PRESENT;
|
||||
|
||||
ret = mmc_sdio_init_card(host, host->ocr, host->card,
|
||||
mmc_card_keep_power(host));
|
||||
if (!ret && host->sdio_irqs)
|
||||
@@ -1085,6 +1103,10 @@ int mmc_attach_sdio(struct mmc_host *host)
|
||||
/*
|
||||
* Detect and init the card.
|
||||
*/
|
||||
if (mmc_host_uhs(host))
|
||||
/* to query card if 1.8V signalling is supported */
|
||||
host->ocr |= R4_18V_PRESENT;
|
||||
|
||||
err = mmc_sdio_init_card(host, host->ocr, NULL, 0);
|
||||
if (err) {
|
||||
if (err == -EAGAIN) {
|
||||
|
||||
@@ -92,6 +92,20 @@ int mmc_gpio_get_cd(struct mmc_host *host)
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_gpio_get_cd);
|
||||
|
||||
/**
|
||||
* mmc_gpio_request_ro - request a gpio for write-protection
|
||||
* @host: mmc host
|
||||
* @gpio: gpio number requested
|
||||
*
|
||||
* As devm_* managed functions are used in mmc_gpio_request_ro(), client
|
||||
* drivers do not need to explicitly call mmc_gpio_free_ro() for freeing up,
|
||||
* if the requesting and freeing are only needed at probing and unbinding time
|
||||
* for once. However, if client drivers do something special like runtime
|
||||
* switching for write-protection, they are responsible for calling
|
||||
* mmc_gpio_request_ro() and mmc_gpio_free_ro() as a pair on their own.
|
||||
*
|
||||
* Returns zero on success, else an error.
|
||||
*/
|
||||
int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio)
|
||||
{
|
||||
struct mmc_gpio *ctx;
|
||||
@@ -106,7 +120,8 @@ int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio)
|
||||
|
||||
ctx = host->slot.handler_priv;
|
||||
|
||||
ret = gpio_request_one(gpio, GPIOF_DIR_IN, ctx->ro_label);
|
||||
ret = devm_gpio_request_one(&host->class_dev, gpio, GPIOF_DIR_IN,
|
||||
ctx->ro_label);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -116,6 +131,20 @@ int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio)
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_gpio_request_ro);
|
||||
|
||||
/**
|
||||
* mmc_gpio_request_cd - request a gpio for card-detection
|
||||
* @host: mmc host
|
||||
* @gpio: gpio number requested
|
||||
*
|
||||
* As devm_* managed functions are used in mmc_gpio_request_cd(), client
|
||||
* drivers do not need to explicitly call mmc_gpio_free_cd() for freeing up,
|
||||
* if the requesting and freeing are only needed at probing and unbinding time
|
||||
* for once. However, if client drivers do something special like runtime
|
||||
* switching for card-detection, they are responsible for calling
|
||||
* mmc_gpio_request_cd() and mmc_gpio_free_cd() as a pair on their own.
|
||||
*
|
||||
* Returns zero on success, else an error.
|
||||
*/
|
||||
int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
|
||||
{
|
||||
struct mmc_gpio *ctx;
|
||||
@@ -128,7 +157,8 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
|
||||
|
||||
ctx = host->slot.handler_priv;
|
||||
|
||||
ret = gpio_request_one(gpio, GPIOF_DIR_IN, ctx->cd_label);
|
||||
ret = devm_gpio_request_one(&host->class_dev, gpio, GPIOF_DIR_IN,
|
||||
ctx->cd_label);
|
||||
if (ret < 0)
|
||||
/*
|
||||
* don't bother freeing memory. It might still get used by other
|
||||
@@ -146,7 +176,8 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
|
||||
irq = -EINVAL;
|
||||
|
||||
if (irq >= 0) {
|
||||
ret = request_threaded_irq(irq, NULL, mmc_gpio_cd_irqt,
|
||||
ret = devm_request_threaded_irq(&host->class_dev, irq,
|
||||
NULL, mmc_gpio_cd_irqt,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
ctx->cd_label, host);
|
||||
if (ret < 0)
|
||||
@@ -164,6 +195,13 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_gpio_request_cd);
|
||||
|
||||
/**
|
||||
* mmc_gpio_free_ro - free the write-protection gpio
|
||||
* @host: mmc host
|
||||
*
|
||||
* It's provided only for cases that client drivers need to manually free
|
||||
* up the write-protection gpio requested by mmc_gpio_request_ro().
|
||||
*/
|
||||
void mmc_gpio_free_ro(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_gpio *ctx = host->slot.handler_priv;
|
||||
@@ -175,10 +213,17 @@ void mmc_gpio_free_ro(struct mmc_host *host)
|
||||
gpio = ctx->ro_gpio;
|
||||
ctx->ro_gpio = -EINVAL;
|
||||
|
||||
gpio_free(gpio);
|
||||
devm_gpio_free(&host->class_dev, gpio);
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_gpio_free_ro);
|
||||
|
||||
/**
|
||||
* mmc_gpio_free_cd - free the card-detection gpio
|
||||
* @host: mmc host
|
||||
*
|
||||
* It's provided only for cases that client drivers need to manually free
|
||||
* up the card-detection gpio requested by mmc_gpio_request_cd().
|
||||
*/
|
||||
void mmc_gpio_free_cd(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_gpio *ctx = host->slot.handler_priv;
|
||||
@@ -188,13 +233,13 @@ void mmc_gpio_free_cd(struct mmc_host *host)
|
||||
return;
|
||||
|
||||
if (host->slot.cd_irq >= 0) {
|
||||
free_irq(host->slot.cd_irq, host);
|
||||
devm_free_irq(&host->class_dev, host->slot.cd_irq, host);
|
||||
host->slot.cd_irq = -EINVAL;
|
||||
}
|
||||
|
||||
gpio = ctx->cd_gpio;
|
||||
ctx->cd_gpio = -EINVAL;
|
||||
|
||||
gpio_free(gpio);
|
||||
devm_gpio_free(&host->class_dev, gpio);
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_gpio_free_cd);
|
||||
|
||||
@@ -238,6 +238,17 @@ config MMC_SDHCI_S3C_DMA
|
||||
|
||||
YMMV.
|
||||
|
||||
config MMC_SDHCI_BCM2835
|
||||
tristate "SDHCI platform support for the BCM2835 SD/MMC Controller"
|
||||
depends on ARCH_BCM2835
|
||||
depends on MMC_SDHCI_PLTFM
|
||||
select MMC_SDHCI_IO_ACCESSORS
|
||||
help
|
||||
This selects the BCM2835 SD/MMC controller. If you have a BCM2835
|
||||
platform with SD or MMC devices, say Y or M here.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config MMC_OMAP
|
||||
tristate "TI OMAP Multimedia Card Interface support"
|
||||
depends on ARCH_OMAP
|
||||
@@ -361,6 +372,13 @@ config MMC_DAVINCI
|
||||
If you have an DAVINCI board with a Multimedia Card slot,
|
||||
say Y or M here. If unsure, say N.
|
||||
|
||||
config MMC_GOLDFISH
|
||||
tristate "goldfish qemu Multimedia Card Interface support"
|
||||
depends on GOLDFISH
|
||||
help
|
||||
This selects the Goldfish Multimedia card Interface emulation
|
||||
found on the Goldfish Android virtual device emulation.
|
||||
|
||||
config MMC_SPI
|
||||
tristate "MMC/SD/SDIO over SPI"
|
||||
depends on SPI_MASTER && !HIGHMEM && HAS_DMA
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user