blob: cbef92e8dd11ced633c46eb178de7b73a836faf2 [file] [log] [blame]
Lee Leahy77ff0b12015-05-05 15:07:29 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2013 Google Inc.
Lee Leahy32471722015-04-20 15:20:28 -07005 * Copyright (C) 2015 Intel Corp.
Lee Leahy77ff0b12015-05-05 15:07:29 -07006 *
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.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Lee Leahy77ff0b12015-05-05 15:07:29 -070015 */
16
17#include <stdint.h>
18#include <arch/io.h>
19#include <cbmem.h>
20#include <console/console.h>
21#include <device/device.h>
22#include <device/pci.h>
23#include <device/pci_ids.h>
24#include <reg_script.h>
25
26#include <soc/iosf.h>
27#include <soc/nvs.h>
28#include <soc/pci_devs.h>
29#include <soc/ramstage.h>
30
31#include "chip.h"
32
33static void dev_enable_acpi_mode(device_t dev, int iosf_reg, int nvs_index)
34{
35 struct reg_script ops[] = {
36 /* Disable PCI interrupt, enable Memory and Bus Master */
37 REG_PCI_OR32(PCI_COMMAND,
38 PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | (1<<10)),
39 /* Enable ACPI mode */
40 REG_IOSF_OR(IOSF_PORT_LPSS, iosf_reg,
41 LPSS_CTL_PCI_CFG_DIS | LPSS_CTL_ACPI_INT_EN),
42 REG_SCRIPT_END
43 };
44 struct resource *bar;
45 global_nvs_t *gnvs;
46
47 /* Find ACPI NVS to update BARs */
Lee Leahy32471722015-04-20 15:20:28 -070048 gnvs = cbmem_find(CBMEM_ID_ACPI_GNVS);
Lee Leahy77ff0b12015-05-05 15:07:29 -070049 if (!gnvs) {
50 printk(BIOS_ERR, "Unable to locate Global NVS\n");
51 return;
52 }
53
54 /* Save BAR0 and BAR1 to ACPI NVS */
55 bar = find_resource(dev, PCI_BASE_ADDRESS_0);
56 if (bar)
57 gnvs->dev.lpss_bar0[nvs_index] = (u32)bar->base;
58
59 bar = find_resource(dev, PCI_BASE_ADDRESS_1);
60 if (bar)
61 gnvs->dev.lpss_bar1[nvs_index] = (u32)bar->base;
62
63 /* Device is enabled in ACPI mode */
64 gnvs->dev.lpss_en[nvs_index] = 1;
65
66 /* Put device in ACPI mode */
67 reg_script_run_on_dev(dev, ops);
68}
69
Lee Leahy77ff0b12015-05-05 15:07:29 -070070static void dev_ctl_reg(device_t dev, int *iosf_reg, int *nvs_index)
71{
72 *iosf_reg = -1;
73 *nvs_index = -1;
74#define SET_IOSF_REG(name_) \
75 case PCI_DEVFN(name_ ## _DEV, name_ ## _FUNC): \
Lee Leahy32471722015-04-20 15:20:28 -070076 do { \
77 *iosf_reg = LPSS_ ## name_ ## _CTL; \
78 *nvs_index = LPSS_NVS_ ## name_; \
79 } while (0)
Lee Leahy77ff0b12015-05-05 15:07:29 -070080
81 switch (dev->path.pci.devfn) {
82 SET_IOSF_REG(SIO_DMA1);
83 break;
84 SET_IOSF_REG(I2C1);
85 break;
86 SET_IOSF_REG(I2C2);
87 break;
88 SET_IOSF_REG(I2C3);
89 break;
90 SET_IOSF_REG(I2C4);
91 break;
92 SET_IOSF_REG(I2C5);
93 break;
94 SET_IOSF_REG(I2C6);
95 break;
96 SET_IOSF_REG(I2C7);
97 break;
98 SET_IOSF_REG(SIO_DMA2);
99 break;
100 SET_IOSF_REG(PWM1);
101 break;
102 SET_IOSF_REG(PWM2);
103 break;
104 SET_IOSF_REG(HSUART1);
105 break;
106 SET_IOSF_REG(HSUART2);
107 break;
108 SET_IOSF_REG(SPI);
109 break;
110 }
111}
112
113static void i2c_disable_resets(device_t dev)
114{
115 /* Release the I2C devices from reset. */
116 static const struct reg_script ops[] = {
117 REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x804, 0x3),
118 REG_SCRIPT_END,
119 };
120
121#define CASE_I2C(name_) \
122 case PCI_DEVFN(name_ ## _DEV, name_ ## _FUNC)
123
124 switch (dev->path.pci.devfn) {
Lee Leahy32471722015-04-20 15:20:28 -0700125 CASE_I2C(I2C1) :
126 CASE_I2C(I2C2) :
127 CASE_I2C(I2C3) :
128 CASE_I2C(I2C4) :
129 CASE_I2C(I2C5) :
130 CASE_I2C(I2C6) :
131 CASE_I2C(I2C7) :
Lee Leahy77ff0b12015-05-05 15:07:29 -0700132 printk(BIOS_DEBUG, "Releasing I2C device from reset.\n");
133 reg_script_run_on_dev(dev, ops);
134 break;
135 default:
136 return;
137 }
138}
139
140static void lpss_init(device_t dev)
141{
Lee Leahy32471722015-04-20 15:20:28 -0700142 struct soc_intel_braswell_config *config = dev->chip_info;
Lee Leahy77ff0b12015-05-05 15:07:29 -0700143 int iosf_reg, nvs_index;
144
Lee Leahy32471722015-04-20 15:20:28 -0700145 printk(BIOS_SPEW, "%s/%s ( %s )\n",
146 __FILE__, __func__, dev_name(dev));
147 printk(BIOS_SPEW, "%s - %s\n",
148 get_pci_class_name(dev),
149 get_pci_subclass_name(dev));
150
Lee Leahy77ff0b12015-05-05 15:07:29 -0700151 dev_ctl_reg(dev, &iosf_reg, &nvs_index);
152
153 if (iosf_reg < 0) {
154 int slot = PCI_SLOT(dev->path.pci.devfn);
155 int func = PCI_FUNC(dev->path.pci.devfn);
156 printk(BIOS_DEBUG, "Could not find iosf_reg for %02x.%01x\n",
157 slot, func);
158 return;
159 }
Lee Leahy32471722015-04-20 15:20:28 -0700160
Lee Leahy77ff0b12015-05-05 15:07:29 -0700161 i2c_disable_resets(dev);
162
163 if (config->lpss_acpi_mode)
164 dev_enable_acpi_mode(dev, iosf_reg, nvs_index);
165}
166
167static struct device_operations device_ops = {
168 .read_resources = pci_dev_read_resources,
169 .set_resources = pci_dev_set_resources,
170 .enable_resources = pci_dev_enable_resources,
171 .init = lpss_init,
172 .enable = NULL,
173 .scan_bus = NULL,
174 .ops_pci = &soc_pci_ops,
175};
176
177static const unsigned short pci_device_ids[] = {
178 SIO_DMA1_DEVID,
179 I2C1_DEVID,
180 I2C2_DEVID,
181 I2C3_DEVID,
182 I2C4_DEVID,
183 I2C5_DEVID,
184 I2C6_DEVID,
185 I2C7_DEVID,
186 SIO_DMA2_DEVID,
187 PWM1_DEVID,
188 PWM2_DEVID,
189 HSUART1_DEVID,
190 HSUART2_DEVID,
191 SPI_DEVID,
192 0,
193};
194
195static const struct pci_driver southcluster __pci_driver = {
196 .ops = &device_ops,
197 .vendor = PCI_VENDOR_ID_INTEL,
198 .devices = pci_device_ids,
199};