1
Arm changes for before softfreeze: mostly my PL061/GPIO patches,
1
The following changes since commit 8f6330a807f2642dc2a3cdf33347aa28a4c00a87:
2
but also a new M-profile board and various other things.
3
2
4
thanks
3
Merge tag 'pull-maintainer-updates-060324-1' of https://gitlab.com/stsquad/qemu into staging (2024-03-06 16:56:20 +0000)
5
-- PMM
6
7
The following changes since commit 05de778b5b8ab0b402996769117b88c7ea5c7c61:
8
9
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging (2021-07-09 14:30:01 +0100)
10
4
11
are available in the Git repository at:
5
are available in the Git repository at:
12
6
13
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20210709
7
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20240308
14
8
15
for you to fetch changes up to 05449abb1d4c5f0c69ceb3d8d03cbc75de39b646:
9
for you to fetch changes up to bbf6c6dbead82292a20951eb1204442a6b838de9:
16
10
17
hw/intc: Improve formatting of MEMTX_ERROR guest error message (2021-07-09 16:09:12 +0100)
11
target/arm: Move v7m-related code from cpu32.c into a separate file (2024-03-08 14:45:03 +0000)
18
12
19
----------------------------------------------------------------
13
----------------------------------------------------------------
20
target-arm queue:
14
target-arm queue:
21
* New machine type: stm32vldiscovery
15
* Implement FEAT_ECV
22
* hw/intc/arm_gicv3_cpuif: Fix virtual irq number check in icv_[dir|eoir]_write
16
* STM32L4x5: Implement GPIO device
23
* hw/gpio/pl061: Honour Luminary PL061 PUR and PDR registers
17
* Fix 32-bit SMOPA
24
* virt: Fix implementation of GPIO-based powerdown/shutdown mechanism
18
* Refactor v7m related code from cpu32.c into its own file
25
* Correct the encoding of MDCCSR_EL0 and DBGDSCRint
19
* hw/rtc/sun4v-rtc: Relicense to GPLv2-or-later
26
* hw/intc: Improve formatting of MEMTX_ERROR guest error message
27
20
28
----------------------------------------------------------------
21
----------------------------------------------------------------
29
Alexandre Iooss (4):
22
Inès Varhol (3):
30
stm32f100: Add the stm32f100 SoC
23
hw/gpio: Implement STM32L4x5 GPIO
31
stm32vldiscovery: Add the STM32VLDISCOVERY Machine
24
hw/arm: Connect STM32L4x5 GPIO to STM32L4x5 SoC
32
docs/system: arm: Add stm32 boards description
25
tests/qtest: Add STM32L4x5 GPIO QTest testcase
33
tests/boot-serial-test: Add STM32VLDISCOVERY board testcase
34
26
35
Peter Maydell (10):
27
Peter Maydell (9):
36
hw/gpio/pl061: Convert DPRINTF to tracepoints
28
target/arm: Move some register related defines to internals.h
37
hw/gpio/pl061: Clean up read/write offset handling logic
29
target/arm: Timer _EL02 registers UNDEF for E2H == 0
38
hw/gpio/pl061: Add tracepoints for register read and write
30
target/arm: use FIELD macro for CNTHCTL bit definitions
39
hw/gpio/pl061: Document the interface of this device
31
target/arm: Don't allow RES0 CNTHCTL_EL2 bits to be written
40
hw/gpio/pl061: Honour Luminary PL061 PUR and PDR registers
32
target/arm: Implement new FEAT_ECV trap bits
41
hw/gpio/pl061: Make pullup/pulldown of outputs configurable
33
target/arm: Define CNTPCTSS_EL0 and CNTVCTSS_EL0
42
hw/arm/virt: Make PL061 GPIO lines pulled low, not high
34
target/arm: Implement FEAT_ECV CNTPOFF_EL2 handling
43
hw/gpio/pl061: Convert to 3-phase reset and assert GPIO lines correctly on reset
35
target/arm: Enable FEAT_ECV for 'max' CPU
44
hw/gpio/pl061: Document a shortcoming in our implementation
36
hw/rtc/sun4v-rtc: Relicense to GPLv2-or-later
45
hw/arm/stellaris: Expand comment about handling of OLED chipselect
46
37
47
Rebecca Cran (1):
38
Richard Henderson (1):
48
hw/intc: Improve formatting of MEMTX_ERROR guest error message
39
target/arm: Fix 32-bit SMOPA
49
40
50
Ricardo Koller (1):
41
Thomas Huth (1):
51
hw/intc/arm_gicv3_cpuif: Fix virtual irq number check in icv_[dir|eoir]_write
42
target/arm: Move v7m-related code from cpu32.c into a separate file
52
43
53
hnick@vmware.com (1):
44
MAINTAINERS | 1 +
54
target/arm: Correct the encoding of MDCCSR_EL0 and DBGDSCRint
45
docs/system/arm/b-l475e-iot01a.rst | 2 +-
46
docs/system/arm/emulation.rst | 1 +
47
include/hw/arm/stm32l4x5_soc.h | 2 +
48
include/hw/gpio/stm32l4x5_gpio.h | 71 +++++
49
include/hw/misc/stm32l4x5_syscfg.h | 3 +-
50
include/hw/rtc/sun4v-rtc.h | 2 +-
51
target/arm/cpu-features.h | 10 +
52
target/arm/cpu.h | 129 +--------
53
target/arm/internals.h | 151 ++++++++++
54
hw/arm/stm32l4x5_soc.c | 71 ++++-
55
hw/gpio/stm32l4x5_gpio.c | 477 ++++++++++++++++++++++++++++++++
56
hw/misc/stm32l4x5_syscfg.c | 1 +
57
hw/rtc/sun4v-rtc.c | 2 +-
58
target/arm/helper.c | 189 ++++++++++++-
59
target/arm/tcg/cpu-v7m.c | 290 +++++++++++++++++++
60
target/arm/tcg/cpu32.c | 261 ------------------
61
target/arm/tcg/cpu64.c | 1 +
62
target/arm/tcg/sme_helper.c | 77 +++---
63
tests/qtest/stm32l4x5_gpio-test.c | 551 +++++++++++++++++++++++++++++++++++++
64
tests/tcg/aarch64/sme-smopa-1.c | 47 ++++
65
tests/tcg/aarch64/sme-smopa-2.c | 54 ++++
66
hw/arm/Kconfig | 3 +-
67
hw/gpio/Kconfig | 3 +
68
hw/gpio/meson.build | 1 +
69
hw/gpio/trace-events | 6 +
70
target/arm/meson.build | 3 +
71
target/arm/tcg/meson.build | 3 +
72
target/arm/trace-events | 1 +
73
tests/qtest/meson.build | 3 +-
74
tests/tcg/aarch64/Makefile.target | 2 +-
75
31 files changed, 1962 insertions(+), 456 deletions(-)
76
create mode 100644 include/hw/gpio/stm32l4x5_gpio.h
77
create mode 100644 hw/gpio/stm32l4x5_gpio.c
78
create mode 100644 target/arm/tcg/cpu-v7m.c
79
create mode 100644 tests/qtest/stm32l4x5_gpio-test.c
80
create mode 100644 tests/tcg/aarch64/sme-smopa-1.c
81
create mode 100644 tests/tcg/aarch64/sme-smopa-2.c
55
82
56
docs/system/arm/stm32.rst | 66 +++++++
57
docs/system/target-arm.rst | 1 +
58
default-configs/devices/arm-softmmu.mak | 1 +
59
include/hw/arm/stm32f100_soc.h | 57 ++++++
60
hw/arm/stellaris.c | 56 +++++-
61
hw/arm/stm32f100_soc.c | 182 +++++++++++++++++
62
hw/arm/stm32vldiscovery.c | 66 +++++++
63
hw/arm/virt.c | 3 +
64
hw/gpio/pl061.c | 341 +++++++++++++++++++++++++-------
65
hw/intc/arm_gicv3_cpuif.c | 4 +-
66
hw/intc/arm_gicv3_redist.c | 4 +-
67
target/arm/helper.c | 16 +-
68
tests/qtest/boot-serial-test.c | 37 ++++
69
MAINTAINERS | 13 ++
70
hw/arm/Kconfig | 10 +
71
hw/arm/meson.build | 2 +
72
hw/gpio/trace-events | 9 +
73
17 files changed, 790 insertions(+), 78 deletions(-)
74
create mode 100644 docs/system/arm/stm32.rst
75
create mode 100644 include/hw/arm/stm32f100_soc.h
76
create mode 100644 hw/arm/stm32f100_soc.c
77
create mode 100644 hw/arm/stm32vldiscovery.c
78
diff view generated by jsdifflib
1
From: Rebecca Cran <rebecca@nuviainc.com>
1
cpu.h has a lot of #defines relating to CPU register fields.
2
Most of these aren't actually used outside target/arm code,
3
so there's no point in cluttering up the cpu.h file with them.
4
Move some easy ones to internals.h.
2
5
3
Add a space in the message printed when gicr_read*/gicr_write* returns
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
MEMTX_ERROR in arm_gicv3_redist.c.
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20240301183219.2424889-2-peter.maydell@linaro.org
10
---
11
target/arm/cpu.h | 128 -----------------------------------------
12
target/arm/internals.h | 128 +++++++++++++++++++++++++++++++++++++++++
13
2 files changed, 128 insertions(+), 128 deletions(-)
5
14
6
Signed-off-by: Rebecca Cran <rebecca@nuviainc.com>
15
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
7
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Message-id: 20210706211432.31902-1-rebecca@nuviainc.com
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
hw/intc/arm_gicv3_redist.c | 4 ++--
12
1 file changed, 2 insertions(+), 2 deletions(-)
13
14
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
15
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/intc/arm_gicv3_redist.c
17
--- a/target/arm/cpu.h
17
+++ b/hw/intc/arm_gicv3_redist.c
18
+++ b/target/arm/cpu.h
18
@@ -XXX,XX +XXX,XX @@ MemTxResult gicv3_redist_read(void *opaque, hwaddr offset, uint64_t *data,
19
@@ -XXX,XX +XXX,XX @@ typedef struct ARMGenericTimer {
19
if (r == MEMTX_ERROR) {
20
uint64_t ctl; /* Timer Control register */
20
qemu_log_mask(LOG_GUEST_ERROR,
21
} ARMGenericTimer;
21
"%s: invalid guest read at offset " TARGET_FMT_plx
22
22
- "size %u\n", __func__, offset, size);
23
-#define VTCR_NSW (1u << 29)
23
+ " size %u\n", __func__, offset, size);
24
-#define VTCR_NSA (1u << 30)
24
trace_gicv3_redist_badread(gicv3_redist_affid(cs), offset,
25
-#define VSTCR_SW VTCR_NSW
25
size, attrs.secure);
26
-#define VSTCR_SA VTCR_NSA
26
/* The spec requires that reserved registers are RAZ/WI;
27
-
27
@@ -XXX,XX +XXX,XX @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
28
/* Define a maximum sized vector register.
28
if (r == MEMTX_ERROR) {
29
* For 32-bit, this is a 128-bit NEON/AdvSIMD register.
29
qemu_log_mask(LOG_GUEST_ERROR,
30
* For 64-bit, this is a 2048-bit SVE register.
30
"%s: invalid guest write at offset " TARGET_FMT_plx
31
@@ -XXX,XX +XXX,XX @@ void pmu_init(ARMCPU *cpu);
31
- "size %u\n", __func__, offset, size);
32
#define SCTLR_SPINTMASK (1ULL << 62) /* FEAT_NMI */
32
+ " size %u\n", __func__, offset, size);
33
#define SCTLR_TIDCP (1ULL << 63) /* FEAT_TIDCP1 */
33
trace_gicv3_redist_badwrite(gicv3_redist_affid(cs), offset, data,
34
34
size, attrs.secure);
35
-/* Bit definitions for CPACR (AArch32 only) */
35
/* The spec requires that reserved registers are RAZ/WI;
36
-FIELD(CPACR, CP10, 20, 2)
37
-FIELD(CPACR, CP11, 22, 2)
38
-FIELD(CPACR, TRCDIS, 28, 1) /* matches CPACR_EL1.TTA */
39
-FIELD(CPACR, D32DIS, 30, 1) /* up to v7; RAZ in v8 */
40
-FIELD(CPACR, ASEDIS, 31, 1)
41
-
42
-/* Bit definitions for CPACR_EL1 (AArch64 only) */
43
-FIELD(CPACR_EL1, ZEN, 16, 2)
44
-FIELD(CPACR_EL1, FPEN, 20, 2)
45
-FIELD(CPACR_EL1, SMEN, 24, 2)
46
-FIELD(CPACR_EL1, TTA, 28, 1) /* matches CPACR.TRCDIS */
47
-
48
-/* Bit definitions for HCPTR (AArch32 only) */
49
-FIELD(HCPTR, TCP10, 10, 1)
50
-FIELD(HCPTR, TCP11, 11, 1)
51
-FIELD(HCPTR, TASE, 15, 1)
52
-FIELD(HCPTR, TTA, 20, 1)
53
-FIELD(HCPTR, TAM, 30, 1) /* matches CPTR_EL2.TAM */
54
-FIELD(HCPTR, TCPAC, 31, 1) /* matches CPTR_EL2.TCPAC */
55
-
56
-/* Bit definitions for CPTR_EL2 (AArch64 only) */
57
-FIELD(CPTR_EL2, TZ, 8, 1) /* !E2H */
58
-FIELD(CPTR_EL2, TFP, 10, 1) /* !E2H, matches HCPTR.TCP10 */
59
-FIELD(CPTR_EL2, TSM, 12, 1) /* !E2H */
60
-FIELD(CPTR_EL2, ZEN, 16, 2) /* E2H */
61
-FIELD(CPTR_EL2, FPEN, 20, 2) /* E2H */
62
-FIELD(CPTR_EL2, SMEN, 24, 2) /* E2H */
63
-FIELD(CPTR_EL2, TTA, 28, 1)
64
-FIELD(CPTR_EL2, TAM, 30, 1) /* matches HCPTR.TAM */
65
-FIELD(CPTR_EL2, TCPAC, 31, 1) /* matches HCPTR.TCPAC */
66
-
67
-/* Bit definitions for CPTR_EL3 (AArch64 only) */
68
-FIELD(CPTR_EL3, EZ, 8, 1)
69
-FIELD(CPTR_EL3, TFP, 10, 1)
70
-FIELD(CPTR_EL3, ESM, 12, 1)
71
-FIELD(CPTR_EL3, TTA, 20, 1)
72
-FIELD(CPTR_EL3, TAM, 30, 1)
73
-FIELD(CPTR_EL3, TCPAC, 31, 1)
74
-
75
-#define MDCR_MTPME (1U << 28)
76
-#define MDCR_TDCC (1U << 27)
77
-#define MDCR_HLP (1U << 26) /* MDCR_EL2 */
78
-#define MDCR_SCCD (1U << 23) /* MDCR_EL3 */
79
-#define MDCR_HCCD (1U << 23) /* MDCR_EL2 */
80
-#define MDCR_EPMAD (1U << 21)
81
-#define MDCR_EDAD (1U << 20)
82
-#define MDCR_TTRF (1U << 19)
83
-#define MDCR_STE (1U << 18) /* MDCR_EL3 */
84
-#define MDCR_SPME (1U << 17) /* MDCR_EL3 */
85
-#define MDCR_HPMD (1U << 17) /* MDCR_EL2 */
86
-#define MDCR_SDD (1U << 16)
87
-#define MDCR_SPD (3U << 14)
88
-#define MDCR_TDRA (1U << 11)
89
-#define MDCR_TDOSA (1U << 10)
90
-#define MDCR_TDA (1U << 9)
91
-#define MDCR_TDE (1U << 8)
92
-#define MDCR_HPME (1U << 7)
93
-#define MDCR_TPM (1U << 6)
94
-#define MDCR_TPMCR (1U << 5)
95
-#define MDCR_HPMN (0x1fU)
96
-
97
-/* Not all of the MDCR_EL3 bits are present in the 32-bit SDCR */
98
-#define SDCR_VALID_MASK (MDCR_MTPME | MDCR_TDCC | MDCR_SCCD | \
99
- MDCR_EPMAD | MDCR_EDAD | MDCR_TTRF | \
100
- MDCR_STE | MDCR_SPME | MDCR_SPD)
101
-
102
#define CPSR_M (0x1fU)
103
#define CPSR_T (1U << 5)
104
#define CPSR_F (1U << 6)
105
@@ -XXX,XX +XXX,XX @@ FIELD(CPTR_EL3, TCPAC, 31, 1)
106
#define XPSR_NZCV CPSR_NZCV
107
#define XPSR_IT CPSR_IT
108
109
-#define TTBCR_N (7U << 0) /* TTBCR.EAE==0 */
110
-#define TTBCR_T0SZ (7U << 0) /* TTBCR.EAE==1 */
111
-#define TTBCR_PD0 (1U << 4)
112
-#define TTBCR_PD1 (1U << 5)
113
-#define TTBCR_EPD0 (1U << 7)
114
-#define TTBCR_IRGN0 (3U << 8)
115
-#define TTBCR_ORGN0 (3U << 10)
116
-#define TTBCR_SH0 (3U << 12)
117
-#define TTBCR_T1SZ (3U << 16)
118
-#define TTBCR_A1 (1U << 22)
119
-#define TTBCR_EPD1 (1U << 23)
120
-#define TTBCR_IRGN1 (3U << 24)
121
-#define TTBCR_ORGN1 (3U << 26)
122
-#define TTBCR_SH1 (1U << 28)
123
-#define TTBCR_EAE (1U << 31)
124
-
125
-FIELD(VTCR, T0SZ, 0, 6)
126
-FIELD(VTCR, SL0, 6, 2)
127
-FIELD(VTCR, IRGN0, 8, 2)
128
-FIELD(VTCR, ORGN0, 10, 2)
129
-FIELD(VTCR, SH0, 12, 2)
130
-FIELD(VTCR, TG0, 14, 2)
131
-FIELD(VTCR, PS, 16, 3)
132
-FIELD(VTCR, VS, 19, 1)
133
-FIELD(VTCR, HA, 21, 1)
134
-FIELD(VTCR, HD, 22, 1)
135
-FIELD(VTCR, HWU59, 25, 1)
136
-FIELD(VTCR, HWU60, 26, 1)
137
-FIELD(VTCR, HWU61, 27, 1)
138
-FIELD(VTCR, HWU62, 28, 1)
139
-FIELD(VTCR, NSW, 29, 1)
140
-FIELD(VTCR, NSA, 30, 1)
141
-FIELD(VTCR, DS, 32, 1)
142
-FIELD(VTCR, SL2, 33, 1)
143
-
144
/* Bit definitions for ARMv8 SPSR (PSTATE) format.
145
* Only these are valid when in AArch64 mode; in
146
* AArch32 mode SPSRs are basically CPSR-format.
147
@@ -XXX,XX +XXX,XX @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
148
#define HCR_TWEDEN (1ULL << 59)
149
#define HCR_TWEDEL MAKE_64BIT_MASK(60, 4)
150
151
-#define HCRX_ENAS0 (1ULL << 0)
152
-#define HCRX_ENALS (1ULL << 1)
153
-#define HCRX_ENASR (1ULL << 2)
154
-#define HCRX_FNXS (1ULL << 3)
155
-#define HCRX_FGTNXS (1ULL << 4)
156
-#define HCRX_SMPME (1ULL << 5)
157
-#define HCRX_TALLINT (1ULL << 6)
158
-#define HCRX_VINMI (1ULL << 7)
159
-#define HCRX_VFNMI (1ULL << 8)
160
-#define HCRX_CMOW (1ULL << 9)
161
-#define HCRX_MCE2 (1ULL << 10)
162
-#define HCRX_MSCEN (1ULL << 11)
163
-
164
-#define HPFAR_NS (1ULL << 63)
165
-
166
#define SCR_NS (1ULL << 0)
167
#define SCR_IRQ (1ULL << 1)
168
#define SCR_FIQ (1ULL << 2)
169
@@ -XXX,XX +XXX,XX @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
170
#define SCR_GPF (1ULL << 48)
171
#define SCR_NSE (1ULL << 62)
172
173
-#define HSTR_TTEE (1 << 16)
174
-#define HSTR_TJDBX (1 << 17)
175
-
176
-#define CNTHCTL_CNTVMASK (1 << 18)
177
-#define CNTHCTL_CNTPMASK (1 << 19)
178
-
179
/* Return the current FPSCR value. */
180
uint32_t vfp_get_fpscr(CPUARMState *env);
181
void vfp_set_fpscr(CPUARMState *env, uint32_t val);
182
diff --git a/target/arm/internals.h b/target/arm/internals.h
183
index XXXXXXX..XXXXXXX 100644
184
--- a/target/arm/internals.h
185
+++ b/target/arm/internals.h
186
@@ -XXX,XX +XXX,XX @@ FIELD(DBGWCR, WT, 20, 1)
187
FIELD(DBGWCR, MASK, 24, 5)
188
FIELD(DBGWCR, SSCE, 29, 1)
189
190
+#define VTCR_NSW (1u << 29)
191
+#define VTCR_NSA (1u << 30)
192
+#define VSTCR_SW VTCR_NSW
193
+#define VSTCR_SA VTCR_NSA
194
+
195
+/* Bit definitions for CPACR (AArch32 only) */
196
+FIELD(CPACR, CP10, 20, 2)
197
+FIELD(CPACR, CP11, 22, 2)
198
+FIELD(CPACR, TRCDIS, 28, 1) /* matches CPACR_EL1.TTA */
199
+FIELD(CPACR, D32DIS, 30, 1) /* up to v7; RAZ in v8 */
200
+FIELD(CPACR, ASEDIS, 31, 1)
201
+
202
+/* Bit definitions for CPACR_EL1 (AArch64 only) */
203
+FIELD(CPACR_EL1, ZEN, 16, 2)
204
+FIELD(CPACR_EL1, FPEN, 20, 2)
205
+FIELD(CPACR_EL1, SMEN, 24, 2)
206
+FIELD(CPACR_EL1, TTA, 28, 1) /* matches CPACR.TRCDIS */
207
+
208
+/* Bit definitions for HCPTR (AArch32 only) */
209
+FIELD(HCPTR, TCP10, 10, 1)
210
+FIELD(HCPTR, TCP11, 11, 1)
211
+FIELD(HCPTR, TASE, 15, 1)
212
+FIELD(HCPTR, TTA, 20, 1)
213
+FIELD(HCPTR, TAM, 30, 1) /* matches CPTR_EL2.TAM */
214
+FIELD(HCPTR, TCPAC, 31, 1) /* matches CPTR_EL2.TCPAC */
215
+
216
+/* Bit definitions for CPTR_EL2 (AArch64 only) */
217
+FIELD(CPTR_EL2, TZ, 8, 1) /* !E2H */
218
+FIELD(CPTR_EL2, TFP, 10, 1) /* !E2H, matches HCPTR.TCP10 */
219
+FIELD(CPTR_EL2, TSM, 12, 1) /* !E2H */
220
+FIELD(CPTR_EL2, ZEN, 16, 2) /* E2H */
221
+FIELD(CPTR_EL2, FPEN, 20, 2) /* E2H */
222
+FIELD(CPTR_EL2, SMEN, 24, 2) /* E2H */
223
+FIELD(CPTR_EL2, TTA, 28, 1)
224
+FIELD(CPTR_EL2, TAM, 30, 1) /* matches HCPTR.TAM */
225
+FIELD(CPTR_EL2, TCPAC, 31, 1) /* matches HCPTR.TCPAC */
226
+
227
+/* Bit definitions for CPTR_EL3 (AArch64 only) */
228
+FIELD(CPTR_EL3, EZ, 8, 1)
229
+FIELD(CPTR_EL3, TFP, 10, 1)
230
+FIELD(CPTR_EL3, ESM, 12, 1)
231
+FIELD(CPTR_EL3, TTA, 20, 1)
232
+FIELD(CPTR_EL3, TAM, 30, 1)
233
+FIELD(CPTR_EL3, TCPAC, 31, 1)
234
+
235
+#define MDCR_MTPME (1U << 28)
236
+#define MDCR_TDCC (1U << 27)
237
+#define MDCR_HLP (1U << 26) /* MDCR_EL2 */
238
+#define MDCR_SCCD (1U << 23) /* MDCR_EL3 */
239
+#define MDCR_HCCD (1U << 23) /* MDCR_EL2 */
240
+#define MDCR_EPMAD (1U << 21)
241
+#define MDCR_EDAD (1U << 20)
242
+#define MDCR_TTRF (1U << 19)
243
+#define MDCR_STE (1U << 18) /* MDCR_EL3 */
244
+#define MDCR_SPME (1U << 17) /* MDCR_EL3 */
245
+#define MDCR_HPMD (1U << 17) /* MDCR_EL2 */
246
+#define MDCR_SDD (1U << 16)
247
+#define MDCR_SPD (3U << 14)
248
+#define MDCR_TDRA (1U << 11)
249
+#define MDCR_TDOSA (1U << 10)
250
+#define MDCR_TDA (1U << 9)
251
+#define MDCR_TDE (1U << 8)
252
+#define MDCR_HPME (1U << 7)
253
+#define MDCR_TPM (1U << 6)
254
+#define MDCR_TPMCR (1U << 5)
255
+#define MDCR_HPMN (0x1fU)
256
+
257
+/* Not all of the MDCR_EL3 bits are present in the 32-bit SDCR */
258
+#define SDCR_VALID_MASK (MDCR_MTPME | MDCR_TDCC | MDCR_SCCD | \
259
+ MDCR_EPMAD | MDCR_EDAD | MDCR_TTRF | \
260
+ MDCR_STE | MDCR_SPME | MDCR_SPD)
261
+
262
+#define TTBCR_N (7U << 0) /* TTBCR.EAE==0 */
263
+#define TTBCR_T0SZ (7U << 0) /* TTBCR.EAE==1 */
264
+#define TTBCR_PD0 (1U << 4)
265
+#define TTBCR_PD1 (1U << 5)
266
+#define TTBCR_EPD0 (1U << 7)
267
+#define TTBCR_IRGN0 (3U << 8)
268
+#define TTBCR_ORGN0 (3U << 10)
269
+#define TTBCR_SH0 (3U << 12)
270
+#define TTBCR_T1SZ (3U << 16)
271
+#define TTBCR_A1 (1U << 22)
272
+#define TTBCR_EPD1 (1U << 23)
273
+#define TTBCR_IRGN1 (3U << 24)
274
+#define TTBCR_ORGN1 (3U << 26)
275
+#define TTBCR_SH1 (1U << 28)
276
+#define TTBCR_EAE (1U << 31)
277
+
278
+FIELD(VTCR, T0SZ, 0, 6)
279
+FIELD(VTCR, SL0, 6, 2)
280
+FIELD(VTCR, IRGN0, 8, 2)
281
+FIELD(VTCR, ORGN0, 10, 2)
282
+FIELD(VTCR, SH0, 12, 2)
283
+FIELD(VTCR, TG0, 14, 2)
284
+FIELD(VTCR, PS, 16, 3)
285
+FIELD(VTCR, VS, 19, 1)
286
+FIELD(VTCR, HA, 21, 1)
287
+FIELD(VTCR, HD, 22, 1)
288
+FIELD(VTCR, HWU59, 25, 1)
289
+FIELD(VTCR, HWU60, 26, 1)
290
+FIELD(VTCR, HWU61, 27, 1)
291
+FIELD(VTCR, HWU62, 28, 1)
292
+FIELD(VTCR, NSW, 29, 1)
293
+FIELD(VTCR, NSA, 30, 1)
294
+FIELD(VTCR, DS, 32, 1)
295
+FIELD(VTCR, SL2, 33, 1)
296
+
297
+#define HCRX_ENAS0 (1ULL << 0)
298
+#define HCRX_ENALS (1ULL << 1)
299
+#define HCRX_ENASR (1ULL << 2)
300
+#define HCRX_FNXS (1ULL << 3)
301
+#define HCRX_FGTNXS (1ULL << 4)
302
+#define HCRX_SMPME (1ULL << 5)
303
+#define HCRX_TALLINT (1ULL << 6)
304
+#define HCRX_VINMI (1ULL << 7)
305
+#define HCRX_VFNMI (1ULL << 8)
306
+#define HCRX_CMOW (1ULL << 9)
307
+#define HCRX_MCE2 (1ULL << 10)
308
+#define HCRX_MSCEN (1ULL << 11)
309
+
310
+#define HPFAR_NS (1ULL << 63)
311
+
312
+#define HSTR_TTEE (1 << 16)
313
+#define HSTR_TJDBX (1 << 17)
314
+
315
+#define CNTHCTL_CNTVMASK (1 << 18)
316
+#define CNTHCTL_CNTPMASK (1 << 19)
317
+
318
/* We use a few fake FSR values for internal purposes in M profile.
319
* M profile cores don't have A/R format FSRs, but currently our
320
* get_phys_addr() code assumes A/R profile and reports failures via
36
--
321
--
37
2.20.1
322
2.34.1
38
323
39
324
diff view generated by jsdifflib
1
Add a comment documenting the "QEMU interface" of this device:
1
The timer _EL02 registers should UNDEF for invalid accesses from EL2
2
which MMIO regions, IRQ lines, GPIO lines, etc it exposes.
2
or EL3 when HCR_EL2.E2H == 0, not take a cp access trap. We were
3
delivering the exception to EL2 with the wrong syndrome.
3
4
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20240301183219.2424889-3-peter.maydell@linaro.org
6
---
8
---
7
hw/gpio/pl061.c | 7 +++++++
9
target/arm/helper.c | 2 +-
8
1 file changed, 7 insertions(+)
10
1 file changed, 1 insertion(+), 1 deletion(-)
9
11
10
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c
12
diff --git a/target/arm/helper.c b/target/arm/helper.c
11
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
12
--- a/hw/gpio/pl061.c
14
--- a/target/arm/helper.c
13
+++ b/hw/gpio/pl061.c
15
+++ b/target/arm/helper.c
14
@@ -XXX,XX +XXX,XX @@
16
@@ -XXX,XX +XXX,XX @@ static CPAccessResult e2h_access(CPUARMState *env, const ARMCPRegInfo *ri,
15
* Written by Paul Brook
17
return CP_ACCESS_OK;
16
*
18
}
17
* This code is licensed under the GPL.
19
if (!(arm_hcr_el2_eff(env) & HCR_E2H)) {
18
+ *
20
- return CP_ACCESS_TRAP;
19
+ * QEMU interface:
21
+ return CP_ACCESS_TRAP_UNCATEGORIZED;
20
+ * + sysbus MMIO region 0: the device registers
22
}
21
+ * + sysbus IRQ: the GPIOINTR interrupt line
23
return CP_ACCESS_OK;
22
+ * + unnamed GPIO inputs 0..7: inputs to connect to the emulated GPIO lines
24
}
23
+ * + unnamed GPIO outputs 0..7: the emulated GPIO lines, considered as
24
+ * outputs
25
*/
26
27
#include "qemu/osdep.h"
28
--
25
--
29
2.20.1
26
2.34.1
30
31
diff view generated by jsdifflib
1
The Luminary PL061s in the Stellaris LM3S9695 don't all have the same
1
We prefer the FIELD macro over ad-hoc #defines for register bits;
2
reset value for GPIOPUR. We can get away with not letting the board
2
switch CNTHCTL to that style before we add any more bits.
3
configure the PUR reset value because we don't actually wire anything
4
up to the lines which should reset to pull-up. Add a comment noting
5
this omission.
6
3
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
5
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20240301183219.2424889-4-peter.maydell@linaro.org
9
---
8
---
10
hw/gpio/pl061.c | 9 +++++++++
9
target/arm/internals.h | 27 +++++++++++++++++++++++++--
11
1 file changed, 9 insertions(+)
10
target/arm/helper.c | 9 ++++-----
11
2 files changed, 29 insertions(+), 7 deletions(-)
12
12
13
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c
13
diff --git a/target/arm/internals.h b/target/arm/internals.h
14
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/gpio/pl061.c
15
--- a/target/arm/internals.h
16
+++ b/hw/gpio/pl061.c
16
+++ b/target/arm/internals.h
17
@@ -XXX,XX +XXX,XX @@ static void pl061_enter_reset(Object *obj, ResetType type)
17
@@ -XXX,XX +XXX,XX @@ FIELD(VTCR, SL2, 33, 1)
18
trace_pl061_reset(DEVICE(s)->canonical_path);
18
#define HSTR_TTEE (1 << 16)
19
19
#define HSTR_TJDBX (1 << 17)
20
/* reset values from PL061 TRM, Stellaris LM3S5P31 & LM3S8962 Data Sheet */
20
21
+
21
-#define CNTHCTL_CNTVMASK (1 << 18)
22
+ /*
22
-#define CNTHCTL_CNTPMASK (1 << 19)
23
+ * FIXME: For the LM3S6965, not all of the PL061 instances have the
23
+/*
24
+ * same reset values for GPIOPUR, GPIOAFSEL and GPIODEN, so in theory
24
+ * Depending on the value of HCR_EL2.E2H, bits 0 and 1
25
+ * we should allow the board to configure these via properties.
25
+ * have different bit definitions, and EL1PCTEN might be
26
+ * In practice, we don't wire anything up to the affected GPIO lines
26
+ * bit 0 or bit 10. We use _E2H1 and _E2H0 suffixes to
27
+ * (PB7, PC0, PC1, PC2, PC3 -- they're used for JTAG), so we can
27
+ * disambiguate if necessary.
28
+ * get away with this inaccuracy.
28
+ */
29
+ */
29
+FIELD(CNTHCTL, EL0PCTEN_E2H1, 0, 1)
30
s->data = 0;
30
+FIELD(CNTHCTL, EL0VCTEN_E2H1, 1, 1)
31
s->old_in_data = 0;
31
+FIELD(CNTHCTL, EL1PCTEN_E2H0, 0, 1)
32
s->dir = 0;
32
+FIELD(CNTHCTL, EL1PCEN_E2H0, 1, 1)
33
+FIELD(CNTHCTL, EVNTEN, 2, 1)
34
+FIELD(CNTHCTL, EVNTDIR, 3, 1)
35
+FIELD(CNTHCTL, EVNTI, 4, 4)
36
+FIELD(CNTHCTL, EL0VTEN, 8, 1)
37
+FIELD(CNTHCTL, EL0PTEN, 9, 1)
38
+FIELD(CNTHCTL, EL1PCTEN_E2H1, 10, 1)
39
+FIELD(CNTHCTL, EL1PTEN, 11, 1)
40
+FIELD(CNTHCTL, ECV, 12, 1)
41
+FIELD(CNTHCTL, EL1TVT, 13, 1)
42
+FIELD(CNTHCTL, EL1TVCT, 14, 1)
43
+FIELD(CNTHCTL, EL1NVPCT, 15, 1)
44
+FIELD(CNTHCTL, EL1NVVCT, 16, 1)
45
+FIELD(CNTHCTL, EVNTIS, 17, 1)
46
+FIELD(CNTHCTL, CNTVMASK, 18, 1)
47
+FIELD(CNTHCTL, CNTPMASK, 19, 1)
48
49
/* We use a few fake FSR values for internal purposes in M profile.
50
* M profile cores don't have A/R format FSRs, but currently our
51
diff --git a/target/arm/helper.c b/target/arm/helper.c
52
index XXXXXXX..XXXXXXX 100644
53
--- a/target/arm/helper.c
54
+++ b/target/arm/helper.c
55
@@ -XXX,XX +XXX,XX @@ static void gt_update_irq(ARMCPU *cpu, int timeridx)
56
* It is RES0 in Secure and NonSecure state.
57
*/
58
if ((ss == ARMSS_Root || ss == ARMSS_Realm) &&
59
- ((timeridx == GTIMER_VIRT && (cnthctl & CNTHCTL_CNTVMASK)) ||
60
- (timeridx == GTIMER_PHYS && (cnthctl & CNTHCTL_CNTPMASK)))) {
61
+ ((timeridx == GTIMER_VIRT && (cnthctl & R_CNTHCTL_CNTVMASK_MASK)) ||
62
+ (timeridx == GTIMER_PHYS && (cnthctl & R_CNTHCTL_CNTPMASK_MASK)))) {
63
irqstate = 0;
64
}
65
66
@@ -XXX,XX +XXX,XX @@ static void gt_cnthctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
67
{
68
ARMCPU *cpu = env_archcpu(env);
69
uint32_t oldval = env->cp15.cnthctl_el2;
70
-
71
raw_write(env, ri, value);
72
73
- if ((oldval ^ value) & CNTHCTL_CNTVMASK) {
74
+ if ((oldval ^ value) & R_CNTHCTL_CNTVMASK_MASK) {
75
gt_update_irq(cpu, GTIMER_VIRT);
76
- } else if ((oldval ^ value) & CNTHCTL_CNTPMASK) {
77
+ } else if ((oldval ^ value) & R_CNTHCTL_CNTPMASK_MASK) {
78
gt_update_irq(cpu, GTIMER_PHYS);
79
}
80
}
33
--
81
--
34
2.20.1
82
2.34.1
35
83
36
84
diff view generated by jsdifflib
1
From: "hnick@vmware.com" <hnick@vmware.com>
1
Don't allow the guest to write CNTHCTL_EL2 bits which don't exist.
2
This is not strictly architecturally required, but it is how we've
3
tended to implement registers more recently.
2
4
3
Signed-off-by: Nick Hudson <hnick@vmware.com>
5
In particular, bits [19:18] are only present with FEAT_RME,
4
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
and bits [17:12] will only be present with FEAT_ECV.
7
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 20240301183219.2424889-5-peter.maydell@linaro.org
6
---
11
---
7
target/arm/helper.c | 16 +++++++++++++---
12
target/arm/helper.c | 18 ++++++++++++++++++
8
1 file changed, 13 insertions(+), 3 deletions(-)
13
1 file changed, 18 insertions(+)
9
14
10
diff --git a/target/arm/helper.c b/target/arm/helper.c
15
diff --git a/target/arm/helper.c b/target/arm/helper.c
11
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
12
--- a/target/arm/helper.c
17
--- a/target/arm/helper.c
13
+++ b/target/arm/helper.c
18
+++ b/target/arm/helper.c
14
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo debug_cp_reginfo[] = {
19
@@ -XXX,XX +XXX,XX @@ static void gt_cnthctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
15
.access = PL1_RW, .accessfn = access_tda,
20
{
16
.fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1),
21
ARMCPU *cpu = env_archcpu(env);
17
.resetvalue = 0 },
22
uint32_t oldval = env->cp15.cnthctl_el2;
18
- /* MDCCSR_EL0, aka DBGDSCRint. This is a read-only mirror of MDSCR_EL1.
23
+ uint32_t valid_mask =
19
+ /*
24
+ R_CNTHCTL_EL0PCTEN_E2H1_MASK |
20
+ * MDCCSR_EL0[30:29] map to EDSCR[30:29]. Simply RAZ as the external
25
+ R_CNTHCTL_EL0VCTEN_E2H1_MASK |
21
+ * Debug Communication Channel is not implemented.
26
+ R_CNTHCTL_EVNTEN_MASK |
22
+ */
27
+ R_CNTHCTL_EVNTDIR_MASK |
23
+ { .name = "MDCCSR_EL0", .state = ARM_CP_STATE_AA64,
28
+ R_CNTHCTL_EVNTI_MASK |
24
+ .opc0 = 2, .opc1 = 3, .crn = 0, .crm = 1, .opc2 = 0,
29
+ R_CNTHCTL_EL0VTEN_MASK |
25
+ .access = PL0_R, .accessfn = access_tda,
30
+ R_CNTHCTL_EL0PTEN_MASK |
26
+ .type = ARM_CP_CONST, .resetvalue = 0 },
31
+ R_CNTHCTL_EL1PCTEN_E2H1_MASK |
27
+ /*
32
+ R_CNTHCTL_EL1PTEN_MASK;
28
+ * DBGDSCRint[15,12,5:2] map to MDSCR_EL1[15,12,5:2]. Map all bits as
33
+
29
+ * it is unlikely a guest will care.
34
+ if (cpu_isar_feature(aa64_rme, cpu)) {
30
* We don't implement the configurable EL0 access.
35
+ valid_mask |= R_CNTHCTL_CNTVMASK_MASK | R_CNTHCTL_CNTPMASK_MASK;
31
*/
36
+ }
32
- { .name = "MDCCSR_EL0", .state = ARM_CP_STATE_BOTH,
37
+
33
- .cp = 14, .opc0 = 2, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 0,
38
+ /* Clear RES0 bits */
34
+ { .name = "DBGDSCRint", .state = ARM_CP_STATE_AA32,
39
+ value &= valid_mask;
35
+ .cp = 14, .opc1 = 0, .crn = 0, .crm = 1, .opc2 = 0,
40
+
36
.type = ARM_CP_ALIAS,
41
raw_write(env, ri, value);
37
.access = PL1_R, .accessfn = access_tda,
42
38
.fieldoffset = offsetof(CPUARMState, cp15.mdscr_el1), },
43
if ((oldval ^ value) & R_CNTHCTL_CNTVMASK_MASK) {
39
--
44
--
40
2.20.1
45
2.34.1
41
42
diff view generated by jsdifflib
1
Currently the pl061_read() and pl061_write() functions handle offsets
1
The functionality defined by ID_AA64MMFR0_EL1.ECV == 1 is:
2
using a combination of three if() statements and a switch(). Clean
2
* four new trap bits for various counter and timer registers
3
this up to use just a switch, using case ranges.
3
* the CNTHCTL_EL2.EVNTIS and CNTKCTL_EL1.EVNTIS bits which control
4
scaling of the event stream. This is a no-op for us, because we don't
5
implement the event stream (our WFE is a NOP): all we need to do is
6
allow CNTHCTL_EL2.ENVTIS to be read and written.
7
* extensions to PMSCR_EL1.PCT, PMSCR_EL2.PCT, TRFCR_EL1.TS and
8
TRFCR_EL2.TS: these are all no-ops for us, because we don't implement
9
FEAT_SPE or FEAT_TRF.
10
* new registers CNTPCTSS_EL0 and NCTVCTSS_EL0 which are
11
"self-sychronizing" views of the CNTPCT_EL0 and CNTVCT_EL0, meaning
12
that no barriers are needed around their accesses. For us these
13
are just the same as the normal views, because all our sysregs are
14
inherently self-sychronizing.
4
15
5
This requires that instead of catching accesses to the luminary-only
16
In this commit we implement the trap handling and permit the new
6
registers on a stock PL061 via a check on s->rsvd_start we use
17
CNTHCTL_EL2 bits to be written.
7
an "is this luminary?" check in the cases for each luminary-only
8
register.
9
18
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
19
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
20
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
21
Message-id: 20240301183219.2424889-6-peter.maydell@linaro.org
12
---
22
---
13
hw/gpio/pl061.c | 104 ++++++++++++++++++++++++++++++++++++------------
23
target/arm/cpu-features.h | 5 ++++
14
1 file changed, 79 insertions(+), 25 deletions(-)
24
target/arm/helper.c | 51 +++++++++++++++++++++++++++++++++++----
25
2 files changed, 51 insertions(+), 5 deletions(-)
15
26
16
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c
27
diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
17
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/gpio/pl061.c
29
--- a/target/arm/cpu-features.h
19
+++ b/hw/gpio/pl061.c
30
+++ b/target/arm/cpu-features.h
20
@@ -XXX,XX +XXX,XX @@ struct PL061State {
31
@@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_fgt(const ARMISARegisters *id)
21
qemu_irq irq;
32
return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, FGT) != 0;
22
qemu_irq out[N_GPIOS];
33
}
23
const unsigned char *id;
34
24
- uint32_t rsvd_start; /* reserved area: [rsvd_start, 0xfcc] */
35
+static inline bool isar_feature_aa64_ecv_traps(const ARMISARegisters *id)
25
};
36
+{
26
37
+ return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, ECV) > 0;
27
static const VMStateDescription vmstate_pl061 = {
38
+}
28
@@ -XXX,XX +XXX,XX @@ static uint64_t pl061_read(void *opaque, hwaddr offset,
39
+
40
static inline bool isar_feature_aa64_vh(const ARMISARegisters *id)
29
{
41
{
30
PL061State *s = (PL061State *)opaque;
42
return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, VH) != 0;
31
43
diff --git a/target/arm/helper.c b/target/arm/helper.c
32
- if (offset < 0x400) {
44
index XXXXXXX..XXXXXXX 100644
33
- return s->data & (offset >> 2);
45
--- a/target/arm/helper.c
34
- }
46
+++ b/target/arm/helper.c
35
- if (offset >= s->rsvd_start && offset <= 0xfcc) {
47
@@ -XXX,XX +XXX,XX @@ static CPAccessResult gt_counter_access(CPUARMState *env, int timeridx,
36
- goto err_out;
48
: !extract32(env->cp15.cnthctl_el2, 0, 1))) {
37
- }
49
return CP_ACCESS_TRAP_EL2;
38
- if (offset >= 0xfd0 && offset < 0x1000) {
50
}
39
- return s->id[(offset - 0xfd0) >> 2];
51
+ if (has_el2 && timeridx == GTIMER_VIRT) {
40
- }
52
+ if (FIELD_EX64(env->cp15.cnthctl_el2, CNTHCTL, EL1TVCT)) {
41
switch (offset) {
53
+ return CP_ACCESS_TRAP_EL2;
42
+ case 0x0 ... 0x3ff: /* Data */
54
+ }
43
+ return s->data & (offset >> 2);
44
case 0x400: /* Direction */
45
return s->dir;
46
case 0x404: /* Interrupt sense */
47
@@ -XXX,XX +XXX,XX @@ static uint64_t pl061_read(void *opaque, hwaddr offset,
48
case 0x420: /* Alternate function select */
49
return s->afsel;
50
case 0x500: /* 2mA drive */
51
+ if (s->id != pl061_id_luminary) {
52
+ goto bad_offset;
53
+ }
55
+ }
54
return s->dr2r;
55
case 0x504: /* 4mA drive */
56
+ if (s->id != pl061_id_luminary) {
57
+ goto bad_offset;
58
+ }
59
return s->dr4r;
60
case 0x508: /* 8mA drive */
61
+ if (s->id != pl061_id_luminary) {
62
+ goto bad_offset;
63
+ }
64
return s->dr8r;
65
case 0x50c: /* Open drain */
66
+ if (s->id != pl061_id_luminary) {
67
+ goto bad_offset;
68
+ }
69
return s->odr;
70
case 0x510: /* Pull-up */
71
+ if (s->id != pl061_id_luminary) {
72
+ goto bad_offset;
73
+ }
74
return s->pur;
75
case 0x514: /* Pull-down */
76
+ if (s->id != pl061_id_luminary) {
77
+ goto bad_offset;
78
+ }
79
return s->pdr;
80
case 0x518: /* Slew rate control */
81
+ if (s->id != pl061_id_luminary) {
82
+ goto bad_offset;
83
+ }
84
return s->slr;
85
case 0x51c: /* Digital enable */
86
+ if (s->id != pl061_id_luminary) {
87
+ goto bad_offset;
88
+ }
89
return s->den;
90
case 0x520: /* Lock */
91
+ if (s->id != pl061_id_luminary) {
92
+ goto bad_offset;
93
+ }
94
return s->locked;
95
case 0x524: /* Commit */
96
+ if (s->id != pl061_id_luminary) {
97
+ goto bad_offset;
98
+ }
99
return s->cr;
100
case 0x528: /* Analog mode select */
101
+ if (s->id != pl061_id_luminary) {
102
+ goto bad_offset;
103
+ }
104
return s->amsel;
105
+ case 0xfd0 ... 0xfff: /* ID registers */
106
+ return s->id[(offset - 0xfd0) >> 2];
107
default:
108
+ bad_offset:
109
+ qemu_log_mask(LOG_GUEST_ERROR,
110
+ "pl061_read: Bad offset %x\n", (int)offset);
111
break;
56
break;
112
}
57
}
113
-err_out:
58
return CP_ACCESS_OK;
114
- qemu_log_mask(LOG_GUEST_ERROR,
59
@@ -XXX,XX +XXX,XX @@ static CPAccessResult gt_timer_access(CPUARMState *env, int timeridx,
115
- "pl061_read: Bad offset %x\n", (int)offset);
60
}
116
return 0;
61
}
62
}
63
+ if (has_el2 && timeridx == GTIMER_VIRT) {
64
+ if (FIELD_EX64(env->cp15.cnthctl_el2, CNTHCTL, EL1TVT)) {
65
+ return CP_ACCESS_TRAP_EL2;
66
+ }
67
+ }
68
break;
69
}
70
return CP_ACCESS_OK;
71
@@ -XXX,XX +XXX,XX @@ static void gt_cnthctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
72
if (cpu_isar_feature(aa64_rme, cpu)) {
73
valid_mask |= R_CNTHCTL_CNTVMASK_MASK | R_CNTHCTL_CNTPMASK_MASK;
74
}
75
+ if (cpu_isar_feature(aa64_ecv_traps, cpu)) {
76
+ valid_mask |=
77
+ R_CNTHCTL_EL1TVT_MASK |
78
+ R_CNTHCTL_EL1TVCT_MASK |
79
+ R_CNTHCTL_EL1NVPCT_MASK |
80
+ R_CNTHCTL_EL1NVVCT_MASK |
81
+ R_CNTHCTL_EVNTIS_MASK;
82
+ }
83
84
/* Clear RES0 bits */
85
value &= valid_mask;
86
@@ -XXX,XX +XXX,XX @@ static CPAccessResult e2h_access(CPUARMState *env, const ARMCPRegInfo *ri,
87
{
88
if (arm_current_el(env) == 1) {
89
/* This must be a FEAT_NV access */
90
- /* TODO: FEAT_ECV will need to check CNTHCTL_EL2 here */
91
return CP_ACCESS_OK;
92
}
93
if (!(arm_hcr_el2_eff(env) & HCR_E2H)) {
94
@@ -XXX,XX +XXX,XX @@ static CPAccessResult e2h_access(CPUARMState *env, const ARMCPRegInfo *ri,
95
return CP_ACCESS_OK;
117
}
96
}
118
97
119
@@ -XXX,XX +XXX,XX @@ static void pl061_write(void *opaque, hwaddr offset,
98
+static CPAccessResult access_el1nvpct(CPUARMState *env, const ARMCPRegInfo *ri,
120
PL061State *s = (PL061State *)opaque;
99
+ bool isread)
121
uint8_t mask;
100
+{
122
101
+ if (arm_current_el(env) == 1) {
123
- if (offset < 0x400) {
102
+ /* This must be a FEAT_NV access with NVx == 101 */
124
+ switch (offset) {
103
+ if (FIELD_EX64(env->cp15.cnthctl_el2, CNTHCTL, EL1NVPCT)) {
125
+ case 0 ... 0x3ff:
104
+ return CP_ACCESS_TRAP_EL2;
126
mask = (offset >> 2) & s->dir;
127
s->data = (s->data & ~mask) | (value & mask);
128
pl061_update(s);
129
return;
130
- }
131
- if (offset >= s->rsvd_start) {
132
- goto err_out;
133
- }
134
- switch (offset) {
135
case 0x400: /* Direction */
136
s->dir = value & 0xff;
137
break;
138
@@ -XXX,XX +XXX,XX @@ static void pl061_write(void *opaque, hwaddr offset,
139
s->afsel = (s->afsel & ~mask) | (value & mask);
140
break;
141
case 0x500: /* 2mA drive */
142
+ if (s->id != pl061_id_luminary) {
143
+ goto bad_offset;
144
+ }
105
+ }
145
s->dr2r = value & 0xff;
106
+ }
146
break;
107
+ return e2h_access(env, ri, isread);
147
case 0x504: /* 4mA drive */
108
+}
148
+ if (s->id != pl061_id_luminary) {
109
+
149
+ goto bad_offset;
110
+static CPAccessResult access_el1nvvct(CPUARMState *env, const ARMCPRegInfo *ri,
111
+ bool isread)
112
+{
113
+ if (arm_current_el(env) == 1) {
114
+ /* This must be a FEAT_NV access with NVx == 101 */
115
+ if (FIELD_EX64(env->cp15.cnthctl_el2, CNTHCTL, EL1NVVCT)) {
116
+ return CP_ACCESS_TRAP_EL2;
150
+ }
117
+ }
151
s->dr4r = value & 0xff;
118
+ }
152
break;
119
+ return e2h_access(env, ri, isread);
153
case 0x508: /* 8mA drive */
120
+}
154
+ if (s->id != pl061_id_luminary) {
121
+
155
+ goto bad_offset;
122
/* Test if system register redirection is to occur in the current state. */
156
+ }
123
static bool redirect_for_e2h(CPUARMState *env)
157
s->dr8r = value & 0xff;
124
{
158
break;
125
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo vhe_reginfo[] = {
159
case 0x50c: /* Open drain */
126
{ .name = "CNTP_CTL_EL02", .state = ARM_CP_STATE_AA64,
160
+ if (s->id != pl061_id_luminary) {
127
.opc0 = 3, .opc1 = 5, .crn = 14, .crm = 2, .opc2 = 1,
161
+ goto bad_offset;
128
.type = ARM_CP_IO | ARM_CP_ALIAS,
162
+ }
129
- .access = PL2_RW, .accessfn = e2h_access,
163
s->odr = value & 0xff;
130
+ .access = PL2_RW, .accessfn = access_el1nvpct,
164
break;
131
.nv2_redirect_offset = 0x180 | NV2_REDIR_NO_NV1,
165
case 0x510: /* Pull-up */
132
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].ctl),
166
+ if (s->id != pl061_id_luminary) {
133
.writefn = gt_phys_ctl_write, .raw_writefn = raw_write },
167
+ goto bad_offset;
134
{ .name = "CNTV_CTL_EL02", .state = ARM_CP_STATE_AA64,
168
+ }
135
.opc0 = 3, .opc1 = 5, .crn = 14, .crm = 3, .opc2 = 1,
169
s->pur = value & 0xff;
136
.type = ARM_CP_IO | ARM_CP_ALIAS,
170
break;
137
- .access = PL2_RW, .accessfn = e2h_access,
171
case 0x514: /* Pull-down */
138
+ .access = PL2_RW, .accessfn = access_el1nvvct,
172
+ if (s->id != pl061_id_luminary) {
139
.nv2_redirect_offset = 0x170 | NV2_REDIR_NO_NV1,
173
+ goto bad_offset;
140
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].ctl),
174
+ }
141
.writefn = gt_virt_ctl_write, .raw_writefn = raw_write },
175
s->pdr = value & 0xff;
142
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo vhe_reginfo[] = {
176
break;
143
.type = ARM_CP_IO | ARM_CP_ALIAS,
177
case 0x518: /* Slew rate control */
144
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval),
178
+ if (s->id != pl061_id_luminary) {
145
.nv2_redirect_offset = 0x178 | NV2_REDIR_NO_NV1,
179
+ goto bad_offset;
146
- .access = PL2_RW, .accessfn = e2h_access,
180
+ }
147
+ .access = PL2_RW, .accessfn = access_el1nvpct,
181
s->slr = value & 0xff;
148
.writefn = gt_phys_cval_write, .raw_writefn = raw_write },
182
break;
149
{ .name = "CNTV_CVAL_EL02", .state = ARM_CP_STATE_AA64,
183
case 0x51c: /* Digital enable */
150
.opc0 = 3, .opc1 = 5, .crn = 14, .crm = 3, .opc2 = 2,
184
+ if (s->id != pl061_id_luminary) {
151
.type = ARM_CP_IO | ARM_CP_ALIAS,
185
+ goto bad_offset;
152
.nv2_redirect_offset = 0x168 | NV2_REDIR_NO_NV1,
186
+ }
153
.fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval),
187
s->den = value & 0xff;
154
- .access = PL2_RW, .accessfn = e2h_access,
188
break;
155
+ .access = PL2_RW, .accessfn = access_el1nvvct,
189
case 0x520: /* Lock */
156
.writefn = gt_virt_cval_write, .raw_writefn = raw_write },
190
+ if (s->id != pl061_id_luminary) {
157
#endif
191
+ goto bad_offset;
158
};
192
+ }
193
s->locked = (value != 0xacce551);
194
break;
195
case 0x524: /* Commit */
196
+ if (s->id != pl061_id_luminary) {
197
+ goto bad_offset;
198
+ }
199
if (!s->locked)
200
s->cr = value & 0xff;
201
break;
202
case 0x528:
203
+ if (s->id != pl061_id_luminary) {
204
+ goto bad_offset;
205
+ }
206
s->amsel = value & 0xff;
207
break;
208
default:
209
- goto err_out;
210
+ bad_offset:
211
+ qemu_log_mask(LOG_GUEST_ERROR,
212
+ "pl061_write: Bad offset %x\n", (int)offset);
213
+ return;
214
}
215
pl061_update(s);
216
return;
217
-err_out:
218
- qemu_log_mask(LOG_GUEST_ERROR,
219
- "pl061_write: Bad offset %x\n", (int)offset);
220
}
221
222
static void pl061_reset(DeviceState *dev)
223
@@ -XXX,XX +XXX,XX @@ static void pl061_luminary_init(Object *obj)
224
PL061State *s = PL061(obj);
225
226
s->id = pl061_id_luminary;
227
- s->rsvd_start = 0x52c;
228
}
229
230
static void pl061_init(Object *obj)
231
@@ -XXX,XX +XXX,XX @@ static void pl061_init(Object *obj)
232
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
233
234
s->id = pl061_id;
235
- s->rsvd_start = 0x424;
236
237
memory_region_init_io(&s->iomem, obj, &pl061_ops, s, "pl061", 0x1000);
238
sysbus_init_mmio(sbd, &s->iomem);
239
--
159
--
240
2.20.1
160
2.34.1
241
242
diff view generated by jsdifflib
1
The PL061 GPIO does not itself include pullup or pulldown resistors
1
For FEAT_ECV, new registers CNTPCTSS_EL0 and CNTVCTSS_EL0 are
2
to set the value of a GPIO line treated as an output when it is
2
defined, which are "self-synchronized" views of the physical and
3
configured as an input (ie when the PL061 itself is not driving it).
3
virtual counts as seen in the CNTPCT_EL0 and CNTVCT_EL0 registers
4
In real hardware it is up to the board to add suitable pullups or
4
(meaning that no barriers are needed around accesses to them to
5
pulldowns. Currently our implementation hardwires this to "outputs
5
ensure that reads of them do not occur speculatively and out-of-order
6
pulled high", which is correct for some boards (eg the realview ones:
6
with other instructions).
7
see figure 3-29 in the "RealView Platform Baseboard for ARM926EJ-S
8
User Guide" DUI0224I), but wrong for others.
9
7
10
In particular, the wiring in the 'virt' board and the gpio-pwr device
8
For QEMU, all our system registers are self-synchronized, so we can
11
assumes that wires should be pulled low, because otherwise the
9
simply copy the existing implementation of CNTPCT_EL0 and CNTVCT_EL0
12
pull-to-high will trigger a shutdown or reset action. (The only
10
to the new register encodings.
13
reason this doesn't happen immediately on startup is due to another
14
bug in the PL061, where we don't assert the GPIOs to the correct
15
value on reset, but will do so as soon as the guest touches a
16
register and pl061_update() gets called.)
17
11
18
Add properties to the pl061 so the board can configure whether it
12
This means we now implement all the functionality required for
19
wants GPIO lines to have pullup, pulldown, or neither.
13
ID_AA64MMFR0_EL1.ECV == 0b0001.
20
14
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
22
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
16
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
17
Message-id: 20240301183219.2424889-7-peter.maydell@linaro.org
23
---
18
---
24
hw/gpio/pl061.c | 51 +++++++++++++++++++++++++++++++++++++++++++++----
19
target/arm/helper.c | 43 +++++++++++++++++++++++++++++++++++++++++++
25
1 file changed, 47 insertions(+), 4 deletions(-)
20
1 file changed, 43 insertions(+)
26
21
27
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c
22
diff --git a/target/arm/helper.c b/target/arm/helper.c
28
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
29
--- a/hw/gpio/pl061.c
24
--- a/target/arm/helper.c
30
+++ b/hw/gpio/pl061.c
25
+++ b/target/arm/helper.c
31
@@ -XXX,XX +XXX,XX @@
26
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
32
* + unnamed GPIO inputs 0..7: inputs to connect to the emulated GPIO lines
27
},
33
* + unnamed GPIO outputs 0..7: the emulated GPIO lines, considered as
34
* outputs
35
+ * + QOM property "pullups": an integer defining whether non-floating lines
36
+ * configured as inputs should be pulled up to logical 1 (ie whether in
37
+ * real hardware they have a pullup resistor on the line out of the PL061).
38
+ * This should be an 8-bit value, where bit 0 is 1 if GPIO line 0 should
39
+ * be pulled high, bit 1 configures line 1, and so on. The default is 0xff,
40
+ * indicating that all GPIO lines are pulled up to logical 1.
41
+ * + QOM property "pulldowns": an integer defining whether non-floating lines
42
+ * configured as inputs should be pulled down to logical 0 (ie whether in
43
+ * real hardware they have a pulldown resistor on the line out of the PL061).
44
+ * This should be an 8-bit value, where bit 0 is 1 if GPIO line 0 should
45
+ * be pulled low, bit 1 configures line 1, and so on. The default is 0x0.
46
+ * It is an error to set a bit in both "pullups" and "pulldowns". If a bit
47
+ * is 0 in both, then the line is considered to be floating, and it will
48
+ * not have qemu_set_irq() called on it when it is configured as an input.
49
*/
50
51
#include "qemu/osdep.h"
52
#include "hw/irq.h"
53
#include "hw/sysbus.h"
54
+#include "hw/qdev-properties.h"
55
#include "migration/vmstate.h"
56
+#include "qapi/error.h"
57
#include "qemu/log.h"
58
#include "qemu/module.h"
59
#include "qom/object.h"
60
@@ -XXX,XX +XXX,XX @@ struct PL061State {
61
qemu_irq irq;
62
qemu_irq out[N_GPIOS];
63
const unsigned char *id;
64
+ /* Properties, for non-Luminary PL061 */
65
+ uint32_t pullups;
66
+ uint32_t pulldowns;
67
};
28
};
68
29
69
static const VMStateDescription vmstate_pl061 = {
30
+/*
70
@@ -XXX,XX +XXX,XX @@ static uint8_t pl061_floating(PL061State *s)
31
+ * FEAT_ECV adds extra views of CNTVCT_EL0 and CNTPCT_EL0 which
71
*/
32
+ * are "self-synchronizing". For QEMU all sysregs are self-synchronizing,
72
floating = ~(s->pur | s->pdr);
33
+ * so our implementations here are identical to the normal registers.
73
} else {
34
+ */
74
- /* Assume outputs are pulled high. FIXME: this is board dependent. */
35
+static const ARMCPRegInfo gen_timer_ecv_cp_reginfo[] = {
75
- floating = 0;
36
+ { .name = "CNTVCTSS", .cp = 15, .crm = 14, .opc1 = 9,
76
+ floating = ~(s->pullups | s->pulldowns);
37
+ .access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_RAW | ARM_CP_IO,
77
}
38
+ .accessfn = gt_vct_access,
78
return floating & ~s->dir;
39
+ .readfn = gt_virt_cnt_read, .resetfn = arm_cp_reset_ignore,
79
}
40
+ },
80
@@ -XXX,XX +XXX,XX @@ static uint8_t pl061_pullups(PL061State *s)
41
+ { .name = "CNTVCTSS_EL0", .state = ARM_CP_STATE_AA64,
81
*/
42
+ .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 6,
82
pullups = s->pur;
43
+ .access = PL0_R, .type = ARM_CP_NO_RAW | ARM_CP_IO,
83
} else {
44
+ .accessfn = gt_vct_access, .readfn = gt_virt_cnt_read,
84
- /* Assume outputs are pulled high. FIXME: this is board dependent. */
45
+ },
85
- pullups = 0xff;
46
+ { .name = "CNTPCTSS", .cp = 15, .crm = 14, .opc1 = 8,
86
+ pullups = s->pullups;
47
+ .access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_RAW | ARM_CP_IO,
87
}
48
+ .accessfn = gt_pct_access,
88
return pullups & ~s->dir;
49
+ .readfn = gt_cnt_read, .resetfn = arm_cp_reset_ignore,
89
}
50
+ },
90
@@ -XXX,XX +XXX,XX @@ static void pl061_init(Object *obj)
51
+ { .name = "CNTPCTSS_EL0", .state = ARM_CP_STATE_AA64,
91
qdev_init_gpio_out(dev, s->out, N_GPIOS);
52
+ .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 5,
92
}
53
+ .access = PL0_R, .type = ARM_CP_NO_RAW | ARM_CP_IO,
93
54
+ .accessfn = gt_pct_access, .readfn = gt_cnt_read,
94
+static void pl061_realize(DeviceState *dev, Error **errp)
55
+ },
95
+{
96
+ PL061State *s = PL061(dev);
97
+
98
+ if (s->pullups > 0xff) {
99
+ error_setg(errp, "pullups property must be between 0 and 0xff");
100
+ return;
101
+ }
102
+ if (s->pulldowns > 0xff) {
103
+ error_setg(errp, "pulldowns property must be between 0 and 0xff");
104
+ return;
105
+ }
106
+ if (s->pullups & s->pulldowns) {
107
+ error_setg(errp, "no bit may be set both in pullups and pulldowns");
108
+ return;
109
+ }
110
+}
111
+
112
+static Property pl061_props[] = {
113
+ DEFINE_PROP_UINT32("pullups", PL061State, pullups, 0xff),
114
+ DEFINE_PROP_UINT32("pulldowns", PL061State, pulldowns, 0x0),
115
+ DEFINE_PROP_END_OF_LIST()
116
+};
56
+};
117
+
57
+
118
static void pl061_class_init(ObjectClass *klass, void *data)
58
#else
119
{
59
120
DeviceClass *dc = DEVICE_CLASS(klass);
60
/*
121
61
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
122
dc->vmsd = &vmstate_pl061;
62
},
123
dc->reset = &pl061_reset;
63
};
124
+ dc->realize = pl061_realize;
64
125
+ device_class_set_props(dc, pl061_props);
65
+/*
126
}
66
+ * CNTVCTSS_EL0 has the same trap conditions as CNTVCT_EL0, so it also
127
67
+ * is exposed to userspace by Linux.
128
static const TypeInfo pl061_info = {
68
+ */
69
+static const ARMCPRegInfo gen_timer_ecv_cp_reginfo[] = {
70
+ { .name = "CNTVCTSS_EL0", .state = ARM_CP_STATE_AA64,
71
+ .opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 6,
72
+ .access = PL0_R, .type = ARM_CP_NO_RAW | ARM_CP_IO,
73
+ .readfn = gt_virt_cnt_read,
74
+ },
75
+};
76
+
77
#endif
78
79
static void par_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
80
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
81
if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) {
82
define_arm_cp_regs(cpu, generic_timer_cp_reginfo);
83
}
84
+ if (cpu_isar_feature(aa64_ecv_traps, cpu)) {
85
+ define_arm_cp_regs(cpu, gen_timer_ecv_cp_reginfo);
86
+ }
87
if (arm_feature(env, ARM_FEATURE_VAPA)) {
88
ARMCPRegInfo vapa_cp_reginfo[] = {
89
{ .name = "PAR", .cp = 15, .crn = 7, .crm = 4, .opc1 = 0, .opc2 = 0,
129
--
90
--
130
2.20.1
91
2.34.1
131
132
diff view generated by jsdifflib
1
The Luminary variant of the PL061 has registers GPIOPUR and GPIOPDR
1
When ID_AA64MMFR0_EL1.ECV is 0b0010, a new register CNTPOFF_EL2 is
2
which lets the guest configure whether the GPIO lines are pull-up,
2
implemented. This is similar to the existing CNTVOFF_EL2, except
3
pull-down, or truly floating. Instead of assuming all lines are pulled
3
that it controls a hypervisor-adjustable offset made to the physical
4
high, honour the PUR and PDR registers.
4
counter and timer.
5
5
6
For the plain PL061, continue to assume that lines have an external
6
Implement the handling for this register, which includes control/trap
7
pull-up resistor, as we did before.
7
bits in SCR_EL3 and CNTHCTL_EL2.
8
9
The stellaris board actually relies on this behaviour -- the CD line
10
of the ssd0323 display device is connected to GPIO output C7, and it
11
is only because of a different bug which we're about to fix that we
12
weren't incorrectly driving this line high on reset and putting the
13
ssd0323 into data mode.
14
8
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
11
Message-id: 20240301183219.2424889-8-peter.maydell@linaro.org
17
---
12
---
18
hw/gpio/pl061.c | 58 +++++++++++++++++++++++++++++++++++++++++---
13
target/arm/cpu-features.h | 5 +++
19
hw/gpio/trace-events | 2 +-
14
target/arm/cpu.h | 1 +
20
2 files changed, 55 insertions(+), 5 deletions(-)
15
target/arm/helper.c | 68 +++++++++++++++++++++++++++++++++++++--
16
target/arm/trace-events | 1 +
17
4 files changed, 73 insertions(+), 2 deletions(-)
21
18
22
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c
19
diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
23
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
24
--- a/hw/gpio/pl061.c
21
--- a/target/arm/cpu-features.h
25
+++ b/hw/gpio/pl061.c
22
+++ b/target/arm/cpu-features.h
26
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_pl061 = {
23
@@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_ecv_traps(const ARMISARegisters *id)
27
}
24
return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, ECV) > 0;
28
};
25
}
29
26
30
+static uint8_t pl061_floating(PL061State *s)
27
+static inline bool isar_feature_aa64_ecv(const ARMISARegisters *id)
31
+{
28
+{
32
+ /*
29
+ return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, ECV) > 1;
33
+ * Return mask of bits which correspond to pins configured as inputs
34
+ * and which are floating (neither pulled up to 1 nor down to 0).
35
+ */
36
+ uint8_t floating;
37
+
38
+ if (s->id == pl061_id_luminary) {
39
+ /*
40
+ * If both PUR and PDR bits are clear, there is neither a pullup
41
+ * nor a pulldown in place, and the output truly floats.
42
+ */
43
+ floating = ~(s->pur | s->pdr);
44
+ } else {
45
+ /* Assume outputs are pulled high. FIXME: this is board dependent. */
46
+ floating = 0;
47
+ }
48
+ return floating & ~s->dir;
49
+}
30
+}
50
+
31
+
51
+static uint8_t pl061_pullups(PL061State *s)
32
static inline bool isar_feature_aa64_vh(const ARMISARegisters *id)
33
{
34
return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, VH) != 0;
35
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
36
index XXXXXXX..XXXXXXX 100644
37
--- a/target/arm/cpu.h
38
+++ b/target/arm/cpu.h
39
@@ -XXX,XX +XXX,XX @@ typedef struct CPUArchState {
40
uint64_t c14_cntkctl; /* Timer Control register */
41
uint64_t cnthctl_el2; /* Counter/Timer Hyp Control register */
42
uint64_t cntvoff_el2; /* Counter Virtual Offset register */
43
+ uint64_t cntpoff_el2; /* Counter Physical Offset register */
44
ARMGenericTimer c14_timer[NUM_GTIMERS];
45
uint32_t c15_cpar; /* XScale Coprocessor Access Register */
46
uint32_t c15_ticonfig; /* TI925T configuration byte. */
47
diff --git a/target/arm/helper.c b/target/arm/helper.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/target/arm/helper.c
50
+++ b/target/arm/helper.c
51
@@ -XXX,XX +XXX,XX @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
52
if (cpu_isar_feature(aa64_rme, cpu)) {
53
valid_mask |= SCR_NSE | SCR_GPF;
54
}
55
+ if (cpu_isar_feature(aa64_ecv, cpu)) {
56
+ valid_mask |= SCR_ECVEN;
57
+ }
58
} else {
59
valid_mask &= ~(SCR_RW | SCR_ST);
60
if (cpu_isar_feature(aa32_ras, cpu)) {
61
@@ -XXX,XX +XXX,XX @@ void gt_rme_post_el_change(ARMCPU *cpu, void *ignored)
62
gt_update_irq(cpu, GTIMER_PHYS);
63
}
64
65
+static uint64_t gt_phys_raw_cnt_offset(CPUARMState *env)
52
+{
66
+{
53
+ /*
67
+ if ((env->cp15.scr_el3 & SCR_ECVEN) &&
54
+ * Return mask of bits which correspond to pins configured as inputs
68
+ FIELD_EX64(env->cp15.cnthctl_el2, CNTHCTL, ECV) &&
55
+ * and which are pulled up to 1.
69
+ arm_is_el2_enabled(env) &&
56
+ */
70
+ (arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) {
57
+ uint8_t pullups;
71
+ return env->cp15.cntpoff_el2;
58
+
59
+ if (s->id == pl061_id_luminary) {
60
+ /*
61
+ * The Luminary variant of the PL061 has an extra registers which
62
+ * the guest can use to configure whether lines should be pullup
63
+ * or pulldown.
64
+ */
65
+ pullups = s->pur;
66
+ } else {
67
+ /* Assume outputs are pulled high. FIXME: this is board dependent. */
68
+ pullups = 0xff;
69
+ }
72
+ }
70
+ return pullups & ~s->dir;
73
+ return 0;
71
+}
74
+}
72
+
75
+
73
static void pl061_update(PL061State *s)
76
+static uint64_t gt_phys_cnt_offset(CPUARMState *env)
77
+{
78
+ if (arm_current_el(env) >= 2) {
79
+ return 0;
80
+ }
81
+ return gt_phys_raw_cnt_offset(env);
82
+}
83
+
84
static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
74
{
85
{
75
uint8_t changed;
86
ARMGenericTimer *gt = &cpu->env.cp15.c14_timer[timeridx];
76
uint8_t mask;
87
@@ -XXX,XX +XXX,XX @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
77
uint8_t out;
88
* reset timer to when ISTATUS next has to change
78
int i;
89
*/
79
+ uint8_t pullups = pl061_pullups(s);
90
uint64_t offset = timeridx == GTIMER_VIRT ?
80
+ uint8_t floating = pl061_floating(s);
91
- cpu->env.cp15.cntvoff_el2 : 0;
81
92
+ cpu->env.cp15.cntvoff_el2 : gt_phys_raw_cnt_offset(&cpu->env);
82
- trace_pl061_update(DEVICE(s)->canonical_path, s->dir, s->data);
93
uint64_t count = gt_get_countervalue(&cpu->env);
83
+ trace_pl061_update(DEVICE(s)->canonical_path, s->dir, s->data,
94
/* Note that this must be unsigned 64 bit arithmetic: */
84
+ pullups, floating);
95
int istatus = count - offset >= gt->cval;
85
96
@@ -XXX,XX +XXX,XX @@ static void gt_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri,
86
- /* Outputs float high. */
97
87
- /* FIXME: This is board dependent. */
98
static uint64_t gt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
88
- out = (s->data & s->dir) | ~s->dir;
99
{
89
+ /*
100
- return gt_get_countervalue(env);
90
+ * Pins configured as output are driven from the data register;
101
+ return gt_get_countervalue(env) - gt_phys_cnt_offset(env);
91
+ * otherwise if they're pulled up they're 1, and if they're floating
102
}
92
+ * then we give them the same value they had previously, so we don't
103
93
+ * report any change to the other end.
104
static uint64_t gt_virt_cnt_offset(CPUARMState *env)
94
+ */
105
@@ -XXX,XX +XXX,XX @@ static uint64_t gt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri,
95
+ out = (s->data & s->dir) | pullups | (s->old_out_data & floating);
106
case GTIMER_HYPVIRT:
96
changed = s->old_out_data ^ out;
107
offset = gt_virt_cnt_offset(env);
97
if (changed) {
108
break;
98
s->old_out_data = out;
109
+ case GTIMER_PHYS:
99
diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events
110
+ offset = gt_phys_cnt_offset(env);
111
+ break;
112
}
113
114
return (uint32_t)(env->cp15.c14_timer[timeridx].cval -
115
@@ -XXX,XX +XXX,XX @@ static void gt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
116
case GTIMER_HYPVIRT:
117
offset = gt_virt_cnt_offset(env);
118
break;
119
+ case GTIMER_PHYS:
120
+ offset = gt_phys_cnt_offset(env);
121
+ break;
122
}
123
124
trace_arm_gt_tval_write(timeridx, value);
125
@@ -XXX,XX +XXX,XX @@ static void gt_cnthctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
126
R_CNTHCTL_EL1NVVCT_MASK |
127
R_CNTHCTL_EVNTIS_MASK;
128
}
129
+ if (cpu_isar_feature(aa64_ecv, cpu)) {
130
+ valid_mask |= R_CNTHCTL_ECV_MASK;
131
+ }
132
133
/* Clear RES0 bits */
134
value &= valid_mask;
135
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo gen_timer_ecv_cp_reginfo[] = {
136
},
137
};
138
139
+static CPAccessResult gt_cntpoff_access(CPUARMState *env,
140
+ const ARMCPRegInfo *ri,
141
+ bool isread)
142
+{
143
+ if (arm_current_el(env) == 2 && !(env->cp15.scr_el3 & SCR_ECVEN)) {
144
+ return CP_ACCESS_TRAP_EL3;
145
+ }
146
+ return CP_ACCESS_OK;
147
+}
148
+
149
+static void gt_cntpoff_write(CPUARMState *env, const ARMCPRegInfo *ri,
150
+ uint64_t value)
151
+{
152
+ ARMCPU *cpu = env_archcpu(env);
153
+
154
+ trace_arm_gt_cntpoff_write(value);
155
+ raw_write(env, ri, value);
156
+ gt_recalc_timer(cpu, GTIMER_PHYS);
157
+}
158
+
159
+static const ARMCPRegInfo gen_timer_cntpoff_reginfo = {
160
+ .name = "CNTPOFF_EL2", .state = ARM_CP_STATE_AA64,
161
+ .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 0, .opc2 = 6,
162
+ .access = PL2_RW, .type = ARM_CP_IO, .resetvalue = 0,
163
+ .accessfn = gt_cntpoff_access, .writefn = gt_cntpoff_write,
164
+ .nv2_redirect_offset = 0x1a8,
165
+ .fieldoffset = offsetof(CPUARMState, cp15.cntpoff_el2),
166
+};
167
#else
168
169
/*
170
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
171
if (cpu_isar_feature(aa64_ecv_traps, cpu)) {
172
define_arm_cp_regs(cpu, gen_timer_ecv_cp_reginfo);
173
}
174
+#ifndef CONFIG_USER_ONLY
175
+ if (cpu_isar_feature(aa64_ecv, cpu)) {
176
+ define_one_arm_cp_reg(cpu, &gen_timer_cntpoff_reginfo);
177
+ }
178
+#endif
179
if (arm_feature(env, ARM_FEATURE_VAPA)) {
180
ARMCPRegInfo vapa_cp_reginfo[] = {
181
{ .name = "PAR", .cp = 15, .crn = 7, .crm = 4, .opc1 = 0, .opc2 = 0,
182
diff --git a/target/arm/trace-events b/target/arm/trace-events
100
index XXXXXXX..XXXXXXX 100644
183
index XXXXXXX..XXXXXXX 100644
101
--- a/hw/gpio/trace-events
184
--- a/target/arm/trace-events
102
+++ b/hw/gpio/trace-events
185
+++ b/target/arm/trace-events
103
@@ -XXX,XX +XXX,XX @@ nrf51_gpio_set(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
186
@@ -XXX,XX +XXX,XX @@ arm_gt_tval_write(int timer, uint64_t value) "gt_tval_write: timer %d value 0x%"
104
nrf51_gpio_update_output_irq(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
187
arm_gt_ctl_write(int timer, uint64_t value) "gt_ctl_write: timer %d value 0x%" PRIx64
105
188
arm_gt_imask_toggle(int timer) "gt_ctl_write: timer %d IMASK toggle"
106
# pl061.c
189
arm_gt_cntvoff_write(uint64_t value) "gt_cntvoff_write: value 0x%" PRIx64
107
-pl061_update(const char *id, uint32_t dir, uint32_t data) "%s GPIODIR 0x%x GPIODATA 0x%x"
190
+arm_gt_cntpoff_write(uint64_t value) "gt_cntpoff_write: value 0x%" PRIx64
108
+pl061_update(const char *id, uint32_t dir, uint32_t data, uint32_t pullups, uint32_t floating) "%s GPIODIR 0x%x GPIODATA 0x%x pullups 0x%x floating 0x%x"
191
arm_gt_update_irq(int timer, int irqstate) "gt_update_irq: timer %d irqstate %d"
109
pl061_set_output(const char *id, int gpio, int level) "%s setting output %d to %d"
192
110
pl061_input_change(const char *id, int gpio, int level) "%s input %d changed to %d"
193
# kvm.c
111
pl061_update_istate(const char *id, uint32_t istate, uint32_t im, int level) "%s GPIORIS 0x%x GPIOIE 0x%x interrupt level %d"
112
--
194
--
113
2.20.1
195
2.34.1
114
115
diff view generated by jsdifflib
1
Add tracepoints for reads and writes to the PL061 registers. This requires
1
Enable all FEAT_ECV features on the 'max' CPU.
2
restructuring pl061_read() to only return after the tracepoint, rather
3
than having lots of early-returns.
4
2
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
3
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
4
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20240301183219.2424889-9-peter.maydell@linaro.org
8
---
7
---
9
hw/gpio/pl061.c | 70 ++++++++++++++++++++++++++++++--------------
8
docs/system/arm/emulation.rst | 1 +
10
hw/gpio/trace-events | 2 ++
9
target/arm/tcg/cpu64.c | 1 +
11
2 files changed, 50 insertions(+), 22 deletions(-)
10
2 files changed, 2 insertions(+)
12
11
13
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c
12
diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst
14
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/gpio/pl061.c
14
--- a/docs/system/arm/emulation.rst
16
+++ b/hw/gpio/pl061.c
15
+++ b/docs/system/arm/emulation.rst
17
@@ -XXX,XX +XXX,XX @@ static uint64_t pl061_read(void *opaque, hwaddr offset,
16
@@ -XXX,XX +XXX,XX @@ the following architecture extensions:
18
unsigned size)
17
- FEAT_DotProd (Advanced SIMD dot product instructions)
19
{
18
- FEAT_DoubleFault (Double Fault Extension)
20
PL061State *s = (PL061State *)opaque;
19
- FEAT_E0PD (Preventing EL0 access to halves of address maps)
21
+ uint64_t r = 0;
20
+- FEAT_ECV (Enhanced Counter Virtualization)
22
21
- FEAT_EPAC (Enhanced pointer authentication)
23
switch (offset) {
22
- FEAT_ETS (Enhanced Translation Synchronization)
24
case 0x0 ... 0x3ff: /* Data */
23
- FEAT_EVT (Enhanced Virtualization Traps)
25
- return s->data & (offset >> 2);
24
diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
26
+ r = s->data & (offset >> 2);
27
+ break;
28
case 0x400: /* Direction */
29
- return s->dir;
30
+ r = s->dir;
31
+ break;
32
case 0x404: /* Interrupt sense */
33
- return s->isense;
34
+ r = s->isense;
35
+ break;
36
case 0x408: /* Interrupt both edges */
37
- return s->ibe;
38
+ r = s->ibe;
39
+ break;
40
case 0x40c: /* Interrupt event */
41
- return s->iev;
42
+ r = s->iev;
43
+ break;
44
case 0x410: /* Interrupt mask */
45
- return s->im;
46
+ r = s->im;
47
+ break;
48
case 0x414: /* Raw interrupt status */
49
- return s->istate;
50
+ r = s->istate;
51
+ break;
52
case 0x418: /* Masked interrupt status */
53
- return s->istate & s->im;
54
+ r = s->istate & s->im;
55
+ break;
56
case 0x420: /* Alternate function select */
57
- return s->afsel;
58
+ r = s->afsel;
59
+ break;
60
case 0x500: /* 2mA drive */
61
if (s->id != pl061_id_luminary) {
62
goto bad_offset;
63
}
64
- return s->dr2r;
65
+ r = s->dr2r;
66
+ break;
67
case 0x504: /* 4mA drive */
68
if (s->id != pl061_id_luminary) {
69
goto bad_offset;
70
}
71
- return s->dr4r;
72
+ r = s->dr4r;
73
+ break;
74
case 0x508: /* 8mA drive */
75
if (s->id != pl061_id_luminary) {
76
goto bad_offset;
77
}
78
- return s->dr8r;
79
+ r = s->dr8r;
80
+ break;
81
case 0x50c: /* Open drain */
82
if (s->id != pl061_id_luminary) {
83
goto bad_offset;
84
}
85
- return s->odr;
86
+ r = s->odr;
87
+ break;
88
case 0x510: /* Pull-up */
89
if (s->id != pl061_id_luminary) {
90
goto bad_offset;
91
}
92
- return s->pur;
93
+ r = s->pur;
94
+ break;
95
case 0x514: /* Pull-down */
96
if (s->id != pl061_id_luminary) {
97
goto bad_offset;
98
}
99
- return s->pdr;
100
+ r = s->pdr;
101
+ break;
102
case 0x518: /* Slew rate control */
103
if (s->id != pl061_id_luminary) {
104
goto bad_offset;
105
}
106
- return s->slr;
107
+ r = s->slr;
108
+ break;
109
case 0x51c: /* Digital enable */
110
if (s->id != pl061_id_luminary) {
111
goto bad_offset;
112
}
113
- return s->den;
114
+ r = s->den;
115
+ break;
116
case 0x520: /* Lock */
117
if (s->id != pl061_id_luminary) {
118
goto bad_offset;
119
}
120
- return s->locked;
121
+ r = s->locked;
122
+ break;
123
case 0x524: /* Commit */
124
if (s->id != pl061_id_luminary) {
125
goto bad_offset;
126
}
127
- return s->cr;
128
+ r = s->cr;
129
+ break;
130
case 0x528: /* Analog mode select */
131
if (s->id != pl061_id_luminary) {
132
goto bad_offset;
133
}
134
- return s->amsel;
135
+ r = s->amsel;
136
+ break;
137
case 0xfd0 ... 0xfff: /* ID registers */
138
- return s->id[(offset - 0xfd0) >> 2];
139
+ r = s->id[(offset - 0xfd0) >> 2];
140
+ break;
141
default:
142
bad_offset:
143
qemu_log_mask(LOG_GUEST_ERROR,
144
"pl061_read: Bad offset %x\n", (int)offset);
145
break;
146
}
147
- return 0;
148
+
149
+ trace_pl061_read(DEVICE(s)->canonical_path, offset, r);
150
+ return r;
151
}
152
153
static void pl061_write(void *opaque, hwaddr offset,
154
@@ -XXX,XX +XXX,XX @@ static void pl061_write(void *opaque, hwaddr offset,
155
PL061State *s = (PL061State *)opaque;
156
uint8_t mask;
157
158
+ trace_pl061_write(DEVICE(s)->canonical_path, offset, value);
159
+
160
switch (offset) {
161
case 0 ... 0x3ff:
162
mask = (offset >> 2) & s->dir;
163
diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events
164
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
165
--- a/hw/gpio/trace-events
26
--- a/target/arm/tcg/cpu64.c
166
+++ b/hw/gpio/trace-events
27
+++ b/target/arm/tcg/cpu64.c
167
@@ -XXX,XX +XXX,XX @@ pl061_update(const char *id, uint32_t dir, uint32_t data) "%s GPIODIR 0x%x GPIOD
28
@@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj)
168
pl061_set_output(const char *id, int gpio, int level) "%s setting output %d to %d"
29
t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN64_2, 2); /* 64k stage2 supported */
169
pl061_input_change(const char *id, int gpio, int level) "%s input %d changed to %d"
30
t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN4_2, 2); /* 4k stage2 supported */
170
pl061_update_istate(const char *id, uint32_t istate, uint32_t im, int level) "%s GPIORIS 0x%x GPIOIE 0x%x interrupt level %d"
31
t = FIELD_DP64(t, ID_AA64MMFR0, FGT, 1); /* FEAT_FGT */
171
+pl061_read(const char *id, uint64_t offset, uint64_t r) "%s offset 0x%" PRIx64 " value 0x%" PRIx64
32
+ t = FIELD_DP64(t, ID_AA64MMFR0, ECV, 2); /* FEAT_ECV */
172
+pl061_write(const char *id, uint64_t offset, uint64_t value) "%s offset 0x%" PRIx64 " value 0x%" PRIx64
33
cpu->isar.id_aa64mmfr0 = t;
173
34
174
# sifive_gpio.c
35
t = cpu->isar.id_aa64mmfr1;
175
sifive_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" PRIx64
176
--
36
--
177
2.20.1
37
2.34.1
178
38
179
39
diff view generated by jsdifflib
1
Convert the use of the DPRINTF debug macro in the PL061 model to
1
From: Inès Varhol <ines.varhol@telecom-paris.fr>
2
use tracepoints.
3
2
3
Features supported :
4
- the 8 STM32L4x5 GPIOs are initialized with their reset values
5
(except IDR, see below)
6
- input mode : setting a pin in input mode "externally" (using input
7
irqs) results in an out irq (transmitted to SYSCFG)
8
- output mode : setting a bit in ODR sets the corresponding out irq
9
(if this line is configured in output mode)
10
- pull-up, pull-down
11
- push-pull, open-drain
12
13
Difference with the real GPIOs :
14
- Alternate Function and Analog mode aren't implemented :
15
pins in AF/Analog behave like pins in input mode
16
- floating pins stay at their last value
17
- register IDR reset values differ from the real one :
18
values are coherent with the other registers reset values
19
and the fact that AF/Analog modes aren't implemented
20
- setting I/O output speed isn't supported
21
- locking port bits isn't supported
22
- ADC function isn't supported
23
- GPIOH has 16 pins instead of 2 pins
24
- writing to registers LCKR, AFRL, AFRH and ASCR is ineffective
25
26
Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
27
Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
28
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
29
Acked-by: Alistair Francis <alistair.francis@wdc.com>
30
Message-id: 20240305210444.310665-2-ines.varhol@telecom-paris.fr
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
31
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
---
32
---
8
hw/gpio/pl061.c | 27 +++++++++------------------
33
MAINTAINERS | 1 +
9
hw/gpio/trace-events | 6 ++++++
34
docs/system/arm/b-l475e-iot01a.rst | 2 +-
10
2 files changed, 15 insertions(+), 18 deletions(-)
35
include/hw/gpio/stm32l4x5_gpio.h | 70 +++++
36
hw/gpio/stm32l4x5_gpio.c | 477 +++++++++++++++++++++++++++++
37
hw/gpio/Kconfig | 3 +
38
hw/gpio/meson.build | 1 +
39
hw/gpio/trace-events | 6 +
40
7 files changed, 559 insertions(+), 1 deletion(-)
41
create mode 100644 include/hw/gpio/stm32l4x5_gpio.h
42
create mode 100644 hw/gpio/stm32l4x5_gpio.c
11
43
12
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c
44
diff --git a/MAINTAINERS b/MAINTAINERS
13
index XXXXXXX..XXXXXXX 100644
45
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/gpio/pl061.c
46
--- a/MAINTAINERS
15
+++ b/hw/gpio/pl061.c
47
+++ b/MAINTAINERS
48
@@ -XXX,XX +XXX,XX @@ F: hw/arm/stm32l4x5_soc.c
49
F: hw/misc/stm32l4x5_exti.c
50
F: hw/misc/stm32l4x5_syscfg.c
51
F: hw/misc/stm32l4x5_rcc.c
52
+F: hw/gpio/stm32l4x5_gpio.c
53
F: include/hw/*/stm32l4x5_*.h
54
55
B-L475E-IOT01A IoT Node
56
diff --git a/docs/system/arm/b-l475e-iot01a.rst b/docs/system/arm/b-l475e-iot01a.rst
57
index XXXXXXX..XXXXXXX 100644
58
--- a/docs/system/arm/b-l475e-iot01a.rst
59
+++ b/docs/system/arm/b-l475e-iot01a.rst
60
@@ -XXX,XX +XXX,XX @@ Currently B-L475E-IOT01A machine's only supports the following devices:
61
- STM32L4x5 EXTI (Extended interrupts and events controller)
62
- STM32L4x5 SYSCFG (System configuration controller)
63
- STM32L4x5 RCC (Reset and clock control)
64
+- STM32L4x5 GPIOs (General-purpose I/Os)
65
66
Missing devices
67
"""""""""""""""
68
@@ -XXX,XX +XXX,XX @@ Missing devices
69
The B-L475E-IOT01A does *not* support the following devices:
70
71
- Serial ports (UART)
72
-- General-purpose I/Os (GPIO)
73
- Analog to Digital Converter (ADC)
74
- SPI controller
75
- Timer controller (TIMER)
76
diff --git a/include/hw/gpio/stm32l4x5_gpio.h b/include/hw/gpio/stm32l4x5_gpio.h
77
new file mode 100644
78
index XXXXXXX..XXXXXXX
79
--- /dev/null
80
+++ b/include/hw/gpio/stm32l4x5_gpio.h
16
@@ -XXX,XX +XXX,XX @@
81
@@ -XXX,XX +XXX,XX @@
17
#include "qemu/log.h"
82
+/*
18
#include "qemu/module.h"
83
+ * STM32L4x5 GPIO (General Purpose Input/Ouput)
19
#include "qom/object.h"
84
+ *
20
-
85
+ * Copyright (c) 2024 Arnaud Minier <arnaud.minier@telecom-paris.fr>
21
-//#define DEBUG_PL061 1
86
+ * Copyright (c) 2024 Inès Varhol <ines.varhol@telecom-paris.fr>
22
-
87
+ *
23
-#ifdef DEBUG_PL061
88
+ * SPDX-License-Identifier: GPL-2.0-or-later
24
-#define DPRINTF(fmt, ...) \
89
+ *
25
-do { printf("pl061: " fmt , ## __VA_ARGS__); } while (0)
90
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
26
-#define BADF(fmt, ...) \
91
+ * See the COPYING file in the top-level directory.
27
-do { fprintf(stderr, "pl061: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
92
+ */
28
-#else
93
+
29
-#define DPRINTF(fmt, ...) do {} while(0)
94
+/*
30
-#define BADF(fmt, ...) \
95
+ * The reference used is the STMicroElectronics RM0351 Reference manual
31
-do { fprintf(stderr, "pl061: error: " fmt , ## __VA_ARGS__);} while (0)
96
+ * for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs.
32
-#endif
97
+ * https://www.st.com/en/microcontrollers-microprocessors/stm32l4x5/documentation.html
98
+ */
99
+
100
+#ifndef HW_STM32L4X5_GPIO_H
101
+#define HW_STM32L4X5_GPIO_H
102
+
103
+#include "hw/sysbus.h"
104
+#include "qom/object.h"
105
+
106
+#define TYPE_STM32L4X5_GPIO "stm32l4x5-gpio"
107
+OBJECT_DECLARE_SIMPLE_TYPE(Stm32l4x5GpioState, STM32L4X5_GPIO)
108
+
109
+#define GPIO_NUM_PINS 16
110
+
111
+struct Stm32l4x5GpioState {
112
+ SysBusDevice parent_obj;
113
+
114
+ MemoryRegion mmio;
115
+
116
+ /* GPIO registers */
117
+ uint32_t moder;
118
+ uint32_t otyper;
119
+ uint32_t ospeedr;
120
+ uint32_t pupdr;
121
+ uint32_t idr;
122
+ uint32_t odr;
123
+ uint32_t lckr;
124
+ uint32_t afrl;
125
+ uint32_t afrh;
126
+ uint32_t ascr;
127
+
128
+ /* GPIO registers reset values */
129
+ uint32_t moder_reset;
130
+ uint32_t ospeedr_reset;
131
+ uint32_t pupdr_reset;
132
+
133
+ /*
134
+ * External driving of pins.
135
+ * The pins can be set externally through the device
136
+ * anonymous input GPIOs lines under certain conditions.
137
+ * The pin must not be in push-pull output mode,
138
+ * and can't be set high in open-drain mode.
139
+ * Pins driven externally and configured to
140
+ * output mode will in general be "disconnected"
141
+ * (see `get_gpio_pinmask_to_disconnect()`)
142
+ */
143
+ uint16_t disconnected_pins;
144
+ uint16_t pins_connected_high;
145
+
146
+ char *name;
147
+ Clock *clk;
148
+ qemu_irq pin[GPIO_NUM_PINS];
149
+};
150
+
151
+#endif
152
diff --git a/hw/gpio/stm32l4x5_gpio.c b/hw/gpio/stm32l4x5_gpio.c
153
new file mode 100644
154
index XXXXXXX..XXXXXXX
155
--- /dev/null
156
+++ b/hw/gpio/stm32l4x5_gpio.c
157
@@ -XXX,XX +XXX,XX @@
158
+/*
159
+ * STM32L4x5 GPIO (General Purpose Input/Ouput)
160
+ *
161
+ * Copyright (c) 2024 Arnaud Minier <arnaud.minier@telecom-paris.fr>
162
+ * Copyright (c) 2024 Inès Varhol <ines.varhol@telecom-paris.fr>
163
+ *
164
+ * SPDX-License-Identifier: GPL-2.0-or-later
165
+ *
166
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
167
+ * See the COPYING file in the top-level directory.
168
+ */
169
+
170
+/*
171
+ * The reference used is the STMicroElectronics RM0351 Reference manual
172
+ * for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs.
173
+ * https://www.st.com/en/microcontrollers-microprocessors/stm32l4x5/documentation.html
174
+ */
175
+
176
+#include "qemu/osdep.h"
177
+#include "qemu/log.h"
178
+#include "hw/gpio/stm32l4x5_gpio.h"
179
+#include "hw/irq.h"
180
+#include "hw/qdev-clock.h"
181
+#include "hw/qdev-properties.h"
182
+#include "qapi/visitor.h"
183
+#include "qapi/error.h"
184
+#include "migration/vmstate.h"
33
+#include "trace.h"
185
+#include "trace.h"
34
186
+
35
static const uint8_t pl061_id[12] =
187
+#define GPIO_MODER 0x00
36
{ 0x00, 0x00, 0x00, 0x00, 0x61, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
188
+#define GPIO_OTYPER 0x04
37
@@ -XXX,XX +XXX,XX @@ static void pl061_update(PL061State *s)
189
+#define GPIO_OSPEEDR 0x08
38
uint8_t out;
190
+#define GPIO_PUPDR 0x0C
39
int i;
191
+#define GPIO_IDR 0x10
40
192
+#define GPIO_ODR 0x14
41
- DPRINTF("dir = %d, data = %d\n", s->dir, s->data);
193
+#define GPIO_BSRR 0x18
42
+ trace_pl061_update(DEVICE(s)->canonical_path, s->dir, s->data);
194
+#define GPIO_LCKR 0x1C
43
195
+#define GPIO_AFRL 0x20
44
/* Outputs float high. */
196
+#define GPIO_AFRH 0x24
45
/* FIXME: This is board dependent. */
197
+#define GPIO_BRR 0x28
46
@@ -XXX,XX +XXX,XX @@ static void pl061_update(PL061State *s)
198
+#define GPIO_ASCR 0x2C
47
for (i = 0; i < N_GPIOS; i++) {
199
+
48
mask = 1 << i;
200
+/* 0b11111111_11111111_00000000_00000000 */
49
if (changed & mask) {
201
+#define RESERVED_BITS_MASK 0xFFFF0000
50
- DPRINTF("Set output %d = %d\n", i, (out & mask) != 0);
202
+
51
- qemu_set_irq(s->out[i], (out & mask) != 0);
203
+static void update_gpio_idr(Stm32l4x5GpioState *s);
52
+ int level = (out & mask) != 0;
204
+
53
+ trace_pl061_set_output(DEVICE(s)->canonical_path, i, level);
205
+static bool is_pull_up(Stm32l4x5GpioState *s, unsigned pin)
54
+ qemu_set_irq(s->out[i], level);
206
+{
55
}
207
+ return extract32(s->pupdr, 2 * pin, 2) == 1;
56
}
208
+}
57
}
209
+
58
@@ -XXX,XX +XXX,XX @@ static void pl061_update(PL061State *s)
210
+static bool is_pull_down(Stm32l4x5GpioState *s, unsigned pin)
59
for (i = 0; i < N_GPIOS; i++) {
211
+{
60
mask = 1 << i;
212
+ return extract32(s->pupdr, 2 * pin, 2) == 2;
61
if (changed & mask) {
213
+}
62
- DPRINTF("Changed input %d = %d\n", i, (s->data & mask) != 0);
214
+
63
+ trace_pl061_input_change(DEVICE(s)->canonical_path, i,
215
+static bool is_output(Stm32l4x5GpioState *s, unsigned pin)
64
+ (s->data & mask) != 0);
216
+{
65
217
+ return extract32(s->moder, 2 * pin, 2) == 1;
66
if (!(s->isense & mask)) {
218
+}
67
/* Edge interrupt */
219
+
68
@@ -XXX,XX +XXX,XX @@ static void pl061_update(PL061State *s)
220
+static bool is_open_drain(Stm32l4x5GpioState *s, unsigned pin)
69
/* Level interrupt */
221
+{
70
s->istate |= ~(s->data ^ s->iev) & s->isense;
222
+ return extract32(s->otyper, pin, 1) == 1;
71
223
+}
72
- DPRINTF("istate = %02X\n", s->istate);
224
+
73
+ trace_pl061_update_istate(DEVICE(s)->canonical_path,
225
+static bool is_push_pull(Stm32l4x5GpioState *s, unsigned pin)
74
+ s->istate, s->im, (s->istate & s->im) != 0);
226
+{
75
227
+ return extract32(s->otyper, pin, 1) == 0;
76
qemu_set_irq(s->irq, (s->istate & s->im) != 0);
228
+}
77
}
229
+
230
+static void stm32l4x5_gpio_reset_hold(Object *obj)
231
+{
232
+ Stm32l4x5GpioState *s = STM32L4X5_GPIO(obj);
233
+
234
+ s->moder = s->moder_reset;
235
+ s->otyper = 0x00000000;
236
+ s->ospeedr = s->ospeedr_reset;
237
+ s->pupdr = s->pupdr_reset;
238
+ s->idr = 0x00000000;
239
+ s->odr = 0x00000000;
240
+ s->lckr = 0x00000000;
241
+ s->afrl = 0x00000000;
242
+ s->afrh = 0x00000000;
243
+ s->ascr = 0x00000000;
244
+
245
+ s->disconnected_pins = 0xFFFF;
246
+ s->pins_connected_high = 0x0000;
247
+ update_gpio_idr(s);
248
+}
249
+
250
+static void stm32l4x5_gpio_set(void *opaque, int line, int level)
251
+{
252
+ Stm32l4x5GpioState *s = opaque;
253
+ /*
254
+ * The pin isn't set if line is configured in output mode
255
+ * except if level is 0 and the output is open-drain.
256
+ * This way there will be no short-circuit prone situations.
257
+ */
258
+ if (is_output(s, line) && !(is_open_drain(s, line) && (level == 0))) {
259
+ qemu_log_mask(LOG_GUEST_ERROR, "Line %d can't be driven externally\n",
260
+ line);
261
+ return;
262
+ }
263
+
264
+ s->disconnected_pins &= ~(1 << line);
265
+ if (level) {
266
+ s->pins_connected_high |= (1 << line);
267
+ } else {
268
+ s->pins_connected_high &= ~(1 << line);
269
+ }
270
+ trace_stm32l4x5_gpio_pins(s->name, s->disconnected_pins,
271
+ s->pins_connected_high);
272
+ update_gpio_idr(s);
273
+}
274
+
275
+
276
+static void update_gpio_idr(Stm32l4x5GpioState *s)
277
+{
278
+ uint32_t new_idr_mask = 0;
279
+ uint32_t new_idr = s->odr;
280
+ uint32_t old_idr = s->idr;
281
+ int new_pin_state, old_pin_state;
282
+
283
+ for (int i = 0; i < GPIO_NUM_PINS; i++) {
284
+ if (is_output(s, i)) {
285
+ if (is_push_pull(s, i)) {
286
+ new_idr_mask |= (1 << i);
287
+ } else if (!(s->odr & (1 << i))) {
288
+ /* open-drain ODR 0 */
289
+ new_idr_mask |= (1 << i);
290
+ /* open-drain ODR 1 */
291
+ } else if (!(s->disconnected_pins & (1 << i)) &&
292
+ !(s->pins_connected_high & (1 << i))) {
293
+ /* open-drain ODR 1 with pin connected low */
294
+ new_idr_mask |= (1 << i);
295
+ new_idr &= ~(1 << i);
296
+ /* open-drain ODR 1 with unactive pin */
297
+ } else if (is_pull_up(s, i)) {
298
+ new_idr_mask |= (1 << i);
299
+ } else if (is_pull_down(s, i)) {
300
+ new_idr_mask |= (1 << i);
301
+ new_idr &= ~(1 << i);
302
+ }
303
+ /*
304
+ * The only case left is for open-drain ODR 1
305
+ * with unactive pin without pull-up or pull-down :
306
+ * the value is floating.
307
+ */
308
+ /* input or analog mode with connected pin */
309
+ } else if (!(s->disconnected_pins & (1 << i))) {
310
+ if (s->pins_connected_high & (1 << i)) {
311
+ /* pin high */
312
+ new_idr_mask |= (1 << i);
313
+ new_idr |= (1 << i);
314
+ } else {
315
+ /* pin low */
316
+ new_idr_mask |= (1 << i);
317
+ new_idr &= ~(1 << i);
318
+ }
319
+ /* input or analog mode with disconnected pin */
320
+ } else {
321
+ if (is_pull_up(s, i)) {
322
+ /* pull-up */
323
+ new_idr_mask |= (1 << i);
324
+ new_idr |= (1 << i);
325
+ } else if (is_pull_down(s, i)) {
326
+ /* pull-down */
327
+ new_idr_mask |= (1 << i);
328
+ new_idr &= ~(1 << i);
329
+ }
330
+ /*
331
+ * The only case left is for a disconnected pin
332
+ * without pull-up or pull-down :
333
+ * the value is floating.
334
+ */
335
+ }
336
+ }
337
+
338
+ s->idr = (old_idr & ~new_idr_mask) | (new_idr & new_idr_mask);
339
+ trace_stm32l4x5_gpio_update_idr(s->name, old_idr, s->idr);
340
+
341
+ for (int i = 0; i < GPIO_NUM_PINS; i++) {
342
+ if (new_idr_mask & (1 << i)) {
343
+ new_pin_state = (new_idr & (1 << i)) > 0;
344
+ old_pin_state = (old_idr & (1 << i)) > 0;
345
+ if (new_pin_state > old_pin_state) {
346
+ qemu_irq_raise(s->pin[i]);
347
+ } else if (new_pin_state < old_pin_state) {
348
+ qemu_irq_lower(s->pin[i]);
349
+ }
350
+ }
351
+ }
352
+}
353
+
354
+/*
355
+ * Return mask of pins that are both configured in output
356
+ * mode and externally driven (except pins in open-drain
357
+ * mode externally set to 0).
358
+ */
359
+static uint32_t get_gpio_pinmask_to_disconnect(Stm32l4x5GpioState *s)
360
+{
361
+ uint32_t pins_to_disconnect = 0;
362
+ for (int i = 0; i < GPIO_NUM_PINS; i++) {
363
+ /* for each connected pin in output mode */
364
+ if (!(s->disconnected_pins & (1 << i)) && is_output(s, i)) {
365
+ /* if either push-pull or high level */
366
+ if (is_push_pull(s, i) || s->pins_connected_high & (1 << i)) {
367
+ pins_to_disconnect |= (1 << i);
368
+ qemu_log_mask(LOG_GUEST_ERROR,
369
+ "Line %d can't be driven externally\n",
370
+ i);
371
+ }
372
+ }
373
+ }
374
+ return pins_to_disconnect;
375
+}
376
+
377
+/*
378
+ * Set field `disconnected_pins` and call `update_gpio_idr()`
379
+ */
380
+static void disconnect_gpio_pins(Stm32l4x5GpioState *s, uint16_t lines)
381
+{
382
+ s->disconnected_pins |= lines;
383
+ trace_stm32l4x5_gpio_pins(s->name, s->disconnected_pins,
384
+ s->pins_connected_high);
385
+ update_gpio_idr(s);
386
+}
387
+
388
+static void disconnected_pins_set(Object *obj, Visitor *v,
389
+ const char *name, void *opaque, Error **errp)
390
+{
391
+ Stm32l4x5GpioState *s = STM32L4X5_GPIO(obj);
392
+ uint16_t value;
393
+ if (!visit_type_uint16(v, name, &value, errp)) {
394
+ return;
395
+ }
396
+ disconnect_gpio_pins(s, value);
397
+}
398
+
399
+static void disconnected_pins_get(Object *obj, Visitor *v,
400
+ const char *name, void *opaque, Error **errp)
401
+{
402
+ visit_type_uint16(v, name, (uint16_t *)opaque, errp);
403
+}
404
+
405
+static void clock_freq_get(Object *obj, Visitor *v,
406
+ const char *name, void *opaque, Error **errp)
407
+{
408
+ Stm32l4x5GpioState *s = STM32L4X5_GPIO(obj);
409
+ uint32_t clock_freq_hz = clock_get_hz(s->clk);
410
+ visit_type_uint32(v, name, &clock_freq_hz, errp);
411
+}
412
+
413
+static void stm32l4x5_gpio_write(void *opaque, hwaddr addr,
414
+ uint64_t val64, unsigned int size)
415
+{
416
+ Stm32l4x5GpioState *s = opaque;
417
+
418
+ uint32_t value = val64;
419
+ trace_stm32l4x5_gpio_write(s->name, addr, val64);
420
+
421
+ switch (addr) {
422
+ case GPIO_MODER:
423
+ s->moder = value;
424
+ disconnect_gpio_pins(s, get_gpio_pinmask_to_disconnect(s));
425
+ qemu_log_mask(LOG_UNIMP,
426
+ "%s: Analog and AF modes aren't supported\n\
427
+ Analog and AF mode behave like input mode\n",
428
+ __func__);
429
+ return;
430
+ case GPIO_OTYPER:
431
+ s->otyper = value & ~RESERVED_BITS_MASK;
432
+ disconnect_gpio_pins(s, get_gpio_pinmask_to_disconnect(s));
433
+ return;
434
+ case GPIO_OSPEEDR:
435
+ qemu_log_mask(LOG_UNIMP,
436
+ "%s: Changing I/O output speed isn't supported\n\
437
+ I/O speed is already maximal\n",
438
+ __func__);
439
+ s->ospeedr = value;
440
+ return;
441
+ case GPIO_PUPDR:
442
+ s->pupdr = value;
443
+ update_gpio_idr(s);
444
+ return;
445
+ case GPIO_IDR:
446
+ qemu_log_mask(LOG_UNIMP,
447
+ "%s: GPIO->IDR is read-only\n",
448
+ __func__);
449
+ return;
450
+ case GPIO_ODR:
451
+ s->odr = value & ~RESERVED_BITS_MASK;
452
+ update_gpio_idr(s);
453
+ return;
454
+ case GPIO_BSRR: {
455
+ uint32_t bits_to_reset = (value & RESERVED_BITS_MASK) >> GPIO_NUM_PINS;
456
+ uint32_t bits_to_set = value & ~RESERVED_BITS_MASK;
457
+ /* If both BSx and BRx are set, BSx has priority.*/
458
+ s->odr &= ~bits_to_reset;
459
+ s->odr |= bits_to_set;
460
+ update_gpio_idr(s);
461
+ return;
462
+ }
463
+ case GPIO_LCKR:
464
+ qemu_log_mask(LOG_UNIMP,
465
+ "%s: Locking port bits configuration isn't supported\n",
466
+ __func__);
467
+ s->lckr = value & ~RESERVED_BITS_MASK;
468
+ return;
469
+ case GPIO_AFRL:
470
+ qemu_log_mask(LOG_UNIMP,
471
+ "%s: Alternate functions aren't supported\n",
472
+ __func__);
473
+ s->afrl = value;
474
+ return;
475
+ case GPIO_AFRH:
476
+ qemu_log_mask(LOG_UNIMP,
477
+ "%s: Alternate functions aren't supported\n",
478
+ __func__);
479
+ s->afrh = value;
480
+ return;
481
+ case GPIO_BRR: {
482
+ uint32_t bits_to_reset = value & ~RESERVED_BITS_MASK;
483
+ s->odr &= ~bits_to_reset;
484
+ update_gpio_idr(s);
485
+ return;
486
+ }
487
+ case GPIO_ASCR:
488
+ qemu_log_mask(LOG_UNIMP,
489
+ "%s: ADC function isn't supported\n",
490
+ __func__);
491
+ s->ascr = value & ~RESERVED_BITS_MASK;
492
+ return;
493
+ default:
494
+ qemu_log_mask(LOG_GUEST_ERROR,
495
+ "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
496
+ }
497
+}
498
+
499
+static uint64_t stm32l4x5_gpio_read(void *opaque, hwaddr addr,
500
+ unsigned int size)
501
+{
502
+ Stm32l4x5GpioState *s = opaque;
503
+
504
+ trace_stm32l4x5_gpio_read(s->name, addr);
505
+
506
+ switch (addr) {
507
+ case GPIO_MODER:
508
+ return s->moder;
509
+ case GPIO_OTYPER:
510
+ return s->otyper;
511
+ case GPIO_OSPEEDR:
512
+ return s->ospeedr;
513
+ case GPIO_PUPDR:
514
+ return s->pupdr;
515
+ case GPIO_IDR:
516
+ return s->idr;
517
+ case GPIO_ODR:
518
+ return s->odr;
519
+ case GPIO_BSRR:
520
+ return 0;
521
+ case GPIO_LCKR:
522
+ return s->lckr;
523
+ case GPIO_AFRL:
524
+ return s->afrl;
525
+ case GPIO_AFRH:
526
+ return s->afrh;
527
+ case GPIO_BRR:
528
+ return 0;
529
+ case GPIO_ASCR:
530
+ return s->ascr;
531
+ default:
532
+ qemu_log_mask(LOG_GUEST_ERROR,
533
+ "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
534
+ return 0;
535
+ }
536
+}
537
+
538
+static const MemoryRegionOps stm32l4x5_gpio_ops = {
539
+ .read = stm32l4x5_gpio_read,
540
+ .write = stm32l4x5_gpio_write,
541
+ .endianness = DEVICE_NATIVE_ENDIAN,
542
+ .impl = {
543
+ .min_access_size = 4,
544
+ .max_access_size = 4,
545
+ .unaligned = false,
546
+ },
547
+ .valid = {
548
+ .min_access_size = 4,
549
+ .max_access_size = 4,
550
+ .unaligned = false,
551
+ },
552
+};
553
+
554
+static void stm32l4x5_gpio_init(Object *obj)
555
+{
556
+ Stm32l4x5GpioState *s = STM32L4X5_GPIO(obj);
557
+
558
+ memory_region_init_io(&s->mmio, obj, &stm32l4x5_gpio_ops, s,
559
+ TYPE_STM32L4X5_GPIO, 0x400);
560
+
561
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
562
+
563
+ qdev_init_gpio_out(DEVICE(obj), s->pin, GPIO_NUM_PINS);
564
+ qdev_init_gpio_in(DEVICE(obj), stm32l4x5_gpio_set, GPIO_NUM_PINS);
565
+
566
+ s->clk = qdev_init_clock_in(DEVICE(s), "clk", NULL, s, 0);
567
+
568
+ object_property_add(obj, "disconnected-pins", "uint16",
569
+ disconnected_pins_get, disconnected_pins_set,
570
+ NULL, &s->disconnected_pins);
571
+ object_property_add(obj, "clock-freq-hz", "uint32",
572
+ clock_freq_get, NULL, NULL, NULL);
573
+}
574
+
575
+static void stm32l4x5_gpio_realize(DeviceState *dev, Error **errp)
576
+{
577
+ Stm32l4x5GpioState *s = STM32L4X5_GPIO(dev);
578
+ if (!clock_has_source(s->clk)) {
579
+ error_setg(errp, "GPIO: clk input must be connected");
580
+ return;
581
+ }
582
+}
583
+
584
+static const VMStateDescription vmstate_stm32l4x5_gpio = {
585
+ .name = TYPE_STM32L4X5_GPIO,
586
+ .version_id = 1,
587
+ .minimum_version_id = 1,
588
+ .fields = (VMStateField[]){
589
+ VMSTATE_UINT32(moder, Stm32l4x5GpioState),
590
+ VMSTATE_UINT32(otyper, Stm32l4x5GpioState),
591
+ VMSTATE_UINT32(ospeedr, Stm32l4x5GpioState),
592
+ VMSTATE_UINT32(pupdr, Stm32l4x5GpioState),
593
+ VMSTATE_UINT32(idr, Stm32l4x5GpioState),
594
+ VMSTATE_UINT32(odr, Stm32l4x5GpioState),
595
+ VMSTATE_UINT32(lckr, Stm32l4x5GpioState),
596
+ VMSTATE_UINT32(afrl, Stm32l4x5GpioState),
597
+ VMSTATE_UINT32(afrh, Stm32l4x5GpioState),
598
+ VMSTATE_UINT32(ascr, Stm32l4x5GpioState),
599
+ VMSTATE_UINT16(disconnected_pins, Stm32l4x5GpioState),
600
+ VMSTATE_UINT16(pins_connected_high, Stm32l4x5GpioState),
601
+ VMSTATE_END_OF_LIST()
602
+ }
603
+};
604
+
605
+static Property stm32l4x5_gpio_properties[] = {
606
+ DEFINE_PROP_STRING("name", Stm32l4x5GpioState, name),
607
+ DEFINE_PROP_UINT32("mode-reset", Stm32l4x5GpioState, moder_reset, 0),
608
+ DEFINE_PROP_UINT32("ospeed-reset", Stm32l4x5GpioState, ospeedr_reset, 0),
609
+ DEFINE_PROP_UINT32("pupd-reset", Stm32l4x5GpioState, pupdr_reset, 0),
610
+ DEFINE_PROP_END_OF_LIST(),
611
+};
612
+
613
+static void stm32l4x5_gpio_class_init(ObjectClass *klass, void *data)
614
+{
615
+ DeviceClass *dc = DEVICE_CLASS(klass);
616
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
617
+
618
+ device_class_set_props(dc, stm32l4x5_gpio_properties);
619
+ dc->vmsd = &vmstate_stm32l4x5_gpio;
620
+ dc->realize = stm32l4x5_gpio_realize;
621
+ rc->phases.hold = stm32l4x5_gpio_reset_hold;
622
+}
623
+
624
+static const TypeInfo stm32l4x5_gpio_types[] = {
625
+ {
626
+ .name = TYPE_STM32L4X5_GPIO,
627
+ .parent = TYPE_SYS_BUS_DEVICE,
628
+ .instance_size = sizeof(Stm32l4x5GpioState),
629
+ .instance_init = stm32l4x5_gpio_init,
630
+ .class_init = stm32l4x5_gpio_class_init,
631
+ },
632
+};
633
+
634
+DEFINE_TYPES(stm32l4x5_gpio_types)
635
diff --git a/hw/gpio/Kconfig b/hw/gpio/Kconfig
636
index XXXXXXX..XXXXXXX 100644
637
--- a/hw/gpio/Kconfig
638
+++ b/hw/gpio/Kconfig
639
@@ -XXX,XX +XXX,XX @@ config GPIO_PWR
640
641
config SIFIVE_GPIO
642
bool
643
+
644
+config STM32L4X5_GPIO
645
+ bool
646
diff --git a/hw/gpio/meson.build b/hw/gpio/meson.build
647
index XXXXXXX..XXXXXXX 100644
648
--- a/hw/gpio/meson.build
649
+++ b/hw/gpio/meson.build
650
@@ -XXX,XX +XXX,XX @@ system_ss.add(when: 'CONFIG_RASPI', if_true: files(
651
'bcm2835_gpio.c',
652
'bcm2838_gpio.c'
653
))
654
+system_ss.add(when: 'CONFIG_STM32L4X5_SOC', if_true: files('stm32l4x5_gpio.c'))
655
system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_gpio.c'))
656
system_ss.add(when: 'CONFIG_SIFIVE_GPIO', if_true: files('sifive_gpio.c'))
78
diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events
657
diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events
79
index XXXXXXX..XXXXXXX 100644
658
index XXXXXXX..XXXXXXX 100644
80
--- a/hw/gpio/trace-events
659
--- a/hw/gpio/trace-events
81
+++ b/hw/gpio/trace-events
660
+++ b/hw/gpio/trace-events
82
@@ -XXX,XX +XXX,XX @@ nrf51_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x
661
@@ -XXX,XX +XXX,XX @@ sifive_gpio_update_output_irq(int64_t line, int64_t value) "line %" PRIi64 " val
83
nrf51_gpio_set(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
662
# aspeed_gpio.c
84
nrf51_gpio_update_output_irq(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
663
aspeed_gpio_read(uint64_t offset, uint64_t value) "offset: 0x%" PRIx64 " value 0x%" PRIx64
85
664
aspeed_gpio_write(uint64_t offset, uint64_t value) "offset: 0x%" PRIx64 " value 0x%" PRIx64
86
+# pl061.c
665
+
87
+pl061_update(const char *id, uint32_t dir, uint32_t data) "%s GPIODIR 0x%x GPIODATA 0x%x"
666
+# stm32l4x5_gpio.c
88
+pl061_set_output(const char *id, int gpio, int level) "%s setting output %d to %d"
667
+stm32l4x5_gpio_read(char *gpio, uint64_t addr) "GPIO%s addr: 0x%" PRIx64 " "
89
+pl061_input_change(const char *id, int gpio, int level) "%s input %d changed to %d"
668
+stm32l4x5_gpio_write(char *gpio, uint64_t addr, uint64_t data) "GPIO%s addr: 0x%" PRIx64 " val: 0x%" PRIx64 ""
90
+pl061_update_istate(const char *id, uint32_t istate, uint32_t im, int level) "%s GPIORIS 0x%x GPIOIE 0x%x interrupt level %d"
669
+stm32l4x5_gpio_update_idr(char *gpio, uint32_t old_idr, uint32_t new_idr) "GPIO%s from: 0x%x to: 0x%x"
91
+
670
+stm32l4x5_gpio_pins(char *gpio, uint16_t disconnected, uint16_t high) "GPIO%s disconnected pins: 0x%x levels: 0x%x"
92
# sifive_gpio.c
93
sifive_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" PRIx64
94
sifive_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x%" PRIx64
95
--
671
--
96
2.20.1
672
2.34.1
97
673
98
674
diff view generated by jsdifflib
1
From: Alexandre Iooss <erdnaxe@crans.org>
1
From: Inès Varhol <ines.varhol@telecom-paris.fr>
2
2
3
This SoC is similar to stm32f205 SoC.
3
Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
4
This will be used by the STM32VLDISCOVERY to create a machine.
4
Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
5
5
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
6
Signed-off-by: Alexandre Iooss <erdnaxe@crans.org>
6
Acked-by: Alistair Francis <alistair.francis@wdc.com>
7
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
7
Message-id: 20240305210444.310665-3-ines.varhol@telecom-paris.fr
8
Message-id: 20210617165647.2575955-2-erdnaxe@crans.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
9
---
11
include/hw/arm/stm32f100_soc.h | 57 +++++++++++
10
include/hw/arm/stm32l4x5_soc.h | 2 +
12
hw/arm/stm32f100_soc.c | 182 +++++++++++++++++++++++++++++++++
11
include/hw/gpio/stm32l4x5_gpio.h | 1 +
13
MAINTAINERS | 6 ++
12
include/hw/misc/stm32l4x5_syscfg.h | 3 +-
14
hw/arm/Kconfig | 6 ++
13
hw/arm/stm32l4x5_soc.c | 71 +++++++++++++++++++++++-------
15
hw/arm/meson.build | 1 +
14
hw/misc/stm32l4x5_syscfg.c | 1 +
16
5 files changed, 252 insertions(+)
15
hw/arm/Kconfig | 3 +-
17
create mode 100644 include/hw/arm/stm32f100_soc.h
16
6 files changed, 63 insertions(+), 18 deletions(-)
18
create mode 100644 hw/arm/stm32f100_soc.c
17
19
18
diff --git a/include/hw/arm/stm32l4x5_soc.h b/include/hw/arm/stm32l4x5_soc.h
20
diff --git a/include/hw/arm/stm32f100_soc.h b/include/hw/arm/stm32f100_soc.h
19
index XXXXXXX..XXXXXXX 100644
21
new file mode 100644
20
--- a/include/hw/arm/stm32l4x5_soc.h
22
index XXXXXXX..XXXXXXX
21
+++ b/include/hw/arm/stm32l4x5_soc.h
23
--- /dev/null
22
@@ -XXX,XX +XXX,XX @@
24
+++ b/include/hw/arm/stm32f100_soc.h
23
#include "hw/misc/stm32l4x5_syscfg.h"
25
@@ -XXX,XX +XXX,XX @@
24
#include "hw/misc/stm32l4x5_exti.h"
26
+/*
25
#include "hw/misc/stm32l4x5_rcc.h"
27
+ * STM32F100 SoC
26
+#include "hw/gpio/stm32l4x5_gpio.h"
28
+ *
27
#include "qom/object.h"
29
+ * Copyright (c) 2021 Alexandre Iooss <erdnaxe@crans.org>
28
30
+ *
29
#define TYPE_STM32L4X5_SOC "stm32l4x5-soc"
31
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
30
@@ -XXX,XX +XXX,XX @@ struct Stm32l4x5SocState {
32
+ * of this software and associated documentation files (the "Software"), to deal
31
OrIRQState exti_or_gates[NUM_EXTI_OR_GATES];
33
+ * in the Software without restriction, including without limitation the rights
32
Stm32l4x5SyscfgState syscfg;
34
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33
Stm32l4x5RccState rcc;
35
+ * copies of the Software, and to permit persons to whom the Software is
34
+ Stm32l4x5GpioState gpio[NUM_GPIOS];
36
+ * furnished to do so, subject to the following conditions:
35
37
+ *
36
MemoryRegion sram1;
38
+ * The above copyright notice and this permission notice shall be included in
37
MemoryRegion sram2;
39
+ * all copies or substantial portions of the Software.
38
diff --git a/include/hw/gpio/stm32l4x5_gpio.h b/include/hw/gpio/stm32l4x5_gpio.h
40
+ *
39
index XXXXXXX..XXXXXXX 100644
41
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40
--- a/include/hw/gpio/stm32l4x5_gpio.h
42
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41
+++ b/include/hw/gpio/stm32l4x5_gpio.h
43
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
42
@@ -XXX,XX +XXX,XX @@
44
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43
#define TYPE_STM32L4X5_GPIO "stm32l4x5-gpio"
45
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44
OBJECT_DECLARE_SIMPLE_TYPE(Stm32l4x5GpioState, STM32L4X5_GPIO)
46
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
45
47
+ * THE SOFTWARE.
46
+#define NUM_GPIOS 8
48
+ */
47
#define GPIO_NUM_PINS 16
49
+
48
50
+#ifndef HW_ARM_STM32F100_SOC_H
49
struct Stm32l4x5GpioState {
51
+#define HW_ARM_STM32F100_SOC_H
50
diff --git a/include/hw/misc/stm32l4x5_syscfg.h b/include/hw/misc/stm32l4x5_syscfg.h
52
+
51
index XXXXXXX..XXXXXXX 100644
53
+#include "hw/char/stm32f2xx_usart.h"
52
--- a/include/hw/misc/stm32l4x5_syscfg.h
54
+#include "hw/ssi/stm32f2xx_spi.h"
53
+++ b/include/hw/misc/stm32l4x5_syscfg.h
55
+#include "hw/arm/armv7m.h"
54
@@ -XXX,XX +XXX,XX @@
56
+#include "qom/object.h"
55
57
+
56
#include "hw/sysbus.h"
58
+#define TYPE_STM32F100_SOC "stm32f100-soc"
57
#include "qom/object.h"
59
+OBJECT_DECLARE_SIMPLE_TYPE(STM32F100State, STM32F100_SOC)
58
+#include "hw/gpio/stm32l4x5_gpio.h"
60
+
59
61
+#define STM_NUM_USARTS 3
60
#define TYPE_STM32L4X5_SYSCFG "stm32l4x5-syscfg"
62
+#define STM_NUM_SPIS 2
61
OBJECT_DECLARE_SIMPLE_TYPE(Stm32l4x5SyscfgState, STM32L4X5_SYSCFG)
63
+
62
64
+#define FLASH_BASE_ADDRESS 0x08000000
63
-#define NUM_GPIOS 8
65
+#define FLASH_SIZE (128 * 1024)
64
-#define GPIO_NUM_PINS 16
66
+#define SRAM_BASE_ADDRESS 0x20000000
65
#define SYSCFG_NUM_EXTICR 4
67
+#define SRAM_SIZE (8 * 1024)
66
68
+
67
struct Stm32l4x5SyscfgState {
69
+struct STM32F100State {
68
diff --git a/hw/arm/stm32l4x5_soc.c b/hw/arm/stm32l4x5_soc.c
70
+ /*< private >*/
69
index XXXXXXX..XXXXXXX 100644
71
+ SysBusDevice parent_obj;
70
--- a/hw/arm/stm32l4x5_soc.c
72
+
71
+++ b/hw/arm/stm32l4x5_soc.c
73
+ /*< public >*/
72
@@ -XXX,XX +XXX,XX @@
74
+ char *cpu_type;
73
#include "sysemu/sysemu.h"
75
+
74
#include "hw/or-irq.h"
76
+ ARMv7MState armv7m;
75
#include "hw/arm/stm32l4x5_soc.h"
77
+
76
+#include "hw/gpio/stm32l4x5_gpio.h"
78
+ STM32F2XXUsartState usart[STM_NUM_USARTS];
77
#include "hw/qdev-clock.h"
79
+ STM32F2XXSPIState spi[STM_NUM_SPIS];
78
#include "hw/misc/unimp.h"
79
80
@@ -XXX,XX +XXX,XX @@ static const int exti_or_gate1_lines_in[EXTI_OR_GATE1_NUM_LINES_IN] = {
81
16, 35, 36, 37, 38,
82
};
83
84
+static const struct {
85
+ uint32_t addr;
86
+ uint32_t moder_reset;
87
+ uint32_t ospeedr_reset;
88
+ uint32_t pupdr_reset;
89
+} stm32l4x5_gpio_cfg[NUM_GPIOS] = {
90
+ { 0x48000000, 0xABFFFFFF, 0x0C000000, 0x64000000 },
91
+ { 0x48000400, 0xFFFFFEBF, 0x00000000, 0x00000100 },
92
+ { 0x48000800, 0xFFFFFFFF, 0x00000000, 0x00000000 },
93
+ { 0x48000C00, 0xFFFFFFFF, 0x00000000, 0x00000000 },
94
+ { 0x48001000, 0xFFFFFFFF, 0x00000000, 0x00000000 },
95
+ { 0x48001400, 0xFFFFFFFF, 0x00000000, 0x00000000 },
96
+ { 0x48001800, 0xFFFFFFFF, 0x00000000, 0x00000000 },
97
+ { 0x48001C00, 0x0000000F, 0x00000000, 0x00000000 },
80
+};
98
+};
81
+
99
+
82
+#endif
100
static void stm32l4x5_soc_initfn(Object *obj)
83
diff --git a/hw/arm/stm32f100_soc.c b/hw/arm/stm32f100_soc.c
101
{
84
new file mode 100644
102
Stm32l4x5SocState *s = STM32L4X5_SOC(obj);
85
index XXXXXXX..XXXXXXX
103
@@ -XXX,XX +XXX,XX @@ static void stm32l4x5_soc_initfn(Object *obj)
86
--- /dev/null
104
}
87
+++ b/hw/arm/stm32f100_soc.c
105
object_initialize_child(obj, "syscfg", &s->syscfg, TYPE_STM32L4X5_SYSCFG);
88
@@ -XXX,XX +XXX,XX @@
106
object_initialize_child(obj, "rcc", &s->rcc, TYPE_STM32L4X5_RCC);
89
+/*
107
+
90
+ * STM32F100 SoC
108
+ for (unsigned i = 0; i < NUM_GPIOS; i++) {
91
+ *
109
+ g_autofree char *name = g_strdup_printf("gpio%c", 'a' + i);
92
+ * Copyright (c) 2021 Alexandre Iooss <erdnaxe@crans.org>
110
+ object_initialize_child(obj, name, &s->gpio[i], TYPE_STM32L4X5_GPIO);
93
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
94
+ *
95
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
96
+ * of this software and associated documentation files (the "Software"), to deal
97
+ * in the Software without restriction, including without limitation the rights
98
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
99
+ * copies of the Software, and to permit persons to whom the Software is
100
+ * furnished to do so, subject to the following conditions:
101
+ *
102
+ * The above copyright notice and this permission notice shall be included in
103
+ * all copies or substantial portions of the Software.
104
+ *
105
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
106
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
107
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
108
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
109
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
110
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
111
+ * THE SOFTWARE.
112
+ */
113
+
114
+#include "qemu/osdep.h"
115
+#include "qapi/error.h"
116
+#include "qemu/module.h"
117
+#include "hw/arm/boot.h"
118
+#include "exec/address-spaces.h"
119
+#include "hw/arm/stm32f100_soc.h"
120
+#include "hw/qdev-properties.h"
121
+#include "hw/misc/unimp.h"
122
+#include "sysemu/sysemu.h"
123
+
124
+/* stm32f100_soc implementation is derived from stm32f205_soc */
125
+
126
+static const uint32_t usart_addr[STM_NUM_USARTS] = { 0x40013800, 0x40004400,
127
+ 0x40004800 };
128
+static const uint32_t spi_addr[STM_NUM_SPIS] = { 0x40013000, 0x40003800 };
129
+
130
+static const int usart_irq[STM_NUM_USARTS] = {37, 38, 39};
131
+static const int spi_irq[STM_NUM_SPIS] = {35, 36};
132
+
133
+static void stm32f100_soc_initfn(Object *obj)
134
+{
135
+ STM32F100State *s = STM32F100_SOC(obj);
136
+ int i;
137
+
138
+ object_initialize_child(obj, "armv7m", &s->armv7m, TYPE_ARMV7M);
139
+
140
+ for (i = 0; i < STM_NUM_USARTS; i++) {
141
+ object_initialize_child(obj, "usart[*]", &s->usart[i],
142
+ TYPE_STM32F2XX_USART);
143
+ }
111
+ }
144
+
112
}
145
+ for (i = 0; i < STM_NUM_SPIS; i++) {
113
146
+ object_initialize_child(obj, "spi[*]", &s->spi[i], TYPE_STM32F2XX_SPI);
114
static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
147
+ }
115
@@ -XXX,XX +XXX,XX @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
148
+}
116
Stm32l4x5SocState *s = STM32L4X5_SOC(dev_soc);
149
+
117
const Stm32l4x5SocClass *sc = STM32L4X5_SOC_GET_CLASS(dev_soc);
150
+static void stm32f100_soc_realize(DeviceState *dev_soc, Error **errp)
118
MemoryRegion *system_memory = get_system_memory();
151
+{
119
- DeviceState *armv7m;
152
+ STM32F100State *s = STM32F100_SOC(dev_soc);
120
+ DeviceState *armv7m, *dev;
153
+ DeviceState *dev, *armv7m;
121
SysBusDevice *busdev;
154
+ SysBusDevice *busdev;
122
+ uint32_t pin_index;
155
+ int i;
123
156
+
124
if (!memory_region_init_rom(&s->flash, OBJECT(dev_soc), "flash",
157
+ MemoryRegion *system_memory = get_system_memory();
125
sc->flash_size, errp)) {
158
+ MemoryRegion *sram = g_new(MemoryRegion, 1);
126
@@ -XXX,XX +XXX,XX @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
159
+ MemoryRegion *flash = g_new(MemoryRegion, 1);
127
return;
160
+ MemoryRegion *flash_alias = g_new(MemoryRegion, 1);
128
}
161
+
129
162
+ /*
130
+ /* GPIOs */
163
+ * Init flash region
131
+ for (unsigned i = 0; i < NUM_GPIOS; i++) {
164
+ * Flash starts at 0x08000000 and then is aliased to boot memory at 0x0
132
+ g_autofree char *name = g_strdup_printf("%c", 'A' + i);
165
+ */
133
+ dev = DEVICE(&s->gpio[i]);
166
+ memory_region_init_rom(flash, OBJECT(dev_soc), "STM32F100.flash",
134
+ qdev_prop_set_string(dev, "name", name);
167
+ FLASH_SIZE, &error_fatal);
135
+ qdev_prop_set_uint32(dev, "mode-reset",
168
+ memory_region_init_alias(flash_alias, OBJECT(dev_soc),
136
+ stm32l4x5_gpio_cfg[i].moder_reset);
169
+ "STM32F100.flash.alias", flash, 0, FLASH_SIZE);
137
+ qdev_prop_set_uint32(dev, "ospeed-reset",
170
+ memory_region_add_subregion(system_memory, FLASH_BASE_ADDRESS, flash);
138
+ stm32l4x5_gpio_cfg[i].ospeedr_reset);
171
+ memory_region_add_subregion(system_memory, 0, flash_alias);
139
+ qdev_prop_set_uint32(dev, "pupd-reset",
172
+
140
+ stm32l4x5_gpio_cfg[i].pupdr_reset);
173
+ /* Init SRAM region */
141
+ busdev = SYS_BUS_DEVICE(&s->gpio[i]);
174
+ memory_region_init_ram(sram, NULL, "STM32F100.sram", SRAM_SIZE,
142
+ g_free(name);
175
+ &error_fatal);
143
+ name = g_strdup_printf("gpio%c-out", 'a' + i);
176
+ memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, sram);
144
+ qdev_connect_clock_in(DEVICE(&s->gpio[i]), "clk",
177
+
145
+ qdev_get_clock_out(DEVICE(&(s->rcc)), name));
178
+ /* Init ARMv7m */
146
+ if (!sysbus_realize(busdev, errp)) {
179
+ armv7m = DEVICE(&s->armv7m);
180
+ qdev_prop_set_uint32(armv7m, "num-irq", 61);
181
+ qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type);
182
+ qdev_prop_set_bit(armv7m, "enable-bitband", true);
183
+ object_property_set_link(OBJECT(&s->armv7m), "memory",
184
+ OBJECT(get_system_memory()), &error_abort);
185
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), errp)) {
186
+ return;
187
+ }
188
+
189
+ /* Attach UART (uses USART registers) and USART controllers */
190
+ for (i = 0; i < STM_NUM_USARTS; i++) {
191
+ dev = DEVICE(&(s->usart[i]));
192
+ qdev_prop_set_chr(dev, "chardev", serial_hd(i));
193
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->usart[i]), errp)) {
194
+ return;
147
+ return;
195
+ }
148
+ }
196
+ busdev = SYS_BUS_DEVICE(dev);
149
+ sysbus_mmio_map(busdev, 0, stm32l4x5_gpio_cfg[i].addr);
197
+ sysbus_mmio_map(busdev, 0, usart_addr[i]);
198
+ sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, usart_irq[i]));
199
+ }
150
+ }
200
+
151
+
201
+ /* SPI 1 and 2 */
152
/* System configuration controller */
202
+ for (i = 0; i < STM_NUM_SPIS; i++) {
153
busdev = SYS_BUS_DEVICE(&s->syscfg);
203
+ dev = DEVICE(&(s->spi[i]));
154
if (!sysbus_realize(busdev, errp)) {
204
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) {
155
return;
205
+ return;
156
}
157
sysbus_mmio_map(busdev, 0, SYSCFG_ADDR);
158
- /*
159
- * TODO: when the GPIO device is implemented, connect it
160
- * to SYCFG using `qdev_connect_gpio_out`, NUM_GPIOS and
161
- * GPIO_NUM_PINS.
162
- */
163
+
164
+ for (unsigned i = 0; i < NUM_GPIOS; i++) {
165
+ for (unsigned j = 0; j < GPIO_NUM_PINS; j++) {
166
+ pin_index = GPIO_NUM_PINS * i + j;
167
+ qdev_connect_gpio_out(DEVICE(&s->gpio[i]), j,
168
+ qdev_get_gpio_in(DEVICE(&s->syscfg),
169
+ pin_index));
206
+ }
170
+ }
207
+ busdev = SYS_BUS_DEVICE(dev);
208
+ sysbus_mmio_map(busdev, 0, spi_addr[i]);
209
+ sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m, spi_irq[i]));
210
+ }
171
+ }
211
+
172
212
+ create_unimplemented_device("timer[2]", 0x40000000, 0x400);
173
/* EXTI device */
213
+ create_unimplemented_device("timer[3]", 0x40000400, 0x400);
174
busdev = SYS_BUS_DEVICE(&s->exti);
214
+ create_unimplemented_device("timer[4]", 0x40000800, 0x400);
175
@@ -XXX,XX +XXX,XX @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
215
+ create_unimplemented_device("timer[6]", 0x40001000, 0x400);
176
}
216
+ create_unimplemented_device("timer[7]", 0x40001400, 0x400);
177
}
217
+ create_unimplemented_device("RTC", 0x40002800, 0x400);
178
218
+ create_unimplemented_device("WWDG", 0x40002C00, 0x400);
179
- for (unsigned i = 0; i < 16; i++) {
219
+ create_unimplemented_device("IWDG", 0x40003000, 0x400);
180
+ for (unsigned i = 0; i < GPIO_NUM_PINS; i++) {
220
+ create_unimplemented_device("I2C1", 0x40005400, 0x400);
181
qdev_connect_gpio_out(DEVICE(&s->syscfg), i,
221
+ create_unimplemented_device("I2C2", 0x40005800, 0x400);
182
qdev_get_gpio_in(DEVICE(&s->exti), i));
222
+ create_unimplemented_device("BKP", 0x40006C00, 0x400);
183
}
223
+ create_unimplemented_device("PWR", 0x40007000, 0x400);
184
@@ -XXX,XX +XXX,XX @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
224
+ create_unimplemented_device("DAC", 0x40007400, 0x400);
185
/* RESERVED: 0x40024400, 0x7FDBC00 */
225
+ create_unimplemented_device("CEC", 0x40007800, 0x400);
186
226
+ create_unimplemented_device("AFIO", 0x40010000, 0x400);
187
/* AHB2 BUS */
227
+ create_unimplemented_device("EXTI", 0x40010400, 0x400);
188
- create_unimplemented_device("GPIOA", 0x48000000, 0x400);
228
+ create_unimplemented_device("GPIOA", 0x40010800, 0x400);
189
- create_unimplemented_device("GPIOB", 0x48000400, 0x400);
229
+ create_unimplemented_device("GPIOB", 0x40010C00, 0x400);
190
- create_unimplemented_device("GPIOC", 0x48000800, 0x400);
230
+ create_unimplemented_device("GPIOC", 0x40011000, 0x400);
191
- create_unimplemented_device("GPIOD", 0x48000C00, 0x400);
231
+ create_unimplemented_device("GPIOD", 0x40011400, 0x400);
192
- create_unimplemented_device("GPIOE", 0x48001000, 0x400);
232
+ create_unimplemented_device("GPIOE", 0x40011800, 0x400);
193
- create_unimplemented_device("GPIOF", 0x48001400, 0x400);
233
+ create_unimplemented_device("ADC1", 0x40012400, 0x400);
194
- create_unimplemented_device("GPIOG", 0x48001800, 0x400);
234
+ create_unimplemented_device("timer[1]", 0x40012C00, 0x400);
195
- create_unimplemented_device("GPIOH", 0x48001C00, 0x400);
235
+ create_unimplemented_device("timer[15]", 0x40014000, 0x400);
196
/* RESERVED: 0x48002000, 0x7FDBC00 */
236
+ create_unimplemented_device("timer[16]", 0x40014400, 0x400);
197
create_unimplemented_device("OTG_FS", 0x50000000, 0x40000);
237
+ create_unimplemented_device("timer[17]", 0x40014800, 0x400);
198
create_unimplemented_device("ADC", 0x50040000, 0x400);
238
+ create_unimplemented_device("DMA", 0x40020000, 0x400);
199
diff --git a/hw/misc/stm32l4x5_syscfg.c b/hw/misc/stm32l4x5_syscfg.c
239
+ create_unimplemented_device("RCC", 0x40021000, 0x400);
200
index XXXXXXX..XXXXXXX 100644
240
+ create_unimplemented_device("Flash Int", 0x40022000, 0x400);
201
--- a/hw/misc/stm32l4x5_syscfg.c
241
+ create_unimplemented_device("CRC", 0x40023000, 0x400);
202
+++ b/hw/misc/stm32l4x5_syscfg.c
242
+}
203
@@ -XXX,XX +XXX,XX @@
243
+
204
#include "hw/irq.h"
244
+static Property stm32f100_soc_properties[] = {
205
#include "migration/vmstate.h"
245
+ DEFINE_PROP_STRING("cpu-type", STM32F100State, cpu_type),
206
#include "hw/misc/stm32l4x5_syscfg.h"
246
+ DEFINE_PROP_END_OF_LIST(),
207
+#include "hw/gpio/stm32l4x5_gpio.h"
247
+};
208
248
+
209
#define SYSCFG_MEMRMP 0x00
249
+static void stm32f100_soc_class_init(ObjectClass *klass, void *data)
210
#define SYSCFG_CFGR1 0x04
250
+{
251
+ DeviceClass *dc = DEVICE_CLASS(klass);
252
+
253
+ dc->realize = stm32f100_soc_realize;
254
+ device_class_set_props(dc, stm32f100_soc_properties);
255
+}
256
+
257
+static const TypeInfo stm32f100_soc_info = {
258
+ .name = TYPE_STM32F100_SOC,
259
+ .parent = TYPE_SYS_BUS_DEVICE,
260
+ .instance_size = sizeof(STM32F100State),
261
+ .instance_init = stm32f100_soc_initfn,
262
+ .class_init = stm32f100_soc_class_init,
263
+};
264
+
265
+static void stm32f100_soc_types(void)
266
+{
267
+ type_register_static(&stm32f100_soc_info);
268
+}
269
+
270
+type_init(stm32f100_soc_types)
271
diff --git a/MAINTAINERS b/MAINTAINERS
272
index XXXXXXX..XXXXXXX 100644
273
--- a/MAINTAINERS
274
+++ b/MAINTAINERS
275
@@ -XXX,XX +XXX,XX @@ L: qemu-arm@nongnu.org
276
S: Maintained
277
F: hw/arm/virt-acpi-build.c
278
279
+STM32F100
280
+M: Alexandre Iooss <erdnaxe@crans.org>
281
+L: qemu-arm@nongnu.org
282
+S: Maintained
283
+F: hw/arm/stm32f100_soc.c
284
+
285
STM32F205
286
M: Alistair Francis <alistair@alistair23.me>
287
M: Peter Maydell <peter.maydell@linaro.org>
288
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
211
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
289
index XXXXXXX..XXXXXXX 100644
212
index XXXXXXX..XXXXXXX 100644
290
--- a/hw/arm/Kconfig
213
--- a/hw/arm/Kconfig
291
+++ b/hw/arm/Kconfig
214
+++ b/hw/arm/Kconfig
292
@@ -XXX,XX +XXX,XX @@ config RASPI
215
@@ -XXX,XX +XXX,XX @@ config STM32L4X5_SOC
293
select SDHCI
294
select USB_DWC2
295
296
+config STM32F100_SOC
297
+ bool
298
+ select ARM_V7M
299
+ select STM32F2XX_USART
300
+ select STM32F2XX_SPI
301
+
302
config STM32F205_SOC
303
bool
216
bool
304
select ARM_V7M
217
select ARM_V7M
305
diff --git a/hw/arm/meson.build b/hw/arm/meson.build
218
select OR_IRQ
306
index XXXXXXX..XXXXXXX 100644
219
- select STM32L4X5_SYSCFG
307
--- a/hw/arm/meson.build
220
select STM32L4X5_EXTI
308
+++ b/hw/arm/meson.build
221
+ select STM32L4X5_SYSCFG
309
@@ -XXX,XX +XXX,XX @@ arm_ss.add(when: 'CONFIG_STRONGARM', if_true: files('strongarm.c'))
222
select STM32L4X5_RCC
310
arm_ss.add(when: 'CONFIG_ALLWINNER_A10', if_true: files('allwinner-a10.c', 'cubieboard.c'))
223
+ select STM32L4X5_GPIO
311
arm_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3.c', 'orangepi.c'))
224
312
arm_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_peripherals.c', 'bcm2836.c', 'raspi.c'))
225
config XLNX_ZYNQMP_ARM
313
+arm_ss.add(when: 'CONFIG_STM32F100_SOC', if_true: files('stm32f100_soc.c'))
226
bool
314
arm_ss.add(when: 'CONFIG_STM32F205_SOC', if_true: files('stm32f205_soc.c'))
315
arm_ss.add(when: 'CONFIG_STM32F405_SOC', if_true: files('stm32f405_soc.c'))
316
arm_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp.c', 'xlnx-zcu102.c'))
317
--
227
--
318
2.20.1
228
2.34.1
319
229
320
230
diff view generated by jsdifflib
1
From: Alexandre Iooss <erdnaxe@crans.org>
1
From: Inès Varhol <ines.varhol@telecom-paris.fr>
2
2
3
This adds the target guide for Netduino 2, Netduino Plus 2 and STM32VLDISCOVERY.
3
The testcase contains :
4
- `test_idr_reset_value()` :
5
Checks the reset values of MODER, OTYPER, PUPDR, ODR and IDR.
6
- `test_gpio_output_mode()` :
7
Checks that writing a bit in register ODR results in the corresponding
8
pin rising or lowering, if this pin is configured in output mode.
9
- `test_gpio_input_mode()` :
10
Checks that a input pin set high or low externally results
11
in the pin rising and lowering.
12
- `test_pull_up_pull_down()` :
13
Checks that a floating pin in pull-up/down mode is actually high/down.
14
- `test_push_pull()` :
15
Checks that a pin set externally is disconnected when configured in
16
push-pull output mode, and can't be set externally while in this mode.
17
- `test_open_drain()` :
18
Checks that a pin set externally high is disconnected when configured
19
in open-drain output mode, and can't be set high while in this mode.
20
- `test_bsrr_brr()` :
21
Checks that writing to BSRR and BRR has the desired result in ODR.
22
- `test_clock_enable()` :
23
Checks that GPIO clock is at the right frequency after enabling it.
4
24
5
Signed-off-by: Alexandre Iooss <erdnaxe@crans.org>
25
Acked-by: Thomas Huth <thuth@redhat.com>
6
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
26
Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
7
Message-id: 20210617165647.2575955-4-erdnaxe@crans.org
27
Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
28
Message-id: 20240305210444.310665-4-ines.varhol@telecom-paris.fr
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
29
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
30
---
10
docs/system/arm/stm32.rst | 66 ++++++++++++++++++++++++++++++++++++++
31
tests/qtest/stm32l4x5_gpio-test.c | 551 ++++++++++++++++++++++++++++++
11
docs/system/target-arm.rst | 1 +
32
tests/qtest/meson.build | 3 +-
12
MAINTAINERS | 1 +
33
2 files changed, 553 insertions(+), 1 deletion(-)
13
3 files changed, 68 insertions(+)
34
create mode 100644 tests/qtest/stm32l4x5_gpio-test.c
14
create mode 100644 docs/system/arm/stm32.rst
15
35
16
diff --git a/docs/system/arm/stm32.rst b/docs/system/arm/stm32.rst
36
diff --git a/tests/qtest/stm32l4x5_gpio-test.c b/tests/qtest/stm32l4x5_gpio-test.c
17
new file mode 100644
37
new file mode 100644
18
index XXXXXXX..XXXXXXX
38
index XXXXXXX..XXXXXXX
19
--- /dev/null
39
--- /dev/null
20
+++ b/docs/system/arm/stm32.rst
40
+++ b/tests/qtest/stm32l4x5_gpio-test.c
21
@@ -XXX,XX +XXX,XX @@
41
@@ -XXX,XX +XXX,XX @@
22
+STMicroelectronics STM32 boards (``netduino2``, ``netduinoplus2``, ``stm32vldiscovery``)
42
+/*
23
+========================================================================================
43
+ * QTest testcase for STM32L4x5_GPIO
24
+
44
+ *
25
+The `STM32`_ chips are a family of 32-bit ARM-based microcontroller by
45
+ * Copyright (c) 2024 Arnaud Minier <arnaud.minier@telecom-paris.fr>
26
+STMicroelectronics.
46
+ * Copyright (c) 2024 Inès Varhol <ines.varhol@telecom-paris.fr>
27
+
47
+ *
28
+.. _STM32: https://www.st.com/en/microcontrollers-microprocessors/stm32-32-bit-arm-cortex-mcus.html
48
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
29
+
49
+ * See the COPYING file in the top-level directory.
30
+The STM32F1 series is based on ARM Cortex-M3 core. The following machines are
50
+ */
31
+based on this chip :
51
+
32
+
52
+#include "qemu/osdep.h"
33
+- ``stm32vldiscovery`` STM32VLDISCOVERY board with STM32F100RBT6 microcontroller
53
+#include "libqtest-single.h"
34
+
54
+
35
+The STM32F2 series is based on ARM Cortex-M3 core. The following machines are
55
+#define GPIO_BASE_ADDR 0x48000000
36
+based on this chip :
56
+#define GPIO_SIZE 0x400
37
+
57
+#define NUM_GPIOS 8
38
+- ``netduino2`` Netduino 2 board with STM32F205RFT6 microcontroller
58
+#define NUM_GPIO_PINS 16
39
+
59
+
40
+The STM32F4 series is based on ARM Cortex-M4F core. This series is pin-to-pin
60
+#define GPIO_A 0x48000000
41
+compatible with STM32F2 series. The following machines are based on this chip :
61
+#define GPIO_B 0x48000400
42
+
62
+#define GPIO_C 0x48000800
43
+- ``netduinoplus2`` Netduino Plus 2 board with STM32F405RGT6 microcontroller
63
+#define GPIO_D 0x48000C00
44
+
64
+#define GPIO_E 0x48001000
45
+There are many other STM32 series that are currently not supported by QEMU.
65
+#define GPIO_F 0x48001400
46
+
66
+#define GPIO_G 0x48001800
47
+Supported devices
67
+#define GPIO_H 0x48001C00
48
+-----------------
68
+
49
+
69
+#define MODER 0x00
50
+ * ARM Cortex-M3, Cortex M4F
70
+#define OTYPER 0x04
51
+ * Analog to Digital Converter (ADC)
71
+#define PUPDR 0x0C
52
+ * EXTI interrupt
72
+#define IDR 0x10
53
+ * Serial ports (USART)
73
+#define ODR 0x14
54
+ * SPI controller
74
+#define BSRR 0x18
55
+ * System configuration (SYSCFG)
75
+#define BRR 0x28
56
+ * Timer controller (TIMER)
76
+
57
+
77
+#define MODER_INPUT 0
58
+Missing devices
78
+#define MODER_OUTPUT 1
59
+---------------
79
+
60
+
80
+#define PUPDR_NONE 0
61
+ * Camera interface (DCMI)
81
+#define PUPDR_PULLUP 1
62
+ * Controller Area Network (CAN)
82
+#define PUPDR_PULLDOWN 2
63
+ * Cycle Redundancy Check (CRC) calculation unit
83
+
64
+ * Digital to Analog Converter (DAC)
84
+#define OTYPER_PUSH_PULL 0
65
+ * DMA controller
85
+#define OTYPER_OPEN_DRAIN 1
66
+ * Ethernet controller
86
+
67
+ * Flash Interface Unit
87
+const uint32_t moder_reset[NUM_GPIOS] = {
68
+ * GPIO controller
88
+ 0xABFFFFFF,
69
+ * I2C controller
89
+ 0xFFFFFEBF,
70
+ * Inter-Integrated Sound (I2S) controller
90
+ 0xFFFFFFFF,
71
+ * Power supply configuration (PWR)
91
+ 0xFFFFFFFF,
72
+ * Random Number Generator (RNG)
92
+ 0xFFFFFFFF,
73
+ * Real-Time Clock (RTC) controller
93
+ 0xFFFFFFFF,
74
+ * Reset and Clock Controller (RCC)
94
+ 0xFFFFFFFF,
75
+ * Secure Digital Input/Output (SDIO) interface
95
+ 0x0000000F
76
+ * USB OTG
96
+};
77
+ * Watchdog controller (IWDG, WWDG)
97
+
78
+
98
+const uint32_t pupdr_reset[NUM_GPIOS] = {
79
+Boot options
99
+ 0x64000000,
80
+------------
100
+ 0x00000100,
81
+
101
+ 0x00000000,
82
+The STM32 machines can be started using the ``-kernel`` option to load a
102
+ 0x00000000,
83
+firmware. Example:
103
+ 0x00000000,
84
+
104
+ 0x00000000,
85
+.. code-block:: bash
105
+ 0x00000000,
86
+
106
+ 0x00000000
87
+ $ qemu-system-arm -M stm32vldiscovery -kernel firmware.bin
107
+};
88
diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst
108
+
109
+const uint32_t idr_reset[NUM_GPIOS] = {
110
+ 0x0000A000,
111
+ 0x00000010,
112
+ 0x00000000,
113
+ 0x00000000,
114
+ 0x00000000,
115
+ 0x00000000,
116
+ 0x00000000,
117
+ 0x00000000
118
+};
119
+
120
+static uint32_t gpio_readl(unsigned int gpio, unsigned int offset)
121
+{
122
+ return readl(gpio + offset);
123
+}
124
+
125
+static void gpio_writel(unsigned int gpio, unsigned int offset, uint32_t value)
126
+{
127
+ writel(gpio + offset, value);
128
+}
129
+
130
+static void gpio_set_bit(unsigned int gpio, unsigned int reg,
131
+ unsigned int pin, uint32_t value)
132
+{
133
+ uint32_t mask = 0xFFFFFFFF & ~(0x1 << pin);
134
+ gpio_writel(gpio, reg, (gpio_readl(gpio, reg) & mask) | value << pin);
135
+}
136
+
137
+static void gpio_set_2bits(unsigned int gpio, unsigned int reg,
138
+ unsigned int pin, uint32_t value)
139
+{
140
+ uint32_t offset = 2 * pin;
141
+ uint32_t mask = 0xFFFFFFFF & ~(0x3 << offset);
142
+ gpio_writel(gpio, reg, (gpio_readl(gpio, reg) & mask) | value << offset);
143
+}
144
+
145
+static unsigned int get_gpio_id(uint32_t gpio_addr)
146
+{
147
+ return (gpio_addr - GPIO_BASE_ADDR) / GPIO_SIZE;
148
+}
149
+
150
+static void gpio_set_irq(unsigned int gpio, int num, int level)
151
+{
152
+ g_autofree char *name = g_strdup_printf("/machine/soc/gpio%c",
153
+ get_gpio_id(gpio) + 'a');
154
+ qtest_set_irq_in(global_qtest, name, NULL, num, level);
155
+}
156
+
157
+static void disconnect_all_pins(unsigned int gpio)
158
+{
159
+ g_autofree char *path = g_strdup_printf("/machine/soc/gpio%c",
160
+ get_gpio_id(gpio) + 'a');
161
+ QDict *r;
162
+
163
+ r = qtest_qmp(global_qtest, "{ 'execute': 'qom-set', 'arguments': "
164
+ "{ 'path': %s, 'property': 'disconnected-pins', 'value': %d } }",
165
+ path, 0xFFFF);
166
+ g_assert_false(qdict_haskey(r, "error"));
167
+ qobject_unref(r);
168
+}
169
+
170
+static uint32_t get_disconnected_pins(unsigned int gpio)
171
+{
172
+ g_autofree char *path = g_strdup_printf("/machine/soc/gpio%c",
173
+ get_gpio_id(gpio) + 'a');
174
+ uint32_t disconnected_pins = 0;
175
+ QDict *r;
176
+
177
+ r = qtest_qmp(global_qtest, "{ 'execute': 'qom-get', 'arguments':"
178
+ " { 'path': %s, 'property': 'disconnected-pins'} }", path);
179
+ g_assert_false(qdict_haskey(r, "error"));
180
+ disconnected_pins = qdict_get_int(r, "return");
181
+ qobject_unref(r);
182
+ return disconnected_pins;
183
+}
184
+
185
+static uint32_t reset(uint32_t gpio, unsigned int offset)
186
+{
187
+ switch (offset) {
188
+ case MODER:
189
+ return moder_reset[get_gpio_id(gpio)];
190
+ case PUPDR:
191
+ return pupdr_reset[get_gpio_id(gpio)];
192
+ case IDR:
193
+ return idr_reset[get_gpio_id(gpio)];
194
+ }
195
+ return 0x0;
196
+}
197
+
198
+static void system_reset(void)
199
+{
200
+ QDict *r;
201
+ r = qtest_qmp(global_qtest, "{'execute': 'system_reset'}");
202
+ g_assert_false(qdict_haskey(r, "error"));
203
+ qobject_unref(r);
204
+}
205
+
206
+static void test_idr_reset_value(void)
207
+{
208
+ /*
209
+ * Checks that the values in MODER, OTYPER, PUPDR and ODR
210
+ * after reset are correct, and that the value in IDR is
211
+ * coherent.
212
+ * Since AF and analog modes aren't implemented, IDR reset
213
+ * values aren't the same as with a real board.
214
+ *
215
+ * Register IDR contains the actual values of all GPIO pins.
216
+ * Its value depends on the pins' configuration
217
+ * (intput/output/analog : register MODER, push-pull/open-drain :
218
+ * register OTYPER, pull-up/pull-down/none : register PUPDR)
219
+ * and on the values stored in register ODR
220
+ * (in case the pin is in output mode).
221
+ */
222
+
223
+ gpio_writel(GPIO_A, MODER, 0xDEADBEEF);
224
+ gpio_writel(GPIO_A, ODR, 0xDEADBEEF);
225
+ gpio_writel(GPIO_A, OTYPER, 0xDEADBEEF);
226
+ gpio_writel(GPIO_A, PUPDR, 0xDEADBEEF);
227
+
228
+ gpio_writel(GPIO_B, MODER, 0xDEADBEEF);
229
+ gpio_writel(GPIO_B, ODR, 0xDEADBEEF);
230
+ gpio_writel(GPIO_B, OTYPER, 0xDEADBEEF);
231
+ gpio_writel(GPIO_B, PUPDR, 0xDEADBEEF);
232
+
233
+ gpio_writel(GPIO_C, MODER, 0xDEADBEEF);
234
+ gpio_writel(GPIO_C, ODR, 0xDEADBEEF);
235
+ gpio_writel(GPIO_C, OTYPER, 0xDEADBEEF);
236
+ gpio_writel(GPIO_C, PUPDR, 0xDEADBEEF);
237
+
238
+ gpio_writel(GPIO_H, MODER, 0xDEADBEEF);
239
+ gpio_writel(GPIO_H, ODR, 0xDEADBEEF);
240
+ gpio_writel(GPIO_H, OTYPER, 0xDEADBEEF);
241
+ gpio_writel(GPIO_H, PUPDR, 0xDEADBEEF);
242
+
243
+ system_reset();
244
+
245
+ uint32_t moder = gpio_readl(GPIO_A, MODER);
246
+ uint32_t odr = gpio_readl(GPIO_A, ODR);
247
+ uint32_t otyper = gpio_readl(GPIO_A, OTYPER);
248
+ uint32_t pupdr = gpio_readl(GPIO_A, PUPDR);
249
+ uint32_t idr = gpio_readl(GPIO_A, IDR);
250
+ /* 15: AF, 14: AF, 13: AF, 12: Analog ... */
251
+ /* here AF is the same as Analog and Input mode */
252
+ g_assert_cmphex(moder, ==, reset(GPIO_A, MODER));
253
+ g_assert_cmphex(odr, ==, reset(GPIO_A, ODR));
254
+ g_assert_cmphex(otyper, ==, reset(GPIO_A, OTYPER));
255
+ /* 15: pull-up, 14: pull-down, 13: pull-up, 12: neither ... */
256
+ g_assert_cmphex(pupdr, ==, reset(GPIO_A, PUPDR));
257
+ /* 15 : 1, 14: 0, 13: 1, 12 : reset value ... */
258
+ g_assert_cmphex(idr, ==, reset(GPIO_A, IDR));
259
+
260
+ moder = gpio_readl(GPIO_B, MODER);
261
+ odr = gpio_readl(GPIO_B, ODR);
262
+ otyper = gpio_readl(GPIO_B, OTYPER);
263
+ pupdr = gpio_readl(GPIO_B, PUPDR);
264
+ idr = gpio_readl(GPIO_B, IDR);
265
+ /* ... 5: Analog, 4: AF, 3: AF, 2: Analog ... */
266
+ /* here AF is the same as Analog and Input mode */
267
+ g_assert_cmphex(moder, ==, reset(GPIO_B, MODER));
268
+ g_assert_cmphex(odr, ==, reset(GPIO_B, ODR));
269
+ g_assert_cmphex(otyper, ==, reset(GPIO_B, OTYPER));
270
+ /* ... 5: neither, 4: pull-up, 3: neither ... */
271
+ g_assert_cmphex(pupdr, ==, reset(GPIO_B, PUPDR));
272
+ /* ... 5 : reset value, 4 : 1, 3 : reset value ... */
273
+ g_assert_cmphex(idr, ==, reset(GPIO_B, IDR));
274
+
275
+ moder = gpio_readl(GPIO_C, MODER);
276
+ odr = gpio_readl(GPIO_C, ODR);
277
+ otyper = gpio_readl(GPIO_C, OTYPER);
278
+ pupdr = gpio_readl(GPIO_C, PUPDR);
279
+ idr = gpio_readl(GPIO_C, IDR);
280
+ /* Analog, same as Input mode*/
281
+ g_assert_cmphex(moder, ==, reset(GPIO_C, MODER));
282
+ g_assert_cmphex(odr, ==, reset(GPIO_C, ODR));
283
+ g_assert_cmphex(otyper, ==, reset(GPIO_C, OTYPER));
284
+ /* no pull-up or pull-down */
285
+ g_assert_cmphex(pupdr, ==, reset(GPIO_C, PUPDR));
286
+ /* reset value */
287
+ g_assert_cmphex(idr, ==, reset(GPIO_C, IDR));
288
+
289
+ moder = gpio_readl(GPIO_H, MODER);
290
+ odr = gpio_readl(GPIO_H, ODR);
291
+ otyper = gpio_readl(GPIO_H, OTYPER);
292
+ pupdr = gpio_readl(GPIO_H, PUPDR);
293
+ idr = gpio_readl(GPIO_H, IDR);
294
+ /* Analog, same as Input mode */
295
+ g_assert_cmphex(moder, ==, reset(GPIO_H, MODER));
296
+ g_assert_cmphex(odr, ==, reset(GPIO_H, ODR));
297
+ g_assert_cmphex(otyper, ==, reset(GPIO_H, OTYPER));
298
+ /* no pull-up or pull-down */
299
+ g_assert_cmphex(pupdr, ==, reset(GPIO_H, PUPDR));
300
+ /* reset value */
301
+ g_assert_cmphex(idr, ==, reset(GPIO_H, IDR));
302
+}
303
+
304
+static void test_gpio_output_mode(const void *data)
305
+{
306
+ /*
307
+ * Checks that setting a bit in ODR sets the corresponding
308
+ * GPIO line high : it should set the right bit in IDR
309
+ * and send an irq to syscfg.
310
+ * Additionally, it checks that values written to ODR
311
+ * when not in output mode are stored and not discarded.
312
+ */
313
+ unsigned int pin = ((uint64_t)data) & 0xF;
314
+ uint32_t gpio = ((uint64_t)data) >> 32;
315
+ unsigned int gpio_id = get_gpio_id(gpio);
316
+
317
+ qtest_irq_intercept_in(global_qtest, "/machine/soc/syscfg");
318
+
319
+ /* Set a bit in ODR and check nothing happens */
320
+ gpio_set_bit(gpio, ODR, pin, 1);
321
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR));
322
+ g_assert_false(get_irq(gpio_id * NUM_GPIO_PINS + pin));
323
+
324
+ /* Configure the relevant line as output and check the pin is high */
325
+ gpio_set_2bits(gpio, MODER, pin, MODER_OUTPUT);
326
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) | (1 << pin));
327
+ g_assert_true(get_irq(gpio_id * NUM_GPIO_PINS + pin));
328
+
329
+ /* Reset the bit in ODR and check the pin is low */
330
+ gpio_set_bit(gpio, ODR, pin, 0);
331
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
332
+ g_assert_false(get_irq(gpio_id * NUM_GPIO_PINS + pin));
333
+
334
+ /* Clean the test */
335
+ gpio_writel(gpio, ODR, reset(gpio, ODR));
336
+ gpio_writel(gpio, MODER, reset(gpio, MODER));
337
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR));
338
+ g_assert_false(get_irq(gpio_id * NUM_GPIO_PINS + pin));
339
+}
340
+
341
+static void test_gpio_input_mode(const void *data)
342
+{
343
+ /*
344
+ * Test that setting a line high/low externally sets the
345
+ * corresponding GPIO line high/low : it should set the
346
+ * right bit in IDR and send an irq to syscfg.
347
+ */
348
+ unsigned int pin = ((uint64_t)data) & 0xF;
349
+ uint32_t gpio = ((uint64_t)data) >> 32;
350
+ unsigned int gpio_id = get_gpio_id(gpio);
351
+
352
+ qtest_irq_intercept_in(global_qtest, "/machine/soc/syscfg");
353
+
354
+ /* Configure a line as input, raise it, and check that the pin is high */
355
+ gpio_set_2bits(gpio, MODER, pin, MODER_INPUT);
356
+ gpio_set_irq(gpio, pin, 1);
357
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) | (1 << pin));
358
+ g_assert_true(get_irq(gpio_id * NUM_GPIO_PINS + pin));
359
+
360
+ /* Lower the line and check that the pin is low */
361
+ gpio_set_irq(gpio, pin, 0);
362
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
363
+ g_assert_false(get_irq(gpio_id * NUM_GPIO_PINS + pin));
364
+
365
+ /* Clean the test */
366
+ gpio_writel(gpio, MODER, reset(gpio, MODER));
367
+ disconnect_all_pins(gpio);
368
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR));
369
+}
370
+
371
+static void test_pull_up_pull_down(const void *data)
372
+{
373
+ /*
374
+ * Test that a floating pin with pull-up sets the pin
375
+ * high and vice-versa.
376
+ */
377
+ unsigned int pin = ((uint64_t)data) & 0xF;
378
+ uint32_t gpio = ((uint64_t)data) >> 32;
379
+ unsigned int gpio_id = get_gpio_id(gpio);
380
+
381
+ qtest_irq_intercept_in(global_qtest, "/machine/soc/syscfg");
382
+
383
+ /* Configure a line as input with pull-up, check the line is set high */
384
+ gpio_set_2bits(gpio, MODER, pin, MODER_INPUT);
385
+ gpio_set_2bits(gpio, PUPDR, pin, PUPDR_PULLUP);
386
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) | (1 << pin));
387
+ g_assert_true(get_irq(gpio_id * NUM_GPIO_PINS + pin));
388
+
389
+ /* Configure the line with pull-down, check the line is low */
390
+ gpio_set_2bits(gpio, PUPDR, pin, PUPDR_PULLDOWN);
391
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
392
+ g_assert_false(get_irq(gpio_id * NUM_GPIO_PINS + pin));
393
+
394
+ /* Clean the test */
395
+ gpio_writel(gpio, MODER, reset(gpio, MODER));
396
+ gpio_writel(gpio, PUPDR, reset(gpio, PUPDR));
397
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR));
398
+}
399
+
400
+static void test_push_pull(const void *data)
401
+{
402
+ /*
403
+ * Test that configuring a line in push-pull output mode
404
+ * disconnects the pin, that the pin can't be set or reset
405
+ * externally afterwards.
406
+ */
407
+ unsigned int pin = ((uint64_t)data) & 0xF;
408
+ uint32_t gpio = ((uint64_t)data) >> 32;
409
+ uint32_t gpio2 = GPIO_BASE_ADDR + (GPIO_H - gpio);
410
+
411
+ qtest_irq_intercept_in(global_qtest, "/machine/soc/syscfg");
412
+
413
+ /* Setting a line high externally, configuring it in push-pull output */
414
+ /* And checking the pin was disconnected */
415
+ gpio_set_irq(gpio, pin, 1);
416
+ gpio_set_2bits(gpio, MODER, pin, MODER_OUTPUT);
417
+ g_assert_cmphex(get_disconnected_pins(gpio), ==, 0xFFFF);
418
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
419
+
420
+ /* Setting a line low externally, configuring it in push-pull output */
421
+ /* And checking the pin was disconnected */
422
+ gpio_set_irq(gpio2, pin, 0);
423
+ gpio_set_bit(gpio2, ODR, pin, 1);
424
+ gpio_set_2bits(gpio2, MODER, pin, MODER_OUTPUT);
425
+ g_assert_cmphex(get_disconnected_pins(gpio2), ==, 0xFFFF);
426
+ g_assert_cmphex(gpio_readl(gpio2, IDR), ==, reset(gpio2, IDR) | (1 << pin));
427
+
428
+ /* Trying to set a push-pull output pin, checking it doesn't work */
429
+ gpio_set_irq(gpio, pin, 1);
430
+ g_assert_cmphex(get_disconnected_pins(gpio), ==, 0xFFFF);
431
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
432
+
433
+ /* Trying to reset a push-pull output pin, checking it doesn't work */
434
+ gpio_set_irq(gpio2, pin, 0);
435
+ g_assert_cmphex(get_disconnected_pins(gpio2), ==, 0xFFFF);
436
+ g_assert_cmphex(gpio_readl(gpio2, IDR), ==, reset(gpio2, IDR) | (1 << pin));
437
+
438
+ /* Clean the test */
439
+ gpio_writel(gpio, MODER, reset(gpio, MODER));
440
+ gpio_writel(gpio2, ODR, reset(gpio2, ODR));
441
+ gpio_writel(gpio2, MODER, reset(gpio2, MODER));
442
+}
443
+
444
+static void test_open_drain(const void *data)
445
+{
446
+ /*
447
+ * Test that configuring a line in open-drain output mode
448
+ * disconnects a pin set high externally and that the pin
449
+ * can't be set high externally while configured in open-drain.
450
+ *
451
+ * However a pin set low externally shouldn't be disconnected,
452
+ * and it can be set low externally when in open-drain mode.
453
+ */
454
+ unsigned int pin = ((uint64_t)data) & 0xF;
455
+ uint32_t gpio = ((uint64_t)data) >> 32;
456
+ uint32_t gpio2 = GPIO_BASE_ADDR + (GPIO_H - gpio);
457
+
458
+ qtest_irq_intercept_in(global_qtest, "/machine/soc/syscfg");
459
+
460
+ /* Setting a line high externally, configuring it in open-drain output */
461
+ /* And checking the pin was disconnected */
462
+ gpio_set_irq(gpio, pin, 1);
463
+ gpio_set_bit(gpio, OTYPER, pin, OTYPER_OPEN_DRAIN);
464
+ gpio_set_2bits(gpio, MODER, pin, MODER_OUTPUT);
465
+ g_assert_cmphex(get_disconnected_pins(gpio), ==, 0xFFFF);
466
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
467
+
468
+ /* Setting a line low externally, configuring it in open-drain output */
469
+ /* And checking the pin wasn't disconnected */
470
+ gpio_set_irq(gpio2, pin, 0);
471
+ gpio_set_bit(gpio2, ODR, pin, 1);
472
+ gpio_set_bit(gpio2, OTYPER, pin, OTYPER_OPEN_DRAIN);
473
+ gpio_set_2bits(gpio2, MODER, pin, MODER_OUTPUT);
474
+ g_assert_cmphex(get_disconnected_pins(gpio2), ==, 0xFFFF & ~(1 << pin));
475
+ g_assert_cmphex(gpio_readl(gpio2, IDR), ==,
476
+ reset(gpio2, IDR) & ~(1 << pin));
477
+
478
+ /* Trying to set a open-drain output pin, checking it doesn't work */
479
+ gpio_set_irq(gpio, pin, 1);
480
+ g_assert_cmphex(get_disconnected_pins(gpio), ==, 0xFFFF);
481
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR) & ~(1 << pin));
482
+
483
+ /* Trying to reset a open-drain output pin, checking it works */
484
+ gpio_set_bit(gpio, ODR, pin, 1);
485
+ gpio_set_irq(gpio, pin, 0);
486
+ g_assert_cmphex(get_disconnected_pins(gpio2), ==, 0xFFFF & ~(1 << pin));
487
+ g_assert_cmphex(gpio_readl(gpio2, IDR), ==,
488
+ reset(gpio2, IDR) & ~(1 << pin));
489
+
490
+ /* Clean the test */
491
+ disconnect_all_pins(gpio2);
492
+ gpio_writel(gpio2, OTYPER, reset(gpio2, OTYPER));
493
+ gpio_writel(gpio2, ODR, reset(gpio2, ODR));
494
+ gpio_writel(gpio2, MODER, reset(gpio2, MODER));
495
+ g_assert_cmphex(gpio_readl(gpio2, IDR), ==, reset(gpio2, IDR));
496
+ disconnect_all_pins(gpio);
497
+ gpio_writel(gpio, OTYPER, reset(gpio, OTYPER));
498
+ gpio_writel(gpio, ODR, reset(gpio, ODR));
499
+ gpio_writel(gpio, MODER, reset(gpio, MODER));
500
+ g_assert_cmphex(gpio_readl(gpio, IDR), ==, reset(gpio, IDR));
501
+}
502
+
503
+static void test_bsrr_brr(const void *data)
504
+{
505
+ /*
506
+ * Test that writing a '1' in BSS and BSRR
507
+ * has the desired effect on ODR.
508
+ * In BSRR, BSx has priority over BRx.
509
+ */
510
+ unsigned int pin = ((uint64_t)data) & 0xF;
511
+ uint32_t gpio = ((uint64_t)data) >> 32;
512
+
513
+ gpio_writel(gpio, BSRR, (1 << pin));
514
+ g_assert_cmphex(gpio_readl(gpio, ODR), ==, reset(gpio, ODR) | (1 << pin));
515
+
516
+ gpio_writel(gpio, BSRR, (1 << (pin + NUM_GPIO_PINS)));
517
+ g_assert_cmphex(gpio_readl(gpio, ODR), ==, reset(gpio, ODR));
518
+
519
+ gpio_writel(gpio, BSRR, (1 << pin));
520
+ g_assert_cmphex(gpio_readl(gpio, ODR), ==, reset(gpio, ODR) | (1 << pin));
521
+
522
+ gpio_writel(gpio, BRR, (1 << pin));
523
+ g_assert_cmphex(gpio_readl(gpio, ODR), ==, reset(gpio, ODR));
524
+
525
+ /* BSx should have priority over BRx */
526
+ gpio_writel(gpio, BSRR, (1 << pin) | (1 << (pin + NUM_GPIO_PINS)));
527
+ g_assert_cmphex(gpio_readl(gpio, ODR), ==, reset(gpio, ODR) | (1 << pin));
528
+
529
+ gpio_writel(gpio, BRR, (1 << pin));
530
+ g_assert_cmphex(gpio_readl(gpio, ODR), ==, reset(gpio, ODR));
531
+
532
+ gpio_writel(gpio, ODR, reset(gpio, ODR));
533
+}
534
+
535
+int main(int argc, char **argv)
536
+{
537
+ int ret;
538
+
539
+ g_test_init(&argc, &argv, NULL);
540
+ g_test_set_nonfatal_assertions();
541
+ qtest_add_func("stm32l4x5/gpio/test_idr_reset_value",
542
+ test_idr_reset_value);
543
+ /*
544
+ * The inputs for the tests (gpio and pin) can be changed,
545
+ * but the tests don't work for pins that are high at reset
546
+ * (GPIOA15, GPIO13 and GPIOB5).
547
+ * Specifically, rising the pin then checking `get_irq()`
548
+ * is problematic since the pin was already high.
549
+ */
550
+ qtest_add_data_func("stm32l4x5/gpio/test_gpioc5_output_mode",
551
+ (void *)((uint64_t)GPIO_C << 32 | 5),
552
+ test_gpio_output_mode);
553
+ qtest_add_data_func("stm32l4x5/gpio/test_gpioh3_output_mode",
554
+ (void *)((uint64_t)GPIO_H << 32 | 3),
555
+ test_gpio_output_mode);
556
+ qtest_add_data_func("stm32l4x5/gpio/test_gpio_input_mode1",
557
+ (void *)((uint64_t)GPIO_D << 32 | 6),
558
+ test_gpio_input_mode);
559
+ qtest_add_data_func("stm32l4x5/gpio/test_gpio_input_mode2",
560
+ (void *)((uint64_t)GPIO_C << 32 | 10),
561
+ test_gpio_input_mode);
562
+ qtest_add_data_func("stm32l4x5/gpio/test_gpio_pull_up_pull_down1",
563
+ (void *)((uint64_t)GPIO_B << 32 | 5),
564
+ test_pull_up_pull_down);
565
+ qtest_add_data_func("stm32l4x5/gpio/test_gpio_pull_up_pull_down2",
566
+ (void *)((uint64_t)GPIO_F << 32 | 1),
567
+ test_pull_up_pull_down);
568
+ qtest_add_data_func("stm32l4x5/gpio/test_gpio_push_pull1",
569
+ (void *)((uint64_t)GPIO_G << 32 | 6),
570
+ test_push_pull);
571
+ qtest_add_data_func("stm32l4x5/gpio/test_gpio_push_pull2",
572
+ (void *)((uint64_t)GPIO_H << 32 | 3),
573
+ test_push_pull);
574
+ qtest_add_data_func("stm32l4x5/gpio/test_gpio_open_drain1",
575
+ (void *)((uint64_t)GPIO_C << 32 | 4),
576
+ test_open_drain);
577
+ qtest_add_data_func("stm32l4x5/gpio/test_gpio_open_drain2",
578
+ (void *)((uint64_t)GPIO_E << 32 | 11),
579
+ test_open_drain);
580
+ qtest_add_data_func("stm32l4x5/gpio/test_bsrr_brr1",
581
+ (void *)((uint64_t)GPIO_A << 32 | 12),
582
+ test_bsrr_brr);
583
+ qtest_add_data_func("stm32l4x5/gpio/test_bsrr_brr2",
584
+ (void *)((uint64_t)GPIO_D << 32 | 0),
585
+ test_bsrr_brr);
586
+
587
+ qtest_start("-machine b-l475e-iot01a");
588
+ ret = g_test_run();
589
+ qtest_end();
590
+
591
+ return ret;
592
+}
593
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
89
index XXXXXXX..XXXXXXX 100644
594
index XXXXXXX..XXXXXXX 100644
90
--- a/docs/system/target-arm.rst
595
--- a/tests/qtest/meson.build
91
+++ b/docs/system/target-arm.rst
596
+++ b/tests/qtest/meson.build
92
@@ -XXX,XX +XXX,XX @@ undocumented; you can get a complete list by running
597
@@ -XXX,XX +XXX,XX @@ qtests_aspeed = \
93
arm/collie
598
qtests_stm32l4x5 = \
94
arm/sx1
599
['stm32l4x5_exti-test',
95
arm/stellaris
600
'stm32l4x5_syscfg-test',
96
+ arm/stm32
601
- 'stm32l4x5_rcc-test']
97
arm/virt
602
+ 'stm32l4x5_rcc-test',
98
arm/xlnx-versal-virt
603
+ 'stm32l4x5_gpio-test']
99
604
100
diff --git a/MAINTAINERS b/MAINTAINERS
605
qtests_arm = \
101
index XXXXXXX..XXXXXXX 100644
606
(config_all_devices.has_key('CONFIG_MPS2') ? ['sse-timer-test'] : []) + \
102
--- a/MAINTAINERS
103
+++ b/MAINTAINERS
104
@@ -XXX,XX +XXX,XX @@ M: Alexandre Iooss <erdnaxe@crans.org>
105
L: qemu-arm@nongnu.org
106
S: Maintained
107
F: hw/arm/stm32vldiscovery.c
108
+F: docs/system/arm/stm32.rst
109
110
Versatile Express
111
M: Peter Maydell <peter.maydell@linaro.org>
112
--
607
--
113
2.20.1
608
2.34.1
114
609
115
610
diff view generated by jsdifflib
1
The PL061 comes out of reset with all its lines configured as input,
1
From: Richard Henderson <richard.henderson@linaro.org>
2
which means they might need to be pulled to 0 or 1 depending on the
2
3
'pullups' and 'pulldowns' properties. Currently we do not assert
3
While the 8-bit input elements are sequential in the input vector,
4
these lines on reset; they will only be set whenever the guest first
4
the 32-bit output elements are not sequential in the output matrix.
5
touches a register that triggers a call to pl061_update().
5
Do not attempt to compute 2 32-bit outputs at the same time.
6
6
7
Convert the device to three-phase reset so we have a place where we
7
Cc: qemu-stable@nongnu.org
8
can safely call qemu_set_irq() to set the floating lines to their
8
Fixes: 23a5e3859f5 ("target/arm: Implement SME integer outer product")
9
correct values.
9
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2083
10
10
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
11
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
12
Message-id: 20240305163931.242795-1-richard.henderson@linaro.org
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
13
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
14
---
14
---
15
hw/gpio/pl061.c | 29 +++++++++++++++++++++++++----
15
target/arm/tcg/sme_helper.c | 77 ++++++++++++++++++-------------
16
hw/gpio/trace-events | 1 +
16
tests/tcg/aarch64/sme-smopa-1.c | 47 +++++++++++++++++++
17
2 files changed, 26 insertions(+), 4 deletions(-)
17
tests/tcg/aarch64/sme-smopa-2.c | 54 ++++++++++++++++++++++
18
18
tests/tcg/aarch64/Makefile.target | 2 +-
19
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c
19
4 files changed, 147 insertions(+), 33 deletions(-)
20
create mode 100644 tests/tcg/aarch64/sme-smopa-1.c
21
create mode 100644 tests/tcg/aarch64/sme-smopa-2.c
22
23
diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c
20
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
21
--- a/hw/gpio/pl061.c
25
--- a/target/arm/tcg/sme_helper.c
22
+++ b/hw/gpio/pl061.c
26
+++ b/target/arm/tcg/sme_helper.c
23
@@ -XXX,XX +XXX,XX @@ static void pl061_write(void *opaque, hwaddr offset,
27
@@ -XXX,XX +XXX,XX @@ void HELPER(sme_bfmopa)(void *vza, void *vzn, void *vzm, void *vpn,
24
return;
28
}
25
}
29
}
26
30
27
-static void pl061_reset(DeviceState *dev)
31
-typedef uint64_t IMOPFn(uint64_t, uint64_t, uint64_t, uint8_t, bool);
28
+static void pl061_enter_reset(Object *obj, ResetType type)
32
+typedef uint32_t IMOPFn32(uint32_t, uint32_t, uint32_t, uint8_t, bool);
33
+static inline void do_imopa_s(uint32_t *za, uint32_t *zn, uint32_t *zm,
34
+ uint8_t *pn, uint8_t *pm,
35
+ uint32_t desc, IMOPFn32 *fn)
36
+{
37
+ intptr_t row, col, oprsz = simd_oprsz(desc) / 4;
38
+ bool neg = simd_data(desc);
39
40
-static inline void do_imopa(uint64_t *za, uint64_t *zn, uint64_t *zm,
41
- uint8_t *pn, uint8_t *pm,
42
- uint32_t desc, IMOPFn *fn)
43
+ for (row = 0; row < oprsz; ++row) {
44
+ uint8_t pa = (pn[H1(row >> 1)] >> ((row & 1) * 4)) & 0xf;
45
+ uint32_t *za_row = &za[tile_vslice_index(row)];
46
+ uint32_t n = zn[H4(row)];
47
+
48
+ for (col = 0; col < oprsz; ++col) {
49
+ uint8_t pb = pm[H1(col >> 1)] >> ((col & 1) * 4);
50
+ uint32_t *a = &za_row[H4(col)];
51
+
52
+ *a = fn(n, zm[H4(col)], *a, pa & pb, neg);
53
+ }
54
+ }
55
+}
56
+
57
+typedef uint64_t IMOPFn64(uint64_t, uint64_t, uint64_t, uint8_t, bool);
58
+static inline void do_imopa_d(uint64_t *za, uint64_t *zn, uint64_t *zm,
59
+ uint8_t *pn, uint8_t *pm,
60
+ uint32_t desc, IMOPFn64 *fn)
29
{
61
{
30
- PL061State *s = PL061(dev);
62
intptr_t row, col, oprsz = simd_oprsz(desc) / 8;
31
+ PL061State *s = PL061(obj);
63
bool neg = simd_data(desc);
32
+
64
@@ -XXX,XX +XXX,XX @@ static inline void do_imopa(uint64_t *za, uint64_t *zn, uint64_t *zm,
33
+ trace_pl061_reset(DEVICE(s)->canonical_path);
34
35
/* reset values from PL061 TRM, Stellaris LM3S5P31 & LM3S8962 Data Sheet */
36
s->data = 0;
37
- s->old_out_data = 0;
38
s->old_in_data = 0;
39
s->dir = 0;
40
s->isense = 0;
41
@@ -XXX,XX +XXX,XX @@ static void pl061_reset(DeviceState *dev)
42
s->amsel = 0;
43
}
65
}
44
66
45
+static void pl061_hold_reset(Object *obj)
67
#define DEF_IMOP_32(NAME, NTYPE, MTYPE) \
68
-static uint64_t NAME(uint64_t n, uint64_t m, uint64_t a, uint8_t p, bool neg) \
69
+static uint32_t NAME(uint32_t n, uint32_t m, uint32_t a, uint8_t p, bool neg) \
70
{ \
71
- uint32_t sum0 = 0, sum1 = 0; \
72
+ uint32_t sum = 0; \
73
/* Apply P to N as a mask, making the inactive elements 0. */ \
74
n &= expand_pred_b(p); \
75
- sum0 += (NTYPE)(n >> 0) * (MTYPE)(m >> 0); \
76
- sum0 += (NTYPE)(n >> 8) * (MTYPE)(m >> 8); \
77
- sum0 += (NTYPE)(n >> 16) * (MTYPE)(m >> 16); \
78
- sum0 += (NTYPE)(n >> 24) * (MTYPE)(m >> 24); \
79
- sum1 += (NTYPE)(n >> 32) * (MTYPE)(m >> 32); \
80
- sum1 += (NTYPE)(n >> 40) * (MTYPE)(m >> 40); \
81
- sum1 += (NTYPE)(n >> 48) * (MTYPE)(m >> 48); \
82
- sum1 += (NTYPE)(n >> 56) * (MTYPE)(m >> 56); \
83
- if (neg) { \
84
- sum0 = (uint32_t)a - sum0, sum1 = (uint32_t)(a >> 32) - sum1; \
85
- } else { \
86
- sum0 = (uint32_t)a + sum0, sum1 = (uint32_t)(a >> 32) + sum1; \
87
- } \
88
- return ((uint64_t)sum1 << 32) | sum0; \
89
+ sum += (NTYPE)(n >> 0) * (MTYPE)(m >> 0); \
90
+ sum += (NTYPE)(n >> 8) * (MTYPE)(m >> 8); \
91
+ sum += (NTYPE)(n >> 16) * (MTYPE)(m >> 16); \
92
+ sum += (NTYPE)(n >> 24) * (MTYPE)(m >> 24); \
93
+ return neg ? a - sum : a + sum; \
94
}
95
96
#define DEF_IMOP_64(NAME, NTYPE, MTYPE) \
97
@@ -XXX,XX +XXX,XX @@ DEF_IMOP_64(umopa_d, uint16_t, uint16_t)
98
DEF_IMOP_64(sumopa_d, int16_t, uint16_t)
99
DEF_IMOP_64(usmopa_d, uint16_t, int16_t)
100
101
-#define DEF_IMOPH(NAME) \
102
- void HELPER(sme_##NAME)(void *vza, void *vzn, void *vzm, void *vpn, \
103
- void *vpm, uint32_t desc) \
104
- { do_imopa(vza, vzn, vzm, vpn, vpm, desc, NAME); }
105
+#define DEF_IMOPH(NAME, S) \
106
+ void HELPER(sme_##NAME##_##S)(void *vza, void *vzn, void *vzm, \
107
+ void *vpn, void *vpm, uint32_t desc) \
108
+ { do_imopa_##S(vza, vzn, vzm, vpn, vpm, desc, NAME##_##S); }
109
110
-DEF_IMOPH(smopa_s)
111
-DEF_IMOPH(umopa_s)
112
-DEF_IMOPH(sumopa_s)
113
-DEF_IMOPH(usmopa_s)
114
-DEF_IMOPH(smopa_d)
115
-DEF_IMOPH(umopa_d)
116
-DEF_IMOPH(sumopa_d)
117
-DEF_IMOPH(usmopa_d)
118
+DEF_IMOPH(smopa, s)
119
+DEF_IMOPH(umopa, s)
120
+DEF_IMOPH(sumopa, s)
121
+DEF_IMOPH(usmopa, s)
122
+
123
+DEF_IMOPH(smopa, d)
124
+DEF_IMOPH(umopa, d)
125
+DEF_IMOPH(sumopa, d)
126
+DEF_IMOPH(usmopa, d)
127
diff --git a/tests/tcg/aarch64/sme-smopa-1.c b/tests/tcg/aarch64/sme-smopa-1.c
128
new file mode 100644
129
index XXXXXXX..XXXXXXX
130
--- /dev/null
131
+++ b/tests/tcg/aarch64/sme-smopa-1.c
132
@@ -XXX,XX +XXX,XX @@
133
+#include <stdio.h>
134
+#include <string.h>
135
+
136
+int main()
46
+{
137
+{
47
+ PL061State *s = PL061(obj);
138
+ static const int cmp[4][4] = {
48
+ int i, level;
139
+ { 110, 134, 158, 182 },
49
+ uint8_t floating = pl061_floating(s);
140
+ { 390, 478, 566, 654 },
50
+ uint8_t pullups = pl061_pullups(s);
141
+ { 670, 822, 974, 1126 },
51
+
142
+ { 950, 1166, 1382, 1598 }
52
+ for (i = 0; i < N_GPIOS; i++) {
143
+ };
53
+ if (extract32(floating, i, 1)) {
144
+ int dst[4][4];
54
+ continue;
145
+ int *tmp = &dst[0][0];
146
+
147
+ asm volatile(
148
+ ".arch armv8-r+sme\n\t"
149
+ "smstart\n\t"
150
+ "index z0.b, #0, #1\n\t"
151
+ "movprfx z1, z0\n\t"
152
+ "add z1.b, z1.b, #16\n\t"
153
+ "ptrue p0.b\n\t"
154
+ "smopa za0.s, p0/m, p0/m, z0.b, z1.b\n\t"
155
+ "ptrue p0.s, vl4\n\t"
156
+ "mov w12, #0\n\t"
157
+ "st1w { za0h.s[w12, #0] }, p0, [%0]\n\t"
158
+ "add %0, %0, #16\n\t"
159
+ "st1w { za0h.s[w12, #1] }, p0, [%0]\n\t"
160
+ "add %0, %0, #16\n\t"
161
+ "st1w { za0h.s[w12, #2] }, p0, [%0]\n\t"
162
+ "add %0, %0, #16\n\t"
163
+ "st1w { za0h.s[w12, #3] }, p0, [%0]\n\t"
164
+ "smstop"
165
+ : "+r"(tmp) : : "memory");
166
+
167
+ if (memcmp(cmp, dst, sizeof(dst)) == 0) {
168
+ return 0;
169
+ }
170
+
171
+ /* See above for correct results. */
172
+ for (int i = 0; i < 4; ++i) {
173
+ for (int j = 0; j < 4; ++j) {
174
+ printf("%6d", dst[i][j]);
55
+ }
175
+ }
56
+ level = extract32(pullups, i, 1);
176
+ printf("\n");
57
+ trace_pl061_set_output(DEVICE(s)->canonical_path, i, level);
177
+ }
58
+ qemu_set_irq(s->out[i], level);
178
+ return 1;
59
+ }
60
+ s->old_out_data = pullups;
61
+}
179
+}
62
+
180
diff --git a/tests/tcg/aarch64/sme-smopa-2.c b/tests/tcg/aarch64/sme-smopa-2.c
63
static void pl061_set_irq(void * opaque, int irq, int level)
181
new file mode 100644
64
{
182
index XXXXXXX..XXXXXXX
65
PL061State *s = (PL061State *)opaque;
183
--- /dev/null
66
@@ -XXX,XX +XXX,XX @@ static Property pl061_props[] = {
184
+++ b/tests/tcg/aarch64/sme-smopa-2.c
67
static void pl061_class_init(ObjectClass *klass, void *data)
185
@@ -XXX,XX +XXX,XX @@
68
{
186
+#include <stdio.h>
69
DeviceClass *dc = DEVICE_CLASS(klass);
187
+#include <string.h>
70
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
188
+
71
189
+int main()
72
dc->vmsd = &vmstate_pl061;
190
+{
73
- dc->reset = &pl061_reset;
191
+ static const long cmp[4][4] = {
74
dc->realize = pl061_realize;
192
+ { 110, 134, 158, 182 },
75
device_class_set_props(dc, pl061_props);
193
+ { 390, 478, 566, 654 },
76
+ rc->phases.enter = pl061_enter_reset;
194
+ { 670, 822, 974, 1126 },
77
+ rc->phases.hold = pl061_hold_reset;
195
+ { 950, 1166, 1382, 1598 }
78
}
196
+ };
79
197
+ long dst[4][4];
80
static const TypeInfo pl061_info = {
198
+ long *tmp = &dst[0][0];
81
diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events
199
+ long svl;
200
+
201
+ /* Validate that we have a wide enough vector for 4 elements. */
202
+ asm(".arch armv8-r+sme-i64\n\trdsvl %0, #1" : "=r"(svl));
203
+ if (svl < 32) {
204
+ return 0;
205
+ }
206
+
207
+ asm volatile(
208
+ "smstart\n\t"
209
+ "index z0.h, #0, #1\n\t"
210
+ "movprfx z1, z0\n\t"
211
+ "add z1.h, z1.h, #16\n\t"
212
+ "ptrue p0.b\n\t"
213
+ "smopa za0.d, p0/m, p0/m, z0.h, z1.h\n\t"
214
+ "ptrue p0.d, vl4\n\t"
215
+ "mov w12, #0\n\t"
216
+ "st1d { za0h.d[w12, #0] }, p0, [%0]\n\t"
217
+ "add %0, %0, #32\n\t"
218
+ "st1d { za0h.d[w12, #1] }, p0, [%0]\n\t"
219
+ "mov w12, #2\n\t"
220
+ "add %0, %0, #32\n\t"
221
+ "st1d { za0h.d[w12, #0] }, p0, [%0]\n\t"
222
+ "add %0, %0, #32\n\t"
223
+ "st1d { za0h.d[w12, #1] }, p0, [%0]\n\t"
224
+ "smstop"
225
+ : "+r"(tmp) : : "memory");
226
+
227
+ if (memcmp(cmp, dst, sizeof(dst)) == 0) {
228
+ return 0;
229
+ }
230
+
231
+ /* See above for correct results. */
232
+ for (int i = 0; i < 4; ++i) {
233
+ for (int j = 0; j < 4; ++j) {
234
+ printf("%6ld", dst[i][j]);
235
+ }
236
+ printf("\n");
237
+ }
238
+ return 1;
239
+}
240
diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
82
index XXXXXXX..XXXXXXX 100644
241
index XXXXXXX..XXXXXXX 100644
83
--- a/hw/gpio/trace-events
242
--- a/tests/tcg/aarch64/Makefile.target
84
+++ b/hw/gpio/trace-events
243
+++ b/tests/tcg/aarch64/Makefile.target
85
@@ -XXX,XX +XXX,XX @@ pl061_input_change(const char *id, int gpio, int level) "%s input %d changed to
244
@@ -XXX,XX +XXX,XX @@ endif
86
pl061_update_istate(const char *id, uint32_t istate, uint32_t im, int level) "%s GPIORIS 0x%x GPIOIE 0x%x interrupt level %d"
245
87
pl061_read(const char *id, uint64_t offset, uint64_t r) "%s offset 0x%" PRIx64 " value 0x%" PRIx64
246
# SME Tests
88
pl061_write(const char *id, uint64_t offset, uint64_t value) "%s offset 0x%" PRIx64 " value 0x%" PRIx64
247
ifneq ($(CROSS_AS_HAS_ARMV9_SME),)
89
+pl061_reset(const char *id) "%s reset"
248
-AARCH64_TESTS += sme-outprod1
90
249
+AARCH64_TESTS += sme-outprod1 sme-smopa-1 sme-smopa-2
91
# sifive_gpio.c
250
endif
92
sifive_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" PRIx64
251
252
# System Registers Tests
93
--
253
--
94
2.20.1
254
2.34.1
95
255
96
256
diff view generated by jsdifflib
1
The stellaris board doesn't emulate the handling of the OLED
1
The sun4v RTC device model added under commit a0e893039cf2ce0 in 2016
2
chipselect line correctly. Expand the comment describing this,
2
was unfortunately added with a license of GPL-v3-or-later, which is
3
including a sketch of the theoretical correct way to do it.
3
not compatible with other QEMU code which has a GPL-v2-only license.
4
4
5
Relicense the code in the .c and the .h file to GPL-v2-or-later,
6
to make it compatible with the rest of QEMU.
7
8
Cc: qemu-stable@nongnu.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Paolo Bonzini (for Red Hat) <pbonzini@redhat.com>
11
Signed-off-by: Artyom Tarasenko <atar4qemu@gmail.com>
12
Signed-off-by: Markus Armbruster <armbru@redhat.com>
13
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
14
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
15
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
16
Acked-by: Alex Bennée <alex.bennee@linaro.org>
17
Message-id: 20240223161300.938542-1-peter.maydell@linaro.org
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
18
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
---
19
---
7
hw/arm/stellaris.c | 56 +++++++++++++++++++++++++++++++++++++++++++++-
20
include/hw/rtc/sun4v-rtc.h | 2 +-
8
1 file changed, 55 insertions(+), 1 deletion(-)
21
hw/rtc/sun4v-rtc.c | 2 +-
22
2 files changed, 2 insertions(+), 2 deletions(-)
9
23
10
diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
24
diff --git a/include/hw/rtc/sun4v-rtc.h b/include/hw/rtc/sun4v-rtc.h
11
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
12
--- a/hw/arm/stellaris.c
26
--- a/include/hw/rtc/sun4v-rtc.h
13
+++ b/hw/arm/stellaris.c
27
+++ b/include/hw/rtc/sun4v-rtc.h
14
@@ -XXX,XX +XXX,XX @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
28
@@ -XXX,XX +XXX,XX @@
15
DeviceState *sddev;
29
*
16
DeviceState *ssddev;
30
* Copyright (c) 2016 Artyom Tarasenko
17
31
*
18
- /* Some boards have both an OLED controller and SD card connected to
32
- * This code is licensed under the GNU GPL v3 or (at your option) any later
19
+ /*
33
+ * This code is licensed under the GNU GPL v2 or (at your option) any later
20
+ * Some boards have both an OLED controller and SD card connected to
34
* version.
21
* the same SSI port, with the SD card chip select connected to a
35
*/
22
* GPIO pin. Technically the OLED chip select is connected to the
36
23
* SSI Fss pin. We do not bother emulating that as both devices
37
diff --git a/hw/rtc/sun4v-rtc.c b/hw/rtc/sun4v-rtc.c
24
* should never be selected simultaneously, and our OLED controller
38
index XXXXXXX..XXXXXXX 100644
25
* ignores stray 0xff commands that occur when deselecting the SD
39
--- a/hw/rtc/sun4v-rtc.c
26
* card.
40
+++ b/hw/rtc/sun4v-rtc.c
27
+ *
41
@@ -XXX,XX +XXX,XX @@
28
+ * The h/w wiring is:
42
*
29
+ * - GPIO pin D0 is wired to the active-low SD card chip select
43
* Copyright (c) 2016 Artyom Tarasenko
30
+ * - GPIO pin A3 is wired to the active-low OLED chip select
44
*
31
+ * - The SoC wiring of the PL061 "auxiliary function" for A3 is
45
- * This code is licensed under the GNU GPL v3 or (at your option) any later
32
+ * SSI0Fss ("frame signal"), which is an output from the SoC's
46
+ * This code is licensed under the GNU GPL v2 or (at your option) any later
33
+ * SSI controller. The SSI controller takes SSI0Fss low when it
47
* version.
34
+ * transmits a frame, so it can work as a chip-select signal.
48
*/
35
+ * - GPIO A4 is aux-function SSI0Rx, and wired to the SD card Tx
36
+ * (the OLED never sends data to the CPU, so no wiring needed)
37
+ * - GPIO A5 is aux-function SSI0Tx, and wired to the SD card Rx
38
+ * and the OLED display-data-in
39
+ * - GPIO A2 is aux-function SSI0Clk, wired to SD card and OLED
40
+ * serial-clock input
41
+ * So a guest that wants to use the OLED can configure the PL061
42
+ * to make pins A2, A3, A5 aux-function, so they are connected
43
+ * directly to the SSI controller. When the SSI controller sends
44
+ * data it asserts SSI0Fss which selects the OLED.
45
+ * A guest that wants to use the SD card configures A2, A4 and A5
46
+ * as aux-function, but leaves A3 as a software-controlled GPIO
47
+ * line. It asserts the SD card chip-select by using the PL061
48
+ * to control pin D0, and lets the SSI controller handle Clk, Tx
49
+ * and Rx. (The SSI controller asserts Fss during tx cycles as
50
+ * usual, but because A3 is not set to aux-function this is not
51
+ * forwarded to the OLED, and so the OLED stays unselected.)
52
+ *
53
+ * The QEMU implementation instead is:
54
+ * - GPIO pin D0 is wired to the active-low SD card chip select,
55
+ * and also to the OLED chip-select which is implemented
56
+ * as *active-high*
57
+ * - SSI controller signals go to the devices regardless of
58
+ * whether the guest programs A2, A4, A5 as aux-function or not
59
+ *
60
+ * The problem with this implementation is if the guest doesn't
61
+ * care about the SD card and only uses the OLED. In that case it
62
+ * may choose never to do anything with D0 (leaving it in its
63
+ * default floating state, which reliably leaves the card disabled
64
+ * because an SD card has a pullup on CS within the card itself),
65
+ * and only set up A2, A3, A5. This for us would mean the OLED
66
+ * never gets the chip-select assert it needs. We work around
67
+ * this with a manual raise of D0 here (despite board creation
68
+ * code being the wrong place to raise IRQ lines) to put the OLED
69
+ * into an initially selected state.
70
+ *
71
+ * In theory the right way to model this would be:
72
+ * - Implement aux-function support in the PL061, with an
73
+ * extra set of AFIN and AFOUT GPIO lines (set up so that
74
+ * if a GPIO line is in auxfn mode the main GPIO in and out
75
+ * track the AFIN and AFOUT lines)
76
+ * - Wire the AFOUT for D0 up to either a line from the
77
+ * SSI controller that's pulled low around every transmit,
78
+ * or at least to an always-0 line here on the board
79
+ * - Make the ssd0323 OLED controller chipselect active-low
80
*/
81
bus = qdev_get_child_bus(dev, "ssi");
82
49
83
--
50
--
84
2.20.1
51
2.34.1
85
52
86
53
diff view generated by jsdifflib
1
From: Alexandre Iooss <erdnaxe@crans.org>
1
From: Thomas Huth <thuth@redhat.com>
2
2
3
This is a Cortex-M3 based machine. Information can be found at:
3
Move the code to a separate file so that we do not have to compile
4
https://www.st.com/en/evaluation-tools/stm32vldiscovery.html
4
it anymore if CONFIG_ARM_V7M is not set.
5
5
6
Signed-off-by: Alexandre Iooss <erdnaxe@crans.org>
6
Signed-off-by: Thomas Huth <thuth@redhat.com>
7
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
7
Message-id: 20240308141051.536599-2-thuth@redhat.com
8
Message-id: 20210617165647.2575955-3-erdnaxe@crans.org
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
10
---
11
default-configs/devices/arm-softmmu.mak | 1 +
11
target/arm/tcg/cpu-v7m.c | 290 +++++++++++++++++++++++++++++++++++++
12
hw/arm/stm32vldiscovery.c | 66 +++++++++++++++++++++++++
12
target/arm/tcg/cpu32.c | 261 ---------------------------------
13
MAINTAINERS | 6 +++
13
target/arm/meson.build | 3 +
14
hw/arm/Kconfig | 4 ++
14
target/arm/tcg/meson.build | 3 +
15
hw/arm/meson.build | 1 +
15
4 files changed, 296 insertions(+), 261 deletions(-)
16
5 files changed, 78 insertions(+)
16
create mode 100644 target/arm/tcg/cpu-v7m.c
17
create mode 100644 hw/arm/stm32vldiscovery.c
18
17
19
diff --git a/default-configs/devices/arm-softmmu.mak b/default-configs/devices/arm-softmmu.mak
18
diff --git a/target/arm/tcg/cpu-v7m.c b/target/arm/tcg/cpu-v7m.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/default-configs/devices/arm-softmmu.mak
22
+++ b/default-configs/devices/arm-softmmu.mak
23
@@ -XXX,XX +XXX,XX @@ CONFIG_CHEETAH=y
24
CONFIG_SX1=y
25
CONFIG_NSERIES=y
26
CONFIG_STELLARIS=y
27
+CONFIG_STM32VLDISCOVERY=y
28
CONFIG_REALVIEW=y
29
CONFIG_VERSATILE=y
30
CONFIG_VEXPRESS=y
31
diff --git a/hw/arm/stm32vldiscovery.c b/hw/arm/stm32vldiscovery.c
32
new file mode 100644
19
new file mode 100644
33
index XXXXXXX..XXXXXXX
20
index XXXXXXX..XXXXXXX
34
--- /dev/null
21
--- /dev/null
35
+++ b/hw/arm/stm32vldiscovery.c
22
+++ b/target/arm/tcg/cpu-v7m.c
36
@@ -XXX,XX +XXX,XX @@
23
@@ -XXX,XX +XXX,XX @@
37
+/*
24
+/*
38
+ * ST STM32VLDISCOVERY machine
25
+ * QEMU ARMv7-M TCG-only CPUs.
39
+ *
26
+ *
40
+ * Copyright (c) 2021 Alexandre Iooss <erdnaxe@crans.org>
27
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
41
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
42
+ *
28
+ *
43
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
29
+ * This code is licensed under the GNU GPL v2 or later.
44
+ * of this software and associated documentation files (the "Software"), to deal
45
+ * in the Software without restriction, including without limitation the rights
46
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
47
+ * copies of the Software, and to permit persons to whom the Software is
48
+ * furnished to do so, subject to the following conditions:
49
+ *
30
+ *
50
+ * The above copyright notice and this permission notice shall be included in
31
+ * SPDX-License-Identifier: GPL-2.0-or-later
51
+ * all copies or substantial portions of the Software.
52
+ *
53
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
54
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
55
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
56
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
57
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
58
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
59
+ * THE SOFTWARE.
60
+ */
32
+ */
61
+
33
+
62
+#include "qemu/osdep.h"
34
+#include "qemu/osdep.h"
63
+#include "qapi/error.h"
35
+#include "cpu.h"
64
+#include "hw/boards.h"
36
+#include "hw/core/tcg-cpu-ops.h"
65
+#include "hw/qdev-properties.h"
37
+#include "internals.h"
66
+#include "qemu/error-report.h"
38
+
67
+#include "hw/arm/stm32f100_soc.h"
39
+#if !defined(CONFIG_USER_ONLY)
68
+#include "hw/arm/boot.h"
40
+
69
+
41
+#include "hw/intc/armv7m_nvic.h"
70
+/* stm32vldiscovery implementation is derived from netduinoplus2 */
42
+
71
+
43
+static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
72
+/* Main SYSCLK frequency in Hz (24MHz) */
44
+{
73
+#define SYSCLK_FRQ 24000000ULL
45
+ CPUClass *cc = CPU_GET_CLASS(cs);
74
+
46
+ ARMCPU *cpu = ARM_CPU(cs);
75
+static void stm32vldiscovery_init(MachineState *machine)
47
+ CPUARMState *env = &cpu->env;
76
+{
48
+ bool ret = false;
77
+ DeviceState *dev;
78
+
49
+
79
+ /*
50
+ /*
80
+ * TODO: ideally we would model the SoC RCC and let it handle
51
+ * ARMv7-M interrupt masking works differently than -A or -R.
81
+ * system_clock_scale, including its ability to define different
52
+ * There is no FIQ/IRQ distinction. Instead of I and F bits
82
+ * possible SYSCLK sources.
53
+ * masking FIQ and IRQ interrupts, an exception is taken only
54
+ * if it is higher priority than the current execution priority
55
+ * (which depends on state like BASEPRI, FAULTMASK and the
56
+ * currently active exception).
83
+ */
57
+ */
84
+ system_clock_scale = NANOSECONDS_PER_SECOND / SYSCLK_FRQ;
58
+ if (interrupt_request & CPU_INTERRUPT_HARD
85
+
59
+ && (armv7m_nvic_can_take_pending_exception(env->nvic))) {
86
+ dev = qdev_new(TYPE_STM32F100_SOC);
60
+ cs->exception_index = EXCP_IRQ;
87
+ qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3"));
61
+ cc->tcg_ops->do_interrupt(cs);
88
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
62
+ ret = true;
89
+
63
+ }
90
+ armv7m_load_kernel(ARM_CPU(first_cpu),
64
+ return ret;
91
+ machine->kernel_filename,
65
+}
92
+ FLASH_SIZE);
66
+
93
+}
67
+#endif /* !CONFIG_USER_ONLY */
94
+
68
+
95
+static void stm32vldiscovery_machine_init(MachineClass *mc)
69
+static void cortex_m0_initfn(Object *obj)
96
+{
70
+{
97
+ mc->desc = "ST STM32VLDISCOVERY (Cortex-M3)";
71
+ ARMCPU *cpu = ARM_CPU(obj);
98
+ mc->init = stm32vldiscovery_init;
72
+ set_feature(&cpu->env, ARM_FEATURE_V6);
99
+}
73
+ set_feature(&cpu->env, ARM_FEATURE_M);
100
+
74
+
101
+DEFINE_MACHINE("stm32vldiscovery", stm32vldiscovery_machine_init)
75
+ cpu->midr = 0x410cc200;
102
+
76
+
103
diff --git a/MAINTAINERS b/MAINTAINERS
77
+ /*
78
+ * These ID register values are not guest visible, because
79
+ * we do not implement the Main Extension. They must be set
80
+ * to values corresponding to the Cortex-M0's implemented
81
+ * features, because QEMU generally controls its emulation
82
+ * by looking at ID register fields. We use the same values as
83
+ * for the M3.
84
+ */
85
+ cpu->isar.id_pfr0 = 0x00000030;
86
+ cpu->isar.id_pfr1 = 0x00000200;
87
+ cpu->isar.id_dfr0 = 0x00100000;
88
+ cpu->id_afr0 = 0x00000000;
89
+ cpu->isar.id_mmfr0 = 0x00000030;
90
+ cpu->isar.id_mmfr1 = 0x00000000;
91
+ cpu->isar.id_mmfr2 = 0x00000000;
92
+ cpu->isar.id_mmfr3 = 0x00000000;
93
+ cpu->isar.id_isar0 = 0x01141110;
94
+ cpu->isar.id_isar1 = 0x02111000;
95
+ cpu->isar.id_isar2 = 0x21112231;
96
+ cpu->isar.id_isar3 = 0x01111110;
97
+ cpu->isar.id_isar4 = 0x01310102;
98
+ cpu->isar.id_isar5 = 0x00000000;
99
+ cpu->isar.id_isar6 = 0x00000000;
100
+}
101
+
102
+static void cortex_m3_initfn(Object *obj)
103
+{
104
+ ARMCPU *cpu = ARM_CPU(obj);
105
+ set_feature(&cpu->env, ARM_FEATURE_V7);
106
+ set_feature(&cpu->env, ARM_FEATURE_M);
107
+ set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
108
+ cpu->midr = 0x410fc231;
109
+ cpu->pmsav7_dregion = 8;
110
+ cpu->isar.id_pfr0 = 0x00000030;
111
+ cpu->isar.id_pfr1 = 0x00000200;
112
+ cpu->isar.id_dfr0 = 0x00100000;
113
+ cpu->id_afr0 = 0x00000000;
114
+ cpu->isar.id_mmfr0 = 0x00000030;
115
+ cpu->isar.id_mmfr1 = 0x00000000;
116
+ cpu->isar.id_mmfr2 = 0x00000000;
117
+ cpu->isar.id_mmfr3 = 0x00000000;
118
+ cpu->isar.id_isar0 = 0x01141110;
119
+ cpu->isar.id_isar1 = 0x02111000;
120
+ cpu->isar.id_isar2 = 0x21112231;
121
+ cpu->isar.id_isar3 = 0x01111110;
122
+ cpu->isar.id_isar4 = 0x01310102;
123
+ cpu->isar.id_isar5 = 0x00000000;
124
+ cpu->isar.id_isar6 = 0x00000000;
125
+}
126
+
127
+static void cortex_m4_initfn(Object *obj)
128
+{
129
+ ARMCPU *cpu = ARM_CPU(obj);
130
+
131
+ set_feature(&cpu->env, ARM_FEATURE_V7);
132
+ set_feature(&cpu->env, ARM_FEATURE_M);
133
+ set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
134
+ set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
135
+ cpu->midr = 0x410fc240; /* r0p0 */
136
+ cpu->pmsav7_dregion = 8;
137
+ cpu->isar.mvfr0 = 0x10110021;
138
+ cpu->isar.mvfr1 = 0x11000011;
139
+ cpu->isar.mvfr2 = 0x00000000;
140
+ cpu->isar.id_pfr0 = 0x00000030;
141
+ cpu->isar.id_pfr1 = 0x00000200;
142
+ cpu->isar.id_dfr0 = 0x00100000;
143
+ cpu->id_afr0 = 0x00000000;
144
+ cpu->isar.id_mmfr0 = 0x00000030;
145
+ cpu->isar.id_mmfr1 = 0x00000000;
146
+ cpu->isar.id_mmfr2 = 0x00000000;
147
+ cpu->isar.id_mmfr3 = 0x00000000;
148
+ cpu->isar.id_isar0 = 0x01141110;
149
+ cpu->isar.id_isar1 = 0x02111000;
150
+ cpu->isar.id_isar2 = 0x21112231;
151
+ cpu->isar.id_isar3 = 0x01111110;
152
+ cpu->isar.id_isar4 = 0x01310102;
153
+ cpu->isar.id_isar5 = 0x00000000;
154
+ cpu->isar.id_isar6 = 0x00000000;
155
+}
156
+
157
+static void cortex_m7_initfn(Object *obj)
158
+{
159
+ ARMCPU *cpu = ARM_CPU(obj);
160
+
161
+ set_feature(&cpu->env, ARM_FEATURE_V7);
162
+ set_feature(&cpu->env, ARM_FEATURE_M);
163
+ set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
164
+ set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
165
+ cpu->midr = 0x411fc272; /* r1p2 */
166
+ cpu->pmsav7_dregion = 8;
167
+ cpu->isar.mvfr0 = 0x10110221;
168
+ cpu->isar.mvfr1 = 0x12000011;
169
+ cpu->isar.mvfr2 = 0x00000040;
170
+ cpu->isar.id_pfr0 = 0x00000030;
171
+ cpu->isar.id_pfr1 = 0x00000200;
172
+ cpu->isar.id_dfr0 = 0x00100000;
173
+ cpu->id_afr0 = 0x00000000;
174
+ cpu->isar.id_mmfr0 = 0x00100030;
175
+ cpu->isar.id_mmfr1 = 0x00000000;
176
+ cpu->isar.id_mmfr2 = 0x01000000;
177
+ cpu->isar.id_mmfr3 = 0x00000000;
178
+ cpu->isar.id_isar0 = 0x01101110;
179
+ cpu->isar.id_isar1 = 0x02112000;
180
+ cpu->isar.id_isar2 = 0x20232231;
181
+ cpu->isar.id_isar3 = 0x01111131;
182
+ cpu->isar.id_isar4 = 0x01310132;
183
+ cpu->isar.id_isar5 = 0x00000000;
184
+ cpu->isar.id_isar6 = 0x00000000;
185
+}
186
+
187
+static void cortex_m33_initfn(Object *obj)
188
+{
189
+ ARMCPU *cpu = ARM_CPU(obj);
190
+
191
+ set_feature(&cpu->env, ARM_FEATURE_V8);
192
+ set_feature(&cpu->env, ARM_FEATURE_M);
193
+ set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
194
+ set_feature(&cpu->env, ARM_FEATURE_M_SECURITY);
195
+ set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
196
+ cpu->midr = 0x410fd213; /* r0p3 */
197
+ cpu->pmsav7_dregion = 16;
198
+ cpu->sau_sregion = 8;
199
+ cpu->isar.mvfr0 = 0x10110021;
200
+ cpu->isar.mvfr1 = 0x11000011;
201
+ cpu->isar.mvfr2 = 0x00000040;
202
+ cpu->isar.id_pfr0 = 0x00000030;
203
+ cpu->isar.id_pfr1 = 0x00000210;
204
+ cpu->isar.id_dfr0 = 0x00200000;
205
+ cpu->id_afr0 = 0x00000000;
206
+ cpu->isar.id_mmfr0 = 0x00101F40;
207
+ cpu->isar.id_mmfr1 = 0x00000000;
208
+ cpu->isar.id_mmfr2 = 0x01000000;
209
+ cpu->isar.id_mmfr3 = 0x00000000;
210
+ cpu->isar.id_isar0 = 0x01101110;
211
+ cpu->isar.id_isar1 = 0x02212000;
212
+ cpu->isar.id_isar2 = 0x20232232;
213
+ cpu->isar.id_isar3 = 0x01111131;
214
+ cpu->isar.id_isar4 = 0x01310132;
215
+ cpu->isar.id_isar5 = 0x00000000;
216
+ cpu->isar.id_isar6 = 0x00000000;
217
+ cpu->clidr = 0x00000000;
218
+ cpu->ctr = 0x8000c000;
219
+}
220
+
221
+static void cortex_m55_initfn(Object *obj)
222
+{
223
+ ARMCPU *cpu = ARM_CPU(obj);
224
+
225
+ set_feature(&cpu->env, ARM_FEATURE_V8);
226
+ set_feature(&cpu->env, ARM_FEATURE_V8_1M);
227
+ set_feature(&cpu->env, ARM_FEATURE_M);
228
+ set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
229
+ set_feature(&cpu->env, ARM_FEATURE_M_SECURITY);
230
+ set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
231
+ cpu->midr = 0x410fd221; /* r0p1 */
232
+ cpu->revidr = 0;
233
+ cpu->pmsav7_dregion = 16;
234
+ cpu->sau_sregion = 8;
235
+ /* These are the MVFR* values for the FPU + full MVE configuration */
236
+ cpu->isar.mvfr0 = 0x10110221;
237
+ cpu->isar.mvfr1 = 0x12100211;
238
+ cpu->isar.mvfr2 = 0x00000040;
239
+ cpu->isar.id_pfr0 = 0x20000030;
240
+ cpu->isar.id_pfr1 = 0x00000230;
241
+ cpu->isar.id_dfr0 = 0x10200000;
242
+ cpu->id_afr0 = 0x00000000;
243
+ cpu->isar.id_mmfr0 = 0x00111040;
244
+ cpu->isar.id_mmfr1 = 0x00000000;
245
+ cpu->isar.id_mmfr2 = 0x01000000;
246
+ cpu->isar.id_mmfr3 = 0x00000011;
247
+ cpu->isar.id_isar0 = 0x01103110;
248
+ cpu->isar.id_isar1 = 0x02212000;
249
+ cpu->isar.id_isar2 = 0x20232232;
250
+ cpu->isar.id_isar3 = 0x01111131;
251
+ cpu->isar.id_isar4 = 0x01310132;
252
+ cpu->isar.id_isar5 = 0x00000000;
253
+ cpu->isar.id_isar6 = 0x00000000;
254
+ cpu->clidr = 0x00000000; /* caches not implemented */
255
+ cpu->ctr = 0x8303c003;
256
+}
257
+
258
+static const TCGCPUOps arm_v7m_tcg_ops = {
259
+ .initialize = arm_translate_init,
260
+ .synchronize_from_tb = arm_cpu_synchronize_from_tb,
261
+ .debug_excp_handler = arm_debug_excp_handler,
262
+ .restore_state_to_opc = arm_restore_state_to_opc,
263
+
264
+#ifdef CONFIG_USER_ONLY
265
+ .record_sigsegv = arm_cpu_record_sigsegv,
266
+ .record_sigbus = arm_cpu_record_sigbus,
267
+#else
268
+ .tlb_fill = arm_cpu_tlb_fill,
269
+ .cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt,
270
+ .do_interrupt = arm_v7m_cpu_do_interrupt,
271
+ .do_transaction_failed = arm_cpu_do_transaction_failed,
272
+ .do_unaligned_access = arm_cpu_do_unaligned_access,
273
+ .adjust_watchpoint_address = arm_adjust_watchpoint_address,
274
+ .debug_check_watchpoint = arm_debug_check_watchpoint,
275
+ .debug_check_breakpoint = arm_debug_check_breakpoint,
276
+#endif /* !CONFIG_USER_ONLY */
277
+};
278
+
279
+static void arm_v7m_class_init(ObjectClass *oc, void *data)
280
+{
281
+ ARMCPUClass *acc = ARM_CPU_CLASS(oc);
282
+ CPUClass *cc = CPU_CLASS(oc);
283
+
284
+ acc->info = data;
285
+ cc->tcg_ops = &arm_v7m_tcg_ops;
286
+ cc->gdb_core_xml_file = "arm-m-profile.xml";
287
+}
288
+
289
+static const ARMCPUInfo arm_v7m_cpus[] = {
290
+ { .name = "cortex-m0", .initfn = cortex_m0_initfn,
291
+ .class_init = arm_v7m_class_init },
292
+ { .name = "cortex-m3", .initfn = cortex_m3_initfn,
293
+ .class_init = arm_v7m_class_init },
294
+ { .name = "cortex-m4", .initfn = cortex_m4_initfn,
295
+ .class_init = arm_v7m_class_init },
296
+ { .name = "cortex-m7", .initfn = cortex_m7_initfn,
297
+ .class_init = arm_v7m_class_init },
298
+ { .name = "cortex-m33", .initfn = cortex_m33_initfn,
299
+ .class_init = arm_v7m_class_init },
300
+ { .name = "cortex-m55", .initfn = cortex_m55_initfn,
301
+ .class_init = arm_v7m_class_init },
302
+};
303
+
304
+static void arm_v7m_cpu_register_types(void)
305
+{
306
+ size_t i;
307
+
308
+ for (i = 0; i < ARRAY_SIZE(arm_v7m_cpus); ++i) {
309
+ arm_cpu_register(&arm_v7m_cpus[i]);
310
+ }
311
+}
312
+
313
+type_init(arm_v7m_cpu_register_types)
314
diff --git a/target/arm/tcg/cpu32.c b/target/arm/tcg/cpu32.c
104
index XXXXXXX..XXXXXXX 100644
315
index XXXXXXX..XXXXXXX 100644
105
--- a/MAINTAINERS
316
--- a/target/arm/tcg/cpu32.c
106
+++ b/MAINTAINERS
317
+++ b/target/arm/tcg/cpu32.c
107
@@ -XXX,XX +XXX,XX @@ F: hw/*/stellaris*
318
@@ -XXX,XX +XXX,XX @@
108
F: include/hw/input/gamepad.h
319
#include "hw/boards.h"
109
F: docs/system/arm/stellaris.rst
320
#endif
110
321
#include "cpregs.h"
111
+STM32VLDISCOVERY
322
-#if !defined(CONFIG_USER_ONLY) && defined(CONFIG_TCG)
112
+M: Alexandre Iooss <erdnaxe@crans.org>
323
-#include "hw/intc/armv7m_nvic.h"
113
+L: qemu-arm@nongnu.org
324
-#endif
114
+S: Maintained
325
115
+F: hw/arm/stm32vldiscovery.c
326
116
+
327
/* Share AArch32 -cpu max features with AArch64. */
117
Versatile Express
328
@@ -XXX,XX +XXX,XX @@ void aa32_max_features(ARMCPU *cpu)
118
M: Peter Maydell <peter.maydell@linaro.org>
329
/* CPU models. These are not needed for the AArch64 linux-user build. */
119
L: qemu-arm@nongnu.org
330
#if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64)
120
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
331
332
-#if !defined(CONFIG_USER_ONLY)
333
-static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
334
-{
335
- CPUClass *cc = CPU_GET_CLASS(cs);
336
- ARMCPU *cpu = ARM_CPU(cs);
337
- CPUARMState *env = &cpu->env;
338
- bool ret = false;
339
-
340
- /*
341
- * ARMv7-M interrupt masking works differently than -A or -R.
342
- * There is no FIQ/IRQ distinction. Instead of I and F bits
343
- * masking FIQ and IRQ interrupts, an exception is taken only
344
- * if it is higher priority than the current execution priority
345
- * (which depends on state like BASEPRI, FAULTMASK and the
346
- * currently active exception).
347
- */
348
- if (interrupt_request & CPU_INTERRUPT_HARD
349
- && (armv7m_nvic_can_take_pending_exception(env->nvic))) {
350
- cs->exception_index = EXCP_IRQ;
351
- cc->tcg_ops->do_interrupt(cs);
352
- ret = true;
353
- }
354
- return ret;
355
-}
356
-#endif /* !CONFIG_USER_ONLY */
357
-
358
static void arm926_initfn(Object *obj)
359
{
360
ARMCPU *cpu = ARM_CPU(obj);
361
@@ -XXX,XX +XXX,XX @@ static void cortex_a15_initfn(Object *obj)
362
define_arm_cp_regs(cpu, cortexa15_cp_reginfo);
363
}
364
365
-static void cortex_m0_initfn(Object *obj)
366
-{
367
- ARMCPU *cpu = ARM_CPU(obj);
368
- set_feature(&cpu->env, ARM_FEATURE_V6);
369
- set_feature(&cpu->env, ARM_FEATURE_M);
370
-
371
- cpu->midr = 0x410cc200;
372
-
373
- /*
374
- * These ID register values are not guest visible, because
375
- * we do not implement the Main Extension. They must be set
376
- * to values corresponding to the Cortex-M0's implemented
377
- * features, because QEMU generally controls its emulation
378
- * by looking at ID register fields. We use the same values as
379
- * for the M3.
380
- */
381
- cpu->isar.id_pfr0 = 0x00000030;
382
- cpu->isar.id_pfr1 = 0x00000200;
383
- cpu->isar.id_dfr0 = 0x00100000;
384
- cpu->id_afr0 = 0x00000000;
385
- cpu->isar.id_mmfr0 = 0x00000030;
386
- cpu->isar.id_mmfr1 = 0x00000000;
387
- cpu->isar.id_mmfr2 = 0x00000000;
388
- cpu->isar.id_mmfr3 = 0x00000000;
389
- cpu->isar.id_isar0 = 0x01141110;
390
- cpu->isar.id_isar1 = 0x02111000;
391
- cpu->isar.id_isar2 = 0x21112231;
392
- cpu->isar.id_isar3 = 0x01111110;
393
- cpu->isar.id_isar4 = 0x01310102;
394
- cpu->isar.id_isar5 = 0x00000000;
395
- cpu->isar.id_isar6 = 0x00000000;
396
-}
397
-
398
-static void cortex_m3_initfn(Object *obj)
399
-{
400
- ARMCPU *cpu = ARM_CPU(obj);
401
- set_feature(&cpu->env, ARM_FEATURE_V7);
402
- set_feature(&cpu->env, ARM_FEATURE_M);
403
- set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
404
- cpu->midr = 0x410fc231;
405
- cpu->pmsav7_dregion = 8;
406
- cpu->isar.id_pfr0 = 0x00000030;
407
- cpu->isar.id_pfr1 = 0x00000200;
408
- cpu->isar.id_dfr0 = 0x00100000;
409
- cpu->id_afr0 = 0x00000000;
410
- cpu->isar.id_mmfr0 = 0x00000030;
411
- cpu->isar.id_mmfr1 = 0x00000000;
412
- cpu->isar.id_mmfr2 = 0x00000000;
413
- cpu->isar.id_mmfr3 = 0x00000000;
414
- cpu->isar.id_isar0 = 0x01141110;
415
- cpu->isar.id_isar1 = 0x02111000;
416
- cpu->isar.id_isar2 = 0x21112231;
417
- cpu->isar.id_isar3 = 0x01111110;
418
- cpu->isar.id_isar4 = 0x01310102;
419
- cpu->isar.id_isar5 = 0x00000000;
420
- cpu->isar.id_isar6 = 0x00000000;
421
-}
422
-
423
-static void cortex_m4_initfn(Object *obj)
424
-{
425
- ARMCPU *cpu = ARM_CPU(obj);
426
-
427
- set_feature(&cpu->env, ARM_FEATURE_V7);
428
- set_feature(&cpu->env, ARM_FEATURE_M);
429
- set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
430
- set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
431
- cpu->midr = 0x410fc240; /* r0p0 */
432
- cpu->pmsav7_dregion = 8;
433
- cpu->isar.mvfr0 = 0x10110021;
434
- cpu->isar.mvfr1 = 0x11000011;
435
- cpu->isar.mvfr2 = 0x00000000;
436
- cpu->isar.id_pfr0 = 0x00000030;
437
- cpu->isar.id_pfr1 = 0x00000200;
438
- cpu->isar.id_dfr0 = 0x00100000;
439
- cpu->id_afr0 = 0x00000000;
440
- cpu->isar.id_mmfr0 = 0x00000030;
441
- cpu->isar.id_mmfr1 = 0x00000000;
442
- cpu->isar.id_mmfr2 = 0x00000000;
443
- cpu->isar.id_mmfr3 = 0x00000000;
444
- cpu->isar.id_isar0 = 0x01141110;
445
- cpu->isar.id_isar1 = 0x02111000;
446
- cpu->isar.id_isar2 = 0x21112231;
447
- cpu->isar.id_isar3 = 0x01111110;
448
- cpu->isar.id_isar4 = 0x01310102;
449
- cpu->isar.id_isar5 = 0x00000000;
450
- cpu->isar.id_isar6 = 0x00000000;
451
-}
452
-
453
-static void cortex_m7_initfn(Object *obj)
454
-{
455
- ARMCPU *cpu = ARM_CPU(obj);
456
-
457
- set_feature(&cpu->env, ARM_FEATURE_V7);
458
- set_feature(&cpu->env, ARM_FEATURE_M);
459
- set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
460
- set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
461
- cpu->midr = 0x411fc272; /* r1p2 */
462
- cpu->pmsav7_dregion = 8;
463
- cpu->isar.mvfr0 = 0x10110221;
464
- cpu->isar.mvfr1 = 0x12000011;
465
- cpu->isar.mvfr2 = 0x00000040;
466
- cpu->isar.id_pfr0 = 0x00000030;
467
- cpu->isar.id_pfr1 = 0x00000200;
468
- cpu->isar.id_dfr0 = 0x00100000;
469
- cpu->id_afr0 = 0x00000000;
470
- cpu->isar.id_mmfr0 = 0x00100030;
471
- cpu->isar.id_mmfr1 = 0x00000000;
472
- cpu->isar.id_mmfr2 = 0x01000000;
473
- cpu->isar.id_mmfr3 = 0x00000000;
474
- cpu->isar.id_isar0 = 0x01101110;
475
- cpu->isar.id_isar1 = 0x02112000;
476
- cpu->isar.id_isar2 = 0x20232231;
477
- cpu->isar.id_isar3 = 0x01111131;
478
- cpu->isar.id_isar4 = 0x01310132;
479
- cpu->isar.id_isar5 = 0x00000000;
480
- cpu->isar.id_isar6 = 0x00000000;
481
-}
482
-
483
-static void cortex_m33_initfn(Object *obj)
484
-{
485
- ARMCPU *cpu = ARM_CPU(obj);
486
-
487
- set_feature(&cpu->env, ARM_FEATURE_V8);
488
- set_feature(&cpu->env, ARM_FEATURE_M);
489
- set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
490
- set_feature(&cpu->env, ARM_FEATURE_M_SECURITY);
491
- set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
492
- cpu->midr = 0x410fd213; /* r0p3 */
493
- cpu->pmsav7_dregion = 16;
494
- cpu->sau_sregion = 8;
495
- cpu->isar.mvfr0 = 0x10110021;
496
- cpu->isar.mvfr1 = 0x11000011;
497
- cpu->isar.mvfr2 = 0x00000040;
498
- cpu->isar.id_pfr0 = 0x00000030;
499
- cpu->isar.id_pfr1 = 0x00000210;
500
- cpu->isar.id_dfr0 = 0x00200000;
501
- cpu->id_afr0 = 0x00000000;
502
- cpu->isar.id_mmfr0 = 0x00101F40;
503
- cpu->isar.id_mmfr1 = 0x00000000;
504
- cpu->isar.id_mmfr2 = 0x01000000;
505
- cpu->isar.id_mmfr3 = 0x00000000;
506
- cpu->isar.id_isar0 = 0x01101110;
507
- cpu->isar.id_isar1 = 0x02212000;
508
- cpu->isar.id_isar2 = 0x20232232;
509
- cpu->isar.id_isar3 = 0x01111131;
510
- cpu->isar.id_isar4 = 0x01310132;
511
- cpu->isar.id_isar5 = 0x00000000;
512
- cpu->isar.id_isar6 = 0x00000000;
513
- cpu->clidr = 0x00000000;
514
- cpu->ctr = 0x8000c000;
515
-}
516
-
517
-static void cortex_m55_initfn(Object *obj)
518
-{
519
- ARMCPU *cpu = ARM_CPU(obj);
520
-
521
- set_feature(&cpu->env, ARM_FEATURE_V8);
522
- set_feature(&cpu->env, ARM_FEATURE_V8_1M);
523
- set_feature(&cpu->env, ARM_FEATURE_M);
524
- set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
525
- set_feature(&cpu->env, ARM_FEATURE_M_SECURITY);
526
- set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
527
- cpu->midr = 0x410fd221; /* r0p1 */
528
- cpu->revidr = 0;
529
- cpu->pmsav7_dregion = 16;
530
- cpu->sau_sregion = 8;
531
- /* These are the MVFR* values for the FPU + full MVE configuration */
532
- cpu->isar.mvfr0 = 0x10110221;
533
- cpu->isar.mvfr1 = 0x12100211;
534
- cpu->isar.mvfr2 = 0x00000040;
535
- cpu->isar.id_pfr0 = 0x20000030;
536
- cpu->isar.id_pfr1 = 0x00000230;
537
- cpu->isar.id_dfr0 = 0x10200000;
538
- cpu->id_afr0 = 0x00000000;
539
- cpu->isar.id_mmfr0 = 0x00111040;
540
- cpu->isar.id_mmfr1 = 0x00000000;
541
- cpu->isar.id_mmfr2 = 0x01000000;
542
- cpu->isar.id_mmfr3 = 0x00000011;
543
- cpu->isar.id_isar0 = 0x01103110;
544
- cpu->isar.id_isar1 = 0x02212000;
545
- cpu->isar.id_isar2 = 0x20232232;
546
- cpu->isar.id_isar3 = 0x01111131;
547
- cpu->isar.id_isar4 = 0x01310132;
548
- cpu->isar.id_isar5 = 0x00000000;
549
- cpu->isar.id_isar6 = 0x00000000;
550
- cpu->clidr = 0x00000000; /* caches not implemented */
551
- cpu->ctr = 0x8303c003;
552
-}
553
-
554
static const ARMCPRegInfo cortexr5_cp_reginfo[] = {
555
/* Dummy the TCM region regs for the moment */
556
{ .name = "ATCM", .cp = 15, .opc1 = 0, .crn = 9, .crm = 1, .opc2 = 0,
557
@@ -XXX,XX +XXX,XX @@ static void pxa270c5_initfn(Object *obj)
558
cpu->reset_sctlr = 0x00000078;
559
}
560
561
-static const TCGCPUOps arm_v7m_tcg_ops = {
562
- .initialize = arm_translate_init,
563
- .synchronize_from_tb = arm_cpu_synchronize_from_tb,
564
- .debug_excp_handler = arm_debug_excp_handler,
565
- .restore_state_to_opc = arm_restore_state_to_opc,
566
-
567
-#ifdef CONFIG_USER_ONLY
568
- .record_sigsegv = arm_cpu_record_sigsegv,
569
- .record_sigbus = arm_cpu_record_sigbus,
570
-#else
571
- .tlb_fill = arm_cpu_tlb_fill,
572
- .cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt,
573
- .do_interrupt = arm_v7m_cpu_do_interrupt,
574
- .do_transaction_failed = arm_cpu_do_transaction_failed,
575
- .do_unaligned_access = arm_cpu_do_unaligned_access,
576
- .adjust_watchpoint_address = arm_adjust_watchpoint_address,
577
- .debug_check_watchpoint = arm_debug_check_watchpoint,
578
- .debug_check_breakpoint = arm_debug_check_breakpoint,
579
-#endif /* !CONFIG_USER_ONLY */
580
-};
581
-
582
-static void arm_v7m_class_init(ObjectClass *oc, void *data)
583
-{
584
- ARMCPUClass *acc = ARM_CPU_CLASS(oc);
585
- CPUClass *cc = CPU_CLASS(oc);
586
-
587
- acc->info = data;
588
- cc->tcg_ops = &arm_v7m_tcg_ops;
589
- cc->gdb_core_xml_file = "arm-m-profile.xml";
590
-}
591
-
592
#ifndef TARGET_AARCH64
593
/*
594
* -cpu max: a CPU with as many features enabled as our emulation supports.
595
@@ -XXX,XX +XXX,XX @@ static const ARMCPUInfo arm_tcg_cpus[] = {
596
{ .name = "cortex-a8", .initfn = cortex_a8_initfn },
597
{ .name = "cortex-a9", .initfn = cortex_a9_initfn },
598
{ .name = "cortex-a15", .initfn = cortex_a15_initfn },
599
- { .name = "cortex-m0", .initfn = cortex_m0_initfn,
600
- .class_init = arm_v7m_class_init },
601
- { .name = "cortex-m3", .initfn = cortex_m3_initfn,
602
- .class_init = arm_v7m_class_init },
603
- { .name = "cortex-m4", .initfn = cortex_m4_initfn,
604
- .class_init = arm_v7m_class_init },
605
- { .name = "cortex-m7", .initfn = cortex_m7_initfn,
606
- .class_init = arm_v7m_class_init },
607
- { .name = "cortex-m33", .initfn = cortex_m33_initfn,
608
- .class_init = arm_v7m_class_init },
609
- { .name = "cortex-m55", .initfn = cortex_m55_initfn,
610
- .class_init = arm_v7m_class_init },
611
{ .name = "cortex-r5", .initfn = cortex_r5_initfn },
612
{ .name = "cortex-r5f", .initfn = cortex_r5f_initfn },
613
{ .name = "cortex-r52", .initfn = cortex_r52_initfn },
614
diff --git a/target/arm/meson.build b/target/arm/meson.build
121
index XXXXXXX..XXXXXXX 100644
615
index XXXXXXX..XXXXXXX 100644
122
--- a/hw/arm/Kconfig
616
--- a/target/arm/meson.build
123
+++ b/hw/arm/Kconfig
617
+++ b/target/arm/meson.build
124
@@ -XXX,XX +XXX,XX @@ config STELLARIS
618
@@ -XXX,XX +XXX,XX @@ arm_system_ss.add(files(
125
select STELLARIS_ENET # ethernet
619
'ptw.c',
126
select UNIMP
620
))
127
621
128
+config STM32VLDISCOVERY
622
+arm_user_ss = ss.source_set()
129
+ bool
623
+
130
+ select STM32F100_SOC
624
subdir('hvf')
131
+
625
132
config STRONGARM
626
if 'CONFIG_TCG' in config_all_accel
133
bool
627
@@ -XXX,XX +XXX,XX @@ endif
134
select PXA2XX
628
135
diff --git a/hw/arm/meson.build b/hw/arm/meson.build
629
target_arch += {'arm': arm_ss}
630
target_system_arch += {'arm': arm_system_ss}
631
+target_user_arch += {'arm': arm_user_ss}
632
diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build
136
index XXXXXXX..XXXXXXX 100644
633
index XXXXXXX..XXXXXXX 100644
137
--- a/hw/arm/meson.build
634
--- a/target/arm/tcg/meson.build
138
+++ b/hw/arm/meson.build
635
+++ b/target/arm/tcg/meson.build
139
@@ -XXX,XX +XXX,XX @@ arm_ss.add(when: 'CONFIG_Z2', if_true: files('z2.c'))
636
@@ -XXX,XX +XXX,XX @@ arm_ss.add(when: 'TARGET_AARCH64', if_true: files(
140
arm_ss.add(when: 'CONFIG_REALVIEW', if_true: files('realview.c'))
637
arm_system_ss.add(files(
141
arm_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa-ref.c'))
638
'psci.c',
142
arm_ss.add(when: 'CONFIG_STELLARIS', if_true: files('stellaris.c'))
639
))
143
+arm_ss.add(when: 'CONFIG_STM32VLDISCOVERY', if_true: files('stm32vldiscovery.c'))
640
+
144
arm_ss.add(when: 'CONFIG_COLLIE', if_true: files('collie.c'))
641
+arm_system_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('cpu-v7m.c'))
145
arm_ss.add(when: 'CONFIG_VERSATILE', if_true: files('versatilepb.c'))
642
+arm_user_ss.add(when: 'TARGET_AARCH64', if_false: files('cpu-v7m.c'))
146
arm_ss.add(when: 'CONFIG_VEXPRESS', if_true: files('vexpress.c'))
147
--
643
--
148
2.20.1
644
2.34.1
149
150
diff view generated by jsdifflib
Deleted patch
1
From: Alexandre Iooss <erdnaxe@crans.org>
2
1
3
New mini-kernel test for STM32VLDISCOVERY USART1.
4
5
Signed-off-by: Alexandre Iooss <erdnaxe@crans.org>
6
Acked-by: Thomas Huth <thuth@redhat.com>
7
Acked-by: Alistair Francis <alistair.francis@wdc.com>
8
Message-id: 20210617165647.2575955-5-erdnaxe@crans.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
tests/qtest/boot-serial-test.c | 37 ++++++++++++++++++++++++++++++++++
12
1 file changed, 37 insertions(+)
13
14
diff --git a/tests/qtest/boot-serial-test.c b/tests/qtest/boot-serial-test.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/qtest/boot-serial-test.c
17
+++ b/tests/qtest/boot-serial-test.c
18
@@ -XXX,XX +XXX,XX @@ static const uint8_t kernel_nrf51[] = {
19
0x1c, 0x25, 0x00, 0x40 /* 0x4000251c = UART TXD */
20
};
21
22
+static const uint8_t kernel_stm32vldiscovery[] = {
23
+ 0x00, 0x00, 0x00, 0x00, /* Stack top address */
24
+ 0x1d, 0x00, 0x00, 0x00, /* Reset handler address */
25
+ 0x00, 0x00, 0x00, 0x00, /* NMI */
26
+ 0x00, 0x00, 0x00, 0x00, /* Hard fault */
27
+ 0x00, 0x00, 0x00, 0x00, /* Memory management fault */
28
+ 0x00, 0x00, 0x00, 0x00, /* Bus fault */
29
+ 0x00, 0x00, 0x00, 0x00, /* Usage fault */
30
+ 0x0b, 0x4b, /* ldr r3, [pc, #44] Get RCC */
31
+ 0x44, 0xf2, 0x04, 0x02, /* movw r2, #16388 */
32
+ 0x1a, 0x60, /* str r2, [r3] */
33
+ 0x0a, 0x4b, /* ldr r3, [pc, #40] Get GPIOA */
34
+ 0x1a, 0x68, /* ldr r2, [r3] */
35
+ 0x22, 0xf0, 0xf0, 0x02, /* bic r2, r2, #240 */
36
+ 0x1a, 0x60, /* str r2, [r3] */
37
+ 0x1a, 0x68, /* ldr r2, [r3] */
38
+ 0x42, 0xf0, 0xb0, 0x02, /* orr r2, r2, #176 */
39
+ 0x1a, 0x60, /* str r2, [r3] */
40
+ 0x07, 0x4b, /* ldr r3, [pc, #26] Get BAUD */
41
+ 0x45, 0x22, /* movs r2, #69 */
42
+ 0x1a, 0x60, /* str r2, [r3] */
43
+ 0x06, 0x4b, /* ldr r3, [pc, #24] Get ENABLE */
44
+ 0x42, 0xf2, 0x08, 0x02, /* movw r2, #8200 */
45
+ 0x1a, 0x60, /* str r2, [r3] */
46
+ 0x05, 0x4b, /* ldr r3, [pc, #20] Get TXD */
47
+ 0x54, 0x22, /* movs r2, 'T' */
48
+ 0x1a, 0x60, /* str r2, [r3] */
49
+ 0xfe, 0xe7, /* b . */
50
+ 0x18, 0x10, 0x02, 0x40, /* 0x40021018 = RCC */
51
+ 0x04, 0x08, 0x01, 0x40, /* 0x40010804 = GPIOA */
52
+ 0x08, 0x38, 0x01, 0x40, /* 0x40013808 = USART1 BAUD */
53
+ 0x0c, 0x38, 0x01, 0x40, /* 0x4001380c = USART1 ENABLE */
54
+ 0x04, 0x38, 0x01, 0x40 /* 0x40013804 = USART1 TXD */
55
+};
56
+
57
typedef struct testdef {
58
const char *arch; /* Target architecture */
59
const char *machine; /* Name of the machine */
60
@@ -XXX,XX +XXX,XX @@ static testdef_t tests[] = {
61
{ "aarch64", "virt", "-cpu max", "TT", sizeof(kernel_aarch64),
62
kernel_aarch64 },
63
{ "arm", "microbit", "", "T", sizeof(kernel_nrf51), kernel_nrf51 },
64
+ { "arm", "stm32vldiscovery", "", "T",
65
+ sizeof(kernel_stm32vldiscovery), kernel_stm32vldiscovery },
66
67
{ NULL }
68
};
69
--
70
2.20.1
71
72
diff view generated by jsdifflib
Deleted patch
1
From: Ricardo Koller <ricarkol@google.com>
2
1
3
icv_eoir_write() and icv_dir_write() ignore invalid virtual IRQ numbers
4
(like LPIs). The issue is that these functions check against the number
5
of implemented IRQs (QEMU's default is num_irq=288) which can be lower
6
than the maximum virtual IRQ number (1020 - 1). The consequence is that
7
if a hypervisor creates an LR for an IRQ between 288 and 1020, then the
8
guest is unable to deactivate the resulting IRQ. Note that other
9
functions that deal with large IRQ numbers, like icv_iar_read, check
10
against 1020 and not against num_irq.
11
12
Fix the checks by using GICV3_MAXIRQ (1020) instead of the number of
13
implemented IRQs.
14
15
Signed-off-by: Ricardo Koller <ricarkol@google.com>
16
Message-id: 20210702233701.3369-1-ricarkol@google.com
17
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
18
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
19
---
20
hw/intc/arm_gicv3_cpuif.c | 4 ++--
21
1 file changed, 2 insertions(+), 2 deletions(-)
22
23
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
24
index XXXXXXX..XXXXXXX 100644
25
--- a/hw/intc/arm_gicv3_cpuif.c
26
+++ b/hw/intc/arm_gicv3_cpuif.c
27
@@ -XXX,XX +XXX,XX @@ static void icv_dir_write(CPUARMState *env, const ARMCPRegInfo *ri,
28
29
trace_gicv3_icv_dir_write(gicv3_redist_affid(cs), value);
30
31
- if (irq >= cs->gic->num_irq) {
32
+ if (irq >= GICV3_MAXIRQ) {
33
/* Also catches special interrupt numbers and LPIs */
34
return;
35
}
36
@@ -XXX,XX +XXX,XX @@ static void icv_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri,
37
trace_gicv3_icv_eoir_write(ri->crm == 8 ? 0 : 1,
38
gicv3_redist_affid(cs), value);
39
40
- if (irq >= cs->gic->num_irq) {
41
+ if (irq >= GICV3_MAXIRQ) {
42
/* Also catches special interrupt numbers and LPIs */
43
return;
44
}
45
--
46
2.20.1
47
48
diff view generated by jsdifflib
Deleted patch
1
For the virt board we have two PL061 devices -- one for NonSecure which
2
is inputs only, and one for Secure which is outputs only. For the former,
3
we don't care whether its outputs are pulled low or high when the line is
4
configured as an input, because we don't connect them. For the latter,
5
we do care, because we wire the lines up to the gpio-pwr device, which
6
assumes that level 1 means "do the action" and 1 means "do nothing".
7
For consistency in case we add more outputs in future, configure both
8
PL061s to pull GPIO lines down to 0.
9
1
10
Reported-by: Maxim Uvarov <maxim.uvarov@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
13
---
14
hw/arm/virt.c | 3 +++
15
1 file changed, 3 insertions(+)
16
17
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/arm/virt.c
20
+++ b/hw/arm/virt.c
21
@@ -XXX,XX +XXX,XX @@ static void create_gpio_devices(const VirtMachineState *vms, int gpio,
22
MachineState *ms = MACHINE(vms);
23
24
pl061_dev = qdev_new("pl061");
25
+ /* Pull lines down to 0 if not driven by the PL061 */
26
+ qdev_prop_set_uint32(pl061_dev, "pullups", 0);
27
+ qdev_prop_set_uint32(pl061_dev, "pulldowns", 0xff);
28
s = SYS_BUS_DEVICE(pl061_dev);
29
sysbus_realize_and_unref(s, &error_fatal);
30
memory_region_add_subregion(mem, base, sysbus_mmio_get_region(s, 0));
31
--
32
2.20.1
33
34
diff view generated by jsdifflib