Browse Source

Merge tag 'u-boot-at91-2022.04-a' of https://source.denx.de/u-boot/custodians/u-boot-at91 into next

First set of u-boot-at91 features for the 2022.04 cycle:

This feature set includes : support for the new QSPI hardware on
sama7g5, small fixes on sam9x60 and sama7g5, some additions of commands
and PIO controller on sam9x60/sam9x60ek.
Tom Rini 2 years ago
parent
commit
b9c9ce8a40

+ 9 - 0
arch/arm/dts/sam9x60.dtsi

@@ -22,6 +22,7 @@
 		serial0 = &dbgu;
 		gpio0 = &pioA;
 		gpio1 = &pioB;
+		gpio2 = &pioC;
 		gpio3 = &pioD;
 		spi0 = &qspi;
 	};
@@ -197,6 +198,14 @@
 				clocks = <&pmc PMC_TYPE_PERIPHERAL 3>;
 			};
 
+			pioC: gpio@fffff800 {
+				compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+				reg = <0xfffff800 0x200>;
+				#gpio-cells = <2>;
+				gpio-controller;
+				clocks = <&pmc PMC_TYPE_PERIPHERAL 4>;
+			};
+
 			pioD: gpio@fffffa00 {
 				compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
 				reg = <0xfffffa00 0x200>;

+ 1 - 1
arch/arm/dts/sama7g5-pinfunc.h

@@ -765,7 +765,7 @@
 #define PIN_PD20__PCK0			PINMUX_PIN(PIN_PD20, 1, 3)
 #define PIN_PD20__FLEXCOM2_IO3		PINMUX_PIN(PIN_PD20, 2, 2)
 #define PIN_PD20__PWMH3			PINMUX_PIN(PIN_PD20, 3, 4)
-#define PIN_PD20__CANTX4		PINMUX_PIN(PIN_PD20, 5, 2)
+#define PIN_PD20__CANTX4		PINMUX_PIN(PIN_PD20, 4, 2)
 #define PIN_PD20__FLEXCOM5_IO0		PINMUX_PIN(PIN_PD20, 6, 5)
 #define PIN_PD21			117
 #define PIN_PD21__GPIO			PINMUX_PIN(PIN_PD21, 0, 0)

+ 26 - 0
arch/arm/dts/sama7g5.dtsi

@@ -91,6 +91,32 @@
 				#clock-cells = <1>;
 			};
 
+			qspi0: spi@e080c000 {
+				compatible = "microchip,sama7g5-ospi";
+				reg = <0xe080c000 0x400>, <0x20000000 0x10000000>;
+				reg-names = "qspi_base", "qspi_mmap";
+				clocks = <&pmc PMC_TYPE_PERIPHERAL 78>, <&pmc PMC_TYPE_GCK 78>;
+				clock-names = "pclk", "gclk";
+				assigned-clocks = <&pmc PMC_TYPE_GCK 78>;
+				assigned-clock-parents = <&pmc PMC_TYPE_CORE 10>; /* sys pll div. */
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+
+			qspi1: spi@e0810000 {
+				compatible = "microchip,sama7g5-qspi";
+				reg = <0xe0810000 0x400>, <0x30000000 0x10000000>;
+				reg-names = "qspi_base", "qspi_mmap";
+				clocks = <&pmc PMC_TYPE_PERIPHERAL 79>, <&pmc PMC_TYPE_GCK 79>;
+				clock-names = "pclk", "gclk";
+				assigned-clocks = <&pmc PMC_TYPE_GCK 78>;
+				assigned-clock-parents = <&pmc PMC_TYPE_CORE 10>; /* sys pll div. */
+				#address-cells = <1>;
+				#size-cells = <0>;
+				status = "disabled";
+			};
+
 			sdmmc0: sdio-host@e1204000 {
 				compatible = "microchip,sama7g5-sdhci";
 				reg = <0xe1204000 0x300>;

+ 38 - 0
arch/arm/dts/sama7g5ek.dts

@@ -11,6 +11,7 @@
 #include <dt-bindings/mfd/atmel-flexcom.h>
 #include "sama7g5.dtsi"
 #include "sama7g5-pinfunc.h"
+#include <dt-bindings/pinctrl/at91.h>
 
 / {
 	model = "Microchip SAMA7G5 Evaluation Kit";
@@ -64,6 +65,24 @@
 	};
 };
 
+&qspi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_qspi>;
+	status = "okay";
+
+	flash@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <133000000>;
+		spi-tx-bus-width = <8>;
+		spi-rx-bus-width = <8>;
+		m25p,fast-read;
+
+	};
+};
+
 &flx1 {
 	atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_TWI>;
 	status = "okay";
@@ -126,6 +145,25 @@
 		bias-pull-up;
 	};
 
