Merge https://gitlab.denx.de/u-boot/custodians/u-boot-x86

- Add two- and three-argument versions of CONFIG_IS_ENABLED in
  linux/kconfig.h
- Adds a new feature which supports copying modified parts of
  the frame buffer to the uncached hardware buffer
- Enable the copy framebuffer on various x86 targets
diff --git a/MAINTAINERS b/MAINTAINERS
index e3f3e5f..2a281a9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -182,6 +182,8 @@
 F:	drivers/watchdog/cortina_wdt.c
 F:	drivers/serial/serial_cortina.c
 F:	drivers/mmc/ca_dw_mmc.c
+F:	drivers/i2c/i2c-cortina.c
+F:	drivers/i2c/i2c-cortina.h
 
 ARM/CZ.NIC TURRIS MOX SUPPORT
 M:	Marek Behun <marek.behun@nic.cz>
@@ -740,6 +742,8 @@
 F:	drivers/watchdog/cortina_wdt.c
 F:	drivers/serial/serial_cortina.c
 F:	drivers/mmc/ca_dw_mmc.c
+F:	drivers/i2c/i2c-cortina.c
+F:	drivers/i2c/i2c-cortina.h
 
 MIPS MSCC
 M:	Gregory CLEMENT <gregory.clement@bootlin.com>
diff --git a/arch/arm/dts/armada-388-helios4-u-boot.dtsi b/arch/arm/dts/armada-388-helios4-u-boot.dtsi
index f0da9f4..0753889 100644
--- a/arch/arm/dts/armada-388-helios4-u-boot.dtsi
+++ b/arch/arm/dts/armada-388-helios4-u-boot.dtsi
@@ -14,6 +14,9 @@
 
 &spi1 {
 	u-boot,dm-spl;
+	spi-flash@0 {
+		u-boot,dm-spl;
+	};
 };
 
 &w25q32 {
@@ -21,6 +24,18 @@
 	u-boot,dm-spl;
 };
 
+&gpio0 {
+	u-boot,dm-spl;
+};
+
+&ahci0 {
+	u-boot,dm-spl;
+};
+
+&ahci1 {
+	u-boot,dm-spl;
+};
+
 &sdhci {
        u-boot,dm-spl;
 };
