allwinner-a10-spi.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. /*
  2. * Allwinner SPI Bus Serial Interface Emulation
  3. *
  4. * Copyright (C) 2024 Strahinja Jankovic <strahinja.p.jankovic@gmail.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful, but WITHOUT
  12. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  14. * for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program; if not, see <http://www.gnu.org/licenses/>.
  18. *
  19. * SPDX-License-Identifier: GPL-2.0-or-later
  20. */
  21. #include "qemu/osdep.h"
  22. #include "hw/irq.h"
  23. #include "hw/ssi/allwinner-a10-spi.h"
  24. #include "migration/vmstate.h"
  25. #include "qemu/log.h"
  26. #include "qemu/module.h"
  27. #include "trace.h"
  28. /* Allwinner SPI memory map */
  29. #define SPI_RXDATA_REG 0x00 /* receive data register */
  30. #define SPI_TXDATA_REG 0x04 /* transmit data register */
  31. #define SPI_CTL_REG 0x08 /* control register */
  32. #define SPI_INTCTL_REG 0x0c /* interrupt control register */
  33. #define SPI_INT_STA_REG 0x10 /* interrupt status register */
  34. #define SPI_DMACTL_REG 0x14 /* DMA control register */
  35. #define SPI_WAIT_REG 0x18 /* wait clock counter register */
  36. #define SPI_CCTL_REG 0x1c /* clock rate control register */
  37. #define SPI_BC_REG 0x20 /* burst control register */
  38. #define SPI_TC_REG 0x24 /* transmit counter register */
  39. #define SPI_FIFO_STA_REG 0x28 /* FIFO status register */
  40. /* Data register */
  41. #define SPI_DATA_RESET 0
  42. /* Control register */
  43. #define SPI_CTL_SDC (1 << 19)
  44. #define SPI_CTL_TP_EN (1 << 18)
  45. #define SPI_CTL_SS_LEVEL (1 << 17)
  46. #define SPI_CTL_SS_CTRL (1 << 16)
  47. #define SPI_CTL_DHB (1 << 15)
  48. #define SPI_CTL_DDB (1 << 14)
  49. #define SPI_CTL_SS (3 << 12)
  50. #define SPI_CTL_SS_SHIFT 12
  51. #define SPI_CTL_RPSM (1 << 11)
  52. #define SPI_CTL_XCH (1 << 10)
  53. #define SPI_CTL_RF_RST (1 << 9)
  54. #define SPI_CTL_TF_RST (1 << 8)
  55. #define SPI_CTL_SSCTL (1 << 7)
  56. #define SPI_CTL_LMTF (1 << 6)
  57. #define SPI_CTL_DMAMC (1 << 5)
  58. #define SPI_CTL_SSPOL (1 << 4)
  59. #define SPI_CTL_POL (1 << 3)
  60. #define SPI_CTL_PHA (1 << 2)
  61. #define SPI_CTL_MODE (1 << 1)
  62. #define SPI_CTL_EN (1 << 0)
  63. #define SPI_CTL_MASK 0xFFFFFu
  64. #define SPI_CTL_RESET 0x0002001Cu
  65. /* Interrupt control register */
  66. #define SPI_INTCTL_SS_INT_EN (1 << 17)
  67. #define SPI_INTCTL_TX_INT_EN (1 << 16)
  68. #define SPI_INTCTL_TF_UR_INT_EN (1 << 14)
  69. #define SPI_INTCTL_TF_OF_INT_EN (1 << 13)
  70. #define SPI_INTCTL_TF_E34_INT_EN (1 << 12)
  71. #define SPI_INTCTL_TF_E14_INT_EN (1 << 11)
  72. #define SPI_INTCTL_TF_FL_INT_EN (1 << 10)
  73. #define SPI_INTCTL_TF_HALF_EMP_INT_EN (1 << 9)
  74. #define SPI_INTCTL_TF_EMP_INT_EN (1 << 8)
  75. #define SPI_INTCTL_RF_UR_INT_EN (1 << 6)
  76. #define SPI_INTCTL_RF_OF_INT_EN (1 << 5)
  77. #define SPI_INTCTL_RF_E34_INT_EN (1 << 4)
  78. #define SPI_INTCTL_RF_E14_INT_EN (1 << 3)
  79. #define SPI_INTCTL_RF_FU_INT_EN (1 << 2)
  80. #define SPI_INTCTL_RF_HALF_FU_INT_EN (1 << 1)
  81. #define SPI_INTCTL_RF_RDY_INT_EN (1 << 0)
  82. #define SPI_INTCTL_MASK 0x37F7Fu
  83. #define SPI_INTCTL_RESET 0
  84. /* Interrupt status register */
  85. #define SPI_INT_STA_INT_CBF (1 << 31)
  86. #define SPI_INT_STA_SSI (1 << 17)
  87. #define SPI_INT_STA_TC (1 << 16)
  88. #define SPI_INT_STA_TU (1 << 14)
  89. #define SPI_INT_STA_TO (1 << 13)
  90. #define SPI_INT_STA_TE34 (1 << 12)
  91. #define SPI_INT_STA_TE14 (1 << 11)
  92. #define SPI_INT_STA_TF (1 << 10)
  93. #define SPI_INT_STA_THE (1 << 9)
  94. #define SPI_INT_STA_TE (1 << 8)
  95. #define SPI_INT_STA_RU (1 << 6)
  96. #define SPI_INT_STA_RO (1 << 5)
  97. #define SPI_INT_STA_RF34 (1 << 4)
  98. #define SPI_INT_STA_RF14 (1 << 3)
  99. #define SPI_INT_STA_RF (1 << 2)
  100. #define SPI_INT_STA_RHF (1 << 1)
  101. #define SPI_INT_STA_RR (1 << 0)
  102. #define SPI_INT_STA_MASK 0x80037F7Fu
  103. #define SPI_INT_STA_RESET 0x00001B00u
  104. /* DMA control register - not implemented */
  105. #define SPI_DMACTL_RESET 0
  106. /* Wait clock register */
  107. #define SPI_WAIT_REG_WCC_MASK 0xFFFFu
  108. #define SPI_WAIT_RESET 0
  109. /* Clock control register - not implemented */
  110. #define SPI_CCTL_RESET 2
  111. /* Burst count register */
  112. #define SPI_BC_BC_MASK 0xFFFFFFu
  113. #define SPI_BC_RESET 0
  114. /* Transmi counter register */
  115. #define SPI_TC_WTC_MASK 0xFFFFFFu
  116. #define SPI_TC_RESET 0
  117. /* FIFO status register */
  118. #define SPI_FIFO_STA_CNT_MASK 0x7F
  119. #define SPI_FIFO_STA_TF_CNT_SHIFT 16
  120. #define SPI_FIFO_STA_RF_CNT_SHIFT 0
  121. #define SPI_FIFO_STA_RESET 0
  122. #define REG_INDEX(offset) (offset / sizeof(uint32_t))
  123. static const char *allwinner_a10_spi_get_regname(unsigned offset)
  124. {
  125. switch (offset) {
  126. case SPI_RXDATA_REG:
  127. return "RXDATA";
  128. case SPI_TXDATA_REG:
  129. return "TXDATA";
  130. case SPI_CTL_REG:
  131. return "CTL";
  132. case SPI_INTCTL_REG:
  133. return "INTCTL";
  134. case SPI_INT_STA_REG:
  135. return "INT_STA";
  136. case SPI_DMACTL_REG:
  137. return "DMACTL";
  138. case SPI_WAIT_REG:
  139. return "WAIT";
  140. case SPI_CCTL_REG:
  141. return "CCTL";
  142. case SPI_BC_REG:
  143. return "BC";
  144. case SPI_TC_REG:
  145. return "TC";
  146. case SPI_FIFO_STA_REG:
  147. return "FIFO_STA";
  148. default:
  149. return "[?]";
  150. }
  151. }
  152. static bool allwinner_a10_spi_is_enabled(AWA10SPIState *s)
  153. {
  154. return s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_EN;
  155. }
  156. static void allwinner_a10_spi_txfifo_reset(AWA10SPIState *s)
  157. {
  158. fifo8_reset(&s->tx_fifo);
  159. s->regs[REG_INDEX(SPI_INT_STA_REG)] |= (SPI_INT_STA_TE | SPI_INT_STA_TE14 |
  160. SPI_INT_STA_THE | SPI_INT_STA_TE34);
  161. s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~(SPI_INT_STA_TU | SPI_INT_STA_TO);
  162. }
  163. static void allwinner_a10_spi_rxfifo_reset(AWA10SPIState *s)
  164. {
  165. fifo8_reset(&s->rx_fifo);
  166. s->regs[REG_INDEX(SPI_INT_STA_REG)] &=
  167. ~(SPI_INT_STA_RU | SPI_INT_STA_RO | SPI_INT_STA_RF | SPI_INT_STA_RR |
  168. SPI_INT_STA_RHF | SPI_INT_STA_RF14 | SPI_INT_STA_RF34);
  169. }
  170. static uint8_t allwinner_a10_spi_selected_channel(AWA10SPIState *s)
  171. {
  172. return (s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_SS) >> SPI_CTL_SS_SHIFT;
  173. }
  174. static void allwinner_a10_spi_reset_hold(Object *obj, ResetType type)
  175. {
  176. AWA10SPIState *s = AW_A10_SPI(obj);
  177. s->regs[REG_INDEX(SPI_RXDATA_REG)] = SPI_DATA_RESET;
  178. s->regs[REG_INDEX(SPI_TXDATA_REG)] = SPI_DATA_RESET;
  179. s->regs[REG_INDEX(SPI_CTL_REG)] = SPI_CTL_RESET;
  180. s->regs[REG_INDEX(SPI_INTCTL_REG)] = SPI_INTCTL_RESET;
  181. s->regs[REG_INDEX(SPI_INT_STA_REG)] = SPI_INT_STA_RESET;
  182. s->regs[REG_INDEX(SPI_DMACTL_REG)] = SPI_DMACTL_RESET;
  183. s->regs[REG_INDEX(SPI_WAIT_REG)] = SPI_WAIT_RESET;
  184. s->regs[REG_INDEX(SPI_CCTL_REG)] = SPI_CCTL_RESET;
  185. s->regs[REG_INDEX(SPI_BC_REG)] = SPI_BC_RESET;
  186. s->regs[REG_INDEX(SPI_TC_REG)] = SPI_TC_RESET;
  187. s->regs[REG_INDEX(SPI_FIFO_STA_REG)] = SPI_FIFO_STA_RESET;
  188. allwinner_a10_spi_txfifo_reset(s);
  189. allwinner_a10_spi_rxfifo_reset(s);
  190. }
  191. static void allwinner_a10_spi_update_irq(AWA10SPIState *s)
  192. {
  193. bool level;
  194. if (fifo8_is_empty(&s->rx_fifo)) {
  195. s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_RR;
  196. } else {
  197. s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_RR;
  198. }
  199. if (fifo8_num_used(&s->rx_fifo) >= (AW_A10_SPI_FIFO_SIZE >> 2)) {
  200. s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_RF14;
  201. } else {
  202. s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_RF14;
  203. }
  204. if (fifo8_num_used(&s->rx_fifo) >= (AW_A10_SPI_FIFO_SIZE >> 1)) {
  205. s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_RHF;
  206. } else {
  207. s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_RHF;
  208. }
  209. if (fifo8_num_free(&s->rx_fifo) <= (AW_A10_SPI_FIFO_SIZE >> 2)) {
  210. s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_RF34;
  211. } else {
  212. s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_RF34;
  213. }
  214. if (fifo8_is_full(&s->rx_fifo)) {
  215. s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_RF;
  216. } else {
  217. s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_RF;
  218. }
  219. if (fifo8_is_empty(&s->tx_fifo)) {
  220. s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_TE;
  221. } else {
  222. s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_TE;
  223. }
  224. if (fifo8_num_free(&s->tx_fifo) >= (AW_A10_SPI_FIFO_SIZE >> 2)) {
  225. s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_TE14;
  226. } else {
  227. s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_TE14;
  228. }
  229. if (fifo8_num_free(&s->tx_fifo) >= (AW_A10_SPI_FIFO_SIZE >> 1)) {
  230. s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_THE;
  231. } else {
  232. s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_THE;
  233. }
  234. if (fifo8_num_used(&s->tx_fifo) <= (AW_A10_SPI_FIFO_SIZE >> 2)) {
  235. s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_TE34;
  236. } else {
  237. s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_TE34;
  238. }
  239. if (fifo8_is_full(&s->rx_fifo)) {
  240. s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_TF;
  241. } else {
  242. s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~SPI_INT_STA_TF;
  243. }
  244. level = (s->regs[REG_INDEX(SPI_INT_STA_REG)] &
  245. s->regs[REG_INDEX(SPI_INTCTL_REG)]) != 0;
  246. qemu_set_irq(s->irq, level);
  247. trace_allwinner_a10_spi_update_irq(level);
  248. }
  249. static void allwinner_a10_spi_flush_txfifo(AWA10SPIState *s)
  250. {
  251. uint32_t burst_count = s->regs[REG_INDEX(SPI_BC_REG)];
  252. uint32_t tx_burst = s->regs[REG_INDEX(SPI_TC_REG)];
  253. trace_allwinner_a10_spi_burst_length(tx_burst);
  254. trace_allwinner_a10_spi_flush_txfifo_begin(fifo8_num_used(&s->tx_fifo),
  255. fifo8_num_used(&s->rx_fifo));
  256. while (!fifo8_is_empty(&s->tx_fifo)) {
  257. uint8_t tx = fifo8_pop(&s->tx_fifo);
  258. uint8_t rx = 0;
  259. bool fill_rx = true;
  260. trace_allwinner_a10_spi_tx(tx);
  261. /* Write one byte at a time */
  262. rx = ssi_transfer(s->bus, tx);
  263. trace_allwinner_a10_spi_rx(rx);
  264. /* Check DHB here to determine if RX bytes should be stored */
  265. if (s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_DHB) {
  266. /* Store rx bytes only after WTC transfers */
  267. if (tx_burst > 0u) {
  268. fill_rx = false;
  269. tx_burst--;
  270. }
  271. }
  272. if (fill_rx) {
  273. if (fifo8_is_full(&s->rx_fifo)) {
  274. s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_RF;
  275. } else {
  276. fifo8_push(&s->rx_fifo, rx);
  277. }
  278. }
  279. allwinner_a10_spi_update_irq(s);
  280. burst_count--;
  281. if (burst_count == 0) {
  282. s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_TC;
  283. s->regs[REG_INDEX(SPI_CTL_REG)] &= ~SPI_CTL_XCH;
  284. break;
  285. }
  286. }
  287. if (fifo8_is_empty(&s->tx_fifo)) {
  288. s->regs[REG_INDEX(SPI_INT_STA_REG)] |= SPI_INT_STA_TC;
  289. s->regs[REG_INDEX(SPI_CTL_REG)] &= ~SPI_CTL_XCH;
  290. }
  291. trace_allwinner_a10_spi_flush_txfifo_end(fifo8_num_used(&s->tx_fifo),
  292. fifo8_num_used(&s->rx_fifo));
  293. }
  294. static uint64_t allwinner_a10_spi_read(void *opaque, hwaddr offset,
  295. unsigned size)
  296. {
  297. uint32_t value = 0;
  298. AWA10SPIState *s = opaque;
  299. uint32_t index = offset >> 2;
  300. if (offset > SPI_FIFO_STA_REG) {
  301. qemu_log_mask(LOG_GUEST_ERROR,
  302. "[%s]%s: Bad register at offset 0x%" HWADDR_PRIx "\n",
  303. TYPE_AW_A10_SPI, __func__, offset);
  304. return 0;
  305. }
  306. value = s->regs[index];
  307. if (allwinner_a10_spi_is_enabled(s)) {
  308. switch (offset) {
  309. case SPI_RXDATA_REG:
  310. if (fifo8_is_empty(&s->rx_fifo)) {
  311. /* value is undefined */
  312. value = 0xdeadbeef;
  313. } else {
  314. /* read from the RX FIFO */
  315. value = fifo8_pop(&s->rx_fifo);
  316. }
  317. break;
  318. case SPI_TXDATA_REG:
  319. qemu_log_mask(LOG_GUEST_ERROR,
  320. "[%s]%s: Trying to read from TX FIFO\n",
  321. TYPE_AW_A10_SPI, __func__);
  322. /* Reading from TXDATA gives 0 */
  323. break;
  324. case SPI_FIFO_STA_REG:
  325. /* Read current tx/rx fifo data count */
  326. value = fifo8_num_used(&s->tx_fifo) << SPI_FIFO_STA_TF_CNT_SHIFT |
  327. fifo8_num_used(&s->rx_fifo) << SPI_FIFO_STA_RF_CNT_SHIFT;
  328. break;
  329. case SPI_CTL_REG:
  330. case SPI_INTCTL_REG:
  331. case SPI_INT_STA_REG:
  332. case SPI_DMACTL_REG:
  333. case SPI_WAIT_REG:
  334. case SPI_CCTL_REG:
  335. case SPI_BC_REG:
  336. case SPI_TC_REG:
  337. break;
  338. default:
  339. qemu_log_mask(LOG_GUEST_ERROR,
  340. "%s: bad offset 0x%x\n", __func__,
  341. (uint32_t)offset);
  342. break;
  343. }
  344. allwinner_a10_spi_update_irq(s);
  345. }
  346. trace_allwinner_a10_spi_read(allwinner_a10_spi_get_regname(offset), value);
  347. return value;
  348. }
  349. static bool allwinner_a10_spi_update_cs_level(AWA10SPIState *s, int cs_line_nr)
  350. {
  351. if (cs_line_nr == allwinner_a10_spi_selected_channel(s)) {
  352. return (s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_SS_LEVEL) != 0;
  353. } else {
  354. return (s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_SSPOL) != 0;
  355. }
  356. }
  357. static void allwinner_a10_spi_write(void *opaque, hwaddr offset, uint64_t value,
  358. unsigned size)
  359. {
  360. AWA10SPIState *s = opaque;
  361. uint32_t index = offset >> 2;
  362. int i = 0;
  363. if (offset > SPI_FIFO_STA_REG) {
  364. qemu_log_mask(LOG_GUEST_ERROR,
  365. "[%s]%s: Bad register at offset 0x%" HWADDR_PRIx "\n",
  366. TYPE_AW_A10_SPI, __func__, offset);
  367. return;
  368. }
  369. trace_allwinner_a10_spi_write(allwinner_a10_spi_get_regname(offset),
  370. (uint32_t)value);
  371. if (!allwinner_a10_spi_is_enabled(s)) {
  372. /* Block is disabled */
  373. if (offset != SPI_CTL_REG) {
  374. /* Ignore access */
  375. return;
  376. }
  377. }
  378. switch (offset) {
  379. case SPI_RXDATA_REG:
  380. qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Trying to write to RX FIFO\n",
  381. TYPE_AW_A10_SPI, __func__);
  382. break;
  383. case SPI_TXDATA_REG:
  384. if (fifo8_is_full(&s->tx_fifo)) {
  385. /* Ignore writes if queue is full */
  386. break;
  387. }
  388. fifo8_push(&s->tx_fifo, (uint8_t)value);
  389. break;
  390. case SPI_INT_STA_REG:
  391. /* Handle W1C bits - everything except SPI_INT_STA_INT_CBF. */
  392. value &= ~SPI_INT_STA_INT_CBF;
  393. s->regs[REG_INDEX(SPI_INT_STA_REG)] &= ~(value & SPI_INT_STA_MASK);
  394. break;
  395. case SPI_CTL_REG:
  396. s->regs[REG_INDEX(SPI_CTL_REG)] = value;
  397. for (i = 0; i < AW_A10_SPI_CS_LINES_NR; i++) {
  398. qemu_set_irq(
  399. s->cs_lines[i],
  400. allwinner_a10_spi_update_cs_level(s, i));
  401. }
  402. if (s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_XCH) {
  403. /* Request to start emitting */
  404. allwinner_a10_spi_flush_txfifo(s);
  405. }
  406. if (s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_TF_RST) {
  407. allwinner_a10_spi_txfifo_reset(s);
  408. s->regs[REG_INDEX(SPI_CTL_REG)] &= ~SPI_CTL_TF_RST;
  409. }
  410. if (s->regs[REG_INDEX(SPI_CTL_REG)] & SPI_CTL_RF_RST) {
  411. allwinner_a10_spi_rxfifo_reset(s);
  412. s->regs[REG_INDEX(SPI_CTL_REG)] &= ~SPI_CTL_RF_RST;
  413. }
  414. break;
  415. case SPI_INTCTL_REG:
  416. case SPI_DMACTL_REG:
  417. case SPI_WAIT_REG:
  418. case SPI_CCTL_REG:
  419. case SPI_BC_REG:
  420. case SPI_TC_REG:
  421. case SPI_FIFO_STA_REG:
  422. s->regs[index] = value;
  423. break;
  424. default:
  425. qemu_log_mask(LOG_GUEST_ERROR,
  426. "%s: bad offset 0x%x\n", __func__,
  427. (uint32_t)offset);
  428. break;
  429. }
  430. allwinner_a10_spi_update_irq(s);
  431. }
  432. static const MemoryRegionOps allwinner_a10_spi_ops = {
  433. .read = allwinner_a10_spi_read,
  434. .write = allwinner_a10_spi_write,
  435. .valid.min_access_size = 1,
  436. .valid.max_access_size = 4,
  437. .endianness = DEVICE_LITTLE_ENDIAN,
  438. };
  439. static const VMStateDescription allwinner_a10_spi_vmstate = {
  440. .name = TYPE_AW_A10_SPI,
  441. .version_id = 1,
  442. .minimum_version_id = 1,
  443. .fields = (const VMStateField[]) {
  444. VMSTATE_FIFO8(tx_fifo, AWA10SPIState),
  445. VMSTATE_FIFO8(rx_fifo, AWA10SPIState),
  446. VMSTATE_UINT32_ARRAY(regs, AWA10SPIState, AW_A10_SPI_REGS_NUM),
  447. VMSTATE_END_OF_LIST()
  448. }
  449. };
  450. static void allwinner_a10_spi_realize(DeviceState *dev, Error **errp)
  451. {
  452. AWA10SPIState *s = AW_A10_SPI(dev);
  453. int i = 0;
  454. memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_a10_spi_ops, s,
  455. TYPE_AW_A10_SPI, AW_A10_SPI_IOSIZE);
  456. sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
  457. sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
  458. s->bus = ssi_create_bus(dev, "spi");
  459. for (i = 0; i < AW_A10_SPI_CS_LINES_NR; i++) {
  460. sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->cs_lines[i]);
  461. }
  462. fifo8_create(&s->tx_fifo, AW_A10_SPI_FIFO_SIZE);
  463. fifo8_create(&s->rx_fifo, AW_A10_SPI_FIFO_SIZE);
  464. }
  465. static void allwinner_a10_spi_class_init(ObjectClass *klass, void *data)
  466. {
  467. DeviceClass *dc = DEVICE_CLASS(klass);
  468. ResettableClass *rc = RESETTABLE_CLASS(klass);
  469. rc->phases.hold = allwinner_a10_spi_reset_hold;
  470. dc->vmsd = &allwinner_a10_spi_vmstate;
  471. dc->realize = allwinner_a10_spi_realize;
  472. dc->desc = "Allwinner A10 SPI Controller";
  473. }
  474. static const TypeInfo allwinner_a10_spi_type_info = {
  475. .name = TYPE_AW_A10_SPI,
  476. .parent = TYPE_SYS_BUS_DEVICE,
  477. .instance_size = sizeof(AWA10SPIState),
  478. .class_init = allwinner_a10_spi_class_init,
  479. };
  480. static void allwinner_a10_spi_register_types(void)
  481. {
  482. type_register_static(&allwinner_a10_spi_type_info);
  483. }
  484. type_init(allwinner_a10_spi_register_types)