2 * QEMU PowerPC PowerNV Emulation of some SBE behaviour
4 * Copyright (c) 2022, IBM Corporation.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2, as
8 * published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 #include "qemu/osdep.h"
20 #include "target/ppc/cpu.h"
21 #include "qapi/error.h"
23 #include "qemu/module.h"
25 #include "hw/qdev-properties.h"
26 #include "hw/ppc/pnv.h"
27 #include "hw/ppc/pnv_xscom.h"
28 #include "hw/ppc/pnv_sbe.h"
32 * Most register and command definitions come from skiboot.
34 * xscom addresses are adjusted to be relative to xscom subregion bases
38 * SBE MBOX register address
39 * Reg 0 - 3 : Host to send command packets to SBE
40 * Reg 4 - 7 : SBE to send response packets to Host
42 #define PSU_HOST_SBE_MBOX_REG0 0x00000000
43 #define PSU_HOST_SBE_MBOX_REG1 0x00000001
44 #define PSU_HOST_SBE_MBOX_REG2 0x00000002
45 #define PSU_HOST_SBE_MBOX_REG3 0x00000003
46 #define PSU_HOST_SBE_MBOX_REG4 0x00000004
47 #define PSU_HOST_SBE_MBOX_REG5 0x00000005
48 #define PSU_HOST_SBE_MBOX_REG6 0x00000006
49 #define PSU_HOST_SBE_MBOX_REG7 0x00000007
50 #define PSU_SBE_DOORBELL_REG_RW 0x00000010
51 #define PSU_SBE_DOORBELL_REG_AND 0x00000011
52 #define PSU_SBE_DOORBELL_REG_OR 0x00000012
53 #define PSU_HOST_DOORBELL_REG_RW 0x00000013
54 #define PSU_HOST_DOORBELL_REG_AND 0x00000014
55 #define PSU_HOST_DOORBELL_REG_OR 0x00000015
58 * Doorbell register to trigger SBE interrupt. Set by OPAL to inform
59 * the SBE about a waiting message in the Host/SBE mailbox registers
61 #define HOST_SBE_MSG_WAITING PPC_BIT(0)
64 * Doorbell register for host bridge interrupt. Set by the SBE to inform
65 * host about a response message in the Host/SBE mailbox registers
67 #define SBE_HOST_RESPONSE_WAITING PPC_BIT(0)
68 #define SBE_HOST_MSG_READ PPC_BIT(1)
69 #define SBE_HOST_STOP15_EXIT PPC_BIT(2)
70 #define SBE_HOST_RESET PPC_BIT(3)
71 #define SBE_HOST_PASSTHROUGH PPC_BIT(4)
72 #define SBE_HOST_TIMER_EXPIRY PPC_BIT(14)
73 #define SBE_HOST_RESPONSE_MASK (PPC_BITMASK(0, 4) | \
74 SBE_HOST_TIMER_EXPIRY)
76 /* SBE Control Register */
77 #define SBE_CONTROL_REG_RW 0x00000000
79 /* SBE interrupt s0/s1 bits */
80 #define SBE_CONTROL_REG_S0 PPC_BIT(14)
81 #define SBE_CONTROL_REG_S1 PPC_BIT(15)
87 static uint64_t pnv_sbe_power9_xscom_ctrl_read(void *opaque
, hwaddr addr
,
90 uint32_t offset
= addr
>> 3;
95 qemu_log_mask(LOG_UNIMP
, "SBE Unimplemented register: Ox%"
96 HWADDR_PRIx
"\n", addr
>> 3);
99 trace_pnv_sbe_xscom_ctrl_read(addr
, val
);
104 static void pnv_sbe_power9_xscom_ctrl_write(void *opaque
, hwaddr addr
,
105 uint64_t val
, unsigned size
)
107 uint32_t offset
= addr
>> 3;
109 trace_pnv_sbe_xscom_ctrl_write(addr
, val
);
113 qemu_log_mask(LOG_UNIMP
, "SBE Unimplemented register: Ox%"
114 HWADDR_PRIx
"\n", addr
>> 3);
118 static const MemoryRegionOps pnv_sbe_power9_xscom_ctrl_ops
= {
119 .read
= pnv_sbe_power9_xscom_ctrl_read
,
120 .write
= pnv_sbe_power9_xscom_ctrl_write
,
121 .valid
.min_access_size
= 8,
122 .valid
.max_access_size
= 8,
123 .impl
.min_access_size
= 8,
124 .impl
.max_access_size
= 8,
125 .endianness
= DEVICE_BIG_ENDIAN
,
128 static void pnv_sbe_set_host_doorbell(PnvSBE
*sbe
, uint64_t val
)
130 val
&= SBE_HOST_RESPONSE_MASK
; /* Is this right? What does HW do? */
131 sbe
->host_doorbell
= val
;
133 trace_pnv_sbe_reg_set_host_doorbell(val
);
134 qemu_set_irq(sbe
->psi_irq
, !!val
);
137 /* SBE Target Type */
138 #define SBE_TARGET_TYPE_PROC 0x00
139 #define SBE_TARGET_TYPE_EX 0x01
140 #define SBE_TARGET_TYPE_PERV 0x02
141 #define SBE_TARGET_TYPE_MCS 0x03
142 #define SBE_TARGET_TYPE_EQ 0x04
143 #define SBE_TARGET_TYPE_CORE 0x05
145 /* SBE MBOX command class */
146 #define SBE_MCLASS_FIRST 0xD1
147 #define SBE_MCLASS_CORE_STATE 0xD1
148 #define SBE_MCLASS_SCOM 0xD2
149 #define SBE_MCLASS_RING 0xD3
150 #define SBE_MCLASS_TIMER 0xD4
151 #define SBE_MCLASS_MPIPL 0xD5
152 #define SBE_MCLASS_SECURITY 0xD6
153 #define SBE_MCLASS_GENERIC 0xD7
154 #define SBE_MCLASS_LAST 0xD7
157 * Commands are provided in xxyy form where:
158 * - xx : command class
161 * Both request and response message uses same seq ID,
162 * command class and command.
164 #define SBE_CMD_CTRL_DEADMAN_LOOP 0xD101
165 #define SBE_CMD_MULTI_SCOM 0xD201
166 #define SBE_CMD_PUT_RING_FORM_IMAGE 0xD301
167 #define SBE_CMD_CONTROL_TIMER 0xD401
168 #define SBE_CMD_GET_ARCHITECTED_REG 0xD501
169 #define SBE_CMD_CLR_ARCHITECTED_REG 0xD502
170 #define SBE_CMD_SET_UNSEC_MEM_WINDOW 0xD601
171 #define SBE_CMD_GET_SBE_FFDC 0xD701
172 #define SBE_CMD_GET_CAPABILITY 0xD702
173 #define SBE_CMD_READ_SBE_SEEPROM 0xD703
174 #define SBE_CMD_SET_FFDC_ADDR 0xD704
175 #define SBE_CMD_QUIESCE_SBE 0xD705
176 #define SBE_CMD_SET_FABRIC_ID_MAP 0xD706
177 #define SBE_CMD_STASH_MPIPL_CONFIG 0xD707
179 /* SBE MBOX control flags */
182 #define SBE_CMD_CTRL_RESP_REQ 0x0100
183 #define SBE_CMD_CTRL_ACK_REQ 0x0200
186 #define CTRL_DEADMAN_LOOP_START 0x0001
187 #define CTRL_DEADMAN_LOOP_STOP 0x0002
190 #define CONTROL_TIMER_START 0x0001
191 #define CONTROL_TIMER_STOP 0x0002
193 /* Stash MPIPL config */
194 #define SBE_STASH_KEY_SKIBOOT_BASE 0x03
196 static void sbe_timer(void *opaque
)
198 PnvSBE
*sbe
= opaque
;
200 trace_pnv_sbe_cmd_timer_expired();
202 pnv_sbe_set_host_doorbell(sbe
, sbe
->host_doorbell
| SBE_HOST_TIMER_EXPIRY
);
205 static void do_sbe_msg(PnvSBE
*sbe
)
208 uint16_t cmd
, ctrl_flags
, seq_id
;
211 memset(&msg
, 0, sizeof(msg
));
213 for (i
= 0; i
< 4; i
++) {
214 msg
.reg
[i
] = sbe
->mbox
[i
];
218 seq_id
= msg
.reg
[0] >> 16;
219 ctrl_flags
= msg
.reg
[0] >> 32;
221 trace_pnv_sbe_msg_recv(cmd
, seq_id
, ctrl_flags
);
223 if (ctrl_flags
& SBE_CMD_CTRL_ACK_REQ
) {
224 pnv_sbe_set_host_doorbell(sbe
, sbe
->host_doorbell
| SBE_HOST_MSG_READ
);
228 case SBE_CMD_CONTROL_TIMER
:
229 if (ctrl_flags
& CONTROL_TIMER_START
) {
230 uint64_t us
= msg
.reg
[1];
231 trace_pnv_sbe_cmd_timer_start(us
);
232 timer_mod(sbe
->timer
, qemu_clock_get_us(QEMU_CLOCK_VIRTUAL
) + us
);
234 if (ctrl_flags
& CONTROL_TIMER_STOP
) {
235 trace_pnv_sbe_cmd_timer_stop();
236 timer_del(sbe
->timer
);
240 qemu_log_mask(LOG_UNIMP
, "SBE Unimplemented command: 0x%x\n", cmd
);
244 static void pnv_sbe_set_sbe_doorbell(PnvSBE
*sbe
, uint64_t val
)
246 val
&= HOST_SBE_MSG_WAITING
;
247 sbe
->sbe_doorbell
= val
;
249 if (val
& HOST_SBE_MSG_WAITING
) {
250 sbe
->sbe_doorbell
&= ~HOST_SBE_MSG_WAITING
;
255 static uint64_t pnv_sbe_power9_xscom_mbox_read(void *opaque
, hwaddr addr
,
258 PnvSBE
*sbe
= PNV_SBE(opaque
);
259 uint32_t offset
= addr
>> 3;
262 if (offset
<= PSU_HOST_SBE_MBOX_REG7
) {
263 uint32_t idx
= offset
- PSU_HOST_SBE_MBOX_REG0
;
264 val
= sbe
->mbox
[idx
];
267 case PSU_SBE_DOORBELL_REG_RW
:
268 val
= sbe
->sbe_doorbell
;
270 case PSU_HOST_DOORBELL_REG_RW
:
271 val
= sbe
->host_doorbell
;
274 qemu_log_mask(LOG_UNIMP
, "SBE Unimplemented register: Ox%"
275 HWADDR_PRIx
"\n", addr
>> 3);
279 trace_pnv_sbe_xscom_mbox_read(addr
, val
);
284 static void pnv_sbe_power9_xscom_mbox_write(void *opaque
, hwaddr addr
,
285 uint64_t val
, unsigned size
)
287 PnvSBE
*sbe
= PNV_SBE(opaque
);
288 uint32_t offset
= addr
>> 3;
290 trace_pnv_sbe_xscom_mbox_write(addr
, val
);
292 if (offset
<= PSU_HOST_SBE_MBOX_REG7
) {
293 uint32_t idx
= offset
- PSU_HOST_SBE_MBOX_REG0
;
294 sbe
->mbox
[idx
] = val
;
297 case PSU_SBE_DOORBELL_REG_RW
:
298 pnv_sbe_set_sbe_doorbell(sbe
, val
);
300 case PSU_SBE_DOORBELL_REG_AND
:
301 pnv_sbe_set_sbe_doorbell(sbe
, sbe
->sbe_doorbell
& val
);
303 case PSU_SBE_DOORBELL_REG_OR
:
304 pnv_sbe_set_sbe_doorbell(sbe
, sbe
->sbe_doorbell
| val
);
307 case PSU_HOST_DOORBELL_REG_RW
:
308 pnv_sbe_set_host_doorbell(sbe
, val
);
310 case PSU_HOST_DOORBELL_REG_AND
:
311 pnv_sbe_set_host_doorbell(sbe
, sbe
->host_doorbell
& val
);
313 case PSU_HOST_DOORBELL_REG_OR
:
314 pnv_sbe_set_host_doorbell(sbe
, sbe
->host_doorbell
| val
);
318 qemu_log_mask(LOG_UNIMP
, "SBE Unimplemented register: Ox%"
319 HWADDR_PRIx
"\n", addr
>> 3);
324 static const MemoryRegionOps pnv_sbe_power9_xscom_mbox_ops
= {
325 .read
= pnv_sbe_power9_xscom_mbox_read
,
326 .write
= pnv_sbe_power9_xscom_mbox_write
,
327 .valid
.min_access_size
= 8,
328 .valid
.max_access_size
= 8,
329 .impl
.min_access_size
= 8,
330 .impl
.max_access_size
= 8,
331 .endianness
= DEVICE_BIG_ENDIAN
,
334 static void pnv_sbe_power9_class_init(ObjectClass
*klass
, void *data
)
336 PnvSBEClass
*psc
= PNV_SBE_CLASS(klass
);
337 DeviceClass
*dc
= DEVICE_CLASS(klass
);
339 dc
->desc
= "PowerNV SBE Controller (POWER9)";
340 psc
->xscom_ctrl_size
= PNV9_XSCOM_SBE_CTRL_SIZE
;
341 psc
->xscom_ctrl_ops
= &pnv_sbe_power9_xscom_ctrl_ops
;
342 psc
->xscom_mbox_size
= PNV9_XSCOM_SBE_MBOX_SIZE
;
343 psc
->xscom_mbox_ops
= &pnv_sbe_power9_xscom_mbox_ops
;
346 static const TypeInfo pnv_sbe_power9_type_info
= {
347 .name
= TYPE_PNV9_SBE
,
348 .parent
= TYPE_PNV_SBE
,
349 .instance_size
= sizeof(PnvSBE
),
350 .class_init
= pnv_sbe_power9_class_init
,
353 static void pnv_sbe_power10_class_init(ObjectClass
*klass
, void *data
)
355 PnvSBEClass
*psc
= PNV_SBE_CLASS(klass
);
356 DeviceClass
*dc
= DEVICE_CLASS(klass
);
358 dc
->desc
= "PowerNV SBE Controller (POWER10)";
359 psc
->xscom_ctrl_size
= PNV10_XSCOM_SBE_CTRL_SIZE
;
360 psc
->xscom_ctrl_ops
= &pnv_sbe_power9_xscom_ctrl_ops
;
361 psc
->xscom_mbox_size
= PNV10_XSCOM_SBE_MBOX_SIZE
;
362 psc
->xscom_mbox_ops
= &pnv_sbe_power9_xscom_mbox_ops
;
365 static const TypeInfo pnv_sbe_power10_type_info
= {
366 .name
= TYPE_PNV10_SBE
,
367 .parent
= TYPE_PNV9_SBE
,
368 .class_init
= pnv_sbe_power10_class_init
,
371 static void pnv_sbe_realize(DeviceState
*dev
, Error
**errp
)
373 PnvSBE
*sbe
= PNV_SBE(dev
);
374 PnvSBEClass
*psc
= PNV_SBE_GET_CLASS(sbe
);
376 /* XScom regions for SBE registers */
377 pnv_xscom_region_init(&sbe
->xscom_ctrl_regs
, OBJECT(dev
),
378 psc
->xscom_ctrl_ops
, sbe
, "xscom-sbe-ctrl",
379 psc
->xscom_ctrl_size
);
380 pnv_xscom_region_init(&sbe
->xscom_mbox_regs
, OBJECT(dev
),
381 psc
->xscom_mbox_ops
, sbe
, "xscom-sbe-mbox",
382 psc
->xscom_mbox_size
);
384 qdev_init_gpio_out(DEVICE(dev
), &sbe
->psi_irq
, 1);
386 sbe
->timer
= timer_new_us(QEMU_CLOCK_VIRTUAL
, sbe_timer
, sbe
);
389 static void pnv_sbe_class_init(ObjectClass
*klass
, void *data
)
391 DeviceClass
*dc
= DEVICE_CLASS(klass
);
393 dc
->realize
= pnv_sbe_realize
;
394 dc
->desc
= "PowerNV SBE Controller";
395 dc
->user_creatable
= false;
398 static const TypeInfo pnv_sbe_type_info
= {
399 .name
= TYPE_PNV_SBE
,
400 .parent
= TYPE_DEVICE
,
401 .instance_size
= sizeof(PnvSBE
),
402 .class_init
= pnv_sbe_class_init
,
403 .class_size
= sizeof(PnvSBEClass
),
407 static void pnv_sbe_register_types(void)
409 type_register_static(&pnv_sbe_type_info
);
410 type_register_static(&pnv_sbe_power9_type_info
);
411 type_register_static(&pnv_sbe_power10_type_info
);
414 type_init(pnv_sbe_register_types
);