diff --git a/arch/arm/dts/armada-388-helios4.dts b/arch/arm/dts/armada-388-helios4.dts
index a154e0f..fb49df2 100644
--- a/arch/arm/dts/armada-388-helios4.dts
+++ b/arch/arm/dts/armada-388-helios4.dts
@@ -140,11 +140,6 @@
 	soc {
 		internal-regs {
 			i2c@11000 {
-				clock-frequency = <400000>;
-				pinctrl-0 = <&i2c0_pins>;
-				pinctrl-names = "default";
-				status = "okay";
-
 				/*
 				 * PCA9655 GPIO expander, up to 1MHz clock.
 				 *  0-Board Revision bit 0 #
@@ -187,8 +182,7 @@
 						gpio-hog;
 						gpios = <5 GPIO_ACTIVE_HIGH>;
 						input;
-						line-name =
-						"usb-overcurrent-status";
+						line-name = "usb-overcurrent-status";
 					};
 				};
 
@@ -248,7 +242,7 @@
 				bus-width = <4>;
 				cd-gpios = <&gpio0 20 GPIO_ACTIVE_LOW>;
 				no-1-8-v;
-				pinctrl-0 = <&microsom_sdhci_pins
+				pinctrl-0 = <&helios_sdhci_pins
 					     &helios_sdhci_cd_pins>;
 				pinctrl-names = "default";
 				status = "okay";
@@ -286,6 +280,12 @@
 					marvell,pins = "mpp20";
 					marvell,function = "gpio";
 				};
+				helios_sdhci_pins: helios-sdhci-pins {
+					marvell,pins = "mpp21", "mpp28",
+						       "mpp37", "mpp38",
+						       "mpp39", "mpp40";
+					marvell,function = "sd0";
+				};
 				helios_led_pins: helios-led-pins {
 					marvell,pins = "mpp24", "mpp25",
 						       "mpp49", "mpp50",
diff --git a/arch/arm/dts/kirkwood-d2net-u-boot.dtsi b/arch/arm/dts/kirkwood-d2net-u-boot.dtsi
new file mode 100644
index 0000000..1f3b185
--- /dev/null
+++ b/arch/arm/dts/kirkwood-d2net-u-boot.dtsi
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/ {
+	aliases {
+		spi0 = &spi0;
+	};
+};
diff --git a/arch/arm/dts/kirkwood-is2-u-boot.dtsi b/arch/arm/dts/kirkwood-is2-u-boot.dtsi
new file mode 100644
index 0000000..1f3b185
--- /dev/null
+++ b/arch/arm/dts/kirkwood-is2-u-boot.dtsi
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/ {
+	aliases {
+		spi0 = &spi0;
+	};
+};
diff --git a/arch/arm/dts/kirkwood-net2big-u-boot.dtsi b/arch/arm/dts/kirkwood-net2big-u-boot.dtsi
new file mode 100644
index 0000000..1f3b185
--- /dev/null
+++ b/arch/arm/dts/kirkwood-net2big-u-boot.dtsi
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/ {
+	aliases {
+		spi0 = &spi0;
+	};
+};
diff --git a/arch/arm/dts/kirkwood-ns2-u-boot.dtsi b/arch/arm/dts/kirkwood-ns2-u-boot.dtsi
new file mode 100644
index 0000000..1f3b185
--- /dev/null
+++ b/arch/arm/dts/kirkwood-ns2-u-boot.dtsi
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/ {
+	aliases {
+		spi0 = &spi0;
+	};
+};
diff --git a/arch/arm/dts/kirkwood-ns2lite-u-boot.dtsi b/arch/arm/dts/kirkwood-ns2lite-u-boot.dtsi
new file mode 100644
index 0000000..1f3b185
--- /dev/null
+++ b/arch/arm/dts/kirkwood-ns2lite-u-boot.dtsi
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/ {
+	aliases {
+		spi0 = &spi0;
+	};
+};
diff --git a/arch/arm/dts/kirkwood-ns2max-u-boot.dtsi b/arch/arm/dts/kirkwood-ns2max-u-boot.dtsi
new file mode 100644
index 0000000..1f3b185
--- /dev/null
+++ b/arch/arm/dts/kirkwood-ns2max-u-boot.dtsi
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/ {
+	aliases {
+		spi0 = &spi0;
+	};
+};
diff --git a/arch/arm/dts/kirkwood-ns2mini-u-boot.dtsi b/arch/arm/dts/kirkwood-ns2mini-u-boot.dtsi
new file mode 100644
index 0000000..1f3b185
--- /dev/null
+++ b/arch/arm/dts/kirkwood-ns2mini-u-boot.dtsi
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/ {
+	aliases {
+		spi0 = &spi0;
+	};
+};
diff --git a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c
index 67a00cf..2454730 100644
--- a/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c
+++ b/arch/arm/mach-mvebu/serdes/a38x/high_speed_env_spec.c
@@ -533,7 +533,7 @@
 struct op_params pex_by4_config_params[] = {
 	/* unit_base_reg, unit_offset, mask, data, wait_time, num_of_loops */
 	{GLOBAL_CLK_SRC_HI, 0x800, 0x7, {0x5, 0x0, 0x0, 0x2}, 0, 0},
-	/* Lane Alignement enable */
+	/* Lane Alignment enable */
 	{LANE_ALIGN_REG0, 0x800, 0x1000, {0x0, 0x0, 0x0, 0x0}, 0, 0},
 	/* Max PLL phy config */
 	{CALIBRATION_CTRL_REG, 0x800, 0x1000, {0x1000, 0x1000, 0x1000, 0x1000},
@@ -672,12 +672,29 @@
 	{0xc200c, 0x0 /*NA*/, 0x1000000, {0x1000000}, 0, 0},
 	/* Phy0 register 3  - TX Channel control 0 */
 	{0xc400c, 0x0 /*NA*/, 0x1000000, {0x1000000}, 0, 0},
-	/* check PLLCAL_DONE is set and IMPCAL_DONE is set */
+	/* Decrease the amplitude of the low speed eye to meet the spec */
+	{0xc000c, 0x0 /*NA*/, 0xf000, {0x1000}, 0, 0},
+	{0xc200c, 0x0 /*NA*/, 0xf000, {0x1000}, 0, 0},
+	{0xc400c, 0x0 /*NA*/, 0xf000, {0x1000}, 0, 0},
+	/* Change the High speed impedance threshold */
+	{0xc0008, 0x0 /*NA*/, 0x700, {0x600}, 0, 0},
+	{0xc2008, 0x0 /*NA*/, 0x700, {0x600}, 0, 0},
+	{0xc4008, 0x0 /*NA*/, 0x700, {0x600}, 0, 0},
+	/* Change the squelch level of the receiver to meet the receiver electrical measurements (squelch and receiver sensitivity tests) */
+	{0xc0014, 0x0 /*NA*/, 0xf, {0x8}, 0, 0},
+	{0xc2014, 0x0 /*NA*/, 0xf, {0x8}, 0, 0},
+	{0xc4014, 0x0 /*NA*/, 0xf, {0x8}, 0, 0},
+	/* Check PLLCAL_DONE is set and IMPCAL_DONE is set */
 	{0xc0008, 0x0 /*NA*/, 0x80800000, {0x80800000}, 1, 1000},
-	/* check REG_SQCAL_DONE  is set */
+	/* Check REG_SQCAL_DONE  is set */
 	{0xc0018, 0x0 /*NA*/, 0x80000000, {0x80000000}, 1, 1000},
-	/* check PLL_READY  is set */
-	{0xc0000, 0x0 /*NA*/, 0x80000000, {0x80000000}, 1, 1000}
+	/* Check PLL_READY  is set */
+	{0xc0000, 0x0 /*NA*/, 0x80000000, {0x80000000}, 1, 1000},
+	/* Start calibrate of high seed impedance */
+	{0xc0008, 0x0 /*NA*/, 0x2000, {0x2000}, 0, 0},
+	{0x0, 0x0 /*NA*/, 0x0, {0x0}, 10, 0},
+	/* De-assert  the calibration signal */
+	{0xc0008, 0x0 /*NA*/, 0x2000, {0x0}, 0, 0},
 };
 
 /*
diff --git a/arch/sandbox/include/asm/rtc.h b/arch/sandbox/include/asm/rtc.h
index 1fbfea7..5bb032f 100644
--- a/arch/sandbox/include/asm/rtc.h
+++ b/arch/sandbox/include/asm/rtc.h
@@ -21,6 +21,11 @@
 
 	REG_RESET	= 0x20,
 
+	REG_AUX0	= 0x30,
+	REG_AUX1,
+	REG_AUX2,
+	REG_AUX3,
+
 	REG_COUNT	= 0x80,
 };
 
diff --git a/board/LaCie/net2big_v2/MAINTAINERS b/board/LaCie/net2big_v2/MAINTAINERS
index 8fec703..7046e1b 100644
--- a/board/LaCie/net2big_v2/MAINTAINERS
+++ b/board/LaCie/net2big_v2/MAINTAINERS
@@ -1,6 +1,12 @@
 NET2BIG_V2 BOARD
 M:	Simon Guinot <simon.guinot@sequanux.org>
 S:	Maintained
+F:	arch/arm/dts/kirkwood-d2net.dts
+F:	arch/arm/dts/kirkwood-d2net-u-boot.dtsi
+F:	arch/arm/dts/kirkwood-d2net.dtsi
+F:	arch/arm/dts/kirkwood-net2big.dts
+F:	arch/arm/dts/kirkwood-net2big-u-boot.dtsi
+F:	arch/arm/dts/kirkwood-netxbig.dtsi
 F:	board/LaCie/net2big_v2/
 F:	include/configs/lacie_kw.h
 F:	configs/d2net_v2_defconfig
diff --git a/board/LaCie/net2big_v2/net2big_v2.c b/board/LaCie/net2big_v2/net2big_v2.c
index dbd8b57..e94c9a6 100644
--- a/board/LaCie/net2big_v2/net2big_v2.c
+++ b/board/LaCie/net2big_v2/net2big_v2.c
@@ -239,7 +239,7 @@
 /* Configure and initialize PHY */
 void reset_phy(void)
 {
-	mv_phy_88e1116_init("egiga0", 8);
+	mv_phy_88e1116_init("ethernet-controller@72000", 8);
 }
 #endif
 
diff --git a/board/LaCie/netspace_v2/MAINTAINERS b/board/LaCie/netspace_v2/MAINTAINERS
index 55fd50d..1cc4f71 100644
--- a/board/LaCie/netspace_v2/MAINTAINERS
+++ b/board/LaCie/netspace_v2/MAINTAINERS
@@ -1,14 +1,21 @@
-NETSPACE_V2 BOARD
+NETSPACE_V2 BOARDS
 M:	Simon Guinot <simon.guinot@sequanux.org>
 S:	Maintained
+F:	arch/arm/dts/kirkwood-is2.dts
+F:	arch/arm/dts/kirkwood-is2-u-boot.dtsi
+F:	arch/arm/dts/kirkwood-ns2-common.dtsi
+F:	arch/arm/dts/kirkwood-ns2.dts
+F:	arch/arm/dts/kirkwood-ns2lite.dts
+F:	arch/arm/dts/kirkwood-ns2lite-u-boot.dtsi
+F:	arch/arm/dts/kirkwood-ns2max.dts
+F:	arch/arm/dts/kirkwood-ns2max-u-boot.dtsi
+F:	arch/arm/dts/kirkwood-ns2mini.dts
+F:	arch/arm/dts/kirkwood-ns2mini-u-boot.dtsi
+F:	arch/arm/dts/kirkwood-ns2-u-boot.dtsi
 F:	board/LaCie/netspace_v2/
 F:	include/configs/lacie_kw.h
 F:	configs/inetspace_v2_defconfig
-F:	configs/netspace_max_v2_defconfig
-F:	configs/netspace_v2_defconfig
-
-NETSPACE_LITE_V2 BOARD
-#M:	-
-S:	Maintained
 F:	configs/netspace_lite_v2_defconfig
+F:	configs/netspace_max_v2_defconfig
 F:	configs/netspace_mini_v2_defconfig
+F:	configs/netspace_v2_defconfig
diff --git a/board/LaCie/netspace_v2/netspace_v2.c b/board/LaCie/netspace_v2/netspace_v2.c
index 011cc56..33246b2 100644
--- a/board/LaCie/netspace_v2/netspace_v2.c
+++ b/board/LaCie/netspace_v2/netspace_v2.c
@@ -100,9 +100,9 @@
 void reset_phy(void)
 {
 #if defined(CONFIG_NETSPACE_LITE_V2) || defined(CONFIG_NETSPACE_MINI_V2)
-	mv_phy_88e1318_init("egiga0", 0);
+	mv_phy_88e1318_init("ethernet-controller@72000", 0);
 #else
-	mv_phy_88e1116_init("egiga0", 8);
+	mv_phy_88e1116_init("ethernet-controller@72000", 8);
 #endif
 }
 #endif
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 2b823dd..846c905 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1739,6 +1739,12 @@
 	  Enable the 'date' command for getting/setting the time/date in RTC
 	  devices.
 
+config CMD_RTC
+	bool "rtc"
+	depends on DM_RTC
+	help
+	  Enable the 'rtc' command for low-level access to RTC devices.
+
 config CMD_TIME
 	bool "time"
 	help
diff --git a/cmd/Makefile b/cmd/Makefile
index 7008dd4..dc412d1 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -122,6 +122,7 @@
 obj-$(CONFIG_CMD_REMOTEPROC) += remoteproc.o
 obj-$(CONFIG_CMD_RNG) += rng.o
 obj-$(CONFIG_CMD_ROCKUSB) += rockusb.o
+obj-$(CONFIG_CMD_RTC) += rtc.o
 obj-$(CONFIG_SANDBOX) += host.o
 obj-$(CONFIG_CMD_SATA) += sata.o
 obj-$(CONFIG_CMD_NVME) += nvme.o
diff --git a/cmd/rtc.c b/cmd/rtc.c
new file mode 100644
index 0000000..b4f61b2
--- /dev/null
+++ b/cmd/rtc.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <hexdump.h>
+#include <i2c.h>
+#include <mapmem.h>
+#include <rtc.h>
+
+#define MAX_RTC_BYTES 32
+
+static int do_rtc_read(struct udevice *dev, int argc, char * const argv[])
+{
+	u8 buf[MAX_RTC_BYTES];
+	int reg, len, ret, r;
+
+	if (argc < 2 || argc > 3)
+		return CMD_RET_USAGE;
+
+	reg = simple_strtoul(argv[0], NULL, 16);
+	len = simple_strtoul(argv[1], NULL, 16);
+
+	if (argc == 3) {
+		u8 *addr;
+
+		addr = map_sysmem(simple_strtoul(argv[2], NULL, 16), len);
+		ret = dm_rtc_read(dev, reg, addr, len);
+		unmap_sysmem(addr);
+		if (ret) {
+			printf("dm_rtc_read() failed: %d\n", ret);
+			return CMD_RET_FAILURE;
+		}
+		return CMD_RET_SUCCESS;
+	}
+
+	while (len) {
+		r = min_t(int, len, sizeof(buf));
+		ret = dm_rtc_read(dev, reg, buf, r);
+		if (ret) {
+			printf("dm_rtc_read() failed: %d\n", ret);
+			return CMD_RET_FAILURE;
+		}
+		print_buffer(reg, buf, 1, r, 0);
+		len -= r;
+		reg += r;
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
+static int do_rtc_write(struct udevice *dev, int argc, char * const argv[])
+{
+	u8 buf[MAX_RTC_BYTES];
+	int reg, len, ret;
+	const char *s;
+	int slen;
+
+	if (argc < 2 || argc > 3)
+		return CMD_RET_USAGE;
+
+	reg = simple_strtoul(argv[0], NULL, 16);
+
+	if (argc == 3) {
+		u8 *addr;
+
+		len = simple_strtoul(argv[1], NULL, 16);
+		addr = map_sysmem(simple_strtoul(argv[2], NULL, 16), len);
+		ret = dm_rtc_write(dev, reg, addr, len);
+		unmap_sysmem(addr);
+		if (ret) {
+			printf("dm_rtc_write() failed: %d\n", ret);
+			return CMD_RET_FAILURE;
+		}
+		return CMD_RET_SUCCESS;
+	}
+
+	s = argv[1];
+	slen = strlen(s);
+
+	if (slen % 2) {
+		printf("invalid hex string\n");
+		return CMD_RET_FAILURE;
+	}
+
+	while (slen) {
+		len = min_t(int, slen / 2, sizeof(buf));
+		if (hex2bin(buf, s, len)) {
+			printf("invalid hex string\n");
+			return CMD_RET_FAILURE;
+		}
+
+		ret = dm_rtc_write(dev, reg, buf, len);
+		if (ret) {
+			printf("dm_rtc_write() failed: %d\n", ret);
+			return CMD_RET_FAILURE;
+		}
+		s += 2 * len;
+		slen -= 2 * len;
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
+int do_rtc(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
+{
+	static int curr_rtc;
+	struct udevice *dev;
+	int ret, idx;
+
+	if (argc < 2)
+		return CMD_RET_USAGE;
+
+	argc--;
+	argv++;
+
+	if (!strcmp(argv[0], "list")) {
+		struct uclass *uc;
+
+		idx = 0;
+		uclass_id_foreach_dev(UCLASS_RTC, dev, uc) {
+			printf("RTC #%d - %s\n", idx++, dev->name);
+		}
+		if (!idx) {
+			printf("*** no RTC devices available ***\n");
+			return CMD_RET_FAILURE;
+		}
+		return CMD_RET_SUCCESS;
+	}
+
+	idx = curr_rtc;
+	if (!strcmp(argv[0], "dev") && argc >= 2)
+		idx = simple_strtoul(argv[1], NULL, 10);
+
+	ret = uclass_get_device(UCLASS_RTC, idx, &dev);
+	if (ret) {
+		printf("Cannot find RTC #%d: err=%d\n", idx, ret);
+		return CMD_RET_FAILURE;
+	}
+
+	if (!strcmp(argv[0], "dev")) {
+		/* Show the existing or newly selected RTC */
+		if (argc >= 2)
+			curr_rtc = idx;
+		printf("RTC #%d - %s\n", idx, dev->name);
+		return CMD_RET_SUCCESS;
+	}
+
+	if (!strcmp(argv[0], "read"))
+		return do_rtc_read(dev, argc - 1, argv + 1);
+
+	if (!strcmp(argv[0], "write"))
+		return do_rtc_write(dev, argc - 1, argv + 1);
+
+	return CMD_RET_USAGE;
+}
+
+U_BOOT_CMD(
+	rtc,	5,	0,	do_rtc,
+	"RTC subsystem",
+	"list                        - show available rtc devices\n"
+	"rtc dev [n]                     - show or set current rtc device\n"
+	"rtc read <reg> <count>          - read and display 8-bit registers starting at <reg>\n"
+	"rtc read <reg> <count> <addr>   - read 8-bit registers starting at <reg> to memory <addr>\n"
+	"rtc write <reg> <hexstring>     - write 8-bit registers starting at <reg>\n"
+	"rtc write <reg> <count> <addr>  - write from memory <addr> to 8-bit registers starting at <reg>\n"
+);
diff --git a/configs/cortina_presidio-asic-emmc_defconfig b/configs/cortina_presidio-asic-emmc_defconfig
index e10008a..e45e23c 100644
--- a/configs/cortina_presidio-asic-emmc_defconfig
+++ b/configs/cortina_presidio-asic-emmc_defconfig
@@ -10,6 +10,7 @@
 CONFIG_BOOTDELAY=3
 CONFIG_BOARD_EARLY_INIT_R=y
 CONFIG_SYS_PROMPT="G3#"
+CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_PART=y
 CONFIG_CMD_WDT=y
@@ -24,6 +25,8 @@
 # CONFIG_NET is not set
 CONFIG_DM=y
 CONFIG_CORTINA_GPIO=y
+CONFIG_DM_I2C=y
+CONFIG_SYS_I2C_CA=y
 CONFIG_DM_MMC=y
 CONFIG_MMC_DW=y
 CONFIG_MMC_DW_CORTINA=y
diff --git a/configs/d2net_v2_defconfig b/configs/d2net_v2_defconfig
index fe3c6c4..31a5d91 100644
--- a/configs/d2net_v2_defconfig
+++ b/configs/d2net_v2_defconfig
@@ -9,6 +9,7 @@
 CONFIG_ENV_SECT_SIZE=0x10000
 CONFIG_NR_DRAM_BANKS=2
 CONFIG_IDENT_STRING=" D2 v2"
+# CONFIG_SYS_MALLOC_F is not set
 CONFIG_SYS_EXTRA_OPTIONS="D2NET_V2"
 CONFIG_BOOTDELAY=3
 CONFIG_USE_BOOTARGS=y
@@ -20,9 +21,8 @@
 CONFIG_HUSH_PARSER=y
 CONFIG_SYS_PROMPT="d2v2> "
 CONFIG_CMD_EEPROM=y
-CONFIG_CMD_IDE=y
 CONFIG_CMD_I2C=y
-CONFIG_CMD_SF=y
+CONFIG_CMD_SATA=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
@@ -39,15 +39,20 @@
 CONFIG_USE_ENV_SPI_MAX_HZ=y
 CONFIG_ENV_SPI_MAX_HZ=20000000
 CONFIG_ENV_ADDR=0x70000
-CONFIG_MVSATA_IDE=y
+CONFIG_DM=y
+CONFIG_SATA_MV=y
+CONFIG_BLK=y
 # CONFIG_MMC is not set
-CONFIG_SPI_FLASH=y
+CONFIG_DM_SPI_FLASH=y
 CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_DM_ETH=y
 CONFIG_MVGBE=y
 CONFIG_MII=y
 CONFIG_SYS_NS16550=y
 CONFIG_SPI=y
+CONFIG_DM_SPI=y
 CONFIG_KIRKWOOD_SPI=y
 CONFIG_USB=y
+CONFIG_DM_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_STORAGE=y
diff --git a/configs/helios4_defconfig b/configs/helios4_defconfig
index 1edd832..2085887 100644
--- a/configs/helios4_defconfig
+++ b/configs/helios4_defconfig
@@ -1,5 +1,6 @@
 CONFIG_ARM=y
 CONFIG_ARCH_CPU_INIT=y
+CONFIG_SYS_THUMB_BUILD=y
 CONFIG_ARCH_MVEBU=y
 CONFIG_SYS_TEXT_BASE=0x00800000
 CONFIG_SPL_LIBCOMMON_SUPPORT=y
@@ -24,40 +25,47 @@
 CONFIG_SYS_CONSOLE_INFO_QUIET=y
 # CONFIG_DISPLAY_BOARDINFO is not set
 CONFIG_DISPLAY_BOARDINFO_LATE=y
-CONFIG_SPL_SYS_MALLOC_SIMPLE=y
-CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x141
+CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_DATA_PART_OFFSET=0x1
+CONFIG_SPL_I2C_SUPPORT=y
+CONFIG_CMD_TLV_EEPROM=y
+CONFIG_SPL_CMD_TLV_EEPROM=y
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_GPIO=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
+CONFIG_CMD_PCI=y
 CONFIG_CMD_SPI=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_TFTPPUT=y
 CONFIG_CMD_CACHE=y
 CONFIG_CMD_TIME=y
+CONFIG_CMD_MVEBU_BUBT=y
 # CONFIG_SPL_PARTITION_UUIDS is not set
 CONFIG_DEFAULT_DEVICE_TREE="armada-388-helios4"
 CONFIG_NET_RANDOM_ETHADDR=y
 CONFIG_SPL_OF_TRANSLATE=y
-CONFIG_SCSI_AHCI=y
+CONFIG_AHCI_MVEBU=y
 CONFIG_DM_PCA953X=y
 CONFIG_DM_I2C=y
-CONFIG_I2C_SET_DEFAULT_BUS_NUM=y
-CONFIG_I2C_DEFAULT_BUS_NUMBER=0x1
 CONFIG_SYS_I2C_MVTWSI=y
+CONFIG_I2C_EEPROM=y
+CONFIG_SPL_I2C_EEPROM=y
 CONFIG_DM_MMC=y
+CONFIG_SUPPORT_EMMC_BOOT=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_SDMA=y
 CONFIG_MMC_SDHCI_MV=y
 CONFIG_MTD=y
 CONFIG_SF_DEFAULT_BUS=1
-CONFIG_SF_DEFAULT_SPEED=104000000
 CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_MTD=y
 CONFIG_PHY_MARVELL=y
 CONFIG_PHY_GIGE=y
 CONFIG_MVNETA=y
 CONFIG_MII=y
+CONFIG_PCI=y
+CONFIG_PCI_MVEBU=y
 CONFIG_SCSI=y
 CONFIG_DEBUG_UART_SHIFT=2
 CONFIG_SYS_NS16550=y
diff --git a/configs/inetspace_v2_defconfig b/configs/inetspace_v2_defconfig
index 6144eb5..b597397 100644
--- a/configs/inetspace_v2_defconfig
+++ b/configs/inetspace_v2_defconfig
@@ -9,6 +9,7 @@
 CONFIG_ENV_SECT_SIZE=0x10000
 CONFIG_NR_DRAM_BANKS=2
 CONFIG_IDENT_STRING=" IS v2"
+# CONFIG_SYS_MALLOC_F is not set
 CONFIG_SYS_EXTRA_OPTIONS="INETSPACE_V2"
 CONFIG_BOOTDELAY=3
 CONFIG_USE_BOOTARGS=y
@@ -20,9 +21,8 @@
 CONFIG_HUSH_PARSER=y
 CONFIG_SYS_PROMPT="ns2> "
 CONFIG_CMD_EEPROM=y
-CONFIG_CMD_IDE=y
 CONFIG_CMD_I2C=y
-CONFIG_CMD_SF=y
+CONFIG_CMD_SATA=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
@@ -39,15 +39,20 @@
 CONFIG_USE_ENV_SPI_MAX_HZ=y
 CONFIG_ENV_SPI_MAX_HZ=20000000
 CONFIG_ENV_ADDR=0x70000
-CONFIG_MVSATA_IDE=y
+CONFIG_DM=y
+CONFIG_SATA_MV=y
+CONFIG_BLK=y
 # CONFIG_MMC is not set
-CONFIG_SPI_FLASH=y
+CONFIG_DM_SPI_FLASH=y
 CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_DM_ETH=y
 CONFIG_MVGBE=y
 CONFIG_MII=y
 CONFIG_SYS_NS16550=y
 CONFIG_SPI=y
+CONFIG_DM_SPI=y
 CONFIG_KIRKWOOD_SPI=y
 CONFIG_USB=y
+CONFIG_DM_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_STORAGE=y
diff --git a/configs/net2big_v2_defconfig b/configs/net2big_v2_defconfig
index 1389d30..bba8503 100644
--- a/configs/net2big_v2_defconfig
+++ b/configs/net2big_v2_defconfig
@@ -9,6 +9,7 @@
 CONFIG_ENV_SECT_SIZE=0x10000
 CONFIG_NR_DRAM_BANKS=2
 CONFIG_IDENT_STRING=" 2Big v2"
+# CONFIG_SYS_MALLOC_F is not set
 CONFIG_SYS_EXTRA_OPTIONS="NET2BIG_V2"
 CONFIG_BOOTDELAY=3
 CONFIG_USE_BOOTARGS=y
@@ -20,9 +21,8 @@
 CONFIG_HUSH_PARSER=y
 CONFIG_SYS_PROMPT="2big2> "
 CONFIG_CMD_EEPROM=y
-CONFIG_CMD_IDE=y
 CONFIG_CMD_I2C=y
-CONFIG_CMD_SF=y
+CONFIG_CMD_SATA=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
@@ -39,15 +39,20 @@
 CONFIG_USE_ENV_SPI_MAX_HZ=y
 CONFIG_ENV_SPI_MAX_HZ=20000000
 CONFIG_ENV_ADDR=0x70000
-CONFIG_MVSATA_IDE=y
+CONFIG_DM=y
+CONFIG_SATA_MV=y
+CONFIG_BLK=y
 # CONFIG_MMC is not set
-CONFIG_SPI_FLASH=y
+CONFIG_DM_SPI_FLASH=y
 CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_DM_ETH=y
 CONFIG_MVGBE=y
 CONFIG_MII=y
 CONFIG_SYS_NS16550=y
 CONFIG_SPI=y
+CONFIG_DM_SPI=y
 CONFIG_KIRKWOOD_SPI=y
 CONFIG_USB=y
+CONFIG_DM_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_STORAGE=y
diff --git a/configs/netspace_lite_v2_defconfig b/configs/netspace_lite_v2_defconfig
index c744d2c..bfa93db 100644
--- a/configs/netspace_lite_v2_defconfig
+++ b/configs/netspace_lite_v2_defconfig
@@ -9,6 +9,7 @@
 CONFIG_ENV_SECT_SIZE=0x10000
 CONFIG_NR_DRAM_BANKS=2
 CONFIG_IDENT_STRING=" NS v2 Lite"
+# CONFIG_SYS_MALLOC_F is not set
 CONFIG_SYS_EXTRA_OPTIONS="NETSPACE_LITE_V2"
 CONFIG_BOOTDELAY=3
 CONFIG_USE_BOOTARGS=y
@@ -20,9 +21,8 @@
 CONFIG_HUSH_PARSER=y
 CONFIG_SYS_PROMPT="ns2> "
 CONFIG_CMD_EEPROM=y
-CONFIG_CMD_IDE=y
 CONFIG_CMD_I2C=y
-CONFIG_CMD_SF=y
+CONFIG_CMD_SATA=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
@@ -39,15 +39,21 @@
 CONFIG_USE_ENV_SPI_MAX_HZ=y
 CONFIG_ENV_SPI_MAX_HZ=20000000
 CONFIG_ENV_ADDR=0x70000
-CONFIG_MVSATA_IDE=y
+CONFIG_DM=y
+CONFIG_SATA_MV=y
+CONFIG_BLK=y
 # CONFIG_MMC is not set
-CONFIG_SPI_FLASH=y
+CONFIG_DM_SPI_FLASH=y
 CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_DM_ETH=y
 CONFIG_MVGBE=y
 CONFIG_MII=y
 CONFIG_SYS_NS16550=y
 CONFIG_SPI=y
+CONFIG_DM_SPI=y
 CONFIG_KIRKWOOD_SPI=y
 CONFIG_USB=y
+CONFIG_DM_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE=y
diff --git a/configs/netspace_max_v2_defconfig b/configs/netspace_max_v2_defconfig
index 8602729..d0f7503 100644
--- a/configs/netspace_max_v2_defconfig
+++ b/configs/netspace_max_v2_defconfig
@@ -9,6 +9,7 @@
 CONFIG_ENV_SECT_SIZE=0x10000
 CONFIG_NR_DRAM_BANKS=2
 CONFIG_IDENT_STRING=" NS Max v2"
+# CONFIG_SYS_MALLOC_F is not set
 CONFIG_SYS_EXTRA_OPTIONS="NETSPACE_MAX_V2"
 CONFIG_BOOTDELAY=3
 CONFIG_USE_BOOTARGS=y
@@ -20,9 +21,8 @@
 CONFIG_HUSH_PARSER=y
 CONFIG_SYS_PROMPT="ns2> "
 CONFIG_CMD_EEPROM=y
-CONFIG_CMD_IDE=y
 CONFIG_CMD_I2C=y
-CONFIG_CMD_SF=y
+CONFIG_CMD_SATA=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
@@ -39,15 +39,21 @@
 CONFIG_USE_ENV_SPI_MAX_HZ=y
 CONFIG_ENV_SPI_MAX_HZ=20000000
 CONFIG_ENV_ADDR=0x70000
-CONFIG_MVSATA_IDE=y
+CONFIG_DM=y
+CONFIG_SATA_MV=y
+CONFIG_BLK=y
 # CONFIG_MMC is not set
-CONFIG_SPI_FLASH=y
+CONFIG_DM_SPI_FLASH=y
 CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_DM_ETH=y
 CONFIG_MVGBE=y
 CONFIG_MII=y
 CONFIG_SYS_NS16550=y
 CONFIG_SPI=y
+CONFIG_DM_SPI=y
 CONFIG_KIRKWOOD_SPI=y
 CONFIG_USB=y
+CONFIG_DM_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE=y
diff --git a/configs/netspace_mini_v2_defconfig b/configs/netspace_mini_v2_defconfig
index ba9301d..6cfaccf 100644
--- a/configs/netspace_mini_v2_defconfig
+++ b/configs/netspace_mini_v2_defconfig
@@ -9,6 +9,7 @@
 CONFIG_ENV_SECT_SIZE=0x10000
 CONFIG_NR_DRAM_BANKS=2
 CONFIG_IDENT_STRING=" NS v2 Mini"
+# CONFIG_SYS_MALLOC_F is not set
 CONFIG_SYS_EXTRA_OPTIONS="NETSPACE_MINI_V2"
 CONFIG_BOOTDELAY=3
 CONFIG_USE_BOOTARGS=y
@@ -20,9 +21,8 @@
 CONFIG_HUSH_PARSER=y
 CONFIG_SYS_PROMPT="ns2> "
 CONFIG_CMD_EEPROM=y
-CONFIG_CMD_IDE=y
 CONFIG_CMD_I2C=y
-CONFIG_CMD_SF=y
+CONFIG_CMD_SATA=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
@@ -37,12 +37,16 @@
 CONFIG_USE_ENV_SPI_MAX_HZ=y
 CONFIG_ENV_SPI_MAX_HZ=20000000
 CONFIG_ENV_ADDR=0x70000
-CONFIG_MVSATA_IDE=y
+CONFIG_DM=y
+CONFIG_SATA_MV=y
+CONFIG_BLK=y
 # CONFIG_MMC is not set
-CONFIG_SPI_FLASH=y
+CONFIG_DM_SPI_FLASH=y
 CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_DM_ETH=y
 CONFIG_MVGBE=y
 CONFIG_MII=y
 CONFIG_SYS_NS16550=y
 CONFIG_SPI=y
+CONFIG_DM_SPI=y
 CONFIG_KIRKWOOD_SPI=y
diff --git a/configs/netspace_v2_defconfig b/configs/netspace_v2_defconfig
index 6ba1ef4..1bd148f 100644
--- a/configs/netspace_v2_defconfig
+++ b/configs/netspace_v2_defconfig
@@ -9,6 +9,7 @@
 CONFIG_ENV_SECT_SIZE=0x10000
 CONFIG_NR_DRAM_BANKS=2
 CONFIG_IDENT_STRING=" NS v2"
+# CONFIG_SYS_MALLOC_F is not set
 CONFIG_SYS_EXTRA_OPTIONS="NETSPACE_V2"
 CONFIG_BOOTDELAY=3
 CONFIG_USE_BOOTARGS=y
@@ -20,9 +21,8 @@
 CONFIG_HUSH_PARSER=y
 CONFIG_SYS_PROMPT="ns2> "
 CONFIG_CMD_EEPROM=y
-CONFIG_CMD_IDE=y
 CONFIG_CMD_I2C=y
-CONFIG_CMD_SF=y
+CONFIG_CMD_SATA=y
 CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_DHCP=y
@@ -39,15 +39,20 @@
 CONFIG_USE_ENV_SPI_MAX_HZ=y
 CONFIG_ENV_SPI_MAX_HZ=20000000
 CONFIG_ENV_ADDR=0x70000
-CONFIG_MVSATA_IDE=y
+CONFIG_DM=y
+CONFIG_SATA_MV=y
+CONFIG_BLK=y
 # CONFIG_MMC is not set
-CONFIG_SPI_FLASH=y
+CONFIG_DM_SPI_FLASH=y
 CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_DM_ETH=y
 CONFIG_MVGBE=y
 CONFIG_MII=y
 CONFIG_SYS_NS16550=y
 CONFIG_SPI=y
+CONFIG_DM_SPI=y
 CONFIG_KIRKWOOD_SPI=y
 CONFIG_USB=y
+CONFIG_DM_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_STORAGE=y
diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
index ac604b5..dcf2f44 100644
--- a/configs/sandbox64_defconfig
+++ b/configs/sandbox64_defconfig
@@ -60,6 +60,7 @@
 CONFIG_CMD_ETHSW=y
 CONFIG_CMD_BMP=y
 CONFIG_CMD_EFIDEBUG=y
+CONFIG_CMD_RTC=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_TIMER=y
 CONFIG_CMD_SOUND=y
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 8a9ec87..9b74e40 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -69,6 +69,7 @@
 CONFIG_CMD_BMP=y
 CONFIG_CMD_BOOTCOUNT=y
 CONFIG_CMD_EFIDEBUG=y
+CONFIG_CMD_RTC=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_TIMER=y
 CONFIG_CMD_SOUND=y
diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig
index dfcc435..4158b9b 100644
--- a/configs/sandbox_flattree_defconfig
+++ b/configs/sandbox_flattree_defconfig
@@ -49,6 +49,7 @@
 CONFIG_CMD_DNS=y
 CONFIG_CMD_LINK_LOCAL=y
 CONFIG_CMD_EFIDEBUG=y
+CONFIG_CMD_RTC=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_TIMER=y
 CONFIG_CMD_SOUND=y
diff --git a/doc/device-tree-bindings/i2c/i2c-cortina.txt b/doc/device-tree-bindings/i2c/i2c-cortina.txt
new file mode 100644
index 0000000..59d5235
--- /dev/null
+++ b/doc/device-tree-bindings/i2c/i2c-cortina.txt
@@ -0,0 +1,18 @@
+* I2C for Cortina platforms
+
+Required properties :
+- compatible : Must be "cortina,ca-i2c"
+- reg : Offset and length of the register set for the device
+
+Recommended properties :
+- clock-frequency : desired I2C bus clock frequency in Hz. If not specified,
+		    default value is 100000. Possible values are 100000,
+		    400000 and 1000000.
+
+Examples :
+
+	i2c: i2c@f4329120 {
+		compatible = "cortina,ca-i2c";
+		reg = <0x0 0xf4329120 0x28>;
+		clock-frequency = <400000>;
+	};
diff --git a/doc/device-tree-bindings/i2c/octeon-i2c.txt b/doc/device-tree-bindings/i2c/octeon-i2c.txt
new file mode 100644
index 0000000..9c1908e
--- /dev/null
+++ b/doc/device-tree-bindings/i2c/octeon-i2c.txt
@@ -0,0 +1,24 @@
+* I2C controller embedded in Marvell Octeon platforms
+
+Required properties :
+- compatible : Must be "cavium,octeon-7890-twsi" or a compatible string
+- reg : Offset and length of the register set for the device
+- clocks: Must contain the input clock of the I2C instance
+- #address-cells = <1>;
+- #size-cells = <0>;
+
+Optional properties :
+- clock-frequency : Desired I2C bus clock frequency in Hz. If not specified,
+  the default 100 kHz frequency will be used. As only Normal, Fast and Fast+
+  modes are implemented, possible values are 100000, 400000 and 1000000.
+
+Example :
+
+	i2c0: i2c@1180000001000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "cavium,octeon-7890-twsi";
+		reg = <0x11800 0x00001000 0x0 0x200>;
+		clock-frequency = <100000>;
+		clocks = <&sclk>;
+	};
diff --git a/doc/device-tree-bindings/pwm/pwm-sifive.txt b/doc/device-tree-bindings/pwm/pwm-sifive.txt
new file mode 100644
index 0000000..9a98837
--- /dev/null
+++ b/doc/device-tree-bindings/pwm/pwm-sifive.txt
@@ -0,0 +1,31 @@
+SiFive PWM controller
+
+Unlike most other PWM controllers, the SiFive PWM controller currently only
+supports one period for all channels in the PWM. All PWMs need to run at
+the same period. The period also has significant restrictions on the values
+it can achieve, which the driver rounds to the nearest achievable period.
+PWM RTL that corresponds to the IP block version numbers can be found
+here:
+
+https://github.com/sifive/sifive-blocks/tree/master/src/main/scala/devices/pwm
+
+Required properties:
+- compatible: Should be "sifive,<chip>-pwm" and "sifive,pwm<version>".
+  Supported compatible strings are: "sifive,fu540-c000-pwm" for the SiFive
+  PWM v0 as integrated onto the SiFive FU540 chip, and "sifive,pwm0" for the
+  SiFive PWM v0 IP block with no chip integration tweaks.
+- reg: physical base address and length of the controller's registers
+- clocks: Should contain a clock identifier for the PWM's parent clock.
+- #pwm-cells: Should be 3.
+- interrupts: one interrupt per PWM channel
+
+Examples:
+
+pwm:  pwm@10020000 {
+	compatible = "sifive,fu540-c000-pwm", "sifive,pwm0";
+	reg = <0x0 0x10020000 0x0 0x1000>;
+	clocks = <&tlclk>;
+	interrupt-parent = <&plic>;
+	interrupts = <42 43 44 45>;
+	#pwm-cells = <3>;
+};
diff --git a/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.c b/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.c
index df832ac..58ffb20 100644
--- a/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.c
+++ b/drivers/ddr/marvell/a38x/ddr3_training_hw_algo.c
@@ -11,7 +11,7 @@
 #define VREF_MAX_INDEX			7
 #define MAX_VALUE			(1024 - 1)
 #define MIN_VALUE			(-MAX_VALUE)
-#define GET_RD_SAMPLE_DELAY(data, cs)	((data >> rd_sample_mask[cs]) & 0xf)
+#define GET_RD_SAMPLE_DELAY(data, cs)	((data >> rd_sample_mask[cs]) & 0x1f)
 
 u32 ca_delay;
 int ddr3_tip_centr_skip_min_win_check = 0;
@@ -91,8 +91,8 @@
 			min_read_sample = read_sample[cs_num];
 	}
 
-	min_read_sample = min_read_sample - 1;
-	max_read_sample = max_read_sample + 4 + (max_phase + 1) / 2 + 1;
+	min_read_sample = min_read_sample + 2;
+	max_read_sample = max_read_sample + 7 + (max_phase + 1) / 2 + 1;
 	if (min_read_sample >= 0xf)
 		min_read_sample = 0xf;
 	if (max_read_sample >= 0x1f)
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index f8b18de..87d11b6 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -93,6 +93,14 @@
 	  Say yes here to select Cadence I2C Host Controller. This controller is
 	  e.g. used by Xilinx Zynq.
 
+config SYS_I2C_CA
+	tristate "Cortina-Access I2C Controller"
+	depends on DM_I2C && CORTINA_PLATFORM
+	default n
+	help
+	  Add support for the Cortina Access I2C host controller.
+	  Say yes here to select Cortina-Access I2C Host Controller.
+
 config SYS_I2C_DAVINCI
 	bool "Davinci I2C Controller"
 	depends on (ARCH_KEYSTONE || ARCH_DAVINCI)
@@ -374,6 +382,16 @@
 	  bus. Devices can be attached to the bus using the device tree
 	  which specifies the driver to use.  See sandbox.dts as an example.
 
+config SYS_I2C_OCTEON
+	bool "Octeon II/III/TX/TX2 I2C driver"
+	depends on (ARCH_OCTEON || ARCH_OCTEONTX || ARCH_OCTEONTX2) && DM_I2C
+	default y
+	help
+	  Add support for the Marvell Octeon I2C driver. This is used with
+	  various Octeon parts such as Octeon II/III and OcteonTX/TX2. All
+	  chips have several I2C ports and all are provided, controlled by
+	  the device tree.
+
 config SYS_I2C_S3C24X0
 	bool "Samsung I2C driver"
 	depends on ARCH_EXYNOS4 && DM_I2C
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 62935b7..174081e 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -12,6 +12,7 @@
 obj-$(CONFIG_SYS_I2C_ASPEED) += ast_i2c.o
 obj-$(CONFIG_SYS_I2C_AT91) += at91_i2c.o
 obj-$(CONFIG_SYS_I2C_CADENCE) += i2c-cdns.o
+obj-$(CONFIG_SYS_I2C_CA) += i2c-cortina.o
 obj-$(CONFIG_SYS_I2C_DAVINCI) += davinci_i2c.o
 obj-$(CONFIG_SYS_I2C_DW) += designware_i2c.o
 ifdef CONFIG_DM_PCI
@@ -27,6 +28,7 @@
 obj-$(CONFIG_SYS_I2C_MESON) += meson_i2c.o
 obj-$(CONFIG_SYS_I2C_MVTWSI) += mvtwsi.o
 obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o
+obj-$(CONFIG_SYS_I2C_OCTEON) += octeon_i2c.o
 obj-$(CONFIG_SYS_I2C_OMAP24XX) += omap24xx_i2c.o
 obj-$(CONFIG_SYS_I2C_RCAR_I2C) += rcar_i2c.o
 obj-$(CONFIG_SYS_I2C_RCAR_IIC) += rcar_iic.o
diff --git a/drivers/i2c/i2c-cortina.c b/drivers/i2c/i2c-cortina.c
new file mode 100644
index 0000000..036fc42
--- /dev/null
+++ b/drivers/i2c/i2c-cortina.c
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2020
+ * Arthur Li, Cortina Access, arthur.li@cortina-access.com.
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <log.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <mapmem.h>
+#include "i2c-cortina.h"
+
+static void set_speed(struct i2c_regs *regs, int i2c_spd)
+{
+	union ca_biw_cfg i2c_cfg;
+
+	i2c_cfg.wrd = readl(&regs->i2c_cfg);
+	i2c_cfg.bf.core_en = 0;
+	writel(i2c_cfg.wrd, &regs->i2c_cfg);
+
+	switch (i2c_spd) {
+	case IC_SPEED_MODE_FAST_PLUS:
+		i2c_cfg.bf.prer = CORTINA_PER_IO_FREQ /
+				  (5 * I2C_SPEED_FAST_PLUS_RATE) - 1;
+		break;
+
+	case IC_SPEED_MODE_STANDARD:
+		i2c_cfg.bf.prer = CORTINA_PER_IO_FREQ /
+				  (5 * I2C_SPEED_STANDARD_RATE) - 1;
+		break;
+
+	case IC_SPEED_MODE_FAST:
+	default:
+		i2c_cfg.bf.prer = CORTINA_PER_IO_FREQ /
+				  (5 * I2C_SPEED_FAST_RATE) - 1;
+		break;
+	}
+
+	i2c_cfg.bf.core_en = 1;
+	writel(i2c_cfg.wrd, &regs->i2c_cfg);
+}
+
+static int ca_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+	struct ca_i2c *priv = dev_get_priv(bus);
+	int i2c_spd;
+
+	if (speed >= I2C_SPEED_FAST_PLUS_RATE) {
+		i2c_spd = IC_SPEED_MODE_FAST_PLUS;
+		priv->speed = I2C_SPEED_FAST_PLUS_RATE;
+	} else if (speed >= I2C_SPEED_FAST_RATE) {
+		i2c_spd = IC_SPEED_MODE_FAST;
+		priv->speed = I2C_SPEED_FAST_RATE;
+	} else {
+		i2c_spd = IC_SPEED_MODE_STANDARD;
+		priv->speed = I2C_SPEED_STANDARD_RATE;
+	}
+
+	set_speed(priv->regs, i2c_spd);
+
+	return 0;
+}
+
+static int ca_i2c_get_bus_speed(struct udevice *bus)
+{
+	struct ca_i2c *priv = dev_get_priv(bus);
+
+	return priv->speed;
+}
+
+static void ca_i2c_init(struct i2c_regs *regs)
+{
+	union ca_biw_cfg i2c_cfg;
+
+	i2c_cfg.wrd = readl(&regs->i2c_cfg);
+	i2c_cfg.bf.core_en = 0;
+	i2c_cfg.bf.biw_soft_reset = 1;
+	writel(i2c_cfg.wrd, &regs->i2c_cfg);
+	mdelay(10);
+	i2c_cfg.bf.biw_soft_reset = 0;
+	writel(i2c_cfg.wrd, &regs->i2c_cfg);
+
+	set_speed(regs, IC_SPEED_MODE_STANDARD);
+
+	i2c_cfg.wrd = readl(&regs->i2c_cfg);
+	i2c_cfg.bf.core_en = 1;
+	writel(i2c_cfg.wrd, &regs->i2c_cfg);
+}
+
+static int i2c_wait_complete(struct i2c_regs *regs)
+{
+	union ca_biw_ctrl i2c_ctrl;
+	unsigned long start_time_bb = get_timer(0);
+
+	i2c_ctrl.wrd = readl(&regs->i2c_ctrl);
+
+	while (i2c_ctrl.bf.biwdone == 0) {
+		i2c_ctrl.wrd = readl(&regs->i2c_ctrl);
+
+		if (get_timer(start_time_bb) >
+		   (unsigned long)(I2C_BYTE_TO_BB)) {
+			printf("%s not done!!!\n", __func__);
+			return -ETIMEDOUT;
+		}
+	}
+
+	/* Clear done bit */
+	writel(i2c_ctrl.wrd, &regs->i2c_ctrl);
+
+	return 0;
+}
+
+static void i2c_setaddress(struct i2c_regs *regs, unsigned int i2c_addr,
+			   int write_read)
+{
+	writel(i2c_addr | write_read, &regs->i2c_txr);
+
+	writel(BIW_CTRL_START | BIW_CTRL_WRITE,
+	       &regs->i2c_ctrl);
+
+	i2c_wait_complete(regs);
+}
+
+static int i2c_wait_for_bus_busy(struct i2c_regs *regs)
+{
+	union ca_biw_ack i2c_ack;
+	unsigned long start_time_bb = get_timer(0);
+
+	i2c_ack.wrd = readl(&regs->i2c_ack);
+
+	while (i2c_ack.bf.biw_busy) {
+		i2c_ack.wrd = readl(&regs->i2c_ack);
+
+		if (get_timer(start_time_bb) >
+		   (unsigned long)(I2C_BYTE_TO_BB)) {
+			printf("%s: timeout!\n", __func__);
+			return -ETIMEDOUT;
+		}
+	}
+
+	return 0;
+}
+
+static int i2c_xfer_init(struct i2c_regs *regs, uint8_t chip, uint addr,
+			 int alen, int write_read)
+{
+	int addr_len = alen;
+
+	if (i2c_wait_for_bus_busy(regs))
+		return 1;
+
+	/* First cycle must write addr + offset */
+	chip = ((chip & 0x7F) << 1);
+	if (alen == 0 && write_read == I2C_CMD_RD)
+		i2c_setaddress(regs, chip, I2C_CMD_RD);
+	else
+		i2c_setaddress(regs, chip, I2C_CMD_WT);
+
+	while (alen) {
+		alen--;
+		writel(addr, &regs->i2c_txr);
+		if (write_read == I2C_CMD_RD)
+			writel(BIW_CTRL_WRITE | BIW_CTRL_STOP,
+			       &regs->i2c_ctrl);
+		else
+			writel(BIW_CTRL_WRITE, &regs->i2c_ctrl);
+		i2c_wait_complete(regs);
+	}
+
+	/* Send address again with Read flag if it's read command */
+	if (write_read == I2C_CMD_RD && addr_len > 0)
+		i2c_setaddress(regs, chip, I2C_CMD_RD);
+
+	return 0;
+}
+
+static int i2c_xfer_finish(struct i2c_regs *regs)
+{
+	/* Dummy read makes bus free */
+	writel(BIW_CTRL_READ | BIW_CTRL_STOP, &regs->i2c_ctrl);
+	i2c_wait_complete(regs);
+
+	if (i2c_wait_for_bus_busy(regs)) {
+		printf("Timed out waiting for bus\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int ca_i2c_read(struct i2c_regs *regs, uint8_t chip, uint addr,
+		       int alen, uint8_t *buffer, int len)
+{
+	unsigned long start_time_rx;
+	int rc = 0;
+
+	rc = i2c_xfer_init(regs, chip, addr, alen, I2C_CMD_RD);
+	if (rc)
+		return rc;
+
+	start_time_rx = get_timer(0);
+	while (len) {
+		/* ACK_IN is ack value to send during read.
+		 * ack high only on the very last byte!
+		 */
+		if (len == 1)
+			writel(BIW_CTRL_READ | BIW_CTRL_ACK_IN | BIW_CTRL_STOP,
+			       &regs->i2c_ctrl);
+		else
+			writel(BIW_CTRL_READ, &regs->i2c_ctrl);
+
+		rc = i2c_wait_complete(regs);
+		udelay(1);
+
+		if (rc == 0) {
+			*buffer++ =
+				(uchar) readl(&regs->i2c_rxr);
+			len--;
+			start_time_rx = get_timer(0);
+
+		} else if (get_timer(start_time_rx) > I2C_BYTE_TO) {
+			return -ETIMEDOUT;
+		}
+	}
+	i2c_xfer_finish(regs);
+	return rc;
+}
+
+static int ca_i2c_write(struct i2c_regs *regs, uint8_t chip, uint addr,
+			int alen, uint8_t *buffer, int len)
+{
+	int rc, nb = len;
+	unsigned long start_time_tx;
+
+	rc = i2c_xfer_init(regs, chip, addr, alen, I2C_CMD_WT);
+	if (rc)
+		return rc;
+
+	start_time_tx = get_timer(0);
+	while (len) {
+		writel(*buffer, &regs->i2c_txr);
+		if (len == 1)
+			writel(BIW_CTRL_WRITE | BIW_CTRL_STOP,
+			       &regs->i2c_ctrl);
+		else
+			writel(BIW_CTRL_WRITE, &regs->i2c_ctrl);
+
+		rc = i2c_wait_complete(regs);
+
+		if (rc == 0) {
+			len--;
+			buffer++;
+			start_time_tx = get_timer(0);
+		} else if (get_timer(start_time_tx) > (nb * I2C_BYTE_TO)) {
+			return -ETIMEDOUT;
+		}
+	}
+
+	return 0;
+}
+
+static int ca_i2c_probe_chip(struct udevice *bus, uint chip_addr,
+			     uint chip_flags)
+{
+	struct ca_i2c *priv = dev_get_priv(bus);
+	int ret;
+	u32 tmp;
+
+	/* Try to read the first location of the chip */
+	ret = ca_i2c_read(priv->regs, chip_addr, 0, 1, (uchar *)&tmp, 1);
+	if (ret)
+		ca_i2c_init(priv->regs);
+
+	return ret;
+}
+
+static int ca_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
+{
+	struct ca_i2c *priv = dev_get_priv(bus);
+	int ret;
+
+	debug("i2c_xfer: %d messages\n", nmsgs);
+	for (; nmsgs > 0; nmsgs--, msg++) {
+		debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
+		if (msg->flags & I2C_M_RD)
+			ret = ca_i2c_read(priv->regs, msg->addr, 0, 0,
+					  msg->buf, msg->len);
+		else
+			ret = ca_i2c_write(priv->regs, msg->addr, 0, 0,
+					   msg->buf, msg->len);
+
+		if (ret) {
+			printf("i2c_xfer: %s error\n",
+			       msg->flags & I2C_M_RD ? "read" : "write");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static const struct dm_i2c_ops ca_i2c_ops = {
+	.xfer		= ca_i2c_xfer,
+	.probe_chip	= ca_i2c_probe_chip,
+	.set_bus_speed	= ca_i2c_set_bus_speed,
+	.get_bus_speed	= ca_i2c_get_bus_speed,
+};
+
+static const struct udevice_id ca_i2c_ids[] = {
+	{ .compatible = "cortina,ca-i2c", },
+	{ }
+};
+
+static int ca_i2c_probe(struct udevice *bus)
+{
+	struct ca_i2c *priv = dev_get_priv(bus);
+
+	ca_i2c_init(priv->regs);
+
+	return 0;
+}
+
+static int ca_i2c_ofdata_to_platdata(struct udevice *bus)
+{
+	struct ca_i2c *priv = dev_get_priv(bus);
+
+	priv->regs = map_sysmem(dev_read_addr(bus), sizeof(struct i2c_regs));
+	if (!priv->regs) {
+		printf("I2C: base address is invalid\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+U_BOOT_DRIVER(i2c_cortina) = {
+	.name	= "i2c_cortina",
+	.id	= UCLASS_I2C,
+	.of_match = ca_i2c_ids,
+	.ofdata_to_platdata = ca_i2c_ofdata_to_platdata,
+	.probe	= ca_i2c_probe,
+	.priv_auto_alloc_size = sizeof(struct ca_i2c),
+	.ops	= &ca_i2c_ops,
+	.flags  = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/i2c/i2c-cortina.h b/drivers/i2c/i2c-cortina.h
new file mode 100644
index 0000000..7e406b5
--- /dev/null
+++ b/drivers/i2c/i2c-cortina.h
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2019
+ * Cortina Access, <www.cortina-access.com>
+ */
+
+#ifndef __CA_I2C_H_
+#define __CA_I2C_H_
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+
+#if !defined(__ASSEMBLER__) && !defined(__ASSEMBLY__)
+struct i2c_regs {
+	u32 i2c_cfg;
+	u32 i2c_ctrl;
+	u32 i2c_txr;
+	u32 i2c_rxr;
+	u32 i2c_ack;
+	u32 i2c_ie0;
+	u32 i2c_int0;
+	u32 i2c_ie1;
+	u32 i2c_int1;
+	u32 i2c_stat;
+};
+
+union ca_biw_cfg {
+	struct biw_cfg {
+		u32 core_en		: 1;
+		u32 biw_soft_reset	: 1;
+		u32 busywait_en		: 1;
+		u32 stretch_en		: 1;
+		u32 arb_en		: 1;
+		u32 clksync_en		: 1;
+		u32 rsrvd1		: 2;
+		u32 spike_cnt		: 4;
+		u32 rsrvd2		: 4;
+		u32 prer		: 16;
+	} bf;
+	unsigned int wrd;
+};
+
+union ca_biw_ctrl {
+	struct biw_ctrl {
+		u32 biwdone	: 1;
+		u32 rsrvd1	: 2;
+		u32 ack_in	: 1;
+		u32 write	: 1;
+		u32 read	: 1;
+		u32 stop	: 1;
+		u32 start	: 1;
+		u32 rsrvd2	: 24;
+	} bf;
+	unsigned int wrd;
+};
+
+union ca_biw_ack {
+	struct biw_ack {
+		u32 al		:1;
+		u32 biw_busy	:1;
+		u32 ack_out	:1;
+		u32 rsrvd1	:29;
+	} bf;
+	unsigned int wrd;
+};
+#endif /* !__ASSEMBLER__*/
+
+struct ca_i2c {
+	struct i2c_regs *regs;
+	unsigned int speed;
+};
+
+#define I2C_CMD_WT			0
+#define I2C_CMD_RD			1
+
+#define BIW_CTRL_DONE		BIT(0)
+#define BIW_CTRL_ACK_IN		BIT(3)
+#define BIW_CTRL_WRITE		BIT(4)
+#define BIW_CTRL_READ		BIT(5)
+#define BIW_CTRL_STOP		BIT(6)
+#define BIW_CTRL_START		BIT(7)
+
+#define I2C_BYTE_TO		(CONFIG_SYS_HZ / 500)
+#define I2C_STOPDET_TO		(CONFIG_SYS_HZ / 500)
+#define I2C_BYTE_TO_BB		(10)
+
+#endif							/* __CA_I2C_H_ */
diff --git a/drivers/i2c/imx_lpi2c.c b/drivers/i2c/imx_lpi2c.c
index c8e42e0..b7b2aaf 100644
--- a/drivers/i2c/imx_lpi2c.c
+++ b/drivers/i2c/imx_lpi2c.c
@@ -97,7 +97,8 @@
 
 static int bus_i2c_send(struct udevice *bus, u8 *txbuf, int len)
 {
-	struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus);
+	struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
+	struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)(i2c_bus->base);
 	lpi2c_status_t result = LPI2C_SUCESS;
 
 	/* empty tx */
@@ -118,7 +119,8 @@
 
 static int bus_i2c_receive(struct udevice *bus, u8 *rxbuf, int len)
 {
-	struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus);
+	struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
+	struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)(i2c_bus->base);
 	lpi2c_status_t result = LPI2C_SUCESS;
 	u32 val;
 	ulong start_time = get_timer(0);
@@ -162,8 +164,8 @@
 static int bus_i2c_start(struct udevice *bus, u8 addr, u8 dir)
 {
 	lpi2c_status_t result;
-	struct imx_lpi2c_reg *regs =
-		(struct imx_lpi2c_reg *)devfdt_get_addr(bus);
+	struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
+	struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)(i2c_bus->base);
 	u32 val;
 
 	result = imx_lpci2c_check_busy_bus(regs);
@@ -199,8 +201,8 @@
 static int bus_i2c_stop(struct udevice *bus)
 {
 	lpi2c_status_t result;
-	struct imx_lpi2c_reg *regs =
-		(struct imx_lpi2c_reg *)devfdt_get_addr(bus);
+	struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
+	struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)(i2c_bus->base);
 	u32 status;
 	ulong start_time;
 
@@ -271,7 +273,7 @@
 static int bus_i2c_set_bus_speed(struct udevice *bus, int speed)
 {
 	struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
-	struct imx_lpi2c_reg *regs;
+	struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)(i2c_bus->base);
 	u32 val;
 	u32 preescale = 0, best_pre = 0, clkhi = 0;
 	u32 best_clkhi = 0, abs_error = 0, rate;
@@ -280,8 +282,6 @@
 	bool mode;
 	int i;
 
-	regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus);
-
 	if (IS_ENABLED(CONFIG_CLK)) {
 		clock_rate = clk_get_rate(&i2c_bus->per_clk);
 		if (clock_rate <= 0) {
@@ -348,11 +348,11 @@
 
 static int bus_i2c_init(struct udevice *bus, int speed)
 {
-	struct imx_lpi2c_reg *regs;
 	u32 val;
 	int ret;
 
-	regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus);
+	struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
+	struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)(i2c_bus->base);
 	/* reset peripheral */
 	writel(LPI2C_MCR_RST_MASK, &regs->mcr);
 	writel(0x0, &regs->mcr);
diff --git a/drivers/i2c/octeon_i2c.c b/drivers/i2c/octeon_i2c.c
new file mode 100644
index 0000000..c11d6ff
--- /dev/null
+++ b/drivers/i2c/octeon_i2c.c
@@ -0,0 +1,847 @@
+// SPDX-License-Identifier:    GPL-2.0
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <i2c.h>
+#include <pci_ids.h>
+#include <asm/io.h>
+#include <linux/bitfield.h>
+#include <linux/compat.h>
+#include <linux/delay.h>
+
+#define TWSI_SW_TWSI		0x00
+#define TWSI_TWSI_SW		0x08
+#define TWSI_INT		0x10
+#define TWSI_SW_TWSI_EXT	0x18
+
+#define TWSI_SW_DATA_MASK	GENMASK_ULL(31, 0)
+#define TWSI_SW_EOP_IA_MASK	GENMASK_ULL(34, 32)
+#define TWSI_SW_IA_MASK		GENMASK_ULL(39, 35)
+#define TWSI_SW_ADDR_MASK	GENMASK_ULL(49, 40)
+#define TWSI_SW_SCR_MASK	GENMASK_ULL(51, 50)
+#define TWSI_SW_SIZE_MASK	GENMASK_ULL(54, 52)
+#define TWSI_SW_SOVR		BIT_ULL(55)
+#define TWSI_SW_R		BIT_ULL(56)
+#define TWSI_SW_OP_MASK		GENMASK_ULL(60, 57)
+#define TWSI_SW_EIA		GENMASK_ULL(61)
+#define TWSI_SW_SLONLY		BIT_ULL(62)
+#define TWSI_SW_V		BIT_ULL(63)
+
+#define TWSI_INT_SDA_OVR	BIT_ULL(8)
+#define TWSI_INT_SCL_OVR	BIT_ULL(9)
+#define TWSI_INT_SDA		BIT_ULL(10)
+#define TWSI_INT_SCL		BIT_ULL(11)
+
+enum {
+	TWSI_OP_WRITE	= 0,
+	TWSI_OP_READ	= 1,
+};
+
+enum {
+	TWSI_EOP_SLAVE_ADDR = 0,
+	TWSI_EOP_CLK_CTL = 3,
+	TWSI_SW_EOP_IA   = 6,
+};
+
+enum {
+	TWSI_SLAVEADD     = 0,
+	TWSI_DATA         = 1,
+	TWSI_CTL          = 2,
+	TWSI_CLKCTL       = 3,
+	TWSI_STAT         = 3,
+	TWSI_SLAVEADD_EXT = 4,
+	TWSI_RST          = 7,
+};
+
+enum {
+	TWSI_CTL_AAK	= BIT(2),
+	TWSI_CTL_IFLG	= BIT(3),
+	TWSI_CTL_STP	= BIT(4),
+	TWSI_CTL_STA	= BIT(5),
+	TWSI_CTL_ENAB	= BIT(6),
+	TWSI_CTL_CE	= BIT(7),
+};
+
+/*
+ * Internal errors. When debugging is enabled, the driver will report the
+ * error number and the user / developer can check the table below for the
+ * detailed error description.
+ */
+enum {
+	/** Bus error */
+	TWSI_STAT_BUS_ERROR		= 0x00,
+	/** Start condition transmitted */
+	TWSI_STAT_START			= 0x08,
+	/** Repeat start condition transmitted */
+	TWSI_STAT_RSTART		= 0x10,
+	/** Address + write bit transmitted, ACK received */
+	TWSI_STAT_TXADDR_ACK		= 0x18,
+	/** Address + write bit transmitted, /ACK received */
+	TWSI_STAT_TXADDR_NAK		= 0x20,
+	/** Data byte transmitted in master mode, ACK received */
+	TWSI_STAT_TXDATA_ACK		= 0x28,
+	/** Data byte transmitted in master mode, ACK received */
+	TWSI_STAT_TXDATA_NAK		= 0x30,
+	/** Arbitration lost in address or data byte */
+	TWSI_STAT_TX_ARB_LOST		= 0x38,
+	/** Address + read bit transmitted, ACK received */
+	TWSI_STAT_RXADDR_ACK		= 0x40,
+	/** Address + read bit transmitted, /ACK received */
+	TWSI_STAT_RXADDR_NAK		= 0x48,
+	/** Data byte received in master mode, ACK transmitted */
+	TWSI_STAT_RXDATA_ACK_SENT	= 0x50,
+	/** Data byte received, NACK transmitted */
+	TWSI_STAT_RXDATA_NAK_SENT	= 0x58,
+	/** Slave address received, sent ACK */
+	TWSI_STAT_SLAVE_RXADDR_ACK	= 0x60,
+	/**
+	 * Arbitration lost in address as master, slave address + write bit
+	 * received, ACK transmitted
+	 */
+	TWSI_STAT_TX_ACK_ARB_LOST	= 0x68,
+	/** General call address received, ACK transmitted */
+	TWSI_STAT_RX_GEN_ADDR_ACK	= 0x70,
+	/**
+	 * Arbitration lost in address as master, general call address
+	 * received, ACK transmitted
+	 */
+	TWSI_STAT_RX_GEN_ADDR_ARB_LOST	= 0x78,
+	/** Data byte received after slave address received, ACK transmitted */
+	TWSI_STAT_SLAVE_RXDATA_ACK	= 0x80,
+	/** Data byte received after slave address received, /ACK transmitted */
+	TWSI_STAT_SLAVE_RXDATA_NAK	= 0x88,
+	/**
+	 * Data byte received after general call address received, ACK
+	 * transmitted
+	 */
+	TWSI_STAT_GEN_RXADDR_ACK	= 0x90,
+	/**
+	 * Data byte received after general call address received, /ACK
+	 * transmitted
+	 */
+	TWSI_STAT_GEN_RXADDR_NAK	= 0x98,
+	/** STOP or repeated START condition received in slave mode */
+	TWSI_STAT_STOP_MULTI_START	= 0xa0,
+	/** Slave address + read bit received, ACK transmitted */
+	TWSI_STAT_SLAVE_RXADDR2_ACK	= 0xa8,
+	/**
+	 * Arbitration lost in address as master, slave address + read bit
+	 * received, ACK transmitted
+	 */
+	TWSI_STAT_RXDATA_ACK_ARB_LOST	= 0xb0,
+	/** Data byte transmitted in slave mode, ACK received */
+	TWSI_STAT_SLAVE_TXDATA_ACK	= 0xb8,
+	/** Data byte transmitted in slave mode, /ACK received */
+	TWSI_STAT_SLAVE_TXDATA_NAK	= 0xc0,
+	/** Last byte transmitted in slave mode, ACK received */
+	TWSI_STAT_SLAVE_TXDATA_END_ACK	= 0xc8,
+	/** Second address byte + write bit transmitted, ACK received */
+	TWSI_STAT_TXADDR2DATA_ACK	= 0xd0,
+	/** Second address byte + write bit transmitted, /ACK received */
+	TWSI_STAT_TXADDR2DATA_NAK	= 0xd8,
+	/** No relevant status information */
+	TWSI_STAT_IDLE			= 0xf8
+};
+
+#define CONFIG_SYS_I2C_OCTEON_SLAVE_ADDR	0x77
+
+enum {
+	PROBE_PCI = 0,		/* PCI based probing */
+	PROBE_DT,		/* DT based probing */
+};
+
+enum {
+	CLK_METHOD_OCTEON = 0,
+	CLK_METHOD_OCTEONTX2,
+};
+
+/**
+ * struct octeon_i2c_data - SoC specific data of this driver
+ *
+ * @probe:	Probing of this SoC (DT vs PCI)
+ * @reg_offs:	Register offset
+ * @thp:	THP define for divider calculation
+ * @clk_method:	Clock calculation method
+ */
+struct octeon_i2c_data {
+	int probe;
+	u32 reg_offs;
+	int thp;
+	int clk_method;
+};
+
+/**
+ * struct octeon_twsi - Private data of this driver
+ *
+ * @base:	Base address of i2c registers
+ * @data:	Pointer to SoC specific data struct
+ */
+struct octeon_twsi {
+	void __iomem *base;
+	const struct octeon_i2c_data *data;
+	struct clk clk;
+};
+
+static void twsi_unblock(void *base);
+static int twsi_stop(void *base);
+
+/**
+ * Returns true if we lost arbitration
+ *
+ * @code	status code
+ * @final_read	true if this is the final read operation
+ * @return	true if arbitration has been lost, false if it hasn't been lost.
+ */
+static int twsi_i2c_lost_arb(u8 code, int final_read)
+{
+	switch (code) {
+	case TWSI_STAT_TX_ARB_LOST:
+	case TWSI_STAT_TX_ACK_ARB_LOST:
+	case TWSI_STAT_RX_GEN_ADDR_ARB_LOST:
+	case TWSI_STAT_RXDATA_ACK_ARB_LOST:
+		/* Arbitration lost */
+		return -EAGAIN;
+
+	case TWSI_STAT_SLAVE_RXADDR_ACK:
+	case TWSI_STAT_RX_GEN_ADDR_ACK:
+	case TWSI_STAT_GEN_RXADDR_ACK:
+	case TWSI_STAT_GEN_RXADDR_NAK:
+		/* Being addressed as slave, should back off and listen */
+		return -EIO;
+
+	case TWSI_STAT_SLAVE_RXDATA_ACK:
+	case TWSI_STAT_SLAVE_RXDATA_NAK:
+	case TWSI_STAT_STOP_MULTI_START:
+	case TWSI_STAT_SLAVE_RXADDR2_ACK:
+	case TWSI_STAT_SLAVE_TXDATA_ACK:
+	case TWSI_STAT_SLAVE_TXDATA_NAK:
+	case TWSI_STAT_SLAVE_TXDATA_END_ACK:
+		/* Core busy as slave */
+		return  -EIO;
+
+	case TWSI_STAT_RXDATA_ACK_SENT:
+		/* Ack allowed on pre-terminal bytes only */
+		if (!final_read)
+			return 0;
+		return -EAGAIN;
+
+	case TWSI_STAT_RXDATA_NAK_SENT:
+		/* NAK allowed on terminal byte only */
+		if (!final_read)
+			return 0;
+		return -EAGAIN;
+
+	case TWSI_STAT_TXDATA_NAK:
+	case TWSI_STAT_TXADDR_NAK:
+	case TWSI_STAT_RXADDR_NAK:
+	case TWSI_STAT_TXADDR2DATA_NAK:
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
+/**
+ * Writes to the MIO_TWS(0..5)_SW_TWSI register
+ *
+ * @base	Base address of i2c registers
+ * @val		value to write
+ * @return	0 for success, otherwise error
+ */
+static u64 twsi_write_sw(void __iomem *base, u64 val)
+{
+	unsigned long start = get_timer(0);
+
+	val &= ~TWSI_SW_R;
+	val |= TWSI_SW_V;
+
+	debug("%s(%p, 0x%llx)\n", __func__, base, val);
+	writeq(val, base + TWSI_SW_TWSI);
+	do {
+		val = readq(base + TWSI_SW_TWSI);
+	} while ((val & TWSI_SW_V) && (get_timer(start) < 50));
+
+	if (val & TWSI_SW_V)
+		debug("%s: timed out\n", __func__);
+	return val;
+}
+
+/**
+ * Reads the MIO_TWS(0..5)_SW_TWSI register
+ *
+ * @base	Base address of i2c registers
+ * @val		value for eia and op, etc. to read
+ * @return	value of the register
+ */
+static u64 twsi_read_sw(void __iomem *base, u64 val)
+{
+	unsigned long start = get_timer(0);
+
+	val |= TWSI_SW_R | TWSI_SW_V;
+
+	debug("%s(%p, 0x%llx)\n", __func__, base, val);
+	writeq(val, base + TWSI_SW_TWSI);
+
+	do {
+		val = readq(base + TWSI_SW_TWSI);
+	} while ((val & TWSI_SW_V) && (get_timer(start) < 50));
+
+	if (val & TWSI_SW_V)
+		debug("%s: Error writing 0x%llx\n", __func__, val);
+
+	debug("%s: Returning 0x%llx\n", __func__, val);
+	return val;
+}
+
+/**
+ * Write control register
+ *
+ * @base	Base address for i2c registers
+ * @data	data to write
+ */
+static void twsi_write_ctl(void __iomem *base, u8 data)
+{
+	u64 val;
+
+	debug("%s(%p, 0x%x)\n", __func__, base, data);
+	val = data | FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_CTL) |
+		FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA);
+	twsi_write_sw(base, val);
+}
+
+/**
+ * Reads the TWSI Control Register
+ *
+ * @base	Base address for i2c
+ * @return	8-bit TWSI control register
+ */
+static u8 twsi_read_ctl(void __iomem *base)
+{
+	u64 val;
+
+	val = FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_CTL) |
+		FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA);
+	val = twsi_read_sw(base, val);
+
+	debug("%s(%p): 0x%x\n", __func__, base, (u8)val);
+	return (u8)val;
+}
+
+/**
+ * Read i2c status register
+ *
+ * @base	Base address of i2c registers
+ * @return	value of status register
+ */
+static u8 twsi_read_status(void __iomem *base)
+{
+	u64 val;
+
+	val = FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_STAT) |
+		FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA);
+
+	return twsi_read_sw(base, val);
+}
+
+/**
+ * Waits for an i2c operation to complete
+ *
+ * @param	base	Base address of registers
+ * @return	0 for success, 1 if timeout
+ */
+static int twsi_wait(void __iomem *base)
+{
+	unsigned long start = get_timer(0);
+	u8 twsi_ctl;
+
+	debug("%s(%p)\n", __func__, base);
+	do {
+		twsi_ctl = twsi_read_ctl(base);
+		twsi_ctl &= TWSI_CTL_IFLG;
+	} while (!twsi_ctl && get_timer(start) < 50);
+
+	debug("  return: %u\n", !twsi_ctl);
+	return !twsi_ctl;
+}
+
+/**
+ * Unsticks the i2c bus
+ *
+ * @base	base address of registers
+ */
+static int twsi_start_unstick(void __iomem *base)
+{
+	twsi_stop(base);
+	twsi_unblock(base);
+
+	return 0;
+}
+
+/**
+ * Sends an i2c start condition
+ *
+ * @base	base address of registers
+ * @return	0 for success, otherwise error
+ */
+static int twsi_start(void __iomem *base)
+{
+	int ret;
+	u8 stat;
+
+	debug("%s(%p)\n", __func__, base);
+	twsi_write_ctl(base, TWSI_CTL_STA | TWSI_CTL_ENAB);
+	ret = twsi_wait(base);
+	if (ret) {
+		stat = twsi_read_status(base);
+		debug("%s: ret: 0x%x, status: 0x%x\n", __func__, ret, stat);
+		switch (stat) {
+		case TWSI_STAT_START:
+		case TWSI_STAT_RSTART:
+			return 0;
+		case TWSI_STAT_RXADDR_ACK:
+		default:
+			return twsi_start_unstick(base);
+		}
+	}
+
+	debug("%s: success\n", __func__);
+	return 0;
+}
+
+/**
+ * Sends an i2c stop condition
+ *
+ * @base	register base address
+ * @return	0 for success, -1 if error
+ */
+static int twsi_stop(void __iomem *base)
+{
+	u8 stat;
+
+	twsi_write_ctl(base, TWSI_CTL_STP | TWSI_CTL_ENAB);
+
+	stat = twsi_read_status(base);
+	if (stat != TWSI_STAT_IDLE) {
+		debug("%s: Bad status on bus@%p\n", __func__, base);
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * Writes data to the i2c bus
+ *
+ * @base	register base address
+ * @slave_addr	address of slave to write to
+ * @buffer	Pointer to buffer to write
+ * @length	Number of bytes in buffer to write
+ * @return	0 for success, otherwise error
+ */
+static int twsi_write_data(void __iomem *base, u8  slave_addr,
+			   u8 *buffer, unsigned int length)
+{
+	unsigned int curr = 0;
+	u64 val;
+	int ret;
+
+	debug("%s(%p, 0x%x, %p, 0x%x)\n", __func__, base, slave_addr,
+	      buffer, length);
+	ret = twsi_start(base);
+	if (ret) {
+		debug("%s: Could not start BUS transaction\n", __func__);
+		return -1;
+	}
+
+	ret = twsi_wait(base);
+	if (ret) {
+		debug("%s: wait failed\n", __func__);
+		return ret;
+	}
+
+	val = (u32)(slave_addr << 1) | TWSI_OP_WRITE |
+		FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_DATA) |
+		FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA);
+	twsi_write_sw(base, val);
+	twsi_write_ctl(base, TWSI_CTL_ENAB);
+
+	debug("%s: Waiting\n", __func__);
+	ret = twsi_wait(base);
+	if (ret) {
+		debug("%s: Timed out writing slave address 0x%x to target\n",
+		      __func__, slave_addr);
+		return ret;
+	}
+
+	ret = twsi_read_status(base);
+	debug("%s: status: 0x%x\n", __func__, ret);
+	if (ret != TWSI_STAT_TXADDR_ACK) {
+		debug("%s: status: 0x%x\n", __func__, ret);
+		twsi_stop(base);
+		return twsi_i2c_lost_arb(ret, 0);
+	}
+
+	while (curr < length) {
+		val = buffer[curr++] |
+			FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_DATA) |
+			FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA);
+		twsi_write_sw(base, val);
+		twsi_write_ctl(base, TWSI_CTL_ENAB);
+
+		debug("%s: Writing 0x%llx\n", __func__, val);
+
+		ret = twsi_wait(base);
+		if (ret) {
+			debug("%s: Timed out writing data to 0x%x\n",
+			      __func__, slave_addr);
+			return ret;
+		}
+		ret = twsi_read_status(base);
+		debug("%s: status: 0x%x\n", __func__, ret);
+	}
+
+	debug("%s: Stopping\n", __func__);
+	return twsi_stop(base);
+}
+
+/**
+ * Manually clear the I2C bus and send a stop
+ *
+ * @base	register base address
+ */
+static void twsi_unblock(void __iomem *base)
+{
+	int i;
+
+	for (i = 0; i < 9; i++) {
+		writeq(0, base + TWSI_INT);
+		udelay(5);
+		writeq(TWSI_INT_SCL_OVR, base + TWSI_INT);
+		udelay(5);
+	}
+	writeq(TWSI_INT_SCL_OVR | TWSI_INT_SDA_OVR, base + TWSI_INT);
+	udelay(5);
+	writeq(TWSI_INT_SDA_OVR, base + TWSI_INT);
+	udelay(5);
+	writeq(0, base + TWSI_INT);
+	udelay(5);
+}
+
+/**
+ * Performs a read transaction on the i2c bus
+ *
+ * @base	Base address of twsi registers
+ * @slave_addr	i2c bus address to read from
+ * @buffer	buffer to read into
+ * @length	number of bytes to read
+ * @return	0 for success, otherwise error
+ */
+static int twsi_read_data(void __iomem *base, u8 slave_addr,
+			  u8 *buffer, unsigned int length)
+{
+	unsigned int curr = 0;
+	u64 val;
+	int ret;
+
+	debug("%s(%p, 0x%x, %p, %u)\n", __func__, base, slave_addr,
+	      buffer, length);
+	ret = twsi_start(base);
+	if (ret) {
+		debug("%s: start failed\n", __func__);
+		return ret;
+	}
+
+	ret = twsi_wait(base);
+	if (ret) {
+		debug("%s: wait failed\n", __func__);
+		return ret;
+	}
+
+	val = (u32)(slave_addr << 1) | TWSI_OP_READ |
+		FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_DATA) |
+		FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA);
+	twsi_write_sw(base, val);
+	twsi_write_ctl(base, TWSI_CTL_ENAB);
+
+	ret = twsi_wait(base);
+	if (ret) {
+		debug("%s: waiting for sending addr failed\n", __func__);
+		return ret;
+	}
+
+	ret = twsi_read_status(base);
+	debug("%s: status: 0x%x\n", __func__, ret);
+	if (ret != TWSI_STAT_RXADDR_ACK) {
+		debug("%s: status: 0x%x\n", __func__, ret);
+		twsi_stop(base);
+		return twsi_i2c_lost_arb(ret, 0);
+	}
+
+	while (curr < length) {
+		twsi_write_ctl(base, TWSI_CTL_ENAB |
+			       ((curr < length - 1) ? TWSI_CTL_AAK : 0));
+
+		ret = twsi_wait(base);
+		if (ret) {
+			debug("%s: waiting for data failed\n", __func__);
+			return ret;
+		}
+
+		val = twsi_read_sw(base, val);
+		buffer[curr++] = (u8)val;
+	}
+
+	twsi_stop(base);
+
+	return 0;
+}
+
+/**
+ * Calculate the divisor values
+ *
+ * @speed	Speed to set
+ * @m_div	Pointer to M divisor
+ * @n_div	Pointer to N divisor
+ * @return	0 for success, otherwise error
+ */
+static void twsi_calc_div(struct udevice *bus, ulong sclk, unsigned int speed,
+			  int *m_div, int *n_div)
+{
+	struct octeon_twsi *twsi = dev_get_priv(bus);
+	int thp = twsi->data->thp;
+	int tclk, fsamp;
+	int ndiv, mdiv;
+
+	if (twsi->data->clk_method == CLK_METHOD_OCTEON) {
+		tclk = sclk / (2 * (thp + 1));
+	} else {
+		/* Refclk src in mode register defaults to 100MHz clock */
+		sclk = 100000000; /* 100 Mhz */
+		tclk = sclk / (thp + 2);
+	}
+	debug("%s( io_clock %lu tclk %u)\n", __func__, sclk, tclk);
+
+	/*
+	 * Compute the clocks M divider:
+	 *
+	 * TWSI freq = (core freq) / (10 x (M+1) x 2 * (thp+1) x 2^N)
+	 * M = ((core freq) / (10 x (TWSI freq) x 2 * (thp+1) x 2^N)) - 1
+	 *
+	 * For OcteonTX2 -
+	 * TWSI freq = (core freq) / (10 x (M+1) x (thp+2) x 2^N)
+	 * M = ((core freq) / (10 x (TWSI freq) x (thp+2) x 2^N)) - 1
+	 */
+	for (ndiv = 0; ndiv < 8; ndiv++) {
+		fsamp = tclk / (1 << ndiv);
+		mdiv = fsamp / speed / 10;
+		mdiv -= 1;
+		if (mdiv < 16)
+			break;
+	}
+
+	*m_div = mdiv;
+	*n_div = ndiv;
+}
+
+/**
+ * Init I2C controller
+ *
+ * @base	Base address of twsi registers
+ * @slave_addr	I2C slave address to configure this controller to
+ * @return	0 for success, otherwise error
+ */
+static int twsi_init(void __iomem *base, int slaveaddr)
+{
+	u64 val;
+
+	debug("%s (%p, 0x%x)\n", __func__, base, slaveaddr);
+
+	val = slaveaddr << 1 |
+		FIELD_PREP(TWSI_SW_EOP_IA_MASK, 0) |
+		FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA) |
+		TWSI_SW_V;
+	twsi_write_sw(base, val);
+
+	/* Set slave address */
+	val = slaveaddr |
+		FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_EOP_SLAVE_ADDR) |
+		FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA) |
+		TWSI_SW_V;
+	twsi_write_sw(base, val);
+
+	return 0;
+}
+
+/**
+ * Transfers data over the i2c bus
+ *
+ * @bus		i2c bus to transfer data over
+ * @msg		Array of i2c messages
+ * @nmsgs	Number of messages to send/receive
+ * @return	0 for success, otherwise error
+ */
+static int octeon_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
+			   int nmsgs)
+{
+	struct octeon_twsi *twsi = dev_get_priv(bus);
+	int ret;
+	int i;
+
+	debug("%s: %d messages\n", __func__, nmsgs);
+	for (i = 0; i < nmsgs; i++, msg++) {
+		debug("%s: chip=0x%x, len=0x%x\n", __func__, msg->addr,
+		      msg->len);
+
+		if (msg->flags & I2C_M_RD) {
+			debug("%s: Reading data\n", __func__);
+			ret = twsi_read_data(twsi->base, msg->addr,
+					     msg->buf, msg->len);
+		} else {
+			debug("%s: Writing data\n", __func__);
+			ret = twsi_write_data(twsi->base, msg->addr,
+					      msg->buf, msg->len);
+		}
+		if (ret) {
+			debug("%s: error sending\n", __func__);
+			return -EREMOTEIO;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Set I2C bus speed
+ *
+ * @bus		i2c bus to transfer data over
+ * @speed	Speed in Hz to set
+ * @return	0 for success, otherwise error
+ */
+static int octeon_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+	struct octeon_twsi *twsi = dev_get_priv(bus);
+	int m_div, n_div;
+	ulong clk_rate;
+	u64 val;
+
+	debug("%s(%p, %u)\n", __func__, bus, speed);
+
+	clk_rate = clk_get_rate(&twsi->clk);
+	if (IS_ERR_VALUE(clk_rate))
+		return -EINVAL;
+
+	twsi_calc_div(bus, clk_rate, speed, &m_div, &n_div);
+	if (m_div >= 16)
+		return -1;
+
+	val = (u32)(((m_div & 0xf) << 3) | ((n_div & 0x7) << 0)) |
+		FIELD_PREP(TWSI_SW_EOP_IA_MASK, TWSI_CLKCTL) |
+		FIELD_PREP(TWSI_SW_OP_MASK, TWSI_SW_EOP_IA) |
+		TWSI_SW_V;
+	/* Only init non-slave ports */
+	writeq(val, twsi->base + TWSI_SW_TWSI);
+
+	debug("%s: Wrote 0x%llx to sw_twsi\n", __func__, val);
+	return 0;
+}
+
+/**
+ * Driver probe function
+ *
+ * @dev		I2C device to probe
+ * @return	0 for success, otherwise error
+ */
+static int octeon_i2c_probe(struct udevice *dev)
+{
+	struct octeon_twsi *twsi = dev_get_priv(dev);
+	u32 i2c_slave_addr;
+	int ret;
+
+	twsi->data = (const struct octeon_i2c_data *)dev_get_driver_data(dev);
+
+	if (twsi->data->probe == PROBE_PCI) {
+		pci_dev_t bdf = dm_pci_get_bdf(dev);
+
+		debug("TWSI PCI device: %x\n", bdf);
+		dev->req_seq = PCI_FUNC(bdf);
+
+		twsi->base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
+					    PCI_REGION_MEM);
+	} else {
+		twsi->base = dev_remap_addr(dev);
+	}
+	twsi->base += twsi->data->reg_offs;
+
+	i2c_slave_addr = dev_read_u32_default(dev, "i2c-sda-hold-time-ns",
+					      CONFIG_SYS_I2C_OCTEON_SLAVE_ADDR);
+
+	ret = clk_get_by_index(dev, 0, &twsi->clk);
+	if (ret < 0)
+		return ret;
+
+	ret = clk_enable(&twsi->clk);
+	if (ret)
+		return ret;
+
+	debug("TWSI bus %d at %p\n", dev->seq, twsi->base);
+
+	/* Start with standard speed, real speed set via DT or cmd */
+	return twsi_init(twsi->base, i2c_slave_addr);
+}
+
+static const struct dm_i2c_ops octeon_i2c_ops = {
+	.xfer		= octeon_i2c_xfer,
+	.set_bus_speed	= octeon_i2c_set_bus_speed,
+};
+
+static const struct octeon_i2c_data i2c_octeon_data = {
+	.probe = PROBE_DT,
+	.reg_offs = 0x0000,
+	.thp = 3,
+	.clk_method = CLK_METHOD_OCTEON,
+};
+
+static const struct octeon_i2c_data i2c_octeontx_data = {
+	.probe = PROBE_PCI,
+	.reg_offs = 0x8000,
+	.thp = 3,
+	.clk_method = CLK_METHOD_OCTEON,
+};
+
+static const struct octeon_i2c_data i2c_octeontx2_data = {
+	.probe = PROBE_PCI,
+	.reg_offs = 0x8000,
+	.thp = 24,
+	.clk_method = CLK_METHOD_OCTEONTX2,
+};
+
+static const struct udevice_id octeon_i2c_ids[] = {
+	{ .compatible = "cavium,octeon-7890-twsi",
+	  .data = (ulong)&i2c_octeon_data },
+	{ .compatible = "cavium,thunder-8890-twsi",
+	  .data = (ulong)&i2c_octeontx_data },
+	{ .compatible = "cavium,thunder2-99xx-twsi",
+	  .data = (ulong)&i2c_octeontx2_data },
+	{ }
+};
+
+U_BOOT_DRIVER(octeon_pci_twsi) = {
+	.name	= "i2c_octeon",
+	.id	= UCLASS_I2C,
+	.of_match = octeon_i2c_ids,
+	.probe	= octeon_i2c_probe,
+	.priv_auto_alloc_size = sizeof(struct octeon_twsi),
+	.ops	= &octeon_i2c_ops,
+};
+
+static struct pci_device_id octeon_twsi_supported[] = {
+	{ PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_TWSI),
+	  .driver_data = (ulong)&i2c_octeontx2_data },
+	{ },
+};
+
+U_BOOT_PCI_DEVICE(octeon_pci_twsi, octeon_twsi_supported);
diff --git a/drivers/i2c/stm32f7_i2c.c b/drivers/i2c/stm32f7_i2c.c
index ada8f40..2f60911 100644
--- a/drivers/i2c/stm32f7_i2c.c
+++ b/drivers/i2c/stm32f7_i2c.c
@@ -8,7 +8,9 @@
 #include <dm.h>
 #include <i2c.h>
 #include <log.h>
