mb/dell/optiplex_9010: Add Dell OptiPlex 9010 SFF support

Based on the autoport. The OptiPlex 9010 comes in four different sizes:
MT, DT, SFF and USFF. Tested on SFF only. The other PCBs are slightly
different, but they are designed with intercompatibility in mind. With
small devicetree overrides it should work on OptiPlex 7010 and other
OptiPlex 9010 variants as well.

Signed-off-by: Michał Żygowski <michal.zygowski@3mdeb.com>
Change-Id: I88d65cae30d08ca727d86d930707c2be25a527cf
Reviewed-on: https://review.coreboot.org/c/coreboot/+/40351
Reviewed-by: Felix Held <felix-coreboot@felixheld.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Michał Żygowski 2020-04-13 21:42:24 +02:00
parent fba08308f0
commit 72f06ca554
29 changed files with 2057 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

View File

@ -0,0 +1,147 @@
# Dell OptiPlex 9010
This page describes how to run coreboot on Dell OptiPlex 9010 SFF.
![](optiplex_9010.jpg)
## Technology
```eval_rst
+------------+---------------------------------------------------------------+
| CPU | Intel Core 2nd Gen (Sandybridge) or 3rd Gen (Ivybridge) |
+------------+---------------------------------------------------------------+
| DRAM | Up to 4 DIMM slots, up to 32GB 1600MHz non-ECC DDR3 SDRAM |
+------------+---------------------------------------------------------------+
| Chipset | Intel Q77 Express |
+------------+---------------------------------------------------------------+
| Super I/O | SMSC SCH5545 (or SCH5544) with Environmental Controller |
+------------+---------------------------------------------------------------+
| TPM | ST Microelectronics ST33ZP24 |
+------------+---------------------------------------------------------------+
| Boot | From USB, SATA, NVMe (using PCIe x4 expansion card) |
+------------+---------------------------------------------------------------+
| Power | 200W-275W PSU |
+------------+---------------------------------------------------------------+
```
More specifications on [Dell OptiPlex 9010 specifications].
## Required proprietary blobs
```eval_rst
+------------------+---------------------------------+---------------------+
| Binary file | Apply | Required / Optional |
+==================+=================================+=====================+
| smsc_sch5545.bin | SMSC SCH5545 EC | Optional |
+------------------+---------------------------------+---------------------+
| microcode | CPU microcode | Required |
+------------------+---------------------------------+---------------------+
```
Microcode updates are automatically included into the coreboot image by build
system from the `3rdparty/intel-microcode` submodule.
SMSC SC5545 EC firmware is optional, however lack of the binary will result in
EC malfunction after power failure and fans running at full speed. The blob can
be extracted from original firmware. It should be located under a file with
GUID D386BEB8-4B54-4E69-94F5-06091F67E0D3, raw section. The file begins with a
signature `SMSCUBIM`. The easiest way to do this is to use [UEFITool] and
`Extract body` option on the raw section of the file.
## Flashing coreboot
```eval_rst
+---------------------+--------------------------+
| Type | Value |
+=====================+==========================+
| Socketed flash | no |
+---------------------+--------------------------+
| Model | MX25L6406E/MX25L3206E |
+---------------------+--------------------------+
| Size | 8 + 4 MiB |
+---------------------+--------------------------+
| Package | SOIC-16 + SOIC-8 |
+---------------------+--------------------------+
| Write protection | chipset PRR |
+---------------------+--------------------------+
| Dual BIOS feature | no |
+---------------------+--------------------------+
| Internal flashing | yes |
+---------------------+--------------------------+
```
### Internal programming
The SPI flash can be accessed using [flashrom].
flashrom -p internal -w coreboot.rom --ifd -i bios
Internal programming will not work when migrating from original UEFI firmware.
One will have to short the SERVICE_MODE jumper to enable HMRFPO and then boot
the machine to flash it.
### External programming
The external access to flash chip is available through standard SOP-8 clip
and/or SOP-16 clip on the right side of the CPU fan (marked on the board
image). The voltage of SPI flash is 3.3V.
There are no restrictions as to the programmer device. It is only recommended
to flash firmware without supplying power. There are no diodes connected to the
flash chips. External programming can be performed, for example using OrangePi
and Armbian. You can use linux_spi driver which provides communication with SPI
devices. Example command to program SPI flash with OrangePi using linux_spi:
flashrom -w coreboot.rom -p linux_spi:dev=/dev/spidev1.0,spispeed=16000
## Schematics
There are no schematics for SFF, but if one looks for MT/DT schematics, they
can be found publicly. Most of the schematics should match the SFF (although
MT/DT has additional PCIe and PCI slot).
## Known issues
- There seems to be a problem with DRAM clearing on reboot. The SSKPD register
still contains 0xCAFE which leads to reset loop.
## Untested
Not all mainboard's peripherals and functions were tested because of lack of
the cables or not being populated on the board case.
- Internal USB 2.0 header
- Wake from S3 using serial port
- Wake-on-Lan from ACPI S4/S5
## Working
- USB 3.0 and 2.0 rear and front ports (SeaBIOS and Linux 4.19)
- Gigabit Ethernet
- VGA and 2x DP port using libgfxinit
- flashrom
- PCIe x1 WiFi in PCIe x4 slot
- NVMe PCIe x4 using PCIe x4 expansion card
- PCIe x16 PEG port using Dell Radeon HD 7570
- SATA ports (SATA disks and DVD)
- Super I/O serial port 0 (RS232 DB9 connector on the rear side)
- SMBus (reading SPD from DIMMs)
- CPU initialization using Intel i7-3770
- Sandy Bridge/Ivy Bridge native RAM initialization
- SeaBIOS payload (version rel-1.13.0)
- PS/2 keyboard and mouse (including wake support)
- LPC debug header (requires soldering of the pin header and shorting RF24 for
LPC clock)
- USB debug dongle (the most bottom USB 2.0 port under RJ45 on the read side)
- SMSC SCH5545 Super I/O initialization
- SMSC SCH5545 EC initialization and firmware update
- SMSC SCH5545 EC automatic fan control
- TPM 1.2
- Booting Debian 10, Ubuntu 18.04, QubesOS R4.01
- Boot with cleaned ME
- Intruder detection
- Wake-on-Lan from ACPI S3
[flashrom]: https://flashrom.org/Flashrom
[Dell OptiPlex 9010 specifications]: https://www.dell.com/downloads/global/products/optix/en/dell_optiplex_9010_spec_sheet.pdf
[UEFITool]: https://github.com/LongSoft/UEFITool

View File

@ -26,6 +26,10 @@ This section contains documentation about coreboot on specific mainboards.
- [CN81XX EVB SFF](cavium/cn8100_sff_evb.md)
## Dell
- [OptiPlex 9010 SFF](dell/optiplex_9010.md)
## Emulation
The boards in this section are not real mainboards, but emulators.

View File

@ -0,0 +1,9 @@
CONFIG_USE_OPTION_TABLE=y
CONFIG_USE_BLOBS=y
CONFIG_VENDOR_DELL=y
CONFIG_ONBOARD_VGA_IS_PRIMARY=y
# CONFIG_DRIVERS_UART_8250IO is not set
CONFIG_PCIEXP_CLK_PM=y
CONFIG_SEABIOS_PS2_TIMEOUT=3000
CONFIG_POST_DEVICE_LPC=y
CONFIG_HAVE_EM100_SUPPORT=y

View File

@ -0,0 +1,16 @@
if VENDOR_DELL
choice
prompt "Mainboard model"
source "src/mainboard/dell/*/Kconfig.name"
endchoice
source "src/mainboard/dell/*/Kconfig"
config MAINBOARD_VENDOR
string
default "Dell Inc."
endif # VENDOR_DELL

View File

@ -0,0 +1,2 @@
config VENDOR_DELL
bool "Dell Inc."

View File

@ -0,0 +1,69 @@
if BOARD_DELL_OPTIPLEX_9010
config BOARD_SPECIFIC_OPTIONS
def_bool y
select BOARD_ROMSIZE_KB_12288
select HAVE_ACPI_RESUME
select HAVE_ACPI_TABLES
select INTEL_INT15
select NORTHBRIDGE_INTEL_SANDYBRIDGE
select SERIRQ_CONTINUOUS_MODE
select SOUTHBRIDGE_INTEL_C216
select USE_NATIVE_RAMINIT
select MAINBOARD_HAS_LPC_TPM
select MAINBOARD_HAS_TPM1
select MAINBOARD_USES_IFD_GBE_REGION
select SUPERIO_SMSC_SCH5545
select MAINBOARD_HAS_LIBGFXINIT
select INTEL_GMA_HAVE_VBT
select HAVE_OPTION_TABLE
select HAVE_CMOS_DEFAULT
select PCIEXP_L1_SUB_STATE
config MAINBOARD_DIR
string
default dell/optiplex_9010
config MAINBOARD_PART_NUMBER
string
default "OptiPlex 9010"
config VGA_BIOS_FILE
string
default "pci8086,0162.rom"
config VGA_BIOS_ID
string
default "8086,0162"
config DRAM_RESET_GATE_GPIO
int
default 60
config MAX_CPUS
int
default 8
config USBDEBUG_HCD_INDEX
int
default 2
config CBFS_SIZE
hex
default 0x600000
config INCLUDE_SMSC_SCH5545_EC_FW
bool "Include SMSC SCH5545 EC firmware binary"
default n
help
This option allows to add the SMSC SCH5545 Environmental Controller
firmware binary. The firmware must be loaded after each power failure
in order to properly initialize the fan control, because EC loses its
configuration when power is cut off. Otherwise the fans will keep
running at full speed after power failure.
config SMSC_SCH5545_EC_FW_FILE
string "File path to the SMSC SCH5545 EC firmware binary"
depends on INCLUDE_SMSC_SCH5545_EC_FW
endif

View File

@ -0,0 +1,2 @@
config BOARD_DELL_OPTIPLEX_9010
bool "OptiPlex 9010 SFF"

View File

@ -0,0 +1,22 @@
# SPDX-License-Identifier: GPL-2.0-only
smm-y += smihandler.c
bootblock-y += gpio.c
romstage-y += gpio.c
bootblock-y += early_init.c
romstage-y += early_init.c
bootblock-y += sch5545_ec_early.c
romstage-y += sch5545_ec.c
ramstage-y += sch5545_ec.c
ramstage-$(CONFIG_MAINBOARD_USE_LIBGFXINIT) += gma-mainboard.ads
ifeq ($(CONFIG_INCLUDE_SMSC_SCH5545_EC_FW),y)
cbfs-files-y += sch5545_ecfw.bin
sch5545_ecfw.bin-file := $(call strip_quotes,$(CONFIG_SMSC_SCH5545_EC_FW_FILE))
sch5545_ecfw.bin-type := raw
endif

