mirror of
https://github.com/LuckfoxTECH/luckfox-pico.git
synced 2026-01-19 09:52:31 +01:00
project:build.sh: Added fastboot support; custom modifications to U-Boot and kernel implemented using patches.
project:cfg:BoardConfig_IPC: Added fastboot BoardConfig file and firmware post-scripts, distinguishing between the BoardConfigs for Luckfox Pico Pro and Luckfox Pico Max. project:app: Added fastboot_client and rk_smart_door for quick boot applications; updated rkipc app to adapt to the latest media library. media:samples: Added more usage examples. media:rockit: Fixed bugs; removed support for retrieving data frames from VPSS. media:isp: Updated rkaiq library and related tools to support connection to RKISP_Tuner. sysdrv:Makefile: Added support for compiling drv_ko on Luckfox Pico Ultra W using Ubuntu; added support for custom root filesystem. sysdrv:tools:board: Updated Buildroot optional mirror sources, updated some software versions, and stored device tree files and configuration files that undergo multiple modifications for U-Boot and kernel separately. sysdrv:source:mcu: Used RISC-V MCU SDK with RT-Thread system, mainly for initializing camera AE during quick boot. sysdrv:source:uboot: Added support for fastboot; added high baud rate DDR bin for serial firmware upgrades. sysdrv:source:kernel: Upgraded to version 5.10.160; increased NPU frequency for RV1106G3; added support for fastboot. Signed-off-by: luckfox-eng29 <eng29@luckfox.com>
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
#
|
||||
# Makefile for the kernel mmc device drivers.
|
||||
#
|
||||
#subdir-ccflags-y := -DDEBUG
|
||||
|
||||
obj-$(CONFIG_MMC) += core/
|
||||
obj-$(subst m,y,$(CONFIG_MMC)) += host/
|
||||
|
||||
@@ -172,7 +172,7 @@ static inline int mmc_blk_part_switch(struct mmc_card *card,
|
||||
unsigned int part_type);
|
||||
static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
|
||||
struct mmc_card *card,
|
||||
int disable_multi,
|
||||
int recovery_mode,
|
||||
struct mmc_queue *mq);
|
||||
static void mmc_blk_hsq_req_done(struct mmc_request *mrq);
|
||||
|
||||
@@ -415,7 +415,7 @@ static int mmc_blk_ioctl_copy_to_user(struct mmc_ioc_cmd __user *ic_ptr,
|
||||
static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms,
|
||||
u32 *resp_errs)
|
||||
{
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms > 2000 ? 2000 : timeout_ms);
|
||||
int err = 0;
|
||||
u32 status;
|
||||
|
||||
@@ -1085,6 +1085,11 @@ static void mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
|
||||
nr = blk_rq_sectors(req);
|
||||
|
||||
do {
|
||||
unsigned int erase_arg = card->erase_arg;
|
||||
|
||||
if (mmc_card_broken_sd_discard(card))
|
||||
erase_arg = SD_ERASE_ARG;
|
||||
|
||||
err = 0;
|
||||
if (card->quirks & MMC_QUIRK_INAND_CMD38) {
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
@@ -1095,7 +1100,7 @@ static void mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
|
||||
card->ext_csd.generic_cmd6_time);
|
||||
}
|
||||
if (!err)
|
||||
err = mmc_erase(card, from, nr, card->erase_arg);
|
||||
err = mmc_erase(card, from, nr, erase_arg);
|
||||
} while (err == -EIO && !mmc_blk_reset(md, card->host, type));
|
||||
if (err)
|
||||
status = BLK_STS_IOERR;
|
||||
@@ -1263,7 +1268,7 @@ static void mmc_blk_eval_resp_error(struct mmc_blk_request *brq)
|
||||
}
|
||||
|
||||
static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
|
||||
int disable_multi, bool *do_rel_wr_p,
|
||||
int recovery_mode, bool *do_rel_wr_p,
|
||||
bool *do_data_tag_p)
|
||||
{
|
||||
struct mmc_blk_data *md = mq->blkdata;
|
||||
@@ -1329,12 +1334,12 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
|
||||
brq->data.blocks--;
|
||||
|
||||
/*
|
||||
* After a read error, we redo the request one sector
|
||||
* After a read error, we redo the request one (native) sector
|
||||
* at a time in order to accurately determine which
|
||||
* sectors can be read successfully.
|
||||
*/
|
||||
if (disable_multi)
|
||||
brq->data.blocks = 1;
|
||||
if (recovery_mode)
|
||||
brq->data.blocks = queue_physical_block_size(mq->queue) >> 9;
|
||||
|
||||
/*
|
||||
* Some controllers have HW issues while operating
|
||||
@@ -1460,8 +1465,7 @@ void mmc_blk_cqe_recovery(struct mmc_queue *mq)
|
||||
err = mmc_cqe_recovery(host);
|
||||
if (err)
|
||||
mmc_blk_reset(mq->blkdata, host, MMC_BLK_CQE_RECOVERY);
|
||||
else
|
||||
mmc_blk_reset_success(mq->blkdata, MMC_BLK_CQE_RECOVERY);
|
||||
mmc_blk_reset_success(mq->blkdata, MMC_BLK_CQE_RECOVERY);
|
||||
|
||||
pr_debug("%s: CQE recovery done\n", mmc_hostname(host));
|
||||
}
|
||||
@@ -1552,7 +1556,7 @@ static int mmc_blk_cqe_issue_rw_rq(struct mmc_queue *mq, struct request *req)
|
||||
|
||||
static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
|
||||
struct mmc_card *card,
|
||||
int disable_multi,
|
||||
int recovery_mode,
|
||||
struct mmc_queue *mq)
|
||||
{
|
||||
u32 readcmd, writecmd;
|
||||
@@ -1561,7 +1565,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
|
||||
struct mmc_blk_data *md = mq->blkdata;
|
||||
bool do_rel_wr, do_data_tag;
|
||||
|
||||
mmc_blk_data_prep(mq, mqrq, disable_multi, &do_rel_wr, &do_data_tag);
|
||||
mmc_blk_data_prep(mq, mqrq, recovery_mode, &do_rel_wr, &do_data_tag);
|
||||
|
||||
brq->mrq.cmd = &brq->cmd;
|
||||
|
||||
@@ -1652,7 +1656,7 @@ static int mmc_blk_fix_state(struct mmc_card *card, struct request *req)
|
||||
|
||||
#define MMC_READ_SINGLE_RETRIES 2
|
||||
|
||||
/* Single sector read during recovery */
|
||||
/* Single (native) sector read during recovery */
|
||||
static void mmc_blk_read_single(struct mmc_queue *mq, struct request *req)
|
||||
{
|
||||
struct mmc_queue_req *mqrq = req_to_mmc_queue_req(req);
|
||||
@@ -1660,6 +1664,7 @@ static void mmc_blk_read_single(struct mmc_queue *mq, struct request *req)
|
||||
struct mmc_card *card = mq->card;
|
||||
struct mmc_host *host = card->host;
|
||||
blk_status_t error = BLK_STS_OK;
|
||||
size_t bytes_per_read = queue_physical_block_size(mq->queue);
|
||||
|
||||
do {
|
||||
u32 status;
|
||||
@@ -1694,13 +1699,13 @@ static void mmc_blk_read_single(struct mmc_queue *mq, struct request *req)
|
||||
else
|
||||
error = BLK_STS_OK;
|
||||
|
||||
} while (blk_update_request(req, error, 512));
|
||||
} while (blk_update_request(req, error, bytes_per_read));
|
||||
|
||||
return;
|
||||
|
||||
error_exit:
|
||||
mrq->data->bytes_xfered = 0;
|
||||
blk_update_request(req, BLK_STS_IOERR, 512);
|
||||
blk_update_request(req, BLK_STS_IOERR, bytes_per_read);
|
||||
/* Let it try the remaining request again */
|
||||
if (mqrq->retries > MMC_MAX_RETRIES - 1)
|
||||
mqrq->retries = MMC_MAX_RETRIES - 1;
|
||||
@@ -1776,8 +1781,15 @@ static void mmc_blk_mq_rw_recovery(struct mmc_queue *mq, struct request *req)
|
||||
* bytes transferred to zero in that case.
|
||||
*/
|
||||
err = __mmc_send_status(card, &status, 0);
|
||||
if (err || mmc_blk_status_error(req, status))
|
||||
if (err || mmc_blk_status_error(req, status)) {
|
||||
brq->data.bytes_xfered = 0;
|
||||
if (mmc_card_sd(card) && !mmc_card_removed(card)) {
|
||||
mmc_blk_reset_success(mq->blkdata, type);
|
||||
if (!mmc_blk_reset(md, card->host, type))
|
||||
return;
|
||||
pr_err("%s: pre recovery failed!\n", req->rq_disk->disk_name);
|
||||
}
|
||||
}
|
||||
|
||||
mmc_retune_release(card->host);
|
||||
|
||||
@@ -1842,10 +1854,9 @@ static void mmc_blk_mq_rw_recovery(struct mmc_queue *mq, struct request *req)
|
||||
return;
|
||||
}
|
||||
|
||||
/* FIXME: Missing single sector read for large sector size */
|
||||
if (!mmc_large_sector(card) && rq_data_dir(req) == READ &&
|
||||
brq->data.blocks > 1) {
|
||||
/* Read one sector at a time */
|
||||
if (rq_data_dir(req) == READ && brq->data.blocks >
|
||||
queue_physical_block_size(mq->queue) >> 9) {
|
||||
/* Read one (native) sector at a time */
|
||||
mmc_blk_read_single(mq, req);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ struct mmc_fixup {
|
||||
#define EXT_CSD_REV_ANY (-1u)
|
||||
|
||||
#define CID_MANFID_SANDISK 0x2
|
||||
#define CID_MANFID_SANDISK_SD 0x3
|
||||
#define CID_MANFID_ATP 0x9
|
||||
#define CID_MANFID_TOSHIBA 0x11
|
||||
#define CID_MANFID_MICRON 0x13
|
||||
@@ -223,4 +224,9 @@ static inline int mmc_card_broken_hpi(const struct mmc_card *c)
|
||||
return c->quirks & MMC_QUIRK_BROKEN_HPI;
|
||||
}
|
||||
|
||||
static inline int mmc_card_broken_sd_discard(const struct mmc_card *c)
|
||||
{
|
||||
return c->quirks & MMC_QUIRK_BROKEN_SD_DISCARD;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1131,7 +1131,13 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
|
||||
mmc_power_cycle(host, ocr);
|
||||
} else {
|
||||
bit = fls(ocr) - 1;
|
||||
ocr &= 3 << bit;
|
||||
/*
|
||||
* The bit variable represents the highest voltage bit set in
|
||||
* the OCR register.
|
||||
* To keep a range of 2 values (e.g. 3.2V/3.3V and 3.3V/3.4V),
|
||||
* we must shift the mask '3' with (bit - 1).
|
||||
*/
|
||||
ocr &= 3 << (bit - 1);
|
||||
if (bit != host->ios.vdd)
|
||||
dev_warn(mmc_dev(host), "exceeding card's volts\n");
|
||||
}
|
||||
@@ -1537,6 +1543,11 @@ void mmc_init_erase(struct mmc_card *card)
|
||||
card->pref_erase = 0;
|
||||
}
|
||||
|
||||
static bool is_trim_arg(unsigned int arg)
|
||||
{
|
||||
return (arg & MMC_TRIM_OR_DISCARD_ARGS) && arg != MMC_DISCARD_ARG;
|
||||
}
|
||||
|
||||
static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
|
||||
unsigned int arg, unsigned int qty)
|
||||
{
|
||||
@@ -1835,7 +1846,7 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
|
||||
!(card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (mmc_card_mmc(card) && (arg & MMC_TRIM_ARGS) &&
|
||||
if (mmc_card_mmc(card) && is_trim_arg(arg) &&
|
||||
!(card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
@@ -1865,7 +1876,7 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
|
||||
* identified by the card->eg_boundary flag.
|
||||
*/
|
||||
rem = card->erase_size - (from % card->erase_size);
|
||||
if ((arg & MMC_TRIM_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);
|
||||
from += rem;
|
||||
if ((err) || (to <= from))
|
||||
@@ -2061,7 +2072,7 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_set_blocklen);
|
||||
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
|
||||
static void mmc_hw_reset_for_init(struct mmc_host *host)
|
||||
{
|
||||
mmc_pwrseq_reset(host);
|
||||
@@ -2143,7 +2154,7 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
|
||||
* Some eMMCs (with VCCQ always on) may not be reset after power up, so
|
||||
* do a hardware reset if possible.
|
||||
*/
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
|
||||
mmc_hw_reset_for_init(host);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ static const unsigned int taac_mant[] = {
|
||||
/*
|
||||
* Given the decoded CSD structure, decode the raw CID to our CID structure.
|
||||
*/
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
|
||||
static int mmc_decode_cid(struct mmc_card *card)
|
||||
{
|
||||
u32 *resp = card->raw_cid;
|
||||
@@ -666,7 +666,7 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT
|
||||
#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
|
||||
static void *mmc_tb_map_ecsd(phys_addr_t start, size_t len)
|
||||
{
|
||||
int i;
|
||||
@@ -696,7 +696,7 @@ static int mmc_read_ext_csd(struct mmc_card *card)
|
||||
{
|
||||
u8 *ext_csd;
|
||||
int err;
|
||||
#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT
|
||||
#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
|
||||
void *ecsd;
|
||||
bool valid_ecsd = false;
|
||||
bool valid_reserved = false;
|
||||
@@ -707,7 +707,7 @@ static int mmc_read_ext_csd(struct mmc_card *card)
|
||||
if (!mmc_can_ext_csd(card))
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT
|
||||
#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
|
||||
mem = of_parse_phandle(dev->of_node, "memory-region-ecsd", 0);
|
||||
if (mem) {
|
||||
err = of_address_to_resource(mem, 0, ®);
|
||||
@@ -758,11 +758,11 @@ get_ecsd:
|
||||
|
||||
return err;
|
||||
}
|
||||
#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT
|
||||
#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
|
||||
decode:
|
||||
#endif
|
||||
err = mmc_decode_ext_csd(card, ext_csd);
|
||||
#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT
|
||||
#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
|
||||
if (!valid_ecsd)
|
||||
kfree(ext_csd);
|
||||
else
|
||||
@@ -777,7 +777,7 @@ decode:
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
|
||||
static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
|
||||
{
|
||||
u8 *bw_ext_csd;
|
||||
@@ -1120,7 +1120,7 @@ int mmc_select_bus_width(struct mmc_card *card)
|
||||
* compare ext_csd previously read in 1 bit mode
|
||||
* against ext_csd at new bus width
|
||||
*/
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
|
||||
if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
|
||||
err = mmc_compare_ext_csds(card, bus_width);
|
||||
else
|
||||
@@ -1462,9 +1462,13 @@ static int mmc_select_hs400es(struct mmc_card *card)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bump to HS timing and frequency. Some cards don't handle
|
||||
* SEND_STATUS reliably at the initial frequency.
|
||||
*/
|
||||
mmc_set_timing(host, MMC_TIMING_MMC_HS);
|
||||
/* Set clock immediately after changing timing */
|
||||
mmc_set_clock(host, card->ext_csd.hs_max_dtr);
|
||||
mmc_set_bus_speed(card);
|
||||
|
||||
err = mmc_switch_status(card, true);
|
||||
if (err)
|
||||
@@ -1527,7 +1531,7 @@ out_err:
|
||||
static int mmc_select_hs200(struct mmc_card *card)
|
||||
{
|
||||
struct mmc_host *host = card->host;
|
||||
unsigned int old_timing, old_signal_voltage;
|
||||
unsigned int old_timing, old_signal_voltage, old_clock;
|
||||
int err = -EINVAL;
|
||||
u8 val;
|
||||
|
||||
@@ -1558,8 +1562,17 @@ static int mmc_select_hs200(struct mmc_card *card)
|
||||
false, true);
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* Bump to HS timing and frequency. Some cards don't handle
|
||||
* SEND_STATUS reliably at the initial frequency.
|
||||
* NB: We can't move to full (HS200) speeds until after we've
|
||||
* successfully switched over.
|
||||
*/
|
||||
old_timing = host->ios.timing;
|
||||
old_clock = host->ios.clock;
|
||||
mmc_set_timing(host, MMC_TIMING_MMC_HS200);
|
||||
mmc_set_clock(card->host, card->ext_csd.hs_max_dtr);
|
||||
|
||||
/*
|
||||
* For HS200, CRC errors are not a reliable way to know the
|
||||
@@ -1572,8 +1585,10 @@ static int mmc_select_hs200(struct mmc_card *card)
|
||||
* mmc_select_timing() assumes timing has not changed if
|
||||
* it is a switch error.
|
||||
*/
|
||||
if (err == -EBADMSG)
|
||||
if (err == -EBADMSG) {
|
||||
mmc_set_clock(host, old_clock);
|
||||
mmc_set_timing(host, old_timing);
|
||||
}
|
||||
}
|
||||
err:
|
||||
if (err) {
|
||||
@@ -1665,7 +1680,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
* respond.
|
||||
* mmc_go_idle is needed for eMMC that are asleep
|
||||
*/
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
|
||||
mmc_go_idle(host);
|
||||
#endif
|
||||
|
||||
@@ -1712,7 +1727,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
card->ocr = ocr;
|
||||
card->type = MMC_TYPE_MMC;
|
||||
card->rca = 1;
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
|
||||
memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
|
||||
#endif
|
||||
}
|
||||
@@ -1745,7 +1760,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
err = mmc_decode_csd(card);
|
||||
if (err)
|
||||
goto free_card;
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
|
||||
err = mmc_decode_cid(card);
|
||||
if (err)
|
||||
goto free_card;
|
||||
@@ -1892,7 +1907,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
/*
|
||||
* Enable HPI feature (if supported)
|
||||
*/
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
|
||||
if (card->ext_csd.hpi) {
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_HPI_MGMT, 1,
|
||||
|
||||
@@ -145,7 +145,7 @@ int mmc_go_idle(struct mmc_host *host)
|
||||
* rules that must accommodate non-MMC slaves which this layer
|
||||
* won't even know about.
|
||||
*/
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
|
||||
if (!mmc_host_is_spi(host)) {
|
||||
mmc_set_chip_select(host, MMC_CS_HIGH);
|
||||
mmc_delay(1);
|
||||
@@ -157,7 +157,7 @@ int mmc_go_idle(struct mmc_host *host)
|
||||
|
||||
err = mmc_wait_for_cmd(host, &cmd, 0);
|
||||
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
|
||||
mmc_delay(1);
|
||||
|
||||
if (!mmc_host_is_spi(host)) {
|
||||
@@ -179,12 +179,12 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
|
||||
cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
|
||||
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
|
||||
|
||||
for (i = 100; i; i--) {
|
||||
for (i = 1000; i; i--) {
|
||||
err = mmc_wait_for_cmd(host, &cmd, 0);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT
|
||||
#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
|
||||
/* if we're just probing, do a single pass */
|
||||
if (ocr == 0)
|
||||
break;
|
||||
@@ -219,7 +219,7 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
|
||||
*/
|
||||
if (!ocr && !mmc_host_is_spi(host))
|
||||
cmd.arg = cmd.resp[0] | BIT(30);
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
|
||||
mmc_delay(1);
|
||||
#else
|
||||
udelay(1);
|
||||
|
||||
@@ -3195,7 +3195,8 @@ static int __mmc_test_register_dbgfs_file(struct mmc_card *card,
|
||||
struct mmc_test_dbgfs_file *df;
|
||||
|
||||
if (card->debugfs_root)
|
||||
debugfs_create_file(name, mode, card->debugfs_root, card, fops);
|
||||
file = debugfs_create_file(name, mode, card->debugfs_root,
|
||||
card, fops);
|
||||
|
||||
df = kmalloc(sizeof(*df), GFP_KERNEL);
|
||||
if (!df) {
|
||||
|
||||
@@ -101,6 +101,12 @@ static const struct mmc_fixup __maybe_unused mmc_blk_fixups[] = {
|
||||
MMC_FIXUP("V10016", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc,
|
||||
MMC_QUIRK_TRIM_BROKEN),
|
||||
|
||||
/*
|
||||
* Some SD cards reports discard support while they don't
|
||||
*/
|
||||
MMC_FIXUP(CID_NAME_ANY, CID_MANFID_SANDISK_SD, 0x5344, add_quirk_sd,
|
||||
MMC_QUIRK_BROKEN_SD_DISCARD),
|
||||
|
||||
END_FIXUP
|
||||
};
|
||||
|
||||
|
||||
@@ -857,7 +857,8 @@ try_again:
|
||||
* the CCS bit is set as well. We deliberately deviate from the spec in
|
||||
* regards to this, which allows UHS-I to be supported for SDSC cards.
|
||||
*/
|
||||
if (!mmc_host_is_spi(host) && rocr && (*rocr & 0x01000000)) {
|
||||
if (!mmc_host_is_spi(host) && (ocr & SD_OCR_S18R) &&
|
||||
rocr && (*rocr & SD_ROCR_S18A)) {
|
||||
err = mmc_set_uhs_voltage(host, pocr);
|
||||
if (err == -EAGAIN) {
|
||||
retries--;
|
||||
@@ -936,15 +937,16 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
|
||||
|
||||
/* Erase init depends on CSD and SSR */
|
||||
mmc_init_erase(card);
|
||||
|
||||
/*
|
||||
* Fetch switch information from card.
|
||||
*/
|
||||
err = mmc_read_switch(card);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch switch information from card. Note, sd3_bus_mode can change if
|
||||
* voltage switch outcome changes, so do this always.
|
||||
*/
|
||||
err = mmc_read_switch(card);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* For SPI, enable CRC as appropriate.
|
||||
* This CRC enable is located AFTER the reading of the
|
||||
@@ -1093,26 +1095,15 @@ retry:
|
||||
if (!v18_fixup_failed && !mmc_host_is_spi(host) && mmc_host_uhs(host) &&
|
||||
mmc_sd_card_using_v18(card) &&
|
||||
host->ios.signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
|
||||
/*
|
||||
* Re-read switch information in case it has changed since
|
||||
* oldcard was initialized.
|
||||
*/
|
||||
if (oldcard) {
|
||||
err = mmc_read_switch(card);
|
||||
if (err)
|
||||
goto free_card;
|
||||
}
|
||||
if (mmc_sd_card_using_v18(card)) {
|
||||
if (mmc_host_set_uhs_voltage(host) ||
|
||||
mmc_sd_init_uhs_card(card)) {
|
||||
v18_fixup_failed = true;
|
||||
mmc_power_cycle(host, ocr);
|
||||
if (!oldcard)
|
||||
mmc_remove_card(card);
|
||||
goto retry;
|
||||
}
|
||||
goto done;
|
||||
if (mmc_host_set_uhs_voltage(host) ||
|
||||
mmc_sd_init_uhs_card(card)) {
|
||||
v18_fixup_failed = true;
|
||||
mmc_power_cycle(host, ocr);
|
||||
if (!oldcard)
|
||||
mmc_remove_card(card);
|
||||
goto retry;
|
||||
}
|
||||
goto cont;
|
||||
}
|
||||
|
||||
/* Initialization sequence for UHS-I cards */
|
||||
@@ -1147,7 +1138,7 @@ retry:
|
||||
mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
|
||||
}
|
||||
}
|
||||
|
||||
cont:
|
||||
if (host->cqe_ops && !host->cqe_enabled) {
|
||||
err = host->cqe_ops->cqe_enable(host, card);
|
||||
if (!err) {
|
||||
@@ -1165,7 +1156,7 @@ retry:
|
||||
err = -EINVAL;
|
||||
goto free_card;
|
||||
}
|
||||
done:
|
||||
|
||||
host->card = card;
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
|
||||
cmd.arg = ocr;
|
||||
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
|
||||
|
||||
for (i = 100; i; i--) {
|
||||
for (i = 200; i; i--) {
|
||||
err = mmc_wait_for_app_cmd(host, NULL, &cmd);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
@@ -292,7 +292,8 @@ static void sdio_release_func(struct device *dev)
|
||||
{
|
||||
struct sdio_func *func = dev_to_sdio_func(dev);
|
||||
|
||||
sdio_free_func_cis(func);
|
||||
if (!(func->card->quirks & MMC_QUIRK_NONSTD_SDIO))
|
||||
sdio_free_func_cis(func);
|
||||
|
||||
kfree(func->info);
|
||||
kfree(func->tmpbuf);
|
||||
|
||||
@@ -1081,9 +1081,10 @@ config MMC_SDHCI_OMAP
|
||||
|
||||
config MMC_SDHCI_AM654
|
||||
tristate "Support for the SDHCI Controller in TI's AM654 SOCs"
|
||||
depends on MMC_SDHCI_PLTFM && OF && REGMAP_MMIO
|
||||
depends on MMC_SDHCI_PLTFM && OF
|
||||
select MMC_SDHCI_IO_ACCESSORS
|
||||
select MMC_CQHCI
|
||||
select REGMAP_MMIO
|
||||
help
|
||||
This selects the Secure Digital Host Controller Interface (SDHCI)
|
||||
support present in TI's AM654 SOCs. The controller supports
|
||||
|
||||
@@ -1097,8 +1097,9 @@ out5:
|
||||
if (host->platdata && host->platdata->cd_setup &&
|
||||
!(mmc->caps & MMC_CAP_NEEDS_POLL))
|
||||
host->platdata->cd_setup(mmc, 0);
|
||||
out_clk:
|
||||
|
||||
clk_disable_unprepare(host->clk);
|
||||
out_clk:
|
||||
clk_put(host->clk);
|
||||
out_irq:
|
||||
free_irq(host->irq, host);
|
||||
|
||||
@@ -277,6 +277,7 @@ static int octeon_mmc_probe(struct platform_device *pdev)
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Error populating slots\n");
|
||||
octeon_mmc_set_shared_power(host, 0);
|
||||
of_node_put(cn);
|
||||
goto error;
|
||||
}
|
||||
i++;
|
||||
|
||||
@@ -142,8 +142,10 @@ static int thunder_mmc_probe(struct pci_dev *pdev,
|
||||
continue;
|
||||
|
||||
ret = cvm_mmc_of_slot_probe(&host->slot_pdev[i]->dev, host);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
of_node_put(child_node);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
@@ -124,6 +124,8 @@ void rv1106_sdmmc_put_lock(void)
|
||||
EXPORT_SYMBOL(rv1106_sdmmc_put_lock);
|
||||
#endif
|
||||
|
||||
#define RV1106_RAMDON_DATA_SIZE 508
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
static int dw_mci_req_show(struct seq_file *s, void *v)
|
||||
{
|
||||
@@ -239,7 +241,7 @@ static void dw_mci_wait_while_busy(struct dw_mci *host, u32 cmd_flags)
|
||||
* ...also allow sending for SDMMC_CMD_VOLT_SWITCH where busy is
|
||||
* expected.
|
||||
*/
|
||||
#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT
|
||||
#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
|
||||
if (host->slot->mmc->caps2 & MMC_CAP2_NO_SD &&
|
||||
host->slot->mmc->caps2 & MMC_CAP2_NO_SDIO)
|
||||
delay = 0;
|
||||
@@ -525,8 +527,7 @@ static void dw_mci_dmac_complete_dma(void *arg)
|
||||
tasklet_schedule(&host->tasklet);
|
||||
}
|
||||
|
||||
if (host->need_xfer_timer &&
|
||||
host->dir_status == DW_MCI_RECV_STATUS)
|
||||
if (host->need_xfer_timer)
|
||||
del_timer(&host->xfer_timer);
|
||||
}
|
||||
|
||||
@@ -739,7 +740,7 @@ static inline int dw_mci_prepare_desc32(struct dw_mci *host,
|
||||
if (host->is_rv1106_sd && (data->flags & MMC_DATA_WRITE)) {
|
||||
desc->des0 = desc_last->des0;
|
||||
desc->des2 = desc_last->des2;
|
||||
desc->des1 = 0x8; /* Random dirty data for last one desc */
|
||||
desc->des1 = RV1106_RAMDON_DATA_SIZE; /* Random dirty data for last one desc */
|
||||
desc_last = desc;
|
||||
}
|
||||
|
||||
@@ -1447,13 +1448,6 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||
return;
|
||||
}
|
||||
|
||||
if (host->is_rv1106_sd) {
|
||||
u32 reg;
|
||||
|
||||
readl_poll_timeout(host->regs + SDMMC_STATUS, reg,
|
||||
reg & BIT(2), USEC_PER_MSEC, 500 * USEC_PER_MSEC);
|
||||
}
|
||||
|
||||
spin_lock_bh(&host->lock);
|
||||
|
||||
if (host->is_rv1106_sd)
|
||||
@@ -1468,7 +1462,7 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
{
|
||||
struct dw_mci_slot *slot = mmc_priv(mmc);
|
||||
const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
|
||||
u32 regs;
|
||||
u32 regs, power_off_delay;
|
||||
int ret;
|
||||
|
||||
switch (ios->bus_width) {
|
||||
@@ -1507,6 +1501,15 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
|
||||
switch (ios->power_mode) {
|
||||
case MMC_POWER_UP:
|
||||
if (dw_mci_get_cd(mmc) && !IS_ERR_OR_NULL(slot->host->pinctrl)) {
|
||||
if (!pinctrl_select_state(slot->host->pinctrl, slot->host->idle_state)) {
|
||||
if (device_property_read_u32(slot->host->dev, "power-off-delay-ms",
|
||||
&power_off_delay))
|
||||
power_off_delay = 200;
|
||||
msleep(power_off_delay);
|
||||
}
|
||||
}
|
||||
|
||||
if (!IS_ERR(mmc->supply.vmmc)) {
|
||||
ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
|
||||
ios->vdd);
|
||||
@@ -1523,6 +1526,9 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
mci_writel(slot->host, PWREN, regs);
|
||||
break;
|
||||
case MMC_POWER_ON:
|
||||
if (!IS_ERR_OR_NULL(slot->host->pinctrl))
|
||||
pinctrl_select_state(slot->host->pinctrl, slot->host->normal_state);
|
||||
|
||||
if (!slot->host->vqmmc_enabled) {
|
||||
if (!IS_ERR(mmc->supply.vqmmc)) {
|
||||
ret = regulator_enable(mmc->supply.vqmmc);
|
||||
@@ -1537,9 +1543,11 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
slot->host->vqmmc_enabled = true;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
|
||||
/* Reset our state machine after powering on */
|
||||
dw_mci_ctrl_reset(slot->host,
|
||||
SDMMC_CTRL_ALL_RESET_FLAGS);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Adjust clock / bus width after power is up */
|
||||
@@ -1547,6 +1555,9 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
|
||||
break;
|
||||
case MMC_POWER_OFF:
|
||||
if (!IS_ERR_OR_NULL(slot->host->pinctrl))
|
||||
pinctrl_select_state(slot->host->pinctrl, slot->host->idle_state);
|
||||
|
||||
/* Turn clock off before power goes down */
|
||||
dw_mci_setup_bus(slot, false);
|
||||
|
||||
@@ -1859,6 +1870,9 @@ static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
|
||||
|
||||
WARN_ON(host->cmd || host->data);
|
||||
|
||||
if (host->need_xfer_timer)
|
||||
del_timer(&host->xfer_timer);
|
||||
|
||||
host->slot->mrq = NULL;
|
||||
host->mrq = NULL;
|
||||
if (!list_empty(&host->queue)) {
|
||||
@@ -2004,8 +2018,10 @@ static void dw_mci_set_xfer_timeout(struct dw_mci *host)
|
||||
host->bus_hz);
|
||||
|
||||
/* add a bit spare time */
|
||||
xfer_ms += 100;
|
||||
|
||||
if (host->dir_status == DW_MCI_RECV_STATUS)
|
||||
xfer_ms += 100;
|
||||
else
|
||||
xfer_ms += 2500;
|
||||
spin_lock_irqsave(&host->irq_lock, irqflags);
|
||||
if (!test_bit(EVENT_XFER_COMPLETE, &host->pending_events))
|
||||
mod_timer(&host->xfer_timer,
|
||||
@@ -2140,6 +2156,13 @@ static void dw_mci_tasklet_func(unsigned long priv)
|
||||
send_stop_abort(host, data);
|
||||
dw_mci_stop_dma(host);
|
||||
state = STATE_DATA_ERROR;
|
||||
if (host->dir_status == DW_MCI_SEND_STATUS) {
|
||||
data->bytes_xfered = 0;
|
||||
data->error = -ETIMEDOUT;
|
||||
host->data = NULL;
|
||||
dw_mci_request_end(host, mrq);
|
||||
goto unlock;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2151,8 +2174,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
|
||||
*/
|
||||
if (host->dir_status == DW_MCI_RECV_STATUS)
|
||||
dw_mci_set_drto(host);
|
||||
if (host->need_xfer_timer &&
|
||||
host->dir_status == DW_MCI_RECV_STATUS)
|
||||
if (host->need_xfer_timer)
|
||||
dw_mci_set_xfer_timeout(host);
|
||||
break;
|
||||
}
|
||||
@@ -2194,6 +2216,8 @@ static void dw_mci_tasklet_func(unsigned long priv)
|
||||
*/
|
||||
if (host->dir_status == DW_MCI_RECV_STATUS)
|
||||
dw_mci_set_drto(host);
|
||||
if (host->need_xfer_timer && host->dir_status == DW_MCI_SEND_STATUS)
|
||||
dw_mci_set_xfer_timeout(host);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2210,8 +2234,19 @@ static void dw_mci_tasklet_func(unsigned long priv)
|
||||
}
|
||||
|
||||
/* stop command for open-ended transfer*/
|
||||
if (data->stop)
|
||||
if (data->stop) {
|
||||
if (host->is_rv1106_sd && (data->flags & MMC_DATA_WRITE)) {
|
||||
int fifo_count;
|
||||
|
||||
if (readl_poll_timeout_atomic(host->regs + SDMMC_STATUS, fifo_count,
|
||||
((fifo_count >> 17) & 0x7FF) <= RV1106_RAMDON_DATA_SIZE / 4,
|
||||
0, 5000 * USEC_PER_MSEC))
|
||||
data->error = -ETIMEDOUT;
|
||||
udelay(1);
|
||||
dw_mci_reset(host);
|
||||
}
|
||||
send_stop_abort(host, data);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* If we don't have a command complete now we'll
|
||||
@@ -2742,8 +2777,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
|
||||
del_timer(&host->cto_timer);
|
||||
mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
|
||||
host->cmd_status = pending;
|
||||
if ((host->need_xfer_timer) &&
|
||||
host->dir_status == DW_MCI_RECV_STATUS)
|
||||
if (host->need_xfer_timer)
|
||||
del_timer(&host->xfer_timer);
|
||||
smp_wmb(); /* drain writebuffer */
|
||||
set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
|
||||
@@ -3262,6 +3296,22 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
host->pinctrl = devm_pinctrl_get(host->dev);
|
||||
if (!IS_ERR(host->pinctrl)) {
|
||||
host->normal_state = pinctrl_lookup_state(host->pinctrl, "normal");
|
||||
if (IS_ERR(host->normal_state))
|
||||
dev_warn(dev, "No normal pinctrl state\n");
|
||||
|
||||
host->idle_state = pinctrl_lookup_state(host->pinctrl, "idle");
|
||||
if (IS_ERR(host->idle_state))
|
||||
dev_warn(dev, "No idle pinctrl state\n");
|
||||
|
||||
if (!IS_ERR(host->normal_state) && !IS_ERR(host->idle_state))
|
||||
pinctrl_select_state(host->pinctrl, host->idle_state);
|
||||
else
|
||||
host->pinctrl = NULL;
|
||||
}
|
||||
|
||||
return pdata;
|
||||
}
|
||||
|
||||
@@ -3317,7 +3367,7 @@ int dw_mci_probe(struct dw_mci *host)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT
|
||||
#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT_MMC
|
||||
if (device_property_read_bool(host->dev, "no-sd") &&
|
||||
device_property_read_bool(host->dev, "no-sdio")) {
|
||||
if (readl_poll_timeout(host->regs + SDMMC_STATUS,
|
||||
|
||||
@@ -233,6 +233,9 @@ struct dw_mci {
|
||||
bool need_xfer_timer;
|
||||
struct timer_list xfer_timer;
|
||||
bool is_rv1106_sd;
|
||||
struct pinctrl *pinctrl;
|
||||
struct pinctrl_state *normal_state;
|
||||
struct pinctrl_state *idle_state;
|
||||
};
|
||||
|
||||
/* DMA ops for Internal/External DMAC interface */
|
||||
|
||||
@@ -236,6 +236,26 @@ static int jz4740_mmc_acquire_dma_channels(struct jz4740_mmc_host *host)
|
||||
return PTR_ERR(host->dma_rx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Limit the maximum segment size in any SG entry according to
|
||||
* the parameters of the DMA engine device.
|
||||
*/
|
||||
if (host->dma_tx) {
|
||||
struct device *dev = host->dma_tx->device->dev;
|
||||
unsigned int max_seg_size = dma_get_max_seg_size(dev);
|
||||
|
||||
if (max_seg_size < host->mmc->max_seg_size)
|
||||
host->mmc->max_seg_size = max_seg_size;
|
||||
}
|
||||
|
||||
if (host->dma_rx) {
|
||||
struct device *dev = host->dma_rx->device->dev;
|
||||
unsigned int max_seg_size = dma_get_max_seg_size(dev);
|
||||
|
||||
if (max_seg_size < host->mmc->max_seg_size)
|
||||
host->mmc->max_seg_size = max_seg_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1161,8 +1161,10 @@ static int meson_mmc_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
ret = device_reset_optional(&pdev->dev);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "device reset failed\n");
|
||||
if (ret) {
|
||||
dev_err_probe(&pdev->dev, ret, "device reset failed\n");
|
||||
goto free_host;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
host->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
|
||||
@@ -62,8 +62,8 @@ static int sdmmc_idma_validate_data(struct mmci_host *host,
|
||||
* excepted the last element which has no constraint on idmasize
|
||||
*/
|
||||
for_each_sg(data->sg, sg, data->sg_len - 1, i) {
|
||||
if (!IS_ALIGNED(data->sg->offset, sizeof(u32)) ||
|
||||
!IS_ALIGNED(data->sg->length, SDMMC_IDMA_BURST)) {
|
||||
if (!IS_ALIGNED(sg->offset, sizeof(u32)) ||
|
||||
!IS_ALIGNED(sg->length, SDMMC_IDMA_BURST)) {
|
||||
dev_err(mmc_dev(host->mmc),
|
||||
"unaligned scatterlist: ofst:%x length:%d\n",
|
||||
data->sg->offset, data->sg->length);
|
||||
@@ -71,7 +71,7 @@ static int sdmmc_idma_validate_data(struct mmci_host *host,
|
||||
}
|
||||
}
|
||||
|
||||
if (!IS_ALIGNED(data->sg->offset, sizeof(u32))) {
|
||||
if (!IS_ALIGNED(sg->offset, sizeof(u32))) {
|
||||
dev_err(mmc_dev(host->mmc),
|
||||
"unaligned last scatterlist: ofst:%x length:%d\n",
|
||||
data->sg->offset, data->sg->length);
|
||||
|
||||
@@ -111,8 +111,8 @@
|
||||
#define CLK_DIV_MASK 0x7f
|
||||
|
||||
/* REG_BUS_WIDTH */
|
||||
#define BUS_WIDTH_8 BIT(2)
|
||||
#define BUS_WIDTH_4 BIT(1)
|
||||
#define BUS_WIDTH_4_SUPPORT BIT(3)
|
||||
#define BUS_WIDTH_4 BIT(2)
|
||||
#define BUS_WIDTH_1 BIT(0)
|
||||
|
||||
#define MMC_VDD_360 23
|
||||
@@ -527,9 +527,6 @@ static void moxart_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
case MMC_BUS_WIDTH_4:
|
||||
writel(BUS_WIDTH_4, host->base + REG_BUS_WIDTH);
|
||||
break;
|
||||
case MMC_BUS_WIDTH_8:
|
||||
writel(BUS_WIDTH_8, host->base + REG_BUS_WIDTH);
|
||||
break;
|
||||
default:
|
||||
writel(BUS_WIDTH_1, host->base + REG_BUS_WIDTH);
|
||||
break;
|
||||
@@ -654,16 +651,8 @@ static int moxart_probe(struct platform_device *pdev)
|
||||
dmaengine_slave_config(host->dma_chan_rx, &cfg);
|
||||
}
|
||||
|
||||
switch ((readl(host->base + REG_BUS_WIDTH) >> 3) & 3) {
|
||||
case 1:
|
||||
if (readl(host->base + REG_BUS_WIDTH) & BUS_WIDTH_4_SUPPORT)
|
||||
mmc->caps |= MMC_CAP_4_BIT_DATA;
|
||||
break;
|
||||
case 2:
|
||||
mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
writel(0, host->base + REG_INTERRUPT_MASK);
|
||||
|
||||
|
||||
@@ -2293,6 +2293,9 @@ static void msdc_cqe_disable(struct mmc_host *mmc, bool recovery)
|
||||
/* disable busy check */
|
||||
sdr_clr_bits(host->base + MSDC_PATCH_BIT1, MSDC_PB1_BUSY_CHECK_SEL);
|
||||
|
||||
val = readl(host->base + MSDC_INT);
|
||||
writel(val, host->base + MSDC_INT);
|
||||
|
||||
if (recovery) {
|
||||
sdr_set_field(host->base + MSDC_DMA_CTRL,
|
||||
MSDC_DMA_CTRL_STOP, 1);
|
||||
@@ -2693,11 +2696,14 @@ static int __maybe_unused msdc_suspend(struct device *dev)
|
||||
{
|
||||
struct mmc_host *mmc = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
if (mmc->caps2 & MMC_CAP2_CQE) {
|
||||
ret = cqhci_suspend(mmc);
|
||||
if (ret)
|
||||
return ret;
|
||||
val = readl(((struct msdc_host *)mmc_priv(mmc))->base + MSDC_INT);
|
||||
writel(val, ((struct msdc_host *)mmc_priv(mmc))->base + MSDC_INT);
|
||||
}
|
||||
|
||||
return pm_runtime_force_suspend(dev);
|
||||
|
||||
@@ -648,7 +648,7 @@ static int pxamci_probe(struct platform_device *pdev)
|
||||
|
||||
ret = pxamci_of_init(pdev, mmc);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
host = mmc_priv(mmc);
|
||||
host->mmc = mmc;
|
||||
@@ -672,7 +672,7 @@ static int pxamci_probe(struct platform_device *pdev)
|
||||
|
||||
ret = pxamci_init_ocr(host);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
mmc->caps = 0;
|
||||
host->cmdat = 0;
|
||||
|
||||
@@ -390,10 +390,10 @@ static void renesas_sdhi_hs400_complete(struct mmc_host *mmc)
|
||||
SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL) |
|
||||
sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_TMPPORT2));
|
||||
|
||||
/* Set the sampling clock selection range of HS400 mode */
|
||||
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL,
|
||||
SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN |
|
||||
0x4 << SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT);
|
||||
sd_scc_read32(host, priv,
|
||||
SH_MOBILE_SDHI_SCC_DTCNTL));
|
||||
|
||||
/* Avoid bad TAP */
|
||||
if (bad_taps & BIT(priv->tap_set)) {
|
||||
|
||||
@@ -37,10 +37,7 @@ struct realtek_pci_sdmmc {
|
||||
bool double_clk;
|
||||
bool eject;
|
||||
bool initial_mode;
|
||||
int power_state;
|
||||
#define SDMMC_POWER_ON 1
|
||||
#define SDMMC_POWER_OFF 0
|
||||
|
||||
int prev_power_state;
|
||||
int sg_count;
|
||||
s32 cookie;
|
||||
int cookie_sg_count;
|
||||
@@ -902,14 +899,21 @@ static int sd_set_bus_width(struct realtek_pci_sdmmc *host,
|
||||
return err;
|
||||
}
|
||||
|
||||
static int sd_power_on(struct realtek_pci_sdmmc *host)
|
||||
static int sd_power_on(struct realtek_pci_sdmmc *host, unsigned char power_mode)
|
||||
{
|
||||
struct rtsx_pcr *pcr = host->pcr;
|
||||
int err;
|
||||
|
||||
if (host->power_state == SDMMC_POWER_ON)
|
||||
if (host->prev_power_state == MMC_POWER_ON)
|
||||
return 0;
|
||||
|
||||
if (host->prev_power_state == MMC_POWER_UP) {
|
||||
rtsx_pci_write_register(pcr, SD_BUS_STAT, SD_CLK_TOGGLE_EN, 0);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
msleep(100);
|
||||
|
||||
rtsx_pci_init_cmd(pcr);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SELECT, 0x07, SD_MOD_SEL);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SHARE_MODE,
|
||||
@@ -928,11 +932,17 @@ static int sd_power_on(struct realtek_pci_sdmmc *host)
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
mdelay(1);
|
||||
|
||||
err = rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
host->power_state = SDMMC_POWER_ON;
|
||||
/* send at least 74 clocks */
|
||||
rtsx_pci_write_register(pcr, SD_BUS_STAT, SD_CLK_TOGGLE_EN, SD_CLK_TOGGLE_EN);
|
||||
|
||||
finish:
|
||||
host->prev_power_state = power_mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -941,7 +951,7 @@ static int sd_power_off(struct realtek_pci_sdmmc *host)
|
||||
struct rtsx_pcr *pcr = host->pcr;
|
||||
int err;
|
||||
|
||||
host->power_state = SDMMC_POWER_OFF;
|
||||
host->prev_power_state = MMC_POWER_OFF;
|
||||
|
||||
rtsx_pci_init_cmd(pcr);
|
||||
|
||||
@@ -967,7 +977,7 @@ static int sd_set_power_mode(struct realtek_pci_sdmmc *host,
|
||||
if (power_mode == MMC_POWER_OFF)
|
||||
err = sd_power_off(host);
|
||||
else
|
||||
err = sd_power_on(host);
|
||||
err = sd_power_on(host, power_mode);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -1404,10 +1414,11 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
|
||||
|
||||
host = mmc_priv(mmc);
|
||||
host->pcr = pcr;
|
||||
mmc->ios.power_delay_ms = 5;
|
||||
host->mmc = mmc;
|
||||
host->pdev = pdev;
|
||||
host->cookie = -1;
|
||||
host->power_state = SDMMC_POWER_OFF;
|
||||
host->prev_power_state = MMC_POWER_OFF;
|
||||
INIT_WORK(&host->work, sd_request);
|
||||
platform_set_drvdata(pdev, host);
|
||||
pcr->slots[RTSX_SD_CARD].p_dev = pdev;
|
||||
|
||||
@@ -12,28 +12,55 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "sdhci-cqhci.h"
|
||||
#include "sdhci-pltfm.h"
|
||||
#include "cqhci.h"
|
||||
|
||||
#define SDHCI_VENDOR 0x78
|
||||
#define SDHCI_VENDOR_ENHANCED_STRB 0x1
|
||||
#define SDHCI_VENDOR_GATE_SDCLK_EN 0x2
|
||||
|
||||
#define BRCMSTB_PRIV_FLAGS_NO_64BIT BIT(0)
|
||||
#define BRCMSTB_PRIV_FLAGS_BROKEN_TIMEOUT BIT(1)
|
||||
#define BRCMSTB_MATCH_FLAGS_NO_64BIT BIT(0)
|
||||
#define BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT BIT(1)
|
||||
#define BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE BIT(2)
|
||||
|
||||
#define BRCMSTB_PRIV_FLAGS_HAS_CQE BIT(0)
|
||||
#define BRCMSTB_PRIV_FLAGS_GATE_CLOCK BIT(1)
|
||||
|
||||
#define SDHCI_ARASAN_CQE_BASE_ADDR 0x200
|
||||
|
||||
struct sdhci_brcmstb_priv {
|
||||
void __iomem *cfg_regs;
|
||||
bool has_cqe;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
struct brcmstb_match_priv {
|
||||
void (*hs400es)(struct mmc_host *mmc, struct mmc_ios *ios);
|
||||
struct sdhci_ops *ops;
|
||||
unsigned int flags;
|
||||
const unsigned int flags;
|
||||
};
|
||||
|
||||
static inline void enable_clock_gating(struct sdhci_host *host)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = sdhci_readl(host, SDHCI_VENDOR);
|
||||
reg |= SDHCI_VENDOR_GATE_SDCLK_EN;
|
||||
sdhci_writel(host, reg, SDHCI_VENDOR);
|
||||
}
|
||||
|
||||
void brcmstb_reset(struct sdhci_host *host, u8 mask)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
||||
|
||||
sdhci_and_cqhci_reset(host, mask);
|
||||
|
||||
/* Reset will clear this, so re-enable it */
|
||||
if (priv->flags & BRCMSTB_PRIV_FLAGS_GATE_CLOCK)
|
||||
enable_clock_gating(host);
|
||||
}
|
||||
|
||||
static void sdhci_brcmstb_hs400es(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
{
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
@@ -129,22 +156,23 @@ static struct sdhci_ops sdhci_brcmstb_ops = {
|
||||
static struct sdhci_ops sdhci_brcmstb_ops_7216 = {
|
||||
.set_clock = sdhci_brcmstb_set_clock,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
.reset = sdhci_reset,
|
||||
.reset = brcmstb_reset,
|
||||
.set_uhs_signaling = sdhci_brcmstb_set_uhs_signaling,
|
||||
};
|
||||
|
||||
static struct brcmstb_match_priv match_priv_7425 = {
|
||||
.flags = BRCMSTB_PRIV_FLAGS_NO_64BIT |
|
||||
BRCMSTB_PRIV_FLAGS_BROKEN_TIMEOUT,
|
||||
.flags = BRCMSTB_MATCH_FLAGS_NO_64BIT |
|
||||
BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT,
|
||||
.ops = &sdhci_brcmstb_ops,
|
||||
};
|
||||
|
||||
static struct brcmstb_match_priv match_priv_7445 = {
|
||||
.flags = BRCMSTB_PRIV_FLAGS_BROKEN_TIMEOUT,
|
||||
.flags = BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT,
|
||||
.ops = &sdhci_brcmstb_ops,
|
||||
};
|
||||
|
||||
static const struct brcmstb_match_priv match_priv_7216 = {
|
||||
.flags = BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE,
|
||||
.hs400es = sdhci_brcmstb_hs400es,
|
||||
.ops = &sdhci_brcmstb_ops_7216,
|
||||
};
|
||||
@@ -176,7 +204,7 @@ static int sdhci_brcmstb_add_host(struct sdhci_host *host,
|
||||
bool dma64;
|
||||
int ret;
|
||||
|
||||
if (!priv->has_cqe)
|
||||
if ((priv->flags & BRCMSTB_PRIV_FLAGS_HAS_CQE) == 0)
|
||||
return sdhci_add_host(host);
|
||||
|
||||
dev_dbg(mmc_dev(host->mmc), "CQE is enabled\n");
|
||||
@@ -225,7 +253,6 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
|
||||
struct sdhci_brcmstb_priv *priv;
|
||||
struct sdhci_host *host;
|
||||
struct resource *iomem;
|
||||
bool has_cqe = false;
|
||||
struct clk *clk;
|
||||
int res;
|
||||
|
||||
@@ -244,10 +271,6 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
|
||||
return res;
|
||||
|
||||
memset(&brcmstb_pdata, 0, sizeof(brcmstb_pdata));
|
||||
if (device_property_read_bool(&pdev->dev, "supports-cqe")) {
|
||||
has_cqe = true;
|
||||
match_priv->ops->irq = sdhci_brcmstb_cqhci_irq;
|
||||
}
|
||||
brcmstb_pdata.ops = match_priv->ops;
|
||||
host = sdhci_pltfm_init(pdev, &brcmstb_pdata,
|
||||
sizeof(struct sdhci_brcmstb_priv));
|
||||
@@ -258,7 +281,10 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
|
||||
|
||||
pltfm_host = sdhci_priv(host);
|
||||
priv = sdhci_pltfm_priv(pltfm_host);
|
||||
priv->has_cqe = has_cqe;
|
||||
if (device_property_read_bool(&pdev->dev, "supports-cqe")) {
|
||||
priv->flags |= BRCMSTB_PRIV_FLAGS_HAS_CQE;
|
||||
match_priv->ops->irq = sdhci_brcmstb_cqhci_irq;
|
||||
}
|
||||
|
||||
/* Map in the non-standard CFG registers */
|
||||
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
@@ -273,6 +299,14 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
|
||||
if (res)
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* Automatic clock gating does not work for SD cards that may
|
||||
* voltage switch so only enable it for non-removable devices.
|
||||
*/
|
||||
if ((match_priv->flags & BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE) &&
|
||||
(host->mmc->caps & MMC_CAP_NONREMOVABLE))
|
||||
priv->flags |= BRCMSTB_PRIV_FLAGS_GATE_CLOCK;
|
||||
|
||||
/*
|
||||
* If the chip has enhanced strobe and it's enabled, add
|
||||
* callback
|
||||
@@ -287,14 +321,14 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
|
||||
* properties through mmc_of_parse().
|
||||
*/
|
||||
host->caps = sdhci_readl(host, SDHCI_CAPABILITIES);
|
||||
if (match_priv->flags & BRCMSTB_PRIV_FLAGS_NO_64BIT)
|
||||
if (match_priv->flags & BRCMSTB_MATCH_FLAGS_NO_64BIT)
|
||||
host->caps &= ~SDHCI_CAN_64BIT;
|
||||
host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
|
||||
host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 |
|
||||
SDHCI_SUPPORT_DDR50);
|
||||
host->quirks |= SDHCI_QUIRK_MISSING_CAPS;
|
||||
|
||||
if (match_priv->flags & BRCMSTB_PRIV_FLAGS_BROKEN_TIMEOUT)
|
||||
if (match_priv->flags & BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT)
|
||||
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
|
||||
|
||||
res = sdhci_brcmstb_add_host(host, priv);
|
||||
|
||||
24
sysdrv/source/kernel/drivers/mmc/host/sdhci-cqhci.h
Normal file
24
sysdrv/source/kernel/drivers/mmc/host/sdhci-cqhci.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright 2022 The Chromium OS Authors
|
||||
*
|
||||
* Support that applies to the combination of SDHCI and CQHCI, while not
|
||||
* expressing a dependency between the two modules.
|
||||
*/
|
||||
|
||||
#ifndef __MMC_HOST_SDHCI_CQHCI_H__
|
||||
#define __MMC_HOST_SDHCI_CQHCI_H__
|
||||
|
||||
#include "cqhci.h"
|
||||
#include "sdhci.h"
|
||||
|
||||
static inline void sdhci_and_cqhci_reset(struct sdhci_host *host, u8 mask)
|
||||
{
|
||||
if ((host->mmc->caps2 & MMC_CAP2_CQE) && (mask & SDHCI_RESET_ALL) &&
|
||||
host->mmc->cqe_private)
|
||||
cqhci_deactivate(host->mmc);
|
||||
|
||||
sdhci_reset(host, mask);
|
||||
}
|
||||
|
||||
#endif /* __MMC_HOST_SDHCI_CQHCI_H__ */
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_data/mmc-esdhc-imx.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include "sdhci-cqhci.h"
|
||||
#include "sdhci-pltfm.h"
|
||||
#include "sdhci-esdhc.h"
|
||||
#include "cqhci.h"
|
||||
@@ -294,22 +295,6 @@ struct pltfm_imx_data {
|
||||
struct pm_qos_request pm_qos_req;
|
||||
};
|
||||
|
||||
static const struct platform_device_id imx_esdhc_devtype[] = {
|
||||
{
|
||||
.name = "sdhci-esdhc-imx25",
|
||||
.driver_data = (kernel_ulong_t) &esdhc_imx25_data,
|
||||
}, {
|
||||
.name = "sdhci-esdhc-imx35",
|
||||
.driver_data = (kernel_ulong_t) &esdhc_imx35_data,
|
||||
}, {
|
||||
.name = "sdhci-esdhc-imx51",
|
||||
.driver_data = (kernel_ulong_t) &esdhc_imx51_data,
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, imx_esdhc_devtype);
|
||||
|
||||
static const struct of_device_id imx_esdhc_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx25-esdhc", .data = &esdhc_imx25_data, },
|
||||
{ .compatible = "fsl,imx35-esdhc", .data = &esdhc_imx35_data, },
|
||||
@@ -1243,7 +1228,7 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
|
||||
|
||||
static void esdhc_reset(struct sdhci_host *host, u8 mask)
|
||||
{
|
||||
sdhci_reset(host, mask);
|
||||
sdhci_and_cqhci_reset(host, mask);
|
||||
|
||||
sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
|
||||
sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
|
||||
@@ -1464,7 +1449,7 @@ static void esdhc_cqe_enable(struct mmc_host *mmc)
|
||||
* system resume back.
|
||||
*/
|
||||
cqhci_writel(cq_host, 0, CQHCI_CTL);
|
||||
if (cqhci_readl(cq_host, CQHCI_CTL) && CQHCI_HALT)
|
||||
if (cqhci_readl(cq_host, CQHCI_CTL) & CQHCI_HALT)
|
||||
dev_err(mmc_dev(host->mmc),
|
||||
"failed to exit halt state when enable CQE\n");
|
||||
|
||||
@@ -1545,72 +1530,6 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
|
||||
}
|
||||
#endif
|
||||
|
||||
static int sdhci_esdhc_imx_probe_nondt(struct platform_device *pdev,
|
||||
struct sdhci_host *host,
|
||||
struct pltfm_imx_data *imx_data)
|
||||
{
|
||||
struct esdhc_platform_data *boarddata = &imx_data->boarddata;
|
||||
int err;
|
||||
|
||||
if (!host->mmc->parent->platform_data) {
|
||||
dev_err(mmc_dev(host->mmc), "no board data!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
imx_data->boarddata = *((struct esdhc_platform_data *)
|
||||
host->mmc->parent->platform_data);
|
||||
/* write_protect */
|
||||
if (boarddata->wp_type == ESDHC_WP_GPIO) {
|
||||
host->mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
|
||||
|
||||
err = mmc_gpiod_request_ro(host->mmc, "wp", 0, 0);
|
||||
if (err) {
|
||||
dev_err(mmc_dev(host->mmc),
|
||||
"failed to request write-protect gpio!\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* card_detect */
|
||||
switch (boarddata->cd_type) {
|
||||
case ESDHC_CD_GPIO:
|
||||
err = mmc_gpiod_request_cd(host->mmc, "cd", 0, false, 0);
|
||||
if (err) {
|
||||
dev_err(mmc_dev(host->mmc),
|
||||
"failed to request card-detect gpio!\n");
|
||||
return err;
|
||||
}
|
||||
fallthrough;
|
||||
|
||||
case ESDHC_CD_CONTROLLER:
|
||||
/* we have a working card_detect back */
|
||||
host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
|
||||
break;
|
||||
|
||||
case ESDHC_CD_PERMANENT:
|
||||
host->mmc->caps |= MMC_CAP_NONREMOVABLE;
|
||||
break;
|
||||
|
||||
case ESDHC_CD_NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (boarddata->max_bus_width) {
|
||||
case 8:
|
||||
host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA;
|
||||
break;
|
||||
case 4:
|
||||
host->mmc->caps |= MMC_CAP_4_BIT_DATA;
|
||||
break;
|
||||
case 1:
|
||||
default:
|
||||
host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *of_id =
|
||||
@@ -1630,8 +1549,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
|
||||
|
||||
imx_data = sdhci_pltfm_priv(pltfm_host);
|
||||
|
||||
imx_data->socdata = of_id ? of_id->data : (struct esdhc_soc_data *)
|
||||
pdev->id_entry->driver_data;
|
||||
imx_data->socdata = of_id->data;
|
||||
|
||||
if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
|
||||
cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0);
|
||||
@@ -1692,6 +1610,10 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
|
||||
host->mmc_host_ops.execute_tuning = usdhc_execute_tuning;
|
||||
}
|
||||
|
||||
err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data);
|
||||
if (err)
|
||||
goto disable_ahb_clk;
|
||||
|
||||
if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING)
|
||||
sdhci_esdhc_ops.platform_execute_tuning =
|
||||
esdhc_executing_tuning;
|
||||
@@ -1699,13 +1621,15 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
|
||||
if (imx_data->socdata->flags & ESDHC_FLAG_ERR004536)
|
||||
host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
|
||||
|
||||
if (imx_data->socdata->flags & ESDHC_FLAG_HS400)
|
||||
if (host->mmc->caps & MMC_CAP_8_BIT_DATA &&
|
||||
imx_data->socdata->flags & ESDHC_FLAG_HS400)
|
||||
host->quirks2 |= SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400;
|
||||
|
||||
if (imx_data->socdata->flags & ESDHC_FLAG_BROKEN_AUTO_CMD23)
|
||||
host->quirks2 |= SDHCI_QUIRK2_ACMD23_BROKEN;
|
||||
|
||||
if (imx_data->socdata->flags & ESDHC_FLAG_HS400_ES) {
|
||||
if (host->mmc->caps & MMC_CAP_8_BIT_DATA &&
|
||||
imx_data->socdata->flags & ESDHC_FLAG_HS400_ES) {
|
||||
host->mmc->caps2 |= MMC_CAP2_HS400_ES;
|
||||
host->mmc_host_ops.hs400_enhanced_strobe =
|
||||
esdhc_hs400_enhanced_strobe;
|
||||
@@ -1727,13 +1651,6 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
|
||||
goto disable_ahb_clk;
|
||||
}
|
||||
|
||||
if (of_id)
|
||||
err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data);
|
||||
else
|
||||
err = sdhci_esdhc_imx_probe_nondt(pdev, host, imx_data);
|
||||
if (err)
|
||||
goto disable_ahb_clk;
|
||||
|
||||
sdhci_esdhc_imx_hwinit(host);
|
||||
|
||||
err = sdhci_add_host(host);
|
||||
@@ -1944,7 +1861,6 @@ static struct platform_driver sdhci_esdhc_imx_driver = {
|
||||
.of_match_table = imx_esdhc_dt_ids,
|
||||
.pm = &sdhci_esdhc_pmops,
|
||||
},
|
||||
.id_table = imx_esdhc_devtype,
|
||||
.probe = sdhci_esdhc_imx_probe,
|
||||
.remove = sdhci_esdhc_imx_remove,
|
||||
};
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/interconnect.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include "sdhci-pltfm.h"
|
||||
#include "cqhci.h"
|
||||
@@ -2441,6 +2442,7 @@ static const struct sdhci_msm_variant_info sm8250_sdhci_var = {
|
||||
static const struct of_device_id sdhci_msm_dt_match[] = {
|
||||
{.compatible = "qcom,sdhci-msm-v4", .data = &sdhci_msm_mci_var},
|
||||
{.compatible = "qcom,sdhci-msm-v5", .data = &sdhci_msm_v5_var},
|
||||
{.compatible = "qcom,sdm670-sdhci", .data = &sdm845_sdhci_var},
|
||||
{.compatible = "qcom,sdm845-sdhci", .data = &sdm845_sdhci_var},
|
||||
{.compatible = "qcom,sm8250-sdhci", .data = &sm8250_sdhci_var},
|
||||
{.compatible = "qcom,sc7180-sdhci", .data = &sdm845_sdhci_var},
|
||||
@@ -2488,6 +2490,43 @@ static inline void sdhci_msm_get_of_property(struct platform_device *pdev,
|
||||
of_property_read_u32(node, "qcom,dll-config", &msm_host->dll_config);
|
||||
}
|
||||
|
||||
static int sdhci_msm_gcc_reset(struct device *dev, struct sdhci_host *host)
|
||||
{
|
||||
struct reset_control *reset;
|
||||
int ret = 0;
|
||||
|
||||
reset = reset_control_get_optional_exclusive(dev, NULL);
|
||||
if (IS_ERR(reset))
|
||||
return dev_err_probe(dev, PTR_ERR(reset),
|
||||
"unable to acquire core_reset\n");
|
||||
|
||||
if (!reset)
|
||||
return ret;
|
||||
|
||||
ret = reset_control_assert(reset);
|
||||
if (ret) {
|
||||
reset_control_put(reset);
|
||||
return dev_err_probe(dev, ret, "core_reset assert failed\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* The hardware requirement for delay between assert/deassert
|
||||
* is at least 3-4 sleep clock (32.7KHz) cycles, which comes to
|
||||
* ~125us (4/32768). To be on the safe side add 200us delay.
|
||||
*/
|
||||
usleep_range(200, 210);
|
||||
|
||||
ret = reset_control_deassert(reset);
|
||||
if (ret) {
|
||||
reset_control_put(reset);
|
||||
return dev_err_probe(dev, ret, "core_reset deassert failed\n");
|
||||
}
|
||||
|
||||
usleep_range(200, 210);
|
||||
reset_control_put(reset);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sdhci_msm_probe(struct platform_device *pdev)
|
||||
{
|
||||
@@ -2536,6 +2575,10 @@ static int sdhci_msm_probe(struct platform_device *pdev)
|
||||
|
||||
msm_host->saved_tuning_phase = INVALID_TUNING_PHASE;
|
||||
|
||||
ret = sdhci_msm_gcc_reset(&pdev->dev, host);
|
||||
if (ret)
|
||||
goto pltfm_free;
|
||||
|
||||
/* Setup SDCC bus voter clock. */
|
||||
msm_host->bus_clk = devm_clk_get(&pdev->dev, "bus");
|
||||
if (!IS_ERR(msm_host->bus_clk)) {
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <linux/firmware/xlnx-zynqmp.h>
|
||||
|
||||
#include "cqhci.h"
|
||||
#include "sdhci-cqhci.h"
|
||||
#include "sdhci-pltfm.h"
|
||||
|
||||
#define SDHCI_ARASAN_VENDOR_REGISTER 0x78
|
||||
@@ -359,7 +360,7 @@ static void sdhci_arasan_reset(struct sdhci_host *host, u8 mask)
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
|
||||
|
||||
sdhci_reset(host, mask);
|
||||
sdhci_and_cqhci_reset(host, mask);
|
||||
|
||||
if (sdhci_arasan->quirks & SDHCI_ARASAN_QUIRK_FORCE_CDTEST) {
|
||||
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
|
||||
|
||||
@@ -100,8 +100,13 @@ static void sdhci_at91_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
static void sdhci_at91_set_uhs_signaling(struct sdhci_host *host,
|
||||
unsigned int timing)
|
||||
{
|
||||
if (timing == MMC_TIMING_MMC_DDR52)
|
||||
sdhci_writeb(host, SDMMC_MC1R_DDR, SDMMC_MC1R);
|
||||
u8 mc1r;
|
||||
|
||||
if (timing == MMC_TIMING_MMC_DDR52) {
|
||||
mc1r = sdhci_readb(host, SDMMC_MC1R);
|
||||
mc1r |= SDMMC_MC1R_DDR;
|
||||
sdhci_writeb(host, mc1r, SDMMC_MC1R);
|
||||
}
|
||||
sdhci_set_uhs_signaling(host, timing);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,11 +27,15 @@
|
||||
/* DWCMSHC specific Mode Select value */
|
||||
#define DWCMSHC_CTRL_HS400 0x7
|
||||
|
||||
#define DWCMSHC_VER_ID 0x500
|
||||
#define DWCMSHC_VER_TYPE 0x504
|
||||
#define DWCMSHC_HOST_CTRL3 0x508
|
||||
#define DWCMSHC_EMMC_CONTROL 0x52c
|
||||
#define DWCMSHC_EMMC_ATCTRL 0x540
|
||||
/* DWC IP vendor area 1 pointer */
|
||||
#define DWCMSHC_P_VENDOR_AREA1 0xe8
|
||||
#define DWCMSHC_AREA1_MASK GENMASK(11, 0)
|
||||
/* Offset inside the vendor area 1 */
|
||||
#define DWCMSHC_HOST_CTRL3 0x8
|
||||
#define DWCMSHC_EMMC_CONTROL 0x2c
|
||||
#define DWCMSHC_CARD_IS_EMMC BIT(0)
|
||||
#define DWCMSHC_ENHANCED_STROBE BIT(8)
|
||||
#define DWCMSHC_EMMC_ATCTRL 0x40
|
||||
|
||||
/* Rockchip specific Registers */
|
||||
#define DWCMSHC_EMMC_DLL_CTRL 0x800
|
||||
@@ -41,30 +45,30 @@
|
||||
#define DECMSHC_EMMC_DLL_CMDOUT 0x810
|
||||
#define DWCMSHC_EMMC_DLL_STATUS0 0x840
|
||||
#define DWCMSHC_EMMC_DLL_STATUS1 0x844
|
||||
|
||||
#define DWCMSHC_EMMC_DLL_START BIT(0)
|
||||
#define DWCMSHC_EMMC_DLL_LOCKED BIT(8)
|
||||
#define DWCMSHC_EMMC_DLL_TIMEOUT BIT(9)
|
||||
#define DWCMSHC_EMMC_DLL_RXCLK_SRCSEL 29
|
||||
#define DWCMSHC_EMMC_DLL_START_POINT 16
|
||||
#define DWCMSHC_EMMC_DLL_INC 8
|
||||
#define DWCMSHC_EMMC_DLL_BYPASS BIT(24)
|
||||
#define DWCMSHC_EMMC_DLL_DLYENA BIT(27)
|
||||
|
||||
#define DLL_TAP_VALUE_SEL BIT(25)
|
||||
#define DLL_TAP_VALUE_OFFSET 8
|
||||
#define DLL_TXCLK_TAPNUM_DEFAULT 0x10
|
||||
#define DLL_TXCLK_TAPNUM_90_DEGREES 0xA
|
||||
#define DLL_TXCLK_TAPNUM_FROM_SW BIT(24)
|
||||
#define DLL_TXCLK_NO_INVERTER BIT(29)
|
||||
|
||||
#define DLL_STRBIN_TAPNUM_DEFAULT 0x8
|
||||
#define DLL_STRBIN_TAPNUM_FROM_SW BIT(24)
|
||||
#define DLL_STRBIN_DELAY_NUM_SEL BIT(26)
|
||||
#define DLL_STRBIN_DELAY_NUM_OFFSET 16
|
||||
|
||||
#define DLL_STRBIN_DELAY_NUM_DEFAULT 0x16
|
||||
#define DLL_RXCLK_NO_INVERTER 1
|
||||
#define DLL_RXCLK_INVERTER 0
|
||||
#define DLL_CMDOUT_TAPNUM_90_DEGREES 0x8
|
||||
#define DLL_RXCLK_TAPNUM_FROM_SW BIT(24)
|
||||
#define DLL_RXCLK_NO_INVERTER BIT(29)
|
||||
#define DLL_RXCLK_ORI_GATE BIT(31)
|
||||
#define DLL_RXCLK_MAX_TAP 32
|
||||
|
||||
#define DWCMSHC_CARD_IS_EMMC BIT(0)
|
||||
#define DWCMSHC_ENHANCED_STROBE BIT(8)
|
||||
|
||||
#define DLL_CMDOUT_TAPNUM_FROM_SW BIT(24)
|
||||
#define DLL_CMDOUT_SRC_CLK_NEG BIT(28)
|
||||
#define DLL_CMDOUT_EN_SRC_CLK_NEG BIT(29)
|
||||
@@ -73,18 +77,23 @@
|
||||
#define DLL_LOCK_WO_TMOUT(x) \
|
||||
((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \
|
||||
(((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0))
|
||||
#define ROCKCHIP_MAX_CLKS 3
|
||||
#define RK35xx_MAX_CLKS 3
|
||||
|
||||
#define BOUNDARY_OK(addr, len) \
|
||||
((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1)))
|
||||
|
||||
enum dwcmshc_rk_type {
|
||||
DWCMSHC_RK3568,
|
||||
DWCMSHC_RK3588,
|
||||
};
|
||||
|
||||
struct dwcmshc_driver_data {
|
||||
const struct sdhci_pltfm_data *pdata;
|
||||
u32 flags;
|
||||
#define RK_PLATFROM BIT(0)
|
||||
#define RK_DLL_CMD_OUT BIT(1)
|
||||
#define RK_RXCLK_NO_INVERTER BIT(2)
|
||||
#define RK_RXCLK_SW_TUNING BIT(3)
|
||||
#define RK_TAP_VALUE_SEL BIT(3)
|
||||
|
||||
u8 hs200_tx_tap;
|
||||
u8 hs400_tx_tap;
|
||||
@@ -93,19 +102,24 @@ struct dwcmshc_driver_data {
|
||||
u8 hs400_strbin_tap;
|
||||
};
|
||||
|
||||
struct dwcmshc_priv {
|
||||
struct clk *bus_clk;
|
||||
u32 cclk_rate;
|
||||
u8 hs200_rx_tap;
|
||||
|
||||
struct rk35xx_priv {
|
||||
/* Rockchip specified optional clocks */
|
||||
struct clk_bulk_data rockchip_clks[ROCKCHIP_MAX_CLKS];
|
||||
struct clk_bulk_data rockchip_clks[RK35xx_MAX_CLKS];
|
||||
struct reset_control *reset;
|
||||
enum dwcmshc_rk_type devtype;
|
||||
u8 txclk_tapnum;
|
||||
u32 cclk_rate;
|
||||
unsigned int actual_clk;
|
||||
const struct dwcmshc_driver_data *drv_data;
|
||||
u32 acpi_en;
|
||||
};
|
||||
|
||||
struct dwcmshc_priv {
|
||||
struct clk *bus_clk;
|
||||
int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA reg */
|
||||
void *priv; /* pointer to SoC private stuff */
|
||||
};
|
||||
|
||||
/*
|
||||
* If DMA addr spans 128MB boundary, we split the DMA transfer into two
|
||||
* so that each DMA transfer doesn't exceed the boundary.
|
||||
@@ -129,6 +143,16 @@ static void dwcmshc_adma_write_desc(struct sdhci_host *host, void **desc,
|
||||
sdhci_adma_write_desc(host, desc, addr, len, cmd);
|
||||
}
|
||||
|
||||
static unsigned int dwcmshc_get_max_clock(struct sdhci_host *host)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
|
||||
if (pltfm_host->clk)
|
||||
return sdhci_pltfm_clk_get_max_clock(host);
|
||||
else
|
||||
return pltfm_host->clock;
|
||||
}
|
||||
|
||||
static void dwcmshc_check_auto_cmd23(struct mmc_host *mmc,
|
||||
struct mmc_request *mrq)
|
||||
{
|
||||
@@ -155,7 +179,9 @@ static void dwcmshc_request(struct mmc_host *mmc, struct mmc_request *mrq)
|
||||
static void dwcmshc_set_uhs_signaling(struct sdhci_host *host,
|
||||
unsigned int timing)
|
||||
{
|
||||
u16 ctrl_2, ctrl;
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
||||
u16 ctrl, ctrl_2;
|
||||
|
||||
ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
|
||||
/* Select Bus Speed Mode for host */
|
||||
@@ -175,9 +201,9 @@ static void dwcmshc_set_uhs_signaling(struct sdhci_host *host,
|
||||
ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
|
||||
else if (timing == MMC_TIMING_MMC_HS400) {
|
||||
/* set CARD_IS_EMMC bit to enable Data Strobe for HS400 */
|
||||
ctrl = sdhci_readw(host, DWCMSHC_EMMC_CONTROL);
|
||||
ctrl = sdhci_readw(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL);
|
||||
ctrl |= DWCMSHC_CARD_IS_EMMC;
|
||||
sdhci_writew(host, ctrl, DWCMSHC_EMMC_CONTROL);
|
||||
sdhci_writew(host, ctrl, priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL);
|
||||
|
||||
ctrl_2 |= DWCMSHC_CTRL_HS400;
|
||||
}
|
||||
@@ -190,22 +216,27 @@ static void dwcmshc_hs400_enhanced_strobe(struct mmc_host *mmc,
|
||||
{
|
||||
u32 vendor;
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
||||
int reg = priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL;
|
||||
|
||||
vendor = sdhci_readl(host, DWCMSHC_EMMC_CONTROL);
|
||||
vendor = sdhci_readl(host, reg);
|
||||
if (ios->enhanced_strobe)
|
||||
vendor |= DWCMSHC_ENHANCED_STROBE;
|
||||
else
|
||||
vendor &= ~DWCMSHC_ENHANCED_STROBE;
|
||||
|
||||
sdhci_writel(host, vendor, DWCMSHC_EMMC_CONTROL);
|
||||
sdhci_writel(host, vendor, reg);
|
||||
}
|
||||
|
||||
static void dwcmshc_rk_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
static void dwcmshc_rk3568_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
||||
struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host);
|
||||
struct rk35xx_priv *priv = dwc_priv->priv;
|
||||
const struct dwcmshc_driver_data *drv_data = priv->drv_data;
|
||||
u32 txclk_tapnum, extra, rxclk_tapnum;
|
||||
u8 txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT;
|
||||
u32 extra, reg, dll_lock_value;
|
||||
int err;
|
||||
|
||||
host->mmc->actual_clock = 0;
|
||||
@@ -238,13 +269,19 @@ static void dwcmshc_rk_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
sdhci_set_clock(host, clock);
|
||||
|
||||
/* Disable cmd conflict check */
|
||||
extra = sdhci_readl(host, DWCMSHC_HOST_CTRL3);
|
||||
reg = dwc_priv->vendor_specific_area1 + DWCMSHC_HOST_CTRL3;
|
||||
extra = sdhci_readl(host, reg);
|
||||
extra &= ~BIT(0);
|
||||
sdhci_writel(host, extra, DWCMSHC_HOST_CTRL3);
|
||||
sdhci_writel(host, extra, reg);
|
||||
|
||||
/* Disable output clock while config DLL */
|
||||
sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
|
||||
|
||||
if (clock <= 52000000) {
|
||||
/* Disable DLL */
|
||||
sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL);
|
||||
/*
|
||||
* Disable DLL and reset both of sample and drive clock.
|
||||
* Config DLL BYPASS and Reset both of sample and drive clock.
|
||||
* The bypass bit and start bit need to set if DLL is not locked.
|
||||
*/
|
||||
sdhci_writel(host, DWCMSHC_EMMC_DLL_BYPASS | DWCMSHC_EMMC_DLL_START, DWCMSHC_EMMC_DLL_CTRL);
|
||||
@@ -260,7 +297,7 @@ static void dwcmshc_rk_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
DLL_STRBIN_DELAY_NUM_SEL |
|
||||
drv_data->ddr50_strbin_delay_num << DLL_STRBIN_DELAY_NUM_OFFSET;
|
||||
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN);
|
||||
return;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Reset DLL */
|
||||
@@ -270,6 +307,7 @@ static void dwcmshc_rk_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
|
||||
/* Init DLL settings, clean start bit before resetting */
|
||||
sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL);
|
||||
/* Init DLL settings */
|
||||
extra = 0x5 << DWCMSHC_EMMC_DLL_START_POINT |
|
||||
0x2 << DWCMSHC_EMMC_DLL_INC |
|
||||
DWCMSHC_EMMC_DLL_START;
|
||||
@@ -279,26 +317,21 @@ static void dwcmshc_rk_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
500 * USEC_PER_MSEC);
|
||||
if (err) {
|
||||
dev_err(mmc_dev(host->mmc), "DLL lock timeout!\n");
|
||||
return;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
dll_lock_value = ((sdhci_readl(host, DWCMSHC_EMMC_DLL_STATUS0) & 0xFF) * 2) & 0xFF;
|
||||
|
||||
extra = 0x1 << 16 | /* tune clock stop en */
|
||||
0x3 << 17 | /* pre-change delay */
|
||||
0x3 << 19; /* post-change delay */
|
||||
sdhci_writel(host, extra, DWCMSHC_EMMC_ATCTRL);
|
||||
sdhci_writel(host, extra, dwc_priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL);
|
||||
|
||||
rxclk_tapnum = priv->hs200_rx_tap;
|
||||
if ((drv_data->flags & RK_RXCLK_NO_INVERTER) &&
|
||||
host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
|
||||
extra = drv_data->hs200_tx_tap - drv_data->hs400_tx_tap;
|
||||
if (rxclk_tapnum + extra < DLL_RXCLK_MAX_TAP)
|
||||
rxclk_tapnum += extra;
|
||||
}
|
||||
extra = DWCMSHC_EMMC_DLL_DLYENA | DLL_RXCLK_ORI_GATE;
|
||||
if (drv_data->flags & RK_RXCLK_NO_INVERTER)
|
||||
extra |= DLL_RXCLK_NO_INVERTER;
|
||||
if (drv_data->flags & RK_RXCLK_SW_TUNING && priv->hs200_rx_tap)
|
||||
extra |= DLL_RXCLK_TAPNUM_FROM_SW | rxclk_tapnum;
|
||||
extra |= DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL;
|
||||
if (drv_data->flags & RK_TAP_VALUE_SEL)
|
||||
extra |= DLL_TAP_VALUE_SEL | dll_lock_value << DLL_TAP_VALUE_OFFSET;
|
||||
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK);
|
||||
|
||||
txclk_tapnum = drv_data->hs200_tx_tap;
|
||||
@@ -310,33 +343,40 @@ static void dwcmshc_rk_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
DWCMSHC_EMMC_DLL_DLYENA |
|
||||
drv_data->hs400_cmd_tap |
|
||||
DLL_CMDOUT_TAPNUM_FROM_SW;
|
||||
if (drv_data->flags & RK_TAP_VALUE_SEL)
|
||||
extra |= DLL_TAP_VALUE_SEL | dll_lock_value << DLL_TAP_VALUE_OFFSET;
|
||||
sdhci_writel(host, extra, DECMSHC_EMMC_DLL_CMDOUT);
|
||||
}
|
||||
extra = DWCMSHC_EMMC_DLL_DLYENA |
|
||||
DLL_TXCLK_TAPNUM_FROM_SW |
|
||||
DLL_RXCLK_NO_INVERTER |
|
||||
DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL |
|
||||
txclk_tapnum;
|
||||
if (drv_data->flags & RK_TAP_VALUE_SEL)
|
||||
extra |= DLL_TAP_VALUE_SEL | dll_lock_value << DLL_TAP_VALUE_OFFSET;
|
||||
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK);
|
||||
|
||||
extra = DWCMSHC_EMMC_DLL_DLYENA |
|
||||
drv_data->hs400_strbin_tap |
|
||||
DLL_STRBIN_TAPNUM_FROM_SW;
|
||||
if (drv_data->flags & RK_TAP_VALUE_SEL)
|
||||
extra |= DLL_TAP_VALUE_SEL | dll_lock_value << DLL_TAP_VALUE_OFFSET;
|
||||
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN);
|
||||
|
||||
exit:
|
||||
/* enable output clock */
|
||||
sdhci_enable_clk(host, 0);
|
||||
}
|
||||
|
||||
static void rockchip_sdhci_reset(struct sdhci_host *host, u8 mask)
|
||||
static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host;
|
||||
struct dwcmshc_priv *priv;
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct dwcmshc_priv *dwc_priv = sdhci_pltfm_priv(pltfm_host);
|
||||
struct rk35xx_priv *priv = dwc_priv->priv;
|
||||
|
||||
if (mask & SDHCI_RESET_ALL) {
|
||||
pltfm_host = sdhci_priv(host);
|
||||
priv = sdhci_pltfm_priv(pltfm_host);
|
||||
if (!IS_ERR_OR_NULL(priv->reset)) {
|
||||
reset_control_assert(priv->reset);
|
||||
udelay(1);
|
||||
reset_control_deassert(priv->reset);
|
||||
}
|
||||
if (mask & SDHCI_RESET_ALL && priv->reset) {
|
||||
reset_control_assert(priv->reset);
|
||||
udelay(1);
|
||||
reset_control_deassert(priv->reset);
|
||||
}
|
||||
|
||||
sdhci_reset(host, mask);
|
||||
@@ -350,45 +390,21 @@ static void sdhci_dwcmshc_request_done(struct sdhci_host *host, struct mmc_reque
|
||||
mmc_request_done(host->mmc, mrq);
|
||||
}
|
||||
|
||||
static int dwcmshc_rk_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
||||
{
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
||||
int rx_delay, dll_lock_num, ret;
|
||||
u32 extra;
|
||||
|
||||
ret = sdhci_execute_tuning(mmc, opcode);
|
||||
if (!ret) {
|
||||
rx_delay = (sdhci_readl(host, DWCMSHC_EMMC_DLL_STATUS1) >> 8) & 0xFF;
|
||||
dll_lock_num = sdhci_readl(host, DWCMSHC_EMMC_DLL_STATUS0) & 0xFF;
|
||||
sdhci_reset_tuning(host);
|
||||
priv->hs200_rx_tap = rx_delay * 16 / dll_lock_num;
|
||||
extra = sdhci_readl(host, DWCMSHC_EMMC_DLL_RXCLK);
|
||||
extra &= DLL_RXCLK_NO_INVERTER;
|
||||
extra |= DWCMSHC_EMMC_DLL_DLYENA | DLL_RXCLK_ORI_GATE |
|
||||
DLL_RXCLK_TAPNUM_FROM_SW | priv->hs200_rx_tap;
|
||||
sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct sdhci_ops sdhci_dwcmshc_ops = {
|
||||
.set_clock = sdhci_set_clock,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
.set_uhs_signaling = dwcmshc_set_uhs_signaling,
|
||||
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
|
||||
.get_max_clock = dwcmshc_get_max_clock,
|
||||
.reset = sdhci_reset,
|
||||
.adma_write_desc = dwcmshc_adma_write_desc,
|
||||
};
|
||||
|
||||
static const struct sdhci_ops sdhci_dwcmshc_rk_ops = {
|
||||
.set_clock = dwcmshc_rk_set_clock,
|
||||
static const struct sdhci_ops sdhci_dwcmshc_rk35xx_ops = {
|
||||
.set_clock = dwcmshc_rk3568_set_clock,
|
||||
.set_bus_width = sdhci_set_bus_width,
|
||||
.set_uhs_signaling = dwcmshc_set_uhs_signaling,
|
||||
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
|
||||
.reset = rockchip_sdhci_reset,
|
||||
.reset = rk35xx_sdhci_reset,
|
||||
.adma_write_desc = dwcmshc_adma_write_desc,
|
||||
.request_done = sdhci_dwcmshc_request_done,
|
||||
};
|
||||
@@ -399,20 +415,84 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = {
|
||||
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
|
||||
};
|
||||
|
||||
static const struct sdhci_pltfm_data sdhci_dwcmshc_rk_pdata = {
|
||||
.ops = &sdhci_dwcmshc_rk_ops,
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct sdhci_pltfm_data sdhci_dwcmshc_bf3_pdata = {
|
||||
.ops = &sdhci_dwcmshc_ops,
|
||||
.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
|
||||
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
|
||||
SDHCI_QUIRK2_ACMD23_BROKEN,
|
||||
};
|
||||
#endif
|
||||
|
||||
static const struct sdhci_pltfm_data sdhci_dwcmshc_rk35xx_pdata = {
|
||||
.ops = &sdhci_dwcmshc_rk35xx_ops,
|
||||
.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
|
||||
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
|
||||
SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
|
||||
};
|
||||
|
||||
static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)
|
||||
{
|
||||
int err;
|
||||
struct rk35xx_priv *priv = dwc_priv->priv;
|
||||
|
||||
priv->reset = devm_reset_control_array_get_optional_exclusive(mmc_dev(host->mmc));
|
||||
if (IS_ERR(priv->reset)) {
|
||||
err = PTR_ERR(priv->reset);
|
||||
dev_err(mmc_dev(host->mmc), "failed to get reset control %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
priv->rockchip_clks[0].id = "axi";
|
||||
priv->rockchip_clks[1].id = "block";
|
||||
priv->rockchip_clks[2].id = "timer";
|
||||
err = devm_clk_bulk_get_optional(mmc_dev(host->mmc), RK35xx_MAX_CLKS,
|
||||
priv->rockchip_clks);
|
||||
if (err) {
|
||||
dev_err(mmc_dev(host->mmc), "failed to get clocks %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = clk_bulk_prepare_enable(RK35xx_MAX_CLKS, priv->rockchip_clks);
|
||||
if (err) {
|
||||
dev_err(mmc_dev(host->mmc), "failed to enable clocks %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (of_property_read_u8(mmc_dev(host->mmc)->of_node, "rockchip,txclk-tapnum",
|
||||
&priv->txclk_tapnum))
|
||||
priv->txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT;
|
||||
|
||||
/* Disable cmd conflict check */
|
||||
sdhci_writel(host, 0x0, dwc_priv->vendor_specific_area1 + DWCMSHC_HOST_CTRL3);
|
||||
/* Reset previous settings */
|
||||
sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK);
|
||||
sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_STRBIN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwcmshc_rk35xx_postinit(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)
|
||||
{
|
||||
/*
|
||||
* Don't support highspeed bus mode with low clk speed as we
|
||||
* cannot use DLL for this condition.
|
||||
*/
|
||||
if (host->mmc->f_max <= 52000000) {
|
||||
dev_info(mmc_dev(host->mmc), "Disabling HS200/HS400, frequency too low (%d)\n",
|
||||
host->mmc->f_max);
|
||||
host->mmc->caps2 &= ~(MMC_CAP2_HS200 | MMC_CAP2_HS400);
|
||||
host->mmc->caps &= ~(MMC_CAP_3_3V_DDR | MMC_CAP_1_8V_DDR);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct dwcmshc_driver_data dwcmshc_drvdata = {
|
||||
.pdata = &sdhci_dwcmshc_pdata,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
static const struct dwcmshc_driver_data rk3568_drvdata = {
|
||||
.pdata = &sdhci_dwcmshc_rk_pdata,
|
||||
.pdata = &sdhci_dwcmshc_rk35xx_pdata,
|
||||
.flags = RK_PLATFROM | RK_RXCLK_NO_INVERTER,
|
||||
.hs200_tx_tap = 16,
|
||||
.hs400_tx_tap = 8,
|
||||
@@ -422,7 +502,7 @@ static const struct dwcmshc_driver_data rk3568_drvdata = {
|
||||
};
|
||||
|
||||
static const struct dwcmshc_driver_data rk3588_drvdata = {
|
||||
.pdata = &sdhci_dwcmshc_rk_pdata,
|
||||
.pdata = &sdhci_dwcmshc_rk35xx_pdata,
|
||||
.flags = RK_PLATFROM | RK_DLL_CMD_OUT,
|
||||
.hs200_tx_tap = 16,
|
||||
.hs400_tx_tap = 9,
|
||||
@@ -432,8 +512,8 @@ static const struct dwcmshc_driver_data rk3588_drvdata = {
|
||||
};
|
||||
|
||||
static const struct dwcmshc_driver_data rk3528_drvdata = {
|
||||
.pdata = &sdhci_dwcmshc_rk_pdata,
|
||||
.flags = RK_PLATFROM | RK_DLL_CMD_OUT | RK_RXCLK_SW_TUNING | RK_RXCLK_NO_INVERTER,
|
||||
.pdata = &sdhci_dwcmshc_rk35xx_pdata,
|
||||
.flags = RK_PLATFROM | RK_DLL_CMD_OUT | RK_TAP_VALUE_SEL,
|
||||
.hs200_tx_tap = 12,
|
||||
.hs400_tx_tap = 6,
|
||||
.hs400_cmd_tap = 6,
|
||||
@@ -441,51 +521,23 @@ static const struct dwcmshc_driver_data rk3528_drvdata = {
|
||||
.ddr50_strbin_delay_num = 10,
|
||||
};
|
||||
|
||||
static int rockchip_pltf_init(struct sdhci_host *host, struct dwcmshc_priv *priv)
|
||||
{
|
||||
int err;
|
||||
|
||||
priv->rockchip_clks[0].id = "axi";
|
||||
priv->rockchip_clks[1].id = "block";
|
||||
priv->rockchip_clks[2].id = "timer";
|
||||
err = devm_clk_bulk_get_optional(mmc_dev(host->mmc), ROCKCHIP_MAX_CLKS,
|
||||
priv->rockchip_clks);
|
||||
if (err) {
|
||||
dev_err(mmc_dev(host->mmc), "failed to get clocks %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = clk_bulk_prepare_enable(ROCKCHIP_MAX_CLKS, priv->rockchip_clks);
|
||||
if (err) {
|
||||
dev_err(mmc_dev(host->mmc), "failed to enable clocks %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Disable cmd conflict check */
|
||||
sdhci_writel(host, 0x0, DWCMSHC_HOST_CTRL3);
|
||||
/* Reset previous settings */
|
||||
sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_TXCLK);
|
||||
sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_STRBIN);
|
||||
|
||||
/*
|
||||
* Don't support highspeed bus mode with low clk speed as we
|
||||
* cannot use DLL for this condition.
|
||||
*/
|
||||
if (host->mmc->f_max <= 52000000) {
|
||||
host->mmc->caps2 &= ~(MMC_CAP2_HS200 | MMC_CAP2_HS400);
|
||||
host->mmc->caps &= ~(MMC_CAP_3_3V_DDR | MMC_CAP_1_8V_DDR);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static const struct dwcmshc_driver_data rk3562_drvdata = {
|
||||
.pdata = &sdhci_dwcmshc_rk35xx_pdata,
|
||||
.flags = RK_PLATFROM | RK_DLL_CMD_OUT | RK_TAP_VALUE_SEL,
|
||||
.hs200_tx_tap = 12,
|
||||
.hs400_tx_tap = 6,
|
||||
.hs400_cmd_tap = 6,
|
||||
.hs400_strbin_tap = 3,
|
||||
.ddr50_strbin_delay_num = 10,
|
||||
};
|
||||
|
||||
static const struct of_device_id sdhci_dwcmshc_dt_ids[] = {
|
||||
{
|
||||
.compatible = "snps,dwcmshc-sdhci",
|
||||
.data = &dwcmshc_drvdata,
|
||||
.compatible = "rockchip,rk3588-dwcmshc",
|
||||
.data = &rk3588_drvdata,
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,dwcmshc-sdhci",
|
||||
.compatible = "rockchip,rk3568-dwcmshc",
|
||||
.data = &rk3568_drvdata,
|
||||
},
|
||||
{
|
||||
@@ -493,17 +545,35 @@ static const struct of_device_id sdhci_dwcmshc_dt_ids[] = {
|
||||
.data = &rk3528_drvdata,
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,rk3588-dwcmshc",
|
||||
.data = &rk3588_drvdata,
|
||||
.compatible = "rockchip,rk3562-dwcmshc",
|
||||
.data = &rk3562_drvdata,
|
||||
},
|
||||
{
|
||||
.compatible = "snps,dwcmshc-sdhci",
|
||||
.data = &dwcmshc_drvdata,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id sdhci_dwcmshc_acpi_ids[] = {
|
||||
{
|
||||
.id = "MLNXBF30",
|
||||
.driver_data = (kernel_ulong_t)&sdhci_dwcmshc_bf3_pdata,
|
||||
},
|
||||
{}
|
||||
};
|
||||
#endif
|
||||
|
||||
static int dwcmshc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct sdhci_pltfm_host *pltfm_host;
|
||||
struct sdhci_host *host;
|
||||
struct dwcmshc_priv *priv;
|
||||
struct rk35xx_priv *rk_priv = NULL;
|
||||
const struct sdhci_pltfm_data *pltfm_data;
|
||||
const struct dwcmshc_driver_data *drv_data;
|
||||
struct mmc_hsq *hsq;
|
||||
int err;
|
||||
@@ -514,8 +584,9 @@ static int dwcmshc_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "Error: No device match data found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
pltfm_data = drv_data->pdata;
|
||||
|
||||
host = sdhci_pltfm_init(pdev, drv_data->pdata,
|
||||
host = sdhci_pltfm_init(pdev, pltfm_data,
|
||||
sizeof(struct dwcmshc_priv));
|
||||
if (IS_ERR(host))
|
||||
return PTR_ERR(host);
|
||||
@@ -523,30 +594,26 @@ static int dwcmshc_probe(struct platform_device *pdev)
|
||||
/*
|
||||
* extra adma table cnt for cross 128M boundary handling.
|
||||
*/
|
||||
extra = DIV_ROUND_UP_ULL(dma_get_required_mask(&pdev->dev), SZ_128M);
|
||||
extra = DIV_ROUND_UP_ULL(dma_get_required_mask(dev), SZ_128M);
|
||||
if (extra > SDHCI_MAX_SEGS)
|
||||
extra = SDHCI_MAX_SEGS;
|
||||
host->adma_table_cnt += extra;
|
||||
|
||||
pltfm_host = sdhci_priv(host);
|
||||
priv = sdhci_pltfm_priv(pltfm_host);
|
||||
priv->drv_data = drv_data;
|
||||
|
||||
priv->acpi_en = has_acpi_companion(&pdev->dev);
|
||||
|
||||
if (!priv->acpi_en) {
|
||||
priv->reset = devm_reset_control_array_get_exclusive(&pdev->dev);
|
||||
pltfm_host->clk = devm_clk_get(&pdev->dev, "core");
|
||||
if (dev->of_node) {
|
||||
pltfm_host->clk = devm_clk_get(dev, "core");
|
||||
if (IS_ERR(pltfm_host->clk)) {
|
||||
err = PTR_ERR(pltfm_host->clk);
|
||||
dev_err(&pdev->dev, "failed to get core clk: %d\n", err);
|
||||
dev_err(dev, "failed to get core clk: %d\n", err);
|
||||
goto free_pltfm;
|
||||
}
|
||||
err = clk_prepare_enable(pltfm_host->clk);
|
||||
if (err)
|
||||
goto free_pltfm;
|
||||
|
||||
priv->bus_clk = devm_clk_get(&pdev->dev, "bus");
|
||||
priv->bus_clk = devm_clk_get(dev, "bus");
|
||||
if (!IS_ERR(priv->bus_clk))
|
||||
clk_prepare_enable(priv->bus_clk);
|
||||
}
|
||||
@@ -557,6 +624,9 @@ static int dwcmshc_probe(struct platform_device *pdev)
|
||||
|
||||
sdhci_get_of_property(pdev);
|
||||
|
||||
priv->vendor_specific_area1 =
|
||||
sdhci_readl(host, DWCMSHC_P_VENDOR_AREA1) & DWCMSHC_AREA1_MASK;
|
||||
|
||||
host->mmc_host_ops.request = dwcmshc_request;
|
||||
host->mmc_host_ops.hs400_enhanced_strobe = dwcmshc_hs400_enhanced_strobe;
|
||||
|
||||
@@ -570,20 +640,42 @@ static int dwcmshc_probe(struct platform_device *pdev)
|
||||
if (err)
|
||||
goto err_clk;
|
||||
|
||||
err = sdhci_add_host(host);
|
||||
if (err)
|
||||
goto err_clk;
|
||||
|
||||
if (drv_data->flags & RK_PLATFROM) {
|
||||
priv->hs200_rx_tap = 0;
|
||||
if (drv_data->flags & RK_RXCLK_SW_TUNING)
|
||||
host->mmc_host_ops.execute_tuning = dwcmshc_rk_execute_tuning;
|
||||
err = rockchip_pltf_init(host, priv);
|
||||
rk_priv = devm_kzalloc(&pdev->dev, sizeof(struct rk35xx_priv), GFP_KERNEL);
|
||||
if (!rk_priv) {
|
||||
err = -ENOMEM;
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
rk_priv->drv_data = drv_data;
|
||||
rk_priv->acpi_en = has_acpi_companion(&pdev->dev);
|
||||
|
||||
if (of_device_is_compatible(pdev->dev.of_node, "rockchip,rk3588-dwcmshc"))
|
||||
rk_priv->devtype = DWCMSHC_RK3588;
|
||||
else
|
||||
rk_priv->devtype = DWCMSHC_RK3568;
|
||||
|
||||
priv->priv = rk_priv;
|
||||
|
||||
err = dwcmshc_rk35xx_init(host, priv);
|
||||
if (err)
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
if (!priv->acpi_en) {
|
||||
host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
|
||||
|
||||
err = sdhci_setup_host(host);
|
||||
if (err)
|
||||
goto err_clk;
|
||||
|
||||
if (rk_priv)
|
||||
dwcmshc_rk35xx_postinit(host, priv);
|
||||
|
||||
err = __sdhci_add_host(host);
|
||||
if (err)
|
||||
goto err_setup_host;
|
||||
|
||||
if (rk_priv && !rk_priv->acpi_en) {
|
||||
pm_runtime_get_noresume(&pdev->dev);
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
@@ -594,10 +686,14 @@ static int dwcmshc_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
|
||||
err_setup_host:
|
||||
sdhci_cleanup_host(host);
|
||||
err_clk:
|
||||
clk_disable_unprepare(pltfm_host->clk);
|
||||
clk_disable_unprepare(priv->bus_clk);
|
||||
clk_bulk_disable_unprepare(ROCKCHIP_MAX_CLKS, priv->rockchip_clks);
|
||||
if (rk_priv)
|
||||
clk_bulk_disable_unprepare(RK35xx_MAX_CLKS,
|
||||
rk_priv->rockchip_clks);
|
||||
free_pltfm:
|
||||
sdhci_pltfm_free(pdev);
|
||||
return err;
|
||||
@@ -608,13 +704,15 @@ static int dwcmshc_remove(struct platform_device *pdev)
|
||||
struct sdhci_host *host = platform_get_drvdata(pdev);
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
||||
struct rk35xx_priv *rk_priv = priv->priv;
|
||||
|
||||
sdhci_remove_host(host, 0);
|
||||
|
||||
clk_disable_unprepare(pltfm_host->clk);
|
||||
clk_disable_unprepare(priv->bus_clk);
|
||||
clk_bulk_disable_unprepare(ROCKCHIP_MAX_CLKS, priv->rockchip_clks);
|
||||
|
||||
if (rk_priv)
|
||||
clk_bulk_disable_unprepare(RK35xx_MAX_CLKS,
|
||||
rk_priv->rockchip_clks);
|
||||
sdhci_pltfm_free(pdev);
|
||||
|
||||
return 0;
|
||||
@@ -626,6 +724,7 @@ static int dwcmshc_suspend(struct device *dev)
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
||||
struct rk35xx_priv *rk_priv = priv->priv;
|
||||
int ret;
|
||||
|
||||
mmc_hsq_suspend(host->mmc);
|
||||
@@ -638,7 +737,10 @@ static int dwcmshc_suspend(struct device *dev)
|
||||
if (!IS_ERR(priv->bus_clk))
|
||||
clk_disable_unprepare(priv->bus_clk);
|
||||
|
||||
clk_bulk_disable_unprepare(ROCKCHIP_MAX_CLKS, priv->rockchip_clks);
|
||||
if (rk_priv)
|
||||
clk_bulk_disable_unprepare(RK35xx_MAX_CLKS,
|
||||
rk_priv->rockchip_clks);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -647,6 +749,7 @@ static int dwcmshc_resume(struct device *dev)
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
||||
struct rk35xx_priv *rk_priv = priv->priv;
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(pltfm_host->clk);
|
||||
@@ -659,9 +762,12 @@ static int dwcmshc_resume(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_bulk_prepare_enable(ROCKCHIP_MAX_CLKS, priv->rockchip_clks);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (rk_priv) {
|
||||
ret = clk_bulk_prepare_enable(RK35xx_MAX_CLKS,
|
||||
rk_priv->rockchip_clks);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sdhci_resume_host(host);
|
||||
if (ret)
|
||||
@@ -699,13 +805,13 @@ static const struct dev_pm_ops dwcmshc_pmops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(dwcmshc_suspend, dwcmshc_resume)
|
||||
SET_RUNTIME_PM_OPS(dwcmshc_runtime_suspend, dwcmshc_runtime_resume, NULL)
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids);
|
||||
|
||||
static struct platform_driver sdhci_dwcmshc_driver = {
|
||||
.driver = {
|
||||
.name = "sdhci-dwcmshc",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.of_match_table = sdhci_dwcmshc_dt_ids,
|
||||
.acpi_match_table = ACPI_PTR(sdhci_dwcmshc_acpi_ids),
|
||||
.pm = &dwcmshc_pmops,
|
||||
},
|
||||
.probe = dwcmshc_probe,
|
||||
|
||||
@@ -904,6 +904,7 @@ static int esdhc_signal_voltage_switch(struct mmc_host *mmc,
|
||||
scfg_node = of_find_matching_node(NULL, scfg_device_ids);
|
||||
if (scfg_node)
|
||||
scfg_base = of_iomap(scfg_node, 0);
|
||||
of_node_put(scfg_node);
|
||||
if (scfg_base) {
|
||||
sdhciovselcr = SDHCIOVSELCR_TGLEN |
|
||||
SDHCIOVSELCR_VSELVAL;
|
||||
|
||||
@@ -967,6 +967,12 @@ static bool glk_broken_cqhci(struct sdhci_pci_slot *slot)
|
||||
dmi_match(DMI_SYS_VENDOR, "IRBIS"));
|
||||
}
|
||||
|
||||
static bool jsl_broken_hs400es(struct sdhci_pci_slot *slot)
|
||||
{
|
||||
return slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_JSL_EMMC &&
|
||||
dmi_match(DMI_BIOS_VENDOR, "ASUSTeK COMPUTER INC.");
|
||||
}
|
||||
|
||||
static int glk_emmc_probe_slot(struct sdhci_pci_slot *slot)
|
||||
{
|
||||
int ret = byt_emmc_probe_slot(slot);
|
||||
@@ -975,9 +981,11 @@ static int glk_emmc_probe_slot(struct sdhci_pci_slot *slot)
|
||||
slot->host->mmc->caps2 |= MMC_CAP2_CQE;
|
||||
|
||||
if (slot->chip->pdev->device != PCI_DEVICE_ID_INTEL_GLK_EMMC) {
|
||||
slot->host->mmc->caps2 |= MMC_CAP2_HS400_ES,
|
||||
slot->host->mmc_host_ops.hs400_enhanced_strobe =
|
||||
intel_hs400_enhanced_strobe;
|
||||
if (!jsl_broken_hs400es(slot)) {
|
||||
slot->host->mmc->caps2 |= MMC_CAP2_HS400_ES;
|
||||
slot->host->mmc_host_ops.hs400_enhanced_strobe =
|
||||
intel_hs400_enhanced_strobe;
|
||||
}
|
||||
slot->host->mmc->caps2 |= MMC_CAP2_CQE_DCMD;
|
||||
}
|
||||
|
||||
@@ -1791,6 +1799,8 @@ static int amd_probe(struct sdhci_pci_chip *chip)
|
||||
}
|
||||
}
|
||||
|
||||
pci_dev_put(smbus_dev);
|
||||
|
||||
if (gen == AMD_CHIPSET_BEFORE_ML || gen == AMD_CHIPSET_CZ)
|
||||
chip->quirks2 |= SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD;
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#define O2_SD_CAPS 0xE0
|
||||
#define O2_SD_ADMA1 0xE2
|
||||
#define O2_SD_ADMA2 0xE7
|
||||
#define O2_SD_MISC_CTRL2 0xF0
|
||||
#define O2_SD_INF_MOD 0xF1
|
||||
#define O2_SD_MISC_CTRL4 0xFC
|
||||
#define O2_SD_MISC_CTRL 0x1C0
|
||||
@@ -147,6 +148,8 @@ static int sdhci_o2_get_cd(struct mmc_host *mmc)
|
||||
|
||||
if (!(sdhci_readw(host, O2_PLL_DLL_WDT_CONTROL1) & O2_PLL_LOCK_STATUS))
|
||||
sdhci_o2_enable_internal_clock(host);
|
||||
else
|
||||
sdhci_o2_wait_card_detect_stable(host);
|
||||
|
||||
return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
|
||||
}
|
||||
@@ -820,6 +823,12 @@ static int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip)
|
||||
/* Set Tuning Windows to 5 */
|
||||
pci_write_config_byte(chip->pdev,
|
||||
O2_SD_TUNING_CTRL, 0x55);
|
||||
//Adjust 1st and 2nd CD debounce time
|
||||
pci_read_config_dword(chip->pdev, O2_SD_MISC_CTRL2, &scratch_32);
|
||||
scratch_32 &= 0xFFE7FFFF;
|
||||
scratch_32 |= 0x00180000;
|
||||
pci_write_config_dword(chip->pdev, O2_SD_MISC_CTRL2, scratch_32);
|
||||
pci_write_config_dword(chip->pdev, O2_SD_DETECT_SETTING, 1);
|
||||
/* Lock WP */
|
||||
ret = pci_read_config_byte(chip->pdev,
|
||||
O2_SD_LOCK_WP, &scratch);
|
||||
|
||||
@@ -296,7 +296,7 @@ static unsigned int sdhci_sprd_get_max_clock(struct sdhci_host *host)
|
||||
|
||||
static unsigned int sdhci_sprd_get_min_clock(struct sdhci_host *host)
|
||||
{
|
||||
return 400000;
|
||||
return 100000;
|
||||
}
|
||||
|
||||
static void sdhci_sprd_set_uhs_signaling(struct sdhci_host *host,
|
||||
@@ -457,7 +457,7 @@ static int sdhci_sprd_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
}
|
||||
|
||||
if (IS_ERR(sprd_host->pinctrl))
|
||||
return 0;
|
||||
goto reset;
|
||||
|
||||
switch (ios->signal_voltage) {
|
||||
case MMC_SIGNAL_VOLTAGE_180:
|
||||
@@ -485,6 +485,8 @@ static int sdhci_sprd_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
|
||||
/* Wait for 300 ~ 500 us for pin state stable */
|
||||
usleep_range(300, 500);
|
||||
|
||||
reset:
|
||||
sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/ktime.h>
|
||||
|
||||
#include "sdhci-cqhci.h"
|
||||
#include "sdhci-pltfm.h"
|
||||
#include "cqhci.h"
|
||||
|
||||
@@ -361,7 +362,7 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
|
||||
const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
|
||||
u32 misc_ctrl, clk_ctrl, pad_ctrl;
|
||||
|
||||
sdhci_reset(host, mask);
|
||||
sdhci_and_cqhci_reset(host, mask);
|
||||
|
||||
if (!(mask & SDHCI_RESET_ALL))
|
||||
return;
|
||||
@@ -760,7 +761,7 @@ static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
*/
|
||||
host_clk = tegra_host->ddr_signaling ? clock * 2 : clock;
|
||||
clk_set_rate(pltfm_host->clk, host_clk);
|
||||
tegra_host->curr_clk_rate = host_clk;
|
||||
tegra_host->curr_clk_rate = clk_get_rate(pltfm_host->clk);
|
||||
if (tegra_host->ddr_signaling)
|
||||
host->max_clk = host_clk;
|
||||
else
|
||||
|
||||
@@ -240,16 +240,6 @@ static void xenon_voltage_switch(struct sdhci_host *host)
|
||||
{
|
||||
/* Wait for 5ms after set 1.8V signal enable bit */
|
||||
usleep_range(5000, 5500);
|
||||
|
||||
/*
|
||||
* For some reason the controller's Host Control2 register reports
|
||||
* the bit representing 1.8V signaling as 0 when read after it was
|
||||
* written as 1. Subsequent read reports 1.
|
||||
*
|
||||
* Since this may cause some issues, do an empty read of the Host
|
||||
* Control2 register here to circumvent this.
|
||||
*/
|
||||
sdhci_readw(host, SDHCI_HOST_CONTROL2);
|
||||
}
|
||||
|
||||
static const struct sdhci_ops sdhci_xenon_ops = {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <linux/sys_soc.h>
|
||||
|
||||
#include "cqhci.h"
|
||||
#include "sdhci-cqhci.h"
|
||||
#include "sdhci-pltfm.h"
|
||||
|
||||
/* CTL_CFG Registers */
|
||||
@@ -147,6 +148,9 @@ struct sdhci_am654_data {
|
||||
int drv_strength;
|
||||
int strb_sel;
|
||||
u32 flags;
|
||||
u32 quirks;
|
||||
|
||||
#define SDHCI_AM654_QUIRK_FORCE_CDTEST BIT(0)
|
||||
};
|
||||
|
||||
struct sdhci_am654_driver_data {
|
||||
@@ -369,6 +373,21 @@ static void sdhci_am654_write_b(struct sdhci_host *host, u8 val, int reg)
|
||||
}
|
||||
}
|
||||
|
||||
static void sdhci_am654_reset(struct sdhci_host *host, u8 mask)
|
||||
{
|
||||
u8 ctrl;
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host);
|
||||
|
||||
sdhci_and_cqhci_reset(host, mask);
|
||||
|
||||
if (sdhci_am654->quirks & SDHCI_AM654_QUIRK_FORCE_CDTEST) {
|
||||
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
|
||||
ctrl |= SDHCI_CTRL_CDTEST_INS | SDHCI_CTRL_CDTEST_EN;
|
||||
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
|
||||
}
|
||||
}
|
||||
|
||||
static int sdhci_am654_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
||||
{
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
@@ -446,7 +465,7 @@ static struct sdhci_ops sdhci_am654_ops = {
|
||||
.set_clock = sdhci_am654_set_clock,
|
||||
.write_b = sdhci_am654_write_b,
|
||||
.irq = sdhci_am654_cqhci_irq,
|
||||
.reset = sdhci_reset,
|
||||
.reset = sdhci_and_cqhci_reset,
|
||||
};
|
||||
|
||||
static const struct sdhci_pltfm_data sdhci_am654_pdata = {
|
||||
@@ -476,7 +495,7 @@ static struct sdhci_ops sdhci_j721e_8bit_ops = {
|
||||
.set_clock = sdhci_am654_set_clock,
|
||||
.write_b = sdhci_am654_write_b,
|
||||
.irq = sdhci_am654_cqhci_irq,
|
||||
.reset = sdhci_reset,
|
||||
.reset = sdhci_and_cqhci_reset,
|
||||
};
|
||||
|
||||
static const struct sdhci_pltfm_data sdhci_j721e_8bit_pdata = {
|
||||
@@ -500,7 +519,7 @@ static struct sdhci_ops sdhci_j721e_4bit_ops = {
|
||||
.set_clock = sdhci_j721e_4bit_set_clock,
|
||||
.write_b = sdhci_am654_write_b,
|
||||
.irq = sdhci_am654_cqhci_irq,
|
||||
.reset = sdhci_reset,
|
||||
.reset = sdhci_am654_reset,
|
||||
};
|
||||
|
||||
static const struct sdhci_pltfm_data sdhci_j721e_4bit_pdata = {
|
||||
@@ -719,6 +738,9 @@ static int sdhci_am654_get_of_property(struct platform_device *pdev,
|
||||
device_property_read_u32(dev, "ti,clkbuf-sel",
|
||||
&sdhci_am654->clkbuf_sel);
|
||||
|
||||
if (device_property_read_bool(dev, "ti,fails-without-test-cd"))
|
||||
sdhci_am654->quirks |= SDHCI_AM654_QUIRK_FORCE_CDTEST;
|
||||
|
||||
sdhci_get_of_property(pdev);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -849,7 +849,7 @@ static int wmt_mci_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(priv->clk_sdmmc)) {
|
||||
dev_err(&pdev->dev, "Error getting clock\n");
|
||||
ret = PTR_ERR(priv->clk_sdmmc);
|
||||
goto fail5;
|
||||
goto fail5_and_a_half;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(priv->clk_sdmmc);
|
||||
@@ -866,6 +866,9 @@ static int wmt_mci_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
fail6:
|
||||
clk_put(priv->clk_sdmmc);
|
||||
fail5_and_a_half:
|
||||
dma_free_coherent(&pdev->dev, mmc->max_blk_count * 16,
|
||||
priv->dma_desc_buffer, priv->dma_desc_device_addr);
|
||||
fail5:
|
||||
free_irq(dma_irq, priv);
|
||||
fail4:
|
||||
|
||||
Reference in New Issue
Block a user