Merge tag 'for-v2022.10' of https://source.denx.de/u-boot/custodians/u-boot-i2c

i2c changes for 2022.10

- new driver nuvoton, NPCM7xx from Jim Liu

Fixes:

- ast_i2c: Remove SCL direct drive mode
  from Eddie James

- avoid dynamic stack use in dm_i2c_write

    bloat-o-meter drivers/i2c/i2c-uclass.o.{0,1}
    add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-144 (-144)
    Function                                     old     new   delta
    dm_i2c_write                                 552     408    -144
    Total: Before=3828, After=3684, chg -3.76%

  patch from Rasmus Villemoes
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index 71a7f8d..5712576 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -679,15 +679,6 @@
 	slot or emmc on mmc1 - mmc3. Setting this to 1, 2 or 3 will enable
 	support for this.
 
-config INITIAL_USB_SCAN_DELAY
-	int "delay initial usb scan by x ms to allow builtin devices to init"
-	default 0
-	---help---
-	Some boards have on board usb devices which need longer than the
-	USB spec's 1 second to connect from board powerup. Set this config
-	option to a non 0 value to add an extra delay before the first usb
-	bus scan.
-
 config USB0_VBUS_PIN
 	string "Vbus enable pin for usb0 (otg)"
 	default ""
@@ -850,8 +841,9 @@
 	int "LCD panel display clock phase"
 	depends on VIDEO_SUNXI || DM_VIDEO
 	default 1
+	range 0 3
 	---help---
-	Select LCD panel display clock phase shift, range 0-3.
+	Select LCD panel display clock phase shift
 
 config VIDEO_LCD_POWER
 	string "LCD panel power enable pin"
diff --git a/cmd/sf.c b/cmd/sf.c
index 8713736..cd50b38 100644
--- a/cmd/sf.c
+++ b/cmd/sf.c
@@ -294,6 +294,12 @@
 		return 1;
 	}
 
+	if (strncmp(argv[0], "read", 4) != 0 && flash->flash_is_unlocked &&
+	    !flash->flash_is_unlocked(flash, offset, len)) {
+		printf("ERROR: flash area is locked\n");
+		return 1;
+	}
+
 	buf = map_physmem(addr, len, MAP_WRBACK);
 	if (!buf && addr) {
 		puts("Failed to map physical memory\n");
@@ -350,6 +356,12 @@
 		return 1;
 	}
 
+	if (flash->flash_is_unlocked &&
+	    !flash->flash_is_unlocked(flash, offset, len)) {
+		printf("ERROR: flash area is locked\n");
+		return 1;
+	}
+
 	ret = spi_flash_erase(flash, offset, size);
 	printf("SF: %zu bytes @ %#x Erased: ", (size_t)size, (u32)offset);
 	if (ret)
diff --git a/common/spl/spl_spi.c b/common/spl/spl_spi.c
index 3eef2f8..d959ad1 100644
--- a/common/spl/spl_spi.c
+++ b/common/spl/spl_spi.c
@@ -172,6 +172,11 @@
 					     spl_image->size,
 					     (void *)spl_image->load_addr);
 		}
+		if (IS_ENABLED(CONFIG_SPI_FLASH_SOFT_RESET)) {
+			err = spi_nor_remove(flash);
+			if (err)
+				return err;
+		}
 	}
 
 	return err;
diff --git a/configs/licheepi_nano_defconfig b/configs/licheepi_nano_defconfig
index 0252763..30c569d 100644
--- a/configs/licheepi_nano_defconfig
+++ b/configs/licheepi_nano_defconfig
@@ -13,3 +13,6 @@
 CONFIG_SPL_STACK=0x8000
 CONFIG_SYS_PBSIZE=1024
 # CONFIG_SYSRESET is not set
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_XTX=y
+CONFIG_SPI=y
diff --git a/configs/orangepi_zero_defconfig b/configs/orangepi_zero_defconfig
index b5ff84a..b6de0b9 100644
--- a/configs/orangepi_zero_defconfig
+++ b/configs/orangepi_zero_defconfig
@@ -10,6 +10,7 @@
 CONFIG_CONSOLE_MUX=y
 CONFIG_SPL_STACK=0x8000
 CONFIG_SYS_PBSIZE=1024
+CONFIG_SPI_FLASH_MACRONIX=y
 CONFIG_SPI_FLASH_WINBOND=y
 CONFIG_SUN8I_EMAC=y
 CONFIG_SPI=y
diff --git a/drivers/clk/sunxi/clk_a10.c b/drivers/clk/sunxi/clk_a10.c
index db92848..abd4e8b 100644
--- a/drivers/clk/sunxi/clk_a10.c
+++ b/drivers/clk/sunxi/clk_a10.c
@@ -64,30 +64,9 @@
 	[RST_USB_PHY2]		= RESET(0x0cc, BIT(2)),
 };
 
-static const struct ccu_desc a10_ccu_desc = {
+const struct ccu_desc a10_ccu_desc = {
 	.gates = a10_gates,
 	.resets = a10_resets,
-};
-
-static int a10_clk_bind(struct udevice *dev)
-{
-	return sunxi_reset_bind(dev, ARRAY_SIZE(a10_resets));
-}
-
-static const struct udevice_id a10_ccu_ids[] = {
-	{ .compatible = "allwinner,sun4i-a10-ccu",
-	  .data = (ulong)&a10_ccu_desc },
-	{ .compatible = "allwinner,sun7i-a20-ccu",
-	  .data = (ulong)&a10_ccu_desc },
-	{ }
-};
-
-U_BOOT_DRIVER(clk_sun4i_a10) = {
-	.name		= "sun4i_a10_ccu",
-	.id		= UCLASS_CLK,
-	.of_match	= a10_ccu_ids,
-	.priv_auto	= sizeof(struct ccu_priv),
-	.ops		= &sunxi_clk_ops,
-	.probe		= sunxi_clk_probe,
-	.bind		= a10_clk_bind,
+	.num_gates = ARRAY_SIZE(a10_gates),
+	.num_resets = ARRAY_SIZE(a10_resets),
 };
diff --git a/drivers/clk/sunxi/clk_a10s.c b/drivers/clk/sunxi/clk_a10s.c
index 0c6564e..e486ced 100644
--- a/drivers/clk/sunxi/clk_a10s.c
+++ b/drivers/clk/sunxi/clk_a10s.c
@@ -49,30 +49,9 @@
 	[RST_USB_PHY1]		= RESET(0x0cc, BIT(1)),
 };
 
-static const struct ccu_desc a10s_ccu_desc = {
+const struct ccu_desc a10s_ccu_desc = {
 	.gates = a10s_gates,
 	.resets = a10s_resets,
-};
-
-static int a10s_clk_bind(struct udevice *dev)
-{
-	return sunxi_reset_bind(dev, ARRAY_SIZE(a10s_resets));
-}
-
-static const struct udevice_id a10s_ccu_ids[] = {
-	{ .compatible = "allwinner,sun5i-a10s-ccu",
-	  .data = (ulong)&a10s_ccu_desc },
-	{ .compatible = "allwinner,sun5i-a13-ccu",
-	  .data = (ulong)&a10s_ccu_desc },
-	{ }
-};
-
-U_BOOT_DRIVER(clk_sun5i_a10s) = {
-	.name		= "sun5i_a10s_ccu",
-	.id		= UCLASS_CLK,
-	.of_match	= a10s_ccu_ids,
-	.priv_auto	= sizeof(struct ccu_priv),
-	.ops		= &sunxi_clk_ops,
-	.probe		= sunxi_clk_probe,
-	.bind		= a10s_clk_bind,
+	.num_gates = ARRAY_SIZE(a10s_gates),
+	.num_resets = ARRAY_SIZE(a10s_resets),
 };
diff --git a/drivers/clk/sunxi/clk_a23.c b/drivers/clk/sunxi/clk_a23.c
index 0280fb5..d94feca 100644
--- a/drivers/clk/sunxi/clk_a23.c
+++ b/drivers/clk/sunxi/clk_a23.c
@@ -68,30 +68,9 @@
 	[RST_BUS_UART4]		= RESET(0x2d8, BIT(20)),
 };
 
-static const struct ccu_desc a23_ccu_desc = {
+const struct ccu_desc a23_ccu_desc = {
 	.gates = a23_gates,
 	.resets = a23_resets,
-};
-
-static int a23_clk_bind(struct udevice *dev)
-{
-	return sunxi_reset_bind(dev, ARRAY_SIZE(a23_resets));
-}
-
-static const struct udevice_id a23_clk_ids[] = {
-	{ .compatible = "allwinner,sun8i-a23-ccu",
-	  .data = (ulong)&a23_ccu_desc },
-	{ .compatible = "allwinner,sun8i-a33-ccu",
-	  .data = (ulong)&a23_ccu_desc },
-	{ }
-};
-
-U_BOOT_DRIVER(clk_sun8i_a23) = {
-	.name		= "sun8i_a23_ccu",
-	.id		= UCLASS_CLK,
-	.of_match	= a23_clk_ids,
-	.priv_auto	= sizeof(struct ccu_priv),
-	.ops		= &sunxi_clk_ops,
-	.probe		= sunxi_clk_probe,
-	.bind		= a23_clk_bind,
+	.num_gates = ARRAY_SIZE(a23_gates),
+	.num_resets = ARRAY_SIZE(a23_resets),
 };
diff --git a/drivers/clk/sunxi/clk_a31.c b/drivers/clk/sunxi/clk_a31.c
index 26d25f3..3606589 100644
--- a/drivers/clk/sunxi/clk_a31.c
+++ b/drivers/clk/sunxi/clk_a31.c
@@ -89,28 +89,9 @@
 	[RST_APB2_UART5]	= RESET(0x2d8, BIT(21)),
 };
 
-static const struct ccu_desc a31_ccu_desc = {
+const struct ccu_desc a31_ccu_desc = {
 	.gates = a31_gates,
 	.resets = a31_resets,
-};
-
-static int a31_clk_bind(struct udevice *dev)
-{
-	return sunxi_reset_bind(dev, ARRAY_SIZE(a31_resets));
-}
-
-static const struct udevice_id a31_clk_ids[] = {
-	{ .compatible = "allwinner,sun6i-a31-ccu",
-	  .data = (ulong)&a31_ccu_desc },
-	{ }
-};
-
-U_BOOT_DRIVER(clk_sun6i_a31) = {
-	.name		= "sun6i_a31_ccu",
-	.id		= UCLASS_CLK,
-	.of_match	= a31_clk_ids,
-	.priv_auto	= sizeof(struct ccu_priv),
-	.ops		= &sunxi_clk_ops,
-	.probe		= sunxi_clk_probe,
-	.bind		= a31_clk_bind,
+	.num_gates = ARRAY_SIZE(a31_gates),
+	.num_resets = ARRAY_SIZE(a31_resets),
 };
diff --git a/drivers/clk/sunxi/clk_a31_r.c b/drivers/clk/sunxi/clk_a31_r.c
index 1f08ea9..fa6887f 100644
--- a/drivers/clk/sunxi/clk_a31_r.c
+++ b/drivers/clk/sunxi/clk_a31_r.c
@@ -28,32 +28,9 @@
 	[RST_APB0_I2C]		= RESET(0x0b0, BIT(6)),
 };
 
