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:
Linus Torvalds 2024-11-20 12:51:32 -08:00
commit 38556294b8
116 changed files with 4581 additions and 399 deletions

View File

@ -15,6 +15,7 @@ properties:
- enum: - enum:
- amd,pensando-elba-sd4hc - amd,pensando-elba-sd4hc
- microchip,mpfs-sd4hc - microchip,mpfs-sd4hc
- microchip,pic64gx-sd4hc
- socionext,uniphier-sd4hc - socionext,uniphier-sd4hc
- const: cdns,sd4hc - const: cdns,sd4hc
@ -120,7 +121,7 @@ required:
- clocks - clocks
allOf: allOf:
- $ref: mmc-controller.yaml - $ref: sdhci-common.yaml
- if: - if:
properties: properties:
compatible: compatible:

View File

@ -21,9 +21,11 @@ properties:
- mediatek,mt7620-mmc - mediatek,mt7620-mmc
- mediatek,mt7622-mmc - mediatek,mt7622-mmc
- mediatek,mt7986-mmc - mediatek,mt7986-mmc
- mediatek,mt7988-mmc
- mediatek,mt8135-mmc - mediatek,mt8135-mmc
- mediatek,mt8173-mmc - mediatek,mt8173-mmc
- mediatek,mt8183-mmc - mediatek,mt8183-mmc
- mediatek,mt8196-mmc
- mediatek,mt8516-mmc - mediatek,mt8516-mmc
- items: - items:
- const: mediatek,mt7623-mmc - const: mediatek,mt7623-mmc
@ -190,6 +192,7 @@ allOf:
- mediatek,mt8186-mmc - mediatek,mt8186-mmc
- mediatek,mt8188-mmc - mediatek,mt8188-mmc
- mediatek,mt8195-mmc - mediatek,mt8195-mmc
- mediatek,mt8196-mmc
- mediatek,mt8516-mmc - mediatek,mt8516-mmc
then: then:
properties: properties:
@ -263,6 +266,27 @@ allOf:
- const: bus_clk - const: bus_clk
- const: sys_cg - 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: - if:
properties: properties:
compatible: compatible:

View File

@ -38,11 +38,14 @@ properties:
- enum: - enum:
- qcom,ipq5018-sdhci - qcom,ipq5018-sdhci
- qcom,ipq5332-sdhci - qcom,ipq5332-sdhci
- qcom,ipq5424-sdhci
- qcom,ipq6018-sdhci - qcom,ipq6018-sdhci
- qcom,ipq9574-sdhci - qcom,ipq9574-sdhci
- qcom,qcm2290-sdhci - qcom,qcm2290-sdhci
- qcom,qcs404-sdhci - qcom,qcs404-sdhci
- qcom,qcs615-sdhci
- qcom,qdu1000-sdhci - qcom,qdu1000-sdhci
- qcom,sar2130p-sdhci
- qcom,sc7180-sdhci - qcom,sc7180-sdhci
- qcom,sc7280-sdhci - qcom,sc7280-sdhci
- qcom,sc8280xp-sdhci - qcom,sc8280xp-sdhci
@ -62,6 +65,7 @@ properties:
- qcom,sm8450-sdhci - qcom,sm8450-sdhci
- qcom,sm8550-sdhci - qcom,sm8550-sdhci
- qcom,sm8650-sdhci - qcom,sm8650-sdhci
- qcom,x1e80100-sdhci
- const: qcom,sdhci-msm-v5 # for sdcc version 5.0 - const: qcom,sdhci-msm-v5 # for sdcc version 5.0
reg: reg:

View File

@ -26,7 +26,7 @@ static DEFINE_IDR(memstick_host_idr);
static DEFINE_SPINLOCK(memstick_host_lock); static DEFINE_SPINLOCK(memstick_host_lock);
static int memstick_dev_match(struct memstick_dev *card, 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->match_flags & MEMSTICK_MATCH_ALL) {
if ((id->type == card->id.type) if ((id->type == card->id.type)
@ -44,7 +44,7 @@ static int memstick_bus_match(struct device *dev, const struct device_driver *dr
dev); dev);
const struct memstick_driver *ms_drv = container_of_const(drv, struct memstick_driver, const struct memstick_driver *ms_drv = container_of_const(drv, struct memstick_driver,
driver); driver);
struct memstick_device_id *ids = ms_drv->id_table; const struct memstick_device_id *ids = ms_drv->id_table;
if (ids) { if (ids) {
while (ids->match_flags) { while (ids->match_flags) {

View File

@ -996,7 +996,7 @@ static int msb_verify_block(struct msb_data *msb, u16 pba,
return 0; return 0;
} }
/* Writes exectly one block + oob */ /* Writes exactly one block + oob */
static int msb_write_block(struct msb_data *msb, static int msb_write_block(struct msb_data *msb,
u16 pba, u32 lba, struct scatterlist *sg, int offset) 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[] = { static const struct chs_entry chs_table[] = {
/* size sectors cylynders heads */ /* size sectors cylinders heads */
{ 4, 16, 247, 2 }, { 4, 16, 247, 2 },
{ 8, 16, 495, 2 }, { 8, 16, 495, 2 },
{ 16, 16, 495, 4 }, { 16, 16, 495, 4 },
@ -1729,7 +1729,7 @@ static int msb_init_card(struct memstick_dev *card)
boot_block = &msb->boot_page[0]; 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->block_count = boot_block->attr.number_of_blocks;
msb->page_size = boot_block->attr.page_size; msb->page_size = boot_block->attr.page_size;
@ -2279,7 +2279,7 @@ static int msb_resume(struct memstick_dev *card)
#endif /* CONFIG_PM */ #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_MATCH_ALL, MEMSTICK_TYPE_LEGACY, MEMSTICK_CATEGORY_STORAGE,
MEMSTICK_CLASS_FLASH}, MEMSTICK_CLASS_FLASH},

View File

@ -1349,7 +1349,7 @@ static int mspro_block_resume(struct memstick_dev *card)
#endif /* CONFIG_PM */ #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_MATCH_ALL, MEMSTICK_TYPE_PRO, MEMSTICK_CATEGORY_STORAGE_DUO,
MEMSTICK_CLASS_DUO}, MEMSTICK_CLASS_DUO},
{} {}

View File

@ -675,7 +675,7 @@ static irqreturn_t r592_irq(int irq, void *data)
return ret; return ret;
} }
/* External inteface: set settings */ /* External interface: set settings */
static int r592_set_param(struct memstick_host *host, static int r592_set_param(struct memstick_host *host,
enum memstick_param param, int value) enum memstick_param param, int value)
{ {

View File

@ -7,7 +7,7 @@ obj-$(CONFIG_MMC) += mmc_core.o
mmc_core-y := core.o bus.o host.o \ mmc_core-y := core.o bus.o host.o \
mmc.o mmc_ops.o sd.o sd_ops.o \ mmc.o mmc_ops.o sd.o sd_ops.o \
sdio.o sdio_ops.o sdio_bus.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 slot-gpio.o regulator.o
mmc_core-$(CONFIG_OF) += pwrseq.o mmc_core-$(CONFIG_OF) += pwrseq.o
obj-$(CONFIG_PWRSEQ_SIMPLE) += pwrseq_simple.o obj-$(CONFIG_PWRSEQ_SIMPLE) += pwrseq_simple.o

View File

@ -50,6 +50,7 @@
#include <linux/mmc/sd.h> #include <linux/mmc/sd.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/unaligned.h>
#include "queue.h" #include "queue.h"
#include "block.h" #include "block.h"
@ -993,11 +994,12 @@ static int mmc_sd_num_wr_blocks(struct mmc_card *card, u32 *written_blocks)
int err; int err;
u32 result; u32 result;
__be32 *blocks; __be32 *blocks;
u8 resp_sz = mmc_card_ult_capacity(card) ? 8 : 4;
unsigned int noio_flag;
struct mmc_request mrq = {}; struct mmc_request mrq = {};
struct mmc_command cmd = {}; struct mmc_command cmd = {};
struct mmc_data data = {}; struct mmc_data data = {};
struct scatterlist sg; struct scatterlist sg;
err = mmc_app_cmd(card->host, card); 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.arg = 0;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
data.blksz = 4; data.blksz = resp_sz;
data.blocks = 1; data.blocks = 1;
data.flags = MMC_DATA_READ; data.flags = MMC_DATA_READ;
data.sg = &sg; 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.cmd = &cmd;
mrq.data = &data; 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) if (!blocks)
return -ENOMEM; return -ENOMEM;
sg_init_one(&sg, blocks, 4); sg_init_one(&sg, blocks, resp_sz);
mmc_wait_for_req(card->host, &mrq); mmc_wait_for_req(card->host, &mrq);
result = ntohl(*blocks); 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); kfree(blocks);
if (cmd.error || data.error) 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_blk_data *md = mq->blkdata;
struct mmc_card *card = md->queue.card; struct mmc_card *card = md->queue.card;
unsigned int from, nr; unsigned int nr;
sector_t from;
int err = 0; int err = 0;
blk_status_t status = BLK_STS_OK; 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_blk_data *md = mq->blkdata;
struct mmc_card *card = md->queue.card; 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; int err = 0, type = MMC_BLK_SECDISCARD;
blk_status_t status = BLK_STS_OK; 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->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
brq->mrq.sbc = &brq->sbc; 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 #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_host_cmd23(card->host)) {
if ((mmc_card_mmc(card) && if ((mmc_card_mmc(card) &&
card->csd.mmca_vsn >= CSD_SPEC_VER_3) || 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)) card->scr.cmds & SD_SCR_CMD23_SUPPORT))
md->flags |= MMC_BLK_CMD23; md->flags |= MMC_BLK_CMD23;
} }

View File

