xref: /qemu/hw/nubus/nubus-device.c (revision fa2ba3b80e13e6bb961bfe3e614c606cd4985d3d)
1*fa2ba3b8SLaurent Vivier /*
2*fa2ba3b8SLaurent Vivier  * QEMU Macintosh Nubus
3*fa2ba3b8SLaurent Vivier  *
4*fa2ba3b8SLaurent Vivier  * Copyright (c) 2013-2018 Laurent Vivier <laurent@vivier.eu>
5*fa2ba3b8SLaurent Vivier  *
6*fa2ba3b8SLaurent Vivier  * This work is licensed under the terms of the GNU GPL, version 2 or later.
7*fa2ba3b8SLaurent Vivier  * See the COPYING file in the top-level directory.
8*fa2ba3b8SLaurent Vivier  *
9*fa2ba3b8SLaurent Vivier  */
10*fa2ba3b8SLaurent Vivier 
11*fa2ba3b8SLaurent Vivier #include "qemu/osdep.h"
12*fa2ba3b8SLaurent Vivier #include "hw/nubus/nubus.h"
13*fa2ba3b8SLaurent Vivier #include "qapi/error.h"
14*fa2ba3b8SLaurent Vivier 
15*fa2ba3b8SLaurent Vivier 
16*fa2ba3b8SLaurent Vivier /* The Format Block Structure */
17*fa2ba3b8SLaurent Vivier 
18*fa2ba3b8SLaurent Vivier #define FBLOCK_DIRECTORY_OFFSET 0
19*fa2ba3b8SLaurent Vivier #define FBLOCK_LENGTH           4
20*fa2ba3b8SLaurent Vivier #define FBLOCK_CRC              8
21*fa2ba3b8SLaurent Vivier #define FBLOCK_REVISION_LEVEL   12
22*fa2ba3b8SLaurent Vivier #define FBLOCK_FORMAT           13
23*fa2ba3b8SLaurent Vivier #define FBLOCK_TEST_PATTERN     14
24*fa2ba3b8SLaurent Vivier #define FBLOCK_RESERVED         18
25*fa2ba3b8SLaurent Vivier #define FBLOCK_BYTE_LANES       19
26*fa2ba3b8SLaurent Vivier 
27*fa2ba3b8SLaurent Vivier #define FBLOCK_SIZE             20
28*fa2ba3b8SLaurent Vivier #define FBLOCK_PATTERN_VAL      0x5a932bc7
29*fa2ba3b8SLaurent Vivier 
30*fa2ba3b8SLaurent Vivier static uint64_t nubus_fblock_read(void *opaque, hwaddr addr, unsigned int size)
31*fa2ba3b8SLaurent Vivier {
32*fa2ba3b8SLaurent Vivier     NubusDevice *dev = opaque;
33*fa2ba3b8SLaurent Vivier     uint64_t val;
34*fa2ba3b8SLaurent Vivier 
35*fa2ba3b8SLaurent Vivier #define BYTE(v, b) (((v) >> (24 - 8 * (b))) & 0xff)
36*fa2ba3b8SLaurent Vivier     switch (addr) {
37*fa2ba3b8SLaurent Vivier     case FBLOCK_BYTE_LANES:
38*fa2ba3b8SLaurent Vivier         val = dev->byte_lanes;
39*fa2ba3b8SLaurent Vivier         val |= (val ^ 0xf) << 4;
40*fa2ba3b8SLaurent Vivier         break;
41*fa2ba3b8SLaurent Vivier     case FBLOCK_RESERVED:
42*fa2ba3b8SLaurent Vivier         val = 0x00;
43*fa2ba3b8SLaurent Vivier         break;
44*fa2ba3b8SLaurent Vivier     case FBLOCK_TEST_PATTERN...FBLOCK_TEST_PATTERN + 3:
45*fa2ba3b8SLaurent Vivier         val = BYTE(FBLOCK_PATTERN_VAL, addr - FBLOCK_TEST_PATTERN);
46*fa2ba3b8SLaurent Vivier         break;
47*fa2ba3b8SLaurent Vivier     case FBLOCK_FORMAT:
48*fa2ba3b8SLaurent Vivier         val = dev->rom_format;
49*fa2ba3b8SLaurent Vivier         break;
50*fa2ba3b8SLaurent Vivier     case FBLOCK_REVISION_LEVEL:
51*fa2ba3b8SLaurent Vivier         val = dev->rom_rev;
52*fa2ba3b8SLaurent Vivier         break;
53*fa2ba3b8SLaurent Vivier     case FBLOCK_CRC...FBLOCK_CRC + 3:
54*fa2ba3b8SLaurent Vivier         val = BYTE(dev->rom_crc, addr - FBLOCK_CRC);
55*fa2ba3b8SLaurent Vivier         break;
56*fa2ba3b8SLaurent Vivier     case FBLOCK_LENGTH...FBLOCK_LENGTH + 3:
57*fa2ba3b8SLaurent Vivier         val = BYTE(dev->rom_length, addr - FBLOCK_LENGTH);
58*fa2ba3b8SLaurent Vivier         break;
59*fa2ba3b8SLaurent Vivier     case FBLOCK_DIRECTORY_OFFSET...FBLOCK_DIRECTORY_OFFSET + 3:
60*fa2ba3b8SLaurent Vivier         val = BYTE(dev->directory_offset, addr - FBLOCK_DIRECTORY_OFFSET);
61*fa2ba3b8SLaurent Vivier         break;
62*fa2ba3b8SLaurent Vivier     default:
63*fa2ba3b8SLaurent Vivier         val = 0;
64*fa2ba3b8SLaurent Vivier         break;
65*fa2ba3b8SLaurent Vivier     }
66*fa2ba3b8SLaurent Vivier     return val;
67*fa2ba3b8SLaurent Vivier }
68*fa2ba3b8SLaurent Vivier 
69*fa2ba3b8SLaurent Vivier static void nubus_fblock_write(void *opaque, hwaddr addr, uint64_t val,
70*fa2ba3b8SLaurent Vivier                                unsigned int size)
71*fa2ba3b8SLaurent Vivier {
72*fa2ba3b8SLaurent Vivier     /* read only */
73*fa2ba3b8SLaurent Vivier }
74*fa2ba3b8SLaurent Vivier 
75*fa2ba3b8SLaurent Vivier static const MemoryRegionOps nubus_format_block_ops = {
76*fa2ba3b8SLaurent Vivier     .read = nubus_fblock_read,
77*fa2ba3b8SLaurent Vivier     .write = nubus_fblock_write,
78*fa2ba3b8SLaurent Vivier     .endianness = DEVICE_BIG_ENDIAN,
79*fa2ba3b8SLaurent Vivier     .valid = {
80*fa2ba3b8SLaurent Vivier         .min_access_size = 1,
81*fa2ba3b8SLaurent Vivier         .max_access_size = 1,
82*fa2ba3b8SLaurent Vivier     }
83*fa2ba3b8SLaurent Vivier };
84*fa2ba3b8SLaurent Vivier 
85*fa2ba3b8SLaurent Vivier static void nubus_register_format_block(NubusDevice *dev)
86*fa2ba3b8SLaurent Vivier {
87*fa2ba3b8SLaurent Vivier     char *fblock_name;
88*fa2ba3b8SLaurent Vivier 
89*fa2ba3b8SLaurent Vivier     fblock_name = g_strdup_printf("nubus-slot-%d-format-block",
90*fa2ba3b8SLaurent Vivier                                   dev->slot_nb);
91*fa2ba3b8SLaurent Vivier 
92*fa2ba3b8SLaurent Vivier     hwaddr fblock_offset = memory_region_size(&dev->slot_mem) - FBLOCK_SIZE;
93*fa2ba3b8SLaurent Vivier     memory_region_init_io(&dev->fblock_io, NULL, &nubus_format_block_ops,
94*fa2ba3b8SLaurent Vivier                           dev, fblock_name, FBLOCK_SIZE);
95*fa2ba3b8SLaurent Vivier     memory_region_add_subregion(&dev->slot_mem, fblock_offset,
96*fa2ba3b8SLaurent Vivier                                 &dev->fblock_io);
97*fa2ba3b8SLaurent Vivier 
98*fa2ba3b8SLaurent Vivier     g_free(fblock_name);
99*fa2ba3b8SLaurent Vivier }
100*fa2ba3b8SLaurent Vivier 
101*fa2ba3b8SLaurent Vivier static void mac_nubus_rom_write(void *opaque, hwaddr addr, uint64_t val,
102*fa2ba3b8SLaurent Vivier                                        unsigned int size)
103*fa2ba3b8SLaurent Vivier {
104*fa2ba3b8SLaurent Vivier     /* read only */
105*fa2ba3b8SLaurent Vivier }
106*fa2ba3b8SLaurent Vivier 
107*fa2ba3b8SLaurent Vivier static uint64_t mac_nubus_rom_read(void *opaque, hwaddr addr,
108*fa2ba3b8SLaurent Vivier                                     unsigned int size)
109*fa2ba3b8SLaurent Vivier {
110*fa2ba3b8SLaurent Vivier     NubusDevice *dev = opaque;
111*fa2ba3b8SLaurent Vivier 
112*fa2ba3b8SLaurent Vivier     return dev->rom[addr];
113*fa2ba3b8SLaurent Vivier }
114*fa2ba3b8SLaurent Vivier 
115*fa2ba3b8SLaurent Vivier static const MemoryRegionOps mac_nubus_rom_ops = {
116*fa2ba3b8SLaurent Vivier     .read  = mac_nubus_rom_read,
117*fa2ba3b8SLaurent Vivier     .write = mac_nubus_rom_write,
118*fa2ba3b8SLaurent Vivier     .endianness = DEVICE_BIG_ENDIAN,
119*fa2ba3b8SLaurent Vivier     .valid = {
120*fa2ba3b8SLaurent Vivier         .min_access_size = 1,
121*fa2ba3b8SLaurent Vivier         .max_access_size = 1,
122*fa2ba3b8SLaurent Vivier     },
123*fa2ba3b8SLaurent Vivier };
124*fa2ba3b8SLaurent Vivier 
125*fa2ba3b8SLaurent Vivier 
126*fa2ba3b8SLaurent Vivier void nubus_register_rom(NubusDevice *dev, const uint8_t *rom, uint32_t size,
127*fa2ba3b8SLaurent Vivier                         int revision, int format, uint8_t byte_lanes)
128*fa2ba3b8SLaurent Vivier {
129*fa2ba3b8SLaurent Vivier     hwaddr rom_offset;
130*fa2ba3b8SLaurent Vivier     char *rom_name;
131*fa2ba3b8SLaurent Vivier 
132*fa2ba3b8SLaurent Vivier     /* FIXME : really compute CRC */
133*fa2ba3b8SLaurent Vivier     dev->rom_length = 0;
134*fa2ba3b8SLaurent Vivier     dev->rom_crc = 0;
135*fa2ba3b8SLaurent Vivier 
136*fa2ba3b8SLaurent Vivier     dev->rom_rev = revision;
137*fa2ba3b8SLaurent Vivier     dev->rom_format = format;
138*fa2ba3b8SLaurent Vivier 
139*fa2ba3b8SLaurent Vivier     dev->byte_lanes = byte_lanes;
140*fa2ba3b8SLaurent Vivier     dev->directory_offset = -size;
141*fa2ba3b8SLaurent Vivier 
142*fa2ba3b8SLaurent Vivier     /* ROM */
143*fa2ba3b8SLaurent Vivier 
144*fa2ba3b8SLaurent Vivier     dev->rom = rom;
145*fa2ba3b8SLaurent Vivier     rom_name = g_strdup_printf("nubus-slot-%d-rom", dev->slot_nb);
146*fa2ba3b8SLaurent Vivier     memory_region_init_io(&dev->rom_io, NULL, &mac_nubus_rom_ops,
147*fa2ba3b8SLaurent Vivier                           dev, rom_name, size);
148*fa2ba3b8SLaurent Vivier     memory_region_set_readonly(&dev->rom_io, true);
149*fa2ba3b8SLaurent Vivier 
150*fa2ba3b8SLaurent Vivier     rom_offset = memory_region_size(&dev->slot_mem) - FBLOCK_SIZE +
151*fa2ba3b8SLaurent Vivier                  dev->directory_offset;
152*fa2ba3b8SLaurent Vivier     memory_region_add_subregion(&dev->slot_mem, rom_offset, &dev->rom_io);
153*fa2ba3b8SLaurent Vivier 
154*fa2ba3b8SLaurent Vivier     g_free(rom_name);
155*fa2ba3b8SLaurent Vivier }
156*fa2ba3b8SLaurent Vivier 
157*fa2ba3b8SLaurent Vivier static void nubus_device_realize(DeviceState *dev, Error **errp)
158*fa2ba3b8SLaurent Vivier {
159*fa2ba3b8SLaurent Vivier     NubusBus *nubus = NUBUS_BUS(qdev_get_parent_bus(DEVICE(dev)));
160*fa2ba3b8SLaurent Vivier     NubusDevice *nd = NUBUS_DEVICE(dev);
161*fa2ba3b8SLaurent Vivier     char *name;
162*fa2ba3b8SLaurent Vivier     hwaddr slot_offset;
163*fa2ba3b8SLaurent Vivier 
164*fa2ba3b8SLaurent Vivier     if (nubus->current_slot < NUBUS_FIRST_SLOT ||
165*fa2ba3b8SLaurent Vivier             nubus->current_slot > NUBUS_LAST_SLOT) {
166*fa2ba3b8SLaurent Vivier         error_setg(errp, "Cannot register nubus card, not enough slots");
167*fa2ba3b8SLaurent Vivier         return;
168*fa2ba3b8SLaurent Vivier     }
169*fa2ba3b8SLaurent Vivier 
170*fa2ba3b8SLaurent Vivier     nd->slot_nb = nubus->current_slot++;
171*fa2ba3b8SLaurent Vivier     name = g_strdup_printf("nubus-slot-%d", nd->slot_nb);
172*fa2ba3b8SLaurent Vivier 
173*fa2ba3b8SLaurent Vivier     if (nd->slot_nb < NUBUS_FIRST_SLOT) {
174*fa2ba3b8SLaurent Vivier         /* Super */
175*fa2ba3b8SLaurent Vivier         slot_offset = (nd->slot_nb - 6) * NUBUS_SUPER_SLOT_SIZE;
176*fa2ba3b8SLaurent Vivier 
177*fa2ba3b8SLaurent Vivier         memory_region_init(&nd->slot_mem, OBJECT(dev), name,
178*fa2ba3b8SLaurent Vivier                            NUBUS_SUPER_SLOT_SIZE);
179*fa2ba3b8SLaurent Vivier         memory_region_add_subregion(&nubus->super_slot_io, slot_offset,
180*fa2ba3b8SLaurent Vivier                                     &nd->slot_mem);
181*fa2ba3b8SLaurent Vivier     } else {
182*fa2ba3b8SLaurent Vivier         /* Normal */
183*fa2ba3b8SLaurent Vivier         slot_offset = nd->slot_nb * NUBUS_SLOT_SIZE;
184*fa2ba3b8SLaurent Vivier 
185*fa2ba3b8SLaurent Vivier         memory_region_init(&nd->slot_mem, OBJECT(dev), name, NUBUS_SLOT_SIZE);
186*fa2ba3b8SLaurent Vivier         memory_region_add_subregion(&nubus->slot_io, slot_offset,
187*fa2ba3b8SLaurent Vivier                                     &nd->slot_mem);
188*fa2ba3b8SLaurent Vivier     }
189*fa2ba3b8SLaurent Vivier 
190*fa2ba3b8SLaurent Vivier     g_free(name);
191*fa2ba3b8SLaurent Vivier     nubus_register_format_block(nd);
192*fa2ba3b8SLaurent Vivier }
193*fa2ba3b8SLaurent Vivier 
194*fa2ba3b8SLaurent Vivier static void nubus_device_class_init(ObjectClass *oc, void *data)
195*fa2ba3b8SLaurent Vivier {
196*fa2ba3b8SLaurent Vivier     DeviceClass *dc = DEVICE_CLASS(oc);
197*fa2ba3b8SLaurent Vivier 
198*fa2ba3b8SLaurent Vivier     dc->realize = nubus_device_realize;
199*fa2ba3b8SLaurent Vivier     dc->bus_type = TYPE_NUBUS_BUS;
200*fa2ba3b8SLaurent Vivier }
201*fa2ba3b8SLaurent Vivier 
202*fa2ba3b8SLaurent Vivier static const TypeInfo nubus_device_type_info = {
203*fa2ba3b8SLaurent Vivier     .name = TYPE_NUBUS_DEVICE,
204*fa2ba3b8SLaurent Vivier     .parent = TYPE_DEVICE,
205*fa2ba3b8SLaurent Vivier     .abstract = true,
206*fa2ba3b8SLaurent Vivier     .instance_size = sizeof(NubusDevice),
207*fa2ba3b8SLaurent Vivier     .class_init = nubus_device_class_init,
208*fa2ba3b8SLaurent Vivier };
209*fa2ba3b8SLaurent Vivier 
210*fa2ba3b8SLaurent Vivier static void nubus_register_types(void)
211*fa2ba3b8SLaurent Vivier {
212*fa2ba3b8SLaurent Vivier     type_register_static(&nubus_device_type_info);
213*fa2ba3b8SLaurent Vivier }
214*fa2ba3b8SLaurent Vivier 
215*fa2ba3b8SLaurent Vivier type_init(nubus_register_types)
216