Merge remote-tracking branch 'upstream/master' into galp5

Change-Id: Ia43c6f4cdd97cd8c20a15a71499291ad4a92dedf
This commit is contained in:
Jeremy Soller
2020-10-28 12:03:28 -06:00
888 changed files with 14451 additions and 8942 deletions

1
.gitignore vendored
View File

@@ -59,6 +59,7 @@ site-local
*.debug
!Kconfig.debug
*.elf
*.fd
*.o
*.o.d
*.out

2
3rdparty/blobs vendored

View File

@@ -19,7 +19,7 @@ In order to add support for x86_64 the following assumptions were made:
* x86 payloads are loaded below 4GiB in physical memory and are jumped
to in *protected mode*
## Assuptions for all stages using the reference implementation
## Assumptions for all stages using the reference implementation
* 0-4GiB are identity mapped using 2MiB-pages as WB
* Memory above 4GiB isn't accessible
* page tables reside in memory mapped ROM

View File

@@ -7,3 +7,4 @@ they allow to easily reuse existing code accross platforms.
* [IPMI KCS](ipmi_kcs.md)
* [SMMSTORE](smmstore.md)
* [SoundWire](soundwire.md)
* [SMMSTOREv2](smmstorev2.md)

View File

@@ -0,0 +1,40 @@
# USB4 Retimers
# Introduction
As USB speeds continue to increase (up to 5G, 10G, and even 20G or higher in
newer revisions of the spec), it becomes more difficult to maintain signal
integrity for longer traces. Devices such as retimers and redrivers can be used
to help signals maintain their integrity over long distances.
A redriver is a device that boosts the high-frequency content of a signal in
order to compensate for the attenuation typically caused by travelling through
various circuit components (PCB, connectors, CPU, etc.). Redrivers are not
protocol-aware, which makes them relatively simple. However, their effectiveness
is limited, and may not work at all in some scenarios.
A retimer is a device that retransmits a fresh copy of the signal it receives,
by doing CDR and retransmitting the data (i.e., it is protocol-aware). Since
this is a digital component, it may have firmware.
# Driver Usage
Some operating systems may have the ability to update firmware on USB4 retimers,
and ultimately will need some way to power the device on and off so that its new
firmware can be loaded. This is achieved by providing a GPIO signal that can be
used for this purpose; its active state must be the one in which power is
applied to the retimer. This driver will generate the required ACPI AML code
which will toggle the GPIO in response to the kernel's request (through the
`_DSM` ACPI method). Simply put something like the following in your devicetree:
```
device pci 0.0 on
chip drivers/intel/usb4/retimer
register "power_gpio" = "ACPI_GPIO_OUTPUT_ACTIVE_HIGH(GPP_A0)"
device generic 0 on end
end
end
```
replacing the GPIO with the appropriate pin and polarity.

View File

@@ -0,0 +1,221 @@
# SMM based flash storage driver Version 2
This documents the API exposed by the x86 system management based
storage driver.
## SMMSTOREv2
SMMSTOREv2 is a [SMM] mediated driver to read from, write to and erase
a predefined region in flash. It can be enabled by setting
`CONFIG_SMMSTORE=y` and `CONFIG_SMMSTORE_V2=y` in menuconfig.
This can be used by the OS or the payload to implement persistent
storage to hold for instance configuration data, without needing to
implement a (platform specific) storage driver in the payload itself.
### Storage size and alignment
SMMSTORE version 2 requires a minimum alignment of 64 KiB, which should
be supported by all flash chips. Not having to perform read-modify-write
operations is desired, as it reduces complexity and potential for bugs.
This can be used by a FTW (FaultTolerantWrite) implementation that uses
at least two regions in an A/B update scheme. The FTW implementation in
EDK2 uses three different regions in the store:
- The variable store
- The FTW spare block
- The FTW working block
All regions must be block-aligned, and the FTW spare size must be larger
than that of the variable store. FTW working block can be much smaller.
With 64 KiB as block size, the minimum size of the FTW-enabled store is:
- The variable store: 1 block = 64 KiB
- The FTW spare block: 2 blocks = 2 * 64 KiB
- The FTW working block: 1 block = 64 KiB
Therefore, the minimum size for EDK2 FTW is 4 blocks, or 256 KiB.
## API
The API provides read and write access to an unformatted block storage.
### Storage region
By default SMMSTOREv2 will operate on a separate FMAP region called
`SMMSTORE`. The default generated FMAP will include such a region. On
systems with a locked FMAP, e.g. in an existing vboot setup with a
locked RO region, the option exists to add a cbfsfile called `smm_store`
in the `RW_LEGACY` (if CHROMEOS) or in the `COREBOOT` FMAP regions. It
is recommended for new builds using a handcrafted FMD that intend to
make use of SMMSTORE to include a sufficiently large `SMMSTORE` FMAP
region. It is mandatory to align the `SMMSTORE` region to 64KiB for
compatibility with the largest flash erase operation.
When a default generated FMAP is used, the size of the FMAP region is
equal to `CONFIG_SMMSTORE_SIZE`. UEFI payloads expect at least 64 KiB.
To support a fault tolerant write mechanism, at least a multiple of
this size is recommended.
### Communication buffer
To prevent malicious ring0 code to access arbitrary memory locations,
SMMSTOREv2 uses a communication buffer in CBMEM/HOB for all transfers.
This buffer has to be at least 64 KiB in size and must be installed
before calling any of the SMMSTORE read or write operations. Usually,
coreboot will install this buffer to transfer data between ring0 and
the [SMM] handler.
In order to get the communication buffer address, the payload or OS
has to read the coreboot table with tag `0x0039`, containing:
```C
struct lb_smmstorev2 {
uint32_t tag;
uint32_t size;
uint32_t num_blocks; /* Number of writeable blocks in SMM */
uint32_t block_size; /* Size of a block in byte. Default: 64 KiB */
uint32_t mmap_addr; /* MMIO address of the store for read only access */
uint32_t com_buffer; /* Physical address of the communication buffer */
uint32_t com_buffer_size; /* Size of the communication buffer in byte */
uint8_t apm_cmd; /* The command byte to write to the APM I/O port */
uint8_t unused[3]; /* Set to zero */
};
```
The absence of this coreboot table entry indicates that there's no
SMMSTOREv2 support.
### Blocks
The SMMSTOREv2 splits the SMMSTORE FMAP partition into smaller chunks
called *blocks*. Every block is at least the size of 64KiB to support
arbitrary NOR flash erase ops. A payload or OS must make no further
assumptions about the block or communication buffer size.
### Generating the SMI
SMMSTOREv2 is called via an SMI, which is generated via a write to the
IO port defined in the smi_cmd entry of the FADT ACPI table. `%al`
contains `APM_CNT_SMMSTORE=0xed` and is written to the smi_cmd IO
port. `%ah` contains the SMMSTOREv2 command. `%ebx` contains the
parameter buffer to the SMMSTOREv2 command.
### Return values
If a command succeeds, SMMSTOREv2 will return with
`SMMSTORE_RET_SUCCESS=0` in `%eax`. On failure SMMSTORE will return
`SMMSTORE_RET_FAILURE=1`. For unsupported SMMSTORE commands
`SMMSTORE_REG_UNSUPPORTED=2` is returned.
**NOTE 1**: The caller **must** check the return value and should make
no assumption on the returned data if `%eax` does not contain
`SMMSTORE_RET_SUCCESS`.
**NOTE 2**: If the SMI returns without changing `%ax`, it can be assumed
that the SMMSTOREv2 feature is not installed.
### Calling arguments
SMMSTOREv2 supports 3 subcommands that are passed via `%ah`, the
additional calling arguments are passed via `%ebx`.
**NOTE**: The size of the struct entries are in the native word size of
smihandler. This means 32 bits in almost all cases.
#### - SMMSTORE_CMD_INIT = 4
This installs the communication buffer to use and thus enables the
SMMSTORE handler. This command can only be executed once and is done
by the firmware. Calling this function at runtime has no effect.
The additional parameter buffer `%ebx` contains a pointer to the
following struct:
```C
struct smmstore_params_init {
uint32_t com_buffer;
uint32_t com_buffer_size;
} __packed;
```
INPUT:
- `com_buffer`: Physical address of the communication buffer (CBMEM)
- `com_buffer_size`: Size in bytes of the communication buffer
#### - SMMSTORE_CMD_RAW_READ = 5
SMMSTOREv2 allows reading arbitrary data. It is up to the caller to
initialize the store with meaningful data before using it.
The additional parameter buffer `%ebx` contains a pointer to the
following struct:
```C
struct smmstore_params_raw_read {
uint32_t bufsize;
uint32_t bufoffset;
uint32_t block_id;
} __packed;
```
INPUT:
- `bufsize`: Size of data to read within the communication buffer
- `bufoffset`: Offset within the communication buffer
- `block_id`: Block to read from
#### - SMMSTORE_CMD_RAW_WRITE = 6
SMMSTOREv2 allows writing arbitrary data. It is up to the caller to
erase a block before writing it.
The additional parameter buffer `%ebx` contains a pointer to
the following struct:
```C
struct smmstore_params_raw_write {
uint32_t bufsize;
uint32_t bufoffset;
uint32_t block_id;
} __packed;
```
INPUT:
- `bufsize`: Size of data to write within the communication buffer
- `bufoffset`: Offset within the communication buffer
- `block_id`: Block to write to
#### - SMMSTORE_CMD_RAW_CLEAR = 7
SMMSTOREv2 allows clearing blocks. A cleared block will read as `0xff`.
By providing multiple blocks the caller can implement a fault tolerant
write mechanism. It is up to the caller to clear blocks before writing
to them.
```C
struct smmstore_params_raw_clear {
uint32_t block_id;
} __packed;
```
INPUT:
- `block_id`: Block to erase
#### Security
Pointers provided by the payload or OS are checked to not overlap with
SMM. This protects the SMM handler from being compromised.
As all information is exchanged using the communication buffer and
coreboot tables, there's no risk that a malicious application capable
of issuing SMIs could extract arbitrary data or modify the currently
running kernel.
## External links
* [A Tour Beyond BIOS Implementing UEFI Authenticated Variables in SMM with EDKI](https://software.intel.com/sites/default/files/managed/cf/ea/a_tour_beyond_bios_implementing_uefi_authenticated_variables_in_smm_with_edkii.pdf)
Note that this differs significantly from coreboot's implementation.
[SMM]: ../security/smm.md

View File

@@ -0,0 +1,103 @@
# Supermicro X11SSH-F
This section details how to run coreboot on the [Supermicro X11SSH-F].
## Flashing coreboot
The board can be flashed externally. [STM32-based programmers] worked.
The flash IC "W25Q128.V" (detected by flashrom) can be found near PCH PCIe Slot 4. It is sometime
socketed, and covered by a sticker, hindering the observation of its precise model.
It can be programmed in-system with a clip like pomona 5250.
## BMC (IPMI)
This board has an ASPEED [AST2400], which has BMC/[IPMI] functionality. The BMC firmware resides in a
32 MiB SOIC-16 chip in the corner of the mainboard near the PCH PCIe Slot 4. This chip is a
[MX25L25635F].
## IGD
If an IGD is integrated with CPU, it will be enabled on this board. Though there is no video output
for it (The onboard VGA port is connected to BMC), it is said to be capable of being used for compute
tasks, or for offloading graphics rendering via "muxless" [vga_witcheroo].
## Tested and working
- SeaBIOS payload to boot Kali Linux live USB
- ECC ram (Linux' ie31200 driver works)
- Integrated graphics device available without output
- USB ports
- Ethernet
- SATA ports
- RS232 external
- PCIe slots
- BMC (IPMI)
- VGA on Aspeed
- TPM on TPM expansion header
## Known issues
- See general issue section
- S3 resume not working (vendor and coreboot)
- SeaBIOS cannot make use of VGA on Aspeed (even if IGD is disabled)
## ToDo
- Fix known issues
- Testing other payloads
## Technology
```eval_rst
+------------------+--------------------------------------------------+
| CPU | Intel Kaby Lake |
+------------------+--------------------------------------------------+
| PCH | Intel C236 |
+------------------+--------------------------------------------------+
| Coprocessor | Intel SPS (server version of the ME) |
+------------------+--------------------------------------------------+
| Super I/O | ASPEED AST2400 |
+------------------+--------------------------------------------------+
| Ethernet | 2x Intel I210-AT 1 GbE |
| | 1x dedicated BMC |
+------------------+--------------------------------------------------+
| PCIe slots | 1x 3.0 x8 |
| | 1x 3.0 x8 (in x16) |
| | 1x 3.0 x4 (in x8) |
| | 1x 3.0 x2 (in M.2 slot with key M) |
+------------------+--------------------------------------------------+
| USB slots | 2x USB 2.0 (ext) |
| | 2x USB 3.0 (ext) |
| | 1x USB 3.0 (int) |
| | 1x dual USB 3.0 header |
| | 2x dual USB 2.0 header |
+------------------+--------------------------------------------------+
| SATA slots | 8x S-ATA III |
+------------------+--------------------------------------------------+
| Other slots | 1x RS232 (ext) |
| | 1x RS232 header |
| | 1x TPM header |
| | 1x Power SMB header |
| | 5x PWM Fan connector |
| | 2x I-SGPIO |
| | 2x S-ATA DOM Power connector |
| | 1x XDP Port (connector may absent) |
| | 1x External BMC I2C Header (for IPMI card) |
| | 1x Chassis Intrusion Header |
+------------------+--------------------------------------------------+
```
## Extra links
- [Supermicro X11SSH-F]
- [Board manual]
[Supermicro X11SSH-F]: https://www.supermicro.com/en/products/motherboard/X11SSH-F
[Board manual]: https://www.supermicro.com/manuals/motherboard/C236/MNL-1778.pdf
[AST2400]: https://www.aspeedtech.com/products.php?fPath=20&rId=376
[IPMI]: ../../../../drivers/ipmi_kcs.md
[MX25L25635F]: https://media.digikey.com/pdf/Data%20Sheets/Macronix/MX25L25635F.pdf
[STM32-based programmers]: https://github.com/dword1511/stm32-vserprog
[vga_switcheroo]: https://01.org/linuxgraphics/gfx-docs/drm/gpu/vga-switcheroo.html

View File

@@ -208,6 +208,14 @@ F: src/mainboard/asus/p8z77-v_lx2/
CLEVO MAINBOARDS
M: Felix Singer <felixsinger@posteo.net>
M: Michael Niewöhner <foss@mniewoehner.de>
S: Supported
F: src/mainboard/clevo
FACEBOOK FBG1701 MAINBOARD
M: Frans Hendriks <fhendriks@eltan.com>
M: Wim Vervoorn <wvervoorn@eltan.com>

View File

@@ -80,7 +80,7 @@ subdirs-y := src/lib src/commonlib/ src/console src/device src/acpi
subdirs-y += src/ec/acpi $(wildcard src/ec/*/*) $(wildcard src/southbridge/*/*)
subdirs-y += $(wildcard src/soc/*/*) $(wildcard src/northbridge/*/*)
subdirs-y += src/superio
subdirs-y += $(wildcard src/drivers/*) $(wildcard src/drivers/*/*)
subdirs-y += $(wildcard src/drivers/*) $(wildcard src/drivers/*/*) $(wildcard src/drivers/*/*/*)
subdirs-y += src/cpu src/vendorcode
subdirs-y += util/cbfstool util/sconfig util/nvramtool util/pgtblgen util/amdfwtool
subdirs-y += util/futility util/marvell util/bincfg util/supermicro
@@ -611,6 +611,12 @@ SCONFIG_OPTIONS += --output_c=$(DEVICETREE_STATIC_C)
DEVICETREE_STATIC_H := $(obj)/static.h
SCONFIG_OPTIONS += --output_h=$(DEVICETREE_STATIC_H)
DEVICETREE_DEVICENAMES_H := $(obj)/static_devices.h
SCONFIG_OPTIONS += --output_d=$(DEVICETREE_DEVICENAMES_H)
DEVICETREE_FWCONFIG_H := $(obj)/static_fw_config.h
SCONFIG_OPTIONS += --output_f=$(DEVICETREE_FWCONFIG_H)
$(DEVICETREE_STATIC_C): $(DEVICETREE_FILE) $(OVERRIDE_DEVICETREE_FILE) $(CHIPSET_DEVICETREE_FILE) $(objutil)/sconfig/sconfig
@printf " SCONFIG $(subst $(src)/,,$(<))\n"
mkdir -p $(dir $(DEVICETREE_STATIC_C))

View File

@@ -0,0 +1,10 @@
# Known-working configuration to boot with TXT enabled. Since BIOS
# and SINIT ACM blobs are missing, use something else as placeholder.
# Used ACMs were extracted from a Supermicro X10SLH firmware update.
CONFIG_VENDOR_ASROCK=y
CONFIG_BOARD_ASROCK_B85M_PRO4=y
CONFIG_USER_TPM2=y
CONFIG_INTEL_TXT=y
CONFIG_INTEL_TXT_BIOSACM_FILE="3rdparty/blobs/cpu/intel/stm/stm.bin"
CONFIG_INTEL_TXT_SINITACM_FILE="3rdparty/blobs/cpu/intel/stm/stm.bin"
CONFIG_INTEL_TXT_LOGGING=y

View File

@@ -151,7 +151,7 @@ static int pci_module_redraw(WINDOW *win)
return 0;
}
static void pci_scan_bus(int bus)
static void ci_pci_scan_bus(int bus)
{
int slot, func;
unsigned int val;
@@ -196,7 +196,7 @@ static void pci_scan_bus(int bus)
busses = pci_read_config32(dev, REG_PRIMARY_BUS);
pci_scan_bus((busses >> 8) & 0xff);
ci_pci_scan_bus((busses >> 8) & 0xff);
}
}
@@ -240,7 +240,7 @@ static int pci_module_handle(int key)
static int pci_module_init(void)
{
pci_scan_bus(0);
ci_pci_scan_bus(0);
return 0;
}

