392 changes: 392 additions & 0 deletions Documentation/infrastructure/builders.md
@@ -0,0 +1,392 @@
# Jenkins builder setup and configuration

## How to set up a new jenkins builder

### Contact a jenkins admin

Let a jenkins admin know that you’re interested in setting up a jenkins
build system.

For a permanent build system, this should generally be a dedicated
machine that is not generally being used for other purposes. The
coreboot builds are very intensive.

It's also best to be aware that although we don't know of any security
issues, the jenkins-node image is run with the privileged flag which
gives the container root access to the build machine. See
[this article](https://blog.trendmicro.com/trendlabs-security-intelligence/why-running-a-privileged-container-in-docker-is-a-bad-idea/)
about why this is discouraged.

It's recommended that you give an admin root access on your machine so
that they can reset it in case of a failure. This is not a requirement,
as the system can just be disabled until someone is available to fix any
issues.

Currently active Jenkins admins:
* Patrick Georgi:
* Email: [patrick@georgi-clan.de](mailto:patrick@georgi-clan.de)
* IRC: pgeorgi


### Build Machine requirements

For a builder, we need a fast system with lots of threads and plenty of
RAM. The builder builds and stores the git repos and output in tmpfs
along with the ccache save area, so if there isn't enough memory, the
builds will slow down because of smaller ccache areas and can run into
"out of storage space" errors.

#### Current Build Machines

To give an idea of what a suitable build machine might be, currently the
coreboot project has 3 active jenkins build machines.

* Congenialbuilder - 128 threads, 256GiB RAM
* Fastest Passing coreboot gerrit build: 4 min, 30 sec
* Slowest Passing coreboot gerrit build: 9 min, 56 sec


* Gleeful builder - 64 thread, 64GiB RAM
* Fastest Passing coreboot gerrit build: 6 min, 6 sec
* Slowest Passing coreboot gerrit build, 34 min


* Ultron (9elements) - 48 threads, 128GiB RAM
* Fastest Passing coreboot gerrit build: 6 min, 32 sec
* Slowest Passing coreboot gerrit build: 44 min


### Jenkins Builds

There are a number of builds handled by the coreboot jenkins builders,
for a number of different projects - coreboot, flashrom, memtest86+,
em100, etc. Many of these have builders for their current master branch
as well as gerrit and coverity builds.

You can see all the builds here:
[https://qa.coreboot.org/](https://qa.coreboot.org/)

Most of the time on the builders is taken up by the coreboot master and
gerrit builds.

* [coreboot gerrit build](https://qa.coreboot.org/job/coreboot-gerrit/)
([Time trend](https://qa.coreboot.org/job/coreboot-gerrit/buildTimeTrend))


* [coreboot master build](https://qa.coreboot.org/job/coreboot/)
([Time trend](https://qa.coreboot.org/job/coreboot/buildTimeTrend))


### Stress test the machine

Test the machine to make sure that building won't stress the hardware
too much. Install stress-ng, then run the stress test for at least an
hour.

On a system with 32 cores, it was tested with this command:

```
$ stress-ng --cpu 20 --io 6 --vm 6 --vm-bytes 1G --verify --metrics-brief -t 60m
```

You can watch the temperature with the sensors package or with ‘acpi -t’
if your machine supports that.

You can check for thermal throttling by running this command and seeing
if the values go down on any of the cores after it's been running for a
while.

```
$ while [ true ]; do clear; cat /proc/cpuinfo | grep 'cpu MHz' ; sleep 1; done
```

If the machine throttles or resets, you probably need to upgrade the
cooling system.


## jenkins-server docker installation


### Manual Installation

If you’ve met all the above requirements, and an admin has agreed to set
up the builder in jenkins, you’re ready to go on to the next steps.


### Set up your network so jenkins can talk to the container

Expose a local port through any firewalls you might have on your router.
This would generally be in the port forwarding section, and you'd just
forward a port (typically 49151) from the internet directly to the
builder’s IP address.

You might also want to set up a port to forward to port 22 on your
machine and set up openssh so you or the jenkins admins can manage
the machine remotely (if you allow them).


### Install and set up docker

Install docker by following the
[directions](https://docs.docker.com/engine/install/) on the docker
site. These instructions keep changing, so just check the latest
information.


#### Set up environment variables

To make configuration and the later commands easier, these should go in
your shell's .rc file. Note that you only need to set them if you're
using something other than the default.

```
# Set the port used on your machine to connect to jenkins.
export COREBOOT_JENKINS_PORT=49151
# Set the revision of the container from docker hub
export DOCKER_COMMIT=65718760fa
# Set the location of where the jenkins cache directory will be.
export COREBOOT_JENKINS_CACHE_DIR="/srv/docker/coreboot-builder/cache"
# Set the name of the container
export COREBOOT_JENKINS_CONTAINER="coreboot_jenkins"
```

Make sure any variables needed are set in your environment before
continuing to the next step.


### Using the Makefile for docker installation

From the coreboot directory, run

```
make -C util/docker help
```

This will show you the available targets and variables needed:

```
Commands for working with docker images:
coreboot-sdk - Build coreboot-sdk container
upload-coreboot-sdk - Upload coreboot-sdk to hub.docker.com
coreboot-jenkins-node - Build coreboot-jenkins-node container
upload-coreboot-jenkins-node - Upload coreboot-jenkins-node to hub.docker.com
doc.coreboot.org - Build doc.coreboot.org container
clean-coreboot-containers - Remove all docker coreboot containers
clean-coreboot-images - Remove all docker coreboot images
docker-clean - Remove docker coreboot containers & images
Commands for using docker images
docker-build-coreboot - Build coreboot under coreboot-sdk
<BUILD_CMD=target>
docker-abuild - Run abuild under coreboot-sdk
<ABUILD_ARGS='-a -B'>
docker-what-jenkins-does - Run 'what-jenkins-does' target
docker-shell - Bash prompt in coreboot-jenkins-node
<USER=root or USER=coreboot>
docker-jenkins-server - Run coreboot-jenkins-node image (for server)
docker-jenkins-attach - Open shell in running jenkins server
docker-build-docs - Build the documentation
docker-livehtml-docs - Run sphinx-autobuild
Variables:
COREBOOT_JENKINS_PORT=49151
COREBOOT_JENKINS_CACHE_DIR=/srv/docker/coreboot-builder/cache
COREBOOT_JENKINS_CONTAINER=coreboot_jenkins
COREBOOT_IMAGE_TAG=f2741aa632f
DOCKER_COMMIT=65718760fa
```

### Set up the system for the jenkins builder

As a regular user - *Not root*, run:

```
sudo mkdir -p ${COREBOOT_JENKINS_CACHE_DIR}
sudo mkdir -p ${COREBOOT_JENKINS_CCACHE_DIR}
sudo chown $(whoami):$(whoami) ${COREBOOT_JENKINS_CCACHE_DIR}
sudo chown $(whoami):$(whoami) ${COREBOOT_JENKINS_CACHE_DIR}
wget http://www.dediprog.com/save/78.rar/to/EM100Pro.rar
mv EM100Pro.rar ${COREBOOT_JENKINS_CACHE_DIR}
```

### Install the coreboot jenkins builder

```
make -C util/docker docker-jenkins-server
```

Your installation is complete on your side.

### Tell the Admins that the machine is set up
Let the admins know that the builder is set up so they can set up the
machine profile on qa.coreboot.org.

They need to know:
* Your external IP address or domain name. If you don’t have a static
IP, make sure you have a dynamic dns hostname configured.
* The port on your machine and firewall that’s exposed for jenkins:
`$COREBOOT_JENKINS_PORT`
* The core count of the machine.
* How much memory is available on the machine. This helps determine
the amount of memory used for ccache.


### First build
On the first build after a machine is reset, it will frequently take
20-25 minutes to do the entire what-jenkins-does build while the ccache
is getting filled up and the entire coreboot repo gets downloaded. As
the ccache gets populated, the build time will drop.


## Additional Information


### How to log in to the docker instance for debugging
```
$ make -C util/docker docker-jenkins-attach
$ su coreboot
$ cd ~/slave-root/workspace
$ bash
```


WARNING: This should not be used to make changes to the build system,
but just to debug issues. Changes to the build system are highly
discouraged as it leads to situations where patches can pass the build
testing on one builder and fail on another builder. Any changes that are
made in the image will be lost on the next update, so if you
accidentally change something, you can remove the containers and images
and update to get a fresh installation.


### How to download containers/images for a fresh installation and remove old containers

To delete the old containers & images:

```
$ docker stop $COREBOOT_JENKINS_CONTAINER
$ docker rm $COREBOOT_JENKINS_CONTAINER
$ docker images # lists all existing images
$ docker rmi XXXX # Use the image ID found in the above command.
```

To get and run the new coreboot-jenkins image, change the value in the
`DOCKER_COMMIT` variable to the new image value.

```
$ make -C util/docker docker-jenkins-server
```

#### Getting ready to push the docker images

Set up an account on hub.docker.com

Get an admin to add the account to the coreboot team on hub.docker.com

[https://hub.docker.com/u/coreboot/dashboard/teams/?team=owners](https://hub.docker.com/u/coreboot/dashboard/teams/?team=owners)

Make sure your credentials are configured on your host machine by
running

```
$ docker login
```

This will prompt you for your docker username, password, and your email
address, and write out to ~/.docker/config.json. Without this file, you
won’t be able to push the images.

#### Updating the Dockerfiles:

The coreboot-sdk Dockerfile will need to be updated when any additional
dependencies are added. Both the coreboot-sdk and the
coreboot-jenkins-node Dockerfiles will need to be updated to the new
version number and git commit id anytime the toolchain is updated. Both
files are stored in the coreboot repo under coreboot/util/docker.

Read the [dockerfile best practices](https://docs.docker.com/v1.8/articles/dockerfile_best-practices/)
page before updating the files.

#### Rebuilding the coreboot-sdk docker image to update the toolchain:

```
$ make -C util/docker coreboot-sdk
```

This takes a relatively long time.

#### Test the coreboot-sdk docker image:

There are two methods of running the docker image - interactively as a
shell, or doing the build directly. Running interactively as a shell is
useful for early testing, because it allows you to update the image
(without any changes getting saved) and re-test builds. This saves the
time of having to rebuild the image for every issue you find.

#### Running the docker image interactively:

Run:

```
$ make -C util/docker docker-jenkins-server
$ make -C util/docker docker-jenkins-attach
```

#### Running the build directly:

From the coreboot directory:

```
$ make -C util/docker docker-build-coreboot
```

You’ll also want to test building the other projects and payloads:
ChromeEC, flashrom, memtest86+, em100, Grub2, SeaBIOS, iPXE, coreinfo,
nvramcui, tint...

#### Pushing the coreboot-sdk image to hub.docker.com for use:

When you’re satisfied with the testing, push the coreboot-sdk image to
the hub.docker.com

```
$ make -C util/docker upload-coreboot-sdk
```

#### Building and pushing the coreboot-jenkins-node docker image:

This docker image is pretty simple, so there’s not really any testing
that needs to be done.

```
$ make -C util/docker coreboot-jenkins-node
$ make -C util/docker upload-coreboot-jenkins-node
```

### Coverity Setup

To run coverity jobs, the builder needs to have the tools available, and
to be marked as a coverity builder.


#### Set up the Coverity tools

Download the Linux-64 coverity build tool and decompress it into your
cache directory as defined by the `$COREBOOT_JENKINS_CACHE_DIR` variable

[https://scan.coverity.com/download](https://scan.coverity.com/download)

Rename the directory from its original name
(cov-analysis-linux64-7.7.0.4) to ‘coverity’, or better, create a
symlink:

```
ln -s cov-analysis-linux64-7.7.0.4 coverity
```


Let the admins know that the ‘coverity’ label can be added to the
builder.
6 changes: 6 additions & 0 deletions Documentation/infrastructure/index.md
@@ -0,0 +1,6 @@
# coreboot infrastructure

This section contains documentation about coreboot infrastructure

## Jenkins builders and builds
[Setting up Jenkins build machines](builders.md)
5 changes: 5 additions & 0 deletions Documentation/mainboard/index.md
Expand Up @@ -16,6 +16,7 @@ This section contains documentation about coreboot on specific mainboards.

## ASUS

- [A88XM-E](asus/a88xm-e.md)
- [F2A85-M](asus/f2a85-m.md)
- [P5Q](asus/p5q.md)
- [P8H61-M LX](asus/p8h61-m_lx.md)
Expand Down Expand Up @@ -176,6 +177,10 @@ The boards in this section are not real mainboards, but emulators.

- [Lemur Pro](system76/lemp9.md)

## Texas Instruments

- [Beaglebone Black](ti/beaglebone-black.md)

## UP

- [Squared](up/squared/index.md)
2 changes: 1 addition & 1 deletion Documentation/mainboard/lenovo/Ivy_Bridge_series.md
Expand Up @@ -25,7 +25,7 @@ This information is valid for all supported models, except T430s, [T431s](t431s.

## Installation instructions
* Update the EC firmware, as there's no support for EC updates in coreboot.
* Do **NOT** accidently swap pins or power on the board while a SPI flasher
* Do **NOT** accidentally swap pins or power on the board while a SPI flasher
is connected. It will permanently brick your device.
* It's recommended to only flash the BIOS region. In that case you don't
need to extract blobs from vendor firmware.
Expand Down
6 changes: 5 additions & 1 deletion Documentation/mainboard/lenovo/Sandy_Bridge_series.md
Expand Up @@ -22,8 +22,12 @@
```

## Installation instructions

Flashing coreboot for the first time needs to be done using an external
programmer, because vendor firmware prevents rewriting the BIOS region.

* Update the EC firmware, as there's no support for EC updates in coreboot.
* Do **NOT** accidently swap pins or power on the board while a SPI flasher
* Do **NOT** accidentally swap pins or power on the board while a SPI flasher
is connected. It will destroy your device.
* It's recommended to only flash the BIOS region. In that case you don't
need to extract blobs from vendor firmware.
Expand Down
131 changes: 131 additions & 0 deletions Documentation/mainboard/ti/beaglebone-black.md
@@ -0,0 +1,131 @@
# Beaglebone Black
This page gives some details about the [BeagleBone Black] coreboot port and
describes how to build and run it.

The port currently only supports booting coreboot from a micro SD card and has
some other limitations listed below.

## Supported Boards
The Beaglebone port supports the following boards:

- Beaglebone Black
- Beaglebone Black Wireless
- Beaglebone Pocket (untested, may need tweaking)
- Beaglebone Blue (untested, may need tweaking)
- Beaglebone Original (untested, may need tweaking)

## Use Cases
This port was primarily developed as a learning exercise and there is
potentially little reason to use it compared to the defacto bootloader choice of
U-Boot. However, it does have some interesting practical use cases compared to
U-Boot:

1. Choosing coreboot as a lightweight alternative to U-Boot. In this case,
coreboot is used to do the absolute minimum necessary to boot Linux, forgoing
some U-Boot features and functionality. Complex boot logic can then instead
be moved into Linux where it can be more flexibly and safely executed. This
is essentially the LinuxBoot philosophy. [U-Boot Falcon mode] has similar
goals to this as well.
2. Facilitating experimenting with coreboot on real hardware. The Beaglebone
Black is widely available at a low pricepoint (~$65) making it a great way to
experiment with coreboot on real ARMv7 hardware. It also works well as a
development platform as it has exposed pads for JTAG and, due to the way it
boots, is effectively impossible to brick.
3. The Beaglebone Black is often used as a external flasher and EHCI debug
gadget in the coreboot community, so many members have access to it and can
use it as a reference platform.

## Quickstart
1. Run `make menuconfig` and select _TI_/_Beaglebone_ in the _Mainboard_ menu.
2. Add a payload as normal.
3. Run `make`.
4. Copy the resulting `build/MLO` file to the micro SD card at offset 128k - ie
`dd if=build/MLO of=/dev/sdcard seek=1 bs=128k`.

**NOTE**: By default, the Beaglebone is configured to try to boot first from
eMMC before booting from SD card. To ensure that the Beaglebone boots from SD,
either erase the internal eMMC or hold the _S2_ button while powering on (note
that this has to be while powering on - ie when plugging in the USB or DC barrel
jack - the boot order doesn't change on reset) to prioritize SD in the boot
order.

## Serial Console
By default, coreboot uses UART0 as the serial console. UART0 is available
through the J1 header on both the Beaglebone Black and Beaglebone Black
Wireless. The serial runs at 3.3V and 115200 8n1.

The pin mapping is shown below for J1.

```eval_rst
+----------------------------+------------+
| Pin number | Function |
+============================+============+
| 1 (Closest to barrel jack) | GND |
+----------------------------+------------+
| 4 | RX |
+----------------------------+------------+
| 5 | TX |
+----------------------------+------------+
```

## Boot Process
The AM335x contains ROM code to allow booting in a number of different
configurations. More information about the boot ROM code can be found in the
AM335x technical reference manual (_SPRUH73Q_) in the _Initialization_ section.

This coreboot port is currently configured to boot in "SD Raw Mode" where the
boot binary, with header ("Table of Contents" in TI's nomenclature), is placed
at the offset of 0x20000 (128KB) on the SD card. The boot ROM loads the coreboot
bootblock stage into SRAM and executes it.

The bootblock and subsequent romstage and ramstage coreboot stages expect that
the coreboot image, containing the CBFS, is located at 0x20000 on the SD card.
All stages directly read from the SD card in order to load the next stage in
sequence.

## Clock Initialization and PMIC
To simplify the port, the TPS65217C Power Management IC (PMIC) on the Beaglebone
Black is not configured by coreboot. By default, the PMIC reset values for
VDD_MPU (1.1V) and VDD_CORE (1.8V) are within the Operating Performance Point
(OPP) for the MPU PLL configuration set by the boot ROM of 500 MHz.

When using Linux as a payload, the kernel will appropriately scale the core
voltages for the desired MPU clock frequency as defined in the device tree.

One significant difference because of this to the U-Boot port is that the DCDC1
rail that powers the DDR3 RAM will be 1.5V by default. The Micron DDR3 supports
both 1.35V and 1.5V and U-Boot makes use of this by setting it to 1.35V to
conserve power. Fortunately, Linux is again able to configure this rail but it
involves adding an entry to the device tree:

&dcdc1_reg {
regulator-name = "vdd_ddr3";
regulator-min-microvolt = <1350000>;
regulator-max-microvolt = <1350000>;
regulator-boot-on;
regulator-always-on;
};

If this port was to be extended to work with boards or SoCs with different
requirements for the MPU clock frequency or different Operating Performance
Points, then the port may need to be extended to set the core voltages and MPU
PLL within coreboot, prior to loading a payload. Extending coreboot so that it
can configure the PMIC would also be necessary if there was a requirement for
coreboot to run at a different MPU frequency than the 500 MHz set by the boot
ROM.

# Todo
- Allow coreboot to run from the Beaglebone Black's internal eMMC. This would
require updating the `mmc.c` driver to support running from both SD and eMMC.
- Support the boot ROMs *FAT mode* so that the coreboot binary can be placed on
a FAT partition.
- Increase the MMC read speed, it currently takes ~15s to read ~20MB which is a
bit slow. To do this, it should be possible to update the MMC driver to:
- Increase the supported blocksize (currently is always set to 1)
- Support 4-bit data width (currently only supports 1-bit data width)
- Convert the while loops in the MMC driver to timeout so that coreboot does not
hang on a bad SD card or when the SD card is removed during boot.


[Beaglebone Black]: https://beagleboard.org/black [U-Boot Falcon mode]:
https://elixir.bootlin.com/u-boot/v2020.07/source/doc/README.falcon
Expand Up @@ -20,11 +20,6 @@ Like any other Intel SoC, Ice Lake coreboot development is also based on "Intel
:doc:`../../../mainboard/intel/icelake_rvp`
```

3. OEMs to design based on reference platform and make use of mainboard sample code. Dragonegg is Ice Lake based mainboard developed by Google
```eval_rst
:doc:`../../../mainboard/google/dragonegg`
```

### Summary:
* SoC is Ice Lake.
* Reference platform is icelake_rvp.
Expand Down
2 changes: 1 addition & 1 deletion Documentation/soc/intel/index.md
Expand Up @@ -11,4 +11,4 @@ This section contains documentation about coreboot on specific Intel SOCs.
- [Microcode Updates](microcode.md)
- [Firmware Interface Table](fit.md)
- [Apollolake](apollolake/index.md)
- [CSE FW Update](cse_fw_update/cse_fw_update_model.md)
- [CSE FW Update](cse_fw_update/cse_fw_update.md)
2 changes: 2 additions & 0 deletions MAINTAINERS
Expand Up @@ -717,6 +717,8 @@ F: src/drivers/aspeed/common/
F: src/drivers/aspeed/ast2050/

ACPI
M: Lance Zhao <lance.zhao@gmail.com>
S: Supported
F: src/acpi/
F: src/arch/x86/acpi/
F: util/acpi/
Expand Down
17 changes: 10 additions & 7 deletions Makefile
Expand Up @@ -8,6 +8,7 @@ src := src
srck := $(top)/util/kconfig
obj ?= build
override obj := $(subst $(top)/,,$(abspath $(obj)))
xcompile ?= $(obj)/xcompile
objutil ?= $(obj)/util
objk := $(objutil)/kconfig
absobj := $(abspath $(obj))
Expand Down Expand Up @@ -119,7 +120,7 @@ UNIT_TEST:=1
NOCOMPILE:=
endif

.xcompile: util/xcompile/xcompile
$(xcompile): util/xcompile/xcompile
rm -f $@
$< $(XGCCPATH) > $@.tmp
\mv -f $@.tmp $@ 2> /dev/null
Expand All @@ -146,15 +147,17 @@ ifneq ($(UNIT_TEST),1)
include $(DOTCONFIG)
endif

# in addition to the dependency below, create the file if it doesn't exist
# to silence stupid warnings about a file that would be generated anyway.
$(if $(wildcard .xcompile)$(NOCOMPILE),,$(eval $(shell util/xcompile/xcompile $(XGCCPATH) > .xcompile || rm -f .xcompile)))
# The toolchain requires xcompile to determine the ARCH_SUPPORTED, so we can't
# wait for make to generate the file.
$(if $(wildcard $(xcompile)),, $(shell \
mkdir -p $(dir $(xcompile)) && \
util/xcompile/xcompile $(XGCCPATH) > $(xcompile) || rm -f $(xcompile)))

-include .xcompile
include $(xcompile)

ifneq ($(XCOMPILE_COMPLETE),1)
$(shell rm -f .xcompile)
$(error .xcompile deleted because it's invalid. \
$(shell rm -f $(xcompile))
$(error $(xcompile) deleted because it's invalid. \
Restarting the build should fix that, or explain the problem)
endif

Expand Down
38 changes: 27 additions & 11 deletions Makefile.inc
Expand Up @@ -77,14 +77,15 @@ PHONY+= clean-abuild coreboot check-style build-dirs build_complete

#######################################################################
# root source directories of coreboot
subdirs-y := src/lib src/commonlib/ src/console src/device src/acpi
subdirs-y := src/lib src/commonlib/ src/console src/device src/acpi src/superio/common
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/superio/*) $(wildcard src/superio/*/*)
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 util/qemu
subdirs-y += util/ifdtool
subdirs-y += $(wildcard src/arch/*)
subdirs-y += src/mainboard/$(MAINBOARDDIR)
subdirs-y += src/security
Expand Down Expand Up @@ -483,7 +484,13 @@ ADAFLAGS_common += -gnatwa.eeD.HHTU.U.W.Y
# Disable style checks for now
ADAFLAGS_common += -gnatyN

LDFLAGS_common := --gc-sections -nostdlib -nostartfiles -static --emit-relocs
LDFLAGS_common := --gc-sections -nostdlib -nostartfiles -static

# Workaround for RISC-V linker bug, merge back into above line when fixed.
# https://sourceware.org/bugzilla/show_bug.cgi?id=27180
ifneq ($(CONFIG_ARCH_RISCV),y)
LDFLAGS_common += --emit-relocs
endif

ifeq ($(CONFIG_WARNINGS_ARE_ERRORS),y)
CFLAGS_common += -Werror
Expand Down Expand Up @@ -520,7 +527,8 @@ build_h_exports := BUILD_TIMELESS KERNELVERSION COREBOOT_EXTRA_VERSION
# Report new `build.ht` as dependency if `build.h` differs.
build_h_check := \
export $(foreach exp,$(build_h_exports),$(exp)="$($(exp))"); \
util/genbuild_h/genbuild_h.sh .xcompile >$(build_h)t 2>/dev/null; \
util/genbuild_h/genbuild_h.sh $(xcompile) \
>$(build_h)t 2>/dev/null; \
cmp -s $(build_h)t $(build_h) >/dev/null 2>&1 || echo $(build_h)t

$(build_h): $$(shell $$(build_h_check))
Expand Down Expand Up @@ -575,10 +583,6 @@ endif
BINCFG:=$(objutil)/bincfg/bincfg

IFDTOOL:=$(objutil)/ifdtool/ifdtool
$(IFDTOOL):
@printf " Compile IFDTOOL\n"
+$(MAKE) -C $(top)/util/ifdtool
cp -a $(top)/util/ifdtool/ifdtool $@

AMDFWTOOL:=$(objutil)/amdfwtool/amdfwtool

Expand Down Expand Up @@ -982,6 +986,15 @@ else
FMAP_SPD_CACHE_ENTRY :=
endif

ifeq ($(CONFIG_VPD),y)
FMAP_VPD_BASE := $(call int-align, $(FMAP_CURRENT_BASE), 0x4000)
FMAP_VPD_SIZE := $(CONFIG_VPD_FMAP_SIZE)
FMAP_VPD_ENTRY := $(CONFIG_VPD_FMAP_NAME)@$(FMAP_VPD_BASE) $(FMAP_VPD_SIZE)
FMAP_CURRENT_BASE := $(call int-add, $(FMAP_VPD_BASE) $(FMAP_VPD_SIZE))
else
FMAP_VPD_ENTRY :=
endif

#
# X86 FMAP region
#
Expand Down Expand Up @@ -1059,6 +1072,7 @@ $(obj)/fmap.fmd: $(top)/Makefile.inc $(DEFAULT_FLASHMAP) $(obj)/config.h
-e "s,##MRC_CACHE_ENTRY##,$(FMAP_MRC_CACHE_ENTRY)," \
-e "s,##SMMSTORE_ENTRY##,$(FMAP_SMMSTORE_ENTRY)," \
-e "s,##SPD_CACHE_ENTRY##,$(FMAP_SPD_CACHE_ENTRY)," \
-e "s,##VPD_ENTRY##,$(FMAP_VPD_ENTRY)," \
-e "s,##CBFS_BASE##,$(FMAP_CBFS_BASE)," \
-e "s,##CBFS_SIZE##,$(FMAP_CBFS_SIZE)," \
$(DEFAULT_FLASHMAP) > $@.tmp
Expand Down Expand Up @@ -1136,6 +1150,10 @@ else
RAMSTAGE=
endif

add_intermediate = \
$(1): $(obj)/coreboot.pre $(2) | $(INTERMEDIATE) \
$(eval INTERMEDIATE+=$(1)) $(eval PHONY+=$(1))

$(obj)/coreboot.rom: $(obj)/coreboot.pre $(RAMSTAGE) $(CBFSTOOL) $$(INTERMEDIATE)
@printf " CBFS $(subst $(obj)/,,$(@))\n"
# The full ROM may be larger than the CBFS part, so create an empty
Expand Down Expand Up @@ -1242,7 +1260,7 @@ cbfs-get-segments-cmd = $(CBFSTOOL) $(obj)/coreboot.pre print -v | sed -n \
ramstage-symbol-addr-cmd = $(OBJDUMP_ramstage) -t $(objcbfs)/ramstage.elf | \
sed -n '/ $(1)$$/s/^\([0-9a-fA-F]*\) .*/0x\1/p'

check-ramstage-overlaps: $(obj)/coreboot.pre
$(call add_intermediate, check-ramstage-overlaps)
programs=$$($(foreach file,$(check-ramstage-overlap-files), \
$(call cbfs-get-segments-cmd,$(file)) ; )) ; \
regions=$$($(foreach region,$(check-ramstage-overlap-regions), \
Expand All @@ -1268,6 +1286,4 @@ check-ramstage-overlaps: $(obj)/coreboot.pre
pstart= ; pend= ; \
done

INTERMEDIATE+=check-ramstage-overlaps
PHONY+=check-ramstage-overlaps
endif
2 changes: 1 addition & 1 deletion configs/config.pcengines_apu1
@@ -1,4 +1,4 @@
CONFIG_LOCALVERSION="v4.13.0.2"
CONFIG_LOCALVERSION="v4.13.0.3"
CONFIG_VENDOR_PCENGINES=y
CONFIG_PAYLOAD_CONFIGFILE="$(top)/src/mainboard/$(MAINBOARDDIR)/seabios_config"
CONFIG_NO_GFX_INIT=y
Expand Down
2 changes: 1 addition & 1 deletion configs/config.pcengines_apu2
@@ -1,4 +1,4 @@
CONFIG_LOCALVERSION="v4.13.0.2"
CONFIG_LOCALVERSION="v4.13.0.3"
CONFIG_VENDOR_PCENGINES=y
CONFIG_PAYLOAD_CONFIGFILE="$(top)/src/mainboard/$(MAINBOARDDIR)/seabios_config"
CONFIG_BOARD_PCENGINES_APU2=y
Expand Down
2 changes: 1 addition & 1 deletion configs/config.pcengines_apu3
@@ -1,4 +1,4 @@
CONFIG_LOCALVERSION="v4.13.0.2"
CONFIG_LOCALVERSION="v4.13.0.3"
CONFIG_VENDOR_PCENGINES=y
CONFIG_PAYLOAD_CONFIGFILE="$(top)/src/mainboard/$(MAINBOARDDIR)/seabios_config"
CONFIG_BOARD_PCENGINES_APU3=y
Expand Down
2 changes: 1 addition & 1 deletion configs/config.pcengines_apu4
@@ -1,4 +1,4 @@
CONFIG_LOCALVERSION="v4.13.0.2"
CONFIG_LOCALVERSION="v4.13.0.3"
CONFIG_VENDOR_PCENGINES=y
CONFIG_PAYLOAD_CONFIGFILE="$(top)/src/mainboard/$(MAINBOARDDIR)/seabios_config"
CONFIG_BOARD_PCENGINES_APU4=y
Expand Down
2 changes: 1 addition & 1 deletion configs/config.pcengines_apu5
@@ -1,4 +1,4 @@
CONFIG_LOCALVERSION="v4.13.0.2"
CONFIG_LOCALVERSION="v4.13.0.3"
CONFIG_VENDOR_PCENGINES=y
CONFIG_PAYLOAD_CONFIGFILE="$(top)/src/mainboard/$(MAINBOARDDIR)/seabios_config"
CONFIG_BOARD_PCENGINES_APU5=y
Expand Down
2 changes: 1 addition & 1 deletion configs/config.pcengines_apu6
@@ -1,4 +1,4 @@
CONFIG_LOCALVERSION="v4.13.0.2"
CONFIG_LOCALVERSION="v4.13.0.3"
CONFIG_VENDOR_PCENGINES=y
CONFIG_PAYLOAD_CONFIGFILE="$(top)/src/mainboard/$(MAINBOARDDIR)/seabios_config"
CONFIG_BOARD_PCENGINES_APU6=y
Expand Down
15 changes: 7 additions & 8 deletions payloads/external/Makefile.inc
Expand Up @@ -145,26 +145,24 @@ endif

ifneq ($(CONFIG_SEABIOS_PS2_TIMEOUT),)
ifneq ($(CONFIG_SEABIOS_PS2_TIMEOUT),0)
ifneq ($(CONFIG_UPDATE_IMAGE),y)
INTERMEDIATE+=seabios_ps2_timeout
seabios_ps2_timeout: $(obj)/coreboot.pre $(CBFSTOOL)
$(call add_intermediate, seabios_ps2_timeout, $(CBFSTOOL))
@printf " SeaBIOS Wait up to $(CONFIG_SEABIOS_PS2_TIMEOUT) ms for PS/2 keyboard controller initialization\n"
$(if $(CONFIG_UPDATE_IMAGE),-$(CBFSTOOL) $< remove -n etc/ps2-keyboard-spinup 2>/dev/null)
$(CBFSTOOL) $< add-int -i $(CONFIG_SEABIOS_PS2_TIMEOUT) -n etc/ps2-keyboard-spinup
endif
endif
endif

ifeq ($(CONFIG_SEABIOS_ADD_SERCON_PORT_FILE),y)
INTERMEDIATE+=seabios_sercon
seabios_sercon: $(obj)/coreboot.pre $(CBFSTOOL)
$(call add_intermediate, seabios_sercon, $(CBFSTOOL))
@printf " SeaBIOS Add sercon-port file\n"
$(if $(CONFIG_UPDATE_IMAGE),-$(CBFSTOOL) $< remove -n etc/sercon-port 2>/dev/null)
$(CBFSTOOL) $< add-int -i $(CONFIG_SEABIOS_SERCON_PORT_ADDR) -n etc/sercon-port
endif

ifeq ($(CONFIG_SEABIOS_THREAD_OPTIONROMS),y)
INTERMEDIATE+=seabios_thread_optionroms
seabios_thread_optionroms: $(obj)/coreboot.pre $(CBFSTOOL)
$(call add_intermediate, seabios_thread_optionroms, $(CBFSTOOL))
@printf " SeaBIOS Thread optionroms\n"
$(if $(CONFIG_UPDATE_IMAGE),-$(CBFSTOOL) $< remove -n etc/threads 2>/dev/null)
$(CBFSTOOL) $< add-int -i 2 -n etc/threads
endif

Expand Down Expand Up @@ -194,6 +192,7 @@ payloads/external/tianocore/tianocore/Build/UEFIPAYLOAD.fd tianocore: $(DOTCONFI
CONFIG_TIANOCORE_UEFIPAYLOAD=$(CONFIG_TIANOCORE_UEFIPAYLOAD) \
CONFIG_TIANOCORE_COREBOOTPAYLOAD=$(CONFIG_TIANOCORE_COREBOOTPAYLOAD) \
CONFIG_MMCONF_BASE_ADDRESS=$(CONFIG_MMCONF_BASE_ADDRESS) \
CONFIG_TIANOCORE_BOOT_TIMEOUT=$(CONFIG_TIANOCORE_BOOT_TIMEOUT) \
GCC_CC_x86_32=$(GCC_CC_x86_32) \
GCC_CC_x86_64=$(GCC_CC_x86_64) \
GCC_CC_arm=$(GCC_CC_arm) \
Expand Down
8 changes: 8 additions & 0 deletions payloads/external/tianocore/Kconfig
Expand Up @@ -100,4 +100,12 @@ config TIANOCORE_BOOTSPLASH_FILE
If an absolute path is not given, the path will assumed to be
relative to the coreboot root directory.

config TIANOCORE_BOOT_TIMEOUT
int
default 2
help
The length of time in seconds for which the boot splash/menu prompt will be displayed.
For boards with an internal display, the default value of 2s is generally sufficient.
For boards without an internal display, a value of 5s is generally sufficient.

endif
8 changes: 6 additions & 2 deletions payloads/external/tianocore/Makefile
Expand Up @@ -34,12 +34,16 @@ ifneq ($(CONFIG_TIANOCORE_USE_8254_TIMER), y)
TIMER=-DUSE_HPET_TIMER
endif

TIMEOUT=-D PLATFORM_BOOT_TIMEOUT=$(CONFIG_TIANOCORE_BOOT_TIMEOUT)

ifeq ($(CONFIG_TIANOCORE_TARGET_IA32), y)
BUILD_STR=-q -a IA32 -t COREBOOT -p $(bootloader)/$(bootloader)Ia32.dsc -b $(BUILD_TYPE) $(TIMER) $(build_flavor)
ARCH=-a IA32 -p $(bootloader)/$(bootloader)Ia32.dsc
else
BUILD_STR=-q -a IA32 -a X64 -t COREBOOT -p $(bootloader)/$(bootloader)Ia32X64.dsc -b $(BUILD_TYPE) $(TIMER) $(build_flavor)
ARCH=-a IA32 -a X64 -p $(bootloader)/$(bootloader)Ia32X64.dsc
endif

BUILD_STR=-q $(ARCH) -t COREBOOT -b $(BUILD_TYPE) $(TIMER) $(TIMEOUT) $(build_flavor)

all: clean build

$(project_dir):
Expand Down
4 changes: 0 additions & 4 deletions payloads/libpayload/Kconfig
Expand Up @@ -375,10 +375,6 @@ config PC_KEYBOARD
default y if ARCH_X86 # uses IO
default n

config PC_KEYBOARD_AT_TRANSLATED
bool "AT Translation keyboard device"
default n

config PC_KEYBOARD_LAYOUT_US
bool "English (US) keyboard layout"
depends on PC_KEYBOARD
Expand Down
21 changes: 15 additions & 6 deletions payloads/libpayload/Makefile
Expand Up @@ -118,6 +118,11 @@ NOCOMPILE:=1
endif
endif

xcompile ?= $(obj)/xcompile
$(xcompile): $(top)/../../util/xcompile/xcompile
$< $(XGCCPATH) > $@.tmp
\mv -f $@.tmp $@ 2> /dev/null

ifeq ($(NOCOMPILE),1)
include $(TOPLEVEL)/Makefile.inc
real-all: config
Expand All @@ -126,13 +131,17 @@ else

# in addition to the dependency below, create the file if it doesn't exist
# to silence stupid warnings about a file that would be generated anyway.
$(if $(wildcard .xcompile)$(NOCOMPILE),,$(eval $(shell $(top)/../../util/xcompile/xcompile $(XGCCPATH) > .xcompile)))
$(if $(wildcard $(xcompile)),,$(shell \
mkdir -p $(dir $(xcompile)) && \
$(top)/../../util/xcompile/xcompile $(XGCCPATH) > $(xcompile) || rm -f $(xcompile)))

.xcompile: $(top)/../../util/xcompile/xcompile
$< $(XGCCPATH) > $@.tmp
\mv -f $@.tmp $@ 2> /dev/null
include $(xcompile)

-include .xcompile
ifneq ($(XCOMPILE_COMPLETE),1)
$(shell rm -f $(xcompile))
$(error $(xcompile) deleted because it's invalid. \
Restarting the build should fix that, or explain the problem)
endif

CC := $(CC_$(ARCH-y))
AS := $(AS_$(ARCH-y))
Expand Down Expand Up @@ -294,7 +303,7 @@ doxygen-clean:
rm -rf $(DOXYGEN_OUTPUT_DIR)

clean-for-update: doxygen-clean clean-for-update-target
rm -f $(allobjs) .xcompile
rm -f $(allobjs) $(xcompile)
rm -f $(DEPENDENCIES)
rmdir -p $(alldirs) 2>/dev/null >/dev/null || true

Expand Down
7 changes: 5 additions & 2 deletions payloads/libpayload/Makefile.inc
Expand Up @@ -69,7 +69,10 @@ ifeq ($(CONFIG_LP_LTO),y)
CFLAGS += -flto
endif

$(obj)/libpayload-config.h: $(KCONFIG_AUTOHEADER)
$(obj)/libpayload.config: $(DOTCONFIG)
cp $< $@

$(obj)/libpayload-config.h: $(KCONFIG_AUTOHEADER) $(obj)/libpayload.config
cmp $@ $< 2>/dev/null || cp $< $@

library-targets = $(addsuffix .a,$(addprefix $(obj)/,$(libraries))) $(obj)/libpayload.a
Expand Down Expand Up @@ -121,7 +124,7 @@ install: real-target
install -m 755 bin/lpas $(DESTDIR)/libpayload/bin
install -m 644 bin/lp.functions $(DESTDIR)/libpayload/bin
install -m 644 $(DOTCONFIG) $(DESTDIR)/libpayload/libpayload.config
install -m 755 .xcompile $(DESTDIR)/libpayload/libpayload.xcompile
install -m 755 $(xcompile) $(DESTDIR)/libpayload/libpayload.xcompile

clean-for-update-target:
rm -f $(addsuffix .a,$(addprefix $(obj)/,$(libraries))) $(obj)/libpayload.a
Expand Down
8 changes: 6 additions & 2 deletions payloads/libpayload/bin/lp.functions
Expand Up @@ -35,6 +35,10 @@ warn() {
echo "Warning: $1"
}

# For in-tree builds, allow to override the libpayload build dir.

_OBJ=${_OBJ:-$BASE/../build}

# If the user didn't specify LIBPAYLOAD_PREFIX, then preload it
# with the default prefix value

Expand All @@ -48,8 +52,8 @@ fi

if [ -f $BASE/../lib/libpayload.a ]; then
_LIBDIR=$BASE/../lib
elif [ -f $BASE/../build/libpayload.a ]; then
_LIBDIR=$BASE/../build
elif [ -f $_OBJ/libpayload.config ]; then
_LIBDIR=$_OBJ
else
_LIBDIR=$LIBPAYLOAD_PREFIX/lib
fi
Expand Down
41 changes: 26 additions & 15 deletions payloads/libpayload/bin/lpgcc
Expand Up @@ -57,11 +57,17 @@ BASE=`dirname $0`
# This will set the _LIBDIR and _INCDIR variables used below
. $BASE/lp.functions

if [ $_LIBDIR != $_OBJ ]; then
_DOTCONFIG=$BASE/../libpayload.config
_XCOMPILE=$BASE/../libpayload.xcompile
else
_DOTCONFIG=$_OBJ/libpayload.config
_XCOMPILE=$_OBJ/xcompile
fi

# include libpayload config
if [ -f $BASE/../libpayload.config ]; then
. $BASE/../libpayload.config
elif [ -f $BASE/../.config ]; then
. $BASE/../.config
if [ -f $_DOTCONFIG ]; then
. $_DOTCONFIG
else
echo "Can't find config"
exit 1
Expand Down Expand Up @@ -137,14 +143,19 @@ while [ $# -gt 0 ]; do
shift
done

_CFLAGS="$_ARCHEXTRA -nostdinc -nostdlib -I$BASE/../build -I$_INCDIR -I$_ARCHINCDIR -D__LIBPAYLOAD__=1"
_CFLAGS="$_ARCHEXTRA -nostdinc -nostdlib -I$_INCDIR -I$_ARCHINCDIR -D__LIBPAYLOAD__=1"

if [ "$CONFIG_LP_PDCURSES" = y ]; then
_CFLAGS="$_CFLAGS -I$BASE/../curses/PDCurses"
fi
if [ $_LIBDIR = $_OBJ ]; then
_CFLAGS="$_CFLAGS -I$_OBJ"

if [ "$CONFIG_LP_TINYCURSES" = y ]; then
_CFLAGS="$_CFLAGS -I$BASE/../curses"
if [ "$CONFIG_LP_PDCURSES" = y ]; then
_CFLAGS="$_CFLAGS -I$BASE/../curses/PDCurses -I$BASE/../curses/pdcurses-backend"
_CFLAGS="$_CFLAGS -I$BASE/../curses/form -I$BASE/../curses/menu"
fi

if [ "$CONFIG_LP_TINYCURSES" = y ]; then
_CFLAGS="$_CFLAGS -I$BASE/../curses"
fi
fi

# Check for the -fno-stack-protector silliness
Expand All @@ -155,7 +166,7 @@ trygccoption -fno-stack-protector
_CFLAGS="$_CFLAGS -include $BASE/../include/kconfig.h -include $BASE/../include/compiler.h"
_CFLAGS="$_CFLAGS -I`$DEFAULT_CC $_ARCHEXTRA -print-search-dirs | head -n 1 | cut -d' ' -f2`include"

_LDFLAGS="-L$BASE/../lib -L$_LIBDIR $_LDSCRIPT -static"
_LDFLAGS="-L$_LIBDIR $_LDSCRIPT -static"

if [ $DOLINK -eq 0 ]; then
if [ $DEBUGME -eq 1 ]; then
Expand All @@ -167,15 +178,15 @@ else
_LIBGCC=`$DEFAULT_CC $_ARCHEXTRA -print-libgcc-file-name`
if [ -f $_ARCHLIBDIR/head.o ]; then
HEAD_O=$_ARCHLIBDIR/head.o
elif [ -f $BASE/../build/head.o ]; then
HEAD_O=$BASE/../build/head.o
elif [ -f $_OBJ/head.o ]; then
HEAD_O=$_OBJ/head.o
else
echo "Could not find head.o"
exit 1
fi

if grep -q ARM64_A53_ERRATUM_843419=y $BASE/../libpayload.config &&
grep -q fix-cortex-a53-843419 $BASE/../libpayload.xcompile; then
if [ "$CONFIG_LP_ARM64_A53_ERRATUM_843419" = y ] &&
grep -q fix-cortex-a53-843419 $_XCOMPILE; then
_LDFLAGS="$_LDFLAGS -Wl,--fix-cortex-a53-843419"
fi

Expand Down
73 changes: 73 additions & 0 deletions payloads/libpayload/drivers/i8042/i8042.c
Expand Up @@ -28,6 +28,7 @@

#include <libpayload-config.h>
#include <libpayload.h>
#include <stdbool.h>
#include <stddef.h>

#include "i8042.h"
Expand Down Expand Up @@ -111,6 +112,19 @@ static u8 fifo_pop(struct fifo *fifo)
return ret;
}

/** Peek on the head of fifo queue.
* Returns the oldest object on the queue if any.
* In case the queue is empty 0 is returned.
* @fifo: Fifo to use
*/
static u8 fifo_peek(struct fifo *fifo)
{
if (fifo_is_empty(fifo))
return 0;

return fifo->buf[fifo->rx];
}

/** Destroys a fifo queue.
* @fifo: Fifo to use
*/
Expand Down Expand Up @@ -318,6 +332,24 @@ void i8042_write_data(u8 data)
return;
}

/**
* Send command & data to keyboard controller.
*
* @param cmd: The command to be sent.
* @param data: The data to be sent.
* Returns 0 on success, -1 on failure.
*/
static int i8042_cmd_with_data(const u8 cmd, const u8 data)
{
const int ret = i8042_cmd(cmd);
if (ret != 0)
return ret;

i8042_write_data(data);

return ret;
}

/**
* Probe for keyboard controller data and queue it.
*/
Expand Down Expand Up @@ -371,6 +403,14 @@ u8 i8042_read_data_ps2(void)
return fifo_pop(ps2_fifo);
}

/**
* Returns available keyboard data without advancing the queue.
*/
u8 i8042_peek_data_ps2(void)
{
return fifo_peek(ps2_fifo);
}

/**
* Returns available mouse data, if any.
*/
Expand Down Expand Up @@ -408,3 +448,36 @@ int i8042_wait_read_aux(void)

return (retries <= 0) ? -1 : i8042_read_data_aux();
}

/**
* Get the keyboard scancode translation state.
*
* Returns: -1 on timeout, 1 if the controller translates
* scancode set #2 to #1, and 0 if not.
*/
int i8042_get_kbd_translation(void)
{
const int cfg = i8042_cmd_with_response(I8042_CMD_RD_CMD_BYTE);
if (cfg < 0)
return cfg;

return !!(cfg & I8042_CMD_BYTE_XLATE);
}

/**
* Sets the keyboard scancode translation state.
*
* Returns: -1 on timeout, 0 otherwise.
*/
int i8042_set_kbd_translation(const bool xlate)
{
int cfg = i8042_cmd_with_response(I8042_CMD_RD_CMD_BYTE);
if (cfg < 0)
return cfg;

if (xlate)
cfg |= I8042_CMD_BYTE_XLATE;
else
cfg &= ~I8042_CMD_BYTE_XLATE;
return i8042_cmd_with_data(I8042_CMD_WR_CMD_BYTE, cfg);
}
3 changes: 0 additions & 3 deletions payloads/libpayload/drivers/i8042/i8042.h
Expand Up @@ -56,9 +56,6 @@
#define I8042_MODE_SCROLL_LOCK_ON (1 << 0)
#define I8042_MODE_SCROLL_LOCK_OFF (0 << 0)
#define I8042_KBCMD_SET_SCANCODE 0xf0
#define I8042_SCANCODE_SET_1 (1)
#define I8042_SCANCODE_SET_2 (2)
#define I8042_SCANCODE_SET_3 (3)
#define I8042_KBCMD_SET_TYPEMATIC 0xf3
#define I8042_KBCMD_EN 0xf4
#define I8042_KBCMD_DEFAULT_DIS 0xf5
Expand Down
329 changes: 255 additions & 74 deletions payloads/libpayload/drivers/i8042/keyboard.c
Expand Up @@ -28,13 +28,20 @@
*/

#include <stdbool.h>
#include <stdint.h>

#include <keycodes.h>
#include <libpayload-config.h>
#include <libpayload.h>

#include "i8042.h"

#ifdef DEBUG
#define debug(x...) printf(x)
#else
#define debug(x...) do {} while (0)
#endif

#define POWER_BUTTON 0x90
#define MEDIA_KEY_PREFIX 0xE0

Expand Down Expand Up @@ -171,16 +178,253 @@ static struct layout_maps keyboard_layouts[] = {
#endif
};

static void keyboard_drain_input(void)
{
while (i8042_data_ready_ps2())
(void)i8042_read_data_ps2();
}

static bool keyboard_cmd(unsigned char cmd)
{
const uint64_t timeout_us = cmd == I8042_KBCMD_RESET ? 1*1000*1000 : 200*1000;
const uint64_t start_time = timer_us(0);

i8042_write_data(cmd);

return i8042_wait_read_ps2() == 0xfa;
do {
if (!i8042_data_ready_ps2()) {
udelay(50);
continue;
}

const uint8_t data = i8042_read_data_ps2();
switch (data) {
case 0xfa:
return true;
case 0xfe:
return false;
default:
/* Warn only if we already disabled keyboard input. */
if (cmd != I8042_KBCMD_DEFAULT_DIS)
debug("WARNING: Keyboard sent spurious 0x%02x.\n", data);
break;
}
} while (timer_us(start_time) < timeout_us);

debug("ERROR: Keyboard command timed out.\n");
return false;
}

static bool set_scancode_set(const unsigned char set)
{
bool ret;

if (set < 1 || set > 3)
return false;

ret = keyboard_cmd(I8042_KBCMD_SET_SCANCODE);
if (!ret) {
debug("ERROR: Keyboard set scancode failed!\n");
return ret;
}

ret = keyboard_cmd(set);
if (!ret) {
debug("ERROR: Keyboard scancode set#%u failed!\n", set);
return ret;
}

return ret;
}

static enum keyboard_state {
STATE_INIT = 0,
STATE_SIMPLIFIED_INIT,
STATE_DISABLE_SCAN,
STATE_DRAIN_INPUT,
STATE_DISABLE_TRANSLATION,
STATE_START_SELF_TEST,
STATE_SELF_TEST,
STATE_CONFIGURE,
STATE_CONFIGURE_SET1,
STATE_ENABLE_TRANSLATION,
STATE_ENABLE_SCAN,
STATE_RUNNING,
STATE_IGNORE,
} keyboard_state;

#define STATE_NAMES_ENTRY(name) [STATE_##name] = #name
static const char *const state_names[] = {
STATE_NAMES_ENTRY(INIT),
STATE_NAMES_ENTRY(SIMPLIFIED_INIT),
STATE_NAMES_ENTRY(DISABLE_SCAN),
STATE_NAMES_ENTRY(DRAIN_INPUT),
STATE_NAMES_ENTRY(DISABLE_TRANSLATION),
STATE_NAMES_ENTRY(START_SELF_TEST),
STATE_NAMES_ENTRY(SELF_TEST),
STATE_NAMES_ENTRY(CONFIGURE),
STATE_NAMES_ENTRY(CONFIGURE_SET1),
STATE_NAMES_ENTRY(ENABLE_TRANSLATION),
STATE_NAMES_ENTRY(ENABLE_SCAN),
STATE_NAMES_ENTRY(RUNNING),
STATE_NAMES_ENTRY(IGNORE),
};

__attribute__((unused))
static const char *state_name(enum keyboard_state state)
{
if (state >= ARRAY_SIZE(state_names) || !state_names[state])
return "<unknown>";
return state_names[state];
}

static uint64_t keyboard_time;
static uint64_t state_time;

static void keyboard_poll(void)
{
enum keyboard_state next_state = keyboard_state;
unsigned int i;

switch (keyboard_state) {

case STATE_INIT:
/* Wait until keyboard_init() has been called. */
break;

case STATE_SIMPLIFIED_INIT:
/* On the first try, start opportunistically, do
the first steps at once and skip the self-test. */
(void)keyboard_cmd(I8042_KBCMD_DEFAULT_DIS);
keyboard_drain_input();
(void)i8042_set_kbd_translation(false);
next_state = STATE_CONFIGURE;
break;

case STATE_DISABLE_SCAN:
(void)keyboard_cmd(I8042_KBCMD_DEFAULT_DIS);
next_state = STATE_DRAIN_INPUT;
break;

case STATE_DRAIN_INPUT:
/* Limit number of bytes drained per poll. */
for (i = 0; i < 50 && i8042_data_ready_ps2(); ++i)
(void)i8042_read_data_ps2();
if (i == 0)
next_state = STATE_DISABLE_TRANSLATION;
break;

case STATE_DISABLE_TRANSLATION:
/* Be opportunistic and assume it's disabled on failure. */
(void)i8042_set_kbd_translation(false);
next_state = STATE_START_SELF_TEST;
break;

case STATE_START_SELF_TEST:
if (!keyboard_cmd(I8042_KBCMD_RESET))
debug("ERROR: Keyboard self-test couldn't be started.\n");
/* We ignore errors and always move to the self-test state
which will simply try again if necessary. */
next_state = STATE_SELF_TEST;
break;

case STATE_SELF_TEST:
if (!i8042_data_ready_ps2()) {
if (timer_us(state_time) > 5*1000*1000) {
debug("WARNING: Keyboard self-test timed out.\n");
next_state = STATE_DISABLE_SCAN;
}
break;
}

const uint8_t self_test_result = i8042_read_data_ps2();
switch (self_test_result) {
case 0xaa:
debug("INFO: Keyboard self-test succeeded.\n");
next_state = STATE_CONFIGURE;
break;
case 0xfc:
case 0xfd:
/* Failure. Try again. */
debug("WARNING: Keyboard self-test failed.\n");
next_state = STATE_START_SELF_TEST;
break;
default:
debug("WARNING: Keyboard self-test received spurious 0x%02x\n",
self_test_result);
break;
}
break;

case STATE_CONFIGURE:
if (set_scancode_set(2))
next_state = STATE_ENABLE_TRANSLATION;
else
next_state = STATE_CONFIGURE_SET1;
break;

case STATE_CONFIGURE_SET1:
if (!set_scancode_set(1)) {
debug("ERROR: Keyboard failed to set any scancode set.\n");
next_state = STATE_DISABLE_SCAN;
break;
}

next_state = STATE_ENABLE_SCAN;
break;

case STATE_ENABLE_TRANSLATION:
if (i8042_set_kbd_translation(true) != 0) {
debug("ERROR: Keyboard controller set translation failed!\n");
next_state = STATE_DISABLE_SCAN;
break;
}

next_state = STATE_ENABLE_SCAN;
break;

case STATE_ENABLE_SCAN:
if (!keyboard_cmd(I8042_KBCMD_EN)) {
debug("ERROR: Keyboard enable scanning failed!\n");
next_state = STATE_DISABLE_SCAN;
break;
}

next_state = STATE_RUNNING;
break;

case STATE_RUNNING:
/* TODO: Use echo command to detect detach. */
break;

case STATE_IGNORE:
/* TODO: Try again after timeout if it ever seems useful. */
break;

}

switch (next_state) {
case STATE_INIT:
case STATE_RUNNING:
case STATE_IGNORE:
break;
default:
if (timer_us(keyboard_time) > 30*1000*1000)
next_state = STATE_IGNORE;
break;
}

if (keyboard_state != next_state) {
debug("INFO: Keyboard advancing state to '%s'.\n", state_name(next_state));
keyboard_state = next_state;
state_time = timer_us(0);
}
}

bool keyboard_havechar(void)
{
return i8042_data_ready_ps2();
keyboard_poll();
return keyboard_state == STATE_RUNNING && i8042_data_ready_ps2();
}

unsigned char keyboard_get_scancode(void)
Expand Down Expand Up @@ -313,83 +557,22 @@ static struct console_input_driver cons = {
.input_type = CONSOLE_INPUT_TYPE_EC,
};

/* Enable keyboard translated */
static bool enable_translated(void)
{
if (!i8042_cmd(I8042_CMD_RD_CMD_BYTE)) {
int cmd = i8042_read_data_ps2();
cmd |= I8042_CMD_BYTE_XLATE;
if (!i8042_cmd(I8042_CMD_WR_CMD_BYTE)) {
i8042_write_data(cmd);
} else {
printf("ERROR: i8042_cmd WR_CMD failed!\n");
return false;
}
} else {
printf("ERROR: i8042_cmd RD_CMD failed!\n");
return false;
}
return true;
}

/* Set scancode set 1 */
static bool set_scancode_set(void)
{
bool ret;
ret = keyboard_cmd(I8042_KBCMD_SET_SCANCODE);
if (!ret) {
printf("ERROR: Keyboard set scancode failed!\n");
return ret;
}

ret = keyboard_cmd(I8042_SCANCODE_SET_1);
if (!ret) {
printf("ERROR: Keyboard scancode set#1 failed!\n");
return ret;
}

/*
* Set default parameters.
* Fix for broken QEMU PS/2 make scancodes.
*/
ret = keyboard_cmd(I8042_KBCMD_SET_DEFAULT);
if (!ret) {
printf("ERROR: Keyboard set default params failed!\n");
return ret;
}

/* Enable scanning */
ret = keyboard_cmd(I8042_KBCMD_EN);
if (!ret) {
printf("ERROR: Keyboard enable scanning failed!\n");
return ret;
}

return ret;
}

void keyboard_init(void)
{
if (keyboard_state != STATE_INIT)
return;

map = &keyboard_layouts[0];

/* Initialized keyboard controller. */
if (!i8042_probe() || !i8042_has_ps2())
return;

/* Empty keyboard buffer */
while (keyboard_havechar())
keyboard_getchar();

/* Enable first PS/2 port */
i8042_cmd(I8042_CMD_EN_KB);

if (CONFIG(LP_PC_KEYBOARD_AT_TRANSLATED)) {
if (!enable_translated())
return;
} else {
if (!set_scancode_set())
return;
}
keyboard_state = STATE_SIMPLIFIED_INIT;
keyboard_time = state_time = timer_us(0);

console_add_input_driver(&cons);
}
Expand All @@ -404,20 +587,18 @@ void keyboard_disconnect(void)
if (!i8042_has_ps2())
return;

/* Empty keyboard buffer */
while (keyboard_havechar())
keyboard_getchar();

/* Disable scanning */
keyboard_cmd(I8042_KBCMD_DEFAULT_DIS);
keyboard_drain_input();

/* Send keyboard disconnect command */
i8042_cmd(I8042_CMD_DIS_KB);

/* Hand off with empty buffer */
while (keyboard_havechar())
keyboard_getchar();
keyboard_drain_input();

/* Release keyboard controller driver */
i8042_close();

keyboard_state = STATE_INIT;
}
4 changes: 4 additions & 0 deletions payloads/libpayload/include/libpayload.h
Expand Up @@ -233,11 +233,15 @@ u8 i8042_data_ready_ps2(void);
u8 i8042_data_ready_aux(void);

u8 i8042_read_data_ps2(void);
u8 i8042_peek_data_ps2(void);
u8 i8042_read_data_aux(void);

int i8042_wait_read_ps2(void);
int i8042_wait_read_aux(void);

int i8042_get_kbd_translation(void);
int i8042_set_kbd_translation(bool xlate);

/** @} */

/**
Expand Down
2 changes: 1 addition & 1 deletion payloads/libpayload/sample/Makefile
Expand Up @@ -28,7 +28,7 @@

# Sample libpayload Makefile.
include ../.config
include ../.xcompile
include ../build/xcompile

ARCH-$(CONFIG_LP_ARCH_ARM) := arm
ARCH-$(CONFIG_LP_ARCH_X86) := x86_32
Expand Down
2 changes: 1 addition & 1 deletion payloads/nvramcui/nvramcui.c
Expand Up @@ -37,7 +37,7 @@ static int max(int x, int y)
return y;
}

void render_form(FORM *form)
static void render_form(FORM *form)
{
int y, x, line;
WINDOW *w = form_win(form);
Expand Down
11 changes: 10 additions & 1 deletion src/acpi/Kconfig
Expand Up @@ -24,8 +24,11 @@ config ACPI_INTEL_HARDWARE_SLEEP_VALUES
Provide common definitions for Intel hardware PM1_CNT register sleep
values.

config ACPI_NO_SMI_GNVS
config ACPI_SOC_NVS
bool
help
Set to indicate <soc/nvs.h> exists for the platform with a definition
for global_nvs.

config ACPI_NO_PCAT_8259
bool
Expand All @@ -37,3 +40,9 @@ config HAVE_ACPI_TABLES
help
This variable specifies whether a given board has ACPI table support.
It is usually set in mainboard/*/Kconfig.

config ACPI_LPIT
bool
depends on HAVE_ACPI_TABLES
help
Selected by platforms that support and fill Intel Low Power Idle Table.
6 changes: 3 additions & 3 deletions src/acpi/Makefile.inc
Expand Up @@ -3,20 +3,20 @@
ifeq ($(CONFIG_HAVE_ACPI_TABLES),y)

ramstage-y += acpi.c
ramstage-y += acpi_pm.c
ramstage-y += acpigen.c
ramstage-y += acpigen_dptf.c
ramstage-y += acpigen_dsm.c
ramstage-y += acpigen_ps2_keybd.c
ramstage-y += acpigen_usb.c
ramstage-y += device.c
ramstage-$(CONFIG_CHROMEOS) += chromeos-gnvs.c
ramstage-y += gnvs.c
ramstage-$(CONFIG_ACPI_SOC_NVS) += gnvs.c
ramstage-y += pld.c
ramstage-y += sata.c
ramstage-y += soundwire.c

postcar-y += acpi_pm.c
all-y += acpi_pm.c
smm-y += acpi_pm.c

ifneq ($(wildcard src/mainboard/$(MAINBOARDDIR)/acpi_tables.c),)
ramstage-srcs += src/mainboard/$(MAINBOARDDIR)/acpi_tables.c
Expand Down
89 changes: 89 additions & 0 deletions src/acpi/acpi.c
Expand Up @@ -878,6 +878,35 @@ void acpi_create_ivrs(acpi_ivrs_t *ivrs,
header->checksum = acpi_checksum((void *)ivrs, header->length);
}

void acpi_create_crat(struct acpi_crat_header *crat,
unsigned long (*acpi_fill_crat)(struct acpi_crat_header *crat_struct,
unsigned long current))
{
acpi_header_t *header = &(crat->header);
unsigned long current = (unsigned long)crat + sizeof(struct acpi_crat_header);

memset((void *)crat, 0, sizeof(struct acpi_crat_header));

if (!header)
return;

/* Fill out header fields. */
memcpy(header->signature, "CRAT", 4);
memcpy(header->oem_id, OEM_ID, 6);
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
memcpy(header->asl_compiler_id, ASLC, 4);

header->asl_compiler_revision = asl_revision;
header->length = sizeof(struct acpi_crat_header);
header->revision = get_acpi_table_revision(CRAT);

current = acpi_fill_crat(crat, current);

/* (Re)calculate length and checksum. */
header->length = current - (unsigned long)crat;
header->checksum = acpi_checksum((void *)crat, header->length);
}

unsigned long acpi_write_hpet(const struct device *device, unsigned long current,
acpi_rsdp_t *rsdp)
{
Expand Down Expand Up @@ -1264,6 +1293,44 @@ void acpi_create_fadt(acpi_fadt_t *fadt, acpi_facs_t *facs, void *dsdt)
acpi_checksum((void *) fadt, header->length);
}

void acpi_create_lpit(acpi_lpit_t *lpit)
{
acpi_header_t *header = &(lpit->header);
unsigned long current = (unsigned long)lpit + sizeof(acpi_lpit_t);

memset((void *)lpit, 0, sizeof(acpi_lpit_t));

if (!header)
return;

/* Fill out header fields. */
memcpy(header->signature, "LPIT", 4);
memcpy(header->oem_id, OEM_ID, 6);
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
memcpy(header->asl_compiler_id, ASLC, 4);

header->asl_compiler_revision = asl_revision;
header->revision = get_acpi_table_revision(LPIT);
header->oem_revision = 42;
header->length = sizeof(acpi_lpit_t);

current = acpi_fill_lpit(current);

/* (Re)calculate length and checksum. */
header->length = current - (unsigned long)lpit;
header->checksum = acpi_checksum((void *)lpit, header->length);
}

unsigned long acpi_create_lpi_desc_ncst(acpi_lpi_desc_ncst_t *lpi_desc, uint16_t uid)
{
memset(lpi_desc, 0, sizeof(acpi_lpi_desc_ncst_t));
lpi_desc->header.length = sizeof(acpi_lpi_desc_ncst_t);
lpi_desc->header.type = ACPI_LPI_DESC_TYPE_NATIVE_CSTATE;
lpi_desc->header.uid = uid;

return lpi_desc->header.length;
}

unsigned long __weak fw_cfg_acpi_tables(unsigned long start)
{
return 0;
Expand All @@ -1284,6 +1351,7 @@ unsigned long write_acpi_tables(unsigned long start)
acpi_tcpa_t *tcpa;
acpi_tpm2_t *tpm2;
acpi_madt_t *madt;
acpi_lpit_t *lpit;
struct device *dev;
unsigned long fw;
size_t slic_size, dsdt_size;
Expand Down Expand Up @@ -1404,6 +1472,10 @@ unsigned long write_acpi_tables(unsigned long start)
current += sizeof(acpi_header_t);

acpigen_set_current((char *) current);

if (CONFIG(ACPI_SOC_NVS))
acpi_fill_gnvs();

for (dev = all_devices; dev; dev = dev->next)
if (dev->ops && dev->ops->acpi_inject_dsdt)
dev->ops->acpi_inject_dsdt(dev);
Expand Down Expand Up @@ -1478,6 +1550,18 @@ unsigned long write_acpi_tables(unsigned long start)
}
}

if (CONFIG(ACPI_LPIT)) {
printk(BIOS_DEBUG, "ACPI: * LPIT\n");

lpit = (acpi_lpit_t *)current;
acpi_create_lpit(lpit);
if (lpit->header.length >= sizeof(acpi_lpit_t)) {
current += lpit->header.length;
current = acpi_align_current(current);
acpi_add_table(rsdp, lpit);
}
}

printk(BIOS_DEBUG, "ACPI: * MADT\n");

madt = (acpi_madt_t *) current;
Expand All @@ -1486,6 +1570,7 @@ unsigned long write_acpi_tables(unsigned long start)
current += madt->header.length;
acpi_add_table(rsdp, madt);
}

current = acpi_align_current(current);

printk(BIOS_DEBUG, "current = %lx\n", current);
Expand Down Expand Up @@ -1636,6 +1721,10 @@ int get_acpi_table_revision(enum acpi_tables table)
return 5;
case BERT:
return 1;
case CRAT:
return 1;
case LPIT: /* ACPI 5.1 up to 6.3: 0 */
return 0;
default:
return -1;
}
Expand Down
65 changes: 42 additions & 23 deletions src/acpi/acpi_pm.c
@@ -1,32 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0-only */

#include <acpi/acpi.h>
#include <acpi/acpi_pm.h>
#include <cbmem.h>
#include <console/console.h>
#include <romstage_handoff.h>
#include <smbios.h>

/* This is filled with acpi_handoff_wakeup_s3() call early in ramstage. */
static int acpi_slp_type = -1;

static void acpi_handoff_wakeup(void)
{
if (acpi_slp_type < 0) {
if (romstage_handoff_is_resume()) {
printk(BIOS_DEBUG, "S3 Resume\n");
acpi_slp_type = ACPI_S3;
} else {
printk(BIOS_DEBUG, "Normal boot\n");
acpi_slp_type = ACPI_S0;
}
}
}

int acpi_handoff_wakeup_s3(void)
{
acpi_handoff_wakeup();
return (acpi_slp_type == ACPI_S3);
}

void __weak mainboard_suspend_resume(void)
{
}
Expand All @@ -48,3 +27,43 @@ uint8_t acpi_get_preferred_pm_profile(void)
return PM_UNSPECIFIED;
}
}

struct chipset_power_state *acpi_get_pm_state(void)
{
static struct chipset_power_state *acpi_pm_state;
if (acpi_pm_state)
return acpi_pm_state;

acpi_pm_state = cbmem_find(CBMEM_ID_POWER_STATE);
return acpi_pm_state;
}

int acpi_pm_state_for_elog(const struct chipset_power_state **ps)
{
*ps = acpi_get_pm_state();
if (!*ps) {
printk(BIOS_ERR, "No CBMEM_ID_POWER_STATE entry, no event recorded in ELOG.\n");
return -1;
}
return 0;
}

int acpi_pm_state_for_rtc(const struct chipset_power_state **ps)
{
*ps = acpi_get_pm_state();
if (!*ps) {
printk(BIOS_ERR, "No CBMEM_ID_POWER_STATE entry, RTC init aborted.\n");
return -1;
}
return 0;
}

int acpi_pm_state_for_wake(const struct chipset_power_state **ps)
{
*ps = acpi_get_pm_state();
if (!*ps) {
printk(BIOS_ERR, "No CBMEM_ID_POWER_STATE entry, wake source unknown.\n");
return -1;
}
return 0;
}
25 changes: 23 additions & 2 deletions src/acpi/chromeos-gnvs.c
Expand Up @@ -2,11 +2,13 @@

#include <acpi/acpi_gnvs.h>
#include <ec/google/chromeec/ec.h>
#include <smbios.h>
#include <vendorcode/google/chromeos/gnvs.h>

void gnvs_assign_chromeos(void)
void gnvs_assign_chromeos(void *gnvs_section)
{
chromeos_acpi_t *gnvs_chromeos = gnvs_chromeos_ptr();
chromeos_acpi_t *gnvs_chromeos = gnvs_section;

chromeos_init_chromeos_acpi(gnvs_chromeos);

/* EC can override to ECFW_RW. */
Expand All @@ -15,3 +17,22 @@ void gnvs_assign_chromeos(void)
if (CONFIG(EC_GOOGLE_CHROMEEC) && !google_ec_running_ro())
gnvs_chromeos->vbt2 = ACTIVE_ECFW_RW;
}

void gnvs_set_ecfw_rw(void)
{
chromeos_acpi_t *gnvs_chromeos = chromeos_get_chromeos_acpi();
if (!gnvs_chromeos)
return;

gnvs_chromeos->vbt2 = ACTIVE_ECFW_RW;
}

void smbios_type0_bios_version(uintptr_t address)
{
chromeos_acpi_t *gnvs_chromeos = chromeos_get_chromeos_acpi();
if (!gnvs_chromeos)
return;

/* Location of smbios_type0.bios_version() string filled with spaces. */
gnvs_chromeos->vbt10 = address;
}
50 changes: 26 additions & 24 deletions src/acpi/gnvs.c
Expand Up @@ -4,10 +4,13 @@
#include <acpi/acpigen.h>
#include <cbmem.h>
#include <console/console.h>
#include <soc/nvs.h>
#include <stdint.h>
#include <string.h>
#include <types.h>
#include <vendorcode/google/chromeos/gnvs.h>

static void *gnvs;
static struct global_nvs *gnvs;

void *acpi_get_gnvs(void)
{
Expand All @@ -22,48 +25,47 @@ void *acpi_get_gnvs(void)
return NULL;
}

static void gnvs_assign_cbmc(void)
{
uint32_t *gnvs_cbmc = gnvs_cbmc_ptr();
if (gnvs_cbmc)
*gnvs_cbmc = (uintptr_t)cbmem_find(CBMEM_ID_CONSOLE);
}
__weak void soc_fill_gnvs(struct global_nvs *gnvs_) { }
__weak void mainboard_fill_gnvs(struct global_nvs *gnvs_) { }

void *gnvs_get_or_create(void)
void acpi_create_gnvs(void)
{
size_t gnvs_size;

if (gnvs)
return gnvs;

gnvs = cbmem_find(CBMEM_ID_ACPI_GNVS);
if (gnvs)
return gnvs;
if (cbmem_find(CBMEM_ID_ACPI_GNVS))
return;

gnvs_size = gnvs_size_of_array();
/* Match with OpRegion declared in global_nvs.asl. */
gnvs_size = sizeof(struct global_nvs);
if (gnvs_size < 0x100)
gnvs_size = 0x100;
if (gnvs_size > 0x1000)
gnvs_size = 0x2000;
else if (CONFIG(MAINBOARD_HAS_CHROMEOS))
gnvs_size = 0x1000;

gnvs = cbmem_add(CBMEM_ID_ACPI_GNVS, gnvs_size);
if (!gnvs)
return gnvs;
return;

memset(gnvs, 0, gnvs_size);

if (CONFIG(CONSOLE_CBMEM))
gnvs_assign_cbmc();
gnvs->cbmc = (uintptr_t)cbmem_find(CBMEM_ID_CONSOLE);

if (CONFIG(CHROMEOS))
gnvs_assign_chromeos();

return gnvs;
gnvs_assign_chromeos((u8 *)gnvs + GNVS_CHROMEOS_ACPI_OFFSET);
}

void acpi_inject_nvsa(void)
void acpi_fill_gnvs(void)
{
uintptr_t gnvs_address = (uintptr_t)acpi_get_gnvs();
if (!gnvs_address)
if (!gnvs)
return;

soc_fill_gnvs(gnvs);
mainboard_fill_gnvs(gnvs);

acpigen_write_scope("\\");
acpigen_write_name_dword("NVSA", gnvs_address);
acpigen_write_name_dword("NVSA", (uintptr_t)gnvs);
acpigen_pop_len();
}
4 changes: 4 additions & 0 deletions src/arch/arm64/armv8/Kconfig
Expand Up @@ -14,6 +14,8 @@ config ARCH_RAMSTAGE_ARMV8_64
bool
select ARCH_RAMSTAGE_ARM64

if ARCH_ARM64

config ARCH_ARMV8_EXTENSION
int
default 0
Expand All @@ -25,3 +27,5 @@ config ARCH_ARMV8_EXTENSION
All ARMv8 implementations are downwards-compatible, so this does not
need to be changed unless specific features (e.g. new instructions)
are used by the SoC's coreboot code.

endif # ARCH_ARM64
29 changes: 3 additions & 26 deletions src/arch/x86/Makefile.inc
Expand Up @@ -45,25 +45,6 @@ pci$(stripped_vgabios_dgpu_id).rom-type := optionrom
# common support for early assembly includes
###############################################################################

# Chipset specific assembly stubs in the romstage program flow. Certain
# boards have more than one assembly stub so collect those and put them
# into a single generated file.
crt0s = $(cpu_incs-y)

$(objgenerated)/assembly.inc: build-dirs $$(crt0s)
@printf " GEN $(subst $(obj)/,,$(@))\n"
printf '$(foreach crt0,$(crt0s),#include "$(crt0)"\n)' > $@


define early_x86_assembly_entry_rule
# $1 stage name
# Add the assembly file that pulls in the rest of the dependencies in
# the right order. Make sure the auto generated assembly.inc is a proper
# dependency.
$(1)-y += assembly_entry.S
$(call src-to-obj,$(1),$(dir)/assembly_entry.S): $(objgenerated)/assembly.inc
endef

define early_x86_stage
# $1 stage name
# $2 oformat
Expand Down Expand Up @@ -122,6 +103,7 @@ endif # CONFIG_ARCH_BOOTBLOCK_X86_32 / CONFIG_ARCH_BOOTBLOCK_X86_64

ifeq ($(CONFIG_ARCH_VERSTAGE_X86_32)$(CONFIG_ARCH_VERSTAGE_X86_64),y)

verstage-y += assembly_entry.S
verstage-y += boot.c
verstage-y += post.c
verstage-$(CONFIG_VBOOT_SEPARATE_VERSTAGE) += gdt_init.S
Expand All @@ -143,8 +125,6 @@ verstage-$(CONFIG_COLLECT_TIMESTAMPS_TSC) += timestamp.c

verstage-libs ?=

$(eval $(call early_x86_assembly_entry_rule,verstage))

ifeq ($(CONFIG_ARCH_VERSTAGE_X86_32),y)
$(eval $(call early_x86_stage,verstage,elf32-i386))
else
Expand All @@ -159,6 +139,7 @@ endif # CONFIG_ARCH_VERSTAGE_X86_32 / CONFIG_ARCH_VERSTAGE_X86_64

ifeq ($(CONFIG_ARCH_ROMSTAGE_X86_32)$(CONFIG_ARCH_ROMSTAGE_X86_64),y)

romstage-y += assembly_entry.S
romstage-y += boot.c
romstage-y += post.c
romstage-y += gdt_init.S
Expand All @@ -176,8 +157,6 @@ romstage-$(CONFIG_HAVE_CF9_RESET) += cf9_reset.c
romstage-srcs += $(wildcard $(src)/mainboard/$(MAINBOARDDIR)/romstage.c)
romstage-libs ?=

$(eval $(call early_x86_assembly_entry_rule,romstage))

ifeq ($(CONFIG_ARCH_ROMSTAGE_X86_32),y)
$(eval $(call early_x86_stage,romstage,elf32-i386))
else
Expand Down Expand Up @@ -315,6 +294,4 @@ smm-y += memmove.c
smm-y += memset.c
smm-$(CONFIG_X86_TOP4G_BOOTMEDIA_MAP) += mmap_boot.c

ifneq ($(wildcard src/mainboard/$(MAINBOARDDIR)/smihandler.c),)
smm-srcs += src/mainboard/$(MAINBOARDDIR)/smihandler.c
endif
smm-srcs += $(wildcard src/mainboard/$(MAINBOARDDIR)/smihandler.c)
4 changes: 0 additions & 4 deletions src/arch/x86/acpi_s3.c
Expand Up @@ -5,7 +5,6 @@
#include <acpi/acpi.h>
#include <arch/cpu.h>
#include <commonlib/helpers.h>
#include <cpu/x86/smm.h>
#include <fallback.h>
#include <timestamp.h>

Expand All @@ -18,9 +17,6 @@ extern unsigned int __wakeup_size;

void __noreturn acpi_resume(void *wake_vec)
{
/* Restore GNVS pointer in SMM if found. */
apm_control(APM_CNT_GNVS_UPDATE);

/* Call mainboard resume handler first, if defined. */
mainboard_suspend_resume();

Expand Down
9 changes: 7 additions & 2 deletions src/arch/x86/bootblock.ld
Expand Up @@ -19,14 +19,19 @@ SECTIONS {
.id (.): {
KEEP(*(.id));
}
_ID_SECTION = 0xffffff80 - SIZEOF(.id);

. = 0xffffffc0;
/* Flashrom and FILO have two alternatives for the location of .id section. */
_ID_SECTION_END = SIZEOF(.fit_pointer) && SIZEOF(.id) > 0x28 ? 0xffffff80 : _X86_RESET_VECTOR;
_ID_SECTION = _ID_SECTION_END - SIZEOF(.id);

. = _FIT_POINTER;
.fit_pointer (.): {
KEEP(*(.fit_pointer));
}
_FIT_POINTER = SIZEOF(.fit_pointer) ? 0xffffffc0 : _X86_RESET_VECTOR;

. = 0xfffffff0;
_X86_RESET_VECTOR = .;
.reset . : {
*(.reset);
. = 15;
Expand Down
2 changes: 1 addition & 1 deletion src/arch/x86/bootblock_crt0.S
Expand Up @@ -10,7 +10,7 @@

#include <cpu/x86/cr.h>

.section .text._start
.section .init._start, "ax", @progbits

/*
* Include the old code for reset vector and protected mode entry. That code has
Expand Down
15 changes: 14 additions & 1 deletion src/arch/x86/car.ld
Expand Up @@ -7,6 +7,7 @@
. = CONFIG_DCACHE_RAM_BASE;
.car.data . (NOLOAD) : {
_car_region_start = . ;
. += CONFIG_FSP_M_RC_HEAP_SIZE;
#if CONFIG(PAGING_IN_CACHE_AS_RAM)
/* Page table pre-allocation. CONFIG_DCACHE_RAM_BASE should be 4KiB
* aligned when using this option. */
Expand Down Expand Up @@ -80,13 +81,25 @@
REGION(asan_shadow, ., _shadow_size, ARCH_POINTER_ALIGN_SIZE)
#endif
_car_unallocated_start = .;
_car_region_end = . + CONFIG_DCACHE_RAM_SIZE - (. - _car_region_start);
_car_region_end = . + CONFIG_DCACHE_RAM_SIZE - (. - _car_region_start)
- CONFIG_FSP_T_RESERVED_SIZE;
}

. = _car_region_start;
.car.fspm_rc_heap . (NOLOAD) : {
. += CONFIG_FSP_M_RC_HEAP_SIZE;
}

. = _car_region_end;
.car.mrc_var . (NOLOAD) : {
. += CONFIG_DCACHE_RAM_MRC_VAR_SIZE;
}

. = _car_region_end;
.car.fspt_reserved . (NOLOAD) : {
. += CONFIG_FSP_T_RESERVED_SIZE;
}

#if ENV_BOOTBLOCK
_car_mtrr_end = .;
_car_mtrr_start = _car_region_start;
Expand Down
7 changes: 5 additions & 2 deletions src/arch/x86/gdt_init.S
@@ -1,7 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0-only */

.code32
.section ".text._gdt_", "ax", @progbits

.section .init, "ax", @progbits

.section .init._gdt_, "ax", @progbits

.globl gdt_init
gdt_init:
Expand All @@ -17,7 +20,7 @@ gdtptr:

#ifdef __x86_64__
.code64
.section ".text._gdt64_", "ax", @progbits
.section .init._gdt64_, "ax", @progbits
.globl gdt_init64
gdt_init64:
/* Workaround a bug in the assembler.
Expand Down
6 changes: 5 additions & 1 deletion src/arch/x86/postcar.c
Expand Up @@ -23,8 +23,12 @@ void main(void)
/*
* CBMEM needs to be recovered because timestamps rely on
* the cbmem infrastructure being around. Explicitly recover it.
*
* On some platforms CBMEM needs to be initialized earlier.
* Use cbmem_online() to avoid init CBMEM twice.
*/
cbmem_initialize();
if (!cbmem_online())
cbmem_initialize();

timestamp_add_now(TS_START_POSTCAR);

Expand Down
30 changes: 21 additions & 9 deletions src/arch/x86/smbios.c
Expand Up @@ -16,9 +16,6 @@
#include <device/pci_ids.h>
#include <device/pci_def.h>
#include <device/pci.h>
#if CONFIG(CHROMEOS)
#include <vendorcode/google/chromeos/gnvs.h>
#endif
#include <drivers/vpd/vpd.h>
#include <stdlib.h>

Expand Down Expand Up @@ -330,8 +327,22 @@ static int create_smbios_type17_for_dimm(struct dimm_info *dimm,
t->minimum_voltage = dimm->vdd_voltage;
t->maximum_voltage = dimm->vdd_voltage;

/* Fill in type detail */
switch (dimm->mod_type) {
case SPD_RDIMM:
case SPD_MINI_RDIMM:
t->type_detail = MEMORY_TYPE_DETAIL_REGISTERED;
break;
case SPD_UDIMM:
case SPD_MINI_UDIMM:
t->type_detail = MEMORY_TYPE_DETAIL_UNBUFFERED;
break;
default:
t->type_detail = MEMORY_TYPE_DETAIL_UNKNOWN;
break;
}
/* Synchronous = 1 */
t->type_detail = MEMORY_TYPE_DETAIL_SYNCHRONOUS;
t->type_detail |= MEMORY_TYPE_DETAIL_SYNCHRONOUS;
/* no handle for error information */
t->memory_error_information_handle = 0xFFFE;
t->attributes = dimm->rank_per_dimm;
Expand Down Expand Up @@ -411,11 +422,12 @@ static int smbios_write_type0(unsigned long *current, int handle)
t->vendor = smbios_add_string(t->eos, "coreboot");
t->bios_release_date = smbios_add_string(t->eos, coreboot_dmi_date);

#if CONFIG(CHROMEOS) && CONFIG(HAVE_ACPI_TABLES)
u32 version_offset = (u32)smbios_string_table_len(t->eos);
/* SMBIOS offsets start at 1 rather than 0 */
chromeos_get_chromeos_acpi()->vbt10 = (uintptr_t)t->eos + (version_offset - 1);
#endif
if (CONFIG(CHROMEOS)) {
uintptr_t version_address = (uintptr_t)t->eos;
/* SMBIOS offsets start at 1 rather than 0 */
version_address += (u32)smbios_string_table_len(t->eos) - 1;
smbios_type0_bios_version(version_address);
}
t->bios_version = smbios_add_string(t->eos, get_bios_version());
uint32_t rom_size = CONFIG_ROM_SIZE;
rom_size = MIN(CONFIG_ROM_SIZE, 16 * MiB);
Expand Down
2 changes: 1 addition & 1 deletion src/arch/x86/walkcbfs.S
Expand Up @@ -21,7 +21,7 @@
#define CBFS_FILE_STRUCTSIZE (CBFS_FILE_OFFSET + 4)

.code32
.section .text
.section .init
.global walkcbfs_asm

/*
Expand Down
1 change: 1 addition & 0 deletions src/commonlib/include/commonlib/cbmem_id.h
Expand Up @@ -57,6 +57,7 @@
#define CBMEM_ID_TCPA_TCG_LOG 0x54445041
#define CBMEM_ID_TIMESTAMP 0x54494d45
#define CBMEM_ID_TPM2_TCG_LOG 0x54504d32
#define CBMEM_ID_TPM_PPI 0x54505049
#define CBMEM_ID_VBOOT_HANDOFF 0x780074f0 /* deprecated */
#define CBMEM_ID_VBOOT_SEL_REG 0x780074f1 /* deprecated */
#define CBMEM_ID_VBOOT_WORKBUF 0x78007343
Expand Down
24 changes: 24 additions & 0 deletions src/commonlib/include/commonlib/coreboot_tables.h
Expand Up @@ -81,6 +81,7 @@ enum {
LB_TAG_FMAP = 0x0037,
LB_TAG_PLATFORM_BLOB_VERSION = 0x0038,
LB_TAG_SMMSTOREV2 = 0x0039,
LB_TAG_TPM_PPI_HANDOFF = 0x003a,
LB_TAG_BOARD_CONFIG = 0x0040,
/* The following options are CMOS-related */
LB_TAG_CMOS_OPTION_TABLE = 0x00c8,
Expand Down Expand Up @@ -521,4 +522,27 @@ struct lb_smmstorev2 {
uint8_t unused[3]; /* Set to zero */
};

enum lb_tmp_ppi_tpm_version {
LB_TPM_VERSION_UNSPEC = 0,
LB_TPM_VERSION_TPM_VERSION_1_2,
LB_TPM_VERSION_TPM_VERSION_2,
};

/*
* Handoff buffer for TPM Physical Presence Interface.
* * ppi_address Pointer to PPI buffer shared with ACPI
* The layout of the buffer matches the QEMU virtual memory device
* that is generated by QEMU.
* See files 'hw/i386/acpi-build.c' and 'include/hw/acpi/tpm.h'
* for details.
* * tpm_version TPM version: 1 for TPM1.2, 2 for TPM2.0
* * ppi_version BCD encoded version of TPM PPI interface
*/
struct lb_tpm_physical_presence {
uint32_t tag;
uint32_t size;
uint32_t ppi_address; /* Address of ACPI PPI communication buffer */
uint8_t tpm_version; /* 1: TPM1.2, 2: TPM2.0 */
uint8_t ppi_version; /* BCD encoded */
} __packed;
#endif
1 change: 0 additions & 1 deletion src/cpu/amd/agesa/Kconfig
Expand Up @@ -14,7 +14,6 @@ config CPU_AMD_AGESA
select SPI_FLASH if HAVE_ACPI_RESUME
select SMM_ASEG
select SSE2
select ACPI_NO_SMI_GNVS

if CPU_AMD_AGESA

Expand Down
1 change: 0 additions & 1 deletion src/cpu/amd/pi/Kconfig
Expand Up @@ -13,7 +13,6 @@ config CPU_AMD_PI
select SPI_FLASH if HAVE_ACPI_RESUME
select SMM_ASEG
select SSE2
select ACPI_NO_SMI_GNVS

if CPU_AMD_PI

Expand Down
1 change: 1 addition & 0 deletions src/cpu/intel/car/core2/cache_as_ram.S
Expand Up @@ -4,6 +4,7 @@
#include <cpu/x86/cache.h>
#include <cpu/x86/post_code.h>

.section .init
.global bootblock_pre_c_entry

.code32
Expand Down
1 change: 1 addition & 0 deletions src/cpu/intel/car/non-evict/cache_as_ram.S
Expand Up @@ -7,6 +7,7 @@
#define NoEvictMod_MSR 0x2e0
#define BBL_CR_CTL3_MSR 0x11e

.section .init
.global bootblock_pre_c_entry

#include <cpu/intel/car/cache_as_ram_symbols.inc>
Expand Down
1 change: 1 addition & 0 deletions src/cpu/intel/car/p3/cache_as_ram.S
Expand Up @@ -4,6 +4,7 @@
#include <cpu/x86/cache.h>
#include <cpu/x86/post_code.h>

.section .init
.global bootblock_pre_c_entry

.code32
Expand Down
1 change: 1 addition & 0 deletions src/cpu/intel/car/p4-netburst/cache_as_ram.S
Expand Up @@ -8,6 +8,7 @@
/* Macro to access Local APIC registers at default base. */
#define LAPIC(x) $(LAPIC_DEFAULT_BASE | LAPIC_ ## x)

.section .init
.global bootblock_pre_c_entry

.code32
Expand Down
6 changes: 2 additions & 4 deletions src/cpu/intel/fit/Makefile.inc
Expand Up @@ -6,16 +6,14 @@ ifneq ($(CONFIG_UPDATE_IMAGE),y) # never update the bootblock

ifneq ($(CONFIG_CPU_MICROCODE_CBFS_NONE),y)

INTERMEDIATE+=add_mcu_fit
add_mcu_fit: $(obj)/coreboot.pre $(IFITTOOL)
$(call add_intermediate, add_mcu_fit, $(IFITTOOL))
@printf " UPDATE-FIT Microcode\n"
$(IFITTOOL) -f $< -a -n cpu_microcode_blob.bin -t 1 -s $(CONFIG_CPU_INTEL_NUM_FIT_ENTRIES) -r COREBOOT

# Second FIT in TOP_SWAP bootblock
ifeq ($(CONFIG_INTEL_ADD_TOP_SWAP_BOOTBLOCK),y)

INTERMEDIATE+=add_ts_mcu_fit
add_ts_mcu_fit: $(obj)/coreboot.pre $(IFITTOOL)
$(call add_intermediate, add_ts_mcu_fit, $(IFITTOOL))
@printf " UPDATE-FIT Top Swap: Microcode\n"
ifneq ($(FIT_ENTRY),)
$(IFITTOOL) -f $< -A -n $(FIT_ENTRY) -t 1 -s $(CONFIG_CPU_INTEL_NUM_FIT_ENTRIES) $(TS_OPTIONS) -r COREBOOT
Expand Down
6 changes: 6 additions & 0 deletions src/cpu/intel/haswell/Makefile.inc
@@ -1,4 +1,6 @@
ramstage-y += haswell_init.c

romstage-y += romstage.c
romstage-y += ../car/romstage.c

ramstage-y += acpi.c
Expand All @@ -23,3 +25,7 @@ subdirs-y += ../turbo

cpu_microcode_bins += $(wildcard 3rdparty/intel-microcode/intel-ucode/06-3c-*)
cpu_microcode_bins += $(wildcard 3rdparty/intel-microcode/intel-ucode/06-45-*)

ifeq ($(CONFIG_SOC_INTEL_BROADWELL),y)
cpu_microcode_bins += 3rdparty/blobs/soc/intel/broadwell/microcode.bin
endif
117 changes: 52 additions & 65 deletions src/cpu/intel/haswell/acpi.c
Expand Up @@ -14,6 +14,24 @@

#include <southbridge/intel/lynxpoint/pch.h>

static int cstate_set_s0ix[3] = {
C_STATE_C1E,
C_STATE_C7S_LONG_LAT,
C_STATE_C10,
};

static int cstate_set_lp[3] = {
C_STATE_C1E,
C_STATE_C3,
C_STATE_C7S_LONG_LAT,
};

static int cstate_set_trad[3] = {
C_STATE_C1,
C_STATE_C3,
C_STATE_C6_LONG_LAT,
};

static int get_cores_per_package(void)
{
struct cpuinfo_x86 c;
Expand All @@ -30,41 +48,6 @@ static int get_cores_per_package(void)
return cores;
}

static void generate_cstate_entries(acpi_cstate_t *cstates,
int c1, int c2, int c3)
{
int cstate_count = 0;

/* Count number of active C-states */
if (c1 > 0)
++cstate_count;
if (c2 > 0)
++cstate_count;
if (c3 > 0)
++cstate_count;
if (!cstate_count)
return;

acpigen_write_package(cstate_count + 1);
acpigen_write_byte(cstate_count);

/* Add an entry if the level is enabled */
if (c1 > 0) {
cstates[c1].ctype = 1;
acpigen_write_CST_package_entry(&cstates[c1]);
}
if (c2 > 0) {
cstates[c2].ctype = 2;
acpigen_write_CST_package_entry(&cstates[c2]);
}
if (c3 > 0) {
cstates[c3].ctype = 3;
acpigen_write_CST_package_entry(&cstates[c3]);
}

acpigen_pop_len();
}

static acpi_tstate_t tss_table_fine[] = {
{ 100, 1000, 0, 0x00, 0 },
{ 94, 940, 0, 0x1f, 0 },
Expand Down Expand Up @@ -117,20 +100,29 @@ static void generate_T_state_entries(int core, int cores_per_package)
ARRAY_SIZE(tss_table_coarse), tss_table_coarse);
}

static bool is_s0ix_enabled(void)
{
if (!haswell_is_ult())
return false;

const struct device *lapic = dev_find_lapic(SPEEDSTEP_APIC_MAGIC);

if (!lapic || !lapic->chip_info)
return false;

const struct cpu_intel_haswell_config *conf = lapic->chip_info;

return conf->s0ix_enable;
}

static void generate_C_state_entries(void)
{
acpi_cstate_t map[3];
int *set;
int i;

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();
Expand All @@ -140,25 +132,20 @@ static void generate_C_state_entries(void)
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();
if (is_s0ix_enabled())
set = cstate_set_s0ix;
else if (haswell_is_ult())
set = cstate_set_lp;
else
set = cstate_set_trad;

/* 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();
for (i = 0; i < ARRAY_SIZE(map); i++) {
map[i] = cpu->cstates[set[i]];
map[i].ctype = i + 1;
}

/* Generate C-state tables */
acpigen_write_CST_package(map, ARRAY_SIZE(map));
}

static int calculate_power(int tdp, int p1_ratio, int ratio)
Expand Down Expand Up @@ -209,7 +196,7 @@ static void generate_P_state_entries(int core, int cores_per_package)
/* Max Non-Turbo Ratio */
ratio_max = (msr.lo >> 8) & 0xff;
}
clock_max = ratio_max * HASWELL_BCLK;
clock_max = ratio_max * CPU_BCLK;

/* Calculate CPU TDP in mW */
msr = rdmsr(MSR_PKG_POWER_SKU_UNIT);
Expand Down Expand Up @@ -273,7 +260,7 @@ static void generate_P_state_entries(int core, int cores_per_package)

/* Calculate power at this ratio */
power = calculate_power(power_max, ratio_max, ratio);
clock = ratio * HASWELL_BCLK;
clock = ratio * CPU_BCLK;

acpigen_write_PSS_package(
clock, /*MHz*/
Expand Down
5 changes: 5 additions & 0 deletions src/cpu/intel/haswell/bootblock.c
Expand Up @@ -4,6 +4,7 @@
#include <arch/bootblock.h>
#include <cpu/x86/msr.h>
#include <arch/io.h>
#include <delay.h>
#include <halt.h>

#include "haswell.h"
Expand Down Expand Up @@ -50,6 +51,10 @@ static void set_flex_ratio_to_tdp_nominal(void)
/* Set soft reset control to use register value */
RCBA32_OR(SOFT_RESET_CTRL, 1);

/* Delay before reset to avoid potential TPM lockout */
if (CONFIG(TPM1) || CONFIG(TPM2))
mdelay(30);

/* Issue warm reset, will be "CPU only" due to soft reset data */
outb(0x0, 0xcf9);
outb(0x6, 0xcf9);
Expand Down
38 changes: 30 additions & 8 deletions src/cpu/intel/haswell/chip.h
Expand Up @@ -3,16 +3,38 @@
/* Magic value used to locate this chip in the device tree */
#define SPEEDSTEP_APIC_MAGIC 0xACAC

struct cpu_intel_haswell_config {
u8 disable_acpi; /* Do not generate CPU ACPI tables */
#include <stdbool.h>
#include <stdint.h>

struct cpu_vr_config {
/*
* Minimum voltage for C6/C7 state:
* 0x67 = 1.6V (full swing)
* ...
* 0x79 = 1.7V
* ...
* 0x83 = 1.8V (no swing)
*/
uint8_t cpu_min_vid;

int c1_battery; /* ACPI C1 on Battery Power */
int c2_battery; /* ACPI C2 on Battery Power */
int c3_battery; /* ACPI C3 on Battery Power */
/*
* Set slow VR ramp rate on C-state exit:
* 0 = Fast VR ramp rate / 2
* 1 = Fast VR ramp rate / 4
* 2 = Fast VR ramp rate / 8
* 3 = Fast VR ramp rate / 16
*/
uint8_t slow_ramp_rate_set;

int c1_acpower; /* ACPI C1 on AC Power */
int c2_acpower; /* ACPI C2 on AC Power */
int c3_acpower; /* ACPI C3 on AC Power */
/* Enable slow VR ramp rate */
bool slow_ramp_rate_enable;
};

struct cpu_intel_haswell_config {
int tcc_offset; /* TCC Activation Offset */

struct cpu_vr_config vr_config;

/* Enable S0iX support */
bool s0ix_enable;
};
149 changes: 93 additions & 56 deletions src/cpu/intel/haswell/haswell.h
Expand Up @@ -3,40 +3,62 @@
#ifndef _CPU_INTEL_HASWELL_H
#define _CPU_INTEL_HASWELL_H

#include <arch/cpu.h>
#include <stdint.h>

/* Haswell CPU types */
#define HASWELL_FAMILY_MOBILE 0x306c0
#define HASWELL_FAMILY_ULT 0x40650
/* CPU types without stepping */
#define HASWELL_FAMILY_TRAD 0x306c0
#define HASWELL_FAMILY_ULT 0x40650
#define CRYSTALWELL_FAMILY 0x306c0
#define BROADWELL_FAMILY_ULT 0x306d0

/* Haswell CPU steppings */
#define HASWELL_STEPPING_MOBILE_A0 1
#define HASWELL_STEPPING_MOBILE_B0 2
#define HASWELL_STEPPING_MOBILE_C0 3
#define HASWELL_STEPPING_MOBILE_D0 4
#define HASWELL_STEPPING_ULT_B0 0
#define HASWELL_STEPPING_ULT_C0 1
/* Haswell CPUIDs */
#define CPUID_HASWELL_A0 0x306c1
#define CPUID_HASWELL_B0 0x306c2
#define CPUID_HASWELL_C0 0x306c3

/* Haswell bus clock is fixed at 100MHz */
#define HASWELL_BCLK 100
#define CPUID_HASWELL_ULT_B0 0x40650
#define CPUID_HASWELL_ULT_C0 0x40651

/* Crystalwell CPUIDs */
#define CPUID_CRYSTALWELL_B0 0x40660
#define CPUID_CRYSTALWELL_C0 0x40661

/* Broadwell CPUIDs */
#define CPUID_BROADWELL_C0 0x40671

#define CPUID_BROADWELL_ULT_C0 0x306d2
#define CPUID_BROADWELL_ULT_D0 0x306d3
#define CPUID_BROADWELL_ULT_E0 0x306d4

/* Haswell and Broadwell bus clock is fixed at 100MHz */
#define CPU_BCLK 100

#define MSR_CORE_THREAD_COUNT 0x35
#define MSR_PLATFORM_INFO 0xce
#define PLATFORM_INFO_SET_TDP (1 << 29)
#define TIMED_MWAIT_SUPPORTED (1 << (37 - 32))
#define MSR_PKG_CST_CONFIG_CONTROL 0xe2
#define MSR_PMG_IO_CAPTURE_BASE 0xe4
#define MSR_FEATURE_CONFIG 0x13c
#define SMM_MCA_CAP_MSR 0x17d
#define SMM_CPU_SVRSTR_BIT 57
#define SMM_CPU_SVRSTR_MASK (1 << (SMM_CPU_SVRSTR_BIT - 32))
#define MSR_FLEX_RATIO 0x194
#define FLEX_RATIO_LOCK (1 << 20)
#define FLEX_RATIO_EN (1 << 16)
#define MSR_TEMPERATURE_TARGET 0x1a2
#define MSR_LT_LOCK_MEMORY 0x2e7

#define MSR_PLATFORM_INFO 0xce
#define PLATFORM_INFO_SET_TDP (1 << 29)
#define MSR_PKG_CST_CONFIG_CONTROL 0xe2
#define MSR_PMG_IO_CAPTURE_BASE 0xe4

#define MSR_MISC_PWR_MGMT 0x1aa
#define MISC_PWR_MGMT_EIST_HW_DIS (1 << 0)
#define MSR_TURBO_RATIO_LIMIT 0x1ad
#define MSR_PRMRR_PHYS_BASE 0x1f4
#define MSR_PRMRR_PHYS_MASK 0x1f5
#define MSR_POWER_CTL 0x1fc
#define MSR_LT_LOCK_MEMORY 0x2e7
#define MSR_UNCORE_PRMRR_PHYS_BASE 0x2f4
#define MSR_UNCORE_PRMRR_PHYS_MASK 0x2f5
#define SMM_FEATURE_CONTROL_MSR 0x4e0
#define SMM_CPU_SAVE_EN (1 << 1)

#define MSR_C_STATE_LATENCY_CONTROL_0 0x60a
#define MSR_C_STATE_LATENCY_CONTROL_1 0x60b
Expand All @@ -53,7 +75,7 @@
#define IRTL_33554432_NS (5 << 10)
#define IRTL_RESPONSE_MASK (0x3ff)

/* long duration in low dword, short duration in high dword */
/* Long duration in low dword, short duration in high dword */
#define MSR_PKG_POWER_LIMIT 0x610
#define PKG_POWER_LIMIT_MASK 0x7fff
#define PKG_POWER_LIMIT_EN (1 << 15)
Expand All @@ -76,18 +98,6 @@
#define MSR_CONFIG_TDP_CONTROL 0x64b
#define MSR_TURBO_ACTIVATION_RATIO 0x64c

#define SMM_MCA_CAP_MSR 0x17d
#define SMM_CPU_SVRSTR_BIT 57
#define SMM_CPU_SVRSTR_MASK (1 << (SMM_CPU_SVRSTR_BIT - 32))

#define MSR_PRMRR_PHYS_BASE 0x1f4
#define MSR_PRMRR_PHYS_MASK 0x1f5
#define MSR_UNCORE_PRMRR_PHYS_BASE 0x2f4
#define MSR_UNCORE_PRMRR_PHYS_MASK 0x2f5

#define SMM_FEATURE_CONTROL_MSR 0x4e0
#define SMM_CPU_SAVE_EN (1 << 1)

/* SMM save state MSRs */
#define SMBASE_MSR 0xc20
#define IEDBASE_MSR 0xc22
Expand All @@ -96,33 +106,26 @@
#define SMRR_SUPPORTED (1 << 11)
#define PRMRR_SUPPORTED (1 << 12)

/* Intel suggested latency times in units of 1024ns. */
#define C_STATE_LATENCY_CONTROL_0_LIMIT 0x42
#define C_STATE_LATENCY_CONTROL_1_LIMIT 0x73
#define C_STATE_LATENCY_CONTROL_2_LIMIT 0x91
#define C_STATE_LATENCY_CONTROL_3_LIMIT 0xe4
#define C_STATE_LATENCY_CONTROL_4_LIMIT 0x145
#define C_STATE_LATENCY_CONTROL_5_LIMIT 0x1ef

#define C_STATE_LATENCY_MICRO_SECONDS(limit, base) \
(((1 << ((base) * 5)) * (limit)) / 1000)
#define C_STATE_LATENCY_FROM_LAT_REG(reg) \
C_STATE_LATENCY_MICRO_SECONDS(C_STATE_LATENCY_CONTROL_ ##reg## _LIMIT, \
(IRTL_1024_NS >> 10))

/* P-state configuration */
#define PSS_MAX_ENTRIES 8
#define PSS_RATIO_STEP 2
#define PSS_LATENCY_TRANSITION 10
#define PSS_LATENCY_BUSMASTER 10

/* PCODE MMIO communications live in the MCHBAR. */
#define BIOS_MAILBOX_INTERFACE 0x5da4
#define MAILBOX_RUN_BUSY (1 << 31)
#define MAILBOX_BIOS_CMD_READ_PCS 1
#define MAILBOX_BIOS_CMD_WRITE_PCS 2
#define MAILBOX_BIOS_CMD_READ_CALIBRATION 0x509
#define MAILBOX_BIOS_CMD_FSM_MEASURE_INTVL 0x909
#define MAILBOX_BIOS_CMD_READ_PCH_POWER 0xa
#define MAILBOX_BIOS_CMD_READ_PCH_POWER_EXT 0xb
/* Errors are returned back in bits 7:0. */
#define MAILBOX_BIOS_ERROR_NONE 0
#define MAILBOX_BIOS_ERROR_INVALID_COMMAND 1
#define MAILBOX_BIOS_ERROR_TIMEOUT 2
#define MAILBOX_BIOS_ERROR_ILLEGAL_DATA 3
#define MAILBOX_BIOS_ERROR_RESERVED 4
#define MAILBOX_BIOS_ERROR_ILLEGAL_VR_ID 5
#define MAILBOX_BIOS_ERROR_VR_INTERFACE_LOCKED 6
#define MAILBOX_BIOS_ERROR_VR_ERROR 7
/* Data is passed through bits 31:0 of the data register. */
#define BIOS_MAILBOX_DATA 0x5da0

/* Sanity check config options. */
#if (CONFIG_SMM_TSEG_SIZE <= (CONFIG_IED_REGION_SIZE + CONFIG_SMM_RESERVED_SIZE))
# error "CONFIG_SMM_TSEG_SIZE <= (CONFIG_IED_REGION_SIZE + CONFIG_SMM_RESERVED_SIZE)"
Expand All @@ -137,16 +140,50 @@
# error "CONFIG_IED_REGION_SIZE is not a power of 2"
#endif

/*
* List of supported C-states for Haswell and Broadwell.
* Only the ULT parts support C8, C9, and C10.
*/
enum {
C_STATE_C0 = 0,
C_STATE_C1 = 1,
C_STATE_C1E = 2,
C_STATE_C3 = 3,
C_STATE_C6_SHORT_LAT = 4,
C_STATE_C6_LONG_LAT = 5,
C_STATE_C7_SHORT_LAT = 6,
C_STATE_C7_LONG_LAT = 7,
C_STATE_C7S_SHORT_LAT = 8,
C_STATE_C7S_LONG_LAT = 9,
C_STATE_C8 = 10,
C_STATE_C9 = 11,
C_STATE_C10 = 12,
NUM_C_STATES,
};

/* Lock MSRs */
void intel_cpu_haswell_finalize_smm(void);

/* Configure power limits for turbo mode */
void set_power_limits(u8 power_limit_1_time);
int cpu_config_tdp_levels(void);

void set_max_freq(void);

/* CPU identification */
int haswell_family_model(void);
int haswell_stepping(void);
int haswell_is_ult(void);
static inline u32 cpu_family_model(void)
{
return cpuid_eax(1) & 0x0fff0ff0;
}

static inline u32 cpu_stepping(void)
{
return cpuid_eax(1) & 0xf;
}

static inline int haswell_is_ult(void)
{
return CONFIG(INTEL_LYNXPOINT_LP);
}

#endif