blob: 9cc80259573228b9dc7ee1acbaea08daeabd5ad4 [file] [log] [blame]
Aaron Durbindc866cf2013-11-12 20:21:53 -06001/*
2 * This file is part of the coreboot project.
3 *
Aaron Durbindc866cf2013-11-12 20:21:53 -06004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
Aaron Durbindc866cf2013-11-12 20:21:53 -060013 */
14
15#include <stdint.h>
Duncan Laurie430bf0d2013-12-10 14:37:42 -080016#include <cbmem.h>
Aaron Durbindc866cf2013-11-12 20:21:53 -060017#include <console/console.h>
18#include <device/device.h>
19#include <device/pci.h>
20#include <device/pci_ids.h>
21#include <reg_script.h>
22
Julius Werner18ea2d32014-10-07 16:42:17 -070023#include <soc/iosf.h>
24#include <soc/nvs.h>
25#include <soc/pci_devs.h>
26#include <soc/ramstage.h>
Aaron Durbindc866cf2013-11-12 20:21:53 -060027
Duncan Laurie430bf0d2013-12-10 14:37:42 -080028#include "chip.h"
29
Elyes HAOUAS17a3ceb2018-05-22 10:42:28 +020030static void dev_enable_acpi_mode(struct device *dev, int iosf_reg,
31 int nvs_index)
Duncan Laurie430bf0d2013-12-10 14:37:42 -080032{
33 struct reg_script ops[] = {
Duncan Laurie430bf0d2013-12-10 14:37:42 -080034 /* Disable PCI interrupt, enable Memory and Bus Master */
35 REG_PCI_OR32(PCI_COMMAND,
36 PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | (1<<10)),
37 /* Enable ACPI mode */
38 REG_IOSF_OR(IOSF_PORT_LPSS, iosf_reg,
39 LPSS_CTL_PCI_CFG_DIS | LPSS_CTL_ACPI_INT_EN),
40 REG_SCRIPT_END
41 };
42 struct resource *bar;
43 global_nvs_t *gnvs;
44
45 /* Find ACPI NVS to update BARs */
46 gnvs = (global_nvs_t *)cbmem_find(CBMEM_ID_ACPI_GNVS);
47 if (!gnvs) {
48 printk(BIOS_ERR, "Unable to locate Global NVS\n");
49 return;
50 }
51
52 /* Save BAR0 and BAR1 to ACPI NVS */
53 bar = find_resource(dev, PCI_BASE_ADDRESS_0);
54 if (bar)
55 gnvs->dev.lpss_bar0[nvs_index] = (u32)bar->base;
56
57 bar = find_resource(dev, PCI_BASE_ADDRESS_1);
58 if (bar)
59 gnvs->dev.lpss_bar1[nvs_index] = (u32)bar->base;
60
61 /* Device is enabled in ACPI mode */
62 gnvs->dev.lpss_en[nvs_index] = 1;
63
64 /* Put device in ACPI mode */
Aaron Durbin616f3942013-12-10 17:12:44 -080065 reg_script_run_on_dev(dev, ops);
Duncan Laurie430bf0d2013-12-10 14:37:42 -080066}
Aaron Durbindc866cf2013-11-12 20:21:53 -060067
Elyes HAOUAS17a3ceb2018-05-22 10:42:28 +020068static void dev_enable_snoop_and_pm(struct device *dev, int iosf_reg)
Aaron Durbindc866cf2013-11-12 20:21:53 -060069{
70 struct reg_script ops[] = {
Aaron Durbindc866cf2013-11-12 20:21:53 -060071 REG_IOSF_RMW(IOSF_PORT_LPSS, iosf_reg,
72 ~(LPSS_CTL_SNOOP | LPSS_CTL_NOSNOOP),
73 LPSS_CTL_SNOOP | LPSS_CTL_PM_CAP_PRSNT),
74 REG_SCRIPT_END,
75 };
76
Aaron Durbin616f3942013-12-10 17:12:44 -080077 reg_script_run_on_dev(dev, ops);
Aaron Durbindc866cf2013-11-12 20:21:53 -060078}
79
Elyes HAOUAS17a3ceb2018-05-22 10:42:28 +020080static void dev_ctl_reg(struct device *dev, int *iosf_reg, int *nvs_index)
Aaron Durbindc866cf2013-11-12 20:21:53 -060081{
Duncan Laurie430bf0d2013-12-10 14:37:42 -080082 *iosf_reg = -1;
83 *nvs_index = -1;
Aaron Durbindc866cf2013-11-12 20:21:53 -060084#define SET_IOSF_REG(name_) \
85 case PCI_DEVFN(name_ ## _DEV, name_ ## _FUNC): \
Duncan Laurie430bf0d2013-12-10 14:37:42 -080086 *iosf_reg = LPSS_ ## name_ ## _CTL; \
87 *nvs_index = LPSS_NVS_ ## name_
Aaron Durbindc866cf2013-11-12 20:21:53 -060088
89 switch (dev->path.pci.devfn) {
90 SET_IOSF_REG(SIO_DMA1);
91 break;
92 SET_IOSF_REG(I2C1);
93 break;
94 SET_IOSF_REG(I2C2);
95 break;
96 SET_IOSF_REG(I2C3);
97 break;
98 SET_IOSF_REG(I2C4);
99 break;
100 SET_IOSF_REG(I2C5);
101 break;
102 SET_IOSF_REG(I2C6);
103 break;
104 SET_IOSF_REG(I2C7);
105 break;
106 SET_IOSF_REG(SIO_DMA2);
107 break;
108 SET_IOSF_REG(PWM1);
109 break;
110 SET_IOSF_REG(PWM2);
111 break;
112 SET_IOSF_REG(HSUART1);
113 break;
114 SET_IOSF_REG(HSUART2);
115 break;
116 SET_IOSF_REG(SPI);
117 break;
118 }
Aaron Durbindc866cf2013-11-12 20:21:53 -0600119}
120
Elyes HAOUAS17a3ceb2018-05-22 10:42:28 +0200121static void i2c_disable_resets(struct device *dev)
Aaron Durbindc866cf2013-11-12 20:21:53 -0600122{
123 /* Release the I2C devices from reset. */
Aaron Durbin616f3942013-12-10 17:12:44 -0800124 static const struct reg_script ops[] = {
Aaron Durbindc866cf2013-11-12 20:21:53 -0600125 REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x804, 0x3),
126 REG_SCRIPT_END,
127 };
128
129#define CASE_I2C(name_) \
130 case PCI_DEVFN(name_ ## _DEV, name_ ## _FUNC)
131
132 switch (dev->path.pci.devfn) {
133 CASE_I2C(I2C1):
134 CASE_I2C(I2C2):
135 CASE_I2C(I2C3):
136 CASE_I2C(I2C4):
137 CASE_I2C(I2C5):
138 CASE_I2C(I2C6):
139 CASE_I2C(I2C7):
140 printk(BIOS_DEBUG, "Releasing I2C device from reset.\n");
Aaron Durbin616f3942013-12-10 17:12:44 -0800141 reg_script_run_on_dev(dev, ops);
Aaron Durbindc866cf2013-11-12 20:21:53 -0600142 break;
143 default:
144 return;
145 }
146}
147
Elyes HAOUAS17a3ceb2018-05-22 10:42:28 +0200148static void lpss_init(struct device *dev)
Aaron Durbindc866cf2013-11-12 20:21:53 -0600149{
Kyösti Mälkki8950cfb2019-07-13 22:16:25 +0300150 struct soc_intel_baytrail_config *config = config_of(dev);
Duncan Laurie430bf0d2013-12-10 14:37:42 -0800151 int iosf_reg, nvs_index;
152
153 dev_ctl_reg(dev, &iosf_reg, &nvs_index);
Aaron Durbindc866cf2013-11-12 20:21:53 -0600154
155 if (iosf_reg < 0) {
156 int slot = PCI_SLOT(dev->path.pci.devfn);
157 int func = PCI_FUNC(dev->path.pci.devfn);
158 printk(BIOS_DEBUG, "Could not find iosf_reg for %02x.%01x\n",
159 slot, func);
160 return;
161 }
162 dev_enable_snoop_and_pm(dev, iosf_reg);
Duncan Lauriec29d6b82013-12-12 16:55:36 -0800163 i2c_disable_resets(dev);
Aaron Durbindc866cf2013-11-12 20:21:53 -0600164
Duncan Laurie430bf0d2013-12-10 14:37:42 -0800165 if (config->lpss_acpi_mode)
166 dev_enable_acpi_mode(dev, iosf_reg, nvs_index);
Aaron Durbindc866cf2013-11-12 20:21:53 -0600167}
168
169static struct device_operations device_ops = {
170 .read_resources = pci_dev_read_resources,
171 .set_resources = pci_dev_set_resources,
172 .enable_resources = pci_dev_enable_resources,
173 .init = lpss_init,
Aaron Durbindc866cf2013-11-12 20:21:53 -0600174 .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};