diff options
author | Tom Rini <trini@konsulko.com> | 2022-11-03 08:27:44 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2022-11-03 08:27:44 -0400 |
commit | c07babda65a47439b4f02bbb3204dfcb8679edc1 (patch) | |
tree | 328a9d369b453a38a81c86f8b731770a48886bda | |
parent | cca41ed3d63f462ca044e0d2d30a34d4917fc6c5 (diff) | |
parent | 7321bad25f18684b53cff4346543fb2da2a2c0d0 (diff) |
Merge branch 'master' of https://source.denx.de/u-boot/custodians/u-boot-riscv
-rw-r--r-- | arch/riscv/Kconfig | 6 | ||||
-rw-r--r-- | arch/riscv/cpu/ax25/Kconfig | 2 | ||||
-rw-r--r-- | arch/riscv/dts/ae350-u-boot.dtsi | 2 | ||||
-rw-r--r-- | arch/riscv/dts/ae350_32.dts | 6 | ||||
-rw-r--r-- | arch/riscv/dts/ae350_64.dts | 6 | ||||
-rw-r--r-- | arch/riscv/dts/microchip-mpfs-icicle-kit.dts | 91 | ||||
-rw-r--r-- | arch/riscv/include/asm/global_data.h | 4 | ||||
-rw-r--r-- | arch/riscv/include/asm/syscon.h | 2 | ||||
-rw-r--r-- | arch/riscv/lib/Makefile | 2 | ||||
-rw-r--r-- | arch/riscv/lib/andes_plicsw.c (renamed from arch/riscv/lib/andes_plic.c) | 26 | ||||
-rw-r--r-- | board/microchip/mpfs_icicle/Kconfig | 7 | ||||
-rw-r--r-- | configs/microchip_mpfs_icicle_defconfig | 1 | ||||
-rw-r--r-- | drivers/spi/Kconfig | 6 | ||||
-rw-r--r-- | drivers/spi/Makefile | 1 | ||||
-rw-r--r-- | drivers/spi/microchip_coreqspi.c | 505 | ||||
-rw-r--r-- | drivers/timer/andes_plmt_timer.c | 2 |
16 files changed, 582 insertions, 87 deletions
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 8f9578171d3..4d64e9be3f2 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -199,7 +199,7 @@ config SIFIVE_CACHE help This enables the operations to configure SiFive cache -config ANDES_PLIC +config ANDES_PLICSW bool depends on RISCV_MMODE || SPL_RISCV_MMODE select REGMAP @@ -207,8 +207,8 @@ config ANDES_PLIC select SPL_REGMAP if SPL select SPL_SYSCON if SPL help - The Andes PLIC block holds memory-mapped claim and pending registers - associated with software interrupt. + The Andes PLICSW block holds memory-mapped claim and pending + registers associated with software interrupt. config SMP bool "Symmetric Multi-Processing" diff --git a/arch/riscv/cpu/ax25/Kconfig b/arch/riscv/cpu/ax25/Kconfig index 941d963ece4..4a7295d30c5 100644 --- a/arch/riscv/cpu/ax25/Kconfig +++ b/arch/riscv/cpu/ax25/Kconfig @@ -4,7 +4,7 @@ config RISCV_NDS imply CPU imply CPU_RISCV imply RISCV_TIMER if (RISCV_SMODE || SPL_RISCV_SMODE) - imply ANDES_PLIC if (RISCV_MMODE || SPL_RISCV_MMODE) + imply ANDES_PLICSW if (RISCV_MMODE || SPL_RISCV_MMODE) imply ANDES_PLMT_TIMER if (RISCV_MMODE || SPL_RISCV_MMODE) imply SPL_CPU imply SPL_OPENSBI diff --git a/arch/riscv/dts/ae350-u-boot.dtsi b/arch/riscv/dts/ae350-u-boot.dtsi index 0d4201cfae9..7011f598316 100644 --- a/arch/riscv/dts/ae350-u-boot.dtsi +++ b/arch/riscv/dts/ae350-u-boot.dtsi @@ -36,7 +36,7 @@ soc { u-boot,dm-spl; - plic1: interrupt-controller@e6400000 { + plicsw: interrupt-controller@e6400000 { u-boot,dm-spl; }; diff --git a/arch/riscv/dts/ae350_32.dts b/arch/riscv/dts/ae350_32.dts index 083f676333d..96ef8bd8ddb 100644 --- a/arch/riscv/dts/ae350_32.dts +++ b/arch/riscv/dts/ae350_32.dts @@ -146,8 +146,8 @@ &CPU3_intc 11 &CPU3_intc 9>; }; - plic1: interrupt-controller@e6400000 { - compatible = "riscv,plic1"; + plicsw: interrupt-controller@e6400000 { + compatible = "andestech,plicsw"; #interrupt-cells = <1>; interrupt-controller; reg = <0xe6400000 0x400000>; @@ -159,7 +159,7 @@ }; plmt0@e6000000 { - compatible = "riscv,plmt0"; + compatible = "andestech,plmt0"; interrupts-extended = <&CPU0_intc 7 &CPU1_intc 7 &CPU2_intc 7 diff --git a/arch/riscv/dts/ae350_64.dts b/arch/riscv/dts/ae350_64.dts index 74cff9122d4..cddbaec98ad 100644 --- a/arch/riscv/dts/ae350_64.dts +++ b/arch/riscv/dts/ae350_64.dts @@ -146,8 +146,8 @@ &CPU3_intc 11 &CPU3_intc 9>; }; - plic1: interrupt-controller@e6400000 { - compatible = "riscv,plic1"; + plicsw: interrupt-controller@e6400000 { + compatible = "andestech,plicsw"; #interrupt-cells = <2>; interrupt-controller; reg = <0x0 0xe6400000 0x0 0x400000>; @@ -159,7 +159,7 @@ }; plmt0@e6000000 { - compatible = "riscv,plmt0"; + compatible = "andestech,plmt0"; interrupts-extended = <&CPU0_intc 7 &CPU1_intc 7 &CPU2_intc 7 diff --git a/arch/riscv/dts/microchip-mpfs-icicle-kit.dts b/arch/riscv/dts/microchip-mpfs-icicle-kit.dts index 287ef3d23b7..762dcfc6944 100644 --- a/arch/riscv/dts/microchip-mpfs-icicle-kit.dts +++ b/arch/riscv/dts/microchip-mpfs-icicle-kit.dts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* - * Copyright (C) 2021 Microchip Technology Inc. + * Copyright (C) 2021-2022 Microchip Technology Inc. * Padmarao Begari <padmarao.begari@microchip.com> */ @@ -13,11 +13,13 @@ / { model = "Microchip PolarFire-SoC Icicle Kit"; - compatible = "microchip,mpfs-icicle-kit", "microchip,mpfs"; + compatible = "microchip,mpfs-icicle-reference-rtlv2210", + "microchip,mpfs-icicle-kit", "microchip,mpfs"; aliases { serial1 = &uart1; ethernet0 = &mac1; + spi0 = &qspi; }; chosen { @@ -28,70 +30,28 @@ timebase-frequency = <RTCCLK_FREQ>; }; - reserved-memory { - ranges; - #size-cells = <2>; - #address-cells = <2>; - - fabricbuf0: fabricbuf@0 { - compatible = "shared-dma-pool"; - reg = <0x0 0xae000000 0x0 0x2000000>; - label = "fabricbuf0-ddr-c"; - }; - - fabricbuf1: fabricbuf@1 { - compatible = "shared-dma-pool"; - reg = <0x0 0xc0000000 0x0 0x8000000>; - label = "fabricbuf1-ddr-nc"; - }; - - fabricbuf2: fabricbuf@2 { - compatible = "shared-dma-pool"; - reg = <0x0 0xd8000000 0x0 0x8000000>; - label = "fabricbuf2-ddr-nc-wcb"; - }; - }; - - udmabuf0 { - compatible = "ikwzm,u-dma-buf"; - device-name = "udmabuf-ddr-c0"; - minor-number = <0>; - size = <0x0 0x2000000>; - memory-region = <&fabricbuf0>; - sync-mode = <3>; - }; - - udmabuf1 { - compatible = "ikwzm,u-dma-buf"; - device-name = "udmabuf-ddr-nc0"; - minor-number = <1>; - size = <0x0 0x8000000>; - memory-region = <&fabricbuf1>; - sync-mode = <3>; - }; - - udmabuf2 { - compatible = "ikwzm,u-dma-buf"; - device-name = "udmabuf-ddr-nc-wcb0"; - minor-number = <2>; - size = <0x0 0x8000000>; - memory-region = <&fabricbuf2>; - sync-mode = <3>; - }; - ddrc_cache_lo: memory@80000000 { device_type = "memory"; - reg = <0x0 0x80000000 0x0 0x2e000000>; - clocks = <&clkcfg CLK_DDRC>; + reg = <0x0 0x80000000 0x0 0x40000000>; status = "okay"; }; - ddrc_cache_hi: memory@1000000000 { + ddrc_cache_hi: memory@1040000000 { device_type = "memory"; - reg = <0x10 0x0 0x0 0x40000000>; - clocks = <&clkcfg CLK_DDRC>; + reg = <0x10 0x40000000 0x0 0x40000000>; status = "okay"; }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + hss_payload: region@BFC00000 { + reg = <0x0 0xBFC00000 0x0 0x400000>; + no-map; + }; + }; }; &uart1 { @@ -155,3 +115,18 @@ ti,fifo-depth = <0x1>; }; }; + +&qspi { + status = "okay"; + num-cs = <1>; + + flash0: flash@0 { + compatible = "spi-nand"; + reg = <0x0>; + spi-tx-bus-width = <4>; + spi-rx-bus-width = <4>; + spi-max-frequency = <20000000>; + spi-cpol; + spi-cpha; + }; +}; diff --git a/arch/riscv/include/asm/global_data.h b/arch/riscv/include/asm/global_data.h index 858594a1911..6fdc86dd8b1 100644 --- a/arch/riscv/include/asm/global_data.h +++ b/arch/riscv/include/asm/global_data.h @@ -21,8 +21,8 @@ struct arch_global_data { #if CONFIG_IS_ENABLED(SIFIVE_CLINT) void __iomem *clint; /* clint base address */ #endif -#ifdef CONFIG_ANDES_PLIC - void __iomem *plic; /* plic base address */ +#ifdef CONFIG_ANDES_PLICSW + void __iomem *plicsw; /* plic base address */ #endif #if CONFIG_IS_ENABLED(SMP) struct ipi_data ipi[CONFIG_NR_CPUS]; diff --git a/arch/riscv/include/asm/syscon.h b/arch/riscv/include/asm/syscon.h index c3629e4b53d..f2b37975f37 100644 --- a/arch/riscv/include/asm/syscon.h +++ b/arch/riscv/include/asm/syscon.h @@ -13,7 +13,7 @@ enum { RISCV_NONE, RISCV_SYSCON_CLINT, /* Core Local Interruptor (CLINT) */ - RISCV_SYSCON_PLIC, /* Platform Level Interrupt Controller (PLIC) */ + RISCV_SYSCON_PLICSW, /* Andes PLICSW */ }; #endif /* _ASM_SYSCON_H */ diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile index 06020fcc2ad..d6a8ae97284 100644 --- a/arch/riscv/lib/Makefile +++ b/arch/riscv/lib/Makefile @@ -13,7 +13,7 @@ obj-y += cache.o obj-$(CONFIG_SIFIVE_CACHE) += sifive_cache.o ifeq ($(CONFIG_$(SPL_)RISCV_MMODE),y) obj-$(CONFIG_$(SPL_)SIFIVE_CLINT) += sifive_clint.o -obj-$(CONFIG_ANDES_PLIC) += andes_plic.o +obj-$(CONFIG_ANDES_PLICSW) += andes_plicsw.o else obj-$(CONFIG_SBI) += sbi.o obj-$(CONFIG_SBI_IPI) += sbi_ipi.o diff --git a/arch/riscv/lib/andes_plic.c b/arch/riscv/lib/andes_plicsw.c index 1eabcacd09d..324eb445aaa 100644 --- a/arch/riscv/lib/andes_plic.c +++ b/arch/riscv/lib/andes_plicsw.c @@ -37,8 +37,8 @@ static int enable_ipi(int hart) unsigned int en; en = ENABLE_HART_IPI << hart; - writel(en, (void __iomem *)ENABLE_REG(gd->arch.plic, hart)); - writel(en, (void __iomem *)ENABLE_REG(gd->arch.plic + 0x4, hart)); + writel(en, (void __iomem *)ENABLE_REG(gd->arch.plicsw, hart)); + writel(en, (void __iomem *)ENABLE_REG(gd->arch.plicsw + 0x4, hart)); return 0; } @@ -46,14 +46,14 @@ static int enable_ipi(int hart) int riscv_init_ipi(void) { int ret; - long *base = syscon_get_first_range(RISCV_SYSCON_PLIC); + long *base = syscon_get_first_range(RISCV_SYSCON_PLICSW); ofnode node; struct udevice *dev; u32 reg; if (IS_ERR(base)) return PTR_ERR(base); - gd->arch.plic = base; + gd->arch.plicsw = base; ret = uclass_find_first_device(UCLASS_CPU, &dev); if (ret) @@ -88,7 +88,7 @@ int riscv_send_ipi(int hart) { unsigned int ipi = (SEND_IPI_TO_HART(hart) << (8 * gd->arch.boot_hart)); - writel(ipi, (void __iomem *)PENDING_REG(gd->arch.plic, + writel(ipi, (void __iomem *)PENDING_REG(gd->arch.plicsw, gd->arch.boot_hart)); return 0; @@ -98,8 +98,8 @@ int riscv_clear_ipi(int hart) { u32 source_id; - source_id = readl((void __iomem *)CLAIM_REG(gd->arch.plic, hart)); - writel(source_id, (void __iomem *)CLAIM_REG(gd->arch.plic, hart)); + source_id = readl((void __iomem *)CLAIM_REG(gd->arch.plicsw, hart)); + writel(source_id, (void __iomem *)CLAIM_REG(gd->arch.plicsw, hart)); return 0; } @@ -108,21 +108,21 @@ int riscv_get_ipi(int hart, int *pending) { unsigned int ipi = (SEND_IPI_TO_HART(hart) << (8 * gd->arch.boot_hart)); - *pending = readl((void __iomem *)PENDING_REG(gd->arch.plic, + *pending = readl((void __iomem *)PENDING_REG(gd->arch.plicsw, gd->arch.boot_hart)); *pending = !!(*pending & ipi); return 0; } -static const struct udevice_id andes_plic_ids[] = { - { .compatible = "riscv,plic1", .data = RISCV_SYSCON_PLIC }, +static const struct udevice_id andes_plicsw_ids[] = { + { .compatible = "andestech,plicsw", .data = RISCV_SYSCON_PLICSW }, { } }; -U_BOOT_DRIVER(andes_plic) = { - .name = "andes_plic", +U_BOOT_DRIVER(andes_plicsw) = { + .name = "andes_plicsw", .id = UCLASS_SYSCON, - .of_match = andes_plic_ids, + .of_match = andes_plicsw_ids, .flags = DM_FLAG_PRE_RELOC, }; diff --git a/board/microchip/mpfs_icicle/Kconfig b/board/microchip/mpfs_icicle/Kconfig index e37091373ff..7cd5a597bba 100644 --- a/board/microchip/mpfs_icicle/Kconfig +++ b/board/microchip/mpfs_icicle/Kconfig @@ -50,5 +50,12 @@ config BOARD_SPECIFIC_OPTIONS # dummy imply CMD_I2C imply DM_I2C imply SYS_I2C_MICROCHIP + imply SPI + imply DM_SPI + imply MICROCHIP_COREQSPI + imply MTD_SPI_NAND + imply CMD_MTD + imply MTD_PARTITIONS + imply CMD_MTDPARTS endif diff --git a/configs/microchip_mpfs_icicle_defconfig b/configs/microchip_mpfs_icicle_defconfig index 6113c5be809..c295b9bad3f 100644 --- a/configs/microchip_mpfs_icicle_defconfig +++ b/configs/microchip_mpfs_icicle_defconfig @@ -17,6 +17,7 @@ CONFIG_DISPLAY_BOARDINFO=y CONFIG_SYS_CBSIZE=256 CONFIG_SYS_PBSIZE=282 CONFIG_SYS_BOOTM_LEN=0x4000000 +CONFIG_SYS_MEM_TOP_HIDE=0x400000 CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_BOOTP_SEND_HOSTNAME=y CONFIG_DM_MTD=y diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index f9f5255bdca..c6900f449d5 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -236,6 +236,12 @@ config MESON_SPIFC This driver can be used to access the SPI NOR flash chips on Amlogic Meson SoCs. +config MICROCHIP_COREQSPI + bool "Microchip FPGA QSPI Controller driver" + help + Enable the QSPI driver for Microchip FPGA QSPI controllers. + This driver can be used on Polarfire SoC. + config MPC8XX_SPI bool "MPC8XX SPI Driver" depends on MPC8xx diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index bf1ffd20d5b..674d81caae3 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_ICH_SPI) += ich.o obj-$(CONFIG_IPROC_QSPI) += iproc_qspi.o obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o obj-$(CONFIG_MESON_SPIFC) += meson_spifc.o +obj-$(CONFIG_MICROCHIP_COREQSPI) += microchip_coreqspi.o obj-$(CONFIG_MPC8XX_SPI) += mpc8xx_spi.o obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o obj-$(CONFIG_MTK_SNFI_SPI) += mtk_snfi_spi.o diff --git a/drivers/spi/microchip_coreqspi.c b/drivers/spi/microchip_coreqspi.c new file mode 100644 index 00000000000..5fe0c8e1237 --- /dev/null +++ b/drivers/spi/microchip_coreqspi.c @@ -0,0 +1,505 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2022 Microchip Technology Inc. + * Padmarao Begari <padmarao.begari@microchip.com> + * Naga Sureshkumar Relli <nagasuresh.relli@microchip.com> + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <log.h> +#include <malloc.h> +#include <spi.h> +#include <spi-mem.h> +#include <asm/io.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/types.h> +#include <linux/sizes.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * QSPI Control register mask defines + */ +#define CONTROL_ENABLE BIT(0) +#define CONTROL_MASTER BIT(1) +#define CONTROL_XIP BIT(2) +#define CONTROL_XIPADDR BIT(3) +#define CONTROL_CLKIDLE BIT(10) +#define CONTROL_SAMPLE_MASK GENMASK(12, 11) +#define CONTROL_MODE0 BIT(13) +#define CONTROL_MODE12_MASK GENMASK(15, 14) +#define CONTROL_MODE12_EX_RO BIT(14) +#define CONTROL_MODE12_EX_RW BIT(15) +#define CONTROL_MODE12_FULL GENMASK(15, 14) +#define CONTROL_FLAGSX4 BIT(16) +#define CONTROL_CLKRATE_MASK GENMASK(27, 24) +#define CONTROL_CLKRATE_SHIFT 24 + +/* + * QSPI Frames register mask defines + */ +#define FRAMES_TOTALBYTES_MASK GENMASK(15, 0) +#define FRAMES_CMDBYTES_MASK GENMASK(24, 16) +#define FRAMES_CMDBYTES_SHIFT 16 +#define FRAMES_SHIFT 25 +#define FRAMES_IDLE_MASK GENMASK(29, 26) +#define FRAMES_IDLE_SHIFT 26 +#define FRAMES_FLAGBYTE BIT(30) +#define FRAMES_FLAGWORD BIT(31) + +/* + * QSPI Interrupt Enable register mask defines + */ +#define IEN_TXDONE BIT(0) +#define IEN_RXDONE BIT(1) +#define IEN_RXAVAILABLE BIT(2) +#define IEN_TXAVAILABLE BIT(3) +#define IEN_RXFIFOEMPTY BIT(4) +#define IEN_TXFIFOFULL BIT(5) + +/* + * QSPI Status register mask defines + */ +#define STATUS_TXDONE BIT(0) +#define STATUS_RXDONE BIT(1) +#define STATUS_RXAVAILABLE BIT(2) +#define STATUS_TXAVAILABLE BIT(3) +#define STATUS_RXFIFOEMPTY BIT(4) +#define STATUS_TXFIFOFULL BIT(5) +#define STATUS_READY BIT(7) +#define STATUS_FLAGSX4 BIT(8) +#define STATUS_MASK GENMASK(8, 0) + +#define BYTESUPPER_MASK GENMASK(31, 16) +#define BYTESLOWER_MASK GENMASK(15, 0) + +#define MAX_DIVIDER 16 +#define MIN_DIVIDER 0 +#define MAX_DATA_CMD_LEN 256 + +/* QSPI ready time out value */ +#define TIMEOUT_MS (1000 * 500) + +/* + * QSPI Register offsets. + */ +#define REG_CONTROL (0x00) +#define REG_FRAMES (0x04) +#define REG_IEN (0x0c) +#define REG_STATUS (0x10) +#define REG_DIRECT_ACCESS (0x14) +#define REG_UPPER_ACCESS (0x18) +#define REG_RX_DATA (0x40) +#define REG_TX_DATA (0x44) +#define REG_X4_RX_DATA (0x48) +#define REG_X4_TX_DATA (0x4c) +#define REG_FRAMESUP (0x50) + +/** + * struct mchp_coreqspi - Defines qspi driver instance + * @regs: Address of the QSPI controller registers + * @freq: QSPI Input frequency + * @txbuf: TX buffer + * @rxbuf: RX buffer + * @tx_len: Number of bytes left to transfer + * @rx_len: Number of bytes left to receive + */ +struct mchp_coreqspi { + void __iomem *regs; + u32 freq; + u8 *txbuf; + u8 *rxbuf; + int tx_len; + int rx_len; +}; + +static void mchp_coreqspi_init_hw(struct mchp_coreqspi *qspi) +{ + u32 control; + + control = CONTROL_CLKIDLE | CONTROL_ENABLE; + + writel(control, qspi->regs + REG_CONTROL); + writel(0, qspi->regs + REG_IEN); +} + +static inline void mchp_coreqspi_read_op(struct mchp_coreqspi *qspi) +{ + u32 control, data; + + if (!qspi->rx_len) + return; + + control = readl(qspi->regs + REG_CONTROL); + + /* + * Read 4-bytes from the SPI FIFO in single transaction and then read + * the reamaining data byte wise. + */ + control |= CONTROL_FLAGSX4; + writel(control, qspi->regs + REG_CONTROL); + + while (qspi->rx_len >= 4) { + while (readl(qspi->regs + REG_STATUS) & STATUS_RXFIFOEMPTY) + ; + data = readl(qspi->regs + REG_X4_RX_DATA); + *(u32 *)qspi->rxbuf = data; + qspi->rxbuf += 4; + qspi->rx_len -= 4; + } + + control &= ~CONTROL_FLAGSX4; + writel(control, qspi->regs + REG_CONTROL); + + while (qspi->rx_len--) { + while (readl(qspi->regs + REG_STATUS) & STATUS_RXFIFOEMPTY) + ; + data = readl(qspi->regs + REG_RX_DATA); + *qspi->rxbuf++ = (data & 0xFF); + } +} + +static inline void mchp_coreqspi_write_op(struct mchp_coreqspi *qspi, bool word) +{ + u32 control, data; + + control = readl(qspi->regs + REG_CONTROL); + control |= CONTROL_FLAGSX4; + writel(control, qspi->regs + REG_CONTROL); + + while (qspi->tx_len >= 4) { + while (readl(qspi->regs + REG_STATUS) & STATUS_TXFIFOFULL) + ; + data = *(u32 *)qspi->txbuf; + qspi->txbuf += 4; + qspi->tx_len -= 4; + writel(data, qspi->regs + REG_X4_TX_DATA); + } + + control &= ~CONTROL_FLAGSX4; + writel(control, qspi->regs + REG_CONTROL); + + while (qspi->tx_len--) { + while (readl(qspi->regs + REG_STATUS) & STATUS_TXFIFOFULL) + ; + data = *qspi->txbuf++; + writel(data, qspi->regs + REG_TX_DATA); + } +} + +static inline void mchp_coreqspi_config_op(struct mchp_coreqspi *qspi, + const struct spi_mem_op *op) +{ + u32 idle_cycles = 0; + int total_bytes, cmd_bytes, frames, ctrl; + + cmd_bytes = op->cmd.nbytes + op->addr.nbytes; + total_bytes = cmd_bytes + op->data.nbytes; + + /* + * As per the coreQSPI IP spec,the number of command and data bytes are + * controlled by the frames register for each SPI sequence. This supports + * the SPI flash memory read and writes sequences as below. so configure + * the cmd and total bytes accordingly. + * --------------------------------------------------------------------- + * TOTAL BYTES | CMD BYTES | What happens | + * ______________________________________________________________________ + * | | | + * 1 | 1 | The SPI core will transmit a single byte | + * | | and receive data is discarded | + * | | | + * 1 | 0 | The SPI core will transmit a single byte | + * | | and return a single byte | + * | | | + * 10 | 4 | The SPI core will transmit 4 command | + * | | bytes discarding the receive data and | + * | | transmits 6 dummy bytes returning the 6 | + * | | received bytes and return a single byte | + * | | | + * 10 | 10 | The SPI core will transmit 10 command | + * | | | + * 10 | 0 | The SPI core will transmit 10 command | + * | | bytes and returning 10 received bytes | + * ______________________________________________________________________ + */ + + if (!(op->data.dir == SPI_MEM_DATA_IN)) + cmd_bytes = total_bytes; + + frames = total_bytes & BYTESUPPER_MASK; + writel(frames, qspi->regs + REG_FRAMESUP); + frames = total_bytes & BYTESLOWER_MASK; + frames |= cmd_bytes << FRAMES_CMDBYTES_SHIFT; + + if (op->dummy.buswidth) + idle_cycles = op->dummy.nbytes * 8 / op->dummy.buswidth; + + frames |= idle_cycles << FRAMES_IDLE_SHIFT; + ctrl = readl(qspi->regs + REG_CONTROL); + + if (ctrl & CONTROL_MODE12_MASK) + frames |= (1 << FRAMES_SHIFT); + + frames |= FRAMES_FLAGWORD; + writel(frames, qspi->regs + REG_FRAMES); +} + +static int mchp_coreqspi_wait_for_ready(struct spi_slave *slave) +{ + struct mchp_coreqspi *qspi = dev_get_priv(slave->dev->parent); + unsigned long count = 0; + + while (1) { + if (readl(qspi->regs + REG_STATUS) & STATUS_READY) + return 0; + + udelay(1); + count += 1; + if (count == TIMEOUT_MS) + return -ETIMEDOUT; + } +} + +static int mchp_coreqspi_set_operate_mode(struct mchp_coreqspi *qspi, + const struct spi_mem_op *op) +{ + u32 control = readl(qspi->regs + REG_CONTROL); + + /* + * The operating mode can be configured based on the command that needs + * to be send. + * bits[15:14]: Sets whether multiple bit SPI operates in normal, + * extended or full modes. + * 00: Normal (single DQ0 TX and single DQ1 RX lines) + * 01: Extended RO (command and address bytes on DQ0 only) + * 10: Extended RW (command byte on DQ0 only) + * 11: Full. (command and address are on all DQ lines) + * bit[13]: Sets whether multiple bit SPI uses 2 or 4 bits of data + * 0: 2-bits (BSPI) + * 1: 4-bits (QSPI) + */ + if (op->data.buswidth == 4 || op->data.buswidth == 2) { + control &= ~CONTROL_MODE12_MASK; + if (op->cmd.buswidth == 1 && (op->addr.buswidth == 1 || + op->addr.buswidth == 0)) + control |= CONTROL_MODE12_EX_RO; + else if (op->cmd.buswidth == 1) + control |= CONTROL_MODE12_EX_RW; + else + control |= CONTROL_MODE12_FULL; + + control |= CONTROL_MODE0; + } else { + control &= ~(CONTROL_MODE12_MASK | CONTROL_MODE0); + } + + writel(control, qspi->regs + REG_CONTROL); + + return 0; +} + +static int mchp_coreqspi_exec_op(struct spi_slave *slave, + const struct spi_mem_op *op) +{ + struct mchp_coreqspi *qspi = dev_get_priv(slave->dev->parent); + + u32 address = op->addr.val; + u8 opcode = op->cmd.opcode; + u8 opaddr[5]; + int err = 0, i; + + err = mchp_coreqspi_wait_for_ready(slave); + if (err) + return err; + + err = mchp_coreqspi_set_operate_mode(qspi, op); + if (err) + return err; + + mchp_coreqspi_config_op(qspi, op); + if (op->cmd.opcode) { + qspi->txbuf = &opcode; + qspi->rxbuf = NULL; + qspi->tx_len = op->cmd.nbytes; + qspi->rx_len = 0; + mchp_coreqspi_write_op(qspi, false); + } + + qspi->txbuf = &opaddr[0]; + if (op->addr.nbytes) { + for (i = 0; i < op->addr.nbytes; i++) + qspi->txbuf[i] = address >> (8 * (op->addr.nbytes - i - 1)); + + qspi->rxbuf = NULL; + qspi->tx_len = op->addr.nbytes; + qspi->rx_len = 0; + mchp_coreqspi_write_op(qspi, false); + } + + if (op->data.nbytes) { + if (op->data.dir == SPI_MEM_DATA_OUT) { + qspi->txbuf = (u8 *)op->data.buf.out; + qspi->rxbuf = NULL; + qspi->rx_len = 0; + qspi->tx_len = op->data.nbytes; + mchp_coreqspi_write_op(qspi, true); + } else { + qspi->txbuf = NULL; + qspi->rxbuf = (u8 *)op->data.buf.in; + qspi->rx_len = op->data.nbytes; + qspi->tx_len = 0; + mchp_coreqspi_read_op(qspi); + } + } + + return 0; +} + +static bool mchp_coreqspi_supports_op(struct spi_slave *slave, + const struct spi_mem_op *op) +{ + if (!spi_mem_default_supports_op(slave, op)) + return false; + + if ((op->data.buswidth == 4 || op->data.buswidth == 2) && + (op->cmd.buswidth == 1 && (op->addr.buswidth == 1 || + op->addr.buswidth == 0))) { + /* + * If the command and address are on DQ0 only, then this + * controller doesn't support sending data on dual and + * quad lines. but it supports reading data on dual and + * quad lines with same configuration as command and + * address on DQ0. + * i.e. The control register[15:13] :EX_RO(read only) is + * meant only for the command and address are on DQ0 but + * not to write data, it is just to read. + * Ex: 0x34h is Quad Load Program Data which is not + * supported. Then the spi-mem layer will iterate over + * each command and it will chose the supported one. + */ + if (op->data.dir == SPI_MEM_DATA_OUT) + return false; + } + + return true; +} + +static int mchp_coreqspi_adjust_op_size(struct spi_slave *slave, + struct spi_mem_op *op) +{ + if (op->data.dir == SPI_MEM_DATA_OUT) { + if (op->data.nbytes > MAX_DATA_CMD_LEN) + op->data.nbytes = MAX_DATA_CMD_LEN; + } + + return 0; +} + +static int mchp_coreqspi_set_speed(struct udevice *dev, uint speed) +{ + struct mchp_coreqspi *qspi = dev_get_priv(dev); + u32 control, baud_rate_val = 0; + + if (speed > (qspi->freq / 2)) + speed = qspi->freq / 2; + + baud_rate_val = DIV_ROUND_UP(qspi->freq, 2 * speed); + if (baud_rate_val >= MAX_DIVIDER || baud_rate_val <= MIN_DIVIDER) + return -EINVAL; + + control = readl(qspi->regs + REG_CONTROL); + control &= ~CONTROL_CLKRATE_MASK; + control |= baud_rate_val << CONTROL_CLKRATE_SHIFT; + writel(control, qspi->regs + REG_CONTROL); + + return 0; +} + +static int mchp_coreqspi_set_mode(struct udevice *dev, uint mode) +{ + struct mchp_coreqspi *qspi = dev_get_priv(dev); + u32 control; + + control = readl(qspi->regs + REG_CONTROL); + + if ((mode & SPI_CPOL) && (mode & SPI_CPHA)) + control |= CONTROL_CLKIDLE; + else + control &= ~CONTROL_CLKIDLE; + + writel(control, qspi->regs + REG_CONTROL); + + return 0; +} + +static int mchp_coreqspi_claim_bus(struct udevice *dev) +{ + return 0; +} + +static int mchp_coreqspi_release_bus(struct udevice *dev) +{ + return 0; +} + +static int mchp_coreqspi_probe(struct udevice *dev) +{ + struct mchp_coreqspi *qspi = dev_get_priv(dev); + struct clk clk; + ulong clk_rate; + int ret; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return -EINVAL; + + ret = clk_enable(&clk); + if (ret) + return ret; + + clk_rate = clk_get_rate(&clk); + if (!clk_rate) + return -EINVAL; + qspi->freq = clk_rate; + + qspi->regs = dev_read_addr_ptr(dev); + if (!qspi->regs) + return -EINVAL; + + /* Init the mpfs qspi hw */ + mchp_coreqspi_init_hw(qspi); + + return 0; +} + +static const struct spi_controller_mem_ops mchp_coreqspi_mem_ops = { + .adjust_op_size = mchp_coreqspi_adjust_op_size, + .supports_op = mchp_coreqspi_supports_op, + .exec_op = mchp_coreqspi_exec_op, +}; + +static const struct dm_spi_ops mchp_coreqspi_ops = { + .claim_bus = mchp_coreqspi_claim_bus, + .release_bus = mchp_coreqspi_release_bus, + .set_speed = mchp_coreqspi_set_speed, + .set_mode = mchp_coreqspi_set_mode, + .mem_ops = &mchp_coreqspi_mem_ops, +}; + +static const struct udevice_id mchp_coreqspi_ids[] = { + { .compatible = "microchip,mpfs-coreqspi-rtl-v2" }, + { .compatible = "microchip,mpfs-qspi" }, + { } +}; + +U_BOOT_DRIVER(mchp_coreqspi) = { + .name = "mchp_coreqspi", + .id = UCLASS_SPI, + .of_match = mchp_coreqspi_ids, + .ops = &mchp_coreqspi_ops, + .priv_auto = sizeof(struct mchp_coreqspi), + .probe = mchp_coreqspi_probe, +}; diff --git a/drivers/timer/andes_plmt_timer.c b/drivers/timer/andes_plmt_timer.c index a3797b22c74..42dd4b62317 100644 --- a/drivers/timer/andes_plmt_timer.c +++ b/drivers/timer/andes_plmt_timer.c @@ -56,7 +56,7 @@ static int andes_plmt_probe(struct udevice *dev) } static const struct udevice_id andes_plmt_ids[] = { - { .compatible = "riscv,plmt0" }, + { .compatible = "andestech,plmt0" }, { } }; |