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 <stdint.h>
|
||||||
#include <commonlib/helpers.h>
|
#include <commonlib/helpers.h>
|
||||||
#include <drivers/i2c/designware/dw_i2c.h>
|
#include <drivers/i2c/designware/dw_i2c.h>
|
||||||
#include <soc/gpio.h>
|
#include <soc/i2c.h>
|
||||||
#include <arch/acpi_device.h>
|
#include <arch/acpi_device.h>
|
||||||
|
|
||||||
#define MAX_NODES 1
|
#define MAX_NODES 1
|
||||||
|
|
|
@ -18,11 +18,9 @@
|
||||||
#include <device/mmio.h>
|
#include <device/mmio.h>
|
||||||
#include <device/device.h>
|
#include <device/device.h>
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <delay.h>
|
|
||||||
#include <gpio.h>
|
#include <gpio.h>
|
||||||
#include <amdblocks/acpimmio.h>
|
#include <amdblocks/acpimmio.h>
|
||||||
#include <soc/gpio.h>
|
#include <soc/gpio.h>
|
||||||
#include <soc/pci_devs.h>
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "chip.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);
|
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)
|
int gpio_interrupt_status(gpio_t gpio)
|
||||||
{
|
{
|
||||||
uintptr_t gpio_address = gpio_get_address(gpio);
|
uintptr_t gpio_address = gpio_get_address(gpio);
|
||||||
|
|
|
@ -13,12 +13,16 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <device/mmio.h>
|
||||||
#include <arch/acpi.h>
|
#include <arch/acpi.h>
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
|
#include <delay.h>
|
||||||
#include <drivers/i2c/designware/dw_i2c.h>
|
#include <drivers/i2c/designware/dw_i2c.h>
|
||||||
|
#include <amdblocks/acpimmio.h>
|
||||||
#include <soc/iomap.h>
|
#include <soc/iomap.h>
|
||||||
#include <soc/pci_devs.h>
|
#include <soc/pci_devs.h>
|
||||||
#include <soc/southbridge.h>
|
#include <soc/southbridge.h>
|
||||||
|
#include <soc/i2c.h>
|
||||||
#include "chip.h"
|
#include "chip.h"
|
||||||
|
|
||||||
#define I2C_BUS_ADDRESS(x) (I2C_BASE_ADDRESS + I2C_DEVICE_SIZE * (x))
|
#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_name = i2c_acpi_name,
|
||||||
.acpi_fill_ssdt_generator = dw_i2c_acpi_fill_ssdt,
|
.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;
|
uint8_t event;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct soc_amd_i2c_save {
|
|
||||||
uint32_t control_value;
|
|
||||||
uint8_t mux_value;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define GPIO_MASTER_SWITCH 0xFC
|
#define GPIO_MASTER_SWITCH 0xFC
|
||||||
#define GPIO_MASK_STS_EN BIT(28)
|
#define GPIO_MASK_STS_EN BIT(28)
|
||||||
#define GPIO_INTERRUPT_EN BIT(30)
|
#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_TOTAL_PINS 149
|
||||||
#define GPIO_PIN_IN (1 << 0) /* for byte access */
|
#define GPIO_PIN_IN (1 << 0) /* for byte access */
|
||||||
#define GPIO_PIN_OUT (1 << 6) /* 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_147 147
|
||||||
#define GPIO_148 148
|
#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_HIGH 0
|
||||||
#define GPIO_SCL_LOW GPIO_OUTPUT_ENABLE
|
#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_I2C1_SDA 0
|
||||||
#define GPIO_148_IOMUX_GPIOxx 1
|
#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 {
|
enum {
|
||||||
GEVENT_0,
|
GEVENT_0,
|
||||||
GEVENT_1,
|
GEVENT_1,
|
||||||
|
@ -599,7 +574,6 @@ uintptr_t gpio_get_address(gpio_t gpio_num);
|
||||||
* @return none
|
* @return none
|
||||||
*/
|
*/
|
||||||
void sb_program_gpios(const struct soc_amd_gpio *gpio_list_ptr, size_t size);
|
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. */
|
/* Return the interrupt status and clear if set. */
|
||||||
int gpio_interrupt_status(gpio_t gpio);
|
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