xref: /openbmc/u-boot/cmd/aspeed/peci.c (revision 1029ebb0a1c5890cae634e9ee40ed05bc91f59b3)
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