View File

@ -0,0 +1,54 @@
/* SPDX-License-Identifier: GPL-2.0-only */
Method(_WAK,1)
{
\_SB.PCI0.LPCB.SIO1.SIOW (Arg0)
Return(Package(){0,0})
}
Method(_PTS,1)
{
\_SB.PCI0.LPCB.SIO1.SIOS (Arg0)
}
Scope (\_SB)
{
Device (PWRB)
{
Name (_HID, EisaId ("PNP0C0C"))
Name (_UID, 0xAA)
Name (_STA, 0x0B)
Name (_PRW, Package() { 8, 3})
}
}
Scope (\_GPE)
{
Method (_L08, 0, NotSerialized)
{
\_SB.PCI0.LPCB.SIO1.SIOH ()
Notify (\_SB.PWRB, 0x02)
}
Method (_L0D, 0, NotSerialized)
{
Notify (\_SB.PCI0.EHC1, 0x02)
Notify (\_SB.PCI0.EHC2, 0x02)
Notify (\_SB.PCI0.GLAN, 0x02)
}
Method (_L09, 0, NotSerialized)
{
Notify (\_SB.PCI0.RP01, 0x02)
Notify (\_SB.PCI0.RP02, 0x02)
Notify (\_SB.PCI0.RP03, 0x02)
Notify (\_SB.PCI0.RP04, 0x02)
Notify (\_SB.PCI0.RP05, 0x02)
Notify (\_SB.PCI0.RP06, 0x02)
Notify (\_SB.PCI0.RP07, 0x02)
Notify (\_SB.PCI0.RP08, 0x02)
Notify (\_SB.PCI0.PEGP, 0x02)
}
}

View File

@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#undef SUPERIO_DEV
#undef SUPERIO_PNP_BASE
#define SUPERIO_DEV SIO1
#define SUPERIO_PNP_BASE 0x2e
#define SCH5545_RUNTIME_BASE 0xa00
#define SCH5545_EMI_BASE 0xa40
#define SCH5545_SHOW_UARTA
#define SCH5545_SHOW_KBC
#include <superio/smsc/sch5545/acpi/superio.asl>

View File

@ -0,0 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <southbridge/intel/bd82x6x/nvs.h>
void acpi_create_gnvs(global_nvs_t *gnvs)
{
gnvs->tcrt = 100;
gnvs->tpsv = 90;
}

View File

@ -0,0 +1,6 @@
Category: desktop
ROM protocol: SPI
ROM package: SOIC-8, SOIC-16
ROM socketed: n
Flashrom support: y
Release year: 2012

View File

@ -0,0 +1,7 @@
boot_option=Fallback
debug_level=Debug
power_on_after_fail=Disable
nmi=Enable
sata_mode=AHCI
gfx_uma_size=128M
fan_full_speed=Disable

View File

@ -0,0 +1,95 @@
## SPDX-License-Identifier: GPL-2.0-only
# -----------------------------------------------------------------
entries
# -----------------------------------------------------------------
# Status Register A
# -----------------------------------------------------------------
# Status Register B
# -----------------------------------------------------------------
# Status Register C
#96 4 r 0 status_c_rsvd
#100 1 r 0 uf_flag
#101 1 r 0 af_flag
#102 1 r 0 pf_flag
#103 1 r 0 irqf_flag
# -----------------------------------------------------------------
# Status Register D
#104 7 r 0 status_d_rsvd
#111 1 r 0 valid_cmos_ram
# -----------------------------------------------------------------
# Diagnostic Status Register
#112 8 r 0 diag_rsvd1
# -----------------------------------------------------------------
0 120 r 0 reserved_memory
# -----------------------------------------------------------------
# RTC_BOOT_BYTE (coreboot hardcoded)
384 1 e 4 boot_option
388 4 h 0 reboot_counter
# -----------------------------------------------------------------
# coreboot config options: console
395 4 e 6 debug_level
#400 8 r 0 reserved for century byte
# coreboot config options: southbridge
408 1 e 1 nmi
409 2 e 7 power_on_after_fail
411 1 e 8 sata_mode
# coreboot config options: EC
412 1 e 1 fan_full_speed
# coreboot config options: northbridge
432 3 e 9 gfx_uma_size
# SandyBridge MRC Scrambler Seed values
896 32 r 0 mrc_scrambler_seed
928 32 r 0 mrc_scrambler_seed_s3
960 16 r 0 mrc_scrambler_seed_chk
# coreboot config options: check sums
984 16 h 0 check_sum
# -----------------------------------------------------------------
enumerations
#ID value text
1 0 Disable
1 1 Enable
2 0 Enable
2 1 Disable
4 0 Fallback
4 1 Normal
6 0 Emergency
6 1 Alert
6 2 Critical
6 3 Error
6 4 Warning
6 5 Notice
6 6 Info
6 7 Debug
6 8 Spew
7 0 Disable
7 1 Enable
7 2 Keep
8 0 AHCI
8 1 Compatible
9 0 32M
9 1 64M
9 2 96M
9 3 128M
9 4 160M
9 5 192M
9 6 224M
# -----------------------------------------------------------------
checksums
checksum 392 447 984

Binary file not shown.

View File

@ -0,0 +1,99 @@
chip northbridge/intel/sandybridge
device cpu_cluster 0 on
chip cpu/intel/model_206ax
register "c1_acpower" = "1"
register "c1_battery" = "1"
register "c2_acpower" = "3"
register "c2_battery" = "3"
register "c3_acpower" = "5"
register "c3_battery" = "5"
register "tcc_offset" = "5" # TCC of 95C
device lapic 0 on end
device lapic 0xacac off end
end
end
device domain 0x0 on
subsystemid 0x1028 0x052c inherit
device pci 00.0 on end # Host bridge Host bridge
device pci 01.0 on # PEG1 (blue slot1)
smbios_slot_desc "0xB6" "4" "SLOT1" "0x0D"
end
device pci 02.0 on end # Internal graphics VGA controller
device pci 06.0 off end # PEG2
chip southbridge/intel/bd82x6x # Intel Series 7 Panther Point PCH
register "gpe0_en" = "0x00000146"
register "alt_gp_smi_en" = "0x0004"
register "gpi2_routing" = "1"
register "gpi12_routing" = "2"
register "c2_latency" = "0x0065"
register "gen1_dec" = "0x007c0a01"
register "gen2_dec" = "0x007c0901"
register "gen3_dec" = "0x003c07e1"
register "gen4_dec" = "0x001c0901"
register "pcie_port_coalesce" = "1"
register "sata_interface_speed_support" = "0x3"
register "sata_port_map" = "0x7"
register "spi_lvscc" = "0x2005"
register "spi_uvscc" = "0x2005"
register "superspeed_capable_ports" = "0x0000000f"
register "xhci_overcurrent_mapping" = "0x08040201"
register "xhci_switchable_ports" = "0x0000000f"
device pci 14.0 on end # USB 3.0 Controller
device pci 16.0 off end # Management Engine Interface 1
device pci 16.1 off end # Management Engine Interface 2
device pci 16.2 off end # Management Engine IDE-R
device pci 16.3 off end # Management Engine KT
device pci 19.0 on end # Intel Gigabit Ethernet
device pci 1a.0 on end # USB2 EHCI #2
device pci 1b.0 on end # High Definition Audio controller
device pci 1c.0 off end # PCIe Port #1
device pci 1c.1 off end # PCIe Port #2
device pci 1c.2 off end # PCIe Port #3
device pci 1c.3 off end # PCIe Port #4
device pci 1c.4 on # PCIe Port #5
smbios_slot_desc "0xB6" "4" "SLOT2" "0x0A"
end
device pci 1c.5 on end # PCIe Port #6
device pci 1c.6 on end # PCIe Port #7
device pci 1c.7 on end # PCIe Port #8
device pci 1d.0 on end # USB2 EHCI #1
device pci 1e.0 off end # PCI bridge
device pci 1f.0 on # LPC bridge
chip drivers/pc80/tpm
device pnp 0c31.0 on end
end
chip superio/smsc/sch5545
device pnp 2e.c on # LPC
io 0x60 = 0x2e
end
device pnp 2e.0 on # EMI
io 0x60 = 0xa40
end
device pnp 2e.1 on # KBC/PS2M
io 0x60 = 0x60
irq 0x70 = 1
irq 0x72 = 12
end
device pnp 2e.7 on # UART1
io 0x60 = 0x3f8
irq 0x70 = 4
irq 0xf0 = 0x02
end
device pnp 2e.8 off end # UART2
device pnp 2e.a on # Runtime registers
io 0x60 = 0xa00
irq 0x70 = 9 # PME
end
device pnp 2e.b off end # Floppy
device pnp 2e.11 off end # PP
end
end
device pci 1f.2 on end # SATA Controller 1
device pci 1f.3 on end # SMBus
device pci 1f.5 off end # SATA Controller 2
device pci 1f.6 on end # Thermal
end
end
end

View File

@ -0,0 +1,32 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <acpi/acpi.h>
DefinitionBlock(
"dsdt.aml",
"DSDT",
0x02, /* DSDT revision: ACPI 2.0 and up */
OEM_ID,
ACPI_TABLE_CREATOR,
0x20141018 /* OEM revision */
)
{
#include "acpi/platform.asl"
#include <cpu/intel/common/acpi/cpu.asl>
#include <southbridge/intel/common/acpi/platform.asl>
#include <southbridge/intel/bd82x6x/acpi/globalnvs.asl>
#include <southbridge/intel/common/acpi/sleepstates.asl>
Scope (\_SB)
{
Device (PCI0)
{
#include <northbridge/intel/sandybridge/acpi/sandybridge.asl>
#include <southbridge/intel/bd82x6x/acpi/pch.asl>
Device (GLAN)
{
Name (_ADR, 0x00190000)
Name (_PRW, Package() { 13, 4 })
}
}
}
}

View File

