diff --git a/msm/sde/sde_hw_vbif.c b/msm/sde/sde_hw_vbif.c index 6b02e4f83b..d07e3d8669 100644 --- a/msm/sde/sde_hw_vbif.c +++ b/msm/sde/sde_hw_vbif.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ +#include #include "sde_hwio.h" #include "sde_hw_catalog.h" @@ -9,6 +10,7 @@ #include "sde_dbg.h" #define VBIF_VERSION 0x0000 +#define VBIF_CLKON 0x0004 #define VBIF_CLK_FORCE_CTRL0 0x0008 #define VBIF_CLK_FORCE_CTRL1 0x000C #define VBIF_QOS_REMAP_00 0x0020 @@ -33,6 +35,8 @@ #define VBIF_XIN_CLR_ERR 0x019C #define VBIF_XIN_HALT_CTRL0 0x0200 #define VBIF_XIN_HALT_CTRL1 0x0204 +#define VBIF_AXI_HALT_CTRL0 0x0208 +#define VBIF_AXI_HALT_CTRL1 0x020c #define VBIF_XINL_QOS_RP_REMAP_000 0x0550 #define VBIF_XINL_QOS_LVL_REMAP_000 0x0590 @@ -154,7 +158,7 @@ static u32 sde_hw_get_limit_conf(struct sde_hw_vbif *vbif, return limit; } -static void sde_hw_set_halt_ctrl(struct sde_hw_vbif *vbif, +static void sde_hw_set_xin_halt(struct sde_hw_vbif *vbif, u32 xin_id, bool enable) { struct sde_hw_blk_reg_map *c = &vbif->hw; @@ -168,9 +172,10 @@ static void sde_hw_set_halt_ctrl(struct sde_hw_vbif *vbif, reg_val &= ~BIT(xin_id); SDE_REG_WRITE(c, VBIF_XIN_HALT_CTRL0, reg_val); + wmb(); /* make sure that xin client halted */ } -static bool sde_hw_get_halt_ctrl(struct sde_hw_vbif *vbif, +static bool sde_hw_get_xin_halt_status(struct sde_hw_vbif *vbif, u32 xin_id) { struct sde_hw_blk_reg_map *c = &vbif->hw; @@ -181,6 +186,24 @@ static bool sde_hw_get_halt_ctrl(struct sde_hw_vbif *vbif, return ((reg_val >> 16) & BIT(xin_id)) ? true : false; } +static void sde_hw_set_axi_halt(struct sde_hw_vbif *vbif) +{ + struct sde_hw_blk_reg_map *c = &vbif->hw; + + SDE_REG_WRITE(c, VBIF_CLKON, BIT(0)); + SDE_REG_WRITE(c, VBIF_AXI_HALT_CTRL0, BIT(0)); + wmb(); /* make sure that axi transactions are halted */ +} + +static int sde_hw_get_axi_halt_status(struct sde_hw_vbif *vbif) +{ + struct sde_hw_blk_reg_map *c = &vbif->hw; + int ctrl = 0; + + return readl_poll_timeout(c->base_off + c->blk_off + + VBIF_AXI_HALT_CTRL1, ctrl, ctrl & BIT(0), 100, 4000); +} + static void sde_hw_set_qos_remap(struct sde_hw_vbif *vbif, u32 xin_id, u32 level, u32 remap_level) { @@ -230,8 +253,10 @@ static void _setup_vbif_ops(const struct sde_mdss_cfg *m, { ops->set_limit_conf = sde_hw_set_limit_conf; ops->get_limit_conf = sde_hw_get_limit_conf; - ops->set_halt_ctrl = sde_hw_set_halt_ctrl; - ops->get_halt_ctrl = sde_hw_get_halt_ctrl; + ops->set_axi_halt = sde_hw_set_axi_halt; + ops->get_axi_halt_status = sde_hw_get_axi_halt_status; + ops->set_xin_halt = sde_hw_set_xin_halt; + ops->get_xin_halt_status = sde_hw_get_xin_halt_status; if (test_bit(SDE_VBIF_QOS_REMAP, &cap)) ops->set_qos_remap = sde_hw_set_qos_remap; if (test_bit(SDE_VBIF_DISABLE_SHAREABLE, &cap)) diff --git a/msm/sde/sde_hw_vbif.h b/msm/sde/sde_hw_vbif.h index 826b126a60..3b75ab88ed 100644 --- a/msm/sde/sde_hw_vbif.h +++ b/msm/sde/sde_hw_vbif.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #ifndef _SDE_HW_VBIF_H @@ -38,23 +38,35 @@ struct sde_hw_vbif_ops { u32 xin_id, bool rd); /** - * set_halt_ctrl - set halt control + * set_xin_halt - set xin client halt control * @vbif: vbif context driver * @xin_id: client interface identifier * @enable: halt control enable */ - void (*set_halt_ctrl)(struct sde_hw_vbif *vbif, + void (*set_xin_halt)(struct sde_hw_vbif *vbif, u32 xin_id, bool enable); /** - * get_halt_ctrl - get halt control + * get_xin_halt_status - get xin client halt control * @vbif: vbif context driver * @xin_id: client interface identifier * @return: halt control enable */ - bool (*get_halt_ctrl)(struct sde_hw_vbif *vbif, + bool (*get_xin_halt_status)(struct sde_hw_vbif *vbif, u32 xin_id); + /** + * set_axi_halt - set axi port halt control + * @vbif: vbif context driver + */ + void (*set_axi_halt)(struct sde_hw_vbif *vbif); + + /** + * get_axi_halt_status - get axi port halt control status + * @vbif: vbif context driver + */ + int (*get_axi_halt_status)(struct sde_hw_vbif *vbif); + /** * set_qos_remap - set QoS priority remap * @vbif: vbif context driver diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index db6d376456..f1c35c99d8 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -2948,6 +2948,8 @@ static void sde_kms_handle_power_event(u32 event_type, void *usr) sde_irq_update(msm_kms, false); sde_kms->first_kickoff = false; _sde_kms_active_override(sde_kms, true); + if (!is_sde_rsc_available(SDE_RSC_INDEX)) + sde_vbif_axi_halt_request(sde_kms); } } diff --git a/msm/sde/sde_vbif.c b/msm/sde/sde_vbif.c index 2dd7d3e270..daea2eb463 100644 --- a/msm/sde/sde_vbif.c +++ b/msm/sde/sde_vbif.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ @@ -26,18 +26,18 @@ static int _sde_vbif_wait_for_xin_halt(struct sde_hw_vbif *vbif, u32 xin_id) bool status; int rc; - if (!vbif || !vbif->cap || !vbif->ops.get_halt_ctrl) { + if (!vbif || !vbif->cap || !vbif->ops.get_xin_halt_status) { SDE_ERROR("invalid arguments vbif %d\n", !vbif); return -EINVAL; } timeout = ktime_add_us(ktime_get(), vbif->cap->xin_halt_timeout); for (;;) { - status = vbif->ops.get_halt_ctrl(vbif, xin_id); + status = vbif->ops.get_xin_halt_status(vbif, xin_id); if (status) break; if (ktime_compare_safe(ktime_get(), timeout) > 0) { - status = vbif->ops.get_halt_ctrl(vbif, xin_id); + status = vbif->ops.get_xin_halt_status(vbif, xin_id); break; } usleep_range(501, 1000); @@ -56,6 +56,26 @@ static int _sde_vbif_wait_for_xin_halt(struct sde_hw_vbif *vbif, u32 xin_id) return rc; } +static int _sde_vbif_wait_for_axi_halt(struct sde_hw_vbif *vbif) +{ + int rc; + + if (!vbif || !vbif->cap || !vbif->ops.get_axi_halt_status) { + SDE_ERROR("invalid arguments vbif %d\n", !vbif); + return -EINVAL; + } + + rc = vbif->ops.get_axi_halt_status(vbif); + if (rc) + SDE_ERROR("VBIF %d AXI port(s) not halting. TIMEDOUT.\n", + vbif->idx - VBIF_0); + else + SDE_DEBUG("VBIF %d AXI port(s) halted\n", + vbif->idx - VBIF_0); + + return rc; +} + int sde_vbif_halt_plane_xin(struct sde_kms *sde_kms, u32 xin_id, u32 clk_ctrl) { struct sde_hw_vbif *vbif = NULL; @@ -76,8 +96,8 @@ int sde_vbif_halt_plane_xin(struct sde_kms *sde_kms, u32 xin_id, u32 clk_ctrl) vbif = sde_kms->hw_vbif[VBIF_RT]; mdp = sde_kms->hw_mdp; - if (!vbif || !mdp || !vbif->ops.get_halt_ctrl || - !vbif->ops.set_halt_ctrl || + if (!vbif || !mdp || !vbif->ops.get_xin_halt_status || + !vbif->ops.set_xin_halt || !mdp->ops.setup_clk_force_ctrl) { SDE_ERROR("invalid vbif or mdp arguments\n"); return -EINVAL; @@ -92,7 +112,7 @@ int sde_vbif_halt_plane_xin(struct sde_kms *sde_kms, u32 xin_id, u32 clk_ctrl) * while halting by forcing it ON only if it was not previously * forced on. If status is 1 then its already halted. */ - status = vbif->ops.get_halt_ctrl(vbif, xin_id); + status = vbif->ops.get_xin_halt_status(vbif, xin_id); if (status) { mutex_unlock(&vbif->mutex); return 0; @@ -101,7 +121,7 @@ int sde_vbif_halt_plane_xin(struct sde_kms *sde_kms, u32 xin_id, u32 clk_ctrl) forced_on = mdp->ops.setup_clk_force_ctrl(mdp, clk_ctrl, true); /* send halt request for unused plane's xin client */ - vbif->ops.set_halt_ctrl(vbif, xin_id, true); + vbif->ops.set_xin_halt(vbif, xin_id, true); rc = _sde_vbif_wait_for_xin_halt(vbif, xin_id); if (rc) { @@ -112,7 +132,7 @@ int sde_vbif_halt_plane_xin(struct sde_kms *sde_kms, u32 xin_id, u32 clk_ctrl) } /* open xin client to enable transactions */ - vbif->ops.set_halt_ctrl(vbif, xin_id, false); + vbif->ops.set_xin_halt(vbif, xin_id, false); if (forced_on) mdp->ops.setup_clk_force_ctrl(mdp, clk_ctrl, false); @@ -250,7 +270,7 @@ void sde_vbif_set_ot_limit(struct sde_kms *sde_kms, if (!mdp->ops.setup_clk_force_ctrl || !vbif->ops.set_limit_conf || - !vbif->ops.set_halt_ctrl) + !vbif->ops.set_xin_halt) return; mutex_lock(&vbif->mutex); @@ -273,13 +293,13 @@ void sde_vbif_set_ot_limit(struct sde_kms *sde_kms, vbif->ops.set_limit_conf(vbif, params->xin_id, params->rd, ot_lim); - vbif->ops.set_halt_ctrl(vbif, params->xin_id, true); + vbif->ops.set_xin_halt(vbif, params->xin_id, true); ret = _sde_vbif_wait_for_xin_halt(vbif, params->xin_id); if (ret) SDE_EVT32(vbif->idx, params->xin_id); - vbif->ops.set_halt_ctrl(vbif, params->xin_id, false); + vbif->ops.set_xin_halt(vbif, params->xin_id, false); if (forced_on) mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, false); @@ -357,7 +377,7 @@ bool sde_vbif_set_xin_halt(struct sde_kms *sde_kms, } if (!mdp->ops.setup_clk_force_ctrl || - !vbif->ops.set_halt_ctrl) + !vbif->ops.set_xin_halt) return false; mutex_lock(&vbif->mutex); @@ -368,13 +388,13 @@ bool sde_vbif_set_xin_halt(struct sde_kms *sde_kms, forced_on = mdp->ops.setup_clk_force_ctrl(mdp, params->clk_ctrl, true); - vbif->ops.set_halt_ctrl(vbif, params->xin_id, true); + vbif->ops.set_xin_halt(vbif, params->xin_id, true); ret = _sde_vbif_wait_for_xin_halt(vbif, params->xin_id); if (ret) SDE_EVT32(vbif->idx, params->xin_id, SDE_EVTLOG_ERROR); } else { - vbif->ops.set_halt_ctrl(vbif, params->xin_id, false); + vbif->ops.set_xin_halt(vbif, params->xin_id, false); if (params->forced_on) mdp->ops.setup_clk_force_ctrl(mdp, @@ -511,6 +531,32 @@ void sde_vbif_init_memtypes(struct sde_kms *sde_kms) } } +void sde_vbif_axi_halt_request(struct sde_kms *sde_kms) +{ + struct sde_hw_vbif *vbif; + int i; + + if (!sde_kms) { + SDE_ERROR("invalid argument\n"); + return; + } + + if (!sde_kms_is_vbif_operation_allowed(sde_kms)) { + SDE_DEBUG("vbif operations not permitted\n"); + return; + } + + for (i = 0; i < ARRAY_SIZE(sde_kms->hw_vbif); i++) { + vbif = sde_kms->hw_vbif[i]; + if (vbif && vbif->cap && vbif->ops.set_axi_halt) { + mutex_lock(&vbif->mutex); + vbif->ops.set_axi_halt(vbif); + _sde_vbif_wait_for_axi_halt(vbif); + mutex_unlock(&vbif->mutex); + } + } +} + int sde_vbif_halt_xin_mask(struct sde_kms *sde_kms, u32 xin_id_mask, bool halt) { @@ -524,7 +570,7 @@ int sde_vbif_halt_xin_mask(struct sde_kms *sde_kms, u32 xin_id_mask, vbif = sde_kms->hw_vbif[VBIF_RT]; - if (!vbif->ops.get_halt_ctrl || !vbif->ops.set_halt_ctrl) + if (!vbif->ops.get_xin_halt_status || !vbif->ops.set_xin_halt) return 0; SDE_EVT32(xin_id_mask, halt); @@ -533,16 +579,16 @@ int sde_vbif_halt_xin_mask(struct sde_kms *sde_kms, u32 xin_id_mask, if (xin_id_mask & BIT(i)) { /* unhalt the xin-clients */ if (!halt) { - vbif->ops.set_halt_ctrl(vbif, i, false); + vbif->ops.set_xin_halt(vbif, i, false); continue; } - status = vbif->ops.get_halt_ctrl(vbif, i); + status = vbif->ops.get_xin_halt_status(vbif, i); if (status) continue; /* halt xin-clients and wait for ack */ - vbif->ops.set_halt_ctrl(vbif, i, true); + vbif->ops.set_xin_halt(vbif, i, true); rc = _sde_vbif_wait_for_xin_halt(vbif, i); if (rc) { diff --git a/msm/sde/sde_vbif.h b/msm/sde/sde_vbif.h index b16e0c757c..ba21c0a5e9 100644 --- a/msm/sde/sde_vbif.h +++ b/msm/sde/sde_vbif.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef __SDE_VBIF_H__ @@ -98,6 +98,12 @@ void sde_vbif_clear_errors(struct sde_kms *sde_kms); */ void sde_vbif_init_memtypes(struct sde_kms *sde_kms); +/** + * sde_vbif_axi_halt_request - halt all axi transcations on vbif + * @sde_kms: SDE handler + */ +void sde_vbif_axi_halt_request(struct sde_kms *sde_kms); + /** * sde_vbif_halt_plane_xin - halts the xin client for the unused plane * On unused plane, check if the vbif for this plane is idle or not.