blob: e007da951230a3005756ba183ccd57e5c4b7cbea [file] [log] [blame]
Hannah Williams01bc8972016-02-04 20:13:34 -08001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2013 Google Inc.
5 * Copyright (C) 2015-2016 Intel Corp.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
Alexandru Gagniuca6339802016-04-05 12:40:24 -070018#define __SIMPLE_DEVICE__
19
Duncan Laurie2e790092016-09-19 12:05:49 -070020#include <arch/acpi.h>
Hannah Williams01bc8972016-02-04 20:13:34 -080021#include <arch/io.h>
22#include <console/console.h>
Andrey Petrov3b637532016-11-30 17:39:16 -080023#include <cpu/x86/msr.h>
Shaunak Saha93cdc8b2017-04-18 15:42:09 -070024#include <device/device.h>
25#include <device/pci.h>
Hannah Williams01bc8972016-02-04 20:13:34 -080026#include <device/pci_def.h>
Barnali Sarkar66fe0c42017-05-23 18:17:14 +053027#include <intelblocks/msr.h>
Shaunak Saha93cdc8b2017-04-18 15:42:09 -070028#include <intelblocks/pmclib.h>
29#include <rules.h>
Hannah Williams01bc8972016-02-04 20:13:34 -080030#include <soc/iomap.h>
Andrey Petrov3b637532016-11-30 17:39:16 -080031#include <soc/cpu.h>
Alexandru Gagniuca6339802016-04-05 12:40:24 -070032#include <soc/pci_devs.h>
Hannah Williams01bc8972016-02-04 20:13:34 -080033#include <soc/pm.h>
Duncan Laurie2f3736e2016-11-03 10:33:43 -070034#include <timer.h>
Duncan Lauriea673d1c2016-09-19 12:02:54 -070035#include "chip.h"
Hannah Williams01bc8972016-02-04 20:13:34 -080036
Alexandru Gagniuca6339802016-04-05 12:40:24 -070037static uintptr_t read_pmc_mmio_bar(void)
38{
Lijian Zhao91086802016-09-06 18:15:29 -070039 return PMC_BAR0;
Alexandru Gagniuca6339802016-04-05 12:40:24 -070040}
Hannah Williams01bc8972016-02-04 20:13:34 -080041
Shaunak Saha93cdc8b2017-04-18 15:42:09 -070042uintptr_t soc_read_pmc_base(void)
Shaunak Saha9a0c9ac2016-06-27 23:00:15 -070043{
44 return read_pmc_mmio_bar();
45}
46
Shaunak Saha93cdc8b2017-04-18 15:42:09 -070047const char *const *soc_smi_sts_array(size_t *a)
Hannah Williams01bc8972016-02-04 20:13:34 -080048{
Shaunak Saha93cdc8b2017-04-18 15:42:09 -070049 static const char *const smi_sts_bits[] = {
Aaron Durbin7929dd02016-06-10 18:01:45 -050050 [BIOS_SMI_STS] = "BIOS",
51 [LEGACY_USB_SMI_STS] = "LEGACY USB",
52 [SLP_SMI_STS] = "SLP_SMI",
53 [APM_SMI_STS] = "APM",
54 [SWSMI_TMR_SMI_STS] = "SWSMI_TMR",
Aaron Durbina554b712016-06-10 18:04:21 -050055 [FAKE_PM1_SMI_STS] = "PM1",
Lee Leahy320b7ca2017-03-09 09:42:48 -080056 [GPIO_SMI_STS] = "GPIO_SMI",
57 [GPIO_UNLOCK_SMI_STS] = "GPIO_UNLOCK_SSMI",
Aaron Durbin7929dd02016-06-10 18:01:45 -050058 [MC_SMI_STS] = "MCSMI",
59 [TCO_SMI_STS] = "TCO",
60 [PERIODIC_SMI_STS] = "PERIODIC",
61 [SERIRQ_SMI_STS] = "SERIRQ",
62 [SMBUS_SMI_STS] = "SMBUS_SMI",
63 [XHCI_SMI_STS] = "XHCI",
64 [HSMBUS_SMI_STS] = "HOST_SMBUS",
65 [SCS_SMI_STS] = "SCS",
66 [PCIE_SMI_STS] = "PCI_EXP_SMI",
67 [SCC2_SMI_STS] = "SCC2",
68 [SPI_SSMI_STS] = "SPI_SSMI",
69 [SPI_SMI_STS] = "SPI",
70 [PMC_OCP_SMI_STS] = "OCP_CSE",
Hannah Williams01bc8972016-02-04 20:13:34 -080071 };
72
Shaunak Saha93cdc8b2017-04-18 15:42:09 -070073 *a = ARRAY_SIZE(smi_sts_bits);
74 return smi_sts_bits;
Hannah Williams01bc8972016-02-04 20:13:34 -080075}
76
Shaunak Saha93cdc8b2017-04-18 15:42:09 -070077/*
78 * For APL/GLK this check for power button status if nothing else
79 * is indicating an SMI and SMIs aren't turned into SCIs.
80 * Apparently, there is no PM1 status bit in the SMI status
81 * register. That makes things difficult for
82 * determining if the power button caused an SMI.
83 */
84uint32_t soc_get_smi_status(uint32_t generic_sts)
Hannah Williams01bc8972016-02-04 20:13:34 -080085{
Shaunak Saha93cdc8b2017-04-18 15:42:09 -070086 if (generic_sts == 0 && !(inl(ACPI_BASE_ADDRESS + PM1_CNT) & SCI_EN)) {
Barnali Sarkar9e55ff62017-06-05 20:01:14 +053087 uint16_t pm1_sts = inw(ACPI_BASE_ADDRESS + PM1_STS);
Aaron Durbina554b712016-06-10 18:04:21 -050088
89 /* Fake PM1 status bit if power button pressed. */
90 if (pm1_sts & PWRBTN_STS)
Shaunak Saha93cdc8b2017-04-18 15:42:09 -070091 generic_sts |= (1 << FAKE_PM1_SMI_STS);
Aaron Durbina554b712016-06-10 18:04:21 -050092 }
93
Shaunak Saha93cdc8b2017-04-18 15:42:09 -070094 return generic_sts;
Hannah Williams01bc8972016-02-04 20:13:34 -080095}
96
Shaunak Saha93cdc8b2017-04-18 15:42:09 -070097const char *const *soc_tco_sts_array(size_t *a)
Hannah Williams01bc8972016-02-04 20:13:34 -080098{
Shaunak Saha93cdc8b2017-04-18 15:42:09 -070099 static const char *const tco_sts_bits[] = {
Hannah Williams01bc8972016-02-04 20:13:34 -0800100 [3] = "TIMEOUT",
101 [17] = "SECOND_TO",
102 };
103
Shaunak Saha93cdc8b2017-04-18 15:42:09 -0700104 *a = ARRAY_SIZE(tco_sts_bits);
105 return tco_sts_bits;
Hannah Williams01bc8972016-02-04 20:13:34 -0800106}
107
Shaunak Saha93cdc8b2017-04-18 15:42:09 -0700108const char *const *soc_gpe_sts_array(size_t *a)
Hannah Williams01bc8972016-02-04 20:13:34 -0800109{
Shaunak Saha93cdc8b2017-04-18 15:42:09 -0700110 static const char *const gpe_sts_bits[] = {
Hannah Williams01bc8972016-02-04 20:13:34 -0800111 [0] = "PCIE_SCI",
112 [2] = "SWGPE",
113 [3] = "PCIE_WAKE0",
114 [4] = "PUNIT",
115 [6] = "PCIE_WAKE1",
116 [7] = "PCIE_WAKE2",
117 [8] = "PCIE_WAKE3",
118 [9] = "PCI_EXP",
119 [10] = "BATLOW",
120 [11] = "CSE_PME",
121 [12] = "XDCI_PME",
122 [13] = "XHCI_PME",
123 [14] = "AVS_PME",
124 [15] = "GPIO_TIER1_SCI",
125 [16] = "SMB_WAK",
126 [17] = "SATA_PME",
127 };
128
Shaunak Saha93cdc8b2017-04-18 15:42:09 -0700129 *a = ARRAY_SIZE(gpe_sts_bits);
130 return gpe_sts_bits;
Hannah Williams01bc8972016-02-04 20:13:34 -0800131}
132
Shaunak Saha93cdc8b2017-04-18 15:42:09 -0700133uint32_t soc_reset_tco_status(void)
Hannah Williams01bc8972016-02-04 20:13:34 -0800134{
Shaunak Saha93cdc8b2017-04-18 15:42:09 -0700135 uint32_t tco_sts = inl(ACPI_BASE_ADDRESS + TCO_STS);
136 uint32_t tco_en = inl(ACPI_BASE_ADDRESS + TCO1_CNT);
137
138 outl(tco_sts, ACPI_BASE_ADDRESS + TCO_STS);
139 return tco_sts & tco_en;
Hannah Williams01bc8972016-02-04 20:13:34 -0800140}
141
Shaunak Saha93cdc8b2017-04-18 15:42:09 -0700142void soc_clear_pm_registers(uintptr_t pmc_bar)
Duncan Laurie2e790092016-09-19 12:05:49 -0700143{
Hannah Williams01bc8972016-02-04 20:13:34 -0800144 uint32_t gen_pmcon1;
145
Shaunak Saha93cdc8b2017-04-18 15:42:09 -0700146 gen_pmcon1 = read32((void *)(pmc_bar + GEN_PMCON1));
Hannah Williams01bc8972016-02-04 20:13:34 -0800147 /* Clear the status bits. The RPS field is cleared on a 0 write. */
Shaunak Saha93cdc8b2017-04-18 15:42:09 -0700148 write32((void *)(pmc_bar + GEN_PMCON1), gen_pmcon1 & ~RPS);
Hannah Williams01bc8972016-02-04 20:13:34 -0800149}
150
Shaunak Saha93cdc8b2017-04-18 15:42:09 -0700151void soc_get_gpe_configs(uint8_t *dw0, uint8_t *dw1, uint8_t *dw2)
Hannah Williams01bc8972016-02-04 20:13:34 -0800152{
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500153 DEVTREE_CONST struct soc_intel_apollolake_config *config;
Duncan Lauriea673d1c2016-09-19 12:02:54 -0700154
155 /* Look up the device in devicetree */
Aaron Durbine4d7abc2017-04-16 22:05:36 -0500156 DEVTREE_CONST struct device *dev = dev_find_slot(0, SA_DEVFN_ROOT);
Duncan Lauriea673d1c2016-09-19 12:02:54 -0700157 if (!dev || !dev->chip_info) {
158 printk(BIOS_ERR, "BUG! Could not find SOC devicetree config\n");
159 return;
160 }
161 config = dev->chip_info;
162
Shaunak Saha93cdc8b2017-04-18 15:42:09 -0700163 /* Assign to out variable */
164 *dw0 = config->gpe0_dw1;
165 *dw1 = config->gpe0_dw2;
166 *dw2 = config->gpe0_dw3;
167}
Duncan Lauriea673d1c2016-09-19 12:02:54 -0700168
Shaunak Saha93cdc8b2017-04-18 15:42:09 -0700169void soc_fill_power_state(struct chipset_power_state *ps)
170{
171 uintptr_t pmc_bar0 = read_pmc_mmio_bar();
Duncan Lauriea673d1c2016-09-19 12:02:54 -0700172
Shaunak Saha93cdc8b2017-04-18 15:42:09 -0700173 ps->tco_sts = inl(ACPI_BASE_ADDRESS + TCO_STS);
174 ps->prsts = read32((void *)(pmc_bar0 + PRSTS));
175 ps->gen_pmcon1 = read32((void *)(pmc_bar0 + GEN_PMCON1));
176 ps->gen_pmcon2 = read32((void *)(pmc_bar0 + GEN_PMCON2));
177 ps->gen_pmcon3 = read32((void *)(pmc_bar0 + GEN_PMCON3));
Duncan Lauriea673d1c2016-09-19 12:02:54 -0700178
Shaunak Saha93cdc8b2017-04-18 15:42:09 -0700179 printk(BIOS_DEBUG, "prsts: %08x tco_sts: %08x\n",
180 ps->prsts, ps->tco_sts);
181 printk(BIOS_DEBUG,
182 "gen_pmcon1: %08x gen_pmcon2: %08x gen_pmcon3: %08x\n",
183 ps->gen_pmcon1, ps->gen_pmcon2, ps->gen_pmcon3);
Duncan Lauriea673d1c2016-09-19 12:02:54 -0700184}
Andrey Petrov3b637532016-11-30 17:39:16 -0800185
186void enable_pm_timer_emulation(void)
187{
188 /* ACPI PM timer emulation */
189 msr_t msr;
190 /*
191 * The derived frequency is calculated as follows:
192 * (CTC_FREQ * msr[63:32]) >> 32 = target frequency.
193 * Back solve the multiplier so the 3.579545MHz ACPI timer
194 * frequency is used.
195 */
196 msr.hi = (3579545ULL << 32) / CTC_FREQ;
Shaunak Saha93cdc8b2017-04-18 15:42:09 -0700197 /* Set PM1 timer IO port and enable */
Barnali Sarkar9e55ff62017-06-05 20:01:14 +0530198 msr.lo = EMULATE_PM_TMR_EN | (ACPI_BASE_ADDRESS + R_ACPI_PM1_TMR);
Andrey Petrov3b637532016-11-30 17:39:16 -0800199 wrmsr(MSR_EMULATE_PM_TMR, msr);
200}