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>
diff --git a/src/southbridge/intel/common/smbus.c b/src/southbridge/intel/common/smbus.c
index af1eb60..e575abc 100644
--- a/src/southbridge/intel/common/smbus.c
+++ b/src/southbridge/intel/common/smbus.c
@@ -4,6 +4,7 @@
  * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com>
  * Copyright (C) 2009 coresystems GmbH
  * Copyright (C) 2013 Vladimir Serbinenko
+ * Copyright (C) 2018-2019 Eltan B.V.
  *
  * 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
@@ -410,3 +411,47 @@
 
 	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;
+}