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 Inline Diff

arch/arm/mach-imx/imx8/lpcg.c
1 /* 1 /*
2 * Copyright 2017-2018 NXP 2 * Copyright 2017-2019 NXP
3 * 3 *
4 * SPDX-License-Identifier: GPL-2.0+ 4 * SPDX-License-Identifier: GPL-2.0+
5 */ 5 */
6 6
7 #include <common.h> 7 #include <common.h>
8 #include <asm/io.h> 8 #include <asm/io.h>
9 #include <linux/errno.h> 9 #include <linux/errno.h>
10 #include <asm/arch/lpcg.h> 10 #include <asm/arch/lpcg.h>
11 11
12 #define LPCG_CLOCK_MASK 0x3U 12 #define LPCG_CLOCK_MASK 0x3U
13 #define LPCG_CLOCK_OFF 0x0U 13 #define LPCG_CLOCK_OFF 0x0U
14 #define LPCG_CLOCK_ON 0x2U 14 #define LPCG_CLOCK_ON 0x2U
15 #define LPCG_CLOCK_AUTO 0x3U 15 #define LPCG_CLOCK_AUTO 0x3U
16 #define LPCG_CLOCK_STOP 0x8U 16 #define LPCG_CLOCK_STOP 0x8U
17 17
18 #define LPCG_ALL_CLOCK_OFF 0x00000000U 18 #define LPCG_ALL_CLOCK_OFF 0x00000000U
19 #define LPCG_ALL_CLOCK_ON 0x22222222U 19 #define LPCG_ALL_CLOCK_ON 0x22222222U
20 #define LPCG_ALL_CLOCK_AUTO 0x33333333U 20 #define LPCG_ALL_CLOCK_AUTO 0x33333333U
21 #define LPCG_ALL_CLOCK_STOP 0x88888888U 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 void LPCG_ClockOff(u32 lpcg_addr, u8 clk) 35 void LPCG_ClockOff(u32 lpcg_addr, u8 clk)
24 { 36 {
25 u32 lpcgVal; 37 u32 lpcgVal;
26 38
27 /* Read from LPCG */ 39 /* Read from LPCG */
28 lpcgVal = readl((ulong)lpcg_addr); 40 lpcgVal = readl((ulong)lpcg_addr);
29 41
30 /* Modify */ 42 /* Modify */
31 lpcgVal &= ~((u32)(LPCG_CLOCK_MASK) << (clk * 4U)); 43 lpcgVal &= ~((u32)(LPCG_CLOCK_MASK) << (clk * 4U));
32 lpcgVal |= ((u32)(LPCG_CLOCK_OFF) << (clk * 4U)); 44 lpcgVal |= ((u32)(LPCG_CLOCK_OFF) << (clk * 4U));
33 45
34 /* Write to LPCG */ 46 /* Write to LPCG */
35 writel(lpcgVal, (ulong)lpcg_addr); 47 lpcg_write(lpcgVal, (ulong)lpcg_addr);
36 } 48 }
37 49
38 void LPCG_ClockOn(u32 lpcg_addr, u8 clk) 50 void LPCG_ClockOn(u32 lpcg_addr, u8 clk)
39 { 51 {
40 u32 lpcgVal; 52 u32 lpcgVal;
41 53
42 /* Read from LPCG */ 54 /* Read from LPCG */
43 lpcgVal = readl((ulong)lpcg_addr); 55 lpcgVal = readl((ulong)lpcg_addr);
44 56
45 /* Modify */ 57 /* Modify */
46 lpcgVal &= ~((u32)(LPCG_CLOCK_MASK) << (clk * 4U)); 58 lpcgVal &= ~((u32)(LPCG_CLOCK_MASK) << (clk * 4U));
47 lpcgVal |= ((u32)(LPCG_CLOCK_ON) << (clk * 4U)); 59 lpcgVal |= ((u32)(LPCG_CLOCK_ON) << (clk * 4U));
48 60
49 /* Write to LPCG */ 61 /* Write to LPCG */
50 writel(lpcgVal, (ulong)lpcg_addr); 62 lpcg_write(lpcgVal, (ulong)lpcg_addr);
51 } 63 }
52 64
53 void LPCG_ClockAutoGate(u32 lpcg_addr, u8 clk) 65 void LPCG_ClockAutoGate(u32 lpcg_addr, u8 clk)
54 { 66 {
55 u32 lpcgVal; 67 u32 lpcgVal;
56 68
57 /* Read from LPCG */ 69 /* Read from LPCG */
58 lpcgVal = readl((ulong)lpcg_addr); 70 lpcgVal = readl((ulong)lpcg_addr);
59 71
60 /* Modify */ 72 /* Modify */
61 lpcgVal &= ~((u32)(LPCG_CLOCK_MASK) << (clk * 4U)); 73 lpcgVal &= ~((u32)(LPCG_CLOCK_MASK) << (clk * 4U));
62 lpcgVal |= ((u32)(LPCG_CLOCK_AUTO) << (clk * 4U)); 74 lpcgVal |= ((u32)(LPCG_CLOCK_AUTO) << (clk * 4U));
63 75
64 /* Write to LPCG */ 76 /* Write to LPCG */
65 writel(lpcgVal, (ulong)lpcg_addr); 77 lpcg_write(lpcgVal, (ulong)lpcg_addr);
66 } 78 }
67 79
68 void LPCG_AllClockOff(u32 lpcg_addr) 80 void LPCG_AllClockOff(u32 lpcg_addr)
69 { 81 {
70 /* Write to LPCG */ 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 void LPCG_AllClockOn(u32 lpcg_addr) 86 void LPCG_AllClockOn(u32 lpcg_addr)
75 { 87 {
76 /* Write to LPCG */ 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 /* Wait for clocks to start */ 91 /* Wait for clocks to start */
80 while ((readl((ulong)lpcg_addr) & LPCG_ALL_CLOCK_STOP) != 0U) 92 while ((readl((ulong)lpcg_addr) & LPCG_ALL_CLOCK_STOP) != 0U)
81 { 93 {
82 } 94 }
83 } 95 }
84 96
85 void LPCG_AllClockAutoGate(u32 lpcg_addr) 97 void LPCG_AllClockAutoGate(u32 lpcg_addr)
86 { 98 {
87 /* Write to LPCG */ 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 }
90 102