allwinner-r40-dramc.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. /*
  2. * Allwinner R40 SDRAM Controller emulation
  3. *
  4. * CCopyright (C) 2023 qianfan Zhao <qianfanguijin@163.com>
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the 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,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "qemu/osdep.h"
  20. #include "qemu/units.h"
  21. #include "qemu/error-report.h"
  22. #include "hw/sysbus.h"
  23. #include "migration/vmstate.h"
  24. #include "qemu/log.h"
  25. #include "qemu/module.h"
  26. #include "exec/address-spaces.h"
  27. #include "hw/qdev-properties.h"
  28. #include "qapi/error.h"
  29. #include "qemu/bitops.h"
  30. #include "hw/misc/allwinner-r40-dramc.h"
  31. #include "trace.h"
  32. #define REG_INDEX(offset) (offset / sizeof(uint32_t))
  33. /* DRAMCOM register offsets */
  34. enum {
  35. REG_DRAMCOM_CR = 0x0000, /* Control Register */
  36. };
  37. /* DRAMCOMM register flags */
  38. enum {
  39. REG_DRAMCOM_CR_DUAL_RANK = (1 << 0),
  40. };
  41. /* DRAMCTL register offsets */
  42. enum {
  43. REG_DRAMCTL_PIR = 0x0000, /* PHY Initialization Register */
  44. REG_DRAMCTL_PGSR = 0x0010, /* PHY General Status Register */
  45. REG_DRAMCTL_STATR = 0x0018, /* Status Register */
  46. REG_DRAMCTL_PGCR = 0x0100, /* PHY general configuration registers */
  47. };
  48. /* DRAMCTL register flags */
  49. enum {
  50. REG_DRAMCTL_PGSR_INITDONE = (1 << 0),
  51. REG_DRAMCTL_PGSR_READ_TIMEOUT = (1 << 13),
  52. REG_DRAMCTL_PGCR_ENABLE_READ_TIMEOUT = (1 << 25),
  53. };
  54. enum {
  55. REG_DRAMCTL_STATR_ACTIVE = (1 << 0),
  56. };
  57. #define DRAM_MAX_ROW_BITS 16
  58. #define DRAM_MAX_COL_BITS 13 /* 8192 */
  59. #define DRAM_MAX_BANK 3
  60. static uint64_t dram_autodetect_cells[DRAM_MAX_ROW_BITS]
  61. [DRAM_MAX_BANK]
  62. [DRAM_MAX_COL_BITS];
  63. struct VirtualDDRChip {
  64. uint32_t ram_size;
  65. uint8_t bank_bits;
  66. uint8_t row_bits;
  67. uint8_t col_bits;
  68. };
  69. /*
  70. * Only power of 2 RAM sizes from 256MiB up to 2048MiB are supported,
  71. * 2GiB memory is not supported due to dual rank feature.
  72. */
  73. static const struct VirtualDDRChip dummy_ddr_chips[] = {
  74. {
  75. .ram_size = 256,
  76. .bank_bits = 3,
  77. .row_bits = 12,
  78. .col_bits = 13,
  79. }, {
  80. .ram_size = 512,
  81. .bank_bits = 3,
  82. .row_bits = 13,
  83. .col_bits = 13,
  84. }, {
  85. .ram_size = 1024,
  86. .bank_bits = 3,
  87. .row_bits = 14,
  88. .col_bits = 13,
  89. }, {
  90. 0
  91. }
  92. };
  93. static const struct VirtualDDRChip *get_match_ddr(uint32_t ram_size)
  94. {
  95. const struct VirtualDDRChip *ddr;
  96. for (ddr = &dummy_ddr_chips[0]; ddr->ram_size; ddr++) {
  97. if (ddr->ram_size == ram_size) {
  98. return ddr;
  99. }
  100. }
  101. return NULL;
  102. }
  103. static uint64_t *address_to_autodetect_cells(AwR40DramCtlState *s,
  104. const struct VirtualDDRChip *ddr,
  105. uint32_t offset)
  106. {
  107. int row_index = 0, bank_index = 0, col_index = 0;
  108. uint32_t row_addr, bank_addr, col_addr;
  109. row_addr = extract32(offset, s->set_col_bits + s->set_bank_bits,
  110. s->set_row_bits);
  111. bank_addr = extract32(offset, s->set_col_bits, s->set_bank_bits);
  112. col_addr = extract32(offset, 0, s->set_col_bits);
  113. for (int i = 0; i < ddr->row_bits; i++) {
  114. if (row_addr & BIT(i)) {
  115. row_index = i;
  116. }
  117. }
  118. for (int i = 0; i < ddr->bank_bits; i++) {
  119. if (bank_addr & BIT(i)) {
  120. bank_index = i;
  121. }
  122. }
  123. for (int i = 0; i < ddr->col_bits; i++) {
  124. if (col_addr & BIT(i)) {
  125. col_index = i;
  126. }
  127. }
  128. trace_allwinner_r40_dramc_offset_to_cell(offset, row_index, bank_index,
  129. col_index);
  130. return &dram_autodetect_cells[row_index][bank_index][col_index];
  131. }
  132. static void allwinner_r40_dramc_map_rows(AwR40DramCtlState *s, uint8_t row_bits,
  133. uint8_t bank_bits, uint8_t col_bits)
  134. {
  135. const struct VirtualDDRChip *ddr = get_match_ddr(s->ram_size);
  136. bool enable_detect_cells;
  137. trace_allwinner_r40_dramc_map_rows(row_bits, bank_bits, col_bits);
  138. if (!ddr) {
  139. return;
  140. }
  141. s->set_row_bits = row_bits;
  142. s->set_bank_bits = bank_bits;
  143. s->set_col_bits = col_bits;
  144. enable_detect_cells = ddr->bank_bits != bank_bits
  145. || ddr->row_bits != row_bits
  146. || ddr->col_bits != col_bits;
  147. if (enable_detect_cells) {
  148. trace_allwinner_r40_dramc_detect_cells_enable();
  149. } else {
  150. trace_allwinner_r40_dramc_detect_cells_disable();
  151. }
  152. memory_region_set_enabled(&s->detect_cells, enable_detect_cells);
  153. }
  154. static uint64_t allwinner_r40_dramcom_read(void *opaque, hwaddr offset,
  155. unsigned size)
  156. {
  157. const AwR40DramCtlState *s = AW_R40_DRAMC(opaque);
  158. const uint32_t idx = REG_INDEX(offset);
  159. if (idx >= AW_R40_DRAMCOM_REGS_NUM) {
  160. qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n",
  161. __func__, (uint32_t)offset);
  162. return 0;
  163. }
  164. trace_allwinner_r40_dramcom_read(offset, s->dramcom[idx], size);
  165. return s->dramcom[idx];
  166. }
  167. static void allwinner_r40_dramcom_write(void *opaque, hwaddr offset,
  168. uint64_t val, unsigned size)
  169. {
  170. AwR40DramCtlState *s = AW_R40_DRAMC(opaque);
  171. const uint32_t idx = REG_INDEX(offset);
  172. trace_allwinner_r40_dramcom_write(offset, val, size);
  173. if (idx >= AW_R40_DRAMCOM_REGS_NUM) {
  174. qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n",
  175. __func__, (uint32_t)offset);
  176. return;
  177. }
  178. switch (offset) {
  179. case REG_DRAMCOM_CR: /* Control Register */
  180. if (!(val & REG_DRAMCOM_CR_DUAL_RANK)) {
  181. allwinner_r40_dramc_map_rows(s, ((val >> 4) & 0xf) + 1,
  182. ((val >> 2) & 0x1) + 2,
  183. (((val >> 8) & 0xf) + 3));
  184. }
  185. break;
  186. };
  187. s->dramcom[idx] = (uint32_t) val;
  188. }
  189. static uint64_t allwinner_r40_dramctl_read(void *opaque, hwaddr offset,
  190. unsigned size)
  191. {
  192. const AwR40DramCtlState *s = AW_R40_DRAMC(opaque);
  193. const uint32_t idx = REG_INDEX(offset);
  194. if (idx >= AW_R40_DRAMCTL_REGS_NUM) {
  195. qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n",
  196. __func__, (uint32_t)offset);
  197. return 0;
  198. }
  199. trace_allwinner_r40_dramctl_read(offset, s->dramctl[idx], size);
  200. return s->dramctl[idx];
  201. }
  202. static void allwinner_r40_dramctl_write(void *opaque, hwaddr offset,
  203. uint64_t val, unsigned size)
  204. {
  205. AwR40DramCtlState *s = AW_R40_DRAMC(opaque);
  206. const uint32_t idx = REG_INDEX(offset);
  207. trace_allwinner_r40_dramctl_write(offset, val, size);
  208. if (idx >= AW_R40_DRAMCTL_REGS_NUM) {
  209. qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n",
  210. __func__, (uint32_t)offset);
  211. return;
  212. }
  213. switch (offset) {
  214. case REG_DRAMCTL_PIR: /* PHY Initialization Register */
  215. s->dramctl[REG_INDEX(REG_DRAMCTL_PGSR)] |= REG_DRAMCTL_PGSR_INITDONE;
  216. s->dramctl[REG_INDEX(REG_DRAMCTL_STATR)] |= REG_DRAMCTL_STATR_ACTIVE;
  217. break;
  218. }
  219. s->dramctl[idx] = (uint32_t) val;
  220. }
  221. static uint64_t allwinner_r40_dramphy_read(void *opaque, hwaddr offset,
  222. unsigned size)
  223. {
  224. const AwR40DramCtlState *s = AW_R40_DRAMC(opaque);
  225. const uint32_t idx = REG_INDEX(offset);
  226. if (idx >= AW_R40_DRAMPHY_REGS_NUM) {
  227. qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n",
  228. __func__, (uint32_t)offset);
  229. return 0;
  230. }
  231. trace_allwinner_r40_dramphy_read(offset, s->dramphy[idx], size);
  232. return s->dramphy[idx];
  233. }
  234. static void allwinner_r40_dramphy_write(void *opaque, hwaddr offset,
  235. uint64_t val, unsigned size)
  236. {
  237. AwR40DramCtlState *s = AW_R40_DRAMC(opaque);
  238. const uint32_t idx = REG_INDEX(offset);
  239. trace_allwinner_r40_dramphy_write(offset, val, size);
  240. if (idx >= AW_R40_DRAMPHY_REGS_NUM) {
  241. qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n",
  242. __func__, (uint32_t)offset);
  243. return;
  244. }
  245. s->dramphy[idx] = (uint32_t) val;
  246. }
  247. static const MemoryRegionOps allwinner_r40_dramcom_ops = {
  248. .read = allwinner_r40_dramcom_read,
  249. .write = allwinner_r40_dramcom_write,
  250. .endianness = DEVICE_LITTLE_ENDIAN,
  251. .valid = {
  252. .min_access_size = 4,
  253. .max_access_size = 4,
  254. },
  255. .impl.min_access_size = 4,
  256. };
  257. static const MemoryRegionOps allwinner_r40_dramctl_ops = {
  258. .read = allwinner_r40_dramctl_read,
  259. .write = allwinner_r40_dramctl_write,
  260. .endianness = DEVICE_LITTLE_ENDIAN,
  261. .valid = {
  262. .min_access_size = 4,
  263. .max_access_size = 4,
  264. },
  265. .impl.min_access_size = 4,
  266. };
  267. static const MemoryRegionOps allwinner_r40_dramphy_ops = {
  268. .read = allwinner_r40_dramphy_read,
  269. .write = allwinner_r40_dramphy_write,
  270. .endianness = DEVICE_LITTLE_ENDIAN,
  271. .valid = {
  272. .min_access_size = 4,
  273. .max_access_size = 4,
  274. },
  275. .impl.min_access_size = 4,
  276. };
  277. static uint64_t allwinner_r40_detect_read(void *opaque, hwaddr offset,
  278. unsigned size)
  279. {
  280. AwR40DramCtlState *s = AW_R40_DRAMC(opaque);
  281. const struct VirtualDDRChip *ddr = get_match_ddr(s->ram_size);
  282. uint64_t data = 0;
  283. if (ddr) {
  284. data = *address_to_autodetect_cells(s, ddr, (uint32_t)offset);
  285. }
  286. trace_allwinner_r40_dramc_detect_cell_read(offset, data);
  287. return data;
  288. }
  289. static void allwinner_r40_detect_write(void *opaque, hwaddr offset,
  290. uint64_t data, unsigned size)
  291. {
  292. AwR40DramCtlState *s = AW_R40_DRAMC(opaque);
  293. const struct VirtualDDRChip *ddr = get_match_ddr(s->ram_size);
  294. if (ddr) {
  295. uint64_t *cell = address_to_autodetect_cells(s, ddr, (uint32_t)offset);
  296. trace_allwinner_r40_dramc_detect_cell_write(offset, data);
  297. *cell = data;
  298. }
  299. }
  300. static const MemoryRegionOps allwinner_r40_detect_ops = {
  301. .read = allwinner_r40_detect_read,
  302. .write = allwinner_r40_detect_write,
  303. .endianness = DEVICE_LITTLE_ENDIAN,
  304. .valid = {
  305. .min_access_size = 4,
  306. .max_access_size = 4,
  307. },
  308. .impl.min_access_size = 4,
  309. };
  310. /*
  311. * mctl_r40_detect_rank_count in u-boot will write the high 1G of DDR
  312. * to detect whether the board support dual_rank or not. Create a virtual memory
  313. * if the board's ram_size less or equal than 1G, and set read time out flag of
  314. * REG_DRAMCTL_PGSR when the user touch this high dram.
  315. */
  316. static uint64_t allwinner_r40_dualrank_detect_read(void *opaque, hwaddr offset,
  317. unsigned size)
  318. {
  319. AwR40DramCtlState *s = AW_R40_DRAMC(opaque);
  320. uint32_t reg;
  321. reg = s->dramctl[REG_INDEX(REG_DRAMCTL_PGCR)];
  322. if (reg & REG_DRAMCTL_PGCR_ENABLE_READ_TIMEOUT) { /* Enable read time out */
  323. /*
  324. * this driver only support one rank, mark READ_TIMEOUT when try
  325. * read the second rank.
  326. */
  327. s->dramctl[REG_INDEX(REG_DRAMCTL_PGSR)]
  328. |= REG_DRAMCTL_PGSR_READ_TIMEOUT;
  329. }
  330. return 0;
  331. }
  332. static const MemoryRegionOps allwinner_r40_dualrank_detect_ops = {
  333. .read = allwinner_r40_dualrank_detect_read,
  334. .endianness = DEVICE_LITTLE_ENDIAN,
  335. .valid = {
  336. .min_access_size = 4,
  337. .max_access_size = 4,
  338. },
  339. .impl.min_access_size = 4,
  340. };
  341. static void allwinner_r40_dramc_reset(DeviceState *dev)
  342. {
  343. AwR40DramCtlState *s = AW_R40_DRAMC(dev);
  344. /* Set default values for registers */
  345. memset(&s->dramcom, 0, sizeof(s->dramcom));
  346. memset(&s->dramctl, 0, sizeof(s->dramctl));
  347. memset(&s->dramphy, 0, sizeof(s->dramphy));
  348. }
  349. static void allwinner_r40_dramc_realize(DeviceState *dev, Error **errp)
  350. {
  351. AwR40DramCtlState *s = AW_R40_DRAMC(dev);
  352. if (!get_match_ddr(s->ram_size)) {
  353. error_report("%s: ram-size %u MiB is not supported",
  354. __func__, s->ram_size);
  355. exit(1);
  356. }
  357. /* R40 support max 2G memory but we only support up to 1G now. */
  358. memory_region_init_io(&s->detect_cells, OBJECT(s),
  359. &allwinner_r40_detect_ops, s,
  360. "DRAMCELLS", 1 * GiB);
  361. memory_region_add_subregion_overlap(get_system_memory(), s->ram_addr,
  362. &s->detect_cells, 10);
  363. memory_region_set_enabled(&s->detect_cells, false);
  364. /*
  365. * We only support DRAM size up to 1G now, so prepare a high memory page
  366. * after 1G for dualrank detect.
  367. */
  368. memory_region_init_io(&s->dram_high, OBJECT(s),
  369. &allwinner_r40_dualrank_detect_ops, s,
  370. "DRAMHIGH", KiB);
  371. memory_region_add_subregion(get_system_memory(), s->ram_addr + GiB,
  372. &s->dram_high);
  373. }
  374. static void allwinner_r40_dramc_init(Object *obj)
  375. {
  376. SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
  377. AwR40DramCtlState *s = AW_R40_DRAMC(obj);
  378. /* DRAMCOM registers, index 0 */
  379. memory_region_init_io(&s->dramcom_iomem, OBJECT(s),
  380. &allwinner_r40_dramcom_ops, s,
  381. "DRAMCOM", 4 * KiB);
  382. sysbus_init_mmio(sbd, &s->dramcom_iomem);
  383. /* DRAMCTL registers, index 1 */
  384. memory_region_init_io(&s->dramctl_iomem, OBJECT(s),
  385. &allwinner_r40_dramctl_ops, s,
  386. "DRAMCTL", 4 * KiB);
  387. sysbus_init_mmio(sbd, &s->dramctl_iomem);
  388. /* DRAMPHY registers. index 2 */
  389. memory_region_init_io(&s->dramphy_iomem, OBJECT(s),
  390. &allwinner_r40_dramphy_ops, s,
  391. "DRAMPHY", 4 * KiB);
  392. sysbus_init_mmio(sbd, &s->dramphy_iomem);
  393. }
  394. static const Property allwinner_r40_dramc_properties[] = {
  395. DEFINE_PROP_UINT64("ram-addr", AwR40DramCtlState, ram_addr, 0x0),
  396. DEFINE_PROP_UINT32("ram-size", AwR40DramCtlState, ram_size, 256), /* MiB */
  397. };
  398. static const VMStateDescription allwinner_r40_dramc_vmstate = {
  399. .name = "allwinner-r40-dramc",
  400. .version_id = 1,
  401. .minimum_version_id = 1,
  402. .fields = (const VMStateField[]) {
  403. VMSTATE_UINT32_ARRAY(dramcom, AwR40DramCtlState,
  404. AW_R40_DRAMCOM_REGS_NUM),
  405. VMSTATE_UINT32_ARRAY(dramctl, AwR40DramCtlState,
  406. AW_R40_DRAMCTL_REGS_NUM),
  407. VMSTATE_UINT32_ARRAY(dramphy, AwR40DramCtlState,
  408. AW_R40_DRAMPHY_REGS_NUM),
  409. VMSTATE_END_OF_LIST()
  410. }
  411. };
  412. static void allwinner_r40_dramc_class_init(ObjectClass *klass, void *data)
  413. {
  414. DeviceClass *dc = DEVICE_CLASS(klass);
  415. device_class_set_legacy_reset(dc, allwinner_r40_dramc_reset);
  416. dc->vmsd = &allwinner_r40_dramc_vmstate;
  417. dc->realize = allwinner_r40_dramc_realize;
  418. device_class_set_props(dc, allwinner_r40_dramc_properties);
  419. }
  420. static const TypeInfo allwinner_r40_dramc_info = {
  421. .name = TYPE_AW_R40_DRAMC,
  422. .parent = TYPE_SYS_BUS_DEVICE,
  423. .instance_init = allwinner_r40_dramc_init,
  424. .instance_size = sizeof(AwR40DramCtlState),
  425. .class_init = allwinner_r40_dramc_class_init,
  426. };
  427. static void allwinner_r40_dramc_register(void)
  428. {
  429. type_register_static(&allwinner_r40_dramc_info);
  430. }
  431. type_init(allwinner_r40_dramc_register)