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