18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Driver for Cadence QSPI Controller 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright Altera Corporation (C) 2012-2014. All rights reserved. 68c2ecf20Sopenharmony_ci// Copyright Intel Corporation (C) 2019-2020. All rights reserved. 78c2ecf20Sopenharmony_ci// Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/clk.h> 108c2ecf20Sopenharmony_ci#include <linux/completion.h> 118c2ecf20Sopenharmony_ci#include <linux/delay.h> 128c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 138c2ecf20Sopenharmony_ci#include <linux/dmaengine.h> 148c2ecf20Sopenharmony_ci#include <linux/err.h> 158c2ecf20Sopenharmony_ci#include <linux/errno.h> 168c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 178c2ecf20Sopenharmony_ci#include <linux/io.h> 188c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 198c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 208c2ecf20Sopenharmony_ci#include <linux/kernel.h> 218c2ecf20Sopenharmony_ci#include <linux/module.h> 228c2ecf20Sopenharmony_ci#include <linux/of_device.h> 238c2ecf20Sopenharmony_ci#include <linux/of.h> 248c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 258c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 268c2ecf20Sopenharmony_ci#include <linux/reset.h> 278c2ecf20Sopenharmony_ci#include <linux/sched.h> 288c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 298c2ecf20Sopenharmony_ci#include <linux/spi/spi-mem.h> 308c2ecf20Sopenharmony_ci#include <linux/timer.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define CQSPI_NAME "cadence-qspi" 338c2ecf20Sopenharmony_ci#define CQSPI_MAX_CHIPSELECT 16 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* Quirks */ 368c2ecf20Sopenharmony_ci#define CQSPI_NEEDS_WR_DELAY BIT(0) 378c2ecf20Sopenharmony_ci#define CQSPI_DISABLE_DAC_MODE BIT(1) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* Capabilities */ 408c2ecf20Sopenharmony_ci#define CQSPI_SUPPORTS_OCTAL BIT(0) 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistruct cqspi_st; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistruct cqspi_flash_pdata { 458c2ecf20Sopenharmony_ci struct cqspi_st *cqspi; 468c2ecf20Sopenharmony_ci u32 clk_rate; 478c2ecf20Sopenharmony_ci u32 read_delay; 488c2ecf20Sopenharmony_ci u32 tshsl_ns; 498c2ecf20Sopenharmony_ci u32 tsd2d_ns; 508c2ecf20Sopenharmony_ci u32 tchsh_ns; 518c2ecf20Sopenharmony_ci u32 tslch_ns; 528c2ecf20Sopenharmony_ci u8 inst_width; 538c2ecf20Sopenharmony_ci u8 addr_width; 548c2ecf20Sopenharmony_ci u8 data_width; 558c2ecf20Sopenharmony_ci u8 cs; 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistruct cqspi_st { 598c2ecf20Sopenharmony_ci struct platform_device *pdev; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci struct clk *clk; 628c2ecf20Sopenharmony_ci unsigned int sclk; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci void __iomem *iobase; 658c2ecf20Sopenharmony_ci void __iomem *ahb_base; 668c2ecf20Sopenharmony_ci resource_size_t ahb_size; 678c2ecf20Sopenharmony_ci struct completion transfer_complete; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci struct dma_chan *rx_chan; 708c2ecf20Sopenharmony_ci struct completion rx_dma_complete; 718c2ecf20Sopenharmony_ci dma_addr_t mmap_phys_base; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci int current_cs; 748c2ecf20Sopenharmony_ci unsigned long master_ref_clk_hz; 758c2ecf20Sopenharmony_ci bool is_decoded_cs; 768c2ecf20Sopenharmony_ci u32 fifo_depth; 778c2ecf20Sopenharmony_ci u32 fifo_width; 788c2ecf20Sopenharmony_ci bool rclk_en; 798c2ecf20Sopenharmony_ci u32 trigger_address; 808c2ecf20Sopenharmony_ci u32 wr_delay; 818c2ecf20Sopenharmony_ci bool use_direct_mode; 828c2ecf20Sopenharmony_ci struct cqspi_flash_pdata f_pdata[CQSPI_MAX_CHIPSELECT]; 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistruct cqspi_driver_platdata { 868c2ecf20Sopenharmony_ci u32 hwcaps_mask; 878c2ecf20Sopenharmony_ci u8 quirks; 888c2ecf20Sopenharmony_ci}; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* Operation timeout value */ 918c2ecf20Sopenharmony_ci#define CQSPI_TIMEOUT_MS 500 928c2ecf20Sopenharmony_ci#define CQSPI_READ_TIMEOUT_MS 10 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/* Instruction type */ 958c2ecf20Sopenharmony_ci#define CQSPI_INST_TYPE_SINGLE 0 968c2ecf20Sopenharmony_ci#define CQSPI_INST_TYPE_DUAL 1 978c2ecf20Sopenharmony_ci#define CQSPI_INST_TYPE_QUAD 2 988c2ecf20Sopenharmony_ci#define CQSPI_INST_TYPE_OCTAL 3 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci#define CQSPI_DUMMY_CLKS_PER_BYTE 8 1018c2ecf20Sopenharmony_ci#define CQSPI_DUMMY_BYTES_MAX 4 1028c2ecf20Sopenharmony_ci#define CQSPI_DUMMY_CLKS_MAX 31 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci#define CQSPI_STIG_DATA_LEN_MAX 8 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* Register map */ 1078c2ecf20Sopenharmony_ci#define CQSPI_REG_CONFIG 0x00 1088c2ecf20Sopenharmony_ci#define CQSPI_REG_CONFIG_ENABLE_MASK BIT(0) 1098c2ecf20Sopenharmony_ci#define CQSPI_REG_CONFIG_ENB_DIR_ACC_CTRL BIT(7) 1108c2ecf20Sopenharmony_ci#define CQSPI_REG_CONFIG_DECODE_MASK BIT(9) 1118c2ecf20Sopenharmony_ci#define CQSPI_REG_CONFIG_CHIPSELECT_LSB 10 1128c2ecf20Sopenharmony_ci#define CQSPI_REG_CONFIG_DMA_MASK BIT(15) 1138c2ecf20Sopenharmony_ci#define CQSPI_REG_CONFIG_BAUD_LSB 19 1148c2ecf20Sopenharmony_ci#define CQSPI_REG_CONFIG_IDLE_LSB 31 1158c2ecf20Sopenharmony_ci#define CQSPI_REG_CONFIG_CHIPSELECT_MASK 0xF 1168c2ecf20Sopenharmony_ci#define CQSPI_REG_CONFIG_BAUD_MASK 0xF 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci#define CQSPI_REG_RD_INSTR 0x04 1198c2ecf20Sopenharmony_ci#define CQSPI_REG_RD_INSTR_OPCODE_LSB 0 1208c2ecf20Sopenharmony_ci#define CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB 8 1218c2ecf20Sopenharmony_ci#define CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB 12 1228c2ecf20Sopenharmony_ci#define CQSPI_REG_RD_INSTR_TYPE_DATA_LSB 16 1238c2ecf20Sopenharmony_ci#define CQSPI_REG_RD_INSTR_MODE_EN_LSB 20 1248c2ecf20Sopenharmony_ci#define CQSPI_REG_RD_INSTR_DUMMY_LSB 24 1258c2ecf20Sopenharmony_ci#define CQSPI_REG_RD_INSTR_TYPE_INSTR_MASK 0x3 1268c2ecf20Sopenharmony_ci#define CQSPI_REG_RD_INSTR_TYPE_ADDR_MASK 0x3 1278c2ecf20Sopenharmony_ci#define CQSPI_REG_RD_INSTR_TYPE_DATA_MASK 0x3 1288c2ecf20Sopenharmony_ci#define CQSPI_REG_RD_INSTR_DUMMY_MASK 0x1F 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci#define CQSPI_REG_WR_INSTR 0x08 1318c2ecf20Sopenharmony_ci#define CQSPI_REG_WR_INSTR_OPCODE_LSB 0 1328c2ecf20Sopenharmony_ci#define CQSPI_REG_WR_INSTR_TYPE_ADDR_LSB 12 1338c2ecf20Sopenharmony_ci#define CQSPI_REG_WR_INSTR_TYPE_DATA_LSB 16 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci#define CQSPI_REG_DELAY 0x0C 1368c2ecf20Sopenharmony_ci#define CQSPI_REG_DELAY_TSLCH_LSB 0 1378c2ecf20Sopenharmony_ci#define CQSPI_REG_DELAY_TCHSH_LSB 8 1388c2ecf20Sopenharmony_ci#define CQSPI_REG_DELAY_TSD2D_LSB 16 1398c2ecf20Sopenharmony_ci#define CQSPI_REG_DELAY_TSHSL_LSB 24 1408c2ecf20Sopenharmony_ci#define CQSPI_REG_DELAY_TSLCH_MASK 0xFF 1418c2ecf20Sopenharmony_ci#define CQSPI_REG_DELAY_TCHSH_MASK 0xFF 1428c2ecf20Sopenharmony_ci#define CQSPI_REG_DELAY_TSD2D_MASK 0xFF 1438c2ecf20Sopenharmony_ci#define CQSPI_REG_DELAY_TSHSL_MASK 0xFF 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci#define CQSPI_REG_READCAPTURE 0x10 1468c2ecf20Sopenharmony_ci#define CQSPI_REG_READCAPTURE_BYPASS_LSB 0 1478c2ecf20Sopenharmony_ci#define CQSPI_REG_READCAPTURE_DELAY_LSB 1 1488c2ecf20Sopenharmony_ci#define CQSPI_REG_READCAPTURE_DELAY_MASK 0xF 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci#define CQSPI_REG_SIZE 0x14 1518c2ecf20Sopenharmony_ci#define CQSPI_REG_SIZE_ADDRESS_LSB 0 1528c2ecf20Sopenharmony_ci#define CQSPI_REG_SIZE_PAGE_LSB 4 1538c2ecf20Sopenharmony_ci#define CQSPI_REG_SIZE_BLOCK_LSB 16 1548c2ecf20Sopenharmony_ci#define CQSPI_REG_SIZE_ADDRESS_MASK 0xF 1558c2ecf20Sopenharmony_ci#define CQSPI_REG_SIZE_PAGE_MASK 0xFFF 1568c2ecf20Sopenharmony_ci#define CQSPI_REG_SIZE_BLOCK_MASK 0x3F 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci#define CQSPI_REG_SRAMPARTITION 0x18 1598c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTTRIGGER 0x1C 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci#define CQSPI_REG_DMA 0x20 1628c2ecf20Sopenharmony_ci#define CQSPI_REG_DMA_SINGLE_LSB 0 1638c2ecf20Sopenharmony_ci#define CQSPI_REG_DMA_BURST_LSB 8 1648c2ecf20Sopenharmony_ci#define CQSPI_REG_DMA_SINGLE_MASK 0xFF 1658c2ecf20Sopenharmony_ci#define CQSPI_REG_DMA_BURST_MASK 0xFF 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci#define CQSPI_REG_REMAP 0x24 1688c2ecf20Sopenharmony_ci#define CQSPI_REG_MODE_BIT 0x28 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci#define CQSPI_REG_SDRAMLEVEL 0x2C 1718c2ecf20Sopenharmony_ci#define CQSPI_REG_SDRAMLEVEL_RD_LSB 0 1728c2ecf20Sopenharmony_ci#define CQSPI_REG_SDRAMLEVEL_WR_LSB 16 1738c2ecf20Sopenharmony_ci#define CQSPI_REG_SDRAMLEVEL_RD_MASK 0xFFFF 1748c2ecf20Sopenharmony_ci#define CQSPI_REG_SDRAMLEVEL_WR_MASK 0xFFFF 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci#define CQSPI_REG_IRQSTATUS 0x40 1778c2ecf20Sopenharmony_ci#define CQSPI_REG_IRQMASK 0x44 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTRD 0x60 1808c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTRD_START_MASK BIT(0) 1818c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTRD_CANCEL_MASK BIT(1) 1828c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTRD_DONE_MASK BIT(5) 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTRDWATERMARK 0x64 1858c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTRDSTARTADDR 0x68 1868c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTRDBYTES 0x6C 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL 0x90 1898c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_EXECUTE_MASK BIT(0) 1908c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_INPROGRESS_MASK BIT(1) 1918c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_WR_BYTES_LSB 12 1928c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_WR_EN_LSB 15 1938c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_ADD_BYTES_LSB 16 1948c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_ADDR_EN_LSB 19 1958c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_RD_BYTES_LSB 20 1968c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_RD_EN_LSB 23 1978c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_OPCODE_LSB 24 1988c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_WR_BYTES_MASK 0x7 1998c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_ADD_BYTES_MASK 0x3 2008c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDCTRL_RD_BYTES_MASK 0x7 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTWR 0x70 2038c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTWR_START_MASK BIT(0) 2048c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTWR_CANCEL_MASK BIT(1) 2058c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTWR_DONE_MASK BIT(5) 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTWRWATERMARK 0x74 2088c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTWRSTARTADDR 0x78 2098c2ecf20Sopenharmony_ci#define CQSPI_REG_INDIRECTWRBYTES 0x7C 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDADDRESS 0x94 2128c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDREADDATALOWER 0xA0 2138c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDREADDATAUPPER 0xA4 2148c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDWRITEDATALOWER 0xA8 2158c2ecf20Sopenharmony_ci#define CQSPI_REG_CMDWRITEDATAUPPER 0xAC 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci/* Interrupt status bits */ 2188c2ecf20Sopenharmony_ci#define CQSPI_REG_IRQ_MODE_ERR BIT(0) 2198c2ecf20Sopenharmony_ci#define CQSPI_REG_IRQ_UNDERFLOW BIT(1) 2208c2ecf20Sopenharmony_ci#define CQSPI_REG_IRQ_IND_COMP BIT(2) 2218c2ecf20Sopenharmony_ci#define CQSPI_REG_IRQ_IND_RD_REJECT BIT(3) 2228c2ecf20Sopenharmony_ci#define CQSPI_REG_IRQ_WR_PROTECTED_ERR BIT(4) 2238c2ecf20Sopenharmony_ci#define CQSPI_REG_IRQ_ILLEGAL_AHB_ERR BIT(5) 2248c2ecf20Sopenharmony_ci#define CQSPI_REG_IRQ_WATERMARK BIT(6) 2258c2ecf20Sopenharmony_ci#define CQSPI_REG_IRQ_IND_SRAM_FULL BIT(12) 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci#define CQSPI_IRQ_MASK_RD (CQSPI_REG_IRQ_WATERMARK | \ 2288c2ecf20Sopenharmony_ci CQSPI_REG_IRQ_IND_SRAM_FULL | \ 2298c2ecf20Sopenharmony_ci CQSPI_REG_IRQ_IND_COMP) 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci#define CQSPI_IRQ_MASK_WR (CQSPI_REG_IRQ_IND_COMP | \ 2328c2ecf20Sopenharmony_ci CQSPI_REG_IRQ_WATERMARK | \ 2338c2ecf20Sopenharmony_ci CQSPI_REG_IRQ_UNDERFLOW) 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci#define CQSPI_IRQ_STATUS_MASK 0x1FFFF 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic int cqspi_wait_for_bit(void __iomem *reg, const u32 mask, bool clr) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci u32 val; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci return readl_relaxed_poll_timeout(reg, val, 2428c2ecf20Sopenharmony_ci (((clr ? ~val : val) & mask) == mask), 2438c2ecf20Sopenharmony_ci 10, CQSPI_TIMEOUT_MS * 1000); 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic bool cqspi_is_idle(struct cqspi_st *cqspi) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci u32 reg = readl(cqspi->iobase + CQSPI_REG_CONFIG); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci return reg & (1 << CQSPI_REG_CONFIG_IDLE_LSB); 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic u32 cqspi_get_rd_sram_level(struct cqspi_st *cqspi) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci u32 reg = readl(cqspi->iobase + CQSPI_REG_SDRAMLEVEL); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci reg >>= CQSPI_REG_SDRAMLEVEL_RD_LSB; 2588c2ecf20Sopenharmony_ci return reg & CQSPI_REG_SDRAMLEVEL_RD_MASK; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic irqreturn_t cqspi_irq_handler(int this_irq, void *dev) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct cqspi_st *cqspi = dev; 2648c2ecf20Sopenharmony_ci unsigned int irq_status; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci /* Read interrupt status */ 2678c2ecf20Sopenharmony_ci irq_status = readl(cqspi->iobase + CQSPI_REG_IRQSTATUS); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci /* Clear interrupt */ 2708c2ecf20Sopenharmony_ci writel(irq_status, cqspi->iobase + CQSPI_REG_IRQSTATUS); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci irq_status &= CQSPI_IRQ_MASK_RD | CQSPI_IRQ_MASK_WR; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (irq_status) 2758c2ecf20Sopenharmony_ci complete(&cqspi->transfer_complete); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic unsigned int cqspi_calc_rdreg(struct cqspi_flash_pdata *f_pdata) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci u32 rdreg = 0; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci rdreg |= f_pdata->inst_width << CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB; 2858c2ecf20Sopenharmony_ci rdreg |= f_pdata->addr_width << CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB; 2868c2ecf20Sopenharmony_ci rdreg |= f_pdata->data_width << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci return rdreg; 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic int cqspi_wait_idle(struct cqspi_st *cqspi) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci const unsigned int poll_idle_retry = 3; 2948c2ecf20Sopenharmony_ci unsigned int count = 0; 2958c2ecf20Sopenharmony_ci unsigned long timeout; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(CQSPI_TIMEOUT_MS); 2988c2ecf20Sopenharmony_ci while (1) { 2998c2ecf20Sopenharmony_ci /* 3008c2ecf20Sopenharmony_ci * Read few times in succession to ensure the controller 3018c2ecf20Sopenharmony_ci * is indeed idle, that is, the bit does not transition 3028c2ecf20Sopenharmony_ci * low again. 3038c2ecf20Sopenharmony_ci */ 3048c2ecf20Sopenharmony_ci if (cqspi_is_idle(cqspi)) 3058c2ecf20Sopenharmony_ci count++; 3068c2ecf20Sopenharmony_ci else 3078c2ecf20Sopenharmony_ci count = 0; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (count >= poll_idle_retry) 3108c2ecf20Sopenharmony_ci return 0; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (time_after(jiffies, timeout)) { 3138c2ecf20Sopenharmony_ci /* Timeout, in busy mode. */ 3148c2ecf20Sopenharmony_ci dev_err(&cqspi->pdev->dev, 3158c2ecf20Sopenharmony_ci "QSPI is still busy after %dms timeout.\n", 3168c2ecf20Sopenharmony_ci CQSPI_TIMEOUT_MS); 3178c2ecf20Sopenharmony_ci return -ETIMEDOUT; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci cpu_relax(); 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic int cqspi_exec_flash_cmd(struct cqspi_st *cqspi, unsigned int reg) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci void __iomem *reg_base = cqspi->iobase; 3278c2ecf20Sopenharmony_ci int ret; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci /* Write the CMDCTRL without start execution. */ 3308c2ecf20Sopenharmony_ci writel(reg, reg_base + CQSPI_REG_CMDCTRL); 3318c2ecf20Sopenharmony_ci /* Start execute */ 3328c2ecf20Sopenharmony_ci reg |= CQSPI_REG_CMDCTRL_EXECUTE_MASK; 3338c2ecf20Sopenharmony_ci writel(reg, reg_base + CQSPI_REG_CMDCTRL); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* Polling for completion. */ 3368c2ecf20Sopenharmony_ci ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_CMDCTRL, 3378c2ecf20Sopenharmony_ci CQSPI_REG_CMDCTRL_INPROGRESS_MASK, 1); 3388c2ecf20Sopenharmony_ci if (ret) { 3398c2ecf20Sopenharmony_ci dev_err(&cqspi->pdev->dev, 3408c2ecf20Sopenharmony_ci "Flash command execution timed out.\n"); 3418c2ecf20Sopenharmony_ci return ret; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci /* Polling QSPI idle status. */ 3458c2ecf20Sopenharmony_ci return cqspi_wait_idle(cqspi); 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic int cqspi_command_read(struct cqspi_flash_pdata *f_pdata, 3498c2ecf20Sopenharmony_ci const struct spi_mem_op *op) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct cqspi_st *cqspi = f_pdata->cqspi; 3528c2ecf20Sopenharmony_ci void __iomem *reg_base = cqspi->iobase; 3538c2ecf20Sopenharmony_ci u8 *rxbuf = op->data.buf.in; 3548c2ecf20Sopenharmony_ci u8 opcode = op->cmd.opcode; 3558c2ecf20Sopenharmony_ci size_t n_rx = op->data.nbytes; 3568c2ecf20Sopenharmony_ci unsigned int rdreg; 3578c2ecf20Sopenharmony_ci unsigned int reg; 3588c2ecf20Sopenharmony_ci size_t read_len; 3598c2ecf20Sopenharmony_ci int status; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci if (!n_rx || n_rx > CQSPI_STIG_DATA_LEN_MAX || !rxbuf) { 3628c2ecf20Sopenharmony_ci dev_err(&cqspi->pdev->dev, 3638c2ecf20Sopenharmony_ci "Invalid input argument, len %zu rxbuf 0x%p\n", 3648c2ecf20Sopenharmony_ci n_rx, rxbuf); 3658c2ecf20Sopenharmony_ci return -EINVAL; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci rdreg = cqspi_calc_rdreg(f_pdata); 3718c2ecf20Sopenharmony_ci writel(rdreg, reg_base + CQSPI_REG_RD_INSTR); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* 0 means 1 byte. */ 3768c2ecf20Sopenharmony_ci reg |= (((n_rx - 1) & CQSPI_REG_CMDCTRL_RD_BYTES_MASK) 3778c2ecf20Sopenharmony_ci << CQSPI_REG_CMDCTRL_RD_BYTES_LSB); 3788c2ecf20Sopenharmony_ci status = cqspi_exec_flash_cmd(cqspi, reg); 3798c2ecf20Sopenharmony_ci if (status) 3808c2ecf20Sopenharmony_ci return status; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci reg = readl(reg_base + CQSPI_REG_CMDREADDATALOWER); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* Put the read value into rx_buf */ 3858c2ecf20Sopenharmony_ci read_len = (n_rx > 4) ? 4 : n_rx; 3868c2ecf20Sopenharmony_ci memcpy(rxbuf, ®, read_len); 3878c2ecf20Sopenharmony_ci rxbuf += read_len; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci if (n_rx > 4) { 3908c2ecf20Sopenharmony_ci reg = readl(reg_base + CQSPI_REG_CMDREADDATAUPPER); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci read_len = n_rx - read_len; 3938c2ecf20Sopenharmony_ci memcpy(rxbuf, ®, read_len); 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci return 0; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic int cqspi_command_write(struct cqspi_flash_pdata *f_pdata, 4008c2ecf20Sopenharmony_ci const struct spi_mem_op *op) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci struct cqspi_st *cqspi = f_pdata->cqspi; 4038c2ecf20Sopenharmony_ci void __iomem *reg_base = cqspi->iobase; 4048c2ecf20Sopenharmony_ci const u8 opcode = op->cmd.opcode; 4058c2ecf20Sopenharmony_ci const u8 *txbuf = op->data.buf.out; 4068c2ecf20Sopenharmony_ci size_t n_tx = op->data.nbytes; 4078c2ecf20Sopenharmony_ci unsigned int reg; 4088c2ecf20Sopenharmony_ci unsigned int data; 4098c2ecf20Sopenharmony_ci size_t write_len; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (n_tx > CQSPI_STIG_DATA_LEN_MAX || (n_tx && !txbuf)) { 4128c2ecf20Sopenharmony_ci dev_err(&cqspi->pdev->dev, 4138c2ecf20Sopenharmony_ci "Invalid input argument, cmdlen %zu txbuf 0x%p\n", 4148c2ecf20Sopenharmony_ci n_tx, txbuf); 4158c2ecf20Sopenharmony_ci return -EINVAL; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci if (op->addr.nbytes) { 4218c2ecf20Sopenharmony_ci reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB); 4228c2ecf20Sopenharmony_ci reg |= ((op->addr.nbytes - 1) & 4238c2ecf20Sopenharmony_ci CQSPI_REG_CMDCTRL_ADD_BYTES_MASK) 4248c2ecf20Sopenharmony_ci << CQSPI_REG_CMDCTRL_ADD_BYTES_LSB; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci writel(op->addr.val, reg_base + CQSPI_REG_CMDADDRESS); 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (n_tx) { 4308c2ecf20Sopenharmony_ci reg |= (0x1 << CQSPI_REG_CMDCTRL_WR_EN_LSB); 4318c2ecf20Sopenharmony_ci reg |= ((n_tx - 1) & CQSPI_REG_CMDCTRL_WR_BYTES_MASK) 4328c2ecf20Sopenharmony_ci << CQSPI_REG_CMDCTRL_WR_BYTES_LSB; 4338c2ecf20Sopenharmony_ci data = 0; 4348c2ecf20Sopenharmony_ci write_len = (n_tx > 4) ? 4 : n_tx; 4358c2ecf20Sopenharmony_ci memcpy(&data, txbuf, write_len); 4368c2ecf20Sopenharmony_ci txbuf += write_len; 4378c2ecf20Sopenharmony_ci writel(data, reg_base + CQSPI_REG_CMDWRITEDATALOWER); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci if (n_tx > 4) { 4408c2ecf20Sopenharmony_ci data = 0; 4418c2ecf20Sopenharmony_ci write_len = n_tx - 4; 4428c2ecf20Sopenharmony_ci memcpy(&data, txbuf, write_len); 4438c2ecf20Sopenharmony_ci writel(data, reg_base + CQSPI_REG_CMDWRITEDATAUPPER); 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci return cqspi_exec_flash_cmd(cqspi, reg); 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic int cqspi_read_setup(struct cqspi_flash_pdata *f_pdata, 4518c2ecf20Sopenharmony_ci const struct spi_mem_op *op) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci struct cqspi_st *cqspi = f_pdata->cqspi; 4548c2ecf20Sopenharmony_ci void __iomem *reg_base = cqspi->iobase; 4558c2ecf20Sopenharmony_ci unsigned int dummy_clk = 0; 4568c2ecf20Sopenharmony_ci unsigned int reg; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci reg = op->cmd.opcode << CQSPI_REG_RD_INSTR_OPCODE_LSB; 4598c2ecf20Sopenharmony_ci reg |= cqspi_calc_rdreg(f_pdata); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* Setup dummy clock cycles */ 4628c2ecf20Sopenharmony_ci dummy_clk = op->dummy.nbytes * 8; 4638c2ecf20Sopenharmony_ci if (dummy_clk > CQSPI_DUMMY_CLKS_MAX) 4648c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (dummy_clk) 4678c2ecf20Sopenharmony_ci reg |= (dummy_clk & CQSPI_REG_RD_INSTR_DUMMY_MASK) 4688c2ecf20Sopenharmony_ci << CQSPI_REG_RD_INSTR_DUMMY_LSB; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci writel(reg, reg_base + CQSPI_REG_RD_INSTR); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci /* Set address width */ 4738c2ecf20Sopenharmony_ci reg = readl(reg_base + CQSPI_REG_SIZE); 4748c2ecf20Sopenharmony_ci reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK; 4758c2ecf20Sopenharmony_ci reg |= (op->addr.nbytes - 1); 4768c2ecf20Sopenharmony_ci writel(reg, reg_base + CQSPI_REG_SIZE); 4778c2ecf20Sopenharmony_ci return 0; 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata, 4818c2ecf20Sopenharmony_ci u8 *rxbuf, loff_t from_addr, 4828c2ecf20Sopenharmony_ci const size_t n_rx) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci struct cqspi_st *cqspi = f_pdata->cqspi; 4858c2ecf20Sopenharmony_ci struct device *dev = &cqspi->pdev->dev; 4868c2ecf20Sopenharmony_ci void __iomem *reg_base = cqspi->iobase; 4878c2ecf20Sopenharmony_ci void __iomem *ahb_base = cqspi->ahb_base; 4888c2ecf20Sopenharmony_ci unsigned int remaining = n_rx; 4898c2ecf20Sopenharmony_ci unsigned int mod_bytes = n_rx % 4; 4908c2ecf20Sopenharmony_ci unsigned int bytes_to_read = 0; 4918c2ecf20Sopenharmony_ci u8 *rxbuf_end = rxbuf + n_rx; 4928c2ecf20Sopenharmony_ci int ret = 0; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci writel(from_addr, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR); 4958c2ecf20Sopenharmony_ci writel(remaining, reg_base + CQSPI_REG_INDIRECTRDBYTES); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci /* Clear all interrupts. */ 4988c2ecf20Sopenharmony_ci writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci writel(CQSPI_IRQ_MASK_RD, reg_base + CQSPI_REG_IRQMASK); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci reinit_completion(&cqspi->transfer_complete); 5038c2ecf20Sopenharmony_ci writel(CQSPI_REG_INDIRECTRD_START_MASK, 5048c2ecf20Sopenharmony_ci reg_base + CQSPI_REG_INDIRECTRD); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci while (remaining > 0) { 5078c2ecf20Sopenharmony_ci if (!wait_for_completion_timeout(&cqspi->transfer_complete, 5088c2ecf20Sopenharmony_ci msecs_to_jiffies(CQSPI_READ_TIMEOUT_MS))) 5098c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci bytes_to_read = cqspi_get_rd_sram_level(cqspi); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (ret && bytes_to_read == 0) { 5148c2ecf20Sopenharmony_ci dev_err(dev, "Indirect read timeout, no bytes\n"); 5158c2ecf20Sopenharmony_ci goto failrd; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci while (bytes_to_read != 0) { 5198c2ecf20Sopenharmony_ci unsigned int word_remain = round_down(remaining, 4); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci bytes_to_read *= cqspi->fifo_width; 5228c2ecf20Sopenharmony_ci bytes_to_read = bytes_to_read > remaining ? 5238c2ecf20Sopenharmony_ci remaining : bytes_to_read; 5248c2ecf20Sopenharmony_ci bytes_to_read = round_down(bytes_to_read, 4); 5258c2ecf20Sopenharmony_ci /* Read 4 byte word chunks then single bytes */ 5268c2ecf20Sopenharmony_ci if (bytes_to_read) { 5278c2ecf20Sopenharmony_ci ioread32_rep(ahb_base, rxbuf, 5288c2ecf20Sopenharmony_ci (bytes_to_read / 4)); 5298c2ecf20Sopenharmony_ci } else if (!word_remain && mod_bytes) { 5308c2ecf20Sopenharmony_ci unsigned int temp = ioread32(ahb_base); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci bytes_to_read = mod_bytes; 5338c2ecf20Sopenharmony_ci memcpy(rxbuf, &temp, min((unsigned int) 5348c2ecf20Sopenharmony_ci (rxbuf_end - rxbuf), 5358c2ecf20Sopenharmony_ci bytes_to_read)); 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci rxbuf += bytes_to_read; 5388c2ecf20Sopenharmony_ci remaining -= bytes_to_read; 5398c2ecf20Sopenharmony_ci bytes_to_read = cqspi_get_rd_sram_level(cqspi); 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (remaining > 0) 5438c2ecf20Sopenharmony_ci reinit_completion(&cqspi->transfer_complete); 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci /* Check indirect done status */ 5478c2ecf20Sopenharmony_ci ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_INDIRECTRD, 5488c2ecf20Sopenharmony_ci CQSPI_REG_INDIRECTRD_DONE_MASK, 0); 5498c2ecf20Sopenharmony_ci if (ret) { 5508c2ecf20Sopenharmony_ci dev_err(dev, "Indirect read completion error (%i)\n", ret); 5518c2ecf20Sopenharmony_ci goto failrd; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci /* Disable interrupt */ 5558c2ecf20Sopenharmony_ci writel(0, reg_base + CQSPI_REG_IRQMASK); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci /* Clear indirect completion status */ 5588c2ecf20Sopenharmony_ci writel(CQSPI_REG_INDIRECTRD_DONE_MASK, reg_base + CQSPI_REG_INDIRECTRD); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci return 0; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_cifailrd: 5638c2ecf20Sopenharmony_ci /* Disable interrupt */ 5648c2ecf20Sopenharmony_ci writel(0, reg_base + CQSPI_REG_IRQMASK); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci /* Cancel the indirect read */ 5678c2ecf20Sopenharmony_ci writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK, 5688c2ecf20Sopenharmony_ci reg_base + CQSPI_REG_INDIRECTRD); 5698c2ecf20Sopenharmony_ci return ret; 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic int cqspi_write_setup(struct cqspi_flash_pdata *f_pdata, 5738c2ecf20Sopenharmony_ci const struct spi_mem_op *op) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci unsigned int reg; 5768c2ecf20Sopenharmony_ci struct cqspi_st *cqspi = f_pdata->cqspi; 5778c2ecf20Sopenharmony_ci void __iomem *reg_base = cqspi->iobase; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci /* Set opcode. */ 5808c2ecf20Sopenharmony_ci reg = op->cmd.opcode << CQSPI_REG_WR_INSTR_OPCODE_LSB; 5818c2ecf20Sopenharmony_ci writel(reg, reg_base + CQSPI_REG_WR_INSTR); 5828c2ecf20Sopenharmony_ci reg = cqspi_calc_rdreg(f_pdata); 5838c2ecf20Sopenharmony_ci writel(reg, reg_base + CQSPI_REG_RD_INSTR); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci reg = readl(reg_base + CQSPI_REG_SIZE); 5868c2ecf20Sopenharmony_ci reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK; 5878c2ecf20Sopenharmony_ci reg |= (op->addr.nbytes - 1); 5888c2ecf20Sopenharmony_ci writel(reg, reg_base + CQSPI_REG_SIZE); 5898c2ecf20Sopenharmony_ci return 0; 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_cistatic int cqspi_indirect_write_execute(struct cqspi_flash_pdata *f_pdata, 5938c2ecf20Sopenharmony_ci loff_t to_addr, const u8 *txbuf, 5948c2ecf20Sopenharmony_ci const size_t n_tx) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci struct cqspi_st *cqspi = f_pdata->cqspi; 5978c2ecf20Sopenharmony_ci struct device *dev = &cqspi->pdev->dev; 5988c2ecf20Sopenharmony_ci void __iomem *reg_base = cqspi->iobase; 5998c2ecf20Sopenharmony_ci unsigned int remaining = n_tx; 6008c2ecf20Sopenharmony_ci unsigned int write_bytes; 6018c2ecf20Sopenharmony_ci int ret; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci writel(to_addr, reg_base + CQSPI_REG_INDIRECTWRSTARTADDR); 6048c2ecf20Sopenharmony_ci writel(remaining, reg_base + CQSPI_REG_INDIRECTWRBYTES); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci /* Clear all interrupts. */ 6078c2ecf20Sopenharmony_ci writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci writel(CQSPI_IRQ_MASK_WR, reg_base + CQSPI_REG_IRQMASK); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci reinit_completion(&cqspi->transfer_complete); 6128c2ecf20Sopenharmony_ci writel(CQSPI_REG_INDIRECTWR_START_MASK, 6138c2ecf20Sopenharmony_ci reg_base + CQSPI_REG_INDIRECTWR); 6148c2ecf20Sopenharmony_ci /* 6158c2ecf20Sopenharmony_ci * As per 66AK2G02 TRM SPRUHY8F section 11.15.5.3 Indirect Access 6168c2ecf20Sopenharmony_ci * Controller programming sequence, couple of cycles of 6178c2ecf20Sopenharmony_ci * QSPI_REF_CLK delay is required for the above bit to 6188c2ecf20Sopenharmony_ci * be internally synchronized by the QSPI module. Provide 5 6198c2ecf20Sopenharmony_ci * cycles of delay. 6208c2ecf20Sopenharmony_ci */ 6218c2ecf20Sopenharmony_ci if (cqspi->wr_delay) 6228c2ecf20Sopenharmony_ci ndelay(cqspi->wr_delay); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci while (remaining > 0) { 6258c2ecf20Sopenharmony_ci size_t write_words, mod_bytes; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci write_bytes = remaining; 6288c2ecf20Sopenharmony_ci write_words = write_bytes / 4; 6298c2ecf20Sopenharmony_ci mod_bytes = write_bytes % 4; 6308c2ecf20Sopenharmony_ci /* Write 4 bytes at a time then single bytes. */ 6318c2ecf20Sopenharmony_ci if (write_words) { 6328c2ecf20Sopenharmony_ci iowrite32_rep(cqspi->ahb_base, txbuf, write_words); 6338c2ecf20Sopenharmony_ci txbuf += (write_words * 4); 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci if (mod_bytes) { 6368c2ecf20Sopenharmony_ci unsigned int temp = 0xFFFFFFFF; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci memcpy(&temp, txbuf, mod_bytes); 6398c2ecf20Sopenharmony_ci iowrite32(temp, cqspi->ahb_base); 6408c2ecf20Sopenharmony_ci txbuf += mod_bytes; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci if (!wait_for_completion_timeout(&cqspi->transfer_complete, 6448c2ecf20Sopenharmony_ci msecs_to_jiffies(CQSPI_TIMEOUT_MS))) { 6458c2ecf20Sopenharmony_ci dev_err(dev, "Indirect write timeout\n"); 6468c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 6478c2ecf20Sopenharmony_ci goto failwr; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci remaining -= write_bytes; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci if (remaining > 0) 6538c2ecf20Sopenharmony_ci reinit_completion(&cqspi->transfer_complete); 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci /* Check indirect done status */ 6578c2ecf20Sopenharmony_ci ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_INDIRECTWR, 6588c2ecf20Sopenharmony_ci CQSPI_REG_INDIRECTWR_DONE_MASK, 0); 6598c2ecf20Sopenharmony_ci if (ret) { 6608c2ecf20Sopenharmony_ci dev_err(dev, "Indirect write completion error (%i)\n", ret); 6618c2ecf20Sopenharmony_ci goto failwr; 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci /* Disable interrupt. */ 6658c2ecf20Sopenharmony_ci writel(0, reg_base + CQSPI_REG_IRQMASK); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci /* Clear indirect completion status */ 6688c2ecf20Sopenharmony_ci writel(CQSPI_REG_INDIRECTWR_DONE_MASK, reg_base + CQSPI_REG_INDIRECTWR); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci cqspi_wait_idle(cqspi); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci return 0; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_cifailwr: 6758c2ecf20Sopenharmony_ci /* Disable interrupt. */ 6768c2ecf20Sopenharmony_ci writel(0, reg_base + CQSPI_REG_IRQMASK); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci /* Cancel the indirect write */ 6798c2ecf20Sopenharmony_ci writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK, 6808c2ecf20Sopenharmony_ci reg_base + CQSPI_REG_INDIRECTWR); 6818c2ecf20Sopenharmony_ci return ret; 6828c2ecf20Sopenharmony_ci} 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_cistatic void cqspi_chipselect(struct cqspi_flash_pdata *f_pdata) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci struct cqspi_st *cqspi = f_pdata->cqspi; 6878c2ecf20Sopenharmony_ci void __iomem *reg_base = cqspi->iobase; 6888c2ecf20Sopenharmony_ci unsigned int chip_select = f_pdata->cs; 6898c2ecf20Sopenharmony_ci unsigned int reg; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci reg = readl(reg_base + CQSPI_REG_CONFIG); 6928c2ecf20Sopenharmony_ci if (cqspi->is_decoded_cs) { 6938c2ecf20Sopenharmony_ci reg |= CQSPI_REG_CONFIG_DECODE_MASK; 6948c2ecf20Sopenharmony_ci } else { 6958c2ecf20Sopenharmony_ci reg &= ~CQSPI_REG_CONFIG_DECODE_MASK; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci /* Convert CS if without decoder. 6988c2ecf20Sopenharmony_ci * CS0 to 4b'1110 6998c2ecf20Sopenharmony_ci * CS1 to 4b'1101 7008c2ecf20Sopenharmony_ci * CS2 to 4b'1011 7018c2ecf20Sopenharmony_ci * CS3 to 4b'0111 7028c2ecf20Sopenharmony_ci */ 7038c2ecf20Sopenharmony_ci chip_select = 0xF & ~(1 << chip_select); 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci reg &= ~(CQSPI_REG_CONFIG_CHIPSELECT_MASK 7078c2ecf20Sopenharmony_ci << CQSPI_REG_CONFIG_CHIPSELECT_LSB); 7088c2ecf20Sopenharmony_ci reg |= (chip_select & CQSPI_REG_CONFIG_CHIPSELECT_MASK) 7098c2ecf20Sopenharmony_ci << CQSPI_REG_CONFIG_CHIPSELECT_LSB; 7108c2ecf20Sopenharmony_ci writel(reg, reg_base + CQSPI_REG_CONFIG); 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_cistatic unsigned int calculate_ticks_for_ns(const unsigned int ref_clk_hz, 7148c2ecf20Sopenharmony_ci const unsigned int ns_val) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci unsigned int ticks; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci ticks = ref_clk_hz / 1000; /* kHz */ 7198c2ecf20Sopenharmony_ci ticks = DIV_ROUND_UP(ticks * ns_val, 1000000); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci return ticks; 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_cistatic void cqspi_delay(struct cqspi_flash_pdata *f_pdata) 7258c2ecf20Sopenharmony_ci{ 7268c2ecf20Sopenharmony_ci struct cqspi_st *cqspi = f_pdata->cqspi; 7278c2ecf20Sopenharmony_ci void __iomem *iobase = cqspi->iobase; 7288c2ecf20Sopenharmony_ci const unsigned int ref_clk_hz = cqspi->master_ref_clk_hz; 7298c2ecf20Sopenharmony_ci unsigned int tshsl, tchsh, tslch, tsd2d; 7308c2ecf20Sopenharmony_ci unsigned int reg; 7318c2ecf20Sopenharmony_ci unsigned int tsclk; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci /* calculate the number of ref ticks for one sclk tick */ 7348c2ecf20Sopenharmony_ci tsclk = DIV_ROUND_UP(ref_clk_hz, cqspi->sclk); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci tshsl = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tshsl_ns); 7378c2ecf20Sopenharmony_ci /* this particular value must be at least one sclk */ 7388c2ecf20Sopenharmony_ci if (tshsl < tsclk) 7398c2ecf20Sopenharmony_ci tshsl = tsclk; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci tchsh = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tchsh_ns); 7428c2ecf20Sopenharmony_ci tslch = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tslch_ns); 7438c2ecf20Sopenharmony_ci tsd2d = calculate_ticks_for_ns(ref_clk_hz, f_pdata->tsd2d_ns); 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci reg = (tshsl & CQSPI_REG_DELAY_TSHSL_MASK) 7468c2ecf20Sopenharmony_ci << CQSPI_REG_DELAY_TSHSL_LSB; 7478c2ecf20Sopenharmony_ci reg |= (tchsh & CQSPI_REG_DELAY_TCHSH_MASK) 7488c2ecf20Sopenharmony_ci << CQSPI_REG_DELAY_TCHSH_LSB; 7498c2ecf20Sopenharmony_ci reg |= (tslch & CQSPI_REG_DELAY_TSLCH_MASK) 7508c2ecf20Sopenharmony_ci << CQSPI_REG_DELAY_TSLCH_LSB; 7518c2ecf20Sopenharmony_ci reg |= (tsd2d & CQSPI_REG_DELAY_TSD2D_MASK) 7528c2ecf20Sopenharmony_ci << CQSPI_REG_DELAY_TSD2D_LSB; 7538c2ecf20Sopenharmony_ci writel(reg, iobase + CQSPI_REG_DELAY); 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_cistatic void cqspi_config_baudrate_div(struct cqspi_st *cqspi) 7578c2ecf20Sopenharmony_ci{ 7588c2ecf20Sopenharmony_ci const unsigned int ref_clk_hz = cqspi->master_ref_clk_hz; 7598c2ecf20Sopenharmony_ci void __iomem *reg_base = cqspi->iobase; 7608c2ecf20Sopenharmony_ci u32 reg, div; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci /* Recalculate the baudrate divisor based on QSPI specification. */ 7638c2ecf20Sopenharmony_ci div = DIV_ROUND_UP(ref_clk_hz, 2 * cqspi->sclk) - 1; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci reg = readl(reg_base + CQSPI_REG_CONFIG); 7668c2ecf20Sopenharmony_ci reg &= ~(CQSPI_REG_CONFIG_BAUD_MASK << CQSPI_REG_CONFIG_BAUD_LSB); 7678c2ecf20Sopenharmony_ci reg |= (div & CQSPI_REG_CONFIG_BAUD_MASK) << CQSPI_REG_CONFIG_BAUD_LSB; 7688c2ecf20Sopenharmony_ci writel(reg, reg_base + CQSPI_REG_CONFIG); 7698c2ecf20Sopenharmony_ci} 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_cistatic void cqspi_readdata_capture(struct cqspi_st *cqspi, 7728c2ecf20Sopenharmony_ci const bool bypass, 7738c2ecf20Sopenharmony_ci const unsigned int delay) 7748c2ecf20Sopenharmony_ci{ 7758c2ecf20Sopenharmony_ci void __iomem *reg_base = cqspi->iobase; 7768c2ecf20Sopenharmony_ci unsigned int reg; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci reg = readl(reg_base + CQSPI_REG_READCAPTURE); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci if (bypass) 7818c2ecf20Sopenharmony_ci reg |= (1 << CQSPI_REG_READCAPTURE_BYPASS_LSB); 7828c2ecf20Sopenharmony_ci else 7838c2ecf20Sopenharmony_ci reg &= ~(1 << CQSPI_REG_READCAPTURE_BYPASS_LSB); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci reg &= ~(CQSPI_REG_READCAPTURE_DELAY_MASK 7868c2ecf20Sopenharmony_ci << CQSPI_REG_READCAPTURE_DELAY_LSB); 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci reg |= (delay & CQSPI_REG_READCAPTURE_DELAY_MASK) 7898c2ecf20Sopenharmony_ci << CQSPI_REG_READCAPTURE_DELAY_LSB; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci writel(reg, reg_base + CQSPI_REG_READCAPTURE); 7928c2ecf20Sopenharmony_ci} 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_cistatic void cqspi_controller_enable(struct cqspi_st *cqspi, bool enable) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci void __iomem *reg_base = cqspi->iobase; 7978c2ecf20Sopenharmony_ci unsigned int reg; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci reg = readl(reg_base + CQSPI_REG_CONFIG); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci if (enable) 8028c2ecf20Sopenharmony_ci reg |= CQSPI_REG_CONFIG_ENABLE_MASK; 8038c2ecf20Sopenharmony_ci else 8048c2ecf20Sopenharmony_ci reg &= ~CQSPI_REG_CONFIG_ENABLE_MASK; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci writel(reg, reg_base + CQSPI_REG_CONFIG); 8078c2ecf20Sopenharmony_ci} 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_cistatic void cqspi_configure(struct cqspi_flash_pdata *f_pdata, 8108c2ecf20Sopenharmony_ci unsigned long sclk) 8118c2ecf20Sopenharmony_ci{ 8128c2ecf20Sopenharmony_ci struct cqspi_st *cqspi = f_pdata->cqspi; 8138c2ecf20Sopenharmony_ci int switch_cs = (cqspi->current_cs != f_pdata->cs); 8148c2ecf20Sopenharmony_ci int switch_ck = (cqspi->sclk != sclk); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci if (switch_cs || switch_ck) 8178c2ecf20Sopenharmony_ci cqspi_controller_enable(cqspi, 0); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci /* Switch chip select. */ 8208c2ecf20Sopenharmony_ci if (switch_cs) { 8218c2ecf20Sopenharmony_ci cqspi->current_cs = f_pdata->cs; 8228c2ecf20Sopenharmony_ci cqspi_chipselect(f_pdata); 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci /* Setup baudrate divisor and delays */ 8268c2ecf20Sopenharmony_ci if (switch_ck) { 8278c2ecf20Sopenharmony_ci cqspi->sclk = sclk; 8288c2ecf20Sopenharmony_ci cqspi_config_baudrate_div(cqspi); 8298c2ecf20Sopenharmony_ci cqspi_delay(f_pdata); 8308c2ecf20Sopenharmony_ci cqspi_readdata_capture(cqspi, !cqspi->rclk_en, 8318c2ecf20Sopenharmony_ci f_pdata->read_delay); 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci if (switch_cs || switch_ck) 8358c2ecf20Sopenharmony_ci cqspi_controller_enable(cqspi, 1); 8368c2ecf20Sopenharmony_ci} 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_cistatic int cqspi_set_protocol(struct cqspi_flash_pdata *f_pdata, 8398c2ecf20Sopenharmony_ci const struct spi_mem_op *op) 8408c2ecf20Sopenharmony_ci{ 8418c2ecf20Sopenharmony_ci f_pdata->inst_width = CQSPI_INST_TYPE_SINGLE; 8428c2ecf20Sopenharmony_ci f_pdata->addr_width = CQSPI_INST_TYPE_SINGLE; 8438c2ecf20Sopenharmony_ci f_pdata->data_width = CQSPI_INST_TYPE_SINGLE; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci if (op->data.dir == SPI_MEM_DATA_IN) { 8468c2ecf20Sopenharmony_ci switch (op->data.buswidth) { 8478c2ecf20Sopenharmony_ci case 1: 8488c2ecf20Sopenharmony_ci f_pdata->data_width = CQSPI_INST_TYPE_SINGLE; 8498c2ecf20Sopenharmony_ci break; 8508c2ecf20Sopenharmony_ci case 2: 8518c2ecf20Sopenharmony_ci f_pdata->data_width = CQSPI_INST_TYPE_DUAL; 8528c2ecf20Sopenharmony_ci break; 8538c2ecf20Sopenharmony_ci case 4: 8548c2ecf20Sopenharmony_ci f_pdata->data_width = CQSPI_INST_TYPE_QUAD; 8558c2ecf20Sopenharmony_ci break; 8568c2ecf20Sopenharmony_ci case 8: 8578c2ecf20Sopenharmony_ci f_pdata->data_width = CQSPI_INST_TYPE_OCTAL; 8588c2ecf20Sopenharmony_ci break; 8598c2ecf20Sopenharmony_ci default: 8608c2ecf20Sopenharmony_ci return -EINVAL; 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci return 0; 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_cistatic ssize_t cqspi_write(struct cqspi_flash_pdata *f_pdata, 8688c2ecf20Sopenharmony_ci const struct spi_mem_op *op) 8698c2ecf20Sopenharmony_ci{ 8708c2ecf20Sopenharmony_ci struct cqspi_st *cqspi = f_pdata->cqspi; 8718c2ecf20Sopenharmony_ci loff_t to = op->addr.val; 8728c2ecf20Sopenharmony_ci size_t len = op->data.nbytes; 8738c2ecf20Sopenharmony_ci const u_char *buf = op->data.buf.out; 8748c2ecf20Sopenharmony_ci int ret; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci ret = cqspi_set_protocol(f_pdata, op); 8778c2ecf20Sopenharmony_ci if (ret) 8788c2ecf20Sopenharmony_ci return ret; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci ret = cqspi_write_setup(f_pdata, op); 8818c2ecf20Sopenharmony_ci if (ret) 8828c2ecf20Sopenharmony_ci return ret; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci if (cqspi->use_direct_mode && ((to + len) <= cqspi->ahb_size)) { 8858c2ecf20Sopenharmony_ci memcpy_toio(cqspi->ahb_base + to, buf, len); 8868c2ecf20Sopenharmony_ci return cqspi_wait_idle(cqspi); 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci return cqspi_indirect_write_execute(f_pdata, to, buf, len); 8908c2ecf20Sopenharmony_ci} 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_cistatic void cqspi_rx_dma_callback(void *param) 8938c2ecf20Sopenharmony_ci{ 8948c2ecf20Sopenharmony_ci struct cqspi_st *cqspi = param; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci complete(&cqspi->rx_dma_complete); 8978c2ecf20Sopenharmony_ci} 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_cistatic int cqspi_direct_read_execute(struct cqspi_flash_pdata *f_pdata, 9008c2ecf20Sopenharmony_ci u_char *buf, loff_t from, size_t len) 9018c2ecf20Sopenharmony_ci{ 9028c2ecf20Sopenharmony_ci struct cqspi_st *cqspi = f_pdata->cqspi; 9038c2ecf20Sopenharmony_ci struct device *dev = &cqspi->pdev->dev; 9048c2ecf20Sopenharmony_ci enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; 9058c2ecf20Sopenharmony_ci dma_addr_t dma_src = (dma_addr_t)cqspi->mmap_phys_base + from; 9068c2ecf20Sopenharmony_ci int ret = 0; 9078c2ecf20Sopenharmony_ci struct dma_async_tx_descriptor *tx; 9088c2ecf20Sopenharmony_ci dma_cookie_t cookie; 9098c2ecf20Sopenharmony_ci dma_addr_t dma_dst; 9108c2ecf20Sopenharmony_ci struct device *ddev; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci if (!cqspi->rx_chan || !virt_addr_valid(buf)) { 9138c2ecf20Sopenharmony_ci memcpy_fromio(buf, cqspi->ahb_base + from, len); 9148c2ecf20Sopenharmony_ci return 0; 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci ddev = cqspi->rx_chan->device->dev; 9188c2ecf20Sopenharmony_ci dma_dst = dma_map_single(ddev, buf, len, DMA_FROM_DEVICE); 9198c2ecf20Sopenharmony_ci if (dma_mapping_error(ddev, dma_dst)) { 9208c2ecf20Sopenharmony_ci dev_err(dev, "dma mapping failed\n"); 9218c2ecf20Sopenharmony_ci return -ENOMEM; 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci tx = dmaengine_prep_dma_memcpy(cqspi->rx_chan, dma_dst, dma_src, 9248c2ecf20Sopenharmony_ci len, flags); 9258c2ecf20Sopenharmony_ci if (!tx) { 9268c2ecf20Sopenharmony_ci dev_err(dev, "device_prep_dma_memcpy error\n"); 9278c2ecf20Sopenharmony_ci ret = -EIO; 9288c2ecf20Sopenharmony_ci goto err_unmap; 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci tx->callback = cqspi_rx_dma_callback; 9328c2ecf20Sopenharmony_ci tx->callback_param = cqspi; 9338c2ecf20Sopenharmony_ci cookie = tx->tx_submit(tx); 9348c2ecf20Sopenharmony_ci reinit_completion(&cqspi->rx_dma_complete); 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci ret = dma_submit_error(cookie); 9378c2ecf20Sopenharmony_ci if (ret) { 9388c2ecf20Sopenharmony_ci dev_err(dev, "dma_submit_error %d\n", cookie); 9398c2ecf20Sopenharmony_ci ret = -EIO; 9408c2ecf20Sopenharmony_ci goto err_unmap; 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci dma_async_issue_pending(cqspi->rx_chan); 9448c2ecf20Sopenharmony_ci if (!wait_for_completion_timeout(&cqspi->rx_dma_complete, 9458c2ecf20Sopenharmony_ci msecs_to_jiffies(len))) { 9468c2ecf20Sopenharmony_ci dmaengine_terminate_sync(cqspi->rx_chan); 9478c2ecf20Sopenharmony_ci dev_err(dev, "DMA wait_for_completion_timeout\n"); 9488c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 9498c2ecf20Sopenharmony_ci goto err_unmap; 9508c2ecf20Sopenharmony_ci } 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_cierr_unmap: 9538c2ecf20Sopenharmony_ci dma_unmap_single(ddev, dma_dst, len, DMA_FROM_DEVICE); 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci return ret; 9568c2ecf20Sopenharmony_ci} 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_cistatic ssize_t cqspi_read(struct cqspi_flash_pdata *f_pdata, 9598c2ecf20Sopenharmony_ci const struct spi_mem_op *op) 9608c2ecf20Sopenharmony_ci{ 9618c2ecf20Sopenharmony_ci struct cqspi_st *cqspi = f_pdata->cqspi; 9628c2ecf20Sopenharmony_ci loff_t from = op->addr.val; 9638c2ecf20Sopenharmony_ci size_t len = op->data.nbytes; 9648c2ecf20Sopenharmony_ci u_char *buf = op->data.buf.in; 9658c2ecf20Sopenharmony_ci int ret; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci ret = cqspi_set_protocol(f_pdata, op); 9688c2ecf20Sopenharmony_ci if (ret) 9698c2ecf20Sopenharmony_ci return ret; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci ret = cqspi_read_setup(f_pdata, op); 9728c2ecf20Sopenharmony_ci if (ret) 9738c2ecf20Sopenharmony_ci return ret; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci if (cqspi->use_direct_mode && ((from + len) <= cqspi->ahb_size)) 9768c2ecf20Sopenharmony_ci return cqspi_direct_read_execute(f_pdata, buf, from, len); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci return cqspi_indirect_read_execute(f_pdata, buf, from, len); 9798c2ecf20Sopenharmony_ci} 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_cistatic int cqspi_mem_process(struct spi_mem *mem, const struct spi_mem_op *op) 9828c2ecf20Sopenharmony_ci{ 9838c2ecf20Sopenharmony_ci struct cqspi_st *cqspi = spi_master_get_devdata(mem->spi->master); 9848c2ecf20Sopenharmony_ci struct cqspi_flash_pdata *f_pdata; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci f_pdata = &cqspi->f_pdata[mem->spi->chip_select]; 9878c2ecf20Sopenharmony_ci cqspi_configure(f_pdata, mem->spi->max_speed_hz); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci if (op->data.dir == SPI_MEM_DATA_IN && op->data.buf.in) { 9908c2ecf20Sopenharmony_ci if (!op->addr.nbytes) 9918c2ecf20Sopenharmony_ci return cqspi_command_read(f_pdata, op); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci return cqspi_read(f_pdata, op); 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci if (!op->addr.nbytes || !op->data.buf.out) 9978c2ecf20Sopenharmony_ci return cqspi_command_write(f_pdata, op); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci return cqspi_write(f_pdata, op); 10008c2ecf20Sopenharmony_ci} 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_cistatic int cqspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op) 10038c2ecf20Sopenharmony_ci{ 10048c2ecf20Sopenharmony_ci int ret; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci ret = cqspi_mem_process(mem, op); 10078c2ecf20Sopenharmony_ci if (ret) 10088c2ecf20Sopenharmony_ci dev_err(&mem->spi->dev, "operation failed with %d\n", ret); 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci return ret; 10118c2ecf20Sopenharmony_ci} 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_cistatic int cqspi_of_get_flash_pdata(struct platform_device *pdev, 10148c2ecf20Sopenharmony_ci struct cqspi_flash_pdata *f_pdata, 10158c2ecf20Sopenharmony_ci struct device_node *np) 10168c2ecf20Sopenharmony_ci{ 10178c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "cdns,read-delay", &f_pdata->read_delay)) { 10188c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "couldn't determine read-delay\n"); 10198c2ecf20Sopenharmony_ci return -ENXIO; 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "cdns,tshsl-ns", &f_pdata->tshsl_ns)) { 10238c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "couldn't determine tshsl-ns\n"); 10248c2ecf20Sopenharmony_ci return -ENXIO; 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "cdns,tsd2d-ns", &f_pdata->tsd2d_ns)) { 10288c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "couldn't determine tsd2d-ns\n"); 10298c2ecf20Sopenharmony_ci return -ENXIO; 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "cdns,tchsh-ns", &f_pdata->tchsh_ns)) { 10338c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "couldn't determine tchsh-ns\n"); 10348c2ecf20Sopenharmony_ci return -ENXIO; 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "cdns,tslch-ns", &f_pdata->tslch_ns)) { 10388c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "couldn't determine tslch-ns\n"); 10398c2ecf20Sopenharmony_ci return -ENXIO; 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "spi-max-frequency", &f_pdata->clk_rate)) { 10438c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "couldn't determine spi-max-frequency\n"); 10448c2ecf20Sopenharmony_ci return -ENXIO; 10458c2ecf20Sopenharmony_ci } 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci return 0; 10488c2ecf20Sopenharmony_ci} 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_cistatic int cqspi_of_get_pdata(struct cqspi_st *cqspi) 10518c2ecf20Sopenharmony_ci{ 10528c2ecf20Sopenharmony_ci struct device *dev = &cqspi->pdev->dev; 10538c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci cqspi->is_decoded_cs = of_property_read_bool(np, "cdns,is-decoded-cs"); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "cdns,fifo-depth", &cqspi->fifo_depth)) { 10588c2ecf20Sopenharmony_ci dev_err(dev, "couldn't determine fifo-depth\n"); 10598c2ecf20Sopenharmony_ci return -ENXIO; 10608c2ecf20Sopenharmony_ci } 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "cdns,fifo-width", &cqspi->fifo_width)) { 10638c2ecf20Sopenharmony_ci dev_err(dev, "couldn't determine fifo-width\n"); 10648c2ecf20Sopenharmony_ci return -ENXIO; 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "cdns,trigger-address", 10688c2ecf20Sopenharmony_ci &cqspi->trigger_address)) { 10698c2ecf20Sopenharmony_ci dev_err(dev, "couldn't determine trigger-address\n"); 10708c2ecf20Sopenharmony_ci return -ENXIO; 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci cqspi->rclk_en = of_property_read_bool(np, "cdns,rclk-en"); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci return 0; 10768c2ecf20Sopenharmony_ci} 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_cistatic void cqspi_controller_init(struct cqspi_st *cqspi) 10798c2ecf20Sopenharmony_ci{ 10808c2ecf20Sopenharmony_ci u32 reg; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci cqspi_controller_enable(cqspi, 0); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci /* Configure the remap address register, no remap */ 10858c2ecf20Sopenharmony_ci writel(0, cqspi->iobase + CQSPI_REG_REMAP); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci /* Disable all interrupts. */ 10888c2ecf20Sopenharmony_ci writel(0, cqspi->iobase + CQSPI_REG_IRQMASK); 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci /* Configure the SRAM split to 1:1 . */ 10918c2ecf20Sopenharmony_ci writel(cqspi->fifo_depth / 2, cqspi->iobase + CQSPI_REG_SRAMPARTITION); 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci /* Load indirect trigger address. */ 10948c2ecf20Sopenharmony_ci writel(cqspi->trigger_address, 10958c2ecf20Sopenharmony_ci cqspi->iobase + CQSPI_REG_INDIRECTTRIGGER); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci /* Program read watermark -- 1/2 of the FIFO. */ 10988c2ecf20Sopenharmony_ci writel(cqspi->fifo_depth * cqspi->fifo_width / 2, 10998c2ecf20Sopenharmony_ci cqspi->iobase + CQSPI_REG_INDIRECTRDWATERMARK); 11008c2ecf20Sopenharmony_ci /* Program write watermark -- 1/8 of the FIFO. */ 11018c2ecf20Sopenharmony_ci writel(cqspi->fifo_depth * cqspi->fifo_width / 8, 11028c2ecf20Sopenharmony_ci cqspi->iobase + CQSPI_REG_INDIRECTWRWATERMARK); 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci /* Enable Direct Access Controller */ 11058c2ecf20Sopenharmony_ci reg = readl(cqspi->iobase + CQSPI_REG_CONFIG); 11068c2ecf20Sopenharmony_ci reg |= CQSPI_REG_CONFIG_ENB_DIR_ACC_CTRL; 11078c2ecf20Sopenharmony_ci writel(reg, cqspi->iobase + CQSPI_REG_CONFIG); 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci cqspi_controller_enable(cqspi, 1); 11108c2ecf20Sopenharmony_ci} 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_cistatic int cqspi_request_mmap_dma(struct cqspi_st *cqspi) 11138c2ecf20Sopenharmony_ci{ 11148c2ecf20Sopenharmony_ci dma_cap_mask_t mask; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci dma_cap_zero(mask); 11178c2ecf20Sopenharmony_ci dma_cap_set(DMA_MEMCPY, mask); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci cqspi->rx_chan = dma_request_chan_by_mask(&mask); 11208c2ecf20Sopenharmony_ci if (IS_ERR(cqspi->rx_chan)) { 11218c2ecf20Sopenharmony_ci int ret = PTR_ERR(cqspi->rx_chan); 11228c2ecf20Sopenharmony_ci cqspi->rx_chan = NULL; 11238c2ecf20Sopenharmony_ci return dev_err_probe(&cqspi->pdev->dev, ret, "No Rx DMA available\n"); 11248c2ecf20Sopenharmony_ci } 11258c2ecf20Sopenharmony_ci init_completion(&cqspi->rx_dma_complete); 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci return 0; 11288c2ecf20Sopenharmony_ci} 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_cistatic const char *cqspi_get_name(struct spi_mem *mem) 11318c2ecf20Sopenharmony_ci{ 11328c2ecf20Sopenharmony_ci struct cqspi_st *cqspi = spi_master_get_devdata(mem->spi->master); 11338c2ecf20Sopenharmony_ci struct device *dev = &cqspi->pdev->dev; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci return devm_kasprintf(dev, GFP_KERNEL, "%s.%d", dev_name(dev), mem->spi->chip_select); 11368c2ecf20Sopenharmony_ci} 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_cistatic const struct spi_controller_mem_ops cqspi_mem_ops = { 11398c2ecf20Sopenharmony_ci .exec_op = cqspi_exec_mem_op, 11408c2ecf20Sopenharmony_ci .get_name = cqspi_get_name, 11418c2ecf20Sopenharmony_ci}; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_cistatic int cqspi_setup_flash(struct cqspi_st *cqspi) 11448c2ecf20Sopenharmony_ci{ 11458c2ecf20Sopenharmony_ci struct platform_device *pdev = cqspi->pdev; 11468c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 11478c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 11488c2ecf20Sopenharmony_ci struct cqspi_flash_pdata *f_pdata; 11498c2ecf20Sopenharmony_ci unsigned int cs; 11508c2ecf20Sopenharmony_ci int ret; 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci /* Get flash device data */ 11538c2ecf20Sopenharmony_ci for_each_available_child_of_node(dev->of_node, np) { 11548c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "reg", &cs); 11558c2ecf20Sopenharmony_ci if (ret) { 11568c2ecf20Sopenharmony_ci dev_err(dev, "Couldn't determine chip select.\n"); 11578c2ecf20Sopenharmony_ci return ret; 11588c2ecf20Sopenharmony_ci } 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci if (cs >= CQSPI_MAX_CHIPSELECT) { 11618c2ecf20Sopenharmony_ci dev_err(dev, "Chip select %d out of range.\n", cs); 11628c2ecf20Sopenharmony_ci return -EINVAL; 11638c2ecf20Sopenharmony_ci } 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci f_pdata = &cqspi->f_pdata[cs]; 11668c2ecf20Sopenharmony_ci f_pdata->cqspi = cqspi; 11678c2ecf20Sopenharmony_ci f_pdata->cs = cs; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci ret = cqspi_of_get_flash_pdata(pdev, f_pdata, np); 11708c2ecf20Sopenharmony_ci if (ret) 11718c2ecf20Sopenharmony_ci return ret; 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci return 0; 11758c2ecf20Sopenharmony_ci} 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_cistatic int cqspi_probe(struct platform_device *pdev) 11788c2ecf20Sopenharmony_ci{ 11798c2ecf20Sopenharmony_ci const struct cqspi_driver_platdata *ddata; 11808c2ecf20Sopenharmony_ci struct reset_control *rstc, *rstc_ocp; 11818c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 11828c2ecf20Sopenharmony_ci struct spi_master *master; 11838c2ecf20Sopenharmony_ci struct resource *res_ahb; 11848c2ecf20Sopenharmony_ci struct cqspi_st *cqspi; 11858c2ecf20Sopenharmony_ci struct resource *res; 11868c2ecf20Sopenharmony_ci int ret; 11878c2ecf20Sopenharmony_ci int irq; 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci master = spi_alloc_master(&pdev->dev, sizeof(*cqspi)); 11908c2ecf20Sopenharmony_ci if (!master) { 11918c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "spi_alloc_master failed\n"); 11928c2ecf20Sopenharmony_ci return -ENOMEM; 11938c2ecf20Sopenharmony_ci } 11948c2ecf20Sopenharmony_ci master->mode_bits = SPI_RX_QUAD | SPI_RX_DUAL; 11958c2ecf20Sopenharmony_ci master->mem_ops = &cqspi_mem_ops; 11968c2ecf20Sopenharmony_ci master->dev.of_node = pdev->dev.of_node; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci cqspi = spi_master_get_devdata(master); 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci cqspi->pdev = pdev; 12018c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, cqspi); 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci /* Obtain configuration from OF. */ 12048c2ecf20Sopenharmony_ci ret = cqspi_of_get_pdata(cqspi); 12058c2ecf20Sopenharmony_ci if (ret) { 12068c2ecf20Sopenharmony_ci dev_err(dev, "Cannot get mandatory OF data.\n"); 12078c2ecf20Sopenharmony_ci ret = -ENODEV; 12088c2ecf20Sopenharmony_ci goto probe_master_put; 12098c2ecf20Sopenharmony_ci } 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci /* Obtain QSPI clock. */ 12128c2ecf20Sopenharmony_ci cqspi->clk = devm_clk_get(dev, NULL); 12138c2ecf20Sopenharmony_ci if (IS_ERR(cqspi->clk)) { 12148c2ecf20Sopenharmony_ci dev_err(dev, "Cannot claim QSPI clock.\n"); 12158c2ecf20Sopenharmony_ci ret = PTR_ERR(cqspi->clk); 12168c2ecf20Sopenharmony_ci goto probe_master_put; 12178c2ecf20Sopenharmony_ci } 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci /* Obtain and remap controller address. */ 12208c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 12218c2ecf20Sopenharmony_ci cqspi->iobase = devm_ioremap_resource(dev, res); 12228c2ecf20Sopenharmony_ci if (IS_ERR(cqspi->iobase)) { 12238c2ecf20Sopenharmony_ci dev_err(dev, "Cannot remap controller address.\n"); 12248c2ecf20Sopenharmony_ci ret = PTR_ERR(cqspi->iobase); 12258c2ecf20Sopenharmony_ci goto probe_master_put; 12268c2ecf20Sopenharmony_ci } 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci /* Obtain and remap AHB address. */ 12298c2ecf20Sopenharmony_ci res_ahb = platform_get_resource(pdev, IORESOURCE_MEM, 1); 12308c2ecf20Sopenharmony_ci cqspi->ahb_base = devm_ioremap_resource(dev, res_ahb); 12318c2ecf20Sopenharmony_ci if (IS_ERR(cqspi->ahb_base)) { 12328c2ecf20Sopenharmony_ci dev_err(dev, "Cannot remap AHB address.\n"); 12338c2ecf20Sopenharmony_ci ret = PTR_ERR(cqspi->ahb_base); 12348c2ecf20Sopenharmony_ci goto probe_master_put; 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci cqspi->mmap_phys_base = (dma_addr_t)res_ahb->start; 12378c2ecf20Sopenharmony_ci cqspi->ahb_size = resource_size(res_ahb); 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci init_completion(&cqspi->transfer_complete); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci /* Obtain IRQ line. */ 12428c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 12438c2ecf20Sopenharmony_ci if (irq < 0) { 12448c2ecf20Sopenharmony_ci ret = -ENXIO; 12458c2ecf20Sopenharmony_ci goto probe_master_put; 12468c2ecf20Sopenharmony_ci } 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 12498c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(dev); 12508c2ecf20Sopenharmony_ci if (ret < 0) { 12518c2ecf20Sopenharmony_ci pm_runtime_put_noidle(dev); 12528c2ecf20Sopenharmony_ci goto probe_master_put; 12538c2ecf20Sopenharmony_ci } 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci ret = clk_prepare_enable(cqspi->clk); 12568c2ecf20Sopenharmony_ci if (ret) { 12578c2ecf20Sopenharmony_ci dev_err(dev, "Cannot enable QSPI clock.\n"); 12588c2ecf20Sopenharmony_ci goto probe_clk_failed; 12598c2ecf20Sopenharmony_ci } 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci /* Obtain QSPI reset control */ 12628c2ecf20Sopenharmony_ci rstc = devm_reset_control_get_optional_exclusive(dev, "qspi"); 12638c2ecf20Sopenharmony_ci if (IS_ERR(rstc)) { 12648c2ecf20Sopenharmony_ci ret = PTR_ERR(rstc); 12658c2ecf20Sopenharmony_ci dev_err(dev, "Cannot get QSPI reset.\n"); 12668c2ecf20Sopenharmony_ci goto probe_reset_failed; 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci rstc_ocp = devm_reset_control_get_optional_exclusive(dev, "qspi-ocp"); 12708c2ecf20Sopenharmony_ci if (IS_ERR(rstc_ocp)) { 12718c2ecf20Sopenharmony_ci ret = PTR_ERR(rstc_ocp); 12728c2ecf20Sopenharmony_ci dev_err(dev, "Cannot get QSPI OCP reset.\n"); 12738c2ecf20Sopenharmony_ci goto probe_reset_failed; 12748c2ecf20Sopenharmony_ci } 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci reset_control_assert(rstc); 12778c2ecf20Sopenharmony_ci reset_control_deassert(rstc); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci reset_control_assert(rstc_ocp); 12808c2ecf20Sopenharmony_ci reset_control_deassert(rstc_ocp); 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci cqspi->master_ref_clk_hz = clk_get_rate(cqspi->clk); 12838c2ecf20Sopenharmony_ci ddata = of_device_get_match_data(dev); 12848c2ecf20Sopenharmony_ci if (ddata) { 12858c2ecf20Sopenharmony_ci if (ddata->quirks & CQSPI_NEEDS_WR_DELAY) 12868c2ecf20Sopenharmony_ci cqspi->wr_delay = 5 * DIV_ROUND_UP(NSEC_PER_SEC, 12878c2ecf20Sopenharmony_ci cqspi->master_ref_clk_hz); 12888c2ecf20Sopenharmony_ci if (ddata->hwcaps_mask & CQSPI_SUPPORTS_OCTAL) 12898c2ecf20Sopenharmony_ci master->mode_bits |= SPI_RX_OCTAL; 12908c2ecf20Sopenharmony_ci if (!(ddata->quirks & CQSPI_DISABLE_DAC_MODE)) 12918c2ecf20Sopenharmony_ci cqspi->use_direct_mode = true; 12928c2ecf20Sopenharmony_ci } 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci ret = devm_request_irq(dev, irq, cqspi_irq_handler, 0, 12958c2ecf20Sopenharmony_ci pdev->name, cqspi); 12968c2ecf20Sopenharmony_ci if (ret) { 12978c2ecf20Sopenharmony_ci dev_err(dev, "Cannot request IRQ.\n"); 12988c2ecf20Sopenharmony_ci goto probe_reset_failed; 12998c2ecf20Sopenharmony_ci } 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci cqspi_wait_idle(cqspi); 13028c2ecf20Sopenharmony_ci cqspi_controller_init(cqspi); 13038c2ecf20Sopenharmony_ci cqspi->current_cs = -1; 13048c2ecf20Sopenharmony_ci cqspi->sclk = 0; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci ret = cqspi_setup_flash(cqspi); 13078c2ecf20Sopenharmony_ci if (ret) { 13088c2ecf20Sopenharmony_ci dev_err(dev, "failed to setup flash parameters %d\n", ret); 13098c2ecf20Sopenharmony_ci goto probe_setup_failed; 13108c2ecf20Sopenharmony_ci } 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci if (cqspi->use_direct_mode) { 13138c2ecf20Sopenharmony_ci ret = cqspi_request_mmap_dma(cqspi); 13148c2ecf20Sopenharmony_ci if (ret == -EPROBE_DEFER) 13158c2ecf20Sopenharmony_ci goto probe_setup_failed; 13168c2ecf20Sopenharmony_ci } 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci ret = devm_spi_register_master(dev, master); 13198c2ecf20Sopenharmony_ci if (ret) { 13208c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to register SPI ctlr %d\n", ret); 13218c2ecf20Sopenharmony_ci goto probe_setup_failed; 13228c2ecf20Sopenharmony_ci } 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci return 0; 13258c2ecf20Sopenharmony_ciprobe_setup_failed: 13268c2ecf20Sopenharmony_ci cqspi_controller_enable(cqspi, 0); 13278c2ecf20Sopenharmony_ciprobe_reset_failed: 13288c2ecf20Sopenharmony_ci clk_disable_unprepare(cqspi->clk); 13298c2ecf20Sopenharmony_ciprobe_clk_failed: 13308c2ecf20Sopenharmony_ci pm_runtime_put_sync(dev); 13318c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 13328c2ecf20Sopenharmony_ciprobe_master_put: 13338c2ecf20Sopenharmony_ci spi_master_put(master); 13348c2ecf20Sopenharmony_ci return ret; 13358c2ecf20Sopenharmony_ci} 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_cistatic int cqspi_remove(struct platform_device *pdev) 13388c2ecf20Sopenharmony_ci{ 13398c2ecf20Sopenharmony_ci struct cqspi_st *cqspi = platform_get_drvdata(pdev); 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci cqspi_controller_enable(cqspi, 0); 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci if (cqspi->rx_chan) 13448c2ecf20Sopenharmony_ci dma_release_channel(cqspi->rx_chan); 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci clk_disable_unprepare(cqspi->clk); 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci pm_runtime_put_sync(&pdev->dev); 13498c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci return 0; 13528c2ecf20Sopenharmony_ci} 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 13558c2ecf20Sopenharmony_cistatic int cqspi_suspend(struct device *dev) 13568c2ecf20Sopenharmony_ci{ 13578c2ecf20Sopenharmony_ci struct cqspi_st *cqspi = dev_get_drvdata(dev); 13588c2ecf20Sopenharmony_ci struct spi_master *master = dev_get_drvdata(dev); 13598c2ecf20Sopenharmony_ci int ret; 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci ret = spi_master_suspend(master); 13628c2ecf20Sopenharmony_ci cqspi_controller_enable(cqspi, 0); 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci clk_disable_unprepare(cqspi->clk); 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci return ret; 13678c2ecf20Sopenharmony_ci} 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_cistatic int cqspi_resume(struct device *dev) 13708c2ecf20Sopenharmony_ci{ 13718c2ecf20Sopenharmony_ci struct cqspi_st *cqspi = dev_get_drvdata(dev); 13728c2ecf20Sopenharmony_ci struct spi_master *master = dev_get_drvdata(dev); 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci clk_prepare_enable(cqspi->clk); 13758c2ecf20Sopenharmony_ci cqspi_wait_idle(cqspi); 13768c2ecf20Sopenharmony_ci cqspi_controller_init(cqspi); 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci cqspi->current_cs = -1; 13798c2ecf20Sopenharmony_ci cqspi->sclk = 0; 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci return spi_master_resume(master); 13828c2ecf20Sopenharmony_ci} 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_cistatic const struct dev_pm_ops cqspi__dev_pm_ops = { 13858c2ecf20Sopenharmony_ci .suspend = cqspi_suspend, 13868c2ecf20Sopenharmony_ci .resume = cqspi_resume, 13878c2ecf20Sopenharmony_ci}; 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci#define CQSPI_DEV_PM_OPS (&cqspi__dev_pm_ops) 13908c2ecf20Sopenharmony_ci#else 13918c2ecf20Sopenharmony_ci#define CQSPI_DEV_PM_OPS NULL 13928c2ecf20Sopenharmony_ci#endif 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_cistatic const struct cqspi_driver_platdata cdns_qspi = { 13958c2ecf20Sopenharmony_ci .quirks = CQSPI_DISABLE_DAC_MODE, 13968c2ecf20Sopenharmony_ci}; 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_cistatic const struct cqspi_driver_platdata k2g_qspi = { 13998c2ecf20Sopenharmony_ci .quirks = CQSPI_NEEDS_WR_DELAY, 14008c2ecf20Sopenharmony_ci}; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_cistatic const struct cqspi_driver_platdata am654_ospi = { 14038c2ecf20Sopenharmony_ci .hwcaps_mask = CQSPI_SUPPORTS_OCTAL, 14048c2ecf20Sopenharmony_ci .quirks = CQSPI_NEEDS_WR_DELAY, 14058c2ecf20Sopenharmony_ci}; 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_cistatic const struct of_device_id cqspi_dt_ids[] = { 14088c2ecf20Sopenharmony_ci { 14098c2ecf20Sopenharmony_ci .compatible = "cdns,qspi-nor", 14108c2ecf20Sopenharmony_ci .data = &cdns_qspi, 14118c2ecf20Sopenharmony_ci }, 14128c2ecf20Sopenharmony_ci { 14138c2ecf20Sopenharmony_ci .compatible = "ti,k2g-qspi", 14148c2ecf20Sopenharmony_ci .data = &k2g_qspi, 14158c2ecf20Sopenharmony_ci }, 14168c2ecf20Sopenharmony_ci { 14178c2ecf20Sopenharmony_ci .compatible = "ti,am654-ospi", 14188c2ecf20Sopenharmony_ci .data = &am654_ospi, 14198c2ecf20Sopenharmony_ci }, 14208c2ecf20Sopenharmony_ci { /* end of table */ } 14218c2ecf20Sopenharmony_ci}; 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, cqspi_dt_ids); 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_cistatic struct platform_driver cqspi_platform_driver = { 14268c2ecf20Sopenharmony_ci .probe = cqspi_probe, 14278c2ecf20Sopenharmony_ci .remove = cqspi_remove, 14288c2ecf20Sopenharmony_ci .driver = { 14298c2ecf20Sopenharmony_ci .name = CQSPI_NAME, 14308c2ecf20Sopenharmony_ci .pm = CQSPI_DEV_PM_OPS, 14318c2ecf20Sopenharmony_ci .of_match_table = cqspi_dt_ids, 14328c2ecf20Sopenharmony_ci }, 14338c2ecf20Sopenharmony_ci}; 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_cimodule_platform_driver(cqspi_platform_driver); 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Cadence QSPI Controller Driver"); 14388c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 14398c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:" CQSPI_NAME); 14408c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ley Foon Tan <lftan@altera.com>"); 14418c2ecf20Sopenharmony_ciMODULE_AUTHOR("Graham Moore <grmoore@opensource.altera.com>"); 14428c2ecf20Sopenharmony_ciMODULE_AUTHOR("Vadivel Murugan R <vadivel.muruganx.ramuthevar@intel.com>"); 14438c2ecf20Sopenharmony_ciMODULE_AUTHOR("Vignesh Raghavendra <vigneshr@ti.com>"); 1444