18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Driver for Broadcom BRCMSTB, NSP,  NS2, Cygnus SPI Controllers
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2016 Broadcom
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/clk.h>
98c2ecf20Sopenharmony_ci#include <linux/delay.h>
108c2ecf20Sopenharmony_ci#include <linux/device.h>
118c2ecf20Sopenharmony_ci#include <linux/init.h>
128c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
138c2ecf20Sopenharmony_ci#include <linux/io.h>
148c2ecf20Sopenharmony_ci#include <linux/ioport.h>
158c2ecf20Sopenharmony_ci#include <linux/kernel.h>
168c2ecf20Sopenharmony_ci#include <linux/module.h>
178c2ecf20Sopenharmony_ci#include <linux/of.h>
188c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
198c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
208c2ecf20Sopenharmony_ci#include <linux/slab.h>
218c2ecf20Sopenharmony_ci#include <linux/spi/spi.h>
228c2ecf20Sopenharmony_ci#include <linux/mtd/spi-nor.h>
238c2ecf20Sopenharmony_ci#include <linux/sysfs.h>
248c2ecf20Sopenharmony_ci#include <linux/types.h>
258c2ecf20Sopenharmony_ci#include "spi-bcm-qspi.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define DRIVER_NAME "bcm_qspi"
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/* BSPI register offsets */
318c2ecf20Sopenharmony_ci#define BSPI_REVISION_ID			0x000
328c2ecf20Sopenharmony_ci#define BSPI_SCRATCH				0x004
338c2ecf20Sopenharmony_ci#define BSPI_MAST_N_BOOT_CTRL			0x008
348c2ecf20Sopenharmony_ci#define BSPI_BUSY_STATUS			0x00c
358c2ecf20Sopenharmony_ci#define BSPI_INTR_STATUS			0x010
368c2ecf20Sopenharmony_ci#define BSPI_B0_STATUS				0x014
378c2ecf20Sopenharmony_ci#define BSPI_B0_CTRL				0x018
388c2ecf20Sopenharmony_ci#define BSPI_B1_STATUS				0x01c
398c2ecf20Sopenharmony_ci#define BSPI_B1_CTRL				0x020
408c2ecf20Sopenharmony_ci#define BSPI_STRAP_OVERRIDE_CTRL		0x024
418c2ecf20Sopenharmony_ci#define BSPI_FLEX_MODE_ENABLE			0x028
428c2ecf20Sopenharmony_ci#define BSPI_BITS_PER_CYCLE			0x02c
438c2ecf20Sopenharmony_ci#define BSPI_BITS_PER_PHASE			0x030
448c2ecf20Sopenharmony_ci#define BSPI_CMD_AND_MODE_BYTE			0x034
458c2ecf20Sopenharmony_ci#define BSPI_BSPI_FLASH_UPPER_ADDR_BYTE	0x038
468c2ecf20Sopenharmony_ci#define BSPI_BSPI_XOR_VALUE			0x03c
478c2ecf20Sopenharmony_ci#define BSPI_BSPI_XOR_ENABLE			0x040
488c2ecf20Sopenharmony_ci#define BSPI_BSPI_PIO_MODE_ENABLE		0x044
498c2ecf20Sopenharmony_ci#define BSPI_BSPI_PIO_IODIR			0x048
508c2ecf20Sopenharmony_ci#define BSPI_BSPI_PIO_DATA			0x04c
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/* RAF register offsets */
538c2ecf20Sopenharmony_ci#define BSPI_RAF_START_ADDR			0x100
548c2ecf20Sopenharmony_ci#define BSPI_RAF_NUM_WORDS			0x104
558c2ecf20Sopenharmony_ci#define BSPI_RAF_CTRL				0x108
568c2ecf20Sopenharmony_ci#define BSPI_RAF_FULLNESS			0x10c
578c2ecf20Sopenharmony_ci#define BSPI_RAF_WATERMARK			0x110
588c2ecf20Sopenharmony_ci#define BSPI_RAF_STATUS			0x114
598c2ecf20Sopenharmony_ci#define BSPI_RAF_READ_DATA			0x118
608c2ecf20Sopenharmony_ci#define BSPI_RAF_WORD_CNT			0x11c
618c2ecf20Sopenharmony_ci#define BSPI_RAF_CURR_ADDR			0x120
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/* Override mode masks */
648c2ecf20Sopenharmony_ci#define BSPI_STRAP_OVERRIDE_CTRL_OVERRIDE	BIT(0)
658c2ecf20Sopenharmony_ci#define BSPI_STRAP_OVERRIDE_CTRL_DATA_DUAL	BIT(1)
668c2ecf20Sopenharmony_ci#define BSPI_STRAP_OVERRIDE_CTRL_ADDR_4BYTE	BIT(2)
678c2ecf20Sopenharmony_ci#define BSPI_STRAP_OVERRIDE_CTRL_DATA_QUAD	BIT(3)
688c2ecf20Sopenharmony_ci#define BSPI_STRAP_OVERRIDE_CTRL_ENDAIN_MODE	BIT(4)
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci#define BSPI_ADDRLEN_3BYTES			3
718c2ecf20Sopenharmony_ci#define BSPI_ADDRLEN_4BYTES			4
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci#define BSPI_RAF_STATUS_FIFO_EMPTY_MASK	BIT(1)
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci#define BSPI_RAF_CTRL_START_MASK		BIT(0)
768c2ecf20Sopenharmony_ci#define BSPI_RAF_CTRL_CLEAR_MASK		BIT(1)
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci#define BSPI_BPP_MODE_SELECT_MASK		BIT(8)
798c2ecf20Sopenharmony_ci#define BSPI_BPP_ADDR_SELECT_MASK		BIT(16)
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci#define BSPI_READ_LENGTH			256
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci/* MSPI register offsets */
848c2ecf20Sopenharmony_ci#define MSPI_SPCR0_LSB				0x000
858c2ecf20Sopenharmony_ci#define MSPI_SPCR0_MSB				0x004
868c2ecf20Sopenharmony_ci#define MSPI_SPCR1_LSB				0x008
878c2ecf20Sopenharmony_ci#define MSPI_SPCR1_MSB				0x00c
888c2ecf20Sopenharmony_ci#define MSPI_NEWQP				0x010
898c2ecf20Sopenharmony_ci#define MSPI_ENDQP				0x014
908c2ecf20Sopenharmony_ci#define MSPI_SPCR2				0x018
918c2ecf20Sopenharmony_ci#define MSPI_MSPI_STATUS			0x020
928c2ecf20Sopenharmony_ci#define MSPI_CPTQP				0x024
938c2ecf20Sopenharmony_ci#define MSPI_SPCR3				0x028
948c2ecf20Sopenharmony_ci#define MSPI_REV				0x02c
958c2ecf20Sopenharmony_ci#define MSPI_TXRAM				0x040
968c2ecf20Sopenharmony_ci#define MSPI_RXRAM				0x0c0
978c2ecf20Sopenharmony_ci#define MSPI_CDRAM				0x140
988c2ecf20Sopenharmony_ci#define MSPI_WRITE_LOCK			0x180
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci#define MSPI_MASTER_BIT			BIT(7)
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci#define MSPI_NUM_CDRAM				16
1038c2ecf20Sopenharmony_ci#define MSPI_CDRAM_CONT_BIT			BIT(7)
1048c2ecf20Sopenharmony_ci#define MSPI_CDRAM_BITSE_BIT			BIT(6)
1058c2ecf20Sopenharmony_ci#define MSPI_CDRAM_PCS				0xf
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci#define MSPI_SPCR2_SPE				BIT(6)
1088c2ecf20Sopenharmony_ci#define MSPI_SPCR2_CONT_AFTER_CMD		BIT(7)
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci#define MSPI_SPCR3_FASTBR			BIT(0)
1118c2ecf20Sopenharmony_ci#define MSPI_SPCR3_FASTDT			BIT(1)
1128c2ecf20Sopenharmony_ci#define MSPI_SPCR3_SYSCLKSEL_MASK		GENMASK(11, 10)
1138c2ecf20Sopenharmony_ci#define MSPI_SPCR3_SYSCLKSEL_27			(MSPI_SPCR3_SYSCLKSEL_MASK & \
1148c2ecf20Sopenharmony_ci						 ~(BIT(10) | BIT(11)))
1158c2ecf20Sopenharmony_ci#define MSPI_SPCR3_SYSCLKSEL_108		(MSPI_SPCR3_SYSCLKSEL_MASK & \
1168c2ecf20Sopenharmony_ci						 BIT(11))
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci#define MSPI_MSPI_STATUS_SPIF			BIT(0)
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci#define INTR_BASE_BIT_SHIFT			0x02
1218c2ecf20Sopenharmony_ci#define INTR_COUNT				0x07
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci#define NUM_CHIPSELECT				4
1248c2ecf20Sopenharmony_ci#define QSPI_SPBR_MAX				255U
1258c2ecf20Sopenharmony_ci#define MSPI_BASE_FREQ				27000000UL
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci#define OPCODE_DIOR				0xBB
1288c2ecf20Sopenharmony_ci#define OPCODE_QIOR				0xEB
1298c2ecf20Sopenharmony_ci#define OPCODE_DIOR_4B				0xBC
1308c2ecf20Sopenharmony_ci#define OPCODE_QIOR_4B				0xEC
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci#define MAX_CMD_SIZE				6
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci#define ADDR_4MB_MASK				GENMASK(22, 0)
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci/* stop at end of transfer, no other reason */
1378c2ecf20Sopenharmony_ci#define TRANS_STATUS_BREAK_NONE		0
1388c2ecf20Sopenharmony_ci/* stop at end of spi_message */
1398c2ecf20Sopenharmony_ci#define TRANS_STATUS_BREAK_EOM			1
1408c2ecf20Sopenharmony_ci/* stop at end of spi_transfer if delay */
1418c2ecf20Sopenharmony_ci#define TRANS_STATUS_BREAK_DELAY		2
1428c2ecf20Sopenharmony_ci/* stop at end of spi_transfer if cs_change */
1438c2ecf20Sopenharmony_ci#define TRANS_STATUS_BREAK_CS_CHANGE		4
1448c2ecf20Sopenharmony_ci/* stop if we run out of bytes */
1458c2ecf20Sopenharmony_ci#define TRANS_STATUS_BREAK_NO_BYTES		8
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci/* events that make us stop filling TX slots */
1488c2ecf20Sopenharmony_ci#define TRANS_STATUS_BREAK_TX (TRANS_STATUS_BREAK_EOM |		\
1498c2ecf20Sopenharmony_ci			       TRANS_STATUS_BREAK_DELAY |		\
1508c2ecf20Sopenharmony_ci			       TRANS_STATUS_BREAK_CS_CHANGE)
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci/* events that make us deassert CS */
1538c2ecf20Sopenharmony_ci#define TRANS_STATUS_BREAK_DESELECT (TRANS_STATUS_BREAK_EOM |		\
1548c2ecf20Sopenharmony_ci				     TRANS_STATUS_BREAK_CS_CHANGE)
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistruct bcm_qspi_parms {
1578c2ecf20Sopenharmony_ci	u32 speed_hz;
1588c2ecf20Sopenharmony_ci	u8 mode;
1598c2ecf20Sopenharmony_ci	u8 bits_per_word;
1608c2ecf20Sopenharmony_ci};
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistruct bcm_xfer_mode {
1638c2ecf20Sopenharmony_ci	bool flex_mode;
1648c2ecf20Sopenharmony_ci	unsigned int width;
1658c2ecf20Sopenharmony_ci	unsigned int addrlen;
1668c2ecf20Sopenharmony_ci	unsigned int hp;
1678c2ecf20Sopenharmony_ci};
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cienum base_type {
1708c2ecf20Sopenharmony_ci	MSPI,
1718c2ecf20Sopenharmony_ci	BSPI,
1728c2ecf20Sopenharmony_ci	CHIP_SELECT,
1738c2ecf20Sopenharmony_ci	BASEMAX,
1748c2ecf20Sopenharmony_ci};
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cienum irq_source {
1778c2ecf20Sopenharmony_ci	SINGLE_L2,
1788c2ecf20Sopenharmony_ci	MUXED_L1,
1798c2ecf20Sopenharmony_ci};
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistruct bcm_qspi_irq {
1828c2ecf20Sopenharmony_ci	const char *irq_name;
1838c2ecf20Sopenharmony_ci	const irq_handler_t irq_handler;
1848c2ecf20Sopenharmony_ci	int irq_source;
1858c2ecf20Sopenharmony_ci	u32 mask;
1868c2ecf20Sopenharmony_ci};
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistruct bcm_qspi_dev_id {
1898c2ecf20Sopenharmony_ci	const struct bcm_qspi_irq *irqp;
1908c2ecf20Sopenharmony_ci	void *dev;
1918c2ecf20Sopenharmony_ci};
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistruct qspi_trans {
1958c2ecf20Sopenharmony_ci	struct spi_transfer *trans;
1968c2ecf20Sopenharmony_ci	int byte;
1978c2ecf20Sopenharmony_ci	bool mspi_last_trans;
1988c2ecf20Sopenharmony_ci};
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistruct bcm_qspi {
2018c2ecf20Sopenharmony_ci	struct platform_device *pdev;
2028c2ecf20Sopenharmony_ci	struct spi_master *master;
2038c2ecf20Sopenharmony_ci	struct clk *clk;
2048c2ecf20Sopenharmony_ci	u32 base_clk;
2058c2ecf20Sopenharmony_ci	u32 max_speed_hz;
2068c2ecf20Sopenharmony_ci	void __iomem *base[BASEMAX];
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	/* Some SoCs provide custom interrupt status register(s) */
2098c2ecf20Sopenharmony_ci	struct bcm_qspi_soc_intc	*soc_intc;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	struct bcm_qspi_parms last_parms;
2128c2ecf20Sopenharmony_ci	struct qspi_trans  trans_pos;
2138c2ecf20Sopenharmony_ci	int curr_cs;
2148c2ecf20Sopenharmony_ci	int bspi_maj_rev;
2158c2ecf20Sopenharmony_ci	int bspi_min_rev;
2168c2ecf20Sopenharmony_ci	int bspi_enabled;
2178c2ecf20Sopenharmony_ci	const struct spi_mem_op *bspi_rf_op;
2188c2ecf20Sopenharmony_ci	u32 bspi_rf_op_idx;
2198c2ecf20Sopenharmony_ci	u32 bspi_rf_op_len;
2208c2ecf20Sopenharmony_ci	u32 bspi_rf_op_status;
2218c2ecf20Sopenharmony_ci	struct bcm_xfer_mode xfer_mode;
2228c2ecf20Sopenharmony_ci	u32 s3_strap_override_ctrl;
2238c2ecf20Sopenharmony_ci	bool bspi_mode;
2248c2ecf20Sopenharmony_ci	bool big_endian;
2258c2ecf20Sopenharmony_ci	int num_irqs;
2268c2ecf20Sopenharmony_ci	struct bcm_qspi_dev_id *dev_ids;
2278c2ecf20Sopenharmony_ci	struct completion mspi_done;
2288c2ecf20Sopenharmony_ci	struct completion bspi_done;
2298c2ecf20Sopenharmony_ci	u8 mspi_maj_rev;
2308c2ecf20Sopenharmony_ci	u8 mspi_min_rev;
2318c2ecf20Sopenharmony_ci	bool mspi_spcr3_sysclk;
2328c2ecf20Sopenharmony_ci};
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_cistatic inline bool has_bspi(struct bcm_qspi *qspi)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	return qspi->bspi_mode;
2378c2ecf20Sopenharmony_ci}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci/* hardware supports spcr3 and fast baud-rate  */
2408c2ecf20Sopenharmony_cistatic inline bool bcm_qspi_has_fastbr(struct bcm_qspi *qspi)
2418c2ecf20Sopenharmony_ci{
2428c2ecf20Sopenharmony_ci	if (!has_bspi(qspi) &&
2438c2ecf20Sopenharmony_ci	    ((qspi->mspi_maj_rev >= 1) &&
2448c2ecf20Sopenharmony_ci	     (qspi->mspi_min_rev >= 5)))
2458c2ecf20Sopenharmony_ci		return true;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	return false;
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci/* hardware supports sys clk 108Mhz  */
2518c2ecf20Sopenharmony_cistatic inline bool bcm_qspi_has_sysclk_108(struct bcm_qspi *qspi)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	if (!has_bspi(qspi) && (qspi->mspi_spcr3_sysclk ||
2548c2ecf20Sopenharmony_ci	    ((qspi->mspi_maj_rev >= 1) &&
2558c2ecf20Sopenharmony_ci	     (qspi->mspi_min_rev >= 6))))
2568c2ecf20Sopenharmony_ci		return true;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	return false;
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic inline int bcm_qspi_spbr_min(struct bcm_qspi *qspi)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	if (bcm_qspi_has_fastbr(qspi))
2648c2ecf20Sopenharmony_ci		return 1;
2658c2ecf20Sopenharmony_ci	else
2668c2ecf20Sopenharmony_ci		return 8;
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci/* Read qspi controller register*/
2708c2ecf20Sopenharmony_cistatic inline u32 bcm_qspi_read(struct bcm_qspi *qspi, enum base_type type,
2718c2ecf20Sopenharmony_ci				unsigned int offset)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	return bcm_qspi_readl(qspi->big_endian, qspi->base[type] + offset);
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci/* Write qspi controller register*/
2778c2ecf20Sopenharmony_cistatic inline void bcm_qspi_write(struct bcm_qspi *qspi, enum base_type type,
2788c2ecf20Sopenharmony_ci				  unsigned int offset, unsigned int data)
2798c2ecf20Sopenharmony_ci{
2808c2ecf20Sopenharmony_ci	bcm_qspi_writel(qspi->big_endian, data, qspi->base[type] + offset);
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci/* BSPI helpers */
2848c2ecf20Sopenharmony_cistatic int bcm_qspi_bspi_busy_poll(struct bcm_qspi *qspi)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	int i;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	/* this should normally finish within 10us */
2898c2ecf20Sopenharmony_ci	for (i = 0; i < 1000; i++) {
2908c2ecf20Sopenharmony_ci		if (!(bcm_qspi_read(qspi, BSPI, BSPI_BUSY_STATUS) & 1))
2918c2ecf20Sopenharmony_ci			return 0;
2928c2ecf20Sopenharmony_ci		udelay(1);
2938c2ecf20Sopenharmony_ci	}
2948c2ecf20Sopenharmony_ci	dev_warn(&qspi->pdev->dev, "timeout waiting for !busy_status\n");
2958c2ecf20Sopenharmony_ci	return -EIO;
2968c2ecf20Sopenharmony_ci}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_cistatic inline bool bcm_qspi_bspi_ver_three(struct bcm_qspi *qspi)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	if (qspi->bspi_maj_rev < 4)
3018c2ecf20Sopenharmony_ci		return true;
3028c2ecf20Sopenharmony_ci	return false;
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_cistatic void bcm_qspi_bspi_flush_prefetch_buffers(struct bcm_qspi *qspi)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	bcm_qspi_bspi_busy_poll(qspi);
3088c2ecf20Sopenharmony_ci	/* Force rising edge for the b0/b1 'flush' field */
3098c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, BSPI, BSPI_B0_CTRL, 1);
3108c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, BSPI, BSPI_B1_CTRL, 1);
3118c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, BSPI, BSPI_B0_CTRL, 0);
3128c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, BSPI, BSPI_B1_CTRL, 0);
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_cistatic int bcm_qspi_bspi_lr_is_fifo_empty(struct bcm_qspi *qspi)
3168c2ecf20Sopenharmony_ci{
3178c2ecf20Sopenharmony_ci	return (bcm_qspi_read(qspi, BSPI, BSPI_RAF_STATUS) &
3188c2ecf20Sopenharmony_ci				BSPI_RAF_STATUS_FIFO_EMPTY_MASK);
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic inline u32 bcm_qspi_bspi_lr_read_fifo(struct bcm_qspi *qspi)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	u32 data = bcm_qspi_read(qspi, BSPI, BSPI_RAF_READ_DATA);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	/* BSPI v3 LR is LE only, convert data to host endianness */
3268c2ecf20Sopenharmony_ci	if (bcm_qspi_bspi_ver_three(qspi))
3278c2ecf20Sopenharmony_ci		data = le32_to_cpu(data);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	return data;
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cistatic inline void bcm_qspi_bspi_lr_start(struct bcm_qspi *qspi)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	bcm_qspi_bspi_busy_poll(qspi);
3358c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, BSPI, BSPI_RAF_CTRL,
3368c2ecf20Sopenharmony_ci		       BSPI_RAF_CTRL_START_MASK);
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistatic inline void bcm_qspi_bspi_lr_clear(struct bcm_qspi *qspi)
3408c2ecf20Sopenharmony_ci{
3418c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, BSPI, BSPI_RAF_CTRL,
3428c2ecf20Sopenharmony_ci		       BSPI_RAF_CTRL_CLEAR_MASK);
3438c2ecf20Sopenharmony_ci	bcm_qspi_bspi_flush_prefetch_buffers(qspi);
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic void bcm_qspi_bspi_lr_data_read(struct bcm_qspi *qspi)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	u32 *buf = (u32 *)qspi->bspi_rf_op->data.buf.in;
3498c2ecf20Sopenharmony_ci	u32 data = 0;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	dev_dbg(&qspi->pdev->dev, "xfer %p rx %p rxlen %d\n", qspi->bspi_rf_op,
3528c2ecf20Sopenharmony_ci		qspi->bspi_rf_op->data.buf.in, qspi->bspi_rf_op_len);
3538c2ecf20Sopenharmony_ci	while (!bcm_qspi_bspi_lr_is_fifo_empty(qspi)) {
3548c2ecf20Sopenharmony_ci		data = bcm_qspi_bspi_lr_read_fifo(qspi);
3558c2ecf20Sopenharmony_ci		if (likely(qspi->bspi_rf_op_len >= 4) &&
3568c2ecf20Sopenharmony_ci		    IS_ALIGNED((uintptr_t)buf, 4)) {
3578c2ecf20Sopenharmony_ci			buf[qspi->bspi_rf_op_idx++] = data;
3588c2ecf20Sopenharmony_ci			qspi->bspi_rf_op_len -= 4;
3598c2ecf20Sopenharmony_ci		} else {
3608c2ecf20Sopenharmony_ci			/* Read out remaining bytes, make sure*/
3618c2ecf20Sopenharmony_ci			u8 *cbuf = (u8 *)&buf[qspi->bspi_rf_op_idx];
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci			data = cpu_to_le32(data);
3648c2ecf20Sopenharmony_ci			while (qspi->bspi_rf_op_len) {
3658c2ecf20Sopenharmony_ci				*cbuf++ = (u8)data;
3668c2ecf20Sopenharmony_ci				data >>= 8;
3678c2ecf20Sopenharmony_ci				qspi->bspi_rf_op_len--;
3688c2ecf20Sopenharmony_ci			}
3698c2ecf20Sopenharmony_ci		}
3708c2ecf20Sopenharmony_ci	}
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_cistatic void bcm_qspi_bspi_set_xfer_params(struct bcm_qspi *qspi, u8 cmd_byte,
3748c2ecf20Sopenharmony_ci					  int bpp, int bpc, int flex_mode)
3758c2ecf20Sopenharmony_ci{
3768c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, BSPI, BSPI_FLEX_MODE_ENABLE, 0);
3778c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, BSPI, BSPI_BITS_PER_CYCLE, bpc);
3788c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, BSPI, BSPI_BITS_PER_PHASE, bpp);
3798c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, BSPI, BSPI_CMD_AND_MODE_BYTE, cmd_byte);
3808c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, BSPI, BSPI_FLEX_MODE_ENABLE, flex_mode);
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistatic int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi,
3848c2ecf20Sopenharmony_ci				       const struct spi_mem_op *op, int hp)
3858c2ecf20Sopenharmony_ci{
3868c2ecf20Sopenharmony_ci	int bpc = 0, bpp = 0;
3878c2ecf20Sopenharmony_ci	u8 command = op->cmd.opcode;
3888c2ecf20Sopenharmony_ci	int width = op->data.buswidth ? op->data.buswidth : SPI_NBITS_SINGLE;
3898c2ecf20Sopenharmony_ci	int addrlen = op->addr.nbytes;
3908c2ecf20Sopenharmony_ci	int flex_mode = 1;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	dev_dbg(&qspi->pdev->dev, "set flex mode w %x addrlen %x hp %d\n",
3938c2ecf20Sopenharmony_ci		width, addrlen, hp);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	if (addrlen == BSPI_ADDRLEN_4BYTES)
3968c2ecf20Sopenharmony_ci		bpp = BSPI_BPP_ADDR_SELECT_MASK;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	bpp |= (op->dummy.nbytes * 8) / op->dummy.buswidth;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	switch (width) {
4018c2ecf20Sopenharmony_ci	case SPI_NBITS_SINGLE:
4028c2ecf20Sopenharmony_ci		if (addrlen == BSPI_ADDRLEN_3BYTES)
4038c2ecf20Sopenharmony_ci			/* default mode, does not need flex_cmd */
4048c2ecf20Sopenharmony_ci			flex_mode = 0;
4058c2ecf20Sopenharmony_ci		break;
4068c2ecf20Sopenharmony_ci	case SPI_NBITS_DUAL:
4078c2ecf20Sopenharmony_ci		bpc = 0x00000001;
4088c2ecf20Sopenharmony_ci		if (hp) {
4098c2ecf20Sopenharmony_ci			bpc |= 0x00010100; /* address and mode are 2-bit */
4108c2ecf20Sopenharmony_ci			bpp = BSPI_BPP_MODE_SELECT_MASK;
4118c2ecf20Sopenharmony_ci		}
4128c2ecf20Sopenharmony_ci		break;
4138c2ecf20Sopenharmony_ci	case SPI_NBITS_QUAD:
4148c2ecf20Sopenharmony_ci		bpc = 0x00000002;
4158c2ecf20Sopenharmony_ci		if (hp) {
4168c2ecf20Sopenharmony_ci			bpc |= 0x00020200; /* address and mode are 4-bit */
4178c2ecf20Sopenharmony_ci			bpp |= BSPI_BPP_MODE_SELECT_MASK;
4188c2ecf20Sopenharmony_ci		}
4198c2ecf20Sopenharmony_ci		break;
4208c2ecf20Sopenharmony_ci	default:
4218c2ecf20Sopenharmony_ci		return -EINVAL;
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	bcm_qspi_bspi_set_xfer_params(qspi, command, bpp, bpc, flex_mode);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	return 0;
4278c2ecf20Sopenharmony_ci}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_cistatic int bcm_qspi_bspi_set_override(struct bcm_qspi *qspi,
4308c2ecf20Sopenharmony_ci				      const struct spi_mem_op *op, int hp)
4318c2ecf20Sopenharmony_ci{
4328c2ecf20Sopenharmony_ci	int width = op->data.buswidth ? op->data.buswidth : SPI_NBITS_SINGLE;
4338c2ecf20Sopenharmony_ci	int addrlen = op->addr.nbytes;
4348c2ecf20Sopenharmony_ci	u32 data = bcm_qspi_read(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL);
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	dev_dbg(&qspi->pdev->dev, "set override mode w %x addrlen %x hp %d\n",
4378c2ecf20Sopenharmony_ci		width, addrlen, hp);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	switch (width) {
4408c2ecf20Sopenharmony_ci	case SPI_NBITS_SINGLE:
4418c2ecf20Sopenharmony_ci		/* clear quad/dual mode */
4428c2ecf20Sopenharmony_ci		data &= ~(BSPI_STRAP_OVERRIDE_CTRL_DATA_QUAD |
4438c2ecf20Sopenharmony_ci			  BSPI_STRAP_OVERRIDE_CTRL_DATA_DUAL);
4448c2ecf20Sopenharmony_ci		break;
4458c2ecf20Sopenharmony_ci	case SPI_NBITS_QUAD:
4468c2ecf20Sopenharmony_ci		/* clear dual mode and set quad mode */
4478c2ecf20Sopenharmony_ci		data &= ~BSPI_STRAP_OVERRIDE_CTRL_DATA_DUAL;
4488c2ecf20Sopenharmony_ci		data |= BSPI_STRAP_OVERRIDE_CTRL_DATA_QUAD;
4498c2ecf20Sopenharmony_ci		break;
4508c2ecf20Sopenharmony_ci	case SPI_NBITS_DUAL:
4518c2ecf20Sopenharmony_ci		/* clear quad mode set dual mode */
4528c2ecf20Sopenharmony_ci		data &= ~BSPI_STRAP_OVERRIDE_CTRL_DATA_QUAD;
4538c2ecf20Sopenharmony_ci		data |= BSPI_STRAP_OVERRIDE_CTRL_DATA_DUAL;
4548c2ecf20Sopenharmony_ci		break;
4558c2ecf20Sopenharmony_ci	default:
4568c2ecf20Sopenharmony_ci		return -EINVAL;
4578c2ecf20Sopenharmony_ci	}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	if (addrlen == BSPI_ADDRLEN_4BYTES)
4608c2ecf20Sopenharmony_ci		/* set 4byte mode*/
4618c2ecf20Sopenharmony_ci		data |= BSPI_STRAP_OVERRIDE_CTRL_ADDR_4BYTE;
4628c2ecf20Sopenharmony_ci	else
4638c2ecf20Sopenharmony_ci		/* clear 4 byte mode */
4648c2ecf20Sopenharmony_ci		data &= ~BSPI_STRAP_OVERRIDE_CTRL_ADDR_4BYTE;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	/* set the override mode */
4678c2ecf20Sopenharmony_ci	data |=	BSPI_STRAP_OVERRIDE_CTRL_OVERRIDE;
4688c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL, data);
4698c2ecf20Sopenharmony_ci	bcm_qspi_bspi_set_xfer_params(qspi, op->cmd.opcode, 0, 0, 0);
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	return 0;
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_cistatic int bcm_qspi_bspi_set_mode(struct bcm_qspi *qspi,
4758c2ecf20Sopenharmony_ci				  const struct spi_mem_op *op, int hp)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	int error = 0;
4788c2ecf20Sopenharmony_ci	int width = op->data.buswidth ? op->data.buswidth : SPI_NBITS_SINGLE;
4798c2ecf20Sopenharmony_ci	int addrlen = op->addr.nbytes;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	/* default mode */
4828c2ecf20Sopenharmony_ci	qspi->xfer_mode.flex_mode = true;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	if (!bcm_qspi_bspi_ver_three(qspi)) {
4858c2ecf20Sopenharmony_ci		u32 val, mask;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci		val = bcm_qspi_read(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL);
4888c2ecf20Sopenharmony_ci		mask = BSPI_STRAP_OVERRIDE_CTRL_OVERRIDE;
4898c2ecf20Sopenharmony_ci		if (val & mask || qspi->s3_strap_override_ctrl & mask) {
4908c2ecf20Sopenharmony_ci			qspi->xfer_mode.flex_mode = false;
4918c2ecf20Sopenharmony_ci			bcm_qspi_write(qspi, BSPI, BSPI_FLEX_MODE_ENABLE, 0);
4928c2ecf20Sopenharmony_ci			error = bcm_qspi_bspi_set_override(qspi, op, hp);
4938c2ecf20Sopenharmony_ci		}
4948c2ecf20Sopenharmony_ci	}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	if (qspi->xfer_mode.flex_mode)
4978c2ecf20Sopenharmony_ci		error = bcm_qspi_bspi_set_flex_mode(qspi, op, hp);
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	if (error) {
5008c2ecf20Sopenharmony_ci		dev_warn(&qspi->pdev->dev,
5018c2ecf20Sopenharmony_ci			 "INVALID COMBINATION: width=%d addrlen=%d hp=%d\n",
5028c2ecf20Sopenharmony_ci			 width, addrlen, hp);
5038c2ecf20Sopenharmony_ci	} else if (qspi->xfer_mode.width != width ||
5048c2ecf20Sopenharmony_ci		   qspi->xfer_mode.addrlen != addrlen ||
5058c2ecf20Sopenharmony_ci		   qspi->xfer_mode.hp != hp) {
5068c2ecf20Sopenharmony_ci		qspi->xfer_mode.width = width;
5078c2ecf20Sopenharmony_ci		qspi->xfer_mode.addrlen = addrlen;
5088c2ecf20Sopenharmony_ci		qspi->xfer_mode.hp = hp;
5098c2ecf20Sopenharmony_ci		dev_dbg(&qspi->pdev->dev,
5108c2ecf20Sopenharmony_ci			"cs:%d %d-lane output, %d-byte address%s\n",
5118c2ecf20Sopenharmony_ci			qspi->curr_cs,
5128c2ecf20Sopenharmony_ci			qspi->xfer_mode.width,
5138c2ecf20Sopenharmony_ci			qspi->xfer_mode.addrlen,
5148c2ecf20Sopenharmony_ci			qspi->xfer_mode.hp != -1 ? ", hp mode" : "");
5158c2ecf20Sopenharmony_ci	}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	return error;
5188c2ecf20Sopenharmony_ci}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_cistatic void bcm_qspi_enable_bspi(struct bcm_qspi *qspi)
5218c2ecf20Sopenharmony_ci{
5228c2ecf20Sopenharmony_ci	if (!has_bspi(qspi))
5238c2ecf20Sopenharmony_ci		return;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	qspi->bspi_enabled = 1;
5268c2ecf20Sopenharmony_ci	if ((bcm_qspi_read(qspi, BSPI, BSPI_MAST_N_BOOT_CTRL) & 1) == 0)
5278c2ecf20Sopenharmony_ci		return;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	bcm_qspi_bspi_flush_prefetch_buffers(qspi);
5308c2ecf20Sopenharmony_ci	udelay(1);
5318c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, BSPI, BSPI_MAST_N_BOOT_CTRL, 0);
5328c2ecf20Sopenharmony_ci	udelay(1);
5338c2ecf20Sopenharmony_ci}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_cistatic void bcm_qspi_disable_bspi(struct bcm_qspi *qspi)
5368c2ecf20Sopenharmony_ci{
5378c2ecf20Sopenharmony_ci	if (!has_bspi(qspi))
5388c2ecf20Sopenharmony_ci		return;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	qspi->bspi_enabled = 0;
5418c2ecf20Sopenharmony_ci	if ((bcm_qspi_read(qspi, BSPI, BSPI_MAST_N_BOOT_CTRL) & 1))
5428c2ecf20Sopenharmony_ci		return;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	bcm_qspi_bspi_busy_poll(qspi);
5458c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, BSPI, BSPI_MAST_N_BOOT_CTRL, 1);
5468c2ecf20Sopenharmony_ci	udelay(1);
5478c2ecf20Sopenharmony_ci}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_cistatic void bcm_qspi_chip_select(struct bcm_qspi *qspi, int cs)
5508c2ecf20Sopenharmony_ci{
5518c2ecf20Sopenharmony_ci	u32 rd = 0;
5528c2ecf20Sopenharmony_ci	u32 wr = 0;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	if (cs >= 0 && qspi->base[CHIP_SELECT]) {
5558c2ecf20Sopenharmony_ci		rd = bcm_qspi_read(qspi, CHIP_SELECT, 0);
5568c2ecf20Sopenharmony_ci		wr = (rd & ~0xff) | (1 << cs);
5578c2ecf20Sopenharmony_ci		if (rd == wr)
5588c2ecf20Sopenharmony_ci			return;
5598c2ecf20Sopenharmony_ci		bcm_qspi_write(qspi, CHIP_SELECT, 0, wr);
5608c2ecf20Sopenharmony_ci		usleep_range(10, 20);
5618c2ecf20Sopenharmony_ci	}
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	dev_dbg(&qspi->pdev->dev, "using cs:%d\n", cs);
5648c2ecf20Sopenharmony_ci	qspi->curr_cs = cs;
5658c2ecf20Sopenharmony_ci}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci/* MSPI helpers */
5688c2ecf20Sopenharmony_cistatic void bcm_qspi_hw_set_parms(struct bcm_qspi *qspi,
5698c2ecf20Sopenharmony_ci				  const struct bcm_qspi_parms *xp)
5708c2ecf20Sopenharmony_ci{
5718c2ecf20Sopenharmony_ci	u32 spcr, spbr = 0;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	if (xp->speed_hz)
5748c2ecf20Sopenharmony_ci		spbr = qspi->base_clk / (2 * xp->speed_hz);
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	spcr = clamp_val(spbr, bcm_qspi_spbr_min(qspi), QSPI_SPBR_MAX);
5778c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, MSPI, MSPI_SPCR0_LSB, spcr);
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	if (!qspi->mspi_maj_rev)
5808c2ecf20Sopenharmony_ci		/* legacy controller */
5818c2ecf20Sopenharmony_ci		spcr = MSPI_MASTER_BIT;
5828c2ecf20Sopenharmony_ci	else
5838c2ecf20Sopenharmony_ci		spcr = 0;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	/* for 16 bit the data should be zero */
5868c2ecf20Sopenharmony_ci	if (xp->bits_per_word != 16)
5878c2ecf20Sopenharmony_ci		spcr |= xp->bits_per_word << 2;
5888c2ecf20Sopenharmony_ci	spcr |= xp->mode & 3;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, MSPI, MSPI_SPCR0_MSB, spcr);
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	if (bcm_qspi_has_fastbr(qspi)) {
5938c2ecf20Sopenharmony_ci		spcr = 0;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci		/* enable fastbr */
5968c2ecf20Sopenharmony_ci		spcr |=	MSPI_SPCR3_FASTBR;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci		if (bcm_qspi_has_sysclk_108(qspi)) {
5998c2ecf20Sopenharmony_ci			/* SYSCLK_108 */
6008c2ecf20Sopenharmony_ci			spcr |= MSPI_SPCR3_SYSCLKSEL_108;
6018c2ecf20Sopenharmony_ci			qspi->base_clk = MSPI_BASE_FREQ * 4;
6028c2ecf20Sopenharmony_ci			/* Change spbr as we changed sysclk */
6038c2ecf20Sopenharmony_ci			bcm_qspi_write(qspi, MSPI, MSPI_SPCR0_LSB, 4);
6048c2ecf20Sopenharmony_ci		}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci		bcm_qspi_write(qspi, MSPI, MSPI_SPCR3, spcr);
6078c2ecf20Sopenharmony_ci	}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	qspi->last_parms = *xp;
6108c2ecf20Sopenharmony_ci}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_cistatic void bcm_qspi_update_parms(struct bcm_qspi *qspi,
6138c2ecf20Sopenharmony_ci				  struct spi_device *spi,
6148c2ecf20Sopenharmony_ci				  struct spi_transfer *trans)
6158c2ecf20Sopenharmony_ci{
6168c2ecf20Sopenharmony_ci	struct bcm_qspi_parms xp;
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	xp.speed_hz = trans->speed_hz;
6198c2ecf20Sopenharmony_ci	xp.bits_per_word = trans->bits_per_word;
6208c2ecf20Sopenharmony_ci	xp.mode = spi->mode;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	bcm_qspi_hw_set_parms(qspi, &xp);
6238c2ecf20Sopenharmony_ci}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_cistatic int bcm_qspi_setup(struct spi_device *spi)
6268c2ecf20Sopenharmony_ci{
6278c2ecf20Sopenharmony_ci	struct bcm_qspi_parms *xp;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	if (spi->bits_per_word > 16)
6308c2ecf20Sopenharmony_ci		return -EINVAL;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	xp = spi_get_ctldata(spi);
6338c2ecf20Sopenharmony_ci	if (!xp) {
6348c2ecf20Sopenharmony_ci		xp = kzalloc(sizeof(*xp), GFP_KERNEL);
6358c2ecf20Sopenharmony_ci		if (!xp)
6368c2ecf20Sopenharmony_ci			return -ENOMEM;
6378c2ecf20Sopenharmony_ci		spi_set_ctldata(spi, xp);
6388c2ecf20Sopenharmony_ci	}
6398c2ecf20Sopenharmony_ci	xp->speed_hz = spi->max_speed_hz;
6408c2ecf20Sopenharmony_ci	xp->mode = spi->mode;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	if (spi->bits_per_word)
6438c2ecf20Sopenharmony_ci		xp->bits_per_word = spi->bits_per_word;
6448c2ecf20Sopenharmony_ci	else
6458c2ecf20Sopenharmony_ci		xp->bits_per_word = 8;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	return 0;
6488c2ecf20Sopenharmony_ci}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_cistatic bool bcm_qspi_mspi_transfer_is_last(struct bcm_qspi *qspi,
6518c2ecf20Sopenharmony_ci					   struct qspi_trans *qt)
6528c2ecf20Sopenharmony_ci{
6538c2ecf20Sopenharmony_ci	if (qt->mspi_last_trans &&
6548c2ecf20Sopenharmony_ci	    spi_transfer_is_last(qspi->master, qt->trans))
6558c2ecf20Sopenharmony_ci		return true;
6568c2ecf20Sopenharmony_ci	else
6578c2ecf20Sopenharmony_ci		return false;
6588c2ecf20Sopenharmony_ci}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_cistatic int update_qspi_trans_byte_count(struct bcm_qspi *qspi,
6618c2ecf20Sopenharmony_ci					struct qspi_trans *qt, int flags)
6628c2ecf20Sopenharmony_ci{
6638c2ecf20Sopenharmony_ci	int ret = TRANS_STATUS_BREAK_NONE;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	/* count the last transferred bytes */
6668c2ecf20Sopenharmony_ci	if (qt->trans->bits_per_word <= 8)
6678c2ecf20Sopenharmony_ci		qt->byte++;
6688c2ecf20Sopenharmony_ci	else
6698c2ecf20Sopenharmony_ci		qt->byte += 2;
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	if (qt->byte >= qt->trans->len) {
6728c2ecf20Sopenharmony_ci		/* we're at the end of the spi_transfer */
6738c2ecf20Sopenharmony_ci		/* in TX mode, need to pause for a delay or CS change */
6748c2ecf20Sopenharmony_ci		if (qt->trans->delay_usecs &&
6758c2ecf20Sopenharmony_ci		    (flags & TRANS_STATUS_BREAK_DELAY))
6768c2ecf20Sopenharmony_ci			ret |= TRANS_STATUS_BREAK_DELAY;
6778c2ecf20Sopenharmony_ci		if (qt->trans->cs_change &&
6788c2ecf20Sopenharmony_ci		    (flags & TRANS_STATUS_BREAK_CS_CHANGE))
6798c2ecf20Sopenharmony_ci			ret |= TRANS_STATUS_BREAK_CS_CHANGE;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci		if (bcm_qspi_mspi_transfer_is_last(qspi, qt))
6828c2ecf20Sopenharmony_ci			ret |= TRANS_STATUS_BREAK_EOM;
6838c2ecf20Sopenharmony_ci		else
6848c2ecf20Sopenharmony_ci			ret |= TRANS_STATUS_BREAK_NO_BYTES;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci		qt->trans = NULL;
6878c2ecf20Sopenharmony_ci	}
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	dev_dbg(&qspi->pdev->dev, "trans %p len %d byte %d ret %x\n",
6908c2ecf20Sopenharmony_ci		qt->trans, qt->trans ? qt->trans->len : 0, qt->byte, ret);
6918c2ecf20Sopenharmony_ci	return ret;
6928c2ecf20Sopenharmony_ci}
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_cistatic inline u8 read_rxram_slot_u8(struct bcm_qspi *qspi, int slot)
6958c2ecf20Sopenharmony_ci{
6968c2ecf20Sopenharmony_ci	u32 slot_offset = MSPI_RXRAM + (slot << 3) + 0x4;
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	/* mask out reserved bits */
6998c2ecf20Sopenharmony_ci	return bcm_qspi_read(qspi, MSPI, slot_offset) & 0xff;
7008c2ecf20Sopenharmony_ci}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_cistatic inline u16 read_rxram_slot_u16(struct bcm_qspi *qspi, int slot)
7038c2ecf20Sopenharmony_ci{
7048c2ecf20Sopenharmony_ci	u32 reg_offset = MSPI_RXRAM;
7058c2ecf20Sopenharmony_ci	u32 lsb_offset = reg_offset + (slot << 3) + 0x4;
7068c2ecf20Sopenharmony_ci	u32 msb_offset = reg_offset + (slot << 3);
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	return (bcm_qspi_read(qspi, MSPI, lsb_offset) & 0xff) |
7098c2ecf20Sopenharmony_ci		((bcm_qspi_read(qspi, MSPI, msb_offset) & 0xff) << 8);
7108c2ecf20Sopenharmony_ci}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_cistatic void read_from_hw(struct bcm_qspi *qspi, int slots)
7138c2ecf20Sopenharmony_ci{
7148c2ecf20Sopenharmony_ci	struct qspi_trans tp;
7158c2ecf20Sopenharmony_ci	int slot;
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	bcm_qspi_disable_bspi(qspi);
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	if (slots > MSPI_NUM_CDRAM) {
7208c2ecf20Sopenharmony_ci		/* should never happen */
7218c2ecf20Sopenharmony_ci		dev_err(&qspi->pdev->dev, "%s: too many slots!\n", __func__);
7228c2ecf20Sopenharmony_ci		return;
7238c2ecf20Sopenharmony_ci	}
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	tp = qspi->trans_pos;
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	for (slot = 0; slot < slots; slot++) {
7288c2ecf20Sopenharmony_ci		if (tp.trans->bits_per_word <= 8) {
7298c2ecf20Sopenharmony_ci			u8 *buf = tp.trans->rx_buf;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci			if (buf)
7328c2ecf20Sopenharmony_ci				buf[tp.byte] = read_rxram_slot_u8(qspi, slot);
7338c2ecf20Sopenharmony_ci			dev_dbg(&qspi->pdev->dev, "RD %02x\n",
7348c2ecf20Sopenharmony_ci				buf ? buf[tp.byte] : 0x0);
7358c2ecf20Sopenharmony_ci		} else {
7368c2ecf20Sopenharmony_ci			u16 *buf = tp.trans->rx_buf;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci			if (buf)
7398c2ecf20Sopenharmony_ci				buf[tp.byte / 2] = read_rxram_slot_u16(qspi,
7408c2ecf20Sopenharmony_ci								      slot);
7418c2ecf20Sopenharmony_ci			dev_dbg(&qspi->pdev->dev, "RD %04x\n",
7428c2ecf20Sopenharmony_ci				buf ? buf[tp.byte / 2] : 0x0);
7438c2ecf20Sopenharmony_ci		}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci		update_qspi_trans_byte_count(qspi, &tp,
7468c2ecf20Sopenharmony_ci					     TRANS_STATUS_BREAK_NONE);
7478c2ecf20Sopenharmony_ci	}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	qspi->trans_pos = tp;
7508c2ecf20Sopenharmony_ci}
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_cistatic inline void write_txram_slot_u8(struct bcm_qspi *qspi, int slot,
7538c2ecf20Sopenharmony_ci				       u8 val)
7548c2ecf20Sopenharmony_ci{
7558c2ecf20Sopenharmony_ci	u32 reg_offset = MSPI_TXRAM + (slot << 3);
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	/* mask out reserved bits */
7588c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, MSPI, reg_offset, val);
7598c2ecf20Sopenharmony_ci}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_cistatic inline void write_txram_slot_u16(struct bcm_qspi *qspi, int slot,
7628c2ecf20Sopenharmony_ci					u16 val)
7638c2ecf20Sopenharmony_ci{
7648c2ecf20Sopenharmony_ci	u32 reg_offset = MSPI_TXRAM;
7658c2ecf20Sopenharmony_ci	u32 msb_offset = reg_offset + (slot << 3);
7668c2ecf20Sopenharmony_ci	u32 lsb_offset = reg_offset + (slot << 3) + 0x4;
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, MSPI, msb_offset, (val >> 8));
7698c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, MSPI, lsb_offset, (val & 0xff));
7708c2ecf20Sopenharmony_ci}
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_cistatic inline u32 read_cdram_slot(struct bcm_qspi *qspi, int slot)
7738c2ecf20Sopenharmony_ci{
7748c2ecf20Sopenharmony_ci	return bcm_qspi_read(qspi, MSPI, MSPI_CDRAM + (slot << 2));
7758c2ecf20Sopenharmony_ci}
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_cistatic inline void write_cdram_slot(struct bcm_qspi *qspi, int slot, u32 val)
7788c2ecf20Sopenharmony_ci{
7798c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, MSPI, (MSPI_CDRAM + (slot << 2)), val);
7808c2ecf20Sopenharmony_ci}
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci/* Return number of slots written */
7838c2ecf20Sopenharmony_cistatic int write_to_hw(struct bcm_qspi *qspi, struct spi_device *spi)
7848c2ecf20Sopenharmony_ci{
7858c2ecf20Sopenharmony_ci	struct qspi_trans tp;
7868c2ecf20Sopenharmony_ci	int slot = 0, tstatus = 0;
7878c2ecf20Sopenharmony_ci	u32 mspi_cdram = 0;
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	bcm_qspi_disable_bspi(qspi);
7908c2ecf20Sopenharmony_ci	tp = qspi->trans_pos;
7918c2ecf20Sopenharmony_ci	bcm_qspi_update_parms(qspi, spi, tp.trans);
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	/* Run until end of transfer or reached the max data */
7948c2ecf20Sopenharmony_ci	while (!tstatus && slot < MSPI_NUM_CDRAM) {
7958c2ecf20Sopenharmony_ci		if (tp.trans->bits_per_word <= 8) {
7968c2ecf20Sopenharmony_ci			const u8 *buf = tp.trans->tx_buf;
7978c2ecf20Sopenharmony_ci			u8 val = buf ? buf[tp.byte] : 0x00;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci			write_txram_slot_u8(qspi, slot, val);
8008c2ecf20Sopenharmony_ci			dev_dbg(&qspi->pdev->dev, "WR %02x\n", val);
8018c2ecf20Sopenharmony_ci		} else {
8028c2ecf20Sopenharmony_ci			const u16 *buf = tp.trans->tx_buf;
8038c2ecf20Sopenharmony_ci			u16 val = buf ? buf[tp.byte / 2] : 0x0000;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci			write_txram_slot_u16(qspi, slot, val);
8068c2ecf20Sopenharmony_ci			dev_dbg(&qspi->pdev->dev, "WR %04x\n", val);
8078c2ecf20Sopenharmony_ci		}
8088c2ecf20Sopenharmony_ci		mspi_cdram = MSPI_CDRAM_CONT_BIT;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci		if (has_bspi(qspi))
8118c2ecf20Sopenharmony_ci			mspi_cdram &= ~1;
8128c2ecf20Sopenharmony_ci		else
8138c2ecf20Sopenharmony_ci			mspi_cdram |= (~(1 << spi->chip_select) &
8148c2ecf20Sopenharmony_ci				       MSPI_CDRAM_PCS);
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci		mspi_cdram |= ((tp.trans->bits_per_word <= 8) ? 0 :
8178c2ecf20Sopenharmony_ci				MSPI_CDRAM_BITSE_BIT);
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci		write_cdram_slot(qspi, slot, mspi_cdram);
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci		tstatus = update_qspi_trans_byte_count(qspi, &tp,
8228c2ecf20Sopenharmony_ci						       TRANS_STATUS_BREAK_TX);
8238c2ecf20Sopenharmony_ci		slot++;
8248c2ecf20Sopenharmony_ci	}
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	if (!slot) {
8278c2ecf20Sopenharmony_ci		dev_err(&qspi->pdev->dev, "%s: no data to send?", __func__);
8288c2ecf20Sopenharmony_ci		goto done;
8298c2ecf20Sopenharmony_ci	}
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	dev_dbg(&qspi->pdev->dev, "submitting %d slots\n", slot);
8328c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, MSPI, MSPI_NEWQP, 0);
8338c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, MSPI, MSPI_ENDQP, slot - 1);
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	/*
8368c2ecf20Sopenharmony_ci	 *  case 1) EOM =1, cs_change =0: SSb inactive
8378c2ecf20Sopenharmony_ci	 *  case 2) EOM =1, cs_change =1: SSb stay active
8388c2ecf20Sopenharmony_ci	 *  case 3) EOM =0, cs_change =0: SSb stay active
8398c2ecf20Sopenharmony_ci	 *  case 4) EOM =0, cs_change =1: SSb inactive
8408c2ecf20Sopenharmony_ci	 */
8418c2ecf20Sopenharmony_ci	if (((tstatus & TRANS_STATUS_BREAK_DESELECT)
8428c2ecf20Sopenharmony_ci	     == TRANS_STATUS_BREAK_CS_CHANGE) ||
8438c2ecf20Sopenharmony_ci	    ((tstatus & TRANS_STATUS_BREAK_DESELECT)
8448c2ecf20Sopenharmony_ci	     == TRANS_STATUS_BREAK_EOM)) {
8458c2ecf20Sopenharmony_ci		mspi_cdram = read_cdram_slot(qspi, slot - 1) &
8468c2ecf20Sopenharmony_ci			~MSPI_CDRAM_CONT_BIT;
8478c2ecf20Sopenharmony_ci		write_cdram_slot(qspi, slot - 1, mspi_cdram);
8488c2ecf20Sopenharmony_ci	}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	if (has_bspi(qspi))
8518c2ecf20Sopenharmony_ci		bcm_qspi_write(qspi, MSPI, MSPI_WRITE_LOCK, 1);
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	/* Must flush previous writes before starting MSPI operation */
8548c2ecf20Sopenharmony_ci	mb();
8558c2ecf20Sopenharmony_ci	/* Set cont | spe | spifie */
8568c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, MSPI, MSPI_SPCR2, 0xe0);
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_cidone:
8598c2ecf20Sopenharmony_ci	return slot;
8608c2ecf20Sopenharmony_ci}
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_cistatic int bcm_qspi_bspi_exec_mem_op(struct spi_device *spi,
8638c2ecf20Sopenharmony_ci				     const struct spi_mem_op *op)
8648c2ecf20Sopenharmony_ci{
8658c2ecf20Sopenharmony_ci	struct bcm_qspi *qspi = spi_master_get_devdata(spi->master);
8668c2ecf20Sopenharmony_ci	u32 addr = 0, len, rdlen, len_words, from = 0;
8678c2ecf20Sopenharmony_ci	int ret = 0;
8688c2ecf20Sopenharmony_ci	unsigned long timeo = msecs_to_jiffies(100);
8698c2ecf20Sopenharmony_ci	struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	if (bcm_qspi_bspi_ver_three(qspi))
8728c2ecf20Sopenharmony_ci		if (op->addr.nbytes == BSPI_ADDRLEN_4BYTES)
8738c2ecf20Sopenharmony_ci			return -EIO;
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	from = op->addr.val;
8768c2ecf20Sopenharmony_ci	if (!spi->cs_gpiod)
8778c2ecf20Sopenharmony_ci		bcm_qspi_chip_select(qspi, spi->chip_select);
8788c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, MSPI, MSPI_WRITE_LOCK, 0);
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	/*
8818c2ecf20Sopenharmony_ci	 * when using flex mode we need to send
8828c2ecf20Sopenharmony_ci	 * the upper address byte to bspi
8838c2ecf20Sopenharmony_ci	 */
8848c2ecf20Sopenharmony_ci	if (bcm_qspi_bspi_ver_three(qspi) == false) {
8858c2ecf20Sopenharmony_ci		addr = from & 0xff000000;
8868c2ecf20Sopenharmony_ci		bcm_qspi_write(qspi, BSPI,
8878c2ecf20Sopenharmony_ci			       BSPI_BSPI_FLASH_UPPER_ADDR_BYTE, addr);
8888c2ecf20Sopenharmony_ci	}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	if (!qspi->xfer_mode.flex_mode)
8918c2ecf20Sopenharmony_ci		addr = from;
8928c2ecf20Sopenharmony_ci	else
8938c2ecf20Sopenharmony_ci		addr = from & 0x00ffffff;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	if (bcm_qspi_bspi_ver_three(qspi) == true)
8968c2ecf20Sopenharmony_ci		addr = (addr + 0xc00000) & 0xffffff;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	/*
8998c2ecf20Sopenharmony_ci	 * read into the entire buffer by breaking the reads
9008c2ecf20Sopenharmony_ci	 * into RAF buffer read lengths
9018c2ecf20Sopenharmony_ci	 */
9028c2ecf20Sopenharmony_ci	len = op->data.nbytes;
9038c2ecf20Sopenharmony_ci	qspi->bspi_rf_op_idx = 0;
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	do {
9068c2ecf20Sopenharmony_ci		if (len > BSPI_READ_LENGTH)
9078c2ecf20Sopenharmony_ci			rdlen = BSPI_READ_LENGTH;
9088c2ecf20Sopenharmony_ci		else
9098c2ecf20Sopenharmony_ci			rdlen = len;
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci		reinit_completion(&qspi->bspi_done);
9128c2ecf20Sopenharmony_ci		bcm_qspi_enable_bspi(qspi);
9138c2ecf20Sopenharmony_ci		len_words = (rdlen + 3) >> 2;
9148c2ecf20Sopenharmony_ci		qspi->bspi_rf_op = op;
9158c2ecf20Sopenharmony_ci		qspi->bspi_rf_op_status = 0;
9168c2ecf20Sopenharmony_ci		qspi->bspi_rf_op_len = rdlen;
9178c2ecf20Sopenharmony_ci		dev_dbg(&qspi->pdev->dev,
9188c2ecf20Sopenharmony_ci			"bspi xfr addr 0x%x len 0x%x", addr, rdlen);
9198c2ecf20Sopenharmony_ci		bcm_qspi_write(qspi, BSPI, BSPI_RAF_START_ADDR, addr);
9208c2ecf20Sopenharmony_ci		bcm_qspi_write(qspi, BSPI, BSPI_RAF_NUM_WORDS, len_words);
9218c2ecf20Sopenharmony_ci		bcm_qspi_write(qspi, BSPI, BSPI_RAF_WATERMARK, 0);
9228c2ecf20Sopenharmony_ci		if (qspi->soc_intc) {
9238c2ecf20Sopenharmony_ci			/*
9248c2ecf20Sopenharmony_ci			 * clear soc MSPI and BSPI interrupts and enable
9258c2ecf20Sopenharmony_ci			 * BSPI interrupts.
9268c2ecf20Sopenharmony_ci			 */
9278c2ecf20Sopenharmony_ci			soc_intc->bcm_qspi_int_ack(soc_intc, MSPI_BSPI_DONE);
9288c2ecf20Sopenharmony_ci			soc_intc->bcm_qspi_int_set(soc_intc, BSPI_DONE, true);
9298c2ecf20Sopenharmony_ci		}
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci		/* Must flush previous writes before starting BSPI operation */
9328c2ecf20Sopenharmony_ci		mb();
9338c2ecf20Sopenharmony_ci		bcm_qspi_bspi_lr_start(qspi);
9348c2ecf20Sopenharmony_ci		if (!wait_for_completion_timeout(&qspi->bspi_done, timeo)) {
9358c2ecf20Sopenharmony_ci			dev_err(&qspi->pdev->dev, "timeout waiting for BSPI\n");
9368c2ecf20Sopenharmony_ci			ret = -ETIMEDOUT;
9378c2ecf20Sopenharmony_ci			break;
9388c2ecf20Sopenharmony_ci		}
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci		/* set msg return length */
9418c2ecf20Sopenharmony_ci		addr += rdlen;
9428c2ecf20Sopenharmony_ci		len -= rdlen;
9438c2ecf20Sopenharmony_ci	} while (len);
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	return ret;
9468c2ecf20Sopenharmony_ci}
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_cistatic int bcm_qspi_transfer_one(struct spi_master *master,
9498c2ecf20Sopenharmony_ci				 struct spi_device *spi,
9508c2ecf20Sopenharmony_ci				 struct spi_transfer *trans)
9518c2ecf20Sopenharmony_ci{
9528c2ecf20Sopenharmony_ci	struct bcm_qspi *qspi = spi_master_get_devdata(master);
9538c2ecf20Sopenharmony_ci	int slots;
9548c2ecf20Sopenharmony_ci	unsigned long timeo = msecs_to_jiffies(100);
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	if (!spi->cs_gpiod)
9578c2ecf20Sopenharmony_ci		bcm_qspi_chip_select(qspi, spi->chip_select);
9588c2ecf20Sopenharmony_ci	qspi->trans_pos.trans = trans;
9598c2ecf20Sopenharmony_ci	qspi->trans_pos.byte = 0;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	while (qspi->trans_pos.byte < trans->len) {
9628c2ecf20Sopenharmony_ci		reinit_completion(&qspi->mspi_done);
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci		slots = write_to_hw(qspi, spi);
9658c2ecf20Sopenharmony_ci		if (!wait_for_completion_timeout(&qspi->mspi_done, timeo)) {
9668c2ecf20Sopenharmony_ci			dev_err(&qspi->pdev->dev, "timeout waiting for MSPI\n");
9678c2ecf20Sopenharmony_ci			return -ETIMEDOUT;
9688c2ecf20Sopenharmony_ci		}
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci		read_from_hw(qspi, slots);
9718c2ecf20Sopenharmony_ci	}
9728c2ecf20Sopenharmony_ci	bcm_qspi_enable_bspi(qspi);
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	return 0;
9758c2ecf20Sopenharmony_ci}
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_cistatic int bcm_qspi_mspi_exec_mem_op(struct spi_device *spi,
9788c2ecf20Sopenharmony_ci				     const struct spi_mem_op *op)
9798c2ecf20Sopenharmony_ci{
9808c2ecf20Sopenharmony_ci	struct spi_master *master = spi->master;
9818c2ecf20Sopenharmony_ci	struct bcm_qspi *qspi = spi_master_get_devdata(master);
9828c2ecf20Sopenharmony_ci	struct spi_transfer t[2];
9838c2ecf20Sopenharmony_ci	u8 cmd[6] = { };
9848c2ecf20Sopenharmony_ci	int ret, i;
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	memset(cmd, 0, sizeof(cmd));
9878c2ecf20Sopenharmony_ci	memset(t, 0, sizeof(t));
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	/* tx */
9908c2ecf20Sopenharmony_ci	/* opcode is in cmd[0] */
9918c2ecf20Sopenharmony_ci	cmd[0] = op->cmd.opcode;
9928c2ecf20Sopenharmony_ci	for (i = 0; i < op->addr.nbytes; i++)
9938c2ecf20Sopenharmony_ci		cmd[1 + i] = op->addr.val >> (8 * (op->addr.nbytes - i - 1));
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	t[0].tx_buf = cmd;
9968c2ecf20Sopenharmony_ci	t[0].len = op->addr.nbytes + op->dummy.nbytes + 1;
9978c2ecf20Sopenharmony_ci	t[0].bits_per_word = spi->bits_per_word;
9988c2ecf20Sopenharmony_ci	t[0].tx_nbits = op->cmd.buswidth;
9998c2ecf20Sopenharmony_ci	/* lets mspi know that this is not last transfer */
10008c2ecf20Sopenharmony_ci	qspi->trans_pos.mspi_last_trans = false;
10018c2ecf20Sopenharmony_ci	ret = bcm_qspi_transfer_one(master, spi, &t[0]);
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	/* rx */
10048c2ecf20Sopenharmony_ci	qspi->trans_pos.mspi_last_trans = true;
10058c2ecf20Sopenharmony_ci	if (!ret) {
10068c2ecf20Sopenharmony_ci		/* rx */
10078c2ecf20Sopenharmony_ci		t[1].rx_buf = op->data.buf.in;
10088c2ecf20Sopenharmony_ci		t[1].len = op->data.nbytes;
10098c2ecf20Sopenharmony_ci		t[1].rx_nbits =  op->data.buswidth;
10108c2ecf20Sopenharmony_ci		t[1].bits_per_word = spi->bits_per_word;
10118c2ecf20Sopenharmony_ci		ret = bcm_qspi_transfer_one(master, spi, &t[1]);
10128c2ecf20Sopenharmony_ci	}
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	return ret;
10158c2ecf20Sopenharmony_ci}
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_cistatic int bcm_qspi_exec_mem_op(struct spi_mem *mem,
10188c2ecf20Sopenharmony_ci				const struct spi_mem_op *op)
10198c2ecf20Sopenharmony_ci{
10208c2ecf20Sopenharmony_ci	struct spi_device *spi = mem->spi;
10218c2ecf20Sopenharmony_ci	struct bcm_qspi *qspi = spi_master_get_devdata(spi->master);
10228c2ecf20Sopenharmony_ci	int ret = 0;
10238c2ecf20Sopenharmony_ci	bool mspi_read = false;
10248c2ecf20Sopenharmony_ci	u32 addr = 0, len;
10258c2ecf20Sopenharmony_ci	u_char *buf;
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	if (!op->data.nbytes || !op->addr.nbytes || op->addr.nbytes > 4 ||
10288c2ecf20Sopenharmony_ci	    op->data.dir != SPI_MEM_DATA_IN)
10298c2ecf20Sopenharmony_ci		return -ENOTSUPP;
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci	buf = op->data.buf.in;
10328c2ecf20Sopenharmony_ci	addr = op->addr.val;
10338c2ecf20Sopenharmony_ci	len = op->data.nbytes;
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	if (has_bspi(qspi) && bcm_qspi_bspi_ver_three(qspi) == true) {
10368c2ecf20Sopenharmony_ci		/*
10378c2ecf20Sopenharmony_ci		 * The address coming into this function is a raw flash offset.
10388c2ecf20Sopenharmony_ci		 * But for BSPI <= V3, we need to convert it to a remapped BSPI
10398c2ecf20Sopenharmony_ci		 * address. If it crosses a 4MB boundary, just revert back to
10408c2ecf20Sopenharmony_ci		 * using MSPI.
10418c2ecf20Sopenharmony_ci		 */
10428c2ecf20Sopenharmony_ci		addr = (addr + 0xc00000) & 0xffffff;
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci		if ((~ADDR_4MB_MASK & addr) ^
10458c2ecf20Sopenharmony_ci		    (~ADDR_4MB_MASK & (addr + len - 1)))
10468c2ecf20Sopenharmony_ci			mspi_read = true;
10478c2ecf20Sopenharmony_ci	}
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	/* non-aligned and very short transfers are handled by MSPI */
10508c2ecf20Sopenharmony_ci	if (!IS_ALIGNED((uintptr_t)addr, 4) || !IS_ALIGNED((uintptr_t)buf, 4) ||
10518c2ecf20Sopenharmony_ci	    len < 4 || op->cmd.opcode == SPINOR_OP_RDSFDP)
10528c2ecf20Sopenharmony_ci		mspi_read = true;
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	if (!has_bspi(qspi) || mspi_read)
10558c2ecf20Sopenharmony_ci		return bcm_qspi_mspi_exec_mem_op(spi, op);
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	ret = bcm_qspi_bspi_set_mode(qspi, op, 0);
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	if (!ret)
10608c2ecf20Sopenharmony_ci		ret = bcm_qspi_bspi_exec_mem_op(spi, op);
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	return ret;
10638c2ecf20Sopenharmony_ci}
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_cistatic void bcm_qspi_cleanup(struct spi_device *spi)
10668c2ecf20Sopenharmony_ci{
10678c2ecf20Sopenharmony_ci	struct bcm_qspi_parms *xp = spi_get_ctldata(spi);
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	kfree(xp);
10708c2ecf20Sopenharmony_ci}
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_cistatic irqreturn_t bcm_qspi_mspi_l2_isr(int irq, void *dev_id)
10738c2ecf20Sopenharmony_ci{
10748c2ecf20Sopenharmony_ci	struct bcm_qspi_dev_id *qspi_dev_id = dev_id;
10758c2ecf20Sopenharmony_ci	struct bcm_qspi *qspi = qspi_dev_id->dev;
10768c2ecf20Sopenharmony_ci	u32 status = bcm_qspi_read(qspi, MSPI, MSPI_MSPI_STATUS);
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	if (status & MSPI_MSPI_STATUS_SPIF) {
10798c2ecf20Sopenharmony_ci		struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
10808c2ecf20Sopenharmony_ci		/* clear interrupt */
10818c2ecf20Sopenharmony_ci		status &= ~MSPI_MSPI_STATUS_SPIF;
10828c2ecf20Sopenharmony_ci		bcm_qspi_write(qspi, MSPI, MSPI_MSPI_STATUS, status);
10838c2ecf20Sopenharmony_ci		if (qspi->soc_intc)
10848c2ecf20Sopenharmony_ci			soc_intc->bcm_qspi_int_ack(soc_intc, MSPI_DONE);
10858c2ecf20Sopenharmony_ci		complete(&qspi->mspi_done);
10868c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
10878c2ecf20Sopenharmony_ci	}
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	return IRQ_NONE;
10908c2ecf20Sopenharmony_ci}
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_cistatic irqreturn_t bcm_qspi_bspi_lr_l2_isr(int irq, void *dev_id)
10938c2ecf20Sopenharmony_ci{
10948c2ecf20Sopenharmony_ci	struct bcm_qspi_dev_id *qspi_dev_id = dev_id;
10958c2ecf20Sopenharmony_ci	struct bcm_qspi *qspi = qspi_dev_id->dev;
10968c2ecf20Sopenharmony_ci	struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
10978c2ecf20Sopenharmony_ci	u32 status = qspi_dev_id->irqp->mask;
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	if (qspi->bspi_enabled && qspi->bspi_rf_op) {
11008c2ecf20Sopenharmony_ci		bcm_qspi_bspi_lr_data_read(qspi);
11018c2ecf20Sopenharmony_ci		if (qspi->bspi_rf_op_len == 0) {
11028c2ecf20Sopenharmony_ci			qspi->bspi_rf_op = NULL;
11038c2ecf20Sopenharmony_ci			if (qspi->soc_intc) {
11048c2ecf20Sopenharmony_ci				/* disable soc BSPI interrupt */
11058c2ecf20Sopenharmony_ci				soc_intc->bcm_qspi_int_set(soc_intc, BSPI_DONE,
11068c2ecf20Sopenharmony_ci							   false);
11078c2ecf20Sopenharmony_ci				/* indicate done */
11088c2ecf20Sopenharmony_ci				status = INTR_BSPI_LR_SESSION_DONE_MASK;
11098c2ecf20Sopenharmony_ci			}
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci			if (qspi->bspi_rf_op_status)
11128c2ecf20Sopenharmony_ci				bcm_qspi_bspi_lr_clear(qspi);
11138c2ecf20Sopenharmony_ci			else
11148c2ecf20Sopenharmony_ci				bcm_qspi_bspi_flush_prefetch_buffers(qspi);
11158c2ecf20Sopenharmony_ci		}
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci		if (qspi->soc_intc)
11188c2ecf20Sopenharmony_ci			/* clear soc BSPI interrupt */
11198c2ecf20Sopenharmony_ci			soc_intc->bcm_qspi_int_ack(soc_intc, BSPI_DONE);
11208c2ecf20Sopenharmony_ci	}
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci	status &= INTR_BSPI_LR_SESSION_DONE_MASK;
11238c2ecf20Sopenharmony_ci	if (qspi->bspi_enabled && status && qspi->bspi_rf_op_len == 0)
11248c2ecf20Sopenharmony_ci		complete(&qspi->bspi_done);
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
11278c2ecf20Sopenharmony_ci}
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_cistatic irqreturn_t bcm_qspi_bspi_lr_err_l2_isr(int irq, void *dev_id)
11308c2ecf20Sopenharmony_ci{
11318c2ecf20Sopenharmony_ci	struct bcm_qspi_dev_id *qspi_dev_id = dev_id;
11328c2ecf20Sopenharmony_ci	struct bcm_qspi *qspi = qspi_dev_id->dev;
11338c2ecf20Sopenharmony_ci	struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	dev_err(&qspi->pdev->dev, "BSPI INT error\n");
11368c2ecf20Sopenharmony_ci	qspi->bspi_rf_op_status = -EIO;
11378c2ecf20Sopenharmony_ci	if (qspi->soc_intc)
11388c2ecf20Sopenharmony_ci		/* clear soc interrupt */
11398c2ecf20Sopenharmony_ci		soc_intc->bcm_qspi_int_ack(soc_intc, BSPI_ERR);
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci	complete(&qspi->bspi_done);
11428c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
11438c2ecf20Sopenharmony_ci}
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_cistatic irqreturn_t bcm_qspi_l1_isr(int irq, void *dev_id)
11468c2ecf20Sopenharmony_ci{
11478c2ecf20Sopenharmony_ci	struct bcm_qspi_dev_id *qspi_dev_id = dev_id;
11488c2ecf20Sopenharmony_ci	struct bcm_qspi *qspi = qspi_dev_id->dev;
11498c2ecf20Sopenharmony_ci	struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
11508c2ecf20Sopenharmony_ci	irqreturn_t ret = IRQ_NONE;
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	if (soc_intc) {
11538c2ecf20Sopenharmony_ci		u32 status = soc_intc->bcm_qspi_get_int_status(soc_intc);
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci		if (status & MSPI_DONE)
11568c2ecf20Sopenharmony_ci			ret = bcm_qspi_mspi_l2_isr(irq, dev_id);
11578c2ecf20Sopenharmony_ci		else if (status & BSPI_DONE)
11588c2ecf20Sopenharmony_ci			ret = bcm_qspi_bspi_lr_l2_isr(irq, dev_id);
11598c2ecf20Sopenharmony_ci		else if (status & BSPI_ERR)
11608c2ecf20Sopenharmony_ci			ret = bcm_qspi_bspi_lr_err_l2_isr(irq, dev_id);
11618c2ecf20Sopenharmony_ci	}
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci	return ret;
11648c2ecf20Sopenharmony_ci}
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_cistatic const struct bcm_qspi_irq qspi_irq_tab[] = {
11678c2ecf20Sopenharmony_ci	{
11688c2ecf20Sopenharmony_ci		.irq_name = "spi_lr_fullness_reached",
11698c2ecf20Sopenharmony_ci		.irq_handler = bcm_qspi_bspi_lr_l2_isr,
11708c2ecf20Sopenharmony_ci		.mask = INTR_BSPI_LR_FULLNESS_REACHED_MASK,
11718c2ecf20Sopenharmony_ci	},
11728c2ecf20Sopenharmony_ci	{
11738c2ecf20Sopenharmony_ci		.irq_name = "spi_lr_session_aborted",
11748c2ecf20Sopenharmony_ci		.irq_handler = bcm_qspi_bspi_lr_err_l2_isr,
11758c2ecf20Sopenharmony_ci		.mask = INTR_BSPI_LR_SESSION_ABORTED_MASK,
11768c2ecf20Sopenharmony_ci	},
11778c2ecf20Sopenharmony_ci	{
11788c2ecf20Sopenharmony_ci		.irq_name = "spi_lr_impatient",
11798c2ecf20Sopenharmony_ci		.irq_handler = bcm_qspi_bspi_lr_err_l2_isr,
11808c2ecf20Sopenharmony_ci		.mask = INTR_BSPI_LR_IMPATIENT_MASK,
11818c2ecf20Sopenharmony_ci	},
11828c2ecf20Sopenharmony_ci	{
11838c2ecf20Sopenharmony_ci		.irq_name = "spi_lr_session_done",
11848c2ecf20Sopenharmony_ci		.irq_handler = bcm_qspi_bspi_lr_l2_isr,
11858c2ecf20Sopenharmony_ci		.mask = INTR_BSPI_LR_SESSION_DONE_MASK,
11868c2ecf20Sopenharmony_ci	},
11878c2ecf20Sopenharmony_ci#ifdef QSPI_INT_DEBUG
11888c2ecf20Sopenharmony_ci	/* this interrupt is for debug purposes only, dont request irq */
11898c2ecf20Sopenharmony_ci	{
11908c2ecf20Sopenharmony_ci		.irq_name = "spi_lr_overread",
11918c2ecf20Sopenharmony_ci		.irq_handler = bcm_qspi_bspi_lr_err_l2_isr,
11928c2ecf20Sopenharmony_ci		.mask = INTR_BSPI_LR_OVERREAD_MASK,
11938c2ecf20Sopenharmony_ci	},
11948c2ecf20Sopenharmony_ci#endif
11958c2ecf20Sopenharmony_ci	{
11968c2ecf20Sopenharmony_ci		.irq_name = "mspi_done",
11978c2ecf20Sopenharmony_ci		.irq_handler = bcm_qspi_mspi_l2_isr,
11988c2ecf20Sopenharmony_ci		.mask = INTR_MSPI_DONE_MASK,
11998c2ecf20Sopenharmony_ci	},
12008c2ecf20Sopenharmony_ci	{
12018c2ecf20Sopenharmony_ci		.irq_name = "mspi_halted",
12028c2ecf20Sopenharmony_ci		.irq_handler = bcm_qspi_mspi_l2_isr,
12038c2ecf20Sopenharmony_ci		.mask = INTR_MSPI_HALTED_MASK,
12048c2ecf20Sopenharmony_ci	},
12058c2ecf20Sopenharmony_ci	{
12068c2ecf20Sopenharmony_ci		/* single muxed L1 interrupt source */
12078c2ecf20Sopenharmony_ci		.irq_name = "spi_l1_intr",
12088c2ecf20Sopenharmony_ci		.irq_handler = bcm_qspi_l1_isr,
12098c2ecf20Sopenharmony_ci		.irq_source = MUXED_L1,
12108c2ecf20Sopenharmony_ci		.mask = QSPI_INTERRUPTS_ALL,
12118c2ecf20Sopenharmony_ci	},
12128c2ecf20Sopenharmony_ci};
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_cistatic void bcm_qspi_bspi_init(struct bcm_qspi *qspi)
12158c2ecf20Sopenharmony_ci{
12168c2ecf20Sopenharmony_ci	u32 val = 0;
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	val = bcm_qspi_read(qspi, BSPI, BSPI_REVISION_ID);
12198c2ecf20Sopenharmony_ci	qspi->bspi_maj_rev = (val >> 8) & 0xff;
12208c2ecf20Sopenharmony_ci	qspi->bspi_min_rev = val & 0xff;
12218c2ecf20Sopenharmony_ci	if (!(bcm_qspi_bspi_ver_three(qspi))) {
12228c2ecf20Sopenharmony_ci		/* Force mapping of BSPI address -> flash offset */
12238c2ecf20Sopenharmony_ci		bcm_qspi_write(qspi, BSPI, BSPI_BSPI_XOR_VALUE, 0);
12248c2ecf20Sopenharmony_ci		bcm_qspi_write(qspi, BSPI, BSPI_BSPI_XOR_ENABLE, 1);
12258c2ecf20Sopenharmony_ci	}
12268c2ecf20Sopenharmony_ci	qspi->bspi_enabled = 1;
12278c2ecf20Sopenharmony_ci	bcm_qspi_disable_bspi(qspi);
12288c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, BSPI, BSPI_B0_CTRL, 0);
12298c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, BSPI, BSPI_B1_CTRL, 0);
12308c2ecf20Sopenharmony_ci}
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_cistatic void bcm_qspi_hw_init(struct bcm_qspi *qspi)
12338c2ecf20Sopenharmony_ci{
12348c2ecf20Sopenharmony_ci	struct bcm_qspi_parms parms;
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, MSPI, MSPI_SPCR1_LSB, 0);
12378c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, MSPI, MSPI_SPCR1_MSB, 0);
12388c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, MSPI, MSPI_NEWQP, 0);
12398c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, MSPI, MSPI_ENDQP, 0);
12408c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, MSPI, MSPI_SPCR2, 0x20);
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	parms.mode = SPI_MODE_3;
12438c2ecf20Sopenharmony_ci	parms.bits_per_word = 8;
12448c2ecf20Sopenharmony_ci	parms.speed_hz = qspi->max_speed_hz;
12458c2ecf20Sopenharmony_ci	bcm_qspi_hw_set_parms(qspi, &parms);
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci	if (has_bspi(qspi))
12488c2ecf20Sopenharmony_ci		bcm_qspi_bspi_init(qspi);
12498c2ecf20Sopenharmony_ci}
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_cistatic void bcm_qspi_hw_uninit(struct bcm_qspi *qspi)
12528c2ecf20Sopenharmony_ci{
12538c2ecf20Sopenharmony_ci	u32 status = bcm_qspi_read(qspi, MSPI, MSPI_MSPI_STATUS);
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, MSPI, MSPI_SPCR2, 0);
12568c2ecf20Sopenharmony_ci	if (has_bspi(qspi))
12578c2ecf20Sopenharmony_ci		bcm_qspi_write(qspi, MSPI, MSPI_WRITE_LOCK, 0);
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	/* clear interrupt */
12608c2ecf20Sopenharmony_ci	bcm_qspi_write(qspi, MSPI, MSPI_MSPI_STATUS, status & ~1);
12618c2ecf20Sopenharmony_ci}
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_cistatic const struct spi_controller_mem_ops bcm_qspi_mem_ops = {
12648c2ecf20Sopenharmony_ci	.exec_op = bcm_qspi_exec_mem_op,
12658c2ecf20Sopenharmony_ci};
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_cistruct bcm_qspi_data {
12688c2ecf20Sopenharmony_ci	bool	has_mspi_rev;
12698c2ecf20Sopenharmony_ci	bool	has_spcr3_sysclk;
12708c2ecf20Sopenharmony_ci};
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_cistatic const struct bcm_qspi_data bcm_qspi_no_rev_data = {
12738c2ecf20Sopenharmony_ci	.has_mspi_rev	= false,
12748c2ecf20Sopenharmony_ci	.has_spcr3_sysclk = false,
12758c2ecf20Sopenharmony_ci};
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_cistatic const struct bcm_qspi_data bcm_qspi_rev_data = {
12788c2ecf20Sopenharmony_ci	.has_mspi_rev	= true,
12798c2ecf20Sopenharmony_ci	.has_spcr3_sysclk = false,
12808c2ecf20Sopenharmony_ci};
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_cistatic const struct bcm_qspi_data bcm_qspi_spcr3_data = {
12838c2ecf20Sopenharmony_ci	.has_mspi_rev	= true,
12848c2ecf20Sopenharmony_ci	.has_spcr3_sysclk = true,
12858c2ecf20Sopenharmony_ci};
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_cistatic const struct of_device_id bcm_qspi_of_match[] = {
12888c2ecf20Sopenharmony_ci	{
12898c2ecf20Sopenharmony_ci		.compatible = "brcm,spi-bcm7445-qspi",
12908c2ecf20Sopenharmony_ci		.data = &bcm_qspi_rev_data,
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_ci	},
12938c2ecf20Sopenharmony_ci	{
12948c2ecf20Sopenharmony_ci		.compatible = "brcm,spi-bcm-qspi",
12958c2ecf20Sopenharmony_ci		.data = &bcm_qspi_no_rev_data,
12968c2ecf20Sopenharmony_ci	},
12978c2ecf20Sopenharmony_ci	{
12988c2ecf20Sopenharmony_ci		.compatible = "brcm,spi-bcm7216-qspi",
12998c2ecf20Sopenharmony_ci		.data = &bcm_qspi_spcr3_data,
13008c2ecf20Sopenharmony_ci	},
13018c2ecf20Sopenharmony_ci	{
13028c2ecf20Sopenharmony_ci		.compatible = "brcm,spi-bcm7278-qspi",
13038c2ecf20Sopenharmony_ci		.data = &bcm_qspi_spcr3_data,
13048c2ecf20Sopenharmony_ci	},
13058c2ecf20Sopenharmony_ci	{},
13068c2ecf20Sopenharmony_ci};
13078c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, bcm_qspi_of_match);
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ciint bcm_qspi_probe(struct platform_device *pdev,
13108c2ecf20Sopenharmony_ci		   struct bcm_qspi_soc_intc *soc_intc)
13118c2ecf20Sopenharmony_ci{
13128c2ecf20Sopenharmony_ci	const struct of_device_id *of_id = NULL;
13138c2ecf20Sopenharmony_ci	const struct bcm_qspi_data *data;
13148c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
13158c2ecf20Sopenharmony_ci	struct bcm_qspi *qspi;
13168c2ecf20Sopenharmony_ci	struct spi_master *master;
13178c2ecf20Sopenharmony_ci	struct resource *res;
13188c2ecf20Sopenharmony_ci	int irq, ret = 0, num_ints = 0;
13198c2ecf20Sopenharmony_ci	u32 val;
13208c2ecf20Sopenharmony_ci	u32 rev = 0;
13218c2ecf20Sopenharmony_ci	const char *name = NULL;
13228c2ecf20Sopenharmony_ci	int num_irqs = ARRAY_SIZE(qspi_irq_tab);
13238c2ecf20Sopenharmony_ci
13248c2ecf20Sopenharmony_ci	/* We only support device-tree instantiation */
13258c2ecf20Sopenharmony_ci	if (!dev->of_node)
13268c2ecf20Sopenharmony_ci		return -ENODEV;
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_ci	of_id = of_match_node(bcm_qspi_of_match, dev->of_node);
13298c2ecf20Sopenharmony_ci	if (!of_id)
13308c2ecf20Sopenharmony_ci		return -ENODEV;
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	data = of_id->data;
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci	master = devm_spi_alloc_master(dev, sizeof(struct bcm_qspi));
13358c2ecf20Sopenharmony_ci	if (!master) {
13368c2ecf20Sopenharmony_ci		dev_err(dev, "error allocating spi_master\n");
13378c2ecf20Sopenharmony_ci		return -ENOMEM;
13388c2ecf20Sopenharmony_ci	}
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci	qspi = spi_master_get_devdata(master);
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	qspi->clk = devm_clk_get_optional(&pdev->dev, NULL);
13438c2ecf20Sopenharmony_ci	if (IS_ERR(qspi->clk))
13448c2ecf20Sopenharmony_ci		return PTR_ERR(qspi->clk);
13458c2ecf20Sopenharmony_ci
13468c2ecf20Sopenharmony_ci	qspi->pdev = pdev;
13478c2ecf20Sopenharmony_ci	qspi->trans_pos.trans = NULL;
13488c2ecf20Sopenharmony_ci	qspi->trans_pos.byte = 0;
13498c2ecf20Sopenharmony_ci	qspi->trans_pos.mspi_last_trans = true;
13508c2ecf20Sopenharmony_ci	qspi->master = master;
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci	master->bus_num = -1;
13538c2ecf20Sopenharmony_ci	master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_RX_DUAL | SPI_RX_QUAD;
13548c2ecf20Sopenharmony_ci	master->setup = bcm_qspi_setup;
13558c2ecf20Sopenharmony_ci	master->transfer_one = bcm_qspi_transfer_one;
13568c2ecf20Sopenharmony_ci	master->mem_ops = &bcm_qspi_mem_ops;
13578c2ecf20Sopenharmony_ci	master->cleanup = bcm_qspi_cleanup;
13588c2ecf20Sopenharmony_ci	master->dev.of_node = dev->of_node;
13598c2ecf20Sopenharmony_ci	master->num_chipselect = NUM_CHIPSELECT;
13608c2ecf20Sopenharmony_ci	master->use_gpio_descriptors = true;
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci	qspi->big_endian = of_device_is_big_endian(dev->of_node);
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	if (!of_property_read_u32(dev->of_node, "num-cs", &val))
13658c2ecf20Sopenharmony_ci		master->num_chipselect = val;
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hif_mspi");
13688c2ecf20Sopenharmony_ci	if (!res)
13698c2ecf20Sopenharmony_ci		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
13708c2ecf20Sopenharmony_ci						   "mspi");
13718c2ecf20Sopenharmony_ci
13728c2ecf20Sopenharmony_ci	qspi->base[MSPI]  = devm_ioremap_resource(dev, res);
13738c2ecf20Sopenharmony_ci	if (IS_ERR(qspi->base[MSPI]))
13748c2ecf20Sopenharmony_ci		return PTR_ERR(qspi->base[MSPI]);
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "bspi");
13778c2ecf20Sopenharmony_ci	if (res) {
13788c2ecf20Sopenharmony_ci		qspi->base[BSPI]  = devm_ioremap_resource(dev, res);
13798c2ecf20Sopenharmony_ci		if (IS_ERR(qspi->base[BSPI]))
13808c2ecf20Sopenharmony_ci			return PTR_ERR(qspi->base[BSPI]);
13818c2ecf20Sopenharmony_ci		qspi->bspi_mode = true;
13828c2ecf20Sopenharmony_ci	} else {
13838c2ecf20Sopenharmony_ci		qspi->bspi_mode = false;
13848c2ecf20Sopenharmony_ci	}
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci	dev_info(dev, "using %smspi mode\n", qspi->bspi_mode ? "bspi-" : "");
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ci	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cs_reg");
13898c2ecf20Sopenharmony_ci	if (res) {
13908c2ecf20Sopenharmony_ci		qspi->base[CHIP_SELECT]  = devm_ioremap_resource(dev, res);
13918c2ecf20Sopenharmony_ci		if (IS_ERR(qspi->base[CHIP_SELECT]))
13928c2ecf20Sopenharmony_ci			return PTR_ERR(qspi->base[CHIP_SELECT]);
13938c2ecf20Sopenharmony_ci	}
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci	qspi->dev_ids = kcalloc(num_irqs, sizeof(struct bcm_qspi_dev_id),
13968c2ecf20Sopenharmony_ci				GFP_KERNEL);
13978c2ecf20Sopenharmony_ci	if (!qspi->dev_ids)
13988c2ecf20Sopenharmony_ci		return -ENOMEM;
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci	/*
14018c2ecf20Sopenharmony_ci	 * Some SoCs integrate spi controller (e.g., its interrupt bits)
14028c2ecf20Sopenharmony_ci	 * in specific ways
14038c2ecf20Sopenharmony_ci	 */
14048c2ecf20Sopenharmony_ci	if (soc_intc) {
14058c2ecf20Sopenharmony_ci		qspi->soc_intc = soc_intc;
14068c2ecf20Sopenharmony_ci		soc_intc->bcm_qspi_int_set(soc_intc, MSPI_DONE, true);
14078c2ecf20Sopenharmony_ci	} else {
14088c2ecf20Sopenharmony_ci		qspi->soc_intc = NULL;
14098c2ecf20Sopenharmony_ci	}
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci	if (qspi->clk) {
14128c2ecf20Sopenharmony_ci		ret = clk_prepare_enable(qspi->clk);
14138c2ecf20Sopenharmony_ci		if (ret) {
14148c2ecf20Sopenharmony_ci			dev_err(dev, "failed to prepare clock\n");
14158c2ecf20Sopenharmony_ci			goto qspi_probe_err;
14168c2ecf20Sopenharmony_ci		}
14178c2ecf20Sopenharmony_ci		qspi->base_clk = clk_get_rate(qspi->clk);
14188c2ecf20Sopenharmony_ci	} else {
14198c2ecf20Sopenharmony_ci		qspi->base_clk = MSPI_BASE_FREQ;
14208c2ecf20Sopenharmony_ci	}
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_ci	if (data->has_mspi_rev) {
14238c2ecf20Sopenharmony_ci		rev = bcm_qspi_read(qspi, MSPI, MSPI_REV);
14248c2ecf20Sopenharmony_ci		/* some older revs do not have a MSPI_REV register */
14258c2ecf20Sopenharmony_ci		if ((rev & 0xff) == 0xff)
14268c2ecf20Sopenharmony_ci			rev = 0;
14278c2ecf20Sopenharmony_ci	}
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	qspi->mspi_maj_rev = (rev >> 4) & 0xf;
14308c2ecf20Sopenharmony_ci	qspi->mspi_min_rev = rev & 0xf;
14318c2ecf20Sopenharmony_ci	qspi->mspi_spcr3_sysclk = data->has_spcr3_sysclk;
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_ci	qspi->max_speed_hz = qspi->base_clk / (bcm_qspi_spbr_min(qspi) * 2);
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci	/*
14368c2ecf20Sopenharmony_ci	 * On SW resets it is possible to have the mask still enabled
14378c2ecf20Sopenharmony_ci	 * Need to disable the mask and clear the status while we init
14388c2ecf20Sopenharmony_ci	 */
14398c2ecf20Sopenharmony_ci	bcm_qspi_hw_uninit(qspi);
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci	for (val = 0; val < num_irqs; val++) {
14428c2ecf20Sopenharmony_ci		irq = -1;
14438c2ecf20Sopenharmony_ci		name = qspi_irq_tab[val].irq_name;
14448c2ecf20Sopenharmony_ci		if (qspi_irq_tab[val].irq_source == SINGLE_L2) {
14458c2ecf20Sopenharmony_ci			/* get the l2 interrupts */
14468c2ecf20Sopenharmony_ci			irq = platform_get_irq_byname_optional(pdev, name);
14478c2ecf20Sopenharmony_ci		} else if (!num_ints && soc_intc) {
14488c2ecf20Sopenharmony_ci			/* all mspi, bspi intrs muxed to one L1 intr */
14498c2ecf20Sopenharmony_ci			irq = platform_get_irq(pdev, 0);
14508c2ecf20Sopenharmony_ci		}
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci		if (irq  >= 0) {
14538c2ecf20Sopenharmony_ci			ret = devm_request_irq(&pdev->dev, irq,
14548c2ecf20Sopenharmony_ci					       qspi_irq_tab[val].irq_handler, 0,
14558c2ecf20Sopenharmony_ci					       name,
14568c2ecf20Sopenharmony_ci					       &qspi->dev_ids[val]);
14578c2ecf20Sopenharmony_ci			if (ret < 0) {
14588c2ecf20Sopenharmony_ci				dev_err(&pdev->dev, "IRQ %s not found\n", name);
14598c2ecf20Sopenharmony_ci				goto qspi_unprepare_err;
14608c2ecf20Sopenharmony_ci			}
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_ci			qspi->dev_ids[val].dev = qspi;
14638c2ecf20Sopenharmony_ci			qspi->dev_ids[val].irqp = &qspi_irq_tab[val];
14648c2ecf20Sopenharmony_ci			num_ints++;
14658c2ecf20Sopenharmony_ci			dev_dbg(&pdev->dev, "registered IRQ %s %d\n",
14668c2ecf20Sopenharmony_ci				qspi_irq_tab[val].irq_name,
14678c2ecf20Sopenharmony_ci				irq);
14688c2ecf20Sopenharmony_ci		}
14698c2ecf20Sopenharmony_ci	}
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_ci	if (!num_ints) {
14728c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "no IRQs registered, cannot init driver\n");
14738c2ecf20Sopenharmony_ci		ret = -EINVAL;
14748c2ecf20Sopenharmony_ci		goto qspi_unprepare_err;
14758c2ecf20Sopenharmony_ci	}
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_ci	bcm_qspi_hw_init(qspi);
14788c2ecf20Sopenharmony_ci	init_completion(&qspi->mspi_done);
14798c2ecf20Sopenharmony_ci	init_completion(&qspi->bspi_done);
14808c2ecf20Sopenharmony_ci	qspi->curr_cs = -1;
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, qspi);
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	qspi->xfer_mode.width = -1;
14858c2ecf20Sopenharmony_ci	qspi->xfer_mode.addrlen = -1;
14868c2ecf20Sopenharmony_ci	qspi->xfer_mode.hp = -1;
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	ret = spi_register_master(master);
14898c2ecf20Sopenharmony_ci	if (ret < 0) {
14908c2ecf20Sopenharmony_ci		dev_err(dev, "can't register master\n");
14918c2ecf20Sopenharmony_ci		goto qspi_reg_err;
14928c2ecf20Sopenharmony_ci	}
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci	return 0;
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ciqspi_reg_err:
14978c2ecf20Sopenharmony_ci	bcm_qspi_hw_uninit(qspi);
14988c2ecf20Sopenharmony_ciqspi_unprepare_err:
14998c2ecf20Sopenharmony_ci	clk_disable_unprepare(qspi->clk);
15008c2ecf20Sopenharmony_ciqspi_probe_err:
15018c2ecf20Sopenharmony_ci	kfree(qspi->dev_ids);
15028c2ecf20Sopenharmony_ci	return ret;
15038c2ecf20Sopenharmony_ci}
15048c2ecf20Sopenharmony_ci/* probe function to be called by SoC specific platform driver probe */
15058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcm_qspi_probe);
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_ciint bcm_qspi_remove(struct platform_device *pdev)
15088c2ecf20Sopenharmony_ci{
15098c2ecf20Sopenharmony_ci	struct bcm_qspi *qspi = platform_get_drvdata(pdev);
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci	spi_unregister_master(qspi->master);
15128c2ecf20Sopenharmony_ci	bcm_qspi_hw_uninit(qspi);
15138c2ecf20Sopenharmony_ci	clk_disable_unprepare(qspi->clk);
15148c2ecf20Sopenharmony_ci	kfree(qspi->dev_ids);
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci	return 0;
15178c2ecf20Sopenharmony_ci}
15188c2ecf20Sopenharmony_ci/* function to be called by SoC specific platform driver remove() */
15198c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcm_qspi_remove);
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_cistatic int __maybe_unused bcm_qspi_suspend(struct device *dev)
15228c2ecf20Sopenharmony_ci{
15238c2ecf20Sopenharmony_ci	struct bcm_qspi *qspi = dev_get_drvdata(dev);
15248c2ecf20Sopenharmony_ci
15258c2ecf20Sopenharmony_ci	/* store the override strap value */
15268c2ecf20Sopenharmony_ci	if (!bcm_qspi_bspi_ver_three(qspi))
15278c2ecf20Sopenharmony_ci		qspi->s3_strap_override_ctrl =
15288c2ecf20Sopenharmony_ci			bcm_qspi_read(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL);
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci	spi_master_suspend(qspi->master);
15318c2ecf20Sopenharmony_ci	clk_disable_unprepare(qspi->clk);
15328c2ecf20Sopenharmony_ci	bcm_qspi_hw_uninit(qspi);
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	return 0;
15358c2ecf20Sopenharmony_ci};
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_cistatic int __maybe_unused bcm_qspi_resume(struct device *dev)
15388c2ecf20Sopenharmony_ci{
15398c2ecf20Sopenharmony_ci	struct bcm_qspi *qspi = dev_get_drvdata(dev);
15408c2ecf20Sopenharmony_ci	int ret = 0;
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci	bcm_qspi_hw_init(qspi);
15438c2ecf20Sopenharmony_ci	bcm_qspi_chip_select(qspi, qspi->curr_cs);
15448c2ecf20Sopenharmony_ci	if (qspi->soc_intc)
15458c2ecf20Sopenharmony_ci		/* enable MSPI interrupt */
15468c2ecf20Sopenharmony_ci		qspi->soc_intc->bcm_qspi_int_set(qspi->soc_intc, MSPI_DONE,
15478c2ecf20Sopenharmony_ci						 true);
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(qspi->clk);
15508c2ecf20Sopenharmony_ci	if (!ret)
15518c2ecf20Sopenharmony_ci		spi_master_resume(qspi->master);
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci	return ret;
15548c2ecf20Sopenharmony_ci}
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ciSIMPLE_DEV_PM_OPS(bcm_qspi_pm_ops, bcm_qspi_suspend, bcm_qspi_resume);
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci/* pm_ops to be called by SoC specific platform driver */
15598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcm_qspi_pm_ops);
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ciMODULE_AUTHOR("Kamal Dasu");
15628c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Broadcom QSPI driver");
15638c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
15648c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:" DRIVER_NAME);
1565