Commit 2f60dd50 authored by Luben Tuikov's avatar Luben Tuikov Committed by Alex Deucher
Browse files

drm/amd: Expose the FRU SMU I2C bus



Expose both SMU I2C buses. Some boards use the same bus for both the RAS
and FRU EEPROMs and others use different buses.  This enables the
additional I2C bus and sets the right buses to use for RAS and FRU EEPROM
access.

Cc: Roy Sun <Roy.Sun@amd.com>
Co-developed-by: default avatarAlex Deucher <Alexander.Deucher@amd.com>
Signed-off-by: default avatarLuben Tuikov <luben.tuikov@amd.com>
Reviewed-by: default avatarAlex Deucher <Alexander.Deucher@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent f06d9e4e
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -75,7 +75,7 @@ static int amdgpu_fru_read_eeprom(struct amdgpu_device *adev, uint32_t addrptr,
{
	int ret, size;

	ret = amdgpu_eeprom_read(&adev->pm.smu_i2c, addrptr, buff, 1);
	ret = amdgpu_eeprom_read(adev->pm.fru_eeprom_i2c_bus, addrptr, buff, 1);
	if (ret < 1) {
		DRM_WARN("FRU: Failed to get size field");
		return ret;
@@ -86,7 +86,7 @@ static int amdgpu_fru_read_eeprom(struct amdgpu_device *adev, uint32_t addrptr,
	 */
	size = buff[0] - I2C_PRODUCT_INFO_OFFSET;

	ret = amdgpu_eeprom_read(&adev->pm.smu_i2c, addrptr + 1, buff, size);
	ret = amdgpu_eeprom_read(adev->pm.fru_eeprom_i2c_bus, addrptr + 1, buff, size);
	if (ret < 1) {
		DRM_WARN("FRU: Failed to get data field");
		return ret;
@@ -109,7 +109,7 @@ int amdgpu_fru_get_product_info(struct amdgpu_device *adev)
		offset = 0;

	/* If algo exists, it means that the i2c_adapter's initialized */
	if (!adev->pm.smu_i2c.algo) {
	if (!adev->pm.fru_eeprom_i2c_bus || !adev->pm.fru_eeprom_i2c_bus->algo) {
		DRM_WARN("Cannot access FRU, EEPROM accessor not initialized");
		return -ENODEV;
	}
+7 −7
Original line number Diff line number Diff line
@@ -194,7 +194,7 @@ static int __write_table_header(struct amdgpu_ras_eeprom_control *control)

	/* i2c may be unstable in gpu reset */
	down_read(&adev->reset_sem);
	res = amdgpu_eeprom_write(&adev->pm.smu_i2c,
	res = amdgpu_eeprom_write(adev->pm.ras_eeprom_i2c_bus,
				  control->i2c_address +
				  control->ras_header_offset,
				  buf, RAS_TABLE_HEADER_SIZE);
@@ -389,7 +389,7 @@ static int __amdgpu_ras_eeprom_write(struct amdgpu_ras_eeprom_control *control,
	/* i2c may be unstable in gpu reset */
	down_read(&adev->reset_sem);
	buf_size = num * RAS_TABLE_RECORD_SIZE;
	res = amdgpu_eeprom_write(&adev->pm.smu_i2c,
	res = amdgpu_eeprom_write(adev->pm.ras_eeprom_i2c_bus,
				  control->i2c_address +
				  RAS_INDEX_TO_OFFSET(control, fri),
				  buf, buf_size);
@@ -548,7 +548,7 @@ amdgpu_ras_eeprom_update_header(struct amdgpu_ras_eeprom_control *control)
	}

	down_read(&adev->reset_sem);
	res = amdgpu_eeprom_read(&adev->pm.smu_i2c,
	res = amdgpu_eeprom_read(adev->pm.ras_eeprom_i2c_bus,
				 control->i2c_address +
				 control->ras_record_offset,
				 buf, buf_size);
@@ -644,7 +644,7 @@ static int __amdgpu_ras_eeprom_read(struct amdgpu_ras_eeprom_control *control,
	/* i2c may be unstable in gpu reset */
	down_read(&adev->reset_sem);
	buf_size = num * RAS_TABLE_RECORD_SIZE;
	res = amdgpu_eeprom_read(&adev->pm.smu_i2c,
	res = amdgpu_eeprom_read(adev->pm.ras_eeprom_i2c_bus,
				 control->i2c_address +
				 RAS_INDEX_TO_OFFSET(control, fri),
				 buf, buf_size);
@@ -1009,7 +1009,7 @@ static int __verify_ras_table_checksum(struct amdgpu_ras_eeprom_control *control
		return -ENOMEM;
	}

	res = amdgpu_eeprom_read(&adev->pm.smu_i2c,
	res = amdgpu_eeprom_read(adev->pm.ras_eeprom_i2c_bus,
				 control->i2c_address +
				 control->ras_header_offset,
				 buf, buf_size);
@@ -1045,7 +1045,7 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control,
		return 0;

	/* Verify i2c adapter is initialized */
	if (!adev->pm.smu_i2c.algo)
	if (!adev->pm.ras_eeprom_i2c_bus || !adev->pm.ras_eeprom_i2c_bus->algo)
		return -ENOENT;

	if (!__get_eeprom_i2c_addr(adev, control))
@@ -1057,7 +1057,7 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control,
	mutex_init(&control->ras_tbl_mutex);

	/* Read the table header from EEPROM address */
	res = amdgpu_eeprom_read(&adev->pm.smu_i2c,
	res = amdgpu_eeprom_read(adev->pm.ras_eeprom_i2c_bus,
				 control->i2c_address + control->ras_header_offset,
				 buf, RAS_TABLE_HEADER_SIZE);
	if (res < RAS_TABLE_HEADER_SIZE) {
+53 −27
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@

#include "smu_v11_0_i2c.h"
#include "amdgpu.h"
#include "amdgpu_dpm.h"
#include "soc15_common.h"
#include <drm/drm_fixed.h>
#include <drm/drm_drv.h>
@@ -43,11 +44,10 @@

#define I2C_X_RESTART         BIT(31)

#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c))

static void smu_v11_0_i2c_set_clock_gating(struct i2c_adapter *control, bool en)
{
	struct amdgpu_device *adev = to_amdgpu_device(control);
	struct amdgpu_smu_i2c_bus *smu_i2c = i2c_get_adapdata(control);
	struct amdgpu_device *adev = smu_i2c->adev;
	uint32_t reg = RREG32_SOC15(SMUIO, 0, mmSMUIO_PWRMGT);

	reg = REG_SET_FIELD(reg, SMUIO_PWRMGT, i2c_clk_gate_en, en ? 1 : 0);
@@ -75,7 +75,8 @@ static void smu_v11_0_i2c_set_clock_gating(struct i2c_adapter *control, bool en)

static int smu_v11_0_i2c_enable(struct i2c_adapter *control, bool enable)
{
	struct amdgpu_device *adev = to_amdgpu_device(control);
	struct amdgpu_smu_i2c_bus *smu_i2c = i2c_get_adapdata(control);
	struct amdgpu_device *adev = smu_i2c->adev;

	WREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_ENABLE, enable ? 1 : 0);

@@ -100,7 +101,8 @@ static int smu_v11_0_i2c_enable(struct i2c_adapter *control, bool enable)

static void smu_v11_0_i2c_clear_status(struct i2c_adapter *control)
{
	struct amdgpu_device *adev = to_amdgpu_device(control);
	struct amdgpu_smu_i2c_bus *smu_i2c = i2c_get_adapdata(control);
	struct amdgpu_device *adev = smu_i2c->adev;
	/* do */
	{
		RREG32_SOC15(SMUIO, 0, mmCKSVII2C_IC_CLR_INTR);
@@ -110,7 +112,8 @@ static void smu_v11_0_i2c_clear_status(struct i2c_adapter *control)

static void smu_v11_0_i2c_configure(struct i2c_adapter *control)
{
	struct amdgpu_device *adev = to_amdgpu_device(control);
	struct amdgpu_smu_i2c_bus *smu_i2c = i2c_get_adapdata(control);
	struct amdgpu_device *adev = smu_i2c->adev;
	uint32_t reg = 0;

	reg = REG_SET_FIELD(reg, CKSVII2C_IC_CON, IC_SLAVE_DISABLE, 1);
@@ -131,7 +134,8 @@ static void smu_v11_0_i2c_configure(struct i2c_adapter *control)

static void smu_v11_0_i2c_set_clock(struct i2c_adapter *control)
{
	struct amdgpu_device *adev = to_amdgpu_device(control);
	struct amdgpu_smu_i2c_bus *smu_i2c = i2c_get_adapdata(control);
	struct amdgpu_device *adev = smu_i2c->adev;

	/*
	 * Standard mode speed, These values are taken from SMUIO MAS,
@@ -154,7 +158,8 @@ static void smu_v11_0_i2c_set_clock(struct i2c_adapter *control)

static void smu_v11_0_i2c_set_address(struct i2c_adapter *control, u16 address)
{
	struct amdgpu_device *adev = to_amdgpu_device(control);
	struct amdgpu_smu_i2c_bus *smu_i2c = i2c_get_adapdata(control);
	struct amdgpu_device *adev = smu_i2c->adev;

	/* The IC_TAR::IC_TAR field is 10-bits wide.
	 * It takes a 7-bit or 10-bit addresses as an address,
@@ -165,7 +170,8 @@ static void smu_v11_0_i2c_set_address(struct i2c_adapter *control, u16 address)

static uint32_t smu_v11_0_i2c_poll_tx_status(struct i2c_adapter *control)
{
	struct amdgpu_device *adev = to_amdgpu_device(control);
	struct amdgpu_smu_i2c_bus *smu_i2c = i2c_get_adapdata(control);
	struct amdgpu_device *adev = smu_i2c->adev;
	uint32_t ret = I2C_OK;
	uint32_t reg, reg_c_tx_abrt_source;

@@ -216,7 +222,8 @@ static uint32_t smu_v11_0_i2c_poll_tx_status(struct i2c_adapter *control)

static uint32_t smu_v11_0_i2c_poll_rx_status(struct i2c_adapter *control)
{
	struct amdgpu_device *adev = to_amdgpu_device(control);
	struct amdgpu_smu_i2c_bus *smu_i2c = i2c_get_adapdata(control);
	struct amdgpu_device *adev = smu_i2c->adev;
	uint32_t ret = I2C_OK;
	uint32_t reg_ic_status, reg_c_tx_abrt_source;

@@ -262,7 +269,8 @@ static uint32_t smu_v11_0_i2c_transmit(struct i2c_adapter *control,
				       u16 address, u8 *data,
				       u32 numbytes, u32 i2c_flag)
{
	struct amdgpu_device *adev = to_amdgpu_device(control);
	struct amdgpu_smu_i2c_bus *smu_i2c = i2c_get_adapdata(control);
	struct amdgpu_device *adev = smu_i2c->adev;
	u32 bytes_sent, reg, ret = I2C_OK;
	unsigned long  timeout_counter;

@@ -360,7 +368,8 @@ static uint32_t smu_v11_0_i2c_receive(struct i2c_adapter *control,
				      u16 address, u8 *data,
				      u32 numbytes, u32 i2c_flag)
{
	struct amdgpu_device *adev = to_amdgpu_device(control);
	struct amdgpu_smu_i2c_bus *smu_i2c = i2c_get_adapdata(control);
	struct amdgpu_device *adev = smu_i2c->adev;
	uint32_t bytes_received, ret = I2C_OK;

	bytes_received = 0;
@@ -431,7 +440,8 @@ static uint32_t smu_v11_0_i2c_receive(struct i2c_adapter *control,

static void smu_v11_0_i2c_abort(struct i2c_adapter *control)
{
	struct amdgpu_device *adev = to_amdgpu_device(control);
	struct amdgpu_smu_i2c_bus *smu_i2c = i2c_get_adapdata(control);
	struct amdgpu_device *adev = smu_i2c->adev;
	uint32_t reg = 0;

	/* Enable I2C engine; */
@@ -447,7 +457,8 @@ static void smu_v11_0_i2c_abort(struct i2c_adapter *control)

static bool smu_v11_0_i2c_activity_done(struct i2c_adapter *control)
{
	struct amdgpu_device *adev = to_amdgpu_device(control);
	struct amdgpu_smu_i2c_bus *smu_i2c = i2c_get_adapdata(control);
	struct amdgpu_device *adev = smu_i2c->adev;

	const uint32_t IDLE_TIMEOUT = 1024;
	uint32_t timeout_count = 0;
@@ -508,7 +519,8 @@ static void smu_v11_0_i2c_init(struct i2c_adapter *control)

static void smu_v11_0_i2c_fini(struct i2c_adapter *control)
{
	struct amdgpu_device *adev = to_amdgpu_device(control);
	struct amdgpu_smu_i2c_bus *smu_i2c = i2c_get_adapdata(control);
	struct amdgpu_device *adev = smu_i2c->adev;
	u32 status, enable, en_stat;
	int res;

@@ -543,7 +555,8 @@ static void smu_v11_0_i2c_fini(struct i2c_adapter *control)

static bool smu_v11_0_i2c_bus_lock(struct i2c_adapter *control)
{
	struct amdgpu_device *adev = to_amdgpu_device(control);
	struct amdgpu_smu_i2c_bus *smu_i2c = i2c_get_adapdata(control);
	struct amdgpu_device *adev = smu_i2c->adev;

	/* Send  PPSMC_MSG_RequestI2CBus */
	if (!amdgpu_dpm_smu_i2c_bus_access(adev, true))
@@ -554,7 +567,8 @@ static bool smu_v11_0_i2c_bus_lock(struct i2c_adapter *control)

static bool smu_v11_0_i2c_bus_unlock(struct i2c_adapter *control)
{
	struct amdgpu_device *adev = to_amdgpu_device(control);
	struct amdgpu_smu_i2c_bus *smu_i2c = i2c_get_adapdata(control);
	struct amdgpu_device *adev = smu_i2c->adev;

	/* Send  PPSMC_MSG_ReleaseI2CBus */
	if (!amdgpu_dpm_smu_i2c_bus_access(adev, false))
@@ -594,9 +608,10 @@ static uint32_t smu_v11_0_i2c_write_data(struct i2c_adapter *control,

static void lock_bus(struct i2c_adapter *i2c, unsigned int flags)
{
	struct amdgpu_device *adev = to_amdgpu_device(i2c);
	struct amdgpu_smu_i2c_bus *smu_i2c = i2c_get_adapdata(i2c);
	struct amdgpu_device *adev = smu_i2c->adev;

	mutex_lock(&adev->pm.smu_i2c_mutex);
	mutex_lock(&smu_i2c->mutex);
	if (!smu_v11_0_i2c_bus_lock(i2c))
		DRM_ERROR("Failed to lock the bus from SMU");
	else
@@ -611,13 +626,14 @@ static int trylock_bus(struct i2c_adapter *i2c, unsigned int flags)

static void unlock_bus(struct i2c_adapter *i2c, unsigned int flags)
{
	struct amdgpu_device *adev = to_amdgpu_device(i2c);
	struct amdgpu_smu_i2c_bus *smu_i2c = i2c_get_adapdata(i2c);
	struct amdgpu_device *adev = smu_i2c->adev;

	if (!smu_v11_0_i2c_bus_unlock(i2c))
		DRM_ERROR("Failed to unlock the bus from SMU");
	else
		adev->pm.bus_locked = false;
	mutex_unlock(&adev->pm.smu_i2c_mutex);
	mutex_unlock(&smu_i2c->mutex);
}

static const struct i2c_lock_operations smu_v11_0_i2c_i2c_lock_ops = {
@@ -706,19 +722,26 @@ static const struct i2c_adapter_quirks smu_v11_0_i2c_control_quirks = {
	.flags = I2C_AQ_NO_ZERO_LEN,
};

int smu_v11_0_i2c_control_init(struct i2c_adapter *control)
int smu_v11_0_i2c_control_init(struct amdgpu_device *adev)
{
	struct amdgpu_device *adev = to_amdgpu_device(control);
	struct amdgpu_smu_i2c_bus *smu_i2c = &adev->pm.smu_i2c[0];
	struct i2c_adapter *control = &smu_i2c->adapter;
	int res;

	mutex_init(&adev->pm.smu_i2c_mutex);
	smu_i2c->adev = adev;
	smu_i2c->port = 0;
	mutex_init(&smu_i2c->mutex);
	control->owner = THIS_MODULE;
	control->class = I2C_CLASS_HWMON;
	control->dev.parent = &adev->pdev->dev;
	control->algo = &smu_v11_0_i2c_algo;
	snprintf(control->name, sizeof(control->name), "AMDGPU SMU");
	snprintf(control->name, sizeof(control->name), "AMDGPU SMU 0");
	control->lock_ops = &smu_v11_0_i2c_i2c_lock_ops;
	control->quirks = &smu_v11_0_i2c_control_quirks;
	i2c_set_adapdata(control, smu_i2c);

	adev->pm.ras_eeprom_i2c_bus = &adev->pm.smu_i2c[0].adapter;
	adev->pm.fru_eeprom_i2c_bus = NULL;

	res = i2c_add_adapter(control);
	if (res)
@@ -727,9 +750,12 @@ int smu_v11_0_i2c_control_init(struct i2c_adapter *control)
	return res;
}

void smu_v11_0_i2c_control_fini(struct i2c_adapter *control)
void smu_v11_0_i2c_control_fini(struct amdgpu_device *adev)
{
	struct i2c_adapter *control = adev->pm.ras_eeprom_i2c_bus;

	i2c_del_adapter(control);
	adev->pm.ras_eeprom_i2c_bus = NULL;
}

/*
+3 −3
Original line number Diff line number Diff line
@@ -26,9 +26,9 @@

#include <linux/types.h>

struct i2c_adapter;
struct amdgpu_device;

int smu_v11_0_i2c_control_init(struct i2c_adapter *control);
void smu_v11_0_i2c_control_fini(struct i2c_adapter *control);
int smu_v11_0_i2c_control_init(struct amdgpu_device *adev);
void smu_v11_0_i2c_control_fini(struct amdgpu_device *adev);

#endif
+12 −2
Original line number Diff line number Diff line
@@ -284,6 +284,15 @@ enum ip_power_state {
/* Used to mask smu debug modes */
#define SMU_DEBUG_HALT_ON_ERROR		0x1

#define MAX_SMU_I2C_BUSES       2

struct amdgpu_smu_i2c_bus {
	struct i2c_adapter adapter;
	struct amdgpu_device *adev;
	int port;
	struct mutex mutex;
};

struct amdgpu_pm {
	struct mutex		mutex;
	u32                     current_sclk;
@@ -316,8 +325,9 @@ struct amdgpu_pm {
	uint32_t pp_feature;

	/* Used for I2C access to various EEPROMs on relevant ASICs */
	struct i2c_adapter smu_i2c;
	struct mutex		smu_i2c_mutex;
	struct amdgpu_smu_i2c_bus smu_i2c[MAX_SMU_I2C_BUSES];
	struct i2c_adapter     *ras_eeprom_i2c_bus;
	struct i2c_adapter     *fru_eeprom_i2c_bus;
	struct list_head	pm_attr_list;

	atomic_t		pwr_state[AMD_IP_BLOCK_TYPE_NUM];
Loading