@ -0,0 +1,47 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <bootblock_common.h>
#include <device/pci_ops.h>
#include <northbridge/intel/sandybridge/sandybridge.h>
#include <southbridge/intel/bd82x6x/pch.h>
#include <superio/smsc/sch5545/sch5545.h>
#include <superio/smsc/sch5545/sch5545_emi.h>
#include "sch5545_ec.h"
const struct southbridge_usb_port mainboard_usb_ports[] = {
{ 1, 6, 0 },
{ 1, 6, 0 },
{ 1, 1, 1 },
{ 1, 1, 1 },
{ 1, 1, 2 },
{ 1, 1, 2 },
{ 1, 6, 3 },
{ 1, 6, 3 },
{ 1, 6, 4 },
{ 1, 6, 4 },
{ 1, 6, 5 },
{ 1, 1, 5 },
{ 1, 1, 6 },
{ 1, 6, 6 },
};
void bootblock_mainboard_early_init(void)
{
/*
* FIXME: the board gets stuck in reset loop in
* mainboard_romstage_entry. Avoid that by clearing SSKPD
*/
pci_write_config32(HOST_BRIDGE, MCHBAR, (uintptr_t)DEFAULT_MCHBAR | 1);
pci_write_config32(HOST_BRIDGE, MCHBAR + 4, (0LL + (uintptr_t)DEFAULT_MCHBAR) >> 32);
MCHBAR16(SSKPD_HI) = 0;
sch5545_early_init(0x2e);
/* Bare EC and SIO GPIO initialization which allows to enable serial port */
sch5545_emi_init(0x2e);
sch5545_emi_disable_interrupts();
sch5545_ec_early_init();
if (CONFIG(CONSOLE_SERIAL))
sch5545_enable_uart(0x2e, 0);
}

View File

@ -0,0 +1,19 @@
-- SPDX-License-Identifier: GPL-2.0-or-later
with HW.GFX.GMA;
with HW.GFX.GMA.Display_Probing;
use HW.GFX.GMA;
use HW.GFX.GMA.Display_Probing;
private package GMA.Mainboard is
ports : constant Port_List :=
(DP1,
DP2,
HDMI1,
HDMI2,
Analog,
others => Disabled);
end GMA.Mainboard;

View File

@ -0,0 +1,208 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <southbridge/intel/common/gpio.h>
static const struct pch_gpio_set1 pch_gpio_set1_mode = {
.gpio0 = GPIO_MODE_NATIVE,
.gpio1 = GPIO_MODE_GPIO, /* CHASSIS_ID0 */
.gpio2 = GPIO_MODE_GPIO,
.gpio3 = GPIO_MODE_GPIO,
.gpio4 = GPIO_MODE_GPIO, /* VGA_CBL_DET# */
.gpio5 = GPIO_MODE_GPIO,
.gpio6 = GPIO_MODE_GPIO, /* PCH_HS_DET# (unused?) */
.gpio7 = GPIO_MODE_GPIO, /* SKU2 */
.gpio8 = GPIO_MODE_GPIO,
.gpio9 = GPIO_MODE_NATIVE,
.gpio10 = GPIO_MODE_NATIVE,
.gpio11 = GPIO_MODE_GPIO, /* PCIE_X4_WAKE*/
.gpio12 = GPIO_MODE_NATIVE,
.gpio13 = GPIO_MODE_GPIO, /* PCIE_X1_WAKE (MT/DT only)*/
.gpio14 = GPIO_MODE_GPIO,
.gpio15 = GPIO_MODE_GPIO,
.gpio16 = GPIO_MODE_GPIO,
.gpio17 = GPIO_MODE_GPIO, /* CHASSIS_ID1 */
.gpio18 = GPIO_MODE_NATIVE,
.gpio19 = GPIO_MODE_NATIVE,
.gpio20 = GPIO_MODE_GPIO, /* FLEXBAY_HDR_CBL_DET# */
.gpio21 = GPIO_MODE_GPIO, /* BOARD_REV0 */
.gpio22 = GPIO_MODE_GPIO,
.gpio23 = GPIO_MODE_GPIO,
.gpio24 = GPIO_MODE_GPIO,
.gpio25 = GPIO_MODE_NATIVE,
.gpio26 = GPIO_MODE_NATIVE,
.gpio27 = GPIO_MODE_GPIO,
.gpio28 = GPIO_MODE_GPIO,
.gpio29 = GPIO_MODE_GPIO,
.gpio30 = GPIO_MODE_NATIVE,
.gpio31 = GPIO_MODE_GPIO, /* Password Clear Jumper */
};
static const struct pch_gpio_set1 pch_gpio_set1_direction = {
.gpio1 = GPIO_DIR_INPUT,
.gpio2 = GPIO_DIR_INPUT,
.gpio3 = GPIO_DIR_INPUT,
.gpio4 = GPIO_DIR_INPUT,
.gpio5 = GPIO_DIR_INPUT,
.gpio6 = GPIO_DIR_INPUT,
.gpio7 = GPIO_DIR_INPUT,
.gpio8 = GPIO_DIR_OUTPUT,
.gpio11 = GPIO_DIR_INPUT,
.gpio13 = GPIO_DIR_INPUT,
.gpio14 = GPIO_DIR_OUTPUT,
.gpio15 = GPIO_DIR_OUTPUT,
.gpio16 = GPIO_DIR_INPUT,
.gpio17 = GPIO_DIR_INPUT,
.gpio20 = GPIO_DIR_INPUT,
.gpio21 = GPIO_DIR_INPUT,
.gpio22 = GPIO_DIR_INPUT,
.gpio23 = GPIO_DIR_INPUT,
.gpio24 = GPIO_DIR_INPUT,
.gpio27 = GPIO_DIR_OUTPUT,
.gpio28 = GPIO_DIR_OUTPUT,
.gpio29 = GPIO_DIR_OUTPUT,
.gpio31 = GPIO_DIR_INPUT,
};
static const struct pch_gpio_set1 pch_gpio_set1_level = {
.gpio8 = GPIO_LEVEL_HIGH,
.gpio14 = GPIO_LEVEL_HIGH,
.gpio15 = GPIO_LEVEL_LOW,
.gpio27 = GPIO_LEVEL_LOW,
.gpio28 = GPIO_LEVEL_LOW,
.gpio29 = GPIO_LEVEL_HIGH,
};
static const struct pch_gpio_set1 pch_gpio_set1_reset = {
};
static const struct pch_gpio_set1 pch_gpio_set1_invert = {
.gpio2 = GPIO_INVERT,
.gpio5 = GPIO_INVERT,
.gpio6 = GPIO_INVERT,
.gpio11 = GPIO_INVERT,
.gpio13 = GPIO_INVERT,
};
static const struct pch_gpio_set1 pch_gpio_set1_blink = {
};
static const struct pch_gpio_set2 pch_gpio_set2_mode = {
.gpio32 = GPIO_MODE_GPIO, /* SKU0 */
.gpio33 = GPIO_MODE_GPIO,
.gpio34 = GPIO_MODE_GPIO,
.gpio35 = GPIO_MODE_GPIO, /* SKU1 */
.gpio36 = GPIO_MODE_NATIVE,
.gpio37 = GPIO_MODE_NATIVE,
.gpio38 = GPIO_MODE_GPIO, /* CHASSIS_ID2 */
.gpio39 = GPIO_MODE_GPIO, /* FP_PRESENCE# */
.gpio40 = GPIO_MODE_NATIVE,
.gpio41 = GPIO_MODE_NATIVE,
.gpio42 = GPIO_MODE_NATIVE,
.gpio43 = GPIO_MODE_NATIVE,
.gpio44 = GPIO_MODE_GPIO, /* INTRUD_CBL_DET# */
.gpio45 = GPIO_MODE_GPIO, /* COM_SER2_DET# (unused?) */
.gpio46 = GPIO_MODE_GPIO, /* BOARD_REV1 */
.gpio47 = GPIO_MODE_NATIVE,
.gpio48 = GPIO_MODE_GPIO,
.gpio49 = GPIO_MODE_GPIO,
.gpio50 = GPIO_MODE_NATIVE,
.gpio51 = GPIO_MODE_NATIVE,
.gpio52 = GPIO_MODE_NATIVE,
.gpio53 = GPIO_MODE_NATIVE,
.gpio54 = GPIO_MODE_NATIVE,
.gpio55 = GPIO_MODE_NATIVE,
.gpio56 = GPIO_MODE_NATIVE,
.gpio57 = GPIO_MODE_GPIO,
.gpio58 = GPIO_MODE_NATIVE,
.gpio59 = GPIO_MODE_NATIVE,
.gpio60 = GPIO_MODE_GPIO,
.gpio61 = GPIO_MODE_NATIVE,
.gpio62 = GPIO_MODE_NATIVE,
.gpio63 = GPIO_MODE_NATIVE,
};
static const struct pch_gpio_set2 pch_gpio_set2_direction = {
.gpio32 = GPIO_DIR_INPUT,
.gpio33 = GPIO_DIR_OUTPUT,
.gpio34 = GPIO_DIR_OUTPUT,
.gpio35 = GPIO_DIR_INPUT,
.gpio38 = GPIO_DIR_INPUT,
.gpio39 = GPIO_DIR_INPUT,
.gpio44 = GPIO_DIR_INPUT,
.gpio45 = GPIO_DIR_INPUT,
.gpio46 = GPIO_DIR_INPUT,
.gpio48 = GPIO_DIR_INPUT,
.gpio49 = GPIO_DIR_OUTPUT,
.gpio57 = GPIO_DIR_OUTPUT,
.gpio60 = GPIO_DIR_OUTPUT,
.gpio63 = GPIO_DIR_OUTPUT,
};
static const struct pch_gpio_set2 pch_gpio_set2_level = {
.gpio33 = GPIO_LEVEL_HIGH,
.gpio34 = GPIO_LEVEL_HIGH,
.gpio49 = GPIO_LEVEL_HIGH,
.gpio57 = GPIO_LEVEL_LOW,
.gpio60 = GPIO_LEVEL_HIGH,
};
static const struct pch_gpio_set2 pch_gpio_set2_reset = {
};
static const struct pch_gpio_set3 pch_gpio_set3_mode = {
.gpio64 = GPIO_MODE_NATIVE,
.gpio65 = GPIO_MODE_NATIVE,
.gpio66 = GPIO_MODE_NATIVE,
.gpio67 = GPIO_MODE_NATIVE,
.gpio68 = GPIO_MODE_GPIO, /* BOARD_REV2 */
.gpio69 = GPIO_MODE_GPIO, /* USB_HDR_DET# */
.gpio70 = GPIO_MODE_GPIO, /* FP_CHAS_DET# */
.gpio71 = GPIO_MODE_GPIO,
.gpio72 = GPIO_MODE_GPIO,
.gpio73 = GPIO_MODE_GPIO,
.gpio74 = GPIO_MODE_GPIO, /* ME_MFG_MODE */
.gpio75 = GPIO_MODE_NATIVE,
};
static const struct pch_gpio_set3 pch_gpio_set3_direction = {
.gpio68 = GPIO_DIR_INPUT,
.gpio69 = GPIO_DIR_INPUT,
.gpio70 = GPIO_DIR_INPUT,
.gpio71 = GPIO_DIR_OUTPUT,
.gpio72 = GPIO_DIR_OUTPUT,
.gpio73 = GPIO_DIR_INPUT,
.gpio74 = GPIO_DIR_OUTPUT,
};
static const struct pch_gpio_set3 pch_gpio_set3_level = {
.gpio71 = GPIO_LEVEL_HIGH,
.gpio72 = GPIO_LEVEL_HIGH,
.gpio74 = GPIO_LEVEL_HIGH,
};
static const struct pch_gpio_set3 pch_gpio_set3_reset = {
.gpio74 = GPIO_RESET_RSMRST,
};
const struct pch_gpio_map mainboard_gpio_map = {
.set1 = {
.mode = &pch_gpio_set1_mode,
.direction = &pch_gpio_set1_direction,
.level = &pch_gpio_set1_level,
.blink = &pch_gpio_set1_blink,
.invert = &pch_gpio_set1_invert,
.reset = &pch_gpio_set1_reset,
},
.set2 = {
.mode = &pch_gpio_set2_mode,
.direction = &pch_gpio_set2_direction,
.level = &pch_gpio_set2_level,
.reset = &pch_gpio_set2_reset,
},
.set3 = {
.mode = &pch_gpio_set3_mode,
.direction = &pch_gpio_set3_direction,
.level = &pch_gpio_set3_level,
.reset = &pch_gpio_set3_reset,
},
};

