2 * This file is part of the coreboot project.
4 * Copyright (C) 2016 Intel Corp.
5 * (Written by Alexandru Gagniuc <alexandrux.gagniuc@intel.com> for Intel Corp.)
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; either version 2 of the License, or
10 * (at your option) any later version.
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.
18 #include <device/device.h>
19 #include <device/pci.h>
20 #include <device/pci_ids.h>
21 #include <console/console.h>
22 #include <cpu/x86/smm.h>
23 #include <soc/iomap.h>
24 #include <soc/pci_ids.h>
26 #include <soc/pci_devs.h>
32 * The ACPI IO BAR (offset 0x20) is not PCI compliant. We've observed cases
33 * where the BAR reads back as 0, but the IO window is open. This also means
34 * that it will not respond to PCI probing. In the event that probing the BAR
35 * fails, we still need to create a resource for it.
37 static void read_resources(device_t dev
)
40 pci_dev_read_resources(dev
);
42 res
= new_resource(dev
, PCI_BASE_ADDRESS_4
);
43 res
->base
= ACPI_PMIO_BASE
;
44 res
->size
= ACPI_PMIO_SIZE
;
45 res
->flags
= IORESOURCE_IO
| IORESOURCE_ASSIGNED
| IORESOURCE_FIXED
;
50 * Resources are assigned, and no other device was given an IO resource to
51 * overlap with our ACPI BAR. But because the resource is FIXED,
52 * pci_dev_set_resources() will not store it for us. We need to do that
55 static void set_resources(device_t dev
)
59 pci_dev_set_resources(dev
);
61 res
= find_resource(dev
, PCI_BASE_ADDRESS_4
);
62 pci_write_config32(dev
, res
->index
, res
->base
);
63 dev
->command
|= PCI_COMMAND_IO
;
64 res
->flags
|= IORESOURCE_STORED
;
65 report_resource_stored(dev
, res
, " ACPI BAR");
68 static void pch_set_acpi_mode(void)
70 if (IS_ENABLED(CONFIG_HAVE_SMI_HANDLER
) && !acpi_is_wakeup_s3()) {
71 printk(BIOS_DEBUG
, "Disabling ACPI via APMC:");
72 outb(APM_CNT_ACPI_DISABLE
, APM_CNT
);
73 printk(BIOS_DEBUG
, "Done.\n");
77 static int choose_slp_s3_assertion_width(int width_usecs
)
83 } slp_s3_settings
[] = {
86 .value
= SLP_S3_ASSERT_60_USEC
,
89 .max_width
= 1 * USECS_PER_MSEC
,
90 .value
= SLP_S3_ASSERT_1_MSEC
,
93 .max_width
= 50 * USECS_PER_MSEC
,
94 .value
= SLP_S3_ASSERT_50_MSEC
,
97 .max_width
= 2 * USECS_PER_SEC
,
98 .value
= SLP_S3_ASSERT_2_SEC
,
102 for (i
= 0; i
< ARRAY_SIZE(slp_s3_settings
); i
++) {
103 if (width_usecs
<= slp_s3_settings
[i
].max_width
)
107 /* Provide conservative default if nothing set in devicetree
108 * or requested assertion width too large. */
109 if (width_usecs
<= 0 || i
== ARRAY_SIZE(slp_s3_settings
))
110 i
= ARRAY_SIZE(slp_s3_settings
) - 1;
112 printk(BIOS_DEBUG
, "SLP S3 assertion width: %d usecs\n",
113 slp_s3_settings
[i
].max_width
);
115 return slp_s3_settings
[i
].value
;
118 static void set_slp_s3_assertion_width(int width_usecs
)
121 uintptr_t gen_pmcon3
= get_pmc_mmio_bar() + GEN_PMCON3
;
122 int setting
= choose_slp_s3_assertion_width(width_usecs
);
124 reg
= read32((void *)gen_pmcon3
);
125 reg
&= ~SLP_S3_ASSERT_MASK
;
126 reg
|= setting
<< SLP_S3_ASSERT_WIDTH_SHIFT
;
127 write32((void *)gen_pmcon3
, reg
);
130 static void pmc_init(struct device
*dev
)
132 const struct soc_intel_apollolake_config
*cfg
= dev
->chip_info
;
134 /* Set up GPE configuration */
140 set_slp_s3_assertion_width(cfg
->slp_s3_assertion_width_usecs
);
142 /* Log power state */
146 static const struct device_operations device_ops
= {
147 .read_resources
= read_resources
,
148 .set_resources
= set_resources
,
149 .enable_resources
= pci_dev_enable_resources
,
153 static const struct pci_driver pmc __pci_driver
= {
155 .vendor
= PCI_VENDOR_ID_INTEL
,
156 .device
= PCI_DEVICE_ID_APOLLOLAKE_PMC
,