View File

@@ -78,5 +78,10 @@ int lib_get_sysinfo(void)
lib_sysinfo.memrange[1].type = CB_MEM_RAM;
}
#if CONFIG(LP_PCI)
pci_init(&lib_sysinfo.pacc);
pci_scan_bus(&lib_sysinfo.pacc);
#endif
return ret;
}

View File

@@ -41,6 +41,7 @@ PDCurses portable platform definitions list:
/*----------------------------------------------------------------------*/
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h> /* Required by X/Open usage below */
@@ -48,12 +49,6 @@ PDCurses portable platform definitions list:
# include <wchar.h>
#endif
#if defined(__cplusplus) || defined(__cplusplus__) || defined(__CPLUSPLUS)
extern "C"
{
# define bool _bool
#endif
/*----------------------------------------------------------------------
*
* PDCurses Manifest Constants
@@ -82,8 +77,6 @@ extern "C"
*
*/
typedef unsigned char bool; /* PDCurses Boolean type */
#ifdef CHTYPE_LONG
# if _LP64
typedef unsigned int chtype;

View File

@@ -87,7 +87,7 @@
* User-definable tweak to disable the include of <stdbool.h>.
*/
#ifndef NCURSES_ENABLE_STDBOOL_H
#define NCURSES_ENABLE_STDBOOL_H 0 //// XXX
#define NCURSES_ENABLE_STDBOOL_H 1
#endif
/*

View File

@@ -27,6 +27,8 @@
* SUCH DAMAGE.
*/
#include <stdbool.h>
#include <keycodes.h>
#include <libpayload-config.h>
#include <libpayload.h>
@@ -169,14 +171,14 @@ static struct layout_maps keyboard_layouts[] = {
#endif
};
static unsigned char keyboard_cmd(unsigned char cmd)
static bool keyboard_cmd(unsigned char cmd)
{
i8042_write_data(cmd);
return i8042_wait_read_ps2() == 0xfa;
}
int keyboard_havechar(void)
bool keyboard_havechar(void)
{
return i8042_data_ready_ps2();
}
@@ -306,13 +308,13 @@ int keyboard_set_layout(char *country)
}
static struct console_input_driver cons = {
.havekey = keyboard_havechar,
.havekey = (int (*)(void))keyboard_havechar,
.getchar = keyboard_getchar,
.input_type = CONSOLE_INPUT_TYPE_EC,
};
/* Enable keyboard translated */
static int enable_translated(void)
static bool enable_translated(void)
{
if (!i8042_cmd(I8042_CMD_RD_CMD_BYTE)) {
int cmd = i8042_read_data_ps2();
@@ -321,19 +323,19 @@ static int enable_translated(void)
i8042_write_data(cmd);
} else {
printf("ERROR: i8042_cmd WR_CMD failed!\n");
return 0;
return false;
}
} else {
printf("ERROR: i8042_cmd RD_CMD failed!\n");
return 0;
return false;
}
return 1;
return true;
}
/* Set scancode set 1 */
static int set_scancode_set(void)
static bool set_scancode_set(void)
{
unsigned int ret;
bool ret;
ret = keyboard_cmd(I8042_KBCMD_SET_SCANCODE);
if (!ret) {
printf("ERROR: Keyboard set scancode failed!\n");

View File

@@ -12,7 +12,7 @@ config STORAGE
config STORAGE_64BIT_LBA
bool "Use 64-bit integers to address sectors"
depends on STORAGE
default n
default y
help
If this is selected, sectors will be addressed by an 64-bit integer.
Select this to support LBA-48 for ATA drives.
@@ -45,7 +45,7 @@ config STORAGE_AHCI
config STORAGE_AHCI_ONLY_TESTED
bool "Only enable tested controllers"
depends on STORAGE_AHCI
default y
default n
help
If this option is selected only AHCI controllers which are known
If this option is selected, only AHCI controllers which are known
to work will be used.

View File

@@ -227,34 +227,28 @@ static u32 working_controllers[] = {
0x8086 | 0x5ae3 << 16, /* Apollo Lake */
};
#endif
static void ahci_init_pci(pcidev_t dev)
void ahci_initialize(struct pci_dev *dev)
{
int i;
const u16 class = pci_read_config16(dev, 0xa);
if (class != 0x0106)
return;
const u16 vendor = pci_read_config16(dev, 0x00);
const u16 device = pci_read_config16(dev, 0x02);
#if CONFIG(LP_STORAGE_AHCI_ONLY_TESTED)
const u32 vendor_device = pci_read_config32(dev, 0x0);
const u32 vendor_device = dev->vendor_id | dev->device_id << 16;
for (i = 0; i < ARRAY_SIZE(working_controllers); ++i)
if (vendor_device == working_controllers[i])
break;
if (i == ARRAY_SIZE(working_controllers)) {
printf("ahci: Not using untested SATA controller "
"%02x:%02x.%02x (%04x:%04x).\n", PCI_BUS(dev),
PCI_SLOT(dev), PCI_FUNC(dev), vendor, device);
"%02x:%02x.%02x (%04x:%04x).\n", dev->bus,
dev->dev, dev->func, dev->vendor_id, dev->device_id);
return;
}
#endif
printf("ahci: Found SATA controller %02x:%02x.%02x (%04x:%04x).\n",
PCI_BUS(dev), PCI_SLOT(dev), PCI_FUNC(dev), vendor, device);
dev->bus, dev->dev, dev->func, dev->vendor_id, dev->device_id);
hba_ctrl_t *const ctrl = phys_to_virt(
pci_read_config32(dev, 0x24) & ~0x3ff);
hba_ctrl_t *const ctrl = phys_to_virt(pci_read_long(dev, 0x24) & ~0x3ff);
hba_port_t *const ports = ctrl->ports;
/* Reset host controller. */
@@ -273,8 +267,8 @@ static void ahci_init_pci(pcidev_t dev)
ctrl->global_ctrl |= HBA_CTRL_AHCI_EN;
/* Enable bus mastering. */
const u16 command = pci_read_config16(dev, PCI_COMMAND);
pci_write_config16(dev, PCI_COMMAND, command | PCI_COMMAND_MASTER);
const u16 command = pci_read_word(dev, PCI_COMMAND);
pci_write_word(dev, PCI_COMMAND, command | PCI_COMMAND_MASTER);
/* Probe for devices. */
for (i = 0; i < 32; ++i) {
@@ -282,19 +276,3 @@ static void ahci_init_pci(pcidev_t dev)
ahci_port_probe(ctrl, &ports[i], i + 1);
}
}
void ahci_initialize(void)
{
int bus, dev, func;
for (bus = 0; bus < 256; ++bus) {
for (dev = 0; dev < 32; ++dev) {
const u16 class =
pci_read_config16(PCI_DEV(bus, dev, 0), 0xa);
if (class != 0xffff) {
for (func = 0; func < 8; ++func)
ahci_init_pci(PCI_DEV(bus, dev, func));
}
}
}
}

View File

