xref: /openbmc/linux/drivers/spi/spi-npcm-fiu.c (revision dd72f9c7e512da377074d47d990564959b772643)
1ace55c41STomer Maimon // SPDX-License-Identifier: GPL-2.0
2ace55c41STomer Maimon // Copyright (c) 2019 Nuvoton Technology corporation.
3ace55c41STomer Maimon 
40ec544ceSAndy Shevchenko #include <linux/bits.h>
5ace55c41STomer Maimon #include <linux/init.h>
6ace55c41STomer Maimon #include <linux/kernel.h>
7ace55c41STomer Maimon #include <linux/device.h>
8ace55c41STomer Maimon #include <linux/module.h>
9ace55c41STomer Maimon #include <linux/ioport.h>
10ace55c41STomer Maimon #include <linux/clk.h>
11ace55c41STomer Maimon #include <linux/platform_device.h>
12ace55c41STomer Maimon #include <linux/io.h>
13ace55c41STomer Maimon #include <linux/vmalloc.h>
14ace55c41STomer Maimon #include <linux/regmap.h>
15749396cbSRob Herring #include <linux/of.h>
16ace55c41STomer Maimon #include <linux/spi/spi-mem.h>
17ace55c41STomer Maimon #include <linux/mfd/syscon.h>
18ace55c41STomer Maimon 
19ace55c41STomer Maimon /* NPCM7xx GCR module */
20ace55c41STomer Maimon #define NPCM7XX_INTCR3_OFFSET		0x9C
21ace55c41STomer Maimon #define NPCM7XX_INTCR3_FIU_FIX		BIT(6)
22ace55c41STomer Maimon 
23ace55c41STomer Maimon /* Flash Interface Unit (FIU) Registers */
24ace55c41STomer Maimon #define NPCM_FIU_DRD_CFG		0x00
25ace55c41STomer Maimon #define NPCM_FIU_DWR_CFG		0x04
26ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG		0x08
27ace55c41STomer Maimon #define NPCM_FIU_UMA_CTS		0x0C
28ace55c41STomer Maimon #define NPCM_FIU_UMA_CMD		0x10
29ace55c41STomer Maimon #define NPCM_FIU_UMA_ADDR		0x14
30ace55c41STomer Maimon #define NPCM_FIU_PRT_CFG		0x18
31ace55c41STomer Maimon #define NPCM_FIU_UMA_DW0		0x20
32ace55c41STomer Maimon #define NPCM_FIU_UMA_DW1		0x24
33ace55c41STomer Maimon #define NPCM_FIU_UMA_DW2		0x28
34ace55c41STomer Maimon #define NPCM_FIU_UMA_DW3		0x2C
35ace55c41STomer Maimon #define NPCM_FIU_UMA_DR0		0x30
36ace55c41STomer Maimon #define NPCM_FIU_UMA_DR1		0x34
37ace55c41STomer Maimon #define NPCM_FIU_UMA_DR2		0x38
38ace55c41STomer Maimon #define NPCM_FIU_UMA_DR3		0x3C
39650b014fSTomer Maimon #define NPCM_FIU_CFG			0x78
40ace55c41STomer Maimon #define NPCM_FIU_MAX_REG_LIMIT		0x80
41ace55c41STomer Maimon 
42ace55c41STomer Maimon /* FIU Direct Read Configuration Register */
43ace55c41STomer Maimon #define NPCM_FIU_DRD_CFG_LCK		BIT(31)
44ace55c41STomer Maimon #define NPCM_FIU_DRD_CFG_R_BURST	GENMASK(25, 24)
45ace55c41STomer Maimon #define NPCM_FIU_DRD_CFG_ADDSIZ		GENMASK(17, 16)
46ace55c41STomer Maimon #define NPCM_FIU_DRD_CFG_DBW		GENMASK(13, 12)
47ace55c41STomer Maimon #define NPCM_FIU_DRD_CFG_ACCTYPE	GENMASK(9, 8)
48ace55c41STomer Maimon #define NPCM_FIU_DRD_CFG_RDCMD		GENMASK(7, 0)
49ace55c41STomer Maimon #define NPCM_FIU_DRD_ADDSIZ_SHIFT	16
50ace55c41STomer Maimon #define NPCM_FIU_DRD_DBW_SHIFT		12
51ace55c41STomer Maimon #define NPCM_FIU_DRD_ACCTYPE_SHIFT	8
52ace55c41STomer Maimon 
53ace55c41STomer Maimon /* FIU Direct Write Configuration Register */
54ace55c41STomer Maimon #define NPCM_FIU_DWR_CFG_LCK		BIT(31)
55ace55c41STomer Maimon #define NPCM_FIU_DWR_CFG_W_BURST	GENMASK(25, 24)
56ace55c41STomer Maimon #define NPCM_FIU_DWR_CFG_ADDSIZ		GENMASK(17, 16)
57ace55c41STomer Maimon #define NPCM_FIU_DWR_CFG_ABPCK		GENMASK(11, 10)
58ace55c41STomer Maimon #define NPCM_FIU_DWR_CFG_DBPCK		GENMASK(9, 8)
59ace55c41STomer Maimon #define NPCM_FIU_DWR_CFG_WRCMD		GENMASK(7, 0)
60ace55c41STomer Maimon #define NPCM_FIU_DWR_ADDSIZ_SHIFT	16
61ace55c41STomer Maimon #define NPCM_FIU_DWR_ABPCK_SHIFT	10
62ace55c41STomer Maimon #define NPCM_FIU_DWR_DBPCK_SHIFT	8
63ace55c41STomer Maimon 
64ace55c41STomer Maimon /* FIU UMA Configuration Register */
65ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_LCK		BIT(31)
66ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_CMMLCK		BIT(30)
67ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_RDATSIZ	GENMASK(28, 24)
68ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_DBSIZ		GENMASK(23, 21)
69ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_WDATSIZ	GENMASK(20, 16)
70ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_ADDSIZ		GENMASK(13, 11)
71ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_CMDSIZ		BIT(10)
72ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_RDBPCK		GENMASK(9, 8)
73ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_DBPCK		GENMASK(7, 6)
74ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_WDBPCK		GENMASK(5, 4)
75ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_ADBPCK		GENMASK(3, 2)
76ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_CMBPCK		GENMASK(1, 0)
77ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_ADBPCK_SHIFT	2
78ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_WDBPCK_SHIFT	4
79ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_DBPCK_SHIFT	6
80ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_RDBPCK_SHIFT	8
81ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_ADDSIZ_SHIFT	11
82ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_WDATSIZ_SHIFT	16
83ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_DBSIZ_SHIFT	21
84ace55c41STomer Maimon #define NPCM_FIU_UMA_CFG_RDATSIZ_SHIFT	24
85ace55c41STomer Maimon 
86ace55c41STomer Maimon /* FIU UMA Control and Status Register */
87ace55c41STomer Maimon #define NPCM_FIU_UMA_CTS_RDYIE		BIT(25)
88ace55c41STomer Maimon #define NPCM_FIU_UMA_CTS_RDYST		BIT(24)
89ace55c41STomer Maimon #define NPCM_FIU_UMA_CTS_SW_CS		BIT(16)
90ace55c41STomer Maimon #define NPCM_FIU_UMA_CTS_DEV_NUM	GENMASK(9, 8)
91ace55c41STomer Maimon #define NPCM_FIU_UMA_CTS_EXEC_DONE	BIT(0)
92ace55c41STomer Maimon #define NPCM_FIU_UMA_CTS_DEV_NUM_SHIFT	8
93ace55c41STomer Maimon 
94ace55c41STomer Maimon /* FIU UMA Command Register */
95ace55c41STomer Maimon #define NPCM_FIU_UMA_CMD_DUM3		GENMASK(31, 24)
96ace55c41STomer Maimon #define NPCM_FIU_UMA_CMD_DUM2		GENMASK(23, 16)
97ace55c41STomer Maimon #define NPCM_FIU_UMA_CMD_DUM1		GENMASK(15, 8)
98ace55c41STomer Maimon #define NPCM_FIU_UMA_CMD_CMD		GENMASK(7, 0)
99ace55c41STomer Maimon 
100ace55c41STomer Maimon /* FIU UMA Address Register */
101ace55c41STomer Maimon #define NPCM_FIU_UMA_ADDR_UMA_ADDR	GENMASK(31, 0)
102ace55c41STomer Maimon #define NPCM_FIU_UMA_ADDR_AB3		GENMASK(31, 24)
103ace55c41STomer Maimon #define NPCM_FIU_UMA_ADDR_AB2		GENMASK(23, 16)
104ace55c41STomer Maimon #define NPCM_FIU_UMA_ADDR_AB1		GENMASK(15, 8)
105ace55c41STomer Maimon #define NPCM_FIU_UMA_ADDR_AB0		GENMASK(7, 0)
106ace55c41STomer Maimon 
107ace55c41STomer Maimon /* FIU UMA Write Data Bytes 0-3 Register */
108ace55c41STomer Maimon #define NPCM_FIU_UMA_DW0_WB3		GENMASK(31, 24)
109ace55c41STomer Maimon #define NPCM_FIU_UMA_DW0_WB2		GENMASK(23, 16)
110ace55c41STomer Maimon #define NPCM_FIU_UMA_DW0_WB1		GENMASK(15, 8)
111ace55c41STomer Maimon #define NPCM_FIU_UMA_DW0_WB0		GENMASK(7, 0)
112ace55c41STomer Maimon 
113ace55c41STomer Maimon /* FIU UMA Write Data Bytes 4-7 Register */
114ace55c41STomer Maimon #define NPCM_FIU_UMA_DW1_WB7		GENMASK(31, 24)
115ace55c41STomer Maimon #define NPCM_FIU_UMA_DW1_WB6		GENMASK(23, 16)
116ace55c41STomer Maimon #define NPCM_FIU_UMA_DW1_WB5		GENMASK(15, 8)
117ace55c41STomer Maimon #define NPCM_FIU_UMA_DW1_WB4		GENMASK(7, 0)
118ace55c41STomer Maimon 
119ace55c41STomer Maimon /* FIU UMA Write Data Bytes 8-11 Register */
120ace55c41STomer Maimon #define NPCM_FIU_UMA_DW2_WB11		GENMASK(31, 24)
121ace55c41STomer Maimon #define NPCM_FIU_UMA_DW2_WB10		GENMASK(23, 16)
122ace55c41STomer Maimon #define NPCM_FIU_UMA_DW2_WB9		GENMASK(15, 8)
123ace55c41STomer Maimon #define NPCM_FIU_UMA_DW2_WB8		GENMASK(7, 0)
124ace55c41STomer Maimon 
125ace55c41STomer Maimon /* FIU UMA Write Data Bytes 12-15 Register */
126ace55c41STomer Maimon #define NPCM_FIU_UMA_DW3_WB15		GENMASK(31, 24)
127ace55c41STomer Maimon #define NPCM_FIU_UMA_DW3_WB14		GENMASK(23, 16)
128ace55c41STomer Maimon #define NPCM_FIU_UMA_DW3_WB13		GENMASK(15, 8)
129ace55c41STomer Maimon #define NPCM_FIU_UMA_DW3_WB12		GENMASK(7, 0)
130ace55c41STomer Maimon 
131ace55c41STomer Maimon /* FIU UMA Read Data Bytes 0-3 Register */
132ace55c41STomer Maimon #define NPCM_FIU_UMA_DR0_RB3		GENMASK(31, 24)
133ace55c41STomer Maimon #define NPCM_FIU_UMA_DR0_RB2		GENMASK(23, 16)
134ace55c41STomer Maimon #define NPCM_FIU_UMA_DR0_RB1		GENMASK(15, 8)
135ace55c41STomer Maimon #define NPCM_FIU_UMA_DR0_RB0		GENMASK(7, 0)
136ace55c41STomer Maimon 
137ace55c41STomer Maimon /* FIU UMA Read Data Bytes 4-7 Register */
138ace55c41STomer Maimon #define NPCM_FIU_UMA_DR1_RB15		GENMASK(31, 24)
139ace55c41STomer Maimon #define NPCM_FIU_UMA_DR1_RB14		GENMASK(23, 16)
140ace55c41STomer Maimon #define NPCM_FIU_UMA_DR1_RB13		GENMASK(15, 8)
141ace55c41STomer Maimon #define NPCM_FIU_UMA_DR1_RB12		GENMASK(7, 0)
142ace55c41STomer Maimon 
143ace55c41STomer Maimon /* FIU UMA Read Data Bytes 8-11 Register */
144ace55c41STomer Maimon #define NPCM_FIU_UMA_DR2_RB15		GENMASK(31, 24)
145ace55c41STomer Maimon #define NPCM_FIU_UMA_DR2_RB14		GENMASK(23, 16)
146ace55c41STomer Maimon #define NPCM_FIU_UMA_DR2_RB13		GENMASK(15, 8)
147ace55c41STomer Maimon #define NPCM_FIU_UMA_DR2_RB12		GENMASK(7, 0)
148ace55c41STomer Maimon 
149ace55c41STomer Maimon /* FIU UMA Read Data Bytes 12-15 Register */
150ace55c41STomer Maimon #define NPCM_FIU_UMA_DR3_RB15		GENMASK(31, 24)
151ace55c41STomer Maimon #define NPCM_FIU_UMA_DR3_RB14		GENMASK(23, 16)
152ace55c41STomer Maimon #define NPCM_FIU_UMA_DR3_RB13		GENMASK(15, 8)
153ace55c41STomer Maimon #define NPCM_FIU_UMA_DR3_RB12		GENMASK(7, 0)
154ace55c41STomer Maimon 
155650b014fSTomer Maimon /* FIU Configuration Register */
156650b014fSTomer Maimon #define NPCM_FIU_CFG_FIU_FIX		BIT(31)
157650b014fSTomer Maimon 
158ace55c41STomer Maimon /* FIU Read Mode */
159ace55c41STomer Maimon enum {
160ace55c41STomer Maimon 	DRD_SINGLE_WIRE_MODE	= 0,
161ace55c41STomer Maimon 	DRD_DUAL_IO_MODE	= 1,
162ace55c41STomer Maimon 	DRD_QUAD_IO_MODE	= 2,
163ace55c41STomer Maimon 	DRD_SPI_X_MODE		= 3,
164ace55c41STomer Maimon };
165ace55c41STomer Maimon 
166ace55c41STomer Maimon enum {
167ace55c41STomer Maimon 	DWR_ABPCK_BIT_PER_CLK	= 0,
168ace55c41STomer Maimon 	DWR_ABPCK_2_BIT_PER_CLK	= 1,
169ace55c41STomer Maimon 	DWR_ABPCK_4_BIT_PER_CLK	= 2,
170ace55c41STomer Maimon };
171ace55c41STomer Maimon 
172ace55c41STomer Maimon enum {
173ace55c41STomer Maimon 	DWR_DBPCK_BIT_PER_CLK	= 0,
174ace55c41STomer Maimon 	DWR_DBPCK_2_BIT_PER_CLK	= 1,
175ace55c41STomer Maimon 	DWR_DBPCK_4_BIT_PER_CLK	= 2,
176ace55c41STomer Maimon };
177ace55c41STomer Maimon 
178ace55c41STomer Maimon #define NPCM_FIU_DRD_16_BYTE_BURST	0x3000000
179ace55c41STomer Maimon #define NPCM_FIU_DWR_16_BYTE_BURST	0x3000000
180ace55c41STomer Maimon 
181ace55c41STomer Maimon #define MAP_SIZE_128MB			0x8000000
182ace55c41STomer Maimon #define MAP_SIZE_16MB			0x1000000
183ace55c41STomer Maimon #define MAP_SIZE_8MB			0x800000
184ace55c41STomer Maimon 
185ace55c41STomer Maimon #define FIU_DRD_MAX_DUMMY_NUMBER	3
186ace55c41STomer Maimon #define NPCM_MAX_CHIP_NUM		4
187ace55c41STomer Maimon #define CHUNK_SIZE			16
188ace55c41STomer Maimon #define UMA_MICRO_SEC_TIMEOUT		150
189ace55c41STomer Maimon 
190ace55c41STomer Maimon enum {
191ace55c41STomer Maimon 	FIU0 = 0,
192ace55c41STomer Maimon 	FIU3,
193ace55c41STomer Maimon 	FIUX,
194650b014fSTomer Maimon 	FIU1,
195ace55c41STomer Maimon };
196ace55c41STomer Maimon 
197ace55c41STomer Maimon struct npcm_fiu_info {
198ace55c41STomer Maimon 	char *name;
199ace55c41STomer Maimon 	u32 fiu_id;
200ace55c41STomer Maimon 	u32 max_map_size;
201ace55c41STomer Maimon 	u32 max_cs;
202ace55c41STomer Maimon };
203ace55c41STomer Maimon 
204ace55c41STomer Maimon struct fiu_data {
205ace55c41STomer Maimon 	const struct npcm_fiu_info *npcm_fiu_data_info;
206ace55c41STomer Maimon 	int fiu_max;
207ace55c41STomer Maimon };
208ace55c41STomer Maimon 
209b15e3bc7SJonathan Neuschäfer static const struct npcm_fiu_info npcm7xx_fiu_info[] = {
210ace55c41STomer Maimon 	{.name = "FIU0", .fiu_id = FIU0,
211ace55c41STomer Maimon 		.max_map_size = MAP_SIZE_128MB, .max_cs = 2},
212ace55c41STomer Maimon 	{.name = "FIU3", .fiu_id = FIU3,
213ace55c41STomer Maimon 		.max_map_size = MAP_SIZE_128MB, .max_cs = 4},
214ace55c41STomer Maimon 	{.name = "FIUX", .fiu_id = FIUX,
215ace55c41STomer Maimon 		.max_map_size = MAP_SIZE_16MB, .max_cs = 2} };
216ace55c41STomer Maimon 
217b15e3bc7SJonathan Neuschäfer static const struct fiu_data npcm7xx_fiu_data = {
218b15e3bc7SJonathan Neuschäfer 	.npcm_fiu_data_info = npcm7xx_fiu_info,
219ace55c41STomer Maimon 	.fiu_max = 3,
220ace55c41STomer Maimon };
221ace55c41STomer Maimon 
222650b014fSTomer Maimon static const struct npcm_fiu_info npxm8xx_fiu_info[] = {
223650b014fSTomer Maimon 	{.name = "FIU0", .fiu_id = FIU0,
224650b014fSTomer Maimon 		.max_map_size = MAP_SIZE_128MB, .max_cs = 2},
225650b014fSTomer Maimon 	{.name = "FIU3", .fiu_id = FIU3,
226650b014fSTomer Maimon 		.max_map_size = MAP_SIZE_128MB, .max_cs = 4},
227650b014fSTomer Maimon 	{.name = "FIUX", .fiu_id = FIUX,
228650b014fSTomer Maimon 		.max_map_size = MAP_SIZE_16MB, .max_cs = 2},
229650b014fSTomer Maimon 	{.name = "FIU1", .fiu_id = FIU1,
230650b014fSTomer Maimon 		.max_map_size = MAP_SIZE_16MB, .max_cs = 4} };
231650b014fSTomer Maimon 
232650b014fSTomer Maimon static const struct fiu_data npxm8xx_fiu_data = {
233650b014fSTomer Maimon 	.npcm_fiu_data_info = npxm8xx_fiu_info,
234650b014fSTomer Maimon 	.fiu_max = 4,
235650b014fSTomer Maimon };
236650b014fSTomer Maimon 
237ace55c41STomer Maimon struct npcm_fiu_spi;
238ace55c41STomer Maimon 
239ace55c41STomer Maimon struct npcm_fiu_chip {
240ace55c41STomer Maimon 	void __iomem *flash_region_mapped_ptr;
241ace55c41STomer Maimon 	struct npcm_fiu_spi *fiu;
242ace55c41STomer Maimon 	unsigned long clkrate;
243ace55c41STomer Maimon 	u32 chipselect;
244ace55c41STomer Maimon };
245ace55c41STomer Maimon 
246ace55c41STomer Maimon struct npcm_fiu_spi {
247ace55c41STomer Maimon 	struct npcm_fiu_chip chip[NPCM_MAX_CHIP_NUM];
248ace55c41STomer Maimon 	const struct npcm_fiu_info *info;
249ace55c41STomer Maimon 	struct spi_mem_op drd_op;
250ace55c41STomer Maimon 	struct resource *res_mem;
251ace55c41STomer Maimon 	struct regmap *regmap;
252ace55c41STomer Maimon 	unsigned long clkrate;
253ace55c41STomer Maimon 	struct device *dev;
254ace55c41STomer Maimon 	struct clk *clk;
255ace55c41STomer Maimon 	bool spix_mode;
256ace55c41STomer Maimon };
257ace55c41STomer Maimon 
258ace55c41STomer Maimon static const struct regmap_config npcm_mtd_regmap_config = {
259ace55c41STomer Maimon 	.reg_bits = 32,
260ace55c41STomer Maimon 	.val_bits = 32,
261ace55c41STomer Maimon 	.reg_stride = 4,
262ace55c41STomer Maimon 	.max_register = NPCM_FIU_MAX_REG_LIMIT,
263ace55c41STomer Maimon };
264ace55c41STomer Maimon 
npcm_fiu_set_drd(struct npcm_fiu_spi * fiu,const struct spi_mem_op * op)265ace55c41STomer Maimon static void npcm_fiu_set_drd(struct npcm_fiu_spi *fiu,
266ace55c41STomer Maimon 			     const struct spi_mem_op *op)
267ace55c41STomer Maimon {
268ace55c41STomer Maimon 	regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
269ace55c41STomer Maimon 			   NPCM_FIU_DRD_CFG_ACCTYPE,
270ace55c41STomer Maimon 			   ilog2(op->addr.buswidth) <<
271ace55c41STomer Maimon 			   NPCM_FIU_DRD_ACCTYPE_SHIFT);
272ace55c41STomer Maimon 	fiu->drd_op.addr.buswidth = op->addr.buswidth;
273ace55c41STomer Maimon 	regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
274ace55c41STomer Maimon 			   NPCM_FIU_DRD_CFG_DBW,
2757c3193f7STomer Maimon 			   op->dummy.nbytes << NPCM_FIU_DRD_DBW_SHIFT);
276ace55c41STomer Maimon 	fiu->drd_op.dummy.nbytes = op->dummy.nbytes;
277ace55c41STomer Maimon 	regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
278ace55c41STomer Maimon 			   NPCM_FIU_DRD_CFG_RDCMD, op->cmd.opcode);
279ace55c41STomer Maimon 	fiu->drd_op.cmd.opcode = op->cmd.opcode;
280ace55c41STomer Maimon 	regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
281ace55c41STomer Maimon 			   NPCM_FIU_DRD_CFG_ADDSIZ,
282ace55c41STomer Maimon 			   (op->addr.nbytes - 3) << NPCM_FIU_DRD_ADDSIZ_SHIFT);
283ace55c41STomer Maimon 	fiu->drd_op.addr.nbytes = op->addr.nbytes;
284ace55c41STomer Maimon }
285ace55c41STomer Maimon 
npcm_fiu_direct_read(struct spi_mem_dirmap_desc * desc,u64 offs,size_t len,void * buf)286ace55c41STomer Maimon static ssize_t npcm_fiu_direct_read(struct spi_mem_dirmap_desc *desc,
287ace55c41STomer Maimon 				    u64 offs, size_t len, void *buf)
288ace55c41STomer Maimon {
289ace55c41STomer Maimon 	struct npcm_fiu_spi *fiu =
2901f6c80a7SYang Yingliang 		spi_controller_get_devdata(desc->mem->spi->controller);
2919e264f3fSAmit Kumar Mahapatra via Alsa-devel 	struct npcm_fiu_chip *chip = &fiu->chip[spi_get_chipselect(desc->mem->spi, 0)];
292ace55c41STomer Maimon 	void __iomem *src = (void __iomem *)(chip->flash_region_mapped_ptr +
293ace55c41STomer Maimon 					     offs);
294ace55c41STomer Maimon 	u8 *buf_rx = buf;
295ace55c41STomer Maimon 	u32 i;
296ace55c41STomer Maimon 
297ace55c41STomer Maimon 	if (fiu->spix_mode) {
298ace55c41STomer Maimon 		for (i = 0 ; i < len ; i++)
299ace55c41STomer Maimon 			*(buf_rx + i) = ioread8(src + i);
300ace55c41STomer Maimon 	} else {
301ace55c41STomer Maimon 		if (desc->info.op_tmpl.addr.buswidth != fiu->drd_op.addr.buswidth ||
302ace55c41STomer Maimon 		    desc->info.op_tmpl.dummy.nbytes != fiu->drd_op.dummy.nbytes ||
303ace55c41STomer Maimon 		    desc->info.op_tmpl.cmd.opcode != fiu->drd_op.cmd.opcode ||
304ace55c41STomer Maimon 		    desc->info.op_tmpl.addr.nbytes != fiu->drd_op.addr.nbytes)
305ace55c41STomer Maimon 			npcm_fiu_set_drd(fiu, &desc->info.op_tmpl);
306ace55c41STomer Maimon 
307ace55c41STomer Maimon 		memcpy_fromio(buf_rx, src, len);
308ace55c41STomer Maimon 	}
309ace55c41STomer Maimon 
310ace55c41STomer Maimon 	return len;
311ace55c41STomer Maimon }
312ace55c41STomer Maimon 
npcm_fiu_direct_write(struct spi_mem_dirmap_desc * desc,u64 offs,size_t len,const void * buf)313ace55c41STomer Maimon static ssize_t npcm_fiu_direct_write(struct spi_mem_dirmap_desc *desc,
314ace55c41STomer Maimon 				     u64 offs, size_t len, const void *buf)
315ace55c41STomer Maimon {
316ace55c41STomer Maimon 	struct npcm_fiu_spi *fiu =
3171f6c80a7SYang Yingliang 		spi_controller_get_devdata(desc->mem->spi->controller);
3189e264f3fSAmit Kumar Mahapatra via Alsa-devel 	struct npcm_fiu_chip *chip = &fiu->chip[spi_get_chipselect(desc->mem->spi, 0)];
319ace55c41STomer Maimon 	void __iomem *dst = (void __iomem *)(chip->flash_region_mapped_ptr +
320ace55c41STomer Maimon 					     offs);
321ace55c41STomer Maimon 	const u8 *buf_tx = buf;
322ace55c41STomer Maimon 	u32 i;
323ace55c41STomer Maimon 
324ace55c41STomer Maimon 	if (fiu->spix_mode)
325ace55c41STomer Maimon 		for (i = 0 ; i < len ; i++)
326ace55c41STomer Maimon 			iowrite8(*(buf_tx + i), dst + i);
327ace55c41STomer Maimon 	else
328ace55c41STomer Maimon 		memcpy_toio(dst, buf_tx, len);
329ace55c41STomer Maimon 
330ace55c41STomer Maimon 	return len;
331ace55c41STomer Maimon }
332ace55c41STomer Maimon 
npcm_fiu_uma_read(struct spi_mem * mem,const struct spi_mem_op * op,u32 addr,bool is_address_size,u8 * data,u32 data_size)333ace55c41STomer Maimon static int npcm_fiu_uma_read(struct spi_mem *mem,
334ace55c41STomer Maimon 			     const struct spi_mem_op *op, u32 addr,
335ace55c41STomer Maimon 			      bool is_address_size, u8 *data, u32 data_size)
336ace55c41STomer Maimon {
337ace55c41STomer Maimon 	struct npcm_fiu_spi *fiu =
3381f6c80a7SYang Yingliang 		spi_controller_get_devdata(mem->spi->controller);
339ace55c41STomer Maimon 	u32 uma_cfg = BIT(10);
340ace55c41STomer Maimon 	u32 data_reg[4];
341ace55c41STomer Maimon 	int ret;
342ace55c41STomer Maimon 	u32 val;
343ace55c41STomer Maimon 	u32 i;
344ace55c41STomer Maimon 
345ace55c41STomer Maimon 	regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
346ace55c41STomer Maimon 			   NPCM_FIU_UMA_CTS_DEV_NUM,
3479e264f3fSAmit Kumar Mahapatra via Alsa-devel 			   (spi_get_chipselect(mem->spi, 0) <<
348ace55c41STomer Maimon 			    NPCM_FIU_UMA_CTS_DEV_NUM_SHIFT));
349ace55c41STomer Maimon 	regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CMD,
350ace55c41STomer Maimon 			   NPCM_FIU_UMA_CMD_CMD, op->cmd.opcode);
351ace55c41STomer Maimon 
352ace55c41STomer Maimon 	if (is_address_size) {
353ace55c41STomer Maimon 		uma_cfg |= ilog2(op->cmd.buswidth);
354ace55c41STomer Maimon 		uma_cfg |= ilog2(op->addr.buswidth)
355ace55c41STomer Maimon 			<< NPCM_FIU_UMA_CFG_ADBPCK_SHIFT;
356*2ec8b010SWilliam A. Kennington III 		if (op->dummy.nbytes)
357ace55c41STomer Maimon 			uma_cfg |= ilog2(op->dummy.buswidth)
358ace55c41STomer Maimon 				<< NPCM_FIU_UMA_CFG_DBPCK_SHIFT;
359ace55c41STomer Maimon 		uma_cfg |= ilog2(op->data.buswidth)
360ace55c41STomer Maimon 			<< NPCM_FIU_UMA_CFG_RDBPCK_SHIFT;
361ace55c41STomer Maimon 		uma_cfg |= op->dummy.nbytes << NPCM_FIU_UMA_CFG_DBSIZ_SHIFT;
362ace55c41STomer Maimon 		uma_cfg |= op->addr.nbytes << NPCM_FIU_UMA_CFG_ADDSIZ_SHIFT;
363ace55c41STomer Maimon 		regmap_write(fiu->regmap, NPCM_FIU_UMA_ADDR, addr);
364ace55c41STomer Maimon 	} else {
365ace55c41STomer Maimon 		regmap_write(fiu->regmap, NPCM_FIU_UMA_ADDR, 0x0);
366ace55c41STomer Maimon 	}
367ace55c41STomer Maimon 
368ace55c41STomer Maimon 	uma_cfg |= data_size << NPCM_FIU_UMA_CFG_RDATSIZ_SHIFT;
369ace55c41STomer Maimon 	regmap_write(fiu->regmap, NPCM_FIU_UMA_CFG, uma_cfg);
370ace55c41STomer Maimon 	regmap_write_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
371ace55c41STomer Maimon 			  NPCM_FIU_UMA_CTS_EXEC_DONE,
372ace55c41STomer Maimon 			  NPCM_FIU_UMA_CTS_EXEC_DONE);
373ace55c41STomer Maimon 	ret = regmap_read_poll_timeout(fiu->regmap, NPCM_FIU_UMA_CTS, val,
374ace55c41STomer Maimon 				       (!(val & NPCM_FIU_UMA_CTS_EXEC_DONE)), 0,
375ace55c41STomer Maimon 				       UMA_MICRO_SEC_TIMEOUT);
376ace55c41STomer Maimon 	if (ret)
377ace55c41STomer Maimon 		return ret;
378ace55c41STomer Maimon 
379ace55c41STomer Maimon 	if (data_size) {
380ace55c41STomer Maimon 		for (i = 0; i < DIV_ROUND_UP(data_size, 4); i++)
381ace55c41STomer Maimon 			regmap_read(fiu->regmap, NPCM_FIU_UMA_DR0 + (i * 4),
382ace55c41STomer Maimon 				    &data_reg[i]);
383ace55c41STomer Maimon 		memcpy(data, data_reg, data_size);
384ace55c41STomer Maimon 	}
385ace55c41STomer Maimon 
386ace55c41STomer Maimon 	return 0;
387ace55c41STomer Maimon }
388ace55c41STomer Maimon 
npcm_fiu_uma_write(struct spi_mem * mem,const struct spi_mem_op * op,u8 cmd,bool is_address_size,u8 * data,u32 data_size)389ace55c41STomer Maimon static int npcm_fiu_uma_write(struct spi_mem *mem,
390ace55c41STomer Maimon 			      const struct spi_mem_op *op, u8 cmd,
391ace55c41STomer Maimon 			      bool is_address_size, u8 *data, u32 data_size)
392ace55c41STomer Maimon {
393ace55c41STomer Maimon 	struct npcm_fiu_spi *fiu =
3941f6c80a7SYang Yingliang 		spi_controller_get_devdata(mem->spi->controller);
395ace55c41STomer Maimon 	u32 uma_cfg = BIT(10);
396ace55c41STomer Maimon 	u32 data_reg[4] = {0};
397ace55c41STomer Maimon 	u32 val;
398ace55c41STomer Maimon 	u32 i;
399ace55c41STomer Maimon 
400ace55c41STomer Maimon 	regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
401ace55c41STomer Maimon 			   NPCM_FIU_UMA_CTS_DEV_NUM,
4029e264f3fSAmit Kumar Mahapatra via Alsa-devel 			   (spi_get_chipselect(mem->spi, 0) <<
403ace55c41STomer Maimon 			    NPCM_FIU_UMA_CTS_DEV_NUM_SHIFT));
404ace55c41STomer Maimon 
405ace55c41STomer Maimon 	regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CMD,
406ace55c41STomer Maimon 			   NPCM_FIU_UMA_CMD_CMD, cmd);
407ace55c41STomer Maimon 
408ace55c41STomer Maimon 	if (data_size) {
409ace55c41STomer Maimon 		memcpy(data_reg, data, data_size);
410ace55c41STomer Maimon 		for (i = 0; i < DIV_ROUND_UP(data_size, 4); i++)
411ace55c41STomer Maimon 			regmap_write(fiu->regmap, NPCM_FIU_UMA_DW0 + (i * 4),
412ace55c41STomer Maimon 				     data_reg[i]);
413ace55c41STomer Maimon 	}
414ace55c41STomer Maimon 
415ace55c41STomer Maimon 	if (is_address_size) {
416ace55c41STomer Maimon 		uma_cfg |= ilog2(op->cmd.buswidth);
417ace55c41STomer Maimon 		uma_cfg |= ilog2(op->addr.buswidth) <<
418ace55c41STomer Maimon 			NPCM_FIU_UMA_CFG_ADBPCK_SHIFT;
419ace55c41STomer Maimon 		uma_cfg |= ilog2(op->data.buswidth) <<
420ace55c41STomer Maimon 			NPCM_FIU_UMA_CFG_WDBPCK_SHIFT;
421ace55c41STomer Maimon 		uma_cfg |= op->addr.nbytes << NPCM_FIU_UMA_CFG_ADDSIZ_SHIFT;
422ace55c41STomer Maimon 		regmap_write(fiu->regmap, NPCM_FIU_UMA_ADDR, op->addr.val);
423ace55c41STomer Maimon 	} else {
424ace55c41STomer Maimon 		regmap_write(fiu->regmap, NPCM_FIU_UMA_ADDR, 0x0);
425ace55c41STomer Maimon 	}
426ace55c41STomer Maimon 
427ace55c41STomer Maimon 	uma_cfg |= (data_size << NPCM_FIU_UMA_CFG_WDATSIZ_SHIFT);
428ace55c41STomer Maimon 	regmap_write(fiu->regmap, NPCM_FIU_UMA_CFG, uma_cfg);
429ace55c41STomer Maimon 
430ace55c41STomer Maimon 	regmap_write_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
431ace55c41STomer Maimon 			  NPCM_FIU_UMA_CTS_EXEC_DONE,
432ace55c41STomer Maimon 			  NPCM_FIU_UMA_CTS_EXEC_DONE);
433ace55c41STomer Maimon 
434ace55c41STomer Maimon 	return regmap_read_poll_timeout(fiu->regmap, NPCM_FIU_UMA_CTS, val,
435ace55c41STomer Maimon 				       (!(val & NPCM_FIU_UMA_CTS_EXEC_DONE)), 0,
436ace55c41STomer Maimon 					UMA_MICRO_SEC_TIMEOUT);
437ace55c41STomer Maimon }
438ace55c41STomer Maimon 
npcm_fiu_manualwrite(struct spi_mem * mem,const struct spi_mem_op * op)439ace55c41STomer Maimon static int npcm_fiu_manualwrite(struct spi_mem *mem,
440ace55c41STomer Maimon 				const struct spi_mem_op *op)
441ace55c41STomer Maimon {
442ace55c41STomer Maimon 	struct npcm_fiu_spi *fiu =
4431f6c80a7SYang Yingliang 		spi_controller_get_devdata(mem->spi->controller);
444ace55c41STomer Maimon 	u8 *data = (u8 *)op->data.buf.out;
445ace55c41STomer Maimon 	u32 num_data_chunks;
446ace55c41STomer Maimon 	u32 remain_data;
447ace55c41STomer Maimon 	u32 idx = 0;
448ace55c41STomer Maimon 	int ret;
449ace55c41STomer Maimon 
450ace55c41STomer Maimon 	num_data_chunks  = op->data.nbytes / CHUNK_SIZE;
451ace55c41STomer Maimon 	remain_data  = op->data.nbytes % CHUNK_SIZE;
452ace55c41STomer Maimon 
453ace55c41STomer Maimon 	regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
454ace55c41STomer Maimon 			   NPCM_FIU_UMA_CTS_DEV_NUM,
4559e264f3fSAmit Kumar Mahapatra via Alsa-devel 			   (spi_get_chipselect(mem->spi, 0) <<
456ace55c41STomer Maimon 			    NPCM_FIU_UMA_CTS_DEV_NUM_SHIFT));
457ace55c41STomer Maimon 	regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
458ace55c41STomer Maimon 			   NPCM_FIU_UMA_CTS_SW_CS, 0);
459ace55c41STomer Maimon 
460ace55c41STomer Maimon 	ret = npcm_fiu_uma_write(mem, op, op->cmd.opcode, true, NULL, 0);
461ace55c41STomer Maimon 	if (ret)
462ace55c41STomer Maimon 		return ret;
463ace55c41STomer Maimon 
464ace55c41STomer Maimon 	/* Starting the data writing loop in multiples of 8 */
465ace55c41STomer Maimon 	for (idx = 0; idx < num_data_chunks; ++idx) {
466ace55c41STomer Maimon 		ret = npcm_fiu_uma_write(mem, op, data[0], false,
467ace55c41STomer Maimon 					 &data[1], CHUNK_SIZE - 1);
468ace55c41STomer Maimon 		if (ret)
469ace55c41STomer Maimon 			return ret;
470ace55c41STomer Maimon 
471ace55c41STomer Maimon 		data += CHUNK_SIZE;
472ace55c41STomer Maimon 	}
473ace55c41STomer Maimon 
474ace55c41STomer Maimon 	/* Handling chunk remains */
475ace55c41STomer Maimon 	if (remain_data > 0) {
476ace55c41STomer Maimon 		ret = npcm_fiu_uma_write(mem, op, data[0], false,
477ace55c41STomer Maimon 					 &data[1], remain_data - 1);
478ace55c41STomer Maimon 		if (ret)
479ace55c41STomer Maimon 			return ret;
480ace55c41STomer Maimon 	}
481ace55c41STomer Maimon 
482ace55c41STomer Maimon 	regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS,
483ace55c41STomer Maimon 			   NPCM_FIU_UMA_CTS_SW_CS, NPCM_FIU_UMA_CTS_SW_CS);
484ace55c41STomer Maimon 
485ace55c41STomer Maimon 	return 0;
486ace55c41STomer Maimon }
487ace55c41STomer Maimon 
npcm_fiu_read(struct spi_mem * mem,const struct spi_mem_op * op)488ace55c41STomer Maimon static int npcm_fiu_read(struct spi_mem *mem, const struct spi_mem_op *op)
489ace55c41STomer Maimon {
490ace55c41STomer Maimon 	u8 *data = op->data.buf.in;
491ace55c41STomer Maimon 	int i, readlen, currlen;
492ace55c41STomer Maimon 	u8 *buf_ptr;
493ace55c41STomer Maimon 	u32 addr;
494ace55c41STomer Maimon 	int ret;
495ace55c41STomer Maimon 
496ace55c41STomer Maimon 	i = 0;
497ace55c41STomer Maimon 	currlen = op->data.nbytes;
498ace55c41STomer Maimon 
499ace55c41STomer Maimon 	do {
500ace55c41STomer Maimon 		addr = ((u32)op->addr.val + i);
501ace55c41STomer Maimon 		if (currlen < 16)
502ace55c41STomer Maimon 			readlen = currlen;
503ace55c41STomer Maimon 		else
504ace55c41STomer Maimon 			readlen = 16;
505ace55c41STomer Maimon 
506ace55c41STomer Maimon 		buf_ptr = data + i;
507ace55c41STomer Maimon 		ret = npcm_fiu_uma_read(mem, op, addr, true, buf_ptr,
508ace55c41STomer Maimon 					readlen);
509ace55c41STomer Maimon 		if (ret)
510ace55c41STomer Maimon 			return ret;
511ace55c41STomer Maimon 
512ace55c41STomer Maimon 		i += readlen;
513ace55c41STomer Maimon 		currlen -= 16;
514ace55c41STomer Maimon 	} while (currlen > 0);
515ace55c41STomer Maimon 
516ace55c41STomer Maimon 	return 0;
517ace55c41STomer Maimon }
518ace55c41STomer Maimon 
npcm_fiux_set_direct_wr(struct npcm_fiu_spi * fiu)519ace55c41STomer Maimon static void npcm_fiux_set_direct_wr(struct npcm_fiu_spi *fiu)
520ace55c41STomer Maimon {
521ace55c41STomer Maimon 	regmap_write(fiu->regmap, NPCM_FIU_DWR_CFG,
522ace55c41STomer Maimon 		     NPCM_FIU_DWR_16_BYTE_BURST);
523ace55c41STomer Maimon 	regmap_update_bits(fiu->regmap, NPCM_FIU_DWR_CFG,
524ace55c41STomer Maimon 			   NPCM_FIU_DWR_CFG_ABPCK,
525ace55c41STomer Maimon 			   DWR_ABPCK_4_BIT_PER_CLK << NPCM_FIU_DWR_ABPCK_SHIFT);
526ace55c41STomer Maimon 	regmap_update_bits(fiu->regmap, NPCM_FIU_DWR_CFG,
527ace55c41STomer Maimon 			   NPCM_FIU_DWR_CFG_DBPCK,
528ace55c41STomer Maimon 			   DWR_DBPCK_4_BIT_PER_CLK << NPCM_FIU_DWR_DBPCK_SHIFT);
529ace55c41STomer Maimon }
530ace55c41STomer Maimon 
npcm_fiux_set_direct_rd(struct npcm_fiu_spi * fiu)531ace55c41STomer Maimon static void npcm_fiux_set_direct_rd(struct npcm_fiu_spi *fiu)
532ace55c41STomer Maimon {
533ace55c41STomer Maimon 	u32 rx_dummy = 0;
534ace55c41STomer Maimon 
535ace55c41STomer Maimon 	regmap_write(fiu->regmap, NPCM_FIU_DRD_CFG,
536ace55c41STomer Maimon 		     NPCM_FIU_DRD_16_BYTE_BURST);
537ace55c41STomer Maimon 	regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
538ace55c41STomer Maimon 			   NPCM_FIU_DRD_CFG_ACCTYPE,
539ace55c41STomer Maimon 			   DRD_SPI_X_MODE << NPCM_FIU_DRD_ACCTYPE_SHIFT);
540ace55c41STomer Maimon 	regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
541ace55c41STomer Maimon 			   NPCM_FIU_DRD_CFG_DBW,
542ace55c41STomer Maimon 			   rx_dummy << NPCM_FIU_DRD_DBW_SHIFT);
543ace55c41STomer Maimon }
544ace55c41STomer Maimon 
npcm_fiu_exec_op(struct spi_mem * mem,const struct spi_mem_op * op)545ace55c41STomer Maimon static int npcm_fiu_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
546ace55c41STomer Maimon {
547ace55c41STomer Maimon 	struct npcm_fiu_spi *fiu =
5481f6c80a7SYang Yingliang 		spi_controller_get_devdata(mem->spi->controller);
5499e264f3fSAmit Kumar Mahapatra via Alsa-devel 	struct npcm_fiu_chip *chip = &fiu->chip[spi_get_chipselect(mem->spi, 0)];
550ace55c41STomer Maimon 	int ret = 0;
551ace55c41STomer Maimon 	u8 *buf;
552ace55c41STomer Maimon 
553ace55c41STomer Maimon 	dev_dbg(fiu->dev, "cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n",
554ace55c41STomer Maimon 		op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
555ace55c41STomer Maimon 		op->dummy.buswidth, op->data.buswidth, op->addr.val,
556ace55c41STomer Maimon 		op->data.nbytes);
557ace55c41STomer Maimon 
558ace55c41STomer Maimon 	if (fiu->spix_mode || op->addr.nbytes > 4)
559ace55c41STomer Maimon 		return -ENOTSUPP;
560ace55c41STomer Maimon 
561ace55c41STomer Maimon 	if (fiu->clkrate != chip->clkrate) {
562ace55c41STomer Maimon 		ret = clk_set_rate(fiu->clk, chip->clkrate);
563ace55c41STomer Maimon 		if (ret < 0)
5640d6fccc1SColin Ian King 			dev_warn(fiu->dev, "Failed setting %lu frequency, stay at %lu frequency\n",
5650d6fccc1SColin Ian King 				 chip->clkrate, fiu->clkrate);
566ace55c41STomer Maimon 		else
567ace55c41STomer Maimon 			fiu->clkrate = chip->clkrate;
568ace55c41STomer Maimon 	}
569ace55c41STomer Maimon 
570ace55c41STomer Maimon 	if (op->data.dir == SPI_MEM_DATA_IN) {
571ace55c41STomer Maimon 		if (!op->addr.nbytes) {
572ace55c41STomer Maimon 			buf = op->data.buf.in;
573ace55c41STomer Maimon 			ret = npcm_fiu_uma_read(mem, op, op->addr.val, false,
574ace55c41STomer Maimon 						buf, op->data.nbytes);
575ace55c41STomer Maimon 		} else {
576ace55c41STomer Maimon 			ret = npcm_fiu_read(mem, op);
577ace55c41STomer Maimon 		}
578ace55c41STomer Maimon 	} else  {
579ace55c41STomer Maimon 		if (!op->addr.nbytes && !op->data.nbytes)
580ace55c41STomer Maimon 			ret = npcm_fiu_uma_write(mem, op, op->cmd.opcode, false,
581ace55c41STomer Maimon 						 NULL, 0);
582ace55c41STomer Maimon 		if (op->addr.nbytes && !op->data.nbytes) {
583ace55c41STomer Maimon 			int i;
584ace55c41STomer Maimon 			u8 buf_addr[4];
585ace55c41STomer Maimon 			u32 addr = op->addr.val;
586ace55c41STomer Maimon 
587ace55c41STomer Maimon 			for (i = op->addr.nbytes - 1; i >= 0; i--) {
588ace55c41STomer Maimon 				buf_addr[i] = addr & 0xff;
589ace55c41STomer Maimon 				addr >>= 8;
590ace55c41STomer Maimon 			}
591ace55c41STomer Maimon 			ret = npcm_fiu_uma_write(mem, op, op->cmd.opcode, false,
592ace55c41STomer Maimon 						 buf_addr, op->addr.nbytes);
593ace55c41STomer Maimon 		}
594ace55c41STomer Maimon 		if (!op->addr.nbytes && op->data.nbytes)
595ace55c41STomer Maimon 			ret = npcm_fiu_uma_write(mem, op, op->cmd.opcode, false,
596ace55c41STomer Maimon 						 (u8 *)op->data.buf.out,
597ace55c41STomer Maimon 						 op->data.nbytes);
598ace55c41STomer Maimon 		if (op->addr.nbytes && op->data.nbytes)
599ace55c41STomer Maimon 			ret = npcm_fiu_manualwrite(mem, op);
600ace55c41STomer Maimon 	}
601ace55c41STomer Maimon 
602ace55c41STomer Maimon 	return ret;
603ace55c41STomer Maimon }
604ace55c41STomer Maimon 
npcm_fiu_dirmap_create(struct spi_mem_dirmap_desc * desc)605ace55c41STomer Maimon static int npcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc)
606ace55c41STomer Maimon {
607ace55c41STomer Maimon 	struct npcm_fiu_spi *fiu =
6081f6c80a7SYang Yingliang 		spi_controller_get_devdata(desc->mem->spi->controller);
6099e264f3fSAmit Kumar Mahapatra via Alsa-devel 	struct npcm_fiu_chip *chip = &fiu->chip[spi_get_chipselect(desc->mem->spi, 0)];
610ace55c41STomer Maimon 	struct regmap *gcr_regmap;
611ace55c41STomer Maimon 
612ace55c41STomer Maimon 	if (!fiu->res_mem) {
613ace55c41STomer Maimon 		dev_warn(fiu->dev, "Reserved memory not defined, direct read disabled\n");
614ace55c41STomer Maimon 		desc->nodirmap = true;
615ace55c41STomer Maimon 		return 0;
616ace55c41STomer Maimon 	}
617ace55c41STomer Maimon 
618ace55c41STomer Maimon 	if (!fiu->spix_mode &&
619ace55c41STomer Maimon 	    desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) {
620ace55c41STomer Maimon 		desc->nodirmap = true;
621ace55c41STomer Maimon 		return 0;
622ace55c41STomer Maimon 	}
623ace55c41STomer Maimon 
624ace55c41STomer Maimon 	if (!chip->flash_region_mapped_ptr) {
625ace55c41STomer Maimon 		chip->flash_region_mapped_ptr =
6264bdc0d67SChristoph Hellwig 			devm_ioremap(fiu->dev, (fiu->res_mem->start +
627ace55c41STomer Maimon 							(fiu->info->max_map_size *
6289e264f3fSAmit Kumar Mahapatra via Alsa-devel 						    spi_get_chipselect(desc->mem->spi, 0))),
629ace55c41STomer Maimon 					     (u32)desc->info.length);
630ace55c41STomer Maimon 		if (!chip->flash_region_mapped_ptr) {
631ace55c41STomer Maimon 			dev_warn(fiu->dev, "Error mapping memory region, direct read disabled\n");
632ace55c41STomer Maimon 			desc->nodirmap = true;
633ace55c41STomer Maimon 			return 0;
634ace55c41STomer Maimon 		}
635ace55c41STomer Maimon 	}
636ace55c41STomer Maimon 
637ace55c41STomer Maimon 	if (of_device_is_compatible(fiu->dev->of_node, "nuvoton,npcm750-fiu")) {
638ace55c41STomer Maimon 		gcr_regmap =
639ace55c41STomer Maimon 			syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr");
640ace55c41STomer Maimon 		if (IS_ERR(gcr_regmap)) {
641ace55c41STomer Maimon 			dev_warn(fiu->dev, "Didn't find nuvoton,npcm750-gcr, direct read disabled\n");
642ace55c41STomer Maimon 			desc->nodirmap = true;
643ace55c41STomer Maimon 			return 0;
644ace55c41STomer Maimon 		}
645ace55c41STomer Maimon 		regmap_update_bits(gcr_regmap, NPCM7XX_INTCR3_OFFSET,
646ace55c41STomer Maimon 				   NPCM7XX_INTCR3_FIU_FIX,
647ace55c41STomer Maimon 				   NPCM7XX_INTCR3_FIU_FIX);
648650b014fSTomer Maimon 	} else {
649650b014fSTomer Maimon 		regmap_update_bits(fiu->regmap, NPCM_FIU_CFG,
650650b014fSTomer Maimon 				   NPCM_FIU_CFG_FIU_FIX,
651650b014fSTomer Maimon 				   NPCM_FIU_CFG_FIU_FIX);
652ace55c41STomer Maimon 	}
653ace55c41STomer Maimon 
654ace55c41STomer Maimon 	if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) {
655ace55c41STomer Maimon 		if (!fiu->spix_mode)
656ace55c41STomer Maimon 			npcm_fiu_set_drd(fiu, &desc->info.op_tmpl);
657ace55c41STomer Maimon 		else
658ace55c41STomer Maimon 			npcm_fiux_set_direct_rd(fiu);
659ace55c41STomer Maimon 
660ace55c41STomer Maimon 	} else {
661ace55c41STomer Maimon 		npcm_fiux_set_direct_wr(fiu);
662ace55c41STomer Maimon 	}
663ace55c41STomer Maimon 
664ace55c41STomer Maimon 	return 0;
665ace55c41STomer Maimon }
666ace55c41STomer Maimon 
npcm_fiu_setup(struct spi_device * spi)667ace55c41STomer Maimon static int npcm_fiu_setup(struct spi_device *spi)
668ace55c41STomer Maimon {
6691f6c80a7SYang Yingliang 	struct spi_controller *ctrl = spi->controller;
670ace55c41STomer Maimon 	struct npcm_fiu_spi *fiu = spi_controller_get_devdata(ctrl);
671ace55c41STomer Maimon 	struct npcm_fiu_chip *chip;
672ace55c41STomer Maimon 
6739e264f3fSAmit Kumar Mahapatra via Alsa-devel 	chip = &fiu->chip[spi_get_chipselect(spi, 0)];
674ace55c41STomer Maimon 	chip->fiu = fiu;
6759e264f3fSAmit Kumar Mahapatra via Alsa-devel 	chip->chipselect = spi_get_chipselect(spi, 0);
676ace55c41STomer Maimon 	chip->clkrate = spi->max_speed_hz;
677ace55c41STomer Maimon 
678ace55c41STomer Maimon 	fiu->clkrate = clk_get_rate(fiu->clk);
679ace55c41STomer Maimon 
680ace55c41STomer Maimon 	return 0;
681ace55c41STomer Maimon }
682ace55c41STomer Maimon 
683ace55c41STomer Maimon static const struct spi_controller_mem_ops npcm_fiu_mem_ops = {
684ace55c41STomer Maimon 	.exec_op = npcm_fiu_exec_op,
685ace55c41STomer Maimon 	.dirmap_create = npcm_fiu_dirmap_create,
686ace55c41STomer Maimon 	.dirmap_read = npcm_fiu_direct_read,
687ace55c41STomer Maimon 	.dirmap_write = npcm_fiu_direct_write,
688ace55c41STomer Maimon };
689ace55c41STomer Maimon 
690ace55c41STomer Maimon static const struct of_device_id npcm_fiu_dt_ids[] = {
691b15e3bc7SJonathan Neuschäfer 	{ .compatible = "nuvoton,npcm750-fiu", .data = &npcm7xx_fiu_data  },
692650b014fSTomer Maimon 	{ .compatible = "nuvoton,npcm845-fiu", .data = &npxm8xx_fiu_data  },
693ace55c41STomer Maimon 	{ /* sentinel */ }
694ace55c41STomer Maimon };
695ace55c41STomer Maimon 
npcm_fiu_probe(struct platform_device * pdev)696ace55c41STomer Maimon static int npcm_fiu_probe(struct platform_device *pdev)
697ace55c41STomer Maimon {
698ace55c41STomer Maimon 	const struct fiu_data *fiu_data_match;
699ace55c41STomer Maimon 	struct device *dev = &pdev->dev;
700ace55c41STomer Maimon 	struct spi_controller *ctrl;
701ace55c41STomer Maimon 	struct npcm_fiu_spi *fiu;
702ace55c41STomer Maimon 	void __iomem *regbase;
703234266a5SLukas Wunner 	int id, ret;
704ace55c41STomer Maimon 
7051f6c80a7SYang Yingliang 	ctrl = devm_spi_alloc_host(dev, sizeof(*fiu));
706ace55c41STomer Maimon 	if (!ctrl)
707ace55c41STomer Maimon 		return -ENOMEM;
708ace55c41STomer Maimon 
709ace55c41STomer Maimon 	fiu = spi_controller_get_devdata(ctrl);
710ace55c41STomer Maimon 
711dc8fea13SMinghao Chi (CGEL ZTE) 	fiu_data_match = of_device_get_match_data(dev);
712dc8fea13SMinghao Chi (CGEL ZTE) 	if (!fiu_data_match) {
713ace55c41STomer Maimon 		dev_err(dev, "No compatible OF match\n");
714ace55c41STomer Maimon 		return -ENODEV;
715ace55c41STomer Maimon 	}
716ace55c41STomer Maimon 
717ace55c41STomer Maimon 	id = of_alias_get_id(dev->of_node, "fiu");
718ace55c41STomer Maimon 	if (id < 0 || id >= fiu_data_match->fiu_max) {
719ace55c41STomer Maimon 		dev_err(dev, "Invalid platform device id: %d\n", id);
720ace55c41STomer Maimon 		return -EINVAL;
721ace55c41STomer Maimon 	}
722ace55c41STomer Maimon 
723ace55c41STomer Maimon 	fiu->info = &fiu_data_match->npcm_fiu_data_info[id];
724ace55c41STomer Maimon 
725ace55c41STomer Maimon 	platform_set_drvdata(pdev, fiu);
726ace55c41STomer Maimon 	fiu->dev = dev;
727ace55c41STomer Maimon 
7281793d366SYang Yingliang 	regbase = devm_platform_ioremap_resource_byname(pdev, "control");
729ace55c41STomer Maimon 	if (IS_ERR(regbase))
730ace55c41STomer Maimon 		return PTR_ERR(regbase);
731ace55c41STomer Maimon 
732ace55c41STomer Maimon 	fiu->regmap = devm_regmap_init_mmio(dev, regbase,
733ace55c41STomer Maimon 					    &npcm_mtd_regmap_config);
734ace55c41STomer Maimon 	if (IS_ERR(fiu->regmap)) {
735ace55c41STomer Maimon 		dev_err(dev, "Failed to create regmap\n");
736ace55c41STomer Maimon 		return PTR_ERR(fiu->regmap);
737ace55c41STomer Maimon 	}
738ace55c41STomer Maimon 
739ace55c41STomer Maimon 	fiu->res_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
740ace55c41STomer Maimon 						    "memory");
741ace55c41STomer Maimon 	fiu->clk = devm_clk_get(dev, NULL);
742ace55c41STomer Maimon 	if (IS_ERR(fiu->clk))
743ace55c41STomer Maimon 		return PTR_ERR(fiu->clk);
744ace55c41STomer Maimon 
745ace55c41STomer Maimon 	fiu->spix_mode = of_property_read_bool(dev->of_node,
746ace55c41STomer Maimon 					       "nuvoton,spix-mode");
747ace55c41STomer Maimon 
748ace55c41STomer Maimon 	platform_set_drvdata(pdev, fiu);
749ace55c41STomer Maimon 	clk_prepare_enable(fiu->clk);
750ace55c41STomer Maimon 
751ace55c41STomer Maimon 	ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD
752ace55c41STomer Maimon 		| SPI_TX_DUAL | SPI_TX_QUAD;
753ace55c41STomer Maimon 	ctrl->setup = npcm_fiu_setup;
754ace55c41STomer Maimon 	ctrl->bus_num = -1;
755ace55c41STomer Maimon 	ctrl->mem_ops = &npcm_fiu_mem_ops;
756ace55c41STomer Maimon 	ctrl->num_chipselect = fiu->info->max_cs;
757ace55c41STomer Maimon 	ctrl->dev.of_node = dev->of_node;
758ace55c41STomer Maimon 
7591f6c80a7SYang Yingliang 	ret = devm_spi_register_controller(dev, ctrl);
760234266a5SLukas Wunner 	if (ret)
761234266a5SLukas Wunner 		clk_disable_unprepare(fiu->clk);
762234266a5SLukas Wunner 
763234266a5SLukas Wunner 	return ret;
764ace55c41STomer Maimon }
765ace55c41STomer Maimon 
npcm_fiu_remove(struct platform_device * pdev)7665e4830adSUwe Kleine-König static void npcm_fiu_remove(struct platform_device *pdev)
767ace55c41STomer Maimon {
768ace55c41STomer Maimon 	struct npcm_fiu_spi *fiu = platform_get_drvdata(pdev);
769ace55c41STomer Maimon 
770ace55c41STomer Maimon 	clk_disable_unprepare(fiu->clk);
771ace55c41STomer Maimon }
772ace55c41STomer Maimon 
773ace55c41STomer Maimon MODULE_DEVICE_TABLE(of, npcm_fiu_dt_ids);
774ace55c41STomer Maimon 
775ace55c41STomer Maimon static struct platform_driver npcm_fiu_driver = {
776ace55c41STomer Maimon 	.driver = {
777ace55c41STomer Maimon 		.name	= "NPCM-FIU",
778ace55c41STomer Maimon 		.bus	= &platform_bus_type,
779ace55c41STomer Maimon 		.of_match_table = npcm_fiu_dt_ids,
780ace55c41STomer Maimon 	},
781ace55c41STomer Maimon 	.probe      = npcm_fiu_probe,
7825e4830adSUwe Kleine-König 	.remove_new	    = npcm_fiu_remove,
783ace55c41STomer Maimon };
784ace55c41STomer Maimon module_platform_driver(npcm_fiu_driver);
785ace55c41STomer Maimon 
786ace55c41STomer Maimon MODULE_DESCRIPTION("Nuvoton FLASH Interface Unit SPI Controller Driver");
787ace55c41STomer Maimon MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
788ace55c41STomer Maimon MODULE_LICENSE("GPL v2");
789