Auto hibern8 causes false interrupt assertion. To overcome this, disable hibern8 interrupt during initialization and Enable/Disable hibern8 interrupt during manual hibern8 Entry/Exit. Signed-off-by: sheebab <sheebab@xxxxxxxxxxx> --- drivers/scsi/ufs/cdns-pltfrm.c | 75 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c index b2af04c..adbbd60 100644 --- a/drivers/scsi/ufs/cdns-pltfrm.c +++ b/drivers/scsi/ufs/cdns-pltfrm.c @@ -21,6 +21,32 @@ #define CDNS_UFS_REG_PHY_XCFGD1 0x113C /** + * cdns_ufs_enable_intr - enable interrupts + * @hba: per adapter instance + * @intrs: interrupt bits + */ +static void cdns_ufs_enable_intr(struct ufs_hba *hba, u32 intrs) +{ + u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE); + + set = set | intrs; + ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE); +} + +/** + * cdns_ufs_disable_intr - disable interrupts + * @hba: per adapter instance + * @intrs: interrupt bits + */ +static void cdns_ufs_disable_intr(struct ufs_hba *hba, u32 intrs) +{ + u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE); + + set = set & ~intrs; + ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE); +} + +/** * Sets HCLKDIV register value based on the core_clk * @hba: host controller instance * @@ -71,10 +97,51 @@ static int cdns_ufs_set_hclkdiv(struct ufs_hba *hba) static int cdns_ufs_hce_enable_notify(struct ufs_hba *hba, enum ufs_notify_change_status status) { - if (status != PRE_CHANGE) - return 0; + int err = 0; + + switch (status) { + case PRE_CHANGE: + err = cdns_ufs_set_hclkdiv(hba); + break; + case POST_CHANGE: + /** + * Hibern8 interrupts(UHESE, UHXSE) disabled + * during initialization. + */ + cdns_ufs_disable_intr(hba, UFSHCD_UIC_HIBERN8_MASK); + break; + default: + dev_err(hba->dev, "%s: invalid status %d\n", __func__, status); + err = -EINVAL; + break; + } + return err; +} - return cdns_ufs_set_hclkdiv(hba); +/** + * Called around hibern8 enter/exit. + * @hba: host controller instance + * @cmd: UIC Command + * @status: notify stage (pre, post change) + * + */ +static void cdns_ufs_hibern8_notify(struct ufs_hba *hba, enum uic_cmd_dme cmd, + enum ufs_notify_change_status status) +{ + if (status == PRE_CHANGE && cmd == UIC_CMD_DME_HIBER_ENTER) { + /** + * Hibern8 interrupts(UHESE, UHXSE) enabled + * before manual hibernate entry. + */ + cdns_ufs_enable_intr(hba, UFSHCD_UIC_HIBERN8_MASK); + } + if (status == POST_CHANGE && cmd == UIC_CMD_DME_HIBER_EXIT) { + /** + * Hibern8 interrupts(UHESE, UHXSE) disabled + * after manual hibern8 exit. + */ + cdns_ufs_disable_intr(hba, UFSHCD_UIC_HIBERN8_MASK); + } } /** @@ -140,6 +207,7 @@ static const struct ufs_hba_variant_ops cdns_ufs_pltfm_hba_vops = { .name = "cdns-ufs-pltfm", .hce_enable_notify = cdns_ufs_hce_enable_notify, .link_startup_notify = cdns_ufs_link_startup_notify, + .hibern8_notify = cdns_ufs_hibern8_notify, }; static const struct ufs_hba_variant_ops cdns_ufs_m31_16nm_pltfm_hba_vops = { @@ -148,6 +216,7 @@ static const struct ufs_hba_variant_ops cdns_ufs_m31_16nm_pltfm_hba_vops = { .hce_enable_notify = cdns_ufs_hce_enable_notify, .link_startup_notify = cdns_ufs_link_startup_notify, .phy_initialization = cdns_ufs_m31_16nm_phy_initialization, + .hibern8_notify = cdns_ufs_hibern8_notify, }; static const struct of_device_id cdns_ufs_of_match[] = { -- 2.7.4