Pass &bool to zynq_slcr_compute_clocks[_internal](), so we can pass it to the clock_set() calls which might update it. Then check it and only call zynq_slcr_propagate_clocks() and clock_propagate() when necessary.
Signed-off-by: Philippe Mathieu-Daudé <phi...@linaro.org> --- hw/misc/zynq_slcr.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c index e637798507..ad9c575137 100644 --- a/hw/misc/zynq_slcr.c +++ b/hw/misc/zynq_slcr.c @@ -269,7 +269,8 @@ static uint64_t zynq_slcr_compute_clock(const uint64_t periods[], zynq_slcr_compute_clock((plls), (state)->regs[reg], \ reg ## _ ## enable_field ## _SHIFT) -static void zynq_slcr_compute_clocks_internal(ZynqSLCRState *s, uint64_t ps_clk) +static void zynq_slcr_compute_clocks_internal(ZynqSLCRState *s, uint64_t ps_clk, + bool *changed) { uint64_t io_pll = zynq_slcr_compute_pll(ps_clk, s->regs[R_IO_PLL_CTRL]); uint64_t arm_pll = zynq_slcr_compute_pll(ps_clk, s->regs[R_ARM_PLL_CTRL]); @@ -279,9 +280,9 @@ static void zynq_slcr_compute_clocks_internal(ZynqSLCRState *s, uint64_t ps_clk) /* compute uartX reference clocks */ clock_set(s->uart0_ref_clk, - ZYNQ_COMPUTE_CLK(s, uart_mux, R_UART_CLK_CTRL, CLKACT0), NULL); + ZYNQ_COMPUTE_CLK(s, uart_mux, R_UART_CLK_CTRL, CLKACT0), changed); clock_set(s->uart1_ref_clk, - ZYNQ_COMPUTE_CLK(s, uart_mux, R_UART_CLK_CTRL, CLKACT1), NULL); + ZYNQ_COMPUTE_CLK(s, uart_mux, R_UART_CLK_CTRL, CLKACT1), changed); } /** @@ -289,7 +290,7 @@ static void zynq_slcr_compute_clocks_internal(ZynqSLCRState *s, uint64_t ps_clk) * But do not propagate them further. Connected clocks * will not receive any updates (See zynq_slcr_compute_clocks()) */ -static void zynq_slcr_compute_clocks(ZynqSLCRState *s) +static void zynq_slcr_compute_clocks(ZynqSLCRState *s, bool *changed) { uint64_t ps_clk = clock_get(s->ps_clk); @@ -298,7 +299,7 @@ static void zynq_slcr_compute_clocks(ZynqSLCRState *s) ps_clk = 0; } - zynq_slcr_compute_clocks_internal(s, ps_clk); + zynq_slcr_compute_clocks_internal(s, ps_clk, changed); } /** @@ -315,9 +316,12 @@ static void zynq_slcr_propagate_clocks(ZynqSLCRState *s) static void zynq_slcr_ps_clk_callback(void *opaque, ClockEvent event) { ZynqSLCRState *s = (ZynqSLCRState *) opaque; + bool propagate = false; - zynq_slcr_compute_clocks(s); - zynq_slcr_propagate_clocks(s); + zynq_slcr_compute_clocks(s, &propagate); + if (propagate) { + zynq_slcr_propagate_clocks(s); + } } static void zynq_slcr_reset_init(Object *obj, ResetType type) @@ -419,19 +423,25 @@ static void zynq_slcr_reset_init(Object *obj, ResetType type) static void zynq_slcr_reset_hold(Object *obj) { ZynqSLCRState *s = ZYNQ_SLCR(obj); + bool propagate = false; /* will disable all output clocks */ - zynq_slcr_compute_clocks_internal(s, 0); - zynq_slcr_propagate_clocks(s); + zynq_slcr_compute_clocks_internal(s, 0, &propagate); + if (propagate) { + zynq_slcr_propagate_clocks(s); + } } static void zynq_slcr_reset_exit(Object *obj) { ZynqSLCRState *s = ZYNQ_SLCR(obj); + bool propagate = false; /* will compute output clocks according to ps_clk and registers */ - zynq_slcr_compute_clocks_internal(s, clock_get(s->ps_clk)); - zynq_slcr_propagate_clocks(s); + zynq_slcr_compute_clocks_internal(s, clock_get(s->ps_clk), &propagate); + if (propagate) { + zynq_slcr_propagate_clocks(s); + } } static bool zynq_slcr_check_offset(hwaddr offset, bool rnw) @@ -516,6 +526,7 @@ static void zynq_slcr_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) { ZynqSLCRState *s = (ZynqSLCRState *)opaque; + bool propagate = false; offset /= 4; DB_PRINT("addr: %08" HWADDR_PRIx " data: %08" PRIx64 "\n", offset * 4, val); @@ -569,8 +580,10 @@ static void zynq_slcr_write(void *opaque, hwaddr offset, case R_ARM_PLL_CTRL: case R_DDR_PLL_CTRL: case R_UART_CLK_CTRL: - zynq_slcr_compute_clocks(s); - zynq_slcr_propagate_clocks(s); + zynq_slcr_compute_clocks(s, &propagate); + if (propagate) { + zynq_slcr_propagate_clocks(s); + } break; } } -- 2.41.0