Loading drivers/mmc/core/block.c +1 −2 Original line number Diff line number Diff line Loading @@ -1543,7 +1543,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 +9 −2 Original line number Diff line number Diff line Loading @@ -2304,6 +2304,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 @@ -2907,6 +2909,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 @@ -2933,9 +2940,9 @@ static int _mmc_hw_reset(struct mmc_host *host) return ret; } ret = mmc_suspend_clk_scaling(host); ret = mmc_resume_clk_scaling(host); if (ret) { pr_err("%s: %s: fail to suspend clock scaling (%d)\n", pr_err("%s: %s: fail to resume clock scaling (%d)\n", mmc_hostname(host), __func__, ret); } return ret; Loading drivers/mmc/host/cqhci.c +9 −2 Original line number Diff line number Diff line Loading @@ -901,14 +901,21 @@ irqreturn_t cqhci_irq(struct mmc_host *mmc, u32 intmask, int cmd_error, struct cqhci_host *cq_host = mmc->cqe_private; status = cqhci_readl(cq_host, CQHCI_IS); cqhci_writel(cq_host, status, CQHCI_IS); pr_debug("%s: cqhci: IRQ status: 0x%08x\n", mmc_hostname(mmc), status); mmc_log_string(mmc, "CQIS: 0x%x cmd_error : %d data_err: %d\n", status, cmd_error, data_error); if ((status & CQHCI_IS_RED) || cmd_error || data_error) if ((status & CQHCI_IS_RED) || cmd_error || data_error) { pr_err("%s: cqhci: error IRQ status: 0x%08x cmd error %d data error %d\n", mmc_hostname(mmc), status, cmd_error, data_error); cqhci_dumpregs(cq_host); cqhci_writel(cq_host, status, CQHCI_IS); cqhci_error_irq(mmc, status, cmd_error, data_error); } else { /* Clear interrupt */ cqhci_writel(cq_host, status, CQHCI_IS); } if (status & CQHCI_IS_TCC) { /* read TCN and complete the request */ Loading drivers/mmc/host/sdhci-msm.c +238 −3 Original line number Diff line number Diff line Loading @@ -1206,6 +1206,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 @@ -1240,6 +1312,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 @@ -1433,6 +1506,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 @@ -1980,6 +2054,23 @@ static int sdhci_msm_dt_parse_hsr_info(struct device *dev, return ret; } 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 @@ -1997,6 +2088,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 @@ -2150,6 +2242,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 @@ -2240,11 +2335,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 @@ -3235,7 +3340,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 @@ -3299,8 +3405,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 @@ -3957,6 +4064,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 @@ -4014,6 +4188,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 @@ -4705,6 +4887,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 @@ -4732,6 +4962,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 @@ -5311,6 +5544,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 Loading
drivers/mmc/core/block.c +1 −2 Original line number Diff line number Diff line Loading @@ -1543,7 +1543,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 +9 −2 Original line number Diff line number Diff line Loading @@ -2304,6 +2304,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 @@ -2907,6 +2909,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 @@ -2933,9 +2940,9 @@ static int _mmc_hw_reset(struct mmc_host *host) return ret; } ret = mmc_suspend_clk_scaling(host); ret = mmc_resume_clk_scaling(host); if (ret) { pr_err("%s: %s: fail to suspend clock scaling (%d)\n", pr_err("%s: %s: fail to resume clock scaling (%d)\n", mmc_hostname(host), __func__, ret); } return ret; Loading
drivers/mmc/host/cqhci.c +9 −2 Original line number Diff line number Diff line Loading @@ -901,14 +901,21 @@ irqreturn_t cqhci_irq(struct mmc_host *mmc, u32 intmask, int cmd_error, struct cqhci_host *cq_host = mmc->cqe_private; status = cqhci_readl(cq_host, CQHCI_IS); cqhci_writel(cq_host, status, CQHCI_IS); pr_debug("%s: cqhci: IRQ status: 0x%08x\n", mmc_hostname(mmc), status); mmc_log_string(mmc, "CQIS: 0x%x cmd_error : %d data_err: %d\n", status, cmd_error, data_error); if ((status & CQHCI_IS_RED) || cmd_error || data_error) if ((status & CQHCI_IS_RED) || cmd_error || data_error) { pr_err("%s: cqhci: error IRQ status: 0x%08x cmd error %d data error %d\n", mmc_hostname(mmc), status, cmd_error, data_error); cqhci_dumpregs(cq_host); cqhci_writel(cq_host, status, CQHCI_IS); cqhci_error_irq(mmc, status, cmd_error, data_error); } else { /* Clear interrupt */ cqhci_writel(cq_host, status, CQHCI_IS); } if (status & CQHCI_IS_TCC) { /* read TCN and complete the request */ Loading
drivers/mmc/host/sdhci-msm.c +238 −3 Original line number Diff line number Diff line Loading @@ -1206,6 +1206,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 @@ -1240,6 +1312,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 @@ -1433,6 +1506,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 @@ -1980,6 +2054,23 @@ static int sdhci_msm_dt_parse_hsr_info(struct device *dev, return ret; } 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 @@ -1997,6 +2088,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 @@ -2150,6 +2242,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 @@ -2240,11 +2335,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 @@ -3235,7 +3340,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 @@ -3299,8 +3405,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 @@ -3957,6 +4064,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 @@ -4014,6 +4188,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 @@ -4705,6 +4887,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 @@ -4732,6 +4962,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 @@ -5311,6 +5544,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