blob: 9d016150c0dc07b510cb3658b48e1405d57ef0e9 [file] [log] [blame]
Angel Ponsae593872020-04-04 18:50:57 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Martin Roth5c354b92019-04-22 14:55:16 -06002
3#include <device/mmio.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -07004#include <acpi/acpi.h>
Martin Roth5c354b92019-04-22 14:55:16 -06005#include <console/console.h>
6#include <delay.h>
Felix Held00058f52020-04-06 23:36:24 +02007#include <device/device.h>
Martin Roth5c354b92019-04-22 14:55:16 -06008#include <drivers/i2c/designware/dw_i2c.h>
9#include <amdblocks/acpimmio.h>
Karthikeyan Ramasubramanian0dbea482021-03-08 23:23:50 -070010#include <amdblocks/i2c.h>
Martin Roth7e78e562019-11-03 23:29:02 -070011#include <soc/i2c.h>
Martin Roth5c354b92019-04-22 14:55:16 -060012#include <soc/iomap.h>
13#include <soc/pci_devs.h>
14#include <soc/southbridge.h>
Martin Roth5c354b92019-04-22 14:55:16 -060015#include "chip.h"
16
Martin Rothac41f582020-06-14 17:24:12 -060017#if ENV_X86
Martin Roth7e78e562019-11-03 23:29:02 -070018static const uintptr_t i2c_bus_address[I2C_MASTER_DEV_COUNT + I2C_SLAVE_DEV_COUNT] = {
19 0,
20 0,
Marshall Dawsone2c24f72019-06-20 08:47:58 -060021 APU_I2C2_BASE,
22 APU_I2C3_BASE,
Martin Roth7e78e562019-11-03 23:29:02 -070023 APU_I2C4_BASE, /* Can only be used in slave mode */
Martin Roth5c354b92019-04-22 14:55:16 -060024};
Martin Rothac41f582020-06-14 17:24:12 -060025#else
26static uintptr_t i2c_bus_address[I2C_MASTER_DEV_COUNT + I2C_SLAVE_DEV_COUNT];
27#endif
Martin Roth5c354b92019-04-22 14:55:16 -060028
29uintptr_t dw_i2c_base_address(unsigned int bus)
30{
Martin Roth7e78e562019-11-03 23:29:02 -070031 if (bus >= ARRAY_SIZE(i2c_bus_address))
Marshall Dawsone2c24f72019-06-20 08:47:58 -060032 return 0;
33
Martin Roth7e78e562019-11-03 23:29:02 -070034 return i2c_bus_address[bus];
Martin Roth5c354b92019-04-22 14:55:16 -060035}
36
Martin Rothac41f582020-06-14 17:24:12 -060037#if !ENV_X86
38void i2c_set_bar(unsigned int bus, uintptr_t bar)
39{
40 if (bus >= ARRAY_SIZE(i2c_bus_address)) {
41 printk(BIOS_ERR, "Error: i2c index out of bounds: %u.", bus);
42 return;
43 }
44
45 i2c_bus_address[bus] = bar;
46}
47#endif
48
Martin Roth5c354b92019-04-22 14:55:16 -060049const struct dw_i2c_bus_config *dw_i2c_get_soc_cfg(unsigned int bus)
50{
Marshall Dawsonbc4c9032019-06-11 12:18:20 -060051 const struct soc_amd_picasso_config *config;
Martin Roth5c354b92019-04-22 14:55:16 -060052
Martin Roth7e78e562019-11-03 23:29:02 -070053 if (bus >= ARRAY_SIZE(config->i2c))
Martin Roth5c354b92019-04-22 14:55:16 -060054 return NULL;
55
Felix Held00058f52020-04-06 23:36:24 +020056 /* config is not NULL; if it was, config_of_soc calls die() internally */
57 config = config_of_soc();
Martin Roth5c354b92019-04-22 14:55:16 -060058
59 return &config->i2c[bus];
60}
61
Furquan Shaikh46637492020-06-03 16:22:20 -070062static const char *i2c_acpi_name(const struct device *dev)
Martin Roth5c354b92019-04-22 14:55:16 -060063{
Martin Rothac41f582020-06-14 17:24:12 -060064 if ((uintptr_t)dev->path.mmio.addr == i2c_bus_address[2])
Marshall Dawson59e97b62019-08-15 17:49:11 -060065 return "I2C2";
Martin Rothac41f582020-06-14 17:24:12 -060066 else if ((uintptr_t)dev->path.mmio.addr == i2c_bus_address[3])
Marshall Dawson59e97b62019-08-15 17:49:11 -060067 return "I2C3";
Martin Rothac41f582020-06-14 17:24:12 -060068 else if ((uintptr_t)dev->path.mmio.addr == i2c_bus_address[4])
Marshall Dawson59e97b62019-08-15 17:49:11 -060069 return "I2C4";
Martin Rothac41f582020-06-14 17:24:12 -060070 return NULL;
Martin Roth5c354b92019-04-22 14:55:16 -060071}
72
Furquan Shaikh00296ea2020-04-24 21:33:02 -070073int dw_i2c_soc_dev_to_bus(const struct device *dev)
Martin Roth5c354b92019-04-22 14:55:16 -060074{
Martin Rothac41f582020-06-14 17:24:12 -060075 if ((uintptr_t)dev->path.mmio.addr == i2c_bus_address[2])
Martin Roth5c354b92019-04-22 14:55:16 -060076 return 2;
Martin Rothac41f582020-06-14 17:24:12 -060077 else if ((uintptr_t)dev->path.mmio.addr == i2c_bus_address[3])
Martin Roth5c354b92019-04-22 14:55:16 -060078 return 3;
Martin Rothac41f582020-06-14 17:24:12 -060079 else if ((uintptr_t)dev->path.mmio.addr == i2c_bus_address[4])
Marshall Dawsone2c24f72019-06-20 08:47:58 -060080 return 4;
Martin Roth5c354b92019-04-22 14:55:16 -060081 return -1;
82}
83
Marshall Dawsone2c24f72019-06-20 08:47:58 -060084__weak void mainboard_i2c_override(int bus, uint32_t *pad_settings) { }
85
Martin Roth5c354b92019-04-22 14:55:16 -060086static void dw_i2c_soc_init(bool is_early_init)
87{
88 size_t i;
Marshall Dawsonbc4c9032019-06-11 12:18:20 -060089 const struct soc_amd_picasso_config *config;
Marshall Dawsone2c24f72019-06-20 08:47:58 -060090 uint32_t pad_ctrl;
91 int misc_reg;
Martin Roth5c354b92019-04-22 14:55:16 -060092
Felix Held00058f52020-04-06 23:36:24 +020093 /* config is not NULL; if it was, config_of_soc calls die() internally */
94 config = config_of_soc();
Martin Roth5c354b92019-04-22 14:55:16 -060095
Martin Roth7e78e562019-11-03 23:29:02 -070096 for (i = I2C_MASTER_START_INDEX; i < ARRAY_SIZE(config->i2c); i++) {
Martin Roth5c354b92019-04-22 14:55:16 -060097 const struct dw_i2c_bus_config *cfg = &config->i2c[i];
98
99 if (cfg->early_init != is_early_init)
100 continue;
101
Marshall Dawsone2c24f72019-06-20 08:47:58 -0600102 if (dw_i2c_init(i, cfg)) {
Martin Roth5c354b92019-04-22 14:55:16 -0600103 printk(BIOS_ERR, "Failed to init i2c bus %zd\n", i);
Marshall Dawsone2c24f72019-06-20 08:47:58 -0600104 continue;
105 }
106
107 misc_reg = MISC_I2C0_PAD_CTRL + sizeof(uint32_t) * i;
108 pad_ctrl = misc_read32(misc_reg);
109
110 pad_ctrl &= ~I2C_PAD_CTRL_NG_MASK;
111 pad_ctrl |= I2C_PAD_CTRL_NG_NORMAL;
112
113 pad_ctrl &= ~I2C_PAD_CTRL_RX_SEL_MASK;
114 pad_ctrl |= I2C_PAD_CTRL_RX_SEL_3_3V;
115
116 pad_ctrl &= ~I2C_PAD_CTRL_FALLSLEW_MASK;
117 pad_ctrl |= cfg->speed == I2C_SPEED_STANDARD
118 ? I2C_PAD_CTRL_FALLSLEW_STD
119 : I2C_PAD_CTRL_FALLSLEW_LOW;
120 pad_ctrl |= I2C_PAD_CTRL_FALLSLEW_EN;
121
122 mainboard_i2c_override(i, &pad_ctrl);
123 misc_write32(misc_reg, pad_ctrl);
Martin Roth5c354b92019-04-22 14:55:16 -0600124 }
125}
126
127void i2c_soc_early_init(void)
128{
129 dw_i2c_soc_init(true);
130}
131
132void i2c_soc_init(void)
133{
134 dw_i2c_soc_init(false);
135}
136
Marshall Dawsonbc4c9032019-06-11 12:18:20 -0600137struct device_operations picasso_i2c_mmio_ops = {
Martin Roth5c354b92019-04-22 14:55:16 -0600138 /* TODO(teravest): Move I2C resource info here. */
Nico Huber2f8ba692020-04-05 14:05:24 +0200139 .read_resources = noop_read_resources,
140 .set_resources = noop_set_resources,
Martin Roth5c354b92019-04-22 14:55:16 -0600141 .scan_bus = scan_smbus,
142 .acpi_name = i2c_acpi_name,
Nico Huber68680dd2020-03-31 17:34:52 +0200143 .acpi_fill_ssdt = dw_i2c_acpi_fill_ssdt,
Martin Roth5c354b92019-04-22 14:55:16 -0600144};