1 /* SPDX-License-Identifier: GPL-2.0-only */
5 #include <console/console.h>
6 #include <device/pci_ops.h>
7 #include <drivers/intel/gma/int15.h>
8 #include <ec/acpi/ec.h>
10 #include <intelblocks/lpc_lib.h>
11 #include <intelblocks/pmclib.h>
14 #include <soc/pci_devs.h>
16 #include "include/ec.h"
17 #include "include/gpio.h"
19 static unsigned long mainboard_write_acpi_tables(
20 const struct device
*device
, unsigned long current
, acpi_rsdp_t
*rsdp
)
33 /* Override subsystem ID */
34 nhlt
->subsystem_id
= 0x10251037;
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");
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");
46 end_addr
= nhlt_soc_serialize(nhlt
, start_addr
);
48 if (end_addr
!= start_addr
) {
49 acpi_add_table(rsdp
, (void *)start_addr
);
55 static void mainboard_enable(struct device
*dev
)
57 install_intel_vga_int15_handler(GMA_INT15_ACTIVE_LFP_EDP
,
58 GMA_INT15_PANEL_FIT_DEFAULT
,
59 GMA_INT15_BOOT_DISPLAY_DEFAULT
, 0);
61 if (CONFIG(INCLUDE_NHLT_BLOBS
)) {
62 dev
->ops
->write_acpi_tables
= mainboard_write_acpi_tables
;
66 /* Update the EC's clock. */
67 static void ec_send_time(void)
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
)
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
++) {
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
);
89 printk(BIOS_DEBUG
, "EC: response 0x%x\n", recv_ec_data());
92 static void ec_requests_time(void)
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);
104 * Init from vendor's PeiOemModule. KbcPeim does not appear to be used
105 * (It implements commands also found in RtKbcDriver and SmmKbcDriver).
107 * Mostly, this puts the system back to sleep if the lid is closed during
110 static void ec_init(void)
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);
126 /* Clear below events and go back to sleep */
127 /* Clear ABase PM1_STS - RW/1C set bits */
128 pmc_clear_pm1_status();
129 /* Clear ABase GPE0_STS[127:96] - RW/1C set bits */
130 uint32_t gpe_sts
= inl(ACPI_BASE_ADDRESS
+ GPE0_STS(GPE_STD
));
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);
137 pmc_enable_pm1_control(SLP_EN
| (SLP_TYP_S3
<< SLP_TYP_SHIFT
));
143 static void mainboard_init(void *chip_info
)
145 mainboard_config_stage_gpios();
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 */
156 struct chip_operations mainboard_ops
= {
157 .enable_dev
= mainboard_enable
,
158 .init
= mainboard_init
,