soc/amd/stoneyridge: Move I2C bus clear out of gpio.c
Relocate the I2C bus reset code from gpio.c to i2c.c. When it first went in, gpio.c was a natural location due to the nature of the algorithm. This is preparation for moving most of gpio.c to common code. Change-Id: I3b2d8e1b54e7c5929220d763bd99fe01b0636aaa Signed-off-by: Marshall Dawson <marshalldawson3rd@gmail.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/32650 Reviewed-by: Martin Roth <martinroth@google.com> Reviewed-by: Richard Spiegel <richard.spiegel@silverbackltd.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
parent
69486cac74
commit
f42344a389
|
@ -20,7 +20,7 @@
|
|||
#include <stdint.h>
|
||||
#include <commonlib/helpers.h>
|
||||
#include <drivers/i2c/designware/dw_i2c.h>
|
||||
#include <soc/gpio.h>
|
||||
#include <soc/i2c.h>
|
||||
#include <arch/acpi_device.h>
|
||||
|
||||
#define MAX_NODES 1
|
||||
|
|
|
@ -18,11 +18,9 @@
|
|||
#include <device/mmio.h>
|
||||
#include <device/device.h>
|
||||
#include <console/console.h>
|
||||
#include <delay.h>
|
||||
#include <gpio.h>
|
||||
#include <amdblocks/acpimmio.h>
|
||||
#include <soc/gpio.h>
|
||||
#include <soc/pci_devs.h>
|
||||
#include <assert.h>
|
||||
#include "chip.h"
|
||||
|
||||
|
@ -326,101 +324,6 @@ void sb_program_gpios(const struct soc_amd_gpio *gpio_list_ptr, size_t size)
|
|||
edge_level, mask);
|
||||
}
|
||||
|
||||
/*
|
||||
* I2C pins are open drain with external pull up, so in order to bit bang them
|
||||
* all, SCL pins must become GPIO inputs with no pull, then they need to be
|
||||
* toggled between input-no-pull and output-low. This table is for the initial
|
||||
* conversion of all SCL pins to input with no pull.
|
||||
*/
|
||||
static const struct soc_amd_gpio i2c_2_gpi[] = {
|
||||
PAD_GPI(I2C0_SCL_PIN, PULL_NONE),
|
||||
PAD_GPI(I2C1_SCL_PIN, PULL_NONE),
|
||||
PAD_GPI(I2C2_SCL_PIN, PULL_NONE),
|
||||
PAD_GPI(I2C3_SCL_PIN, PULL_NONE),
|
||||
};
|
||||
#define saved_pins_count ARRAY_SIZE(i2c_2_gpi)
|
||||
|
||||
/*
|
||||
* To program I2C pins without destroying their programming, the registers
|
||||
* that will be changed need to be saved first.
|
||||
*/
|
||||
static void save_i2c_pin_registers(uint8_t gpio,
|
||||
struct soc_amd_i2c_save *save_table)
|
||||
{
|
||||
uint32_t *gpio_ptr;
|
||||
|
||||
gpio_ptr = (uint32_t *)gpio_get_address(gpio);
|
||||
save_table->mux_value = iomux_read8(gpio);
|
||||
save_table->control_value = read32(gpio_ptr);
|
||||
}
|
||||
|
||||
static void restore_i2c_pin_registers(uint8_t gpio,
|
||||
struct soc_amd_i2c_save *save_table)
|
||||
{
|
||||
uint32_t *gpio_ptr;
|
||||
|
||||
gpio_ptr = (uint32_t *)gpio_get_address(gpio);
|
||||
iomux_write8(gpio, save_table->mux_value);
|
||||
iomux_read8(gpio);
|
||||
write32(gpio_ptr, save_table->control_value);
|
||||
read32(gpio_ptr);
|
||||
}
|
||||
|
||||
/* Slaves to be reset are controlled by devicetree register i2c_scl_reset */
|
||||
void sb_reset_i2c_slaves(void)
|
||||
{
|
||||
const struct soc_amd_stoneyridge_config *cfg;
|
||||
const struct device *dev = pcidev_path_on_root(GNB_DEVFN);
|
||||
struct soc_amd_i2c_save save_table[saved_pins_count];
|
||||
uint8_t i, j, control;
|
||||
|
||||
if (!dev || !dev->chip_info)
|
||||
return;
|
||||
cfg = dev->chip_info;
|
||||
control = cfg->i2c_scl_reset & GPIO_I2C_MASK;
|
||||
if (control == 0)
|
||||
return;
|
||||
|
||||
/* Save and reprogram I2C SCL pins */
|
||||
for (i = 0; i < saved_pins_count; i++)
|
||||
save_i2c_pin_registers(i2c_2_gpi[i].gpio, &save_table[i]);
|
||||
sb_program_gpios(i2c_2_gpi, saved_pins_count);
|
||||
|
||||
/*
|
||||
* Toggle SCL back and forth 9 times under 100KHz. A single read is
|
||||
* needed after the writes to force the posted write to complete.
|
||||
*/
|
||||
for (j = 0; j < 9; j++) {
|
||||
if (control & GPIO_I2C0_SCL)
|
||||
write32((uint32_t *)GPIO_I2C0_ADDRESS, GPIO_SCL_LOW);
|
||||
if (control & GPIO_I2C1_SCL)
|
||||
write32((uint32_t *)GPIO_I2C1_ADDRESS, GPIO_SCL_LOW);
|
||||
if (control & GPIO_I2C2_SCL)
|
||||
write32((uint32_t *)GPIO_I2C2_ADDRESS, GPIO_SCL_LOW);
|
||||
if (control & GPIO_I2C3_SCL)
|
||||
write32((uint32_t *)GPIO_I2C3_ADDRESS, GPIO_SCL_LOW);
|
||||
|
||||
read32((uint32_t *)GPIO_I2C3_ADDRESS); /* Flush posted write */
|
||||
udelay(4); /* 4usec gets 85KHz for 1 pin, 70KHz for 4 pins */
|
||||
|
||||
if (control & GPIO_I2C0_SCL)
|
||||
write32((uint32_t *)GPIO_I2C0_ADDRESS, GPIO_SCL_HIGH);
|
||||
if (control & GPIO_I2C1_SCL)
|
||||
write32((uint32_t *)GPIO_I2C1_ADDRESS, GPIO_SCL_HIGH);
|
||||
if (control & GPIO_I2C2_SCL)
|
||||
write32((uint32_t *)GPIO_I2C2_ADDRESS, GPIO_SCL_HIGH);
|
||||
if (control & GPIO_I2C3_SCL)
|
||||
write32((uint32_t *)GPIO_I2C3_ADDRESS, GPIO_SCL_HIGH);
|
||||
|
||||
read32((uint32_t *)GPIO_I2C3_ADDRESS); /* Flush posted write */
|
||||
udelay(4);
|
||||
}
|
||||
|
||||
/* Restore I2C pins. */
|
||||
for (i = 0; i < saved_pins_count; i++)
|
||||
restore_i2c_pin_registers(i2c_2_gpi[i].gpio, &save_table[i]);
|
||||
}
|
||||
|
||||
int gpio_interrupt_status(gpio_t gpio)
|
||||
{
|
||||
uintptr_t gpio_address = gpio_get_address(gpio);
|
||||
|
|
|
@ -13,12 +13,16 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <device/mmio.h>
|
||||
#include <arch/acpi.h>
|
||||
#include <console/console.h>
|
||||
#include <delay.h>
|
||||
#include <drivers/i2c/designware/dw_i2c.h>
|
||||
#include <amdblocks/acpimmio.h>
|
||||
#include <soc/iomap.h>
|
||||
#include <soc/pci_devs.h>
|
||||
#include <soc/southbridge.h>
|
||||
#include <soc/i2c.h>
|
||||
#include "chip.h"
|
||||
|
||||
#define I2C_BUS_ADDRESS(x) (I2C_BASE_ADDRESS + I2C_DEVICE_SIZE * (x))
|
||||
|
@ -140,3 +144,98 @@ struct device_operations stoneyridge_i2c_mmio_ops = {
|
|||
.acpi_name = i2c_acpi_name,
|
||||
.acpi_fill_ssdt_generator = dw_i2c_acpi_fill_ssdt,
|
||||
};
|
||||
|
||||
/*
|
||||
* I2C pins are open drain with external pull up, so in order to bit bang them
|
||||
* all, SCL pins must become GPIO inputs with no pull, then they need to be
|
||||
* toggled between input-no-pull and output-low. This table is for the initial
|
||||
* conversion of all SCL pins to input with no pull.
|
||||
*/
|
||||
static const struct soc_amd_gpio i2c_2_gpi[] = {
|
||||
PAD_GPI(I2C0_SCL_PIN, PULL_NONE),
|
||||
PAD_GPI(I2C1_SCL_PIN, PULL_NONE),
|
||||
PAD_GPI(I2C2_SCL_PIN, PULL_NONE),
|
||||
PAD_GPI(I2C3_SCL_PIN, PULL_NONE),
|
||||
};
|
||||
#define saved_pins_count ARRAY_SIZE(i2c_2_gpi)
|
||||
|
||||
/*
|
||||
* To program I2C pins without destroying their programming, the registers
|
||||
* that will be changed need to be saved first.
|
||||
*/
|
||||
static void save_i2c_pin_registers(uint8_t gpio,
|
||||
struct soc_amd_i2c_save *save_table)
|
||||
{
|
||||
uint32_t *gpio_ptr;
|
||||
|
||||
gpio_ptr = (uint32_t *)gpio_get_address(gpio);
|
||||
save_table->mux_value = iomux_read8(gpio);
|
||||
save_table->control_value = read32(gpio_ptr);
|
||||
}
|
||||
|
||||
static void restore_i2c_pin_registers(uint8_t gpio,
|
||||
struct soc_amd_i2c_save *save_table)
|
||||
{
|
||||
uint32_t *gpio_ptr;
|
||||
|
||||
gpio_ptr = (uint32_t *)gpio_get_address(gpio);
|
||||
iomux_write8(gpio, save_table->mux_value);
|
||||
iomux_read8(gpio);
|
||||
write32(gpio_ptr, save_table->control_value);
|
||||
read32(gpio_ptr);
|
||||
}
|
||||
|
||||
/* Slaves to be reset are controlled by devicetree register i2c_scl_reset */
|
||||
void sb_reset_i2c_slaves(void)
|
||||
{
|
||||
const struct soc_amd_stoneyridge_config *cfg;
|
||||
const struct device *dev = pcidev_path_on_root(GNB_DEVFN);
|
||||
struct soc_amd_i2c_save save_table[saved_pins_count];
|
||||
uint8_t i, j, control;
|
||||
|
||||
if (!dev || !dev->chip_info)
|
||||
return;
|
||||
cfg = dev->chip_info;
|
||||
control = cfg->i2c_scl_reset & GPIO_I2C_MASK;
|
||||
if (control == 0)
|
||||
return;
|
||||
|
||||
/* Save and reprogram I2C SCL pins */
|
||||
for (i = 0; i < saved_pins_count; i++)
|
||||
save_i2c_pin_registers(i2c_2_gpi[i].gpio, &save_table[i]);
|
||||
sb_program_gpios(i2c_2_gpi, saved_pins_count);
|
||||
|
||||
/*
|
||||
* Toggle SCL back and forth 9 times under 100KHz. A single read is
|
||||
* needed after the writes to force the posted write to complete.
|
||||
*/
|
||||
for (j = 0; j < 9; j++) {
|
||||
if (control & GPIO_I2C0_SCL)
|
||||
write32((uint32_t *)GPIO_I2C0_ADDRESS, GPIO_SCL_LOW);
|
||||
if (control & GPIO_I2C1_SCL)
|
||||
write32((uint32_t *)GPIO_I2C1_ADDRESS, GPIO_SCL_LOW);
|
||||
if (control & GPIO_I2C2_SCL)
|
||||
write32((uint32_t *)GPIO_I2C2_ADDRESS, GPIO_SCL_LOW);
|
||||
if (control & GPIO_I2C3_SCL)
|
||||
write32((uint32_t *)GPIO_I2C3_ADDRESS, GPIO_SCL_LOW);
|
||||
|
||||
read32((uint32_t *)GPIO_I2C3_ADDRESS); /* Flush posted write */
|
||||
udelay(4); /* 4usec gets 85KHz for 1 pin, 70KHz for 4 pins */
|
||||
|
||||
if (control & GPIO_I2C0_SCL)
|
||||
write32((uint32_t *)GPIO_I2C0_ADDRESS, GPIO_SCL_HIGH);
|
||||
if (control & GPIO_I2C1_SCL)
|
||||
write32((uint32_t *)GPIO_I2C1_ADDRESS, GPIO_SCL_HIGH);
|
||||
if (control & GPIO_I2C2_SCL)
|
||||
write32((uint32_t *)GPIO_I2C2_ADDRESS, GPIO_SCL_HIGH);
|
||||
if (control & GPIO_I2C3_SCL)
|
||||
write32((uint32_t *)GPIO_I2C3_ADDRESS, GPIO_SCL_HIGH);
|
||||
|
||||
read32((uint32_t *)GPIO_I2C3_ADDRESS); /* Flush posted write */
|
||||
udelay(4);
|
||||
}
|
||||
|
||||
/* Restore I2C pins. */
|
||||
for (i = 0; i < saved_pins_count; i++)
|
||||
restore_i2c_pin_registers(i2c_2_gpi[i].gpio, &save_table[i]);
|
||||
}
|
||||
|
|
|
@ -36,21 +36,10 @@ struct soc_amd_event {
|
|||
uint8_t event;
|
||||
};
|
||||
|
||||
struct soc_amd_i2c_save {
|
||||
uint32_t control_value;
|
||||
uint8_t mux_value;
|
||||
};
|
||||
|
||||
#define GPIO_MASTER_SWITCH 0xFC
|
||||
#define GPIO_MASK_STS_EN BIT(28)
|
||||
#define GPIO_INTERRUPT_EN BIT(30)
|
||||
|
||||
#define GPIO_I2C0_SCL BIT(0)
|
||||
#define GPIO_I2C1_SCL BIT(1)
|
||||
#define GPIO_I2C2_SCL BIT(2)
|
||||
#define GPIO_I2C3_SCL BIT(3)
|
||||
#define GPIO_I2C_MASK (BIT(0) | BIT(1) | BIT(2) | BIT(3))
|
||||
|
||||
#define GPIO_TOTAL_PINS 149
|
||||
#define GPIO_PIN_IN (1 << 0) /* for byte access */
|
||||
#define GPIO_PIN_OUT (1 << 6) /* for byte access */
|
||||
|
@ -186,15 +175,6 @@ struct soc_amd_i2c_save {
|
|||
#define GPIO_147 147
|
||||
#define GPIO_148 148
|
||||
|
||||
#define I2C0_SCL_PIN GPIO_145
|
||||
#define I2C1_SCL_PIN GPIO_147
|
||||
#define I2C2_SCL_PIN GPIO_113
|
||||
#define I2C3_SCL_PIN GPIO_19
|
||||
|
||||
#define GPIO_I2C0_ADDRESS GPIO_BANK2_CONTROL(I2C0_SCL_PIN)
|
||||
#define GPIO_I2C1_ADDRESS GPIO_BANK2_CONTROL(I2C1_SCL_PIN)
|
||||
#define GPIO_I2C2_ADDRESS GPIO_BANK1_CONTROL(I2C2_SCL_PIN)
|
||||
#define GPIO_I2C3_ADDRESS GPIO_BANK0_CONTROL(I2C3_SCL_PIN)
|
||||
#define GPIO_SCL_HIGH 0
|
||||
#define GPIO_SCL_LOW GPIO_OUTPUT_ENABLE
|
||||
|
||||
|
@ -373,11 +353,6 @@ struct soc_amd_i2c_save {
|
|||
#define GPIO_148_IOMUX_I2C1_SDA 0
|
||||
#define GPIO_148_IOMUX_GPIOxx 1
|
||||
|
||||
#define I2C0_SCL_PIN_IOMUX_GPIOxx GPIO_145_IOMUX_GPIOxx
|
||||
#define I2C1_SCL_PIN_IOMUX_GPIOxx GPIO_147_IOMUX_GPIOxx
|
||||
#define I2C2_SCL_PIN_IOMUX_GPIOxx GPIO_113_IOMUX_GPIOxx
|
||||
#define I2C3_SCL_PIN_IOMUX_GPIOxx GPIO_19_IOMUX_GPIOxx
|
||||
|
||||
enum {
|
||||
GEVENT_0,
|
||||
GEVENT_1,
|
||||
|
@ -599,7 +574,6 @@ uintptr_t gpio_get_address(gpio_t gpio_num);
|
|||
* @return none
|
||||
*/
|
||||
void sb_program_gpios(const struct soc_amd_gpio *gpio_list_ptr, size_t size);
|
||||
void sb_reset_i2c_slaves(void);
|
||||
|
||||
/* Return the interrupt status and clear if set. */
|
||||
int gpio_interrupt_status(gpio_t gpio);
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2018 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __STONEYRIDGE_I2C_H__
|
||||
#define __STONEYRIDGE_I2C_H__
|
||||
|
||||
#include <soc/gpio.h>
|
||||
|
||||
struct soc_amd_i2c_save {
|
||||
uint32_t control_value;
|
||||
uint8_t mux_value;
|
||||
};
|
||||
|
||||
#define GPIO_I2C0_SCL BIT(0)
|
||||
#define GPIO_I2C1_SCL BIT(1)
|
||||
#define GPIO_I2C2_SCL BIT(2)
|
||||
#define GPIO_I2C3_SCL BIT(3)
|
||||
#define GPIO_I2C_MASK (BIT(0) | BIT(1) | BIT(2) | BIT(3))
|
||||
|
||||
#define I2C0_SCL_PIN GPIO_145
|
||||
#define I2C1_SCL_PIN GPIO_147
|
||||
#define I2C2_SCL_PIN GPIO_113
|
||||
#define I2C3_SCL_PIN GPIO_19
|
||||
|
||||
#define GPIO_I2C0_ADDRESS GPIO_BANK2_CONTROL(I2C0_SCL_PIN)
|
||||
#define GPIO_I2C1_ADDRESS GPIO_BANK2_CONTROL(I2C1_SCL_PIN)
|
||||
#define GPIO_I2C2_ADDRESS GPIO_BANK1_CONTROL(I2C2_SCL_PIN)
|
||||
#define GPIO_I2C3_ADDRESS GPIO_BANK0_CONTROL(I2C3_SCL_PIN)
|
||||
|
||||
#define I2C0_SCL_PIN_IOMUX_GPIOxx GPIO_145_IOMUX_GPIOxx
|
||||
#define I2C1_SCL_PIN_IOMUX_GPIOxx GPIO_147_IOMUX_GPIOxx
|
||||
#define I2C2_SCL_PIN_IOMUX_GPIOxx GPIO_113_IOMUX_GPIOxx
|
||||
#define I2C3_SCL_PIN_IOMUX_GPIOxx GPIO_19_IOMUX_GPIOxx
|
||||
|
||||
void sb_reset_i2c_slaves(void);
|
||||
|
||||
#endif /* __STONEYRIDGE_I2C_H__ */
|
Loading…
Reference in New Issue