+#include <regmap.h>
 #include <reset.h>
+#include <syscon.h>
 #include <linux/bitops.h>
 #include <linux/delay.h>
 
@@ -154,6 +156,7 @@
  * @fall_time: Fall time (ns)
  * @dnf: Digital filter coefficient (0-16)
  * @analog_filter: Analog filter delay (On/Off)
+ * @fmp_clr_offset: Fast Mode Plus clear register offset from set register
  */
 struct stm32_i2c_setup {
 	u32 speed_freq;
@@ -162,6 +165,7 @@
 	u32 fall_time;
 	u8 dnf;
 	bool analog_filter;
+	u32 fmp_clr_offset;
 };
 
 /**
@@ -181,11 +185,26 @@
 	u8 scll;
 };
 
+/**
+ * struct stm32_i2c_priv - private data of the controller
+ * @regs: I2C registers address
+ * @clk: hw i2c clock
+ * @setup: I2C timing setup parameters
+ * @speed: I2C clock frequency of the controller. Standard, Fast or Fast+
+ * @regmap: holds SYSCFG phandle for Fast Mode Plus bit
+ * @regmap_sreg: register address for setting Fast Mode Plus bits
+ * @regmap_creg: register address for clearing Fast Mode Plus bits
+ * @regmap_mask: mask for Fast Mode Plus bits
+ */
 struct stm32_i2c_priv {
 	struct stm32_i2c_regs *regs;
 	struct clk clk;
 	struct stm32_i2c_setup *setup;
 	u32 speed;
+	struct regmap *regmap;
+	u32 regmap_sreg;
+	u32 regmap_creg;
+	u32 regmap_mask;
 };
 
 static const struct stm32_i2c_spec i2c_specs[] = {
@@ -235,6 +254,14 @@
 	.fall_time = STM32_I2C_FALL_TIME_DEFAULT,
 	.dnf = STM32_I2C_DNF_DEFAULT,
 	.analog_filter = STM32_I2C_ANALOG_FILTER_ENABLE,
+};
+
+static const struct stm32_i2c_setup stm32mp15_setup = {
+	.rise_time = STM32_I2C_RISE_TIME_DEFAULT,
+	.fall_time = STM32_I2C_FALL_TIME_DEFAULT,
+	.dnf = STM32_I2C_DNF_DEFAULT,
+	.analog_filter = STM32_I2C_ANALOG_FILTER_ENABLE,
+	.fmp_clr_offset = 0x40,
 };
 
 static int stm32_i2c_check_device_busy(struct stm32_i2c_priv *i2c_priv)