View File

@ -0,0 +1,36 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <device/azalia_device.h>
const u32 cim_verb_data[] = {
0x10ec0269, /* Codec Vendor / Device ID: Realtek */
0x1028052c, /* Subsystem ID */
11, /* Number of 4 dword sets */
AZALIA_SUBVENDOR(0, 0x1028052c),
AZALIA_PIN_CFG(0, 0x12, 0x411111f0),
AZALIA_PIN_CFG(0, 0x14, 0x99130110),
AZALIA_PIN_CFG(0, 0x17, 0x411111f0),
AZALIA_PIN_CFG(0, 0x18, 0x02a19830),
AZALIA_PIN_CFG(0, 0x19, 0x01a19840),
AZALIA_PIN_CFG(0, 0x1a, 0x411111f0),
AZALIA_PIN_CFG(0, 0x1b, 0x01014020),
AZALIA_PIN_CFG(0, 0x1d, 0x411111f0),
AZALIA_PIN_CFG(0, 0x1e, 0x411111f0),
AZALIA_PIN_CFG(0, 0x21, 0x0221402f),
0x80862806, /* Codec Vendor / Device ID: Intel */
0x80860101, /* Subsystem ID */
4, /* Number of 4 dword sets */
AZALIA_SUBVENDOR(3, 0x80860101),
AZALIA_PIN_CFG(3, 0x05, 0x18560010),
AZALIA_PIN_CFG(3, 0x06, 0x18560020),
AZALIA_PIN_CFG(3, 0x07, 0x58560030),
};
const u32 pc_beep_verbs[0] = {};
AZALIA_ARRAY_SIZES;

View File

@ -0,0 +1,191 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <bootstate.h>
#include <console/console.h>
#include <device/device.h>
#include <device/pci_ops.h>
#include <drivers/intel/gma/int15.h>
#include <southbridge/intel/bd82x6x/pch.h>
#include <southbridge/intel/common/gpio.h>
#include <superio/smsc/sch5545/sch5545.h>
#include "sch5545_ec.h"
#define SIO_PORT 0x2e
#define GPIO_CHASSIS_ID0 1
#define GPIO_VGA_CABLE_DET_L 4
#define GPIO_SKU2 7
#define GPIO_CHASSIS_ID1 17
/* Internal USB header on mainboard */
#define FLEXBAY_HEADER_CABLE_DET_L 20
#define GPIO_BOARD_REV0 21
/* Password clear jumper */
#define GPIO_PSWD_CLR 31
#define GPIO_SKU0 32
#define GPIO_SKU1 35
#define GPIO_CHASSIS_ID2 37
/* Front panel presence */
#define GPIO_FRONT_PANEL_PRESENT_L 39
#define GPIO_INTRUDER_CABLE_DET_L 44
#define GPIO_BOARD_REV1 46
#define GPIO_BOARD_REV2 68
/* Front USB 3.0 ports */
#define GPIO_USB_HEADER_DET_L 69
/* Differentiate between MT/DT on the Medium Tower and Desktop variants */
#define GPIO_FRONT_PANEL_CHASSIS_DET_L 70
/*
* This GPIO is connected to the transistor gate. If high, it will pull the
* HDA_SDO high. When strapped at PCH_PWROK it will enable the Flash Descriptor
* Security Override and disable ME after chipset bringup. Alternative method
* is to use the service jumper on the mainboard.
*/
#define GPIO_ME_MFG_MODE 74
/* These GPIOs are on SCH5545 */
/* Detect if the power switch cable is connected */
#define SIO_GPIO_FP_CBL_DET_L 25
/* Detect internal speaker connected to front cover */
#define SIO_GPIO_PCSPKR_DET_L 31
static void mainboard_enable(struct device *dev)
{
int pin_sts;
install_intel_vga_int15_handler(GMA_INT15_ACTIVE_LFP_NONE,
GMA_INT15_PANEL_FIT_DEFAULT,
GMA_INT15_BOOT_DISPLAY_DEFAULT, 0);
pin_sts = get_gpio(GPIO_CHASSIS_ID0);
pin_sts |= get_gpio(GPIO_CHASSIS_ID1) << 1;
pin_sts |= get_gpio(GPIO_CHASSIS_ID2) << 2;
pin_sts |= get_gpio(GPIO_FRONT_PANEL_CHASSIS_DET_L) << 3;
printk(BIOS_DEBUG, "Chassis type:");
switch (pin_sts) {
case 0:
printk(BIOS_DEBUG, "MT\n");
break;
case 3:
case 11:
printk(BIOS_DEBUG, "USFF\n");
break;
case 4:
/* As per table in schematics, but don't know what this is */
printk(BIOS_DEBUG, "Comoros\n");
break;
case 1:
case 9:
case 5:
case 13:
printk(BIOS_DEBUG, "SFF\n");
break;
case 8:
printk(BIOS_DEBUG, "DT\n");
break;
default:
printk(BIOS_DEBUG, "Unknown chassis type %u\n", pin_sts);
break;
}
pin_sts = get_gpio(GPIO_BOARD_REV0);
pin_sts |= get_gpio(GPIO_BOARD_REV1) << 1;
pin_sts |= get_gpio(GPIO_BOARD_REV2) << 2;
printk(BIOS_DEBUG, "Board revision: %d\n", pin_sts);
pin_sts = get_gpio(GPIO_SKU0);
pin_sts |= get_gpio(GPIO_SKU1) << 1;
pin_sts |= get_gpio(GPIO_SKU2) << 2;
printk(BIOS_DEBUG, "SKU ID is %d:", pin_sts);
switch (pin_sts) {
case 0:
printk(BIOS_DEBUG, "TPM\n");
break;
case 1:
printk(BIOS_DEBUG, "TCM\n");
break;
case 2:
printk(BIOS_DEBUG, "Non TPM/TCM\n");
break;
default:
printk(BIOS_DEBUG, "Unknown/reserved\n");
break;
}
printk(BIOS_DEBUG, "VGA cable %sconnected\n",
get_gpio(GPIO_VGA_CABLE_DET_L) ? "dis" : "");
printk(BIOS_DEBUG, "Flexbay %sattached to internal USB 2.0 header\n",
get_gpio(FLEXBAY_HEADER_CABLE_DET_L) ? "not " : "");
printk(BIOS_DEBUG, "Password clear jumper %sactive\n",
get_gpio(GPIO_PSWD_CLR) ? "in" : "");
if (!get_gpio(GPIO_FRONT_PANEL_PRESENT_L)) {
printk(BIOS_DEBUG, "Front panel cable connected\n");
} else {
printk(BIOS_WARNING, "Front panel cable not connected!\n");
printk(BIOS_WARNING, "Front USB 2.0 ports, SATA LED, microphone"
" and speaker jacks will not work!\n");
printk(BIOS_WARNING, "Check the front panel cable!\n");
}
if (!get_gpio(GPIO_INTRUDER_CABLE_DET_L)) {
printk(BIOS_DEBUG, "Intruder cable connected\n");
} else {
printk(BIOS_WARNING, "Intruder cable not connected!\n");
printk(BIOS_WARNING, "Intrusion detection will not work!\n");
printk(BIOS_WARNING, "Check the intruder cable!\n");
}
if (!get_gpio(GPIO_USB_HEADER_DET_L)) {
printk(BIOS_DEBUG, "Front USB 3.0 cable connected\n");
} else {
printk(BIOS_WARNING, "Front USB 3.0 cable not connected!\n");
printk(BIOS_WARNING, "Front USB 3.0 ports will not work!\n");
printk(BIOS_WARNING, "Check the front USB 3.0 cable!\n");
}
}
static void mainboard_final(void *chip_info)
{
int pin_sts;
struct device *dev = pcidev_on_root(0x1f, 0);
const u8 pirq_routing = 11;
pci_write_config8(dev, PIRQA_ROUT, pirq_routing);
pci_write_config8(dev, PIRQB_ROUT, pirq_routing);
pci_write_config8(dev, PIRQC_ROUT, pirq_routing);
pci_write_config8(dev, PIRQD_ROUT, pirq_routing);
pci_write_config8(dev, PIRQE_ROUT, pirq_routing);
pci_write_config8(dev, PIRQF_ROUT, pirq_routing);
pci_write_config8(dev, PIRQG_ROUT, pirq_routing);
pci_write_config8(dev, PIRQH_ROUT, pirq_routing);
pin_sts = sch5545_get_gpio(SIO_PORT, SIO_GPIO_FP_CBL_DET_L);
if (pin_sts != -1) {
if (pin_sts) {
printk(BIOS_WARNING, "Power switch cable not connected!\n");
printk(BIOS_WARNING, "Check power switch cable!\n");
} else {
printk(BIOS_DEBUG, "Power switch cable connected\n");
}
}
pin_sts = sch5545_get_gpio(SIO_PORT, SIO_GPIO_PCSPKR_DET_L);
if (pin_sts != -1)
printk(BIOS_DEBUG, "Internal chassis PC speaker %sconnected\n",
pin_sts ? "not " : "");
}
struct chip_operations mainboard_ops = {
.enable_dev = mainboard_enable,
.final = mainboard_final,
};
BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_EXIT, sch5545_ec_hwm_init, NULL);

