blob: f72adfce8a43ec80decf089bc14c67ab5f112d04 [file] [log] [blame]
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +05301/*
2 * This file is part of the coreboot project.
3 *
Subrata Banik7d8c0c22018-09-27 19:27:39 +05304 * Copyright 2017-2018 Intel Corporation.
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +05305 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
Subrata Banike62836b2018-05-07 16:27:51 +053016#include <arch/io.h>
17#include <console/console.h>
18#include <device/device.h>
19#include <device/i2c_simple.h>
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +053020#include <device/pci.h>
21#include <device/pci_def.h>
22#include <device/pci_ids.h>
Chris Chingb8dc63b2017-12-06 14:26:15 -070023#include <drivers/i2c/designware/dw_i2c.h>
Subrata Banike62836b2018-05-07 16:27:51 +053024#include <intelblocks/chip.h>
25#include <intelblocks/lpss.h>
26#include <soc/iomap.h>
27#include <soc/pci_devs.h>
28
29int dw_i2c_soc_dev_to_bus(struct device *dev)
30{
31 pci_devfn_t devfn = dev->path.pci.devfn;
32 return dw_i2c_soc_devfn_to_bus(devfn);
33}
34
35/* Getting I2C bus configuration from devicetree config */
36const struct dw_i2c_bus_config *dw_i2c_get_soc_cfg(unsigned int bus)
37{
38 const struct soc_intel_common_config *common_config;
39 common_config = chip_get_common_soc_structure();
40
41 return &common_config->i2c[bus];
42}
43
44/* Get base address for early init of I2C controllers. */
45uintptr_t dw_i2c_get_soc_early_base(unsigned int bus)
46{
47 return EARLY_I2C_BASE(bus);
48}
49
50#if !ENV_RAMSTAGE
51static int lpss_i2c_early_init_bus(unsigned int bus)
52{
53 const struct dw_i2c_bus_config *config;
54 const struct device *tree_dev;
55 pci_devfn_t dev;
56 int devfn;
57 uintptr_t base;
58
59 /* Find the PCI device for this bus controller */
60 devfn = dw_i2c_soc_bus_to_devfn(bus);
61 if (devfn < 0) {
62 printk(BIOS_ERR, "I2C%u device not found\n", bus);
63 return -1;
64 }
65
66 /* Look up the controller device in the devicetree */
67 dev = PCI_DEV(0, PCI_SLOT(devfn), PCI_FUNC(devfn));
Kyösti Mälkkie7377552018-06-21 16:20:55 +030068 tree_dev = pcidev_path_on_root(devfn);
Subrata Banike62836b2018-05-07 16:27:51 +053069 if (!tree_dev || !tree_dev->enabled) {
70 printk(BIOS_ERR, "I2C%u device not enabled\n", bus);
71 return -1;
72 }
73
74 /* Skip if not enabled for early init */
75 config = dw_i2c_get_soc_cfg(bus);
76 if (!config || !config->early_init) {
77 printk(BIOS_DEBUG, "I2C%u not enabled for early init\n", bus);
78 return -1;
79 }
80
81 /* Prepare early base address for access before memory */
82 base = dw_i2c_get_soc_early_base(bus);
83 pci_write_config32(dev, PCI_BASE_ADDRESS_0, base);
84 pci_write_config32(dev, PCI_COMMAND,
85 PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
86
87 /* Take device out of reset */
88 lpss_reset_release(base);
89
90 /* Initialize the controller */
91 if (dw_i2c_init(bus, config) < 0) {
92 printk(BIOS_ERR, "I2C%u failed to initialize\n", bus);
93 return -1;
94 }
95
96 return 0;
97}
98
99uintptr_t dw_i2c_base_address(unsigned int bus)
100{
101 int devfn;
102 pci_devfn_t dev;
103 uintptr_t base;
104
105 /* Find device+function for this controller */
106 devfn = dw_i2c_soc_bus_to_devfn(bus);
107 if (devfn < 0)
108 return (uintptr_t)NULL;
109
110 /* Form a PCI address for this device */
111 dev = PCI_DEV(0, PCI_SLOT(devfn), PCI_FUNC(devfn));
112
113 /* Read the first base address for this device */
114 base = ALIGN_DOWN(pci_read_config32(dev, PCI_BASE_ADDRESS_0), 16);
115
116 /* Attempt to initialize bus if base is not set yet */
117 if (!base && !lpss_i2c_early_init_bus(bus))
118 base = ALIGN_DOWN(pci_read_config32(dev, PCI_BASE_ADDRESS_0),
119 16);
120 return base;
121}
122#else
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +0530123
Chris Chingb8dc63b2017-12-06 14:26:15 -0700124uintptr_t dw_i2c_base_address(unsigned int bus)
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +0530125{
126 int devfn;
127 struct device *dev;
128 struct resource *res;
129
130 /* bus -> devfn */
Aaron Durbin9aee8192018-01-22 20:29:25 -0700131 devfn = dw_i2c_soc_bus_to_devfn(bus);
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +0530132
133 if (devfn < 0)
134 return (uintptr_t)NULL;
135
136 /* devfn -> dev */
Kyösti Mälkkie7377552018-06-21 16:20:55 +0300137 dev = pcidev_path_on_root(devfn);
Furquan Shaikhd629e4332017-06-09 17:54:00 -0700138 if (!dev || !dev->enabled)
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +0530139 return (uintptr_t)NULL;
140
141 /* dev -> bar0 */
142 res = find_resource(dev, PCI_BASE_ADDRESS_0);
143 if (res)
144 return res->base;
145
146 return (uintptr_t)NULL;
147}
148
Subrata Banik7d8c0c22018-09-27 19:27:39 +0530149/*
150 * This function ensures that the device is actually out of reset and
151 * its ready for initialization sequence.
152 */
153static void dw_i2c_device_init(struct device *dev)
154{
155 uintptr_t base_address;
156 int bus = dw_i2c_soc_dev_to_bus(dev);
157
158 if (bus < 0)
159 return;
160
161 base_address = dw_i2c_base_address(bus);
162 if (!base_address)
163 return;
164
165 /* Take device out of reset if its not done before */
166 if (lpss_is_controller_in_reset(base_address))
167 lpss_reset_release(base_address);
168
169 dw_i2c_dev_init(dev);
170}
171
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +0530172static struct device_operations i2c_dev_ops = {
173 .read_resources = &pci_dev_read_resources,
174 .set_resources = &pci_dev_set_resources,
175 .enable_resources = &pci_dev_enable_resources,
176 .scan_bus = &scan_smbus,
Aaron Durbinb7d79cd2018-01-22 21:31:48 -0700177 .ops_i2c_bus = &dw_i2c_bus_ops,
Subrata Banik6bbc91a2017-12-07 14:55:51 +0530178 .ops_pci = &pci_dev_ops_pci,
Subrata Banik7d8c0c22018-09-27 19:27:39 +0530179 .init = &dw_i2c_device_init,
Aaron Durbinb7d79cd2018-01-22 21:31:48 -0700180 .acpi_fill_ssdt_generator = &dw_i2c_acpi_fill_ssdt,
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +0530181};
182
183static const unsigned short pci_device_ids[] = {
184 PCI_DEVICE_ID_INTEL_SPT_I2C0,
185 PCI_DEVICE_ID_INTEL_SPT_I2C1,
186 PCI_DEVICE_ID_INTEL_SPT_I2C2,
187 PCI_DEVICE_ID_INTEL_SPT_I2C3,
188 PCI_DEVICE_ID_INTEL_SPT_I2C4,
189 PCI_DEVICE_ID_INTEL_SPT_I2C5,
V Sowmyaacc2a482018-01-23 15:27:23 +0530190 PCI_DEVICE_ID_INTEL_KBP_H_I2C0,
191 PCI_DEVICE_ID_INTEL_KBP_H_I2C1,
192 PCI_DEVICE_ID_INTEL_KBP_H_I2C2,
193 PCI_DEVICE_ID_INTEL_KBP_H_I2C3,
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +0530194 PCI_DEVICE_ID_INTEL_APL_I2C0,
195 PCI_DEVICE_ID_INTEL_APL_I2C1,
196 PCI_DEVICE_ID_INTEL_APL_I2C2,
197 PCI_DEVICE_ID_INTEL_APL_I2C3,
198 PCI_DEVICE_ID_INTEL_APL_I2C4,
199 PCI_DEVICE_ID_INTEL_APL_I2C5,
200 PCI_DEVICE_ID_INTEL_APL_I2C6,
201 PCI_DEVICE_ID_INTEL_APL_I2C7,
Lijian Zhaobbedef92017-07-29 16:38:38 -0700202 PCI_DEVICE_ID_INTEL_CNL_I2C0,
203 PCI_DEVICE_ID_INTEL_CNL_I2C1,
204 PCI_DEVICE_ID_INTEL_CNL_I2C2,
205 PCI_DEVICE_ID_INTEL_CNL_I2C3,
206 PCI_DEVICE_ID_INTEL_CNL_I2C4,
207 PCI_DEVICE_ID_INTEL_CNL_I2C5,
Ravi Sarawadi3038e9b2017-05-18 16:00:35 -0700208 PCI_DEVICE_ID_INTEL_GLK_I2C0,
209 PCI_DEVICE_ID_INTEL_GLK_I2C1,
210 PCI_DEVICE_ID_INTEL_GLK_I2C2,
211 PCI_DEVICE_ID_INTEL_GLK_I2C3,
212 PCI_DEVICE_ID_INTEL_GLK_I2C4,
213 PCI_DEVICE_ID_INTEL_GLK_I2C5,
214 PCI_DEVICE_ID_INTEL_GLK_I2C6,
215 PCI_DEVICE_ID_INTEL_GLK_I2C7,
praveen hodagatta praneshe26c4a42018-09-20 03:49:45 +0800216 PCI_DEVICE_ID_INTEL_CNP_H_I2C0,
217 PCI_DEVICE_ID_INTEL_CNP_H_I2C1,
218 PCI_DEVICE_ID_INTEL_CNP_H_I2C2,
219 PCI_DEVICE_ID_INTEL_CNP_H_I2C3,
Aamir Bohra9eac0392018-06-30 12:07:04 +0530220 PCI_DEVICE_ID_INTEL_ICP_I2C0,
221 PCI_DEVICE_ID_INTEL_ICP_I2C1,
222 PCI_DEVICE_ID_INTEL_ICP_I2C2,
223 PCI_DEVICE_ID_INTEL_ICP_I2C3,
224 PCI_DEVICE_ID_INTEL_ICP_I2C4,
225 PCI_DEVICE_ID_INTEL_ICP_I2C5,
Ravi Sarawadi3038e9b2017-05-18 16:00:35 -0700226 0,
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +0530227};
228
229static const struct pci_driver pch_i2c __pci_driver = {
230 .ops = &i2c_dev_ops,
231 .vendor = PCI_VENDOR_ID_INTEL,
232 .devices = pci_device_ids,
233};
Subrata Banike62836b2018-05-07 16:27:51 +0530234#endif