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