Merge tag 'u-boot-at91-2022.04-a' of https://source.denx.de/u-boot/custodians/u-boot...
authorTom Rini <trini@konsulko.com>
Fri, 17 Dec 2021 12:25:34 +0000 (07:25 -0500)
committerTom Rini <trini@konsulko.com>
Fri, 17 Dec 2021 12:25:34 +0000 (07:25 -0500)
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.

21 files changed:
arch/arm/dts/sam9x60.dtsi
arch/arm/dts/sama7g5-pinfunc.h
arch/arm/dts/sama7g5.dtsi
arch/arm/dts/sama7g5ek.dts
arch/arm/mach-at91/arm926ejs/Makefile
configs/sam9x60ek_mmc_defconfig
configs/sam9x60ek_nandflash_defconfig
configs/sam9x60ek_qspiflash_defconfig
configs/sama5d27_som1_ek_mmc1_defconfig
configs/sama5d27_som1_ek_mmc_defconfig
configs/sama5d27_som1_ek_qspiflash_defconfig
configs/sama5d27_wlsom1_ek_mmc_defconfig
configs/sama5d27_wlsom1_ek_qspiflash_defconfig
configs/sama5d2_icp_mmc_defconfig
configs/sama5d2_ptc_ek_mmc_defconfig
configs/sama5d2_ptc_ek_nandflash_defconfig
configs/sama5d2_xplained_emmc_defconfig
configs/sama5d2_xplained_mmc_defconfig
configs/sama5d2_xplained_qspiflash_defconfig
configs/sama5d2_xplained_spiflash_defconfig
drivers/spi/atmel-quadspi.c

index e801331..be44519 100644 (file)
@@ -22,6 +22,7 @@
                serial0 = &dbgu;
                gpio0 = &pioA;
                gpio1 = &pioB;
+               gpio2 = &pioC;
                gpio3 = &pioD;
                spi0 = &qspi;
        };
                                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>;
index b5472fa..38d6962 100644 (file)
 #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)
index b951aff..4a3c675 100644 (file)
                                #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>;
index 1c59a8a..16192ca 100644 (file)
@@ -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";
        };
 };
 
+&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";
                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>,
index 8de6a2f..c1904d5 100644 (file)
@@ -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
index 28b75b1..59fc4a9 100644 (file)
@@ -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
index c36e565..fe88daf 100644 (file)
@@ -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
index 7124fd0..7a5d4d0 100644 (file)
@@ -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
index acb7c15..4728901 100644 (file)
@@ -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
index 96b0804..811e7f7 100644 (file)
@@ -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
index bd59526..7bff572 100644 (file)
@@ -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
index 7562457..b379c26 100644 (file)
@@ -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
index c23c209..b68d6cd 100644 (file)
@@ -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
index 56bd3f4..3c7500c 100644 (file)
@@ -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
index 57af30a..77053bc 100644 (file)
@@ -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
index 832a91c..07ed9d1 100644 (file)
@@ -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
index 9357e0a..0c72f33 100644 (file)
@@ -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
index 31d4204..8919f61 100644 (file)
@@ -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
index 78d691c..58919ab 100644 (file)
@@ -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
index 6ec92f1..ae192c0 100644 (file)
@@ -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
index b1a3aa9..0982983 100644 (file)
@@ -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 */
 #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 */
 
 /* 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) */
 #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)
 #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)
 #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)
 
 #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)
 #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)
 
 #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 */ }
 };