-static const struct ccu_desc a31_r_ccu_desc = {
+const struct ccu_desc a31_r_ccu_desc = {
 	.gates = a31_r_gates,
 	.resets = a31_r_resets,
-};
-
-static int a31_r_clk_bind(struct udevice *dev)
-{
-	return sunxi_reset_bind(dev, ARRAY_SIZE(a31_r_resets));
-}
-
-static const struct udevice_id a31_r_clk_ids[] = {
-	{ .compatible = "allwinner,sun8i-a83t-r-ccu",
-	  .data = (ulong)&a31_r_ccu_desc },
-	{ .compatible = "allwinner,sun8i-h3-r-ccu",
-	  .data = (ulong)&a31_r_ccu_desc },
-	{ .compatible = "allwinner,sun50i-a64-r-ccu",
-	  .data = (ulong)&a31_r_ccu_desc },
-	{ }
-};
-
-U_BOOT_DRIVER(clk_sun6i_a31_r) = {
-	.name		= "sun6i_a31_r_ccu",
-	.id		= UCLASS_CLK,
-	.of_match	= a31_r_clk_ids,
-	.priv_auto	= sizeof(struct ccu_priv),
-	.ops		= &sunxi_clk_ops,
-	.probe		= sunxi_clk_probe,
-	.bind		= a31_r_clk_bind,
+	.num_gates = ARRAY_SIZE(a31_r_gates),
+	.num_resets = ARRAY_SIZE(a31_r_resets),
 };
diff --git a/drivers/clk/sunxi/clk_a64.c b/drivers/clk/sunxi/clk_a64.c
index cbb9168..8c81b1a 100644
--- a/drivers/clk/sunxi/clk_a64.c
+++ b/drivers/clk/sunxi/clk_a64.c
@@ -77,28 +77,9 @@
 	[RST_BUS_UART4]		= RESET(0x2d8, BIT(20)),
 };
 
-static const struct ccu_desc a64_ccu_desc = {
+const struct ccu_desc a64_ccu_desc = {
 	.gates = a64_gates,
 	.resets = a64_resets,
-};
-
-static int a64_clk_bind(struct udevice *dev)
-{
-	return sunxi_reset_bind(dev, ARRAY_SIZE(a64_resets));
-}
-
-static const struct udevice_id a64_ccu_ids[] = {
-	{ .compatible = "allwinner,sun50i-a64-ccu",
-	  .data = (ulong)&a64_ccu_desc },
-	{ }
-};
-
-U_BOOT_DRIVER(clk_sun50i_a64) = {
-	.name		= "sun50i_a64_ccu",
-	.id		= UCLASS_CLK,
-	.of_match	= a64_ccu_ids,
-	.priv_auto	= sizeof(struct ccu_priv),
-	.ops		= &sunxi_clk_ops,
-	.probe		= sunxi_clk_probe,
-	.bind		= a64_clk_bind,
+	.num_gates = ARRAY_SIZE(a64_gates),
+	.num_resets = ARRAY_SIZE(a64_resets),
 };
diff --git a/drivers/clk/sunxi/clk_a80.c b/drivers/clk/sunxi/clk_a80.c
index 1ee1f99..3c9eb14 100644
--- a/drivers/clk/sunxi/clk_a80.c
+++ b/drivers/clk/sunxi/clk_a80.c
@@ -74,40 +74,16 @@
 	[3]			= GATE(0xc, BIT(18)),
 };
 
