southbridge/intel/common/smbus: Add do_i2c_block_write()

Intel Braswell supports i2c block writes using SMBus controller.
This support is missing in actual smbus routines.

Add do_i2c_block_write() which is a based on do_smbus_block_write() but
also write first byte to SMBHSTDAT1.
The caller needs to configure the SMBus controller in i2c mode.

In i2c mode SMBus controller will send the next sequence:
SMBXINTADD, SMBHSTDAT1, SMBBLKDAT .. SMBBLKDAT

To ensure the the command is send over the bus the SMBHSTCMD register must
be written also

BUG=N/A
TEST=Config eDP for LCD display on Facebook FBG-1701

Change-Id: I40f8c0f5257a62398189f36892b8159052481693
Signed-off-by: Frans Hendriks <fhendriks@eltan.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/30800
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
This commit is contained in:
Frans Hendriks 2019-06-19 11:01:27 +02:00 committed by Martin Roth
parent b09de70eda
commit e48be35bca
2 changed files with 47 additions and 0 deletions

View File

@ -4,6 +4,7 @@
* Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com> * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
* Copyright (C) 2009 coresystems GmbH * Copyright (C) 2009 coresystems GmbH
* Copyright (C) 2013 Vladimir Serbinenko * Copyright (C) 2013 Vladimir Serbinenko
* Copyright (C) 2018-2019 Eltan B.V.
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -410,3 +411,47 @@ int do_i2c_eeprom_read(unsigned int smbus_base, u8 device,
return ret; return ret;
} }
/*
* The caller is responsible of settings HOSTC I2C_EN bit prior to making this
* call!
*/
int do_i2c_block_write(unsigned int smbus_base, u8 device,
unsigned int bytes, u8 *buf)
{
u8 cmd;
int ret;
if (!CONFIG(SOC_INTEL_BRASWELL))
return SMBUS_ERROR;
if (!bytes || (bytes > SMBUS_BLOCK_MAXLEN))
return SMBUS_ERROR;
/* Set up for a block data write. */
ret = setup_command(smbus_base, I801_BLOCK_DATA, XMIT_WRITE(device));
if (ret < 0)
return ret;
/*
* In i2c mode SMBus controller sequence on bus will be:
* <SMBXINTADD> <SMBHSTDAT1> <SMBBLKDAT> .. <SMBBLKDAT>
* The SMBHSTCMD must be written also to ensure the SMBUs controller
* will generate the i2c sequence.
*/
cmd = *buf++;
bytes--;
outb(cmd, smbus_base + SMBHSTCMD);
outb(cmd, smbus_base + SMBHSTDAT1);
/* Execute block transaction. */
ret = block_cmd_loop(smbus_base, buf, bytes, BLOCK_WRITE);
if (ret < 0)
return ret;
if (ret < bytes)
return SMBUS_ERROR;
ret++; /* 1st byte has been written using SMBHSTDAT1 */
return ret;
}

View File

@ -43,4 +43,6 @@ int do_smbus_block_write(unsigned int smbus_base, u8 device,
/* Only since ICH5 */ /* Only since ICH5 */
int do_i2c_eeprom_read(unsigned int smbus_base, u8 device, int do_i2c_eeprom_read(unsigned int smbus_base, u8 device,
unsigned int offset, unsigned int bytes, u8 *buf); unsigned int offset, unsigned int bytes, u8 *buf);
int do_i2c_block_write(unsigned int smbus_base, u8 device,
unsigned int bytes, u8 *buf);
#endif #endif