xref: /openbmc/qemu/hw/ipack/tpci200.c (revision d328fef93ae757a0dd65ed786a4086e27952eef3)
11f9c4cfdSAndreas Färber /*
21f9c4cfdSAndreas Färber  * QEMU TEWS TPCI200 IndustryPack carrier emulation
31f9c4cfdSAndreas Färber  *
41f9c4cfdSAndreas Färber  * Copyright (C) 2012 Igalia, S.L.
5b996aed5SAlberto Garcia  * Author: Alberto Garcia <berto@igalia.com>
61f9c4cfdSAndreas Färber  *
71f9c4cfdSAndreas Färber  * This code is licensed under the GNU GPL v2 or (at your option) any
81f9c4cfdSAndreas Färber  * later version.
91f9c4cfdSAndreas Färber  */
101f9c4cfdSAndreas Färber 
110430891cSPeter Maydell #include "qemu/osdep.h"
12a7174d70SPhilippe Mathieu-Daudé #include "qemu/units.h"
131f9c4cfdSAndreas Färber #include "hw/ipack/ipack.h"
1464552b6bSMarkus Armbruster #include "hw/irq.h"
15edf5ca5dSMarkus Armbruster #include "hw/pci/pci_device.h"
16d6454270SMarkus Armbruster #include "migration/vmstate.h"
171f9c4cfdSAndreas Färber #include "qemu/bitops.h"
180b8fa32fSMarkus Armbruster #include "qemu/module.h"
19db1015e9SEduardo Habkost #include "qom/object.h"
201f9c4cfdSAndreas Färber 
211f9c4cfdSAndreas Färber /* #define DEBUG_TPCI */
221f9c4cfdSAndreas Färber 
231f9c4cfdSAndreas Färber #ifdef DEBUG_TPCI
241f9c4cfdSAndreas Färber #define DPRINTF(fmt, ...) \
251f9c4cfdSAndreas Färber     do { fprintf(stderr, "TPCI200: " fmt, ## __VA_ARGS__); } while (0)
261f9c4cfdSAndreas Färber #else
271f9c4cfdSAndreas Färber #define DPRINTF(fmt, ...) do { } while (0)
281f9c4cfdSAndreas Färber #endif
291f9c4cfdSAndreas Färber 
301f9c4cfdSAndreas Färber #define N_MODULES 4
311f9c4cfdSAndreas Färber 
321f9c4cfdSAndreas Färber #define IP_ID_SPACE  2
331f9c4cfdSAndreas Färber #define IP_INT_SPACE 3
341f9c4cfdSAndreas Färber #define IP_IO_SPACE_ADDR_MASK  0x7F
351f9c4cfdSAndreas Färber #define IP_ID_SPACE_ADDR_MASK  0x3F
361f9c4cfdSAndreas Färber #define IP_INT_SPACE_ADDR_MASK 0x3F
371f9c4cfdSAndreas Färber 
381f9c4cfdSAndreas Färber #define STATUS_INT(IP, INTNO) BIT((IP) * 2 + (INTNO))
391f9c4cfdSAndreas Färber #define STATUS_TIME(IP)       BIT((IP) + 12)
401f9c4cfdSAndreas Färber #define STATUS_ERR_ANY        0xF00
411f9c4cfdSAndreas Färber 
421f9c4cfdSAndreas Färber #define CTRL_CLKRATE          BIT(0)
431f9c4cfdSAndreas Färber #define CTRL_RECOVER          BIT(1)
441f9c4cfdSAndreas Färber #define CTRL_TIME_INT         BIT(2)
451f9c4cfdSAndreas Färber #define CTRL_ERR_INT          BIT(3)
461f9c4cfdSAndreas Färber #define CTRL_INT_EDGE(INTNO)  BIT(4 + (INTNO))
471f9c4cfdSAndreas Färber #define CTRL_INT(INTNO)       BIT(6 + (INTNO))
481f9c4cfdSAndreas Färber 
491f9c4cfdSAndreas Färber #define REG_REV_ID    0x00
501f9c4cfdSAndreas Färber #define REG_IP_A_CTRL 0x02
511f9c4cfdSAndreas Färber #define REG_IP_B_CTRL 0x04
521f9c4cfdSAndreas Färber #define REG_IP_C_CTRL 0x06
531f9c4cfdSAndreas Färber #define REG_IP_D_CTRL 0x08
541f9c4cfdSAndreas Färber #define REG_RESET     0x0A
551f9c4cfdSAndreas Färber #define REG_STATUS    0x0C
561f9c4cfdSAndreas Färber #define IP_N_FROM_REG(REG) ((REG) / 2 - 1)
571f9c4cfdSAndreas Färber 
58db1015e9SEduardo Habkost struct TPCI200State {
591f9c4cfdSAndreas Färber     PCIDevice dev;
601f9c4cfdSAndreas Färber     IPackBus bus;
611f9c4cfdSAndreas Färber     MemoryRegion mmio;
621f9c4cfdSAndreas Färber     MemoryRegion io;
631f9c4cfdSAndreas Färber     MemoryRegion las0;
641f9c4cfdSAndreas Färber     MemoryRegion las1;
651f9c4cfdSAndreas Färber     MemoryRegion las2;
661f9c4cfdSAndreas Färber     MemoryRegion las3;
671f9c4cfdSAndreas Färber     bool big_endian[3];
681f9c4cfdSAndreas Färber     uint8_t ctrl[N_MODULES];
691f9c4cfdSAndreas Färber     uint16_t status;
701f9c4cfdSAndreas Färber     uint8_t int_set;
71db1015e9SEduardo Habkost };
721f9c4cfdSAndreas Färber 
731f9c4cfdSAndreas Färber #define TYPE_TPCI200 "tpci200"
741f9c4cfdSAndreas Färber 
758063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(TPCI200State, TPCI200)
761f9c4cfdSAndreas Färber 
771f9c4cfdSAndreas Färber static const uint8_t local_config_regs[] = {
781f9c4cfdSAndreas Färber     0x00, 0xFF, 0xFF, 0x0F, 0x00, 0xFC, 0xFF, 0x0F, 0x00, 0x00, 0x00,
791f9c4cfdSAndreas Färber     0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
801f9c4cfdSAndreas Färber     0x00, 0x08, 0x01, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x01,
811f9c4cfdSAndreas Färber     0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x60, 0x41, 0xD4,
821f9c4cfdSAndreas Färber     0xA2, 0x20, 0x41, 0x14, 0xA2, 0x20, 0x41, 0x14, 0xA2, 0x20, 0x01,
831f9c4cfdSAndreas Färber     0x14, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x08, 0x01, 0x02,
841f9c4cfdSAndreas Färber     0x00, 0x04, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x80, 0x02, 0x41,
851f9c4cfdSAndreas Färber     0x00, 0x00, 0x00, 0x00, 0x40, 0x7A, 0x00, 0x52, 0x92, 0x24, 0x02
861f9c4cfdSAndreas Färber };
871f9c4cfdSAndreas Färber 
adjust_addr(bool big_endian,hwaddr * addr,unsigned size)881f9c4cfdSAndreas Färber static void adjust_addr(bool big_endian, hwaddr *addr, unsigned size)
891f9c4cfdSAndreas Färber {
901f9c4cfdSAndreas Färber     /* During 8 bit access in big endian mode,
911f9c4cfdSAndreas Färber        odd and even addresses are swapped */
921f9c4cfdSAndreas Färber     if (big_endian && size == 1) {
931f9c4cfdSAndreas Färber         *addr ^= 1;
941f9c4cfdSAndreas Färber     }
951f9c4cfdSAndreas Färber }
961f9c4cfdSAndreas Färber 
adjust_value(bool big_endian,uint64_t * val,unsigned size)971f9c4cfdSAndreas Färber static uint64_t adjust_value(bool big_endian, uint64_t *val, unsigned size)
981f9c4cfdSAndreas Färber {
991f9c4cfdSAndreas Färber     /* Local spaces only support 8/16 bit access,
1001f9c4cfdSAndreas Färber      * so there's no need to care for sizes > 2 */
1011f9c4cfdSAndreas Färber     if (big_endian && size == 2) {
1021f9c4cfdSAndreas Färber         *val = bswap16(*val);
1031f9c4cfdSAndreas Färber     }
1041f9c4cfdSAndreas Färber     return *val;
1051f9c4cfdSAndreas Färber }
1061f9c4cfdSAndreas Färber 
tpci200_set_irq(void * opaque,int intno,int level)1071f9c4cfdSAndreas Färber static void tpci200_set_irq(void *opaque, int intno, int level)
1081f9c4cfdSAndreas Färber {
1091f9c4cfdSAndreas Färber     IPackDevice *ip = opaque;
1101f9c4cfdSAndreas Färber     IPackBus *bus = IPACK_BUS(qdev_get_parent_bus(DEVICE(ip)));
1111f9c4cfdSAndreas Färber     PCIDevice *pcidev = PCI_DEVICE(BUS(bus)->parent);
1121f9c4cfdSAndreas Färber     TPCI200State *dev = TPCI200(pcidev);
1131f9c4cfdSAndreas Färber     unsigned ip_n = ip->slot;
1141f9c4cfdSAndreas Färber     uint16_t prev_status = dev->status;
1151f9c4cfdSAndreas Färber 
1161f9c4cfdSAndreas Färber     assert(ip->slot >= 0 && ip->slot < N_MODULES);
1171f9c4cfdSAndreas Färber 
1181f9c4cfdSAndreas Färber     /* The requested interrupt must be enabled in the IP CONTROL
1191f9c4cfdSAndreas Färber      * register */
1201f9c4cfdSAndreas Färber     if (!(dev->ctrl[ip_n] & CTRL_INT(intno))) {
1211f9c4cfdSAndreas Färber         return;
1221f9c4cfdSAndreas Färber     }
1231f9c4cfdSAndreas Färber 
1241f9c4cfdSAndreas Färber     /* Update the interrupt status in the IP STATUS register */
1251f9c4cfdSAndreas Färber     if (level) {
1261f9c4cfdSAndreas Färber         dev->status |=  STATUS_INT(ip_n, intno);
1271f9c4cfdSAndreas Färber     } else {
1281f9c4cfdSAndreas Färber         dev->status &= ~STATUS_INT(ip_n, intno);
1291f9c4cfdSAndreas Färber     }
1301f9c4cfdSAndreas Färber 
1311f9c4cfdSAndreas Färber     /* Return if there are no changes */
1321f9c4cfdSAndreas Färber     if (dev->status == prev_status) {
1331f9c4cfdSAndreas Färber         return;
1341f9c4cfdSAndreas Färber     }
1351f9c4cfdSAndreas Färber 
1361f9c4cfdSAndreas Färber     DPRINTF("IP %u INT%u#: %u\n", ip_n, intno, level);
1371f9c4cfdSAndreas Färber 
1381f9c4cfdSAndreas Färber     /* Check if the interrupt is edge sensitive */
1391f9c4cfdSAndreas Färber     if (dev->ctrl[ip_n] & CTRL_INT_EDGE(intno)) {
1401f9c4cfdSAndreas Färber         if (level) {
1411f9c4cfdSAndreas Färber             pci_set_irq(&dev->dev, !dev->int_set);
1421f9c4cfdSAndreas Färber             pci_set_irq(&dev->dev,  dev->int_set);
1431f9c4cfdSAndreas Färber         }
1441f9c4cfdSAndreas Färber     } else {
1451f9c4cfdSAndreas Färber         unsigned i, j;
1461f9c4cfdSAndreas Färber         uint16_t level_status = dev->status;
1471f9c4cfdSAndreas Färber 
1481f9c4cfdSAndreas Färber         /* Check if there are any level sensitive interrupts set by
1491f9c4cfdSAndreas Färber            removing the ones that are edge sensitive from the status
1501f9c4cfdSAndreas Färber            register */
1511f9c4cfdSAndreas Färber         for (i = 0; i < N_MODULES; i++) {
1521f9c4cfdSAndreas Färber             for (j = 0; j < 2; j++) {
1531f9c4cfdSAndreas Färber                 if (dev->ctrl[i] & CTRL_INT_EDGE(j)) {
1541f9c4cfdSAndreas Färber                     level_status &= ~STATUS_INT(i, j);
1551f9c4cfdSAndreas Färber                 }
1561f9c4cfdSAndreas Färber             }
1571f9c4cfdSAndreas Färber         }
1581f9c4cfdSAndreas Färber 
1591f9c4cfdSAndreas Färber         if (level_status && !dev->int_set) {
1601f9c4cfdSAndreas Färber             pci_irq_assert(&dev->dev);
1611f9c4cfdSAndreas Färber             dev->int_set = 1;
1621f9c4cfdSAndreas Färber         } else if (!level_status && dev->int_set) {
1631f9c4cfdSAndreas Färber             pci_irq_deassert(&dev->dev);
1641f9c4cfdSAndreas Färber             dev->int_set = 0;
1651f9c4cfdSAndreas Färber         }
1661f9c4cfdSAndreas Färber     }
1671f9c4cfdSAndreas Färber }
1681f9c4cfdSAndreas Färber 
tpci200_read_cfg(void * opaque,hwaddr addr,unsigned size)1691f9c4cfdSAndreas Färber static uint64_t tpci200_read_cfg(void *opaque, hwaddr addr, unsigned size)
1701f9c4cfdSAndreas Färber {
1711f9c4cfdSAndreas Färber     TPCI200State *s = opaque;
1721f9c4cfdSAndreas Färber     uint8_t ret = 0;
1731f9c4cfdSAndreas Färber     if (addr < ARRAY_SIZE(local_config_regs)) {
1741f9c4cfdSAndreas Färber         ret = local_config_regs[addr];
1751f9c4cfdSAndreas Färber     }
1761f9c4cfdSAndreas Färber     /* Endianness is stored in the first bit of these registers */
1771f9c4cfdSAndreas Färber     if ((addr == 0x2b && s->big_endian[0]) ||
1781f9c4cfdSAndreas Färber         (addr == 0x2f && s->big_endian[1]) ||
1791f9c4cfdSAndreas Färber         (addr == 0x33 && s->big_endian[2])) {
1801f9c4cfdSAndreas Färber         ret |= 1;
1811f9c4cfdSAndreas Färber     }
1821f9c4cfdSAndreas Färber     DPRINTF("Read from LCR 0x%x: 0x%x\n", (unsigned) addr, (unsigned) ret);
1831f9c4cfdSAndreas Färber     return ret;
1841f9c4cfdSAndreas Färber }
1851f9c4cfdSAndreas Färber 
tpci200_write_cfg(void * opaque,hwaddr addr,uint64_t val,unsigned size)1861f9c4cfdSAndreas Färber static void tpci200_write_cfg(void *opaque, hwaddr addr, uint64_t val,
1871f9c4cfdSAndreas Färber                               unsigned size)
1881f9c4cfdSAndreas Färber {
1891f9c4cfdSAndreas Färber     TPCI200State *s = opaque;
1901f9c4cfdSAndreas Färber     /* Endianness is stored in the first bit of these registers */
1911f9c4cfdSAndreas Färber     if (addr == 0x2b || addr == 0x2f || addr == 0x33) {
1921f9c4cfdSAndreas Färber         unsigned las = (addr - 0x2b) / 4;
1931f9c4cfdSAndreas Färber         s->big_endian[las] = val & 1;
1941f9c4cfdSAndreas Färber         DPRINTF("LAS%u big endian mode: %u\n", las, (unsigned) val & 1);
1951f9c4cfdSAndreas Färber     } else {
1961f9c4cfdSAndreas Färber         DPRINTF("Write to LCR 0x%x: 0x%x\n", (unsigned) addr, (unsigned) val);
1971f9c4cfdSAndreas Färber     }
1981f9c4cfdSAndreas Färber }
1991f9c4cfdSAndreas Färber 
tpci200_read_las0(void * opaque,hwaddr addr,unsigned size)2001f9c4cfdSAndreas Färber static uint64_t tpci200_read_las0(void *opaque, hwaddr addr, unsigned size)
2011f9c4cfdSAndreas Färber {
2021f9c4cfdSAndreas Färber     TPCI200State *s = opaque;
2031f9c4cfdSAndreas Färber     uint64_t ret = 0;
2041f9c4cfdSAndreas Färber 
2051f9c4cfdSAndreas Färber     switch (addr) {
2061f9c4cfdSAndreas Färber 
2071f9c4cfdSAndreas Färber     case REG_REV_ID:
2081f9c4cfdSAndreas Färber         DPRINTF("Read REVISION ID\n"); /* Current value is 0x00 */
2091f9c4cfdSAndreas Färber         break;
2101f9c4cfdSAndreas Färber 
2111f9c4cfdSAndreas Färber     case REG_IP_A_CTRL:
2121f9c4cfdSAndreas Färber     case REG_IP_B_CTRL:
2131f9c4cfdSAndreas Färber     case REG_IP_C_CTRL:
2141f9c4cfdSAndreas Färber     case REG_IP_D_CTRL:
2151f9c4cfdSAndreas Färber         {
2161f9c4cfdSAndreas Färber             unsigned ip_n = IP_N_FROM_REG(addr);
2171f9c4cfdSAndreas Färber             ret = s->ctrl[ip_n];
2181f9c4cfdSAndreas Färber             DPRINTF("Read IP %c CONTROL: 0x%x\n", 'A' + ip_n, (unsigned) ret);
2191f9c4cfdSAndreas Färber         }
2201f9c4cfdSAndreas Färber         break;
2211f9c4cfdSAndreas Färber 
2221f9c4cfdSAndreas Färber     case REG_RESET:
2231f9c4cfdSAndreas Färber         DPRINTF("Read RESET\n"); /* Not implemented */
2241f9c4cfdSAndreas Färber         break;
2251f9c4cfdSAndreas Färber 
2261f9c4cfdSAndreas Färber     case REG_STATUS:
2271f9c4cfdSAndreas Färber         ret = s->status;
2281f9c4cfdSAndreas Färber         DPRINTF("Read STATUS: 0x%x\n", (unsigned) ret);
2291f9c4cfdSAndreas Färber         break;
2301f9c4cfdSAndreas Färber 
2311f9c4cfdSAndreas Färber     /* Reserved */
2321f9c4cfdSAndreas Färber     default:
2331f9c4cfdSAndreas Färber         DPRINTF("Unsupported read from LAS0 0x%x\n", (unsigned) addr);
2341f9c4cfdSAndreas Färber         break;
2351f9c4cfdSAndreas Färber     }
2361f9c4cfdSAndreas Färber 
2371f9c4cfdSAndreas Färber     return adjust_value(s->big_endian[0], &ret, size);
2381f9c4cfdSAndreas Färber }
2391f9c4cfdSAndreas Färber 
tpci200_write_las0(void * opaque,hwaddr addr,uint64_t val,unsigned size)2401f9c4cfdSAndreas Färber static void tpci200_write_las0(void *opaque, hwaddr addr, uint64_t val,
2411f9c4cfdSAndreas Färber                                unsigned size)
2421f9c4cfdSAndreas Färber {
2431f9c4cfdSAndreas Färber     TPCI200State *s = opaque;
2441f9c4cfdSAndreas Färber 
2451f9c4cfdSAndreas Färber     adjust_value(s->big_endian[0], &val, size);
2461f9c4cfdSAndreas Färber 
2471f9c4cfdSAndreas Färber     switch (addr) {
2481f9c4cfdSAndreas Färber 
2491f9c4cfdSAndreas Färber     case REG_REV_ID:
2501f9c4cfdSAndreas Färber         DPRINTF("Write Revision ID: 0x%x\n", (unsigned) val); /* No effect */
2511f9c4cfdSAndreas Färber         break;
2521f9c4cfdSAndreas Färber 
2531f9c4cfdSAndreas Färber     case REG_IP_A_CTRL:
2541f9c4cfdSAndreas Färber     case REG_IP_B_CTRL:
2551f9c4cfdSAndreas Färber     case REG_IP_C_CTRL:
2561f9c4cfdSAndreas Färber     case REG_IP_D_CTRL:
2571f9c4cfdSAndreas Färber         {
2581f9c4cfdSAndreas Färber             unsigned ip_n = IP_N_FROM_REG(addr);
2591f9c4cfdSAndreas Färber             s->ctrl[ip_n] = val;
2601f9c4cfdSAndreas Färber             DPRINTF("Write IP %c CONTROL: 0x%x\n", 'A' + ip_n, (unsigned) val);
2611f9c4cfdSAndreas Färber         }
2621f9c4cfdSAndreas Färber         break;
2631f9c4cfdSAndreas Färber 
2641f9c4cfdSAndreas Färber     case REG_RESET:
2651f9c4cfdSAndreas Färber         DPRINTF("Write RESET: 0x%x\n", (unsigned) val); /* Not implemented */
2661f9c4cfdSAndreas Färber         break;
2671f9c4cfdSAndreas Färber 
2681f9c4cfdSAndreas Färber     case REG_STATUS:
2691f9c4cfdSAndreas Färber         {
2701f9c4cfdSAndreas Färber             unsigned i;
2711f9c4cfdSAndreas Färber 
2721f9c4cfdSAndreas Färber             for (i = 0; i < N_MODULES; i++) {
2731f9c4cfdSAndreas Färber                 IPackDevice *ip = ipack_device_find(&s->bus, i);
2741f9c4cfdSAndreas Färber 
2751f9c4cfdSAndreas Färber                 if (ip != NULL) {
2761f9c4cfdSAndreas Färber                     if (val & STATUS_INT(i, 0)) {
2771f9c4cfdSAndreas Färber                         DPRINTF("Clear IP %c INT0# status\n", 'A' + i);
2781f9c4cfdSAndreas Färber                         qemu_irq_lower(ip->irq[0]);
2791f9c4cfdSAndreas Färber                     }
2801f9c4cfdSAndreas Färber                     if (val & STATUS_INT(i, 1)) {
2811f9c4cfdSAndreas Färber                         DPRINTF("Clear IP %c INT1# status\n", 'A' + i);
2821f9c4cfdSAndreas Färber                         qemu_irq_lower(ip->irq[1]);
2831f9c4cfdSAndreas Färber                     }
2841f9c4cfdSAndreas Färber                 }
2851f9c4cfdSAndreas Färber 
2861f9c4cfdSAndreas Färber                 if (val & STATUS_TIME(i)) {
2871f9c4cfdSAndreas Färber                     DPRINTF("Clear IP %c timeout\n", 'A' + i);
2881f9c4cfdSAndreas Färber                     s->status &= ~STATUS_TIME(i);
2891f9c4cfdSAndreas Färber                 }
2901f9c4cfdSAndreas Färber             }
2911f9c4cfdSAndreas Färber 
2921f9c4cfdSAndreas Färber             if (val & STATUS_ERR_ANY) {
2931f9c4cfdSAndreas Färber                 DPRINTF("Unexpected write to STATUS register: 0x%x\n",
2941f9c4cfdSAndreas Färber                         (unsigned) val);
2951f9c4cfdSAndreas Färber             }
2961f9c4cfdSAndreas Färber         }
2971f9c4cfdSAndreas Färber         break;
2981f9c4cfdSAndreas Färber 
2991f9c4cfdSAndreas Färber     /* Reserved */
3001f9c4cfdSAndreas Färber     default:
3011f9c4cfdSAndreas Färber         DPRINTF("Unsupported write to LAS0 0x%x: 0x%x\n",
3021f9c4cfdSAndreas Färber                 (unsigned) addr, (unsigned) val);
3031f9c4cfdSAndreas Färber         break;
3041f9c4cfdSAndreas Färber     }
3051f9c4cfdSAndreas Färber }
3061f9c4cfdSAndreas Färber 
tpci200_read_las1(void * opaque,hwaddr addr,unsigned size)3071f9c4cfdSAndreas Färber static uint64_t tpci200_read_las1(void *opaque, hwaddr addr, unsigned size)
3081f9c4cfdSAndreas Färber {
3091f9c4cfdSAndreas Färber     TPCI200State *s = opaque;
3101f9c4cfdSAndreas Färber     IPackDevice *ip;
3111f9c4cfdSAndreas Färber     uint64_t ret = 0;
3121f9c4cfdSAndreas Färber     unsigned ip_n, space;
3131f9c4cfdSAndreas Färber     uint8_t offset;
3141f9c4cfdSAndreas Färber 
3151f9c4cfdSAndreas Färber     adjust_addr(s->big_endian[1], &addr, size);
3161f9c4cfdSAndreas Färber 
3171f9c4cfdSAndreas Färber     /*
3181f9c4cfdSAndreas Färber      * The address is divided into the IP module number (0-4), the IP
3191f9c4cfdSAndreas Färber      * address space (I/O, ID, INT) and the offset within that space.
3201f9c4cfdSAndreas Färber      */
3211f9c4cfdSAndreas Färber     ip_n = addr >> 8;
3221f9c4cfdSAndreas Färber     space = (addr >> 6) & 3;
3231f9c4cfdSAndreas Färber     ip = ipack_device_find(&s->bus, ip_n);
3241f9c4cfdSAndreas Färber 
3251f9c4cfdSAndreas Färber     if (ip == NULL) {
3261f9c4cfdSAndreas Färber         DPRINTF("Read LAS1: IP module %u not installed\n", ip_n);
3271f9c4cfdSAndreas Färber     } else {
3281f9c4cfdSAndreas Färber         IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
3291f9c4cfdSAndreas Färber         switch (space) {
3301f9c4cfdSAndreas Färber 
3311f9c4cfdSAndreas Färber         case IP_ID_SPACE:
3321f9c4cfdSAndreas Färber             offset = addr & IP_ID_SPACE_ADDR_MASK;
3331f9c4cfdSAndreas Färber             if (k->id_read) {
3341f9c4cfdSAndreas Färber                 ret = k->id_read(ip, offset);
3351f9c4cfdSAndreas Färber             }
3361f9c4cfdSAndreas Färber             break;
3371f9c4cfdSAndreas Färber 
3381f9c4cfdSAndreas Färber         case IP_INT_SPACE:
3391f9c4cfdSAndreas Färber             offset = addr & IP_INT_SPACE_ADDR_MASK;
3401f9c4cfdSAndreas Färber 
3411f9c4cfdSAndreas Färber             /* Read address 0 to ACK IP INT0# and address 2 to ACK IP INT1# */
3421f9c4cfdSAndreas Färber             if (offset == 0 || offset == 2) {
3431f9c4cfdSAndreas Färber                 unsigned intno = offset / 2;
3441f9c4cfdSAndreas Färber                 bool int_set = s->status & STATUS_INT(ip_n, intno);
3451f9c4cfdSAndreas Färber                 bool int_edge_sensitive = s->ctrl[ip_n] & CTRL_INT_EDGE(intno);
3461f9c4cfdSAndreas Färber                 if (int_set && !int_edge_sensitive) {
3471f9c4cfdSAndreas Färber                     qemu_irq_lower(ip->irq[intno]);
3481f9c4cfdSAndreas Färber                 }
3491f9c4cfdSAndreas Färber             }
3501f9c4cfdSAndreas Färber 
3511f9c4cfdSAndreas Färber             if (k->int_read) {
3521f9c4cfdSAndreas Färber                 ret = k->int_read(ip, offset);
3531f9c4cfdSAndreas Färber             }
3541f9c4cfdSAndreas Färber             break;
3551f9c4cfdSAndreas Färber 
3561f9c4cfdSAndreas Färber         default:
3571f9c4cfdSAndreas Färber             offset = addr & IP_IO_SPACE_ADDR_MASK;
3581f9c4cfdSAndreas Färber             if (k->io_read) {
3591f9c4cfdSAndreas Färber                 ret = k->io_read(ip, offset);
3601f9c4cfdSAndreas Färber             }
3611f9c4cfdSAndreas Färber             break;
3621f9c4cfdSAndreas Färber         }
3631f9c4cfdSAndreas Färber     }
3641f9c4cfdSAndreas Färber 
3651f9c4cfdSAndreas Färber     return adjust_value(s->big_endian[1], &ret, size);
3661f9c4cfdSAndreas Färber }
3671f9c4cfdSAndreas Färber 
tpci200_write_las1(void * opaque,hwaddr addr,uint64_t val,unsigned size)3681f9c4cfdSAndreas Färber static void tpci200_write_las1(void *opaque, hwaddr addr, uint64_t val,
3691f9c4cfdSAndreas Färber                                unsigned size)
3701f9c4cfdSAndreas Färber {
3711f9c4cfdSAndreas Färber     TPCI200State *s = opaque;
3721f9c4cfdSAndreas Färber     IPackDevice *ip;
3731f9c4cfdSAndreas Färber     unsigned ip_n, space;
3741f9c4cfdSAndreas Färber     uint8_t offset;
3751f9c4cfdSAndreas Färber 
3761f9c4cfdSAndreas Färber     adjust_addr(s->big_endian[1], &addr, size);
3771f9c4cfdSAndreas Färber     adjust_value(s->big_endian[1], &val, size);
3781f9c4cfdSAndreas Färber 
3791f9c4cfdSAndreas Färber     /*
3801f9c4cfdSAndreas Färber      * The address is divided into the IP module number, the IP
3811f9c4cfdSAndreas Färber      * address space (I/O, ID, INT) and the offset within that space.
3821f9c4cfdSAndreas Färber      */
3831f9c4cfdSAndreas Färber     ip_n = addr >> 8;
3841f9c4cfdSAndreas Färber     space = (addr >> 6) & 3;
3851f9c4cfdSAndreas Färber     ip = ipack_device_find(&s->bus, ip_n);
3861f9c4cfdSAndreas Färber 
3871f9c4cfdSAndreas Färber     if (ip == NULL) {
3881f9c4cfdSAndreas Färber         DPRINTF("Write LAS1: IP module %u not installed\n", ip_n);
3891f9c4cfdSAndreas Färber     } else {
3901f9c4cfdSAndreas Färber         IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
3911f9c4cfdSAndreas Färber         switch (space) {
3921f9c4cfdSAndreas Färber 
3931f9c4cfdSAndreas Färber         case IP_ID_SPACE:
3941f9c4cfdSAndreas Färber             offset = addr & IP_ID_SPACE_ADDR_MASK;
3951f9c4cfdSAndreas Färber             if (k->id_write) {
3961f9c4cfdSAndreas Färber                 k->id_write(ip, offset, val);
3971f9c4cfdSAndreas Färber             }
3981f9c4cfdSAndreas Färber             break;
3991f9c4cfdSAndreas Färber 
4001f9c4cfdSAndreas Färber         case IP_INT_SPACE:
4011f9c4cfdSAndreas Färber             offset = addr & IP_INT_SPACE_ADDR_MASK;
4021f9c4cfdSAndreas Färber             if (k->int_write) {
4031f9c4cfdSAndreas Färber                 k->int_write(ip, offset, val);
4041f9c4cfdSAndreas Färber             }
4051f9c4cfdSAndreas Färber             break;
4061f9c4cfdSAndreas Färber 
4071f9c4cfdSAndreas Färber         default:
4081f9c4cfdSAndreas Färber             offset = addr & IP_IO_SPACE_ADDR_MASK;
4091f9c4cfdSAndreas Färber             if (k->io_write) {
4101f9c4cfdSAndreas Färber                 k->io_write(ip, offset, val);
4111f9c4cfdSAndreas Färber             }
4121f9c4cfdSAndreas Färber             break;
4131f9c4cfdSAndreas Färber         }
4141f9c4cfdSAndreas Färber     }
4151f9c4cfdSAndreas Färber }
4161f9c4cfdSAndreas Färber 
tpci200_read_las2(void * opaque,hwaddr addr,unsigned size)4171f9c4cfdSAndreas Färber static uint64_t tpci200_read_las2(void *opaque, hwaddr addr, unsigned size)
4181f9c4cfdSAndreas Färber {
4191f9c4cfdSAndreas Färber     TPCI200State *s = opaque;
4201f9c4cfdSAndreas Färber     IPackDevice *ip;
4211f9c4cfdSAndreas Färber     uint64_t ret = 0;
4221f9c4cfdSAndreas Färber     unsigned ip_n;
4231f9c4cfdSAndreas Färber     uint32_t offset;
4241f9c4cfdSAndreas Färber 
4251f9c4cfdSAndreas Färber     adjust_addr(s->big_endian[2], &addr, size);
4261f9c4cfdSAndreas Färber 
4271f9c4cfdSAndreas Färber     /*
4281f9c4cfdSAndreas Färber      * The address is divided into the IP module number and the offset
4291f9c4cfdSAndreas Färber      * within the IP module MEM space.
4301f9c4cfdSAndreas Färber      */
4311f9c4cfdSAndreas Färber     ip_n = addr >> 23;
4321f9c4cfdSAndreas Färber     offset = addr & 0x7fffff;
4331f9c4cfdSAndreas Färber     ip = ipack_device_find(&s->bus, ip_n);
4341f9c4cfdSAndreas Färber 
4351f9c4cfdSAndreas Färber     if (ip == NULL) {
4361f9c4cfdSAndreas Färber         DPRINTF("Read LAS2: IP module %u not installed\n", ip_n);
4371f9c4cfdSAndreas Färber     } else {
4381f9c4cfdSAndreas Färber         IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
4391f9c4cfdSAndreas Färber         if (k->mem_read16) {
4401f9c4cfdSAndreas Färber             ret = k->mem_read16(ip, offset);
4411f9c4cfdSAndreas Färber         }
4421f9c4cfdSAndreas Färber     }
4431f9c4cfdSAndreas Färber 
4441f9c4cfdSAndreas Färber     return adjust_value(s->big_endian[2], &ret, size);
4451f9c4cfdSAndreas Färber }
4461f9c4cfdSAndreas Färber 
tpci200_write_las2(void * opaque,hwaddr addr,uint64_t val,unsigned size)4471f9c4cfdSAndreas Färber static void tpci200_write_las2(void *opaque, hwaddr addr, uint64_t val,
4481f9c4cfdSAndreas Färber                                unsigned size)
4491f9c4cfdSAndreas Färber {
4501f9c4cfdSAndreas Färber     TPCI200State *s = opaque;
4511f9c4cfdSAndreas Färber     IPackDevice *ip;
4521f9c4cfdSAndreas Färber     unsigned ip_n;
4531f9c4cfdSAndreas Färber     uint32_t offset;
4541f9c4cfdSAndreas Färber 
4551f9c4cfdSAndreas Färber     adjust_addr(s->big_endian[2], &addr, size);
4561f9c4cfdSAndreas Färber     adjust_value(s->big_endian[2], &val, size);
4571f9c4cfdSAndreas Färber 
4581f9c4cfdSAndreas Färber     /*
4591f9c4cfdSAndreas Färber      * The address is divided into the IP module number and the offset
4601f9c4cfdSAndreas Färber      * within the IP module MEM space.
4611f9c4cfdSAndreas Färber      */
4621f9c4cfdSAndreas Färber     ip_n = addr >> 23;
4631f9c4cfdSAndreas Färber     offset = addr & 0x7fffff;
4641f9c4cfdSAndreas Färber     ip = ipack_device_find(&s->bus, ip_n);
4651f9c4cfdSAndreas Färber 
4661f9c4cfdSAndreas Färber     if (ip == NULL) {
4671f9c4cfdSAndreas Färber         DPRINTF("Write LAS2: IP module %u not installed\n", ip_n);
4681f9c4cfdSAndreas Färber     } else {
4691f9c4cfdSAndreas Färber         IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
4701f9c4cfdSAndreas Färber         if (k->mem_write16) {
4711f9c4cfdSAndreas Färber             k->mem_write16(ip, offset, val);
4721f9c4cfdSAndreas Färber         }
4731f9c4cfdSAndreas Färber     }
4741f9c4cfdSAndreas Färber }
4751f9c4cfdSAndreas Färber 
tpci200_read_las3(void * opaque,hwaddr addr,unsigned size)4761f9c4cfdSAndreas Färber static uint64_t tpci200_read_las3(void *opaque, hwaddr addr, unsigned size)
4771f9c4cfdSAndreas Färber {
4781f9c4cfdSAndreas Färber     TPCI200State *s = opaque;
4791f9c4cfdSAndreas Färber     IPackDevice *ip;
4801f9c4cfdSAndreas Färber     uint64_t ret = 0;
4811f9c4cfdSAndreas Färber     /*
4821f9c4cfdSAndreas Färber      * The address is divided into the IP module number and the offset
4831f9c4cfdSAndreas Färber      * within the IP module MEM space.
4841f9c4cfdSAndreas Färber      */
4851f9c4cfdSAndreas Färber     unsigned ip_n = addr >> 22;
4861f9c4cfdSAndreas Färber     uint32_t offset = addr & 0x3fffff;
4871f9c4cfdSAndreas Färber 
4881f9c4cfdSAndreas Färber     ip = ipack_device_find(&s->bus, ip_n);
4891f9c4cfdSAndreas Färber 
4901f9c4cfdSAndreas Färber     if (ip == NULL) {
4911f9c4cfdSAndreas Färber         DPRINTF("Read LAS3: IP module %u not installed\n", ip_n);
4921f9c4cfdSAndreas Färber     } else {
4931f9c4cfdSAndreas Färber         IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
4941f9c4cfdSAndreas Färber         if (k->mem_read8) {
4951f9c4cfdSAndreas Färber             ret = k->mem_read8(ip, offset);
4961f9c4cfdSAndreas Färber         }
4971f9c4cfdSAndreas Färber     }
4981f9c4cfdSAndreas Färber 
4991f9c4cfdSAndreas Färber     return ret;
5001f9c4cfdSAndreas Färber }
5011f9c4cfdSAndreas Färber 
tpci200_write_las3(void * opaque,hwaddr addr,uint64_t val,unsigned size)5021f9c4cfdSAndreas Färber static void tpci200_write_las3(void *opaque, hwaddr addr, uint64_t val,
5031f9c4cfdSAndreas Färber                                unsigned size)
5041f9c4cfdSAndreas Färber {
5051f9c4cfdSAndreas Färber     TPCI200State *s = opaque;
5061f9c4cfdSAndreas Färber     IPackDevice *ip;
5071f9c4cfdSAndreas Färber     /*
5081f9c4cfdSAndreas Färber      * The address is divided into the IP module number and the offset
5091f9c4cfdSAndreas Färber      * within the IP module MEM space.
5101f9c4cfdSAndreas Färber      */
5111f9c4cfdSAndreas Färber     unsigned ip_n = addr >> 22;
5121f9c4cfdSAndreas Färber     uint32_t offset = addr & 0x3fffff;
5131f9c4cfdSAndreas Färber 
5141f9c4cfdSAndreas Färber     ip = ipack_device_find(&s->bus, ip_n);
5151f9c4cfdSAndreas Färber 
5161f9c4cfdSAndreas Färber     if (ip == NULL) {
5171f9c4cfdSAndreas Färber         DPRINTF("Write LAS3: IP module %u not installed\n", ip_n);
5181f9c4cfdSAndreas Färber     } else {
5191f9c4cfdSAndreas Färber         IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
5201f9c4cfdSAndreas Färber         if (k->mem_write8) {
5211f9c4cfdSAndreas Färber             k->mem_write8(ip, offset, val);
5221f9c4cfdSAndreas Färber         }
5231f9c4cfdSAndreas Färber     }
5241f9c4cfdSAndreas Färber }
5251f9c4cfdSAndreas Färber 
5261f9c4cfdSAndreas Färber static const MemoryRegionOps tpci200_cfg_ops = {
5271f9c4cfdSAndreas Färber     .read = tpci200_read_cfg,
5281f9c4cfdSAndreas Färber     .write = tpci200_write_cfg,
5291f9c4cfdSAndreas Färber     .endianness = DEVICE_NATIVE_ENDIAN,
5301f9c4cfdSAndreas Färber     .valid =  {
5311f9c4cfdSAndreas Färber         .min_access_size = 1,
5321f9c4cfdSAndreas Färber         .max_access_size = 4
5331f9c4cfdSAndreas Färber     },
5341f9c4cfdSAndreas Färber     .impl = {
5351f9c4cfdSAndreas Färber         .min_access_size = 1,
5361f9c4cfdSAndreas Färber         .max_access_size = 1
5371f9c4cfdSAndreas Färber     }
5381f9c4cfdSAndreas Färber };
5391f9c4cfdSAndreas Färber 
5401f9c4cfdSAndreas Färber static const MemoryRegionOps tpci200_las0_ops = {
5411f9c4cfdSAndreas Färber     .read = tpci200_read_las0,
5421f9c4cfdSAndreas Färber     .write = tpci200_write_las0,
5431f9c4cfdSAndreas Färber     .endianness = DEVICE_NATIVE_ENDIAN,
5441f9c4cfdSAndreas Färber     .valid =  {
5451f9c4cfdSAndreas Färber         .min_access_size = 2,
5461f9c4cfdSAndreas Färber         .max_access_size = 2
5471f9c4cfdSAndreas Färber     }
5481f9c4cfdSAndreas Färber };
5491f9c4cfdSAndreas Färber 
5501f9c4cfdSAndreas Färber static const MemoryRegionOps tpci200_las1_ops = {
5511f9c4cfdSAndreas Färber     .read = tpci200_read_las1,
5521f9c4cfdSAndreas Färber     .write = tpci200_write_las1,
5531f9c4cfdSAndreas Färber     .endianness = DEVICE_NATIVE_ENDIAN,
5541f9c4cfdSAndreas Färber     .valid =  {
5551f9c4cfdSAndreas Färber         .min_access_size = 1,
5561f9c4cfdSAndreas Färber         .max_access_size = 2
5571f9c4cfdSAndreas Färber     }
5581f9c4cfdSAndreas Färber };
5591f9c4cfdSAndreas Färber 
5601f9c4cfdSAndreas Färber static const MemoryRegionOps tpci200_las2_ops = {
5611f9c4cfdSAndreas Färber     .read = tpci200_read_las2,
5621f9c4cfdSAndreas Färber     .write = tpci200_write_las2,
5631f9c4cfdSAndreas Färber     .endianness = DEVICE_NATIVE_ENDIAN,
5641f9c4cfdSAndreas Färber     .valid =  {
5651f9c4cfdSAndreas Färber         .min_access_size = 1,
5661f9c4cfdSAndreas Färber         .max_access_size = 2
5671f9c4cfdSAndreas Färber     }
5681f9c4cfdSAndreas Färber };
5691f9c4cfdSAndreas Färber 
5701f9c4cfdSAndreas Färber static const MemoryRegionOps tpci200_las3_ops = {
5711f9c4cfdSAndreas Färber     .read = tpci200_read_las3,
5721f9c4cfdSAndreas Färber     .write = tpci200_write_las3,
5731f9c4cfdSAndreas Färber     .endianness = DEVICE_NATIVE_ENDIAN,
5741f9c4cfdSAndreas Färber     .valid =  {
5751f9c4cfdSAndreas Färber         .min_access_size = 1,
5761f9c4cfdSAndreas Färber         .max_access_size = 1
5771f9c4cfdSAndreas Färber     }
5781f9c4cfdSAndreas Färber };
5791f9c4cfdSAndreas Färber 
tpci200_realize(PCIDevice * pci_dev,Error ** errp)5809af21dbeSMarkus Armbruster static void tpci200_realize(PCIDevice *pci_dev, Error **errp)
5811f9c4cfdSAndreas Färber {
5821f9c4cfdSAndreas Färber     TPCI200State *s = TPCI200(pci_dev);
5831f9c4cfdSAndreas Färber     uint8_t *c = s->dev.config;
5841f9c4cfdSAndreas Färber 
5851f9c4cfdSAndreas Färber     pci_set_word(c + PCI_COMMAND, 0x0003);
5861f9c4cfdSAndreas Färber     pci_set_word(c + PCI_STATUS,  0x0280);
5871f9c4cfdSAndreas Färber 
5881f9c4cfdSAndreas Färber     pci_set_byte(c + PCI_INTERRUPT_PIN, 0x01); /* Interrupt pin A */
5891f9c4cfdSAndreas Färber 
5901f9c4cfdSAndreas Färber     pci_set_byte(c + PCI_CAPABILITY_LIST, 0x40);
5911f9c4cfdSAndreas Färber     pci_set_long(c + 0x40, 0x48014801);
5921f9c4cfdSAndreas Färber     pci_set_long(c + 0x48, 0x00024C06);
5931f9c4cfdSAndreas Färber     pci_set_long(c + 0x4C, 0x00000003);
5941f9c4cfdSAndreas Färber 
5951f9c4cfdSAndreas Färber     memory_region_init_io(&s->mmio, OBJECT(s), &tpci200_cfg_ops,
5961f9c4cfdSAndreas Färber                           s, "tpci200_mmio", 128);
5971f9c4cfdSAndreas Färber     memory_region_init_io(&s->io, OBJECT(s),   &tpci200_cfg_ops,
5981f9c4cfdSAndreas Färber                           s, "tpci200_io",   128);
5991f9c4cfdSAndreas Färber     memory_region_init_io(&s->las0, OBJECT(s), &tpci200_las0_ops,
6001f9c4cfdSAndreas Färber                           s, "tpci200_las0", 256);
6011f9c4cfdSAndreas Färber     memory_region_init_io(&s->las1, OBJECT(s), &tpci200_las1_ops,
6021f9c4cfdSAndreas Färber                           s, "tpci200_las1", 1024);
6031f9c4cfdSAndreas Färber     memory_region_init_io(&s->las2, OBJECT(s), &tpci200_las2_ops,
604a7174d70SPhilippe Mathieu-Daudé                           s, "tpci200_las2", 32 * MiB);
6051f9c4cfdSAndreas Färber     memory_region_init_io(&s->las3, OBJECT(s), &tpci200_las3_ops,
606a7174d70SPhilippe Mathieu-Daudé                           s, "tpci200_las3", 16 * MiB);
6071f9c4cfdSAndreas Färber     pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio);
6081f9c4cfdSAndreas Färber     pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO,     &s->io);
6091f9c4cfdSAndreas Färber     pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las0);
6101f9c4cfdSAndreas Färber     pci_register_bar(&s->dev, 3, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las1);
6111f9c4cfdSAndreas Färber     pci_register_bar(&s->dev, 4, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las2);
6121f9c4cfdSAndreas Färber     pci_register_bar(&s->dev, 5, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las3);
6131f9c4cfdSAndreas Färber 
61443417c0cSPeter Maydell     ipack_bus_init(&s->bus, sizeof(s->bus), DEVICE(pci_dev),
6151f9c4cfdSAndreas Färber                    N_MODULES, tpci200_set_irq);
6161f9c4cfdSAndreas Färber }
6171f9c4cfdSAndreas Färber 
6181f9c4cfdSAndreas Färber static const VMStateDescription vmstate_tpci200 = {
6191f9c4cfdSAndreas Färber     .name = "tpci200",
6201f9c4cfdSAndreas Färber     .version_id = 1,
6211f9c4cfdSAndreas Färber     .minimum_version_id = 1,
622*8913d05dSRichard Henderson     .fields = (const VMStateField[]) {
6231f9c4cfdSAndreas Färber         VMSTATE_PCI_DEVICE(dev, TPCI200State),
6241f9c4cfdSAndreas Färber         VMSTATE_BOOL_ARRAY(big_endian, TPCI200State, 3),
6251f9c4cfdSAndreas Färber         VMSTATE_UINT8_ARRAY(ctrl, TPCI200State, N_MODULES),
6261f9c4cfdSAndreas Färber         VMSTATE_UINT16(status, TPCI200State),
6271f9c4cfdSAndreas Färber         VMSTATE_UINT8(int_set, TPCI200State),
6281f9c4cfdSAndreas Färber         VMSTATE_END_OF_LIST()
6291f9c4cfdSAndreas Färber     }
6301f9c4cfdSAndreas Färber };
6311f9c4cfdSAndreas Färber 
tpci200_class_init(ObjectClass * klass,void * data)6321f9c4cfdSAndreas Färber static void tpci200_class_init(ObjectClass *klass, void *data)
6331f9c4cfdSAndreas Färber {
6341f9c4cfdSAndreas Färber     DeviceClass *dc = DEVICE_CLASS(klass);
6351f9c4cfdSAndreas Färber     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
6361f9c4cfdSAndreas Färber 
6379af21dbeSMarkus Armbruster     k->realize = tpci200_realize;
6381f9c4cfdSAndreas Färber     k->vendor_id = PCI_VENDOR_ID_TEWS;
6391f9c4cfdSAndreas Färber     k->device_id = PCI_DEVICE_ID_TEWS_TPCI200;
6401f9c4cfdSAndreas Färber     k->class_id = PCI_CLASS_BRIDGE_OTHER;
6411f9c4cfdSAndreas Färber     k->subsystem_vendor_id = PCI_VENDOR_ID_TEWS;
6421f9c4cfdSAndreas Färber     k->subsystem_id = 0x300A;
6431f9c4cfdSAndreas Färber     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
6441f9c4cfdSAndreas Färber     dc->desc = "TEWS TPCI200 IndustryPack carrier";
6451f9c4cfdSAndreas Färber     dc->vmsd = &vmstate_tpci200;
6461f9c4cfdSAndreas Färber }
6471f9c4cfdSAndreas Färber 
6481f9c4cfdSAndreas Färber static const TypeInfo tpci200_info = {
6491f9c4cfdSAndreas Färber     .name          = TYPE_TPCI200,
6501f9c4cfdSAndreas Färber     .parent        = TYPE_PCI_DEVICE,
6511f9c4cfdSAndreas Färber     .instance_size = sizeof(TPCI200State),
6521f9c4cfdSAndreas Färber     .class_init    = tpci200_class_init,
653fd3b02c8SEduardo Habkost     .interfaces = (InterfaceInfo[]) {
654fd3b02c8SEduardo Habkost         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
655fd3b02c8SEduardo Habkost         { },
656fd3b02c8SEduardo Habkost     },
6571f9c4cfdSAndreas Färber };
6581f9c4cfdSAndreas Färber 
tpci200_register_types(void)6591f9c4cfdSAndreas Färber static void tpci200_register_types(void)
6601f9c4cfdSAndreas Färber {
6611f9c4cfdSAndreas Färber     type_register_static(&tpci200_info);
6621f9c4cfdSAndreas Färber }
6631f9c4cfdSAndreas Färber 
6641f9c4cfdSAndreas Färber type_init(tpci200_register_types)
665