18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci// Copyright (c) 2019 Nuvoton Technology corporation.
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/bits.h>
58c2ecf20Sopenharmony_ci#include <linux/init.h>
68c2ecf20Sopenharmony_ci#include <linux/kernel.h>
78c2ecf20Sopenharmony_ci#include <linux/device.h>
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/ioport.h>
108c2ecf20Sopenharmony_ci#include <linux/clk.h>
118c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
128c2ecf20Sopenharmony_ci#include <linux/io.h>
138c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
148c2ecf20Sopenharmony_ci#include <linux/regmap.h>
158c2ecf20Sopenharmony_ci#include <linux/of_device.h>
168c2ecf20Sopenharmony_ci#include <linux/spi/spi-mem.h>
178c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/* NPCM7xx GCR module */
208c2ecf20Sopenharmony_ci#define NPCM7XX_INTCR3_OFFSET		0x9C
218c2ecf20Sopenharmony_ci#define NPCM7XX_INTCR3_FIU_FIX		BIT(6)
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/* Flash Interface Unit (FIU) Registers */
248c2ecf20Sopenharmony_ci#define NPCM_FIU_DRD_CFG		0x00
258c2ecf20Sopenharmony_ci#define NPCM_FIU_DWR_CFG		0x04
268c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG		0x08
278c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CTS		0x0C
288c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CMD		0x10
298c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_ADDR		0x14
308c2ecf20Sopenharmony_ci#define NPCM_FIU_PRT_CFG		0x18
318c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW0		0x20
328c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW1		0x24
338c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW2		0x28
348c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW3		0x2C
358c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR0		0x30
368c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR1		0x34
378c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR2		0x38
388c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR3		0x3C
398c2ecf20Sopenharmony_ci#define NPCM_FIU_MAX_REG_LIMIT		0x80
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/* FIU Direct Read Configuration Register */
428c2ecf20Sopenharmony_ci#define NPCM_FIU_DRD_CFG_LCK		BIT(31)
438c2ecf20Sopenharmony_ci#define NPCM_FIU_DRD_CFG_R_BURST	GENMASK(25, 24)
448c2ecf20Sopenharmony_ci#define NPCM_FIU_DRD_CFG_ADDSIZ		GENMASK(17, 16)
458c2ecf20Sopenharmony_ci#define NPCM_FIU_DRD_CFG_DBW		GENMASK(13, 12)
468c2ecf20Sopenharmony_ci#define NPCM_FIU_DRD_CFG_ACCTYPE	GENMASK(9, 8)
478c2ecf20Sopenharmony_ci#define NPCM_FIU_DRD_CFG_RDCMD		GENMASK(7, 0)
488c2ecf20Sopenharmony_ci#define NPCM_FIU_DRD_ADDSIZ_SHIFT	16
498c2ecf20Sopenharmony_ci#define NPCM_FIU_DRD_DBW_SHIFT		12
508c2ecf20Sopenharmony_ci#define NPCM_FIU_DRD_ACCTYPE_SHIFT	8
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/* FIU Direct Write Configuration Register */
538c2ecf20Sopenharmony_ci#define NPCM_FIU_DWR_CFG_LCK		BIT(31)
548c2ecf20Sopenharmony_ci#define NPCM_FIU_DWR_CFG_W_BURST	GENMASK(25, 24)
558c2ecf20Sopenharmony_ci#define NPCM_FIU_DWR_CFG_ADDSIZ		GENMASK(17, 16)
568c2ecf20Sopenharmony_ci#define NPCM_FIU_DWR_CFG_ABPCK		GENMASK(11, 10)
578c2ecf20Sopenharmony_ci#define NPCM_FIU_DWR_CFG_DBPCK		GENMASK(9, 8)
588c2ecf20Sopenharmony_ci#define NPCM_FIU_DWR_CFG_WRCMD		GENMASK(7, 0)
598c2ecf20Sopenharmony_ci#define NPCM_FIU_DWR_ADDSIZ_SHIFT	16
608c2ecf20Sopenharmony_ci#define NPCM_FIU_DWR_ABPCK_SHIFT	10
618c2ecf20Sopenharmony_ci#define NPCM_FIU_DWR_DBPCK_SHIFT	8
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/* FIU UMA Configuration Register */
648c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_LCK		BIT(31)
658c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_CMMLCK		BIT(30)
668c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_RDATSIZ	GENMASK(28, 24)
678c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_DBSIZ		GENMASK(23, 21)
688c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_WDATSIZ	GENMASK(20, 16)
698c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_ADDSIZ		GENMASK(13, 11)
708c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_CMDSIZ		BIT(10)
718c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_RDBPCK		GENMASK(9, 8)
728c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_DBPCK		GENMASK(7, 6)
738c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_WDBPCK		GENMASK(5, 4)
748c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_ADBPCK		GENMASK(3, 2)
758c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_CMBPCK		GENMASK(1, 0)
768c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_ADBPCK_SHIFT	2
778c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_WDBPCK_SHIFT	4
788c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_DBPCK_SHIFT	6
798c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_RDBPCK_SHIFT	8
808c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_ADDSIZ_SHIFT	11
818c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_WDATSIZ_SHIFT	16
828c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_DBSIZ_SHIFT	21
838c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_RDATSIZ_SHIFT	24
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci/* FIU UMA Control and Status Register */
868c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CTS_RDYIE		BIT(25)
878c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CTS_RDYST		BIT(24)
888c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CTS_SW_CS		BIT(16)
898c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CTS_DEV_NUM	GENMASK(9, 8)
908c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CTS_EXEC_DONE	BIT(0)
918c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CTS_DEV_NUM_SHIFT	8
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci/* FIU UMA Command Register */
948c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CMD_DUM3		GENMASK(31, 24)
958c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CMD_DUM2		GENMASK(23, 16)
968c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CMD_DUM1		GENMASK(15, 8)
978c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CMD_CMD		GENMASK(7, 0)
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci/* FIU UMA Address Register */
1008c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_ADDR_UMA_ADDR	GENMASK(31, 0)
1018c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_ADDR_AB3		GENMASK(31, 24)
1028c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_ADDR_AB2		GENMASK(23, 16)
1038c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_ADDR_AB1		GENMASK(15, 8)
1048c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_ADDR_AB0		GENMASK(7, 0)
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci/* FIU UMA Write Data Bytes 0-3 Register */
1078c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW0_WB3		GENMASK(31, 24)
1088c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW0_WB2		GENMASK(23, 16)
1098c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW0_WB1		GENMASK(15, 8)
1108c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW0_WB0		GENMASK(7, 0)
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci/* FIU UMA Write Data Bytes 4-7 Register */
1138c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW1_WB7		GENMASK(31, 24)
1148c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW1_WB6		GENMASK(23, 16)
1158c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW1_WB5		GENMASK(15, 8)
1168c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW1_WB4		GENMASK(7, 0)
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci/* FIU UMA Write Data Bytes 8-11 Register */
1198c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW2_WB11		GENMASK(31, 24)
1208c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW2_WB10		GENMASK(23, 16)
1218c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW2_WB9		GENMASK(15, 8)
1228c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW2_WB8		GENMASK(7, 0)
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci/* FIU UMA Write Data Bytes 12-15 Register */
1258c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW3_WB15		GENMASK(31, 24)
1268c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW3_WB14		GENMASK(23, 16)
1278c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW3_WB13		GENMASK(15, 8)
1288c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW3_WB12		GENMASK(7, 0)
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci/* FIU UMA Read Data Bytes 0-3 Register */
1318c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR0_RB3		GENMASK(31, 24)
1328c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR0_RB2		GENMASK(23, 16)
1338c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR0_RB1		GENMASK(15, 8)
1348c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR0_RB0		GENMASK(7, 0)
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci/* FIU UMA Read Data Bytes 4-7 Register */
1378c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR1_RB15		GENMASK(31, 24)
1388c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR1_RB14		GENMASK(23, 16)
1398c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR1_RB13		GENMASK(15, 8)
1408c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR1_RB12		GENMASK(7, 0)
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci/* FIU UMA Read Data Bytes 8-11 Register */
1438c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR2_RB15		GENMASK(31, 24)
1448c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR2_RB14		GENMASK(23, 16)
1458c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR2_RB13		GENMASK(15, 8)
1468c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR2_RB12		GENMASK(7, 0)
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci/* FIU UMA Read Data Bytes 12-15 Register */
1498c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR3_RB15		GENMASK(31, 24)
1508c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR3_RB14		GENMASK(23, 16)
1518c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR3_RB13		GENMASK(15, 8)
1528c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR3_RB12		GENMASK(7, 0)
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci/* FIU Read Mode */
1558c2ecf20Sopenharmony_cienum {
1568c2ecf20Sopenharmony_ci	DRD_SINGLE_WIRE_MODE	= 0,
1578c2ecf20Sopenharmony_ci	DRD_DUAL_IO_MODE	= 1,
1588c2ecf20Sopenharmony_ci	DRD_QUAD_IO_MODE	= 2,
1598c2ecf20Sopenharmony_ci	DRD_SPI_X_MODE		= 3,
1608c2ecf20Sopenharmony_ci};
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cienum {
1638c2ecf20Sopenharmony_ci	DWR_ABPCK_BIT_PER_CLK	= 0,
1648c2ecf20Sopenharmony_ci	DWR_ABPCK_2_BIT_PER_CLK	= 1,
1658c2ecf20Sopenharmony_ci	DWR_ABPCK_4_BIT_PER_CLK	= 2,
1668c2ecf20Sopenharmony_ci};
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cienum {
1698c2ecf20Sopenharmony_ci	DWR_DBPCK_BIT_PER_CLK	= 0,
1708c2ecf20Sopenharmony_ci	DWR_DBPCK_2_BIT_PER_CLK	= 1,
1718c2ecf20Sopenharmony_ci	DWR_DBPCK_4_BIT_PER_CLK	= 2,
1728c2ecf20Sopenharmony_ci};
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci#define NPCM_FIU_DRD_16_BYTE_BURST	0x3000000
1758c2ecf20Sopenharmony_ci#define NPCM_FIU_DWR_16_BYTE_BURST	0x3000000
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci#define MAP_SIZE_128MB			0x8000000
1788c2ecf20Sopenharmony_ci#define MAP_SIZE_16MB			0x1000000
1798c2ecf20Sopenharmony_ci#define MAP_SIZE_8MB			0x800000
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci#define FIU_DRD_MAX_DUMMY_NUMBER	3
1828c2ecf20Sopenharmony_ci#define NPCM_MAX_CHIP_NUM		4
1838c2ecf20Sopenharmony_ci#define CHUNK_SIZE			16
1848c2ecf20Sopenharmony_ci#define UMA_MICRO_SEC_TIMEOUT		150
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cienum {
1878c2ecf20Sopenharmony_ci	FIU0 = 0,
1888c2ecf20Sopenharmony_ci	FIU3,
1898c2ecf20Sopenharmony_ci	FIUX,
1908c2ecf20Sopenharmony_ci};
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cistruct npcm_fiu_info {
1938c2ecf20Sopenharmony_ci	char *name;
1948c2ecf20Sopenharmony_ci	u32 fiu_id;
1958c2ecf20Sopenharmony_ci	u32 max_map_size;
1968c2ecf20Sopenharmony_ci	u32 max_cs;
1978c2ecf20Sopenharmony_ci};
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistruct fiu_data {
2008c2ecf20Sopenharmony_ci	const struct npcm_fiu_info *npcm_fiu_data_info;
2018c2ecf20Sopenharmony_ci	int fiu_max;
2028c2ecf20Sopenharmony_ci};
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic const struct npcm_fiu_info npxm7xx_fiu_info[] = {
2058c2ecf20Sopenharmony_ci	{.name = "FIU0", .fiu_id = FIU0,
2068c2ecf20Sopenharmony_ci		.max_map_size = MAP_SIZE_128MB, .max_cs = 2},
2078c2ecf20Sopenharmony_ci	{.name = "FIU3", .fiu_id = FIU3,
2088c2ecf20Sopenharmony_ci		.max_map_size = MAP_SIZE_128MB, .max_cs = 4},
2098c2ecf20Sopenharmony_ci	{.name = "FIUX", .fiu_id = FIUX,
2108c2ecf20Sopenharmony_ci		.max_map_size = MAP_SIZE_16MB, .max_cs = 2} };
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic const struct fiu_data npxm7xx_fiu_data = {
2138c2ecf20Sopenharmony_ci	.npcm_fiu_data_info = npxm7xx_fiu_info,
2148c2ecf20Sopenharmony_ci	.fiu_max = 3,
2158c2ecf20Sopenharmony_ci};
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistruct npcm_fiu_spi;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistruct npcm_fiu_chip {
2208c2ecf20Sopenharmony_ci	void __iomem *flash_region_mapped_ptr;
2218c2ecf20Sopenharmony_ci	struct npcm_fiu_spi *fiu;
2228c2ecf20Sopenharmony_ci	unsigned long clkrate;
2238c2ecf20Sopenharmony_ci	u32 chipselect;
2248c2ecf20Sopenharmony_ci};
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_cistruct npcm_fiu_spi {
2278c2ecf20Sopenharmony_ci	struct npcm_fiu_chip chip[NPCM_MAX_CHIP_NUM];
2288c2ecf20Sopenharmony_ci	const struct npcm_fiu_info *info;
2298c2ecf20Sopenharmony_ci	struct spi_mem_op drd_op;
2308c2ecf20Sopenharmony_ci	struct resource *res_mem;
2318c2ecf20Sopenharmony_ci	struct regmap *regmap;
2328c2ecf20Sopenharmony_ci	unsigned long clkrate;
2338c2ecf20Sopenharmony_ci	struct device *dev;
2348c2ecf20Sopenharmony_ci	struct clk *clk;
2358c2ecf20Sopenharmony_ci	bool spix_mode;
2368c2ecf20Sopenharmony_ci};
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic const struct regmap_config npcm_mtd_regmap_config = {
2398c2ecf20Sopenharmony_ci	.reg_bits = 32,
2408c2ecf20Sopenharmony_ci	.val_bits = 32,
2418c2ecf20Sopenharmony_ci	.reg_stride = 4,
2428c2ecf20Sopenharmony_ci	.max_register = NPCM_FIU_MAX_REG_LIMIT,
2438c2ecf20Sopenharmony_ci};
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic void npcm_fiu_set_drd(struct npcm_fiu_spi *fiu,
2468c2ecf20Sopenharmony_ci			     const struct spi_mem_op *op)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
2498c2ecf20Sopenharmony_ci			   NPCM_FIU_DRD_CFG_ACCTYPE,
2508c2ecf20Sopenharmony_ci			   ilog2(op->addr.buswidth) <<
2518c2ecf20Sopenharmony_ci			   NPCM_FIU_DRD_ACCTYPE_SHIFT);
2528c2ecf20Sopenharmony_ci	fiu->drd_op.addr.buswidth = op->addr.buswidth;
2538c2ecf20Sopenharmony_ci	regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
2548c2ecf20Sopenharmony_ci			   NPCM_FIU_DRD_CFG_DBW,
2558c2ecf20Sopenharmony_ci			   ((op->dummy.nbytes * ilog2(op->addr.buswidth)) / BITS_PER_BYTE)
2568c2ecf20Sopenharmony_ci			   << NPCM_FIU_DRD_DBW_SHIFT);
2578c2ecf20Sopenharmony_ci	fiu->drd_op.dummy.nbytes = op->dummy.nbytes;
2588c2ecf20Sopenharmony_ci	regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
2598c2ecf20Sopenharmony_ci			   NPCM_FIU_DRD_CFG_RDCMD, op->cmd.opcode);
2608c2ecf20Sopenharmony_ci	fiu->drd_op.cmd.opcode = op->cmd.opcode;
2618c2ecf20Sopenharmony_ci	regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
2628c2ecf20Sopenharmony_ci			   NPCM_FIU_DRD_CFG_ADDSIZ,
2638c2ecf20Sopenharmony_ci			   (op->addr.nbytes - 3) << NPCM_FIU_DRD_ADDSIZ_SHIFT);
2648c2ecf20Sopenharmony_ci	fiu->drd_op.addr.nbytes = op->addr.nbytes;
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_cistatic ssize_t npcm_fiu_direct_read(struct spi_mem_dirmap_desc *desc,
2688c2ecf20Sopenharmony_ci				    u64 offs, size_t len, void *buf)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	struct npcm_fiu_spi *fiu =
2718c2ecf20Sopenharmony_ci		spi_controller_get_devdata(desc->mem->spi->master);
2728c2ecf20Sopenharmony_ci	struct npcm_fiu_chip *chip = &fiu->chip[desc->mem->spi->chip_select];
2738c2ecf20Sopenharmony_ci	void __iomem *src = (void __iomem *)(chip->flash_region_mapped_ptr +
2748c2ecf20Sopenharmony_ci					     offs);
2758c2ecf20Sopenharmony_ci	u8 *buf_rx = buf;
2768c2ecf20Sopenharmony_ci	u32 i;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	if (fiu->spix_mode) {
2798c2ecf20Sopenharmony_ci		for (i = 0 ; i < len ; i++)
2808c2ecf20Sopenharmony_ci			*(buf_rx + i) = ioread8(src + i);
2818c2ecf20Sopenharmony_ci	} else {
2828c2ecf20Sopenharmony_ci		if (desc->info.op_tmpl.addr.buswidth != fiu->drd_op.addr.buswidth ||
2838c2ecf20Sopenharmony_ci		    desc->info.op_tmpl.dummy.nbytes != fiu->drd_op.dummy.nbytes ||
2848c2ecf20Sopenharmony_ci		    desc->info.op_tmpl.cmd.opcode != fiu->drd_op.cmd.opcode ||
2858c2ecf20Sopenharmony_ci		    desc->info.op_tmpl.addr.nbytes != fiu->drd_op.addr.nbytes)
2868c2ecf20Sopenharmony_ci			npcm_fiu_set_drd(fiu, &desc->info.op_tmpl);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci		memcpy_fromio(buf_rx, src, len);
2898c2ecf20Sopenharmony_ci	}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	return len;
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_cistatic ssize_t npcm_fiu_direct_write(struct spi_mem_dirmap_desc *desc,
2958c2ecf20Sopenharmony_ci				     u64 offs, size_t len, const void *buf)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	struct npcm_fiu_spi *fiu =
2988c2ecf20Sopenharmony_ci		spi_controller_get_devdata(desc->mem->spi->master);
2998c2ecf20Sopenharmony_ci	struct npcm_fiu_chip *chip = &fiu->chip[desc->mem->spi->chip_select];
3008c2ecf20Sopenharmony_ci	void __iomem *dst = (void __iomem *)(chip->flash_region_mapped_ptr +
3018c2ecf20Sopenharmony_ci					     offs);
3028c2ecf20Sopenharmony_ci	const u8 *buf_tx = buf;
3038c2ecf20Sopenharmony_ci	u32 i;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	if (fiu->spix_mode)
3068c2ecf20Sopenharmony_ci		for (i = 0 ; i < len ; i++)
3078c2ecf20Sopenharmony_ci			iowrite8(*(buf_tx + i), dst + i);
3088c2ecf20Sopenharmony_ci	else
3098c2ecf20Sopenharmony_ci		memcpy_toio(dst, buf_tx, len);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	return len;
3128c2ecf20Sopenharmony_ci}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_cistatic int npcm_fiu_uma_read(struct spi_mem *mem,
3158c2ecf20Sopenharmony_ci			     const struct spi_mem_op *op, u32 addr,
3168c2ecf20Sopenharmony_ci			      bool is_address_size, u8 *data, u32 data_size)
3178c2ecf20Sopenharmony_ci{
3188c2ecf20Sopenharmony_ci	struct npcm_fiu_spi *fiu =
3198c2ecf20Sopenharmony_ci		spi_controller_get_devdata(mem->spi->master);
3208c2ecf20Sopenharmony_ci	u32 uma_cfg = BIT(10);
3218c2ecf20Sopenharmony_ci	u32 data_reg[4];
3228c2ecf20Sopenharmony_ci	int ret;
3238c2ecf20Sopenharmony_ci	u32 val;
3248c2ecf20Sopenharmony_ci	u32 i;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
3278c2ecf20Sopenharmony_ci			   NPCM_FIU_UMA_CTS_DEV_NUM,
3288c2ecf20Sopenharmony_ci			   (mem->spi->chip_select <<
3298c2ecf20Sopenharmony_ci			    NPCM_FIU_UMA_CTS_DEV_NUM_SHIFT));
3308c2ecf20Sopenharmony_ci	regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CMD,
3318c2ecf20Sopenharmony_ci			   NPCM_FIU_UMA_CMD_CMD, op->cmd.opcode);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	if (is_address_size) {
3348c2ecf20Sopenharmony_ci		uma_cfg |= ilog2(op->cmd.buswidth);
3358c2ecf20Sopenharmony_ci		uma_cfg |= ilog2(op->addr.buswidth)
3368c2ecf20Sopenharmony_ci			<< NPCM_FIU_UMA_CFG_ADBPCK_SHIFT;
3378c2ecf20Sopenharmony_ci		if (op->dummy.nbytes)
3388c2ecf20Sopenharmony_ci			uma_cfg |= ilog2(op->dummy.buswidth)
3398c2ecf20Sopenharmony_ci				<< NPCM_FIU_UMA_CFG_DBPCK_SHIFT;
3408c2ecf20Sopenharmony_ci		uma_cfg |= ilog2(op->data.buswidth)
3418c2ecf20Sopenharmony_ci			<< NPCM_FIU_UMA_CFG_RDBPCK_SHIFT;
3428c2ecf20Sopenharmony_ci		uma_cfg |= op->dummy.nbytes << NPCM_FIU_UMA_CFG_DBSIZ_SHIFT;
3438c2ecf20Sopenharmony_ci		uma_cfg |= op->addr.nbytes << NPCM_FIU_UMA_CFG_ADDSIZ_SHIFT;
3448c2ecf20Sopenharmony_ci		regmap_write(fiu->regmap, NPCM_FIU_UMA_ADDR, addr);
3458c2ecf20Sopenharmony_ci	} else {
3468c2ecf20Sopenharmony_ci		regmap_write(fiu->regmap, NPCM_FIU_UMA_ADDR, 0x0);
3478c2ecf20Sopenharmony_ci	}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	uma_cfg |= data_size << NPCM_FIU_UMA_CFG_RDATSIZ_SHIFT;
3508c2ecf20Sopenharmony_ci	regmap_write(fiu->regmap, NPCM_FIU_UMA_CFG, uma_cfg);
3518c2ecf20Sopenharmony_ci	regmap_write_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
3528c2ecf20Sopenharmony_ci			  NPCM_FIU_UMA_CTS_EXEC_DONE,
3538c2ecf20Sopenharmony_ci			  NPCM_FIU_UMA_CTS_EXEC_DONE);
3548c2ecf20Sopenharmony_ci	ret = regmap_read_poll_timeout(fiu->regmap, NPCM_FIU_UMA_CTS, val,
3558c2ecf20Sopenharmony_ci				       (!(val & NPCM_FIU_UMA_CTS_EXEC_DONE)), 0,
3568c2ecf20Sopenharmony_ci				       UMA_MICRO_SEC_TIMEOUT);
3578c2ecf20Sopenharmony_ci	if (ret)
3588c2ecf20Sopenharmony_ci		return ret;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	if (data_size) {
3618c2ecf20Sopenharmony_ci		for (i = 0; i < DIV_ROUND_UP(data_size, 4); i++)
3628c2ecf20Sopenharmony_ci			regmap_read(fiu->regmap, NPCM_FIU_UMA_DR0 + (i * 4),
3638c2ecf20Sopenharmony_ci				    &data_reg[i]);
3648c2ecf20Sopenharmony_ci		memcpy(data, data_reg, data_size);
3658c2ecf20Sopenharmony_ci	}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	return 0;
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_cistatic int npcm_fiu_uma_write(struct spi_mem *mem,
3718c2ecf20Sopenharmony_ci			      const struct spi_mem_op *op, u8 cmd,
3728c2ecf20Sopenharmony_ci			      bool is_address_size, u8 *data, u32 data_size)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	struct npcm_fiu_spi *fiu =
3758c2ecf20Sopenharmony_ci		spi_controller_get_devdata(mem->spi->master);
3768c2ecf20Sopenharmony_ci	u32 uma_cfg = BIT(10);
3778c2ecf20Sopenharmony_ci	u32 data_reg[4] = {0};
3788c2ecf20Sopenharmony_ci	u32 val;
3798c2ecf20Sopenharmony_ci	u32 i;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
3828c2ecf20Sopenharmony_ci			   NPCM_FIU_UMA_CTS_DEV_NUM,
3838c2ecf20Sopenharmony_ci			   (mem->spi->chip_select <<
3848c2ecf20Sopenharmony_ci			    NPCM_FIU_UMA_CTS_DEV_NUM_SHIFT));
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CMD,
3878c2ecf20Sopenharmony_ci			   NPCM_FIU_UMA_CMD_CMD, cmd);
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	if (data_size) {
3908c2ecf20Sopenharmony_ci		memcpy(data_reg, data, data_size);
3918c2ecf20Sopenharmony_ci		for (i = 0; i < DIV_ROUND_UP(data_size, 4); i++)
3928c2ecf20Sopenharmony_ci			regmap_write(fiu->regmap, NPCM_FIU_UMA_DW0 + (i * 4),
3938c2ecf20Sopenharmony_ci				     data_reg[i]);
3948c2ecf20Sopenharmony_ci	}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	if (is_address_size) {
3978c2ecf20Sopenharmony_ci		uma_cfg |= ilog2(op->cmd.buswidth);
3988c2ecf20Sopenharmony_ci		uma_cfg |= ilog2(op->addr.buswidth) <<
3998c2ecf20Sopenharmony_ci			NPCM_FIU_UMA_CFG_ADBPCK_SHIFT;
4008c2ecf20Sopenharmony_ci		uma_cfg |= ilog2(op->data.buswidth) <<
4018c2ecf20Sopenharmony_ci			NPCM_FIU_UMA_CFG_WDBPCK_SHIFT;
4028c2ecf20Sopenharmony_ci		uma_cfg |= op->addr.nbytes << NPCM_FIU_UMA_CFG_ADDSIZ_SHIFT;
4038c2ecf20Sopenharmony_ci		regmap_write(fiu->regmap, NPCM_FIU_UMA_ADDR, op->addr.val);
4048c2ecf20Sopenharmony_ci	} else {
4058c2ecf20Sopenharmony_ci		regmap_write(fiu->regmap, NPCM_FIU_UMA_ADDR, 0x0);
4068c2ecf20Sopenharmony_ci	}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	uma_cfg |= (data_size << NPCM_FIU_UMA_CFG_WDATSIZ_SHIFT);
4098c2ecf20Sopenharmony_ci	regmap_write(fiu->regmap, NPCM_FIU_UMA_CFG, uma_cfg);
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	regmap_write_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
4128c2ecf20Sopenharmony_ci			  NPCM_FIU_UMA_CTS_EXEC_DONE,
4138c2ecf20Sopenharmony_ci			  NPCM_FIU_UMA_CTS_EXEC_DONE);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	return regmap_read_poll_timeout(fiu->regmap, NPCM_FIU_UMA_CTS, val,
4168c2ecf20Sopenharmony_ci				       (!(val & NPCM_FIU_UMA_CTS_EXEC_DONE)), 0,
4178c2ecf20Sopenharmony_ci					UMA_MICRO_SEC_TIMEOUT);
4188c2ecf20Sopenharmony_ci}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_cistatic int npcm_fiu_manualwrite(struct spi_mem *mem,
4218c2ecf20Sopenharmony_ci				const struct spi_mem_op *op)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	struct npcm_fiu_spi *fiu =
4248c2ecf20Sopenharmony_ci		spi_controller_get_devdata(mem->spi->master);
4258c2ecf20Sopenharmony_ci	u8 *data = (u8 *)op->data.buf.out;
4268c2ecf20Sopenharmony_ci	u32 num_data_chunks;
4278c2ecf20Sopenharmony_ci	u32 remain_data;
4288c2ecf20Sopenharmony_ci	u32 idx = 0;
4298c2ecf20Sopenharmony_ci	int ret;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	num_data_chunks  = op->data.nbytes / CHUNK_SIZE;
4328c2ecf20Sopenharmony_ci	remain_data  = op->data.nbytes % CHUNK_SIZE;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
4358c2ecf20Sopenharmony_ci			   NPCM_FIU_UMA_CTS_DEV_NUM,
4368c2ecf20Sopenharmony_ci			   (mem->spi->chip_select <<
4378c2ecf20Sopenharmony_ci			    NPCM_FIU_UMA_CTS_DEV_NUM_SHIFT));
4388c2ecf20Sopenharmony_ci	regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
4398c2ecf20Sopenharmony_ci			   NPCM_FIU_UMA_CTS_SW_CS, 0);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	ret = npcm_fiu_uma_write(mem, op, op->cmd.opcode, true, NULL, 0);
4428c2ecf20Sopenharmony_ci	if (ret)
4438c2ecf20Sopenharmony_ci		return ret;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	/* Starting the data writing loop in multiples of 8 */
4468c2ecf20Sopenharmony_ci	for (idx = 0; idx < num_data_chunks; ++idx) {
4478c2ecf20Sopenharmony_ci		ret = npcm_fiu_uma_write(mem, op, data[0], false,
4488c2ecf20Sopenharmony_ci					 &data[1], CHUNK_SIZE - 1);
4498c2ecf20Sopenharmony_ci		if (ret)
4508c2ecf20Sopenharmony_ci			return ret;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci		data += CHUNK_SIZE;
4538c2ecf20Sopenharmony_ci	}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	/* Handling chunk remains */
4568c2ecf20Sopenharmony_ci	if (remain_data > 0) {
4578c2ecf20Sopenharmony_ci		ret = npcm_fiu_uma_write(mem, op, data[0], false,
4588c2ecf20Sopenharmony_ci					 &data[1], remain_data - 1);
4598c2ecf20Sopenharmony_ci		if (ret)
4608c2ecf20Sopenharmony_ci			return ret;
4618c2ecf20Sopenharmony_ci	}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
4648c2ecf20Sopenharmony_ci			   NPCM_FIU_UMA_CTS_SW_CS, NPCM_FIU_UMA_CTS_SW_CS);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	return 0;
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_cistatic int npcm_fiu_read(struct spi_mem *mem, const struct spi_mem_op *op)
4708c2ecf20Sopenharmony_ci{
4718c2ecf20Sopenharmony_ci	u8 *data = op->data.buf.in;
4728c2ecf20Sopenharmony_ci	int i, readlen, currlen;
4738c2ecf20Sopenharmony_ci	u8 *buf_ptr;
4748c2ecf20Sopenharmony_ci	u32 addr;
4758c2ecf20Sopenharmony_ci	int ret;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	i = 0;
4788c2ecf20Sopenharmony_ci	currlen = op->data.nbytes;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	do {
4818c2ecf20Sopenharmony_ci		addr = ((u32)op->addr.val + i);
4828c2ecf20Sopenharmony_ci		if (currlen < 16)
4838c2ecf20Sopenharmony_ci			readlen = currlen;
4848c2ecf20Sopenharmony_ci		else
4858c2ecf20Sopenharmony_ci			readlen = 16;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci		buf_ptr = data + i;
4888c2ecf20Sopenharmony_ci		ret = npcm_fiu_uma_read(mem, op, addr, true, buf_ptr,
4898c2ecf20Sopenharmony_ci					readlen);
4908c2ecf20Sopenharmony_ci		if (ret)
4918c2ecf20Sopenharmony_ci			return ret;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci		i += readlen;
4948c2ecf20Sopenharmony_ci		currlen -= 16;
4958c2ecf20Sopenharmony_ci	} while (currlen > 0);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	return 0;
4988c2ecf20Sopenharmony_ci}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_cistatic void npcm_fiux_set_direct_wr(struct npcm_fiu_spi *fiu)
5018c2ecf20Sopenharmony_ci{
5028c2ecf20Sopenharmony_ci	regmap_write(fiu->regmap, NPCM_FIU_DWR_CFG,
5038c2ecf20Sopenharmony_ci		     NPCM_FIU_DWR_16_BYTE_BURST);
5048c2ecf20Sopenharmony_ci	regmap_update_bits(fiu->regmap, NPCM_FIU_DWR_CFG,
5058c2ecf20Sopenharmony_ci			   NPCM_FIU_DWR_CFG_ABPCK,
5068c2ecf20Sopenharmony_ci			   DWR_ABPCK_4_BIT_PER_CLK << NPCM_FIU_DWR_ABPCK_SHIFT);
5078c2ecf20Sopenharmony_ci	regmap_update_bits(fiu->regmap, NPCM_FIU_DWR_CFG,
5088c2ecf20Sopenharmony_ci			   NPCM_FIU_DWR_CFG_DBPCK,
5098c2ecf20Sopenharmony_ci			   DWR_DBPCK_4_BIT_PER_CLK << NPCM_FIU_DWR_DBPCK_SHIFT);
5108c2ecf20Sopenharmony_ci}
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_cistatic void npcm_fiux_set_direct_rd(struct npcm_fiu_spi *fiu)
5138c2ecf20Sopenharmony_ci{
5148c2ecf20Sopenharmony_ci	u32 rx_dummy = 0;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	regmap_write(fiu->regmap, NPCM_FIU_DRD_CFG,
5178c2ecf20Sopenharmony_ci		     NPCM_FIU_DRD_16_BYTE_BURST);
5188c2ecf20Sopenharmony_ci	regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
5198c2ecf20Sopenharmony_ci			   NPCM_FIU_DRD_CFG_ACCTYPE,
5208c2ecf20Sopenharmony_ci			   DRD_SPI_X_MODE << NPCM_FIU_DRD_ACCTYPE_SHIFT);
5218c2ecf20Sopenharmony_ci	regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
5228c2ecf20Sopenharmony_ci			   NPCM_FIU_DRD_CFG_DBW,
5238c2ecf20Sopenharmony_ci			   rx_dummy << NPCM_FIU_DRD_DBW_SHIFT);
5248c2ecf20Sopenharmony_ci}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_cistatic int npcm_fiu_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
5278c2ecf20Sopenharmony_ci{
5288c2ecf20Sopenharmony_ci	struct npcm_fiu_spi *fiu =
5298c2ecf20Sopenharmony_ci		spi_controller_get_devdata(mem->spi->master);
5308c2ecf20Sopenharmony_ci	struct npcm_fiu_chip *chip = &fiu->chip[mem->spi->chip_select];
5318c2ecf20Sopenharmony_ci	int ret = 0;
5328c2ecf20Sopenharmony_ci	u8 *buf;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	dev_dbg(fiu->dev, "cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n",
5358c2ecf20Sopenharmony_ci		op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
5368c2ecf20Sopenharmony_ci		op->dummy.buswidth, op->data.buswidth, op->addr.val,
5378c2ecf20Sopenharmony_ci		op->data.nbytes);
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	if (fiu->spix_mode || op->addr.nbytes > 4)
5408c2ecf20Sopenharmony_ci		return -ENOTSUPP;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	if (fiu->clkrate != chip->clkrate) {
5438c2ecf20Sopenharmony_ci		ret = clk_set_rate(fiu->clk, chip->clkrate);
5448c2ecf20Sopenharmony_ci		if (ret < 0)
5458c2ecf20Sopenharmony_ci			dev_warn(fiu->dev, "Failed setting %lu frequency, stay at %lu frequency\n",
5468c2ecf20Sopenharmony_ci				 chip->clkrate, fiu->clkrate);
5478c2ecf20Sopenharmony_ci		else
5488c2ecf20Sopenharmony_ci			fiu->clkrate = chip->clkrate;
5498c2ecf20Sopenharmony_ci	}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	if (op->data.dir == SPI_MEM_DATA_IN) {
5528c2ecf20Sopenharmony_ci		if (!op->addr.nbytes) {
5538c2ecf20Sopenharmony_ci			buf = op->data.buf.in;
5548c2ecf20Sopenharmony_ci			ret = npcm_fiu_uma_read(mem, op, op->addr.val, false,
5558c2ecf20Sopenharmony_ci						buf, op->data.nbytes);
5568c2ecf20Sopenharmony_ci		} else {
5578c2ecf20Sopenharmony_ci			ret = npcm_fiu_read(mem, op);
5588c2ecf20Sopenharmony_ci		}
5598c2ecf20Sopenharmony_ci	} else  {
5608c2ecf20Sopenharmony_ci		if (!op->addr.nbytes && !op->data.nbytes)
5618c2ecf20Sopenharmony_ci			ret = npcm_fiu_uma_write(mem, op, op->cmd.opcode, false,
5628c2ecf20Sopenharmony_ci						 NULL, 0);
5638c2ecf20Sopenharmony_ci		if (op->addr.nbytes && !op->data.nbytes) {
5648c2ecf20Sopenharmony_ci			int i;
5658c2ecf20Sopenharmony_ci			u8 buf_addr[4];
5668c2ecf20Sopenharmony_ci			u32 addr = op->addr.val;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci			for (i = op->addr.nbytes - 1; i >= 0; i--) {
5698c2ecf20Sopenharmony_ci				buf_addr[i] = addr & 0xff;
5708c2ecf20Sopenharmony_ci				addr >>= 8;
5718c2ecf20Sopenharmony_ci			}
5728c2ecf20Sopenharmony_ci			ret = npcm_fiu_uma_write(mem, op, op->cmd.opcode, false,
5738c2ecf20Sopenharmony_ci						 buf_addr, op->addr.nbytes);
5748c2ecf20Sopenharmony_ci		}
5758c2ecf20Sopenharmony_ci		if (!op->addr.nbytes && op->data.nbytes)
5768c2ecf20Sopenharmony_ci			ret = npcm_fiu_uma_write(mem, op, op->cmd.opcode, false,
5778c2ecf20Sopenharmony_ci						 (u8 *)op->data.buf.out,
5788c2ecf20Sopenharmony_ci						 op->data.nbytes);
5798c2ecf20Sopenharmony_ci		if (op->addr.nbytes && op->data.nbytes)
5808c2ecf20Sopenharmony_ci			ret = npcm_fiu_manualwrite(mem, op);
5818c2ecf20Sopenharmony_ci	}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	return ret;
5848c2ecf20Sopenharmony_ci}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_cistatic int npcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc)
5878c2ecf20Sopenharmony_ci{
5888c2ecf20Sopenharmony_ci	struct npcm_fiu_spi *fiu =
5898c2ecf20Sopenharmony_ci		spi_controller_get_devdata(desc->mem->spi->master);
5908c2ecf20Sopenharmony_ci	struct npcm_fiu_chip *chip = &fiu->chip[desc->mem->spi->chip_select];
5918c2ecf20Sopenharmony_ci	struct regmap *gcr_regmap;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	if (!fiu->res_mem) {
5948c2ecf20Sopenharmony_ci		dev_warn(fiu->dev, "Reserved memory not defined, direct read disabled\n");
5958c2ecf20Sopenharmony_ci		desc->nodirmap = true;
5968c2ecf20Sopenharmony_ci		return 0;
5978c2ecf20Sopenharmony_ci	}
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	if (!fiu->spix_mode &&
6008c2ecf20Sopenharmony_ci	    desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) {
6018c2ecf20Sopenharmony_ci		desc->nodirmap = true;
6028c2ecf20Sopenharmony_ci		return 0;
6038c2ecf20Sopenharmony_ci	}
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	if (!chip->flash_region_mapped_ptr) {
6068c2ecf20Sopenharmony_ci		chip->flash_region_mapped_ptr =
6078c2ecf20Sopenharmony_ci			devm_ioremap(fiu->dev, (fiu->res_mem->start +
6088c2ecf20Sopenharmony_ci							(fiu->info->max_map_size *
6098c2ecf20Sopenharmony_ci						    desc->mem->spi->chip_select)),
6108c2ecf20Sopenharmony_ci					     (u32)desc->info.length);
6118c2ecf20Sopenharmony_ci		if (!chip->flash_region_mapped_ptr) {
6128c2ecf20Sopenharmony_ci			dev_warn(fiu->dev, "Error mapping memory region, direct read disabled\n");
6138c2ecf20Sopenharmony_ci			desc->nodirmap = true;
6148c2ecf20Sopenharmony_ci			return 0;
6158c2ecf20Sopenharmony_ci		}
6168c2ecf20Sopenharmony_ci	}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	if (of_device_is_compatible(fiu->dev->of_node, "nuvoton,npcm750-fiu")) {
6198c2ecf20Sopenharmony_ci		gcr_regmap =
6208c2ecf20Sopenharmony_ci			syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr");
6218c2ecf20Sopenharmony_ci		if (IS_ERR(gcr_regmap)) {
6228c2ecf20Sopenharmony_ci			dev_warn(fiu->dev, "Didn't find nuvoton,npcm750-gcr, direct read disabled\n");
6238c2ecf20Sopenharmony_ci			desc->nodirmap = true;
6248c2ecf20Sopenharmony_ci			return 0;
6258c2ecf20Sopenharmony_ci		}
6268c2ecf20Sopenharmony_ci		regmap_update_bits(gcr_regmap, NPCM7XX_INTCR3_OFFSET,
6278c2ecf20Sopenharmony_ci				   NPCM7XX_INTCR3_FIU_FIX,
6288c2ecf20Sopenharmony_ci				   NPCM7XX_INTCR3_FIU_FIX);
6298c2ecf20Sopenharmony_ci	}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) {
6328c2ecf20Sopenharmony_ci		if (!fiu->spix_mode)
6338c2ecf20Sopenharmony_ci			npcm_fiu_set_drd(fiu, &desc->info.op_tmpl);
6348c2ecf20Sopenharmony_ci		else
6358c2ecf20Sopenharmony_ci			npcm_fiux_set_direct_rd(fiu);
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	} else {
6388c2ecf20Sopenharmony_ci		npcm_fiux_set_direct_wr(fiu);
6398c2ecf20Sopenharmony_ci	}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	return 0;
6428c2ecf20Sopenharmony_ci}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_cistatic int npcm_fiu_setup(struct spi_device *spi)
6458c2ecf20Sopenharmony_ci{
6468c2ecf20Sopenharmony_ci	struct spi_controller *ctrl = spi->master;
6478c2ecf20Sopenharmony_ci	struct npcm_fiu_spi *fiu = spi_controller_get_devdata(ctrl);
6488c2ecf20Sopenharmony_ci	struct npcm_fiu_chip *chip;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	chip = &fiu->chip[spi->chip_select];
6518c2ecf20Sopenharmony_ci	chip->fiu = fiu;
6528c2ecf20Sopenharmony_ci	chip->chipselect = spi->chip_select;
6538c2ecf20Sopenharmony_ci	chip->clkrate = spi->max_speed_hz;
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	fiu->clkrate = clk_get_rate(fiu->clk);
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	return 0;
6588c2ecf20Sopenharmony_ci}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_cistatic const struct spi_controller_mem_ops npcm_fiu_mem_ops = {
6618c2ecf20Sopenharmony_ci	.exec_op = npcm_fiu_exec_op,
6628c2ecf20Sopenharmony_ci	.dirmap_create = npcm_fiu_dirmap_create,
6638c2ecf20Sopenharmony_ci	.dirmap_read = npcm_fiu_direct_read,
6648c2ecf20Sopenharmony_ci	.dirmap_write = npcm_fiu_direct_write,
6658c2ecf20Sopenharmony_ci};
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_cistatic const struct of_device_id npcm_fiu_dt_ids[] = {
6688c2ecf20Sopenharmony_ci	{ .compatible = "nuvoton,npcm750-fiu", .data = &npxm7xx_fiu_data  },
6698c2ecf20Sopenharmony_ci	{ /* sentinel */ }
6708c2ecf20Sopenharmony_ci};
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_cistatic int npcm_fiu_probe(struct platform_device *pdev)
6738c2ecf20Sopenharmony_ci{
6748c2ecf20Sopenharmony_ci	const struct fiu_data *fiu_data_match;
6758c2ecf20Sopenharmony_ci	const struct of_device_id *match;
6768c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
6778c2ecf20Sopenharmony_ci	struct spi_controller *ctrl;
6788c2ecf20Sopenharmony_ci	struct npcm_fiu_spi *fiu;
6798c2ecf20Sopenharmony_ci	void __iomem *regbase;
6808c2ecf20Sopenharmony_ci	struct resource *res;
6818c2ecf20Sopenharmony_ci	int id, ret;
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	ctrl = devm_spi_alloc_master(dev, sizeof(*fiu));
6848c2ecf20Sopenharmony_ci	if (!ctrl)
6858c2ecf20Sopenharmony_ci		return -ENOMEM;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	fiu = spi_controller_get_devdata(ctrl);
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	match = of_match_device(npcm_fiu_dt_ids, dev);
6908c2ecf20Sopenharmony_ci	if (!match || !match->data) {
6918c2ecf20Sopenharmony_ci		dev_err(dev, "No compatible OF match\n");
6928c2ecf20Sopenharmony_ci		return -ENODEV;
6938c2ecf20Sopenharmony_ci	}
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	fiu_data_match = match->data;
6968c2ecf20Sopenharmony_ci	id = of_alias_get_id(dev->of_node, "fiu");
6978c2ecf20Sopenharmony_ci	if (id < 0 || id >= fiu_data_match->fiu_max) {
6988c2ecf20Sopenharmony_ci		dev_err(dev, "Invalid platform device id: %d\n", id);
6998c2ecf20Sopenharmony_ci		return -EINVAL;
7008c2ecf20Sopenharmony_ci	}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	fiu->info = &fiu_data_match->npcm_fiu_data_info[id];
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, fiu);
7058c2ecf20Sopenharmony_ci	fiu->dev = dev;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "control");
7088c2ecf20Sopenharmony_ci	regbase = devm_ioremap_resource(dev, res);
7098c2ecf20Sopenharmony_ci	if (IS_ERR(regbase))
7108c2ecf20Sopenharmony_ci		return PTR_ERR(regbase);
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	fiu->regmap = devm_regmap_init_mmio(dev, regbase,
7138c2ecf20Sopenharmony_ci					    &npcm_mtd_regmap_config);
7148c2ecf20Sopenharmony_ci	if (IS_ERR(fiu->regmap)) {
7158c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to create regmap\n");
7168c2ecf20Sopenharmony_ci		return PTR_ERR(fiu->regmap);
7178c2ecf20Sopenharmony_ci	}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	fiu->res_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
7208c2ecf20Sopenharmony_ci						    "memory");
7218c2ecf20Sopenharmony_ci	fiu->clk = devm_clk_get(dev, NULL);
7228c2ecf20Sopenharmony_ci	if (IS_ERR(fiu->clk))
7238c2ecf20Sopenharmony_ci		return PTR_ERR(fiu->clk);
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	fiu->spix_mode = of_property_read_bool(dev->of_node,
7268c2ecf20Sopenharmony_ci					       "nuvoton,spix-mode");
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, fiu);
7298c2ecf20Sopenharmony_ci	clk_prepare_enable(fiu->clk);
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD
7328c2ecf20Sopenharmony_ci		| SPI_TX_DUAL | SPI_TX_QUAD;
7338c2ecf20Sopenharmony_ci	ctrl->setup = npcm_fiu_setup;
7348c2ecf20Sopenharmony_ci	ctrl->bus_num = -1;
7358c2ecf20Sopenharmony_ci	ctrl->mem_ops = &npcm_fiu_mem_ops;
7368c2ecf20Sopenharmony_ci	ctrl->num_chipselect = fiu->info->max_cs;
7378c2ecf20Sopenharmony_ci	ctrl->dev.of_node = dev->of_node;
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	ret = devm_spi_register_master(dev, ctrl);
7408c2ecf20Sopenharmony_ci	if (ret)
7418c2ecf20Sopenharmony_ci		clk_disable_unprepare(fiu->clk);
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	return ret;
7448c2ecf20Sopenharmony_ci}
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_cistatic int npcm_fiu_remove(struct platform_device *pdev)
7478c2ecf20Sopenharmony_ci{
7488c2ecf20Sopenharmony_ci	struct npcm_fiu_spi *fiu = platform_get_drvdata(pdev);
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	clk_disable_unprepare(fiu->clk);
7518c2ecf20Sopenharmony_ci	return 0;
7528c2ecf20Sopenharmony_ci}
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, npcm_fiu_dt_ids);
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_cistatic struct platform_driver npcm_fiu_driver = {
7578c2ecf20Sopenharmony_ci	.driver = {
7588c2ecf20Sopenharmony_ci		.name	= "NPCM-FIU",
7598c2ecf20Sopenharmony_ci		.bus	= &platform_bus_type,
7608c2ecf20Sopenharmony_ci		.of_match_table = npcm_fiu_dt_ids,
7618c2ecf20Sopenharmony_ci	},
7628c2ecf20Sopenharmony_ci	.probe      = npcm_fiu_probe,
7638c2ecf20Sopenharmony_ci	.remove	    = npcm_fiu_remove,
7648c2ecf20Sopenharmony_ci};
7658c2ecf20Sopenharmony_cimodule_platform_driver(npcm_fiu_driver);
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Nuvoton FLASH Interface Unit SPI Controller Driver");
7688c2ecf20Sopenharmony_ciMODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
7698c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
770