summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2021-12-17 15:25:34 +0300
committerTom Rini <trini@konsulko.com>2021-12-17 15:25:34 +0300
commitb9c9ce8a4064c8d88f714604db856cf1cd2b40b5 (patch)
treeee0ae60cf9b45f293141fba4805c7574fe9717b2
parent6c56bd31b7c11c1f4e97bf6bd1db9f48e35ec10b (diff)
parent9bf459c23dc03f3c4405650e3c8578265fd9d62c (diff)
downloadu-boot-b9c9ce8a4064c8d88f714604db856cf1cd2b40b5.tar.xz
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.
-rw-r--r--arch/arm/dts/sam9x60.dtsi9
-rw-r--r--arch/arm/dts/sama7g5-pinfunc.h2
-rw-r--r--arch/arm/dts/sama7g5.dtsi26
-rw-r--r--arch/arm/dts/sama7g5ek.dts38
-rw-r--r--arch/arm/mach-at91/arm926ejs/Makefile7
-rw-r--r--configs/sam9x60ek_mmc_defconfig2
-rw-r--r--configs/sam9x60ek_nandflash_defconfig2
-rw-r--r--configs/sam9x60ek_qspiflash_defconfig2
-rw-r--r--configs/sama5d27_som1_ek_mmc1_defconfig2
-rw-r--r--configs/sama5d27_som1_ek_mmc_defconfig2
-rw-r--r--configs/sama5d27_som1_ek_qspiflash_defconfig2
-rw-r--r--configs/sama5d27_wlsom1_ek_mmc_defconfig2
-rw-r--r--configs/sama5d27_wlsom1_ek_qspiflash_defconfig2
-rw-r--r--configs/sama5d2_icp_mmc_defconfig2
-rw-r--r--configs/sama5d2_ptc_ek_mmc_defconfig2
-rw-r--r--configs/sama5d2_ptc_ek_nandflash_defconfig2
-rw-r--r--configs/sama5d2_xplained_emmc_defconfig2
-rw-r--r--configs/sama5d2_xplained_mmc_defconfig2
-rw-r--r--configs/sama5d2_xplained_qspiflash_defconfig2
-rw-r--r--configs/sama5d2_xplained_spiflash_defconfig2
-rw-r--r--drivers/spi/atmel-quadspi.c597
21 files changed, 681 insertions, 28 deletions
diff --git a/arch/arm/dts/sam9x60.dtsi b/arch/arm/dts/sam9x60.dtsi
index e801331d80..be44519934 100644
--- a/arch/arm/dts/sam9x60.dtsi
+++ b/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>;
diff --git a/arch/arm/dts/sama7g5-pinfunc.h b/arch/arm/dts/sama7g5-pinfunc.h
index b5472fa4c9..38d6962d00 100644
--- a/arch/arm/dts/sama7g5-pinfunc.h
+++ b/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)
diff --git a/arch/arm/dts/sama7g5.dtsi b/arch/arm/dts/sama7g5.dtsi
index b951aff43e..4a3c675d34 100644
--- a/arch/arm/dts/sama7g5.dtsi
+++ b/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>;
diff --git a/arch/arm/dts/sama7g5ek.dts b/arch/arm/dts/sama7g5ek.dts
index 1c59a8aaf8..16192ca0b1 100644
--- a/arch/arm/dts/sama7g5ek.dts
+++ b/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>,
diff --git a/arch/arm/mach-at91/arm926ejs/Makefile b/arch/arm/mach-at91/arm926ejs/Makefile
index 8de6a2f966..c1904d535b 100644
--- a/arch/arm/mach-at91/arm926ejs/Makefile
+++ b/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
diff --git a/configs/sam9x60ek_mmc_defconfig b/configs/sam9x60ek_mmc_defconfig
index 28b75b12fb..59fc4a983d 100644
--- a/configs/sam9x60ek_mmc_defconfig
+++ b/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
diff --git a/configs/sam9x60ek_nandflash_defconfig b/configs/sam9x60ek_nandflash_defconfig
index c36e565aee..fe88daf431 100644
--- a/configs/sam9x60ek_nandflash_defconfig
+++ b/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
diff --git a/configs/sam9x60ek_qspiflash_defconfig b/configs/sam9x60ek_qspiflash_defconfig
index 7124fd0509..7a5d4d0600 100644
--- a/configs/sam9x60ek_qspiflash_defconfig
+++ b/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
diff --git a/configs/sama5d27_som1_ek_mmc1_defconfig b/configs/sama5d27_som1_ek_mmc1_defconfig
index acb7c1582f..472890183f 100644
--- a/configs/sama5d27_som1_ek_mmc1_defconfig
+++ b/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
diff --git a/configs/sama5d27_som1_ek_mmc_defconfig b/configs/sama5d27_som1_ek_mmc_defconfig
index 96b08044fc..811e7f7a7c 100644
--- a/configs/sama5d27_som1_ek_mmc_defconfig
+++ b/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
diff --git a/configs/sama5d27_som1_ek_qspiflash_defconfig b/configs/sama5d27_som1_ek_qspiflash_defconfig
index bd59526b41..7bff5726fc 100644
--- a/configs/sama5d27_som1_ek_qspiflash_defconfig
+++ b/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
diff --git a/configs/sama5d27_wlsom1_ek_mmc_defconfig b/configs/sama5d27_wlsom1_ek_mmc_defconfig
index 7562457902..b379c26d35 100644
--- a/configs/sama5d27_wlsom1_ek_mmc_defconfig
+++ b/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
diff --git a/configs/sama5d27_wlsom1_ek_qspiflash_defconfig b/configs/sama5d27_wlsom1_ek_qspiflash_defconfig
index c23c209931..b68d6cde3d 100644
--- a/configs/sama5d27_wlsom1_ek_qspiflash_defconfig
+++ b/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
diff --git a/configs/sama5d2_icp_mmc_defconfig b/configs/sama5d2_icp_mmc_defconfig
index 56bd3f44a6..3c7500ce7b 100644
--- a/configs/sama5d2_icp_mmc_defconfig
+++ b/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
diff --git a/configs/sama5d2_ptc_ek_mmc_defconfig b/configs/sama5d2_ptc_ek_mmc_defconfig
index 57af30adf0..77053bce6f 100644
--- a/configs/sama5d2_ptc_ek_mmc_defconfig
+++ b/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
diff --git a/configs/sama5d2_ptc_ek_nandflash_defconfig b/configs/sama5d2_ptc_ek_nandflash_defconfig
index 832a91c023..07ed9d178e 100644
--- a/configs/sama5d2_ptc_ek_nandflash_defconfig
+++ b/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
diff --git a/configs/sama5d2_xplained_emmc_defconfig b/configs/sama5d2_xplained_emmc_defconfig
index 9357e0a1d3..0c72f33f2f 100644
--- a/configs/sama5d2_xplained_emmc_defconfig
+++ b/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
diff --git a/configs/sama5d2_xplained_mmc_defconfig b/configs/sama5d2_xplained_mmc_defconfig
index 31d420416e..8919f612d3 100644
--- a/configs/sama5d2_xplained_mmc_defconfig
+++ b/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
diff --git a/configs/sama5d2_xplained_qspiflash_defconfig b/configs/sama5d2_xplained_qspiflash_defconfig
index 78d691c317..58919ab3eb 100644
--- a/configs/sama5d2_xplained_qspiflash_defconfig
+++ b/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
diff --git a/configs/sama5d2_xplained_spiflash_defconfig b/configs/sama5d2_xplained_spiflash_defconfig
index 6ec92f10cf..ae192c0057 100644
--- a/configs/sama5d2_xplained_spiflash_defconfig
+++ b/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
diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c
index b1a3aa9a29..098298336d 100644
--- a/drivers/spi/atmel-quadspi.c
+++ b/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 */ }
};