Commit 487875a832c5b16bd2b40e1ac65c201d4ee28da7

Authored by Ye Li
1 parent 47096e5310

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 <ye.li@nxp.com>
Reviewed-by: Peng Fan <peng.fan@nxp.com>
(cherry picked from commit 96186ca0048e6ae261176e5f3ebf02be09bacb08)

Showing 1 changed file with 19 additions and 7 deletions Side-by-side Diff

arch/arm/mach-imx/imx8/lpcg.c
1 1 /*
2   - * Copyright 2017-2018 NXP
  2 + * Copyright 2017-2019 NXP
3 3 *
4 4 * SPDX-License-Identifier: GPL-2.0+
5 5 */
... ... @@ -20,6 +20,18 @@
20 20 #define LPCG_ALL_CLOCK_AUTO 0x33333333U
21 21 #define LPCG_ALL_CLOCK_STOP 0x88888888U
22 22  
  23 +static inline void lpcg_write(u32 lpcgVal, ulong lpcg_addr)
  24 +{
  25 + /*
  26 + * Write twice with 4x DSC clock cycles (40x IPS clock cycles) interval
  27 + * to work around LPCG issue
  28 + */
  29 + writel(lpcgVal, lpcg_addr);
  30 + udelay(10); /* 10us is enough. Worst case is 40x IPS cycle (200Mhz) */
  31 + writel(lpcgVal, lpcg_addr);
  32 + udelay(10);
  33 +}
  34 +
23 35 void LPCG_ClockOff(u32 lpcg_addr, u8 clk)
24 36 {
25 37 u32 lpcgVal;
... ... @@ -32,7 +44,7 @@
32 44 lpcgVal |= ((u32)(LPCG_CLOCK_OFF) << (clk * 4U));
33 45  
34 46 /* Write to LPCG */
35   - writel(lpcgVal, (ulong)lpcg_addr);
  47 + lpcg_write(lpcgVal, (ulong)lpcg_addr);
36 48 }
37 49  
38 50 void LPCG_ClockOn(u32 lpcg_addr, u8 clk)
... ... @@ -47,7 +59,7 @@
47 59 lpcgVal |= ((u32)(LPCG_CLOCK_ON) << (clk * 4U));
48 60  
49 61 /* Write to LPCG */
50   - writel(lpcgVal, (ulong)lpcg_addr);
  62 + lpcg_write(lpcgVal, (ulong)lpcg_addr);
51 63 }
52 64  
53 65 void LPCG_ClockAutoGate(u32 lpcg_addr, u8 clk)
54 66  
55 67  
... ... @@ -62,19 +74,19 @@
62 74 lpcgVal |= ((u32)(LPCG_CLOCK_AUTO) << (clk * 4U));
63 75  
64 76 /* Write to LPCG */
65   - writel(lpcgVal, (ulong)lpcg_addr);
  77 + lpcg_write(lpcgVal, (ulong)lpcg_addr);
66 78 }
67 79  
68 80 void LPCG_AllClockOff(u32 lpcg_addr)
69 81 {
70 82 /* Write to LPCG */
71   - writel(LPCG_ALL_CLOCK_OFF, (ulong)lpcg_addr);
  83 + lpcg_write(LPCG_ALL_CLOCK_OFF, (ulong)lpcg_addr);
72 84 }
73 85  
74 86 void LPCG_AllClockOn(u32 lpcg_addr)
75 87 {
76 88 /* Write to LPCG */
77   - writel(LPCG_ALL_CLOCK_ON, (ulong)lpcg_addr);
  89 + lpcg_write(LPCG_ALL_CLOCK_ON, (ulong)lpcg_addr);
78 90  
79 91 /* Wait for clocks to start */
80 92 while ((readl((ulong)lpcg_addr) & LPCG_ALL_CLOCK_STOP) != 0U)
... ... @@ -85,6 +97,6 @@
85 97 void LPCG_AllClockAutoGate(u32 lpcg_addr)
86 98 {
87 99 /* Write to LPCG */
88   - writel(LPCG_ALL_CLOCK_AUTO, (ulong)lpcg_addr);
  100 + lpcg_write(LPCG_ALL_CLOCK_AUTO, (ulong)lpcg_addr);
89 101 }