diff options
Diffstat (limited to 'src/mainboard/lattepanda/mu')
20 files changed, 1000 insertions, 0 deletions
diff --git a/src/mainboard/lattepanda/mu/Kconfig b/src/mainboard/lattepanda/mu/Kconfig new file mode 100644 index 0000000000..7908aade55 --- /dev/null +++ b/src/mainboard/lattepanda/mu/Kconfig @@ -0,0 +1,30 @@ +## SPDX-License-Identifier: GPL-2.0-only + +if BOARD_LATTEPANDA_MU + +config BOARD_SPECIFIC_OPTIONS + def_bool y + select BOARD_ROMSIZE_KB_16384 + select DRIVERS_SPI_ACPI + select DRIVERS_UART_8250IO + select DRIVERS_USB_ACPI + select FSP_TYPE_IOT + select HAVE_ACPI_RESUME + select HAVE_ACPI_TABLES + select HAVE_SPD_IN_CBFS + select INTEL_GMA_HAVE_VBT + select REALTEK_8168_RESET + select RT8168_GEN_ACPI_POWER_RESOURCE + select SOC_INTEL_ALDERLAKE_PCH_N + select SUPERIO_ITE_IT8613E + +config MAINBOARD_DIR + default "lattepanda/mu" + +config MAINBOARD_PART_NUMBER + default "MU_8G" + +config UART_FOR_CONSOLE + default 0 + +endif diff --git a/src/mainboard/lattepanda/mu/Kconfig.name b/src/mainboard/lattepanda/mu/Kconfig.name new file mode 100644 index 0000000000..7d49671fbf --- /dev/null +++ b/src/mainboard/lattepanda/mu/Kconfig.name @@ -0,0 +1,6 @@ +## SPDX-License-Identifier: GPL-2.0-only + +config BOARD_LATTEPANDA_MU + bool "LattePanda Mu" + help + LattePanda Mu with lite carrier board. diff --git a/src/mainboard/lattepanda/mu/Makefile.mk b/src/mainboard/lattepanda/mu/Makefile.mk new file mode 100644 index 0000000000..b4e894dc44 --- /dev/null +++ b/src/mainboard/lattepanda/mu/Makefile.mk @@ -0,0 +1,17 @@ +## SPDX-License-Identifier: GPL-2.0-only + +subdirs-y += spd + +bootblock-y += bootblock.c +bootblock-y += early_gpio.c + +romstage-y += romstage_fsp_params.c +romstage-y += memory.c + +ramstage-y += mainboard.c +ramstage-y += gpio.c +ramstage-y += ramstage.c + +smm-y += smihandler.c + +CPPFLAGS_common += -I$(src)/mainboard/$(MAINBOARDDIR)/include diff --git a/src/mainboard/lattepanda/mu/board_info.txt b/src/mainboard/lattepanda/mu/board_info.txt new file mode 100644 index 0000000000..b1d0e97018 --- /dev/null +++ b/src/mainboard/lattepanda/mu/board_info.txt @@ -0,0 +1,6 @@ +Vendor name: DFRobot +Board name: LattePanda Mu +Category: sbc +ROM protocol: SPI +ROM socketed: n +Flashrom support: y diff --git a/src/mainboard/lattepanda/mu/bootblock.c b/src/mainboard/lattepanda/mu/bootblock.c new file mode 100644 index 0000000000..4d0216c63b --- /dev/null +++ b/src/mainboard/lattepanda/mu/bootblock.c @@ -0,0 +1,270 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <bootblock_common.h> +#include <arch/io.h> +#include <baseboard/variants.h> +#include <device/pci_ops.h> +#include <device/pnp_ops.h> +#include <intelpch/espi.h> +#include <soc/pci_devs.h> +#include <superio/ite/common/ite.h> +#include <superio/ite/it8613e/it8613e.h> + +#define it8613e_index (0x2e) +#define it8613e_data (0x2f) +#define it8613e_ecdata_base (0xa40) + +#define EC_DEV PNP_DEV(it8613e_index, IT8613E_EC) +#define UART_DEV PNP_DEV(it8613e_index, IT8613E_SP1) + +/* + * IT8613E/LX Super I/O Chip Initialization Settings + */ +struct initdata { + u16 reg; + u8 OpAnd; + u8 OpOr; +}; + +static const struct initdata init_values[] = { + /* Entry ITE SIO configuration */ + { it8613e_index, 0x00, 0x87 }, + { it8613e_index, 0x00, 0x01 }, + { it8613e_index, 0x00, 0x55 }, + { it8613e_index, 0x00, 0x55 }, + /* Start IT8613E/LX config */ + { it8613e_index, 0x00, 0x23 }, + { it8613e_data, 0x1f, 0x40 }, + /* LDN: 04, EC */ + { it8613e_index, 0x00, 0x07 }, + { it8613e_data, 0x00, 0x04 }, + { it8613e_index, 0x00, 0xf0 }, + { it8613e_data, 0x00, 0x00 }, + { it8613e_index, 0x00, 0xf1 }, + { it8613e_data, 0x00, 0xbf }, + { it8613e_index, 0x00, 0xf2 }, + { it8613e_data, 0x00, 0x00 }, + { it8613e_index, 0x00, 0xf3 }, + { it8613e_data, 0x00, 0x00 }, + { it8613e_index, 0x00, 0xf4 }, + { it8613e_data, 0x00, 0x60 }, + { it8613e_index, 0x00, 0xf5 }, + { it8613e_data, 0x3f, 0x00 }, + { it8613e_index, 0x00, 0xfa }, + { it8613e_data, 0x00, 0x00 }, + { it8613e_index, 0x00, 0xfb }, + { it8613e_data, 0xf3, 0x0c }, + /* LDN: 03, Unknown Device */ + { it8613e_index, 0x00, 0x07 }, + { it8613e_data, 0x00, 0x03 }, + { it8613e_index, 0x00, 0xf0 }, + { it8613e_data, 0xf7, 0x08 }, + { it8613e_index, 0x00, 0x07 }, + { it8613e_data, 0x00, 0x07 }, + { it8613e_index, 0x00, 0x28 }, + { it8613e_data, 0xbf, 0x00 }, + { it8613e_index, 0x00, 0x72 }, + { it8613e_data, 0xff, 0x00 }, + { it8613e_index, 0x00, 0x2c }, + { it8613e_data, 0xbf, 0x40 }, + /* LDN: 04, EC */ + { it8613e_index, 0x00, 0x07 }, + { it8613e_data, 0x00, 0x04 }, + /* Set IO1 to 0xa40 */ + { it8613e_index, 0x00, 0x61 }, + { it8613e_data, 0x00, 0x40 }, + { it8613e_index, 0x00, 0x60 }, + { it8613e_data, 0x00, 0x0a }, + /* Set IO2 to 0xa30 */ + { it8613e_index, 0x00, 0x62 }, + { it8613e_data, 0x00, 0x0a }, + { it8613e_index, 0x00, 0x63 }, + { it8613e_data, 0x00, 0x30 }, + /* Enable the EC Device */ + { it8613e_index, 0x00, 0x30 }, + { it8613e_data, 0x00, 0x01 }, + /* for Environment Controller */ + { 0x0a45, 0x00, 0x50 }, + { 0x0a46, 0x00, 0xff }, + { 0x0a45, 0x00, 0x51 }, + { 0x0a46, 0x00, 0x38 }, + { 0x0a45, 0x00, 0x00 }, + { 0x0a46, 0x00, 0x01 }, + { 0x0a45, 0x00, 0x0a }, + { 0x0a46, 0x00, 0x64 }, + { 0x0a45, 0x00, 0x8e }, + { 0x0a46, 0x3f, 0xc0 }, + { 0x0a45, 0x00, 0x00 }, + { 0x0a46, 0x00, 0x40 }, + /* */ + { it8613e_index, 0x00, 0x23 }, + { it8613e_data, 0xfe, 0x00 }, + /* LDN: 07, GPIO */ + { it8613e_index, 0x00, 0x07 }, + { it8613e_data, 0x00, 0x07 }, + { it8613e_index, 0x00, 0x25 }, + { it8613e_data, 0x08, 0x00 }, + { it8613e_index, 0x00, 0x26 }, + { it8613e_data, 0x00, 0x00 }, + { it8613e_index, 0x00, 0x27 }, + { it8613e_data, 0x00, 0x00 }, + { it8613e_index, 0x00, 0x28 }, + { it8613e_data, 0x40, 0x00 }, + { it8613e_index, 0x00, 0x29 }, + { it8613e_data, 0x00, 0x00 }, + { it8613e_index, 0x00, 0x71 }, + { it8613e_data, 0x00, 0x00 }, + { it8613e_index, 0x00, 0x72 }, + { it8613e_data, 0x00, 0x90 }, + { it8613e_index, 0x00, 0x73 }, + { it8613e_data, 0x00, 0x00 }, + { it8613e_index, 0x00, 0x2a }, + { it8613e_data, 0xdf, 0x00 }, + { it8613e_index, 0x00, 0x2b }, + { it8613e_data, 0x0f, 0x00 }, + { it8613e_index, 0x00, 0x2c }, + { it8613e_data, 0x62, 0x00 }, + /* LDN: 05, Keyboard */ + { it8613e_index, 0x00, 0x07 }, + { it8613e_data, 0x00, 0x05 }, + /* Disable the Device */ + { it8613e_index, 0x00, 0x30 }, + { it8613e_data, 0x00, 0x00 }, + /* LDN: 06, Mouse */ + { it8613e_index, 0x00, 0x07 }, + { it8613e_data, 0x00, 0x06 }, + /* Disable the Device */ + { it8613e_index, 0x00, 0x30 }, + { it8613e_data, 0x00, 0x00 }, + /* LDN: 05, Keyboard */ + { it8613e_index, 0x00, 0x07 }, + { it8613e_data, 0x00, 0x05 }, + { it8613e_index, 0x00, 0xf0 }, + { it8613e_data, 0xf7, 0x08 }, + /* LDN: 04, EC */ + { it8613e_index, 0x00, 0x07 }, + { it8613e_data, 0x00, 0x04 }, + { it8613e_index, 0x00, 0xf4 }, + { it8613e_data, 0x7f, 0x80 }, + { it8613e_index, 0x00, 0x70 }, + { it8613e_data, 0x00, 0x00 }, + /* exit ITE config */ + { it8613e_index, 0x00, 0x02 }, + { it8613e_data, 0x00, 0x02 }, +}; + +static void sio_init(const struct initdata *table, const size_t count) +{ + u8 val; + for (size_t i = 0; i < count; i++) { + if (table[i].OpAnd != 0) { + val = inb(table->reg) & table[i].OpAnd; + val |= table[i].OpOr; + } else { + val = table[i].OpOr; + } + + outb(val, table[i].reg); + } +} + +static const struct initdata it8613e_initdata[] = { + { 0x0007, 0x00, IT8613E_GPIO }, /* LDN GPIO */ + { 0x0071, 0xf7, 0x00 }, /* ESPI_CLOCK */ + { 0x0023, 0xf6, 0x00 }, + { 0x002d, 0xfb, (1 << 1) }, + { 0x0007, 0x00, IT8613E_CIR }, + { 0x0030, 0x00, 0x00 }, + { 0x0060, 0x00, 0x00 }, + { 0x0061, 0x00, 0x00 }, + { 0x0070, 0x00, 0x00 }, + { 0x0007, 0x00, IT8613E_EC }, /* LDN EC */ + { 0x00f0, 0x00, 0x00 }, + { 0x00f1, 0x00, 0xbf }, + { 0x00f2, 0x00, 0x00 }, + { 0x00f3, 0x00, 0x00 }, + { 0x00f4, 0x9f, 0x60 }, + { 0x00f5, 0x3f, 0x00 }, + { 0x00fa, 0x00, 0x00 }, + { 0x00fb, 0xf3, 0x0c }, + { 0x0007, 0x00, IT8613E_GPIO }, /* LDN GPIO */ + { 0x0026, 0x00, 0x00 }, + { 0x0029, 0x00, 0x00 }, + { 0x002a, 0x7f, 0x80 }, + { 0x002b, 0xbf, 0x00 }, +}; + +static const struct initdata it8613e_ecdata[] = { + { 0x0050, 0x00, 0xff }, + { 0x0051, 0x00, 0x15 }, + { 0x000a, 0x8f, 0x68 }, + { 0x000b, 0x00, 0xc9 }, + { 0x000c, 0xf8, 0x07 }, + { 0x0013, 0x07, 0x70 }, + { 0x0014, 0x7f, 0xc0 }, + { 0x005c, 0x7f, 0x80 }, + { 0x0056, 0x00, 0x68 }, + { 0x0057, 0x00, 0x05 }, + { 0x0059, 0x00, 0x00 }, + { 0x005c, 0x7f, 0x00 }, + { 0x0065, 0x60, 0x04 }, + { 0x006d, 0x60, 0x04 }, + { 0x0075, 0x60, 0x04 }, + { 0x0089, 0x00, 0x30 }, + { 0x008a, 0x00, 0x01 }, + { 0x008b, 0x00, 0x02 }, + { 0x008c, 0x00, 0x01 }, + { 0x008e, 0x00, 0x20 }, + { 0x0006, 0x00, 0x40 }, + { 0x001d, 0x00, 0x14 }, + { 0x001e, 0x00, 0x04 }, + { 0x0006, 0x00, 0x00 }, + { 0x0055, 0x7f, 0x80 }, + { 0x0000, 0xbe, 0x41 }, + { 0x0000, 0x00, 0x00 }, + { 0x0000, 0x00, 0x00 }, +}; + +static void it8613e_init(const u16 p_idx, const u16 p_dat, const struct initdata *table, const size_t count) +{ + u8 val; + + for (size_t i = 0; i < count; i++) { + outb(table[i].reg, p_idx); + + if (table[i].OpAnd == 0) { + val = table[i].OpOr; + } else { + val = ((inb(p_dat) & table[i].OpAnd) | + table[i].OpOr); + } + + outb(val, p_dat); + } +} + +void bootblock_mainboard_early_init(void) +{ + /* fixed io decode of espi */ + pci_write_config32(PCH_DEV_ESPI, ESPI_IO_DEC, 0x3c030070); + variant_configure_early_gpio_pads(); + + /* initial IT8613e/LX from table */ + sio_init(init_values, ARRAY_SIZE(init_values)); + + pnp_enter_conf_state(EC_DEV); + it8613e_init(it8613e_index, it8613e_data, + it8613e_initdata, ARRAY_SIZE(it8613e_initdata)); + pnp_exit_conf_state(EC_DEV); + + /* Environment Controller */ + it8613e_init(it8613e_ecdata_base + 5, it8613e_ecdata_base + 6, + it8613e_ecdata, ARRAY_SIZE(it8613e_ecdata)); + + /* 5VSB_CTRL# disable */ + ite_reg_write(EC_DEV, 0xfa, 0); + ite_disable_pme_out(EC_DEV); + ite_ac_resume_southbridge(EC_DEV); + + ite_enable_serial(UART_DEV, CONFIG_TTYS0_BASE); +} diff --git a/src/mainboard/lattepanda/mu/data.vbt b/src/mainboard/lattepanda/mu/data.vbt Binary files differnew file mode 100644 index 0000000000..fc35e8faf6 --- /dev/null +++ b/src/mainboard/lattepanda/mu/data.vbt diff --git a/src/mainboard/lattepanda/mu/devicetree.cb b/src/mainboard/lattepanda/mu/devicetree.cb new file mode 100644 index 0000000000..ba55f1412a --- /dev/null +++ b/src/mainboard/lattepanda/mu/devicetree.cb @@ -0,0 +1,152 @@ +# SPDX-License-Identifier: GPL-2.0-only + +chip soc/intel/alderlake + # FSP configuration + # Sagv Configuration + register "sagv" = "SaGv_Enabled" + + # Enable EDP in PortA + register "ddi_portA_config" = "1" + # Enable HDMI in Port B + register "ddi_ports_config" = "{ + [DDI_PORT_B] = DDI_ENABLE_HPD | DDI_ENABLE_DDC, + }" + + register "s0ix_enable" = "1" + + register "serial_io_i2c_mode" = "{ + [PchSerialIoIndexI2C0] = PchSerialIoDisabled, + [PchSerialIoIndexI2C1] = PchSerialIoDisabled, + [PchSerialIoIndexI2C2] = PchSerialIoPci, + [PchSerialIoIndexI2C3] = PchSerialIoPci, + [PchSerialIoIndexI2C4] = PchSerialIoPci, + [PchSerialIoIndexI2C5] = PchSerialIoPci, + }" + + register "serial_io_uart_mode" = "{ + [PchSerialIoIndexUART0] = PchSerialIoSkipInit, + [PchSerialIoIndexUART1] = PchSerialIoDisabled, + [PchSerialIoIndexUART2] = PchSerialIoDisabled, + }" + + # Intel Common SoC Config + register "common_soc_config" = "{ + .i2c[2] = { + .speed = I2C_SPEED_FAST, + }, + .i2c[3] = { + .speed = I2C_SPEED_FAST, + }, + .i2c[4] = { + .speed = I2C_SPEED_FAST, + }, + .i2c[5] = { + .speed = I2C_SPEED_FAST, + }, + }" + + # Configure external V1P05/Vnn/VnnSx Rails + register "ext_fivr_settings" = "{ + .configure_ext_fivr = 1, + .v1p05_enable_bitmap = FIVR_ENABLE_ALL_SX & ~FIVR_ENABLE_S0, + .vnn_enable_bitmap = FIVR_ENABLE_ALL_SX, + .vnn_sx_enable_bitmap = FIVR_ENABLE_ALL_SX, + .v1p05_supported_voltage_bitmap = FIVR_VOLTAGE_NORMAL, + .vnn_supported_voltage_bitmap = FIVR_VOLTAGE_MIN_ACTIVE, + .v1p05_voltage_mv = 1050, + .vnn_voltage_mv = 780, + .vnn_sx_voltage_mv = 1050, + .v1p05_icc_max_ma = 500, + .vnn_icc_max_ma = 500, + }" + + device domain 0 on + device ref igpu on end + device ref crashlog off end + device ref xhci on + register "usb2_ports" = "{ + [0] = USB2_PORT_MID(OC_SKIP), // USB3/2 Type A + [1] = USB2_PORT_MID(OC_SKIP), // USB3/2 Type A + [2] = USB2_PORT_MID(OC_SKIP), // USB2 Type A + [4] = USB2_PORT_MID(OC_SKIP), // USB2 Type A + [6] = USB2_PORT_MID(OC_SKIP), // M.2 E 2230 + }" + + register "usb3_ports" = "{ + [0] = USB3_PORT_DEFAULT(OC_SKIP),// USB3/2 Type A + [1] = USB3_PORT_DEFAULT(OC_SKIP),// USB3/2 Type A + }" + end + device ref i2c2 on end + device ref i2c3 on end + device ref i2c4 on end + device ref i2c5 on end + device ref pcie_rp3 on + register "pcie_clk_config_flag[0]" = "PCIE_CLK_FREE_RUNNING" + register "pch_pcie_rp[PCH_RP(3)]" = "{ + .flags = PCIE_RP_LTR | PCIE_RP_AER | PCIE_RP_CLK_SRC_UNUSED | PCIE_RP_CLK_REQ_UNUSED, + .pcie_rp_aspm = ASPM_DISABLE, + .PcieRpL1Substates = L1_SS_DISABLED, + }" + smbios_slot_desc "SlotTypeM2Socket3" "SlotLengthOther" + "M.2/M 2230 (M2_SSD)" "SlotDataBusWidth1X" + end + device ref pcie_rp4 on + register "pcie_clk_config_flag[3]" = "PCIE_CLK_FREE_RUNNING" + register "pch_pcie_rp[PCH_RP(4)]" = "{ + .flags = PCIE_RP_LTR | PCIE_RP_AER | PCIE_RP_CLK_SRC_UNUSED | PCIE_RP_CLK_REQ_UNUSED, + .pcie_rp_aspm = ASPM_DISABLE, + .PcieRpL1Substates = L1_SS_DISABLED, + }" + smbios_slot_desc "SlotTypeM2Socket1_SD" "SlotLengthOther" + "M.2/E 2230 (M2_WIFI)" "SlotDataBusWidth1X" + end + device ref pcie_rp7 on # RTL8111H Ethernet NIC + register "pcie_clk_config_flag[4]" = "PCIE_CLK_FREE_RUNNING" + register "pch_pcie_rp[PCH_RP(7)]" = "{ + .flags = PCIE_RP_LTR | PCIE_RP_AER | PCIE_RP_CLK_SRC_UNUSED | PCIE_RP_CLK_REQ_UNUSED | PCIE_RP_BUILT_IN, + .pcie_rp_aspm = ASPM_DISABLE, + .PcieRpL1Substates = L1_SS_DISABLED, + }" + chip drivers/net + # register "wake" = "no link" + register "device_index" = "0" + register "add_acpi_dma_property" = "true" + device pci 00.0 on end + end + end + device ref emmc on + register "emmc_enable_hs400_mode" = "1" + end + device ref hda on + # HD Audio + register "pch_hda_dsp_enable" = "1" + register "pch_hda_idisp_link_tmode" = "HDA_TMODE_8T" + register "pch_hda_idisp_link_frequency" = "HDA_LINKFREQ_96MHZ" + register "pch_hda_idisp_codec_enable" = "1" + end + device ref pch_espi on + register "gen1_dec" = "0x00fc0201" + register "gen2_dec" = "0x003c0a01" + register "gen3_dec" = "0x000c03f1" + register "gen4_dec" = "0x000c0081" + chip superio/ite/it8613e + device pnp 2e.0 off end + device pnp 2e.1 on # COM 1 + io 0x60 = 0x3f8 + irq 0x70 = 4 + irq 0xf0 = 0x1 + end + device pnp 2e.4 on # Environment Controller + io 0x60 = 0xa40 + io 0x62 = 0xa30 + irq 0x70 = 0x00 + end + device pnp 2e.5 off end # Keyboard + device pnp 2e.6 off end # Mouse + device pnp 2e.7 off end # GPIO + device pnp 2e.a off end # CIR + end + end + end +end diff --git a/src/mainboard/lattepanda/mu/dsdt.asl b/src/mainboard/lattepanda/mu/dsdt.asl new file mode 100644 index 0000000000..a3a29bc22f --- /dev/null +++ b/src/mainboard/lattepanda/mu/dsdt.asl @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <acpi/acpi.h> +#include <baseboard/gpio.h> + +DefinitionBlock( + "dsdt.aml", + "DSDT", + ACPI_DSDT_REV_2, + OEM_ID, + ACPI_TABLE_CREATOR, + 0x20110725 +) +{ + #include <acpi/dsdt_top.asl> + #include <soc/intel/common/block/acpi/acpi/platform.asl> + #include <soc/intel/common/block/acpi/acpi/globalnvs.asl> + #include <cpu/intel/common/acpi/cpu.asl> + + Device (\_SB.PCI0) { + #include <soc/intel/common/block/acpi/acpi/northbridge.asl> + #include <soc/intel/alderlake/acpi/southbridge.asl> + #include <soc/intel/alderlake/acpi/tcss.asl> + } + + #include <southbridge/intel/common/acpi/sleepstates.asl> +} diff --git a/src/mainboard/lattepanda/mu/early_gpio.c b/src/mainboard/lattepanda/mu/early_gpio.c new file mode 100644 index 0000000000..f44e67dcfb --- /dev/null +++ b/src/mainboard/lattepanda/mu/early_gpio.c @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <baseboard/gpio.h> +#include <baseboard/variants.h> +#include <soc/gpio.h> + +static const struct pad_config early_uart_gpio_table[] = { + /* UART0 RX */ + PAD_CFG_NF(GPP_H10, NONE, DEEP, NF2), + /* UART0 TX */ + PAD_CFG_NF(GPP_H11, NONE, DEEP, NF2), + /* UART1 RX */ + PAD_CFG_NF(GPP_D17, NONE, DEEP, NF2), + /* UART1 TX */ + PAD_CFG_NF(GPP_D18, NONE, DEEP, NF2), + /* UART2 RX */ + PAD_CFG_NF(GPP_F1, NONE, DEEP, NF2), + /* UART2 TX */ + PAD_CFG_NF(GPP_F2, NONE, DEEP, NF2), +}; + +void variant_configure_early_gpio_pads(void) +{ + if (CONFIG(INTEL_LPSS_UART_FOR_CONSOLE)) + gpio_configure_pads(early_uart_gpio_table, ARRAY_SIZE(early_uart_gpio_table)); + +} diff --git a/src/mainboard/lattepanda/mu/gpio.c b/src/mainboard/lattepanda/mu/gpio.c new file mode 100644 index 0000000000..9af526947d --- /dev/null +++ b/src/mainboard/lattepanda/mu/gpio.c @@ -0,0 +1,133 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <baseboard/gpio.h> +#include <baseboard/variants.h> +#include <commonlib/helpers.h> + +/* Pad configuration in ramstage*/ +static const struct pad_config gpio_table[] = { + /* CORE_VID0 */ + PAD_CFG_NF(GPP_B0, NONE, DEEP, NF1), + /* CORE_VID1 */ + PAD_CFG_NF(GPP_B1, NONE, DEEP, NF1), + /* VR_ALERT_N */ + PAD_CFG_NF(GPP_B2, NONE, DEEP, NF1), + /* SLP_S0_N */ + PAD_CFG_NF(GPP_B12, NONE, DEEP, NF1), + /* PLTRST_N */ + PAD_CFG_NF(GPP_B13, NONE, DEEP, NF1), + PAD_CFG_GPO(GPP_B14, 0, PLTRST), + + /* ESPI_IO0_EC_R / ESPI_IO0_HDR */ + PAD_CFG_NF(GPP_A0, NONE, DEEP, NF1), + /* ESPI_IO1_EC_R / ESPI_IO1_HDR */ + PAD_CFG_NF(GPP_A1, NONE, DEEP, NF1), + /* ESPI_IO2_EC_R / ESPI_IO2_HDR */ + PAD_CFG_NF(GPP_A2, NONE, DEEP, NF1), + /* ESPI_IO3_EC_R / ESPI_IO3_HDR */ + PAD_CFG_NF(GPP_A3, NONE, DEEP, NF1), + /* ESPI_CS0_EC_R_N / ESPI_CS0_HDR_N */ + PAD_CFG_NF(GPP_A4, NONE, DEEP, NF1), + /* ESPI_ALERT0_EC_R_N / ESPI_ALERT0_HDR_N */ + PAD_CFG_NF(GPP_A5, NONE, DEEP, NF1), + /* ESPI_ALERT1_EC_R_N / ESPI_ALERT1_HDR_N */ + PAD_CFG_NF(GPP_A6, NONE, DEEP, NF1), + /* ESPI_CLK_EC_R / ESPI_CLK_HDR */ + PAD_CFG_NF(GPP_A9, NONE, DEEP, NF1), + /* ESPI_RST_EC_R_N / ESPI_RST_HDR_N */ + PAD_CFG_NF(GPP_A10, NONE, DEEP, NF1), + + /* H15 : DDPB_CTRLCLK ==> DDIB_HDMI_CTRLCLK */ + PAD_CFG_NF(GPP_H15, NONE, DEEP, NF1), + /* H17 : DDPB_CTRLDATA ==> DDIB_HDMI_CTRLDATA */ + PAD_CFG_NF(GPP_H17, NONE, DEEP, NF1), + + /* I5 : NC */ + PAD_NC(GPP_I5, NONE), + /* I7 : EMMC_CMD ==> EMMC_CMD */ + PAD_CFG_NF(GPP_I7, NONE, DEEP, NF1), + /* I8 : EMMC_DATA0 ==> EMMC_D0 */ + PAD_CFG_NF(GPP_I8, NONE, DEEP, NF1), + /* I9 : EMMC_DATA1 ==> EMMC_D1 */ + PAD_CFG_NF(GPP_I9, NONE, DEEP, NF1), + /* I10 : EMMC_DATA2 ==> EMMC_D2 */ + PAD_CFG_NF(GPP_I10, NONE, DEEP, NF1), + /* I11 : EMMC_DATA3 ==> EMMC_D3 */ + PAD_CFG_NF(GPP_I11, NONE, DEEP, NF1), + /* I12 : EMMC_DATA4 ==> EMMC_D4 */ + PAD_CFG_NF(GPP_I12, NONE, DEEP, NF1), + /* I13 : EMMC_DATA5 ==> EMMC_D5 */ + PAD_CFG_NF(GPP_I13, NONE, DEEP, NF1), + /* I14 : EMMC_DATA6 ==> EMMC_D6 */ + PAD_CFG_NF(GPP_I14, NONE, DEEP, NF1), + /* I15 : EMMC_DATA7 ==> EMMC_D7 */ + PAD_CFG_NF(GPP_I15, NONE, DEEP, NF1), + /* I16 : EMMC_RCLK ==> EMMC_RCLK */ + PAD_CFG_NF(GPP_I16, NONE, DEEP, NF1), + /* I17 : EMMC_CLK ==> EMMC_CLK */ + PAD_CFG_NF(GPP_I17, NONE, DEEP, NF1), + /* I18 : EMMC_RESET# ==> EMMC_RST_L */ + PAD_CFG_NF(GPP_I18, NONE, DEEP, NF1), + + /* EDP1_HPD_MIPI_PNL_RST */ + PAD_CFG_NF(GPP_E14, NONE, DEEP, NF1), + + /* PM_SLP_S0_N */ + PAD_CFG_NF(GPP_B12, NONE, DEEP, NF1), + /* PLT_RST_N */ + PAD_CFG_NF(GPP_B13, NONE, DEEP, NF1), + /* PM_SLP_DRAM_N */ + PAD_CFG_NF(GPP_E8, NONE, DEEP, NF2), + /* CPU_C10_GATE_N_R */ + PAD_CFG_NF(GPP_H18, NONE, DEEP, NF1), + + /* DDIB_DP_HDMI_ALS_HDP */ + PAD_CFG_NF(GPP_A18, NONE, DEEP, NF1), + /* PM_BATLOW_N */ + PAD_CFG_NF(GPD0, UP_20K, PWROK, NF1), + /* AC_PRESENT */ + PAD_CFG_NF(GPD1, NATIVE, PWROK, NF1), + PAD_CFG_GPI_SCI(GPD2, NONE, DEEP, EDGE_SINGLE, INVERT), + /* PWR_BTN_N */ + PAD_CFG_NF(GPD3, UP_20K, PWROK, NF1), + /* SUSB_N_PCH */ + PAD_CFG_NF(GPD4, NONE, PWROK, NF1), + /* SUSC_N_PCH */ + PAD_CFG_NF(GPD5, NONE, PWROK, NF1), + /* SLP_A_N */ + PAD_CFG_NF(GPD6, NONE, PWROK, NF1), + PAD_CFG_GPO(GPD7, 0, PWROK), + /* SUS_CLK */ + PAD_CFG_NF(GPD8, NONE, PWROK, NF1), + /* SLP_WLAN_N */ + PAD_CFG_NF(GPD9, NONE, PWROK, NF1), + /* SLP_S5_N */ + PAD_CFG_NF(GPD10, NONE, PWROK, NF1), + PAD_NC(GPD11, NONE), + PAD_CFG_NF(GPD_INPUT3VSEL, NONE, PWROK, NF1), + PAD_CFG_NF(GPD_SLP_LANB, NONE, PWROK, NF1), + PAD_CFG_NF(GPD_SLP_SUSB, NONE, PWROK, NF1), + PAD_CFG_NF(GPD_WAKEB, NONE, PWROK, NF1), + PAD_CFG_NF(GPD_DRAM_RESETB, NONE, PWROK, NF1), + + /* SMB_CLK */ + PAD_CFG_NF(GPP_C0, NONE, DEEP, NF1), + /* SMB_DATA */ + PAD_CFG_NF(GPP_C1, NONE, DEEP, NF1), + /* SMB_ALERT_N */ + PAD_CFG_NF(GPP_C2, NONE, DEEP, NF1), + /* SML0_CLK */ + PAD_CFG_NF(GPP_C3, NONE, DEEP, NF1), + /* SML1_DATA */ + PAD_CFG_NF(GPP_C4, NONE, DEEP, NF1), + PAD_CFG_TERM_GPO(GPP_C5, 1, DN_20K, PLTRST), + /* SML1_CLK */ + PAD_CFG_NF(GPP_C6, NONE, RSMRST, NF1), + /* SML1_DATA */ + PAD_CFG_NF(GPP_C7, NONE, RSMRST, NF1), +}; + +void variant_configure_gpio_pads(void) +{ + gpio_configure_pads(gpio_table, ARRAY_SIZE(gpio_table)); +} diff --git a/src/mainboard/lattepanda/mu/include/baseboard/gpio.h b/src/mainboard/lattepanda/mu/include/baseboard/gpio.h new file mode 100644 index 0000000000..a27221c728 --- /dev/null +++ b/src/mainboard/lattepanda/mu/include/baseboard/gpio.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __BASEBOARD_GPIO_H__ +#define __BASEBOARD_GPIO_H__ + +#include <soc/gpe.h> +#include <soc/gpio.h> + +#endif /* __BASEBOARD_GPIO_H__ */ diff --git a/src/mainboard/lattepanda/mu/include/baseboard/variants.h b/src/mainboard/lattepanda/mu/include/baseboard/variants.h new file mode 100644 index 0000000000..61b0f68887 --- /dev/null +++ b/src/mainboard/lattepanda/mu/include/baseboard/variants.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __BASEBOARD_VARIANTS_H__ +#define __BASEBOARD_VARIANTS_H__ + +#include <soc/gpio.h> +#include <soc/meminit.h> +#include <stdint.h> + +/* Functions to configure GPIO as per variant schematics */ +void variant_configure_gpio_pads(void); +void variant_configure_early_gpio_pads(void); + +size_t variant_memory_sku(void); +const struct mb_cfg *variant_memory_params(void); +void rpl_memory_params(FSPM_UPD *memupd); + +/* Modify devictree settings during ramstage */ +void variant_devtree_update(void); +struct cpu_power_limits { + uint16_t mchid; + u8 cpu_tdp; + unsigned int pl1_min_power; + unsigned int pl1_max_power; + unsigned int pl2_min_power; + unsigned int pl2_max_power; + unsigned int pl4_power; +}; +/* Modify Power Limit devictree settings during ramstage */ +void variant_update_power_limits(void); + +#endif /*__BASEBOARD_VARIANTS_H__ */ diff --git a/src/mainboard/lattepanda/mu/mainboard.c b/src/mainboard/lattepanda/mu/mainboard.c new file mode 100644 index 0000000000..4270f050c7 --- /dev/null +++ b/src/mainboard/lattepanda/mu/mainboard.c @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <baseboard/gpio.h> +#include <baseboard/variants.h> +#include <cpu/cpu.h> +#include <cpu/intel/cpu_ids.h> +#include <device/device.h> +#include <drivers/intel/gma/opregion.h> +#include <fw_config.h> +#include <smbios.h> +#include <soc/gpio.h> +#include <stdint.h> +#include <stdio.h> + +const char *smbios_system_sku(void) +{ + static char sku_str[7] = ""; + uint8_t sku_id = 1; + + snprintf(sku_str, sizeof(sku_str), "sku%u", sku_id); + return sku_str; +} + +static void mainboard_init(void *chip_info) +{ + variant_configure_gpio_pads(); + variant_devtree_update(); +} + +struct chip_operations mainboard_ops = { + .init = mainboard_init, +}; diff --git a/src/mainboard/lattepanda/mu/memory.c b/src/mainboard/lattepanda/mu/memory.c new file mode 100644 index 0000000000..e6c81793cb --- /dev/null +++ b/src/mainboard/lattepanda/mu/memory.c @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <baseboard/variants.h> +#include <console/console.h> +#include <soc/romstage.h> + +static const struct mb_cfg mu_lp5_mem_config = { + .type = MEM_TYPE_LP5X, + + /* DQ byte map */ + .lpx_dq_map = { + .ddr0 = { + .dq0 = { 12, 10, 9, 11, 15, 14, 8, 13 }, + .dq1 = { 0, 3, 1, 2, 7, 4, 6, 5 }, + }, + .ddr1 = { + .dq0 = { 0, 2, 1, 3, 4, 7, 5, 6 }, + .dq1 = { 13, 11, 9, 10, 8, 15, 12, 14 }, + }, + .ddr2 = { + .dq0 = { 0, 1, 2, 3, 7, 4, 5, 6 }, + .dq1 = { 9, 10, 8, 11, 14, 15, 12, 13 }, + }, + .ddr3 = { + .dq0 = { 3, 0, 1, 2, 5, 6, 4, 7 }, + .dq1 = { 14, 10, 8, 11, 12, 15, 9, 13 }, + }, + .ddr4 = { + .dq0 = { 3, 0, 2, 1, 6, 7, 5, 4 }, + .dq1 = { 12, 14, 15, 13, 9, 11, 8, 10 }, + }, + .ddr5 = { + .dq0 = { 0, 1, 2, 3, 6, 4, 5, 7 }, + .dq1 = { 15, 14, 12, 13, 9, 11, 8, 10 }, + }, + .ddr6 = { + .dq0 = { 3, 0, 1, 2, 5, 4, 6, 7 }, + .dq1 = { 12, 13, 15, 14, 9, 11, 10, 8 }, + }, + .ddr7 = { + .dq0 = { 3, 0, 2, 1, 5, 4, 6, 7 }, + .dq1 = { 10, 8, 15, 14, 9, 12, 13, 11 }, + }, + }, + + /* DQS CPU<>DRAM map */ + .lpx_dqs_map = { + .ddr0 = { .dqs0 = 1, .dqs1 = 0 }, + .ddr1 = { .dqs0 = 0, .dqs1 = 1 }, + .ddr2 = { .dqs0 = 0, .dqs1 = 1 }, + .ddr3 = { .dqs0 = 0, .dqs1 = 1 }, + .ddr4 = { .dqs0 = 0, .dqs1 = 1 }, + .ddr5 = { .dqs0 = 0, .dqs1 = 1 }, + .ddr6 = { .dqs0 = 0, .dqs1 = 1 }, + .ddr7 = { .dqs0 = 0, .dqs1 = 1 } + }, + + .ect = true, /* Early Command Training */ + + .UserBd = BOARD_TYPE_ULT_ULX, + + .LpDdrDqDqsReTraining = 1, + + .lp5x_config = { + .ccc_config = 0x00, + }, +}; + +const struct mb_cfg *variant_memory_params(void) +{ + return &mu_lp5_mem_config; +} diff --git a/src/mainboard/lattepanda/mu/ramstage.c b/src/mainboard/lattepanda/mu/ramstage.c new file mode 100644 index 0000000000..952524e64e --- /dev/null +++ b/src/mainboard/lattepanda/mu/ramstage.c @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <acpi/acpi_device.h> +#include <baseboard/variants.h> +#include <console/console.h> +#include <device/pci_ids.h> +#include <device/pci_ops.h> +#include <soc/gpio_soc_defs.h> +#include <soc/pci_devs.h> +#include <soc/soc_chip.h> +#include <string.h> +#include <drivers/intel/dptf/chip.h> +#include <intelblocks/power_limit.h> + +const struct cpu_power_limits limits[] = { + /* SKU_ID, TDP (Watts), pl1_min, pl1_max, pl2_min, pl2_max, PL4 */ + /* PL2 values are for performance configuration */ + { PCI_DID_INTEL_ADL_N_ID_1, 15, 3000, 15000, 35000, 35000, 83000 }, + { PCI_DID_INTEL_ADL_N_ID_2, 6, 3000, 6000, 25000, 25000, 78000 }, + { PCI_DID_INTEL_ADL_N_ID_3, 6, 3000, 6000, 25000, 25000, 78000 }, + { PCI_DID_INTEL_ADL_N_ID_4, 6, 3000, 6000, 25000, 25000, 78000 }, + { PCI_DID_INTEL_ADL_N_ID_5, 6, 3000, 6000, 25000, 25000, 78000 }, +}; + +WEAK_DEV_PTR(dptf_policy); +void variant_update_power_limits(void) +{ + const struct device *policy_dev = DEV_PTR(dptf_policy); + if (!policy_dev) + return; + + struct drivers_intel_dptf_config *config = config_of(policy_dev); + + uint16_t mchid = pci_s_read_config16(PCI_DEV(0, 0, 0), PCI_DEVICE_ID); + + u8 tdp = get_cpu_tdp(); + + for (size_t i = 0; i < ARRAY_SIZE(limits); i++) { + if (mchid == limits[i].mchid && tdp == limits[i].cpu_tdp) { + struct dptf_power_limits *settings = &config->controls.power_limits; + config_t *conf = config_of_soc(); + struct soc_power_limits_config *soc_config = conf->power_limits_config; + settings->pl1.min_power = limits[i].pl1_min_power; + settings->pl1.max_power = limits[i].pl1_max_power; + settings->pl2.min_power = limits[i].pl2_min_power; + settings->pl2.max_power = limits[i].pl2_max_power; + soc_config->tdp_pl4 = DIV_ROUND_UP(limits[i].pl4_power, + MILLIWATTS_TO_WATTS); + printk(BIOS_INFO, "Overriding power limits PL1 (%u, %u) PL2 (%u, %u) PL4 (%u)\n", + limits[i].pl1_min_power, + limits[i].pl1_max_power, + limits[i].pl2_min_power, + limits[i].pl2_max_power, + limits[i].pl4_power); + } + } +} + +void variant_devtree_update(void) +{ + variant_update_power_limits(); +} diff --git a/src/mainboard/lattepanda/mu/romstage_fsp_params.c b/src/mainboard/lattepanda/mu/romstage_fsp_params.c new file mode 100644 index 0000000000..f2b8124773 --- /dev/null +++ b/src/mainboard/lattepanda/mu/romstage_fsp_params.c @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <assert.h> +#include <console/console.h> +#include <fsp/api.h> +#include <soc/romstage.h> +#include <spd_bin.h> +#include <soc/meminit.h> +#include <baseboard/variants.h> + +static size_t get_spd_index(void) +{ + size_t spd_index = 0; + printk(BIOS_INFO, "SPD index is 0x%x\n", (unsigned int)spd_index); + return spd_index; +} + +void mainboard_memory_init_params(FSPM_UPD *memupd) +{ + const struct mb_cfg *mem_config = variant_memory_params(); + const bool half_populated = (true); + + const struct mem_spd memory_down_spd_info = { + .topo = MEM_TOPO_MEMORY_DOWN, + .cbfs_index = get_spd_index(), + }; + + memcfg_init(memupd, mem_config, &memory_down_spd_info, half_populated); +} diff --git a/src/mainboard/lattepanda/mu/smihandler.c b/src/mainboard/lattepanda/mu/smihandler.c new file mode 100644 index 0000000000..1de3bb7743 --- /dev/null +++ b/src/mainboard/lattepanda/mu/smihandler.c @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <acpi/acpi.h> +#include <arch/io.h> +#include <cpu/x86/smm.h> +#include <intelblocks/smihandler.h> +#include <superio/ite/common/ite.h> +#include <superio/ite/it8613e/it8613e.h> + +#define it8613e_index (0x2e) +#define EC_DEV PNP_DEV(it8613e_index, IT8613E_EC) + +void mainboard_smi_sleep(u8 slp_typ) +{ + printk(BIOS_DEBUG, "SMI: sleep S%d\n", slp_typ); + + switch (slp_typ) { + case ACPI_S3: + case ACPI_S4: + case ACPI_S5: + /* 5VSB_CTRL# Enabled */ + ite_reg_write(EC_DEV, 0xfa, 2); + break; + default: + break; + } + +} diff --git a/src/mainboard/lattepanda/mu/spd/Makefile.mk b/src/mainboard/lattepanda/mu/spd/Makefile.mk new file mode 100644 index 0000000000..e07bb07111 --- /dev/null +++ b/src/mainboard/lattepanda/mu/spd/Makefile.mk @@ -0,0 +1,4 @@ +## SPDX-License-Identifier: GPL-2.0-only + +SPD_SOURCES = mu_lp5_8gb # 0b000 +SPD_SOURCES += mu_lp5_16gb # 0b002 diff --git a/src/mainboard/lattepanda/mu/spd/mu_lp5_16gb.spd.hex b/src/mainboard/lattepanda/mu/spd/mu_lp5_16gb.spd.hex new file mode 100644 index 0000000000..d20646629c --- /dev/null +++ b/src/mainboard/lattepanda/mu/spd/mu_lp5_16gb.spd.hex @@ -0,0 +1,32 @@ +27 10 13 0E 16 22 F9 08 00 40 00 00 0A 01 00 00 +48 00 0A FF 92 55 05 00 AA 00 90 A8 90 C0 08 60 +04 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 7F 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 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 20 00 00 00 20 20 20 20 20 20 20 +20 20 20 20 20 20 20 20 20 20 20 20 20 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 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 diff --git a/src/mainboard/lattepanda/mu/spd/mu_lp5_8gb.spd.hex b/src/mainboard/lattepanda/mu/spd/mu_lp5_8gb.spd.hex new file mode 100644 index 0000000000..a8d059cec9 --- /dev/null +++ b/src/mainboard/lattepanda/mu/spd/mu_lp5_8gb.spd.hex @@ -0,0 +1,32 @@ +27 10 13 0E 16 22 B9 08 00 40 00 00 02 01 00 00 +48 00 0A FF 92 55 05 00 AA 00 90 A8 90 C0 08 60 +04 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 7F 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 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 20 00 00 00 20 20 20 20 20 20 20 +20 20 20 20 20 20 20 20 20 20 20 20 20 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 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 |