+	pinctrl_qspi: qspi {
+		pinmux = <PIN_PB12__QSPI0_IO0>,
+			 <PIN_PB11__QSPI0_IO1>,
+			 <PIN_PB10__QSPI0_IO2>,
+			 <PIN_PB9__QSPI0_IO3>,
+			 <PIN_PB16__QSPI0_IO4>,
+			 <PIN_PB17__QSPI0_IO5>,
+			 <PIN_PB18__QSPI0_IO6>,
+			 <PIN_PB19__QSPI0_IO7>,
+			 <PIN_PB13__QSPI0_CS>,
+			 <PIN_PB14__QSPI0_SCK>,
+			 <PIN_PB15__QSPI0_SCKN>,
+			 <PIN_PB20__QSPI0_DQS>,
+			 <PIN_PB21__QSPI0_INT>;
+		bias-disable;
+		slew-rate = <0>;
+		atmel,drive-strength = <ATMEL_PIO_DRVSTR_HI>;
+	};
+
 	pinctrl_sdmmc0_cmd_data_default: sdmmc0_cmd_data_default {
 		pinmux = <PIN_PA1__SDMMC0_CMD>,
 			 <PIN_PA3__SDMMC0_DAT0>,

+ 5 - 2
arch/arm/mach-at91/arm926ejs/Makefile

@@ -20,8 +20,11 @@ obj-$(CONFIG_AT91_LED)	+= led.o
 obj-y += clock.o
 obj-y += cpu.o
 obj-y	+= reset.o
-ifeq ($(CONFIG_ATMEL_PIT_TIMER),)
-obj-y	+= timer.o
+ifneq ($(CONFIG_ATMEL_PIT_TIMER),y)
+ifneq ($(CONFIG_MCHP_PIT64B_TIMER),y)
+# old non-DM timer driver
+obj-y += timer.o
+endif
 endif
 
 ifndef CONFIG_SKIP_LOWLEVEL_INIT

+ 2 - 0
configs/sam9x60ek_mmc_defconfig

@@ -27,7 +27,9 @@ CONFIG_MISC_INIT_R=y
 CONFIG_HUSH_PARSER=y
 CONFIG_SYS_PROMPT="U-Boot> "
 CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_CLK=y
 CONFIG_CMD_DM=y
+CONFIG_CMD_GPIO=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_NAND=y

+ 2 - 0
configs/sam9x60ek_nandflash_defconfig

@@ -27,7 +27,9 @@ CONFIG_MISC_INIT_R=y
 CONFIG_HUSH_PARSER=y
 CONFIG_SYS_PROMPT="U-Boot> "
 CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_CLK=y
 CONFIG_CMD_DM=y
+CONFIG_CMD_GPIO=y
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y

+ 2 - 0
configs/sam9x60ek_qspiflash_defconfig

@@ -28,7 +28,9 @@ CONFIG_MISC_INIT_R=y
 CONFIG_HUSH_PARSER=y
 CONFIG_SYS_PROMPT="U-Boot> "
 CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_CLK=y
 CONFIG_CMD_DM=y
+CONFIG_CMD_GPIO=y
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y

+ 2 - 0
configs/sama5d27_som1_ek_mmc1_defconfig

@@ -36,6 +36,8 @@ CONFIG_BOOTCOMMAND="fatload mmc 1 0x22000000 at91-sama5d27_som1_ek.dtb; fatload
 CONFIG_MISC_INIT_R=y
 CONFIG_HUSH_PARSER=y
 CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_DM=y
+CONFIG_CMD_GPIO=y
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_I2C=y
 # CONFIG_CMD_LOADS is not set

+ 2 - 0
configs/sama5d27_som1_ek_mmc_defconfig

@@ -37,6 +37,8 @@ CONFIG_BOOTCOMMAND="fatload mmc 0 0x22000000 at91-sama5d27_som1_ek.dtb; fatload
 CONFIG_MISC_INIT_R=y
 CONFIG_HUSH_PARSER=y
 CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_DM=y
+CONFIG_CMD_GPIO=y
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_I2C=y
 # CONFIG_CMD_LOADS is not set

+ 2 - 0
configs/sama5d27_som1_ek_qspiflash_defconfig

@@ -35,6 +35,8 @@ CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p2 rw rootwai
 CONFIG_MISC_INIT_R=y
 CONFIG_HUSH_PARSER=y
 CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_DM=y
+CONFIG_CMD_GPIO=y
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_I2C=y
 # CONFIG_CMD_LOADS is not set

+ 2 - 0
configs/sama5d27_wlsom1_ek_mmc_defconfig

@@ -39,6 +39,8 @@ CONFIG_SPL_DISPLAY_PRINT=y
 CONFIG_SPL_AT91_MCK_BYPASS=y
 CONFIG_HUSH_PARSER=y
 CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_DM=y
+CONFIG_CMD_GPIO=y
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_I2C=y
 # CONFIG_CMD_LOADS is not set

+ 2 - 0
configs/sama5d27_wlsom1_ek_qspiflash_defconfig

@@ -42,6 +42,8 @@ CONFIG_SYS_SPI_U_BOOT_OFFS=0x40000
 CONFIG_SPL_AT91_MCK_BYPASS=y
 CONFIG_HUSH_PARSER=y
 CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_DM=y
+CONFIG_CMD_GPIO=y
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_I2C=y
 # CONFIG_CMD_LOADS is not set

+ 2 - 0
configs/sama5d2_icp_mmc_defconfig

@@ -40,6 +40,8 @@ CONFIG_SPL_RAM_DEVICE=y
 CONFIG_SPL_AT91_MCK_BYPASS=y
 CONFIG_HUSH_PARSER=y
 CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_DM=y
+CONFIG_CMD_GPIO=y
 # CONFIG_CMD_IMI is not set
 CONFIG_CMD_I2C=y
 # CONFIG_CMD_LOADS is not set

+ 2 - 0
configs/sama5d2_ptc_ek_mmc_defconfig

@@ -28,6 +28,8 @@ CONFIG_CONSOLE_MUX=y
 CONFIG_MISC_INIT_R=y
 CONFIG_HUSH_PARSER=y
 CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_DM=y
+CONFIG_CMD_GPIO=y
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_I2C=y
 # CONFIG_CMD_LOADS is not set

+ 2 - 0
configs/sama5d2_ptc_ek_nandflash_defconfig

@@ -28,6 +28,8 @@ CONFIG_CONSOLE_MUX=y
 CONFIG_MISC_INIT_R=y
 CONFIG_HUSH_PARSER=y
 CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_DM=y
+CONFIG_CMD_GPIO=y
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_I2C=y
 # CONFIG_CMD_LOADS is not set

+ 2 - 0
configs/sama5d2_xplained_emmc_defconfig

@@ -35,6 +35,8 @@ CONFIG_BOOTCOMMAND="fatload mmc 0:1 0x22000000 at91-sama5d2_xplained.dtb; fatloa
 # CONFIG_DISPLAY_BOARDINFO is not set
 CONFIG_HUSH_PARSER=y
 CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_DM=y
+CONFIG_CMD_GPIO=y
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_I2C=y
 # CONFIG_CMD_LOADS is not set

+ 2 - 0
configs/sama5d2_xplained_mmc_defconfig

@@ -37,6 +37,8 @@ CONFIG_BOOTCOMMAND="fatload mmc 1:1 0x22000000 at91-sama5d2_xplained.dtb; fatloa
 CONFIG_MISC_INIT_R=y
 CONFIG_HUSH_PARSER=y
 CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_DM=y
+CONFIG_CMD_GPIO=y
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_I2C=y
 # CONFIG_CMD_LOADS is not set

+ 2 - 0
configs/sama5d2_xplained_qspiflash_defconfig

@@ -37,6 +37,8 @@ CONFIG_BOOTCOMMAND="sf probe 1:0; sf read 0x22000000 0x180000 0x80000; sf read 0
 CONFIG_MISC_INIT_R=y
 CONFIG_HUSH_PARSER=y
 CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_DM=y
+CONFIG_CMD_GPIO=y
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_I2C=y
 # CONFIG_CMD_LOADS is not set

+ 2 - 0
configs/sama5d2_xplained_spiflash_defconfig

@@ -41,6 +41,8 @@ CONFIG_SPL_SPI_LOAD=y
 CONFIG_SYS_SPI_U_BOOT_OFFS=0x10000
 CONFIG_HUSH_PARSER=y
 CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_DM=y
+CONFIG_CMD_GPIO=y
 # CONFIG_CMD_FLASH is not set
 CONFIG_CMD_I2C=y
 # CONFIG_CMD_LOADS is not set

+ 572 - 25
drivers/spi/atmel-quadspi.c

@@ -17,6 +17,7 @@
 #include <errno.h>
 #include <fdtdec.h>
 #include <dm/device_compat.h>
+#include <linux/bitfield.h>
 #include <linux/bitops.h>
 #include <linux/err.h>
 #include <linux/io.h>
@@ -32,6 +33,7 @@
 #define QSPI_RD      0x0008  /* Receive Data Register */
 #define QSPI_TD      0x000c  /* Transmit Data Register */
 #define QSPI_SR      0x0010  /* Status Register */
+#define QSPI_SR2     0x0024  /* SAMA7G5 Status Register */
 #define QSPI_IER     0x0014  /* Interrupt Enable Register */
 #define QSPI_IDR     0x0018  /* Interrupt Disable Register */
 #define QSPI_IMR     0x001c  /* Interrupt Mask Register */
@@ -46,6 +48,13 @@
 #define QSPI_SMR     0x0040  /* Scrambling Mode Register */
 #define QSPI_SKR     0x0044  /* Scrambling Key Register */
 
+#define QSPI_REFRESH 0x0050  /* Refresh Register */
+#define QSPI_WRACNT  0x0054  /* Write Access Counter Register */
+#define QSPI_DLLCFG  0x0058  /* DLL Configuration Register */
+#define QSPI_PCALCFG 0x005C  /* Pad Calibration Configuration Register */
+#define QSPI_PCALBP  0x0060  /* Pad Calibration Bypass Register */
+#define QSPI_TOUT    0x0064  /* Timeout Register */
+
 #define QSPI_WPMR    0x00E4  /* Write Protection Mode Register */
 #define QSPI_WPSR    0x00E8  /* Write Protection Status Register */
 
@@ -54,7 +63,14 @@
 /* Bitfields in QSPI_CR (Control Register) */
 #define QSPI_CR_QSPIEN                  BIT(0)
 #define QSPI_CR_QSPIDIS                 BIT(1)
+#define QSPI_CR_DLLON			BIT(2)
+#define QSPI_CR_DLLOFF			BIT(3)
+#define QSPI_CR_STPCAL			BIT(4)
+#define QSPI_CR_SRFRSH			BIT(5)
 #define QSPI_CR_SWRST                   BIT(7)
+#define QSPI_CR_UPDCFG			BIT(8)
+#define QSPI_CR_STTFR			BIT(9)
+#define QSPI_CR_RTOUT			BIT(10)
 #define QSPI_CR_LASTXFER                BIT(24)
 
 /* Bitfields in QSPI_MR (Mode Register) */
@@ -62,12 +78,15 @@
 #define QSPI_MR_LLB                     BIT(1)
 #define QSPI_MR_WDRBT                   BIT(2)
 #define QSPI_MR_SMRM                    BIT(3)
+#define QSPI_MR_DQSDLYEN		BIT(3)
+
 #define QSPI_MR_CSMODE_MASK             GENMASK(5, 4)
 #define QSPI_MR_CSMODE_NOT_RELOADED     (0 << 4)
 #define QSPI_MR_CSMODE_LASTXFER         (1 << 4)
 #define QSPI_MR_CSMODE_SYSTEMATICALLY   (2 << 4)
 #define QSPI_MR_NBBITS_MASK             GENMASK(11, 8)
 #define QSPI_MR_NBBITS(n)               ((((n) - 8) << 8) & QSPI_MR_NBBITS_MASK)
+#define QSPI_MR_OENSD			BIT(15)
 #define QSPI_MR_DLYBCT_MASK             GENMASK(23, 16)
 #define QSPI_MR_DLYBCT(n)               (((n) << 16) & QSPI_MR_DLYBCT_MASK)
 #define QSPI_MR_DLYCS_MASK              GENMASK(31, 24)
@@ -81,6 +100,13 @@
 #define QSPI_SR_CSR                     BIT(8)
 #define QSPI_SR_CSS                     BIT(9)
 #define QSPI_SR_INSTRE                  BIT(10)
+#define QSPI_SR_LWRA			BIT(11)
+#define QSPI_SR_QITF			BIT(12)
+#define QSPI_SR_QITR			BIT(13)
+#define QSPI_SR_CSFA			BIT(14)
+#define QSPI_SR_CSRA			BIT(15)
+#define QSPI_SR_RFRSHD			BIT(16)
+#define QSPI_SR_TOUT			BIT(17)
 #define QSPI_SR_QSPIENS                 BIT(24)
 
 #define QSPI_SR_CMD_COMPLETED	(QSPI_SR_INSTRE | QSPI_SR_CSR)
@@ -93,9 +119,22 @@
 #define QSPI_SCR_DLYBS_MASK             GENMASK(23, 16)
 #define QSPI_SCR_DLYBS(n)               (((n) << 16) & QSPI_SCR_DLYBS_MASK)
 
+/* Bitfields in QSPI_SR2 (SAMA7G5 Status Register) */
+#define QSPI_SR2_SYNCBSY		BIT(0)
+#define QSPI_SR2_QSPIENS		BIT(1)
+#define QSPI_SR2_CSS			BIT(2)
+#define QSPI_SR2_RBUSY			BIT(3)
+#define QSPI_SR2_HIDLE			BIT(4)
+#define QSPI_SR2_DLOCK			BIT(5)
+#define QSPI_SR2_CALBSY			BIT(6)
+
+/* Bitfields in QSPI_IAR (Instruction Address Register) */
+#define QSPI_IAR_ADDR			GENMASK(31, 0)
+
 /* Bitfields in QSPI_ICR (Read/Write Instruction Code Register) */
 #define QSPI_ICR_INST_MASK              GENMASK(7, 0)
 #define QSPI_ICR_INST(inst)             (((inst) << 0) & QSPI_ICR_INST_MASK)
+#define QSPI_ICR_INST_MASK_SAMA7G5	GENMASK(15, 0)
 #define QSPI_ICR_OPT_MASK               GENMASK(23, 16)
 #define QSPI_ICR_OPT(opt)               (((opt) << 16) & QSPI_ICR_OPT_MASK)
 
@@ -108,6 +147,9 @@
 #define QSPI_IFR_WIDTH_QUAD_IO          (4 << 0)
 #define QSPI_IFR_WIDTH_DUAL_CMD         (5 << 0)
 #define QSPI_IFR_WIDTH_QUAD_CMD         (6 << 0)
+#define QSPI_IFR_WIDTH_OCT_OUTPUT	(7 << 0)
+#define QSPI_IFR_WIDTH_OCT_IO		(8 << 0)
+#define QSPI_IFR_WIDTH_OCT_CMD		(9 << 0)
 #define QSPI_IFR_INSTEN                 BIT(4)
 #define QSPI_IFR_ADDREN                 BIT(5)
 #define QSPI_IFR_OPTEN                  BIT(6)
@@ -118,19 +160,60 @@
 #define QSPI_IFR_OPTL_4BIT              (2 << 8)
 #define QSPI_IFR_OPTL_8BIT              (3 << 8)
 #define QSPI_IFR_ADDRL                  BIT(10)
+#define QSPI_IFR_ADDRL_SAMA7G5		GENMASK(11, 10)
 #define QSPI_IFR_TFRTYP_MEM		BIT(12)
 #define QSPI_IFR_SAMA5D2_WRITE_TRSFR	BIT(13)
 #define QSPI_IFR_CRM                    BIT(14)
+#define QSPI_IFR_DDREN			BIT(15)
 #define QSPI_IFR_NBDUM_MASK             GENMASK(20, 16)
 #define QSPI_IFR_NBDUM(n)               (((n) << 16) & QSPI_IFR_NBDUM_MASK)
+#define QSPI_IFR_END			BIT(22)
+#define QSPI_IFR_SMRM			BIT(23)
 #define QSPI_IFR_APBTFRTYP_READ		BIT(24)	/* Defined in SAM9X60 */
+#define QSPI_IFR_DQSEN			BIT(25)
+#define QSPI_IFR_DDRCMDEN		BIT(26)
+#define QSPI_IFR_HFWBEN			BIT(27)
+#define QSPI_IFR_PROTTYP		GENMASK(29, 28)
+#define QSPI_IFR_PROTTYP_STD_SPI	0
+#define QSPI_IFR_PROTTYP_TWIN_QUAD	1
+#define QSPI_IFR_PROTTYP_OCTAFLASH	2
+#define QSPI_IFR_PROTTYP_HYPERFLASH	3
 
 /* Bitfields in QSPI_SMR (Scrambling Mode Register) */
 #define QSPI_SMR_SCREN                  BIT(0)
 #define QSPI_SMR_RVDIS                  BIT(1)
+#define QSPI_SMR_SCRKL			BIT(2)
+
+/* Bitfields in QSPI_REFRESH (Refresh Register) */
+#define QSPI_REFRESH_DELAY_COUNTER	GENMASK(31, 0)
+
+/* Bitfields in QSPI_WRACNT (Write Access Counter Register) */
+#define QSPI_WRACNT_NBWRA		GENMASK(31, 0)
+
+/* Bitfields in QSPI_DLLCFG (DLL Configuration Register) */
+#define QSPI_DLLCFG_RANGE		BIT(0)
+
+/* Bitfields in QSPI_PCALCFG (DLL Pad Calibration Configuration Register) */
+#define QSPI_PCALCFG_AAON		BIT(0)
+#define QSPI_PCALCFG_DAPCAL		BIT(1)
+#define QSPI_PCALCFG_DIFFPM		BIT(2)
+#define QSPI_PCALCFG_CLKDIV		GENMASK(6, 4)
+#define QSPI_PCALCFG_CALCNT		GENMASK(16, 8)
+#define QSPI_PCALCFG_CALP		GENMASK(27, 24)
+#define QSPI_PCALCFG_CALN		GENMASK(31, 28)
+
+/* Bitfields in QSPI_PCALBP (DLL Pad Calibration Bypass Register) */
+#define QSPI_PCALBP_BPEN		BIT(0)
+#define QSPI_PCALBP_CALPBP		GENMASK(11, 8)
+#define QSPI_PCALBP_CALNBP		GENMASK(19, 16)
+
+/* Bitfields in QSPI_TOUT (Timeout Register) */
+#define QSPI_TOUT_TCNTM			GENMASK(15, 0)
 
 /* Bitfields in QSPI_WPMR (Write Protection Mode Register) */
 #define QSPI_WPMR_WPEN                  BIT(0)
+#define QSPI_WPMR_WPITEN		BIT(1)
+#define QSPI_WPMR_WPCREN		BIT(2)
 #define QSPI_WPMR_WPKEY_MASK            GENMASK(31, 8)
 #define QSPI_WPMR_WPKEY(wpkey)          (((wpkey) << 8) & QSPI_WPMR_WPKEY_MASK)
 
@@ -139,21 +222,61 @@
 #define QSPI_WPSR_WPVSRC_MASK           GENMASK(15, 8)
 #define QSPI_WPSR_WPVSRC(src)           (((src) << 8) & QSPI_WPSR_WPVSRC)
 
+#define ATMEL_QSPI_TIMEOUT		1000000	/* us */
+#define ATMEL_QSPI_SYNC_TIMEOUT		300000	/* us */
+#define QSPI_DLLCFG_THRESHOLD_FREQ	90000000U
+#define QSPI_TOUT_MAX			0xffff
+
+/**
+ * struct atmel_qspi_pcal - Pad Calibration Clock Division
+ * @pclk_rate: peripheral clock rate.
+ * @pclkdiv: calibration clock division. The clock applied to the calibration
+ *	     cell is divided by pclkdiv + 1.
+ */
+struct atmel_qspi_pcal {
+	u32 pclk_rate;
+	u8 pclk_div;
+};
+
+#define ATMEL_QSPI_PCAL_ARRAY_SIZE     8
+static const struct atmel_qspi_pcal pcal[ATMEL_QSPI_PCAL_ARRAY_SIZE] = {
+	{25000000, 0},
+	{50000000, 1},
+	{75000000, 2},
+	{100000000, 3},
+	{125000000, 4},
+	{150000000, 5},
+	{175000000, 6},
+	{200000000, 7},
+};
+
 struct atmel_qspi_caps {
 	bool has_qspick;
+	bool has_gclk;
 	bool has_ricr;
+	bool octal;
 };
 
+struct atmel_qspi_priv_ops;
+
 struct atmel_qspi {
 	void __iomem *regs;
 	void __iomem *mem;
 	resource_size_t mmap_size;
 	const struct atmel_qspi_caps *caps;
+	const struct atmel_qspi_priv_ops *ops;
 	struct udevice *dev;
 	ulong bus_clk_rate;
 	u32 mr;
 };
 
+struct atmel_qspi_priv_ops {
+	int (*set_cfg)(struct atmel_qspi *aq, const struct spi_mem_op *op,
+		       u32 *offset);
+	int (*transfer)(struct atmel_qspi *aq, const struct spi_mem_op *op,
+			u32 offset);
+};
+
 struct atmel_qspi_mode {
 	u8 cmd_buswidth;
 	u8 addr_buswidth;
@@ -171,6 +294,19 @@ static const struct atmel_qspi_mode atmel_qspi_modes[] = {
 	{ 4, 4, 4, QSPI_IFR_WIDTH_QUAD_CMD },
 };
 
+static const struct atmel_qspi_mode atmel_qspi_sama7g5_modes[] = {
+	{ 1, 1, 1, QSPI_IFR_WIDTH_SINGLE_BIT_SPI },
+	{ 1, 1, 2, QSPI_IFR_WIDTH_DUAL_OUTPUT },
+	{ 1, 1, 4, QSPI_IFR_WIDTH_QUAD_OUTPUT },
+	{ 1, 2, 2, QSPI_IFR_WIDTH_DUAL_IO },
+	{ 1, 4, 4, QSPI_IFR_WIDTH_QUAD_IO },
+	{ 2, 2, 2, QSPI_IFR_WIDTH_DUAL_CMD },
+	{ 4, 4, 4, QSPI_IFR_WIDTH_QUAD_CMD },
+	{ 1, 1, 8, QSPI_IFR_WIDTH_OCT_OUTPUT },
+	{ 1, 8, 8, QSPI_IFR_WIDTH_OCT_IO },
+	{ 8, 8, 8, QSPI_IFR_WIDTH_OCT_CMD },
+};
+
 #ifdef VERBOSE_DEBUG
 static const char *atmel_qspi_reg_name(u32 offset, char *tmp, size_t sz)
 {
@@ -180,7 +316,7 @@ static const char *atmel_qspi_reg_name(u32 offset, char *tmp, size_t sz)
 	case QSPI_MR:
 		return "MR";
 	case QSPI_RD:
-		return "MR";
+		return "RD";
 	case QSPI_TD:
 		return "TD";
 	case QSPI_SR:
@@ -193,6 +329,8 @@ static const char *atmel_qspi_reg_name(u32 offset, char *tmp, size_t sz)
 		return "IMR";
 	case QSPI_SCR:
 		return "SCR";
+	case QSPI_SR2:
+		return "SR2";
 	case QSPI_IAR:
 		return "IAR";
 	case QSPI_ICR:
@@ -205,6 +343,18 @@ static const char *atmel_qspi_reg_name(u32 offset, char *tmp, size_t sz)
 		return "SMR";
 	case QSPI_SKR:
 		return "SKR";
+	case QSPI_REFRESH:
+		return "REFRESH";
+	case QSPI_WRACNT:
+		return "WRACNT";
+	case QSPI_DLLCFG:
+		return "DLLCFG";
+	case QSPI_PCALCFG:
+		return "PCALCFG";
+	case QSPI_PCALBP:
+		return "PCALBP";
+	case QSPI_TOUT:
+		return "TOUT";
 	case QSPI_WPMR:
 		return "WPMR";
 	case QSPI_WPSR:
@@ -272,9 +422,29 @@ static int atmel_qspi_find_mode(const struct spi_mem_op *op)
 	return -ENOTSUPP;
 }
 
+static int atmel_qspi_sama7g5_find_mode(const struct spi_mem_op *op)
+{
+	u32 i;
+
+	for (i = 0; i < ARRAY_SIZE(atmel_qspi_sama7g5_modes); i++)
+		if (atmel_qspi_is_compatible(op, &atmel_qspi_sama7g5_modes[i]))
+			return i;
+
+	return -EOPNOTSUPP;
+}
+
 static bool atmel_qspi_supports_op(struct spi_slave *slave,
 				   const struct spi_mem_op *op)
 {
+	struct atmel_qspi *aq = dev_get_priv(slave->dev->parent);
+
+	if (aq->caps->octal) {
+		if (atmel_qspi_sama7g5_find_mode(op) < 0)
+			return false;
+		else
+			return true;
+	}
+
 	if (atmel_qspi_find_mode(op) < 0)
 		return false;
 
@@ -397,24 +567,10 @@ static int atmel_qspi_set_cfg(struct atmel_qspi *aq,
 	return 0;
 }
 
-static int atmel_qspi_exec_op(struct spi_slave *slave,
-			      const struct spi_mem_op *op)
+static int atmel_qspi_transfer(struct atmel_qspi *aq,
+			       const struct spi_mem_op *op, u32 offset)
 {
-	struct atmel_qspi *aq = dev_get_priv(slave->dev->parent);
-	u32 sr, imr, offset;
-	int err;
-
-	/*
-	 * Check if the address exceeds the MMIO window size. An improvement
-	 * would be to add support for regular SPI mode and fall back to it
-	 * when the flash memories overrun the controller's memory space.
-	 */
-	if (op->addr.val + op->data.nbytes > aq->mmap_size)
-		return -ENOTSUPP;
-
-	err = atmel_qspi_set_cfg(aq, op, &offset);
-	if (err)
-		return err;
+	u32 sr, imr;
 
 	/* Skip to the final steps if there is no data */
 	if (op->data.nbytes) {
@@ -436,7 +592,341 @@ static int atmel_qspi_exec_op(struct spi_slave *slave,
 	/* Poll INSTruction End and Chip Select Rise flags. */
 	imr = QSPI_SR_INSTRE | QSPI_SR_CSR;
 	return readl_poll_timeout(aq->regs + QSPI_SR, sr, (sr & imr) == imr,
-				  1000000);
+				  ATMEL_QSPI_TIMEOUT);
+}
+
+static int atmel_qspi_reg_sync(struct atmel_qspi *aq)
+{
+	u32 val;
+
+	return readl_poll_timeout(aq->regs + QSPI_SR2, val,
+				  !(val & QSPI_SR2_SYNCBSY),
+				  ATMEL_QSPI_SYNC_TIMEOUT);
+}
+
+static int atmel_qspi_update_config(struct atmel_qspi *aq)
+{
+	int ret;
+
+	ret = atmel_qspi_reg_sync(aq);
+	if (ret)
+		return ret;
+	atmel_qspi_write(QSPI_CR_UPDCFG, aq, QSPI_CR);
+	return atmel_qspi_reg_sync(aq);
+}
+
+static int atmel_qspi_sama7g5_set_cfg(struct atmel_qspi *aq,
+				      const struct spi_mem_op *op, u32 *offset)
+{
+	u32 iar, icr, ifr;
+	int mode, ret;
+
+	iar = 0;
+	icr = FIELD_PREP(QSPI_ICR_INST_MASK_SAMA7G5, op->cmd.opcode);
+	ifr = QSPI_IFR_INSTEN;
+
+	mode = atmel_qspi_sama7g5_find_mode(op);
+	if (mode < 0)
+		return mode;
+	ifr |= atmel_qspi_sama7g5_modes[mode].config;
+
+	if (op->dummy.buswidth && op->dummy.nbytes) {
+		if (op->addr.dtr && op->dummy.dtr && op->data.dtr)
+			ifr |= QSPI_IFR_NBDUM(op->dummy.nbytes * 8 /
+					      (2 * op->dummy.buswidth));
+		else
+			ifr |= QSPI_IFR_NBDUM(op->dummy.nbytes * 8 /
+					      op->dummy.buswidth);
+	}
+
+	if (op->addr.buswidth && op->addr.nbytes) {
+		ifr |= FIELD_PREP(QSPI_IFR_ADDRL_SAMA7G5, op->addr.nbytes - 1) |
+		       QSPI_IFR_ADDREN;
+		iar = FIELD_PREP(QSPI_IAR_ADDR, op->addr.val);
+	}
+
+	if (op->addr.dtr && op->dummy.dtr && op->data.dtr) {
+		ifr |= QSPI_IFR_DDREN;
+		if (op->cmd.dtr)
+			ifr |= QSPI_IFR_DDRCMDEN;
+		ifr |= QSPI_IFR_DQSEN;
+	}
+
+	if (op->cmd.buswidth == 8 || op->addr.buswidth == 8 ||
+	    op->data.buswidth == 8)
+		ifr |= FIELD_PREP(QSPI_IFR_PROTTYP, QSPI_IFR_PROTTYP_OCTAFLASH);
+
+	/* offset of the data access in the QSPI memory space */
+	*offset = iar;
+
+	/* Set data enable */
+	if (op->data.nbytes) {
+		ifr |= QSPI_IFR_DATAEN;
+		if (op->addr.nbytes)
+			ifr |= QSPI_IFR_TFRTYP_MEM;
+	}
+
+	/*
+	 * If the QSPI controller is set in regular SPI mode, set it in
+	 * Serial Memory Mode (SMM).
+	 */
+	if (aq->mr != QSPI_MR_SMM) {
+		atmel_qspi_write(QSPI_MR_SMM | QSPI_MR_DQSDLYEN, aq, QSPI_MR);
+		ret = atmel_qspi_update_config(aq);
+		if (ret)
+			return ret;
+		aq->mr = QSPI_MR_SMM;
+	}
+
+	/* Clear pending interrupts */
+	(void)atmel_qspi_read(aq, QSPI_SR);
+
+	/* Set QSPI Instruction Frame registers */
+	if (op->addr.nbytes && !op->data.nbytes)
+		atmel_qspi_write(iar, aq, QSPI_IAR);
+
+	if (op->data.dir == SPI_MEM_DATA_IN) {
+		atmel_qspi_write(icr, aq, QSPI_RICR);
+	} else {
+		atmel_qspi_write(icr, aq, QSPI_WICR);
+		if (op->data.nbytes)
+			atmel_qspi_write(FIELD_PREP(QSPI_WRACNT_NBWRA,
+						    op->data.nbytes),
+					 aq, QSPI_WRACNT);
+	}
+
+	atmel_qspi_write(ifr, aq, QSPI_IFR);
+
+	return atmel_qspi_update_config(aq);
+}
+
+static int atmel_qspi_sama7g5_transfer(struct atmel_qspi *aq,
+				       const struct spi_mem_op *op, u32 offset)
+{
+	int err;
+	u32 val;
+
+	if (!op->data.nbytes) {
+		/* Start the transfer. */
+		err = atmel_qspi_reg_sync(aq);
+		if (err)
+			return err;
+		atmel_qspi_write(QSPI_CR_STTFR, aq, QSPI_CR);
+
+		return readl_poll_timeout(aq->regs + QSPI_SR, val,
+					  val & QSPI_SR_CSRA,
+					  ATMEL_QSPI_TIMEOUT);
+	}
+
+	/* Send/Receive data. */
+	if (op->data.dir == SPI_MEM_DATA_IN) {
+		memcpy_fromio(op->data.buf.in, aq->mem + offset,
+			      op->data.nbytes);
+
+		if (op->addr.nbytes) {
+			err = readl_poll_timeout(aq->regs + QSPI_SR2, val,
+						 !(val & QSPI_SR2_RBUSY),
+						 ATMEL_QSPI_SYNC_TIMEOUT);
+			if (err)
+				return err;
+		}
+	} else {
+		memcpy_toio(aq->mem + offset, op->data.buf.out,
+			    op->data.nbytes);
+
+		err = readl_poll_timeout(aq->regs + QSPI_SR, val,
+					 val & QSPI_SR_LWRA,
+					 ATMEL_QSPI_TIMEOUT);
+		if (err)
+			return err;
+	}
+
+	/* Release the chip-select. */
+	err = atmel_qspi_reg_sync(aq);
+	if (err)
+		return err;
+	atmel_qspi_write(QSPI_CR_LASTXFER, aq, QSPI_CR);
+
+	return readl_poll_timeout(aq->regs + QSPI_SR, val, val & QSPI_SR_CSRA,
+				  ATMEL_QSPI_TIMEOUT);
+}
+
+static int atmel_qspi_exec_op(struct spi_slave *slave,
+			      const struct spi_mem_op *op)
+{
+	struct atmel_qspi *aq = dev_get_priv(slave->dev->parent);
+	u32 offset;
+	int err;
+
+	/*
+	 * Check if the address exceeds the MMIO window size. An improvement
+	 * would be to add support for regular SPI mode and fall back to it
+	 * when the flash memories overrun the controller's memory space.
+	 */
+	if (op->addr.val + op->data.nbytes > aq->mmap_size)
+		return -ENOTSUPP;
+
+	if (op->addr.nbytes > 4)
+		return -EOPNOTSUPP;
+
+	err = aq->ops->set_cfg(aq, op, &offset);
+	if (err)
+		return err;
+
+	return aq->ops->transfer(aq, op, offset);
+}
+
+static int atmel_qspi_set_pad_calibration(struct udevice *bus, uint hz)
+{
+	struct atmel_qspi *aq = dev_get_priv(bus);
+	u32 status, val;
+	int i, ret;
+	u8 pclk_div = 0;
+
+	for (i = 0; i < ATMEL_QSPI_PCAL_ARRAY_SIZE; i++) {
+		if (aq->bus_clk_rate <= pcal[i].pclk_rate) {
+			pclk_div = pcal[i].pclk_div;
+			break;
+		}
+	}
+
+	/*
+	 * Use the biggest divider in case the peripheral clock exceeds
+	 * 200MHZ.
+	 */
+	if (aq->bus_clk_rate > pcal[ATMEL_QSPI_PCAL_ARRAY_SIZE - 1].pclk_rate)
+		pclk_div = pcal[ATMEL_QSPI_PCAL_ARRAY_SIZE - 1].pclk_div;
+
+	/* Disable QSPI while configuring the pad calibration. */
+	status = atmel_qspi_read(aq, QSPI_SR2);
+	if (status & QSPI_SR2_QSPIENS) {
+		ret = atmel_qspi_reg_sync(aq);
+		if (ret)
+			return ret;
+		atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR);
+	}
+
+	/*
+	 * The analog circuitry is not shut down at the end of the calibration
+	 * and the start-up time is only required for the first calibration
+	 * sequence, thus increasing performance. Set the delay between the Pad
+	 * calibration analog circuitry and the calibration request to 2us.
+	 */
+	atmel_qspi_write(QSPI_PCALCFG_AAON |
+			 FIELD_PREP(QSPI_PCALCFG_CLKDIV, pclk_div) |
+			 FIELD_PREP(QSPI_PCALCFG_CALCNT,
+				    2 * (aq->bus_clk_rate / 1000000)),
+			 aq, QSPI_PCALCFG);
+
+	/* DLL On + start calibration. */
+	atmel_qspi_write(QSPI_CR_DLLON | QSPI_CR_STPCAL, aq, QSPI_CR);
+	ret =  readl_poll_timeout(aq->regs + QSPI_SR2, val,
+				  (val & QSPI_SR2_DLOCK) &&
+				  !(val & QSPI_SR2_CALBSY),
+				  ATMEL_QSPI_TIMEOUT);
+
+	/* Refresh analogic blocks every 1 ms.*/
+	atmel_qspi_write(FIELD_PREP(QSPI_REFRESH_DELAY_COUNTER, hz / 1000),
+			 aq, QSPI_REFRESH);
+
+	return ret;
+}
+
+static int atmel_qspi_set_gclk(struct udevice *bus, uint hz)
+{
+	struct atmel_qspi *aq = dev_get_priv(bus);
+	struct clk gclk;
+	u32 status, val;
+	int ret;
+
+	/* Disable DLL before setting GCLK */
+	status = atmel_qspi_read(aq, QSPI_SR2);
+	if (status & QSPI_SR2_DLOCK) {
+		atmel_qspi_write(QSPI_CR_DLLOFF, aq, QSPI_CR);
+		ret = readl_poll_timeout(aq->regs + QSPI_SR2, val,
+					 !(val & QSPI_SR2_DLOCK),
+					 ATMEL_QSPI_TIMEOUT);
+		if (ret)
+			return ret;
+	}
+
+	if (hz > QSPI_DLLCFG_THRESHOLD_FREQ)
+		atmel_qspi_write(QSPI_DLLCFG_RANGE, aq, QSPI_DLLCFG);
+	else
+		atmel_qspi_write(0, aq, QSPI_DLLCFG);
+
+	ret = clk_get_by_name(bus, "gclk", &gclk);
+	if (ret) {
+		dev_err(bus, "Missing QSPI generic clock\n");
+		return ret;
+	}
+
+	ret = clk_disable(&gclk);
+	if (ret)
+		dev_err(bus, "Failed to disable QSPI generic clock\n");
+
+	ret = clk_set_rate(&gclk, hz);
+	if (ret < 0) {
+		dev_err(bus, "Failed to set generic clock rate.\n");
+		return ret;
+	}
+
+	ret = clk_enable(&gclk);
+	if (ret)
+		dev_err(bus, "Failed to enable QSPI generic clock\n");
+	clk_free(&gclk);
+
+	return ret;
+}
+
+static int atmel_qspi_sama7g5_set_speed(struct udevice *bus, uint hz)
+{
+	struct atmel_qspi *aq = dev_get_priv(bus);
+	u32 val;
+	int ret;
+
+	ret = atmel_qspi_set_gclk(bus, hz);
+	if (ret)
+		return ret;
+
+	if (aq->caps->octal) {
+		ret = atmel_qspi_set_pad_calibration(bus, hz);
+		if (ret)
+			return ret;
+	} else {
+		atmel_qspi_write(QSPI_CR_DLLON, aq, QSPI_CR);
+		ret =  readl_poll_timeout(aq->regs + QSPI_SR2, val,
+					  val & QSPI_SR2_DLOCK,
+					  ATMEL_QSPI_TIMEOUT);
+	}
+
+	/* Set the QSPI controller by default in Serial Memory Mode */
+	atmel_qspi_write(QSPI_MR_SMM | QSPI_MR_DQSDLYEN, aq, QSPI_MR);
+	ret = atmel_qspi_update_config(aq);
+	if (ret)
+		return ret;
+	aq->mr = QSPI_MR_SMM;
+
+	/* Enable the QSPI controller. */
+	ret = atmel_qspi_reg_sync(aq);
+	if (ret)
+		return ret;
+	atmel_qspi_write(QSPI_CR_QSPIEN, aq, QSPI_CR);
+	ret = readl_poll_timeout(aq->regs + QSPI_SR2, val,
+				 val & QSPI_SR2_QSPIENS,
+				 ATMEL_QSPI_SYNC_TIMEOUT);
+	if (ret)
+		return ret;
+
+	if (aq->caps->octal)
+		ret = readl_poll_timeout(aq->regs + QSPI_SR, val,
+					 val & QSPI_SR_RFRSHD,
+					 ATMEL_QSPI_TIMEOUT);
+
+	atmel_qspi_write(FIELD_PREP(QSPI_TOUT_TCNTM, QSPI_TOUT_MAX),
+			 aq, QSPI_TOUT);
+
+	return ret;
 }
 
 static int atmel_qspi_set_speed(struct udevice *bus, uint hz)
@@ -444,6 +934,9 @@ static int atmel_qspi_set_speed(struct udevice *bus, uint hz)
 	struct atmel_qspi *aq = dev_get_priv(bus);
 	u32 scr, scbr, mask, new_value;
 
+	if (aq->caps->has_gclk)
+		return atmel_qspi_sama7g5_set_speed(bus, hz);
+
 	/* Compute the QSPI baudrate */
 	scbr = DIV_ROUND_UP(aq->bus_clk_rate, hz);
 	if (scbr > 0)
@@ -480,6 +973,8 @@ static int atmel_qspi_set_mode(struct udevice *bus, uint mode)
 
 	scr = (scr & ~mask) | new_value;
 	atmel_qspi_write(scr, aq, QSPI_SCR);
+	if (aq->caps->has_gclk)
+		return atmel_qspi_update_config(aq);
 
 	return 0;
 }
@@ -487,7 +982,7 @@ static int atmel_qspi_set_mode(struct udevice *bus, uint mode)
 static int atmel_qspi_enable_clk(struct udevice *dev)
 {
 	struct atmel_qspi *aq = dev_get_priv(dev);
-	struct clk pclk, qspick;
+	struct clk pclk, qspick, gclk;
 	int ret;
 
 	ret = clk_get_by_name(dev, "pclk", &pclk);
@@ -517,6 +1012,17 @@ static int atmel_qspi_enable_clk(struct udevice *dev)
 		if (ret)
 			dev_err(dev, "Failed to enable QSPI system clock\n");
 		clk_free(&qspick);
+	} else if (aq->caps->has_gclk) {
+		ret = clk_get_by_name(dev, "gclk", &gclk);
+		if (ret) {
+			dev_err(dev, "Missing QSPI generic clock\n");
+			goto free_pclk;
+		}
+
+		ret = clk_enable(&gclk);
+		if (ret)
+			dev_err(dev, "Failed to enable QSPI system clock\n");
+		clk_free(&gclk);
 	}
 
 	aq->bus_clk_rate = clk_get_rate(&pclk);
@@ -529,8 +1035,18 @@ free_pclk:
 	return ret;
 }
 
-static void atmel_qspi_init(struct atmel_qspi *aq)
+static int atmel_qspi_init(struct atmel_qspi *aq)
 {
+	int ret;
+
+	if (aq->caps->has_gclk) {
+		ret = atmel_qspi_reg_sync(aq);
+		if (ret)
+			return ret;
+		atmel_qspi_write(QSPI_CR_SWRST, aq, QSPI_CR);
+		return 0;
+	}
+
 	/* Reset the QSPI controller */
 	atmel_qspi_write(QSPI_CR_SWRST, aq, QSPI_CR);
 
@@ -540,8 +1056,20 @@ static void atmel_qspi_init(struct atmel_qspi *aq)
 
 	/* Enable the QSPI controller */
 	atmel_qspi_write(QSPI_CR_QSPIEN, aq, QSPI_CR);
+
+	return 0;
 }
 
+static const struct atmel_qspi_priv_ops atmel_qspi_priv_ops = {
+	.set_cfg = atmel_qspi_set_cfg,
+	.transfer = atmel_qspi_transfer,
+};
+
+static const struct atmel_qspi_priv_ops atmel_qspi_sama7g5_priv_ops = {
+	.set_cfg = atmel_qspi_sama7g5_set_cfg,
+	.transfer = atmel_qspi_sama7g5_transfer,
+};
+
 static int atmel_qspi_probe(struct udevice *dev)
 {
 	struct atmel_qspi *aq = dev_get_priv(dev);
@@ -554,6 +1082,11 @@ static int atmel_qspi_probe(struct udevice *dev)
 		return -EINVAL;
 	};
 
+	if (aq->caps->has_gclk)
+		aq->ops = &atmel_qspi_sama7g5_priv_ops;
+	else
+		aq->ops = &atmel_qspi_priv_ops;
+
 	/* Map the registers */
 	ret = dev_read_resource_byname(dev, "qspi_base", &res);
 	if (ret) {
@@ -583,10 +1116,7 @@ static int atmel_qspi_probe(struct udevice *dev)
 		return ret;
 
 	aq->dev = dev;
-
-	atmel_qspi_init(aq);
-
-	return 0;
+	return atmel_qspi_init(aq);
 }
 
 static const struct spi_controller_mem_ops atmel_qspi_mem_ops = {
@@ -607,6 +1137,15 @@ static const struct atmel_qspi_caps atmel_sam9x60_qspi_caps = {
 	.has_ricr = true,
 };
 
+static const struct atmel_qspi_caps atmel_sama7g5_ospi_caps = {
+	.has_gclk = true,
+	.octal = true,
+};
+
+static const struct atmel_qspi_caps atmel_sama7g5_qspi_caps = {
+	.has_gclk = true,
+};
+
 static const struct udevice_id atmel_qspi_ids[] = {
 	{
 		.compatible = "atmel,sama5d2-qspi",
@@ -616,6 +1155,14 @@ static const struct udevice_id atmel_qspi_ids[] = {
 		.compatible = "microchip,sam9x60-qspi",
 		.data = (ulong)&atmel_sam9x60_qspi_caps,
 	},
+	{
+		.compatible = "microchip,sama7g5-ospi",
+		.data = (ulong)&atmel_sama7g5_ospi_caps,
+	},
+	{
+		.compatible = "microchip,sama7g5-qspi",
+		.data = (ulong)&atmel_sama7g5_qspi_caps,
+	},
 	{ /* sentinel */ }
 };