blob: 11c986722650c2297b9381fe0a7a274381edf5c8 [file] [log] [blame]
Simon Glasse2be5532019-12-06 21:41:40 -07001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2009
Patrick Delaunaya6b185e2022-05-20 18:38:10 +02004 * Vipin Kumar, STMicroelectronics, vipin.kumar@st.com.
Simon Glasse2be5532019-12-06 21:41:40 -07005 * Copyright 2019 Google Inc
6 */
7
Simon Glasse2be5532019-12-06 21:41:40 -07008#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -06009#include <log.h>
Simon Glassf0c98902019-12-06 21:41:42 -070010#include <spl.h>
Simon Glass3908d902020-07-07 21:32:29 -060011#include <acpi/acpigen.h>
12#include <acpi/acpi_device.h>
Simon Glass9daae2c2019-12-10 21:28:20 -070013#include <asm/lpss.h>
Simon Glass3908d902020-07-07 21:32:29 -060014#include <dm/acpi.h>
15#include <dm/device-internal.h>
16#include <dm/uclass-internal.h>
Simon Glasse2be5532019-12-06 21:41:40 -070017#include "designware_i2c.h"
18
Simon Glass9daae2c2019-12-10 21:28:20 -070019enum {
20 VANILLA = 0, /* standard I2C with no tweaks */
21 INTEL_APL, /* Apollo Lake I2C */
22};
23
Simon Glasse2be5532019-12-06 21:41:40 -070024/* BayTrail HCNT/LCNT/SDA hold time */
25static struct dw_scl_sda_cfg byt_config = {
26 .ss_hcnt = 0x200,
27 .fs_hcnt = 0x55,
28 .ss_lcnt = 0x200,
29 .fs_lcnt = 0x99,
30 .sda_hold = 0x6,
31};
32
Simon Glass9daae2c2019-12-10 21:28:20 -070033/* Have a weak function for now - possibly should be a new uclass */
34__weak void lpss_reset_release(void *regs);
35
Simon Glassaad29ae2020-12-03 16:55:21 -070036static int designware_i2c_pci_of_to_plat(struct udevice *dev)
Simon Glasse2be5532019-12-06 21:41:40 -070037{
38 struct dw_i2c *priv = dev_get_priv(dev);
39
Simon Glassf0c98902019-12-06 21:41:42 -070040 if (spl_phase() < PHASE_SPL) {
41 u32 base;
42 int ret;
43
44 ret = dev_read_u32(dev, "early-regs", &base);
45 if (ret)
46 return log_msg_ret("early-regs", ret);
47
48 /* Set i2c base address */
49 dm_pci_write_config32(dev, PCI_BASE_ADDRESS_0, base);
50
51 /* Enable memory access and bus master */
52 dm_pci_write_config32(dev, PCI_COMMAND, PCI_COMMAND_MEMORY |
53 PCI_COMMAND_MASTER);
54 }
55
56 if (spl_phase() < PHASE_BOARD_F) {
57 /* Handle early, fixed mapping into a different address space */
58 priv->regs = (struct i2c_regs *)dm_pci_read_bar32(dev, 0);
59 } else {
60 priv->regs = (struct i2c_regs *)
Andrew Scull6520c822022-04-21 16:11:13 +000061 dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0,
62 PCI_REGION_TYPE, PCI_REGION_MEM);
Simon Glassf0c98902019-12-06 21:41:42 -070063 }
64 if (!priv->regs)
65 return -EINVAL;
66
Simon Glasse2be5532019-12-06 21:41:40 -070067 /* Save base address from PCI BAR */
Simon Glasse2be5532019-12-06 21:41:40 -070068 if (IS_ENABLED(CONFIG_INTEL_BAYTRAIL))
69 /* Use BayTrail specific timing values */
70 priv->scl_sda_cfg = &byt_config;
Simon Glassc38e2b32020-01-23 11:48:15 -070071 if (dev_get_driver_data(dev) == INTEL_APL)
72 priv->has_spk_cnt = true;
Simon Glasse2be5532019-12-06 21:41:40 -070073
Simon Glassaad29ae2020-12-03 16:55:21 -070074 return designware_i2c_of_to_plat(dev);
Simon Glassf0c98902019-12-06 21:41:42 -070075}
76
77static int designware_i2c_pci_probe(struct udevice *dev)
78{
Simon Glass9daae2c2019-12-10 21:28:20 -070079 struct dw_i2c *priv = dev_get_priv(dev);
80
81 if (dev_get_driver_data(dev) == INTEL_APL) {
82 /* Ensure controller is in D0 state */
83 lpss_set_power_state(dev, STATE_D0);
84
85 lpss_reset_release(priv->regs);
86 }
87
Simon Glasse2be5532019-12-06 21:41:40 -070088 return designware_i2c_probe(dev);
89}
90
91static int designware_i2c_pci_bind(struct udevice *dev)
92{
Simon Glasse2be5532019-12-06 21:41:40 -070093 char name[20];
94
Simon Glassf1d50f72020-12-19 10:40:13 -070095 if (dev_has_ofnode(dev))
Simon Glass3908d902020-07-07 21:32:29 -060096 return 0;
97
Simon Glass4123ba02020-12-16 21:20:15 -070098 sprintf(name, "i2c_designware#%u", dev_seq(dev));
Simon Glasse2be5532019-12-06 21:41:40 -070099 device_set_name(dev, name);
100
101 return 0;
102}
103
Simon Glass3908d902020-07-07 21:32:29 -0600104/*
105 * Write ACPI object to describe speed configuration.
106 *
107 * ACPI Object: Name ("xxxx", Package () { scl_lcnt, scl_hcnt, sda_hold }
108 *
109 * SSCN: I2C_SPEED_STANDARD
110 * FMCN: I2C_SPEED_FAST
111 * FPCN: I2C_SPEED_FAST_PLUS
112 * HSCN: I2C_SPEED_HIGH
113 */
114static void dw_i2c_acpi_write_speed_config(struct acpi_ctx *ctx,
115 struct dw_i2c_speed_config *config)
116{
117 switch (config->speed_mode) {
118 case IC_SPEED_MODE_HIGH:
119 acpigen_write_name(ctx, "HSCN");
120 break;
121 case IC_SPEED_MODE_FAST_PLUS:
122 acpigen_write_name(ctx, "FPCN");
123 break;
124 case IC_SPEED_MODE_FAST:
125 acpigen_write_name(ctx, "FMCN");
126 break;
127 case IC_SPEED_MODE_STANDARD:
128 default:
129 acpigen_write_name(ctx, "SSCN");
130 }
131
132 /* Package () { scl_lcnt, scl_hcnt, sda_hold } */
133 acpigen_write_package(ctx, 3);
134 acpigen_write_word(ctx, config->scl_hcnt);
135 acpigen_write_word(ctx, config->scl_lcnt);
136 acpigen_write_dword(ctx, config->sda_hold);
137 acpigen_pop_len(ctx);
138}
139
140/*
141 * Generate I2C timing information into the SSDT for the OS driver to consume,
142 * optionally applying override values provided by the caller.
143 */
144static int dw_i2c_acpi_fill_ssdt(const struct udevice *dev,
145 struct acpi_ctx *ctx)
146{
147 struct dw_i2c_speed_config config;
148 char path[ACPI_PATH_MAX];
Simon Glass3908d902020-07-07 21:32:29 -0600149 uint speed;
Simon Glass3908d902020-07-07 21:32:29 -0600150 int ret;
151
152 /* If no device-tree node, ignore this since we assume it isn't used */
Simon Glassf1d50f72020-12-19 10:40:13 -0700153 if (!dev_has_ofnode(dev))
Simon Glass3908d902020-07-07 21:32:29 -0600154 return 0;
155
156 ret = acpi_device_path(dev, path, sizeof(path));
157 if (ret)
158 return log_msg_ret("path", ret);
159
Simon Glass3908d902020-07-07 21:32:29 -0600160 speed = dev_read_u32_default(dev, "clock-frequency", 100000);
161 acpigen_write_scope(ctx, path);
162 ret = dw_i2c_gen_speed_config(dev, speed, &config);
163 if (ret)
164 return log_msg_ret("config", ret);
165 dw_i2c_acpi_write_speed_config(ctx, &config);
166 acpigen_pop_len(ctx);
167
168 return 0;
169}
170
171struct acpi_ops dw_i2c_acpi_ops = {
172 .fill_ssdt = dw_i2c_acpi_fill_ssdt,
173};
174
Simon Glassf0c98902019-12-06 21:41:42 -0700175static const struct udevice_id designware_i2c_pci_ids[] = {
176 { .compatible = "snps,designware-i2c-pci" },
Simon Glass9daae2c2019-12-10 21:28:20 -0700177 { .compatible = "intel,apl-i2c", .data = INTEL_APL },
Simon Glassf0c98902019-12-06 21:41:42 -0700178 { }
179};
180
Simon Glass62b54872021-01-21 13:57:08 -0700181DM_DRIVER_ALIAS(i2c_designware_pci, intel_apl_i2c)
182
Simon Glasse2be5532019-12-06 21:41:40 -0700183U_BOOT_DRIVER(i2c_designware_pci) = {
184 .name = "i2c_designware_pci",
185 .id = UCLASS_I2C,
Simon Glassf0c98902019-12-06 21:41:42 -0700186 .of_match = designware_i2c_pci_ids,
Simon Glasse2be5532019-12-06 21:41:40 -0700187 .bind = designware_i2c_pci_bind,
Simon Glassaad29ae2020-12-03 16:55:21 -0700188 .of_to_plat = designware_i2c_pci_of_to_plat,
Simon Glasse2be5532019-12-06 21:41:40 -0700189 .probe = designware_i2c_pci_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700190 .priv_auto = sizeof(struct dw_i2c),
Simon Glasse2be5532019-12-06 21:41:40 -0700191 .remove = designware_i2c_remove,
192 .flags = DM_FLAG_OS_PREPARE,
193 .ops = &designware_i2c_ops,
Simon Glass3908d902020-07-07 21:32:29 -0600194 ACPI_OPS_PTR(&dw_i2c_acpi_ops)
Simon Glasse2be5532019-12-06 21:41:40 -0700195};
196
197static struct pci_device_id designware_pci_supported[] = {
198 /* Intel BayTrail has 7 I2C controller located on the PCI bus */
199 { PCI_VDEVICE(INTEL, 0x0f41) },
200 { PCI_VDEVICE(INTEL, 0x0f42) },
201 { PCI_VDEVICE(INTEL, 0x0f43) },
202 { PCI_VDEVICE(INTEL, 0x0f44) },
203 { PCI_VDEVICE(INTEL, 0x0f45) },
204 { PCI_VDEVICE(INTEL, 0x0f46) },
205 { PCI_VDEVICE(INTEL, 0x0f47) },
Simon Glass9daae2c2019-12-10 21:28:20 -0700206 { PCI_VDEVICE(INTEL, 0x5aac), .driver_data = INTEL_APL },
207 { PCI_VDEVICE(INTEL, 0x5aae), .driver_data = INTEL_APL },
208 { PCI_VDEVICE(INTEL, 0x5ab0), .driver_data = INTEL_APL },
209 { PCI_VDEVICE(INTEL, 0x5ab2), .driver_data = INTEL_APL },
210 { PCI_VDEVICE(INTEL, 0x5ab4), .driver_data = INTEL_APL },
211 { PCI_VDEVICE(INTEL, 0x5ab6), .driver_data = INTEL_APL },
Simon Glasse2be5532019-12-06 21:41:40 -0700212 {},
213};
214
215U_BOOT_PCI_DEVICE(i2c_designware_pci, designware_pci_supported);