blob: a5da75b74c14f60c9e496f3ac81ce8ad31401bf8 [file] [log] [blame]
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +00001/*
Stefan Reinauer7e61e452008-01-18 10:35:56 +00002 * This file is part of the coreboot project.
Marc Jones2006b382007-12-19 00:47:09 +00003 *
4 * Copyright (C) 2007 Advanced Micro Devices, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
Paul Menzela46a7122013-02-23 18:37:27 +010017 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Marc Jones2006b382007-12-19 00:47:09 +000018 */
19
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000020#include <stdint.h>
21#include <console/console.h>
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000022#include <cpu/x86/msr.h>
23#include <cpu/amd/microcode.h>
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +020024#include <cbfs.h>
25
26#define UCODE_DEBUG(fmt, args...) \
27 do { printk(BIOS_DEBUG, "[microcode] "fmt, ##args); } while(0)
Marc Jones8ae8c882007-12-19 01:32:08 +000028
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000029struct microcode {
Marc Jones2006b382007-12-19 00:47:09 +000030 u32 date_code;
31 u32 patch_id;
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000032
Marc Jones2006b382007-12-19 00:47:09 +000033 u16 m_patch_data_id;
34 u8 m_patch_data_len;
35 u8 init_flag;
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000036
Marc Jones2006b382007-12-19 00:47:09 +000037 u32 m_patch_data_cksum;
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000038
Marc Jones2006b382007-12-19 00:47:09 +000039 u32 nb_dev_id;
40 u32 ht_io_hub_dev_id;
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000041
Marc Jones2006b382007-12-19 00:47:09 +000042 u16 processor_rev_id;
43 u8 ht_io_hub_rev_id;
44 u8 nb_rev_id;
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000045
Marc Jones2006b382007-12-19 00:47:09 +000046 u8 bios_api_rev;
47 u8 resv1[3];
48
49 u32 match_reg[8];
50
51 u8 m_patch_data[896];
52 u8 resv2[896];
53
54 u8 x86_code_present;
55 u8 x86_code_entry[191];
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000056};
57
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +020058static void apply_microcode_patch(const struct microcode *m)
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000059{
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +020060 uint32_t new_patch_id;
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000061 msr_t msr;
Marc Jones2006b382007-12-19 00:47:09 +000062
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +020063 /* apply patch */
64 msr.hi = 0;
65 msr.lo = (uint32_t)m;
66
67 wrmsr(0xc0010020, msr);
68
69 UCODE_DEBUG("patch id to apply = 0x%08x\n", m->patch_id);
70
71 /* read the patch_id again */
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000072 msr = rdmsr(0x8b);
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +020073 new_patch_id = msr.lo;
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000074
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +020075 UCODE_DEBUG("updated to patch id = 0x%08x %s\n", new_patch_id ,
76 (new_patch_id == m->patch_id) ? "success" : "fail");
77}
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000078
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +020079static void amd_update_microcode(const void *ucode, size_t ucode_len,
80 uint32_t equivalent_processor_rev_id)
81{
82 const struct microcode *m;
83 const void *c;
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000084
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +020085 for(m = c = ucode; m->date_code; m = c) {
Kyösti Mälkki75b68d82013-12-12 06:53:05 +020086 if (m->processor_rev_id == equivalent_processor_rev_id) {
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +020087 apply_microcode_patch(m);
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000088 break;
89 }
90 c += 2048;
91 }
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +020092}
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000093
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +020094#define MICROCODE_CBFS_FILE "cpu_microcode_blob.bin"
95
96void amd_update_microcode_from_cbfs(u32 equivalent_processor_rev_id)
97{
98 const void *ucode;
99 size_t ucode_len;
100
101 if (equivalent_processor_rev_id == 0) {
102 UCODE_DEBUG("rev id not found. Skipping microcode patch!\n");
103 return;
104 }
105
106 ucode = cbfs_get_file_content(CBFS_DEFAULT_MEDIA, MICROCODE_CBFS_FILE,
107 CBFS_TYPE_MICROCODE, &ucode_len);
108 if (!ucode) {
109 UCODE_DEBUG("microcode file not found. Skipping updates.\n");
110 return;
111 }
112
113 amd_update_microcode(ucode, ucode_len, equivalent_processor_rev_id);
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +0000114}