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
ast2500_peci_init(void)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
ast2600_peci_init(void)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
ast_peci_init(void)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
do_ast_peci_ping(unsigned long client_addr)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
do_ast_peci_getdib(unsigned long client_addr)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 unsigned int rec_rfcs;
181 unsigned int exp_rfcs;
182
183 ast_peci_init();
184
185 memset(dib, 0, sizeof(dib));
186
187 /* make PECI no operation */
188 writel(0x0, AST_PECI_CMD);
189
190 /* prepare GetDIB command code 0xF7 */
191 writel(0xf7, AST_PECI_WR_DATA0);
192 writel(0x00, AST_PECI_WR_DATA1);
193 writel(0x00, AST_PECI_WR_DATA2);
194 writel(0x00, AST_PECI_WR_DATA3);
195 writel(0x00, AST_PECI_WR_DATA4);
196 writel(0x00, AST_PECI_WR_DATA5);
197 writel(0x00, AST_PECI_WR_DATA6);
198 writel(0x00, AST_PECI_WR_DATA7);
199
200 /*
201 * 1. set read length to 8 bytes
202 * 2. set write length to 1 bytes
203 * 3. set client address
204 */
205 writel((0x80100 | (client_addr & 0xff)), AST_PECI_RW_LEN);
206
207 /* clear interrupt status */
208 writel(0x1f, AST_PECI_INT_STAT);
209
210 /* fire PECI command */
211 writel(0x1, AST_PECI_CMD);
212
213 /* wait PECI done for 10 seconds */
214 printf("Waiting PECI ... ");
215 while (retry) {
216 val = readl(AST_PECI_INT_STAT);
217 if (val & 0x1)
218 break;
219 printf("Retry ... ");
220 udelay(1000000);
221 --retry;
222 }
223
224 if (retry == 0) {
225 printf("Timeout\n");
226 goto getdib_clean_and_exit;
227 }
228 printf("Done\n");
229
230 /* compare the expected WFCS and the captured one */
231 exp_wfcs = readl(AST_PECI_EXP_FCS) & 0xFF;
232 rec_wfcs = readl(AST_PECI_CAP_FCS) & 0xFF;
233 if (exp_wfcs != rec_wfcs) {
234 printf("Mismatched WFCS: %02x, expected %02x\n",
235 rec_wfcs, exp_wfcs);
236 goto getdib_clean_and_exit;
237 }
238
239 /* compare the expected RFCS and the captured one */
240 exp_rfcs = readl(AST_PECI_EXP_FCS) & 0xFF0000;
241 rec_rfcs = readl(AST_PECI_CAP_FCS) & 0xFF0000;
242 if (exp_rfcs != rec_rfcs) {
243 printf("Mismatched RFCS: %02x, expected %02x\n",
244 rec_rfcs, exp_rfcs);
245 goto getdib_clean_and_exit;
246 }
247
248 *((unsigned int*)dib) = readl(AST_PECI_RD_DATA0);
249 *((unsigned int*)(dib + 4)) = readl(AST_PECI_RD_DATA1);
250
251 printf("DIB: %02x %02x %02x %02x %02x %02x %02x %02x\n",
252 dib[0], dib[1], dib[2], dib[3],
253 dib[4], dib[5], dib[6], dib[7]);
254
255 getdib_clean_and_exit:
256 writel(0x1f, AST_PECI_INT_STAT);
257 writel(0x0, AST_PECI_CMD);
258
259 return 0;
260 }
261
do_ast_peci(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])262 static int do_ast_peci(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
263 {
264 char *peci_cmd;
265 unsigned long client_addr;
266
267 if (argc < 3)
268 return CMD_RET_USAGE;
269
270 peci_cmd = argv[1];
271 client_addr = strtoul(argv[2], 0, 0);
272
273 if (client_addr > 0xFF) {
274 printf("Invalid client address: %lu\n", client_addr);
275 return CMD_RET_USAGE;
276 }
277
278 if (!strcmp(peci_cmd, "ping"))
279 return do_ast_peci_ping(client_addr);
280
281 if (!strcmp(peci_cmd, "getdib"))
282 return do_ast_peci_getdib(client_addr);
283
284 return CMD_RET_USAGE;
285 }
286
287 U_BOOT_CMD(peci, 3, 0, do_ast_peci,
288 "ASPEED PECI general bus command test program",
289 "ping <client_addr> - Ping to check if the device at the targeted address can respond\n"
290 "peci getdib <client_addr> - Get 8-byte Device Information Bytes\n"
291 );
292