1 | /* |
2 | * ASPEED AST2400 SMC Controller (SPI Flash Only) |
3 | * |
4 | * Copyright (C) 2016 IBM Corp. |
5 | * |
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | * of this software and associated documentation files (the "Software"), to deal |
8 | * in the Software without restriction, including without limitation the rights |
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
10 | * copies of the Software, and to permit persons to whom the Software is |
11 | * furnished to do so, subject to the following conditions: |
12 | * |
13 | * The above copyright notice and this permission notice shall be included in |
14 | * all copies or substantial portions of the Software. |
15 | * |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
22 | * THE SOFTWARE. |
23 | */ |
24 | |
25 | #include "qemu/osdep.h" |
26 | #include "hw/sysbus.h" |
27 | #include "migration/vmstate.h" |
28 | #include "qemu/log.h" |
29 | #include "qemu/module.h" |
30 | #include "qemu/error-report.h" |
31 | |
32 | #include "hw/irq.h" |
33 | #include "hw/qdev-properties.h" |
34 | #include "hw/ssi/aspeed_smc.h" |
35 | |
36 | /* CE Type Setting Register */ |
37 | #define R_CONF (0x00 / 4) |
38 | #define CONF_LEGACY_DISABLE (1 << 31) |
39 | #define CONF_ENABLE_W4 20 |
40 | #define CONF_ENABLE_W3 19 |
41 | #define CONF_ENABLE_W2 18 |
42 | #define CONF_ENABLE_W1 17 |
43 | #define CONF_ENABLE_W0 16 |
44 | #define CONF_FLASH_TYPE4 8 |
45 | #define CONF_FLASH_TYPE3 6 |
46 | #define CONF_FLASH_TYPE2 4 |
47 | #define CONF_FLASH_TYPE1 2 |
48 | #define CONF_FLASH_TYPE0 0 |
49 | #define CONF_FLASH_TYPE_NOR 0x0 |
50 | #define CONF_FLASH_TYPE_NAND 0x1 |
51 | #define CONF_FLASH_TYPE_SPI 0x2 |
52 | |
53 | /* CE Control Register */ |
54 | #define R_CE_CTRL (0x04 / 4) |
55 | #define CTRL_EXTENDED4 4 /* 32 bit addressing for SPI */ |
56 | #define CTRL_EXTENDED3 3 /* 32 bit addressing for SPI */ |
57 | #define CTRL_EXTENDED2 2 /* 32 bit addressing for SPI */ |
58 | #define CTRL_EXTENDED1 1 /* 32 bit addressing for SPI */ |
59 | #define CTRL_EXTENDED0 0 /* 32 bit addressing for SPI */ |
60 | |
61 | /* Interrupt Control and Status Register */ |
62 | #define R_INTR_CTRL (0x08 / 4) |
63 | #define INTR_CTRL_DMA_STATUS (1 << 11) |
64 | #define INTR_CTRL_CMD_ABORT_STATUS (1 << 10) |
65 | #define INTR_CTRL_WRITE_PROTECT_STATUS (1 << 9) |
66 | #define INTR_CTRL_DMA_EN (1 << 3) |
67 | #define INTR_CTRL_CMD_ABORT_EN (1 << 2) |
68 | #define INTR_CTRL_WRITE_PROTECT_EN (1 << 1) |
69 | |
70 | /* CEx Control Register */ |
71 | #define R_CTRL0 (0x10 / 4) |
72 | #define CTRL_IO_DUAL_DATA (1 << 29) |
73 | #define CTRL_IO_DUAL_ADDR_DATA (1 << 28) /* Includes dummies */ |
74 | #define CTRL_CMD_SHIFT 16 |
75 | #define CTRL_CMD_MASK 0xff |
76 | #define CTRL_DUMMY_HIGH_SHIFT 14 |
77 | #define CTRL_AST2400_SPI_4BYTE (1 << 13) |
78 | #define CTRL_DUMMY_LOW_SHIFT 6 /* 2 bits [7:6] */ |
79 | #define CTRL_CE_STOP_ACTIVE (1 << 2) |
80 | #define CTRL_CMD_MODE_MASK 0x3 |
81 | #define CTRL_READMODE 0x0 |
82 | #define CTRL_FREADMODE 0x1 |
83 | #define CTRL_WRITEMODE 0x2 |
84 | #define CTRL_USERMODE 0x3 |
85 | #define R_CTRL1 (0x14 / 4) |
86 | #define R_CTRL2 (0x18 / 4) |
87 | #define R_CTRL3 (0x1C / 4) |
88 | #define R_CTRL4 (0x20 / 4) |
89 | |
90 | /* CEx Segment Address Register */ |
91 | #define R_SEG_ADDR0 (0x30 / 4) |
92 | #define SEG_END_SHIFT 24 /* 8MB units */ |
93 | #define SEG_END_MASK 0xff |
94 | #define SEG_START_SHIFT 16 /* address bit [A29-A23] */ |
95 | #define SEG_START_MASK 0xff |
96 | #define R_SEG_ADDR1 (0x34 / 4) |
97 | #define R_SEG_ADDR2 (0x38 / 4) |
98 | #define R_SEG_ADDR3 (0x3C / 4) |
99 | #define R_SEG_ADDR4 (0x40 / 4) |
100 | |
101 | /* Misc Control Register #1 */ |
102 | #define R_MISC_CTRL1 (0x50 / 4) |
103 | |
104 | /* SPI dummy cycle data */ |
105 | #define R_DUMMY_DATA (0x54 / 4) |
106 | |
107 | /* DMA Control/Status Register */ |
108 | #define R_DMA_CTRL (0x80 / 4) |
109 | #define DMA_CTRL_DELAY_MASK 0xf |
110 | #define DMA_CTRL_DELAY_SHIFT 8 |
111 | #define DMA_CTRL_FREQ_MASK 0xf |
112 | #define DMA_CTRL_FREQ_SHIFT 4 |
113 | #define DMA_CTRL_MODE (1 << 3) |
114 | #define DMA_CTRL_CKSUM (1 << 2) |
115 | #define DMA_CTRL_DIR (1 << 1) |
116 | #define DMA_CTRL_EN (1 << 0) |
117 | |
118 | /* DMA Flash Side Address */ |
119 | #define R_DMA_FLASH_ADDR (0x84 / 4) |
120 | |
121 | /* DMA DRAM Side Address */ |
122 | #define R_DMA_DRAM_ADDR (0x88 / 4) |
123 | |
124 | /* DMA Length Register */ |
125 | #define R_DMA_LEN (0x8C / 4) |
126 | |
127 | /* Checksum Calculation Result */ |
128 | #define R_DMA_CHECKSUM (0x90 / 4) |
129 | |
130 | /* Misc Control Register #2 */ |
131 | #define R_TIMINGS (0x94 / 4) |
132 | |
133 | /* SPI controller registers and bits */ |
134 | #define R_SPI_CONF (0x00 / 4) |
135 | #define SPI_CONF_ENABLE_W0 0 |
136 | #define R_SPI_CTRL0 (0x4 / 4) |
137 | #define R_SPI_MISC_CTRL (0x10 / 4) |
138 | #define R_SPI_TIMINGS (0x14 / 4) |
139 | |
140 | #define ASPEED_SMC_R_SPI_MAX (0x20 / 4) |
141 | #define ASPEED_SMC_R_SMC_MAX (0x20 / 4) |
142 | |
143 | #define ASPEED_SOC_SMC_FLASH_BASE 0x10000000 |
144 | #define ASPEED_SOC_FMC_FLASH_BASE 0x20000000 |
145 | #define ASPEED_SOC_SPI_FLASH_BASE 0x30000000 |
146 | #define ASPEED_SOC_SPI2_FLASH_BASE 0x38000000 |
147 | |
148 | /* Flash opcodes. */ |
149 | #define SPI_OP_READ 0x03 /* Read data bytes (low frequency) */ |
150 | |
151 | #define SNOOP_OFF 0xFF |
152 | #define SNOOP_START 0x0 |
153 | |
154 | /* |
155 | * Default segments mapping addresses and size for each slave per |
156 | * controller. These can be changed when board is initialized with the |
157 | * Segment Address Registers. |
158 | */ |
159 | static const AspeedSegments aspeed_segments_legacy[] = { |
160 | { 0x10000000, 32 * 1024 * 1024 }, |
161 | }; |
162 | |
163 | static const AspeedSegments aspeed_segments_fmc[] = { |
164 | { 0x20000000, 64 * 1024 * 1024 }, /* start address is readonly */ |
165 | { 0x24000000, 32 * 1024 * 1024 }, |
166 | { 0x26000000, 32 * 1024 * 1024 }, |
167 | { 0x28000000, 32 * 1024 * 1024 }, |
168 | { 0x2A000000, 32 * 1024 * 1024 } |
169 | }; |
170 | |
171 | static const AspeedSegments aspeed_segments_spi[] = { |
172 | { 0x30000000, 64 * 1024 * 1024 }, |
173 | }; |
174 | |
175 | static const AspeedSegments aspeed_segments_ast2500_fmc[] = { |
176 | { 0x20000000, 128 * 1024 * 1024 }, /* start address is readonly */ |
177 | { 0x28000000, 32 * 1024 * 1024 }, |
178 | { 0x2A000000, 32 * 1024 * 1024 }, |
179 | }; |
180 | |
181 | static const AspeedSegments aspeed_segments_ast2500_spi1[] = { |
182 | { 0x30000000, 32 * 1024 * 1024 }, /* start address is readonly */ |
183 | { 0x32000000, 96 * 1024 * 1024 }, /* end address is readonly */ |
184 | }; |
185 | |
186 | static const AspeedSegments aspeed_segments_ast2500_spi2[] = { |
187 | { 0x38000000, 32 * 1024 * 1024 }, /* start address is readonly */ |
188 | { 0x3A000000, 96 * 1024 * 1024 }, /* end address is readonly */ |
189 | }; |
190 | |
191 | static const AspeedSMCController controllers[] = { |
192 | { |
193 | .name = "aspeed.smc.smc" , |
194 | .r_conf = R_CONF, |
195 | .r_ce_ctrl = R_CE_CTRL, |
196 | .r_ctrl0 = R_CTRL0, |
197 | .r_timings = R_TIMINGS, |
198 | .conf_enable_w0 = CONF_ENABLE_W0, |
199 | .max_slaves = 5, |
200 | .segments = aspeed_segments_legacy, |
201 | .flash_window_base = ASPEED_SOC_SMC_FLASH_BASE, |
202 | .flash_window_size = 0x6000000, |
203 | .has_dma = false, |
204 | .nregs = ASPEED_SMC_R_SMC_MAX, |
205 | }, { |
206 | .name = "aspeed.smc.fmc" , |
207 | .r_conf = R_CONF, |
208 | .r_ce_ctrl = R_CE_CTRL, |
209 | .r_ctrl0 = R_CTRL0, |
210 | .r_timings = R_TIMINGS, |
211 | .conf_enable_w0 = CONF_ENABLE_W0, |
212 | .max_slaves = 5, |
213 | .segments = aspeed_segments_fmc, |
214 | .flash_window_base = ASPEED_SOC_FMC_FLASH_BASE, |
215 | .flash_window_size = 0x10000000, |
216 | .has_dma = true, |
217 | .nregs = ASPEED_SMC_R_MAX, |
218 | }, { |
219 | .name = "aspeed.smc.spi" , |
220 | .r_conf = R_SPI_CONF, |
221 | .r_ce_ctrl = 0xff, |
222 | .r_ctrl0 = R_SPI_CTRL0, |
223 | .r_timings = R_SPI_TIMINGS, |
224 | .conf_enable_w0 = SPI_CONF_ENABLE_W0, |
225 | .max_slaves = 1, |
226 | .segments = aspeed_segments_spi, |
227 | .flash_window_base = ASPEED_SOC_SPI_FLASH_BASE, |
228 | .flash_window_size = 0x10000000, |
229 | .has_dma = false, |
230 | .nregs = ASPEED_SMC_R_SPI_MAX, |
231 | }, { |
232 | .name = "aspeed.smc.ast2500-fmc" , |
233 | .r_conf = R_CONF, |
234 | .r_ce_ctrl = R_CE_CTRL, |
235 | .r_ctrl0 = R_CTRL0, |
236 | .r_timings = R_TIMINGS, |
237 | .conf_enable_w0 = CONF_ENABLE_W0, |
238 | .max_slaves = 3, |
239 | .segments = aspeed_segments_ast2500_fmc, |
240 | .flash_window_base = ASPEED_SOC_FMC_FLASH_BASE, |
241 | .flash_window_size = 0x10000000, |
242 | .has_dma = true, |
243 | .nregs = ASPEED_SMC_R_MAX, |
244 | }, { |
245 | .name = "aspeed.smc.ast2500-spi1" , |
246 | .r_conf = R_CONF, |
247 | .r_ce_ctrl = R_CE_CTRL, |
248 | .r_ctrl0 = R_CTRL0, |
249 | .r_timings = R_TIMINGS, |
250 | .conf_enable_w0 = CONF_ENABLE_W0, |
251 | .max_slaves = 2, |
252 | .segments = aspeed_segments_ast2500_spi1, |
253 | .flash_window_base = ASPEED_SOC_SPI_FLASH_BASE, |
254 | .flash_window_size = 0x8000000, |
255 | .has_dma = false, |
256 | .nregs = ASPEED_SMC_R_MAX, |
257 | }, { |
258 | .name = "aspeed.smc.ast2500-spi2" , |
259 | .r_conf = R_CONF, |
260 | .r_ce_ctrl = R_CE_CTRL, |
261 | .r_ctrl0 = R_CTRL0, |
262 | .r_timings = R_TIMINGS, |
263 | .conf_enable_w0 = CONF_ENABLE_W0, |
264 | .max_slaves = 2, |
265 | .segments = aspeed_segments_ast2500_spi2, |
266 | .flash_window_base = ASPEED_SOC_SPI2_FLASH_BASE, |
267 | .flash_window_size = 0x8000000, |
268 | .has_dma = false, |
269 | .nregs = ASPEED_SMC_R_MAX, |
270 | }, |
271 | }; |
272 | |
273 | /* |
274 | * The Segment Register uses a 8MB unit to encode the start address |
275 | * and the end address of the mapping window of a flash SPI slave : |
276 | * |
277 | * | byte 1 | byte 2 | byte 3 | byte 4 | |
278 | * +--------+--------+--------+--------+ |
279 | * | end | start | 0 | 0 | |
280 | * |
281 | */ |
282 | static inline uint32_t aspeed_smc_segment_to_reg(const AspeedSegments *seg) |
283 | { |
284 | uint32_t reg = 0; |
285 | reg |= ((seg->addr >> 23) & SEG_START_MASK) << SEG_START_SHIFT; |
286 | reg |= (((seg->addr + seg->size) >> 23) & SEG_END_MASK) << SEG_END_SHIFT; |
287 | return reg; |
288 | } |
289 | |
290 | static inline void aspeed_smc_reg_to_segment(uint32_t reg, AspeedSegments *seg) |
291 | { |
292 | seg->addr = ((reg >> SEG_START_SHIFT) & SEG_START_MASK) << 23; |
293 | seg->size = (((reg >> SEG_END_SHIFT) & SEG_END_MASK) << 23) - seg->addr; |
294 | } |
295 | |
296 | static bool aspeed_smc_flash_overlap(const AspeedSMCState *s, |
297 | const AspeedSegments *new, |
298 | int cs) |
299 | { |
300 | AspeedSegments seg; |
301 | int i; |
302 | |
303 | for (i = 0; i < s->ctrl->max_slaves; i++) { |
304 | if (i == cs) { |
305 | continue; |
306 | } |
307 | |
308 | aspeed_smc_reg_to_segment(s->regs[R_SEG_ADDR0 + i], &seg); |
309 | |
310 | if (new->addr + new->size > seg.addr && |
311 | new->addr < seg.addr + seg.size) { |
312 | qemu_log_mask(LOG_GUEST_ERROR, "%s: new segment CS%d [ 0x%" |
313 | HWADDR_PRIx" - 0x%" HWADDR_PRIx" ] overlaps with " |
314 | "CS%d [ 0x%" HWADDR_PRIx" - 0x%" HWADDR_PRIx" ]\n" , |
315 | s->ctrl->name, cs, new->addr, new->addr + new->size, |
316 | i, seg.addr, seg.addr + seg.size); |
317 | return true; |
318 | } |
319 | } |
320 | return false; |
321 | } |
322 | |
323 | static void aspeed_smc_flash_set_segment(AspeedSMCState *s, int cs, |
324 | uint64_t new) |
325 | { |
326 | AspeedSMCFlash *fl = &s->flashes[cs]; |
327 | AspeedSegments seg; |
328 | |
329 | aspeed_smc_reg_to_segment(new, &seg); |
330 | |
331 | /* The start address of CS0 is read-only */ |
332 | if (cs == 0 && seg.addr != s->ctrl->flash_window_base) { |
333 | qemu_log_mask(LOG_GUEST_ERROR, |
334 | "%s: Tried to change CS0 start address to 0x%" |
335 | HWADDR_PRIx "\n" , s->ctrl->name, seg.addr); |
336 | seg.addr = s->ctrl->flash_window_base; |
337 | new = aspeed_smc_segment_to_reg(&seg); |
338 | } |
339 | |
340 | /* |
341 | * The end address of the AST2500 spi controllers is also |
342 | * read-only. |
343 | */ |
344 | if ((s->ctrl->segments == aspeed_segments_ast2500_spi1 || |
345 | s->ctrl->segments == aspeed_segments_ast2500_spi2) && |
346 | cs == s->ctrl->max_slaves && |
347 | seg.addr + seg.size != s->ctrl->segments[cs].addr + |
348 | s->ctrl->segments[cs].size) { |
349 | qemu_log_mask(LOG_GUEST_ERROR, |
350 | "%s: Tried to change CS%d end address to 0x%" |
351 | HWADDR_PRIx "\n" , s->ctrl->name, cs, seg.addr + seg.size); |
352 | seg.size = s->ctrl->segments[cs].addr + s->ctrl->segments[cs].size - |
353 | seg.addr; |
354 | new = aspeed_smc_segment_to_reg(&seg); |
355 | } |
356 | |
357 | /* Keep the segment in the overall flash window */ |
358 | if (seg.addr + seg.size <= s->ctrl->flash_window_base || |
359 | seg.addr > s->ctrl->flash_window_base + s->ctrl->flash_window_size) { |
360 | qemu_log_mask(LOG_GUEST_ERROR, "%s: new segment for CS%d is invalid : " |
361 | "[ 0x%" HWADDR_PRIx" - 0x%" HWADDR_PRIx" ]\n" , |
362 | s->ctrl->name, cs, seg.addr, seg.addr + seg.size); |
363 | return; |
364 | } |
365 | |
366 | /* Check start address vs. alignment */ |
367 | if (seg.size && !QEMU_IS_ALIGNED(seg.addr, seg.size)) { |
368 | qemu_log_mask(LOG_GUEST_ERROR, "%s: new segment for CS%d is not " |
369 | "aligned : [ 0x%" HWADDR_PRIx" - 0x%" HWADDR_PRIx" ]\n" , |
370 | s->ctrl->name, cs, seg.addr, seg.addr + seg.size); |
371 | } |
372 | |
373 | /* And segments should not overlap (in the specs) */ |
374 | aspeed_smc_flash_overlap(s, &seg, cs); |
375 | |
376 | /* All should be fine now to move the region */ |
377 | memory_region_transaction_begin(); |
378 | memory_region_set_size(&fl->mmio, seg.size); |
379 | memory_region_set_address(&fl->mmio, seg.addr - s->ctrl->flash_window_base); |
380 | memory_region_set_enabled(&fl->mmio, true); |
381 | memory_region_transaction_commit(); |
382 | |
383 | s->regs[R_SEG_ADDR0 + cs] = new; |
384 | } |
385 | |
386 | static uint64_t aspeed_smc_flash_default_read(void *opaque, hwaddr addr, |
387 | unsigned size) |
388 | { |
389 | qemu_log_mask(LOG_GUEST_ERROR, "%s: To 0x%" HWADDR_PRIx " of size %u" |
390 | PRIx64 "\n" , __func__, addr, size); |
391 | return 0; |
392 | } |
393 | |
394 | static void aspeed_smc_flash_default_write(void *opaque, hwaddr addr, |
395 | uint64_t data, unsigned size) |
396 | { |
397 | qemu_log_mask(LOG_GUEST_ERROR, "%s: To 0x%" HWADDR_PRIx " of size %u: 0x%" |
398 | PRIx64 "\n" , __func__, addr, size, data); |
399 | } |
400 | |
401 | static const MemoryRegionOps aspeed_smc_flash_default_ops = { |
402 | .read = aspeed_smc_flash_default_read, |
403 | .write = aspeed_smc_flash_default_write, |
404 | .endianness = DEVICE_LITTLE_ENDIAN, |
405 | .valid = { |
406 | .min_access_size = 1, |
407 | .max_access_size = 4, |
408 | }, |
409 | }; |
410 | |
411 | static inline int aspeed_smc_flash_mode(const AspeedSMCFlash *fl) |
412 | { |
413 | const AspeedSMCState *s = fl->controller; |
414 | |
415 | return s->regs[s->r_ctrl0 + fl->id] & CTRL_CMD_MODE_MASK; |
416 | } |
417 | |
418 | static inline bool aspeed_smc_is_writable(const AspeedSMCFlash *fl) |
419 | { |
420 | const AspeedSMCState *s = fl->controller; |
421 | |
422 | return s->regs[s->r_conf] & (1 << (s->conf_enable_w0 + fl->id)); |
423 | } |
424 | |
425 | static inline int aspeed_smc_flash_cmd(const AspeedSMCFlash *fl) |
426 | { |
427 | const AspeedSMCState *s = fl->controller; |
428 | int cmd = (s->regs[s->r_ctrl0 + fl->id] >> CTRL_CMD_SHIFT) & CTRL_CMD_MASK; |
429 | |
430 | /* In read mode, the default SPI command is READ (0x3). In other |
431 | * modes, the command should necessarily be defined */ |
432 | if (aspeed_smc_flash_mode(fl) == CTRL_READMODE) { |
433 | cmd = SPI_OP_READ; |
434 | } |
435 | |
436 | if (!cmd) { |
437 | qemu_log_mask(LOG_GUEST_ERROR, "%s: no command defined for mode %d\n" , |
438 | __func__, aspeed_smc_flash_mode(fl)); |
439 | } |
440 | |
441 | return cmd; |
442 | } |
443 | |
444 | static inline int aspeed_smc_flash_is_4byte(const AspeedSMCFlash *fl) |
445 | { |
446 | const AspeedSMCState *s = fl->controller; |
447 | |
448 | if (s->ctrl->segments == aspeed_segments_spi) { |
449 | return s->regs[s->r_ctrl0] & CTRL_AST2400_SPI_4BYTE; |
450 | } else { |
451 | return s->regs[s->r_ce_ctrl] & (1 << (CTRL_EXTENDED0 + fl->id)); |
452 | } |
453 | } |
454 | |
455 | static inline bool aspeed_smc_is_ce_stop_active(const AspeedSMCFlash *fl) |
456 | { |
457 | const AspeedSMCState *s = fl->controller; |
458 | |
459 | return s->regs[s->r_ctrl0 + fl->id] & CTRL_CE_STOP_ACTIVE; |
460 | } |
461 | |
462 | static void aspeed_smc_flash_select(AspeedSMCFlash *fl) |
463 | { |
464 | AspeedSMCState *s = fl->controller; |
465 | |
466 | s->regs[s->r_ctrl0 + fl->id] &= ~CTRL_CE_STOP_ACTIVE; |
467 | qemu_set_irq(s->cs_lines[fl->id], aspeed_smc_is_ce_stop_active(fl)); |
468 | } |
469 | |
470 | static void aspeed_smc_flash_unselect(AspeedSMCFlash *fl) |
471 | { |
472 | AspeedSMCState *s = fl->controller; |
473 | |
474 | s->regs[s->r_ctrl0 + fl->id] |= CTRL_CE_STOP_ACTIVE; |
475 | qemu_set_irq(s->cs_lines[fl->id], aspeed_smc_is_ce_stop_active(fl)); |
476 | } |
477 | |
478 | static uint32_t aspeed_smc_check_segment_addr(const AspeedSMCFlash *fl, |
479 | uint32_t addr) |
480 | { |
481 | const AspeedSMCState *s = fl->controller; |
482 | AspeedSegments seg; |
483 | |
484 | aspeed_smc_reg_to_segment(s->regs[R_SEG_ADDR0 + fl->id], &seg); |
485 | if ((addr % seg.size) != addr) { |
486 | qemu_log_mask(LOG_GUEST_ERROR, |
487 | "%s: invalid address 0x%08x for CS%d segment : " |
488 | "[ 0x%" HWADDR_PRIx" - 0x%" HWADDR_PRIx" ]\n" , |
489 | s->ctrl->name, addr, fl->id, seg.addr, |
490 | seg.addr + seg.size); |
491 | addr %= seg.size; |
492 | } |
493 | |
494 | return addr; |
495 | } |
496 | |
497 | static int aspeed_smc_flash_dummies(const AspeedSMCFlash *fl) |
498 | { |
499 | const AspeedSMCState *s = fl->controller; |
500 | uint32_t r_ctrl0 = s->regs[s->r_ctrl0 + fl->id]; |
501 | uint32_t dummy_high = (r_ctrl0 >> CTRL_DUMMY_HIGH_SHIFT) & 0x1; |
502 | uint32_t dummy_low = (r_ctrl0 >> CTRL_DUMMY_LOW_SHIFT) & 0x3; |
503 | uint32_t dummies = ((dummy_high << 2) | dummy_low) * 8; |
504 | |
505 | if (r_ctrl0 & CTRL_IO_DUAL_ADDR_DATA) { |
506 | dummies /= 2; |
507 | } |
508 | |
509 | return dummies; |
510 | } |
511 | |
512 | static void aspeed_smc_flash_setup(AspeedSMCFlash *fl, uint32_t addr) |
513 | { |
514 | const AspeedSMCState *s = fl->controller; |
515 | uint8_t cmd = aspeed_smc_flash_cmd(fl); |
516 | int i; |
517 | |
518 | /* Flash access can not exceed CS segment */ |
519 | addr = aspeed_smc_check_segment_addr(fl, addr); |
520 | |
521 | ssi_transfer(s->spi, cmd); |
522 | |
523 | if (aspeed_smc_flash_is_4byte(fl)) { |
524 | ssi_transfer(s->spi, (addr >> 24) & 0xff); |
525 | } |
526 | ssi_transfer(s->spi, (addr >> 16) & 0xff); |
527 | ssi_transfer(s->spi, (addr >> 8) & 0xff); |
528 | ssi_transfer(s->spi, (addr & 0xff)); |
529 | |
530 | /* |
531 | * Use fake transfers to model dummy bytes. The value should |
532 | * be configured to some non-zero value in fast read mode and |
533 | * zero in read mode. But, as the HW allows inconsistent |
534 | * settings, let's check for fast read mode. |
535 | */ |
536 | if (aspeed_smc_flash_mode(fl) == CTRL_FREADMODE) { |
537 | for (i = 0; i < aspeed_smc_flash_dummies(fl); i++) { |
538 | ssi_transfer(fl->controller->spi, s->regs[R_DUMMY_DATA] & 0xff); |
539 | } |
540 | } |
541 | } |
542 | |
543 | static uint64_t aspeed_smc_flash_read(void *opaque, hwaddr addr, unsigned size) |
544 | { |
545 | AspeedSMCFlash *fl = opaque; |
546 | AspeedSMCState *s = fl->controller; |
547 | uint64_t ret = 0; |
548 | int i; |
549 | |
550 | switch (aspeed_smc_flash_mode(fl)) { |
551 | case CTRL_USERMODE: |
552 | for (i = 0; i < size; i++) { |
553 | ret |= ssi_transfer(s->spi, 0x0) << (8 * i); |
554 | } |
555 | break; |
556 | case CTRL_READMODE: |
557 | case CTRL_FREADMODE: |
558 | aspeed_smc_flash_select(fl); |
559 | aspeed_smc_flash_setup(fl, addr); |
560 | |
561 | for (i = 0; i < size; i++) { |
562 | ret |= ssi_transfer(s->spi, 0x0) << (8 * i); |
563 | } |
564 | |
565 | aspeed_smc_flash_unselect(fl); |
566 | break; |
567 | default: |
568 | qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid flash mode %d\n" , |
569 | __func__, aspeed_smc_flash_mode(fl)); |
570 | } |
571 | |
572 | return ret; |
573 | } |
574 | |
575 | /* |
576 | * TODO (clg@kaod.org): stolen from xilinx_spips.c. Should move to a |
577 | * common include header. |
578 | */ |
579 | typedef enum { |
580 | READ = 0x3, READ_4 = 0x13, |
581 | FAST_READ = 0xb, FAST_READ_4 = 0x0c, |
582 | DOR = 0x3b, DOR_4 = 0x3c, |
583 | QOR = 0x6b, QOR_4 = 0x6c, |
584 | DIOR = 0xbb, DIOR_4 = 0xbc, |
585 | QIOR = 0xeb, QIOR_4 = 0xec, |
586 | |
587 | PP = 0x2, PP_4 = 0x12, |
588 | DPP = 0xa2, |
589 | QPP = 0x32, QPP_4 = 0x34, |
590 | } FlashCMD; |
591 | |
592 | static int aspeed_smc_num_dummies(uint8_t command) |
593 | { |
594 | switch (command) { /* check for dummies */ |
595 | case READ: /* no dummy bytes/cycles */ |
596 | case PP: |
597 | case DPP: |
598 | case QPP: |
599 | case READ_4: |
600 | case PP_4: |
601 | case QPP_4: |
602 | return 0; |
603 | case FAST_READ: |
604 | case DOR: |
605 | case QOR: |
606 | case DOR_4: |
607 | case QOR_4: |
608 | return 1; |
609 | case DIOR: |
610 | case FAST_READ_4: |
611 | case DIOR_4: |
612 | return 2; |
613 | case QIOR: |
614 | case QIOR_4: |
615 | return 4; |
616 | default: |
617 | return -1; |
618 | } |
619 | } |
620 | |
621 | static bool aspeed_smc_do_snoop(AspeedSMCFlash *fl, uint64_t data, |
622 | unsigned size) |
623 | { |
624 | AspeedSMCState *s = fl->controller; |
625 | uint8_t addr_width = aspeed_smc_flash_is_4byte(fl) ? 4 : 3; |
626 | |
627 | if (s->snoop_index == SNOOP_OFF) { |
628 | return false; /* Do nothing */ |
629 | |
630 | } else if (s->snoop_index == SNOOP_START) { |
631 | uint8_t cmd = data & 0xff; |
632 | int ndummies = aspeed_smc_num_dummies(cmd); |
633 | |
634 | /* |
635 | * No dummy cycles are expected with the current command. Turn |
636 | * off snooping and let the transfer proceed normally. |
637 | */ |
638 | if (ndummies <= 0) { |
639 | s->snoop_index = SNOOP_OFF; |
640 | return false; |
641 | } |
642 | |
643 | s->snoop_dummies = ndummies * 8; |
644 | |
645 | } else if (s->snoop_index >= addr_width + 1) { |
646 | |
647 | /* The SPI transfer has reached the dummy cycles sequence */ |
648 | for (; s->snoop_dummies; s->snoop_dummies--) { |
649 | ssi_transfer(s->spi, s->regs[R_DUMMY_DATA] & 0xff); |
650 | } |
651 | |
652 | /* If no more dummy cycles are expected, turn off snooping */ |
653 | if (!s->snoop_dummies) { |
654 | s->snoop_index = SNOOP_OFF; |
655 | } else { |
656 | s->snoop_index += size; |
657 | } |
658 | |
659 | /* |
660 | * Dummy cycles have been faked already. Ignore the current |
661 | * SPI transfer |
662 | */ |
663 | return true; |
664 | } |
665 | |
666 | s->snoop_index += size; |
667 | return false; |
668 | } |
669 | |
670 | static void aspeed_smc_flash_write(void *opaque, hwaddr addr, uint64_t data, |
671 | unsigned size) |
672 | { |
673 | AspeedSMCFlash *fl = opaque; |
674 | AspeedSMCState *s = fl->controller; |
675 | int i; |
676 | |
677 | if (!aspeed_smc_is_writable(fl)) { |
678 | qemu_log_mask(LOG_GUEST_ERROR, "%s: flash is not writable at 0x%" |
679 | HWADDR_PRIx "\n" , __func__, addr); |
680 | return; |
681 | } |
682 | |
683 | switch (aspeed_smc_flash_mode(fl)) { |
684 | case CTRL_USERMODE: |
685 | if (aspeed_smc_do_snoop(fl, data, size)) { |
686 | break; |
687 | } |
688 | |
689 | for (i = 0; i < size; i++) { |
690 | ssi_transfer(s->spi, (data >> (8 * i)) & 0xff); |
691 | } |
692 | break; |
693 | case CTRL_WRITEMODE: |
694 | aspeed_smc_flash_select(fl); |
695 | aspeed_smc_flash_setup(fl, addr); |
696 | |
697 | for (i = 0; i < size; i++) { |
698 | ssi_transfer(s->spi, (data >> (8 * i)) & 0xff); |
699 | } |
700 | |
701 | aspeed_smc_flash_unselect(fl); |
702 | break; |
703 | default: |
704 | qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid flash mode %d\n" , |
705 | __func__, aspeed_smc_flash_mode(fl)); |
706 | } |
707 | } |
708 | |
709 | static const MemoryRegionOps aspeed_smc_flash_ops = { |
710 | .read = aspeed_smc_flash_read, |
711 | .write = aspeed_smc_flash_write, |
712 | .endianness = DEVICE_LITTLE_ENDIAN, |
713 | .valid = { |
714 | .min_access_size = 1, |
715 | .max_access_size = 4, |
716 | }, |
717 | }; |
718 | |
719 | static void aspeed_smc_flash_update_cs(AspeedSMCFlash *fl) |
720 | { |
721 | AspeedSMCState *s = fl->controller; |
722 | |
723 | s->snoop_index = aspeed_smc_is_ce_stop_active(fl) ? SNOOP_OFF : SNOOP_START; |
724 | |
725 | qemu_set_irq(s->cs_lines[fl->id], aspeed_smc_is_ce_stop_active(fl)); |
726 | } |
727 | |
728 | static void aspeed_smc_reset(DeviceState *d) |
729 | { |
730 | AspeedSMCState *s = ASPEED_SMC(d); |
731 | int i; |
732 | |
733 | memset(s->regs, 0, sizeof s->regs); |
734 | |
735 | /* Pretend DMA is done (u-boot initialization) */ |
736 | s->regs[R_INTR_CTRL] = INTR_CTRL_DMA_STATUS; |
737 | |
738 | /* Unselect all slaves */ |
739 | for (i = 0; i < s->num_cs; ++i) { |
740 | s->regs[s->r_ctrl0 + i] |= CTRL_CE_STOP_ACTIVE; |
741 | qemu_set_irq(s->cs_lines[i], true); |
742 | } |
743 | |
744 | /* setup default segment register values for all */ |
745 | for (i = 0; i < s->ctrl->max_slaves; ++i) { |
746 | s->regs[R_SEG_ADDR0 + i] = |
747 | aspeed_smc_segment_to_reg(&s->ctrl->segments[i]); |
748 | } |
749 | |
750 | /* HW strapping flash type for FMC controllers */ |
751 | if (s->ctrl->segments == aspeed_segments_ast2500_fmc) { |
752 | /* flash type is fixed to SPI for CE0 and CE1 */ |
753 | s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0); |
754 | s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE1); |
755 | } |
756 | |
757 | /* HW strapping for AST2400 FMC controllers (SCU70). Let's use the |
758 | * configuration of the palmetto-bmc machine */ |
759 | if (s->ctrl->segments == aspeed_segments_fmc) { |
760 | s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0); |
761 | } |
762 | |
763 | s->snoop_index = SNOOP_OFF; |
764 | s->snoop_dummies = 0; |
765 | } |
766 | |
767 | static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size) |
768 | { |
769 | AspeedSMCState *s = ASPEED_SMC(opaque); |
770 | |
771 | addr >>= 2; |
772 | |
773 | if (addr == s->r_conf || |
774 | addr == s->r_timings || |
775 | addr == s->r_ce_ctrl || |
776 | addr == R_INTR_CTRL || |
777 | addr == R_DUMMY_DATA || |
778 | (addr >= R_SEG_ADDR0 && addr < R_SEG_ADDR0 + s->ctrl->max_slaves) || |
779 | (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->ctrl->max_slaves)) { |
780 | return s->regs[addr]; |
781 | } else { |
782 | qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n" , |
783 | __func__, addr); |
784 | return -1; |
785 | } |
786 | } |
787 | |
788 | static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data, |
789 | unsigned int size) |
790 | { |
791 | AspeedSMCState *s = ASPEED_SMC(opaque); |
792 | uint32_t value = data; |
793 | |
794 | addr >>= 2; |
795 | |
796 | if (addr == s->r_conf || |
797 | addr == s->r_timings || |
798 | addr == s->r_ce_ctrl) { |
799 | s->regs[addr] = value; |
800 | } else if (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->num_cs) { |
801 | int cs = addr - s->r_ctrl0; |
802 | s->regs[addr] = value; |
803 | aspeed_smc_flash_update_cs(&s->flashes[cs]); |
804 | } else if (addr >= R_SEG_ADDR0 && |
805 | addr < R_SEG_ADDR0 + s->ctrl->max_slaves) { |
806 | int cs = addr - R_SEG_ADDR0; |
807 | |
808 | if (value != s->regs[R_SEG_ADDR0 + cs]) { |
809 | aspeed_smc_flash_set_segment(s, cs, value); |
810 | } |
811 | } else if (addr == R_DUMMY_DATA) { |
812 | s->regs[addr] = value & 0xff; |
813 | } else { |
814 | qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n" , |
815 | __func__, addr); |
816 | return; |
817 | } |
818 | } |
819 | |
820 | static const MemoryRegionOps aspeed_smc_ops = { |
821 | .read = aspeed_smc_read, |
822 | .write = aspeed_smc_write, |
823 | .endianness = DEVICE_LITTLE_ENDIAN, |
824 | .valid.unaligned = true, |
825 | }; |
826 | |
827 | static void aspeed_smc_realize(DeviceState *dev, Error **errp) |
828 | { |
829 | SysBusDevice *sbd = SYS_BUS_DEVICE(dev); |
830 | AspeedSMCState *s = ASPEED_SMC(dev); |
831 | AspeedSMCClass *mc = ASPEED_SMC_GET_CLASS(s); |
832 | int i; |
833 | char name[32]; |
834 | hwaddr offset = 0; |
835 | |
836 | s->ctrl = mc->ctrl; |
837 | |
838 | /* keep a copy under AspeedSMCState to speed up accesses */ |
839 | s->r_conf = s->ctrl->r_conf; |
840 | s->r_ce_ctrl = s->ctrl->r_ce_ctrl; |
841 | s->r_ctrl0 = s->ctrl->r_ctrl0; |
842 | s->r_timings = s->ctrl->r_timings; |
843 | s->conf_enable_w0 = s->ctrl->conf_enable_w0; |
844 | |
845 | /* Enforce some real HW limits */ |
846 | if (s->num_cs > s->ctrl->max_slaves) { |
847 | qemu_log_mask(LOG_GUEST_ERROR, "%s: num_cs cannot exceed: %d\n" , |
848 | __func__, s->ctrl->max_slaves); |
849 | s->num_cs = s->ctrl->max_slaves; |
850 | } |
851 | |
852 | s->spi = ssi_create_bus(dev, "spi" ); |
853 | |
854 | /* Setup cs_lines for slaves */ |
855 | sysbus_init_irq(sbd, &s->irq); |
856 | s->cs_lines = g_new0(qemu_irq, s->num_cs); |
857 | ssi_auto_connect_slaves(dev, s->cs_lines, s->spi); |
858 | |
859 | for (i = 0; i < s->num_cs; ++i) { |
860 | sysbus_init_irq(sbd, &s->cs_lines[i]); |
861 | } |
862 | |
863 | /* The memory region for the controller registers */ |
864 | memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_smc_ops, s, |
865 | s->ctrl->name, s->ctrl->nregs * 4); |
866 | sysbus_init_mmio(sbd, &s->mmio); |
867 | |
868 | /* |
869 | * The container memory region representing the address space |
870 | * window in which the flash modules are mapped. The size and |
871 | * address depends on the SoC model and controller type. |
872 | */ |
873 | snprintf(name, sizeof(name), "%s.flash" , s->ctrl->name); |
874 | |
875 | memory_region_init_io(&s->mmio_flash, OBJECT(s), |
876 | &aspeed_smc_flash_default_ops, s, name, |
877 | s->ctrl->flash_window_size); |
878 | sysbus_init_mmio(sbd, &s->mmio_flash); |
879 | |
880 | s->flashes = g_new0(AspeedSMCFlash, s->ctrl->max_slaves); |
881 | |
882 | /* |
883 | * Let's create a sub memory region for each possible slave. All |
884 | * have a configurable memory segment in the overall flash mapping |
885 | * window of the controller but, there is not necessarily a flash |
886 | * module behind to handle the memory accesses. This depends on |
887 | * the board configuration. |
888 | */ |
889 | for (i = 0; i < s->ctrl->max_slaves; ++i) { |
890 | AspeedSMCFlash *fl = &s->flashes[i]; |
891 | |
892 | snprintf(name, sizeof(name), "%s.%d" , s->ctrl->name, i); |
893 | |
894 | fl->id = i; |
895 | fl->controller = s; |
896 | fl->size = s->ctrl->segments[i].size; |
897 | memory_region_init_io(&fl->mmio, OBJECT(s), &aspeed_smc_flash_ops, |
898 | fl, name, fl->size); |
899 | memory_region_add_subregion(&s->mmio_flash, offset, &fl->mmio); |
900 | offset += fl->size; |
901 | } |
902 | } |
903 | |
904 | static const VMStateDescription vmstate_aspeed_smc = { |
905 | .name = "aspeed.smc" , |
906 | .version_id = 2, |
907 | .minimum_version_id = 2, |
908 | .fields = (VMStateField[]) { |
909 | VMSTATE_UINT32_ARRAY(regs, AspeedSMCState, ASPEED_SMC_R_MAX), |
910 | VMSTATE_UINT8(snoop_index, AspeedSMCState), |
911 | VMSTATE_UINT8(snoop_dummies, AspeedSMCState), |
912 | VMSTATE_END_OF_LIST() |
913 | } |
914 | }; |
915 | |
916 | static Property aspeed_smc_properties[] = { |
917 | DEFINE_PROP_UINT32("num-cs" , AspeedSMCState, num_cs, 1), |
918 | DEFINE_PROP_UINT64("sdram-base" , AspeedSMCState, sdram_base, 0), |
919 | DEFINE_PROP_END_OF_LIST(), |
920 | }; |
921 | |
922 | static void aspeed_smc_class_init(ObjectClass *klass, void *data) |
923 | { |
924 | DeviceClass *dc = DEVICE_CLASS(klass); |
925 | AspeedSMCClass *mc = ASPEED_SMC_CLASS(klass); |
926 | |
927 | dc->realize = aspeed_smc_realize; |
928 | dc->reset = aspeed_smc_reset; |
929 | dc->props = aspeed_smc_properties; |
930 | dc->vmsd = &vmstate_aspeed_smc; |
931 | mc->ctrl = data; |
932 | } |
933 | |
934 | static const TypeInfo aspeed_smc_info = { |
935 | .name = TYPE_ASPEED_SMC, |
936 | .parent = TYPE_SYS_BUS_DEVICE, |
937 | .instance_size = sizeof(AspeedSMCState), |
938 | .class_size = sizeof(AspeedSMCClass), |
939 | .abstract = true, |
940 | }; |
941 | |
942 | static void aspeed_smc_register_types(void) |
943 | { |
944 | int i; |
945 | |
946 | type_register_static(&aspeed_smc_info); |
947 | for (i = 0; i < ARRAY_SIZE(controllers); ++i) { |
948 | TypeInfo ti = { |
949 | .name = controllers[i].name, |
950 | .parent = TYPE_ASPEED_SMC, |
951 | .class_init = aspeed_smc_class_init, |
952 | .class_data = (void *)&controllers[i], |
953 | }; |
954 | type_register(&ti); |
955 | } |
956 | } |
957 | |
958 | type_init(aspeed_smc_register_types) |
959 | |