@@ -761,6 +788,29 @@
 	return 0;
 }
 
+static int stm32_i2c_write_fm_plus_bits(struct stm32_i2c_priv *i2c_priv)
+{
+	int ret;
+	bool enable = i2c_priv->speed > I2C_SPEED_FAST_RATE;
+
+	/* Optional */
+	if (IS_ERR_OR_NULL(i2c_priv->regmap))
+		return 0;
+
+	if (i2c_priv->regmap_sreg == i2c_priv->regmap_creg)
+		ret = regmap_update_bits(i2c_priv->regmap,
+					 i2c_priv->regmap_sreg,
+					 i2c_priv->regmap_mask,
+					 enable ? i2c_priv->regmap_mask : 0);
+	else
+		ret = regmap_write(i2c_priv->regmap,
+				   enable ? i2c_priv->regmap_sreg :
+					    i2c_priv->regmap_creg,
+				   i2c_priv->regmap_mask);
+
+	return ret;
+}
+
 static int stm32_i2c_hw_config(struct stm32_i2c_priv *i2c_priv)
 {
 	struct stm32_i2c_regs *regs = i2c_priv->regs;
@@ -775,6 +825,11 @@
 	/* Disable I2C */
 	clrbits_le32(&regs->cr1, STM32_I2C_CR1_PE);
 
+	/* Setup Fast mode plus if necessary */
+	ret = stm32_i2c_write_fm_plus_bits(i2c_priv);
+	if (ret)
+		return ret;
+
 	/* Timing settings */
 	timing |= STM32_I2C_TIMINGR_PRESC(t.presc);
 	timing |= STM32_I2C_TIMINGR_SCLDEL(t.scldel);
@@ -850,6 +905,7 @@
 {
 	struct stm32_i2c_priv *i2c_priv = dev_get_priv(dev);
 	u32 rise_time, fall_time;
+	int ret;
 
 	i2c_priv->setup = (struct stm32_i2c_setup *)dev_get_driver_data(dev);
 	if (!i2c_priv->setup)
@@ -863,6 +919,22 @@
 	if (fall_time)
 		i2c_priv->setup->fall_time = fall_time;
 
+	/* Optional */
+	i2c_priv->regmap = syscon_regmap_lookup_by_phandle(dev,
+							   "st,syscfg-fmp");
+	if (!IS_ERR(i2c_priv->regmap)) {
+		u32 fmp[3];
+
+		ret = dev_read_u32_array(dev, "st,syscfg-fmp", fmp, 3);
+		if (ret)
+			return ret;
+
+		i2c_priv->regmap_sreg = fmp[1];
+		i2c_priv->regmap_creg = fmp[1] +
+					i2c_priv->setup->fmp_clr_offset;
+		i2c_priv->regmap_mask = fmp[2];
+	}
+
 	return 0;
 }
 
@@ -873,6 +945,7 @@
 
 static const struct udevice_id stm32_i2c_of_match[] = {
 	{ .compatible = "st,stm32f7-i2c", .data = (ulong)&stm32f7_setup },
+	{ .compatible = "st,stm32mp15-i2c", .data = (ulong)&stm32mp15_setup },
 	{}
 };
 
diff --git a/drivers/net/mvpp2.c b/drivers/net/mvpp2.c
index 19b9375..a5747a2 100644
--- a/drivers/net/mvpp2.c
+++ b/drivers/net/mvpp2.c
@@ -1263,6 +1263,7 @@
  * can be enabled at once
  */
 static struct buffer_location buffer_loc;
+static int buffer_loc_init;
 
 /*
  * Page table entries are set to 1MB, or multiples of 1MB
@@ -5247,39 +5248,43 @@
 	 * be active. Make this area DMA-safe by disabling the D-cache
 	 */
 
-	/* Align buffer area for descs and rx_buffers to 1MiB */
-	bd_space = memalign(1 << MMU_SECTION_SHIFT, BD_SPACE);
-	mmu_set_region_dcache_behaviour((unsigned long)bd_space,
-					BD_SPACE, DCACHE_OFF);
+	if (!buffer_loc_init) {
+		/* Align buffer area for descs and rx_buffers to 1MiB */
+		bd_space = memalign(1 << MMU_SECTION_SHIFT, BD_SPACE);
+		mmu_set_region_dcache_behaviour((unsigned long)bd_space,
+						BD_SPACE, DCACHE_OFF);
 
-	buffer_loc.aggr_tx_descs = (struct mvpp2_tx_desc *)bd_space;
-	size += MVPP2_AGGR_TXQ_SIZE * MVPP2_DESC_ALIGNED_SIZE;
+		buffer_loc.aggr_tx_descs = (struct mvpp2_tx_desc *)bd_space;
+		size += MVPP2_AGGR_TXQ_SIZE * MVPP2_DESC_ALIGNED_SIZE;
 
-	buffer_loc.tx_descs =
-		(struct mvpp2_tx_desc *)((unsigned long)bd_space + size);
-	size += MVPP2_MAX_TXD * MVPP2_DESC_ALIGNED_SIZE;
+		buffer_loc.tx_descs =
+			(struct mvpp2_tx_desc *)((unsigned long)bd_space + size);
+		size += MVPP2_MAX_TXD * MVPP2_DESC_ALIGNED_SIZE;
 
-	buffer_loc.rx_descs =
-		(struct mvpp2_rx_desc *)((unsigned long)bd_space + size);
-	size += MVPP2_MAX_RXD * MVPP2_DESC_ALIGNED_SIZE;
+		buffer_loc.rx_descs =
+			(struct mvpp2_rx_desc *)((unsigned long)bd_space + size);
+		size += MVPP2_MAX_RXD * MVPP2_DESC_ALIGNED_SIZE;
 
-	for (i = 0; i < MVPP2_BM_POOLS_NUM; i++) {
-		buffer_loc.bm_pool[i] =
-			(unsigned long *)((unsigned long)bd_space + size);
-		if (priv->hw_version == MVPP21)
-			size += MVPP2_BM_POOL_SIZE_MAX * 2 * sizeof(u32);
-		else
-			size += MVPP2_BM_POOL_SIZE_MAX * 2 * sizeof(u64);
-	}
+		for (i = 0; i < MVPP2_BM_POOLS_NUM; i++) {
+			buffer_loc.bm_pool[i] =
+				(unsigned long *)((unsigned long)bd_space + size);
+			if (priv->hw_version == MVPP21)
+				size += MVPP2_BM_POOL_SIZE_MAX * 2 * sizeof(u32);
+			else
+				size += MVPP2_BM_POOL_SIZE_MAX * 2 * sizeof(u64);
+		}
 
-	for (i = 0; i < MVPP2_BM_LONG_BUF_NUM; i++) {
-		buffer_loc.rx_buffer[i] =
-			(unsigned long *)((unsigned long)bd_space + size);
-		size += RX_BUFFER_SIZE;
-	}
+		for (i = 0; i < MVPP2_BM_LONG_BUF_NUM; i++) {
+			buffer_loc.rx_buffer[i] =
+				(unsigned long *)((unsigned long)bd_space + size);
+			size += RX_BUFFER_SIZE;
+		}
 
-	/* Clear the complete area so that all descriptors are cleared */
-	memset(bd_space, 0, size);
+		/* Clear the complete area so that all descriptors are cleared */
+		memset(bd_space, 0, size);
+
+		buffer_loc_init = 1;
+	}
 
 	/* Save base addresses for later use */
 	priv->base = (void *)devfdt_get_addr_index(dev, 0);
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index edb3f0f..61eb468 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -47,6 +47,12 @@
 	  useful. The PWM can be enabled but is not connected to any outputs
 	  so this is not very useful.
 
+config PWM_SIFIVE
+	bool "Enable support for SiFive PWM"
+	depends on DM_PWM
+	help
+	  This PWM is found SiFive's FU540 and other SoCs.
+
 config PWM_TEGRA
 	bool "Enable support for the Tegra PWM"
 	depends on DM_PWM
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 2c3a069..0f4e84b 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -15,5 +15,6 @@
 obj-$(CONFIG_PWM_MTK)		+= pwm-mtk.o
 obj-$(CONFIG_PWM_ROCKCHIP)	+= rk_pwm.o
 obj-$(CONFIG_PWM_SANDBOX)	+= sandbox_pwm.o
+obj-$(CONFIG_PWM_SIFIVE)	+= pwm-sifive.o
 obj-$(CONFIG_PWM_TEGRA)		+= tegra_pwm.o
 obj-$(CONFIG_PWM_SUNXI)		+= sunxi_pwm.o
diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c
new file mode 100644
index 0000000..77bc659
--- /dev/null
+++ b/drivers/pwm/pwm-sifive.c
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 SiFive, Inc
+ * For SiFive's PWM IP block documentation please refer Chapter 14 of
+ * Reference Manual : https://static.dev.sifive.com/FU540-C000-v1.0.pdf
+ *
+ * Limitations:
+ * - When changing both duty cycle and period, we cannot prevent in
+ *   software that the output might produce a period with mixed
+ *   settings (new period length and old duty cycle).
+ * - The hardware cannot generate a 100% duty cycle.
+ * - The hardware generates only inverted output.
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <div64.h>
+#include <dm.h>
+#include <pwm.h>
+#include <regmap.h>
+#include <linux/io.h>
+#include <linux/log2.h>
+#include <linux/bitfield.h>
+
+/* PWMCFG fields */
+#define PWM_SIFIVE_PWMCFG_SCALE         GENMASK(3, 0)
+#define PWM_SIFIVE_PWMCFG_STICKY        BIT(8)
+#define PWM_SIFIVE_PWMCFG_ZERO_CMP      BIT(9)
+#define PWM_SIFIVE_PWMCFG_DEGLITCH      BIT(10)
+#define PWM_SIFIVE_PWMCFG_EN_ALWAYS     BIT(12)
+#define PWM_SIFIVE_PWMCFG_EN_ONCE       BIT(13)
+#define PWM_SIFIVE_PWMCFG_CENTER        BIT(16)
+#define PWM_SIFIVE_PWMCFG_GANG          BIT(24)
+#define PWM_SIFIVE_PWMCFG_IP            BIT(28)
+
+/* PWM_SIFIVE_SIZE_PWMCMP is used to calculate offset for pwmcmpX registers */
+#define PWM_SIFIVE_SIZE_PWMCMP          4
+#define PWM_SIFIVE_CMPWIDTH             16
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct pwm_sifive_regs {
+	unsigned long cfg;
+	unsigned long cnt;
+	unsigned long pwms;
+	unsigned long cmp0;
+};
+
+struct pwm_sifive_data {
+	struct pwm_sifive_regs regs;
+};
+
+struct pwm_sifive_priv {
+	void __iomem *base;
+	ulong freq;
+	const struct pwm_sifive_data *data;
+};
+
+static int pwm_sifive_set_config(struct udevice *dev, uint channel,
+				 uint period_ns, uint duty_ns)
+{
+	struct pwm_sifive_priv *priv = dev_get_priv(dev);
+	const struct pwm_sifive_regs *regs = &priv->data->regs;
+	unsigned long scale_pow;
+	unsigned long long num;
+	u32 scale, val = 0, frac;
+
+	debug("%s: period_ns=%u, duty_ns=%u\n", __func__, period_ns, duty_ns);
+
+	/*
+	 * The PWM unit is used with pwmzerocmp=0, so the only way to modify the
+	 * period length is using pwmscale which provides the number of bits the
+	 * counter is shifted before being feed to the comparators. A period
+	 * lasts (1 << (PWM_SIFIVE_CMPWIDTH + pwmscale)) clock ticks.
+	 * (1 << (PWM_SIFIVE_CMPWIDTH + scale)) * 10^9/rate = period
+	 */
+	scale_pow = lldiv((uint64_t)priv->freq * period_ns, 1000000000);
+	scale = clamp(ilog2(scale_pow) - PWM_SIFIVE_CMPWIDTH, 0, 0xf);
+	val |= FIELD_PREP(PWM_SIFIVE_PWMCFG_SCALE, scale);
+
+	/*
+	 * The problem of output producing mixed setting as mentioned at top,
+	 * occurs here. To minimize the window for this problem, we are
+	 * calculating the register values first and then writing them
+	 * consecutively
+	 */
+	num = (u64)duty_ns * (1U << PWM_SIFIVE_CMPWIDTH);
+	frac = DIV_ROUND_CLOSEST_ULL(num, period_ns);
+	frac = min(frac, (1U << PWM_SIFIVE_CMPWIDTH) - 1);
+
+	writel(val, priv->base + regs->cfg);
+	writel(frac, priv->base + regs->cmp0 + channel *
+	       PWM_SIFIVE_SIZE_PWMCMP);
+
+	return 0;
+}
+
+static int pwm_sifive_set_enable(struct udevice *dev, uint channel, bool enable)
+{
+	struct pwm_sifive_priv *priv = dev_get_priv(dev);
+	const struct pwm_sifive_regs *regs = &priv->data->regs;
+	u32 val;
+
+	debug("%s: Enable '%s'\n", __func__, dev->name);
+
+	if (enable) {
+		val = readl(priv->base + regs->cfg);
+		val |= PWM_SIFIVE_PWMCFG_EN_ALWAYS;
+		writel(val, priv->base + regs->cfg);
+	} else {
+		writel(0, priv->base + regs->cmp0 + channel *
+		       PWM_SIFIVE_SIZE_PWMCMP);
+	}
+
+	return 0;
+}
+
+static int pwm_sifive_ofdata_to_platdata(struct udevice *dev)
+{
+	struct pwm_sifive_priv *priv = dev_get_priv(dev);
+
+	priv->base = dev_read_addr_ptr(dev);
+
+	return 0;
+}
+
+static int pwm_sifive_probe(struct udevice *dev)
+{
+	struct pwm_sifive_priv *priv = dev_get_priv(dev);
+	struct clk clk;
+	int ret = 0;
+
+	ret = clk_get_by_index(dev, 0, &clk);
+	if (ret < 0) {
+		debug("%s get clock fail!\n", __func__);
+		return -EINVAL;
+	}
+
+	priv->freq = clk_get_rate(&clk);
+	priv->data = (struct pwm_sifive_data *)dev_get_driver_data(dev);
+
+	return 0;
+}
+
+static const struct pwm_ops pwm_sifive_ops = {
+	.set_config	= pwm_sifive_set_config,
+	.set_enable	= pwm_sifive_set_enable,
+};
+
+static const struct pwm_sifive_data pwm_data = {
+	.regs = {
+		.cfg = 0x00,
+		.cnt = 0x08,
+		.pwms = 0x10,
+		.cmp0 = 0x20,
+	},
+};
+
+static const struct udevice_id pwm_sifive_ids[] = {
+	{ .compatible = "sifive,pwm0", .data = (ulong)&pwm_data},
+	{ }
+};
+
+U_BOOT_DRIVER(pwm_sifive) = {
+	.name	= "pwm_sifive",
+	.id	= UCLASS_PWM,
+	.of_match = pwm_sifive_ids,
+	.ops	= &pwm_sifive_ops,
+	.ofdata_to_platdata     = pwm_sifive_ofdata_to_platdata,
+	.probe		= pwm_sifive_probe,
+	.priv_auto_alloc_size	= sizeof(struct pwm_sifive_priv),
+};
diff --git a/drivers/rtc/i2c_rtc_emul.c b/drivers/rtc/i2c_rtc_emul.c
index a010af4..7f78ff8 100644
--- a/drivers/rtc/i2c_rtc_emul.c
+++ b/drivers/rtc/i2c_rtc_emul.c
@@ -197,7 +197,8 @@
 
 			/* Write the register */
 			memcpy(plat->reg + offset, ptr, len);
-			if (offset == REG_RESET)
+			/* If the reset register was written to, do reset. */
+			if (offset <= REG_RESET && REG_RESET < offset + len)
 				reset_time(emul);
 		}
 	}