-static const struct ccu_desc a80_ccu_desc = {
+const struct ccu_desc a80_ccu_desc = {
 	.gates = a80_gates,
 	.resets = a80_resets,
+	.num_gates = ARRAY_SIZE(a80_gates),
+	.num_resets = ARRAY_SIZE(a80_resets),
 };
 
-static const struct ccu_desc a80_mmc_clk_desc = {
+const struct ccu_desc a80_mmc_clk_desc = {
 	.gates = a80_mmc_gates,
 	.resets = a80_mmc_resets,
-};
-
-static int a80_clk_bind(struct udevice *dev)
-{
-	ulong count = ARRAY_SIZE(a80_resets);
-
-	if (device_is_compatible(dev, "allwinner,sun9i-a80-mmc-config-clk"))
-		count = ARRAY_SIZE(a80_mmc_resets);
-
-	return sunxi_reset_bind(dev, count);
-}
-
-static const struct udevice_id a80_ccu_ids[] = {
-	{ .compatible = "allwinner,sun9i-a80-ccu",
-	  .data = (ulong)&a80_ccu_desc },
-	{ .compatible = "allwinner,sun9i-a80-mmc-config-clk",
-	  .data = (ulong)&a80_mmc_clk_desc },
-	{ }
-};
-
-U_BOOT_DRIVER(clk_sun9i_a80) = {
-	.name		= "sun9i_a80_ccu",
-	.id		= UCLASS_CLK,
-	.of_match	= a80_ccu_ids,
-	.priv_auto	= sizeof(struct ccu_priv),
-	.ops		= &sunxi_clk_ops,
-	.probe		= sunxi_clk_probe,
-	.bind		= a80_clk_bind,
+	.num_gates = ARRAY_SIZE(a80_mmc_gates),
+	.num_resets = ARRAY_SIZE(a80_mmc_resets),
 };
diff --git a/drivers/clk/sunxi/clk_a83t.c b/drivers/clk/sunxi/clk_a83t.c
index 4b57434..3562da6 100644
--- a/drivers/clk/sunxi/clk_a83t.c
+++ b/drivers/clk/sunxi/clk_a83t.c
@@ -72,28 +72,9 @@
 	[RST_BUS_UART4]		= RESET(0x2d8, BIT(20)),
 };
 
-static const struct ccu_desc a83t_ccu_desc = {
+const struct ccu_desc a83t_ccu_desc = {
 	.gates = a83t_gates,
 	.resets = a83t_resets,
-};
-
-static int a83t_clk_bind(struct udevice *dev)
-{
-	return sunxi_reset_bind(dev, ARRAY_SIZE(a83t_resets));
-}
-
-static const struct udevice_id a83t_clk_ids[] = {
-	{ .compatible = "allwinner,sun8i-a83t-ccu",
-	  .data = (ulong)&a83t_ccu_desc },
-	{ }
-};
-
-U_BOOT_DRIVER(clk_sun8i_a83t) = {
-	.name		= "sun8i_a83t_ccu",
-	.id		= UCLASS_CLK,
-	.of_match	= a83t_clk_ids,
-	.priv_auto	= sizeof(struct ccu_priv),
-	.ops		= &sunxi_clk_ops,
-	.probe		= sunxi_clk_probe,
-	.bind		= a83t_clk_bind,
+	.num_gates = ARRAY_SIZE(a83t_gates),
+	.num_resets = ARRAY_SIZE(a83t_resets),
 };
diff --git a/drivers/clk/sunxi/clk_f1c100s.c b/drivers/clk/sunxi/clk_f1c100s.c
index 72cf8a6..7b4c3ce 100644
--- a/drivers/clk/sunxi/clk_f1c100s.c
+++ b/drivers/clk/sunxi/clk_f1c100s.c
@@ -47,28 +47,9 @@
 	[RST_BUS_UART2]		= RESET(0x2d0, BIT(22)),
 };
 
-static const struct ccu_desc f1c100s_ccu_desc = {
+const struct ccu_desc f1c100s_ccu_desc = {
 	.gates = f1c100s_gates,
 	.resets = f1c100s_resets,
-};
-
-static int f1c100s_clk_bind(struct udevice *dev)
-{
-	return sunxi_reset_bind(dev, ARRAY_SIZE(f1c100s_resets));
-}
-
-static const struct udevice_id f1c100s_clk_ids[] = {
-	{ .compatible = "allwinner,suniv-f1c100s-ccu",
-	  .data = (ulong)&f1c100s_ccu_desc },
-	{ }
-};
-
-U_BOOT_DRIVER(clk_suniv_f1c100s) = {
-	.name		= "suniv_f1c100s_ccu",
-	.id		= UCLASS_CLK,
-	.of_match	= f1c100s_clk_ids,
-	.priv_auto	= sizeof(struct ccu_priv),
-	.ops		= &sunxi_clk_ops,
-	.probe		= sunxi_clk_probe,
-	.bind		= f1c100s_clk_bind,
+	.num_gates = ARRAY_SIZE(f1c100s_gates),
+	.num_resets = ARRAY_SIZE(f1c100s_resets),
 };
diff --git a/drivers/clk/sunxi/clk_h3.c b/drivers/clk/sunxi/clk_h3.c
index 08a830b..17ab3b5 100644
--- a/drivers/clk/sunxi/clk_h3.c
+++ b/drivers/clk/sunxi/clk_h3.c
@@ -90,30 +90,9 @@
 	[RST_BUS_UART3]		= RESET(0x2d8, BIT(19)),
 };
 
-static const struct ccu_desc h3_ccu_desc = {
+const struct ccu_desc h3_ccu_desc = {
 	.gates = h3_gates,
 	.resets = h3_resets,
-};
-
-static int h3_clk_bind(struct udevice *dev)
-{
-	return sunxi_reset_bind(dev, ARRAY_SIZE(h3_resets));
-}
-
-static const struct udevice_id h3_ccu_ids[] = {
-	{ .compatible = "allwinner,sun8i-h3-ccu",
-	  .data = (ulong)&h3_ccu_desc },
-	{ .compatible = "allwinner,sun50i-h5-ccu",
-	  .data = (ulong)&h3_ccu_desc },
-	{ }
-};
-
-U_BOOT_DRIVER(clk_sun8i_h3) = {
-	.name		= "sun8i_h3_ccu",
-	.id		= UCLASS_CLK,
-	.of_match	= h3_ccu_ids,
-	.priv_auto	= sizeof(struct ccu_priv),
-	.ops		= &sunxi_clk_ops,
-	.probe		= sunxi_clk_probe,
-	.bind		= h3_clk_bind,
+	.num_gates = ARRAY_SIZE(h3_gates),
+	.num_resets = ARRAY_SIZE(h3_resets),
 };
diff --git a/drivers/clk/sunxi/clk_h6.c b/drivers/clk/sunxi/clk_h6.c
index b320234..041bc5e 100644
--- a/drivers/clk/sunxi/clk_h6.c
+++ b/drivers/clk/sunxi/clk_h6.c
@@ -91,28 +91,9 @@
 	[RST_BUS_OTG]		= RESET(0xa8c, BIT(24)),
 };
 
-static const struct ccu_desc h6_ccu_desc = {
+const struct ccu_desc h6_ccu_desc = {
 	.gates = h6_gates,
 	.resets = h6_resets,
-};
-
-static int h6_clk_bind(struct udevice *dev)
-{
-	return sunxi_reset_bind(dev, ARRAY_SIZE(h6_resets));
-}
-
-static const struct udevice_id h6_ccu_ids[] = {
-	{ .compatible = "allwinner,sun50i-h6-ccu",
-	  .data = (ulong)&h6_ccu_desc },
-	{ }
-};
-
-U_BOOT_DRIVER(clk_sun50i_h6) = {
-	.name		= "sun50i_h6_ccu",
-	.id		= UCLASS_CLK,
-	.of_match	= h6_ccu_ids,
-	.priv_auto	= sizeof(struct ccu_priv),
-	.ops		= &sunxi_clk_ops,
-	.probe		= sunxi_clk_probe,
-	.bind		= h6_clk_bind,
+	.num_gates = ARRAY_SIZE(h6_gates),
+	.num_resets = ARRAY_SIZE(h6_resets),
 };
diff --git a/drivers/clk/sunxi/clk_h616.c b/drivers/clk/sunxi/clk_h616.c
index 8009972..964636d 100644
--- a/drivers/clk/sunxi/clk_h616.c
+++ b/drivers/clk/sunxi/clk_h616.c
@@ -109,28 +109,9 @@
 	[RST_BUS_OTG]		= RESET(0xa8c, BIT(24)),
 };
 
-static const struct ccu_desc h616_ccu_desc = {
+const struct ccu_desc h616_ccu_desc = {
 	.gates = h616_gates,
 	.resets = h616_resets,
-};
-
-static int h616_clk_bind(struct udevice *dev)
-{
-	return sunxi_reset_bind(dev, ARRAY_SIZE(h616_resets));
-}
-
-static const struct udevice_id h616_ccu_ids[] = {
-	{ .compatible = "allwinner,sun50i-h616-ccu",
-	  .data = (ulong)&h616_ccu_desc },
-	{ }
-};
-
-U_BOOT_DRIVER(clk_sun50i_h616) = {
-	.name		= "sun50i_h616_ccu",
-	.id		= UCLASS_CLK,
-	.of_match	= h616_ccu_ids,
-	.priv_auto	= sizeof(struct ccu_priv),
-	.ops		= &sunxi_clk_ops,
-	.probe		= sunxi_clk_probe,
-	.bind		= h616_clk_bind,
+	.num_gates = ARRAY_SIZE(h616_gates),
+	.num_resets = ARRAY_SIZE(h616_resets),
 };
diff --git a/drivers/clk/sunxi/clk_h6_r.c b/drivers/clk/sunxi/clk_h6_r.c
index c592886..ddcb3da 100644
--- a/drivers/clk/sunxi/clk_h6_r.c
+++ b/drivers/clk/sunxi/clk_h6_r.c
@@ -34,30 +34,9 @@
 	[RST_R_APB1_W1]		= RESET(0x1ec, BIT(16)),
 };
 
-static const struct ccu_desc h6_r_ccu_desc = {
+const struct ccu_desc h6_r_ccu_desc = {
 	.gates = h6_r_gates,
 	.resets = h6_r_resets,
-};
-
-static int h6_r_clk_bind(struct udevice *dev)
-{
-	return sunxi_reset_bind(dev, ARRAY_SIZE(h6_r_resets));
-}
-
-static const struct udevice_id h6_r_clk_ids[] = {
-	{ .compatible = "allwinner,sun50i-h6-r-ccu",
-	  .data = (ulong)&h6_r_ccu_desc },
-	{ .compatible = "allwinner,sun50i-h616-r-ccu",
-	  .data = (ulong)&h6_r_ccu_desc },
-	{ }
-};
-
-U_BOOT_DRIVER(clk_sun50i_h6_r) = {
-	.name		= "sun50i_h6_r_ccu",
-	.id		= UCLASS_CLK,
-	.of_match	= h6_r_clk_ids,
-	.priv_auto	= sizeof(struct ccu_priv),
-	.ops		= &sunxi_clk_ops,
-	.probe		= sunxi_clk_probe,
-	.bind		= h6_r_clk_bind,
+	.num_gates = ARRAY_SIZE(h6_r_gates),
+	.num_resets = ARRAY_SIZE(h6_r_resets),
 };
diff --git a/drivers/clk/sunxi/clk_r40.c b/drivers/clk/sunxi/clk_r40.c
index 45633a2..ef743d6 100644
--- a/drivers/clk/sunxi/clk_r40.c
+++ b/drivers/clk/sunxi/clk_r40.c
@@ -99,28 +99,9 @@
 	[RST_BUS_UART7]		= RESET(0x2d8, BIT(23)),
 };
 
-static const struct ccu_desc r40_ccu_desc = {
+const struct ccu_desc r40_ccu_desc = {
 	.gates = r40_gates,
 	.resets = r40_resets,
-};
-
-static int r40_clk_bind(struct udevice *dev)
-{
-	return sunxi_reset_bind(dev, ARRAY_SIZE(r40_resets));
-}
-
-static const struct udevice_id r40_clk_ids[] = {
-	{ .compatible = "allwinner,sun8i-r40-ccu",
-	  .data = (ulong)&r40_ccu_desc },
-	{ }
-};
-
-U_BOOT_DRIVER(clk_sun8i_r40) = {
-	.name		= "sun8i_r40_ccu",
-	.id		= UCLASS_CLK,
-	.of_match	= r40_clk_ids,
-	.priv_auto	= sizeof(struct ccu_priv),
-	.ops		= &sunxi_clk_ops,
-	.probe		= sunxi_clk_probe,
-	.bind		= r40_clk_bind,
+	.num_gates = ARRAY_SIZE(r40_gates),
+	.num_resets = ARRAY_SIZE(r40_resets),
 };
diff --git a/drivers/clk/sunxi/clk_sunxi.c b/drivers/clk/sunxi/clk_sunxi.c
index 9a21367..ec02a2d 100644
--- a/drivers/clk/sunxi/clk_sunxi.c
+++ b/drivers/clk/sunxi/clk_sunxi.c
@@ -12,25 +12,31 @@
 #include <reset.h>
 #include <asm/io.h>
 #include <clk/sunxi.h>
+#include <dm/device-internal.h>
 #include <linux/bitops.h>
 #include <linux/log2.h>
 
-static const struct ccu_clk_gate *priv_to_gate(struct ccu_priv *priv,
+extern U_BOOT_DRIVER(sunxi_reset);
+
+static const struct ccu_clk_gate *plat_to_gate(struct ccu_plat *plat,
 					       unsigned long id)
 {
-	return &priv->desc->gates[id];
+	if (id >= plat->desc->num_gates)
+		return NULL;
+
+	return &plat->desc->gates[id];
 }
 
 static int sunxi_set_gate(struct clk *clk, bool on)
 {
-	struct ccu_priv *priv = dev_get_priv(clk->dev);
-	const struct ccu_clk_gate *gate = priv_to_gate(priv, clk->id);
+	struct ccu_plat *plat = dev_get_plat(clk->dev);
+	const struct ccu_clk_gate *gate = plat_to_gate(plat, clk->id);
 	u32 reg;
 
-	if ((gate->flags & CCU_CLK_F_DUMMY_GATE))
+	if (gate && (gate->flags & CCU_CLK_F_DUMMY_GATE))
 		return 0;
 
-	if (!(gate->flags & CCU_CLK_F_IS_VALID)) {
+	if (!gate || !(gate->flags & CCU_CLK_F_IS_VALID)) {
 		printf("%s: (CLK#%ld) unhandled\n", __func__, clk->id);
 		return 0;
 	}
@@ -38,13 +44,13 @@
 	debug("%s: (CLK#%ld) off#0x%x, BIT(%d)\n", __func__,
 	      clk->id, gate->off, ilog2(gate->bit));
 
-	reg = readl(priv->base + gate->off);
+	reg = readl(plat->base + gate->off);
 	if (on)
 		reg |= gate->bit;
 	else
 		reg &= ~gate->bit;
 
-	writel(reg, priv->base + gate->off);
+	writel(reg, plat->base + gate->off);
 
 	return 0;
 }
@@ -64,21 +70,19 @@
 	.disable = sunxi_clk_disable,
 };
 
+static int sunxi_clk_bind(struct udevice *dev)
+{
+	/* Reuse the platform data for the reset driver. */
+	return device_bind(dev, DM_DRIVER_REF(sunxi_reset), "reset",
+			   dev_get_plat(dev), dev_ofnode(dev), NULL);
+}
+
-int sunxi_clk_probe(struct udevice *dev)
+static int sunxi_clk_probe(struct udevice *dev)
 {
-	struct ccu_priv *priv = dev_get_priv(dev);
 	struct clk_bulk clk_bulk;
 	struct reset_ctl_bulk rst_bulk;
 	int ret;
 
-	priv->base = dev_read_addr_ptr(dev);
-	if (!priv->base)
-		return -ENOMEM;
-
-	priv->desc = (const struct ccu_desc *)dev_get_driver_data(dev);
-	if (!priv->desc)
-		return -EINVAL;
-
 	ret = clk_get_bulk(dev, &clk_bulk);
 	if (!ret)
 		clk_enable_bulk(&clk_bulk);
@@ -89,3 +93,138 @@
 
 	return 0;
 }
+
+static int sunxi_clk_of_to_plat(struct udevice *dev)
+{
+	struct ccu_plat *plat = dev_get_plat(dev);
+
+	plat->base = dev_read_addr_ptr(dev);
+	if (!plat->base)
+		return -ENOMEM;
+
+	plat->desc = (const struct ccu_desc *)dev_get_driver_data(dev);
+	if (!plat->desc)
+		return -EINVAL;
+
+	return 0;
+}
+
+extern const struct ccu_desc a10_ccu_desc;
+extern const struct ccu_desc a10s_ccu_desc;
+extern const struct ccu_desc a23_ccu_desc;
+extern const struct ccu_desc a31_ccu_desc;
+extern const struct ccu_desc a31_r_ccu_desc;
+extern const struct ccu_desc a64_ccu_desc;
+extern const struct ccu_desc a80_ccu_desc;
+extern const struct ccu_desc a80_mmc_clk_desc;
+extern const struct ccu_desc a83t_ccu_desc;
+extern const struct ccu_desc f1c100s_ccu_desc;
+extern const struct ccu_desc h3_ccu_desc;
+extern const struct ccu_desc h6_ccu_desc;
+extern const struct ccu_desc h616_ccu_desc;
+extern const struct ccu_desc h6_r_ccu_desc;
+extern const struct ccu_desc r40_ccu_desc;
+extern const struct ccu_desc v3s_ccu_desc;
+
+static const struct udevice_id sunxi_clk_ids[] = {
+#ifdef CONFIG_CLK_SUN4I_A10
+	{ .compatible = "allwinner,sun4i-a10-ccu",
+	  .data = (ulong)&a10_ccu_desc },
+#endif
+#ifdef CONFIG_CLK_SUN5I_A10S
+	{ .compatible = "allwinner,sun5i-a10s-ccu",
+	  .data = (ulong)&a10s_ccu_desc },
+	{ .compatible = "allwinner,sun5i-a13-ccu",
+	  .data = (ulong)&a10s_ccu_desc },
+#endif
+#ifdef CONFIG_CLK_SUN6I_A31
+	{ .compatible = "allwinner,sun6i-a31-ccu",
+	  .data = (ulong)&a31_ccu_desc },
+#endif
+#ifdef CONFIG_CLK_SUN4I_A10
+	{ .compatible = "allwinner,sun7i-a20-ccu",
+	  .data = (ulong)&a10_ccu_desc },
+#endif
+#ifdef CONFIG_CLK_SUN8I_A23
+	{ .compatible = "allwinner,sun8i-a23-ccu",
+	  .data = (ulong)&a23_ccu_desc },
+	{ .compatible = "allwinner,sun8i-a33-ccu",
+	  .data = (ulong)&a23_ccu_desc },
+#endif
+#ifdef CONFIG_CLK_SUN8I_A83T
+	{ .compatible = "allwinner,sun8i-a83t-ccu",
+	  .data = (ulong)&a83t_ccu_desc },
+#endif
+#ifdef CONFIG_CLK_SUN6I_A31_R
+	{ .compatible = "allwinner,sun8i-a83t-r-ccu",
+	  .data = (ulong)&a31_r_ccu_desc },
+#endif
+#ifdef CONFIG_CLK_SUN8I_H3
+	{ .compatible = "allwinner,sun8i-h3-ccu",
+	  .data = (ulong)&h3_ccu_desc },
+#endif
+#ifdef CONFIG_CLK_SUN6I_A31_R
+	{ .compatible = "allwinner,sun8i-h3-r-ccu",
+	  .data = (ulong)&a31_r_ccu_desc },
+#endif
+#ifdef CONFIG_CLK_SUN8I_R40
+	{ .compatible = "allwinner,sun8i-r40-ccu",
+	  .data = (ulong)&r40_ccu_desc },
+#endif
+#ifdef CONFIG_CLK_SUN8I_V3S
+	{ .compatible = "allwinner,sun8i-v3-ccu",
+	  .data = (ulong)&v3s_ccu_desc },
+	{ .compatible = "allwinner,sun8i-v3s-ccu",
+	  .data = (ulong)&v3s_ccu_desc },
+#endif
+#ifdef CONFIG_CLK_SUN9I_A80
+	{ .compatible = "allwinner,sun9i-a80-ccu",
+	  .data = (ulong)&a80_ccu_desc },
+	{ .compatible = "allwinner,sun9i-a80-mmc-config-clk",
+	  .data = (ulong)&a80_mmc_clk_desc },
+#endif
+#ifdef CONFIG_CLK_SUN50I_A64
+	{ .compatible = "allwinner,sun50i-a64-ccu",
+	  .data = (ulong)&a64_ccu_desc },
+#endif
+#ifdef CONFIG_CLK_SUN6I_A31_R
+	{ .compatible = "allwinner,sun50i-a64-r-ccu",
+	  .data = (ulong)&a31_r_ccu_desc },
+#endif
+#ifdef CONFIG_CLK_SUN8I_H3
+	{ .compatible = "allwinner,sun50i-h5-ccu",
+	  .data = (ulong)&h3_ccu_desc },
+#endif
+#ifdef CONFIG_CLK_SUN50I_H6
+	{ .compatible = "allwinner,sun50i-h6-ccu",
+	  .data = (ulong)&h6_ccu_desc },
+#endif
+#ifdef CONFIG_CLK_SUN50I_H6_R
+	{ .compatible = "allwinner,sun50i-h6-r-ccu",
+	  .data = (ulong)&h6_r_ccu_desc },
+#endif
+#ifdef CONFIG_CLK_SUN50I_H616
+	{ .compatible = "allwinner,sun50i-h616-ccu",
+	  .data = (ulong)&h616_ccu_desc },
+#endif
+#ifdef CONFIG_CLK_SUN50I_H6_R
+	{ .compatible = "allwinner,sun50i-h616-r-ccu",
+	  .data = (ulong)&h6_r_ccu_desc },
+#endif
+#ifdef CONFIG_CLK_SUNIV_F1C100S
+	{ .compatible = "allwinner,suniv-f1c100s-ccu",
+	  .data = (ulong)&f1c100s_ccu_desc },
+#endif
+	{ }
+};
+
+U_BOOT_DRIVER(sunxi_clk) = {
+	.name		= "sunxi_clk",
+	.id		= UCLASS_CLK,
+	.of_match	= sunxi_clk_ids,
+	.bind		= sunxi_clk_bind,
+	.probe		= sunxi_clk_probe,
+	.of_to_plat	= sunxi_clk_of_to_plat,
+	.plat_auto	= sizeof(struct ccu_plat),
+	.ops		= &sunxi_clk_ops,
+};
diff --git a/drivers/clk/sunxi/clk_v3s.c b/drivers/clk/sunxi/clk_v3s.c
index 67d215c..f2fd11e 100644
--- a/drivers/clk/sunxi/clk_v3s.c
+++ b/drivers/clk/sunxi/clk_v3s.c
@@ -49,30 +49,9 @@
 	[RST_BUS_UART2]		= RESET(0x2d8, BIT(18)),
 };
 
-static const struct ccu_desc v3s_ccu_desc = {
+const struct ccu_desc v3s_ccu_desc = {
 	.gates = v3s_gates,
 	.resets = v3s_resets,
-};
-
-static int v3s_clk_bind(struct udevice *dev)
-{
-	return sunxi_reset_bind(dev, ARRAY_SIZE(v3s_resets));
-}
-
-static const struct udevice_id v3s_clk_ids[] = {
-	{ .compatible = "allwinner,sun8i-v3s-ccu",
-	  .data = (ulong)&v3s_ccu_desc },
-	{ .compatible = "allwinner,sun8i-v3-ccu",
-	  .data = (ulong)&v3s_ccu_desc },
-	{ }
-};
-
-U_BOOT_DRIVER(clk_sun8i_v3s) = {
-	.name		= "sun8i_v3s_ccu",
-	.id		= UCLASS_CLK,
-	.of_match	= v3s_clk_ids,
-	.priv_auto	= sizeof(struct ccu_priv),
-	.ops		= &sunxi_clk_ops,
-	.probe		= sunxi_clk_probe,
-	.bind		= v3s_clk_bind,
+	.num_gates = ARRAY_SIZE(v3s_gates),
+	.num_resets = ARRAY_SIZE(v3s_resets),
 };
diff --git a/drivers/mtd/nand/raw/sunxi_nand_spl.c b/drivers/mtd/nand/raw/sunxi_nand_spl.c
index a29a76c..6de0b0a 100644
--- a/drivers/mtd/nand/raw/sunxi_nand_spl.c
+++ b/drivers/mtd/nand/raw/sunxi_nand_spl.c
@@ -208,7 +208,7 @@
 
 	val = readl(SUNXI_NFC_BASE + NFC_CTL);
 	val &= ~NFC_CTL_PAGE_SIZE_MASK;
-	writel(val | NFC_CTL_RAM_METHOD | NFC_CTL_PAGE_SIZE(conf->page_size),
+	writel(val | NFC_CTL_PAGE_SIZE(conf->page_size),
 	       SUNXI_NFC_BASE + NFC_CTL);
 	writel(conf->ecc_size, SUNXI_NFC_BASE + NFC_CNT);
 	writel(conf->page_size, SUNXI_NFC_BASE + NFC_SPARE_AREA);
diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
index f83876c..096338f 100644
--- a/drivers/mtd/spi/Kconfig
+++ b/drivers/mtd/spi/Kconfig
@@ -97,6 +97,13 @@
 	 can support a type of operation in a much more refined way compared
 	 to using flags like SPI_RX_DUAL, SPI_TX_QUAD, etc.
 
+config SPI_NOR_BOOT_SOFT_RESET_EXT_INVERT
+	bool "Command extension type is INVERT for Software Reset on boot"
+	default n
+	help
+	 Because of SFDP information can not be get before boot.
+	 So define command extension type is INVERT when Software Reset on boot only.
+
 config SPI_FLASH_SOFT_RESET
 	bool "Software Reset support for SPI NOR flashes"
 	help
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 3b7c817..8a226a7 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -65,6 +65,10 @@
 #define SFDP_SECTOR_MAP_ID	0xff81	/* Sector Map Table */
 #define SFDP_SST_ID		0x01bf	/* Manufacturer specific Table */
 #define SFDP_PROFILE1_ID	0xff05	/* xSPI Profile 1.0 Table */
+#define SFDP_SCCR_MAP_ID	0xff87	/*
+					 * Status, Control and Configuration
+					 * Register Map.
+					 */
 
 #define SFDP_SIGNATURE		0x50444653U
 #define SFDP_JESD216_MAJOR	1
@@ -174,6 +178,9 @@
 #define PROFILE1_DWORD5_DUMMY_100MHZ		GENMASK(11, 7)
 #define PROFILE1_DUMMY_DEFAULT			20
 
+/* Status, Control and Configuration Register Map(SCCR) */
+#define SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE      BIT(31)
+
 struct sfdp_bfpt {
 	u32	dwords[BFPT_DWORD_MAX];
 };
@@ -1308,13 +1315,13 @@
 }
 
 /*
- * Check if a region of the flash is (completely) locked. See stm_lock() for
+ * Check if a region of the flash is (completely) unlocked. See stm_lock() for
  * more info.
  *
- * Returns 1 if entire region is locked, 0 if any portion is unlocked, and
+ * Returns 1 if entire region is unlocked, 0 if any portion is locked, and
  * negative on errors.
  */
-static int stm_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
+static int stm_is_unlocked(struct spi_nor *nor, loff_t ofs, uint64_t len)
 {
 	int status;
 
@@ -1322,7 +1329,7 @@
 	if (status < 0)
 		return status;
 
-	return stm_is_locked_sr(nor, ofs, len, status);
+	return stm_is_unlocked_sr(nor, ofs, len, status);
 }
 #endif /* CONFIG_SPI_FLASH_STMICRO */
 
@@ -1555,16 +1562,16 @@
 }
 
 /*
- * Returns EACCES (positive value) if region is locked, 0 if region is unlocked,
- * and negative on errors.
+ * Returns EACCES (positive value) if region is (partially) locked, 0 if region
+ * is completely unlocked, and negative on errors.
  */
-static int sst26_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
+static int sst26_is_unlocked(struct spi_nor *nor, loff_t ofs, uint64_t len)
 {
 	/*
-	 * is_locked function is used for check before reading or erasing flash
-	 * region, so offset and length might be not 64k allighned, so adjust
-	 * them to be 64k allighned as sst26_lock_ctl works only with 64k
-	 * allighned regions.
+	 * is_unlocked function is used for check before reading or erasing
+	 * flash region, so offset and length might be not 64k aligned, so
+	 * adjust them to be 64k aligned as sst26_lock_ctl works only with 64k
+	 * aligned regions.
 	 */
 	ofs -= ofs & (SZ_64K - 1);
 	len = len & (SZ_64K - 1) ? (len & ~(SZ_64K - 1)) + SZ_64K : len;
@@ -2457,6 +2464,44 @@
 }
 
 /**
+ * spi_nor_parse_sccr() - Parse the Status, Control and Configuration Register
+ *			  Map.
+ * @nor:		  pointer to a 'struct spi_nor'
+ * @sccr_header:	  pointer to the 'struct sfdp_parameter_header' describing
+ * 			  the SCCR Map table length and version.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_parse_sccr(struct spi_nor *nor,
+			      const struct sfdp_parameter_header *sccr_header)
+{
+	u32 *table, addr;
+	size_t len;
+	int ret, i;
+
+	len = sccr_header->length * sizeof(*table);
+	table = kmalloc(len, GFP_KERNEL);
+	if (!table)
+		return -ENOMEM;
+
+	addr = SFDP_PARAM_HEADER_PTP(sccr_header);
+	ret = spi_nor_read_sfdp(nor, addr, len, table);
+	if (ret)
+		goto out;
+
+	/* Fix endianness of the table DWORDs. */
+	for (i = 0; i < sccr_header->length; i++)
+		table[i] = le32_to_cpu(table[i]);
+
+	if (FIELD_GET(SCCR_DWORD22_OCTAL_DTR_EN_VOLATILE, table[22]))
+		nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE;
+
+out:
+	kfree(table);
+	return ret;
+}
+
+/**
  * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters.
  * @nor:		pointer to a 'struct spi_nor'
  * @params:		pointer to the 'struct spi_nor_flash_parameter' to be
@@ -2562,6 +2607,10 @@
 			err = spi_nor_parse_profile1(nor, param_header, params);
 			break;
 
+		case SFDP_SCCR_MAP_ID:
+			err = spi_nor_parse_sccr(nor, param_header);
+			break;
+
 		default:
 			break;
 		}
@@ -3526,6 +3575,84 @@
 };
 #endif /* CONFIG_SPI_FLASH_MT35XU */
 
+#if CONFIG_IS_ENABLED(SPI_FLASH_MACRONIX)
+/**
+ * spi_nor_macronix_octal_dtr_enable() - Enable octal DTR on Macronix flashes.
+ * @nor:	pointer to a 'struct spi_nor'
+ *
+ * Set Macronix max dummy cycles 20 to allow the flash to run at fastest frequency.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_macronix_octal_dtr_enable(struct spi_nor *nor)
+{
+	struct spi_mem_op op;
+	int ret;
+	u8 buf;
+
+	ret = write_enable(nor);
+	if (ret)
+		return ret;
+
+	buf = SPINOR_REG_MXIC_DC_20;
+	op = (struct spi_mem_op)
+		SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_CR2, 1),
+			   SPI_MEM_OP_ADDR(4, SPINOR_REG_MXIC_CR2_DC, 1),
+			   SPI_MEM_OP_NO_DUMMY,
+			   SPI_MEM_OP_DATA_OUT(1, &buf, 1));
+
+	ret = spi_mem_exec_op(nor->spi, &op);
+	if (ret)
+		return ret;
+
+	ret = spi_nor_wait_till_ready(nor);
+	if (ret)
+		return ret;
+
+	nor->read_dummy = MXIC_MAX_DC;
+	ret = write_enable(nor);
+	if (ret)
+		return ret;
+
+	buf = SPINOR_REG_MXIC_OPI_DTR_EN;
+	op = (struct spi_mem_op)
+		SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_CR2, 1),
+			   SPI_MEM_OP_ADDR(4, SPINOR_REG_MXIC_CR2_MODE, 1),
+			   SPI_MEM_OP_NO_DUMMY,
+			   SPI_MEM_OP_DATA_OUT(1, &buf, 1));
+
+	ret = spi_mem_exec_op(nor->spi, &op);
+	if (ret) {
+		dev_err(nor->dev, "Failed to enable octal DTR mode\n");
+		return ret;
+	}
+	nor->reg_proto = SNOR_PROTO_8_8_8_DTR;
+
+	return 0;
+}
+
+static void macronix_octal_default_init(struct spi_nor *nor)
+{
+	nor->octal_dtr_enable = spi_nor_macronix_octal_dtr_enable;
+}
+
+static void macronix_octal_post_sfdp_fixup(struct spi_nor *nor,
+					 struct spi_nor_flash_parameter *params)
+{
+	/*
+	 * Adding SNOR_HWCAPS_PP_8_8_8_DTR in hwcaps.mask when
+	 * SPI_NOR_OCTAL_DTR_READ flag exists.
+	 */
+	if (params->hwcaps.mask & SNOR_HWCAPS_READ_8_8_8_DTR)
+		params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR;
+}
+
+static struct spi_nor_fixups macronix_octal_fixups = {
+	.default_init = macronix_octal_default_init,
+	.post_sfdp = macronix_octal_post_sfdp_fixup,
+};
+#endif /* CONFIG_SPI_FLASH_MACRONIX */
+
 /** spi_nor_octal_dtr_enable() - enable Octal DTR I/O if needed
  * @nor:                 pointer to a 'struct spi_nor'
  *
@@ -3542,6 +3669,9 @@
 	      nor->write_proto == SNOR_PROTO_8_8_8_DTR))
 		return 0;
 
+	if (!(nor->flags & SNOR_F_IO_MODE_EN_VOLATILE))
+		return 0;
+
 	ret = nor->octal_dtr_enable(nor);
 	if (ret)
 		return ret;
@@ -3619,7 +3749,12 @@
 	enum spi_nor_cmd_ext ext;
 
 	ext = nor->cmd_ext_type;
-	nor->cmd_ext_type = SPI_NOR_EXT_REPEAT;
+	if (nor->cmd_ext_type == SPI_NOR_EXT_NONE) {
+		nor->cmd_ext_type = SPI_NOR_EXT_REPEAT;
+#if CONFIG_IS_ENABLED(SPI_NOR_BOOT_SOFT_RESET_EXT_INVERT)
+		nor->cmd_ext_type = SPI_NOR_EXT_INVERT;
+#endif /* SPI_NOR_BOOT_SOFT_RESET_EXT_INVERT */
+	}
 
 	op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_SRSTEN, 0),
 			SPI_MEM_OP_NO_DUMMY,