@ -299,6 +299,7 @@ int mmc_add_card(struct mmc_card *card)
{ {
int ret; int ret;
const char *type; const char *type;
const char *speed_mode = "";
const char *uhs_bus_speed_mode = ""; const char *uhs_bus_speed_mode = "";
static const char *const uhs_speeds[] = { static const char *const uhs_speeds[] = {
[UHS_SDR12_BUS_SPEED] = "SDR12 ", [UHS_SDR12_BUS_SPEED] = "SDR12 ",
@ -321,7 +322,9 @@ int mmc_add_card(struct mmc_card *card)
case MMC_TYPE_SD: case MMC_TYPE_SD:
type = "SD"; type = "SD";
if (mmc_card_blockaddr(card)) { 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"; type = "SDXC";
else else
type = "SDHC"; type = "SDHC";
@ -340,27 +343,32 @@ int mmc_add_card(struct mmc_card *card)
break; 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) && if (mmc_card_uhs(card) &&
(card->sd_bus_speed < ARRAY_SIZE(uhs_speeds))) (card->sd_bus_speed < ARRAY_SIZE(uhs_speeds)))
uhs_bus_speed_mode = uhs_speeds[card->sd_bus_speed]; uhs_bus_speed_mode = uhs_speeds[card->sd_bus_speed];
if (mmc_host_is_spi(card->host)) { if (mmc_host_is_spi(card->host))
pr_info("%s: new %s%s%s card on SPI\n", pr_info("%s: new %s%s card on SPI\n",
mmc_hostname(card->host), mmc_hostname(card->host), speed_mode, type);
mmc_card_hs(card) ? "high speed " : "", else
mmc_card_ddr52(card) ? "DDR " : "", pr_info("%s: new %s%s%s card at address %04x\n",
type); mmc_hostname(card->host), speed_mode,
} 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 " : "",
uhs_bus_speed_mode, type, card->rca); uhs_bus_speed_mode, type, card->rca);
}
mmc_add_card_debugfs(card); mmc_add_card_debugfs(card);
card->dev.of_node = mmc_of_find_child_device(card->host, 0); card->dev.of_node = mmc_of_find_child_device(card->host, 0);

View File

@ -23,6 +23,7 @@
#define MMC_CARD_SDXC (1<<3) /* card is SDXC */ #define MMC_CARD_SDXC (1<<3) /* card is SDXC */
#define MMC_CARD_REMOVED (1<<4) /* card has been removed */ #define MMC_CARD_REMOVED (1<<4) /* card has been removed */
#define MMC_STATE_SUSPENDED (1<<5) /* card is suspended */ #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_present(c) ((c)->state & MMC_STATE_PRESENT)
#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY) #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_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
#define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED)) #define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED))
#define mmc_card_suspended(c) ((c)->state & MMC_STATE_SUSPENDED) #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_present(c) ((c)->state |= MMC_STATE_PRESENT)
#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) #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_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
#define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC) #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_removed(c) ((c)->state |= MMC_CARD_REMOVED)
#define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED) #define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED)
#define mmc_card_clr_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_SANDISK_SD 0x3
#define CID_MANFID_ATP 0x9 #define CID_MANFID_ATP 0x9
#define CID_MANFID_TOSHIBA 0x11 #define CID_MANFID_TOSHIBA 0x11
#define CID_MANFID_GIGASTONE 0x12
#define CID_MANFID_MICRON 0x13 #define CID_MANFID_MICRON 0x13
#define CID_MANFID_SAMSUNG 0x15 #define CID_MANFID_SAMSUNG 0x15
#define CID_MANFID_APACER 0x27 #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; 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 #endif

View File

@ -336,6 +336,9 @@ int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
{ {
int err; int err;
if (mrq->cmd && mrq->cmd->has_ext_addr)
mmc_send_ext_addr(host, mrq->cmd->ext_addr);
init_completion(&mrq->cmd_completion); init_completion(&mrq->cmd_completion);
mmc_retune_hold(host); mmc_retune_hold(host);
@ -351,6 +354,9 @@ int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
if (err) if (err)
return err; return err;
if (host->uhs2_sd_tran)
mmc_uhs2_prepare_cmd(host, mrq);
led_trigger_event(host->led, LED_FULL); led_trigger_event(host->led, LED_FULL);
__mmc_start_request(host, mrq); __mmc_start_request(host, mrq);
@ -450,6 +456,9 @@ int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq)
if (err) if (err)
goto out_err; goto out_err;
if (host->uhs2_sd_tran)
mmc_uhs2_prepare_cmd(host, mrq);
err = host->cqe_ops->cqe_request(host, mrq); err = host->cqe_ops->cqe_request(host, mrq);
if (err) if (err)
goto out_err; goto out_err;
@ -1132,7 +1141,7 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
return 0; 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; bit = ffs(ocr) - 1;
ocr &= 3 << bit; ocr &= 3 << bit;
mmc_power_cycle(host, ocr); 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); return mmc_mmc_erase_timeout(card, arg, qty);
} }
static int mmc_do_erase(struct mmc_card *card, unsigned int from, static int mmc_do_erase(struct mmc_card *card, sector_t from,
unsigned int to, unsigned int arg) sector_t to, unsigned int arg)
{ {
struct mmc_command cmd = {}; struct mmc_command cmd = {};
unsigned int qty = 0, busy_timeout = 0; 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)) else if (mmc_card_sd(card))
qty += to - from + 1; qty += to - from + 1;
else else
qty += ((to / card->erase_size) - qty += (mmc_sector_div(to, card->erase_size) -
(from / card->erase_size)) + 1; mmc_sector_div(from, card->erase_size)) + 1;
if (!mmc_card_blockaddr(card)) { if (!mmc_card_blockaddr(card)) {
from <<= 9; 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.opcode = MMC_ERASE_GROUP_START;
cmd.arg = from; cmd.arg = from;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; 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); err = mmc_wait_for_cmd(card->host, &cmd, 0);
if (err) { if (err) {
pr_err("mmc_erase: group start error %d, " 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.opcode = MMC_ERASE_GROUP_END;
cmd.arg = to; cmd.arg = to;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; 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); err = mmc_wait_for_cmd(card->host, &cmd, 0);
if (err) { if (err) {
pr_err("mmc_erase: group end error %d, status %#x\n", pr_err("mmc_erase: group end error %d, status %#x\n",
@ -1700,18 +1721,19 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
} }
static unsigned int mmc_align_erase_size(struct mmc_card *card, static unsigned int mmc_align_erase_size(struct mmc_card *card,
unsigned int *from, sector_t *from,
unsigned int *to, sector_t *to,
unsigned int nr) 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() * When the 'card->erase_size' is power of 2, we can use round_up/down()
* to align the erase size efficiently. * to align the erase size efficiently.
*/ */
if (is_power_of_2(card->erase_size)) { 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); from_new = round_up(temp, card->erase_size);
rem = from_new - temp; 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); nr_new = round_down(nr_new, card->erase_size);
} else { } else {
rem = from_new % card->erase_size; rem = mmc_sector_mod(from_new, card->erase_size);
if (rem) { if (rem) {
rem = card->erase_size - rem; rem = card->erase_size - rem;
from_new += 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. * 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 arg)
{ {
unsigned int rem, to = from + nr; unsigned int rem;
sector_t to = from + nr;
int err; int err;
if (!(card->csd.cmdclass & CCC_ERASE)) 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; return -EOPNOTSUPP;
if (arg == MMC_SECURE_ERASE_ARG) { 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; 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 * and call mmc_do_erase() twice if necessary. This special case is
* identified by the card->eg_boundary flag. * 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) { if ((arg & MMC_TRIM_OR_DISCARD_ARGS) && card->eg_boundary && nr > rem) {
err = mmc_do_erase(card, from, from + rem - 1, arg); err = mmc_do_erase(card, from, from + rem - 1, arg);
from += rem; from += rem;
@ -1863,12 +1887,12 @@ int mmc_can_secure_erase_trim(struct mmc_card *card)
} }
EXPORT_SYMBOL(mmc_can_secure_erase_trim); 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) unsigned int nr)
{ {
if (!card->erase_size) if (!card->erase_size)
return 0; 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 0;
return 1; return 1;
} }
@ -2249,6 +2273,18 @@ void mmc_rescan(struct work_struct *work)
goto out; 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++) { for (i = 0; i < ARRAY_SIZE(freqs); i++) {
unsigned int freq = freqs[i]; unsigned int freq = freqs[i];
if (freq > host->f_max) { if (freq > host->f_max) {
@ -2281,10 +2317,13 @@ void mmc_rescan(struct work_struct *work)
void mmc_start_host(struct mmc_host *host) 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->f_init = max(min(freqs[0], host->f_max), host->f_min);
host->rescan_disable = 0; host->rescan_disable = 0;
if (!(host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)) { if (power_up) {
mmc_claim_host(host); mmc_claim_host(host);
mmc_power_up(host, host->ocr_avail); mmc_power_up(host, host->ocr_avail);
mmc_release_host(host); mmc_release_host(host);

View File

@ -81,6 +81,7 @@ int mmc_detect_card_removed(struct mmc_host *host);
int mmc_attach_mmc(struct mmc_host *host); int mmc_attach_mmc(struct mmc_host *host);
int mmc_attach_sd(struct mmc_host *host); int mmc_attach_sd(struct mmc_host *host);
int mmc_attach_sdio(struct mmc_host *host); int mmc_attach_sdio(struct mmc_host *host);
int mmc_attach_sd_uhs2(struct mmc_host *host);
/* Module parameters */ /* Module parameters */
extern bool use_spi_crc; 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_start_request(struct mmc_host *host, struct mmc_request *mrq);
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 arg);
int mmc_can_erase(struct mmc_card *card); int mmc_can_erase(struct mmc_card *card);
int mmc_can_trim(struct mmc_card *card); int mmc_can_trim(struct mmc_card *card);
int mmc_can_discard(struct mmc_card *card); int mmc_can_discard(struct mmc_card *card);
int mmc_can_sanitize(struct mmc_card *card); int mmc_can_sanitize(struct mmc_card *card);
int mmc_can_secure_erase_trim(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, int mmc_erase_group_aligned(struct mmc_card *card, sector_t from, unsigned int nr);
unsigned int nr);
unsigned int mmc_calc_max_discard(struct mmc_card *card); unsigned int mmc_calc_max_discard(struct mmc_card *card);
int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen); 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; 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 #endif

View File

@ -144,10 +144,24 @@ int mmc_set_dsr(struct mmc_host *host)
return mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); 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 mmc_go_idle(struct mmc_host *host)
{ {
int err; int err;
struct mmc_command cmd = {};
/* /*
* Non-SPI hosts need to prevent chipselect going active during * 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); mmc_delay(1);
} }
cmd.opcode = MMC_GO_IDLE_STATE; err = __mmc_go_idle(host);
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);
if (!mmc_host_is_spi(host)) { if (!mmc_host_is_spi(host)) {
mmc_set_chip_select(host, MMC_CS_DONTCARE); mmc_set_chip_select(host, MMC_CS_DONTCARE);

View File

@ -25,6 +25,7 @@ struct mmc_command;
int mmc_select_card(struct mmc_card *card); int mmc_select_card(struct mmc_card *card);
int mmc_deselect_cards(struct mmc_host *host); int mmc_deselect_cards(struct mmc_host *host);
int mmc_set_dsr(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_go_idle(struct mmc_host *host);
int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
int mmc_set_relative_addr(struct mmc_card *card); int mmc_set_relative_addr(struct mmc_card *card);

View File

@ -3241,6 +3241,12 @@ static int mmc_test_probe(struct mmc_card *card)
if (!mmc_card_mmc(card) && !mmc_card_sd(card)) if (!mmc_card_mmc(card) && !mmc_card_sd(card))
return -ENODEV; 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); ret = mmc_test_register_dbgfs_file(card);
if (ret) if (ret)
return ret; return ret;

View File

@ -107,7 +107,7 @@ MODULE_DEVICE_TABLE(of, mmc_pwrseq_emmc_of_match);
static struct platform_driver mmc_pwrseq_emmc_driver = { static struct platform_driver mmc_pwrseq_emmc_driver = {
.probe = mmc_pwrseq_emmc_probe, .probe = mmc_pwrseq_emmc_probe,
.remove_new = mmc_pwrseq_emmc_remove, .remove = mmc_pwrseq_emmc_remove,
.driver = { .driver = {
.name = "pwrseq_emmc", .name = "pwrseq_emmc",
.of_match_table = mmc_pwrseq_emmc_of_match, .of_match_table = mmc_pwrseq_emmc_of_match,

View File

@ -122,7 +122,7 @@ static void mmc_pwrseq_sd8787_remove(struct platform_device *pdev)
static struct platform_driver mmc_pwrseq_sd8787_driver = { static struct platform_driver mmc_pwrseq_sd8787_driver = {
.probe = mmc_pwrseq_sd8787_probe, .probe = mmc_pwrseq_sd8787_probe,
.remove_new = mmc_pwrseq_sd8787_remove, .remove = mmc_pwrseq_sd8787_remove,
.driver = { .driver = {
.name = "pwrseq_sd8787", .name = "pwrseq_sd8787",
.of_match_table = mmc_pwrseq_sd8787_of_match, .of_match_table = mmc_pwrseq_sd8787_of_match,

View File

@ -17,6 +17,8 @@
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/property.h> #include <linux/property.h>
#include <linux/of.h>
#include <linux/reset.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
@ -29,6 +31,7 @@ struct mmc_pwrseq_simple {
u32 power_off_delay_us; u32 power_off_delay_us;
struct clk *ext_clk; struct clk *ext_clk;
struct gpio_descs *reset_gpios; struct gpio_descs *reset_gpios;
struct reset_control *reset_ctrl;
}; };
#define to_pwrseq_simple(p) container_of(p, struct mmc_pwrseq_simple, pwrseq) #define to_pwrseq_simple(p) container_of(p, struct mmc_pwrseq_simple, pwrseq)
@ -67,14 +70,21 @@ static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host)
pwrseq->clk_enabled = true; pwrseq->clk_enabled = true;
} }
mmc_pwrseq_simple_set_gpios_value(pwrseq, 1); 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);
} }
static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host) static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host)
{ {
struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq); struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
mmc_pwrseq_simple_set_gpios_value(pwrseq, 0); 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) if (pwrseq->post_power_on_delay_ms)
msleep(pwrseq->post_power_on_delay_ms); msleep(pwrseq->post_power_on_delay_ms);
@ -84,7 +94,10 @@ static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
{ {
struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq); struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
mmc_pwrseq_simple_set_gpios_value(pwrseq, 1); 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) if (pwrseq->power_off_delay_us)
usleep_range(pwrseq->power_off_delay_us, usleep_range(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 mmc_pwrseq_simple *pwrseq;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
int ngpio;
pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL); pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL);
if (!pwrseq) 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) 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"); return dev_err_probe(dev, PTR_ERR(pwrseq->ext_clk), "external clock not ready\n");
pwrseq->reset_gpios = devm_gpiod_get_array(dev, "reset", ngpio = of_count_phandle_with_args(dev->of_node, "reset-gpios", "#gpio-cells");
GPIOD_OUT_HIGH); if (ngpio == 1) {
if (IS_ERR(pwrseq->reset_gpios) && pwrseq->reset_ctrl = devm_reset_control_get_optional_shared(dev, NULL);
PTR_ERR(pwrseq->reset_gpios) != -ENOENT && if (IS_ERR(pwrseq->reset_ctrl))
PTR_ERR(pwrseq->reset_gpios) != -ENOSYS) { return dev_err_probe(dev, PTR_ERR(pwrseq->reset_ctrl),
return dev_err_probe(dev, PTR_ERR(pwrseq->reset_gpios), "reset GPIOs not ready\n"); "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");
}
} }
device_property_read_u32(dev, "post-power-on-delay-ms", 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 = { static struct platform_driver mmc_pwrseq_simple_driver = {
.probe = mmc_pwrseq_simple_probe, .probe = mmc_pwrseq_simple_probe,
.remove_new = mmc_pwrseq_simple_remove, .remove = mmc_pwrseq_simple_remove,
.driver = { .driver = {
.name = "pwrseq_simple", .name = "pwrseq_simple",
.of_match_table = mmc_pwrseq_simple_of_match, .of_match_table = mmc_pwrseq_simple_of_match,

View File

@ -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, 0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY), 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 END_FIXUP
}; };

View File

@ -226,6 +226,33 @@ int mmc_regulator_set_vqmmc(struct mmc_host *mmc, struct mmc_ios *ios)
} }
EXPORT_SYMBOL_GPL(mmc_regulator_set_vqmmc); 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 #else
static inline int mmc_regulator_get_ocrmask(struct regulator *supply) 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.vmmc = devm_regulator_get_optional(dev, "vmmc");
mmc->supply.vqmmc = devm_regulator_get_optional(dev, "vqmmc"); 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 (IS_ERR(mmc->supply.vmmc)) {
if (PTR_ERR(mmc->supply.vmmc) == -EPROBE_DEFER) 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"); 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; return 0;
} }
EXPORT_SYMBOL_GPL(mmc_regulator_get_supply); EXPORT_SYMBOL_GPL(mmc_regulator_get_supply);

View File

@ -100,7 +100,7 @@ void mmc_decode_cid(struct mmc_card *card)
/* /*
* Given a 128-bit response, decode to our card CSD structure. * 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; struct mmc_csd *csd = &card->csd;
unsigned int e, m, csd_struct; unsigned int e, m, csd_struct;
@ -144,9 +144,10 @@ static int mmc_decode_csd(struct mmc_card *card)
mmc_card_set_readonly(card); mmc_card_set_readonly(card);
break; break;
case 1: case 1:
case 2:
/* /*
* This is a block-addressed SDHC or SDXC card. Most * This is a block-addressed SDHC, SDXC or SDUC card.
* interesting fields are unused and have fixed * Most interesting fields are unused and have fixed
* values. To avoid getting tripped by buggy cards, * values. To avoid getting tripped by buggy cards,
* we assume those fixed values ourselves. * 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); e = unstuff_bits(resp, 96, 3);
csd->max_dtr = tran_exp[e] * tran_mant[m]; csd->max_dtr = tran_exp[e] * tran_mant[m];
csd->cmdclass = unstuff_bits(resp, 84, 12); 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_struct == 1)
if (csd->c_size >= 0xFFFF) 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); mmc_card_set_ext_capacity(card);
m = unstuff_bits(resp, 48, 22); csd->capacity = (1 + (typeof(sector_t))m) << 10;
csd->capacity = (1 + m) << 10;
csd->read_blkbits = 9; csd->read_blkbits = 9;
csd->read_partial = 0; 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. * 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; struct sd_scr *scr = &card->scr;
unsigned int scr_struct; unsigned int scr_struct;
@ -830,8 +836,11 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
* block-addressed SDHC cards. * block-addressed SDHC cards.
*/ */
err = mmc_send_if_cond(host, ocr); err = mmc_send_if_cond(host, ocr);
if (!err) if (!err) {
ocr |= SD_OCR_CCS; 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 * If the host supports one of UHS-I modes, request the card
@ -876,7 +885,7 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
return err; 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; int err;
@ -887,14 +896,14 @@ int mmc_sd_get_csd(struct mmc_card *card)
if (err) if (err)
return err; return err;
err = mmc_decode_csd(card); err = mmc_decode_csd(card, is_sduc);
if (err) if (err)
return err; return err;
return 0; return 0;
} }
static int mmc_sd_get_ro(struct mmc_host *host) int mmc_sd_get_ro(struct mmc_host *host)
{ {
int ro; 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; card->ext_power.rev = reg_buf[0] & 0xf;
/* Power Off Notification support at bit 4. */ /* 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; card->ext_power.feature_support |= SD_EXT_POWER_OFF_NOTIFY;
/* Power Sustenance support at bit 5. */ /* Power Sustenance support at bit 5. */
@ -1442,7 +1451,10 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
} }
if (!oldcard) { 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) if (err)
goto free_card; goto free_card;
@ -1552,7 +1564,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
goto free_card; 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); err = host->cqe_ops->cqe_enable(host, card);
if (!err) { if (!err) {
host->cqe_enabled = true; host->cqe_enabled = true;

View File

@ -10,7 +10,9 @@ struct mmc_host;
struct mmc_card; struct mmc_card;
int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr); 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); void mmc_decode_cid(struct mmc_card *card);
int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card, int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
bool reinit); bool reinit);

View File

@ -16,6 +16,7 @@
#include <linux/mmc/sd.h> #include <linux/mmc/sd.h>
#include "core.h" #include "core.h"
#include "card.h"
#include "sd_ops.h" #include "sd_ops.h"
#include "mmc_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)) if (WARN_ON(card && card->host != host))
return -EINVAL; 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; cmd.opcode = MMC_APP_CMD;
if (card) { if (card) {
@ -188,6 +198,20 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
return 0; 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, static int __mmc_send_if_cond(struct mmc_host *host, u32 ocr, u8 pcie_bits,
u32 *resp) u32 *resp)
{ {

View File

@ -12,6 +12,7 @@
struct mmc_card; struct mmc_card;
struct mmc_host; struct mmc_host;
struct mmc_request;
int mmc_app_set_bus_width(struct mmc_card *card, int width); int mmc_app_set_bus_width(struct mmc_card *card, int width);
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
@ -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_send_scr(struct mmc_card *card);
int mmc_app_sd_status(struct mmc_card *card, void *ssr); 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_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 #endif

1304
drivers/mmc/core/sd_uhs2.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -769,7 +769,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
* Read CSD, before selecting the card * Read CSD, before selecting the card
*/ */
if (!oldcard && mmc_card_sd_combo(card)) { if (!oldcard && mmc_card_sd_combo(card)) {
err = mmc_sd_get_csd(card); err = mmc_sd_get_csd(card, false);
if (err) if (err)
goto remove; goto remove;

View File

@ -98,10 +98,20 @@ config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
This is the case for the Nintendo Wii SDHCI. 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 config MMC_SDHCI_PCI
tristate "SDHCI support on PCI bus" tristate "SDHCI support on PCI bus"
depends on MMC_SDHCI && PCI depends on MMC_SDHCI && PCI
select MMC_CQHCI select MMC_CQHCI
select MMC_SDHCI_UHS2
select IOSF_MBI if X86 select IOSF_MBI if X86
select MMC_SDHCI_IO_ACCESSORS select MMC_SDHCI_IO_ACCESSORS
help help
@ -1009,6 +1019,7 @@ config MMC_MTK
depends on COMMON_CLK depends on COMMON_CLK
select REGULATOR select REGULATOR
select MMC_CQHCI select MMC_CQHCI
select MMC_HSQ
help help
This selects the MediaTek(R) Secure digital and Multimedia card Interface. 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. If you have a machine with a integrated SD/MMC card reader, say Y or M here.

View File

@ -11,6 +11,7 @@ obj-$(CONFIG_MMC_PXA) += pxamci.o
obj-$(CONFIG_MMC_MXC) += mxcmmc.o obj-$(CONFIG_MMC_MXC) += mxcmmc.o
obj-$(CONFIG_MMC_MXS) += mxs-mmc.o obj-$(CONFIG_MMC_MXS) += mxs-mmc.o
obj-$(CONFIG_MMC_SDHCI) += sdhci.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o
obj-$(CONFIG_MMC_SDHCI_UHS2) += sdhci-uhs2.o
obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.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-y += sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o \
sdhci-pci-dwc-mshc.o sdhci-pci-gli.o sdhci-pci-dwc-mshc.o sdhci-pci-gli.o

View File

@ -1175,7 +1175,7 @@ MODULE_DEVICE_TABLE(platform, alcor_pci_sdmmc_ids);
static struct platform_driver alcor_pci_sdmmc_driver = { static struct platform_driver alcor_pci_sdmmc_driver = {
.probe = alcor_pci_sdmmc_drv_probe, .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, .id_table = alcor_pci_sdmmc_ids,
.driver = { .driver = {
.name = DRV_NAME_ALCOR_PCI_SDMMC, .name = DRV_NAME_ALCOR_PCI_SDMMC,

View File

@ -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. * Update host->data_size and host->sg.
*/ */
static void atmci_pdc_set_single_buf(struct atmel_mci *host, 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 = { static struct platform_driver atmci_driver = {
.probe = atmci_probe, .probe = atmci_probe,
.remove_new = atmci_remove, .remove = atmci_remove,
.driver = { .driver = {
.name = "atmel_mci", .name = "atmel_mci",
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -543,7 +543,7 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
cmd->resp[i] |= (r[i + 1] & 0xFF000000) >> 24; cmd->resp[i] |= (r[i + 1] & 0xFF000000) >> 24;
} }
} else { } 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 * the response (SD_RESP1 + SD_RESP2), but because
* our response omits the CRC, our data ends up * our response omits the CRC, our data ends up
* being shifted 8 bits to the right. In this case, * 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 = { static struct platform_driver au1xmmc_driver = {
.probe = au1xmmc_probe, .probe = au1xmmc_probe,
.remove_new = au1xmmc_remove, .remove = au1xmmc_remove,
.suspend = au1xmmc_suspend, .suspend = au1xmmc_suspend,
.resume = au1xmmc_resume, .resume = au1xmmc_resume,
.driver = { .driver = {

View File

@ -148,9 +148,10 @@ struct bcm2835_host {
void __iomem *ioaddr; void __iomem *ioaddr;
u32 phys_addr; u32 phys_addr;
struct clk *clk;
struct platform_device *pdev; struct platform_device *pdev;
int clock; /* Current clock speed */ unsigned int clock; /* Current clock speed */
unsigned int max_clk; /* Max possible freq */ unsigned int max_clk; /* Max possible freq */
struct work_struct dma_work; struct work_struct dma_work;
struct delayed_work timeout_work; /* Timer for timeouts */ 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) static int bcm2835_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct clk *clk;
struct bcm2835_host *host; struct bcm2835_host *host;
struct mmc_host *mmc; struct mmc_host *mmc;
const __be32 *regaddr_p; const __be32 *regaddr_p;
@ -1393,15 +1393,6 @@ static int bcm2835_probe(struct platform_device *pdev)
/* Ignore errors to fall back to PIO mode */ /* 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); host->irq = platform_get_irq(pdev, 0);
if (host->irq < 0) { if (host->irq < 0) {
ret = host->irq; ret = host->irq;
@ -1412,16 +1403,30 @@ static int bcm2835_probe(struct platform_device *pdev)
if (ret) if (ret)
goto err; 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) if (ret)
goto err; 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); platform_set_drvdata(pdev, host);
dev_dbg(dev, "%s -> OK\n", __func__); dev_dbg(dev, "%s -> OK\n", __func__);
return 0; return 0;
err_clk:
clk_disable_unprepare(host->clk);
err: err:
dev_dbg(dev, "%s -> err %d\n", __func__, ret); dev_dbg(dev, "%s -> err %d\n", __func__, ret);
if (host->dma_chan_rxtx) if (host->dma_chan_rxtx)
@ -1445,6 +1450,8 @@ static void bcm2835_remove(struct platform_device *pdev)
cancel_work_sync(&host->dma_work); cancel_work_sync(&host->dma_work);
cancel_delayed_work_sync(&host->timeout_work); cancel_delayed_work_sync(&host->timeout_work);
clk_disable_unprepare(host->clk);
if (host->dma_chan_rxtx) if (host->dma_chan_rxtx)
dma_release_channel(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 = { static struct platform_driver bcm2835_driver = {
.probe = bcm2835_probe, .probe = bcm2835_probe,
.remove_new = bcm2835_remove, .remove = bcm2835_remove,
.driver = { .driver = {
.name = "sdhost-bcm2835", .name = "sdhost-bcm2835",
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -217,7 +217,7 @@ static int octeon_mmc_probe(struct platform_device *pdev)
return PTR_ERR(base); return PTR_ERR(base);
host->dma_base = 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 * a negative offset here, first register used on Octeon therefore
* starts at 0x20 (MIO_EMM_DMA_CFG). * 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 = { static struct platform_driver octeon_mmc_driver = {
.probe = octeon_mmc_probe, .probe = octeon_mmc_probe,
.remove_new = octeon_mmc_remove, .remove = octeon_mmc_remove,
.driver = { .driver = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -771,7 +771,7 @@ static void cb710_mmc_exit(struct platform_device *pdev)
static struct platform_driver cb710_mmc_driver = { static struct platform_driver cb710_mmc_driver = {
.driver.name = "cb710-mmc", .driver.name = "cb710-mmc",
.probe = cb710_mmc_init, .probe = cb710_mmc_init,
.remove_new = cb710_mmc_exit, .remove = cb710_mmc_exit,
#ifdef CONFIG_PM #ifdef CONFIG_PM
.suspend = cb710_mmc_suspend, .suspend = cb710_mmc_suspend,
.resume = cb710_mmc_resume, .resume = cb710_mmc_resume,

View File

@ -7,24 +7,23 @@
* Copyright (C) 2009 David Brownell * Copyright (C) 2009 David Brownell
*/ */
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/err.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/mmc/host.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/mmc/mmc.h> #include <linux/dmaengine.h>
#include <linux/of.h> #include <linux/err.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/interrupt.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_data/mmc-davinci.h>
#include <linux/platform_device.h>
#include <linux/property.h>
/* /*
* Register Definitions * Register Definitions
@ -1229,7 +1228,7 @@ static int davinci_mmcsd_probe(struct platform_device *pdev)
host->mmc_input_clk = clk_get_rate(host->clk); 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) { if (pdev->id_entry) {
ret = mmc_of_parse(mmc); ret = mmc_of_parse(mmc);
if (ret) { if (ret) {
@ -1400,7 +1399,7 @@ static struct platform_driver davinci_mmcsd_driver = {
.of_match_table = davinci_mmc_dt_ids, .of_match_table = davinci_mmc_dt_ids,
}, },
.probe = davinci_mmcsd_probe, .probe = davinci_mmcsd_probe,
.remove_new = davinci_mmcsd_remove, .remove = davinci_mmcsd_remove,
.id_table = davinci_mmc_devtype, .id_table = davinci_mmc_devtype,
}; };

View File

@ -68,7 +68,7 @@ static int dw_mci_bluefield_probe(struct platform_device *pdev)
static struct platform_driver dw_mci_bluefield_pltfm_driver = { static struct platform_driver dw_mci_bluefield_pltfm_driver = {
.probe = dw_mci_bluefield_probe, .probe = dw_mci_bluefield_probe,
.remove_new = dw_mci_pltfm_remove, .remove = dw_mci_pltfm_remove,
.driver = { .driver = {
.name = "dwmmc_bluefield", .name = "dwmmc_bluefield",
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -682,7 +682,7 @@ static const struct dev_pm_ops dw_mci_exynos_pmops = {
static struct platform_driver dw_mci_exynos_pltfm_driver = { static struct platform_driver dw_mci_exynos_pltfm_driver = {
.probe = dw_mci_exynos_probe, .probe = dw_mci_exynos_probe,
.remove_new = dw_mci_exynos_remove, .remove = dw_mci_exynos_remove,
.driver = { .driver = {
.name = "dwmmc_exynos", .name = "dwmmc_exynos",
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -189,7 +189,7 @@ static const struct of_device_id dw_mci_hi3798cv200_match[] = {
MODULE_DEVICE_TABLE(of, dw_mci_hi3798cv200_match); MODULE_DEVICE_TABLE(of, dw_mci_hi3798cv200_match);
static struct platform_driver dw_mci_hi3798cv200_driver = { static struct platform_driver dw_mci_hi3798cv200_driver = {
.probe = dw_mci_hi3798cv200_probe, .probe = dw_mci_hi3798cv200_probe,
.remove_new = dw_mci_hi3798cv200_remove, .remove = dw_mci_hi3798cv200_remove,
.driver = { .driver = {
.name = "dwmmc_hi3798cv200", .name = "dwmmc_hi3798cv200",
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -237,7 +237,7 @@ static void dw_mci_hi3798mv200_remove(struct platform_device *pdev)
MODULE_DEVICE_TABLE(of, dw_mci_hi3798mv200_match); MODULE_DEVICE_TABLE(of, dw_mci_hi3798mv200_match);
static struct platform_driver dw_mci_hi3798mv200_driver = { static struct platform_driver dw_mci_hi3798mv200_driver = {
.probe = dw_mci_hi3798mv200_probe, .probe = dw_mci_hi3798mv200_probe,
.remove_new = dw_mci_hi3798mv200_remove, .remove = dw_mci_hi3798mv200_remove,
.driver = { .driver = {
.name = "dwmmc_hi3798mv200", .name = "dwmmc_hi3798mv200",
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -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 = { static struct platform_driver dw_mci_k3_pltfm_driver = {
.probe = dw_mci_k3_probe, .probe = dw_mci_k3_probe,
.remove_new = dw_mci_pltfm_remove, .remove = dw_mci_pltfm_remove,
.driver = { .driver = {
.name = "dwmmc_k3", .name = "dwmmc_k3",
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -131,7 +131,7 @@ EXPORT_SYMBOL_GPL(dw_mci_pltfm_remove);
static struct platform_driver dw_mci_pltfm_driver = { static struct platform_driver dw_mci_pltfm_driver = {
.probe = dw_mci_pltfm_probe, .probe = dw_mci_pltfm_probe,
.remove_new = dw_mci_pltfm_remove, .remove = dw_mci_pltfm_remove,
.driver = { .driver = {
.name = "dw_mmc", .name = "dw_mmc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -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 = { static struct platform_driver dw_mci_rockchip_pltfm_driver = {
.probe = dw_mci_rockchip_probe, .probe = dw_mci_rockchip_probe,
.remove_new = dw_mci_rockchip_remove, .remove = dw_mci_rockchip_remove,
.driver = { .driver = {
.name = "dwmmc_rockchip", .name = "dwmmc_rockchip",
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -115,7 +115,7 @@ static int dw_mci_starfive_probe(struct platform_device *pdev)
static struct platform_driver dw_mci_starfive_driver = { static struct platform_driver dw_mci_starfive_driver = {
.probe = dw_mci_starfive_probe, .probe = dw_mci_starfive_probe,
.remove_new = dw_mci_pltfm_remove, .remove = dw_mci_pltfm_remove,
.driver = { .driver = {
.name = "dwmmc_starfive", .name = "dwmmc_starfive",
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -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 * Use the initial fifoth_val for PIO mode. If wm_algined
* is set, we set watermark same as data size. * 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. * prev_blksz should be invalidated.
*/ */
if (host->wm_aligned) if (host->wm_aligned)

View File

@ -1191,7 +1191,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend,
static struct platform_driver jz4740_mmc_driver = { static struct platform_driver jz4740_mmc_driver = {
.probe = jz4740_mmc_probe, .probe = jz4740_mmc_probe,
.remove_new = jz4740_mmc_remove, .remove = jz4740_mmc_remove,
.driver = { .driver = {
.name = "jz4740-mmc", .name = "jz4740-mmc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -644,7 +644,7 @@ MODULE_DEVICE_TABLE(of, litex_match);
static struct platform_driver litex_mmc_driver = { static struct platform_driver litex_mmc_driver = {
.probe = litex_mmc_probe, .probe = litex_mmc_probe,
.remove_new = litex_mmc_remove, .remove = litex_mmc_remove,
.driver = { .driver = {
.name = "litex-mmc", .name = "litex-mmc",
.of_match_table = litex_match, .of_match_table = litex_match,

View File

@ -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 memory at the end of the controller used as bounce buffer for
* the dram_access_quirk only accepts 32bit read/write access, * 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) { if (host->dram_access_quirk && mrq->data) {
mrq->cmd->error = meson_mmc_validate_dram_access(mmc, 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 = { static struct platform_driver meson_mmc_driver = {
.probe = meson_mmc_probe, .probe = meson_mmc_probe,
.remove_new = meson_mmc_remove, .remove = meson_mmc_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -904,7 +904,7 @@ MODULE_DEVICE_TABLE(of, meson_mx_sdhc_of_match);
static struct platform_driver meson_mx_sdhc_driver = { static struct platform_driver meson_mx_sdhc_driver = {
.probe = meson_mx_sdhc_probe, .probe = meson_mx_sdhc_probe,
.remove_new = meson_mx_sdhc_remove, .remove = meson_mx_sdhc_remove,
.driver = { .driver = {
.name = "meson-mx-sdhc", .name = "meson-mx-sdhc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -754,7 +754,7 @@ MODULE_DEVICE_TABLE(of, meson_mx_mmc_of_match);
static struct platform_driver meson_mx_mmc_driver = { static struct platform_driver meson_mx_mmc_driver = {
.probe = meson_mx_mmc_probe, .probe = meson_mx_mmc_probe,
.remove_new = meson_mx_mmc_remove, .remove = meson_mx_mmc_remove,
.driver = { .driver = {
.name = "meson-mx-sdio", .name = "meson-mx-sdio",
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -222,10 +222,6 @@ static int mmc_spi_response_get(struct mmc_spi_host *host,
u8 leftover = 0; u8 leftover = 0;
unsigned short rotator; unsigned short rotator;
int i; 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 /* Except for data block reads, the whole response will already
* be stored in the scratch buffer. It's somewhere after the * be stored in the scratch buffer. It's somewhere after the
@ -378,8 +374,9 @@ static int mmc_spi_response_get(struct mmc_spi_host *host,
} }
if (value < 0) if (value < 0)
dev_dbg(&host->spi->dev, "%s: resp %04x %08x\n", dev_dbg(&host->spi->dev,
tag, cmd->resp[0], cmd->resp[1]); " ... 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 */ /* disable chipselect on errors and some success cases */
if (value >= 0 && cs_on) if (value >= 0 && cs_on)

View File

@ -77,7 +77,7 @@
#define MCI_CPSM_INTERRUPT BIT(8) #define MCI_CPSM_INTERRUPT BIT(8)
#define MCI_CPSM_PENDING BIT(9) #define MCI_CPSM_PENDING BIT(9)
#define MCI_CPSM_ENABLE BIT(10) #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_SDIO_SUSP BIT(11)
#define MCI_CPSM_ST_ENCMD_COMPL BIT(12) #define MCI_CPSM_ST_ENCMD_COMPL BIT(12)
#define MCI_CPSM_ST_NIEN BIT(13) #define MCI_CPSM_ST_NIEN BIT(13)

View File

@ -719,7 +719,7 @@ MODULE_DEVICE_TABLE(of, moxart_mmc_match);
static struct platform_driver moxart_mmc_driver = { static struct platform_driver moxart_mmc_driver = {
.probe = moxart_probe, .probe = moxart_probe,
.remove_new = moxart_remove, .remove = moxart_remove,
.driver = { .driver = {
.name = "mmc-moxart", .name = "mmc-moxart",
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -33,6 +33,7 @@
#include <linux/mmc/slot-gpio.h> #include <linux/mmc/slot-gpio.h>
#include "cqhci.h" #include "cqhci.h"
#include "mmc_hsq.h"
#define MAX_BD_NUM 1024 #define MAX_BD_NUM 1024
#define MSDC_NR_CLOCKS 3 #define MSDC_NR_CLOCKS 3
@ -65,6 +66,7 @@
#define SDC_RESP3 0x4c #define SDC_RESP3 0x4c
#define SDC_BLK_NUM 0x50 #define SDC_BLK_NUM 0x50
#define SDC_ADV_CFG0 0x64 #define SDC_ADV_CFG0 0x64
#define MSDC_NEW_RX_CFG 0x68
#define EMMC_IOCON 0x7c #define EMMC_IOCON 0x7c
#define SDC_ACMD_RESP 0x80 #define SDC_ACMD_RESP 0x80
#define DMA_SA_H4BIT 0x8c #define DMA_SA_H4BIT 0x8c
@ -91,6 +93,7 @@
#define EMMC_TOP_CONTROL 0x00 #define EMMC_TOP_CONTROL 0x00
#define EMMC_TOP_CMD 0x04 #define EMMC_TOP_CMD 0x04
#define EMMC50_PAD_DS_TUNE 0x0c #define EMMC50_PAD_DS_TUNE 0x0c
#define LOOP_TEST_CONTROL 0x30
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
/* Register Mask */ /* Register Mask */
@ -202,9 +205,13 @@
#define SDC_STS_CMDBUSY BIT(1) /* RW */ #define SDC_STS_CMDBUSY BIT(1) /* RW */
#define SDC_STS_SWR_COMPL BIT(31) /* RW */ #define SDC_STS_SWR_COMPL BIT(31) /* RW */
#define SDC_DAT1_IRQ_TRIGGER BIT(19) /* RW */
/* SDC_ADV_CFG0 mask */ /* SDC_ADV_CFG0 mask */
#define SDC_DAT1_IRQ_TRIGGER BIT(19) /* RW */
#define SDC_RX_ENHANCE_EN BIT(20) /* 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 */ /* DMA_SA_H4BIT mask */
#define DMA_ADDR_HIGH_4BIT GENMASK(3, 0) /* RW */ #define DMA_ADDR_HIGH_4BIT GENMASK(3, 0) /* RW */
@ -226,6 +233,7 @@
/* MSDC_PATCH_BIT mask */ /* MSDC_PATCH_BIT mask */
#define MSDC_PATCH_BIT_ODDSUPP BIT(1) /* RW */ #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_INT_DAT_LATCH_CK_SEL GENMASK(9, 7)
#define MSDC_CKGEN_MSDC_DLY_SEL GENMASK(14, 10) #define MSDC_CKGEN_MSDC_DLY_SEL GENMASK(14, 10)
#define MSDC_PATCH_BIT_IODSSEL BIT(16) /* RW */ #define MSDC_PATCH_BIT_IODSSEL BIT(16) /* RW */
@ -247,6 +255,8 @@
#define MSDC_PB2_SUPPORT_64G BIT(1) /* RW */ #define MSDC_PB2_SUPPORT_64G BIT(1) /* RW */
#define MSDC_PB2_RESPWAIT GENMASK(3, 2) /* RW */ #define MSDC_PB2_RESPWAIT GENMASK(3, 2) /* RW */
#define MSDC_PB2_RESPSTSENSEL GENMASK(18, 16) /* 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_PB2_CRCSTSENSEL GENMASK(31, 29) /* RW */
#define MSDC_PAD_TUNE_DATWRDLY GENMASK(4, 0) /* 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_DLY1 GENMASK(14, 10) /* RW */
#define PAD_DS_DLY3 GENMASK(4, 0) /* 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_EIO BIT(0)
#define REQ_CMD_TMO BIT(1) #define REQ_CMD_TMO BIT(1)
#define REQ_DAT_ERR BIT(2) #define REQ_DAT_ERR BIT(2)
@ -391,6 +407,7 @@ struct msdc_save_para {
u32 emmc_top_control; u32 emmc_top_control;
u32 emmc_top_cmd; u32 emmc_top_cmd;
u32 emmc50_pad_ds_tune; u32 emmc50_pad_ds_tune;
u32 loop_test_control;
}; };
struct mtk_mmc_compatible { struct mtk_mmc_compatible {
@ -402,9 +419,13 @@ struct mtk_mmc_compatible {
bool data_tune; bool data_tune;
bool busy_check; bool busy_check;
bool stop_clk_fix; bool stop_clk_fix;
u8 stop_dly_sel;
u8 pop_en_cnt;
bool enhance_rx; bool enhance_rx;
bool support_64g; bool support_64g;
bool use_internal_cd; bool use_internal_cd;
bool support_new_tx;
bool support_new_rx;
}; };
struct msdc_tune_para { struct msdc_tune_para {
@ -473,6 +494,7 @@ struct msdc_host {
bool hs400_tuning; /* hs400 mode online tuning */ bool hs400_tuning; /* hs400 mode online tuning */
bool internal_cd; /* Use internal card-detect logic */ bool internal_cd; /* Use internal card-detect logic */
bool cqhci; /* support eMMC hw cmdq */ 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_save_para save_para; /* used when gate HCLK */
struct msdc_tune_para def_tune_para; /* default tune setting */ struct msdc_tune_para def_tune_para; /* default tune setting */
struct msdc_tune_para saved_tune_para; /* tune result of CMD21/CMD19 */ 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, .data_tune = true,
.busy_check = true, .busy_check = true,
.stop_clk_fix = true, .stop_clk_fix = true,
.stop_dly_sel = 3,
.enhance_rx = true, .enhance_rx = true,
.support_64g = true, .support_64g = true,
}; };
@ -515,6 +538,7 @@ static const struct mtk_mmc_compatible mt6779_compat = {
.data_tune = true, .data_tune = true,
.busy_check = true, .busy_check = true,
.stop_clk_fix = true, .stop_clk_fix = true,
.stop_dly_sel = 3,
.enhance_rx = true, .enhance_rx = true,
.support_64g = true, .support_64g = true,
}; };
@ -554,6 +578,7 @@ static const struct mtk_mmc_compatible mt7622_compat = {
.data_tune = true, .data_tune = true,
.busy_check = true, .busy_check = true,
.stop_clk_fix = true, .stop_clk_fix = true,
.stop_dly_sel = 3,
.enhance_rx = true, .enhance_rx = true,
.support_64g = false, .support_64g = false,
}; };
@ -567,6 +592,7 @@ static const struct mtk_mmc_compatible mt7986_compat = {
.data_tune = true, .data_tune = true,
.busy_check = true, .busy_check = true,
.stop_clk_fix = true, .stop_clk_fix = true,
.stop_dly_sel = 3,
.enhance_rx = true, .enhance_rx = true,
.support_64g = true, .support_64g = true,
}; };
@ -606,6 +632,7 @@ static const struct mtk_mmc_compatible mt8183_compat = {
.data_tune = true, .data_tune = true,
.busy_check = true, .busy_check = true,
.stop_clk_fix = true, .stop_clk_fix = true,
.stop_dly_sel = 3,
.enhance_rx = true, .enhance_rx = true,
.support_64g = true, .support_64g = true,
}; };
@ -619,6 +646,24 @@ static const struct mtk_mmc_compatible mt8516_compat = {
.data_tune = true, .data_tune = true,
.busy_check = true, .busy_check = true,
.stop_clk_fix = 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[] = { 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,mt7620-mmc", .data = &mt7620_compat},
{ .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat}, { .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat},
{ .compatible = "mediatek,mt7986-mmc", .data = &mt7986_compat}, { .compatible = "mediatek,mt7986-mmc", .data = &mt7986_compat},
{ .compatible = "mediatek,mt7988-mmc", .data = &mt7986_compat},
{ .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat}, { .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat},
{ .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat}, { .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat},
{ .compatible = "mediatek,mt8183-mmc", .data = &mt8183_compat}, { .compatible = "mediatek,mt8183-mmc", .data = &mt8183_compat},
{ .compatible = "mediatek,mt8196-mmc", .data = &mt8196_compat},
{ .compatible = "mediatek,mt8516-mmc", .data = &mt8516_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); (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) static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
{ {
struct mmc_host *mmc = mmc_from_priv(host); 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 sclk;
u32 tune_reg = host->dev_comp->pad_tune_reg; u32 tune_reg = host->dev_comp->pad_tune_reg;
u32 val; u32 val;
bool timing_changed;
if (!hz) { if (!hz) {
dev_dbg(host->dev, "set mclk to 0\n"); 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; return;
} }
if (host->timing != timing)
timing_changed = true;
else
timing_changed = false;
flags = readl(host->base + MSDC_INTEN); flags = readl(host->base + MSDC_INTEN);
sdr_clr_bits(host->base + MSDC_INTEN, flags); sdr_clr_bits(host->base + MSDC_INTEN, flags);
if (host->dev_comp->clk_div_bits == 8) 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, sdr_set_field(host->base + tune_reg,
MSDC_PAD_TUNE_CMDRRDLY, MSDC_PAD_TUNE_CMDRRDLY,
host->hs400_cmd_int_delay); 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, dev_dbg(host->dev, "sclk: %d, timing: %d\n", mmc->actual_clock,
timing); 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) static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq)
{ {
struct mmc_host *mmc = mmc_from_priv(host);
unsigned long flags; unsigned long flags;
bool hsq_req_done;
/* /*
* No need check the return value of cancel_delayed_work, as only ONE * 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); 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); spin_lock_irqsave(&host->lock, flags);
host->mrq = NULL; host->mrq = NULL;
spin_unlock_irqrestore(&host->lock, flags); 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); msdc_unprepare_data(host, mrq->data);
if (host->error) if (host->error)
msdc_reset_hw(host); msdc_reset_hw(host);
mmc_request_done(mmc_from_priv(host), mrq); mmc_request_done(mmc, mrq);
if (host->dev_comp->recheck_sdio_irq) if (host->dev_comp->recheck_sdio_irq)
msdc_recheck_sdio_irq(host); 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); struct msdc_host *host = mmc_priv(mmc);
host->error = 0; host->error = 0;
WARN_ON(host->mrq); WARN_ON(!host->hsq_en && host->mrq);
host->mrq = mrq; host->mrq = mrq;
if (mrq->data) if (mrq->data)
@ -1704,6 +1818,17 @@ static void msdc_init_hw(struct msdc_host *host)
reset_control_deassert(host->reset); 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 */ /* Configure to MMC/SD mode, clock free running */
sdr_set_bits(host->base + MSDC_CFG, MSDC_CFG_MODE | MSDC_CFG_CKPDN); 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); sdr_set_bits(host->base + EMMC50_CFG0, EMMC50_CFG_CFCSTS_SEL);
if (host->dev_comp->stop_clk_fix) { if (host->dev_comp->stop_clk_fix) {
sdr_set_field(host->base + MSDC_PATCH_BIT1, if (host->dev_comp->stop_dly_sel)
MSDC_PATCH_BIT1_STOP_DLY, 3); sdr_set_field(host->base + MSDC_PATCH_BIT1,
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, sdr_clr_bits(host->base + SDC_FIFO_CFG,
SDC_FIFO_CFG_WRVALIDSEL); SDC_FIFO_CFG_WRVALIDSEL);
sdr_clr_bits(host->base + SDC_FIFO_CFG, 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) static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
{ {
struct msdc_host *host = mmc_priv(mmc); 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, sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_INT_DAT_LATCH_CK_SEL,
host->latch_ck); host->latch_ck);
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL); msdc_set_data_sample_edge(host, true);
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
for (i = 0; i < host->tuning_step; i++) { for (i = 0; i < host->tuning_step; i++) {
msdc_set_data_delay(host, i); msdc_set_data_delay(host, i);
ret = mmc_send_tuning(mmc, opcode, NULL); 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)) (final_rise_delay.start == 0 && final_rise_delay.maxlen >= 4))
goto skip_fall; goto skip_fall;
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL); msdc_set_data_sample_edge(host, false);
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
for (i = 0; i < host->tuning_step; i++) { for (i = 0; i < host->tuning_step; i++) {
msdc_set_data_delay(host, i); msdc_set_data_delay(host, i);
ret = mmc_send_tuning(mmc, opcode, NULL); ret = mmc_send_tuning(mmc, opcode, NULL);
@ -2237,12 +2381,10 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
skip_fall: skip_fall:
final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen); final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
if (final_maxlen == final_rise_delay.maxlen) { if (final_maxlen == final_rise_delay.maxlen) {
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL); msdc_set_data_sample_edge(host, true);
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
final_delay = final_rise_delay.final_phase; final_delay = final_rise_delay.final_phase;
} else { } else {
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL); msdc_set_data_sample_edge(host, false);
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
final_delay = final_fall_delay.final_phase; final_delay = final_fall_delay.final_phase;
} }
msdc_set_data_delay(host, final_delay); 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); host->latch_ck);
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
sdr_clr_bits(host->base + MSDC_IOCON, msdc_set_data_sample_edge(host, true);
MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL);
for (i = 0; i < host->tuning_step; i++) { for (i = 0; i < host->tuning_step; i++) {
msdc_set_cmd_delay(host, i); msdc_set_cmd_delay(host, i);
msdc_set_data_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; goto skip_fall;
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
sdr_set_bits(host->base + MSDC_IOCON, msdc_set_data_sample_edge(host, false);
MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL);
for (i = 0; i < host->tuning_step; i++) { for (i = 0; i < host->tuning_step; i++) {
msdc_set_cmd_delay(host, i); msdc_set_cmd_delay(host, i);
msdc_set_data_delay(host, i); msdc_set_data_delay(host, i);
@ -2298,13 +2438,11 @@ static int msdc_tune_together(struct mmc_host *mmc, u32 opcode)
final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen); final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
if (final_maxlen == final_rise_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_RSPL);
sdr_clr_bits(host->base + MSDC_IOCON, msdc_set_data_sample_edge(host, true);
MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL);
final_delay = final_rise_delay.final_phase; final_delay = final_rise_delay.final_phase;
} else { } else {
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL); sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
sdr_set_bits(host->base + MSDC_IOCON, msdc_set_data_sample_edge(host, false);
MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL);
final_delay = final_fall_delay.final_phase; 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) { if (host->dev_comp->data_tune && host->dev_comp->async_fifo) {
ret = msdc_tune_together(mmc, opcode); ret = msdc_tune_together(mmc, opcode);
if (host->hs400_mode) { if (host->hs400_mode) {
sdr_clr_bits(host->base + MSDC_IOCON, msdc_set_data_sample_edge(host, true);
MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL);
msdc_set_data_delay(host, 0); msdc_set_data_delay(host, 0);
} }
goto tune_done; goto tune_done;
@ -2727,7 +2864,6 @@ static int msdc_drv_probe(struct platform_device *pdev)
{ {
struct mmc_host *mmc; struct mmc_host *mmc;
struct msdc_host *host; struct msdc_host *host;
struct resource *res;
int ret; int ret;
if (!pdev->dev.of_node) { if (!pdev->dev.of_node) {
@ -2736,77 +2872,64 @@ static int msdc_drv_probe(struct platform_device *pdev)
} }
/* Allocate MMC host for this device */ /* 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) if (!mmc)
return -ENOMEM; return -ENOMEM;
host = mmc_priv(mmc); host = mmc_priv(mmc);
ret = mmc_of_parse(mmc); ret = mmc_of_parse(mmc);
if (ret) if (ret)
goto host_free; return ret;
host->base = devm_platform_ioremap_resource(pdev, 0); host->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(host->base)) { if (IS_ERR(host->base))
ret = PTR_ERR(host->base); return PTR_ERR(host->base);
goto host_free;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 1); host->top_base = devm_platform_ioremap_resource(pdev, 1);
if (res) { if (IS_ERR(host->top_base))
host->top_base = devm_ioremap_resource(&pdev->dev, res); host->top_base = NULL;
if (IS_ERR(host->top_base))
host->top_base = NULL;
}
ret = mmc_regulator_get_supply(mmc); ret = mmc_regulator_get_supply(mmc);
if (ret) if (ret)
goto host_free; return ret;
ret = msdc_of_clock_parse(pdev, host); ret = msdc_of_clock_parse(pdev, host);
if (ret) if (ret)
goto host_free; return ret;
host->reset = devm_reset_control_get_optional_exclusive(&pdev->dev, host->reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
"hrst"); "hrst");
if (IS_ERR(host->reset)) { if (IS_ERR(host->reset))
ret = PTR_ERR(host->reset); return PTR_ERR(host->reset);
goto host_free;
}
/* only eMMC has crypto property */ /* only eMMC has crypto property */
if (!(mmc->caps2 & MMC_CAP2_NO_MMC)) { if (!(mmc->caps2 & MMC_CAP2_NO_MMC)) {
host->crypto_clk = devm_clk_get_optional(&pdev->dev, "crypto"); host->crypto_clk = devm_clk_get_optional(&pdev->dev, "crypto");
if (IS_ERR(host->crypto_clk)) if (IS_ERR(host->crypto_clk))
host->crypto_clk = NULL; return PTR_ERR(host->crypto_clk);
else else if (host->crypto_clk)
mmc->caps2 |= MMC_CAP2_CRYPTO; mmc->caps2 |= MMC_CAP2_CRYPTO;
} }
host->irq = platform_get_irq(pdev, 0); host->irq = platform_get_irq(pdev, 0);
if (host->irq < 0) { if (host->irq < 0)
ret = host->irq; return host->irq;
goto host_free;
}
host->pinctrl = devm_pinctrl_get(&pdev->dev); host->pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(host->pinctrl)) { if (IS_ERR(host->pinctrl))
ret = PTR_ERR(host->pinctrl); return dev_err_probe(&pdev->dev, PTR_ERR(host->pinctrl),
dev_err(&pdev->dev, "Cannot find pinctrl!\n"); "Cannot find pinctrl");
goto host_free;
}
host->pins_default = pinctrl_lookup_state(host->pinctrl, "default"); host->pins_default = pinctrl_lookup_state(host->pinctrl, "default");
if (IS_ERR(host->pins_default)) { if (IS_ERR(host->pins_default)) {
ret = PTR_ERR(host->pins_default);
dev_err(&pdev->dev, "Cannot find pinctrl default!\n"); 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"); host->pins_uhs = pinctrl_lookup_state(host->pinctrl, "state_uhs");
if (IS_ERR(host->pins_uhs)) { if (IS_ERR(host->pins_uhs)) {
ret = PTR_ERR(host->pins_uhs);
dev_err(&pdev->dev, "Cannot find pinctrl uhs!\n"); dev_err(&pdev->dev, "Cannot find pinctrl uhs!\n");
goto host_free; return PTR_ERR(host->pins_uhs);
} }
/* Support for SDIO eint irq ? */ /* Support for SDIO eint irq ? */
@ -2885,7 +3008,7 @@ static int msdc_drv_probe(struct platform_device *pdev)
ret = msdc_ungate_clock(host); ret = msdc_ungate_clock(host);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Cannot ungate clocks!\n"); dev_err(&pdev->dev, "Cannot ungate clocks!\n");
goto release_mem; goto release_clk;
} }
msdc_init_hw(host); msdc_init_hw(host);
@ -2895,20 +3018,33 @@ static int msdc_drv_probe(struct platform_device *pdev)
GFP_KERNEL); GFP_KERNEL);
if (!host->cq_host) { if (!host->cq_host) {
ret = -ENOMEM; ret = -ENOMEM;
goto host_free; goto release;
} }
host->cq_host->caps |= CQHCI_TASK_DESC_SZ_128; host->cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
host->cq_host->mmio = host->base + 0x800; host->cq_host->mmio = host->base + 0x800;
host->cq_host->ops = &msdc_cmdq_ops; host->cq_host->ops = &msdc_cmdq_ops;
ret = cqhci_init(host->cq_host, mmc, true); ret = cqhci_init(host->cq_host, mmc, true);
if (ret) if (ret)
goto host_free; goto release;
mmc->max_segs = 128; mmc->max_segs = 128;
/* cqhci 16bit length */ /* cqhci 16bit length */
/* 0 size, means 65536 so we don't have to -1 here */ /* 0 size, means 65536 so we don't have to -1 here */
mmc->max_seg_size = 64 * 1024; mmc->max_seg_size = 64 * 1024;
/* Reduce CIT to 0x40 that corresponds to 2.35us */ /* Reduce CIT to 0x40 that corresponds to 2.35us */
msdc_cqe_cit_cal(host, 2350); 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, ret = devm_request_irq(&pdev->dev, host->irq, msdc_irq,
@ -2929,9 +3065,10 @@ static int msdc_drv_probe(struct platform_device *pdev)
end: end:
pm_runtime_disable(host->dev); pm_runtime_disable(host->dev);
release: release:
platform_set_drvdata(pdev, NULL);
msdc_deinit_hw(host); msdc_deinit_hw(host);
release_clk:
msdc_gate_clock(host); msdc_gate_clock(host);
platform_set_drvdata(pdev, NULL);
release_mem: release_mem:
if (host->dma.gpd) if (host->dma.gpd)
dma_free_coherent(&pdev->dev, dma_free_coherent(&pdev->dev,
@ -2939,11 +3076,8 @@ static int msdc_drv_probe(struct platform_device *pdev)
host->dma.gpd, host->dma.gpd_addr); host->dma.gpd, host->dma.gpd_addr);
if (host->dma.bd) if (host->dma.bd)
dma_free_coherent(&pdev->dev, dma_free_coherent(&pdev->dev,
MAX_BD_NUM * sizeof(struct mt_bdma_desc), MAX_BD_NUM * sizeof(struct mt_bdma_desc),
host->dma.bd, host->dma.bd_addr); host->dma.bd, host->dma.bd_addr);
host_free:
mmc_free_host(mmc);
return ret; return ret;
} }
@ -2968,9 +3102,7 @@ static void msdc_drv_remove(struct platform_device *pdev)
2 * sizeof(struct mt_gpdma_desc), 2 * sizeof(struct mt_gpdma_desc),
host->dma.gpd, host->dma.gpd_addr); host->dma.gpd, host->dma.gpd_addr);
dma_free_coherent(&pdev->dev, MAX_BD_NUM * sizeof(struct mt_bdma_desc), dma_free_coherent(&pdev->dev, MAX_BD_NUM * sizeof(struct mt_bdma_desc),
host->dma.bd, host->dma.bd_addr); host->dma.bd, host->dma.bd_addr);
mmc_free_host(mmc);
} }
static void msdc_save_reg(struct msdc_host *host) 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); readl(host->top_base + EMMC_TOP_CMD);
host->save_para.emmc50_pad_ds_tune = host->save_para.emmc50_pad_ds_tune =
readl(host->top_base + 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 { } else {
host->save_para.pad_tune = readl(host->base + tune_reg); 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); struct mmc_host *mmc = mmc_from_priv(host);
u32 tune_reg = host->dev_comp->pad_tune_reg; 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.msdc_cfg, host->base + MSDC_CFG);
writel(host->save_para.iocon, host->base + MSDC_IOCON); writel(host->save_para.iocon, host->base + MSDC_IOCON);
writel(host->save_para.sdc_cfg, host->base + SDC_CFG); 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); host->top_base + EMMC_TOP_CMD);
writel(host->save_para.emmc50_pad_ds_tune, writel(host->save_para.emmc50_pad_ds_tune,
host->top_base + 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 { } else {
writel(host->save_para.pad_tune, host->base + tune_reg); 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 mmc_host *mmc = dev_get_drvdata(dev);
struct msdc_host *host = mmc_priv(mmc); struct msdc_host *host = mmc_priv(mmc);
if (host->hsq_en)
mmc_hsq_suspend(mmc);
msdc_save_reg(host); msdc_save_reg(host);
if (sdio_irq_claimed(mmc)) { 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); pinctrl_select_state(host->pinctrl, host->pins_uhs);
enable_irq(host->irq); enable_irq(host->irq);
} }
if (host->hsq_en)
mmc_hsq_resume(mmc);
return 0; return 0;
} }
@ -3112,7 +3264,7 @@ static const struct dev_pm_ops msdc_dev_pm_ops = {
static struct platform_driver mt_msdc_driver = { static struct platform_driver mt_msdc_driver = {
.probe = msdc_drv_probe, .probe = msdc_drv_probe,
.remove_new = msdc_drv_remove, .remove = msdc_drv_remove,
.driver = { .driver = {
.name = "mtk-msdc", .name = "mtk-msdc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -819,7 +819,7 @@ MODULE_DEVICE_TABLE(of, mvsdio_dt_ids);
static struct platform_driver mvsd_driver = { static struct platform_driver mvsd_driver = {
.probe = mvsd_probe, .probe = mvsd_probe,
.remove_new = mvsd_remove, .remove = mvsd_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -1225,7 +1225,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume);
static struct platform_driver mxcmci_driver = { static struct platform_driver mxcmci_driver = {
.probe = mxcmci_probe, .probe = mxcmci_probe,
.remove_new = mxcmci_remove, .remove = mxcmci_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -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 = { static struct platform_driver mxs_mmc_driver = {
.probe = mxs_mmc_probe, .probe = mxs_mmc_probe,
.remove_new = mxs_mmc_remove, .remove = mxs_mmc_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -1554,7 +1554,7 @@ MODULE_DEVICE_TABLE(of, mmc_omap_match);
static struct platform_driver mmc_omap_driver = { static struct platform_driver mmc_omap_driver = {
.probe = mmc_omap_probe, .probe = mmc_omap_probe,
.remove_new = mmc_omap_remove, .remove = mmc_omap_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -2121,7 +2121,7 @@ static const struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
static struct platform_driver omap_hsmmc_driver = { static struct platform_driver omap_hsmmc_driver = {
.probe = omap_hsmmc_probe, .probe = omap_hsmmc_probe,
.remove_new = omap_hsmmc_remove, .remove = omap_hsmmc_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -692,7 +692,7 @@ static struct platform_driver owl_mmc_driver = {
.of_match_table = owl_mmc_of_match, .of_match_table = owl_mmc_of_match,
}, },
.probe = owl_mmc_probe, .probe = owl_mmc_probe,
.remove_new = owl_mmc_remove, .remove = owl_mmc_remove,
}; };
module_platform_driver(owl_mmc_driver); module_platform_driver(owl_mmc_driver);

View File

@ -810,7 +810,7 @@ static void pxamci_remove(struct platform_device *pdev)
static struct platform_driver pxamci_driver = { static struct platform_driver pxamci_driver = {
.probe = pxamci_probe, .probe = pxamci_probe,
.remove_new = pxamci_remove, .remove = pxamci_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -613,7 +613,7 @@ static struct platform_driver renesas_internal_dmac_sdhi_driver = {
.of_match_table = renesas_sdhi_internal_dmac_of_match, .of_match_table = renesas_sdhi_internal_dmac_of_match,
}, },
.probe = renesas_sdhi_internal_dmac_probe, .probe = renesas_sdhi_internal_dmac_probe,
.remove_new = renesas_sdhi_remove, .remove = renesas_sdhi_remove,
}; };
module_platform_driver(renesas_internal_dmac_sdhi_driver); module_platform_driver(renesas_internal_dmac_sdhi_driver);

View File

@ -471,7 +471,7 @@ static struct platform_driver renesas_sys_dmac_sdhi_driver = {
.of_match_table = renesas_sdhi_sys_dmac_of_match, .of_match_table = renesas_sdhi_sys_dmac_of_match,
}, },
.probe = renesas_sdhi_sys_dmac_probe, .probe = renesas_sdhi_sys_dmac_probe,
.remove_new = renesas_sdhi_remove, .remove = renesas_sdhi_remove,
}; };
module_platform_driver(renesas_sys_dmac_sdhi_driver); module_platform_driver(renesas_sys_dmac_sdhi_driver);

View File

@ -1591,7 +1591,7 @@ MODULE_DEVICE_TABLE(platform, rtsx_pci_sdmmc_ids);
static struct platform_driver rtsx_pci_sdmmc_driver = { static struct platform_driver rtsx_pci_sdmmc_driver = {
.probe = rtsx_pci_sdmmc_drv_probe, .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, .id_table = rtsx_pci_sdmmc_ids,
.driver = { .driver = {
.name = DRV_NAME_RTSX_PCI_SDMMC, .name = DRV_NAME_RTSX_PCI_SDMMC,

View File

@ -1453,7 +1453,7 @@ MODULE_DEVICE_TABLE(platform, rtsx_usb_sdmmc_ids);
static struct platform_driver rtsx_usb_sdmmc_driver = { static struct platform_driver rtsx_usb_sdmmc_driver = {
.probe = rtsx_usb_sdmmc_drv_probe, .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, .id_table = rtsx_usb_sdmmc_ids,
.driver = { .driver = {
.name = "rtsx_usb_sdmmc", .name = "rtsx_usb_sdmmc",

View File

@ -1080,7 +1080,7 @@ static struct platform_driver sdhci_acpi_driver = {
.pm = &sdhci_acpi_pm_ops, .pm = &sdhci_acpi_pm_ops,
}, },
.probe = sdhci_acpi_probe, .probe = sdhci_acpi_probe,
.remove_new = sdhci_acpi_remove, .remove = sdhci_acpi_remove,
}; };
module_platform_driver(sdhci_acpi_driver); module_platform_driver(sdhci_acpi_driver);

View File

@ -328,7 +328,7 @@ static struct platform_driver sdhci_bcm_kona_driver = {
.of_match_table = sdhci_bcm_kona_of_match, .of_match_table = sdhci_bcm_kona_of_match,
}, },
.probe = sdhci_bcm_kona_probe, .probe = sdhci_bcm_kona_probe,
.remove_new = sdhci_bcm_kona_remove, .remove = sdhci_bcm_kona_remove,
}; };
module_platform_driver(sdhci_bcm_kona_driver); module_platform_driver(sdhci_bcm_kona_driver);

View File

@ -545,7 +545,7 @@ static struct platform_driver sdhci_brcmstb_driver = {
.of_match_table = of_match_ptr(sdhci_brcm_of_match), .of_match_table = of_match_ptr(sdhci_brcm_of_match),
}, },
.probe = sdhci_brcmstb_probe, .probe = sdhci_brcmstb_probe,
.remove_new = sdhci_pltfm_remove, .remove = sdhci_pltfm_remove,
.shutdown = sdhci_brcmstb_shutdown, .shutdown = sdhci_brcmstb_shutdown,
}; };

View File

@ -608,7 +608,7 @@ static struct platform_driver sdhci_cdns_driver = {
.of_match_table = sdhci_cdns_match, .of_match_table = sdhci_cdns_match,
}, },
.probe = sdhci_cdns_probe, .probe = sdhci_cdns_probe,
.remove_new = sdhci_pltfm_remove, .remove = sdhci_pltfm_remove,
}; };
module_platform_driver(sdhci_cdns_driver); module_platform_driver(sdhci_cdns_driver);

View File

@ -106,7 +106,7 @@ static struct platform_driver sdhci_dove_driver = {
.of_match_table = sdhci_dove_of_match_table, .of_match_table = sdhci_dove_of_match_table,
}, },
.probe = sdhci_dove_probe, .probe = sdhci_dove_probe,
.remove_new = sdhci_pltfm_remove, .remove = sdhci_pltfm_remove,
}; };
module_platform_driver(sdhci_dove_driver); module_platform_driver(sdhci_dove_driver);

View File

@ -30,7 +30,8 @@
#include "sdhci-esdhc.h" #include "sdhci-esdhc.h"
#include "cqhci.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_CTRL_D3CD 0x08
#define ESDHC_BURST_LEN_EN_INCR (1 << 27) #define ESDHC_BURST_LEN_EN_INCR (1 << 27)
/* VENDOR SPEC register */ /* VENDOR SPEC register */
@ -238,6 +239,7 @@ struct esdhc_platform_data {
struct esdhc_soc_data { struct esdhc_soc_data {
u32 flags; u32 flags;
u32 quirks;
}; };
static const struct esdhc_soc_data esdhc_imx25_data = { 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_HAVE_CAP1 | ESDHC_FLAG_HS200
| ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400 | ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400
| ESDHC_FLAG_STATE_LOST_IN_LPMODE, | ESDHC_FLAG_STATE_LOST_IN_LPMODE,
.quirks = SDHCI_QUIRK_NO_LED,
}; };
static struct esdhc_soc_data usdhc_imxrt1050_data = { static struct esdhc_soc_data usdhc_imxrt1050_data = {
.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200, | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200,
.quirks = SDHCI_QUIRK_NO_LED,
}; };
static struct esdhc_soc_data usdhc_imx8qxp_data = { 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_HS400 | ESDHC_FLAG_HS400_ES
| ESDHC_FLAG_STATE_LOST_IN_LPMODE | ESDHC_FLAG_STATE_LOST_IN_LPMODE
| ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME, | ESDHC_FLAG_CLK_RATE_LOST_IN_PM_RUNTIME,
.quirks = SDHCI_QUIRK_NO_LED,
}; };
static struct esdhc_soc_data usdhc_imx8mm_data = { 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_HAVE_CAP1 | ESDHC_FLAG_HS200
| ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES
| ESDHC_FLAG_STATE_LOST_IN_LPMODE, | ESDHC_FLAG_STATE_LOST_IN_LPMODE,
.quirks = SDHCI_QUIRK_NO_LED,
}; };
struct pltfm_imx_data { 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 */ /* use maximum timeout counter */
esdhc_clrset_le(host, ESDHC_SYS_CTRL_DTOCV_MASK, esdhc_clrset_le(host, ESDHC_SYS_CTRL_DTOCV_MASK,
esdhc_is_usdhc(imx_data) ? 0xF : 0xE, esdhc_is_usdhc(imx_data) ? 0xF0000 : 0xE0000,
SDHCI_TIMEOUT_CONTROL); ESDHC_SYSTEM_CONTROL);
} }
static u32 esdhc_cqhci_irq(struct sdhci_host *host, u32 intmask) 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; 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 = { static struct sdhci_ops sdhci_esdhc_ops = {
.read_l = esdhc_readl_le, .read_l = esdhc_readl_le,
.read_w = esdhc_readw_le, .read_w = esdhc_readw_le,
@ -1420,6 +1437,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
.reset = esdhc_reset, .reset = esdhc_reset,
.irq = esdhc_cqhci_irq, .irq = esdhc_cqhci_irq,
.dump_vendor_regs = esdhc_dump_debug_regs, .dump_vendor_regs = esdhc_dump_debug_regs,
.hw_reset = esdhc_hw_reset,
}; };
static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { 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); writel(tmp, host->ioaddr + ESDHC_TUNING_CTRL);
} else if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { } 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 * or ROM code, so clear this bit here to make sure
* the manual tuning can work. * 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. * 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(). * in the call to mmc_of_parse().
*/ */
if (of_property_read_bool(np, "wp-gpios")) 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); imx_data->socdata = device_get_match_data(&pdev->dev);
host->quirks |= imx_data->socdata->quirks;
if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0); 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, .pm = &sdhci_esdhc_pmops,
}, },
.probe = sdhci_esdhc_imx_probe, .probe = sdhci_esdhc_imx_probe,
.remove_new = sdhci_esdhc_imx_remove, .remove = sdhci_esdhc_imx_remove,
}; };
module_platform_driver(sdhci_esdhc_imx_driver); module_platform_driver(sdhci_esdhc_imx_driver);

View File

@ -512,7 +512,7 @@ static struct platform_driver sdhci_esdhc_mcf_driver = {
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,
}, },
.probe = sdhci_esdhc_mcf_probe, .probe = sdhci_esdhc_mcf_probe,
.remove_new = sdhci_esdhc_mcf_remove, .remove = sdhci_esdhc_mcf_remove,
}; };
module_platform_driver(sdhci_esdhc_mcf_driver); module_platform_driver(sdhci_esdhc_mcf_driver);

View File

@ -424,7 +424,7 @@ static struct platform_driver sdhci_iproc_driver = {
.pm = &sdhci_pltfm_pmops, .pm = &sdhci_pltfm_pmops,
}, },
.probe = sdhci_iproc_probe, .probe = sdhci_iproc_probe,
.remove_new = sdhci_pltfm_remove, .remove = sdhci_pltfm_remove,
.shutdown = sdhci_iproc_shutdown, .shutdown = sdhci_iproc_shutdown,
}; };
module_platform_driver(sdhci_iproc_driver); module_platform_driver(sdhci_iproc_driver);

View File

@ -335,7 +335,7 @@ static struct platform_driver sdhci_milbeaut_driver = {
.of_match_table = mlb_dt_ids, .of_match_table = mlb_dt_ids,
}, },
.probe = sdhci_milbeaut_probe, .probe = sdhci_milbeaut_probe,
.remove_new = sdhci_milbeaut_remove, .remove = sdhci_milbeaut_remove,
}; };
module_platform_driver(sdhci_milbeaut_driver); module_platform_driver(sdhci_milbeaut_driver);

View File

@ -2601,7 +2601,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
sdhci_msm_handle_pwr_irq(host, 0); 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. * in GIC.
*/ */
mb(); mb();
@ -2753,7 +2753,7 @@ static const struct dev_pm_ops sdhci_msm_pm_ops = {
static struct platform_driver sdhci_msm_driver = { static struct platform_driver sdhci_msm_driver = {
.probe = sdhci_msm_probe, .probe = sdhci_msm_probe,
.remove_new = sdhci_msm_remove, .remove = sdhci_msm_remove,
.driver = { .driver = {
.name = "sdhci_msm", .name = "sdhci_msm",
.of_match_table = sdhci_msm_dt_match, .of_match_table = sdhci_msm_dt_match,

View File

@ -85,7 +85,7 @@ static struct platform_driver npcm_sdhci_driver = {
.pm = &sdhci_pltfm_pmops, .pm = &sdhci_pltfm_pmops,
}, },
.probe = npcm_sdhci_probe, .probe = npcm_sdhci_probe,
.remove_new = sdhci_pltfm_remove, .remove = sdhci_pltfm_remove,
}; };
module_platform_driver(npcm_sdhci_driver); module_platform_driver(npcm_sdhci_driver);

View File

@ -76,6 +76,8 @@
#define FREQSEL_225M_200M 0x7 #define FREQSEL_225M_200M 0x7
#define PHY_DLL_TIMEOUT_MS 100 #define PHY_DLL_TIMEOUT_MS 100
#define SDHCI_HW_RST_EN BIT(4)
/* Default settings for ZynqMP Clock Phases */ /* Default settings for ZynqMP Clock Phases */
#define ZYNQMP_ICLK_PHASE {0, 63, 63, 0, 63, 0, 0, 183, 54, 0, 0} #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} #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, static int sdhci_arasan_voltage_switch(struct mmc_host *mmc,
struct mmc_ios *ios) struct mmc_ios *ios)
{ {
@ -505,6 +522,7 @@ static const struct sdhci_ops sdhci_arasan_ops = {
.reset = sdhci_arasan_reset, .reset = sdhci_arasan_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling, .set_uhs_signaling = sdhci_set_uhs_signaling,
.set_power = sdhci_set_power_and_bus_voltage, .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) 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, .pm = &sdhci_arasan_dev_pm_ops,
}, },
.probe = sdhci_arasan_probe, .probe = sdhci_arasan_probe,
.remove_new = sdhci_arasan_remove, .remove = sdhci_arasan_remove,
}; };
module_platform_driver(sdhci_arasan_driver); module_platform_driver(sdhci_arasan_driver);

View File

@ -519,7 +519,7 @@ static struct platform_driver aspeed_sdhci_driver = {
.of_match_table = aspeed_sdhci_of_match, .of_match_table = aspeed_sdhci_of_match,
}, },
.probe = aspeed_sdhci_probe, .probe = aspeed_sdhci_probe,
.remove_new = aspeed_sdhci_remove, .remove = aspeed_sdhci_remove,
}; };
static int aspeed_sdc_probe(struct platform_device *pdev) 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, .of_match_table = aspeed_sdc_of_match,
}, },
.probe = aspeed_sdc_probe, .probe = aspeed_sdc_probe,
.remove_new = aspeed_sdc_remove, .remove = aspeed_sdc_remove,
}; };
#if defined(CONFIG_MMC_SDHCI_OF_ASPEED_TEST) #if defined(CONFIG_MMC_SDHCI_OF_ASPEED_TEST)

View File

@ -471,7 +471,7 @@ static struct platform_driver sdhci_at91_driver = {
.pm = &sdhci_at91_dev_pm_ops, .pm = &sdhci_at91_dev_pm_ops,
}, },
.probe = sdhci_at91_probe, .probe = sdhci_at91_probe,
.remove_new = sdhci_at91_remove, .remove = sdhci_at91_remove,
}; };
module_platform_driver(sdhci_at91_driver); module_platform_driver(sdhci_at91_driver);

View File

@ -1626,7 +1626,7 @@ static struct platform_driver sdhci_dwcmshc_driver = {
.pm = &dwcmshc_pmops, .pm = &dwcmshc_pmops,
}, },
.probe = dwcmshc_probe, .probe = dwcmshc_probe,
.remove_new = dwcmshc_remove, .remove = dwcmshc_remove,
}; };
module_platform_driver(sdhci_dwcmshc_driver); module_platform_driver(sdhci_dwcmshc_driver);

View File

@ -1521,7 +1521,7 @@ static struct platform_driver sdhci_esdhc_driver = {
.pm = &esdhc_of_dev_pm_ops, .pm = &esdhc_of_dev_pm_ops,
}, },
.probe = sdhci_esdhc_probe, .probe = sdhci_esdhc_probe,
.remove_new = sdhci_pltfm_remove, .remove = sdhci_pltfm_remove,
}; };
module_platform_driver(sdhci_esdhc_driver); module_platform_driver(sdhci_esdhc_driver);

