xref: /openbmc/qemu/hw/fsi/cfam.c (revision f5e80be3922945c51a85aa08c4dfab0a2f3aacc5)
1*f5e80be3SNinad Palsule /*
2*f5e80be3SNinad Palsule  * SPDX-License-Identifier: GPL-2.0-or-later
3*f5e80be3SNinad Palsule  * Copyright (C) 2024 IBM Corp.
4*f5e80be3SNinad Palsule  *
5*f5e80be3SNinad Palsule  * IBM Common FRU Access Macro
6*f5e80be3SNinad Palsule  */
7*f5e80be3SNinad Palsule 
8*f5e80be3SNinad Palsule #include "qemu/osdep.h"
9*f5e80be3SNinad Palsule #include "qemu/units.h"
10*f5e80be3SNinad Palsule 
11*f5e80be3SNinad Palsule #include "qapi/error.h"
12*f5e80be3SNinad Palsule #include "trace.h"
13*f5e80be3SNinad Palsule 
14*f5e80be3SNinad Palsule #include "hw/fsi/cfam.h"
15*f5e80be3SNinad Palsule #include "hw/fsi/fsi.h"
16*f5e80be3SNinad Palsule 
17*f5e80be3SNinad Palsule #include "hw/qdev-properties.h"
18*f5e80be3SNinad Palsule 
19*f5e80be3SNinad Palsule #define ENGINE_CONFIG_NEXT            BIT(31)
20*f5e80be3SNinad Palsule #define ENGINE_CONFIG_TYPE_PEEK       (0x02 << 4)
21*f5e80be3SNinad Palsule #define ENGINE_CONFIG_TYPE_FSI        (0x03 << 4)
22*f5e80be3SNinad Palsule #define ENGINE_CONFIG_TYPE_SCRATCHPAD (0x06 << 4)
23*f5e80be3SNinad Palsule 
24*f5e80be3SNinad Palsule /* Valid, slots, version, type, crc */
25*f5e80be3SNinad Palsule #define CFAM_CONFIG_REG(__VER, __TYPE, __CRC)   \
26*f5e80be3SNinad Palsule     (ENGINE_CONFIG_NEXT       |   \
27*f5e80be3SNinad Palsule      0x00010000               |   \
28*f5e80be3SNinad Palsule      (__VER)                  |   \
29*f5e80be3SNinad Palsule      (__TYPE)                 |   \
30*f5e80be3SNinad Palsule      (__CRC))
31*f5e80be3SNinad Palsule 
32*f5e80be3SNinad Palsule #define TO_REG(x)                          ((x) >> 2)
33*f5e80be3SNinad Palsule 
34*f5e80be3SNinad Palsule #define CFAM_CONFIG_CHIP_ID                TO_REG(0x00)
35*f5e80be3SNinad Palsule #define CFAM_CONFIG_PEEK_STATUS            TO_REG(0x04)
36*f5e80be3SNinad Palsule #define CFAM_CONFIG_CHIP_ID_P9             0xc0022d15
37*f5e80be3SNinad Palsule #define CFAM_CONFIG_CHIP_ID_BREAK          0xc0de0000
38*f5e80be3SNinad Palsule 
fsi_cfam_config_read(void * opaque,hwaddr addr,unsigned size)39*f5e80be3SNinad Palsule static uint64_t fsi_cfam_config_read(void *opaque, hwaddr addr, unsigned size)
40*f5e80be3SNinad Palsule {
41*f5e80be3SNinad Palsule     trace_fsi_cfam_config_read(addr, size);
42*f5e80be3SNinad Palsule 
43*f5e80be3SNinad Palsule     switch (addr) {
44*f5e80be3SNinad Palsule     case 0x00:
45*f5e80be3SNinad Palsule         return CFAM_CONFIG_CHIP_ID_P9;
46*f5e80be3SNinad Palsule     case 0x04:
47*f5e80be3SNinad Palsule         return CFAM_CONFIG_REG(0x1000, ENGINE_CONFIG_TYPE_PEEK, 0xc);
48*f5e80be3SNinad Palsule     case 0x08:
49*f5e80be3SNinad Palsule         return CFAM_CONFIG_REG(0x5000, ENGINE_CONFIG_TYPE_FSI, 0xa);
50*f5e80be3SNinad Palsule     case 0xc:
51*f5e80be3SNinad Palsule         return CFAM_CONFIG_REG(0x1000, ENGINE_CONFIG_TYPE_SCRATCHPAD, 0x7);
52*f5e80be3SNinad Palsule     default:
53*f5e80be3SNinad Palsule         /*
54*f5e80be3SNinad Palsule          * The config table contains different engines from 0xc onwards.
55*f5e80be3SNinad Palsule          * The scratch pad is already added at address 0xc. We need to add
56*f5e80be3SNinad Palsule          * future engines from address 0x10 onwards. Returning 0 as engine
57*f5e80be3SNinad Palsule          * is not implemented.
58*f5e80be3SNinad Palsule          */
59*f5e80be3SNinad Palsule         return 0;
60*f5e80be3SNinad Palsule     }
61*f5e80be3SNinad Palsule }
62*f5e80be3SNinad Palsule 
fsi_cfam_config_write(void * opaque,hwaddr addr,uint64_t data,unsigned size)63*f5e80be3SNinad Palsule static void fsi_cfam_config_write(void *opaque, hwaddr addr, uint64_t data,
64*f5e80be3SNinad Palsule                                   unsigned size)
65*f5e80be3SNinad Palsule {
66*f5e80be3SNinad Palsule     FSICFAMState *cfam = FSI_CFAM(opaque);
67*f5e80be3SNinad Palsule 
68*f5e80be3SNinad Palsule     trace_fsi_cfam_config_write(addr, size, data);
69*f5e80be3SNinad Palsule 
70*f5e80be3SNinad Palsule     switch (TO_REG(addr)) {
71*f5e80be3SNinad Palsule     case CFAM_CONFIG_CHIP_ID:
72*f5e80be3SNinad Palsule     case CFAM_CONFIG_PEEK_STATUS:
73*f5e80be3SNinad Palsule         if (data == CFAM_CONFIG_CHIP_ID_BREAK) {
74*f5e80be3SNinad Palsule             bus_cold_reset(BUS(&cfam->lbus));
75*f5e80be3SNinad Palsule         }
76*f5e80be3SNinad Palsule         break;
77*f5e80be3SNinad Palsule     default:
78*f5e80be3SNinad Palsule         trace_fsi_cfam_config_write_noaddr(addr, size, data);
79*f5e80be3SNinad Palsule     }
80*f5e80be3SNinad Palsule }
81*f5e80be3SNinad Palsule 
82*f5e80be3SNinad Palsule static const struct MemoryRegionOps cfam_config_ops = {
83*f5e80be3SNinad Palsule     .read = fsi_cfam_config_read,
84*f5e80be3SNinad Palsule     .write = fsi_cfam_config_write,
85*f5e80be3SNinad Palsule     .valid.max_access_size = 4,
86*f5e80be3SNinad Palsule     .valid.min_access_size = 4,
87*f5e80be3SNinad Palsule     .impl.max_access_size = 4,
88*f5e80be3SNinad Palsule     .impl.min_access_size = 4,
89*f5e80be3SNinad Palsule     .endianness = DEVICE_BIG_ENDIAN,
90*f5e80be3SNinad Palsule };
91*f5e80be3SNinad Palsule 
fsi_cfam_unimplemented_read(void * opaque,hwaddr addr,unsigned size)92*f5e80be3SNinad Palsule static uint64_t fsi_cfam_unimplemented_read(void *opaque, hwaddr addr,
93*f5e80be3SNinad Palsule                                             unsigned size)
94*f5e80be3SNinad Palsule {
95*f5e80be3SNinad Palsule     trace_fsi_cfam_unimplemented_read(addr, size);
96*f5e80be3SNinad Palsule 
97*f5e80be3SNinad Palsule     return 0;
98*f5e80be3SNinad Palsule }
99*f5e80be3SNinad Palsule 
fsi_cfam_unimplemented_write(void * opaque,hwaddr addr,uint64_t data,unsigned size)100*f5e80be3SNinad Palsule static void fsi_cfam_unimplemented_write(void *opaque, hwaddr addr,
101*f5e80be3SNinad Palsule                                          uint64_t data, unsigned size)
102*f5e80be3SNinad Palsule {
103*f5e80be3SNinad Palsule     trace_fsi_cfam_unimplemented_write(addr, size, data);
104*f5e80be3SNinad Palsule }
105*f5e80be3SNinad Palsule 
106*f5e80be3SNinad Palsule static const struct MemoryRegionOps fsi_cfam_unimplemented_ops = {
107*f5e80be3SNinad Palsule     .read = fsi_cfam_unimplemented_read,
108*f5e80be3SNinad Palsule     .write = fsi_cfam_unimplemented_write,
109*f5e80be3SNinad Palsule     .endianness = DEVICE_BIG_ENDIAN,
110*f5e80be3SNinad Palsule };
111*f5e80be3SNinad Palsule 
fsi_cfam_instance_init(Object * obj)112*f5e80be3SNinad Palsule static void fsi_cfam_instance_init(Object *obj)
113*f5e80be3SNinad Palsule {
114*f5e80be3SNinad Palsule     FSICFAMState *s = FSI_CFAM(obj);
115*f5e80be3SNinad Palsule 
116*f5e80be3SNinad Palsule     object_initialize_child(obj, "scratchpad", &s->scratchpad,
117*f5e80be3SNinad Palsule                             TYPE_FSI_SCRATCHPAD);
118*f5e80be3SNinad Palsule }
119*f5e80be3SNinad Palsule 
fsi_cfam_realize(DeviceState * dev,Error ** errp)120*f5e80be3SNinad Palsule static void fsi_cfam_realize(DeviceState *dev, Error **errp)
121*f5e80be3SNinad Palsule {
122*f5e80be3SNinad Palsule     FSICFAMState *cfam = FSI_CFAM(dev);
123*f5e80be3SNinad Palsule     FSISlaveState *slave = FSI_SLAVE(dev);
124*f5e80be3SNinad Palsule 
125*f5e80be3SNinad Palsule     /* Each slave has a 2MiB address space */
126*f5e80be3SNinad Palsule     memory_region_init_io(&cfam->mr, OBJECT(cfam), &fsi_cfam_unimplemented_ops,
127*f5e80be3SNinad Palsule                           cfam, TYPE_FSI_CFAM, 2 * MiB);
128*f5e80be3SNinad Palsule 
129*f5e80be3SNinad Palsule     qbus_init(&cfam->lbus, sizeof(cfam->lbus), TYPE_FSI_LBUS, DEVICE(cfam),
130*f5e80be3SNinad Palsule               NULL);
131*f5e80be3SNinad Palsule 
132*f5e80be3SNinad Palsule     memory_region_init_io(&cfam->config_iomem, OBJECT(cfam), &cfam_config_ops,
133*f5e80be3SNinad Palsule                           cfam, TYPE_FSI_CFAM ".config", 0x400);
134*f5e80be3SNinad Palsule 
135*f5e80be3SNinad Palsule     memory_region_add_subregion(&cfam->mr, 0, &cfam->config_iomem);
136*f5e80be3SNinad Palsule     memory_region_add_subregion(&cfam->mr, 0x800, &slave->iomem);
137*f5e80be3SNinad Palsule     memory_region_add_subregion(&cfam->mr, 0xc00, &cfam->lbus.mr);
138*f5e80be3SNinad Palsule 
139*f5e80be3SNinad Palsule     /* Add scratchpad engine */
140*f5e80be3SNinad Palsule     if (!qdev_realize(DEVICE(&cfam->scratchpad), BUS(&cfam->lbus), errp)) {
141*f5e80be3SNinad Palsule         return;
142*f5e80be3SNinad Palsule     }
143*f5e80be3SNinad Palsule 
144*f5e80be3SNinad Palsule     FSILBusDevice *fsi_dev = FSI_LBUS_DEVICE(&cfam->scratchpad);
145*f5e80be3SNinad Palsule     memory_region_add_subregion(&cfam->lbus.mr, 0, &fsi_dev->iomem);
146*f5e80be3SNinad Palsule }
147*f5e80be3SNinad Palsule 
fsi_cfam_class_init(ObjectClass * klass,void * data)148*f5e80be3SNinad Palsule static void fsi_cfam_class_init(ObjectClass *klass, void *data)
149*f5e80be3SNinad Palsule {
150*f5e80be3SNinad Palsule     DeviceClass *dc = DEVICE_CLASS(klass);
151*f5e80be3SNinad Palsule     dc->bus_type = TYPE_FSI_BUS;
152*f5e80be3SNinad Palsule     dc->realize = fsi_cfam_realize;
153*f5e80be3SNinad Palsule }
154*f5e80be3SNinad Palsule 
155*f5e80be3SNinad Palsule static const TypeInfo fsi_cfam_info = {
156*f5e80be3SNinad Palsule     .name = TYPE_FSI_CFAM,
157*f5e80be3SNinad Palsule     .parent = TYPE_FSI_SLAVE,
158*f5e80be3SNinad Palsule     .instance_init = fsi_cfam_instance_init,
159*f5e80be3SNinad Palsule     .instance_size = sizeof(FSICFAMState),
160*f5e80be3SNinad Palsule     .class_init = fsi_cfam_class_init,
161*f5e80be3SNinad Palsule };
162*f5e80be3SNinad Palsule 
fsi_cfam_register_types(void)163*f5e80be3SNinad Palsule static void fsi_cfam_register_types(void)
164*f5e80be3SNinad Palsule {
165*f5e80be3SNinad Palsule     type_register_static(&fsi_cfam_info);
166*f5e80be3SNinad Palsule }
167*f5e80be3SNinad Palsule 
168*f5e80be3SNinad Palsule type_init(fsi_cfam_register_types);
169*f5e80be3SNinad Palsule