xref: /openbmc/u-boot/cmd/aspeed/peci.c (revision fd0bc623)
1 #include <common.h>
2 #include <command.h>
3 #include <string.h>
4 #include <asm/io.h>
5 
6 #define AST_SCU				(0x1e6e2000)
7 #if defined(CONFIG_ASPEED_AST2500)
8 #define AST_SCU_SYSRST_CTRL (AST_SCU + 0x04)
9 #elif defined(CONFIG_ASPEED_AST2600)
10 #define AST_SCU_SYSRST_CLR2	(AST_SCU + 0x54)
11 #endif
12 
13 #define AST_PECI			(0x1e78b000)
14 #define AST_PECI_CTRL		(AST_PECI + 0x00)
15 #define AST_PECI_TIMING		(AST_PECI + 0x04)
16 #define AST_PECI_CMD		(AST_PECI + 0x08)
17 #define AST_PECI_RW_LEN		(AST_PECI + 0x0C)
18 #define AST_PECI_EXP_FCS	(AST_PECI + 0x10)
19 #define AST_PECI_CAP_FCS	(AST_PECI + 0x14)
20 #define AST_PECI_INT_CTRL	(AST_PECI + 0x18)
21 #define AST_PECI_INT_STAT	(AST_PECI + 0x1C)
22 #define AST_PECI_WR_DATA0	(AST_PECI + 0x20)
23 #define AST_PECI_WR_DATA1	(AST_PECI + 0x24)
24 #define AST_PECI_WR_DATA2	(AST_PECI + 0x28)
25 #define AST_PECI_WR_DATA3	(AST_PECI + 0x2C)
26 #define AST_PECI_RD_DATA0	(AST_PECI + 0x30)
27 #define AST_PECI_RD_DATA1	(AST_PECI + 0x34)
28 #define AST_PECI_RD_DATA2	(AST_PECI + 0x38)
29 #define AST_PECI_RD_DATA3	(AST_PECI + 0x3C)
30 #define AST_PECI_WR_DATA4	(AST_PECI + 0x40)
31 #define AST_PECI_WR_DATA5	(AST_PECI + 0x44)
32 #define AST_PECI_WR_DATA6	(AST_PECI + 0x48)
33 #define AST_PECI_WR_DATA7	(AST_PECI + 0x4C)
34 #define AST_PECI_RD_DATA4	(AST_PECI + 0x50)
35 #define AST_PECI_RD_DATA5	(AST_PECI + 0x54)
36 #define AST_PECI_RD_DATA6	(AST_PECI + 0x58)
37 #define AST_PECI_RD_DATA7	(AST_PECI + 0x5C)
38 
39 #ifdef CONFIG_ASPEED_AST2500
40 static void ast2500_peci_init(void)
41 {
42 	unsigned int val;
43 	static bool is_init = false;
44 
45 	/* init once only */
46 	if (is_init)
47 		return;
48 
49 	/* release PECI reset */
50 	val = readl(AST_SCU_SYSRST_CTRL);
51 	val &= ~(0x1 << 10);
52 	writel(val, AST_SCU_SYSRST_CTRL);
53 
54 	/*
55 	 * 1. disable PECI
56 	 * 2. set source clock to 24Mhz oscillator
57 	 * 3. set clock divider to 8
58 	 */
59 	writel(0x80301, AST_PECI_CTRL);
60 
61 	/* set negotiate timing */
62 	writel(0x4040, AST_PECI_TIMING);
63 
64 	/* enable interrupt */
65 	writel(0x1f, AST_PECI_INT_CTRL);
66 
67 	/* enable PECI */
68 	writel(0x80311, AST_PECI_CTRL);
69 
70 	is_init = true;
71 }
72 #endif
73 
74 #ifdef CONFIG_ASPEED_AST2600
75 static void ast2600_peci_init(void)
76 {
77 	static bool is_init = false;
78 
79 	/* init once only */
80 	if (is_init)
81 		return;
82 
83 	/* release PECI reset */
84 	writel(0x10, AST_SCU_SYSRST_CLR2);
85 
86 	/*
87 	 * 1. disable PECI
88 	 * 2. set source clock to HCLK
89 	 * 3. set clock divider to 2
90 	 * 4. set 32-byte mode
91 	 */
92 	writel(0x80901, AST_PECI_CTRL);
93 
94 	/* set negotiate timing */
95 	writel(0x0303, AST_PECI_TIMING);
96 
97 	/* enable interrupt */
98 	writel(0x1f, AST_PECI_INT_CTRL);
99 
100 	/* enable PECI */
101 	writel(0x80911, AST_PECI_CTRL);
102 
103 	is_init = true;
104 }
105 #endif
106 
107 static void ast_peci_init(void)
108 {
109 #if defined(CONFIG_ASPEED_AST2500)
110 	return ast2500_peci_init();
111 #elif defined(CONFIG_ASPEED_AST2600)
112 	return ast2600_peci_init();
113 #endif
114 }
115 
116 static int do_ast_peci_ping(unsigned long client_addr)
117 {
118 	unsigned int rec_wfcs;
119 	unsigned int exp_wfcs;
120 
121 	unsigned long val;
122 	unsigned long retry = 10;
123 
124 	ast_peci_init();
125 
126 	/* make PECI no operation */
127 	writel(0x0, AST_PECI_CMD);
128 
129 	/* set client address */
130 	writel((client_addr & 0xff), AST_PECI_RW_LEN);
131 
132 	/* clear interrupt status */
133 	writel(0x1f, AST_PECI_INT_STAT);
134 
135 	/* fire PECI command */
136 	writel(0x1, AST_PECI_CMD);
137 
138 	/* wait PECI done for 10 seconds */
139 	printf("Waiting PECI ... ");
140 	while (retry) {
141 		val = readl(AST_PECI_INT_STAT);
142 		if (val & 0x1)
143 			break;
144 		printf("Retry ... ");
145 		udelay(1000000);
146 		--retry;
147 	}
148 
149 	if (retry == 0) {
150 		printf("Timeout\n");
151 		goto ping_clean_and_exit;
152 	}
153 	printf("Done\n");
154 
155 	/* compare the expected WFCS and the captured one */
156 	exp_wfcs = readl(AST_PECI_EXP_FCS) & 0xFF;
157 	rec_wfcs = readl(AST_PECI_CAP_FCS) & 0xFF;
158 	if (exp_wfcs != rec_wfcs)
159 		printf("Mismatched WFCS: %02x, expected %02x\n", rec_wfcs, exp_wfcs);
160 	else
161 		printf("Ping: ACK\n");
162 
163 ping_clean_and_exit:
164 	writel(0x1f, AST_PECI_INT_STAT);
165 	writel(0x0, AST_PECI_CMD);
166 
167 	return 0;
168 }
169 
170 static int do_ast_peci_getdib(unsigned long client_addr)
171 {
172 	unsigned char dib[8];
173 
174 	unsigned long val;
175 	unsigned long retry = 10;
176 
177 	unsigned int rec_wfcs;
178 	unsigned int exp_wfcs;
179 
180 	ast_peci_init();
181 
182 	memset(dib, 0, sizeof(dib));
183 
184 	/* make PECI no operation */
185 	writel(0x0, AST_PECI_CMD);
186 
187 	/* prepare GetDIB command code 0xF7 */
188 	writel(0xf7, AST_PECI_WR_DATA0);
189 	writel(0x00, AST_PECI_WR_DATA1);
190 	writel(0x00, AST_PECI_WR_DATA2);
191 	writel(0x00, AST_PECI_WR_DATA3);
192 	writel(0x00, AST_PECI_WR_DATA4);
193 	writel(0x00, AST_PECI_WR_DATA5);
194 	writel(0x00, AST_PECI_WR_DATA6);
195 	writel(0x00, AST_PECI_WR_DATA7);
196 
197 	/*
198 	 * 1. set read length to 8 bytes
199 	 * 2. set write length to 1 bytes
200 	 * 3. set client address
201 	 */
202 	writel((0x80100 | (client_addr & 0xff)), AST_PECI_RW_LEN);
203 
204 	/* clear interrupt status */
205 	writel(0x1f, AST_PECI_INT_STAT);
206 
207 	/* fire PECI command */
208 	writel(0x1, AST_PECI_CMD);
209 
210 	/* wait PECI done for 10 seconds */
211 	printf("Waiting PECI ... ");
212 	while (retry) {
213 		val = readl(AST_PECI_INT_STAT);
214 		if (val & 0x1)
215 			break;
216 		printf("Retry ... ");
217 		udelay(1000000);
218 		--retry;
219 	}
220 
221 	if (retry == 0) {
222 		printf("Timeout\n");
223 		goto getdib_clean_and_exit;
224 	}
225 	printf("Done\n");
226 
227 	/* compare the expected WFCS and the captured one */
228 	exp_wfcs = readl(AST_PECI_EXP_FCS) & 0xFF;
229 	rec_wfcs = readl(AST_PECI_CAP_FCS) & 0xFF;
230 	if (exp_wfcs != rec_wfcs) {
231 		printf("Mismatched WFCS: %02x, expected %02x\n",
232 			   rec_wfcs, exp_wfcs);
233 		goto getdib_clean_and_exit;
234 	}
235 
236 	*((unsigned int*)dib) = readl(AST_PECI_RD_DATA0);
237 	*((unsigned int*)(dib + 4)) = readl(AST_PECI_RD_DATA1);
238 
239 	printf("DIB: %02x %02x %02x %02x %02x %02x %02x %02x\n",
240 		   dib[0], dib[1], dib[2], dib[3],
241 		   dib[4], dib[5], dib[6], dib[7]);
242 
243 getdib_clean_and_exit:
244 	writel(0x1f, AST_PECI_INT_STAT);
245 	writel(0x0, AST_PECI_CMD);
246 
247 	return 0;
248 }
249 
250 static int do_ast_peci(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
251 {
252 	char *peci_cmd;
253 	unsigned long client_addr;
254 
255 	if (argc < 3)
256 		return CMD_RET_USAGE;
257 
258 	peci_cmd = argv[1];
259 	client_addr = strtoul(argv[2], 0, 0);
260 
261 	if (client_addr > 0xFF) {
262 		printf("Invalid client address: %lu\n", client_addr);
263 		return CMD_RET_USAGE;
264 	}
265 
266 	if (!strcmp(peci_cmd, "ping"))
267 		return do_ast_peci_ping(client_addr);
268 
269 	if (!strcmp(peci_cmd, "getdib"))
270 		return do_ast_peci_getdib(client_addr);
271 
272 	return CMD_RET_USAGE;
273 }
274 
275 U_BOOT_CMD(peci, 3, 0, do_ast_peci,
276 		   "ASPEED PECI general bus command test program",
277 		   "ping <client_addr> - Ping to check if the device at the targeted address can respond\n"
278 		   "peci getdib <client_addr> - Get 8-byte Device Information Bytes\n"
279 		   );
280