diff options
21 files changed, 681 insertions, 28 deletions
diff --git a/arch/arm/dts/sam9x60.dtsi b/arch/arm/dts/sam9x60.dtsi index e801331d80a..be44519934b 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 b5472fa4c95..38d6962d004 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 b951aff43e2..4a3c675d344 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 1c59a8aaf8f..16192ca0b15 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 8de6a2f9661..c1904d535be 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 28b75b12fb8..59fc4a983d8 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 c36e565aeed..fe88daf4317 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 7124fd05097..7a5d4d0600c 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 acb7c1582f4..472890183fc 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 96b08044fc0..811e7f7a7c0 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 bd59526b41f..7bff5726fc7 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 75624579023..b379c26d352 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 c23c2099318..b68d6cde3d3 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 56bd3f44a6c..3c7500ce7b6 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 57af30adf08..77053bce6ff 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 832a91c023a..07ed9d178e3 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 9357e0a1d37..0c72f33f2f5 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 31d420416e5..8919f612d36 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 78d691c3170..58919ab3ebb 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 6ec92f10cf2..ae192c00573 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 b1a3aa9a297..098298336da 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 */ } }; |