af05c86dcb
Change-Id: I71704ab292edf8bd343370e6b72c47a8f3aceffd Signed-off-by: Felix Held <felix-coreboot@felixheld.de> Reviewed-on: https://review.coreboot.org/c/coreboot/+/42838 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Raul Rangel <rrangel@chromium.org> Reviewed-by: Angel Pons <th3fanbus@gmail.com>
218 lines
4.7 KiB
C
218 lines
4.7 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
|
|
#include <arch/cpu.h>
|
|
#include <console/console.h>
|
|
#include <FspGuids.h>
|
|
#include <fsp/util.h>
|
|
#include <misc_data.h>
|
|
#include <soc/cpu.h>
|
|
#include <soc/soc_util.h>
|
|
#include <types.h>
|
|
|
|
/*
|
|
* The Zen/Zen+ based APUs can be RV (sometimes called RV1), PCO or RV2 silicon. RV2 has less
|
|
* PCIe, USB3 and DisplayPort connectivity than RV(1) or PCO. A Picasso SoC is always PCO
|
|
* silicon, a Dali SoC can either be RV2 or fused-down PCO silicon that has the same
|
|
* connectivity as the RV2 one and Pollock is always RV2 silicon. Picasso and Dali are in a FP5
|
|
* package while Pollock is in the smaller FT5 package.
|
|
*/
|
|
|
|
#define SOCKET_TYPE_SHIFT 28
|
|
#define SOCKET_TYPSE_MASK (0xf << SOCKET_TYPE_SHIFT)
|
|
|
|
/* some Pollock engineering samples return the wrong socket type */
|
|
enum socket_type get_socket_type(void)
|
|
{
|
|
uint32_t ebx = cpuid_ebx(0x80000001);
|
|
ebx = (ebx & SOCKET_TYPSE_MASK) >> SOCKET_TYPE_SHIFT;
|
|
return (enum socket_type)ebx;
|
|
}
|
|
|
|
void print_socket_type(void)
|
|
{
|
|
enum socket_type socket = get_socket_type();
|
|
|
|
printk(BIOS_INFO, "Socket type: ");
|
|
|
|
switch (socket) {
|
|
case SOCKET_FP5:
|
|
printk(BIOS_INFO, "FP5\n");
|
|
break;
|
|
case SOCKET_AM4:
|
|
printk(BIOS_INFO, "AM4\n");
|
|
break;
|
|
case SOCKET_FT5:
|
|
printk(BIOS_INFO, "FT5\n");
|
|
break;
|
|
default:
|
|
printk(BIOS_INFO, "unknown\n");
|
|
}
|
|
}
|
|
|
|
/* returns 0 in case or errors */
|
|
static uint32_t get_internal_silicon_type(void)
|
|
{
|
|
static uint32_t silicon_type;
|
|
size_t hob_size = 0;
|
|
const struct picasso_misc_data *hob;
|
|
|
|
if (silicon_type)
|
|
return silicon_type;
|
|
|
|
hob = fsp_find_extension_hob_by_guid(PICASSO_MISC_DATA_HOB_GUID.b, &hob_size);
|
|
|
|
if (hob == NULL || hob_size == 0) {
|
|
printk(BIOS_ERR, "Couldn't find Picasso misc data HOB.\n");
|
|
return 0;
|
|
}
|
|
|
|
if (hob->version != PICASSO_MISC_DATA_VERSION) {
|
|
printk(BIOS_ERR, "Unexpected Picasso misc data HOB version.\n");
|
|
return 0;
|
|
}
|
|
|
|
silicon_type = hob->silicon_id;
|
|
|
|
printk(BIOS_DEBUG, "Silicon ID = 0x%x\n", silicon_type);
|
|
|
|
return silicon_type;
|
|
}
|
|
|
|
#define SILICON_IS_MYSTERY_MEAT (1 << 31)
|
|
#define SILICON_IS_RV2 (1 << 30)
|
|
|
|
static bool is_rv2_silicon(void)
|
|
{
|
|
return get_internal_silicon_type() & SILICON_IS_RV2;
|
|
}
|
|
|
|
static bool is_mystery_silicon(void)
|
|
{
|
|
return get_internal_silicon_type() & SILICON_IS_MYSTERY_MEAT;
|
|
}
|
|
|
|
static bool is_fam17_1x(void)
|
|
{
|
|
/* mask lower model number nibble and stepping */
|
|
return cpuid_eax(1) >> 8 == PICASSO_B1_CPUID >> 8;
|
|
}
|
|
|
|
static bool is_fam17_11(void)
|
|
{
|
|
/* only mask stepping */
|
|
return cpuid_eax(1) >> 4 == RAVEN1_B0_CPUID >> 4;
|
|
}
|
|
|
|
static bool is_fam17_18(void)
|
|
{
|
|
/* only mask stepping */
|
|
return cpuid_eax(1) >> 4 == PICASSO_B1_CPUID >> 4;
|
|
}
|
|
|
|
static bool is_fam17_2x(void)
|
|
{
|
|
/* mask lower model number nibble and stepping */
|
|
return cpuid_eax(1) >> 8 == RAVEN2_A1_CPUID >> 8;
|
|
}
|
|
|
|
static bool is_fam17_20(void)
|
|
{
|
|
/* only mask stepping */
|
|
return cpuid_eax(1) >> 4 == RAVEN2_A1_CPUID >> 4;
|
|
}
|
|
|
|
enum silicon_type get_silicon_type(void)
|
|
{
|
|
/*
|
|
* RV2 is fam17_20, but might return a fam17_1x CPUID in the is_mystery_silicon() case.
|
|
* is_rv2_silicon() has the correct information, but requires the HOB to be present.
|
|
*/
|
|
if (is_fam17_20() || is_rv2_silicon())
|
|
return SILICON_RV2;
|
|
|
|
if (is_fam17_18() && !is_rv2_silicon())
|
|
return SILICON_PCO;
|
|
|
|
if (is_fam17_11() && !is_rv2_silicon())
|
|
return SILICON_RV1;
|
|
|
|
/* some cases might still be missing */
|
|
|
|
return SILICON_UNKNOWN;
|
|
}
|
|
|
|
/* some Pollock engineering samples return the wrong socket type and get detected as Dali */
|
|
enum soc_type get_soc_type(void)
|
|
{
|
|
switch (get_socket_type()) {
|
|
case SOCKET_FP5:
|
|
if (is_fam17_1x() && !is_mystery_silicon())
|
|
return SOC_PICASSO;
|
|
|
|
if (is_fam17_2x() || (is_fam17_1x() && is_mystery_silicon()))
|
|
return SOC_DALI;
|
|
|
|
break;
|
|
case SOCKET_FT5:
|
|
/* add is_fam17_20() CPUID sanity check here? */
|
|
return SOC_POLLOCK;
|
|
break;
|
|
case SOCKET_AM4:
|
|
/* AM4 SoC type detection logic not implemented */
|
|
break;
|
|
}
|
|
|
|
return SOC_UNKNOWN;
|
|
}
|
|
|
|
void print_silicon_type(void)
|
|
{
|
|
const enum silicon_type silicon = get_silicon_type();
|
|
|
|
printk(BIOS_INFO, "Silicon type: ");
|
|
|
|
switch (silicon) {
|
|
case SILICON_RV1:
|
|
printk(BIOS_INFO, "RV1\n");
|
|
break;
|
|
case SILICON_PCO:
|
|
printk(BIOS_INFO, "PCO\n");
|
|
break;
|
|
case SILICON_RV2:
|
|
printk(BIOS_INFO, "RV2\n");
|
|
break;
|
|
default:
|
|
printk(BIOS_INFO, "unknown\n");
|
|
}
|
|
}
|
|
|
|
void print_soc_type(void)
|
|
{
|
|
const enum soc_type soc = get_soc_type();
|
|
|
|
printk(BIOS_INFO, "SoC type: ");
|
|
|
|
switch (soc) {
|
|
case SOC_PICASSO:
|
|
printk(BIOS_INFO, "Picasso\n");
|
|
break;
|
|
case SOC_DALI:
|
|
printk(BIOS_INFO, "Dali\n");
|
|
break;
|
|
case SOC_POLLOCK:
|
|
printk(BIOS_INFO, "Pollock\n");
|
|
break;
|
|
default:
|
|
printk(BIOS_INFO, "unknown\n");
|
|
}
|
|
}
|
|
|
|
bool soc_is_reduced_io_sku(void)
|
|
{
|
|
return get_silicon_type() == SILICON_RV2 || get_soc_type() == SOC_DALI;
|
|
}
|
|
|
|
bool soc_is_raven2(void)
|
|
{
|
|
return get_silicon_type() == SILICON_RV2;
|
|
}
|