2 * This file is part of the coreboot project.
4 * Copyright (C) 2010 coresystems GmbH
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; version 2 of
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
21 #include <console/console.h>
22 #include <cpu/x86/cache.h>
23 #include <cpu/x86/smm.h>
24 #include <device/pci_def.h>
27 extern unsigned char *mbi
;
30 // #define DEBUG_SMI_I82830
32 /* If YABEL is enabled and it's not running at 0x00000000, we have to add some
33 * offset to all our mbi object memory accesses
35 #if IS_ENABLED(CONFIG_PCI_OPTION_ROM_RUN_YABEL) && !CONFIG_YABEL_DIRECTHW
36 #define OBJ_OFFSET CONFIG_YABEL_VIRTMEM_LOCATION
38 #define OBJ_OFFSET 0x00000
43 #define D_OPEN (1 << 6)
44 #define D_CLS (1 << 5)
45 #define D_LCK (1 << 4)
46 #define G_SMRANE (1 << 3)
47 #define C_BASE_SEG ((0 << 2) | (1 << 1) | (0 << 0))
55 } __packed banner_id_t
;
58 #define MSH_OK_RESTART 0x0001
59 #define MSH_FWH_ERR 0x00ff
60 #define MSH_IF_BAD_ID 0x0100
61 #define MSH_IF_BAD_FUNC 0x0101
62 #define MSH_IF_MBI_CORRUPT 0x0102
63 #define MSH_IF_BAD_HANDLE 0x0103
64 #define MSH_ALRDY_ATCHED 0x0104
65 #define MSH_NOT_ATCHED 0x0105
67 #define MSH_IF_INVADDR 0x0107
68 #define MSH_IF_UKN_TYPE 0x0108
69 #define MSH_IF_NOT_FOUND 0x0109
70 #define MSH_IF_NO_KEY 0x010a
71 #define MSH_IF_BUF_SIZE 0x010b
72 #define MSH_IF_NOT_PENDING 0x010c
74 #ifdef DEBUG_SMI_I82830
76 dump(u8
* addr
, u32 len
)
78 printk(BIOS_DEBUG
, "\n%s(%p, %x):\n", __func__
, addr
, len
);
80 unsigned int tmpCnt
= len
;
84 printk(BIOS_DEBUG
, "\n%p: ", addr
);
88 printk(BIOS_DEBUG
, "%02x ", x
);
94 //reset addr ptr to print ascii
99 if ((x
< 32) || (x
>= 127)) {
103 printk(BIOS_DEBUG
, "%c", x
);
106 printk(BIOS_DEBUG
, "\n");
114 u32 smicombuffersize
;
115 } __packed version_t
;
126 } __packed mbi_header_t
;
133 } __packed obj_header_t
;
143 } __packed get_object_t
;
145 static void mbi_call(u8 subf
, banner_id_t
*banner_id
)
147 #ifdef DEBUG_SMI_I82830
148 printk(BIOS_DEBUG
, "MBI\n");
149 printk(BIOS_DEBUG
, "|- sub function %x\n", subf
);
150 printk(BIOS_DEBUG
, "|- banner id @ %x\n", (u32
)banner_id
);
151 printk(BIOS_DEBUG
, "| |- mhid %x\n", banner_id
->mhid
);
152 printk(BIOS_DEBUG
, "| |- function %x\n", banner_id
->function
);
153 printk(BIOS_DEBUG
, "| |- return status %x\n", banner_id
->retsts
);
154 printk(BIOS_DEBUG
, "| |- rfu %x\n", banner_id
->rfu
);
157 switch(banner_id
->function
) {
160 printk(BIOS_DEBUG
, "|- MBI_QueryInterface\n");
161 version
= (version_t
*)banner_id
;
162 version
->banner
.retsts
= MSH_OK
;
163 version
->versionmajor
= 1;
164 version
->versionminor
= 3;
165 version
->smicombuffersize
= 0x1000;
169 printk(BIOS_DEBUG
, "|- MBI_Attach\n");
170 printk(BIOS_DEBUG
, "| |- Not Implemented!\n");
173 printk(BIOS_DEBUG
, "|- MBI_Detach\n");
174 printk(BIOS_DEBUG
, "| |- Not Implemented!\n");
177 obj_header_t
*obj_header
= (obj_header_t
*)banner_id
;
178 mbi_header_t
*mbi_header
= NULL
;
179 printk(BIOS_DEBUG
, "|- MBI_GetObjectHeader\n");
180 printk(BIOS_DEBUG
, "| |- objnum = %d\n", obj_header
->objnum
);
183 obj_header
->banner
.retsts
= MSH_IF_NOT_FOUND
;
185 for (i
= 0; i
< mbi_len
;) {
188 if (!(mbi
[i
] == 0xf0 && mbi
[i
+1] == 0xf6)) {
193 mbi_header
= (mbi_header_t
*)&mbi
[i
];
194 len
= ALIGN((mbi_header
->size
* 16) + sizeof(mbi_header
) + ALIGN(mbi_header
->name_len
, 16), 16);
196 if (obj_header
->objnum
== count
) {
197 #ifdef DEBUG_SMI_I82830
198 if (mbi_header
->name_len
== 0xff) {
199 printk(BIOS_DEBUG
, "| |- corrupt.\n");
203 int headerlen
= ALIGN(sizeof(mbi_header
) + ALIGN(mbi_header
->name_len
, 16), 16);
204 #ifdef DEBUG_SMI_I82830
205 printk(BIOS_DEBUG
, "| |- headerlen = %d\n", headerlen
);
207 memcpy(&obj_header
->header
, mbi_header
, headerlen
);
208 obj_header
->banner
.retsts
= MSH_OK
;
209 printk(BIOS_DEBUG
, "| |- MBI module '");
211 for (j
= 0; j
< mbi_header
->name_len
&& mbi_header
->name
[j
]; j
++)
212 printk(BIOS_DEBUG
, "%c", mbi_header
->name
[j
]);
213 printk(BIOS_DEBUG
, "' found.\n");
214 #ifdef DEBUG_SMI_I82830
215 dump((u8
*)banner_id
, sizeof(obj_header_t
) + ALIGN(mbi_header
->name_len
, 16));
222 if (obj_header
->banner
.retsts
== MSH_IF_NOT_FOUND
)
223 printk(BIOS_DEBUG
, "| |- MBI object #%d not found.\n", obj_header
->objnum
);
227 get_object_t
*getobj
= (get_object_t
*)banner_id
;
228 mbi_header_t
*mbi_header
= NULL
;
229 printk(BIOS_DEBUG
, "|- MBI_GetObject\n");
230 #ifdef DEBUG_SMI_I82830
231 printk(BIOS_DEBUG
, "| |- handle = %016Lx\n", getobj
->handle
);
233 printk(BIOS_DEBUG
, "| |- objnum = %d\n", getobj
->objnum
);
234 printk(BIOS_DEBUG
, "| |- start = %x\n", getobj
->start
);
235 printk(BIOS_DEBUG
, "| |- numbytes = %x\n", getobj
->numbytes
);
236 printk(BIOS_DEBUG
, "| |- buflen = %x\n", getobj
->buflen
);
237 printk(BIOS_DEBUG
, "| |- buffer = %x\n", getobj
->buffer
);
240 getobj
->banner
.retsts
= MSH_IF_NOT_FOUND
;
242 for (i
= 0; i
< mbi_len
;) {
243 int headerlen
, objectlen
;
245 if (!(mbi
[i
] == 0xf0 && mbi
[i
+1] == 0xf6)) {
250 mbi_header
= (mbi_header_t
*)&mbi
[i
];
251 headerlen
= ALIGN(sizeof(mbi_header
) + ALIGN(mbi_header
->name_len
, 16), 16);
252 objectlen
= ALIGN((mbi_header
->size
* 16), 16);
254 if (getobj
->objnum
== count
) {
255 printk(BIOS_DEBUG
, "| |- len = %x\n", headerlen
+ objectlen
);
257 memcpy((void *)(getobj
->buffer
+ OBJ_OFFSET
),
258 ((char *)mbi_header
) + headerlen
, (objectlen
> getobj
->buflen
) ? getobj
->buflen
: objectlen
);
260 getobj
->banner
.retsts
= MSH_OK
;
261 #ifdef DEBUG_SMI_I82830
262 dump((u8
*)banner_id
, sizeof(*getobj
));
263 dump((u8
*)getobj
->buffer
+ OBJ_OFFSET
, objectlen
);
267 i
+= (headerlen
+ objectlen
);
270 if (getobj
->banner
.retsts
== MSH_IF_NOT_FOUND
)
271 printk(BIOS_DEBUG
, "MBI module %d not found.\n", getobj
->objnum
);
275 printk(BIOS_DEBUG
, "|- function %x\n", banner_id
->function
);
276 printk(BIOS_DEBUG
, "| |- Unknown Function!\n");
279 printk(BIOS_DEBUG
, "\n");
280 //dump(banner_id, 0x20);
283 #define SMI_IFC_SUCCESS 1
284 #define SMI_IFC_FAILURE_GENERIC 0
285 #define SMI_IFC_FAILURE_INVALID 2
286 #define SMI_IFC_FAILURE_CRITICAL 4
287 #define SMI_IFC_FAILURE_NONCRITICAL 6
294 static void smi_interface_call(void)
296 u8
*mmio
= (u8
*)pci_read_config32(PCI_DEV(0, 0x02, 0), 0x14);
297 // mmio &= 0xfff80000;
298 // printk(BIOS_DEBUG, "mmio=%x\n", mmio);
299 u16 swsmi
= pci_read_config16(PCI_DEV(0, 0x02, 0), 0xe0);
304 swsmi
&= ~(1 << 0); // clear SMI toggle
306 switch ((swsmi
>>1) & 0xf) {
308 printk(BIOS_DEBUG
, "Interface Function Presence Test.\n");
310 swsmi
&= ~(7 << 5); // Exit: Result
311 swsmi
|= (SMI_IFC_SUCCESS
<< 5);
313 swsmi
|= (PC13
<< 8);
314 pci_write_config16(PCI_DEV(0, 0x02, 0), 0xe0, swsmi
);
316 write32(mmio
+ 0x71428, 0x494e5443);
319 printk(BIOS_DEBUG
, "Get BIOS Data.\n");
320 printk(BIOS_DEBUG
, "swsmi=%04x\n", swsmi
);
323 printk(BIOS_DEBUG
, "Call MBI Functions.\n");
324 mbi_call(swsmi
>> 8, (banner_id_t
*)((read32(mmio
+ 0x71428) & 0x000fffff) + OBJ_OFFSET
) );
326 swsmi
&= ~(7 << 5); // Exit: Result
327 swsmi
|= (SMI_IFC_SUCCESS
<< 5);
328 pci_write_config16(PCI_DEV(0, 0x02, 0), 0xe0, swsmi
);
331 printk(BIOS_DEBUG
, "System BIOS Callbacks.\n");
332 printk(BIOS_DEBUG
, "swsmi=%04x\n", swsmi
);
335 printk(BIOS_DEBUG
, "Unknown SMI interface call %04x\n", swsmi
);
339 swsmi
&= ~(7 << 5); // Exit: Result
340 swsmi
|= (SMI_IFC_FAILURE_CRITICAL
<< 7);
341 pci_write_config16(PCI_DEV(0, 0x02, 0), 0xe0, swsmi
);
345 * @brief read and clear ERRSTS
346 * @return ERRSTS register
348 static u16
reset_err_status(void)
352 reg16
= pci_read_config16(PCI_DEV(0, 0x00, 0), ERRSTS
);
353 /* set status bits are cleared by writing 1 to them */
354 pci_write_config16(PCI_DEV(0, 0x00, 0), ERRSTS
, reg16
);
359 static void dump_err_status(u32 errsts
)
361 printk(BIOS_DEBUG
, "ERRSTS: ");
362 if (errsts
& (1 << 12)) printk(BIOS_DEBUG
, "MBI ");
363 if (errsts
& (1 << 9)) printk(BIOS_DEBUG
, "LCKF ");
364 if (errsts
& (1 << 8)) printk(BIOS_DEBUG
, "DTF ");
365 if (errsts
& (1 << 5)) printk(BIOS_DEBUG
, "UNSC ");
366 if (errsts
& (1 << 4)) printk(BIOS_DEBUG
, "OOGF ");
367 if (errsts
& (1 << 3)) printk(BIOS_DEBUG
, "IAAF ");
368 if (errsts
& (1 << 2)) printk(BIOS_DEBUG
, "ITTEF ");
369 printk(BIOS_DEBUG
, "\n");
372 void northbridge_smi_handler(unsigned int node
, smm_state_save_area_t
*state_save
)
376 /* We need to clear the SMI status registers, or we won't see what's
377 * happening in the following calls.
379 errsts
= reset_err_status();
380 if (errsts
& (1 << 12)) {
381 smi_interface_call();
384 dump_err_status(errsts
);