mainboard/lenovo/t430s: Add ThinkPad T431s as a variant

The code is based on autoport and that for T430s

Tested:
- CPU i5-3337U
- Slotted DIMM 2GiB
- Soldered RAM 4GiB from samsung (There may be more models here)
- Camera
- pci-e and usb2 on M.2 slot with A key for wlan
- sata and usb2  (no superspeed components) on M.2 slot with B key for wwan
- On board SDHCI connected to pci-e
- USB3 ports
- libgfxinit-based graphic init
- NVRAM options for North and South bridges
- Sound
- Thinkpad EC
- S3
- TPM1 on LPC
- EHCI debug on SSP2 (USB3 port on the left)
- Linux 4.9.110-3 within Debian GNU/Linux stable, loaded from
  Linux payload (Heads), Seabios may also work.

Not tested:
- Fingerprint reader on USB2 (not present on mine)
- Keyboard backlight (not present on mine)
- "sticky_fn" flag in nvram

Not implemented yet:
- Fn locking in nvram (may not be identical to "sticky_fn")
- C-based native graphic init (since T431s has eDP instead of LVDS)
- Detecting the model of Soldered RAM at runtime, and loading the
  corresponding SPD datum (3 observed) from CBFS (the mechanism may be
  similar to that on x1_carbon_gen1 and s230u, but I do not know how
  to find gpio ports for that, and SPD data stored in vendor firmware.)

Change-Id: Ic8062cacf5e8232405bb5757e1b1d063541f354a
Signed-off-by: Bill XIE <persmule@gmail.com>
Reviewed-on: https://review.coreboot.org/c/30021
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Patrick Rudolph <siro@das-labor.org>
This commit is contained in:
Bill XIE 2018-11-29 20:37:35 +08:00 committed by Patrick Georgi
parent d2226060aa
commit 012ef7735d
27 changed files with 793 additions and 220 deletions

View File

@ -60,6 +60,7 @@ The boards in this section are not real mainboards, but emulators.
- [T530](lenovo/w530.md) - [T530](lenovo/w530.md)
- [W530](lenovo/w530.md) - [W530](lenovo/w530.md)
- [T430 / T530 / X230 / W530 common](lenovo/xx30_series.md) - [T430 / T530 / X230 / W530 common](lenovo/xx30_series.md)
- [T431s](lenovo/t431s.md)
## SiFive ## SiFive

View File

