blob: 3bb7d113098c5b29a552315c8df1c66ff6b59779 [file] [log] [blame]
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +05301/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2017 Intel Corporation.
5 *
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
16#include <arch/acpigen.h>
Nico Huber0f2dd1e2017-08-01 14:02:40 +020017#include <device/i2c_bus.h>
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +053018#include <device/pci.h>
19#include <device/pci_def.h>
20#include <device/pci_ids.h>
21#include <intelblocks/lpss_i2c.h>
22#include "lpss_i2c.h"
23
24static int lpss_i2c_dev_to_bus(struct device *dev)
25{
26 pci_devfn_t devfn = dev->path.pci.devfn;
27 return i2c_soc_devfn_to_bus(devfn);
28}
29
30uintptr_t lpss_i2c_base_address(unsigned int bus)
31{
32 int devfn;
33 struct device *dev;
34 struct resource *res;
35
36 /* bus -> devfn */
37 devfn = i2c_soc_bus_to_devfn(bus);
38
39 if (devfn < 0)
40 return (uintptr_t)NULL;
41
42 /* devfn -> dev */
43 dev = dev_find_slot(0, devfn);
Furquan Shaikhd629e4332017-06-09 17:54:00 -070044 if (!dev || !dev->enabled)
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +053045 return (uintptr_t)NULL;
46
47 /* dev -> bar0 */
48 res = find_resource(dev, PCI_BASE_ADDRESS_0);
49 if (res)
50 return res->base;
51
52 return (uintptr_t)NULL;
53}
54
55/*
56 * Write ACPI object to describe speed configuration.
57 *
58 * ACPI Object: Name ("xxxx", Package () { scl_lcnt, scl_hcnt, sda_hold }
59 *
60 * SSCN: I2C_SPEED_STANDARD
61 * FMCN: I2C_SPEED_FAST
62 * FPCN: I2C_SPEED_FAST_PLUS
63 * HSCN: I2C_SPEED_HIGH
64 */
65static void lpss_i2c_acpi_write_speed_config(
66 const struct lpss_i2c_speed_config *config)
67{
68 if (!config)
69 return;
70 if (!config->scl_lcnt && !config->scl_hcnt && !config->sda_hold)
71 return;
72
73 if (config->speed >= I2C_SPEED_HIGH)
74 acpigen_write_name("HSCN");
75 else if (config->speed >= I2C_SPEED_FAST_PLUS)
76 acpigen_write_name("FPCN");
77 else if (config->speed >= I2C_SPEED_FAST)
78 acpigen_write_name("FMCN");
79 else
80 acpigen_write_name("SSCN");
81
82 /* Package () { scl_lcnt, scl_hcnt, sda_hold } */
83 acpigen_write_package(3);
84 acpigen_write_word(config->scl_hcnt);
85 acpigen_write_word(config->scl_lcnt);
86 acpigen_write_dword(config->sda_hold);
87 acpigen_pop_len();
88}
89
90/*
91 * The device should already be enabled and out of reset,
92 * either from early init in coreboot or SiliconInit in FSP.
93 */
94static void lpss_i2c_dev_init(struct device *dev)
95{
96 const struct lpss_i2c_bus_config *config;
97 int bus = lpss_i2c_dev_to_bus(dev);
98
Rizwan Qureshi7f72c642017-10-04 18:53:19 +053099 if (bus < 0)
100 return;
101
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +0530102 config = i2c_get_soc_cfg(bus, dev);
103
Rizwan Qureshi7f72c642017-10-04 18:53:19 +0530104 if (!config)
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +0530105 return;
106
107 lpss_i2c_init(bus, config);
108}
109
110/*
111 * Generate I2C timing information into the SSDT for the OS driver to consume,
112 * optionally applying override values provided by the caller.
113 */
114static void lpss_i2c_acpi_fill_ssdt(struct device *dev)
115{
116 const struct lpss_i2c_bus_config *bcfg;
117 struct lpss_i2c_regs *regs;
118 struct lpss_i2c_speed_config sgen;
119 enum i2c_speed speeds[LPSS_I2C_SPEED_CONFIG_COUNT] = {
120 I2C_SPEED_STANDARD,
121 I2C_SPEED_FAST,
122 I2C_SPEED_FAST_PLUS,
123 I2C_SPEED_HIGH,
124 };
Furquan Shaikhd629e4332017-06-09 17:54:00 -0700125 int i, bus;
126
127 if (!dev->enabled)
128 return;
129
130 bus = lpss_i2c_dev_to_bus(dev);
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +0530131
Rizwan Qureshi7f72c642017-10-04 18:53:19 +0530132 if (bus < 0)
133 return;
134
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +0530135 bcfg = i2c_get_soc_cfg(bus, dev);
136
137 if (!bcfg)
138 return;
139
140 regs = (struct lpss_i2c_regs *)lpss_i2c_base_address(bus);
141 if (!regs)
142 return;
143
144 acpigen_write_scope(acpi_device_path(dev));
145
146 /* Report timing values for the OS driver */
147 for (i = 0; i < LPSS_I2C_SPEED_CONFIG_COUNT; i++) {
148 /* Generate speed config. */
149 if (lpss_i2c_gen_speed_config(regs, speeds[i], bcfg, &sgen) < 0)
150 continue;
151
152 /* Generate ACPI based on selected speed config */
153 lpss_i2c_acpi_write_speed_config(&sgen);
154 }
155
156 acpigen_pop_len();
157}
158
Nico Huber58173862017-08-01 17:09:35 +0200159static int lpss_i2c_dev_transfer(struct device *dev,
160 const struct i2c_msg *msg, size_t count)
161{
162 return lpss_i2c_transfer(lpss_i2c_dev_to_bus(dev), msg, count);
163}
164
165static const struct i2c_bus_operations i2c_bus_ops = {
166 .transfer = lpss_i2c_dev_transfer,
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +0530167};
168
169static struct device_operations i2c_dev_ops = {
170 .read_resources = &pci_dev_read_resources,
171 .set_resources = &pci_dev_set_resources,
172 .enable_resources = &pci_dev_enable_resources,
173 .scan_bus = &scan_smbus,
174 .ops_i2c_bus = &i2c_bus_ops,
Subrata Banik6bbc91a2017-12-07 14:55:51 +0530175 .ops_pci = &pci_dev_ops_pci,
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +0530176 .init = &lpss_i2c_dev_init,
177 .acpi_fill_ssdt_generator = &lpss_i2c_acpi_fill_ssdt,
178};
179
180static const unsigned short pci_device_ids[] = {
181 PCI_DEVICE_ID_INTEL_SPT_I2C0,
182 PCI_DEVICE_ID_INTEL_SPT_I2C1,
183 PCI_DEVICE_ID_INTEL_SPT_I2C2,
184 PCI_DEVICE_ID_INTEL_SPT_I2C3,
185 PCI_DEVICE_ID_INTEL_SPT_I2C4,
186 PCI_DEVICE_ID_INTEL_SPT_I2C5,
187 PCI_DEVICE_ID_INTEL_APL_I2C0,
188 PCI_DEVICE_ID_INTEL_APL_I2C1,
189 PCI_DEVICE_ID_INTEL_APL_I2C2,
190 PCI_DEVICE_ID_INTEL_APL_I2C3,
191 PCI_DEVICE_ID_INTEL_APL_I2C4,
192 PCI_DEVICE_ID_INTEL_APL_I2C5,
193 PCI_DEVICE_ID_INTEL_APL_I2C6,
194 PCI_DEVICE_ID_INTEL_APL_I2C7,
Lijian Zhaobbedef92017-07-29 16:38:38 -0700195 PCI_DEVICE_ID_INTEL_CNL_I2C0,
196 PCI_DEVICE_ID_INTEL_CNL_I2C1,
197 PCI_DEVICE_ID_INTEL_CNL_I2C2,
198 PCI_DEVICE_ID_INTEL_CNL_I2C3,
199 PCI_DEVICE_ID_INTEL_CNL_I2C4,
200 PCI_DEVICE_ID_INTEL_CNL_I2C5,
Ravi Sarawadi3038e9b2017-05-18 16:00:35 -0700201 PCI_DEVICE_ID_INTEL_GLK_I2C0,
202 PCI_DEVICE_ID_INTEL_GLK_I2C1,
203 PCI_DEVICE_ID_INTEL_GLK_I2C2,
204 PCI_DEVICE_ID_INTEL_GLK_I2C3,
205 PCI_DEVICE_ID_INTEL_GLK_I2C4,
206 PCI_DEVICE_ID_INTEL_GLK_I2C5,
207 PCI_DEVICE_ID_INTEL_GLK_I2C6,
208 PCI_DEVICE_ID_INTEL_GLK_I2C7,
209 0,
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +0530210};
211
212static const struct pci_driver pch_i2c __pci_driver = {
213 .ops = &i2c_dev_ops,
214 .vendor = PCI_VENDOR_ID_INTEL,
215 .devices = pci_device_ids,
216};