@@ -27,6 +27,7 @@
*/
#include <libpayload.h>
#include <pci/pci.h>
#if CONFIG(LP_STORAGE_AHCI)
# include <storage/ahci.h>
#endif
@@ -108,7 +109,18 @@ ssize_t storage_read_blocks512(const size_t dev_num,
*/
void storage_initialize(void)
{
#if CONFIG(LP_PCI)
struct pci_dev *dev;
for (dev = lib_sysinfo.pacc.devices; dev; dev = dev->next) {
switch (dev->device_class) {
#if CONFIG(LP_STORAGE_AHCI)
ahci_initialize();
case PCI_CLASS_STORAGE_AHCI:
ahci_initialize(dev);
break;
#endif
default:
break;
}
}
#endif
}

View File

@@ -79,6 +79,7 @@ enum {
CB_TAG_MMC_INFO = 0x0035,
CB_TAG_TCPA_LOG = 0x0036,
CB_TAG_FMAP = 0x0037,
CB_TAG_SMMSTOREV2 = 0x0039,
CB_TAG_CMOS_OPTION_TABLE = 0x00c8,
CB_TAG_OPTION = 0x00c9,
CB_TAG_OPTION_ENUM = 0x00ca,

View File

@@ -42,6 +42,7 @@
#ifndef _LIBPAYLOAD_H
#define _LIBPAYLOAD_H
#include <stdbool.h>
#include <libpayload-config.h>
#include <compiler.h>
#include <cbgfx.h>
@@ -186,7 +187,7 @@ int add_reset_handler(void (*new_handler)(void));
*/
void keyboard_init(void);
void keyboard_disconnect(void);
int keyboard_havechar(void);
bool keyboard_havechar(void);
unsigned char keyboard_get_scancode(void);
int keyboard_getchar(void);
int keyboard_set_layout(char *country);
@@ -445,6 +446,8 @@ u8 hex2bin(u8 h);
void hexdump(const void *memory, size_t length);
void fatal(const char *msg) __attribute__((noreturn));
/* Population Count: number of bits that are one */
static inline int popcnt(u32 x) { return __builtin_popcount(x); }
/* Count Leading Zeroes: clz(0) == 32, clz(0xf) == 28, clz(1 << 31) == 0 */
static inline int clz(u32 x)
{
@@ -454,6 +457,15 @@ static inline int clz(u32 x)
static inline int log2(u32 x) { return (int)sizeof(x) * 8 - clz(x) - 1; }
/* Find First Set: __ffs(0xf) == 0, __ffs(0) == -1, __ffs(1 << 31) == 31 */
static inline int __ffs(u32 x) { return log2(x & (u32)(-(s32)x)); }
static inline int popcnt64(u64 x) { return __builtin_popcountll(x); }
static inline int clz64(u64 x)
{
return x ? __builtin_clzll(x) : sizeof(x) * 8;
}
static inline int log2_64(u64 x) { return sizeof(x) * 8 - clz64(x) - 1; }
static inline int __ffs64(u64 x) { return log2_64(x & (u64)(-(s64)x)); }
/** @} */
/**

View File

@@ -66,6 +66,7 @@
#define PCI_ROM_ADDRESS1 0x38 // on bridges
#define PCI_ROM_ADDRESS_MASK ~0x7ff
#define PCI_CLASS_STORAGE_AHCI 0x0106
#define PCI_CLASS_MEMORY_OTHER 0x0580
#define PCI_VENDOR_ID_INTEL 0x8086
@@ -74,6 +75,7 @@ struct pci_dev {
u16 domain;
u8 bus, dev, func;
u16 vendor_id, device_id;
u16 device_class;
struct pci_dev *next;
};

View File

@@ -0,0 +1,10 @@
/* SPDX-License-Identifier: BSD-3-Clause */
#ifndef __STDBOOL_H
#define __STDBOOL_H
#define bool _Bool
#define false 0
#define true (!false)
#endif

View File

@@ -26,9 +26,11 @@
* SUCH DAMAGE.
*/
#include <pci/pci.h>
#ifndef _STORAGE_AHCI_H
#define _STORAGE_AHCI_H
void ahci_initialize(void);
void ahci_initialize(struct pci_dev *dev);
#endif

View File

@@ -29,6 +29,7 @@
#ifndef _SYSINFO_H
#define _SYSINFO_H
#include <pci/pci.h>
#include <stdint.h>
/* Maximum number of memory range definitions. */
@@ -130,6 +131,10 @@ struct sysinfo_t {
/* Pointer to FMAP cache in CBMEM */
uintptr_t fmap_cache;
#if CONFIG(LP_PCI)
struct pci_access pacc;
#endif
};
extern struct sysinfo_t lib_sysinfo;

View File

@@ -32,4 +32,36 @@
#define cpuid(fn, eax, ebx, ecx, edx) \
asm("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "0"(fn))
#define _declare_cpuid(reg) \
static inline unsigned int cpuid_##reg(unsigned int fn) \
{ \
unsigned int eax, ebx, ecx, edx; \
cpuid(fn, eax, ebx, ecx, edx); \
return reg; \
}
_declare_cpuid(eax)
_declare_cpuid(ebx)
_declare_cpuid(ecx)
_declare_cpuid(edx)
#undef _declare_cpuid
static inline unsigned int cpuid_max(void)
{
return cpuid_eax(0);
}
static inline unsigned int cpuid_family(void)
{
const unsigned int eax = cpuid_eax(1);
return (eax & 0xff00000) >> (20 - 4) | (eax & 0xf00) >> 8;
}
static inline unsigned int cpuid_model(void)
{
const unsigned int eax = cpuid_eax(1);
return (eax & 0xf0000) >> (16 - 4) | (eax & 0xf0) >> 4;
}
#endif

View File

@@ -72,8 +72,7 @@ int pci_write_long(struct pci_dev *dev, int pos, u32 data)
struct pci_access *pci_alloc(void)
{
struct pci_access *pacc = malloc(sizeof(*pacc));
return pacc;
return malloc(sizeof(struct pci_access));
}
void pci_init(struct pci_access *pacc)
@@ -179,6 +178,7 @@ static struct pci_dev *pci_scan_single_bus(struct pci_dev *dev, uint8_t bus)
dev->func = func;
dev->vendor_id = val & 0xffff;
dev->device_id = (uint16_t)(val >> 16);
dev->device_class = pci_read_config16(PCI_DEV(bus, slot, func), PCI_CLASS_DEVICE);
dev->next = 0;
hdr = pci_read_config8(PCI_DEV(bus, slot, func),

View File

@@ -554,6 +554,7 @@ source "src/device/Kconfig"
menu "Generic Drivers"
source "src/drivers/*/Kconfig"
source "src/drivers/*/*/Kconfig"
source "src/drivers/*/*/*/Kconfig"
source "src/commonlib/storage/Kconfig"
endmenu

View File

@@ -408,7 +408,7 @@ void acpigen_write_processor_cnot(const unsigned int number_of_cores)
* len is region length.
* OperationRegion(regionname, regionspace, regionoffset, regionlength)
*/
void acpigen_write_opregion(struct opregion *opreg)
void acpigen_write_opregion(const struct opregion *opreg)
{
/* OpregionOp */
acpigen_emit_ext_op(OPREGION_OP);
@@ -505,6 +505,12 @@ static void acpigen_write_field_name(const char *name, uint32_t size)
acpigen_write_field_length(size);
}
static void acpigen_write_field_reserved(uint32_t size)
{
acpigen_emit_byte(0);
acpigen_write_field_length(size);
}
/*
* Generate ACPI AML code for Field
* Arg0: region name
@@ -515,6 +521,7 @@ static void acpigen_write_field_name(const char *name, uint32_t size)
* struct fieldlist l[] = {
* FIELDLIST_OFFSET(0x84),
* FIELDLIST_NAMESTR("PMCS", 2),
* FIELDLIST_RESERVED(6),
* };
* acpigen_write_field("UART", l, ARRAY_SIZE(l), FIELD_ANYACC | FIELD_NOLOCK |
* FIELD_PRESERVE);
@@ -522,7 +529,8 @@ static void acpigen_write_field_name(const char *name, uint32_t size)
* Field (UART, AnyAcc, NoLock, Preserve)
* {
* Offset (0x84),
* PMCS, 2
* PMCS, 2,
* , 6,
* }
*/
void acpigen_write_field(const char *name, const struct fieldlist *l, size_t count,
@@ -546,6 +554,10 @@ void acpigen_write_field(const char *name, const struct fieldlist *l, size_t cou
acpigen_write_field_name(l[i].name, l[i].bits);
current_bit_pos += l[i].bits;
break;
case RESERVED:
acpigen_write_field_reserved(l[i].bits);
current_bit_pos += l[i].bits;
break;
case OFFSET:
acpigen_write_field_offset(l[i].bits, current_bit_pos);
current_bit_pos = l[i].bits;
@@ -1231,6 +1243,22 @@ void acpigen_write_store_op_to_namestr(uint8_t src, const char *dst)
acpigen_emit_namestring(dst);
}
/* Store (src, "namestr") */
void acpigen_write_store_int_to_namestr(uint64_t src, const char *dst)
{
acpigen_write_store();
acpigen_write_integer(src);
acpigen_emit_namestring(dst);
}
/* Store (src, dst) */
void acpigen_write_store_int_to_op(uint64_t src, uint8_t dst)
{
acpigen_write_store();
acpigen_write_integer(src);
acpigen_emit_byte(dst);
}
/* Or (arg1, arg2, res) */
void acpigen_write_or(uint8_t arg1, uint8_t arg2, uint8_t res)
{
@@ -1353,6 +1381,14 @@ void acpigen_write_else(void)
acpigen_write_len_f();
}
void acpigen_write_shiftleft_op_int(uint8_t src_result, uint64_t count)
{
acpigen_emit_byte(SHIFT_LEFT_OP);
acpigen_emit_byte(src_result);
acpigen_write_integer(count);
acpigen_emit_byte(ZERO_OP);
}
void acpigen_write_to_buffer(uint8_t src, uint8_t dst)
{
acpigen_emit_byte(TO_BUFFER_OP);
@@ -1829,7 +1865,7 @@ int __weak acpigen_soc_clear_tx_gpio(unsigned int gpio_num)
*
* Returns 0 on success and -1 on error.
*/
int acpigen_enable_tx_gpio(struct acpi_gpio *gpio)
int acpigen_enable_tx_gpio(const struct acpi_gpio *gpio)
{
if (gpio->active_low)
return acpigen_soc_clear_tx_gpio(gpio->pins[0]);
@@ -1837,7 +1873,7 @@ int acpigen_enable_tx_gpio(struct acpi_gpio *gpio)
return acpigen_soc_set_tx_gpio(gpio->pins[0]);
}
int acpigen_disable_tx_gpio(struct acpi_gpio *gpio)
int acpigen_disable_tx_gpio(const struct acpi_gpio *gpio)
{
if (gpio->active_low)
return acpigen_soc_set_tx_gpio(gpio->pins[0]);
@@ -1845,7 +1881,7 @@ int acpigen_disable_tx_gpio(struct acpi_gpio *gpio)
return acpigen_soc_clear_tx_gpio(gpio->pins[0]);
}
void acpigen_get_rx_gpio(struct acpi_gpio *gpio)
void acpigen_get_rx_gpio(const struct acpi_gpio *gpio)
{
acpigen_soc_read_rx_gpio(gpio->pins[0]);
@@ -1853,7 +1889,7 @@ void acpigen_get_rx_gpio(struct acpi_gpio *gpio)
acpigen_write_xor(LOCAL0_OP, 1, LOCAL0_OP);
}
void acpigen_get_tx_gpio(struct acpi_gpio *gpio)
void acpigen_get_tx_gpio(const struct acpi_gpio *gpio)
{
acpigen_soc_get_tx_gpio(gpio->pins[0]);

View File

@@ -7,28 +7,27 @@
#define ACPI_DSM_I2C_HID_UUID "3CDFF6F7-4267-4555-AD05-B30A3D8938DE"
/* I2C HID currently supports revision 1 only, for which, only 1 additional
* function is supported. Thus, the query function should return 0x3:
* bit 0 = additional function supported
* bit 1 = function with index 1 supported
* All other revisions do not support additional functions and hence return 0
*/
static void i2c_hid_func0_cb(void *arg)
{
/* ToInteger (Arg1, Local2) */
acpigen_write_to_integer(ARG1_OP, LOCAL2_OP);
/* If (LEqual (Local2, 0x0)) */
acpigen_write_if_lequal_op_int(LOCAL2_OP, 0x0);
/* Return (Buffer (One) { 0x1f }) */
acpigen_write_return_singleton_buffer(0x1f);
/* If (LEqual (Local2, 0x1)) */
acpigen_write_if_lequal_op_int(LOCAL2_OP, 0x1);
/* Return (Buffer (One) { 0x3 }) */
acpigen_write_return_singleton_buffer(0x3);
acpigen_pop_len(); /* Pop : If */
/* Else */
acpigen_write_else();
/* If (LEqual (Local2, 0x1)) */
acpigen_write_if_lequal_op_int(LOCAL2_OP, 0x1);
/* Return (Buffer (One) { 0x3f }) */
acpigen_write_return_singleton_buffer(0x3f);
acpigen_pop_len(); /* Pop : If */
/* Else */
acpigen_write_else();
/* Return (Buffer (One) { 0x0 }) */
acpigen_write_return_singleton_buffer(0x0);
acpigen_pop_len(); /* Pop : Else */
acpigen_pop_len(); /* Pop : Else */
}
static void i2c_hid_func1_cb(void *arg)

View File

@@ -71,7 +71,7 @@ static void add_device_ref(struct acpi_dp *dsd,
const char *path;
char *fresh;
if (!dev)
if (!dev || !dev->enabled)
return;
/*

View File

@@ -1019,33 +1019,72 @@ struct acpi_dp *acpi_dp_add_integer_array(struct acpi_dp *dp, const char *name,
return dp_array;
}
struct acpi_dp *acpi_dp_add_gpio_array(struct acpi_dp *dp, const char *name,
const struct acpi_gpio_res_params *params,
size_t param_count)
{
struct acpi_dp *gpio;
uint32_t i;
if (!dp || !param_count)
return NULL;
gpio = acpi_dp_new_table(name);
if (!gpio)
return NULL;
/*
* Generate ACPI identifiers as follows:
* Package () {
* name, // e.g. cs-gpios
* Package() {
* ref, index, pin, active_low, // GPIO-0 (params[0])
* ref, index, pin, active_low, // GPIO-1 (params[1])
* ...
* }
* }
*/
for (i = 0; i < param_count; i++, params++) {
/*
* If refs is NULL, leave a hole in the gpio array. This can be used in
* conditions where some controllers use both GPIOs and native signals.
*/
if (!params->ref) {
acpi_dp_add_integer(gpio, NULL, 0);
continue;
}
/* The device that has _CRS containing GpioIO()/GpioInt() */
acpi_dp_add_reference(gpio, NULL, params->ref);
/* Index of the GPIO resource in _CRS starting from zero */
acpi_dp_add_integer(gpio, NULL, params->index);
/* Pin in the GPIO resource, typically zero */
acpi_dp_add_integer(gpio, NULL, params->pin);
/* Set if pin is active low */
acpi_dp_add_integer(gpio, NULL, params->active_low);
}
acpi_dp_add_array(dp, gpio);
return gpio;
}
struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name,
const char *ref, int index, int pin,
int active_low)
{
if (!dp)
return NULL;
struct acpi_gpio_res_params param = {
.ref = ref,
.index = index,
.pin = pin,
.active_low = active_low,
};
struct acpi_dp *gpio = acpi_dp_new_table(name);
if (!gpio)
return NULL;
/* The device that has _CRS containing GpioIO()/GpioInt() */
acpi_dp_add_reference(gpio, NULL, ref);
/* Index of the GPIO resource in _CRS starting from zero */
acpi_dp_add_integer(gpio, NULL, index);
/* Pin in the GPIO resource, typically zero */
acpi_dp_add_integer(gpio, NULL, pin);
/* Set if pin is active low */
acpi_dp_add_integer(gpio, NULL, active_low);
acpi_dp_add_array(dp, gpio);
return gpio;
return acpi_dp_add_gpio_array(dp, name, &param, 1);
}
/*

View File

@@ -31,6 +31,7 @@ bootblock-y += id.S
$(call src-to-obj,decompressor,$(dir)/id.S): $(obj)/build.h
$(call src-to-obj,bootblock,$(dir)/id.S): $(obj)/build.h
decompressor-$(CONFIG_ARM64_USE_ARCH_TIMER) += arch_timer.c
bootblock-$(CONFIG_ARM64_USE_ARCH_TIMER) += arch_timer.c
bootblock-y += transition.c transition_asm.S

View File

@@ -478,6 +478,51 @@ unsigned int __weak smbios_processor_family(struct cpuid_result res)
return (res.eax > 0) ? 0x0c : 0x6;
}
unsigned int __weak smbios_cache_error_correction_type(u8 level)
{
return SMBIOS_CACHE_ERROR_CORRECTION_UNKNOWN;
}
unsigned int __weak smbios_cache_sram_type(void)
{
return SMBIOS_CACHE_SRAM_TYPE_UNKNOWN;
}
unsigned int __weak smbios_cache_conf_operation_mode(u8 level)
{
return SMBIOS_CACHE_OP_MODE_UNKNOWN; /* Unknown */
}
static size_t get_number_of_caches(struct cpuid_result res_deterministic_cache)
{
size_t max_logical_cpus_sharing_cache = 0;
size_t number_of_cpus_per_package = 0;
size_t max_logical_cpus_per_package = 0;
struct cpuid_result res;
if (!cpu_have_cpuid())
return 1;
res = cpuid(1);
max_logical_cpus_per_package = (res.ebx >> 16) & 0xff;
max_logical_cpus_sharing_cache = ((res_deterministic_cache.eax >> 14) & 0xfff) + 1;
/* Check if it's last level cache */
if (max_logical_cpus_sharing_cache == max_logical_cpus_per_package)
return 1;
if (cpuid_get_max_func() >= 0xb) {
res = cpuid_ext(0xb, 1);
number_of_cpus_per_package = res.ebx & 0xff;
} else {
number_of_cpus_per_package = max_logical_cpus_per_package;
}
return number_of_cpus_per_package / max_logical_cpus_sharing_cache;
}
static int smbios_write_type1(unsigned long *current, int handle)
{
struct smbios_type1 *t = (struct smbios_type1 *)*current;
@@ -662,7 +707,6 @@ static int smbios_write_type7(unsigned long *current,
{
struct smbios_type7 *t = (struct smbios_type7 *)*current;
int len = sizeof(struct smbios_type7);
static unsigned int cnt = 0;
char buf[8];
memset(t, 0, sizeof(struct smbios_type7));
@@ -670,13 +714,13 @@ static int smbios_write_type7(unsigned long *current,
t->handle = handle;
t->length = len - 2;
snprintf(buf, sizeof(buf), "CACHE%x", cnt++);
snprintf(buf, sizeof(buf), "CACHE%x", level);
t->socket_designation = smbios_add_string(t->eos, buf);
t->cache_configuration = SMBIOS_CACHE_CONF_LEVEL(level) |
SMBIOS_CACHE_CONF_LOCATION(0) | /* Internal */
SMBIOS_CACHE_CONF_ENABLED(1) | /* Enabled */
SMBIOS_CACHE_CONF_OPERATION_MODE(3); /* Unknown */
SMBIOS_CACHE_CONF_OPERATION_MODE(smbios_cache_conf_operation_mode(level));
if (max_cache_size < (SMBIOS_CACHE_SIZE_MASK * KiB)) {
t->max_cache_size = max_cache_size / KiB;
@@ -716,7 +760,7 @@ static int smbios_write_type7(unsigned long *current,
t->supported_sram_type = sram_type;
t->current_sram_type = sram_type;
t->cache_speed = 0; /* Unknown */
t->error_correction_type = SMBIOS_CACHE_ERROR_CORRECTION_UNKNOWN;
t->error_correction_type = smbios_cache_error_correction_type(level);
t->system_cache_type = type;
len = t->length + smbios_string_table_len(t->eos);
@@ -811,7 +855,8 @@ static int smbios_write_type7_cache_parameters(unsigned long *current,
const size_t partitions = CPUID_CACHE_PHYS_LINE(res) + 1;
const size_t cache_line_size = CPUID_CACHE_COHER_LINE(res) + 1;
const size_t number_of_sets = CPUID_CACHE_NO_OF_SETS(res) + 1;
const size_t cache_size = assoc * partitions * cache_line_size * number_of_sets;
const size_t cache_size = assoc * partitions * cache_line_size * number_of_sets
* get_number_of_caches(res);
if (!cache_type)
/* No more caches in the system */
@@ -840,7 +885,7 @@ static int smbios_write_type7_cache_parameters(unsigned long *current,
const int h = (*handle)++;
update_max(len, *max_struct_size, smbios_write_type7(current, h,
level, SMBIOS_CACHE_SRAM_TYPE_UNKNOWN, associativity,
level, smbios_cache_sram_type(), associativity,
type, cache_size, cache_size));
if (type4) {

View File

@@ -68,6 +68,7 @@
#define CBMEM_ID_ROM3 0x524f4d33
#define CBMEM_ID_FMAP 0x464d4150
#define CBMEM_ID_FSP_LOGO 0x4c4f474f
#define CBMEM_ID_SMM_COMBUFFER 0x53534d32
#define CBMEM_ID_TO_NAME_TABLE \
{ CBMEM_ID_ACPI, "ACPI " }, \

View File

@@ -80,6 +80,7 @@ enum {
LB_TAG_TCPA_LOG = 0x0036,
LB_TAG_FMAP = 0x0037,
LB_TAG_PLATFORM_BLOB_VERSION = 0x0038,
LB_TAG_SMMSTOREV2 = 0x0039,
LB_TAG_CMOS_OPTION_TABLE = 0x00c8,
LB_TAG_OPTION = 0x00c9,
LB_TAG_OPTION_ENUM = 0x00ca,
@@ -484,4 +485,20 @@ struct cmos_checksum {
#define CHECKSUM_PCBIOS 1
};
/* SMMSTOREv2 record
* This record contains information to use SMMSTOREv2.
*/
struct lb_smmstorev2 {
uint32_t tag;
uint32_t size;
uint32_t num_blocks; /* Number of writeable blocks in SMM */
uint32_t block_size; /* Size of a block in byte. Default: 64 KiB */
uint32_t mmap_addr; /* MMIO address of the store for read only access */
uint32_t com_buffer; /* Physical address of the communication buffer */
uint32_t com_buffer_size; /* Size of the communication buffer in bytes */
uint8_t apm_cmd; /* The command byte to write to the APM I/O port */
uint8_t unused[3]; /* Set to zero */
};
#endif

View File

@@ -8,40 +8,25 @@
#include <option.h>
#include <version.h>
/* Mutable console log level only allowed when RAM comes online. */
#define CONSOLE_LEVEL_CONST !ENV_STAGE_HAS_DATA_SECTION
#define FIRST_CONSOLE (ENV_BOOTBLOCK || (CONFIG(NO_BOOTBLOCK_CONSOLE) && ENV_ROMSTAGE))
static int console_inited;
static int console_loglevel = CONFIG_DEFAULT_CONSOLE_LOGLEVEL;
static int console_loglevel;
static inline int get_log_level(void)
{
if (console_inited == 0)
return -1;
if (CONSOLE_LEVEL_CONST)
return get_console_loglevel();
return console_loglevel;
}
static inline void set_log_level(int new_level)
{
if (CONSOLE_LEVEL_CONST)
return;
console_loglevel = new_level;
}
static void init_log_level(void)
{
int debug_level = get_console_loglevel();
console_loglevel = get_console_loglevel();
if (CONSOLE_LEVEL_CONST)
return;
get_option(&debug_level, "debug_level");
set_log_level(debug_level);
if (!FIRST_CONSOLE)
get_option(&console_loglevel, "debug_level");
}
int console_log_level(int msg_level)

View File

@@ -19,10 +19,15 @@ config SET_IA32_FC_LOCK_BIT
However, leaving the lock bit unset will break Windows' detection of
VMX support and built-in virtualization features like Hyper-V.
config CPU_INTEL_COMMON_TIMEBASE
bool
config SET_MSR_AESNI_LOCK_BIT
bool "Lock the AES-NI enablement state"
default y
help
This config sets the AES-NI lock bit, if available, to prevent any
further change of AES-NI enablement. This may be disabled for e.g.
testing or debugging.
config CPU_INTEL_COMMON_HYPERTHREADING
config CPU_INTEL_COMMON_TIMEBASE
bool
endif

View File

@@ -1,5 +1,5 @@
ramstage-$(CONFIG_CPU_INTEL_COMMON) += common_init.c
ramstage-$(CONFIG_CPU_INTEL_COMMON_HYPERTHREADING) += hyperthreading.c
ramstage-$(CONFIG_CPU_INTEL_COMMON) += hyperthreading.c
ifeq ($(CONFIG_CPU_INTEL_COMMON_TIMEBASE),y)
bootblock-y += fsb.c

View File

@@ -27,4 +27,22 @@ bool intel_ht_supported(void);
*/
bool intel_ht_sibling(void);
/*
* Lock AES-NI feature (MSR_FEATURE_CONFIG) to prevent unintended changes
* to the enablement state as suggested in Intel document 325384-070US.
*/
void set_aesni_lock(void);
/* Enable local CPU APIC TPR (Task Priority Register) updates */
void enable_lapic_tpr(void);
/* Enable DCA (Direct Cache Access) */
void configure_dca_cap(void);
/*
* Set EPB (Energy Performance Bias)
* Possible values are 0 (performance) to 15 (powersave).
*/
void set_energy_perf_bias(u8 policy);
#endif

View File

@@ -3,9 +3,13 @@
#include <acpi/acpigen.h>
#include <arch/cpu.h>
#include <console/console.h>
#include <cpu/intel/msr.h>
#include <cpu/x86/lapic.h>
#include <cpu/x86/msr.h>
#include "common.h"
#define CPUID_6_ECX_EPB (1 << 3)
void set_vmx_and_lock(void)
{
set_feature_ctrl_vmx();
@@ -235,11 +239,23 @@ void cpu_init_cppc_config(struct cppc_config *config, u32 version)
if (version >= 2) {
/* Autonomous Selection Enable is populated below */
/* Autonomous Activity Window Register */
config->regs[CPPC_AUTO_ACTIVITY_WINDOW] = unsupported;
msr.addrl = IA32_HWP_REQUEST;
/* Energy Performance Preference Register */
config->regs[CPPC_PERF_PREF] = unsupported;
/*
* Autonomous Activity Window Register
* ResourceTemplate(){Register(FFixedHW, 0x0a, 0x20, 0x774, 0x04,)},
*/
msr.bit_width = 10;
msr.bit_offset = 32;
config->regs[CPPC_AUTO_ACTIVITY_WINDOW] = msr;
/*
* Autonomous Energy Performance Preference Register
* ResourceTemplate(){Register(FFixedHW, 0x08, 0x18, 0x774, 0x04,)},
*/
msr.bit_width = 8;
msr.bit_offset = 24;
config->regs[CPPC_PERF_PREF] = msr;
/* Reference Performance */
config->regs[CPPC_REF_PERF] = unsupported;
@@ -264,3 +280,46 @@ void cpu_init_cppc_config(struct cppc_config *config, u32 version)
config->regs[CPPC_AUTO_SELECT] = msr;
}
}
void set_aesni_lock(void)
{
msr_t msr;
if (!CONFIG(SET_MSR_AESNI_LOCK_BIT))
return;
if (!(cpu_get_feature_flags_ecx() & CPUID_AES))
return;
/* Only run once per core as specified in the MSR datasheet */
if (intel_ht_sibling())
return;
msr = rdmsr(MSR_FEATURE_CONFIG);
if (msr.lo & AESNI_LOCK)
return;
msr_set(MSR_FEATURE_CONFIG, AESNI_LOCK);
}
void enable_lapic_tpr(void)
{
msr_unset(MSR_PIC_MSG_CONTROL, TPR_UPDATES_DISABLE);
}
void configure_dca_cap(void)
{
if (cpu_get_feature_flags_ecx() & CPUID_DCA)
msr_set(IA32_PLATFORM_DCA_CAP, DCA_TYPE0_EN);
}
void set_energy_perf_bias(u8 policy)
{
u8 epb = policy & ENERGY_POLICY_MASK;
if (!(cpuid_ecx(6) & CPUID_6_ECX_EPB))
return;
msr_unset_and_set(IA32_ENERGY_PERF_BIAS, ENERGY_POLICY_MASK, epb);
printk(BIOS_DEBUG, "cpu: energy policy set to %u\n", epb);
}

View File

@@ -65,50 +65,6 @@ static void generate_cstate_entries(acpi_cstate_t *cstates,
acpigen_pop_len();
}
static void generate_C_state_entries(void)
{
struct cpu_info *info;
struct cpu_driver *cpu;
struct device *lapic;
struct cpu_intel_haswell_config *conf = NULL;
/* Find the SpeedStep CPU in the device tree using magic APIC ID */
lapic = dev_find_lapic(SPEEDSTEP_APIC_MAGIC);
if (!lapic)
return;
conf = lapic->chip_info;
if (!conf)
return;
/* Find CPU map of supported C-states */
info = cpu_info();
if (!info)
return;
cpu = find_cpu_driver(info->cpu);
if (!cpu || !cpu->cstates)
return;
acpigen_emit_byte(0x14); /* MethodOp */
acpigen_write_len_f(); /* PkgLength */
acpigen_emit_namestring("_CST");
acpigen_emit_byte(0x00); /* No Arguments */
/* If running on AC power */
acpigen_emit_byte(0xa0); /* IfOp */
acpigen_write_len_f(); /* PkgLength */
acpigen_emit_namestring("PWRS");
acpigen_emit_byte(0xa4); /* ReturnOp */
generate_cstate_entries(cpu->cstates, conf->c1_acpower,
conf->c2_acpower, conf->c3_acpower);
acpigen_pop_len();
/* Else on battery power */
acpigen_emit_byte(0xa4); /* ReturnOp */
generate_cstate_entries(cpu->cstates, conf->c1_battery,
conf->c2_battery, conf->c3_battery);
acpigen_pop_len();
}
static acpi_tstate_t tss_table_fine[] = {
{ 100, 1000, 0, 0x00, 0 },
{ 94, 940, 0, 0x1f, 0 },
@@ -161,6 +117,50 @@ static void generate_T_state_entries(int core, int cores_per_package)
ARRAY_SIZE(tss_table_coarse), tss_table_coarse);
}
static void generate_C_state_entries(void)
{
struct cpu_info *info;
struct cpu_driver *cpu;
struct device *lapic;
struct cpu_intel_haswell_config *conf = NULL;
/* Find the SpeedStep CPU in the device tree using magic APIC ID */
lapic = dev_find_lapic(SPEEDSTEP_APIC_MAGIC);
if (!lapic)
return;
conf = lapic->chip_info;
if (!conf)
return;
/* Find CPU map of supported C-states */
info = cpu_info();
if (!info)
return;
cpu = find_cpu_driver(info->cpu);
if (!cpu || !cpu->cstates)
return;
acpigen_emit_byte(0x14); /* MethodOp */
acpigen_write_len_f(); /* PkgLength */
acpigen_emit_namestring("_CST");
acpigen_emit_byte(0x00); /* No Arguments */
/* If running on AC power */
acpigen_emit_byte(0xa0); /* IfOp */
acpigen_write_len_f(); /* PkgLength */
acpigen_emit_namestring("PWRS");
acpigen_emit_byte(0xa4); /* ReturnOp */
generate_cstate_entries(cpu->cstates, conf->c1_acpower,
conf->c2_acpower, conf->c3_acpower);
acpigen_pop_len();
/* Else on battery power */
acpigen_emit_byte(0xa4); /* ReturnOp */
generate_cstate_entries(cpu->cstates, conf->c1_battery,
conf->c2_battery, conf->c3_battery);
acpigen_pop_len();
}
static int calculate_power(int tdp, int p1_ratio, int ratio)
{
u32 m;
@@ -307,19 +307,19 @@ void generate_cpu_entries(const struct device *device)
/* Generate processor \_SB.CPUx */
acpigen_write_processor(
(cpuID-1)*cores_per_package+coreID-1,
(cpuID - 1) * cores_per_package+coreID - 1,
pcontrol_blk, plen);
/* Generate P-state tables */
generate_P_state_entries(
coreID-1, cores_per_package);
coreID - 1, cores_per_package);
/* Generate C-state tables */
generate_C_state_entries();
/* Generate T-state tables */
generate_T_state_entries(
cpuID-1, cores_per_package);
cpuID - 1, cores_per_package);
acpigen_pop_len();
}

View File

@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <types.h>
#include <arch/cpu.h>
#include <cpu/x86/msr.h>
#include "haswell.h"
@@ -7,5 +8,5 @@
void intel_cpu_haswell_finalize_smm(void)
{
/* Lock memory configuration to protect SMM */
msr_set_bit(MSR_LT_LOCK_MEMORY, 0);
msr_set(MSR_LT_LOCK_MEMORY, BIT(0));
}

View File

@@ -28,7 +28,6 @@
#define MSR_TEMPERATURE_TARGET 0x1a2
#define MSR_LT_LOCK_MEMORY 0x2e7
#define MSR_PIC_MSG_CONTROL 0x2e
#define MSR_PLATFORM_INFO 0xce
#define PLATFORM_INFO_SET_TDP (1 << 29)
#define MSR_PKG_CST_CONFIG_CONTROL 0xe2

View File

@@ -207,8 +207,8 @@ int haswell_is_ult(void)
return ult;
}
/* The core 100MHz BLCK is disabled in deeper c-states. One needs to calibrate
* the 100MHz BCLCK against the 24MHz BLCK to restore the clocks properly
/* The core 100MHz BCLK is disabled in deeper c-states. One needs to calibrate
* the 100MHz BCLK against the 24MHz BCLK to restore the clocks properly
* when a core is woken up. */
static int pcode_ready(void)
{
@@ -247,7 +247,7 @@ static void calibrate_24mhz_bclk(void)
err_code = MCHBAR32(BIOS_MAILBOX_INTERFACE) & 0xff;
printk(BIOS_DEBUG, "PCODE: 24MHz BLCK calibration response: %d\n",
printk(BIOS_DEBUG, "PCODE: 24MHz BCLK calibration response: %d\n",
err_code);
/* Read the calibrated value. */
@@ -259,7 +259,7 @@ static void calibrate_24mhz_bclk(void)
return;
}
printk(BIOS_DEBUG, "PCODE: 24MHz BLCK calibration value: 0x%08x\n",
printk(BIOS_DEBUG, "PCODE: 24MHz BCLK calibration value: 0x%08x\n",
MCHBAR32(BIOS_MAILBOX_DATA));
}
@@ -577,29 +577,6 @@ static void configure_misc(void)
wrmsr(IA32_PACKAGE_THERM_INTERRUPT, msr);
}
static void enable_lapic_tpr(void)
{
msr_t msr;
msr = rdmsr(MSR_PIC_MSG_CONTROL);
msr.lo &= ~(1 << 10); /* Enable APIC TPR updates */
wrmsr(MSR_PIC_MSG_CONTROL, msr);
}
static void configure_dca_cap(void)
{
uint32_t feature_flag;
msr_t msr;
/* Check feature flag in CPUID.(EAX=1):ECX[18]==1 */
feature_flag = cpu_get_feature_flags_ecx();
if (feature_flag & CPUID_DCA) {
msr = rdmsr(IA32_PLATFORM_DCA_CAP);
msr.lo |= 1;
wrmsr(IA32_PLATFORM_DCA_CAP, msr);
}
}
static void set_max_ratio(void)
{
msr_t msr, perf_ctl;
@@ -622,25 +599,6 @@ static void set_max_ratio(void)
((perf_ctl.lo >> 8) & 0xff) * HASWELL_BCLK);
}
static void set_energy_perf_bias(u8 policy)
{
msr_t msr;
int ecx;
/* Determine if energy efficient policy is supported. */
ecx = cpuid_ecx(0x6);
if (!(ecx & (1 << 3)))
return;
/* Energy Policy is bits 3:0 */
msr = rdmsr(IA32_ENERGY_PERF_BIAS);
msr.lo &= ~0xf;
msr.lo |= policy & 0xf;
wrmsr(IA32_ENERGY_PERF_BIAS, msr);
printk(BIOS_DEBUG, "CPU: energy policy set to %u\n", policy);
}
static void configure_mca(void)
{
msr_t msr;

View File

@@ -156,7 +156,6 @@ static void fill_in_relocation_params(struct smm_relocation_params *params)
{
uintptr_t tseg_base;
size_t tseg_size;
u32 prmrr_base;
u32 prmrr_size;
int phys_bits;
@@ -197,7 +196,7 @@ static void fill_in_relocation_params(struct smm_relocation_params *params)
params->uncore_prmrr_base.lo = prmrr_base;
params->uncore_prmrr_base.hi = 0;
params->uncore_prmrr_mask.lo = (~(prmrr_size - 1) & rmask) |
MTRR_PHYS_MASK_VALID;
MTRR_PHYS_MASK_VALID;
params->uncore_prmrr_mask.hi = (1 << (39 - 32)) - 1;
}
@@ -282,6 +281,5 @@ void smm_lock(void)
* make the SMM registers writable again.
*/
printk(BIOS_DEBUG, "Locking SMM.\n");
pci_write_config8(pcidev_on_root(0, 0), SMRAM,
D_LCK | G_SMRAME | C_BASE_SEG);
pci_write_config8(pcidev_on_root(0, 0), SMRAM, D_LCK | G_SMRAME | C_BASE_SEG);
}

View File

@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <types.h>
#include <arch/cpu.h>
#include <cpu/x86/msr.h>
#include <cpu/intel/speedstep.h>
@@ -13,12 +14,8 @@
void intel_model_2065x_finalize_smm(void)
{
/* Lock C-State MSR */
msr_set_bit(MSR_PKG_CST_CONFIG_CONTROL, 15);
/* Lock AES-NI only if supported */
if (cpuid_ecx(1) & (1 << 25))
msr_set_bit(MSR_FEATURE_CONFIG, 0);
msr_set(MSR_PKG_CST_CONFIG_CONTROL, BIT(15));
/* Lock TM interrupts - route thermal events to all processors */
msr_set_bit(MSR_MISC_PWR_MGMT, 22);
msr_set(MSR_MISC_PWR_MGMT, BIT(22));
}

View File

@@ -15,7 +15,6 @@
#define IA32_FERR_CAPABILITY 0x1f1
#define FERR_ENABLE (1 << 0)
#define MSR_PIC_MSG_CONTROL 0x2e
#define MSR_PLATFORM_INFO 0xce
#define PLATFORM_INFO_SET_TDP (1 << 29)

View File

@@ -148,15 +148,6 @@ static void configure_misc(void)
wrmsr(IA32_THERM_INTERRUPT, msr);
}
static void enable_lapic_tpr(void)
{
msr_t msr;
msr = rdmsr(MSR_PIC_MSG_CONTROL);
msr.lo &= ~(1 << 10); /* Enable APIC TPR updates */
wrmsr(MSR_PIC_MSG_CONTROL, msr);
}
static void set_max_ratio(void)
{
msr_t msr, perf_ctl;
@@ -216,6 +207,8 @@ static void model_2065x_init(struct device *cpu)
/* Set virtualization based on Kconfig option */
set_vmx_and_lock();
set_aesni_lock();
/* Configure Enhanced SpeedStep and Thermal Sensors */
configure_misc();

View File

@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <types.h>
#include <arch/cpu.h>
#include <cpu/x86/msr.h>
#include "model_206ax.h"
@@ -11,13 +12,9 @@
void intel_model_206ax_finalize_smm(void)
{
/* Lock AES-NI only if supported */
if (cpuid_ecx(1) & (1 << 25))
msr_set_bit(MSR_FEATURE_CONFIG, 0);
/* Lock TM interrupts - route thermal events to all processors */
msr_set_bit(MSR_MISC_PWR_MGMT, 22);
msr_set(MSR_MISC_PWR_MGMT, BIT(22));
/* Lock memory configuration to protect SMM */
msr_set_bit(MSR_LT_LOCK_MEMORY, 0);
msr_set(MSR_LT_LOCK_MEMORY, BIT(0));
}

View File

@@ -15,7 +15,6 @@
#define FLEX_RATIO_EN (1 << 16)
#define MSR_TEMPERATURE_TARGET 0x1a2
#define MSR_LT_LOCK_MEMORY 0x2e7
#define MSR_PIC_MSG_CONTROL 0x2e
#define MSR_PLATFORM_INFO 0xce
#define PLATFORM_INFO_SET_TDP (1 << 29)

View File

@@ -338,29 +338,6 @@ static void configure_misc(void)
wrmsr(IA32_PACKAGE_THERM_INTERRUPT, msr);
}
static void enable_lapic_tpr(void)
{
msr_t msr;
msr = rdmsr(MSR_PIC_MSG_CONTROL);
msr.lo &= ~(1 << 10); /* Enable APIC TPR updates */
wrmsr(MSR_PIC_MSG_CONTROL, msr);
}
static void configure_dca_cap(void)
{
uint32_t feature_flag;
msr_t msr;
/* Check feature flag in CPUID.(EAX=1):ECX[18]==1 */
feature_flag = cpu_get_feature_flags_ecx();
if (feature_flag & CPUID_DCA) {
msr = rdmsr(IA32_PLATFORM_DCA_CAP);
msr.lo |= 1;
wrmsr(IA32_PLATFORM_DCA_CAP, msr);
}
}
static void set_max_ratio(void)
{
msr_t msr, perf_ctl;
@@ -383,20 +360,6 @@ static void set_max_ratio(void)
((perf_ctl.lo >> 8) & 0xff) * SANDYBRIDGE_BCLK);
}
static void set_energy_perf_bias(u8 policy)
{
msr_t msr;
/* Energy Policy is bits 3:0 */
msr = rdmsr(IA32_ENERGY_PERF_BIAS);
msr.lo &= ~0xf;
msr.lo |= policy & 0xf;
wrmsr(IA32_ENERGY_PERF_BIAS, msr);
printk(BIOS_DEBUG, "model_x06ax: energy policy set to %u\n",
policy);
}
static void configure_mca(void)
{
msr_t msr;
@@ -470,6 +433,8 @@ static void model_206ax_init(struct device *cpu)
/* Thermal throttle activation offset */
configure_thermal_target();
set_aesni_lock();
/* Enable Direct Cache Access */
configure_dca_cap();

View File

@@ -4,4 +4,3 @@ config CPU_INTEL_MODEL_F2X
select SUPPORT_CPU_UCODE_IN_CBFS
select SMM_ASEG
select CPU_INTEL_COMMON
select CPU_INTEL_COMMON_HYPERTHREADING

View File

@@ -3,4 +3,3 @@ config CPU_INTEL_MODEL_F3X
select ARCH_ALL_STAGES_X86_32
select SUPPORT_CPU_UCODE_IN_CBFS
select CPU_INTEL_COMMON
select CPU_INTEL_COMMON_HYPERTHREADING

View File

@@ -104,9 +104,7 @@ static void enable_var_mtrr(unsigned char deftype)
#define MTRR_VERBOSE_LEVEL BIOS_NEVER
/* MTRRs are at a 4KiB granularity. Therefore all address calculations can
* be done with 32-bit numbers. This allows for the MTRR code to handle
* up to 2^44 bytes (16 TiB) of address space. */
/* MTRRs are at a 4KiB granularity. */
#define RANGE_SHIFT 12
#define ADDR_SHIFT_TO_RANGE_SHIFT(x) \
(((x) > RANGE_SHIFT) ? ((x) - RANGE_SHIFT) : RANGE_SHIFT)
@@ -115,18 +113,18 @@ static void enable_var_mtrr(unsigned char deftype)
#define NUM_FIXED_MTRRS (NUM_FIXED_RANGES / RANGES_PER_FIXED_MTRR)
/* Helpful constants. */
#define RANGE_1MB PHYS_TO_RANGE_ADDR(1 << 20)
#define RANGE_4GB (1 << (ADDR_SHIFT_TO_RANGE_SHIFT(32)))
#define RANGE_1MB PHYS_TO_RANGE_ADDR(1ULL << 20)
#define RANGE_4GB (1ULL << (ADDR_SHIFT_TO_RANGE_SHIFT(32)))
#define MTRR_ALGO_SHIFT (8)
#define MTRR_TAG_MASK ((1 << MTRR_ALGO_SHIFT) - 1)
static inline uint32_t range_entry_base_mtrr_addr(struct range_entry *r)
static inline uint64_t range_entry_base_mtrr_addr(struct range_entry *r)
{
return PHYS_TO_RANGE_ADDR(range_entry_base(r));
}
static inline uint32_t range_entry_end_mtrr_addr(struct range_entry *r)
static inline uint64_t range_entry_end_mtrr_addr(struct range_entry *r)
{
return PHYS_TO_RANGE_ADDR(range_entry_end(r));
}
@@ -402,7 +400,7 @@ static void clear_var_mtrr(int index)
}
static void prep_var_mtrr(struct var_mtrr_state *var_state,
uint32_t base, uint32_t size, int mtrr_type)
uint64_t base, uint64_t size, int mtrr_type)
{
struct var_mtrr_regs *regs;
resource_t rbase;
@@ -444,24 +442,51 @@ static void prep_var_mtrr(struct var_mtrr_state *var_state,
regs->mask.hi = rsize >> 32;
}
/*
* fls64: find least significant bit set in a 64-bit word
* As samples, fls64(0x0) = 64; fls64(0x4400) = 10;
* fls64(0x40400000000) = 34.
*/
static uint32_t fls64(uint64_t x)
{
uint32_t lo = (uint32_t)x;
if (lo)
return fls(lo);
uint32_t hi = x >> 32;
return fls(hi) + 32;
}
/*
* fms64: find most significant bit set in a 64-bit word
* As samples, fms64(0x0) = 0; fms64(0x4400) = 14;
* fms64(0x40400000000) = 42.
*/
static uint32_t fms64(uint64_t x)
{
uint32_t hi = (uint32_t)(x >> 32);
if (!hi)
return fms((uint32_t)x);
return fms(hi) + 32;
}
static void calc_var_mtrr_range(struct var_mtrr_state *var_state,
uint32_t base, uint32_t size, int mtrr_type)
uint64_t base, uint64_t size, int mtrr_type)
{
while (size != 0) {
uint32_t addr_lsb;
uint32_t size_msb;
uint32_t mtrr_size;
uint64_t mtrr_size;
addr_lsb = fls(base);
size_msb = fms(size);
addr_lsb = fls64(base);
size_msb = fms64(size);
/* All MTRR entries need to have their base aligned to the mask
* size. The maximum size is calculated by a function of the
* min base bit set and maximum size bit set. */
if (addr_lsb > size_msb)
mtrr_size = 1 << size_msb;
mtrr_size = 1ULL << size_msb;
else
mtrr_size = 1 << addr_lsb;
mtrr_size = 1ULL << addr_lsb;
if (var_state->prepare_msrs)
prep_var_mtrr(var_state, base, mtrr_size, mtrr_type);
@@ -472,8 +497,8 @@ static void calc_var_mtrr_range(struct var_mtrr_state *var_state,
}
}
static uint32_t optimize_var_mtrr_hole(const uint32_t base,
const uint32_t hole,
static uint64_t optimize_var_mtrr_hole(const uint64_t base,
const uint64_t hole,
const uint64_t limit,
const int carve_hole)
{
@@ -531,7 +556,7 @@ static uint32_t optimize_var_mtrr_hole(const uint32_t base,
static void calc_var_mtrrs_with_hole(struct var_mtrr_state *var_state,
struct range_entry *r)
{
uint32_t a1, a2, b1, b2;
uint64_t a1, a2, b1, b2;
int mtrr_type, carve_hole;
/*
@@ -671,6 +696,7 @@ static void __calc_var_mtrrs(struct memranges *addr_space,
wb_deftype_count += var_state.mtrr_index;
}
}
*num_def_wb_mtrrs = wb_deftype_count;
*num_def_uc_mtrrs = uc_deftype_count;
}

View File

@@ -520,7 +520,7 @@ config PCIEXP_PLUGIN_SUPPORT
default y
config PCI_ALLOW_BUS_MASTER
bool "Allow PCI bus master bit to be enabled by coreboot"
bool "Allow coreboot to set optional PCI bus master bits"
default y
help
For security reasons, bus mastering should be enabled as late as

View File

@@ -1006,16 +1006,11 @@ static struct device *pci_scan_get_dev(struct bus *bus, unsigned int devfn)
prev = &bus->children;
for (dev = bus->children; dev; dev = dev->sibling) {
if (dev->path.type == DEVICE_PATH_PCI) {
if (dev->path.pci.devfn == devfn) {
/* Unlink from the list. */
*prev = dev->sibling;
dev->sibling = NULL;
break;
}
} else {
printk(BIOS_ERR, "child %s not a PCI device\n",
dev_path(dev));
if (dev->path.type == DEVICE_PATH_PCI && dev->path.pci.devfn == devfn) {
/* Unlink from the list. */
*prev = dev->sibling;
dev->sibling = NULL;
break;
}
prev = &dev->sibling;
}
@@ -1283,6 +1278,16 @@ void pci_scan_bus(struct bus *bus, unsigned int min_devfn,
prev = &bus->children;
for (dev = bus->children; dev; dev = dev->sibling) {
/*
* If static device is not PCI then enable it here and don't
* treat it as a leftover device.
*/
if (dev->path.type != DEVICE_PATH_PCI) {
enable_static_device(dev);
continue;
}
/*
* The device is only considered leftover if it is not hidden
* and it has a Vendor ID of 0 (the default for a device that

View File

@@ -180,6 +180,8 @@ static void pciexp_enable_ltr(struct device *dev)
for (bus = dev->link_list ; bus ; bus = bus->next) {
for (child = bus->children; child; child = child->sibling) {
if (child->path.type != DEVICE_PATH_PCI)
continue;
pciexp_configure_ltr(child);
if (child->ops && child->ops->scan_bus)
pciexp_enable_ltr(child);
@@ -478,6 +480,8 @@ void pciexp_scan_bus(struct bus *bus, unsigned int min_devfn,
pci_scan_bus(bus, min_devfn, max_devfn);
for (child = bus->children; child; child = child->sibling) {
if (child->path.type != DEVICE_PATH_PCI)
continue;
if ((child->path.pci.devfn < min_devfn) ||
(child->path.pci.devfn > max_devfn)) {
continue;

View File

@@ -7,6 +7,18 @@
const char mainboard_name[] = CONFIG_MAINBOARD_VENDOR " " CONFIG_MAINBOARD_PART_NUMBER;
void enable_static_device(struct device *dev)
{
if (dev->chip_ops && dev->chip_ops->enable_dev)
dev->chip_ops->enable_dev(dev);
if (dev->ops && dev->ops->enable)
dev->ops->enable(dev);
printk(BIOS_DEBUG, "%s %s\n", dev_path(dev),
dev->enabled ? "enabled" : "disabled");
}
/**
* Enable devices on static buses.
*
@@ -32,15 +44,7 @@ void enable_static_devices(struct device *bus)
for (link = bus->link_list; link; link = link->next) {
for (child = link->children; child; child = child->sibling) {
if (child->chip_ops && child->chip_ops->enable_dev)
child->chip_ops->enable_dev(child);
if (child->ops && child->ops->enable)
child->ops->enable(child);
printk(BIOS_DEBUG, "%s %s\n", dev_path(child),
child->enabled ? "enabled" : "disabled");
enable_static_device(child);
}
}
}
@@ -58,18 +62,9 @@ void scan_generic_bus(struct device *bus)
link->secondary = ++bus_max;
for (child = link->children; child; child = child->sibling) {
if (child->chip_ops && child->chip_ops->enable_dev)
child->chip_ops->enable_dev(child);
if (child->ops && child->ops->enable)
child->ops->enable(child);
enable_static_device(child);
printk(BIOS_DEBUG, "bus: %s[%d]->", dev_path(child->bus->dev),
child->bus->link_num);
printk(BIOS_DEBUG, "%s %s\n", dev_path(child),
child->enabled ? "enabled" : "disabled");
}
}

View File

@@ -0,0 +1,7 @@
config CHROMEOS_CAMERA
bool
default n
help
Camera with identifiers following Chrome OS Camera Info. The info is
usually available on MIPI camera EEPROM for identifying correct
drivers and config.

View File

@@ -0,0 +1 @@
ramstage-$(CONFIG_CHROMEOS_CAMERA) += cros_camera.c

View File

@@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <console/console.h>
#include <crc_byte.h>
#include <string.h>
#include "cros_camera.h"
int check_cros_camera_info(const struct cros_camera_info *info)
{
if (memcmp(info->magic, CROS_CAMERA_INFO_MAGIC, sizeof(info->magic))) {
printk(BIOS_ERR, "Invalid magic in camera info\n");
return -1;
}
const uint8_t *ptr = (void *)(&info->crc16 + 1);
uint16_t crc16 = 0;
while (ptr < (uint8_t *)info + sizeof(struct cros_camera_info))
crc16 = crc16_byte(crc16, *ptr++);
if (info->crc16 != crc16) {
printk(BIOS_ERR, "Incorrect CRC16: expected %#06x, got %#06x\n",
crc16, info->crc16);
return -1;
}
if (info->version != CROS_CAMERA_INFO_VERSION) {
printk(BIOS_ERR, "Unknown camera info version: %u\n",
info->version);
return -1;
}
if (info->size < CROS_CAMERA_INFO_SIZE_MIN) {
printk(BIOS_ERR, "Size of camera info is too small: %u\n",
info->size);
return -1;
}
return 0;
}

View File

@@ -0,0 +1,27 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __VENDORCODE_GOOGLE_CHROMEOS_CAMERA_H
#define __VENDORCODE_GOOGLE_CHROMEOS_CAMERA_H
#include <stdint.h>
#define CROS_CAMERA_INFO_MAGIC "CrOS"
#define CROS_CAMERA_INFO_VERSION 1
#define CROS_CAMERA_INFO_SIZE_MIN 0x0a
struct cros_camera_info {
uint8_t magic[4]; /* CROS_CAMERA_INFO_MAGIC */
uint16_t crc16;
uint8_t version;
uint8_t size;
uint16_t data_format;
uint16_t module_pid;
uint8_t module_vid[2];
uint8_t sensor_vid[2];
uint16_t sensor_pid;
};
/* Returns 0 on success, non-zero on errors. */
int check_cros_camera_info(const struct cros_camera_info *info);
#endif

View File

@@ -0,0 +1,6 @@
config DRIVERS_I2C_GPIO_MUX
bool
default n
depends on HAVE_ACPI_TABLES
help
When enabled, add identifiers in ACPI tables for GPIO based I2C multiplexer.

View File

@@ -0,0 +1,2 @@
subdirs-$(CONFIG_DRIVERS_I2C_GPIO_MUX) += mux
subdirs-$(CONFIG_DRIVERS_I2C_GPIO_MUX) += bus

View File

@@ -0,0 +1 @@
ramstage-$(CONFIG_DRIVERS_I2C_GPIO_MUX) += bus.c

View File

@@ -0,0 +1,60 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <acpi/acpi_device.h>
#include <acpi/acpigen.h>
#include <console/console.h>
#include <device/device.h>
#include <device/path.h>
#include <stdlib.h>
#include <string.h>
#include "chip.h"
static const char *i2c_gpiomux_bus_acpi_name(const struct device *dev)
{
static char name[ACPI_NAME_BUFFER_SIZE];
snprintf(name, ACPI_NAME_BUFFER_SIZE, "MXA%01.1X", dev->path.generic.id);
return name;
}
static void i2c_gpiomux_bus_fill_ssdt(const struct device *dev)
{
const char *scope = acpi_device_scope(dev);
const char *path = acpi_device_path(dev);
if (!dev || !dev->enabled || !scope || !path)
return;
/* Device */
acpigen_write_scope(scope);
acpigen_write_device(acpi_device_name(dev));
acpigen_write_STA(acpi_device_status(dev));
acpigen_write_ADR(dev->path.generic.id);
acpigen_pop_len(); /* Device */
acpigen_pop_len(); /* Scope */
printk(BIOS_INFO, "%s: %s at %s\n", path, dev->chip_ops->name, dev_path(dev));
}
static struct device_operations i2c_gpiomux_bus_ops = {
.read_resources = noop_read_resources,
.set_resources = noop_set_resources,
.scan_bus = scan_static_bus,
.acpi_name = i2c_gpiomux_bus_acpi_name,
.acpi_fill_ssdt = i2c_gpiomux_bus_fill_ssdt,
};
static void i2c_gpiomux_bus_enable(struct device *dev)
{
if (!dev)
return;
dev->ops = &i2c_gpiomux_bus_ops;
}
struct chip_operations drivers_i2c_gpiomux_bus_ops = {
CHIP_NAME("I2C GPIO MUX Bus Device")
.enable_dev = i2c_gpiomux_bus_enable
};

View File

@@ -0,0 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __I2C_GPIOMUX_BUS_CHIP_H__
#define __I2C_GPIOMUX_BUS_CHIP_H__
struct drivers_i2c_gpiomux_bus_config {
};
#endif /* __I2C_GPIOMUX_BUS_CHIP_H__ */

View File

@@ -0,0 +1 @@
ramstage-$(CONFIG_DRIVERS_I2C_GPIO_MUX) += mux.c

View File

@@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __I2C_GPIOMUX_MUX_CHIP_H__
#define __I2C_GPIOMUX_MUX_CHIP_H__
#include <acpi/acpi_device.h>
#include <types.h>
#define MAX_NUM_MUX_GPIOS 4
struct drivers_i2c_gpiomux_mux_config {
/* GPIOs used to select the mux lines */
uint32_t mux_gpio_count;
struct acpi_gpio mux_gpio[MAX_NUM_MUX_GPIOS];
};
#endif /* __I2C_GPIOMUX_MUX_CHIP_H__ */

View File

@@ -0,0 +1,82 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <acpi/acpi_device.h>
#include <acpi/acpigen.h>
#include <console/console.h>
#include <device/device.h>
#include <device/path.h>
#include <stdlib.h>
#include <string.h>
#include "chip.h"
static const char *i2c_gpiomux_mux_acpi_name(const struct device *dev)
{
static char name[ACPI_NAME_BUFFER_SIZE];
snprintf(name, ACPI_NAME_BUFFER_SIZE, "MUX%01.1X", dev->path.generic.id);
return name;
}
static void i2c_gpiomux_mux_fill_ssdt(const struct device *dev)
{
const char *scope = acpi_device_scope(dev);
const char *path = acpi_device_path(dev);
struct drivers_i2c_gpiomux_mux_config *config = config_of(dev);
struct acpi_dp *dsd = NULL;
const char *compat_string = "i2c-mux-gpio";
struct acpi_gpio_res_params param[MAX_NUM_MUX_GPIOS];
int i;
if (!dev->enabled || !scope || !path)
return;
/* Device */
acpigen_write_scope(scope);
acpigen_write_device(acpi_device_name(dev));
acpigen_write_name_string("_HID", ACPI_DT_NAMESPACE_HID);
acpigen_write_STA(acpi_device_status(dev));
/* Resources */
acpigen_write_name("_CRS");
acpigen_write_resourcetemplate_header();
for (i = 0; i < config->mux_gpio_count; i++) {
acpi_device_write_gpio(&config->mux_gpio[i]);
param[i].ref = path;
param[i].index = i;
param[i].pin = 0;
param[i].active_low = config->mux_gpio[i].active_low;
}
acpigen_write_resourcetemplate_footer();
/* DSD */
dsd = acpi_dp_new_table("_DSD");
acpi_dp_add_string(dsd, "compatible", compat_string);
acpi_dp_add_gpio_array(dsd, "mux-gpios", param, config->mux_gpio_count);
acpi_dp_write(dsd);
acpigen_pop_len(); /* Device */
acpigen_pop_len(); /* Scope */
printk(BIOS_INFO, "%s: %s at %s\n", path, dev->chip_ops->name, dev_path(dev));
}
static struct device_operations i2c_gpiomux_mux_ops = {
.read_resources = noop_read_resources,
.set_resources = noop_set_resources,
.scan_bus = scan_static_bus,
.acpi_name = i2c_gpiomux_mux_acpi_name,
.acpi_fill_ssdt = i2c_gpiomux_mux_fill_ssdt,
};
static void i2c_gpiomux_mux_enable(struct device *dev)
{
if (!dev)
return;
dev->ops = &i2c_gpiomux_mux_ops;
}
struct chip_operations drivers_i2c_gpiomux_mux_ops = {
CHIP_NAME("I2C GPIO MUX Device")
.enable_dev = i2c_gpiomux_mux_enable
};

View File

@@ -141,23 +141,6 @@ config FSP_TEMP_RAM_SIZE
own stack that will be placed in DRAM and not in CAR, this is the
amount of memory the FSP needs for its stack and heap.
config FSP2_0_USES_TPM_MRC_HASH
bool
depends on TPM1 || TPM2
depends on VBOOT && VBOOT_STARTS_IN_BOOTBLOCK
default y if HAS_RECOVERY_MRC_CACHE
default n
select VBOOT_HAS_REC_HASH_SPACE
help
Store hash of trained recovery MRC cache in NVRAM space in TPM.
Use the hash to validate recovery MRC cache before using it.
This hash needs to be updated every time recovery mode training
is recomputed, or if the hash does not match recovery MRC cache.
Selecting this option requires that TPM already be setup by this
point in time. Thus it is only compatible when the option
VBOOT_STARTS_IN_BOOTBLOCK is selected, which causes verstage and
TPM setup to occur prior to memory initialization.
config FSP_PLATFORM_MEMORY_SETTINGS_VERSIONS
bool
help

View File

@@ -1,19 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _FSP2_0_MEMORY_INIT_H_
#define _FSP2_0_MEMORY_INIT_H_
#include <types.h>
/*
* Updates mrc cache hash if it differs.
*/
void mrc_cache_update_hash(const uint8_t *data, size_t size);
/*
* Verifies mrc cache hash which is stored somewhere.
* return 1 verification was successful and 0 for error.
*/
int mrc_cache_verify_hash(const uint8_t *data, size_t size);
#endif /* _FSP2_0_MEMORY_INIT_H_ */

View File

@@ -21,16 +21,10 @@
#include <security/vboot/vboot_common.h>
#include <security/tpm/tspi.h>
#include <vb2_api.h>
#include <fsp/memory_init.h>
#include <types.h>
static uint8_t temp_ram[CONFIG_FSP_TEMP_RAM_SIZE] __aligned(sizeof(uint64_t));
/* TPM MRC hash functionality depends on vboot starting before memory init. */
_Static_assert(!CONFIG(FSP2_0_USES_TPM_MRC_HASH) ||
CONFIG(VBOOT_STARTS_IN_BOOTBLOCK),
"for TPM MRC hash functionality, vboot must start in bootblock");
static void save_memory_training_data(bool s3wake, uint32_t fsp_version)
{
size_t mrc_data_size;
@@ -54,9 +48,6 @@ static void save_memory_training_data(bool s3wake, uint32_t fsp_version)
if (mrc_cache_stash_data(MRC_TRAINING_DATA, fsp_version, mrc_data,
mrc_data_size) < 0)
printk(BIOS_ERR, "Failed to stash MRC data\n");
if (CONFIG(FSP2_0_USES_TPM_MRC_HASH))
mrc_cache_update_hash(mrc_data, mrc_data_size);
}
static void do_fsp_post_memory_init(bool s3wake, uint32_t fsp_version)
@@ -121,10 +112,6 @@ static void fsp_fill_mrc_cache(FSPM_ARCH_UPD *arch_upd, uint32_t fsp_version)
if (data == NULL)
return;
if (CONFIG(FSP2_0_USES_TPM_MRC_HASH) &&
!mrc_cache_verify_hash(data, mrc_size))
return;
/* MRC cache found */
arch_upd->NvsBufferPtr = data;

View File

@@ -19,7 +19,7 @@ const char *mainboard_vbt_filename(void)
return "vbt.bin";
}
static char vbt_data[8 * KiB];
static char vbt_data[9 * KiB];
static size_t vbt_data_sz;
void *locate_vbt(size_t *vbt_size)

View File

@@ -0,0 +1,8 @@
config DRIVERS_INTEL_USB4_RETIMER
bool
depends on HAVE_ACPI_TABLES
help
A retimer is a device that retransmits a fresh copy of the signal it
receives, by doing CDR and retransmitting the data (i.e., it is
protocol-aware). If your mainboard has a USB4 retimer (usually
located close to the USB4 ports), then select this driver.

View File

@@ -0,0 +1 @@
ramstage-$(CONFIG_DRIVERS_INTEL_USB4_RETIMER) += retimer.c

View File

@@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef __DRIVERS_INTEL_USB4_RETIMER_H__
#define __DRIVERS_INTEL_USB4_RETIMER_H__
#include <acpi/acpi_device.h>
struct drivers_intel_usb4_retimer_config {
/* GPIO used to control power of retimer device. */
struct acpi_gpio power_gpio;
};
#endif /* __DRIVERS_INTEL_USB4_RETIMER_H__ */

View File

@@ -0,0 +1,136 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include <acpi/acpigen.h>
#include <acpi/acpi_device.h>
#include <console/console.h>
#include <device/device.h>
#include <device/path.h>
#include <gpio.h>
#include <string.h>
#include "chip.h"
/* Unique ID for the retimer _DSM. */
#define INTEL_USB4_RETIMER_DSM_UUID "61788900-C470-42BB-80F0-23A313864593"
/*
* Arg0: UUID
* Arg1: Revision ID (set to 1)
* Arg2: Function Index
* 0: Query command implemented
* 1: Query force power enable state
* 2: Set force power state
* Arg3: A package containing parameters for the function specified
* by the UUID, revision ID and function index.
*/
static void usb4_retimer_cb_standard_query(void *arg)
{
/*
* ToInteger (Arg1, Local2)
* If (Local2 == 1) {
* Return(Buffer() {0x07})
* }
* Return (Buffer() {0x01})
*/
acpigen_write_to_integer(ARG1_OP, LOCAL2_OP);
/* Revision 1 supports 2 Functions beyond the standard query */
acpigen_write_if_lequal_op_int(LOCAL2_OP, 1);
acpigen_write_return_singleton_buffer(0x07);
acpigen_pop_len(); /* If */
/* Other revisions support no additional functions */
acpigen_write_return_singleton_buffer(0);
}
static void usb4_retimer_cb_get_power_state(void *arg)
{
struct acpi_gpio *power_gpio = arg;
/*
* // Read power gpio into Local0
* Store (\_SB.PCI0.GTXS (power_gpio), Local0)
* Return (Local0)
*/
acpigen_get_tx_gpio(power_gpio);
acpigen_write_return_op(LOCAL0_OP);
}
static void usb4_retimer_cb_set_power_state(void *arg)
{
struct acpi_gpio *power_gpio = arg;
/*
* // Get argument for on/off from Arg3[0]
* Local0 = DeRefOf (Arg3[0])
*/
acpigen_get_package_op_element(ARG3_OP, 0, LOCAL0_OP);
/*
* If (Local0 == 0) {
* // Turn power off
* \_SB.PCI0.CTXS (power_gpio)
* }
*/
acpigen_write_if_lequal_op_int(LOCAL0_OP, 0);
acpigen_disable_tx_gpio(power_gpio);
acpigen_pop_len(); /* If */
/*
* Else {
* // Turn power on
* \_SB.PCI0.STXS (power_gpio)
* }
*/
acpigen_write_else();
acpigen_enable_tx_gpio(power_gpio);
acpigen_pop_len();
/* Return (Zero) */
acpigen_write_return_integer(0);
}
static void (*usb4_retimer_callbacks[3])(void *) = {
usb4_retimer_cb_standard_query, /* Function 0 */
usb4_retimer_cb_get_power_state, /* Function 1 */
usb4_retimer_cb_set_power_state, /* Function 2 */
};
static void usb4_retimer_fill_ssdt(const struct device *dev)
{
const struct drivers_intel_usb4_retimer_config *config = dev->chip_info;
const char *scope = acpi_device_scope(dev);
if (!dev->enabled || !scope || !config)
return;
if (!config->power_gpio.pin_count) {
printk(BIOS_ERR, "%s: Power GPIO required for %s\n", __func__, dev_path(dev));
return;
}
/* Write the _DSM that toggles power with provided GPIO. */
acpigen_write_scope(scope);
acpigen_write_dsm(INTEL_USB4_RETIMER_DSM_UUID, usb4_retimer_callbacks,
ARRAY_SIZE(usb4_retimer_callbacks), (void *)&config->power_gpio);
acpigen_pop_len(); /* Scope */
printk(BIOS_INFO, "%s: %s at %s\n", acpi_device_path(dev), dev->chip_ops->name,
dev_path(dev));
}
static struct device_operations usb4_retimer_dev_ops = {
.read_resources = noop_read_resources,
.set_resources = noop_set_resources,
.acpi_fill_ssdt = usb4_retimer_fill_ssdt,
};
static void usb4_retimer_enable(struct device *dev)
{
dev->ops = &usb4_retimer_dev_ops;
}
struct chip_operations drivers_intel_usb4_retimer_ops = {
CHIP_NAME("Intel USB4 Retimer")
.enable_dev = usb4_retimer_enable
};

View File

@@ -1,8 +0,0 @@
config DRIVERS_INTEL_WIFI
bool "Support Intel PCI-e WiFi adapters"
depends on PCI
default y if PCIEXP_PLUGIN_SUPPORT
select DRIVERS_WIFI_GENERIC if HAVE_ACPI_TABLES
help
When enabled, add identifiers in ACPI and SMBIOS tables to
make OS drivers work with certain Intel PCI-e WiFi chipsets.

View File

@@ -1,7 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
ramstage-$(CONFIG_DRIVERS_INTEL_WIFI) += wifi.c
cbfs-files-$(CONFIG_WIFI_SAR_CBFS) += wifi_sar_defaults.hex
wifi_sar_defaults.hex-file := $(call strip_quotes,$(CONFIG_WIFI_SAR_CBFS_FILEPATH))
wifi_sar_defaults.hex-type := raw

View File

@@ -1,10 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _INTEL_WIFI_CHIP_H_
#define _INTEL_WIFI_CHIP_H_
struct drivers_intel_wifi_config {
unsigned int wake; /* Wake pin for ACPI _PRW */
};
#endif /* _INTEL_WIFI_CHIP_H_ */

View File

@@ -1,146 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_ops.h>
#include <device/pci_ids.h>
#include <elog.h>
#include <smbios.h>
#include <string.h>
#include "chip.h"
#include "drivers/wifi/generic/chip.h"
#if CONFIG(GENERATE_SMBIOS_TABLES)
static int smbios_write_wifi(struct device *dev, int *handle,
unsigned long *current)
{
struct smbios_type_intel_wifi {
u8 type;
u8 length;
u16 handle;
u8 str;
u8 eos[2];
} __packed;
struct smbios_type_intel_wifi *t =
(struct smbios_type_intel_wifi *)*current;
int len = sizeof(struct smbios_type_intel_wifi);
memset(t, 0, sizeof(struct smbios_type_intel_wifi));
t->type = 0x85;
t->length = len - 2;
t->handle = *handle;
/*
* Intel wifi driver expects this string to be in the table 0x85
* with PCI IDs enumerated below.
*/
t->str = smbios_add_string(t->eos, "KHOIHGIUCCHHII");
len = t->length + smbios_string_table_len(t->eos);
*current += len;
*handle += 1;
return len;
}
#endif
#if CONFIG(HAVE_ACPI_TABLES)
static void intel_wifi_fill_ssdt(const struct device *dev)
{
struct drivers_intel_wifi_config *config = dev->chip_info;
struct drivers_wifi_generic_config generic_config;
if (config)
generic_config.wake = config->wake;
wifi_generic_fill_ssdt(dev, config ? &generic_config : NULL);
}
#endif
static void wifi_pci_dev_init(struct device *dev)
{
if (pci_dev_is_wake_source(dev))
elog_add_event_wake(ELOG_WAKE_SOURCE_PME_WIFI, 0);
}
struct device_operations device_ops = {
.read_resources = pci_dev_read_resources,
.set_resources = pci_dev_set_resources,
.enable_resources = pci_dev_enable_resources,
.init = wifi_pci_dev_init,
#if CONFIG(GENERATE_SMBIOS_TABLES)
.get_smbios_data = smbios_write_wifi,
#endif
.ops_pci = &pci_dev_ops_pci,
#if CONFIG(HAVE_ACPI_TABLES)
.acpi_name = wifi_generic_acpi_name,
.acpi_fill_ssdt = intel_wifi_fill_ssdt,
#endif
};
static const unsigned short pci_device_ids[] = {
PCI_DEVICE_ID_1000_SERIES_WIFI,
PCI_DEVICE_ID_6005_SERIES_WIFI,
PCI_DEVICE_ID_6005_I_SERIES_WIFI,
PCI_DEVICE_ID_1030_SERIES_WIFI,
PCI_DEVICE_ID_6030_I_SERIES_WIFI,
PCI_DEVICE_ID_6030_SERIES_WIFI,
PCI_DEVICE_ID_6150_SERIES_WIFI,
PCI_DEVICE_ID_2030_SERIES_WIFI,
PCI_DEVICE_ID_2000_SERIES_WIFI,
PCI_DEVICE_ID_0135_SERIES_WIFI,
PCI_DEVICE_ID_0105_SERIES_WIFI,
PCI_DEVICE_ID_6035_SERIES_WIFI,
PCI_DEVICE_ID_5300_SERIES_WIFI,
PCI_DEVICE_ID_5100_SERIES_WIFI,
PCI_DEVICE_ID_6000_SERIES_WIFI,
PCI_DEVICE_ID_6000_I_SERIES_WIFI,
PCI_DEVICE_ID_5350_SERIES_WIFI,
PCI_DEVICE_ID_5150_SERIES_WIFI,
/* Wilkins Peak 2 */
PCI_DEVICE_ID_WP_7260_SERIES_1_WIFI,
PCI_DEVICE_ID_WP_7260_SERIES_2_WIFI,
/* Stone Peak 2 */
PCI_DEVICE_ID_SP_7265_SERIES_1_WIFI,
PCI_DEVICE_ID_SP_7265_SERIES_2_WIFI,
/* Stone Field Peak */
PCI_DEVICE_ID_SFP_8260_SERIES_1_WIFI,
PCI_DEVICE_ID_SFP_8260_SERIES_2_WIFI,
/* Windstorm Peak */
PCI_DEVICE_ID_WSP_8275_SERIES_1_WIFI,
/* Jefferson Peak */
PCI_DEVICE_ID_JP_9000_SERIES_1_WIFI,
PCI_DEVICE_ID_JP_9000_SERIES_2_WIFI,
PCI_DEVICE_ID_JP_9000_SERIES_3_WIFI,
/* Thunder Peak 2 */
PCI_DEVICE_ID_TP_9260_SERIES_WIFI,
/* Harrison Peak */
PCI_DEVICE_ID_HrP_9560_SERIES_1_WIFI,
PCI_DEVICE_ID_HrP_9560_SERIES_2_WIFI,
PCI_DEVICE_ID_HrP_9560_SERIES_3_WIFI,
PCI_DEVICE_ID_HrP_9560_SERIES_4_WIFI,
PCI_DEVICE_ID_HrP_6SERIES_WIFI,
/* Cyclone Peak */
PCI_DEVICE_ID_CyP_6SERIES_WIFI,
/* Typhoon Peak */
PCI_DEVICE_ID_TyP_6SERIES_WIFI,
/* Garfiled Peak */
PCI_DEVICE_ID_GrP_6SERIES_1_WIFI,
PCI_DEVICE_ID_GrP_6SERIES_2_WIFI,
0
};
static const struct pci_driver pch_intel_wifi __pci_driver = {
.ops = &device_ops,
.vendor = PCI_VENDOR_ID_INTEL,
.devices = pci_device_ids,
};
static void intel_wifi_enable(struct device *dev)
{
dev->ops = &device_ops;
}
struct chip_operations drivers_intel_wifi_ops = {
CHIP_NAME("Intel WiFi")
.enable_dev = intel_wifi_enable
};

View File

@@ -33,6 +33,8 @@ extern int ipmi_kcs_message(int port, int netfn, int lun, int cmd,
* returns CB_SUCCESS on success and CB_ERR if an error occurred. */
enum cb_err ipmi_kcs_premem_init(const u16 port, const u16 device);
void ipmi_bmc_version(uint8_t *ipmi_bmc_major_revision, uint8_t *ipmi_bmc_minor_revision);
struct ipmi_rsp {
uint8_t lun;
uint8_t cmd;

View File

@@ -8,6 +8,7 @@
* end
*/
#include <arch/io.h>
#include <console/console.h>
#include <device/device.h>
#include <device/pnp.h>
@@ -28,6 +29,9 @@
static u8 ipmi_revision_major = 0x1;
static u8 ipmi_revision_minor = 0x0;
static u8 bmc_revision_major = 0x0;
static u8 bmc_revision_minor = 0x0;
static int ipmi_get_device_id(struct device *dev, struct ipmi_devid_rsp *rsp)
{
int ret;
@@ -144,6 +148,9 @@ static void ipmi_kcs_init(struct device *dev)
ipmi_revision_minor = IPMI_IPMI_VERSION_MINOR(rsp.ipmi_version);
ipmi_revision_major = IPMI_IPMI_VERSION_MAJOR(rsp.ipmi_version);
bmc_revision_major = rsp.fw_rev1;
bmc_revision_minor = rsp.fw_rev2;
memcpy(&man_id, rsp.manufacturer_id,
sizeof(rsp.manufacturer_id));
@@ -272,6 +279,18 @@ static void ipmi_ssdt(const struct device *dev)
}
#endif
void ipmi_bmc_version(uint8_t *ipmi_bmc_major_revision, uint8_t *ipmi_bmc_minor_revision)
{
if (!bmc_revision_major || !bmc_revision_minor) {
printk(BIOS_ERR, "IPMI: BMC revision missing\n");
*ipmi_bmc_major_revision = 0;
*ipmi_bmc_minor_revision = 0;
} else {
*ipmi_bmc_major_revision = bmc_revision_major;
*ipmi_bmc_minor_revision = bmc_revision_minor;
}
}
#if CONFIG(GENERATE_SMBIOS_TABLES)
static int ipmi_smbios_data(struct device *dev, int *handle,
unsigned long *current)

View File

@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <arch/io.h>
#include <console/console.h>
#include <device/pnp.h>
#include <delay.h>

View File

@@ -49,4 +49,12 @@ config MRC_STASH_TO_CBMEM
that need to write back the MRC data in late ramstage boot
states (MRC_WRITE_NV_LATE).
config MRC_SAVE_HASH_IN_TPM
bool "Save a hash of the MRC_CACHE data in TPM NVRAM"
depends on VBOOT_STARTS_IN_BOOTBLOCK && TPM2 && !TPM1
default y
help
Store a hash of the MRC_CACHE training data in a TPM NVRAM
space to ensure that it cannot be tampered with.
endif # CACHE_MRC_SETTINGS

View File

@@ -10,6 +10,8 @@
#include <fmap.h>
#include <ip_checksum.h>
#include <region_file.h>
#include <security/vboot/antirollback.h>
#include <security/vboot/mrc_cache_hash_tpm.h>
#include <security/vboot/vboot_common.h>
#include <spi_flash.h>
@@ -44,6 +46,7 @@ struct cache_region {
uint32_t cbmem_id;
int type;
int elog_slot;
uint32_t tpm_hash_index;
int flags;
};
@@ -52,6 +55,7 @@ static const struct cache_region recovery_training = {
.cbmem_id = CBMEM_ID_MRCDATA,
.type = MRC_TRAINING_DATA,
.elog_slot = ELOG_MEM_CACHE_UPDATE_SLOT_RECOVERY,
.tpm_hash_index = MRC_REC_HASH_NV_INDEX,
#if CONFIG(HAS_RECOVERY_MRC_CACHE)
.flags = RECOVERY_FLAG,
#else
@@ -64,6 +68,7 @@ static const struct cache_region normal_training = {
.cbmem_id = CBMEM_ID_MRCDATA,
.type = MRC_TRAINING_DATA,
.elog_slot = ELOG_MEM_CACHE_UPDATE_SLOT_NORMAL,
.tpm_hash_index = MRC_RW_HASH_NV_INDEX,
.flags = NORMAL_FLAG | RECOVERY_FLAG,
};
@@ -72,6 +77,7 @@ static const struct cache_region variable_data = {
.cbmem_id = CBMEM_ID_VAR_MRCDATA,
.type = MRC_VARIABLE_DATA,
.elog_slot = ELOG_MEM_CACHE_UPDATE_SLOT_VARIABLE,
.tpm_hash_index = 0,
.flags = NORMAL_FLAG | RECOVERY_FLAG,
};
@@ -82,6 +88,11 @@ static const struct cache_region *cache_regions[] = {
&variable_data,
};
/* TPM MRC hash functionality depends on vboot starting before memory init. */
_Static_assert(!CONFIG(MRC_SAVE_HASH_IN_TPM) ||
CONFIG(VBOOT_STARTS_IN_BOOTBLOCK),
"for TPM MRC hash functionality, vboot must start in bootblock");
static int lookup_region_by_name(const char *name, struct region *r)
{
if (fmap_locate_area(name, r) == 0)
@@ -169,20 +180,31 @@ static int mrc_header_valid(struct region_device *rdev, struct mrc_metadata *md)
return 0;
}
static int mrc_data_valid(const struct mrc_metadata *md,
static int mrc_data_valid(int type, const struct mrc_metadata *md,
void *data, size_t data_size)
{
uint16_t checksum;
const struct cache_region *cr = lookup_region_type(type);
uint32_t hash_idx;
if (cr == NULL)
return -1;
if (md->data_size != data_size)
return -1;
checksum = compute_ip_checksum(data, data_size);
hash_idx = cr->tpm_hash_index;
if (hash_idx && CONFIG(MRC_SAVE_HASH_IN_TPM)) {
if (!mrc_cache_verify_hash(hash_idx, data, data_size))
return -1;
} else {
checksum = compute_ip_checksum(data, data_size);
if (md->data_checksum != checksum) {
printk(BIOS_ERR, "MRC: data checksum mismatch: %x vs %x\n",
md->data_checksum, checksum);
return -1;
if (md->data_checksum != checksum) {
printk(BIOS_ERR, "MRC: data checksum mismatch: %x vs %x\n",
md->data_checksum, checksum);
return -1;
}
}
return 0;
@@ -277,7 +299,7 @@ ssize_t mrc_cache_load_current(int type, uint32_t version, void *buffer,
if (rdev_readat(&rdev, buffer, 0, data_size) != data_size)
return -1;
if (mrc_data_valid(&md, buffer, data_size) < 0)
if (mrc_data_valid(type, &md, buffer, data_size) < 0)
return -1;
return data_size;
@@ -304,7 +326,7 @@ void *mrc_cache_current_mmap_leak(int type, uint32_t version,
return NULL;
}
if (mrc_data_valid(&md, data, region_device_size) < 0)
if (mrc_data_valid(type, &md, data, region_device_size) < 0)
return NULL;
return data;
@@ -315,10 +337,10 @@ static bool mrc_cache_needs_update(const struct region_device *rdev,
const void *new_data, size_t new_data_size)
{
void *mapping, *data_mapping;
size_t size = region_device_sz(rdev);
size_t old_data_size = region_device_sz(rdev) - sizeof(struct mrc_metadata);
bool need_update = false;
if (new_data_size != size)
if (new_data_size != old_data_size)
return true;
mapping = rdev_mmap_full(rdev);
@@ -384,6 +406,7 @@ static void update_mrc_cache_by_type(int type,
const struct region_device *backing_rdev;
struct region_device latest_rdev;
const bool fail_bad_data = false;
uint32_t hash_idx;
cr = lookup_region(&region, type);
@@ -443,6 +466,9 @@ static void update_mrc_cache_by_type(int type,
} else {
printk(BIOS_DEBUG, "MRC: updated '%s'.\n", cr->name);
log_event_cache_update(cr->elog_slot, UPDATE_SUCCESS);
hash_idx = cr->tpm_hash_index;
if (hash_idx && CONFIG(MRC_SAVE_HASH_IN_TPM))
mrc_cache_update_hash(hash_idx, new_data, new_data_size);
}
}

View File

@@ -6,6 +6,18 @@ config SMMSTORE
default y if PAYLOAD_TIANOCORE
select SPI_FLASH_SMM if BOOT_DEVICE_SPI_FLASH_RW_NOMMAP
config SMMSTORE_V2
bool "Use version 2 of SMMSTORE API"
depends on SMMSTORE
default n
help
Version 2 of SMMSTORE allows secure communication with SMM and
makes no assumptions on the structure of the data stored within.
It splits the store into chunks to allows fault tolerant writes.
By using version 2 you cannot make use of software that expects
a version 1 SMMSTORE.
config SMMSTORE_IN_CBFS
bool
default n

View File

@@ -1,3 +1,4 @@
ramstage-$(CONFIG_SMMSTORE) += store.c
ramstage-$(CONFIG_SMMSTORE_V2) += ramstage.c
smm-$(CONFIG_SMMSTORE) += store.c smi.c

View File

@@ -0,0 +1,76 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <bootstate.h>
#include <cpu/x86/smm.h>
#include <commonlib/helpers.h>
#include <commonlib/region.h>
#include <console/console.h>
#include <smmstore.h>
#include <types.h>
#include <cbmem.h>
static struct smmstore_params_info info;
void lb_smmstorev2(struct lb_header *header)
{
struct lb_record *rec;
struct lb_smmstorev2 *store;
const struct cbmem_entry *e;
e = cbmem_entry_find(CBMEM_ID_SMM_COMBUFFER);
if (!e)
return;
rec = lb_new_record(header);
store = (struct lb_smmstorev2 *)rec;
store->tag = LB_TAG_SMMSTOREV2;
store->size = sizeof(*store);
store->com_buffer = (uintptr_t)cbmem_entry_start(e);
store->com_buffer_size = cbmem_entry_size(e);
store->mmap_addr = info.mmap_addr;
store->num_blocks = info.num_blocks;
store->block_size = info.block_size;
store->apm_cmd = APM_CNT_SMMSTORE;
}
static void init_store(void *unused)
{
struct smmstore_params_init args;
uint32_t eax = ~0;
uint32_t ebx;
if (smmstore_get_info(&info) < 0) {
printk(BIOS_INFO, "SMMSTORE: Failed to get meta data\n");
return;
}
void *ptr = cbmem_add(CBMEM_ID_SMM_COMBUFFER, info.block_size);
if (!ptr) {
printk(BIOS_ERR, "SMMSTORE: Failed to add com buffer\n");
return;
}
args.com_buffer = (uintptr_t)ptr;
args.com_buffer_size = info.block_size;
ebx = (uintptr_t)&args;
printk(BIOS_INFO, "SMMSTORE: Setting up SMI handler\n");
/* Issue SMI using APM to update the com buffer and to lock the SMMSTORE */
__asm__ __volatile__ (
"outb %%al, %%dx"
: "=a" (eax)
: "a" ((SMMSTORE_CMD_INIT << 8) | APM_CNT_SMMSTORE),
"b" (ebx),
"d" (APM_CNT)
: "memory");
if (eax != SMMSTORE_RET_SUCCESS) {
printk(BIOS_ERR, "SMMSTORE: Failed to install com buffer\n");
return;
}
}
/* The SMI APM handler is installed at DEV_INIT phase */
BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_EXIT, init_store, NULL);

View File

@@ -23,8 +23,7 @@ static int range_check(void *start, size_t size)
return 0;
}
/* Param is usually EBX, ret in EAX */
uint32_t smmstore_exec(uint8_t command, void *param)
static uint32_t smmstorev1_exec(uint8_t command, void *param)
{
uint32_t ret = SMMSTORE_RET_FAILURE;
@@ -66,13 +65,89 @@ uint32_t smmstore_exec(uint8_t command, void *param)
ret = SMMSTORE_RET_SUCCESS;
break;
}
default:
printk(BIOS_DEBUG,
"Unknown SMM store command: 0x%02x\n", command);
"Unknown SMM store v1 command: 0x%02x\n", command);
ret = SMMSTORE_RET_UNSUPPORTED;
break;
}
return ret;
}
static uint32_t smmstorev2_exec(uint8_t command, void *param)
{
uint32_t ret = SMMSTORE_RET_FAILURE;
switch (command) {
case SMMSTORE_CMD_INIT: {
printk(BIOS_DEBUG, "Init SMM store\n");
struct smmstore_params_init *params = param;
if (range_check(params, sizeof(*params)) != 0)
break;
void *buf = (void *)(uintptr_t)params->com_buffer;
if (range_check(buf, params->com_buffer_size) != 0)
break;
if (smmstore_init(buf, params->com_buffer_size) == 0)
ret = SMMSTORE_RET_SUCCESS;
break;
}
case SMMSTORE_CMD_RAW_READ: {
printk(BIOS_DEBUG, "Raw read from SMM store, param = %p\n", param);
struct smmstore_params_raw_read *params = param;
if (range_check(params, sizeof(*params)) != 0)
break;
if (smmstore_rawread_region(params->block_id, params->bufoffset,
params->bufsize) == 0)
ret = SMMSTORE_RET_SUCCESS;
break;
}
case SMMSTORE_CMD_RAW_WRITE: {
printk(BIOS_DEBUG, "Raw write to SMM store, param = %p\n", param);
struct smmstore_params_raw_write *params = param;
if (range_check(params, sizeof(*params)) != 0)
break;
if (smmstore_rawwrite_region(params->block_id, params->bufoffset,
params->bufsize) == 0)
ret = SMMSTORE_RET_SUCCESS;
break;
}
case SMMSTORE_CMD_RAW_CLEAR: {
printk(BIOS_DEBUG, "Raw clear SMM store, param = %p\n", param);
struct smmstore_params_raw_clear *params = param;
if (range_check(params, sizeof(*params)) != 0)
break;
if (smmstore_rawclear_region(params->block_id) == 0)
ret = SMMSTORE_RET_SUCCESS;
break;
}
default:
printk(BIOS_DEBUG,
"Unknown SMM store v2 command: 0x%02x\n", command);
ret = SMMSTORE_RET_UNSUPPORTED;
break;
}
return ret;
}
uint32_t smmstore_exec(uint8_t command, void *param)
{
if (!param)
return SMMSTORE_RET_FAILURE;
if (CONFIG(SMMSTORE_V2))
return smmstorev2_exec(command, param);
else
return smmstorev1_exec(command, param);
}

View File

@@ -262,3 +262,200 @@ int smmstore_clear_region(void)
return 0;
}
/* Implementation of Version 2 */
static bool store_initialized;
static struct mem_region_device mdev_com_buf;
static int smmstore_rdev_chain(struct region_device *rdev)
{
if (!store_initialized)
return -1;
return rdev_chain_full(rdev, &mdev_com_buf.rdev);
}
/**
* Call once before using the store. In SMM this must be called through an
* APM SMI handler providing the communication buffer address and length.
*/
int smmstore_init(void *buf, size_t len)
{
if (!buf || len < SMM_BLOCK_SIZE)
return -1;
if (store_initialized)
return -1;
mem_region_device_rw_init(&mdev_com_buf, buf, len);
store_initialized = true;
return 0;
}
#if ENV_RAMSTAGE
/**
* Provide metadata for the coreboot tables.
* Must only be called in ramstage, but not in SMM.
*/
int smmstore_get_info(struct smmstore_params_info *out)
{
struct region_device store;
if (lookup_store(&store) < 0) {
printk(BIOS_ERR, "smm store: lookup of store failed\n");
return -1;
}
if (!IS_ALIGNED(region_device_offset(&store), SMM_BLOCK_SIZE)) {
printk(BIOS_ERR, "smm store: store not aligned to block size\n");
return -1;
}
out->block_size = SMM_BLOCK_SIZE;
out->num_blocks = region_device_sz(&store) / SMM_BLOCK_SIZE;
/* FIXME: Broken EDK2 always assumes memory mapped Firmware Block Volumes */
out->mmap_addr = (uintptr_t)rdev_mmap_full(&store);
printk(BIOS_DEBUG, "smm store: %d # blocks with size 0x%x\n",
out->num_blocks, out->block_size);
return 0;
}
#endif
/* Returns -1 on error, 0 on success */
static int lookup_block_in_store(struct region_device *store, uint32_t block_id)
{
if (lookup_store(store) < 0) {
printk(BIOS_ERR, "smm store: lookup of store failed\n");
return -1;
}
if ((block_id * SMM_BLOCK_SIZE) >= region_device_sz(store)) {
printk(BIOS_ERR, "smm store: block ID out of range\n");
return -1;
}
return 0;
}
/* Returns NULL on error, pointer from rdev_mmap on success */
static void *mmap_com_buf(struct region_device *com_buf, uint32_t offset, uint32_t bufsize)
{
if (smmstore_rdev_chain(com_buf) < 0) {
printk(BIOS_ERR, "smm store: lookup of com buffer failed\n");
return NULL;
}
if (offset >= region_device_sz(com_buf)) {
printk(BIOS_ERR, "smm store: offset out of range\n");
return NULL;
}
void *ptr = rdev_mmap(com_buf, offset, bufsize);
if (!ptr)
printk(BIOS_ERR, "smm store: not enough space for new data\n");
return ptr;
}
/**
* Reads the specified block of the SMMSTORE and places it in the communication
* buffer.
* @param block_id The id of the block to operate on
* @param offset Offset within the block.
* Must be smaller than the block size.
* @param bufsize Size of chunk to read within the block.
* Must be smaller than the block size.
* @return Returns -1 on error, 0 on success.
*/
int smmstore_rawread_region(uint32_t block_id, uint32_t offset, uint32_t bufsize)
{
struct region_device store;
struct region_device com_buf;
if (lookup_block_in_store(&store, block_id) < 0)
return -1;
void *ptr = mmap_com_buf(&com_buf, offset, bufsize);
if (!ptr)
return -1;
printk(BIOS_DEBUG, "smm store: reading %p block %d, offset=0x%x, size=%x\n",
ptr, block_id, offset, bufsize);
ssize_t ret = rdev_readat(&store, ptr, block_id * SMM_BLOCK_SIZE + offset, bufsize);
rdev_munmap(&com_buf, ptr);
if (ret < 0)
return -1;
return 0;
}
/**
* Writes the specified block of the SMMSTORE by reading it from the communication
* buffer.
* @param block_id The id of the block to operate on
* @param offset Offset within the block.
* Must be smaller than the block size.
* @param bufsize Size of chunk to read within the block.
* Must be smaller than the block size.
* @return Returns -1 on error, 0 on success.
*/
int smmstore_rawwrite_region(uint32_t block_id, uint32_t offset, uint32_t bufsize)
{
struct region_device store;
struct region_device com_buf;
if (lookup_block_in_store(&store, block_id) < 0)
return -1;
if (rdev_chain(&store, &store, block_id * SMM_BLOCK_SIZE + offset, bufsize)) {
printk(BIOS_ERR, "smm store: not enough space for new data\n");
return -1;
}
void *ptr = mmap_com_buf(&com_buf, offset, bufsize);
if (!ptr)
return -1;
printk(BIOS_DEBUG, "smm store: writing %p block %d, offset=0x%x, size=%x\n",
ptr, block_id, offset, bufsize);
ssize_t ret = rdev_writeat(&store, ptr, 0, bufsize);
rdev_munmap(&com_buf, ptr);
if (ret < 0)
return -1;
return 0;
}
/**
* Erases the specified block of the SMMSTORE. The communication buffer remains untouched.
*
* @param block_id The id of the block to operate on
*
* @return Returns -1 on error, 0 on success.
*/
int smmstore_rawclear_region(uint32_t block_id)
{
struct region_device store;
if (lookup_block_in_store(&store, block_id) < 0)
return -1;
ssize_t ret = rdev_eraseat(&store, block_id * SMM_BLOCK_SIZE, SMM_BLOCK_SIZE);
if (ret != SMM_BLOCK_SIZE) {
printk(BIOS_ERR, "smm store: erasing block failed\n");
return -1;
}
return 0;
}

View File

@@ -259,11 +259,11 @@ static void sn65dsi86_bridge_valid_dp_rates(uint8_t bus, uint8_t chip, bool rate
DP_BRIDGE_DPCD_REV, 1, DPCD_READ, &dpcd_val);
if (dpcd_val >= DP_BRIDGE_14) {
/* eDP 1.4 devices must provide a custom table */
uint8_t sink_rates[DP_MAX_SUPPORTED_RATES * 2];
uint16_t sink_rates[DP_MAX_SUPPORTED_RATES] = {0};
sn65dsi86_bridge_dpcd_request(bus, chip, DP_SUPPORTED_LINK_RATES,
sizeof(sink_rates),
DPCD_READ, sink_rates);
DPCD_READ, (void *)sink_rates);
for (i = 0; i < ARRAY_SIZE(sink_rates); i++) {
rate_per_200khz = le16_to_cpu(sink_rates[i]);
@@ -288,14 +288,12 @@ static void sn65dsi86_bridge_valid_dp_rates(uint8_t bus, uint8_t chip, bool rate
}
/* On older versions best we can do is use DP_MAX_LINK_RATE */
sn65dsi86_bridge_dpcd_request(bus, chip,
DP_MAX_LINK_RATE, 1, DPCD_READ, &dpcd_val);
sn65dsi86_bridge_dpcd_request(bus, chip, DP_MAX_LINK_RATE, 1, DPCD_READ, &dpcd_val);
switch (dpcd_val) {
default:
printk(BIOS_ERR,
"Unexpected max rate (%#x); assuming 5.4 GHz\n",
(int)dpcd_val);
printk(BIOS_ERR, "Unexpected max rate (%#x); assuming 5.4 GHz\n",
(int)dpcd_val);
/* fall through */
case DP_LINK_BW_5_4:
rate_valid[7] = 1;

View File

@@ -1,11 +1,19 @@
config DRIVERS_WIFI_GENERIC
bool
default n
depends on HAVE_ACPI_TABLES
help
When enabled, add identifiers in ACPI tables that are common
to WiFi chipsets from multiple vendors.
config DRIVERS_INTEL_WIFI
bool "Support Intel PCI-e WiFi adapters"
depends on PCI
default y if PCIEXP_PLUGIN_SUPPORT
select DRIVERS_WIFI_GENERIC
help
When enabled, add identifiers in ACPI and SMBIOS tables to
make OS drivers work with certain Intel PCI-e WiFi chipsets.
if DRIVERS_WIFI_GENERIC
config USE_SAR

View File

@@ -1 +1,5 @@
ramstage-$(CONFIG_DRIVERS_WIFI_GENERIC) += generic.c
cbfs-files-$(CONFIG_WIFI_SAR_CBFS) += wifi_sar_defaults.hex
wifi_sar_defaults.hex-file := $(call strip_quotes,$(CONFIG_WIFI_SAR_CBFS_FILEPATH))
wifi_sar_defaults.hex-type := raw

View File

@@ -11,26 +11,4 @@ struct drivers_wifi_generic_config {
unsigned int wake;
};
/**
* wifi_generic_fill_ssdt() - Fill ACPI SSDT table for WiFi controller
* @dev: Device structure corresponding to WiFi controller.
* @config: Generic wifi config required to fill ACPI SSDT table.
*
* This function implements common device operation to help fill ACPI SSDT
* table for WiFi controller.
*/
void wifi_generic_fill_ssdt(const struct device *dev,
const struct drivers_wifi_generic_config *config);
/**
* wifi_generic_acpi_name() - Get ACPI name for WiFi controller
* @dev: Device structure corresponding to WiFi controller.
*
* This function implements common device operation to get the ACPI name for
* WiFi controller.
*
* Return: string representing the ACPI name for WiFi controller.
*/
const char *wifi_generic_acpi_name(const struct device *dev);
#endif /* _GENERIC_WIFI_H_ */

View File

@@ -6,8 +6,10 @@
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_def.h>
#include <device/pci_ids.h>
#include <elog.h>
#include <sar.h>
#include <smbios.h>
#include <string.h>
#include <wrdd.h>
#include "chip.h"
@@ -35,18 +37,23 @@
*/
#define WIFI_ACPI_NAME_MAX_LEN 5
#if CONFIG(HAVE_ACPI_TABLES)
__weak
int get_wifi_sar_limits(struct wifi_sar_limits *sar_limits)
{
return -1;
}
static void emit_sar_acpi_structures(void)
static void emit_sar_acpi_structures(const struct device *dev)
{
int i, j, package_size;
struct wifi_sar_limits sar_limits;
struct wifi_sar_delta_table *wgds;
/* CBFS SAR and SAR ACPI tables are currently used only by Intel WiFi devices. */
if (dev->vendor != PCI_VENDOR_ID_INTEL)
return;
/* Retrieve the sar limits data */
if (get_wifi_sar_limits(&sar_limits) < 0) {
printk(BIOS_ERR, "Error: failed from getting SAR limits!\n");
@@ -160,11 +167,11 @@ static void emit_sar_acpi_structures(void)
acpigen_pop_len();
}
void wifi_generic_fill_ssdt(const struct device *dev,
const struct drivers_wifi_generic_config *config)
static void wifi_generic_fill_ssdt(const struct device *dev)
{
const char *path;
u32 address;
const struct drivers_wifi_generic_config *config = dev->chip_info;
if (!dev->enabled)
return;
@@ -214,7 +221,7 @@ void wifi_generic_fill_ssdt(const struct device *dev,
/* Fill Wifi sar related ACPI structures */
if (CONFIG(USE_SAR))
emit_sar_acpi_structures();
emit_sar_acpi_structures(dev);
acpigen_pop_len(); /* Device */
acpigen_pop_len(); /* Scope */
@@ -223,7 +230,7 @@ void wifi_generic_fill_ssdt(const struct device *dev,
dev->chip_ops ? dev->chip_ops->name : "", dev_path(dev));
}
const char *wifi_generic_acpi_name(const struct device *dev)
static const char *wifi_generic_acpi_name(const struct device *dev)
{
static char wifi_acpi_name[WIFI_ACPI_NAME_MAX_LEN];
@@ -232,11 +239,7 @@ const char *wifi_generic_acpi_name(const struct device *dev)
(dev_path_encode(dev) & 0xff));
return wifi_acpi_name;
}
static void wifi_generic_fill_ssdt_generator(const struct device *dev)
{
wifi_generic_fill_ssdt(dev, dev->chip_info);
}
#endif
static void wifi_pci_dev_init(struct device *dev)
{
@@ -244,14 +247,55 @@ static void wifi_pci_dev_init(struct device *dev)
elog_add_event_wake(ELOG_WAKE_SOURCE_PME_WIFI, 0);
}
#if CONFIG(GENERATE_SMBIOS_TABLES)
static int smbios_write_intel_wifi(struct device *dev, int *handle, unsigned long *current)
{
struct smbios_type_intel_wifi {
u8 type;
u8 length;
u16 handle;
u8 str;
u8 eos[2];
} __packed;
struct smbios_type_intel_wifi *t = (struct smbios_type_intel_wifi *)*current;
int len = sizeof(struct smbios_type_intel_wifi);
memset(t, 0, sizeof(struct smbios_type_intel_wifi));
t->type = 0x85;
t->length = len - 2;
t->handle = *handle;
/* Intel wifi driver expects this string to be in the table 0x85. */
t->str = smbios_add_string(t->eos, "KHOIHGIUCCHHII");
len = t->length + smbios_string_table_len(t->eos);
*current += len;
*handle += 1;
return len;
}
static int smbios_write_wifi(struct device *dev, int *handle, unsigned long *current)
{
if (dev->vendor == PCI_VENDOR_ID_INTEL)
return smbios_write_intel_wifi(dev, handle, current);
return 0;
}
#endif
struct device_operations wifi_generic_ops = {
.read_resources = pci_dev_read_resources,
.set_resources = pci_dev_set_resources,
.enable_resources = pci_dev_enable_resources,
.init = wifi_pci_dev_init,
.ops_pci = &pci_dev_ops_pci,
#if CONFIG(HAVE_ACPI_TABLES)
.acpi_name = wifi_generic_acpi_name,
.acpi_fill_ssdt = wifi_generic_fill_ssdt_generator,
.acpi_fill_ssdt = wifi_generic_fill_ssdt,
#endif
#if CONFIG(GENERATE_SMBIOS_TABLES)
.get_smbios_data = smbios_write_wifi,
#endif
};
static void wifi_generic_enable(struct device *dev)
@@ -268,3 +312,67 @@ struct chip_operations drivers_wifi_generic_ops = {
CHIP_NAME("WIFI Device")
.enable_dev = wifi_generic_enable
};
static const unsigned short intel_pci_device_ids[] = {
PCI_DEVICE_ID_1000_SERIES_WIFI,
PCI_DEVICE_ID_6005_SERIES_WIFI,
PCI_DEVICE_ID_6005_I_SERIES_WIFI,
PCI_DEVICE_ID_1030_SERIES_WIFI,
PCI_DEVICE_ID_6030_I_SERIES_WIFI,
PCI_DEVICE_ID_6030_SERIES_WIFI,
PCI_DEVICE_ID_6150_SERIES_WIFI,
PCI_DEVICE_ID_2030_SERIES_WIFI,
PCI_DEVICE_ID_2000_SERIES_WIFI,
PCI_DEVICE_ID_0135_SERIES_WIFI,
PCI_DEVICE_ID_0105_SERIES_WIFI,
PCI_DEVICE_ID_6035_SERIES_WIFI,
PCI_DEVICE_ID_5300_SERIES_WIFI,
PCI_DEVICE_ID_5100_SERIES_WIFI,
PCI_DEVICE_ID_6000_SERIES_WIFI,
PCI_DEVICE_ID_6000_I_SERIES_WIFI,
PCI_DEVICE_ID_5350_SERIES_WIFI,
PCI_DEVICE_ID_5150_SERIES_WIFI,
/* Wilkins Peak 2 */
PCI_DEVICE_ID_WP_7260_SERIES_1_WIFI,
PCI_DEVICE_ID_WP_7260_SERIES_2_WIFI,
/* Stone Peak 2 */
PCI_DEVICE_ID_SP_7265_SERIES_1_WIFI,
PCI_DEVICE_ID_SP_7265_SERIES_2_WIFI,
/* Stone Field Peak */
PCI_DEVICE_ID_SFP_8260_SERIES_1_WIFI,
PCI_DEVICE_ID_SFP_8260_SERIES_2_WIFI,
/* Windstorm Peak */
PCI_DEVICE_ID_WSP_8275_SERIES_1_WIFI,
/* Jefferson Peak */
PCI_DEVICE_ID_JP_9000_SERIES_1_WIFI,
PCI_DEVICE_ID_JP_9000_SERIES_2_WIFI,
PCI_DEVICE_ID_JP_9000_SERIES_3_WIFI,
/* Thunder Peak 2 */
PCI_DEVICE_ID_TP_9260_SERIES_WIFI,
/* Harrison Peak */
PCI_DEVICE_ID_HrP_9560_SERIES_1_WIFI,
PCI_DEVICE_ID_HrP_9560_SERIES_2_WIFI,
PCI_DEVICE_ID_HrP_9560_SERIES_3_WIFI,
PCI_DEVICE_ID_HrP_9560_SERIES_4_WIFI,
PCI_DEVICE_ID_HrP_6SERIES_WIFI,
/* Cyclone Peak */
PCI_DEVICE_ID_CyP_6SERIES_WIFI,
/* Typhoon Peak */
PCI_DEVICE_ID_TyP_6SERIES_WIFI,
/* Garfield Peak */
PCI_DEVICE_ID_GrP_6SERIES_1_WIFI,
PCI_DEVICE_ID_GrP_6SERIES_2_WIFI,
0
};
/*
* The PCI driver is retained for backward compatibility with boards that never utilized the
* chip driver to support Intel WiFi device. For these devices, the PCI driver helps perform the
* same operations as above (except exposing the wake property) by utilizing the same
* `wifi_generic_ops`.
*/
static const struct pci_driver intel_wifi_pci_driver __pci_driver = {
.ops = &wifi_generic_ops,
.vendor = PCI_VENDOR_ID_INTEL,
.devices = intel_pci_device_ids,
};

View File

@@ -1380,11 +1380,11 @@ enum ec_image google_chromeec_get_current_image(void)
return ec_image_type;
}
int google_chromeec_get_num_pd_ports(int *num_ports)
int google_chromeec_get_num_pd_ports(unsigned int *num_ports)
{
struct ec_response_charge_port_count resp = {};
struct chromeec_command cmd = {
.cmd_code = EC_CMD_CHARGE_PORT_COUNT,
.cmd_code = EC_CMD_USB_PD_PORTS,
.cmd_version = 0,
.cmd_data_out = &resp,
.cmd_size_in = 0,
@@ -1441,6 +1441,65 @@ int google_ec_running_ro(void)
return (google_chromeec_get_current_image() == EC_IMAGE_RO);
}
int google_chromeec_usb_pd_control(int port, bool *ufp, bool *dbg_acc, uint8_t *dp_mode)
{
struct ec_params_usb_pd_control pd_control = {
.port = port,
.role = USB_PD_CTRL_ROLE_NO_CHANGE,
.mux = USB_PD_CTRL_ROLE_NO_CHANGE,
.swap = USB_PD_CTRL_SWAP_NONE,
};
struct ec_response_usb_pd_control_v2 resp = {};
struct chromeec_command cmd = {
.cmd_code = EC_CMD_USB_PD_CONTROL,
.cmd_version = 2,
.cmd_data_in = &pd_control,
.cmd_size_in = sizeof(pd_control),
.cmd_data_out = &resp,
.cmd_size_out = sizeof(resp),
.cmd_dev_index = 0,
};
if (google_chromeec_command(&cmd) < 0)
return -1;
*ufp = (resp.cc_state == PD_CC_DFP_ATTACHED);
*dbg_acc = (resp.cc_state == PD_CC_DFP_DEBUG_ACC);
*dp_mode = resp.dp_mode;
return 0;
}
/**
* Check for the current mux state in EC. Flags representing the mux state found
* in ec_commands.h
*/
int google_chromeec_usb_get_pd_mux_info(int port, uint8_t *flags)
{
struct ec_params_usb_pd_mux_info req_mux = {
.port = port,
};
struct ec_response_usb_pd_mux_info resp_mux = {};
struct chromeec_command cmd = {
.cmd_code = EC_CMD_USB_PD_MUX_INFO,
.cmd_version = 0,
.cmd_data_in = &req_mux,
.cmd_size_in = sizeof(req_mux),
.cmd_data_out = &resp_mux,
.cmd_size_out = sizeof(resp_mux),
.cmd_dev_index = 0,
};
if (port < 0)
return -1;
if (google_chromeec_command(&cmd) < 0)
return -1;
*flags = resp_mux.flags;
return 0;
}
/**
* Check if EC/TCPM is in an alternate mode or not.
*
@@ -1557,3 +1616,50 @@ int google_chromeec_ap_reset(void)
return 0;
}
int google_chromeec_regulator_set_voltage(uint32_t index, uint32_t min_mv,
uint32_t max_mv)
{
struct ec_params_regulator_set_voltage params = {
.index = index,
.min_mv = min_mv,
.max_mv = max_mv,
};
struct chromeec_command cmd = {
.cmd_code = EC_CMD_REGULATOR_SET_VOLTAGE,
.cmd_version = 0,
.cmd_data_in = &params,
.cmd_size_in = sizeof(params),
.cmd_data_out = NULL,
.cmd_size_out = 0,
.cmd_dev_index = 0,
};
if (google_chromeec_command(&cmd))
return -1;
return 0;
}
int google_chromeec_regulator_get_voltage(uint32_t index, uint32_t *voltage_mv)
{
struct ec_params_regulator_get_voltage params = {
.index = index,
};
struct ec_response_regulator_get_voltage resp = {};
struct chromeec_command cmd = {
.cmd_code = EC_CMD_REGULATOR_GET_VOLTAGE,
.cmd_version = 0,
.cmd_data_in = &params,
.cmd_size_in = sizeof(params),
.cmd_data_out = &resp,
.cmd_size_out = sizeof(resp),
.cmd_dev_index = 0,
};
if (google_chromeec_command(&cmd))
return -1;
*voltage_mv = resp.voltage_mv;
return 0;
}

View File

@@ -27,6 +27,15 @@ int google_ec_running_ro(void);
enum ec_image google_chromeec_get_current_image(void);
void google_chromeec_init(void);
int google_chromeec_pd_get_amode(uint16_t svid);
/* Check for the current mux state in EC
* in: int port physical port number of the type-c port
* out: uint8_t flags flags representing the status of the mux such as
* usb capability, dp capability, cable type, etc
*/
int google_chromeec_usb_get_pd_mux_info(int port, uint8_t *flags);
/* Returns data role and type of device connected */
int google_chromeec_usb_pd_control(int port, bool *ufp, bool *dbg_acc,
uint8_t *dp_mode);
int google_chromeec_wait_for_displayport(long timeout);
/* Device events */
@@ -306,7 +315,7 @@ int google_chromeec_get_cmd_versions(int command, uint32_t *pmask);
* of PD-capable USB ports according to the EC.
* @return 0 on success, -1 on error
*/
int google_chromeec_get_num_pd_ports(int *num_ports);
int google_chromeec_get_num_pd_ports(unsigned int *num_ports);
/* Structure representing the capabilities of a USB-PD port */
struct usb_pd_port_caps {
@@ -344,6 +353,24 @@ int google_chromeec_get_keybd_config(struct ec_response_keybd_config *keybd);
*/
int google_chromeec_ap_reset(void);
/**
* Set voltage for the voltage regulator within the range specified.
* @param index Regulator ID
* @param min_mv Minimum voltage
* @param max_mv Maximum voltage
* @return 0 on success, -1 on error
*/
int google_chromeec_regulator_set_voltage(uint32_t index, uint32_t min_mv,
uint32_t max_mv);
/**
* Get the currently configured voltage for the voltage regulator.
* @param index Regulator ID
* @param *voltage_mv If successful, voltage_mv is filled with current voltage
* @return 0 on success, -1 on error
*/
int google_chromeec_regulator_get_voltage(uint32_t index, uint32_t *voltage_mv);
#if CONFIG(HAVE_ACPI_TABLES)
/**
* Writes USB Type-C PD related information to the SSDT

Some files were not shown because too many files have changed in this diff Show More