2 * This file is part of the coreboot project.
4 * Copyright (C) 2015-2016 Intel Corp.
5 * (Written by Lance Zhao <lijian.zhao@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 <console/console.h>
19 #include <device/device.h>
20 #include <device/pci.h>
21 #include <device/pci_ids.h>
24 #include <soc/pci_ids.h>
30 * The purpose of this driver is to eliminate manual resource allocation for
31 * devices under the LPC bridge.
34 * The resource allocator reserves IO and memory resources to devices on the
35 * LPC bus, but it is up to the hardware driver to make sure that those
36 * resources are decoded to the LPC bus. This is what this driver does.
38 * THEORY OF OPERATION:
39 * The .scan_bus member of the driver's ops will scan the static device tree
40 * (devicetree.cb) and invoke drivers of devices on the LPC bus. This creates
41 * a list of child devices, along with their resources. set_child_resources()
42 * parses that list and looks for resources needed by the child devices. It
43 * opens up IO and memory windows as needed.
46 static void lpc_init(struct device
*dev
)
49 struct soc_intel_apollolake_config
*cfg
;
53 printk(BIOS_ERR
, "BUG! Could not find SOC devicetree config\n");
57 scnt
= pci_read_config8(dev
, REG_SERIRQ_CTL
);
58 scnt
&= ~(SCNT_EN
| SCNT_MODE
);
59 if (cfg
->serirq_mode
== SERIRQ_QUIET
)
61 else if (cfg
->serirq_mode
== SERIRQ_CONTINUOUS
)
62 scnt
|= SCNT_EN
| SCNT_MODE
;
63 pci_write_config8(dev
, REG_SERIRQ_CTL
, scnt
);
66 static void soc_lpc_add_io_resources(device_t dev
)
70 /* Add the default claimed legacy IO range for the LPC device. */
71 res
= new_resource(dev
, 0);
74 res
->flags
= IORESOURCE_IO
| IORESOURCE_ASSIGNED
| IORESOURCE_FIXED
;
77 static void soc_lpc_read_resources(device_t dev
)
79 /* Get the PCI resources of this device. */
80 pci_dev_read_resources(dev
);
82 /* Add IO resources to LPC. */
83 soc_lpc_add_io_resources(dev
);
86 static void set_child_resources(struct device
*dev
);
88 static void loop_resources(struct device
*dev
)
92 for (res
= dev
->resource_list
; res
; res
= res
->next
) {
94 if (res
->flags
& IORESOURCE_IO
) {
95 lpc_open_pmio_window(res
->base
, res
->size
);
98 if (res
->flags
& IORESOURCE_MEM
) {
99 /* Check if this is already decoded. */
100 if (lpc_fits_fixed_mmio_window(res
->base
, res
->size
))
103 lpc_open_mmio_window(res
->base
, res
->size
);
107 set_child_resources(dev
);
111 * Loop through all the child devices' resources, and open up windows to the
112 * LPC bus, as appropriate.
114 static void set_child_resources(struct device
*dev
)
117 struct device
*child
;
119 for (link
= dev
->link_list
; link
; link
= link
->next
) {
120 for (child
= link
->children
; child
; child
= child
->sibling
) {
121 loop_resources(child
);
126 static void set_resources(device_t dev
)
128 pci_dev_set_resources(dev
);
130 /* Close all previously opened windows and allocate from scratch. */
131 lpc_close_pmio_windows();
132 /* Now open up windows to devices which have declared resources. */
133 set_child_resources(dev
);
136 static struct device_operations device_ops
= {
137 .read_resources
= &soc_lpc_read_resources
,
138 .set_resources
= set_resources
,
139 .enable_resources
= &pci_dev_enable_resources
,
140 .write_acpi_tables
= southbridge_write_acpi_tables
,
141 .acpi_inject_dsdt_generator
= southbridge_inject_dsdt
,
143 .scan_bus
= scan_lpc_bus
,
146 static const struct pci_driver soc_lpc __pci_driver
= {
148 .vendor
= PCI_VENDOR_ID_INTEL
,
149 .device
= PCI_DEVICE_ID_APOLLOLAKE_LPC
,