View File

@ -0,0 +1,53 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <stdint.h>
#include <arch/io.h>
#include <console/console.h>
#include <northbridge/intel/sandybridge/sandybridge.h>
#include <northbridge/intel/sandybridge/raminit_native.h>
#include <southbridge/intel/bd82x6x/pch.h>
#include <superio/smsc/sch5545/sch5545.h>
#include <superio/smsc/sch5545/sch5545_emi.h>
#include "sch5545_ec.h"
void mainboard_early_init(int s3resume)
{
uint16_t ec_fw_version;
/*
* We do EC initialization in romstage, because it makes no sense to
* bloat the bootblock any more. Secondly, the EC expects to receive
* correct initialization sequence from the host in the time window of
* about 3-5 seconds since system reset. If it doesn't receive the
* initialization sequence, it enters an error path which results in
* fans spinned up to high speed. In this state EC doesn't respond to
* further messages sent over EMI. The issue appears after power
* failure, where EC loses its configuration. For this particular
* reasons we do the initialization in romstage instead of ramstage.
*/
sch5545_emi_init(0x2e);
if (sch5545_emi_get_int_mask_high())
printk(BIOS_SPEW, "EC interrupt mask MSB is not 0\n");
sch5545_ec_hwm_early_init();
if (!s3resume) {
ec_fw_version = sch5545_get_ec_fw_version();
printk(BIOS_DEBUG, "SCH5545 EC firmware version %04x\n", ec_fw_version);
sch5545_update_ec_firmware(ec_fw_version);
}
printk(BIOS_DEBUG, "EC early init complete.\n");
/* Disable SMIs and clear SMI status */
outb(0, SCH5545_RUNTIME_REG_BASE + SCH5545_RR_SMI_EN);
outb(SCH5545_SMI_GLOBAL_STS, SCH5545_RUNTIME_REG_BASE + SCH5545_RR_SMI_STS);
}
void mainboard_get_spd(spd_raw_data *spd, bool id_only)
{
read_spd(&spd[0], 0x50, id_only);
read_spd(&spd[1], 0x51, id_only);
read_spd(&spd[2], 0x52, id_only);
read_spd(&spd[3], 0x53, id_only);
}

View File