View File

@ -85,7 +85,7 @@ static struct platform_driver sdhci_hlwd_driver = {
.pm = &sdhci_pltfm_pmops, .pm = &sdhci_pltfm_pmops,
}, },
.probe = sdhci_hlwd_probe, .probe = sdhci_hlwd_probe,
.remove_new = sdhci_pltfm_remove, .remove = sdhci_pltfm_remove,
}; };
module_platform_driver(sdhci_hlwd_driver); module_platform_driver(sdhci_hlwd_driver);

View File

@ -305,7 +305,7 @@ static struct platform_driver sdhci_ma35_driver = {
.of_match_table = sdhci_ma35_dt_ids, .of_match_table = sdhci_ma35_dt_ids,
}, },
.probe = ma35_probe, .probe = ma35_probe,
.remove_new = ma35_remove, .remove = ma35_remove,
}; };
module_platform_driver(sdhci_ma35_driver); module_platform_driver(sdhci_ma35_driver);

View File

@ -255,7 +255,7 @@ static struct platform_driver sdhci_sparx5_driver = {
.pm = &sdhci_pltfm_pmops, .pm = &sdhci_pltfm_pmops,
}, },
.probe = sdhci_sparx5_probe, .probe = sdhci_sparx5_probe,
.remove_new = sdhci_pltfm_remove, .remove = sdhci_pltfm_remove,
}; };
module_platform_driver(sdhci_sparx5_driver); module_platform_driver(sdhci_sparx5_driver);

