1
target-arm queue for softfreeze: this is quite big as I
1
Last minute pullreq for arm related patches; quite large because
2
was on holiday last week, so this is all just sneaking in
2
there were several series that only just made it through code review
3
under the wire. I particularly wanted to get Philippe's
3
in time.
4
patches in before freeze as that sort of code-movement
5
patchset is painful to have to rebase.
6
4
7
thanks
5
thanks
8
-- PMM
6
-- PMM
9
7
10
The following changes since commit ae9108f8f0746ce64d02afb1a216153a50926132:
8
The following changes since commit 091e3e3dbc499d84c004e1c50bc9870af37f6e99:
11
9
12
Merge remote-tracking branch 'remotes/vivier2/tags/linux-user-for-4.1-pull-request' into staging (2019-07-01 15:55:40 +0100)
10
Merge remote-tracking branch 'remotes/ericb/tags/pull-bitmaps-2020-10-26' into staging (2020-10-26 22:36:35 +0000)
13
11
14
are available in the Git repository at:
12
are available in the Git repository at:
15
13
16
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20190701
14
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20201027-1
17
15
18
for you to fetch changes up to 787a7e76c2e93a48c47b324fea592c9910a70483:
16
for you to fetch changes up to 32bd322a0134ed89db00f2b9b3894982db3dedcb:
19
17
20
target/arm: Declare some M-profile functions publicly (2019-07-01 17:29:01 +0100)
18
hw/timer/armv7m_systick: Rewrite to use ptimers (2020-10-27 11:15:31 +0000)
21
19
22
----------------------------------------------------------------
20
----------------------------------------------------------------
23
target-arm queue:
21
target-arm queue:
24
* hw/arm/boot: fix direct kernel boot with initrd
22
* raspi: add model of cprman clock manager
25
* hw/arm/msf2-som: Exit when the cpu is not the expected one
23
* sbsa-ref: add an SBSA generic watchdog device
26
* i.mx7: fix bugs in PCI controller needed to boot recent kernels
24
* arm/trace: Fix hex printing
27
* aspeed: add RTC device
25
* raspi: Add models of Pi 3 model A+, Pi Zero and Pi A+
28
* aspeed: fix some timer device bugs
26
* hw/arm/smmuv3: Set the restoration priority of the vSMMUv3 explicitly
29
* aspeed: add swift-bmc board
27
* Nuvoton NPCM7xx: Add USB, RNG, GPIO and watchdog support
30
* aspeed: vic: Add support for legacy register interface
28
* hw/arm: fix min_cpus for xlnx-versal-virt platform
31
* aspeed: add aspeed-xdma device
29
* hw/arm/highbank: Silence warnings about missing fallthrough statements
32
* Add new sbsa-ref board for aarch64
30
* linux-user: Support Aarch64 BTI
33
* target/arm: code refactoring in preparation for support of
31
* Armv7M systick: fix corner case bugs by rewriting to use ptimer
34
compilation with TCG disabled
35
32
36
----------------------------------------------------------------
33
----------------------------------------------------------------
37
Adriana Kobylak (1):
34
Dr. David Alan Gilbert (1):
38
aspeed: Add support for the swift-bmc board
35
arm/trace: Fix hex printing
39
36
40
Andrew Jeffery (3):
37
Hao Wu (1):
41
aspeed/timer: Status register contains reload for stopped timer
38
hw/timer: Adding watchdog for NPCM7XX Timer.
42
aspeed/timer: Fix match calculations
43
aspeed: vic: Add support for legacy register interface
44
39
45
Andrew Jones (1):
40
Havard Skinnemoen (4):
46
hw/arm/boot: fix direct kernel boot with initrd
41
Move npcm7xx_timer_reached_zero call out of npcm7xx_timer_pause
42
hw/misc: Add npcm7xx random number generator
43
hw/arm/npcm7xx: Add EHCI and OHCI controllers
44
hw/gpio: Add GPIO model for Nuvoton NPCM7xx
47
45
48
Andrey Smirnov (5):
46
Luc Michel (14):
49
i.mx7d: Add no-op/unimplemented APBH DMA module
47
hw/core/clock: provide the VMSTATE_ARRAY_CLOCK macro
50
i.mx7d: Add no-op/unimplemented PCIE PHY IP block
48
hw/core/clock: trace clock values in Hz instead of ns
51
pci: designware: Update MSI mapping unconditionally
49
hw/arm/raspi: fix CPRMAN base address
52
pci: designware: Update MSI mapping when MSI address changes
50
hw/arm/raspi: add a skeleton implementation of the CPRMAN
53
i.mx7d: pci: Update PCI IRQ mapping to match HW
51
hw/misc/bcm2835_cprman: add a PLL skeleton implementation
52
hw/misc/bcm2835_cprman: implement PLLs behaviour
53
hw/misc/bcm2835_cprman: add a PLL channel skeleton implementation
54
hw/misc/bcm2835_cprman: implement PLL channels behaviour
55
hw/misc/bcm2835_cprman: add a clock mux skeleton implementation
56
hw/misc/bcm2835_cprman: implement clock mux behaviour
57
hw/misc/bcm2835_cprman: add the DSI0HSCK multiplexer
58
hw/misc/bcm2835_cprman: add sane reset values to the registers
59
hw/char/pl011: add a clock input
60
hw/arm/bcm2835_peripherals: connect the UART clock
54
61
55
Christian Svensson (1):
62
Pavel Dovgalyuk (1):
56
aspeed/timer: Ensure positive muldiv delta
63
hw/arm: fix min_cpus for xlnx-versal-virt platform
57
64
58
Cédric Le Goater (7):
65
Peter Maydell (2):
59
aspeed: add a per SoC mapping for the interrupt space
66
hw/core/ptimer: Support ptimer being disabled by timer callback
60
aspeed: add a per SoC mapping for the memory space
67
hw/timer/armv7m_systick: Rewrite to use ptimers
61
aspeed: introduce a configurable number of CPU per machine
62
aspeed: add support for multiple NICs
63
aspeed: remove the "ram" link
64
aspeed: add a RAM memory region container
65
aspeed/smc: add a 'sdram_base' property
66
68
67
Eddie James (1):
69
Philippe Mathieu-Daudé (10):
68
hw/misc/aspeed_xdma: New device
70
linux-user/elfload: Avoid leaking interp_name using GLib memory API
71
hw/arm/bcm2836: Restrict BCM283XInfo declaration to C source
72
hw/arm/bcm2836: QOM'ify more by adding class_init() to each SoC type
73
hw/arm/bcm2836: Introduce BCM283XClass::core_count
74
hw/arm/bcm2836: Only provide "enabled-cpus" property to multicore SoCs
75
hw/arm/bcm2836: Split out common realize() code
76
hw/arm/bcm2836: Introduce the BCM2835 SoC
77
hw/arm/raspi: Add the Raspberry Pi A+ machine
78
hw/arm/raspi: Add the Raspberry Pi Zero machine
79
hw/arm/raspi: Add the Raspberry Pi 3 model A+
69
80
70
Hongbo Zhang (2):
81
Richard Henderson (11):
71
hw/arm: Add arm SBSA reference machine, skeleton part
82
linux-user/aarch64: Reset btype for signals
72
hw/arm: Add arm SBSA reference machine, devices part
83
linux-user: Set PAGE_TARGET_1 for TARGET_PROT_BTI
84
include/elf: Add defines related to GNU property notes for AArch64
85
linux-user/elfload: Fix coding style in load_elf_image
86
linux-user/elfload: Adjust iteration over phdr
87
linux-user/elfload: Move PT_INTERP detection to first loop
88
linux-user/elfload: Use Error for load_elf_image
89
linux-user/elfload: Use Error for load_elf_interp
90
linux-user/elfload: Parse NT_GNU_PROPERTY_TYPE_0 notes
91
linux-user/elfload: Parse GNU_PROPERTY_AARCH64_FEATURE_1_AND
92
tests/tcg/aarch64: Add bti smoke tests
73
93
74
Jan Kiszka (1):
94
Shashi Mallela (2):
75
hw/arm/virt: Add support for Cortex-A7
95
hw/watchdog: Implement SBSA watchdog device
96
hw/arm/sbsa-ref: add SBSA watchdog device
76
97
77
Joel Stanley (4):
98
Thomas Huth (1):
78
hw: timer: Add ASPEED RTC device
99
hw/arm/highbank: Silence warnings about missing fallthrough statements
79
hw/arm/aspeed: Add RTC to SoC
80
aspeed/timer: Fix behaviour running Linux
81
aspeed: Link SCU to the watchdog
82
100
83
Philippe Mathieu-Daudé (19):
101
Zenghui Yu (1):
84
hw/arm/msf2-som: Exit when the cpu is not the expected one
102
hw/arm/smmuv3: Set the restoration priority of the vSMMUv3 explicitly
85
target/arm: Makefile cleanup (Aarch64)
86
target/arm: Makefile cleanup (ARM)
87
target/arm: Makefile cleanup (KVM)
88
target/arm: Makefile cleanup (softmmu)
89
target/arm: Add copyright boilerplate
90
target/arm/helper: Remove unused include
91
target/arm: Fix multiline comment syntax
92
target/arm: Fix coding style issues
93
target/arm: Move CPU state dumping routines to cpu.c
94
target/arm: Declare get_phys_addr() function publicly
95
target/arm: Move TLB related routines to tlb_helper.c
96
target/arm/vfp_helper: Move code around
97
target/arm/vfp_helper: Extract vfp_set_fpscr_to_host()
98
target/arm/vfp_helper: Extract vfp_set_fpscr_from_host()
99
target/arm/vfp_helper: Restrict the SoftFloat use to TCG
100
target/arm: Restrict PSCI to TCG
101
target/arm: Declare arm_log_exception() function publicly
102
target/arm: Declare some M-profile functions publicly
103
103
104
Samuel Ortiz (1):
104
docs/system/arm/nuvoton.rst | 6 +-
105
target/arm: Move the DC ZVA helper into op_helper
105
hw/usb/hcd-ehci.h | 1 +
106
include/elf.h | 22 +
107
include/exec/cpu-all.h | 2 +
108
include/hw/arm/bcm2835_peripherals.h | 5 +-
109
include/hw/arm/bcm2836.h | 9 +-
110
include/hw/arm/npcm7xx.h | 8 +
111
include/hw/arm/raspi_platform.h | 5 +-
112
include/hw/char/pl011.h | 1 +
113
include/hw/clock.h | 5 +
114
include/hw/gpio/npcm7xx_gpio.h | 55 ++
115
include/hw/misc/bcm2835_cprman.h | 210 ++++++
116
include/hw/misc/bcm2835_cprman_internals.h | 1019 ++++++++++++++++++++++++++++
117
include/hw/misc/npcm7xx_clk.h | 2 +
118
include/hw/misc/npcm7xx_rng.h | 34 +
119
include/hw/timer/armv7m_systick.h | 3 +-
120
include/hw/timer/npcm7xx_timer.h | 48 +-
121
include/hw/watchdog/sbsa_gwdt.h | 79 +++
122
linux-user/qemu.h | 4 +
123
linux-user/syscall_defs.h | 4 +
124
target/arm/cpu.h | 5 +
125
hw/arm/bcm2835_peripherals.c | 15 +-
126
hw/arm/bcm2836.c | 182 +++--
127
hw/arm/highbank.c | 2 +
128
hw/arm/npcm7xx.c | 126 +++-
129
hw/arm/raspi.c | 41 ++
130
hw/arm/sbsa-ref.c | 23 +
131
hw/arm/smmuv3.c | 1 +
132
hw/arm/xlnx-versal-virt.c | 1 +
133
hw/char/pl011.c | 45 ++
134
hw/core/clock.c | 6 +-
135
hw/core/ptimer.c | 4 +
136
hw/gpio/npcm7xx_gpio.c | 424 ++++++++++++
137
hw/misc/bcm2835_cprman.c | 808 ++++++++++++++++++++++
138
hw/misc/npcm7xx_clk.c | 28 +
139
hw/misc/npcm7xx_rng.c | 180 +++++
140
hw/timer/armv7m_systick.c | 124 ++--
141
hw/timer/npcm7xx_timer.c | 270 ++++++--
142
hw/usb/hcd-ehci-sysbus.c | 19 +
143
hw/watchdog/sbsa_gwdt.c | 293 ++++++++
144
linux-user/aarch64/signal.c | 10 +-
145
linux-user/elfload.c | 326 +++++++--
146
linux-user/mmap.c | 16 +
147
target/arm/translate-a64.c | 6 +-
148
tests/qtest/npcm7xx_gpio-test.c | 385 +++++++++++
149
tests/qtest/npcm7xx_rng-test.c | 278 ++++++++
150
tests/qtest/npcm7xx_watchdog_timer-test.c | 319 +++++++++
151
tests/tcg/aarch64/bti-1.c | 62 ++
152
tests/tcg/aarch64/bti-2.c | 116 ++++
153
tests/tcg/aarch64/bti-crt.inc.c | 51 ++
154
MAINTAINERS | 1 +
155
hw/arm/Kconfig | 1 +
156
hw/arm/trace-events | 2 +-
157
hw/char/trace-events | 1 +
158
hw/core/trace-events | 4 +-
159
hw/gpio/meson.build | 1 +
160
hw/gpio/trace-events | 7 +
161
hw/misc/meson.build | 2 +
162
hw/misc/trace-events | 9 +
163
hw/watchdog/Kconfig | 3 +
164
hw/watchdog/meson.build | 1 +
165
tests/qtest/meson.build | 6 +-
166
tests/tcg/aarch64/Makefile.target | 10 +
167
tests/tcg/configure.sh | 4 +
168
64 files changed, 5461 insertions(+), 279 deletions(-)
169
create mode 100644 include/hw/gpio/npcm7xx_gpio.h
170
create mode 100644 include/hw/misc/bcm2835_cprman.h
171
create mode 100644 include/hw/misc/bcm2835_cprman_internals.h
172
create mode 100644 include/hw/misc/npcm7xx_rng.h
173
create mode 100644 include/hw/watchdog/sbsa_gwdt.h
174
create mode 100644 hw/gpio/npcm7xx_gpio.c
175
create mode 100644 hw/misc/bcm2835_cprman.c
176
create mode 100644 hw/misc/npcm7xx_rng.c
177
create mode 100644 hw/watchdog/sbsa_gwdt.c
178
create mode 100644 tests/qtest/npcm7xx_gpio-test.c
179
create mode 100644 tests/qtest/npcm7xx_rng-test.c
180
create mode 100644 tests/qtest/npcm7xx_watchdog_timer-test.c
181
create mode 100644 tests/tcg/aarch64/bti-1.c
182
create mode 100644 tests/tcg/aarch64/bti-2.c
183
create mode 100644 tests/tcg/aarch64/bti-crt.inc.c
106
184
107
hw/arm/Makefile.objs | 1 +
108
hw/misc/Makefile.objs | 1 +
109
hw/timer/Makefile.objs | 2 +-
110
target/arm/Makefile.objs | 24 +-
111
include/hw/arm/aspeed_soc.h | 53 ++-
112
include/hw/arm/fsl-imx7.h | 14 +-
113
include/hw/misc/aspeed_xdma.h | 30 ++
114
include/hw/ssi/aspeed_smc.h | 3 +
115
include/hw/timer/aspeed_rtc.h | 31 ++
116
include/hw/watchdog/wdt_aspeed.h | 1 +
117
target/arm/cpu.h | 2 -
118
target/arm/internals.h | 69 ++-
119
target/arm/translate.h | 5 -
120
hw/arm/aspeed.c | 76 +++-
121
hw/arm/aspeed_soc.c | 262 +++++++++---
122
hw/arm/boot.c | 3 +-
123
hw/arm/fsl-imx7.c | 11 +
124
hw/arm/msf2-som.c | 1 +
125
hw/arm/sbsa-ref.c | 806 ++++++++++++++++++++++++++++++++++++
126
hw/arm/virt.c | 1 +
127
hw/intc/aspeed_vic.c | 105 +++--
128
hw/misc/aspeed_xdma.c | 165 ++++++++
129
hw/pci-host/designware.c | 18 +-
130
hw/ssi/aspeed_smc.c | 1 +
131
hw/timer/aspeed_rtc.c | 180 ++++++++
132
hw/timer/aspeed_timer.c | 76 ++--
133
hw/watchdog/wdt_aspeed.c | 20 +
134
target/arm/cpu.c | 232 ++++++++++-
135
target/arm/helper.c | 498 +++++++++-------------
136
target/arm/op_helper.c | 262 ++++++------
137
target/arm/tlb_helper.c | 200 +++++++++
138
target/arm/translate-a64.c | 128 ------
139
target/arm/translate.c | 91 +---
140
target/arm/vfp_helper.c | 199 +++++----
141
MAINTAINERS | 8 +
142
default-configs/aarch64-softmmu.mak | 1 +
143
hw/arm/Kconfig | 14 +
144
hw/misc/trace-events | 3 +
145
hw/timer/trace-events | 4 +
146
39 files changed, 2675 insertions(+), 926 deletions(-)
147
create mode 100644 include/hw/misc/aspeed_xdma.h
148
create mode 100644 include/hw/timer/aspeed_rtc.h
149
create mode 100644 hw/arm/sbsa-ref.c
150
create mode 100644 hw/misc/aspeed_xdma.c
151
create mode 100644 hw/timer/aspeed_rtc.c
152
create mode 100644 target/arm/tlb_helper.c
153
diff view generated by jsdifflib
New patch
1
From: Richard Henderson <richard.henderson@linaro.org>
1
2
3
The kernel sets btype for the signal handler as if for a call.
4
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20201021173749.111103-2-richard.henderson@linaro.org
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
10
linux-user/aarch64/signal.c | 10 ++++++++--
11
1 file changed, 8 insertions(+), 2 deletions(-)
12
13
diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/linux-user/aarch64/signal.c
16
+++ b/linux-user/aarch64/signal.c
17
@@ -XXX,XX +XXX,XX @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
18
+ offsetof(struct target_rt_frame_record, tramp);
19
}
20
env->xregs[0] = usig;
21
- env->xregs[31] = frame_addr;
22
env->xregs[29] = frame_addr + fr_ofs;
23
- env->pc = ka->_sa_handler;
24
env->xregs[30] = return_addr;
25
+ env->xregs[31] = frame_addr;
26
+ env->pc = ka->_sa_handler;
27
+
28
+ /* Invoke the signal handler as if by indirect call. */
29
+ if (cpu_isar_feature(aa64_bti, env_archcpu(env))) {
30
+ env->btype = 2;
31
+ }
32
+
33
if (info) {
34
tswap_siginfo(&frame->info, info);
35
env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
36
--
37
2.20.1
38
39
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Suggested-by: Samuel Ortiz <sameo@linux.intel.com>
3
Transform the prot bit to a qemu internal page bit, and save
4
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
4
it in the page tables.
5
Message-id: 20190701132516.26392-11-philmd@redhat.com
5
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20201021173749.111103-3-richard.henderson@linaro.org
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
---
10
---
9
target/arm/cpu.h | 2 -
11
include/exec/cpu-all.h | 2 ++
10
target/arm/translate.h | 5 -
12
linux-user/syscall_defs.h | 4 ++++
11
target/arm/cpu.c | 226 +++++++++++++++++++++++++++++++++++++
13
target/arm/cpu.h | 5 +++++
12
target/arm/translate-a64.c | 128 ---------------------
14
linux-user/mmap.c | 16 ++++++++++++++++
13
target/arm/translate.c | 88 ---------------
15
target/arm/translate-a64.c | 6 +++---
14
5 files changed, 226 insertions(+), 223 deletions(-)
16
5 files changed, 30 insertions(+), 3 deletions(-)
15
17
18
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
19
index XXXXXXX..XXXXXXX 100644
20
--- a/include/exec/cpu-all.h
21
+++ b/include/exec/cpu-all.h
22
@@ -XXX,XX +XXX,XX @@ extern intptr_t qemu_host_page_mask;
23
/* FIXME: Code that sets/uses this is broken and needs to go away. */
24
#define PAGE_RESERVED 0x0020
25
#endif
26
+/* Target-specific bits that will be used via page_get_flags(). */
27
+#define PAGE_TARGET_1 0x0080
28
29
#if defined(CONFIG_USER_ONLY)
30
void page_dump(FILE *f);
31
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
32
index XXXXXXX..XXXXXXX 100644
33
--- a/linux-user/syscall_defs.h
34
+++ b/linux-user/syscall_defs.h
35
@@ -XXX,XX +XXX,XX @@ struct target_winsize {
36
#define TARGET_PROT_SEM 0x08
37
#endif
38
39
+#ifdef TARGET_AARCH64
40
+#define TARGET_PROT_BTI 0x10
41
+#endif
42
+
43
/* Common */
44
#define TARGET_MAP_SHARED    0x01        /* Share changes */
45
#define TARGET_MAP_PRIVATE    0x02        /* Changes are private */
16
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
46
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
17
index XXXXXXX..XXXXXXX 100644
47
index XXXXXXX..XXXXXXX 100644
18
--- a/target/arm/cpu.h
48
--- a/target/arm/cpu.h
19
+++ b/target/arm/cpu.h
49
+++ b/target/arm/cpu.h
20
@@ -XXX,XX +XXX,XX @@ void arm_cpu_do_interrupt(CPUState *cpu);
50
@@ -XXX,XX +XXX,XX @@ static inline MemTxAttrs *typecheck_memtxattrs(MemTxAttrs *x)
21
void arm_v7m_cpu_do_interrupt(CPUState *cpu);
51
#define arm_tlb_bti_gp(x) (typecheck_memtxattrs(x)->target_tlb_bit0)
22
bool arm_cpu_exec_interrupt(CPUState *cpu, int int_req);
52
#define arm_tlb_mte_tagged(x) (typecheck_memtxattrs(x)->target_tlb_bit1)
23
53
24
-void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags);
54
+/*
25
-
55
+ * AArch64 usage of the PAGE_TARGET_* bits for linux-user.
26
hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
56
+ */
27
MemTxAttrs *attrs);
57
+#define PAGE_BTI PAGE_TARGET_1
28
58
+
29
diff --git a/target/arm/translate.h b/target/arm/translate.h
59
/*
60
* Naming convention for isar_feature functions:
61
* Functions which test 32-bit ID registers should have _aa32_ in
62
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
30
index XXXXXXX..XXXXXXX 100644
63
index XXXXXXX..XXXXXXX 100644
31
--- a/target/arm/translate.h
64
--- a/linux-user/mmap.c
32
+++ b/target/arm/translate.h
65
+++ b/linux-user/mmap.c
33
@@ -XXX,XX +XXX,XX @@ static inline void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
66
@@ -XXX,XX +XXX,XX @@ static int validate_prot_to_pageflags(int *host_prot, int prot)
34
#ifdef TARGET_AARCH64
67
*host_prot = (prot & (PROT_READ | PROT_WRITE))
35
void a64_translate_init(void);
68
| (prot & PROT_EXEC ? PROT_READ : 0);
36
void gen_a64_set_pc_im(uint64_t val);
37
-void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags);
38
extern const TranslatorOps aarch64_translator_ops;
39
#else
40
static inline void a64_translate_init(void)
41
@@ -XXX,XX +XXX,XX @@ static inline void a64_translate_init(void)
42
static inline void gen_a64_set_pc_im(uint64_t val)
43
{
44
}
45
-
46
-static inline void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
47
-{
48
-}
49
#endif
50
51
void arm_test_cc(DisasCompare *cmp, int cc);
52
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
53
index XXXXXXX..XXXXXXX 100644
54
--- a/target/arm/cpu.c
55
+++ b/target/arm/cpu.c
56
@@ -XXX,XX +XXX,XX @@
57
*/
58
59
#include "qemu/osdep.h"
60
+#include "qemu/qemu-print.h"
61
#include "qemu-common.h"
62
#include "target/arm/idau.h"
63
#include "qemu/module.h"
64
@@ -XXX,XX +XXX,XX @@ static void arm_disas_set_info(CPUState *cpu, disassemble_info *info)
65
#endif
66
}
67
69
68
+#ifdef TARGET_AARCH64
70
+#ifdef TARGET_AARCH64
69
+
71
+ /*
70
+static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
72
+ * The PROT_BTI bit is only accepted if the cpu supports the feature.
71
+{
73
+ * Since this is the unusual case, don't bother checking unless
72
+ ARMCPU *cpu = ARM_CPU(cs);
74
+ * the bit has been requested. If set and valid, record the bit
73
+ CPUARMState *env = &cpu->env;
75
+ * within QEMU's page_flags.
74
+ uint32_t psr = pstate_read(env);
76
+ */
75
+ int i;
77
+ if (prot & TARGET_PROT_BTI) {
76
+ int el = arm_current_el(env);
78
+ ARMCPU *cpu = ARM_CPU(thread_cpu);
77
+ const char *ns_status;
79
+ if (cpu_isar_feature(aa64_bti, cpu)) {
78
+
80
+ valid |= TARGET_PROT_BTI;
79
+ qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc);
81
+ page_flags |= PAGE_BTI;
80
+ for (i = 0; i < 32; i++) {
81
+ if (i == 31) {
82
+ qemu_fprintf(f, " SP=%016" PRIx64 "\n", env->xregs[i]);
83
+ } else {
84
+ qemu_fprintf(f, "X%02d=%016" PRIx64 "%s", i, env->xregs[i],
85
+ (i + 2) % 3 ? " " : "\n");
86
+ }
82
+ }
87
+ }
83
+ }
88
+
89
+ if (arm_feature(env, ARM_FEATURE_EL3) && el != 3) {
90
+ ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
91
+ } else {
92
+ ns_status = "";
93
+ }
94
+ qemu_fprintf(f, "PSTATE=%08x %c%c%c%c %sEL%d%c",
95
+ psr,
96
+ psr & PSTATE_N ? 'N' : '-',
97
+ psr & PSTATE_Z ? 'Z' : '-',
98
+ psr & PSTATE_C ? 'C' : '-',
99
+ psr & PSTATE_V ? 'V' : '-',
100
+ ns_status,
101
+ el,
102
+ psr & PSTATE_SP ? 'h' : 't');
103
+
104
+ if (cpu_isar_feature(aa64_bti, cpu)) {
105
+ qemu_fprintf(f, " BTYPE=%d", (psr & PSTATE_BTYPE) >> 10);
106
+ }
107
+ if (!(flags & CPU_DUMP_FPU)) {
108
+ qemu_fprintf(f, "\n");
109
+ return;
110
+ }
111
+ if (fp_exception_el(env, el) != 0) {
112
+ qemu_fprintf(f, " FPU disabled\n");
113
+ return;
114
+ }
115
+ qemu_fprintf(f, " FPCR=%08x FPSR=%08x\n",
116
+ vfp_get_fpcr(env), vfp_get_fpsr(env));
117
+
118
+ if (cpu_isar_feature(aa64_sve, cpu) && sve_exception_el(env, el) == 0) {
119
+ int j, zcr_len = sve_zcr_len_for_el(env, el);
120
+
121
+ for (i = 0; i <= FFR_PRED_NUM; i++) {
122
+ bool eol;
123
+ if (i == FFR_PRED_NUM) {
124
+ qemu_fprintf(f, "FFR=");
125
+ /* It's last, so end the line. */
126
+ eol = true;
127
+ } else {
128
+ qemu_fprintf(f, "P%02d=", i);
129
+ switch (zcr_len) {
130
+ case 0:
131
+ eol = i % 8 == 7;
132
+ break;
133
+ case 1:
134
+ eol = i % 6 == 5;
135
+ break;
136
+ case 2:
137
+ case 3:
138
+ eol = i % 3 == 2;
139
+ break;
140
+ default:
141
+ /* More than one quadword per predicate. */
142
+ eol = true;
143
+ break;
144
+ }
145
+ }
146
+ for (j = zcr_len / 4; j >= 0; j--) {
147
+ int digits;
148
+ if (j * 4 + 4 <= zcr_len + 1) {
149
+ digits = 16;
150
+ } else {
151
+ digits = (zcr_len % 4 + 1) * 4;
152
+ }
153
+ qemu_fprintf(f, "%0*" PRIx64 "%s", digits,
154
+ env->vfp.pregs[i].p[j],
155
+ j ? ":" : eol ? "\n" : " ");
156
+ }
157
+ }
158
+
159
+ for (i = 0; i < 32; i++) {
160
+ if (zcr_len == 0) {
161
+ qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64 "%s",
162
+ i, env->vfp.zregs[i].d[1],
163
+ env->vfp.zregs[i].d[0], i & 1 ? "\n" : " ");
164
+ } else if (zcr_len == 1) {
165
+ qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64
166
+ ":%016" PRIx64 ":%016" PRIx64 "\n",
167
+ i, env->vfp.zregs[i].d[3], env->vfp.zregs[i].d[2],
168
+ env->vfp.zregs[i].d[1], env->vfp.zregs[i].d[0]);
169
+ } else {
170
+ for (j = zcr_len; j >= 0; j--) {
171
+ bool odd = (zcr_len - j) % 2 != 0;
172
+ if (j == zcr_len) {
173
+ qemu_fprintf(f, "Z%02d[%x-%x]=", i, j, j - 1);
174
+ } else if (!odd) {
175
+ if (j > 0) {
176
+ qemu_fprintf(f, " [%x-%x]=", j, j - 1);
177
+ } else {
178
+ qemu_fprintf(f, " [%x]=", j);
179
+ }
180
+ }
181
+ qemu_fprintf(f, "%016" PRIx64 ":%016" PRIx64 "%s",
182
+ env->vfp.zregs[i].d[j * 2 + 1],
183
+ env->vfp.zregs[i].d[j * 2],
184
+ odd || j == 0 ? "\n" : ":");
185
+ }
186
+ }
187
+ }
188
+ } else {
189
+ for (i = 0; i < 32; i++) {
190
+ uint64_t *q = aa64_vfp_qreg(env, i);
191
+ qemu_fprintf(f, "Q%02d=%016" PRIx64 ":%016" PRIx64 "%s",
192
+ i, q[1], q[0], (i & 1 ? "\n" : " "));
193
+ }
194
+ }
195
+}
196
+
197
+#else
198
+
199
+static inline void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
200
+{
201
+ g_assert_not_reached();
202
+}
203
+
204
+#endif
84
+#endif
205
+
85
+
206
+static void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags)
86
return prot & ~valid ? 0 : page_flags;
207
+{
87
}
208
+ ARMCPU *cpu = ARM_CPU(cs);
88
209
+ CPUARMState *env = &cpu->env;
210
+ int i;
211
+
212
+ if (is_a64(env)) {
213
+ aarch64_cpu_dump_state(cs, f, flags);
214
+ return;
215
+ }
216
+
217
+ for (i = 0; i < 16; i++) {
218
+ qemu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
219
+ if ((i % 4) == 3) {
220
+ qemu_fprintf(f, "\n");
221
+ } else {
222
+ qemu_fprintf(f, " ");
223
+ }
224
+ }
225
+
226
+ if (arm_feature(env, ARM_FEATURE_M)) {
227
+ uint32_t xpsr = xpsr_read(env);
228
+ const char *mode;
229
+ const char *ns_status = "";
230
+
231
+ if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
232
+ ns_status = env->v7m.secure ? "S " : "NS ";
233
+ }
234
+
235
+ if (xpsr & XPSR_EXCP) {
236
+ mode = "handler";
237
+ } else {
238
+ if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_NPRIV_MASK) {
239
+ mode = "unpriv-thread";
240
+ } else {
241
+ mode = "priv-thread";
242
+ }
243
+ }
244
+
245
+ qemu_fprintf(f, "XPSR=%08x %c%c%c%c %c %s%s\n",
246
+ xpsr,
247
+ xpsr & XPSR_N ? 'N' : '-',
248
+ xpsr & XPSR_Z ? 'Z' : '-',
249
+ xpsr & XPSR_C ? 'C' : '-',
250
+ xpsr & XPSR_V ? 'V' : '-',
251
+ xpsr & XPSR_T ? 'T' : 'A',
252
+ ns_status,
253
+ mode);
254
+ } else {
255
+ uint32_t psr = cpsr_read(env);
256
+ const char *ns_status = "";
257
+
258
+ if (arm_feature(env, ARM_FEATURE_EL3) &&
259
+ (psr & CPSR_M) != ARM_CPU_MODE_MON) {
260
+ ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
261
+ }
262
+
263
+ qemu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%s%d\n",
264
+ psr,
265
+ psr & CPSR_N ? 'N' : '-',
266
+ psr & CPSR_Z ? 'Z' : '-',
267
+ psr & CPSR_C ? 'C' : '-',
268
+ psr & CPSR_V ? 'V' : '-',
269
+ psr & CPSR_T ? 'T' : 'A',
270
+ ns_status,
271
+ aarch32_mode_name(psr), (psr & 0x10) ? 32 : 26);
272
+ }
273
+
274
+ if (flags & CPU_DUMP_FPU) {
275
+ int numvfpregs = 0;
276
+ if (arm_feature(env, ARM_FEATURE_VFP)) {
277
+ numvfpregs += 16;
278
+ }
279
+ if (arm_feature(env, ARM_FEATURE_VFP3)) {
280
+ numvfpregs += 16;
281
+ }
282
+ for (i = 0; i < numvfpregs; i++) {
283
+ uint64_t v = *aa32_vfp_dreg(env, i);
284
+ qemu_fprintf(f, "s%02d=%08x s%02d=%08x d%02d=%016" PRIx64 "\n",
285
+ i * 2, (uint32_t)v,
286
+ i * 2 + 1, (uint32_t)(v >> 32),
287
+ i, v);
288
+ }
289
+ qemu_fprintf(f, "FPSCR: %08x\n", vfp_get_fpscr(env));
290
+ }
291
+}
292
+
293
uint64_t arm_cpu_mp_affinity(int idx, uint8_t clustersz)
294
{
295
uint32_t Aff1 = idx / clustersz;
296
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
89
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
297
index XXXXXXX..XXXXXXX 100644
90
index XXXXXXX..XXXXXXX 100644
298
--- a/target/arm/translate-a64.c
91
--- a/target/arm/translate-a64.c
299
+++ b/target/arm/translate-a64.c
92
+++ b/target/arm/translate-a64.c
300
@@ -XXX,XX +XXX,XX @@
93
@@ -XXX,XX +XXX,XX @@ static void disas_data_proc_simd_fp(DisasContext *s, uint32_t insn)
301
#include "translate.h"
94
*/
302
#include "internals.h"
95
static bool is_guarded_page(CPUARMState *env, DisasContext *s)
303
#include "qemu/host-utils.h"
304
-#include "qemu/qemu-print.h"
305
306
#include "hw/semihosting/semihost.h"
307
#include "exec/gen-icount.h"
308
@@ -XXX,XX +XXX,XX @@ static void set_btype(DisasContext *s, int val)
309
s->btype = -1;
310
}
311
312
-void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags)
313
-{
314
- ARMCPU *cpu = ARM_CPU(cs);
315
- CPUARMState *env = &cpu->env;
316
- uint32_t psr = pstate_read(env);
317
- int i;
318
- int el = arm_current_el(env);
319
- const char *ns_status;
320
-
321
- qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc);
322
- for (i = 0; i < 32; i++) {
323
- if (i == 31) {
324
- qemu_fprintf(f, " SP=%016" PRIx64 "\n", env->xregs[i]);
325
- } else {
326
- qemu_fprintf(f, "X%02d=%016" PRIx64 "%s", i, env->xregs[i],
327
- (i + 2) % 3 ? " " : "\n");
328
- }
329
- }
330
-
331
- if (arm_feature(env, ARM_FEATURE_EL3) && el != 3) {
332
- ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
333
- } else {
334
- ns_status = "";
335
- }
336
- qemu_fprintf(f, "PSTATE=%08x %c%c%c%c %sEL%d%c",
337
- psr,
338
- psr & PSTATE_N ? 'N' : '-',
339
- psr & PSTATE_Z ? 'Z' : '-',
340
- psr & PSTATE_C ? 'C' : '-',
341
- psr & PSTATE_V ? 'V' : '-',
342
- ns_status,
343
- el,
344
- psr & PSTATE_SP ? 'h' : 't');
345
-
346
- if (cpu_isar_feature(aa64_bti, cpu)) {
347
- qemu_fprintf(f, " BTYPE=%d", (psr & PSTATE_BTYPE) >> 10);
348
- }
349
- if (!(flags & CPU_DUMP_FPU)) {
350
- qemu_fprintf(f, "\n");
351
- return;
352
- }
353
- if (fp_exception_el(env, el) != 0) {
354
- qemu_fprintf(f, " FPU disabled\n");
355
- return;
356
- }
357
- qemu_fprintf(f, " FPCR=%08x FPSR=%08x\n",
358
- vfp_get_fpcr(env), vfp_get_fpsr(env));
359
-
360
- if (cpu_isar_feature(aa64_sve, cpu) && sve_exception_el(env, el) == 0) {
361
- int j, zcr_len = sve_zcr_len_for_el(env, el);
362
-
363
- for (i = 0; i <= FFR_PRED_NUM; i++) {
364
- bool eol;
365
- if (i == FFR_PRED_NUM) {
366
- qemu_fprintf(f, "FFR=");
367
- /* It's last, so end the line. */
368
- eol = true;
369
- } else {
370
- qemu_fprintf(f, "P%02d=", i);
371
- switch (zcr_len) {
372
- case 0:
373
- eol = i % 8 == 7;
374
- break;
375
- case 1:
376
- eol = i % 6 == 5;
377
- break;
378
- case 2:
379
- case 3:
380
- eol = i % 3 == 2;
381
- break;
382
- default:
383
- /* More than one quadword per predicate. */
384
- eol = true;
385
- break;
386
- }
387
- }
388
- for (j = zcr_len / 4; j >= 0; j--) {
389
- int digits;
390
- if (j * 4 + 4 <= zcr_len + 1) {
391
- digits = 16;
392
- } else {
393
- digits = (zcr_len % 4 + 1) * 4;
394
- }
395
- qemu_fprintf(f, "%0*" PRIx64 "%s", digits,
396
- env->vfp.pregs[i].p[j],
397
- j ? ":" : eol ? "\n" : " ");
398
- }
399
- }
400
-
401
- for (i = 0; i < 32; i++) {
402
- if (zcr_len == 0) {
403
- qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64 "%s",
404
- i, env->vfp.zregs[i].d[1],
405
- env->vfp.zregs[i].d[0], i & 1 ? "\n" : " ");
406
- } else if (zcr_len == 1) {
407
- qemu_fprintf(f, "Z%02d=%016" PRIx64 ":%016" PRIx64
408
- ":%016" PRIx64 ":%016" PRIx64 "\n",
409
- i, env->vfp.zregs[i].d[3], env->vfp.zregs[i].d[2],
410
- env->vfp.zregs[i].d[1], env->vfp.zregs[i].d[0]);
411
- } else {
412
- for (j = zcr_len; j >= 0; j--) {
413
- bool odd = (zcr_len - j) % 2 != 0;
414
- if (j == zcr_len) {
415
- qemu_fprintf(f, "Z%02d[%x-%x]=", i, j, j - 1);
416
- } else if (!odd) {
417
- if (j > 0) {
418
- qemu_fprintf(f, " [%x-%x]=", j, j - 1);
419
- } else {
420
- qemu_fprintf(f, " [%x]=", j);
421
- }
422
- }
423
- qemu_fprintf(f, "%016" PRIx64 ":%016" PRIx64 "%s",
424
- env->vfp.zregs[i].d[j * 2 + 1],
425
- env->vfp.zregs[i].d[j * 2],
426
- odd || j == 0 ? "\n" : ":");
427
- }
428
- }
429
- }
430
- } else {
431
- for (i = 0; i < 32; i++) {
432
- uint64_t *q = aa64_vfp_qreg(env, i);
433
- qemu_fprintf(f, "Q%02d=%016" PRIx64 ":%016" PRIx64 "%s",
434
- i, q[1], q[0], (i & 1 ? "\n" : " "));
435
- }
436
- }
437
-}
438
-
439
void gen_a64_set_pc_im(uint64_t val)
440
{
96
{
441
tcg_gen_movi_i64(cpu_pc, val);
97
-#ifdef CONFIG_USER_ONLY
442
diff --git a/target/arm/translate.c b/target/arm/translate.c
98
- return false; /* FIXME */
443
index XXXXXXX..XXXXXXX 100644
99
-#else
444
--- a/target/arm/translate.c
100
uint64_t addr = s->base.pc_first;
445
+++ b/target/arm/translate.c
101
+#ifdef CONFIG_USER_ONLY
446
@@ -XXX,XX +XXX,XX @@
102
+ return page_get_flags(addr) & PAGE_BTI;
447
#include "tcg-op-gvec.h"
103
+#else
448
#include "qemu/log.h"
104
int mmu_idx = arm_to_core_mmu_idx(s->mmu_idx);
449
#include "qemu/bitops.h"
105
unsigned int index = tlb_index(env, mmu_idx, addr);
450
-#include "qemu/qemu-print.h"
106
CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr);
451
#include "arm_ldst.h"
452
#include "hw/semihosting/semihost.h"
453
454
@@ -XXX,XX +XXX,XX @@ void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns)
455
translator_loop(ops, &dc.base, cpu, tb, max_insns);
456
}
457
458
-void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags)
459
-{
460
- ARMCPU *cpu = ARM_CPU(cs);
461
- CPUARMState *env = &cpu->env;
462
- int i;
463
-
464
- if (is_a64(env)) {
465
- aarch64_cpu_dump_state(cs, f, flags);
466
- return;
467
- }
468
-
469
- for (i = 0; i < 16; i++) {
470
- qemu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
471
- if ((i % 4) == 3) {
472
- qemu_fprintf(f, "\n");
473
- } else {
474
- qemu_fprintf(f, " ");
475
- }
476
- }
477
-
478
- if (arm_feature(env, ARM_FEATURE_M)) {
479
- uint32_t xpsr = xpsr_read(env);
480
- const char *mode;
481
- const char *ns_status = "";
482
-
483
- if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
484
- ns_status = env->v7m.secure ? "S " : "NS ";
485
- }
486
-
487
- if (xpsr & XPSR_EXCP) {
488
- mode = "handler";
489
- } else {
490
- if (env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_NPRIV_MASK) {
491
- mode = "unpriv-thread";
492
- } else {
493
- mode = "priv-thread";
494
- }
495
- }
496
-
497
- qemu_fprintf(f, "XPSR=%08x %c%c%c%c %c %s%s\n",
498
- xpsr,
499
- xpsr & XPSR_N ? 'N' : '-',
500
- xpsr & XPSR_Z ? 'Z' : '-',
501
- xpsr & XPSR_C ? 'C' : '-',
502
- xpsr & XPSR_V ? 'V' : '-',
503
- xpsr & XPSR_T ? 'T' : 'A',
504
- ns_status,
505
- mode);
506
- } else {
507
- uint32_t psr = cpsr_read(env);
508
- const char *ns_status = "";
509
-
510
- if (arm_feature(env, ARM_FEATURE_EL3) &&
511
- (psr & CPSR_M) != ARM_CPU_MODE_MON) {
512
- ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
513
- }
514
-
515
- qemu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%s%d\n",
516
- psr,
517
- psr & CPSR_N ? 'N' : '-',
518
- psr & CPSR_Z ? 'Z' : '-',
519
- psr & CPSR_C ? 'C' : '-',
520
- psr & CPSR_V ? 'V' : '-',
521
- psr & CPSR_T ? 'T' : 'A',
522
- ns_status,
523
- aarch32_mode_name(psr), (psr & 0x10) ? 32 : 26);
524
- }
525
-
526
- if (flags & CPU_DUMP_FPU) {
527
- int numvfpregs = 0;
528
- if (arm_feature(env, ARM_FEATURE_VFP)) {
529
- numvfpregs += 16;
530
- }
531
- if (arm_feature(env, ARM_FEATURE_VFP3)) {
532
- numvfpregs += 16;
533
- }
534
- for (i = 0; i < numvfpregs; i++) {
535
- uint64_t v = *aa32_vfp_dreg(env, i);
536
- qemu_fprintf(f, "s%02d=%08x s%02d=%08x d%02d=%016" PRIx64 "\n",
537
- i * 2, (uint32_t)v,
538
- i * 2 + 1, (uint32_t)(v >> 32),
539
- i, v);
540
- }
541
- qemu_fprintf(f, "FPSCR: %08x\n", vfp_get_fpscr(env));
542
- }
543
-}
544
-
545
void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb,
546
target_ulong *data)
547
{
548
--
107
--
549
2.20.1
108
2.20.1
550
109
551
110
diff view generated by jsdifflib
New patch
1
From: Richard Henderson <richard.henderson@linaro.org>
1
2
3
These are all of the defines required to parse
4
GNU_PROPERTY_AARCH64_FEATURE_1_AND, copied from binutils.
5
Other missing defines related to other GNU program headers
6
and notes are elided for now.
7
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 20201021173749.111103-4-richard.henderson@linaro.org
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
13
include/elf.h | 22 ++++++++++++++++++++++
14
1 file changed, 22 insertions(+)
15
16
diff --git a/include/elf.h b/include/elf.h
17
index XXXXXXX..XXXXXXX 100644
18
--- a/include/elf.h
19
+++ b/include/elf.h
20
@@ -XXX,XX +XXX,XX @@ typedef int64_t Elf64_Sxword;
21
#define PT_NOTE 4
22
#define PT_SHLIB 5
23
#define PT_PHDR 6
24
+#define PT_LOOS 0x60000000
25
+#define PT_HIOS 0x6fffffff
26
#define PT_LOPROC 0x70000000
27
#define PT_HIPROC 0x7fffffff
28
29
+#define PT_GNU_PROPERTY (PT_LOOS + 0x474e553)
30
+
31
#define PT_MIPS_REGINFO 0x70000000
32
#define PT_MIPS_RTPROC 0x70000001
33
#define PT_MIPS_OPTIONS 0x70000002
34
@@ -XXX,XX +XXX,XX @@ typedef struct elf64_shdr {
35
#define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */
36
#define NT_ARM_SVE 0x405 /* ARM Scalable Vector Extension regs */
37
38
+/* Defined note types for GNU systems. */
39
+
40
+#define NT_GNU_PROPERTY_TYPE_0 5 /* Program property */
41
+
42
+/* Values used in GNU .note.gnu.property notes (NT_GNU_PROPERTY_TYPE_0). */
43
+
44
+#define GNU_PROPERTY_STACK_SIZE 1
45
+#define GNU_PROPERTY_NO_COPY_ON_PROTECTED 2
46
+
47
+#define GNU_PROPERTY_LOPROC 0xc0000000
48
+#define GNU_PROPERTY_HIPROC 0xdfffffff
49
+#define GNU_PROPERTY_LOUSER 0xe0000000
50
+#define GNU_PROPERTY_HIUSER 0xffffffff
51
+
52
+#define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000
53
+#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI (1u << 0)
54
+#define GNU_PROPERTY_AARCH64_FEATURE_1_PAC (1u << 1)
55
+
56
/*
57
* Physical entry point into the kernel.
58
*
59
--
60
2.20.1
61
62
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
2
3
In the next commit we will split the TLB related routines of
3
Fix an unlikely memory leak in load_elf_image().
4
this file, and this function will also be called in the new
5
file. Declare it in the "internals.h" header.
6
4
7
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
5
Fixes: bf858897b7 ("linux-user: Re-use load_elf_image for the main binary.")
8
Message-id: 20190701132516.26392-12-philmd@redhat.com
6
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20201021173749.111103-5-richard.henderson@linaro.org
9
Message-Id: <20201003174944.1972444-1-f4bug@amsat.org>
10
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
13
---
12
target/arm/internals.h | 16 ++++++++++++++++
14
linux-user/elfload.c | 8 ++++----
13
target/arm/helper.c | 21 +++++----------------
15
1 file changed, 4 insertions(+), 4 deletions(-)
14
2 files changed, 21 insertions(+), 16 deletions(-)
15
16
16
diff --git a/target/arm/internals.h b/target/arm/internals.h
17
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
17
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
18
--- a/target/arm/internals.h
19
--- a/linux-user/elfload.c
19
+++ b/target/arm/internals.h
20
+++ b/linux-user/elfload.c
20
@@ -XXX,XX +XXX,XX @@ static inline int exception_target_el(CPUARMState *env)
21
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
21
return target_el;
22
info->brk = vaddr_em;
22
}
23
}
23
24
} else if (eppnt->p_type == PT_INTERP && pinterp_name) {
24
+#ifndef CONFIG_USER_ONLY
25
- char *interp_name;
25
+
26
+ g_autofree char *interp_name = NULL;
26
+/* Cacheability and shareability attributes for a memory access */
27
27
+typedef struct ARMCacheAttrs {
28
if (*pinterp_name) {
28
+ unsigned int attrs:8; /* as in the MAIR register encoding */
29
errmsg = "Multiple PT_INTERP entries";
29
+ unsigned int shareability:2; /* as in the SH field of the VMSAv8-64 PTEs */
30
goto exit_errmsg;
30
+} ARMCacheAttrs;
31
}
31
+
32
- interp_name = malloc(eppnt->p_filesz);
32
+bool get_phys_addr(CPUARMState *env, target_ulong address,
33
+ interp_name = g_malloc(eppnt->p_filesz);
33
+ MMUAccessType access_type, ARMMMUIdx mmu_idx,
34
if (!interp_name) {
34
+ hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
35
goto exit_perror;
35
+ target_ulong *page_size,
36
}
36
+ ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs);
37
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
37
+
38
errmsg = "Invalid PT_INTERP entry";
38
+#endif /* !CONFIG_USER_ONLY */
39
goto exit_errmsg;
39
+
40
}
40
#endif
41
- *pinterp_name = interp_name;
41
diff --git a/target/arm/helper.c b/target/arm/helper.c
42
+ *pinterp_name = g_steal_pointer(&interp_name);
42
index XXXXXXX..XXXXXXX 100644
43
#ifdef TARGET_MIPS
43
--- a/target/arm/helper.c
44
} else if (eppnt->p_type == PT_MIPS_ABIFLAGS) {
44
+++ b/target/arm/helper.c
45
Mips_elf_abiflags_v0 abiflags;
45
@@ -XXX,XX +XXX,XX @@
46
@@ -XXX,XX +XXX,XX @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
46
#define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */
47
if (elf_interpreter) {
47
48
info->load_bias = interp_info.load_bias;
48
#ifndef CONFIG_USER_ONLY
49
info->entry = interp_info.entry;
49
-/* Cacheability and shareability attributes for a memory access */
50
- free(elf_interpreter);
50
-typedef struct ARMCacheAttrs {
51
+ g_free(elf_interpreter);
51
- unsigned int attrs:8; /* as in the MAIR register encoding */
52
}
52
- unsigned int shareability:2; /* as in the SH field of the VMSAv8-64 PTEs */
53
53
-} ARMCacheAttrs;
54
#ifdef USE_ELF_CORE_DUMP
54
-
55
-static bool get_phys_addr(CPUARMState *env, target_ulong address,
56
- MMUAccessType access_type, ARMMMUIdx mmu_idx,
57
- hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
58
- target_ulong *page_size,
59
- ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs);
60
61
static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
62
MMUAccessType access_type, ARMMMUIdx mmu_idx,
63
@@ -XXX,XX +XXX,XX @@ static ARMCacheAttrs combine_cacheattrs(ARMCacheAttrs s1, ARMCacheAttrs s2)
64
* @fi: set to fault info if the translation fails
65
* @cacheattrs: (if non-NULL) set to the cacheability/shareability attributes
66
*/
67
-static bool get_phys_addr(CPUARMState *env, target_ulong address,
68
- MMUAccessType access_type, ARMMMUIdx mmu_idx,
69
- hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
70
- target_ulong *page_size,
71
- ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs)
72
+bool get_phys_addr(CPUARMState *env, target_ulong address,
73
+ MMUAccessType access_type, ARMMMUIdx mmu_idx,
74
+ hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
75
+ target_ulong *page_size,
76
+ ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs)
77
{
78
if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) {
79
/* Call ourselves recursively to do the stage 1 and then stage 2
80
--
55
--
81
2.20.1
56
2.20.1
82
57
83
58
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
3
Fixing this now will clarify following patches.
4
Message-id: 20190701132516.26392-7-philmd@redhat.com
4
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20201021173749.111103-6-richard.henderson@linaro.org
7
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
---
9
---
8
target/arm/helper.c | 2 --
10
linux-user/elfload.c | 12 +++++++++---
9
1 file changed, 2 deletions(-)
11
1 file changed, 9 insertions(+), 3 deletions(-)
10
12
11
diff --git a/target/arm/helper.c b/target/arm/helper.c
13
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
12
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
13
--- a/target/arm/helper.c
15
--- a/linux-user/elfload.c
14
+++ b/target/arm/helper.c
16
+++ b/linux-user/elfload.c
15
@@ -XXX,XX +XXX,XX @@
17
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
16
#include "exec/gdbstub.h"
18
abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em, vaddr_len;
17
#include "exec/helper-proto.h"
19
int elf_prot = 0;
18
#include "qemu/host-utils.h"
20
19
-#include "sysemu/arch_init.h"
21
- if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
20
#include "sysemu/sysemu.h"
22
- if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
21
#include "qemu/bitops.h"
23
- if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
22
#include "qemu/crc32c.h"
24
+ if (eppnt->p_flags & PF_R) {
23
@@ -XXX,XX +XXX,XX @@
25
+ elf_prot |= PROT_READ;
24
#include "hw/semihosting/semihost.h"
26
+ }
25
#include "sysemu/cpus.h"
27
+ if (eppnt->p_flags & PF_W) {
26
#include "sysemu/kvm.h"
28
+ elf_prot |= PROT_WRITE;
27
-#include "fpu/softfloat.h"
29
+ }
28
#include "qemu/range.h"
30
+ if (eppnt->p_flags & PF_X) {
29
#include "qapi/qapi-commands-target.h"
31
+ elf_prot |= PROT_EXEC;
30
#include "qapi/error.h"
32
+ }
33
34
vaddr = load_bias + eppnt->p_vaddr;
35
vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr);
31
--
36
--
32
2.20.1
37
2.20.1
33
38
34
39
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Group KVM rules together.
3
The second loop uses a loop induction variable, and the first
4
does not. Transform the first to match the second, to simplify
5
a following patch moving code between them.
4
6
5
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
Message-id: 20201021173749.111103-7-richard.henderson@linaro.org
7
Message-id: 20190701132516.26392-4-philmd@redhat.com
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
11
---
10
target/arm/Makefile.objs | 9 +++++----
12
linux-user/elfload.c | 9 +++++----
11
1 file changed, 5 insertions(+), 4 deletions(-)
13
1 file changed, 5 insertions(+), 4 deletions(-)
12
14
13
diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
15
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
14
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/Makefile.objs
17
--- a/linux-user/elfload.c
16
+++ b/target/arm/Makefile.objs
18
+++ b/linux-user/elfload.c
17
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
18
obj-y += arm-semi.o
20
loaddr = -1, hiaddr = 0;
19
obj-$(CONFIG_SOFTMMU) += machine.o psci.o arch_dump.o monitor.o
21
info->alignment = 0;
20
-obj-$(CONFIG_KVM) += kvm.o
22
for (i = 0; i < ehdr->e_phnum; ++i) {
21
-obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
23
- if (phdr[i].p_type == PT_LOAD) {
22
-obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
24
- abi_ulong a = phdr[i].p_vaddr - phdr[i].p_offset;
23
-obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
25
+ struct elf_phdr *eppnt = phdr + i;
24
obj-y += helper.o vfp_helper.o
26
+ if (eppnt->p_type == PT_LOAD) {
25
obj-y += cpu.o gdbstub.o
27
+ abi_ulong a = eppnt->p_vaddr - eppnt->p_offset;
26
obj-$(TARGET_AARCH64) += cpu64.o gdbstub64.o
28
if (a < loaddr) {
27
obj-$(CONFIG_SOFTMMU) += arm-powerctl.o
29
loaddr = a;
28
30
}
29
+obj-$(CONFIG_KVM) += kvm.o
31
- a = phdr[i].p_vaddr + phdr[i].p_memsz;
30
+obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
32
+ a = eppnt->p_vaddr + eppnt->p_memsz;
31
+obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
33
if (a > hiaddr) {
32
+obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
34
hiaddr = a;
33
+
35
}
34
DECODETREE = $(SRC_PATH)/scripts/decodetree.py
36
++info->nsegs;
35
37
- info->alignment |= phdr[i].p_align;
36
target/arm/decode-sve.inc.c: $(SRC_PATH)/target/arm/sve.decode $(DECODETREE)
38
+ info->alignment |= eppnt->p_align;
39
}
40
}
41
37
--
42
--
38
2.20.1
43
2.20.1
39
44
40
45
diff view generated by jsdifflib
1
From: Samuel Ortiz <sameo@linux.intel.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Those helpers are a software implementation of the ARM v8 memory zeroing
3
For BTI, we need to know if the executable is static or dynamic,
4
op code. They should be moved to the op helper file, which is going to
4
which means looking for PT_INTERP earlier.
5
eventually be built only when TCG is enabled.
6
5
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Reviewed-by: Robert Bradford <robert.bradford@intel.com>
7
Message-id: 20201021173749.111103-8-richard.henderson@linaro.org
9
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
10
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
11
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
12
Message-id: 20190701132516.26392-10-philmd@redhat.com
13
[PMD: Rebased]
14
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
15
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
---
10
---
18
target/arm/helper.c | 92 -----------------------------------------
11
linux-user/elfload.c | 60 +++++++++++++++++++++++---------------------
19
target/arm/op_helper.c | 93 ++++++++++++++++++++++++++++++++++++++++++
12
1 file changed, 31 insertions(+), 29 deletions(-)
20
2 files changed, 93 insertions(+), 92 deletions(-)
21
13
22
diff --git a/target/arm/helper.c b/target/arm/helper.c
14
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
23
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
24
--- a/target/arm/helper.c
16
--- a/linux-user/elfload.c
25
+++ b/target/arm/helper.c
17
+++ b/linux-user/elfload.c
26
@@ -XXX,XX +XXX,XX @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
18
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
27
#endif
19
28
}
20
mmap_lock();
29
21
30
-void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
22
- /* Find the maximum size of the image and allocate an appropriate
31
-{
23
- amount of memory to handle that. */
32
- /*
24
+ /*
33
- * Implement DC ZVA, which zeroes a fixed-length block of memory.
25
+ * Find the maximum size of the image and allocate an appropriate
34
- * Note that we do not implement the (architecturally mandated)
26
+ * amount of memory to handle that. Locate the interpreter, if any.
35
- * alignment fault for attempts to use this on Device memory
27
+ */
36
- * (which matches the usual QEMU behaviour of not implementing either
28
loaddr = -1, hiaddr = 0;
37
- * alignment faults or any memory attribute handling).
29
info->alignment = 0;
38
- */
30
for (i = 0; i < ehdr->e_phnum; ++i) {
31
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
32
}
33
++info->nsegs;
34
info->alignment |= eppnt->p_align;
35
+ } else if (eppnt->p_type == PT_INTERP && pinterp_name) {
36
+ g_autofree char *interp_name = NULL;
37
+
38
+ if (*pinterp_name) {
39
+ errmsg = "Multiple PT_INTERP entries";
40
+ goto exit_errmsg;
41
+ }
42
+ interp_name = g_malloc(eppnt->p_filesz);
43
+ if (!interp_name) {
44
+ goto exit_perror;
45
+ }
46
+
47
+ if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
48
+ memcpy(interp_name, bprm_buf + eppnt->p_offset,
49
+ eppnt->p_filesz);
50
+ } else {
51
+ retval = pread(image_fd, interp_name, eppnt->p_filesz,
52
+ eppnt->p_offset);
53
+ if (retval != eppnt->p_filesz) {
54
+ goto exit_perror;
55
+ }
56
+ }
57
+ if (interp_name[eppnt->p_filesz - 1] != 0) {
58
+ errmsg = "Invalid PT_INTERP entry";
59
+ goto exit_errmsg;
60
+ }
61
+ *pinterp_name = g_steal_pointer(&interp_name);
62
}
63
}
64
65
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
66
if (vaddr_em > info->brk) {
67
info->brk = vaddr_em;
68
}
69
- } else if (eppnt->p_type == PT_INTERP && pinterp_name) {
70
- g_autofree char *interp_name = NULL;
39
-
71
-
40
- ARMCPU *cpu = env_archcpu(env);
72
- if (*pinterp_name) {
41
- uint64_t blocklen = 4 << cpu->dcz_blocksize;
73
- errmsg = "Multiple PT_INTERP entries";
42
- uint64_t vaddr = vaddr_in & ~(blocklen - 1);
74
- goto exit_errmsg;
75
- }
76
- interp_name = g_malloc(eppnt->p_filesz);
77
- if (!interp_name) {
78
- goto exit_perror;
79
- }
43
-
80
-
44
-#ifndef CONFIG_USER_ONLY
81
- if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
45
- {
82
- memcpy(interp_name, bprm_buf + eppnt->p_offset,
46
- /*
83
- eppnt->p_filesz);
47
- * Slightly awkwardly, QEMU's TARGET_PAGE_SIZE may be less than
84
- } else {
48
- * the block size so we might have to do more than one TLB lookup.
85
- retval = pread(image_fd, interp_name, eppnt->p_filesz,
49
- * We know that in fact for any v8 CPU the page size is at least 4K
86
- eppnt->p_offset);
50
- * and the block size must be 2K or less, but TARGET_PAGE_SIZE is only
87
- if (retval != eppnt->p_filesz) {
51
- * 1K as an artefact of legacy v5 subpage support being present in the
88
- goto exit_perror;
52
- * same QEMU executable. So in practice the hostaddr[] array has
53
- * two entries, given the current setting of TARGET_PAGE_BITS_MIN.
54
- */
55
- int maxidx = DIV_ROUND_UP(blocklen, TARGET_PAGE_SIZE);
56
- void *hostaddr[DIV_ROUND_UP(2 * KiB, 1 << TARGET_PAGE_BITS_MIN)];
57
- int try, i;
58
- unsigned mmu_idx = cpu_mmu_index(env, false);
59
- TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
60
-
61
- assert(maxidx <= ARRAY_SIZE(hostaddr));
62
-
63
- for (try = 0; try < 2; try++) {
64
-
65
- for (i = 0; i < maxidx; i++) {
66
- hostaddr[i] = tlb_vaddr_to_host(env,
67
- vaddr + TARGET_PAGE_SIZE * i,
68
- 1, mmu_idx);
69
- if (!hostaddr[i]) {
70
- break;
71
- }
89
- }
72
- }
90
- }
73
- if (i == maxidx) {
91
- if (interp_name[eppnt->p_filesz - 1] != 0) {
74
- /*
92
- errmsg = "Invalid PT_INTERP entry";
75
- * If it's all in the TLB it's fair game for just writing to;
93
- goto exit_errmsg;
76
- * we know we don't need to update dirty status, etc.
77
- */
78
- for (i = 0; i < maxidx - 1; i++) {
79
- memset(hostaddr[i], 0, TARGET_PAGE_SIZE);
80
- }
81
- memset(hostaddr[i], 0, blocklen - (i * TARGET_PAGE_SIZE));
82
- return;
83
- }
94
- }
84
- /*
95
- *pinterp_name = g_steal_pointer(&interp_name);
85
- * OK, try a store and see if we can populate the tlb. This
96
#ifdef TARGET_MIPS
86
- * might cause an exception if the memory isn't writable,
97
} else if (eppnt->p_type == PT_MIPS_ABIFLAGS) {
87
- * in which case we will longjmp out of here. We must for
98
Mips_elf_abiflags_v0 abiflags;
88
- * this purpose use the actual register value passed to us
89
- * so that we get the fault address right.
90
- */
91
- helper_ret_stb_mmu(env, vaddr_in, 0, oi, GETPC());
92
- /* Now we can populate the other TLB entries, if any */
93
- for (i = 0; i < maxidx; i++) {
94
- uint64_t va = vaddr + TARGET_PAGE_SIZE * i;
95
- if (va != (vaddr_in & TARGET_PAGE_MASK)) {
96
- helper_ret_stb_mmu(env, va, 0, oi, GETPC());
97
- }
98
- }
99
- }
100
-
101
- /*
102
- * Slow path (probably attempt to do this to an I/O device or
103
- * similar, or clearing of a block of code we have translations
104
- * cached for). Just do a series of byte writes as the architecture
105
- * demands. It's not worth trying to use a cpu_physical_memory_map(),
106
- * memset(), unmap() sequence here because:
107
- * + we'd need to account for the blocksize being larger than a page
108
- * + the direct-RAM access case is almost always going to be dealt
109
- * with in the fastpath code above, so there's no speed benefit
110
- * + we would have to deal with the map returning NULL because the
111
- * bounce buffer was in use
112
- */
113
- for (i = 0; i < blocklen; i++) {
114
- helper_ret_stb_mmu(env, vaddr + i, 0, oi, GETPC());
115
- }
116
- }
117
-#else
118
- memset(g2h(vaddr), 0, blocklen);
119
-#endif
120
-}
121
-
122
/* Note that signed overflow is undefined in C. The following routines are
123
careful to use unsigned types where modulo arithmetic is required.
124
Failure to do so _will_ break on newer gcc. */
125
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
126
index XXXXXXX..XXXXXXX 100644
127
--- a/target/arm/op_helper.c
128
+++ b/target/arm/op_helper.c
129
@@ -XXX,XX +XXX,XX @@
130
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
131
*/
132
#include "qemu/osdep.h"
133
+#include "qemu/units.h"
134
#include "qemu/log.h"
135
#include "qemu/main-loop.h"
136
#include "cpu.h"
137
@@ -XXX,XX +XXX,XX @@ uint32_t HELPER(ror_cc)(CPUARMState *env, uint32_t x, uint32_t i)
138
return ((uint32_t)x >> shift) | (x << (32 - shift));
139
}
140
}
141
+
142
+void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
143
+{
144
+ /*
145
+ * Implement DC ZVA, which zeroes a fixed-length block of memory.
146
+ * Note that we do not implement the (architecturally mandated)
147
+ * alignment fault for attempts to use this on Device memory
148
+ * (which matches the usual QEMU behaviour of not implementing either
149
+ * alignment faults or any memory attribute handling).
150
+ */
151
+
152
+ ARMCPU *cpu = env_archcpu(env);
153
+ uint64_t blocklen = 4 << cpu->dcz_blocksize;
154
+ uint64_t vaddr = vaddr_in & ~(blocklen - 1);
155
+
156
+#ifndef CONFIG_USER_ONLY
157
+ {
158
+ /*
159
+ * Slightly awkwardly, QEMU's TARGET_PAGE_SIZE may be less than
160
+ * the block size so we might have to do more than one TLB lookup.
161
+ * We know that in fact for any v8 CPU the page size is at least 4K
162
+ * and the block size must be 2K or less, but TARGET_PAGE_SIZE is only
163
+ * 1K as an artefact of legacy v5 subpage support being present in the
164
+ * same QEMU executable. So in practice the hostaddr[] array has
165
+ * two entries, given the current setting of TARGET_PAGE_BITS_MIN.
166
+ */
167
+ int maxidx = DIV_ROUND_UP(blocklen, TARGET_PAGE_SIZE);
168
+ void *hostaddr[DIV_ROUND_UP(2 * KiB, 1 << TARGET_PAGE_BITS_MIN)];
169
+ int try, i;
170
+ unsigned mmu_idx = cpu_mmu_index(env, false);
171
+ TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
172
+
173
+ assert(maxidx <= ARRAY_SIZE(hostaddr));
174
+
175
+ for (try = 0; try < 2; try++) {
176
+
177
+ for (i = 0; i < maxidx; i++) {
178
+ hostaddr[i] = tlb_vaddr_to_host(env,
179
+ vaddr + TARGET_PAGE_SIZE * i,
180
+ 1, mmu_idx);
181
+ if (!hostaddr[i]) {
182
+ break;
183
+ }
184
+ }
185
+ if (i == maxidx) {
186
+ /*
187
+ * If it's all in the TLB it's fair game for just writing to;
188
+ * we know we don't need to update dirty status, etc.
189
+ */
190
+ for (i = 0; i < maxidx - 1; i++) {
191
+ memset(hostaddr[i], 0, TARGET_PAGE_SIZE);
192
+ }
193
+ memset(hostaddr[i], 0, blocklen - (i * TARGET_PAGE_SIZE));
194
+ return;
195
+ }
196
+ /*
197
+ * OK, try a store and see if we can populate the tlb. This
198
+ * might cause an exception if the memory isn't writable,
199
+ * in which case we will longjmp out of here. We must for
200
+ * this purpose use the actual register value passed to us
201
+ * so that we get the fault address right.
202
+ */
203
+ helper_ret_stb_mmu(env, vaddr_in, 0, oi, GETPC());
204
+ /* Now we can populate the other TLB entries, if any */
205
+ for (i = 0; i < maxidx; i++) {
206
+ uint64_t va = vaddr + TARGET_PAGE_SIZE * i;
207
+ if (va != (vaddr_in & TARGET_PAGE_MASK)) {
208
+ helper_ret_stb_mmu(env, va, 0, oi, GETPC());
209
+ }
210
+ }
211
+ }
212
+
213
+ /*
214
+ * Slow path (probably attempt to do this to an I/O device or
215
+ * similar, or clearing of a block of code we have translations
216
+ * cached for). Just do a series of byte writes as the architecture
217
+ * demands. It's not worth trying to use a cpu_physical_memory_map(),
218
+ * memset(), unmap() sequence here because:
219
+ * + we'd need to account for the blocksize being larger than a page
220
+ * + the direct-RAM access case is almost always going to be dealt
221
+ * with in the fastpath code above, so there's no speed benefit
222
+ * + we would have to deal with the map returning NULL because the
223
+ * bounce buffer was in use
224
+ */
225
+ for (i = 0; i < blocklen; i++) {
226
+ helper_ret_stb_mmu(env, vaddr + i, 0, oi, GETPC());
227
+ }
228
+ }
229
+#else
230
+ memset(g2h(vaddr), 0, blocklen);
231
+#endif
232
+}
233
--
99
--
234
2.20.1
100
2.20.1
235
101
236
102
diff view generated by jsdifflib
1
From: Adriana Kobylak <anoo@us.ibm.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
The Swift board is an OpenPOWER system hosting POWER processors.
3
This is a bit clearer than open-coding some of this
4
Add support for their BMC including the I2C devices as found on HW.
4
with a bare c string.
5
5
6
Signed-off-by: Adriana Kobylak <anoo@us.ibm.com>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Reviewed-by: Cédric Le Goater <clg@kaod.org>
7
Message-id: 20201021173749.111103-9-richard.henderson@linaro.org
8
Reviewed-by: Joel Stanley <joel@jms.id.au>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Message-id: 20190618165311.27066-20-clg@kaod.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
10
---
12
hw/arm/aspeed.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++
11
linux-user/elfload.c | 37 ++++++++++++++++++++-----------------
13
1 file changed, 50 insertions(+)
12
1 file changed, 20 insertions(+), 17 deletions(-)
14
13
15
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
14
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
16
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/arm/aspeed.c
16
--- a/linux-user/elfload.c
18
+++ b/hw/arm/aspeed.c
17
+++ b/linux-user/elfload.c
19
@@ -XXX,XX +XXX,XX @@ struct AspeedBoardState {
18
@@ -XXX,XX +XXX,XX @@
20
SCU_AST2500_HW_STRAP_ACPI_ENABLE | \
19
#include "qemu/guest-random.h"
21
SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_MASTER))
20
#include "qemu/units.h"
22
21
#include "qemu/selfmap.h"
23
+/* Swift hardware value: 0xF11AD206 */
22
+#include "qapi/error.h"
24
+#define SWIFT_BMC_HW_STRAP1 ( \
23
25
+ AST2500_HW_STRAP1_DEFAULTS | \
24
#ifdef _ARCH_PPC64
26
+ SCU_AST2500_HW_STRAP_SPI_AUTOFETCH_ENABLE | \
25
#undef ARCH_DLINFO
27
+ SCU_AST2500_HW_STRAP_GPIO_STRAP_ENABLE | \
26
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
28
+ SCU_AST2500_HW_STRAP_UART_DEBUG | \
27
struct elf_phdr *phdr;
29
+ SCU_AST2500_HW_STRAP_DDR4_ENABLE | \
28
abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
30
+ SCU_H_PLL_BYPASS_EN | \
29
int i, retval;
31
+ SCU_AST2500_HW_STRAP_ACPI_ENABLE | \
30
- const char *errmsg;
32
+ SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_MASTER))
31
+ Error *err = NULL;
32
33
/* First of all, some simple consistency checks */
34
- errmsg = "Invalid ELF image for this architecture";
35
if (!elf_check_ident(ehdr)) {
36
+ error_setg(&err, "Invalid ELF image for this architecture");
37
goto exit_errmsg;
38
}
39
bswap_ehdr(ehdr);
40
if (!elf_check_ehdr(ehdr)) {
41
+ error_setg(&err, "Invalid ELF image for this architecture");
42
goto exit_errmsg;
43
}
44
45
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
46
g_autofree char *interp_name = NULL;
47
48
if (*pinterp_name) {
49
- errmsg = "Multiple PT_INTERP entries";
50
+ error_setg(&err, "Multiple PT_INTERP entries");
51
goto exit_errmsg;
52
}
33
+
53
+
34
/* Witherspoon hardware value: 0xF10AD216 (but use romulus definition) */
54
interp_name = g_malloc(eppnt->p_filesz);
35
#define WITHERSPOON_BMC_HW_STRAP1 ROMULUS_BMC_HW_STRAP1
55
- if (!interp_name) {
36
56
- goto exit_perror;
37
@@ -XXX,XX +XXX,XX @@ static void romulus_bmc_i2c_init(AspeedBoardState *bmc)
57
- }
38
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "ds1338", 0x32);
58
59
if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
60
memcpy(interp_name, bprm_buf + eppnt->p_offset,
61
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
62
retval = pread(image_fd, interp_name, eppnt->p_filesz,
63
eppnt->p_offset);
64
if (retval != eppnt->p_filesz) {
65
- goto exit_perror;
66
+ goto exit_read;
67
}
68
}
69
if (interp_name[eppnt->p_filesz - 1] != 0) {
70
- errmsg = "Invalid PT_INTERP entry";
71
+ error_setg(&err, "Invalid PT_INTERP entry");
72
goto exit_errmsg;
73
}
74
*pinterp_name = g_steal_pointer(&interp_name);
75
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
76
(ehdr->e_type == ET_EXEC ? MAP_FIXED : 0),
77
-1, 0);
78
if (load_addr == -1) {
79
- goto exit_perror;
80
+ goto exit_mmap;
81
}
82
load_bias = load_addr - loaddr;
83
84
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
85
image_fd, eppnt->p_offset - vaddr_po);
86
87
if (error == -1) {
88
- goto exit_perror;
89
+ goto exit_mmap;
90
}
91
}
92
93
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
94
} else if (eppnt->p_type == PT_MIPS_ABIFLAGS) {
95
Mips_elf_abiflags_v0 abiflags;
96
if (eppnt->p_filesz < sizeof(Mips_elf_abiflags_v0)) {
97
- errmsg = "Invalid PT_MIPS_ABIFLAGS entry";
98
+ error_setg(&err, "Invalid PT_MIPS_ABIFLAGS entry");
99
goto exit_errmsg;
100
}
101
if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
102
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
103
retval = pread(image_fd, &abiflags, sizeof(Mips_elf_abiflags_v0),
104
eppnt->p_offset);
105
if (retval != sizeof(Mips_elf_abiflags_v0)) {
106
- goto exit_perror;
107
+ goto exit_read;
108
}
109
}
110
bswap_mips_abiflags(&abiflags);
111
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
112
113
exit_read:
114
if (retval >= 0) {
115
- errmsg = "Incomplete read of file header";
116
- goto exit_errmsg;
117
+ error_setg(&err, "Incomplete read of file header");
118
+ } else {
119
+ error_setg_errno(&err, errno, "Error reading file header");
120
}
121
- exit_perror:
122
- errmsg = strerror(errno);
123
+ goto exit_errmsg;
124
+ exit_mmap:
125
+ error_setg_errno(&err, errno, "Error mapping file");
126
+ goto exit_errmsg;
127
exit_errmsg:
128
- fprintf(stderr, "%s: %s\n", image_name, errmsg);
129
+ error_reportf_err(err, "%s: ", image_name);
130
exit(-1);
39
}
131
}
40
132
41
+static void swift_bmc_i2c_init(AspeedBoardState *bmc)
42
+{
43
+ AspeedSoCState *soc = &bmc->soc;
44
+
45
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 3), "pca9552", 0x60);
46
+
47
+ /* The swift board expects a TMP275 but a TMP105 is compatible */
48
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 7), "tmp105", 0x48);
49
+ /* The swift board expects a pca9551 but a pca9552 is compatible */
50
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 7), "pca9552", 0x60);
51
+
52
+ /* The swift board expects an Epson RX8900 RTC but a ds1338 is compatible */
53
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 8), "ds1338", 0x32);
54
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 8), "pca9552", 0x60);
55
+
56
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 9), "tmp423", 0x4c);
57
+ /* The swift board expects a pca9539 but a pca9552 is compatible */
58
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 9), "pca9552", 0x74);
59
+
60
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 10), "tmp423", 0x4c);
61
+ /* The swift board expects a pca9539 but a pca9552 is compatible */
62
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 10), "pca9552",
63
+ 0x74);
64
+
65
+ /* The swift board expects a TMP275 but a TMP105 is compatible */
66
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 12), "tmp105", 0x48);
67
+ i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 12), "tmp105", 0x4a);
68
+}
69
+
70
static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc)
71
{
72
AspeedSoCState *soc = &bmc->soc;
73
@@ -XXX,XX +XXX,XX @@ static const AspeedBoardConfig aspeed_boards[] = {
74
.num_cs = 2,
75
.i2c_init = romulus_bmc_i2c_init,
76
.ram = 512 * MiB,
77
+ }, {
78
+ .name = MACHINE_TYPE_NAME("swift-bmc"),
79
+ .desc = "OpenPOWER Swift BMC (ARM1176)",
80
+ .soc_name = "ast2500-a1",
81
+ .hw_strap1 = SWIFT_BMC_HW_STRAP1,
82
+ .fmc_model = "mx66l1g45g",
83
+ .spi_model = "mx66l1g45g",
84
+ .num_cs = 2,
85
+ .i2c_init = swift_bmc_i2c_init,
86
+ .ram = 512 * MiB,
87
}, {
88
.name = MACHINE_TYPE_NAME("witherspoon-bmc"),
89
.desc = "OpenPOWER Witherspoon BMC (ARM1176)",
90
--
133
--
91
2.20.1
134
2.20.1
92
135
93
136
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Since we'll move this code around, fix its style first.
3
This is slightly clearer than just using strerror, though
4
the different forms produced by error_setg_file_open and
5
error_setg_errno isn't entirely convenient.
4
6
5
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
Message-id: 20201021173749.111103-10-richard.henderson@linaro.org
7
Message-id: 20190701132516.26392-9-philmd@redhat.com
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
11
---
10
target/arm/translate.c | 11 ++++++-----
12
linux-user/elfload.c | 15 ++++++++-------
11
target/arm/vfp_helper.c | 36 ++++++++++++++++++++++++------------
13
1 file changed, 8 insertions(+), 7 deletions(-)
12
2 files changed, 30 insertions(+), 17 deletions(-)
13
14
14
diff --git a/target/arm/translate.c b/target/arm/translate.c
15
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
15
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/translate.c
17
--- a/linux-user/elfload.c
17
+++ b/target/arm/translate.c
18
+++ b/linux-user/elfload.c
18
@@ -XXX,XX +XXX,XX @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
19
@@ -XXX,XX +XXX,XX @@ static void load_elf_interp(const char *filename, struct image_info *info,
19
loaded_base = 0;
20
char bprm_buf[BPRM_BUF_SIZE])
20
loaded_var = NULL;
21
{
21
n = 0;
22
int fd, retval;
22
- for(i=0;i<16;i++) {
23
+ Error *err = NULL;
23
+ for (i = 0; i < 16; i++) {
24
24
if (insn & (1 << i))
25
fd = open(path(filename), O_RDONLY);
25
n++;
26
if (fd < 0) {
26
}
27
- goto exit_perror;
27
@@ -XXX,XX +XXX,XX @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
28
+ error_setg_file_open(&err, errno, filename);
28
}
29
+ error_report_err(err);
29
}
30
+ exit(-1);
30
j = 0;
31
- for(i=0;i<16;i++) {
32
+ for (i = 0; i < 16; i++) {
33
if (insn & (1 << i)) {
34
if (is_load) {
35
/* load */
36
@@ -XXX,XX +XXX,XX @@ void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags)
37
return;
38
}
31
}
39
32
40
- for(i=0;i<16;i++) {
33
retval = read(fd, bprm_buf, BPRM_BUF_SIZE);
41
+ for (i = 0; i < 16; i++) {
34
if (retval < 0) {
42
qemu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
35
- goto exit_perror;
43
- if ((i % 4) == 3)
36
+ error_setg_errno(&err, errno, "Error reading file header");
44
+ if ((i % 4) == 3) {
37
+ error_reportf_err(err, "%s: ", filename);
45
qemu_fprintf(f, "\n");
38
+ exit(-1);
46
- else
47
+ } else {
48
qemu_fprintf(f, " ");
49
+ }
50
}
39
}
51
40
+
52
if (arm_feature(env, ARM_FEATURE_M)) {
41
if (retval < BPRM_BUF_SIZE) {
53
diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c
42
memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval);
54
index XXXXXXX..XXXXXXX 100644
43
}
55
--- a/target/arm/vfp_helper.c
44
56
+++ b/target/arm/vfp_helper.c
45
load_elf_image(filename, fd, info, NULL, bprm_buf);
57
@@ -XXX,XX +XXX,XX @@ static inline int vfp_exceptbits_from_host(int host_bits)
46
- return;
58
{
47
-
59
int target_bits = 0;
48
- exit_perror:
60
49
- fprintf(stderr, "%s: %s\n", filename, strerror(errno));
61
- if (host_bits & float_flag_invalid)
50
- exit(-1);
62
+ if (host_bits & float_flag_invalid) {
63
target_bits |= 1;
64
- if (host_bits & float_flag_divbyzero)
65
+ }
66
+ if (host_bits & float_flag_divbyzero) {
67
target_bits |= 2;
68
- if (host_bits & float_flag_overflow)
69
+ }
70
+ if (host_bits & float_flag_overflow) {
71
target_bits |= 4;
72
- if (host_bits & (float_flag_underflow | float_flag_output_denormal))
73
+ }
74
+ if (host_bits & (float_flag_underflow | float_flag_output_denormal)) {
75
target_bits |= 8;
76
- if (host_bits & float_flag_inexact)
77
+ }
78
+ if (host_bits & float_flag_inexact) {
79
target_bits |= 0x10;
80
- if (host_bits & float_flag_input_denormal)
81
+ }
82
+ if (host_bits & float_flag_input_denormal) {
83
target_bits |= 0x80;
84
+ }
85
return target_bits;
86
}
51
}
87
52
88
@@ -XXX,XX +XXX,XX @@ static inline int vfp_exceptbits_to_host(int target_bits)
53
static int symfind(const void *s0, const void *s1)
89
{
90
int host_bits = 0;
91
92
- if (target_bits & 1)
93
+ if (target_bits & 1) {
94
host_bits |= float_flag_invalid;
95
- if (target_bits & 2)
96
+ }
97
+ if (target_bits & 2) {
98
host_bits |= float_flag_divbyzero;
99
- if (target_bits & 4)
100
+ }
101
+ if (target_bits & 4) {
102
host_bits |= float_flag_overflow;
103
- if (target_bits & 8)
104
+ }
105
+ if (target_bits & 8) {
106
host_bits |= float_flag_underflow;
107
- if (target_bits & 0x10)
108
+ }
109
+ if (target_bits & 0x10) {
110
host_bits |= float_flag_inexact;
111
- if (target_bits & 0x80)
112
+ }
113
+ if (target_bits & 0x80) {
114
host_bits |= float_flag_input_denormal;
115
+ }
116
return host_bits;
117
}
118
119
--
54
--
120
2.20.1
55
2.20.1
121
56
122
57
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Under KVM, the kernel gets the HVC call and handle the PSCI requests.
3
This is generic support, with the code disabled for all targets.
4
4
5
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20190701132516.26392-20-philmd@redhat.com
6
Message-id: 20201021173749.111103-11-richard.henderson@linaro.org
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
9
---
10
target/arm/internals.h | 6 +++++-
10
linux-user/qemu.h | 4 ++
11
1 file changed, 5 insertions(+), 1 deletion(-)
11
linux-user/elfload.c | 157 +++++++++++++++++++++++++++++++++++++++++++
12
12
2 files changed, 161 insertions(+)
13
diff --git a/target/arm/internals.h b/target/arm/internals.h
13
14
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
14
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/internals.h
16
--- a/linux-user/qemu.h
16
+++ b/target/arm/internals.h
17
+++ b/linux-user/qemu.h
17
@@ -XXX,XX +XXX,XX @@ vaddr arm_adjust_watchpoint_address(CPUState *cs, vaddr addr, int len);
18
@@ -XXX,XX +XXX,XX @@ struct image_info {
18
/* Callback function for when a watchpoint or breakpoint triggers. */
19
abi_ulong interpreter_loadmap_addr;
19
void arm_debug_excp_handler(CPUState *cs);
20
abi_ulong interpreter_pt_dynamic_addr;
20
21
struct image_info *other_info;
21
-#ifdef CONFIG_USER_ONLY
22
+
22
+#if defined(CONFIG_USER_ONLY) || !defined(CONFIG_TCG)
23
+ /* For target-specific processing of NT_GNU_PROPERTY_TYPE_0. */
23
static inline bool arm_is_psci_call(ARMCPU *cpu, int excp_type)
24
+ uint32_t note_flags;
24
{
25
+
25
return false;
26
#ifdef TARGET_MIPS
26
}
27
int fp_abi;
27
+static inline void arm_handle_psci_call(ARMCPU *cpu)
28
int interp_fp_abi;
29
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/linux-user/elfload.c
32
+++ b/linux-user/elfload.c
33
@@ -XXX,XX +XXX,XX @@ static void elf_core_copy_regs(target_elf_gregset_t *regs,
34
35
#include "elf.h"
36
37
+static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
38
+ const uint32_t *data,
39
+ struct image_info *info,
40
+ Error **errp)
28
+{
41
+{
29
+ g_assert_not_reached();
42
+ g_assert_not_reached();
30
+}
43
+}
31
#else
44
+#define ARCH_USE_GNU_PROPERTY 0
32
/* Return true if the r0/x0 value indicates that this SMC/HVC is a PSCI call. */
45
+
33
bool arm_is_psci_call(ARMCPU *cpu, int excp_type);
46
struct exec
47
{
48
unsigned int a_info; /* Use macros N_MAGIC, etc for access */
49
@@ -XXX,XX +XXX,XX @@ void probe_guest_base(const char *image_name, abi_ulong guest_loaddr,
50
"@ 0x%" PRIx64 "\n", (uint64_t)guest_base);
51
}
52
53
+enum {
54
+ /* The string "GNU\0" as a magic number. */
55
+ GNU0_MAGIC = const_le32('G' | 'N' << 8 | 'U' << 16),
56
+ NOTE_DATA_SZ = 1 * KiB,
57
+ NOTE_NAME_SZ = 4,
58
+ ELF_GNU_PROPERTY_ALIGN = ELF_CLASS == ELFCLASS32 ? 4 : 8,
59
+};
60
+
61
+/*
62
+ * Process a single gnu_property entry.
63
+ * Return false for error.
64
+ */
65
+static bool parse_elf_property(const uint32_t *data, int *off, int datasz,
66
+ struct image_info *info, bool have_prev_type,
67
+ uint32_t *prev_type, Error **errp)
68
+{
69
+ uint32_t pr_type, pr_datasz, step;
70
+
71
+ if (*off > datasz || !QEMU_IS_ALIGNED(*off, ELF_GNU_PROPERTY_ALIGN)) {
72
+ goto error_data;
73
+ }
74
+ datasz -= *off;
75
+ data += *off / sizeof(uint32_t);
76
+
77
+ if (datasz < 2 * sizeof(uint32_t)) {
78
+ goto error_data;
79
+ }
80
+ pr_type = data[0];
81
+ pr_datasz = data[1];
82
+ data += 2;
83
+ datasz -= 2 * sizeof(uint32_t);
84
+ step = ROUND_UP(pr_datasz, ELF_GNU_PROPERTY_ALIGN);
85
+ if (step > datasz) {
86
+ goto error_data;
87
+ }
88
+
89
+ /* Properties are supposed to be unique and sorted on pr_type. */
90
+ if (have_prev_type && pr_type <= *prev_type) {
91
+ if (pr_type == *prev_type) {
92
+ error_setg(errp, "Duplicate property in PT_GNU_PROPERTY");
93
+ } else {
94
+ error_setg(errp, "Unsorted property in PT_GNU_PROPERTY");
95
+ }
96
+ return false;
97
+ }
98
+ *prev_type = pr_type;
99
+
100
+ if (!arch_parse_elf_property(pr_type, pr_datasz, data, info, errp)) {
101
+ return false;
102
+ }
103
+
104
+ *off += 2 * sizeof(uint32_t) + step;
105
+ return true;
106
+
107
+ error_data:
108
+ error_setg(errp, "Ill-formed property in PT_GNU_PROPERTY");
109
+ return false;
110
+}
111
+
112
+/* Process NT_GNU_PROPERTY_TYPE_0. */
113
+static bool parse_elf_properties(int image_fd,
114
+ struct image_info *info,
115
+ const struct elf_phdr *phdr,
116
+ char bprm_buf[BPRM_BUF_SIZE],
117
+ Error **errp)
118
+{
119
+ union {
120
+ struct elf_note nhdr;
121
+ uint32_t data[NOTE_DATA_SZ / sizeof(uint32_t)];
122
+ } note;
123
+
124
+ int n, off, datasz;
125
+ bool have_prev_type;
126
+ uint32_t prev_type;
127
+
128
+ /* Unless the arch requires properties, ignore them. */
129
+ if (!ARCH_USE_GNU_PROPERTY) {
130
+ return true;
131
+ }
132
+
133
+ /* If the properties are crazy large, that's too bad. */
134
+ n = phdr->p_filesz;
135
+ if (n > sizeof(note)) {
136
+ error_setg(errp, "PT_GNU_PROPERTY too large");
137
+ return false;
138
+ }
139
+ if (n < sizeof(note.nhdr)) {
140
+ error_setg(errp, "PT_GNU_PROPERTY too small");
141
+ return false;
142
+ }
143
+
144
+ if (phdr->p_offset + n <= BPRM_BUF_SIZE) {
145
+ memcpy(&note, bprm_buf + phdr->p_offset, n);
146
+ } else {
147
+ ssize_t len = pread(image_fd, &note, n, phdr->p_offset);
148
+ if (len != n) {
149
+ error_setg_errno(errp, errno, "Error reading file header");
150
+ return false;
151
+ }
152
+ }
153
+
154
+ /*
155
+ * The contents of a valid PT_GNU_PROPERTY is a sequence
156
+ * of uint32_t -- swap them all now.
157
+ */
158
+#ifdef BSWAP_NEEDED
159
+ for (int i = 0; i < n / 4; i++) {
160
+ bswap32s(note.data + i);
161
+ }
162
+#endif
163
+
164
+ /*
165
+ * Note that nhdr is 3 words, and that the "name" described by namesz
166
+ * immediately follows nhdr and is thus at the 4th word. Further, all
167
+ * of the inputs to the kernel's round_up are multiples of 4.
168
+ */
169
+ if (note.nhdr.n_type != NT_GNU_PROPERTY_TYPE_0 ||
170
+ note.nhdr.n_namesz != NOTE_NAME_SZ ||
171
+ note.data[3] != GNU0_MAGIC) {
172
+ error_setg(errp, "Invalid note in PT_GNU_PROPERTY");
173
+ return false;
174
+ }
175
+ off = sizeof(note.nhdr) + NOTE_NAME_SZ;
176
+
177
+ datasz = note.nhdr.n_descsz + off;
178
+ if (datasz > n) {
179
+ error_setg(errp, "Invalid note size in PT_GNU_PROPERTY");
180
+ return false;
181
+ }
182
+
183
+ have_prev_type = false;
184
+ prev_type = 0;
185
+ while (1) {
186
+ if (off == datasz) {
187
+ return true; /* end, exit ok */
188
+ }
189
+ if (!parse_elf_property(note.data, &off, datasz, info,
190
+ have_prev_type, &prev_type, errp)) {
191
+ return false;
192
+ }
193
+ have_prev_type = true;
194
+ }
195
+}
196
+
197
/* Load an ELF image into the address space.
198
199
IMAGE_NAME is the filename of the image, to use in error messages.
200
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
201
goto exit_errmsg;
202
}
203
*pinterp_name = g_steal_pointer(&interp_name);
204
+ } else if (eppnt->p_type == PT_GNU_PROPERTY) {
205
+ if (!parse_elf_properties(image_fd, info, eppnt, bprm_buf, &err)) {
206
+ goto exit_errmsg;
207
+ }
208
}
209
}
210
34
--
211
--
35
2.20.1
212
2.20.1
36
213
37
214
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
This code is specific to the SoftFloat floating-point
3
Use the new generic support for NT_GNU_PROPERTY_TYPE_0.
4
implementation, which is only used by TCG.
5
4
6
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20190701132516.26392-18-philmd@redhat.com
6
Message-id: 20201021173749.111103-12-richard.henderson@linaro.org
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
9
---
11
target/arm/vfp_helper.c | 26 +++++++++++++++++++++++---
10
linux-user/elfload.c | 48 ++++++++++++++++++++++++++++++++++++++++++--
12
1 file changed, 23 insertions(+), 3 deletions(-)
11
1 file changed, 46 insertions(+), 2 deletions(-)
13
12
14
diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c
13
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
15
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/vfp_helper.c
15
--- a/linux-user/elfload.c
17
+++ b/target/arm/vfp_helper.c
16
+++ b/linux-user/elfload.c
18
@@ -XXX,XX +XXX,XX @@
17
@@ -XXX,XX +XXX,XX @@ static void elf_core_copy_regs(target_elf_gregset_t *regs,
19
*/
18
20
19
#include "elf.h"
21
#include "qemu/osdep.h"
20
22
-#include "qemu/log.h"
21
+/* We must delay the following stanzas until after "elf.h". */
23
#include "cpu.h"
22
+#if defined(TARGET_AARCH64)
24
#include "exec/helper-proto.h"
25
-#include "fpu/softfloat.h"
26
#include "internals.h"
27
-
28
+#ifdef CONFIG_TCG
29
+#include "qemu/log.h"
30
+#include "fpu/softfloat.h"
31
+#endif
32
33
/* VFP support. We follow the convention used for VFP instructions:
34
Single precision routines have a "s" suffix, double precision a
35
"d" suffix. */
36
37
+#ifdef CONFIG_TCG
38
+
23
+
39
/* Convert host exception flags to vfp form. */
24
+static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
40
static inline int vfp_exceptbits_from_host(int host_bits)
25
+ const uint32_t *data,
41
{
26
+ struct image_info *info,
42
@@ -XXX,XX +XXX,XX @@ static void vfp_set_fpscr_to_host(CPUARMState *env, uint32_t val)
27
+ Error **errp)
43
set_float_exception_flags(0, &env->vfp.standard_fp_status);
28
+{
44
}
29
+ if (pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) {
45
30
+ if (pr_datasz != sizeof(uint32_t)) {
31
+ error_setg(errp, "Ill-formed GNU_PROPERTY_AARCH64_FEATURE_1_AND");
32
+ return false;
33
+ }
34
+ /* We will extract GNU_PROPERTY_AARCH64_FEATURE_1_BTI later. */
35
+ info->note_flags = *data;
36
+ }
37
+ return true;
38
+}
39
+#define ARCH_USE_GNU_PROPERTY 1
40
+
46
+#else
41
+#else
47
+
42
+
48
+static uint32_t vfp_get_fpscr_from_host(CPUARMState *env)
43
static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
49
+{
44
const uint32_t *data,
50
+ return 0;
45
struct image_info *info,
51
+}
46
@@ -XXX,XX +XXX,XX @@ static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
52
+
47
}
53
+static void vfp_set_fpscr_to_host(CPUARMState *env, uint32_t val)
48
#define ARCH_USE_GNU_PROPERTY 0
54
+{
49
55
+}
56
+
57
+#endif
50
+#endif
58
+
51
+
59
uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env)
52
struct exec
60
{
53
{
61
uint32_t i, fpscr;
54
unsigned int a_info; /* Use macros N_MAGIC, etc for access */
62
@@ -XXX,XX +XXX,XX @@ void vfp_set_fpscr(CPUARMState *env, uint32_t val)
55
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
63
HELPER(vfp_set_fpscr)(env, val);
56
struct elfhdr *ehdr = (struct elfhdr *)bprm_buf;
64
}
57
struct elf_phdr *phdr;
65
58
abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
66
+#ifdef CONFIG_TCG
59
- int i, retval;
60
+ int i, retval, prot_exec;
61
Error *err = NULL;
62
63
/* First of all, some simple consistency checks */
64
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
65
info->brk = 0;
66
info->elf_flags = ehdr->e_flags;
67
68
+ prot_exec = PROT_EXEC;
69
+#ifdef TARGET_AARCH64
70
+ /*
71
+ * If the BTI feature is present, this indicates that the executable
72
+ * pages of the startup binary should be mapped with PROT_BTI, so that
73
+ * branch targets are enforced.
74
+ *
75
+ * The startup binary is either the interpreter or the static executable.
76
+ * The interpreter is responsible for all pages of a dynamic executable.
77
+ *
78
+ * Elf notes are backward compatible to older cpus.
79
+ * Do not enable BTI unless it is supported.
80
+ */
81
+ if ((info->note_flags & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)
82
+ && (pinterp_name == NULL || *pinterp_name == 0)
83
+ && cpu_isar_feature(aa64_bti, ARM_CPU(thread_cpu))) {
84
+ prot_exec |= TARGET_PROT_BTI;
85
+ }
86
+#endif
67
+
87
+
68
#define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p))
88
for (i = 0; i < ehdr->e_phnum; i++) {
69
89
struct elf_phdr *eppnt = phdr + i;
70
#define VFP_BINOP(name) \
90
if (eppnt->p_type == PT_LOAD) {
71
@@ -XXX,XX +XXX,XX @@ float64 HELPER(frint64_d)(float64 f, void *fpst)
91
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
72
{
92
elf_prot |= PROT_WRITE;
73
return frint_d(f, fpst, 64);
93
}
74
}
94
if (eppnt->p_flags & PF_X) {
75
+
95
- elf_prot |= PROT_EXEC;
76
+#endif
96
+ elf_prot |= prot_exec;
97
}
98
99
vaddr = load_bias + eppnt->p_vaddr;
77
--
100
--
78
2.20.1
101
2.20.1
79
102
80
103
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Reviewed-by: Robert Bradford <robert.bradford@intel.com>
3
The note test requires gcc 10 for -mbranch-protection=standard.
4
Reviewed-by: Samuel Ortiz <sameo@linux.intel.com>
4
The mmap test uses PROT_BTI and does not require special compiler support.
5
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
5
6
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
6
Acked-by: Alex Bennée <alex.bennee@linaro.org>
7
Message-id: 20190701132516.26392-6-philmd@redhat.com
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20201021173749.111103-13-richard.henderson@linaro.org
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
11
---
10
target/arm/helper.c | 7 +++++++
12
tests/tcg/aarch64/bti-1.c | 62 ++++++++++++++++
11
1 file changed, 7 insertions(+)
13
tests/tcg/aarch64/bti-2.c | 116 ++++++++++++++++++++++++++++++
12
14
tests/tcg/aarch64/bti-crt.inc.c | 51 +++++++++++++
13
diff --git a/target/arm/helper.c b/target/arm/helper.c
15
tests/tcg/aarch64/Makefile.target | 10 +++
14
index XXXXXXX..XXXXXXX 100644
16
tests/tcg/configure.sh | 4 ++
15
--- a/target/arm/helper.c
17
5 files changed, 243 insertions(+)
16
+++ b/target/arm/helper.c
18
create mode 100644 tests/tcg/aarch64/bti-1.c
19
create mode 100644 tests/tcg/aarch64/bti-2.c
20
create mode 100644 tests/tcg/aarch64/bti-crt.inc.c
21
22
diff --git a/tests/tcg/aarch64/bti-1.c b/tests/tcg/aarch64/bti-1.c
23
new file mode 100644
24
index XXXXXXX..XXXXXXX
25
--- /dev/null
26
+++ b/tests/tcg/aarch64/bti-1.c
17
@@ -XXX,XX +XXX,XX @@
27
@@ -XXX,XX +XXX,XX @@
18
+/*
28
+/*
19
+ * ARM generic helpers.
29
+ * Branch target identification, basic notskip cases.
30
+ */
31
+
32
+#include "bti-crt.inc.c"
33
+
34
+static void skip2_sigill(int sig, siginfo_t *info, ucontext_t *uc)
35
+{
36
+ uc->uc_mcontext.pc += 8;
37
+ uc->uc_mcontext.pstate = 1;
38
+}
39
+
40
+#define NOP "nop"
41
+#define BTI_N "hint #32"
42
+#define BTI_C "hint #34"
43
+#define BTI_J "hint #36"
44
+#define BTI_JC "hint #38"
45
+
46
+#define BTYPE_1(DEST) \
47
+ asm("mov %0,#1; adr x16, 1f; br x16; 1: " DEST "; mov %0,#0" \
48
+ : "=r"(skipped) : : "x16")
49
+
50
+#define BTYPE_2(DEST) \
51
+ asm("mov %0,#1; adr x16, 1f; blr x16; 1: " DEST "; mov %0,#0" \
52
+ : "=r"(skipped) : : "x16", "x30")
53
+
54
+#define BTYPE_3(DEST) \
55
+ asm("mov %0,#1; adr x15, 1f; br x15; 1: " DEST "; mov %0,#0" \
56
+ : "=r"(skipped) : : "x15")
57
+
58
+#define TEST(WHICH, DEST, EXPECT) \
59
+ do { WHICH(DEST); fail += skipped ^ EXPECT; } while (0)
60
+
61
+
62
+int main()
63
+{
64
+ int fail = 0;
65
+ int skipped;
66
+
67
+ /* Signal-like with SA_SIGINFO. */
68
+ signal_info(SIGILL, skip2_sigill);
69
+
70
+ TEST(BTYPE_1, NOP, 1);
71
+ TEST(BTYPE_1, BTI_N, 1);
72
+ TEST(BTYPE_1, BTI_C, 0);
73
+ TEST(BTYPE_1, BTI_J, 0);
74
+ TEST(BTYPE_1, BTI_JC, 0);
75
+
76
+ TEST(BTYPE_2, NOP, 1);
77
+ TEST(BTYPE_2, BTI_N, 1);
78
+ TEST(BTYPE_2, BTI_C, 0);
79
+ TEST(BTYPE_2, BTI_J, 1);
80
+ TEST(BTYPE_2, BTI_JC, 0);
81
+
82
+ TEST(BTYPE_3, NOP, 1);
83
+ TEST(BTYPE_3, BTI_N, 1);
84
+ TEST(BTYPE_3, BTI_C, 1);
85
+ TEST(BTYPE_3, BTI_J, 0);
86
+ TEST(BTYPE_3, BTI_JC, 0);
87
+
88
+ return fail;
89
+}
90
diff --git a/tests/tcg/aarch64/bti-2.c b/tests/tcg/aarch64/bti-2.c
91
new file mode 100644
92
index XXXXXXX..XXXXXXX
93
--- /dev/null
94
+++ b/tests/tcg/aarch64/bti-2.c
95
@@ -XXX,XX +XXX,XX @@
96
+/*
97
+ * Branch target identification, basic notskip cases.
98
+ */
99
+
100
+#include <stdio.h>
101
+#include <signal.h>
102
+#include <string.h>
103
+#include <unistd.h>
104
+#include <sys/mman.h>
105
+
106
+#ifndef PROT_BTI
107
+#define PROT_BTI 0x10
108
+#endif
109
+
110
+static void skip2_sigill(int sig, siginfo_t *info, void *vuc)
111
+{
112
+ ucontext_t *uc = vuc;
113
+ uc->uc_mcontext.pc += 8;
114
+ uc->uc_mcontext.pstate = 1;
115
+}
116
+
117
+#define NOP "nop"
118
+#define BTI_N "hint #32"
119
+#define BTI_C "hint #34"
120
+#define BTI_J "hint #36"
121
+#define BTI_JC "hint #38"
122
+
123
+#define BTYPE_1(DEST) \
124
+ "mov x1, #1\n\t" \
125
+ "adr x16, 1f\n\t" \
126
+ "br x16\n" \
127
+"1: " DEST "\n\t" \
128
+ "mov x1, #0"
129
+
130
+#define BTYPE_2(DEST) \
131
+ "mov x1, #1\n\t" \
132
+ "adr x16, 1f\n\t" \
133
+ "blr x16\n" \
134
+"1: " DEST "\n\t" \
135
+ "mov x1, #0"
136
+
137
+#define BTYPE_3(DEST) \
138
+ "mov x1, #1\n\t" \
139
+ "adr x15, 1f\n\t" \
140
+ "br x15\n" \
141
+"1: " DEST "\n\t" \
142
+ "mov x1, #0"
143
+
144
+#define TEST(WHICH, DEST, EXPECT) \
145
+ WHICH(DEST) "\n" \
146
+ ".if " #EXPECT "\n\t" \
147
+ "eor x1, x1," #EXPECT "\n" \
148
+ ".endif\n\t" \
149
+ "add x0, x0, x1\n\t"
150
+
151
+asm("\n"
152
+"test_begin:\n\t"
153
+ BTI_C "\n\t"
154
+ "mov x2, x30\n\t"
155
+ "mov x0, #0\n\t"
156
+
157
+ TEST(BTYPE_1, NOP, 1)
158
+ TEST(BTYPE_1, BTI_N, 1)
159
+ TEST(BTYPE_1, BTI_C, 0)
160
+ TEST(BTYPE_1, BTI_J, 0)
161
+ TEST(BTYPE_1, BTI_JC, 0)
162
+
163
+ TEST(BTYPE_2, NOP, 1)
164
+ TEST(BTYPE_2, BTI_N, 1)
165
+ TEST(BTYPE_2, BTI_C, 0)
166
+ TEST(BTYPE_2, BTI_J, 1)
167
+ TEST(BTYPE_2, BTI_JC, 0)
168
+
169
+ TEST(BTYPE_3, NOP, 1)
170
+ TEST(BTYPE_3, BTI_N, 1)
171
+ TEST(BTYPE_3, BTI_C, 1)
172
+ TEST(BTYPE_3, BTI_J, 0)
173
+ TEST(BTYPE_3, BTI_JC, 0)
174
+
175
+ "ret x2\n"
176
+"test_end:"
177
+);
178
+
179
+int main()
180
+{
181
+ struct sigaction sa;
182
+ void *tb, *te;
183
+
184
+ void *p = mmap(0, getpagesize(),
185
+ PROT_EXEC | PROT_READ | PROT_WRITE | PROT_BTI,
186
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
187
+ if (p == MAP_FAILED) {
188
+ perror("mmap");
189
+ return 1;
190
+ }
191
+
192
+ memset(&sa, 0, sizeof(sa));
193
+ sa.sa_sigaction = skip2_sigill;
194
+ sa.sa_flags = SA_SIGINFO;
195
+ if (sigaction(SIGILL, &sa, NULL) < 0) {
196
+ perror("sigaction");
197
+ return 1;
198
+ }
199
+
200
+ /*
201
+ * ??? With "extern char test_begin[]", some compiler versions
202
+ * will use :got references, and some linker versions will
203
+ * resolve this reference to a static symbol incorrectly.
204
+ * Bypass this error by using a pc-relative reference directly.
205
+ */
206
+ asm("adr %0, test_begin; adr %1, test_end" : "=r"(tb), "=r"(te));
207
+
208
+ memcpy(p, tb, te - tb);
209
+
210
+ return ((int (*)(void))p)();
211
+}
212
diff --git a/tests/tcg/aarch64/bti-crt.inc.c b/tests/tcg/aarch64/bti-crt.inc.c
213
new file mode 100644
214
index XXXXXXX..XXXXXXX
215
--- /dev/null
216
+++ b/tests/tcg/aarch64/bti-crt.inc.c
217
@@ -XXX,XX +XXX,XX @@
218
+/*
219
+ * Minimal user-environment for testing BTI.
20
+ *
220
+ *
21
+ * This code is licensed under the GNU GPL v2 or later.
221
+ * Normal libc is not (yet) built with BTI support enabled,
22
+ *
222
+ * and so could generate a BTI TRAP before ever reaching main.
23
+ * SPDX-License-Identifier: GPL-2.0-or-later
24
+ */
223
+ */
25
#include "qemu/osdep.h"
224
+
26
#include "qemu/units.h"
225
+#include <stdlib.h>
27
#include "target/arm/idau.h"
226
+#include <signal.h>
227
+#include <ucontext.h>
228
+#include <asm/unistd.h>
229
+
230
+int main(void);
231
+
232
+void _start(void)
233
+{
234
+ exit(main());
235
+}
236
+
237
+void exit(int ret)
238
+{
239
+ register int x0 __asm__("x0") = ret;
240
+ register int x8 __asm__("x8") = __NR_exit;
241
+
242
+ asm volatile("svc #0" : : "r"(x0), "r"(x8));
243
+ __builtin_unreachable();
244
+}
245
+
246
+/*
247
+ * Irritatingly, the user API struct sigaction does not match the
248
+ * kernel API struct sigaction. So for simplicity, isolate the
249
+ * kernel ABI here, and make this act like signal.
250
+ */
251
+void signal_info(int sig, void (*fn)(int, siginfo_t *, ucontext_t *))
252
+{
253
+ struct kernel_sigaction {
254
+ void (*handler)(int, siginfo_t *, ucontext_t *);
255
+ unsigned long flags;
256
+ unsigned long restorer;
257
+ unsigned long mask;
258
+ } sa = { fn, SA_SIGINFO, 0, 0 };
259
+
260
+ register int x0 __asm__("x0") = sig;
261
+ register void *x1 __asm__("x1") = &sa;
262
+ register void *x2 __asm__("x2") = 0;
263
+ register int x3 __asm__("x3") = sizeof(unsigned long);
264
+ register int x8 __asm__("x8") = __NR_rt_sigaction;
265
+
266
+ asm volatile("svc #0"
267
+ : : "r"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x8) : "memory");
268
+}
269
diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
270
index XXXXXXX..XXXXXXX 100644
271
--- a/tests/tcg/aarch64/Makefile.target
272
+++ b/tests/tcg/aarch64/Makefile.target
273
@@ -XXX,XX +XXX,XX @@ run-pauth-%: QEMU_OPTS += -cpu max
274
run-plugin-pauth-%: QEMU_OPTS += -cpu max
275
endif
276
277
+# BTI Tests
278
+# bti-1 tests the elf notes, so we require special compiler support.
279
+ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_ARMV8_BTI),)
280
+AARCH64_TESTS += bti-1
281
+bti-1: CFLAGS += -mbranch-protection=standard
282
+bti-1: LDFLAGS += -nostdlib
283
+endif
284
+# bti-2 tests PROT_BTI, so no special compiler support required.
285
+AARCH64_TESTS += bti-2
286
+
287
# Semihosting smoke test for linux-user
288
AARCH64_TESTS += semihosting
289
run-semihosting: semihosting
290
diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh
291
index XXXXXXX..XXXXXXX 100755
292
--- a/tests/tcg/configure.sh
293
+++ b/tests/tcg/configure.sh
294
@@ -XXX,XX +XXX,XX @@ for target in $target_list; do
295
-march=armv8.3-a -o $TMPE $TMPC; then
296
echo "CROSS_CC_HAS_ARMV8_3=y" >> $config_target_mak
297
fi
298
+ if do_compiler "$target_compiler" $target_compiler_cflags \
299
+ -mbranch-protection=standard -o $TMPE $TMPC; then
300
+ echo "CROSS_CC_HAS_ARMV8_BTI=y" >> $config_target_mak
301
+ fi
302
;;
303
esac
304
28
--
305
--
29
2.20.1
306
2.20.1
30
307
31
308
diff view generated by jsdifflib
1
From: Andrey Smirnov <andrew.smirnov@gmail.com>
1
From: Thomas Huth <thuth@redhat.com>
2
2
3
MSI mapping needs to be update when MSI address changes, so add the
3
When compiling with -Werror=implicit-fallthrough, gcc complains about
4
code to do so.
4
missing fallthrough annotations in this file. Looking at the code,
5
the fallthrough is very likely intended here, so add some comments
6
to silence the compiler warnings.
5
7
6
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
8
Signed-off-by: Thomas Huth <thuth@redhat.com>
7
Cc: Peter Maydell <peter.maydell@linaro.org>
9
Message-id: 20201020105938.23209-1-thuth@redhat.com
8
Cc: Michael S. Tsirkin <mst@redhat.com>
9
Cc: qemu-devel@nongnu.org
10
Cc: qemu-arm@nongnu.org
11
Acked-by: Michael S. Tsirkin <mst@redhat.com>
12
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
---
12
---
15
hw/pci-host/designware.c | 2 ++
13
hw/arm/highbank.c | 2 ++
16
1 file changed, 2 insertions(+)
14
1 file changed, 2 insertions(+)
17
15
18
diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c
16
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
19
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
20
--- a/hw/pci-host/designware.c
18
--- a/hw/arm/highbank.c
21
+++ b/hw/pci-host/designware.c
19
+++ b/hw/arm/highbank.c
22
@@ -XXX,XX +XXX,XX @@ static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address,
20
@@ -XXX,XX +XXX,XX @@ static void hb_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
23
case DESIGNWARE_PCIE_MSI_ADDR_LO:
21
address_space_stl_notdirty(&address_space_memory,
24
root->msi.base &= 0xFFFFFFFF00000000ULL;
22
SMP_BOOT_REG + 0x30, 0,
25
root->msi.base |= val;
23
MEMTXATTRS_UNSPECIFIED, NULL);
26
+ designware_pcie_root_update_msi_mapping(root);
24
+ /* fallthrough */
27
break;
25
case 3:
28
26
address_space_stl_notdirty(&address_space_memory,
29
case DESIGNWARE_PCIE_MSI_ADDR_HI:
27
SMP_BOOT_REG + 0x20, 0,
30
root->msi.base &= 0x00000000FFFFFFFFULL;
28
MEMTXATTRS_UNSPECIFIED, NULL);
31
root->msi.base |= (uint64_t)val << 32;
29
+ /* fallthrough */
32
+ designware_pcie_root_update_msi_mapping(root);
30
case 2:
33
break;
31
address_space_stl_notdirty(&address_space_memory,
34
32
SMP_BOOT_REG + 0x10, 0,
35
case DESIGNWARE_PCIE_MSI_INTR0_ENABLE:
36
--
33
--
37
2.20.1
34
2.20.1
38
35
39
36
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru>
2
2
3
Group ARM objects together, TCG related ones at the bottom.
3
This patch sets min_cpus field for xlnx-versal-virt platform,
4
This will help when restricting TCG-only objects.
4
because it always creates XLNX_VERSAL_NR_ACPUS cpus even with
5
-smp 1 command line option.
5
6
6
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
7
Signed-off-by: Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru>
7
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Message-id: 20190701132516.26392-3-philmd@redhat.com
9
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
10
Message-id: 160343854912.8460.17915238517799132371.stgit@pasha-ThinkPad-X280
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
12
---
11
target/arm/Makefile.objs | 10 ++++++----
13
hw/arm/xlnx-versal-virt.c | 1 +
12
1 file changed, 6 insertions(+), 4 deletions(-)
14
1 file changed, 1 insertion(+)
13
15
14
diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
16
diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c
15
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/Makefile.objs
18
--- a/hw/arm/xlnx-versal-virt.c
17
+++ b/target/arm/Makefile.objs
19
+++ b/hw/arm/xlnx-versal-virt.c
18
@@ -XXX,XX +XXX,XX @@ obj-$(CONFIG_KVM) += kvm.o
20
@@ -XXX,XX +XXX,XX @@ static void versal_virt_machine_class_init(ObjectClass *oc, void *data)
19
obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o
21
20
obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o
22
mc->desc = "Xilinx Versal Virtual development board";
21
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
23
mc->init = versal_virt_init;
22
-obj-y += translate.o op_helper.o helper.o cpu.o
24
+ mc->min_cpus = XLNX_VERSAL_NR_ACPUS;
23
-obj-y += neon_helper.o iwmmxt_helper.o vec_helper.o vfp_helper.o
25
mc->max_cpus = XLNX_VERSAL_NR_ACPUS;
24
-obj-y += gdbstub.o
26
mc->default_cpus = XLNX_VERSAL_NR_ACPUS;
25
+obj-y += helper.o vfp_helper.o
27
mc->no_cdrom = true;
26
+obj-y += cpu.o gdbstub.o
27
obj-$(TARGET_AARCH64) += cpu64.o gdbstub64.o
28
-obj-y += crypto_helper.o
29
obj-$(CONFIG_SOFTMMU) += arm-powerctl.o
30
31
DECODETREE = $(SRC_PATH)/scripts/decodetree.py
32
@@ -XXX,XX +XXX,XX @@ target/arm/translate-sve.o: target/arm/decode-sve.inc.c
33
target/arm/translate.o: target/arm/decode-vfp.inc.c
34
target/arm/translate.o: target/arm/decode-vfp-uncond.inc.c
35
36
+obj-y += translate.o op_helper.o
37
+obj-y += crypto_helper.o
38
+obj-y += iwmmxt_helper.o vec_helper.o neon_helper.o
39
+
40
obj-$(TARGET_AARCH64) += translate-a64.o helper-a64.o
41
obj-$(TARGET_AARCH64) += translate-sve.o sve_helper.o
42
obj-$(TARGET_AARCH64) += pauth_helper.o
43
--
28
--
44
2.20.1
29
2.20.1
45
30
46
31
diff view generated by jsdifflib
1
From: Andrey Smirnov <andrew.smirnov@gmail.com>
1
From: Havard Skinnemoen <hskinnemoen@google.com>
2
2
3
Add no-op/unimplemented PCIE PHY IP block. Needed by new kernels to
3
This allows us to reuse npcm7xx_timer_pause for the watchdog timer.
4
use PCIE.
5
4
6
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
5
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Cc: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
8
Cc: Michael S. Tsirkin <mst@redhat.com>
9
Cc: qemu-devel@nongnu.org
10
Cc: qemu-arm@nongnu.org
11
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
8
---
14
include/hw/arm/fsl-imx7.h | 3 +++
9
hw/timer/npcm7xx_timer.c | 6 +++---
15
hw/arm/fsl-imx7.c | 5 +++++
10
1 file changed, 3 insertions(+), 3 deletions(-)
16
2 files changed, 8 insertions(+)
17
11
18
diff --git a/include/hw/arm/fsl-imx7.h b/include/hw/arm/fsl-imx7.h
12
diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c
19
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
20
--- a/include/hw/arm/fsl-imx7.h
14
--- a/hw/timer/npcm7xx_timer.c
21
+++ b/include/hw/arm/fsl-imx7.h
15
+++ b/hw/timer/npcm7xx_timer.c
22
@@ -XXX,XX +XXX,XX @@ enum FslIMX7MemoryMap {
16
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_pause(NPCM7xxTimer *t)
23
FSL_IMX7_ADC2_ADDR = 0x30620000,
17
timer_del(&t->qtimer);
24
FSL_IMX7_ADCn_SIZE = 0x1000,
18
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
25
19
t->remaining_ns = t->expires_ns - now;
26
+ FSL_IMX7_PCIE_PHY_ADDR = 0x306D0000,
20
- if (t->remaining_ns <= 0) {
27
+ FSL_IMX7_PCIE_PHY_SIZE = 0x10000,
21
- npcm7xx_timer_reached_zero(t);
28
+
22
- }
29
FSL_IMX7_GPC_ADDR = 0x303A0000,
30
31
FSL_IMX7_I2C1_ADDR = 0x30A20000,
32
diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/hw/arm/fsl-imx7.c
35
+++ b/hw/arm/fsl-imx7.c
36
@@ -XXX,XX +XXX,XX @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
37
*/
38
create_unimplemented_device("dma-apbh", FSL_IMX7_DMA_APBH_ADDR,
39
FSL_IMX7_DMA_APBH_SIZE);
40
+ /*
41
+ * PCIe PHY
42
+ */
43
+ create_unimplemented_device("pcie-phy", FSL_IMX7_PCIE_PHY_ADDR,
44
+ FSL_IMX7_PCIE_PHY_SIZE);
45
}
23
}
46
24
47
static void fsl_imx7_class_init(ObjectClass *oc, void *data)
25
/*
26
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr)
27
} else {
28
t->tcsr &= ~NPCM7XX_TCSR_CACT;
29
npcm7xx_timer_pause(t);
30
+ if (t->remaining_ns <= 0) {
31
+ npcm7xx_timer_reached_zero(t);
32
+ }
33
}
34
}
35
}
48
--
36
--
49
2.20.1
37
2.20.1
50
38
51
39
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
In the next commit we will split the M-profile functions from this
3
The watchdog is part of NPCM7XX's timer module. Its behavior is
4
file. Some function will be called out of helper.c. Declare them in
4
controlled by the WTCR register in the timer.
5
the "internals.h" header.
6
5
7
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
6
When enabled, the watchdog issues an interrupt signal after a pre-set
8
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
7
amount of cycles, and issues a reset signal shortly after that.
9
Message-id: 20190701132516.26392-22-philmd@redhat.com
8
9
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
10
Signed-off-by: Hao Wu <wuhaotsh@google.com>
11
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
12
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
13
[PMM: deleted blank line at end of npcm_watchdog_timer-test.c]
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
15
---
12
target/arm/internals.h | 42 ++++++++++++++++++++++++++++++++++++++++++
16
include/hw/misc/npcm7xx_clk.h | 2 +
13
target/arm/helper.c | 38 ++------------------------------------
17
include/hw/timer/npcm7xx_timer.h | 48 +++-
14
2 files changed, 44 insertions(+), 36 deletions(-)
18
hw/arm/npcm7xx.c | 12 +
19
hw/misc/npcm7xx_clk.c | 28 ++
20
hw/timer/npcm7xx_timer.c | 266 ++++++++++++++----
21
tests/qtest/npcm7xx_watchdog_timer-test.c | 319 ++++++++++++++++++++++
22
MAINTAINERS | 1 +
23
tests/qtest/meson.build | 2 +-
24
8 files changed, 624 insertions(+), 54 deletions(-)
25
create mode 100644 tests/qtest/npcm7xx_watchdog_timer-test.c
15
26
16
diff --git a/target/arm/internals.h b/target/arm/internals.h
27
diff --git a/include/hw/misc/npcm7xx_clk.h b/include/hw/misc/npcm7xx_clk.h
17
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
18
--- a/target/arm/internals.h
29
--- a/include/hw/misc/npcm7xx_clk.h
19
+++ b/target/arm/internals.h
30
+++ b/include/hw/misc/npcm7xx_clk.h
20
@@ -XXX,XX +XXX,XX @@ static inline uint32_t v7m_sp_limit(CPUARMState *env)
31
@@ -XXX,XX +XXX,XX @@
32
*/
33
#define NPCM7XX_CLK_NR_REGS (0x70 / sizeof(uint32_t))
34
35
+#define NPCM7XX_WATCHDOG_RESET_GPIO_IN "npcm7xx-clk-watchdog-reset-gpio-in"
36
+
37
typedef struct NPCM7xxCLKState {
38
SysBusDevice parent;
39
40
diff --git a/include/hw/timer/npcm7xx_timer.h b/include/hw/timer/npcm7xx_timer.h
41
index XXXXXXX..XXXXXXX 100644
42
--- a/include/hw/timer/npcm7xx_timer.h
43
+++ b/include/hw/timer/npcm7xx_timer.h
44
@@ -XXX,XX +XXX,XX @@
45
*/
46
#define NPCM7XX_TIMER_NR_REGS (0x54 / sizeof(uint32_t))
47
48
+/* The basic watchdog timer period is 2^14 clock cycles. */
49
+#define NPCM7XX_WATCHDOG_BASETIME_SHIFT 14
50
+
51
+#define NPCM7XX_WATCHDOG_RESET_GPIO_OUT "npcm7xx-clk-watchdog-reset-gpio-out"
52
+
53
typedef struct NPCM7xxTimerCtrlState NPCM7xxTimerCtrlState;
54
55
/**
56
- * struct NPCM7xxTimer - Individual timer state.
57
- * @irq: GIC interrupt line to fire on expiration (if enabled).
58
+ * struct NPCM7xxBaseTimer - Basic functionality that both regular timer and
59
+ * watchdog timer use.
60
* @qtimer: QEMU timer that notifies us on expiration.
61
* @expires_ns: Absolute virtual expiration time.
62
* @remaining_ns: Remaining time until expiration if timer is paused.
63
+ */
64
+typedef struct NPCM7xxBaseTimer {
65
+ QEMUTimer qtimer;
66
+ int64_t expires_ns;
67
+ int64_t remaining_ns;
68
+} NPCM7xxBaseTimer;
69
+
70
+/**
71
+ * struct NPCM7xxTimer - Individual timer state.
72
+ * @ctrl: The timer module that owns this timer.
73
+ * @irq: GIC interrupt line to fire on expiration (if enabled).
74
+ * @base_timer: The basic timer functionality for this timer.
75
* @tcsr: The Timer Control and Status Register.
76
* @ticr: The Timer Initial Count Register.
77
*/
78
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxTimer {
79
NPCM7xxTimerCtrlState *ctrl;
80
81
qemu_irq irq;
82
- QEMUTimer qtimer;
83
- int64_t expires_ns;
84
- int64_t remaining_ns;
85
+ NPCM7xxBaseTimer base_timer;
86
87
uint32_t tcsr;
88
uint32_t ticr;
89
} NPCM7xxTimer;
90
91
+/**
92
+ * struct NPCM7xxWatchdogTimer - The watchdog timer state.
93
+ * @ctrl: The timer module that owns this timer.
94
+ * @irq: GIC interrupt line to fire on expiration (if enabled).
95
+ * @reset_signal: The GPIO used to send a reset signal.
96
+ * @base_timer: The basic timer functionality for this timer.
97
+ * @wtcr: The Watchdog Timer Control Register.
98
+ */
99
+typedef struct NPCM7xxWatchdogTimer {
100
+ NPCM7xxTimerCtrlState *ctrl;
101
+
102
+ qemu_irq irq;
103
+ qemu_irq reset_signal;
104
+ NPCM7xxBaseTimer base_timer;
105
+
106
+ uint32_t wtcr;
107
+} NPCM7xxWatchdogTimer;
108
+
109
/**
110
* struct NPCM7xxTimerCtrlState - Timer Module device state.
111
* @parent: System bus device.
112
* @iomem: Memory region through which registers are accessed.
113
+ * @index: The index of this timer module.
114
* @tisr: The Timer Interrupt Status Register.
115
- * @wtcr: The Watchdog Timer Control Register.
116
* @timer: The five individual timers managed by this module.
117
+ * @watchdog_timer: The watchdog timer managed by this module.
118
*/
119
struct NPCM7xxTimerCtrlState {
120
SysBusDevice parent;
121
@@ -XXX,XX +XXX,XX @@ struct NPCM7xxTimerCtrlState {
122
MemoryRegion iomem;
123
124
uint32_t tisr;
125
- uint32_t wtcr;
126
127
NPCM7xxTimer timer[NPCM7XX_TIMERS_PER_CTRL];
128
+ NPCM7xxWatchdogTimer watchdog_timer;
129
};
130
131
#define TYPE_NPCM7XX_TIMER "npcm7xx-timer"
132
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
133
index XXXXXXX..XXXXXXX 100644
134
--- a/hw/arm/npcm7xx.c
135
+++ b/hw/arm/npcm7xx.c
136
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxInterrupt {
137
NPCM7XX_TIMER12_IRQ,
138
NPCM7XX_TIMER13_IRQ,
139
NPCM7XX_TIMER14_IRQ,
140
+ NPCM7XX_WDG0_IRQ = 47, /* Timer Module 0 Watchdog */
141
+ NPCM7XX_WDG1_IRQ, /* Timer Module 1 Watchdog */
142
+ NPCM7XX_WDG2_IRQ, /* Timer Module 2 Watchdog */
143
};
144
145
/* Total number of GIC interrupts, including internal Cortex-A9 interrupts. */
146
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
147
qemu_irq irq = npcm7xx_irq(s, first_irq + j);
148
sysbus_connect_irq(sbd, j, irq);
149
}
150
+
151
+ /* IRQ for watchdogs */
152
+ sysbus_connect_irq(sbd, NPCM7XX_TIMERS_PER_CTRL,
153
+ npcm7xx_irq(s, NPCM7XX_WDG0_IRQ + i));
154
+ /* GPIO that connects clk module with watchdog */
155
+ qdev_connect_gpio_out_named(DEVICE(&s->tim[i]),
156
+ NPCM7XX_WATCHDOG_RESET_GPIO_OUT, 0,
157
+ qdev_get_gpio_in_named(DEVICE(&s->clk),
158
+ NPCM7XX_WATCHDOG_RESET_GPIO_IN, i));
21
}
159
}
160
161
/* UART0..3 (16550 compatible) */
162
diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
163
index XXXXXXX..XXXXXXX 100644
164
--- a/hw/misc/npcm7xx_clk.c
165
+++ b/hw/misc/npcm7xx_clk.c
166
@@ -XXX,XX +XXX,XX @@
167
#include "qemu/osdep.h"
168
169
#include "hw/misc/npcm7xx_clk.h"
170
+#include "hw/timer/npcm7xx_timer.h"
171
#include "migration/vmstate.h"
172
#include "qemu/error-report.h"
173
#include "qemu/log.h"
174
@@ -XXX,XX +XXX,XX @@
175
#include "qemu/timer.h"
176
#include "qemu/units.h"
177
#include "trace.h"
178
+#include "sysemu/watchdog.h"
179
180
#define PLLCON_LOKI BIT(31)
181
#define PLLCON_LOKS BIT(30)
182
@@ -XXX,XX +XXX,XX @@ static const uint32_t cold_reset_values[NPCM7XX_CLK_NR_REGS] = {
183
[NPCM7XX_CLK_AHBCKFI] = 0x000000c8,
184
};
185
186
+/* Register Field Definitions */
187
+#define NPCM7XX_CLK_WDRCR_CA9C BIT(0) /* Cortex A9 Cores */
188
+
189
+/* The number of watchdogs that can trigger a reset. */
190
+#define NPCM7XX_NR_WATCHDOGS (3)
191
+
192
static uint64_t npcm7xx_clk_read(void *opaque, hwaddr offset, unsigned size)
193
{
194
uint32_t reg = offset / sizeof(uint32_t);
195
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_write(void *opaque, hwaddr offset,
196
s->regs[reg] = value;
22
}
197
}
23
198
24
+/**
199
+/* Perform reset action triggered by a watchdog */
25
+ * v7m_cpacr_pass:
200
+static void npcm7xx_clk_perform_watchdog_reset(void *opaque, int n,
26
+ * Return true if the v7M CPACR permits access to the FPU for the specified
201
+ int level)
27
+ * security state and privilege level.
202
+{
203
+ NPCM7xxCLKState *clk = NPCM7XX_CLK(opaque);
204
+ uint32_t rcr;
205
+
206
+ g_assert(n >= 0 && n <= NPCM7XX_NR_WATCHDOGS);
207
+ rcr = clk->regs[NPCM7XX_CLK_WD0RCR + n];
208
+ if (rcr & NPCM7XX_CLK_WDRCR_CA9C) {
209
+ watchdog_perform_action();
210
+ } else {
211
+ qemu_log_mask(LOG_UNIMP,
212
+ "%s: only CPU reset is implemented. (requested 0x%" PRIx32")\n",
213
+ __func__, rcr);
214
+ }
215
+}
216
+
217
static const struct MemoryRegionOps npcm7xx_clk_ops = {
218
.read = npcm7xx_clk_read,
219
.write = npcm7xx_clk_write,
220
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_init(Object *obj)
221
memory_region_init_io(&s->iomem, obj, &npcm7xx_clk_ops, s,
222
TYPE_NPCM7XX_CLK, 4 * KiB);
223
sysbus_init_mmio(&s->parent, &s->iomem);
224
+ qdev_init_gpio_in_named(DEVICE(s), npcm7xx_clk_perform_watchdog_reset,
225
+ NPCM7XX_WATCHDOG_RESET_GPIO_IN, NPCM7XX_NR_WATCHDOGS);
226
}
227
228
static const VMStateDescription vmstate_npcm7xx_clk = {
229
diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c
230
index XXXXXXX..XXXXXXX 100644
231
--- a/hw/timer/npcm7xx_timer.c
232
+++ b/hw/timer/npcm7xx_timer.c
233
@@ -XXX,XX +XXX,XX @@
234
#include "qemu/osdep.h"
235
236
#include "hw/irq.h"
237
+#include "hw/qdev-properties.h"
238
#include "hw/misc/npcm7xx_clk.h"
239
#include "hw/timer/npcm7xx_timer.h"
240
#include "migration/vmstate.h"
241
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxTimerRegisters {
242
#define NPCM7XX_TCSR_PRESCALE_START 0
243
#define NPCM7XX_TCSR_PRESCALE_LEN 8
244
245
+#define NPCM7XX_WTCR_WTCLK(rv) extract32(rv, 10, 2)
246
+#define NPCM7XX_WTCR_FREEZE_EN BIT(9)
247
+#define NPCM7XX_WTCR_WTE BIT(7)
248
+#define NPCM7XX_WTCR_WTIE BIT(6)
249
+#define NPCM7XX_WTCR_WTIS(rv) extract32(rv, 4, 2)
250
+#define NPCM7XX_WTCR_WTIF BIT(3)
251
+#define NPCM7XX_WTCR_WTRF BIT(2)
252
+#define NPCM7XX_WTCR_WTRE BIT(1)
253
+#define NPCM7XX_WTCR_WTR BIT(0)
254
+
255
+/*
256
+ * The number of clock cycles between interrupt and reset in watchdog, used
257
+ * by the software to handle the interrupt before system is reset.
28
+ */
258
+ */
29
+static inline bool v7m_cpacr_pass(CPUARMState *env,
259
+#define NPCM7XX_WATCHDOG_INTERRUPT_TO_RESET_CYCLES 1024
30
+ bool is_secure, bool is_priv)
260
+
31
+{
261
+/* Start or resume the timer. */
32
+ switch (extract32(env->v7m.cpacr[is_secure], 20, 2)) {
262
+static void npcm7xx_timer_start(NPCM7xxBaseTimer *t)
263
+{
264
+ int64_t now;
265
+
266
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
267
+ t->expires_ns = now + t->remaining_ns;
268
+ timer_mod(&t->qtimer, t->expires_ns);
269
+}
270
+
271
+/* Stop counting. Record the time remaining so we can continue later. */
272
+static void npcm7xx_timer_pause(NPCM7xxBaseTimer *t)
273
+{
274
+ int64_t now;
275
+
276
+ timer_del(&t->qtimer);
277
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
278
+ t->remaining_ns = t->expires_ns - now;
279
+}
280
+
281
+/* Delete the timer and reset it to default state. */
282
+static void npcm7xx_timer_clear(NPCM7xxBaseTimer *t)
283
+{
284
+ timer_del(&t->qtimer);
285
+ t->expires_ns = 0;
286
+ t->remaining_ns = 0;
287
+}
288
+
289
/*
290
* Returns the index of timer in the tc->timer array. This can be used to
291
* locate the registers that belong to this timer.
292
@@ -XXX,XX +XXX,XX @@ static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns)
293
return count;
294
}
295
296
+static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t)
297
+{
298
+ switch (NPCM7XX_WTCR_WTCLK(t->wtcr)) {
33
+ case 0:
299
+ case 0:
34
+ case 2: /* UNPREDICTABLE: we treat like 0 */
300
+ return 1;
35
+ return false;
36
+ case 1:
301
+ case 1:
37
+ return is_priv;
302
+ return 256;
303
+ case 2:
304
+ return 2048;
38
+ case 3:
305
+ case 3:
39
+ return true;
306
+ return 65536;
40
+ default:
307
+ default:
41
+ g_assert_not_reached();
308
+ g_assert_not_reached();
42
+ }
309
+ }
43
+}
310
+}
44
+
311
+
45
/**
312
+static void npcm7xx_watchdog_timer_reset_cycles(NPCM7xxWatchdogTimer *t,
46
* aarch32_mode_name(): Return name of the AArch32 CPU mode
313
+ int64_t cycles)
47
* @psr: Program Status Register indicating CPU mode
314
+{
48
@@ -XXX,XX +XXX,XX @@ static inline int exception_target_el(CPUARMState *env)
315
+ uint32_t prescaler = npcm7xx_watchdog_timer_prescaler(t);
49
316
+ int64_t ns = (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ) * cycles;
50
#ifndef CONFIG_USER_ONLY
317
+
51
318
+ /*
52
+/* Security attributes for an address, as returned by v8m_security_lookup. */
319
+ * The reset function always clears the current timer. The caller of the
53
+typedef struct V8M_SAttributes {
320
+ * this needs to decide whether to start the watchdog timer based on
54
+ bool subpage; /* true if these attrs don't cover the whole TARGET_PAGE */
321
+ * specific flag in WTCR.
55
+ bool ns;
322
+ */
56
+ bool nsc;
323
+ npcm7xx_timer_clear(&t->base_timer);
57
+ uint8_t sregion;
324
+
58
+ bool srvalid;
325
+ ns *= prescaler;
59
+ uint8_t iregion;
326
+ t->base_timer.remaining_ns = ns;
60
+ bool irvalid;
327
+}
61
+} V8M_SAttributes;
328
+
62
+
329
+static void npcm7xx_watchdog_timer_reset(NPCM7xxWatchdogTimer *t)
63
+void v8m_security_lookup(CPUARMState *env, uint32_t address,
330
+{
64
+ MMUAccessType access_type, ARMMMUIdx mmu_idx,
331
+ int64_t cycles = 1;
65
+ V8M_SAttributes *sattrs);
332
+ uint32_t s = NPCM7XX_WTCR_WTIS(t->wtcr);
66
+
333
+
67
+bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
334
+ g_assert(s <= 3);
68
+ MMUAccessType access_type, ARMMMUIdx mmu_idx,
335
+
69
+ hwaddr *phys_ptr, MemTxAttrs *txattrs,
336
+ cycles <<= NPCM7XX_WATCHDOG_BASETIME_SHIFT;
70
+ int *prot, bool *is_subpage,
337
+ cycles <<= 2 * s;
71
+ ARMMMUFaultInfo *fi, uint32_t *mregion);
338
+
72
+
339
+ npcm7xx_watchdog_timer_reset_cycles(t, cycles);
73
/* Cacheability and shareability attributes for a memory access */
340
+}
74
typedef struct ARMCacheAttrs {
341
+
75
unsigned int attrs:8; /* as in the MAIR register encoding */
342
/*
76
diff --git a/target/arm/helper.c b/target/arm/helper.c
343
* Raise the interrupt line if there's a pending interrupt and interrupts are
77
index XXXXXXX..XXXXXXX 100644
344
* enabled for this timer. If not, lower it.
78
--- a/target/arm/helper.c
345
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_check_interrupt(NPCM7xxTimer *t)
79
+++ b/target/arm/helper.c
346
trace_npcm7xx_timer_irq(DEVICE(tc)->canonical_path, index, pending);
80
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
347
}
81
hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot,
348
82
target_ulong *page_size_ptr,
349
-/* Start or resume the timer. */
83
ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs);
350
-static void npcm7xx_timer_start(NPCM7xxTimer *t)
351
-{
352
- int64_t now;
84
-
353
-
85
-/* Security attributes for an address, as returned by v8m_security_lookup. */
354
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
86
-typedef struct V8M_SAttributes {
355
- t->expires_ns = now + t->remaining_ns;
87
- bool subpage; /* true if these attrs don't cover the whole TARGET_PAGE */
356
- timer_mod(&t->qtimer, t->expires_ns);
88
- bool ns;
89
- bool nsc;
90
- uint8_t sregion;
91
- bool srvalid;
92
- uint8_t iregion;
93
- bool irvalid;
94
-} V8M_SAttributes;
95
-
96
-static void v8m_security_lookup(CPUARMState *env, uint32_t address,
97
- MMUAccessType access_type, ARMMMUIdx mmu_idx,
98
- V8M_SAttributes *sattrs);
99
#endif
100
101
static void switch_mode(CPUARMState *env, int mode);
102
@@ -XXX,XX +XXX,XX @@ void arm_log_exception(int idx)
103
}
104
}
105
106
-/*
107
- * Return true if the v7M CPACR permits access to the FPU for the specified
108
- * security state and privilege level.
109
- */
110
-static bool v7m_cpacr_pass(CPUARMState *env, bool is_secure, bool is_priv)
111
-{
112
- switch (extract32(env->v7m.cpacr[is_secure], 20, 2)) {
113
- case 0:
114
- case 2: /* UNPREDICTABLE: we treat like 0 */
115
- return false;
116
- case 1:
117
- return is_priv;
118
- case 3:
119
- return true;
120
- default:
121
- g_assert_not_reached();
122
- }
123
-}
357
-}
124
-
358
-
125
/*
359
/*
126
* What kind of stack write are we doing? This affects how exceptions
360
* Called when the counter reaches zero. Sets the interrupt flag, and either
127
* generated during the stacking are treated.
361
* restarts or disables the timer.
128
@@ -XXX,XX +XXX,XX @@ static bool v8m_is_sau_exempt(CPUARMState *env,
362
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_reached_zero(NPCM7xxTimer *t)
129
(address >= 0xe00ff000 && address <= 0xe00fffff);
363
tc->tisr |= BIT(index);
364
365
if (t->tcsr & NPCM7XX_TCSR_PERIODIC) {
366
- t->remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
367
+ t->base_timer.remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
368
if (t->tcsr & NPCM7XX_TCSR_CEN) {
369
- npcm7xx_timer_start(t);
370
+ npcm7xx_timer_start(&t->base_timer);
371
}
372
} else {
373
t->tcsr &= ~(NPCM7XX_TCSR_CEN | NPCM7XX_TCSR_CACT);
374
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_reached_zero(NPCM7xxTimer *t)
375
npcm7xx_timer_check_interrupt(t);
130
}
376
}
131
377
132
-static void v8m_security_lookup(CPUARMState *env, uint32_t address,
378
-/* Stop counting. Record the time remaining so we can continue later. */
133
+void v8m_security_lookup(CPUARMState *env, uint32_t address,
379
-static void npcm7xx_timer_pause(NPCM7xxTimer *t)
134
MMUAccessType access_type, ARMMMUIdx mmu_idx,
380
-{
135
V8M_SAttributes *sattrs)
381
- int64_t now;
382
-
383
- timer_del(&t->qtimer);
384
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
385
- t->remaining_ns = t->expires_ns - now;
386
-}
387
388
/*
389
* Restart the timer from its initial value. If the timer was enabled and stays
390
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_pause(NPCM7xxTimer *t)
391
*/
392
static void npcm7xx_timer_restart(NPCM7xxTimer *t, uint32_t old_tcsr)
136
{
393
{
137
@@ -XXX,XX +XXX,XX @@ static void v8m_security_lookup(CPUARMState *env, uint32_t address,
394
- t->remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
395
+ t->base_timer.remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
396
397
if (old_tcsr & t->tcsr & NPCM7XX_TCSR_CEN) {
398
- npcm7xx_timer_start(t);
399
+ npcm7xx_timer_start(&t->base_timer);
138
}
400
}
139
}
401
}
140
402
141
-static bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
403
@@ -XXX,XX +XXX,XX @@ static uint32_t npcm7xx_timer_read_tdr(NPCM7xxTimer *t)
142
+bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
404
if (t->tcsr & NPCM7XX_TCSR_CEN) {
143
MMUAccessType access_type, ARMMMUIdx mmu_idx,
405
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
144
hwaddr *phys_ptr, MemTxAttrs *txattrs,
406
145
int *prot, bool *is_subpage,
407
- return npcm7xx_timer_ns_to_count(t, t->expires_ns - now);
408
+ return npcm7xx_timer_ns_to_count(t, t->base_timer.expires_ns - now);
409
}
410
411
- return npcm7xx_timer_ns_to_count(t, t->remaining_ns);
412
+ return npcm7xx_timer_ns_to_count(t, t->base_timer.remaining_ns);
413
}
414
415
static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr)
416
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr)
417
418
if (npcm7xx_tcsr_prescaler(old_tcsr) != npcm7xx_tcsr_prescaler(new_tcsr)) {
419
/* Recalculate time remaining based on the current TDR value. */
420
- t->remaining_ns = npcm7xx_timer_count_to_ns(t, tdr);
421
+ t->base_timer.remaining_ns = npcm7xx_timer_count_to_ns(t, tdr);
422
if (old_tcsr & t->tcsr & NPCM7XX_TCSR_CEN) {
423
- npcm7xx_timer_start(t);
424
+ npcm7xx_timer_start(&t->base_timer);
425
}
426
}
427
428
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr)
429
if ((old_tcsr ^ new_tcsr) & NPCM7XX_TCSR_CEN) {
430
if (new_tcsr & NPCM7XX_TCSR_CEN) {
431
t->tcsr |= NPCM7XX_TCSR_CACT;
432
- npcm7xx_timer_start(t);
433
+ npcm7xx_timer_start(&t->base_timer);
434
} else {
435
t->tcsr &= ~NPCM7XX_TCSR_CACT;
436
- npcm7xx_timer_pause(t);
437
- if (t->remaining_ns <= 0) {
438
+ npcm7xx_timer_pause(&t->base_timer);
439
+ if (t->base_timer.remaining_ns <= 0) {
440
npcm7xx_timer_reached_zero(t);
441
}
442
}
443
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_write_tisr(NPCM7xxTimerCtrlState *s, uint32_t value)
444
if (value & (1U << i)) {
445
npcm7xx_timer_check_interrupt(&s->timer[i]);
446
}
447
+
448
}
449
}
450
451
+static void npcm7xx_timer_write_wtcr(NPCM7xxWatchdogTimer *t, uint32_t new_wtcr)
452
+{
453
+ uint32_t old_wtcr = t->wtcr;
454
+
455
+ /*
456
+ * WTIF and WTRF are cleared by writing 1. Writing 0 makes these bits
457
+ * unchanged.
458
+ */
459
+ if (new_wtcr & NPCM7XX_WTCR_WTIF) {
460
+ new_wtcr &= ~NPCM7XX_WTCR_WTIF;
461
+ } else if (old_wtcr & NPCM7XX_WTCR_WTIF) {
462
+ new_wtcr |= NPCM7XX_WTCR_WTIF;
463
+ }
464
+ if (new_wtcr & NPCM7XX_WTCR_WTRF) {
465
+ new_wtcr &= ~NPCM7XX_WTCR_WTRF;
466
+ } else if (old_wtcr & NPCM7XX_WTCR_WTRF) {
467
+ new_wtcr |= NPCM7XX_WTCR_WTRF;
468
+ }
469
+
470
+ t->wtcr = new_wtcr;
471
+
472
+ if (new_wtcr & NPCM7XX_WTCR_WTR) {
473
+ t->wtcr &= ~NPCM7XX_WTCR_WTR;
474
+ npcm7xx_watchdog_timer_reset(t);
475
+ if (new_wtcr & NPCM7XX_WTCR_WTE) {
476
+ npcm7xx_timer_start(&t->base_timer);
477
+ }
478
+ } else if ((old_wtcr ^ new_wtcr) & NPCM7XX_WTCR_WTE) {
479
+ if (new_wtcr & NPCM7XX_WTCR_WTE) {
480
+ npcm7xx_timer_start(&t->base_timer);
481
+ } else {
482
+ npcm7xx_timer_pause(&t->base_timer);
483
+ }
484
+ }
485
+
486
+}
487
+
488
static hwaddr npcm7xx_tcsr_index(hwaddr reg)
489
{
490
switch (reg) {
491
@@ -XXX,XX +XXX,XX @@ static uint64_t npcm7xx_timer_read(void *opaque, hwaddr offset, unsigned size)
492
break;
493
494
case NPCM7XX_TIMER_WTCR:
495
- value = s->wtcr;
496
+ value = s->watchdog_timer.wtcr;
497
break;
498
499
default:
500
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_write(void *opaque, hwaddr offset,
501
return;
502
503
case NPCM7XX_TIMER_WTCR:
504
- qemu_log_mask(LOG_UNIMP, "%s: WTCR write not implemented: 0x%08x\n",
505
- __func__, value);
506
+ npcm7xx_timer_write_wtcr(&s->watchdog_timer, value);
507
return;
508
}
509
510
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_enter_reset(Object *obj, ResetType type)
511
for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) {
512
NPCM7xxTimer *t = &s->timer[i];
513
514
- timer_del(&t->qtimer);
515
- t->expires_ns = 0;
516
- t->remaining_ns = 0;
517
+ npcm7xx_timer_clear(&t->base_timer);
518
t->tcsr = 0x00000005;
519
t->ticr = 0x00000000;
520
}
521
522
s->tisr = 0x00000000;
523
- s->wtcr = 0x00000400;
524
+ /*
525
+ * Set WTCLK to 1(default) and reset all flags except WTRF.
526
+ * WTRF is not reset during a core domain reset.
527
+ */
528
+ s->watchdog_timer.wtcr = 0x00000400 | (s->watchdog_timer.wtcr &
529
+ NPCM7XX_WTCR_WTRF);
530
+}
531
+
532
+static void npcm7xx_watchdog_timer_expired(void *opaque)
533
+{
534
+ NPCM7xxWatchdogTimer *t = opaque;
535
+
536
+ if (t->wtcr & NPCM7XX_WTCR_WTE) {
537
+ if (t->wtcr & NPCM7XX_WTCR_WTIF) {
538
+ if (t->wtcr & NPCM7XX_WTCR_WTRE) {
539
+ t->wtcr |= NPCM7XX_WTCR_WTRF;
540
+ /* send reset signal to CLK module*/
541
+ qemu_irq_raise(t->reset_signal);
542
+ }
543
+ } else {
544
+ t->wtcr |= NPCM7XX_WTCR_WTIF;
545
+ if (t->wtcr & NPCM7XX_WTCR_WTIE) {
546
+ /* send interrupt */
547
+ qemu_irq_raise(t->irq);
548
+ }
549
+ npcm7xx_watchdog_timer_reset_cycles(t,
550
+ NPCM7XX_WATCHDOG_INTERRUPT_TO_RESET_CYCLES);
551
+ npcm7xx_timer_start(&t->base_timer);
552
+ }
553
+ }
554
}
555
556
static void npcm7xx_timer_hold_reset(Object *obj)
557
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_hold_reset(Object *obj)
558
for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) {
559
qemu_irq_lower(s->timer[i].irq);
560
}
561
+ qemu_irq_lower(s->watchdog_timer.irq);
562
}
563
564
static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
565
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
566
NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(dev);
567
SysBusDevice *sbd = &s->parent;
568
int i;
569
+ NPCM7xxWatchdogTimer *w;
570
571
for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) {
572
NPCM7xxTimer *t = &s->timer[i];
573
t->ctrl = s;
574
- timer_init_ns(&t->qtimer, QEMU_CLOCK_VIRTUAL, npcm7xx_timer_expired, t);
575
+ timer_init_ns(&t->base_timer.qtimer, QEMU_CLOCK_VIRTUAL,
576
+ npcm7xx_timer_expired, t);
577
sysbus_init_irq(sbd, &t->irq);
578
}
579
580
+ w = &s->watchdog_timer;
581
+ w->ctrl = s;
582
+ timer_init_ns(&w->base_timer.qtimer, QEMU_CLOCK_VIRTUAL,
583
+ npcm7xx_watchdog_timer_expired, w);
584
+ sysbus_init_irq(sbd, &w->irq);
585
+
586
memory_region_init_io(&s->iomem, OBJECT(s), &npcm7xx_timer_ops, s,
587
TYPE_NPCM7XX_TIMER, 4 * KiB);
588
sysbus_init_mmio(sbd, &s->iomem);
589
+ qdev_init_gpio_out_named(dev, &w->reset_signal,
590
+ NPCM7XX_WATCHDOG_RESET_GPIO_OUT, 1);
591
}
592
593
-static const VMStateDescription vmstate_npcm7xx_timer = {
594
- .name = "npcm7xx-timer",
595
+static const VMStateDescription vmstate_npcm7xx_base_timer = {
596
+ .name = "npcm7xx-base-timer",
597
.version_id = 0,
598
.minimum_version_id = 0,
599
.fields = (VMStateField[]) {
600
- VMSTATE_TIMER(qtimer, NPCM7xxTimer),
601
- VMSTATE_INT64(expires_ns, NPCM7xxTimer),
602
- VMSTATE_INT64(remaining_ns, NPCM7xxTimer),
603
+ VMSTATE_TIMER(qtimer, NPCM7xxBaseTimer),
604
+ VMSTATE_INT64(expires_ns, NPCM7xxBaseTimer),
605
+ VMSTATE_INT64(remaining_ns, NPCM7xxBaseTimer),
606
+ VMSTATE_END_OF_LIST(),
607
+ },
608
+};
609
+
610
+static const VMStateDescription vmstate_npcm7xx_timer = {
611
+ .name = "npcm7xx-timer",
612
+ .version_id = 1,
613
+ .minimum_version_id = 1,
614
+ .fields = (VMStateField[]) {
615
+ VMSTATE_STRUCT(base_timer, NPCM7xxTimer,
616
+ 0, vmstate_npcm7xx_base_timer,
617
+ NPCM7xxBaseTimer),
618
VMSTATE_UINT32(tcsr, NPCM7xxTimer),
619
VMSTATE_UINT32(ticr, NPCM7xxTimer),
620
VMSTATE_END_OF_LIST(),
621
},
622
};
623
624
-static const VMStateDescription vmstate_npcm7xx_timer_ctrl = {
625
- .name = "npcm7xx-timer-ctrl",
626
+static const VMStateDescription vmstate_npcm7xx_watchdog_timer = {
627
+ .name = "npcm7xx-watchdog-timer",
628
.version_id = 0,
629
.minimum_version_id = 0,
630
+ .fields = (VMStateField[]) {
631
+ VMSTATE_STRUCT(base_timer, NPCM7xxWatchdogTimer,
632
+ 0, vmstate_npcm7xx_base_timer,
633
+ NPCM7xxBaseTimer),
634
+ VMSTATE_UINT32(wtcr, NPCM7xxWatchdogTimer),
635
+ VMSTATE_END_OF_LIST(),
636
+ },
637
+};
638
+
639
+static const VMStateDescription vmstate_npcm7xx_timer_ctrl = {
640
+ .name = "npcm7xx-timer-ctrl",
641
+ .version_id = 1,
642
+ .minimum_version_id = 1,
643
.fields = (VMStateField[]) {
644
VMSTATE_UINT32(tisr, NPCM7xxTimerCtrlState),
645
- VMSTATE_UINT32(wtcr, NPCM7xxTimerCtrlState),
646
VMSTATE_STRUCT_ARRAY(timer, NPCM7xxTimerCtrlState,
647
NPCM7XX_TIMERS_PER_CTRL, 0, vmstate_npcm7xx_timer,
648
NPCM7xxTimer),
649
+ VMSTATE_STRUCT(watchdog_timer, NPCM7xxTimerCtrlState,
650
+ 0, vmstate_npcm7xx_watchdog_timer,
651
+ NPCM7xxWatchdogTimer),
652
VMSTATE_END_OF_LIST(),
653
},
654
};
655
diff --git a/tests/qtest/npcm7xx_watchdog_timer-test.c b/tests/qtest/npcm7xx_watchdog_timer-test.c
656
new file mode 100644
657
index XXXXXXX..XXXXXXX
658
--- /dev/null
659
+++ b/tests/qtest/npcm7xx_watchdog_timer-test.c
660
@@ -XXX,XX +XXX,XX @@
661
+/*
662
+ * QTests for Nuvoton NPCM7xx Timer Watchdog Modules.
663
+ *
664
+ * Copyright 2020 Google LLC
665
+ *
666
+ * This program is free software; you can redistribute it and/or modify it
667
+ * under the terms of the GNU General Public License as published by the
668
+ * Free Software Foundation; either version 2 of the License, or
669
+ * (at your option) any later version.
670
+ *
671
+ * This program is distributed in the hope that it will be useful, but WITHOUT
672
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
673
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
674
+ * for more details.
675
+ */
676
+
677
+#include "qemu/osdep.h"
678
+#include "qemu/timer.h"
679
+
680
+#include "libqos/libqtest.h"
681
+#include "qapi/qmp/qdict.h"
682
+
683
+#define WTCR_OFFSET 0x1c
684
+#define REF_HZ (25000000)
685
+
686
+/* WTCR bit fields */
687
+#define WTCLK(rv) ((rv) << 10)
688
+#define WTE BIT(7)
689
+#define WTIE BIT(6)
690
+#define WTIS(rv) ((rv) << 4)
691
+#define WTIF BIT(3)
692
+#define WTRF BIT(2)
693
+#define WTRE BIT(1)
694
+#define WTR BIT(0)
695
+
696
+typedef struct Watchdog {
697
+ int irq;
698
+ uint64_t base_addr;
699
+} Watchdog;
700
+
701
+static const Watchdog watchdog_list[] = {
702
+ {
703
+ .irq = 47,
704
+ .base_addr = 0xf0008000
705
+ },
706
+ {
707
+ .irq = 48,
708
+ .base_addr = 0xf0009000
709
+ },
710
+ {
711
+ .irq = 49,
712
+ .base_addr = 0xf000a000
713
+ }
714
+};
715
+
716
+static int watchdog_index(const Watchdog *wd)
717
+{
718
+ ptrdiff_t diff = wd - watchdog_list;
719
+
720
+ g_assert(diff >= 0 && diff < ARRAY_SIZE(watchdog_list));
721
+
722
+ return diff;
723
+}
724
+
725
+static uint32_t watchdog_read_wtcr(QTestState *qts, const Watchdog *wd)
726
+{
727
+ return qtest_readl(qts, wd->base_addr + WTCR_OFFSET);
728
+}
729
+
730
+static void watchdog_write_wtcr(QTestState *qts, const Watchdog *wd,
731
+ uint32_t value)
732
+{
733
+ qtest_writel(qts, wd->base_addr + WTCR_OFFSET, value);
734
+}
735
+
736
+static uint32_t watchdog_prescaler(QTestState *qts, const Watchdog *wd)
737
+{
738
+ switch (extract32(watchdog_read_wtcr(qts, wd), 10, 2)) {
739
+ case 0:
740
+ return 1;
741
+ case 1:
742
+ return 256;
743
+ case 2:
744
+ return 2048;
745
+ case 3:
746
+ return 65536;
747
+ default:
748
+ g_assert_not_reached();
749
+ }
750
+}
751
+
752
+static QDict *get_watchdog_action(QTestState *qts)
753
+{
754
+ QDict *ev = qtest_qmp_eventwait_ref(qts, "WATCHDOG");
755
+ QDict *data;
756
+
757
+ data = qdict_get_qdict(ev, "data");
758
+ qobject_ref(data);
759
+ qobject_unref(ev);
760
+ return data;
761
+}
762
+
763
+#define RESET_CYCLES 1024
764
+static uint32_t watchdog_interrupt_cycles(QTestState *qts, const Watchdog *wd)
765
+{
766
+ uint32_t wtis = extract32(watchdog_read_wtcr(qts, wd), 4, 2);
767
+ return 1 << (14 + 2 * wtis);
768
+}
769
+
770
+static int64_t watchdog_calculate_steps(uint32_t count, uint32_t prescale)
771
+{
772
+ return (NANOSECONDS_PER_SECOND / REF_HZ) * count * prescale;
773
+}
774
+
775
+static int64_t watchdog_interrupt_steps(QTestState *qts, const Watchdog *wd)
776
+{
777
+ return watchdog_calculate_steps(watchdog_interrupt_cycles(qts, wd),
778
+ watchdog_prescaler(qts, wd));
779
+}
780
+
781
+/* Check wtcr can be reset to default value */
782
+static void test_init(gconstpointer watchdog)
783
+{
784
+ const Watchdog *wd = watchdog;
785
+ QTestState *qts = qtest_init("-machine quanta-gsj");
786
+
787
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
788
+
789
+ watchdog_write_wtcr(qts, wd, WTCLK(1) | WTRF | WTIF | WTR);
790
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(1));
791
+
792
+ qtest_quit(qts);
793
+}
794
+
795
+/* Check a watchdog can generate interrupt and reset actions */
796
+static void test_reset_action(gconstpointer watchdog)
797
+{
798
+ const Watchdog *wd = watchdog;
799
+ QTestState *qts = qtest_init("-machine quanta-gsj");
800
+ QDict *ad;
801
+
802
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
803
+
804
+ watchdog_write_wtcr(qts, wd,
805
+ WTCLK(0) | WTE | WTRF | WTRE | WTIF | WTIE | WTR);
806
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==,
807
+ WTCLK(0) | WTE | WTRE | WTIE);
808
+
809
+ /* Check a watchdog can generate an interrupt */
810
+ qtest_clock_step(qts, watchdog_interrupt_steps(qts, wd));
811
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==,
812
+ WTCLK(0) | WTE | WTIF | WTIE | WTRE);
813
+ g_assert_true(qtest_get_irq(qts, wd->irq));
814
+
815
+ /* Check a watchdog can generate a reset signal */
816
+ qtest_clock_step(qts, watchdog_calculate_steps(RESET_CYCLES,
817
+ watchdog_prescaler(qts, wd)));
818
+ ad = get_watchdog_action(qts);
819
+ /* The signal is a reset signal */
820
+ g_assert_false(strcmp(qdict_get_str(ad, "action"), "reset"));
821
+ qobject_unref(ad);
822
+ qtest_qmp_eventwait(qts, "RESET");
823
+ /*
824
+ * Make sure WTCR is reset to default except for WTRF bit which shouldn't
825
+ * be reset.
826
+ */
827
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(1) | WTRF);
828
+ qtest_quit(qts);
829
+}
830
+
831
+/* Check a watchdog works with all possible WTCLK prescalers and WTIS cycles */
832
+static void test_prescaler(gconstpointer watchdog)
833
+{
834
+ const Watchdog *wd = watchdog;
835
+
836
+ for (int wtclk = 0; wtclk < 4; ++wtclk) {
837
+ for (int wtis = 0; wtis < 4; ++wtis) {
838
+ QTestState *qts = qtest_init("-machine quanta-gsj");
839
+
840
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
841
+ watchdog_write_wtcr(qts, wd,
842
+ WTCLK(wtclk) | WTE | WTIF | WTIS(wtis) | WTIE | WTR);
843
+ /*
844
+ * The interrupt doesn't fire until watchdog_interrupt_steps()
845
+ * cycles passed
846
+ */
847
+ qtest_clock_step(qts, watchdog_interrupt_steps(qts, wd) - 1);
848
+ g_assert_false(watchdog_read_wtcr(qts, wd) & WTIF);
849
+ g_assert_false(qtest_get_irq(qts, wd->irq));
850
+ qtest_clock_step(qts, 1);
851
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
852
+ g_assert_true(qtest_get_irq(qts, wd->irq));
853
+
854
+ qtest_quit(qts);
855
+ }
856
+ }
857
+}
858
+
859
+/*
860
+ * Check a watchdog doesn't fire if corresponding flags (WTIE and WTRE) are not
861
+ * set.
862
+ */
863
+static void test_enabling_flags(gconstpointer watchdog)
864
+{
865
+ const Watchdog *wd = watchdog;
866
+ QTestState *qts;
867
+
868
+ /* Neither WTIE or WTRE is set, no interrupt or reset should happen */
869
+ qts = qtest_init("-machine quanta-gsj");
870
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
871
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTE | WTIF | WTRF | WTR);
872
+ qtest_clock_step(qts, watchdog_interrupt_steps(qts, wd));
873
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
874
+ g_assert_false(qtest_get_irq(qts, wd->irq));
875
+ qtest_clock_step(qts, watchdog_calculate_steps(RESET_CYCLES,
876
+ watchdog_prescaler(qts, wd)));
877
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
878
+ g_assert_false(watchdog_read_wtcr(qts, wd) & WTRF);
879
+ qtest_quit(qts);
880
+
881
+ /* Only WTIE is set, interrupt is triggered but reset should not happen */
882
+ qts = qtest_init("-machine quanta-gsj");
883
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
884
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTE | WTIF | WTIE | WTRF | WTR);
885
+ qtest_clock_step(qts, watchdog_interrupt_steps(qts, wd));
886
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
887
+ g_assert_true(qtest_get_irq(qts, wd->irq));
888
+ qtest_clock_step(qts, watchdog_calculate_steps(RESET_CYCLES,
889
+ watchdog_prescaler(qts, wd)));
890
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
891
+ g_assert_false(watchdog_read_wtcr(qts, wd) & WTRF);
892
+ qtest_quit(qts);
893
+
894
+ /* Only WTRE is set, interrupt is triggered but reset should not happen */
895
+ qts = qtest_init("-machine quanta-gsj");
896
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
897
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTE | WTIF | WTRE | WTRF | WTR);
898
+ qtest_clock_step(qts, watchdog_interrupt_steps(qts, wd));
899
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
900
+ g_assert_false(qtest_get_irq(qts, wd->irq));
901
+ qtest_clock_step(qts, watchdog_calculate_steps(RESET_CYCLES,
902
+ watchdog_prescaler(qts, wd)));
903
+ g_assert_false(strcmp(qdict_get_str(get_watchdog_action(qts), "action"),
904
+ "reset"));
905
+ qtest_qmp_eventwait(qts, "RESET");
906
+ qtest_quit(qts);
907
+
908
+ /*
909
+ * The case when both flags are set is already tested in
910
+ * test_reset_action().
911
+ */
912
+}
913
+
914
+/* Check a watchdog can pause and resume by setting WTE bits */
915
+static void test_pause(gconstpointer watchdog)
916
+{
917
+ const Watchdog *wd = watchdog;
918
+ QTestState *qts;
919
+ int64_t remaining_steps, steps;
920
+
921
+ qts = qtest_init("-machine quanta-gsj");
922
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
923
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTE | WTIF | WTIE | WTRF | WTR);
924
+ remaining_steps = watchdog_interrupt_steps(qts, wd);
925
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(0) | WTE | WTIE);
926
+
927
+ /* Run for half of the execution period. */
928
+ steps = remaining_steps / 2;
929
+ remaining_steps -= steps;
930
+ qtest_clock_step(qts, steps);
931
+
932
+ /* Pause the watchdog */
933
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTIE);
934
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(0) | WTIE);
935
+
936
+ /* Run for a long period of time, the watchdog shouldn't fire */
937
+ qtest_clock_step(qts, steps << 4);
938
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(0) | WTIE);
939
+ g_assert_false(qtest_get_irq(qts, wd->irq));
940
+
941
+ /* Resume the watchdog */
942
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTE | WTIE);
943
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(0) | WTE | WTIE);
944
+
945
+ /* Run for the reset of the execution period, the watchdog should fire */
946
+ qtest_clock_step(qts, remaining_steps);
947
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==,
948
+ WTCLK(0) | WTE | WTIF | WTIE);
949
+ g_assert_true(qtest_get_irq(qts, wd->irq));
950
+
951
+ qtest_quit(qts);
952
+}
953
+
954
+static void watchdog_add_test(const char *name, const Watchdog* wd,
955
+ GTestDataFunc fn)
956
+{
957
+ g_autofree char *full_name = g_strdup_printf(
958
+ "npcm7xx_watchdog_timer[%d]/%s", watchdog_index(wd), name);
959
+ qtest_add_data_func(full_name, wd, fn);
960
+}
961
+#define add_test(name, td) watchdog_add_test(#name, td, test_##name)
962
+
963
+int main(int argc, char **argv)
964
+{
965
+ g_test_init(&argc, &argv, NULL);
966
+ g_test_set_nonfatal_assertions();
967
+
968
+ for (int i = 0; i < ARRAY_SIZE(watchdog_list); ++i) {
969
+ const Watchdog *wd = &watchdog_list[i];
970
+
971
+ add_test(init, wd);
972
+ add_test(reset_action, wd);
973
+ add_test(prescaler, wd);
974
+ add_test(enabling_flags, wd);
975
+ add_test(pause, wd);
976
+ }
977
+
978
+ return g_test_run();
979
+}
980
diff --git a/MAINTAINERS b/MAINTAINERS
981
index XXXXXXX..XXXXXXX 100644
982
--- a/MAINTAINERS
983
+++ b/MAINTAINERS
984
@@ -XXX,XX +XXX,XX @@ L: qemu-arm@nongnu.org
985
S: Supported
986
F: hw/*/npcm7xx*
987
F: include/hw/*/npcm7xx*
988
+F: tests/qtest/npcm7xx*
989
F: pc-bios/npcm7xx_bootrom.bin
990
F: roms/vbootrom
991
992
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
993
index XXXXXXX..XXXXXXX 100644
994
--- a/tests/qtest/meson.build
995
+++ b/tests/qtest/meson.build
996
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
997
(config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) + \
998
['prom-env-test', 'boot-serial-test']
999
1000
-qtests_npcm7xx = ['npcm7xx_timer-test']
1001
+qtests_npcm7xx = ['npcm7xx_timer-test', 'npcm7xx_watchdog_timer-test']
1002
qtests_arm = \
1003
(config_all_devices.has_key('CONFIG_PFLASH_CFI02') ? ['pflash-cfi02-test'] : []) + \
1004
(config_all_devices.has_key('CONFIG_NPCM7XX') ? qtests_npcm7xx : []) + \
146
--
1005
--
147
2.20.1
1006
2.20.1
148
1007
149
1008
diff view generated by jsdifflib
1
From: Eddie James <eajames@linux.ibm.com>
1
From: Havard Skinnemoen <hskinnemoen@google.com>
2
2
3
The XDMA engine embedded in the Aspeed SOCs performs PCI DMA operations
3
The RNG module returns a byte of randomness when the Data Valid bit is
4
between the SOC (acting as a BMC) and a host processor in a server.
4
set.
5
5
6
The XDMA engine exists on the AST2400, AST2500, and AST2600 SOCs, so
6
This implementation ignores the prescaler setting, and loads a new value
7
enable it for all of those. Add trace events on the important register
7
into RNGD every time RNGCS is read while the RNG is enabled and random
8
writes in the XDMA engine.
8
data is available.
9
9
10
Signed-off-by: Eddie James <eajames@linux.ibm.com>
10
A qtest featuring some simple randomness tests is included.
11
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
11
12
Signed-off-by: Cédric Le Goater <clg@kaod.org>
12
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
13
Message-id: 20190618165311.27066-21-clg@kaod.org
13
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
14
[clg: - changed title ]
14
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
15
Signed-off-by: Cédric Le Goater <clg@kaod.org>
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
---
16
---
18
hw/misc/Makefile.objs | 1 +
17
docs/system/arm/nuvoton.rst | 2 +-
19
include/hw/arm/aspeed_soc.h | 3 +
18
include/hw/arm/npcm7xx.h | 2 +
20
include/hw/misc/aspeed_xdma.h | 30 +++++++
19
include/hw/misc/npcm7xx_rng.h | 34 ++++
21
hw/arm/aspeed_soc.c | 17 ++++
20
hw/arm/npcm7xx.c | 7 +-
22
hw/misc/aspeed_xdma.c | 165 ++++++++++++++++++++++++++++++++++
21
hw/misc/npcm7xx_rng.c | 180 +++++++++++++++++++++
23
hw/misc/trace-events | 3 +
22
tests/qtest/npcm7xx_rng-test.c | 278 +++++++++++++++++++++++++++++++++
24
6 files changed, 219 insertions(+)
23
hw/misc/meson.build | 1 +
25
create mode 100644 include/hw/misc/aspeed_xdma.h
24
hw/misc/trace-events | 4 +
26
create mode 100644 hw/misc/aspeed_xdma.c
25
tests/qtest/meson.build | 5 +-
26
9 files changed, 510 insertions(+), 3 deletions(-)
27
create mode 100644 include/hw/misc/npcm7xx_rng.h
28
create mode 100644 hw/misc/npcm7xx_rng.c
29
create mode 100644 tests/qtest/npcm7xx_rng-test.c
27
30
28
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
31
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
29
index XXXXXXX..XXXXXXX 100644
32
index XXXXXXX..XXXXXXX 100644
30
--- a/hw/misc/Makefile.objs
33
--- a/docs/system/arm/nuvoton.rst
31
+++ b/hw/misc/Makefile.objs
34
+++ b/docs/system/arm/nuvoton.rst
32
@@ -XXX,XX +XXX,XX @@ obj-$(CONFIG_ARMSSE_MHU) += armsse-mhu.o
35
@@ -XXX,XX +XXX,XX @@ Supported devices
33
36
* DDR4 memory controller (dummy interface indicating memory training is done)
34
obj-$(CONFIG_PVPANIC) += pvpanic.o
37
* OTP controllers (no protection features)
35
obj-$(CONFIG_AUX) += auxbus.o
38
* Flash Interface Unit (FIU; no protection features)
36
+obj-$(CONFIG_ASPEED_SOC) += aspeed_xdma.o
39
+ * Random Number Generator (RNG)
37
obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o aspeed_sdmc.o
40
38
obj-$(CONFIG_MSF2) += msf2-sysreg.o
41
Missing devices
39
obj-$(CONFIG_NRF51_SOC) += nrf51_rng.o
42
---------------
40
diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h
43
@@ -XXX,XX +XXX,XX @@ Missing devices
44
* Peripheral SPI controller (PSPI)
45
* Analog to Digital Converter (ADC)
46
* SD/MMC host
47
- * Random Number Generator (RNG)
48
* PECI interface
49
* Pulse Width Modulation (PWM)
50
* Tachometer
51
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
41
index XXXXXXX..XXXXXXX 100644
52
index XXXXXXX..XXXXXXX 100644
42
--- a/include/hw/arm/aspeed_soc.h
53
--- a/include/hw/arm/npcm7xx.h
43
+++ b/include/hw/arm/aspeed_soc.h
54
+++ b/include/hw/arm/npcm7xx.h
44
@@ -XXX,XX +XXX,XX @@
55
@@ -XXX,XX +XXX,XX @@
45
#include "hw/intc/aspeed_vic.h"
56
#include "hw/mem/npcm7xx_mc.h"
46
#include "hw/misc/aspeed_scu.h"
57
#include "hw/misc/npcm7xx_clk.h"
47
#include "hw/misc/aspeed_sdmc.h"
58
#include "hw/misc/npcm7xx_gcr.h"
48
+#include "hw/misc/aspeed_xdma.h"
59
+#include "hw/misc/npcm7xx_rng.h"
49
#include "hw/timer/aspeed_timer.h"
60
#include "hw/nvram/npcm7xx_otp.h"
50
#include "hw/timer/aspeed_rtc.h"
61
#include "hw/timer/npcm7xx_timer.h"
51
#include "hw/i2c/aspeed_i2c.h"
62
#include "hw/ssi/npcm7xx_fiu.h"
52
@@ -XXX,XX +XXX,XX @@ typedef struct AspeedSoCState {
63
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
53
AspeedTimerCtrlState timerctrl;
64
NPCM7xxOTPState key_storage;
54
AspeedI2CState i2c;
65
NPCM7xxOTPState fuse_array;
55
AspeedSCUState scu;
66
NPCM7xxMCState mc;
56
+ AspeedXDMAState xdma;
67
+ NPCM7xxRNGState rng;
57
AspeedSMCState fmc;
68
NPCM7xxFIUState fiu[2];
58
AspeedSMCState spi[ASPEED_SPIS_NUM];
69
} NPCM7xxState;
59
AspeedSDMCState sdmc;
70
60
@@ -XXX,XX +XXX,XX @@ enum {
71
diff --git a/include/hw/misc/npcm7xx_rng.h b/include/hw/misc/npcm7xx_rng.h
61
ASPEED_ETH1,
62
ASPEED_ETH2,
63
ASPEED_SDRAM,
64
+ ASPEED_XDMA,
65
};
66
67
#endif /* ASPEED_SOC_H */
68
diff --git a/include/hw/misc/aspeed_xdma.h b/include/hw/misc/aspeed_xdma.h
69
new file mode 100644
72
new file mode 100644
70
index XXXXXXX..XXXXXXX
73
index XXXXXXX..XXXXXXX
71
--- /dev/null
74
--- /dev/null
72
+++ b/include/hw/misc/aspeed_xdma.h
75
+++ b/include/hw/misc/npcm7xx_rng.h
73
@@ -XXX,XX +XXX,XX @@
76
@@ -XXX,XX +XXX,XX @@
74
+/*
77
+/*
75
+ * ASPEED XDMA Controller
78
+ * Nuvoton NPCM7xx Random Number Generator.
76
+ * Eddie James <eajames@linux.ibm.com>
79
+ *
77
+ *
80
+ * Copyright 2020 Google LLC
78
+ * Copyright (C) 2019 IBM Corp.
81
+ *
79
+ * SPDX-License-Identifer: GPL-2.0-or-later
82
+ * This program is free software; you can redistribute it and/or modify it
80
+ */
83
+ * under the terms of the GNU General Public License as published by the
81
+
84
+ * Free Software Foundation; either version 2 of the License, or
82
+#ifndef ASPEED_XDMA_H
85
+ * (at your option) any later version.
83
+#define ASPEED_XDMA_H
86
+ *
87
+ * This program is distributed in the hope that it will be useful, but WITHOUT
88
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
89
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
90
+ * for more details.
91
+ */
92
+#ifndef NPCM7XX_RNG_H
93
+#define NPCM7XX_RNG_H
84
+
94
+
85
+#include "hw/sysbus.h"
95
+#include "hw/sysbus.h"
86
+
96
+
87
+#define TYPE_ASPEED_XDMA "aspeed.xdma"
97
+typedef struct NPCM7xxRNGState {
88
+#define ASPEED_XDMA(obj) OBJECT_CHECK(AspeedXDMAState, (obj), TYPE_ASPEED_XDMA)
89
+
90
+#define ASPEED_XDMA_NUM_REGS (ASPEED_XDMA_REG_SIZE / sizeof(uint32_t))
91
+#define ASPEED_XDMA_REG_SIZE 0x7C
92
+
93
+typedef struct AspeedXDMAState {
94
+ SysBusDevice parent;
98
+ SysBusDevice parent;
95
+
99
+
96
+ MemoryRegion iomem;
100
+ MemoryRegion iomem;
97
+ qemu_irq irq;
101
+
98
+
102
+ uint8_t rngcs;
99
+ char bmc_cmdq_readp_set;
103
+ uint8_t rngd;
100
+ uint32_t regs[ASPEED_XDMA_NUM_REGS];
104
+ uint8_t rngmode;
101
+} AspeedXDMAState;
105
+} NPCM7xxRNGState;
102
+
106
+
103
+#endif /* ASPEED_XDMA_H */
107
+#define TYPE_NPCM7XX_RNG "npcm7xx-rng"
104
diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c
108
+#define NPCM7XX_RNG(obj) OBJECT_CHECK(NPCM7xxRNGState, (obj), TYPE_NPCM7XX_RNG)
109
+
110
+#endif /* NPCM7XX_RNG_H */
111
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
105
index XXXXXXX..XXXXXXX 100644
112
index XXXXXXX..XXXXXXX 100644
106
--- a/hw/arm/aspeed_soc.c
113
--- a/hw/arm/npcm7xx.c
107
+++ b/hw/arm/aspeed_soc.c
114
+++ b/hw/arm/npcm7xx.c
108
@@ -XXX,XX +XXX,XX @@ static const hwaddr aspeed_soc_ast2400_memmap[] = {
115
@@ -XXX,XX +XXX,XX @@
109
[ASPEED_VIC] = 0x1E6C0000,
116
#define NPCM7XX_GCR_BA (0xf0800000)
110
[ASPEED_SDMC] = 0x1E6E0000,
117
#define NPCM7XX_CLK_BA (0xf0801000)
111
[ASPEED_SCU] = 0x1E6E2000,
118
#define NPCM7XX_MC_BA (0xf0824000)
112
+ [ASPEED_XDMA] = 0x1E6E7000,
119
+#define NPCM7XX_RNG_BA (0xf000b000)
113
[ASPEED_ADC] = 0x1E6E9000,
120
114
[ASPEED_SRAM] = 0x1E720000,
121
/* Internal AHB SRAM */
115
[ASPEED_GPIO] = 0x1E780000,
122
#define NPCM7XX_RAM3_BA (0xc0008000)
116
@@ -XXX,XX +XXX,XX @@ static const hwaddr aspeed_soc_ast2500_memmap[] = {
123
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
117
[ASPEED_VIC] = 0x1E6C0000,
124
object_initialize_child(obj, "otp2", &s->fuse_array,
118
[ASPEED_SDMC] = 0x1E6E0000,
125
TYPE_NPCM7XX_FUSE_ARRAY);
119
[ASPEED_SCU] = 0x1E6E2000,
126
object_initialize_child(obj, "mc", &s->mc, TYPE_NPCM7XX_MC);
120
+ [ASPEED_XDMA] = 0x1E6E7000,
127
+ object_initialize_child(obj, "rng", &s->rng, TYPE_NPCM7XX_RNG);
121
[ASPEED_ADC] = 0x1E6E9000,
128
122
[ASPEED_SRAM] = 0x1E720000,
129
for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
123
[ASPEED_GPIO] = 0x1E780000,
130
object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
124
@@ -XXX,XX +XXX,XX @@ static const int aspeed_soc_ast2400_irqmap[] = {
131
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
125
[ASPEED_I2C] = 12,
132
serial_hd(i), DEVICE_LITTLE_ENDIAN);
126
[ASPEED_ETH1] = 2,
127
[ASPEED_ETH2] = 3,
128
+ [ASPEED_XDMA] = 6,
129
};
130
131
#define aspeed_soc_ast2500_irqmap aspeed_soc_ast2400_irqmap
132
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_init(Object *obj)
133
sysbus_init_child_obj(obj, "ftgmac100[*]", OBJECT(&s->ftgmac100[i]),
134
sizeof(s->ftgmac100[i]), TYPE_FTGMAC100);
135
}
133
}
136
+
134
137
+ sysbus_init_child_obj(obj, "xdma", OBJECT(&s->xdma), sizeof(s->xdma),
135
+ /* Random Number Generator. Cannot fail. */
138
+ TYPE_ASPEED_XDMA);
136
+ sysbus_realize(SYS_BUS_DEVICE(&s->rng), &error_abort);
139
}
137
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->rng), 0, NPCM7XX_RNG_BA);
140
138
+
141
static void aspeed_soc_realize(DeviceState *dev, Error **errp)
139
/*
142
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
140
* Flash Interface Unit (FIU). Can fail if incorrect number of chip selects
143
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
141
* specified, but this is a programming error.
144
aspeed_soc_get_irq(s, ASPEED_ETH1 + i));
142
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
145
}
143
create_unimplemented_device("npcm7xx.vdmx", 0xe0800000, 4 * KiB);
146
+
144
create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB);
147
+ /* XDMA */
145
create_unimplemented_device("npcm7xx.kcs", 0xf0007000, 4 * KiB);
148
+ object_property_set_bool(OBJECT(&s->xdma), true, "realized", &err);
146
- create_unimplemented_device("npcm7xx.rng", 0xf000b000, 4 * KiB);
149
+ if (err) {
147
create_unimplemented_device("npcm7xx.adc", 0xf000c000, 4 * KiB);
150
+ error_propagate(errp, err);
148
create_unimplemented_device("npcm7xx.gfxi", 0xf000e000, 4 * KiB);
151
+ return;
149
create_unimplemented_device("npcm7xx.gpio[0]", 0xf0010000, 4 * KiB);
152
+ }
150
diff --git a/hw/misc/npcm7xx_rng.c b/hw/misc/npcm7xx_rng.c
153
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->xdma), 0,
154
+ sc->info->memmap[ASPEED_XDMA]);
155
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->xdma), 0,
156
+ aspeed_soc_get_irq(s, ASPEED_XDMA));
157
}
158
static Property aspeed_soc_properties[] = {
159
DEFINE_PROP_UINT32("num-cpus", AspeedSoCState, num_cpus, 0),
160
diff --git a/hw/misc/aspeed_xdma.c b/hw/misc/aspeed_xdma.c
161
new file mode 100644
151
new file mode 100644
162
index XXXXXXX..XXXXXXX
152
index XXXXXXX..XXXXXXX
163
--- /dev/null
153
--- /dev/null
164
+++ b/hw/misc/aspeed_xdma.c
154
+++ b/hw/misc/npcm7xx_rng.c
165
@@ -XXX,XX +XXX,XX @@
155
@@ -XXX,XX +XXX,XX @@
166
+/*
156
+/*
167
+ * ASPEED XDMA Controller
157
+ * Nuvoton NPCM7xx Random Number Generator.
168
+ * Eddie James <eajames@linux.ibm.com>
158
+ *
169
+ *
159
+ * Copyright 2020 Google LLC
170
+ * Copyright (C) 2019 IBM Corp
160
+ *
171
+ * SPDX-License-Identifer: GPL-2.0-or-later
161
+ * This program is free software; you can redistribute it and/or modify it
162
+ * under the terms of the GNU General Public License as published by the
163
+ * Free Software Foundation; either version 2 of the License, or
164
+ * (at your option) any later version.
165
+ *
166
+ * This program is distributed in the hope that it will be useful, but WITHOUT
167
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
168
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
169
+ * for more details.
172
+ */
170
+ */
173
+
171
+
174
+#include "qemu/osdep.h"
172
+#include "qemu/osdep.h"
173
+
174
+#include "hw/misc/npcm7xx_rng.h"
175
+#include "migration/vmstate.h"
176
+#include "qemu/bitops.h"
177
+#include "qemu/guest-random.h"
175
+#include "qemu/log.h"
178
+#include "qemu/log.h"
176
+#include "qemu/error-report.h"
179
+#include "qemu/module.h"
177
+#include "hw/misc/aspeed_xdma.h"
180
+#include "qemu/units.h"
178
+#include "qapi/error.h"
179
+
181
+
180
+#include "trace.h"
182
+#include "trace.h"
181
+
183
+
182
+#define XDMA_BMC_CMDQ_ADDR 0x10
184
+#define NPCM7XX_RNG_REGS_SIZE (4 * KiB)
183
+#define XDMA_BMC_CMDQ_ENDP 0x14
185
+
184
+#define XDMA_BMC_CMDQ_WRP 0x18
186
+#define NPCM7XX_RNGCS (0x00)
185
+#define XDMA_BMC_CMDQ_W_MASK 0x0003FFFF
187
+#define NPCM7XX_RNGCS_CLKP(rv) extract32(rv, 2, 4)
186
+#define XDMA_BMC_CMDQ_RDP 0x1C
188
+#define NPCM7XX_RNGCS_DVALID BIT(1)
187
+#define XDMA_BMC_CMDQ_RDP_MAGIC 0xEE882266
189
+#define NPCM7XX_RNGCS_RNGE BIT(0)
188
+#define XDMA_IRQ_ENG_CTRL 0x20
190
+
189
+#define XDMA_IRQ_ENG_CTRL_US_COMP BIT(4)
191
+#define NPCM7XX_RNGD (0x04)
190
+#define XDMA_IRQ_ENG_CTRL_DS_COMP BIT(5)
192
+#define NPCM7XX_RNGMODE (0x08)
191
+#define XDMA_IRQ_ENG_CTRL_W_MASK 0xBFEFF07F
193
+#define NPCM7XX_RNGMODE_NORMAL (0x02)
192
+#define XDMA_IRQ_ENG_STAT 0x24
194
+
193
+#define XDMA_IRQ_ENG_STAT_US_COMP BIT(4)
195
+static bool npcm7xx_rng_is_enabled(NPCM7xxRNGState *s)
194
+#define XDMA_IRQ_ENG_STAT_DS_COMP BIT(5)
196
+{
195
+#define XDMA_IRQ_ENG_STAT_RESET 0xF8000000
197
+ return (s->rngcs & NPCM7XX_RNGCS_RNGE) &&
196
+#define XDMA_MEM_SIZE 0x1000
198
+ (s->rngmode == NPCM7XX_RNGMODE_NORMAL);
197
+
199
+}
198
+#define TO_REG(addr) ((addr) / sizeof(uint32_t))
200
+
199
+
201
+static uint64_t npcm7xx_rng_read(void *opaque, hwaddr offset, unsigned size)
200
+static uint64_t aspeed_xdma_read(void *opaque, hwaddr addr, unsigned int size)
202
+{
201
+{
203
+ NPCM7xxRNGState *s = opaque;
202
+ uint32_t val = 0;
204
+ uint64_t value = 0;
203
+ AspeedXDMAState *xdma = opaque;
205
+
204
+
206
+ switch (offset) {
205
+ if (addr < ASPEED_XDMA_REG_SIZE) {
207
+ case NPCM7XX_RNGCS:
206
+ val = xdma->regs[TO_REG(addr)];
208
+ /*
207
+ }
209
+ * If the RNG is enabled, but we don't have any valid random data, try
208
+
210
+ * obtaining some and update the DVALID bit accordingly.
209
+ return (uint64_t)val;
211
+ */
210
+}
212
+ if (!npcm7xx_rng_is_enabled(s)) {
211
+
213
+ s->rngcs &= ~NPCM7XX_RNGCS_DVALID;
212
+static void aspeed_xdma_write(void *opaque, hwaddr addr, uint64_t val,
214
+ } else if (!(s->rngcs & NPCM7XX_RNGCS_DVALID)) {
213
+ unsigned int size)
215
+ uint8_t byte = 0;
214
+{
216
+
215
+ unsigned int idx;
217
+ if (qemu_guest_getrandom(&byte, sizeof(byte), NULL) == 0) {
216
+ uint32_t val32 = (uint32_t)val;
218
+ s->rngd = byte;
217
+ AspeedXDMAState *xdma = opaque;
219
+ s->rngcs |= NPCM7XX_RNGCS_DVALID;
218
+
220
+ }
219
+ if (addr >= ASPEED_XDMA_REG_SIZE) {
220
+ return;
221
+ }
222
+
223
+ switch (addr) {
224
+ case XDMA_BMC_CMDQ_ENDP:
225
+ xdma->regs[TO_REG(addr)] = val32 & XDMA_BMC_CMDQ_W_MASK;
226
+ break;
227
+ case XDMA_BMC_CMDQ_WRP:
228
+ idx = TO_REG(addr);
229
+ xdma->regs[idx] = val32 & XDMA_BMC_CMDQ_W_MASK;
230
+ xdma->regs[TO_REG(XDMA_BMC_CMDQ_RDP)] = xdma->regs[idx];
231
+
232
+ trace_aspeed_xdma_write(addr, val);
233
+
234
+ if (xdma->bmc_cmdq_readp_set) {
235
+ xdma->bmc_cmdq_readp_set = 0;
236
+ } else {
237
+ xdma->regs[TO_REG(XDMA_IRQ_ENG_STAT)] |=
238
+ XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP;
239
+
240
+ if (xdma->regs[TO_REG(XDMA_IRQ_ENG_CTRL)] &
241
+ (XDMA_IRQ_ENG_CTRL_US_COMP | XDMA_IRQ_ENG_CTRL_DS_COMP))
242
+ qemu_irq_raise(xdma->irq);
243
+ }
221
+ }
244
+ break;
222
+ value = s->rngcs;
245
+ case XDMA_BMC_CMDQ_RDP:
223
+ break;
246
+ trace_aspeed_xdma_write(addr, val);
224
+ case NPCM7XX_RNGD:
247
+
225
+ if (npcm7xx_rng_is_enabled(s) && s->rngcs & NPCM7XX_RNGCS_DVALID) {
248
+ if (val32 == XDMA_BMC_CMDQ_RDP_MAGIC) {
226
+ s->rngcs &= ~NPCM7XX_RNGCS_DVALID;
249
+ xdma->bmc_cmdq_readp_set = 1;
227
+ value = s->rngd;
228
+ s->rngd = 0;
250
+ }
229
+ }
251
+ break;
230
+ break;
252
+ case XDMA_IRQ_ENG_CTRL:
231
+ case NPCM7XX_RNGMODE:
253
+ xdma->regs[TO_REG(addr)] = val32 & XDMA_IRQ_ENG_CTRL_W_MASK;
232
+ value = s->rngmode;
254
+ break;
233
+ break;
255
+ case XDMA_IRQ_ENG_STAT:
234
+
256
+ trace_aspeed_xdma_write(addr, val);
257
+
258
+ idx = TO_REG(addr);
259
+ if (val32 & (XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP)) {
260
+ xdma->regs[idx] &=
261
+ ~(XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP);
262
+ qemu_irq_lower(xdma->irq);
263
+ }
264
+ break;
265
+ default:
235
+ default:
266
+ xdma->regs[TO_REG(addr)] = val32;
236
+ qemu_log_mask(LOG_GUEST_ERROR,
267
+ break;
237
+ "%s: read from invalid offset 0x%" HWADDR_PRIx "\n",
268
+ }
238
+ DEVICE(s)->canonical_path, offset);
269
+}
239
+ break;
270
+
240
+ }
271
+static const MemoryRegionOps aspeed_xdma_ops = {
241
+
272
+ .read = aspeed_xdma_read,
242
+ trace_npcm7xx_rng_read(offset, value, size);
273
+ .write = aspeed_xdma_write,
243
+
274
+ .endianness = DEVICE_NATIVE_ENDIAN,
244
+ return value;
275
+ .valid.min_access_size = 4,
245
+}
276
+ .valid.max_access_size = 4,
246
+
247
+static void npcm7xx_rng_write(void *opaque, hwaddr offset, uint64_t value,
248
+ unsigned size)
249
+{
250
+ NPCM7xxRNGState *s = opaque;
251
+
252
+ trace_npcm7xx_rng_write(offset, value, size);
253
+
254
+ switch (offset) {
255
+ case NPCM7XX_RNGCS:
256
+ s->rngcs &= NPCM7XX_RNGCS_DVALID;
257
+ s->rngcs |= value & ~NPCM7XX_RNGCS_DVALID;
258
+ break;
259
+ case NPCM7XX_RNGD:
260
+ qemu_log_mask(LOG_GUEST_ERROR,
261
+ "%s: write to read-only register @ 0x%" HWADDR_PRIx "\n",
262
+ DEVICE(s)->canonical_path, offset);
263
+ break;
264
+ case NPCM7XX_RNGMODE:
265
+ s->rngmode = value;
266
+ break;
267
+ default:
268
+ qemu_log_mask(LOG_GUEST_ERROR,
269
+ "%s: write to invalid offset 0x%" HWADDR_PRIx "\n",
270
+ DEVICE(s)->canonical_path, offset);
271
+ break;
272
+ }
273
+}
274
+
275
+static const MemoryRegionOps npcm7xx_rng_ops = {
276
+ .read = npcm7xx_rng_read,
277
+ .write = npcm7xx_rng_write,
278
+ .endianness = DEVICE_LITTLE_ENDIAN,
279
+ .valid = {
280
+ .min_access_size = 1,
281
+ .max_access_size = 4,
282
+ .unaligned = false,
283
+ },
277
+};
284
+};
278
+
285
+
279
+static void aspeed_xdma_realize(DeviceState *dev, Error **errp)
286
+static void npcm7xx_rng_enter_reset(Object *obj, ResetType type)
280
+{
287
+{
281
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
288
+ NPCM7xxRNGState *s = NPCM7XX_RNG(obj);
282
+ AspeedXDMAState *xdma = ASPEED_XDMA(dev);
289
+
283
+
290
+ s->rngcs = 0;
284
+ sysbus_init_irq(sbd, &xdma->irq);
291
+ s->rngd = 0;
285
+ memory_region_init_io(&xdma->iomem, OBJECT(xdma), &aspeed_xdma_ops, xdma,
292
+ s->rngmode = 0;
286
+ TYPE_ASPEED_XDMA, XDMA_MEM_SIZE);
293
+}
287
+ sysbus_init_mmio(sbd, &xdma->iomem);
294
+
288
+}
295
+static void npcm7xx_rng_init(Object *obj)
289
+
296
+{
290
+static void aspeed_xdma_reset(DeviceState *dev)
297
+ NPCM7xxRNGState *s = NPCM7XX_RNG(obj);
291
+{
298
+
292
+ AspeedXDMAState *xdma = ASPEED_XDMA(dev);
299
+ memory_region_init_io(&s->iomem, obj, &npcm7xx_rng_ops, s, "regs",
293
+
300
+ NPCM7XX_RNG_REGS_SIZE);
294
+ xdma->bmc_cmdq_readp_set = 0;
301
+ sysbus_init_mmio(&s->parent, &s->iomem);
295
+ memset(xdma->regs, 0, ASPEED_XDMA_REG_SIZE);
302
+}
296
+ xdma->regs[TO_REG(XDMA_IRQ_ENG_STAT)] = XDMA_IRQ_ENG_STAT_RESET;
303
+
297
+
304
+static const VMStateDescription vmstate_npcm7xx_rng = {
298
+ qemu_irq_lower(xdma->irq);
305
+ .name = "npcm7xx-rng",
299
+}
306
+ .version_id = 0,
300
+
307
+ .minimum_version_id = 0,
301
+static const VMStateDescription aspeed_xdma_vmstate = {
302
+ .name = TYPE_ASPEED_XDMA,
303
+ .version_id = 1,
304
+ .fields = (VMStateField[]) {
308
+ .fields = (VMStateField[]) {
305
+ VMSTATE_UINT32_ARRAY(regs, AspeedXDMAState, ASPEED_XDMA_NUM_REGS),
309
+ VMSTATE_UINT8(rngcs, NPCM7xxRNGState),
310
+ VMSTATE_UINT8(rngd, NPCM7xxRNGState),
311
+ VMSTATE_UINT8(rngmode, NPCM7xxRNGState),
306
+ VMSTATE_END_OF_LIST(),
312
+ VMSTATE_END_OF_LIST(),
307
+ },
313
+ },
308
+};
314
+};
309
+
315
+
310
+static void aspeed_xdma_class_init(ObjectClass *classp, void *data)
316
+static void npcm7xx_rng_class_init(ObjectClass *klass, void *data)
311
+{
317
+{
312
+ DeviceClass *dc = DEVICE_CLASS(classp);
318
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
313
+
319
+ DeviceClass *dc = DEVICE_CLASS(klass);
314
+ dc->realize = aspeed_xdma_realize;
320
+
315
+ dc->reset = aspeed_xdma_reset;
321
+ dc->desc = "NPCM7xx Random Number Generator";
316
+ dc->vmsd = &aspeed_xdma_vmstate;
322
+ dc->vmsd = &vmstate_npcm7xx_rng;
317
+}
323
+ rc->phases.enter = npcm7xx_rng_enter_reset;
318
+
324
+}
319
+static const TypeInfo aspeed_xdma_info = {
325
+
320
+ .name = TYPE_ASPEED_XDMA,
326
+static const TypeInfo npcm7xx_rng_types[] = {
321
+ .parent = TYPE_SYS_BUS_DEVICE,
327
+ {
322
+ .instance_size = sizeof(AspeedXDMAState),
328
+ .name = TYPE_NPCM7XX_RNG,
323
+ .class_init = aspeed_xdma_class_init,
329
+ .parent = TYPE_SYS_BUS_DEVICE,
330
+ .instance_size = sizeof(NPCM7xxRNGState),
331
+ .class_init = npcm7xx_rng_class_init,
332
+ .instance_init = npcm7xx_rng_init,
333
+ },
324
+};
334
+};
325
+
335
+DEFINE_TYPES(npcm7xx_rng_types);
326
+static void aspeed_xdma_register_type(void)
336
diff --git a/tests/qtest/npcm7xx_rng-test.c b/tests/qtest/npcm7xx_rng-test.c
327
+{
337
new file mode 100644
328
+ type_register_static(&aspeed_xdma_info);
338
index XXXXXXX..XXXXXXX
329
+}
339
--- /dev/null
330
+type_init(aspeed_xdma_register_type);
340
+++ b/tests/qtest/npcm7xx_rng-test.c
341
@@ -XXX,XX +XXX,XX @@
342
+/*
343
+ * QTest testcase for the Nuvoton NPCM7xx Random Number Generator
344
+ *
345
+ * Copyright 2020 Google LLC
346
+ *
347
+ * This program is free software; you can redistribute it and/or modify it
348
+ * under the terms of the GNU General Public License as published by the
349
+ * Free Software Foundation; either version 2 of the License, or
350
+ * (at your option) any later version.
351
+ *
352
+ * This program is distributed in the hope that it will be useful, but WITHOUT
353
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
354
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
355
+ * for more details.
356
+ */
357
+
358
+#include "qemu/osdep.h"
359
+
360
+#include <math.h>
361
+
362
+#include "libqtest-single.h"
363
+#include "qemu/bitops.h"
364
+
365
+#define RNG_BASE_ADDR 0xf000b000
366
+
367
+/* Control and Status Register */
368
+#define RNGCS 0x00
369
+# define DVALID BIT(1) /* Data Valid */
370
+# define RNGE BIT(0) /* RNG Enable */
371
+/* Data Register */
372
+#define RNGD 0x04
373
+/* Mode Register */
374
+#define RNGMODE 0x08
375
+# define ROSEL_NORMAL (2) /* RNG only works in this mode */
376
+
377
+/* Number of bits to collect for randomness tests. */
378
+#define TEST_INPUT_BITS (128)
379
+
380
+static void rng_writeb(unsigned int offset, uint8_t value)
381
+{
382
+ writeb(RNG_BASE_ADDR + offset, value);
383
+}
384
+
385
+static uint8_t rng_readb(unsigned int offset)
386
+{
387
+ return readb(RNG_BASE_ADDR + offset);
388
+}
389
+
390
+/* Disable RNG and set normal ring oscillator mode. */
391
+static void rng_reset(void)
392
+{
393
+ rng_writeb(RNGCS, 0);
394
+ rng_writeb(RNGMODE, ROSEL_NORMAL);
395
+}
396
+
397
+/* Reset RNG and then enable it. */
398
+static void rng_reset_enable(void)
399
+{
400
+ rng_reset();
401
+ rng_writeb(RNGCS, RNGE);
402
+}
403
+
404
+/* Wait until Data Valid bit is set. */
405
+static bool rng_wait_ready(void)
406
+{
407
+ /* qemu_guest_getrandom may fail. Assume it won't fail 10 times in a row. */
408
+ int retries = 10;
409
+
410
+ while (retries-- > 0) {
411
+ if (rng_readb(RNGCS) & DVALID) {
412
+ return true;
413
+ }
414
+ }
415
+
416
+ return false;
417
+}
418
+
419
+/*
420
+ * Perform a frequency (monobit) test, as defined by NIST SP 800-22, on the
421
+ * sequence in buf and return the P-value. This represents the probability of a
422
+ * truly random sequence having the same proportion of zeros and ones as the
423
+ * sequence in buf.
424
+ *
425
+ * An RNG which always returns 0x00 or 0xff, or has some bits stuck at 0 or 1,
426
+ * will fail this test. However, an RNG which always returns 0x55, 0xf0 or some
427
+ * other value with an equal number of zeroes and ones will pass.
428
+ */
429
+static double calc_monobit_p(const uint8_t *buf, unsigned int len)
430
+{
431
+ unsigned int i;
432
+ double s_obs;
433
+ int sn = 0;
434
+
435
+ for (i = 0; i < len; i++) {
436
+ /*
437
+ * Each 1 counts as 1, each 0 counts as -1.
438
+ * s = cp - (8 - cp) = 2 * cp - 8
439
+ */
440
+ sn += 2 * ctpop8(buf[i]) - 8;
441
+ }
442
+
443
+ s_obs = abs(sn) / sqrt(len * BITS_PER_BYTE);
444
+
445
+ return erfc(s_obs / sqrt(2));
446
+}
447
+
448
+/*
449
+ * Perform a runs test, as defined by NIST SP 800-22, and return the P-value.
450
+ * This represents the probability of a truly random sequence having the same
451
+ * number of runs (i.e. uninterrupted sequences of identical bits) as the
452
+ * sequence in buf.
453
+ */
454
+static double calc_runs_p(const unsigned long *buf, unsigned int nr_bits)
455
+{
456
+ unsigned int j;
457
+ unsigned int k;
458
+ int nr_ones = 0;
459
+ int vn_obs = 0;
460
+ double pi;
461
+
462
+ g_assert(nr_bits % BITS_PER_LONG == 0);
463
+
464
+ for (j = 0; j < nr_bits / BITS_PER_LONG; j++) {
465
+ nr_ones += __builtin_popcountl(buf[j]);
466
+ }
467
+ pi = (double)nr_ones / nr_bits;
468
+
469
+ for (k = 0; k < nr_bits - 1; k++) {
470
+ vn_obs += !(test_bit(k, buf) ^ test_bit(k + 1, buf));
471
+ }
472
+ vn_obs += 1;
473
+
474
+ return erfc(fabs(vn_obs - 2 * nr_bits * pi * (1.0 - pi))
475
+ / (2 * sqrt(2 * nr_bits) * pi * (1.0 - pi)));
476
+}
477
+
478
+/*
479
+ * Verifies that DVALID is clear, and RNGD reads zero, when RNGE is cleared,
480
+ * and DVALID eventually becomes set when RNGE is set.
481
+ */
482
+static void test_enable_disable(void)
483
+{
484
+ /* Disable: DVALID should not be set, and RNGD should read zero */
485
+ rng_reset();
486
+ g_assert_cmphex(rng_readb(RNGCS), ==, 0);
487
+ g_assert_cmphex(rng_readb(RNGD), ==, 0);
488
+
489
+ /* Enable: DVALID should be set, but we can't make assumptions about RNGD */
490
+ rng_writeb(RNGCS, RNGE);
491
+ g_assert_true(rng_wait_ready());
492
+ g_assert_cmphex(rng_readb(RNGCS), ==, DVALID | RNGE);
493
+
494
+ /* Disable: DVALID should not be set, and RNGD should read zero */
495
+ rng_writeb(RNGCS, 0);
496
+ g_assert_cmphex(rng_readb(RNGCS), ==, 0);
497
+ g_assert_cmphex(rng_readb(RNGD), ==, 0);
498
+}
499
+
500
+/*
501
+ * Verifies that the RNG only produces data when RNGMODE is set to 'normal'
502
+ * ring oscillator mode.
503
+ */
504
+static void test_rosel(void)
505
+{
506
+ rng_reset_enable();
507
+ g_assert_true(rng_wait_ready());
508
+ rng_writeb(RNGMODE, 0);
509
+ g_assert_false(rng_wait_ready());
510
+ rng_writeb(RNGMODE, ROSEL_NORMAL);
511
+ g_assert_true(rng_wait_ready());
512
+ rng_writeb(RNGMODE, 0);
513
+ g_assert_false(rng_wait_ready());
514
+}
515
+
516
+/*
517
+ * Verifies that a continuous sequence of bits collected after enabling the RNG
518
+ * satisfies a monobit test.
519
+ */
520
+static void test_continuous_monobit(void)
521
+{
522
+ uint8_t buf[TEST_INPUT_BITS / BITS_PER_BYTE];
523
+ unsigned int i;
524
+
525
+ rng_reset_enable();
526
+ for (i = 0; i < sizeof(buf); i++) {
527
+ g_assert_true(rng_wait_ready());
528
+ buf[i] = rng_readb(RNGD);
529
+ }
530
+
531
+ g_assert_cmpfloat(calc_monobit_p(buf, sizeof(buf)), >, 0.01);
532
+}
533
+
534
+/*
535
+ * Verifies that a continuous sequence of bits collected after enabling the RNG
536
+ * satisfies a runs test.
537
+ */
538
+static void test_continuous_runs(void)
539
+{
540
+ union {
541
+ unsigned long l[TEST_INPUT_BITS / BITS_PER_LONG];
542
+ uint8_t c[TEST_INPUT_BITS / BITS_PER_BYTE];
543
+ } buf;
544
+ unsigned int i;
545
+
546
+ rng_reset_enable();
547
+ for (i = 0; i < sizeof(buf); i++) {
548
+ g_assert_true(rng_wait_ready());
549
+ buf.c[i] = rng_readb(RNGD);
550
+ }
551
+
552
+ g_assert_cmpfloat(calc_runs_p(buf.l, sizeof(buf) * BITS_PER_BYTE), >, 0.01);
553
+}
554
+
555
+/*
556
+ * Verifies that the first data byte collected after enabling the RNG satisfies
557
+ * a monobit test.
558
+ */
559
+static void test_first_byte_monobit(void)
560
+{
561
+ /* Enable, collect one byte, disable. Repeat until we have 100 bits. */
562
+ uint8_t buf[TEST_INPUT_BITS / BITS_PER_BYTE];
563
+ unsigned int i;
564
+
565
+ rng_reset();
566
+ for (i = 0; i < sizeof(buf); i++) {
567
+ rng_writeb(RNGCS, RNGE);
568
+ g_assert_true(rng_wait_ready());
569
+ buf[i] = rng_readb(RNGD);
570
+ rng_writeb(RNGCS, 0);
571
+ }
572
+
573
+ g_assert_cmpfloat(calc_monobit_p(buf, sizeof(buf)), >, 0.01);
574
+}
575
+
576
+/*
577
+ * Verifies that the first data byte collected after enabling the RNG satisfies
578
+ * a runs test.
579
+ */
580
+static void test_first_byte_runs(void)
581
+{
582
+ /* Enable, collect one byte, disable. Repeat until we have 100 bits. */
583
+ union {
584
+ unsigned long l[TEST_INPUT_BITS / BITS_PER_LONG];
585
+ uint8_t c[TEST_INPUT_BITS / BITS_PER_BYTE];
586
+ } buf;
587
+ unsigned int i;
588
+
589
+ rng_reset();
590
+ for (i = 0; i < sizeof(buf); i++) {
591
+ rng_writeb(RNGCS, RNGE);
592
+ g_assert_true(rng_wait_ready());
593
+ buf.c[i] = rng_readb(RNGD);
594
+ rng_writeb(RNGCS, 0);
595
+ }
596
+
597
+ g_assert_cmpfloat(calc_runs_p(buf.l, sizeof(buf) * BITS_PER_BYTE), >, 0.01);
598
+}
599
+
600
+int main(int argc, char **argv)
601
+{
602
+ int ret;
603
+
604
+ g_test_init(&argc, &argv, NULL);
605
+ g_test_set_nonfatal_assertions();
606
+
607
+ qtest_add_func("npcm7xx_rng/enable_disable", test_enable_disable);
608
+ qtest_add_func("npcm7xx_rng/rosel", test_rosel);
609
+ qtest_add_func("npcm7xx_rng/continuous/monobit", test_continuous_monobit);
610
+ qtest_add_func("npcm7xx_rng/continuous/runs", test_continuous_runs);
611
+ qtest_add_func("npcm7xx_rng/first_byte/monobit", test_first_byte_monobit);
612
+ qtest_add_func("npcm7xx_rng/first_byte/runs", test_first_byte_runs);
613
+
614
+ qtest_start("-machine npcm750-evb");
615
+ ret = g_test_run();
616
+ qtest_end();
617
+
618
+ return ret;
619
+}
620
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
621
index XXXXXXX..XXXXXXX 100644
622
--- a/hw/misc/meson.build
623
+++ b/hw/misc/meson.build
624
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mst_fpga.c'))
625
softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
626
'npcm7xx_clk.c',
627
'npcm7xx_gcr.c',
628
+ 'npcm7xx_rng.c',
629
))
630
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files(
631
'omap_clk.c',
331
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
632
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
332
index XXXXXXX..XXXXXXX 100644
633
index XXXXXXX..XXXXXXX 100644
333
--- a/hw/misc/trace-events
634
--- a/hw/misc/trace-events
334
+++ b/hw/misc/trace-events
635
+++ b/hw/misc/trace-events
335
@@ -XXX,XX +XXX,XX @@ armsse_cpuid_write(uint64_t offset, uint64_t data, unsigned size) "SSE-200 CPU_I
636
@@ -XXX,XX +XXX,XX @@ npcm7xx_clk_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " valu
336
# armsse-mhu.c
637
npcm7xx_gcr_read(uint64_t offset, uint32_t value) " offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
337
armsse_mhu_read(uint64_t offset, uint64_t data, unsigned size) "SSE-200 MHU read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
638
npcm7xx_gcr_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
338
armsse_mhu_write(uint64_t offset, uint64_t data, unsigned size) "SSE-200 MHU write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
639
339
+
640
+# npcm7xx_rng.c
340
+# aspeed_xdma.c
641
+npcm7xx_rng_read(uint64_t offset, uint64_t value, unsigned size) "offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
341
+aspeed_xdma_write(uint64_t offset, uint64_t data) "XDMA write: offset 0x%" PRIx64 " data 0x%" PRIx64
642
+npcm7xx_rng_write(uint64_t offset, uint64_t value, unsigned size) "offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
643
+
644
# stm32f4xx_syscfg.c
645
stm32f4xx_syscfg_set_irq(int gpio, int line, int level) "Interupt: GPIO: %d, Line: %d; Level: %d"
646
stm32f4xx_pulse_exti(int irq) "Pulse EXTI: %d"
647
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
648
index XXXXXXX..XXXXXXX 100644
649
--- a/tests/qtest/meson.build
650
+++ b/tests/qtest/meson.build
651
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
652
(config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) + \
653
['prom-env-test', 'boot-serial-test']
654
655
-qtests_npcm7xx = ['npcm7xx_timer-test', 'npcm7xx_watchdog_timer-test']
656
+qtests_npcm7xx = \
657
+ ['npcm7xx_rng-test',
658
+ 'npcm7xx_timer-test',
659
+ 'npcm7xx_watchdog_timer-test']
660
qtests_arm = \
661
(config_all_devices.has_key('CONFIG_PFLASH_CFI02') ? ['pflash-cfi02-test'] : []) + \
662
(config_all_devices.has_key('CONFIG_NPCM7XX') ? qtests_npcm7xx : []) + \
342
--
663
--
343
2.20.1
664
2.20.1
344
665
345
666
diff view generated by jsdifflib
1
From: Cédric Le Goater <clg@kaod.org>
1
From: Havard Skinnemoen <hskinnemoen@google.com>
2
2
3
The current models of the Aspeed SoCs only have one CPU but future
3
The NPCM730 and NPCM750 chips have a single USB host port shared between
4
ones will support SMP. Introduce a new num_cpus field at the SoC class
4
a USB 2.0 EHCI host controller and a USB 1.1 OHCI host controller. This
5
level to define the number of available CPUs per SoC and also
5
adds support for both of them.
6
introduce a 'num-cpus' property to activate the CPUs configured for
7
the machine.
8
6
9
The max_cpus limit of the machine should depend on the SoC definition
7
Testing notes:
10
but, unfortunately, these values are not available when the machine
8
* With -device usb-kbd, qemu will automatically insert a full-speed
11
class is initialized. This is the reason why we add a check on
9
hub, and the keyboard becomes controlled by the OHCI controller.
12
num_cpus in the AspeedSoC realize handler.
10
* With -device usb-kbd,bus=usb-bus.0,port=1, the keyboard is directly
11
attached to the port without any hubs, and the device becomes
12
controlled by the EHCI controller since it's high speed capable.
13
* With -device usb-kbd,bus=usb-bus.0,port=1,usb_version=1, the
14
keyboard is directly attached to the port, but it only advertises
15
itself as full-speed capable, so it becomes controlled by the OHCI
16
controller.
13
17
14
SMP support will be activated when models for such SoCs are implemented.
18
In all cases, the keyboard device enumerates correctly.
15
19
16
Signed-off-by: Cédric Le Goater <clg@kaod.org>
20
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
17
Reviewed-by: Joel Stanley <joel@jms.id.au>
21
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
18
Message-id: 20190618165311.27066-6-clg@kaod.org
22
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
19
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
23
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
20
---
24
---
21
include/hw/arm/aspeed_soc.h | 5 ++++-
25
docs/system/arm/nuvoton.rst | 2 +-
22
hw/arm/aspeed.c | 7 +++++--
26
hw/usb/hcd-ehci.h | 1 +
23
hw/arm/aspeed_soc.c | 33 +++++++++++++++++++++++++++------
27
include/hw/arm/npcm7xx.h | 4 ++++
24
3 files changed, 36 insertions(+), 9 deletions(-)
28
hw/arm/npcm7xx.c | 27 +++++++++++++++++++++++++--
29
hw/usb/hcd-ehci-sysbus.c | 19 +++++++++++++++++++
30
5 files changed, 50 insertions(+), 3 deletions(-)
25
31
26
diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h
32
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
27
index XXXXXXX..XXXXXXX 100644
33
index XXXXXXX..XXXXXXX 100644
28
--- a/include/hw/arm/aspeed_soc.h
34
--- a/docs/system/arm/nuvoton.rst
29
+++ b/include/hw/arm/aspeed_soc.h
35
+++ b/docs/system/arm/nuvoton.rst
36
@@ -XXX,XX +XXX,XX @@ Supported devices
37
* OTP controllers (no protection features)
38
* Flash Interface Unit (FIU; no protection features)
39
* Random Number Generator (RNG)
40
+ * USB host (USBH)
41
42
Missing devices
43
---------------
44
@@ -XXX,XX +XXX,XX @@ Missing devices
45
* eSPI slave interface
46
47
* Ethernet controllers (GMAC and EMC)
48
- * USB host (USBH)
49
* USB device (USBD)
50
* SMBus controller (SMBF)
51
* Peripheral SPI controller (PSPI)
52
diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
53
index XXXXXXX..XXXXXXX 100644
54
--- a/hw/usb/hcd-ehci.h
55
+++ b/hw/usb/hcd-ehci.h
56
@@ -XXX,XX +XXX,XX @@ struct EHCIPCIState {
57
#define TYPE_PLATFORM_EHCI "platform-ehci-usb"
58
#define TYPE_EXYNOS4210_EHCI "exynos4210-ehci-usb"
59
#define TYPE_AW_H3_EHCI "aw-h3-ehci-usb"
60
+#define TYPE_NPCM7XX_EHCI "npcm7xx-ehci-usb"
61
#define TYPE_TEGRA2_EHCI "tegra2-ehci-usb"
62
#define TYPE_PPC4xx_EHCI "ppc4xx-ehci-usb"
63
#define TYPE_FUSBH200_EHCI "fusbh200-ehci-usb"
64
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
65
index XXXXXXX..XXXXXXX 100644
66
--- a/include/hw/arm/npcm7xx.h
67
+++ b/include/hw/arm/npcm7xx.h
30
@@ -XXX,XX +XXX,XX @@
68
@@ -XXX,XX +XXX,XX @@
31
69
#include "hw/nvram/npcm7xx_otp.h"
32
#define ASPEED_SPIS_NUM 2
70
#include "hw/timer/npcm7xx_timer.h"
33
#define ASPEED_WDTS_NUM 3
71
#include "hw/ssi/npcm7xx_fiu.h"
34
+#define ASPEED_CPUS_NUM 2
72
+#include "hw/usb/hcd-ehci.h"
35
73
+#include "hw/usb/hcd-ohci.h"
36
typedef struct AspeedSoCState {
74
#include "target/arm/cpu.h"
37
/*< private >*/
75
38
DeviceState parent;
76
#define NPCM7XX_MAX_NUM_CPUS (2)
39
77
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
40
/*< public >*/
78
NPCM7xxOTPState fuse_array;
41
- ARMCPU cpu;
79
NPCM7xxMCState mc;
42
+ ARMCPU cpu[ASPEED_CPUS_NUM];
80
NPCM7xxRNGState rng;
43
+ uint32_t num_cpus;
81
+ EHCISysBusState ehci;
44
MemoryRegion sram;
82
+ OHCISysBusState ohci;
45
AspeedVICState vic;
83
NPCM7xxFIUState fiu[2];
46
AspeedRtcState rtc;
84
} NPCM7xxState;
47
@@ -XXX,XX +XXX,XX @@ typedef struct AspeedSoCInfo {
85
48
int wdts_num;
86
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
49
const int *irqmap;
50
const hwaddr *memmap;
51
+ uint32_t num_cpus;
52
} AspeedSoCInfo;
53
54
typedef struct AspeedSoCClass {
55
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
56
index XXXXXXX..XXXXXXX 100644
87
index XXXXXXX..XXXXXXX 100644
57
--- a/hw/arm/aspeed.c
88
--- a/hw/arm/npcm7xx.c
58
+++ b/hw/arm/aspeed.c
89
+++ b/hw/arm/npcm7xx.c
59
@@ -XXX,XX +XXX,XX @@
90
@@ -XXX,XX +XXX,XX @@
60
#include "hw/misc/tmp105.h"
91
#define NPCM7XX_MC_BA (0xf0824000)
61
#include "qemu/log.h"
92
#define NPCM7XX_RNG_BA (0xf000b000)
62
#include "sysemu/block-backend.h"
93
63
+#include "sysemu/sysemu.h"
94
+/* USB Host modules */
64
#include "hw/loader.h"
95
+#define NPCM7XX_EHCI_BA (0xf0806000)
65
#include "qemu/error-report.h"
96
+#define NPCM7XX_OHCI_BA (0xf0807000)
66
#include "qemu/units.h"
97
+
67
98
/* Internal AHB SRAM */
68
static struct arm_boot_info aspeed_board_binfo = {
99
#define NPCM7XX_RAM3_BA (0xc0008000)
69
.board_id = -1, /* device-tree-only board */
100
#define NPCM7XX_RAM3_SZ (4 * KiB)
70
- .nb_cpus = 1,
101
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxInterrupt {
102
NPCM7XX_WDG0_IRQ = 47, /* Timer Module 0 Watchdog */
103
NPCM7XX_WDG1_IRQ, /* Timer Module 1 Watchdog */
104
NPCM7XX_WDG2_IRQ, /* Timer Module 2 Watchdog */
105
+ NPCM7XX_EHCI_IRQ = 61,
106
+ NPCM7XX_OHCI_IRQ = 62,
71
};
107
};
72
108
73
struct AspeedBoardState {
109
/* Total number of GIC interrupts, including internal Cortex-A9 interrupts. */
74
@@ -XXX,XX +XXX,XX @@ static void aspeed_board_init(MachineState *machine,
110
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
75
&error_abort);
111
object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
76
object_property_set_int(OBJECT(&bmc->soc), cfg->num_cs, "num-cs",
112
}
77
&error_abort);
113
78
+ object_property_set_int(OBJECT(&bmc->soc), smp_cpus, "num-cpus",
114
+ object_initialize_child(obj, "ehci", &s->ehci, TYPE_NPCM7XX_EHCI);
115
+ object_initialize_child(obj, "ohci", &s->ohci, TYPE_SYSBUS_OHCI);
116
+
117
QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_fiu) != ARRAY_SIZE(s->fiu));
118
for (i = 0; i < ARRAY_SIZE(s->fiu); i++) {
119
object_initialize_child(obj, npcm7xx_fiu[i].name, &s->fiu[i],
120
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
121
sysbus_realize(SYS_BUS_DEVICE(&s->rng), &error_abort);
122
sysbus_mmio_map(SYS_BUS_DEVICE(&s->rng), 0, NPCM7XX_RNG_BA);
123
124
+ /* USB Host */
125
+ object_property_set_bool(OBJECT(&s->ehci), "companion-enable", true,
126
+ &error_abort);
127
+ sysbus_realize(SYS_BUS_DEVICE(&s->ehci), &error_abort);
128
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->ehci), 0, NPCM7XX_EHCI_BA);
129
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci), 0,
130
+ npcm7xx_irq(s, NPCM7XX_EHCI_IRQ));
131
+
132
+ object_property_set_str(OBJECT(&s->ohci), "masterbus", "usb-bus.0",
79
+ &error_abort);
133
+ &error_abort);
80
if (machine->kernel_filename) {
134
+ object_property_set_uint(OBJECT(&s->ohci), "num-ports", 1, &error_abort);
81
/*
135
+ sysbus_realize(SYS_BUS_DEVICE(&s->ohci), &error_abort);
82
* When booting with a -kernel command line there is no u-boot
136
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->ohci), 0, NPCM7XX_OHCI_BA);
83
@@ -XXX,XX +XXX,XX @@ static void aspeed_board_init(MachineState *machine,
137
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->ohci), 0,
84
aspeed_board_binfo.kernel_cmdline = machine->kernel_cmdline;
138
+ npcm7xx_irq(s, NPCM7XX_OHCI_IRQ));
85
aspeed_board_binfo.ram_size = ram_size;
139
+
86
aspeed_board_binfo.loader_start = sc->info->memmap[ASPEED_SDRAM];
140
/*
87
+ aspeed_board_binfo.nb_cpus = bmc->soc.num_cpus;
141
* Flash Interface Unit (FIU). Can fail if incorrect number of chip selects
88
142
* specified, but this is a programming error.
89
if (cfg->i2c_init) {
143
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
90
cfg->i2c_init(bmc);
144
create_unimplemented_device("npcm7xx.mcphy", 0xf05f0000, 64 * KiB);
91
@@ -XXX,XX +XXX,XX @@ static void aspeed_machine_class_init(ObjectClass *oc, void *data)
145
create_unimplemented_device("npcm7xx.gmac1", 0xf0802000, 8 * KiB);
92
146
create_unimplemented_device("npcm7xx.gmac2", 0xf0804000, 8 * KiB);
93
mc->desc = board->desc;
147
- create_unimplemented_device("npcm7xx.ehci", 0xf0806000, 4 * KiB);
94
mc->init = aspeed_machine_init;
148
- create_unimplemented_device("npcm7xx.ohci", 0xf0807000, 4 * KiB);
95
- mc->max_cpus = 1;
149
create_unimplemented_device("npcm7xx.vcd", 0xf0810000, 64 * KiB);
96
+ mc->max_cpus = ASPEED_CPUS_NUM;
150
create_unimplemented_device("npcm7xx.ece", 0xf0820000, 8 * KiB);
97
mc->no_sdcard = 1;
151
create_unimplemented_device("npcm7xx.vdma", 0xf0822000, 8 * KiB);
98
mc->no_floppy = 1;
152
diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c
99
mc->no_cdrom = 1;
100
diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c
101
index XXXXXXX..XXXXXXX 100644
153
index XXXXXXX..XXXXXXX 100644
102
--- a/hw/arm/aspeed_soc.c
154
--- a/hw/usb/hcd-ehci-sysbus.c
103
+++ b/hw/arm/aspeed_soc.c
155
+++ b/hw/usb/hcd-ehci-sysbus.c
104
@@ -XXX,XX +XXX,XX @@
156
@@ -XXX,XX +XXX,XX @@ static const TypeInfo ehci_aw_h3_type_info = {
105
#include "hw/char/serial.h"
157
.class_init = ehci_aw_h3_class_init,
106
#include "qemu/log.h"
107
#include "qemu/module.h"
108
+#include "qemu/error-report.h"
109
#include "hw/i2c/aspeed_i2c.h"
110
#include "net/net.h"
111
112
@@ -XXX,XX +XXX,XX @@ static const AspeedSoCInfo aspeed_socs[] = {
113
.wdts_num = 2,
114
.irqmap = aspeed_soc_ast2400_irqmap,
115
.memmap = aspeed_soc_ast2400_memmap,
116
+ .num_cpus = 1,
117
}, {
118
.name = "ast2400-a1",
119
.cpu_type = ARM_CPU_TYPE_NAME("arm926"),
120
@@ -XXX,XX +XXX,XX @@ static const AspeedSoCInfo aspeed_socs[] = {
121
.wdts_num = 2,
122
.irqmap = aspeed_soc_ast2400_irqmap,
123
.memmap = aspeed_soc_ast2400_memmap,
124
+ .num_cpus = 1,
125
}, {
126
.name = "ast2400",
127
.cpu_type = ARM_CPU_TYPE_NAME("arm926"),
128
@@ -XXX,XX +XXX,XX @@ static const AspeedSoCInfo aspeed_socs[] = {
129
.wdts_num = 2,
130
.irqmap = aspeed_soc_ast2400_irqmap,
131
.memmap = aspeed_soc_ast2400_memmap,
132
+ .num_cpus = 1,
133
}, {
134
.name = "ast2500-a1",
135
.cpu_type = ARM_CPU_TYPE_NAME("arm1176"),
136
@@ -XXX,XX +XXX,XX @@ static const AspeedSoCInfo aspeed_socs[] = {
137
.wdts_num = 3,
138
.irqmap = aspeed_soc_ast2500_irqmap,
139
.memmap = aspeed_soc_ast2500_memmap,
140
+ .num_cpus = 1,
141
},
142
};
158
};
143
159
144
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_init(Object *obj)
160
+static void ehci_npcm7xx_class_init(ObjectClass *oc, void *data)
145
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
161
+{
146
int i;
162
+ SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
147
163
+ DeviceClass *dc = DEVICE_CLASS(oc);
148
- object_initialize_child(obj, "cpu", OBJECT(&s->cpu), sizeof(s->cpu),
149
- sc->info->cpu_type, &error_abort, NULL);
150
+ for (i = 0; i < sc->info->num_cpus; i++) {
151
+ object_initialize_child(obj, "cpu[*]", OBJECT(&s->cpu[i]),
152
+ sizeof(s->cpu[i]), sc->info->cpu_type,
153
+ &error_abort, NULL);
154
+ }
155
156
sysbus_init_child_obj(obj, "scu", OBJECT(&s->scu), sizeof(s->scu),
157
TYPE_ASPEED_SCU);
158
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
159
create_unimplemented_device("aspeed_soc.io", sc->info->memmap[ASPEED_IOMEM],
160
ASPEED_SOC_IOMEM_SIZE);
161
162
+ if (s->num_cpus > sc->info->num_cpus) {
163
+ warn_report("%s: invalid number of CPUs %d, using default %d",
164
+ sc->info->name, s->num_cpus, sc->info->num_cpus);
165
+ s->num_cpus = sc->info->num_cpus;
166
+ }
167
+
164
+
168
/* CPU */
165
+ sec->capsbase = 0x0;
169
- object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err);
166
+ sec->opregbase = 0x10;
170
- if (err) {
167
+ sec->portscbase = 0x44;
171
- error_propagate(errp, err);
168
+ sec->portnr = 1;
172
- return;
169
+ set_bit(DEVICE_CATEGORY_USB, dc->categories);
173
+ for (i = 0; i < s->num_cpus; i++) {
170
+}
174
+ object_property_set_bool(OBJECT(&s->cpu[i]), true, "realized", &err);
171
+
175
+ if (err) {
172
+static const TypeInfo ehci_npcm7xx_type_info = {
176
+ error_propagate(errp, err);
173
+ .name = TYPE_NPCM7XX_EHCI,
177
+ return;
174
+ .parent = TYPE_SYS_BUS_EHCI,
178
+ }
175
+ .class_init = ehci_npcm7xx_class_init,
179
}
180
181
/* SRAM */
182
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
183
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100), 0,
184
aspeed_soc_get_irq(s, ASPEED_ETH1));
185
}
186
+static Property aspeed_soc_properties[] = {
187
+ DEFINE_PROP_UINT32("num-cpus", AspeedSoCState, num_cpus, 0),
188
+ DEFINE_PROP_END_OF_LIST(),
189
+};
176
+};
190
177
+
191
static void aspeed_soc_class_init(ObjectClass *oc, void *data)
178
static void ehci_tegra2_class_init(ObjectClass *oc, void *data)
192
{
179
{
193
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_class_init(ObjectClass *oc, void *data)
180
SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
194
dc->realize = aspeed_soc_realize;
181
@@ -XXX,XX +XXX,XX @@ static void ehci_sysbus_register_types(void)
195
/* Reason: Uses serial_hds and nd_table in realize() directly */
182
type_register_static(&ehci_platform_type_info);
196
dc->user_creatable = false;
183
type_register_static(&ehci_exynos4210_type_info);
197
+ dc->props = aspeed_soc_properties;
184
type_register_static(&ehci_aw_h3_type_info);
198
}
185
+ type_register_static(&ehci_npcm7xx_type_info);
199
186
type_register_static(&ehci_tegra2_type_info);
200
static const TypeInfo aspeed_soc_type_info = {
187
type_register_static(&ehci_ppc4xx_type_info);
188
type_register_static(&ehci_fusbh200_type_info);
201
--
189
--
202
2.20.1
190
2.20.1
203
191
204
192
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Havard Skinnemoen <hskinnemoen@google.com>
2
2
3
These routines are TCG specific.
3
The NPCM7xx chips have multiple GPIO controllers that are mostly
4
The arm_deliver_fault() function is only used within the new
4
identical except for some minor differences like the reset values of
5
helper. Make it static.
5
some registers. Each controller controls up to 32 pins.
6
6
7
Suggested-by: Alex Bennée <alex.bennee@linaro.org>
7
Each individual pin is modeled as a pair of unnamed GPIOs -- one for
8
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
emitting the actual pin state, and one for driving the pin externally.
9
Message-id: 20190701132516.26392-13-philmd@redhat.com
9
Like the nRF51 GPIO controller, a gpio level may be negative, which
10
means the pin is not driven, or floating.
11
12
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
13
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
14
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
16
---
13
target/arm/Makefile.objs | 1 +
17
docs/system/arm/nuvoton.rst | 2 +-
14
target/arm/internals.h | 3 -
18
include/hw/arm/npcm7xx.h | 2 +
15
target/arm/cpu.c | 6 +-
19
include/hw/gpio/npcm7xx_gpio.h | 55 +++++
16
target/arm/helper.c | 53 -----------
20
hw/arm/npcm7xx.c | 80 ++++++
17
target/arm/op_helper.c | 135 --------------------------
21
hw/gpio/npcm7xx_gpio.c | 424 ++++++++++++++++++++++++++++++++
18
target/arm/tlb_helper.c | 200 +++++++++++++++++++++++++++++++++++++++
22
tests/qtest/npcm7xx_gpio-test.c | 385 +++++++++++++++++++++++++++++
19
6 files changed, 205 insertions(+), 193 deletions(-)
23
hw/gpio/meson.build | 1 +
20
create mode 100644 target/arm/tlb_helper.c
24
hw/gpio/trace-events | 7 +
25
tests/qtest/meson.build | 3 +-
26
9 files changed, 957 insertions(+), 2 deletions(-)
27
create mode 100644 include/hw/gpio/npcm7xx_gpio.h
28
create mode 100644 hw/gpio/npcm7xx_gpio.c
29
create mode 100644 tests/qtest/npcm7xx_gpio-test.c
21
30
22
diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
31
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
23
index XXXXXXX..XXXXXXX 100644
32
index XXXXXXX..XXXXXXX 100644
24
--- a/target/arm/Makefile.objs
33
--- a/docs/system/arm/nuvoton.rst
25
+++ b/target/arm/Makefile.objs
34
+++ b/docs/system/arm/nuvoton.rst
26
@@ -XXX,XX +XXX,XX @@ target/arm/translate-sve.o: target/arm/decode-sve.inc.c
35
@@ -XXX,XX +XXX,XX @@ Supported devices
27
target/arm/translate.o: target/arm/decode-vfp.inc.c
36
* Flash Interface Unit (FIU; no protection features)
28
target/arm/translate.o: target/arm/decode-vfp-uncond.inc.c
37
* Random Number Generator (RNG)
29
38
* USB host (USBH)
30
+obj-y += tlb_helper.o
39
+ * GPIO controller
31
obj-y += translate.o op_helper.o
40
32
obj-y += crypto_helper.o
41
Missing devices
33
obj-y += iwmmxt_helper.o vec_helper.o neon_helper.o
42
---------------
34
diff --git a/target/arm/internals.h b/target/arm/internals.h
43
44
- * GPIO controller
45
* LPC/eSPI host-to-BMC interface, including
46
47
* Keyboard and mouse controller interface (KBCI)
48
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
35
index XXXXXXX..XXXXXXX 100644
49
index XXXXXXX..XXXXXXX 100644
36
--- a/target/arm/internals.h
50
--- a/include/hw/arm/npcm7xx.h
37
+++ b/target/arm/internals.h
51
+++ b/include/hw/arm/npcm7xx.h
38
@@ -XXX,XX +XXX,XX @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
52
@@ -XXX,XX +XXX,XX @@
39
MMUAccessType access_type, int mmu_idx,
53
40
bool probe, uintptr_t retaddr);
54
#include "hw/boards.h"
41
55
#include "hw/cpu/a9mpcore.h"
42
-void arm_deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type,
56
+#include "hw/gpio/npcm7xx_gpio.h"
43
- int mmu_idx, ARMMMUFaultInfo *fi) QEMU_NORETURN;
57
#include "hw/mem/npcm7xx_mc.h"
44
-
58
#include "hw/misc/npcm7xx_clk.h"
45
/* Return true if the stage 1 translation regime is using LPAE format page
59
#include "hw/misc/npcm7xx_gcr.h"
46
* tables */
60
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
47
bool arm_s1_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx);
61
NPCM7xxOTPState fuse_array;
48
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
62
NPCM7xxMCState mc;
49
index XXXXXXX..XXXXXXX 100644
63
NPCM7xxRNGState rng;
50
--- a/target/arm/cpu.c
64
+ NPCM7xxGPIOState gpio[8];
51
+++ b/target/arm/cpu.c
65
EHCISysBusState ehci;
52
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
66
OHCISysBusState ohci;
53
cc->gdb_write_register = arm_cpu_gdb_write_register;
67
NPCM7xxFIUState fiu[2];
54
#ifndef CONFIG_USER_ONLY
68
diff --git a/include/hw/gpio/npcm7xx_gpio.h b/include/hw/gpio/npcm7xx_gpio.h
55
cc->do_interrupt = arm_cpu_do_interrupt;
56
- cc->do_unaligned_access = arm_cpu_do_unaligned_access;
57
- cc->do_transaction_failed = arm_cpu_do_transaction_failed;
58
cc->get_phys_page_attrs_debug = arm_cpu_get_phys_page_attrs_debug;
59
cc->asidx_from_attrs = arm_asidx_from_attrs;
60
cc->vmsd = &vmstate_arm_cpu;
61
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
62
#ifdef CONFIG_TCG
63
cc->tcg_initialize = arm_translate_init;
64
cc->tlb_fill = arm_cpu_tlb_fill;
65
+#if !defined(CONFIG_USER_ONLY)
66
+ cc->do_unaligned_access = arm_cpu_do_unaligned_access;
67
+ cc->do_transaction_failed = arm_cpu_do_transaction_failed;
68
+#endif /* CONFIG_TCG && !CONFIG_USER_ONLY */
69
#endif
70
}
71
72
diff --git a/target/arm/helper.c b/target/arm/helper.c
73
index XXXXXXX..XXXXXXX 100644
74
--- a/target/arm/helper.c
75
+++ b/target/arm/helper.c
76
@@ -XXX,XX +XXX,XX @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
77
78
#endif
79
80
-bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
81
- MMUAccessType access_type, int mmu_idx,
82
- bool probe, uintptr_t retaddr)
83
-{
84
- ARMCPU *cpu = ARM_CPU(cs);
85
-
86
-#ifdef CONFIG_USER_ONLY
87
- cpu->env.exception.vaddress = address;
88
- if (access_type == MMU_INST_FETCH) {
89
- cs->exception_index = EXCP_PREFETCH_ABORT;
90
- } else {
91
- cs->exception_index = EXCP_DATA_ABORT;
92
- }
93
- cpu_loop_exit_restore(cs, retaddr);
94
-#else
95
- hwaddr phys_addr;
96
- target_ulong page_size;
97
- int prot, ret;
98
- MemTxAttrs attrs = {};
99
- ARMMMUFaultInfo fi = {};
100
-
101
- /*
102
- * Walk the page table and (if the mapping exists) add the page
103
- * to the TLB. On success, return true. Otherwise, if probing,
104
- * return false. Otherwise populate fsr with ARM DFSR/IFSR fault
105
- * register format, and signal the fault.
106
- */
107
- ret = get_phys_addr(&cpu->env, address, access_type,
108
- core_to_arm_mmu_idx(&cpu->env, mmu_idx),
109
- &phys_addr, &attrs, &prot, &page_size, &fi, NULL);
110
- if (likely(!ret)) {
111
- /*
112
- * Map a single [sub]page. Regions smaller than our declared
113
- * target page size are handled specially, so for those we
114
- * pass in the exact addresses.
115
- */
116
- if (page_size >= TARGET_PAGE_SIZE) {
117
- phys_addr &= TARGET_PAGE_MASK;
118
- address &= TARGET_PAGE_MASK;
119
- }
120
- tlb_set_page_with_attrs(cs, address, phys_addr, attrs,
121
- prot, mmu_idx, page_size);
122
- return true;
123
- } else if (probe) {
124
- return false;
125
- } else {
126
- /* now we have a real cpu fault */
127
- cpu_restore_state(cs, retaddr, true);
128
- arm_deliver_fault(cpu, address, access_type, mmu_idx, &fi);
129
- }
130
-#endif
131
-}
132
-
133
/* Note that signed overflow is undefined in C. The following routines are
134
careful to use unsigned types where modulo arithmetic is required.
135
Failure to do so _will_ break on newer gcc. */
136
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
137
index XXXXXXX..XXXXXXX 100644
138
--- a/target/arm/op_helper.c
139
+++ b/target/arm/op_helper.c
140
@@ -XXX,XX +XXX,XX @@ uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def, void *vn,
141
return val;
142
}
143
144
-#if !defined(CONFIG_USER_ONLY)
145
-
146
-static inline uint32_t merge_syn_data_abort(uint32_t template_syn,
147
- unsigned int target_el,
148
- bool same_el, bool ea,
149
- bool s1ptw, bool is_write,
150
- int fsc)
151
-{
152
- uint32_t syn;
153
-
154
- /*
155
- * ISV is only set for data aborts routed to EL2 and
156
- * never for stage-1 page table walks faulting on stage 2.
157
- *
158
- * Furthermore, ISV is only set for certain kinds of load/stores.
159
- * If the template syndrome does not have ISV set, we should leave
160
- * it cleared.
161
- *
162
- * See ARMv8 specs, D7-1974:
163
- * ISS encoding for an exception from a Data Abort, the
164
- * ISV field.
165
- */
166
- if (!(template_syn & ARM_EL_ISV) || target_el != 2 || s1ptw) {
167
- syn = syn_data_abort_no_iss(same_el,
168
- ea, 0, s1ptw, is_write, fsc);
169
- } else {
170
- /*
171
- * Fields: IL, ISV, SAS, SSE, SRT, SF and AR come from the template
172
- * syndrome created at translation time.
173
- * Now we create the runtime syndrome with the remaining fields.
174
- */
175
- syn = syn_data_abort_with_iss(same_el,
176
- 0, 0, 0, 0, 0,
177
- ea, 0, s1ptw, is_write, fsc,
178
- false);
179
- /* Merge the runtime syndrome with the template syndrome. */
180
- syn |= template_syn;
181
- }
182
- return syn;
183
-}
184
-
185
-void arm_deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type,
186
- int mmu_idx, ARMMMUFaultInfo *fi)
187
-{
188
- CPUARMState *env = &cpu->env;
189
- int target_el;
190
- bool same_el;
191
- uint32_t syn, exc, fsr, fsc;
192
- ARMMMUIdx arm_mmu_idx = core_to_arm_mmu_idx(env, mmu_idx);
193
-
194
- target_el = exception_target_el(env);
195
- if (fi->stage2) {
196
- target_el = 2;
197
- env->cp15.hpfar_el2 = extract64(fi->s2addr, 12, 47) << 4;
198
- }
199
- same_el = (arm_current_el(env) == target_el);
200
-
201
- if (target_el == 2 || arm_el_is_aa64(env, target_el) ||
202
- arm_s1_regime_using_lpae_format(env, arm_mmu_idx)) {
203
- /*
204
- * LPAE format fault status register : bottom 6 bits are
205
- * status code in the same form as needed for syndrome
206
- */
207
- fsr = arm_fi_to_lfsc(fi);
208
- fsc = extract32(fsr, 0, 6);
209
- } else {
210
- fsr = arm_fi_to_sfsc(fi);
211
- /*
212
- * Short format FSR : this fault will never actually be reported
213
- * to an EL that uses a syndrome register. Use a (currently)
214
- * reserved FSR code in case the constructed syndrome does leak
215
- * into the guest somehow.
216
- */
217
- fsc = 0x3f;
218
- }
219
-
220
- if (access_type == MMU_INST_FETCH) {
221
- syn = syn_insn_abort(same_el, fi->ea, fi->s1ptw, fsc);
222
- exc = EXCP_PREFETCH_ABORT;
223
- } else {
224
- syn = merge_syn_data_abort(env->exception.syndrome, target_el,
225
- same_el, fi->ea, fi->s1ptw,
226
- access_type == MMU_DATA_STORE,
227
- fsc);
228
- if (access_type == MMU_DATA_STORE
229
- && arm_feature(env, ARM_FEATURE_V6)) {
230
- fsr |= (1 << 11);
231
- }
232
- exc = EXCP_DATA_ABORT;
233
- }
234
-
235
- env->exception.vaddress = addr;
236
- env->exception.fsr = fsr;
237
- raise_exception(env, exc, syn, target_el);
238
-}
239
-
240
-/* Raise a data fault alignment exception for the specified virtual address */
241
-void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
242
- MMUAccessType access_type,
243
- int mmu_idx, uintptr_t retaddr)
244
-{
245
- ARMCPU *cpu = ARM_CPU(cs);
246
- ARMMMUFaultInfo fi = {};
247
-
248
- /* now we have a real cpu fault */
249
- cpu_restore_state(cs, retaddr, true);
250
-
251
- fi.type = ARMFault_Alignment;
252
- arm_deliver_fault(cpu, vaddr, access_type, mmu_idx, &fi);
253
-}
254
-
255
-/*
256
- * arm_cpu_do_transaction_failed: handle a memory system error response
257
- * (eg "no device/memory present at address") by raising an external abort
258
- * exception
259
- */
260
-void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
261
- vaddr addr, unsigned size,
262
- MMUAccessType access_type,
263
- int mmu_idx, MemTxAttrs attrs,
264
- MemTxResult response, uintptr_t retaddr)
265
-{
266
- ARMCPU *cpu = ARM_CPU(cs);
267
- ARMMMUFaultInfo fi = {};
268
-
269
- /* now we have a real cpu fault */
270
- cpu_restore_state(cs, retaddr, true);
271
-
272
- fi.ea = arm_extabort_type(response);
273
- fi.type = ARMFault_SyncExternal;
274
- arm_deliver_fault(cpu, addr, access_type, mmu_idx, &fi);
275
-}
276
-
277
-#endif /* !defined(CONFIG_USER_ONLY) */
278
-
279
void HELPER(v8m_stackcheck)(CPUARMState *env, uint32_t newvalue)
280
{
281
/*
282
diff --git a/target/arm/tlb_helper.c b/target/arm/tlb_helper.c
283
new file mode 100644
69
new file mode 100644
284
index XXXXXXX..XXXXXXX
70
index XXXXXXX..XXXXXXX
285
--- /dev/null
71
--- /dev/null
286
+++ b/target/arm/tlb_helper.c
72
+++ b/include/hw/gpio/npcm7xx_gpio.h
287
@@ -XXX,XX +XXX,XX @@
73
@@ -XXX,XX +XXX,XX @@
288
+/*
74
+/*
289
+ * ARM TLB (Translation lookaside buffer) helpers.
75
+ * Nuvoton NPCM7xx General Purpose Input / Output (GPIO)
290
+ *
76
+ *
291
+ * This code is licensed under the GNU GPL v2 or later.
77
+ * Copyright 2020 Google LLC
292
+ *
78
+ *
293
+ * SPDX-License-Identifier: GPL-2.0-or-later
79
+ * This program is free software; you can redistribute it and/or
80
+ * modify it under the terms of the GNU General Public License
81
+ * version 2 as published by the Free Software Foundation.
82
+ *
83
+ * This program is distributed in the hope that it will be useful,
84
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
85
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
86
+ * GNU General Public License for more details.
294
+ */
87
+ */
88
+#ifndef NPCM7XX_GPIO_H
89
+#define NPCM7XX_GPIO_H
90
+
91
+#include "exec/memory.h"
92
+#include "hw/sysbus.h"
93
+
94
+/* Number of pins managed by each controller. */
95
+#define NPCM7XX_GPIO_NR_PINS (32)
96
+
97
+/*
98
+ * Number of registers in our device state structure. Don't change this without
99
+ * incrementing the version_id in the vmstate.
100
+ */
101
+#define NPCM7XX_GPIO_NR_REGS (0x80 / sizeof(uint32_t))
102
+
103
+typedef struct NPCM7xxGPIOState {
104
+ SysBusDevice parent;
105
+
106
+ /* Properties to be defined by the SoC */
107
+ uint32_t reset_pu;
108
+ uint32_t reset_pd;
109
+ uint32_t reset_osrc;
110
+ uint32_t reset_odsc;
111
+
112
+ MemoryRegion mmio;
113
+
114
+ qemu_irq irq;
115
+ qemu_irq output[NPCM7XX_GPIO_NR_PINS];
116
+
117
+ uint32_t pin_level;
118
+ uint32_t ext_level;
119
+ uint32_t ext_driven;
120
+
121
+ uint32_t regs[NPCM7XX_GPIO_NR_REGS];
122
+} NPCM7xxGPIOState;
123
+
124
+#define TYPE_NPCM7XX_GPIO "npcm7xx-gpio"
125
+#define NPCM7XX_GPIO(obj) \
126
+ OBJECT_CHECK(NPCM7xxGPIOState, (obj), TYPE_NPCM7XX_GPIO)
127
+
128
+#endif /* NPCM7XX_GPIO_H */
129
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
130
index XXXXXXX..XXXXXXX 100644
131
--- a/hw/arm/npcm7xx.c
132
+++ b/hw/arm/npcm7xx.c
133
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxInterrupt {
134
NPCM7XX_WDG2_IRQ, /* Timer Module 2 Watchdog */
135
NPCM7XX_EHCI_IRQ = 61,
136
NPCM7XX_OHCI_IRQ = 62,
137
+ NPCM7XX_GPIO0_IRQ = 116,
138
+ NPCM7XX_GPIO1_IRQ,
139
+ NPCM7XX_GPIO2_IRQ,
140
+ NPCM7XX_GPIO3_IRQ,
141
+ NPCM7XX_GPIO4_IRQ,
142
+ NPCM7XX_GPIO5_IRQ,
143
+ NPCM7XX_GPIO6_IRQ,
144
+ NPCM7XX_GPIO7_IRQ,
145
};
146
147
/* Total number of GIC interrupts, including internal Cortex-A9 interrupts. */
148
@@ -XXX,XX +XXX,XX @@ static const hwaddr npcm7xx_fiu3_flash_addr[] = {
149
0xb8000000, /* CS3 */
150
};
151
152
+static const struct {
153
+ hwaddr regs_addr;
154
+ uint32_t unconnected_pins;
155
+ uint32_t reset_pu;
156
+ uint32_t reset_pd;
157
+ uint32_t reset_osrc;
158
+ uint32_t reset_odsc;
159
+} npcm7xx_gpio[] = {
160
+ {
161
+ .regs_addr = 0xf0010000,
162
+ .reset_pu = 0xff03ffff,
163
+ .reset_pd = 0x00fc0000,
164
+ }, {
165
+ .regs_addr = 0xf0011000,
166
+ .unconnected_pins = 0x0000001e,
167
+ .reset_pu = 0xfefffe07,
168
+ .reset_pd = 0x010001e0,
169
+ }, {
170
+ .regs_addr = 0xf0012000,
171
+ .reset_pu = 0x780fffff,
172
+ .reset_pd = 0x07f00000,
173
+ .reset_odsc = 0x00700000,
174
+ }, {
175
+ .regs_addr = 0xf0013000,
176
+ .reset_pu = 0x00fc0000,
177
+ .reset_pd = 0xff000000,
178
+ }, {
179
+ .regs_addr = 0xf0014000,
180
+ .reset_pu = 0xffffffff,
181
+ }, {
182
+ .regs_addr = 0xf0015000,
183
+ .reset_pu = 0xbf83f801,
184
+ .reset_pd = 0x007c0000,
185
+ .reset_osrc = 0x000000f1,
186
+ .reset_odsc = 0x3f9f80f1,
187
+ }, {
188
+ .regs_addr = 0xf0016000,
189
+ .reset_pu = 0xfc00f801,
190
+ .reset_pd = 0x000007fe,
191
+ .reset_odsc = 0x00000800,
192
+ }, {
193
+ .regs_addr = 0xf0017000,
194
+ .unconnected_pins = 0xffffff00,
195
+ .reset_pu = 0x0000007f,
196
+ .reset_osrc = 0x0000007f,
197
+ .reset_odsc = 0x0000007f,
198
+ },
199
+};
200
+
201
static const struct {
202
const char *name;
203
hwaddr regs_addr;
204
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
205
object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
206
}
207
208
+ for (i = 0; i < ARRAY_SIZE(s->gpio); i++) {
209
+ object_initialize_child(obj, "gpio[*]", &s->gpio[i], TYPE_NPCM7XX_GPIO);
210
+ }
211
+
212
object_initialize_child(obj, "ehci", &s->ehci, TYPE_NPCM7XX_EHCI);
213
object_initialize_child(obj, "ohci", &s->ohci, TYPE_SYSBUS_OHCI);
214
215
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
216
sysbus_realize(SYS_BUS_DEVICE(&s->rng), &error_abort);
217
sysbus_mmio_map(SYS_BUS_DEVICE(&s->rng), 0, NPCM7XX_RNG_BA);
218
219
+ /* GPIO modules. Cannot fail. */
220
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_gpio) != ARRAY_SIZE(s->gpio));
221
+ for (i = 0; i < ARRAY_SIZE(s->gpio); i++) {
222
+ Object *obj = OBJECT(&s->gpio[i]);
223
+
224
+ object_property_set_uint(obj, "reset-pullup",
225
+ npcm7xx_gpio[i].reset_pu, &error_abort);
226
+ object_property_set_uint(obj, "reset-pulldown",
227
+ npcm7xx_gpio[i].reset_pd, &error_abort);
228
+ object_property_set_uint(obj, "reset-osrc",
229
+ npcm7xx_gpio[i].reset_osrc, &error_abort);
230
+ object_property_set_uint(obj, "reset-odsc",
231
+ npcm7xx_gpio[i].reset_odsc, &error_abort);
232
+ sysbus_realize(SYS_BUS_DEVICE(obj), &error_abort);
233
+ sysbus_mmio_map(SYS_BUS_DEVICE(obj), 0, npcm7xx_gpio[i].regs_addr);
234
+ sysbus_connect_irq(SYS_BUS_DEVICE(obj), 0,
235
+ npcm7xx_irq(s, NPCM7XX_GPIO0_IRQ + i));
236
+ }
237
+
238
/* USB Host */
239
object_property_set_bool(OBJECT(&s->ehci), "companion-enable", true,
240
&error_abort);
241
diff --git a/hw/gpio/npcm7xx_gpio.c b/hw/gpio/npcm7xx_gpio.c
242
new file mode 100644
243
index XXXXXXX..XXXXXXX
244
--- /dev/null
245
+++ b/hw/gpio/npcm7xx_gpio.c
246
@@ -XXX,XX +XXX,XX @@
247
+/*
248
+ * Nuvoton NPCM7xx General Purpose Input / Output (GPIO)
249
+ *
250
+ * Copyright 2020 Google LLC
251
+ *
252
+ * This program is free software; you can redistribute it and/or
253
+ * modify it under the terms of the GNU General Public License
254
+ * version 2 as published by the Free Software Foundation.
255
+ *
256
+ * This program is distributed in the hope that it will be useful,
257
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
258
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
259
+ * GNU General Public License for more details.
260
+ */
261
+
295
+#include "qemu/osdep.h"
262
+#include "qemu/osdep.h"
296
+#include "cpu.h"
263
+
297
+#include "internals.h"
264
+#include "hw/gpio/npcm7xx_gpio.h"
298
+#include "exec/exec-all.h"
265
+#include "hw/irq.h"
299
+
266
+#include "hw/qdev-properties.h"
300
+#if !defined(CONFIG_USER_ONLY)
267
+#include "migration/vmstate.h"
301
+
268
+#include "qapi/error.h"
302
+static inline uint32_t merge_syn_data_abort(uint32_t template_syn,
269
+#include "qemu/log.h"
303
+ unsigned int target_el,
270
+#include "qemu/module.h"
304
+ bool same_el, bool ea,
271
+#include "qemu/units.h"
305
+ bool s1ptw, bool is_write,
272
+#include "trace.h"
306
+ int fsc)
273
+
307
+{
274
+/* 32-bit register indices. */
308
+ uint32_t syn;
275
+enum NPCM7xxGPIORegister {
309
+
276
+ NPCM7XX_GPIO_TLOCK1,
277
+ NPCM7XX_GPIO_DIN,
278
+ NPCM7XX_GPIO_POL,
279
+ NPCM7XX_GPIO_DOUT,
280
+ NPCM7XX_GPIO_OE,
281
+ NPCM7XX_GPIO_OTYP,
282
+ NPCM7XX_GPIO_MP,
283
+ NPCM7XX_GPIO_PU,
284
+ NPCM7XX_GPIO_PD,
285
+ NPCM7XX_GPIO_DBNC,
286
+ NPCM7XX_GPIO_EVTYP,
287
+ NPCM7XX_GPIO_EVBE,
288
+ NPCM7XX_GPIO_OBL0,
289
+ NPCM7XX_GPIO_OBL1,
290
+ NPCM7XX_GPIO_OBL2,
291
+ NPCM7XX_GPIO_OBL3,
292
+ NPCM7XX_GPIO_EVEN,
293
+ NPCM7XX_GPIO_EVENS,
294
+ NPCM7XX_GPIO_EVENC,
295
+ NPCM7XX_GPIO_EVST,
296
+ NPCM7XX_GPIO_SPLCK,
297
+ NPCM7XX_GPIO_MPLCK,
298
+ NPCM7XX_GPIO_IEM,
299
+ NPCM7XX_GPIO_OSRC,
300
+ NPCM7XX_GPIO_ODSC,
301
+ NPCM7XX_GPIO_DOS = 0x68 / sizeof(uint32_t),
302
+ NPCM7XX_GPIO_DOC,
303
+ NPCM7XX_GPIO_OES,
304
+ NPCM7XX_GPIO_OEC,
305
+ NPCM7XX_GPIO_TLOCK2 = 0x7c / sizeof(uint32_t),
306
+ NPCM7XX_GPIO_REGS_END,
307
+};
308
+
309
+#define NPCM7XX_GPIO_REGS_SIZE (4 * KiB)
310
+
311
+#define NPCM7XX_GPIO_LOCK_MAGIC1 (0xc0defa73)
312
+#define NPCM7XX_GPIO_LOCK_MAGIC2 (0xc0de1248)
313
+
314
+static void npcm7xx_gpio_update_events(NPCM7xxGPIOState *s, uint32_t din_diff)
315
+{
316
+ uint32_t din_new = s->regs[NPCM7XX_GPIO_DIN];
317
+
318
+ /* Trigger on high level */
319
+ s->regs[NPCM7XX_GPIO_EVST] |= din_new & ~s->regs[NPCM7XX_GPIO_EVTYP];
320
+ /* Trigger on both edges */
321
+ s->regs[NPCM7XX_GPIO_EVST] |= (din_diff & s->regs[NPCM7XX_GPIO_EVTYP]
322
+ & s->regs[NPCM7XX_GPIO_EVBE]);
323
+ /* Trigger on rising edge */
324
+ s->regs[NPCM7XX_GPIO_EVST] |= (din_diff & din_new
325
+ & s->regs[NPCM7XX_GPIO_EVTYP]);
326
+
327
+ trace_npcm7xx_gpio_update_events(DEVICE(s)->canonical_path,
328
+ s->regs[NPCM7XX_GPIO_EVST],
329
+ s->regs[NPCM7XX_GPIO_EVEN]);
330
+ qemu_set_irq(s->irq, !!(s->regs[NPCM7XX_GPIO_EVST]
331
+ & s->regs[NPCM7XX_GPIO_EVEN]));
332
+}
333
+
334
+static void npcm7xx_gpio_update_pins(NPCM7xxGPIOState *s, uint32_t diff)
335
+{
336
+ uint32_t drive_en;
337
+ uint32_t drive_lvl;
338
+ uint32_t not_driven;
339
+ uint32_t undefined;
340
+ uint32_t pin_diff;
341
+ uint32_t din_old;
342
+
343
+ /* Calculate level of each pin driven by GPIO controller. */
344
+ drive_lvl = s->regs[NPCM7XX_GPIO_DOUT] ^ s->regs[NPCM7XX_GPIO_POL];
345
+ /* If OTYP=1, only drive low (open drain) */
346
+ drive_en = s->regs[NPCM7XX_GPIO_OE] & ~(s->regs[NPCM7XX_GPIO_OTYP]
347
+ & drive_lvl);
310
+ /*
348
+ /*
311
+ * ISV is only set for data aborts routed to EL2 and
349
+ * If a pin is driven to opposite levels by the GPIO controller and the
312
+ * never for stage-1 page table walks faulting on stage 2.
350
+ * external driver, the result is undefined.
313
+ *
314
+ * Furthermore, ISV is only set for certain kinds of load/stores.
315
+ * If the template syndrome does not have ISV set, we should leave
316
+ * it cleared.
317
+ *
318
+ * See ARMv8 specs, D7-1974:
319
+ * ISS encoding for an exception from a Data Abort, the
320
+ * ISV field.
321
+ */
351
+ */
322
+ if (!(template_syn & ARM_EL_ISV) || target_el != 2 || s1ptw) {
352
+ undefined = drive_en & s->ext_driven & (drive_lvl ^ s->ext_level);
323
+ syn = syn_data_abort_no_iss(same_el,
353
+ if (undefined) {
324
+ ea, 0, s1ptw, is_write, fsc);
354
+ qemu_log_mask(LOG_GUEST_ERROR,
325
+ } else {
355
+ "%s: pins have multiple drivers: 0x%" PRIx32 "\n",
326
+ /*
356
+ DEVICE(s)->canonical_path, undefined);
327
+ * Fields: IL, ISV, SAS, SSE, SRT, SF and AR come from the template
328
+ * syndrome created at translation time.
329
+ * Now we create the runtime syndrome with the remaining fields.
330
+ */
331
+ syn = syn_data_abort_with_iss(same_el,
332
+ 0, 0, 0, 0, 0,
333
+ ea, 0, s1ptw, is_write, fsc,
334
+ false);
335
+ /* Merge the runtime syndrome with the template syndrome. */
336
+ syn |= template_syn;
337
+ }
357
+ }
338
+ return syn;
358
+
339
+}
359
+ not_driven = ~(drive_en | s->ext_driven);
340
+
360
+ pin_diff = s->pin_level;
341
+static void QEMU_NORETURN arm_deliver_fault(ARMCPU *cpu, vaddr addr,
361
+
342
+ MMUAccessType access_type,
362
+ /* Set pins to externally driven level. */
343
+ int mmu_idx, ARMMMUFaultInfo *fi)
363
+ s->pin_level = s->ext_level & s->ext_driven;
344
+{
364
+ /* Set internally driven pins, ignoring any conflicts. */
345
+ CPUARMState *env = &cpu->env;
365
+ s->pin_level |= drive_lvl & drive_en;
346
+ int target_el;
366
+ /* Pull up undriven pins with internal pull-up enabled. */
347
+ bool same_el;
367
+ s->pin_level |= not_driven & s->regs[NPCM7XX_GPIO_PU];
348
+ uint32_t syn, exc, fsr, fsc;
368
+ /* Pins not driven, pulled up or pulled down are undefined */
349
+ ARMMMUIdx arm_mmu_idx = core_to_arm_mmu_idx(env, mmu_idx);
369
+ undefined |= not_driven & ~(s->regs[NPCM7XX_GPIO_PU]
350
+
370
+ | s->regs[NPCM7XX_GPIO_PD]);
351
+ target_el = exception_target_el(env);
371
+
352
+ if (fi->stage2) {
372
+ /* If any pins changed state, update the outgoing GPIOs. */
353
+ target_el = 2;
373
+ pin_diff ^= s->pin_level;
354
+ env->cp15.hpfar_el2 = extract64(fi->s2addr, 12, 47) << 4;
374
+ pin_diff |= undefined & diff;
375
+ if (pin_diff) {
376
+ int i;
377
+
378
+ for (i = 0; i < NPCM7XX_GPIO_NR_PINS; i++) {
379
+ uint32_t mask = BIT(i);
380
+ if (pin_diff & mask) {
381
+ int level = (undefined & mask) ? -1 : !!(s->pin_level & mask);
382
+ trace_npcm7xx_gpio_set_output(DEVICE(s)->canonical_path,
383
+ i, level);
384
+ qemu_set_irq(s->output[i], level);
385
+ }
386
+ }
355
+ }
387
+ }
356
+ same_el = (arm_current_el(env) == target_el);
388
+
357
+
389
+ /* Calculate new value of DIN after masking and polarity setting. */
358
+ if (target_el == 2 || arm_el_is_aa64(env, target_el) ||
390
+ din_old = s->regs[NPCM7XX_GPIO_DIN];
359
+ arm_s1_regime_using_lpae_format(env, arm_mmu_idx)) {
391
+ s->regs[NPCM7XX_GPIO_DIN] = ((s->pin_level & s->regs[NPCM7XX_GPIO_IEM])
360
+ /*
392
+ ^ s->regs[NPCM7XX_GPIO_POL]);
361
+ * LPAE format fault status register : bottom 6 bits are
393
+
362
+ * status code in the same form as needed for syndrome
394
+ /* See if any new events triggered because of all this. */
363
+ */
395
+ npcm7xx_gpio_update_events(s, din_old ^ s->regs[NPCM7XX_GPIO_DIN]);
364
+ fsr = arm_fi_to_lfsc(fi);
396
+}
365
+ fsc = extract32(fsr, 0, 6);
397
+
366
+ } else {
398
+static bool npcm7xx_gpio_is_locked(NPCM7xxGPIOState *s)
367
+ fsr = arm_fi_to_sfsc(fi);
399
+{
368
+ /*
400
+ return s->regs[NPCM7XX_GPIO_TLOCK1] == 1;
369
+ * Short format FSR : this fault will never actually be reported
401
+}
370
+ * to an EL that uses a syndrome register. Use a (currently)
402
+
371
+ * reserved FSR code in case the constructed syndrome does leak
403
+static uint64_t npcm7xx_gpio_regs_read(void *opaque, hwaddr addr,
372
+ * into the guest somehow.
404
+ unsigned int size)
373
+ */
405
+{
374
+ fsc = 0x3f;
406
+ hwaddr reg = addr / sizeof(uint32_t);
407
+ NPCM7xxGPIOState *s = opaque;
408
+ uint64_t value = 0;
409
+
410
+ switch (reg) {
411
+ case NPCM7XX_GPIO_TLOCK1 ... NPCM7XX_GPIO_EVEN:
412
+ case NPCM7XX_GPIO_EVST ... NPCM7XX_GPIO_ODSC:
413
+ value = s->regs[reg];
414
+ break;
415
+
416
+ case NPCM7XX_GPIO_EVENS ... NPCM7XX_GPIO_EVENC:
417
+ case NPCM7XX_GPIO_DOS ... NPCM7XX_GPIO_TLOCK2:
418
+ qemu_log_mask(LOG_GUEST_ERROR,
419
+ "%s: read from write-only register 0x%" HWADDR_PRIx "\n",
420
+ DEVICE(s)->canonical_path, addr);
421
+ break;
422
+
423
+ default:
424
+ qemu_log_mask(LOG_GUEST_ERROR,
425
+ "%s: read from invalid offset 0x%" HWADDR_PRIx "\n",
426
+ DEVICE(s)->canonical_path, addr);
427
+ break;
375
+ }
428
+ }
376
+
429
+
377
+ if (access_type == MMU_INST_FETCH) {
430
+ trace_npcm7xx_gpio_read(DEVICE(s)->canonical_path, addr, value);
378
+ syn = syn_insn_abort(same_el, fi->ea, fi->s1ptw, fsc);
431
+
379
+ exc = EXCP_PREFETCH_ABORT;
432
+ return value;
380
+ } else {
433
+}
381
+ syn = merge_syn_data_abort(env->exception.syndrome, target_el,
434
+
382
+ same_el, fi->ea, fi->s1ptw,
435
+static void npcm7xx_gpio_regs_write(void *opaque, hwaddr addr, uint64_t v,
383
+ access_type == MMU_DATA_STORE,
436
+ unsigned int size)
384
+ fsc);
437
+{
385
+ if (access_type == MMU_DATA_STORE
438
+ hwaddr reg = addr / sizeof(uint32_t);
386
+ && arm_feature(env, ARM_FEATURE_V6)) {
439
+ NPCM7xxGPIOState *s = opaque;
387
+ fsr |= (1 << 11);
440
+ uint32_t value = v;
441
+ uint32_t diff;
442
+
443
+ trace_npcm7xx_gpio_write(DEVICE(s)->canonical_path, addr, v);
444
+
445
+ if (npcm7xx_gpio_is_locked(s)) {
446
+ switch (reg) {
447
+ case NPCM7XX_GPIO_TLOCK1:
448
+ if (s->regs[NPCM7XX_GPIO_TLOCK2] == NPCM7XX_GPIO_LOCK_MAGIC2 &&
449
+ value == NPCM7XX_GPIO_LOCK_MAGIC1) {
450
+ s->regs[NPCM7XX_GPIO_TLOCK1] = 0;
451
+ s->regs[NPCM7XX_GPIO_TLOCK2] = 0;
452
+ }
453
+ break;
454
+
455
+ case NPCM7XX_GPIO_TLOCK2:
456
+ s->regs[reg] = value;
457
+ break;
458
+
459
+ default:
460
+ qemu_log_mask(LOG_GUEST_ERROR,
461
+ "%s: write to locked register @ 0x%" HWADDR_PRIx "\n",
462
+ DEVICE(s)->canonical_path, addr);
463
+ break;
388
+ }
464
+ }
389
+ exc = EXCP_DATA_ABORT;
465
+
466
+ return;
390
+ }
467
+ }
391
+
468
+
392
+ env->exception.vaddress = addr;
469
+ diff = s->regs[reg] ^ value;
393
+ env->exception.fsr = fsr;
470
+
394
+ raise_exception(env, exc, syn, target_el);
471
+ switch (reg) {
395
+}
472
+ case NPCM7XX_GPIO_TLOCK1:
396
+
473
+ case NPCM7XX_GPIO_TLOCK2:
397
+/* Raise a data fault alignment exception for the specified virtual address */
474
+ s->regs[NPCM7XX_GPIO_TLOCK1] = 1;
398
+void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
475
+ s->regs[NPCM7XX_GPIO_TLOCK2] = 0;
399
+ MMUAccessType access_type,
476
+ break;
400
+ int mmu_idx, uintptr_t retaddr)
477
+
401
+{
478
+ case NPCM7XX_GPIO_DIN:
402
+ ARMCPU *cpu = ARM_CPU(cs);
479
+ qemu_log_mask(LOG_GUEST_ERROR,
403
+ ARMMMUFaultInfo fi = {};
480
+ "%s: write to read-only register @ 0x%" HWADDR_PRIx "\n",
404
+
481
+ DEVICE(s)->canonical_path, addr);
405
+ /* now we have a real cpu fault */
482
+ break;
406
+ cpu_restore_state(cs, retaddr, true);
483
+
407
+
484
+ case NPCM7XX_GPIO_POL:
408
+ fi.type = ARMFault_Alignment;
485
+ case NPCM7XX_GPIO_DOUT:
409
+ arm_deliver_fault(cpu, vaddr, access_type, mmu_idx, &fi);
486
+ case NPCM7XX_GPIO_OE:
410
+}
487
+ case NPCM7XX_GPIO_OTYP:
411
+
488
+ case NPCM7XX_GPIO_PU:
489
+ case NPCM7XX_GPIO_PD:
490
+ case NPCM7XX_GPIO_IEM:
491
+ s->regs[reg] = value;
492
+ npcm7xx_gpio_update_pins(s, diff);
493
+ break;
494
+
495
+ case NPCM7XX_GPIO_DOS:
496
+ s->regs[NPCM7XX_GPIO_DOUT] |= value;
497
+ npcm7xx_gpio_update_pins(s, value);
498
+ break;
499
+ case NPCM7XX_GPIO_DOC:
500
+ s->regs[NPCM7XX_GPIO_DOUT] &= ~value;
501
+ npcm7xx_gpio_update_pins(s, value);
502
+ break;
503
+ case NPCM7XX_GPIO_OES:
504
+ s->regs[NPCM7XX_GPIO_OE] |= value;
505
+ npcm7xx_gpio_update_pins(s, value);
506
+ break;
507
+ case NPCM7XX_GPIO_OEC:
508
+ s->regs[NPCM7XX_GPIO_OE] &= ~value;
509
+ npcm7xx_gpio_update_pins(s, value);
510
+ break;
511
+
512
+ case NPCM7XX_GPIO_EVTYP:
513
+ case NPCM7XX_GPIO_EVBE:
514
+ case NPCM7XX_GPIO_EVEN:
515
+ s->regs[reg] = value;
516
+ npcm7xx_gpio_update_events(s, 0);
517
+ break;
518
+
519
+ case NPCM7XX_GPIO_EVENS:
520
+ s->regs[NPCM7XX_GPIO_EVEN] |= value;
521
+ npcm7xx_gpio_update_events(s, 0);
522
+ break;
523
+ case NPCM7XX_GPIO_EVENC:
524
+ s->regs[NPCM7XX_GPIO_EVEN] &= ~value;
525
+ npcm7xx_gpio_update_events(s, 0);
526
+ break;
527
+
528
+ case NPCM7XX_GPIO_EVST:
529
+ s->regs[reg] &= ~value;
530
+ npcm7xx_gpio_update_events(s, 0);
531
+ break;
532
+
533
+ case NPCM7XX_GPIO_MP:
534
+ case NPCM7XX_GPIO_DBNC:
535
+ case NPCM7XX_GPIO_OSRC:
536
+ case NPCM7XX_GPIO_ODSC:
537
+ /* Nothing to do; just store the value. */
538
+ s->regs[reg] = value;
539
+ break;
540
+
541
+ case NPCM7XX_GPIO_OBL0:
542
+ case NPCM7XX_GPIO_OBL1:
543
+ case NPCM7XX_GPIO_OBL2:
544
+ case NPCM7XX_GPIO_OBL3:
545
+ s->regs[reg] = value;
546
+ qemu_log_mask(LOG_UNIMP, "%s: Blinking is not implemented\n",
547
+ __func__);
548
+ break;
549
+
550
+ case NPCM7XX_GPIO_SPLCK:
551
+ case NPCM7XX_GPIO_MPLCK:
552
+ qemu_log_mask(LOG_UNIMP, "%s: Per-pin lock is not implemented\n",
553
+ __func__);
554
+ break;
555
+
556
+ default:
557
+ qemu_log_mask(LOG_GUEST_ERROR,
558
+ "%s: write to invalid offset 0x%" HWADDR_PRIx "\n",
559
+ DEVICE(s)->canonical_path, addr);
560
+ break;
561
+ }
562
+}
563
+
564
+static const MemoryRegionOps npcm7xx_gpio_regs_ops = {
565
+ .read = npcm7xx_gpio_regs_read,
566
+ .write = npcm7xx_gpio_regs_write,
567
+ .endianness = DEVICE_NATIVE_ENDIAN,
568
+ .valid = {
569
+ .min_access_size = 4,
570
+ .max_access_size = 4,
571
+ .unaligned = false,
572
+ },
573
+};
574
+
575
+static void npcm7xx_gpio_set_input(void *opaque, int line, int level)
576
+{
577
+ NPCM7xxGPIOState *s = opaque;
578
+
579
+ trace_npcm7xx_gpio_set_input(DEVICE(s)->canonical_path, line, level);
580
+
581
+ g_assert(line >= 0 && line < NPCM7XX_GPIO_NR_PINS);
582
+
583
+ s->ext_driven = deposit32(s->ext_driven, line, 1, level >= 0);
584
+ s->ext_level = deposit32(s->ext_level, line, 1, level > 0);
585
+
586
+ npcm7xx_gpio_update_pins(s, BIT(line));
587
+}
588
+
589
+static void npcm7xx_gpio_enter_reset(Object *obj, ResetType type)
590
+{
591
+ NPCM7xxGPIOState *s = NPCM7XX_GPIO(obj);
592
+
593
+ memset(s->regs, 0, sizeof(s->regs));
594
+
595
+ s->regs[NPCM7XX_GPIO_PU] = s->reset_pu;
596
+ s->regs[NPCM7XX_GPIO_PD] = s->reset_pd;
597
+ s->regs[NPCM7XX_GPIO_OSRC] = s->reset_osrc;
598
+ s->regs[NPCM7XX_GPIO_ODSC] = s->reset_odsc;
599
+}
600
+
601
+static void npcm7xx_gpio_hold_reset(Object *obj)
602
+{
603
+ NPCM7xxGPIOState *s = NPCM7XX_GPIO(obj);
604
+
605
+ npcm7xx_gpio_update_pins(s, -1);
606
+}
607
+
608
+static void npcm7xx_gpio_init(Object *obj)
609
+{
610
+ NPCM7xxGPIOState *s = NPCM7XX_GPIO(obj);
611
+ DeviceState *dev = DEVICE(obj);
612
+
613
+ memory_region_init_io(&s->mmio, obj, &npcm7xx_gpio_regs_ops, s,
614
+ "regs", NPCM7XX_GPIO_REGS_SIZE);
615
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
616
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
617
+
618
+ qdev_init_gpio_in(dev, npcm7xx_gpio_set_input, NPCM7XX_GPIO_NR_PINS);
619
+ qdev_init_gpio_out(dev, s->output, NPCM7XX_GPIO_NR_PINS);
620
+}
621
+
622
+static const VMStateDescription vmstate_npcm7xx_gpio = {
623
+ .name = "npcm7xx-gpio",
624
+ .version_id = 0,
625
+ .minimum_version_id = 0,
626
+ .fields = (VMStateField[]) {
627
+ VMSTATE_UINT32(pin_level, NPCM7xxGPIOState),
628
+ VMSTATE_UINT32(ext_level, NPCM7xxGPIOState),
629
+ VMSTATE_UINT32(ext_driven, NPCM7xxGPIOState),
630
+ VMSTATE_UINT32_ARRAY(regs, NPCM7xxGPIOState, NPCM7XX_GPIO_NR_REGS),
631
+ VMSTATE_END_OF_LIST(),
632
+ },
633
+};
634
+
635
+static Property npcm7xx_gpio_properties[] = {
636
+ /* Bit n set => pin n has pullup enabled by default. */
637
+ DEFINE_PROP_UINT32("reset-pullup", NPCM7xxGPIOState, reset_pu, 0),
638
+ /* Bit n set => pin n has pulldown enabled by default. */
639
+ DEFINE_PROP_UINT32("reset-pulldown", NPCM7xxGPIOState, reset_pd, 0),
640
+ /* Bit n set => pin n has high slew rate by default. */
641
+ DEFINE_PROP_UINT32("reset-osrc", NPCM7xxGPIOState, reset_osrc, 0),
642
+ /* Bit n set => pin n has high drive strength by default. */
643
+ DEFINE_PROP_UINT32("reset-odsc", NPCM7xxGPIOState, reset_odsc, 0),
644
+ DEFINE_PROP_END_OF_LIST(),
645
+};
646
+
647
+static void npcm7xx_gpio_class_init(ObjectClass *klass, void *data)
648
+{
649
+ ResettableClass *reset = RESETTABLE_CLASS(klass);
650
+ DeviceClass *dc = DEVICE_CLASS(klass);
651
+
652
+ QEMU_BUILD_BUG_ON(NPCM7XX_GPIO_REGS_END > NPCM7XX_GPIO_NR_REGS);
653
+
654
+ dc->desc = "NPCM7xx GPIO Controller";
655
+ dc->vmsd = &vmstate_npcm7xx_gpio;
656
+ reset->phases.enter = npcm7xx_gpio_enter_reset;
657
+ reset->phases.hold = npcm7xx_gpio_hold_reset;
658
+ device_class_set_props(dc, npcm7xx_gpio_properties);
659
+}
660
+
661
+static const TypeInfo npcm7xx_gpio_types[] = {
662
+ {
663
+ .name = TYPE_NPCM7XX_GPIO,
664
+ .parent = TYPE_SYS_BUS_DEVICE,
665
+ .instance_size = sizeof(NPCM7xxGPIOState),
666
+ .class_init = npcm7xx_gpio_class_init,
667
+ .instance_init = npcm7xx_gpio_init,
668
+ },
669
+};
670
+DEFINE_TYPES(npcm7xx_gpio_types);
671
diff --git a/tests/qtest/npcm7xx_gpio-test.c b/tests/qtest/npcm7xx_gpio-test.c
672
new file mode 100644
673
index XXXXXXX..XXXXXXX
674
--- /dev/null
675
+++ b/tests/qtest/npcm7xx_gpio-test.c
676
@@ -XXX,XX +XXX,XX @@
412
+/*
677
+/*
413
+ * arm_cpu_do_transaction_failed: handle a memory system error response
678
+ * QTest testcase for the Nuvoton NPCM7xx GPIO modules.
414
+ * (eg "no device/memory present at address") by raising an external abort
679
+ *
415
+ * exception
680
+ * Copyright 2020 Google LLC
681
+ *
682
+ * This program is free software; you can redistribute it and/or modify it
683
+ * under the terms of the GNU General Public License as published by the
684
+ * Free Software Foundation; either version 2 of the License, or
685
+ * (at your option) any later version.
686
+ *
687
+ * This program is distributed in the hope that it will be useful, but WITHOUT
688
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
689
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
690
+ * for more details.
416
+ */
691
+ */
417
+void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
692
+
418
+ vaddr addr, unsigned size,
693
+#include "qemu/osdep.h"
419
+ MMUAccessType access_type,
694
+#include "libqtest-single.h"
420
+ int mmu_idx, MemTxAttrs attrs,
695
+
421
+ MemTxResult response, uintptr_t retaddr)
696
+#define NR_GPIO_DEVICES (8)
422
+{
697
+#define GPIO(x) (0xf0010000 + (x) * 0x1000)
423
+ ARMCPU *cpu = ARM_CPU(cs);
698
+#define GPIO_IRQ(x) (116 + (x))
424
+ ARMMMUFaultInfo fi = {};
699
+
425
+
700
+/* GPIO registers */
426
+ /* now we have a real cpu fault */
701
+#define GP_N_TLOCK1 0x00
427
+ cpu_restore_state(cs, retaddr, true);
702
+#define GP_N_DIN 0x04 /* Data IN */
428
+
703
+#define GP_N_POL 0x08 /* Polarity */
429
+ fi.ea = arm_extabort_type(response);
704
+#define GP_N_DOUT 0x0c /* Data OUT */
430
+ fi.type = ARMFault_SyncExternal;
705
+#define GP_N_OE 0x10 /* Output Enable */
431
+ arm_deliver_fault(cpu, addr, access_type, mmu_idx, &fi);
706
+#define GP_N_OTYP 0x14
432
+}
707
+#define GP_N_MP 0x18
433
+
708
+#define GP_N_PU 0x1c /* Pull-up */
434
+#endif /* !defined(CONFIG_USER_ONLY) */
709
+#define GP_N_PD 0x20 /* Pull-down */
435
+
710
+#define GP_N_DBNC 0x24 /* Debounce */
436
+bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
711
+#define GP_N_EVTYP 0x28 /* Event Type */
437
+ MMUAccessType access_type, int mmu_idx,
712
+#define GP_N_EVBE 0x2c /* Event Both Edge */
438
+ bool probe, uintptr_t retaddr)
713
+#define GP_N_OBL0 0x30
439
+{
714
+#define GP_N_OBL1 0x34
440
+ ARMCPU *cpu = ARM_CPU(cs);
715
+#define GP_N_OBL2 0x38
441
+
716
+#define GP_N_OBL3 0x3c
442
+#ifdef CONFIG_USER_ONLY
717
+#define GP_N_EVEN 0x40 /* Event Enable */
443
+ cpu->env.exception.vaddress = address;
718
+#define GP_N_EVENS 0x44 /* Event Set (enable) */
444
+ if (access_type == MMU_INST_FETCH) {
719
+#define GP_N_EVENC 0x48 /* Event Clear (disable) */
445
+ cs->exception_index = EXCP_PREFETCH_ABORT;
720
+#define GP_N_EVST 0x4c /* Event Status */
446
+ } else {
721
+#define GP_N_SPLCK 0x50
447
+ cs->exception_index = EXCP_DATA_ABORT;
722
+#define GP_N_MPLCK 0x54
723
+#define GP_N_IEM 0x58 /* Input Enable */
724
+#define GP_N_OSRC 0x5c
725
+#define GP_N_ODSC 0x60
726
+#define GP_N_DOS 0x68 /* Data OUT Set */
727
+#define GP_N_DOC 0x6c /* Data OUT Clear */
728
+#define GP_N_OES 0x70 /* Output Enable Set */
729
+#define GP_N_OEC 0x74 /* Output Enable Clear */
730
+#define GP_N_TLOCK2 0x7c
731
+
732
+static void gpio_unlock(int n)
733
+{
734
+ if (readl(GPIO(n) + GP_N_TLOCK1) != 0) {
735
+ writel(GPIO(n) + GP_N_TLOCK2, 0xc0de1248);
736
+ writel(GPIO(n) + GP_N_TLOCK1, 0xc0defa73);
448
+ }
737
+ }
449
+ cpu_loop_exit_restore(cs, retaddr);
738
+}
450
+#else
739
+
451
+ hwaddr phys_addr;
740
+/* Restore the GPIO controller to a sensible default state. */
452
+ target_ulong page_size;
741
+static void gpio_reset(int n)
453
+ int prot, ret;
742
+{
454
+ MemTxAttrs attrs = {};
743
+ gpio_unlock(0);
455
+ ARMMMUFaultInfo fi = {};
744
+
745
+ writel(GPIO(n) + GP_N_EVEN, 0x00000000);
746
+ writel(GPIO(n) + GP_N_EVST, 0xffffffff);
747
+ writel(GPIO(n) + GP_N_POL, 0x00000000);
748
+ writel(GPIO(n) + GP_N_DOUT, 0x00000000);
749
+ writel(GPIO(n) + GP_N_OE, 0x00000000);
750
+ writel(GPIO(n) + GP_N_OTYP, 0x00000000);
751
+ writel(GPIO(n) + GP_N_PU, 0xffffffff);
752
+ writel(GPIO(n) + GP_N_PD, 0x00000000);
753
+ writel(GPIO(n) + GP_N_IEM, 0xffffffff);
754
+}
755
+
756
+static void test_dout_to_din(void)
757
+{
758
+ gpio_reset(0);
759
+
760
+ /* When output is enabled, DOUT should be reflected on DIN. */
761
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
762
+ /* PU and PD shouldn't have any impact on DIN. */
763
+ writel(GPIO(0) + GP_N_PU, 0xffff0000);
764
+ writel(GPIO(0) + GP_N_PD, 0x0000ffff);
765
+ writel(GPIO(0) + GP_N_DOUT, 0x12345678);
766
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0x12345678);
767
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x12345678);
768
+}
769
+
770
+static void test_pullup_pulldown(void)
771
+{
772
+ gpio_reset(0);
456
+
773
+
457
+ /*
774
+ /*
458
+ * Walk the page table and (if the mapping exists) add the page
775
+ * When output is disabled, and PD is the inverse of PU, PU should be
459
+ * to the TLB. On success, return true. Otherwise, if probing,
776
+ * reflected on DIN. If PD is not the inverse of PU, the state of DIN is
460
+ * return false. Otherwise populate fsr with ARM DFSR/IFSR fault
777
+ * undefined, so we don't test that.
461
+ * register format, and signal the fault.
462
+ */
778
+ */
463
+ ret = get_phys_addr(&cpu->env, address, access_type,
779
+ writel(GPIO(0) + GP_N_OE, 0x00000000);
464
+ core_to_arm_mmu_idx(&cpu->env, mmu_idx),
780
+ /* DOUT shouldn't have any impact on DIN. */
465
+ &phys_addr, &attrs, &prot, &page_size, &fi, NULL);
781
+ writel(GPIO(0) + GP_N_DOUT, 0xffff0000);
466
+ if (likely(!ret)) {
782
+ writel(GPIO(0) + GP_N_PU, 0x23456789);
467
+ /*
783
+ writel(GPIO(0) + GP_N_PD, ~0x23456789U);
468
+ * Map a single [sub]page. Regions smaller than our declared
784
+ g_assert_cmphex(readl(GPIO(0) + GP_N_PU), ==, 0x23456789);
469
+ * target page size are handled specially, so for those we
785
+ g_assert_cmphex(readl(GPIO(0) + GP_N_PD), ==, ~0x23456789U);
470
+ * pass in the exact addresses.
786
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x23456789);
471
+ */
787
+}
472
+ if (page_size >= TARGET_PAGE_SIZE) {
788
+
473
+ phys_addr &= TARGET_PAGE_MASK;
789
+static void test_output_enable(void)
474
+ address &= TARGET_PAGE_MASK;
790
+{
475
+ }
791
+ gpio_reset(0);
476
+ tlb_set_page_with_attrs(cs, address, phys_addr, attrs,
792
+
477
+ prot, mmu_idx, page_size);
793
+ /*
478
+ return true;
794
+ * With all pins weakly pulled down, and DOUT all-ones, OE should be
479
+ } else if (probe) {
795
+ * reflected on DIN.
480
+ return false;
796
+ */
481
+ } else {
797
+ writel(GPIO(0) + GP_N_DOUT, 0xffffffff);
482
+ /* now we have a real cpu fault */
798
+ writel(GPIO(0) + GP_N_PU, 0x00000000);
483
+ cpu_restore_state(cs, retaddr, true);
799
+ writel(GPIO(0) + GP_N_PD, 0xffffffff);
484
+ arm_deliver_fault(cpu, address, access_type, mmu_idx, &fi);
800
+ writel(GPIO(0) + GP_N_OE, 0x3456789a);
801
+ g_assert_cmphex(readl(GPIO(0) + GP_N_OE), ==, 0x3456789a);
802
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x3456789a);
803
+
804
+ writel(GPIO(0) + GP_N_OEC, 0x00030002);
805
+ g_assert_cmphex(readl(GPIO(0) + GP_N_OE), ==, 0x34547898);
806
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x34547898);
807
+
808
+ writel(GPIO(0) + GP_N_OES, 0x0000f001);
809
+ g_assert_cmphex(readl(GPIO(0) + GP_N_OE), ==, 0x3454f899);
810
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x3454f899);
811
+}
812
+
813
+static void test_open_drain(void)
814
+{
815
+ gpio_reset(0);
816
+
817
+ /*
818
+ * Upper half of DOUT drives a 1 only if the corresponding bit in OTYP is
819
+ * not set. If OTYP is set, DIN is determined by PU/PD. Lower half of
820
+ * DOUT always drives a 0 regardless of OTYP; PU/PD have no effect. When
821
+ * OE is 0, output is determined by PU/PD; OTYP has no effect.
822
+ */
823
+ writel(GPIO(0) + GP_N_OTYP, 0x456789ab);
824
+ writel(GPIO(0) + GP_N_OE, 0xf0f0f0f0);
825
+ writel(GPIO(0) + GP_N_DOUT, 0xffff0000);
826
+ writel(GPIO(0) + GP_N_PU, 0xff00ff00);
827
+ writel(GPIO(0) + GP_N_PD, 0x00ff00ff);
828
+ g_assert_cmphex(readl(GPIO(0) + GP_N_OTYP), ==, 0x456789ab);
829
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0xff900f00);
830
+}
831
+
832
+static void test_polarity(void)
833
+{
834
+ gpio_reset(0);
835
+
836
+ /*
837
+ * In push-pull mode, DIN should reflect DOUT because the signal is
838
+ * inverted in both directions.
839
+ */
840
+ writel(GPIO(0) + GP_N_OTYP, 0x00000000);
841
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
842
+ writel(GPIO(0) + GP_N_DOUT, 0x56789abc);
843
+ writel(GPIO(0) + GP_N_POL, 0x6789abcd);
844
+ g_assert_cmphex(readl(GPIO(0) + GP_N_POL), ==, 0x6789abcd);
845
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x56789abc);
846
+
847
+ /*
848
+ * When turning off the drivers, DIN should reflect the inverse of the
849
+ * pulled-up lines.
850
+ */
851
+ writel(GPIO(0) + GP_N_OE, 0x00000000);
852
+ writel(GPIO(0) + GP_N_POL, 0xffffffff);
853
+ writel(GPIO(0) + GP_N_PU, 0x789abcde);
854
+ writel(GPIO(0) + GP_N_PD, ~0x789abcdeU);
855
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, ~0x789abcdeU);
856
+
857
+ /*
858
+ * In open-drain mode, DOUT=1 will appear to drive the pin high (since DIN
859
+ * is inverted), while DOUT=0 will leave the pin floating.
860
+ */
861
+ writel(GPIO(0) + GP_N_OTYP, 0xffffffff);
862
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
863
+ writel(GPIO(0) + GP_N_PU, 0xffff0000);
864
+ writel(GPIO(0) + GP_N_PD, 0x0000ffff);
865
+ writel(GPIO(0) + GP_N_DOUT, 0xff00ff00);
866
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0xff00ffff);
867
+}
868
+
869
+static void test_input_mask(void)
870
+{
871
+ gpio_reset(0);
872
+
873
+ /* IEM=0 forces the input to zero before polarity inversion. */
874
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
875
+ writel(GPIO(0) + GP_N_DOUT, 0xff00ff00);
876
+ writel(GPIO(0) + GP_N_POL, 0xffff0000);
877
+ writel(GPIO(0) + GP_N_IEM, 0x87654321);
878
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0xff9a4300);
879
+}
880
+
881
+static void test_temp_lock(void)
882
+{
883
+ gpio_reset(0);
884
+
885
+ writel(GPIO(0) + GP_N_DOUT, 0x98765432);
886
+
887
+ /* Make sure we're unlocked initially. */
888
+ g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 0);
889
+ /* Writing any value to TLOCK1 will lock. */
890
+ writel(GPIO(0) + GP_N_TLOCK1, 0);
891
+ g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 1);
892
+ writel(GPIO(0) + GP_N_DOUT, 0xa9876543);
893
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0x98765432);
894
+ /* Now, try to unlock. */
895
+ gpio_unlock(0);
896
+ g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 0);
897
+ writel(GPIO(0) + GP_N_DOUT, 0xa9876543);
898
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0xa9876543);
899
+
900
+ /* Try it again, but write TLOCK2 to lock. */
901
+ writel(GPIO(0) + GP_N_TLOCK2, 0);
902
+ g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 1);
903
+ writel(GPIO(0) + GP_N_DOUT, 0x98765432);
904
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0xa9876543);
905
+ /* Now, try to unlock. */
906
+ gpio_unlock(0);
907
+ g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 0);
908
+ writel(GPIO(0) + GP_N_DOUT, 0x98765432);
909
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0x98765432);
910
+}
911
+
912
+static void test_events_level(void)
913
+{
914
+ gpio_reset(0);
915
+
916
+ writel(GPIO(0) + GP_N_EVTYP, 0x00000000);
917
+ writel(GPIO(0) + GP_N_DOUT, 0xba987654);
918
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
919
+ writel(GPIO(0) + GP_N_EVST, 0xffffffff);
920
+
921
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0xba987654);
922
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
923
+ writel(GPIO(0) + GP_N_DOUT, 0x00000000);
924
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0xba987654);
925
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
926
+ writel(GPIO(0) + GP_N_EVST, 0x00007654);
927
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0xba980000);
928
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
929
+ writel(GPIO(0) + GP_N_EVST, 0xba980000);
930
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
931
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
932
+}
933
+
934
+static void test_events_rising_edge(void)
935
+{
936
+ gpio_reset(0);
937
+
938
+ writel(GPIO(0) + GP_N_EVTYP, 0xffffffff);
939
+ writel(GPIO(0) + GP_N_EVBE, 0x00000000);
940
+ writel(GPIO(0) + GP_N_DOUT, 0xffff0000);
941
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
942
+ writel(GPIO(0) + GP_N_EVST, 0xffffffff);
943
+
944
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
945
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
946
+ writel(GPIO(0) + GP_N_DOUT, 0xff00ff00);
947
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x0000ff00);
948
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
949
+ writel(GPIO(0) + GP_N_DOUT, 0x00ff0000);
950
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00ffff00);
951
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
952
+ writel(GPIO(0) + GP_N_EVST, 0x0000f000);
953
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00ff0f00);
954
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
955
+ writel(GPIO(0) + GP_N_EVST, 0x00ff0f00);
956
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
957
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
958
+}
959
+
960
+static void test_events_both_edges(void)
961
+{
962
+ gpio_reset(0);
963
+
964
+ writel(GPIO(0) + GP_N_EVTYP, 0xffffffff);
965
+ writel(GPIO(0) + GP_N_EVBE, 0xffffffff);
966
+ writel(GPIO(0) + GP_N_DOUT, 0xffff0000);
967
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
968
+ writel(GPIO(0) + GP_N_EVST, 0xffffffff);
969
+
970
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
971
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
972
+ writel(GPIO(0) + GP_N_DOUT, 0xff00ff00);
973
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00ffff00);
974
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
975
+ writel(GPIO(0) + GP_N_DOUT, 0xef00ff08);
976
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x10ffff08);
977
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
978
+ writel(GPIO(0) + GP_N_EVST, 0x0000f000);
979
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x10ff0f08);
980
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
981
+ writel(GPIO(0) + GP_N_EVST, 0x10ff0f08);
982
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
983
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
984
+}
985
+
986
+static void test_gpion_irq(gconstpointer test_data)
987
+{
988
+ intptr_t n = (intptr_t)test_data;
989
+
990
+ gpio_reset(n);
991
+
992
+ writel(GPIO(n) + GP_N_EVTYP, 0x00000000);
993
+ writel(GPIO(n) + GP_N_DOUT, 0x00000000);
994
+ writel(GPIO(n) + GP_N_OE, 0xffffffff);
995
+ writel(GPIO(n) + GP_N_EVST, 0xffffffff);
996
+ writel(GPIO(n) + GP_N_EVEN, 0x00000000);
997
+
998
+ /* Trigger an event; interrupts are masked. */
999
+ g_assert_cmphex(readl(GPIO(n) + GP_N_EVST), ==, 0x00000000);
1000
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1001
+ writel(GPIO(n) + GP_N_DOS, 0x00008000);
1002
+ g_assert_cmphex(readl(GPIO(n) + GP_N_EVST), ==, 0x00008000);
1003
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1004
+
1005
+ /* Unmask all event interrupts; verify that the interrupt fired. */
1006
+ writel(GPIO(n) + GP_N_EVEN, 0xffffffff);
1007
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1008
+
1009
+ /* Clear the current bit, set a new bit, irq stays asserted. */
1010
+ writel(GPIO(n) + GP_N_DOC, 0x00008000);
1011
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1012
+ writel(GPIO(n) + GP_N_DOS, 0x00000200);
1013
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1014
+ writel(GPIO(n) + GP_N_EVST, 0x00008000);
1015
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1016
+
1017
+ /* Mask/unmask the event that's currently active. */
1018
+ writel(GPIO(n) + GP_N_EVENC, 0x00000200);
1019
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1020
+ writel(GPIO(n) + GP_N_EVENS, 0x00000200);
1021
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1022
+
1023
+ /* Clear the input and the status bit, irq is deasserted. */
1024
+ writel(GPIO(n) + GP_N_DOC, 0x00000200);
1025
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1026
+ writel(GPIO(n) + GP_N_EVST, 0x00000200);
1027
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1028
+}
1029
+
1030
+int main(int argc, char **argv)
1031
+{
1032
+ int ret;
1033
+ int i;
1034
+
1035
+ g_test_init(&argc, &argv, NULL);
1036
+ g_test_set_nonfatal_assertions();
1037
+
1038
+ qtest_add_func("/npcm7xx_gpio/dout_to_din", test_dout_to_din);
1039
+ qtest_add_func("/npcm7xx_gpio/pullup_pulldown", test_pullup_pulldown);
1040
+ qtest_add_func("/npcm7xx_gpio/output_enable", test_output_enable);
1041
+ qtest_add_func("/npcm7xx_gpio/open_drain", test_open_drain);
1042
+ qtest_add_func("/npcm7xx_gpio/polarity", test_polarity);
1043
+ qtest_add_func("/npcm7xx_gpio/input_mask", test_input_mask);
1044
+ qtest_add_func("/npcm7xx_gpio/temp_lock", test_temp_lock);
1045
+ qtest_add_func("/npcm7xx_gpio/events/level", test_events_level);
1046
+ qtest_add_func("/npcm7xx_gpio/events/rising_edge", test_events_rising_edge);
1047
+ qtest_add_func("/npcm7xx_gpio/events/both_edges", test_events_both_edges);
1048
+
1049
+ for (i = 0; i < NR_GPIO_DEVICES; i++) {
1050
+ g_autofree char *test_name =
1051
+ g_strdup_printf("/npcm7xx_gpio/gpio[%d]/irq", i);
1052
+ qtest_add_data_func(test_name, (void *)(intptr_t)i, test_gpion_irq);
485
+ }
1053
+ }
486
+#endif
1054
+
487
+}
1055
+ qtest_start("-machine npcm750-evb");
1056
+ qtest_irq_intercept_in(global_qtest, "/machine/soc/a9mpcore/gic");
1057
+ ret = g_test_run();
1058
+ qtest_end();
1059
+
1060
+ return ret;
1061
+}
1062
diff --git a/hw/gpio/meson.build b/hw/gpio/meson.build
1063
index XXXXXXX..XXXXXXX 100644
1064
--- a/hw/gpio/meson.build
1065
+++ b/hw/gpio/meson.build
1066
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_gpio.c'))
1067
softmmu_ss.add(when: 'CONFIG_ZAURUS', if_true: files('zaurus.c'))
1068
1069
softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_gpio.c'))
1070
+softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_gpio.c'))
1071
softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_gpio.c'))
1072
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_gpio.c'))
1073
softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_gpio.c'))
1074
diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events
1075
index XXXXXXX..XXXXXXX 100644
1076
--- a/hw/gpio/trace-events
1077
+++ b/hw/gpio/trace-events
1078
@@ -XXX,XX +XXX,XX @@
1079
# See docs/devel/tracing.txt for syntax documentation.
1080
1081
+# npcm7xx_gpio.c
1082
+npcm7xx_gpio_read(const char *id, uint64_t offset, uint64_t value) " %s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
1083
+npcm7xx_gpio_write(const char *id, uint64_t offset, uint64_t value) "%s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
1084
+npcm7xx_gpio_set_input(const char *id, int32_t line, int32_t level) "%s line: %" PRIi32 " level: %" PRIi32
1085
+npcm7xx_gpio_set_output(const char *id, int32_t line, int32_t level) "%s line: %" PRIi32 " level: %" PRIi32
1086
+npcm7xx_gpio_update_events(const char *id, uint32_t evst, uint32_t even) "%s evst: 0x%08" PRIx32 " even: 0x%08" PRIx32
1087
+
1088
# nrf51_gpio.c
1089
nrf51_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" PRIx64
1090
nrf51_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x%" PRIx64
1091
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
1092
index XXXXXXX..XXXXXXX 100644
1093
--- a/tests/qtest/meson.build
1094
+++ b/tests/qtest/meson.build
1095
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
1096
['prom-env-test', 'boot-serial-test']
1097
1098
qtests_npcm7xx = \
1099
- ['npcm7xx_rng-test',
1100
+ ['npcm7xx_gpio-test',
1101
+ 'npcm7xx_rng-test',
1102
'npcm7xx_timer-test',
1103
'npcm7xx_watchdog_timer-test']
1104
qtests_arm = \
488
--
1105
--
489
2.20.1
1106
2.20.1
490
1107
491
1108
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Zenghui Yu <yuzenghui@huawei.com>
2
2
3
This machine correctly defines its default_cpu_type to cortex-m3
3
Ensure the vSMMUv3 will be restored before all PCIe devices so that DMA
4
and report an error if the user requested another cpu_type,
4
translation can work properly during migration.
5
however it does not exit, and this can confuse users trying
6
to use another core:
7
5
8
$ qemu-system-arm -M emcraft-sf2 -cpu cortex-m4 -kernel test-m4.elf
6
Signed-off-by: Zenghui Yu <yuzenghui@huawei.com>
9
qemu-system-arm: This board can only be used with CPU cortex-m3-arm-cpu
7
Message-id: 20201019091508.197-1-yuzenghui@huawei.com
10
[output related to M3 core ...]
8
Acked-by: Eric Auger <eric.auger@redhat.com>
11
12
The CPU is indeed a M3 core:
13
14
(qemu) info qom-tree
15
/machine (emcraft-sf2-machine)
16
/unattached (container)
17
/device[0] (msf2-soc)
18
/armv7m (armv7m)
19
/cpu (cortex-m3-arm-cpu)
20
21
Add the missing exit() call to return to the shell.
22
23
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
24
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
25
Reviewed-by: Eduardo Habkost <ehabkost@redhat.com>
26
Message-id: 20190617160136.29930-1-philmd@redhat.com
27
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
28
---
10
---
29
hw/arm/msf2-som.c | 1 +
11
hw/arm/smmuv3.c | 1 +
30
1 file changed, 1 insertion(+)
12
1 file changed, 1 insertion(+)
31
13
32
diff --git a/hw/arm/msf2-som.c b/hw/arm/msf2-som.c
14
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
33
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
34
--- a/hw/arm/msf2-som.c
16
--- a/hw/arm/smmuv3.c
35
+++ b/hw/arm/msf2-som.c
17
+++ b/hw/arm/smmuv3.c
36
@@ -XXX,XX +XXX,XX @@ static void emcraft_sf2_s2s010_init(MachineState *machine)
18
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_smmuv3 = {
37
if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) {
19
.name = "smmuv3",
38
error_report("This board can only be used with CPU %s",
20
.version_id = 1,
39
mc->default_cpu_type);
21
.minimum_version_id = 1,
40
+ exit(1);
22
+ .priority = MIG_PRI_IOMMU,
41
}
23
.fields = (VMStateField[]) {
42
24
VMSTATE_UINT32(features, SMMUv3State),
43
memory_region_init_ram(ddr, NULL, "ddr-ram", DDR_SIZE,
25
VMSTATE_UINT8(sid_size, SMMUv3State),
44
--
26
--
45
2.20.1
27
2.20.1
46
28
47
29
diff view generated by jsdifflib
1
From: Cédric Le Goater <clg@kaod.org>
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
2
3
The DRAM address of a DMA transaction depends on the DRAM base address
3
No code out of bcm2836.c uses (or requires) the BCM283XInfo
4
of the SoC. Inform the SMC controller model with this value.
4
declarations. Move it locally to the C source file.
5
5
6
Signed-off-by: Cédric Le Goater <clg@kaod.org>
6
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
7
Reviewed-by: Joel Stanley <joel@jms.id.au>
7
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
Message-id: 20201024170127.3592182-2-f4bug@amsat.org
9
Message-id: 20190618165311.27066-15-clg@kaod.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
10
---
12
include/hw/ssi/aspeed_smc.h | 3 +++
11
include/hw/arm/bcm2836.h | 8 --------
13
hw/arm/aspeed_soc.c | 6 ++++++
12
hw/arm/bcm2836.c | 14 ++++++++++++++
14
hw/ssi/aspeed_smc.c | 1 +
13
2 files changed, 14 insertions(+), 8 deletions(-)
15
3 files changed, 10 insertions(+)
16
14
17
diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h
15
diff --git a/include/hw/arm/bcm2836.h b/include/hw/arm/bcm2836.h
18
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
19
--- a/include/hw/ssi/aspeed_smc.h
17
--- a/include/hw/arm/bcm2836.h
20
+++ b/include/hw/ssi/aspeed_smc.h
18
+++ b/include/hw/arm/bcm2836.h
21
@@ -XXX,XX +XXX,XX @@ typedef struct AspeedSMCState {
19
@@ -XXX,XX +XXX,XX @@ struct BCM283XState {
22
uint8_t r_timings;
20
BCM2835PeripheralState peripherals;
23
uint8_t conf_enable_w0;
21
};
24
22
25
+ /* for DMA support */
23
-typedef struct BCM283XInfo BCM283XInfo;
26
+ uint64_t sdram_base;
24
-
25
-struct BCM283XClass {
26
- DeviceClass parent_class;
27
- const BCM283XInfo *info;
28
-};
29
-
30
-
31
#endif /* BCM2836_H */
32
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/hw/arm/bcm2836.c
35
+++ b/hw/arm/bcm2836.c
36
@@ -XXX,XX +XXX,XX @@
37
#include "hw/arm/raspi_platform.h"
38
#include "hw/sysbus.h"
39
40
+typedef struct BCM283XInfo BCM283XInfo;
27
+
41
+
28
AspeedSMCFlash *flashes;
42
+typedef struct BCM283XClass {
29
43
+ /*< private >*/
30
uint8_t snoop_index;
44
+ DeviceClass parent_class;
31
diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c
45
+ /*< public >*/
32
index XXXXXXX..XXXXXXX 100644
46
+ const BCM283XInfo *info;
33
--- a/hw/arm/aspeed_soc.c
47
+} BCM283XClass;
34
+++ b/hw/arm/aspeed_soc.c
48
+
35
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
49
struct BCM283XInfo {
36
aspeed_soc_get_irq(s, ASPEED_I2C));
50
const char *name;
37
51
const char *cpu_type;
38
/* FMC, The number of CS is set at the board level */
52
@@ -XXX,XX +XXX,XX @@ struct BCM283XInfo {
39
+ object_property_set_int(OBJECT(&s->fmc), sc->info->memmap[ASPEED_SDRAM],
53
int clusterid;
40
+ "sdram-base", &err);
41
+ if (err) {
42
+ error_propagate(errp, err);
43
+ return;
44
+ }
45
object_property_set_bool(OBJECT(&s->fmc), true, "realized", &err);
46
if (err) {
47
error_propagate(errp, err);
48
diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/hw/ssi/aspeed_smc.c
51
+++ b/hw/ssi/aspeed_smc.c
52
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_aspeed_smc = {
53
54
static Property aspeed_smc_properties[] = {
55
DEFINE_PROP_UINT32("num-cs", AspeedSMCState, num_cs, 1),
56
+ DEFINE_PROP_UINT64("sdram-base", AspeedSMCState, sdram_base, 0),
57
DEFINE_PROP_END_OF_LIST(),
58
};
54
};
59
55
56
+#define BCM283X_CLASS(klass) \
57
+ OBJECT_CLASS_CHECK(BCM283XClass, (klass), TYPE_BCM283X)
58
+#define BCM283X_GET_CLASS(obj) \
59
+ OBJECT_GET_CLASS(BCM283XClass, (obj), TYPE_BCM283X)
60
+
61
static const BCM283XInfo bcm283x_socs[] = {
62
{
63
.name = TYPE_BCM2836,
60
--
64
--
61
2.20.1
65
2.20.1
62
66
63
67
diff view generated by jsdifflib
1
From: Cédric Le Goater <clg@kaod.org>
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
2
3
This will simplify the definition of new SoCs, like the AST2600 which
3
Remove usage of TypeInfo::class_data. Instead fill the fields in
4
should use a slightly different address space and have a different set
4
the corresponding class_init().
5
of controllers.
5
6
6
So far all children use the same values for almost all fields,
7
Signed-off-by: Cédric Le Goater <clg@kaod.org>
7
but we are going to add the BCM2711/BCM2838 SoC for the raspi4
8
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
machine which use different fields.
9
Reviewed-by: Joel Stanley <joel@jms.id.au>
9
10
Message-id: 20190618165311.27066-3-clg@kaod.org
10
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
11
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
12
Message-id: 20201024170127.3592182-3-f4bug@amsat.org
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
14
---
13
include/hw/arm/aspeed_soc.h | 4 +-
15
hw/arm/bcm2836.c | 108 ++++++++++++++++++++++-------------------------
14
hw/arm/aspeed.c | 8 +--
16
1 file changed, 51 insertions(+), 57 deletions(-)
15
hw/arm/aspeed_soc.c | 117 ++++++++++++++++++++++--------------
17
16
3 files changed, 78 insertions(+), 51 deletions(-)
18
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
17
18
diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h
19
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
20
--- a/include/hw/arm/aspeed_soc.h
20
--- a/hw/arm/bcm2836.c
21
+++ b/include/hw/arm/aspeed_soc.h
21
+++ b/hw/arm/bcm2836.c
22
@@ -XXX,XX +XXX,XX @@ typedef struct AspeedSoCInfo {
22
@@ -XXX,XX +XXX,XX @@
23
#include "hw/arm/raspi_platform.h"
24
#include "hw/sysbus.h"
25
26
-typedef struct BCM283XInfo BCM283XInfo;
27
-
28
typedef struct BCM283XClass {
29
/*< private >*/
30
DeviceClass parent_class;
31
/*< public >*/
32
- const BCM283XInfo *info;
33
-} BCM283XClass;
34
-
35
-struct BCM283XInfo {
23
const char *name;
36
const char *name;
24
const char *cpu_type;
37
const char *cpu_type;
25
uint32_t silicon_rev;
38
hwaddr peri_base; /* Peripheral base address seen by the CPU */
26
- hwaddr sdram_base;
39
hwaddr ctrl_base; /* Interrupt controller and mailboxes etc. */
27
uint64_t sram_size;
40
int clusterid;
28
int spis_num;
41
-};
29
- const hwaddr *spi_bases;
42
+} BCM283XClass;
30
const char *fmc_typename;
43
31
const char **spi_typename;
44
#define BCM283X_CLASS(klass) \
32
int wdts_num;
45
OBJECT_CLASS_CHECK(BCM283XClass, (klass), TYPE_BCM283X)
33
const int *irqmap;
46
#define BCM283X_GET_CLASS(obj) \
34
+ const hwaddr *memmap;
47
OBJECT_GET_CLASS(BCM283XClass, (obj), TYPE_BCM283X)
35
} AspeedSoCInfo;
48
36
49
-static const BCM283XInfo bcm283x_socs[] = {
37
typedef struct AspeedSoCClass {
50
- {
38
@@ -XXX,XX +XXX,XX @@ enum {
51
- .name = TYPE_BCM2836,
39
ASPEED_I2C,
52
- .cpu_type = ARM_CPU_TYPE_NAME("cortex-a7"),
40
ASPEED_ETH1,
53
- .peri_base = 0x3f000000,
41
ASPEED_ETH2,
54
- .ctrl_base = 0x40000000,
42
+ ASPEED_SDRAM,
55
- .clusterid = 0xf,
43
};
56
- },
44
57
-#ifdef TARGET_AARCH64
45
#endif /* ASPEED_SOC_H */
58
- {
46
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
59
- .name = TYPE_BCM2837,
47
index XXXXXXX..XXXXXXX 100644
60
- .cpu_type = ARM_CPU_TYPE_NAME("cortex-a53"),
48
--- a/hw/arm/aspeed.c
61
- .peri_base = 0x3f000000,
49
+++ b/hw/arm/aspeed.c
62
- .ctrl_base = 0x40000000,
50
@@ -XXX,XX +XXX,XX @@ static void aspeed_board_init(MachineState *machine,
63
- .clusterid = 0x0,
51
&error_abort);
64
- },
52
65
-#endif
53
memory_region_allocate_system_memory(&bmc->ram, NULL, "ram", ram_size);
66
-};
54
- memory_region_add_subregion(get_system_memory(), sc->info->sdram_base,
55
- &bmc->ram);
56
+ memory_region_add_subregion(get_system_memory(),
57
+ sc->info->memmap[ASPEED_SDRAM], &bmc->ram);
58
object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram),
59
&error_abort);
60
61
@@ -XXX,XX +XXX,XX @@ static void aspeed_board_init(MachineState *machine,
62
memory_region_init_io(&bmc->max_ram, NULL, &max_ram_ops, NULL,
63
"max_ram", max_ram_size - ram_size);
64
memory_region_add_subregion(get_system_memory(),
65
- sc->info->sdram_base + ram_size,
66
+ sc->info->memmap[ASPEED_SDRAM] + ram_size,
67
&bmc->max_ram);
68
69
aspeed_board_init_flashes(&bmc->soc.fmc, cfg->fmc_model, &error_abort);
70
@@ -XXX,XX +XXX,XX @@ static void aspeed_board_init(MachineState *machine,
71
aspeed_board_binfo.initrd_filename = machine->initrd_filename;
72
aspeed_board_binfo.kernel_cmdline = machine->kernel_cmdline;
73
aspeed_board_binfo.ram_size = ram_size;
74
- aspeed_board_binfo.loader_start = sc->info->sdram_base;
75
+ aspeed_board_binfo.loader_start = sc->info->memmap[ASPEED_SDRAM];
76
77
if (cfg->i2c_init) {
78
cfg->i2c_init(bmc);
79
diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c
80
index XXXXXXX..XXXXXXX 100644
81
--- a/hw/arm/aspeed_soc.c
82
+++ b/hw/arm/aspeed_soc.c
83
@@ -XXX,XX +XXX,XX @@
84
#include "hw/i2c/aspeed_i2c.h"
85
#include "net/net.h"
86
87
-#define ASPEED_SOC_UART_5_BASE 0x00184000
88
#define ASPEED_SOC_IOMEM_SIZE 0x00200000
89
-#define ASPEED_SOC_IOMEM_BASE 0x1E600000
90
-#define ASPEED_SOC_FMC_BASE 0x1E620000
91
-#define ASPEED_SOC_SPI_BASE 0x1E630000
92
-#define ASPEED_SOC_SPI2_BASE 0x1E631000
93
-#define ASPEED_SOC_VIC_BASE 0x1E6C0000
94
-#define ASPEED_SOC_SDMC_BASE 0x1E6E0000
95
-#define ASPEED_SOC_SCU_BASE 0x1E6E2000
96
-#define ASPEED_SOC_SRAM_BASE 0x1E720000
97
-#define ASPEED_SOC_TIMER_BASE 0x1E782000
98
-#define ASPEED_SOC_WDT_BASE 0x1E785000
99
-#define ASPEED_SOC_I2C_BASE 0x1E78A000
100
-#define ASPEED_SOC_ETH1_BASE 0x1E660000
101
-#define ASPEED_SOC_ETH2_BASE 0x1E680000
102
+
103
+static const hwaddr aspeed_soc_ast2400_memmap[] = {
104
+ [ASPEED_IOMEM] = 0x1E600000,
105
+ [ASPEED_FMC] = 0x1E620000,
106
+ [ASPEED_SPI1] = 0x1E630000,
107
+ [ASPEED_VIC] = 0x1E6C0000,
108
+ [ASPEED_SDMC] = 0x1E6E0000,
109
+ [ASPEED_SCU] = 0x1E6E2000,
110
+ [ASPEED_ADC] = 0x1E6E9000,
111
+ [ASPEED_SRAM] = 0x1E720000,
112
+ [ASPEED_GPIO] = 0x1E780000,
113
+ [ASPEED_RTC] = 0x1E781000,
114
+ [ASPEED_TIMER1] = 0x1E782000,
115
+ [ASPEED_WDT] = 0x1E785000,
116
+ [ASPEED_PWM] = 0x1E786000,
117
+ [ASPEED_LPC] = 0x1E789000,
118
+ [ASPEED_IBT] = 0x1E789140,
119
+ [ASPEED_I2C] = 0x1E78A000,
120
+ [ASPEED_ETH1] = 0x1E660000,
121
+ [ASPEED_ETH2] = 0x1E680000,
122
+ [ASPEED_UART1] = 0x1E783000,
123
+ [ASPEED_UART5] = 0x1E784000,
124
+ [ASPEED_VUART] = 0x1E787000,
125
+ [ASPEED_SDRAM] = 0x40000000,
126
+};
127
+
128
+static const hwaddr aspeed_soc_ast2500_memmap[] = {
129
+ [ASPEED_IOMEM] = 0x1E600000,
130
+ [ASPEED_FMC] = 0x1E620000,
131
+ [ASPEED_SPI1] = 0x1E630000,
132
+ [ASPEED_SPI2] = 0x1E631000,
133
+ [ASPEED_VIC] = 0x1E6C0000,
134
+ [ASPEED_SDMC] = 0x1E6E0000,
135
+ [ASPEED_SCU] = 0x1E6E2000,
136
+ [ASPEED_ADC] = 0x1E6E9000,
137
+ [ASPEED_SRAM] = 0x1E720000,
138
+ [ASPEED_GPIO] = 0x1E780000,
139
+ [ASPEED_RTC] = 0x1E781000,
140
+ [ASPEED_TIMER1] = 0x1E782000,
141
+ [ASPEED_WDT] = 0x1E785000,
142
+ [ASPEED_PWM] = 0x1E786000,
143
+ [ASPEED_LPC] = 0x1E789000,
144
+ [ASPEED_IBT] = 0x1E789140,
145
+ [ASPEED_I2C] = 0x1E78A000,
146
+ [ASPEED_ETH1] = 0x1E660000,
147
+ [ASPEED_ETH2] = 0x1E680000,
148
+ [ASPEED_UART1] = 0x1E783000,
149
+ [ASPEED_UART5] = 0x1E784000,
150
+ [ASPEED_VUART] = 0x1E787000,
151
+ [ASPEED_SDRAM] = 0x80000000,
152
+};
153
154
static const int aspeed_soc_ast2400_irqmap[] = {
155
[ASPEED_UART1] = 9,
156
@@ -XXX,XX +XXX,XX @@ static const int aspeed_soc_ast2400_irqmap[] = {
157
[ASPEED_ETH2] = 3,
158
};
159
160
-#define AST2400_SDRAM_BASE 0x40000000
161
-#define AST2500_SDRAM_BASE 0x80000000
162
-
67
-
163
-/* AST2500 uses the same IRQs as the AST2400 */
68
static void bcm2836_init(Object *obj)
164
#define aspeed_soc_ast2500_irqmap aspeed_soc_ast2400_irqmap
69
{
165
70
BCM283XState *s = BCM283X(obj);
166
-static const hwaddr aspeed_soc_ast2400_spi_bases[] = { ASPEED_SOC_SPI_BASE };
71
BCM283XClass *bc = BCM283X_GET_CLASS(obj);
167
static const char *aspeed_soc_ast2400_typenames[] = { "aspeed.smc.spi" };
72
- const BCM283XInfo *info = bc->info;
168
-
73
int n;
169
-static const hwaddr aspeed_soc_ast2500_spi_bases[] = { ASPEED_SOC_SPI_BASE,
74
170
- ASPEED_SOC_SPI2_BASE};
75
for (n = 0; n < BCM283X_NCPUS; n++) {
171
static const char *aspeed_soc_ast2500_typenames[] = {
76
object_initialize_child(obj, "cpu[*]", &s->cpu[n].core,
172
"aspeed.smc.ast2500-spi1", "aspeed.smc.ast2500-spi2" };
77
- info->cpu_type);
173
78
+ bc->cpu_type);
174
@@ -XXX,XX +XXX,XX @@ static const AspeedSoCInfo aspeed_socs[] = {
79
}
175
.name = "ast2400-a0",
80
176
.cpu_type = ARM_CPU_TYPE_NAME("arm926"),
81
object_initialize_child(obj, "control", &s->control, TYPE_BCM2836_CONTROL);
177
.silicon_rev = AST2400_A0_SILICON_REV,
82
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
178
- .sdram_base = AST2400_SDRAM_BASE,
83
{
179
.sram_size = 0x8000,
84
BCM283XState *s = BCM283X(dev);
180
.spis_num = 1,
85
BCM283XClass *bc = BCM283X_GET_CLASS(dev);
181
- .spi_bases = aspeed_soc_ast2400_spi_bases,
86
- const BCM283XInfo *info = bc->info;
182
.fmc_typename = "aspeed.smc.fmc",
87
Object *obj;
183
.spi_typename = aspeed_soc_ast2400_typenames,
88
int n;
184
.wdts_num = 2,
89
185
.irqmap = aspeed_soc_ast2400_irqmap,
90
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
186
+ .memmap = aspeed_soc_ast2400_memmap,
91
"sd-bus");
187
}, {
92
188
.name = "ast2400-a1",
93
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0,
189
.cpu_type = ARM_CPU_TYPE_NAME("arm926"),
94
- info->peri_base, 1);
190
.silicon_rev = AST2400_A1_SILICON_REV,
95
+ bc->peri_base, 1);
191
- .sdram_base = AST2400_SDRAM_BASE,
96
192
.sram_size = 0x8000,
97
/* bcm2836 interrupt controller (and mailboxes, etc.) */
193
.spis_num = 1,
98
if (!sysbus_realize(SYS_BUS_DEVICE(&s->control), errp)) {
194
- .spi_bases = aspeed_soc_ast2400_spi_bases,
195
.fmc_typename = "aspeed.smc.fmc",
196
.spi_typename = aspeed_soc_ast2400_typenames,
197
.wdts_num = 2,
198
.irqmap = aspeed_soc_ast2400_irqmap,
199
+ .memmap = aspeed_soc_ast2400_memmap,
200
}, {
201
.name = "ast2400",
202
.cpu_type = ARM_CPU_TYPE_NAME("arm926"),
203
.silicon_rev = AST2400_A0_SILICON_REV,
204
- .sdram_base = AST2400_SDRAM_BASE,
205
.sram_size = 0x8000,
206
.spis_num = 1,
207
- .spi_bases = aspeed_soc_ast2400_spi_bases,
208
.fmc_typename = "aspeed.smc.fmc",
209
.spi_typename = aspeed_soc_ast2400_typenames,
210
.wdts_num = 2,
211
.irqmap = aspeed_soc_ast2400_irqmap,
212
+ .memmap = aspeed_soc_ast2400_memmap,
213
}, {
214
.name = "ast2500-a1",
215
.cpu_type = ARM_CPU_TYPE_NAME("arm1176"),
216
.silicon_rev = AST2500_A1_SILICON_REV,
217
- .sdram_base = AST2500_SDRAM_BASE,
218
.sram_size = 0x9000,
219
.spis_num = 2,
220
- .spi_bases = aspeed_soc_ast2500_spi_bases,
221
.fmc_typename = "aspeed.smc.ast2500-fmc",
222
.spi_typename = aspeed_soc_ast2500_typenames,
223
.wdts_num = 3,
224
.irqmap = aspeed_soc_ast2500_irqmap,
225
+ .memmap = aspeed_soc_ast2500_memmap,
226
},
227
};
228
229
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
230
Error *err = NULL, *local_err = NULL;
231
232
/* IO space */
233
- create_unimplemented_device("aspeed_soc.io",
234
- ASPEED_SOC_IOMEM_BASE, ASPEED_SOC_IOMEM_SIZE);
235
+ create_unimplemented_device("aspeed_soc.io", sc->info->memmap[ASPEED_IOMEM],
236
+ ASPEED_SOC_IOMEM_SIZE);
237
238
/* CPU */
239
object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err);
240
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
241
error_propagate(errp, err);
242
return;
99
return;
243
}
100
}
244
- memory_region_add_subregion(get_system_memory(), ASPEED_SOC_SRAM_BASE,
101
245
- &s->sram);
102
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, info->ctrl_base);
246
+ memory_region_add_subregion(get_system_memory(),
103
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, bc->ctrl_base);
247
+ sc->info->memmap[ASPEED_SRAM], &s->sram);
104
248
105
sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
249
/* SCU */
106
qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-irq", 0));
250
object_property_set_bool(OBJECT(&s->scu), true, "realized", &err);
107
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
251
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
108
252
error_propagate(errp, err);
109
for (n = 0; n < BCM283X_NCPUS; n++) {
253
return;
110
/* TODO: this should be converted to a property of ARM_CPU */
254
}
111
- s->cpu[n].core.mp_affinity = (info->clusterid << 8) | n;
255
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, ASPEED_SOC_SCU_BASE);
112
+ s->cpu[n].core.mp_affinity = (bc->clusterid << 8) | n;
256
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, sc->info->memmap[ASPEED_SCU]);
113
257
114
/* set periphbase/CBAR value for CPU-local registers */
258
/* VIC */
115
if (!object_property_set_int(OBJECT(&s->cpu[n].core), "reset-cbar",
259
object_property_set_bool(OBJECT(&s->vic), true, "realized", &err);
116
- info->peri_base, errp)) {
260
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
117
+ bc->peri_base, errp)) {
261
error_propagate(errp, err);
262
return;
263
}
264
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, ASPEED_SOC_VIC_BASE);
265
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, sc->info->memmap[ASPEED_VIC]);
266
sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 0,
267
qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ));
268
sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 1,
269
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
270
error_propagate(errp, err);
271
return;
272
}
273
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, ASPEED_SOC_TIMER_BASE);
274
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0,
275
+ sc->info->memmap[ASPEED_TIMER1]);
276
for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
277
qemu_irq irq = aspeed_soc_get_irq(s, ASPEED_TIMER1 + i);
278
sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq);
279
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
280
/* UART - attach an 8250 to the IO space as our UART5 */
281
if (serial_hd(0)) {
282
qemu_irq uart5 = aspeed_soc_get_irq(s, ASPEED_UART5);
283
- serial_mm_init(get_system_memory(),
284
- ASPEED_SOC_IOMEM_BASE + ASPEED_SOC_UART_5_BASE, 2,
285
+ serial_mm_init(get_system_memory(), sc->info->memmap[ASPEED_UART5], 2,
286
uart5, 38400, serial_hd(0), DEVICE_LITTLE_ENDIAN);
287
}
288
289
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
290
error_propagate(errp, err);
291
return;
292
}
293
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, ASPEED_SOC_I2C_BASE);
294
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, sc->info->memmap[ASPEED_I2C]);
295
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0,
296
aspeed_soc_get_irq(s, ASPEED_I2C));
297
298
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
299
error_propagate(errp, err);
300
return;
301
}
302
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, ASPEED_SOC_FMC_BASE);
303
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, sc->info->memmap[ASPEED_FMC]);
304
sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 1,
305
s->fmc.ctrl->flash_window_base);
306
sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0,
307
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
308
error_propagate(errp, err);
309
return;
118
return;
310
}
119
}
311
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, sc->info->spi_bases[i]);
120
312
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0,
121
@@ -XXX,XX +XXX,XX @@ static Property bcm2836_props[] = {
313
+ sc->info->memmap[ASPEED_SPI1 + i]);
122
static void bcm283x_class_init(ObjectClass *oc, void *data)
314
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 1,
123
{
315
s->spi[i].ctrl->flash_window_base);
124
DeviceClass *dc = DEVICE_CLASS(oc);
125
- BCM283XClass *bc = BCM283X_CLASS(oc);
126
127
- bc->info = data;
128
- dc->realize = bcm2836_realize;
129
- device_class_set_props(dc, bcm2836_props);
130
/* Reason: Must be wired up in code (see raspi_init() function) */
131
dc->user_creatable = false;
132
}
133
134
-static const TypeInfo bcm283x_type_info = {
135
- .name = TYPE_BCM283X,
136
- .parent = TYPE_DEVICE,
137
- .instance_size = sizeof(BCM283XState),
138
- .instance_init = bcm2836_init,
139
- .class_size = sizeof(BCM283XClass),
140
- .abstract = true,
141
+static void bcm2836_class_init(ObjectClass *oc, void *data)
142
+{
143
+ DeviceClass *dc = DEVICE_CLASS(oc);
144
+ BCM283XClass *bc = BCM283X_CLASS(oc);
145
+
146
+ bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a7");
147
+ bc->peri_base = 0x3f000000;
148
+ bc->ctrl_base = 0x40000000;
149
+ bc->clusterid = 0xf;
150
+ dc->realize = bcm2836_realize;
151
+ device_class_set_props(dc, bcm2836_props);
152
};
153
154
-static void bcm2836_register_types(void)
155
+#ifdef TARGET_AARCH64
156
+static void bcm2837_class_init(ObjectClass *oc, void *data)
157
{
158
- int i;
159
+ DeviceClass *dc = DEVICE_CLASS(oc);
160
+ BCM283XClass *bc = BCM283X_CLASS(oc);
161
162
- type_register_static(&bcm283x_type_info);
163
- for (i = 0; i < ARRAY_SIZE(bcm283x_socs); i++) {
164
- TypeInfo ti = {
165
- .name = bcm283x_socs[i].name,
166
- .parent = TYPE_BCM283X,
167
- .class_init = bcm283x_class_init,
168
- .class_data = (void *) &bcm283x_socs[i],
169
- };
170
- type_register(&ti);
171
+ bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a53");
172
+ bc->peri_base = 0x3f000000;
173
+ bc->ctrl_base = 0x40000000;
174
+ bc->clusterid = 0x0;
175
+ dc->realize = bcm2836_realize;
176
+ device_class_set_props(dc, bcm2836_props);
177
+};
178
+#endif
179
+
180
+static const TypeInfo bcm283x_types[] = {
181
+ {
182
+ .name = TYPE_BCM2836,
183
+ .parent = TYPE_BCM283X,
184
+ .class_init = bcm2836_class_init,
185
+#ifdef TARGET_AARCH64
186
+ }, {
187
+ .name = TYPE_BCM2837,
188
+ .parent = TYPE_BCM283X,
189
+ .class_init = bcm2837_class_init,
190
+#endif
191
+ }, {
192
+ .name = TYPE_BCM283X,
193
+ .parent = TYPE_DEVICE,
194
+ .instance_size = sizeof(BCM283XState),
195
+ .instance_init = bcm2836_init,
196
+ .class_size = sizeof(BCM283XClass),
197
+ .class_init = bcm283x_class_init,
198
+ .abstract = true,
316
}
199
}
317
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
200
-}
318
error_propagate(errp, err);
201
+};
319
return;
202
320
}
203
-type_init(bcm2836_register_types)
321
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, ASPEED_SOC_SDMC_BASE);
204
+DEFINE_TYPES(bcm283x_types)
322
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, sc->info->memmap[ASPEED_SDMC]);
323
324
/* Watch dog */
325
for (i = 0; i < sc->info->wdts_num; i++) {
326
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
327
return;
328
}
329
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0,
330
- ASPEED_SOC_WDT_BASE + i * 0x20);
331
+ sc->info->memmap[ASPEED_WDT] + i * 0x20);
332
}
333
334
/* Net */
335
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
336
error_propagate(errp, err);
337
return;
338
}
339
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->ftgmac100), 0, ASPEED_SOC_ETH1_BASE);
340
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->ftgmac100), 0,
341
+ sc->info->memmap[ASPEED_ETH1]);
342
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100), 0,
343
aspeed_soc_get_irq(s, ASPEED_ETH1));
344
}
345
--
205
--
346
2.20.1
206
2.20.1
347
207
348
208
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
2
3
Group SOFTMMU objects together.
3
The BCM2835 has only one core. Introduce the core_count field to
4
Since PSCI is TCG specific, keep it separate.
4
be able to use values different than BCM283X_NCPUS (4).
5
5
6
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
6
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
7
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
7
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Message-id: 20190701132516.26392-5-philmd@redhat.com
8
Message-id: 20201024170127.3592182-4-f4bug@amsat.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
10
---
11
target/arm/Makefile.objs | 5 ++++-
11
hw/arm/bcm2836.c | 5 ++++-
12
1 file changed, 4 insertions(+), 1 deletion(-)
12
1 file changed, 4 insertions(+), 1 deletion(-)
13
13
14
diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
14
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
15
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/Makefile.objs
16
--- a/hw/arm/bcm2836.c
17
+++ b/target/arm/Makefile.objs
17
+++ b/hw/arm/bcm2836.c
18
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@ typedef struct BCM283XClass {
19
obj-y += arm-semi.o
19
/*< public >*/
20
-obj-$(CONFIG_SOFTMMU) += machine.o psci.o arch_dump.o monitor.o
20
const char *name;
21
obj-y += helper.o vfp_helper.o
21
const char *cpu_type;
22
obj-y += cpu.o gdbstub.o
22
+ unsigned core_count;
23
obj-$(TARGET_AARCH64) += cpu64.o gdbstub64.o
23
hwaddr peri_base; /* Peripheral base address seen by the CPU */
24
+
24
hwaddr ctrl_base; /* Interrupt controller and mailboxes etc. */
25
+obj-$(CONFIG_SOFTMMU) += machine.o arch_dump.o monitor.o
25
int clusterid;
26
obj-$(CONFIG_SOFTMMU) += arm-powerctl.o
26
@@ -XXX,XX +XXX,XX @@ static void bcm2836_init(Object *obj)
27
27
BCM283XClass *bc = BCM283X_GET_CLASS(obj);
28
obj-$(CONFIG_KVM) += kvm.o
28
int n;
29
@@ -XXX,XX +XXX,XX @@ obj-y += translate.o op_helper.o
29
30
obj-y += crypto_helper.o
30
- for (n = 0; n < BCM283X_NCPUS; n++) {
31
obj-y += iwmmxt_helper.o vec_helper.o neon_helper.o
31
+ for (n = 0; n < bc->core_count; n++) {
32
32
object_initialize_child(obj, "cpu[*]", &s->cpu[n].core,
33
+obj-$(CONFIG_SOFTMMU) += psci.o
33
bc->cpu_type);
34
+
34
}
35
obj-$(TARGET_AARCH64) += translate-a64.o helper-a64.o
35
@@ -XXX,XX +XXX,XX @@ static void bcm2836_class_init(ObjectClass *oc, void *data)
36
obj-$(TARGET_AARCH64) += translate-sve.o sve_helper.o
36
BCM283XClass *bc = BCM283X_CLASS(oc);
37
obj-$(TARGET_AARCH64) += pauth_helper.o
37
38
bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a7");
39
+ bc->core_count = BCM283X_NCPUS;
40
bc->peri_base = 0x3f000000;
41
bc->ctrl_base = 0x40000000;
42
bc->clusterid = 0xf;
43
@@ -XXX,XX +XXX,XX @@ static void bcm2837_class_init(ObjectClass *oc, void *data)
44
BCM283XClass *bc = BCM283X_CLASS(oc);
45
46
bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a53");
47
+ bc->core_count = BCM283X_NCPUS;
48
bc->peri_base = 0x3f000000;
49
bc->ctrl_base = 0x40000000;
50
bc->clusterid = 0x0;
38
--
51
--
39
2.20.1
52
2.20.1
40
53
41
54
diff view generated by jsdifflib
1
From: Andrey Smirnov <andrew.smirnov@gmail.com>
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
2
3
Datasheet for i.MX7 is incorrect and i.MX7's PCI IRQ mapping matches
3
It makes no sense to set enabled-cpus=0 on single core SoCs.
4
that of i.MX6:
5
4
6
* INTD/MSI 122
5
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
7
* INTC 123
6
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
* INTB 124
7
Message-id: 20201024170127.3592182-5-f4bug@amsat.org
9
* INTA 125
10
11
Fix all of the relevant code to reflect that fact. Needed by latest
12
Linux kernels.
13
14
(Reference: Linux kernel commit 538d6e9d597584e80 from an
15
NXP employee confirming that the datasheet is incorrect and
16
with a report of a test against hardware.)
17
18
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
19
Cc: Peter Maydell <peter.maydell@linaro.org>
20
Cc: Michael S. Tsirkin <mst@redhat.com>
21
Cc: qemu-devel@nongnu.org
22
Cc: qemu-arm@nongnu.org
23
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
24
[PMM: added ref to kernel commit confirming the datasheet error]
25
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
26
---
9
---
27
include/hw/arm/fsl-imx7.h | 8 ++++----
10
hw/arm/bcm2836.c | 15 +++++++--------
28
hw/pci-host/designware.c | 6 ++++--
11
1 file changed, 7 insertions(+), 8 deletions(-)
29
2 files changed, 8 insertions(+), 6 deletions(-)
30
12
31
diff --git a/include/hw/arm/fsl-imx7.h b/include/hw/arm/fsl-imx7.h
13
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
32
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
33
--- a/include/hw/arm/fsl-imx7.h
15
--- a/hw/arm/bcm2836.c
34
+++ b/include/hw/arm/fsl-imx7.h
16
+++ b/hw/arm/bcm2836.c
35
@@ -XXX,XX +XXX,XX @@ enum FslIMX7IRQs {
17
@@ -XXX,XX +XXX,XX @@ typedef struct BCM283XClass {
36
FSL_IMX7_USB2_IRQ = 42,
18
#define BCM283X_GET_CLASS(obj) \
37
FSL_IMX7_USB3_IRQ = 40,
19
OBJECT_GET_CLASS(BCM283XClass, (obj), TYPE_BCM283X)
38
20
39
- FSL_IMX7_PCI_INTA_IRQ = 122,
21
+static Property bcm2836_enabled_cores_property =
40
- FSL_IMX7_PCI_INTB_IRQ = 123,
22
+ DEFINE_PROP_UINT32("enabled-cpus", BCM283XState, enabled_cpus, 0);
41
- FSL_IMX7_PCI_INTC_IRQ = 124,
42
- FSL_IMX7_PCI_INTD_IRQ = 125,
43
+ FSL_IMX7_PCI_INTA_IRQ = 125,
44
+ FSL_IMX7_PCI_INTB_IRQ = 124,
45
+ FSL_IMX7_PCI_INTC_IRQ = 123,
46
+ FSL_IMX7_PCI_INTD_IRQ = 122,
47
48
FSL_IMX7_UART7_IRQ = 126,
49
50
diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c
51
index XXXXXXX..XXXXXXX 100644
52
--- a/hw/pci-host/designware.c
53
+++ b/hw/pci-host/designware.c
54
@@ -XXX,XX +XXX,XX @@
55
#define DESIGNWARE_PCIE_ATU_DEVFN(x) (((x) >> 16) & 0xff)
56
#define DESIGNWARE_PCIE_ATU_UPPER_TARGET 0x91C
57
58
+#define DESIGNWARE_PCIE_IRQ_MSI 3
59
+
23
+
60
static DesignwarePCIEHost *
24
static void bcm2836_init(Object *obj)
61
designware_pcie_root_to_host(DesignwarePCIERoot *root)
62
{
25
{
63
@@ -XXX,XX +XXX,XX @@ static void designware_pcie_root_msi_write(void *opaque, hwaddr addr,
26
BCM283XState *s = BCM283X(obj);
64
root->msi.intr[0].status |= BIT(val) & root->msi.intr[0].enable;
27
@@ -XXX,XX +XXX,XX @@ static void bcm2836_init(Object *obj)
65
28
object_initialize_child(obj, "cpu[*]", &s->cpu[n].core,
66
if (root->msi.intr[0].status & ~root->msi.intr[0].mask) {
29
bc->cpu_type);
67
- qemu_set_irq(host->pci.irqs[0], 1);
30
}
68
+ qemu_set_irq(host->pci.irqs[DESIGNWARE_PCIE_IRQ_MSI], 1);
31
+ if (bc->core_count > 1) {
32
+ qdev_property_add_static(DEVICE(obj), &bcm2836_enabled_cores_property);
33
+ qdev_prop_set_uint32(DEVICE(obj), "enabled-cpus", bc->core_count);
34
+ }
35
36
object_initialize_child(obj, "control", &s->control, TYPE_BCM2836_CONTROL);
37
38
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
69
}
39
}
70
}
40
}
71
41
72
@@ -XXX,XX +XXX,XX @@ static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address,
42
-static Property bcm2836_props[] = {
73
case DESIGNWARE_PCIE_MSI_INTR0_STATUS:
43
- DEFINE_PROP_UINT32("enabled-cpus", BCM283XState, enabled_cpus,
74
root->msi.intr[0].status ^= val;
44
- BCM283X_NCPUS),
75
if (!root->msi.intr[0].status) {
45
- DEFINE_PROP_END_OF_LIST()
76
- qemu_set_irq(host->pci.irqs[0], 0);
46
-};
77
+ qemu_set_irq(host->pci.irqs[DESIGNWARE_PCIE_IRQ_MSI], 0);
47
-
78
}
48
static void bcm283x_class_init(ObjectClass *oc, void *data)
79
break;
49
{
50
DeviceClass *dc = DEVICE_CLASS(oc);
51
@@ -XXX,XX +XXX,XX @@ static void bcm2836_class_init(ObjectClass *oc, void *data)
52
bc->ctrl_base = 0x40000000;
53
bc->clusterid = 0xf;
54
dc->realize = bcm2836_realize;
55
- device_class_set_props(dc, bcm2836_props);
56
};
57
58
#ifdef TARGET_AARCH64
59
@@ -XXX,XX +XXX,XX @@ static void bcm2837_class_init(ObjectClass *oc, void *data)
60
bc->ctrl_base = 0x40000000;
61
bc->clusterid = 0x0;
62
dc->realize = bcm2836_realize;
63
- device_class_set_props(dc, bcm2836_props);
64
};
65
#endif
80
66
81
--
67
--
82
2.20.1
68
2.20.1
83
69
84
70
diff view generated by jsdifflib
1
From: Cédric Le Goater <clg@kaod.org>
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
2
3
The Aspeed SoCs have two MACs. Extend the Aspeed model to support a
3
The realize() function is clearly composed of two parts,
4
second NIC.
4
each described by a comment:
5
5
6
Signed-off-by: Cédric Le Goater <clg@kaod.org>
6
void realize()
7
Reviewed-by: Joel Stanley <joel@jms.id.au>
7
{
8
Message-id: 20190618165311.27066-7-clg@kaod.org
8
/* common peripherals from bcm2835 */
9
...
10
/* bcm2836 interrupt controller (and mailboxes, etc.) */
11
...
12
}
13
14
Split the two part, so we can reuse the common part with other
15
SoCs from this family.
16
17
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
18
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
19
Message-id: 20201024170127.3592182-6-f4bug@amsat.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
20
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
21
---
11
include/hw/arm/aspeed_soc.h | 3 ++-
22
hw/arm/bcm2836.c | 22 ++++++++++++++++++----
12
hw/arm/aspeed_soc.c | 33 +++++++++++++++++++--------------
23
1 file changed, 18 insertions(+), 4 deletions(-)
13
2 files changed, 21 insertions(+), 15 deletions(-)
14
24
15
diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h
25
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
16
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
17
--- a/include/hw/arm/aspeed_soc.h
27
--- a/hw/arm/bcm2836.c
18
+++ b/include/hw/arm/aspeed_soc.h
28
+++ b/hw/arm/bcm2836.c
19
@@ -XXX,XX +XXX,XX @@
29
@@ -XXX,XX +XXX,XX @@ static void bcm2836_init(Object *obj)
20
#define ASPEED_SPIS_NUM 2
30
qdev_prop_set_uint32(DEVICE(obj), "enabled-cpus", bc->core_count);
21
#define ASPEED_WDTS_NUM 3
22
#define ASPEED_CPUS_NUM 2
23
+#define ASPEED_MACS_NUM 2
24
25
typedef struct AspeedSoCState {
26
/*< private >*/
27
@@ -XXX,XX +XXX,XX @@ typedef struct AspeedSoCState {
28
AspeedSMCState spi[ASPEED_SPIS_NUM];
29
AspeedSDMCState sdmc;
30
AspeedWDTState wdt[ASPEED_WDTS_NUM];
31
- FTGMAC100State ftgmac100;
32
+ FTGMAC100State ftgmac100[ASPEED_MACS_NUM];
33
} AspeedSoCState;
34
35
#define TYPE_ASPEED_SOC "aspeed-soc"
36
diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c
37
index XXXXXXX..XXXXXXX 100644
38
--- a/hw/arm/aspeed_soc.c
39
+++ b/hw/arm/aspeed_soc.c
40
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_init(Object *obj)
41
sc->info->silicon_rev);
42
}
31
}
43
32
44
- sysbus_init_child_obj(obj, "ftgmac100", OBJECT(&s->ftgmac100),
33
- object_initialize_child(obj, "control", &s->control, TYPE_BCM2836_CONTROL);
45
- sizeof(s->ftgmac100), TYPE_FTGMAC100);
34
+ if (bc->ctrl_base) {
46
+ for (i = 0; i < ASPEED_MACS_NUM; i++) {
35
+ object_initialize_child(obj, "control", &s->control,
47
+ sysbus_init_child_obj(obj, "ftgmac100[*]", OBJECT(&s->ftgmac100[i]),
36
+ TYPE_BCM2836_CONTROL);
48
+ sizeof(s->ftgmac100[i]), TYPE_FTGMAC100);
49
+ }
37
+ }
38
39
object_initialize_child(obj, "peripherals", &s->peripherals,
40
TYPE_BCM2835_PERIPHERALS);
41
@@ -XXX,XX +XXX,XX @@ static void bcm2836_init(Object *obj)
42
"vcram-size");
50
}
43
}
51
44
52
static void aspeed_soc_realize(DeviceState *dev, Error **errp)
45
-static void bcm2836_realize(DeviceState *dev, Error **errp)
53
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
46
+static bool bcm283x_common_realize(DeviceState *dev, Error **errp)
47
{
48
BCM283XState *s = BCM283X(dev);
49
BCM283XClass *bc = BCM283X_GET_CLASS(dev);
50
Object *obj;
51
- int n;
52
53
/* common peripherals from bcm2835 */
54
55
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
56
object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj);
57
58
if (!sysbus_realize(SYS_BUS_DEVICE(&s->peripherals), errp)) {
59
- return;
60
+ return false;
54
}
61
}
55
62
56
/* Net */
63
object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->peripherals),
57
- qdev_set_nic_properties(DEVICE(&s->ftgmac100), &nd_table[0]);
64
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
58
- object_property_set_bool(OBJECT(&s->ftgmac100), true, "aspeed", &err);
65
59
- object_property_set_bool(OBJECT(&s->ftgmac100), true, "realized",
66
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0,
60
- &local_err);
67
bc->peri_base, 1);
61
- error_propagate(&err, local_err);
68
+ return true;
62
- if (err) {
69
+}
63
- error_propagate(errp, err);
70
+
64
- return;
71
+static void bcm2836_realize(DeviceState *dev, Error **errp)
65
+ for (i = 0; i < nb_nics; i++) {
72
+{
66
+ qdev_set_nic_properties(DEVICE(&s->ftgmac100[i]), &nd_table[i]);
73
+ BCM283XState *s = BCM283X(dev);
67
+ object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "aspeed",
74
+ BCM283XClass *bc = BCM283X_GET_CLASS(dev);
68
+ &err);
75
+ int n;
69
+ object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "realized",
76
+
70
+ &local_err);
77
+ if (!bcm283x_common_realize(dev, errp)) {
71
+ error_propagate(&err, local_err);
78
+ return;
72
+ if (err) {
79
+ }
73
+ error_propagate(errp, err);
80
74
+ return;
81
/* bcm2836 interrupt controller (and mailboxes, etc.) */
75
+ }
82
if (!sysbus_realize(SYS_BUS_DEVICE(&s->control), errp)) {
76
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
77
+ sc->info->memmap[ASPEED_ETH1 + i]);
78
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
79
+ aspeed_soc_get_irq(s, ASPEED_ETH1 + i));
80
}
81
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->ftgmac100), 0,
82
- sc->info->memmap[ASPEED_ETH1]);
83
- sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100), 0,
84
- aspeed_soc_get_irq(s, ASPEED_ETH1));
85
}
86
static Property aspeed_soc_properties[] = {
87
DEFINE_PROP_UINT32("num-cpus", AspeedSoCState, num_cpus, 0),
88
--
83
--
89
2.20.1
84
2.20.1
90
85
91
86
diff view generated by jsdifflib
1
From: Joel Stanley <joel@jms.id.au>
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
2
3
The ast2500 uses the watchdog to reset the SDRAM controller. This
3
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
4
operation is usually performed by u-boot's memory training procedure,
4
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
5
and it is enabled by setting a bit in the SCU and then causing the
5
Message-id: 20201024170127.3592182-7-f4bug@amsat.org
6
watchdog to expire. Therefore, we need the watchdog to be able to
7
access the SCU's register space.
8
9
This causes the watchdog to not perform a system reset when the bit is
10
set. In the future it could perform a reset of the SDMC model.
11
12
Signed-off-by: Joel Stanley <joel@jms.id.au>
13
Signed-off-by: Cédric Le Goater <clg@kaod.org>
14
Reviewed-by: Cédric Le Goater <clg@kaod.org>
15
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
16
Message-id: 20190621065242.32535-1-joel@jms.id.au
17
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
18
---
7
---
19
include/hw/watchdog/wdt_aspeed.h | 1 +
8
include/hw/arm/bcm2836.h | 1 +
20
hw/arm/aspeed_soc.c | 2 ++
9
hw/arm/bcm2836.c | 34 ++++++++++++++++++++++++++++++++++
21
hw/watchdog/wdt_aspeed.c | 20 ++++++++++++++++++++
10
hw/arm/raspi.c | 2 ++
22
3 files changed, 23 insertions(+)
11
3 files changed, 37 insertions(+)
23
12
24
diff --git a/include/hw/watchdog/wdt_aspeed.h b/include/hw/watchdog/wdt_aspeed.h
13
diff --git a/include/hw/arm/bcm2836.h b/include/hw/arm/bcm2836.h
25
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
26
--- a/include/hw/watchdog/wdt_aspeed.h
15
--- a/include/hw/arm/bcm2836.h
27
+++ b/include/hw/watchdog/wdt_aspeed.h
16
+++ b/include/hw/arm/bcm2836.h
28
@@ -XXX,XX +XXX,XX @@ typedef struct AspeedWDTState {
17
@@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_TYPE(BCM283XState, BCM283XClass, BCM283X)
29
MemoryRegion iomem;
18
* them, code using these devices should always handle them via the
30
uint32_t regs[ASPEED_WDT_REGS_MAX];
19
* BCM283x base class, so they have no BCM2836(obj) etc macros.
31
20
*/
32
+ AspeedSCUState *scu;
21
+#define TYPE_BCM2835 "bcm2835"
33
uint32_t pclk_freq;
22
#define TYPE_BCM2836 "bcm2836"
34
uint32_t silicon_rev;
23
#define TYPE_BCM2837 "bcm2837"
35
uint32_t ext_pulse_width_mask;
24
36
diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c
25
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
37
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
38
--- a/hw/arm/aspeed_soc.c
27
--- a/hw/arm/bcm2836.c
39
+++ b/hw/arm/aspeed_soc.c
28
+++ b/hw/arm/bcm2836.c
40
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_init(Object *obj)
29
@@ -XXX,XX +XXX,XX @@ static bool bcm283x_common_realize(DeviceState *dev, Error **errp)
41
sizeof(s->wdt[i]), TYPE_ASPEED_WDT);
30
return true;
42
qdev_prop_set_uint32(DEVICE(&s->wdt[i]), "silicon-rev",
31
}
43
sc->info->silicon_rev);
32
44
+ object_property_add_const_link(OBJECT(&s->wdt[i]), "scu",
33
+static void bcm2835_realize(DeviceState *dev, Error **errp)
45
+ OBJECT(&s->scu), &error_abort);
34
+{
46
}
35
+ BCM283XState *s = BCM283X(dev);
47
48
for (i = 0; i < ASPEED_MACS_NUM; i++) {
49
diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c
50
index XXXXXXX..XXXXXXX 100644
51
--- a/hw/watchdog/wdt_aspeed.c
52
+++ b/hw/watchdog/wdt_aspeed.c
53
@@ -XXX,XX +XXX,XX @@
54
55
#define WDT_RESTART_MAGIC 0x4755
56
57
+#define SCU_RESET_CONTROL1 (0x04 / 4)
58
+#define SCU_RESET_SDRAM BIT(0)
59
+
36
+
60
static bool aspeed_wdt_is_enabled(const AspeedWDTState *s)
37
+ if (!bcm283x_common_realize(dev, errp)) {
61
{
62
return s->regs[WDT_CTRL] & WDT_CTRL_ENABLE;
63
@@ -XXX,XX +XXX,XX @@ static void aspeed_wdt_timer_expired(void *dev)
64
{
65
AspeedWDTState *s = ASPEED_WDT(dev);
66
67
+ /* Do not reset on SDRAM controller reset */
68
+ if (s->scu->regs[SCU_RESET_CONTROL1] & SCU_RESET_SDRAM) {
69
+ timer_del(s->timer);
70
+ s->regs[WDT_CTRL] = 0;
71
+ return;
38
+ return;
72
+ }
39
+ }
73
+
40
+
74
qemu_log_mask(CPU_LOG_RESET, "Watchdog timer expired.\n");
41
+ if (!qdev_realize(DEVICE(&s->cpu[0].core), NULL, errp)) {
75
watchdog_perform_action();
76
timer_del(s->timer);
77
@@ -XXX,XX +XXX,XX @@ static void aspeed_wdt_realize(DeviceState *dev, Error **errp)
78
{
79
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
80
AspeedWDTState *s = ASPEED_WDT(dev);
81
+ Error *err = NULL;
82
+ Object *obj;
83
+
84
+ obj = object_property_get_link(OBJECT(dev), "scu", &err);
85
+ if (!obj) {
86
+ error_propagate(errp, err);
87
+ error_prepend(errp, "required link 'scu' not found: ");
88
+ return;
42
+ return;
89
+ }
43
+ }
90
+ s->scu = ASPEED_SCU(obj);
44
+
91
45
+ /* Connect irq/fiq outputs from the interrupt controller. */
92
if (!is_supported_silicon_rev(s->silicon_rev)) {
46
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
93
error_setg(errp, "Unknown silicon revision: 0x%" PRIx32,
47
+ qdev_get_gpio_in(DEVICE(&s->cpu[0].core), ARM_CPU_IRQ));
48
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
49
+ qdev_get_gpio_in(DEVICE(&s->cpu[0].core), ARM_CPU_FIQ));
50
+}
51
+
52
static void bcm2836_realize(DeviceState *dev, Error **errp)
53
{
54
BCM283XState *s = BCM283X(dev);
55
@@ -XXX,XX +XXX,XX @@ static void bcm283x_class_init(ObjectClass *oc, void *data)
56
dc->user_creatable = false;
57
}
58
59
+static void bcm2835_class_init(ObjectClass *oc, void *data)
60
+{
61
+ DeviceClass *dc = DEVICE_CLASS(oc);
62
+ BCM283XClass *bc = BCM283X_CLASS(oc);
63
+
64
+ bc->cpu_type = ARM_CPU_TYPE_NAME("arm1176");
65
+ bc->core_count = 1;
66
+ bc->peri_base = 0x20000000;
67
+ dc->realize = bcm2835_realize;
68
+};
69
+
70
static void bcm2836_class_init(ObjectClass *oc, void *data)
71
{
72
DeviceClass *dc = DEVICE_CLASS(oc);
73
@@ -XXX,XX +XXX,XX @@ static void bcm2837_class_init(ObjectClass *oc, void *data)
74
75
static const TypeInfo bcm283x_types[] = {
76
{
77
+ .name = TYPE_BCM2835,
78
+ .parent = TYPE_BCM283X,
79
+ .class_init = bcm2835_class_init,
80
+ }, {
81
.name = TYPE_BCM2836,
82
.parent = TYPE_BCM283X,
83
.class_init = bcm2836_class_init,
84
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
85
index XXXXXXX..XXXXXXX 100644
86
--- a/hw/arm/raspi.c
87
+++ b/hw/arm/raspi.c
88
@@ -XXX,XX +XXX,XX @@ FIELD(REV_CODE, MEMORY_SIZE, 20, 3);
89
FIELD(REV_CODE, STYLE, 23, 1);
90
91
typedef enum RaspiProcessorId {
92
+ PROCESSOR_ID_BCM2835 = 0,
93
PROCESSOR_ID_BCM2836 = 1,
94
PROCESSOR_ID_BCM2837 = 2,
95
} RaspiProcessorId;
96
@@ -XXX,XX +XXX,XX @@ static const struct {
97
const char *type;
98
int cores_count;
99
} soc_property[] = {
100
+ [PROCESSOR_ID_BCM2835] = {TYPE_BCM2835, 1},
101
[PROCESSOR_ID_BCM2836] = {TYPE_BCM2836, BCM283X_NCPUS},
102
[PROCESSOR_ID_BCM2837] = {TYPE_BCM2837, BCM283X_NCPUS},
103
};
94
--
104
--
95
2.20.1
105
2.20.1
96
106
97
107
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
2
3
Group Aarch64 rules together, TCG related ones at the bottom.
3
The Pi A is almost the first machine released.
4
This will help when restricting TCG-only objects.
4
It uses a BCM2835 SoC which includes a ARMv6Z core.
5
5
6
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
6
Example booting the machine using content from [*]
7
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
7
(we use the device tree from the B model):
8
Message-id: 20190701132516.26392-2-philmd@redhat.com
8
9
$ qemu-system-arm -M raspi1ap -serial stdio \
10
-kernel raspberrypi/firmware/boot/kernel.img \
11
-dtb raspberrypi/firmware/boot/bcm2708-rpi-b-plus.dtb \
12
-append 'earlycon=pl011,0x20201000 console=ttyAMA0'
13
[ 0.000000] Booting Linux on physical CPU 0x0
14
[ 0.000000] Linux version 4.19.118+ (dom@buildbot) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611)) #1311 Mon Apr 27 14:16:15 BST 2020
15
[ 0.000000] CPU: ARMv6-compatible processor [410fb767] revision 7 (ARMv7), cr=00c5387d
16
[ 0.000000] CPU: VIPT aliasing data cache, unknown instruction cache
17
[ 0.000000] OF: fdt: Machine model: Raspberry Pi Model B+
18
...
19
20
[*] http://archive.raspberrypi.org/debian/pool/main/r/raspberrypi-firmware/raspberrypi-kernel_1.20200512-2_armhf.deb
21
22
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
23
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
24
Message-id: 20201024170127.3592182-8-f4bug@amsat.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
25
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
26
---
11
target/arm/Makefile.objs | 5 +++--
27
hw/arm/raspi.c | 13 +++++++++++++
12
1 file changed, 3 insertions(+), 2 deletions(-)
28
1 file changed, 13 insertions(+)
13
29
14
diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
30
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
15
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/Makefile.objs
32
--- a/hw/arm/raspi.c
17
+++ b/target/arm/Makefile.objs
33
+++ b/hw/arm/raspi.c
18
@@ -XXX,XX +XXX,XX @@ obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
34
@@ -XXX,XX +XXX,XX @@ static void raspi_machine_class_common_init(MachineClass *mc,
19
obj-y += translate.o op_helper.o helper.o cpu.o
35
mc->default_ram_id = "ram";
20
obj-y += neon_helper.o iwmmxt_helper.o vec_helper.o vfp_helper.o
36
};
21
obj-y += gdbstub.o
37
22
-obj-$(TARGET_AARCH64) += cpu64.o translate-a64.o helper-a64.o gdbstub64.o
38
+static void raspi1ap_machine_class_init(ObjectClass *oc, void *data)
23
-obj-$(TARGET_AARCH64) += pauth_helper.o
39
+{
24
+obj-$(TARGET_AARCH64) += cpu64.o gdbstub64.o
40
+ MachineClass *mc = MACHINE_CLASS(oc);
25
obj-y += crypto_helper.o
41
+ RaspiMachineClass *rmc = RASPI_MACHINE_CLASS(oc);
26
obj-$(CONFIG_SOFTMMU) += arm-powerctl.o
42
+
27
43
+ rmc->board_rev = 0x900021; /* Revision 1.1 */
28
@@ -XXX,XX +XXX,XX @@ target/arm/translate-sve.o: target/arm/decode-sve.inc.c
44
+ raspi_machine_class_common_init(mc, rmc->board_rev);
29
target/arm/translate.o: target/arm/decode-vfp.inc.c
45
+};
30
target/arm/translate.o: target/arm/decode-vfp-uncond.inc.c
46
+
31
47
static void raspi2b_machine_class_init(ObjectClass *oc, void *data)
32
+obj-$(TARGET_AARCH64) += translate-a64.o helper-a64.o
48
{
33
obj-$(TARGET_AARCH64) += translate-sve.o sve_helper.o
49
MachineClass *mc = MACHINE_CLASS(oc);
34
+obj-$(TARGET_AARCH64) += pauth_helper.o
50
@@ -XXX,XX +XXX,XX @@ static void raspi3b_machine_class_init(ObjectClass *oc, void *data)
51
52
static const TypeInfo raspi_machine_types[] = {
53
{
54
+ .name = MACHINE_TYPE_NAME("raspi1ap"),
55
+ .parent = TYPE_RASPI_MACHINE,
56
+ .class_init = raspi1ap_machine_class_init,
57
+ }, {
58
.name = MACHINE_TYPE_NAME("raspi2b"),
59
.parent = TYPE_RASPI_MACHINE,
60
.class_init = raspi2b_machine_class_init,
35
--
61
--
36
2.20.1
62
2.20.1
37
63
38
64
diff view generated by jsdifflib
1
From: Cédric Le Goater <clg@kaod.org>
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
2
3
The RAM memory region is defined after the SoC is realized when the
3
Similarly to the Pi A, the Pi Zero uses a BCM2835 SoC (ARMv6Z core).
4
SDMC controller has checked that the defined RAM size for the machine
5
is correct. This is problematic for controller models requiring a link
6
on the RAM region, for DMA support in the SMC controller for instance.
7
4
8
Introduce a container memory region for the RAM that we can link into
5
The only difference between the revision 1.2 and 1.3 is the latter
9
the controllers early, before the SoC is realized. It will be
6
exposes a CSI camera connector. As we do not implement the Unicam
10
populated with the RAM region after the checks have be done.
7
peripheral, there is no point in exposing a camera connector :)
8
Therefore we choose to model the 1.2 revision.
11
9
12
Signed-off-by: Cédric Le Goater <clg@kaod.org>
10
Example booting the machine using content from [*]:
13
Reviewed-by: Joel Stanley <joel@jms.id.au>
11
14
Message-id: 20190618165311.27066-14-clg@kaod.org
12
$ qemu-system-arm -M raspi0 -serial stdio \
13
-kernel raspberrypi/firmware/boot/kernel.img \
14
-dtb raspberrypi/firmware/boot/bcm2708-rpi-zero.dtb \
15
-append 'printk.time=0 earlycon=pl011,0x20201000 console=ttyAMA0'
16
[ 0.000000] Booting Linux on physical CPU 0x0
17
[ 0.000000] Linux version 4.19.118+ (dom@buildbot) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611)) #1311 Mon Apr 27 14:16:15 BST 2020
18
[ 0.000000] CPU: ARMv6-compatible processor [410fb767] revision 7 (ARMv7), cr=00c5387d
19
[ 0.000000] CPU: VIPT aliasing data cache, unknown instruction cache
20
[ 0.000000] OF: fdt: Machine model: Raspberry Pi Zero
21
...
22
23
[*] http://archive.raspberrypi.org/debian/pool/main/r/raspberrypi-firmware/raspberrypi-kernel_1.20200512-2_armhf.deb
24
25
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
26
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
27
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
28
Message-id: 20201024170127.3592182-9-f4bug@amsat.org
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
29
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
---
30
---
17
hw/arm/aspeed.c | 13 +++++++++----
31
hw/arm/raspi.c | 13 +++++++++++++
18
1 file changed, 9 insertions(+), 4 deletions(-)
32
1 file changed, 13 insertions(+)
19
33
20
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
34
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
21
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
22
--- a/hw/arm/aspeed.c
36
--- a/hw/arm/raspi.c
23
+++ b/hw/arm/aspeed.c
37
+++ b/hw/arm/raspi.c
24
@@ -XXX,XX +XXX,XX @@ static struct arm_boot_info aspeed_board_binfo = {
38
@@ -XXX,XX +XXX,XX @@ static void raspi_machine_class_common_init(MachineClass *mc,
25
39
mc->default_ram_id = "ram";
26
struct AspeedBoardState {
27
AspeedSoCState soc;
28
+ MemoryRegion ram_container;
29
MemoryRegion ram;
30
MemoryRegion max_ram;
31
};
40
};
32
@@ -XXX,XX +XXX,XX @@ static void aspeed_board_init(MachineState *machine,
41
33
ram_addr_t max_ram_size;
42
+static void raspi0_machine_class_init(ObjectClass *oc, void *data)
34
43
+{
35
bmc = g_new0(AspeedBoardState, 1);
44
+ MachineClass *mc = MACHINE_CLASS(oc);
45
+ RaspiMachineClass *rmc = RASPI_MACHINE_CLASS(oc);
36
+
46
+
37
+ memory_region_init(&bmc->ram_container, NULL, "aspeed-ram-container",
47
+ rmc->board_rev = 0x920092; /* Revision 1.2 */
38
+ UINT32_MAX);
48
+ raspi_machine_class_common_init(mc, rmc->board_rev);
49
+};
39
+
50
+
40
object_initialize_child(OBJECT(machine), "soc", &bmc->soc,
51
static void raspi1ap_machine_class_init(ObjectClass *oc, void *data)
41
(sizeof(bmc->soc)), cfg->soc_name, &error_abort,
52
{
42
NULL);
53
MachineClass *mc = MACHINE_CLASS(oc);
43
@@ -XXX,XX +XXX,XX @@ static void aspeed_board_init(MachineState *machine,
54
@@ -XXX,XX +XXX,XX @@ static void raspi3b_machine_class_init(ObjectClass *oc, void *data)
44
&error_abort);
55
45
56
static const TypeInfo raspi_machine_types[] = {
46
memory_region_allocate_system_memory(&bmc->ram, NULL, "ram", ram_size);
57
{
47
+ memory_region_add_subregion(&bmc->ram_container, 0, &bmc->ram);
58
+ .name = MACHINE_TYPE_NAME("raspi0"),
48
memory_region_add_subregion(get_system_memory(),
59
+ .parent = TYPE_RASPI_MACHINE,
49
- sc->info->memmap[ASPEED_SDRAM], &bmc->ram);
60
+ .class_init = raspi0_machine_class_init,
50
+ sc->info->memmap[ASPEED_SDRAM],
61
+ }, {
51
+ &bmc->ram_container);
62
.name = MACHINE_TYPE_NAME("raspi1ap"),
52
63
.parent = TYPE_RASPI_MACHINE,
53
max_ram_size = object_property_get_uint(OBJECT(&bmc->soc), "max-ram-size",
64
.class_init = raspi1ap_machine_class_init,
54
&error_abort);
55
memory_region_init_io(&bmc->max_ram, NULL, &max_ram_ops, NULL,
56
"max_ram", max_ram_size - ram_size);
57
- memory_region_add_subregion(get_system_memory(),
58
- sc->info->memmap[ASPEED_SDRAM] + ram_size,
59
- &bmc->max_ram);
60
+ memory_region_add_subregion(&bmc->ram_container, ram_size, &bmc->max_ram);
61
62
aspeed_board_init_flashes(&bmc->soc.fmc, cfg->fmc_model, &error_abort);
63
aspeed_board_init_flashes(&bmc->soc.spi[0], cfg->spi_model, &error_abort);
64
--
65
--
65
2.20.1
66
2.20.1
66
67
67
68
diff view generated by jsdifflib
1
From: Jan Kiszka <jan.kiszka@siemens.com>
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
2
3
Allow cortex-a7 to be used with the virt board; it supports
3
The Pi 3A+ is a stripped down version of the 3B:
4
the v7VE features and there is no reason to deny this type.
4
- 512 MiB of RAM instead of 1 GiB
5
- no on-board ethernet chipset
5
6
6
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
7
Add it as it is a closer match to what we model.
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
8
Message-id: fc5404f7-4d1d-c28f-6e48-d8799c82acc0@web.de
9
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
11
Message-id: 20201024170127.3592182-10-f4bug@amsat.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
13
---
12
hw/arm/virt.c | 1 +
14
hw/arm/raspi.c | 13 +++++++++++++
13
1 file changed, 1 insertion(+)
15
1 file changed, 13 insertions(+)
14
16
15
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
17
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
16
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/arm/virt.c
19
--- a/hw/arm/raspi.c
18
+++ b/hw/arm/virt.c
20
+++ b/hw/arm/raspi.c
19
@@ -XXX,XX +XXX,XX @@ static const int a15irqmap[] = {
21
@@ -XXX,XX +XXX,XX @@ static void raspi2b_machine_class_init(ObjectClass *oc, void *data)
20
};
22
};
21
23
22
static const char *valid_cpus[] = {
24
#ifdef TARGET_AARCH64
23
+ ARM_CPU_TYPE_NAME("cortex-a7"),
25
+static void raspi3ap_machine_class_init(ObjectClass *oc, void *data)
24
ARM_CPU_TYPE_NAME("cortex-a15"),
26
+{
25
ARM_CPU_TYPE_NAME("cortex-a53"),
27
+ MachineClass *mc = MACHINE_CLASS(oc);
26
ARM_CPU_TYPE_NAME("cortex-a57"),
28
+ RaspiMachineClass *rmc = RASPI_MACHINE_CLASS(oc);
29
+
30
+ rmc->board_rev = 0x9020e0; /* Revision 1.0 */
31
+ raspi_machine_class_common_init(mc, rmc->board_rev);
32
+};
33
+
34
static void raspi3b_machine_class_init(ObjectClass *oc, void *data)
35
{
36
MachineClass *mc = MACHINE_CLASS(oc);
37
@@ -XXX,XX +XXX,XX @@ static const TypeInfo raspi_machine_types[] = {
38
.parent = TYPE_RASPI_MACHINE,
39
.class_init = raspi2b_machine_class_init,
40
#ifdef TARGET_AARCH64
41
+ }, {
42
+ .name = MACHINE_TYPE_NAME("raspi3ap"),
43
+ .parent = TYPE_RASPI_MACHINE,
44
+ .class_init = raspi3ap_machine_class_init,
45
}, {
46
.name = MACHINE_TYPE_NAME("raspi3b"),
47
.parent = TYPE_RASPI_MACHINE,
27
--
48
--
28
2.20.1
49
2.20.1
29
50
30
51
diff view generated by jsdifflib
1
From: Cédric Le Goater <clg@kaod.org>
1
From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
2
2
3
It has never been used as far as I can tell from the git history.
3
Use of 0x%d - make up our mind as 0x%x
4
4
5
Signed-off-by: Cédric Le Goater <clg@kaod.org>
5
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
6
Reviewed-by: Joel Stanley <joel@jms.id.au>
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Message-id: 20190618165311.27066-13-clg@kaod.org
7
Acked-by: Eric Auger <eric.auger@redhat.com>
8
Message-id: 20201014193355.53074-1-dgilbert@redhat.com
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
10
---
10
hw/arm/aspeed.c | 2 --
11
hw/arm/trace-events | 2 +-
11
1 file changed, 2 deletions(-)
12
1 file changed, 1 insertion(+), 1 deletion(-)
12
13
13
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
14
diff --git a/hw/arm/trace-events b/hw/arm/trace-events
14
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/arm/aspeed.c
16
--- a/hw/arm/trace-events
16
+++ b/hw/arm/aspeed.c
17
+++ b/hw/arm/trace-events
17
@@ -XXX,XX +XXX,XX @@ static void aspeed_board_init(MachineState *machine,
18
@@ -XXX,XX +XXX,XX @@ smmuv3_get_cd(uint64_t addr) "CD addr: 0x%"PRIx64
18
memory_region_allocate_system_memory(&bmc->ram, NULL, "ram", ram_size);
19
smmuv3_decode_cd(uint32_t oas) "oas=%d"
19
memory_region_add_subregion(get_system_memory(),
20
smmuv3_decode_cd_tt(int i, uint32_t tsz, uint64_t ttb, uint32_t granule_sz, bool had) "TT[%d]:tsz:%d ttb:0x%"PRIx64" granule_sz:%d had:%d"
20
sc->info->memmap[ASPEED_SDRAM], &bmc->ram);
21
smmuv3_cmdq_cfgi_ste(int streamid) "streamid =%d"
21
- object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram),
22
-smmuv3_cmdq_cfgi_ste_range(int start, int end) "start=0x%d - end=0x%d"
22
- &error_abort);
23
+smmuv3_cmdq_cfgi_ste_range(int start, int end) "start=0x%x - end=0x%x"
23
24
smmuv3_cmdq_cfgi_cd(uint32_t sid) "streamid = %d"
24
max_ram_size = object_property_get_uint(OBJECT(&bmc->soc), "max-ram-size",
25
smmuv3_config_cache_hit(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache HIT for sid %d (hits=%d, misses=%d, hit rate=%d)"
25
&error_abort);
26
smmuv3_config_cache_miss(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache MISS for sid %d (hits=%d, misses=%d, hit rate=%d)"
26
--
27
--
27
2.20.1
28
2.20.1
28
29
29
30
diff view generated by jsdifflib
1
From: Christian Svensson <bluecmd@google.com>
1
From: Luc Michel <luc@lmichel.fr>
2
2
3
If the host decrements the counter register that results in a negative
3
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
4
delta. This is then passed to muldiv64 which only handles unsigned
4
Reviewed-by: Damien Hedde <damien.hedde@greensocs.com>
5
numbers resulting in bogus results.
5
Signed-off-by: Luc Michel <luc@lmichel.fr>
6
6
Tested-by: Guenter Roeck <linux@roeck-us.net>
7
This fix ensures the delta being operated on is positive.
7
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
9
Test case: kexec a kernel using aspeed_timer and it will freeze on the
10
second bootup when the kernel initializes the timer. With this patch
11
that no longer happens and the timer appears to run OK.
12
13
Signed-off-by: Christian Svensson <bluecmd@google.com>
14
Signed-off-by: Cédric Le Goater <clg@kaod.org>
15
Reviewed-by: Joel Stanley <joel@jms.id.au>
16
Reviewed-by: Andrew Jeffery <andrew@aj.id.au>
17
Message-id: 20190618165311.27066-12-clg@kaod.org
18
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
19
---
9
---
20
hw/timer/aspeed_timer.c | 6 +++++-
10
include/hw/clock.h | 5 +++++
21
1 file changed, 5 insertions(+), 1 deletion(-)
11
1 file changed, 5 insertions(+)
22
12
23
diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c
13
diff --git a/include/hw/clock.h b/include/hw/clock.h
24
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
25
--- a/hw/timer/aspeed_timer.c
15
--- a/include/hw/clock.h
26
+++ b/hw/timer/aspeed_timer.c
16
+++ b/include/hw/clock.h
27
@@ -XXX,XX +XXX,XX @@ static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg,
17
@@ -XXX,XX +XXX,XX @@ extern const VMStateDescription vmstate_clock;
28
int64_t delta = (int64_t) value - (int64_t) calculate_ticks(t, now);
18
VMSTATE_CLOCK_V(field, state, 0)
29
uint32_t rate = calculate_rate(t);
19
#define VMSTATE_CLOCK_V(field, state, version) \
30
20
VMSTATE_STRUCT_POINTER_V(field, state, version, vmstate_clock, Clock)
31
- t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate);
21
+#define VMSTATE_ARRAY_CLOCK(field, state, num) \
32
+ if (delta >= 0) {
22
+ VMSTATE_ARRAY_CLOCK_V(field, state, num, 0)
33
+ t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate);
23
+#define VMSTATE_ARRAY_CLOCK_V(field, state, num, version) \
34
+ } else {
24
+ VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(field, state, num, version, \
35
+ t->start -= muldiv64(-delta, NANOSECONDS_PER_SECOND, rate);
25
+ vmstate_clock, Clock)
36
+ }
26
37
aspeed_timer_mod(t);
27
/**
38
}
28
* clock_setup_canonical_path:
39
break;
40
--
29
--
41
2.20.1
30
2.20.1
42
31
43
32
diff view generated by jsdifflib
1
From: Andrew Jeffery <andrew@aj.id.au>
1
From: Luc Michel <luc@lmichel.fr>
2
2
3
From the datasheet:
3
The nanosecond unit greatly limits the dynamic range we can display in
4
clock value traces, for values in the order of 1GHz and more. The
5
internal representation can go way beyond this value and it is quite
6
common for today's clocks to be within those ranges.
4
7
5
This register stores the current status of counter #N. When timer
8
For example, a frequency between 500MHz+ and 1GHz will be displayed as
6
enable bit TMC30[N * b] is disabled, the reload register will be
9
1ns. Beyond 1GHz, it will show up as 0ns.
7
loaded into this counter. When timer bit TMC30[N * b] is set, the
8
counter will start to decrement. CPU can update this register value
9
when enable bit is set.
10
10
11
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
11
Replace nanosecond periods traces with frequencies in the Hz unit
12
Signed-off-by: Cédric Le Goater <clg@kaod.org>
12
to have more dynamic range in the trace output.
13
Reviewed-by: Joel Stanley <joel@jms.id.au>
13
14
Message-id: 20190618165311.27066-9-clg@kaod.org
14
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
15
Reviewed-by: Damien Hedde <damien.hedde@greensocs.com>
16
Signed-off-by: Luc Michel <luc@lmichel.fr>
17
Tested-by: Guenter Roeck <linux@roeck-us.net>
18
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
19
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
---
20
---
17
hw/timer/aspeed_timer.c | 6 +++++-
21
hw/core/clock.c | 6 +++---
18
1 file changed, 5 insertions(+), 1 deletion(-)
22
hw/core/trace-events | 4 ++--
23
2 files changed, 5 insertions(+), 5 deletions(-)
19
24
20
diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c
25
diff --git a/hw/core/clock.c b/hw/core/clock.c
21
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
22
--- a/hw/timer/aspeed_timer.c
27
--- a/hw/core/clock.c
23
+++ b/hw/timer/aspeed_timer.c
28
+++ b/hw/core/clock.c
24
@@ -XXX,XX +XXX,XX @@ static uint64_t aspeed_timer_get_value(AspeedTimer *t, int reg)
29
@@ -XXX,XX +XXX,XX @@ bool clock_set(Clock *clk, uint64_t period)
25
30
if (clk->period == period) {
26
switch (reg) {
31
return false;
27
case TIMER_REG_STATUS:
32
}
28
- value = calculate_ticks(t, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
33
- trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_NS(clk->period),
29
+ if (timer_enabled(t)) {
34
- CLOCK_PERIOD_TO_NS(period));
30
+ value = calculate_ticks(t, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
35
+ trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_HZ(clk->period),
31
+ } else {
36
+ CLOCK_PERIOD_TO_HZ(period));
32
+ value = t->reload;
37
clk->period = period;
33
+ }
38
34
break;
39
return true;
35
case TIMER_REG_RELOAD:
40
@@ -XXX,XX +XXX,XX @@ static void clock_propagate_period(Clock *clk, bool call_callbacks)
36
value = t->reload;
41
if (child->period != clk->period) {
42
child->period = clk->period;
43
trace_clock_update(CLOCK_PATH(child), CLOCK_PATH(clk),
44
- CLOCK_PERIOD_TO_NS(clk->period),
45
+ CLOCK_PERIOD_TO_HZ(clk->period),
46
call_callbacks);
47
if (call_callbacks && child->callback) {
48
child->callback(child->callback_opaque);
49
diff --git a/hw/core/trace-events b/hw/core/trace-events
50
index XXXXXXX..XXXXXXX 100644
51
--- a/hw/core/trace-events
52
+++ b/hw/core/trace-events
53
@@ -XXX,XX +XXX,XX @@ resettable_transitional_function(void *obj, const char *objtype) "obj=%p(%s)"
54
# clock.c
55
clock_set_source(const char *clk, const char *src) "'%s', src='%s'"
56
clock_disconnect(const char *clk) "'%s'"
57
-clock_set(const char *clk, uint64_t old, uint64_t new) "'%s', ns=%"PRIu64"->%"PRIu64
58
+clock_set(const char *clk, uint64_t old, uint64_t new) "'%s', %"PRIu64"Hz->%"PRIu64"Hz"
59
clock_propagate(const char *clk) "'%s'"
60
-clock_update(const char *clk, const char *src, uint64_t val, int cb) "'%s', src='%s', ns=%"PRIu64", cb=%d"
61
+clock_update(const char *clk, const char *src, uint64_t hz, int cb) "'%s', src='%s', val=%"PRIu64"Hz cb=%d"
37
--
62
--
38
2.20.1
63
2.20.1
39
64
40
65
diff view generated by jsdifflib
1
From: Joel Stanley <joel@jms.id.au>
1
From: Luc Michel <luc@lmichel.fr>
2
2
3
All systems have an RTC.
3
The CPRMAN (clock controller) was mapped at the watchdog/power manager
4
address. It was also split into two unimplemented peripherals (CM and
5
A2W) but this is really the same one, as shown by this extract of the
6
Raspberry Pi 3 Linux device tree:
4
7
5
The IRQ is hooked up but the model does not use it at this stage. There
8
watchdog@7e100000 {
6
is no guest code that uses it, so this limitation is acceptable.
9
compatible = "brcm,bcm2835-pm\0brcm,bcm2835-pm-wdt";
10
[...]
11
reg = <0x7e100000 0x114 0x7e00a000 0x24>;
12
[...]
13
};
7
14
8
Signed-off-by: Joel Stanley <joel@jms.id.au>
15
[...]
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
16
cprman@7e101000 {
10
Message-id: 20190618165311.27066-5-clg@kaod.org
17
compatible = "brcm,bcm2835-cprman";
18
[...]
19
reg = <0x7e101000 0x2000>;
20
[...]
21
};
22
23
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
24
Signed-off-by: Luc Michel <luc@lmichel.fr>
25
Tested-by: Guenter Roeck <linux@roeck-us.net>
26
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
27
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
28
---
13
include/hw/arm/aspeed_soc.h | 2 ++
29
include/hw/arm/bcm2835_peripherals.h | 2 +-
14
hw/arm/aspeed_soc.c | 13 +++++++++++++
30
include/hw/arm/raspi_platform.h | 5 ++---
15
2 files changed, 15 insertions(+)
31
hw/arm/bcm2835_peripherals.c | 4 ++--
32
3 files changed, 5 insertions(+), 6 deletions(-)
16
33
17
diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h
34
diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h
18
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
19
--- a/include/hw/arm/aspeed_soc.h
36
--- a/include/hw/arm/bcm2835_peripherals.h
20
+++ b/include/hw/arm/aspeed_soc.h
37
+++ b/include/hw/arm/bcm2835_peripherals.h
38
@@ -XXX,XX +XXX,XX @@ struct BCM2835PeripheralState {
39
BCM2835MphiState mphi;
40
UnimplementedDeviceState txp;
41
UnimplementedDeviceState armtmr;
42
+ UnimplementedDeviceState powermgt;
43
UnimplementedDeviceState cprman;
44
- UnimplementedDeviceState a2w;
45
PL011State uart0;
46
BCM2835AuxState aux;
47
BCM2835FBState fb;
48
diff --git a/include/hw/arm/raspi_platform.h b/include/hw/arm/raspi_platform.h
49
index XXXXXXX..XXXXXXX 100644
50
--- a/include/hw/arm/raspi_platform.h
51
+++ b/include/hw/arm/raspi_platform.h
21
@@ -XXX,XX +XXX,XX @@
52
@@ -XXX,XX +XXX,XX @@
22
#include "hw/misc/aspeed_scu.h"
53
#define ARMCTRL_TIMER0_1_OFFSET (ARM_OFFSET + 0x400) /* Timer 0 and 1 (SP804) */
23
#include "hw/misc/aspeed_sdmc.h"
54
#define ARMCTRL_0_SBM_OFFSET (ARM_OFFSET + 0x800) /* User 0 (ARM) Semaphores
24
#include "hw/timer/aspeed_timer.h"
55
* Doorbells & Mailboxes */
25
+#include "hw/timer/aspeed_rtc.h"
56
-#define CPRMAN_OFFSET 0x100000 /* Power Management, Watchdog */
26
#include "hw/i2c/aspeed_i2c.h"
57
-#define CM_OFFSET 0x101000 /* Clock Management */
27
#include "hw/ssi/aspeed_smc.h"
58
-#define A2W_OFFSET 0x102000 /* Reset controller */
28
#include "hw/watchdog/wdt_aspeed.h"
59
+#define PM_OFFSET 0x100000 /* Power Management */
29
@@ -XXX,XX +XXX,XX @@ typedef struct AspeedSoCState {
60
+#define CPRMAN_OFFSET 0x101000 /* Clock Management */
30
ARMCPU cpu;
61
#define AVS_OFFSET 0x103000 /* Audio Video Standard */
31
MemoryRegion sram;
62
#define RNG_OFFSET 0x104000
32
AspeedVICState vic;
63
#define GPIO_OFFSET 0x200000
33
+ AspeedRtcState rtc;
64
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
34
AspeedTimerCtrlState timerctrl;
35
AspeedI2CState i2c;
36
AspeedSCUState scu;
37
diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c
38
index XXXXXXX..XXXXXXX 100644
65
index XXXXXXX..XXXXXXX 100644
39
--- a/hw/arm/aspeed_soc.c
66
--- a/hw/arm/bcm2835_peripherals.c
40
+++ b/hw/arm/aspeed_soc.c
67
+++ b/hw/arm/bcm2835_peripherals.c
41
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_init(Object *obj)
68
@@ -XXX,XX +XXX,XX @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
42
sysbus_init_child_obj(obj, "vic", OBJECT(&s->vic), sizeof(s->vic),
69
43
TYPE_ASPEED_VIC);
70
create_unimp(s, &s->txp, "bcm2835-txp", TXP_OFFSET, 0x1000);
44
71
create_unimp(s, &s->armtmr, "bcm2835-sp804", ARMCTRL_TIMER0_1_OFFSET, 0x40);
45
+ sysbus_init_child_obj(obj, "rtc", OBJECT(&s->rtc), sizeof(s->rtc),
72
- create_unimp(s, &s->cprman, "bcm2835-cprman", CPRMAN_OFFSET, 0x1000);
46
+ TYPE_ASPEED_RTC);
73
- create_unimp(s, &s->a2w, "bcm2835-a2w", A2W_OFFSET, 0x1000);
47
+
74
+ create_unimp(s, &s->powermgt, "bcm2835-powermgt", PM_OFFSET, 0x114);
48
sysbus_init_child_obj(obj, "timerctrl", OBJECT(&s->timerctrl),
75
+ create_unimp(s, &s->cprman, "bcm2835-cprman", CPRMAN_OFFSET, 0x2000);
49
sizeof(s->timerctrl), TYPE_ASPEED_TIMER);
76
create_unimp(s, &s->i2s, "bcm2835-i2s", I2S_OFFSET, 0x100);
50
object_property_add_const_link(OBJECT(&s->timerctrl), "scu",
77
create_unimp(s, &s->smi, "bcm2835-smi", SMI_OFFSET, 0x100);
51
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
78
create_unimp(s, &s->spi[0], "bcm2835-spi0", SPI0_OFFSET, 0x20);
52
sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 1,
53
qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ));
54
55
+ /* RTC */
56
+ object_property_set_bool(OBJECT(&s->rtc), true, "realized", &err);
57
+ if (err) {
58
+ error_propagate(errp, err);
59
+ return;
60
+ }
61
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->rtc), 0, sc->info->memmap[ASPEED_RTC]);
62
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->rtc), 0,
63
+ aspeed_soc_get_irq(s, ASPEED_RTC));
64
+
65
/* Timer */
66
object_property_set_bool(OBJECT(&s->timerctrl), true, "realized", &err);
67
if (err) {
68
--
79
--
69
2.20.1
80
2.20.1
70
81
71
82
diff view generated by jsdifflib
1
From: Joel Stanley <joel@jms.id.au>
1
From: Luc Michel <luc@lmichel.fr>
2
2
3
The RTC is modeled to provide time and date functionality. It is
3
The BCM2835 CPRMAN is the clock manager of the SoC. It is composed of a
4
initialised at zero to match the hardware.
4
main oscillator, and several sub-components (PLLs, multiplexers, ...) to
5
5
generate the BCM2835 clock tree.
6
There is no modelling of the alarm functionality, which includes the IRQ
6
7
line. As there is no guest code to exercise this function that is
7
This commit adds a skeleton of the CPRMAN, with a dummy register
8
acceptable for now.
8
read/write implementation. It embeds the main oscillator (xosc) from
9
9
which all the clocks will be derived.
10
Signed-off-by: Joel Stanley <joel@jms.id.au>
10
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
12
Message-id: 20190618165311.27066-4-clg@kaod.org
12
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
13
Signed-off-by: Luc Michel <luc@lmichel.fr>
14
Tested-by: Guenter Roeck <linux@roeck-us.net>
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
---
16
---
15
hw/timer/Makefile.objs | 2 +-
17
include/hw/arm/bcm2835_peripherals.h | 3 +-
16
include/hw/timer/aspeed_rtc.h | 31 ++++++
18
include/hw/misc/bcm2835_cprman.h | 37 +++++
17
hw/timer/aspeed_rtc.c | 180 ++++++++++++++++++++++++++++++++++
19
include/hw/misc/bcm2835_cprman_internals.h | 24 +++
18
hw/timer/trace-events | 4 +
20
hw/arm/bcm2835_peripherals.c | 11 +-
19
4 files changed, 216 insertions(+), 1 deletion(-)
21
hw/misc/bcm2835_cprman.c | 163 +++++++++++++++++++++
20
create mode 100644 include/hw/timer/aspeed_rtc.h
22
hw/misc/meson.build | 1 +
21
create mode 100644 hw/timer/aspeed_rtc.c
23
hw/misc/trace-events | 5 +
22
24
7 files changed, 242 insertions(+), 2 deletions(-)
23
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
25
create mode 100644 include/hw/misc/bcm2835_cprman.h
26
create mode 100644 include/hw/misc/bcm2835_cprman_internals.h
27
create mode 100644 hw/misc/bcm2835_cprman.c
28
29
diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h
24
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
25
--- a/hw/timer/Makefile.objs
31
--- a/include/hw/arm/bcm2835_peripherals.h
26
+++ b/hw/timer/Makefile.objs
32
+++ b/include/hw/arm/bcm2835_peripherals.h
27
@@ -XXX,XX +XXX,XX @@ obj-$(CONFIG_MC146818RTC) += mc146818rtc.o
33
@@ -XXX,XX +XXX,XX @@
28
obj-$(CONFIG_ALLWINNER_A10_PIT) += allwinner-a10-pit.o
34
#include "hw/misc/bcm2835_mbox.h"
29
35
#include "hw/misc/bcm2835_mphi.h"
30
common-obj-$(CONFIG_STM32F2XX_TIMER) += stm32f2xx_timer.o
36
#include "hw/misc/bcm2835_thermal.h"
31
-common-obj-$(CONFIG_ASPEED_SOC) += aspeed_timer.o
37
+#include "hw/misc/bcm2835_cprman.h"
32
+common-obj-$(CONFIG_ASPEED_SOC) += aspeed_timer.o aspeed_rtc.o
38
#include "hw/sd/sdhci.h"
33
39
#include "hw/sd/bcm2835_sdhost.h"
34
common-obj-$(CONFIG_SUN4V_RTC) += sun4v-rtc.o
40
#include "hw/gpio/bcm2835_gpio.h"
35
common-obj-$(CONFIG_CMSDK_APB_TIMER) += cmsdk-apb-timer.o
41
@@ -XXX,XX +XXX,XX @@ struct BCM2835PeripheralState {
36
diff --git a/include/hw/timer/aspeed_rtc.h b/include/hw/timer/aspeed_rtc.h
42
UnimplementedDeviceState txp;
43
UnimplementedDeviceState armtmr;
44
UnimplementedDeviceState powermgt;
45
- UnimplementedDeviceState cprman;
46
+ BCM2835CprmanState cprman;
47
PL011State uart0;
48
BCM2835AuxState aux;
49
BCM2835FBState fb;
50
diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h
37
new file mode 100644
51
new file mode 100644
38
index XXXXXXX..XXXXXXX
52
index XXXXXXX..XXXXXXX
39
--- /dev/null
53
--- /dev/null
40
+++ b/include/hw/timer/aspeed_rtc.h
54
+++ b/include/hw/misc/bcm2835_cprman.h
41
@@ -XXX,XX +XXX,XX @@
55
@@ -XXX,XX +XXX,XX @@
42
+/*
56
+/*
43
+ * ASPEED Real Time Clock
57
+ * BCM2835 CPRMAN clock manager
44
+ * Joel Stanley <joel@jms.id.au>
58
+ *
45
+ *
59
+ * Copyright (c) 2020 Luc Michel <luc@lmichel.fr>
46
+ * Copyright 2019 IBM Corp
60
+ *
47
+ * SPDX-License-Identifier: GPL-2.0-or-later
61
+ * SPDX-License-Identifier: GPL-2.0-or-later
48
+ */
62
+ */
49
+#ifndef ASPEED_RTC_H
63
+
50
+#define ASPEED_RTC_H
64
+#ifndef HW_MISC_CPRMAN_H
51
+
65
+#define HW_MISC_CPRMAN_H
52
+#include <stdint.h>
66
+
53
+
54
+#include "hw/hw.h"
55
+#include "hw/irq.h"
56
+#include "hw/sysbus.h"
67
+#include "hw/sysbus.h"
57
+
68
+#include "hw/qdev-clock.h"
58
+typedef struct AspeedRtcState {
69
+
70
+#define TYPE_BCM2835_CPRMAN "bcm2835-cprman"
71
+
72
+typedef struct BCM2835CprmanState BCM2835CprmanState;
73
+
74
+DECLARE_INSTANCE_CHECKER(BCM2835CprmanState, CPRMAN,
75
+ TYPE_BCM2835_CPRMAN)
76
+
77
+#define CPRMAN_NUM_REGS (0x2000 / sizeof(uint32_t))
78
+
79
+struct BCM2835CprmanState {
80
+ /*< private >*/
59
+ SysBusDevice parent_obj;
81
+ SysBusDevice parent_obj;
60
+
82
+
83
+ /*< public >*/
61
+ MemoryRegion iomem;
84
+ MemoryRegion iomem;
62
+ qemu_irq irq;
85
+
63
+
86
+ uint32_t regs[CPRMAN_NUM_REGS];
64
+ uint32_t reg[0x18];
87
+ uint32_t xosc_freq;
65
+ int offset;
88
+
66
+
89
+ Clock *xosc;
67
+} AspeedRtcState;
90
+};
68
+
91
+
69
+#define TYPE_ASPEED_RTC "aspeed.rtc"
92
+#endif
70
+#define ASPEED_RTC(obj) OBJECT_CHECK(AspeedRtcState, (obj), TYPE_ASPEED_RTC)
93
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
71
+
72
+#endif /* ASPEED_RTC_H */
73
diff --git a/hw/timer/aspeed_rtc.c b/hw/timer/aspeed_rtc.c
74
new file mode 100644
94
new file mode 100644
75
index XXXXXXX..XXXXXXX
95
index XXXXXXX..XXXXXXX
76
--- /dev/null
96
--- /dev/null
77
+++ b/hw/timer/aspeed_rtc.c
97
+++ b/include/hw/misc/bcm2835_cprman_internals.h
78
@@ -XXX,XX +XXX,XX @@
98
@@ -XXX,XX +XXX,XX @@
79
+/*
99
+/*
80
+ * ASPEED Real Time Clock
100
+ * BCM2835 CPRMAN clock manager
81
+ * Joel Stanley <joel@jms.id.au>
101
+ *
82
+ *
102
+ * Copyright (c) 2020 Luc Michel <luc@lmichel.fr>
83
+ * Copyright 2019 IBM Corp
103
+ *
84
+ * SPDX-License-Identifier: GPL-2.0-or-later
104
+ * SPDX-License-Identifier: GPL-2.0-or-later
85
+ */
105
+ */
86
+
106
+
107
+#ifndef HW_MISC_CPRMAN_INTERNALS_H
108
+#define HW_MISC_CPRMAN_INTERNALS_H
109
+
110
+#include "hw/registerfields.h"
111
+#include "hw/misc/bcm2835_cprman.h"
112
+
113
+/* Register map */
114
+
115
+/*
116
+ * This field is common to all registers. Each register write value must match
117
+ * the CPRMAN_PASSWORD magic value in its 8 MSB.
118
+ */
119
+FIELD(CPRMAN, PASSWORD, 24, 8)
120
+#define CPRMAN_PASSWORD 0x5a
121
+
122
+#endif
123
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
124
index XXXXXXX..XXXXXXX 100644
125
--- a/hw/arm/bcm2835_peripherals.c
126
+++ b/hw/arm/bcm2835_peripherals.c
127
@@ -XXX,XX +XXX,XX @@ static void bcm2835_peripherals_init(Object *obj)
128
/* DWC2 */
129
object_initialize_child(obj, "dwc2", &s->dwc2, TYPE_DWC2_USB);
130
131
+ /* CPRMAN clock manager */
132
+ object_initialize_child(obj, "cprman", &s->cprman, TYPE_BCM2835_CPRMAN);
133
+
134
object_property_add_const_link(OBJECT(&s->dwc2), "dma-mr",
135
OBJECT(&s->gpu_bus_mr));
136
}
137
@@ -XXX,XX +XXX,XX @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
138
return;
139
}
140
141
+ /* CPRMAN clock manager */
142
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->cprman), errp)) {
143
+ return;
144
+ }
145
+ memory_region_add_subregion(&s->peri_mr, CPRMAN_OFFSET,
146
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cprman), 0));
147
+
148
memory_region_add_subregion(&s->peri_mr, ARMCTRL_IC_OFFSET,
149
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->ic), 0));
150
sysbus_pass_irq(SYS_BUS_DEVICE(s), SYS_BUS_DEVICE(&s->ic));
151
@@ -XXX,XX +XXX,XX @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
152
create_unimp(s, &s->txp, "bcm2835-txp", TXP_OFFSET, 0x1000);
153
create_unimp(s, &s->armtmr, "bcm2835-sp804", ARMCTRL_TIMER0_1_OFFSET, 0x40);
154
create_unimp(s, &s->powermgt, "bcm2835-powermgt", PM_OFFSET, 0x114);
155
- create_unimp(s, &s->cprman, "bcm2835-cprman", CPRMAN_OFFSET, 0x2000);
156
create_unimp(s, &s->i2s, "bcm2835-i2s", I2S_OFFSET, 0x100);
157
create_unimp(s, &s->smi, "bcm2835-smi", SMI_OFFSET, 0x100);
158
create_unimp(s, &s->spi[0], "bcm2835-spi0", SPI0_OFFSET, 0x20);
159
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
160
new file mode 100644
161
index XXXXXXX..XXXXXXX
162
--- /dev/null
163
+++ b/hw/misc/bcm2835_cprman.c
164
@@ -XXX,XX +XXX,XX @@
165
+/*
166
+ * BCM2835 CPRMAN clock manager
167
+ *
168
+ * Copyright (c) 2020 Luc Michel <luc@lmichel.fr>
169
+ *
170
+ * SPDX-License-Identifier: GPL-2.0-or-later
171
+ */
172
+
173
+/*
174
+ * This peripheral is roughly divided into 3 main parts:
175
+ * - the PLLs
176
+ * - the PLL channels
177
+ * - the clock muxes
178
+ *
179
+ * A main oscillator (xosc) feeds all the PLLs. Each PLLs has one or more
180
+ * channels. Those channel are then connected to the clock muxes. Each mux has
181
+ * multiples sources (usually the xosc, some of the PLL channels and some "test
182
+ * debug" clocks). A mux is configured to select a given source through its
183
+ * control register. Each mux has one output clock that also goes out of the
184
+ * CPRMAN. This output clock usually connects to another peripheral in the SoC
185
+ * (so a given mux is dedicated to a peripheral).
186
+ *
187
+ * At each level (PLL, channel and mux), the clock can be altered through
188
+ * dividers (and multipliers in case of the PLLs), and can be disabled (in this
189
+ * case, the next levels see no clock).
190
+ *
191
+ * This can be sum-up as follows (this is an example and not the actual BCM2835
192
+ * clock tree):
193
+ *
194
+ * /-->[PLL]-|->[PLL channel]--... [mux]--> to peripherals
195
+ * | |->[PLL channel] muxes takes [mux]
196
+ * | \->[PLL channel] inputs from [mux]
197
+ * | some channels [mux]
198
+ * [xosc]---|-->[PLL]-|->[PLL channel] and other srcs [mux]
199
+ * | \->[PLL channel] ...-->[mux]
200
+ * | [mux]
201
+ * \-->[PLL]--->[PLL channel] [mux]
202
+ *
203
+ * The page at https://elinux.org/The_Undocumented_Pi gives the actual clock
204
+ * tree configuration.
205
+ */
206
+
87
+#include "qemu/osdep.h"
207
+#include "qemu/osdep.h"
88
+#include "qemu-common.h"
89
+#include "hw/timer/aspeed_rtc.h"
90
+#include "qemu/log.h"
208
+#include "qemu/log.h"
91
+#include "qemu/timer.h"
209
+#include "migration/vmstate.h"
92
+
210
+#include "hw/qdev-properties.h"
211
+#include "hw/misc/bcm2835_cprman.h"
212
+#include "hw/misc/bcm2835_cprman_internals.h"
93
+#include "trace.h"
213
+#include "trace.h"
94
+
214
+
95
+#define COUNTER1 (0x00 / 4)
215
+/* CPRMAN "top level" model */
96
+#define COUNTER2 (0x04 / 4)
216
+
97
+#define ALARM (0x08 / 4)
217
+static uint64_t cprman_read(void *opaque, hwaddr offset,
98
+#define CONTROL (0x10 / 4)
218
+ unsigned size)
99
+#define ALARM_STATUS (0x14 / 4)
219
+{
100
+
220
+ BCM2835CprmanState *s = CPRMAN(opaque);
101
+#define RTC_UNLOCKED BIT(1)
221
+ uint64_t r = 0;
102
+#define RTC_ENABLED BIT(0)
222
+ size_t idx = offset / sizeof(uint32_t);
103
+
223
+
104
+static void aspeed_rtc_calc_offset(AspeedRtcState *rtc)
224
+ switch (idx) {
105
+{
106
+ struct tm tm;
107
+ uint32_t year, cent;
108
+ uint32_t reg1 = rtc->reg[COUNTER1];
109
+ uint32_t reg2 = rtc->reg[COUNTER2];
110
+
111
+ tm.tm_mday = (reg1 >> 24) & 0x1f;
112
+ tm.tm_hour = (reg1 >> 16) & 0x1f;
113
+ tm.tm_min = (reg1 >> 8) & 0x3f;
114
+ tm.tm_sec = (reg1 >> 0) & 0x3f;
115
+
116
+ cent = (reg2 >> 16) & 0x1f;
117
+ year = (reg2 >> 8) & 0x7f;
118
+ tm.tm_mon = ((reg2 >> 0) & 0x0f) - 1;
119
+ tm.tm_year = year + (cent * 100) - 1900;
120
+
121
+ rtc->offset = qemu_timedate_diff(&tm);
122
+}
123
+
124
+static uint32_t aspeed_rtc_get_counter(AspeedRtcState *rtc, int r)
125
+{
126
+ uint32_t year, cent;
127
+ struct tm now;
128
+
129
+ qemu_get_timedate(&now, rtc->offset);
130
+
131
+ switch (r) {
132
+ case COUNTER1:
133
+ return (now.tm_mday << 24) | (now.tm_hour << 16) |
134
+ (now.tm_min << 8) | now.tm_sec;
135
+ case COUNTER2:
136
+ cent = (now.tm_year + 1900) / 100;
137
+ year = now.tm_year % 100;
138
+ return ((cent & 0x1f) << 16) | ((year & 0x7f) << 8) |
139
+ ((now.tm_mon + 1) & 0xf);
140
+ default:
225
+ default:
141
+ g_assert_not_reached();
226
+ r = s->regs[idx];
142
+ }
227
+ }
143
+}
228
+
144
+
229
+ trace_bcm2835_cprman_read(offset, r);
145
+static uint64_t aspeed_rtc_read(void *opaque, hwaddr addr,
230
+ return r;
146
+ unsigned size)
231
+}
147
+{
232
+
148
+ AspeedRtcState *rtc = opaque;
233
+static void cprman_write(void *opaque, hwaddr offset,
149
+ uint64_t val;
234
+ uint64_t value, unsigned size)
150
+ uint32_t r = addr >> 2;
235
+{
151
+
236
+ BCM2835CprmanState *s = CPRMAN(opaque);
152
+ switch (r) {
237
+ size_t idx = offset / sizeof(uint32_t);
153
+ case COUNTER1:
238
+
154
+ case COUNTER2:
239
+ if (FIELD_EX32(value, CPRMAN, PASSWORD) != CPRMAN_PASSWORD) {
155
+ if (rtc->reg[CONTROL] & RTC_ENABLED) {
240
+ trace_bcm2835_cprman_write_invalid_magic(offset, value);
156
+ rtc->reg[r] = aspeed_rtc_get_counter(rtc, r);
241
+ return;
157
+ }
158
+ /* fall through */
159
+ case CONTROL:
160
+ val = rtc->reg[r];
161
+ break;
162
+ case ALARM:
163
+ case ALARM_STATUS:
164
+ default:
165
+ qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx "\n", __func__, addr);
166
+ return 0;
167
+ }
242
+ }
168
+
243
+
169
+ trace_aspeed_rtc_read(addr, val);
244
+ value &= ~R_CPRMAN_PASSWORD_MASK;
170
+
245
+
171
+ return val;
246
+ trace_bcm2835_cprman_write(offset, value);
172
+}
247
+ s->regs[idx] = value;
173
+
248
+
174
+static void aspeed_rtc_write(void *opaque, hwaddr addr,
249
+}
175
+ uint64_t val, unsigned size)
250
+
176
+{
251
+static const MemoryRegionOps cprman_ops = {
177
+ AspeedRtcState *rtc = opaque;
252
+ .read = cprman_read,
178
+ uint32_t r = addr >> 2;
253
+ .write = cprman_write,
179
+
254
+ .endianness = DEVICE_LITTLE_ENDIAN,
180
+ switch (r) {
255
+ .valid = {
181
+ case COUNTER1:
256
+ /*
182
+ case COUNTER2:
257
+ * Although this hasn't been checked against real hardware, nor the
183
+ if (!(rtc->reg[CONTROL] & RTC_UNLOCKED)) {
258
+ * information can be found in a datasheet, it seems reasonable because
184
+ break;
259
+ * of the "PASSWORD" magic value found in every registers.
185
+ }
260
+ */
186
+ /* fall through */
261
+ .min_access_size = 4,
187
+ case CONTROL:
262
+ .max_access_size = 4,
188
+ rtc->reg[r] = val;
263
+ .unaligned = false,
189
+ aspeed_rtc_calc_offset(rtc);
264
+ },
190
+ break;
265
+ .impl = {
191
+ case ALARM:
266
+ .max_access_size = 4,
192
+ case ALARM_STATUS:
267
+ },
193
+ default:
268
+};
194
+ qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx "\n", __func__, addr);
269
+
195
+ break;
270
+static void cprman_reset(DeviceState *dev)
196
+ }
271
+{
197
+ trace_aspeed_rtc_write(addr, val);
272
+ BCM2835CprmanState *s = CPRMAN(dev);
198
+}
273
+
199
+
274
+ memset(s->regs, 0, sizeof(s->regs));
200
+static void aspeed_rtc_reset(DeviceState *d)
275
+
201
+{
276
+ clock_update_hz(s->xosc, s->xosc_freq);
202
+ AspeedRtcState *rtc = ASPEED_RTC(d);
277
+}
203
+
278
+
204
+ rtc->offset = 0;
279
+static void cprman_init(Object *obj)
205
+ memset(rtc->reg, 0, sizeof(rtc->reg));
280
+{
206
+}
281
+ BCM2835CprmanState *s = CPRMAN(obj);
207
+
282
+
208
+static const MemoryRegionOps aspeed_rtc_ops = {
283
+ s->xosc = clock_new(obj, "xosc");
209
+ .read = aspeed_rtc_read,
284
+
210
+ .write = aspeed_rtc_write,
285
+ memory_region_init_io(&s->iomem, obj, &cprman_ops,
211
+ .endianness = DEVICE_NATIVE_ENDIAN,
286
+ s, "bcm2835-cprman", 0x2000);
212
+};
287
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
213
+
288
+}
214
+static const VMStateDescription vmstate_aspeed_rtc = {
289
+
215
+ .name = TYPE_ASPEED_RTC,
290
+static const VMStateDescription cprman_vmstate = {
291
+ .name = TYPE_BCM2835_CPRMAN,
216
+ .version_id = 1,
292
+ .version_id = 1,
293
+ .minimum_version_id = 1,
217
+ .fields = (VMStateField[]) {
294
+ .fields = (VMStateField[]) {
218
+ VMSTATE_UINT32_ARRAY(reg, AspeedRtcState, 0x18),
295
+ VMSTATE_UINT32_ARRAY(regs, BCM2835CprmanState, CPRMAN_NUM_REGS),
219
+ VMSTATE_INT32(offset, AspeedRtcState),
220
+ VMSTATE_INT32(offset, AspeedRtcState),
221
+ VMSTATE_END_OF_LIST()
296
+ VMSTATE_END_OF_LIST()
222
+ }
297
+ }
223
+};
298
+};
224
+
299
+
225
+static void aspeed_rtc_realize(DeviceState *dev, Error **errp)
300
+static Property cprman_properties[] = {
226
+{
301
+ DEFINE_PROP_UINT32("xosc-freq-hz", BCM2835CprmanState, xosc_freq, 19200000),
227
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
302
+ DEFINE_PROP_END_OF_LIST()
228
+ AspeedRtcState *s = ASPEED_RTC(dev);
303
+};
229
+
304
+
230
+ sysbus_init_irq(sbd, &s->irq);
305
+static void cprman_class_init(ObjectClass *klass, void *data)
231
+
232
+ memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_rtc_ops, s,
233
+ "aspeed-rtc", 0x18ULL);
234
+ sysbus_init_mmio(sbd, &s->iomem);
235
+}
236
+
237
+static void aspeed_rtc_class_init(ObjectClass *klass, void *data)
238
+{
306
+{
239
+ DeviceClass *dc = DEVICE_CLASS(klass);
307
+ DeviceClass *dc = DEVICE_CLASS(klass);
240
+
308
+
241
+ dc->realize = aspeed_rtc_realize;
309
+ dc->reset = cprman_reset;
242
+ dc->vmsd = &vmstate_aspeed_rtc;
310
+ dc->vmsd = &cprman_vmstate;
243
+ dc->reset = aspeed_rtc_reset;
311
+ device_class_set_props(dc, cprman_properties);
244
+}
312
+}
245
+
313
+
246
+static const TypeInfo aspeed_rtc_info = {
314
+static const TypeInfo cprman_info = {
247
+ .name = TYPE_ASPEED_RTC,
315
+ .name = TYPE_BCM2835_CPRMAN,
248
+ .parent = TYPE_SYS_BUS_DEVICE,
316
+ .parent = TYPE_SYS_BUS_DEVICE,
249
+ .instance_size = sizeof(AspeedRtcState),
317
+ .instance_size = sizeof(BCM2835CprmanState),
250
+ .class_init = aspeed_rtc_class_init,
318
+ .class_init = cprman_class_init,
251
+};
319
+ .instance_init = cprman_init,
252
+
320
+};
253
+static void aspeed_rtc_register_types(void)
321
+
254
+{
322
+static void cprman_register_types(void)
255
+ type_register_static(&aspeed_rtc_info);
323
+{
256
+}
324
+ type_register_static(&cprman_info);
257
+
325
+}
258
+type_init(aspeed_rtc_register_types)
326
+
259
diff --git a/hw/timer/trace-events b/hw/timer/trace-events
327
+type_init(cprman_register_types);
328
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
260
index XXXXXXX..XXXXXXX 100644
329
index XXXXXXX..XXXXXXX 100644
261
--- a/hw/timer/trace-events
330
--- a/hw/misc/meson.build
262
+++ b/hw/timer/trace-events
331
+++ b/hw/misc/meson.build
263
@@ -XXX,XX +XXX,XX @@ cmsdk_apb_dualtimer_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK A
332
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files(
264
cmsdk_apb_dualtimer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB dualtimer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
333
'bcm2835_property.c',
265
cmsdk_apb_dualtimer_reset(void) "CMSDK APB dualtimer: reset"
334
'bcm2835_rng.c',
266
335
'bcm2835_thermal.c',
267
+# hw/timer/aspeed-rtc.c
336
+ 'bcm2835_cprman.c',
268
+aspeed_rtc_read(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
337
))
269
+aspeed_rtc_write(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
338
softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_misc.c'))
270
+
339
softmmu_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq_slcr.c', 'zynq-xadc.c'))
271
# sun4v-rtc.c
340
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
272
sun4v_rtc_read(uint64_t addr, uint64_t value) "read: addr 0x%" PRIx64 " value 0x%" PRIx64
341
index XXXXXXX..XXXXXXX 100644
273
sun4v_rtc_write(uint64_t addr, uint64_t value) "write: addr 0x%" PRIx64 " value 0x%" PRIx64
342
--- a/hw/misc/trace-events
343
+++ b/hw/misc/trace-events
344
@@ -XXX,XX +XXX,XX @@ grlib_apb_pnp_read(uint64_t addr, uint32_t value) "APB PnP read addr:0x%03"PRIx6
345
# pca9552.c
346
pca955x_gpio_status(const char *description, const char *buf) "%s GPIOs 0-15 [%s]"
347
pca955x_gpio_change(const char *description, unsigned id, unsigned prev_state, unsigned current_state) "%s GPIO id:%u status: %u -> %u"
348
+
349
+# bcm2835_cprman.c
350
+bcm2835_cprman_read(uint64_t offset, uint64_t value) "offset:0x%" PRIx64 " value:0x%" PRIx64
351
+bcm2835_cprman_write(uint64_t offset, uint64_t value) "offset:0x%" PRIx64 " value:0x%" PRIx64
352
+bcm2835_cprman_write_invalid_magic(uint64_t offset, uint64_t value) "offset:0x%" PRIx64 " value:0x%" PRIx64
274
--
353
--
275
2.20.1
354
2.20.1
276
355
277
356
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Luc Michel <luc@lmichel.fr>
2
2
3
In few commits we will split the M-profile functions from this
3
There are 5 PLLs in the CPRMAN, namely PLL A, C, D, H and B. All of them
4
file, and this function will also be called in the new file.
4
take the xosc clock as input and produce a new clock.
5
Declare it in the "internals.h" header.
5
6
Since it is in the middle of a block of M profile functions,
6
This commit adds a skeleton implementation for the PLLs as sub-devices
7
move it previous to this block to ease the later refactor.
7
of the CPRMAN. The PLLs are instantiated and connected internally to the
8
8
main oscillator.
9
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
9
10
Message-id: 20190701132516.26392-21-philmd@redhat.com
10
Each PLL has 6 registers : CM, A2W_CTRL, A2W_ANA[0,1,2,3], A2W_FRAC. A
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
write to any of them triggers a call to the (not yet implemented)
12
pll_update function.
13
14
If the main oscillator changes frequency, an update is also triggered.
15
16
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
17
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
18
Signed-off-by: Luc Michel <luc@lmichel.fr>
19
Tested-by: Guenter Roeck <linux@roeck-us.net>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
20
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
21
---
14
target/arm/internals.h | 2 ++
22
include/hw/misc/bcm2835_cprman.h | 29 +++++
15
target/arm/helper.c | 76 +++++++++++++++++++++---------------------
23
include/hw/misc/bcm2835_cprman_internals.h | 144 +++++++++++++++++++++
16
2 files changed, 40 insertions(+), 38 deletions(-)
24
hw/misc/bcm2835_cprman.c | 108 ++++++++++++++++
17
25
3 files changed, 281 insertions(+)
18
diff --git a/target/arm/internals.h b/target/arm/internals.h
26
27
diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h
19
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
20
--- a/target/arm/internals.h
29
--- a/include/hw/misc/bcm2835_cprman.h
21
+++ b/target/arm/internals.h
30
+++ b/include/hw/misc/bcm2835_cprman.h
22
@@ -XXX,XX +XXX,XX @@ bool get_phys_addr(CPUARMState *env, target_ulong address,
31
@@ -XXX,XX +XXX,XX @@ DECLARE_INSTANCE_CHECKER(BCM2835CprmanState, CPRMAN,
23
target_ulong *page_size,
32
24
ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs);
33
#define CPRMAN_NUM_REGS (0x2000 / sizeof(uint32_t))
25
34
26
+void arm_log_exception(int idx);
35
+typedef enum CprmanPll {
27
+
36
+ CPRMAN_PLLA = 0,
28
#endif /* !CONFIG_USER_ONLY */
37
+ CPRMAN_PLLC,
29
38
+ CPRMAN_PLLD,
39
+ CPRMAN_PLLH,
40
+ CPRMAN_PLLB,
41
+
42
+ CPRMAN_NUM_PLL
43
+} CprmanPll;
44
+
45
+typedef struct CprmanPllState {
46
+ /*< private >*/
47
+ DeviceState parent_obj;
48
+
49
+ /*< public >*/
50
+ CprmanPll id;
51
+
52
+ uint32_t *reg_cm;
53
+ uint32_t *reg_a2w_ctrl;
54
+ uint32_t *reg_a2w_ana; /* ANA[0] .. ANA[3] */
55
+ uint32_t prediv_mask; /* prediv bit in ana[1] */
56
+ uint32_t *reg_a2w_frac;
57
+
58
+ Clock *xosc_in;
59
+ Clock *out;
60
+} CprmanPllState;
61
+
62
struct BCM2835CprmanState {
63
/*< private >*/
64
SysBusDevice parent_obj;
65
@@ -XXX,XX +XXX,XX @@ struct BCM2835CprmanState {
66
/*< public >*/
67
MemoryRegion iomem;
68
69
+ CprmanPllState plls[CPRMAN_NUM_PLL];
70
+
71
uint32_t regs[CPRMAN_NUM_REGS];
72
uint32_t xosc_freq;
73
74
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
75
index XXXXXXX..XXXXXXX 100644
76
--- a/include/hw/misc/bcm2835_cprman_internals.h
77
+++ b/include/hw/misc/bcm2835_cprman_internals.h
78
@@ -XXX,XX +XXX,XX @@
79
#include "hw/registerfields.h"
80
#include "hw/misc/bcm2835_cprman.h"
81
82
+#define TYPE_CPRMAN_PLL "bcm2835-cprman-pll"
83
+
84
+DECLARE_INSTANCE_CHECKER(CprmanPllState, CPRMAN_PLL,
85
+ TYPE_CPRMAN_PLL)
86
+
87
/* Register map */
88
89
+/* PLLs */
90
+REG32(CM_PLLA, 0x104)
91
+ FIELD(CM_PLLA, LOADDSI0, 0, 1)
92
+ FIELD(CM_PLLA, HOLDDSI0, 1, 1)
93
+ FIELD(CM_PLLA, LOADCCP2, 2, 1)
94
+ FIELD(CM_PLLA, HOLDCCP2, 3, 1)
95
+ FIELD(CM_PLLA, LOADCORE, 4, 1)
96
+ FIELD(CM_PLLA, HOLDCORE, 5, 1)
97
+ FIELD(CM_PLLA, LOADPER, 6, 1)
98
+ FIELD(CM_PLLA, HOLDPER, 7, 1)
99
+ FIELD(CM_PLLx, ANARST, 8, 1)
100
+REG32(CM_PLLC, 0x108)
101
+ FIELD(CM_PLLC, LOADCORE0, 0, 1)
102
+ FIELD(CM_PLLC, HOLDCORE0, 1, 1)
103
+ FIELD(CM_PLLC, LOADCORE1, 2, 1)
104
+ FIELD(CM_PLLC, HOLDCORE1, 3, 1)
105
+ FIELD(CM_PLLC, LOADCORE2, 4, 1)
106
+ FIELD(CM_PLLC, HOLDCORE2, 5, 1)
107
+ FIELD(CM_PLLC, LOADPER, 6, 1)
108
+ FIELD(CM_PLLC, HOLDPER, 7, 1)
109
+REG32(CM_PLLD, 0x10c)
110
+ FIELD(CM_PLLD, LOADDSI0, 0, 1)
111
+ FIELD(CM_PLLD, HOLDDSI0, 1, 1)
112
+ FIELD(CM_PLLD, LOADDSI1, 2, 1)
113
+ FIELD(CM_PLLD, HOLDDSI1, 3, 1)
114
+ FIELD(CM_PLLD, LOADCORE, 4, 1)
115
+ FIELD(CM_PLLD, HOLDCORE, 5, 1)
116
+ FIELD(CM_PLLD, LOADPER, 6, 1)
117
+ FIELD(CM_PLLD, HOLDPER, 7, 1)
118
+REG32(CM_PLLH, 0x110)
119
+ FIELD(CM_PLLH, LOADPIX, 0, 1)
120
+ FIELD(CM_PLLH, LOADAUX, 1, 1)
121
+ FIELD(CM_PLLH, LOADRCAL, 2, 1)
122
+REG32(CM_PLLB, 0x170)
123
+ FIELD(CM_PLLB, LOADARM, 0, 1)
124
+ FIELD(CM_PLLB, HOLDARM, 1, 1)
125
+
126
+REG32(A2W_PLLA_CTRL, 0x1100)
127
+ FIELD(A2W_PLLx_CTRL, NDIV, 0, 10)
128
+ FIELD(A2W_PLLx_CTRL, PDIV, 12, 3)
129
+ FIELD(A2W_PLLx_CTRL, PWRDN, 16, 1)
130
+ FIELD(A2W_PLLx_CTRL, PRST_DISABLE, 17, 1)
131
+REG32(A2W_PLLC_CTRL, 0x1120)
132
+REG32(A2W_PLLD_CTRL, 0x1140)
133
+REG32(A2W_PLLH_CTRL, 0x1160)
134
+REG32(A2W_PLLB_CTRL, 0x11e0)
135
+
136
+REG32(A2W_PLLA_ANA0, 0x1010)
137
+REG32(A2W_PLLA_ANA1, 0x1014)
138
+ FIELD(A2W_PLLx_ANA1, FB_PREDIV, 14, 1)
139
+REG32(A2W_PLLA_ANA2, 0x1018)
140
+REG32(A2W_PLLA_ANA3, 0x101c)
141
+
142
+REG32(A2W_PLLC_ANA0, 0x1030)
143
+REG32(A2W_PLLC_ANA1, 0x1034)
144
+REG32(A2W_PLLC_ANA2, 0x1038)
145
+REG32(A2W_PLLC_ANA3, 0x103c)
146
+
147
+REG32(A2W_PLLD_ANA0, 0x1050)
148
+REG32(A2W_PLLD_ANA1, 0x1054)
149
+REG32(A2W_PLLD_ANA2, 0x1058)
150
+REG32(A2W_PLLD_ANA3, 0x105c)
151
+
152
+REG32(A2W_PLLH_ANA0, 0x1070)
153
+REG32(A2W_PLLH_ANA1, 0x1074)
154
+ FIELD(A2W_PLLH_ANA1, FB_PREDIV, 11, 1)
155
+REG32(A2W_PLLH_ANA2, 0x1078)
156
+REG32(A2W_PLLH_ANA3, 0x107c)
157
+
158
+REG32(A2W_PLLB_ANA0, 0x10f0)
159
+REG32(A2W_PLLB_ANA1, 0x10f4)
160
+REG32(A2W_PLLB_ANA2, 0x10f8)
161
+REG32(A2W_PLLB_ANA3, 0x10fc)
162
+
163
+REG32(A2W_PLLA_FRAC, 0x1200)
164
+ FIELD(A2W_PLLx_FRAC, FRAC, 0, 20)
165
+REG32(A2W_PLLC_FRAC, 0x1220)
166
+REG32(A2W_PLLD_FRAC, 0x1240)
167
+REG32(A2W_PLLH_FRAC, 0x1260)
168
+REG32(A2W_PLLB_FRAC, 0x12e0)
169
+
170
/*
171
* This field is common to all registers. Each register write value must match
172
* the CPRMAN_PASSWORD magic value in its 8 MSB.
173
@@ -XXX,XX +XXX,XX @@
174
FIELD(CPRMAN, PASSWORD, 24, 8)
175
#define CPRMAN_PASSWORD 0x5a
176
177
+/* PLL init info */
178
+typedef struct PLLInitInfo {
179
+ const char *name;
180
+ size_t cm_offset;
181
+ size_t a2w_ctrl_offset;
182
+ size_t a2w_ana_offset;
183
+ uint32_t prediv_mask; /* Prediv bit in ana[1] */
184
+ size_t a2w_frac_offset;
185
+} PLLInitInfo;
186
+
187
+#define FILL_PLL_INIT_INFO(pll_) \
188
+ .cm_offset = R_CM_ ## pll_, \
189
+ .a2w_ctrl_offset = R_A2W_ ## pll_ ## _CTRL, \
190
+ .a2w_ana_offset = R_A2W_ ## pll_ ## _ANA0, \
191
+ .a2w_frac_offset = R_A2W_ ## pll_ ## _FRAC
192
+
193
+static const PLLInitInfo PLL_INIT_INFO[] = {
194
+ [CPRMAN_PLLA] = {
195
+ .name = "plla",
196
+ .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK,
197
+ FILL_PLL_INIT_INFO(PLLA),
198
+ },
199
+ [CPRMAN_PLLC] = {
200
+ .name = "pllc",
201
+ .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK,
202
+ FILL_PLL_INIT_INFO(PLLC),
203
+ },
204
+ [CPRMAN_PLLD] = {
205
+ .name = "plld",
206
+ .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK,
207
+ FILL_PLL_INIT_INFO(PLLD),
208
+ },
209
+ [CPRMAN_PLLH] = {
210
+ .name = "pllh",
211
+ .prediv_mask = R_A2W_PLLH_ANA1_FB_PREDIV_MASK,
212
+ FILL_PLL_INIT_INFO(PLLH),
213
+ },
214
+ [CPRMAN_PLLB] = {
215
+ .name = "pllb",
216
+ .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK,
217
+ FILL_PLL_INIT_INFO(PLLB),
218
+ },
219
+};
220
+
221
+#undef FILL_PLL_CHANNEL_INIT_INFO
222
+
223
+static inline void set_pll_init_info(BCM2835CprmanState *s,
224
+ CprmanPllState *pll,
225
+ CprmanPll id)
226
+{
227
+ pll->id = id;
228
+ pll->reg_cm = &s->regs[PLL_INIT_INFO[id].cm_offset];
229
+ pll->reg_a2w_ctrl = &s->regs[PLL_INIT_INFO[id].a2w_ctrl_offset];
230
+ pll->reg_a2w_ana = &s->regs[PLL_INIT_INFO[id].a2w_ana_offset];
231
+ pll->prediv_mask = PLL_INIT_INFO[id].prediv_mask;
232
+ pll->reg_a2w_frac = &s->regs[PLL_INIT_INFO[id].a2w_frac_offset];
233
+}
234
+
30
#endif
235
#endif
31
diff --git a/target/arm/helper.c b/target/arm/helper.c
236
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
32
index XXXXXXX..XXXXXXX 100644
237
index XXXXXXX..XXXXXXX 100644
33
--- a/target/arm/helper.c
238
--- a/hw/misc/bcm2835_cprman.c
34
+++ b/target/arm/helper.c
239
+++ b/hw/misc/bcm2835_cprman.c
35
@@ -XXX,XX +XXX,XX @@ uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx,
240
@@ -XXX,XX +XXX,XX @@
36
return target_el;
241
#include "hw/misc/bcm2835_cprman_internals.h"
242
#include "trace.h"
243
244
+/* PLL */
245
+
246
+static void pll_update(CprmanPllState *pll)
247
+{
248
+ clock_update(pll->out, 0);
249
+}
250
+
251
+static void pll_xosc_update(void *opaque)
252
+{
253
+ pll_update(CPRMAN_PLL(opaque));
254
+}
255
+
256
+static void pll_init(Object *obj)
257
+{
258
+ CprmanPllState *s = CPRMAN_PLL(obj);
259
+
260
+ s->xosc_in = qdev_init_clock_in(DEVICE(s), "xosc-in", pll_xosc_update, s);
261
+ s->out = qdev_init_clock_out(DEVICE(s), "out");
262
+}
263
+
264
+static const VMStateDescription pll_vmstate = {
265
+ .name = TYPE_CPRMAN_PLL,
266
+ .version_id = 1,
267
+ .minimum_version_id = 1,
268
+ .fields = (VMStateField[]) {
269
+ VMSTATE_CLOCK(xosc_in, CprmanPllState),
270
+ VMSTATE_END_OF_LIST()
271
+ }
272
+};
273
+
274
+static void pll_class_init(ObjectClass *klass, void *data)
275
+{
276
+ DeviceClass *dc = DEVICE_CLASS(klass);
277
+
278
+ dc->vmsd = &pll_vmstate;
279
+}
280
+
281
+static const TypeInfo cprman_pll_info = {
282
+ .name = TYPE_CPRMAN_PLL,
283
+ .parent = TYPE_DEVICE,
284
+ .instance_size = sizeof(CprmanPllState),
285
+ .class_init = pll_class_init,
286
+ .instance_init = pll_init,
287
+};
288
+
289
+
290
/* CPRMAN "top level" model */
291
292
static uint64_t cprman_read(void *opaque, hwaddr offset,
293
@@ -XXX,XX +XXX,XX @@ static uint64_t cprman_read(void *opaque, hwaddr offset,
294
return r;
37
}
295
}
38
296
39
+void arm_log_exception(int idx)
297
+#define CASE_PLL_REGS(pll_) \
40
+{
298
+ case R_CM_ ## pll_: \
41
+ if (qemu_loglevel_mask(CPU_LOG_INT)) {
299
+ case R_A2W_ ## pll_ ## _CTRL: \
42
+ const char *exc = NULL;
300
+ case R_A2W_ ## pll_ ## _ANA0: \
43
+ static const char * const excnames[] = {
301
+ case R_A2W_ ## pll_ ## _ANA1: \
44
+ [EXCP_UDEF] = "Undefined Instruction",
302
+ case R_A2W_ ## pll_ ## _ANA2: \
45
+ [EXCP_SWI] = "SVC",
303
+ case R_A2W_ ## pll_ ## _ANA3: \
46
+ [EXCP_PREFETCH_ABORT] = "Prefetch Abort",
304
+ case R_A2W_ ## pll_ ## _FRAC
47
+ [EXCP_DATA_ABORT] = "Data Abort",
305
+
48
+ [EXCP_IRQ] = "IRQ",
306
static void cprman_write(void *opaque, hwaddr offset,
49
+ [EXCP_FIQ] = "FIQ",
307
uint64_t value, unsigned size)
50
+ [EXCP_BKPT] = "Breakpoint",
308
{
51
+ [EXCP_EXCEPTION_EXIT] = "QEMU v7M exception exit",
309
@@ -XXX,XX +XXX,XX @@ static void cprman_write(void *opaque, hwaddr offset,
52
+ [EXCP_KERNEL_TRAP] = "QEMU intercept of kernel commpage",
310
trace_bcm2835_cprman_write(offset, value);
53
+ [EXCP_HVC] = "Hypervisor Call",
311
s->regs[idx] = value;
54
+ [EXCP_HYP_TRAP] = "Hypervisor Trap",
312
55
+ [EXCP_SMC] = "Secure Monitor Call",
313
+ switch (idx) {
56
+ [EXCP_VIRQ] = "Virtual IRQ",
314
+ CASE_PLL_REGS(PLLA) :
57
+ [EXCP_VFIQ] = "Virtual FIQ",
315
+ pll_update(&s->plls[CPRMAN_PLLA]);
58
+ [EXCP_SEMIHOST] = "Semihosting call",
316
+ break;
59
+ [EXCP_NOCP] = "v7M NOCP UsageFault",
317
+
60
+ [EXCP_INVSTATE] = "v7M INVSTATE UsageFault",
318
+ CASE_PLL_REGS(PLLC) :
61
+ [EXCP_STKOF] = "v8M STKOF UsageFault",
319
+ pll_update(&s->plls[CPRMAN_PLLC]);
62
+ [EXCP_LAZYFP] = "v7M exception during lazy FP stacking",
320
+ break;
63
+ [EXCP_LSERR] = "v8M LSERR UsageFault",
321
+
64
+ [EXCP_UNALIGNED] = "v7M UNALIGNED UsageFault",
322
+ CASE_PLL_REGS(PLLD) :
65
+ };
323
+ pll_update(&s->plls[CPRMAN_PLLD]);
66
+
324
+ break;
67
+ if (idx >= 0 && idx < ARRAY_SIZE(excnames)) {
325
+
68
+ exc = excnames[idx];
326
+ CASE_PLL_REGS(PLLH) :
327
+ pll_update(&s->plls[CPRMAN_PLLH]);
328
+ break;
329
+
330
+ CASE_PLL_REGS(PLLB) :
331
+ pll_update(&s->plls[CPRMAN_PLLB]);
332
+ break;
333
+ }
334
}
335
336
+#undef CASE_PLL_REGS
337
+
338
static const MemoryRegionOps cprman_ops = {
339
.read = cprman_read,
340
.write = cprman_write,
341
@@ -XXX,XX +XXX,XX @@ static const MemoryRegionOps cprman_ops = {
342
static void cprman_reset(DeviceState *dev)
343
{
344
BCM2835CprmanState *s = CPRMAN(dev);
345
+ size_t i;
346
347
memset(s->regs, 0, sizeof(s->regs));
348
349
+ for (i = 0; i < CPRMAN_NUM_PLL; i++) {
350
+ device_cold_reset(DEVICE(&s->plls[i]));
351
+ }
352
+
353
clock_update_hz(s->xosc, s->xosc_freq);
354
}
355
356
static void cprman_init(Object *obj)
357
{
358
BCM2835CprmanState *s = CPRMAN(obj);
359
+ size_t i;
360
+
361
+ for (i = 0; i < CPRMAN_NUM_PLL; i++) {
362
+ object_initialize_child(obj, PLL_INIT_INFO[i].name,
363
+ &s->plls[i], TYPE_CPRMAN_PLL);
364
+ set_pll_init_info(s, &s->plls[i], i);
365
+ }
366
367
s->xosc = clock_new(obj, "xosc");
368
369
@@ -XXX,XX +XXX,XX @@ static void cprman_init(Object *obj)
370
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
371
}
372
373
+static void cprman_realize(DeviceState *dev, Error **errp)
374
+{
375
+ BCM2835CprmanState *s = CPRMAN(dev);
376
+ size_t i;
377
+
378
+ for (i = 0; i < CPRMAN_NUM_PLL; i++) {
379
+ CprmanPllState *pll = &s->plls[i];
380
+
381
+ clock_set_source(pll->xosc_in, s->xosc);
382
+
383
+ if (!qdev_realize(DEVICE(pll), NULL, errp)) {
384
+ return;
69
+ }
385
+ }
70
+ if (!exc) {
71
+ exc = "unknown";
72
+ }
73
+ qemu_log_mask(CPU_LOG_INT, "Taking exception %d [%s]\n", idx, exc);
74
+ }
386
+ }
75
+}
387
+}
76
+
388
+
77
/*
389
static const VMStateDescription cprman_vmstate = {
78
* Return true if the v7M CPACR permits access to the FPU for the specified
390
.name = TYPE_BCM2835_CPRMAN,
79
* security state and privilege level.
391
.version_id = 1,
80
@@ -XXX,XX +XXX,XX @@ static bool do_v7m_function_return(ARMCPU *cpu)
392
@@ -XXX,XX +XXX,XX @@ static void cprman_class_init(ObjectClass *klass, void *data)
81
return true;
393
{
394
DeviceClass *dc = DEVICE_CLASS(klass);
395
396
+ dc->realize = cprman_realize;
397
dc->reset = cprman_reset;
398
dc->vmsd = &cprman_vmstate;
399
device_class_set_props(dc, cprman_properties);
400
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_info = {
401
static void cprman_register_types(void)
402
{
403
type_register_static(&cprman_info);
404
+ type_register_static(&cprman_pll_info);
82
}
405
}
83
406
84
-static void arm_log_exception(int idx)
407
type_init(cprman_register_types);
85
-{
86
- if (qemu_loglevel_mask(CPU_LOG_INT)) {
87
- const char *exc = NULL;
88
- static const char * const excnames[] = {
89
- [EXCP_UDEF] = "Undefined Instruction",
90
- [EXCP_SWI] = "SVC",
91
- [EXCP_PREFETCH_ABORT] = "Prefetch Abort",
92
- [EXCP_DATA_ABORT] = "Data Abort",
93
- [EXCP_IRQ] = "IRQ",
94
- [EXCP_FIQ] = "FIQ",
95
- [EXCP_BKPT] = "Breakpoint",
96
- [EXCP_EXCEPTION_EXIT] = "QEMU v7M exception exit",
97
- [EXCP_KERNEL_TRAP] = "QEMU intercept of kernel commpage",
98
- [EXCP_HVC] = "Hypervisor Call",
99
- [EXCP_HYP_TRAP] = "Hypervisor Trap",
100
- [EXCP_SMC] = "Secure Monitor Call",
101
- [EXCP_VIRQ] = "Virtual IRQ",
102
- [EXCP_VFIQ] = "Virtual FIQ",
103
- [EXCP_SEMIHOST] = "Semihosting call",
104
- [EXCP_NOCP] = "v7M NOCP UsageFault",
105
- [EXCP_INVSTATE] = "v7M INVSTATE UsageFault",
106
- [EXCP_STKOF] = "v8M STKOF UsageFault",
107
- [EXCP_LAZYFP] = "v7M exception during lazy FP stacking",
108
- [EXCP_LSERR] = "v8M LSERR UsageFault",
109
- [EXCP_UNALIGNED] = "v7M UNALIGNED UsageFault",
110
- };
111
-
112
- if (idx >= 0 && idx < ARRAY_SIZE(excnames)) {
113
- exc = excnames[idx];
114
- }
115
- if (!exc) {
116
- exc = "unknown";
117
- }
118
- qemu_log_mask(CPU_LOG_INT, "Taking exception %d [%s]\n", idx, exc);
119
- }
120
-}
121
-
122
static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx,
123
uint32_t addr, uint16_t *insn)
124
{
125
--
408
--
126
2.20.1
409
2.20.1
127
410
128
411
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Luc Michel <luc@lmichel.fr>
2
2
3
The vfp_set_fpscr() helper contains code specific to the host
3
The CPRMAN PLLs generate a clock based on a prescaler, a multiplier and
4
floating point implementation (here the SoftFloat library).
4
a divider. The prescaler doubles the parent (xosc) frequency, then the
5
Extract this code to vfp_set_fpscr_to_host().
5
multiplier/divider are applied. The multiplier has an integer and a
6
fractional part.
6
7
7
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
This commit also implements the CPRMAN CM_LOCK register. This register
8
Message-id: 20190701132516.26392-16-philmd@redhat.com
9
reports which PLL is currently locked. We consider a PLL has being
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
locked as soon as it is enabled (on real hardware, there is a delay
11
after turning a PLL on, for it to stabilize).
12
13
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
14
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
15
Signed-off-by: Luc Michel <luc@lmichel.fr>
16
Tested-by: Guenter Roeck <linux@roeck-us.net>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
18
---
12
target/arm/vfp_helper.c | 127 +++++++++++++++++++++-------------------
19
include/hw/misc/bcm2835_cprman_internals.h | 8 +++
13
1 file changed, 66 insertions(+), 61 deletions(-)
20
hw/misc/bcm2835_cprman.c | 64 +++++++++++++++++++++-
21
2 files changed, 71 insertions(+), 1 deletion(-)
14
22
15
diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c
23
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
16
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/vfp_helper.c
25
--- a/include/hw/misc/bcm2835_cprman_internals.h
18
+++ b/target/arm/vfp_helper.c
26
+++ b/include/hw/misc/bcm2835_cprman_internals.h
19
@@ -XXX,XX +XXX,XX @@ static inline int vfp_exceptbits_to_host(int target_bits)
27
@@ -XXX,XX +XXX,XX @@ REG32(A2W_PLLD_FRAC, 0x1240)
20
return host_bits;
28
REG32(A2W_PLLH_FRAC, 0x1260)
21
}
29
REG32(A2W_PLLB_FRAC, 0x12e0)
22
30
23
-uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env)
31
+/* misc registers */
24
-{
32
+REG32(CM_LOCK, 0x114)
25
- uint32_t i, fpscr;
33
+ FIELD(CM_LOCK, FLOCKH, 12, 1)
26
-
34
+ FIELD(CM_LOCK, FLOCKD, 11, 1)
27
- fpscr = env->vfp.xregs[ARM_VFP_FPSCR]
35
+ FIELD(CM_LOCK, FLOCKC, 10, 1)
28
- | (env->vfp.vec_len << 16)
36
+ FIELD(CM_LOCK, FLOCKB, 9, 1)
29
- | (env->vfp.vec_stride << 20);
37
+ FIELD(CM_LOCK, FLOCKA, 8, 1)
30
-
38
+
31
- i = get_float_exception_flags(&env->vfp.fp_status);
39
/*
32
- i |= get_float_exception_flags(&env->vfp.standard_fp_status);
40
* This field is common to all registers. Each register write value must match
33
- /* FZ16 does not generate an input denormal exception. */
41
* the CPRMAN_PASSWORD magic value in its 8 MSB.
34
- i |= (get_float_exception_flags(&env->vfp.fp_status_f16)
42
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
35
- & ~float_flag_input_denormal);
43
index XXXXXXX..XXXXXXX 100644
36
- fpscr |= vfp_exceptbits_from_host(i);
44
--- a/hw/misc/bcm2835_cprman.c
37
-
45
+++ b/hw/misc/bcm2835_cprman.c
38
- i = env->vfp.qc[0] | env->vfp.qc[1] | env->vfp.qc[2] | env->vfp.qc[3];
46
@@ -XXX,XX +XXX,XX @@
39
- fpscr |= i ? FPCR_QC : 0;
47
40
-
48
/* PLL */
41
- return fpscr;
49
42
-}
50
+static bool pll_is_locked(const CprmanPllState *pll)
43
-
44
-uint32_t vfp_get_fpscr(CPUARMState *env)
45
-{
46
- return HELPER(vfp_get_fpscr)(env);
47
-}
48
-
49
-void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val)
50
+static void vfp_set_fpscr_to_host(CPUARMState *env, uint32_t val)
51
{
52
int i;
53
uint32_t changed = env->vfp.xregs[ARM_VFP_FPSCR];
54
55
- /* When ARMv8.2-FP16 is not supported, FZ16 is RES0. */
56
- if (!cpu_isar_feature(aa64_fp16, env_archcpu(env))) {
57
- val &= ~FPCR_FZ16;
58
- }
59
-
60
- if (arm_feature(env, ARM_FEATURE_M)) {
61
- /*
62
- * M profile FPSCR is RES0 for the QC, STRIDE, FZ16, LEN bits
63
- * and also for the trapped-exception-handling bits IxE.
64
- */
65
- val &= 0xf7c0009f;
66
- }
67
-
68
- /*
69
- * We don't implement trapped exception handling, so the
70
- * trap enable bits, IDE|IXE|UFE|OFE|DZE|IOE are all RAZ/WI (not RES0!)
71
- *
72
- * If we exclude the exception flags, IOC|DZC|OFC|UFC|IXC|IDC
73
- * (which are stored in fp_status), and the other RES0 bits
74
- * in between, then we clear all of the low 16 bits.
75
- */
76
- env->vfp.xregs[ARM_VFP_FPSCR] = val & 0xf7c80000;
77
- env->vfp.vec_len = (val >> 16) & 7;
78
- env->vfp.vec_stride = (val >> 20) & 3;
79
-
80
- /*
81
- * The bit we set within fpscr_q is arbitrary; the register as a
82
- * whole being zero/non-zero is what counts.
83
- */
84
- env->vfp.qc[0] = val & FPCR_QC;
85
- env->vfp.qc[1] = 0;
86
- env->vfp.qc[2] = 0;
87
- env->vfp.qc[3] = 0;
88
-
89
changed ^= val;
90
if (changed & (3 << 22)) {
91
i = (val >> 22) & 3;
92
@@ -XXX,XX +XXX,XX @@ void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val)
93
set_float_exception_flags(0, &env->vfp.standard_fp_status);
94
}
95
96
+uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env)
97
+{
51
+{
98
+ uint32_t i, fpscr;
52
+ return !FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, PWRDN)
99
+
53
+ && !FIELD_EX32(*pll->reg_cm, CM_PLLx, ANARST);
100
+ fpscr = env->vfp.xregs[ARM_VFP_FPSCR]
101
+ | (env->vfp.vec_len << 16)
102
+ | (env->vfp.vec_stride << 20);
103
+
104
+ i = get_float_exception_flags(&env->vfp.fp_status);
105
+ i |= get_float_exception_flags(&env->vfp.standard_fp_status);
106
+ /* FZ16 does not generate an input denormal exception. */
107
+ i |= (get_float_exception_flags(&env->vfp.fp_status_f16)
108
+ & ~float_flag_input_denormal);
109
+ fpscr |= vfp_exceptbits_from_host(i);
110
+
111
+ i = env->vfp.qc[0] | env->vfp.qc[1] | env->vfp.qc[2] | env->vfp.qc[3];
112
+ fpscr |= i ? FPCR_QC : 0;
113
+
114
+ return fpscr;
115
+}
54
+}
116
+
55
+
117
+uint32_t vfp_get_fpscr(CPUARMState *env)
56
static void pll_update(CprmanPllState *pll)
118
+{
57
{
119
+ return HELPER(vfp_get_fpscr)(env);
58
- clock_update(pll->out, 0);
120
+}
59
+ uint64_t freq, ndiv, fdiv, pdiv;
121
+
60
+
122
+void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val)
61
+ if (!pll_is_locked(pll)) {
123
+{
62
+ clock_update(pll->out, 0);
124
+ /* When ARMv8.2-FP16 is not supported, FZ16 is RES0. */
63
+ return;
125
+ if (!cpu_isar_feature(aa64_fp16, env_archcpu(env))) {
126
+ val &= ~FPCR_FZ16;
127
+ }
64
+ }
128
+
65
+
129
+ if (arm_feature(env, ARM_FEATURE_M)) {
66
+ pdiv = FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, PDIV);
130
+ /*
67
+
131
+ * M profile FPSCR is RES0 for the QC, STRIDE, FZ16, LEN bits
68
+ if (!pdiv) {
132
+ * and also for the trapped-exception-handling bits IxE.
69
+ clock_update(pll->out, 0);
133
+ */
70
+ return;
134
+ val &= 0xf7c0009f;
71
+ }
72
+
73
+ ndiv = FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, NDIV);
74
+ fdiv = FIELD_EX32(*pll->reg_a2w_frac, A2W_PLLx_FRAC, FRAC);
75
+
76
+ if (pll->reg_a2w_ana[1] & pll->prediv_mask) {
77
+ /* The prescaler doubles the parent frequency */
78
+ ndiv *= 2;
79
+ fdiv *= 2;
135
+ }
80
+ }
136
+
81
+
137
+ /*
82
+ /*
138
+ * We don't implement trapped exception handling, so the
83
+ * We have a multiplier with an integer part (ndiv) and a fractional part
139
+ * trap enable bits, IDE|IXE|UFE|OFE|DZE|IOE are all RAZ/WI (not RES0!)
84
+ * (fdiv), and a divider (pdiv).
140
+ *
141
+ * If we exclude the exception flags, IOC|DZC|OFC|UFC|IXC|IDC
142
+ * (which are stored in fp_status), and the other RES0 bits
143
+ * in between, then we clear all of the low 16 bits.
144
+ */
85
+ */
145
+ env->vfp.xregs[ARM_VFP_FPSCR] = val & 0xf7c80000;
86
+ freq = clock_get_hz(pll->xosc_in) *
146
+ env->vfp.vec_len = (val >> 16) & 7;
87
+ ((ndiv << R_A2W_PLLx_FRAC_FRAC_LENGTH) + fdiv);
147
+ env->vfp.vec_stride = (val >> 20) & 3;
88
+ freq /= pdiv;
89
+ freq >>= R_A2W_PLLx_FRAC_FRAC_LENGTH;
148
+
90
+
149
+ /*
91
+ clock_update_hz(pll->out, freq);
150
+ * The bit we set within fpscr_q is arbitrary; the register as a
92
}
151
+ * whole being zero/non-zero is what counts.
93
152
+ */
94
static void pll_xosc_update(void *opaque)
153
+ env->vfp.qc[0] = val & FPCR_QC;
95
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_info = {
154
+ env->vfp.qc[1] = 0;
96
155
+ env->vfp.qc[2] = 0;
97
/* CPRMAN "top level" model */
156
+ env->vfp.qc[3] = 0;
98
99
+static uint32_t get_cm_lock(const BCM2835CprmanState *s)
100
+{
101
+ static const int CM_LOCK_MAPPING[CPRMAN_NUM_PLL] = {
102
+ [CPRMAN_PLLA] = R_CM_LOCK_FLOCKA_SHIFT,
103
+ [CPRMAN_PLLC] = R_CM_LOCK_FLOCKC_SHIFT,
104
+ [CPRMAN_PLLD] = R_CM_LOCK_FLOCKD_SHIFT,
105
+ [CPRMAN_PLLH] = R_CM_LOCK_FLOCKH_SHIFT,
106
+ [CPRMAN_PLLB] = R_CM_LOCK_FLOCKB_SHIFT,
107
+ };
157
+
108
+
158
+ vfp_set_fpscr_to_host(env, val);
109
+ uint32_t r = 0;
110
+ size_t i;
111
+
112
+ for (i = 0; i < CPRMAN_NUM_PLL; i++) {
113
+ r |= pll_is_locked(&s->plls[i]) << CM_LOCK_MAPPING[i];
114
+ }
115
+
116
+ return r;
159
+}
117
+}
160
+
118
+
161
void vfp_set_fpscr(CPUARMState *env, uint32_t val)
119
static uint64_t cprman_read(void *opaque, hwaddr offset,
120
unsigned size)
162
{
121
{
163
HELPER(vfp_set_fpscr)(env, val);
122
@@ -XXX,XX +XXX,XX @@ static uint64_t cprman_read(void *opaque, hwaddr offset,
123
size_t idx = offset / sizeof(uint32_t);
124
125
switch (idx) {
126
+ case R_CM_LOCK:
127
+ r = get_cm_lock(s);
128
+ break;
129
+
130
default:
131
r = s->regs[idx];
132
}
164
--
133
--
165
2.20.1
134
2.20.1
166
135
167
136
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Luc Michel <luc@lmichel.fr>
2
2
3
Since commit 8c06fbdf36b checkpatch.pl enforce a new multiline
3
PLLs are composed of multiple channels. Each channel outputs one clock
4
comment syntax. Since we'll move this code around, fix its style
4
signal. They are modeled as one device taking the PLL generated clock as
5
first.
5
input, and outputting a new clock.
6
6
7
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
7
A channel shares the CM register with its parent PLL, and has its own
8
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
A2W_CTRL register. A write to the CM register will trigger an update of
9
Message-id: 20190701132516.26392-8-philmd@redhat.com
9
the PLL and all its channels, while a write to an A2W_CTRL channel
10
register will update the required channel only.
11
12
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
13
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
14
Signed-off-by: Luc Michel <luc@lmichel.fr>
15
Tested-by: Guenter Roeck <linux@roeck-us.net>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
17
---
12
target/arm/helper.c | 237 ++++++++++++++++++++++++++--------------
18
include/hw/misc/bcm2835_cprman.h | 44 ++++++
13
target/arm/op_helper.c | 54 ++++++---
19
include/hw/misc/bcm2835_cprman_internals.h | 146 +++++++++++++++++++
14
target/arm/vfp_helper.c | 3 +-
20
hw/misc/bcm2835_cprman.c | 155 +++++++++++++++++++--
15
3 files changed, 196 insertions(+), 98 deletions(-)
21
3 files changed, 337 insertions(+), 8 deletions(-)
16
22
17
diff --git a/target/arm/helper.c b/target/arm/helper.c
23
diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h
18
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/helper.c
25
--- a/include/hw/misc/bcm2835_cprman.h
20
+++ b/target/arm/helper.c
26
+++ b/include/hw/misc/bcm2835_cprman.h
21
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr)
27
@@ -XXX,XX +XXX,XX @@ typedef enum CprmanPll {
22
28
CPRMAN_NUM_PLL
23
uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
29
} CprmanPll;
24
{
30
25
- /* The TT instructions can be used by unprivileged code, but in
31
+typedef enum CprmanPllChannel {
26
+ /*
32
+ CPRMAN_PLLA_CHANNEL_DSI0 = 0,
27
+ * The TT instructions can be used by unprivileged code, but in
33
+ CPRMAN_PLLA_CHANNEL_CORE,
28
* user-only emulation we don't have the MPU.
34
+ CPRMAN_PLLA_CHANNEL_PER,
29
* Luckily since we know we are NonSecure unprivileged (and that in
35
+ CPRMAN_PLLA_CHANNEL_CCP2,
30
* turn means that the A flag wasn't specified), all the bits in the
36
+
31
@@ -XXX,XX +XXX,XX @@ static bool v7m_stack_write(ARMCPU *cpu, uint32_t addr, uint32_t value,
37
+ CPRMAN_PLLC_CHANNEL_CORE2,
32
return true;
38
+ CPRMAN_PLLC_CHANNEL_CORE1,
33
39
+ CPRMAN_PLLC_CHANNEL_PER,
34
pend_fault:
40
+ CPRMAN_PLLC_CHANNEL_CORE0,
35
- /* By pending the exception at this point we are making
41
+
36
+ /*
42
+ CPRMAN_PLLD_CHANNEL_DSI0,
37
+ * By pending the exception at this point we are making
43
+ CPRMAN_PLLD_CHANNEL_CORE,
38
* the IMPDEF choice "overridden exceptions pended" (see the
44
+ CPRMAN_PLLD_CHANNEL_PER,
39
* MergeExcInfo() pseudocode). The other choice would be to not
45
+ CPRMAN_PLLD_CHANNEL_DSI1,
40
* pend them now and then make a choice about which to throw away
46
+
41
@@ -XXX,XX +XXX,XX @@ static bool v7m_stack_read(ARMCPU *cpu, uint32_t *dest, uint32_t addr,
47
+ CPRMAN_PLLH_CHANNEL_AUX,
42
return true;
48
+ CPRMAN_PLLH_CHANNEL_RCAL,
43
49
+ CPRMAN_PLLH_CHANNEL_PIX,
44
pend_fault:
50
+
45
- /* By pending the exception at this point we are making
51
+ CPRMAN_PLLB_CHANNEL_ARM,
46
+ /*
52
+
47
+ * By pending the exception at this point we are making
53
+ CPRMAN_NUM_PLL_CHANNEL,
48
* the IMPDEF choice "overridden exceptions pended" (see the
54
+} CprmanPllChannel;
49
* MergeExcInfo() pseudocode). The other choice would be to not
55
+
50
* pend them now and then make a choice about which to throw away
56
typedef struct CprmanPllState {
51
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_preserve_fp_state)(CPUARMState *env)
57
/*< private >*/
52
*/
58
DeviceState parent_obj;
53
}
59
@@ -XXX,XX +XXX,XX @@ typedef struct CprmanPllState {
54
60
Clock *out;
55
-/* Write to v7M CONTROL.SPSEL bit for the specified security bank.
61
} CprmanPllState;
56
+/*
62
57
+ * Write to v7M CONTROL.SPSEL bit for the specified security bank.
63
+typedef struct CprmanPllChannelState {
58
* This may change the current stack pointer between Main and Process
64
+ /*< private >*/
59
* stack pointers if it is done for the CONTROL register for the current
65
+ DeviceState parent_obj;
60
* security state.
66
+
61
@@ -XXX,XX +XXX,XX @@ static void write_v7m_control_spsel_for_secstate(CPUARMState *env,
67
+ /*< public >*/
68
+ CprmanPllChannel id;
69
+ CprmanPll parent;
70
+
71
+ uint32_t *reg_cm;
72
+ uint32_t hold_mask;
73
+ uint32_t load_mask;
74
+ uint32_t *reg_a2w_ctrl;
75
+ int fixed_divider;
76
+
77
+ Clock *pll_in;
78
+ Clock *out;
79
+} CprmanPllChannelState;
80
+
81
struct BCM2835CprmanState {
82
/*< private >*/
83
SysBusDevice parent_obj;
84
@@ -XXX,XX +XXX,XX @@ struct BCM2835CprmanState {
85
MemoryRegion iomem;
86
87
CprmanPllState plls[CPRMAN_NUM_PLL];
88
+ CprmanPllChannelState channels[CPRMAN_NUM_PLL_CHANNEL];
89
90
uint32_t regs[CPRMAN_NUM_REGS];
91
uint32_t xosc_freq;
92
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
93
index XXXXXXX..XXXXXXX 100644
94
--- a/include/hw/misc/bcm2835_cprman_internals.h
95
+++ b/include/hw/misc/bcm2835_cprman_internals.h
96
@@ -XXX,XX +XXX,XX @@
97
#include "hw/misc/bcm2835_cprman.h"
98
99
#define TYPE_CPRMAN_PLL "bcm2835-cprman-pll"
100
+#define TYPE_CPRMAN_PLL_CHANNEL "bcm2835-cprman-pll-channel"
101
102
DECLARE_INSTANCE_CHECKER(CprmanPllState, CPRMAN_PLL,
103
TYPE_CPRMAN_PLL)
104
+DECLARE_INSTANCE_CHECKER(CprmanPllChannelState, CPRMAN_PLL_CHANNEL,
105
+ TYPE_CPRMAN_PLL_CHANNEL)
106
107
/* Register map */
108
109
@@ -XXX,XX +XXX,XX @@ REG32(A2W_PLLD_FRAC, 0x1240)
110
REG32(A2W_PLLH_FRAC, 0x1260)
111
REG32(A2W_PLLB_FRAC, 0x12e0)
112
113
+/* PLL channels */
114
+REG32(A2W_PLLA_DSI0, 0x1300)
115
+ FIELD(A2W_PLLx_CHANNELy, DIV, 0, 8)
116
+ FIELD(A2W_PLLx_CHANNELy, DISABLE, 8, 1)
117
+REG32(A2W_PLLA_CORE, 0x1400)
118
+REG32(A2W_PLLA_PER, 0x1500)
119
+REG32(A2W_PLLA_CCP2, 0x1600)
120
+
121
+REG32(A2W_PLLC_CORE2, 0x1320)
122
+REG32(A2W_PLLC_CORE1, 0x1420)
123
+REG32(A2W_PLLC_PER, 0x1520)
124
+REG32(A2W_PLLC_CORE0, 0x1620)
125
+
126
+REG32(A2W_PLLD_DSI0, 0x1340)
127
+REG32(A2W_PLLD_CORE, 0x1440)
128
+REG32(A2W_PLLD_PER, 0x1540)
129
+REG32(A2W_PLLD_DSI1, 0x1640)
130
+
131
+REG32(A2W_PLLH_AUX, 0x1360)
132
+REG32(A2W_PLLH_RCAL, 0x1460)
133
+REG32(A2W_PLLH_PIX, 0x1560)
134
+REG32(A2W_PLLH_STS, 0x1660)
135
+
136
+REG32(A2W_PLLB_ARM, 0x13e0)
137
+
138
/* misc registers */
139
REG32(CM_LOCK, 0x114)
140
FIELD(CM_LOCK, FLOCKH, 12, 1)
141
@@ -XXX,XX +XXX,XX @@ static inline void set_pll_init_info(BCM2835CprmanState *s,
142
pll->reg_a2w_frac = &s->regs[PLL_INIT_INFO[id].a2w_frac_offset];
143
}
144
145
+
146
+/* PLL channel init info */
147
+typedef struct PLLChannelInitInfo {
148
+ const char *name;
149
+ CprmanPll parent;
150
+ size_t cm_offset;
151
+ uint32_t cm_hold_mask;
152
+ uint32_t cm_load_mask;
153
+ size_t a2w_ctrl_offset;
154
+ unsigned int fixed_divider;
155
+} PLLChannelInitInfo;
156
+
157
+#define FILL_PLL_CHANNEL_INIT_INFO_common(pll_, channel_) \
158
+ .parent = CPRMAN_ ## pll_, \
159
+ .cm_offset = R_CM_ ## pll_, \
160
+ .cm_load_mask = R_CM_ ## pll_ ## _ ## LOAD ## channel_ ## _MASK, \
161
+ .a2w_ctrl_offset = R_A2W_ ## pll_ ## _ ## channel_
162
+
163
+#define FILL_PLL_CHANNEL_INIT_INFO(pll_, channel_) \
164
+ FILL_PLL_CHANNEL_INIT_INFO_common(pll_, channel_), \
165
+ .cm_hold_mask = R_CM_ ## pll_ ## _ ## HOLD ## channel_ ## _MASK, \
166
+ .fixed_divider = 1
167
+
168
+#define FILL_PLL_CHANNEL_INIT_INFO_nohold(pll_, channel_) \
169
+ FILL_PLL_CHANNEL_INIT_INFO_common(pll_, channel_), \
170
+ .cm_hold_mask = 0
171
+
172
+static PLLChannelInitInfo PLL_CHANNEL_INIT_INFO[] = {
173
+ [CPRMAN_PLLA_CHANNEL_DSI0] = {
174
+ .name = "plla-dsi0",
175
+ FILL_PLL_CHANNEL_INIT_INFO(PLLA, DSI0),
176
+ },
177
+ [CPRMAN_PLLA_CHANNEL_CORE] = {
178
+ .name = "plla-core",
179
+ FILL_PLL_CHANNEL_INIT_INFO(PLLA, CORE),
180
+ },
181
+ [CPRMAN_PLLA_CHANNEL_PER] = {
182
+ .name = "plla-per",
183
+ FILL_PLL_CHANNEL_INIT_INFO(PLLA, PER),
184
+ },
185
+ [CPRMAN_PLLA_CHANNEL_CCP2] = {
186
+ .name = "plla-ccp2",
187
+ FILL_PLL_CHANNEL_INIT_INFO(PLLA, CCP2),
188
+ },
189
+
190
+ [CPRMAN_PLLC_CHANNEL_CORE2] = {
191
+ .name = "pllc-core2",
192
+ FILL_PLL_CHANNEL_INIT_INFO(PLLC, CORE2),
193
+ },
194
+ [CPRMAN_PLLC_CHANNEL_CORE1] = {
195
+ .name = "pllc-core1",
196
+ FILL_PLL_CHANNEL_INIT_INFO(PLLC, CORE1),
197
+ },
198
+ [CPRMAN_PLLC_CHANNEL_PER] = {
199
+ .name = "pllc-per",
200
+ FILL_PLL_CHANNEL_INIT_INFO(PLLC, PER),
201
+ },
202
+ [CPRMAN_PLLC_CHANNEL_CORE0] = {
203
+ .name = "pllc-core0",
204
+ FILL_PLL_CHANNEL_INIT_INFO(PLLC, CORE0),
205
+ },
206
+
207
+ [CPRMAN_PLLD_CHANNEL_DSI0] = {
208
+ .name = "plld-dsi0",
209
+ FILL_PLL_CHANNEL_INIT_INFO(PLLD, DSI0),
210
+ },
211
+ [CPRMAN_PLLD_CHANNEL_CORE] = {
212
+ .name = "plld-core",
213
+ FILL_PLL_CHANNEL_INIT_INFO(PLLD, CORE),
214
+ },
215
+ [CPRMAN_PLLD_CHANNEL_PER] = {
216
+ .name = "plld-per",
217
+ FILL_PLL_CHANNEL_INIT_INFO(PLLD, PER),
218
+ },
219
+ [CPRMAN_PLLD_CHANNEL_DSI1] = {
220
+ .name = "plld-dsi1",
221
+ FILL_PLL_CHANNEL_INIT_INFO(PLLD, DSI1),
222
+ },
223
+
224
+ [CPRMAN_PLLH_CHANNEL_AUX] = {
225
+ .name = "pllh-aux",
226
+ .fixed_divider = 1,
227
+ FILL_PLL_CHANNEL_INIT_INFO_nohold(PLLH, AUX),
228
+ },
229
+ [CPRMAN_PLLH_CHANNEL_RCAL] = {
230
+ .name = "pllh-rcal",
231
+ .fixed_divider = 10,
232
+ FILL_PLL_CHANNEL_INIT_INFO_nohold(PLLH, RCAL),
233
+ },
234
+ [CPRMAN_PLLH_CHANNEL_PIX] = {
235
+ .name = "pllh-pix",
236
+ .fixed_divider = 10,
237
+ FILL_PLL_CHANNEL_INIT_INFO_nohold(PLLH, PIX),
238
+ },
239
+
240
+ [CPRMAN_PLLB_CHANNEL_ARM] = {
241
+ .name = "pllb-arm",
242
+ FILL_PLL_CHANNEL_INIT_INFO(PLLB, ARM),
243
+ },
244
+};
245
+
246
+#undef FILL_PLL_CHANNEL_INIT_INFO_nohold
247
+#undef FILL_PLL_CHANNEL_INIT_INFO
248
+#undef FILL_PLL_CHANNEL_INIT_INFO_common
249
+
250
+static inline void set_pll_channel_init_info(BCM2835CprmanState *s,
251
+ CprmanPllChannelState *channel,
252
+ CprmanPllChannel id)
253
+{
254
+ channel->id = id;
255
+ channel->parent = PLL_CHANNEL_INIT_INFO[id].parent;
256
+ channel->reg_cm = &s->regs[PLL_CHANNEL_INIT_INFO[id].cm_offset];
257
+ channel->hold_mask = PLL_CHANNEL_INIT_INFO[id].cm_hold_mask;
258
+ channel->load_mask = PLL_CHANNEL_INIT_INFO[id].cm_load_mask;
259
+ channel->reg_a2w_ctrl = &s->regs[PLL_CHANNEL_INIT_INFO[id].a2w_ctrl_offset];
260
+ channel->fixed_divider = PLL_CHANNEL_INIT_INFO[id].fixed_divider;
261
+}
262
+
263
#endif
264
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
265
index XXXXXXX..XXXXXXX 100644
266
--- a/hw/misc/bcm2835_cprman.c
267
+++ b/hw/misc/bcm2835_cprman.c
268
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_info = {
269
};
270
271
272
+/* PLL channel */
273
+
274
+static void pll_channel_update(CprmanPllChannelState *channel)
275
+{
276
+ clock_update(channel->out, 0);
277
+}
278
+
279
+/* Update a PLL and all its channels */
280
+static void pll_update_all_channels(BCM2835CprmanState *s,
281
+ CprmanPllState *pll)
282
+{
283
+ size_t i;
284
+
285
+ pll_update(pll);
286
+
287
+ for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
288
+ CprmanPllChannelState *channel = &s->channels[i];
289
+ if (channel->parent == pll->id) {
290
+ pll_channel_update(channel);
291
+ }
292
+ }
293
+}
294
+
295
+static void pll_channel_pll_in_update(void *opaque)
296
+{
297
+ pll_channel_update(CPRMAN_PLL_CHANNEL(opaque));
298
+}
299
+
300
+static void pll_channel_init(Object *obj)
301
+{
302
+ CprmanPllChannelState *s = CPRMAN_PLL_CHANNEL(obj);
303
+
304
+ s->pll_in = qdev_init_clock_in(DEVICE(s), "pll-in",
305
+ pll_channel_pll_in_update, s);
306
+ s->out = qdev_init_clock_out(DEVICE(s), "out");
307
+}
308
+
309
+static const VMStateDescription pll_channel_vmstate = {
310
+ .name = TYPE_CPRMAN_PLL_CHANNEL,
311
+ .version_id = 1,
312
+ .minimum_version_id = 1,
313
+ .fields = (VMStateField[]) {
314
+ VMSTATE_CLOCK(pll_in, CprmanPllChannelState),
315
+ VMSTATE_END_OF_LIST()
316
+ }
317
+};
318
+
319
+static void pll_channel_class_init(ObjectClass *klass, void *data)
320
+{
321
+ DeviceClass *dc = DEVICE_CLASS(klass);
322
+
323
+ dc->vmsd = &pll_channel_vmstate;
324
+}
325
+
326
+static const TypeInfo cprman_pll_channel_info = {
327
+ .name = TYPE_CPRMAN_PLL_CHANNEL,
328
+ .parent = TYPE_DEVICE,
329
+ .instance_size = sizeof(CprmanPllChannelState),
330
+ .class_init = pll_channel_class_init,
331
+ .instance_init = pll_channel_init,
332
+};
333
+
334
+
335
/* CPRMAN "top level" model */
336
337
static uint32_t get_cm_lock(const BCM2835CprmanState *s)
338
@@ -XXX,XX +XXX,XX @@ static uint64_t cprman_read(void *opaque, hwaddr offset,
339
return r;
340
}
341
342
-#define CASE_PLL_REGS(pll_) \
343
- case R_CM_ ## pll_: \
344
+static inline void update_pll_and_channels_from_cm(BCM2835CprmanState *s,
345
+ size_t idx)
346
+{
347
+ size_t i;
348
+
349
+ for (i = 0; i < CPRMAN_NUM_PLL; i++) {
350
+ if (PLL_INIT_INFO[i].cm_offset == idx) {
351
+ pll_update_all_channels(s, &s->plls[i]);
352
+ return;
353
+ }
354
+ }
355
+}
356
+
357
+static inline void update_channel_from_a2w(BCM2835CprmanState *s, size_t idx)
358
+{
359
+ size_t i;
360
+
361
+ for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
362
+ if (PLL_CHANNEL_INIT_INFO[i].a2w_ctrl_offset == idx) {
363
+ pll_channel_update(&s->channels[i]);
364
+ return;
365
+ }
366
+ }
367
+}
368
+
369
+#define CASE_PLL_A2W_REGS(pll_) \
370
case R_A2W_ ## pll_ ## _CTRL: \
371
case R_A2W_ ## pll_ ## _ANA0: \
372
case R_A2W_ ## pll_ ## _ANA1: \
373
@@ -XXX,XX +XXX,XX @@ static void cprman_write(void *opaque, hwaddr offset,
374
s->regs[idx] = value;
375
376
switch (idx) {
377
- CASE_PLL_REGS(PLLA) :
378
+ case R_CM_PLLA ... R_CM_PLLH:
379
+ case R_CM_PLLB:
380
+ /*
381
+ * A given CM_PLLx register is shared by both the PLL and the channels
382
+ * of this PLL.
383
+ */
384
+ update_pll_and_channels_from_cm(s, idx);
385
+ break;
386
+
387
+ CASE_PLL_A2W_REGS(PLLA) :
388
pll_update(&s->plls[CPRMAN_PLLA]);
389
break;
390
391
- CASE_PLL_REGS(PLLC) :
392
+ CASE_PLL_A2W_REGS(PLLC) :
393
pll_update(&s->plls[CPRMAN_PLLC]);
394
break;
395
396
- CASE_PLL_REGS(PLLD) :
397
+ CASE_PLL_A2W_REGS(PLLD) :
398
pll_update(&s->plls[CPRMAN_PLLD]);
399
break;
400
401
- CASE_PLL_REGS(PLLH) :
402
+ CASE_PLL_A2W_REGS(PLLH) :
403
pll_update(&s->plls[CPRMAN_PLLH]);
404
break;
405
406
- CASE_PLL_REGS(PLLB) :
407
+ CASE_PLL_A2W_REGS(PLLB) :
408
pll_update(&s->plls[CPRMAN_PLLB]);
409
break;
410
+
411
+ case R_A2W_PLLA_DSI0:
412
+ case R_A2W_PLLA_CORE:
413
+ case R_A2W_PLLA_PER:
414
+ case R_A2W_PLLA_CCP2:
415
+ case R_A2W_PLLC_CORE2:
416
+ case R_A2W_PLLC_CORE1:
417
+ case R_A2W_PLLC_PER:
418
+ case R_A2W_PLLC_CORE0:
419
+ case R_A2W_PLLD_DSI0:
420
+ case R_A2W_PLLD_CORE:
421
+ case R_A2W_PLLD_PER:
422
+ case R_A2W_PLLD_DSI1:
423
+ case R_A2W_PLLH_AUX:
424
+ case R_A2W_PLLH_RCAL:
425
+ case R_A2W_PLLH_PIX:
426
+ case R_A2W_PLLB_ARM:
427
+ update_channel_from_a2w(s, idx);
428
+ break;
62
}
429
}
63
}
430
}
64
431
65
-/* Write to v7M CONTROL.SPSEL bit. This may change the current
432
-#undef CASE_PLL_REGS
66
+/*
433
+#undef CASE_PLL_A2W_REGS
67
+ * Write to v7M CONTROL.SPSEL bit. This may change the current
434
68
* stack pointer between Main and Process stack pointers.
435
static const MemoryRegionOps cprman_ops = {
69
*/
436
.read = cprman_read,
70
static void write_v7m_control_spsel(CPUARMState *env, bool new_spsel)
437
@@ -XXX,XX +XXX,XX @@ static void cprman_reset(DeviceState *dev)
71
@@ -XXX,XX +XXX,XX @@ static void write_v7m_control_spsel(CPUARMState *env, bool new_spsel)
438
device_cold_reset(DEVICE(&s->plls[i]));
72
73
void write_v7m_exception(CPUARMState *env, uint32_t new_exc)
74
{
75
- /* Write a new value to v7m.exception, thus transitioning into or out
76
+ /*
77
+ * Write a new value to v7m.exception, thus transitioning into or out
78
* of Handler mode; this may result in a change of active stack pointer.
79
*/
80
bool new_is_psp, old_is_psp = v7m_using_psp(env);
81
@@ -XXX,XX +XXX,XX @@ static void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
82
return;
83
}
439
}
84
440
85
- /* All the banked state is accessed by looking at env->v7m.secure
441
+ for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
86
+ /*
442
+ device_cold_reset(DEVICE(&s->channels[i]));
87
+ * All the banked state is accessed by looking at env->v7m.secure
443
+ }
88
* except for the stack pointer; rearrange the SP appropriately.
444
+
89
*/
445
clock_update_hz(s->xosc, s->xosc_freq);
90
new_ss_msp = env->v7m.other_ss_msp;
446
}
91
@@ -XXX,XX +XXX,XX @@ static void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
447
92
448
@@ -XXX,XX +XXX,XX @@ static void cprman_init(Object *obj)
93
void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
449
set_pll_init_info(s, &s->plls[i], i);
94
{
95
- /* Handle v7M BXNS:
96
+ /*
97
+ * Handle v7M BXNS:
98
* - if the return value is a magic value, do exception return (like BX)
99
* - otherwise bit 0 of the return value is the target security state
100
*/
101
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
102
}
450
}
103
451
104
if (dest >= min_magic) {
452
+ for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
105
- /* This is an exception return magic value; put it where
453
+ object_initialize_child(obj, PLL_CHANNEL_INIT_INFO[i].name,
106
+ /*
454
+ &s->channels[i],
107
+ * This is an exception return magic value; put it where
455
+ TYPE_CPRMAN_PLL_CHANNEL);
108
* do_v7m_exception_exit() expects and raise EXCEPTION_EXIT.
456
+ set_pll_channel_init_info(s, &s->channels[i], i);
109
* Note that if we ever add gen_ss_advance() singlestep support to
457
+ }
110
* M profile this should count as an "instruction execution complete"
458
+
111
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
459
s->xosc = clock_new(obj, "xosc");
112
460
113
void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
461
memory_region_init_io(&s->iomem, obj, &cprman_ops,
114
{
462
@@ -XXX,XX +XXX,XX @@ static void cprman_realize(DeviceState *dev, Error **errp)
115
- /* Handle v7M BLXNS:
463
return;
116
+ /*
117
+ * Handle v7M BLXNS:
118
* - bit 0 of the destination address is the target security state
119
*/
120
121
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
122
assert(env->v7m.secure);
123
124
if (dest & 1) {
125
- /* target is Secure, so this is just a normal BLX,
126
+ /*
127
+ * Target is Secure, so this is just a normal BLX,
128
* except that the low bit doesn't indicate Thumb/not.
129
*/
130
env->regs[14] = nextinst;
131
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
132
env->regs[13] = sp;
133
env->regs[14] = 0xfeffffff;
134
if (arm_v7m_is_handler_mode(env)) {
135
- /* Write a dummy value to IPSR, to avoid leaking the current secure
136
+ /*
137
+ * Write a dummy value to IPSR, to avoid leaking the current secure
138
* exception number to non-secure code. This is guaranteed not
139
* to cause write_v7m_exception() to actually change stacks.
140
*/
141
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
142
static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool threadmode,
143
bool spsel)
144
{
145
- /* Return a pointer to the location where we currently store the
146
+ /*
147
+ * Return a pointer to the location where we currently store the
148
* stack pointer for the requested security state and thread mode.
149
* This pointer will become invalid if the CPU state is updated
150
* such that the stack pointers are switched around (eg changing
151
@@ -XXX,XX +XXX,XX @@ static bool arm_v7m_load_vector(ARMCPU *cpu, int exc, bool targets_secure,
152
153
mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, targets_secure, true);
154
155
- /* We don't do a get_phys_addr() here because the rules for vector
156
+ /*
157
+ * We don't do a get_phys_addr() here because the rules for vector
158
* loads are special: they always use the default memory map, and
159
* the default memory map permits reads from all addresses.
160
* Since there's no easy way to pass through to pmsav8_mpu_lookup()
161
@@ -XXX,XX +XXX,XX @@ static bool arm_v7m_load_vector(ARMCPU *cpu, int exc, bool targets_secure,
162
return true;
163
164
load_fail:
165
- /* All vector table fetch fails are reported as HardFault, with
166
+ /*
167
+ * All vector table fetch fails are reported as HardFault, with
168
* HFSR.VECTTBL and .FORCED set. (FORCED is set because
169
* technically the underlying exception is a MemManage or BusFault
170
* that is escalated to HardFault.) This is a terminal exception,
171
@@ -XXX,XX +XXX,XX @@ static uint32_t v7m_integrity_sig(CPUARMState *env, uint32_t lr)
172
static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
173
bool ignore_faults)
174
{
175
- /* For v8M, push the callee-saves register part of the stack frame.
176
+ /*
177
+ * For v8M, push the callee-saves register part of the stack frame.
178
* Compare the v8M pseudocode PushCalleeStack().
179
* In the tailchaining case this may not be the current stack.
180
*/
181
@@ -XXX,XX +XXX,XX @@ static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
182
return true;
183
}
184
185
- /* Write as much of the stack frame as we can. A write failure may
186
+ /*
187
+ * Write as much of the stack frame as we can. A write failure may
188
* cause us to pend a derived exception.
189
*/
190
sig = v7m_integrity_sig(env, lr);
191
@@ -XXX,XX +XXX,XX @@ static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailchain,
192
static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
193
bool ignore_stackfaults)
194
{
195
- /* Do the "take the exception" parts of exception entry,
196
+ /*
197
+ * Do the "take the exception" parts of exception entry,
198
* but not the pushing of state to the stack. This is
199
* similar to the pseudocode ExceptionTaken() function.
200
*/
201
@@ -XXX,XX +XXX,XX @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
202
if (arm_feature(env, ARM_FEATURE_V8)) {
203
if (arm_feature(env, ARM_FEATURE_M_SECURITY) &&
204
(lr & R_V7M_EXCRET_S_MASK)) {
205
- /* The background code (the owner of the registers in the
206
+ /*
207
+ * The background code (the owner of the registers in the
208
* exception frame) is Secure. This means it may either already
209
* have or now needs to push callee-saves registers.
210
*/
211
if (targets_secure) {
212
if (dotailchain && !(lr & R_V7M_EXCRET_ES_MASK)) {
213
- /* We took an exception from Secure to NonSecure
214
+ /*
215
+ * We took an exception from Secure to NonSecure
216
* (which means the callee-saved registers got stacked)
217
* and are now tailchaining to a Secure exception.
218
* Clear DCRS so eventual return from this Secure
219
@@ -XXX,XX +XXX,XX @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
220
lr &= ~R_V7M_EXCRET_DCRS_MASK;
221
}
222
} else {
223
- /* We're going to a non-secure exception; push the
224
+ /*
225
+ * We're going to a non-secure exception; push the
226
* callee-saves registers to the stack now, if they're
227
* not already saved.
228
*/
229
@@ -XXX,XX +XXX,XX @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
230
lr |= R_V7M_EXCRET_SPSEL_MASK;
231
}
232
233
- /* Clear registers if necessary to prevent non-secure exception
234
+ /*
235
+ * Clear registers if necessary to prevent non-secure exception
236
* code being able to see register values from secure code.
237
* Where register values become architecturally UNKNOWN we leave
238
* them with their previous values.
239
*/
240
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
241
if (!targets_secure) {
242
- /* Always clear the caller-saved registers (they have been
243
+ /*
244
+ * Always clear the caller-saved registers (they have been
245
* pushed to the stack earlier in v7m_push_stack()).
246
* Clear callee-saved registers if the background code is
247
* Secure (in which case these regs were saved in
248
@@ -XXX,XX +XXX,XX @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
249
}
250
251
if (push_failed && !ignore_stackfaults) {
252
- /* Derived exception on callee-saves register stacking:
253
+ /*
254
+ * Derived exception on callee-saves register stacking:
255
* we might now want to take a different exception which
256
* targets a different security state, so try again from the top.
257
*/
258
@@ -XXX,XX +XXX,XX @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain,
259
return;
260
}
261
262
- /* Now we've done everything that might cause a derived exception
263
+ /*
264
+ * Now we've done everything that might cause a derived exception
265
* we can go ahead and activate whichever exception we're going to
266
* take (which might now be the derived exception).
267
*/
268
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr)
269
270
static bool v7m_push_stack(ARMCPU *cpu)
271
{
272
- /* Do the "set up stack frame" part of exception entry,
273
+ /*
274
+ * Do the "set up stack frame" part of exception entry,
275
* similar to pseudocode PushStack().
276
* Return true if we generate a derived exception (and so
277
* should ignore further stack faults trying to process
278
@@ -XXX,XX +XXX,XX @@ static bool v7m_push_stack(ARMCPU *cpu)
279
}
464
}
280
}
465
}
281
466
+
282
- /* Write as much of the stack frame as we can. If we fail a stack
467
+ for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
283
+ /*
468
+ CprmanPllChannelState *channel = &s->channels[i];
284
+ * Write as much of the stack frame as we can. If we fail a stack
469
+ CprmanPll parent = PLL_CHANNEL_INIT_INFO[i].parent;
285
* write this will result in a derived exception being pended
470
+ Clock *parent_clk = s->plls[parent].out;
286
* (which may be taken in preference to the one we started with
471
+
287
* if it has higher priority).
472
+ clock_set_source(channel->pll_in, parent_clk);
288
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
473
+
289
bool ftype;
474
+ if (!qdev_realize(DEVICE(channel), NULL, errp)) {
290
bool restore_s16_s31;
475
+ return;
291
476
+ }
292
- /* If we're not in Handler mode then jumps to magic exception-exit
477
+ }
293
+ /*
478
}
294
+ * If we're not in Handler mode then jumps to magic exception-exit
479
295
* addresses don't have magic behaviour. However for the v8M
480
static const VMStateDescription cprman_vmstate = {
296
* security extensions the magic secure-function-return has to
481
@@ -XXX,XX +XXX,XX @@ static void cprman_register_types(void)
297
* work in thread mode too, so to avoid doing an extra check in
298
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
299
return;
300
}
301
302
- /* In the spec pseudocode ExceptionReturn() is called directly
303
+ /*
304
+ * In the spec pseudocode ExceptionReturn() is called directly
305
* from BXWritePC() and gets the full target PC value including
306
* bit zero. In QEMU's implementation we treat it as a normal
307
* jump-to-register (which is then caught later on), and so split
308
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
309
}
310
311
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
312
- /* EXC_RETURN.ES validation check (R_SMFL). We must do this before
313
+ /*
314
+ * EXC_RETURN.ES validation check (R_SMFL). We must do this before
315
* we pick which FAULTMASK to clear.
316
*/
317
if (!env->v7m.secure &&
318
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
319
}
320
321
if (env->v7m.exception != ARMV7M_EXCP_NMI) {
322
- /* Auto-clear FAULTMASK on return from other than NMI.
323
+ /*
324
+ * Auto-clear FAULTMASK on return from other than NMI.
325
* If the security extension is implemented then this only
326
* happens if the raw execution priority is >= 0; the
327
* value of the ES bit in the exception return value indicates
328
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
329
/* still an irq active now */
330
break;
331
case 1:
332
- /* we returned to base exception level, no nesting.
333
+ /*
334
+ * We returned to base exception level, no nesting.
335
* (In the pseudocode this is written using "NestedActivation != 1"
336
* where we have 'rettobase == false'.)
337
*/
338
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
339
340
if (arm_feature(env, ARM_FEATURE_V8)) {
341
if (!arm_feature(env, ARM_FEATURE_M_SECURITY)) {
342
- /* UNPREDICTABLE if S == 1 or DCRS == 0 or ES == 1 (R_XLCP);
343
+ /*
344
+ * UNPREDICTABLE if S == 1 or DCRS == 0 or ES == 1 (R_XLCP);
345
* we choose to take the UsageFault.
346
*/
347
if ((excret & R_V7M_EXCRET_S_MASK) ||
348
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
349
break;
350
case 13: /* Return to Thread using Process stack */
351
case 9: /* Return to Thread using Main stack */
352
- /* We only need to check NONBASETHRDENA for v7M, because in
353
+ /*
354
+ * We only need to check NONBASETHRDENA for v7M, because in
355
* v8M this bit does not exist (it is RES1).
356
*/
357
if (!rettobase &&
358
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
359
}
360
361
if (ufault) {
362
- /* Bad exception return: instead of popping the exception
363
+ /*
364
+ * Bad exception return: instead of popping the exception
365
* stack, directly take a usage fault on the current stack.
366
*/
367
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
368
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
369
switch_v7m_security_state(env, return_to_secure);
370
371
{
372
- /* The stack pointer we should be reading the exception frame from
373
+ /*
374
+ * The stack pointer we should be reading the exception frame from
375
* depends on bits in the magic exception return type value (and
376
* for v8M isn't necessarily the stack pointer we will eventually
377
* end up resuming execution with). Get a pointer to the location
378
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
379
v7m_stack_read(cpu, &xpsr, frameptr + 0x1c, mmu_idx);
380
381
if (!pop_ok) {
382
- /* v7m_stack_read() pended a fault, so take it (as a tail
383
+ /*
384
+ * v7m_stack_read() pended a fault, so take it (as a tail
385
* chained exception on the same stack frame)
386
*/
387
qemu_log_mask(CPU_LOG_INT, "...derived exception on unstacking\n");
388
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
389
return;
390
}
391
392
- /* Returning from an exception with a PC with bit 0 set is defined
393
+ /*
394
+ * Returning from an exception with a PC with bit 0 set is defined
395
* behaviour on v8M (bit 0 is ignored), but for v7M it was specified
396
* to be UNPREDICTABLE. In practice actual v7M hardware seems to ignore
397
* the lsbit, and there are several RTOSes out there which incorrectly
398
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
399
}
400
401
if (arm_feature(env, ARM_FEATURE_V8)) {
402
- /* For v8M we have to check whether the xPSR exception field
403
+ /*
404
+ * For v8M we have to check whether the xPSR exception field
405
* matches the EXCRET value for return to handler/thread
406
* before we commit to changing the SP and xPSR.
407
*/
408
bool will_be_handler = (xpsr & XPSR_EXCP) != 0;
409
if (return_to_handler != will_be_handler) {
410
- /* Take an INVPC UsageFault on the current stack.
411
+ /*
412
+ * Take an INVPC UsageFault on the current stack.
413
* By this point we will have switched to the security state
414
* for the background state, so this UsageFault will target
415
* that state.
416
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
417
frameptr += 0x40;
418
}
419
}
420
- /* Undo stack alignment (the SPREALIGN bit indicates that the original
421
+ /*
422
+ * Undo stack alignment (the SPREALIGN bit indicates that the original
423
* pre-exception SP was not 8-aligned and we added a padding word to
424
* align it, so we undo this by ORing in the bit that increases it
425
* from the current 8-aligned value to the 8-unaligned value. (Adding 4
426
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
427
V7M_CONTROL, SFPA, sfpa);
428
}
429
430
- /* The restored xPSR exception field will be zero if we're
431
+ /*
432
+ * The restored xPSR exception field will be zero if we're
433
* resuming in Thread mode. If that doesn't match what the
434
* exception return excret specified then this is a UsageFault.
435
* v7M requires we make this check here; v8M did it earlier.
436
*/
437
if (return_to_handler != arm_v7m_is_handler_mode(env)) {
438
- /* Take an INVPC UsageFault by pushing the stack again;
439
+ /*
440
+ * Take an INVPC UsageFault by pushing the stack again;
441
* we know we're v7M so this is never a Secure UsageFault.
442
*/
443
bool ignore_stackfaults;
444
@@ -XXX,XX +XXX,XX @@ static void do_v7m_exception_exit(ARMCPU *cpu)
445
446
static bool do_v7m_function_return(ARMCPU *cpu)
447
{
482
{
448
- /* v8M security extensions magic function return.
483
type_register_static(&cprman_info);
449
+ /*
484
type_register_static(&cprman_pll_info);
450
+ * v8M security extensions magic function return.
485
+ type_register_static(&cprman_pll_channel_info);
451
* We may either:
486
}
452
* (1) throw an exception (longjump)
487
453
* (2) return true if we successfully handled the function return
488
type_init(cprman_register_types);
454
@@ -XXX,XX +XXX,XX @@ static bool do_v7m_function_return(ARMCPU *cpu)
455
frame_sp_p = get_v7m_sp_ptr(env, true, threadmode, spsel);
456
frameptr = *frame_sp_p;
457
458
- /* These loads may throw an exception (for MPU faults). We want to
459
+ /*
460
+ * These loads may throw an exception (for MPU faults). We want to
461
* do them as secure, so work out what MMU index that is.
462
*/
463
mmu_idx = arm_v7m_mmu_idx_for_secstate(env, true);
464
@@ -XXX,XX +XXX,XX @@ static void arm_log_exception(int idx)
465
static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx,
466
uint32_t addr, uint16_t *insn)
467
{
468
- /* Load a 16-bit portion of a v7M instruction, returning true on success,
469
+ /*
470
+ * Load a 16-bit portion of a v7M instruction, returning true on success,
471
* or false on failure (in which case we will have pended the appropriate
472
* exception).
473
* We need to do the instruction fetch's MPU and SAU checks
474
@@ -XXX,XX +XXX,XX @@ static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx,
475
476
v8m_security_lookup(env, addr, MMU_INST_FETCH, mmu_idx, &sattrs);
477
if (!sattrs.nsc || sattrs.ns) {
478
- /* This must be the second half of the insn, and it straddles a
479
+ /*
480
+ * This must be the second half of the insn, and it straddles a
481
* region boundary with the second half not being S&NSC.
482
*/
483
env->v7m.sfsr |= R_V7M_SFSR_INVEP_MASK;
484
@@ -XXX,XX +XXX,XX @@ static bool v7m_read_half_insn(ARMCPU *cpu, ARMMMUIdx mmu_idx,
485
486
static bool v7m_handle_execute_nsc(ARMCPU *cpu)
487
{
488
- /* Check whether this attempt to execute code in a Secure & NS-Callable
489
+ /*
490
+ * Check whether this attempt to execute code in a Secure & NS-Callable
491
* memory region is for an SG instruction; if so, then emulate the
492
* effect of the SG instruction and return true. Otherwise pend
493
* the correct kind of exception and return false.
494
@@ -XXX,XX +XXX,XX @@ static bool v7m_handle_execute_nsc(ARMCPU *cpu)
495
ARMMMUIdx mmu_idx;
496
uint16_t insn;
497
498
- /* We should never get here unless get_phys_addr_pmsav8() caused
499
+ /*
500
+ * We should never get here unless get_phys_addr_pmsav8() caused
501
* an exception for NS executing in S&NSC memory.
502
*/
503
assert(!env->v7m.secure);
504
@@ -XXX,XX +XXX,XX @@ static bool v7m_handle_execute_nsc(ARMCPU *cpu)
505
}
506
507
if (insn != 0xe97f) {
508
- /* Not an SG instruction first half (we choose the IMPDEF
509
+ /*
510
+ * Not an SG instruction first half (we choose the IMPDEF
511
* early-SG-check option).
512
*/
513
goto gen_invep;
514
@@ -XXX,XX +XXX,XX @@ static bool v7m_handle_execute_nsc(ARMCPU *cpu)
515
}
516
517
if (insn != 0xe97f) {
518
- /* Not an SG instruction second half (yes, both halves of the SG
519
+ /*
520
+ * Not an SG instruction second half (yes, both halves of the SG
521
* insn have the same hex value)
522
*/
523
goto gen_invep;
524
}
525
526
- /* OK, we have confirmed that we really have an SG instruction.
527
+ /*
528
+ * OK, we have confirmed that we really have an SG instruction.
529
* We know we're NS in S memory so don't need to repeat those checks.
530
*/
531
qemu_log_mask(CPU_LOG_INT, "...really an SG instruction at 0x%08" PRIx32
532
@@ -XXX,XX +XXX,XX @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
533
534
arm_log_exception(cs->exception_index);
535
536
- /* For exceptions we just mark as pending on the NVIC, and let that
537
- handle it. */
538
+ /*
539
+ * For exceptions we just mark as pending on the NVIC, and let that
540
+ * handle it.
541
+ */
542
switch (cs->exception_index) {
543
case EXCP_UDEF:
544
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure);
545
@@ -XXX,XX +XXX,XX @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
546
break;
547
case EXCP_PREFETCH_ABORT:
548
case EXCP_DATA_ABORT:
549
- /* Note that for M profile we don't have a guest facing FSR, but
550
+ /*
551
+ * Note that for M profile we don't have a guest facing FSR, but
552
* the env->exception.fsr will be populated by the code that
553
* raises the fault, in the A profile short-descriptor format.
554
*/
555
switch (env->exception.fsr & 0xf) {
556
case M_FAKE_FSR_NSC_EXEC:
557
- /* Exception generated when we try to execute code at an address
558
+ /*
559
+ * Exception generated when we try to execute code at an address
560
* which is marked as Secure & Non-Secure Callable and the CPU
561
* is in the Non-Secure state. The only instruction which can
562
* be executed like this is SG (and that only if both halves of
563
@@ -XXX,XX +XXX,XX @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
564
}
565
break;
566
case M_FAKE_FSR_SFAULT:
567
- /* Various flavours of SecureFault for attempts to execute or
568
+ /*
569
+ * Various flavours of SecureFault for attempts to execute or
570
* access data in the wrong security state.
571
*/
572
switch (cs->exception_index) {
573
@@ -XXX,XX +XXX,XX @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
574
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS, false);
575
break;
576
default:
577
- /* All other FSR values are either MPU faults or "can't happen
578
+ /*
579
+ * All other FSR values are either MPU faults or "can't happen
580
* for M profile" cases.
581
*/
582
switch (cs->exception_index) {
583
@@ -XXX,XX +XXX,XX @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
584
if (arm_feature(env, ARM_FEATURE_V8)) {
585
lr = R_V7M_EXCRET_RES1_MASK |
586
R_V7M_EXCRET_DCRS_MASK;
587
- /* The S bit indicates whether we should return to Secure
588
+ /*
589
+ * The S bit indicates whether we should return to Secure
590
* or NonSecure (ie our current state).
591
* The ES bit indicates whether we're taking this exception
592
* to Secure or NonSecure (ie our target state). We set it
593
@@ -XXX,XX +XXX,XX @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
594
v7m_exception_taken(cpu, lr, false, ignore_stackfaults);
595
}
596
597
-/* Function used to synchronize QEMU's AArch64 register set with AArch32
598
+/*
599
+ * Function used to synchronize QEMU's AArch64 register set with AArch32
600
* register set. This is necessary when switching between AArch32 and AArch64
601
* execution state.
602
*/
603
@@ -XXX,XX +XXX,XX @@ void aarch64_sync_32_to_64(CPUARMState *env)
604
env->xregs[i] = env->regs[i];
605
}
606
607
- /* Unless we are in FIQ mode, x8-x12 come from the user registers r8-r12.
608
+ /*
609
+ * Unless we are in FIQ mode, x8-x12 come from the user registers r8-r12.
610
* Otherwise, they come from the banked user regs.
611
*/
612
if (mode == ARM_CPU_MODE_FIQ) {
613
@@ -XXX,XX +XXX,XX @@ void aarch64_sync_32_to_64(CPUARMState *env)
614
}
615
}
616
617
- /* Registers x13-x23 are the various mode SP and FP registers. Registers
618
+ /*
619
+ * Registers x13-x23 are the various mode SP and FP registers. Registers
620
* r13 and r14 are only copied if we are in that mode, otherwise we copy
621
* from the mode banked register.
622
*/
623
@@ -XXX,XX +XXX,XX @@ void aarch64_sync_32_to_64(CPUARMState *env)
624
env->xregs[23] = env->banked_r13[bank_number(ARM_CPU_MODE_UND)];
625
}
626
627
- /* Registers x24-x30 are mapped to r8-r14 in FIQ mode. If we are in FIQ
628
+ /*
629
+ * Registers x24-x30 are mapped to r8-r14 in FIQ mode. If we are in FIQ
630
* mode, then we can copy from r8-r14. Otherwise, we copy from the
631
* FIQ bank for r8-r14.
632
*/
633
@@ -XXX,XX +XXX,XX @@ void aarch64_sync_32_to_64(CPUARMState *env)
634
env->pc = env->regs[15];
635
}
636
637
-/* Function used to synchronize QEMU's AArch32 register set with AArch64
638
+/*
639
+ * Function used to synchronize QEMU's AArch32 register set with AArch64
640
* register set. This is necessary when switching between AArch32 and AArch64
641
* execution state.
642
*/
643
@@ -XXX,XX +XXX,XX @@ void aarch64_sync_64_to_32(CPUARMState *env)
644
env->regs[i] = env->xregs[i];
645
}
646
647
- /* Unless we are in FIQ mode, r8-r12 come from the user registers x8-x12.
648
+ /*
649
+ * Unless we are in FIQ mode, r8-r12 come from the user registers x8-x12.
650
* Otherwise, we copy x8-x12 into the banked user regs.
651
*/
652
if (mode == ARM_CPU_MODE_FIQ) {
653
@@ -XXX,XX +XXX,XX @@ void aarch64_sync_64_to_32(CPUARMState *env)
654
}
655
}
656
657
- /* Registers r13 & r14 depend on the current mode.
658
+ /*
659
+ * Registers r13 & r14 depend on the current mode.
660
* If we are in a given mode, we copy the corresponding x registers to r13
661
* and r14. Otherwise, we copy the x register to the banked r13 and r14
662
* for the mode.
663
@@ -XXX,XX +XXX,XX @@ void aarch64_sync_64_to_32(CPUARMState *env)
664
} else {
665
env->banked_r13[bank_number(ARM_CPU_MODE_USR)] = env->xregs[13];
666
667
- /* HYP is an exception in that it does not have its own banked r14 but
668
+ /*
669
+ * HYP is an exception in that it does not have its own banked r14 but
670
* shares the USR r14
671
*/
672
if (mode == ARM_CPU_MODE_HYP) {
673
@@ -XXX,XX +XXX,XX @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
674
return value;
675
}
676
case 0x94: /* CONTROL_NS */
677
- /* We have to handle this here because unprivileged Secure code
678
+ /*
679
+ * We have to handle this here because unprivileged Secure code
680
* can read the NS CONTROL register.
681
*/
682
if (!env->v7m.secure) {
683
@@ -XXX,XX +XXX,XX @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
684
return env->v7m.faultmask[M_REG_NS];
685
case 0x98: /* SP_NS */
686
{
687
- /* This gives the non-secure SP selected based on whether we're
688
+ /*
689
+ * This gives the non-secure SP selected based on whether we're
690
* currently in handler mode or not, using the NS CONTROL.SPSEL.
691
*/
692
bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
693
@@ -XXX,XX +XXX,XX @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
694
695
void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
696
{
697
- /* We're passed bits [11..0] of the instruction; extract
698
+ /*
699
+ * We're passed bits [11..0] of the instruction; extract
700
* SYSm and the mask bits.
701
* Invalid combinations of SYSm and mask are UNPREDICTABLE;
702
* we choose to treat them as if the mask bits were valid.
703
@@ -XXX,XX +XXX,XX @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
704
return;
705
case 0x98: /* SP_NS */
706
{
707
- /* This gives the non-secure SP selected based on whether we're
708
+ /*
709
+ * This gives the non-secure SP selected based on whether we're
710
* currently in handler mode or not, using the NS CONTROL.SPSEL.
711
*/
712
bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
713
@@ -XXX,XX +XXX,XX @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
714
bool targetsec = env->v7m.secure;
715
bool is_subpage;
716
717
- /* Work out what the security state and privilege level we're
718
+ /*
719
+ * Work out what the security state and privilege level we're
720
* interested in is...
721
*/
722
if (alt) {
723
@@ -XXX,XX +XXX,XX @@ uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
724
/* ...and then figure out which MMU index this is */
725
mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, targetsec, targetpriv);
726
727
- /* We know that the MPU and SAU don't care about the access type
728
+ /*
729
+ * We know that the MPU and SAU don't care about the access type
730
* for our purposes beyond that we don't want to claim to be
731
* an insn fetch, so we arbitrarily call this a read.
732
*/
733
734
- /* MPU region info only available for privileged or if
735
+ /*
736
+ * MPU region info only available for privileged or if
737
* inspecting the other MPU state.
738
*/
739
if (arm_current_el(env) != 0 || alt) {
740
@@ -XXX,XX +XXX,XX @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
741
742
void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
743
{
744
- /* Implement DC ZVA, which zeroes a fixed-length block of memory.
745
+ /*
746
+ * Implement DC ZVA, which zeroes a fixed-length block of memory.
747
* Note that we do not implement the (architecturally mandated)
748
* alignment fault for attempts to use this on Device memory
749
* (which matches the usual QEMU behaviour of not implementing either
750
@@ -XXX,XX +XXX,XX @@ void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
751
752
#ifndef CONFIG_USER_ONLY
753
{
754
- /* Slightly awkwardly, QEMU's TARGET_PAGE_SIZE may be less than
755
+ /*
756
+ * Slightly awkwardly, QEMU's TARGET_PAGE_SIZE may be less than
757
* the block size so we might have to do more than one TLB lookup.
758
* We know that in fact for any v8 CPU the page size is at least 4K
759
* and the block size must be 2K or less, but TARGET_PAGE_SIZE is only
760
@@ -XXX,XX +XXX,XX @@ void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
761
}
762
}
763
if (i == maxidx) {
764
- /* If it's all in the TLB it's fair game for just writing to;
765
+ /*
766
+ * If it's all in the TLB it's fair game for just writing to;
767
* we know we don't need to update dirty status, etc.
768
*/
769
for (i = 0; i < maxidx - 1; i++) {
770
@@ -XXX,XX +XXX,XX @@ void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
771
memset(hostaddr[i], 0, blocklen - (i * TARGET_PAGE_SIZE));
772
return;
773
}
774
- /* OK, try a store and see if we can populate the tlb. This
775
+ /*
776
+ * OK, try a store and see if we can populate the tlb. This
777
* might cause an exception if the memory isn't writable,
778
* in which case we will longjmp out of here. We must for
779
* this purpose use the actual register value passed to us
780
@@ -XXX,XX +XXX,XX @@ void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
781
}
782
}
783
784
- /* Slow path (probably attempt to do this to an I/O device or
785
+ /*
786
+ * Slow path (probably attempt to do this to an I/O device or
787
* similar, or clearing of a block of code we have translations
788
* cached for). Just do a series of byte writes as the architecture
789
* demands. It's not worth trying to use a cpu_physical_memory_map(),
790
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
791
index XXXXXXX..XXXXXXX 100644
792
--- a/target/arm/op_helper.c
793
+++ b/target/arm/op_helper.c
794
@@ -XXX,XX +XXX,XX @@ static inline uint32_t merge_syn_data_abort(uint32_t template_syn,
795
{
796
uint32_t syn;
797
798
- /* ISV is only set for data aborts routed to EL2 and
799
+ /*
800
+ * ISV is only set for data aborts routed to EL2 and
801
* never for stage-1 page table walks faulting on stage 2.
802
*
803
* Furthermore, ISV is only set for certain kinds of load/stores.
804
@@ -XXX,XX +XXX,XX @@ static inline uint32_t merge_syn_data_abort(uint32_t template_syn,
805
syn = syn_data_abort_no_iss(same_el,
806
ea, 0, s1ptw, is_write, fsc);
807
} else {
808
- /* Fields: IL, ISV, SAS, SSE, SRT, SF and AR come from the template
809
+ /*
810
+ * Fields: IL, ISV, SAS, SSE, SRT, SF and AR come from the template
811
* syndrome created at translation time.
812
* Now we create the runtime syndrome with the remaining fields.
813
*/
814
@@ -XXX,XX +XXX,XX @@ void arm_deliver_fault(ARMCPU *cpu, vaddr addr, MMUAccessType access_type,
815
816
if (target_el == 2 || arm_el_is_aa64(env, target_el) ||
817
arm_s1_regime_using_lpae_format(env, arm_mmu_idx)) {
818
- /* LPAE format fault status register : bottom 6 bits are
819
+ /*
820
+ * LPAE format fault status register : bottom 6 bits are
821
* status code in the same form as needed for syndrome
822
*/
823
fsr = arm_fi_to_lfsc(fi);
824
fsc = extract32(fsr, 0, 6);
825
} else {
826
fsr = arm_fi_to_sfsc(fi);
827
- /* Short format FSR : this fault will never actually be reported
828
+ /*
829
+ * Short format FSR : this fault will never actually be reported
830
* to an EL that uses a syndrome register. Use a (currently)
831
* reserved FSR code in case the constructed syndrome does leak
832
* into the guest somehow.
833
@@ -XXX,XX +XXX,XX @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
834
arm_deliver_fault(cpu, vaddr, access_type, mmu_idx, &fi);
835
}
836
837
-/* arm_cpu_do_transaction_failed: handle a memory system error response
838
+/*
839
+ * arm_cpu_do_transaction_failed: handle a memory system error response
840
* (eg "no device/memory present at address") by raising an external abort
841
* exception
842
*/
843
@@ -XXX,XX +XXX,XX @@ static bool linked_bp_matches(ARMCPU *cpu, int lbn)
844
int bt;
845
uint32_t contextidr;
846
847
- /* Links to unimplemented or non-context aware breakpoints are
848
+ /*
849
+ * Links to unimplemented or non-context aware breakpoints are
850
* CONSTRAINED UNPREDICTABLE: either behave as if disabled, or
851
* as if linked to an UNKNOWN context-aware breakpoint (in which
852
* case DBGWCR<n>_EL1.LBN must indicate that breakpoint).
853
@@ -XXX,XX +XXX,XX @@ static bool linked_bp_matches(ARMCPU *cpu, int lbn)
854
855
bt = extract64(bcr, 20, 4);
856
857
- /* We match the whole register even if this is AArch32 using the
858
+ /*
859
+ * We match the whole register even if this is AArch32 using the
860
* short descriptor format (in which case it holds both PROCID and ASID),
861
* since we don't implement the optional v7 context ID masking.
862
*/
863
@@ -XXX,XX +XXX,XX @@ static bool linked_bp_matches(ARMCPU *cpu, int lbn)
864
case 9: /* linked VMID match (reserved if no EL2) */
865
case 11: /* linked context ID and VMID match (reserved if no EL2) */
866
default:
867
- /* Links to Unlinked context breakpoints must generate no
868
+ /*
869
+ * Links to Unlinked context breakpoints must generate no
870
* events; we choose to do the same for reserved values too.
871
*/
872
return false;
873
@@ -XXX,XX +XXX,XX @@ static bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp)
874
CPUARMState *env = &cpu->env;
875
uint64_t cr;
876
int pac, hmc, ssc, wt, lbn;
877
- /* Note that for watchpoints the check is against the CPU security
878
+ /*
879
+ * Note that for watchpoints the check is against the CPU security
880
* state, not the S/NS attribute on the offending data access.
881
*/
882
bool is_secure = arm_is_secure(env);
883
@@ -XXX,XX +XXX,XX @@ static bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp)
884
}
885
cr = env->cp15.dbgwcr[n];
886
if (wp->hitattrs.user) {
887
- /* The LDRT/STRT/LDT/STT "unprivileged access" instructions should
888
+ /*
889
+ * The LDRT/STRT/LDT/STT "unprivileged access" instructions should
890
* match watchpoints as if they were accesses done at EL0, even if
891
* the CPU is at EL1 or higher.
892
*/
893
@@ -XXX,XX +XXX,XX @@ static bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp)
894
}
895
cr = env->cp15.dbgbcr[n];
896
}
897
- /* The WATCHPOINT_HIT flag guarantees us that the watchpoint is
898
+ /*
899
+ * The WATCHPOINT_HIT flag guarantees us that the watchpoint is
900
* enabled and that the address and access type match; for breakpoints
901
* we know the address matched; check the remaining fields, including
902
* linked breakpoints. We rely on WCR and BCR having the same layout
903
@@ -XXX,XX +XXX,XX @@ static bool check_watchpoints(ARMCPU *cpu)
904
CPUARMState *env = &cpu->env;
905
int n;
906
907
- /* If watchpoints are disabled globally or we can't take debug
908
+ /*
909
+ * If watchpoints are disabled globally or we can't take debug
910
* exceptions here then watchpoint firings are ignored.
911
*/
912
if (extract32(env->cp15.mdscr_el1, 15, 1) == 0
913
@@ -XXX,XX +XXX,XX @@ static bool check_breakpoints(ARMCPU *cpu)
914
CPUARMState *env = &cpu->env;
915
int n;
916
917
- /* If breakpoints are disabled globally or we can't take debug
918
+ /*
919
+ * If breakpoints are disabled globally or we can't take debug
920
* exceptions here then breakpoint firings are ignored.
921
*/
922
if (extract32(env->cp15.mdscr_el1, 15, 1) == 0
923
@@ -XXX,XX +XXX,XX @@ void HELPER(check_breakpoints)(CPUARMState *env)
924
925
bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp)
926
{
927
- /* Called by core code when a CPU watchpoint fires; need to check if this
928
+ /*
929
+ * Called by core code when a CPU watchpoint fires; need to check if this
930
* is also an architectural watchpoint match.
931
*/
932
ARMCPU *cpu = ARM_CPU(cs);
933
@@ -XXX,XX +XXX,XX @@ vaddr arm_adjust_watchpoint_address(CPUState *cs, vaddr addr, int len)
934
ARMCPU *cpu = ARM_CPU(cs);
935
CPUARMState *env = &cpu->env;
936
937
- /* In BE32 system mode, target memory is stored byteswapped (on a
938
+ /*
939
+ * In BE32 system mode, target memory is stored byteswapped (on a
940
* little-endian host system), and by the time we reach here (via an
941
* opcode helper) the addresses of subword accesses have been adjusted
942
* to account for that, which means that watchpoints will not match.
943
@@ -XXX,XX +XXX,XX @@ vaddr arm_adjust_watchpoint_address(CPUState *cs, vaddr addr, int len)
944
945
void arm_debug_excp_handler(CPUState *cs)
946
{
947
- /* Called by core code when a watchpoint or breakpoint fires;
948
+ /*
949
+ * Called by core code when a watchpoint or breakpoint fires;
950
* need to check which one and raise the appropriate exception.
951
*/
952
ARMCPU *cpu = ARM_CPU(cs);
953
@@ -XXX,XX +XXX,XX @@ void arm_debug_excp_handler(CPUState *cs)
954
uint64_t pc = is_a64(env) ? env->pc : env->regs[15];
955
bool same_el = (arm_debug_target_el(env) == arm_current_el(env));
956
957
- /* (1) GDB breakpoints should be handled first.
958
+ /*
959
+ * (1) GDB breakpoints should be handled first.
960
* (2) Do not raise a CPU exception if no CPU breakpoint has fired,
961
* since singlestep is also done by generating a debug internal
962
* exception.
963
@@ -XXX,XX +XXX,XX @@ void arm_debug_excp_handler(CPUState *cs)
964
}
965
966
env->exception.fsr = arm_debug_exception_fsr(env);
967
- /* FAR is UNKNOWN: clear vaddress to avoid potentially exposing
968
+ /*
969
+ * FAR is UNKNOWN: clear vaddress to avoid potentially exposing
970
* values to the guest that it shouldn't be able to see at its
971
* exception/security level.
972
*/
973
diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c
974
index XXXXXXX..XXXXXXX 100644
975
--- a/target/arm/vfp_helper.c
976
+++ b/target/arm/vfp_helper.c
977
@@ -XXX,XX +XXX,XX @@ void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val)
978
set_default_nan_mode(dnan_enabled, &env->vfp.fp_status_f16);
979
}
980
981
- /* The exception flags are ORed together when we read fpscr so we
982
+ /*
983
+ * The exception flags are ORed together when we read fpscr so we
984
* only need to preserve the current state in one of our
985
* float_status values.
986
*/
987
--
489
--
988
2.20.1
490
2.20.1
989
491
990
492
diff view generated by jsdifflib
1
From: Andrew Jeffery <andrew@aj.id.au>
1
From: Luc Michel <luc@lmichel.fr>
2
2
3
If the match value exceeds reload then we don't want to include it in
3
A PLL channel is able to further divide the generated PLL frequency.
4
calculations for the next event.
4
The divider is given in the CTRL_A2W register. Some channels have an
5
additional fixed divider which is always applied to the signal.
5
6
6
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
7
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Signed-off-by: Cédric Le Goater <clg@kaod.org>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Message-id: 20190618165311.27066-10-clg@kaod.org
9
Signed-off-by: Luc Michel <luc@lmichel.fr>
10
Tested-by: Guenter Roeck <linux@roeck-us.net>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
12
---
11
hw/timer/aspeed_timer.c | 13 ++++++++++---
13
hw/misc/bcm2835_cprman.c | 33 ++++++++++++++++++++++++++++++++-
12
1 file changed, 10 insertions(+), 3 deletions(-)
14
1 file changed, 32 insertions(+), 1 deletion(-)
13
15
14
diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c
16
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
15
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/timer/aspeed_timer.c
18
--- a/hw/misc/bcm2835_cprman.c
17
+++ b/hw/timer/aspeed_timer.c
19
+++ b/hw/misc/bcm2835_cprman.c
18
@@ -XXX,XX +XXX,XX @@ static inline uint64_t calculate_time(struct AspeedTimer *t, uint32_t ticks)
20
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_info = {
19
return t->start + delta_ns;
21
20
}
22
/* PLL channel */
21
23
22
+static inline uint32_t calculate_match(struct AspeedTimer *t, int i)
24
+static bool pll_channel_is_enabled(CprmanPllChannelState *channel)
23
+{
25
+{
24
+ return t->match[i] < t->reload ? t->match[i] : 0;
26
+ /*
27
+ * XXX I'm not sure of the purpose of the LOAD field. The Linux driver does
28
+ * not set it when enabling the channel, but does clear it when disabling
29
+ * it.
30
+ */
31
+ return !FIELD_EX32(*channel->reg_a2w_ctrl, A2W_PLLx_CHANNELy, DISABLE)
32
+ && !(*channel->reg_cm & channel->hold_mask);
25
+}
33
+}
26
+
34
+
27
static uint64_t calculate_next(struct AspeedTimer *t)
35
static void pll_channel_update(CprmanPllChannelState *channel)
28
{
36
{
29
uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
37
- clock_update(channel->out, 0);
30
@@ -XXX,XX +XXX,XX @@ static uint64_t calculate_next(struct AspeedTimer *t)
38
+ uint64_t freq, div;
31
* the timer counts down to zero.
32
*/
33
34
- next = calculate_time(t, MAX(t->match[0], t->match[1]));
35
+ next = calculate_time(t, MAX(calculate_match(t, 0), calculate_match(t, 1)));
36
if (now < next) {
37
return next;
38
}
39
40
- next = calculate_time(t, MIN(t->match[0], t->match[1]));
41
+ next = calculate_time(t, MIN(calculate_match(t, 0), calculate_match(t, 1)));
42
if (now < next) {
43
return next;
44
}
45
@@ -XXX,XX +XXX,XX @@ static uint64_t calculate_next(struct AspeedTimer *t)
46
qemu_set_irq(t->irq, t->level);
47
}
48
49
+ next = MAX(MAX(calculate_match(t, 0), calculate_match(t, 1)), 0);
50
t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
51
- return calculate_time(t, MAX(MAX(t->match[0], t->match[1]), 0));
52
+
39
+
53
+ return calculate_time(t, next);
40
+ if (!pll_channel_is_enabled(channel)) {
41
+ clock_update(channel->out, 0);
42
+ return;
43
+ }
44
+
45
+ div = FIELD_EX32(*channel->reg_a2w_ctrl, A2W_PLLx_CHANNELy, DIV);
46
+
47
+ if (!div) {
48
+ /*
49
+ * It seems that when the divider value is 0, it is considered as
50
+ * being maximum by the hardware (see the Linux driver).
51
+ */
52
+ div = R_A2W_PLLx_CHANNELy_DIV_MASK;
53
+ }
54
+
55
+ /* Some channels have an additional fixed divider */
56
+ freq = clock_get_hz(channel->pll_in) / (div * channel->fixed_divider);
57
+
58
+ clock_update_hz(channel->out, freq);
54
}
59
}
55
60
56
static void aspeed_timer_mod(AspeedTimer *t)
61
/* Update a PLL and all its channels */
57
--
62
--
58
2.20.1
63
2.20.1
59
64
60
65
diff view generated by jsdifflib
1
From: Hongbo Zhang <hongbo.zhang@linaro.org>
1
From: Luc Michel <luc@lmichel.fr>
2
2
3
Following the previous patch, this patch adds peripheral devices to the
3
The clock multiplexers are the last clock stage in the CPRMAN. Each mux
4
newly introduced SBSA-ref machine.
4
outputs one clock signal that goes out of the CPRMAN to the SoC
5
5
peripherals.
6
Signed-off-by: Hongbo Zhang <hongbo.zhang@linaro.org>
6
7
Message-id: 1561890034-15921-3-git-send-email-hongbo.zhang@linaro.org
7
Each mux has at most 10 sources. The sources 0 to 3 are common to all
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
muxes. They are:
9
0. ground (no clock signal)
10
1. the main oscillator (xosc)
11
2. "test debug 0" clock
12
3. "test debug 1" clock
13
14
Test debug 0 and 1 are actual clock muxes that can be used as sources to
15
other muxes (for debug purpose).
16
17
Sources 4 to 9 are mux specific and can be unpopulated (grounded). Those
18
sources are fed by the PLL channels outputs.
19
20
One corner case exists for DSI0E and DSI0P muxes. They have their source
21
number 4 connected to an intermediate multiplexer that can select
22
between PLLA-DSI0 and PLLD-DSI0 channel. This multiplexer is called
23
DSI0HSCK and is not a clock mux as such. It is really a simple mux from
24
the hardware point of view (see https://elinux.org/The_Undocumented_Pi).
25
This mux is not implemented in this commit.
26
27
Note that there is some muxes for which sources are unknown (because of
28
a lack of documentation). For those cases all the sources are connected
29
to ground in this implementation.
30
31
Each clock mux output is exported by the CPRMAN at the qdev level,
32
adding the suffix '-out' to the mux name to form the output clock name.
33
(E.g. the 'uart' mux sees its output exported as 'uart-out' at the
34
CPRMAN level.)
35
36
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
37
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
38
Signed-off-by: Luc Michel <luc@lmichel.fr>
39
Tested-by: Guenter Roeck <linux@roeck-us.net>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
40
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
41
---
11
hw/arm/sbsa-ref.c | 535 ++++++++++++++++++++++++++++++++++++++++++++++
42
include/hw/misc/bcm2835_cprman.h | 85 +++++
12
1 file changed, 535 insertions(+)
43
include/hw/misc/bcm2835_cprman_internals.h | 422 +++++++++++++++++++++
13
44
hw/misc/bcm2835_cprman.c | 151 ++++++++
14
diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
45
3 files changed, 658 insertions(+)
46
47
diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h
15
index XXXXXXX..XXXXXXX 100644
48
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/arm/sbsa-ref.c
49
--- a/include/hw/misc/bcm2835_cprman.h
17
+++ b/hw/arm/sbsa-ref.c
50
+++ b/include/hw/misc/bcm2835_cprman.h
51
@@ -XXX,XX +XXX,XX @@ typedef enum CprmanPllChannel {
52
CPRMAN_PLLB_CHANNEL_ARM,
53
54
CPRMAN_NUM_PLL_CHANNEL,
55
+
56
+ /* Special values used when connecting clock sources to clocks */
57
+ CPRMAN_CLOCK_SRC_NORMAL = -1,
58
+ CPRMAN_CLOCK_SRC_FORCE_GROUND = -2,
59
+ CPRMAN_CLOCK_SRC_DSI0HSCK = -3,
60
} CprmanPllChannel;
61
62
+typedef enum CprmanClockMux {
63
+ CPRMAN_CLOCK_GNRIC,
64
+ CPRMAN_CLOCK_VPU,
65
+ CPRMAN_CLOCK_SYS,
66
+ CPRMAN_CLOCK_PERIA,
67
+ CPRMAN_CLOCK_PERII,
68
+ CPRMAN_CLOCK_H264,
69
+ CPRMAN_CLOCK_ISP,
70
+ CPRMAN_CLOCK_V3D,
71
+ CPRMAN_CLOCK_CAM0,
72
+ CPRMAN_CLOCK_CAM1,
73
+ CPRMAN_CLOCK_CCP2,
74
+ CPRMAN_CLOCK_DSI0E,
75
+ CPRMAN_CLOCK_DSI0P,
76
+ CPRMAN_CLOCK_DPI,
77
+ CPRMAN_CLOCK_GP0,
78
+ CPRMAN_CLOCK_GP1,
79
+ CPRMAN_CLOCK_GP2,
80
+ CPRMAN_CLOCK_HSM,
81
+ CPRMAN_CLOCK_OTP,
82
+ CPRMAN_CLOCK_PCM,
83
+ CPRMAN_CLOCK_PWM,
84
+ CPRMAN_CLOCK_SLIM,
85
+ CPRMAN_CLOCK_SMI,
86
+ CPRMAN_CLOCK_TEC,
87
+ CPRMAN_CLOCK_TD0,
88
+ CPRMAN_CLOCK_TD1,
89
+ CPRMAN_CLOCK_TSENS,
90
+ CPRMAN_CLOCK_TIMER,
91
+ CPRMAN_CLOCK_UART,
92
+ CPRMAN_CLOCK_VEC,
93
+ CPRMAN_CLOCK_PULSE,
94
+ CPRMAN_CLOCK_SDC,
95
+ CPRMAN_CLOCK_ARM,
96
+ CPRMAN_CLOCK_AVEO,
97
+ CPRMAN_CLOCK_EMMC,
98
+ CPRMAN_CLOCK_EMMC2,
99
+
100
+ CPRMAN_NUM_CLOCK_MUX
101
+} CprmanClockMux;
102
+
103
+typedef enum CprmanClockMuxSource {
104
+ CPRMAN_CLOCK_SRC_GND = 0,
105
+ CPRMAN_CLOCK_SRC_XOSC,
106
+ CPRMAN_CLOCK_SRC_TD0,
107
+ CPRMAN_CLOCK_SRC_TD1,
108
+ CPRMAN_CLOCK_SRC_PLLA,
109
+ CPRMAN_CLOCK_SRC_PLLC,
110
+ CPRMAN_CLOCK_SRC_PLLD,
111
+ CPRMAN_CLOCK_SRC_PLLH,
112
+ CPRMAN_CLOCK_SRC_PLLC_CORE1,
113
+ CPRMAN_CLOCK_SRC_PLLC_CORE2,
114
+
115
+ CPRMAN_NUM_CLOCK_MUX_SRC
116
+} CprmanClockMuxSource;
117
+
118
typedef struct CprmanPllState {
119
/*< private >*/
120
DeviceState parent_obj;
121
@@ -XXX,XX +XXX,XX @@ typedef struct CprmanPllChannelState {
122
Clock *out;
123
} CprmanPllChannelState;
124
125
+typedef struct CprmanClockMuxState {
126
+ /*< private >*/
127
+ DeviceState parent_obj;
128
+
129
+ /*< public >*/
130
+ CprmanClockMux id;
131
+
132
+ uint32_t *reg_ctl;
133
+ uint32_t *reg_div;
134
+ int int_bits;
135
+ int frac_bits;
136
+
137
+ Clock *srcs[CPRMAN_NUM_CLOCK_MUX_SRC];
138
+ Clock *out;
139
+
140
+ /*
141
+ * Used by clock srcs update callback to retrieve both the clock and the
142
+ * source number.
143
+ */
144
+ struct CprmanClockMuxState *backref[CPRMAN_NUM_CLOCK_MUX_SRC];
145
+} CprmanClockMuxState;
146
+
147
struct BCM2835CprmanState {
148
/*< private >*/
149
SysBusDevice parent_obj;
150
@@ -XXX,XX +XXX,XX @@ struct BCM2835CprmanState {
151
152
CprmanPllState plls[CPRMAN_NUM_PLL];
153
CprmanPllChannelState channels[CPRMAN_NUM_PLL_CHANNEL];
154
+ CprmanClockMuxState clock_muxes[CPRMAN_NUM_CLOCK_MUX];
155
156
uint32_t regs[CPRMAN_NUM_REGS];
157
uint32_t xosc_freq;
158
159
Clock *xosc;
160
+ Clock *gnd;
161
};
162
163
#endif
164
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
165
index XXXXXXX..XXXXXXX 100644
166
--- a/include/hw/misc/bcm2835_cprman_internals.h
167
+++ b/include/hw/misc/bcm2835_cprman_internals.h
18
@@ -XXX,XX +XXX,XX @@
168
@@ -XXX,XX +XXX,XX @@
169
170
#define TYPE_CPRMAN_PLL "bcm2835-cprman-pll"
171
#define TYPE_CPRMAN_PLL_CHANNEL "bcm2835-cprman-pll-channel"
172
+#define TYPE_CPRMAN_CLOCK_MUX "bcm2835-cprman-clock-mux"
173
174
DECLARE_INSTANCE_CHECKER(CprmanPllState, CPRMAN_PLL,
175
TYPE_CPRMAN_PLL)
176
DECLARE_INSTANCE_CHECKER(CprmanPllChannelState, CPRMAN_PLL_CHANNEL,
177
TYPE_CPRMAN_PLL_CHANNEL)
178
+DECLARE_INSTANCE_CHECKER(CprmanClockMuxState, CPRMAN_CLOCK_MUX,
179
+ TYPE_CPRMAN_CLOCK_MUX)
180
181
/* Register map */
182
183
@@ -XXX,XX +XXX,XX @@ REG32(A2W_PLLH_STS, 0x1660)
184
185
REG32(A2W_PLLB_ARM, 0x13e0)
186
187
+/* Clock muxes */
188
+REG32(CM_GNRICCTL, 0x000)
189
+ FIELD(CM_CLOCKx_CTL, SRC, 0, 4)
190
+ FIELD(CM_CLOCKx_CTL, ENABLE, 4, 1)
191
+ FIELD(CM_CLOCKx_CTL, KILL, 5, 1)
192
+ FIELD(CM_CLOCKx_CTL, GATE, 6, 1)
193
+ FIELD(CM_CLOCKx_CTL, BUSY, 7, 1)
194
+ FIELD(CM_CLOCKx_CTL, BUSYD, 8, 1)
195
+ FIELD(CM_CLOCKx_CTL, MASH, 9, 2)
196
+ FIELD(CM_CLOCKx_CTL, FLIP, 11, 1)
197
+REG32(CM_GNRICDIV, 0x004)
198
+ FIELD(CM_CLOCKx_DIV, FRAC, 0, 12)
199
+REG32(CM_VPUCTL, 0x008)
200
+REG32(CM_VPUDIV, 0x00c)
201
+REG32(CM_SYSCTL, 0x010)
202
+REG32(CM_SYSDIV, 0x014)
203
+REG32(CM_PERIACTL, 0x018)
204
+REG32(CM_PERIADIV, 0x01c)
205
+REG32(CM_PERIICTL, 0x020)
206
+REG32(CM_PERIIDIV, 0x024)
207
+REG32(CM_H264CTL, 0x028)
208
+REG32(CM_H264DIV, 0x02c)
209
+REG32(CM_ISPCTL, 0x030)
210
+REG32(CM_ISPDIV, 0x034)
211
+REG32(CM_V3DCTL, 0x038)
212
+REG32(CM_V3DDIV, 0x03c)
213
+REG32(CM_CAM0CTL, 0x040)
214
+REG32(CM_CAM0DIV, 0x044)
215
+REG32(CM_CAM1CTL, 0x048)
216
+REG32(CM_CAM1DIV, 0x04c)
217
+REG32(CM_CCP2CTL, 0x050)
218
+REG32(CM_CCP2DIV, 0x054)
219
+REG32(CM_DSI0ECTL, 0x058)
220
+REG32(CM_DSI0EDIV, 0x05c)
221
+REG32(CM_DSI0PCTL, 0x060)
222
+REG32(CM_DSI0PDIV, 0x064)
223
+REG32(CM_DPICTL, 0x068)
224
+REG32(CM_DPIDIV, 0x06c)
225
+REG32(CM_GP0CTL, 0x070)
226
+REG32(CM_GP0DIV, 0x074)
227
+REG32(CM_GP1CTL, 0x078)
228
+REG32(CM_GP1DIV, 0x07c)
229
+REG32(CM_GP2CTL, 0x080)
230
+REG32(CM_GP2DIV, 0x084)
231
+REG32(CM_HSMCTL, 0x088)
232
+REG32(CM_HSMDIV, 0x08c)
233
+REG32(CM_OTPCTL, 0x090)
234
+REG32(CM_OTPDIV, 0x094)
235
+REG32(CM_PCMCTL, 0x098)
236
+REG32(CM_PCMDIV, 0x09c)
237
+REG32(CM_PWMCTL, 0x0a0)
238
+REG32(CM_PWMDIV, 0x0a4)
239
+REG32(CM_SLIMCTL, 0x0a8)
240
+REG32(CM_SLIMDIV, 0x0ac)
241
+REG32(CM_SMICTL, 0x0b0)
242
+REG32(CM_SMIDIV, 0x0b4)
243
+REG32(CM_TCNTCTL, 0x0c0)
244
+REG32(CM_TCNTCNT, 0x0c4)
245
+REG32(CM_TECCTL, 0x0c8)
246
+REG32(CM_TECDIV, 0x0cc)
247
+REG32(CM_TD0CTL, 0x0d0)
248
+REG32(CM_TD0DIV, 0x0d4)
249
+REG32(CM_TD1CTL, 0x0d8)
250
+REG32(CM_TD1DIV, 0x0dc)
251
+REG32(CM_TSENSCTL, 0x0e0)
252
+REG32(CM_TSENSDIV, 0x0e4)
253
+REG32(CM_TIMERCTL, 0x0e8)
254
+REG32(CM_TIMERDIV, 0x0ec)
255
+REG32(CM_UARTCTL, 0x0f0)
256
+REG32(CM_UARTDIV, 0x0f4)
257
+REG32(CM_VECCTL, 0x0f8)
258
+REG32(CM_VECDIV, 0x0fc)
259
+REG32(CM_PULSECTL, 0x190)
260
+REG32(CM_PULSEDIV, 0x194)
261
+REG32(CM_SDCCTL, 0x1a8)
262
+REG32(CM_SDCDIV, 0x1ac)
263
+REG32(CM_ARMCTL, 0x1b0)
264
+REG32(CM_AVEOCTL, 0x1b8)
265
+REG32(CM_AVEODIV, 0x1bc)
266
+REG32(CM_EMMCCTL, 0x1c0)
267
+REG32(CM_EMMCDIV, 0x1c4)
268
+REG32(CM_EMMC2CTL, 0x1d0)
269
+REG32(CM_EMMC2DIV, 0x1d4)
270
+
271
/* misc registers */
272
REG32(CM_LOCK, 0x114)
273
FIELD(CM_LOCK, FLOCKH, 12, 1)
274
@@ -XXX,XX +XXX,XX @@ static inline void set_pll_channel_init_info(BCM2835CprmanState *s,
275
channel->fixed_divider = PLL_CHANNEL_INIT_INFO[id].fixed_divider;
276
}
277
278
+/* Clock mux init info */
279
+typedef struct ClockMuxInitInfo {
280
+ const char *name;
281
+ size_t cm_offset; /* cm_offset[0]->CM_CTL, cm_offset[1]->CM_DIV */
282
+ int int_bits;
283
+ int frac_bits;
284
+
285
+ CprmanPllChannel src_mapping[CPRMAN_NUM_CLOCK_MUX_SRC];
286
+} ClockMuxInitInfo;
287
+
288
+/*
289
+ * Each clock mux can have up to 10 sources. Sources 0 to 3 are always the
290
+ * same (ground, xosc, td0, td1). Sources 4 to 9 are mux specific, and are not
291
+ * always populated. The following macros catch all those cases.
292
+ */
293
+
294
+/* Unknown mapping. Connect everything to ground */
295
+#define SRC_MAPPING_INFO_unknown \
296
+ .src_mapping = { \
297
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* gnd */ \
298
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* xosc */ \
299
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* test debug 0 */ \
300
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* test debug 1 */ \
301
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll a */ \
302
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll c */ \
303
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll d */ \
304
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll h */ \
305
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll c, core1 */ \
306
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll c, core2 */ \
307
+ }
308
+
309
+/* Only the oscillator and the two test debug clocks */
310
+#define SRC_MAPPING_INFO_xosc \
311
+ .src_mapping = { \
312
+ CPRMAN_CLOCK_SRC_NORMAL, \
313
+ CPRMAN_CLOCK_SRC_NORMAL, \
314
+ CPRMAN_CLOCK_SRC_NORMAL, \
315
+ CPRMAN_CLOCK_SRC_NORMAL, \
316
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
317
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
318
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
319
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
320
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
321
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
322
+ }
323
+
324
+/* All the PLL "core" channels */
325
+#define SRC_MAPPING_INFO_core \
326
+ .src_mapping = { \
327
+ CPRMAN_CLOCK_SRC_NORMAL, \
328
+ CPRMAN_CLOCK_SRC_NORMAL, \
329
+ CPRMAN_CLOCK_SRC_NORMAL, \
330
+ CPRMAN_CLOCK_SRC_NORMAL, \
331
+ CPRMAN_PLLA_CHANNEL_CORE, \
332
+ CPRMAN_PLLC_CHANNEL_CORE0, \
333
+ CPRMAN_PLLD_CHANNEL_CORE, \
334
+ CPRMAN_PLLH_CHANNEL_AUX, \
335
+ CPRMAN_PLLC_CHANNEL_CORE1, \
336
+ CPRMAN_PLLC_CHANNEL_CORE2, \
337
+ }
338
+
339
+/* All the PLL "per" channels */
340
+#define SRC_MAPPING_INFO_periph \
341
+ .src_mapping = { \
342
+ CPRMAN_CLOCK_SRC_NORMAL, \
343
+ CPRMAN_CLOCK_SRC_NORMAL, \
344
+ CPRMAN_CLOCK_SRC_NORMAL, \
345
+ CPRMAN_CLOCK_SRC_NORMAL, \
346
+ CPRMAN_PLLA_CHANNEL_PER, \
347
+ CPRMAN_PLLC_CHANNEL_PER, \
348
+ CPRMAN_PLLD_CHANNEL_PER, \
349
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
350
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
351
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
352
+ }
353
+
354
+/*
355
+ * The DSI0 channels. This one got an intermediate mux between the PLL channels
356
+ * and the clock input.
357
+ */
358
+#define SRC_MAPPING_INFO_dsi0 \
359
+ .src_mapping = { \
360
+ CPRMAN_CLOCK_SRC_NORMAL, \
361
+ CPRMAN_CLOCK_SRC_NORMAL, \
362
+ CPRMAN_CLOCK_SRC_NORMAL, \
363
+ CPRMAN_CLOCK_SRC_NORMAL, \
364
+ CPRMAN_CLOCK_SRC_DSI0HSCK, \
365
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
366
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
367
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
368
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
369
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
370
+ }
371
+
372
+/* The DSI1 channel */
373
+#define SRC_MAPPING_INFO_dsi1 \
374
+ .src_mapping = { \
375
+ CPRMAN_CLOCK_SRC_NORMAL, \
376
+ CPRMAN_CLOCK_SRC_NORMAL, \
377
+ CPRMAN_CLOCK_SRC_NORMAL, \
378
+ CPRMAN_CLOCK_SRC_NORMAL, \
379
+ CPRMAN_PLLD_CHANNEL_DSI1, \
380
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
381
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
382
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
383
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
384
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
385
+ }
386
+
387
+#define FILL_CLOCK_MUX_SRC_MAPPING_INIT_INFO(kind_) \
388
+ SRC_MAPPING_INFO_ ## kind_
389
+
390
+#define FILL_CLOCK_MUX_INIT_INFO(clock_, kind_) \
391
+ .cm_offset = R_CM_ ## clock_ ## CTL, \
392
+ FILL_CLOCK_MUX_SRC_MAPPING_INIT_INFO(kind_)
393
+
394
+static ClockMuxInitInfo CLOCK_MUX_INIT_INFO[] = {
395
+ [CPRMAN_CLOCK_GNRIC] = {
396
+ .name = "gnric",
397
+ FILL_CLOCK_MUX_INIT_INFO(GNRIC, unknown),
398
+ },
399
+ [CPRMAN_CLOCK_VPU] = {
400
+ .name = "vpu",
401
+ .int_bits = 12,
402
+ .frac_bits = 8,
403
+ FILL_CLOCK_MUX_INIT_INFO(VPU, core),
404
+ },
405
+ [CPRMAN_CLOCK_SYS] = {
406
+ .name = "sys",
407
+ FILL_CLOCK_MUX_INIT_INFO(SYS, unknown),
408
+ },
409
+ [CPRMAN_CLOCK_PERIA] = {
410
+ .name = "peria",
411
+ FILL_CLOCK_MUX_INIT_INFO(PERIA, unknown),
412
+ },
413
+ [CPRMAN_CLOCK_PERII] = {
414
+ .name = "perii",
415
+ FILL_CLOCK_MUX_INIT_INFO(PERII, unknown),
416
+ },
417
+ [CPRMAN_CLOCK_H264] = {
418
+ .name = "h264",
419
+ .int_bits = 4,
420
+ .frac_bits = 8,
421
+ FILL_CLOCK_MUX_INIT_INFO(H264, core),
422
+ },
423
+ [CPRMAN_CLOCK_ISP] = {
424
+ .name = "isp",
425
+ .int_bits = 4,
426
+ .frac_bits = 8,
427
+ FILL_CLOCK_MUX_INIT_INFO(ISP, core),
428
+ },
429
+ [CPRMAN_CLOCK_V3D] = {
430
+ .name = "v3d",
431
+ FILL_CLOCK_MUX_INIT_INFO(V3D, core),
432
+ },
433
+ [CPRMAN_CLOCK_CAM0] = {
434
+ .name = "cam0",
435
+ .int_bits = 4,
436
+ .frac_bits = 8,
437
+ FILL_CLOCK_MUX_INIT_INFO(CAM0, periph),
438
+ },
439
+ [CPRMAN_CLOCK_CAM1] = {
440
+ .name = "cam1",
441
+ .int_bits = 4,
442
+ .frac_bits = 8,
443
+ FILL_CLOCK_MUX_INIT_INFO(CAM1, periph),
444
+ },
445
+ [CPRMAN_CLOCK_CCP2] = {
446
+ .name = "ccp2",
447
+ FILL_CLOCK_MUX_INIT_INFO(CCP2, unknown),
448
+ },
449
+ [CPRMAN_CLOCK_DSI0E] = {
450
+ .name = "dsi0e",
451
+ .int_bits = 4,
452
+ .frac_bits = 8,
453
+ FILL_CLOCK_MUX_INIT_INFO(DSI0E, dsi0),
454
+ },
455
+ [CPRMAN_CLOCK_DSI0P] = {
456
+ .name = "dsi0p",
457
+ .int_bits = 0,
458
+ .frac_bits = 0,
459
+ FILL_CLOCK_MUX_INIT_INFO(DSI0P, dsi0),
460
+ },
461
+ [CPRMAN_CLOCK_DPI] = {
462
+ .name = "dpi",
463
+ .int_bits = 4,
464
+ .frac_bits = 8,
465
+ FILL_CLOCK_MUX_INIT_INFO(DPI, periph),
466
+ },
467
+ [CPRMAN_CLOCK_GP0] = {
468
+ .name = "gp0",
469
+ .int_bits = 12,
470
+ .frac_bits = 12,
471
+ FILL_CLOCK_MUX_INIT_INFO(GP0, periph),
472
+ },
473
+ [CPRMAN_CLOCK_GP1] = {
474
+ .name = "gp1",
475
+ .int_bits = 12,
476
+ .frac_bits = 12,
477
+ FILL_CLOCK_MUX_INIT_INFO(GP1, periph),
478
+ },
479
+ [CPRMAN_CLOCK_GP2] = {
480
+ .name = "gp2",
481
+ .int_bits = 12,
482
+ .frac_bits = 12,
483
+ FILL_CLOCK_MUX_INIT_INFO(GP2, periph),
484
+ },
485
+ [CPRMAN_CLOCK_HSM] = {
486
+ .name = "hsm",
487
+ .int_bits = 4,
488
+ .frac_bits = 8,
489
+ FILL_CLOCK_MUX_INIT_INFO(HSM, periph),
490
+ },
491
+ [CPRMAN_CLOCK_OTP] = {
492
+ .name = "otp",
493
+ .int_bits = 4,
494
+ .frac_bits = 0,
495
+ FILL_CLOCK_MUX_INIT_INFO(OTP, xosc),
496
+ },
497
+ [CPRMAN_CLOCK_PCM] = {
498
+ .name = "pcm",
499
+ .int_bits = 12,
500
+ .frac_bits = 12,
501
+ FILL_CLOCK_MUX_INIT_INFO(PCM, periph),
502
+ },
503
+ [CPRMAN_CLOCK_PWM] = {
504
+ .name = "pwm",
505
+ .int_bits = 12,
506
+ .frac_bits = 12,
507
+ FILL_CLOCK_MUX_INIT_INFO(PWM, periph),
508
+ },
509
+ [CPRMAN_CLOCK_SLIM] = {
510
+ .name = "slim",
511
+ .int_bits = 12,
512
+ .frac_bits = 12,
513
+ FILL_CLOCK_MUX_INIT_INFO(SLIM, periph),
514
+ },
515
+ [CPRMAN_CLOCK_SMI] = {
516
+ .name = "smi",
517
+ .int_bits = 4,
518
+ .frac_bits = 8,
519
+ FILL_CLOCK_MUX_INIT_INFO(SMI, periph),
520
+ },
521
+ [CPRMAN_CLOCK_TEC] = {
522
+ .name = "tec",
523
+ .int_bits = 6,
524
+ .frac_bits = 0,
525
+ FILL_CLOCK_MUX_INIT_INFO(TEC, xosc),
526
+ },
527
+ [CPRMAN_CLOCK_TD0] = {
528
+ .name = "td0",
529
+ FILL_CLOCK_MUX_INIT_INFO(TD0, unknown),
530
+ },
531
+ [CPRMAN_CLOCK_TD1] = {
532
+ .name = "td1",
533
+ FILL_CLOCK_MUX_INIT_INFO(TD1, unknown),
534
+ },
535
+ [CPRMAN_CLOCK_TSENS] = {
536
+ .name = "tsens",
537
+ .int_bits = 5,
538
+ .frac_bits = 0,
539
+ FILL_CLOCK_MUX_INIT_INFO(TSENS, xosc),
540
+ },
541
+ [CPRMAN_CLOCK_TIMER] = {
542
+ .name = "timer",
543
+ .int_bits = 6,
544
+ .frac_bits = 12,
545
+ FILL_CLOCK_MUX_INIT_INFO(TIMER, xosc),
546
+ },
547
+ [CPRMAN_CLOCK_UART] = {
548
+ .name = "uart",
549
+ .int_bits = 10,
550
+ .frac_bits = 12,
551
+ FILL_CLOCK_MUX_INIT_INFO(UART, periph),
552
+ },
553
+ [CPRMAN_CLOCK_VEC] = {
554
+ .name = "vec",
555
+ .int_bits = 4,
556
+ .frac_bits = 0,
557
+ FILL_CLOCK_MUX_INIT_INFO(VEC, periph),
558
+ },
559
+ [CPRMAN_CLOCK_PULSE] = {
560
+ .name = "pulse",
561
+ FILL_CLOCK_MUX_INIT_INFO(PULSE, xosc),
562
+ },
563
+ [CPRMAN_CLOCK_SDC] = {
564
+ .name = "sdram",
565
+ .int_bits = 6,
566
+ .frac_bits = 0,
567
+ FILL_CLOCK_MUX_INIT_INFO(SDC, core),
568
+ },
569
+ [CPRMAN_CLOCK_ARM] = {
570
+ .name = "arm",
571
+ FILL_CLOCK_MUX_INIT_INFO(ARM, unknown),
572
+ },
573
+ [CPRMAN_CLOCK_AVEO] = {
574
+ .name = "aveo",
575
+ .int_bits = 4,
576
+ .frac_bits = 0,
577
+ FILL_CLOCK_MUX_INIT_INFO(AVEO, periph),
578
+ },
579
+ [CPRMAN_CLOCK_EMMC] = {
580
+ .name = "emmc",
581
+ .int_bits = 4,
582
+ .frac_bits = 8,
583
+ FILL_CLOCK_MUX_INIT_INFO(EMMC, periph),
584
+ },
585
+ [CPRMAN_CLOCK_EMMC2] = {
586
+ .name = "emmc2",
587
+ .int_bits = 4,
588
+ .frac_bits = 8,
589
+ FILL_CLOCK_MUX_INIT_INFO(EMMC2, unknown),
590
+ },
591
+};
592
+
593
+#undef FILL_CLOCK_MUX_INIT_INFO
594
+#undef FILL_CLOCK_MUX_SRC_MAPPING_INIT_INFO
595
+#undef SRC_MAPPING_INFO_dsi1
596
+#undef SRC_MAPPING_INFO_dsi0
597
+#undef SRC_MAPPING_INFO_periph
598
+#undef SRC_MAPPING_INFO_core
599
+#undef SRC_MAPPING_INFO_xosc
600
+#undef SRC_MAPPING_INFO_unknown
601
+
602
+static inline void set_clock_mux_init_info(BCM2835CprmanState *s,
603
+ CprmanClockMuxState *mux,
604
+ CprmanClockMux id)
605
+{
606
+ mux->id = id;
607
+ mux->reg_ctl = &s->regs[CLOCK_MUX_INIT_INFO[id].cm_offset];
608
+ mux->reg_div = &s->regs[CLOCK_MUX_INIT_INFO[id].cm_offset + 1];
609
+ mux->int_bits = CLOCK_MUX_INIT_INFO[id].int_bits;
610
+ mux->frac_bits = CLOCK_MUX_INIT_INFO[id].frac_bits;
611
+}
612
+
613
#endif
614
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
615
index XXXXXXX..XXXXXXX 100644
616
--- a/hw/misc/bcm2835_cprman.c
617
+++ b/hw/misc/bcm2835_cprman.c
618
@@ -XXX,XX +XXX,XX @@
619
*
620
* The page at https://elinux.org/The_Undocumented_Pi gives the actual clock
621
* tree configuration.
622
+ *
623
+ * The CPRMAN exposes clock outputs with the name of the clock mux suffixed
624
+ * with "-out" (e.g. "uart-out", "h264-out", ...).
19
*/
625
*/
20
626
21
#include "qemu/osdep.h"
627
#include "qemu/osdep.h"
22
+#include "qemu-common.h"
628
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_channel_info = {
23
#include "qapi/error.h"
24
#include "qemu/error-report.h"
25
#include "qemu/units.h"
26
+#include "sysemu/device_tree.h"
27
#include "sysemu/numa.h"
28
#include "sysemu/sysemu.h"
29
#include "exec/address-spaces.h"
30
#include "exec/hwaddr.h"
31
#include "kvm_arm.h"
32
#include "hw/arm/boot.h"
33
+#include "hw/block/flash.h"
34
#include "hw/boards.h"
35
+#include "hw/ide/internal.h"
36
+#include "hw/ide/ahci_internal.h"
37
#include "hw/intc/arm_gicv3_common.h"
38
+#include "hw/loader.h"
39
+#include "hw/pci-host/gpex.h"
40
+#include "hw/usb.h"
41
+#include "net/net.h"
42
43
#define RAMLIMIT_GB 8192
44
#define RAMLIMIT_BYTES (RAMLIMIT_GB * GiB)
45
46
+#define NUM_IRQS 256
47
+#define NUM_SMMU_IRQS 4
48
+#define NUM_SATA_PORTS 6
49
+
50
+#define VIRTUAL_PMU_IRQ 7
51
+#define ARCH_GIC_MAINT_IRQ 9
52
+#define ARCH_TIMER_VIRT_IRQ 11
53
+#define ARCH_TIMER_S_EL1_IRQ 13
54
+#define ARCH_TIMER_NS_EL1_IRQ 14
55
+#define ARCH_TIMER_NS_EL2_IRQ 10
56
+
57
enum {
58
SBSA_FLASH,
59
SBSA_MEM,
60
@@ -XXX,XX +XXX,XX @@ typedef struct {
61
void *fdt;
62
int fdt_size;
63
int psci_conduit;
64
+ PFlashCFI01 *flash[2];
65
} SBSAMachineState;
66
67
#define TYPE_SBSA_MACHINE MACHINE_TYPE_NAME("sbsa-ref")
68
@@ -XXX,XX +XXX,XX @@ static const MemMapEntry sbsa_ref_memmap[] = {
69
[SBSA_MEM] = { 0x10000000000ULL, RAMLIMIT_BYTES },
70
};
629
};
71
630
72
+static const int sbsa_ref_irqmap[] = {
631
73
+ [SBSA_UART] = 1,
632
+/* clock mux */
74
+ [SBSA_RTC] = 2,
633
+
75
+ [SBSA_PCIE] = 3, /* ... to 6 */
634
+static void clock_mux_update(CprmanClockMuxState *mux)
76
+ [SBSA_GPIO] = 7,
635
+{
77
+ [SBSA_SECURE_UART] = 8,
636
+ clock_update(mux->out, 0);
78
+ [SBSA_SECURE_UART_MM] = 9,
637
+}
79
+ [SBSA_AHCI] = 10,
638
+
80
+ [SBSA_EHCI] = 11,
639
+static void clock_mux_src_update(void *opaque)
640
+{
641
+ CprmanClockMuxState **backref = opaque;
642
+ CprmanClockMuxState *s = *backref;
643
+
644
+ clock_mux_update(s);
645
+}
646
+
647
+static void clock_mux_init(Object *obj)
648
+{
649
+ CprmanClockMuxState *s = CPRMAN_CLOCK_MUX(obj);
650
+ size_t i;
651
+
652
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX_SRC; i++) {
653
+ char *name = g_strdup_printf("srcs[%zu]", i);
654
+ s->backref[i] = s;
655
+ s->srcs[i] = qdev_init_clock_in(DEVICE(s), name,
656
+ clock_mux_src_update,
657
+ &s->backref[i]);
658
+ g_free(name);
659
+ }
660
+
661
+ s->out = qdev_init_clock_out(DEVICE(s), "out");
662
+}
663
+
664
+static const VMStateDescription clock_mux_vmstate = {
665
+ .name = TYPE_CPRMAN_CLOCK_MUX,
666
+ .version_id = 1,
667
+ .minimum_version_id = 1,
668
+ .fields = (VMStateField[]) {
669
+ VMSTATE_ARRAY_CLOCK(srcs, CprmanClockMuxState,
670
+ CPRMAN_NUM_CLOCK_MUX_SRC),
671
+ VMSTATE_END_OF_LIST()
672
+ }
81
+};
673
+};
82
+
674
+
83
+/*
675
+static void clock_mux_class_init(ObjectClass *klass, void *data)
84
+ * Firmware on this machine only uses ACPI table to load OS, these limited
85
+ * device tree nodes are just to let firmware know the info which varies from
86
+ * command line parameters, so it is not necessary to be fully compatible
87
+ * with the kernel CPU and NUMA binding rules.
88
+ */
89
+static void create_fdt(SBSAMachineState *sms)
90
+{
676
+{
91
+ void *fdt = create_device_tree(&sms->fdt_size);
677
+ DeviceClass *dc = DEVICE_CLASS(klass);
92
+ const MachineState *ms = MACHINE(sms);
678
+
93
+ int cpu;
679
+ dc->vmsd = &clock_mux_vmstate;
94
+
680
+}
95
+ if (!fdt) {
681
+
96
+ error_report("create_device_tree() failed");
682
+static const TypeInfo cprman_clock_mux_info = {
97
+ exit(1);
683
+ .name = TYPE_CPRMAN_CLOCK_MUX,
98
+ }
684
+ .parent = TYPE_DEVICE,
99
+
685
+ .instance_size = sizeof(CprmanClockMuxState),
100
+ sms->fdt = fdt;
686
+ .class_init = clock_mux_class_init,
101
+
687
+ .instance_init = clock_mux_init,
102
+ qemu_fdt_setprop_string(fdt, "/", "compatible", "linux,sbsa-ref");
688
+};
103
+ qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2);
689
+
104
+ qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2);
690
+
105
+
691
/* CPRMAN "top level" model */
106
+ if (have_numa_distance) {
692
107
+ int size = nb_numa_nodes * nb_numa_nodes * 3 * sizeof(uint32_t);
693
static uint32_t get_cm_lock(const BCM2835CprmanState *s)
108
+ uint32_t *matrix = g_malloc0(size);
694
@@ -XXX,XX +XXX,XX @@ static inline void update_channel_from_a2w(BCM2835CprmanState *s, size_t idx)
109
+ int idx, i, j;
695
}
110
+
696
}
111
+ for (i = 0; i < nb_numa_nodes; i++) {
697
112
+ for (j = 0; j < nb_numa_nodes; j++) {
698
+static inline void update_mux_from_cm(BCM2835CprmanState *s, size_t idx)
113
+ idx = (i * nb_numa_nodes + j) * 3;
699
+{
114
+ matrix[idx + 0] = cpu_to_be32(i);
700
+ size_t i;
115
+ matrix[idx + 1] = cpu_to_be32(j);
701
+
116
+ matrix[idx + 2] = cpu_to_be32(numa_info[i].distance[j]);
702
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
117
+ }
703
+ if ((CLOCK_MUX_INIT_INFO[i].cm_offset == idx) ||
704
+ (CLOCK_MUX_INIT_INFO[i].cm_offset + 4 == idx)) {
705
+ /* matches CM_CTL or CM_DIV mux register */
706
+ clock_mux_update(&s->clock_muxes[i]);
707
+ return;
118
+ }
708
+ }
119
+
709
+ }
120
+ qemu_fdt_add_subnode(fdt, "/distance-map");
710
+}
121
+ qemu_fdt_setprop(fdt, "/distance-map", "distance-matrix",
711
+
122
+ matrix, size);
712
#define CASE_PLL_A2W_REGS(pll_) \
123
+ g_free(matrix);
713
case R_A2W_ ## pll_ ## _CTRL: \
124
+ }
714
case R_A2W_ ## pll_ ## _ANA0: \
125
+
715
@@ -XXX,XX +XXX,XX @@ static void cprman_write(void *opaque, hwaddr offset,
126
+ qemu_fdt_add_subnode(sms->fdt, "/cpus");
716
case R_A2W_PLLB_ARM:
127
+
717
update_channel_from_a2w(s, idx);
128
+ for (cpu = sms->smp_cpus - 1; cpu >= 0; cpu--) {
718
break;
129
+ char *nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
719
+
130
+ ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu));
720
+ case R_CM_GNRICCTL ... R_CM_SMIDIV:
131
+ CPUState *cs = CPU(armcpu);
721
+ case R_CM_TCNTCNT ... R_CM_VECDIV:
132
+
722
+ case R_CM_PULSECTL ... R_CM_PULSEDIV:
133
+ qemu_fdt_add_subnode(sms->fdt, nodename);
723
+ case R_CM_SDCCTL ... R_CM_ARMCTL:
134
+
724
+ case R_CM_AVEOCTL ... R_CM_EMMCDIV:
135
+ if (ms->possible_cpus->cpus[cs->cpu_index].props.has_node_id) {
725
+ case R_CM_EMMC2CTL ... R_CM_EMMC2DIV:
136
+ qemu_fdt_setprop_cell(sms->fdt, nodename, "numa-node-id",
726
+ update_mux_from_cm(s, idx);
137
+ ms->possible_cpus->cpus[cs->cpu_index].props.node_id);
727
+ break;
728
}
729
}
730
731
@@ -XXX,XX +XXX,XX @@ static void cprman_reset(DeviceState *dev)
732
device_cold_reset(DEVICE(&s->channels[i]));
733
}
734
735
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
736
+ device_cold_reset(DEVICE(&s->clock_muxes[i]));
737
+ }
738
+
739
clock_update_hz(s->xosc, s->xosc_freq);
740
}
741
742
@@ -XXX,XX +XXX,XX @@ static void cprman_init(Object *obj)
743
set_pll_channel_init_info(s, &s->channels[i], i);
744
}
745
746
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
747
+ char *alias;
748
+
749
+ object_initialize_child(obj, CLOCK_MUX_INIT_INFO[i].name,
750
+ &s->clock_muxes[i],
751
+ TYPE_CPRMAN_CLOCK_MUX);
752
+ set_clock_mux_init_info(s, &s->clock_muxes[i], i);
753
+
754
+ /* Expose muxes output as CPRMAN outputs */
755
+ alias = g_strdup_printf("%s-out", CLOCK_MUX_INIT_INFO[i].name);
756
+ qdev_alias_clock(DEVICE(&s->clock_muxes[i]), "out", DEVICE(obj), alias);
757
+ g_free(alias);
758
+ }
759
+
760
s->xosc = clock_new(obj, "xosc");
761
+ s->gnd = clock_new(obj, "gnd");
762
+
763
+ clock_set(s->gnd, 0);
764
765
memory_region_init_io(&s->iomem, obj, &cprman_ops,
766
s, "bcm2835-cprman", 0x2000);
767
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
768
}
769
770
+static void connect_mux_sources(BCM2835CprmanState *s,
771
+ CprmanClockMuxState *mux,
772
+ const CprmanPllChannel *clk_mapping)
773
+{
774
+ size_t i;
775
+ Clock *td0 = s->clock_muxes[CPRMAN_CLOCK_TD0].out;
776
+ Clock *td1 = s->clock_muxes[CPRMAN_CLOCK_TD1].out;
777
+
778
+ /* For sources from 0 to 3. Source 4 to 9 are mux specific */
779
+ Clock * const CLK_SRC_MAPPING[] = {
780
+ [CPRMAN_CLOCK_SRC_GND] = s->gnd,
781
+ [CPRMAN_CLOCK_SRC_XOSC] = s->xosc,
782
+ [CPRMAN_CLOCK_SRC_TD0] = td0,
783
+ [CPRMAN_CLOCK_SRC_TD1] = td1,
784
+ };
785
+
786
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX_SRC; i++) {
787
+ CprmanPllChannel mapping = clk_mapping[i];
788
+ Clock *src;
789
+
790
+ if (mapping == CPRMAN_CLOCK_SRC_FORCE_GROUND) {
791
+ src = s->gnd;
792
+ } else if (mapping == CPRMAN_CLOCK_SRC_DSI0HSCK) {
793
+ src = s->gnd; /* TODO */
794
+ } else if (i < CPRMAN_CLOCK_SRC_PLLA) {
795
+ src = CLK_SRC_MAPPING[i];
796
+ } else {
797
+ src = s->channels[mapping].out;
138
+ }
798
+ }
139
+
799
+
140
+ g_free(nodename);
800
+ clock_set_source(mux->srcs[i], src);
141
+ }
801
+ }
142
+}
802
+}
143
+
803
+
144
+#define SBSA_FLASH_SECTOR_SIZE (256 * KiB)
804
static void cprman_realize(DeviceState *dev, Error **errp)
145
+
805
{
146
+static PFlashCFI01 *sbsa_flash_create1(SBSAMachineState *sms,
806
BCM2835CprmanState *s = CPRMAN(dev);
147
+ const char *name,
807
@@ -XXX,XX +XXX,XX @@ static void cprman_realize(DeviceState *dev, Error **errp)
148
+ const char *alias_prop_name)
808
return;
149
+{
809
}
150
+ /*
810
}
151
+ * Create a single flash device. We use the same parameters as
811
+
152
+ * the flash devices on the Versatile Express board.
812
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
153
+ */
813
+ CprmanClockMuxState *clock_mux = &s->clock_muxes[i];
154
+ DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01);
814
+
155
+
815
+ connect_mux_sources(s, clock_mux, CLOCK_MUX_INIT_INFO[i].src_mapping);
156
+ qdev_prop_set_uint64(dev, "sector-length", SBSA_FLASH_SECTOR_SIZE);
816
+
157
+ qdev_prop_set_uint8(dev, "width", 4);
817
+ if (!qdev_realize(DEVICE(clock_mux), NULL, errp)) {
158
+ qdev_prop_set_uint8(dev, "device-width", 2);
818
+ return;
159
+ qdev_prop_set_bit(dev, "big-endian", false);
160
+ qdev_prop_set_uint16(dev, "id0", 0x89);
161
+ qdev_prop_set_uint16(dev, "id1", 0x18);
162
+ qdev_prop_set_uint16(dev, "id2", 0x00);
163
+ qdev_prop_set_uint16(dev, "id3", 0x00);
164
+ qdev_prop_set_string(dev, "name", name);
165
+ object_property_add_child(OBJECT(sms), name, OBJECT(dev),
166
+ &error_abort);
167
+ object_property_add_alias(OBJECT(sms), alias_prop_name,
168
+ OBJECT(dev), "drive", &error_abort);
169
+ return PFLASH_CFI01(dev);
170
+}
171
+
172
+static void sbsa_flash_create(SBSAMachineState *sms)
173
+{
174
+ sms->flash[0] = sbsa_flash_create1(sms, "sbsa.flash0", "pflash0");
175
+ sms->flash[1] = sbsa_flash_create1(sms, "sbsa.flash1", "pflash1");
176
+}
177
+
178
+static void sbsa_flash_map1(PFlashCFI01 *flash,
179
+ hwaddr base, hwaddr size,
180
+ MemoryRegion *sysmem)
181
+{
182
+ DeviceState *dev = DEVICE(flash);
183
+
184
+ assert(size % SBSA_FLASH_SECTOR_SIZE == 0);
185
+ assert(size / SBSA_FLASH_SECTOR_SIZE <= UINT32_MAX);
186
+ qdev_prop_set_uint32(dev, "num-blocks", size / SBSA_FLASH_SECTOR_SIZE);
187
+ qdev_init_nofail(dev);
188
+
189
+ memory_region_add_subregion(sysmem, base,
190
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
191
+ 0));
192
+}
193
+
194
+static void sbsa_flash_map(SBSAMachineState *sms,
195
+ MemoryRegion *sysmem,
196
+ MemoryRegion *secure_sysmem)
197
+{
198
+ /*
199
+ * Map two flash devices to fill the SBSA_FLASH space in the memmap.
200
+ * sysmem is the system memory space. secure_sysmem is the secure view
201
+ * of the system, and the first flash device should be made visible only
202
+ * there. The second flash device is visible to both secure and nonsecure.
203
+ * If sysmem == secure_sysmem this means there is no separate Secure
204
+ * address space and both flash devices are generally visible.
205
+ */
206
+ hwaddr flashsize = sbsa_ref_memmap[SBSA_FLASH].size / 2;
207
+ hwaddr flashbase = sbsa_ref_memmap[SBSA_FLASH].base;
208
+
209
+ sbsa_flash_map1(sms->flash[0], flashbase, flashsize,
210
+ secure_sysmem);
211
+ sbsa_flash_map1(sms->flash[1], flashbase + flashsize, flashsize,
212
+ sysmem);
213
+}
214
+
215
+static bool sbsa_firmware_init(SBSAMachineState *sms,
216
+ MemoryRegion *sysmem,
217
+ MemoryRegion *secure_sysmem)
218
+{
219
+ int i;
220
+ BlockBackend *pflash_blk0;
221
+
222
+ /* Map legacy -drive if=pflash to machine properties */
223
+ for (i = 0; i < ARRAY_SIZE(sms->flash); i++) {
224
+ pflash_cfi01_legacy_drive(sms->flash[i],
225
+ drive_get(IF_PFLASH, 0, i));
226
+ }
227
+
228
+ sbsa_flash_map(sms, sysmem, secure_sysmem);
229
+
230
+ pflash_blk0 = pflash_cfi01_get_blk(sms->flash[0]);
231
+
232
+ if (bios_name) {
233
+ char *fname;
234
+ MemoryRegion *mr;
235
+ int image_size;
236
+
237
+ if (pflash_blk0) {
238
+ error_report("The contents of the first flash device may be "
239
+ "specified with -bios or with -drive if=pflash... "
240
+ "but you cannot use both options at once");
241
+ exit(1);
242
+ }
819
+ }
243
+
820
+ }
244
+ /* Fall back to -bios */
245
+
246
+ fname = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
247
+ if (!fname) {
248
+ error_report("Could not find ROM image '%s'", bios_name);
249
+ exit(1);
250
+ }
251
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(sms->flash[0]), 0);
252
+ image_size = load_image_mr(fname, mr);
253
+ g_free(fname);
254
+ if (image_size < 0) {
255
+ error_report("Could not load ROM image '%s'", bios_name);
256
+ exit(1);
257
+ }
258
+ }
259
+
260
+ return pflash_blk0 || bios_name;
261
+}
262
+
263
+static void create_secure_ram(SBSAMachineState *sms,
264
+ MemoryRegion *secure_sysmem)
265
+{
266
+ MemoryRegion *secram = g_new(MemoryRegion, 1);
267
+ hwaddr base = sbsa_ref_memmap[SBSA_SECURE_MEM].base;
268
+ hwaddr size = sbsa_ref_memmap[SBSA_SECURE_MEM].size;
269
+
270
+ memory_region_init_ram(secram, NULL, "sbsa-ref.secure-ram", size,
271
+ &error_fatal);
272
+ memory_region_add_subregion(secure_sysmem, base, secram);
273
+}
274
+
275
+static void create_gic(SBSAMachineState *sms, qemu_irq *pic)
276
+{
277
+ DeviceState *gicdev;
278
+ SysBusDevice *gicbusdev;
279
+ const char *gictype;
280
+ uint32_t redist0_capacity, redist0_count;
281
+ int i;
282
+
283
+ gictype = gicv3_class_name();
284
+
285
+ gicdev = qdev_create(NULL, gictype);
286
+ qdev_prop_set_uint32(gicdev, "revision", 3);
287
+ qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus);
288
+ /*
289
+ * Note that the num-irq property counts both internal and external
290
+ * interrupts; there are always 32 of the former (mandated by GIC spec).
291
+ */
292
+ qdev_prop_set_uint32(gicdev, "num-irq", NUM_IRQS + 32);
293
+ qdev_prop_set_bit(gicdev, "has-security-extensions", true);
294
+
295
+ redist0_capacity =
296
+ sbsa_ref_memmap[SBSA_GIC_REDIST].size / GICV3_REDIST_SIZE;
297
+ redist0_count = MIN(smp_cpus, redist0_capacity);
298
+
299
+ qdev_prop_set_uint32(gicdev, "len-redist-region-count", 1);
300
+ qdev_prop_set_uint32(gicdev, "redist-region-count[0]", redist0_count);
301
+
302
+ qdev_init_nofail(gicdev);
303
+ gicbusdev = SYS_BUS_DEVICE(gicdev);
304
+ sysbus_mmio_map(gicbusdev, 0, sbsa_ref_memmap[SBSA_GIC_DIST].base);
305
+ sysbus_mmio_map(gicbusdev, 1, sbsa_ref_memmap[SBSA_GIC_REDIST].base);
306
+
307
+ /*
308
+ * Wire the outputs from each CPU's generic timer and the GICv3
309
+ * maintenance interrupt signal to the appropriate GIC PPI inputs,
310
+ * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs.
311
+ */
312
+ for (i = 0; i < smp_cpus; i++) {
313
+ DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
314
+ int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS;
315
+ int irq;
316
+ /*
317
+ * Mapping from the output timer irq lines from the CPU to the
318
+ * GIC PPI inputs used for this board.
319
+ */
320
+ const int timer_irq[] = {
321
+ [GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ,
322
+ [GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ,
323
+ [GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
324
+ [GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
325
+ };
326
+
327
+ for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
328
+ qdev_connect_gpio_out(cpudev, irq,
329
+ qdev_get_gpio_in(gicdev,
330
+ ppibase + timer_irq[irq]));
331
+ }
332
+
333
+ qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt", 0,
334
+ qdev_get_gpio_in(gicdev, ppibase
335
+ + ARCH_GIC_MAINT_IRQ));
336
+ qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
337
+ qdev_get_gpio_in(gicdev, ppibase
338
+ + VIRTUAL_PMU_IRQ));
339
+
340
+ sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
341
+ sysbus_connect_irq(gicbusdev, i + smp_cpus,
342
+ qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
343
+ sysbus_connect_irq(gicbusdev, i + 2 * smp_cpus,
344
+ qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
345
+ sysbus_connect_irq(gicbusdev, i + 3 * smp_cpus,
346
+ qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
347
+ }
348
+
349
+ for (i = 0; i < NUM_IRQS; i++) {
350
+ pic[i] = qdev_get_gpio_in(gicdev, i);
351
+ }
352
+}
353
+
354
+static void create_uart(const SBSAMachineState *sms, qemu_irq *pic, int uart,
355
+ MemoryRegion *mem, Chardev *chr)
356
+{
357
+ hwaddr base = sbsa_ref_memmap[uart].base;
358
+ int irq = sbsa_ref_irqmap[uart];
359
+ DeviceState *dev = qdev_create(NULL, "pl011");
360
+ SysBusDevice *s = SYS_BUS_DEVICE(dev);
361
+
362
+ qdev_prop_set_chr(dev, "chardev", chr);
363
+ qdev_init_nofail(dev);
364
+ memory_region_add_subregion(mem, base,
365
+ sysbus_mmio_get_region(s, 0));
366
+ sysbus_connect_irq(s, 0, pic[irq]);
367
+}
368
+
369
+static void create_rtc(const SBSAMachineState *sms, qemu_irq *pic)
370
+{
371
+ hwaddr base = sbsa_ref_memmap[SBSA_RTC].base;
372
+ int irq = sbsa_ref_irqmap[SBSA_RTC];
373
+
374
+ sysbus_create_simple("pl031", base, pic[irq]);
375
+}
376
+
377
+static DeviceState *gpio_key_dev;
378
+static void sbsa_ref_powerdown_req(Notifier *n, void *opaque)
379
+{
380
+ /* use gpio Pin 3 for power button event */
381
+ qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1);
382
+}
383
+
384
+static Notifier sbsa_ref_powerdown_notifier = {
385
+ .notify = sbsa_ref_powerdown_req
386
+};
387
+
388
+static void create_gpio(const SBSAMachineState *sms, qemu_irq *pic)
389
+{
390
+ DeviceState *pl061_dev;
391
+ hwaddr base = sbsa_ref_memmap[SBSA_GPIO].base;
392
+ int irq = sbsa_ref_irqmap[SBSA_GPIO];
393
+
394
+ pl061_dev = sysbus_create_simple("pl061", base, pic[irq]);
395
+
396
+ gpio_key_dev = sysbus_create_simple("gpio-key", -1,
397
+ qdev_get_gpio_in(pl061_dev, 3));
398
+
399
+ /* connect powerdown request */
400
+ qemu_register_powerdown_notifier(&sbsa_ref_powerdown_notifier);
401
+}
402
+
403
+static void create_ahci(const SBSAMachineState *sms, qemu_irq *pic)
404
+{
405
+ hwaddr base = sbsa_ref_memmap[SBSA_AHCI].base;
406
+ int irq = sbsa_ref_irqmap[SBSA_AHCI];
407
+ DeviceState *dev;
408
+ DriveInfo *hd[NUM_SATA_PORTS];
409
+ SysbusAHCIState *sysahci;
410
+ AHCIState *ahci;
411
+ int i;
412
+
413
+ dev = qdev_create(NULL, "sysbus-ahci");
414
+ qdev_prop_set_uint32(dev, "num-ports", NUM_SATA_PORTS);
415
+ qdev_init_nofail(dev);
416
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
417
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[irq]);
418
+
419
+ sysahci = SYSBUS_AHCI(dev);
420
+ ahci = &sysahci->ahci;
421
+ ide_drive_get(hd, ARRAY_SIZE(hd));
422
+ for (i = 0; i < ahci->ports; i++) {
423
+ if (hd[i] == NULL) {
424
+ continue;
425
+ }
426
+ ide_create_drive(&ahci->dev[i].port, 0, hd[i]);
427
+ }
428
+}
429
+
430
+static void create_ehci(const SBSAMachineState *sms, qemu_irq *pic)
431
+{
432
+ hwaddr base = sbsa_ref_memmap[SBSA_EHCI].base;
433
+ int irq = sbsa_ref_irqmap[SBSA_EHCI];
434
+
435
+ sysbus_create_simple("platform-ehci-usb", base, pic[irq]);
436
+}
437
+
438
+static void create_smmu(const SBSAMachineState *sms, qemu_irq *pic,
439
+ PCIBus *bus)
440
+{
441
+ hwaddr base = sbsa_ref_memmap[SBSA_SMMU].base;
442
+ int irq = sbsa_ref_irqmap[SBSA_SMMU];
443
+ DeviceState *dev;
444
+ int i;
445
+
446
+ dev = qdev_create(NULL, "arm-smmuv3");
447
+
448
+ object_property_set_link(OBJECT(dev), OBJECT(bus), "primary-bus",
449
+ &error_abort);
450
+ qdev_init_nofail(dev);
451
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
452
+ for (i = 0; i < NUM_SMMU_IRQS; i++) {
453
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]);
454
+ }
455
+}
456
+
457
+static void create_pcie(SBSAMachineState *sms, qemu_irq *pic)
458
+{
459
+ hwaddr base_ecam = sbsa_ref_memmap[SBSA_PCIE_ECAM].base;
460
+ hwaddr size_ecam = sbsa_ref_memmap[SBSA_PCIE_ECAM].size;
461
+ hwaddr base_mmio = sbsa_ref_memmap[SBSA_PCIE_MMIO].base;
462
+ hwaddr size_mmio = sbsa_ref_memmap[SBSA_PCIE_MMIO].size;
463
+ hwaddr base_mmio_high = sbsa_ref_memmap[SBSA_PCIE_MMIO_HIGH].base;
464
+ hwaddr size_mmio_high = sbsa_ref_memmap[SBSA_PCIE_MMIO_HIGH].size;
465
+ hwaddr base_pio = sbsa_ref_memmap[SBSA_PCIE_PIO].base;
466
+ int irq = sbsa_ref_irqmap[SBSA_PCIE];
467
+ MemoryRegion *mmio_alias, *mmio_alias_high, *mmio_reg;
468
+ MemoryRegion *ecam_alias, *ecam_reg;
469
+ DeviceState *dev;
470
+ PCIHostState *pci;
471
+ int i;
472
+
473
+ dev = qdev_create(NULL, TYPE_GPEX_HOST);
474
+ qdev_init_nofail(dev);
475
+
476
+ /* Map ECAM space */
477
+ ecam_alias = g_new0(MemoryRegion, 1);
478
+ ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
479
+ memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
480
+ ecam_reg, 0, size_ecam);
481
+ memory_region_add_subregion(get_system_memory(), base_ecam, ecam_alias);
482
+
483
+ /* Map the MMIO space */
484
+ mmio_alias = g_new0(MemoryRegion, 1);
485
+ mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
486
+ memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
487
+ mmio_reg, base_mmio, size_mmio);
488
+ memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias);
489
+
490
+ /* Map the MMIO_HIGH space */
491
+ mmio_alias_high = g_new0(MemoryRegion, 1);
492
+ memory_region_init_alias(mmio_alias_high, OBJECT(dev), "pcie-mmio-high",
493
+ mmio_reg, base_mmio_high, size_mmio_high);
494
+ memory_region_add_subregion(get_system_memory(), base_mmio_high,
495
+ mmio_alias_high);
496
+
497
+ /* Map IO port space */
498
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio);
499
+
500
+ for (i = 0; i < GPEX_NUM_IRQS; i++) {
501
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]);
502
+ gpex_set_irq_num(GPEX_HOST(dev), i, irq + i);
503
+ }
504
+
505
+ pci = PCI_HOST_BRIDGE(dev);
506
+ if (pci->bus) {
507
+ for (i = 0; i < nb_nics; i++) {
508
+ NICInfo *nd = &nd_table[i];
509
+
510
+ if (!nd->model) {
511
+ nd->model = g_strdup("e1000e");
512
+ }
513
+
514
+ pci_nic_init_nofail(nd, pci->bus, nd->model, NULL);
515
+ }
516
+ }
517
+
518
+ pci_create_simple(pci->bus, -1, "VGA");
519
+
520
+ create_smmu(sms, pic, pci->bus);
521
+}
522
+
523
+static void *sbsa_ref_dtb(const struct arm_boot_info *binfo, int *fdt_size)
524
+{
525
+ const SBSAMachineState *board = container_of(binfo, SBSAMachineState,
526
+ bootinfo);
527
+
528
+ *fdt_size = board->fdt_size;
529
+ return board->fdt;
530
+}
531
+
532
static void sbsa_ref_init(MachineState *machine)
533
{
534
SBSAMachineState *sms = SBSA_MACHINE(machine);
535
@@ -XXX,XX +XXX,XX @@ static void sbsa_ref_init(MachineState *machine)
536
MemoryRegion *sysmem = get_system_memory();
537
MemoryRegion *secure_sysmem = NULL;
538
MemoryRegion *ram = g_new(MemoryRegion, 1);
539
+ bool firmware_loaded;
540
const CPUArchIdList *possible_cpus;
541
int n, sbsa_max_cpus;
542
+ qemu_irq pic[NUM_IRQS];
543
544
if (strcmp(machine->cpu_type, ARM_CPU_TYPE_NAME("cortex-a57"))) {
545
error_report("sbsa-ref: CPU type other than the built-in "
546
@@ -XXX,XX +XXX,XX @@ static void sbsa_ref_init(MachineState *machine)
547
exit(1);
548
}
549
550
+ /*
551
+ * The Secure view of the world is the same as the NonSecure,
552
+ * but with a few extra devices. Create it as a container region
553
+ * containing the system memory at low priority; any secure-only
554
+ * devices go in at higher priority and take precedence.
555
+ */
556
+ secure_sysmem = g_new(MemoryRegion, 1);
557
+ memory_region_init(secure_sysmem, OBJECT(machine), "secure-memory",
558
+ UINT64_MAX);
559
+ memory_region_add_subregion_overlap(secure_sysmem, 0, sysmem, -1);
560
+
561
+ firmware_loaded = sbsa_firmware_init(sms, sysmem,
562
+ secure_sysmem ?: sysmem);
563
+
564
+ if (machine->kernel_filename && firmware_loaded) {
565
+ error_report("sbsa-ref: No fw_cfg device on this machine, "
566
+ "so -kernel option is not supported when firmware loaded, "
567
+ "please load OS from hard disk instead");
568
+ exit(1);
569
+ }
570
+
571
/*
572
* This machine has EL3 enabled, external firmware should supply PSCI
573
* implementation, so the QEMU's internal PSCI is disabled.
574
@@ -XXX,XX +XXX,XX @@ static void sbsa_ref_init(MachineState *machine)
575
machine->ram_size);
576
memory_region_add_subregion(sysmem, sbsa_ref_memmap[SBSA_MEM].base, ram);
577
578
+ create_fdt(sms);
579
+
580
+ create_secure_ram(sms, secure_sysmem);
581
+
582
+ create_gic(sms, pic);
583
+
584
+ create_uart(sms, pic, SBSA_UART, sysmem, serial_hd(0));
585
+ create_uart(sms, pic, SBSA_SECURE_UART, secure_sysmem, serial_hd(1));
586
+ /* Second secure UART for RAS and MM from EL0 */
587
+ create_uart(sms, pic, SBSA_SECURE_UART_MM, secure_sysmem, serial_hd(2));
588
+
589
+ create_rtc(sms, pic);
590
+
591
+ create_gpio(sms, pic);
592
+
593
+ create_ahci(sms, pic);
594
+
595
+ create_ehci(sms, pic);
596
+
597
+ create_pcie(sms, pic);
598
+
599
sms->bootinfo.ram_size = machine->ram_size;
600
sms->bootinfo.kernel_filename = machine->kernel_filename;
601
sms->bootinfo.nb_cpus = smp_cpus;
602
sms->bootinfo.board_id = -1;
603
sms->bootinfo.loader_start = sbsa_ref_memmap[SBSA_MEM].base;
604
+ sms->bootinfo.get_dtb = sbsa_ref_dtb;
605
+ sms->bootinfo.firmware_loaded = firmware_loaded;
606
arm_load_kernel(ARM_CPU(first_cpu), &sms->bootinfo);
607
}
821
}
608
822
609
@@ -XXX,XX +XXX,XX @@ sbsa_ref_get_default_cpu_node_id(const MachineState *ms, int idx)
823
static const VMStateDescription cprman_vmstate = {
610
return idx % nb_numa_nodes;
824
@@ -XXX,XX +XXX,XX @@ static void cprman_register_types(void)
825
type_register_static(&cprman_info);
826
type_register_static(&cprman_pll_info);
827
type_register_static(&cprman_pll_channel_info);
828
+ type_register_static(&cprman_clock_mux_info);
611
}
829
}
612
830
613
+static void sbsa_ref_instance_init(Object *obj)
831
type_init(cprman_register_types);
614
+{
615
+ SBSAMachineState *sms = SBSA_MACHINE(obj);
616
+
617
+ sbsa_flash_create(sms);
618
+}
619
+
620
static void sbsa_ref_class_init(ObjectClass *oc, void *data)
621
{
622
MachineClass *mc = MACHINE_CLASS(oc);
623
@@ -XXX,XX +XXX,XX @@ static void sbsa_ref_class_init(ObjectClass *oc, void *data)
624
static const TypeInfo sbsa_ref_info = {
625
.name = TYPE_SBSA_MACHINE,
626
.parent = TYPE_MACHINE,
627
+ .instance_init = sbsa_ref_instance_init,
628
.class_init = sbsa_ref_class_init,
629
.instance_size = sizeof(SBSAMachineState),
630
};
631
--
832
--
632
2.20.1
833
2.20.1
633
834
634
835
diff view generated by jsdifflib
1
From: Joel Stanley <joel@jms.id.au>
1
From: Luc Michel <luc@lmichel.fr>
2
2
3
The Linux kernel driver was updated in commit 4451d3f59f2a
3
A clock mux can be configured to select one of its 10 sources through
4
("clocksource/drivers/fttmr010: Fix set_next_event handler) to fix an
4
the CM_CTL register. It also embeds yet another clock divider, composed
5
issue observed on hardware:
5
of an integer part and a fractional part. The number of bits of each
6
part is mux dependent.
6
7
7
> RELOAD register is loaded into COUNT register when the aspeed timer
8
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
> is enabled, which means the next event may be delayed because timer
9
Signed-off-by: Luc Michel <luc@lmichel.fr>
9
> interrupt won't be generated until <0xFFFFFFFF - current_count +
10
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
> cycles>.
11
Tested-by: Guenter Roeck <linux@roeck-us.net>
11
12
When running under Qemu, the system appeared "laggy". The guest is now
13
scheduling timer events too regularly, starving the host of CPU time.
14
15
This patch modifies the timer model to attempt to schedule the timer
16
expiry as the guest requests, but if we have missed the deadline we
17
re interrupt and try again, which allows the guest to catch up.
18
19
Provides expected behaviour with old and new guest code.
20
21
Fixes: c04bd47db6b9 ("hw/timer: Add ASPEED timer device model")
22
Signed-off-by: Joel Stanley <joel@jms.id.au>
23
Signed-off-by: Cédric Le Goater <clg@kaod.org>
24
Message-id: 20190618165311.27066-8-clg@kaod.org
25
[clg: - merged a fix from Andrew Jeffery <andrew@aj.id.au>
26
"Fire interrupt on failure to meet deadline"
27
https://lists.ozlabs.org/pipermail/openbmc/2019-January/014641.html
28
- adapted commit log
29
- checkpatch fixes ]
30
Signed-off-by: Cédric Le Goater <clg@kaod.org>
31
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
32
---
13
---
33
hw/timer/aspeed_timer.c | 57 ++++++++++++++++++++++-------------------
14
hw/misc/bcm2835_cprman.c | 53 +++++++++++++++++++++++++++++++++++++++-
34
1 file changed, 30 insertions(+), 27 deletions(-)
15
1 file changed, 52 insertions(+), 1 deletion(-)
35
16
36
diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c
17
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
37
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
38
--- a/hw/timer/aspeed_timer.c
19
--- a/hw/misc/bcm2835_cprman.c
39
+++ b/hw/timer/aspeed_timer.c
20
+++ b/hw/misc/bcm2835_cprman.c
40
@@ -XXX,XX +XXX,XX @@ static inline uint64_t calculate_time(struct AspeedTimer *t, uint32_t ticks)
21
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_channel_info = {
41
22
42
static uint64_t calculate_next(struct AspeedTimer *t)
23
/* clock mux */
24
25
+static bool clock_mux_is_enabled(CprmanClockMuxState *mux)
26
+{
27
+ return FIELD_EX32(*mux->reg_ctl, CM_CLOCKx_CTL, ENABLE);
28
+}
29
+
30
static void clock_mux_update(CprmanClockMuxState *mux)
43
{
31
{
44
- uint64_t next = 0;
32
- clock_update(mux->out, 0);
45
- uint32_t rate = calculate_rate(t);
33
+ uint64_t freq;
46
+ uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
34
+ uint32_t div, src = FIELD_EX32(*mux->reg_ctl, CM_CLOCKx_CTL, SRC);
47
+ uint64_t next;
35
+ bool enabled = clock_mux_is_enabled(mux);
48
36
+
49
- while (!next) {
37
+ *mux->reg_ctl = FIELD_DP32(*mux->reg_ctl, CM_CLOCKx_CTL, BUSY, enabled);
50
- /* We don't know the relationship between the values in the match
38
+
51
- * registers, so sort using MAX/MIN/zero. We sort in that order as the
39
+ if (!enabled) {
52
- * timer counts down to zero. */
40
+ clock_update(mux->out, 0);
53
- uint64_t seq[] = {
41
+ return;
54
- calculate_time(t, MAX(t->match[0], t->match[1])),
55
- calculate_time(t, MIN(t->match[0], t->match[1])),
56
- calculate_time(t, 0),
57
- };
58
- uint64_t reload_ns;
59
- uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
60
+ /*
61
+ * We don't know the relationship between the values in the match
62
+ * registers, so sort using MAX/MIN/zero. We sort in that order as
63
+ * the timer counts down to zero.
64
+ */
65
66
- if (now < seq[0]) {
67
- next = seq[0];
68
- } else if (now < seq[1]) {
69
- next = seq[1];
70
- } else if (now < seq[2]) {
71
- next = seq[2];
72
- } else if (t->reload) {
73
- reload_ns = muldiv64(t->reload, NANOSECONDS_PER_SECOND, rate);
74
- t->start = now - ((now - t->start) % reload_ns);
75
- } else {
76
- /* no reload value, return 0 */
77
- break;
78
- }
79
+ next = calculate_time(t, MAX(t->match[0], t->match[1]));
80
+ if (now < next) {
81
+ return next;
82
}
83
84
- return next;
85
+ next = calculate_time(t, MIN(t->match[0], t->match[1]));
86
+ if (now < next) {
87
+ return next;
88
+ }
42
+ }
89
+
43
+
90
+ next = calculate_time(t, 0);
44
+ freq = clock_get_hz(mux->srcs[src]);
91
+ if (now < next) {
45
+
92
+ return next;
46
+ if (mux->int_bits == 0 && mux->frac_bits == 0) {
47
+ clock_update_hz(mux->out, freq);
48
+ return;
93
+ }
49
+ }
94
+
50
+
95
+ /* We've missed all deadlines, fire interrupt and try again */
51
+ /*
96
+ timer_del(&t->timer);
52
+ * The divider has an integer and a fractional part. The size of each part
53
+ * varies with the muxes (int_bits and frac_bits). Both parts are
54
+ * concatenated, with the integer part always starting at bit 12.
55
+ *
56
+ * 31 12 11 0
57
+ * ------------------------------
58
+ * CM_DIV | | int | frac | |
59
+ * ------------------------------
60
+ * <-----> <------>
61
+ * int_bits frac_bits
62
+ */
63
+ div = extract32(*mux->reg_div,
64
+ R_CM_CLOCKx_DIV_FRAC_LENGTH - mux->frac_bits,
65
+ mux->int_bits + mux->frac_bits);
97
+
66
+
98
+ if (timer_overflow_interrupt(t)) {
67
+ if (!div) {
99
+ t->level = !t->level;
68
+ clock_update(mux->out, 0);
100
+ qemu_set_irq(t->irq, t->level);
69
+ return;
101
+ }
70
+ }
102
+
71
+
103
+ t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
72
+ freq = muldiv64(freq, 1 << mux->frac_bits, div);
104
+ return calculate_time(t, MAX(MAX(t->match[0], t->match[1]), 0));
73
+
74
+ clock_update_hz(mux->out, freq);
105
}
75
}
106
76
107
static void aspeed_timer_mod(AspeedTimer *t)
77
static void clock_mux_src_update(void *opaque)
78
{
79
CprmanClockMuxState **backref = opaque;
80
CprmanClockMuxState *s = *backref;
81
+ CprmanClockMuxSource src = backref - s->backref;
82
+
83
+ if (FIELD_EX32(*s->reg_ctl, CM_CLOCKx_CTL, SRC) != src) {
84
+ return;
85
+ }
86
87
clock_mux_update(s);
88
}
108
--
89
--
109
2.20.1
90
2.20.1
110
91
111
92
diff view generated by jsdifflib
1
From: Andrey Smirnov <andrew.smirnov@gmail.com>
1
From: Luc Michel <luc@lmichel.fr>
2
2
3
Instantiate no-op APBH DMA module. Needed to boot latest Linux kernel.
3
This simple mux sits between the PLL channels and the DSI0E and DSI0P
4
4
clock muxes. This mux selects between PLLA-DSI0 and PLLD-DSI0 channel
5
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
5
and outputs the selected signal to source number 4 of DSI0E/P clock
6
Cc: Peter Maydell <peter.maydell@linaro.org>
6
muxes. It is controlled by the cm_dsi0hsck register.
7
Cc: Michael S. Tsirkin <mst@redhat.com>
7
8
Cc: qemu-devel@nongnu.org
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Cc: qemu-arm@nongnu.org
9
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
Signed-off-by: Luc Michel <luc@lmichel.fr>
11
Tested-by: Guenter Roeck <linux@roeck-us.net>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
12
---
13
---
13
include/hw/arm/fsl-imx7.h | 3 +++
14
include/hw/misc/bcm2835_cprman.h | 15 +++++
14
hw/arm/fsl-imx7.c | 6 ++++++
15
include/hw/misc/bcm2835_cprman_internals.h | 6 ++
15
2 files changed, 9 insertions(+)
16
hw/misc/bcm2835_cprman.c | 74 +++++++++++++++++++++-
16
17
3 files changed, 94 insertions(+), 1 deletion(-)
17
diff --git a/include/hw/arm/fsl-imx7.h b/include/hw/arm/fsl-imx7.h
18
19
diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h
18
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
19
--- a/include/hw/arm/fsl-imx7.h
21
--- a/include/hw/misc/bcm2835_cprman.h
20
+++ b/include/hw/arm/fsl-imx7.h
22
+++ b/include/hw/misc/bcm2835_cprman.h
21
@@ -XXX,XX +XXX,XX @@ enum FslIMX7MemoryMap {
23
@@ -XXX,XX +XXX,XX @@ typedef struct CprmanClockMuxState {
22
FSL_IMX7_PCIE_REG_SIZE = 16 * 1024,
24
struct CprmanClockMuxState *backref[CPRMAN_NUM_CLOCK_MUX_SRC];
23
25
} CprmanClockMuxState;
24
FSL_IMX7_GPR_ADDR = 0x30340000,
26
25
+
27
+typedef struct CprmanDsi0HsckMuxState {
26
+ FSL_IMX7_DMA_APBH_ADDR = 0x33000000,
28
+ /*< private >*/
27
+ FSL_IMX7_DMA_APBH_SIZE = 0x2000,
29
+ DeviceState parent_obj;
30
+
31
+ /*< public >*/
32
+ CprmanClockMux id;
33
+
34
+ uint32_t *reg_cm;
35
+
36
+ Clock *plla_in;
37
+ Clock *plld_in;
38
+ Clock *out;
39
+} CprmanDsi0HsckMuxState;
40
+
41
struct BCM2835CprmanState {
42
/*< private >*/
43
SysBusDevice parent_obj;
44
@@ -XXX,XX +XXX,XX @@ struct BCM2835CprmanState {
45
CprmanPllState plls[CPRMAN_NUM_PLL];
46
CprmanPllChannelState channels[CPRMAN_NUM_PLL_CHANNEL];
47
CprmanClockMuxState clock_muxes[CPRMAN_NUM_CLOCK_MUX];
48
+ CprmanDsi0HsckMuxState dsi0hsck_mux;
49
50
uint32_t regs[CPRMAN_NUM_REGS];
51
uint32_t xosc_freq;
52
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
53
index XXXXXXX..XXXXXXX 100644
54
--- a/include/hw/misc/bcm2835_cprman_internals.h
55
+++ b/include/hw/misc/bcm2835_cprman_internals.h
56
@@ -XXX,XX +XXX,XX @@
57
#define TYPE_CPRMAN_PLL "bcm2835-cprman-pll"
58
#define TYPE_CPRMAN_PLL_CHANNEL "bcm2835-cprman-pll-channel"
59
#define TYPE_CPRMAN_CLOCK_MUX "bcm2835-cprman-clock-mux"
60
+#define TYPE_CPRMAN_DSI0HSCK_MUX "bcm2835-cprman-dsi0hsck-mux"
61
62
DECLARE_INSTANCE_CHECKER(CprmanPllState, CPRMAN_PLL,
63
TYPE_CPRMAN_PLL)
64
@@ -XXX,XX +XXX,XX @@ DECLARE_INSTANCE_CHECKER(CprmanPllChannelState, CPRMAN_PLL_CHANNEL,
65
TYPE_CPRMAN_PLL_CHANNEL)
66
DECLARE_INSTANCE_CHECKER(CprmanClockMuxState, CPRMAN_CLOCK_MUX,
67
TYPE_CPRMAN_CLOCK_MUX)
68
+DECLARE_INSTANCE_CHECKER(CprmanDsi0HsckMuxState, CPRMAN_DSI0HSCK_MUX,
69
+ TYPE_CPRMAN_DSI0HSCK_MUX)
70
71
/* Register map */
72
73
@@ -XXX,XX +XXX,XX @@ REG32(CM_LOCK, 0x114)
74
FIELD(CM_LOCK, FLOCKB, 9, 1)
75
FIELD(CM_LOCK, FLOCKA, 8, 1)
76
77
+REG32(CM_DSI0HSCK, 0x120)
78
+ FIELD(CM_DSI0HSCK, SELPLLD, 0, 1)
79
+
80
/*
81
* This field is common to all registers. Each register write value must match
82
* the CPRMAN_PASSWORD magic value in its 8 MSB.
83
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
84
index XXXXXXX..XXXXXXX 100644
85
--- a/hw/misc/bcm2835_cprman.c
86
+++ b/hw/misc/bcm2835_cprman.c
87
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_clock_mux_info = {
28
};
88
};
29
89
30
enum FslIMX7IRQs {
90
31
diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c
91
+/* DSI0HSCK mux */
32
index XXXXXXX..XXXXXXX 100644
92
+
33
--- a/hw/arm/fsl-imx7.c
93
+static void dsi0hsck_mux_update(CprmanDsi0HsckMuxState *s)
34
+++ b/hw/arm/fsl-imx7.c
94
+{
35
@@ -XXX,XX +XXX,XX @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
95
+ bool src_is_plld = FIELD_EX32(*s->reg_cm, CM_DSI0HSCK, SELPLLD);
36
*/
96
+ Clock *src = src_is_plld ? s->plld_in : s->plla_in;
37
create_unimplemented_device("lcdif", FSL_IMX7_LCDIF_ADDR,
97
+
38
FSL_IMX7_LCDIF_SIZE);
98
+ clock_update(s->out, clock_get(src));
39
+
99
+}
40
+ /*
100
+
41
+ * DMA APBH
101
+static void dsi0hsck_mux_in_update(void *opaque)
42
+ */
102
+{
43
+ create_unimplemented_device("dma-apbh", FSL_IMX7_DMA_APBH_ADDR,
103
+ dsi0hsck_mux_update(CPRMAN_DSI0HSCK_MUX(opaque));
44
+ FSL_IMX7_DMA_APBH_SIZE);
104
+}
105
+
106
+static void dsi0hsck_mux_init(Object *obj)
107
+{
108
+ CprmanDsi0HsckMuxState *s = CPRMAN_DSI0HSCK_MUX(obj);
109
+ DeviceState *dev = DEVICE(obj);
110
+
111
+ s->plla_in = qdev_init_clock_in(dev, "plla-in", dsi0hsck_mux_in_update, s);
112
+ s->plld_in = qdev_init_clock_in(dev, "plld-in", dsi0hsck_mux_in_update, s);
113
+ s->out = qdev_init_clock_out(DEVICE(s), "out");
114
+}
115
+
116
+static const VMStateDescription dsi0hsck_mux_vmstate = {
117
+ .name = TYPE_CPRMAN_DSI0HSCK_MUX,
118
+ .version_id = 1,
119
+ .minimum_version_id = 1,
120
+ .fields = (VMStateField[]) {
121
+ VMSTATE_CLOCK(plla_in, CprmanDsi0HsckMuxState),
122
+ VMSTATE_CLOCK(plld_in, CprmanDsi0HsckMuxState),
123
+ VMSTATE_END_OF_LIST()
124
+ }
125
+};
126
+
127
+static void dsi0hsck_mux_class_init(ObjectClass *klass, void *data)
128
+{
129
+ DeviceClass *dc = DEVICE_CLASS(klass);
130
+
131
+ dc->vmsd = &dsi0hsck_mux_vmstate;
132
+}
133
+
134
+static const TypeInfo cprman_dsi0hsck_mux_info = {
135
+ .name = TYPE_CPRMAN_DSI0HSCK_MUX,
136
+ .parent = TYPE_DEVICE,
137
+ .instance_size = sizeof(CprmanDsi0HsckMuxState),
138
+ .class_init = dsi0hsck_mux_class_init,
139
+ .instance_init = dsi0hsck_mux_init,
140
+};
141
+
142
+
143
/* CPRMAN "top level" model */
144
145
static uint32_t get_cm_lock(const BCM2835CprmanState *s)
146
@@ -XXX,XX +XXX,XX @@ static void cprman_write(void *opaque, hwaddr offset,
147
case R_CM_EMMC2CTL ... R_CM_EMMC2DIV:
148
update_mux_from_cm(s, idx);
149
break;
150
+
151
+ case R_CM_DSI0HSCK:
152
+ dsi0hsck_mux_update(&s->dsi0hsck_mux);
153
+ break;
154
}
45
}
155
}
46
156
47
static void fsl_imx7_class_init(ObjectClass *oc, void *data)
157
@@ -XXX,XX +XXX,XX @@ static void cprman_reset(DeviceState *dev)
158
device_cold_reset(DEVICE(&s->channels[i]));
159
}
160
161
+ device_cold_reset(DEVICE(&s->dsi0hsck_mux));
162
+
163
for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
164
device_cold_reset(DEVICE(&s->clock_muxes[i]));
165
}
166
@@ -XXX,XX +XXX,XX @@ static void cprman_init(Object *obj)
167
set_pll_channel_init_info(s, &s->channels[i], i);
168
}
169
170
+ object_initialize_child(obj, "dsi0hsck-mux",
171
+ &s->dsi0hsck_mux, TYPE_CPRMAN_DSI0HSCK_MUX);
172
+ s->dsi0hsck_mux.reg_cm = &s->regs[R_CM_DSI0HSCK];
173
+
174
for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
175
char *alias;
176
177
@@ -XXX,XX +XXX,XX @@ static void connect_mux_sources(BCM2835CprmanState *s,
178
if (mapping == CPRMAN_CLOCK_SRC_FORCE_GROUND) {
179
src = s->gnd;
180
} else if (mapping == CPRMAN_CLOCK_SRC_DSI0HSCK) {
181
- src = s->gnd; /* TODO */
182
+ src = s->dsi0hsck_mux.out;
183
} else if (i < CPRMAN_CLOCK_SRC_PLLA) {
184
src = CLK_SRC_MAPPING[i];
185
} else {
186
@@ -XXX,XX +XXX,XX @@ static void cprman_realize(DeviceState *dev, Error **errp)
187
}
188
}
189
190
+ clock_set_source(s->dsi0hsck_mux.plla_in,
191
+ s->channels[CPRMAN_PLLA_CHANNEL_DSI0].out);
192
+ clock_set_source(s->dsi0hsck_mux.plld_in,
193
+ s->channels[CPRMAN_PLLD_CHANNEL_DSI0].out);
194
+
195
+ if (!qdev_realize(DEVICE(&s->dsi0hsck_mux), NULL, errp)) {
196
+ return;
197
+ }
198
+
199
for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
200
CprmanClockMuxState *clock_mux = &s->clock_muxes[i];
201
202
@@ -XXX,XX +XXX,XX @@ static void cprman_register_types(void)
203
type_register_static(&cprman_pll_info);
204
type_register_static(&cprman_pll_channel_info);
205
type_register_static(&cprman_clock_mux_info);
206
+ type_register_static(&cprman_dsi0hsck_mux_info);
207
}
208
209
type_init(cprman_register_types);
48
--
210
--
49
2.20.1
211
2.20.1
50
212
51
213
diff view generated by jsdifflib
1
From: Cédric Le Goater <clg@kaod.org>
1
From: Luc Michel <luc@lmichel.fr>
2
2
3
This will simplify the definition of new SoCs, like the AST2600 which
3
Those reset values have been extracted from a Raspberry Pi 3 model B
4
should use a different CPU and a different IRQ number layout.
4
v1.2, using the 2020-08-20 version of raspios. The dump was done using
5
5
the debugfs interface of the CPRMAN driver in Linux (under
6
Signed-off-by: Cédric Le Goater <clg@kaod.org>
6
'/sys/kernel/debug/clk'). Each exposed clock tree stage (PLLs, channels
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
7
and muxes) can be observed by reading the 'regdump' file (e.g.
8
Reviewed-by: Joel Stanley <joel@jms.id.au>
8
'plla/regdump').
9
Message-id: 20190618165311.27066-2-clg@kaod.org
9
10
Those values are set by the Raspberry Pi firmware at boot time (Linux
11
expects them to be set when it boots up).
12
13
Some stages are not exposed by the Linux driver (e.g. the PLL B). For
14
those, the reset values are unknown and left to 0 which implies a
15
disabled output.
16
17
Once booted in QEMU, the final clock tree is very similar to the one
18
visible on real hardware. The differences come from some unimplemented
19
devices for which the driver simply disable the corresponding clock.
20
21
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
22
Signed-off-by: Luc Michel <luc@lmichel.fr>
23
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
24
Tested-by: Guenter Roeck <linux@roeck-us.net>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
25
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
26
---
12
include/hw/arm/aspeed_soc.h | 36 +++++++++++++++++++++++
27
include/hw/misc/bcm2835_cprman_internals.h | 269 +++++++++++++++++++++
13
hw/arm/aspeed_soc.c | 57 +++++++++++++++++++++++++++++++------
28
hw/misc/bcm2835_cprman.c | 31 +++
14
2 files changed, 85 insertions(+), 8 deletions(-)
29
2 files changed, 300 insertions(+)
15
30
16
diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h
31
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
17
index XXXXXXX..XXXXXXX 100644
32
index XXXXXXX..XXXXXXX 100644
18
--- a/include/hw/arm/aspeed_soc.h
33
--- a/include/hw/misc/bcm2835_cprman_internals.h
19
+++ b/include/hw/arm/aspeed_soc.h
34
+++ b/include/hw/misc/bcm2835_cprman_internals.h
20
@@ -XXX,XX +XXX,XX @@ typedef struct AspeedSoCInfo {
35
@@ -XXX,XX +XXX,XX @@ static inline void set_clock_mux_init_info(BCM2835CprmanState *s,
21
const char *fmc_typename;
36
mux->frac_bits = CLOCK_MUX_INIT_INFO[id].frac_bits;
22
const char **spi_typename;
37
}
23
int wdts_num;
38
24
+ const int *irqmap;
39
+
25
} AspeedSoCInfo;
40
+/*
26
41
+ * Object reset info
27
typedef struct AspeedSoCClass {
42
+ * Those values have been dumped from a Raspberry Pi 3 Model B v1.2 using the
28
@@ -XXX,XX +XXX,XX @@ typedef struct AspeedSoCClass {
43
+ * clk debugfs interface in Linux.
29
#define ASPEED_SOC_GET_CLASS(obj) \
44
+ */
30
OBJECT_GET_CLASS(AspeedSoCClass, (obj), TYPE_ASPEED_SOC)
45
+typedef struct PLLResetInfo {
31
46
+ uint32_t cm;
32
+enum {
47
+ uint32_t a2w_ctrl;
33
+ ASPEED_IOMEM,
48
+ uint32_t a2w_ana[4];
34
+ ASPEED_UART1,
49
+ uint32_t a2w_frac;
35
+ ASPEED_UART2,
50
+} PLLResetInfo;
36
+ ASPEED_UART3,
51
+
37
+ ASPEED_UART4,
52
+static const PLLResetInfo PLL_RESET_INFO[] = {
38
+ ASPEED_UART5,
53
+ [CPRMAN_PLLA] = {
39
+ ASPEED_VUART,
54
+ .cm = 0x0000008a,
40
+ ASPEED_FMC,
55
+ .a2w_ctrl = 0x0002103a,
41
+ ASPEED_SPI1,
56
+ .a2w_frac = 0x00098000,
42
+ ASPEED_SPI2,
57
+ .a2w_ana = { 0x00000000, 0x00144000, 0x00000000, 0x00000100 }
43
+ ASPEED_VIC,
58
+ },
44
+ ASPEED_SDMC,
59
+
45
+ ASPEED_SCU,
60
+ [CPRMAN_PLLC] = {
46
+ ASPEED_ADC,
61
+ .cm = 0x00000228,
47
+ ASPEED_SRAM,
62
+ .a2w_ctrl = 0x0002103e,
48
+ ASPEED_GPIO,
63
+ .a2w_frac = 0x00080000,
49
+ ASPEED_RTC,
64
+ .a2w_ana = { 0x00000000, 0x00144000, 0x00000000, 0x00000100 }
50
+ ASPEED_TIMER1,
65
+ },
51
+ ASPEED_TIMER2,
66
+
52
+ ASPEED_TIMER3,
67
+ [CPRMAN_PLLD] = {
53
+ ASPEED_TIMER4,
68
+ .cm = 0x0000020a,
54
+ ASPEED_TIMER5,
69
+ .a2w_ctrl = 0x00021034,
55
+ ASPEED_TIMER6,
70
+ .a2w_frac = 0x00015556,
56
+ ASPEED_TIMER7,
71
+ .a2w_ana = { 0x00000000, 0x00144000, 0x00000000, 0x00000100 }
57
+ ASPEED_TIMER8,
72
+ },
58
+ ASPEED_WDT,
73
+
59
+ ASPEED_PWM,
74
+ [CPRMAN_PLLH] = {
60
+ ASPEED_LPC,
75
+ .cm = 0x00000000,
61
+ ASPEED_IBT,
76
+ .a2w_ctrl = 0x0002102d,
62
+ ASPEED_I2C,
77
+ .a2w_frac = 0x00000000,
63
+ ASPEED_ETH1,
78
+ .a2w_ana = { 0x00900000, 0x0000000c, 0x00000000, 0x00000000 }
64
+ ASPEED_ETH2,
79
+ },
80
+
81
+ [CPRMAN_PLLB] = {
82
+ /* unknown */
83
+ .cm = 0x00000000,
84
+ .a2w_ctrl = 0x00000000,
85
+ .a2w_frac = 0x00000000,
86
+ .a2w_ana = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }
87
+ }
65
+};
88
+};
66
+
89
+
67
#endif /* ASPEED_SOC_H */
90
+typedef struct PLLChannelResetInfo {
68
diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c
91
+ /*
92
+ * Even though a PLL channel has a CM register, it shares it with its
93
+ * parent PLL. The parent already takes care of the reset value.
94
+ */
95
+ uint32_t a2w_ctrl;
96
+} PLLChannelResetInfo;
97
+
98
+static const PLLChannelResetInfo PLL_CHANNEL_RESET_INFO[] = {
99
+ [CPRMAN_PLLA_CHANNEL_DSI0] = { .a2w_ctrl = 0x00000100 },
100
+ [CPRMAN_PLLA_CHANNEL_CORE] = { .a2w_ctrl = 0x00000003 },
101
+ [CPRMAN_PLLA_CHANNEL_PER] = { .a2w_ctrl = 0x00000000 }, /* unknown */
102
+ [CPRMAN_PLLA_CHANNEL_CCP2] = { .a2w_ctrl = 0x00000100 },
103
+
104
+ [CPRMAN_PLLC_CHANNEL_CORE2] = { .a2w_ctrl = 0x00000100 },
105
+ [CPRMAN_PLLC_CHANNEL_CORE1] = { .a2w_ctrl = 0x00000100 },
106
+ [CPRMAN_PLLC_CHANNEL_PER] = { .a2w_ctrl = 0x00000002 },
107
+ [CPRMAN_PLLC_CHANNEL_CORE0] = { .a2w_ctrl = 0x00000002 },
108
+
109
+ [CPRMAN_PLLD_CHANNEL_DSI0] = { .a2w_ctrl = 0x00000100 },
110
+ [CPRMAN_PLLD_CHANNEL_CORE] = { .a2w_ctrl = 0x00000004 },
111
+ [CPRMAN_PLLD_CHANNEL_PER] = { .a2w_ctrl = 0x00000004 },
112
+ [CPRMAN_PLLD_CHANNEL_DSI1] = { .a2w_ctrl = 0x00000100 },
113
+
114
+ [CPRMAN_PLLH_CHANNEL_AUX] = { .a2w_ctrl = 0x00000004 },
115
+ [CPRMAN_PLLH_CHANNEL_RCAL] = { .a2w_ctrl = 0x00000000 },
116
+ [CPRMAN_PLLH_CHANNEL_PIX] = { .a2w_ctrl = 0x00000000 },
117
+
118
+ [CPRMAN_PLLB_CHANNEL_ARM] = { .a2w_ctrl = 0x00000000 }, /* unknown */
119
+};
120
+
121
+typedef struct ClockMuxResetInfo {
122
+ uint32_t cm_ctl;
123
+ uint32_t cm_div;
124
+} ClockMuxResetInfo;
125
+
126
+static const ClockMuxResetInfo CLOCK_MUX_RESET_INFO[] = {
127
+ [CPRMAN_CLOCK_GNRIC] = {
128
+ .cm_ctl = 0, /* unknown */
129
+ .cm_div = 0
130
+ },
131
+
132
+ [CPRMAN_CLOCK_VPU] = {
133
+ .cm_ctl = 0x00000245,
134
+ .cm_div = 0x00003000,
135
+ },
136
+
137
+ [CPRMAN_CLOCK_SYS] = {
138
+ .cm_ctl = 0, /* unknown */
139
+ .cm_div = 0
140
+ },
141
+
142
+ [CPRMAN_CLOCK_PERIA] = {
143
+ .cm_ctl = 0, /* unknown */
144
+ .cm_div = 0
145
+ },
146
+
147
+ [CPRMAN_CLOCK_PERII] = {
148
+ .cm_ctl = 0, /* unknown */
149
+ .cm_div = 0
150
+ },
151
+
152
+ [CPRMAN_CLOCK_H264] = {
153
+ .cm_ctl = 0x00000244,
154
+ .cm_div = 0x00003000,
155
+ },
156
+
157
+ [CPRMAN_CLOCK_ISP] = {
158
+ .cm_ctl = 0x00000244,
159
+ .cm_div = 0x00003000,
160
+ },
161
+
162
+ [CPRMAN_CLOCK_V3D] = {
163
+ .cm_ctl = 0, /* unknown */
164
+ .cm_div = 0
165
+ },
166
+
167
+ [CPRMAN_CLOCK_CAM0] = {
168
+ .cm_ctl = 0x00000000,
169
+ .cm_div = 0x00000000,
170
+ },
171
+
172
+ [CPRMAN_CLOCK_CAM1] = {
173
+ .cm_ctl = 0x00000000,
174
+ .cm_div = 0x00000000,
175
+ },
176
+
177
+ [CPRMAN_CLOCK_CCP2] = {
178
+ .cm_ctl = 0, /* unknown */
179
+ .cm_div = 0
180
+ },
181
+
182
+ [CPRMAN_CLOCK_DSI0E] = {
183
+ .cm_ctl = 0x00000000,
184
+ .cm_div = 0x00000000,
185
+ },
186
+
187
+ [CPRMAN_CLOCK_DSI0P] = {
188
+ .cm_ctl = 0x00000000,
189
+ .cm_div = 0x00000000,
190
+ },
191
+
192
+ [CPRMAN_CLOCK_DPI] = {
193
+ .cm_ctl = 0x00000000,
194
+ .cm_div = 0x00000000,
195
+ },
196
+
197
+ [CPRMAN_CLOCK_GP0] = {
198
+ .cm_ctl = 0x00000200,
199
+ .cm_div = 0x00000000,
200
+ },
201
+
202
+ [CPRMAN_CLOCK_GP1] = {
203
+ .cm_ctl = 0x00000096,
204
+ .cm_div = 0x00014000,
205
+ },
206
+
207
+ [CPRMAN_CLOCK_GP2] = {
208
+ .cm_ctl = 0x00000291,
209
+ .cm_div = 0x00249f00,
210
+ },
211
+
212
+ [CPRMAN_CLOCK_HSM] = {
213
+ .cm_ctl = 0x00000000,
214
+ .cm_div = 0x00000000,
215
+ },
216
+
217
+ [CPRMAN_CLOCK_OTP] = {
218
+ .cm_ctl = 0x00000091,
219
+ .cm_div = 0x00004000,
220
+ },
221
+
222
+ [CPRMAN_CLOCK_PCM] = {
223
+ .cm_ctl = 0x00000200,
224
+ .cm_div = 0x00000000,
225
+ },
226
+
227
+ [CPRMAN_CLOCK_PWM] = {
228
+ .cm_ctl = 0x00000200,
229
+ .cm_div = 0x00000000,
230
+ },
231
+
232
+ [CPRMAN_CLOCK_SLIM] = {
233
+ .cm_ctl = 0x00000200,
234
+ .cm_div = 0x00000000,
235
+ },
236
+
237
+ [CPRMAN_CLOCK_SMI] = {
238
+ .cm_ctl = 0x00000000,
239
+ .cm_div = 0x00000000,
240
+ },
241
+
242
+ [CPRMAN_CLOCK_TEC] = {
243
+ .cm_ctl = 0x00000000,
244
+ .cm_div = 0x00000000,
245
+ },
246
+
247
+ [CPRMAN_CLOCK_TD0] = {
248
+ .cm_ctl = 0, /* unknown */
249
+ .cm_div = 0
250
+ },
251
+
252
+ [CPRMAN_CLOCK_TD1] = {
253
+ .cm_ctl = 0, /* unknown */
254
+ .cm_div = 0
255
+ },
256
+
257
+ [CPRMAN_CLOCK_TSENS] = {
258
+ .cm_ctl = 0x00000091,
259
+ .cm_div = 0x0000a000,
260
+ },
261
+
262
+ [CPRMAN_CLOCK_TIMER] = {
263
+ .cm_ctl = 0x00000291,
264
+ .cm_div = 0x00013333,
265
+ },
266
+
267
+ [CPRMAN_CLOCK_UART] = {
268
+ .cm_ctl = 0x00000296,
269
+ .cm_div = 0x0000a6ab,
270
+ },
271
+
272
+ [CPRMAN_CLOCK_VEC] = {
273
+ .cm_ctl = 0x00000097,
274
+ .cm_div = 0x00002000,
275
+ },
276
+
277
+ [CPRMAN_CLOCK_PULSE] = {
278
+ .cm_ctl = 0, /* unknown */
279
+ .cm_div = 0
280
+ },
281
+
282
+ [CPRMAN_CLOCK_SDC] = {
283
+ .cm_ctl = 0x00004006,
284
+ .cm_div = 0x00003000,
285
+ },
286
+
287
+ [CPRMAN_CLOCK_ARM] = {
288
+ .cm_ctl = 0, /* unknown */
289
+ .cm_div = 0
290
+ },
291
+
292
+ [CPRMAN_CLOCK_AVEO] = {
293
+ .cm_ctl = 0x00000000,
294
+ .cm_div = 0x00000000,
295
+ },
296
+
297
+ [CPRMAN_CLOCK_EMMC] = {
298
+ .cm_ctl = 0x00000295,
299
+ .cm_div = 0x00006000,
300
+ },
301
+
302
+ [CPRMAN_CLOCK_EMMC2] = {
303
+ .cm_ctl = 0, /* unknown */
304
+ .cm_div = 0
305
+ },
306
+};
307
+
308
#endif
309
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
69
index XXXXXXX..XXXXXXX 100644
310
index XXXXXXX..XXXXXXX 100644
70
--- a/hw/arm/aspeed_soc.c
311
--- a/hw/misc/bcm2835_cprman.c
71
+++ b/hw/arm/aspeed_soc.c
312
+++ b/hw/misc/bcm2835_cprman.c
72
@@ -XXX,XX +XXX,XX @@
313
@@ -XXX,XX +XXX,XX @@
73
#define ASPEED_SOC_ETH1_BASE 0x1E660000
314
74
#define ASPEED_SOC_ETH2_BASE 0x1E680000
315
/* PLL */
75
316
76
-static const int uart_irqs[] = { 9, 32, 33, 34, 10 };
317
+static void pll_reset(DeviceState *dev)
77
-static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, };
78
+static const int aspeed_soc_ast2400_irqmap[] = {
79
+ [ASPEED_UART1] = 9,
80
+ [ASPEED_UART2] = 32,
81
+ [ASPEED_UART3] = 33,
82
+ [ASPEED_UART4] = 34,
83
+ [ASPEED_UART5] = 10,
84
+ [ASPEED_VUART] = 8,
85
+ [ASPEED_FMC] = 19,
86
+ [ASPEED_SDMC] = 0,
87
+ [ASPEED_SCU] = 21,
88
+ [ASPEED_ADC] = 31,
89
+ [ASPEED_GPIO] = 20,
90
+ [ASPEED_RTC] = 22,
91
+ [ASPEED_TIMER1] = 16,
92
+ [ASPEED_TIMER2] = 17,
93
+ [ASPEED_TIMER3] = 18,
94
+ [ASPEED_TIMER4] = 35,
95
+ [ASPEED_TIMER5] = 36,
96
+ [ASPEED_TIMER6] = 37,
97
+ [ASPEED_TIMER7] = 38,
98
+ [ASPEED_TIMER8] = 39,
99
+ [ASPEED_WDT] = 27,
100
+ [ASPEED_PWM] = 28,
101
+ [ASPEED_LPC] = 8,
102
+ [ASPEED_IBT] = 8, /* LPC */
103
+ [ASPEED_I2C] = 12,
104
+ [ASPEED_ETH1] = 2,
105
+ [ASPEED_ETH2] = 3,
106
+};
107
108
#define AST2400_SDRAM_BASE 0x40000000
109
#define AST2500_SDRAM_BASE 0x80000000
110
111
+/* AST2500 uses the same IRQs as the AST2400 */
112
+#define aspeed_soc_ast2500_irqmap aspeed_soc_ast2400_irqmap
113
+
114
static const hwaddr aspeed_soc_ast2400_spi_bases[] = { ASPEED_SOC_SPI_BASE };
115
static const char *aspeed_soc_ast2400_typenames[] = { "aspeed.smc.spi" };
116
117
@@ -XXX,XX +XXX,XX @@ static const AspeedSoCInfo aspeed_socs[] = {
118
.fmc_typename = "aspeed.smc.fmc",
119
.spi_typename = aspeed_soc_ast2400_typenames,
120
.wdts_num = 2,
121
+ .irqmap = aspeed_soc_ast2400_irqmap,
122
}, {
123
.name = "ast2400-a1",
124
.cpu_type = ARM_CPU_TYPE_NAME("arm926"),
125
@@ -XXX,XX +XXX,XX @@ static const AspeedSoCInfo aspeed_socs[] = {
126
.fmc_typename = "aspeed.smc.fmc",
127
.spi_typename = aspeed_soc_ast2400_typenames,
128
.wdts_num = 2,
129
+ .irqmap = aspeed_soc_ast2400_irqmap,
130
}, {
131
.name = "ast2400",
132
.cpu_type = ARM_CPU_TYPE_NAME("arm926"),
133
@@ -XXX,XX +XXX,XX @@ static const AspeedSoCInfo aspeed_socs[] = {
134
.fmc_typename = "aspeed.smc.fmc",
135
.spi_typename = aspeed_soc_ast2400_typenames,
136
.wdts_num = 2,
137
+ .irqmap = aspeed_soc_ast2400_irqmap,
138
}, {
139
.name = "ast2500-a1",
140
.cpu_type = ARM_CPU_TYPE_NAME("arm1176"),
141
@@ -XXX,XX +XXX,XX @@ static const AspeedSoCInfo aspeed_socs[] = {
142
.fmc_typename = "aspeed.smc.ast2500-fmc",
143
.spi_typename = aspeed_soc_ast2500_typenames,
144
.wdts_num = 3,
145
+ .irqmap = aspeed_soc_ast2500_irqmap,
146
},
147
};
148
149
+static qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int ctrl)
150
+{
318
+{
151
+ AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
319
+ CprmanPllState *s = CPRMAN_PLL(dev);
152
+
320
+ const PLLResetInfo *info = &PLL_RESET_INFO[s->id];
153
+ return qdev_get_gpio_in(DEVICE(&s->vic), sc->info->irqmap[ctrl]);
321
+
322
+ *s->reg_cm = info->cm;
323
+ *s->reg_a2w_ctrl = info->a2w_ctrl;
324
+ memcpy(s->reg_a2w_ana, info->a2w_ana, sizeof(info->a2w_ana));
325
+ *s->reg_a2w_frac = info->a2w_frac;
154
+}
326
+}
155
+
327
+
156
static void aspeed_soc_init(Object *obj)
328
static bool pll_is_locked(const CprmanPllState *pll)
157
{
329
{
158
AspeedSoCState *s = ASPEED_SOC(obj);
330
return !FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, PWRDN)
159
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
331
@@ -XXX,XX +XXX,XX @@ static void pll_class_init(ObjectClass *klass, void *data)
160
return;
332
{
161
}
333
DeviceClass *dc = DEVICE_CLASS(klass);
162
sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, ASPEED_SOC_TIMER_BASE);
334
163
- for (i = 0; i < ARRAY_SIZE(timer_irqs); i++) {
335
+ dc->reset = pll_reset;
164
- qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->vic), timer_irqs[i]);
336
dc->vmsd = &pll_vmstate;
165
+ for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
337
}
166
+ qemu_irq irq = aspeed_soc_get_irq(s, ASPEED_TIMER1 + i);
338
167
sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq);
339
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_info = {
168
}
340
169
341
/* PLL channel */
170
/* UART - attach an 8250 to the IO space as our UART5 */
342
171
if (serial_hd(0)) {
343
+static void pll_channel_reset(DeviceState *dev)
172
- qemu_irq uart5 = qdev_get_gpio_in(DEVICE(&s->vic), uart_irqs[4]);
344
+{
173
+ qemu_irq uart5 = aspeed_soc_get_irq(s, ASPEED_UART5);
345
+ CprmanPllChannelState *s = CPRMAN_PLL_CHANNEL(dev);
174
serial_mm_init(get_system_memory(),
346
+ const PLLChannelResetInfo *info = &PLL_CHANNEL_RESET_INFO[s->id];
175
ASPEED_SOC_IOMEM_BASE + ASPEED_SOC_UART_5_BASE, 2,
347
+
176
uart5, 38400, serial_hd(0), DEVICE_LITTLE_ENDIAN);
348
+ *s->reg_a2w_ctrl = info->a2w_ctrl;
177
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
349
+}
178
}
350
+
179
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, ASPEED_SOC_I2C_BASE);
351
static bool pll_channel_is_enabled(CprmanPllChannelState *channel)
180
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0,
352
{
181
- qdev_get_gpio_in(DEVICE(&s->vic), 12));
353
/*
182
+ aspeed_soc_get_irq(s, ASPEED_I2C));
354
@@ -XXX,XX +XXX,XX @@ static void pll_channel_class_init(ObjectClass *klass, void *data)
183
355
{
184
/* FMC, The number of CS is set at the board level */
356
DeviceClass *dc = DEVICE_CLASS(klass);
185
object_property_set_bool(OBJECT(&s->fmc), true, "realized", &err);
357
186
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
358
+ dc->reset = pll_channel_reset;
187
sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 1,
359
dc->vmsd = &pll_channel_vmstate;
188
s->fmc.ctrl->flash_window_base);
360
}
189
sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0,
361
190
- qdev_get_gpio_in(DEVICE(&s->vic), 19));
362
@@ -XXX,XX +XXX,XX @@ static void clock_mux_src_update(void *opaque)
191
+ aspeed_soc_get_irq(s, ASPEED_FMC));
363
clock_mux_update(s);
192
364
}
193
/* SPI */
365
194
for (i = 0; i < sc->info->spis_num; i++) {
366
+static void clock_mux_reset(DeviceState *dev)
195
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
367
+{
196
}
368
+ CprmanClockMuxState *clock = CPRMAN_CLOCK_MUX(dev);
197
sysbus_mmio_map(SYS_BUS_DEVICE(&s->ftgmac100), 0, ASPEED_SOC_ETH1_BASE);
369
+ const ClockMuxResetInfo *info = &CLOCK_MUX_RESET_INFO[clock->id];
198
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100), 0,
370
+
199
- qdev_get_gpio_in(DEVICE(&s->vic), 2));
371
+ *clock->reg_ctl = info->cm_ctl;
200
+ aspeed_soc_get_irq(s, ASPEED_ETH1));
372
+ *clock->reg_div = info->cm_div;
201
}
373
+}
202
374
+
203
static void aspeed_soc_class_init(ObjectClass *oc, void *data)
375
static void clock_mux_init(Object *obj)
376
{
377
CprmanClockMuxState *s = CPRMAN_CLOCK_MUX(obj);
378
@@ -XXX,XX +XXX,XX @@ static void clock_mux_class_init(ObjectClass *klass, void *data)
379
{
380
DeviceClass *dc = DEVICE_CLASS(klass);
381
382
+ dc->reset = clock_mux_reset;
383
dc->vmsd = &clock_mux_vmstate;
384
}
385
204
--
386
--
205
2.20.1
387
2.20.1
206
388
207
389
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Luc Michel <luc@lmichel.fr>
2
2
3
To ease the review of the next commit,
3
Add a clock input to the PL011 UART so we can compute the current baud
4
move the vfp_exceptbits_to_host() function directly after
4
rate and trace it. This is intended for developers who wish to use QEMU
5
vfp_exceptbits_from_host(). Amusingly the diff shows we
5
to e.g. debug their firmware or to figure out the baud rate configured
6
are moving vfp_get_fpscr().
6
by an unknown/closed source binary.
7
7
8
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Message-id: 20190701132516.26392-15-philmd@redhat.com
9
Signed-off-by: Luc Michel <luc@lmichel.fr>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Tested-by: Guenter Roeck <linux@roeck-us.net>
11
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
13
---
13
target/arm/vfp_helper.c | 52 ++++++++++++++++++++---------------------
14
include/hw/char/pl011.h | 1 +
14
1 file changed, 26 insertions(+), 26 deletions(-)
15
hw/char/pl011.c | 45 +++++++++++++++++++++++++++++++++++++++++
16
hw/char/trace-events | 1 +
17
3 files changed, 47 insertions(+)
15
18
16
diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c
19
diff --git a/include/hw/char/pl011.h b/include/hw/char/pl011.h
17
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
18
--- a/target/arm/vfp_helper.c
21
--- a/include/hw/char/pl011.h
19
+++ b/target/arm/vfp_helper.c
22
+++ b/include/hw/char/pl011.h
20
@@ -XXX,XX +XXX,XX @@ static inline int vfp_exceptbits_from_host(int host_bits)
23
@@ -XXX,XX +XXX,XX @@ struct PL011State {
21
return target_bits;
24
int read_trigger;
25
CharBackend chr;
26
qemu_irq irq[6];
27
+ Clock *clk;
28
const unsigned char *id;
29
};
30
31
diff --git a/hw/char/pl011.c b/hw/char/pl011.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/hw/char/pl011.c
34
+++ b/hw/char/pl011.c
35
@@ -XXX,XX +XXX,XX @@
36
#include "hw/char/pl011.h"
37
#include "hw/irq.h"
38
#include "hw/sysbus.h"
39
+#include "hw/qdev-clock.h"
40
#include "migration/vmstate.h"
41
#include "chardev/char-fe.h"
42
#include "qemu/log.h"
43
@@ -XXX,XX +XXX,XX @@ static void pl011_set_read_trigger(PL011State *s)
44
s->read_trigger = 1;
22
}
45
}
23
46
24
-uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env)
47
+static unsigned int pl011_get_baudrate(const PL011State *s)
25
-{
26
- uint32_t i, fpscr;
27
-
28
- fpscr = env->vfp.xregs[ARM_VFP_FPSCR]
29
- | (env->vfp.vec_len << 16)
30
- | (env->vfp.vec_stride << 20);
31
-
32
- i = get_float_exception_flags(&env->vfp.fp_status);
33
- i |= get_float_exception_flags(&env->vfp.standard_fp_status);
34
- /* FZ16 does not generate an input denormal exception. */
35
- i |= (get_float_exception_flags(&env->vfp.fp_status_f16)
36
- & ~float_flag_input_denormal);
37
- fpscr |= vfp_exceptbits_from_host(i);
38
-
39
- i = env->vfp.qc[0] | env->vfp.qc[1] | env->vfp.qc[2] | env->vfp.qc[3];
40
- fpscr |= i ? FPCR_QC : 0;
41
-
42
- return fpscr;
43
-}
44
-
45
-uint32_t vfp_get_fpscr(CPUARMState *env)
46
-{
47
- return HELPER(vfp_get_fpscr)(env);
48
-}
49
-
50
/* Convert vfp exception flags to target form. */
51
static inline int vfp_exceptbits_to_host(int target_bits)
52
{
53
@@ -XXX,XX +XXX,XX @@ static inline int vfp_exceptbits_to_host(int target_bits)
54
return host_bits;
55
}
56
57
+uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env)
58
+{
48
+{
59
+ uint32_t i, fpscr;
49
+ uint64_t clk;
60
+
50
+
61
+ fpscr = env->vfp.xregs[ARM_VFP_FPSCR]
51
+ if (s->fbrd == 0) {
62
+ | (env->vfp.vec_len << 16)
52
+ return 0;
63
+ | (env->vfp.vec_stride << 20);
53
+ }
64
+
54
+
65
+ i = get_float_exception_flags(&env->vfp.fp_status);
55
+ clk = clock_get_hz(s->clk);
66
+ i |= get_float_exception_flags(&env->vfp.standard_fp_status);
56
+ return (clk / ((s->ibrd << 6) + s->fbrd)) << 2;
67
+ /* FZ16 does not generate an input denormal exception. */
68
+ i |= (get_float_exception_flags(&env->vfp.fp_status_f16)
69
+ & ~float_flag_input_denormal);
70
+ fpscr |= vfp_exceptbits_from_host(i);
71
+
72
+ i = env->vfp.qc[0] | env->vfp.qc[1] | env->vfp.qc[2] | env->vfp.qc[3];
73
+ fpscr |= i ? FPCR_QC : 0;
74
+
75
+ return fpscr;
76
+}
57
+}
77
+
58
+
78
+uint32_t vfp_get_fpscr(CPUARMState *env)
59
+static void pl011_trace_baudrate_change(const PL011State *s)
79
+{
60
+{
80
+ return HELPER(vfp_get_fpscr)(env);
61
+ trace_pl011_baudrate_change(pl011_get_baudrate(s),
62
+ clock_get_hz(s->clk),
63
+ s->ibrd, s->fbrd);
81
+}
64
+}
82
+
65
+
83
void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val)
66
static void pl011_write(void *opaque, hwaddr offset,
67
uint64_t value, unsigned size)
84
{
68
{
85
int i;
69
@@ -XXX,XX +XXX,XX @@ static void pl011_write(void *opaque, hwaddr offset,
70
break;
71
case 9: /* UARTIBRD */
72
s->ibrd = value;
73
+ pl011_trace_baudrate_change(s);
74
break;
75
case 10: /* UARTFBRD */
76
s->fbrd = value;
77
+ pl011_trace_baudrate_change(s);
78
break;
79
case 11: /* UARTLCR_H */
80
/* Reset the FIFO state on FIFO enable or disable */
81
@@ -XXX,XX +XXX,XX @@ static void pl011_event(void *opaque, QEMUChrEvent event)
82
pl011_put_fifo(opaque, 0x400);
83
}
84
85
+static void pl011_clock_update(void *opaque)
86
+{
87
+ PL011State *s = PL011(opaque);
88
+
89
+ pl011_trace_baudrate_change(s);
90
+}
91
+
92
static const MemoryRegionOps pl011_ops = {
93
.read = pl011_read,
94
.write = pl011_write,
95
.endianness = DEVICE_NATIVE_ENDIAN,
96
};
97
98
+static const VMStateDescription vmstate_pl011_clock = {
99
+ .name = "pl011/clock",
100
+ .version_id = 1,
101
+ .minimum_version_id = 1,
102
+ .fields = (VMStateField[]) {
103
+ VMSTATE_CLOCK(clk, PL011State),
104
+ VMSTATE_END_OF_LIST()
105
+ }
106
+};
107
+
108
static const VMStateDescription vmstate_pl011 = {
109
.name = "pl011",
110
.version_id = 2,
111
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_pl011 = {
112
VMSTATE_INT32(read_count, PL011State),
113
VMSTATE_INT32(read_trigger, PL011State),
114
VMSTATE_END_OF_LIST()
115
+ },
116
+ .subsections = (const VMStateDescription * []) {
117
+ &vmstate_pl011_clock,
118
+ NULL
119
}
120
};
121
122
@@ -XXX,XX +XXX,XX @@ static void pl011_init(Object *obj)
123
sysbus_init_irq(sbd, &s->irq[i]);
124
}
125
126
+ s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update, s);
127
+
128
s->read_trigger = 1;
129
s->ifl = 0x12;
130
s->cr = 0x300;
131
diff --git a/hw/char/trace-events b/hw/char/trace-events
132
index XXXXXXX..XXXXXXX 100644
133
--- a/hw/char/trace-events
134
+++ b/hw/char/trace-events
135
@@ -XXX,XX +XXX,XX @@ pl011_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
136
pl011_can_receive(uint32_t lcr, int read_count, int r) "LCR 0x%08x read_count %d returning %d"
137
pl011_put_fifo(uint32_t c, int read_count) "new char 0x%x read_count now %d"
138
pl011_put_fifo_full(void) "FIFO now full, RXFF set"
139
+pl011_baudrate_change(unsigned int baudrate, uint64_t clock, uint32_t ibrd, uint32_t fbrd) "new baudrate %u (clk: %" PRIu64 "hz, ibrd: %" PRIu32 ", fbrd: %" PRIu32 ")"
140
141
# cmsdk-apb-uart.c
142
cmsdk_apb_uart_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB UART read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
86
--
143
--
87
2.20.1
144
2.20.1
88
145
89
146
diff view generated by jsdifflib
1
From: Andrew Jones <drjones@redhat.com>
1
From: Luc Michel <luc@lmichel.fr>
2
2
3
Fix the condition used to check whether the initrd fits
3
Connect the 'uart-out' clock from the CPRMAN to the PL011 instance.
4
into RAM; in some cases if an initrd was also passed on
5
the command line we would get an error stating that it
6
was too big to fit into RAM after the kernel. Despite the
7
error the loader continued anyway, though, so also add an
8
exit(1) when the initrd is actually too big.
9
4
10
Fixes: 852dc64d665f ("hw/arm/boot: Diagnose layouts that put initrd or
5
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
11
DTB off the end of RAM")
6
Signed-off-by: Luc Michel <luc@lmichel.fr>
12
Signed-off-by: Andrew Jones <drjones@redhat.com>
7
Tested-by: Guenter Roeck <linux@roeck-us.net>
13
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
14
Message-id: 20190618125844.4863-1-drjones@redhat.com
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
---
10
---
17
hw/arm/boot.c | 3 ++-
11
hw/arm/bcm2835_peripherals.c | 2 ++
18
1 file changed, 2 insertions(+), 1 deletion(-)
12
1 file changed, 2 insertions(+)
19
13
20
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
14
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
21
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
22
--- a/hw/arm/boot.c
16
--- a/hw/arm/bcm2835_peripherals.c
23
+++ b/hw/arm/boot.c
17
+++ b/hw/arm/bcm2835_peripherals.c
24
@@ -XXX,XX +XXX,XX @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu,
18
@@ -XXX,XX +XXX,XX @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
25
info->initrd_filename);
19
}
26
exit(1);
20
memory_region_add_subregion(&s->peri_mr, CPRMAN_OFFSET,
27
}
21
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cprman), 0));
28
- if (info->initrd_start + initrd_size > info->ram_size) {
22
+ qdev_connect_clock_in(DEVICE(&s->uart0), "clk",
29
+ if (info->initrd_start + initrd_size > ram_end) {
23
+ qdev_get_clock_out(DEVICE(&s->cprman), "uart-out"));
30
error_report("could not load initrd '%s': "
24
31
"too big to fit into RAM after the kernel",
25
memory_region_add_subregion(&s->peri_mr, ARMCTRL_IC_OFFSET,
32
info->initrd_filename);
26
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->ic), 0));
33
+ exit(1);
34
}
35
} else {
36
initrd_size = 0;
37
--
27
--
38
2.20.1
28
2.20.1
39
29
40
30
diff view generated by jsdifflib
1
From: Hongbo Zhang <hongbo.zhang@linaro.org>
1
From: Shashi Mallela <shashi.mallela@linaro.org>
2
2
3
For AArch64, the existing "virt" machine is primarily meant to
3
Generic watchdog device model implementation as per ARM SBSA v6.0
4
run on KVM and execute virtualization workloads, but we need an
5
environment as faithful as possible to physical hardware, for supporting
6
firmware and OS development for physical Aarch64 machines.
7
4
8
This patch introduces new machine type 'sbsa-ref' with main features:
5
Signed-off-by: Shashi Mallela <shashi.mallela@linaro.org>
9
- Based on 'virt' machine type.
6
Message-id: 20201027015927.29495-2-shashi.mallela@linaro.org
10
- A new memory map.
11
- CPU type cortex-a57.
12
- EL2 and EL3 are enabled.
13
- GIC version 3.
14
- System bus AHCI controller.
15
- System bus EHCI controller.
16
- CDROM and hard disc on AHCI bus.
17
- E1000E ethernet card on PCIE bus.
18
- VGA display adaptor on PCIE bus.
19
- No virtio devices.
20
- No fw_cfg device.
21
- No ACPI table supplied.
22
- Only minimal device tree nodes.
23
24
Arm Trusted Firmware and UEFI porting to this are done accordingly,
25
and the firmware should supply ACPI tables to the guest OS. The
26
minimal device tree nodes supplied by QEMU for this platform are only
27
to pass the dynamic info reflecting command line input to firmware,
28
not for loading the guest OS.
29
30
To make the review easier, this task is split into two patches, the
31
fundamental skeleton part and the peripheral devices part; this patch is
32
the first part.
33
34
Signed-off-by: Hongbo Zhang <hongbo.zhang@linaro.org>
35
Message-id: 1561890034-15921-2-git-send-email-hongbo.zhang@linaro.org
36
[PMM: commit message tweaks; moved some bits between patch 1 and 2
37
to ensure patch 1 builds cleanly; removed unneeded lines from
38
Kconfig stanza; only provide board for qemu-system-aarch64, not
39
qemu-system-arm; added MAINTAINERS entry]
40
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
41
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
42
---
9
---
43
hw/arm/Makefile.objs | 1 +
10
include/hw/watchdog/sbsa_gwdt.h | 79 +++++++++
44
hw/arm/sbsa-ref.c | 271 ++++++++++++++++++++++++++++
11
hw/watchdog/sbsa_gwdt.c | 293 ++++++++++++++++++++++++++++++++
45
MAINTAINERS | 8 +
12
hw/arm/Kconfig | 1 +
46
default-configs/aarch64-softmmu.mak | 1 +
13
hw/watchdog/Kconfig | 3 +
47
hw/arm/Kconfig | 14 ++
14
hw/watchdog/meson.build | 1 +
48
5 files changed, 295 insertions(+)
15
5 files changed, 377 insertions(+)
49
create mode 100644 hw/arm/sbsa-ref.c
16
create mode 100644 include/hw/watchdog/sbsa_gwdt.h
17
create mode 100644 hw/watchdog/sbsa_gwdt.c
50
18
51
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
19
diff --git a/include/hw/watchdog/sbsa_gwdt.h b/include/hw/watchdog/sbsa_gwdt.h
52
index XXXXXXX..XXXXXXX 100644
53
--- a/hw/arm/Makefile.objs
54
+++ b/hw/arm/Makefile.objs
55
@@ -XXX,XX +XXX,XX @@ obj-$(CONFIG_SPITZ) += spitz.o
56
obj-$(CONFIG_TOSA) += tosa.o
57
obj-$(CONFIG_Z2) += z2.o
58
obj-$(CONFIG_REALVIEW) += realview.o
59
+obj-$(CONFIG_SBSA_REF) += sbsa-ref.o
60
obj-$(CONFIG_STELLARIS) += stellaris.o
61
obj-$(CONFIG_COLLIE) += collie.o
62
obj-$(CONFIG_VERSATILE) += versatilepb.o
63
diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
64
new file mode 100644
20
new file mode 100644
65
index XXXXXXX..XXXXXXX
21
index XXXXXXX..XXXXXXX
66
--- /dev/null
22
--- /dev/null
67
+++ b/hw/arm/sbsa-ref.c
23
+++ b/include/hw/watchdog/sbsa_gwdt.h
68
@@ -XXX,XX +XXX,XX @@
24
@@ -XXX,XX +XXX,XX @@
69
+/*
25
+/*
70
+ * ARM SBSA Reference Platform emulation
26
+ * Copyright (c) 2020 Linaro Limited
71
+ *
27
+ *
72
+ * Copyright (c) 2018 Linaro Limited
28
+ * Authors:
73
+ * Written by Hongbo Zhang <hongbo.zhang@linaro.org>
29
+ * Shashi Mallela <shashi.mallela@linaro.org>
74
+ *
30
+ *
75
+ * This program is free software; you can redistribute it and/or modify it
31
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
76
+ * under the terms and conditions of the GNU General Public License,
32
+ * option) any later version. See the COPYING file in the top-level directory.
77
+ * version 2 or later, as published by the Free Software Foundation.
33
+ *
78
+ *
79
+ * This program is distributed in the hope it will be useful, but WITHOUT
80
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
81
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
82
+ * more details.
83
+ *
84
+ * You should have received a copy of the GNU General Public License along with
85
+ * this program. If not, see <http://www.gnu.org/licenses/>.
86
+ */
34
+ */
87
+
35
+
36
+#ifndef WDT_SBSA_GWDT_H
37
+#define WDT_SBSA_GWDT_H
38
+
39
+#include "qemu/bitops.h"
40
+#include "hw/sysbus.h"
41
+#include "hw/irq.h"
42
+
43
+#define TYPE_WDT_SBSA "sbsa_gwdt"
44
+#define SBSA_GWDT(obj) \
45
+ OBJECT_CHECK(SBSA_GWDTState, (obj), TYPE_WDT_SBSA)
46
+#define SBSA_GWDT_CLASS(klass) \
47
+ OBJECT_CLASS_CHECK(SBSA_GWDTClass, (klass), TYPE_WDT_SBSA)
48
+#define SBSA_GWDT_GET_CLASS(obj) \
49
+ OBJECT_GET_CLASS(SBSA_GWDTClass, (obj), TYPE_WDT_SBSA)
50
+
51
+/* SBSA Generic Watchdog register definitions */
52
+/* refresh frame */
53
+#define SBSA_GWDT_WRR 0x000
54
+
55
+/* control frame */
56
+#define SBSA_GWDT_WCS 0x000
57
+#define SBSA_GWDT_WOR 0x008
58
+#define SBSA_GWDT_WORU 0x00C
59
+#define SBSA_GWDT_WCV 0x010
60
+#define SBSA_GWDT_WCVU 0x014
61
+
62
+/* Watchdog Interface Identification Register */
63
+#define SBSA_GWDT_W_IIDR 0xFCC
64
+
65
+/* Watchdog Control and Status Register Bits */
66
+#define SBSA_GWDT_WCS_EN BIT(0)
67
+#define SBSA_GWDT_WCS_WS0 BIT(1)
68
+#define SBSA_GWDT_WCS_WS1 BIT(2)
69
+
70
+#define SBSA_GWDT_WOR_MASK 0x0000FFFF
71
+
72
+/*
73
+ * Watchdog Interface Identification Register definition
74
+ * considering JEP106 code for ARM in Bits [11:0]
75
+ */
76
+#define SBSA_GWDT_ID 0x1043B
77
+
78
+/* 2 Separate memory regions for each of refresh & control register frames */
79
+#define SBSA_GWDT_RMMIO_SIZE 0x1000
80
+#define SBSA_GWDT_CMMIO_SIZE 0x1000
81
+
82
+#define SBSA_TIMER_FREQ 62500000 /* Hz */
83
+
84
+typedef struct SBSA_GWDTState {
85
+ /* <private> */
86
+ SysBusDevice parent_obj;
87
+
88
+ /*< public >*/
89
+ MemoryRegion rmmio;
90
+ MemoryRegion cmmio;
91
+ qemu_irq irq;
92
+
93
+ QEMUTimer *timer;
94
+
95
+ uint32_t id;
96
+ uint32_t wcs;
97
+ uint32_t worl;
98
+ uint32_t woru;
99
+ uint32_t wcvl;
100
+ uint32_t wcvu;
101
+} SBSA_GWDTState;
102
+
103
+#endif /* WDT_SBSA_GWDT_H */
104
diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c
105
new file mode 100644
106
index XXXXXXX..XXXXXXX
107
--- /dev/null
108
+++ b/hw/watchdog/sbsa_gwdt.c
109
@@ -XXX,XX +XXX,XX @@
110
+/*
111
+ * Generic watchdog device model for SBSA
112
+ *
113
+ * The watchdog device has been implemented as revision 1 variant of
114
+ * the ARM SBSA specification v6.0
115
+ * (https://developer.arm.com/documentation/den0029/d?lang=en)
116
+ *
117
+ * Copyright Linaro.org 2020
118
+ *
119
+ * Authors:
120
+ * Shashi Mallela <shashi.mallela@linaro.org>
121
+ *
122
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
123
+ * option) any later version. See the COPYING file in the top-level directory.
124
+ *
125
+ */
126
+
88
+#include "qemu/osdep.h"
127
+#include "qemu/osdep.h"
89
+#include "qapi/error.h"
128
+#include "sysemu/reset.h"
90
+#include "qemu/error-report.h"
129
+#include "sysemu/watchdog.h"
91
+#include "qemu/units.h"
130
+#include "hw/watchdog/sbsa_gwdt.h"
92
+#include "sysemu/numa.h"
131
+#include "qemu/timer.h"
93
+#include "sysemu/sysemu.h"
132
+#include "migration/vmstate.h"
94
+#include "exec/address-spaces.h"
133
+#include "qemu/log.h"
95
+#include "exec/hwaddr.h"
134
+#include "qemu/module.h"
96
+#include "kvm_arm.h"
135
+
97
+#include "hw/arm/boot.h"
136
+static WatchdogTimerModel model = {
98
+#include "hw/boards.h"
137
+ .wdt_name = TYPE_WDT_SBSA,
99
+#include "hw/intc/arm_gicv3_common.h"
138
+ .wdt_description = "SBSA-compliant generic watchdog device",
100
+
101
+#define RAMLIMIT_GB 8192
102
+#define RAMLIMIT_BYTES (RAMLIMIT_GB * GiB)
103
+
104
+enum {
105
+ SBSA_FLASH,
106
+ SBSA_MEM,
107
+ SBSA_CPUPERIPHS,
108
+ SBSA_GIC_DIST,
109
+ SBSA_GIC_REDIST,
110
+ SBSA_SMMU,
111
+ SBSA_UART,
112
+ SBSA_RTC,
113
+ SBSA_PCIE,
114
+ SBSA_PCIE_MMIO,
115
+ SBSA_PCIE_MMIO_HIGH,
116
+ SBSA_PCIE_PIO,
117
+ SBSA_PCIE_ECAM,
118
+ SBSA_GPIO,
119
+ SBSA_SECURE_UART,
120
+ SBSA_SECURE_UART_MM,
121
+ SBSA_SECURE_MEM,
122
+ SBSA_AHCI,
123
+ SBSA_EHCI,
124
+};
139
+};
125
+
140
+
126
+typedef struct MemMapEntry {
141
+static const VMStateDescription vmstate_sbsa_gwdt = {
127
+ hwaddr base;
142
+ .name = "sbsa-gwdt",
128
+ hwaddr size;
143
+ .version_id = 1,
129
+} MemMapEntry;
144
+ .minimum_version_id = 1,
130
+
145
+ .fields = (VMStateField[]) {
131
+typedef struct {
146
+ VMSTATE_TIMER_PTR(timer, SBSA_GWDTState),
132
+ MachineState parent;
147
+ VMSTATE_UINT32(wcs, SBSA_GWDTState),
133
+ struct arm_boot_info bootinfo;
148
+ VMSTATE_UINT32(worl, SBSA_GWDTState),
134
+ int smp_cpus;
149
+ VMSTATE_UINT32(woru, SBSA_GWDTState),
135
+ void *fdt;
150
+ VMSTATE_UINT32(wcvl, SBSA_GWDTState),
136
+ int fdt_size;
151
+ VMSTATE_UINT32(wcvu, SBSA_GWDTState),
137
+ int psci_conduit;
152
+ VMSTATE_END_OF_LIST()
138
+} SBSAMachineState;
153
+ }
139
+
140
+#define TYPE_SBSA_MACHINE MACHINE_TYPE_NAME("sbsa-ref")
141
+#define SBSA_MACHINE(obj) \
142
+ OBJECT_CHECK(SBSAMachineState, (obj), TYPE_SBSA_MACHINE)
143
+
144
+static const MemMapEntry sbsa_ref_memmap[] = {
145
+ /* 512M boot ROM */
146
+ [SBSA_FLASH] = { 0, 0x20000000 },
147
+ /* 512M secure memory */
148
+ [SBSA_SECURE_MEM] = { 0x20000000, 0x20000000 },
149
+ /* Space reserved for CPU peripheral devices */
150
+ [SBSA_CPUPERIPHS] = { 0x40000000, 0x00040000 },
151
+ [SBSA_GIC_DIST] = { 0x40060000, 0x00010000 },
152
+ [SBSA_GIC_REDIST] = { 0x40080000, 0x04000000 },
153
+ [SBSA_UART] = { 0x60000000, 0x00001000 },
154
+ [SBSA_RTC] = { 0x60010000, 0x00001000 },
155
+ [SBSA_GPIO] = { 0x60020000, 0x00001000 },
156
+ [SBSA_SECURE_UART] = { 0x60030000, 0x00001000 },
157
+ [SBSA_SECURE_UART_MM] = { 0x60040000, 0x00001000 },
158
+ [SBSA_SMMU] = { 0x60050000, 0x00020000 },
159
+ /* Space here reserved for more SMMUs */
160
+ [SBSA_AHCI] = { 0x60100000, 0x00010000 },
161
+ [SBSA_EHCI] = { 0x60110000, 0x00010000 },
162
+ /* Space here reserved for other devices */
163
+ [SBSA_PCIE_PIO] = { 0x7fff0000, 0x00010000 },
164
+ /* 32-bit address PCIE MMIO space */
165
+ [SBSA_PCIE_MMIO] = { 0x80000000, 0x70000000 },
166
+ /* 256M PCIE ECAM space */
167
+ [SBSA_PCIE_ECAM] = { 0xf0000000, 0x10000000 },
168
+ /* ~1TB PCIE MMIO space (4GB to 1024GB boundary) */
169
+ [SBSA_PCIE_MMIO_HIGH] = { 0x100000000ULL, 0xFF00000000ULL },
170
+ [SBSA_MEM] = { 0x10000000000ULL, RAMLIMIT_BYTES },
171
+};
154
+};
172
+
155
+
173
+static void sbsa_ref_init(MachineState *machine)
156
+typedef enum WdtRefreshType {
174
+{
157
+ EXPLICIT_REFRESH = 0,
175
+ SBSAMachineState *sms = SBSA_MACHINE(machine);
158
+ TIMEOUT_REFRESH = 1,
176
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
159
+} WdtRefreshType;
177
+ MemoryRegion *sysmem = get_system_memory();
160
+
178
+ MemoryRegion *secure_sysmem = NULL;
161
+static uint64_t sbsa_gwdt_rread(void *opaque, hwaddr addr, unsigned int size)
179
+ MemoryRegion *ram = g_new(MemoryRegion, 1);
162
+{
180
+ const CPUArchIdList *possible_cpus;
163
+ SBSA_GWDTState *s = SBSA_GWDT(opaque);
181
+ int n, sbsa_max_cpus;
164
+ uint32_t ret = 0;
182
+
165
+
183
+ if (strcmp(machine->cpu_type, ARM_CPU_TYPE_NAME("cortex-a57"))) {
166
+ switch (addr) {
184
+ error_report("sbsa-ref: CPU type other than the built-in "
167
+ case SBSA_GWDT_WRR:
185
+ "cortex-a57 not supported");
168
+ /* watch refresh read has no effect and returns 0 */
186
+ exit(1);
169
+ ret = 0;
187
+ }
170
+ break;
188
+
171
+ case SBSA_GWDT_W_IIDR:
189
+ if (kvm_enabled()) {
172
+ ret = s->id;
190
+ error_report("sbsa-ref: KVM is not supported for this machine");
173
+ break;
191
+ exit(1);
174
+ default:
192
+ }
175
+ qemu_log_mask(LOG_GUEST_ERROR, "bad address in refresh frame read :"
193
+
176
+ " 0x%x\n", (int)addr);
194
+ /*
177
+ }
195
+ * This machine has EL3 enabled, external firmware should supply PSCI
178
+ return ret;
196
+ * implementation, so the QEMU's internal PSCI is disabled.
179
+}
197
+ */
180
+
198
+ sms->psci_conduit = QEMU_PSCI_CONDUIT_DISABLED;
181
+static uint64_t sbsa_gwdt_read(void *opaque, hwaddr addr, unsigned int size)
199
+
182
+{
200
+ sbsa_max_cpus = sbsa_ref_memmap[SBSA_GIC_REDIST].size / GICV3_REDIST_SIZE;
183
+ SBSA_GWDTState *s = SBSA_GWDT(opaque);
201
+
184
+ uint32_t ret = 0;
202
+ if (max_cpus > sbsa_max_cpus) {
185
+
203
+ error_report("Number of SMP CPUs requested (%d) exceeds max CPUs "
186
+ switch (addr) {
204
+ "supported by machine 'sbsa-ref' (%d)",
187
+ case SBSA_GWDT_WCS:
205
+ max_cpus, sbsa_max_cpus);
188
+ ret = s->wcs;
206
+ exit(1);
189
+ break;
207
+ }
190
+ case SBSA_GWDT_WOR:
208
+
191
+ ret = s->worl;
209
+ sms->smp_cpus = smp_cpus;
192
+ break;
210
+
193
+ case SBSA_GWDT_WORU:
211
+ if (machine->ram_size > sbsa_ref_memmap[SBSA_MEM].size) {
194
+ ret = s->woru;
212
+ error_report("sbsa-ref: cannot model more than %dGB RAM", RAMLIMIT_GB);
195
+ break;
213
+ exit(1);
196
+ case SBSA_GWDT_WCV:
214
+ }
197
+ ret = s->wcvl;
215
+
198
+ break;
216
+ possible_cpus = mc->possible_cpu_arch_ids(machine);
199
+ case SBSA_GWDT_WCVU:
217
+ for (n = 0; n < possible_cpus->len; n++) {
200
+ ret = s->wcvu;
218
+ Object *cpuobj;
201
+ break;
219
+ CPUState *cs;
202
+ case SBSA_GWDT_W_IIDR:
220
+
203
+ ret = s->id;
221
+ if (n >= smp_cpus) {
204
+ break;
205
+ default:
206
+ qemu_log_mask(LOG_GUEST_ERROR, "bad address in control frame read :"
207
+ " 0x%x\n", (int)addr);
208
+ }
209
+ return ret;
210
+}
211
+
212
+static void sbsa_gwdt_update_timer(SBSA_GWDTState *s, WdtRefreshType rtype)
213
+{
214
+ uint64_t timeout = 0;
215
+
216
+ timer_del(s->timer);
217
+
218
+ if (s->wcs & SBSA_GWDT_WCS_EN) {
219
+ /*
220
+ * Extract the upper 16 bits from woru & 32 bits from worl
221
+ * registers to construct the 48 bit offset value
222
+ */
223
+ timeout = s->woru;
224
+ timeout <<= 32;
225
+ timeout |= s->worl;
226
+ timeout = muldiv64(timeout, NANOSECONDS_PER_SECOND, SBSA_TIMER_FREQ);
227
+ timeout += qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
228
+
229
+ if ((rtype == EXPLICIT_REFRESH) || ((rtype == TIMEOUT_REFRESH) &&
230
+ (!(s->wcs & SBSA_GWDT_WCS_WS0)))) {
231
+ /* store the current timeout value into compare registers */
232
+ s->wcvu = timeout >> 32;
233
+ s->wcvl = timeout;
234
+ }
235
+ timer_mod(s->timer, timeout);
236
+ }
237
+}
238
+
239
+static void sbsa_gwdt_rwrite(void *opaque, hwaddr offset, uint64_t data,
240
+ unsigned size) {
241
+ SBSA_GWDTState *s = SBSA_GWDT(opaque);
242
+
243
+ if (offset == SBSA_GWDT_WRR) {
244
+ s->wcs &= ~(SBSA_GWDT_WCS_WS0 | SBSA_GWDT_WCS_WS1);
245
+
246
+ sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH);
247
+ } else {
248
+ qemu_log_mask(LOG_GUEST_ERROR, "bad address in refresh frame write :"
249
+ " 0x%x\n", (int)offset);
250
+ }
251
+}
252
+
253
+static void sbsa_gwdt_write(void *opaque, hwaddr offset, uint64_t data,
254
+ unsigned size) {
255
+ SBSA_GWDTState *s = SBSA_GWDT(opaque);
256
+
257
+ switch (offset) {
258
+ case SBSA_GWDT_WCS:
259
+ s->wcs = data & SBSA_GWDT_WCS_EN;
260
+ qemu_set_irq(s->irq, 0);
261
+ sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH);
262
+ break;
263
+
264
+ case SBSA_GWDT_WOR:
265
+ s->worl = data;
266
+ s->wcs &= ~(SBSA_GWDT_WCS_WS0 | SBSA_GWDT_WCS_WS1);
267
+ qemu_set_irq(s->irq, 0);
268
+ sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH);
269
+ break;
270
+
271
+ case SBSA_GWDT_WORU:
272
+ s->woru = data & SBSA_GWDT_WOR_MASK;
273
+ s->wcs &= ~(SBSA_GWDT_WCS_WS0 | SBSA_GWDT_WCS_WS1);
274
+ qemu_set_irq(s->irq, 0);
275
+ sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH);
276
+ break;
277
+
278
+ case SBSA_GWDT_WCV:
279
+ s->wcvl = data;
280
+ break;
281
+
282
+ case SBSA_GWDT_WCVU:
283
+ s->wcvu = data;
284
+ break;
285
+
286
+ default:
287
+ qemu_log_mask(LOG_GUEST_ERROR, "bad address in control frame write :"
288
+ " 0x%x\n", (int)offset);
289
+ }
290
+ return;
291
+}
292
+
293
+static void wdt_sbsa_gwdt_reset(DeviceState *dev)
294
+{
295
+ SBSA_GWDTState *s = SBSA_GWDT(dev);
296
+
297
+ timer_del(s->timer);
298
+
299
+ s->wcs = 0;
300
+ s->wcvl = 0;
301
+ s->wcvu = 0;
302
+ s->worl = 0;
303
+ s->woru = 0;
304
+ s->id = SBSA_GWDT_ID;
305
+}
306
+
307
+static void sbsa_gwdt_timer_sysinterrupt(void *opaque)
308
+{
309
+ SBSA_GWDTState *s = SBSA_GWDT(opaque);
310
+
311
+ if (!(s->wcs & SBSA_GWDT_WCS_WS0)) {
312
+ s->wcs |= SBSA_GWDT_WCS_WS0;
313
+ sbsa_gwdt_update_timer(s, TIMEOUT_REFRESH);
314
+ qemu_set_irq(s->irq, 1);
315
+ } else {
316
+ s->wcs |= SBSA_GWDT_WCS_WS1;
317
+ qemu_log_mask(CPU_LOG_RESET, "Watchdog timer expired.\n");
318
+ /*
319
+ * Reset the watchdog only if the guest gets notified about
320
+ * expiry. watchdog_perform_action() may temporarily relinquish
321
+ * the BQL; reset before triggering the action to avoid races with
322
+ * sbsa_gwdt instructions.
323
+ */
324
+ switch (get_watchdog_action()) {
325
+ case WATCHDOG_ACTION_DEBUG:
326
+ case WATCHDOG_ACTION_NONE:
327
+ case WATCHDOG_ACTION_PAUSE:
222
+ break;
328
+ break;
329
+ default:
330
+ wdt_sbsa_gwdt_reset(DEVICE(s));
223
+ }
331
+ }
224
+
332
+ watchdog_perform_action();
225
+ cpuobj = object_new(possible_cpus->cpus[n].type);
333
+ }
226
+ object_property_set_int(cpuobj, possible_cpus->cpus[n].arch_id,
334
+}
227
+ "mp-affinity", NULL);
335
+
228
+
336
+static const MemoryRegionOps sbsa_gwdt_rops = {
229
+ cs = CPU(cpuobj);
337
+ .read = sbsa_gwdt_rread,
230
+ cs->cpu_index = n;
338
+ .write = sbsa_gwdt_rwrite,
231
+
339
+ .endianness = DEVICE_LITTLE_ENDIAN,
232
+ numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], DEVICE(cpuobj),
340
+ .valid.min_access_size = 4,
233
+ &error_fatal);
341
+ .valid.max_access_size = 4,
234
+
342
+ .valid.unaligned = false,
235
+ if (object_property_find(cpuobj, "reset-cbar", NULL)) {
236
+ object_property_set_int(cpuobj,
237
+ sbsa_ref_memmap[SBSA_CPUPERIPHS].base,
238
+ "reset-cbar", &error_abort);
239
+ }
240
+
241
+ object_property_set_link(cpuobj, OBJECT(sysmem), "memory",
242
+ &error_abort);
243
+
244
+ object_property_set_link(cpuobj, OBJECT(secure_sysmem),
245
+ "secure-memory", &error_abort);
246
+
247
+ object_property_set_bool(cpuobj, true, "realized", &error_fatal);
248
+ object_unref(cpuobj);
249
+ }
250
+
251
+ memory_region_allocate_system_memory(ram, NULL, "sbsa-ref.ram",
252
+ machine->ram_size);
253
+ memory_region_add_subregion(sysmem, sbsa_ref_memmap[SBSA_MEM].base, ram);
254
+
255
+ sms->bootinfo.ram_size = machine->ram_size;
256
+ sms->bootinfo.kernel_filename = machine->kernel_filename;
257
+ sms->bootinfo.nb_cpus = smp_cpus;
258
+ sms->bootinfo.board_id = -1;
259
+ sms->bootinfo.loader_start = sbsa_ref_memmap[SBSA_MEM].base;
260
+ arm_load_kernel(ARM_CPU(first_cpu), &sms->bootinfo);
261
+}
262
+
263
+static uint64_t sbsa_ref_cpu_mp_affinity(SBSAMachineState *sms, int idx)
264
+{
265
+ uint8_t clustersz = ARM_DEFAULT_CPUS_PER_CLUSTER;
266
+ return arm_cpu_mp_affinity(idx, clustersz);
267
+}
268
+
269
+static const CPUArchIdList *sbsa_ref_possible_cpu_arch_ids(MachineState *ms)
270
+{
271
+ SBSAMachineState *sms = SBSA_MACHINE(ms);
272
+ int n;
273
+
274
+ if (ms->possible_cpus) {
275
+ assert(ms->possible_cpus->len == max_cpus);
276
+ return ms->possible_cpus;
277
+ }
278
+
279
+ ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
280
+ sizeof(CPUArchId) * max_cpus);
281
+ ms->possible_cpus->len = max_cpus;
282
+ for (n = 0; n < ms->possible_cpus->len; n++) {
283
+ ms->possible_cpus->cpus[n].type = ms->cpu_type;
284
+ ms->possible_cpus->cpus[n].arch_id =
285
+ sbsa_ref_cpu_mp_affinity(sms, n);
286
+ ms->possible_cpus->cpus[n].props.has_thread_id = true;
287
+ ms->possible_cpus->cpus[n].props.thread_id = n;
288
+ }
289
+ return ms->possible_cpus;
290
+}
291
+
292
+static CpuInstanceProperties
293
+sbsa_ref_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
294
+{
295
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
296
+ const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms);
297
+
298
+ assert(cpu_index < possible_cpus->len);
299
+ return possible_cpus->cpus[cpu_index].props;
300
+}
301
+
302
+static int64_t
303
+sbsa_ref_get_default_cpu_node_id(const MachineState *ms, int idx)
304
+{
305
+ return idx % nb_numa_nodes;
306
+}
307
+
308
+static void sbsa_ref_class_init(ObjectClass *oc, void *data)
309
+{
310
+ MachineClass *mc = MACHINE_CLASS(oc);
311
+
312
+ mc->init = sbsa_ref_init;
313
+ mc->desc = "QEMU 'SBSA Reference' ARM Virtual Machine";
314
+ mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a57");
315
+ mc->max_cpus = 512;
316
+ mc->pci_allow_0_address = true;
317
+ mc->minimum_page_bits = 12;
318
+ mc->block_default_type = IF_IDE;
319
+ mc->no_cdrom = 1;
320
+ mc->default_ram_size = 1 * GiB;
321
+ mc->default_cpus = 4;
322
+ mc->possible_cpu_arch_ids = sbsa_ref_possible_cpu_arch_ids;
323
+ mc->cpu_index_to_instance_props = sbsa_ref_cpu_index_to_props;
324
+ mc->get_default_cpu_node_id = sbsa_ref_get_default_cpu_node_id;
325
+}
326
+
327
+static const TypeInfo sbsa_ref_info = {
328
+ .name = TYPE_SBSA_MACHINE,
329
+ .parent = TYPE_MACHINE,
330
+ .class_init = sbsa_ref_class_init,
331
+ .instance_size = sizeof(SBSAMachineState),
332
+};
343
+};
333
+
344
+
334
+static void sbsa_ref_machine_init(void)
345
+static const MemoryRegionOps sbsa_gwdt_ops = {
335
+{
346
+ .read = sbsa_gwdt_read,
336
+ type_register_static(&sbsa_ref_info);
347
+ .write = sbsa_gwdt_write,
337
+}
348
+ .endianness = DEVICE_LITTLE_ENDIAN,
338
+
349
+ .valid.min_access_size = 4,
339
+type_init(sbsa_ref_machine_init);
350
+ .valid.max_access_size = 4,
340
diff --git a/MAINTAINERS b/MAINTAINERS
351
+ .valid.unaligned = false,
341
index XXXXXXX..XXXXXXX 100644
352
+};
342
--- a/MAINTAINERS
353
+
343
+++ b/MAINTAINERS
354
+static void wdt_sbsa_gwdt_realize(DeviceState *dev, Error **errp)
344
@@ -XXX,XX +XXX,XX @@ F: include/hw/arm/fsl-imx6.h
355
+{
345
F: include/hw/misc/imx6_*.h
356
+ SBSA_GWDTState *s = SBSA_GWDT(dev);
346
F: include/hw/ssi/imx_spi.h
357
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
347
358
+
348
+SBSA-REF
359
+ memory_region_init_io(&s->rmmio, OBJECT(dev),
349
+M: Radoslaw Biernacki <radoslaw.biernacki@linaro.org>
360
+ &sbsa_gwdt_rops, s,
350
+M: Peter Maydell <peter.maydell@linaro.org>
361
+ "sbsa_gwdt.refresh",
351
+R: Leif Lindholm <leif.lindholm@linaro.org>
362
+ SBSA_GWDT_RMMIO_SIZE);
352
+L: qemu-arm@nongnu.org
363
+
353
+S: Maintained
364
+ memory_region_init_io(&s->cmmio, OBJECT(dev),
354
+F: hw/arm/sbsa-ref.c
365
+ &sbsa_gwdt_ops, s,
355
+
366
+ "sbsa_gwdt.control",
356
Sharp SL-5500 (Collie) PDA
367
+ SBSA_GWDT_CMMIO_SIZE);
357
M: Peter Maydell <peter.maydell@linaro.org>
368
+
358
L: qemu-arm@nongnu.org
369
+ sysbus_init_mmio(sbd, &s->rmmio);
359
diff --git a/default-configs/aarch64-softmmu.mak b/default-configs/aarch64-softmmu.mak
370
+ sysbus_init_mmio(sbd, &s->cmmio);
360
index XXXXXXX..XXXXXXX 100644
371
+
361
--- a/default-configs/aarch64-softmmu.mak
372
+ sysbus_init_irq(sbd, &s->irq);
362
+++ b/default-configs/aarch64-softmmu.mak
373
+
363
@@ -XXX,XX +XXX,XX @@ include arm-softmmu.mak
374
+ s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sbsa_gwdt_timer_sysinterrupt,
364
375
+ dev);
365
CONFIG_XLNX_ZYNQMP_ARM=y
376
+}
366
CONFIG_XLNX_VERSAL=y
377
+
367
+CONFIG_SBSA_REF=y
378
+static void wdt_sbsa_gwdt_class_init(ObjectClass *klass, void *data)
379
+{
380
+ DeviceClass *dc = DEVICE_CLASS(klass);
381
+
382
+ dc->realize = wdt_sbsa_gwdt_realize;
383
+ dc->reset = wdt_sbsa_gwdt_reset;
384
+ dc->hotpluggable = false;
385
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
386
+ dc->vmsd = &vmstate_sbsa_gwdt;
387
+}
388
+
389
+static const TypeInfo wdt_sbsa_gwdt_info = {
390
+ .class_init = wdt_sbsa_gwdt_class_init,
391
+ .parent = TYPE_SYS_BUS_DEVICE,
392
+ .name = TYPE_WDT_SBSA,
393
+ .instance_size = sizeof(SBSA_GWDTState),
394
+};
395
+
396
+static void wdt_sbsa_gwdt_register_types(void)
397
+{
398
+ watchdog_add_model(&model);
399
+ type_register_static(&wdt_sbsa_gwdt_info);
400
+}
401
+
402
+type_init(wdt_sbsa_gwdt_register_types)
368
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
403
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
369
index XXXXXXX..XXXXXXX 100644
404
index XXXXXXX..XXXXXXX 100644
370
--- a/hw/arm/Kconfig
405
--- a/hw/arm/Kconfig
371
+++ b/hw/arm/Kconfig
406
+++ b/hw/arm/Kconfig
372
@@ -XXX,XX +XXX,XX @@ config REALVIEW
407
@@ -XXX,XX +XXX,XX @@ config SBSA_REF
373
select DS1338 # I2C RTC+NVRAM
408
select PL031 # RTC
374
select USB_OHCI
409
select PL061 # GPIO
375
410
select USB_EHCI_SYSBUS
376
+config SBSA_REF
411
+ select WDT_SBSA
377
+ bool
412
378
+ imply PCI_DEVICES
379
+ select AHCI
380
+ select ARM_SMMUV3
381
+ select GPIO_KEY
382
+ select PCI_EXPRESS
383
+ select PCI_EXPRESS_GENERIC_BRIDGE
384
+ select PFLASH_CFI01
385
+ select PL011 # UART
386
+ select PL031 # RTC
387
+ select PL061 # GPIO
388
+ select USB_EHCI_SYSBUS
389
+
390
config SABRELITE
413
config SABRELITE
391
bool
414
bool
392
select FSL_IMX6
415
diff --git a/hw/watchdog/Kconfig b/hw/watchdog/Kconfig
416
index XXXXXXX..XXXXXXX 100644
417
--- a/hw/watchdog/Kconfig
418
+++ b/hw/watchdog/Kconfig
419
@@ -XXX,XX +XXX,XX @@ config WDT_DIAG288
420
421
config WDT_IMX2
422
bool
423
+
424
+config WDT_SBSA
425
+ bool
426
diff --git a/hw/watchdog/meson.build b/hw/watchdog/meson.build
427
index XXXXXXX..XXXXXXX 100644
428
--- a/hw/watchdog/meson.build
429
+++ b/hw/watchdog/meson.build
430
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_WDT_IB700', if_true: files('wdt_ib700.c'))
431
softmmu_ss.add(when: 'CONFIG_WDT_DIAG288', if_true: files('wdt_diag288.c'))
432
softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('wdt_aspeed.c'))
433
softmmu_ss.add(when: 'CONFIG_WDT_IMX2', if_true: files('wdt_imx2.c'))
434
+softmmu_ss.add(when: 'CONFIG_WDT_SBSA', if_true: files('sbsa_gwdt.c'))
393
--
435
--
394
2.20.1
436
2.20.1
395
437
396
438
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Shashi Mallela <shashi.mallela@linaro.org>
2
2
3
The vfp_set_fpscr() helper contains code specific to the host
3
Included the newly implemented SBSA generic watchdog device model into
4
floating point implementation (here the SoftFloat library).
4
SBSA platform
5
Extract this code to vfp_set_fpscr_from_host().
6
5
7
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
6
Signed-off-by: Shashi Mallela <shashi.mallela@linaro.org>
8
Message-id: 20190701132516.26392-17-philmd@redhat.com
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Message-id: 20201027015927.29495-3-shashi.mallela@linaro.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
10
---
12
target/arm/vfp_helper.c | 19 +++++++++++++------
11
hw/arm/sbsa-ref.c | 23 +++++++++++++++++++++++
13
1 file changed, 13 insertions(+), 6 deletions(-)
12
1 file changed, 23 insertions(+)
14
13
15
diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c
14
diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
16
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/vfp_helper.c
16
--- a/hw/arm/sbsa-ref.c
18
+++ b/target/arm/vfp_helper.c
17
+++ b/hw/arm/sbsa-ref.c
19
@@ -XXX,XX +XXX,XX @@ static inline int vfp_exceptbits_to_host(int target_bits)
18
@@ -XXX,XX +XXX,XX @@
20
return host_bits;
19
#include "hw/qdev-properties.h"
20
#include "hw/usb.h"
21
#include "hw/char/pl011.h"
22
+#include "hw/watchdog/sbsa_gwdt.h"
23
#include "net/net.h"
24
#include "qom/object.h"
25
26
@@ -XXX,XX +XXX,XX @@ enum {
27
SBSA_GIC_DIST,
28
SBSA_GIC_REDIST,
29
SBSA_SECURE_EC,
30
+ SBSA_GWDT,
31
+ SBSA_GWDT_REFRESH,
32
+ SBSA_GWDT_CONTROL,
33
SBSA_SMMU,
34
SBSA_UART,
35
SBSA_RTC,
36
@@ -XXX,XX +XXX,XX @@ static const MemMapEntry sbsa_ref_memmap[] = {
37
[SBSA_GIC_DIST] = { 0x40060000, 0x00010000 },
38
[SBSA_GIC_REDIST] = { 0x40080000, 0x04000000 },
39
[SBSA_SECURE_EC] = { 0x50000000, 0x00001000 },
40
+ [SBSA_GWDT_REFRESH] = { 0x50010000, 0x00001000 },
41
+ [SBSA_GWDT_CONTROL] = { 0x50011000, 0x00001000 },
42
[SBSA_UART] = { 0x60000000, 0x00001000 },
43
[SBSA_RTC] = { 0x60010000, 0x00001000 },
44
[SBSA_GPIO] = { 0x60020000, 0x00001000 },
45
@@ -XXX,XX +XXX,XX @@ static const int sbsa_ref_irqmap[] = {
46
[SBSA_AHCI] = 10,
47
[SBSA_EHCI] = 11,
48
[SBSA_SMMU] = 12, /* ... to 15 */
49
+ [SBSA_GWDT] = 16,
50
};
51
52
static uint64_t sbsa_ref_cpu_mp_affinity(SBSAMachineState *sms, int idx)
53
@@ -XXX,XX +XXX,XX @@ static void create_rtc(const SBSAMachineState *sms)
54
sysbus_create_simple("pl031", base, qdev_get_gpio_in(sms->gic, irq));
21
}
55
}
22
56
23
+static uint32_t vfp_get_fpscr_from_host(CPUARMState *env)
57
+static void create_wdt(const SBSAMachineState *sms)
24
+{
58
+{
25
+ uint32_t i;
59
+ hwaddr rbase = sbsa_ref_memmap[SBSA_GWDT_REFRESH].base;
60
+ hwaddr cbase = sbsa_ref_memmap[SBSA_GWDT_CONTROL].base;
61
+ DeviceState *dev = qdev_new(TYPE_WDT_SBSA);
62
+ SysBusDevice *s = SYS_BUS_DEVICE(dev);
63
+ int irq = sbsa_ref_irqmap[SBSA_GWDT];
26
+
64
+
27
+ i = get_float_exception_flags(&env->vfp.fp_status);
65
+ sysbus_realize_and_unref(s, &error_fatal);
28
+ i |= get_float_exception_flags(&env->vfp.standard_fp_status);
66
+ sysbus_mmio_map(s, 0, rbase);
29
+ /* FZ16 does not generate an input denormal exception. */
67
+ sysbus_mmio_map(s, 1, cbase);
30
+ i |= (get_float_exception_flags(&env->vfp.fp_status_f16)
68
+ sysbus_connect_irq(s, 0, qdev_get_gpio_in(sms->gic, irq));
31
+ & ~float_flag_input_denormal);
32
+ return vfp_exceptbits_from_host(i);
33
+}
69
+}
34
+
70
+
35
static void vfp_set_fpscr_to_host(CPUARMState *env, uint32_t val)
71
static DeviceState *gpio_key_dev;
72
static void sbsa_ref_powerdown_req(Notifier *n, void *opaque)
36
{
73
{
37
int i;
74
@@ -XXX,XX +XXX,XX @@ static void sbsa_ref_init(MachineState *machine)
38
@@ -XXX,XX +XXX,XX @@ uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env)
75
39
| (env->vfp.vec_len << 16)
76
create_rtc(sms);
40
| (env->vfp.vec_stride << 20);
77
41
78
+ create_wdt(sms);
42
- i = get_float_exception_flags(&env->vfp.fp_status);
79
+
43
- i |= get_float_exception_flags(&env->vfp.standard_fp_status);
80
create_gpio(sms);
44
- /* FZ16 does not generate an input denormal exception. */
81
45
- i |= (get_float_exception_flags(&env->vfp.fp_status_f16)
82
create_ahci(sms);
46
- & ~float_flag_input_denormal);
47
- fpscr |= vfp_exceptbits_from_host(i);
48
+ fpscr |= vfp_get_fpscr_from_host(env);
49
50
i = env->vfp.qc[0] | env->vfp.qc[1] | env->vfp.qc[2] | env->vfp.qc[3];
51
fpscr |= i ? FPCR_QC : 0;
52
--
83
--
53
2.20.1
84
2.20.1
54
85
55
86
diff view generated by jsdifflib
1
From: Andrew Jeffery <andrew@aj.id.au>
1
In ptimer_reload(), we call the callback function provided by the
2
timer device that is using the ptimer. This callback might disable
3
the ptimer. The code mostly handles this correctly, except that
4
we'll still print the warning about "Timer with delta zero,
5
disabling" if the now-disabled timer happened to be set such that it
6
would fire again immediately if it were enabled (eg because the
7
limit/reload value is zero).
2
8
3
The legacy interface only supported up to 32 IRQs, which became
9
Suppress the spurious warning message and the unnecessary
4
restrictive around the AST2400 generation. QEMU support for the SoCs
10
repeat-deletion of the underlying timer in this case.
5
started with the AST2400 along with an effort to reimplement and
6
upstream drivers for Linux, so up until this point the consumers of the
7
QEMU ASPEED support only required the 64 IRQ register interface.
8
11
9
In an effort to support older BMC firmware, add support for the 32 IRQ
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
interface.
13
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
14
Message-id: 20201015151829.14656-2-peter.maydell@linaro.org
15
---
16
hw/core/ptimer.c | 4 ++++
17
1 file changed, 4 insertions(+)
11
18
12
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
19
diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c
13
Signed-off-by: Cédric Le Goater <clg@kaod.org>
14
Reviewed-by: Joel Stanley <joel@jms.id.au>
15
Message-id: 20190618165311.27066-22-clg@kaod.org
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
---
18
hw/intc/aspeed_vic.c | 105 ++++++++++++++++++++++++++-----------------
19
1 file changed, 63 insertions(+), 42 deletions(-)
20
21
diff --git a/hw/intc/aspeed_vic.c b/hw/intc/aspeed_vic.c
22
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
23
--- a/hw/intc/aspeed_vic.c
21
--- a/hw/core/ptimer.c
24
+++ b/hw/intc/aspeed_vic.c
22
+++ b/hw/core/ptimer.c
25
@@ -XXX,XX +XXX,XX @@ static void aspeed_vic_set_irq(void *opaque, int irq, int level)
23
@@ -XXX,XX +XXX,XX @@ static void ptimer_reload(ptimer_state *s, int delta_adjust)
26
27
static uint64_t aspeed_vic_read(void *opaque, hwaddr offset, unsigned size)
28
{
29
- uint64_t val;
30
- const bool high = !!(offset & 0x4);
31
- hwaddr n_offset = (offset & ~0x4);
32
AspeedVICState *s = (AspeedVICState *)opaque;
33
+ hwaddr n_offset;
34
+ uint64_t val;
35
+ bool high;
36
37
if (offset < AVIC_NEW_BASE_OFFSET) {
38
- qemu_log_mask(LOG_UNIMP, "%s: Ignoring read from legacy registers "
39
- "at 0x%" HWADDR_PRIx "[%u]\n", __func__, offset, size);
40
- return 0;
41
+ high = false;
42
+ n_offset = offset;
43
+ } else {
44
+ high = !!(offset & 0x4);
45
+ n_offset = (offset & ~0x4);
46
}
24
}
47
25
48
- n_offset -= AVIC_NEW_BASE_OFFSET;
26
if (delta == 0) {
49
-
27
+ if (s->enabled == 0) {
50
switch (n_offset) {
28
+ /* trigger callback disabled the timer already */
51
- case 0x0: /* IRQ Status */
29
+ return;
52
+ case 0x80: /* IRQ Status */
30
+ }
53
+ case 0x00:
31
if (!qtest_enabled()) {
54
val = s->raw & ~s->select & s->enable;
32
fprintf(stderr, "Timer with delta zero, disabling\n");
55
break;
56
- case 0x08: /* FIQ Status */
57
+ case 0x88: /* FIQ Status */
58
+ case 0x04:
59
val = s->raw & s->select & s->enable;
60
break;
61
- case 0x10: /* Raw Interrupt Status */
62
+ case 0x90: /* Raw Interrupt Status */
63
+ case 0x08:
64
val = s->raw;
65
break;
66
- case 0x18: /* Interrupt Selection */
67
+ case 0x98: /* Interrupt Selection */
68
+ case 0x0c:
69
val = s->select;
70
break;
71
- case 0x20: /* Interrupt Enable */
72
+ case 0xa0: /* Interrupt Enable */
73
+ case 0x10:
74
val = s->enable;
75
break;
76
- case 0x30: /* Software Interrupt */
77
+ case 0xb0: /* Software Interrupt */
78
+ case 0x18:
79
val = s->trigger;
80
break;
81
- case 0x40: /* Interrupt Sensitivity */
82
+ case 0xc0: /* Interrupt Sensitivity */
83
+ case 0x24:
84
val = s->sense;
85
break;
86
- case 0x48: /* Interrupt Both Edge Trigger Control */
87
+ case 0xc8: /* Interrupt Both Edge Trigger Control */
88
+ case 0x28:
89
val = s->dual_edge;
90
break;
91
- case 0x50: /* Interrupt Event */
92
+ case 0xd0: /* Interrupt Event */
93
+ case 0x2c:
94
val = s->event;
95
break;
96
- case 0x60: /* Edge Triggered Interrupt Status */
97
+ case 0xe0: /* Edge Triggered Interrupt Status */
98
val = s->raw & ~s->sense;
99
break;
100
/* Illegal */
101
- case 0x28: /* Interrupt Enable Clear */
102
- case 0x38: /* Software Interrupt Clear */
103
- case 0x58: /* Edge Triggered Interrupt Clear */
104
+ case 0xa8: /* Interrupt Enable Clear */
105
+ case 0xb8: /* Software Interrupt Clear */
106
+ case 0xd8: /* Edge Triggered Interrupt Clear */
107
qemu_log_mask(LOG_GUEST_ERROR,
108
"%s: Read of write-only register with offset 0x%"
109
HWADDR_PRIx "\n", __func__, offset);
110
@@ -XXX,XX +XXX,XX @@ static uint64_t aspeed_vic_read(void *opaque, hwaddr offset, unsigned size)
111
}
112
if (high) {
113
val = extract64(val, 32, 19);
114
+ } else {
115
+ val = extract64(val, 0, 32);
116
}
117
trace_aspeed_vic_read(offset, size, val);
118
return val;
119
@@ -XXX,XX +XXX,XX @@ static uint64_t aspeed_vic_read(void *opaque, hwaddr offset, unsigned size)
120
static void aspeed_vic_write(void *opaque, hwaddr offset, uint64_t data,
121
unsigned size)
122
{
123
- const bool high = !!(offset & 0x4);
124
- hwaddr n_offset = (offset & ~0x4);
125
AspeedVICState *s = (AspeedVICState *)opaque;
126
+ hwaddr n_offset;
127
+ bool high;
128
129
if (offset < AVIC_NEW_BASE_OFFSET) {
130
- qemu_log_mask(LOG_UNIMP,
131
- "%s: Ignoring write to legacy registers at 0x%"
132
- HWADDR_PRIx "[%u] <- 0x%" PRIx64 "\n", __func__, offset,
133
- size, data);
134
- return;
135
+ high = false;
136
+ n_offset = offset;
137
+ } else {
138
+ high = !!(offset & 0x4);
139
+ n_offset = (offset & ~0x4);
140
}
141
142
- n_offset -= AVIC_NEW_BASE_OFFSET;
143
trace_aspeed_vic_write(offset, size, data);
144
145
/* Given we have members using separate enable/clear registers, deposit64()
146
@@ -XXX,XX +XXX,XX @@ static void aspeed_vic_write(void *opaque, hwaddr offset, uint64_t data,
147
}
148
149
switch (n_offset) {
150
- case 0x18: /* Interrupt Selection */
151
+ case 0x98: /* Interrupt Selection */
152
+ case 0x0c:
153
/* Register has deposit64() semantics - overwrite requested 32 bits */
154
if (high) {
155
s->select &= AVIC_L_MASK;
156
@@ -XXX,XX +XXX,XX @@ static void aspeed_vic_write(void *opaque, hwaddr offset, uint64_t data,
157
}
33
}
158
s->select |= data;
159
break;
160
- case 0x20: /* Interrupt Enable */
161
+ case 0xa0: /* Interrupt Enable */
162
+ case 0x10:
163
s->enable |= data;
164
break;
165
- case 0x28: /* Interrupt Enable Clear */
166
+ case 0xa8: /* Interrupt Enable Clear */
167
+ case 0x14:
168
s->enable &= ~data;
169
break;
170
- case 0x30: /* Software Interrupt */
171
+ case 0xb0: /* Software Interrupt */
172
+ case 0x18:
173
qemu_log_mask(LOG_UNIMP, "%s: Software interrupts unavailable. "
174
"IRQs requested: 0x%016" PRIx64 "\n", __func__, data);
175
break;
176
- case 0x38: /* Software Interrupt Clear */
177
+ case 0xb8: /* Software Interrupt Clear */
178
+ case 0x1c:
179
qemu_log_mask(LOG_UNIMP, "%s: Software interrupts unavailable. "
180
"IRQs to be cleared: 0x%016" PRIx64 "\n", __func__, data);
181
break;
182
- case 0x50: /* Interrupt Event */
183
+ case 0xd0: /* Interrupt Event */
184
/* Register has deposit64() semantics - overwrite the top four valid
185
* IRQ bits, as only the top four IRQs (GPIOs) can change their event
186
* type */
187
@@ -XXX,XX +XXX,XX @@ static void aspeed_vic_write(void *opaque, hwaddr offset, uint64_t data,
188
"Ignoring invalid write to interrupt event register");
189
}
190
break;
191
- case 0x58: /* Edge Triggered Interrupt Clear */
192
+ case 0xd8: /* Edge Triggered Interrupt Clear */
193
+ case 0x38:
194
s->raw &= ~(data & ~s->sense);
195
break;
196
- case 0x00: /* IRQ Status */
197
- case 0x08: /* FIQ Status */
198
- case 0x10: /* Raw Interrupt Status */
199
- case 0x40: /* Interrupt Sensitivity */
200
- case 0x48: /* Interrupt Both Edge Trigger Control */
201
- case 0x60: /* Edge Triggered Interrupt Status */
202
+ case 0x80: /* IRQ Status */
203
+ case 0x00:
204
+ case 0x88: /* FIQ Status */
205
+ case 0x04:
206
+ case 0x90: /* Raw Interrupt Status */
207
+ case 0x08:
208
+ case 0xc0: /* Interrupt Sensitivity */
209
+ case 0x24:
210
+ case 0xc8: /* Interrupt Both Edge Trigger Control */
211
+ case 0x28:
212
+ case 0xe0: /* Edge Triggered Interrupt Status */
213
qemu_log_mask(LOG_GUEST_ERROR,
214
"%s: Write of read-only register with offset 0x%"
215
HWADDR_PRIx "\n", __func__, offset);
216
--
34
--
217
2.20.1
35
2.20.1
218
36
219
37
diff view generated by jsdifflib
1
From: Andrey Smirnov <andrew.smirnov@gmail.com>
1
The armv7m systick timer is a 24-bit decrementing, wrap-on-zero,
2
2
clear-on-write counter. Our current implementation has various
3
Expression to calculate update_msi_mapping in code handling writes to
3
bugs and dubious workarounds in it (for instance see
4
DESIGNWARE_PCIE_MSI_INTR0_ENABLE is missing an ! operator and should
4
https://bugs.launchpad.net/qemu/+bug/1872237).
5
be:
5
6
6
We have an implementation of a simple decrementing counter
7
!!root->msi.intr[0].enable ^ !!val;
7
and we put a lot of effort into making sure it handles the
8
8
interesting corner cases (like "spend a cycle at 0 before
9
so that MSI mapping is updated when enabled transitions from either
9
reloading") -- ptimer.
10
"none" -> "any" or "any" -> "none". Since that register shouldn't be
10
11
written to very often, change the code to update MSI mapping
11
Rewrite the systick timer to use a ptimer rather than
12
unconditionally instead of trying to fix the update_msi_mapping logic.
12
a raw QEMU timer.
13
13
14
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
14
Unfortunately this is a migration compatibility break,
15
Cc: Peter Maydell <peter.maydell@linaro.org>
15
which will affect all M-profile boards.
16
Cc: Michael S. Tsirkin <mst@redhat.com>
16
17
Cc: qemu-devel@nongnu.org
17
Among other bugs, this fixes
18
Cc: qemu-arm@nongnu.org
18
https://bugs.launchpad.net/qemu/+bug/1872237 :
19
Acked-by: Michael S. Tsirkin <mst@redhat.com>
19
now writes to SYST_CVR when the timer is enabled correctly
20
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
20
do nothing; when the timer is enabled via SYST_CSR.ENABLE,
21
the ptimer code will (because of POLICY_NO_IMMEDIATE_RELOAD)
22
arrange that after one timer tick the counter is reloaded
23
from SYST_RVR and then counts down from there, as the
24
architecture requires.
25
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
26
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
27
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
28
Message-id: 20201015151829.14656-3-peter.maydell@linaro.org
22
---
29
---
23
hw/pci-host/designware.c | 10 ++--------
30
include/hw/timer/armv7m_systick.h | 3 +-
24
1 file changed, 2 insertions(+), 8 deletions(-)
31
hw/timer/armv7m_systick.c | 124 +++++++++++++-----------------
25
32
2 files changed, 54 insertions(+), 73 deletions(-)
26
diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c
33
34
diff --git a/include/hw/timer/armv7m_systick.h b/include/hw/timer/armv7m_systick.h
27
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
28
--- a/hw/pci-host/designware.c
36
--- a/include/hw/timer/armv7m_systick.h
29
+++ b/hw/pci-host/designware.c
37
+++ b/include/hw/timer/armv7m_systick.h
30
@@ -XXX,XX +XXX,XX @@ static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address,
38
@@ -XXX,XX +XXX,XX @@
31
root->msi.base |= (uint64_t)val << 32;
39
32
break;
40
#include "hw/sysbus.h"
33
41
#include "qom/object.h"
34
- case DESIGNWARE_PCIE_MSI_INTR0_ENABLE: {
42
+#include "hw/ptimer.h"
35
- const bool update_msi_mapping = !root->msi.intr[0].enable ^ !!val;
43
36
-
44
#define TYPE_SYSTICK "armv7m_systick"
37
+ case DESIGNWARE_PCIE_MSI_INTR0_ENABLE:
45
38
root->msi.intr[0].enable = val;
46
@@ -XXX,XX +XXX,XX @@ struct SysTickState {
39
-
47
uint32_t control;
40
- if (update_msi_mapping) {
48
uint32_t reload;
41
- designware_pcie_root_update_msi_mapping(root);
49
int64_t tick;
50
- QEMUTimer *timer;
51
+ ptimer_state *ptimer;
52
MemoryRegion iomem;
53
qemu_irq irq;
54
};
55
diff --git a/hw/timer/armv7m_systick.c b/hw/timer/armv7m_systick.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/hw/timer/armv7m_systick.c
58
+++ b/hw/timer/armv7m_systick.c
59
@@ -XXX,XX +XXX,XX @@ static inline int64_t systick_scale(SysTickState *s)
60
}
61
}
62
63
-static void systick_reload(SysTickState *s, int reset)
64
-{
65
- /* The Cortex-M3 Devices Generic User Guide says that "When the
66
- * ENABLE bit is set to 1, the counter loads the RELOAD value from the
67
- * SYST RVR register and then counts down". So, we need to check the
68
- * ENABLE bit before reloading the value.
69
- */
70
- trace_systick_reload();
71
-
72
- if ((s->control & SYSTICK_ENABLE) == 0) {
73
- return;
74
- }
75
-
76
- if (reset) {
77
- s->tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
78
- }
79
- s->tick += (s->reload + 1) * systick_scale(s);
80
- timer_mod(s->timer, s->tick);
81
-}
82
-
83
static void systick_timer_tick(void *opaque)
84
{
85
SysTickState *s = (SysTickState *)opaque;
86
@@ -XXX,XX +XXX,XX @@ static void systick_timer_tick(void *opaque)
87
/* Tell the NVIC to pend the SysTick exception */
88
qemu_irq_pulse(s->irq);
89
}
90
- if (s->reload == 0) {
91
- s->control &= ~SYSTICK_ENABLE;
92
- } else {
93
- systick_reload(s, 0);
94
+ if (ptimer_get_limit(s->ptimer) == 0) {
95
+ /*
96
+ * Timer expiry with SYST_RVR zero disables the timer
97
+ * (but doesn't clear SYST_CSR.ENABLE)
98
+ */
99
+ ptimer_stop(s->ptimer);
100
}
101
}
102
103
@@ -XXX,XX +XXX,XX @@ static MemTxResult systick_read(void *opaque, hwaddr addr, uint64_t *data,
104
s->control &= ~SYSTICK_COUNTFLAG;
105
break;
106
case 0x4: /* SysTick Reload Value. */
107
- val = s->reload;
108
+ val = ptimer_get_limit(s->ptimer);
109
break;
110
case 0x8: /* SysTick Current Value. */
111
- {
112
- int64_t t;
113
-
114
- if ((s->control & SYSTICK_ENABLE) == 0) {
115
- val = 0;
116
- break;
42
- }
117
- }
43
+ designware_pcie_root_update_msi_mapping(root);
118
- t = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
119
- if (t >= s->tick) {
120
- val = 0;
121
- break;
122
- }
123
- val = ((s->tick - (t + 1)) / systick_scale(s)) + 1;
124
- /* The interrupt in triggered when the timer reaches zero.
125
- However the counter is not reloaded until the next clock
126
- tick. This is a hack to return zero during the first tick. */
127
- if (val > s->reload) {
128
- val = 0;
129
- }
130
+ val = ptimer_get_count(s->ptimer);
44
break;
131
break;
45
- }
132
- }
46
133
case 0xc: /* SysTick Calibration Value. */
47
case DESIGNWARE_PCIE_MSI_INTR0_MASK:
134
val = 10000;
48
root->msi.intr[0].mask = val;
135
break;
136
@@ -XXX,XX +XXX,XX @@ static MemTxResult systick_write(void *opaque, hwaddr addr,
137
switch (addr) {
138
case 0x0: /* SysTick Control and Status. */
139
{
140
- uint32_t oldval = s->control;
141
+ uint32_t oldval;
142
143
+ ptimer_transaction_begin(s->ptimer);
144
+ oldval = s->control;
145
s->control &= 0xfffffff8;
146
s->control |= value & 7;
147
+
148
if ((oldval ^ value) & SYSTICK_ENABLE) {
149
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
150
if (value & SYSTICK_ENABLE) {
151
- if (s->tick) {
152
- s->tick += now;
153
- timer_mod(s->timer, s->tick);
154
- } else {
155
- systick_reload(s, 1);
156
- }
157
+ /*
158
+ * Always reload the period in case board code has
159
+ * changed system_clock_scale. If we ever replace that
160
+ * global with a more sensible API then we might be able
161
+ * to set the period only when it actually changes.
162
+ */
163
+ ptimer_set_period(s->ptimer, systick_scale(s));
164
+ ptimer_run(s->ptimer, 0);
165
} else {
166
- timer_del(s->timer);
167
- s->tick -= now;
168
- if (s->tick < 0) {
169
- s->tick = 0;
170
- }
171
+ ptimer_stop(s->ptimer);
172
}
173
} else if ((oldval ^ value) & SYSTICK_CLKSOURCE) {
174
- /* This is a hack. Force the timer to be reloaded
175
- when the reference clock is changed. */
176
- systick_reload(s, 1);
177
+ ptimer_set_period(s->ptimer, systick_scale(s));
178
}
179
+ ptimer_transaction_commit(s->ptimer);
180
break;
181
}
182
case 0x4: /* SysTick Reload Value. */
183
- s->reload = value;
184
+ ptimer_transaction_begin(s->ptimer);
185
+ ptimer_set_limit(s->ptimer, value & 0xffffff, 0);
186
+ ptimer_transaction_commit(s->ptimer);
187
break;
188
- case 0x8: /* SysTick Current Value. Writes reload the timer. */
189
- systick_reload(s, 1);
190
+ case 0x8: /* SysTick Current Value. */
191
+ /*
192
+ * Writing any value clears SYST_CVR to zero and clears
193
+ * SYST_CSR.COUNTFLAG. The counter will then reload from SYST_RVR
194
+ * on the next clock edge unless SYST_RVR is zero.
195
+ */
196
+ ptimer_transaction_begin(s->ptimer);
197
+ if (ptimer_get_limit(s->ptimer) == 0) {
198
+ ptimer_stop(s->ptimer);
199
+ }
200
+ ptimer_set_count(s->ptimer, 0);
201
s->control &= ~SYSTICK_COUNTFLAG;
202
+ ptimer_transaction_commit(s->ptimer);
203
break;
204
default:
205
qemu_log_mask(LOG_GUEST_ERROR,
206
@@ -XXX,XX +XXX,XX @@ static void systick_reset(DeviceState *dev)
207
*/
208
assert(system_clock_scale != 0);
209
210
+ ptimer_transaction_begin(s->ptimer);
211
s->control = 0;
212
- s->reload = 0;
213
- s->tick = 0;
214
- timer_del(s->timer);
215
+ ptimer_stop(s->ptimer);
216
+ ptimer_set_count(s->ptimer, 0);
217
+ ptimer_set_limit(s->ptimer, 0, 0);
218
+ ptimer_set_period(s->ptimer, systick_scale(s));
219
+ ptimer_transaction_commit(s->ptimer);
220
}
221
222
static void systick_instance_init(Object *obj)
223
@@ -XXX,XX +XXX,XX @@ static void systick_instance_init(Object *obj)
224
static void systick_realize(DeviceState *dev, Error **errp)
225
{
226
SysTickState *s = SYSTICK(dev);
227
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, systick_timer_tick, s);
228
+ s->ptimer = ptimer_init(systick_timer_tick, s,
229
+ PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD |
230
+ PTIMER_POLICY_NO_COUNTER_ROUND_DOWN |
231
+ PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
232
+ PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT);
233
}
234
235
static const VMStateDescription vmstate_systick = {
236
.name = "armv7m_systick",
237
- .version_id = 1,
238
- .minimum_version_id = 1,
239
+ .version_id = 2,
240
+ .minimum_version_id = 2,
241
.fields = (VMStateField[]) {
242
VMSTATE_UINT32(control, SysTickState),
243
- VMSTATE_UINT32(reload, SysTickState),
244
VMSTATE_INT64(tick, SysTickState),
245
- VMSTATE_TIMER_PTR(timer, SysTickState),
246
+ VMSTATE_PTIMER(ptimer, SysTickState),
247
VMSTATE_END_OF_LIST()
248
}
249
};
49
--
250
--
50
2.20.1
251
2.20.1
51
252
52
253
diff view generated by jsdifflib