@ -0,0 +1,726 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <cbfs.h>
#include <cf9_reset.h>
#include <string.h>
#include <option.h>
#include <arch/io.h>
#include <cpu/x86/msr.h>
#include <console/console.h>
#include <cpu/intel/model_206ax/model_206ax.h>
#include <southbridge/intel/common/gpio.h>
#include <superio/smsc/sch5545/sch5545.h>
#include <superio/smsc/sch5545/sch5545_emi.h>
#include "sch5545_ec.h"
#define GPIO_CHASSIS_ID0 1
#define GPIO_CHASSIS_ID1 17
#define GPIO_CHASSIS_ID2 37
#define GPIO_FRONT_PANEL_CHASSIS_DET_L 70
enum {
TDP_16 = 0x10,
TDP_32 = 0x20,
TDP_COMMON = 0xff,
};
typedef struct ec_val_reg_tdp {
uint8_t val;
uint16_t reg;
uint8_t tdp;
} ec_chassis_tdp_t;
static const struct ec_val_reg ec_hwm_init_seq[] = {
{ 0xa0, 0x02fc },
{ 0x32, 0x02fd },
{ 0x77, 0x0005 },
{ 0x0f, 0x0018 },
{ 0x2f, 0x0019 },
{ 0x2f, 0x001a },
{ 0x33, 0x008a },
{ 0x33, 0x008b },
{ 0x33, 0x008c },
{ 0x10, 0x00ba },
{ 0xff, 0x00d1 },
{ 0xff, 0x00d6 },
{ 0xff, 0x00db },
{ 0x00, 0x0048 },
{ 0x00, 0x0049 },
{ 0x00, 0x007a },
{ 0x00, 0x007b },
{ 0x00, 0x007c },
{ 0x00, 0x0080 },
{ 0x00, 0x0081 },
{ 0x00, 0x0082 },
{ 0xbb, 0x0083 },
{ 0xb0, 0x0084 },
{ 0x88, 0x01a1 },
{ 0x80, 0x01a4 },
{ 0x00, 0x0088 },
{ 0x00, 0x0089 },
{ 0x02, 0x00a0 },
{ 0x02, 0x00a1 },
{ 0x02, 0x00a2 },
{ 0x04, 0x00a4 },
{ 0x04, 0x00a5 },
{ 0x04, 0x00a6 },
{ 0x00, 0x00ab },
{ 0x3f, 0x00ad },
{ 0x07, 0x00b7 },
{ 0x50, 0x0062 },
{ 0x46, 0x0063 },
{ 0x50, 0x0064 },
{ 0x46, 0x0065 },
{ 0x50, 0x0066 },
{ 0x46, 0x0067 },
{ 0x98, 0x0057 },
{ 0x98, 0x0059 },
{ 0x7c, 0x0061 },
{ 0x00, 0x01bc },
{ 0x00, 0x01bd },
{ 0x00, 0x01bb },
{ 0xdd, 0x0085 },
{ 0xdd, 0x0086 },
{ 0x07, 0x0087 },
{ 0x5e, 0x0090 },
{ 0x5e, 0x0091 },
{ 0x5d, 0x0095 },
{ 0x00, 0x0096 },
{ 0x00, 0x0097 },
{ 0x00, 0x009b },
{ 0x86, 0x00ae },
{ 0x86, 0x00af },
{ 0x67, 0x00b3 },
{ 0xff, 0x00c4 },
{ 0xff, 0x00c5 },
{ 0xff, 0x00c9 },
{ 0x01, 0x0040 },
{ 0x00, 0x02fc },
{ 0x9a, 0x02b3 },
{ 0x05, 0x02b4 },
{ 0x01, 0x02cc },
{ 0x4c, 0x02d0 },
{ 0x01, 0x02d2 },
{ 0x01, 0x006f },
{ 0x02, 0x0070 },
{ 0x03, 0x0071 },
};
static const ec_chassis_tdp_t ec_hwm_chassis3[] = {
{ 0x33, 0x0005, TDP_COMMON },
{ 0x2f, 0x0018, TDP_COMMON },
{ 0x2f, 0x0019, TDP_COMMON },
{ 0x2f, 0x001a, TDP_COMMON },
{ 0x00, 0x0080, TDP_COMMON },
{ 0x00, 0x0081, TDP_COMMON },
{ 0xbb, 0x0083, TDP_COMMON },
{ 0x8a, 0x0085, TDP_16 },
{ 0x2c, 0x0086, TDP_16 },
{ 0x66, 0x008a, TDP_16 },
{ 0x5b, 0x008b, TDP_16 },
{ 0x65, 0x0090, TDP_COMMON },
{ 0x70, 0x0091, TDP_COMMON },
{ 0x86, 0x0092, TDP_COMMON },
{ 0xa4, 0x0096, TDP_COMMON },
{ 0xa4, 0x0097, TDP_COMMON },
{ 0xa4, 0x0098, TDP_COMMON },
{ 0xa4, 0x009b, TDP_COMMON },
{ 0x0e, 0x00a0, TDP_COMMON },
{ 0x0e, 0x00a1, TDP_COMMON },
{ 0x7c, 0x00ae, TDP_COMMON },
{ 0x86, 0x00af, TDP_COMMON },
{ 0x95, 0x00b0, TDP_COMMON },
{ 0x9a, 0x00b3, TDP_COMMON },
{ 0x08, 0x00b6, TDP_COMMON },
{ 0x08, 0x00b7, TDP_COMMON },
{ 0x64, 0x00ea, TDP_COMMON },
{ 0xff, 0x00ef, TDP_COMMON },
{ 0x15, 0x00f8, TDP_COMMON },
{ 0x00, 0x00f9, TDP_COMMON },
{ 0x30, 0x00f0, TDP_COMMON },
{ 0x01, 0x00fd, TDP_COMMON },
{ 0x88, 0x01a1, TDP_COMMON },
{ 0x08, 0x01a2, TDP_COMMON },
{ 0x08, 0x01b1, TDP_COMMON },
{ 0x94, 0x01be, TDP_COMMON },
{ 0x94, 0x0280, TDP_16 },
{ 0x11, 0x0281, TDP_16 },
{ 0x03, 0x0282, TDP_COMMON },
{ 0x0a, 0x0283, TDP_COMMON },
{ 0x80, 0x0284, TDP_COMMON },
{ 0x03, 0x0285, TDP_COMMON },
{ 0x68, 0x0288, TDP_16 },
{ 0x10, 0x0289, TDP_16 },
{ 0x03, 0x028a, TDP_COMMON },
{ 0x0a, 0x028b, TDP_COMMON },
{ 0x80, 0x028c, TDP_COMMON },
{ 0x03, 0x028d, TDP_COMMON },
};
static const ec_chassis_tdp_t ec_hwm_chassis4[] = {
{ 0x33, 0x0005, TDP_COMMON },
{ 0x2f, 0x0018, TDP_COMMON },
{ 0x2f, 0x0019, TDP_COMMON },
{ 0x2f, 0x001a, TDP_COMMON },
{ 0x00, 0x0080, TDP_COMMON },
{ 0x00, 0x0081, TDP_COMMON },
{ 0xbb, 0x0083, TDP_COMMON },
{ 0x99, 0x0085, TDP_32 },
{ 0x98, 0x0085, TDP_16 },
{ 0xbc, 0x0086, TDP_32 },
{ 0x1c, 0x0086, TDP_16 },
{ 0x39, 0x008a, TDP_32 },
{ 0x3d, 0x008a, TDP_16 },
{ 0x40, 0x008b, TDP_32 },
{ 0x43, 0x008b, TDP_16 },
{ 0x68, 0x0090, TDP_COMMON },
{ 0x5e, 0x0091, TDP_COMMON },
{ 0x86, 0x0092, TDP_COMMON },
{ 0xa4, 0x0096, TDP_COMMON },
{ 0xa4, 0x0097, TDP_COMMON },
{ 0xa4, 0x0098, TDP_COMMON },
{ 0xa4, 0x009b, TDP_COMMON },
{ 0x0c, 0x00a0, TDP_COMMON },
{ 0x0c, 0x00a1, TDP_COMMON },
{ 0x72, 0x00ae, TDP_COMMON },
{ 0x7c, 0x00af, TDP_COMMON },
{ 0x9a, 0x00b0, TDP_COMMON },
{ 0x7c, 0x00b3, TDP_COMMON },
{ 0x08, 0x00b6, TDP_COMMON },
{ 0x08, 0x00b7, TDP_COMMON },
{ 0x64, 0x00ea, TDP_COMMON },
{ 0xff, 0x00ef, TDP_COMMON },
{ 0x15, 0x00f8, TDP_COMMON },
{ 0x00, 0x00f9, TDP_COMMON },
{ 0x30, 0x00f0, TDP_COMMON },
{ 0x01, 0x00fd, TDP_COMMON },
{ 0x88, 0x01a1, TDP_COMMON },
{ 0x08, 0x01a2, TDP_COMMON },
{ 0x08, 0x01b1, TDP_COMMON },
{ 0x90, 0x01be, TDP_COMMON },
{ 0x94, 0x0280, TDP_32 },
{ 0x11, 0x0281, TDP_32 },
{ 0x68, 0x0280, TDP_16 },
{ 0x10, 0x0281, TDP_16 },
{ 0x03, 0x0282, TDP_COMMON },
{ 0x0a, 0x0283, TDP_COMMON },
{ 0x80, 0x0284, TDP_COMMON },
{ 0x03, 0x0285, TDP_COMMON },
{ 0xa0, 0x0288, TDP_32 },
{ 0x0f, 0x0289, TDP_32 },
{ 0xd8, 0x0288, TDP_16 },
{ 0x0e, 0x0289, TDP_16 },
{ 0x03, 0x028a, TDP_COMMON },
{ 0x0a, 0x028b, TDP_COMMON },
{ 0x80, 0x028c, TDP_COMMON },
{ 0x03, 0x028d, TDP_COMMON },
};
static const ec_chassis_tdp_t ec_hwm_chassis5[] = {
{ 0x33, 0x0005, TDP_COMMON },
{ 0x2f, 0x0018, TDP_COMMON },
{ 0x2f, 0x0019, TDP_COMMON },
{ 0x2f, 0x001a, TDP_COMMON },
{ 0x00, 0x0080, TDP_COMMON },
{ 0x00, 0x0081, TDP_COMMON },
{ 0xbb, 0x0083, TDP_COMMON },
{ 0x89, 0x0085, TDP_32 },
{ 0x99, 0x0085, TDP_16 },
{ 0x9c, 0x0086, TDP_COMMON },
{ 0x39, 0x008a, TDP_32 },
{ 0x42, 0x008a, TDP_16 },
{ 0x6b, 0x008b, TDP_32 },
{ 0x74, 0x008b, TDP_16 },
{ 0x5e, 0x0091, TDP_COMMON },
{ 0x86, 0x0092, TDP_COMMON },
{ 0xa4, 0x0096, TDP_COMMON },
{ 0xa4, 0x0097, TDP_COMMON },
{ 0xa4, 0x0098, TDP_COMMON },
{ 0xa4, 0x009b, TDP_COMMON },
{ 0x0c, 0x00a0, TDP_COMMON },
{ 0x0c, 0x00a1, TDP_COMMON },
{ 0x7c, 0x00ae, TDP_COMMON },
{ 0x7c, 0x00af, TDP_COMMON },
{ 0x9a, 0x00b0, TDP_COMMON },
{ 0x7c, 0x00b3, TDP_COMMON },
{ 0x08, 0x00b6, TDP_COMMON },
{ 0x08, 0x00b7, TDP_COMMON },
{ 0x64, 0x00ea, TDP_COMMON },
{ 0xff, 0x00ef, TDP_COMMON },
{ 0x15, 0x00f8, TDP_COMMON },
{ 0x00, 0x00f9, TDP_COMMON },
{ 0x30, 0x00f0, TDP_COMMON },
{ 0x01, 0x00fd, TDP_COMMON },
{ 0x88, 0x01a1, TDP_COMMON },
{ 0x08, 0x01a2, TDP_COMMON },
{ 0x08, 0x01b1, TDP_COMMON },
{ 0x90, 0x01be, TDP_COMMON },
{ 0x94, 0x0280, TDP_32 },
{ 0x11, 0x0281, TDP_32 },
{ 0x3c, 0x0280, TDP_16 },
{ 0x0f, 0x0281, TDP_16 },
{ 0x03, 0x0282, TDP_COMMON },
{ 0x0a, 0x0283, TDP_COMMON },
{ 0x80, 0x0284, TDP_COMMON },
{ 0x03, 0x0285, TDP_COMMON },
{ 0x60, 0x0288, TDP_32 },
{ 0x09, 0x0289, TDP_32 },
{ 0x98, 0x0288, TDP_16 },
{ 0x08, 0x0289, TDP_16 },
{ 0x03, 0x028a, TDP_COMMON },
{ 0x0a, 0x028b, TDP_COMMON },
{ 0x80, 0x028c, TDP_COMMON },
{ 0x03, 0x028d, TDP_COMMON },
};
static const ec_chassis_tdp_t ec_hwm_chassis6[] = {
{ 0x33, 0x0005, TDP_COMMON },
{ 0x2f, 0x0018, TDP_COMMON },
{ 0x2f, 0x0019, TDP_COMMON },
{ 0x2f, 0x001a, TDP_COMMON },
{ 0x00, 0x0080, TDP_COMMON },
{ 0x00, 0x0081, TDP_COMMON },
{ 0xbb, 0x0083, TDP_COMMON },
{ 0x99, 0x0085, TDP_32 },
{ 0x98, 0x0085, TDP_16 },
{ 0xdc, 0x0086, TDP_32 },
{ 0x9c, 0x0086, TDP_16 },
{ 0x3d, 0x008a, TDP_32 },
{ 0x43, 0x008a, TDP_16 },
{ 0x4e, 0x008b, TDP_32 },
{ 0x47, 0x008b, TDP_16 },
{ 0x6d, 0x0090, TDP_COMMON },
{ 0x5f, 0x0091, TDP_32 },
{ 0x61, 0x0091, TDP_16 },
{ 0x86, 0x0092, TDP_COMMON },
{ 0xa4, 0x0096, TDP_COMMON },
{ 0xa4, 0x0097, TDP_COMMON },
{ 0xa4, 0x0098, TDP_COMMON },
{ 0xa4, 0x009b, TDP_COMMON },
{ 0x0e, 0x00a0, TDP_COMMON },
{ 0x0e, 0x00a1, TDP_COMMON },
{ 0x7c, 0x00ae, TDP_COMMON },
{ 0x7c, 0x00af, TDP_COMMON },
{ 0x98, 0x00b0, TDP_32 },
{ 0x9a, 0x00b0, TDP_16 },
{ 0x9a, 0x00b3, TDP_COMMON },
{ 0x08, 0x00b6, TDP_COMMON },
{ 0x08, 0x00b7, TDP_COMMON },
{ 0x64, 0x00ea, TDP_COMMON },
{ 0xff, 0x00ef, TDP_COMMON },
{ 0x15, 0x00f8, TDP_COMMON },
{ 0x00, 0x00f9, TDP_COMMON },
{ 0x30, 0x00f0, TDP_COMMON },
{ 0x01, 0x00fd, TDP_COMMON },
{ 0x88, 0x01a1, TDP_COMMON },
{ 0x08, 0x01a2, TDP_COMMON },
{ 0x08, 0x01b1, TDP_COMMON },
{ 0x97, 0x01be, TDP_32 },
{ 0x95, 0x01be, TDP_16 },
{ 0x68, 0x0280, TDP_32 },
{ 0x10, 0x0281, TDP_32 },
{ 0xd8, 0x0280, TDP_16 },
{ 0x0e, 0x0281, TDP_16 },
{ 0x03, 0x0282, TDP_COMMON },
{ 0x0a, 0x0283, TDP_COMMON },
{ 0x80, 0x0284, TDP_COMMON },
{ 0x03, 0x0285, TDP_COMMON },
{ 0xe4, 0x0288, TDP_32 },
{ 0x0c, 0x0289, TDP_32 },
{ 0x10, 0x0288, TDP_16 },
{ 0x0e, 0x0289, TDP_16 },
{ 0x03, 0x028a, TDP_COMMON },
{ 0x0a, 0x028b, TDP_COMMON },
{ 0x80, 0x028c, TDP_COMMON },
{ 0x03, 0x028d, TDP_COMMON },
};
static uint8_t send_mbox_msg_with_int(uint8_t mbox_message)
{
uint8_t int_sts, int_cond;
sch5545_emi_h2ec_mbox_write(mbox_message);
do {
int_sts = sch5545_emi_get_int_src_low();
int_cond = int_sts & 0x71;
} while (int_cond == 0);
sch5545_emi_set_int_src_low(int_cond);
if ((int_sts & 1) == 0)
return 0;
if (sch5545_emi_ec2h_mbox_read() == mbox_message)
return 1;
return 0;
}
static uint8_t send_mbox_msg_simple(uint8_t mbox_message)
{
uint8_t int_sts;
sch5545_emi_h2ec_mbox_write(mbox_message);
do {
int_sts = sch5545_emi_get_int_src_low();
if ((int_sts & 70) != 0)
return 0;
} while ((int_sts & 1) == 0);
if (sch5545_emi_ec2h_mbox_read() == mbox_message)
return 1;
return 0;
}
static void ec_check_mbox_and_int_status(uint8_t int_src, uint8_t mbox_msg)
{
uint8_t val;
val = sch5545_emi_ec2h_mbox_read();
if (val != mbox_msg)
printk(BIOS_SPEW, "EC2H mailbox should be %02x, is %02x\n", mbox_msg, val);
val = sch5545_emi_get_int_src_low();
if (val != int_src)
printk(BIOS_SPEW, "EC INT SRC should be %02x, is %02x\n", int_src, val);
sch5545_emi_set_int_src_low(val);
}
static uint8_t ec_read_write_reg(uint8_t ldn, uint16_t reg, uint8_t *value, uint8_t rw_bit)
{
uint8_t int_mask_bckup, ret = 0;
rw_bit &= 1;
int_mask_bckup = sch5545_emi_get_int_mask_low();
sch5545_emi_set_int_mask_low(0);
sch5545_emi_ec_write16(0x8000, (ldn << 1) | 0x100 | rw_bit);
if (rw_bit)
sch5545_emi_ec_write32(0x8004, (reg << 16) | *value);
else
sch5545_emi_ec_write32(0x8004, reg << 16);
ret = send_mbox_msg_with_int(1);
if (ret && !rw_bit)
*value = sch5545_emi_ec_read8(0x8004);
else if (ret != 1 && rw_bit)
printk(BIOS_WARNING, "EC mailbox returned unexpected value "
"when writing %02x to %04x\n", *value, reg);
else if (ret != 1 && !rw_bit)
printk(BIOS_WARNING, "EC mailbox returned unexpected value "
"when reading %04x\n", reg);
sch5545_emi_set_int_mask_low(int_mask_bckup);
return ret;
}
uint16_t sch5545_get_ec_fw_version(void)
{
uint8_t val;
uint16_t ec_fw_version;
/* Read the FW version currently loaded used by EC */
ec_read_write_reg(EC_HWM_LDN, 0x2ad, &val, READ_OP);
ec_fw_version = (val << 8);
ec_read_write_reg(EC_HWM_LDN, 0x2ae, &val, READ_OP);
ec_fw_version |= val;
ec_read_write_reg(EC_HWM_LDN, 0x2ac, &val, READ_OP);
ec_read_write_reg(EC_HWM_LDN, 0x2fd, &val, READ_OP);
ec_read_write_reg(EC_HWM_LDN, 0x2b0, &val, READ_OP);
return ec_fw_version;
}
void sch5545_update_ec_firmware(uint16_t ec_version)
{
uint8_t status;
uint16_t ec_fw_version;
uint32_t *ec_fw_file;
size_t ec_fw_file_size;
ec_fw_file = cbfs_boot_map_with_leak("sch5545_ecfw.bin", CBFS_TYPE_RAW,
&ec_fw_file_size);
if (!ec_fw_file || ec_fw_file_size != 0x1750) {
printk(BIOS_ERR, "EC firmware file not found in CBFS!\n");
printk(BIOS_ERR, "The fans will keep running at maximum speed.\n");
return;
}
ec_fw_version = ec_fw_file[3] & 0xffff;
/*
* After power failure EC loses its configuration. The currently used firmware version
* by EC will be reported as 0x0000. In such case EC firmware needs to be uploaded.
*/
if (ec_version != ec_fw_version) {
printk(BIOS_INFO, "SCH5545 EC is not functional, probably due to power "
"failure\n");
printk(BIOS_INFO, "Uploading EC firmware (version %04x) to SCH5545\n",
ec_fw_version);
if (!send_mbox_msg_simple(0x03)) {
printk(BIOS_WARNING, "EC didn't accept FW upload start signal\n");
printk(BIOS_WARNING, "EC firmware update failed!\n");
return;
}
sch5545_emi_ec_write32_bulk(0x8100, ec_fw_file, ec_fw_file_size);
status = send_mbox_msg_simple(0x04);
status += send_mbox_msg_simple(0x06);
if (status != 2)
printk(BIOS_WARNING, "EC firmware update failed!\n");
if (ec_fw_version != sch5545_get_ec_fw_version()) {
printk(BIOS_ERR, "EC firmware update failed!\n");
printk(BIOS_ERR, "The fans will keep running at maximum speed\n");
} else {
printk(BIOS_INFO, "EC firmware update success\n");
/*
* The vendor BIOS does a full reset after EC firmware update. Most
* likely because the fans are adapting very slowly after automatic fan
* control is enabled. This makes huge noise. To avoid it, also do the
* full reset. On next boot, it will not be necessary.
*/
full_reset();
}
} else {
printk(BIOS_INFO, "SCH5545 EC firmware up to date (version %04x)\n",
ec_version);
}
}
void sch5545_ec_hwm_early_init(void)
{
uint8_t val;
int i;
printk(BIOS_DEBUG, "%s\n", __func__);
ec_check_mbox_and_int_status(0x20, 0x01);
ec_read_write_reg(2, 0xcb, &val, READ_OP);
ec_read_write_reg(2, 0xb8, &val, READ_OP);
for (i = 0; i < ARRAY_SIZE(ec_hwm_init_seq); i++) {
val = ec_hwm_init_seq[i].val;
ec_read_write_reg(EC_HWM_LDN, ec_hwm_init_seq[i].reg, &val,
WRITE_OP);
}
ec_check_mbox_and_int_status(0x01, 0x01);
}
static uint8_t get_sku_tdp_config(void)
{
msr_t msr;
uint32_t power_unit, tdp;
/* Get units */
msr = rdmsr(MSR_PKG_POWER_SKU_UNIT);
power_unit = msr.lo & 0xf;
/* Get power defaults for this SKU */
msr = rdmsr(MSR_PKG_POWER_SKU);
tdp = msr.lo & 0x7fff;
/* These numbers will determine which settings to use to init EC */
if ((tdp >> power_unit) < 66)
return 16;
else
return 32;
}
static uint8_t get_chassis_type(void)
{
uint8_t chassis_id;
chassis_id = get_gpio(GPIO_CHASSIS_ID0);
chassis_id |= get_gpio(GPIO_CHASSIS_ID1) << 1;
chassis_id |= get_gpio(GPIO_CHASSIS_ID2) << 2;
chassis_id |= get_gpio(GPIO_FRONT_PANEL_CHASSIS_DET_L) << 3;
/* This mapping will determine which EC init sequence to use */
switch (chassis_id) {
case 0x0:
return 5;
case 0x8:
return 4;
case 0x3:
case 0xb:
return 3;
case 0x1:
case 0x9:
case 0x5:
case 0xd:
return 6;
default:
printk(BIOS_DEBUG, "Unknown chassis ID %x\n", chassis_id);
break;
}
return 0xff;
}
static void ec_hwm_init_late(const ec_chassis_tdp_t *ec_hwm_sequence, size_t size)
{
unsigned int i;
uint8_t val;
uint8_t tdp_config = get_sku_tdp_config();
for (i = 0; i < size; i++) {
if (ec_hwm_sequence[i].tdp == tdp_config ||
ec_hwm_sequence[i].tdp == TDP_COMMON) {
val = ec_hwm_sequence[i].val;
ec_read_write_reg(EC_HWM_LDN, ec_hwm_sequence[i].reg, &val, WRITE_OP);
}
}
}
static void prepare_for_hwm_ec_sequence(uint8_t write_only, uint8_t *value)
{
uint16_t reg;
uint8_t val;
if (write_only == 1) {
val = *value;
reg = 0x02fc;
} else {
if (value != NULL)
ec_read_write_reg(EC_HWM_LDN, 0x02fc, value, READ_OP);
val = 0xa0;
ec_read_write_reg(EC_HWM_LDN, 0x2fc, &val, WRITE_OP);
val = 0x32;
reg = 0x02fd;
}
ec_read_write_reg(1, reg, &val, WRITE_OP);
}
void sch5545_ec_hwm_init(void *unused)
{
uint8_t val, val_2fc, chassis_type, fan_speed_full = 0;
printk(BIOS_DEBUG, "%s\n", __func__);
sch5545_emi_init(0x2e);
chassis_type = get_chassis_type();
ec_read_write_reg(EC_HWM_LDN, 0x0048, &val, READ_OP);
ec_read_write_reg(EC_HWM_LDN, 0x0048, &val, WRITE_OP);
ec_read_write_reg(EC_HWM_LDN, 0x0042, &val, READ_OP);
ec_read_write_reg(EC_HWM_LDN, 0x0048, &val, READ_OP);
val |= 0x02;
ec_read_write_reg(EC_HWM_LDN, 0x0048, &val, WRITE_OP);
ec_read_write_reg(EC_HWM_LDN, 0x0048, &val, READ_OP);
ec_read_write_reg(EC_HWM_LDN, 0x0048, &val, WRITE_OP);
ec_read_write_reg(EC_HWM_LDN, 0x0042, &val, READ_OP);
ec_read_write_reg(EC_HWM_LDN, 0x0048, &val, READ_OP);
val |= 0x04;
ec_read_write_reg(EC_HWM_LDN, 0x0048, &val, WRITE_OP);
ec_read_write_reg(EC_HWM_LDN, 0x0081, &val, READ_OP);
ec_read_write_reg(EC_HWM_LDN, 0x0027, &val, READ_OP);
ec_check_mbox_and_int_status(0x00, 0x01);
prepare_for_hwm_ec_sequence(0, &val_2fc);
if (chassis_type != 0xff) {
printk(BIOS_DEBUG, "Performing HWM init for chassis %d\n", chassis_type);
switch (chassis_type) {
case 3:
ec_hwm_init_late(ec_hwm_chassis3, ARRAY_SIZE(ec_hwm_chassis3));
break;
case 4:
ec_hwm_init_late(ec_hwm_chassis4, ARRAY_SIZE(ec_hwm_chassis4));
break;
case 5:
ec_hwm_init_late(ec_hwm_chassis6, ARRAY_SIZE(ec_hwm_chassis5));
break;
case 6:
ec_hwm_init_late(ec_hwm_chassis6, ARRAY_SIZE(ec_hwm_chassis6));
break;
}
}
if (CONFIG_MAX_CPUS > 2) {
val = 0x30;
ec_read_write_reg(EC_HWM_LDN, 0x009e, &val, WRITE_OP);
ec_read_write_reg(EC_HWM_LDN, 0x00ea, &val, READ_OP);
ec_read_write_reg(EC_HWM_LDN, 0x00eb, &val, WRITE_OP);
}
ec_read_write_reg(EC_HWM_LDN, 0x02fc, &val_2fc, WRITE_OP);
if (get_option(&fan_speed_full, "fan_full_speed") != CB_SUCCESS)
printk(BIOS_INFO, "fan_full_speed CMOS option not found. "
"Fans will be set up for automatic control\n");
if (fan_speed_full) {
ec_read_write_reg(EC_HWM_LDN, 0x0080, &val, READ_OP);
val |= 0x60;
ec_read_write_reg(EC_HWM_LDN, 0x0080, &val, WRITE_OP);
ec_read_write_reg(EC_HWM_LDN, 0x0081, &val, READ_OP);
val |= 0x60;
ec_read_write_reg(EC_HWM_LDN, 0x0081, &val, WRITE_OP);
}
ec_read_write_reg(EC_HWM_LDN, 0x00b8, &val, READ_OP);
if (chassis_type == 4 || chassis_type == 5) {
ec_read_write_reg(EC_HWM_LDN, 0x00a0, &val, READ_OP);
val &= 0xfb;
ec_read_write_reg(EC_HWM_LDN, 0x00a0, &val, WRITE_OP);
ec_read_write_reg(EC_HWM_LDN, 0x00a1, &val, READ_OP);
val &= 0xfb;
ec_read_write_reg(EC_HWM_LDN, 0x00a1, &val, WRITE_OP);
ec_read_write_reg(EC_HWM_LDN, 0x00a2, &val, READ_OP);
val &= 0xfb;
ec_read_write_reg(EC_HWM_LDN, 0x00a2, &val, WRITE_OP);
val = 0x99;
ec_read_write_reg(EC_HWM_LDN, 0x008a, &val, WRITE_OP);
val = 0x47;
ec_read_write_reg(EC_HWM_LDN, 0x008b, &val, WRITE_OP);
val = 0x91;
ec_read_write_reg(EC_HWM_LDN, 0x008c, &val, WRITE_OP);
}
ec_read_write_reg(EC_HWM_LDN, 0x0049, &val, READ_OP);
val &= 0xf7;
ec_read_write_reg(EC_HWM_LDN, 0x0049, &val, WRITE_OP);
val = 0x6a;
if (chassis_type != 3)
ec_read_write_reg(EC_HWM_LDN, 0x0059, &val, WRITE_OP);
else
ec_read_write_reg(EC_HWM_LDN, 0x0057, &val, WRITE_OP);
ec_read_write_reg(EC_HWM_LDN, 0x0041, &val, READ_OP);
val |= 0x40;
ec_read_write_reg(EC_HWM_LDN, 0x0041, &val, WRITE_OP);
if (chassis_type == 3) {
ec_read_write_reg(EC_HWM_LDN, 0x0049, &val, READ_OP);
val |= 0x04;
} else {
ec_read_write_reg(EC_HWM_LDN, 0x0049, &val, READ_OP);
val |= 0x08;
}
ec_read_write_reg(EC_HWM_LDN, 0x0049, &val, WRITE_OP);
val = 0x0e;
ec_read_write_reg(EC_HWM_LDN, 0x007b, &val, WRITE_OP);
ec_read_write_reg(EC_HWM_LDN, 0x007c, &val, WRITE_OP);
val = 0x01;
ec_read_write_reg(EC_HWM_LDN, 0x007a, &val, WRITE_OP);
}

