sii3112.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /*
  2. * QEMU SiI3112A PCI to Serial ATA Controller Emulation
  3. *
  4. * Copyright (C) 2017 BALATON Zoltan <balaton@eik.bme.hu>
  5. *
  6. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  7. * See the COPYING file in the top-level directory.
  8. *
  9. */
  10. /* For documentation on this and similar cards see:
  11. * http://wiki.osdev.org/User:Quok/Silicon_Image_Datasheets
  12. */
  13. #include "qemu/osdep.h"
  14. #include "hw/ide/pci.h"
  15. #include "qemu/module.h"
  16. #include "trace.h"
  17. #include "qom/object.h"
  18. #include "ide-internal.h"
  19. #define TYPE_SII3112_PCI "sii3112"
  20. OBJECT_DECLARE_SIMPLE_TYPE(SiI3112PCIState, SII3112_PCI)
  21. typedef struct SiI3112Regs {
  22. uint32_t confstat;
  23. uint32_t scontrol;
  24. uint16_t sien;
  25. uint8_t swdata;
  26. } SiI3112Regs;
  27. struct SiI3112PCIState {
  28. PCIIDEState i;
  29. MemoryRegion mmio;
  30. SiI3112Regs regs[2];
  31. };
  32. /* The sii3112_reg_read and sii3112_reg_write functions implement the
  33. * Internal Register Space - BAR5 (section 6.7 of the data sheet).
  34. */
  35. static uint64_t sii3112_reg_read(void *opaque, hwaddr addr,
  36. unsigned int size)
  37. {
  38. SiI3112PCIState *d = opaque;
  39. uint64_t val;
  40. switch (addr) {
  41. case 0x00:
  42. val = d->i.bmdma[0].cmd;
  43. break;
  44. case 0x01:
  45. val = d->regs[0].swdata;
  46. break;
  47. case 0x02:
  48. val = d->i.bmdma[0].status;
  49. break;
  50. case 0x03:
  51. val = 0;
  52. break;
  53. case 0x04 ... 0x07:
  54. val = bmdma_addr_ioport_ops.read(&d->i.bmdma[0], addr - 4, size);
  55. break;
  56. case 0x08:
  57. val = d->i.bmdma[1].cmd;
  58. break;
  59. case 0x09:
  60. val = d->regs[1].swdata;
  61. break;
  62. case 0x0a:
  63. val = d->i.bmdma[1].status;
  64. break;
  65. case 0x0b:
  66. val = 0;
  67. break;
  68. case 0x0c ... 0x0f:
  69. val = bmdma_addr_ioport_ops.read(&d->i.bmdma[1], addr - 12, size);
  70. break;
  71. case 0x10:
  72. val = d->i.bmdma[0].cmd;
  73. val |= (d->regs[0].confstat & (1UL << 11) ? (1 << 4) : 0); /*SATAINT0*/
  74. val |= (d->regs[1].confstat & (1UL << 11) ? (1 << 6) : 0); /*SATAINT1*/
  75. val |= (d->i.bmdma[1].status & BM_STATUS_INT ? (1 << 14) : 0);
  76. val |= (uint32_t)d->i.bmdma[0].status << 16;
  77. val |= (uint32_t)d->i.bmdma[1].status << 24;
  78. break;
  79. case 0x18:
  80. val = d->i.bmdma[1].cmd;
  81. val |= (d->regs[1].confstat & (1UL << 11) ? (1 << 4) : 0);
  82. val |= (uint32_t)d->i.bmdma[1].status << 16;
  83. break;
  84. case 0x80 ... 0x87:
  85. val = pci_ide_data_le_ops.read(&d->i.bus[0], addr - 0x80, size);
  86. break;
  87. case 0x8a:
  88. val = pci_ide_cmd_le_ops.read(&d->i.bus[0], 2, size);
  89. break;
  90. case 0xa0:
  91. val = d->regs[0].confstat;
  92. break;
  93. case 0xc0 ... 0xc7:
  94. val = pci_ide_data_le_ops.read(&d->i.bus[1], addr - 0xc0, size);
  95. break;
  96. case 0xca:
  97. val = pci_ide_cmd_le_ops.read(&d->i.bus[1], 2, size);
  98. break;
  99. case 0xe0:
  100. val = d->regs[1].confstat;
  101. break;
  102. case 0x100:
  103. val = d->regs[0].scontrol;
  104. break;
  105. case 0x104:
  106. val = (d->i.bus[0].ifs[0].blk) ? 0x113 : 0;
  107. break;
  108. case 0x148:
  109. val = (uint32_t)d->regs[0].sien << 16;
  110. break;
  111. case 0x180:
  112. val = d->regs[1].scontrol;
  113. break;
  114. case 0x184:
  115. val = (d->i.bus[1].ifs[0].blk) ? 0x113 : 0;
  116. break;
  117. case 0x1c8:
  118. val = (uint32_t)d->regs[1].sien << 16;
  119. break;
  120. default:
  121. val = 0;
  122. break;
  123. }
  124. trace_sii3112_read(size, addr, val);
  125. return val;
  126. }
  127. static void sii3112_reg_write(void *opaque, hwaddr addr,
  128. uint64_t val, unsigned int size)
  129. {
  130. SiI3112PCIState *d = opaque;
  131. trace_sii3112_write(size, addr, val);
  132. switch (addr) {
  133. case 0x00:
  134. case 0x10:
  135. bmdma_cmd_writeb(&d->i.bmdma[0], val);
  136. break;
  137. case 0x01:
  138. case 0x11:
  139. d->regs[0].swdata = val & 0x3f;
  140. break;
  141. case 0x02:
  142. case 0x12:
  143. bmdma_status_writeb(&d->i.bmdma[0], val);
  144. break;
  145. case 0x04 ... 0x07:
  146. bmdma_addr_ioport_ops.write(&d->i.bmdma[0], addr - 4, val, size);
  147. break;
  148. case 0x08:
  149. case 0x18:
  150. bmdma_cmd_writeb(&d->i.bmdma[1], val);
  151. break;
  152. case 0x09:
  153. case 0x19:
  154. d->regs[1].swdata = val & 0x3f;
  155. break;
  156. case 0x0a:
  157. case 0x1a:
  158. bmdma_status_writeb(&d->i.bmdma[1], val);
  159. break;
  160. case 0x0c ... 0x0f:
  161. bmdma_addr_ioport_ops.write(&d->i.bmdma[1], addr - 12, val, size);
  162. break;
  163. case 0x80 ... 0x87:
  164. pci_ide_data_le_ops.write(&d->i.bus[0], addr - 0x80, val, size);
  165. break;
  166. case 0x8a:
  167. pci_ide_cmd_le_ops.write(&d->i.bus[0], 2, val, size);
  168. break;
  169. case 0xc0 ... 0xc7:
  170. pci_ide_data_le_ops.write(&d->i.bus[1], addr - 0xc0, val, size);
  171. break;
  172. case 0xca:
  173. pci_ide_cmd_le_ops.write(&d->i.bus[1], 2, val, size);
  174. break;
  175. case 0x100:
  176. d->regs[0].scontrol = val & 0xfff;
  177. if (val & 1) {
  178. ide_bus_reset(&d->i.bus[0]);
  179. }
  180. break;
  181. case 0x148:
  182. d->regs[0].sien = (val >> 16) & 0x3eed;
  183. break;
  184. case 0x180:
  185. d->regs[1].scontrol = val & 0xfff;
  186. if (val & 1) {
  187. ide_bus_reset(&d->i.bus[1]);
  188. }
  189. break;
  190. case 0x1c8:
  191. d->regs[1].sien = (val >> 16) & 0x3eed;
  192. break;
  193. default:
  194. break;
  195. }
  196. }
  197. static const MemoryRegionOps sii3112_reg_ops = {
  198. .read = sii3112_reg_read,
  199. .write = sii3112_reg_write,
  200. .endianness = DEVICE_LITTLE_ENDIAN,
  201. };
  202. /* the PCI irq level is the logical OR of the two channels */
  203. static void sii3112_update_irq(SiI3112PCIState *s)
  204. {
  205. int i, set = 0;
  206. for (i = 0; i < 2; i++) {
  207. set |= s->regs[i].confstat & (1UL << 11);
  208. }
  209. pci_set_irq(PCI_DEVICE(s), (set ? 1 : 0));
  210. }
  211. static void sii3112_set_irq(void *opaque, int channel, int level)
  212. {
  213. SiI3112PCIState *s = opaque;
  214. trace_sii3112_set_irq(channel, level);
  215. if (level) {
  216. s->regs[channel].confstat |= (1UL << 11);
  217. } else {
  218. s->regs[channel].confstat &= ~(1UL << 11);
  219. }
  220. sii3112_update_irq(s);
  221. }
  222. static void sii3112_reset(DeviceState *dev)
  223. {
  224. SiI3112PCIState *s = SII3112_PCI(dev);
  225. int i;
  226. for (i = 0; i < 2; i++) {
  227. s->regs[i].confstat = 0x6515 << 16;
  228. ide_bus_reset(&s->i.bus[i]);
  229. }
  230. }
  231. static void sii3112_pci_realize(PCIDevice *dev, Error **errp)
  232. {
  233. SiI3112PCIState *d = SII3112_PCI(dev);
  234. PCIIDEState *s = PCI_IDE(dev);
  235. DeviceState *ds = DEVICE(dev);
  236. MemoryRegion *mr;
  237. int i;
  238. pci_config_set_interrupt_pin(dev->config, 1);
  239. pci_set_byte(dev->config + PCI_CACHE_LINE_SIZE, 8);
  240. /* BAR5 is in PCI memory space */
  241. memory_region_init_io(&d->mmio, OBJECT(d), &sii3112_reg_ops, d,
  242. "sii3112.bar5", 0x200);
  243. pci_register_bar(dev, 5, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
  244. /* BAR0-BAR4 are PCI I/O space aliases into BAR5 */
  245. mr = g_new(MemoryRegion, 1);
  246. memory_region_init_alias(mr, OBJECT(d), "sii3112.bar0", &d->mmio, 0x80, 8);
  247. pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, mr);
  248. mr = g_new(MemoryRegion, 1);
  249. memory_region_init_alias(mr, OBJECT(d), "sii3112.bar1", &d->mmio, 0x88, 4);
  250. pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_IO, mr);
  251. mr = g_new(MemoryRegion, 1);
  252. memory_region_init_alias(mr, OBJECT(d), "sii3112.bar2", &d->mmio, 0xc0, 8);
  253. pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_IO, mr);
  254. mr = g_new(MemoryRegion, 1);
  255. memory_region_init_alias(mr, OBJECT(d), "sii3112.bar3", &d->mmio, 0xc8, 4);
  256. pci_register_bar(dev, 3, PCI_BASE_ADDRESS_SPACE_IO, mr);
  257. mr = g_new(MemoryRegion, 1);
  258. memory_region_init_alias(mr, OBJECT(d), "sii3112.bar4", &d->mmio, 0, 16);
  259. pci_register_bar(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, mr);
  260. qdev_init_gpio_in(ds, sii3112_set_irq, 2);
  261. for (i = 0; i < 2; i++) {
  262. ide_bus_init(&s->bus[i], sizeof(s->bus[i]), ds, i, 1);
  263. ide_bus_init_output_irq(&s->bus[i], qdev_get_gpio_in(ds, i));
  264. bmdma_init(&s->bus[i], &s->bmdma[i], s);
  265. ide_bus_register_restart_cb(&s->bus[i]);
  266. }
  267. }
  268. static void sii3112_pci_class_init(ObjectClass *klass, void *data)
  269. {
  270. DeviceClass *dc = DEVICE_CLASS(klass);
  271. PCIDeviceClass *pd = PCI_DEVICE_CLASS(klass);
  272. pd->vendor_id = 0x1095;
  273. pd->device_id = 0x3112;
  274. pd->class_id = PCI_CLASS_STORAGE_RAID;
  275. pd->revision = 1;
  276. pd->realize = sii3112_pci_realize;
  277. device_class_set_legacy_reset(dc, sii3112_reset);
  278. dc->desc = "SiI3112A SATA controller";
  279. set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
  280. }
  281. static const TypeInfo sii3112_pci_info = {
  282. .name = TYPE_SII3112_PCI,
  283. .parent = TYPE_PCI_IDE,
  284. .instance_size = sizeof(SiI3112PCIState),
  285. .class_init = sii3112_pci_class_init,
  286. };
  287. static void sii3112_register_types(void)
  288. {
  289. type_register_static(&sii3112_pci_info);
  290. }
  291. type_init(sii3112_register_types)