@@ -3696,6 +3831,10 @@
 	if (!strcmp(nor->info->name, "mt35xu512aba"))
 		nor->fixups = &mt35xu512aba_fixups;
 #endif
+
+#if CONFIG_IS_ENABLED(SPI_FLASH_MACRONIX)
+	nor->fixups = &macronix_octal_fixups;
+#endif /* SPI_FLASH_MACRONIX */
 }
 
 int spi_nor_scan(struct spi_nor *nor)
@@ -3785,7 +3924,7 @@
 			info->flags & SPI_NOR_HAS_LOCK) {
 		nor->flash_lock = stm_lock;
 		nor->flash_unlock = stm_unlock;
-		nor->flash_is_locked = stm_is_locked;
+		nor->flash_is_unlocked = stm_is_unlocked;
 	}
 #endif
 
@@ -3797,7 +3936,7 @@
 	if (info->flags & SPI_NOR_HAS_SST26LOCK) {
 		nor->flash_lock = sst26_lock;
 		nor->flash_unlock = sst26_unlock;
-		nor->flash_is_locked = sst26_is_locked;
+		nor->flash_is_unlocked = sst26_is_unlocked;
 	}
 #endif
 
diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c
index 67278c4..4fe8b0d 100644
--- a/drivers/mtd/spi/spi-nor-ids.c
+++ b/drivers/mtd/spi/spi-nor-ids.c
@@ -198,7 +198,24 @@
 	{ INFO("mx66l2g45g",  0xc2201c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
 	{ INFO("mx25l1633e", 0xc22415, 0, 64 * 1024,   32, SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | SECT_4K) },
 	{ INFO("mx25r6435f", 0xc22817, 0, 64 * 1024,   128,  SECT_4K) },
-	{ INFO("mx66uw2g345g", 0xc2943c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("mx66uw2g345gx0", 0xc2943c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("mx66lm1g45g",    0xc2853b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("mx25lm51245g",   0xc2853a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("mx25lw51245g",   0xc2863a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("mx25lm25645g",   0xc28539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("mx66uw2g345g",   0xc2843c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("mx66um1g45g",    0xc2803b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("mx66uw1g45g",    0xc2813b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("mx25uw51245g",   0xc2813a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("mx25uw51345g",   0xc2843a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("mx25um25645g",   0xc28039, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("mx25uw25645g",   0xc28139, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("mx25um25345g",   0xc28339, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("mx25uw25345g",   0xc28439, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("mx25uw12845g",   0xc28138, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("mx25uw12345g",   0xc28438, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("mx25uw6445g",    0xc28137, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("mx25uw6345g",    0xc28437, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) },
 #endif
 
 #ifdef CONFIG_SPI_FLASH_STMICRO		/* STMICRO */
@@ -398,6 +415,16 @@
 			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
 	},
 	{
+		INFO("w25q512nwq", 0xef6020, 0, 64 * 1024, 1024,
+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
+	},
+	{
+		INFO("w25q512nwm", 0xef8020, 0, 64 * 1024, 1024,
+			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
+	},
+	{
 		INFO("w25q01jv", 0xef4021, 0, 64 * 1024, 2048,
 			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
 			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c
index 2220f84..9cca8fa 100644
--- a/drivers/net/sun8i_emac.c
+++ b/drivers/net/sun8i_emac.c
@@ -16,7 +16,6 @@
 #include <asm/global_data.h>
 #include <asm/gpio.h>
 #include <asm/io.h>
-#include <asm/arch/clock.h>
 #include <common.h>
 #include <clk.h>
 #include <dm.h>
@@ -857,7 +856,7 @@
 	priv->phyaddr = fdtdec_get_int(gd->fdt_blob, offset, "reg", -1);
 
 	pdata->phy_interface = dev_read_phy_mode(dev);
-	printf("phy interface%d\n", pdata->phy_interface);
+	debug("phy interface %d\n", pdata->phy_interface);
 	if (pdata->phy_interface == PHY_INTERFACE_MODE_NA)
 		return -EINVAL;
 
diff --git a/drivers/phy/allwinner/Kconfig b/drivers/phy/allwinner/Kconfig
index d3ff82f..f8f1e99 100644
--- a/drivers/phy/allwinner/Kconfig
+++ b/drivers/phy/allwinner/Kconfig
@@ -13,6 +13,16 @@
 	  This driver controls the entire USB PHY block, both the USB OTG
 	  parts, as well as the 2 regular USB 2 host PHYs.
 
+config INITIAL_USB_SCAN_DELAY
+	int "Delay initial USB scan by x ms to allow builtin devices to init"
+	depends on PHY_SUN4I_USB
+	default 0
+	help
+	  Some boards have on board usb devices which need longer than
+	  the USB spec's 1 second to connect from board powerup. Set
+	  this option to a nonzero value to add an extra delay before
+	  the first USB bus scan.
+
 config PHY_SUN50I_USB3
 	bool "Allwinner sun50i USB3 PHY driver"
 	depends on ARCH_SUNXI
diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
index aef2cb8..2e969ab 100644
--- a/drivers/phy/allwinner/phy-sun4i-usb.c
+++ b/drivers/phy/allwinner/phy-sun4i-usb.c
@@ -20,8 +20,6 @@
 #include <reset.h>
 #include <asm/gpio.h>
 #include <asm/io.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/cpu.h>
 #include <dm/device_compat.h>
 #include <linux/bitops.h>
 #include <linux/delay.h>
@@ -34,7 +32,8 @@
 #define REG_PHYTUNE			0x0c
 #define REG_PHYCTL_A33			0x10
 #define REG_PHY_OTGCTL			0x20
-#define REG_PMU_UNK1			0x10
+
+#define REG_HCI_PHY_CTL			0x10
 
 /* Common Control Bits for Both PHYs */
 #define PHY_PLL_BW			0x03
@@ -65,6 +64,7 @@
 /* A83T specific control bits for PHY0 */
 #define PHY_CTL_VBUSVLDEXT		BIT(5)
 #define PHY_CTL_SIDDQ			BIT(3)
+#define PHY_CTL_H3_SIDDQ		BIT(1)
 
 /* A83T specific control bits for PHY2 HSIC */
 #define SUNXI_EHCI_HS_FORCE		BIT(20)
@@ -89,9 +89,9 @@
 	int num_phys;
 	enum sun4i_usb_phy_type type;
 	u32 disc_thresh;
+	u32 hci_phy_ctl_clear;
 	u8 phyctl_offset;
 	bool dedicated_clocks;
-	bool enable_pmu_unk1;
 	bool phy0_dual_route;
 	int missing_phys;
 };
@@ -277,6 +277,12 @@
 		return ret;
 	}
 
+	if (usb_phy->pmu && data->cfg->hci_phy_ctl_clear) {
+		val = readl(usb_phy->pmu + REG_HCI_PHY_CTL);
+		val &= ~data->cfg->hci_phy_ctl_clear;
+		writel(val, usb_phy->pmu + REG_HCI_PHY_CTL);
+	}
+
 	if (data->cfg->type == sun8i_a83t_phy ||
 	    data->cfg->type == sun50i_h6_phy) {
 		if (phy->id == 0) {
@@ -286,11 +292,6 @@
 			writel(val, data->base + data->cfg->phyctl_offset);
 		}
 	} else {
-		if (usb_phy->pmu && data->cfg->enable_pmu_unk1) {
-			val = readl(usb_phy->pmu + REG_PMU_UNK1);
-			writel(val & ~2, usb_phy->pmu + REG_PMU_UNK1);
-		}
-
 		if (usb_phy->id == 0)
 			sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN,
 					    PHY_RES45_CAL_DATA,
@@ -530,7 +531,6 @@
 	.disc_thresh = 3,
 	.phyctl_offset = REG_PHYCTL_A10,
 	.dedicated_clocks = false,
-	.enable_pmu_unk1 = false,
 };
 
 static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = {
@@ -539,7 +539,6 @@
 	.disc_thresh = 2,
 	.phyctl_offset = REG_PHYCTL_A10,
 	.dedicated_clocks = false,
-	.enable_pmu_unk1 = false,
 };
 
 static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = {
@@ -548,7 +547,6 @@
 	.disc_thresh = 3,
 	.phyctl_offset = REG_PHYCTL_A10,
 	.dedicated_clocks = true,
-	.enable_pmu_unk1 = false,
 };
 
 static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = {
@@ -557,7 +555,6 @@
 	.disc_thresh = 2,
 	.phyctl_offset = REG_PHYCTL_A10,
 	.dedicated_clocks = false,
-	.enable_pmu_unk1 = false,
 };
 
 static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = {
@@ -566,7 +563,6 @@
 	.disc_thresh = 3,
 	.phyctl_offset = REG_PHYCTL_A10,
 	.dedicated_clocks = true,
-	.enable_pmu_unk1 = false,
 };
 
 static const struct sun4i_usb_phy_cfg sun8i_a33_cfg = {
@@ -575,7 +571,6 @@
 	.disc_thresh = 3,
 	.phyctl_offset = REG_PHYCTL_A33,
 	.dedicated_clocks = true,
-	.enable_pmu_unk1 = false,
 };
 
 static const struct sun4i_usb_phy_cfg sun8i_a83t_cfg = {
@@ -591,7 +586,7 @@
 	.disc_thresh = 3,
 	.phyctl_offset = REG_PHYCTL_A33,
 	.dedicated_clocks = true,
-	.enable_pmu_unk1 = true,
+	.hci_phy_ctl_clear = PHY_CTL_H3_SIDDQ,
 	.phy0_dual_route = true,
 };
 
@@ -601,7 +596,7 @@
 	.disc_thresh = 3,
 	.phyctl_offset = REG_PHYCTL_A33,
 	.dedicated_clocks = true,
-	.enable_pmu_unk1 = true,
+	.hci_phy_ctl_clear = PHY_CTL_H3_SIDDQ,
 	.phy0_dual_route = true,
 };
 
@@ -611,7 +606,16 @@
 	.disc_thresh = 3,
 	.phyctl_offset = REG_PHYCTL_A33,
 	.dedicated_clocks = true,
+	.hci_phy_ctl_clear = PHY_CTL_H3_SIDDQ,
+	.phy0_dual_route = true,
+};
+
+static const struct sun4i_usb_phy_cfg sun20i_d1_cfg = {
+	.num_phys = 2,
+	.type = sun50i_h6_phy,
+	.phyctl_offset = REG_PHYCTL_A33,
+	.dedicated_clocks = true,
-	.enable_pmu_unk1 = true,
+	.hci_phy_ctl_clear = PHY_CTL_SIDDQ,
 	.phy0_dual_route = true,
 };
 
@@ -621,7 +625,7 @@
 	.disc_thresh = 3,
 	.phyctl_offset = REG_PHYCTL_A33,
 	.dedicated_clocks = true,
-	.enable_pmu_unk1 = true,
+	.hci_phy_ctl_clear = PHY_CTL_H3_SIDDQ,
 	.phy0_dual_route = true,
 };
 
@@ -631,7 +635,6 @@
 	.disc_thresh = 3,
 	.phyctl_offset = REG_PHYCTL_A33,
 	.dedicated_clocks = true,
-	.enable_pmu_unk1 = true,
 	.phy0_dual_route = true,
 	.missing_phys = BIT(1) | BIT(2),
 };
@@ -647,6 +650,7 @@
 	{ .compatible = "allwinner,sun8i-h3-usb-phy", .data = (ulong)&sun8i_h3_cfg },
 	{ .compatible = "allwinner,sun8i-r40-usb-phy", .data = (ulong)&sun8i_r40_cfg },
 	{ .compatible = "allwinner,sun8i-v3s-usb-phy", .data = (ulong)&sun8i_v3s_cfg },
+	{ .compatible = "allwinner,sun20i-d1-usb-phy", .data = (ulong)&sun20i_d1_cfg },
 	{ .compatible = "allwinner,sun50i-a64-usb-phy", .data = (ulong)&sun50i_a64_cfg},
 	{ .compatible = "allwinner,sun50i-h6-usb-phy", .data = (ulong)&sun50i_h6_cfg},
 	{ }
diff --git a/drivers/reset/reset-sunxi.c b/drivers/reset/reset-sunxi.c
index e2a9c2a..e484d1f 100644
--- a/drivers/reset/reset-sunxi.c
+++ b/drivers/reset/reset-sunxi.c
@@ -12,30 +12,22 @@
 #include <reset-uclass.h>
 #include <asm/io.h>
 #include <clk/sunxi.h>
-#include <dm/device-internal.h>
-#include <dm/lists.h>
 #include <linux/bitops.h>
 #include <linux/log2.h>
 
-struct sunxi_reset_priv {
-	void *base;
-	ulong count;
-	const struct ccu_desc *desc;
-};
-
-static const struct ccu_reset *priv_to_reset(struct sunxi_reset_priv *priv,
+static const struct ccu_reset *plat_to_reset(struct ccu_plat *plat,
 					     unsigned long id)
 {
-	return	&priv->desc->resets[id];
+	return	&plat->desc->resets[id];
 }
 
 static int sunxi_reset_request(struct reset_ctl *reset_ctl)
 {
-	struct sunxi_reset_priv *priv = dev_get_priv(reset_ctl->dev);
+	struct ccu_plat *plat = dev_get_plat(reset_ctl->dev);
 
 	debug("%s: (RST#%ld)\n", __func__, reset_ctl->id);
 
-	if (reset_ctl->id >= priv->count)
+	if (reset_ctl->id >= plat->desc->num_resets)
 		return -EINVAL;
 
 	return 0;
@@ -43,8 +35,8 @@
 
 static int sunxi_set_reset(struct reset_ctl *reset_ctl, bool on)
 {
-	struct sunxi_reset_priv *priv = dev_get_priv(reset_ctl->dev);
-	const struct ccu_reset *reset = priv_to_reset(priv, reset_ctl->id);
+	struct ccu_plat *plat = dev_get_plat(reset_ctl->dev);
+	const struct ccu_reset *reset = plat_to_reset(plat, reset_ctl->id);
 	u32 reg;
 
 	if (!(reset->flags & CCU_RST_F_IS_VALID)) {
@@ -55,13 +47,13 @@
 	debug("%s: (RST#%ld) off#0x%x, BIT(%d)\n", __func__,
 	      reset_ctl->id, reset->off, ilog2(reset->bit));
 
-	reg = readl(priv->base + reset->off);
+	reg = readl(plat->base + reset->off);
 	if (on)
 		reg |= reset->bit;
 	else
 		reg &= ~reset->bit;
 
-	writel(reg, priv->base + reset->off);
+	writel(reg, plat->base + reset->off);
 
 	return 0;
 }
@@ -82,39 +74,8 @@
 	.rst_deassert = sunxi_reset_deassert,
 };
 
-static int sunxi_reset_probe(struct udevice *dev)
-{
-	struct sunxi_reset_priv *priv = dev_get_priv(dev);
-
-	priv->base = dev_read_addr_ptr(dev);
-
-	return 0;
-}
-
-int sunxi_reset_bind(struct udevice *dev, ulong count)
-{
-	struct udevice *rst_dev;
-	struct sunxi_reset_priv *priv;
-	int ret;
-
-	ret = device_bind_driver_to_node(dev, "sunxi_reset", "reset",
-					 dev_ofnode(dev), &rst_dev);
-	if (ret) {
-		debug("failed to bind sunxi_reset driver (ret=%d)\n", ret);
-		return ret;
-	}
-	priv = malloc(sizeof(struct sunxi_reset_priv));
-	priv->count = count;
-	priv->desc = (const struct ccu_desc *)dev_get_driver_data(dev);
-	dev_set_priv(rst_dev, priv);
-
-	return 0;
-}
-
 U_BOOT_DRIVER(sunxi_reset) = {
 	.name		= "sunxi_reset",
 	.id		= UCLASS_RESET,
 	.ops		= &sunxi_reset_ops,
-	.probe		= sunxi_reset_probe,
-	.priv_auto	= sizeof(struct sunxi_reset_priv),
 };
diff --git a/drivers/spi/spi-sunxi.c b/drivers/spi/spi-sunxi.c
index b6cd7dd..c56d82d 100644
--- a/drivers/spi/spi-sunxi.c
+++ b/drivers/spi/spi-sunxi.c
@@ -72,10 +72,18 @@
 #define SUN4I_XMIT_CNT(cnt)		((cnt) & SUN4I_MAX_XFER_SIZE)
 #define SUN4I_FIFO_STA_RF_CNT_BITS	0
 
-#define SUN4I_SPI_MAX_RATE		24000000
+#ifdef CONFIG_MACH_SUNIV
+/* the AHB clock, which we programmed to be 1/3 of PLL_PERIPH@600MHz */
+#define SUNXI_INPUT_CLOCK		200000000	/* 200 MHz */
+#define SUN4I_SPI_MAX_RATE		(SUNXI_INPUT_CLOCK / 2)
+#else
+/* the SPI mod clock, defaulting to be 1/1 of the HOSC@24MHz */
+#define SUNXI_INPUT_CLOCK		24000000	/* 24 MHz */
+#define SUN4I_SPI_MAX_RATE		SUNXI_INPUT_CLOCK
+#endif
 #define SUN4I_SPI_MIN_RATE		3000
 #define SUN4I_SPI_DEFAULT_RATE		1000000
-#define SUN4I_SPI_TIMEOUT_US		1000000
+#define SUN4I_SPI_TIMEOUT_MS		1000
 
 #define SPI_REG(priv, reg)		((priv)->base + \
 					(priv)->variant->regs[reg])
@@ -221,6 +229,60 @@
 	return ret;
 }
 
+static void sun4i_spi_set_speed_mode(struct udevice *dev)
+{
+	struct sun4i_spi_priv *priv = dev_get_priv(dev);
+	unsigned int div;
+	u32 reg;
+
+	/*
+	 * Setup clock divider.
+	 *
+	 * We have two choices there. Either we can use the clock
+	 * divide rate 1, which is calculated thanks to this formula:
+	 * SPI_CLK = MOD_CLK / (2 ^ (cdr + 1))
+	 * Or we can use CDR2, which is calculated with the formula:
+	 * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
+	 * Whether we use the former or the latter is set through the
+	 * DRS bit.
+	 *
+	 * First try CDR2, and if we can't reach the expected
+	 * frequency, fall back to CDR1.
+	 */
+
+	div = DIV_ROUND_UP(SUNXI_INPUT_CLOCK, priv->freq);
+	reg = readl(SPI_REG(priv, SPI_CCR));
+
+	if ((div / 2) <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) {
+		div /= 2;
+		if (div > 0)
+			div--;
+
+		reg &= ~(SUN4I_CLK_CTL_CDR2_MASK | SUN4I_CLK_CTL_DRS);
+		reg |= SUN4I_CLK_CTL_CDR2(div) | SUN4I_CLK_CTL_DRS;
+	} else {
+		div = fls(div - 1);
+		/* The F1C100s encodes the divider as 2^(n+1) */
+		if (IS_ENABLED(CONFIG_MACH_SUNIV))
+			div--;
+		reg &= ~((SUN4I_CLK_CTL_CDR1_MASK << 8) | SUN4I_CLK_CTL_DRS);
+		reg |= SUN4I_CLK_CTL_CDR1(div);
+	}
+
+	writel(reg, SPI_REG(priv, SPI_CCR));
+
+	reg = readl(SPI_REG(priv, SPI_TCR));
+	reg &= ~(SPI_BIT(priv, SPI_TCR_CPOL) | SPI_BIT(priv, SPI_TCR_CPHA));
+
+	if (priv->mode & SPI_CPOL)
+		reg |= SPI_BIT(priv, SPI_TCR_CPOL);
+
+	if (priv->mode & SPI_CPHA)
+		reg |= SPI_BIT(priv, SPI_TCR_CPHA);
+
+	writel(reg, SPI_REG(priv, SPI_TCR));
+}
+
 static int sun4i_spi_claim_bus(struct udevice *dev)
 {
 	struct sun4i_spi_priv *priv = dev_get_priv(dev->parent);
@@ -240,6 +302,8 @@
 	setbits_le32(SPI_REG(priv, SPI_TCR), SPI_BIT(priv, SPI_TCR_CS_MANUAL) |
 		     SPI_BIT(priv, SPI_TCR_CS_ACTIVE_LOW));
 
+	sun4i_spi_set_speed_mode(dev->parent);
+
 	return 0;
 }
 
@@ -262,7 +326,6 @@
 	struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
 
 	u32 len = bitlen / 8;
-	u32 rx_fifocnt;
 	u8 nbytes;
 	int ret;
 
@@ -300,13 +363,10 @@
 		setbits_le32(SPI_REG(priv, SPI_TCR),
 			     SPI_BIT(priv, SPI_TCR_XCH));
 
-		/* Wait till RX FIFO to be empty */
-		ret = readl_poll_timeout(SPI_REG(priv, SPI_FSR),
-					 rx_fifocnt,
-					 (((rx_fifocnt &
-					 SPI_BIT(priv, SPI_FSR_RF_CNT_MASK)) >>
-					 SUN4I_FIFO_STA_RF_CNT_BITS) >= nbytes),
-					 SUN4I_SPI_TIMEOUT_US);
+		/* Wait for the transfer to be done */
+		ret = wait_for_bit_le32((const void *)SPI_REG(priv, SPI_TCR),
+					SPI_BIT(priv, SPI_TCR_XCH),
+					false, SUN4I_SPI_TIMEOUT_MS, false);
 		if (ret < 0) {
 			printf("ERROR: sun4i_spi: Timeout transferring data\n");
 			sun4i_spi_set_cs(bus, slave_plat->cs, false);
@@ -329,46 +389,14 @@
 {
 	struct sun4i_spi_plat *plat = dev_get_plat(dev);
 	struct sun4i_spi_priv *priv = dev_get_priv(dev);
-	unsigned int div;
-	u32 reg;
 
 	if (speed > plat->max_hz)
 		speed = plat->max_hz;
 
 	if (speed < SUN4I_SPI_MIN_RATE)
 		speed = SUN4I_SPI_MIN_RATE;
-	/*
-	 * Setup clock divider.
-	 *
-	 * We have two choices there. Either we can use the clock
-	 * divide rate 1, which is calculated thanks to this formula:
-	 * SPI_CLK = MOD_CLK / (2 ^ (cdr + 1))
-	 * Or we can use CDR2, which is calculated with the formula:
-	 * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
-	 * Whether we use the former or the latter is set through the
-	 * DRS bit.
-	 *
-	 * First try CDR2, and if we can't reach the expected
-	 * frequency, fall back to CDR1.
-	 */
-
-	div = SUN4I_SPI_MAX_RATE / (2 * speed);
-	reg = readl(SPI_REG(priv, SPI_CCR));
-
-	if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) {
-		if (div > 0)
-			div--;
-
-		reg &= ~(SUN4I_CLK_CTL_CDR2_MASK | SUN4I_CLK_CTL_DRS);
-		reg |= SUN4I_CLK_CTL_CDR2(div) | SUN4I_CLK_CTL_DRS;
-	} else {
-		div = __ilog2(SUN4I_SPI_MAX_RATE) - __ilog2(speed);
-		reg &= ~((SUN4I_CLK_CTL_CDR1_MASK << 8) | SUN4I_CLK_CTL_DRS);
-		reg |= SUN4I_CLK_CTL_CDR1(div);
-	}
 
 	priv->freq = speed;
-	writel(reg, SPI_REG(priv, SPI_CCR));
 
 	return 0;
 }
@@ -376,19 +404,8 @@
 static int sun4i_spi_set_mode(struct udevice *dev, uint mode)
 {
 	struct sun4i_spi_priv *priv = dev_get_priv(dev);
-	u32 reg;
-
-	reg = readl(SPI_REG(priv, SPI_TCR));
-	reg &= ~(SPI_BIT(priv, SPI_TCR_CPOL) | SPI_BIT(priv, SPI_TCR_CPHA));
-
-	if (mode & SPI_CPOL)
-		reg |= SPI_BIT(priv, SPI_TCR_CPOL);
-
-	if (mode & SPI_CPHA)
-		reg |= SPI_BIT(priv, SPI_TCR_CPHA);
 
 	priv->mode = mode;
-	writel(reg, SPI_REG(priv, SPI_TCR));
 
 	return 0;
 }
diff --git a/include/clk/sunxi.h b/include/clk/sunxi.h
index c4a9dee..c298195 100644
--- a/include/clk/sunxi.h
+++ b/include/clk/sunxi.h
@@ -70,34 +70,21 @@
 struct ccu_desc {
 	const struct ccu_clk_gate *gates;
 	const struct ccu_reset *resets;
+	u8 num_gates;
+	u8 num_resets;
 };
 
 /**
- * struct ccu_priv - sunxi clock control unit
+ * struct ccu_plat - sunxi clock control unit platform data
  *
  * @base:	base address
  * @desc:	ccu descriptor
  */
-struct ccu_priv {
+struct ccu_plat {
 	void *base;
 	const struct ccu_desc *desc;
 };
 
-/**
- * sunxi_clk_probe - common sunxi clock probe
- * @dev:	clock device
- */
-int sunxi_clk_probe(struct udevice *dev);
-
 extern struct clk_ops sunxi_clk_ops;
 
-/**
- * sunxi_reset_bind() - reset binding
- *
- * @dev:       reset device
- * @count:     reset count
- * Return: 0 success, or error value
- */
-int sunxi_reset_bind(struct udevice *dev, ulong count);
-
 #endif /* _CLK_SUNXI_H */
diff --git a/include/configs/sun4i.h b/include/configs/sun4i.h
index 0e1baa9..70d451f 100644
--- a/include/configs/sun4i.h
+++ b/include/configs/sun4i.h
@@ -2,18 +2,12 @@
 /*
  * (C) Copyright 2012-2013 Henrik Nordstrom <henrik@henriknordstrom.net>
  *
- * Configuration settings for the Allwinner A10 (sun4i) CPU
+ * Placeholder wrapper to allow addressing Allwinner A10 (sun4i) CPU
+ * based devices separately. Please do not add anything in here.
  */
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-/*
- * A10 specific configuration
- */
-
-/*
- * Include common sunxi configuration where most the settings are
- */
 #include <configs/sunxi-common.h>
 
 #endif /* __CONFIG_H */
diff --git a/include/configs/sun50i.h b/include/configs/sun50i.h
index bc2e3a3..dfcb321 100644
--- a/include/configs/sun50i.h
+++ b/include/configs/sun50i.h
@@ -1,26 +1,11 @@
 /* SPDX-License-Identifier: GPL-2.0+ */
 /*
- * Configuration settings for the Allwinner A64 (sun50i) CPU
+ * Placeholder wrapper to allow addressing Allwinner A64 (and later) sun50i
+ * CPU based devices separately. Please do not add anything in here.
  */
-
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-/*
- * A64 specific configuration
- */
-
-#ifndef CONFIG_SUN50I_GEN_H6
-#define GICD_BASE		0x1c81000
-#define GICC_BASE		0x1c82000
-#else
-#define GICD_BASE		0x3021000
-#define GICC_BASE		0x3022000
-#endif
-
-/*
- * Include common sunxi configuration where most the settings are
- */
 #include <configs/sunxi-common.h>
 
 #endif /* __CONFIG_H */
diff --git a/include/configs/sun5i.h b/include/configs/sun5i.h
index ada18de..3017307 100644
--- a/include/configs/sun5i.h
+++ b/include/configs/sun5i.h
@@ -2,18 +2,12 @@
 /*
  * (C) Copyright 2012-2013 Henrik Nordstrom <henrik@henriknordstrom.net>
  *
- * Configuration settings for the Allwinner A13 (sun5i) CPU
+ * Placeholder wrapper to allow addressing Allwinner A13 (sun5i) CPU
+ * based devices separately. Please do not add anything in here.
  */
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-/*
- * High Level Configuration Options
- */
-
-/*
- * Include common sunxi configuration where most the settings are
- */
 #include <configs/sunxi-common.h>
 
 #endif /* __CONFIG_H */
diff --git a/include/configs/sun6i.h b/include/configs/sun6i.h
index 0b1fedd..cbe04ac 100644
--- a/include/configs/sun6i.h
+++ b/include/configs/sun6i.h
@@ -4,15 +4,12 @@
  * (C) Copyright 2013 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
  * (C) Copyright 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
  *
- * Configuration settings for the Allwinner A31 (sun6i) CPU
+ * Placeholder wrapper to allow addressing Allwinner A31 (sun6i) CPU
+ * based devices separately. Please do not add anything in here.
  */
-
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-/*
- * Include common sunxi configuration where most the settings are
- */
 #include <configs/sunxi-common.h>
 
 #endif /* __CONFIG_H */
diff --git a/include/configs/sun7i.h b/include/configs/sun7i.h
index bc2779f..ad24ab9 100644
--- a/include/configs/sun7i.h
+++ b/include/configs/sun7i.h
@@ -3,14 +3,12 @@
  * (C) Copyright 2012-2013 Henrik Nordstrom <henrik@henriknordstrom.net>
  * (C) Copyright 2013 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
  *
- * Configuration settings for the Allwinner A20 (sun7i) CPU
+ * Placeholder wrapper to allow addressing Allwinner A20 (sun7i) CPU
+ * based devices separately. Please do not add anything in here.
  */
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-/*
- * Include common sunxi configuration where most the settings are
- */
 #include <configs/sunxi-common.h>
 
 #endif /* __CONFIG_H */
diff --git a/include/configs/sun8i.h b/include/configs/sun8i.h
index 106139d..b6cd8d3 100644
--- a/include/configs/sun8i.h
+++ b/include/configs/sun8i.h
@@ -2,21 +2,12 @@
 /*
  * (C) Copyright 2014 Chen-Yu Tsai <wens@csie.org>
  *
- * Configuration settings for the Allwinner A23 (sun8i) CPU
+ * Placeholder wrapper to allow addressing Allwinner A23 (and later) sun8i
+ * CPU based devices separately. Please do not add anything in here.
  */
-
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-/*
- * A23 specific configuration
- */
-
-#include <asm/arch/cpu.h>
-
-/*
- * Include common sunxi configuration where most the settings are
- */
 #include <configs/sunxi-common.h>
 
 #endif /* __CONFIG_H */
diff --git a/include/configs/sun9i.h b/include/configs/sun9i.h
index 6ee08cf..6bf5fc3 100644
--- a/include/configs/sun9i.h
+++ b/include/configs/sun9i.h
@@ -2,19 +2,12 @@
 /*
  * (C) Copyright 2015 Hans de Goede <hdegoede@redhat.com>
  *
- * Configuration settings for the Allwinner A80 (sun9i) CPU
+ * Placeholder wrapper to allow addressing Allwinner A80 (sun9i) CPU
+ * based devices separately. Please do not add anything in here.
  */
-
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-/*
- * A80 specific configuration
- */
-
-/*
- * Include common sunxi configuration where most the settings are
- */
 #include <configs/sunxi-common.h>
 
 #endif /* __CONFIG_H */
diff --git a/include/configs/suniv.h b/include/configs/suniv.h
index 6118cd5..9cc1a77 100644
--- a/include/configs/suniv.h
+++ b/include/configs/suniv.h
@@ -1,14 +1,11 @@
 /* SPDX-License-Identifier: GPL-2.0+ */
 /*
- * Configuration settings for new Allwinner F-series (suniv) CPU
+ * Placeholder wrapper to allow addressing Allwinner F-series (suniv) CPU
+ * based devices separately. Please do not add anything in here.
  */
-
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-/*
- * Include common sunxi configuration where most the settings are
- */
 #include <configs/sunxi-common.h>
 
 #endif /* __CONFIG_H */
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 4ceeae6..2595bad 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -119,6 +119,16 @@
 /* Used for Macronix and Winbond flashes. */
 #define SPINOR_OP_EN4B		0xb7	/* Enter 4-byte mode */
 #define SPINOR_OP_EX4B		0xe9	/* Exit 4-byte mode */
+#define SPINOR_OP_EN4B			0xb7		/* Enter 4-byte mode */
+#define SPINOR_OP_EX4B			0xe9		/* Exit 4-byte mode */
+#define SPINOR_OP_RD_CR2		0x71		/* Read configuration register 2 */
+#define SPINOR_OP_WR_CR2		0x72		/* Write configuration register 2 */
+#define SPINOR_OP_MXIC_DTR_RD		0xee		/* Fast Read opcode in DTR mode */
+#define SPINOR_REG_MXIC_CR2_MODE	0x00000000	/* For setting octal DTR mode */
+#define SPINOR_REG_MXIC_OPI_DTR_EN	0x2		/* Enable Octal DTR */
+#define SPINOR_REG_MXIC_CR2_DC		0x00000300	/* For setting dummy cycles */
+#define SPINOR_REG_MXIC_DC_20		0x0		/* Setting dummy cycles to 20 */
+#define MXIC_MAX_DC			20		/* Maximum value of dummy cycles */
 
 /* Used for Spansion flashes only. */
 #define SPINOR_OP_BRWR		0x17	/* Bank register write */
@@ -280,6 +290,7 @@
 	SNOR_F_USE_CLSR		= BIT(5),
 	SNOR_F_BROKEN_RESET	= BIT(6),
 	SNOR_F_SOFT_RESET	= BIT(7),
+	SNOR_F_IO_MODE_EN_VOLATILE = BIT(8),
 };
 
 struct spi_nor;
@@ -506,8 +517,8 @@
  *			spi-nor will send the erase opcode via write_reg()
  * @flash_lock:		[FLASH-SPECIFIC] lock a region of the SPI NOR
  * @flash_unlock:	[FLASH-SPECIFIC] unlock a region of the SPI NOR
- * @flash_is_locked:	[FLASH-SPECIFIC] check if a region of the SPI NOR is
- *			completely locked
+ * @flash_is_unlocked:	[FLASH-SPECIFIC] check if a region of the SPI NOR is
+ *			completely unlocked
  * @quad_enable:	[FLASH-SPECIFIC] enables SPI NOR quad mode
  * @octal_dtr_enable:	[FLASH-SPECIFIC] enables SPI NOR octal DTR mode.
  * @ready:		[FLASH-SPECIFIC] check if the flash is ready
@@ -556,7 +567,7 @@
 
 	int (*flash_lock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
 	int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
-	int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
+	int (*flash_is_unlocked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
 	int (*quad_enable)(struct spi_nor *nor);
 	int (*octal_dtr_enable)(struct spi_nor *nor);
 	int (*ready)(struct spi_nor *nor);