VIA Nano: Add support for VIA Nano CPUs

Add code to do the following for the VIA Nano CPUs
- Update microcode
- Set maximum frequency
- Initialize power states
- Set up cache

Attempting to change the voltage or frequency of the CPU without
applying the microcode update will hang the CPU, so we only do
transitions if we can verify the microcode has been updated.

The microcode is updated directly from CBFS. No microcode is
included in ramstage. The microcode is not included in this
commit.

To get the microcode, run bios_extract on the manufacturer supplied
BIOS, and look for the file marked "P6 Microcode". Include this
file in CBFS.
You can have the build system include this file automatically by
selecting Expert Mode, then look under
'Chipset' -> 'Include CPU microcode in CBFS' ->
Include external microcode file (check)
'Path and filename of CPU microcode' should contain the location of
the microcode file previously extracted.

Change-Id: I586aaca5715e047b42ef901d66772ace0e6b655e
Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
Reviewed-on: http://review.coreboot.org/1257
Tested-by: build bot (Jenkins)
This commit is contained in:
Alexandru Gagniuc
2012-08-07 19:38:32 -05:00
parent 00b579a447
commit e644bada02
7 changed files with 505 additions and 3 deletions

View File

@@ -0,0 +1,150 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "update_ucode.h"
#include <cpu/x86/msr.h>
#include <console/console.h>
#include <stddef.h>
#include <cpu/cpu.h>
#include <arch/cpu.h>
#include <cbfs.h>
static ucode_update_status nano_apply_ucode(const nano_ucode_header *ucode)
{
printk(BIOS_SPEW, "Attempting to apply microcode update\n");
msr_t msr;
/* Address of ucode block goes in msr.lo for 32-bit mode
* Now remember, we need to pass the address of the actual microcode,
* not the header. The header is just there to help us. */
msr.lo = (unsigned int)(&(ucode->ucode_start));
msr.hi = 0;
wrmsr(MSR_IA32_BIOS_UPDT_TRIG, msr);
/* Let's see if we updated succesfully */
msr = rdmsr(MSR_UCODE_UPDATE_STATUS);
return msr.lo & 0x07;
}
static void nano_print_ucode_info(const nano_ucode_header *ucode)
{
printk(BIOS_SPEW, "Microcode update information:\n");
printk(BIOS_SPEW, "Name: %8s\n", ucode->name );
printk(BIOS_SPEW, "Date: %u/%u/%u\n", ucode->month,
ucode->day, ucode->year );
}
static ucode_validity nano_ucode_is_valid(const nano_ucode_header *ucode)
{
/* We must have a valid signature */
if(ucode->signature != NANO_UCODE_SIGNATURE)
return NANO_UCODE_SIGNATURE_ERROR;
/* The size of the head must be exactly 12 double words */
if( (ucode->total_size - ucode->payload_size) != NANO_UCODE_HEADER_SIZE)
return NANO_UCODE_WRONG_SIZE;
/* How about a checksum ? Checksum must be 0
* Two's complement done over the entire file, including the header */
int i;
u32 check = 0;
u32 *raw = (void*) ucode;
for(i = 0 ; i < ((ucode->total_size) >> 2); i++) {
check += raw[i];
}
if(check != 0)
return NANO_UCODE_CHECKSUM_FAIL;
/* Made it here huh? Then it looks valid to us.
* If there's anything else wrong, the CPU will reject the update */
return NANO_UCODE_VALID;
}
static void nano_print_ucode_status(ucode_update_status stat)
{
switch(stat)
{
case UCODE_UPDATE_SUCCESS:
printk(BIOS_INFO, "Microcode update succesful.\n");
break;
case UCODE_UPDATE_FAIL:
printk(BIOS_ALERT, "Microcode update failed, bad environment."
"Update was not applied.\n");
break;
case UCODE_UPDATE_WRONG_CPU:
printk(BIOS_ALERT, "Update not applicable to this CPU.\n");
break;
case UCODE_INVALID_UPDATE_BLOCK:
printk(BIOS_ALERT, "Microcode block invalid."
"Update was not applied.\n");
break;
default:
printk(BIOS_ALERT, "Unknown status. No update applied.\n");
}
}
unsigned int nano_update_ucode(void)
{
size_t i;
unsigned int n_updates = 0;
const struct cbfs_file *cbfs_ucode;
u32 fms = cpuid_eax(0x1);
cbfs_ucode = cbfs_find("cpu_microcode_blob.bin");
/* Oops, did you forget to include the microcode ? */
if(cbfs_ucode == NULL) {
printk(BIOS_ALERT, "WARNING: No microcode file found in CBFS. "
"Aborting microcode updates\n");
return 0;
}
/* Considering we are running with eXecute-In-Place (XIP), there's no
* need to worry that accessing data from ROM will slow us down.
* Microcode data should be aligned to a 4-byte boundary, but CBFS
* already does that for us (Do you, CBFS?) */
const u32 *ucode_data = CBFS_SUBHEADER(cbfs_ucode);
const u32 ucode_len = ntohl(cbfs_ucode->len);
/* We might do a lot of loops searching for the microcode updates, but
* keep in mind, nano_ucode_is_valid searches for the signature before
* doing anything else. */
for( i = 0; i < (ucode_len >> 2); /* don't increment i here */ )
{
ucode_update_status stat;
const nano_ucode_header * ucode = (void *)(&ucode_data[i]);
if(nano_ucode_is_valid(ucode) != NANO_UCODE_VALID) {
i++;
continue;
}
/* Since we have a valid microcode, there's no need to search
* in this region, so we restart our search at the end of this
* microcode */
i += (ucode->total_size >> 2);
/* Is the microcode compatible with our CPU? */
if(ucode->applicable_fms != fms) continue;
/* For our most curious users */
nano_print_ucode_info(ucode);
/* The meat of the pie */
stat = nano_apply_ucode(ucode);
/* The user might want to know how the update went */
nano_print_ucode_status(stat);
if(stat == UCODE_UPDATE_SUCCESS) n_updates++;
}
return n_updates;
}