README.md
Rendering markdown...
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2018,2019 IBM Corp.
#include "array.h"
#include "log.h"
#include "rev.h"
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <stdint.h>
struct bmc_silicon_rev {
uint32_t rev;
const char *name;
};
static const struct bmc_silicon_rev bmc_silicon_revs[] = {
{ 0x02000303, "AST2400 A0" },
{ 0x02010303, "AST2400 A1" },
{ 0x04000303, "AST2500 A0" },
{ 0x04010303, "AST2500 A1" },
{ 0x04030303, "AST2500 A2" },
{ 0x05000303, "AST2600 A0" },
{ 0x05010303, "AST2600 A1" },
{ 0x05020303, "AST2600 A2" },
};
int64_t rev_probe(struct ahb *ahb)
{
uint32_t probe[2], rev;
bool is_g6;
int rc;
int i;
logd("Probing for SoC revision registers\n");
/*
* The layout of the AST2600 SCU is drastically different from the 2400 and
* 2500 to the point that the silicon revision registers have moved. We
* need to do some fingerprinting to work around it.
*
* That said, 0x1e6e2000 is the SCU on all of the 2400, 2500 and 2600.
*/
#define AST_SCU 0x1e6e2000
/*
* SCU004 is:
*
* - AST2400: System Reset Control Register
* - AST2500: System Reset Control Register
* - AST2600: Silicon Revision ID Register
*
* With the following properties:
*
* - AST2400:
* [31:28]: Reserved, 0b1111
* [27:26]: Reserved, 0b11
*
* - AST2500:
* [31:26]: Reserved, 0b111111
*
* - AST2600:
* [31:24]: Reserved, 0x05
*
* The AST2600 reserved value of 0x05 = 0b00000101. Given Aspeed have used
* 0x05 for the AST2600 we can assume they're not using bit positions to
* indicate the SoC generation. This suggests it should be safe for a while
* to use the top nibble to sense whether we're looking at the Silicon
* Revision ID Register of the 2600 or the System Reset Control Register of
* the 2400 and 2500.
*/
rc = ahb_readl(ahb, AST_SCU | 0x004, &probe[0]);
if (rc < 0) { return rc; }
logt("0x%08" PRIx32 ": 0x%08" PRIx32 "\n", AST_SCU | 0x004, probe[0]);
/*
* SCU07C is:
*
* - AST2400: Silicon Revision ID Register
* - AST2500: Silicon Revision ID Register
* - AST2600: System Reset Event Log Register Set 2-3
*
* With the following properties:
*
* - AST2400:
* [31:24]: Reserved, 0x02
*
* - AST2500:
* [31:24]: Reserved, 0x04
*
* - AST2600:
* [31:16]: Reserved, 0x0000
*
* The AST2600 reserved value of 0x0000 allows us to infer that any set
* bits in the top byte indicate that we are _not_ looking at a 2600 SoC.
*/
rc = ahb_readl(ahb, AST_SCU | 0x07c, &probe[1]);
if (rc < 0) { return rc; }
logt("0x%08" PRIx32 ": 0x%08" PRIx32 "\n", AST_SCU | 0x07c, probe[1]);
is_g6 = !(((probe[0] >> 28) & 0xf) && ((probe[1] >> 24) & 0xff));
/* Based on the above observations, extract the true silicon revision ID */
if (is_g6) {
/*
* AST2600 A2+ doesn't reflect the stepping in SCU004... that's only
* indicated in SCU014. But we can't just use 014 across the board
* because it can't be used to distinguish older chips
* (AST2400/AST2500) as easily as SCU004. So use it once we know it's
* the AST2600.
*/
rc = ahb_readl(ahb, AST_SCU | 0x014, &rev);
if (rc < 0) { return rc; }
logt("0x%08" PRIx32 ": 0x%08" PRIx32 "\n", AST_SCU | 0x014, rev);
} else {
rev = probe[1];
}
#undef AST_SCU
logd("Found revision 0x%x\n", rev);
/* Is it a supported revision? */
for (i = 0; i < ARRAY_SIZE(bmc_silicon_revs); i++) {
if (rev == bmc_silicon_revs[i].rev)
return rev;
}
logd("Revision 0x%x is unsupported\n", rev);
return -ENODEV;
}
bool rev_is_supported(uint32_t rev)
{
int i;
for (i = 0; i < ARRAY_SIZE(bmc_silicon_revs); i++) {
if (rev == bmc_silicon_revs[i].rev)
return true;
}
return false;
}
const char *rev_name(uint32_t rev) {
int i;
for (i = 0; i < ARRAY_SIZE(bmc_silicon_revs); i++) {
if (rev == bmc_silicon_revs[i].rev)
return bmc_silicon_revs[i].name;
}
return NULL;
}
static const uint8_t bmc_silicon_gens[] = {
[ast_g4] = 0x02,
[ast_g5] = 0x04,
[ast_g6] = 0x05,
};
bool rev_is_generation(uint32_t rev, enum ast_generation gen)
{
assert(gen < ARRAY_SIZE(bmc_silicon_gens));
return rev >> 24 == bmc_silicon_gens[gen];
}
int rev_stepping(uint32_t rev)
{
return (rev >> 16) & 0xf;
}