View File

@ -1478,7 +1478,7 @@ static const struct dev_pm_ops sdhci_omap_dev_pm_ops = {
static struct platform_driver sdhci_omap_driver = { static struct platform_driver sdhci_omap_driver = {
.probe = sdhci_omap_probe, .probe = sdhci_omap_probe,
.remove_new = sdhci_omap_remove, .remove = sdhci_omap_remove,
.driver = { .driver = {
.name = "sdhci-omap", .name = "sdhci-omap",
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -40,6 +40,7 @@
#include "sdhci.h" #include "sdhci.h"
#include "sdhci-cqhci.h" #include "sdhci-cqhci.h"
#include "sdhci-pci.h" #include "sdhci-pci.h"
#include "sdhci-uhs2.h"
static void sdhci_pci_hw_reset(struct sdhci_host *host); static void sdhci_pci_hw_reset(struct sdhci_host *host);
@ -2181,7 +2182,10 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot)
if (scratch == (u32)-1) if (scratch == (u32)-1)
dead = 1; dead = 1;
sdhci_remove_host(slot->host, dead); 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) if (slot->chip->fixes && slot->chip->fixes->remove_slot)
slot->chip->fixes->remove_slot(slot, dead); slot->chip->fixes->remove_slot(slot, dead);
@ -2189,6 +2193,16 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot)
sdhci_free_host(slot->host); 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) static void sdhci_pci_runtime_pm_allow(struct device *dev)
{ {
pm_suspend_ignore_children(dev, 1); pm_suspend_ignore_children(dev, 1);

View File

@ -18,6 +18,7 @@
#include "sdhci-cqhci.h" #include "sdhci-cqhci.h"
#include "sdhci-pci.h" #include "sdhci-pci.h"
#include "cqhci.h" #include "cqhci.h"
#include "sdhci-uhs2.h"
/* Genesys Logic extra registers */ /* Genesys Logic extra registers */
#define SDHCI_GLI_9750_WT 0x800 #define SDHCI_GLI_9750_WT 0x800
@ -139,13 +140,49 @@
#define PCI_GLI_9755_PLLSSC 0x68 #define PCI_GLI_9755_PLLSSC 0x68
#define PCI_GLI_9755_PLLSSC_PPM GENMASK(15, 0) #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_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_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 0x78
#define PCI_GLI_9755_MISC_SSC_OFF BIT(26) #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 0x510
#define SDHCI_GLI_9767_GM_BURST_SIZE_AXI_ALWAYS_SET BIT(8) #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_CORE_PWR_D3_OFF BIT(21)
#define PCIE_GLI_9767_SCR_CFG_RST_DATA_LINK_DOWN BIT(30) #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 0x91C
#define PCIE_GLI_9767_SDHC_CAP_SDEI_RESULT BIT(5) #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_EXPRESS_CTL_SD_EXPRESS_MODE BIT(1)
#define PCIE_GLI_9767_SD_DATA_MULTI_CTL 0x944 #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 GENMASK(23, 16)
#define PCIE_GLI_9767_SD_DATA_MULTI_CTL_DISCONNECT_TIME_VALUE 0x64 #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 0x950
#define PCIE_GLI_9767_NORMAL_ERR_INT_STATUS_REG2_SDEI_COMPLETE BIT(0) #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 0x958
#define PCIE_GLI_9767_NORMAL_ERR_INT_SIGNAL_EN_REG2_SDEI_COMPLETE_SIGNAL_EN BIT(0) #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 #define GLI_MAX_TUNING_LOOP 40
/* Genesys Logic chipset */ /* Genesys Logic chipset */
@ -779,6 +851,203 @@ static void gl9755_hw_setting(struct sdhci_pci_slot *slot)
gl9755_wt_off(pdev); 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) static inline void gl9767_vhs_read(struct pci_dev *pdev)
{ {
u32 vhs_enable; 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); 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) static void gli_set_9767(struct sdhci_host *host)
{ {
u32 value; 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_readl(host, SDHCI_GLI_9767_GM_BURST_SIZE);
value &= ~SDHCI_GLI_9767_GM_BURST_SIZE_AXI_ALWAYS_SET; value &= ~SDHCI_GLI_9767_GM_BURST_SIZE_AXI_ALWAYS_SET;
sdhci_writel(host, value, SDHCI_GLI_9767_GM_BURST_SIZE); 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) 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) static void sdhci_gl9767_reset(struct sdhci_host *host, u8 mask)
{ {
sdhci_reset(host, 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); gli_set_9767(host);
} }
@ -1076,6 +1412,86 @@ static int gl9767_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios)
return 0; 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) static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot)
{ {
struct sdhci_host *host = slot->host; 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); gli_pcie_enable_msi(slot);
slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO; slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
sdhci_enable_v4_mode(host); sdhci_enable_v4_mode(host);
gl9755_vendor_init(host);
return 0; 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->caps2 |= MMC_CAP2_SD_EXP;
host->mmc_host_ops.init_sd_express = gl9767_init_sd_express; host->mmc_host_ops.init_sd_express = gl9767_init_sd_express;
sdhci_enable_v4_mode(host); sdhci_enable_v4_mode(host);
gl9767_vendor_init(host);
return 0; return 0;
} }
@ -1534,17 +1952,24 @@ static const struct sdhci_ops sdhci_gl9755_ops = {
.read_w = sdhci_gli_readw, .read_w = sdhci_gli_readw,
.read_b = sdhci_gli_readb, .read_b = sdhci_gli_readb,
.set_clock = sdhci_gl9755_set_clock, .set_clock = sdhci_gl9755_set_clock,
.set_power = gl9755_set_power,
.enable_dma = sdhci_pci_enable_dma, .enable_dma = sdhci_pci_enable_dma,
.set_bus_width = sdhci_set_bus_width, .set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset, .reset = sdhci_gl9755_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling, .set_uhs_signaling = sdhci_set_uhs_signaling,
.voltage_switch = sdhci_gli_voltage_switch, .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 = { const struct sdhci_pci_fixes sdhci_gl9755 = {
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_BROKEN_DDR50, .quirks2 = SDHCI_QUIRK2_BROKEN_DDR50,
.probe_slot = gli_probe_slot_gl9755, .probe_slot = gli_probe_slot_gl9755,
.add_host = sdhci_pci_uhs2_add_host,
.remove_host = sdhci_pci_uhs2_remove_host,
.ops = &sdhci_gl9755_ops, .ops = &sdhci_gl9755_ops,
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
.resume = sdhci_pci_gli_resume, .resume = sdhci_pci_gli_resume,
@ -1607,12 +2032,20 @@ static const struct sdhci_ops sdhci_gl9767_ops = {
.reset = sdhci_gl9767_reset, .reset = sdhci_gl9767_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling, .set_uhs_signaling = sdhci_set_uhs_signaling,
.voltage_switch = sdhci_gl9767_voltage_switch, .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 = { const struct sdhci_pci_fixes sdhci_gl9767 = {
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_BROKEN_DDR50, .quirks2 = SDHCI_QUIRK2_BROKEN_DDR50,
.probe_slot = gli_probe_slot_gl9767, .probe_slot = gli_probe_slot_gl9767,
.add_host = sdhci_pci_uhs2_add_host,
.remove_host = sdhci_pci_uhs2_remove_host,
.ops = &sdhci_gl9767_ops, .ops = &sdhci_gl9767_ops,
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
.resume = sdhci_pci_gli_resume, .resume = sdhci_pci_gli_resume,

View File

@ -145,6 +145,7 @@ struct sdhci_pci_fixes {
int (*probe_slot) (struct sdhci_pci_slot *); int (*probe_slot) (struct sdhci_pci_slot *);
int (*add_host) (struct sdhci_pci_slot *); int (*add_host) (struct sdhci_pci_slot *);
void (*remove_slot) (struct sdhci_pci_slot *, int); void (*remove_slot) (struct sdhci_pci_slot *, int);
void (*remove_host) (struct sdhci_pci_slot *, int);
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
int (*suspend) (struct sdhci_pci_chip *); 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; 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 #ifdef CONFIG_PM_SLEEP
int sdhci_pci_resume_host(struct sdhci_pci_chip *chip); int sdhci_pci_resume_host(struct sdhci_pci_chip *chip);
#endif #endif

View File

@ -236,7 +236,7 @@ static struct platform_driver pic32_sdhci_driver = {
.of_match_table = of_match_ptr(pic32_sdhci_id_table), .of_match_table = of_match_ptr(pic32_sdhci_id_table),
}, },
.probe = pic32_sdhci_probe, .probe = pic32_sdhci_probe,
.remove_new = pic32_sdhci_remove, .remove = pic32_sdhci_remove,
}; };
module_platform_driver(pic32_sdhci_driver); module_platform_driver(pic32_sdhci_driver);

View File

@ -351,7 +351,7 @@ static struct platform_driver sdhci_pxav2_driver = {
.pm = &sdhci_pltfm_pmops, .pm = &sdhci_pltfm_pmops,
}, },
.probe = sdhci_pxav2_probe, .probe = sdhci_pxav2_probe,
.remove_new = sdhci_pltfm_remove, .remove = sdhci_pltfm_remove,
}; };
module_platform_driver(sdhci_pxav2_driver); module_platform_driver(sdhci_pxav2_driver);

View File

@ -568,7 +568,7 @@ static struct platform_driver sdhci_pxav3_driver = {
.pm = &sdhci_pxav3_pmops, .pm = &sdhci_pxav3_pmops,
}, },
.probe = sdhci_pxav3_probe, .probe = sdhci_pxav3_probe,
.remove_new = sdhci_pxav3_remove, .remove = sdhci_pxav3_remove,
}; };
module_platform_driver(sdhci_pxav3_driver); module_platform_driver(sdhci_pxav3_driver);