diff --git a/drivers/rtc/pcf2127.c b/drivers/rtc/pcf2127.c
index c423960..88ff8c5 100644
--- a/drivers/rtc/pcf2127.c
+++ b/drivers/rtc/pcf2127.c
@@ -23,8 +23,7 @@
 #define PCF2127_REG_MO		0x08
 #define PCF2127_REG_YR		0x09
 
-static int pcf2127_read_reg(struct udevice *dev, uint offset,
-			    u8 *buffer, int len)
+static int pcf2127_rtc_read(struct udevice *dev, uint offset, u8 *buffer, uint len)
 {
 	struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
 	struct i2c_msg msg;
@@ -44,6 +43,12 @@
 	return dm_i2c_xfer(dev, &msg, 1);
 }
 
+static int pcf2127_rtc_write(struct udevice *dev, uint offset,
+			     const u8 *buffer, uint len)
+{
+	return dm_i2c_write(dev, offset, buffer, len);
+}
+
 static int pcf2127_rtc_set(struct udevice *dev, const struct rtc_time *tm)
 {
 	uchar buf[7] = {0};
@@ -73,7 +78,7 @@
 	int ret = 0;
 	uchar buf[10] = { PCF2127_REG_CTRL1 };
 
-	ret = pcf2127_read_reg(dev, PCF2127_REG_CTRL1, buf, sizeof(buf));
+	ret = pcf2127_rtc_read(dev, PCF2127_REG_CTRL1, buf, sizeof(buf));
 	if (ret < 0)
 		return ret;
 
@@ -110,6 +115,8 @@
 	.get = pcf2127_rtc_get,
 	.set = pcf2127_rtc_set,
 	.reset = pcf2127_rtc_reset,
+	.read = pcf2127_rtc_read,
+	.write = pcf2127_rtc_write,
 };
 
 static const struct udevice_id pcf2127_rtc_ids[] = {
diff --git a/drivers/rtc/rtc-uclass.c b/drivers/rtc/rtc-uclass.c
index 926cca2..8035f7f 100644
--- a/drivers/rtc/rtc-uclass.c
+++ b/drivers/rtc/rtc-uclass.c
@@ -40,24 +40,75 @@
 	return ops->reset(dev);
 }
 
