blob: 625bb991d4ba5920a5f79a22f341b081866fb8cd [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
99 config = i2c_get_soc_cfg(bus, dev);
100
101 if (!config || bus < 0)
102 return;
103
104 lpss_i2c_init(bus, config);
105}
106
107/*
108 * Generate I2C timing information into the SSDT for the OS driver to consume,
109 * optionally applying override values provided by the caller.
110 */
111static void lpss_i2c_acpi_fill_ssdt(struct device *dev)
112{
113 const struct lpss_i2c_bus_config *bcfg;
114 struct lpss_i2c_regs *regs;
115 struct lpss_i2c_speed_config sgen;
116 enum i2c_speed speeds[LPSS_I2C_SPEED_CONFIG_COUNT] = {
117 I2C_SPEED_STANDARD,
118 I2C_SPEED_FAST,
119 I2C_SPEED_FAST_PLUS,
120 I2C_SPEED_HIGH,
121 };
Furquan Shaikhd629e4332017-06-09 17:54:00 -0700122 int i, bus;
123
124 if (!dev->enabled)
125 return;
126
127 bus = lpss_i2c_dev_to_bus(dev);
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +0530128
129 bcfg = i2c_get_soc_cfg(bus, dev);
130
131 if (!bcfg)
132 return;
133
134 regs = (struct lpss_i2c_regs *)lpss_i2c_base_address(bus);
135 if (!regs)
136 return;
137
138 acpigen_write_scope(acpi_device_path(dev));
139
140 /* Report timing values for the OS driver */
141 for (i = 0; i < LPSS_I2C_SPEED_CONFIG_COUNT; i++) {
142 /* Generate speed config. */
143 if (lpss_i2c_gen_speed_config(regs, speeds[i], bcfg, &sgen) < 0)
144 continue;
145
146 /* Generate ACPI based on selected speed config */
147 lpss_i2c_acpi_write_speed_config(&sgen);
148 }
149
150 acpigen_pop_len();
151}
152
Nico Huber58173862017-08-01 17:09:35 +0200153static int lpss_i2c_dev_transfer(struct device *dev,
154 const struct i2c_msg *msg, size_t count)
155{
156 return lpss_i2c_transfer(lpss_i2c_dev_to_bus(dev), msg, count);
157}
158
159static const struct i2c_bus_operations i2c_bus_ops = {
160 .transfer = lpss_i2c_dev_transfer,
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +0530161};
162
163static struct device_operations i2c_dev_ops = {
164 .read_resources = &pci_dev_read_resources,
165 .set_resources = &pci_dev_set_resources,
166 .enable_resources = &pci_dev_enable_resources,
167 .scan_bus = &scan_smbus,
168 .ops_i2c_bus = &i2c_bus_ops,
169 .init = &lpss_i2c_dev_init,
170 .acpi_fill_ssdt_generator = &lpss_i2c_acpi_fill_ssdt,
171};
172
173static const unsigned short pci_device_ids[] = {
174 PCI_DEVICE_ID_INTEL_SPT_I2C0,
175 PCI_DEVICE_ID_INTEL_SPT_I2C1,
176 PCI_DEVICE_ID_INTEL_SPT_I2C2,
177 PCI_DEVICE_ID_INTEL_SPT_I2C3,
178 PCI_DEVICE_ID_INTEL_SPT_I2C4,
179 PCI_DEVICE_ID_INTEL_SPT_I2C5,
180 PCI_DEVICE_ID_INTEL_APL_I2C0,
181 PCI_DEVICE_ID_INTEL_APL_I2C1,
182 PCI_DEVICE_ID_INTEL_APL_I2C2,
183 PCI_DEVICE_ID_INTEL_APL_I2C3,
184 PCI_DEVICE_ID_INTEL_APL_I2C4,
185 PCI_DEVICE_ID_INTEL_APL_I2C5,
186 PCI_DEVICE_ID_INTEL_APL_I2C6,
187 PCI_DEVICE_ID_INTEL_APL_I2C7,
Lijian Zhaobbedef92017-07-29 16:38:38 -0700188 PCI_DEVICE_ID_INTEL_CNL_I2C0,
189 PCI_DEVICE_ID_INTEL_CNL_I2C1,
190 PCI_DEVICE_ID_INTEL_CNL_I2C2,
191 PCI_DEVICE_ID_INTEL_CNL_I2C3,
192 PCI_DEVICE_ID_INTEL_CNL_I2C4,
193 PCI_DEVICE_ID_INTEL_CNL_I2C5,
Ravi Sarawadi3038e9b2017-05-18 16:00:35 -0700194 PCI_DEVICE_ID_INTEL_GLK_I2C0,
195 PCI_DEVICE_ID_INTEL_GLK_I2C1,
196 PCI_DEVICE_ID_INTEL_GLK_I2C2,
197 PCI_DEVICE_ID_INTEL_GLK_I2C3,
198 PCI_DEVICE_ID_INTEL_GLK_I2C4,
199 PCI_DEVICE_ID_INTEL_GLK_I2C5,
200 PCI_DEVICE_ID_INTEL_GLK_I2C6,
201 PCI_DEVICE_ID_INTEL_GLK_I2C7,
202 0,
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +0530203};
204
205static const struct pci_driver pch_i2c __pci_driver = {
206 .ops = &i2c_dev_ops,
207 .vendor = PCI_VENDOR_ID_INTEL,
208 .devices = pci_device_ids,
209};