@ -0,0 +1,42 @@
# Lenovo T431s
## Disassembly Instructions
You must remove the following parts before flipping the mainboard
off the main frame:
![t431s_bc_removed](t431s_bc_removed.jpg)
* Base cover
* Hard disk drive
* Battery pack
* Keyboard
Its [Hardware Maintenance Manual](https://thinkpads.com/support/hmm/hmm_pdf/t431s_hmm_en_0c10894_02.pdf) could be used as a guidance of disassembly.
![t431s_flash_chip](t431s_flash_chip.jpg)
The WSON-8 flash chip (surrounded with red circle in the photo above)
sits on the opposite side of the mainboard, under a piece of insulating
tape. If solders between the chip and soldering pads fortunately
overflows beside the chip as tiny tin balls attached to soldering pads,
it will be possible to use a pomona 5250 clip to hold the chip, with
its metal tips just attached to tin balls, thus connecting the chip to
the programmer.
![t431s_programming](t431s_programming.jpg)
```eval_rst
:doc:`../../flash_tutorial/ext_power`
```
Currently, detecting the model of soldered RAM at runtime and loading
the corresponding SPD datum from CBFS is not implemented yet. You may
have to dump the SPD data when running the vendor firmware with
inteltool, and replace the content of the SPD hex with what is dumped.
(the mechanism may be similar to that on x1_carbon_gen1 and s230u, but
I do not know how to find gpio ports for that, and SPD data stored in
vendor firmware.)
[T420 / T520 / X220 / T420s / W520 common]: xx20_series.md

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

View File

@ -1,4 +1,4 @@
if BOARD_LENOVO_T430S if BOARD_LENOVO_T430S || BOARD_LENOVO_T431S
config BOARD_SPECIFIC_OPTIONS config BOARD_SPECIFIC_OPTIONS
def_bool y def_bool y
@ -16,12 +16,12 @@ config BOARD_SPECIFIC_OPTIONS
select HAVE_CMOS_DEFAULT select HAVE_CMOS_DEFAULT
select HAVE_ACPI_RESUME select HAVE_ACPI_RESUME
select INTEL_INT15 select INTEL_INT15
select SANDYBRIDGE_IVYBRIDGE_LVDS select SANDYBRIDGE_IVYBRIDGE_LVDS if BOARD_LENOVO_T430S
select ENABLE_VMX select ENABLE_VMX
select MAINBOARD_HAS_LPC_TPM select MAINBOARD_HAS_LPC_TPM
select MAINBOARD_HAS_TPM1 select MAINBOARD_HAS_TPM1
select MAINBOARD_HAS_LIBGFXINIT select MAINBOARD_HAS_LIBGFXINIT
select GFX_GMA_INTERNAL_IS_LVDS select GFX_GMA_INTERNAL_IS_LVDS if BOARD_LENOVO_T430S
select INTEL_GMA_HAVE_VBT select INTEL_GMA_HAVE_VBT
# Workaround for EC/KBC IRQ1. # Workaround for EC/KBC IRQ1.
@ -31,9 +31,19 @@ config MAINBOARD_DIR
string string
default lenovo/t430s default lenovo/t430s
config VARIANT_DIR
string
default "t430s" if BOARD_LENOVO_T430S
default "t431s" if BOARD_LENOVO_T431S
config MAINBOARD_PART_NUMBER config MAINBOARD_PART_NUMBER
string string
default "ThinkPad T430s" default "ThinkPad T430s" if BOARD_LENOVO_T430S
default "ThinkPad T431s" if BOARD_LENOVO_T431S
config OVERRIDE_DEVICETREE
string
default "variants/$(CONFIG_VARIANT_DIR)/overridetree.cb"
config MAX_CPUS config MAX_CPUS
int int
@ -57,10 +67,11 @@ config MAINBOARD_PCI_SUBSYSTEM_VENDOR_ID
config MAINBOARD_PCI_SUBSYSTEM_DEVICE_ID config MAINBOARD_PCI_SUBSYSTEM_DEVICE_ID
hex hex
default 0x21fb default 0x21fb if BOARD_LENOVO_T430S
default 0x2208 if BOARD_LENOVO_T431S
config ONBOARD_VGA_IS_PRIMARY config ONBOARD_VGA_IS_PRIMARY
bool bool
default y default y
endif # BOARD_LENOVO_T430S endif # BOARD_LENOVO_T430S || BOARD_LENOVO_T431S

View File

@ -1,2 +1,5 @@
config BOARD_LENOVO_T430S config BOARD_LENOVO_T430S
bool "ThinkPad T430s" bool "ThinkPad T430s"
config BOARD_LENOVO_T431S
bool "ThinkPad T431s"

View File

@ -14,5 +14,8 @@
## ##
smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c
romstage-y += gpio.c romstage-y += variants/$(VARIANT_DIR)/gpio.c
romstage-y += variants/$(VARIANT_DIR)/romstage.c
ramstage-y += variants/$(VARIANT_DIR)/hda_verb.c
ramstage-$(CONFIG_MAINBOARD_USE_LIBGFXINIT) += gma-mainboard.ads ramstage-$(CONFIG_MAINBOARD_USE_LIBGFXINIT) += gma-mainboard.ads
subdirs-$(CONFIG_BOARD_LENOVO_T431S) += variants/$(VARIANT_DIR)/spd

View File

@ -1,4 +1,5 @@
Category: laptop Category: laptop
Board name: ThinkPad T430s baseboard
ROM package: SOIC-8 / WSON-8 ROM package: SOIC-8 / WSON-8
ROM protocol: SPI ROM protocol: SPI
ROM socketed: n ROM socketed: n

View File

@ -65,8 +65,8 @@ chip northbridge/intel/sandybridge
register "gen4_dec" = "0x0c06a1" register "gen4_dec" = "0x0c06a1"
register "pcie_hotplug_map" = "{ 0, 0, 1, 0, 0, 0, 0, 0 }" register "pcie_hotplug_map" = "{ 0, 0, 1, 0, 0, 0, 0, 0 }"
# Wire port 4 (wwan usb) to ehci for it lacks superspeed components
register "xhci_switchable_ports" = "0xf" register "xhci_switchable_ports" = "0x7"
register "superspeed_capable_ports" = "0xf" register "superspeed_capable_ports" = "0xf"
register "xhci_overcurrent_mapping" = "0x4000201" register "xhci_overcurrent_mapping" = "0x4000201"
@ -74,6 +74,7 @@ chip northbridge/intel/sandybridge
register "pcie_port_coalesce" = "1" register "pcie_port_coalesce" = "1"
register "c2_latency" = "101" # c2 not supported register "c2_latency" = "101" # c2 not supported
register "p_cnt_throttling_supported" = "1" register "p_cnt_throttling_supported" = "1"
register "docking_supported" = "1"
register "spi_uvscc" = "0x2005" register "spi_uvscc" = "0x2005"
register "spi_lvscc" = "0x2005" register "spi_lvscc" = "0x2005"
@ -154,10 +155,6 @@ chip northbridge/intel/sandybridge
register "eventc_enable" = "0xff" register "eventc_enable" = "0xff"
register "eventd_enable" = "0xff" register "eventd_enable" = "0xff"
register "evente_enable" = "0x0d" register "evente_enable" = "0x0d"
register "has_bdc_detection" = "1"
register "bdc_gpio_num" = "54"
register "bdc_gpio_lvl" = "0"
end end
end # LPC Controller end # LPC Controller
device pci 1f.2 on device pci 1f.2 on

View File

@ -1,127 +1 @@
/* /* dummy */
* This file is part of the coreboot project.
*
* Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
* Copyright (C) 2014 Vladimir Serbinenko
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* Vendor Name : Realtek
* Vendor ID : 0x10ec0269
* Subsystem ID : 0x17aa21fb
* Revision ID : 0x100203
*/
#include <device/azalia_device.h>
const u32 cim_verb_data[] = {
/* coreboot specific header */
0x10ec0269, // Codec Vendor / Device ID: Realtek ALC269VC
0x17aa21fb, // Subsystem ID
0x00000013, // Number of 4 dword sets
/* Bits 31:28 - Codec Address */
/* Bits 27:20 - NID */
/* Bits 19:8 - Verb ID */
/* Bits 7:0 - Payload */
/* NID 0x01 - NodeInfo */
AZALIA_SUBVENDOR(0x0, 0x17AA21FB),
/* NID 0x0A - External Microphone Connector
* Config=0x04A11020 (External,Right; MicIn,3.5mm; Black,JD; DA,Seq)
*/
AZALIA_PIN_CFG(0x0, 0x0A, 0x04A11020),
/* NID 0x0B - Headphone Connector
* Config=0x0421101F (External,Right; HP,3.5mm; Black,JD; DA,Seq)
*/
AZALIA_PIN_CFG(0x0, 0x0B, 0x0421101F),
/* NID 0x0C - Not connected
* Config=0x40F000F0 (N/A,N/A; Other,Unknown; Unknown,JD; DA,Seq)
*/
AZALIA_PIN_CFG(0x0, 0x0C, 0x40F000F0),
/* NID 0x0D - Internal Speakers
* Config=0x90170110 (Fixed,Int; Speaker,Other Analog; Unknown,nJD; DA,Seq)
*/
AZALIA_PIN_CFG(0x0, 0x0D, 0x90170110),
/* NID 0x0F - Not connected
* Config=0x40F000F0
*/
AZALIA_PIN_CFG(0x0, 0x0F, 0x40F000F0),
/* NID 0x11 - Internal Microphone
* Config=0xD5A30140 (Fixed internal,Top; Mic In,ATIPI; Unknown,nJD; DA,Seq)
*/
AZALIA_PIN_CFG(0x0, 0x12, 0x90A60140),
AZALIA_PIN_CFG(0x0, 0x14, 0x90170110),
AZALIA_PIN_CFG(0x0, 0x15, 0x03211020),
AZALIA_PIN_CFG(0x0, 0x17, 0x411111F0),
AZALIA_PIN_CFG(0x0, 0x18, 0x03A11830),
AZALIA_PIN_CFG(0x0, 0x19, 0x411111F0),
0x01970804,
0x01870803,
0x01470740,
0x00970600,
AZALIA_PIN_CFG(0x0, 0x1A, 0x411111F0),
AZALIA_PIN_CFG(0x0, 0x1B, 0x411111F0),
AZALIA_PIN_CFG(0x0, 0x1D, 0x40138205),
AZALIA_PIN_CFG(0x0, 0x1E, 0x411111F0),
/* Misc entries */
0x00370600,
0x00270600,
0x00B707C0, /* Enable PortB as Output with HP amp */
0x00D70740, /* Enable PortD as Output */
0x0017A200, /* Disable ClkEn of PortSenseTst */
0x0017C621, /* Slave Port - Port A used as microphone input for
combo Jack
Master Port - Port B used for Jack Presence Detect
Enable Combo Jack Detection */
0x0017A208, /* Enable ClkEn of PortSenseTst */
0x00170500, /* Set power state to D0 */
/* --- Next Codec --- */
/* Vendor Name : Intel
* Vendor ID : 0x80862806
* Subsystem ID : 0x80860101
* Revision ID : 0x100000
*/
/* coreboot specific header */
0x80862806, // Codec Vendor / Device ID: Intel PantherPoint HDMI
0x80860101, // Subsystem ID
0x00000004, // Number of IDs
/* NID 0x01, HDA Codec Subsystem ID Verb Table: 0x80860101 */
AZALIA_SUBVENDOR(0x3, 0x80860101),
/* Pin Complex (NID 0x05) Digital Out at Int HDMI */
AZALIA_PIN_CFG(0x3, 0x05, 0x18560010),
/* Pin Complex (NID 0x06) Digital Out at Int HDMI */
AZALIA_PIN_CFG(0x3, 0x06, 0x18560020),
/* Pin Complex (NID 0x07) Digital Out at Int HDMI */
AZALIA_PIN_CFG(0x3, 0x07, 0x18560030)
};
const u32 pc_beep_verbs[] = {
0x02177a00, /* Digital PCBEEP Gain: 0h=-9db, 1h=-6db ... 4h=+3db, 5h=+6db */
};
AZALIA_ARRAY_SIZES;

View File

@ -15,13 +15,8 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <option.h> #include <northbridge/intel/sandybridge/sandybridge.h>
#include <arch/byteorder.h>
#include <arch/io.h>
#include <device/pci_def.h>
#include <northbridge/intel/sandybridge/raminit_native.h>
#include <southbridge/intel/bd82x6x/pch.h> #include <southbridge/intel/bd82x6x/pch.h>
#include <ec/lenovo/pmh7/pmh7.h>
void pch_enable_lpc(void) void pch_enable_lpc(void)
{ {
@ -41,47 +36,6 @@ void mainboard_rcba_config(void)
{ {
} }
const struct southbridge_usb_port mainboard_usb_ports[] = {
{ 1, 0, 0 }, /* P0:, OC 0 */
{ 1, 1, 1 }, /* P1: (EHCI debug), OC 1 */
{ 1, 1, 3 }, /* P2: OC 3 */
{ 1, 0, -1 }, /* P3: no OC */
{ 1, 2, -1 }, /* P4: no OC */
{ 1, 1, -1 }, /* P5: no OC */
{ 1, 1, -1 }, /* P6: no OC */
{ 0, 1, -1 }, /* P7: empty, no OC */
{ 1, 1, -1 }, /* P8: smart card reader, no OC */
{ 1, 0, 5 }, /* P9: (EHCI debug), OC 5 */
{ 1, 0, -1 }, /* P10: fingerprint reader, no OC */
{ 1, 1, -1 }, /* P11: bluetooth, no OC. */
{ 0, 0, -1 }, /* P12: wlan, no OC */
{ 1, 1, -1 }, /* P13: camera, no OC */
};
void mainboard_get_spd(spd_raw_data *spd, bool id_only) {
read_spd(&spd[0], 0x50, id_only);
read_spd(&spd[2], 0x51, id_only);
}
void mainboard_early_init(int s3resume) {
u8 enable_peg;
if (get_option(&enable_peg, "enable_dual_graphics") != CB_SUCCESS)
enable_peg = 0;
bool power_en = pmh7_dgpu_power_state();
if (enable_peg != power_en)
pmh7_dgpu_power_enable(!power_en);
if (!enable_peg) {
// Hide disabled dGPU device
u32 reg32 = pci_read_config32(PCI_DEV(0, 0, 0), DEVEN);
reg32 &= ~DEVEN_PEG10;
pci_write_config32(PCI_DEV(0, 0, 0), DEVEN, reg32);
}
}
void mainboard_config_superio(void) void mainboard_config_superio(void)
{ {
} }

View File

@ -28,17 +28,17 @@
static void mainboard_smi_brightness_up(void) static void mainboard_smi_brightness_up(void)
{ {
u8 value; u8 value = pci_read_config8(PCI_DEV(0, 2, 1), 0xf4);
if ((value = pci_read_config8(PCI_DEV(0, 2, 1), 0xf4)) < 0xf0) if (value < 0xf0)
pci_write_config8(PCI_DEV(0, 2, 1), 0xf4, (value + 0x10) | 0xf); pci_write_config8(PCI_DEV(0, 2, 1), 0xf4, (value + 0x10) | 0xf);
} }
static void mainboard_smi_brightness_down(void) static void mainboard_smi_brightness_down(void)
{ {
u8 value; u8 value = pci_read_config8(PCI_DEV(0, 2, 1), 0xf4);
if ((value = pci_read_config8(PCI_DEV(0, 2, 1), 0xf4)) > 0x10) if (value > 0x10)
pci_write_config8(PCI_DEV(0, 2, 1), 0xf4, pci_write_config8(PCI_DEV(0, 2, 1), 0xf4,
(value - 0x10) & 0xf0); (value - 0x10) & 0xf0);
} }
@ -55,16 +55,16 @@ static void mainboard_smi_handle_ec_sci(void)
printk(BIOS_DEBUG, "EC event %02x\n", event); printk(BIOS_DEBUG, "EC event %02x\n", event);
switch (event) { switch (event) {
case 0x14: case 0x14:
/* brightness up */ /* brightness up */
mainboard_smi_brightness_up(); mainboard_smi_brightness_up();
break; break;
case 0x15: case 0x15:
/* brightness down */ /* brightness down */
mainboard_smi_brightness_down(); mainboard_smi_brightness_down();
break; break;
default: default:
break; break;
} }
} }
@ -77,25 +77,25 @@ void mainboard_smi_gpi(u32 gpi_sts)
int mainboard_smi_apmc(u8 data) int mainboard_smi_apmc(u8 data)
{ {
switch (data) { switch (data) {
case APM_CNT_ACPI_ENABLE: case APM_CNT_ACPI_ENABLE:
/* use 0x1600/0x1604 to prevent races with userspace */ /* use 0x1600/0x1604 to prevent races with userspace */
ec_set_ports(0x1604, 0x1600); ec_set_ports(0x1604, 0x1600);
/* route EC_SCI to SCI */ /* route EC_SCI to SCI */
gpi_route_interrupt(GPE_EC_SCI, GPI_IS_SCI); gpi_route_interrupt(GPE_EC_SCI, GPI_IS_SCI);
/* discard all events, and enable attention */ /* discard all events, and enable attention */
ec_write(0x80, 0x01); ec_write(0x80, 0x01);
break; break;
case APM_CNT_ACPI_DISABLE: case APM_CNT_ACPI_DISABLE:
/* we have to use port 0x62/0x66, as 0x1600/0x1604 doesn't /* we have to use port 0x62/0x66, as 0x1600/0x1604 doesn't
provide a EC query function */ provide a EC query function */
ec_set_ports(0x66, 0x62); ec_set_ports(0x66, 0x62);
/* route EC_SCI to SMI */ /* route EC_SCI to SMI */
gpi_route_interrupt(GPE_EC_SCI, GPI_IS_SMI); gpi_route_interrupt(GPE_EC_SCI, GPI_IS_SMI);
/* discard all events, and enable attention */ /* discard all events, and enable attention */
ec_write(0x80, 0x01); ec_write(0x80, 0x01);
break; break;
default: default:
break; break;
} }
return 0; return 0;
} }

View File

@ -0,0 +1,7 @@
Category: laptop
Board name: ThinkPad T430s
ROM package: SOIC-8 / WSON-8
ROM protocol: SPI
ROM socketed: n
Flashrom support: n
Release year: 2012

View File

@ -0,0 +1,128 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
* Copyright (C) 2014 Vladimir Serbinenko
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* Vendor Name : Realtek
* Vendor ID : 0x10ec0269
* Subsystem ID : 0x17aa21fb
* Revision ID : 0x100203
*/
#include <device/azalia_device.h>
const u32 cim_verb_data[] = {
/* coreboot specific header */
0x10ec0269, // Codec Vendor / Device ID: Realtek ALC269VC
0x17aa21fb, // Subsystem ID
0x00000013, // Number of 4 dword sets
/* Bits 31:28 - Codec Address */
/* Bits 27:20 - NID */
/* Bits 19:8 - Verb ID */
/* Bits 7:0 - Payload */
/* NID 0x01 - NodeInfo */
AZALIA_SUBVENDOR(0x0, 0x17AA21FB),
/* NID 0x0A - External Microphone Connector
* Config=0x04A11020 (External,Right; MicIn,3.5mm; Black,JD; DA,Seq)
*/
AZALIA_PIN_CFG(0x0, 0x0A, 0x04A11020),
/* NID 0x0B - Headphone Connector
* Config=0x0421101F (External,Right; HP,3.5mm; Black,JD; DA,Seq)
*/
AZALIA_PIN_CFG(0x0, 0x0B, 0x0421101F),
/* NID 0x0C - Not connected
* Config=0x40F000F0 (N/A,N/A; Other,Unknown; Unknown,JD; DA,Seq)
*/
AZALIA_PIN_CFG(0x0, 0x0C, 0x40F000F0),
/* NID 0x0D - Internal Speakers
* Config=0x90170110 (Fixed,Int; Speaker,Other Analog; Unknown,nJD; DA,Seq)
*/
AZALIA_PIN_CFG(0x0, 0x0D, 0x90170110),
/* NID 0x0F - Not connected
* Config=0x40F000F0
*/
AZALIA_PIN_CFG(0x0, 0x0F, 0x40F000F0),
/* NID 0x11 - Internal Microphone
* Config=0xD5A30140 (Fixed internal,Top; Mic In,ATIPI; Unknown,nJD; DA,Seq)
*/
AZALIA_PIN_CFG(0x0, 0x12, 0x90A60140),
AZALIA_PIN_CFG(0x0, 0x14, 0x90170110),
AZALIA_PIN_CFG(0x0, 0x15, 0x03211020),
AZALIA_PIN_CFG(0x0, 0x17, 0x411111F0),
AZALIA_PIN_CFG(0x0, 0x18, 0x03A11830),
AZALIA_PIN_CFG(0x0, 0x19, 0x411111F0),
0x01970804,
0x01870803,
0x01470740,
0x00970600,
AZALIA_PIN_CFG(0x0, 0x1A, 0x411111F0),
AZALIA_PIN_CFG(0x0, 0x1B, 0x411111F0),
AZALIA_PIN_CFG(0x0, 0x1D, 0x40138205),
AZALIA_PIN_CFG(0x0, 0x1E, 0x411111F0),
/* Misc entries */
0x00370600,
0x00270600,
0x00B707C0, /* Enable PortB as Output with HP amp */
0x00D70740, /* Enable PortD as Output */
0x0017A200, /* Disable ClkEn of PortSenseTst */
0x0017C621, /* Slave Port - Port A used as microphone input for
combo Jack
Master Port - Port B used for Jack Presence Detect
Enable Combo Jack Detection */
0x0017A208, /* Enable ClkEn of PortSenseTst */
0x00170500, /* Set power state to D0 */
/* --- Next Codec --- */
/* Vendor Name : Intel
* Vendor ID : 0x80862806
* Subsystem ID : 0x80860101
* Revision ID : 0x100000
*/
/* coreboot specific header */
0x80862806, // Codec Vendor / Device ID: Intel PantherPoint HDMI
0x80860101, // Subsystem ID
0x00000004, // Number of IDs
/* NID 0x01, HDA Codec Subsystem ID Verb Table: 0x80860101 */
AZALIA_SUBVENDOR(0x3, 0x80860101),
/* Pin Complex (NID 0x05) Digital Out at Int HDMI */
AZALIA_PIN_CFG(0x3, 0x05, 0x18560010),
/* Pin Complex (NID 0x06) Digital Out at Int HDMI */
AZALIA_PIN_CFG(0x3, 0x06, 0x18560020),
/* Pin Complex (NID 0x07) Digital Out at Int HDMI */
AZALIA_PIN_CFG(0x3, 0x07, 0x18560030)
};
const u32 pc_beep_verbs[] = {
/* Digital PCBEEP Gain: 0h=-9db, 1h=-6db ... 4h=+3db, 5h=+6db */
0x02177a00,
};
AZALIA_ARRAY_SIZES;

View File

@ -0,0 +1,13 @@
chip northbridge/intel/sandybridge
device domain 0 on
chip southbridge/intel/bd82x6x # Intel Series 7 Panther Point PCH
device pci 1f.0 on
chip ec/lenovo/h8
register "has_bdc_detection" = "1"
register "bdc_gpio_num" = "54"
register "bdc_gpio_lvl" = "0"
end
end # LPC Controller
end
end
end

View File

@ -0,0 +1,67 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007-2010 coresystems GmbH
* Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
* Copyright (C) 2014 Vladimir Serbinenko
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <option.h>
#include <arch/byteorder.h>
#include <arch/io.h>
#include <device/pci_def.h>
#include <northbridge/intel/sandybridge/raminit_native.h>
#include <southbridge/intel/bd82x6x/pch.h>
#include <ec/lenovo/pmh7/pmh7.h>
const struct southbridge_usb_port mainboard_usb_ports[] = {
{ 1, 0, 0 }, /* P0:, OC 0 */
{ 1, 1, 1 }, /* P1: (EHCI debug), OC 1 */
{ 1, 1, 3 }, /* P2: OC 3 */
{ 1, 0, -1 }, /* P3: no OC */
{ 1, 2, -1 }, /* P4: no OC */
{ 1, 1, -1 }, /* P5: no OC */
{ 1, 1, -1 }, /* P6: no OC */
{ 0, 1, -1 }, /* P7: empty, no OC */
{ 1, 1, -1 }, /* P8: smart card reader, no OC */
{ 1, 0, 5 }, /* P9: (EHCI debug), OC 5 */
{ 1, 0, -1 }, /* P10: fingerprint reader, no OC */
{ 1, 1, -1 }, /* P11: bluetooth, no OC. */
{ 0, 0, -1 }, /* P12: wlan, no OC */
{ 1, 1, -1 }, /* P13: camera, no OC */
};
void mainboard_get_spd(spd_raw_data *spd, bool id_only)
{
read_spd(&spd[0], 0x50, id_only);
read_spd(&spd[2], 0x51, id_only);
}
void mainboard_early_init(int s3resume)
{
u8 enable_peg;
if (get_option(&enable_peg, "enable_dual_graphics") != CB_SUCCESS)
enable_peg = 0;
bool power_en = pmh7_dgpu_power_state();
if (enable_peg != power_en)
pmh7_dgpu_power_enable(!power_en);
if (!enable_peg) {
// Hide disabled dGPU device
u32 reg32 = pci_read_config32(PCI_DEV(0, 0, 0), DEVEN);
reg32 &= ~DEVEN_PEG10;
pci_write_config32(PCI_DEV(0, 0, 0), DEVEN, reg32);
}
}

View File

@ -0,0 +1,7 @@
Category: laptop
Board name: ThinkPad T431s baseboard
ROM package: SOIC-8 / WSON-8
ROM protocol: SPI
ROM socketed: n
Flashrom support: n
Release year: 2013

Binary file not shown.

View File

@ -0,0 +1,206 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2008-2009 coresystems GmbH
* Copyright (C) 2014 Vladimir Serbinenko
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; version 2 of
* the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <southbridge/intel/common/gpio.h>
static const struct pch_gpio_set1 pch_gpio_set1_mode = {
.gpio0 = GPIO_MODE_NATIVE,
.gpio1 = GPIO_MODE_GPIO,
.gpio2 = GPIO_MODE_NATIVE,
.gpio3 = GPIO_MODE_GPIO,
.gpio4 = GPIO_MODE_GPIO,
.gpio5 = GPIO_MODE_GPIO,
.gpio6 = GPIO_MODE_NATIVE,
.gpio7 = GPIO_MODE_NATIVE,
.gpio8 = GPIO_MODE_GPIO,
.gpio9 = GPIO_MODE_NATIVE,
.gpio10 = GPIO_MODE_GPIO,
.gpio11 = GPIO_MODE_NATIVE,
.gpio12 = GPIO_MODE_NATIVE,
.gpio13 = GPIO_MODE_GPIO,
.gpio14 = GPIO_MODE_NATIVE,
.gpio15 = GPIO_MODE_GPIO,
.gpio16 = GPIO_MODE_NATIVE,
.gpio17 = GPIO_MODE_NATIVE,
.gpio18 = GPIO_MODE_NATIVE,
.gpio19 = GPIO_MODE_NATIVE,
.gpio20 = GPIO_MODE_NATIVE,
.gpio21 = GPIO_MODE_GPIO,
.gpio22 = GPIO_MODE_NATIVE,
.gpio23 = GPIO_MODE_NATIVE,
.gpio24 = GPIO_MODE_GPIO,
.gpio25 = GPIO_MODE_NATIVE,
.gpio26 = GPIO_MODE_GPIO,
.gpio27 = GPIO_MODE_GPIO,
.gpio28 = GPIO_MODE_GPIO,
.gpio29 = GPIO_MODE_GPIO,
.gpio30 = GPIO_MODE_NATIVE,
.gpio31 = GPIO_MODE_GPIO,
};
static const struct pch_gpio_set1 pch_gpio_set1_direction = {
.gpio1 = GPIO_DIR_INPUT,
.gpio3 = GPIO_DIR_OUTPUT,
.gpio4 = GPIO_DIR_INPUT,
.gpio5 = GPIO_DIR_OUTPUT,
.gpio8 = GPIO_DIR_INPUT,
.gpio10 = GPIO_DIR_OUTPUT,
.gpio13 = GPIO_DIR_INPUT,
.gpio15 = GPIO_DIR_INPUT,
.gpio21 = GPIO_DIR_INPUT,
.gpio24 = GPIO_DIR_OUTPUT,
.gpio26 = GPIO_DIR_INPUT,
.gpio27 = GPIO_DIR_INPUT,
.gpio28 = GPIO_DIR_OUTPUT,
.gpio29 = GPIO_DIR_OUTPUT,
.gpio31 = GPIO_DIR_INPUT,
};
static const struct pch_gpio_set1 pch_gpio_set1_level = {
.gpio3 = GPIO_LEVEL_HIGH,
.gpio5 = GPIO_LEVEL_LOW,
.gpio10 = GPIO_LEVEL_HIGH,
.gpio24 = GPIO_LEVEL_HIGH,
.gpio28 = GPIO_LEVEL_LOW,
.gpio29 = GPIO_LEVEL_HIGH,
};
static const struct pch_gpio_set1 pch_gpio_set1_reset = {
.gpio24 = GPIO_RESET_RSMRST,
};
static const struct pch_gpio_set1 pch_gpio_set1_invert = {
.gpio1 = 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_NATIVE,
.gpio33 = GPIO_MODE_NATIVE,
.gpio34 = GPIO_MODE_GPIO,
.gpio35 = GPIO_MODE_GPIO,
.gpio36 = GPIO_MODE_GPIO,
.gpio37 = GPIO_MODE_GPIO,
.gpio38 = GPIO_MODE_GPIO,
.gpio39 = GPIO_MODE_GPIO,
.gpio40 = GPIO_MODE_NATIVE,
.gpio41 = GPIO_MODE_NATIVE,
.gpio42 = GPIO_MODE_NATIVE,
.gpio43 = GPIO_MODE_GPIO,
.gpio44 = GPIO_MODE_GPIO,
.gpio45 = GPIO_MODE_GPIO,
.gpio46 = GPIO_MODE_NATIVE,
.gpio47 = GPIO_MODE_GPIO,
.gpio48 = GPIO_MODE_GPIO,
.gpio49 = GPIO_MODE_GPIO,
.gpio50 = GPIO_MODE_GPIO,
.gpio51 = GPIO_MODE_NATIVE,
.gpio52 = GPIO_MODE_NATIVE,
.gpio53 = GPIO_MODE_NATIVE,
.gpio54 = GPIO_MODE_NATIVE,
.gpio55 = GPIO_MODE_NATIVE,
.gpio56 = GPIO_MODE_GPIO,
.gpio57 = GPIO_MODE_GPIO,
.gpio58 = GPIO_MODE_NATIVE,
.gpio59 = GPIO_MODE_NATIVE,
.gpio60 = GPIO_MODE_NATIVE,
.gpio61 = GPIO_MODE_NATIVE,
.gpio62 = GPIO_MODE_NATIVE,
.gpio63 = GPIO_MODE_NATIVE,
};
static const struct pch_gpio_set2 pch_gpio_set2_direction = {
.gpio34 = GPIO_DIR_INPUT,
.gpio35 = GPIO_DIR_INPUT,
.gpio36 = GPIO_DIR_INPUT,
.gpio37 = GPIO_DIR_INPUT,
.gpio38 = GPIO_DIR_INPUT,
.gpio39 = GPIO_DIR_INPUT,
.gpio43 = GPIO_DIR_OUTPUT,
.gpio44 = GPIO_DIR_INPUT,
.gpio45 = GPIO_DIR_INPUT,
.gpio47 = GPIO_DIR_INPUT,
.gpio48 = GPIO_DIR_INPUT,
.gpio49 = GPIO_DIR_INPUT,
.gpio50 = GPIO_DIR_INPUT,
.gpio56 = GPIO_DIR_INPUT,
.gpio57 = GPIO_DIR_INPUT,
};
static const struct pch_gpio_set2 pch_gpio_set2_level = {
.gpio43 = 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_GPIO,
.gpio65 = GPIO_MODE_GPIO,
.gpio66 = GPIO_MODE_GPIO,
.gpio67 = GPIO_MODE_GPIO,
.gpio68 = GPIO_MODE_NATIVE,
.gpio69 = GPIO_MODE_GPIO,
.gpio70 = GPIO_MODE_GPIO,
.gpio71 = GPIO_MODE_GPIO,
.gpio72 = GPIO_MODE_NATIVE,
.gpio73 = GPIO_MODE_NATIVE,
.gpio74 = GPIO_MODE_NATIVE,
.gpio75 = GPIO_MODE_NATIVE,
};
static const struct pch_gpio_set3 pch_gpio_set3_direction = {
.gpio64 = GPIO_DIR_INPUT,
.gpio65 = GPIO_DIR_INPUT,
.gpio66 = GPIO_DIR_INPUT,
.gpio67 = GPIO_DIR_INPUT,
.gpio69 = GPIO_DIR_INPUT,
.gpio70 = GPIO_DIR_INPUT,
.gpio71 = GPIO_DIR_INPUT,
};
static const struct pch_gpio_set3 pch_gpio_set3_level = {
};
static const struct pch_gpio_set3 pch_gpio_set3_reset = {
};
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,76 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2008-2009 coresystems GmbH
* Copyright (C) 2014 Vladimir Serbinenko
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; version 2 of
* the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <device/azalia_device.h>
const u32 cim_verb_data[] = {
0x10ec0269, /* Codec Vendor / Device ID: Realtek */
0x17aa2208, /* Subsystem ID */
0x0000000b, /* Number of 4 dword sets */
/* NID 0x01: Subsystem ID. */
AZALIA_SUBVENDOR(0x0, 0x17aa2208),
/* NID 0x12. */
AZALIA_PIN_CFG(0x0, 0x12, 0x90a60140),
/* NID 0x14. */
AZALIA_PIN_CFG(0x0, 0x14, 0x90170110),
/* NID 0x15. */
AZALIA_PIN_CFG(0x0, 0x15, 0x03211020),
/* NID 0x17. */
AZALIA_PIN_CFG(0x0, 0x17, 0x40008000),
/* NID 0x18. */
AZALIA_PIN_CFG(0x0, 0x18, 0x03a11030),
/* NID 0x19. */
AZALIA_PIN_CFG(0x0, 0x19, 0x411111f0),
/* NID 0x1a. */
AZALIA_PIN_CFG(0x0, 0x1a, 0x411111f0),
/* NID 0x1b. */
AZALIA_PIN_CFG(0x0, 0x1b, 0x411111f0),
/* NID 0x1d. */
AZALIA_PIN_CFG(0x0, 0x1d, 0x40f38205),
/* NID 0x1e. */
AZALIA_PIN_CFG(0x0, 0x1e, 0x411111f0),
0x80862806, /* Codec Vendor / Device ID: Intel */
0x80860101, /* Subsystem ID */
0x00000004, /* Number of 4 dword sets */
/* NID 0x01: Subsystem ID. */
AZALIA_SUBVENDOR(0x3, 0x80860101),
/* NID 0x05. */
AZALIA_PIN_CFG(0x3, 0x05, 0x18560010),
/* NID 0x06. */
AZALIA_PIN_CFG(0x3, 0x06, 0x18560020),
/* NID 0x07. */
AZALIA_PIN_CFG(0x3, 0x07, 0x18560030),
};
const u32 pc_beep_verbs[0] = {};
AZALIA_ARRAY_SIZES;

View File

@ -0,0 +1,75 @@
chip northbridge/intel/sandybridge
# Enable DisplayPort Hotplug with 6ms pulse
register "gpu_dp_b_hotplug" = "4"
register "gpu_dp_c_hotplug" = "4"
register "gpu_dp_d_hotplug" = "4"
# Enable Panel as eDP and configure power delays
register "gpu_panel_port_select" = "1" # eDP
register "gpu_panel_power_up_delay" = "2000" # 200ms
register "gpu_panel_power_down_delay" = "500" # 50ms
register "gpu_panel_power_backlight_on_delay" = "1" # 0.1ms
register "gpu_panel_power_backlight_off_delay" = "1" # 0.1ms
register "gpu_cpu_backlight" = "0x03d2"
device domain 0 on
device pci 00.0 on
subsystemid 0x17aa 0x2208
end # host bridge
device pci 01.0 off end # PCIe Bridge for discrete graphics
device pci 02.0 on
subsystemid 0x17aa 0x2208
end # Integrated Graphics Controller
chip southbridge/intel/bd82x6x # Intel Series 7 Panther Point PCH
# Enable SATA ports 0 (HDD bay) & 1 (WWAN M.2 SATA) & 4 (dock)
register "sata_port_map" = "0x13"
# T431s has no Express Card slot.
register "pcie_hotplug_map" = "{ 0, 0, 0, 0, 0, 0, 0, 0 }"
device pci 14.0 on
subsystemid 0x17aa 0x2208
end # USB 3.0 Controller
device pci 1a.0 on
subsystemid 0x17aa 0x2208
end # USB Enhanced Host Controller #2
device pci 1b.0 on
subsystemid 0x17aa 0x2208
end # High Definition Audio Controller
device pci 1c.0 on # PCIe Port #1
subsystemid 0x17aa 0x2208
chip drivers/ricoh/rce822 # Ricoh cardreader
register "disable_mask" = "0x87"
register "sdwppol" = "0"
device pci 00.0 on # Ricoh SD card reader
subsystemid 0x17aa 0x2208
end
end
end
device pci 1c.1 on
subsystemid 0x17aa 0x2208
end # PCIe Port #2 Integrated Wireless LAN
device pci 1c.2 off end # PCIe Port #3
device pci 1d.0 on
subsystemid 0x17aa 0x2208
end # USB Enhanced Host Controller #1
device pci 1e.0 off end # PCI bridge
device pci 1f.0 on
subsystemid 0x17aa 0x2208
chip ec/lenovo/h8
register "config0" = "0xa6"
register "config1" = "0x09"
register "config3" = "0xc0"
register "evente_enable" = "0x1d"
# T431s only has BT on wlan card
register "has_bdc_detection" = "0"
end
end # LPC Controller
device pci 1f.2 on
subsystemid 0x17aa 0x2208
end # 6 port SATA AHCI Controller
device pci 1f.3 on
subsystemid 0x17aa 0x2208
end # SMBus Controller
device pci 1f.6 off end # Thermal
end
end
end

View File

@ -0,0 +1,61 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007-2010 coresystems GmbH
* Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
* Copyright (C) 2014 Vladimir Serbinenko
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <option.h>
#include <arch/byteorder.h>
#include <arch/io.h>
#include <device/pci_def.h>
#include <console/console.h>
#include <cbfs.h>
#include <northbridge/intel/sandybridge/raminit_native.h>
#include <southbridge/intel/bd82x6x/pch.h>
#include <ec/lenovo/pmh7/pmh7.h>
const struct southbridge_usb_port mainboard_usb_ports[] = {
{ 1, 0, 0 }, /* SSP1: right */
{ 1, 0, 1 }, /* SSP2: left, EHCI Debug */
{ 1, 1, 3 }, /* SSP3: dock usb3 */
{ 1, 1, -1 }, /* B0P4: wwan usb */
{ 1, 1, 2 }, /* B0P5: dock usb2 */
{ 0, 0, -1 }, /* B0P6 */
{ 0, 0, -1 }, /* B0P7 */
{ 1, 2, -1 }, /* B0P8: unknown */
{ 1, 0, -1 }, /* B1P1: smart card reader */
{ 0, 2, 5 }, /* B1P2 */
{ 1, 1, -1 }, /* B1P3: fingerprint reader */
{ 0, 0, -1 }, /* B1P4 */
{ 1, 1, -1 }, /* B1P5: wlan usb */
{ 1, 1, -1 }, /* B1P6: Camera */
};
void mainboard_get_spd(spd_raw_data *spd, bool id_only)
{
/* C1S0 is a soldered RAM with no real SPD. Use stored SPD. */
size_t spd_file_len = 0;
void *spd_file = cbfs_boot_map_with_leak("spd.bin", CBFS_TYPE_SPD,
&spd_file_len);
if (!spd_file || spd_file_len < sizeof(spd_raw_data))
die("SPD data for C1S0 not found.");
memcpy(&spd[0], spd_file, spd_file_len);
read_spd(&spd[2], 0x51, id_only);
}
void mainboard_early_init(int s3resume)
{
}

View File

@ -0,0 +1,31 @@
##
## This file is part of the coreboot project.
##
## Copyright (C) 2016 Alexander Couzens <lynxis@fe80.eu>
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; version 2 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
SPD_BIN = $(obj)/spd.bin
SPD_SOURCES = samsung_4gb # 0b0010 4GiB
SPD_DEPS := $(foreach f, $(SPD_SOURCES), src/mainboard/$(MAINBOARDDIR)/variants/$(VARIANT_DIR)/spd/$(f).spd.hex)
# Include spd ROM data
$(SPD_BIN): $(SPD_DEPS)
for f in $+; \
do for c in $$(cat $$f | grep -v ^#); \
do printf $$(printf '\%o' 0x$$c); \
done; \
done > $@
cbfs-files-y += spd.bin
spd.bin-file := $(SPD_BIN)
spd.bin-type := spd

View File

@ -0,0 +1,16 @@
92 11 0b 03 04 00 00 01 03 52 01 08 0a 00 80 00
6e 78 6e 32 6e 11 18 81 20 08 3c 3c 00 f0 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 65 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 b6 3b
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00