1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) ASPEED Technology Inc.
4 */
5 #include <common.h>
6 #include <asm/io.h>
7
8 #define SCU_BASE 0x1e6e2000
9 #define ESPI_BASE 0x1e6ee000
10 #define LPC_BASE 0x1e789000
11 #define LPC_HICR5 (LPC_BASE + 0x80)
12 #define LPC_HICR6 (LPC_BASE + 0x84)
13 #define LPC_SNPWADR (LPC_BASE + 0x90)
14 #define LPC_HICRB (LPC_BASE + 0x100)
15 #define GPIO_BASE 0x1e780000
16
17 /* HICR5 Bits */
18 #define HICR5_EN_SIOGIO BIT(31) /* Enable SIOGIO */
19 #define HICR5_EN80HGIO BIT(30) /* Enable 80hGIO */
20 #define HICR5_SEL80HGIO (0x1f << 24) /* Select 80hGIO */
21 #define SET_SEL80HGIO(x) ((x & 0x1f) << 24) /* Select 80hGIO Offset */
22 #define HICR5_UNKVAL_MASK 0x1FFF0000 /* Bits with unknown values on reset */
23 #define HICR5_ENINT_SNP0W BIT(1) /* Enable Snooping address 0 */
24 #define HICR5_EN_SNP0W BIT(0) /* Enable Snooping address 0 */
25
26 /* HRCR6 Bits */
27 #define HICR6_STR_SNP0W BIT(0) /* Interrupt Status Snoop address 0 */
28 #define HICR6_STR_SNP1W BIT(1) /* Interrupt Status Snoop address 1 */
29
30 /* HICRB Bits */
31 #define HICRB_EN80HSGIO BIT(13) /* Enable 80hSGIO */
32
port80h_snoop_init(void)33 static void __maybe_unused port80h_snoop_init(void)
34 {
35 u32 value;
36 /* enable port80h snoop and sgpio */
37 /* set lpc snoop #0 to port 0x80 */
38 value = readl(LPC_SNPWADR) & 0xffff0000;
39 writel(value | 0x80, LPC_SNPWADR);
40
41 /* clear interrupt status */
42 value = readl(LPC_HICR6);
43 value |= HICR6_STR_SNP0W | HICR6_STR_SNP1W;
44 writel(value, LPC_HICR6);
45
46 /* enable lpc snoop #0 and SIOGIO */
47 value = readl(LPC_HICR5) & ~(HICR5_UNKVAL_MASK);
48 value |= HICR5_EN_SIOGIO | HICR5_EN_SNP0W;
49 writel(value, LPC_HICR5);
50
51 /* enable port80h snoop on SGPIO */
52 value = readl(LPC_HICRB) | HICRB_EN80HSGIO;
53 writel(value, LPC_HICRB);
54 }
55
sgpio_init(void)56 static void __maybe_unused sgpio_init(void)
57 {
58 #define SGPIO_CLK_DIV(N) ((N) << 16)
59 #define SGPIO_BYTES(N) ((N) << 6)
60 #define SGPIO_ENABLE 1
61 #define GPIO554 0x554
62 #define SCU_414 0x414 /* Multi-function Pin Control #5 */
63 #define SCU_414_SGPM_MASK GENMASK(27, 24)
64
65 u32 value;
66 /* set the sgpio clock to pclk/(2*(5+1)) or ~2 MHz */
67 value = SGPIO_CLK_DIV(256) | SGPIO_BYTES(10) | SGPIO_ENABLE;
68 writel(value, GPIO_BASE + GPIO554);
69 writel(readl(SCU_BASE | SCU_414) | SCU_414_SGPM_MASK,
70 SCU_BASE | SCU_414);
71 }
72
espi_init(void)73 static void __maybe_unused espi_init(void)
74 {
75 u32 reg;
76
77 /* skip eSPI init if LPC mode is selected */
78 reg = readl(SCU_BASE + 0x510);
79 if (reg & BIT(6))
80 return;
81
82 /*
83 * Aspeed STRONGLY NOT recommend to use eSPI early init.
84 *
85 * This eSPI early init sequence merely set OOB_FREE. It
86 * is NOT able to actually handle OOB requests from PCH.
87 *
88 * During the power on stage, PCH keep waiting OOB_FREE
89 * to continue its booting. In general, OOB_FREE is set
90 * when BMC firmware is ready. That is, the eSPI kernel
91 * driver is mounted and ready to serve eSPI. However,
92 * it means that PCH must wait until BMC kernel ready.
93 *
94 * For customers that request PCH booting as soon as
95 * possible. You may use this early init to set OOB_FREE
96 * to prevent PCH from blocking by OOB_FREE before BMC
97 * kernel ready.
98 *
99 * If you are not sure what you are doing, DO NOT use it.
100 */
101 reg = readl(ESPI_BASE + 0x000);
102 reg |= 0xef;
103 writel(reg, ESPI_BASE + 0x000);
104
105 writel(0x0, ESPI_BASE + 0x110);
106 writel(0x0, ESPI_BASE + 0x114);
107
108 reg = readl(ESPI_BASE + 0x00c);
109 reg |= 0x80000000;
110 writel(reg, ESPI_BASE + 0x00c);
111
112 writel(0xffffffff, ESPI_BASE + 0x094);
113 writel(0x1, ESPI_BASE + 0x100);
114 writel(0x1, ESPI_BASE + 0x120);
115
116 reg = readl(ESPI_BASE + 0x080);
117 reg |= 0x50;
118 writel(reg, ESPI_BASE + 0x080);
119
120 reg = readl(ESPI_BASE + 0x000);
121 reg |= 0x10;
122 writel(reg, ESPI_BASE + 0x000);
123 }
124
acpi_init(void)125 void __maybe_unused acpi_init(void)
126 {
127 u32 reg;
128
129 reg = readl(SCU_BASE + 0x510);
130
131 if (reg & BIT(30)) {
132 reg = BIT(5);
133 writel(reg, SCU_BASE + 0x510);
134 } else {
135 reg = readl(SCU_BASE + 0x51c);
136 reg |= BIT(10);
137 writel(reg, SCU_BASE + 0x51c);
138 }
139
140 /* PIN Mux */
141 reg = readl(SCU_BASE + 0x434);
142 reg |= BIT(8) | BIT(9) | BIT(10) | BIT(11) | BIT(12);
143 writel(reg, SCU_BASE + 0x434);
144 }
145
reset_eth_phy_dcscm_card_a2(void)146 void reset_eth_phy_dcscm_card_a2(void)
147 {
148 #define GRP_C 16
149 #define PHY_RESET_MASK (BIT(GRP_C + 1))
150 u32 value = readl(0x1e780000);
151 u32 direction = readl(0x1e780004);
152
153 debug("AST2600-DCSCM A2 card reset phy\n");
154
155 direction |= PHY_RESET_MASK;
156 value &= ~PHY_RESET_MASK;
157 writel(direction, 0x1e780004);
158 writel(value, 0x1e780000);
159 while ((readl(0x1e780000) & PHY_RESET_MASK) != 0)
160 ;
161
162 /* Tgap = 10ms */
163 mdelay(10);
164
165 value |= PHY_RESET_MASK;
166 writel(value, 0x1e780000);
167 while ((readl(0x1e780000) & PHY_RESET_MASK) != PHY_RESET_MASK)
168 ;
169 }
170
board_early_init_f(void)171 int board_early_init_f(void)
172 {
173 #if CONFIG_AVENUE_CITY_CRB
174 port80h_snoop_init();
175 sgpio_init();
176 acpi_init();
177 #endif
178 espi_init();
179
180 reset_eth_phy_dcscm_card_a2();
181 return 0;
182 }
183