xref: /openbmc/qemu/hw/ppc/pnv_sbe.c (revision 7d5b0d68)
10bf4d77eSNicholas Piggin /*
20bf4d77eSNicholas Piggin  * QEMU PowerPC PowerNV Emulation of some SBE behaviour
30bf4d77eSNicholas Piggin  *
40bf4d77eSNicholas Piggin  * Copyright (c) 2022, IBM Corporation.
50bf4d77eSNicholas Piggin  *
60bf4d77eSNicholas Piggin  * This program is free software; you can redistribute it and/or modify
70bf4d77eSNicholas Piggin  * it under the terms of the GNU General Public License, version 2, as
80bf4d77eSNicholas Piggin  * published by the Free Software Foundation.
90bf4d77eSNicholas Piggin  *
100bf4d77eSNicholas Piggin  * This program is distributed in the hope that it will be useful,
110bf4d77eSNicholas Piggin  * but WITHOUT ANY WARRANTY; without even the implied warranty of
120bf4d77eSNicholas Piggin  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
130bf4d77eSNicholas Piggin  * GNU General Public License for more details.
140bf4d77eSNicholas Piggin  *
150bf4d77eSNicholas Piggin  * You should have received a copy of the GNU General Public License
160bf4d77eSNicholas Piggin  * along with this program; if not, see <http://www.gnu.org/licenses/>.
170bf4d77eSNicholas Piggin  */
180bf4d77eSNicholas Piggin 
190bf4d77eSNicholas Piggin #include "qemu/osdep.h"
200bf4d77eSNicholas Piggin #include "target/ppc/cpu.h"
210bf4d77eSNicholas Piggin #include "qapi/error.h"
220bf4d77eSNicholas Piggin #include "qemu/log.h"
230bf4d77eSNicholas Piggin #include "qemu/module.h"
240bf4d77eSNicholas Piggin #include "hw/irq.h"
250bf4d77eSNicholas Piggin #include "hw/qdev-properties.h"
260bf4d77eSNicholas Piggin #include "hw/ppc/pnv.h"
270bf4d77eSNicholas Piggin #include "hw/ppc/pnv_xscom.h"
280bf4d77eSNicholas Piggin #include "hw/ppc/pnv_sbe.h"
290bf4d77eSNicholas Piggin #include "trace.h"
300bf4d77eSNicholas Piggin 
310bf4d77eSNicholas Piggin /*
320bf4d77eSNicholas Piggin  * Most register and command definitions come from skiboot.
330bf4d77eSNicholas Piggin  *
340bf4d77eSNicholas Piggin  * xscom addresses are adjusted to be relative to xscom subregion bases
350bf4d77eSNicholas Piggin  */
360bf4d77eSNicholas Piggin 
370bf4d77eSNicholas Piggin /*
380bf4d77eSNicholas Piggin  * SBE MBOX register address
390bf4d77eSNicholas Piggin  *   Reg 0 - 3 : Host to send command packets to SBE
400bf4d77eSNicholas Piggin  *   Reg 4 - 7 : SBE to send response packets to Host
410bf4d77eSNicholas Piggin  */
420bf4d77eSNicholas Piggin #define PSU_HOST_SBE_MBOX_REG0          0x00000000
430bf4d77eSNicholas Piggin #define PSU_HOST_SBE_MBOX_REG1          0x00000001
440bf4d77eSNicholas Piggin #define PSU_HOST_SBE_MBOX_REG2          0x00000002
450bf4d77eSNicholas Piggin #define PSU_HOST_SBE_MBOX_REG3          0x00000003
460bf4d77eSNicholas Piggin #define PSU_HOST_SBE_MBOX_REG4          0x00000004
470bf4d77eSNicholas Piggin #define PSU_HOST_SBE_MBOX_REG5          0x00000005
480bf4d77eSNicholas Piggin #define PSU_HOST_SBE_MBOX_REG6          0x00000006
490bf4d77eSNicholas Piggin #define PSU_HOST_SBE_MBOX_REG7          0x00000007
500bf4d77eSNicholas Piggin #define PSU_SBE_DOORBELL_REG_RW         0x00000010
510bf4d77eSNicholas Piggin #define PSU_SBE_DOORBELL_REG_AND        0x00000011
520bf4d77eSNicholas Piggin #define PSU_SBE_DOORBELL_REG_OR         0x00000012
530bf4d77eSNicholas Piggin #define PSU_HOST_DOORBELL_REG_RW        0x00000013
540bf4d77eSNicholas Piggin #define PSU_HOST_DOORBELL_REG_AND       0x00000014
550bf4d77eSNicholas Piggin #define PSU_HOST_DOORBELL_REG_OR        0x00000015
560bf4d77eSNicholas Piggin 
570bf4d77eSNicholas Piggin /*
580bf4d77eSNicholas Piggin  * Doorbell register to trigger SBE interrupt. Set by OPAL to inform
590bf4d77eSNicholas Piggin  * the SBE about a waiting message in the Host/SBE mailbox registers
600bf4d77eSNicholas Piggin  */
610bf4d77eSNicholas Piggin #define HOST_SBE_MSG_WAITING            PPC_BIT(0)
620bf4d77eSNicholas Piggin 
630bf4d77eSNicholas Piggin /*
640bf4d77eSNicholas Piggin  * Doorbell register for host bridge interrupt. Set by the SBE to inform
650bf4d77eSNicholas Piggin  * host about a response message in the Host/SBE mailbox registers
660bf4d77eSNicholas Piggin  */
670bf4d77eSNicholas Piggin #define SBE_HOST_RESPONSE_WAITING       PPC_BIT(0)
680bf4d77eSNicholas Piggin #define SBE_HOST_MSG_READ               PPC_BIT(1)
690bf4d77eSNicholas Piggin #define SBE_HOST_STOP15_EXIT            PPC_BIT(2)
700bf4d77eSNicholas Piggin #define SBE_HOST_RESET                  PPC_BIT(3)
710bf4d77eSNicholas Piggin #define SBE_HOST_PASSTHROUGH            PPC_BIT(4)
720bf4d77eSNicholas Piggin #define SBE_HOST_TIMER_EXPIRY           PPC_BIT(14)
730bf4d77eSNicholas Piggin #define SBE_HOST_RESPONSE_MASK          (PPC_BITMASK(0, 4) | \
740bf4d77eSNicholas Piggin                                          SBE_HOST_TIMER_EXPIRY)
750bf4d77eSNicholas Piggin 
760bf4d77eSNicholas Piggin /* SBE Control Register */
770bf4d77eSNicholas Piggin #define SBE_CONTROL_REG_RW              0x00000000
780bf4d77eSNicholas Piggin 
790bf4d77eSNicholas Piggin /* SBE interrupt s0/s1 bits */
800bf4d77eSNicholas Piggin #define SBE_CONTROL_REG_S0              PPC_BIT(14)
810bf4d77eSNicholas Piggin #define SBE_CONTROL_REG_S1              PPC_BIT(15)
820bf4d77eSNicholas Piggin 
830bf4d77eSNicholas Piggin struct sbe_msg {
840bf4d77eSNicholas Piggin     uint64_t reg[4];
850bf4d77eSNicholas Piggin };
860bf4d77eSNicholas Piggin 
pnv_sbe_power9_xscom_ctrl_read(void * opaque,hwaddr addr,unsigned size)870bf4d77eSNicholas Piggin static uint64_t pnv_sbe_power9_xscom_ctrl_read(void *opaque, hwaddr addr,
880bf4d77eSNicholas Piggin                                           unsigned size)
890bf4d77eSNicholas Piggin {
900bf4d77eSNicholas Piggin     uint32_t offset = addr >> 3;
910bf4d77eSNicholas Piggin     uint64_t val = 0;
920bf4d77eSNicholas Piggin 
930bf4d77eSNicholas Piggin     switch (offset) {
940bf4d77eSNicholas Piggin     default:
950bf4d77eSNicholas Piggin         qemu_log_mask(LOG_UNIMP, "SBE Unimplemented register: Ox%"
960bf4d77eSNicholas Piggin                       HWADDR_PRIx "\n", addr >> 3);
970bf4d77eSNicholas Piggin     }
980bf4d77eSNicholas Piggin 
990bf4d77eSNicholas Piggin     trace_pnv_sbe_xscom_ctrl_read(addr, val);
1000bf4d77eSNicholas Piggin 
1010bf4d77eSNicholas Piggin     return val;
1020bf4d77eSNicholas Piggin }
1030bf4d77eSNicholas Piggin 
pnv_sbe_power9_xscom_ctrl_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)1040bf4d77eSNicholas Piggin static void pnv_sbe_power9_xscom_ctrl_write(void *opaque, hwaddr addr,
1050bf4d77eSNicholas Piggin                                        uint64_t val, unsigned size)
1060bf4d77eSNicholas Piggin {
1070bf4d77eSNicholas Piggin     uint32_t offset = addr >> 3;
1080bf4d77eSNicholas Piggin 
1090bf4d77eSNicholas Piggin     trace_pnv_sbe_xscom_ctrl_write(addr, val);
1100bf4d77eSNicholas Piggin 
1110bf4d77eSNicholas Piggin     switch (offset) {
1120bf4d77eSNicholas Piggin     default:
1130bf4d77eSNicholas Piggin         qemu_log_mask(LOG_UNIMP, "SBE Unimplemented register: Ox%"
1140bf4d77eSNicholas Piggin                       HWADDR_PRIx "\n", addr >> 3);
1150bf4d77eSNicholas Piggin     }
1160bf4d77eSNicholas Piggin }
1170bf4d77eSNicholas Piggin 
1180bf4d77eSNicholas Piggin static const MemoryRegionOps pnv_sbe_power9_xscom_ctrl_ops = {
1190bf4d77eSNicholas Piggin     .read = pnv_sbe_power9_xscom_ctrl_read,
1200bf4d77eSNicholas Piggin     .write = pnv_sbe_power9_xscom_ctrl_write,
1210bf4d77eSNicholas Piggin     .valid.min_access_size = 8,
1220bf4d77eSNicholas Piggin     .valid.max_access_size = 8,
1230bf4d77eSNicholas Piggin     .impl.min_access_size = 8,
1240bf4d77eSNicholas Piggin     .impl.max_access_size = 8,
1250bf4d77eSNicholas Piggin     .endianness = DEVICE_BIG_ENDIAN,
1260bf4d77eSNicholas Piggin };
1270bf4d77eSNicholas Piggin 
pnv_sbe_set_host_doorbell(PnvSBE * sbe,uint64_t val)1280bf4d77eSNicholas Piggin static void pnv_sbe_set_host_doorbell(PnvSBE *sbe, uint64_t val)
1290bf4d77eSNicholas Piggin {
1300bf4d77eSNicholas Piggin     val &= SBE_HOST_RESPONSE_MASK; /* Is this right? What does HW do? */
1310bf4d77eSNicholas Piggin     sbe->host_doorbell = val;
1320bf4d77eSNicholas Piggin 
1330bf4d77eSNicholas Piggin     trace_pnv_sbe_reg_set_host_doorbell(val);
1340bf4d77eSNicholas Piggin     qemu_set_irq(sbe->psi_irq, !!val);
1350bf4d77eSNicholas Piggin }
1360bf4d77eSNicholas Piggin 
1370bf4d77eSNicholas Piggin /* SBE Target Type */
1380bf4d77eSNicholas Piggin #define SBE_TARGET_TYPE_PROC            0x00
1390bf4d77eSNicholas Piggin #define SBE_TARGET_TYPE_EX              0x01
1400bf4d77eSNicholas Piggin #define SBE_TARGET_TYPE_PERV            0x02
1410bf4d77eSNicholas Piggin #define SBE_TARGET_TYPE_MCS             0x03
1420bf4d77eSNicholas Piggin #define SBE_TARGET_TYPE_EQ              0x04
1430bf4d77eSNicholas Piggin #define SBE_TARGET_TYPE_CORE            0x05
1440bf4d77eSNicholas Piggin 
1450bf4d77eSNicholas Piggin /* SBE MBOX command class */
1460bf4d77eSNicholas Piggin #define SBE_MCLASS_FIRST                0xD1
1470bf4d77eSNicholas Piggin #define SBE_MCLASS_CORE_STATE           0xD1
1480bf4d77eSNicholas Piggin #define SBE_MCLASS_SCOM                 0xD2
1490bf4d77eSNicholas Piggin #define SBE_MCLASS_RING                 0xD3
1500bf4d77eSNicholas Piggin #define SBE_MCLASS_TIMER                0xD4
1510bf4d77eSNicholas Piggin #define SBE_MCLASS_MPIPL                0xD5
1520bf4d77eSNicholas Piggin #define SBE_MCLASS_SECURITY             0xD6
1530bf4d77eSNicholas Piggin #define SBE_MCLASS_GENERIC              0xD7
1540bf4d77eSNicholas Piggin #define SBE_MCLASS_LAST                 0xD7
1550bf4d77eSNicholas Piggin 
1560bf4d77eSNicholas Piggin /*
1570bf4d77eSNicholas Piggin  * Commands are provided in xxyy form where:
1580bf4d77eSNicholas Piggin  *   - xx : command class
1590bf4d77eSNicholas Piggin  *   - yy : command
1600bf4d77eSNicholas Piggin  *
1610bf4d77eSNicholas Piggin  * Both request and response message uses same seq ID,
1620bf4d77eSNicholas Piggin  * command class and command.
1630bf4d77eSNicholas Piggin  */
1640bf4d77eSNicholas Piggin #define SBE_CMD_CTRL_DEADMAN_LOOP       0xD101
1650bf4d77eSNicholas Piggin #define SBE_CMD_MULTI_SCOM              0xD201
1660bf4d77eSNicholas Piggin #define SBE_CMD_PUT_RING_FORM_IMAGE     0xD301
1670bf4d77eSNicholas Piggin #define SBE_CMD_CONTROL_TIMER           0xD401
1680bf4d77eSNicholas Piggin #define SBE_CMD_GET_ARCHITECTED_REG     0xD501
1690bf4d77eSNicholas Piggin #define SBE_CMD_CLR_ARCHITECTED_REG     0xD502
1700bf4d77eSNicholas Piggin #define SBE_CMD_SET_UNSEC_MEM_WINDOW    0xD601
1710bf4d77eSNicholas Piggin #define SBE_CMD_GET_SBE_FFDC            0xD701
1720bf4d77eSNicholas Piggin #define SBE_CMD_GET_CAPABILITY          0xD702
1730bf4d77eSNicholas Piggin #define SBE_CMD_READ_SBE_SEEPROM        0xD703
1740bf4d77eSNicholas Piggin #define SBE_CMD_SET_FFDC_ADDR           0xD704
1750bf4d77eSNicholas Piggin #define SBE_CMD_QUIESCE_SBE             0xD705
1760bf4d77eSNicholas Piggin #define SBE_CMD_SET_FABRIC_ID_MAP       0xD706
1770bf4d77eSNicholas Piggin #define SBE_CMD_STASH_MPIPL_CONFIG      0xD707
1780bf4d77eSNicholas Piggin 
1790bf4d77eSNicholas Piggin /* SBE MBOX control flags */
1800bf4d77eSNicholas Piggin 
1810bf4d77eSNicholas Piggin /* Generic flags */
1820bf4d77eSNicholas Piggin #define SBE_CMD_CTRL_RESP_REQ           0x0100
1830bf4d77eSNicholas Piggin #define SBE_CMD_CTRL_ACK_REQ            0x0200
1840bf4d77eSNicholas Piggin 
1850bf4d77eSNicholas Piggin /* Deadman loop */
1860bf4d77eSNicholas Piggin #define CTRL_DEADMAN_LOOP_START         0x0001
1870bf4d77eSNicholas Piggin #define CTRL_DEADMAN_LOOP_STOP          0x0002
1880bf4d77eSNicholas Piggin 
1890bf4d77eSNicholas Piggin /* Control timer */
1900bf4d77eSNicholas Piggin #define CONTROL_TIMER_START             0x0001
1910bf4d77eSNicholas Piggin #define CONTROL_TIMER_STOP              0x0002
1920bf4d77eSNicholas Piggin 
1930bf4d77eSNicholas Piggin /* Stash MPIPL config */
1940bf4d77eSNicholas Piggin #define SBE_STASH_KEY_SKIBOOT_BASE      0x03
1950bf4d77eSNicholas Piggin 
sbe_timer(void * opaque)1960bf4d77eSNicholas Piggin static void sbe_timer(void *opaque)
1970bf4d77eSNicholas Piggin {
1980bf4d77eSNicholas Piggin     PnvSBE *sbe = opaque;
1990bf4d77eSNicholas Piggin 
2000bf4d77eSNicholas Piggin     trace_pnv_sbe_cmd_timer_expired();
2010bf4d77eSNicholas Piggin 
2020bf4d77eSNicholas Piggin     pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell | SBE_HOST_TIMER_EXPIRY);
2030bf4d77eSNicholas Piggin }
2040bf4d77eSNicholas Piggin 
do_sbe_msg(PnvSBE * sbe)2050bf4d77eSNicholas Piggin static void do_sbe_msg(PnvSBE *sbe)
2060bf4d77eSNicholas Piggin {
2070bf4d77eSNicholas Piggin     struct sbe_msg msg;
2080bf4d77eSNicholas Piggin     uint16_t cmd, ctrl_flags, seq_id;
2090bf4d77eSNicholas Piggin     int i;
2100bf4d77eSNicholas Piggin 
2110bf4d77eSNicholas Piggin     memset(&msg, 0, sizeof(msg));
2120bf4d77eSNicholas Piggin 
2130bf4d77eSNicholas Piggin     for (i = 0; i < 4; i++) {
2140bf4d77eSNicholas Piggin         msg.reg[i] = sbe->mbox[i];
2150bf4d77eSNicholas Piggin     }
2160bf4d77eSNicholas Piggin 
2170bf4d77eSNicholas Piggin     cmd = msg.reg[0];
2180bf4d77eSNicholas Piggin     seq_id = msg.reg[0] >> 16;
2190bf4d77eSNicholas Piggin     ctrl_flags = msg.reg[0] >> 32;
2200bf4d77eSNicholas Piggin 
2210bf4d77eSNicholas Piggin     trace_pnv_sbe_msg_recv(cmd, seq_id, ctrl_flags);
2220bf4d77eSNicholas Piggin 
2230bf4d77eSNicholas Piggin     if (ctrl_flags & SBE_CMD_CTRL_ACK_REQ) {
2240bf4d77eSNicholas Piggin         pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell | SBE_HOST_MSG_READ);
2250bf4d77eSNicholas Piggin     }
2260bf4d77eSNicholas Piggin 
2270bf4d77eSNicholas Piggin     switch (cmd) {
2280bf4d77eSNicholas Piggin     case SBE_CMD_CONTROL_TIMER:
2290bf4d77eSNicholas Piggin         if (ctrl_flags & CONTROL_TIMER_START) {
2300bf4d77eSNicholas Piggin             uint64_t us = msg.reg[1];
2310bf4d77eSNicholas Piggin             trace_pnv_sbe_cmd_timer_start(us);
2320bf4d77eSNicholas Piggin             timer_mod(sbe->timer, qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + us);
2330bf4d77eSNicholas Piggin         }
2340bf4d77eSNicholas Piggin         if (ctrl_flags & CONTROL_TIMER_STOP) {
2350bf4d77eSNicholas Piggin             trace_pnv_sbe_cmd_timer_stop();
2360bf4d77eSNicholas Piggin             timer_del(sbe->timer);
2370bf4d77eSNicholas Piggin         }
2380bf4d77eSNicholas Piggin         break;
2390bf4d77eSNicholas Piggin     default:
2400bf4d77eSNicholas Piggin         qemu_log_mask(LOG_UNIMP, "SBE Unimplemented command: 0x%x\n", cmd);
2410bf4d77eSNicholas Piggin     }
2420bf4d77eSNicholas Piggin }
2430bf4d77eSNicholas Piggin 
pnv_sbe_set_sbe_doorbell(PnvSBE * sbe,uint64_t val)2440bf4d77eSNicholas Piggin static void pnv_sbe_set_sbe_doorbell(PnvSBE *sbe, uint64_t val)
2450bf4d77eSNicholas Piggin {
2460bf4d77eSNicholas Piggin     val &= HOST_SBE_MSG_WAITING;
2470bf4d77eSNicholas Piggin     sbe->sbe_doorbell = val;
2480bf4d77eSNicholas Piggin 
2490bf4d77eSNicholas Piggin     if (val & HOST_SBE_MSG_WAITING) {
2500bf4d77eSNicholas Piggin         sbe->sbe_doorbell &= ~HOST_SBE_MSG_WAITING;
2510bf4d77eSNicholas Piggin         do_sbe_msg(sbe);
2520bf4d77eSNicholas Piggin     }
2530bf4d77eSNicholas Piggin }
2540bf4d77eSNicholas Piggin 
pnv_sbe_power9_xscom_mbox_read(void * opaque,hwaddr addr,unsigned size)2550bf4d77eSNicholas Piggin static uint64_t pnv_sbe_power9_xscom_mbox_read(void *opaque, hwaddr addr,
2560bf4d77eSNicholas Piggin                                           unsigned size)
2570bf4d77eSNicholas Piggin {
2580bf4d77eSNicholas Piggin     PnvSBE *sbe = PNV_SBE(opaque);
2590bf4d77eSNicholas Piggin     uint32_t offset = addr >> 3;
2600bf4d77eSNicholas Piggin     uint64_t val = 0;
2610bf4d77eSNicholas Piggin 
2620bf4d77eSNicholas Piggin     if (offset <= PSU_HOST_SBE_MBOX_REG7) {
2630bf4d77eSNicholas Piggin         uint32_t idx = offset - PSU_HOST_SBE_MBOX_REG0;
2640bf4d77eSNicholas Piggin         val = sbe->mbox[idx];
2650bf4d77eSNicholas Piggin     } else {
2660bf4d77eSNicholas Piggin         switch (offset) {
2670bf4d77eSNicholas Piggin         case PSU_SBE_DOORBELL_REG_RW:
2680bf4d77eSNicholas Piggin             val = sbe->sbe_doorbell;
2690bf4d77eSNicholas Piggin             break;
2700bf4d77eSNicholas Piggin         case PSU_HOST_DOORBELL_REG_RW:
2710bf4d77eSNicholas Piggin             val = sbe->host_doorbell;
2720bf4d77eSNicholas Piggin             break;
2730bf4d77eSNicholas Piggin         default:
2740bf4d77eSNicholas Piggin             qemu_log_mask(LOG_UNIMP, "SBE Unimplemented register: Ox%"
2750bf4d77eSNicholas Piggin                           HWADDR_PRIx "\n", addr >> 3);
2760bf4d77eSNicholas Piggin         }
2770bf4d77eSNicholas Piggin     }
2780bf4d77eSNicholas Piggin 
2790bf4d77eSNicholas Piggin     trace_pnv_sbe_xscom_mbox_read(addr, val);
2800bf4d77eSNicholas Piggin 
2810bf4d77eSNicholas Piggin     return val;
2820bf4d77eSNicholas Piggin }
2830bf4d77eSNicholas Piggin 
pnv_sbe_power9_xscom_mbox_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)2840bf4d77eSNicholas Piggin static void pnv_sbe_power9_xscom_mbox_write(void *opaque, hwaddr addr,
2850bf4d77eSNicholas Piggin                                        uint64_t val, unsigned size)
2860bf4d77eSNicholas Piggin {
2870bf4d77eSNicholas Piggin     PnvSBE *sbe = PNV_SBE(opaque);
2880bf4d77eSNicholas Piggin     uint32_t offset = addr >> 3;
2890bf4d77eSNicholas Piggin 
2900bf4d77eSNicholas Piggin     trace_pnv_sbe_xscom_mbox_write(addr, val);
2910bf4d77eSNicholas Piggin 
2920bf4d77eSNicholas Piggin     if (offset <= PSU_HOST_SBE_MBOX_REG7) {
2930bf4d77eSNicholas Piggin         uint32_t idx = offset - PSU_HOST_SBE_MBOX_REG0;
2940bf4d77eSNicholas Piggin         sbe->mbox[idx] = val;
2950bf4d77eSNicholas Piggin     } else {
2960bf4d77eSNicholas Piggin         switch (offset) {
2970bf4d77eSNicholas Piggin         case PSU_SBE_DOORBELL_REG_RW:
2980bf4d77eSNicholas Piggin             pnv_sbe_set_sbe_doorbell(sbe, val);
2990bf4d77eSNicholas Piggin             break;
3000bf4d77eSNicholas Piggin         case PSU_SBE_DOORBELL_REG_AND:
3010bf4d77eSNicholas Piggin             pnv_sbe_set_sbe_doorbell(sbe, sbe->sbe_doorbell & val);
3020bf4d77eSNicholas Piggin             break;
3030bf4d77eSNicholas Piggin         case PSU_SBE_DOORBELL_REG_OR:
3040bf4d77eSNicholas Piggin             pnv_sbe_set_sbe_doorbell(sbe, sbe->sbe_doorbell | val);
3050bf4d77eSNicholas Piggin             break;
3060bf4d77eSNicholas Piggin 
3070bf4d77eSNicholas Piggin         case PSU_HOST_DOORBELL_REG_RW:
3080bf4d77eSNicholas Piggin             pnv_sbe_set_host_doorbell(sbe, val);
3090bf4d77eSNicholas Piggin             break;
3100bf4d77eSNicholas Piggin         case PSU_HOST_DOORBELL_REG_AND:
3110bf4d77eSNicholas Piggin             pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell & val);
3120bf4d77eSNicholas Piggin             break;
3130bf4d77eSNicholas Piggin         case PSU_HOST_DOORBELL_REG_OR:
3140bf4d77eSNicholas Piggin             pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell | val);
3150bf4d77eSNicholas Piggin             break;
3160bf4d77eSNicholas Piggin 
3170bf4d77eSNicholas Piggin         default:
3180bf4d77eSNicholas Piggin             qemu_log_mask(LOG_UNIMP, "SBE Unimplemented register: Ox%"
3190bf4d77eSNicholas Piggin                           HWADDR_PRIx "\n", addr >> 3);
3200bf4d77eSNicholas Piggin         }
3210bf4d77eSNicholas Piggin     }
3220bf4d77eSNicholas Piggin }
3230bf4d77eSNicholas Piggin 
3240bf4d77eSNicholas Piggin static const MemoryRegionOps pnv_sbe_power9_xscom_mbox_ops = {
3250bf4d77eSNicholas Piggin     .read = pnv_sbe_power9_xscom_mbox_read,
3260bf4d77eSNicholas Piggin     .write = pnv_sbe_power9_xscom_mbox_write,
3270bf4d77eSNicholas Piggin     .valid.min_access_size = 8,
3280bf4d77eSNicholas Piggin     .valid.max_access_size = 8,
3290bf4d77eSNicholas Piggin     .impl.min_access_size = 8,
3300bf4d77eSNicholas Piggin     .impl.max_access_size = 8,
3310bf4d77eSNicholas Piggin     .endianness = DEVICE_BIG_ENDIAN,
3320bf4d77eSNicholas Piggin };
3330bf4d77eSNicholas Piggin 
pnv_sbe_power9_class_init(ObjectClass * klass,void * data)3340bf4d77eSNicholas Piggin static void pnv_sbe_power9_class_init(ObjectClass *klass, void *data)
3350bf4d77eSNicholas Piggin {
3360bf4d77eSNicholas Piggin     PnvSBEClass *psc = PNV_SBE_CLASS(klass);
3370bf4d77eSNicholas Piggin     DeviceClass *dc = DEVICE_CLASS(klass);
3380bf4d77eSNicholas Piggin 
3390bf4d77eSNicholas Piggin     dc->desc = "PowerNV SBE Controller (POWER9)";
3400bf4d77eSNicholas Piggin     psc->xscom_ctrl_size = PNV9_XSCOM_SBE_CTRL_SIZE;
3410bf4d77eSNicholas Piggin     psc->xscom_ctrl_ops = &pnv_sbe_power9_xscom_ctrl_ops;
3420bf4d77eSNicholas Piggin     psc->xscom_mbox_size = PNV9_XSCOM_SBE_MBOX_SIZE;
3430bf4d77eSNicholas Piggin     psc->xscom_mbox_ops = &pnv_sbe_power9_xscom_mbox_ops;
3440bf4d77eSNicholas Piggin }
3450bf4d77eSNicholas Piggin 
3460bf4d77eSNicholas Piggin static const TypeInfo pnv_sbe_power9_type_info = {
3470bf4d77eSNicholas Piggin     .name          = TYPE_PNV9_SBE,
3480bf4d77eSNicholas Piggin     .parent        = TYPE_PNV_SBE,
3490bf4d77eSNicholas Piggin     .instance_size = sizeof(PnvSBE),
3500bf4d77eSNicholas Piggin     .class_init    = pnv_sbe_power9_class_init,
3510bf4d77eSNicholas Piggin };
3520bf4d77eSNicholas Piggin 
pnv_sbe_power10_class_init(ObjectClass * klass,void * data)3530bf4d77eSNicholas Piggin static void pnv_sbe_power10_class_init(ObjectClass *klass, void *data)
3540bf4d77eSNicholas Piggin {
3550bf4d77eSNicholas Piggin     PnvSBEClass *psc = PNV_SBE_CLASS(klass);
3560bf4d77eSNicholas Piggin     DeviceClass *dc = DEVICE_CLASS(klass);
3570bf4d77eSNicholas Piggin 
3580bf4d77eSNicholas Piggin     dc->desc = "PowerNV SBE Controller (POWER10)";
3590bf4d77eSNicholas Piggin     psc->xscom_ctrl_size = PNV10_XSCOM_SBE_CTRL_SIZE;
3600bf4d77eSNicholas Piggin     psc->xscom_ctrl_ops = &pnv_sbe_power9_xscom_ctrl_ops;
3610bf4d77eSNicholas Piggin     psc->xscom_mbox_size = PNV10_XSCOM_SBE_MBOX_SIZE;
3620bf4d77eSNicholas Piggin     psc->xscom_mbox_ops = &pnv_sbe_power9_xscom_mbox_ops;
3630bf4d77eSNicholas Piggin }
3640bf4d77eSNicholas Piggin 
3650bf4d77eSNicholas Piggin static const TypeInfo pnv_sbe_power10_type_info = {
3660bf4d77eSNicholas Piggin     .name          = TYPE_PNV10_SBE,
3670bf4d77eSNicholas Piggin     .parent        = TYPE_PNV9_SBE,
3680bf4d77eSNicholas Piggin     .class_init    = pnv_sbe_power10_class_init,
3690bf4d77eSNicholas Piggin };
3700bf4d77eSNicholas Piggin 
pnv_sbe_realize(DeviceState * dev,Error ** errp)3710bf4d77eSNicholas Piggin static void pnv_sbe_realize(DeviceState *dev, Error **errp)
3720bf4d77eSNicholas Piggin {
3730bf4d77eSNicholas Piggin     PnvSBE *sbe = PNV_SBE(dev);
3740bf4d77eSNicholas Piggin     PnvSBEClass *psc = PNV_SBE_GET_CLASS(sbe);
3750bf4d77eSNicholas Piggin 
3760bf4d77eSNicholas Piggin     /* XScom regions for SBE registers */
3770bf4d77eSNicholas Piggin     pnv_xscom_region_init(&sbe->xscom_ctrl_regs, OBJECT(dev),
3780bf4d77eSNicholas Piggin                           psc->xscom_ctrl_ops, sbe, "xscom-sbe-ctrl",
3790bf4d77eSNicholas Piggin                           psc->xscom_ctrl_size);
3800bf4d77eSNicholas Piggin     pnv_xscom_region_init(&sbe->xscom_mbox_regs, OBJECT(dev),
3810bf4d77eSNicholas Piggin                           psc->xscom_mbox_ops, sbe, "xscom-sbe-mbox",
3820bf4d77eSNicholas Piggin                           psc->xscom_mbox_size);
3830bf4d77eSNicholas Piggin 
384*7d5b0d68SPhilippe Mathieu-Daudé     qdev_init_gpio_out(dev, &sbe->psi_irq, 1);
3850bf4d77eSNicholas Piggin 
3860bf4d77eSNicholas Piggin     sbe->timer = timer_new_us(QEMU_CLOCK_VIRTUAL, sbe_timer, sbe);
3870bf4d77eSNicholas Piggin }
3880bf4d77eSNicholas Piggin 
pnv_sbe_class_init(ObjectClass * klass,void * data)3890bf4d77eSNicholas Piggin static void pnv_sbe_class_init(ObjectClass *klass, void *data)
3900bf4d77eSNicholas Piggin {
3910bf4d77eSNicholas Piggin     DeviceClass *dc = DEVICE_CLASS(klass);
3920bf4d77eSNicholas Piggin 
3930bf4d77eSNicholas Piggin     dc->realize = pnv_sbe_realize;
3940bf4d77eSNicholas Piggin     dc->desc = "PowerNV SBE Controller";
3950bf4d77eSNicholas Piggin     dc->user_creatable = false;
3960bf4d77eSNicholas Piggin }
3970bf4d77eSNicholas Piggin 
3980bf4d77eSNicholas Piggin static const TypeInfo pnv_sbe_type_info = {
3990bf4d77eSNicholas Piggin     .name          = TYPE_PNV_SBE,
4000bf4d77eSNicholas Piggin     .parent        = TYPE_DEVICE,
4010bf4d77eSNicholas Piggin     .instance_size = sizeof(PnvSBE),
4020bf4d77eSNicholas Piggin     .class_init    = pnv_sbe_class_init,
4030bf4d77eSNicholas Piggin     .class_size    = sizeof(PnvSBEClass),
4040bf4d77eSNicholas Piggin     .abstract      = true,
4050bf4d77eSNicholas Piggin };
4060bf4d77eSNicholas Piggin 
pnv_sbe_register_types(void)4070bf4d77eSNicholas Piggin static void pnv_sbe_register_types(void)
4080bf4d77eSNicholas Piggin {
4090bf4d77eSNicholas Piggin     type_register_static(&pnv_sbe_type_info);
4100bf4d77eSNicholas Piggin     type_register_static(&pnv_sbe_power9_type_info);
4110bf4d77eSNicholas Piggin     type_register_static(&pnv_sbe_power10_type_info);
4120bf4d77eSNicholas Piggin }
4130bf4d77eSNicholas Piggin 
4140bf4d77eSNicholas Piggin type_init(pnv_sbe_register_types);
415