15c8f9400Sryan_chen #include <common.h>
25c8f9400Sryan_chen #include <command.h>
35c8f9400Sryan_chen #include <string.h>
45c8f9400Sryan_chen #include <asm/io.h>
55c8f9400Sryan_chen
65c8f9400Sryan_chen #define AST_SCU (0x1e6e2000)
75c8f9400Sryan_chen #if defined(CONFIG_ASPEED_AST2500)
85c8f9400Sryan_chen #define AST_SCU_SYSRST_CTRL (AST_SCU + 0x04)
95c8f9400Sryan_chen #elif defined(CONFIG_ASPEED_AST2600)
105c8f9400Sryan_chen #define AST_SCU_SYSRST_CLR2 (AST_SCU + 0x54)
115c8f9400Sryan_chen #endif
125c8f9400Sryan_chen
135c8f9400Sryan_chen #define AST_PECI (0x1e78b000)
145c8f9400Sryan_chen #define AST_PECI_CTRL (AST_PECI + 0x00)
155c8f9400Sryan_chen #define AST_PECI_TIMING (AST_PECI + 0x04)
165c8f9400Sryan_chen #define AST_PECI_CMD (AST_PECI + 0x08)
175c8f9400Sryan_chen #define AST_PECI_RW_LEN (AST_PECI + 0x0C)
185c8f9400Sryan_chen #define AST_PECI_EXP_FCS (AST_PECI + 0x10)
195c8f9400Sryan_chen #define AST_PECI_CAP_FCS (AST_PECI + 0x14)
205c8f9400Sryan_chen #define AST_PECI_INT_CTRL (AST_PECI + 0x18)
215c8f9400Sryan_chen #define AST_PECI_INT_STAT (AST_PECI + 0x1C)
225c8f9400Sryan_chen #define AST_PECI_WR_DATA0 (AST_PECI + 0x20)
235c8f9400Sryan_chen #define AST_PECI_WR_DATA1 (AST_PECI + 0x24)
245c8f9400Sryan_chen #define AST_PECI_WR_DATA2 (AST_PECI + 0x28)
255c8f9400Sryan_chen #define AST_PECI_WR_DATA3 (AST_PECI + 0x2C)
265c8f9400Sryan_chen #define AST_PECI_RD_DATA0 (AST_PECI + 0x30)
275c8f9400Sryan_chen #define AST_PECI_RD_DATA1 (AST_PECI + 0x34)
285c8f9400Sryan_chen #define AST_PECI_RD_DATA2 (AST_PECI + 0x38)
295c8f9400Sryan_chen #define AST_PECI_RD_DATA3 (AST_PECI + 0x3C)
305c8f9400Sryan_chen #define AST_PECI_WR_DATA4 (AST_PECI + 0x40)
315c8f9400Sryan_chen #define AST_PECI_WR_DATA5 (AST_PECI + 0x44)
325c8f9400Sryan_chen #define AST_PECI_WR_DATA6 (AST_PECI + 0x48)
335c8f9400Sryan_chen #define AST_PECI_WR_DATA7 (AST_PECI + 0x4C)
345c8f9400Sryan_chen #define AST_PECI_RD_DATA4 (AST_PECI + 0x50)
355c8f9400Sryan_chen #define AST_PECI_RD_DATA5 (AST_PECI + 0x54)
365c8f9400Sryan_chen #define AST_PECI_RD_DATA6 (AST_PECI + 0x58)
375c8f9400Sryan_chen #define AST_PECI_RD_DATA7 (AST_PECI + 0x5C)
385c8f9400Sryan_chen
395c8f9400Sryan_chen #ifdef CONFIG_ASPEED_AST2500
ast2500_peci_init(void)405c8f9400Sryan_chen static void ast2500_peci_init(void)
415c8f9400Sryan_chen {
425c8f9400Sryan_chen unsigned int val;
435c8f9400Sryan_chen static bool is_init = false;
445c8f9400Sryan_chen
455c8f9400Sryan_chen /* init once only */
465c8f9400Sryan_chen if (is_init)
475c8f9400Sryan_chen return;
485c8f9400Sryan_chen
495c8f9400Sryan_chen /* release PECI reset */
505c8f9400Sryan_chen val = readl(AST_SCU_SYSRST_CTRL);
515c8f9400Sryan_chen val &= ~(0x1 << 10);
525c8f9400Sryan_chen writel(val, AST_SCU_SYSRST_CTRL);
535c8f9400Sryan_chen
545c8f9400Sryan_chen /*
555c8f9400Sryan_chen * 1. disable PECI
565c8f9400Sryan_chen * 2. set source clock to 24Mhz oscillator
575c8f9400Sryan_chen * 3. set clock divider to 8
585c8f9400Sryan_chen */
595c8f9400Sryan_chen writel(0x80301, AST_PECI_CTRL);
605c8f9400Sryan_chen
615c8f9400Sryan_chen /* set negotiate timing */
625c8f9400Sryan_chen writel(0x4040, AST_PECI_TIMING);
635c8f9400Sryan_chen
645c8f9400Sryan_chen /* enable interrupt */
655c8f9400Sryan_chen writel(0x1f, AST_PECI_INT_CTRL);
665c8f9400Sryan_chen
675c8f9400Sryan_chen /* enable PECI */
685c8f9400Sryan_chen writel(0x80311, AST_PECI_CTRL);
695c8f9400Sryan_chen
705c8f9400Sryan_chen is_init = true;
715c8f9400Sryan_chen }
725c8f9400Sryan_chen #endif
735c8f9400Sryan_chen
745c8f9400Sryan_chen #ifdef CONFIG_ASPEED_AST2600
ast2600_peci_init(void)755c8f9400Sryan_chen static void ast2600_peci_init(void)
765c8f9400Sryan_chen {
775c8f9400Sryan_chen static bool is_init = false;
785c8f9400Sryan_chen
795c8f9400Sryan_chen /* init once only */
805c8f9400Sryan_chen if (is_init)
815c8f9400Sryan_chen return;
825c8f9400Sryan_chen
835c8f9400Sryan_chen /* release PECI reset */
845c8f9400Sryan_chen writel(0x10, AST_SCU_SYSRST_CLR2);
855c8f9400Sryan_chen
865c8f9400Sryan_chen /*
875c8f9400Sryan_chen * 1. disable PECI
885c8f9400Sryan_chen * 2. set source clock to HCLK
895c8f9400Sryan_chen * 3. set clock divider to 2
905c8f9400Sryan_chen * 4. set 32-byte mode
915c8f9400Sryan_chen */
925c8f9400Sryan_chen writel(0x80901, AST_PECI_CTRL);
935c8f9400Sryan_chen
945c8f9400Sryan_chen /* set negotiate timing */
955c8f9400Sryan_chen writel(0x0303, AST_PECI_TIMING);
965c8f9400Sryan_chen
975c8f9400Sryan_chen /* enable interrupt */
985c8f9400Sryan_chen writel(0x1f, AST_PECI_INT_CTRL);
995c8f9400Sryan_chen
1005c8f9400Sryan_chen /* enable PECI */
1015c8f9400Sryan_chen writel(0x80911, AST_PECI_CTRL);
1025c8f9400Sryan_chen
1035c8f9400Sryan_chen is_init = true;
1045c8f9400Sryan_chen }
1055c8f9400Sryan_chen #endif
1065c8f9400Sryan_chen
ast_peci_init(void)1075c8f9400Sryan_chen static void ast_peci_init(void)
1085c8f9400Sryan_chen {
1095c8f9400Sryan_chen #if defined(CONFIG_ASPEED_AST2500)
1105c8f9400Sryan_chen return ast2500_peci_init();
1115c8f9400Sryan_chen #elif defined(CONFIG_ASPEED_AST2600)
1125c8f9400Sryan_chen return ast2600_peci_init();
1135c8f9400Sryan_chen #endif
1145c8f9400Sryan_chen }
1155c8f9400Sryan_chen
do_ast_peci_ping(unsigned long client_addr)1165c8f9400Sryan_chen static int do_ast_peci_ping(unsigned long client_addr)
1175c8f9400Sryan_chen {
1185c8f9400Sryan_chen unsigned int rec_wfcs;
1195c8f9400Sryan_chen unsigned int exp_wfcs;
1205c8f9400Sryan_chen
1215c8f9400Sryan_chen unsigned long val;
1225c8f9400Sryan_chen unsigned long retry = 10;
1235c8f9400Sryan_chen
1245c8f9400Sryan_chen ast_peci_init();
1255c8f9400Sryan_chen
1265c8f9400Sryan_chen /* make PECI no operation */
1275c8f9400Sryan_chen writel(0x0, AST_PECI_CMD);
1285c8f9400Sryan_chen
1295c8f9400Sryan_chen /* set client address */
1305c8f9400Sryan_chen writel((client_addr & 0xff), AST_PECI_RW_LEN);
1315c8f9400Sryan_chen
1325c8f9400Sryan_chen /* clear interrupt status */
1335c8f9400Sryan_chen writel(0x1f, AST_PECI_INT_STAT);
1345c8f9400Sryan_chen
1355c8f9400Sryan_chen /* fire PECI command */
1365c8f9400Sryan_chen writel(0x1, AST_PECI_CMD);
1375c8f9400Sryan_chen
1385c8f9400Sryan_chen /* wait PECI done for 10 seconds */
1395c8f9400Sryan_chen printf("Waiting PECI ... ");
1405c8f9400Sryan_chen while (retry) {
1415c8f9400Sryan_chen val = readl(AST_PECI_INT_STAT);
1425c8f9400Sryan_chen if (val & 0x1)
1435c8f9400Sryan_chen break;
1445c8f9400Sryan_chen printf("Retry ... ");
1455c8f9400Sryan_chen udelay(1000000);
1465c8f9400Sryan_chen --retry;
1475c8f9400Sryan_chen }
1485c8f9400Sryan_chen
1495c8f9400Sryan_chen if (retry == 0) {
1505c8f9400Sryan_chen printf("Timeout\n");
1515c8f9400Sryan_chen goto ping_clean_and_exit;
1525c8f9400Sryan_chen }
1535c8f9400Sryan_chen printf("Done\n");
1545c8f9400Sryan_chen
1555c8f9400Sryan_chen /* compare the expected WFCS and the captured one */
1565c8f9400Sryan_chen exp_wfcs = readl(AST_PECI_EXP_FCS) & 0xFF;
1575c8f9400Sryan_chen rec_wfcs = readl(AST_PECI_CAP_FCS) & 0xFF;
1585c8f9400Sryan_chen if (exp_wfcs != rec_wfcs)
1595c8f9400Sryan_chen printf("Mismatched WFCS: %02x, expected %02x\n", rec_wfcs, exp_wfcs);
1605c8f9400Sryan_chen else
1615c8f9400Sryan_chen printf("Ping: ACK\n");
1625c8f9400Sryan_chen
1635c8f9400Sryan_chen ping_clean_and_exit:
1645c8f9400Sryan_chen writel(0x1f, AST_PECI_INT_STAT);
1655c8f9400Sryan_chen writel(0x0, AST_PECI_CMD);
1665c8f9400Sryan_chen
1675c8f9400Sryan_chen return 0;
1685c8f9400Sryan_chen }
1695c8f9400Sryan_chen
do_ast_peci_getdib(unsigned long client_addr)1705c8f9400Sryan_chen static int do_ast_peci_getdib(unsigned long client_addr)
1715c8f9400Sryan_chen {
1725c8f9400Sryan_chen unsigned char dib[8];
1735c8f9400Sryan_chen
1745c8f9400Sryan_chen unsigned long val;
1755c8f9400Sryan_chen unsigned long retry = 10;
1765c8f9400Sryan_chen
1775c8f9400Sryan_chen unsigned int rec_wfcs;
1785c8f9400Sryan_chen unsigned int exp_wfcs;
1795c8f9400Sryan_chen
180*1c855b30SBilly Tsai unsigned int rec_rfcs;
181*1c855b30SBilly Tsai unsigned int exp_rfcs;
182*1c855b30SBilly Tsai
1835c8f9400Sryan_chen ast_peci_init();
1845c8f9400Sryan_chen
1855c8f9400Sryan_chen memset(dib, 0, sizeof(dib));
1865c8f9400Sryan_chen
1875c8f9400Sryan_chen /* make PECI no operation */
1885c8f9400Sryan_chen writel(0x0, AST_PECI_CMD);
1895c8f9400Sryan_chen
1905c8f9400Sryan_chen /* prepare GetDIB command code 0xF7 */
1915c8f9400Sryan_chen writel(0xf7, AST_PECI_WR_DATA0);
1925c8f9400Sryan_chen writel(0x00, AST_PECI_WR_DATA1);
1935c8f9400Sryan_chen writel(0x00, AST_PECI_WR_DATA2);
1945c8f9400Sryan_chen writel(0x00, AST_PECI_WR_DATA3);
1955c8f9400Sryan_chen writel(0x00, AST_PECI_WR_DATA4);
1965c8f9400Sryan_chen writel(0x00, AST_PECI_WR_DATA5);
1975c8f9400Sryan_chen writel(0x00, AST_PECI_WR_DATA6);
1985c8f9400Sryan_chen writel(0x00, AST_PECI_WR_DATA7);
1995c8f9400Sryan_chen
2005c8f9400Sryan_chen /*
2015c8f9400Sryan_chen * 1. set read length to 8 bytes
2025c8f9400Sryan_chen * 2. set write length to 1 bytes
2035c8f9400Sryan_chen * 3. set client address
2045c8f9400Sryan_chen */
2055c8f9400Sryan_chen writel((0x80100 | (client_addr & 0xff)), AST_PECI_RW_LEN);
2065c8f9400Sryan_chen
2075c8f9400Sryan_chen /* clear interrupt status */
2085c8f9400Sryan_chen writel(0x1f, AST_PECI_INT_STAT);
2095c8f9400Sryan_chen
2105c8f9400Sryan_chen /* fire PECI command */
2115c8f9400Sryan_chen writel(0x1, AST_PECI_CMD);
2125c8f9400Sryan_chen
2135c8f9400Sryan_chen /* wait PECI done for 10 seconds */
2145c8f9400Sryan_chen printf("Waiting PECI ... ");
2155c8f9400Sryan_chen while (retry) {
2165c8f9400Sryan_chen val = readl(AST_PECI_INT_STAT);
2175c8f9400Sryan_chen if (val & 0x1)
2185c8f9400Sryan_chen break;
2195c8f9400Sryan_chen printf("Retry ... ");
2205c8f9400Sryan_chen udelay(1000000);
2215c8f9400Sryan_chen --retry;
2225c8f9400Sryan_chen }
2235c8f9400Sryan_chen
2245c8f9400Sryan_chen if (retry == 0) {
2255c8f9400Sryan_chen printf("Timeout\n");
2265c8f9400Sryan_chen goto getdib_clean_and_exit;
2275c8f9400Sryan_chen }
2285c8f9400Sryan_chen printf("Done\n");
2295c8f9400Sryan_chen
2305c8f9400Sryan_chen /* compare the expected WFCS and the captured one */
2315c8f9400Sryan_chen exp_wfcs = readl(AST_PECI_EXP_FCS) & 0xFF;
2325c8f9400Sryan_chen rec_wfcs = readl(AST_PECI_CAP_FCS) & 0xFF;
2335c8f9400Sryan_chen if (exp_wfcs != rec_wfcs) {
2345c8f9400Sryan_chen printf("Mismatched WFCS: %02x, expected %02x\n",
2355c8f9400Sryan_chen rec_wfcs, exp_wfcs);
2365c8f9400Sryan_chen goto getdib_clean_and_exit;
2375c8f9400Sryan_chen }
2385c8f9400Sryan_chen
239*1c855b30SBilly Tsai /* compare the expected RFCS and the captured one */
240*1c855b30SBilly Tsai exp_rfcs = readl(AST_PECI_EXP_FCS) & 0xFF0000;
241*1c855b30SBilly Tsai rec_rfcs = readl(AST_PECI_CAP_FCS) & 0xFF0000;
242*1c855b30SBilly Tsai if (exp_rfcs != rec_rfcs) {
243*1c855b30SBilly Tsai printf("Mismatched RFCS: %02x, expected %02x\n",
244*1c855b30SBilly Tsai rec_rfcs, exp_rfcs);
245*1c855b30SBilly Tsai goto getdib_clean_and_exit;
246*1c855b30SBilly Tsai }
247*1c855b30SBilly Tsai
2485c8f9400Sryan_chen *((unsigned int*)dib) = readl(AST_PECI_RD_DATA0);
2495c8f9400Sryan_chen *((unsigned int*)(dib + 4)) = readl(AST_PECI_RD_DATA1);
2505c8f9400Sryan_chen
2515c8f9400Sryan_chen printf("DIB: %02x %02x %02x %02x %02x %02x %02x %02x\n",
2525c8f9400Sryan_chen dib[0], dib[1], dib[2], dib[3],
2535c8f9400Sryan_chen dib[4], dib[5], dib[6], dib[7]);
2545c8f9400Sryan_chen
2555c8f9400Sryan_chen getdib_clean_and_exit:
2565c8f9400Sryan_chen writel(0x1f, AST_PECI_INT_STAT);
2575c8f9400Sryan_chen writel(0x0, AST_PECI_CMD);
2585c8f9400Sryan_chen
2595c8f9400Sryan_chen return 0;
2605c8f9400Sryan_chen }
2615c8f9400Sryan_chen
do_ast_peci(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])2625c8f9400Sryan_chen static int do_ast_peci(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
2635c8f9400Sryan_chen {
2645c8f9400Sryan_chen char *peci_cmd;
2655c8f9400Sryan_chen unsigned long client_addr;
2665c8f9400Sryan_chen
2675c8f9400Sryan_chen if (argc < 3)
2685c8f9400Sryan_chen return CMD_RET_USAGE;
2695c8f9400Sryan_chen
2705c8f9400Sryan_chen peci_cmd = argv[1];
2715c8f9400Sryan_chen client_addr = strtoul(argv[2], 0, 0);
2725c8f9400Sryan_chen
2735c8f9400Sryan_chen if (client_addr > 0xFF) {
2745c8f9400Sryan_chen printf("Invalid client address: %lu\n", client_addr);
2755c8f9400Sryan_chen return CMD_RET_USAGE;
2765c8f9400Sryan_chen }
2775c8f9400Sryan_chen
2785c8f9400Sryan_chen if (!strcmp(peci_cmd, "ping"))
2795c8f9400Sryan_chen return do_ast_peci_ping(client_addr);
2805c8f9400Sryan_chen
2815c8f9400Sryan_chen if (!strcmp(peci_cmd, "getdib"))
2825c8f9400Sryan_chen return do_ast_peci_getdib(client_addr);
2835c8f9400Sryan_chen
2845c8f9400Sryan_chen return CMD_RET_USAGE;
2855c8f9400Sryan_chen }
2865c8f9400Sryan_chen
2875c8f9400Sryan_chen U_BOOT_CMD(peci, 3, 0, do_ast_peci,
2885c8f9400Sryan_chen "ASPEED PECI general bus command test program",
2895c8f9400Sryan_chen "ping <client_addr> - Ping to check if the device at the targeted address can respond\n"
2905c8f9400Sryan_chen "peci getdib <client_addr> - Get 8-byte Device Information Bytes\n"
2915c8f9400Sryan_chen );
292