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