View File

@ -0,0 +1,28 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <stdint.h>
#define READ_OP 0
#define WRITE_OP 1
#define EC_HWM_LDN 1
#define EC_GPIO_LDN 2
/* EC GPIO configuration */
#define EC_GPIO_PP (0 << 0)
#define EC_GPIO_OD (1 << 0)
#define EC_GPIO_FUNC0 (0 << 4)
#define EC_GPIO_FUNC1 (1 << 4)
#define EC_GPIO_FUNC2 (2 << 4)
#define EC_GPIO_FUNC3 (3 << 4)
struct ec_val_reg {
uint8_t val;
uint16_t reg;
};
uint16_t sch5545_get_ec_fw_version(void);
void sch5545_update_ec_firmware(uint16_t ec_version);
void sch5545_ec_early_init(void);
void sch5545_ec_hwm_early_init(void);
void sch5545_ec_hwm_init(void *unused);

View File

@ -0,0 +1,116 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <arch/io.h>
#include <superio/smsc/sch5545/sch5545.h>
#include <superio/smsc/sch5545/sch5545_emi.h>
#include "sch5545_ec.h"
static uint16_t emi_bar;
static const struct ec_val_reg ec_gpio_init_table[] = {
/*
* Probably some early GPIO initialization, setting GPIO functions.
* The LSBs in third column match the GPIO config registers offsets for
* non-default GPIOs.
*/
{ EC_GPIO_PP | EC_GPIO_FUNC1, 0x08cc }, /* GP063 (def) / KBDRST# */
{ EC_GPIO_PP | EC_GPIO_FUNC1, 0x08d0 }, /* GP064 (def) / A20M */
{ EC_GPIO_PP | EC_GPIO_FUNC1, 0x089c }, /* GP047 / TXD1 (def) */
{ EC_GPIO_PP | EC_GPIO_FUNC1, 0x0878 }, /* GP036 (def) / SMBCLK1 */
{ EC_GPIO_PP | EC_GPIO_FUNC1, 0x0880 }, /* GP040 (def) / SMBDAT1 */
{ EC_GPIO_OD | EC_GPIO_FUNC1, 0x0884 }, /* GP041 (def) / IO_PME# */
{ EC_GPIO_PP | EC_GPIO_FUNC1, 0x08e4 }, /* GP071 (def) / IO_SMI# */
{ EC_GPIO_PP | EC_GPIO_FUNC1, 0x08e0 }, /* GP070 (def) / SPEAKER */
{ EC_GPIO_PP | EC_GPIO_FUNC1, 0x0848 }, /* GP022 (def) / PWM1 */
{ EC_GPIO_PP | EC_GPIO_FUNC1, 0x084c }, /* GP023 (def) / PWM2 */
{ EC_GPIO_PP | EC_GPIO_FUNC1, 0x0850 }, /* GP024 (def) / PWM3 */
{ EC_GPIO_PP | EC_GPIO_FUNC1, 0x083c }, /* GP017 / TACH1 (def) */
{ EC_GPIO_PP | EC_GPIO_FUNC1, 0x0840 }, /* GP020 / TACH2 (def) */
{ EC_GPIO_PP | EC_GPIO_FUNC1, 0x0844 }, /* GP021 / TACH3 (def) */
{ EC_GPIO_PP | EC_GPIO_FUNC1, 0x0814 }, /* GP005 (def) / PECI_REQ# */
};
static const struct ec_val_reg ec_hwm_early_init_table[] = {
/* Probably some early hardware monitor initialization */
{ 0xff, 0x0005 },
{ 0x30, 0x00f0 },
{ 0x10, 0x00f8 },
{ 0x00, 0x00f9 },
{ 0x00, 0x00fa },
{ 0x00, 0x00fb },
{ 0x00, 0x00ea },
{ 0x00, 0x00eb },
{ 0x7c, 0x00ef },
{ 0x03, 0x006e },
{ 0x51, 0x02d0 },
{ 0x01, 0x02d2 },
{ 0x12, 0x059a },
{ 0x11, 0x059e },
{ 0x14, 0x05a2 },
{ 0x55, 0x05a3 },
{ 0x01, 0x02db },
{ 0x01, 0x0040 },
};
static void ec_read_write_reg_timeout(uint16_t ldn, uint8_t *val, uint16_t reg,
uint8_t rw_bit)
{
uint16_t timeout = 0;
rw_bit &= 1;
sch5545_emi_ec2h_mailbox_clear();
sch5545_emi_ec_write16(0x8000, (ldn << 1) | 0x100 | rw_bit);
sch5545_emi_set_ec_addr(0x8004);
if (rw_bit)
outb(*val, emi_bar + SCH5545_EMI_EC_DATA);
outb(reg & 0xff, emi_bar + SCH5545_EMI_EC_DATA + 2);
outb((reg >> 8) & 0xff, emi_bar + SCH5545_EMI_EC_DATA + 3);
sch5545_emi_h2ec_mbox_write(1);
do {
timeout++;
if ((sch5545_emi_ec2h_mbox_read() & 1) != 0)
break;
} while (timeout < 0xfff);
sch5545_emi_set_int_src(0x11);
sch5545_emi_h2ec_mbox_write(0xc0);
if (!rw_bit)
*val = inb(emi_bar + SCH5545_EMI_EC_DATA);
}
static void ec_init_gpios(void)
{
unsigned int i;
uint8_t val;
for (i = 0; i < ARRAY_SIZE(ec_gpio_init_table); i++) {
val = ec_gpio_init_table[i].val;
ec_read_write_reg_timeout(EC_GPIO_LDN, &val, ec_gpio_init_table[i].reg,
WRITE_OP);
}
}
static void ec_early_hwm_init(void)
{
unsigned int i;
uint8_t val;
for (i = 0; i < ARRAY_SIZE(ec_hwm_early_init_table); i++) {
val = ec_hwm_early_init_table[i].val;
ec_read_write_reg_timeout(EC_HWM_LDN, &val, ec_hwm_early_init_table[i].reg,
WRITE_OP);
}
}
void sch5545_ec_early_init(void)
{
emi_bar = sch5545_read_emi_bar(0x2e);
ec_init_gpios();
ec_early_hwm_init();
}

