mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-26 21:54:11 +08:00
MMC core:
- Add support for Ultra Capacity SD cards (SDUC, 2TB to 128TB) - Add support for Ultra High-Speed II SD cards (UHS-II) - Use a reset control for pwrseq_simple - Add SD card quirk for broken poweroff notification - Use GFP_NOIO for SD ACMD22 MMC host: - bcm2835: Introduce proper clock handling - mtk-sd: Add support for the Host-Software-Queue interface - mtk-sd: Add support for the mt7988/mt8196 variants - mtk-sd: Fix a couple of error paths in ->probe() - sdhci: Add interface to support UHS-II SD cards - sdhci_am654: Fixup support for changing the signal voltage level - sdhci-cadence: Add support for the Microchip PIC64GX variant - sdhci-esdhc-imx: Add support for eMMC HW-reset - sdhci-msm: Add support for the X1E80100/IPQ5424/SAR2130P/QCS615 variants - sdhci-of-arasan: Add support for eMMC HW-reset - sdhci-pci-gli: Add UHS-II support for the GL9767/GL9755 variants MEMSTICK: - A couple of minor updates -----BEGIN PGP SIGNATURE----- iQJLBAABCgA1FiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAmc7NnoXHHVsZi5oYW5z c29uQGxpbmFyby5vcmcACgkQ/iaEJXNYjCnQPRAAkxvhptCjKuLBIMBrNZglQElp Ncm8fXDiS72CvLwC3bp7rxognCKLVQGWc8GrxcBOxMSB5eiDyPe6xcLLQ2Zrm4l/ msnfP29VDtmWw3K1iC2Uzo0vlMWYyRFX0OK3fz3d6WL0dE6TXy5adsdy9BmdxGXk vpDgiTWkSZcoT/upuXs8/0N87eSgLUFzZ8uPNP+aHtF4AVWIwhJ3Y1MKqdfGrUlw 7b9bFeh6DelA+jGDxsPsqSwDBh2CDDP3YaPFYf4yyaeTRJmp6DMSEqjDifBa+hDn wkwNGj9bN05HeRN3TfsF/Z22LcaPcbWlLYh8p06h+Ws+R/2KxAXdV3oWnKNLQB9R 5WIdgb7HBD2OS2RymPeHygPPGt6zgxk55UfTBwchg7fHyugXvpcT/JDS2mbPQT4w Ty4s217wBn6Kkt4/8fWhHyG/rKBTq02Etmdery4AAM49M2iPvf+edio53FLnskrq xB8kYn5UZkk9dQ+GseC4+tXe8A1G/sxh/E2aJ/b15Mc9Mh1/BqL3g2532A+z6x5Q 8o4nyztCJhKWtfYxo1slnWzF+Axrz6ZXgVYh5MecMk9EjKVcX6oN+FGpiK/cg3dQ 7FFyzf+YGwdnOhuHhdBG0NTbvKvIRA0rMQ3xvhsfXqCI206j7FZNpWOxXYn36Lgt oZlprarw04AoECCg5Ko= =LGdl -----END PGP SIGNATURE----- Merge tag 'mmc-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc Pull MMC updates from Ulf Hansson: "MMC core: - Add support for Ultra Capacity SD cards (SDUC, 2TB to 128TB) - Add support for Ultra High-Speed II SD cards (UHS-II) - Use a reset control for pwrseq_simple - Add SD card quirk for broken poweroff notification - Use GFP_NOIO for SD ACMD22 MMC host: - bcm2835: Introduce proper clock handling - mtk-sd: Add support for the Host-Software-Queue interface - mtk-sd: Add support for the mt7988/mt8196 variants - mtk-sd: Fix a couple of error paths in ->probe() - sdhci: Add interface to support UHS-II SD cards - sdhci_am654: Fixup support for changing the signal voltage level - sdhci-cadence: Add support for the Microchip PIC64GX variant - sdhci-esdhc-imx: Add support for eMMC HW-reset - sdhci-msm: Add support for the X1E80100/IPQ5424/SAR2130P/QCS615 variants - sdhci-of-arasan: Add support for eMMC HW-reset - sdhci-pci-gli: Add UHS-II support for the GL9767/GL9755 variants MEMSTICK: - A couple of minor updates" * tag 'mmc-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (78 commits) mmc: pwrseq_simple: Handle !RESET_CONTROLLER properly mmc: mtk-sd: Fix MMC_CAP2_CRYPTO flag setting mmc: mtk-sd: Fix error handle of probe function mmc: core: Correction a warning caused by incorrect type in assignment for UHS-II mmc: sdhci-esdhc-imx: Update esdhc sysctl dtocv bitmask mmc: sdhci-esdhc-imx: Implement emmc hardware reset mmc: core: Correct type in variable assignment for UHS-II mmc: sdhci-uhs2: correction a warning caused by incorrect type in argument mmc: sdhci-uhs2: Remove unnecessary variables mmc: sdhci-uhs2: Correct incorrect type in argument mmc: sdhci: Make MMC_SDHCI_UHS2 config symbol invisible mmc: sdhci-uhs2: Remove unnecessary NULL check mmc: core: Fix error paths for UHS-II card init and re-init mmc: core: Add error handling of sd_uhs2_power_up() mmc: core: Simplify sd_uhs2_power_up() mmc: bcm2835: Introduce proper clock handling mmc: bcm2835: Fix type of current clock speed dt-bindings: mmc: Add sdhci compatible for QCS615 mmc: core: Use GFP_NOIO in ACMD22 dt-bindings: mmc: sdhci-msm: Add SAR2130P compatible ...
This commit is contained in:
commit
38556294b8
@ -15,6 +15,7 @@ properties:
|
||||
- enum:
|
||||
- amd,pensando-elba-sd4hc
|
||||
- microchip,mpfs-sd4hc
|
||||
- microchip,pic64gx-sd4hc
|
||||
- socionext,uniphier-sd4hc
|
||||
- const: cdns,sd4hc
|
||||
|
||||
@ -120,7 +121,7 @@ required:
|
||||
- clocks
|
||||
|
||||
allOf:
|
||||
- $ref: mmc-controller.yaml
|
||||
- $ref: sdhci-common.yaml
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -21,9 +21,11 @@ properties:
|
||||
- mediatek,mt7620-mmc
|
||||
- mediatek,mt7622-mmc
|
||||
- mediatek,mt7986-mmc
|
||||
- mediatek,mt7988-mmc
|
||||
- mediatek,mt8135-mmc
|
||||
- mediatek,mt8173-mmc
|
||||
- mediatek,mt8183-mmc
|
||||
- mediatek,mt8196-mmc
|
||||
- mediatek,mt8516-mmc
|
||||
- items:
|
||||
- const: mediatek,mt7623-mmc
|
||||
@ -190,6 +192,7 @@ allOf:
|
||||
- mediatek,mt8186-mmc
|
||||
- mediatek,mt8188-mmc
|
||||
- mediatek,mt8195-mmc
|
||||
- mediatek,mt8196-mmc
|
||||
- mediatek,mt8516-mmc
|
||||
then:
|
||||
properties:
|
||||
@ -263,6 +266,27 @@ allOf:
|
||||
- const: bus_clk
|
||||
- const: sys_cg
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- mediatek,mt7988-mmc
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: source clock
|
||||
- description: HCLK which used for host
|
||||
- description: Advanced eXtensible Interface
|
||||
- description: Advanced High-performance Bus clock
|
||||
clock-names:
|
||||
items:
|
||||
- const: source
|
||||
- const: hclk
|
||||
- const: axi_cg
|
||||
- const: ahb_cg
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -38,11 +38,14 @@ properties:
|
||||
- enum:
|
||||
- qcom,ipq5018-sdhci
|
||||
- qcom,ipq5332-sdhci
|
||||
- qcom,ipq5424-sdhci
|
||||
- qcom,ipq6018-sdhci
|
||||
- qcom,ipq9574-sdhci
|
||||
- qcom,qcm2290-sdhci
|
||||
- qcom,qcs404-sdhci
|
||||
- qcom,qcs615-sdhci
|
||||
- qcom,qdu1000-sdhci
|
||||
- qcom,sar2130p-sdhci
|
||||
- qcom,sc7180-sdhci
|
||||
- qcom,sc7280-sdhci
|
||||
- qcom,sc8280xp-sdhci
|
||||
@ -62,6 +65,7 @@ properties:
|
||||
- qcom,sm8450-sdhci
|
||||
- qcom,sm8550-sdhci
|
||||
- qcom,sm8650-sdhci
|
||||
- qcom,x1e80100-sdhci
|
||||
- const: qcom,sdhci-msm-v5 # for sdcc version 5.0
|
||||
|
||||
reg:
|
||||
|
@ -26,7 +26,7 @@ static DEFINE_IDR(memstick_host_idr);
|
||||
static DEFINE_SPINLOCK(memstick_host_lock);
|
||||
|
||||
static int memstick_dev_match(struct memstick_dev *card,
|
||||
struct memstick_device_id *id)
|
||||
const struct memstick_device_id *id)
|
||||
{
|
||||
if (id->match_flags & MEMSTICK_MATCH_ALL) {
|
||||
if ((id->type == card->id.type)
|
||||
@ -44,7 +44,7 @@ static int memstick_bus_match(struct device *dev, const struct device_driver *dr
|
||||
dev);
|
||||
const struct memstick_driver *ms_drv = container_of_const(drv, struct memstick_driver,
|
||||
driver);
|
||||
struct memstick_device_id *ids = ms_drv->id_table;
|
||||
const struct memstick_device_id *ids = ms_drv->id_table;
|
||||
|
||||
if (ids) {
|
||||
while (ids->match_flags) {
|
||||
|
@ -996,7 +996,7 @@ static int msb_verify_block(struct msb_data *msb, u16 pba,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Writes exectly one block + oob */
|
||||
/* Writes exactly one block + oob */
|
||||
static int msb_write_block(struct msb_data *msb,
|
||||
u16 pba, u32 lba, struct scatterlist *sg, int offset)
|
||||
{
|
||||
@ -1684,7 +1684,7 @@ static int msb_cache_read(struct msb_data *msb, int lba,
|
||||
*/
|
||||
|
||||
static const struct chs_entry chs_table[] = {
|
||||
/* size sectors cylynders heads */
|
||||
/* size sectors cylinders heads */
|
||||
{ 4, 16, 247, 2 },
|
||||
{ 8, 16, 495, 2 },
|
||||
{ 16, 16, 495, 4 },
|
||||
@ -1729,7 +1729,7 @@ static int msb_init_card(struct memstick_dev *card)
|
||||
|
||||
boot_block = &msb->boot_page[0];
|
||||
|
||||
/* Save intersting attributes from boot page */
|
||||
/* Save interesting attributes from boot page */
|
||||
msb->block_count = boot_block->attr.number_of_blocks;
|
||||
msb->page_size = boot_block->attr.page_size;
|
||||
|
||||
@ -2279,7 +2279,7 @@ out:
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static struct memstick_device_id msb_id_tbl[] = {
|
||||
static const struct memstick_device_id msb_id_tbl[] = {
|
||||
{MEMSTICK_MATCH_ALL, MEMSTICK_TYPE_LEGACY, MEMSTICK_CATEGORY_STORAGE,
|
||||
MEMSTICK_CLASS_FLASH},
|
||||
|
||||
|
@ -1349,7 +1349,7 @@ out_unlock:
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static struct memstick_device_id mspro_block_id_tbl[] = {
|
||||
static const struct memstick_device_id mspro_block_id_tbl[] = {
|
||||
{MEMSTICK_MATCH_ALL, MEMSTICK_TYPE_PRO, MEMSTICK_CATEGORY_STORAGE_DUO,
|
||||
MEMSTICK_CLASS_DUO},
|
||||
{}
|
||||
|
@ -675,7 +675,7 @@ static irqreturn_t r592_irq(int irq, void *data)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* External inteface: set settings */
|
||||
/* External interface: set settings */
|
||||
static int r592_set_param(struct memstick_host *host,
|
||||
enum memstick_param param, int value)
|
||||
{
|
||||
|
@ -7,7 +7,7 @@ obj-$(CONFIG_MMC) += mmc_core.o
|
||||
mmc_core-y := core.o bus.o host.o \
|
||||
mmc.o mmc_ops.o sd.o sd_ops.o \
|
||||
sdio.o sdio_ops.o sdio_bus.o \
|
||||
sdio_cis.o sdio_io.o sdio_irq.o \
|
||||
sdio_cis.o sdio_io.o sdio_irq.o sd_uhs2.o\
|
||||
slot-gpio.o regulator.o
|
||||
mmc_core-$(CONFIG_OF) += pwrseq.o
|
||||
obj-$(CONFIG_PWRSEQ_SIMPLE) += pwrseq_simple.o
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include <linux/mmc/sd.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/unaligned.h>
|
||||
|
||||
#include "queue.h"
|
||||
#include "block.h"
|
||||
@ -993,11 +994,12 @@ static int mmc_sd_num_wr_blocks(struct mmc_card *card, u32 *written_blocks)
|
||||
int err;
|
||||
u32 result;
|
||||
__be32 *blocks;
|
||||
u8 resp_sz = mmc_card_ult_capacity(card) ? 8 : 4;
|
||||
unsigned int noio_flag;
|
||||
|
||||
struct mmc_request mrq = {};
|
||||
struct mmc_command cmd = {};
|
||||
struct mmc_data data = {};
|
||||
|
||||
struct scatterlist sg;
|
||||
|
||||
err = mmc_app_cmd(card->host, card);
|
||||
@ -1008,7 +1010,7 @@ static int mmc_sd_num_wr_blocks(struct mmc_card *card, u32 *written_blocks)
|
||||
cmd.arg = 0;
|
||||
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
|
||||
|
||||
data.blksz = 4;
|
||||
data.blksz = resp_sz;
|
||||
data.blocks = 1;
|
||||
data.flags = MMC_DATA_READ;
|
||||
data.sg = &sg;
|
||||
@ -1018,15 +1020,29 @@ static int mmc_sd_num_wr_blocks(struct mmc_card *card, u32 *written_blocks)
|
||||
mrq.cmd = &cmd;
|
||||
mrq.data = &data;
|
||||
|
||||
blocks = kmalloc(4, GFP_KERNEL);
|
||||
noio_flag = memalloc_noio_save();
|
||||
blocks = kmalloc(resp_sz, GFP_KERNEL);
|
||||
memalloc_noio_restore(noio_flag);
|
||||
if (!blocks)
|
||||
return -ENOMEM;
|
||||
|
||||
sg_init_one(&sg, blocks, 4);
|
||||
sg_init_one(&sg, blocks, resp_sz);
|
||||
|
||||
mmc_wait_for_req(card->host, &mrq);
|
||||
|
||||
if (mmc_card_ult_capacity(card)) {
|
||||
/*
|
||||
* Normally, ACMD22 returns the number of written sectors as
|
||||
* u32. SDUC, however, returns it as u64. This is not a
|
||||
* superfluous requirement, because SDUC writes may exceed 2TB.
|
||||
* For Linux mmc however, the previously write operation could
|
||||
* not be more than the block layer limits, thus just make room
|
||||
* for a u64 and cast the response back to u32.
|
||||
*/
|
||||
result = clamp_val(get_unaligned_be64(blocks), 0, UINT_MAX);
|
||||
} else {
|
||||
result = ntohl(*blocks);
|
||||
}
|
||||
kfree(blocks);
|
||||
|
||||
if (cmd.error || data.error)
|
||||
@ -1199,7 +1215,8 @@ static void mmc_blk_issue_erase_rq(struct mmc_queue *mq, struct request *req,
|
||||
{
|
||||
struct mmc_blk_data *md = mq->blkdata;
|
||||
struct mmc_card *card = md->queue.card;
|
||||
unsigned int from, nr;
|
||||
unsigned int nr;
|
||||
sector_t from;
|
||||
int err = 0;
|
||||
blk_status_t status = BLK_STS_OK;
|
||||
|
||||
@ -1254,7 +1271,8 @@ static void mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
|
||||
{
|
||||
struct mmc_blk_data *md = mq->blkdata;
|
||||
struct mmc_card *card = md->queue.card;
|
||||
unsigned int from, nr, arg;
|
||||
unsigned int nr, arg;
|
||||
sector_t from;
|
||||
int err = 0, type = MMC_BLK_SECDISCARD;
|
||||
blk_status_t status = BLK_STS_OK;
|
||||
|
||||
@ -1759,6 +1777,11 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
|
||||
brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
|
||||
brq->mrq.sbc = &brq->sbc;
|
||||
}
|
||||
|
||||
if (mmc_card_ult_capacity(card)) {
|
||||
brq->cmd.ext_addr = blk_rq_pos(req) >> 32;
|
||||
brq->cmd.has_ext_addr = true;
|
||||
}
|
||||
}
|
||||
|
||||
#define MMC_MAX_RETRIES 5
|
||||
@ -2598,7 +2621,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
|
||||
if (mmc_host_cmd23(card->host)) {
|
||||
if ((mmc_card_mmc(card) &&
|
||||
card->csd.mmca_vsn >= CSD_SPEC_VER_3) ||
|
||||
(mmc_card_sd(card) &&
|
||||
(mmc_card_sd(card) && !mmc_card_ult_capacity(card) &&
|
||||
card->scr.cmds & SD_SCR_CMD23_SUPPORT))
|
||||
md->flags |= MMC_BLK_CMD23;
|
||||
}
|
||||
|
@ -299,6 +299,7 @@ int mmc_add_card(struct mmc_card *card)
|
||||
{
|
||||
int ret;
|
||||
const char *type;
|
||||
const char *speed_mode = "";
|
||||
const char *uhs_bus_speed_mode = "";
|
||||
static const char *const uhs_speeds[] = {
|
||||
[UHS_SDR12_BUS_SPEED] = "SDR12 ",
|
||||
@ -321,7 +322,9 @@ int mmc_add_card(struct mmc_card *card)
|
||||
case MMC_TYPE_SD:
|
||||
type = "SD";
|
||||
if (mmc_card_blockaddr(card)) {
|
||||
if (mmc_card_ext_capacity(card))
|
||||
if (mmc_card_ult_capacity(card))
|
||||
type = "SDUC";
|
||||
else if (mmc_card_ext_capacity(card))
|
||||
type = "SDXC";
|
||||
else
|
||||
type = "SDHC";
|
||||
@ -340,27 +343,32 @@ int mmc_add_card(struct mmc_card *card)
|
||||
break;
|
||||
}
|
||||
|
||||
if (mmc_card_hs(card))
|
||||
speed_mode = "high speed ";
|
||||
else if (mmc_card_uhs(card))
|
||||
speed_mode = "UHS-I speed ";
|
||||
else if (mmc_card_uhs2(card->host))
|
||||
speed_mode = "UHS-II speed ";
|
||||
else if (mmc_card_ddr52(card))
|
||||
speed_mode = "high speed DDR ";
|
||||
else if (mmc_card_hs200(card))
|
||||
speed_mode = "HS200 ";
|
||||
else if (mmc_card_hs400es(card))
|
||||
speed_mode = "HS400 Enhanced strobe ";
|
||||
else if (mmc_card_hs400(card))
|
||||
speed_mode = "HS400 ";
|
||||
|
||||
if (mmc_card_uhs(card) &&
|
||||
(card->sd_bus_speed < ARRAY_SIZE(uhs_speeds)))
|
||||
uhs_bus_speed_mode = uhs_speeds[card->sd_bus_speed];
|
||||
|
||||
if (mmc_host_is_spi(card->host)) {
|
||||
pr_info("%s: new %s%s%s card on SPI\n",
|
||||
mmc_hostname(card->host),
|
||||
mmc_card_hs(card) ? "high speed " : "",
|
||||
mmc_card_ddr52(card) ? "DDR " : "",
|
||||
type);
|
||||
} else {
|
||||
pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
|
||||
mmc_hostname(card->host),
|
||||
mmc_card_uhs(card) ? "ultra high speed " :
|
||||
(mmc_card_hs(card) ? "high speed " : ""),
|
||||
mmc_card_hs400(card) ? "HS400 " :
|
||||
(mmc_card_hs200(card) ? "HS200 " : ""),
|
||||
mmc_card_hs400es(card) ? "Enhanced strobe " : "",
|
||||
mmc_card_ddr52(card) ? "DDR " : "",
|
||||
if (mmc_host_is_spi(card->host))
|
||||
pr_info("%s: new %s%s card on SPI\n",
|
||||
mmc_hostname(card->host), speed_mode, type);
|
||||
else
|
||||
pr_info("%s: new %s%s%s card at address %04x\n",
|
||||
mmc_hostname(card->host), speed_mode,
|
||||
uhs_bus_speed_mode, type, card->rca);
|
||||
}
|
||||
|
||||
mmc_add_card_debugfs(card);
|
||||
card->dev.of_node = mmc_of_find_child_device(card->host, 0);
|
||||
|
@ -23,6 +23,7 @@
|
||||
#define MMC_CARD_SDXC (1<<3) /* card is SDXC */
|
||||
#define MMC_CARD_REMOVED (1<<4) /* card has been removed */
|
||||
#define MMC_STATE_SUSPENDED (1<<5) /* card is suspended */
|
||||
#define MMC_CARD_SDUC (1<<6) /* card is SDUC */
|
||||
|
||||
#define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT)
|
||||
#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
|
||||
@ -30,11 +31,13 @@
|
||||
#define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
|
||||
#define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED))
|
||||
#define mmc_card_suspended(c) ((c)->state & MMC_STATE_SUSPENDED)
|
||||
#define mmc_card_ult_capacity(c) ((c)->state & MMC_CARD_SDUC)
|
||||
|
||||
#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
|
||||
#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
|
||||
#define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
|
||||
#define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
|
||||
#define mmc_card_set_ult_capacity(c) ((c)->state |= MMC_CARD_SDUC)
|
||||
#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
|
||||
#define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED)
|
||||
#define mmc_card_clr_suspended(c) ((c)->state &= ~MMC_STATE_SUSPENDED)
|
||||
@ -82,6 +85,7 @@ struct mmc_fixup {
|
||||
#define CID_MANFID_SANDISK_SD 0x3
|
||||
#define CID_MANFID_ATP 0x9
|
||||
#define CID_MANFID_TOSHIBA 0x11
|
||||
#define CID_MANFID_GIGASTONE 0x12
|
||||
#define CID_MANFID_MICRON 0x13
|
||||
#define CID_MANFID_SAMSUNG 0x15
|
||||
#define CID_MANFID_APACER 0x27
|
||||
@ -284,4 +288,10 @@ static inline int mmc_card_broken_cache_flush(const struct mmc_card *c)
|
||||
{
|
||||
return c->quirks & MMC_QUIRK_BROKEN_CACHE_FLUSH;
|
||||
}
|
||||
|
||||
static inline int mmc_card_broken_sd_poweroff_notify(const struct mmc_card *c)
|
||||
{
|
||||
return c->quirks & MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -336,6 +336,9 @@ int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (mrq->cmd && mrq->cmd->has_ext_addr)
|
||||
mmc_send_ext_addr(host, mrq->cmd->ext_addr);
|
||||
|
||||
init_completion(&mrq->cmd_completion);
|
||||
|
||||
mmc_retune_hold(host);
|
||||
@ -351,6 +354,9 @@ int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (host->uhs2_sd_tran)
|
||||
mmc_uhs2_prepare_cmd(host, mrq);
|
||||
|
||||
led_trigger_event(host->led, LED_FULL);
|
||||
__mmc_start_request(host, mrq);
|
||||
|
||||
@ -450,6 +456,9 @@ int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq)
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
if (host->uhs2_sd_tran)
|
||||
mmc_uhs2_prepare_cmd(host, mrq);
|
||||
|
||||
err = host->cqe_ops->cqe_request(host, mrq);
|
||||
if (err)
|
||||
goto out_err;
|
||||
@ -1132,7 +1141,7 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) {
|
||||
if (!mmc_card_uhs2(host) && host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) {
|
||||
bit = ffs(ocr) - 1;
|
||||
ocr &= 3 << bit;
|
||||
mmc_power_cycle(host, ocr);
|
||||
@ -1598,8 +1607,8 @@ static unsigned int mmc_erase_timeout(struct mmc_card *card,
|
||||
return mmc_mmc_erase_timeout(card, arg, qty);
|
||||
}
|
||||
|
||||
static int mmc_do_erase(struct mmc_card *card, unsigned int from,
|
||||
unsigned int to, unsigned int arg)
|
||||
static int mmc_do_erase(struct mmc_card *card, sector_t from,
|
||||
sector_t to, unsigned int arg)
|
||||
{
|
||||
struct mmc_command cmd = {};
|
||||
unsigned int qty = 0, busy_timeout = 0;
|
||||
@ -1630,8 +1639,8 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
|
||||
else if (mmc_card_sd(card))
|
||||
qty += to - from + 1;
|
||||
else
|
||||
qty += ((to / card->erase_size) -
|
||||
(from / card->erase_size)) + 1;
|
||||
qty += (mmc_sector_div(to, card->erase_size) -
|
||||
mmc_sector_div(from, card->erase_size)) + 1;
|
||||
|
||||
if (!mmc_card_blockaddr(card)) {
|
||||
from <<= 9;
|
||||
@ -1644,6 +1653,12 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
|
||||
cmd.opcode = MMC_ERASE_GROUP_START;
|
||||
cmd.arg = from;
|
||||
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
|
||||
|
||||
if (mmc_card_ult_capacity(card)) {
|
||||
cmd.ext_addr = from >> 32;
|
||||
cmd.has_ext_addr = true;
|
||||
}
|
||||
|
||||
err = mmc_wait_for_cmd(card->host, &cmd, 0);
|
||||
if (err) {
|
||||
pr_err("mmc_erase: group start error %d, "
|
||||
@ -1659,6 +1674,12 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
|
||||
cmd.opcode = MMC_ERASE_GROUP_END;
|
||||
cmd.arg = to;
|
||||
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
|
||||
|
||||
if (mmc_card_ult_capacity(card)) {
|
||||
cmd.ext_addr = to >> 32;
|
||||
cmd.has_ext_addr = true;
|
||||
}
|
||||
|
||||
err = mmc_wait_for_cmd(card->host, &cmd, 0);
|
||||
if (err) {
|
||||
pr_err("mmc_erase: group end error %d, status %#x\n",
|
||||
@ -1700,18 +1721,19 @@ out:
|
||||
}
|
||||
|
||||
static unsigned int mmc_align_erase_size(struct mmc_card *card,
|
||||
unsigned int *from,
|
||||
unsigned int *to,
|
||||
sector_t *from,
|
||||
sector_t *to,
|
||||
unsigned int nr)
|
||||
{
|
||||
unsigned int from_new = *from, nr_new = nr, rem;
|
||||
sector_t from_new = *from;
|
||||
unsigned int nr_new = nr, rem;
|
||||
|
||||
/*
|
||||
* When the 'card->erase_size' is power of 2, we can use round_up/down()
|
||||
* to align the erase size efficiently.
|
||||
*/
|
||||
if (is_power_of_2(card->erase_size)) {
|
||||
unsigned int temp = from_new;
|
||||
sector_t temp = from_new;
|
||||
|
||||
from_new = round_up(temp, card->erase_size);
|
||||
rem = from_new - temp;
|
||||
@ -1723,7 +1745,7 @@ static unsigned int mmc_align_erase_size(struct mmc_card *card,
|
||||
|
||||
nr_new = round_down(nr_new, card->erase_size);
|
||||
} else {
|
||||
rem = from_new % card->erase_size;
|
||||
rem = mmc_sector_mod(from_new, card->erase_size);
|
||||
if (rem) {
|
||||
rem = card->erase_size - rem;
|
||||
from_new += rem;
|
||||
@ -1756,10 +1778,12 @@ static unsigned int mmc_align_erase_size(struct mmc_card *card,
|
||||
*
|
||||
* Caller must claim host before calling this function.
|
||||
*/
|
||||
int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
|
||||
int mmc_erase(struct mmc_card *card, sector_t from, unsigned int nr,
|
||||
unsigned int arg)
|
||||
{
|
||||
unsigned int rem, to = from + nr;
|
||||
unsigned int rem;
|
||||
sector_t to = from + nr;
|
||||
|
||||
int err;
|
||||
|
||||
if (!(card->csd.cmdclass & CCC_ERASE))
|
||||
@ -1780,7 +1804,7 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (arg == MMC_SECURE_ERASE_ARG) {
|
||||
if (from % card->erase_size || nr % card->erase_size)
|
||||
if (mmc_sector_mod(from, card->erase_size) || nr % card->erase_size)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -1804,7 +1828,7 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
|
||||
* and call mmc_do_erase() twice if necessary. This special case is
|
||||
* identified by the card->eg_boundary flag.
|
||||
*/
|
||||
rem = card->erase_size - (from % card->erase_size);
|
||||
rem = card->erase_size - mmc_sector_mod(from, card->erase_size);
|
||||
if ((arg & MMC_TRIM_OR_DISCARD_ARGS) && card->eg_boundary && nr > rem) {
|
||||
err = mmc_do_erase(card, from, from + rem - 1, arg);
|
||||
from += rem;
|
||||
@ -1863,12 +1887,12 @@ int mmc_can_secure_erase_trim(struct mmc_card *card)
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_can_secure_erase_trim);
|
||||
|
||||
int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
|
||||
int mmc_erase_group_aligned(struct mmc_card *card, sector_t from,
|
||||
unsigned int nr)
|
||||
{
|
||||
if (!card->erase_size)
|
||||
return 0;
|
||||
if (from % card->erase_size || nr % card->erase_size)
|
||||
if (mmc_sector_mod(from, card->erase_size) || nr % card->erase_size)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@ -2249,6 +2273,18 @@ void mmc_rescan(struct work_struct *work)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ideally we should favor initialization of legacy SD cards and defer
|
||||
* UHS-II enumeration. However, it seems like cards doesn't reliably
|
||||
* announce their support for UHS-II in the response to the ACMD41,
|
||||
* while initializing the legacy SD interface. Therefore, let's start
|
||||
* with UHS-II for now.
|
||||
*/
|
||||
if (!mmc_attach_sd_uhs2(host)) {
|
||||
mmc_release_host(host);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(freqs); i++) {
|
||||
unsigned int freq = freqs[i];
|
||||
if (freq > host->f_max) {
|
||||
@ -2281,10 +2317,13 @@ void mmc_rescan(struct work_struct *work)
|
||||
|
||||
void mmc_start_host(struct mmc_host *host)
|
||||
{
|
||||
bool power_up = !(host->caps2 &
|
||||
(MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_SD_UHS2));
|
||||
|
||||
host->f_init = max(min(freqs[0], host->f_max), host->f_min);
|
||||
host->rescan_disable = 0;
|
||||
|
||||
if (!(host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)) {
|
||||
if (power_up) {
|
||||
mmc_claim_host(host);
|
||||
mmc_power_up(host, host->ocr_avail);
|
||||
mmc_release_host(host);
|
||||
|
@ -81,6 +81,7 @@ int mmc_detect_card_removed(struct mmc_host *host);
|
||||
int mmc_attach_mmc(struct mmc_host *host);
|
||||
int mmc_attach_sd(struct mmc_host *host);
|
||||
int mmc_attach_sdio(struct mmc_host *host);
|
||||
int mmc_attach_sd_uhs2(struct mmc_host *host);
|
||||
|
||||
/* Module parameters */
|
||||
extern bool use_spi_crc;
|
||||
@ -116,15 +117,13 @@ bool mmc_is_req_done(struct mmc_host *host, struct mmc_request *mrq);
|
||||
|
||||
int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq);
|
||||
|
||||
int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
|
||||
unsigned int arg);
|
||||
int mmc_erase(struct mmc_card *card, sector_t from, unsigned int nr, unsigned int arg);
|
||||
int mmc_can_erase(struct mmc_card *card);
|
||||
int mmc_can_trim(struct mmc_card *card);
|
||||
int mmc_can_discard(struct mmc_card *card);
|
||||
int mmc_can_sanitize(struct mmc_card *card);
|
||||
int mmc_can_secure_erase_trim(struct mmc_card *card);
|
||||
int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
|
||||
unsigned int nr);
|
||||
int mmc_erase_group_aligned(struct mmc_card *card, sector_t from, unsigned int nr);
|
||||
unsigned int mmc_calc_max_discard(struct mmc_card *card);
|
||||
|
||||
int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
|
||||
@ -199,4 +198,14 @@ static inline int mmc_flush_cache(struct mmc_host *host)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned int mmc_sector_div(sector_t dividend, u32 divisor)
|
||||
{
|
||||
return div_u64(dividend, divisor);
|
||||
}
|
||||
|
||||
static inline unsigned int mmc_sector_mod(sector_t dividend, u32 divisor)
|
||||
{
|
||||
return sector_div(dividend, divisor);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -144,10 +144,24 @@ int mmc_set_dsr(struct mmc_host *host)
|
||||
return mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
|
||||
}
|
||||
|
||||
int __mmc_go_idle(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_command cmd = {};
|
||||
int err;
|
||||
|
||||
cmd.opcode = MMC_GO_IDLE_STATE;
|
||||
cmd.arg = 0;
|
||||
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
|
||||
|
||||
err = mmc_wait_for_cmd(host, &cmd, 0);
|
||||
mmc_delay(1);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int mmc_go_idle(struct mmc_host *host)
|
||||
{
|
||||
int err;
|
||||
struct mmc_command cmd = {};
|
||||
|
||||
/*
|
||||
* Non-SPI hosts need to prevent chipselect going active during
|
||||
@ -163,13 +177,7 @@ int mmc_go_idle(struct mmc_host *host)
|
||||
mmc_delay(1);
|
||||
}
|
||||
|
||||
cmd.opcode = MMC_GO_IDLE_STATE;
|
||||
cmd.arg = 0;
|
||||
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
|
||||
|
||||
err = mmc_wait_for_cmd(host, &cmd, 0);
|
||||
|
||||
mmc_delay(1);
|
||||
err = __mmc_go_idle(host);
|
||||
|
||||
if (!mmc_host_is_spi(host)) {
|
||||
mmc_set_chip_select(host, MMC_CS_DONTCARE);
|
||||
|
@ -25,6 +25,7 @@ struct mmc_command;
|
||||
int mmc_select_card(struct mmc_card *card);
|
||||
int mmc_deselect_cards(struct mmc_host *host);
|
||||
int mmc_set_dsr(struct mmc_host *host);
|
||||
int __mmc_go_idle(struct mmc_host *host);
|
||||
int mmc_go_idle(struct mmc_host *host);
|
||||
int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
|
||||
int mmc_set_relative_addr(struct mmc_card *card);
|
||||
|
@ -3241,6 +3241,12 @@ static int mmc_test_probe(struct mmc_card *card)
|
||||
if (!mmc_card_mmc(card) && !mmc_card_sd(card))
|
||||
return -ENODEV;
|
||||
|
||||
if (mmc_card_ult_capacity(card)) {
|
||||
pr_info("%s: mmc-test currently UNSUPPORTED for SDUC\n",
|
||||
mmc_hostname(card->host));
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ret = mmc_test_register_dbgfs_file(card);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -107,7 +107,7 @@ MODULE_DEVICE_TABLE(of, mmc_pwrseq_emmc_of_match);
|
||||
|
||||
static struct platform_driver mmc_pwrseq_emmc_driver = {
|
||||
.probe = mmc_pwrseq_emmc_probe,
|
||||
.remove_new = mmc_pwrseq_emmc_remove,
|
||||
.remove = mmc_pwrseq_emmc_remove,
|
||||
.driver = {
|
||||
.name = "pwrseq_emmc",
|
||||
.of_match_table = mmc_pwrseq_emmc_of_match,
|
||||
|
@ -122,7 +122,7 @@ static void mmc_pwrseq_sd8787_remove(struct platform_device *pdev)
|
||||
|
||||
static struct platform_driver mmc_pwrseq_sd8787_driver = {
|
||||
.probe = mmc_pwrseq_sd8787_probe,
|
||||
.remove_new = mmc_pwrseq_sd8787_remove,
|
||||
.remove = mmc_pwrseq_sd8787_remove,
|
||||
.driver = {
|
||||
.name = "pwrseq_sd8787",
|
||||
.of_match_table = mmc_pwrseq_sd8787_of_match,
|
||||
|
@ -17,6 +17,8 @@
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include <linux/mmc/host.h>
|
||||
|
||||
@ -29,6 +31,7 @@ struct mmc_pwrseq_simple {
|
||||
u32 power_off_delay_us;
|
||||
struct clk *ext_clk;
|
||||
struct gpio_descs *reset_gpios;
|
||||
struct reset_control *reset_ctrl;
|
||||
};
|
||||
|
||||
#define to_pwrseq_simple(p) container_of(p, struct mmc_pwrseq_simple, pwrseq)
|
||||
@ -67,6 +70,10 @@ static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host)
|
||||
pwrseq->clk_enabled = true;
|
||||
}
|
||||
|
||||
if (pwrseq->reset_ctrl) {
|
||||
reset_control_deassert(pwrseq->reset_ctrl);
|
||||
reset_control_assert(pwrseq->reset_ctrl);
|
||||
} else
|
||||
mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
|
||||
}
|
||||
|
||||
@ -74,6 +81,9 @@ static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
|
||||
|
||||
if (pwrseq->reset_ctrl)
|
||||
reset_control_deassert(pwrseq->reset_ctrl);
|
||||
else
|
||||
mmc_pwrseq_simple_set_gpios_value(pwrseq, 0);
|
||||
|
||||
if (pwrseq->post_power_on_delay_ms)
|
||||
@ -84,6 +94,9 @@ static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
|
||||
|
||||
if (pwrseq->reset_ctrl)
|
||||
reset_control_assert(pwrseq->reset_ctrl);
|
||||
else
|
||||
mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
|
||||
|
||||
if (pwrseq->power_off_delay_us)
|
||||
@ -112,6 +125,7 @@ static int mmc_pwrseq_simple_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mmc_pwrseq_simple *pwrseq;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ngpio;
|
||||
|
||||
pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL);
|
||||
if (!pwrseq)
|
||||
@ -121,12 +135,26 @@ static int mmc_pwrseq_simple_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(pwrseq->ext_clk) && PTR_ERR(pwrseq->ext_clk) != -ENOENT)
|
||||
return dev_err_probe(dev, PTR_ERR(pwrseq->ext_clk), "external clock not ready\n");
|
||||
|
||||
pwrseq->reset_gpios = devm_gpiod_get_array(dev, "reset",
|
||||
GPIOD_OUT_HIGH);
|
||||
ngpio = of_count_phandle_with_args(dev->of_node, "reset-gpios", "#gpio-cells");
|
||||
if (ngpio == 1) {
|
||||
pwrseq->reset_ctrl = devm_reset_control_get_optional_shared(dev, NULL);
|
||||
if (IS_ERR(pwrseq->reset_ctrl))
|
||||
return dev_err_probe(dev, PTR_ERR(pwrseq->reset_ctrl),
|
||||
"reset control not ready\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Fallback to GPIO based reset control in case of multiple reset lines
|
||||
* are specified or the platform doesn't have support for RESET at all.
|
||||
*/
|
||||
if (!pwrseq->reset_ctrl) {
|
||||
pwrseq->reset_gpios = devm_gpiod_get_array(dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(pwrseq->reset_gpios) &&
|
||||
PTR_ERR(pwrseq->reset_gpios) != -ENOENT &&
|
||||
PTR_ERR(pwrseq->reset_gpios) != -ENOSYS) {
|
||||
return dev_err_probe(dev, PTR_ERR(pwrseq->reset_gpios), "reset GPIOs not ready\n");
|
||||
return dev_err_probe(dev, PTR_ERR(pwrseq->reset_gpios),
|
||||
"reset GPIOs not ready\n");
|
||||
}
|
||||
}
|
||||
|
||||
device_property_read_u32(dev, "post-power-on-delay-ms",
|
||||
@ -151,7 +179,7 @@ static void mmc_pwrseq_simple_remove(struct platform_device *pdev)
|
||||
|
||||
static struct platform_driver mmc_pwrseq_simple_driver = {
|
||||
.probe = mmc_pwrseq_simple_probe,
|
||||
.remove_new = mmc_pwrseq_simple_remove,
|
||||
.remove = mmc_pwrseq_simple_remove,
|
||||
.driver = {
|
||||
.name = "pwrseq_simple",
|
||||
.of_match_table = mmc_pwrseq_simple_of_match,
|
||||
|
@ -25,6 +25,15 @@ static const struct mmc_fixup __maybe_unused mmc_sd_fixups[] = {
|
||||
0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
|
||||
MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY),
|
||||
|
||||
/*
|
||||
* GIGASTONE Gaming Plus microSD cards manufactured on 02/2022 never
|
||||
* clear Flush Cache bit and set Poweroff Notification Ready bit.
|
||||
*/
|
||||
_FIXUP_EXT("ASTC", CID_MANFID_GIGASTONE, 0x3456, 2022, 2,
|
||||
0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
|
||||
MMC_QUIRK_BROKEN_SD_CACHE | MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY,
|
||||
EXT_CSD_REV_ANY),
|
||||
|
||||
END_FIXUP
|
||||
};
|
||||
|
||||
|
@ -226,6 +226,33 @@ int mmc_regulator_set_vqmmc(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mmc_regulator_set_vqmmc);
|
||||
|
||||
/**
|
||||
* mmc_regulator_set_vqmmc2 - Set vqmmc2 as per the ios->vqmmc2_voltage
|
||||
* @mmc: The mmc host to regulate
|
||||
* @ios: The io bus settings
|
||||
*
|
||||
* Sets a new voltage level for the vqmmc2 regulator, which may correspond to
|
||||
* the vdd2 regulator for an SD UHS-II interface. This function is expected to
|
||||
* be called by mmc host drivers.
|
||||
*
|
||||
* Returns a negative error code on failure, zero if the voltage level was
|
||||
* changed successfully or a positive value if the level didn't need to change.
|
||||
*/
|
||||
int mmc_regulator_set_vqmmc2(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
{
|
||||
if (IS_ERR(mmc->supply.vqmmc2))
|
||||
return -EINVAL;
|
||||
|
||||
switch (ios->vqmmc2_voltage) {
|
||||
case MMC_VQMMC2_VOLTAGE_180:
|
||||
return mmc_regulator_set_voltage_if_supported(
|
||||
mmc->supply.vqmmc2, 1700000, 1800000, 1950000);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mmc_regulator_set_vqmmc2);
|
||||
|
||||
#else
|
||||
|
||||
static inline int mmc_regulator_get_ocrmask(struct regulator *supply)
|
||||
@ -252,6 +279,7 @@ int mmc_regulator_get_supply(struct mmc_host *mmc)
|
||||
|
||||
mmc->supply.vmmc = devm_regulator_get_optional(dev, "vmmc");
|
||||
mmc->supply.vqmmc = devm_regulator_get_optional(dev, "vqmmc");
|
||||
mmc->supply.vqmmc2 = devm_regulator_get_optional(dev, "vqmmc2");
|
||||
|
||||
if (IS_ERR(mmc->supply.vmmc)) {
|
||||
if (PTR_ERR(mmc->supply.vmmc) == -EPROBE_DEFER)
|
||||
@ -275,6 +303,12 @@ int mmc_regulator_get_supply(struct mmc_host *mmc)
|
||||
dev_dbg(dev, "No vqmmc regulator found\n");
|
||||
}
|
||||
|
||||
if (IS_ERR(mmc->supply.vqmmc2)) {
|
||||
if (PTR_ERR(mmc->supply.vqmmc2) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
dev_dbg(dev, "No vqmmc2 regulator found\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mmc_regulator_get_supply);
|
||||
|
@ -100,7 +100,7 @@ void mmc_decode_cid(struct mmc_card *card)
|
||||
/*
|
||||
* Given a 128-bit response, decode to our card CSD structure.
|
||||
*/
|
||||
static int mmc_decode_csd(struct mmc_card *card)
|
||||
static int mmc_decode_csd(struct mmc_card *card, bool is_sduc)
|
||||
{
|
||||
struct mmc_csd *csd = &card->csd;
|
||||
unsigned int e, m, csd_struct;
|
||||
@ -144,9 +144,10 @@ static int mmc_decode_csd(struct mmc_card *card)
|
||||
mmc_card_set_readonly(card);
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
/*
|
||||
* This is a block-addressed SDHC or SDXC card. Most
|
||||
* interesting fields are unused and have fixed
|
||||
* This is a block-addressed SDHC, SDXC or SDUC card.
|
||||
* Most interesting fields are unused and have fixed
|
||||
* values. To avoid getting tripped by buggy cards,
|
||||
* we assume those fixed values ourselves.
|
||||
*/
|
||||
@ -159,14 +160,19 @@ static int mmc_decode_csd(struct mmc_card *card)
|
||||
e = unstuff_bits(resp, 96, 3);
|
||||
csd->max_dtr = tran_exp[e] * tran_mant[m];
|
||||
csd->cmdclass = unstuff_bits(resp, 84, 12);
|
||||
csd->c_size = unstuff_bits(resp, 48, 22);
|
||||
|
||||
/* SDXC cards have a minimum C_SIZE of 0x00FFFF */
|
||||
if (csd->c_size >= 0xFFFF)
|
||||
if (csd_struct == 1)
|
||||
m = unstuff_bits(resp, 48, 22);
|
||||
else
|
||||
m = unstuff_bits(resp, 48, 28);
|
||||
csd->c_size = m;
|
||||
|
||||
if (csd->c_size >= 0x400000 && is_sduc)
|
||||
mmc_card_set_ult_capacity(card);
|
||||
else if (csd->c_size >= 0xFFFF)
|
||||
mmc_card_set_ext_capacity(card);
|
||||
|
||||
m = unstuff_bits(resp, 48, 22);
|
||||
csd->capacity = (1 + m) << 10;
|
||||
csd->capacity = (1 + (typeof(sector_t))m) << 10;
|
||||
|
||||
csd->read_blkbits = 9;
|
||||
csd->read_partial = 0;
|
||||
@ -194,7 +200,7 @@ static int mmc_decode_csd(struct mmc_card *card)
|
||||
/*
|
||||
* Given a 64-bit response, decode to our card SCR structure.
|
||||
*/
|
||||
static int mmc_decode_scr(struct mmc_card *card)
|
||||
int mmc_decode_scr(struct mmc_card *card)
|
||||
{
|
||||
struct sd_scr *scr = &card->scr;
|
||||
unsigned int scr_struct;
|
||||
@ -830,8 +836,11 @@ try_again:
|
||||
* block-addressed SDHC cards.
|
||||
*/
|
||||
err = mmc_send_if_cond(host, ocr);
|
||||
if (!err)
|
||||
if (!err) {
|
||||
ocr |= SD_OCR_CCS;
|
||||
/* Set HO2T as well - SDUC card won't respond otherwise */
|
||||
ocr |= SD_OCR_2T;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the host supports one of UHS-I modes, request the card
|
||||
@ -876,7 +885,7 @@ try_again:
|
||||
return err;
|
||||
}
|
||||
|
||||
int mmc_sd_get_csd(struct mmc_card *card)
|
||||
int mmc_sd_get_csd(struct mmc_card *card, bool is_sduc)
|
||||
{
|
||||
int err;
|
||||
|
||||
@ -887,14 +896,14 @@ int mmc_sd_get_csd(struct mmc_card *card)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = mmc_decode_csd(card);
|
||||
err = mmc_decode_csd(card, is_sduc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmc_sd_get_ro(struct mmc_host *host)
|
||||
int mmc_sd_get_ro(struct mmc_host *host)
|
||||
{
|
||||
int ro;
|
||||
|
||||
@ -1107,7 +1116,7 @@ static int sd_parse_ext_reg_power(struct mmc_card *card, u8 fno, u8 page,
|
||||
card->ext_power.rev = reg_buf[0] & 0xf;
|
||||
|
||||
/* Power Off Notification support at bit 4. */
|
||||
if (reg_buf[1] & BIT(4))
|
||||
if ((reg_buf[1] & BIT(4)) && !mmc_card_broken_sd_poweroff_notify(card))
|
||||
card->ext_power.feature_support |= SD_EXT_POWER_OFF_NOTIFY;
|
||||
|
||||
/* Power Sustenance support at bit 5. */
|
||||
@ -1442,7 +1451,10 @@ retry:
|
||||
}
|
||||
|
||||
if (!oldcard) {
|
||||
err = mmc_sd_get_csd(card);
|
||||
u32 sduc_arg = SD_OCR_CCS | SD_OCR_2T;
|
||||
bool is_sduc = (rocr & sduc_arg) == sduc_arg;
|
||||
|
||||
err = mmc_sd_get_csd(card, is_sduc);
|
||||
if (err)
|
||||
goto free_card;
|
||||
|
||||
@ -1552,7 +1564,7 @@ cont:
|
||||
goto free_card;
|
||||
}
|
||||
|
||||
if (host->cqe_ops && !host->cqe_enabled) {
|
||||
if (!mmc_card_ult_capacity(card) && host->cqe_ops && !host->cqe_enabled) {
|
||||
err = host->cqe_ops->cqe_enable(host, card);
|
||||
if (!err) {
|
||||
host->cqe_enabled = true;
|
||||
|
@ -10,7 +10,9 @@ struct mmc_host;
|
||||
struct mmc_card;
|
||||
|
||||
int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr);
|
||||
int mmc_sd_get_csd(struct mmc_card *card);
|
||||
int mmc_sd_get_csd(struct mmc_card *card, bool is_sduc);
|
||||
int mmc_decode_scr(struct mmc_card *card);
|
||||
int mmc_sd_get_ro(struct mmc_host *host);
|
||||
void mmc_decode_cid(struct mmc_card *card);
|
||||
int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
|
||||
bool reinit);
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <linux/mmc/sd.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "card.h"
|
||||
#include "sd_ops.h"
|
||||
#include "mmc_ops.h"
|
||||
|
||||
@ -41,6 +42,15 @@ int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
|
||||
if (WARN_ON(card && card->host != host))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* UHS2 packet has APP bit so only set APP_CMD flag here.
|
||||
* Will set the APP bit when assembling UHS2 packet.
|
||||
*/
|
||||
if (host->uhs2_sd_tran) {
|
||||
host->uhs2_app_cmd = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
cmd.opcode = MMC_APP_CMD;
|
||||
|
||||
if (card) {
|
||||
@ -188,6 +198,20 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mmc_send_ext_addr(struct mmc_host *host, u32 addr)
|
||||
{
|
||||
struct mmc_command cmd = {
|
||||
.opcode = SD_ADDR_EXT,
|
||||
.arg = addr,
|
||||
.flags = MMC_RSP_R1 | MMC_CMD_AC,
|
||||
};
|
||||
|
||||
if (!mmc_card_ult_capacity(host->card))
|
||||
return 0;
|
||||
|
||||
return mmc_wait_for_cmd(host, &cmd, 0);
|
||||
}
|
||||
|
||||
static int __mmc_send_if_cond(struct mmc_host *host, u32 ocr, u8 pcie_bits,
|
||||
u32 *resp)
|
||||
{
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
struct mmc_card;
|
||||
struct mmc_host;
|
||||
struct mmc_request;
|
||||
|
||||
int mmc_app_set_bus_width(struct mmc_card *card, int width);
|
||||
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
|
||||
@ -21,6 +22,8 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca);
|
||||
int mmc_app_send_scr(struct mmc_card *card);
|
||||
int mmc_app_sd_status(struct mmc_card *card, void *ssr);
|
||||
int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card);
|
||||
int mmc_send_ext_addr(struct mmc_host *host, u32 addr);
|
||||
void mmc_uhs2_prepare_cmd(struct mmc_host *host, struct mmc_request *mrq);
|
||||
|
||||
#endif
|
||||
|
||||
|
1304
drivers/mmc/core/sd_uhs2.c
Normal file
1304
drivers/mmc/core/sd_uhs2.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -769,7 +769,7 @@ try_again:
|
||||
* Read CSD, before selecting the card
|
||||
*/
|
||||
if (!oldcard && mmc_card_sd_combo(card)) {
|
||||
err = mmc_sd_get_csd(card);
|
||||
err = mmc_sd_get_csd(card, false);
|
||||
if (err)
|
||||
goto remove;
|
||||
|
||||
|
@ -98,10 +98,20 @@ config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
|
||||
|
||||
This is the case for the Nintendo Wii SDHCI.
|
||||
|
||||
config MMC_SDHCI_UHS2
|
||||
tristate "UHS2 support on SDHCI controller" if COMPILE_TEST
|
||||
depends on MMC_SDHCI
|
||||
help
|
||||
This option is selected by SDHCI controller drivers that want to
|
||||
support UHS2-capable devices.
|
||||
|
||||
If you have a controller with this feature, say Y or M here.
|
||||
|
||||
config MMC_SDHCI_PCI
|
||||
tristate "SDHCI support on PCI bus"
|
||||
depends on MMC_SDHCI && PCI
|
||||
select MMC_CQHCI
|
||||
select MMC_SDHCI_UHS2
|
||||
select IOSF_MBI if X86
|
||||
select MMC_SDHCI_IO_ACCESSORS
|
||||
help
|
||||
@ -1009,6 +1019,7 @@ config MMC_MTK
|
||||
depends on COMMON_CLK
|
||||
select REGULATOR
|
||||
select MMC_CQHCI
|
||||
select MMC_HSQ
|
||||
help
|
||||
This selects the MediaTek(R) Secure digital and Multimedia card Interface.
|
||||
If you have a machine with a integrated SD/MMC card reader, say Y or M here.
|
||||
|
@ -11,6 +11,7 @@ obj-$(CONFIG_MMC_PXA) += pxamci.o
|
||||
obj-$(CONFIG_MMC_MXC) += mxcmmc.o
|
||||
obj-$(CONFIG_MMC_MXS) += mxs-mmc.o
|
||||
obj-$(CONFIG_MMC_SDHCI) += sdhci.o
|
||||
obj-$(CONFIG_MMC_SDHCI_UHS2) += sdhci-uhs2.o
|
||||
obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o
|
||||
sdhci-pci-y += sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o \
|
||||
sdhci-pci-dwc-mshc.o sdhci-pci-gli.o
|
||||
|
@ -1175,7 +1175,7 @@ MODULE_DEVICE_TABLE(platform, alcor_pci_sdmmc_ids);
|
||||
|
||||
static struct platform_driver alcor_pci_sdmmc_driver = {
|
||||
.probe = alcor_pci_sdmmc_drv_probe,
|
||||
.remove_new = alcor_pci_sdmmc_drv_remove,
|
||||
.remove = alcor_pci_sdmmc_drv_remove,
|
||||
.id_table = alcor_pci_sdmmc_ids,
|
||||
.driver = {
|
||||
.name = DRV_NAME_ALCOR_PCI_SDMMC,
|
||||
|
@ -860,7 +860,7 @@ static void atmci_send_stop_cmd(struct atmel_mci *host, struct mmc_data *data)
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure given PDC buffer taking care of alignement issues.
|
||||
* Configure given PDC buffer taking care of alignment issues.
|
||||
* Update host->data_size and host->sg.
|
||||
*/
|
||||
static void atmci_pdc_set_single_buf(struct atmel_mci *host,
|
||||
@ -2653,7 +2653,7 @@ static const struct dev_pm_ops atmci_dev_pm_ops = {
|
||||
|
||||
static struct platform_driver atmci_driver = {
|
||||
.probe = atmci_probe,
|
||||
.remove_new = atmci_remove,
|
||||
.remove = atmci_remove,
|
||||
.driver = {
|
||||
.name = "atmel_mci",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -543,7 +543,7 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
|
||||
cmd->resp[i] |= (r[i + 1] & 0xFF000000) >> 24;
|
||||
}
|
||||
} else {
|
||||
/* Techincally, we should be getting all 48 bits of
|
||||
/* Technically, we should be getting all 48 bits of
|
||||
* the response (SD_RESP1 + SD_RESP2), but because
|
||||
* our response omits the CRC, our data ends up
|
||||
* being shifted 8 bits to the right. In this case,
|
||||
@ -1185,7 +1185,7 @@ static int au1xmmc_resume(struct platform_device *pdev)
|
||||
|
||||
static struct platform_driver au1xmmc_driver = {
|
||||
.probe = au1xmmc_probe,
|
||||
.remove_new = au1xmmc_remove,
|
||||
.remove = au1xmmc_remove,
|
||||
.suspend = au1xmmc_suspend,
|
||||
.resume = au1xmmc_resume,
|
||||
.driver = {
|
||||
|
@ -148,9 +148,10 @@ struct bcm2835_host {
|
||||
void __iomem *ioaddr;
|
||||
u32 phys_addr;
|
||||
|
||||
struct clk *clk;
|
||||
struct platform_device *pdev;
|
||||
|
||||
int clock; /* Current clock speed */
|
||||
unsigned int clock; /* Current clock speed */
|
||||
unsigned int max_clk; /* Max possible freq */
|
||||
struct work_struct dma_work;
|
||||
struct delayed_work timeout_work; /* Timer for timeouts */
|
||||
@ -1345,7 +1346,6 @@ static int bcm2835_add_host(struct bcm2835_host *host)
|
||||
static int bcm2835_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct clk *clk;
|
||||
struct bcm2835_host *host;
|
||||
struct mmc_host *mmc;
|
||||
const __be32 *regaddr_p;
|
||||
@ -1393,15 +1393,6 @@ static int bcm2835_probe(struct platform_device *pdev)
|
||||
/* Ignore errors to fall back to PIO mode */
|
||||
}
|
||||
|
||||
|
||||
clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(clk)) {
|
||||
ret = dev_err_probe(dev, PTR_ERR(clk), "could not get clk\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
host->max_clk = clk_get_rate(clk);
|
||||
|
||||
host->irq = platform_get_irq(pdev, 0);
|
||||
if (host->irq < 0) {
|
||||
ret = host->irq;
|
||||
@ -1412,16 +1403,30 @@ static int bcm2835_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = bcm2835_add_host(host);
|
||||
host->clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(host->clk)) {
|
||||
ret = dev_err_probe(dev, PTR_ERR(host->clk), "could not get clk\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(host->clk);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
host->max_clk = clk_get_rate(host->clk);
|
||||
|
||||
ret = bcm2835_add_host(host);
|
||||
if (ret)
|
||||
goto err_clk;
|
||||
|
||||
platform_set_drvdata(pdev, host);
|
||||
|
||||
dev_dbg(dev, "%s -> OK\n", __func__);
|
||||
|
||||
return 0;
|
||||
|
||||
err_clk:
|
||||
clk_disable_unprepare(host->clk);
|
||||
err:
|
||||
dev_dbg(dev, "%s -> err %d\n", __func__, ret);
|
||||
if (host->dma_chan_rxtx)
|
||||
@ -1445,6 +1450,8 @@ static void bcm2835_remove(struct platform_device *pdev)
|
||||
cancel_work_sync(&host->dma_work);
|
||||
cancel_delayed_work_sync(&host->timeout_work);
|
||||
|
||||
clk_disable_unprepare(host->clk);
|
||||
|
||||
if (host->dma_chan_rxtx)
|
||||
dma_release_channel(host->dma_chan_rxtx);
|
||||
|
||||
@ -1459,7 +1466,7 @@ MODULE_DEVICE_TABLE(of, bcm2835_match);
|
||||
|
||||
static struct platform_driver bcm2835_driver = {
|
||||
.probe = bcm2835_probe,
|
||||
.remove_new = bcm2835_remove,
|
||||
.remove = bcm2835_remove,
|
||||
.driver = {
|
||||
.name = "sdhost-bcm2835",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -217,7 +217,7 @@ static int octeon_mmc_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(base);
|
||||
host->dma_base = base;
|
||||
/*
|
||||
* To keep the register addresses shared we intentionaly use
|
||||
* To keep the register addresses shared we intentionally use
|
||||
* a negative offset here, first register used on Octeon therefore
|
||||
* starts at 0x20 (MIO_EMM_DMA_CFG).
|
||||
*/
|
||||
@ -326,7 +326,7 @@ MODULE_DEVICE_TABLE(of, octeon_mmc_match);
|
||||
|
||||
static struct platform_driver octeon_mmc_driver = {
|
||||
.probe = octeon_mmc_probe,
|
||||
.remove_new = octeon_mmc_remove,
|
||||
.remove = octeon_mmc_remove,
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -771,7 +771,7 @@ static void cb710_mmc_exit(struct platform_device *pdev)
|
||||
static struct platform_driver cb710_mmc_driver = {
|
||||
.driver.name = "cb710-mmc",
|
||||
.probe = cb710_mmc_init,
|
||||
.remove_new = cb710_mmc_exit,
|
||||
.remove = cb710_mmc_exit,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = cb710_mmc_suspend,
|
||||
.resume = cb710_mmc_resume,
|
||||
|
@ -7,24 +7,23 @@
|
||||
* Copyright (C) 2009 David Brownell
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/mmc/mmc.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/mmc/slot-gpio.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/mmc.h>
|
||||
#include <linux/mmc/slot-gpio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_data/mmc-davinci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
/*
|
||||
* Register Definitions
|
||||
@ -1229,7 +1228,7 @@ static int davinci_mmcsd_probe(struct platform_device *pdev)
|
||||
|
||||
host->mmc_input_clk = clk_get_rate(host->clk);
|
||||
|
||||
pdev->id_entry = of_device_get_match_data(&pdev->dev);
|
||||
pdev->id_entry = device_get_match_data(&pdev->dev);
|
||||
if (pdev->id_entry) {
|
||||
ret = mmc_of_parse(mmc);
|
||||
if (ret) {
|
||||
@ -1400,7 +1399,7 @@ static struct platform_driver davinci_mmcsd_driver = {
|
||||
.of_match_table = davinci_mmc_dt_ids,
|
||||
},
|
||||
.probe = davinci_mmcsd_probe,
|
||||
.remove_new = davinci_mmcsd_remove,
|
||||
.remove = davinci_mmcsd_remove,
|
||||
.id_table = davinci_mmc_devtype,
|
||||
};
|
||||
|
||||
|
@ -68,7 +68,7 @@ static int dw_mci_bluefield_probe(struct platform_device *pdev)
|
||||
|
||||
static struct platform_driver dw_mci_bluefield_pltfm_driver = {
|
||||
.probe = dw_mci_bluefield_probe,
|
||||
.remove_new = dw_mci_pltfm_remove,
|
||||
.remove = dw_mci_pltfm_remove,
|
||||
.driver = {
|
||||
.name = "dwmmc_bluefield",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -682,7 +682,7 @@ static const struct dev_pm_ops dw_mci_exynos_pmops = {
|
||||
|
||||
static struct platform_driver dw_mci_exynos_pltfm_driver = {
|
||||
.probe = dw_mci_exynos_probe,
|
||||
.remove_new = dw_mci_exynos_remove,
|
||||
.remove = dw_mci_exynos_remove,
|
||||
.driver = {
|
||||
.name = "dwmmc_exynos",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -189,7 +189,7 @@ static const struct of_device_id dw_mci_hi3798cv200_match[] = {
|
||||
MODULE_DEVICE_TABLE(of, dw_mci_hi3798cv200_match);
|
||||
static struct platform_driver dw_mci_hi3798cv200_driver = {
|
||||
.probe = dw_mci_hi3798cv200_probe,
|
||||
.remove_new = dw_mci_hi3798cv200_remove,
|
||||
.remove = dw_mci_hi3798cv200_remove,
|
||||
.driver = {
|
||||
.name = "dwmmc_hi3798cv200",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -237,7 +237,7 @@ static void dw_mci_hi3798mv200_remove(struct platform_device *pdev)
|
||||
MODULE_DEVICE_TABLE(of, dw_mci_hi3798mv200_match);
|
||||
static struct platform_driver dw_mci_hi3798mv200_driver = {
|
||||
.probe = dw_mci_hi3798mv200_probe,
|
||||
.remove_new = dw_mci_hi3798mv200_remove,
|
||||
.remove = dw_mci_hi3798mv200_remove,
|
||||
.driver = {
|
||||
.name = "dwmmc_hi3798mv200",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -470,7 +470,7 @@ static const struct dev_pm_ops dw_mci_k3_dev_pm_ops = {
|
||||
|
||||
static struct platform_driver dw_mci_k3_pltfm_driver = {
|
||||
.probe = dw_mci_k3_probe,
|
||||
.remove_new = dw_mci_pltfm_remove,
|
||||
.remove = dw_mci_pltfm_remove,
|
||||
.driver = {
|
||||
.name = "dwmmc_k3",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -131,7 +131,7 @@ EXPORT_SYMBOL_GPL(dw_mci_pltfm_remove);
|
||||
|
||||
static struct platform_driver dw_mci_pltfm_driver = {
|
||||
.probe = dw_mci_pltfm_probe,
|
||||
.remove_new = dw_mci_pltfm_remove,
|
||||
.remove = dw_mci_pltfm_remove,
|
||||
.driver = {
|
||||
.name = "dw_mmc",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -577,7 +577,7 @@ static const struct dev_pm_ops dw_mci_rockchip_dev_pm_ops = {
|
||||
|
||||
static struct platform_driver dw_mci_rockchip_pltfm_driver = {
|
||||
.probe = dw_mci_rockchip_probe,
|
||||
.remove_new = dw_mci_rockchip_remove,
|
||||
.remove = dw_mci_rockchip_remove,
|
||||
.driver = {
|
||||
.name = "dwmmc_rockchip",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -115,7 +115,7 @@ static int dw_mci_starfive_probe(struct platform_device *pdev)
|
||||
|
||||
static struct platform_driver dw_mci_starfive_driver = {
|
||||
.probe = dw_mci_starfive_probe,
|
||||
.remove_new = dw_mci_pltfm_remove,
|
||||
.remove = dw_mci_pltfm_remove,
|
||||
.driver = {
|
||||
.name = "dwmmc_starfive",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -1182,7 +1182,7 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
|
||||
/*
|
||||
* Use the initial fifoth_val for PIO mode. If wm_algined
|
||||
* is set, we set watermark same as data size.
|
||||
* If next issued data may be transfered by DMA mode,
|
||||
* If next issued data may be transferred by DMA mode,
|
||||
* prev_blksz should be invalidated.
|
||||
*/
|
||||
if (host->wm_aligned)
|
||||
|
@ -1191,7 +1191,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend,
|
||||
|
||||
static struct platform_driver jz4740_mmc_driver = {
|
||||
.probe = jz4740_mmc_probe,
|
||||
.remove_new = jz4740_mmc_remove,
|
||||
.remove = jz4740_mmc_remove,
|
||||
.driver = {
|
||||
.name = "jz4740-mmc",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -644,7 +644,7 @@ MODULE_DEVICE_TABLE(of, litex_match);
|
||||
|
||||
static struct platform_driver litex_mmc_driver = {
|
||||
.probe = litex_mmc_probe,
|
||||
.remove_new = litex_mmc_remove,
|
||||
.remove = litex_mmc_remove,
|
||||
.driver = {
|
||||
.name = "litex-mmc",
|
||||
.of_match_table = litex_match,
|
||||
|
@ -879,7 +879,7 @@ static void meson_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||
/*
|
||||
* The memory at the end of the controller used as bounce buffer for
|
||||
* the dram_access_quirk only accepts 32bit read/write access,
|
||||
* check the aligment and length of the data before starting the request.
|
||||
* check the alignment and length of the data before starting the request.
|
||||
*/
|
||||
if (host->dram_access_quirk && mrq->data) {
|
||||
mrq->cmd->error = meson_mmc_validate_dram_access(mmc, mrq->data);
|
||||
@ -1334,7 +1334,7 @@ MODULE_DEVICE_TABLE(of, meson_mmc_of_match);
|
||||
|
||||
static struct platform_driver meson_mmc_driver = {
|
||||
.probe = meson_mmc_probe,
|
||||
.remove_new = meson_mmc_remove,
|
||||
.remove = meson_mmc_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -904,7 +904,7 @@ MODULE_DEVICE_TABLE(of, meson_mx_sdhc_of_match);
|
||||
|
||||
static struct platform_driver meson_mx_sdhc_driver = {
|
||||
.probe = meson_mx_sdhc_probe,
|
||||
.remove_new = meson_mx_sdhc_remove,
|
||||
.remove = meson_mx_sdhc_remove,
|
||||
.driver = {
|
||||
.name = "meson-mx-sdhc",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -754,7 +754,7 @@ MODULE_DEVICE_TABLE(of, meson_mx_mmc_of_match);
|
||||
|
||||
static struct platform_driver meson_mx_mmc_driver = {
|
||||
.probe = meson_mx_mmc_probe,
|
||||
.remove_new = meson_mx_mmc_remove,
|
||||
.remove = meson_mx_mmc_remove,
|
||||
.driver = {
|
||||
.name = "meson-mx-sdio",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -222,10 +222,6 @@ static int mmc_spi_response_get(struct mmc_spi_host *host,
|
||||
u8 leftover = 0;
|
||||
unsigned short rotator;
|
||||
int i;
|
||||
char tag[32];
|
||||
|
||||
snprintf(tag, sizeof(tag), " ... CMD%d response SPI_%s",
|
||||
cmd->opcode, maptype(cmd));
|
||||
|
||||
/* Except for data block reads, the whole response will already
|
||||
* be stored in the scratch buffer. It's somewhere after the
|
||||
@ -378,8 +374,9 @@ checkstatus:
|
||||
}
|
||||
|
||||
if (value < 0)
|
||||
dev_dbg(&host->spi->dev, "%s: resp %04x %08x\n",
|
||||
tag, cmd->resp[0], cmd->resp[1]);
|
||||
dev_dbg(&host->spi->dev,
|
||||
" ... CMD%d response SPI_%s: resp %04x %08x\n",
|
||||
cmd->opcode, maptype(cmd), cmd->resp[0], cmd->resp[1]);
|
||||
|
||||
/* disable chipselect on errors and some success cases */
|
||||
if (value >= 0 && cs_on)
|
||||
|
@ -77,7 +77,7 @@
|
||||
#define MCI_CPSM_INTERRUPT BIT(8)
|
||||
#define MCI_CPSM_PENDING BIT(9)
|
||||
#define MCI_CPSM_ENABLE BIT(10)
|
||||
/* Command register flag extenstions in the ST Micro versions */
|
||||
/* Command register flag extensions in the ST Micro versions */
|
||||
#define MCI_CPSM_ST_SDIO_SUSP BIT(11)
|
||||
#define MCI_CPSM_ST_ENCMD_COMPL BIT(12)
|
||||
#define MCI_CPSM_ST_NIEN BIT(13)
|
||||
|
@ -719,7 +719,7 @@ MODULE_DEVICE_TABLE(of, moxart_mmc_match);
|
||||
|
||||
static struct platform_driver moxart_mmc_driver = {
|
||||
.probe = moxart_probe,
|
||||
.remove_new = moxart_remove,
|
||||
.remove = moxart_remove,
|
||||
.driver = {
|
||||
.name = "mmc-moxart",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <linux/mmc/slot-gpio.h>
|
||||
|
||||
#include "cqhci.h"
|
||||
#include "mmc_hsq.h"
|
||||
|
||||
#define MAX_BD_NUM 1024
|
||||
#define MSDC_NR_CLOCKS 3
|
||||
@ -65,6 +66,7 @@
|
||||
#define SDC_RESP3 0x4c
|
||||
#define SDC_BLK_NUM 0x50
|
||||
#define SDC_ADV_CFG0 0x64
|
||||
#define MSDC_NEW_RX_CFG 0x68
|
||||
#define EMMC_IOCON 0x7c
|
||||
#define SDC_ACMD_RESP 0x80
|
||||
#define DMA_SA_H4BIT 0x8c
|
||||
@ -91,6 +93,7 @@
|
||||
#define EMMC_TOP_CONTROL 0x00
|
||||
#define EMMC_TOP_CMD 0x04
|
||||
#define EMMC50_PAD_DS_TUNE 0x0c
|
||||
#define LOOP_TEST_CONTROL 0x30
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Register Mask */
|
||||
@ -202,9 +205,13 @@
|
||||
#define SDC_STS_CMDBUSY BIT(1) /* RW */
|
||||
#define SDC_STS_SWR_COMPL BIT(31) /* RW */
|
||||
|
||||
#define SDC_DAT1_IRQ_TRIGGER BIT(19) /* RW */
|
||||
/* SDC_ADV_CFG0 mask */
|
||||
#define SDC_DAT1_IRQ_TRIGGER BIT(19) /* RW */
|
||||
#define SDC_RX_ENHANCE_EN BIT(20) /* RW */
|
||||
#define SDC_NEW_TX_EN BIT(31) /* RW */
|
||||
|
||||
/* MSDC_NEW_RX_CFG mask */
|
||||
#define MSDC_NEW_RX_PATH_SEL BIT(0) /* RW */
|
||||
|
||||
/* DMA_SA_H4BIT mask */
|
||||
#define DMA_ADDR_HIGH_4BIT GENMASK(3, 0) /* RW */
|
||||
@ -226,6 +233,7 @@
|
||||
|
||||
/* MSDC_PATCH_BIT mask */
|
||||
#define MSDC_PATCH_BIT_ODDSUPP BIT(1) /* RW */
|
||||
#define MSDC_PATCH_BIT_RD_DAT_SEL BIT(3) /* RW */
|
||||
#define MSDC_INT_DAT_LATCH_CK_SEL GENMASK(9, 7)
|
||||
#define MSDC_CKGEN_MSDC_DLY_SEL GENMASK(14, 10)
|
||||
#define MSDC_PATCH_BIT_IODSSEL BIT(16) /* RW */
|
||||
@ -247,6 +255,8 @@
|
||||
#define MSDC_PB2_SUPPORT_64G BIT(1) /* RW */
|
||||
#define MSDC_PB2_RESPWAIT GENMASK(3, 2) /* RW */
|
||||
#define MSDC_PB2_RESPSTSENSEL GENMASK(18, 16) /* RW */
|
||||
#define MSDC_PB2_POP_EN_CNT GENMASK(23, 20) /* RW */
|
||||
#define MSDC_PB2_CFGCRCSTSEDGE BIT(25) /* RW */
|
||||
#define MSDC_PB2_CRCSTSENSEL GENMASK(31, 29) /* RW */
|
||||
|
||||
#define MSDC_PAD_TUNE_DATWRDLY GENMASK(4, 0) /* RW */
|
||||
@ -311,6 +321,12 @@
|
||||
#define PAD_DS_DLY1 GENMASK(14, 10) /* RW */
|
||||
#define PAD_DS_DLY3 GENMASK(4, 0) /* RW */
|
||||
|
||||
/* LOOP_TEST_CONTROL mask */
|
||||
#define TEST_LOOP_DSCLK_MUX_SEL BIT(0) /* RW */
|
||||
#define TEST_LOOP_LATCH_MUX_SEL BIT(1) /* RW */
|
||||
#define LOOP_EN_SEL_CLK BIT(20) /* RW */
|
||||
#define TEST_HS400_CMD_LOOP_MUX_SEL BIT(31) /* RW */
|
||||
|
||||
#define REQ_CMD_EIO BIT(0)
|
||||
#define REQ_CMD_TMO BIT(1)
|
||||
#define REQ_DAT_ERR BIT(2)
|
||||
@ -391,6 +407,7 @@ struct msdc_save_para {
|
||||
u32 emmc_top_control;
|
||||
u32 emmc_top_cmd;
|
||||
u32 emmc50_pad_ds_tune;
|
||||
u32 loop_test_control;
|
||||
};
|
||||
|
||||
struct mtk_mmc_compatible {
|
||||
@ -402,9 +419,13 @@ struct mtk_mmc_compatible {
|
||||
bool data_tune;
|
||||
bool busy_check;
|
||||
bool stop_clk_fix;
|
||||
u8 stop_dly_sel;
|
||||
u8 pop_en_cnt;
|
||||
bool enhance_rx;
|
||||
bool support_64g;
|
||||
bool use_internal_cd;
|
||||
bool support_new_tx;
|
||||
bool support_new_rx;
|
||||
};
|
||||
|
||||
struct msdc_tune_para {
|
||||
@ -473,6 +494,7 @@ struct msdc_host {
|
||||
bool hs400_tuning; /* hs400 mode online tuning */
|
||||
bool internal_cd; /* Use internal card-detect logic */
|
||||
bool cqhci; /* support eMMC hw cmdq */
|
||||
bool hsq_en; /* Host Software Queue is enabled */
|
||||
struct msdc_save_para save_para; /* used when gate HCLK */
|
||||
struct msdc_tune_para def_tune_para; /* default tune setting */
|
||||
struct msdc_tune_para saved_tune_para; /* tune result of CMD21/CMD19 */
|
||||
@ -502,6 +524,7 @@ static const struct mtk_mmc_compatible mt2712_compat = {
|
||||
.data_tune = true,
|
||||
.busy_check = true,
|
||||
.stop_clk_fix = true,
|
||||
.stop_dly_sel = 3,
|
||||
.enhance_rx = true,
|
||||
.support_64g = true,
|
||||
};
|
||||
@ -515,6 +538,7 @@ static const struct mtk_mmc_compatible mt6779_compat = {
|
||||
.data_tune = true,
|
||||
.busy_check = true,
|
||||
.stop_clk_fix = true,
|
||||
.stop_dly_sel = 3,
|
||||
.enhance_rx = true,
|
||||
.support_64g = true,
|
||||
};
|
||||
@ -554,6 +578,7 @@ static const struct mtk_mmc_compatible mt7622_compat = {
|
||||
.data_tune = true,
|
||||
.busy_check = true,
|
||||
.stop_clk_fix = true,
|
||||
.stop_dly_sel = 3,
|
||||
.enhance_rx = true,
|
||||
.support_64g = false,
|
||||
};
|
||||
@ -567,6 +592,7 @@ static const struct mtk_mmc_compatible mt7986_compat = {
|
||||
.data_tune = true,
|
||||
.busy_check = true,
|
||||
.stop_clk_fix = true,
|
||||
.stop_dly_sel = 3,
|
||||
.enhance_rx = true,
|
||||
.support_64g = true,
|
||||
};
|
||||
@ -606,6 +632,7 @@ static const struct mtk_mmc_compatible mt8183_compat = {
|
||||
.data_tune = true,
|
||||
.busy_check = true,
|
||||
.stop_clk_fix = true,
|
||||
.stop_dly_sel = 3,
|
||||
.enhance_rx = true,
|
||||
.support_64g = true,
|
||||
};
|
||||
@ -619,6 +646,24 @@ static const struct mtk_mmc_compatible mt8516_compat = {
|
||||
.data_tune = true,
|
||||
.busy_check = true,
|
||||
.stop_clk_fix = true,
|
||||
.stop_dly_sel = 3,
|
||||
};
|
||||
|
||||
static const struct mtk_mmc_compatible mt8196_compat = {
|
||||
.clk_div_bits = 12,
|
||||
.recheck_sdio_irq = false,
|
||||
.hs400_tune = false,
|
||||
.pad_tune_reg = MSDC_PAD_TUNE0,
|
||||
.async_fifo = true,
|
||||
.data_tune = true,
|
||||
.busy_check = true,
|
||||
.stop_clk_fix = true,
|
||||
.stop_dly_sel = 1,
|
||||
.pop_en_cnt = 2,
|
||||
.enhance_rx = true,
|
||||
.support_64g = true,
|
||||
.support_new_tx = true,
|
||||
.support_new_rx = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id msdc_of_ids[] = {
|
||||
@ -629,9 +674,11 @@ static const struct of_device_id msdc_of_ids[] = {
|
||||
{ .compatible = "mediatek,mt7620-mmc", .data = &mt7620_compat},
|
||||
{ .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat},
|
||||
{ .compatible = "mediatek,mt7986-mmc", .data = &mt7986_compat},
|
||||
{ .compatible = "mediatek,mt7988-mmc", .data = &mt7986_compat},
|
||||
{ .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat},
|
||||
{ .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat},
|
||||
{ .compatible = "mediatek,mt8183-mmc", .data = &mt8183_compat},
|
||||
{ .compatible = "mediatek,mt8196-mmc", .data = &mt8196_compat},
|
||||
{ .compatible = "mediatek,mt8516-mmc", .data = &mt8516_compat},
|
||||
|
||||
{}
|
||||
@ -872,6 +919,41 @@ static int msdc_ungate_clock(struct msdc_host *host)
|
||||
(val & MSDC_CFG_CKSTB), 1, 20000);
|
||||
}
|
||||
|
||||
static void msdc_new_tx_setting(struct msdc_host *host)
|
||||
{
|
||||
if (!host->top_base)
|
||||
return;
|
||||
|
||||
sdr_set_bits(host->top_base + LOOP_TEST_CONTROL,
|
||||
TEST_LOOP_DSCLK_MUX_SEL);
|
||||
sdr_set_bits(host->top_base + LOOP_TEST_CONTROL,
|
||||
TEST_LOOP_LATCH_MUX_SEL);
|
||||
sdr_clr_bits(host->top_base + LOOP_TEST_CONTROL,
|
||||
TEST_HS400_CMD_LOOP_MUX_SEL);
|
||||
|
||||
switch (host->timing) {
|
||||
case MMC_TIMING_LEGACY:
|
||||
case MMC_TIMING_MMC_HS:
|
||||
case MMC_TIMING_SD_HS:
|
||||
case MMC_TIMING_UHS_SDR12:
|
||||
case MMC_TIMING_UHS_SDR25:
|
||||
case MMC_TIMING_UHS_DDR50:
|
||||
case MMC_TIMING_MMC_DDR52:
|
||||
sdr_clr_bits(host->top_base + LOOP_TEST_CONTROL,
|
||||
LOOP_EN_SEL_CLK);
|
||||
break;
|
||||
case MMC_TIMING_UHS_SDR50:
|
||||
case MMC_TIMING_UHS_SDR104:
|
||||
case MMC_TIMING_MMC_HS200:
|
||||
case MMC_TIMING_MMC_HS400:
|
||||
sdr_set_bits(host->top_base + LOOP_TEST_CONTROL,
|
||||
LOOP_EN_SEL_CLK);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
|
||||
{
|
||||
struct mmc_host *mmc = mmc_from_priv(host);
|
||||
@ -881,6 +963,7 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
|
||||
u32 sclk;
|
||||
u32 tune_reg = host->dev_comp->pad_tune_reg;
|
||||
u32 val;
|
||||
bool timing_changed;
|
||||
|
||||
if (!hz) {
|
||||
dev_dbg(host->dev, "set mclk to 0\n");
|
||||
@ -890,6 +973,11 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
|
||||
return;
|
||||
}
|
||||
|
||||
if (host->timing != timing)
|
||||
timing_changed = true;
|
||||
else
|
||||
timing_changed = false;
|
||||
|
||||
flags = readl(host->base + MSDC_INTEN);
|
||||
sdr_clr_bits(host->base + MSDC_INTEN, flags);
|
||||
if (host->dev_comp->clk_div_bits == 8)
|
||||
@ -996,6 +1084,9 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
|
||||
sdr_set_field(host->base + tune_reg,
|
||||
MSDC_PAD_TUNE_CMDRRDLY,
|
||||
host->hs400_cmd_int_delay);
|
||||
if (host->dev_comp->support_new_tx && timing_changed)
|
||||
msdc_new_tx_setting(host);
|
||||
|
||||
dev_dbg(host->dev, "sclk: %d, timing: %d\n", mmc->actual_clock,
|
||||
timing);
|
||||
}
|
||||
@ -1163,7 +1254,9 @@ static void msdc_track_cmd_data(struct msdc_host *host, struct mmc_command *cmd)
|
||||
|
||||
static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq)
|
||||
{
|
||||
struct mmc_host *mmc = mmc_from_priv(host);
|
||||
unsigned long flags;
|
||||
bool hsq_req_done;
|
||||
|
||||
/*
|
||||
* No need check the return value of cancel_delayed_work, as only ONE
|
||||
@ -1171,6 +1264,27 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq)
|
||||
*/
|
||||
cancel_delayed_work(&host->req_timeout);
|
||||
|
||||
/*
|
||||
* If the request was handled from Host Software Queue, there's almost
|
||||
* nothing to do here, and we also don't need to reset mrq as any race
|
||||
* condition would not have any room to happen, since HSQ stores the
|
||||
* "scheduled" mrqs in an internal array of mrq slots anyway.
|
||||
* However, if the controller experienced an error, we still want to
|
||||
* reset it as soon as possible.
|
||||
*
|
||||
* Note that non-HSQ requests will still be happening at times, even
|
||||
* though it is enabled, and that's what is going to reset host->mrq.
|
||||
* Also, msdc_unprepare_data() is going to be called by HSQ when needed
|
||||
* as HSQ request finalization will eventually call the .post_req()
|
||||
* callback of this driver which, in turn, unprepares the data.
|
||||
*/
|
||||
hsq_req_done = host->hsq_en ? mmc_hsq_finalize_request(mmc, mrq) : false;
|
||||
if (hsq_req_done) {
|
||||
if (host->error)
|
||||
msdc_reset_hw(host);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
host->mrq = NULL;
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
@ -1180,7 +1294,7 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq)
|
||||
msdc_unprepare_data(host, mrq->data);
|
||||
if (host->error)
|
||||
msdc_reset_hw(host);
|
||||
mmc_request_done(mmc_from_priv(host), mrq);
|
||||
mmc_request_done(mmc, mrq);
|
||||
if (host->dev_comp->recheck_sdio_irq)
|
||||
msdc_recheck_sdio_irq(host);
|
||||
}
|
||||
@ -1340,7 +1454,7 @@ static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||
struct msdc_host *host = mmc_priv(mmc);
|
||||
|
||||
host->error = 0;
|
||||
WARN_ON(host->mrq);
|
||||
WARN_ON(!host->hsq_en && host->mrq);
|
||||
host->mrq = mrq;
|
||||
|
||||
if (mrq->data)
|
||||
@ -1704,6 +1818,17 @@ static void msdc_init_hw(struct msdc_host *host)
|
||||
reset_control_deassert(host->reset);
|
||||
}
|
||||
|
||||
/* New tx/rx enable bit need to be 0->1 for hardware check */
|
||||
if (host->dev_comp->support_new_tx) {
|
||||
sdr_clr_bits(host->base + SDC_ADV_CFG0, SDC_NEW_TX_EN);
|
||||
sdr_set_bits(host->base + SDC_ADV_CFG0, SDC_NEW_TX_EN);
|
||||
msdc_new_tx_setting(host);
|
||||
}
|
||||
if (host->dev_comp->support_new_rx) {
|
||||
sdr_clr_bits(host->base + MSDC_NEW_RX_CFG, MSDC_NEW_RX_PATH_SEL);
|
||||
sdr_set_bits(host->base + MSDC_NEW_RX_CFG, MSDC_NEW_RX_PATH_SEL);
|
||||
}
|
||||
|
||||
/* Configure to MMC/SD mode, clock free running */
|
||||
sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_MODE | MSDC_CFG_CKPDN);
|
||||
|
||||
@ -1742,8 +1867,16 @@ static void msdc_init_hw(struct msdc_host *host)
|
||||
sdr_set_bits(host->base + EMMC50_CFG0, EMMC50_CFG_CFCSTS_SEL);
|
||||
|
||||
if (host->dev_comp->stop_clk_fix) {
|
||||
if (host->dev_comp->stop_dly_sel)
|
||||
sdr_set_field(host->base + MSDC_PATCH_BIT1,
|
||||
MSDC_PATCH_BIT1_STOP_DLY, 3);
|
||||
MSDC_PATCH_BIT1_STOP_DLY,
|
||||
host->dev_comp->stop_dly_sel);
|
||||
|
||||
if (host->dev_comp->pop_en_cnt)
|
||||
sdr_set_field(host->base + MSDC_PATCH_BIT2,
|
||||
MSDC_PB2_POP_EN_CNT,
|
||||
host->dev_comp->pop_en_cnt);
|
||||
|
||||
sdr_clr_bits(host->base + SDC_FIFO_CFG,
|
||||
SDC_FIFO_CFG_WRVALIDSEL);
|
||||
sdr_clr_bits(host->base + SDC_FIFO_CFG,
|
||||
@ -2055,6 +2188,19 @@ static inline void msdc_set_data_delay(struct msdc_host *host, u32 value)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void msdc_set_data_sample_edge(struct msdc_host *host, bool rising)
|
||||
{
|
||||
u32 value = rising ? 0 : 1;
|
||||
|
||||
if (host->dev_comp->support_new_rx) {
|
||||
sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_PATCH_BIT_RD_DAT_SEL, value);
|
||||
sdr_set_field(host->base + MSDC_PATCH_BIT2, MSDC_PB2_CFGCRCSTSEDGE, value);
|
||||
} else {
|
||||
sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DSPL, value);
|
||||
sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL, value);
|
||||
}
|
||||
}
|
||||
|
||||
static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
|
||||
{
|
||||
struct msdc_host *host = mmc_priv(mmc);
|
||||
@ -2210,8 +2356,7 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
|
||||
|
||||
sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_INT_DAT_LATCH_CK_SEL,
|
||||
host->latch_ck);
|
||||
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
|
||||
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
|
||||
msdc_set_data_sample_edge(host, true);
|
||||
for (i = 0; i < host->tuning_step; i++) {
|
||||
msdc_set_data_delay(host, i);
|
||||
ret = mmc_send_tuning(mmc, opcode, NULL);
|
||||
@ -2224,8 +2369,7 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
|
||||
(final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4))
|
||||
goto skip_fall;
|
||||
|
||||
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
|
||||
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
|
||||
msdc_set_data_sample_edge(host, false);
|
||||
for (i = 0; i < host->tuning_step; i++) {
|
||||
msdc_set_data_delay(host, i);
|
||||
ret = mmc_send_tuning(mmc, opcode, NULL);
|
||||
@ -2237,12 +2381,10 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
|
||||
skip_fall:
|
||||
final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
|
||||
if (final_maxlen == final_rise_delay.maxlen) {
|
||||
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
|
||||
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
|
||||
msdc_set_data_sample_edge(host, true);
|
||||
final_delay = final_rise_delay.final_phase;
|
||||
} else {
|
||||
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
|
||||
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
|
||||
msdc_set_data_sample_edge(host, false);
|
||||
final_delay = final_fall_delay.final_phase;
|
||||
}
|
||||
msdc_set_data_delay(host, final_delay);
|
||||
@ -2267,8 +2409,7 @@ static int msdc_tune_together(struct mmc_host *mmc, u32 opcode)
|
||||
host->latch_ck);
|
||||
|
||||
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
|
||||
sdr_clr_bits(host->base + MSDC_IOCON,
|
||||
MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL);
|
||||
msdc_set_data_sample_edge(host, true);
|
||||
for (i = 0; i < host->tuning_step; i++) {
|
||||
msdc_set_cmd_delay(host, i);
|
||||
msdc_set_data_delay(host, i);
|
||||
@ -2283,8 +2424,7 @@ static int msdc_tune_together(struct mmc_host *mmc, u32 opcode)
|
||||
goto skip_fall;
|
||||
|
||||
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
|
||||
sdr_set_bits(host->base + MSDC_IOCON,
|
||||
MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL);
|
||||
msdc_set_data_sample_edge(host, false);
|
||||
for (i = 0; i < host->tuning_step; i++) {
|
||||
msdc_set_cmd_delay(host, i);
|
||||
msdc_set_data_delay(host, i);
|
||||
@ -2298,13 +2438,11 @@ skip_fall:
|
||||
final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
|
||||
if (final_maxlen == final_rise_delay.maxlen) {
|
||||
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
|
||||
sdr_clr_bits(host->base + MSDC_IOCON,
|
||||
MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL);
|
||||
msdc_set_data_sample_edge(host, true);
|
||||
final_delay = final_rise_delay.final_phase;
|
||||
} else {
|
||||
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
|
||||
sdr_set_bits(host->base + MSDC_IOCON,
|
||||
MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL);
|
||||
msdc_set_data_sample_edge(host, false);
|
||||
final_delay = final_fall_delay.final_phase;
|
||||
}
|
||||
|
||||
@ -2324,8 +2462,7 @@ static int msdc_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
||||
if (host->dev_comp->data_tune && host->dev_comp->async_fifo) {
|
||||
ret = msdc_tune_together(mmc, opcode);
|
||||
if (host->hs400_mode) {
|
||||
sdr_clr_bits(host->base + MSDC_IOCON,
|
||||
MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL);
|
||||
msdc_set_data_sample_edge(host, true);
|
||||
msdc_set_data_delay(host, 0);
|
||||
}
|
||||
goto tune_done;
|
||||
@ -2727,7 +2864,6 @@ static int msdc_drv_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mmc_host *mmc;
|
||||
struct msdc_host *host;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
if (!pdev->dev.of_node) {
|
||||
@ -2736,77 +2872,64 @@ static int msdc_drv_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* Allocate MMC host for this device */
|
||||
mmc = mmc_alloc_host(sizeof(struct msdc_host), &pdev->dev);
|
||||
mmc = devm_mmc_alloc_host(&pdev->dev, sizeof(struct msdc_host));
|
||||
if (!mmc)
|
||||
return -ENOMEM;
|
||||
|
||||
host = mmc_priv(mmc);
|
||||
ret = mmc_of_parse(mmc);
|
||||
if (ret)
|
||||
goto host_free;
|
||||
return ret;
|
||||
|
||||
host->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(host->base)) {
|
||||
ret = PTR_ERR(host->base);
|
||||
goto host_free;
|
||||
}
|
||||
if (IS_ERR(host->base))
|
||||
return PTR_ERR(host->base);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (res) {
|
||||
host->top_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
host->top_base = devm_platform_ioremap_resource(pdev, 1);
|
||||
if (IS_ERR(host->top_base))
|
||||
host->top_base = NULL;
|
||||
}
|
||||
|
||||
ret = mmc_regulator_get_supply(mmc);
|
||||
if (ret)
|
||||
goto host_free;
|
||||
return ret;
|
||||
|
||||
ret = msdc_of_clock_parse(pdev, host);
|
||||
if (ret)
|
||||
goto host_free;
|
||||
return ret;
|
||||
|
||||
host->reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
|
||||
"hrst");
|
||||
if (IS_ERR(host->reset)) {
|
||||
ret = PTR_ERR(host->reset);
|
||||
goto host_free;
|
||||
}
|
||||
if (IS_ERR(host->reset))
|
||||
return PTR_ERR(host->reset);
|
||||
|
||||
/* only eMMC has crypto property */
|
||||
if (!(mmc->caps2 & MMC_CAP2_NO_MMC)) {
|
||||
host->crypto_clk = devm_clk_get_optional(&pdev->dev, "crypto");
|
||||
if (IS_ERR(host->crypto_clk))
|
||||
host->crypto_clk = NULL;
|
||||
else
|
||||
return PTR_ERR(host->crypto_clk);
|
||||
else if (host->crypto_clk)
|
||||
mmc->caps2 |= MMC_CAP2_CRYPTO;
|
||||
}
|
||||
|
||||
host->irq = platform_get_irq(pdev, 0);
|
||||
if (host->irq < 0) {
|
||||
ret = host->irq;
|
||||
goto host_free;
|
||||
}
|
||||
if (host->irq < 0)
|
||||
return host->irq;
|
||||
|
||||
host->pinctrl = devm_pinctrl_get(&pdev->dev);
|
||||
if (IS_ERR(host->pinctrl)) {
|
||||
ret = PTR_ERR(host->pinctrl);
|
||||
dev_err(&pdev->dev, "Cannot find pinctrl!\n");
|
||||
goto host_free;
|
||||
}
|
||||
if (IS_ERR(host->pinctrl))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(host->pinctrl),
|
||||
"Cannot find pinctrl");
|
||||
|
||||
host->pins_default = pinctrl_lookup_state(host->pinctrl, "default");
|
||||
if (IS_ERR(host->pins_default)) {
|
||||
ret = PTR_ERR(host->pins_default);
|
||||
dev_err(&pdev->dev, "Cannot find pinctrl default!\n");
|
||||
goto host_free;
|
||||
return PTR_ERR(host->pins_default);
|
||||
}
|
||||
|
||||
host->pins_uhs = pinctrl_lookup_state(host->pinctrl, "state_uhs");
|
||||
if (IS_ERR(host->pins_uhs)) {
|
||||
ret = PTR_ERR(host->pins_uhs);
|
||||
dev_err(&pdev->dev, "Cannot find pinctrl uhs!\n");
|
||||
goto host_free;
|
||||
return PTR_ERR(host->pins_uhs);
|
||||
}
|
||||
|
||||
/* Support for SDIO eint irq ? */
|
||||
@ -2885,7 +3008,7 @@ static int msdc_drv_probe(struct platform_device *pdev)
|
||||
ret = msdc_ungate_clock(host);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Cannot ungate clocks!\n");
|
||||
goto release_mem;
|
||||
goto release_clk;
|
||||
}
|
||||
msdc_init_hw(host);
|
||||
|
||||
@ -2895,20 +3018,33 @@ static int msdc_drv_probe(struct platform_device *pdev)
|
||||
GFP_KERNEL);
|
||||
if (!host->cq_host) {
|
||||
ret = -ENOMEM;
|
||||
goto host_free;
|
||||
goto release;
|
||||
}
|
||||
host->cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
|
||||
host->cq_host->mmio = host->base + 0x800;
|
||||
host->cq_host->ops = &msdc_cmdq_ops;
|
||||
ret = cqhci_init(host->cq_host, mmc, true);
|
||||
if (ret)
|
||||
goto host_free;
|
||||
goto release;
|
||||
mmc->max_segs = 128;
|
||||
/* cqhci 16bit length */
|
||||
/* 0 size, means 65536 so we don't have to -1 here */
|
||||
mmc->max_seg_size = 64 * 1024;
|
||||
/* Reduce CIT to 0x40 that corresponds to 2.35us */
|
||||
msdc_cqe_cit_cal(host, 2350);
|
||||
} else if (mmc->caps2 & MMC_CAP2_NO_SDIO) {
|
||||
/* Use HSQ on eMMC/SD (but not on SDIO) if HW CQE not supported */
|
||||
struct mmc_hsq *hsq = devm_kzalloc(&pdev->dev, sizeof(*hsq), GFP_KERNEL);
|
||||
if (!hsq) {
|
||||
ret = -ENOMEM;
|
||||
goto release;
|
||||
}
|
||||
|
||||
ret = mmc_hsq_init(hsq, mmc);
|
||||
if (ret)
|
||||
goto release;
|
||||
|
||||
host->hsq_en = true;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, host->irq, msdc_irq,
|
||||
@ -2929,9 +3065,10 @@ static int msdc_drv_probe(struct platform_device *pdev)
|
||||
end:
|
||||
pm_runtime_disable(host->dev);
|
||||
release:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
msdc_deinit_hw(host);
|
||||
release_clk:
|
||||
msdc_gate_clock(host);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
release_mem:
|
||||
if (host->dma.gpd)
|
||||
dma_free_coherent(&pdev->dev,
|
||||
@ -2941,9 +3078,6 @@ release_mem:
|
||||
dma_free_coherent(&pdev->dev,
|
||||
MAX_BD_NUM * sizeof(struct mt_bdma_desc),
|
||||
host->dma.bd, host->dma.bd_addr);
|
||||
host_free:
|
||||
mmc_free_host(mmc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2969,8 +3103,6 @@ static void msdc_drv_remove(struct platform_device *pdev)
|
||||
host->dma.gpd, host->dma.gpd_addr);
|
||||
dma_free_coherent(&pdev->dev, MAX_BD_NUM * sizeof(struct mt_bdma_desc),
|
||||
host->dma.bd, host->dma.bd_addr);
|
||||
|
||||
mmc_free_host(mmc);
|
||||
}
|
||||
|
||||
static void msdc_save_reg(struct msdc_host *host)
|
||||
@ -2995,6 +3127,8 @@ static void msdc_save_reg(struct msdc_host *host)
|
||||
readl(host->top_base + EMMC_TOP_CMD);
|
||||
host->save_para.emmc50_pad_ds_tune =
|
||||
readl(host->top_base + EMMC50_PAD_DS_TUNE);
|
||||
host->save_para.loop_test_control =
|
||||
readl(host->top_base + LOOP_TEST_CONTROL);
|
||||
} else {
|
||||
host->save_para.pad_tune = readl(host->base + tune_reg);
|
||||
}
|
||||
@ -3005,6 +3139,15 @@ static void msdc_restore_reg(struct msdc_host *host)
|
||||
struct mmc_host *mmc = mmc_from_priv(host);
|
||||
u32 tune_reg = host->dev_comp->pad_tune_reg;
|
||||
|
||||
if (host->dev_comp->support_new_tx) {
|
||||
sdr_clr_bits(host->base + SDC_ADV_CFG0, SDC_NEW_TX_EN);
|
||||
sdr_set_bits(host->base + SDC_ADV_CFG0, SDC_NEW_TX_EN);
|
||||
}
|
||||
if (host->dev_comp->support_new_rx) {
|
||||
sdr_clr_bits(host->base + MSDC_NEW_RX_CFG, MSDC_NEW_RX_PATH_SEL);
|
||||
sdr_set_bits(host->base + MSDC_NEW_RX_CFG, MSDC_NEW_RX_PATH_SEL);
|
||||
}
|
||||
|
||||
writel(host->save_para.msdc_cfg, host->base + MSDC_CFG);
|
||||
writel(host->save_para.iocon, host->base + MSDC_IOCON);
|
||||
writel(host->save_para.sdc_cfg, host->base + SDC_CFG);
|
||||
@ -3023,6 +3166,8 @@ static void msdc_restore_reg(struct msdc_host *host)
|
||||
host->top_base + EMMC_TOP_CMD);
|
||||
writel(host->save_para.emmc50_pad_ds_tune,
|
||||
host->top_base + EMMC50_PAD_DS_TUNE);
|
||||
writel(host->save_para.loop_test_control,
|
||||
host->top_base + LOOP_TEST_CONTROL);
|
||||
} else {
|
||||
writel(host->save_para.pad_tune, host->base + tune_reg);
|
||||
}
|
||||
@ -3036,6 +3181,9 @@ static int __maybe_unused msdc_runtime_suspend(struct device *dev)
|
||||
struct mmc_host *mmc = dev_get_drvdata(dev);
|
||||
struct msdc_host *host = mmc_priv(mmc);
|
||||
|
||||
if (host->hsq_en)
|
||||
mmc_hsq_suspend(mmc);
|
||||
|
||||
msdc_save_reg(host);
|
||||
|
||||
if (sdio_irq_claimed(mmc)) {
|
||||
@ -3066,6 +3214,10 @@ static int __maybe_unused msdc_runtime_resume(struct device *dev)
|
||||
pinctrl_select_state(host->pinctrl, host->pins_uhs);
|
||||
enable_irq(host->irq);
|
||||
}
|
||||
|
||||
if (host->hsq_en)
|
||||
mmc_hsq_resume(mmc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3112,7 +3264,7 @@ static const struct dev_pm_ops msdc_dev_pm_ops = {
|
||||
|
||||
static struct platform_driver mt_msdc_driver = {
|
||||
.probe = msdc_drv_probe,
|
||||
.remove_new = msdc_drv_remove,
|
||||
.remove = msdc_drv_remove,
|
||||
.driver = {
|
||||
.name = "mtk-msdc",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -819,7 +819,7 @@ MODULE_DEVICE_TABLE(of, mvsdio_dt_ids);
|
||||
|
||||
static struct platform_driver mvsd_driver = {
|
||||
.probe = mvsd_probe,
|
||||
.remove_new = mvsd_remove,
|
||||
.remove = mvsd_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -1225,7 +1225,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume);
|
||||
|
||||
static struct platform_driver mxcmci_driver = {
|
||||
.probe = mxcmci_probe,
|
||||
.remove_new = mxcmci_remove,
|
||||
.remove = mxcmci_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -714,7 +714,7 @@ static SIMPLE_DEV_PM_OPS(mxs_mmc_pm_ops, mxs_mmc_suspend, mxs_mmc_resume);
|
||||
|
||||
static struct platform_driver mxs_mmc_driver = {
|
||||
.probe = mxs_mmc_probe,
|
||||
.remove_new = mxs_mmc_remove,
|
||||
.remove = mxs_mmc_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -1554,7 +1554,7 @@ MODULE_DEVICE_TABLE(of, mmc_omap_match);
|
||||
|
||||
static struct platform_driver mmc_omap_driver = {
|
||||
.probe = mmc_omap_probe,
|
||||
.remove_new = mmc_omap_remove,
|
||||
.remove = mmc_omap_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -2121,7 +2121,7 @@ static const struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
|
||||
|
||||
static struct platform_driver omap_hsmmc_driver = {
|
||||
.probe = omap_hsmmc_probe,
|
||||
.remove_new = omap_hsmmc_remove,
|
||||
.remove = omap_hsmmc_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -692,7 +692,7 @@ static struct platform_driver owl_mmc_driver = {
|
||||
.of_match_table = owl_mmc_of_match,
|
||||
},
|
||||
.probe = owl_mmc_probe,
|
||||
.remove_new = owl_mmc_remove,
|
||||
.remove = owl_mmc_remove,
|
||||
};
|
||||
module_platform_driver(owl_mmc_driver);
|
||||
|
||||
|
@ -810,7 +810,7 @@ static void pxamci_remove(struct platform_device *pdev)
|
||||
|
||||
static struct platform_driver pxamci_driver = {
|
||||
.probe = pxamci_probe,
|
||||
.remove_new = pxamci_remove,
|
||||
.remove = pxamci_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -613,7 +613,7 @@ static struct platform_driver renesas_internal_dmac_sdhi_driver = {
|
||||
.of_match_table = renesas_sdhi_internal_dmac_of_match,
|
||||
},
|
||||
.probe = renesas_sdhi_internal_dmac_probe,
|
||||
.remove_new = renesas_sdhi_remove,
|
||||
.remove = renesas_sdhi_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(renesas_internal_dmac_sdhi_driver);
|
||||
|
@ -471,7 +471,7 @@ static struct platform_driver renesas_sys_dmac_sdhi_driver = {
|
||||
.of_match_table = renesas_sdhi_sys_dmac_of_match,
|
||||
},
|
||||
.probe = renesas_sdhi_sys_dmac_probe,
|
||||
.remove_new = renesas_sdhi_remove,
|
||||
.remove = renesas_sdhi_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(renesas_sys_dmac_sdhi_driver);
|
||||
|
@ -1591,7 +1591,7 @@ MODULE_DEVICE_TABLE(platform, rtsx_pci_sdmmc_ids);
|
||||
|
||||
static struct platform_driver rtsx_pci_sdmmc_driver = {
|
||||
.probe = rtsx_pci_sdmmc_drv_probe,
|
||||
.remove_new = rtsx_pci_sdmmc_drv_remove,
|
||||
.remove = rtsx_pci_sdmmc_drv_remove,
|
||||
.id_table = rtsx_pci_sdmmc_ids,
|
||||
.driver = {
|
||||
.name = DRV_NAME_RTSX_PCI_SDMMC,
|
||||
|
@ -1453,7 +1453,7 @@ MODULE_DEVICE_TABLE(platform, rtsx_usb_sdmmc_ids);
|
||||
|
||||
static struct platform_driver rtsx_usb_sdmmc_driver = {
|
||||
.probe = rtsx_usb_sdmmc_drv_probe,
|
||||
.remove_new = rtsx_usb_sdmmc_drv_remove,
|
||||
.remove = rtsx_usb_sdmmc_drv_remove,
|
||||
.id_table = rtsx_usb_sdmmc_ids,
|
||||
.driver = {
|
||||
.name = "rtsx_usb_sdmmc",
|
||||
|
@ -1080,7 +1080,7 @@ static struct platform_driver sdhci_acpi_driver = {
|
||||
.pm = &sdhci_acpi_pm_ops,
|
||||
},
|
||||
.probe = sdhci_acpi_probe,
|
||||
.remove_new = sdhci_acpi_remove,
|
||||
.remove = sdhci_acpi_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(sdhci_acpi_driver);
|
||||
|
@ -328,7 +328,7 @@ static struct platform_driver sdhci_bcm_kona_driver = {
|
||||
.of_match_table = sdhci_bcm_kona_of_match,
|
||||
},
|
||||
.probe = sdhci_bcm_kona_probe,
|
||||
.remove_new = sdhci_bcm_kona_remove,
|
||||
.remove = sdhci_bcm_kona_remove,
|
||||
};
|
||||
module_platform_driver(sdhci_bcm_kona_driver);
|
||||
|
||||
|
@ -545,7 +545,7 @@ static struct platform_driver sdhci_brcmstb_driver = {
|
||||
.of_match_table = of_match_ptr(sdhci_brcm_of_match),
|
||||
},
|
||||
.probe = sdhci_brcmstb_probe,
|
||||
.remove_new = sdhci_pltfm_remove,
|
||||
.remove = sdhci_pltfm_remove,
|
||||
.shutdown = sdhci_brcmstb_shutdown,
|
||||
};
|
||||
|
||||
|
@ -608,7 +608,7 @@ static struct platform_driver sdhci_cdns_driver = {
|
||||
.of_match_table = sdhci_cdns_match,
|
||||
},
|
||||
.probe = sdhci_cdns_probe,
|
||||
.remove_new = sdhci_pltfm_remove,
|
||||
.remove = sdhci_pltfm_remove,
|
||||
};
|
||||
module_platform_driver(sdhci_cdns_driver);
|
||||
|
||||
|
@ -106,7 +106,7 @@ static struct platform_driver sdhci_dove_driver = {
|
||||
.of_match_table = sdhci_dove_of_match_table,
|
||||
},
|
||||
.probe = sdhci_dove_probe,
|
||||
.remove_new = sdhci_pltfm_remove,
|
||||
.remove = sdhci_pltfm_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(sdhci_dove_driver);
|
||||
|
@ -30,7 +30,8 @@
|
||||
#include "sdhci-esdhc.h"
|
||||
#include "cqhci.h"
|
||||
|
||||
#define ESDHC_SYS_CTRL_DTOCV_MASK 0x0f
|
||||
#define ESDHC_SYS_CTRL_DTOCV_MASK GENMASK(19, 16)
|
||||
#define ESDHC_SYS_CTRL_IPP_RST_N BIT(23)
|
||||
#define ESDHC_CTRL_D3CD 0x08
|
||||
#define ESDHC_BURST_LEN_EN_INCR (1 << 27)
|
||||
/* VENDOR SPEC register */
|
||||
@ -238,6 +239,7 @@ struct esdhc_platform_data {
|
||||
|
||||
struct esdhc_soc_data {
|
||||
u32 flags;
|
||||
u32 quirks;
|
||||
};
|
||||
|
||||
static const struct esdhc_soc_data esdhc_imx25_data = {
|
||||
@ -309,10 +311,12 @@ static struct esdhc_soc_data usdhc_imx7ulp_data = {
|
||||
| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
|
||||
| ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400
|
||||
| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
|
||||
.quirks = SDHCI_QUIRK_NO_LED,
|
||||
};
|
||||
static struct esdhc_soc_data usdhc_imxrt1050_data = {
|
||||
.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
|
||||
| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200,
|
||||
.quirks = SDHCI_QUIRK_NO_LED,
|
||||
};
|
||||
|
||||
static struct esdhc_soc_data usdhc_imx8qxp_data = {
|
||||
@ -321,6 +325,7 @@ static struct esdhc_soc_data usdhc_imx8qxp_data = {
|
||||
| ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES
|
||||
| ESDHC_FLAG_STATE_LOST_IN_LPMODE
|
||||
| ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME,
|
||||
.quirks = SDHCI_QUIRK_NO_LED,
|
||||
};
|
||||
|
||||
static struct esdhc_soc_data usdhc_imx8mm_data = {
|
||||
@ -328,6 +333,7 @@ static struct esdhc_soc_data usdhc_imx8mm_data = {
|
||||
| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
|
||||
| ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES
|
||||
| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
|
||||
.quirks = SDHCI_QUIRK_NO_LED,
|
||||
};
|
||||
|
||||
struct pltfm_imx_data {
|
||||
@ -1385,8 +1391,8 @@ static void esdhc_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
|
||||
|
||||
/* use maximum timeout counter */
|
||||
esdhc_clrset_le(host, ESDHC_SYS_CTRL_DTOCV_MASK,
|
||||
esdhc_is_usdhc(imx_data) ? 0xF : 0xE,
|
||||
SDHCI_TIMEOUT_CONTROL);
|
||||
esdhc_is_usdhc(imx_data) ? 0xF0000 : 0xE0000,
|
||||
ESDHC_SYSTEM_CONTROL);
|
||||
}
|
||||
|
||||
static u32 esdhc_cqhci_irq(struct sdhci_host *host, u32 intmask)
|
||||
@ -1402,6 +1408,17 @@ static u32 esdhc_cqhci_irq(struct sdhci_host *host, u32 intmask)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void esdhc_hw_reset(struct sdhci_host *host)
|
||||
{
|
||||
esdhc_clrset_le(host, ESDHC_SYS_CTRL_IPP_RST_N, 0, ESDHC_SYSTEM_CONTROL);
|
||||
/* eMMC spec requires minimum 1us, here delay between 1-10us */
|
||||
usleep_range(1, 10);
|
||||
esdhc_clrset_le(host, ESDHC_SYS_CTRL_IPP_RST_N,
|
||||
ESDHC_SYS_CTRL_IPP_RST_N, ESDHC_SYSTEM_CONTROL);
|
||||
/* eMMC spec requires minimum 200us, here delay between 200-300us */
|
||||
usleep_range(200, 300);
|
||||
}
|
||||
|
||||
static struct sdhci_ops sdhci_esdhc_ops = {
|
||||
.read_l = esdhc_readl_le,
|
||||
.read_w = esdhc_readw_le,
|
||||
@ -1420,6 +1437,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
|
||||
.reset = esdhc_reset,
|
||||
.irq = esdhc_cqhci_irq,
|
||||
.dump_vendor_regs = esdhc_dump_debug_regs,
|
||||
.hw_reset = esdhc_hw_reset,
|
||||
};
|
||||
|
||||
static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
|
||||
@ -1524,7 +1542,7 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
|
||||
writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL);
|
||||
} else if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
|
||||
/*
|
||||
* ESDHC_STD_TUNING_EN may be configed in bootloader
|
||||
* ESDHC_STD_TUNING_EN may be configured in bootloader
|
||||
* or ROM code, so clear this bit here to make sure
|
||||
* the manual tuning can work.
|
||||
*/
|
||||
@ -1626,7 +1644,7 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
|
||||
|
||||
/*
|
||||
* If we have this property, then activate WP check.
|
||||
* Retrieveing and requesting the actual WP GPIO will happen
|
||||
* Retrieving and requesting the actual WP GPIO will happen
|
||||
* in the call to mmc_of_parse().
|
||||
*/
|
||||
if (of_property_read_bool(np, "wp-gpios"))
|
||||
@ -1687,6 +1705,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
|
||||
|
||||
imx_data->socdata = device_get_match_data(&pdev->dev);
|
||||
|
||||
host->quirks |= imx_data->socdata->quirks;
|
||||
if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
|
||||
cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0);
|
||||
|
||||
@ -2015,7 +2034,7 @@ static struct platform_driver sdhci_esdhc_imx_driver = {
|
||||
.pm = &sdhci_esdhc_pmops,
|
||||
},
|
||||
.probe = sdhci_esdhc_imx_probe,
|
||||
.remove_new = sdhci_esdhc_imx_remove,
|
||||
.remove = sdhci_esdhc_imx_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(sdhci_esdhc_imx_driver);
|
||||
|
@ -512,7 +512,7 @@ static struct platform_driver sdhci_esdhc_mcf_driver = {
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
},
|
||||
.probe = sdhci_esdhc_mcf_probe,
|
||||
.remove_new = sdhci_esdhc_mcf_remove,
|
||||
.remove = sdhci_esdhc_mcf_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(sdhci_esdhc_mcf_driver);
|
||||
|
@ -424,7 +424,7 @@ static struct platform_driver sdhci_iproc_driver = {
|
||||
.pm = &sdhci_pltfm_pmops,
|
||||
},
|
||||
.probe = sdhci_iproc_probe,
|
||||
.remove_new = sdhci_pltfm_remove,
|
||||
.remove = sdhci_pltfm_remove,
|
||||
.shutdown = sdhci_iproc_shutdown,
|
||||
};
|
||||
module_platform_driver(sdhci_iproc_driver);
|
||||
|
@ -335,7 +335,7 @@ static struct platform_driver sdhci_milbeaut_driver = {
|
||||
.of_match_table = mlb_dt_ids,
|
||||
},
|
||||
.probe = sdhci_milbeaut_probe,
|
||||
.remove_new = sdhci_milbeaut_remove,
|
||||
.remove = sdhci_milbeaut_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(sdhci_milbeaut_driver);
|
||||
|
@ -2601,7 +2601,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
|
||||
sdhci_msm_handle_pwr_irq(host, 0);
|
||||
|
||||
/*
|
||||
* Ensure that above writes are propogated before interrupt enablement
|
||||
* Ensure that above writes are propagated before interrupt enablement
|
||||
* in GIC.
|
||||
*/
|
||||
mb();
|
||||
@ -2753,7 +2753,7 @@ static const struct dev_pm_ops sdhci_msm_pm_ops = {
|
||||
|
||||
static struct platform_driver sdhci_msm_driver = {
|
||||
.probe = sdhci_msm_probe,
|
||||
.remove_new = sdhci_msm_remove,
|
||||
.remove = sdhci_msm_remove,
|
||||
.driver = {
|
||||
.name = "sdhci_msm",
|
||||
.of_match_table = sdhci_msm_dt_match,
|
||||
|
@ -85,7 +85,7 @@ static struct platform_driver npcm_sdhci_driver = {
|
||||
.pm = &sdhci_pltfm_pmops,
|
||||
},
|
||||
.probe = npcm_sdhci_probe,
|
||||
.remove_new = sdhci_pltfm_remove,
|
||||
.remove = sdhci_pltfm_remove,
|
||||
};
|
||||
module_platform_driver(npcm_sdhci_driver);
|
||||
|
||||
|
@ -76,6 +76,8 @@
|
||||
#define FREQSEL_225M_200M 0x7
|
||||
#define PHY_DLL_TIMEOUT_MS 100
|
||||
|
||||
#define SDHCI_HW_RST_EN BIT(4)
|
||||
|
||||
/* Default settings for ZynqMP Clock Phases */
|
||||
#define ZYNQMP_ICLK_PHASE {0, 63, 63, 0, 63, 0, 0, 183, 54, 0, 0}
|
||||
#define ZYNQMP_OCLK_PHASE {0, 72, 60, 0, 60, 72, 135, 48, 72, 135, 0}
|
||||
@ -475,6 +477,21 @@ static void sdhci_arasan_reset(struct sdhci_host *host, u8 mask)
|
||||
}
|
||||
}
|
||||
|
||||
static void sdhci_arasan_hw_reset(struct sdhci_host *host)
|
||||
{
|
||||
u8 reg;
|
||||
|
||||
reg = sdhci_readb(host, SDHCI_POWER_CONTROL);
|
||||
reg |= SDHCI_HW_RST_EN;
|
||||
sdhci_writeb(host, reg, SDHCI_POWER_CONTROL);
|
||||
/* As per eMMC spec, minimum 1us is required but give it 2us for good measure */
|
||||
usleep_range(2, 5);
|
||||
reg &= ~SDHCI_HW_RST_EN;
|
||||
sdhci_writeb(host, reg, SDHCI_POWER_CONTROL);
|
||||
/* As per eMMC spec, minimum 200us is required but give it 300us for good measure */
|
||||
usleep_range(300, 500);
|
||||
}
|
||||
|
||||
static int sdhci_arasan_voltage_switch(struct mmc_host *mmc,
|
||||
struct mmc_ios *ios)
|
||||
{
|
||||
@ -505,6 +522,7 @@ static const struct sdhci_ops sdhci_arasan_ops = {
|
||||
.reset = sdhci_arasan_reset,
|
||||
.set_uhs_signaling = sdhci_set_uhs_signaling,
|
||||
.set_power = sdhci_set_power_and_bus_voltage,
|
||||
.hw_reset = sdhci_arasan_hw_reset,
|
||||
};
|
||||
|
||||
static u32 sdhci_arasan_cqhci_irq(struct sdhci_host *host, u32 intmask)
|
||||
@ -2046,7 +2064,7 @@ static struct platform_driver sdhci_arasan_driver = {
|
||||
.pm = &sdhci_arasan_dev_pm_ops,
|
||||
},
|
||||
.probe = sdhci_arasan_probe,
|
||||
.remove_new = sdhci_arasan_remove,
|
||||
.remove = sdhci_arasan_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(sdhci_arasan_driver);
|
||||
|
@ -519,7 +519,7 @@ static struct platform_driver aspeed_sdhci_driver = {
|
||||
.of_match_table = aspeed_sdhci_of_match,
|
||||
},
|
||||
.probe = aspeed_sdhci_probe,
|
||||
.remove_new = aspeed_sdhci_remove,
|
||||
.remove = aspeed_sdhci_remove,
|
||||
};
|
||||
|
||||
static int aspeed_sdc_probe(struct platform_device *pdev)
|
||||
@ -596,7 +596,7 @@ static struct platform_driver aspeed_sdc_driver = {
|
||||
.of_match_table = aspeed_sdc_of_match,
|
||||
},
|
||||
.probe = aspeed_sdc_probe,
|
||||
.remove_new = aspeed_sdc_remove,
|
||||
.remove = aspeed_sdc_remove,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_MMC_SDHCI_OF_ASPEED_TEST)
|
||||
|
@ -471,7 +471,7 @@ static struct platform_driver sdhci_at91_driver = {
|
||||
.pm = &sdhci_at91_dev_pm_ops,
|
||||
},
|
||||
.probe = sdhci_at91_probe,
|
||||
.remove_new = sdhci_at91_remove,
|
||||
.remove = sdhci_at91_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(sdhci_at91_driver);
|
||||
|
@ -1626,7 +1626,7 @@ static struct platform_driver sdhci_dwcmshc_driver = {
|
||||
.pm = &dwcmshc_pmops,
|
||||
},
|
||||
.probe = dwcmshc_probe,
|
||||
.remove_new = dwcmshc_remove,
|
||||
.remove = dwcmshc_remove,
|
||||
};
|
||||
module_platform_driver(sdhci_dwcmshc_driver);
|
||||
|
||||
|
@ -1521,7 +1521,7 @@ static struct platform_driver sdhci_esdhc_driver = {
|
||||
.pm = &esdhc_of_dev_pm_ops,
|
||||
},
|
||||
.probe = sdhci_esdhc_probe,
|
||||
.remove_new = sdhci_pltfm_remove,
|
||||
.remove = sdhci_pltfm_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(sdhci_esdhc_driver);
|
||||
|
@ -85,7 +85,7 @@ static struct platform_driver sdhci_hlwd_driver = {
|
||||
.pm = &sdhci_pltfm_pmops,
|
||||
},
|
||||
.probe = sdhci_hlwd_probe,
|
||||
.remove_new = sdhci_pltfm_remove,
|
||||
.remove = sdhci_pltfm_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(sdhci_hlwd_driver);
|
||||
|
@ -305,7 +305,7 @@ static struct platform_driver sdhci_ma35_driver = {
|
||||
.of_match_table = sdhci_ma35_dt_ids,
|
||||
},
|
||||
.probe = ma35_probe,
|
||||
.remove_new = ma35_remove,
|
||||
.remove = ma35_remove,
|
||||
};
|
||||
module_platform_driver(sdhci_ma35_driver);
|
||||
|
||||
|
@ -255,7 +255,7 @@ static struct platform_driver sdhci_sparx5_driver = {
|
||||
.pm = &sdhci_pltfm_pmops,
|
||||
},
|
||||
.probe = sdhci_sparx5_probe,
|
||||
.remove_new = sdhci_pltfm_remove,
|
||||
.remove = sdhci_pltfm_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(sdhci_sparx5_driver);
|
||||
|
@ -1478,7 +1478,7 @@ static const struct dev_pm_ops sdhci_omap_dev_pm_ops = {
|
||||
|
||||
static struct platform_driver sdhci_omap_driver = {
|
||||
.probe = sdhci_omap_probe,
|
||||
.remove_new = sdhci_omap_remove,
|
||||
.remove = sdhci_omap_remove,
|
||||
.driver = {
|
||||
.name = "sdhci-omap",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "sdhci.h"
|
||||
#include "sdhci-cqhci.h"
|
||||
#include "sdhci-pci.h"
|
||||
#include "sdhci-uhs2.h"
|
||||
|
||||
static void sdhci_pci_hw_reset(struct sdhci_host *host);
|
||||
|
||||
@ -2181,6 +2182,9 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot)
|
||||
if (scratch == (u32)-1)
|
||||
dead = 1;
|
||||
|
||||
if (slot->chip->fixes && slot->chip->fixes->remove_host)
|
||||
slot->chip->fixes->remove_host(slot, dead);
|
||||
else
|
||||
sdhci_remove_host(slot->host, dead);
|
||||
|
||||
if (slot->chip->fixes && slot->chip->fixes->remove_slot)
|
||||
@ -2189,6 +2193,16 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot)
|
||||
sdhci_free_host(slot->host);
|
||||
}
|
||||
|
||||
int sdhci_pci_uhs2_add_host(struct sdhci_pci_slot *slot)
|
||||
{
|
||||
return sdhci_uhs2_add_host(slot->host);
|
||||
}
|
||||
|
||||
void sdhci_pci_uhs2_remove_host(struct sdhci_pci_slot *slot, int dead)
|
||||
{
|
||||
sdhci_uhs2_remove_host(slot->host, dead);
|
||||
}
|
||||
|
||||
static void sdhci_pci_runtime_pm_allow(struct device *dev)
|
||||
{
|
||||
pm_suspend_ignore_children(dev, 1);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "sdhci-cqhci.h"
|
||||
#include "sdhci-pci.h"
|
||||
#include "cqhci.h"
|
||||
#include "sdhci-uhs2.h"
|
||||
|
||||
/* Genesys Logic extra registers */
|
||||
#define SDHCI_GLI_9750_WT 0x800
|
||||
@ -139,13 +140,49 @@
|
||||
|
||||
#define PCI_GLI_9755_PLLSSC 0x68
|
||||
#define PCI_GLI_9755_PLLSSC_PPM GENMASK(15, 0)
|
||||
#define PCI_GLI_9755_PLLSSC_RTL BIT(24)
|
||||
#define GLI_9755_PLLSSC_RTL_VALUE 0x1
|
||||
#define PCI_GLI_9755_PLLSSC_TRANS_PASS BIT(27)
|
||||
#define GLI_9755_PLLSSC_TRANS_PASS_VALUE 0x1
|
||||
#define PCI_GLI_9755_PLLSSC_RECV GENMASK(29, 28)
|
||||
#define GLI_9755_PLLSSC_RECV_VALUE 0x0
|
||||
#define PCI_GLI_9755_PLLSSC_TRAN GENMASK(31, 30)
|
||||
#define GLI_9755_PLLSSC_TRAN_VALUE 0x3
|
||||
|
||||
#define PCI_GLI_9755_UHS2_PLL 0x6C
|
||||
#define PCI_GLI_9755_UHS2_PLL_SSC GENMASK(9, 8)
|
||||
#define GLI_9755_UHS2_PLL_SSC_VALUE 0x0
|
||||
#define PCI_GLI_9755_UHS2_PLL_DELAY BIT(18)
|
||||
#define GLI_9755_UHS2_PLL_DELAY_VALUE 0x1
|
||||
#define PCI_GLI_9755_UHS2_PLL_PDRST BIT(27)
|
||||
#define GLI_9755_UHS2_PLL_PDRST_VALUE 0x1
|
||||
|
||||
#define PCI_GLI_9755_SerDes 0x70
|
||||
#define PCI_GLI_9755_UHS2_SERDES_INTR GENMASK(2, 0)
|
||||
#define GLI_9755_UHS2_SERDES_INTR_VALUE 0x3
|
||||
#define PCI_GLI_9755_UHS2_SERDES_ZC1 BIT(3)
|
||||
#define GLI_9755_UHS2_SERDES_ZC1_VALUE 0x0
|
||||
#define PCI_GLI_9755_UHS2_SERDES_ZC2 GENMASK(7, 4)
|
||||
#define GLI_9755_UHS2_SERDES_ZC2_DEFAULT 0xB
|
||||
#define GLI_9755_UHS2_SERDES_ZC2_SANDISK 0x0
|
||||
#define PCI_GLI_9755_SCP_DIS BIT(19)
|
||||
#define PCI_GLI_9755_UHS2_SERDES_TRAN GENMASK(27, 24)
|
||||
#define GLI_9755_UHS2_SERDES_TRAN_VALUE 0xC
|
||||
#define PCI_GLI_9755_UHS2_SERDES_RECV GENMASK(31, 28)
|
||||
#define GLI_9755_UHS2_SERDES_RECV_VALUE 0xF
|
||||
|
||||
#define PCI_GLI_9755_MISC 0x78
|
||||
#define PCI_GLI_9755_MISC_SSC_OFF BIT(26)
|
||||
|
||||
#define SDHCI_GLI_9767_SD_HOST_OPERATION_CTL 0x508
|
||||
#define SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_CMD_CONFLICT_CHECK BIT(0)
|
||||
#define SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE GENMASK(21, 16)
|
||||
#define SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_PLUG_IN_VALUE 0x05
|
||||
#define SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_PLUG_OUT_VALUE 0x3F
|
||||
#define SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_SCALE GENMASK(23, 22)
|
||||
#define SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_SCALE_1MS 0x2
|
||||
#define SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_SCALE_10MS 0x3
|
||||
|
||||
#define SDHCI_GLI_9767_GM_BURST_SIZE 0x510
|
||||
#define SDHCI_GLI_9767_GM_BURST_SIZE_AXI_ALWAYS_SET BIT(8)
|
||||
|
||||
@ -182,6 +219,13 @@
|
||||
#define PCIE_GLI_9767_SCR_CORE_PWR_D3_OFF BIT(21)
|
||||
#define PCIE_GLI_9767_SCR_CFG_RST_DATA_LINK_DOWN BIT(30)
|
||||
|
||||
#define PCIE_GLI_9767_RESET_REG 0x8E4
|
||||
#define PCIE_GLI_9767_RESET_REG_SD_HOST_SW_RESET BIT(0)
|
||||
|
||||
#define PCIE_GLI_9767_UHS2_PHY_SET_REG1 0x90C
|
||||
#define PCIE_GLI_9767_UHS2_PHY_SET_REG1_SERDES_INTR GENMASK(31, 29)
|
||||
#define PCIE_GLI_9767_UHS2_PHY_SET_REG1_SERDES_INTR_VALUE 0x3
|
||||
|
||||
#define PCIE_GLI_9767_SDHC_CAP 0x91C
|
||||
#define PCIE_GLI_9767_SDHC_CAP_SDEI_RESULT BIT(5)
|
||||
|
||||
@ -200,9 +244,15 @@
|
||||
#define PCIE_GLI_9767_SD_EXPRESS_CTL_SD_EXPRESS_MODE BIT(1)
|
||||
|
||||
#define PCIE_GLI_9767_SD_DATA_MULTI_CTL 0x944
|
||||
#define PCIE_GLI_9767_SD_DATA_MULTI_CTL_SELECT_UHS2 BIT(5)
|
||||
#define PCIE_GLI_9767_SD_DATA_MULTI_CTL_UHS2_SWITCH_CTL BIT(8)
|
||||
#define PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME GENMASK(23, 16)
|
||||
#define PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME_VALUE 0x64
|
||||
|
||||
#define PCIE_GLI_9767_UHS2_PHY_SET_REG2 0x948
|
||||
#define PCIE_GLI_9767_UHS2_PHY_SET_REG2_SSC_PPM_SETTING GENMASK(22, 21)
|
||||
#define PCIE_GLI_9767_UHS2_PHY_SET_REG2_SSC_PPM_SETTING_VALUE 0x0
|
||||
|
||||
#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2 0x950
|
||||
#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2_SDEI_COMPLETE BIT(0)
|
||||
|
||||
@ -212,6 +262,28 @@
|
||||
#define PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2 0x958
|
||||
#define PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2_SDEI_COMPLETE_SIGNAL_EN BIT(0)
|
||||
|
||||
#define PCIE_GLI_9767_UHS2_CTL1 0x95C
|
||||
#define PCIE_GLI_9767_UHS2_CTL1_TRANS_PASS BIT(5)
|
||||
#define PCIE_GLI_9767_UHS2_CTL1_TRANS_PASS_VALUE 0x1
|
||||
#define PCIE_GLI_9767_UHS2_CTL1_DECODING_CTL BIT(6)
|
||||
#define PCIE_GLI_9767_UHS2_CTL1_DECODING_CTL_VALUE 0x1
|
||||
#define PCIE_GLI_9767_UHS2_CTL1_SERDES_TRAN GENMASK(10, 7)
|
||||
#define PCIE_GLI_9767_UHS2_CTL1_SERDES_TRAN_VALUE 0x3
|
||||
#define PCIE_GLI_9767_UHS2_CTL1_SERDES_RECV GENMASK(14, 11)
|
||||
#define PCIE_GLI_9767_UHS2_CTL1_SERDES_RECV_VALUE 0xf
|
||||
#define PCIE_GLI_9767_UHS2_CTL1_DIR_TRANS GENMASK(16, 15)
|
||||
#define PCIE_GLI_9767_UHS2_CTL1_DIR_TRANS_VALUE 0x0
|
||||
#define PCIE_GLI_9767_UHS2_CTL1_DIR_RECV GENMASK(18, 17)
|
||||
#define PCIE_GLI_9767_UHS2_CTL1_DIR_RECV_VALUE 0x0
|
||||
#define PCIE_GLI_9767_UHS2_CTL1_PDRST BIT(25)
|
||||
#define PCIE_GLI_9767_UHS2_CTL1_PDRST_VALUE 0x1
|
||||
|
||||
#define PCIE_GLI_9767_UHS2_CTL2 0x964
|
||||
#define PCIE_GLI_9767_UHS2_CTL2_ZC GENMASK(3, 0)
|
||||
#define PCIE_GLI_9767_UHS2_CTL2_ZC_VALUE 0xb
|
||||
#define PCIE_GLI_9767_UHS2_CTL2_ZC_CTL BIT(6)
|
||||
#define PCIE_GLI_9767_UHS2_CTL2_ZC_CTL_VALUE 0x1
|
||||
|
||||
#define GLI_MAX_TUNING_LOOP 40
|
||||
|
||||
/* Genesys Logic chipset */
|
||||
@ -779,6 +851,203 @@ static void gl9755_hw_setting(struct sdhci_pci_slot *slot)
|
||||
gl9755_wt_off(pdev);
|
||||
}
|
||||
|
||||
static void gl9755_vendor_init(struct sdhci_host *host)
|
||||
{
|
||||
struct sdhci_pci_slot *slot = sdhci_priv(host);
|
||||
struct pci_dev *pdev = slot->chip->pdev;
|
||||
u32 serdes;
|
||||
u32 pllssc;
|
||||
u32 uhs2_pll;
|
||||
|
||||
gl9755_wt_on(pdev);
|
||||
|
||||
pci_read_config_dword(pdev, PCI_GLI_9755_SerDes, &serdes);
|
||||
serdes &= ~PCI_GLI_9755_UHS2_SERDES_TRAN;
|
||||
serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_TRAN,
|
||||
GLI_9755_UHS2_SERDES_TRAN_VALUE);
|
||||
serdes &= ~PCI_GLI_9755_UHS2_SERDES_RECV;
|
||||
serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_RECV,
|
||||
GLI_9755_UHS2_SERDES_RECV_VALUE);
|
||||
serdes &= ~PCI_GLI_9755_UHS2_SERDES_INTR;
|
||||
serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_INTR,
|
||||
GLI_9755_UHS2_SERDES_INTR_VALUE);
|
||||
serdes &= ~PCI_GLI_9755_UHS2_SERDES_ZC1;
|
||||
serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_ZC1,
|
||||
GLI_9755_UHS2_SERDES_ZC1_VALUE);
|
||||
serdes &= ~PCI_GLI_9755_UHS2_SERDES_ZC2;
|
||||
serdes |= FIELD_PREP(PCI_GLI_9755_UHS2_SERDES_ZC2,
|
||||
GLI_9755_UHS2_SERDES_ZC2_DEFAULT);
|
||||
pci_write_config_dword(pdev, PCI_GLI_9755_SerDes, serdes);
|
||||
|
||||
pci_read_config_dword(pdev, PCI_GLI_9755_UHS2_PLL, &uhs2_pll);
|
||||
uhs2_pll &= ~PCI_GLI_9755_UHS2_PLL_SSC;
|
||||
uhs2_pll |= FIELD_PREP(PCI_GLI_9755_UHS2_PLL_SSC,
|
||||
GLI_9755_UHS2_PLL_SSC_VALUE);
|
||||
uhs2_pll &= ~PCI_GLI_9755_UHS2_PLL_DELAY;
|
||||
uhs2_pll |= FIELD_PREP(PCI_GLI_9755_UHS2_PLL_DELAY,
|
||||
GLI_9755_UHS2_PLL_DELAY_VALUE);
|
||||
uhs2_pll &= ~PCI_GLI_9755_UHS2_PLL_PDRST;
|
||||
uhs2_pll |= FIELD_PREP(PCI_GLI_9755_UHS2_PLL_PDRST,
|
||||
GLI_9755_UHS2_PLL_PDRST_VALUE);
|
||||
pci_write_config_dword(pdev, PCI_GLI_9755_UHS2_PLL, uhs2_pll);
|
||||
|
||||
pci_read_config_dword(pdev, PCI_GLI_9755_PLLSSC, &pllssc);
|
||||
pllssc &= ~PCI_GLI_9755_PLLSSC_RTL;
|
||||
pllssc |= FIELD_PREP(PCI_GLI_9755_PLLSSC_RTL,
|
||||
GLI_9755_PLLSSC_RTL_VALUE);
|
||||
pllssc &= ~PCI_GLI_9755_PLLSSC_TRANS_PASS;
|
||||
pllssc |= FIELD_PREP(PCI_GLI_9755_PLLSSC_TRANS_PASS,
|
||||
GLI_9755_PLLSSC_TRANS_PASS_VALUE);
|
||||
pllssc &= ~PCI_GLI_9755_PLLSSC_RECV;
|
||||
pllssc |= FIELD_PREP(PCI_GLI_9755_PLLSSC_RECV,
|
||||
GLI_9755_PLLSSC_RECV_VALUE);
|
||||
pllssc &= ~PCI_GLI_9755_PLLSSC_TRAN;
|
||||
pllssc |= FIELD_PREP(PCI_GLI_9755_PLLSSC_TRAN,
|
||||
GLI_9755_PLLSSC_TRAN_VALUE);
|
||||
pci_write_config_dword(pdev, PCI_GLI_9755_PLLSSC, pllssc);
|
||||
|
||||
gl9755_wt_off(pdev);
|
||||
}
|
||||
|
||||
static void sdhci_gli_pre_detect_init(struct sdhci_host *host)
|
||||
{
|
||||
/* Need more time on UHS2 detect flow */
|
||||
sdhci_writeb(host, 0xA7, SDHCI_UHS2_TIMER_CTRL);
|
||||
}
|
||||
|
||||
static void sdhci_gli_overcurrent_event_enable(struct sdhci_host *host, bool enable)
|
||||
{
|
||||
u32 mask;
|
||||
|
||||
mask = sdhci_readl(host, SDHCI_SIGNAL_ENABLE);
|
||||
if (enable)
|
||||
mask |= SDHCI_INT_BUS_POWER;
|
||||
else
|
||||
mask &= ~SDHCI_INT_BUS_POWER;
|
||||
|
||||
sdhci_writel(host, mask, SDHCI_SIGNAL_ENABLE);
|
||||
|
||||
mask = sdhci_readl(host, SDHCI_INT_ENABLE);
|
||||
if (enable)
|
||||
mask |= SDHCI_INT_BUS_POWER;
|
||||
else
|
||||
mask &= ~SDHCI_INT_BUS_POWER;
|
||||
|
||||
sdhci_writel(host, mask, SDHCI_INT_ENABLE);
|
||||
}
|
||||
|
||||
static void gl9755_set_power(struct sdhci_host *host, unsigned char mode,
|
||||
unsigned short vdd)
|
||||
{
|
||||
u8 pwr = 0;
|
||||
|
||||
if (mode != MMC_POWER_OFF) {
|
||||
pwr = sdhci_get_vdd_value(vdd);
|
||||
if (!pwr)
|
||||
WARN(1, "%s: Invalid vdd %#x\n", mmc_hostname(host->mmc), vdd);
|
||||
pwr |= SDHCI_VDD2_POWER_180;
|
||||
}
|
||||
|
||||
if (host->pwr == pwr)
|
||||
return;
|
||||
|
||||
host->pwr = pwr;
|
||||
|
||||
if (pwr == 0) {
|
||||
sdhci_gli_overcurrent_event_enable(host, false);
|
||||
sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
|
||||
} else {
|
||||
sdhci_gli_overcurrent_event_enable(host, false);
|
||||
sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
|
||||
|
||||
pwr |= (SDHCI_POWER_ON | SDHCI_VDD2_POWER_ON);
|
||||
|
||||
sdhci_writeb(host, pwr & 0xf, SDHCI_POWER_CONTROL);
|
||||
/* wait stable */
|
||||
mdelay(5);
|
||||
sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
|
||||
/* wait stable */
|
||||
mdelay(5);
|
||||
sdhci_gli_overcurrent_event_enable(host, true);
|
||||
}
|
||||
}
|
||||
|
||||
static bool sdhci_wait_clock_stable(struct sdhci_host *host)
|
||||
{
|
||||
u16 clk = 0;
|
||||
|
||||
if (read_poll_timeout_atomic(sdhci_readw, clk, (clk & SDHCI_CLOCK_INT_STABLE),
|
||||
10, 20000, false, host, SDHCI_CLOCK_CONTROL)) {
|
||||
pr_err("%s: Internal clock never stabilised.\n", mmc_hostname(host->mmc));
|
||||
sdhci_dumpregs(host);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void sdhci_gli_enable_internal_clock(struct sdhci_host *host)
|
||||
{
|
||||
u16 ctrl2;
|
||||
|
||||
ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
|
||||
|
||||
sdhci_writew(host, SDHCI_CLOCK_INT_EN, SDHCI_CLOCK_CONTROL);
|
||||
|
||||
if (!((ctrl2 & SDHCI_CTRL_V4_MODE) &&
|
||||
(ctrl2 & SDHCI_CTRL_UHS2_ENABLE))) {
|
||||
sdhci_wait_clock_stable(host);
|
||||
sdhci_writew(host, SDHCI_CTRL_V4_MODE, SDHCI_HOST_CONTROL2);
|
||||
}
|
||||
}
|
||||
|
||||
static int sdhci_gli_wait_software_reset_done(struct sdhci_host *host, u8 mask)
|
||||
{
|
||||
u8 rst;
|
||||
|
||||
/* hw clears the bit when it's done */
|
||||
if (read_poll_timeout_atomic(sdhci_readb, rst, !(rst & mask),
|
||||
10, 100000, false, host, SDHCI_SOFTWARE_RESET)) {
|
||||
pr_err("%s: Reset 0x%x never completed.\n", mmc_hostname(host->mmc), (int)mask);
|
||||
sdhci_dumpregs(host);
|
||||
/* manual clear */
|
||||
sdhci_writeb(host, 0, SDHCI_SOFTWARE_RESET);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sdhci_gli_uhs2_reset_sd_tran(struct sdhci_host *host)
|
||||
{
|
||||
/* do this on UHS2 mode */
|
||||
if (host->mmc->uhs2_sd_tran) {
|
||||
sdhci_uhs2_reset(host, SDHCI_UHS2_SW_RESET_SD);
|
||||
sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
|
||||
sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
|
||||
sdhci_uhs2_clear_set_irqs(host,
|
||||
SDHCI_INT_ALL_MASK,
|
||||
SDHCI_UHS2_INT_ERROR_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
static void sdhci_gl9755_reset(struct sdhci_host *host, u8 mask)
|
||||
{
|
||||
/* need internal clock */
|
||||
if (mask & SDHCI_RESET_ALL)
|
||||
sdhci_gli_enable_internal_clock(host);
|
||||
|
||||
sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
|
||||
|
||||
/* reset sd-tran on UHS2 mode if need to reset cmd/data */
|
||||
if ((mask & SDHCI_RESET_CMD) | (mask & SDHCI_RESET_DATA))
|
||||
sdhci_gli_uhs2_reset_sd_tran(host);
|
||||
|
||||
if (mask & SDHCI_RESET_ALL)
|
||||
host->clock = 0;
|
||||
|
||||
sdhci_gli_wait_software_reset_done(host, mask);
|
||||
}
|
||||
|
||||
static inline void gl9767_vhs_read(struct pci_dev *pdev)
|
||||
{
|
||||
u32 vhs_enable;
|
||||
@ -937,6 +1206,31 @@ static void sdhci_gl9767_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
gl9767_set_low_power_negotiation(pdev, true);
|
||||
}
|
||||
|
||||
static void sdhci_gl9767_set_card_detect_debounce_time(struct sdhci_host *host)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = sdhci_readl(host, SDHCI_GLI_9767_SD_HOST_OPERATION_CTL);
|
||||
value &= ~(SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE |
|
||||
SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_SCALE);
|
||||
if (sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)
|
||||
value |= FIELD_PREP(SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE,
|
||||
SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_PLUG_IN_VALUE) |
|
||||
FIELD_PREP(SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_SCALE,
|
||||
SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_SCALE_1MS);
|
||||
else
|
||||
value |= FIELD_PREP(SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE,
|
||||
SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_PLUG_OUT_VALUE) |
|
||||
FIELD_PREP(SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_SCALE,
|
||||
SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_DEBOUNCE_SCALE_10MS);
|
||||
sdhci_writel(host, value, SDHCI_GLI_9767_SD_HOST_OPERATION_CTL);
|
||||
}
|
||||
|
||||
static void sdhci_gl9767_card_event(struct sdhci_host *host)
|
||||
{
|
||||
sdhci_gl9767_set_card_detect_debounce_time(host);
|
||||
}
|
||||
|
||||
static void gli_set_9767(struct sdhci_host *host)
|
||||
{
|
||||
u32 value;
|
||||
@ -944,6 +1238,12 @@ static void gli_set_9767(struct sdhci_host *host)
|
||||
value = sdhci_readl(host, SDHCI_GLI_9767_GM_BURST_SIZE);
|
||||
value &= ~SDHCI_GLI_9767_GM_BURST_SIZE_AXI_ALWAYS_SET;
|
||||
sdhci_writel(host, value, SDHCI_GLI_9767_GM_BURST_SIZE);
|
||||
|
||||
value = sdhci_readl(host, SDHCI_GLI_9767_SD_HOST_OPERATION_CTL);
|
||||
value &= ~SDHCI_GLI_9767_SD_HOST_OPERATION_CTL_CMD_CONFLICT_CHECK;
|
||||
sdhci_writel(host, value, SDHCI_GLI_9767_SD_HOST_OPERATION_CTL);
|
||||
|
||||
sdhci_gl9767_set_card_detect_debounce_time(host);
|
||||
}
|
||||
|
||||
static void gl9767_hw_setting(struct sdhci_pci_slot *slot)
|
||||
@ -982,7 +1282,43 @@ static void gl9767_hw_setting(struct sdhci_pci_slot *slot)
|
||||
|
||||
static void sdhci_gl9767_reset(struct sdhci_host *host, u8 mask)
|
||||
{
|
||||
struct sdhci_pci_slot *slot = sdhci_priv(host);
|
||||
struct pci_dev *pdev = slot->chip->pdev;
|
||||
u32 value;
|
||||
|
||||
/* need internal clock */
|
||||
if (mask & SDHCI_RESET_ALL) {
|
||||
sdhci_gli_enable_internal_clock(host);
|
||||
|
||||
gl9767_vhs_write(pdev);
|
||||
|
||||
pci_read_config_dword(pdev, PCIE_GLI_9767_RESET_REG, &value);
|
||||
value &= ~PCIE_GLI_9767_RESET_REG_SD_HOST_SW_RESET;
|
||||
pci_write_config_dword(pdev, PCIE_GLI_9767_RESET_REG, value);
|
||||
|
||||
if (read_poll_timeout_atomic(pci_read_config_dword, value,
|
||||
!(value & PCIE_GLI_9767_RESET_REG_SD_HOST_SW_RESET),
|
||||
1, 5, true, pdev, PCIE_GLI_9767_RESET_REG, &value)) {
|
||||
pr_warn("%s: %s: Reset SDHC AHB and TL-AMBA failure.\n",
|
||||
__func__, mmc_hostname(host->mmc));
|
||||
gl9767_vhs_read(pdev);
|
||||
return;
|
||||
}
|
||||
gl9767_vhs_read(pdev);
|
||||
}
|
||||
|
||||
if (mmc_card_uhs2(host->mmc)) {
|
||||
if (mask & (SDHCI_RESET_CMD | SDHCI_RESET_DATA)) {
|
||||
sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
|
||||
sdhci_gli_uhs2_reset_sd_tran(host);
|
||||
sdhci_gli_wait_software_reset_done(host, mask);
|
||||
} else {
|
||||
sdhci_uhs2_reset(host, mask);
|
||||
}
|
||||
} else {
|
||||
sdhci_reset(host, mask);
|
||||
}
|
||||
|
||||
gli_set_9767(host);
|
||||
}
|
||||
|
||||
@ -1076,6 +1412,86 @@ static int gl9767_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gl9767_vendor_init(struct sdhci_host *host)
|
||||
{
|
||||
struct sdhci_pci_slot *slot = sdhci_priv(host);
|
||||
struct pci_dev *pdev = slot->chip->pdev;
|
||||
u32 value;
|
||||
|
||||
gl9767_vhs_write(pdev);
|
||||
|
||||
pci_read_config_dword(pdev, PCIE_GLI_9767_UHS2_PHY_SET_REG1, &value);
|
||||
value |= FIELD_PREP(PCIE_GLI_9767_UHS2_PHY_SET_REG1_SERDES_INTR,
|
||||
PCIE_GLI_9767_UHS2_PHY_SET_REG1_SERDES_INTR_VALUE);
|
||||
pci_write_config_dword(pdev, PCIE_GLI_9767_UHS2_PHY_SET_REG1, value);
|
||||
|
||||
pci_read_config_dword(pdev, PCIE_GLI_9767_UHS2_PHY_SET_REG2, &value);
|
||||
value |= FIELD_PREP(PCIE_GLI_9767_UHS2_PHY_SET_REG2_SSC_PPM_SETTING,
|
||||
PCIE_GLI_9767_UHS2_PHY_SET_REG2_SSC_PPM_SETTING_VALUE);
|
||||
pci_write_config_dword(pdev, PCIE_GLI_9767_UHS2_PHY_SET_REG2, value);
|
||||
|
||||
pci_read_config_dword(pdev, PCIE_GLI_9767_UHS2_CTL1, &value);
|
||||
value |= FIELD_PREP(PCIE_GLI_9767_UHS2_CTL1_TRANS_PASS,
|
||||
PCIE_GLI_9767_UHS2_CTL1_TRANS_PASS_VALUE) |
|
||||
FIELD_PREP(PCIE_GLI_9767_UHS2_CTL1_DECODING_CTL,
|
||||
PCIE_GLI_9767_UHS2_CTL1_DECODING_CTL_VALUE) |
|
||||
FIELD_PREP(PCIE_GLI_9767_UHS2_CTL1_SERDES_TRAN,
|
||||
PCIE_GLI_9767_UHS2_CTL1_SERDES_TRAN_VALUE) |
|
||||
FIELD_PREP(PCIE_GLI_9767_UHS2_CTL1_SERDES_RECV,
|
||||
PCIE_GLI_9767_UHS2_CTL1_SERDES_RECV_VALUE) |
|
||||
FIELD_PREP(PCIE_GLI_9767_UHS2_CTL1_DIR_TRANS,
|
||||
PCIE_GLI_9767_UHS2_CTL1_DIR_TRANS_VALUE) |
|
||||
FIELD_PREP(PCIE_GLI_9767_UHS2_CTL1_DIR_RECV,
|
||||
PCIE_GLI_9767_UHS2_CTL1_DIR_RECV_VALUE) |
|
||||
FIELD_PREP(PCIE_GLI_9767_UHS2_CTL1_PDRST,
|
||||
PCIE_GLI_9767_UHS2_CTL1_PDRST_VALUE);
|
||||
pci_write_config_dword(pdev, PCIE_GLI_9767_UHS2_CTL1, value);
|
||||
|
||||
pci_read_config_dword(pdev, PCIE_GLI_9767_UHS2_CTL2, &value);
|
||||
value |= FIELD_PREP(PCIE_GLI_9767_UHS2_CTL2_ZC,
|
||||
PCIE_GLI_9767_UHS2_CTL2_ZC_VALUE) |
|
||||
FIELD_PREP(PCIE_GLI_9767_UHS2_CTL2_ZC_CTL,
|
||||
PCIE_GLI_9767_UHS2_CTL2_ZC_CTL_VALUE);
|
||||
pci_write_config_dword(pdev, PCIE_GLI_9767_UHS2_CTL2, value);
|
||||
|
||||
gl9767_vhs_read(pdev);
|
||||
}
|
||||
|
||||
static void sdhci_gl9767_set_power(struct sdhci_host *host, unsigned char mode, unsigned short vdd)
|
||||
{
|
||||
struct sdhci_pci_slot *slot = sdhci_priv(host);
|
||||
struct pci_dev *pdev = slot->chip->pdev;
|
||||
u32 value;
|
||||
|
||||
if (mmc_card_uhs2(host->mmc)) {
|
||||
gl9767_vhs_write(pdev);
|
||||
|
||||
pci_read_config_dword(pdev, PCIE_GLI_9767_SD_DATA_MULTI_CTL, &value);
|
||||
value |= PCIE_GLI_9767_SD_DATA_MULTI_CTL_SELECT_UHS2 |
|
||||
PCIE_GLI_9767_SD_DATA_MULTI_CTL_UHS2_SWITCH_CTL;
|
||||
pci_write_config_dword(pdev, PCIE_GLI_9767_SD_DATA_MULTI_CTL, value);
|
||||
|
||||
gl9767_vhs_read(pdev);
|
||||
|
||||
sdhci_gli_overcurrent_event_enable(host, false);
|
||||
sdhci_uhs2_set_power(host, mode, vdd);
|
||||
sdhci_gli_overcurrent_event_enable(host, true);
|
||||
} else {
|
||||
gl9767_vhs_write(pdev);
|
||||
|
||||
pci_read_config_dword(pdev, PCIE_GLI_9767_SD_DATA_MULTI_CTL, &value);
|
||||
value &= ~(PCIE_GLI_9767_SD_DATA_MULTI_CTL_SELECT_UHS2 |
|
||||
PCIE_GLI_9767_SD_DATA_MULTI_CTL_UHS2_SWITCH_CTL);
|
||||
pci_write_config_dword(pdev, PCIE_GLI_9767_SD_DATA_MULTI_CTL, value);
|
||||
|
||||
gl9767_vhs_read(pdev);
|
||||
|
||||
sdhci_gli_overcurrent_event_enable(host, false);
|
||||
sdhci_set_power(host, mode, vdd);
|
||||
sdhci_gli_overcurrent_event_enable(host, true);
|
||||
}
|
||||
}
|
||||
|
||||
static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot)
|
||||
{
|
||||
struct sdhci_host *host = slot->host;
|
||||
@ -1096,6 +1512,7 @@ static int gli_probe_slot_gl9755(struct sdhci_pci_slot *slot)
|
||||
gli_pcie_enable_msi(slot);
|
||||
slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
|
||||
sdhci_enable_v4_mode(host);
|
||||
gl9755_vendor_init(host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1111,6 +1528,7 @@ static int gli_probe_slot_gl9767(struct sdhci_pci_slot *slot)
|
||||
host->mmc->caps2 |= MMC_CAP2_SD_EXP;
|
||||
host->mmc_host_ops.init_sd_express = gl9767_init_sd_express;
|
||||
sdhci_enable_v4_mode(host);
|
||||
gl9767_vendor_init(host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1534,17 +1952,24 @@ static const struct sdhci_ops sdhci_gl9755_ops = {
|
||||
.read_w = sdhci_gli_readw,
|
||||
.read_b = sdhci_gli_readb,
|
||||
.set_clock = sdhci_gl9755_set_clock,
|
||||
.set_power = gl9755_set_power,
|
||||
.enable_dma = sdhci_pci_enable_dma,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
.reset = sdhci_reset,
|
||||
.reset = sdhci_gl9755_reset,
|
||||
.set_uhs_signaling = sdhci_set_uhs_signaling,
|
||||
.voltage_switch = sdhci_gli_voltage_switch,
|
||||
.dump_uhs2_regs = sdhci_uhs2_dump_regs,
|
||||
.set_timeout = sdhci_uhs2_set_timeout,
|
||||
.irq = sdhci_uhs2_irq,
|
||||
.uhs2_pre_detect_init = sdhci_gli_pre_detect_init,
|
||||
};
|
||||
|
||||
const struct sdhci_pci_fixes sdhci_gl9755 = {
|
||||
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
|
||||
.quirks2 = SDHCI_QUIRK2_BROKEN_DDR50,
|
||||
.probe_slot = gli_probe_slot_gl9755,
|
||||
.add_host = sdhci_pci_uhs2_add_host,
|
||||
.remove_host = sdhci_pci_uhs2_remove_host,
|
||||
.ops = &sdhci_gl9755_ops,
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.resume = sdhci_pci_gli_resume,
|
||||
@ -1607,12 +2032,20 @@ static const struct sdhci_ops sdhci_gl9767_ops = {
|
||||
.reset = sdhci_gl9767_reset,
|
||||
.set_uhs_signaling = sdhci_set_uhs_signaling,
|
||||
.voltage_switch = sdhci_gl9767_voltage_switch,
|
||||
.dump_uhs2_regs = sdhci_uhs2_dump_regs,
|
||||
.set_timeout = sdhci_uhs2_set_timeout,
|
||||
.irq = sdhci_uhs2_irq,
|
||||
.set_power = sdhci_gl9767_set_power,
|
||||
.uhs2_pre_detect_init = sdhci_gli_pre_detect_init,
|
||||
.card_event = sdhci_gl9767_card_event,
|
||||
};
|
||||
|
||||
const struct sdhci_pci_fixes sdhci_gl9767 = {
|
||||
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
|
||||
.quirks2 = SDHCI_QUIRK2_BROKEN_DDR50,
|
||||
.probe_slot = gli_probe_slot_gl9767,
|
||||
.add_host = sdhci_pci_uhs2_add_host,
|
||||
.remove_host = sdhci_pci_uhs2_remove_host,
|
||||
.ops = &sdhci_gl9767_ops,
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.resume = sdhci_pci_gli_resume,
|
||||
|
@ -145,6 +145,7 @@ struct sdhci_pci_fixes {
|
||||
int (*probe_slot) (struct sdhci_pci_slot *);
|
||||
int (*add_host) (struct sdhci_pci_slot *);
|
||||
void (*remove_slot) (struct sdhci_pci_slot *, int);
|
||||
void (*remove_host) (struct sdhci_pci_slot *, int);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
int (*suspend) (struct sdhci_pci_chip *);
|
||||
@ -189,6 +190,8 @@ static inline void *sdhci_pci_priv(struct sdhci_pci_slot *slot)
|
||||
return (void *)slot->private;
|
||||
}
|
||||
|
||||
int sdhci_pci_uhs2_add_host(struct sdhci_pci_slot *slot);
|
||||
void sdhci_pci_uhs2_remove_host(struct sdhci_pci_slot *slot, int dead);
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
int sdhci_pci_resume_host(struct sdhci_pci_chip *chip);
|
||||
#endif
|
||||
|
@ -236,7 +236,7 @@ static struct platform_driver pic32_sdhci_driver = {
|
||||
.of_match_table = of_match_ptr(pic32_sdhci_id_table),
|
||||
},
|
||||
.probe = pic32_sdhci_probe,
|
||||
.remove_new = pic32_sdhci_remove,
|
||||
.remove = pic32_sdhci_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(pic32_sdhci_driver);
|
||||
|
@ -351,7 +351,7 @@ static struct platform_driver sdhci_pxav2_driver = {
|
||||
.pm = &sdhci_pltfm_pmops,
|
||||
},
|
||||
.probe = sdhci_pxav2_probe,
|
||||
.remove_new = sdhci_pltfm_remove,
|
||||
.remove = sdhci_pltfm_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(sdhci_pxav2_driver);
|
||||
|
@ -568,7 +568,7 @@ static struct platform_driver sdhci_pxav3_driver = {
|
||||
.pm = &sdhci_pxav3_pmops,
|
||||
},
|
||||
.probe = sdhci_pxav3_probe,
|
||||
.remove_new = sdhci_pxav3_remove,
|
||||
.remove = sdhci_pxav3_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(sdhci_pxav3_driver);
|
||||
|
@ -774,7 +774,7 @@ MODULE_DEVICE_TABLE(of, sdhci_s3c_dt_match);
|
||||
|
||||
static struct platform_driver sdhci_s3c_driver = {
|
||||
.probe = sdhci_s3c_probe,
|
||||
.remove_new = sdhci_s3c_remove,
|
||||
.remove = sdhci_s3c_remove,
|
||||
.id_table = sdhci_s3c_driver_ids,
|
||||
.driver = {
|
||||
.name = "s3c-sdhci",
|
||||
|
@ -182,7 +182,7 @@ static struct platform_driver sdhci_driver = {
|
||||
.of_match_table = sdhci_spear_id_table,
|
||||
},
|
||||
.probe = sdhci_probe,
|
||||
.remove_new = sdhci_remove,
|
||||
.remove = sdhci_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(sdhci_driver);
|
||||
|
@ -975,7 +975,7 @@ static const struct dev_pm_ops sdhci_sprd_pm_ops = {
|
||||
|
||||
static struct platform_driver sdhci_sprd_driver = {
|
||||
.probe = sdhci_sprd_probe,
|
||||
.remove_new = sdhci_sprd_remove,
|
||||
.remove = sdhci_sprd_remove,
|
||||
.driver = {
|
||||
.name = "sdhci_sprd_r11",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -507,7 +507,7 @@ MODULE_DEVICE_TABLE(of, st_sdhci_match);
|
||||
|
||||
static struct platform_driver sdhci_st_driver = {
|
||||
.probe = sdhci_st_probe,
|
||||
.remove_new = sdhci_st_remove,
|
||||
.remove = sdhci_st_remove,
|
||||
.driver = {
|
||||
.name = "sdhci-st",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
@ -1930,7 +1930,7 @@ static struct platform_driver sdhci_tegra_driver = {
|
||||
.pm = &sdhci_tegra_dev_pm_ops,
|
||||
},
|
||||
.probe = sdhci_tegra_probe,
|
||||
.remove_new = sdhci_tegra_remove,
|
||||
.remove = sdhci_tegra_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(sdhci_tegra_driver);
|
||||
|
1250
drivers/mmc/host/sdhci-uhs2.c
Normal file
1250
drivers/mmc/host/sdhci-uhs2.c
Normal file
File diff suppressed because it is too large
Load Diff
188
drivers/mmc/host/sdhci-uhs2.h
Normal file
188
drivers/mmc/host/sdhci-uhs2.h
Normal file
@ -0,0 +1,188 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Header file for Host Controller UHS2 related registers.
|
||||
*
|
||||
* Copyright (C) 2014 Intel Corp, All Rights Reserved.
|
||||
*/
|
||||
#ifndef __SDHCI_UHS2_H
|
||||
#define __SDHCI_UHS2_H
|
||||
|
||||
#include <linux/bits.h>
|
||||
|
||||
/* SDHCI Category C registers : UHS2 usage */
|
||||
|
||||
#define SDHCI_UHS2_CM_TRAN_RESP 0x10
|
||||
#define SDHCI_UHS2_SD_TRAN_RESP 0x18
|
||||
#define SDHCI_UHS2_SD_TRAN_RESP_1 0x1C
|
||||
|
||||
/* SDHCI Category B registers : UHS2 only */
|
||||
|
||||
#define SDHCI_UHS2_BLOCK_SIZE 0x80
|
||||
#define SDHCI_UHS2_MAKE_BLKSZ(dma, blksz) ((((dma) & 0x7) << 12) | ((blksz) & 0xFFF))
|
||||
|
||||
#define SDHCI_UHS2_BLOCK_COUNT 0x84
|
||||
|
||||
#define SDHCI_UHS2_CMD_PACKET 0x88
|
||||
#define SDHCI_UHS2_CMD_PACK_MAX_LEN 20
|
||||
|
||||
#define SDHCI_UHS2_TRANS_MODE 0x9C
|
||||
#define SDHCI_UHS2_TRNS_DMA BIT(0)
|
||||
#define SDHCI_UHS2_TRNS_BLK_CNT_EN BIT(1)
|
||||
#define SDHCI_UHS2_TRNS_DATA_TRNS_WRT BIT(4)
|
||||
#define SDHCI_UHS2_TRNS_BLK_BYTE_MODE BIT(5)
|
||||
#define SDHCI_UHS2_TRNS_RES_R5 BIT(6)
|
||||
#define SDHCI_UHS2_TRNS_RES_ERR_CHECK_EN BIT(7)
|
||||
#define SDHCI_UHS2_TRNS_RES_INT_DIS BIT(8)
|
||||
#define SDHCI_UHS2_TRNS_WAIT_EBSY BIT(14)
|
||||
#define SDHCI_UHS2_TRNS_2L_HD BIT(15)
|
||||
|
||||
#define SDHCI_UHS2_CMD 0x9E
|
||||
#define SDHCI_UHS2_CMD_SUB_CMD BIT(2)
|
||||
#define SDHCI_UHS2_CMD_DATA BIT(5)
|
||||
#define SDHCI_UHS2_CMD_TRNS_ABORT BIT(6)
|
||||
#define SDHCI_UHS2_CMD_CMD12 BIT(7)
|
||||
#define SDHCI_UHS2_CMD_DORMANT GENMASK(7, 6)
|
||||
#define SDHCI_UHS2_CMD_PACK_LEN_MASK GENMASK(12, 8)
|
||||
|
||||
#define SDHCI_UHS2_RESPONSE 0xA0
|
||||
#define SDHCI_UHS2_RESPONSE_MAX_LEN 20
|
||||
|
||||
#define SDHCI_UHS2_MSG_SELECT 0xB4
|
||||
#define SDHCI_UHS2_MSG_SELECT_CURR 0x0
|
||||
#define SDHCI_UHS2_MSG_SELECT_ONE 0x1
|
||||
#define SDHCI_UHS2_MSG_SELECT_TWO 0x2
|
||||
#define SDHCI_UHS2_MSG_SELECT_THREE 0x3
|
||||
|
||||
#define SDHCI_UHS2_MSG 0xB8
|
||||
|
||||
#define SDHCI_UHS2_DEV_INT_STATUS 0xBC
|
||||
|
||||
#define SDHCI_UHS2_DEV_SELECT 0xBE
|
||||
#define SDHCI_UHS2_DEV_SEL_MASK GENMASK(3, 0)
|
||||
#define SDHCI_UHS2_DEV_SEL_INT_MSG_EN BIT(7)
|
||||
|
||||
#define SDHCI_UHS2_DEV_INT_CODE 0xBF
|
||||
|
||||
#define SDHCI_UHS2_SW_RESET 0xC0
|
||||
#define SDHCI_UHS2_SW_RESET_FULL BIT(0)
|
||||
#define SDHCI_UHS2_SW_RESET_SD BIT(1)
|
||||
|
||||
#define SDHCI_UHS2_TIMER_CTRL 0xC2
|
||||
#define SDHCI_UHS2_TIMER_CTRL_DEADLOCK_MASK GENMASK(7, 4)
|
||||
|
||||
#define SDHCI_UHS2_INT_STATUS 0xC4
|
||||
#define SDHCI_UHS2_INT_STATUS_ENABLE 0xC8
|
||||
#define SDHCI_UHS2_INT_SIGNAL_ENABLE 0xCC
|
||||
#define SDHCI_UHS2_INT_HEADER_ERR BIT(0)
|
||||
#define SDHCI_UHS2_INT_RES_ERR BIT(1)
|
||||
#define SDHCI_UHS2_INT_RETRY_EXP BIT(2)
|
||||
#define SDHCI_UHS2_INT_CRC BIT(3)
|
||||
#define SDHCI_UHS2_INT_FRAME_ERR BIT(4)
|
||||
#define SDHCI_UHS2_INT_TID_ERR BIT(5)
|
||||
#define SDHCI_UHS2_INT_UNRECOVER BIT(7)
|
||||
#define SDHCI_UHS2_INT_EBUSY_ERR BIT(8)
|
||||
#define SDHCI_UHS2_INT_ADMA_ERROR BIT(15)
|
||||
#define SDHCI_UHS2_INT_CMD_TIMEOUT BIT(16)
|
||||
#define SDHCI_UHS2_INT_DEADLOCK_TIMEOUT BIT(17)
|
||||
#define SDHCI_UHS2_INT_VENDOR_ERR BIT(27)
|
||||
#define SDHCI_UHS2_INT_ERROR_MASK ( \
|
||||
SDHCI_UHS2_INT_HEADER_ERR | \
|
||||
SDHCI_UHS2_INT_RES_ERR | \
|
||||
SDHCI_UHS2_INT_RETRY_EXP | \
|
||||
SDHCI_UHS2_INT_CRC | \
|
||||
SDHCI_UHS2_INT_FRAME_ERR | \
|
||||
SDHCI_UHS2_INT_TID_ERR | \
|
||||
SDHCI_UHS2_INT_UNRECOVER | \
|
||||
SDHCI_UHS2_INT_EBUSY_ERR | \
|
||||
SDHCI_UHS2_INT_ADMA_ERROR | \
|
||||
SDHCI_UHS2_INT_CMD_TIMEOUT | \
|
||||
SDHCI_UHS2_INT_DEADLOCK_TIMEOUT)
|
||||
#define SDHCI_UHS2_INT_CMD_ERR_MASK ( \
|
||||
SDHCI_UHS2_INT_HEADER_ERR | \
|
||||
SDHCI_UHS2_INT_RES_ERR | \
|
||||
SDHCI_UHS2_INT_FRAME_ERR | \
|
||||
SDHCI_UHS2_INT_TID_ERR | \
|
||||
SDHCI_UHS2_INT_CMD_TIMEOUT)
|
||||
/* CRC Error occurs during a packet receiving */
|
||||
#define SDHCI_UHS2_INT_DATA_ERR_MASK ( \
|
||||
SDHCI_UHS2_INT_RETRY_EXP | \
|
||||
SDHCI_UHS2_INT_CRC | \
|
||||
SDHCI_UHS2_INT_UNRECOVER | \
|
||||
SDHCI_UHS2_INT_EBUSY_ERR | \
|
||||
SDHCI_UHS2_INT_ADMA_ERROR | \
|
||||
SDHCI_UHS2_INT_DEADLOCK_TIMEOUT)
|
||||
|
||||
#define SDHCI_UHS2_SETTINGS_PTR 0xE0
|
||||
#define SDHCI_UHS2_GEN_SETTINGS_POWER_LOW BIT(0)
|
||||
#define SDHCI_UHS2_GEN_SETTINGS_N_LANES_MASK GENMASK(11, 8)
|
||||
#define SDHCI_UHS2_FD_OR_2L_HD 0x0 /* 2 lanes */
|
||||
#define SDHCI_UHS2_2D1U_FD 0x2 /* 3 lanes, 2 down, 1 up, full duplex */
|
||||
#define SDHCI_UHS2_1D2U_FD 0x3 /* 3 lanes, 1 down, 2 up, full duplex */
|
||||
#define SDHCI_UHS2_2D2U_FD 0x4 /* 4 lanes, 2 down, 2 up, full duplex */
|
||||
|
||||
#define SDHCI_UHS2_PHY_SET_SPEED_B BIT(6)
|
||||
#define SDHCI_UHS2_PHY_HIBERNATE_EN BIT(12)
|
||||
#define SDHCI_UHS2_PHY_N_LSS_SYN_MASK GENMASK(19, 16)
|
||||
#define SDHCI_UHS2_PHY_N_LSS_DIR_MASK GENMASK(23, 20)
|
||||
|
||||
#define SDHCI_UHS2_TRAN_N_FCU_MASK GENMASK(15, 8)
|
||||
#define SDHCI_UHS2_TRAN_RETRY_CNT_MASK GENMASK(17, 16)
|
||||
#define SDHCI_UHS2_TRAN_1_N_DAT_GAP_MASK GENMASK(7, 0)
|
||||
|
||||
#define SDHCI_UHS2_CAPS_PTR 0xE2
|
||||
#define SDHCI_UHS2_CAPS_OFFSET 0
|
||||
#define SDHCI_UHS2_CAPS_DAP_MASK GENMASK(3, 0)
|
||||
#define SDHCI_UHS2_CAPS_GAP_MASK GENMASK(7, 4)
|
||||
#define SDHCI_UHS2_CAPS_GAP(gap) ((gap) * 360)
|
||||
#define SDHCI_UHS2_CAPS_LANE_MASK GENMASK(13, 8)
|
||||
#define SDHCI_UHS2_CAPS_2L_HD_FD 1
|
||||
#define SDHCI_UHS2_CAPS_2D1U_FD 2
|
||||
#define SDHCI_UHS2_CAPS_1D2U_FD 4
|
||||
#define SDHCI_UHS2_CAPS_2D2U_FD 8
|
||||
#define SDHCI_UHS2_CAPS_ADDR_64 BIT(14)
|
||||
#define SDHCI_UHS2_CAPS_BOOT BIT(15)
|
||||
#define SDHCI_UHS2_CAPS_DEV_TYPE_MASK GENMASK(17, 16)
|
||||
#define SDHCI_UHS2_CAPS_DEV_TYPE_RMV 0
|
||||
#define SDHCI_UHS2_CAPS_DEV_TYPE_EMB 1
|
||||
#define SDHCI_UHS2_CAPS_DEV_TYPE_EMB_RMV 2
|
||||
#define SDHCI_UHS2_CAPS_NUM_DEV_MASK GENMASK(21, 18)
|
||||
#define SDHCI_UHS2_CAPS_BUS_TOPO_MASK GENMASK(23, 22)
|
||||
#define SDHCI_UHS2_CAPS_BUS_TOPO_SHIFT 22
|
||||
#define SDHCI_UHS2_CAPS_BUS_TOPO_P2P 0
|
||||
#define SDHCI_UHS2_CAPS_BUS_TOPO_RING 1
|
||||
#define SDHCI_UHS2_CAPS_BUS_TOPO_HUB 2
|
||||
#define SDHCI_UHS2_CAPS_BUS_TOPO_HUB_RING 3
|
||||
|
||||
#define SDHCI_UHS2_CAPS_PHY_OFFSET 4
|
||||
#define SDHCI_UHS2_CAPS_PHY_REV_MASK GENMASK(5, 0)
|
||||
#define SDHCI_UHS2_CAPS_PHY_RANGE_MASK GENMASK(7, 6)
|
||||
#define SDHCI_UHS2_CAPS_PHY_RANGE_A 0
|
||||
#define SDHCI_UHS2_CAPS_PHY_RANGE_B 1
|
||||
#define SDHCI_UHS2_CAPS_PHY_N_LSS_SYN_MASK GENMASK(19, 16)
|
||||
#define SDHCI_UHS2_CAPS_PHY_N_LSS_DIR_MASK GENMASK(23, 20)
|
||||
#define SDHCI_UHS2_CAPS_TRAN_OFFSET 8
|
||||
#define SDHCI_UHS2_CAPS_TRAN_LINK_REV_MASK GENMASK(5, 0)
|
||||
#define SDHCI_UHS2_CAPS_TRAN_N_FCU_MASK GENMASK(15, 8)
|
||||
#define SDHCI_UHS2_CAPS_TRAN_HOST_TYPE_MASK GENMASK(18, 16)
|
||||
#define SDHCI_UHS2_CAPS_TRAN_BLK_LEN_MASK GENMASK(31, 20)
|
||||
|
||||
#define SDHCI_UHS2_CAPS_TRAN_1_OFFSET 12
|
||||
#define SDHCI_UHS2_CAPS_TRAN_1_N_DATA_GAP_MASK GENMASK(7, 0)
|
||||
|
||||
#define SDHCI_UHS2_EMBED_CTRL_PTR 0xE6
|
||||
#define SDHCI_UHS2_VENDOR_PTR 0xE8
|
||||
|
||||
struct sdhci_host;
|
||||
struct mmc_command;
|
||||
struct mmc_request;
|
||||
|
||||
void sdhci_uhs2_dump_regs(struct sdhci_host *host);
|
||||
void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask);
|
||||
void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode, unsigned short vdd);
|
||||
void sdhci_uhs2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd);
|
||||
int sdhci_uhs2_add_host(struct sdhci_host *host);
|
||||
void sdhci_uhs2_remove_host(struct sdhci_host *host, int dead);
|
||||
void sdhci_uhs2_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set);
|
||||
u32 sdhci_uhs2_irq(struct sdhci_host *host, u32 intmask);
|
||||
|
||||
#endif /* __SDHCI_UHS2_H */
|
@ -734,7 +734,7 @@ static struct platform_driver sdhci_xenon_driver = {
|
||||
.pm = &sdhci_xenon_dev_pm_ops,
|
||||
},
|
||||
.probe = xenon_probe,
|
||||
.remove_new = xenon_remove,
|
||||
.remove = xenon_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(sdhci_xenon_driver);
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/leds.h>
|
||||
|
||||
#include <linux/mmc/mmc.h>
|
||||
@ -47,8 +47,6 @@
|
||||
static unsigned int debug_quirks = 0;
|
||||
static unsigned int debug_quirks2;
|
||||
|
||||
static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
|
||||
|
||||
static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd);
|
||||
|
||||
void sdhci_dumpregs(struct sdhci_host *host)
|
||||
@ -110,6 +108,9 @@ void sdhci_dumpregs(struct sdhci_host *host)
|
||||
}
|
||||
}
|
||||
|
||||
if (host->ops->dump_uhs2_regs)
|
||||
host->ops->dump_uhs2_regs(host);
|
||||
|
||||
if (host->ops->dump_vendor_regs)
|
||||
host->ops->dump_vendor_regs(host);
|
||||
|
||||
@ -146,10 +147,11 @@ void sdhci_enable_v4_mode(struct sdhci_host *host)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_enable_v4_mode);
|
||||
|
||||
static inline bool sdhci_data_line_cmd(struct mmc_command *cmd)
|
||||
bool sdhci_data_line_cmd(struct mmc_command *cmd)
|
||||
{
|
||||
return cmd->data || cmd->flags & MMC_RSP_BUSY;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_data_line_cmd);
|
||||
|
||||
static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
|
||||
{
|
||||
@ -233,7 +235,7 @@ void sdhci_reset(struct sdhci_host *host, u8 mask)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_reset);
|
||||
|
||||
static bool sdhci_do_reset(struct sdhci_host *host, u8 mask)
|
||||
bool sdhci_do_reset(struct sdhci_host *host, u8 mask)
|
||||
{
|
||||
if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
@ -246,6 +248,7 @@ static bool sdhci_do_reset(struct sdhci_host *host, u8 mask)
|
||||
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_do_reset);
|
||||
|
||||
static void sdhci_reset_for_all(struct sdhci_host *host)
|
||||
{
|
||||
@ -501,7 +504,7 @@ static inline void sdhci_led_deactivate(struct sdhci_host *host)
|
||||
|
||||
#endif
|
||||
|
||||
static void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq,
|
||||
void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq,
|
||||
unsigned long timeout)
|
||||
{
|
||||
if (sdhci_data_line_cmd(mrq->cmd))
|
||||
@ -509,6 +512,7 @@ static void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq,
|
||||
else
|
||||
mod_timer(&host->timer, timeout);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_mod_timer);
|
||||
|
||||
static void sdhci_del_timer(struct sdhci_host *host, struct mmc_request *mrq)
|
||||
{
|
||||
@ -1075,8 +1079,7 @@ static void sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd)
|
||||
__sdhci_set_timeout(host, cmd);
|
||||
}
|
||||
|
||||
static void sdhci_initialize_data(struct sdhci_host *host,
|
||||
struct mmc_data *data)
|
||||
void sdhci_initialize_data(struct sdhci_host *host, struct mmc_data *data)
|
||||
{
|
||||
WARN_ON(host->data);
|
||||
|
||||
@ -1089,6 +1092,7 @@ static void sdhci_initialize_data(struct sdhci_host *host,
|
||||
host->data_early = 0;
|
||||
host->data->bytes_xfered = 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_initialize_data);
|
||||
|
||||
static inline void sdhci_set_block_info(struct sdhci_host *host,
|
||||
struct mmc_data *data)
|
||||
@ -1111,12 +1115,8 @@ static inline void sdhci_set_block_info(struct sdhci_host *host,
|
||||
}
|
||||
}
|
||||
|
||||
static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
|
||||
void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data)
|
||||
{
|
||||
struct mmc_data *data = cmd->data;
|
||||
|
||||
sdhci_initialize_data(host, data);
|
||||
|
||||
if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
|
||||
struct scatterlist *sg;
|
||||
unsigned int length_mask, offset_mask;
|
||||
@ -1201,6 +1201,16 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
|
||||
}
|
||||
|
||||
sdhci_set_transfer_irqs(host);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_prepare_dma);
|
||||
|
||||
static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
|
||||
{
|
||||
struct mmc_data *data = cmd->data;
|
||||
|
||||
sdhci_initialize_data(host, data);
|
||||
|
||||
sdhci_prepare_dma(host, data);
|
||||
|
||||
sdhci_set_block_info(host, data);
|
||||
}
|
||||
@ -1488,7 +1498,7 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
|
||||
sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
|
||||
}
|
||||
|
||||
static bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq)
|
||||
bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq)
|
||||
{
|
||||
return (!(host->flags & SDHCI_DEVICE_DEAD) &&
|
||||
((mrq->cmd && mrq->cmd->error) ||
|
||||
@ -1496,6 +1506,7 @@ static bool sdhci_needs_reset(struct sdhci_host *host, struct mmc_request *mrq)
|
||||
(mrq->data && mrq->data->stop && mrq->data->stop->error) ||
|
||||
(host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_needs_reset);
|
||||
|
||||
static void sdhci_set_mrq_done(struct sdhci_host *host, struct mmc_request *mrq)
|
||||
{
|
||||
@ -1518,7 +1529,7 @@ static void sdhci_set_mrq_done(struct sdhci_host *host, struct mmc_request *mrq)
|
||||
WARN_ON(i >= SDHCI_MAX_MRQS);
|
||||
}
|
||||
|
||||
static void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
|
||||
void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
|
||||
{
|
||||
if (host->cmd && host->cmd->mrq == mrq)
|
||||
host->cmd = NULL;
|
||||
@ -1542,15 +1553,17 @@ static void __sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
|
||||
if (!sdhci_has_requests(host))
|
||||
sdhci_led_deactivate(host);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__sdhci_finish_mrq);
|
||||
|
||||
static void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
|
||||
void sdhci_finish_mrq(struct sdhci_host *host, struct mmc_request *mrq)
|
||||
{
|
||||
__sdhci_finish_mrq(host, mrq);
|
||||
|
||||
queue_work(host->complete_wq, &host->complete_work);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_finish_mrq);
|
||||
|
||||
static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout)
|
||||
void __sdhci_finish_data_common(struct sdhci_host *host, bool defer_reset)
|
||||
{
|
||||
struct mmc_command *data_cmd = host->data_cmd;
|
||||
struct mmc_data *data = host->data;
|
||||
@ -1563,7 +1576,9 @@ static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout)
|
||||
* conditions.
|
||||
*/
|
||||
if (data->error) {
|
||||
if (!host->cmd || host->cmd == data_cmd)
|
||||
if (defer_reset)
|
||||
host->pending_reset = true;
|
||||
else if (!host->cmd || host->cmd == data_cmd)
|
||||
sdhci_reset_for(host, REQUEST_ERROR);
|
||||
else
|
||||
sdhci_reset_for(host, REQUEST_ERROR_DATA_ONLY);
|
||||
@ -1584,6 +1599,14 @@ static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout)
|
||||
data->bytes_xfered = 0;
|
||||
else
|
||||
data->bytes_xfered = data->blksz * data->blocks;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__sdhci_finish_data_common);
|
||||
|
||||
static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout)
|
||||
{
|
||||
struct mmc_data *data = host->data;
|
||||
|
||||
__sdhci_finish_data_common(host, false);
|
||||
|
||||
/*
|
||||
* Need to send CMD12 if -
|
||||
@ -1718,7 +1741,7 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool sdhci_present_error(struct sdhci_host *host,
|
||||
bool sdhci_present_error(struct sdhci_host *host,
|
||||
struct mmc_command *cmd, bool present)
|
||||
{
|
||||
if (!present || host->flags & SDHCI_DEVICE_DEAD) {
|
||||
@ -1728,6 +1751,7 @@ static bool sdhci_present_error(struct sdhci_host *host,
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_present_error);
|
||||
|
||||
static bool sdhci_send_command_retry(struct sdhci_host *host,
|
||||
struct mmc_command *cmd,
|
||||
@ -1874,6 +1898,12 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)
|
||||
case MMC_TIMING_MMC_HS400:
|
||||
preset = sdhci_readw(host, SDHCI_PRESET_FOR_HS400);
|
||||
break;
|
||||
case MMC_TIMING_UHS2_SPEED_A:
|
||||
case MMC_TIMING_UHS2_SPEED_A_HD:
|
||||
case MMC_TIMING_UHS2_SPEED_B:
|
||||
case MMC_TIMING_UHS2_SPEED_B_HD:
|
||||
preset = sdhci_readw(host, SDHCI_PRESET_FOR_UHS2);
|
||||
break;
|
||||
default:
|
||||
pr_warn("%s: Invalid UHS-I mode selected\n",
|
||||
mmc_hostname(host->mmc));
|
||||
@ -2058,12 +2088,8 @@ static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode,
|
||||
sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
|
||||
}
|
||||
|
||||
void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
|
||||
unsigned short vdd)
|
||||
unsigned short sdhci_get_vdd_value(unsigned short vdd)
|
||||
{
|
||||
u8 pwr = 0;
|
||||
|
||||
if (mode != MMC_POWER_OFF) {
|
||||
switch (1 << vdd) {
|
||||
case MMC_VDD_165_195:
|
||||
/*
|
||||
@ -2073,26 +2099,35 @@ void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
|
||||
* for the purpose of turning on the power.
|
||||
*/
|
||||
case MMC_VDD_20_21:
|
||||
pwr = SDHCI_POWER_180;
|
||||
break;
|
||||
return SDHCI_POWER_180;
|
||||
case MMC_VDD_29_30:
|
||||
case MMC_VDD_30_31:
|
||||
pwr = SDHCI_POWER_300;
|
||||
break;
|
||||
return SDHCI_POWER_300;
|
||||
case MMC_VDD_32_33:
|
||||
case MMC_VDD_33_34:
|
||||
/*
|
||||
* 3.4 ~ 3.6V are valid only for those platforms where it's
|
||||
* 3.4V ~ 3.6V are valid only for those platforms where it's
|
||||
* known that the voltage range is supported by hardware.
|
||||
*/
|
||||
case MMC_VDD_34_35:
|
||||
case MMC_VDD_35_36:
|
||||
pwr = SDHCI_POWER_330;
|
||||
break;
|
||||
return SDHCI_POWER_330;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_get_vdd_value);
|
||||
|
||||
void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
|
||||
unsigned short vdd)
|
||||
{
|
||||
u8 pwr = 0;
|
||||
|
||||
if (mode != MMC_POWER_OFF) {
|
||||
pwr = sdhci_get_vdd_value(vdd);
|
||||
if (!pwr) {
|
||||
WARN(1, "%s: Invalid vdd %#x\n",
|
||||
mmc_hostname(host->mmc), vdd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2315,24 +2350,9 @@ static bool sdhci_presetable_values_change(struct sdhci_host *host, struct mmc_i
|
||||
(sdhci_preset_needed(host, ios->timing) || host->drv_type != ios->drv_type);
|
||||
}
|
||||
|
||||
void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
void sdhci_set_ios_common(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
{
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
bool reinit_uhs = host->reinit_uhs;
|
||||
bool turning_on_clk = false;
|
||||
u8 ctrl;
|
||||
|
||||
host->reinit_uhs = false;
|
||||
|
||||
if (ios->power_mode == MMC_POWER_UNDEFINED)
|
||||
return;
|
||||
|
||||
if (host->flags & SDHCI_DEVICE_DEAD) {
|
||||
if (!IS_ERR(mmc->supply.vmmc) &&
|
||||
ios->power_mode == MMC_POWER_OFF)
|
||||
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the chip on each power off.
|
||||
@ -2349,8 +2369,6 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
sdhci_enable_preset_value(host, false);
|
||||
|
||||
if (!ios->clock || ios->clock != host->clock) {
|
||||
turning_on_clk = ios->clock && !host->clock;
|
||||
|
||||
host->ops->set_clock(host, ios->clock);
|
||||
host->clock = ios->clock;
|
||||
|
||||
@ -2366,6 +2384,31 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
mmc->max_busy_timeout /= host->timeout_clk;
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_set_ios_common);
|
||||
|
||||
void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
{
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
bool reinit_uhs = host->reinit_uhs;
|
||||
bool turning_on_clk;
|
||||
u8 ctrl;
|
||||
|
||||
host->reinit_uhs = false;
|
||||
|
||||
if (ios->power_mode == MMC_POWER_UNDEFINED)
|
||||
return;
|
||||
|
||||
if (host->flags & SDHCI_DEVICE_DEAD) {
|
||||
if (!IS_ERR(mmc->supply.vmmc) &&
|
||||
ios->power_mode == MMC_POWER_OFF)
|
||||
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
turning_on_clk = ios->clock != host->clock && ios->clock && !host->clock;
|
||||
|
||||
sdhci_set_ios_common(mmc, ios);
|
||||
|
||||
if (host->ops->set_power)
|
||||
host->ops->set_power(host, ios->power_mode, ios->vdd);
|
||||
@ -2934,7 +2977,7 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_execute_tuning);
|
||||
|
||||
static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
|
||||
void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
|
||||
{
|
||||
/* Host Controller v3.00 defines preset value registers */
|
||||
if (host->version < SDHCI_SPEC_300)
|
||||
@ -2962,6 +3005,7 @@ static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
|
||||
host->preset_enabled = enable;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_enable_preset_value);
|
||||
|
||||
static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
|
||||
int err)
|
||||
@ -3055,6 +3099,53 @@ static const struct mmc_host_ops sdhci_ops = {
|
||||
* *
|
||||
\*****************************************************************************/
|
||||
|
||||
void sdhci_request_done_dma(struct sdhci_host *host, struct mmc_request *mrq)
|
||||
{
|
||||
struct mmc_data *data = mrq->data;
|
||||
|
||||
if (data && data->host_cookie == COOKIE_MAPPED) {
|
||||
if (host->bounce_buffer) {
|
||||
/*
|
||||
* On reads, copy the bounced data into the
|
||||
* sglist
|
||||
*/
|
||||
if (mmc_get_dma_dir(data) == DMA_FROM_DEVICE) {
|
||||
unsigned int length = data->bytes_xfered;
|
||||
|
||||
if (length > host->bounce_buffer_size) {
|
||||
pr_err("%s: bounce buffer is %u bytes but DMA claims to have transferred %u bytes\n",
|
||||
mmc_hostname(host->mmc),
|
||||
host->bounce_buffer_size,
|
||||
data->bytes_xfered);
|
||||
/* Cap it down and continue */
|
||||
length = host->bounce_buffer_size;
|
||||
}
|
||||
dma_sync_single_for_cpu(mmc_dev(host->mmc),
|
||||
host->bounce_addr,
|
||||
host->bounce_buffer_size,
|
||||
DMA_FROM_DEVICE);
|
||||
sg_copy_from_buffer(data->sg,
|
||||
data->sg_len,
|
||||
host->bounce_buffer,
|
||||
length);
|
||||
} else {
|
||||
/* No copying, just switch ownership */
|
||||
dma_sync_single_for_cpu(mmc_dev(host->mmc),
|
||||
host->bounce_addr,
|
||||
host->bounce_buffer_size,
|
||||
mmc_get_dma_dir(data));
|
||||
}
|
||||
} else {
|
||||
/* Unmap the raw data */
|
||||
dma_unmap_sg(mmc_dev(host->mmc), data->sg,
|
||||
data->sg_len,
|
||||
mmc_get_dma_dir(data));
|
||||
}
|
||||
data->host_cookie = COOKIE_UNMAPPED;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_request_done_dma);
|
||||
|
||||
static bool sdhci_request_done(struct sdhci_host *host)
|
||||
{
|
||||
unsigned long flags;
|
||||
@ -3119,48 +3210,7 @@ static bool sdhci_request_done(struct sdhci_host *host)
|
||||
sdhci_set_mrq_done(host, mrq);
|
||||
}
|
||||
|
||||
if (data && data->host_cookie == COOKIE_MAPPED) {
|
||||
if (host->bounce_buffer) {
|
||||
/*
|
||||
* On reads, copy the bounced data into the
|
||||
* sglist
|
||||
*/
|
||||
if (mmc_get_dma_dir(data) == DMA_FROM_DEVICE) {
|
||||
unsigned int length = data->bytes_xfered;
|
||||
|
||||
if (length > host->bounce_buffer_size) {
|
||||
pr_err("%s: bounce buffer is %u bytes but DMA claims to have transferred %u bytes\n",
|
||||
mmc_hostname(host->mmc),
|
||||
host->bounce_buffer_size,
|
||||
data->bytes_xfered);
|
||||
/* Cap it down and continue */
|
||||
length = host->bounce_buffer_size;
|
||||
}
|
||||
dma_sync_single_for_cpu(
|
||||
mmc_dev(host->mmc),
|
||||
host->bounce_addr,
|
||||
host->bounce_buffer_size,
|
||||
DMA_FROM_DEVICE);
|
||||
sg_copy_from_buffer(data->sg,
|
||||
data->sg_len,
|
||||
host->bounce_buffer,
|
||||
length);
|
||||
} else {
|
||||
/* No copying, just switch ownership */
|
||||
dma_sync_single_for_cpu(
|
||||
mmc_dev(host->mmc),
|
||||
host->bounce_addr,
|
||||
host->bounce_buffer_size,
|
||||
mmc_get_dma_dir(data));
|
||||
}
|
||||
} else {
|
||||
/* Unmap the raw data */
|
||||
dma_unmap_sg(mmc_dev(host->mmc), data->sg,
|
||||
data->sg_len,
|
||||
mmc_get_dma_dir(data));
|
||||
}
|
||||
data->host_cookie = COOKIE_UNMAPPED;
|
||||
}
|
||||
sdhci_request_done_dma(host, mrq);
|
||||
}
|
||||
|
||||
host->mrqs_done[i] = NULL;
|
||||
@ -3175,7 +3225,7 @@ static bool sdhci_request_done(struct sdhci_host *host)
|
||||
return false;
|
||||
}
|
||||
|
||||
static void sdhci_complete_work(struct work_struct *work)
|
||||
void sdhci_complete_work(struct work_struct *work)
|
||||
{
|
||||
struct sdhci_host *host = container_of(work, struct sdhci_host,
|
||||
complete_work);
|
||||
@ -3183,6 +3233,7 @@ static void sdhci_complete_work(struct work_struct *work)
|
||||
while (!sdhci_request_done(host))
|
||||
;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_complete_work);
|
||||
|
||||
static void sdhci_timeout_timer(struct timer_list *t)
|
||||
{
|
||||
@ -3644,7 +3695,7 @@ out:
|
||||
return result;
|
||||
}
|
||||
|
||||
static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
|
||||
irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct sdhci_host *host = dev_id;
|
||||
struct mmc_command *cmd;
|
||||
@ -3674,6 +3725,7 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sdhci_thread_irq);
|
||||
|
||||
/*****************************************************************************\
|
||||
* *
|
||||
@ -4046,6 +4098,9 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev,
|
||||
|
||||
host->max_timeout_count = 0xE;
|
||||
|
||||
host->complete_work_fn = sdhci_complete_work;
|
||||
host->thread_irq_fn = sdhci_thread_irq;
|
||||
|
||||
return host;
|
||||
}
|
||||
|
||||
@ -4810,7 +4865,7 @@ int __sdhci_add_host(struct sdhci_host *host)
|
||||
if (!host->complete_wq)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_WORK(&host->complete_work, sdhci_complete_work);
|
||||
INIT_WORK(&host->complete_work, host->complete_work_fn);
|
||||
|
||||
timer_setup(&host->timer, sdhci_timeout_timer, 0);
|
||||
timer_setup(&host->data_timer, sdhci_timeout_data_timer, 0);
|
||||
@ -4819,7 +4874,7 @@ int __sdhci_add_host(struct sdhci_host *host)
|
||||
|
||||
sdhci_init(host, 0);
|
||||
|
||||
ret = request_threaded_irq(host->irq, sdhci_irq, sdhci_thread_irq,
|
||||
ret = request_threaded_irq(host->irq, sdhci_irq, host->thread_irq_fn,
|
||||
IRQF_SHARED, mmc_hostname(mmc), host);
|
||||
if (ret) {
|
||||
pr_err("%s: Failed to request IRQ %d: %d\n",
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user