Loading drivers/gpu/drm/msm/sde/sde_rm.c +122 −86 Original line number Original line Diff line number Diff line /* /* * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * * This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -1129,17 +1129,29 @@ static int _sde_rm_make_next_rsvp( return ret; return ret; } } /** static void _sde_rm_clear_irq_status(struct sde_hw_intr *hw_intr, * poll_intr_status - Gets HW interrupt status based on int irq_idx_pp_done, int irq_idx_autorefresh) * given lookup IRQ index. { * @intr: HW interrupt handle u32 intr_value = 0; * @irq_idx: Lookup irq index return from irq_idx_lookup * @msec: Maximum delay allowed to check intr status if ((irq_idx_pp_done >= 0) && (hw_intr->ops.get_intr_status_nomask)) { * return: return zero on success. intr_value = hw_intr->ops.get_intr_status_nomask(hw_intr, */ irq_idx_pp_done, false); static u32 _sde_rm_poll_intr_status_for_cont_splash hw_intr->ops.clear_intr_status_force_mask(hw_intr, (struct sde_hw_intr *intr, irq_idx_pp_done, intr_value); int irq_idx, u32 const msec) } if ((irq_idx_autorefresh >= 0) && (hw_intr->ops.get_intr_status_nomask)) { intr_value = hw_intr->ops.get_intr_status_nomask(hw_intr, irq_idx_autorefresh, false); hw_intr->ops.clear_intr_status_force_mask(hw_intr, irq_idx_autorefresh, intr_value); } } static u32 _sde_rm_poll_intr_status_for_cont_splash(struct sde_hw_intr *intr, int irq_idx_pp_done, int irq_idx_autorefresh, u32 const msec) { { int i; int i; u32 status = 0; u32 status = 0; Loading @@ -1153,19 +1165,112 @@ static u32 _sde_rm_poll_intr_status_for_cont_splash for (i = 0; i < loop; i++) { for (i = 0; i < loop; i++) { status = intr->ops.get_intr_status_nomask status = intr->ops.get_intr_status_nomask (intr, irq_idx, false); (intr, irq_idx_pp_done, false); if (status & BIT(irq_idx)) { if (status & BIT(irq_idx_pp_done)) { SDE_DEBUG(" Poll success. i=%d, status=0x%x\n", SDE_DEBUG("pp_done received i=%d, status=0x%x\n", i, status); i, status); SDE_EVT32(status, i, irq_idx_pp_done); if (status & BIT(irq_idx_autorefresh)) _sde_rm_clear_irq_status(intr, irq_idx_pp_done, irq_idx_autorefresh); else return 0; return 0; } } usleep_range(delay_us, delay_us + 10); usleep_range(delay_us, delay_us + 10); } } SDE_EVT32(status, irq_idx_pp_done, SDE_EVTLOG_ERROR); SDE_ERROR("polling timed out. status = 0x%x\n", status); SDE_ERROR("polling timed out. status = 0x%x\n", status); return -ETIMEDOUT; return -ETIMEDOUT; } } static int _sde_rm_autorefresh_disable(struct sde_hw_pingpong *pp, struct sde_hw_intr *hw_intr) { u32 const timeout_ms = 35; /* Max two vsyncs delay */ int rc = 0, i, loop = 3; struct sde_hw_pp_vsync_info info; int irq_idx_pp_done = -1, irq_idx_autorefresh = -1; struct sde_hw_autorefresh cfg = {0}; if (!pp->ops.get_autorefresh || !pp->ops.setup_autorefresh || !pp->ops.connect_external_te || !pp->ops.get_vsync_info) { SDE_ERROR("autorefresh update api not supported\n"); return 0; } /* read default autorefresh configuration */ pp->ops.get_autorefresh(pp, &cfg); if (!cfg.enable) { SDE_DEBUG("autorefresh already disabled\n"); SDE_EVT32(pp->idx - PINGPONG_0, SDE_EVTLOG_FUNC_CASE1); return 0; } /* disable external TE first */ pp->ops.connect_external_te(pp, false); /* get all IRQ indexes */ if (hw_intr->ops.irq_idx_lookup) { irq_idx_pp_done = hw_intr->ops.irq_idx_lookup( SDE_IRQ_TYPE_PING_PONG_COMP, pp->idx); irq_idx_autorefresh = hw_intr->ops.irq_idx_lookup( SDE_IRQ_TYPE_PING_PONG_AUTO_REF, pp->idx); SDE_DEBUG("pp_done itr_idx = %d autorefresh irq_idx:%d\n", irq_idx_pp_done, irq_idx_autorefresh); } /* disable autorefresh */ cfg.enable = false; pp->ops.setup_autorefresh(pp, &cfg); SDE_EVT32(pp->idx - PINGPONG_0, irq_idx_pp_done, irq_idx_autorefresh); _sde_rm_clear_irq_status(hw_intr, irq_idx_pp_done, irq_idx_autorefresh); /* * Check the line count again if * the line count is equal to the active * height to make sure their is no * additional frame updates */ for (i = 0; i < loop; i++) { info.wr_ptr_line_count = 0; info.rd_ptr_init_val = 0; pp->ops.get_vsync_info(pp, &info); SDE_EVT32(pp->idx - PINGPONG_0, info.wr_ptr_line_count, info.rd_ptr_init_val, SDE_EVTLOG_FUNC_CASE1); /* wait for read ptr intr */ rc = _sde_rm_poll_intr_status_for_cont_splash(hw_intr, irq_idx_pp_done, irq_idx_autorefresh, timeout_ms); info.wr_ptr_line_count = 0; info.rd_ptr_init_val = 0; pp->ops.get_vsync_info(pp, &info); SDE_DEBUG("i=%d, line count=%d\n", i, info.wr_ptr_line_count); SDE_EVT32(pp->idx - PINGPONG_0, info.wr_ptr_line_count, info.rd_ptr_init_val, SDE_EVTLOG_FUNC_CASE2); /* log line count and return */ if (!rc) break; /* * Wait for few milli seconds for line count * to increase if any frame transfer is * pending. */ usleep_range(3000, 4000); } pp->ops.connect_external_te(pp, true); return rc; } /** /** * sde_rm_get_pp_dsc_for_cont_splash - retrieve the current dsc enabled blocks * sde_rm_get_pp_dsc_for_cont_splash - retrieve the current dsc enabled blocks * and disable autorefresh if enabled. * and disable autorefresh if enabled. Loading @@ -1181,9 +1286,7 @@ static int _sde_rm_get_pp_dsc_for_cont_splash(struct sde_rm *rm, { { int index = 0; int index = 0; int value, dsc_cnt = 0; int value, dsc_cnt = 0; struct sde_hw_autorefresh cfg; struct sde_rm_hw_iter iter_pp; struct sde_rm_hw_iter iter_pp; int irq_idx_pp_done = -1; if (!rm || !sde_kms || !dsc_ids) { if (!rm || !sde_kms || !dsc_ids) { SDE_ERROR("invalid input parameters\n"); SDE_ERROR("invalid input parameters\n"); Loading @@ -1195,11 +1298,7 @@ static int _sde_rm_get_pp_dsc_for_cont_splash(struct sde_rm *rm, while (_sde_rm_get_hw_locked(rm, &iter_pp)) { while (_sde_rm_get_hw_locked(rm, &iter_pp)) { struct sde_hw_pingpong *pp = struct sde_hw_pingpong *pp = to_sde_hw_pingpong(iter_pp.blk->hw); to_sde_hw_pingpong(iter_pp.blk->hw); u32 intr_value = 0; u32 const timeout_ms = 35; /* Max two vsyncs delay */ int rc = 0, i, loop = 2; struct sde_hw_intr *hw_intr = NULL; struct sde_hw_intr *hw_intr = NULL; struct sde_hw_pp_vsync_info info; if (!pp->ops.get_dsc_status) { if (!pp->ops.get_dsc_status) { SDE_ERROR("get_dsc_status ops not initialized\n"); SDE_ERROR("get_dsc_status ops not initialized\n"); Loading @@ -1219,70 +1318,7 @@ static int _sde_rm_get_pp_dsc_for_cont_splash(struct sde_rm *rm, } } index++; index++; if (!pp->ops.get_autorefresh) { _sde_rm_autorefresh_disable(pp, hw_intr); SDE_ERROR("get_autorefresh api not supported\n"); return 0; } memset(&cfg, 0, sizeof(cfg)); if (!pp->ops.get_autorefresh(pp, &cfg) && (cfg.enable) && (pp->ops.setup_autorefresh)) { if (hw_intr->ops.irq_idx_lookup) { irq_idx_pp_done = hw_intr->ops.irq_idx_lookup (SDE_IRQ_TYPE_PING_PONG_COMP, pp->idx); SDE_DEBUG(" itr_idx = %d\n", irq_idx_pp_done); } if ((irq_idx_pp_done >= 0) && (hw_intr->ops.get_intr_status_nomask)) { intr_value = hw_intr->ops.get_intr_status_nomask (hw_intr, irq_idx_pp_done, false); hw_intr->ops.clear_intr_status_force_mask (hw_intr, irq_idx_pp_done, intr_value); } cfg.enable = false; SDE_DEBUG("Disabling autorefresh\n"); pp->ops.setup_autorefresh(pp, &cfg); /* * Check the line count again if * the line count is equal to the active * height to make sure their is no * additional frame updates */ for (i = 0; i < loop; i++) { info.wr_ptr_line_count = 0; info.rd_ptr_init_val = 0; if (pp->ops.get_vsync_info) pp->ops.get_vsync_info(pp, &info); /* * For cmd-mode using external-TE logic, * the rd_ptr_init_val is equal to * active-height. Use this init_val to * compare that with lane count. Need * to implement a different check * if external-TE is not used. */ if (info.wr_ptr_line_count < info.rd_ptr_init_val) { /* wait for read ptr intr */ rc = _sde_rm_poll_intr_status_for_cont_splash (hw_intr, irq_idx_pp_done, timeout_ms); if (!rc) break; } SDE_DEBUG("i=%d, line count=%d\n", i, info.wr_ptr_line_count); /* * Wait for few milli seconds for line count * to increase if any frame transfer is * pending. */ usleep_range(3000, 4000); } } } } return dsc_cnt; return dsc_cnt; Loading Loading
drivers/gpu/drm/msm/sde/sde_rm.c +122 −86 Original line number Original line Diff line number Diff line /* /* * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * * This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -1129,17 +1129,29 @@ static int _sde_rm_make_next_rsvp( return ret; return ret; } } /** static void _sde_rm_clear_irq_status(struct sde_hw_intr *hw_intr, * poll_intr_status - Gets HW interrupt status based on int irq_idx_pp_done, int irq_idx_autorefresh) * given lookup IRQ index. { * @intr: HW interrupt handle u32 intr_value = 0; * @irq_idx: Lookup irq index return from irq_idx_lookup * @msec: Maximum delay allowed to check intr status if ((irq_idx_pp_done >= 0) && (hw_intr->ops.get_intr_status_nomask)) { * return: return zero on success. intr_value = hw_intr->ops.get_intr_status_nomask(hw_intr, */ irq_idx_pp_done, false); static u32 _sde_rm_poll_intr_status_for_cont_splash hw_intr->ops.clear_intr_status_force_mask(hw_intr, (struct sde_hw_intr *intr, irq_idx_pp_done, intr_value); int irq_idx, u32 const msec) } if ((irq_idx_autorefresh >= 0) && (hw_intr->ops.get_intr_status_nomask)) { intr_value = hw_intr->ops.get_intr_status_nomask(hw_intr, irq_idx_autorefresh, false); hw_intr->ops.clear_intr_status_force_mask(hw_intr, irq_idx_autorefresh, intr_value); } } static u32 _sde_rm_poll_intr_status_for_cont_splash(struct sde_hw_intr *intr, int irq_idx_pp_done, int irq_idx_autorefresh, u32 const msec) { { int i; int i; u32 status = 0; u32 status = 0; Loading @@ -1153,19 +1165,112 @@ static u32 _sde_rm_poll_intr_status_for_cont_splash for (i = 0; i < loop; i++) { for (i = 0; i < loop; i++) { status = intr->ops.get_intr_status_nomask status = intr->ops.get_intr_status_nomask (intr, irq_idx, false); (intr, irq_idx_pp_done, false); if (status & BIT(irq_idx)) { if (status & BIT(irq_idx_pp_done)) { SDE_DEBUG(" Poll success. i=%d, status=0x%x\n", SDE_DEBUG("pp_done received i=%d, status=0x%x\n", i, status); i, status); SDE_EVT32(status, i, irq_idx_pp_done); if (status & BIT(irq_idx_autorefresh)) _sde_rm_clear_irq_status(intr, irq_idx_pp_done, irq_idx_autorefresh); else return 0; return 0; } } usleep_range(delay_us, delay_us + 10); usleep_range(delay_us, delay_us + 10); } } SDE_EVT32(status, irq_idx_pp_done, SDE_EVTLOG_ERROR); SDE_ERROR("polling timed out. status = 0x%x\n", status); SDE_ERROR("polling timed out. status = 0x%x\n", status); return -ETIMEDOUT; return -ETIMEDOUT; } } static int _sde_rm_autorefresh_disable(struct sde_hw_pingpong *pp, struct sde_hw_intr *hw_intr) { u32 const timeout_ms = 35; /* Max two vsyncs delay */ int rc = 0, i, loop = 3; struct sde_hw_pp_vsync_info info; int irq_idx_pp_done = -1, irq_idx_autorefresh = -1; struct sde_hw_autorefresh cfg = {0}; if (!pp->ops.get_autorefresh || !pp->ops.setup_autorefresh || !pp->ops.connect_external_te || !pp->ops.get_vsync_info) { SDE_ERROR("autorefresh update api not supported\n"); return 0; } /* read default autorefresh configuration */ pp->ops.get_autorefresh(pp, &cfg); if (!cfg.enable) { SDE_DEBUG("autorefresh already disabled\n"); SDE_EVT32(pp->idx - PINGPONG_0, SDE_EVTLOG_FUNC_CASE1); return 0; } /* disable external TE first */ pp->ops.connect_external_te(pp, false); /* get all IRQ indexes */ if (hw_intr->ops.irq_idx_lookup) { irq_idx_pp_done = hw_intr->ops.irq_idx_lookup( SDE_IRQ_TYPE_PING_PONG_COMP, pp->idx); irq_idx_autorefresh = hw_intr->ops.irq_idx_lookup( SDE_IRQ_TYPE_PING_PONG_AUTO_REF, pp->idx); SDE_DEBUG("pp_done itr_idx = %d autorefresh irq_idx:%d\n", irq_idx_pp_done, irq_idx_autorefresh); } /* disable autorefresh */ cfg.enable = false; pp->ops.setup_autorefresh(pp, &cfg); SDE_EVT32(pp->idx - PINGPONG_0, irq_idx_pp_done, irq_idx_autorefresh); _sde_rm_clear_irq_status(hw_intr, irq_idx_pp_done, irq_idx_autorefresh); /* * Check the line count again if * the line count is equal to the active * height to make sure their is no * additional frame updates */ for (i = 0; i < loop; i++) { info.wr_ptr_line_count = 0; info.rd_ptr_init_val = 0; pp->ops.get_vsync_info(pp, &info); SDE_EVT32(pp->idx - PINGPONG_0, info.wr_ptr_line_count, info.rd_ptr_init_val, SDE_EVTLOG_FUNC_CASE1); /* wait for read ptr intr */ rc = _sde_rm_poll_intr_status_for_cont_splash(hw_intr, irq_idx_pp_done, irq_idx_autorefresh, timeout_ms); info.wr_ptr_line_count = 0; info.rd_ptr_init_val = 0; pp->ops.get_vsync_info(pp, &info); SDE_DEBUG("i=%d, line count=%d\n", i, info.wr_ptr_line_count); SDE_EVT32(pp->idx - PINGPONG_0, info.wr_ptr_line_count, info.rd_ptr_init_val, SDE_EVTLOG_FUNC_CASE2); /* log line count and return */ if (!rc) break; /* * Wait for few milli seconds for line count * to increase if any frame transfer is * pending. */ usleep_range(3000, 4000); } pp->ops.connect_external_te(pp, true); return rc; } /** /** * sde_rm_get_pp_dsc_for_cont_splash - retrieve the current dsc enabled blocks * sde_rm_get_pp_dsc_for_cont_splash - retrieve the current dsc enabled blocks * and disable autorefresh if enabled. * and disable autorefresh if enabled. Loading @@ -1181,9 +1286,7 @@ static int _sde_rm_get_pp_dsc_for_cont_splash(struct sde_rm *rm, { { int index = 0; int index = 0; int value, dsc_cnt = 0; int value, dsc_cnt = 0; struct sde_hw_autorefresh cfg; struct sde_rm_hw_iter iter_pp; struct sde_rm_hw_iter iter_pp; int irq_idx_pp_done = -1; if (!rm || !sde_kms || !dsc_ids) { if (!rm || !sde_kms || !dsc_ids) { SDE_ERROR("invalid input parameters\n"); SDE_ERROR("invalid input parameters\n"); Loading @@ -1195,11 +1298,7 @@ static int _sde_rm_get_pp_dsc_for_cont_splash(struct sde_rm *rm, while (_sde_rm_get_hw_locked(rm, &iter_pp)) { while (_sde_rm_get_hw_locked(rm, &iter_pp)) { struct sde_hw_pingpong *pp = struct sde_hw_pingpong *pp = to_sde_hw_pingpong(iter_pp.blk->hw); to_sde_hw_pingpong(iter_pp.blk->hw); u32 intr_value = 0; u32 const timeout_ms = 35; /* Max two vsyncs delay */ int rc = 0, i, loop = 2; struct sde_hw_intr *hw_intr = NULL; struct sde_hw_intr *hw_intr = NULL; struct sde_hw_pp_vsync_info info; if (!pp->ops.get_dsc_status) { if (!pp->ops.get_dsc_status) { SDE_ERROR("get_dsc_status ops not initialized\n"); SDE_ERROR("get_dsc_status ops not initialized\n"); Loading @@ -1219,70 +1318,7 @@ static int _sde_rm_get_pp_dsc_for_cont_splash(struct sde_rm *rm, } } index++; index++; if (!pp->ops.get_autorefresh) { _sde_rm_autorefresh_disable(pp, hw_intr); SDE_ERROR("get_autorefresh api not supported\n"); return 0; } memset(&cfg, 0, sizeof(cfg)); if (!pp->ops.get_autorefresh(pp, &cfg) && (cfg.enable) && (pp->ops.setup_autorefresh)) { if (hw_intr->ops.irq_idx_lookup) { irq_idx_pp_done = hw_intr->ops.irq_idx_lookup (SDE_IRQ_TYPE_PING_PONG_COMP, pp->idx); SDE_DEBUG(" itr_idx = %d\n", irq_idx_pp_done); } if ((irq_idx_pp_done >= 0) && (hw_intr->ops.get_intr_status_nomask)) { intr_value = hw_intr->ops.get_intr_status_nomask (hw_intr, irq_idx_pp_done, false); hw_intr->ops.clear_intr_status_force_mask (hw_intr, irq_idx_pp_done, intr_value); } cfg.enable = false; SDE_DEBUG("Disabling autorefresh\n"); pp->ops.setup_autorefresh(pp, &cfg); /* * Check the line count again if * the line count is equal to the active * height to make sure their is no * additional frame updates */ for (i = 0; i < loop; i++) { info.wr_ptr_line_count = 0; info.rd_ptr_init_val = 0; if (pp->ops.get_vsync_info) pp->ops.get_vsync_info(pp, &info); /* * For cmd-mode using external-TE logic, * the rd_ptr_init_val is equal to * active-height. Use this init_val to * compare that with lane count. Need * to implement a different check * if external-TE is not used. */ if (info.wr_ptr_line_count < info.rd_ptr_init_val) { /* wait for read ptr intr */ rc = _sde_rm_poll_intr_status_for_cont_splash (hw_intr, irq_idx_pp_done, timeout_ms); if (!rc) break; } SDE_DEBUG("i=%d, line count=%d\n", i, info.wr_ptr_line_count); /* * Wait for few milli seconds for line count * to increase if any frame transfer is * pending. */ usleep_range(3000, 4000); } } } } return dsc_cnt; return dsc_cnt; Loading