View File

@ -0,0 +1,47 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <stdint.h>
#include <arch/io.h>
#include <console/console.h>
#include <cpu/x86/smm.h>
#include <superio/smsc/sch5545/sch5545.h>
void mainboard_smi_gpi(u32 gpi_sts)
{
printk(BIOS_SPEW, "%s: gpi_sts: %08x\n", __func__, gpi_sts);
}
int mainboard_smi_apmc(u8 data)
{
u8 val;
switch (data) {
case APM_CNT_ACPI_ENABLE:
printk(BIOS_SPEW, "%s: APM CNT EN: %02x\n", __func__, data);
/* Enable wake on PS2 */
val = inb(SCH5545_RUNTIME_REG_BASE + SCH5545_RR_PME_EN1);
val |= (SCH5545_KBD_PME_EN | SCH5545_MOUSE_PME_EN);
outb(val, SCH5545_RUNTIME_REG_BASE + SCH5545_RR_PME_EN1);
/* Clear pending and enable PMEs */
outb(SCH5545_GLOBAL_PME_STS, SCH5545_RUNTIME_REG_BASE + SCH5545_RR_PME_STS);
outb(SCH5545_GLOBAL_PME_EN, SCH5545_RUNTIME_REG_BASE + SCH5545_RR_PME_EN);
break;
case APM_CNT_ACPI_DISABLE:
printk(BIOS_SPEW, "%s: APM CNT DIS: %02x\n", __func__, data);
/* Disable wake on PS2 */
val = inb(SCH5545_RUNTIME_REG_BASE + SCH5545_RR_PME_EN1);
val &= ~(SCH5545_KBD_PME_EN | SCH5545_MOUSE_PME_EN);
outb(val, SCH5545_RUNTIME_REG_BASE + SCH5545_RR_PME_EN1);
/* Clear pending and disable PMEs */
outb(SCH5545_GLOBAL_PME_STS, SCH5545_RUNTIME_REG_BASE + SCH5545_RR_PME_STS);
outb(0, SCH5545_RUNTIME_REG_BASE + SCH5545_RR_PME_EN);
break;
default:
break;
}
return 0;
}
void mainboard_smi_sleep(u8 slp_typ)
{
printk(BIOS_SPEW, "%s: SMI sleep: %02x\n", __func__, slp_typ);
}