Commit | Line | Data |
---|---|---|
ca7d8b98 SS |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Renesas RPC-IF core driver | |
4 | * | |
5 | * Copyright (C) 2018-2019 Renesas Solutions Corp. | |
6 | * Copyright (C) 2019 Macronix International Co., Ltd. | |
7 | * Copyright (C) 2019-2020 Cogent Embedded, Inc. | |
8 | */ | |
9 | ||
10 | #include <linux/clk.h> | |
11 | #include <linux/io.h> | |
12 | #include <linux/module.h> | |
13 | #include <linux/platform_device.h> | |
14 | #include <linux/of.h> | |
b04cc0d9 | 15 | #include <linux/of_device.h> |
ca7d8b98 SS |
16 | #include <linux/regmap.h> |
17 | #include <linux/reset.h> | |
18 | ||
19 | #include <memory/renesas-rpc-if.h> | |
20 | ||
21 | #define RPCIF_CMNCR 0x0000 /* R/W */ | |
22 | #define RPCIF_CMNCR_MD BIT(31) | |
ca7d8b98 SS |
23 | #define RPCIF_CMNCR_MOIIO3(val) (((val) & 0x3) << 22) |
24 | #define RPCIF_CMNCR_MOIIO2(val) (((val) & 0x3) << 20) | |
25 | #define RPCIF_CMNCR_MOIIO1(val) (((val) & 0x3) << 18) | |
26 | #define RPCIF_CMNCR_MOIIO0(val) (((val) & 0x3) << 16) | |
3542de6a WS |
27 | #define RPCIF_CMNCR_MOIIO(val) (RPCIF_CMNCR_MOIIO0(val) | RPCIF_CMNCR_MOIIO1(val) | \ |
28 | RPCIF_CMNCR_MOIIO2(val) | RPCIF_CMNCR_MOIIO3(val)) | |
b04cc0d9 LP |
29 | #define RPCIF_CMNCR_IO3FV(val) (((val) & 0x3) << 14) /* documented for RZ/G2L */ |
30 | #define RPCIF_CMNCR_IO2FV(val) (((val) & 0x3) << 12) /* documented for RZ/G2L */ | |
ca7d8b98 | 31 | #define RPCIF_CMNCR_IO0FV(val) (((val) & 0x3) << 8) |
3542de6a WS |
32 | #define RPCIF_CMNCR_IOFV(val) (RPCIF_CMNCR_IO0FV(val) | RPCIF_CMNCR_IO2FV(val) | \ |
33 | RPCIF_CMNCR_IO3FV(val)) | |
ca7d8b98 SS |
34 | #define RPCIF_CMNCR_BSZ(val) (((val) & 0x3) << 0) |
35 | ||
36 | #define RPCIF_SSLDR 0x0004 /* R/W */ | |
37 | #define RPCIF_SSLDR_SPNDL(d) (((d) & 0x7) << 16) | |
38 | #define RPCIF_SSLDR_SLNDL(d) (((d) & 0x7) << 8) | |
39 | #define RPCIF_SSLDR_SCKDL(d) (((d) & 0x7) << 0) | |
40 | ||
41 | #define RPCIF_DRCR 0x000C /* R/W */ | |
42 | #define RPCIF_DRCR_SSLN BIT(24) | |
43 | #define RPCIF_DRCR_RBURST(v) ((((v) - 1) & 0x1F) << 16) | |
44 | #define RPCIF_DRCR_RCF BIT(9) | |
45 | #define RPCIF_DRCR_RBE BIT(8) | |
46 | #define RPCIF_DRCR_SSLE BIT(0) | |
47 | ||
48 | #define RPCIF_DRCMR 0x0010 /* R/W */ | |
49 | #define RPCIF_DRCMR_CMD(c) (((c) & 0xFF) << 16) | |
50 | #define RPCIF_DRCMR_OCMD(c) (((c) & 0xFF) << 0) | |
51 | ||
52 | #define RPCIF_DREAR 0x0014 /* R/W */ | |
53 | #define RPCIF_DREAR_EAV(c) (((c) & 0xF) << 16) | |
54 | #define RPCIF_DREAR_EAC(c) (((c) & 0x7) << 0) | |
55 | ||
56 | #define RPCIF_DROPR 0x0018 /* R/W */ | |
57 | ||
58 | #define RPCIF_DRENR 0x001C /* R/W */ | |
59 | #define RPCIF_DRENR_CDB(o) (u32)((((o) & 0x3) << 30)) | |
60 | #define RPCIF_DRENR_OCDB(o) (((o) & 0x3) << 28) | |
61 | #define RPCIF_DRENR_ADB(o) (((o) & 0x3) << 24) | |
62 | #define RPCIF_DRENR_OPDB(o) (((o) & 0x3) << 20) | |
63 | #define RPCIF_DRENR_DRDB(o) (((o) & 0x3) << 16) | |
64 | #define RPCIF_DRENR_DME BIT(15) | |
65 | #define RPCIF_DRENR_CDE BIT(14) | |
66 | #define RPCIF_DRENR_OCDE BIT(12) | |
67 | #define RPCIF_DRENR_ADE(v) (((v) & 0xF) << 8) | |
68 | #define RPCIF_DRENR_OPDE(v) (((v) & 0xF) << 4) | |
69 | ||
70 | #define RPCIF_SMCR 0x0020 /* R/W */ | |
71 | #define RPCIF_SMCR_SSLKP BIT(8) | |
72 | #define RPCIF_SMCR_SPIRE BIT(2) | |
73 | #define RPCIF_SMCR_SPIWE BIT(1) | |
74 | #define RPCIF_SMCR_SPIE BIT(0) | |
75 | ||
76 | #define RPCIF_SMCMR 0x0024 /* R/W */ | |
77 | #define RPCIF_SMCMR_CMD(c) (((c) & 0xFF) << 16) | |
78 | #define RPCIF_SMCMR_OCMD(c) (((c) & 0xFF) << 0) | |
79 | ||
80 | #define RPCIF_SMADR 0x0028 /* R/W */ | |
81 | ||
82 | #define RPCIF_SMOPR 0x002C /* R/W */ | |
83 | #define RPCIF_SMOPR_OPD3(o) (((o) & 0xFF) << 24) | |
84 | #define RPCIF_SMOPR_OPD2(o) (((o) & 0xFF) << 16) | |
85 | #define RPCIF_SMOPR_OPD1(o) (((o) & 0xFF) << 8) | |
86 | #define RPCIF_SMOPR_OPD0(o) (((o) & 0xFF) << 0) | |
87 | ||
88 | #define RPCIF_SMENR 0x0030 /* R/W */ | |
89 | #define RPCIF_SMENR_CDB(o) (((o) & 0x3) << 30) | |
90 | #define RPCIF_SMENR_OCDB(o) (((o) & 0x3) << 28) | |
91 | #define RPCIF_SMENR_ADB(o) (((o) & 0x3) << 24) | |
92 | #define RPCIF_SMENR_OPDB(o) (((o) & 0x3) << 20) | |
93 | #define RPCIF_SMENR_SPIDB(o) (((o) & 0x3) << 16) | |
94 | #define RPCIF_SMENR_DME BIT(15) | |
95 | #define RPCIF_SMENR_CDE BIT(14) | |
96 | #define RPCIF_SMENR_OCDE BIT(12) | |
97 | #define RPCIF_SMENR_ADE(v) (((v) & 0xF) << 8) | |
98 | #define RPCIF_SMENR_OPDE(v) (((v) & 0xF) << 4) | |
99 | #define RPCIF_SMENR_SPIDE(v) (((v) & 0xF) << 0) | |
100 | ||
101 | #define RPCIF_SMRDR0 0x0038 /* R */ | |
102 | #define RPCIF_SMRDR1 0x003C /* R */ | |
103 | #define RPCIF_SMWDR0 0x0040 /* W */ | |
104 | #define RPCIF_SMWDR1 0x0044 /* W */ | |
105 | ||
106 | #define RPCIF_CMNSR 0x0048 /* R */ | |
107 | #define RPCIF_CMNSR_SSLF BIT(1) | |
108 | #define RPCIF_CMNSR_TEND BIT(0) | |
109 | ||
110 | #define RPCIF_DRDMCR 0x0058 /* R/W */ | |
111 | #define RPCIF_DMDMCR_DMCYC(v) ((((v) - 1) & 0x1F) << 0) | |
112 | ||
113 | #define RPCIF_DRDRENR 0x005C /* R/W */ | |
114 | #define RPCIF_DRDRENR_HYPE(v) (((v) & 0x7) << 12) | |
115 | #define RPCIF_DRDRENR_ADDRE BIT(8) | |
116 | #define RPCIF_DRDRENR_OPDRE BIT(4) | |
117 | #define RPCIF_DRDRENR_DRDRE BIT(0) | |
118 | ||
119 | #define RPCIF_SMDMCR 0x0060 /* R/W */ | |
120 | #define RPCIF_SMDMCR_DMCYC(v) ((((v) - 1) & 0x1F) << 0) | |
121 | ||
122 | #define RPCIF_SMDRENR 0x0064 /* R/W */ | |
123 | #define RPCIF_SMDRENR_HYPE(v) (((v) & 0x7) << 12) | |
124 | #define RPCIF_SMDRENR_ADDRE BIT(8) | |
125 | #define RPCIF_SMDRENR_OPDRE BIT(4) | |
126 | #define RPCIF_SMDRENR_SPIDRE BIT(0) | |
127 | ||
b04cc0d9 LP |
128 | #define RPCIF_PHYADD 0x0070 /* R/W available on R-Car E3/D3/V3M and RZ/G2{E,L} */ |
129 | #define RPCIF_PHYWR 0x0074 /* R/W available on R-Car E3/D3/V3M and RZ/G2{E,L} */ | |
130 | ||
ca7d8b98 SS |
131 | #define RPCIF_PHYCNT 0x007C /* R/W */ |
132 | #define RPCIF_PHYCNT_CAL BIT(31) | |
133 | #define RPCIF_PHYCNT_OCTA(v) (((v) & 0x3) << 22) | |
134 | #define RPCIF_PHYCNT_EXDS BIT(21) | |
135 | #define RPCIF_PHYCNT_OCT BIT(20) | |
136 | #define RPCIF_PHYCNT_DDRCAL BIT(19) | |
137 | #define RPCIF_PHYCNT_HS BIT(18) | |
b04cc0d9 | 138 | #define RPCIF_PHYCNT_CKSEL(v) (((v) & 0x3) << 16) /* valid only for RZ/G2L */ |
1de3866f GU |
139 | #define RPCIF_PHYCNT_STRTIM(v) (((v) & 0x7) << 15 | ((v) & 0x8) << 24) /* valid for R-Car and RZ/G2{E,H,M,N} */ |
140 | ||
ca7d8b98 SS |
141 | #define RPCIF_PHYCNT_WBUF2 BIT(4) |
142 | #define RPCIF_PHYCNT_WBUF BIT(2) | |
143 | #define RPCIF_PHYCNT_PHYMEM(v) (((v) & 0x3) << 0) | |
b04cc0d9 | 144 | #define RPCIF_PHYCNT_PHYMEM_MASK GENMASK(1, 0) |
ca7d8b98 SS |
145 | |
146 | #define RPCIF_PHYOFFSET1 0x0080 /* R/W */ | |
147 | #define RPCIF_PHYOFFSET1_DDRTMG(v) (((v) & 0x3) << 28) | |
148 | ||
149 | #define RPCIF_PHYOFFSET2 0x0084 /* R/W */ | |
150 | #define RPCIF_PHYOFFSET2_OCTTMG(v) (((v) & 0x7) << 8) | |
151 | ||
152 | #define RPCIF_PHYINT 0x0088 /* R/W */ | |
153 | #define RPCIF_PHYINT_WPVAL BIT(1) | |
154 | ||
ca7d8b98 SS |
155 | static const struct regmap_range rpcif_volatile_ranges[] = { |
156 | regmap_reg_range(RPCIF_SMRDR0, RPCIF_SMRDR1), | |
157 | regmap_reg_range(RPCIF_SMWDR0, RPCIF_SMWDR1), | |
158 | regmap_reg_range(RPCIF_CMNSR, RPCIF_CMNSR), | |
159 | }; | |
160 | ||
161 | static const struct regmap_access_table rpcif_volatile_table = { | |
162 | .yes_ranges = rpcif_volatile_ranges, | |
163 | .n_yes_ranges = ARRAY_SIZE(rpcif_volatile_ranges), | |
164 | }; | |
165 | ||
fff53a55 WS |
166 | |
167 | /* | |
7e842d70 GU |
168 | * Custom accessor functions to ensure SM[RW]DR[01] are always accessed with |
169 | * proper width. Requires rpcif.xfer_size to be correctly set before! | |
fff53a55 WS |
170 | */ |
171 | static int rpcif_reg_read(void *context, unsigned int reg, unsigned int *val) | |
172 | { | |
173 | struct rpcif *rpc = context; | |
174 | ||
7e842d70 GU |
175 | switch (reg) { |
176 | case RPCIF_SMRDR0: | |
177 | case RPCIF_SMWDR0: | |
178 | switch (rpc->xfer_size) { | |
179 | case 1: | |
fff53a55 WS |
180 | *val = readb(rpc->base + reg); |
181 | return 0; | |
7e842d70 GU |
182 | |
183 | case 2: | |
fff53a55 WS |
184 | *val = readw(rpc->base + reg); |
185 | return 0; | |
7e842d70 GU |
186 | |
187 | case 4: | |
188 | case 8: | |
189 | *val = readl(rpc->base + reg); | |
190 | return 0; | |
191 | ||
192 | default: | |
fff53a55 WS |
193 | return -EILSEQ; |
194 | } | |
7e842d70 GU |
195 | |
196 | case RPCIF_SMRDR1: | |
197 | case RPCIF_SMWDR1: | |
198 | if (rpc->xfer_size != 8) | |
199 | return -EILSEQ; | |
200 | break; | |
fff53a55 WS |
201 | } |
202 | ||
203 | *val = readl(rpc->base + reg); | |
204 | return 0; | |
fff53a55 WS |
205 | } |
206 | ||
207 | static int rpcif_reg_write(void *context, unsigned int reg, unsigned int val) | |
208 | { | |
209 | struct rpcif *rpc = context; | |
210 | ||
7e842d70 GU |
211 | switch (reg) { |
212 | case RPCIF_SMWDR0: | |
213 | switch (rpc->xfer_size) { | |
214 | case 1: | |
fff53a55 WS |
215 | writeb(val, rpc->base + reg); |
216 | return 0; | |
7e842d70 GU |
217 | |
218 | case 2: | |
fff53a55 WS |
219 | writew(val, rpc->base + reg); |
220 | return 0; | |
7e842d70 GU |
221 | |
222 | case 4: | |
223 | case 8: | |
224 | writel(val, rpc->base + reg); | |
225 | return 0; | |
226 | ||
227 | default: | |
fff53a55 WS |
228 | return -EILSEQ; |
229 | } | |
7e842d70 GU |
230 | |
231 | case RPCIF_SMWDR1: | |
232 | if (rpc->xfer_size != 8) | |
233 | return -EILSEQ; | |
234 | break; | |
235 | ||
236 | case RPCIF_SMRDR0: | |
237 | case RPCIF_SMRDR1: | |
238 | return -EPERM; | |
fff53a55 WS |
239 | } |
240 | ||
241 | writel(val, rpc->base + reg); | |
242 | return 0; | |
243 | } | |
244 | ||
ca7d8b98 SS |
245 | static const struct regmap_config rpcif_regmap_config = { |
246 | .reg_bits = 32, | |
247 | .val_bits = 32, | |
248 | .reg_stride = 4, | |
fff53a55 WS |
249 | .reg_read = rpcif_reg_read, |
250 | .reg_write = rpcif_reg_write, | |
ca7d8b98 SS |
251 | .fast_io = true, |
252 | .max_register = RPCIF_PHYINT, | |
253 | .volatile_table = &rpcif_volatile_table, | |
254 | }; | |
255 | ||
256 | int rpcif_sw_init(struct rpcif *rpc, struct device *dev) | |
257 | { | |
258 | struct platform_device *pdev = to_platform_device(dev); | |
259 | struct resource *res; | |
ca7d8b98 SS |
260 | |
261 | rpc->dev = dev; | |
262 | ||
2ca47b33 | 263 | rpc->base = devm_platform_ioremap_resource_byname(pdev, "regs"); |
fff53a55 WS |
264 | if (IS_ERR(rpc->base)) |
265 | return PTR_ERR(rpc->base); | |
ca7d8b98 | 266 | |
fff53a55 | 267 | rpc->regmap = devm_regmap_init(&pdev->dev, NULL, rpc, &rpcif_regmap_config); |
ca7d8b98 SS |
268 | if (IS_ERR(rpc->regmap)) { |
269 | dev_err(&pdev->dev, | |
270 | "failed to init regmap for rpcif, error %ld\n", | |
271 | PTR_ERR(rpc->regmap)); | |
272 | return PTR_ERR(rpc->regmap); | |
273 | } | |
274 | ||
275 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dirmap"); | |
ca7d8b98 SS |
276 | rpc->dirmap = devm_ioremap_resource(&pdev->dev, res); |
277 | if (IS_ERR(rpc->dirmap)) | |
818fdfa8 | 278 | return PTR_ERR(rpc->dirmap); |
59e27d7c | 279 | rpc->size = resource_size(res); |
ca7d8b98 | 280 | |
2602dc10 | 281 | rpc->type = (uintptr_t)of_device_get_match_data(dev); |
ca7d8b98 | 282 | rpc->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); |
ca7d8b98 | 283 | |
3cd70407 | 284 | return PTR_ERR_OR_ZERO(rpc->rstc); |
ca7d8b98 SS |
285 | } |
286 | EXPORT_SYMBOL(rpcif_sw_init); | |
287 | ||
b04cc0d9 LP |
288 | static void rpcif_rzg2l_timing_adjust_sdr(struct rpcif *rpc) |
289 | { | |
b04cc0d9 LP |
290 | regmap_write(rpc->regmap, RPCIF_PHYWR, 0xa5390000); |
291 | regmap_write(rpc->regmap, RPCIF_PHYADD, 0x80000000); | |
292 | regmap_write(rpc->regmap, RPCIF_PHYWR, 0x00008080); | |
293 | regmap_write(rpc->regmap, RPCIF_PHYADD, 0x80000022); | |
294 | regmap_write(rpc->regmap, RPCIF_PHYWR, 0x00008080); | |
295 | regmap_write(rpc->regmap, RPCIF_PHYADD, 0x80000024); | |
2db468d6 WS |
296 | regmap_update_bits(rpc->regmap, RPCIF_PHYCNT, RPCIF_PHYCNT_CKSEL(3), |
297 | RPCIF_PHYCNT_CKSEL(3)); | |
b04cc0d9 LP |
298 | regmap_write(rpc->regmap, RPCIF_PHYWR, 0x00000030); |
299 | regmap_write(rpc->regmap, RPCIF_PHYADD, 0x80000032); | |
300 | } | |
301 | ||
302 | int rpcif_hw_init(struct rpcif *rpc, bool hyperflash) | |
ca7d8b98 SS |
303 | { |
304 | u32 dummy; | |
305 | ||
306 | pm_runtime_get_sync(rpc->dev); | |
307 | ||
b04cc0d9 LP |
308 | if (rpc->type == RPCIF_RZ_G2L) { |
309 | int ret; | |
310 | ||
311 | ret = reset_control_reset(rpc->rstc); | |
312 | if (ret) | |
313 | return ret; | |
314 | usleep_range(200, 300); | |
315 | rpcif_rzg2l_timing_adjust_sdr(rpc); | |
316 | } | |
317 | ||
57ea9daa WS |
318 | regmap_update_bits(rpc->regmap, RPCIF_PHYCNT, RPCIF_PHYCNT_PHYMEM_MASK, |
319 | RPCIF_PHYCNT_PHYMEM(hyperflash ? 3 : 0)); | |
320 | ||
5192481f CD |
321 | /* DMA Transfer is not supported */ |
322 | regmap_update_bits(rpc->regmap, RPCIF_PHYCNT, RPCIF_PHYCNT_HS, 0); | |
323 | ||
57ea9daa WS |
324 | if (rpc->type == RPCIF_RCAR_GEN3) |
325 | regmap_update_bits(rpc->regmap, RPCIF_PHYCNT, | |
326 | RPCIF_PHYCNT_STRTIM(7), RPCIF_PHYCNT_STRTIM(7)); | |
1de3866f GU |
327 | else if (rpc->type == RPCIF_RCAR_GEN4) |
328 | regmap_update_bits(rpc->regmap, RPCIF_PHYCNT, | |
329 | RPCIF_PHYCNT_STRTIM(15), RPCIF_PHYCNT_STRTIM(15)); | |
ca7d8b98 | 330 | |
57ea9daa WS |
331 | regmap_update_bits(rpc->regmap, RPCIF_PHYOFFSET1, RPCIF_PHYOFFSET1_DDRTMG(3), |
332 | RPCIF_PHYOFFSET1_DDRTMG(3)); | |
333 | regmap_update_bits(rpc->regmap, RPCIF_PHYOFFSET2, RPCIF_PHYOFFSET2_OCTTMG(7), | |
334 | RPCIF_PHYOFFSET2_OCTTMG(4)); | |
ca7d8b98 SS |
335 | |
336 | if (hyperflash) | |
337 | regmap_update_bits(rpc->regmap, RPCIF_PHYINT, | |
338 | RPCIF_PHYINT_WPVAL, 0); | |
339 | ||
1de3866f | 340 | if (rpc->type == RPCIF_RZ_G2L) |
57ea9daa | 341 | regmap_update_bits(rpc->regmap, RPCIF_CMNCR, |
3542de6a | 342 | RPCIF_CMNCR_MOIIO(3) | RPCIF_CMNCR_IOFV(3) | |
57ea9daa | 343 | RPCIF_CMNCR_BSZ(3), |
3542de6a | 344 | RPCIF_CMNCR_MOIIO(1) | RPCIF_CMNCR_IOFV(2) | |
57ea9daa | 345 | RPCIF_CMNCR_BSZ(hyperflash ? 1 : 0)); |
1de3866f GU |
346 | else |
347 | regmap_update_bits(rpc->regmap, RPCIF_CMNCR, | |
348 | RPCIF_CMNCR_MOIIO(3) | RPCIF_CMNCR_BSZ(3), | |
349 | RPCIF_CMNCR_MOIIO(3) | | |
350 | RPCIF_CMNCR_BSZ(hyperflash ? 1 : 0)); | |
b04cc0d9 | 351 | |
ca7d8b98 SS |
352 | /* Set RCF after BSZ update */ |
353 | regmap_write(rpc->regmap, RPCIF_DRCR, RPCIF_DRCR_RCF); | |
354 | /* Dummy read according to spec */ | |
355 | regmap_read(rpc->regmap, RPCIF_DRCR, &dummy); | |
356 | regmap_write(rpc->regmap, RPCIF_SSLDR, RPCIF_SSLDR_SPNDL(7) | | |
357 | RPCIF_SSLDR_SLNDL(7) | RPCIF_SSLDR_SCKDL(7)); | |
358 | ||
359 | pm_runtime_put(rpc->dev); | |
360 | ||
361 | rpc->bus_size = hyperflash ? 2 : 1; | |
b04cc0d9 LP |
362 | |
363 | return 0; | |
ca7d8b98 SS |
364 | } |
365 | EXPORT_SYMBOL(rpcif_hw_init); | |
366 | ||
367 | static int wait_msg_xfer_end(struct rpcif *rpc) | |
368 | { | |
369 | u32 sts; | |
370 | ||
371 | return regmap_read_poll_timeout(rpc->regmap, RPCIF_CMNSR, sts, | |
372 | sts & RPCIF_CMNSR_TEND, 0, | |
373 | USEC_PER_SEC); | |
374 | } | |
375 | ||
376 | static u8 rpcif_bits_set(struct rpcif *rpc, u32 nbytes) | |
377 | { | |
378 | if (rpc->bus_size == 2) | |
379 | nbytes /= 2; | |
380 | nbytes = clamp(nbytes, 1U, 4U); | |
381 | return GENMASK(3, 4 - nbytes); | |
382 | } | |
383 | ||
384 | static u8 rpcif_bit_size(u8 buswidth) | |
385 | { | |
386 | return buswidth > 4 ? 2 : ilog2(buswidth); | |
387 | } | |
388 | ||
389 | void rpcif_prepare(struct rpcif *rpc, const struct rpcif_op *op, u64 *offs, | |
390 | size_t *len) | |
391 | { | |
392 | rpc->smcr = 0; | |
393 | rpc->smadr = 0; | |
394 | rpc->enable = 0; | |
395 | rpc->command = 0; | |
396 | rpc->option = 0; | |
397 | rpc->dummy = 0; | |
398 | rpc->ddr = 0; | |
399 | rpc->xferlen = 0; | |
400 | ||
401 | if (op->cmd.buswidth) { | |
402 | rpc->enable = RPCIF_SMENR_CDE | | |
403 | RPCIF_SMENR_CDB(rpcif_bit_size(op->cmd.buswidth)); | |
404 | rpc->command = RPCIF_SMCMR_CMD(op->cmd.opcode); | |
405 | if (op->cmd.ddr) | |
406 | rpc->ddr = RPCIF_SMDRENR_HYPE(0x5); | |
407 | } | |
408 | if (op->ocmd.buswidth) { | |
409 | rpc->enable |= RPCIF_SMENR_OCDE | | |
410 | RPCIF_SMENR_OCDB(rpcif_bit_size(op->ocmd.buswidth)); | |
411 | rpc->command |= RPCIF_SMCMR_OCMD(op->ocmd.opcode); | |
412 | } | |
413 | ||
414 | if (op->addr.buswidth) { | |
415 | rpc->enable |= | |
416 | RPCIF_SMENR_ADB(rpcif_bit_size(op->addr.buswidth)); | |
417 | if (op->addr.nbytes == 4) | |
418 | rpc->enable |= RPCIF_SMENR_ADE(0xF); | |
419 | else | |
420 | rpc->enable |= RPCIF_SMENR_ADE(GENMASK( | |
421 | 2, 3 - op->addr.nbytes)); | |
422 | if (op->addr.ddr) | |
423 | rpc->ddr |= RPCIF_SMDRENR_ADDRE; | |
424 | ||
425 | if (offs && len) | |
426 | rpc->smadr = *offs; | |
427 | else | |
428 | rpc->smadr = op->addr.val; | |
429 | } | |
430 | ||
431 | if (op->dummy.buswidth) { | |
432 | rpc->enable |= RPCIF_SMENR_DME; | |
433 | rpc->dummy = RPCIF_SMDMCR_DMCYC(op->dummy.ncycles / | |
434 | op->dummy.buswidth); | |
435 | } | |
436 | ||
437 | if (op->option.buswidth) { | |
438 | rpc->enable |= RPCIF_SMENR_OPDE( | |
439 | rpcif_bits_set(rpc, op->option.nbytes)) | | |
440 | RPCIF_SMENR_OPDB(rpcif_bit_size(op->option.buswidth)); | |
441 | if (op->option.ddr) | |
442 | rpc->ddr |= RPCIF_SMDRENR_OPDRE; | |
443 | rpc->option = op->option.val; | |
444 | } | |
445 | ||
446 | rpc->dir = op->data.dir; | |
447 | if (op->data.buswidth) { | |
448 | u32 nbytes; | |
449 | ||
450 | rpc->buffer = op->data.buf.in; | |
451 | switch (op->data.dir) { | |
452 | case RPCIF_DATA_IN: | |
453 | rpc->smcr = RPCIF_SMCR_SPIRE; | |
454 | break; | |
455 | case RPCIF_DATA_OUT: | |
456 | rpc->smcr = RPCIF_SMCR_SPIWE; | |
457 | break; | |
458 | default: | |
459 | break; | |
460 | } | |
461 | if (op->data.ddr) | |
462 | rpc->ddr |= RPCIF_SMDRENR_SPIDRE; | |
463 | ||
464 | if (offs && len) | |
465 | nbytes = *len; | |
466 | else | |
467 | nbytes = op->data.nbytes; | |
468 | rpc->xferlen = nbytes; | |
469 | ||
fff53a55 | 470 | rpc->enable |= RPCIF_SMENR_SPIDB(rpcif_bit_size(op->data.buswidth)); |
ca7d8b98 SS |
471 | } |
472 | } | |
473 | EXPORT_SYMBOL(rpcif_prepare); | |
474 | ||
475 | int rpcif_manual_xfer(struct rpcif *rpc) | |
476 | { | |
fff53a55 | 477 | u32 smenr, smcr, pos = 0, max = rpc->bus_size == 2 ? 8 : 4; |
ca7d8b98 SS |
478 | int ret = 0; |
479 | ||
ca7d8b98 SS |
480 | pm_runtime_get_sync(rpc->dev); |
481 | ||
482 | regmap_update_bits(rpc->regmap, RPCIF_PHYCNT, | |
483 | RPCIF_PHYCNT_CAL, RPCIF_PHYCNT_CAL); | |
484 | regmap_update_bits(rpc->regmap, RPCIF_CMNCR, | |
485 | RPCIF_CMNCR_MD, RPCIF_CMNCR_MD); | |
486 | regmap_write(rpc->regmap, RPCIF_SMCMR, rpc->command); | |
487 | regmap_write(rpc->regmap, RPCIF_SMOPR, rpc->option); | |
488 | regmap_write(rpc->regmap, RPCIF_SMDMCR, rpc->dummy); | |
489 | regmap_write(rpc->regmap, RPCIF_SMDRENR, rpc->ddr); | |
fff53a55 | 490 | regmap_write(rpc->regmap, RPCIF_SMADR, rpc->smadr); |
ca7d8b98 SS |
491 | smenr = rpc->enable; |
492 | ||
493 | switch (rpc->dir) { | |
494 | case RPCIF_DATA_OUT: | |
495 | while (pos < rpc->xferlen) { | |
fff53a55 | 496 | u32 bytes_left = rpc->xferlen - pos; |
1f26a60b | 497 | u32 nbytes, data[2], *p = data; |
ca7d8b98 SS |
498 | |
499 | smcr = rpc->smcr | RPCIF_SMCR_SPIE; | |
fff53a55 WS |
500 | |
501 | /* nbytes may only be 1, 2, 4, or 8 */ | |
502 | nbytes = bytes_left >= max ? max : (1 << ilog2(bytes_left)); | |
503 | if (bytes_left > nbytes) | |
ca7d8b98 | 504 | smcr |= RPCIF_SMCR_SSLKP; |
fff53a55 WS |
505 | |
506 | smenr |= RPCIF_SMENR_SPIDE(rpcif_bits_set(rpc, nbytes)); | |
507 | regmap_write(rpc->regmap, RPCIF_SMENR, smenr); | |
7e842d70 | 508 | rpc->xfer_size = nbytes; |
ca7d8b98 SS |
509 | |
510 | memcpy(data, rpc->buffer + pos, nbytes); | |
1f26a60b GU |
511 | if (nbytes == 8) |
512 | regmap_write(rpc->regmap, RPCIF_SMWDR1, *p++); | |
513 | regmap_write(rpc->regmap, RPCIF_SMWDR0, *p); | |
ca7d8b98 | 514 | |
ca7d8b98 SS |
515 | regmap_write(rpc->regmap, RPCIF_SMCR, smcr); |
516 | ret = wait_msg_xfer_end(rpc); | |
517 | if (ret) | |
518 | goto err_out; | |
519 | ||
520 | pos += nbytes; | |
521 | smenr = rpc->enable & | |
522 | ~RPCIF_SMENR_CDE & ~RPCIF_SMENR_ADE(0xF); | |
523 | } | |
524 | break; | |
525 | case RPCIF_DATA_IN: | |
526 | /* | |
527 | * RPC-IF spoils the data for the commands without an address | |
528 | * phase (like RDID) in the manual mode, so we'll have to work | |
529 | * around this issue by using the external address space read | |
530 | * mode instead. | |
531 | */ | |
532 | if (!(smenr & RPCIF_SMENR_ADE(0xF)) && rpc->dirmap) { | |
533 | u32 dummy; | |
534 | ||
535 | regmap_update_bits(rpc->regmap, RPCIF_CMNCR, | |
536 | RPCIF_CMNCR_MD, 0); | |
537 | regmap_write(rpc->regmap, RPCIF_DRCR, | |
538 | RPCIF_DRCR_RBURST(32) | RPCIF_DRCR_RBE); | |
539 | regmap_write(rpc->regmap, RPCIF_DRCMR, rpc->command); | |
540 | regmap_write(rpc->regmap, RPCIF_DREAR, | |
541 | RPCIF_DREAR_EAC(1)); | |
542 | regmap_write(rpc->regmap, RPCIF_DROPR, rpc->option); | |
543 | regmap_write(rpc->regmap, RPCIF_DRENR, | |
544 | smenr & ~RPCIF_SMENR_SPIDE(0xF)); | |
545 | regmap_write(rpc->regmap, RPCIF_DRDMCR, rpc->dummy); | |
546 | regmap_write(rpc->regmap, RPCIF_DRDRENR, rpc->ddr); | |
547 | memcpy_fromio(rpc->buffer, rpc->dirmap, rpc->xferlen); | |
548 | regmap_write(rpc->regmap, RPCIF_DRCR, RPCIF_DRCR_RCF); | |
549 | /* Dummy read according to spec */ | |
550 | regmap_read(rpc->regmap, RPCIF_DRCR, &dummy); | |
551 | break; | |
552 | } | |
553 | while (pos < rpc->xferlen) { | |
fff53a55 | 554 | u32 bytes_left = rpc->xferlen - pos; |
1f26a60b | 555 | u32 nbytes, data[2], *p = data; |
ca7d8b98 | 556 | |
fff53a55 WS |
557 | /* nbytes may only be 1, 2, 4, or 8 */ |
558 | nbytes = bytes_left >= max ? max : (1 << ilog2(bytes_left)); | |
ca7d8b98 SS |
559 | |
560 | regmap_write(rpc->regmap, RPCIF_SMADR, | |
561 | rpc->smadr + pos); | |
fff53a55 WS |
562 | smenr &= ~RPCIF_SMENR_SPIDE(0xF); |
563 | smenr |= RPCIF_SMENR_SPIDE(rpcif_bits_set(rpc, nbytes)); | |
ca7d8b98 SS |
564 | regmap_write(rpc->regmap, RPCIF_SMENR, smenr); |
565 | regmap_write(rpc->regmap, RPCIF_SMCR, | |
566 | rpc->smcr | RPCIF_SMCR_SPIE); | |
7e842d70 | 567 | rpc->xfer_size = nbytes; |
ca7d8b98 SS |
568 | ret = wait_msg_xfer_end(rpc); |
569 | if (ret) | |
570 | goto err_out; | |
571 | ||
1f26a60b GU |
572 | if (nbytes == 8) |
573 | regmap_read(rpc->regmap, RPCIF_SMRDR1, p++); | |
574 | regmap_read(rpc->regmap, RPCIF_SMRDR0, p); | |
ca7d8b98 SS |
575 | memcpy(rpc->buffer + pos, data, nbytes); |
576 | ||
577 | pos += nbytes; | |
578 | } | |
579 | break; | |
580 | default: | |
581 | regmap_write(rpc->regmap, RPCIF_SMENR, rpc->enable); | |
582 | regmap_write(rpc->regmap, RPCIF_SMCR, | |
583 | rpc->smcr | RPCIF_SMCR_SPIE); | |
584 | ret = wait_msg_xfer_end(rpc); | |
585 | if (ret) | |
586 | goto err_out; | |
587 | } | |
588 | ||
589 | exit: | |
590 | pm_runtime_put(rpc->dev); | |
591 | return ret; | |
592 | ||
593 | err_out: | |
a0453f4e LP |
594 | if (reset_control_reset(rpc->rstc)) |
595 | dev_err(rpc->dev, "Failed to reset HW\n"); | |
ca7d8b98 SS |
596 | rpcif_hw_init(rpc, rpc->bus_size == 2); |
597 | goto exit; | |
598 | } | |
599 | EXPORT_SYMBOL(rpcif_manual_xfer); | |
600 | ||
1869023e AG |
601 | static void memcpy_fromio_readw(void *to, |
602 | const void __iomem *from, | |
603 | size_t count) | |
604 | { | |
605 | const int maxw = (IS_ENABLED(CONFIG_64BIT)) ? 8 : 4; | |
606 | u8 buf[2]; | |
607 | ||
608 | if (count && ((unsigned long)from & 1)) { | |
609 | *(u16 *)buf = __raw_readw((void __iomem *)((unsigned long)from & ~1)); | |
610 | *(u8 *)to = buf[1]; | |
611 | from++; | |
612 | to++; | |
613 | count--; | |
614 | } | |
615 | while (count >= 2 && !IS_ALIGNED((unsigned long)from, maxw)) { | |
616 | *(u16 *)to = __raw_readw(from); | |
617 | from += 2; | |
618 | to += 2; | |
619 | count -= 2; | |
620 | } | |
621 | while (count >= maxw) { | |
622 | #ifdef CONFIG_64BIT | |
623 | *(u64 *)to = __raw_readq(from); | |
624 | #else | |
625 | *(u32 *)to = __raw_readl(from); | |
626 | #endif | |
627 | from += maxw; | |
628 | to += maxw; | |
629 | count -= maxw; | |
630 | } | |
631 | while (count >= 2) { | |
632 | *(u16 *)to = __raw_readw(from); | |
633 | from += 2; | |
634 | to += 2; | |
635 | count -= 2; | |
636 | } | |
637 | if (count) { | |
638 | *(u16 *)buf = __raw_readw(from); | |
639 | *(u8 *)to = buf[0]; | |
640 | } | |
641 | } | |
642 | ||
ca7d8b98 SS |
643 | ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf) |
644 | { | |
5da9b59b LP |
645 | loff_t from = offs & (rpc->size - 1); |
646 | size_t size = rpc->size - from; | |
ca7d8b98 SS |
647 | |
648 | if (len > size) | |
649 | len = size; | |
650 | ||
651 | pm_runtime_get_sync(rpc->dev); | |
652 | ||
653 | regmap_update_bits(rpc->regmap, RPCIF_CMNCR, RPCIF_CMNCR_MD, 0); | |
654 | regmap_write(rpc->regmap, RPCIF_DRCR, 0); | |
655 | regmap_write(rpc->regmap, RPCIF_DRCMR, rpc->command); | |
656 | regmap_write(rpc->regmap, RPCIF_DREAR, | |
657 | RPCIF_DREAR_EAV(offs >> 25) | RPCIF_DREAR_EAC(1)); | |
658 | regmap_write(rpc->regmap, RPCIF_DROPR, rpc->option); | |
659 | regmap_write(rpc->regmap, RPCIF_DRENR, | |
660 | rpc->enable & ~RPCIF_SMENR_SPIDE(0xF)); | |
661 | regmap_write(rpc->regmap, RPCIF_DRDMCR, rpc->dummy); | |
662 | regmap_write(rpc->regmap, RPCIF_DRDRENR, rpc->ddr); | |
663 | ||
1869023e AG |
664 | if (rpc->bus_size == 2) |
665 | memcpy_fromio_readw(buf, rpc->dirmap + from, len); | |
666 | else | |
667 | memcpy_fromio(buf, rpc->dirmap + from, len); | |
ca7d8b98 SS |
668 | |
669 | pm_runtime_put(rpc->dev); | |
670 | ||
671 | return len; | |
672 | } | |
673 | EXPORT_SYMBOL(rpcif_dirmap_read); | |
674 | ||
675 | static int rpcif_probe(struct platform_device *pdev) | |
676 | { | |
677 | struct platform_device *vdev; | |
678 | struct device_node *flash; | |
679 | const char *name; | |
b452dbf2 | 680 | int ret; |
ca7d8b98 SS |
681 | |
682 | flash = of_get_next_child(pdev->dev.of_node, NULL); | |
683 | if (!flash) { | |
684 | dev_warn(&pdev->dev, "no flash node found\n"); | |
685 | return -ENODEV; | |
686 | } | |
687 | ||
688 | if (of_device_is_compatible(flash, "jedec,spi-nor")) { | |
689 | name = "rpc-if-spi"; | |
690 | } else if (of_device_is_compatible(flash, "cfi-flash")) { | |
691 | name = "rpc-if-hyperflash"; | |
692 | } else { | |
4e6b86b4 | 693 | of_node_put(flash); |
ca7d8b98 SS |
694 | dev_warn(&pdev->dev, "unknown flash type\n"); |
695 | return -ENODEV; | |
696 | } | |
4e6b86b4 | 697 | of_node_put(flash); |
ca7d8b98 SS |
698 | |
699 | vdev = platform_device_alloc(name, pdev->id); | |
700 | if (!vdev) | |
701 | return -ENOMEM; | |
702 | vdev->dev.parent = &pdev->dev; | |
703 | platform_set_drvdata(pdev, vdev); | |
b452dbf2 JH |
704 | |
705 | ret = platform_device_add(vdev); | |
706 | if (ret) { | |
707 | platform_device_put(vdev); | |
708 | return ret; | |
709 | } | |
710 | ||
711 | return 0; | |
ca7d8b98 SS |
712 | } |
713 | ||
714 | static int rpcif_remove(struct platform_device *pdev) | |
715 | { | |
716 | struct platform_device *vdev = platform_get_drvdata(pdev); | |
717 | ||
718 | platform_device_unregister(vdev); | |
719 | ||
720 | return 0; | |
721 | } | |
722 | ||
723 | static const struct of_device_id rpcif_of_match[] = { | |
b04cc0d9 | 724 | { .compatible = "renesas,rcar-gen3-rpc-if", .data = (void *)RPCIF_RCAR_GEN3 }, |
1de3866f | 725 | { .compatible = "renesas,rcar-gen4-rpc-if", .data = (void *)RPCIF_RCAR_GEN4 }, |
b04cc0d9 | 726 | { .compatible = "renesas,rzg2l-rpc-if", .data = (void *)RPCIF_RZ_G2L }, |
ca7d8b98 SS |
727 | {}, |
728 | }; | |
729 | MODULE_DEVICE_TABLE(of, rpcif_of_match); | |
730 | ||
731 | static struct platform_driver rpcif_driver = { | |
732 | .probe = rpcif_probe, | |
733 | .remove = rpcif_remove, | |
734 | .driver = { | |
735 | .name = "rpc-if", | |
736 | .of_match_table = rpcif_of_match, | |
737 | }, | |
738 | }; | |
739 | module_platform_driver(rpcif_driver); | |
740 | ||
741 | MODULE_DESCRIPTION("Renesas RPC-IF core driver"); | |
742 | MODULE_LICENSE("GPL v2"); |