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