hw/arm/xlnx-zynqmp: Remove 'hw/arm/boot.h' from header
[qemu/ar7.git] / hw / ppc / pnv_sbe.c
blob74cee4eea7ad5d6e32773e564e7a5d4a9cea114d
1 /*
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"
22 #include "qemu/log.h"
23 #include "qemu/module.h"
24 #include "hw/irq.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"
29 #include "trace.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)
83 struct sbe_msg {
84 uint64_t reg[4];
87 static uint64_t pnv_sbe_power9_xscom_ctrl_read(void *opaque, hwaddr addr,
88 unsigned size)
90 uint32_t offset = addr >> 3;
91 uint64_t val = 0;
93 switch (offset) {
94 default:
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);
101 return 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);
111 switch (offset) {
112 default:
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
159 * - yy : command
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 */
181 /* Generic flags */
182 #define SBE_CMD_CTRL_RESP_REQ 0x0100
183 #define SBE_CMD_CTRL_ACK_REQ 0x0200
185 /* Deadman loop */
186 #define CTRL_DEADMAN_LOOP_START 0x0001
187 #define CTRL_DEADMAN_LOOP_STOP 0x0002
189 /* Control timer */
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)
207 struct sbe_msg msg;
208 uint16_t cmd, ctrl_flags, seq_id;
209 int i;
211 memset(&msg, 0, sizeof(msg));
213 for (i = 0; i < 4; i++) {
214 msg.reg[i] = sbe->mbox[i];
217 cmd = msg.reg[0];
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);
227 switch (cmd) {
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);
238 break;
239 default:
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;
251 do_sbe_msg(sbe);
255 static uint64_t pnv_sbe_power9_xscom_mbox_read(void *opaque, hwaddr addr,
256 unsigned size)
258 PnvSBE *sbe = PNV_SBE(opaque);
259 uint32_t offset = addr >> 3;
260 uint64_t val = 0;
262 if (offset <= PSU_HOST_SBE_MBOX_REG7) {
263 uint32_t idx = offset - PSU_HOST_SBE_MBOX_REG0;
264 val = sbe->mbox[idx];
265 } else {
266 switch (offset) {
267 case PSU_SBE_DOORBELL_REG_RW:
268 val = sbe->sbe_doorbell;
269 break;
270 case PSU_HOST_DOORBELL_REG_RW:
271 val = sbe->host_doorbell;
272 break;
273 default:
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);
281 return 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;
295 } else {
296 switch (offset) {
297 case PSU_SBE_DOORBELL_REG_RW:
298 pnv_sbe_set_sbe_doorbell(sbe, val);
299 break;
300 case PSU_SBE_DOORBELL_REG_AND:
301 pnv_sbe_set_sbe_doorbell(sbe, sbe->sbe_doorbell & val);
302 break;
303 case PSU_SBE_DOORBELL_REG_OR:
304 pnv_sbe_set_sbe_doorbell(sbe, sbe->sbe_doorbell | val);
305 break;
307 case PSU_HOST_DOORBELL_REG_RW:
308 pnv_sbe_set_host_doorbell(sbe, val);
309 break;
310 case PSU_HOST_DOORBELL_REG_AND:
311 pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell & val);
312 break;
313 case PSU_HOST_DOORBELL_REG_OR:
314 pnv_sbe_set_host_doorbell(sbe, sbe->host_doorbell | val);
315 break;
317 default:
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(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),
404 .abstract = true,
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);