coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
mainboard.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <acpi/acpi.h>
4 #include <arch/io.h>
5 #include <console/console.h>
6 #include <device/pci_ops.h>
8 #include <ec/acpi/ec.h>
9 #include <halt.h>
10 #include <intelblocks/lpc_lib.h>
11 #include <intelblocks/pmclib.h>
12 #include <rtc.h>
13 #include <soc/nhlt.h>
14 #include <soc/pci_devs.h>
15 #include <soc/pm.h>
16 #include "include/ec.h"
17 #include "include/gpio.h"
18 
19 static unsigned long mainboard_write_acpi_tables(
20  const struct device *device, unsigned long current, acpi_rsdp_t *rsdp)
21 {
22  uintptr_t start_addr;
23  uintptr_t end_addr;
24  struct nhlt *nhlt;
25 
26  start_addr = current;
27 
28  nhlt = nhlt_init();
29  if (!nhlt) {
30  return start_addr;
31  }
32 
33  /* Override subsystem ID */
34  nhlt->subsystem_id = 0x10251037;
35 
36  /* 1 Channel DMIC array. */
37  if (nhlt_soc_add_dmic_array(nhlt, 1) != 0) {
38  printk(BIOS_ERR, "Couldn't add 1CH DMIC array.\n");
39  }
40 
41  /* 2 Channel DMIC array. */
42  if (nhlt_soc_add_dmic_array(nhlt, 2) != 0) {
43  printk(BIOS_ERR, "Couldn't add 2CH DMIC array.\n");
44  }
45 
46  end_addr = nhlt_soc_serialize(nhlt, start_addr);
47 
48  if (end_addr != start_addr) {
49  acpi_add_table(rsdp, (void *)start_addr);
50  }
51 
52  return end_addr;
53 }
54 
55 static void mainboard_enable(struct device *dev)
56 {
60 
61  if (CONFIG(INCLUDE_NHLT_BLOBS)) {
62  dev->ops->write_acpi_tables = mainboard_write_acpi_tables;
63  }
64 }
65 
66 /* Update the EC's clock. */
67 static void ec_send_time(void)
68 {
69  struct rtc_time time;
70  uint8_t ec_time_byte;
71 
72  rtc_get(&time);
73 
74  /* RTC time could be negative (before 2016) */
75  int32_t ec_time = ((time.year << 26) + (time.mon << 22) + (time.mday << 17)
76  + (time.hour << 12) + (time.min << 6) + (time.sec)
77  /* 16 years */
78  - 0x40000000);
79 
80  printk(BIOS_DEBUG, "EC: reporting present time 0x%x\n", ec_time);
81  send_ec_command(0xE0);
82  for (int i = 0; i < 4; i++) {
83  /* Shift bytes */
84  ec_time_byte = (uint8_t) (ec_time >> (i * 8));
85  printk(BIOS_DEBUG, "EC: Sending 0x%x (iteration %d)\n", ec_time_byte, i);
86  send_ec_data(ec_time_byte);
87  }
88 
89  printk(BIOS_DEBUG, "EC: response 0x%x\n", recv_ec_data());
90 }
91 
92 static void ec_requests_time(void)
93 {
94  /* This is executed as protocol notify in vendor's RtKbcDriver
95  when *CommonService protocol is installed. Effectively,
96  this code could execute from the entrypoint */
97  uint8_t dat = ec_cmd_90_read(0x79);
98  if (dat & 1) {
99  ec_send_time();
100  }
101 }
102 
103 /*
104  * Init from vendor's PeiOemModule. KbcPeim does not appear to be used
105  * (It implements commands also found in RtKbcDriver and SmmKbcDriver).
106  *
107  * Mostly, this puts the system back to sleep if the lid is closed during
108  * an S3 resume.
109  */
110 static void ec_init(void)
111 {
112  /* This is called via a "$FNC" in a PeiOemModule pointer table,
113  with "$DPX" on SiInit */
114  outb(0x5A, 0x6C); // 6Ch is the EC sideband port
115  if (acpi_is_wakeup_s3()) {
116  /* "MLID" in LGMR-based memory map is equivalent to "ELID" in EC-based
117  memory map. Vendor firmware accesses through LGMR; remapped
118  - ec_cmd* function calls will not remapped */
119  uint8_t power_state = ec_read(0x70);
120  if (!(power_state & 2)) { // Lid is closed
121  uint8_t out_data = ec_cmd_90_read(0x0A);
122  if (!(out_data & 2)) {
123  ec_cmd_91_write(0x0A, out_data | 2);
124  }
125 
126  /* Clear below events and go back to sleep */
127  /* Clear ABase PM1_STS - RW/1C set bits */
129  /* Clear ABase GPE0_STS[127:96] - RW/1C set bits */
131  outl(gpe_sts, ACPI_BASE_ADDRESS + GPE0_STS(GPE_STD));
132  /* Clear xHCI PM_CS[PME_Status] - RW/1C -
133  and disable xHCI PM_CS[PME_En] */
134  pci_update_config16(PCH_DEV_XHCI, 0x74, ~0x100, 0x8000);
135 
136  /* Enter S3 sleep */
138  halt();
139  }
140  }
141 }
142 
143 static void mainboard_init(void *chip_info)
144 {
146  /* Notify EC */
147  ec_init();
148  /* Program the same 64K range of EC memory as vendor FW
149  - Open unconditionally, user can select whether ACPI uses LGMR */
150  lpc_open_mmio_window(0xFE800000, 0x10000);
151  /* EC is notified of platform resets with UEFI firmware, but coreboot
152  does not offer this service to boards */
154 }
155 
158  .init = mainboard_init,
159 };
struct chip_operations mainboard_ops
Definition: mainboard.c:19
static unsigned long mainboard_write_acpi_tables(const struct device *device, unsigned long current, acpi_rsdp_t *rsdp)
Definition: mainboard.c:19
static void mainboard_init(void *chip_info)
Definition: mainboard.c:143
static void ec_send_time(void)
Definition: mainboard.c:67
static void ec_init(void)
Definition: mainboard.c:110
static void ec_requests_time(void)
Definition: mainboard.c:92
static void mainboard_enable(struct device *dev)
Definition: mainboard.c:55
void acpi_add_table(acpi_rsdp_t *rsdp, void *table)
Add an ACPI table to the RSDT (and XSDT) structure, recalculate length and checksum.
Definition: acpi.c:49
#define GPE0_STS(x)
Definition: pm.h:81
#define GPE_STD
Definition: pm.h:85
static int acpi_is_wakeup_s3(void)
Definition: acpi.h:9
int rtc_get(struct rtc_time *time)
Definition: as3722rtc.c:62
#define printk(level,...)
Definition: stdlib.h:16
void outb(u8 val, u16 port)
u32 inl(u16 port)
void outl(u32 val, u16 port)
void install_intel_vga_int15_handler(int active_lfp_, int pfit_, int display_, int panel_type_)
Definition: int15.c:101
@ GMA_INT15_BOOT_DISPLAY_DEFAULT
Definition: int15.h:6
@ GMA_INT15_ACTIVE_LFP_EDP
Definition: int15.h:27
@ GMA_INT15_PANEL_FIT_DEFAULT
Definition: int15.h:17
@ CONFIG
Definition: dsi_common.h:201
u8 ec_read(u8 addr)
Definition: ec.c:107
int send_ec_command(u8 command)
Definition: ec.c:13
u8 recv_ec_data(void)
Definition: ec.c:65
int send_ec_data(u8 data)
Definition: ec.c:35
void __noreturn halt(void)
halt the system reliably
Definition: halt.c:6
static __always_inline void pci_update_config16(const struct device *dev, u16 reg, u16 mask, u16 or)
Definition: pci_ops.h:104
uintptr_t nhlt_soc_serialize(struct nhlt *nhlt, uintptr_t acpi_addr)
Definition: nhlt.c:7
struct nhlt * nhlt_init(void)
Definition: nhlt.c:23
#define ACPI_BASE_ADDRESS
Definition: iomap.h:99
#define SLP_EN
Definition: pmc.h:62
#define SLP_TYP_S3
Definition: pmc.h:67
#define SLP_TYP_SHIFT
Definition: pmc.h:63
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
void lpc_open_mmio_window(uintptr_t base, size_t size)
Definition: lpc_lib.c:128
void ec_cmd_91_write(uint8_t addr, uint8_t data)
Definition: ec.c:40
uint8_t ec_cmd_90_read(uint8_t addr)
Definition: ec.c:32
void mainboard_config_stage_gpios(void)
Definition: gpio.c:371
#define PCH_DEV_XHCI
Definition: pci_devs.h:128
int nhlt_soc_add_dmic_array(struct nhlt *nhlt, int num_channels)
Definition: nhlt.c:168
static struct chipset_power_state power_state
Definition: romstage.c:19
uint16_t pmc_clear_pm1_status(void)
Definition: pmclib.c:250
void pmc_enable_pm1_control(uint32_t mask)
Definition: pmclib.c:206
unsigned int uint32_t
Definition: stdint.h:14
unsigned long uintptr_t
Definition: stdint.h:21
signed int int32_t
Definition: stdint.h:13
unsigned char uint8_t
Definition: stdint.h:8
Definition: acpi.h:82
void(* enable_dev)(struct device *dev)
Definition: device.h:24
Definition: device.h:107
struct device_operations * ops
Definition: device.h:143
Definition: nhlt.h:287
uint32_t subsystem_id
Definition: nhlt.h:288
Definition: rtc.h:6
int year
Definition: rtc.h:12
int hour
Definition: rtc.h:9
int mon
Definition: rtc.h:11
int min
Definition: rtc.h:8
int sec
Definition: rtc.h:7
int mday
Definition: rtc.h:10