-int rtc_read8(struct udevice *dev, unsigned int reg)
+int dm_rtc_read(struct udevice *dev, unsigned int reg, u8 *buf, unsigned int len)
 {
 	struct rtc_ops *ops = rtc_get_ops(dev);
 
 	assert(ops);
+	if (ops->read)
+		return ops->read(dev, reg, buf, len);
 	if (!ops->read8)
 		return -ENOSYS;
-	return ops->read8(dev, reg);
+	while (len--) {
+		int ret = ops->read8(dev, reg++);
+
+		if (ret < 0)
+			return ret;
+		*buf++ = ret;
+	}
+	return 0;
 }
 
-int rtc_write8(struct udevice *dev, unsigned int reg, int val)
+int dm_rtc_write(struct udevice *dev, unsigned int reg,
+		 const u8 *buf, unsigned int len)
 {
 	struct rtc_ops *ops = rtc_get_ops(dev);
 
 	assert(ops);
+	if (ops->write)
+		return ops->write(dev, reg, buf, len);
 	if (!ops->write8)
 		return -ENOSYS;
-	return ops->write8(dev, reg, val);
+	while (len--) {
+		int ret = ops->write8(dev, reg++, *buf++);
+
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
+
+int rtc_read8(struct udevice *dev, unsigned int reg)
+{
+	struct rtc_ops *ops = rtc_get_ops(dev);
+
+	assert(ops);
+	if (ops->read8)
+		return ops->read8(dev, reg);
+	if (ops->read) {
+		u8 buf[1];
+		int ret = ops->read(dev, reg, buf, 1);
+
+		if (ret < 0)
+			return ret;
+		return buf[0];
+	}
+	return -ENOSYS;
+}
+
+int rtc_write8(struct udevice *dev, unsigned int reg, int val)
+{
+	struct rtc_ops *ops = rtc_get_ops(dev);
+
+	assert(ops);
+	if (ops->write8)
+		return ops->write8(dev, reg, val);
+	if (ops->write) {
+		u8 buf[1] = { val };
+
+		return ops->write(dev, reg, buf, 1);
+	}
+	return -ENOSYS;
 }
 
 int rtc_read16(struct udevice *dev, unsigned int reg, u16 *valuep)
diff --git a/drivers/rtc/sandbox_rtc.c b/drivers/rtc/sandbox_rtc.c
index b08d758..77065e4 100644
--- a/drivers/rtc/sandbox_rtc.c
+++ b/drivers/rtc/sandbox_rtc.c
@@ -14,55 +14,38 @@
 
 static int sandbox_rtc_get(struct udevice *dev, struct rtc_time *time)
 {
-	time->tm_sec = dm_i2c_reg_read(dev, REG_SEC);
-	if (time->tm_sec < 0)
-		return time->tm_sec;
-	time->tm_min = dm_i2c_reg_read(dev, REG_MIN);
-	if (time->tm_min < 0)
-		return time->tm_min;
-	time->tm_hour = dm_i2c_reg_read(dev, REG_HOUR);
-	if (time->tm_hour < 0)
-		return time->tm_hour;
-	time->tm_mday = dm_i2c_reg_read(dev, REG_MDAY);
-	if (time->tm_mday < 0)
-		return time->tm_mday;
-	time->tm_mon = dm_i2c_reg_read(dev, REG_MON);
-	if (time->tm_mon < 0)
-		return time->tm_mon;
-	time->tm_year = dm_i2c_reg_read(dev, REG_YEAR);
-	if (time->tm_year < 0)
-		return time->tm_year;
-	time->tm_year += 1900;
-	time->tm_wday = dm_i2c_reg_read(dev, REG_WDAY);
-	if (time->tm_wday < 0)
-		return time->tm_wday;
+	u8 buf[7];
+	int ret;
+
+	ret = dm_i2c_read(dev, REG_SEC, buf, sizeof(buf));
+	if (ret < 0)
+		return ret;
+
+	time->tm_sec  = buf[REG_SEC - REG_SEC];
+	time->tm_min  = buf[REG_MIN - REG_SEC];
+	time->tm_hour = buf[REG_HOUR - REG_SEC];
+	time->tm_mday = buf[REG_MDAY - REG_SEC];
+	time->tm_mon  = buf[REG_MON - REG_SEC];
+	time->tm_year = buf[REG_YEAR - REG_SEC] + 1900;
+	time->tm_wday = buf[REG_WDAY - REG_SEC];
 
 	return 0;
 }
 
 static int sandbox_rtc_set(struct udevice *dev, const struct rtc_time *time)
 {
+	u8 buf[7];
 	int ret;
 
-	ret = dm_i2c_reg_write(dev, REG_SEC, time->tm_sec);
-	if (ret < 0)
-		return ret;
-	ret = dm_i2c_reg_write(dev, REG_MIN, time->tm_min);
-	if (ret < 0)
-		return ret;
-	ret = dm_i2c_reg_write(dev, REG_HOUR, time->tm_hour);
-	if (ret < 0)
-		return ret;
-	ret = dm_i2c_reg_write(dev, REG_MDAY, time->tm_mday);
-	if (ret < 0)
-		return ret;
-	ret = dm_i2c_reg_write(dev, REG_MON, time->tm_mon);
-	if (ret < 0)
-		return ret;
-	ret = dm_i2c_reg_write(dev, REG_YEAR, time->tm_year - 1900);
-	if (ret < 0)
-		return ret;
-	ret = dm_i2c_reg_write(dev, REG_WDAY, time->tm_wday);
+	buf[REG_SEC - REG_SEC]  = time->tm_sec;
+	buf[REG_MIN - REG_SEC]  = time->tm_min;
+	buf[REG_HOUR - REG_SEC] = time->tm_hour;
+	buf[REG_MDAY - REG_SEC] = time->tm_mday;
+	buf[REG_MON  - REG_SEC] = time->tm_mon;
+	buf[REG_YEAR - REG_SEC] = time->tm_year - 1900;
+	buf[REG_WDAY - REG_SEC] = time->tm_wday;
+
+	ret = dm_i2c_write(dev, REG_SEC, buf, sizeof(buf));
 	if (ret < 0)
 		return ret;
 
diff --git a/include/configs/helios4.h b/include/configs/helios4.h
index 31e2e78..2f4b670 100644
--- a/include/configs/helios4.h
+++ b/include/configs/helios4.h
@@ -6,7 +6,6 @@
 #ifndef _CONFIG_HELIOS4_H
 #define _CONFIG_HELIOS4_H
 
-#include <linux/sizes.h>
 #include <linux/stringify.h>
 
 /*
@@ -30,26 +29,30 @@
 
 #define CONFIG_ENV_MIN_ENTRIES		128
 
+/* Environment in MMC */
+#define CONFIG_SYS_MMC_ENV_DEV		0
 /*
- * SATA/SCSI/AHCI configuration
+ * For SD - reserve 1 LBA for MBR + 1M for u-boot image. The MMC/eMMC
+ * boot image starts @ LBA-0.
+ * As result in MMC/eMMC case it will be a 1 sector gap between u-boot
+ * image and environment
  */
-#define CONFIG_SCSI_AHCI_PLAT
-#define CONFIG_SYS_SCSI_MAX_SCSI_ID     2
-#define CONFIG_SYS_SCSI_MAX_LUN         2
-#define CONFIG_SYS_SCSI_MAX_DEVICE      (CONFIG_SYS_SCSI_MAX_SCSI_ID * \
-					CONFIG_SYS_SCSI_MAX_LUN)
 
-#ifdef CONFIG_MVEBU_SPL_BOOT_DEVICE_SPI
-/* Environment in SPI NOR flash */
-#endif
+#define PHY_ANEG_TIMEOUT	8000	/* PHY needs a longer aneg time */
 
-#ifdef CONFIG_MVEBU_SPL_BOOT_DEVICE_MMC
-/* Environment in MMC */
-#define CONFIG_SYS_MMC_ENV_DEV		0
-/* stay within first 1M */
+/* PCIe support */
+#ifndef CONFIG_SPL_BUILD
+#define CONFIG_PCI_SCAN_SHOW
 #endif
 
-#define PHY_ANEG_TIMEOUT	8000	/* PHY needs a longer aneg time */
+/* SATA support */
+#ifdef CONFIG_SCSI
+#define CONFIG_SCSI_AHCI_PLAT
+#define CONFIG_SYS_SCSI_MAX_SCSI_ID	1
+#define CONFIG_SYS_SCSI_MAX_LUN		1
+#define CONFIG_SYS_SCSI_MAX_DEVICE	(CONFIG_SYS_SCSI_MAX_SCSI_ID * \
+					CONFIG_SYS_SCSI_MAX_LUN)
+#endif
 
 /* Keep device tree and initrd in lower memory so the kernel can access them */
 #define RELOCATION_LIMITS_ENV_SETTINGS	\
@@ -57,22 +60,6 @@
 	"initrd_high=0x10000000\0"
 
 /* SPL */
-/*
- * Select the boot device here
- *
- * Currently supported are:
- * SPL_BOOT_SPI_NOR_FLASH	- Booting via SPI NOR flash
- * SPL_BOOT_SDIO_MMC_CARD	- Booting via SDIO/MMC card (partition 1)
- */
-#define SPL_BOOT_SPI_NOR_FLASH		1
-#define SPL_BOOT_SDIO_MMC_CARD		2
-
-#ifdef CONFIG_MVEBU_SPL_BOOT_DEVICE_SPI
-#define CONFIG_SPL_BOOT_DEVICE		SPL_BOOT_SPI_NOR_FLASH
-#endif
-#ifdef CONFIG_MVEBU_SPL_BOOT_DEVICE_MMC
-#define CONFIG_SPL_BOOT_DEVICE		SPL_BOOT_SDIO_MMC_CARD
-#endif
 
 /* Defines for SPL */
 #define CONFIG_SPL_SIZE			(140 << 10)
@@ -88,11 +75,10 @@
 #define CONFIG_SPL_STACK		(0x40000000 + ((192 - 16) << 10))
 #define CONFIG_SPL_BOOTROM_SAVE		(CONFIG_SPL_STACK + 4)
 
-#if CONFIG_SPL_BOOT_DEVICE == SPL_BOOT_SPI_NOR_FLASH
+#if defined(CONFIG_MVEBU_SPL_BOOT_DEVICE_SPI)
+/* SPL related SPI defines */
 #define CONFIG_SYS_U_BOOT_OFFS		CONFIG_SYS_SPI_U_BOOT_OFFS
-#endif
-
-#if CONFIG_SPL_BOOT_DEVICE == SPL_BOOT_SDIO_MMC_CARD
+#elif defined(CONFIG_MVEBU_SPL_BOOT_DEVICE_MMC) || defined(CONFIG_MVEBU_SPL_BOOT_DEVICE_SATA)
 /* SPL related MMC defines */
 #define CONFIG_SYS_MMC_U_BOOT_OFFS		(160 << 10)
 #define CONFIG_SYS_U_BOOT_OFFS			CONFIG_SYS_MMC_U_BOOT_OFFS
@@ -100,6 +86,7 @@
 #define CONFIG_FIXED_SDHCI_ALIGNED_BUFFER	0x00180000	/* in SDRAM */
 #endif
 #endif
+
 /*
  * mv-common.h should be defined after CMD configs since it used them
  * to enable certain macros
@@ -121,16 +108,46 @@
 #define BOOT_TARGET_DEVICES_USB(func)
 #endif
 
+#ifndef CONFIG_SCSI
+#define BOOT_TARGET_DEVICES_SCSI_BUS0(func)
+#define BOOT_TARGET_DEVICES_SCSI_BUS1(func)
+#define BOOT_TARGET_DEVICES_SCSI_BUS2(func)
+#else
+/*
+ * With SCSI enabled, M.2 SATA is always located on bus 0
+ */
+#define BOOT_TARGET_DEVICES_SCSI_BUS0(func) func(SCSI, scsi, 0)
+
+/*
+ * Either one or both mPCIe slots may be configured as mSATA interfaces. The
+ * SCSI bus ids are assigned based on sequence of hardware present, not always
+ * tied to hardware slot ids. As such, use second SCSI bus if either slot is
+ * set for SATA, and only use third SCSI bus if both slots are SATA enabled.
+ */
+#if defined (CONFIG_HELIOS4_CON2_SATA) || defined (CONFIG_HELIOS4_CON3_SATA)
+#define BOOT_TARGET_DEVICES_SCSI_BUS1(func) func(SCSI, scsi, 1)
+#else
+#define BOOT_TARGET_DEVICES_SCSI_BUS1(func)
+#endif
+
-#ifdef CONFIG_SATA
-#define BOOT_TARGET_DEVICES_SATA(func) func(SATA, sata, 0)
+#if defined (CONFIG_HELIOS4_CON2_SATA) && defined (CONFIG_HELIOS4_CON3_SATA)
+#define BOOT_TARGET_DEVICES_SCSI_BUS2(func) func(SCSI, scsi, 2)
 #else
-#define BOOT_TARGET_DEVICES_SATA(func)
+#define BOOT_TARGET_DEVICES_SCSI_BUS2(func)
 #endif
 
+#endif /* CONFIG_SCSI */
+
+/*
+ * The SCSI buses are attempted in increasing bus order, there is no current
+ * mechanism to alter the default bus priority order for booting.
+ */
 #define BOOT_TARGET_DEVICES(func) \
 	BOOT_TARGET_DEVICES_MMC(func) \
 	BOOT_TARGET_DEVICES_USB(func) \
-	BOOT_TARGET_DEVICES_SATA(func) \
+	BOOT_TARGET_DEVICES_SCSI_BUS0(func) \
+	BOOT_TARGET_DEVICES_SCSI_BUS1(func) \
+	BOOT_TARGET_DEVICES_SCSI_BUS2(func) \
 	func(PXE, pxe, na) \
 	func(DHCP, dhcp, na)
 
diff --git a/include/configs/lacie_kw.h b/include/configs/lacie_kw.h
index 5bb0255..031bc99 100644
--- a/include/configs/lacie_kw.h
+++ b/include/configs/lacie_kw.h
@@ -83,18 +83,17 @@
 /*
  * SATA Driver configuration
  */
-#ifdef CONFIG_MVSATA_IDE
-#define CONFIG_SYS_ATA_IDE0_OFFSET      MV_SATA_PORT0_OFFSET
+
+#ifdef CONFIG_SATA
+#define CONFIG_SYS_64BIT_LBA
+#define CONFIG_LBA48
 #if defined(CONFIG_NETSPACE_MAX_V2) || defined(CONFIG_D2NET_V2) || \
 	defined(CONFIG_NET2BIG_V2)
-#define CONFIG_SYS_ATA_IDE1_OFFSET      MV_SATA_PORT1_OFFSET
-#define CONFIG_SYS_IDE_MAXBUS           2
-#define CONFIG_SYS_IDE_MAXDEVICE        2
+#define CONFIG_SYS_SATA_MAX_DEVICE	2
 #else
-#define CONFIG_SYS_IDE_MAXBUS           1
-#define CONFIG_SYS_IDE_MAXDEVICE        1
+#define CONFIG_SYS_SATA_MAX_DEVICE	1
 #endif
-#endif /* CONFIG_MVSATA_IDE */
+#endif /* CONFIG_SATA */
 
 /*
  * Enable GPI0 support
@@ -144,8 +143,8 @@
 		"set stdin $stdin,nc; "				\
 		"set stdout $stdout,nc; "			\
 		"set stderr $stderr,nc;\0"			\
-	"diskload=ide reset && "				\
-		"ext2load ide 0:1 $loadaddr /boot/$bootfile\0"	\
+	"diskload=sata init && "				\
+		"ext2load sata 0:1 $loadaddr /boot/$bootfile\0"	\
 	"usbload=usb start && "					\
 		"fatload usb 0:1 $loadaddr /boot/$bootfile\0"
 
diff --git a/include/rtc.h b/include/rtc.h
index 8aabfc1..1efc0db 100644
--- a/include/rtc.h
+++ b/include/rtc.h
@@ -56,6 +56,30 @@
 	int (*reset)(struct udevice *dev);
 
 	/**
+	 * read() - Read multiple 8-bit registers
+	 *
+	 * @dev:	Device to read from
+	 * @reg:	First register to read
+	 * @buf:	Output buffer
+	 * @len:	Number of registers to read
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*read)(struct udevice *dev, unsigned int reg,
+		    u8 *buf, unsigned int len);
+
+	/**
+	 * write() - Write multiple 8-bit registers
+	 *
+	 * @dev:	Device to write to
+	 * @reg:	First register to write
+	 * @buf:	Input buffer
+	 * @len:	Number of registers to write
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*write)(struct udevice *dev, unsigned int reg,
+		     const u8 *buf, unsigned int len);
+
+	/**
 	 * read8() - Read an 8-bit register
 	 *
 	 * @dev:	Device to read from
@@ -110,6 +134,29 @@
 int dm_rtc_reset(struct udevice *dev);
 
 /**
+ * dm_rtc_read() - Read multiple 8-bit registers
+ *
+ * @dev:	Device to read from
+ * @reg:	First register to read
+ * @buf:	Output buffer
+ * @len:	Number of registers to read
+ * @return 0 if OK, -ve on error
+ */
+int dm_rtc_read(struct udevice *dev, unsigned int reg, u8 *buf, unsigned int len);
+
+/**
+ * dm_rtc_write() - Write multiple 8-bit registers
+ *
+ * @dev:	Device to write to
+ * @reg:	First register to write
+ * @buf:	Input buffer
+ * @len:	Number of registers to write
+ * @return 0 if OK, -ve on error
+ */
+int dm_rtc_write(struct udevice *dev, unsigned int reg,
+		 const u8 *buf, unsigned int len);
+
+/**
  * rtc_read8() - Read an 8-bit register
  *
  * @dev:	Device to read from
diff --git a/test/dm/rtc.c b/test/dm/rtc.c
index 88f8658..dd037a6 100644
--- a/test/dm/rtc.c
+++ b/test/dm/rtc.c
@@ -5,11 +5,13 @@
  */
 
 #include <common.h>
+#include <console.h>
 #include <dm.h>
 #include <i2c.h>
 #include <log.h>
 #include <rtc.h>
 #include <asm/io.h>
+#include <asm/rtc.h>
 #include <asm/test.h>
 #include <dm/test.h>
 #include <test/ut.h>
@@ -70,7 +72,20 @@
 	old_base_time = sandbox_i2c_rtc_get_set_base_time(emul, -1);
 
 	memset(&time, '\0', sizeof(time));
-	time.tm_mday = 25;
+	time.tm_mday = 3;
+	time.tm_mon = 6;
+	time.tm_year = 2004;
+	time.tm_sec = 0;
+	time.tm_min = 18;
+	time.tm_hour = 18;
+	ut_assertok(dm_rtc_set(dev, &time));
+
+	memset(&cmp, '\0', sizeof(cmp));
+	ut_assertok(dm_rtc_get(dev, &cmp));
+	ut_assertok(cmp_times(&time, &cmp, true));
+
+	memset(&time, '\0', sizeof(time));
+	time.tm_mday = 31;
 	time.tm_mon = 8;
 	time.tm_year = 2004;
 	time.tm_sec = 0;
@@ -117,6 +132,107 @@
 }
 DM_TEST(dm_test_rtc_set_get, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 
+static int dm_test_rtc_read_write(struct unit_test_state *uts)
+{
+	struct rtc_time time;
+	struct udevice *dev, *emul;
+	long old_offset;
+	u8 buf[4], reg;
+
+	ut_assertok(uclass_get_device(UCLASS_RTC, 0, &dev));
+
+	memcpy(buf, "car", 4);
+	ut_assertok(dm_rtc_write(dev, REG_AUX0, buf, 4));
+	memset(buf, '\0', sizeof(buf));
+	ut_assertok(dm_rtc_read(dev, REG_AUX0, buf, 4));
+	ut_asserteq(memcmp(buf, "car", 4), 0);
+
+	reg = 'b';
+	ut_assertok(dm_rtc_write(dev, REG_AUX0, &reg, 1));
+	memset(buf, '\0', sizeof(buf));
+	ut_assertok(dm_rtc_read(dev, REG_AUX0, buf, 4));
+	ut_asserteq(memcmp(buf, "bar", 4), 0);
+
+	reg = 't';
+	ut_assertok(dm_rtc_write(dev, REG_AUX2, &reg, 1));
+	memset(buf, '\0', sizeof(buf));
+	ut_assertok(dm_rtc_read(dev, REG_AUX1, buf, 3));
+	ut_asserteq(memcmp(buf, "at", 3), 0);
+
+	ut_assertok(i2c_emul_find(dev, &emul));
+	ut_assert(emul != NULL);
+
+	old_offset = sandbox_i2c_rtc_set_offset(emul, false, 0);
+	ut_assertok(dm_rtc_get(dev, &time));
+
+	ut_assertok(dm_rtc_read(dev, REG_SEC, &reg, 1));
+	ut_asserteq(time.tm_sec, reg);
+	ut_assertok(dm_rtc_read(dev, REG_MDAY, &reg, 1));
+	ut_asserteq(time.tm_mday, reg);
+
+	sandbox_i2c_rtc_set_offset(emul, true, old_offset);
+
+	return 0;
+}
+DM_TEST(dm_test_rtc_read_write, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test 'rtc list' command */
+static int dm_test_rtc_cmd_list(struct unit_test_state *uts)
+{
+	console_record_reset();
+
+	run_command("rtc list", 0);
+	ut_assert_nextline("RTC #0 - rtc@43");
+	ut_assert_nextline("RTC #1 - rtc@61");
+	ut_assert_console_end();
+
+	return 0;
+}
+DM_TEST(dm_test_rtc_cmd_list, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test 'rtc read' and 'rtc write' commands */
+static int dm_test_rtc_cmd_rw(struct unit_test_state *uts)
+{
+	console_record_reset();
+
+	run_command("rtc dev 0", 0);
+	ut_assert_nextline("RTC #0 - rtc@43");
+	ut_assert_console_end();
+
+	run_command("rtc write 0x30 aabb", 0);
+	ut_assert_console_end();
+
+	run_command("rtc read 0x30 2", 0);
+	ut_assert_nextline("00000030: aa bb                                              ..");
+	ut_assert_console_end();
+
+	run_command("rtc dev 1", 0);
+	ut_assert_nextline("RTC #1 - rtc@61");
+	ut_assert_console_end();
+
+	run_command("rtc write 0x30 ccdd", 0);
+	ut_assert_console_end();
+
+	run_command("rtc read 0x30 2", 0);
+	ut_assert_nextline("00000030: cc dd                                              ..");
+	ut_assert_console_end();
+
+	/*
+	 * Switch back to device #0, check that its aux registers
+	 * still have the same values.
+	 */
+	run_command("rtc dev 0", 0);
+	ut_assert_nextline("RTC #0 - rtc@43");
+	ut_assert_console_end();
+
+	run_command("rtc read 0x30 2", 0);
+	ut_assert_nextline("00000030: aa bb                                              ..");
+	ut_assert_console_end();
+
+	return 0;
+}
+DM_TEST(dm_test_rtc_cmd_rw, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
 /* Reset the time */
 static int dm_test_rtc_reset(struct unit_test_state *uts)
 {