blob: fe220b58fbfbb10d703710e7e355e5c60bc85bbc [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>
17#include <device/i2c.h>
18#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);
44 if (!dev)
45 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 };
122 int i, bus = lpss_i2c_dev_to_bus(dev);
123
124 bcfg = i2c_get_soc_cfg(bus, dev);
125
126 if (!bcfg)
127 return;
128
129 regs = (struct lpss_i2c_regs *)lpss_i2c_base_address(bus);
130 if (!regs)
131 return;
132
133 acpigen_write_scope(acpi_device_path(dev));
134
135 /* Report timing values for the OS driver */
136 for (i = 0; i < LPSS_I2C_SPEED_CONFIG_COUNT; i++) {
137 /* Generate speed config. */
138 if (lpss_i2c_gen_speed_config(regs, speeds[i], bcfg, &sgen) < 0)
139 continue;
140
141 /* Generate ACPI based on selected speed config */
142 lpss_i2c_acpi_write_speed_config(&sgen);
143 }
144
145 acpigen_pop_len();
146}
147
148static struct i2c_bus_operations i2c_bus_ops = {
149 .dev_to_bus = &lpss_i2c_dev_to_bus,
150};
151
152static struct device_operations i2c_dev_ops = {
153 .read_resources = &pci_dev_read_resources,
154 .set_resources = &pci_dev_set_resources,
155 .enable_resources = &pci_dev_enable_resources,
156 .scan_bus = &scan_smbus,
157 .ops_i2c_bus = &i2c_bus_ops,
158 .init = &lpss_i2c_dev_init,
159 .acpi_fill_ssdt_generator = &lpss_i2c_acpi_fill_ssdt,
160};
161
162static const unsigned short pci_device_ids[] = {
163 PCI_DEVICE_ID_INTEL_SPT_I2C0,
164 PCI_DEVICE_ID_INTEL_SPT_I2C1,
165 PCI_DEVICE_ID_INTEL_SPT_I2C2,
166 PCI_DEVICE_ID_INTEL_SPT_I2C3,
167 PCI_DEVICE_ID_INTEL_SPT_I2C4,
168 PCI_DEVICE_ID_INTEL_SPT_I2C5,
169 PCI_DEVICE_ID_INTEL_APL_I2C0,
170 PCI_DEVICE_ID_INTEL_APL_I2C1,
171 PCI_DEVICE_ID_INTEL_APL_I2C2,
172 PCI_DEVICE_ID_INTEL_APL_I2C3,
173 PCI_DEVICE_ID_INTEL_APL_I2C4,
174 PCI_DEVICE_ID_INTEL_APL_I2C5,
175 PCI_DEVICE_ID_INTEL_APL_I2C6,
176 PCI_DEVICE_ID_INTEL_APL_I2C7,
Ravi Sarawadi3038e9b2017-05-18 16:00:35 -0700177 PCI_DEVICE_ID_INTEL_GLK_I2C0,
178 PCI_DEVICE_ID_INTEL_GLK_I2C1,
179 PCI_DEVICE_ID_INTEL_GLK_I2C2,
180 PCI_DEVICE_ID_INTEL_GLK_I2C3,
181 PCI_DEVICE_ID_INTEL_GLK_I2C4,
182 PCI_DEVICE_ID_INTEL_GLK_I2C5,
183 PCI_DEVICE_ID_INTEL_GLK_I2C6,
184 PCI_DEVICE_ID_INTEL_GLK_I2C7,
185 0,
Rizwan Qureshiae6a4b62017-04-26 21:06:35 +0530186};
187
188static const struct pci_driver pch_i2c __pci_driver = {
189 .ops = &i2c_dev_ops,
190 .vendor = PCI_VENDOR_ID_INTEL,
191 .devices = pci_device_ids,
192};