Loading drivers/mmc/core/block.c +1 −2 Original line number Diff line number Diff line Loading @@ -1506,7 +1506,6 @@ 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); pr_debug("%s: CQE recovery done\n", mmc_hostname(host)); Loading drivers/mmc/core/bus.c +2 −0 Original line number Diff line number Diff line Loading @@ -420,6 +420,8 @@ void mmc_remove_card(struct mmc_card *card) device_del(&card->dev); of_node_put(card->dev.of_node); } if (host->ops->exit_dbg_mode) host->ops->exit_dbg_mode(host); put_device(&card->dev); } Loading drivers/mmc/core/mmc.c +7 −0 Original line number Diff line number Diff line Loading @@ -2306,6 +2306,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (!oldcard) host->card = card; if (host->ops->enter_dbg_mode) host->ops->enter_dbg_mode(host); return 0; Loading Loading @@ -2909,6 +2911,11 @@ static int _mmc_hw_reset(struct mmc_host *host) /* If the card accept RST_n signal, send it. */ mmc_set_clock(host, host->f_init); host->ops->hw_reset(host); /* * Do a brute force power cycle as some controller do not * have gpio support to power cycle card */ mmc_power_cycle(host, card->ocr); /* Set initial state and call mmc_set_ios */ mmc_set_initial_state(host); } else { Loading drivers/mmc/host/sdhci-msm.c +238 −3 Original line number Diff line number Diff line Loading @@ -1210,6 +1210,78 @@ static void sdhci_msm_set_mmc_drv_type(struct sdhci_host *host, u32 opcode, drv_type); } #define IPCAT_MINOR_MASK(val) ((val & 0x0fff0000) >> 0x10) /* Enter sdcc debug mode */ void sdhci_msm_enter_dbg_mode(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; struct platform_device *pdev = msm_host->pdev; u32 enable_dbg_feature = 0; u32 minor; minor = IPCAT_MINOR_MASK(readl_relaxed(host->ioaddr + SDCC_IP_CATALOG)); if (minor < 2 || msm_host->debug_mode_enabled) return; /* Enable debug mode */ writel_relaxed(ENABLE_DBG, host->ioaddr + SDCC_TESTBUS_CONFIG); writel_relaxed(DUMMY, host->ioaddr + SDCC_DEBUG_EN_DIS_REG); writel_relaxed((readl_relaxed(host->ioaddr + SDCC_TESTBUS_CONFIG) | TESTBUS_EN), host->ioaddr + SDCC_TESTBUS_CONFIG); if (minor >= 2) enable_dbg_feature |= FSM_HISTORY | AUTO_RECOVERY_DISABLE | MM_TRIGGER_DISABLE | IIB_EN; /* Enable particular feature */ writel_relaxed((readl_relaxed(host->ioaddr + SDCC_DEBUG_FEATURE_CFG_REG) | enable_dbg_feature), host->ioaddr + SDCC_DEBUG_FEATURE_CFG_REG); /* Read back to ensure write went through */ readl_relaxed(host->ioaddr + SDCC_DEBUG_FEATURE_CFG_REG); msm_host->debug_mode_enabled = true; dev_info(&pdev->dev, "Debug feature enabled 0x%08x\n", readl_relaxed(host->ioaddr + SDCC_DEBUG_FEATURE_CFG_REG)); } /* Exit sdcc debug mode */ void sdhci_msm_exit_dbg_mode(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; struct platform_device *pdev = msm_host->pdev; u32 minor; minor = IPCAT_MINOR_MASK(readl_relaxed(host->ioaddr + SDCC_IP_CATALOG)); if (minor < 2 || !msm_host->debug_mode_enabled) return; /* Exit debug mode */ writel_relaxed(DISABLE_DBG, host->ioaddr + SDCC_TESTBUS_CONFIG); writel_relaxed(DUMMY, host->ioaddr + SDCC_DEBUG_EN_DIS_REG); msm_host->debug_mode_enabled = false; dev_dbg(&pdev->dev, "Debug feature disabled 0x%08x\n", readl_relaxed(host->ioaddr + SDCC_DEBUG_FEATURE_CFG_REG)); } int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) { unsigned long flags; Loading Loading @@ -1244,6 +1316,7 @@ int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) */ if (msm_host->tuning_in_progress) return 0; sdhci_msm_exit_dbg_mode(host); msm_host->tuning_in_progress = true; pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__); Loading Loading @@ -1437,6 +1510,7 @@ int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) kfree: kfree(data_buf); out: sdhci_msm_enter_dbg_mode(host); spin_lock_irqsave(&host->lock, flags); if (!rc) msm_host->tuning_done = true; Loading Loading @@ -2020,6 +2094,23 @@ static int sdhci_msm_parse_regulator_info(struct device *dev, return -EINVAL; } int sdhci_msm_parse_reset_data(struct device *dev, struct sdhci_msm_host *msm_host) { int ret = 0; msm_host->core_reset = devm_reset_control_get(dev, "core_reset"); if (IS_ERR(msm_host->core_reset)) { ret = PTR_ERR(msm_host->core_reset); dev_err(dev, "core_reset unavailable,err = %d\n", ret); msm_host->core_reset = NULL; } return ret; } /* Parse platform data */ static struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev, Loading @@ -2037,6 +2128,7 @@ struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev, enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW; int bus_clk_table_len; u32 *bus_clk_table = NULL; int ret = 0; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) Loading Loading @@ -2173,6 +2265,9 @@ struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev, if (sdhci_msm_dt_parse_hsr_info(dev, msm_host)) goto out; ret = sdhci_msm_parse_reset_data(dev, msm_host); if (ret) dev_err(dev, "Reset data parsing error\n"); return pdata; out: Loading Loading @@ -2263,11 +2358,21 @@ static u32 sdhci_msm_cqe_irq(struct sdhci_host *host, u32 intmask) { int cmd_error = 0; int data_error = 0; u32 mask; if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) return intmask; cqhci_irq(host->mmc, intmask, cmd_error, data_error); /* * Clear selected interrupts in err case. * as earlier driver skipped */ if (data_error || cmd_error) { mask = intmask & host->cqe_ier; sdhci_writel(host, mask, SDHCI_INT_STATUS); } return 0; } Loading Loading @@ -3273,7 +3378,8 @@ static void sdhci_msm_registers_save(struct sdhci_host *host) const struct sdhci_msm_offset *msm_host_offset = msm_host->offset; if (!msm_host->regs_restore.is_supported) if (!msm_host->regs_restore.is_supported && !msm_host->reg_store) return; msm_host->regs_restore.vendor_func = readl_relaxed(host->ioaddr + Loading Loading @@ -3337,8 +3443,9 @@ static void sdhci_msm_registers_restore(struct sdhci_host *host) msm_host->offset; struct mmc_ios ios = host->mmc->ios; if (!msm_host->regs_restore.is_supported || !msm_host->regs_restore.is_valid) if ((!msm_host->regs_restore.is_supported || !msm_host->regs_restore.is_valid) && !msm_host->reg_store) return; writel_relaxed(0, host->ioaddr + msm_host_offset->CORE_PWRCTL_MASK); Loading Loading @@ -3995,6 +4102,73 @@ static void sdhci_msm_cqe_dump_debug_ram(struct sdhci_host *host) pr_err("-------------------------\n"); } #define DUMP_FSM readl_relaxed(host->ioaddr + SDCC_DEBUG_FSM_TRACE_RD_REG) #define MAX_FSM 16 void sdhci_msm_dump_fsm_history(struct sdhci_host *host) { u32 sel_fsm; pr_err("----------- FSM REGISTER DUMP -----------\n"); /* select fsm to dump */ for (sel_fsm = 0; sel_fsm <= MAX_FSM; sel_fsm++) { writel_relaxed(sel_fsm, host->ioaddr + SDCC_DEBUG_FSM_TRACE_CFG_REG); pr_err(": selected fsm is 0x%08x\n", readl_relaxed(host->ioaddr + SDCC_DEBUG_FSM_TRACE_CFG_REG)); /* dump selected fsm history */ pr_err("0x%08x 0x%08x 0x%08x 0x%08x\n", readl_relaxed(host->ioaddr + SDCC_DEBUG_FSM_TRACE_RD_REG), readl_relaxed(host->ioaddr + SDCC_DEBUG_FSM_TRACE_RD_REG), readl_relaxed(host->ioaddr + SDCC_DEBUG_FSM_TRACE_RD_REG), readl_relaxed(host->ioaddr + SDCC_DEBUG_FSM_TRACE_RD_REG)); pr_err("0x%08x 0x%08x 0x%08x\n", readl_relaxed(host->ioaddr + SDCC_DEBUG_FSM_TRACE_RD_REG), readl_relaxed(host->ioaddr + SDCC_DEBUG_FSM_TRACE_RD_REG), readl_relaxed(host->ioaddr + SDCC_DEBUG_FSM_TRACE_RD_REG)); } /* Flush all fsm history */ writel_relaxed(DUMMY, host->ioaddr + SDCC_DEBUG_FSM_TRACE_FIFO_FLUSH_REG); /* Exit from Auto recovery disable to move FSMs to idle state */ writel_relaxed(DUMMY, host->ioaddr + SDCC_DEBUG_ERROR_STATE_EXIT_REG); } void sdhci_msm_dump_desc_history(struct sdhci_host *host) { pr_err("----------- DESC HISTORY DUMP -----------\n"); pr_err("Current Desc Addr: 0x%08x | Info: 0x%08x\n", readl_relaxed(host->ioaddr + SDCC_CURR_DESC_ADDR), readl_relaxed(host->ioaddr + SDCC_CURR_DESC_INFO)); pr_err("Processed Desc1 Addr: 0x%08x | Info: 0x%08x\n", readl_relaxed(host->ioaddr + SDCC_PROC_DESC0_ADDR), readl_relaxed(host->ioaddr + SDCC_PROC_DESC0_INFO)); pr_err("Processed Desc2 Addr: 0x%08x | Info: 0x%08x\n", readl_relaxed(host->ioaddr + SDCC_PROC_DESC1_ADDR), readl_relaxed(host->ioaddr + SDCC_PROC_DESC1_INFO)); } void sdhci_msm_dump_iib(struct sdhci_host *host) { u32 iter; pr_err("----------- IIB HISTORY DUMP -----------\n"); for (iter = 0; iter < 8; iter++) pr_err("0x%08x\n", readl_relaxed(host->ioaddr + SDCC_DEBUG_IIB_REG + (iter * 4))); } void sdhci_msm_dump_vendor_regs(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); Loading Loading @@ -4052,6 +4226,14 @@ void sdhci_msm_dump_vendor_regs(struct sdhci_host *host) msm_host_offset->CORE_VENDOR_SPEC_FUNC2), readl_relaxed(host->ioaddr + msm_host_offset->CORE_VENDOR_SPEC3)); if (msm_host->debug_mode_enabled) { sdhci_msm_dump_fsm_history(host); sdhci_msm_dump_desc_history(host); } /* Debug feature enable not must for iib */ sdhci_msm_dump_iib(host); /* * tbsel indicates [2:0] bits and tbsel2 indicates [7:4] bits * of CORE_TESTBUS_CONFIG register. Loading Loading @@ -4743,6 +4925,54 @@ static int sdhci_msm_notify_load(struct sdhci_host *host, enum mmc_load state) return 0; } static void sdhci_msm_hw_reset(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; struct platform_device *pdev = msm_host->pdev; int ret = -ENOTSUPP; if (!msm_host->core_reset) { dev_err(&pdev->dev, "%s: failed, err = %d\n", __func__, ret); return; } if (!msm_host->debug_mode_enabled) return; msm_host->reg_store = true; sdhci_msm_exit_dbg_mode(host); sdhci_msm_registers_save(host); if (host->mmc->caps2 & MMC_CAP2_CQE) { host->mmc->cqe_ops->cqe_disable(host->mmc); host->mmc->cqe_enabled = false; } ret = reset_control_assert(msm_host->core_reset); if (ret) { dev_err(&pdev->dev, "%s: core_reset assert failed, err = %d\n", __func__, ret); goto out; } /* * 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(msm_host->core_reset); if (ret) dev_err(&pdev->dev, "%s: core_reset deassert failed, err = %d\n", __func__, ret); sdhci_msm_registers_restore(host); msm_host->reg_store = false; out: return; } static struct sdhci_ops sdhci_msm_ops = { .crypto_engine_cfg = sdhci_msm_ice_cfg, .crypto_engine_cfg_end = sdhci_msm_ice_cfg_end, Loading Loading @@ -4770,6 +5000,9 @@ static struct sdhci_ops sdhci_msm_ops = { .get_current_limit = sdhci_msm_get_current_limit, .notify_load = sdhci_msm_notify_load, .irq = sdhci_msm_cqe_irq, .enter_dbg_mode = sdhci_msm_enter_dbg_mode, .exit_dbg_mode = sdhci_msm_exit_dbg_mode, .hw_reset = sdhci_msm_hw_reset, }; static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host, Loading Loading @@ -5411,6 +5644,8 @@ static int sdhci_msm_probe(struct platform_device *pdev) msm_host->mmc->caps2 |= MMC_CAP2_MAX_DISCARD_SIZE; msm_host->mmc->caps2 |= MMC_CAP2_SLEEP_AWAKE; msm_host->mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ; if (msm_host->core_reset) msm_host->mmc->caps |= MMC_CAP_HW_RESET; if (msm_host->pdata->nonremovable) msm_host->mmc->caps |= MMC_CAP_NONREMOVABLE; Loading drivers/mmc/host/sdhci-msm.h +65 −0 Original line number Diff line number Diff line Loading @@ -9,8 +9,70 @@ #include <linux/mmc/mmc.h> #include <linux/pm_qos.h> #include <linux/reset.h> #include "sdhci-pltfm.h" /* check IP CATALOG version */ #define SDCC_IP_CATALOG 0x328 /* DBG register offsets */ #define SDCC_TESTBUS_CONFIG 0x32C #define SDCC_DEBUG_EN_DIS_REG 0x390 #define SDCC_DEBUG_FEATURE_CFG_REG 0x394 #define SDCC_DEBUG_FSM_TRACE_CFG_REG 0x398 #define SDCC_DEBUG_FSM_TRACE_RD_REG 0x39C #define SDCC_DEBUG_FSM_TRACE_FIFO_FLUSH_REG 0x3A0 #define SDCC_DEBUG_PANIC_ERROR_EN_REG 0x3A4 #define SDCC_DEBUG_ERROR_STATE_EXIT_REG 0x3B8 #define SDCC_CURR_DESC_ADDR 0x3EC #define SDCC_CURR_DESC_INFO 0x3F0 #define SDCC_PROC_DESC0_ADDR 0x3E4 #define SDCC_PROC_DESC0_INFO 0x3E8 #define SDCC_PROC_DESC1_ADDR 0x3DC #define SDCC_PROC_DESC1_INFO 0x3E0 #define SDCC_DEBUG_IIB_REG 0x980 #define SDCC_DEBUG_MASK_PATTERN_REG 0x3C0 #define SDCC_DEBUG_MATCH_PATTERN_REG 0x3C4 #define SDCC_DEBUG_MM_TB_CFG_REG 0x3BC #define ENABLE_DBG 0x35350000 #define DISABLE_DBG 0x26260000 #define DUMMY 0x1 /* value doesn't matter */ /* Panic on Err */ #define BOOT_ACK_REC_EN BIT(0) #define BOOT_ACK_ERR_EN BIT(1) #define BOOT_TIMEOUT_EN BIT(2) #define AUTO_CMD19_TOUT_EN BIT(3) #define STBITE_EN BIT(4) #define CTOUT_EN BIT(5) #define CCRCF_EN BIT(6) #define CMD_END_BIT_ERR_EN BIT(7) #define CMD_INDEX_ERR_EN BIT(8) #define DTOUT_EN BIT(9) #define DCRCF_EN BIT(10) #define DATA_END_BIT_ERR_EN BIT(11) #define CMDQ_HALT_ACK_INT_EN BIT(16) #define CMDQ_TASK_COMPLETED_INT_EN BIT(17) #define CMDQ_RESP_ERR_INT_EN BIT(18) #define CMDQ_TASK_CLEARED_INT_EN BIT(19) #define CMDQ_GENERAL_CRYPTO_ERROR_EN BIT(20) #define CMDQ_INVALID_CRYPTO_CFG_ERROR_EN BIT(21) #define CMDQ_DEVICE_EXCEPTION_INT_EN BIT(22) #define ADMA_ERROR_EXT_EN BIT(23) #define HC_NONCQ_ICE_INT_STATUS_MASKED_EN BIT(24) /* Select debug Feature */ #define FSM_HISTORY BIT(0) #define PANIC_ALERT BIT(1) #define AUTO_RECOVERY_DISABLE BIT(2) #define MM_TRIGGER_DISABLE BIT(3) #define DESC_HISTORY BIT(4) #define IIB_EN BIT(6) #define TESTBUS_EN BIT(31) /* This structure keeps information per regulator */ struct sdhci_msm_reg_data { /* voltage regulator handle */ Loading Loading @@ -267,6 +329,9 @@ struct sdhci_msm_host { struct sdhci_msm_dll_hsr *dll_hsr; struct sdhci_msm_ice_data ice; u32 ice_clk_rate; bool debug_mode_enabled; bool reg_store; struct reset_control *core_reset; }; extern char *saved_command_line; Loading Loading
drivers/mmc/core/block.c +1 −2 Original line number Diff line number Diff line Loading @@ -1506,7 +1506,6 @@ 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); pr_debug("%s: CQE recovery done\n", mmc_hostname(host)); Loading
drivers/mmc/core/bus.c +2 −0 Original line number Diff line number Diff line Loading @@ -420,6 +420,8 @@ void mmc_remove_card(struct mmc_card *card) device_del(&card->dev); of_node_put(card->dev.of_node); } if (host->ops->exit_dbg_mode) host->ops->exit_dbg_mode(host); put_device(&card->dev); } Loading
drivers/mmc/core/mmc.c +7 −0 Original line number Diff line number Diff line Loading @@ -2306,6 +2306,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (!oldcard) host->card = card; if (host->ops->enter_dbg_mode) host->ops->enter_dbg_mode(host); return 0; Loading Loading @@ -2909,6 +2911,11 @@ static int _mmc_hw_reset(struct mmc_host *host) /* If the card accept RST_n signal, send it. */ mmc_set_clock(host, host->f_init); host->ops->hw_reset(host); /* * Do a brute force power cycle as some controller do not * have gpio support to power cycle card */ mmc_power_cycle(host, card->ocr); /* Set initial state and call mmc_set_ios */ mmc_set_initial_state(host); } else { Loading
drivers/mmc/host/sdhci-msm.c +238 −3 Original line number Diff line number Diff line Loading @@ -1210,6 +1210,78 @@ static void sdhci_msm_set_mmc_drv_type(struct sdhci_host *host, u32 opcode, drv_type); } #define IPCAT_MINOR_MASK(val) ((val & 0x0fff0000) >> 0x10) /* Enter sdcc debug mode */ void sdhci_msm_enter_dbg_mode(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; struct platform_device *pdev = msm_host->pdev; u32 enable_dbg_feature = 0; u32 minor; minor = IPCAT_MINOR_MASK(readl_relaxed(host->ioaddr + SDCC_IP_CATALOG)); if (minor < 2 || msm_host->debug_mode_enabled) return; /* Enable debug mode */ writel_relaxed(ENABLE_DBG, host->ioaddr + SDCC_TESTBUS_CONFIG); writel_relaxed(DUMMY, host->ioaddr + SDCC_DEBUG_EN_DIS_REG); writel_relaxed((readl_relaxed(host->ioaddr + SDCC_TESTBUS_CONFIG) | TESTBUS_EN), host->ioaddr + SDCC_TESTBUS_CONFIG); if (minor >= 2) enable_dbg_feature |= FSM_HISTORY | AUTO_RECOVERY_DISABLE | MM_TRIGGER_DISABLE | IIB_EN; /* Enable particular feature */ writel_relaxed((readl_relaxed(host->ioaddr + SDCC_DEBUG_FEATURE_CFG_REG) | enable_dbg_feature), host->ioaddr + SDCC_DEBUG_FEATURE_CFG_REG); /* Read back to ensure write went through */ readl_relaxed(host->ioaddr + SDCC_DEBUG_FEATURE_CFG_REG); msm_host->debug_mode_enabled = true; dev_info(&pdev->dev, "Debug feature enabled 0x%08x\n", readl_relaxed(host->ioaddr + SDCC_DEBUG_FEATURE_CFG_REG)); } /* Exit sdcc debug mode */ void sdhci_msm_exit_dbg_mode(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; struct platform_device *pdev = msm_host->pdev; u32 minor; minor = IPCAT_MINOR_MASK(readl_relaxed(host->ioaddr + SDCC_IP_CATALOG)); if (minor < 2 || !msm_host->debug_mode_enabled) return; /* Exit debug mode */ writel_relaxed(DISABLE_DBG, host->ioaddr + SDCC_TESTBUS_CONFIG); writel_relaxed(DUMMY, host->ioaddr + SDCC_DEBUG_EN_DIS_REG); msm_host->debug_mode_enabled = false; dev_dbg(&pdev->dev, "Debug feature disabled 0x%08x\n", readl_relaxed(host->ioaddr + SDCC_DEBUG_FEATURE_CFG_REG)); } int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) { unsigned long flags; Loading Loading @@ -1244,6 +1316,7 @@ int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) */ if (msm_host->tuning_in_progress) return 0; sdhci_msm_exit_dbg_mode(host); msm_host->tuning_in_progress = true; pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__); Loading Loading @@ -1437,6 +1510,7 @@ int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode) kfree: kfree(data_buf); out: sdhci_msm_enter_dbg_mode(host); spin_lock_irqsave(&host->lock, flags); if (!rc) msm_host->tuning_done = true; Loading Loading @@ -2020,6 +2094,23 @@ static int sdhci_msm_parse_regulator_info(struct device *dev, return -EINVAL; } int sdhci_msm_parse_reset_data(struct device *dev, struct sdhci_msm_host *msm_host) { int ret = 0; msm_host->core_reset = devm_reset_control_get(dev, "core_reset"); if (IS_ERR(msm_host->core_reset)) { ret = PTR_ERR(msm_host->core_reset); dev_err(dev, "core_reset unavailable,err = %d\n", ret); msm_host->core_reset = NULL; } return ret; } /* Parse platform data */ static struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev, Loading @@ -2037,6 +2128,7 @@ struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev, enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW; int bus_clk_table_len; u32 *bus_clk_table = NULL; int ret = 0; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) Loading Loading @@ -2173,6 +2265,9 @@ struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev, if (sdhci_msm_dt_parse_hsr_info(dev, msm_host)) goto out; ret = sdhci_msm_parse_reset_data(dev, msm_host); if (ret) dev_err(dev, "Reset data parsing error\n"); return pdata; out: Loading Loading @@ -2263,11 +2358,21 @@ static u32 sdhci_msm_cqe_irq(struct sdhci_host *host, u32 intmask) { int cmd_error = 0; int data_error = 0; u32 mask; if (!sdhci_cqe_irq(host, intmask, &cmd_error, &data_error)) return intmask; cqhci_irq(host->mmc, intmask, cmd_error, data_error); /* * Clear selected interrupts in err case. * as earlier driver skipped */ if (data_error || cmd_error) { mask = intmask & host->cqe_ier; sdhci_writel(host, mask, SDHCI_INT_STATUS); } return 0; } Loading Loading @@ -3273,7 +3378,8 @@ static void sdhci_msm_registers_save(struct sdhci_host *host) const struct sdhci_msm_offset *msm_host_offset = msm_host->offset; if (!msm_host->regs_restore.is_supported) if (!msm_host->regs_restore.is_supported && !msm_host->reg_store) return; msm_host->regs_restore.vendor_func = readl_relaxed(host->ioaddr + Loading Loading @@ -3337,8 +3443,9 @@ static void sdhci_msm_registers_restore(struct sdhci_host *host) msm_host->offset; struct mmc_ios ios = host->mmc->ios; if (!msm_host->regs_restore.is_supported || !msm_host->regs_restore.is_valid) if ((!msm_host->regs_restore.is_supported || !msm_host->regs_restore.is_valid) && !msm_host->reg_store) return; writel_relaxed(0, host->ioaddr + msm_host_offset->CORE_PWRCTL_MASK); Loading Loading @@ -3995,6 +4102,73 @@ static void sdhci_msm_cqe_dump_debug_ram(struct sdhci_host *host) pr_err("-------------------------\n"); } #define DUMP_FSM readl_relaxed(host->ioaddr + SDCC_DEBUG_FSM_TRACE_RD_REG) #define MAX_FSM 16 void sdhci_msm_dump_fsm_history(struct sdhci_host *host) { u32 sel_fsm; pr_err("----------- FSM REGISTER DUMP -----------\n"); /* select fsm to dump */ for (sel_fsm = 0; sel_fsm <= MAX_FSM; sel_fsm++) { writel_relaxed(sel_fsm, host->ioaddr + SDCC_DEBUG_FSM_TRACE_CFG_REG); pr_err(": selected fsm is 0x%08x\n", readl_relaxed(host->ioaddr + SDCC_DEBUG_FSM_TRACE_CFG_REG)); /* dump selected fsm history */ pr_err("0x%08x 0x%08x 0x%08x 0x%08x\n", readl_relaxed(host->ioaddr + SDCC_DEBUG_FSM_TRACE_RD_REG), readl_relaxed(host->ioaddr + SDCC_DEBUG_FSM_TRACE_RD_REG), readl_relaxed(host->ioaddr + SDCC_DEBUG_FSM_TRACE_RD_REG), readl_relaxed(host->ioaddr + SDCC_DEBUG_FSM_TRACE_RD_REG)); pr_err("0x%08x 0x%08x 0x%08x\n", readl_relaxed(host->ioaddr + SDCC_DEBUG_FSM_TRACE_RD_REG), readl_relaxed(host->ioaddr + SDCC_DEBUG_FSM_TRACE_RD_REG), readl_relaxed(host->ioaddr + SDCC_DEBUG_FSM_TRACE_RD_REG)); } /* Flush all fsm history */ writel_relaxed(DUMMY, host->ioaddr + SDCC_DEBUG_FSM_TRACE_FIFO_FLUSH_REG); /* Exit from Auto recovery disable to move FSMs to idle state */ writel_relaxed(DUMMY, host->ioaddr + SDCC_DEBUG_ERROR_STATE_EXIT_REG); } void sdhci_msm_dump_desc_history(struct sdhci_host *host) { pr_err("----------- DESC HISTORY DUMP -----------\n"); pr_err("Current Desc Addr: 0x%08x | Info: 0x%08x\n", readl_relaxed(host->ioaddr + SDCC_CURR_DESC_ADDR), readl_relaxed(host->ioaddr + SDCC_CURR_DESC_INFO)); pr_err("Processed Desc1 Addr: 0x%08x | Info: 0x%08x\n", readl_relaxed(host->ioaddr + SDCC_PROC_DESC0_ADDR), readl_relaxed(host->ioaddr + SDCC_PROC_DESC0_INFO)); pr_err("Processed Desc2 Addr: 0x%08x | Info: 0x%08x\n", readl_relaxed(host->ioaddr + SDCC_PROC_DESC1_ADDR), readl_relaxed(host->ioaddr + SDCC_PROC_DESC1_INFO)); } void sdhci_msm_dump_iib(struct sdhci_host *host) { u32 iter; pr_err("----------- IIB HISTORY DUMP -----------\n"); for (iter = 0; iter < 8; iter++) pr_err("0x%08x\n", readl_relaxed(host->ioaddr + SDCC_DEBUG_IIB_REG + (iter * 4))); } void sdhci_msm_dump_vendor_regs(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); Loading Loading @@ -4052,6 +4226,14 @@ void sdhci_msm_dump_vendor_regs(struct sdhci_host *host) msm_host_offset->CORE_VENDOR_SPEC_FUNC2), readl_relaxed(host->ioaddr + msm_host_offset->CORE_VENDOR_SPEC3)); if (msm_host->debug_mode_enabled) { sdhci_msm_dump_fsm_history(host); sdhci_msm_dump_desc_history(host); } /* Debug feature enable not must for iib */ sdhci_msm_dump_iib(host); /* * tbsel indicates [2:0] bits and tbsel2 indicates [7:4] bits * of CORE_TESTBUS_CONFIG register. Loading Loading @@ -4743,6 +4925,54 @@ static int sdhci_msm_notify_load(struct sdhci_host *host, enum mmc_load state) return 0; } static void sdhci_msm_hw_reset(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; struct platform_device *pdev = msm_host->pdev; int ret = -ENOTSUPP; if (!msm_host->core_reset) { dev_err(&pdev->dev, "%s: failed, err = %d\n", __func__, ret); return; } if (!msm_host->debug_mode_enabled) return; msm_host->reg_store = true; sdhci_msm_exit_dbg_mode(host); sdhci_msm_registers_save(host); if (host->mmc->caps2 & MMC_CAP2_CQE) { host->mmc->cqe_ops->cqe_disable(host->mmc); host->mmc->cqe_enabled = false; } ret = reset_control_assert(msm_host->core_reset); if (ret) { dev_err(&pdev->dev, "%s: core_reset assert failed, err = %d\n", __func__, ret); goto out; } /* * 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(msm_host->core_reset); if (ret) dev_err(&pdev->dev, "%s: core_reset deassert failed, err = %d\n", __func__, ret); sdhci_msm_registers_restore(host); msm_host->reg_store = false; out: return; } static struct sdhci_ops sdhci_msm_ops = { .crypto_engine_cfg = sdhci_msm_ice_cfg, .crypto_engine_cfg_end = sdhci_msm_ice_cfg_end, Loading Loading @@ -4770,6 +5000,9 @@ static struct sdhci_ops sdhci_msm_ops = { .get_current_limit = sdhci_msm_get_current_limit, .notify_load = sdhci_msm_notify_load, .irq = sdhci_msm_cqe_irq, .enter_dbg_mode = sdhci_msm_enter_dbg_mode, .exit_dbg_mode = sdhci_msm_exit_dbg_mode, .hw_reset = sdhci_msm_hw_reset, }; static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host, Loading Loading @@ -5411,6 +5644,8 @@ static int sdhci_msm_probe(struct platform_device *pdev) msm_host->mmc->caps2 |= MMC_CAP2_MAX_DISCARD_SIZE; msm_host->mmc->caps2 |= MMC_CAP2_SLEEP_AWAKE; msm_host->mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ; if (msm_host->core_reset) msm_host->mmc->caps |= MMC_CAP_HW_RESET; if (msm_host->pdata->nonremovable) msm_host->mmc->caps |= MMC_CAP_NONREMOVABLE; Loading
drivers/mmc/host/sdhci-msm.h +65 −0 Original line number Diff line number Diff line Loading @@ -9,8 +9,70 @@ #include <linux/mmc/mmc.h> #include <linux/pm_qos.h> #include <linux/reset.h> #include "sdhci-pltfm.h" /* check IP CATALOG version */ #define SDCC_IP_CATALOG 0x328 /* DBG register offsets */ #define SDCC_TESTBUS_CONFIG 0x32C #define SDCC_DEBUG_EN_DIS_REG 0x390 #define SDCC_DEBUG_FEATURE_CFG_REG 0x394 #define SDCC_DEBUG_FSM_TRACE_CFG_REG 0x398 #define SDCC_DEBUG_FSM_TRACE_RD_REG 0x39C #define SDCC_DEBUG_FSM_TRACE_FIFO_FLUSH_REG 0x3A0 #define SDCC_DEBUG_PANIC_ERROR_EN_REG 0x3A4 #define SDCC_DEBUG_ERROR_STATE_EXIT_REG 0x3B8 #define SDCC_CURR_DESC_ADDR 0x3EC #define SDCC_CURR_DESC_INFO 0x3F0 #define SDCC_PROC_DESC0_ADDR 0x3E4 #define SDCC_PROC_DESC0_INFO 0x3E8 #define SDCC_PROC_DESC1_ADDR 0x3DC #define SDCC_PROC_DESC1_INFO 0x3E0 #define SDCC_DEBUG_IIB_REG 0x980 #define SDCC_DEBUG_MASK_PATTERN_REG 0x3C0 #define SDCC_DEBUG_MATCH_PATTERN_REG 0x3C4 #define SDCC_DEBUG_MM_TB_CFG_REG 0x3BC #define ENABLE_DBG 0x35350000 #define DISABLE_DBG 0x26260000 #define DUMMY 0x1 /* value doesn't matter */ /* Panic on Err */ #define BOOT_ACK_REC_EN BIT(0) #define BOOT_ACK_ERR_EN BIT(1) #define BOOT_TIMEOUT_EN BIT(2) #define AUTO_CMD19_TOUT_EN BIT(3) #define STBITE_EN BIT(4) #define CTOUT_EN BIT(5) #define CCRCF_EN BIT(6) #define CMD_END_BIT_ERR_EN BIT(7) #define CMD_INDEX_ERR_EN BIT(8) #define DTOUT_EN BIT(9) #define DCRCF_EN BIT(10) #define DATA_END_BIT_ERR_EN BIT(11) #define CMDQ_HALT_ACK_INT_EN BIT(16) #define CMDQ_TASK_COMPLETED_INT_EN BIT(17) #define CMDQ_RESP_ERR_INT_EN BIT(18) #define CMDQ_TASK_CLEARED_INT_EN BIT(19) #define CMDQ_GENERAL_CRYPTO_ERROR_EN BIT(20) #define CMDQ_INVALID_CRYPTO_CFG_ERROR_EN BIT(21) #define CMDQ_DEVICE_EXCEPTION_INT_EN BIT(22) #define ADMA_ERROR_EXT_EN BIT(23) #define HC_NONCQ_ICE_INT_STATUS_MASKED_EN BIT(24) /* Select debug Feature */ #define FSM_HISTORY BIT(0) #define PANIC_ALERT BIT(1) #define AUTO_RECOVERY_DISABLE BIT(2) #define MM_TRIGGER_DISABLE BIT(3) #define DESC_HISTORY BIT(4) #define IIB_EN BIT(6) #define TESTBUS_EN BIT(31) /* This structure keeps information per regulator */ struct sdhci_msm_reg_data { /* voltage regulator handle */ Loading Loading @@ -267,6 +329,9 @@ struct sdhci_msm_host { struct sdhci_msm_dll_hsr *dll_hsr; struct sdhci_msm_ice_data ice; u32 ice_clk_rate; bool debug_mode_enabled; bool reg_store; struct reset_control *core_reset; }; extern char *saved_command_line; Loading