From 487875a832c5b16bd2b40e1ac65c201d4ee28da7 Mon Sep 17 00:00:00 2001 From: Ye Li Date: Sun, 24 Feb 2019 20:08:43 -0800 Subject: [PATCH] MLK-21165 imx8: Workaround LPCG HW issue There are two LPCG HW issues reported in TKT322331. Add workaround for them in u-boot. 1. Back to back LPCG write access must have 4x DSC cycle interval. 2. When DSC clock is gated, LPCG write access may be missed due to the edge detect is not see by DSC. Two writes shall be performed to re-enable the clock if DSC clock is gated Signed-off-by: Ye Li Reviewed-by: Peng Fan (cherry picked from commit 96186ca0048e6ae261176e5f3ebf02be09bacb08) --- arch/arm/mach-imx/imx8/lpcg.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-imx/imx8/lpcg.c b/arch/arm/mach-imx/imx8/lpcg.c index 7e91574..22cbc60 100644 --- a/arch/arm/mach-imx/imx8/lpcg.c +++ b/arch/arm/mach-imx/imx8/lpcg.c @@ -1,5 +1,5 @@ /* - * Copyright 2017-2018 NXP + * Copyright 2017-2019 NXP * * SPDX-License-Identifier: GPL-2.0+ */ @@ -20,6 +20,18 @@ #define LPCG_ALL_CLOCK_AUTO 0x33333333U #define LPCG_ALL_CLOCK_STOP 0x88888888U +static inline void lpcg_write(u32 lpcgVal, ulong lpcg_addr) +{ + /* + * Write twice with 4x DSC clock cycles (40x IPS clock cycles) interval + * to work around LPCG issue + */ + writel(lpcgVal, lpcg_addr); + udelay(10); /* 10us is enough. Worst case is 40x IPS cycle (200Mhz) */ + writel(lpcgVal, lpcg_addr); + udelay(10); +} + void LPCG_ClockOff(u32 lpcg_addr, u8 clk) { u32 lpcgVal; @@ -32,7 +44,7 @@ void LPCG_ClockOff(u32 lpcg_addr, u8 clk) lpcgVal |= ((u32)(LPCG_CLOCK_OFF) << (clk * 4U)); /* Write to LPCG */ - writel(lpcgVal, (ulong)lpcg_addr); + lpcg_write(lpcgVal, (ulong)lpcg_addr); } void LPCG_ClockOn(u32 lpcg_addr, u8 clk) @@ -47,7 +59,7 @@ void LPCG_ClockOn(u32 lpcg_addr, u8 clk) lpcgVal |= ((u32)(LPCG_CLOCK_ON) << (clk * 4U)); /* Write to LPCG */ - writel(lpcgVal, (ulong)lpcg_addr); + lpcg_write(lpcgVal, (ulong)lpcg_addr); } void LPCG_ClockAutoGate(u32 lpcg_addr, u8 clk) @@ -62,19 +74,19 @@ void LPCG_ClockAutoGate(u32 lpcg_addr, u8 clk) lpcgVal |= ((u32)(LPCG_CLOCK_AUTO) << (clk * 4U)); /* Write to LPCG */ - writel(lpcgVal, (ulong)lpcg_addr); + lpcg_write(lpcgVal, (ulong)lpcg_addr); } void LPCG_AllClockOff(u32 lpcg_addr) { /* Write to LPCG */ - writel(LPCG_ALL_CLOCK_OFF, (ulong)lpcg_addr); + lpcg_write(LPCG_ALL_CLOCK_OFF, (ulong)lpcg_addr); } void LPCG_AllClockOn(u32 lpcg_addr) { /* Write to LPCG */ - writel(LPCG_ALL_CLOCK_ON, (ulong)lpcg_addr); + lpcg_write(LPCG_ALL_CLOCK_ON, (ulong)lpcg_addr); /* Wait for clocks to start */ while ((readl((ulong)lpcg_addr) & LPCG_ALL_CLOCK_STOP) != 0U) @@ -85,5 +97,5 @@ void LPCG_AllClockOn(u32 lpcg_addr) void LPCG_AllClockAutoGate(u32 lpcg_addr) { /* Write to LPCG */ - writel(LPCG_ALL_CLOCK_AUTO, (ulong)lpcg_addr); + lpcg_write(LPCG_ALL_CLOCK_AUTO, (ulong)lpcg_addr); } -- 1.9.1