| package main |
| |
| import "fmt" |
| |
| func LenovoEC(ctx Context) { |
| ap := Create(ctx, "acpi/platform.asl") |
| defer ap.Close() |
| |
| wakeGPE := 13 |
| |
| sbGPE := GuessECGPE(ctx) |
| var GPE int |
| var GPEUnsure bool |
| if sbGPE < 0 { |
| sbGPE = SouthBridge.EncodeGPE(1) |
| GPE = 1 |
| GPEUnsure = true |
| SouthBridge.NeedRouteGPIOManually() |
| } else { |
| GPE = SouthBridge.DecodeGPE(sbGPE) |
| GPEUnsure = false |
| } |
| |
| SouthBridge.EnableGPE(wakeGPE) |
| SouthBridge.EnableGPE(GPE) |
| |
| GPEDefine := DSDTDefine{ |
| Key: "THINKPAD_EC_GPE", |
| } |
| |
| GPEDefine.Value = fmt.Sprintf("%d", sbGPE) |
| if GPEUnsure { |
| GPEDefine.Comment = "FIXME: Check this" |
| } |
| |
| DSDTDefines = append(DSDTDefines, |
| DSDTDefine{ |
| Key: "EC_LENOVO_H8_ME_WORKAROUND", |
| Value: "1", |
| }, GPEDefine) |
| |
| ap.WriteString( |
| `Method(_WAK,1) |
| { |
| /* ME may not be up yet. */ |
| Store (0, \_TZ.MEB1) |
| Store (0, \_TZ.MEB2) |
| Return(Package(){0,0}) |
| } |
| |
| Method(_PTS,1) |
| { |
| \_SB.PCI0.LPCB.EC.RADI(0) |
| } |
| `) |
| |
| si := Create(ctx, "acpi/superio.asl") |
| defer si.Close() |
| |
| si.WriteString("#include <drivers/pc80/ps2_controller.asl>\n") |
| |
| dock := Create(ctx, "dock.c") |
| defer dock.Close() |
| |
| AddRAMStageFile("dock.c", "") |
| |
| dock.WriteString( |
| `#include <ec/lenovo/h8/h8.h> |
| |
| void h8_mainboard_init_dock (void) |
| { |
| /* FIXME: fill this if needed. */ |
| } |
| `) |
| |
| /* FIXME:XX Move this to ec/lenovo. */ |
| smi := Create(ctx, "smihandler.c") |
| defer smi.Close() |
| |
| AddSMMFile("smihandler.c", "") |
| |
| smi.WriteString( |
| `/* |
| * 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. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc. |
| */ |
| |
| #include <arch/io.h> |
| #include <console/console.h> |
| #include <cpu/x86/smm.h> |
| #include <ec/acpi/ec.h> |
| #include <ec/lenovo/h8/h8.h> |
| #include <delay.h> |
| #include <` + SouthBridge.GetGPIOHeader() + ">\n\n") |
| |
| if GPEUnsure { |
| smi.WriteString("/* FIXME: check this */\n") |
| } |
| fmt.Fprintf(smi, "#define GPE_EC_SCI %d\n", GPE) |
| |
| smi.WriteString("/* FIXME: check this */\n") |
| fmt.Fprintf(smi, "#define GPE_EC_WAKE %d\n", wakeGPE) |
| |
| smi.WriteString(` |
| static void mainboard_smm_init(void) |
| { |
| printk(BIOS_DEBUG, "initializing SMI\n"); |
| /* Enable 0x1600/0x1600 register pair */ |
| ec_set_bit(0x00, 0x05); |
| } |
| |
| int mainboard_io_trap_handler(int smif) |
| { |
| static int smm_initialized; |
| |
| if (!smm_initialized) { |
| mainboard_smm_init(); |
| smm_initialized = 1; |
| } |
| |
| return 0; |
| } |
| |
| static void mainboard_smi_handle_ec_sci(void) |
| { |
| u8 status = inb(EC_SC); |
| u8 event; |
| |
| if (!(status & EC_SCI_EVT)) |
| return; |
| |
| event = ec_query(); |
| printk(BIOS_DEBUG, "EC event %02x\n", event); |
| } |
| |
| void mainboard_smi_gpi(u32 gpi_sts) |
| { |
| if (gpi_sts & (1 << GPE_EC_SCI)) |
| mainboard_smi_handle_ec_sci(); |
| } |
| |
| int mainboard_smi_apmc(u8 data) |
| { |
| switch (data) { |
| case APM_CNT_ACPI_ENABLE: |
| /* use 0x1600/0x1604 to prevent races with userspace */ |
| ec_set_ports(0x1604, 0x1600); |
| /* route EC_SCI to SCI */ |
| gpi_route_interrupt(GPE_EC_SCI, GPI_IS_SCI); |
| /* discard all events, and enable attention */ |
| ec_write(0x80, 0x01); |
| break; |
| case APM_CNT_ACPI_DISABLE: |
| /* we have to use port 0x62/0x66, as 0x1600/0x1604 doesn't |
| provide a EC query function */ |
| ec_set_ports(0x66, 0x62); |
| /* route EC_SCI to SMI */ |
| gpi_route_interrupt(GPE_EC_SCI, GPI_IS_SMI); |
| /* discard all events, and enable attention */ |
| ec_write(0x80, 0x01); |
| break; |
| default: |
| break; |
| } |
| return 0; |
| } |
| |
| void mainboard_smi_sleep(u8 slp_typ) |
| { |
| if (slp_typ == 3) { |
| u8 ec_wake = ec_read(0x32); |
| /* If EC wake events are enabled, enable wake on EC WAKE GPE. */ |
| if (ec_wake & 0x14) { |
| /* Redirect EC WAKE GPE to SCI. */ |
| gpi_route_interrupt(GPE_EC_WAKE, GPI_IS_SCI); |
| } |
| } |
| } |
| `) |
| |
| ec := Create(ctx, "acpi/ec.asl") |
| defer ec.Close() |
| |
| ec.WriteString("#include <ec/lenovo/h8/acpi/ec.asl>\n") |
| |
| KconfigBool["EC_LENOVO_PMH7"] = true |
| KconfigBool["EC_LENOVO_H8"] = true |
| |
| pmh := DevTreeNode{ |
| Chip: "ec/lenovo/pmh7", |
| Registers: map[string]string{ |
| "backlight_enable": "0x01", |
| "dock_event_enable": "0x01", |
| }, |
| Children: []DevTreeNode{ |
| DevTreeNode{ |
| Chip: "pnp", |
| Comment: "dummy", |
| Dev: 0xff, |
| Func: 1, |
| }, |
| }, |
| } |
| PutChip("lpc", pmh) |
| |
| ecs := ctx.InfoSource.GetEC() |
| h8 := DevTreeNode{ |
| Chip: "ec/lenovo/h8", |
| Children: []DevTreeNode{ |
| DevTreeNode{ |
| Chip: "pnp", |
| Comment: "dummy", |
| Dev: 0xff, |
| Func: 2, |
| IOs: map[uint16]uint16{ |
| 0x60: 0x62, |
| 0x62: 0x66, |
| 0x64: 0x1600, |
| 0x66: 0x1604, |
| }, |
| }, |
| }, |
| Comment: "FIXME: has_keyboard_backlight, has_power_management_beeps, has_uwb", |
| Registers: map[string]string{ |
| "config0": FormatHex8(ecs[0]), |
| "config1": FormatHex8(ecs[1]), |
| "config2": FormatHex8(ecs[2]), |
| "config3": FormatHex8(ecs[3]), |
| "beepmask0": FormatHex8(ecs[4]), |
| "beepmask1": FormatHex8(ecs[5]), |
| }, |
| } |
| for i := 0; i < 0x10; i++ { |
| if ecs[0x10+i] != 0 { |
| h8.Registers[fmt.Sprintf("event%x_enable", i)] = FormatHex8(ecs[0x10+i]) |
| } |
| } |
| PutChip("lpc", h8) |
| |
| eeprom := DevTreeNode{ |
| Chip: "drivers/i2c/at24rf08c", |
| Comment: "eeprom, 8 virtual devices, same chip", |
| Children: []DevTreeNode{ |
| DevTreeNode{ |
| Chip: "i2c", |
| Dev: 0x54, |
| }, |
| DevTreeNode{ |
| Chip: "i2c", |
| Dev: 0x55, |
| }, |
| DevTreeNode{ |
| Chip: "i2c", |
| Dev: 0x56, |
| }, |
| DevTreeNode{ |
| Chip: "i2c", |
| Dev: 0x57, |
| }, |
| DevTreeNode{ |
| Chip: "i2c", |
| Dev: 0x5c, |
| }, |
| DevTreeNode{ |
| Chip: "i2c", |
| Dev: 0x5d, |
| }, |
| DevTreeNode{ |
| Chip: "i2c", |
| Dev: 0x5e, |
| }, |
| DevTreeNode{ |
| Chip: "i2c", |
| Dev: 0x5f, |
| }, |
| }, |
| } |
| PutChip("smbus", eeprom) |
| } |