162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci/* 462306a36Sopenharmony_ci * NXP FlexSPI(FSPI) controller driver. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright 2019-2020 NXP 762306a36Sopenharmony_ci * Copyright 2020 Puresoftware Ltd. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * FlexSPI is a flexsible SPI host controller which supports two SPI 1062306a36Sopenharmony_ci * channels and up to 4 external devices. Each channel supports 1162306a36Sopenharmony_ci * Single/Dual/Quad/Octal mode data transfer (1/2/4/8 bidirectional 1262306a36Sopenharmony_ci * data lines). 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * FlexSPI controller is driven by the LUT(Look-up Table) registers 1562306a36Sopenharmony_ci * LUT registers are a look-up-table for sequences of instructions. 1662306a36Sopenharmony_ci * A valid sequence consists of four LUT registers. 1762306a36Sopenharmony_ci * Maximum 32 LUT sequences can be programmed simultaneously. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * LUTs are being created at run-time based on the commands passed 2062306a36Sopenharmony_ci * from the spi-mem framework, thus using single LUT index. 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * Software triggered Flash read/write access by IP Bus. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * Memory mapped read access by AHB Bus. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * Based on SPI MEM interface and spi-fsl-qspi.c driver. 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * Author: 2962306a36Sopenharmony_ci * Yogesh Narayan Gaur <yogeshnarayan.gaur@nxp.com> 3062306a36Sopenharmony_ci * Boris Brezillon <bbrezillon@kernel.org> 3162306a36Sopenharmony_ci * Frieder Schrempf <frieder.schrempf@kontron.de> 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include <linux/acpi.h> 3562306a36Sopenharmony_ci#include <linux/bitops.h> 3662306a36Sopenharmony_ci#include <linux/bitfield.h> 3762306a36Sopenharmony_ci#include <linux/clk.h> 3862306a36Sopenharmony_ci#include <linux/completion.h> 3962306a36Sopenharmony_ci#include <linux/delay.h> 4062306a36Sopenharmony_ci#include <linux/err.h> 4162306a36Sopenharmony_ci#include <linux/errno.h> 4262306a36Sopenharmony_ci#include <linux/interrupt.h> 4362306a36Sopenharmony_ci#include <linux/io.h> 4462306a36Sopenharmony_ci#include <linux/iopoll.h> 4562306a36Sopenharmony_ci#include <linux/jiffies.h> 4662306a36Sopenharmony_ci#include <linux/kernel.h> 4762306a36Sopenharmony_ci#include <linux/module.h> 4862306a36Sopenharmony_ci#include <linux/mutex.h> 4962306a36Sopenharmony_ci#include <linux/of.h> 5062306a36Sopenharmony_ci#include <linux/platform_device.h> 5162306a36Sopenharmony_ci#include <linux/pm_qos.h> 5262306a36Sopenharmony_ci#include <linux/regmap.h> 5362306a36Sopenharmony_ci#include <linux/sizes.h> 5462306a36Sopenharmony_ci#include <linux/sys_soc.h> 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 5762306a36Sopenharmony_ci#include <linux/spi/spi.h> 5862306a36Sopenharmony_ci#include <linux/spi/spi-mem.h> 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* 6162306a36Sopenharmony_ci * The driver only uses one single LUT entry, that is updated on 6262306a36Sopenharmony_ci * each call of exec_op(). Index 0 is preset at boot with a basic 6362306a36Sopenharmony_ci * read operation, so let's use the last entry (31). 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_ci#define SEQID_LUT 31 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* Registers used by the driver */ 6862306a36Sopenharmony_ci#define FSPI_MCR0 0x00 6962306a36Sopenharmony_ci#define FSPI_MCR0_AHB_TIMEOUT(x) ((x) << 24) 7062306a36Sopenharmony_ci#define FSPI_MCR0_IP_TIMEOUT(x) ((x) << 16) 7162306a36Sopenharmony_ci#define FSPI_MCR0_LEARN_EN BIT(15) 7262306a36Sopenharmony_ci#define FSPI_MCR0_SCRFRUN_EN BIT(14) 7362306a36Sopenharmony_ci#define FSPI_MCR0_OCTCOMB_EN BIT(13) 7462306a36Sopenharmony_ci#define FSPI_MCR0_DOZE_EN BIT(12) 7562306a36Sopenharmony_ci#define FSPI_MCR0_HSEN BIT(11) 7662306a36Sopenharmony_ci#define FSPI_MCR0_SERCLKDIV BIT(8) 7762306a36Sopenharmony_ci#define FSPI_MCR0_ATDF_EN BIT(7) 7862306a36Sopenharmony_ci#define FSPI_MCR0_ARDF_EN BIT(6) 7962306a36Sopenharmony_ci#define FSPI_MCR0_RXCLKSRC(x) ((x) << 4) 8062306a36Sopenharmony_ci#define FSPI_MCR0_END_CFG(x) ((x) << 2) 8162306a36Sopenharmony_ci#define FSPI_MCR0_MDIS BIT(1) 8262306a36Sopenharmony_ci#define FSPI_MCR0_SWRST BIT(0) 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci#define FSPI_MCR1 0x04 8562306a36Sopenharmony_ci#define FSPI_MCR1_SEQ_TIMEOUT(x) ((x) << 16) 8662306a36Sopenharmony_ci#define FSPI_MCR1_AHB_TIMEOUT(x) (x) 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#define FSPI_MCR2 0x08 8962306a36Sopenharmony_ci#define FSPI_MCR2_IDLE_WAIT(x) ((x) << 24) 9062306a36Sopenharmony_ci#define FSPI_MCR2_SAMEDEVICEEN BIT(15) 9162306a36Sopenharmony_ci#define FSPI_MCR2_CLRLRPHS BIT(14) 9262306a36Sopenharmony_ci#define FSPI_MCR2_ABRDATSZ BIT(8) 9362306a36Sopenharmony_ci#define FSPI_MCR2_ABRLEARN BIT(7) 9462306a36Sopenharmony_ci#define FSPI_MCR2_ABR_READ BIT(6) 9562306a36Sopenharmony_ci#define FSPI_MCR2_ABRWRITE BIT(5) 9662306a36Sopenharmony_ci#define FSPI_MCR2_ABRDUMMY BIT(4) 9762306a36Sopenharmony_ci#define FSPI_MCR2_ABR_MODE BIT(3) 9862306a36Sopenharmony_ci#define FSPI_MCR2_ABRCADDR BIT(2) 9962306a36Sopenharmony_ci#define FSPI_MCR2_ABRRADDR BIT(1) 10062306a36Sopenharmony_ci#define FSPI_MCR2_ABR_CMD BIT(0) 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci#define FSPI_AHBCR 0x0c 10362306a36Sopenharmony_ci#define FSPI_AHBCR_RDADDROPT BIT(6) 10462306a36Sopenharmony_ci#define FSPI_AHBCR_PREF_EN BIT(5) 10562306a36Sopenharmony_ci#define FSPI_AHBCR_BUFF_EN BIT(4) 10662306a36Sopenharmony_ci#define FSPI_AHBCR_CACH_EN BIT(3) 10762306a36Sopenharmony_ci#define FSPI_AHBCR_CLRTXBUF BIT(2) 10862306a36Sopenharmony_ci#define FSPI_AHBCR_CLRRXBUF BIT(1) 10962306a36Sopenharmony_ci#define FSPI_AHBCR_PAR_EN BIT(0) 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#define FSPI_INTEN 0x10 11262306a36Sopenharmony_ci#define FSPI_INTEN_SCLKSBWR BIT(9) 11362306a36Sopenharmony_ci#define FSPI_INTEN_SCLKSBRD BIT(8) 11462306a36Sopenharmony_ci#define FSPI_INTEN_DATALRNFL BIT(7) 11562306a36Sopenharmony_ci#define FSPI_INTEN_IPTXWE BIT(6) 11662306a36Sopenharmony_ci#define FSPI_INTEN_IPRXWA BIT(5) 11762306a36Sopenharmony_ci#define FSPI_INTEN_AHBCMDERR BIT(4) 11862306a36Sopenharmony_ci#define FSPI_INTEN_IPCMDERR BIT(3) 11962306a36Sopenharmony_ci#define FSPI_INTEN_AHBCMDGE BIT(2) 12062306a36Sopenharmony_ci#define FSPI_INTEN_IPCMDGE BIT(1) 12162306a36Sopenharmony_ci#define FSPI_INTEN_IPCMDDONE BIT(0) 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci#define FSPI_INTR 0x14 12462306a36Sopenharmony_ci#define FSPI_INTR_SCLKSBWR BIT(9) 12562306a36Sopenharmony_ci#define FSPI_INTR_SCLKSBRD BIT(8) 12662306a36Sopenharmony_ci#define FSPI_INTR_DATALRNFL BIT(7) 12762306a36Sopenharmony_ci#define FSPI_INTR_IPTXWE BIT(6) 12862306a36Sopenharmony_ci#define FSPI_INTR_IPRXWA BIT(5) 12962306a36Sopenharmony_ci#define FSPI_INTR_AHBCMDERR BIT(4) 13062306a36Sopenharmony_ci#define FSPI_INTR_IPCMDERR BIT(3) 13162306a36Sopenharmony_ci#define FSPI_INTR_AHBCMDGE BIT(2) 13262306a36Sopenharmony_ci#define FSPI_INTR_IPCMDGE BIT(1) 13362306a36Sopenharmony_ci#define FSPI_INTR_IPCMDDONE BIT(0) 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci#define FSPI_LUTKEY 0x18 13662306a36Sopenharmony_ci#define FSPI_LUTKEY_VALUE 0x5AF05AF0 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci#define FSPI_LCKCR 0x1C 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci#define FSPI_LCKER_LOCK 0x1 14162306a36Sopenharmony_ci#define FSPI_LCKER_UNLOCK 0x2 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci#define FSPI_BUFXCR_INVALID_MSTRID 0xE 14462306a36Sopenharmony_ci#define FSPI_AHBRX_BUF0CR0 0x20 14562306a36Sopenharmony_ci#define FSPI_AHBRX_BUF1CR0 0x24 14662306a36Sopenharmony_ci#define FSPI_AHBRX_BUF2CR0 0x28 14762306a36Sopenharmony_ci#define FSPI_AHBRX_BUF3CR0 0x2C 14862306a36Sopenharmony_ci#define FSPI_AHBRX_BUF4CR0 0x30 14962306a36Sopenharmony_ci#define FSPI_AHBRX_BUF5CR0 0x34 15062306a36Sopenharmony_ci#define FSPI_AHBRX_BUF6CR0 0x38 15162306a36Sopenharmony_ci#define FSPI_AHBRX_BUF7CR0 0x3C 15262306a36Sopenharmony_ci#define FSPI_AHBRXBUF0CR7_PREF BIT(31) 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci#define FSPI_AHBRX_BUF0CR1 0x40 15562306a36Sopenharmony_ci#define FSPI_AHBRX_BUF1CR1 0x44 15662306a36Sopenharmony_ci#define FSPI_AHBRX_BUF2CR1 0x48 15762306a36Sopenharmony_ci#define FSPI_AHBRX_BUF3CR1 0x4C 15862306a36Sopenharmony_ci#define FSPI_AHBRX_BUF4CR1 0x50 15962306a36Sopenharmony_ci#define FSPI_AHBRX_BUF5CR1 0x54 16062306a36Sopenharmony_ci#define FSPI_AHBRX_BUF6CR1 0x58 16162306a36Sopenharmony_ci#define FSPI_AHBRX_BUF7CR1 0x5C 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci#define FSPI_FLSHA1CR0 0x60 16462306a36Sopenharmony_ci#define FSPI_FLSHA2CR0 0x64 16562306a36Sopenharmony_ci#define FSPI_FLSHB1CR0 0x68 16662306a36Sopenharmony_ci#define FSPI_FLSHB2CR0 0x6C 16762306a36Sopenharmony_ci#define FSPI_FLSHXCR0_SZ_KB 10 16862306a36Sopenharmony_ci#define FSPI_FLSHXCR0_SZ(x) ((x) >> FSPI_FLSHXCR0_SZ_KB) 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci#define FSPI_FLSHA1CR1 0x70 17162306a36Sopenharmony_ci#define FSPI_FLSHA2CR1 0x74 17262306a36Sopenharmony_ci#define FSPI_FLSHB1CR1 0x78 17362306a36Sopenharmony_ci#define FSPI_FLSHB2CR1 0x7C 17462306a36Sopenharmony_ci#define FSPI_FLSHXCR1_CSINTR(x) ((x) << 16) 17562306a36Sopenharmony_ci#define FSPI_FLSHXCR1_CAS(x) ((x) << 11) 17662306a36Sopenharmony_ci#define FSPI_FLSHXCR1_WA BIT(10) 17762306a36Sopenharmony_ci#define FSPI_FLSHXCR1_TCSH(x) ((x) << 5) 17862306a36Sopenharmony_ci#define FSPI_FLSHXCR1_TCSS(x) (x) 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci#define FSPI_FLSHA1CR2 0x80 18162306a36Sopenharmony_ci#define FSPI_FLSHA2CR2 0x84 18262306a36Sopenharmony_ci#define FSPI_FLSHB1CR2 0x88 18362306a36Sopenharmony_ci#define FSPI_FLSHB2CR2 0x8C 18462306a36Sopenharmony_ci#define FSPI_FLSHXCR2_CLRINSP BIT(24) 18562306a36Sopenharmony_ci#define FSPI_FLSHXCR2_AWRWAIT BIT(16) 18662306a36Sopenharmony_ci#define FSPI_FLSHXCR2_AWRSEQN_SHIFT 13 18762306a36Sopenharmony_ci#define FSPI_FLSHXCR2_AWRSEQI_SHIFT 8 18862306a36Sopenharmony_ci#define FSPI_FLSHXCR2_ARDSEQN_SHIFT 5 18962306a36Sopenharmony_ci#define FSPI_FLSHXCR2_ARDSEQI_SHIFT 0 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci#define FSPI_IPCR0 0xA0 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci#define FSPI_IPCR1 0xA4 19462306a36Sopenharmony_ci#define FSPI_IPCR1_IPAREN BIT(31) 19562306a36Sopenharmony_ci#define FSPI_IPCR1_SEQNUM_SHIFT 24 19662306a36Sopenharmony_ci#define FSPI_IPCR1_SEQID_SHIFT 16 19762306a36Sopenharmony_ci#define FSPI_IPCR1_IDATSZ(x) (x) 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci#define FSPI_IPCMD 0xB0 20062306a36Sopenharmony_ci#define FSPI_IPCMD_TRG BIT(0) 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci#define FSPI_DLPR 0xB4 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci#define FSPI_IPRXFCR 0xB8 20562306a36Sopenharmony_ci#define FSPI_IPRXFCR_CLR BIT(0) 20662306a36Sopenharmony_ci#define FSPI_IPRXFCR_DMA_EN BIT(1) 20762306a36Sopenharmony_ci#define FSPI_IPRXFCR_WMRK(x) ((x) << 2) 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci#define FSPI_IPTXFCR 0xBC 21062306a36Sopenharmony_ci#define FSPI_IPTXFCR_CLR BIT(0) 21162306a36Sopenharmony_ci#define FSPI_IPTXFCR_DMA_EN BIT(1) 21262306a36Sopenharmony_ci#define FSPI_IPTXFCR_WMRK(x) ((x) << 2) 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci#define FSPI_DLLACR 0xC0 21562306a36Sopenharmony_ci#define FSPI_DLLACR_OVRDEN BIT(8) 21662306a36Sopenharmony_ci#define FSPI_DLLACR_SLVDLY(x) ((x) << 3) 21762306a36Sopenharmony_ci#define FSPI_DLLACR_DLLRESET BIT(1) 21862306a36Sopenharmony_ci#define FSPI_DLLACR_DLLEN BIT(0) 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci#define FSPI_DLLBCR 0xC4 22162306a36Sopenharmony_ci#define FSPI_DLLBCR_OVRDEN BIT(8) 22262306a36Sopenharmony_ci#define FSPI_DLLBCR_SLVDLY(x) ((x) << 3) 22362306a36Sopenharmony_ci#define FSPI_DLLBCR_DLLRESET BIT(1) 22462306a36Sopenharmony_ci#define FSPI_DLLBCR_DLLEN BIT(0) 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci#define FSPI_STS0 0xE0 22762306a36Sopenharmony_ci#define FSPI_STS0_DLPHB(x) ((x) << 8) 22862306a36Sopenharmony_ci#define FSPI_STS0_DLPHA(x) ((x) << 4) 22962306a36Sopenharmony_ci#define FSPI_STS0_CMD_SRC(x) ((x) << 2) 23062306a36Sopenharmony_ci#define FSPI_STS0_ARB_IDLE BIT(1) 23162306a36Sopenharmony_ci#define FSPI_STS0_SEQ_IDLE BIT(0) 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci#define FSPI_STS1 0xE4 23462306a36Sopenharmony_ci#define FSPI_STS1_IP_ERRCD(x) ((x) << 24) 23562306a36Sopenharmony_ci#define FSPI_STS1_IP_ERRID(x) ((x) << 16) 23662306a36Sopenharmony_ci#define FSPI_STS1_AHB_ERRCD(x) ((x) << 8) 23762306a36Sopenharmony_ci#define FSPI_STS1_AHB_ERRID(x) (x) 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci#define FSPI_STS2 0xE8 24062306a36Sopenharmony_ci#define FSPI_STS2_BREFLOCK BIT(17) 24162306a36Sopenharmony_ci#define FSPI_STS2_BSLVLOCK BIT(16) 24262306a36Sopenharmony_ci#define FSPI_STS2_AREFLOCK BIT(1) 24362306a36Sopenharmony_ci#define FSPI_STS2_ASLVLOCK BIT(0) 24462306a36Sopenharmony_ci#define FSPI_STS2_AB_LOCK (FSPI_STS2_BREFLOCK | \ 24562306a36Sopenharmony_ci FSPI_STS2_BSLVLOCK | \ 24662306a36Sopenharmony_ci FSPI_STS2_AREFLOCK | \ 24762306a36Sopenharmony_ci FSPI_STS2_ASLVLOCK) 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci#define FSPI_AHBSPNST 0xEC 25062306a36Sopenharmony_ci#define FSPI_AHBSPNST_DATLFT(x) ((x) << 16) 25162306a36Sopenharmony_ci#define FSPI_AHBSPNST_BUFID(x) ((x) << 1) 25262306a36Sopenharmony_ci#define FSPI_AHBSPNST_ACTIVE BIT(0) 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci#define FSPI_IPRXFSTS 0xF0 25562306a36Sopenharmony_ci#define FSPI_IPRXFSTS_RDCNTR(x) ((x) << 16) 25662306a36Sopenharmony_ci#define FSPI_IPRXFSTS_FILL(x) (x) 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci#define FSPI_IPTXFSTS 0xF4 25962306a36Sopenharmony_ci#define FSPI_IPTXFSTS_WRCNTR(x) ((x) << 16) 26062306a36Sopenharmony_ci#define FSPI_IPTXFSTS_FILL(x) (x) 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci#define FSPI_RFDR 0x100 26362306a36Sopenharmony_ci#define FSPI_TFDR 0x180 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci#define FSPI_LUT_BASE 0x200 26662306a36Sopenharmony_ci#define FSPI_LUT_OFFSET (SEQID_LUT * 4 * 4) 26762306a36Sopenharmony_ci#define FSPI_LUT_REG(idx) \ 26862306a36Sopenharmony_ci (FSPI_LUT_BASE + FSPI_LUT_OFFSET + (idx) * 4) 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci/* register map end */ 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/* Instruction set for the LUT register. */ 27362306a36Sopenharmony_ci#define LUT_STOP 0x00 27462306a36Sopenharmony_ci#define LUT_CMD 0x01 27562306a36Sopenharmony_ci#define LUT_ADDR 0x02 27662306a36Sopenharmony_ci#define LUT_CADDR_SDR 0x03 27762306a36Sopenharmony_ci#define LUT_MODE 0x04 27862306a36Sopenharmony_ci#define LUT_MODE2 0x05 27962306a36Sopenharmony_ci#define LUT_MODE4 0x06 28062306a36Sopenharmony_ci#define LUT_MODE8 0x07 28162306a36Sopenharmony_ci#define LUT_NXP_WRITE 0x08 28262306a36Sopenharmony_ci#define LUT_NXP_READ 0x09 28362306a36Sopenharmony_ci#define LUT_LEARN_SDR 0x0A 28462306a36Sopenharmony_ci#define LUT_DATSZ_SDR 0x0B 28562306a36Sopenharmony_ci#define LUT_DUMMY 0x0C 28662306a36Sopenharmony_ci#define LUT_DUMMY_RWDS_SDR 0x0D 28762306a36Sopenharmony_ci#define LUT_JMP_ON_CS 0x1F 28862306a36Sopenharmony_ci#define LUT_CMD_DDR 0x21 28962306a36Sopenharmony_ci#define LUT_ADDR_DDR 0x22 29062306a36Sopenharmony_ci#define LUT_CADDR_DDR 0x23 29162306a36Sopenharmony_ci#define LUT_MODE_DDR 0x24 29262306a36Sopenharmony_ci#define LUT_MODE2_DDR 0x25 29362306a36Sopenharmony_ci#define LUT_MODE4_DDR 0x26 29462306a36Sopenharmony_ci#define LUT_MODE8_DDR 0x27 29562306a36Sopenharmony_ci#define LUT_WRITE_DDR 0x28 29662306a36Sopenharmony_ci#define LUT_READ_DDR 0x29 29762306a36Sopenharmony_ci#define LUT_LEARN_DDR 0x2A 29862306a36Sopenharmony_ci#define LUT_DATSZ_DDR 0x2B 29962306a36Sopenharmony_ci#define LUT_DUMMY_DDR 0x2C 30062306a36Sopenharmony_ci#define LUT_DUMMY_RWDS_DDR 0x2D 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci/* 30362306a36Sopenharmony_ci * Calculate number of required PAD bits for LUT register. 30462306a36Sopenharmony_ci * 30562306a36Sopenharmony_ci * The pad stands for the number of IO lines [0:7]. 30662306a36Sopenharmony_ci * For example, the octal read needs eight IO lines, 30762306a36Sopenharmony_ci * so you should use LUT_PAD(8). This macro 30862306a36Sopenharmony_ci * returns 3 i.e. use eight (2^3) IP lines for read. 30962306a36Sopenharmony_ci */ 31062306a36Sopenharmony_ci#define LUT_PAD(x) (fls(x) - 1) 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci/* 31362306a36Sopenharmony_ci * Macro for constructing the LUT entries with the following 31462306a36Sopenharmony_ci * register layout: 31562306a36Sopenharmony_ci * 31662306a36Sopenharmony_ci * --------------------------------------------------- 31762306a36Sopenharmony_ci * | INSTR1 | PAD1 | OPRND1 | INSTR0 | PAD0 | OPRND0 | 31862306a36Sopenharmony_ci * --------------------------------------------------- 31962306a36Sopenharmony_ci */ 32062306a36Sopenharmony_ci#define PAD_SHIFT 8 32162306a36Sopenharmony_ci#define INSTR_SHIFT 10 32262306a36Sopenharmony_ci#define OPRND_SHIFT 16 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci/* Macros for constructing the LUT register. */ 32562306a36Sopenharmony_ci#define LUT_DEF(idx, ins, pad, opr) \ 32662306a36Sopenharmony_ci ((((ins) << INSTR_SHIFT) | ((pad) << PAD_SHIFT) | \ 32762306a36Sopenharmony_ci (opr)) << (((idx) % 2) * OPRND_SHIFT)) 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci#define POLL_TOUT 5000 33062306a36Sopenharmony_ci#define NXP_FSPI_MAX_CHIPSELECT 4 33162306a36Sopenharmony_ci#define NXP_FSPI_MIN_IOMAP SZ_4M 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci#define DCFG_RCWSR1 0x100 33462306a36Sopenharmony_ci#define SYS_PLL_RAT GENMASK(6, 2) 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci/* Access flash memory using IP bus only */ 33762306a36Sopenharmony_ci#define FSPI_QUIRK_USE_IP_ONLY BIT(0) 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistruct nxp_fspi_devtype_data { 34062306a36Sopenharmony_ci unsigned int rxfifo; 34162306a36Sopenharmony_ci unsigned int txfifo; 34262306a36Sopenharmony_ci unsigned int ahb_buf_size; 34362306a36Sopenharmony_ci unsigned int quirks; 34462306a36Sopenharmony_ci bool little_endian; 34562306a36Sopenharmony_ci}; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic struct nxp_fspi_devtype_data lx2160a_data = { 34862306a36Sopenharmony_ci .rxfifo = SZ_512, /* (64 * 64 bits) */ 34962306a36Sopenharmony_ci .txfifo = SZ_1K, /* (128 * 64 bits) */ 35062306a36Sopenharmony_ci .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ 35162306a36Sopenharmony_ci .quirks = 0, 35262306a36Sopenharmony_ci .little_endian = true, /* little-endian */ 35362306a36Sopenharmony_ci}; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic struct nxp_fspi_devtype_data imx8mm_data = { 35662306a36Sopenharmony_ci .rxfifo = SZ_512, /* (64 * 64 bits) */ 35762306a36Sopenharmony_ci .txfifo = SZ_1K, /* (128 * 64 bits) */ 35862306a36Sopenharmony_ci .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ 35962306a36Sopenharmony_ci .quirks = 0, 36062306a36Sopenharmony_ci .little_endian = true, /* little-endian */ 36162306a36Sopenharmony_ci}; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic struct nxp_fspi_devtype_data imx8qxp_data = { 36462306a36Sopenharmony_ci .rxfifo = SZ_512, /* (64 * 64 bits) */ 36562306a36Sopenharmony_ci .txfifo = SZ_1K, /* (128 * 64 bits) */ 36662306a36Sopenharmony_ci .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ 36762306a36Sopenharmony_ci .quirks = 0, 36862306a36Sopenharmony_ci .little_endian = true, /* little-endian */ 36962306a36Sopenharmony_ci}; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic struct nxp_fspi_devtype_data imx8dxl_data = { 37262306a36Sopenharmony_ci .rxfifo = SZ_512, /* (64 * 64 bits) */ 37362306a36Sopenharmony_ci .txfifo = SZ_1K, /* (128 * 64 bits) */ 37462306a36Sopenharmony_ci .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ 37562306a36Sopenharmony_ci .quirks = FSPI_QUIRK_USE_IP_ONLY, 37662306a36Sopenharmony_ci .little_endian = true, /* little-endian */ 37762306a36Sopenharmony_ci}; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistruct nxp_fspi { 38062306a36Sopenharmony_ci void __iomem *iobase; 38162306a36Sopenharmony_ci void __iomem *ahb_addr; 38262306a36Sopenharmony_ci u32 memmap_phy; 38362306a36Sopenharmony_ci u32 memmap_phy_size; 38462306a36Sopenharmony_ci u32 memmap_start; 38562306a36Sopenharmony_ci u32 memmap_len; 38662306a36Sopenharmony_ci struct clk *clk, *clk_en; 38762306a36Sopenharmony_ci struct device *dev; 38862306a36Sopenharmony_ci struct completion c; 38962306a36Sopenharmony_ci struct nxp_fspi_devtype_data *devtype_data; 39062306a36Sopenharmony_ci struct mutex lock; 39162306a36Sopenharmony_ci struct pm_qos_request pm_qos_req; 39262306a36Sopenharmony_ci int selected; 39362306a36Sopenharmony_ci}; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic inline int needs_ip_only(struct nxp_fspi *f) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci return f->devtype_data->quirks & FSPI_QUIRK_USE_IP_ONLY; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci/* 40162306a36Sopenharmony_ci * R/W functions for big- or little-endian registers: 40262306a36Sopenharmony_ci * The FSPI controller's endianness is independent of 40362306a36Sopenharmony_ci * the CPU core's endianness. So far, although the CPU 40462306a36Sopenharmony_ci * core is little-endian the FSPI controller can use 40562306a36Sopenharmony_ci * big-endian or little-endian. 40662306a36Sopenharmony_ci */ 40762306a36Sopenharmony_cistatic void fspi_writel(struct nxp_fspi *f, u32 val, void __iomem *addr) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci if (f->devtype_data->little_endian) 41062306a36Sopenharmony_ci iowrite32(val, addr); 41162306a36Sopenharmony_ci else 41262306a36Sopenharmony_ci iowrite32be(val, addr); 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic u32 fspi_readl(struct nxp_fspi *f, void __iomem *addr) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci if (f->devtype_data->little_endian) 41862306a36Sopenharmony_ci return ioread32(addr); 41962306a36Sopenharmony_ci else 42062306a36Sopenharmony_ci return ioread32be(addr); 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic irqreturn_t nxp_fspi_irq_handler(int irq, void *dev_id) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci struct nxp_fspi *f = dev_id; 42662306a36Sopenharmony_ci u32 reg; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci /* clear interrupt */ 42962306a36Sopenharmony_ci reg = fspi_readl(f, f->iobase + FSPI_INTR); 43062306a36Sopenharmony_ci fspi_writel(f, FSPI_INTR_IPCMDDONE, f->iobase + FSPI_INTR); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci if (reg & FSPI_INTR_IPCMDDONE) 43362306a36Sopenharmony_ci complete(&f->c); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci return IRQ_HANDLED; 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic int nxp_fspi_check_buswidth(struct nxp_fspi *f, u8 width) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci switch (width) { 44162306a36Sopenharmony_ci case 1: 44262306a36Sopenharmony_ci case 2: 44362306a36Sopenharmony_ci case 4: 44462306a36Sopenharmony_ci case 8: 44562306a36Sopenharmony_ci return 0; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci return -ENOTSUPP; 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic bool nxp_fspi_supports_op(struct spi_mem *mem, 45262306a36Sopenharmony_ci const struct spi_mem_op *op) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci struct nxp_fspi *f = spi_controller_get_devdata(mem->spi->master); 45562306a36Sopenharmony_ci int ret; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci ret = nxp_fspi_check_buswidth(f, op->cmd.buswidth); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (op->addr.nbytes) 46062306a36Sopenharmony_ci ret |= nxp_fspi_check_buswidth(f, op->addr.buswidth); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if (op->dummy.nbytes) 46362306a36Sopenharmony_ci ret |= nxp_fspi_check_buswidth(f, op->dummy.buswidth); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci if (op->data.nbytes) 46662306a36Sopenharmony_ci ret |= nxp_fspi_check_buswidth(f, op->data.buswidth); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci if (ret) 46962306a36Sopenharmony_ci return false; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci /* 47262306a36Sopenharmony_ci * The number of address bytes should be equal to or less than 4 bytes. 47362306a36Sopenharmony_ci */ 47462306a36Sopenharmony_ci if (op->addr.nbytes > 4) 47562306a36Sopenharmony_ci return false; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci /* 47862306a36Sopenharmony_ci * If requested address value is greater than controller assigned 47962306a36Sopenharmony_ci * memory mapped space, return error as it didn't fit in the range 48062306a36Sopenharmony_ci * of assigned address space. 48162306a36Sopenharmony_ci */ 48262306a36Sopenharmony_ci if (op->addr.val >= f->memmap_phy_size) 48362306a36Sopenharmony_ci return false; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci /* Max 64 dummy clock cycles supported */ 48662306a36Sopenharmony_ci if (op->dummy.buswidth && 48762306a36Sopenharmony_ci (op->dummy.nbytes * 8 / op->dummy.buswidth > 64)) 48862306a36Sopenharmony_ci return false; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* Max data length, check controller limits and alignment */ 49162306a36Sopenharmony_ci if (op->data.dir == SPI_MEM_DATA_IN && 49262306a36Sopenharmony_ci (op->data.nbytes > f->devtype_data->ahb_buf_size || 49362306a36Sopenharmony_ci (op->data.nbytes > f->devtype_data->rxfifo - 4 && 49462306a36Sopenharmony_ci !IS_ALIGNED(op->data.nbytes, 8)))) 49562306a36Sopenharmony_ci return false; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (op->data.dir == SPI_MEM_DATA_OUT && 49862306a36Sopenharmony_ci op->data.nbytes > f->devtype_data->txfifo) 49962306a36Sopenharmony_ci return false; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci return spi_mem_default_supports_op(mem, op); 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci/* Instead of busy looping invoke readl_poll_timeout functionality. */ 50562306a36Sopenharmony_cistatic int fspi_readl_poll_tout(struct nxp_fspi *f, void __iomem *base, 50662306a36Sopenharmony_ci u32 mask, u32 delay_us, 50762306a36Sopenharmony_ci u32 timeout_us, bool c) 50862306a36Sopenharmony_ci{ 50962306a36Sopenharmony_ci u32 reg; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (!f->devtype_data->little_endian) 51262306a36Sopenharmony_ci mask = (u32)cpu_to_be32(mask); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci if (c) 51562306a36Sopenharmony_ci return readl_poll_timeout(base, reg, (reg & mask), 51662306a36Sopenharmony_ci delay_us, timeout_us); 51762306a36Sopenharmony_ci else 51862306a36Sopenharmony_ci return readl_poll_timeout(base, reg, !(reg & mask), 51962306a36Sopenharmony_ci delay_us, timeout_us); 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci/* 52362306a36Sopenharmony_ci * If the slave device content being changed by Write/Erase, need to 52462306a36Sopenharmony_ci * invalidate the AHB buffer. This can be achieved by doing the reset 52562306a36Sopenharmony_ci * of controller after setting MCR0[SWRESET] bit. 52662306a36Sopenharmony_ci */ 52762306a36Sopenharmony_cistatic inline void nxp_fspi_invalid(struct nxp_fspi *f) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci u32 reg; 53062306a36Sopenharmony_ci int ret; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci reg = fspi_readl(f, f->iobase + FSPI_MCR0); 53362306a36Sopenharmony_ci fspi_writel(f, reg | FSPI_MCR0_SWRST, f->iobase + FSPI_MCR0); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci /* w1c register, wait unit clear */ 53662306a36Sopenharmony_ci ret = fspi_readl_poll_tout(f, f->iobase + FSPI_MCR0, 53762306a36Sopenharmony_ci FSPI_MCR0_SWRST, 0, POLL_TOUT, false); 53862306a36Sopenharmony_ci WARN_ON(ret); 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic void nxp_fspi_prepare_lut(struct nxp_fspi *f, 54262306a36Sopenharmony_ci const struct spi_mem_op *op) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci void __iomem *base = f->iobase; 54562306a36Sopenharmony_ci u32 lutval[4] = {}; 54662306a36Sopenharmony_ci int lutidx = 1, i; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci /* cmd */ 54962306a36Sopenharmony_ci lutval[0] |= LUT_DEF(0, LUT_CMD, LUT_PAD(op->cmd.buswidth), 55062306a36Sopenharmony_ci op->cmd.opcode); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci /* addr bytes */ 55362306a36Sopenharmony_ci if (op->addr.nbytes) { 55462306a36Sopenharmony_ci lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_ADDR, 55562306a36Sopenharmony_ci LUT_PAD(op->addr.buswidth), 55662306a36Sopenharmony_ci op->addr.nbytes * 8); 55762306a36Sopenharmony_ci lutidx++; 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci /* dummy bytes, if needed */ 56162306a36Sopenharmony_ci if (op->dummy.nbytes) { 56262306a36Sopenharmony_ci lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_DUMMY, 56362306a36Sopenharmony_ci /* 56462306a36Sopenharmony_ci * Due to FlexSPI controller limitation number of PAD for dummy 56562306a36Sopenharmony_ci * buswidth needs to be programmed as equal to data buswidth. 56662306a36Sopenharmony_ci */ 56762306a36Sopenharmony_ci LUT_PAD(op->data.buswidth), 56862306a36Sopenharmony_ci op->dummy.nbytes * 8 / 56962306a36Sopenharmony_ci op->dummy.buswidth); 57062306a36Sopenharmony_ci lutidx++; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci /* read/write data bytes */ 57462306a36Sopenharmony_ci if (op->data.nbytes) { 57562306a36Sopenharmony_ci lutval[lutidx / 2] |= LUT_DEF(lutidx, 57662306a36Sopenharmony_ci op->data.dir == SPI_MEM_DATA_IN ? 57762306a36Sopenharmony_ci LUT_NXP_READ : LUT_NXP_WRITE, 57862306a36Sopenharmony_ci LUT_PAD(op->data.buswidth), 57962306a36Sopenharmony_ci 0); 58062306a36Sopenharmony_ci lutidx++; 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci /* stop condition. */ 58462306a36Sopenharmony_ci lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_STOP, 0, 0); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci /* unlock LUT */ 58762306a36Sopenharmony_ci fspi_writel(f, FSPI_LUTKEY_VALUE, f->iobase + FSPI_LUTKEY); 58862306a36Sopenharmony_ci fspi_writel(f, FSPI_LCKER_UNLOCK, f->iobase + FSPI_LCKCR); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci /* fill LUT */ 59162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(lutval); i++) 59262306a36Sopenharmony_ci fspi_writel(f, lutval[i], base + FSPI_LUT_REG(i)); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci dev_dbg(f->dev, "CMD[%x] lutval[0:%x \t 1:%x \t 2:%x \t 3:%x], size: 0x%08x\n", 59562306a36Sopenharmony_ci op->cmd.opcode, lutval[0], lutval[1], lutval[2], lutval[3], op->data.nbytes); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci /* lock LUT */ 59862306a36Sopenharmony_ci fspi_writel(f, FSPI_LUTKEY_VALUE, f->iobase + FSPI_LUTKEY); 59962306a36Sopenharmony_ci fspi_writel(f, FSPI_LCKER_LOCK, f->iobase + FSPI_LCKCR); 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistatic int nxp_fspi_clk_prep_enable(struct nxp_fspi *f) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci int ret; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci if (is_acpi_node(dev_fwnode(f->dev))) 60762306a36Sopenharmony_ci return 0; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci ret = clk_prepare_enable(f->clk_en); 61062306a36Sopenharmony_ci if (ret) 61162306a36Sopenharmony_ci return ret; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci ret = clk_prepare_enable(f->clk); 61462306a36Sopenharmony_ci if (ret) { 61562306a36Sopenharmony_ci clk_disable_unprepare(f->clk_en); 61662306a36Sopenharmony_ci return ret; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci return 0; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic int nxp_fspi_clk_disable_unprep(struct nxp_fspi *f) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci if (is_acpi_node(dev_fwnode(f->dev))) 62562306a36Sopenharmony_ci return 0; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci clk_disable_unprepare(f->clk); 62862306a36Sopenharmony_ci clk_disable_unprepare(f->clk_en); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci return 0; 63162306a36Sopenharmony_ci} 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_cistatic void nxp_fspi_dll_calibration(struct nxp_fspi *f) 63462306a36Sopenharmony_ci{ 63562306a36Sopenharmony_ci int ret; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci /* Reset the DLL, set the DLLRESET to 1 and then set to 0 */ 63862306a36Sopenharmony_ci fspi_writel(f, FSPI_DLLACR_DLLRESET, f->iobase + FSPI_DLLACR); 63962306a36Sopenharmony_ci fspi_writel(f, FSPI_DLLBCR_DLLRESET, f->iobase + FSPI_DLLBCR); 64062306a36Sopenharmony_ci fspi_writel(f, 0, f->iobase + FSPI_DLLACR); 64162306a36Sopenharmony_ci fspi_writel(f, 0, f->iobase + FSPI_DLLBCR); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci /* 64462306a36Sopenharmony_ci * Enable the DLL calibration mode. 64562306a36Sopenharmony_ci * The delay target for slave delay line is: 64662306a36Sopenharmony_ci * ((SLVDLYTARGET+1) * 1/32 * clock cycle of reference clock. 64762306a36Sopenharmony_ci * When clock rate > 100MHz, recommend SLVDLYTARGET is 0xF, which 64862306a36Sopenharmony_ci * means half of clock cycle of reference clock. 64962306a36Sopenharmony_ci */ 65062306a36Sopenharmony_ci fspi_writel(f, FSPI_DLLACR_DLLEN | FSPI_DLLACR_SLVDLY(0xF), 65162306a36Sopenharmony_ci f->iobase + FSPI_DLLACR); 65262306a36Sopenharmony_ci fspi_writel(f, FSPI_DLLBCR_DLLEN | FSPI_DLLBCR_SLVDLY(0xF), 65362306a36Sopenharmony_ci f->iobase + FSPI_DLLBCR); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci /* Wait to get REF/SLV lock */ 65662306a36Sopenharmony_ci ret = fspi_readl_poll_tout(f, f->iobase + FSPI_STS2, FSPI_STS2_AB_LOCK, 65762306a36Sopenharmony_ci 0, POLL_TOUT, true); 65862306a36Sopenharmony_ci if (ret) 65962306a36Sopenharmony_ci dev_warn(f->dev, "DLL lock failed, please fix it!\n"); 66062306a36Sopenharmony_ci} 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci/* 66362306a36Sopenharmony_ci * In FlexSPI controller, flash access is based on value of FSPI_FLSHXXCR0 66462306a36Sopenharmony_ci * register and start base address of the slave device. 66562306a36Sopenharmony_ci * 66662306a36Sopenharmony_ci * (Higher address) 66762306a36Sopenharmony_ci * -------- <-- FLSHB2CR0 66862306a36Sopenharmony_ci * | B2 | 66962306a36Sopenharmony_ci * | | 67062306a36Sopenharmony_ci * B2 start address --> -------- <-- FLSHB1CR0 67162306a36Sopenharmony_ci * | B1 | 67262306a36Sopenharmony_ci * | | 67362306a36Sopenharmony_ci * B1 start address --> -------- <-- FLSHA2CR0 67462306a36Sopenharmony_ci * | A2 | 67562306a36Sopenharmony_ci * | | 67662306a36Sopenharmony_ci * A2 start address --> -------- <-- FLSHA1CR0 67762306a36Sopenharmony_ci * | A1 | 67862306a36Sopenharmony_ci * | | 67962306a36Sopenharmony_ci * A1 start address --> -------- (Lower address) 68062306a36Sopenharmony_ci * 68162306a36Sopenharmony_ci * 68262306a36Sopenharmony_ci * Start base address defines the starting address range for given CS and 68362306a36Sopenharmony_ci * FSPI_FLSHXXCR0 defines the size of the slave device connected at given CS. 68462306a36Sopenharmony_ci * 68562306a36Sopenharmony_ci * But, different targets are having different combinations of number of CS, 68662306a36Sopenharmony_ci * some targets only have single CS or two CS covering controller's full 68762306a36Sopenharmony_ci * memory mapped space area. 68862306a36Sopenharmony_ci * Thus, implementation is being done as independent of the size and number 68962306a36Sopenharmony_ci * of the connected slave device. 69062306a36Sopenharmony_ci * Assign controller memory mapped space size as the size to the connected 69162306a36Sopenharmony_ci * slave device. 69262306a36Sopenharmony_ci * Mark FLSHxxCR0 as zero initially and then assign value only to the selected 69362306a36Sopenharmony_ci * chip-select Flash configuration register. 69462306a36Sopenharmony_ci * 69562306a36Sopenharmony_ci * For e.g. to access CS2 (B1), FLSHB1CR0 register would be equal to the 69662306a36Sopenharmony_ci * memory mapped size of the controller. 69762306a36Sopenharmony_ci * Value for rest of the CS FLSHxxCR0 register would be zero. 69862306a36Sopenharmony_ci * 69962306a36Sopenharmony_ci */ 70062306a36Sopenharmony_cistatic void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci unsigned long rate = spi->max_speed_hz; 70362306a36Sopenharmony_ci int ret; 70462306a36Sopenharmony_ci uint64_t size_kb; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci /* 70762306a36Sopenharmony_ci * Return, if previously selected slave device is same as current 70862306a36Sopenharmony_ci * requested slave device. 70962306a36Sopenharmony_ci */ 71062306a36Sopenharmony_ci if (f->selected == spi_get_chipselect(spi, 0)) 71162306a36Sopenharmony_ci return; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci /* Reset FLSHxxCR0 registers */ 71462306a36Sopenharmony_ci fspi_writel(f, 0, f->iobase + FSPI_FLSHA1CR0); 71562306a36Sopenharmony_ci fspi_writel(f, 0, f->iobase + FSPI_FLSHA2CR0); 71662306a36Sopenharmony_ci fspi_writel(f, 0, f->iobase + FSPI_FLSHB1CR0); 71762306a36Sopenharmony_ci fspi_writel(f, 0, f->iobase + FSPI_FLSHB2CR0); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci /* Assign controller memory mapped space as size, KBytes, of flash. */ 72062306a36Sopenharmony_ci size_kb = FSPI_FLSHXCR0_SZ(f->memmap_phy_size); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci fspi_writel(f, size_kb, f->iobase + FSPI_FLSHA1CR0 + 72362306a36Sopenharmony_ci 4 * spi_get_chipselect(spi, 0)); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci dev_dbg(f->dev, "Slave device [CS:%x] selected\n", spi_get_chipselect(spi, 0)); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci nxp_fspi_clk_disable_unprep(f); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci ret = clk_set_rate(f->clk, rate); 73062306a36Sopenharmony_ci if (ret) 73162306a36Sopenharmony_ci return; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci ret = nxp_fspi_clk_prep_enable(f); 73462306a36Sopenharmony_ci if (ret) 73562306a36Sopenharmony_ci return; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci /* 73862306a36Sopenharmony_ci * If clock rate > 100MHz, then switch from DLL override mode to 73962306a36Sopenharmony_ci * DLL calibration mode. 74062306a36Sopenharmony_ci */ 74162306a36Sopenharmony_ci if (rate > 100000000) 74262306a36Sopenharmony_ci nxp_fspi_dll_calibration(f); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci f->selected = spi_get_chipselect(spi, 0); 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_cistatic int nxp_fspi_read_ahb(struct nxp_fspi *f, const struct spi_mem_op *op) 74862306a36Sopenharmony_ci{ 74962306a36Sopenharmony_ci u32 start = op->addr.val; 75062306a36Sopenharmony_ci u32 len = op->data.nbytes; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci /* if necessary, ioremap before AHB read */ 75362306a36Sopenharmony_ci if ((!f->ahb_addr) || start < f->memmap_start || 75462306a36Sopenharmony_ci start + len > f->memmap_start + f->memmap_len) { 75562306a36Sopenharmony_ci if (f->ahb_addr) 75662306a36Sopenharmony_ci iounmap(f->ahb_addr); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci f->memmap_start = start; 75962306a36Sopenharmony_ci f->memmap_len = len > NXP_FSPI_MIN_IOMAP ? 76062306a36Sopenharmony_ci len : NXP_FSPI_MIN_IOMAP; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci f->ahb_addr = ioremap(f->memmap_phy + f->memmap_start, 76362306a36Sopenharmony_ci f->memmap_len); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci if (!f->ahb_addr) { 76662306a36Sopenharmony_ci dev_err(f->dev, "failed to alloc memory\n"); 76762306a36Sopenharmony_ci return -ENOMEM; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci /* Read out the data directly from the AHB buffer. */ 77262306a36Sopenharmony_ci memcpy_fromio(op->data.buf.in, 77362306a36Sopenharmony_ci f->ahb_addr + start - f->memmap_start, len); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci return 0; 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_cistatic void nxp_fspi_fill_txfifo(struct nxp_fspi *f, 77962306a36Sopenharmony_ci const struct spi_mem_op *op) 78062306a36Sopenharmony_ci{ 78162306a36Sopenharmony_ci void __iomem *base = f->iobase; 78262306a36Sopenharmony_ci int i, ret; 78362306a36Sopenharmony_ci u8 *buf = (u8 *) op->data.buf.out; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci /* clear the TX FIFO. */ 78662306a36Sopenharmony_ci fspi_writel(f, FSPI_IPTXFCR_CLR, base + FSPI_IPTXFCR); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci /* 78962306a36Sopenharmony_ci * Default value of water mark level is 8 bytes, hence in single 79062306a36Sopenharmony_ci * write request controller can write max 8 bytes of data. 79162306a36Sopenharmony_ci */ 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci for (i = 0; i < ALIGN_DOWN(op->data.nbytes, 8); i += 8) { 79462306a36Sopenharmony_ci /* Wait for TXFIFO empty */ 79562306a36Sopenharmony_ci ret = fspi_readl_poll_tout(f, f->iobase + FSPI_INTR, 79662306a36Sopenharmony_ci FSPI_INTR_IPTXWE, 0, 79762306a36Sopenharmony_ci POLL_TOUT, true); 79862306a36Sopenharmony_ci WARN_ON(ret); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci fspi_writel(f, *(u32 *) (buf + i), base + FSPI_TFDR); 80162306a36Sopenharmony_ci fspi_writel(f, *(u32 *) (buf + i + 4), base + FSPI_TFDR + 4); 80262306a36Sopenharmony_ci fspi_writel(f, FSPI_INTR_IPTXWE, base + FSPI_INTR); 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci if (i < op->data.nbytes) { 80662306a36Sopenharmony_ci u32 data = 0; 80762306a36Sopenharmony_ci int j; 80862306a36Sopenharmony_ci /* Wait for TXFIFO empty */ 80962306a36Sopenharmony_ci ret = fspi_readl_poll_tout(f, f->iobase + FSPI_INTR, 81062306a36Sopenharmony_ci FSPI_INTR_IPTXWE, 0, 81162306a36Sopenharmony_ci POLL_TOUT, true); 81262306a36Sopenharmony_ci WARN_ON(ret); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci for (j = 0; j < ALIGN(op->data.nbytes - i, 4); j += 4) { 81562306a36Sopenharmony_ci memcpy(&data, buf + i + j, 4); 81662306a36Sopenharmony_ci fspi_writel(f, data, base + FSPI_TFDR + j); 81762306a36Sopenharmony_ci } 81862306a36Sopenharmony_ci fspi_writel(f, FSPI_INTR_IPTXWE, base + FSPI_INTR); 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_cistatic void nxp_fspi_read_rxfifo(struct nxp_fspi *f, 82362306a36Sopenharmony_ci const struct spi_mem_op *op) 82462306a36Sopenharmony_ci{ 82562306a36Sopenharmony_ci void __iomem *base = f->iobase; 82662306a36Sopenharmony_ci int i, ret; 82762306a36Sopenharmony_ci int len = op->data.nbytes; 82862306a36Sopenharmony_ci u8 *buf = (u8 *) op->data.buf.in; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci /* 83162306a36Sopenharmony_ci * Default value of water mark level is 8 bytes, hence in single 83262306a36Sopenharmony_ci * read request controller can read max 8 bytes of data. 83362306a36Sopenharmony_ci */ 83462306a36Sopenharmony_ci for (i = 0; i < ALIGN_DOWN(len, 8); i += 8) { 83562306a36Sopenharmony_ci /* Wait for RXFIFO available */ 83662306a36Sopenharmony_ci ret = fspi_readl_poll_tout(f, f->iobase + FSPI_INTR, 83762306a36Sopenharmony_ci FSPI_INTR_IPRXWA, 0, 83862306a36Sopenharmony_ci POLL_TOUT, true); 83962306a36Sopenharmony_ci WARN_ON(ret); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci *(u32 *)(buf + i) = fspi_readl(f, base + FSPI_RFDR); 84262306a36Sopenharmony_ci *(u32 *)(buf + i + 4) = fspi_readl(f, base + FSPI_RFDR + 4); 84362306a36Sopenharmony_ci /* move the FIFO pointer */ 84462306a36Sopenharmony_ci fspi_writel(f, FSPI_INTR_IPRXWA, base + FSPI_INTR); 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci if (i < len) { 84862306a36Sopenharmony_ci u32 tmp; 84962306a36Sopenharmony_ci int size, j; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci buf = op->data.buf.in + i; 85262306a36Sopenharmony_ci /* Wait for RXFIFO available */ 85362306a36Sopenharmony_ci ret = fspi_readl_poll_tout(f, f->iobase + FSPI_INTR, 85462306a36Sopenharmony_ci FSPI_INTR_IPRXWA, 0, 85562306a36Sopenharmony_ci POLL_TOUT, true); 85662306a36Sopenharmony_ci WARN_ON(ret); 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci len = op->data.nbytes - i; 85962306a36Sopenharmony_ci for (j = 0; j < op->data.nbytes - i; j += 4) { 86062306a36Sopenharmony_ci tmp = fspi_readl(f, base + FSPI_RFDR + j); 86162306a36Sopenharmony_ci size = min(len, 4); 86262306a36Sopenharmony_ci memcpy(buf + j, &tmp, size); 86362306a36Sopenharmony_ci len -= size; 86462306a36Sopenharmony_ci } 86562306a36Sopenharmony_ci } 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci /* invalid the RXFIFO */ 86862306a36Sopenharmony_ci fspi_writel(f, FSPI_IPRXFCR_CLR, base + FSPI_IPRXFCR); 86962306a36Sopenharmony_ci /* move the FIFO pointer */ 87062306a36Sopenharmony_ci fspi_writel(f, FSPI_INTR_IPRXWA, base + FSPI_INTR); 87162306a36Sopenharmony_ci} 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_cistatic int nxp_fspi_do_op(struct nxp_fspi *f, const struct spi_mem_op *op) 87462306a36Sopenharmony_ci{ 87562306a36Sopenharmony_ci void __iomem *base = f->iobase; 87662306a36Sopenharmony_ci int seqnum = 0; 87762306a36Sopenharmony_ci int err = 0; 87862306a36Sopenharmony_ci u32 reg; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci reg = fspi_readl(f, base + FSPI_IPRXFCR); 88162306a36Sopenharmony_ci /* invalid RXFIFO first */ 88262306a36Sopenharmony_ci reg &= ~FSPI_IPRXFCR_DMA_EN; 88362306a36Sopenharmony_ci reg = reg | FSPI_IPRXFCR_CLR; 88462306a36Sopenharmony_ci fspi_writel(f, reg, base + FSPI_IPRXFCR); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci init_completion(&f->c); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci fspi_writel(f, op->addr.val, base + FSPI_IPCR0); 88962306a36Sopenharmony_ci /* 89062306a36Sopenharmony_ci * Always start the sequence at the same index since we update 89162306a36Sopenharmony_ci * the LUT at each exec_op() call. And also specify the DATA 89262306a36Sopenharmony_ci * length, since it's has not been specified in the LUT. 89362306a36Sopenharmony_ci */ 89462306a36Sopenharmony_ci fspi_writel(f, op->data.nbytes | 89562306a36Sopenharmony_ci (SEQID_LUT << FSPI_IPCR1_SEQID_SHIFT) | 89662306a36Sopenharmony_ci (seqnum << FSPI_IPCR1_SEQNUM_SHIFT), 89762306a36Sopenharmony_ci base + FSPI_IPCR1); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci /* Trigger the LUT now. */ 90062306a36Sopenharmony_ci fspi_writel(f, FSPI_IPCMD_TRG, base + FSPI_IPCMD); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci /* Wait for the interrupt. */ 90362306a36Sopenharmony_ci if (!wait_for_completion_timeout(&f->c, msecs_to_jiffies(1000))) 90462306a36Sopenharmony_ci err = -ETIMEDOUT; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci /* Invoke IP data read, if request is of data read. */ 90762306a36Sopenharmony_ci if (!err && op->data.nbytes && op->data.dir == SPI_MEM_DATA_IN) 90862306a36Sopenharmony_ci nxp_fspi_read_rxfifo(f, op); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci return err; 91162306a36Sopenharmony_ci} 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_cistatic int nxp_fspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) 91462306a36Sopenharmony_ci{ 91562306a36Sopenharmony_ci struct nxp_fspi *f = spi_controller_get_devdata(mem->spi->master); 91662306a36Sopenharmony_ci int err = 0; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci mutex_lock(&f->lock); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci /* Wait for controller being ready. */ 92162306a36Sopenharmony_ci err = fspi_readl_poll_tout(f, f->iobase + FSPI_STS0, 92262306a36Sopenharmony_ci FSPI_STS0_ARB_IDLE, 1, POLL_TOUT, true); 92362306a36Sopenharmony_ci WARN_ON(err); 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci nxp_fspi_select_mem(f, mem->spi); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci nxp_fspi_prepare_lut(f, op); 92862306a36Sopenharmony_ci /* 92962306a36Sopenharmony_ci * If we have large chunks of data, we read them through the AHB bus by 93062306a36Sopenharmony_ci * accessing the mapped memory. In all other cases we use IP commands 93162306a36Sopenharmony_ci * to access the flash. Read via AHB bus may be corrupted due to 93262306a36Sopenharmony_ci * existence of an errata and therefore discard AHB read in such cases. 93362306a36Sopenharmony_ci */ 93462306a36Sopenharmony_ci if (op->data.nbytes > (f->devtype_data->rxfifo - 4) && 93562306a36Sopenharmony_ci op->data.dir == SPI_MEM_DATA_IN && 93662306a36Sopenharmony_ci !needs_ip_only(f)) { 93762306a36Sopenharmony_ci err = nxp_fspi_read_ahb(f, op); 93862306a36Sopenharmony_ci } else { 93962306a36Sopenharmony_ci if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT) 94062306a36Sopenharmony_ci nxp_fspi_fill_txfifo(f, op); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci err = nxp_fspi_do_op(f, op); 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci /* Invalidate the data in the AHB buffer. */ 94662306a36Sopenharmony_ci nxp_fspi_invalid(f); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci mutex_unlock(&f->lock); 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci return err; 95162306a36Sopenharmony_ci} 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_cistatic int nxp_fspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) 95462306a36Sopenharmony_ci{ 95562306a36Sopenharmony_ci struct nxp_fspi *f = spi_controller_get_devdata(mem->spi->master); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci if (op->data.dir == SPI_MEM_DATA_OUT) { 95862306a36Sopenharmony_ci if (op->data.nbytes > f->devtype_data->txfifo) 95962306a36Sopenharmony_ci op->data.nbytes = f->devtype_data->txfifo; 96062306a36Sopenharmony_ci } else { 96162306a36Sopenharmony_ci if (op->data.nbytes > f->devtype_data->ahb_buf_size) 96262306a36Sopenharmony_ci op->data.nbytes = f->devtype_data->ahb_buf_size; 96362306a36Sopenharmony_ci else if (op->data.nbytes > (f->devtype_data->rxfifo - 4)) 96462306a36Sopenharmony_ci op->data.nbytes = ALIGN_DOWN(op->data.nbytes, 8); 96562306a36Sopenharmony_ci } 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci /* Limit data bytes to RX FIFO in case of IP read only */ 96862306a36Sopenharmony_ci if (op->data.dir == SPI_MEM_DATA_IN && 96962306a36Sopenharmony_ci needs_ip_only(f) && 97062306a36Sopenharmony_ci op->data.nbytes > f->devtype_data->rxfifo) 97162306a36Sopenharmony_ci op->data.nbytes = f->devtype_data->rxfifo; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci return 0; 97462306a36Sopenharmony_ci} 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_cistatic void erratum_err050568(struct nxp_fspi *f) 97762306a36Sopenharmony_ci{ 97862306a36Sopenharmony_ci static const struct soc_device_attribute ls1028a_soc_attr[] = { 97962306a36Sopenharmony_ci { .family = "QorIQ LS1028A" }, 98062306a36Sopenharmony_ci { /* sentinel */ } 98162306a36Sopenharmony_ci }; 98262306a36Sopenharmony_ci struct regmap *map; 98362306a36Sopenharmony_ci u32 val, sys_pll_ratio; 98462306a36Sopenharmony_ci int ret; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci /* Check for LS1028A family */ 98762306a36Sopenharmony_ci if (!soc_device_match(ls1028a_soc_attr)) { 98862306a36Sopenharmony_ci dev_dbg(f->dev, "Errata applicable only for LS1028A\n"); 98962306a36Sopenharmony_ci return; 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci map = syscon_regmap_lookup_by_compatible("fsl,ls1028a-dcfg"); 99362306a36Sopenharmony_ci if (IS_ERR(map)) { 99462306a36Sopenharmony_ci dev_err(f->dev, "No syscon regmap\n"); 99562306a36Sopenharmony_ci goto err; 99662306a36Sopenharmony_ci } 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci ret = regmap_read(map, DCFG_RCWSR1, &val); 99962306a36Sopenharmony_ci if (ret < 0) 100062306a36Sopenharmony_ci goto err; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci sys_pll_ratio = FIELD_GET(SYS_PLL_RAT, val); 100362306a36Sopenharmony_ci dev_dbg(f->dev, "val: 0x%08x, sys_pll_ratio: %d\n", val, sys_pll_ratio); 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci /* Use IP bus only if platform clock is 300MHz */ 100662306a36Sopenharmony_ci if (sys_pll_ratio == 3) 100762306a36Sopenharmony_ci f->devtype_data->quirks |= FSPI_QUIRK_USE_IP_ONLY; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci return; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_cierr: 101262306a36Sopenharmony_ci dev_err(f->dev, "Errata cannot be executed. Read via IP bus may not work\n"); 101362306a36Sopenharmony_ci} 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_cistatic int nxp_fspi_default_setup(struct nxp_fspi *f) 101662306a36Sopenharmony_ci{ 101762306a36Sopenharmony_ci void __iomem *base = f->iobase; 101862306a36Sopenharmony_ci int ret, i; 101962306a36Sopenharmony_ci u32 reg; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci /* disable and unprepare clock to avoid glitch pass to controller */ 102262306a36Sopenharmony_ci nxp_fspi_clk_disable_unprep(f); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci /* the default frequency, we will change it later if necessary. */ 102562306a36Sopenharmony_ci ret = clk_set_rate(f->clk, 20000000); 102662306a36Sopenharmony_ci if (ret) 102762306a36Sopenharmony_ci return ret; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci ret = nxp_fspi_clk_prep_enable(f); 103062306a36Sopenharmony_ci if (ret) 103162306a36Sopenharmony_ci return ret; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci /* 103462306a36Sopenharmony_ci * ERR050568: Flash access by FlexSPI AHB command may not work with 103562306a36Sopenharmony_ci * platform frequency equal to 300 MHz on LS1028A. 103662306a36Sopenharmony_ci * LS1028A reuses LX2160A compatible entry. Make errata applicable for 103762306a36Sopenharmony_ci * Layerscape LS1028A platform. 103862306a36Sopenharmony_ci */ 103962306a36Sopenharmony_ci if (of_device_is_compatible(f->dev->of_node, "nxp,lx2160a-fspi")) 104062306a36Sopenharmony_ci erratum_err050568(f); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci /* Reset the module */ 104362306a36Sopenharmony_ci /* w1c register, wait unit clear */ 104462306a36Sopenharmony_ci ret = fspi_readl_poll_tout(f, f->iobase + FSPI_MCR0, 104562306a36Sopenharmony_ci FSPI_MCR0_SWRST, 0, POLL_TOUT, false); 104662306a36Sopenharmony_ci WARN_ON(ret); 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci /* Disable the module */ 104962306a36Sopenharmony_ci fspi_writel(f, FSPI_MCR0_MDIS, base + FSPI_MCR0); 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci /* 105262306a36Sopenharmony_ci * Config the DLL register to default value, enable the slave clock delay 105362306a36Sopenharmony_ci * line delay cell override mode, and use 1 fixed delay cell in DLL delay 105462306a36Sopenharmony_ci * chain, this is the suggested setting when clock rate < 100MHz. 105562306a36Sopenharmony_ci */ 105662306a36Sopenharmony_ci fspi_writel(f, FSPI_DLLACR_OVRDEN, base + FSPI_DLLACR); 105762306a36Sopenharmony_ci fspi_writel(f, FSPI_DLLBCR_OVRDEN, base + FSPI_DLLBCR); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci /* enable module */ 106062306a36Sopenharmony_ci fspi_writel(f, FSPI_MCR0_AHB_TIMEOUT(0xFF) | 106162306a36Sopenharmony_ci FSPI_MCR0_IP_TIMEOUT(0xFF) | (u32) FSPI_MCR0_OCTCOMB_EN, 106262306a36Sopenharmony_ci base + FSPI_MCR0); 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci /* 106562306a36Sopenharmony_ci * Disable same device enable bit and configure all slave devices 106662306a36Sopenharmony_ci * independently. 106762306a36Sopenharmony_ci */ 106862306a36Sopenharmony_ci reg = fspi_readl(f, f->iobase + FSPI_MCR2); 106962306a36Sopenharmony_ci reg = reg & ~(FSPI_MCR2_SAMEDEVICEEN); 107062306a36Sopenharmony_ci fspi_writel(f, reg, base + FSPI_MCR2); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci /* AHB configuration for access buffer 0~7. */ 107362306a36Sopenharmony_ci for (i = 0; i < 7; i++) 107462306a36Sopenharmony_ci fspi_writel(f, 0, base + FSPI_AHBRX_BUF0CR0 + 4 * i); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci /* 107762306a36Sopenharmony_ci * Set ADATSZ with the maximum AHB buffer size to improve the read 107862306a36Sopenharmony_ci * performance. 107962306a36Sopenharmony_ci */ 108062306a36Sopenharmony_ci fspi_writel(f, (f->devtype_data->ahb_buf_size / 8 | 108162306a36Sopenharmony_ci FSPI_AHBRXBUF0CR7_PREF), base + FSPI_AHBRX_BUF7CR0); 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci /* prefetch and no start address alignment limitation */ 108462306a36Sopenharmony_ci fspi_writel(f, FSPI_AHBCR_PREF_EN | FSPI_AHBCR_RDADDROPT, 108562306a36Sopenharmony_ci base + FSPI_AHBCR); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci /* Reset the FLSHxCR1 registers. */ 108862306a36Sopenharmony_ci reg = FSPI_FLSHXCR1_TCSH(0x3) | FSPI_FLSHXCR1_TCSS(0x3); 108962306a36Sopenharmony_ci fspi_writel(f, reg, base + FSPI_FLSHA1CR1); 109062306a36Sopenharmony_ci fspi_writel(f, reg, base + FSPI_FLSHA2CR1); 109162306a36Sopenharmony_ci fspi_writel(f, reg, base + FSPI_FLSHB1CR1); 109262306a36Sopenharmony_ci fspi_writel(f, reg, base + FSPI_FLSHB2CR1); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci /* AHB Read - Set lut sequence ID for all CS. */ 109562306a36Sopenharmony_ci fspi_writel(f, SEQID_LUT, base + FSPI_FLSHA1CR2); 109662306a36Sopenharmony_ci fspi_writel(f, SEQID_LUT, base + FSPI_FLSHA2CR2); 109762306a36Sopenharmony_ci fspi_writel(f, SEQID_LUT, base + FSPI_FLSHB1CR2); 109862306a36Sopenharmony_ci fspi_writel(f, SEQID_LUT, base + FSPI_FLSHB2CR2); 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci f->selected = -1; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci /* enable the interrupt */ 110362306a36Sopenharmony_ci fspi_writel(f, FSPI_INTEN_IPCMDDONE, base + FSPI_INTEN); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci return 0; 110662306a36Sopenharmony_ci} 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_cistatic const char *nxp_fspi_get_name(struct spi_mem *mem) 110962306a36Sopenharmony_ci{ 111062306a36Sopenharmony_ci struct nxp_fspi *f = spi_controller_get_devdata(mem->spi->master); 111162306a36Sopenharmony_ci struct device *dev = &mem->spi->dev; 111262306a36Sopenharmony_ci const char *name; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci // Set custom name derived from the platform_device of the controller. 111562306a36Sopenharmony_ci if (of_get_available_child_count(f->dev->of_node) == 1) 111662306a36Sopenharmony_ci return dev_name(f->dev); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci name = devm_kasprintf(dev, GFP_KERNEL, 111962306a36Sopenharmony_ci "%s-%d", dev_name(f->dev), 112062306a36Sopenharmony_ci spi_get_chipselect(mem->spi, 0)); 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci if (!name) { 112362306a36Sopenharmony_ci dev_err(dev, "failed to get memory for custom flash name\n"); 112462306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 112562306a36Sopenharmony_ci } 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci return name; 112862306a36Sopenharmony_ci} 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_cistatic const struct spi_controller_mem_ops nxp_fspi_mem_ops = { 113162306a36Sopenharmony_ci .adjust_op_size = nxp_fspi_adjust_op_size, 113262306a36Sopenharmony_ci .supports_op = nxp_fspi_supports_op, 113362306a36Sopenharmony_ci .exec_op = nxp_fspi_exec_op, 113462306a36Sopenharmony_ci .get_name = nxp_fspi_get_name, 113562306a36Sopenharmony_ci}; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_cistatic int nxp_fspi_probe(struct platform_device *pdev) 113862306a36Sopenharmony_ci{ 113962306a36Sopenharmony_ci struct spi_controller *ctlr; 114062306a36Sopenharmony_ci struct device *dev = &pdev->dev; 114162306a36Sopenharmony_ci struct device_node *np = dev->of_node; 114262306a36Sopenharmony_ci struct resource *res; 114362306a36Sopenharmony_ci struct nxp_fspi *f; 114462306a36Sopenharmony_ci int ret; 114562306a36Sopenharmony_ci u32 reg; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci ctlr = spi_alloc_master(&pdev->dev, sizeof(*f)); 114862306a36Sopenharmony_ci if (!ctlr) 114962306a36Sopenharmony_ci return -ENOMEM; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci ctlr->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL | 115262306a36Sopenharmony_ci SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci f = spi_controller_get_devdata(ctlr); 115562306a36Sopenharmony_ci f->dev = dev; 115662306a36Sopenharmony_ci f->devtype_data = (struct nxp_fspi_devtype_data *)device_get_match_data(dev); 115762306a36Sopenharmony_ci if (!f->devtype_data) { 115862306a36Sopenharmony_ci ret = -ENODEV; 115962306a36Sopenharmony_ci goto err_put_ctrl; 116062306a36Sopenharmony_ci } 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci platform_set_drvdata(pdev, f); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci /* find the resources - configuration register address space */ 116562306a36Sopenharmony_ci if (is_acpi_node(dev_fwnode(f->dev))) 116662306a36Sopenharmony_ci f->iobase = devm_platform_ioremap_resource(pdev, 0); 116762306a36Sopenharmony_ci else 116862306a36Sopenharmony_ci f->iobase = devm_platform_ioremap_resource_byname(pdev, "fspi_base"); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci if (IS_ERR(f->iobase)) { 117162306a36Sopenharmony_ci ret = PTR_ERR(f->iobase); 117262306a36Sopenharmony_ci goto err_put_ctrl; 117362306a36Sopenharmony_ci } 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci /* find the resources - controller memory mapped space */ 117662306a36Sopenharmony_ci if (is_acpi_node(dev_fwnode(f->dev))) 117762306a36Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 117862306a36Sopenharmony_ci else 117962306a36Sopenharmony_ci res = platform_get_resource_byname(pdev, 118062306a36Sopenharmony_ci IORESOURCE_MEM, "fspi_mmap"); 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci if (!res) { 118362306a36Sopenharmony_ci ret = -ENODEV; 118462306a36Sopenharmony_ci goto err_put_ctrl; 118562306a36Sopenharmony_ci } 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci /* assign memory mapped starting address and mapped size. */ 118862306a36Sopenharmony_ci f->memmap_phy = res->start; 118962306a36Sopenharmony_ci f->memmap_phy_size = resource_size(res); 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci /* find the clocks */ 119262306a36Sopenharmony_ci if (dev_of_node(&pdev->dev)) { 119362306a36Sopenharmony_ci f->clk_en = devm_clk_get(dev, "fspi_en"); 119462306a36Sopenharmony_ci if (IS_ERR(f->clk_en)) { 119562306a36Sopenharmony_ci ret = PTR_ERR(f->clk_en); 119662306a36Sopenharmony_ci goto err_put_ctrl; 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci f->clk = devm_clk_get(dev, "fspi"); 120062306a36Sopenharmony_ci if (IS_ERR(f->clk)) { 120162306a36Sopenharmony_ci ret = PTR_ERR(f->clk); 120262306a36Sopenharmony_ci goto err_put_ctrl; 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci ret = nxp_fspi_clk_prep_enable(f); 120662306a36Sopenharmony_ci if (ret) { 120762306a36Sopenharmony_ci dev_err(dev, "can not enable the clock\n"); 120862306a36Sopenharmony_ci goto err_put_ctrl; 120962306a36Sopenharmony_ci } 121062306a36Sopenharmony_ci } 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci /* Clear potential interrupts */ 121362306a36Sopenharmony_ci reg = fspi_readl(f, f->iobase + FSPI_INTR); 121462306a36Sopenharmony_ci if (reg) 121562306a36Sopenharmony_ci fspi_writel(f, reg, f->iobase + FSPI_INTR); 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci /* find the irq */ 121862306a36Sopenharmony_ci ret = platform_get_irq(pdev, 0); 121962306a36Sopenharmony_ci if (ret < 0) 122062306a36Sopenharmony_ci goto err_disable_clk; 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci ret = devm_request_irq(dev, ret, 122362306a36Sopenharmony_ci nxp_fspi_irq_handler, 0, pdev->name, f); 122462306a36Sopenharmony_ci if (ret) { 122562306a36Sopenharmony_ci dev_err(dev, "failed to request irq: %d\n", ret); 122662306a36Sopenharmony_ci goto err_disable_clk; 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci mutex_init(&f->lock); 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci ctlr->bus_num = -1; 123262306a36Sopenharmony_ci ctlr->num_chipselect = NXP_FSPI_MAX_CHIPSELECT; 123362306a36Sopenharmony_ci ctlr->mem_ops = &nxp_fspi_mem_ops; 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci nxp_fspi_default_setup(f); 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci ctlr->dev.of_node = np; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci ret = devm_spi_register_controller(&pdev->dev, ctlr); 124062306a36Sopenharmony_ci if (ret) 124162306a36Sopenharmony_ci goto err_destroy_mutex; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci return 0; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_cierr_destroy_mutex: 124662306a36Sopenharmony_ci mutex_destroy(&f->lock); 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_cierr_disable_clk: 124962306a36Sopenharmony_ci nxp_fspi_clk_disable_unprep(f); 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_cierr_put_ctrl: 125262306a36Sopenharmony_ci spi_controller_put(ctlr); 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci dev_err(dev, "NXP FSPI probe failed\n"); 125562306a36Sopenharmony_ci return ret; 125662306a36Sopenharmony_ci} 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_cistatic void nxp_fspi_remove(struct platform_device *pdev) 125962306a36Sopenharmony_ci{ 126062306a36Sopenharmony_ci struct nxp_fspi *f = platform_get_drvdata(pdev); 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci /* disable the hardware */ 126362306a36Sopenharmony_ci fspi_writel(f, FSPI_MCR0_MDIS, f->iobase + FSPI_MCR0); 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci nxp_fspi_clk_disable_unprep(f); 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci mutex_destroy(&f->lock); 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci if (f->ahb_addr) 127062306a36Sopenharmony_ci iounmap(f->ahb_addr); 127162306a36Sopenharmony_ci} 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_cistatic int nxp_fspi_suspend(struct device *dev) 127462306a36Sopenharmony_ci{ 127562306a36Sopenharmony_ci return 0; 127662306a36Sopenharmony_ci} 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_cistatic int nxp_fspi_resume(struct device *dev) 127962306a36Sopenharmony_ci{ 128062306a36Sopenharmony_ci struct nxp_fspi *f = dev_get_drvdata(dev); 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci nxp_fspi_default_setup(f); 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci return 0; 128562306a36Sopenharmony_ci} 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_cistatic const struct of_device_id nxp_fspi_dt_ids[] = { 128862306a36Sopenharmony_ci { .compatible = "nxp,lx2160a-fspi", .data = (void *)&lx2160a_data, }, 128962306a36Sopenharmony_ci { .compatible = "nxp,imx8mm-fspi", .data = (void *)&imx8mm_data, }, 129062306a36Sopenharmony_ci { .compatible = "nxp,imx8mp-fspi", .data = (void *)&imx8mm_data, }, 129162306a36Sopenharmony_ci { .compatible = "nxp,imx8qxp-fspi", .data = (void *)&imx8qxp_data, }, 129262306a36Sopenharmony_ci { .compatible = "nxp,imx8dxl-fspi", .data = (void *)&imx8dxl_data, }, 129362306a36Sopenharmony_ci { /* sentinel */ } 129462306a36Sopenharmony_ci}; 129562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, nxp_fspi_dt_ids); 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci#ifdef CONFIG_ACPI 129862306a36Sopenharmony_cistatic const struct acpi_device_id nxp_fspi_acpi_ids[] = { 129962306a36Sopenharmony_ci { "NXP0009", .driver_data = (kernel_ulong_t)&lx2160a_data, }, 130062306a36Sopenharmony_ci {} 130162306a36Sopenharmony_ci}; 130262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, nxp_fspi_acpi_ids); 130362306a36Sopenharmony_ci#endif 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_cistatic const struct dev_pm_ops nxp_fspi_pm_ops = { 130662306a36Sopenharmony_ci .suspend = nxp_fspi_suspend, 130762306a36Sopenharmony_ci .resume = nxp_fspi_resume, 130862306a36Sopenharmony_ci}; 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_cistatic struct platform_driver nxp_fspi_driver = { 131162306a36Sopenharmony_ci .driver = { 131262306a36Sopenharmony_ci .name = "nxp-fspi", 131362306a36Sopenharmony_ci .of_match_table = nxp_fspi_dt_ids, 131462306a36Sopenharmony_ci .acpi_match_table = ACPI_PTR(nxp_fspi_acpi_ids), 131562306a36Sopenharmony_ci .pm = &nxp_fspi_pm_ops, 131662306a36Sopenharmony_ci }, 131762306a36Sopenharmony_ci .probe = nxp_fspi_probe, 131862306a36Sopenharmony_ci .remove_new = nxp_fspi_remove, 131962306a36Sopenharmony_ci}; 132062306a36Sopenharmony_cimodule_platform_driver(nxp_fspi_driver); 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ciMODULE_DESCRIPTION("NXP FSPI Controller Driver"); 132362306a36Sopenharmony_ciMODULE_AUTHOR("NXP Semiconductor"); 132462306a36Sopenharmony_ciMODULE_AUTHOR("Yogesh Narayan Gaur <yogeshnarayan.gaur@nxp.com>"); 132562306a36Sopenharmony_ciMODULE_AUTHOR("Boris Brezillon <bbrezillon@kernel.org>"); 132662306a36Sopenharmony_ciMODULE_AUTHOR("Frieder Schrempf <frieder.schrempf@kontron.de>"); 132762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1328