View File

@ -774,7 +774,7 @@ MODULE_DEVICE_TABLE(of, sdhci_s3c_dt_match);
static struct platform_driver sdhci_s3c_driver = { static struct platform_driver sdhci_s3c_driver = {
.probe = sdhci_s3c_probe, .probe = sdhci_s3c_probe,
.remove_new = sdhci_s3c_remove, .remove = sdhci_s3c_remove,
.id_table = sdhci_s3c_driver_ids, .id_table = sdhci_s3c_driver_ids,
.driver = { .driver = {
.name = "s3c-sdhci", .name = "s3c-sdhci",

View File

@ -182,7 +182,7 @@ static struct platform_driver sdhci_driver = {
.of_match_table = sdhci_spear_id_table, .of_match_table = sdhci_spear_id_table,
}, },
.probe = sdhci_probe, .probe = sdhci_probe,
.remove_new = sdhci_remove, .remove = sdhci_remove,
}; };
module_platform_driver(sdhci_driver); module_platform_driver(sdhci_driver);

View File

@ -975,7 +975,7 @@ static const struct dev_pm_ops sdhci_sprd_pm_ops = {
static struct platform_driver sdhci_sprd_driver = { static struct platform_driver sdhci_sprd_driver = {
.probe = sdhci_sprd_probe, .probe = sdhci_sprd_probe,
.remove_new = sdhci_sprd_remove, .remove = sdhci_sprd_remove,
.driver = { .driver = {
.name = "sdhci_sprd_r11", .name = "sdhci_sprd_r11",
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -507,7 +507,7 @@ MODULE_DEVICE_TABLE(of, st_sdhci_match);
static struct platform_driver sdhci_st_driver = { static struct platform_driver sdhci_st_driver = {
.probe = sdhci_st_probe, .probe = sdhci_st_probe,
.remove_new = sdhci_st_remove, .remove = sdhci_st_remove,
.driver = { .driver = {
.name = "sdhci-st", .name = "sdhci-st",
.probe_type = PROBE_PREFER_ASYNCHRONOUS, .probe_type = PROBE_PREFER_ASYNCHRONOUS,

View File

@ -1930,7 +1930,7 @@ static struct platform_driver sdhci_tegra_driver = {
.pm = &sdhci_tegra_dev_pm_ops, .pm = &sdhci_tegra_dev_pm_ops,
}, },
.probe = sdhci_tegra_probe, .probe = sdhci_tegra_probe,
.remove_new = sdhci_tegra_remove, .remove = sdhci_tegra_remove,
}; };
module_platform_driver(sdhci_tegra_driver); module_platform_driver(sdhci_tegra_driver);

File diff suppressed because it is too large Load Diff

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

View File

@ -734,7 +734,7 @@ static struct platform_driver sdhci_xenon_driver = {
.pm = &sdhci_xenon_dev_pm_ops, .pm = &sdhci_xenon_dev_pm_ops,
}, },
.probe = xenon_probe, .probe = xenon_probe,
.remove_new = xenon_remove, .remove = xenon_remove,
}; };
module_platform_driver(sdhci_xenon_driver); module_platform_driver(sdhci_xenon_driver);

View File

@ -23,7 +23,7 @@
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/bug.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/mmc/mmc.h> #include <linux/mmc/mmc.h>
@ -47,8 +47,6 @@
static unsigned int debug_quirks = 0; static unsigned int debug_quirks = 0;
static unsigned int debug_quirks2; 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); static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd);
void sdhci_dumpregs(struct sdhci_host *host) 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) if (host->ops->dump_vendor_regs)
host->ops->dump_vendor_regs(host); 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); 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; 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) 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); 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) { if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
struct mmc_host *mmc = host->mmc; struct mmc_host *mmc = host->mmc;
@ -246,6 +248,7 @@ static bool sdhci_do_reset(struct sdhci_host *host, u8 mask)
return true; return true;
} }
EXPORT_SYMBOL_GPL(sdhci_do_reset);
static void sdhci_reset_for_all(struct sdhci_host *host) static void sdhci_reset_for_all(struct sdhci_host *host)
{ {
@ -501,14 +504,15 @@ static inline void sdhci_led_deactivate(struct sdhci_host *host)
#endif #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) unsigned long timeout)
{ {
if (sdhci_data_line_cmd(mrq->cmd)) if (sdhci_data_line_cmd(mrq->cmd))
mod_timer(&host->data_timer, timeout); mod_timer(&host->data_timer, timeout);
else else
mod_timer(&host->timer, timeout); mod_timer(&host->timer, timeout);
} }
EXPORT_SYMBOL_GPL(sdhci_mod_timer);
static void sdhci_del_timer(struct sdhci_host *host, struct mmc_request *mrq) 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); __sdhci_set_timeout(host, cmd);
} }
static void sdhci_initialize_data(struct sdhci_host *host, void sdhci_initialize_data(struct sdhci_host *host, struct mmc_data *data)
struct mmc_data *data)
{ {
WARN_ON(host->data); WARN_ON(host->data);
@ -1089,6 +1092,7 @@ static void sdhci_initialize_data(struct sdhci_host *host,
host->data_early = 0; host->data_early = 0;
host->data->bytes_xfered = 0; host->data->bytes_xfered = 0;
} }
EXPORT_SYMBOL_GPL(sdhci_initialize_data);
static inline void sdhci_set_block_info(struct sdhci_host *host, static inline void sdhci_set_block_info(struct sdhci_host *host,
struct mmc_data *data) 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)) { if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
struct scatterlist *sg; struct scatterlist *sg;
unsigned int length_mask, offset_mask; 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); 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); 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); 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) && return (!(host->flags & SDHCI_DEVICE_DEAD) &&
((mrq->cmd && mrq->cmd->error) || ((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) || (mrq->data && mrq->data->stop && mrq->data->stop->error) ||
(host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))); (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) 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); 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) if (host->cmd && host->cmd->mrq == mrq)
host->cmd = NULL; 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)) if (!sdhci_has_requests(host))
sdhci_led_deactivate(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); __sdhci_finish_mrq(host, mrq);
queue_work(host->complete_wq, &host->complete_work); 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_command *data_cmd = host->data_cmd;
struct mmc_data *data = host->data; struct mmc_data *data = host->data;
@ -1563,7 +1576,9 @@ static void __sdhci_finish_data(struct sdhci_host *host, bool sw_data_timeout)
* conditions. * conditions.
*/ */
if (data->error) { 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); sdhci_reset_for(host, REQUEST_ERROR);
else else
sdhci_reset_for(host, REQUEST_ERROR_DATA_ONLY); 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; data->bytes_xfered = 0;
else else
data->bytes_xfered = data->blksz * data->blocks; 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 - * Need to send CMD12 if -
@ -1718,8 +1741,8 @@ static bool sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
return true; 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) struct mmc_command *cmd, bool present)
{ {
if (!present || host->flags & SDHCI_DEVICE_DEAD) { if (!present || host->flags & SDHCI_DEVICE_DEAD) {
cmd->error = -ENOMEDIUM; cmd->error = -ENOMEDIUM;
@ -1728,6 +1751,7 @@ static bool sdhci_present_error(struct sdhci_host *host,
return false; return false;
} }
EXPORT_SYMBOL_GPL(sdhci_present_error);
static bool sdhci_send_command_retry(struct sdhci_host *host, static bool sdhci_send_command_retry(struct sdhci_host *host,
struct mmc_command *cmd, struct mmc_command *cmd,
@ -1874,6 +1898,12 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)
case MMC_TIMING_MMC_HS400: case MMC_TIMING_MMC_HS400:
preset = sdhci_readw(host, SDHCI_PRESET_FOR_HS400); preset = sdhci_readw(host, SDHCI_PRESET_FOR_HS400);
break; 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: default:
pr_warn("%s: Invalid UHS-I mode selected\n", pr_warn("%s: Invalid UHS-I mode selected\n",
mmc_hostname(host->mmc)); mmc_hostname(host->mmc));
@ -2058,41 +2088,46 @@ static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode,
sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
} }
unsigned short sdhci_get_vdd_value(unsigned short vdd)
{
switch (1 << vdd) {
case MMC_VDD_165_195:
/*
* Without a regulator, SDHCI does not support 2.0v
* so we only get here if the driver deliberately
* added the 2.0v range to ocr_avail. Map it to 1.8v
* for the purpose of turning on the power.
*/
case MMC_VDD_20_21:
return SDHCI_POWER_180;
case MMC_VDD_29_30:
case MMC_VDD_30_31:
return SDHCI_POWER_300;
case MMC_VDD_32_33:
case MMC_VDD_33_34:
/*
* 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:
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, void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
unsigned short vdd) unsigned short vdd)
{ {
u8 pwr = 0; u8 pwr = 0;
if (mode != MMC_POWER_OFF) { if (mode != MMC_POWER_OFF) {
switch (1 << vdd) { pwr = sdhci_get_vdd_value(vdd);
case MMC_VDD_165_195: if (!pwr) {
/*
* Without a regulator, SDHCI does not support 2.0v
* so we only get here if the driver deliberately
* added the 2.0v range to ocr_avail. Map it to 1.8v
* for the purpose of turning on the power.
*/
case MMC_VDD_20_21:
pwr = SDHCI_POWER_180;
break;
case MMC_VDD_29_30:
case MMC_VDD_30_31:
pwr = SDHCI_POWER_300;
break;
case MMC_VDD_32_33:
case MMC_VDD_33_34:
/*
* 3.4 ~ 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;
default:
WARN(1, "%s: Invalid vdd %#x\n", WARN(1, "%s: Invalid vdd %#x\n",
mmc_hostname(host->mmc), vdd); 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); (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); 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. * 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); sdhci_enable_preset_value(host, false);
if (!ios->clock || ios->clock != host->clock) { if (!ios->clock || ios->clock != host->clock) {
turning_on_clk = ios->clock && !host->clock;
host->ops->set_clock(host, ios->clock); host->ops->set_clock(host, ios->clock);
host->clock = 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; 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) if (host->ops->set_power)
host->ops->set_power(host, ios->power_mode, ios->vdd); host->ops->set_power(host, ios->power_mode, ios->vdd);
@ -2934,7 +2977,7 @@ int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
} }
EXPORT_SYMBOL_GPL(sdhci_execute_tuning); 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 */ /* Host Controller v3.00 defines preset value registers */
if (host->version < SDHCI_SPEC_300) 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; host->preset_enabled = enable;
} }
} }
EXPORT_SYMBOL_GPL(sdhci_enable_preset_value);
static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq, static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
int err) 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) static bool sdhci_request_done(struct sdhci_host *host)
{ {
unsigned long flags; unsigned long flags;
@ -3119,48 +3210,7 @@ static bool sdhci_request_done(struct sdhci_host *host)
sdhci_set_mrq_done(host, mrq); sdhci_set_mrq_done(host, mrq);
} }
if (data && data->host_cookie == COOKIE_MAPPED) { sdhci_request_done_dma(host, mrq);
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;
}
} }
host->mrqs_done[i] = NULL; host->mrqs_done[i] = NULL;
@ -3175,7 +3225,7 @@ static bool sdhci_request_done(struct sdhci_host *host)
return false; 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, struct sdhci_host *host = container_of(work, struct sdhci_host,
complete_work); complete_work);
@ -3183,6 +3233,7 @@ static void sdhci_complete_work(struct work_struct *work)
while (!sdhci_request_done(host)) while (!sdhci_request_done(host))
; ;
} }
EXPORT_SYMBOL_GPL(sdhci_complete_work);
static void sdhci_timeout_timer(struct timer_list *t) static void sdhci_timeout_timer(struct timer_list *t)
{ {
@ -3644,7 +3695,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
return result; 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 sdhci_host *host = dev_id;
struct mmc_command *cmd; struct mmc_command *cmd;
@ -3674,6 +3725,7 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
return IRQ_HANDLED; 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->max_timeout_count = 0xE;
host->complete_work_fn = sdhci_complete_work;
host->thread_irq_fn = sdhci_thread_irq;
return host; return host;
} }
@ -4810,7 +4865,7 @@ int __sdhci_add_host(struct sdhci_host *host)
if (!host->complete_wq) if (!host->complete_wq)
return -ENOMEM; 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->timer, sdhci_timeout_timer, 0);
timer_setup(&host->data_timer, sdhci_timeout_data_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); 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); IRQF_SHARED, mmc_hostname(mmc), host);
if (ret) { if (ret) {
pr_err("%s: Failed to request IRQ %d: %d\n", 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