master
c 175 lines 6.32 KB
Raw
1 /*
2 * Hexagon subsystem helpers shared between the machine models.
3 *
4 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8 #include "qemu/osdep.h"
9 #include "qapi/error.h"
10 #include "hw/hexagon/hex-subsys.h"
11 #include "hw/hexagon/hexagon_globalreg.h"
12 #include "hw/hexagon/hexagon_tlb.h"
13 #include "hw/intc/hex-l2vic.h"
14 #include "hw/timer/qct-qtimer.h"
15 #include "hw/cpu/cluster.h"
16 #include "hw/core/loader.h"
17 #include "hw/core/qdev-properties.h"
18 #include "hw/core/qdev.h"
19 #include "hw/core/sysbus.h"
20 #include "system/address-spaces.h"
21
22 #define HEX_L2VIC_CPU_IRQS 8
23
24 /* Number of QTimer frames instantiated for every Hexagon machine. */
25 #define HEX_QTIMER_NR_FRAMES 3
26
27 #define HEX_QTIMER_L2VIC_IRQ_BASE 2
28
29 static DeviceState *l2vic_create(HexagonCommonMachineState *hms,
30 const struct hexagon_machine_config *m_cfg)
31 {
32 DeviceState *l2vic = qdev_new(TYPE_HEX_L2VIC);
33
34 object_property_add_child(OBJECT(hms), "l2vic", OBJECT(l2vic));
35 sysbus_realize_and_unref(SYS_BUS_DEVICE(l2vic), &error_fatal);
36 sysbus_mmio_map(SYS_BUS_DEVICE(l2vic), 0, m_cfg->l2vic_base);
37 sysbus_mmio_map(SYS_BUS_DEVICE(l2vic), 1,
38 m_cfg->cfgtable.fastl2vic_base << 16);
39
40 return l2vic;
41 }
42
43 static void l2vic_connect_cpu(DeviceState *l2vic, DeviceState *cpu)
44 {
45 int i;
46
47 for (i = 0; i < HEX_L2VIC_CPU_IRQS; i++) {
48 sysbus_connect_irq(SYS_BUS_DEVICE(l2vic), i, qdev_get_gpio_in(cpu, i));
49 }
50 }
51
52 static DeviceState *qtimer_create(HexagonCommonMachineState *hms,
53 const struct hexagon_machine_config *m_cfg)
54 {
55 DeviceState *qtimer = qdev_new(TYPE_QCT_QTIMER);
56
57 object_property_add_child(OBJECT(hms), "qtimer", OBJECT(qtimer));
58 qdev_prop_set_uint32(qtimer, "nr_frames", HEX_QTIMER_NR_FRAMES);
59 sysbus_realize_and_unref(SYS_BUS_DEVICE(qtimer), &error_fatal);
60 sysbus_mmio_map(SYS_BUS_DEVICE(qtimer), 0, m_cfg->csr_base);
61 sysbus_mmio_map(SYS_BUS_DEVICE(qtimer), 1, m_cfg->qtmr_region);
62 for (unsigned int i = 0; i < HEX_QTIMER_NR_FRAMES; i++) {
63 sysbus_connect_irq(SYS_BUS_DEVICE(qtimer), i,
64 qdev_get_gpio_in(hms->l2vic,
65 HEX_QTIMER_L2VIC_IRQ_BASE + i));
66 }
67
68 return qtimer;
69 }
70
71 static DeviceState *globalreg_create(HexagonCommonMachineState *hms,
72 const struct hexagon_machine_config *m_cfg,
73 Rev_t rev)
74 {
75 DeviceState *glob_regs = qdev_new(TYPE_HEXAGON_GLOBALREG);
76
77 object_property_add_child(OBJECT(hms), "global-regs", OBJECT(glob_regs));
78 qdev_prop_set_uint64(glob_regs, "config-table-addr", m_cfg->cfgbase);
79 qdev_prop_set_uint32(glob_regs, "dsp-rev", rev);
80 object_property_set_link(OBJECT(glob_regs), "l2vic", OBJECT(hms->l2vic),
81 &error_fatal);
82 object_property_set_link(OBJECT(glob_regs), "qtimer", OBJECT(hms->qtimer),
83 &error_fatal);
84 sysbus_realize_and_unref(SYS_BUS_DEVICE(glob_regs), &error_fatal);
85
86 return glob_regs;
87 }
88
89 static DeviceState *tlb_create(HexagonCommonMachineState *hms,
90 const struct hexagon_machine_config *m_cfg)
91 {
92 DeviceState *tlb = qdev_new(TYPE_HEXAGON_TLB);
93
94 object_property_add_child(OBJECT(hms), "tlb", OBJECT(tlb));
95 qdev_prop_set_uint32(tlb, "num-entries", m_cfg->cfgtable.jtlb_size_entries);
96 sysbus_realize_and_unref(SYS_BUS_DEVICE(tlb), &error_fatal);
97
98 return tlb;
99 }
100
101 static DeviceState *cluster_create(HexagonCommonMachineState *hms)
102 {
103 DeviceState *cluster = qdev_new(TYPE_CPU_CLUSTER);
104
105 object_property_add_child(OBJECT(hms), "cluster", OBJECT(cluster));
106 qdev_prop_set_uint32(cluster, "cluster-id", 0);
107
108 return cluster;
109 }
110
111 void hex_subsys_create(HexagonCommonMachineState *hms,
112 const struct hexagon_machine_config *m_cfg, Rev_t rev)
113 {
114 MachineState *machine = MACHINE(hms);
115 MemoryRegion *sysmem = get_system_memory();
116
117 /* Main DDR at the reset vector. */
118 memory_region_init_ram(&hms->ram, NULL, "ddr.ram", machine->ram_size,
119 &error_fatal);
120 memory_region_add_subregion(sysmem, 0x0, &hms->ram);
121
122 /* Config-table ROM and the blob that backs it. */
123 memory_region_init_rom(&hms->cfgtable_rom, NULL, "config_table.rom",
124 sizeof(m_cfg->cfgtable), &error_fatal);
125 memory_region_add_subregion(sysmem, m_cfg->cfgbase, &hms->cfgtable_rom);
126 rom_add_blob_fixed_as("config_table.rom", &m_cfg->cfgtable,
127 sizeof(m_cfg->cfgtable), m_cfg->cfgbase,
128 &address_space_memory);
129
130 if (m_cfg->cfgtable.vtcm_size_kb > 0) {
131 memory_region_init_ram(&hms->vtcm, NULL, "vtcm.ram",
132 m_cfg->cfgtable.vtcm_size_kb * 1024,
133 &error_fatal);
134 memory_region_add_subregion(sysmem, m_cfg->cfgtable.vtcm_base << 16,
135 &hms->vtcm);
136 }
137
138 hms->cluster = cluster_create(hms);
139 hms->l2vic = l2vic_create(hms, m_cfg);
140 hms->qtimer = qtimer_create(hms, m_cfg);
141 hms->glob_regs = globalreg_create(hms, m_cfg, rev);
142 hms->tlb = tlb_create(hms, m_cfg);
143 }
144
145 void hex_subsys_add_cpu(HexagonCommonMachineState *hms, DeviceState *cpu)
146 {
147 object_property_add_child(OBJECT(hms->cluster), "cpu[*]", OBJECT(cpu));
148 object_property_set_link(OBJECT(cpu), "global-regs",
149 OBJECT(hms->glob_regs), &error_fatal);
150 object_property_set_link(OBJECT(cpu), "tlb", OBJECT(hms->tlb),
151 &error_fatal);
152 object_property_set_link(OBJECT(cpu), "l2vic", OBJECT(hms->l2vic),
153 &error_fatal);
154 }
155
156 void hex_subsys_realize_cluster(HexagonCommonMachineState *hms)
157 {
158 /*
159 * The cluster must be realized after its CPUs have been parented into it
160 * (see hex_subsys_add_cpu()) but before any CPU is itself realized, since
161 * qdev_realize_and_unref() on a CPU latches cluster_index into the TCG
162 * cflags at that point.
163 */
164 qdev_realize_and_unref(hms->cluster, NULL, &error_fatal);
165 }
166
167 void hex_subsys_realize_cpu(HexagonCommonMachineState *hms, DeviceState *cpu,
168 bool boot_cpu)
169 {
170 qdev_realize_and_unref(cpu, NULL, &error_fatal);
171
172 if (boot_cpu) {
173 l2vic_connect_cpu(hms->l2vic, cpu);
174 }
175 }