1
Arm queue; not huge but I figured I might as well send it out since
1
Hi; this pullreq includes FEAT_LSE2 support, the new
2
I've been doing code review today and there's no queue of unprocessed
2
bpim2u board, and some other smaller patchsets.
3
pullreqs...
4
3
5
thanks
4
thanks
6
-- PMM
5
-- PMM
7
6
8
The following changes since commit b3f846c59d8405bb87c551187721fc92ff2f1b92:
7
The following changes since commit 369081c4558e7e940fa36ce59bf17b2e390f55d3:
9
8
10
Merge remote-tracking branch 'remotes/huth-gitlab/tags/pull-request-2021-01-11v2' into staging (2021-01-11 15:15:35 +0000)
9
Merge tag 'pull-tcg-20230605' of https://gitlab.com/rth7680/qemu into staging (2023-06-05 13:16:56 -0700)
11
10
12
are available in the Git repository at:
11
are available in the Git repository at:
13
12
14
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20210112
13
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20230606
15
14
16
for you to fetch changes up to 19d131395ccaf503db21dadd8257e6dc9fc1d7de:
15
for you to fetch changes up to f9ac778898cb28307e0f91421aba34d43c34b679:
17
16
18
ui/cocoa: Fix openFile: deprecation on Big Sur (2021-01-12 11:38:37 +0000)
17
target/arm: trap DCC access in user mode emulation (2023-06-06 10:19:40 +0100)
19
18
20
----------------------------------------------------------------
19
----------------------------------------------------------------
21
target-arm queue:
20
target-arm queue:
22
* arm: Support emulation of ARMv8.4-TTST extension
21
* Support gdbstub (guest debug) in HVF
23
* arm: Update cpu.h ID register field definitions
22
* xnlx-versal: Support CANFD controller
24
* arm: Fix breakage of XScale instruction emulation
23
* bpim2u: New board model: Banana Pi BPI-M2 Ultra
25
* hw/net/lan9118: Fix RX Status FIFO PEEK value
24
* Emulate FEAT_LSE2
26
* npcm7xx: Add ADC and PWM emulation
25
* allow DC CVA[D]P in user mode emulation
27
* ui/cocoa: Make "open docs" help menu entry work again when binary
26
* trap DCC access in user mode emulation
28
is run from the build tree
29
* ui/cocoa: Fix openFile: deprecation on Big Sur
30
* docs: Add qemu-storage-daemon(1) manpage to meson.build
31
* docs: Build and install all the docs in a single manual
32
27
33
----------------------------------------------------------------
28
----------------------------------------------------------------
34
Hao Wu (6):
29
Francesco Cagnin (4):
35
hw/misc: Add clock converter in NPCM7XX CLK module
30
arm: move KVM breakpoints helpers
36
hw/timer: Refactor NPCM7XX Timer to use CLK clock
31
hvf: handle access for more registers
37
hw/adc: Add an ADC module for NPCM7XX
32
hvf: add breakpoint handlers
38
hw/misc: Add a PWM module for NPCM7XX
33
hvf: add guest debugging handlers for Apple Silicon hosts
39
hw/misc: Add QTest for NPCM7XX PWM Module
40
hw/*: Use type casting for SysBusDevice in NPCM7XX
41
34
42
Leif Lindholm (6):
35
Richard Henderson (20):
43
target/arm: fix typo in cpu.h ID_AA64PFR1 field name
36
target/arm: Add commentary for CPUARMState.exclusive_high
44
target/arm: make ARMCPU.clidr 64-bit
37
target/arm: Add feature test for FEAT_LSE2
45
target/arm: make ARMCPU.ctr 64-bit
38
target/arm: Introduce finalize_memop_{atom,pair}
46
target/arm: add descriptions of CLIDR_EL1, CCSIDR_EL1, CTR_EL0 to cpu.h
39
target/arm: Use tcg_gen_qemu_ld_i128 for LDXP
47
target/arm: add aarch64 ID register fields to cpu.h
40
target/arm: Use tcg_gen_qemu_{st, ld}_i128 for do_fp_{st, ld}
48
target/arm: add aarch32 ID register fields to cpu.h
41
target/arm: Use tcg_gen_qemu_st_i128 for STZG, STZ2G
42
target/arm: Use tcg_gen_qemu_{ld, st}_i128 in gen_sve_{ld, st}r
43
target/arm: Sink gen_mte_check1 into load/store_exclusive
44
target/arm: Load/store integer pair with one tcg operation
45
target/arm: Hoist finalize_memop out of do_gpr_{ld, st}
46
target/arm: Hoist finalize_memop out of do_fp_{ld, st}
47
target/arm: Pass memop to gen_mte_check1*
48
target/arm: Pass single_memop to gen_mte_checkN
49
target/arm: Check alignment in helper_mte_check
50
target/arm: Add SCTLR.nAA to TBFLAG_A64
51
target/arm: Relax ordered/atomic alignment checks for LSE2
52
target/arm: Move mte check for store-exclusive
53
tests/tcg/aarch64: Use stz2g in mte-7.c
54
tests/tcg/multiarch: Adjust sigbus.c
55
target/arm: Enable FEAT_LSE2 for -cpu max
49
56
50
Peter Maydell (5):
57
Vikram Garhwal (4):
51
docs: Add qemu-storage-daemon(1) manpage to meson.build
58
hw/net/can: Introduce Xilinx Versal CANFD controller
52
docs: Build and install all the docs in a single manual
59
xlnx-versal: Connect Xilinx VERSAL CANFD controllers
53
target/arm: Don't decode insns in the XScale/iWMMXt space as cp insns
60
MAINTAINERS: Include canfd tests under Xilinx CAN
54
hw/net/lan9118: Fix RX Status FIFO PEEK value
61
tests/qtest: Introduce tests for Xilinx VERSAL CANFD controller
55
hw/net/lan9118: Add symbolic constants for register offsets
56
62
57
Roman Bolshakov (2):
63
Zhuojia Shen (3):
58
ui/cocoa: Update path to docs in build tree
64
target/arm: allow DC CVA[D]P in user mode emulation
59
ui/cocoa: Fix openFile: deprecation on Big Sur
65
tests/tcg/aarch64: add DC CVA[D]P tests
66
target/arm: trap DCC access in user mode emulation
60
67
61
Rémi Denis-Courmont (2):
68
qianfan Zhao (11):
62
target/arm: ARMv8.4-TTST extension
69
hw: arm: Add bananapi M2-Ultra and allwinner-r40 support
63
target/arm: enable Small Translation tables in max CPU
70
hw/arm/allwinner-r40: add Clock Control Unit
71
hw: allwinner-r40: Complete uart devices
72
hw: arm: allwinner-r40: Add i2c0 device
73
hw/misc: Rename axp209 to axp22x and add support AXP221 PMU
74
hw/arm/allwinner-r40: add SDRAM controller device
75
hw: sd: allwinner-sdhost: Add sun50i-a64 SoC support
76
hw: arm: allwinner-r40: Add emac and gmac support
77
hw: arm: allwinner-sramc: Add SRAM Controller support for R40
78
tests: avocado: boot_linux_console: Add test case for bpim2u
79
docs: system: arm: Introduce bananapi_m2u
64
80
65
docs/conf.py | 46 ++-
81
MAINTAINERS | 2 +-
66
docs/devel/conf.py | 15 -
82
docs/system/arm/bananapi_m2u.rst | 139 +++
67
docs/index.html.in | 17 -
83
docs/system/arm/emulation.rst | 1 +
68
docs/interop/conf.py | 28 --
84
docs/system/arm/xlnx-versal-virt.rst | 31 +
69
docs/meson.build | 65 ++--
85
docs/system/target-arm.rst | 1 +
70
docs/specs/conf.py | 16 -
86
include/hw/arm/allwinner-r40.h | 143 +++
71
docs/system/arm/nuvoton.rst | 4 +-
87
include/hw/arm/xlnx-versal.h | 12 +
72
docs/system/conf.py | 28 --
88
include/hw/misc/allwinner-r40-ccu.h | 65 +
73
docs/tools/conf.py | 37 --
89
include/hw/misc/allwinner-r40-dramc.h | 108 ++
74
docs/user/conf.py | 15 -
90
include/hw/misc/allwinner-sramc.h | 69 ++
75
meson.build | 1 +
91
include/hw/net/xlnx-versal-canfd.h | 87 ++
76
hw/adc/trace.h | 1 +
92
include/hw/sd/allwinner-sdhost.h | 9 +
77
include/hw/adc/npcm7xx_adc.h | 69 ++++
93
include/sysemu/hvf.h | 37 +
78
include/hw/arm/npcm7xx.h | 4 +
94
include/sysemu/hvf_int.h | 2 +
79
include/hw/misc/npcm7xx_clk.h | 146 ++++++-
95
target/arm/cpu.h | 16 +-
80
include/hw/misc/npcm7xx_pwm.h | 105 +++++
96
target/arm/hvf_arm.h | 7 +
81
include/hw/timer/npcm7xx_timer.h | 1 +
97
target/arm/internals.h | 53 +-
82
target/arm/cpu.h | 85 ++++-
98
target/arm/tcg/helper-a64.h | 3 +
83
hw/adc/npcm7xx_adc.c | 301 +++++++++++++++
99
target/arm/tcg/translate-a64.h | 4 +-
84
hw/arm/npcm7xx.c | 55 ++-
100
target/arm/tcg/translate.h | 65 +-
85
hw/arm/npcm7xx_boards.c | 2 +-
101
accel/hvf/hvf-accel-ops.c | 119 ++
86
hw/mem/npcm7xx_mc.c | 2 +-
102
accel/hvf/hvf-all.c | 23 +
87
hw/misc/npcm7xx_clk.c | 807 ++++++++++++++++++++++++++++++++++++++-
103
hw/arm/allwinner-r40.c | 526 ++++++++
88
hw/misc/npcm7xx_gcr.c | 2 +-
104
hw/arm/bananapi_m2u.c | 145 +++
89
hw/misc/npcm7xx_pwm.c | 550 ++++++++++++++++++++++++++
105
hw/arm/xlnx-versal-virt.c | 53 +
90
hw/misc/npcm7xx_rng.c | 2 +-
106
hw/arm/xlnx-versal.c | 37 +
91
hw/net/lan9118.c | 26 +-
107
hw/misc/allwinner-r40-ccu.c | 209 ++++
92
hw/nvram/npcm7xx_otp.c | 2 +-
108
hw/misc/allwinner-r40-dramc.c | 513 ++++++++
93
hw/ssi/npcm7xx_fiu.c | 2 +-
109
hw/misc/allwinner-sramc.c | 184 +++
94
hw/timer/npcm7xx_timer.c | 39 +-
110
hw/misc/axp209.c | 238 ----
95
target/arm/cpu64.c | 1 +
111
hw/misc/axp2xx.c | 283 +++++
96
target/arm/helper.c | 15 +-
112
hw/net/can/xlnx-versal-canfd.c | 2107 +++++++++++++++++++++++++++++++++
97
target/arm/translate.c | 7 +
113
hw/sd/allwinner-sdhost.c | 72 +-
98
tests/qtest/npcm7xx_adc-test.c | 377 ++++++++++++++++++
114
target/arm/cpu.c | 2 +
99
tests/qtest/npcm7xx_pwm-test.c | 490 ++++++++++++++++++++++++
115
target/arm/debug_helper.c | 5 +
100
hw/adc/meson.build | 1 +
116
target/arm/helper.c | 6 +-
101
hw/adc/trace-events | 5 +
117
target/arm/hvf/hvf.c | 750 +++++++++++-
102
hw/misc/meson.build | 1 +
118
target/arm/hyp_gdbstub.c | 253 ++++
103
hw/misc/trace-events | 6 +
119
target/arm/kvm64.c | 276 -----
104
tests/qtest/meson.build | 4 +-
120
target/arm/tcg/cpu64.c | 1 +
105
ui/cocoa.m | 7 +-
121
target/arm/tcg/helper-a64.c | 7 +
106
41 files changed, 3124 insertions(+), 263 deletions(-)
122
target/arm/tcg/hflags.c | 6 +
107
delete mode 100644 docs/devel/conf.py
123
target/arm/tcg/mte_helper.c | 18 +
108
delete mode 100644 docs/index.html.in
124
target/arm/tcg/translate-a64.c | 477 +++++---
109
delete mode 100644 docs/interop/conf.py
125
target/arm/tcg/translate-sve.c | 106 +-
110
delete mode 100644 docs/specs/conf.py
126
target/arm/tcg/translate.c | 1 +
111
delete mode 100644 docs/system/conf.py
127
target/i386/hvf/hvf.c | 33 +
112
delete mode 100644 docs/tools/conf.py
128
tests/qtest/xlnx-canfd-test.c | 423 +++++++
113
delete mode 100644 docs/user/conf.py
129
tests/tcg/aarch64/dcpodp.c | 63 +
114
create mode 100644 hw/adc/trace.h
130
tests/tcg/aarch64/dcpop.c | 63 +
115
create mode 100644 include/hw/adc/npcm7xx_adc.h
131
tests/tcg/aarch64/mte-7.c | 3 +-
116
create mode 100644 include/hw/misc/npcm7xx_pwm.h
132
tests/tcg/multiarch/sigbus.c | 13 +-
117
create mode 100644 hw/adc/npcm7xx_adc.c
133
hw/arm/Kconfig | 14 +-
118
create mode 100644 hw/misc/npcm7xx_pwm.c
134
hw/arm/meson.build | 1 +
119
create mode 100644 tests/qtest/npcm7xx_adc-test.c
135
hw/misc/Kconfig | 5 +-
120
create mode 100644 tests/qtest/npcm7xx_pwm-test.c
136
hw/misc/meson.build | 5 +-
121
create mode 100644 hw/adc/trace-events
137
hw/misc/trace-events | 26 +-
122
138
hw/net/can/meson.build | 1 +
139
hw/net/can/trace-events | 7 +
140
target/arm/meson.build | 3 +-
141
tests/avocado/boot_linux_console.py | 176 +++
142
tests/qtest/meson.build | 1 +
143
tests/tcg/aarch64/Makefile.target | 11 +
144
63 files changed, 7386 insertions(+), 733 deletions(-)
145
create mode 100644 docs/system/arm/bananapi_m2u.rst
146
create mode 100644 include/hw/arm/allwinner-r40.h
147
create mode 100644 include/hw/misc/allwinner-r40-ccu.h
148
create mode 100644 include/hw/misc/allwinner-r40-dramc.h
149
create mode 100644 include/hw/misc/allwinner-sramc.h
150
create mode 100644 include/hw/net/xlnx-versal-canfd.h
151
create mode 100644 hw/arm/allwinner-r40.c
152
create mode 100644 hw/arm/bananapi_m2u.c
153
create mode 100644 hw/misc/allwinner-r40-ccu.c
154
create mode 100644 hw/misc/allwinner-r40-dramc.c
155
create mode 100644 hw/misc/allwinner-sramc.c
156
delete mode 100644 hw/misc/axp209.c
157
create mode 100644 hw/misc/axp2xx.c
158
create mode 100644 hw/net/can/xlnx-versal-canfd.c
159
create mode 100644 target/arm/hyp_gdbstub.c
160
create mode 100644 tests/qtest/xlnx-canfd-test.c
161
create mode 100644 tests/tcg/aarch64/dcpodp.c
162
create mode 100644 tests/tcg/aarch64/dcpop.c
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
From: Francesco Cagnin <fcagnin@quarkslab.com>
2
2
3
This patch allows NPCM7XX CLK module to compute clocks that are used by
3
These helpers will be also used for HVF. Aside from reformatting a
4
other NPCM7XX modules.
4
couple of comments for 'checkpatch.pl' and updating meson to compile
5
'hyp_gdbstub.c', this is just code motion.
5
6
6
Add a new struct NPCM7xxClockConverterState which represents a
7
Signed-off-by: Francesco Cagnin <fcagnin@quarkslab.com>
7
single converter. Each clock converter in CLK module represents one
8
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
8
converter in NPCM7XX CLK Module(PLL, SEL or Divider). Each converter
9
takes one or more input clocks and converts them into one output clock.
10
They form a clock hierarchy in the CLK module and are responsible for
11
outputing clocks for various other modules in an NPCM7XX SoC.
12
13
Each converter has a function pointer called "convert" which represents
14
the unique logic for that converter.
15
16
The clock contains two initialization information: ConverterInitInfo and
17
ConverterConnectionInfo. They represent the vertices and edges in the
18
clock diagram respectively.
19
20
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
21
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
22
Signed-off-by: Hao Wu <wuhaotsh@google.com>
23
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
24
Message-id: 20210108190945.949196-2-wuhaotsh@google.com
10
Message-id: 20230601153107.81955-2-fcagnin@quarkslab.com
25
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
26
---
12
---
27
include/hw/misc/npcm7xx_clk.h | 140 +++++-
13
target/arm/internals.h | 50 +++++++
28
hw/misc/npcm7xx_clk.c | 805 +++++++++++++++++++++++++++++++++-
14
target/arm/hyp_gdbstub.c | 253 +++++++++++++++++++++++++++++++++++
29
2 files changed, 932 insertions(+), 13 deletions(-)
15
target/arm/kvm64.c | 276 ---------------------------------------
16
target/arm/meson.build | 3 +-
17
4 files changed, 305 insertions(+), 277 deletions(-)
18
create mode 100644 target/arm/hyp_gdbstub.c
30
19
31
diff --git a/include/hw/misc/npcm7xx_clk.h b/include/hw/misc/npcm7xx_clk.h
20
diff --git a/target/arm/internals.h b/target/arm/internals.h
32
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
33
--- a/include/hw/misc/npcm7xx_clk.h
22
--- a/target/arm/internals.h
34
+++ b/include/hw/misc/npcm7xx_clk.h
23
+++ b/target/arm/internals.h
24
@@ -XXX,XX +XXX,XX @@ static inline bool arm_fgt_active(CPUARMState *env, int el)
25
}
26
27
void assert_hflags_rebuild_correctly(CPUARMState *env);
28
+
29
+/*
30
+ * Although the ARM implementation of hardware assisted debugging
31
+ * allows for different breakpoints per-core, the current GDB
32
+ * interface treats them as a global pool of registers (which seems to
33
+ * be the case for x86, ppc and s390). As a result we store one copy
34
+ * of registers which is used for all active cores.
35
+ *
36
+ * Write access is serialised by virtue of the GDB protocol which
37
+ * updates things. Read access (i.e. when the values are copied to the
38
+ * vCPU) is also gated by GDB's run control.
39
+ *
40
+ * This is not unreasonable as most of the time debugging kernels you
41
+ * never know which core will eventually execute your function.
42
+ */
43
+
44
+typedef struct {
45
+ uint64_t bcr;
46
+ uint64_t bvr;
47
+} HWBreakpoint;
48
+
49
+/*
50
+ * The watchpoint registers can cover more area than the requested
51
+ * watchpoint so we need to store the additional information
52
+ * somewhere. We also need to supply a CPUWatchpoint to the GDB stub
53
+ * when the watchpoint is hit.
54
+ */
55
+typedef struct {
56
+ uint64_t wcr;
57
+ uint64_t wvr;
58
+ CPUWatchpoint details;
59
+} HWWatchpoint;
60
+
61
+/* Maximum and current break/watch point counts */
62
+extern int max_hw_bps, max_hw_wps;
63
+extern GArray *hw_breakpoints, *hw_watchpoints;
64
+
65
+#define cur_hw_wps (hw_watchpoints->len)
66
+#define cur_hw_bps (hw_breakpoints->len)
67
+#define get_hw_bp(i) (&g_array_index(hw_breakpoints, HWBreakpoint, i))
68
+#define get_hw_wp(i) (&g_array_index(hw_watchpoints, HWWatchpoint, i))
69
+
70
+bool find_hw_breakpoint(CPUState *cpu, target_ulong pc);
71
+int insert_hw_breakpoint(target_ulong pc);
72
+int delete_hw_breakpoint(target_ulong pc);
73
+
74
+bool check_watchpoint_in_range(int i, target_ulong addr);
75
+CPUWatchpoint *find_hw_watchpoint(CPUState *cpu, target_ulong addr);
76
+int insert_hw_watchpoint(target_ulong addr, target_ulong len, int type);
77
+int delete_hw_watchpoint(target_ulong addr, target_ulong len, int type);
78
#endif
79
diff --git a/target/arm/hyp_gdbstub.c b/target/arm/hyp_gdbstub.c
80
new file mode 100644
81
index XXXXXXX..XXXXXXX
82
--- /dev/null
83
+++ b/target/arm/hyp_gdbstub.c
35
@@ -XXX,XX +XXX,XX @@
84
@@ -XXX,XX +XXX,XX @@
36
#define NPCM7XX_CLK_H
85
+/*
37
86
+ * ARM implementation of KVM and HVF hooks, 64 bit specific code
38
#include "exec/memory.h"
87
+ *
39
+#include "hw/clock.h"
88
+ * Copyright Mian-M. Hamayun 2013, Virtual Open Systems
40
#include "hw/sysbus.h"
89
+ * Copyright Alex Bennée 2014, Linaro
41
90
+ *
42
/*
91
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
43
@@ -XXX,XX +XXX,XX @@
92
+ * See the COPYING file in the top-level directory.
44
93
+ *
45
#define NPCM7XX_WATCHDOG_RESET_GPIO_IN "npcm7xx-clk-watchdog-reset-gpio-in"
94
+ */
46
95
+
47
-typedef struct NPCM7xxCLKState {
96
+#include "qemu/osdep.h"
48
+/* Maximum amount of clock inputs in a SEL module. */
97
+#include "cpu.h"
49
+#define NPCM7XX_CLK_SEL_MAX_INPUT 5
98
+#include "internals.h"
50
+
99
+#include "exec/gdbstub.h"
51
+/* PLLs in CLK module. */
100
+
52
+typedef enum NPCM7xxClockPLL {
101
+/* Maximum and current break/watch point counts */
53
+ NPCM7XX_CLOCK_PLL0,
102
+int max_hw_bps, max_hw_wps;
54
+ NPCM7XX_CLOCK_PLL1,
103
+GArray *hw_breakpoints, *hw_watchpoints;
55
+ NPCM7XX_CLOCK_PLL2,
56
+ NPCM7XX_CLOCK_PLLG,
57
+ NPCM7XX_CLOCK_NR_PLLS,
58
+} NPCM7xxClockPLL;
59
+
60
+/* SEL/MUX in CLK module. */
61
+typedef enum NPCM7xxClockSEL {
62
+ NPCM7XX_CLOCK_PIXCKSEL,
63
+ NPCM7XX_CLOCK_MCCKSEL,
64
+ NPCM7XX_CLOCK_CPUCKSEL,
65
+ NPCM7XX_CLOCK_CLKOUTSEL,
66
+ NPCM7XX_CLOCK_UARTCKSEL,
67
+ NPCM7XX_CLOCK_TIMCKSEL,
68
+ NPCM7XX_CLOCK_SDCKSEL,
69
+ NPCM7XX_CLOCK_GFXMSEL,
70
+ NPCM7XX_CLOCK_SUCKSEL,
71
+ NPCM7XX_CLOCK_NR_SELS,
72
+} NPCM7xxClockSEL;
73
+
74
+/* Dividers in CLK module. */
75
+typedef enum NPCM7xxClockDivider {
76
+ NPCM7XX_CLOCK_PLL1D2, /* PLL1/2 */
77
+ NPCM7XX_CLOCK_PLL2D2, /* PLL2/2 */
78
+ NPCM7XX_CLOCK_MC_DIVIDER,
79
+ NPCM7XX_CLOCK_AXI_DIVIDER,
80
+ NPCM7XX_CLOCK_AHB_DIVIDER,
81
+ NPCM7XX_CLOCK_AHB3_DIVIDER,
82
+ NPCM7XX_CLOCK_SPI0_DIVIDER,
83
+ NPCM7XX_CLOCK_SPIX_DIVIDER,
84
+ NPCM7XX_CLOCK_APB1_DIVIDER,
85
+ NPCM7XX_CLOCK_APB2_DIVIDER,
86
+ NPCM7XX_CLOCK_APB3_DIVIDER,
87
+ NPCM7XX_CLOCK_APB4_DIVIDER,
88
+ NPCM7XX_CLOCK_APB5_DIVIDER,
89
+ NPCM7XX_CLOCK_CLKOUT_DIVIDER,
90
+ NPCM7XX_CLOCK_UART_DIVIDER,
91
+ NPCM7XX_CLOCK_TIMER_DIVIDER,
92
+ NPCM7XX_CLOCK_ADC_DIVIDER,
93
+ NPCM7XX_CLOCK_MMC_DIVIDER,
94
+ NPCM7XX_CLOCK_SDHC_DIVIDER,
95
+ NPCM7XX_CLOCK_GFXM_DIVIDER, /* divide by 3 */
96
+ NPCM7XX_CLOCK_UTMI_DIVIDER,
97
+ NPCM7XX_CLOCK_NR_DIVIDERS,
98
+} NPCM7xxClockConverter;
99
+
100
+typedef struct NPCM7xxCLKState NPCM7xxCLKState;
101
+
104
+
102
+/**
105
+/**
103
+ * struct NPCM7xxClockPLLState - A PLL module in CLK module.
106
+ * insert_hw_breakpoint()
104
+ * @name: The name of the module.
107
+ * @addr: address of breakpoint
105
+ * @clk: The CLK module that owns this module.
108
+ *
106
+ * @clock_in: The input clock of this module.
109
+ * See ARM ARM D2.9.1 for details but here we are only going to create
107
+ * @clock_out: The output clock of this module.
110
+ * simple un-linked breakpoints (i.e. we don't chain breakpoints
108
+ * @reg: The control registers for this PLL module.
111
+ * together to match address and context or vmid). The hardware is
112
+ * capable of fancier matching but that will require exposing that
113
+ * fanciness to GDB's interface
114
+ *
115
+ * DBGBCR<n>_EL1, Debug Breakpoint Control Registers
116
+ *
117
+ * 31 24 23 20 19 16 15 14 13 12 9 8 5 4 3 2 1 0
118
+ * +------+------+-------+-----+----+------+-----+------+-----+---+
119
+ * | RES0 | BT | LBN | SSC | HMC| RES0 | BAS | RES0 | PMC | E |
120
+ * +------+------+-------+-----+----+------+-----+------+-----+---+
121
+ *
122
+ * BT: Breakpoint type (0 = unlinked address match)
123
+ * LBN: Linked BP number (0 = unused)
124
+ * SSC/HMC/PMC: Security, Higher and Priv access control (Table D-12)
125
+ * BAS: Byte Address Select (RES1 for AArch64)
126
+ * E: Enable bit
127
+ *
128
+ * DBGBVR<n>_EL1, Debug Breakpoint Value Registers
129
+ *
130
+ * 63 53 52 49 48 2 1 0
131
+ * +------+-----------+----------+-----+
132
+ * | RESS | VA[52:49] | VA[48:2] | 0 0 |
133
+ * +------+-----------+----------+-----+
134
+ *
135
+ * Depending on the addressing mode bits the top bits of the register
136
+ * are a sign extension of the highest applicable VA bit. Some
137
+ * versions of GDB don't do it correctly so we ensure they are correct
138
+ * here so future PC comparisons will work properly.
109
+ */
139
+ */
110
+typedef struct NPCM7xxClockPLLState {
140
+
111
+ DeviceState parent;
141
+int insert_hw_breakpoint(target_ulong addr)
112
+
142
+{
113
+ const char *name;
143
+ HWBreakpoint brk = {
114
+ NPCM7xxCLKState *clk;
144
+ .bcr = 0x1, /* BCR E=1, enable */
115
+ Clock *clock_in;
145
+ .bvr = sextract64(addr, 0, 53)
116
+ Clock *clock_out;
146
+ };
117
+
147
+
118
+ int reg;
148
+ if (cur_hw_bps >= max_hw_bps) {
119
+} NPCM7xxClockPLLState;
149
+ return -ENOBUFS;
150
+ }
151
+
152
+ brk.bcr = deposit32(brk.bcr, 1, 2, 0x3); /* PMC = 11 */
153
+ brk.bcr = deposit32(brk.bcr, 5, 4, 0xf); /* BAS = RES1 */
154
+
155
+ g_array_append_val(hw_breakpoints, brk);
156
+
157
+ return 0;
158
+}
120
+
159
+
121
+/**
160
+/**
122
+ * struct NPCM7xxClockSELState - A SEL module in CLK module.
161
+ * delete_hw_breakpoint()
123
+ * @name: The name of the module.
162
+ * @pc: address of breakpoint
124
+ * @clk: The CLK module that owns this module.
163
+ *
125
+ * @input_size: The size of inputs of this module.
164
+ * Delete a breakpoint and shuffle any above down
126
+ * @clock_in: The input clocks of this module.
127
+ * @clock_out: The output clocks of this module.
128
+ * @offset: The offset of this module in the control register.
129
+ * @len: The length of this module in the control register.
130
+ */
165
+ */
131
+typedef struct NPCM7xxClockSELState {
166
+
132
+ DeviceState parent;
167
+int delete_hw_breakpoint(target_ulong pc)
133
+
168
+{
134
+ const char *name;
169
+ int i;
135
+ NPCM7xxCLKState *clk;
170
+ for (i = 0; i < hw_breakpoints->len; i++) {
136
+ uint8_t input_size;
171
+ HWBreakpoint *brk = get_hw_bp(i);
137
+ Clock *clock_in[NPCM7XX_CLK_SEL_MAX_INPUT];
172
+ if (brk->bvr == pc) {
138
+ Clock *clock_out;
173
+ g_array_remove_index(hw_breakpoints, i);
139
+
174
+ return 0;
140
+ int offset;
175
+ }
141
+ int len;
176
+ }
142
+} NPCM7xxClockSELState;
177
+ return -ENOENT;
178
+}
143
+
179
+
144
+/**
180
+/**
145
+ * struct NPCM7xxClockDividerState - A Divider module in CLK module.
181
+ * insert_hw_watchpoint()
146
+ * @name: The name of the module.
182
+ * @addr: address of watch point
147
+ * @clk: The CLK module that owns this module.
183
+ * @len: size of area
148
+ * @clock_in: The input clock of this module.
184
+ * @type: type of watch point
149
+ * @clock_out: The output clock of this module.
185
+ *
150
+ * @divide: The function the divider uses to divide the input.
186
+ * See ARM ARM D2.10. As with the breakpoints we can do some advanced
151
+ * @reg: The index of the control register that contains the divisor.
187
+ * stuff if we want to. The watch points can be linked with the break
152
+ * @offset: The offset of the divisor in the control register.
188
+ * points above to make them context aware. However for simplicity
153
+ * @len: The length of the divisor in the control register.
189
+ * currently we only deal with simple read/write watch points.
154
+ * @divisor: The divisor for a constant divisor
190
+ *
191
+ * D7.3.11 DBGWCR<n>_EL1, Debug Watchpoint Control Registers
192
+ *
193
+ * 31 29 28 24 23 21 20 19 16 15 14 13 12 5 4 3 2 1 0
194
+ * +------+-------+------+----+-----+-----+-----+-----+-----+-----+---+
195
+ * | RES0 | MASK | RES0 | WT | LBN | SSC | HMC | BAS | LSC | PAC | E |
196
+ * +------+-------+------+----+-----+-----+-----+-----+-----+-----+---+
197
+ *
198
+ * MASK: num bits addr mask (0=none,01/10=res,11=3 bits (8 bytes))
199
+ * WT: 0 - unlinked, 1 - linked (not currently used)
200
+ * LBN: Linked BP number (not currently used)
201
+ * SSC/HMC/PAC: Security, Higher and Priv access control (Table D2-11)
202
+ * BAS: Byte Address Select
203
+ * LSC: Load/Store control (01: load, 10: store, 11: both)
204
+ * E: Enable
205
+ *
206
+ * The bottom 2 bits of the value register are masked. Therefore to
207
+ * break on any sizes smaller than an unaligned word you need to set
208
+ * MASK=0, BAS=bit per byte in question. For larger regions (^2) you
209
+ * need to ensure you mask the address as required and set BAS=0xff
155
+ */
210
+ */
156
+typedef struct NPCM7xxClockDividerState {
211
+
157
+ DeviceState parent;
212
+int insert_hw_watchpoint(target_ulong addr, target_ulong len, int type)
158
+
213
+{
159
+ const char *name;
214
+ HWWatchpoint wp = {
160
+ NPCM7xxCLKState *clk;
215
+ .wcr = R_DBGWCR_E_MASK, /* E=1, enable */
161
+ Clock *clock_in;
216
+ .wvr = addr & (~0x7ULL),
162
+ Clock *clock_out;
217
+ .details = { .vaddr = addr, .len = len }
163
+
164
+ uint32_t (*divide)(struct NPCM7xxClockDividerState *s);
165
+ union {
166
+ struct {
167
+ int reg;
168
+ int offset;
169
+ int len;
170
+ };
171
+ int divisor;
172
+ };
218
+ };
173
+} NPCM7xxClockDividerState;
219
+
174
+
220
+ if (cur_hw_wps >= max_hw_wps) {
175
+struct NPCM7xxCLKState {
221
+ return -ENOBUFS;
176
SysBusDevice parent;
222
+ }
177
223
+
178
MemoryRegion iomem;
224
+ /*
179
225
+ * HMC=0 SSC=0 PAC=3 will hit EL0 or EL1, any security state,
180
+ /* Clock converters */
226
+ * valid whether EL3 is implemented or not
181
+ NPCM7xxClockPLLState plls[NPCM7XX_CLOCK_NR_PLLS];
227
+ */
182
+ NPCM7xxClockSELState sels[NPCM7XX_CLOCK_NR_SELS];
228
+ wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, PAC, 3);
183
+ NPCM7xxClockDividerState dividers[NPCM7XX_CLOCK_NR_DIVIDERS];
229
+
184
+
230
+ switch (type) {
185
uint32_t regs[NPCM7XX_CLK_NR_REGS];
231
+ case GDB_WATCHPOINT_READ:
186
232
+ wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, LSC, 1);
187
/* Time reference for SECCNT and CNTR25M, initialized by power on reset */
233
+ wp.details.flags = BP_MEM_READ;
188
int64_t ref_ns;
234
+ break;
189
-} NPCM7xxCLKState;
235
+ case GDB_WATCHPOINT_WRITE:
190
+
236
+ wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, LSC, 2);
191
+ /* The incoming reference clock. */
237
+ wp.details.flags = BP_MEM_WRITE;
192
+ Clock *clkref;
238
+ break;
193
+};
239
+ case GDB_WATCHPOINT_ACCESS:
194
240
+ wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, LSC, 3);
195
#define TYPE_NPCM7XX_CLK "npcm7xx-clk"
241
+ wp.details.flags = BP_MEM_ACCESS;
196
#define NPCM7XX_CLK(obj) OBJECT_CHECK(NPCM7xxCLKState, (obj), TYPE_NPCM7XX_CLK)
242
+ break;
197
diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
198
index XXXXXXX..XXXXXXX 100644
199
--- a/hw/misc/npcm7xx_clk.c
200
+++ b/hw/misc/npcm7xx_clk.c
201
@@ -XXX,XX +XXX,XX @@
202
203
#include "hw/misc/npcm7xx_clk.h"
204
#include "hw/timer/npcm7xx_timer.h"
205
+#include "hw/qdev-clock.h"
206
#include "migration/vmstate.h"
207
#include "qemu/error-report.h"
208
#include "qemu/log.h"
209
@@ -XXX,XX +XXX,XX @@
210
#include "trace.h"
211
#include "sysemu/watchdog.h"
212
213
+/*
214
+ * The reference clock hz, and the SECCNT and CNTR25M registers in this module,
215
+ * is always 25 MHz.
216
+ */
217
+#define NPCM7XX_CLOCK_REF_HZ (25000000)
218
+
219
+/* Register Field Definitions */
220
+#define NPCM7XX_CLK_WDRCR_CA9C BIT(0) /* Cortex A9 Cores */
221
+
222
#define PLLCON_LOKI BIT(31)
223
#define PLLCON_LOKS BIT(30)
224
#define PLLCON_PWDEN BIT(12)
225
+#define PLLCON_FBDV(con) extract32((con), 16, 12)
226
+#define PLLCON_OTDV2(con) extract32((con), 13, 3)
227
+#define PLLCON_OTDV1(con) extract32((con), 8, 3)
228
+#define PLLCON_INDV(con) extract32((con), 0, 6)
229
230
enum NPCM7xxCLKRegisters {
231
NPCM7XX_CLK_CLKEN1,
232
@@ -XXX,XX +XXX,XX @@ static const uint32_t cold_reset_values[NPCM7XX_CLK_NR_REGS] = {
233
[NPCM7XX_CLK_AHBCKFI] = 0x000000c8,
234
};
235
236
-/* Register Field Definitions */
237
-#define NPCM7XX_CLK_WDRCR_CA9C BIT(0) /* Cortex A9 Cores */
238
-
239
/* The number of watchdogs that can trigger a reset. */
240
#define NPCM7XX_NR_WATCHDOGS (3)
241
242
+/* Clock converter functions */
243
+
244
+#define TYPE_NPCM7XX_CLOCK_PLL "npcm7xx-clock-pll"
245
+#define NPCM7XX_CLOCK_PLL(obj) OBJECT_CHECK(NPCM7xxClockPLLState, \
246
+ (obj), TYPE_NPCM7XX_CLOCK_PLL)
247
+#define TYPE_NPCM7XX_CLOCK_SEL "npcm7xx-clock-sel"
248
+#define NPCM7XX_CLOCK_SEL(obj) OBJECT_CHECK(NPCM7xxClockSELState, \
249
+ (obj), TYPE_NPCM7XX_CLOCK_SEL)
250
+#define TYPE_NPCM7XX_CLOCK_DIVIDER "npcm7xx-clock-divider"
251
+#define NPCM7XX_CLOCK_DIVIDER(obj) OBJECT_CHECK(NPCM7xxClockDividerState, \
252
+ (obj), TYPE_NPCM7XX_CLOCK_DIVIDER)
253
+
254
+static void npcm7xx_clk_update_pll(void *opaque)
255
+{
256
+ NPCM7xxClockPLLState *s = opaque;
257
+ uint32_t con = s->clk->regs[s->reg];
258
+ uint64_t freq;
259
+
260
+ /* The PLL is grounded if it is not locked yet. */
261
+ if (con & PLLCON_LOKI) {
262
+ freq = clock_get_hz(s->clock_in);
263
+ freq *= PLLCON_FBDV(con);
264
+ freq /= PLLCON_INDV(con) * PLLCON_OTDV1(con) * PLLCON_OTDV2(con);
265
+ } else {
266
+ freq = 0;
267
+ }
268
+
269
+ clock_update_hz(s->clock_out, freq);
270
+}
271
+
272
+static void npcm7xx_clk_update_sel(void *opaque)
273
+{
274
+ NPCM7xxClockSELState *s = opaque;
275
+ uint32_t index = extract32(s->clk->regs[NPCM7XX_CLK_CLKSEL], s->offset,
276
+ s->len);
277
+
278
+ if (index >= s->input_size) {
279
+ qemu_log_mask(LOG_GUEST_ERROR,
280
+ "%s: SEL index: %u out of range\n",
281
+ __func__, index);
282
+ index = 0;
283
+ }
284
+ clock_update_hz(s->clock_out, clock_get_hz(s->clock_in[index]));
285
+}
286
+
287
+static void npcm7xx_clk_update_divider(void *opaque)
288
+{
289
+ NPCM7xxClockDividerState *s = opaque;
290
+ uint32_t freq;
291
+
292
+ freq = s->divide(s);
293
+ clock_update_hz(s->clock_out, freq);
294
+}
295
+
296
+static uint32_t divide_by_constant(NPCM7xxClockDividerState *s)
297
+{
298
+ return clock_get_hz(s->clock_in) / s->divisor;
299
+}
300
+
301
+static uint32_t divide_by_reg_divisor(NPCM7xxClockDividerState *s)
302
+{
303
+ return clock_get_hz(s->clock_in) /
304
+ (extract32(s->clk->regs[s->reg], s->offset, s->len) + 1);
305
+}
306
+
307
+static uint32_t divide_by_reg_divisor_times_2(NPCM7xxClockDividerState *s)
308
+{
309
+ return divide_by_reg_divisor(s) / 2;
310
+}
311
+
312
+static uint32_t shift_by_reg_divisor(NPCM7xxClockDividerState *s)
313
+{
314
+ return clock_get_hz(s->clock_in) >>
315
+ extract32(s->clk->regs[s->reg], s->offset, s->len);
316
+}
317
+
318
+static NPCM7xxClockPLL find_pll_by_reg(enum NPCM7xxCLKRegisters reg)
319
+{
320
+ switch (reg) {
321
+ case NPCM7XX_CLK_PLLCON0:
322
+ return NPCM7XX_CLOCK_PLL0;
323
+ case NPCM7XX_CLK_PLLCON1:
324
+ return NPCM7XX_CLOCK_PLL1;
325
+ case NPCM7XX_CLK_PLLCON2:
326
+ return NPCM7XX_CLOCK_PLL2;
327
+ case NPCM7XX_CLK_PLLCONG:
328
+ return NPCM7XX_CLOCK_PLLG;
329
+ default:
243
+ default:
330
+ g_assert_not_reached();
244
+ g_assert_not_reached();
331
+ }
245
+ break;
246
+ }
247
+ if (len <= 8) {
248
+ /* we align the address and set the bits in BAS */
249
+ int off = addr & 0x7;
250
+ int bas = (1 << len) - 1;
251
+
252
+ wp.wcr = deposit32(wp.wcr, 5 + off, 8 - off, bas);
253
+ } else {
254
+ /* For ranges above 8 bytes we need to be a power of 2 */
255
+ if (is_power_of_2(len)) {
256
+ int bits = ctz64(len);
257
+
258
+ wp.wvr &= ~((1 << bits) - 1);
259
+ wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, MASK, bits);
260
+ wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, BAS, 0xff);
261
+ } else {
262
+ return -ENOBUFS;
263
+ }
264
+ }
265
+
266
+ g_array_append_val(hw_watchpoints, wp);
267
+ return 0;
332
+}
268
+}
333
+
269
+
334
+static void npcm7xx_clk_update_all_plls(NPCM7xxCLKState *clk)
270
+bool check_watchpoint_in_range(int i, target_ulong addr)
271
+{
272
+ HWWatchpoint *wp = get_hw_wp(i);
273
+ uint64_t addr_top, addr_bottom = wp->wvr;
274
+ int bas = extract32(wp->wcr, 5, 8);
275
+ int mask = extract32(wp->wcr, 24, 4);
276
+
277
+ if (mask) {
278
+ addr_top = addr_bottom + (1 << mask);
279
+ } else {
280
+ /*
281
+ * BAS must be contiguous but can offset against the base
282
+ * address in DBGWVR
283
+ */
284
+ addr_bottom = addr_bottom + ctz32(bas);
285
+ addr_top = addr_bottom + clo32(bas);
286
+ }
287
+
288
+ if (addr >= addr_bottom && addr <= addr_top) {
289
+ return true;
290
+ }
291
+
292
+ return false;
293
+}
294
+
295
+/**
296
+ * delete_hw_watchpoint()
297
+ * @addr: address of breakpoint
298
+ *
299
+ * Delete a breakpoint and shuffle any above down
300
+ */
301
+
302
+int delete_hw_watchpoint(target_ulong addr, target_ulong len, int type)
335
+{
303
+{
336
+ int i;
304
+ int i;
337
+
305
+ for (i = 0; i < cur_hw_wps; i++) {
338
+ for (i = 0; i < NPCM7XX_CLOCK_NR_PLLS; ++i) {
306
+ if (check_watchpoint_in_range(i, addr)) {
339
+ npcm7xx_clk_update_pll(&clk->plls[i]);
307
+ g_array_remove_index(hw_watchpoints, i);
340
+ }
308
+ return 0;
309
+ }
310
+ }
311
+ return -ENOENT;
341
+}
312
+}
342
+
313
+
343
+static void npcm7xx_clk_update_all_sels(NPCM7xxCLKState *clk)
314
+bool find_hw_breakpoint(CPUState *cpu, target_ulong pc)
344
+{
315
+{
345
+ int i;
316
+ int i;
346
+
317
+
347
+ for (i = 0; i < NPCM7XX_CLOCK_NR_SELS; ++i) {
318
+ for (i = 0; i < cur_hw_bps; i++) {
348
+ npcm7xx_clk_update_sel(&clk->sels[i]);
319
+ HWBreakpoint *bp = get_hw_bp(i);
349
+ }
320
+ if (bp->bvr == pc) {
321
+ return true;
322
+ }
323
+ }
324
+ return false;
350
+}
325
+}
351
+
326
+
352
+static void npcm7xx_clk_update_all_dividers(NPCM7xxCLKState *clk)
327
+CPUWatchpoint *find_hw_watchpoint(CPUState *cpu, target_ulong addr)
353
+{
328
+{
354
+ int i;
329
+ int i;
355
+
330
+
356
+ for (i = 0; i < NPCM7XX_CLOCK_NR_DIVIDERS; ++i) {
331
+ for (i = 0; i < cur_hw_wps; i++) {
357
+ npcm7xx_clk_update_divider(&clk->dividers[i]);
332
+ if (check_watchpoint_in_range(i, addr)) {
358
+ }
333
+ return &get_hw_wp(i)->details;
334
+ }
335
+ }
336
+ return NULL;
359
+}
337
+}
360
+
338
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
361
+static void npcm7xx_clk_update_all_clocks(NPCM7xxCLKState *clk)
339
index XXXXXXX..XXXXXXX 100644
362
+{
340
--- a/target/arm/kvm64.c
363
+ clock_update_hz(clk->clkref, NPCM7XX_CLOCK_REF_HZ);
341
+++ b/target/arm/kvm64.c
364
+ npcm7xx_clk_update_all_plls(clk);
342
@@ -XXX,XX +XXX,XX @@
365
+ npcm7xx_clk_update_all_sels(clk);
343
366
+ npcm7xx_clk_update_all_dividers(clk);
344
static bool have_guest_debug;
367
+}
345
368
+
346
-/*
369
+/* Types of clock sources. */
347
- * Although the ARM implementation of hardware assisted debugging
370
+typedef enum ClockSrcType {
348
- * allows for different breakpoints per-core, the current GDB
371
+ CLKSRC_REF,
349
- * interface treats them as a global pool of registers (which seems to
372
+ CLKSRC_PLL,
350
- * be the case for x86, ppc and s390). As a result we store one copy
373
+ CLKSRC_SEL,
351
- * of registers which is used for all active cores.
374
+ CLKSRC_DIV,
352
- *
375
+} ClockSrcType;
353
- * Write access is serialised by virtue of the GDB protocol which
376
+
354
- * updates things. Read access (i.e. when the values are copied to the
377
+typedef struct PLLInitInfo {
355
- * vCPU) is also gated by GDB's run control.
378
+ const char *name;
356
- *
379
+ ClockSrcType src_type;
357
- * This is not unreasonable as most of the time debugging kernels you
380
+ int src_index;
358
- * never know which core will eventually execute your function.
381
+ int reg;
359
- */
382
+ const char *public_name;
360
-
383
+} PLLInitInfo;
361
-typedef struct {
384
+
362
- uint64_t bcr;
385
+typedef struct SELInitInfo {
363
- uint64_t bvr;
386
+ const char *name;
364
-} HWBreakpoint;
387
+ uint8_t input_size;
365
-
388
+ ClockSrcType src_type[NPCM7XX_CLK_SEL_MAX_INPUT];
366
-/* The watchpoint registers can cover more area than the requested
389
+ int src_index[NPCM7XX_CLK_SEL_MAX_INPUT];
367
- * watchpoint so we need to store the additional information
390
+ int offset;
368
- * somewhere. We also need to supply a CPUWatchpoint to the GDB stub
391
+ int len;
369
- * when the watchpoint is hit.
392
+ const char *public_name;
370
- */
393
+} SELInitInfo;
371
-typedef struct {
394
+
372
- uint64_t wcr;
395
+typedef struct DividerInitInfo {
373
- uint64_t wvr;
396
+ const char *name;
374
- CPUWatchpoint details;
397
+ ClockSrcType src_type;
375
-} HWWatchpoint;
398
+ int src_index;
376
-
399
+ uint32_t (*divide)(NPCM7xxClockDividerState *s);
377
-/* Maximum and current break/watch point counts */
400
+ int reg; /* not used when type == CONSTANT */
378
-int max_hw_bps, max_hw_wps;
401
+ int offset; /* not used when type == CONSTANT */
379
-GArray *hw_breakpoints, *hw_watchpoints;
402
+ int len; /* not used when type == CONSTANT */
380
-
403
+ int divisor; /* used only when type == CONSTANT */
381
-#define cur_hw_wps (hw_watchpoints->len)
404
+ const char *public_name;
382
-#define cur_hw_bps (hw_breakpoints->len)
405
+} DividerInitInfo;
383
-#define get_hw_bp(i) (&g_array_index(hw_breakpoints, HWBreakpoint, i))
406
+
384
-#define get_hw_wp(i) (&g_array_index(hw_watchpoints, HWWatchpoint, i))
407
+static const PLLInitInfo pll_init_info_list[] = {
385
-
408
+ [NPCM7XX_CLOCK_PLL0] = {
386
void kvm_arm_init_debug(KVMState *s)
409
+ .name = "pll0",
410
+ .src_type = CLKSRC_REF,
411
+ .reg = NPCM7XX_CLK_PLLCON0,
412
+ },
413
+ [NPCM7XX_CLOCK_PLL1] = {
414
+ .name = "pll1",
415
+ .src_type = CLKSRC_REF,
416
+ .reg = NPCM7XX_CLK_PLLCON1,
417
+ },
418
+ [NPCM7XX_CLOCK_PLL2] = {
419
+ .name = "pll2",
420
+ .src_type = CLKSRC_REF,
421
+ .reg = NPCM7XX_CLK_PLLCON2,
422
+ },
423
+ [NPCM7XX_CLOCK_PLLG] = {
424
+ .name = "pllg",
425
+ .src_type = CLKSRC_REF,
426
+ .reg = NPCM7XX_CLK_PLLCONG,
427
+ },
428
+};
429
+
430
+static const SELInitInfo sel_init_info_list[] = {
431
+ [NPCM7XX_CLOCK_PIXCKSEL] = {
432
+ .name = "pixcksel",
433
+ .input_size = 2,
434
+ .src_type = {CLKSRC_PLL, CLKSRC_REF},
435
+ .src_index = {NPCM7XX_CLOCK_PLLG, 0},
436
+ .offset = 5,
437
+ .len = 1,
438
+ .public_name = "pixel-clock",
439
+ },
440
+ [NPCM7XX_CLOCK_MCCKSEL] = {
441
+ .name = "mccksel",
442
+ .input_size = 4,
443
+ .src_type = {CLKSRC_DIV, CLKSRC_REF, CLKSRC_REF,
444
+ /*MCBPCK, shouldn't be used in normal operation*/
445
+ CLKSRC_REF},
446
+ .src_index = {NPCM7XX_CLOCK_PLL1D2, 0, 0, 0},
447
+ .offset = 12,
448
+ .len = 2,
449
+ .public_name = "mc-phy-clock",
450
+ },
451
+ [NPCM7XX_CLOCK_CPUCKSEL] = {
452
+ .name = "cpucksel",
453
+ .input_size = 4,
454
+ .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF,
455
+ /*SYSBPCK, shouldn't be used in normal operation*/
456
+ CLKSRC_REF},
457
+ .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0, 0},
458
+ .offset = 0,
459
+ .len = 2,
460
+ .public_name = "system-clock",
461
+ },
462
+ [NPCM7XX_CLOCK_CLKOUTSEL] = {
463
+ .name = "clkoutsel",
464
+ .input_size = 5,
465
+ .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF,
466
+ CLKSRC_PLL, CLKSRC_DIV},
467
+ .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0,
468
+ NPCM7XX_CLOCK_PLLG, NPCM7XX_CLOCK_PLL2D2},
469
+ .offset = 18,
470
+ .len = 3,
471
+ .public_name = "tock",
472
+ },
473
+ [NPCM7XX_CLOCK_UARTCKSEL] = {
474
+ .name = "uartcksel",
475
+ .input_size = 4,
476
+ .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF, CLKSRC_DIV},
477
+ .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0,
478
+ NPCM7XX_CLOCK_PLL2D2},
479
+ .offset = 8,
480
+ .len = 2,
481
+ },
482
+ [NPCM7XX_CLOCK_TIMCKSEL] = {
483
+ .name = "timcksel",
484
+ .input_size = 4,
485
+ .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF, CLKSRC_DIV},
486
+ .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0,
487
+ NPCM7XX_CLOCK_PLL2D2},
488
+ .offset = 14,
489
+ .len = 2,
490
+ },
491
+ [NPCM7XX_CLOCK_SDCKSEL] = {
492
+ .name = "sdcksel",
493
+ .input_size = 4,
494
+ .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF, CLKSRC_DIV},
495
+ .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0,
496
+ NPCM7XX_CLOCK_PLL2D2},
497
+ .offset = 6,
498
+ .len = 2,
499
+ },
500
+ [NPCM7XX_CLOCK_GFXMSEL] = {
501
+ .name = "gfxmksel",
502
+ .input_size = 2,
503
+ .src_type = {CLKSRC_REF, CLKSRC_PLL},
504
+ .src_index = {0, NPCM7XX_CLOCK_PLL2},
505
+ .offset = 21,
506
+ .len = 1,
507
+ },
508
+ [NPCM7XX_CLOCK_SUCKSEL] = {
509
+ .name = "sucksel",
510
+ .input_size = 4,
511
+ .src_type = {CLKSRC_PLL, CLKSRC_DIV, CLKSRC_REF, CLKSRC_DIV},
512
+ .src_index = {NPCM7XX_CLOCK_PLL0, NPCM7XX_CLOCK_PLL1D2, 0,
513
+ NPCM7XX_CLOCK_PLL2D2},
514
+ .offset = 10,
515
+ .len = 2,
516
+ },
517
+};
518
+
519
+static const DividerInitInfo divider_init_info_list[] = {
520
+ [NPCM7XX_CLOCK_PLL1D2] = {
521
+ .name = "pll1d2",
522
+ .src_type = CLKSRC_PLL,
523
+ .src_index = NPCM7XX_CLOCK_PLL1,
524
+ .divide = divide_by_constant,
525
+ .divisor = 2,
526
+ },
527
+ [NPCM7XX_CLOCK_PLL2D2] = {
528
+ .name = "pll2d2",
529
+ .src_type = CLKSRC_PLL,
530
+ .src_index = NPCM7XX_CLOCK_PLL2,
531
+ .divide = divide_by_constant,
532
+ .divisor = 2,
533
+ },
534
+ [NPCM7XX_CLOCK_MC_DIVIDER] = {
535
+ .name = "mc-divider",
536
+ .src_type = CLKSRC_SEL,
537
+ .src_index = NPCM7XX_CLOCK_MCCKSEL,
538
+ .divide = divide_by_constant,
539
+ .divisor = 2,
540
+ .public_name = "mc-clock"
541
+ },
542
+ [NPCM7XX_CLOCK_AXI_DIVIDER] = {
543
+ .name = "axi-divider",
544
+ .src_type = CLKSRC_SEL,
545
+ .src_index = NPCM7XX_CLOCK_CPUCKSEL,
546
+ .divide = shift_by_reg_divisor,
547
+ .reg = NPCM7XX_CLK_CLKDIV1,
548
+ .offset = 0,
549
+ .len = 1,
550
+ .public_name = "clk2"
551
+ },
552
+ [NPCM7XX_CLOCK_AHB_DIVIDER] = {
553
+ .name = "ahb-divider",
554
+ .src_type = CLKSRC_DIV,
555
+ .src_index = NPCM7XX_CLOCK_AXI_DIVIDER,
556
+ .divide = divide_by_reg_divisor,
557
+ .reg = NPCM7XX_CLK_CLKDIV1,
558
+ .offset = 26,
559
+ .len = 2,
560
+ .public_name = "clk4"
561
+ },
562
+ [NPCM7XX_CLOCK_AHB3_DIVIDER] = {
563
+ .name = "ahb3-divider",
564
+ .src_type = CLKSRC_DIV,
565
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
566
+ .divide = divide_by_reg_divisor,
567
+ .reg = NPCM7XX_CLK_CLKDIV1,
568
+ .offset = 6,
569
+ .len = 5,
570
+ .public_name = "ahb3-spi3-clock"
571
+ },
572
+ [NPCM7XX_CLOCK_SPI0_DIVIDER] = {
573
+ .name = "spi0-divider",
574
+ .src_type = CLKSRC_DIV,
575
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
576
+ .divide = divide_by_reg_divisor,
577
+ .reg = NPCM7XX_CLK_CLKDIV3,
578
+ .offset = 6,
579
+ .len = 5,
580
+ .public_name = "spi0-clock",
581
+ },
582
+ [NPCM7XX_CLOCK_SPIX_DIVIDER] = {
583
+ .name = "spix-divider",
584
+ .src_type = CLKSRC_DIV,
585
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
586
+ .divide = divide_by_reg_divisor,
587
+ .reg = NPCM7XX_CLK_CLKDIV3,
588
+ .offset = 1,
589
+ .len = 5,
590
+ .public_name = "spix-clock",
591
+ },
592
+ [NPCM7XX_CLOCK_APB1_DIVIDER] = {
593
+ .name = "apb1-divider",
594
+ .src_type = CLKSRC_DIV,
595
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
596
+ .divide = shift_by_reg_divisor,
597
+ .reg = NPCM7XX_CLK_CLKDIV2,
598
+ .offset = 24,
599
+ .len = 2,
600
+ .public_name = "apb1-clock",
601
+ },
602
+ [NPCM7XX_CLOCK_APB2_DIVIDER] = {
603
+ .name = "apb2-divider",
604
+ .src_type = CLKSRC_DIV,
605
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
606
+ .divide = shift_by_reg_divisor,
607
+ .reg = NPCM7XX_CLK_CLKDIV2,
608
+ .offset = 26,
609
+ .len = 2,
610
+ .public_name = "apb2-clock",
611
+ },
612
+ [NPCM7XX_CLOCK_APB3_DIVIDER] = {
613
+ .name = "apb3-divider",
614
+ .src_type = CLKSRC_DIV,
615
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
616
+ .divide = shift_by_reg_divisor,
617
+ .reg = NPCM7XX_CLK_CLKDIV2,
618
+ .offset = 28,
619
+ .len = 2,
620
+ .public_name = "apb3-clock",
621
+ },
622
+ [NPCM7XX_CLOCK_APB4_DIVIDER] = {
623
+ .name = "apb4-divider",
624
+ .src_type = CLKSRC_DIV,
625
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
626
+ .divide = shift_by_reg_divisor,
627
+ .reg = NPCM7XX_CLK_CLKDIV2,
628
+ .offset = 30,
629
+ .len = 2,
630
+ .public_name = "apb4-clock",
631
+ },
632
+ [NPCM7XX_CLOCK_APB5_DIVIDER] = {
633
+ .name = "apb5-divider",
634
+ .src_type = CLKSRC_DIV,
635
+ .src_index = NPCM7XX_CLOCK_AHB_DIVIDER,
636
+ .divide = shift_by_reg_divisor,
637
+ .reg = NPCM7XX_CLK_CLKDIV2,
638
+ .offset = 22,
639
+ .len = 2,
640
+ .public_name = "apb5-clock",
641
+ },
642
+ [NPCM7XX_CLOCK_CLKOUT_DIVIDER] = {
643
+ .name = "clkout-divider",
644
+ .src_type = CLKSRC_SEL,
645
+ .src_index = NPCM7XX_CLOCK_CLKOUTSEL,
646
+ .divide = divide_by_reg_divisor,
647
+ .reg = NPCM7XX_CLK_CLKDIV2,
648
+ .offset = 16,
649
+ .len = 5,
650
+ .public_name = "clkout",
651
+ },
652
+ [NPCM7XX_CLOCK_UART_DIVIDER] = {
653
+ .name = "uart-divider",
654
+ .src_type = CLKSRC_SEL,
655
+ .src_index = NPCM7XX_CLOCK_UARTCKSEL,
656
+ .divide = divide_by_reg_divisor,
657
+ .reg = NPCM7XX_CLK_CLKDIV1,
658
+ .offset = 16,
659
+ .len = 5,
660
+ .public_name = "uart-clock",
661
+ },
662
+ [NPCM7XX_CLOCK_TIMER_DIVIDER] = {
663
+ .name = "timer-divider",
664
+ .src_type = CLKSRC_SEL,
665
+ .src_index = NPCM7XX_CLOCK_TIMCKSEL,
666
+ .divide = divide_by_reg_divisor,
667
+ .reg = NPCM7XX_CLK_CLKDIV1,
668
+ .offset = 21,
669
+ .len = 5,
670
+ .public_name = "timer-clock",
671
+ },
672
+ [NPCM7XX_CLOCK_ADC_DIVIDER] = {
673
+ .name = "adc-divider",
674
+ .src_type = CLKSRC_DIV,
675
+ .src_index = NPCM7XX_CLOCK_TIMER_DIVIDER,
676
+ .divide = shift_by_reg_divisor,
677
+ .reg = NPCM7XX_CLK_CLKDIV1,
678
+ .offset = 28,
679
+ .len = 3,
680
+ .public_name = "adc-clock",
681
+ },
682
+ [NPCM7XX_CLOCK_MMC_DIVIDER] = {
683
+ .name = "mmc-divider",
684
+ .src_type = CLKSRC_SEL,
685
+ .src_index = NPCM7XX_CLOCK_SDCKSEL,
686
+ .divide = divide_by_reg_divisor,
687
+ .reg = NPCM7XX_CLK_CLKDIV1,
688
+ .offset = 11,
689
+ .len = 5,
690
+ .public_name = "mmc-clock",
691
+ },
692
+ [NPCM7XX_CLOCK_SDHC_DIVIDER] = {
693
+ .name = "sdhc-divider",
694
+ .src_type = CLKSRC_SEL,
695
+ .src_index = NPCM7XX_CLOCK_SDCKSEL,
696
+ .divide = divide_by_reg_divisor_times_2,
697
+ .reg = NPCM7XX_CLK_CLKDIV2,
698
+ .offset = 0,
699
+ .len = 4,
700
+ .public_name = "sdhc-clock",
701
+ },
702
+ [NPCM7XX_CLOCK_GFXM_DIVIDER] = {
703
+ .name = "gfxm-divider",
704
+ .src_type = CLKSRC_SEL,
705
+ .src_index = NPCM7XX_CLOCK_GFXMSEL,
706
+ .divide = divide_by_constant,
707
+ .divisor = 3,
708
+ .public_name = "gfxm-clock",
709
+ },
710
+ [NPCM7XX_CLOCK_UTMI_DIVIDER] = {
711
+ .name = "utmi-divider",
712
+ .src_type = CLKSRC_SEL,
713
+ .src_index = NPCM7XX_CLOCK_SUCKSEL,
714
+ .divide = divide_by_reg_divisor,
715
+ .reg = NPCM7XX_CLK_CLKDIV2,
716
+ .offset = 8,
717
+ .len = 5,
718
+ .public_name = "utmi-clock",
719
+ },
720
+};
721
+
722
+static void npcm7xx_clk_pll_init(Object *obj)
723
+{
724
+ NPCM7xxClockPLLState *pll = NPCM7XX_CLOCK_PLL(obj);
725
+
726
+ pll->clock_in = qdev_init_clock_in(DEVICE(pll), "clock-in",
727
+ npcm7xx_clk_update_pll, pll);
728
+ pll->clock_out = qdev_init_clock_out(DEVICE(pll), "clock-out");
729
+}
730
+
731
+static void npcm7xx_clk_sel_init(Object *obj)
732
+{
733
+ int i;
734
+ NPCM7xxClockSELState *sel = NPCM7XX_CLOCK_SEL(obj);
735
+
736
+ for (i = 0; i < NPCM7XX_CLK_SEL_MAX_INPUT; ++i) {
737
+ sel->clock_in[i] = qdev_init_clock_in(DEVICE(sel),
738
+ g_strdup_printf("clock-in[%d]", i),
739
+ npcm7xx_clk_update_sel, sel);
740
+ }
741
+ sel->clock_out = qdev_init_clock_out(DEVICE(sel), "clock-out");
742
+}
743
+static void npcm7xx_clk_divider_init(Object *obj)
744
+{
745
+ NPCM7xxClockDividerState *div = NPCM7XX_CLOCK_DIVIDER(obj);
746
+
747
+ div->clock_in = qdev_init_clock_in(DEVICE(div), "clock-in",
748
+ npcm7xx_clk_update_divider, div);
749
+ div->clock_out = qdev_init_clock_out(DEVICE(div), "clock-out");
750
+}
751
+
752
+static void npcm7xx_init_clock_pll(NPCM7xxClockPLLState *pll,
753
+ NPCM7xxCLKState *clk, const PLLInitInfo *init_info)
754
+{
755
+ pll->name = init_info->name;
756
+ pll->clk = clk;
757
+ pll->reg = init_info->reg;
758
+ if (init_info->public_name != NULL) {
759
+ qdev_alias_clock(DEVICE(pll), "clock-out", DEVICE(clk),
760
+ init_info->public_name);
761
+ }
762
+}
763
+
764
+static void npcm7xx_init_clock_sel(NPCM7xxClockSELState *sel,
765
+ NPCM7xxCLKState *clk, const SELInitInfo *init_info)
766
+{
767
+ int input_size = init_info->input_size;
768
+
769
+ sel->name = init_info->name;
770
+ sel->clk = clk;
771
+ sel->input_size = init_info->input_size;
772
+ g_assert(input_size <= NPCM7XX_CLK_SEL_MAX_INPUT);
773
+ sel->offset = init_info->offset;
774
+ sel->len = init_info->len;
775
+ if (init_info->public_name != NULL) {
776
+ qdev_alias_clock(DEVICE(sel), "clock-out", DEVICE(clk),
777
+ init_info->public_name);
778
+ }
779
+}
780
+
781
+static void npcm7xx_init_clock_divider(NPCM7xxClockDividerState *div,
782
+ NPCM7xxCLKState *clk, const DividerInitInfo *init_info)
783
+{
784
+ div->name = init_info->name;
785
+ div->clk = clk;
786
+
787
+ div->divide = init_info->divide;
788
+ if (div->divide == divide_by_constant) {
789
+ div->divisor = init_info->divisor;
790
+ } else {
791
+ div->reg = init_info->reg;
792
+ div->offset = init_info->offset;
793
+ div->len = init_info->len;
794
+ }
795
+ if (init_info->public_name != NULL) {
796
+ qdev_alias_clock(DEVICE(div), "clock-out", DEVICE(clk),
797
+ init_info->public_name);
798
+ }
799
+}
800
+
801
+static Clock *npcm7xx_get_clock(NPCM7xxCLKState *clk, ClockSrcType type,
802
+ int index)
803
+{
804
+ switch (type) {
805
+ case CLKSRC_REF:
806
+ return clk->clkref;
807
+ case CLKSRC_PLL:
808
+ return clk->plls[index].clock_out;
809
+ case CLKSRC_SEL:
810
+ return clk->sels[index].clock_out;
811
+ case CLKSRC_DIV:
812
+ return clk->dividers[index].clock_out;
813
+ default:
814
+ g_assert_not_reached();
815
+ }
816
+}
817
+
818
+static void npcm7xx_connect_clocks(NPCM7xxCLKState *clk)
819
+{
820
+ int i, j;
821
+ Clock *src;
822
+
823
+ for (i = 0; i < NPCM7XX_CLOCK_NR_PLLS; ++i) {
824
+ src = npcm7xx_get_clock(clk, pll_init_info_list[i].src_type,
825
+ pll_init_info_list[i].src_index);
826
+ clock_set_source(clk->plls[i].clock_in, src);
827
+ }
828
+ for (i = 0; i < NPCM7XX_CLOCK_NR_SELS; ++i) {
829
+ for (j = 0; j < sel_init_info_list[i].input_size; ++j) {
830
+ src = npcm7xx_get_clock(clk, sel_init_info_list[i].src_type[j],
831
+ sel_init_info_list[i].src_index[j]);
832
+ clock_set_source(clk->sels[i].clock_in[j], src);
833
+ }
834
+ }
835
+ for (i = 0; i < NPCM7XX_CLOCK_NR_DIVIDERS; ++i) {
836
+ src = npcm7xx_get_clock(clk, divider_init_info_list[i].src_type,
837
+ divider_init_info_list[i].src_index);
838
+ clock_set_source(clk->dividers[i].clock_in, src);
839
+ }
840
+}
841
+
842
static uint64_t npcm7xx_clk_read(void *opaque, hwaddr offset, unsigned size)
843
{
387
{
844
uint32_t reg = offset / sizeof(uint32_t);
388
have_guest_debug = kvm_check_extension(s,
845
@@ -XXX,XX +XXX,XX @@ static uint64_t npcm7xx_clk_read(void *opaque, hwaddr offset, unsigned size)
389
@@ -XXX,XX +XXX,XX @@ void kvm_arm_init_debug(KVMState *s)
846
*
390
return;
847
* The 4 LSBs are always zero: (1e9 / 640) << 4 = 25000000.
848
*/
849
- value = (((now_ns - s->ref_ns) / 640) << 4) % NPCM7XX_TIMER_REF_HZ;
850
+ value = (((now_ns - s->ref_ns) / 640) << 4) % NPCM7XX_CLOCK_REF_HZ;
851
break;
852
853
default:
854
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_write(void *opaque, hwaddr offset,
855
value |= (value & PLLCON_LOKS);
856
}
857
}
858
+ /* Only update PLL when it is locked. */
859
+ if (value & PLLCON_LOKI) {
860
+ npcm7xx_clk_update_pll(&s->plls[find_pll_by_reg(reg)]);
861
+ }
862
+ break;
863
+
864
+ case NPCM7XX_CLK_CLKSEL:
865
+ npcm7xx_clk_update_all_sels(s);
866
+ break;
867
+
868
+ case NPCM7XX_CLK_CLKDIV1:
869
+ case NPCM7XX_CLK_CLKDIV2:
870
+ case NPCM7XX_CLK_CLKDIV3:
871
+ npcm7xx_clk_update_all_dividers(s);
872
break;
873
874
case NPCM7XX_CLK_CNTR25M:
875
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_enter_reset(Object *obj, ResetType type)
876
case RESET_TYPE_COLD:
877
memcpy(s->regs, cold_reset_values, sizeof(cold_reset_values));
878
s->ref_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
879
+ npcm7xx_clk_update_all_clocks(s);
880
return;
881
}
882
883
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_enter_reset(Object *obj, ResetType type)
884
__func__, type);
885
}
391
}
886
392
887
+static void npcm7xx_clk_init_clock_hierarchy(NPCM7xxCLKState *s)
393
-/**
888
+{
394
- * insert_hw_breakpoint()
889
+ int i;
395
- * @addr: address of breakpoint
890
+
396
- *
891
+ s->clkref = qdev_init_clock_in(DEVICE(s), "clkref", NULL, NULL);
397
- * See ARM ARM D2.9.1 for details but here we are only going to create
892
+
398
- * simple un-linked breakpoints (i.e. we don't chain breakpoints
893
+ /* First pass: init all converter modules */
399
- * together to match address and context or vmid). The hardware is
894
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(pll_init_info_list) != NPCM7XX_CLOCK_NR_PLLS);
400
- * capable of fancier matching but that will require exposing that
895
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(sel_init_info_list) != NPCM7XX_CLOCK_NR_SELS);
401
- * fanciness to GDB's interface
896
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(divider_init_info_list)
402
- *
897
+ != NPCM7XX_CLOCK_NR_DIVIDERS);
403
- * DBGBCR<n>_EL1, Debug Breakpoint Control Registers
898
+ for (i = 0; i < NPCM7XX_CLOCK_NR_PLLS; ++i) {
404
- *
899
+ object_initialize_child(OBJECT(s), pll_init_info_list[i].name,
405
- * 31 24 23 20 19 16 15 14 13 12 9 8 5 4 3 2 1 0
900
+ &s->plls[i], TYPE_NPCM7XX_CLOCK_PLL);
406
- * +------+------+-------+-----+----+------+-----+------+-----+---+
901
+ npcm7xx_init_clock_pll(&s->plls[i], s,
407
- * | RES0 | BT | LBN | SSC | HMC| RES0 | BAS | RES0 | PMC | E |
902
+ &pll_init_info_list[i]);
408
- * +------+------+-------+-----+----+------+-----+------+-----+---+
903
+ }
409
- *
904
+ for (i = 0; i < NPCM7XX_CLOCK_NR_SELS; ++i) {
410
- * BT: Breakpoint type (0 = unlinked address match)
905
+ object_initialize_child(OBJECT(s), sel_init_info_list[i].name,
411
- * LBN: Linked BP number (0 = unused)
906
+ &s->sels[i], TYPE_NPCM7XX_CLOCK_SEL);
412
- * SSC/HMC/PMC: Security, Higher and Priv access control (Table D-12)
907
+ npcm7xx_init_clock_sel(&s->sels[i], s,
413
- * BAS: Byte Address Select (RES1 for AArch64)
908
+ &sel_init_info_list[i]);
414
- * E: Enable bit
909
+ }
415
- *
910
+ for (i = 0; i < NPCM7XX_CLOCK_NR_DIVIDERS; ++i) {
416
- * DBGBVR<n>_EL1, Debug Breakpoint Value Registers
911
+ object_initialize_child(OBJECT(s), divider_init_info_list[i].name,
417
- *
912
+ &s->dividers[i], TYPE_NPCM7XX_CLOCK_DIVIDER);
418
- * 63 53 52 49 48 2 1 0
913
+ npcm7xx_init_clock_divider(&s->dividers[i], s,
419
- * +------+-----------+----------+-----+
914
+ &divider_init_info_list[i]);
420
- * | RESS | VA[52:49] | VA[48:2] | 0 0 |
915
+ }
421
- * +------+-----------+----------+-----+
916
+
422
- *
917
+ /* Second pass: connect converter modules */
423
- * Depending on the addressing mode bits the top bits of the register
918
+ npcm7xx_connect_clocks(s);
424
- * are a sign extension of the highest applicable VA bit. Some
919
+
425
- * versions of GDB don't do it correctly so we ensure they are correct
920
+ clock_update_hz(s->clkref, NPCM7XX_CLOCK_REF_HZ);
426
- * here so future PC comparisons will work properly.
921
+}
427
- */
922
+
428
-
923
static void npcm7xx_clk_init(Object *obj)
429
-static int insert_hw_breakpoint(target_ulong addr)
430
-{
431
- HWBreakpoint brk = {
432
- .bcr = 0x1, /* BCR E=1, enable */
433
- .bvr = sextract64(addr, 0, 53)
434
- };
435
-
436
- if (cur_hw_bps >= max_hw_bps) {
437
- return -ENOBUFS;
438
- }
439
-
440
- brk.bcr = deposit32(brk.bcr, 1, 2, 0x3); /* PMC = 11 */
441
- brk.bcr = deposit32(brk.bcr, 5, 4, 0xf); /* BAS = RES1 */
442
-
443
- g_array_append_val(hw_breakpoints, brk);
444
-
445
- return 0;
446
-}
447
-
448
-/**
449
- * delete_hw_breakpoint()
450
- * @pc: address of breakpoint
451
- *
452
- * Delete a breakpoint and shuffle any above down
453
- */
454
-
455
-static int delete_hw_breakpoint(target_ulong pc)
456
-{
457
- int i;
458
- for (i = 0; i < hw_breakpoints->len; i++) {
459
- HWBreakpoint *brk = get_hw_bp(i);
460
- if (brk->bvr == pc) {
461
- g_array_remove_index(hw_breakpoints, i);
462
- return 0;
463
- }
464
- }
465
- return -ENOENT;
466
-}
467
-
468
-/**
469
- * insert_hw_watchpoint()
470
- * @addr: address of watch point
471
- * @len: size of area
472
- * @type: type of watch point
473
- *
474
- * See ARM ARM D2.10. As with the breakpoints we can do some advanced
475
- * stuff if we want to. The watch points can be linked with the break
476
- * points above to make them context aware. However for simplicity
477
- * currently we only deal with simple read/write watch points.
478
- *
479
- * D7.3.11 DBGWCR<n>_EL1, Debug Watchpoint Control Registers
480
- *
481
- * 31 29 28 24 23 21 20 19 16 15 14 13 12 5 4 3 2 1 0
482
- * +------+-------+------+----+-----+-----+-----+-----+-----+-----+---+
483
- * | RES0 | MASK | RES0 | WT | LBN | SSC | HMC | BAS | LSC | PAC | E |
484
- * +------+-------+------+----+-----+-----+-----+-----+-----+-----+---+
485
- *
486
- * MASK: num bits addr mask (0=none,01/10=res,11=3 bits (8 bytes))
487
- * WT: 0 - unlinked, 1 - linked (not currently used)
488
- * LBN: Linked BP number (not currently used)
489
- * SSC/HMC/PAC: Security, Higher and Priv access control (Table D2-11)
490
- * BAS: Byte Address Select
491
- * LSC: Load/Store control (01: load, 10: store, 11: both)
492
- * E: Enable
493
- *
494
- * The bottom 2 bits of the value register are masked. Therefore to
495
- * break on any sizes smaller than an unaligned word you need to set
496
- * MASK=0, BAS=bit per byte in question. For larger regions (^2) you
497
- * need to ensure you mask the address as required and set BAS=0xff
498
- */
499
-
500
-static int insert_hw_watchpoint(target_ulong addr,
501
- target_ulong len, int type)
502
-{
503
- HWWatchpoint wp = {
504
- .wcr = R_DBGWCR_E_MASK, /* E=1, enable */
505
- .wvr = addr & (~0x7ULL),
506
- .details = { .vaddr = addr, .len = len }
507
- };
508
-
509
- if (cur_hw_wps >= max_hw_wps) {
510
- return -ENOBUFS;
511
- }
512
-
513
- /*
514
- * HMC=0 SSC=0 PAC=3 will hit EL0 or EL1, any security state,
515
- * valid whether EL3 is implemented or not
516
- */
517
- wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, PAC, 3);
518
-
519
- switch (type) {
520
- case GDB_WATCHPOINT_READ:
521
- wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, LSC, 1);
522
- wp.details.flags = BP_MEM_READ;
523
- break;
524
- case GDB_WATCHPOINT_WRITE:
525
- wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, LSC, 2);
526
- wp.details.flags = BP_MEM_WRITE;
527
- break;
528
- case GDB_WATCHPOINT_ACCESS:
529
- wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, LSC, 3);
530
- wp.details.flags = BP_MEM_ACCESS;
531
- break;
532
- default:
533
- g_assert_not_reached();
534
- break;
535
- }
536
- if (len <= 8) {
537
- /* we align the address and set the bits in BAS */
538
- int off = addr & 0x7;
539
- int bas = (1 << len) - 1;
540
-
541
- wp.wcr = deposit32(wp.wcr, 5 + off, 8 - off, bas);
542
- } else {
543
- /* For ranges above 8 bytes we need to be a power of 2 */
544
- if (is_power_of_2(len)) {
545
- int bits = ctz64(len);
546
-
547
- wp.wvr &= ~((1 << bits) - 1);
548
- wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, MASK, bits);
549
- wp.wcr = FIELD_DP64(wp.wcr, DBGWCR, BAS, 0xff);
550
- } else {
551
- return -ENOBUFS;
552
- }
553
- }
554
-
555
- g_array_append_val(hw_watchpoints, wp);
556
- return 0;
557
-}
558
-
559
-
560
-static bool check_watchpoint_in_range(int i, target_ulong addr)
561
-{
562
- HWWatchpoint *wp = get_hw_wp(i);
563
- uint64_t addr_top, addr_bottom = wp->wvr;
564
- int bas = extract32(wp->wcr, 5, 8);
565
- int mask = extract32(wp->wcr, 24, 4);
566
-
567
- if (mask) {
568
- addr_top = addr_bottom + (1 << mask);
569
- } else {
570
- /* BAS must be contiguous but can offset against the base
571
- * address in DBGWVR */
572
- addr_bottom = addr_bottom + ctz32(bas);
573
- addr_top = addr_bottom + clo32(bas);
574
- }
575
-
576
- if (addr >= addr_bottom && addr <= addr_top) {
577
- return true;
578
- }
579
-
580
- return false;
581
-}
582
-
583
-/**
584
- * delete_hw_watchpoint()
585
- * @addr: address of breakpoint
586
- *
587
- * Delete a breakpoint and shuffle any above down
588
- */
589
-
590
-static int delete_hw_watchpoint(target_ulong addr,
591
- target_ulong len, int type)
592
-{
593
- int i;
594
- for (i = 0; i < cur_hw_wps; i++) {
595
- if (check_watchpoint_in_range(i, addr)) {
596
- g_array_remove_index(hw_watchpoints, i);
597
- return 0;
598
- }
599
- }
600
- return -ENOENT;
601
-}
602
-
603
-
604
int kvm_arch_insert_hw_breakpoint(target_ulong addr,
605
target_ulong len, int type)
924
{
606
{
925
NPCM7xxCLKState *s = NPCM7XX_CLK(obj);
607
@@ -XXX,XX +XXX,XX @@ bool kvm_arm_hw_debug_active(CPUState *cs)
926
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_init(Object *obj)
608
return ((cur_hw_wps > 0) || (cur_hw_bps > 0));
927
memory_region_init_io(&s->iomem, obj, &npcm7xx_clk_ops, s,
928
TYPE_NPCM7XX_CLK, 4 * KiB);
929
sysbus_init_mmio(&s->parent, &s->iomem);
930
- qdev_init_gpio_in_named(DEVICE(s), npcm7xx_clk_perform_watchdog_reset,
931
- NPCM7XX_WATCHDOG_RESET_GPIO_IN, NPCM7XX_NR_WATCHDOGS);
932
}
609
}
933
610
934
-static const VMStateDescription vmstate_npcm7xx_clk = {
611
-static bool find_hw_breakpoint(CPUState *cpu, target_ulong pc)
935
- .name = "npcm7xx-clk",
612
-{
936
+static int npcm7xx_clk_post_load(void *opaque, int version_id)
613
- int i;
937
+{
614
-
938
+ if (version_id >= 1) {
615
- for (i = 0; i < cur_hw_bps; i++) {
939
+ NPCM7xxCLKState *clk = opaque;
616
- HWBreakpoint *bp = get_hw_bp(i);
940
+
617
- if (bp->bvr == pc) {
941
+ npcm7xx_clk_update_all_clocks(clk);
618
- return true;
942
+ }
619
- }
943
+
620
- }
944
+ return 0;
621
- return false;
945
+}
622
-}
946
+
623
-
947
+static void npcm7xx_clk_realize(DeviceState *dev, Error **errp)
624
-static CPUWatchpoint *find_hw_watchpoint(CPUState *cpu, target_ulong addr)
948
+{
625
-{
949
+ int i;
626
- int i;
950
+ NPCM7xxCLKState *s = NPCM7XX_CLK(dev);
627
-
951
+
628
- for (i = 0; i < cur_hw_wps; i++) {
952
+ qdev_init_gpio_in_named(DEVICE(s), npcm7xx_clk_perform_watchdog_reset,
629
- if (check_watchpoint_in_range(i, addr)) {
953
+ NPCM7XX_WATCHDOG_RESET_GPIO_IN, NPCM7XX_NR_WATCHDOGS);
630
- return &get_hw_wp(i)->details;
954
+ npcm7xx_clk_init_clock_hierarchy(s);
631
- }
955
+
632
- }
956
+ /* Realize child devices */
633
- return NULL;
957
+ for (i = 0; i < NPCM7XX_CLOCK_NR_PLLS; ++i) {
634
-}
958
+ if (!qdev_realize(DEVICE(&s->plls[i]), NULL, errp)) {
635
-
959
+ return;
636
static bool kvm_arm_set_device_attr(CPUState *cs, struct kvm_device_attr *attr,
960
+ }
637
const char *name)
961
+ }
962
+ for (i = 0; i < NPCM7XX_CLOCK_NR_SELS; ++i) {
963
+ if (!qdev_realize(DEVICE(&s->sels[i]), NULL, errp)) {
964
+ return;
965
+ }
966
+ }
967
+ for (i = 0; i < NPCM7XX_CLOCK_NR_DIVIDERS; ++i) {
968
+ if (!qdev_realize(DEVICE(&s->dividers[i]), NULL, errp)) {
969
+ return;
970
+ }
971
+ }
972
+}
973
+
974
+static const VMStateDescription vmstate_npcm7xx_clk_pll = {
975
+ .name = "npcm7xx-clock-pll",
976
.version_id = 0,
977
.minimum_version_id = 0,
978
- .fields = (VMStateField[]) {
979
- VMSTATE_UINT32_ARRAY(regs, NPCM7xxCLKState, NPCM7XX_CLK_NR_REGS),
980
- VMSTATE_INT64(ref_ns, NPCM7xxCLKState),
981
+ .fields = (VMStateField[]) {
982
+ VMSTATE_CLOCK(clock_in, NPCM7xxClockPLLState),
983
VMSTATE_END_OF_LIST(),
984
},
985
};
986
987
+static const VMStateDescription vmstate_npcm7xx_clk_sel = {
988
+ .name = "npcm7xx-clock-sel",
989
+ .version_id = 0,
990
+ .minimum_version_id = 0,
991
+ .fields = (VMStateField[]) {
992
+ VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(clock_in, NPCM7xxClockSELState,
993
+ NPCM7XX_CLK_SEL_MAX_INPUT, 0, vmstate_clock, Clock),
994
+ VMSTATE_END_OF_LIST(),
995
+ },
996
+};
997
+
998
+static const VMStateDescription vmstate_npcm7xx_clk_divider = {
999
+ .name = "npcm7xx-clock-divider",
1000
+ .version_id = 0,
1001
+ .minimum_version_id = 0,
1002
+ .fields = (VMStateField[]) {
1003
+ VMSTATE_CLOCK(clock_in, NPCM7xxClockDividerState),
1004
+ VMSTATE_END_OF_LIST(),
1005
+ },
1006
+};
1007
+
1008
+static const VMStateDescription vmstate_npcm7xx_clk = {
1009
+ .name = "npcm7xx-clk",
1010
+ .version_id = 1,
1011
+ .minimum_version_id = 1,
1012
+ .post_load = npcm7xx_clk_post_load,
1013
+ .fields = (VMStateField[]) {
1014
+ VMSTATE_UINT32_ARRAY(regs, NPCM7xxCLKState, NPCM7XX_CLK_NR_REGS),
1015
+ VMSTATE_INT64(ref_ns, NPCM7xxCLKState),
1016
+ VMSTATE_CLOCK(clkref, NPCM7xxCLKState),
1017
+ VMSTATE_END_OF_LIST(),
1018
+ },
1019
+};
1020
+
1021
+static void npcm7xx_clk_pll_class_init(ObjectClass *klass, void *data)
1022
+{
1023
+ DeviceClass *dc = DEVICE_CLASS(klass);
1024
+
1025
+ dc->desc = "NPCM7xx Clock PLL Module";
1026
+ dc->vmsd = &vmstate_npcm7xx_clk_pll;
1027
+}
1028
+
1029
+static void npcm7xx_clk_sel_class_init(ObjectClass *klass, void *data)
1030
+{
1031
+ DeviceClass *dc = DEVICE_CLASS(klass);
1032
+
1033
+ dc->desc = "NPCM7xx Clock SEL Module";
1034
+ dc->vmsd = &vmstate_npcm7xx_clk_sel;
1035
+}
1036
+
1037
+static void npcm7xx_clk_divider_class_init(ObjectClass *klass, void *data)
1038
+{
1039
+ DeviceClass *dc = DEVICE_CLASS(klass);
1040
+
1041
+ dc->desc = "NPCM7xx Clock Divider Module";
1042
+ dc->vmsd = &vmstate_npcm7xx_clk_divider;
1043
+}
1044
+
1045
static void npcm7xx_clk_class_init(ObjectClass *klass, void *data)
1046
{
638
{
1047
ResettableClass *rc = RESETTABLE_CLASS(klass);
639
diff --git a/target/arm/meson.build b/target/arm/meson.build
1048
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_class_init(ObjectClass *klass, void *data)
640
index XXXXXXX..XXXXXXX 100644
1049
641
--- a/target/arm/meson.build
1050
dc->desc = "NPCM7xx Clock Control Registers";
642
+++ b/target/arm/meson.build
1051
dc->vmsd = &vmstate_npcm7xx_clk;
643
@@ -XXX,XX +XXX,XX @@ arm_ss.add(files(
1052
+ dc->realize = npcm7xx_clk_realize;
644
))
1053
rc->phases.enter = npcm7xx_clk_enter_reset;
645
arm_ss.add(zlib)
1054
}
646
1055
647
-arm_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c', 'kvm64.c'), if_false: files('kvm-stub.c'))
1056
+static const TypeInfo npcm7xx_clk_pll_info = {
648
+arm_ss.add(when: 'CONFIG_KVM', if_true: files('hyp_gdbstub.c', 'kvm.c', 'kvm64.c'), if_false: files('kvm-stub.c'))
1057
+ .name = TYPE_NPCM7XX_CLOCK_PLL,
649
+arm_ss.add(when: 'CONFIG_HVF', if_true: files('hyp_gdbstub.c'))
1058
+ .parent = TYPE_DEVICE,
650
1059
+ .instance_size = sizeof(NPCM7xxClockPLLState),
651
arm_ss.add(when: 'TARGET_AARCH64', if_true: files(
1060
+ .instance_init = npcm7xx_clk_pll_init,
652
'cpu64.c',
1061
+ .class_init = npcm7xx_clk_pll_class_init,
1062
+};
1063
+
1064
+static const TypeInfo npcm7xx_clk_sel_info = {
1065
+ .name = TYPE_NPCM7XX_CLOCK_SEL,
1066
+ .parent = TYPE_DEVICE,
1067
+ .instance_size = sizeof(NPCM7xxClockSELState),
1068
+ .instance_init = npcm7xx_clk_sel_init,
1069
+ .class_init = npcm7xx_clk_sel_class_init,
1070
+};
1071
+
1072
+static const TypeInfo npcm7xx_clk_divider_info = {
1073
+ .name = TYPE_NPCM7XX_CLOCK_DIVIDER,
1074
+ .parent = TYPE_DEVICE,
1075
+ .instance_size = sizeof(NPCM7xxClockDividerState),
1076
+ .instance_init = npcm7xx_clk_divider_init,
1077
+ .class_init = npcm7xx_clk_divider_class_init,
1078
+};
1079
+
1080
static const TypeInfo npcm7xx_clk_info = {
1081
.name = TYPE_NPCM7XX_CLK,
1082
.parent = TYPE_SYS_BUS_DEVICE,
1083
@@ -XXX,XX +XXX,XX @@ static const TypeInfo npcm7xx_clk_info = {
1084
1085
static void npcm7xx_clk_register_type(void)
1086
{
1087
+ type_register_static(&npcm7xx_clk_pll_info);
1088
+ type_register_static(&npcm7xx_clk_sel_info);
1089
+ type_register_static(&npcm7xx_clk_divider_info);
1090
type_register_static(&npcm7xx_clk_info);
1091
}
1092
type_init(npcm7xx_clk_register_type);
1093
--
653
--
1094
2.20.1
654
2.34.1
1095
655
1096
656
diff view generated by jsdifflib
1
From: Leif Lindholm <leif@nuviainc.com>
1
From: Francesco Cagnin <fcagnin@quarkslab.com>
2
2
3
Add entries present in ARM DDI 0487F.c (August 2020).
3
Required for guest debugging.
4
4
5
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
5
Signed-off-by: Francesco Cagnin <fcagnin@quarkslab.com>
6
Message-id: 20230601153107.81955-3-fcagnin@quarkslab.com
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
8
Message-id: 20210108185154.8108-7-leif@nuviainc.com
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
9
---
11
target/arm/cpu.h | 28 ++++++++++++++++++++++++++++
10
target/arm/hvf/hvf.c | 213 +++++++++++++++++++++++++++++++++++++++++++
12
1 file changed, 28 insertions(+)
11
1 file changed, 213 insertions(+)
13
12
14
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
13
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
15
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/cpu.h
15
--- a/target/arm/hvf/hvf.c
17
+++ b/target/arm/cpu.h
16
+++ b/target/arm/hvf/hvf.c
18
@@ -XXX,XX +XXX,XX @@ FIELD(ID_ISAR6, DP, 4, 4)
17
@@ -XXX,XX +XXX,XX @@
19
FIELD(ID_ISAR6, FHM, 8, 4)
18
#define SYSREG_ICC_SGI1R_EL1 SYSREG(3, 0, 12, 11, 5)
20
FIELD(ID_ISAR6, SB, 12, 4)
19
#define SYSREG_ICC_SRE_EL1 SYSREG(3, 0, 12, 12, 5)
21
FIELD(ID_ISAR6, SPECRES, 16, 4)
20
22
+FIELD(ID_ISAR6, BF16, 20, 4)
21
+#define SYSREG_MDSCR_EL1 SYSREG(2, 0, 0, 2, 2)
23
+FIELD(ID_ISAR6, I8MM, 24, 4)
22
+#define SYSREG_DBGBVR0_EL1 SYSREG(2, 0, 0, 0, 4)
24
23
+#define SYSREG_DBGBCR0_EL1 SYSREG(2, 0, 0, 0, 5)
25
FIELD(ID_MMFR0, VMSA, 0, 4)
24
+#define SYSREG_DBGWVR0_EL1 SYSREG(2, 0, 0, 0, 6)
26
FIELD(ID_MMFR0, PMSA, 4, 4)
25
+#define SYSREG_DBGWCR0_EL1 SYSREG(2, 0, 0, 0, 7)
27
@@ -XXX,XX +XXX,XX @@ FIELD(ID_MMFR0, AUXREG, 20, 4)
26
+#define SYSREG_DBGBVR1_EL1 SYSREG(2, 0, 0, 1, 4)
28
FIELD(ID_MMFR0, FCSE, 24, 4)
27
+#define SYSREG_DBGBCR1_EL1 SYSREG(2, 0, 0, 1, 5)
29
FIELD(ID_MMFR0, INNERSHR, 28, 4)
28
+#define SYSREG_DBGWVR1_EL1 SYSREG(2, 0, 0, 1, 6)
30
29
+#define SYSREG_DBGWCR1_EL1 SYSREG(2, 0, 0, 1, 7)
31
+FIELD(ID_MMFR1, L1HVDVA, 0, 4)
30
+#define SYSREG_DBGBVR2_EL1 SYSREG(2, 0, 0, 2, 4)
32
+FIELD(ID_MMFR1, L1UNIVA, 4, 4)
31
+#define SYSREG_DBGBCR2_EL1 SYSREG(2, 0, 0, 2, 5)
33
+FIELD(ID_MMFR1, L1HVDSW, 8, 4)
32
+#define SYSREG_DBGWVR2_EL1 SYSREG(2, 0, 0, 2, 6)
34
+FIELD(ID_MMFR1, L1UNISW, 12, 4)
33
+#define SYSREG_DBGWCR2_EL1 SYSREG(2, 0, 0, 2, 7)
35
+FIELD(ID_MMFR1, L1HVD, 16, 4)
34
+#define SYSREG_DBGBVR3_EL1 SYSREG(2, 0, 0, 3, 4)
36
+FIELD(ID_MMFR1, L1UNI, 20, 4)
35
+#define SYSREG_DBGBCR3_EL1 SYSREG(2, 0, 0, 3, 5)
37
+FIELD(ID_MMFR1, L1TSTCLN, 24, 4)
36
+#define SYSREG_DBGWVR3_EL1 SYSREG(2, 0, 0, 3, 6)
38
+FIELD(ID_MMFR1, BPRED, 28, 4)
37
+#define SYSREG_DBGWCR3_EL1 SYSREG(2, 0, 0, 3, 7)
38
+#define SYSREG_DBGBVR4_EL1 SYSREG(2, 0, 0, 4, 4)
39
+#define SYSREG_DBGBCR4_EL1 SYSREG(2, 0, 0, 4, 5)
40
+#define SYSREG_DBGWVR4_EL1 SYSREG(2, 0, 0, 4, 6)
41
+#define SYSREG_DBGWCR4_EL1 SYSREG(2, 0, 0, 4, 7)
42
+#define SYSREG_DBGBVR5_EL1 SYSREG(2, 0, 0, 5, 4)
43
+#define SYSREG_DBGBCR5_EL1 SYSREG(2, 0, 0, 5, 5)
44
+#define SYSREG_DBGWVR5_EL1 SYSREG(2, 0, 0, 5, 6)
45
+#define SYSREG_DBGWCR5_EL1 SYSREG(2, 0, 0, 5, 7)
46
+#define SYSREG_DBGBVR6_EL1 SYSREG(2, 0, 0, 6, 4)
47
+#define SYSREG_DBGBCR6_EL1 SYSREG(2, 0, 0, 6, 5)
48
+#define SYSREG_DBGWVR6_EL1 SYSREG(2, 0, 0, 6, 6)
49
+#define SYSREG_DBGWCR6_EL1 SYSREG(2, 0, 0, 6, 7)
50
+#define SYSREG_DBGBVR7_EL1 SYSREG(2, 0, 0, 7, 4)
51
+#define SYSREG_DBGBCR7_EL1 SYSREG(2, 0, 0, 7, 5)
52
+#define SYSREG_DBGWVR7_EL1 SYSREG(2, 0, 0, 7, 6)
53
+#define SYSREG_DBGWCR7_EL1 SYSREG(2, 0, 0, 7, 7)
54
+#define SYSREG_DBGBVR8_EL1 SYSREG(2, 0, 0, 8, 4)
55
+#define SYSREG_DBGBCR8_EL1 SYSREG(2, 0, 0, 8, 5)
56
+#define SYSREG_DBGWVR8_EL1 SYSREG(2, 0, 0, 8, 6)
57
+#define SYSREG_DBGWCR8_EL1 SYSREG(2, 0, 0, 8, 7)
58
+#define SYSREG_DBGBVR9_EL1 SYSREG(2, 0, 0, 9, 4)
59
+#define SYSREG_DBGBCR9_EL1 SYSREG(2, 0, 0, 9, 5)
60
+#define SYSREG_DBGWVR9_EL1 SYSREG(2, 0, 0, 9, 6)
61
+#define SYSREG_DBGWCR9_EL1 SYSREG(2, 0, 0, 9, 7)
62
+#define SYSREG_DBGBVR10_EL1 SYSREG(2, 0, 0, 10, 4)
63
+#define SYSREG_DBGBCR10_EL1 SYSREG(2, 0, 0, 10, 5)
64
+#define SYSREG_DBGWVR10_EL1 SYSREG(2, 0, 0, 10, 6)
65
+#define SYSREG_DBGWCR10_EL1 SYSREG(2, 0, 0, 10, 7)
66
+#define SYSREG_DBGBVR11_EL1 SYSREG(2, 0, 0, 11, 4)
67
+#define SYSREG_DBGBCR11_EL1 SYSREG(2, 0, 0, 11, 5)
68
+#define SYSREG_DBGWVR11_EL1 SYSREG(2, 0, 0, 11, 6)
69
+#define SYSREG_DBGWCR11_EL1 SYSREG(2, 0, 0, 11, 7)
70
+#define SYSREG_DBGBVR12_EL1 SYSREG(2, 0, 0, 12, 4)
71
+#define SYSREG_DBGBCR12_EL1 SYSREG(2, 0, 0, 12, 5)
72
+#define SYSREG_DBGWVR12_EL1 SYSREG(2, 0, 0, 12, 6)
73
+#define SYSREG_DBGWCR12_EL1 SYSREG(2, 0, 0, 12, 7)
74
+#define SYSREG_DBGBVR13_EL1 SYSREG(2, 0, 0, 13, 4)
75
+#define SYSREG_DBGBCR13_EL1 SYSREG(2, 0, 0, 13, 5)
76
+#define SYSREG_DBGWVR13_EL1 SYSREG(2, 0, 0, 13, 6)
77
+#define SYSREG_DBGWCR13_EL1 SYSREG(2, 0, 0, 13, 7)
78
+#define SYSREG_DBGBVR14_EL1 SYSREG(2, 0, 0, 14, 4)
79
+#define SYSREG_DBGBCR14_EL1 SYSREG(2, 0, 0, 14, 5)
80
+#define SYSREG_DBGWVR14_EL1 SYSREG(2, 0, 0, 14, 6)
81
+#define SYSREG_DBGWCR14_EL1 SYSREG(2, 0, 0, 14, 7)
82
+#define SYSREG_DBGBVR15_EL1 SYSREG(2, 0, 0, 15, 4)
83
+#define SYSREG_DBGBCR15_EL1 SYSREG(2, 0, 0, 15, 5)
84
+#define SYSREG_DBGWVR15_EL1 SYSREG(2, 0, 0, 15, 6)
85
+#define SYSREG_DBGWCR15_EL1 SYSREG(2, 0, 0, 15, 7)
39
+
86
+
40
+FIELD(ID_MMFR2, L1HVDFG, 0, 4)
87
#define WFX_IS_WFE (1 << 0)
41
+FIELD(ID_MMFR2, L1HVDBG, 4, 4)
88
42
+FIELD(ID_MMFR2, L1HVDRNG, 8, 4)
89
#define TMR_CTL_ENABLE (1 << 0)
43
+FIELD(ID_MMFR2, HVDTLB, 12, 4)
90
@@ -XXX,XX +XXX,XX @@ static int hvf_sysreg_read(CPUState *cpu, uint32_t reg, uint32_t rt)
44
+FIELD(ID_MMFR2, UNITLB, 16, 4)
91
hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized());
45
+FIELD(ID_MMFR2, MEMBARR, 20, 4)
92
}
46
+FIELD(ID_MMFR2, WFISTALL, 24, 4)
93
break;
47
+FIELD(ID_MMFR2, HWACCFLG, 28, 4)
94
+ case SYSREG_DBGBVR0_EL1:
48
+
95
+ case SYSREG_DBGBVR1_EL1:
49
FIELD(ID_MMFR3, CMAINTVA, 0, 4)
96
+ case SYSREG_DBGBVR2_EL1:
50
FIELD(ID_MMFR3, CMAINTSW, 4, 4)
97
+ case SYSREG_DBGBVR3_EL1:
51
FIELD(ID_MMFR3, BPMAINT, 8, 4)
98
+ case SYSREG_DBGBVR4_EL1:
52
@@ -XXX,XX +XXX,XX @@ FIELD(ID_MMFR4, LSM, 20, 4)
99
+ case SYSREG_DBGBVR5_EL1:
53
FIELD(ID_MMFR4, CCIDX, 24, 4)
100
+ case SYSREG_DBGBVR6_EL1:
54
FIELD(ID_MMFR4, EVT, 28, 4)
101
+ case SYSREG_DBGBVR7_EL1:
55
102
+ case SYSREG_DBGBVR8_EL1:
56
+FIELD(ID_MMFR5, ETS, 0, 4)
103
+ case SYSREG_DBGBVR9_EL1:
57
+
104
+ case SYSREG_DBGBVR10_EL1:
58
FIELD(ID_PFR0, STATE0, 0, 4)
105
+ case SYSREG_DBGBVR11_EL1:
59
FIELD(ID_PFR0, STATE1, 4, 4)
106
+ case SYSREG_DBGBVR12_EL1:
60
FIELD(ID_PFR0, STATE2, 8, 4)
107
+ case SYSREG_DBGBVR13_EL1:
61
@@ -XXX,XX +XXX,XX @@ FIELD(ID_PFR1, SEC_FRAC, 20, 4)
108
+ case SYSREG_DBGBVR14_EL1:
62
FIELD(ID_PFR1, VIRT_FRAC, 24, 4)
109
+ case SYSREG_DBGBVR15_EL1:
63
FIELD(ID_PFR1, GIC, 28, 4)
110
+ val = env->cp15.dbgbvr[SYSREG_CRM(reg)];
64
111
+ break;
65
+FIELD(ID_PFR2, CSV3, 0, 4)
112
+ case SYSREG_DBGBCR0_EL1:
66
+FIELD(ID_PFR2, SSBS, 4, 4)
113
+ case SYSREG_DBGBCR1_EL1:
67
+FIELD(ID_PFR2, RAS_FRAC, 8, 4)
114
+ case SYSREG_DBGBCR2_EL1:
68
+
115
+ case SYSREG_DBGBCR3_EL1:
69
FIELD(ID_AA64ISAR0, AES, 4, 4)
116
+ case SYSREG_DBGBCR4_EL1:
70
FIELD(ID_AA64ISAR0, SHA1, 8, 4)
117
+ case SYSREG_DBGBCR5_EL1:
71
FIELD(ID_AA64ISAR0, SHA2, 12, 4)
118
+ case SYSREG_DBGBCR6_EL1:
72
@@ -XXX,XX +XXX,XX @@ FIELD(ID_DFR0, MPROFDBG, 20, 4)
119
+ case SYSREG_DBGBCR7_EL1:
73
FIELD(ID_DFR0, PERFMON, 24, 4)
120
+ case SYSREG_DBGBCR8_EL1:
74
FIELD(ID_DFR0, TRACEFILT, 28, 4)
121
+ case SYSREG_DBGBCR9_EL1:
75
122
+ case SYSREG_DBGBCR10_EL1:
76
+FIELD(ID_DFR1, MTPMU, 0, 4)
123
+ case SYSREG_DBGBCR11_EL1:
77
+
124
+ case SYSREG_DBGBCR12_EL1:
78
FIELD(DBGDIDR, SE_IMP, 12, 1)
125
+ case SYSREG_DBGBCR13_EL1:
79
FIELD(DBGDIDR, NSUHD_IMP, 14, 1)
126
+ case SYSREG_DBGBCR14_EL1:
80
FIELD(DBGDIDR, VERSION, 16, 4)
127
+ case SYSREG_DBGBCR15_EL1:
128
+ val = env->cp15.dbgbcr[SYSREG_CRM(reg)];
129
+ break;
130
+ case SYSREG_DBGWVR0_EL1:
131
+ case SYSREG_DBGWVR1_EL1:
132
+ case SYSREG_DBGWVR2_EL1:
133
+ case SYSREG_DBGWVR3_EL1:
134
+ case SYSREG_DBGWVR4_EL1:
135
+ case SYSREG_DBGWVR5_EL1:
136
+ case SYSREG_DBGWVR6_EL1:
137
+ case SYSREG_DBGWVR7_EL1:
138
+ case SYSREG_DBGWVR8_EL1:
139
+ case SYSREG_DBGWVR9_EL1:
140
+ case SYSREG_DBGWVR10_EL1:
141
+ case SYSREG_DBGWVR11_EL1:
142
+ case SYSREG_DBGWVR12_EL1:
143
+ case SYSREG_DBGWVR13_EL1:
144
+ case SYSREG_DBGWVR14_EL1:
145
+ case SYSREG_DBGWVR15_EL1:
146
+ val = env->cp15.dbgwvr[SYSREG_CRM(reg)];
147
+ break;
148
+ case SYSREG_DBGWCR0_EL1:
149
+ case SYSREG_DBGWCR1_EL1:
150
+ case SYSREG_DBGWCR2_EL1:
151
+ case SYSREG_DBGWCR3_EL1:
152
+ case SYSREG_DBGWCR4_EL1:
153
+ case SYSREG_DBGWCR5_EL1:
154
+ case SYSREG_DBGWCR6_EL1:
155
+ case SYSREG_DBGWCR7_EL1:
156
+ case SYSREG_DBGWCR8_EL1:
157
+ case SYSREG_DBGWCR9_EL1:
158
+ case SYSREG_DBGWCR10_EL1:
159
+ case SYSREG_DBGWCR11_EL1:
160
+ case SYSREG_DBGWCR12_EL1:
161
+ case SYSREG_DBGWCR13_EL1:
162
+ case SYSREG_DBGWCR14_EL1:
163
+ case SYSREG_DBGWCR15_EL1:
164
+ val = env->cp15.dbgwcr[SYSREG_CRM(reg)];
165
+ break;
166
default:
167
if (is_id_sysreg(reg)) {
168
/* ID system registers read as RES0 */
169
@@ -XXX,XX +XXX,XX @@ static int hvf_sysreg_write(CPUState *cpu, uint32_t reg, uint64_t val)
170
hvf_raise_exception(cpu, EXCP_UDEF, syn_uncategorized());
171
}
172
break;
173
+ case SYSREG_MDSCR_EL1:
174
+ env->cp15.mdscr_el1 = val;
175
+ break;
176
+ case SYSREG_DBGBVR0_EL1:
177
+ case SYSREG_DBGBVR1_EL1:
178
+ case SYSREG_DBGBVR2_EL1:
179
+ case SYSREG_DBGBVR3_EL1:
180
+ case SYSREG_DBGBVR4_EL1:
181
+ case SYSREG_DBGBVR5_EL1:
182
+ case SYSREG_DBGBVR6_EL1:
183
+ case SYSREG_DBGBVR7_EL1:
184
+ case SYSREG_DBGBVR8_EL1:
185
+ case SYSREG_DBGBVR9_EL1:
186
+ case SYSREG_DBGBVR10_EL1:
187
+ case SYSREG_DBGBVR11_EL1:
188
+ case SYSREG_DBGBVR12_EL1:
189
+ case SYSREG_DBGBVR13_EL1:
190
+ case SYSREG_DBGBVR14_EL1:
191
+ case SYSREG_DBGBVR15_EL1:
192
+ env->cp15.dbgbvr[SYSREG_CRM(reg)] = val;
193
+ break;
194
+ case SYSREG_DBGBCR0_EL1:
195
+ case SYSREG_DBGBCR1_EL1:
196
+ case SYSREG_DBGBCR2_EL1:
197
+ case SYSREG_DBGBCR3_EL1:
198
+ case SYSREG_DBGBCR4_EL1:
199
+ case SYSREG_DBGBCR5_EL1:
200
+ case SYSREG_DBGBCR6_EL1:
201
+ case SYSREG_DBGBCR7_EL1:
202
+ case SYSREG_DBGBCR8_EL1:
203
+ case SYSREG_DBGBCR9_EL1:
204
+ case SYSREG_DBGBCR10_EL1:
205
+ case SYSREG_DBGBCR11_EL1:
206
+ case SYSREG_DBGBCR12_EL1:
207
+ case SYSREG_DBGBCR13_EL1:
208
+ case SYSREG_DBGBCR14_EL1:
209
+ case SYSREG_DBGBCR15_EL1:
210
+ env->cp15.dbgbcr[SYSREG_CRM(reg)] = val;
211
+ break;
212
+ case SYSREG_DBGWVR0_EL1:
213
+ case SYSREG_DBGWVR1_EL1:
214
+ case SYSREG_DBGWVR2_EL1:
215
+ case SYSREG_DBGWVR3_EL1:
216
+ case SYSREG_DBGWVR4_EL1:
217
+ case SYSREG_DBGWVR5_EL1:
218
+ case SYSREG_DBGWVR6_EL1:
219
+ case SYSREG_DBGWVR7_EL1:
220
+ case SYSREG_DBGWVR8_EL1:
221
+ case SYSREG_DBGWVR9_EL1:
222
+ case SYSREG_DBGWVR10_EL1:
223
+ case SYSREG_DBGWVR11_EL1:
224
+ case SYSREG_DBGWVR12_EL1:
225
+ case SYSREG_DBGWVR13_EL1:
226
+ case SYSREG_DBGWVR14_EL1:
227
+ case SYSREG_DBGWVR15_EL1:
228
+ env->cp15.dbgwvr[SYSREG_CRM(reg)] = val;
229
+ break;
230
+ case SYSREG_DBGWCR0_EL1:
231
+ case SYSREG_DBGWCR1_EL1:
232
+ case SYSREG_DBGWCR2_EL1:
233
+ case SYSREG_DBGWCR3_EL1:
234
+ case SYSREG_DBGWCR4_EL1:
235
+ case SYSREG_DBGWCR5_EL1:
236
+ case SYSREG_DBGWCR6_EL1:
237
+ case SYSREG_DBGWCR7_EL1:
238
+ case SYSREG_DBGWCR8_EL1:
239
+ case SYSREG_DBGWCR9_EL1:
240
+ case SYSREG_DBGWCR10_EL1:
241
+ case SYSREG_DBGWCR11_EL1:
242
+ case SYSREG_DBGWCR12_EL1:
243
+ case SYSREG_DBGWCR13_EL1:
244
+ case SYSREG_DBGWCR14_EL1:
245
+ case SYSREG_DBGWCR15_EL1:
246
+ env->cp15.dbgwcr[SYSREG_CRM(reg)] = val;
247
+ break;
248
default:
249
cpu_synchronize_state(cpu);
250
trace_hvf_unhandled_sysreg_write(env->pc, reg,
81
--
251
--
82
2.20.1
252
2.34.1
83
84
diff view generated by jsdifflib
New patch
1
From: Francesco Cagnin <fcagnin@quarkslab.com>
1
2
3
Required for guest debugging. The code has been structured like the KVM
4
counterpart.
5
6
Signed-off-by: Francesco Cagnin <fcagnin@quarkslab.com>
7
Message-id: 20230601153107.81955-4-fcagnin@quarkslab.com
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
include/sysemu/hvf.h | 22 ++++++++
12
include/sysemu/hvf_int.h | 1 +
13
accel/hvf/hvf-accel-ops.c | 109 ++++++++++++++++++++++++++++++++++++++
14
accel/hvf/hvf-all.c | 17 ++++++
15
target/arm/hvf/hvf.c | 63 ++++++++++++++++++++++
16
target/i386/hvf/hvf.c | 24 +++++++++
17
6 files changed, 236 insertions(+)
18
19
diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h
20
index XXXXXXX..XXXXXXX 100644
21
--- a/include/sysemu/hvf.h
22
+++ b/include/sysemu/hvf.h
23
@@ -XXX,XX +XXX,XX @@
24
#include "qom/object.h"
25
26
#ifdef NEED_CPU_H
27
+#include "cpu.h"
28
29
#ifdef CONFIG_HVF
30
uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx,
31
@@ -XXX,XX +XXX,XX @@ typedef struct HVFState HVFState;
32
DECLARE_INSTANCE_CHECKER(HVFState, HVF_STATE,
33
TYPE_HVF_ACCEL)
34
35
+#ifdef NEED_CPU_H
36
+struct hvf_sw_breakpoint {
37
+ target_ulong pc;
38
+ target_ulong saved_insn;
39
+ int use_count;
40
+ QTAILQ_ENTRY(hvf_sw_breakpoint) entry;
41
+};
42
+
43
+struct hvf_sw_breakpoint *hvf_find_sw_breakpoint(CPUState *cpu,
44
+ target_ulong pc);
45
+int hvf_sw_breakpoints_active(CPUState *cpu);
46
+
47
+int hvf_arch_insert_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint *bp);
48
+int hvf_arch_remove_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint *bp);
49
+int hvf_arch_insert_hw_breakpoint(target_ulong addr, target_ulong len,
50
+ int type);
51
+int hvf_arch_remove_hw_breakpoint(target_ulong addr, target_ulong len,
52
+ int type);
53
+void hvf_arch_remove_all_hw_breakpoints(void);
54
+#endif /* NEED_CPU_H */
55
+
56
#endif
57
diff --git a/include/sysemu/hvf_int.h b/include/sysemu/hvf_int.h
58
index XXXXXXX..XXXXXXX 100644
59
--- a/include/sysemu/hvf_int.h
60
+++ b/include/sysemu/hvf_int.h
61
@@ -XXX,XX +XXX,XX @@ struct HVFState {
62
63
hvf_vcpu_caps *hvf_caps;
64
uint64_t vtimer_offset;
65
+ QTAILQ_HEAD(, hvf_sw_breakpoint) hvf_sw_breakpoints;
66
};
67
extern HVFState *hvf_state;
68
69
diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c
70
index XXXXXXX..XXXXXXX 100644
71
--- a/accel/hvf/hvf-accel-ops.c
72
+++ b/accel/hvf/hvf-accel-ops.c
73
@@ -XXX,XX +XXX,XX @@
74
#include "qemu/main-loop.h"
75
#include "exec/address-spaces.h"
76
#include "exec/exec-all.h"
77
+#include "exec/gdbstub.h"
78
#include "sysemu/cpus.h"
79
#include "sysemu/hvf.h"
80
#include "sysemu/hvf_int.h"
81
@@ -XXX,XX +XXX,XX @@ static int hvf_accel_init(MachineState *ms)
82
s->slots[x].slot_id = x;
83
}
84
85
+ QTAILQ_INIT(&s->hvf_sw_breakpoints);
86
+
87
hvf_state = s;
88
memory_listener_register(&hvf_memory_listener, &address_space_memory);
89
90
@@ -XXX,XX +XXX,XX @@ static void hvf_start_vcpu_thread(CPUState *cpu)
91
cpu, QEMU_THREAD_JOINABLE);
92
}
93
94
+static int hvf_insert_breakpoint(CPUState *cpu, int type, hwaddr addr, hwaddr len)
95
+{
96
+ struct hvf_sw_breakpoint *bp;
97
+ int err;
98
+
99
+ if (type == GDB_BREAKPOINT_SW) {
100
+ bp = hvf_find_sw_breakpoint(cpu, addr);
101
+ if (bp) {
102
+ bp->use_count++;
103
+ return 0;
104
+ }
105
+
106
+ bp = g_new(struct hvf_sw_breakpoint, 1);
107
+ bp->pc = addr;
108
+ bp->use_count = 1;
109
+ err = hvf_arch_insert_sw_breakpoint(cpu, bp);
110
+ if (err) {
111
+ g_free(bp);
112
+ return err;
113
+ }
114
+
115
+ QTAILQ_INSERT_HEAD(&hvf_state->hvf_sw_breakpoints, bp, entry);
116
+ } else {
117
+ err = hvf_arch_insert_hw_breakpoint(addr, len, type);
118
+ if (err) {
119
+ return err;
120
+ }
121
+ }
122
+
123
+ CPU_FOREACH(cpu) {
124
+ err = hvf_update_guest_debug(cpu);
125
+ if (err) {
126
+ return err;
127
+ }
128
+ }
129
+ return 0;
130
+}
131
+
132
+static int hvf_remove_breakpoint(CPUState *cpu, int type, hwaddr addr, hwaddr len)
133
+{
134
+ struct hvf_sw_breakpoint *bp;
135
+ int err;
136
+
137
+ if (type == GDB_BREAKPOINT_SW) {
138
+ bp = hvf_find_sw_breakpoint(cpu, addr);
139
+ if (!bp) {
140
+ return -ENOENT;
141
+ }
142
+
143
+ if (bp->use_count > 1) {
144
+ bp->use_count--;
145
+ return 0;
146
+ }
147
+
148
+ err = hvf_arch_remove_sw_breakpoint(cpu, bp);
149
+ if (err) {
150
+ return err;
151
+ }
152
+
153
+ QTAILQ_REMOVE(&hvf_state->hvf_sw_breakpoints, bp, entry);
154
+ g_free(bp);
155
+ } else {
156
+ err = hvf_arch_remove_hw_breakpoint(addr, len, type);
157
+ if (err) {
158
+ return err;
159
+ }
160
+ }
161
+
162
+ CPU_FOREACH(cpu) {
163
+ err = hvf_update_guest_debug(cpu);
164
+ if (err) {
165
+ return err;
166
+ }
167
+ }
168
+ return 0;
169
+}
170
+
171
+static void hvf_remove_all_breakpoints(CPUState *cpu)
172
+{
173
+ struct hvf_sw_breakpoint *bp, *next;
174
+ CPUState *tmpcpu;
175
+
176
+ QTAILQ_FOREACH_SAFE(bp, &hvf_state->hvf_sw_breakpoints, entry, next) {
177
+ if (hvf_arch_remove_sw_breakpoint(cpu, bp) != 0) {
178
+ /* Try harder to find a CPU that currently sees the breakpoint. */
179
+ CPU_FOREACH(tmpcpu)
180
+ {
181
+ if (hvf_arch_remove_sw_breakpoint(tmpcpu, bp) == 0) {
182
+ break;
183
+ }
184
+ }
185
+ }
186
+ QTAILQ_REMOVE(&hvf_state->hvf_sw_breakpoints, bp, entry);
187
+ g_free(bp);
188
+ }
189
+ hvf_arch_remove_all_hw_breakpoints();
190
+
191
+ CPU_FOREACH(cpu) {
192
+ hvf_update_guest_debug(cpu);
193
+ }
194
+}
195
+
196
static void hvf_accel_ops_class_init(ObjectClass *oc, void *data)
197
{
198
AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
199
@@ -XXX,XX +XXX,XX @@ static void hvf_accel_ops_class_init(ObjectClass *oc, void *data)
200
ops->synchronize_post_init = hvf_cpu_synchronize_post_init;
201
ops->synchronize_state = hvf_cpu_synchronize_state;
202
ops->synchronize_pre_loadvm = hvf_cpu_synchronize_pre_loadvm;
203
+
204
+ ops->insert_breakpoint = hvf_insert_breakpoint;
205
+ ops->remove_breakpoint = hvf_remove_breakpoint;
206
+ ops->remove_all_breakpoints = hvf_remove_all_breakpoints;
207
};
208
static const TypeInfo hvf_accel_ops_type = {
209
.name = ACCEL_OPS_NAME("hvf"),
210
diff --git a/accel/hvf/hvf-all.c b/accel/hvf/hvf-all.c
211
index XXXXXXX..XXXXXXX 100644
212
--- a/accel/hvf/hvf-all.c
213
+++ b/accel/hvf/hvf-all.c
214
@@ -XXX,XX +XXX,XX @@ void assert_hvf_ok(hv_return_t ret)
215
216
abort();
217
}
218
+
219
+struct hvf_sw_breakpoint *hvf_find_sw_breakpoint(CPUState *cpu, target_ulong pc)
220
+{
221
+ struct hvf_sw_breakpoint *bp;
222
+
223
+ QTAILQ_FOREACH(bp, &hvf_state->hvf_sw_breakpoints, entry) {
224
+ if (bp->pc == pc) {
225
+ return bp;
226
+ }
227
+ }
228
+ return NULL;
229
+}
230
+
231
+int hvf_sw_breakpoints_active(CPUState *cpu)
232
+{
233
+ return !QTAILQ_EMPTY(&hvf_state->hvf_sw_breakpoints);
234
+}
235
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
236
index XXXXXXX..XXXXXXX 100644
237
--- a/target/arm/hvf/hvf.c
238
+++ b/target/arm/hvf/hvf.c
239
@@ -XXX,XX +XXX,XX @@
240
#include "trace/trace-target_arm_hvf.h"
241
#include "migration/vmstate.h"
242
243
+#include "exec/gdbstub.h"
244
+
245
#define HVF_SYSREG(crn, crm, op0, op1, op2) \
246
ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, crn, crm, op0, op1, op2)
247
#define PL1_WRITE_MASK 0x4
248
@@ -XXX,XX +XXX,XX @@ int hvf_arch_init(void)
249
qemu_add_vm_change_state_handler(hvf_vm_state_change, &vtimer);
250
return 0;
251
}
252
+
253
+static const uint32_t brk_insn = 0xd4200000;
254
+
255
+int hvf_arch_insert_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint *bp)
256
+{
257
+ if (cpu_memory_rw_debug(cpu, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) ||
258
+ cpu_memory_rw_debug(cpu, bp->pc, (uint8_t *)&brk_insn, 4, 1)) {
259
+ return -EINVAL;
260
+ }
261
+ return 0;
262
+}
263
+
264
+int hvf_arch_remove_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint *bp)
265
+{
266
+ static uint32_t brk;
267
+
268
+ if (cpu_memory_rw_debug(cpu, bp->pc, (uint8_t *)&brk, 4, 0) ||
269
+ brk != brk_insn ||
270
+ cpu_memory_rw_debug(cpu, bp->pc, (uint8_t *)&bp->saved_insn, 4, 1)) {
271
+ return -EINVAL;
272
+ }
273
+ return 0;
274
+}
275
+
276
+int hvf_arch_insert_hw_breakpoint(target_ulong addr, target_ulong len, int type)
277
+{
278
+ switch (type) {
279
+ case GDB_BREAKPOINT_HW:
280
+ return insert_hw_breakpoint(addr);
281
+ case GDB_WATCHPOINT_READ:
282
+ case GDB_WATCHPOINT_WRITE:
283
+ case GDB_WATCHPOINT_ACCESS:
284
+ return insert_hw_watchpoint(addr, len, type);
285
+ default:
286
+ return -ENOSYS;
287
+ }
288
+}
289
+
290
+int hvf_arch_remove_hw_breakpoint(target_ulong addr, target_ulong len, int type)
291
+{
292
+ switch (type) {
293
+ case GDB_BREAKPOINT_HW:
294
+ return delete_hw_breakpoint(addr);
295
+ case GDB_WATCHPOINT_READ:
296
+ case GDB_WATCHPOINT_WRITE:
297
+ case GDB_WATCHPOINT_ACCESS:
298
+ return delete_hw_watchpoint(addr, len, type);
299
+ default:
300
+ return -ENOSYS;
301
+ }
302
+}
303
+
304
+void hvf_arch_remove_all_hw_breakpoints(void)
305
+{
306
+ if (cur_hw_wps > 0) {
307
+ g_array_remove_range(hw_watchpoints, 0, cur_hw_wps);
308
+ }
309
+ if (cur_hw_bps > 0) {
310
+ g_array_remove_range(hw_breakpoints, 0, cur_hw_bps);
311
+ }
312
+}
313
diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c
314
index XXXXXXX..XXXXXXX 100644
315
--- a/target/i386/hvf/hvf.c
316
+++ b/target/i386/hvf/hvf.c
317
@@ -XXX,XX +XXX,XX @@ int hvf_vcpu_exec(CPUState *cpu)
318
319
return ret;
320
}
321
+
322
+int hvf_arch_insert_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint *bp)
323
+{
324
+ return -ENOSYS;
325
+}
326
+
327
+int hvf_arch_remove_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint *bp)
328
+{
329
+ return -ENOSYS;
330
+}
331
+
332
+int hvf_arch_insert_hw_breakpoint(target_ulong addr, target_ulong len, int type)
333
+{
334
+ return -ENOSYS;
335
+}
336
+
337
+int hvf_arch_remove_hw_breakpoint(target_ulong addr, target_ulong len, int type)
338
+{
339
+ return -ENOSYS;
340
+}
341
+
342
+void hvf_arch_remove_all_hw_breakpoints(void)
343
+{
344
+}
345
--
346
2.34.1
diff view generated by jsdifflib
New patch
1
From: Francesco Cagnin <fcagnin@quarkslab.com>
1
2
3
Guests can now be debugged through the gdbstub. Support is added for
4
single-stepping, software breakpoints, hardware breakpoints and
5
watchpoints. The code has been structured like the KVM counterpart.
6
7
While guest debugging is enabled, the guest can still read and write the
8
DBG*_EL1 registers but they don't have any effect.
9
10
Signed-off-by: Francesco Cagnin <fcagnin@quarkslab.com>
11
Message-id: 20230601153107.81955-5-fcagnin@quarkslab.com
12
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
---
15
include/sysemu/hvf.h | 15 ++
16
include/sysemu/hvf_int.h | 1 +
17
target/arm/hvf_arm.h | 7 +
18
accel/hvf/hvf-accel-ops.c | 10 +
19
accel/hvf/hvf-all.c | 6 +
20
target/arm/hvf/hvf.c | 474 +++++++++++++++++++++++++++++++++++++-
21
target/i386/hvf/hvf.c | 9 +
22
7 files changed, 520 insertions(+), 2 deletions(-)
23
24
diff --git a/include/sysemu/hvf.h b/include/sysemu/hvf.h
25
index XXXXXXX..XXXXXXX 100644
26
--- a/include/sysemu/hvf.h
27
+++ b/include/sysemu/hvf.h
28
@@ -XXX,XX +XXX,XX @@ int hvf_arch_insert_hw_breakpoint(target_ulong addr, target_ulong len,
29
int hvf_arch_remove_hw_breakpoint(target_ulong addr, target_ulong len,
30
int type);
31
void hvf_arch_remove_all_hw_breakpoints(void);
32
+
33
+/*
34
+ * hvf_update_guest_debug:
35
+ * @cs: CPUState for the CPU to update
36
+ *
37
+ * Update guest to enable or disable debugging. Per-arch specifics will be
38
+ * handled by calling down to hvf_arch_update_guest_debug.
39
+ */
40
+int hvf_update_guest_debug(CPUState *cpu);
41
+void hvf_arch_update_guest_debug(CPUState *cpu);
42
+
43
+/*
44
+ * Return whether the guest supports debugging.
45
+ */
46
+bool hvf_arch_supports_guest_debug(void);
47
#endif /* NEED_CPU_H */
48
49
#endif
50
diff --git a/include/sysemu/hvf_int.h b/include/sysemu/hvf_int.h
51
index XXXXXXX..XXXXXXX 100644
52
--- a/include/sysemu/hvf_int.h
53
+++ b/include/sysemu/hvf_int.h
54
@@ -XXX,XX +XXX,XX @@ struct hvf_vcpu_state {
55
void *exit;
56
bool vtimer_masked;
57
sigset_t unblock_ipi_mask;
58
+ bool guest_debug_enabled;
59
};
60
61
void assert_hvf_ok(hv_return_t ret);
62
diff --git a/target/arm/hvf_arm.h b/target/arm/hvf_arm.h
63
index XXXXXXX..XXXXXXX 100644
64
--- a/target/arm/hvf_arm.h
65
+++ b/target/arm/hvf_arm.h
66
@@ -XXX,XX +XXX,XX @@
67
68
#include "cpu.h"
69
70
+/**
71
+ * hvf_arm_init_debug() - initialize guest debug capabilities
72
+ *
73
+ * Should be called only once before using guest debug capabilities.
74
+ */
75
+void hvf_arm_init_debug(void);
76
+
77
void hvf_arm_set_cpu_features_from_host(ARMCPU *cpu);
78
79
#endif
80
diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c
81
index XXXXXXX..XXXXXXX 100644
82
--- a/accel/hvf/hvf-accel-ops.c
83
+++ b/accel/hvf/hvf-accel-ops.c
84
@@ -XXX,XX +XXX,XX @@ static int hvf_accel_init(MachineState *ms)
85
return hvf_arch_init();
86
}
87
88
+static inline int hvf_gdbstub_sstep_flags(void)
89
+{
90
+ return SSTEP_ENABLE | SSTEP_NOIRQ;
91
+}
92
+
93
static void hvf_accel_class_init(ObjectClass *oc, void *data)
94
{
95
AccelClass *ac = ACCEL_CLASS(oc);
96
ac->name = "HVF";
97
ac->init_machine = hvf_accel_init;
98
ac->allowed = &hvf_allowed;
99
+ ac->gdbstub_supported_sstep_flags = hvf_gdbstub_sstep_flags;
100
}
101
102
static const TypeInfo hvf_accel_type = {
103
@@ -XXX,XX +XXX,XX @@ static int hvf_init_vcpu(CPUState *cpu)
104
cpu->vcpu_dirty = 1;
105
assert_hvf_ok(r);
106
107
+ cpu->hvf->guest_debug_enabled = false;
108
+
109
return hvf_arch_init_vcpu(cpu);
110
}
111
112
@@ -XXX,XX +XXX,XX @@ static void hvf_accel_ops_class_init(ObjectClass *oc, void *data)
113
ops->insert_breakpoint = hvf_insert_breakpoint;
114
ops->remove_breakpoint = hvf_remove_breakpoint;
115
ops->remove_all_breakpoints = hvf_remove_all_breakpoints;
116
+ ops->update_guest_debug = hvf_update_guest_debug;
117
+ ops->supports_guest_debug = hvf_arch_supports_guest_debug;
118
};
119
static const TypeInfo hvf_accel_ops_type = {
120
.name = ACCEL_OPS_NAME("hvf"),
121
diff --git a/accel/hvf/hvf-all.c b/accel/hvf/hvf-all.c
122
index XXXXXXX..XXXXXXX 100644
123
--- a/accel/hvf/hvf-all.c
124
+++ b/accel/hvf/hvf-all.c
125
@@ -XXX,XX +XXX,XX @@ int hvf_sw_breakpoints_active(CPUState *cpu)
126
{
127
return !QTAILQ_EMPTY(&hvf_state->hvf_sw_breakpoints);
128
}
129
+
130
+int hvf_update_guest_debug(CPUState *cpu)
131
+{
132
+ hvf_arch_update_guest_debug(cpu);
133
+ return 0;
134
+}
135
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
136
index XXXXXXX..XXXXXXX 100644
137
--- a/target/arm/hvf/hvf.c
138
+++ b/target/arm/hvf/hvf.c
139
@@ -XXX,XX +XXX,XX @@
140
141
#include "exec/gdbstub.h"
142
143
+#define MDSCR_EL1_SS_SHIFT 0
144
+#define MDSCR_EL1_MDE_SHIFT 15
145
+
146
+static uint16_t dbgbcr_regs[] = {
147
+ HV_SYS_REG_DBGBCR0_EL1,
148
+ HV_SYS_REG_DBGBCR1_EL1,
149
+ HV_SYS_REG_DBGBCR2_EL1,
150
+ HV_SYS_REG_DBGBCR3_EL1,
151
+ HV_SYS_REG_DBGBCR4_EL1,
152
+ HV_SYS_REG_DBGBCR5_EL1,
153
+ HV_SYS_REG_DBGBCR6_EL1,
154
+ HV_SYS_REG_DBGBCR7_EL1,
155
+ HV_SYS_REG_DBGBCR8_EL1,
156
+ HV_SYS_REG_DBGBCR9_EL1,
157
+ HV_SYS_REG_DBGBCR10_EL1,
158
+ HV_SYS_REG_DBGBCR11_EL1,
159
+ HV_SYS_REG_DBGBCR12_EL1,
160
+ HV_SYS_REG_DBGBCR13_EL1,
161
+ HV_SYS_REG_DBGBCR14_EL1,
162
+ HV_SYS_REG_DBGBCR15_EL1,
163
+};
164
+static uint16_t dbgbvr_regs[] = {
165
+ HV_SYS_REG_DBGBVR0_EL1,
166
+ HV_SYS_REG_DBGBVR1_EL1,
167
+ HV_SYS_REG_DBGBVR2_EL1,
168
+ HV_SYS_REG_DBGBVR3_EL1,
169
+ HV_SYS_REG_DBGBVR4_EL1,
170
+ HV_SYS_REG_DBGBVR5_EL1,
171
+ HV_SYS_REG_DBGBVR6_EL1,
172
+ HV_SYS_REG_DBGBVR7_EL1,
173
+ HV_SYS_REG_DBGBVR8_EL1,
174
+ HV_SYS_REG_DBGBVR9_EL1,
175
+ HV_SYS_REG_DBGBVR10_EL1,
176
+ HV_SYS_REG_DBGBVR11_EL1,
177
+ HV_SYS_REG_DBGBVR12_EL1,
178
+ HV_SYS_REG_DBGBVR13_EL1,
179
+ HV_SYS_REG_DBGBVR14_EL1,
180
+ HV_SYS_REG_DBGBVR15_EL1,
181
+};
182
+static uint16_t dbgwcr_regs[] = {
183
+ HV_SYS_REG_DBGWCR0_EL1,
184
+ HV_SYS_REG_DBGWCR1_EL1,
185
+ HV_SYS_REG_DBGWCR2_EL1,
186
+ HV_SYS_REG_DBGWCR3_EL1,
187
+ HV_SYS_REG_DBGWCR4_EL1,
188
+ HV_SYS_REG_DBGWCR5_EL1,
189
+ HV_SYS_REG_DBGWCR6_EL1,
190
+ HV_SYS_REG_DBGWCR7_EL1,
191
+ HV_SYS_REG_DBGWCR8_EL1,
192
+ HV_SYS_REG_DBGWCR9_EL1,
193
+ HV_SYS_REG_DBGWCR10_EL1,
194
+ HV_SYS_REG_DBGWCR11_EL1,
195
+ HV_SYS_REG_DBGWCR12_EL1,
196
+ HV_SYS_REG_DBGWCR13_EL1,
197
+ HV_SYS_REG_DBGWCR14_EL1,
198
+ HV_SYS_REG_DBGWCR15_EL1,
199
+};
200
+static uint16_t dbgwvr_regs[] = {
201
+ HV_SYS_REG_DBGWVR0_EL1,
202
+ HV_SYS_REG_DBGWVR1_EL1,
203
+ HV_SYS_REG_DBGWVR2_EL1,
204
+ HV_SYS_REG_DBGWVR3_EL1,
205
+ HV_SYS_REG_DBGWVR4_EL1,
206
+ HV_SYS_REG_DBGWVR5_EL1,
207
+ HV_SYS_REG_DBGWVR6_EL1,
208
+ HV_SYS_REG_DBGWVR7_EL1,
209
+ HV_SYS_REG_DBGWVR8_EL1,
210
+ HV_SYS_REG_DBGWVR9_EL1,
211
+ HV_SYS_REG_DBGWVR10_EL1,
212
+ HV_SYS_REG_DBGWVR11_EL1,
213
+ HV_SYS_REG_DBGWVR12_EL1,
214
+ HV_SYS_REG_DBGWVR13_EL1,
215
+ HV_SYS_REG_DBGWVR14_EL1,
216
+ HV_SYS_REG_DBGWVR15_EL1,
217
+};
218
+
219
+static inline int hvf_arm_num_brps(hv_vcpu_config_t config)
220
+{
221
+ uint64_t val;
222
+ hv_return_t ret;
223
+ ret = hv_vcpu_config_get_feature_reg(config, HV_FEATURE_REG_ID_AA64DFR0_EL1,
224
+ &val);
225
+ assert_hvf_ok(ret);
226
+ return FIELD_EX64(val, ID_AA64DFR0, BRPS) + 1;
227
+}
228
+
229
+static inline int hvf_arm_num_wrps(hv_vcpu_config_t config)
230
+{
231
+ uint64_t val;
232
+ hv_return_t ret;
233
+ ret = hv_vcpu_config_get_feature_reg(config, HV_FEATURE_REG_ID_AA64DFR0_EL1,
234
+ &val);
235
+ assert_hvf_ok(ret);
236
+ return FIELD_EX64(val, ID_AA64DFR0, WRPS) + 1;
237
+}
238
+
239
+void hvf_arm_init_debug(void)
240
+{
241
+ hv_vcpu_config_t config;
242
+ config = hv_vcpu_config_create();
243
+
244
+ max_hw_bps = hvf_arm_num_brps(config);
245
+ hw_breakpoints =
246
+ g_array_sized_new(true, true, sizeof(HWBreakpoint), max_hw_bps);
247
+
248
+ max_hw_wps = hvf_arm_num_wrps(config);
249
+ hw_watchpoints =
250
+ g_array_sized_new(true, true, sizeof(HWWatchpoint), max_hw_wps);
251
+}
252
+
253
#define HVF_SYSREG(crn, crm, op0, op1, op2) \
254
ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, crn, crm, op0, op1, op2)
255
#define PL1_WRITE_MASK 0x4
256
@@ -XXX,XX +XXX,XX @@ int hvf_get_registers(CPUState *cpu)
257
continue;
258
}
259
260
+ if (cpu->hvf->guest_debug_enabled) {
261
+ /* Handle debug registers */
262
+ switch (hvf_sreg_match[i].reg) {
263
+ case HV_SYS_REG_DBGBVR0_EL1:
264
+ case HV_SYS_REG_DBGBCR0_EL1:
265
+ case HV_SYS_REG_DBGWVR0_EL1:
266
+ case HV_SYS_REG_DBGWCR0_EL1:
267
+ case HV_SYS_REG_DBGBVR1_EL1:
268
+ case HV_SYS_REG_DBGBCR1_EL1:
269
+ case HV_SYS_REG_DBGWVR1_EL1:
270
+ case HV_SYS_REG_DBGWCR1_EL1:
271
+ case HV_SYS_REG_DBGBVR2_EL1:
272
+ case HV_SYS_REG_DBGBCR2_EL1:
273
+ case HV_SYS_REG_DBGWVR2_EL1:
274
+ case HV_SYS_REG_DBGWCR2_EL1:
275
+ case HV_SYS_REG_DBGBVR3_EL1:
276
+ case HV_SYS_REG_DBGBCR3_EL1:
277
+ case HV_SYS_REG_DBGWVR3_EL1:
278
+ case HV_SYS_REG_DBGWCR3_EL1:
279
+ case HV_SYS_REG_DBGBVR4_EL1:
280
+ case HV_SYS_REG_DBGBCR4_EL1:
281
+ case HV_SYS_REG_DBGWVR4_EL1:
282
+ case HV_SYS_REG_DBGWCR4_EL1:
283
+ case HV_SYS_REG_DBGBVR5_EL1:
284
+ case HV_SYS_REG_DBGBCR5_EL1:
285
+ case HV_SYS_REG_DBGWVR5_EL1:
286
+ case HV_SYS_REG_DBGWCR5_EL1:
287
+ case HV_SYS_REG_DBGBVR6_EL1:
288
+ case HV_SYS_REG_DBGBCR6_EL1:
289
+ case HV_SYS_REG_DBGWVR6_EL1:
290
+ case HV_SYS_REG_DBGWCR6_EL1:
291
+ case HV_SYS_REG_DBGBVR7_EL1:
292
+ case HV_SYS_REG_DBGBCR7_EL1:
293
+ case HV_SYS_REG_DBGWVR7_EL1:
294
+ case HV_SYS_REG_DBGWCR7_EL1:
295
+ case HV_SYS_REG_DBGBVR8_EL1:
296
+ case HV_SYS_REG_DBGBCR8_EL1:
297
+ case HV_SYS_REG_DBGWVR8_EL1:
298
+ case HV_SYS_REG_DBGWCR8_EL1:
299
+ case HV_SYS_REG_DBGBVR9_EL1:
300
+ case HV_SYS_REG_DBGBCR9_EL1:
301
+ case HV_SYS_REG_DBGWVR9_EL1:
302
+ case HV_SYS_REG_DBGWCR9_EL1:
303
+ case HV_SYS_REG_DBGBVR10_EL1:
304
+ case HV_SYS_REG_DBGBCR10_EL1:
305
+ case HV_SYS_REG_DBGWVR10_EL1:
306
+ case HV_SYS_REG_DBGWCR10_EL1:
307
+ case HV_SYS_REG_DBGBVR11_EL1:
308
+ case HV_SYS_REG_DBGBCR11_EL1:
309
+ case HV_SYS_REG_DBGWVR11_EL1:
310
+ case HV_SYS_REG_DBGWCR11_EL1:
311
+ case HV_SYS_REG_DBGBVR12_EL1:
312
+ case HV_SYS_REG_DBGBCR12_EL1:
313
+ case HV_SYS_REG_DBGWVR12_EL1:
314
+ case HV_SYS_REG_DBGWCR12_EL1:
315
+ case HV_SYS_REG_DBGBVR13_EL1:
316
+ case HV_SYS_REG_DBGBCR13_EL1:
317
+ case HV_SYS_REG_DBGWVR13_EL1:
318
+ case HV_SYS_REG_DBGWCR13_EL1:
319
+ case HV_SYS_REG_DBGBVR14_EL1:
320
+ case HV_SYS_REG_DBGBCR14_EL1:
321
+ case HV_SYS_REG_DBGWVR14_EL1:
322
+ case HV_SYS_REG_DBGWCR14_EL1:
323
+ case HV_SYS_REG_DBGBVR15_EL1:
324
+ case HV_SYS_REG_DBGBCR15_EL1:
325
+ case HV_SYS_REG_DBGWVR15_EL1:
326
+ case HV_SYS_REG_DBGWCR15_EL1: {
327
+ /*
328
+ * If the guest is being debugged, the vCPU's debug registers
329
+ * are holding the gdbstub's view of the registers (set in
330
+ * hvf_arch_update_guest_debug()).
331
+ * Since the environment is used to store only the guest's view
332
+ * of the registers, don't update it with the values from the
333
+ * vCPU but simply keep the values from the previous
334
+ * environment.
335
+ */
336
+ const ARMCPRegInfo *ri;
337
+ ri = get_arm_cp_reginfo(arm_cpu->cp_regs, hvf_sreg_match[i].key);
338
+ val = read_raw_cp_reg(env, ri);
339
+
340
+ arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx] = val;
341
+ continue;
342
+ }
343
+ }
344
+ }
345
+
346
ret = hv_vcpu_get_sys_reg(cpu->hvf->fd, hvf_sreg_match[i].reg, &val);
347
assert_hvf_ok(ret);
348
349
@@ -XXX,XX +XXX,XX @@ int hvf_put_registers(CPUState *cpu)
350
continue;
351
}
352
353
+ if (cpu->hvf->guest_debug_enabled) {
354
+ /* Handle debug registers */
355
+ switch (hvf_sreg_match[i].reg) {
356
+ case HV_SYS_REG_DBGBVR0_EL1:
357
+ case HV_SYS_REG_DBGBCR0_EL1:
358
+ case HV_SYS_REG_DBGWVR0_EL1:
359
+ case HV_SYS_REG_DBGWCR0_EL1:
360
+ case HV_SYS_REG_DBGBVR1_EL1:
361
+ case HV_SYS_REG_DBGBCR1_EL1:
362
+ case HV_SYS_REG_DBGWVR1_EL1:
363
+ case HV_SYS_REG_DBGWCR1_EL1:
364
+ case HV_SYS_REG_DBGBVR2_EL1:
365
+ case HV_SYS_REG_DBGBCR2_EL1:
366
+ case HV_SYS_REG_DBGWVR2_EL1:
367
+ case HV_SYS_REG_DBGWCR2_EL1:
368
+ case HV_SYS_REG_DBGBVR3_EL1:
369
+ case HV_SYS_REG_DBGBCR3_EL1:
370
+ case HV_SYS_REG_DBGWVR3_EL1:
371
+ case HV_SYS_REG_DBGWCR3_EL1:
372
+ case HV_SYS_REG_DBGBVR4_EL1:
373
+ case HV_SYS_REG_DBGBCR4_EL1:
374
+ case HV_SYS_REG_DBGWVR4_EL1:
375
+ case HV_SYS_REG_DBGWCR4_EL1:
376
+ case HV_SYS_REG_DBGBVR5_EL1:
377
+ case HV_SYS_REG_DBGBCR5_EL1:
378
+ case HV_SYS_REG_DBGWVR5_EL1:
379
+ case HV_SYS_REG_DBGWCR5_EL1:
380
+ case HV_SYS_REG_DBGBVR6_EL1:
381
+ case HV_SYS_REG_DBGBCR6_EL1:
382
+ case HV_SYS_REG_DBGWVR6_EL1:
383
+ case HV_SYS_REG_DBGWCR6_EL1:
384
+ case HV_SYS_REG_DBGBVR7_EL1:
385
+ case HV_SYS_REG_DBGBCR7_EL1:
386
+ case HV_SYS_REG_DBGWVR7_EL1:
387
+ case HV_SYS_REG_DBGWCR7_EL1:
388
+ case HV_SYS_REG_DBGBVR8_EL1:
389
+ case HV_SYS_REG_DBGBCR8_EL1:
390
+ case HV_SYS_REG_DBGWVR8_EL1:
391
+ case HV_SYS_REG_DBGWCR8_EL1:
392
+ case HV_SYS_REG_DBGBVR9_EL1:
393
+ case HV_SYS_REG_DBGBCR9_EL1:
394
+ case HV_SYS_REG_DBGWVR9_EL1:
395
+ case HV_SYS_REG_DBGWCR9_EL1:
396
+ case HV_SYS_REG_DBGBVR10_EL1:
397
+ case HV_SYS_REG_DBGBCR10_EL1:
398
+ case HV_SYS_REG_DBGWVR10_EL1:
399
+ case HV_SYS_REG_DBGWCR10_EL1:
400
+ case HV_SYS_REG_DBGBVR11_EL1:
401
+ case HV_SYS_REG_DBGBCR11_EL1:
402
+ case HV_SYS_REG_DBGWVR11_EL1:
403
+ case HV_SYS_REG_DBGWCR11_EL1:
404
+ case HV_SYS_REG_DBGBVR12_EL1:
405
+ case HV_SYS_REG_DBGBCR12_EL1:
406
+ case HV_SYS_REG_DBGWVR12_EL1:
407
+ case HV_SYS_REG_DBGWCR12_EL1:
408
+ case HV_SYS_REG_DBGBVR13_EL1:
409
+ case HV_SYS_REG_DBGBCR13_EL1:
410
+ case HV_SYS_REG_DBGWVR13_EL1:
411
+ case HV_SYS_REG_DBGWCR13_EL1:
412
+ case HV_SYS_REG_DBGBVR14_EL1:
413
+ case HV_SYS_REG_DBGBCR14_EL1:
414
+ case HV_SYS_REG_DBGWVR14_EL1:
415
+ case HV_SYS_REG_DBGWCR14_EL1:
416
+ case HV_SYS_REG_DBGBVR15_EL1:
417
+ case HV_SYS_REG_DBGBCR15_EL1:
418
+ case HV_SYS_REG_DBGWVR15_EL1:
419
+ case HV_SYS_REG_DBGWCR15_EL1:
420
+ /*
421
+ * If the guest is being debugged, the vCPU's debug registers
422
+ * are already holding the gdbstub's view of the registers (set
423
+ * in hvf_arch_update_guest_debug()).
424
+ */
425
+ continue;
426
+ }
427
+ }
428
+
429
val = arm_cpu->cpreg_values[hvf_sreg_match[i].cp_idx];
430
ret = hv_vcpu_set_sys_reg(cpu->hvf->fd, hvf_sreg_match[i].reg, val);
431
assert_hvf_ok(ret);
432
@@ -XXX,XX +XXX,XX @@ int hvf_vcpu_exec(CPUState *cpu)
433
{
434
ARMCPU *arm_cpu = ARM_CPU(cpu);
435
CPUARMState *env = &arm_cpu->env;
436
+ int ret;
437
hv_vcpu_exit_t *hvf_exit = cpu->hvf->exit;
438
hv_return_t r;
439
bool advance_pc = false;
440
441
- if (hvf_inject_interrupts(cpu)) {
442
+ if (!(cpu->singlestep_enabled & SSTEP_NOIRQ) &&
443
+ hvf_inject_interrupts(cpu)) {
444
return EXCP_INTERRUPT;
445
}
446
447
@@ -XXX,XX +XXX,XX @@ int hvf_vcpu_exec(CPUState *cpu)
448
uint64_t syndrome = hvf_exit->exception.syndrome;
449
uint32_t ec = syn_get_ec(syndrome);
450
451
+ ret = 0;
452
qemu_mutex_lock_iothread();
453
switch (exit_reason) {
454
case HV_EXIT_REASON_EXCEPTION:
455
@@ -XXX,XX +XXX,XX @@ int hvf_vcpu_exec(CPUState *cpu)
456
hvf_sync_vtimer(cpu);
457
458
switch (ec) {
459
+ case EC_SOFTWARESTEP: {
460
+ ret = EXCP_DEBUG;
461
+
462
+ if (!cpu->singlestep_enabled) {
463
+ error_report("EC_SOFTWARESTEP but single-stepping not enabled");
464
+ }
465
+ break;
466
+ }
467
+ case EC_AA64_BKPT: {
468
+ ret = EXCP_DEBUG;
469
+
470
+ cpu_synchronize_state(cpu);
471
+
472
+ if (!hvf_find_sw_breakpoint(cpu, env->pc)) {
473
+ /* Re-inject into the guest */
474
+ ret = 0;
475
+ hvf_raise_exception(cpu, EXCP_BKPT, syn_aa64_bkpt(0));
476
+ }
477
+ break;
478
+ }
479
+ case EC_BREAKPOINT: {
480
+ ret = EXCP_DEBUG;
481
+
482
+ cpu_synchronize_state(cpu);
483
+
484
+ if (!find_hw_breakpoint(cpu, env->pc)) {
485
+ error_report("EC_BREAKPOINT but unknown hw breakpoint");
486
+ }
487
+ break;
488
+ }
489
+ case EC_WATCHPOINT: {
490
+ ret = EXCP_DEBUG;
491
+
492
+ cpu_synchronize_state(cpu);
493
+
494
+ CPUWatchpoint *wp =
495
+ find_hw_watchpoint(cpu, hvf_exit->exception.virtual_address);
496
+ if (!wp) {
497
+ error_report("EXCP_DEBUG but unknown hw watchpoint");
498
+ }
499
+ cpu->watchpoint_hit = wp;
500
+ break;
501
+ }
502
case EC_DATAABORT: {
503
bool isv = syndrome & ARM_EL_ISV;
504
bool iswrite = (syndrome >> 6) & 1;
505
@@ -XXX,XX +XXX,XX @@ int hvf_vcpu_exec(CPUState *cpu)
506
pc += 4;
507
r = hv_vcpu_set_reg(cpu->hvf->fd, HV_REG_PC, pc);
508
assert_hvf_ok(r);
509
+
510
+ /* Handle single-stepping over instructions which trigger a VM exit */
511
+ if (cpu->singlestep_enabled) {
512
+ ret = EXCP_DEBUG;
513
+ }
514
}
515
516
- return 0;
517
+ return ret;
518
}
519
520
static const VMStateDescription vmstate_hvf_vtimer = {
521
@@ -XXX,XX +XXX,XX @@ int hvf_arch_init(void)
522
hvf_state->vtimer_offset = mach_absolute_time();
523
vmstate_register(NULL, 0, &vmstate_hvf_vtimer, &vtimer);
524
qemu_add_vm_change_state_handler(hvf_vm_state_change, &vtimer);
525
+
526
+ hvf_arm_init_debug();
527
+
528
return 0;
529
}
530
531
@@ -XXX,XX +XXX,XX @@ void hvf_arch_remove_all_hw_breakpoints(void)
532
g_array_remove_range(hw_breakpoints, 0, cur_hw_bps);
533
}
534
}
535
+
536
+/*
537
+ * Update the vCPU with the gdbstub's view of debug registers. This view
538
+ * consists of all hardware breakpoints and watchpoints inserted so far while
539
+ * debugging the guest.
540
+ */
541
+static void hvf_put_gdbstub_debug_registers(CPUState *cpu)
542
+{
543
+ hv_return_t r = HV_SUCCESS;
544
+ int i;
545
+
546
+ for (i = 0; i < cur_hw_bps; i++) {
547
+ HWBreakpoint *bp = get_hw_bp(i);
548
+ r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgbcr_regs[i], bp->bcr);
549
+ assert_hvf_ok(r);
550
+ r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgbvr_regs[i], bp->bvr);
551
+ assert_hvf_ok(r);
552
+ }
553
+ for (i = cur_hw_bps; i < max_hw_bps; i++) {
554
+ r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgbcr_regs[i], 0);
555
+ assert_hvf_ok(r);
556
+ r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgbvr_regs[i], 0);
557
+ assert_hvf_ok(r);
558
+ }
559
+
560
+ for (i = 0; i < cur_hw_wps; i++) {
561
+ HWWatchpoint *wp = get_hw_wp(i);
562
+ r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgwcr_regs[i], wp->wcr);
563
+ assert_hvf_ok(r);
564
+ r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgwvr_regs[i], wp->wvr);
565
+ assert_hvf_ok(r);
566
+ }
567
+ for (i = cur_hw_wps; i < max_hw_wps; i++) {
568
+ r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgwcr_regs[i], 0);
569
+ assert_hvf_ok(r);
570
+ r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgwvr_regs[i], 0);
571
+ assert_hvf_ok(r);
572
+ }
573
+}
574
+
575
+/*
576
+ * Update the vCPU with the guest's view of debug registers. This view is kept
577
+ * in the environment at all times.
578
+ */
579
+static void hvf_put_guest_debug_registers(CPUState *cpu)
580
+{
581
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
582
+ CPUARMState *env = &arm_cpu->env;
583
+ hv_return_t r = HV_SUCCESS;
584
+ int i;
585
+
586
+ for (i = 0; i < max_hw_bps; i++) {
587
+ r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgbcr_regs[i],
588
+ env->cp15.dbgbcr[i]);
589
+ assert_hvf_ok(r);
590
+ r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgbvr_regs[i],
591
+ env->cp15.dbgbvr[i]);
592
+ assert_hvf_ok(r);
593
+ }
594
+
595
+ for (i = 0; i < max_hw_wps; i++) {
596
+ r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgwcr_regs[i],
597
+ env->cp15.dbgwcr[i]);
598
+ assert_hvf_ok(r);
599
+ r = hv_vcpu_set_sys_reg(cpu->hvf->fd, dbgwvr_regs[i],
600
+ env->cp15.dbgwvr[i]);
601
+ assert_hvf_ok(r);
602
+ }
603
+}
604
+
605
+static inline bool hvf_arm_hw_debug_active(CPUState *cpu)
606
+{
607
+ return ((cur_hw_wps > 0) || (cur_hw_bps > 0));
608
+}
609
+
610
+static void hvf_arch_set_traps(void)
611
+{
612
+ CPUState *cpu;
613
+ bool should_enable_traps = false;
614
+ hv_return_t r = HV_SUCCESS;
615
+
616
+ /* Check whether guest debugging is enabled for at least one vCPU; if it
617
+ * is, enable exiting the guest on all vCPUs */
618
+ CPU_FOREACH(cpu) {
619
+ should_enable_traps |= cpu->hvf->guest_debug_enabled;
620
+ }
621
+ CPU_FOREACH(cpu) {
622
+ /* Set whether debug exceptions exit the guest */
623
+ r = hv_vcpu_set_trap_debug_exceptions(cpu->hvf->fd,
624
+ should_enable_traps);
625
+ assert_hvf_ok(r);
626
+
627
+ /* Set whether accesses to debug registers exit the guest */
628
+ r = hv_vcpu_set_trap_debug_reg_accesses(cpu->hvf->fd,
629
+ should_enable_traps);
630
+ assert_hvf_ok(r);
631
+ }
632
+}
633
+
634
+void hvf_arch_update_guest_debug(CPUState *cpu)
635
+{
636
+ ARMCPU *arm_cpu = ARM_CPU(cpu);
637
+ CPUARMState *env = &arm_cpu->env;
638
+
639
+ /* Check whether guest debugging is enabled */
640
+ cpu->hvf->guest_debug_enabled = cpu->singlestep_enabled ||
641
+ hvf_sw_breakpoints_active(cpu) ||
642
+ hvf_arm_hw_debug_active(cpu);
643
+
644
+ /* Update debug registers */
645
+ if (cpu->hvf->guest_debug_enabled) {
646
+ hvf_put_gdbstub_debug_registers(cpu);
647
+ } else {
648
+ hvf_put_guest_debug_registers(cpu);
649
+ }
650
+
651
+ cpu_synchronize_state(cpu);
652
+
653
+ /* Enable/disable single-stepping */
654
+ if (cpu->singlestep_enabled) {
655
+ env->cp15.mdscr_el1 =
656
+ deposit64(env->cp15.mdscr_el1, MDSCR_EL1_SS_SHIFT, 1, 1);
657
+ pstate_write(env, pstate_read(env) | PSTATE_SS);
658
+ } else {
659
+ env->cp15.mdscr_el1 =
660
+ deposit64(env->cp15.mdscr_el1, MDSCR_EL1_SS_SHIFT, 1, 0);
661
+ }
662
+
663
+ /* Enable/disable Breakpoint exceptions */
664
+ if (hvf_arm_hw_debug_active(cpu)) {
665
+ env->cp15.mdscr_el1 =
666
+ deposit64(env->cp15.mdscr_el1, MDSCR_EL1_MDE_SHIFT, 1, 1);
667
+ } else {
668
+ env->cp15.mdscr_el1 =
669
+ deposit64(env->cp15.mdscr_el1, MDSCR_EL1_MDE_SHIFT, 1, 0);
670
+ }
671
+
672
+ hvf_arch_set_traps();
673
+}
674
+
675
+inline bool hvf_arch_supports_guest_debug(void)
676
+{
677
+ return true;
678
+}
679
diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c
680
index XXXXXXX..XXXXXXX 100644
681
--- a/target/i386/hvf/hvf.c
682
+++ b/target/i386/hvf/hvf.c
683
@@ -XXX,XX +XXX,XX @@ int hvf_arch_remove_hw_breakpoint(target_ulong addr, target_ulong len, int type)
684
void hvf_arch_remove_all_hw_breakpoints(void)
685
{
686
}
687
+
688
+void hvf_arch_update_guest_debug(CPUState *cpu)
689
+{
690
+}
691
+
692
+inline bool hvf_arch_supports_guest_debug(void)
693
+{
694
+ return false;
695
+}
696
--
697
2.34.1
diff view generated by jsdifflib
1
From: Leif Lindholm <leif@nuviainc.com>
1
From: Vikram Garhwal <vikram.garhwal@amd.com>
2
2
3
Add entries present in ARM DDI 0487F.c (August 2020).
3
The Xilinx Versal CANFD controller is developed based on SocketCAN, QEMU CAN bus
4
implementation. Bus connection and socketCAN connection for each CAN module
5
can be set through command lines.
4
6
5
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
7
Signed-off-by: Vikram Garhwal <vikram.garhwal@amd.com>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Francisco Iglesias <frasse.iglesias@gmail.com>
7
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
8
Message-id: 20210108185154.8108-6-leif@nuviainc.com
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
10
---
11
target/arm/cpu.h | 15 +++++++++++++++
11
include/hw/net/xlnx-versal-canfd.h | 87 ++
12
1 file changed, 15 insertions(+)
12
hw/net/can/xlnx-versal-canfd.c | 2107 ++++++++++++++++++++++++++++
13
hw/net/can/meson.build | 1 +
14
hw/net/can/trace-events | 7 +
15
4 files changed, 2202 insertions(+)
16
create mode 100644 include/hw/net/xlnx-versal-canfd.h
17
create mode 100644 hw/net/can/xlnx-versal-canfd.c
13
18
14
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
19
diff --git a/include/hw/net/xlnx-versal-canfd.h b/include/hw/net/xlnx-versal-canfd.h
20
new file mode 100644
21
index XXXXXXX..XXXXXXX
22
--- /dev/null
23
+++ b/include/hw/net/xlnx-versal-canfd.h
24
@@ -XXX,XX +XXX,XX @@
25
+/*
26
+ * QEMU model of the Xilinx Versal CANFD Controller.
27
+ *
28
+ * Copyright (c) 2023 Advanced Micro Devices, Inc.
29
+ *
30
+ * Written-by: Vikram Garhwal<vikram.garhwal@amd.com>
31
+ * Based on QEMU CANFD Device emulation implemented by Jin Yang, Deniz Eren and
32
+ * Pavel Pisa.
33
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
34
+ * of this software and associated documentation files (the "Software"), to deal
35
+ * in the Software without restriction, including without limitation the rights
36
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
37
+ * copies of the Software, and to permit persons to whom the Software is
38
+ * furnished to do so, subject to the following conditions:
39
+ *
40
+ * The above copyright notice and this permission notice shall be included in
41
+ * all copies or substantial portions of the Software.
42
+ *
43
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
44
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
45
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
46
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
47
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
48
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
49
+ * THE SOFTWARE.
50
+ */
51
+
52
+#ifndef HW_CANFD_XILINX_H
53
+#define HW_CANFD_XILINX_H
54
+
55
+#include "hw/register.h"
56
+#include "hw/ptimer.h"
57
+#include "net/can_emu.h"
58
+#include "hw/qdev-clock.h"
59
+
60
+#define TYPE_XILINX_CANFD "xlnx.versal-canfd"
61
+
62
+OBJECT_DECLARE_SIMPLE_TYPE(XlnxVersalCANFDState, XILINX_CANFD)
63
+
64
+#define NUM_REGS_PER_MSG_SPACE 18 /* 1 ID + 1 DLC + 16 Data(DW0 - DW15) regs. */
65
+#define MAX_NUM_RX 64
66
+#define OFFSET_RX1_DW15 (0x4144 / 4)
67
+#define CANFD_TIMER_MAX 0xFFFFUL
68
+#define CANFD_DEFAULT_CLOCK (25 * 1000 * 1000)
69
+
70
+#define XLNX_VERSAL_CANFD_R_MAX (OFFSET_RX1_DW15 + \
71
+ ((MAX_NUM_RX - 1) * NUM_REGS_PER_MSG_SPACE) + 1)
72
+
73
+typedef struct XlnxVersalCANFDState {
74
+ SysBusDevice parent_obj;
75
+ MemoryRegion iomem;
76
+
77
+ qemu_irq irq_canfd_int;
78
+ qemu_irq irq_addr_err;
79
+
80
+ RegisterInfo reg_info[XLNX_VERSAL_CANFD_R_MAX];
81
+ RegisterAccessInfo *tx_regs;
82
+ RegisterAccessInfo *rx0_regs;
83
+ RegisterAccessInfo *rx1_regs;
84
+ RegisterAccessInfo *af_regs;
85
+ RegisterAccessInfo *txe_regs;
86
+ RegisterAccessInfo *rx_mailbox_regs;
87
+ RegisterAccessInfo *af_mask_regs_mailbox;
88
+
89
+ uint32_t regs[XLNX_VERSAL_CANFD_R_MAX];
90
+
91
+ ptimer_state *canfd_timer;
92
+
93
+ CanBusClientState bus_client;
94
+ CanBusState *canfdbus;
95
+
96
+ struct {
97
+ uint8_t rx0_fifo;
98
+ uint8_t rx1_fifo;
99
+ uint8_t tx_fifo;
100
+ bool enable_rx_fifo1;
101
+ uint32_t ext_clk_freq;
102
+ } cfg;
103
+
104
+} XlnxVersalCANFDState;
105
+
106
+typedef struct tx_ready_reg_info {
107
+ uint32_t can_id;
108
+ uint32_t reg_num;
109
+} tx_ready_reg_info;
110
+
111
+#endif
112
diff --git a/hw/net/can/xlnx-versal-canfd.c b/hw/net/can/xlnx-versal-canfd.c
113
new file mode 100644
114
index XXXXXXX..XXXXXXX
115
--- /dev/null
116
+++ b/hw/net/can/xlnx-versal-canfd.c
117
@@ -XXX,XX +XXX,XX @@
118
+/*
119
+ * QEMU model of the Xilinx Versal CANFD device.
120
+ *
121
+ * This implementation is based on the following datasheet:
122
+ * https://docs.xilinx.com/v/u/2.0-English/pg223-canfd
123
+ *
124
+ * Copyright (c) 2023 Advanced Micro Devices, Inc.
125
+ *
126
+ * Written-by: Vikram Garhwal <vikram.garhwal@amd.com>
127
+ *
128
+ * Based on QEMU CANFD Device emulation implemented by Jin Yang, Deniz Eren and
129
+ * Pavel Pisa
130
+ *
131
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
132
+ * of this software and associated documentation files (the "Software"), to deal
133
+ * in the Software without restriction, including without limitation the rights
134
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
135
+ * copies of the Software, and to permit persons to whom the Software is
136
+ * furnished to do so, subject to the following conditions:
137
+ *
138
+ * The above copyright notice and this permission notice shall be included in
139
+ * all copies or substantial portions of the Software.
140
+ *
141
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
142
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
143
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
144
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
145
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
146
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
147
+ * THE SOFTWARE.
148
+ */
149
+
150
+#include "qemu/osdep.h"
151
+#include "hw/sysbus.h"
152
+#include "hw/irq.h"
153
+#include "hw/register.h"
154
+#include "qapi/error.h"
155
+#include "qemu/bitops.h"
156
+#include "qemu/log.h"
157
+#include "qemu/cutils.h"
158
+#include "qemu/event_notifier.h"
159
+#include "hw/qdev-properties.h"
160
+#include "qom/object_interfaces.h"
161
+#include "migration/vmstate.h"
162
+#include "hw/net/xlnx-versal-canfd.h"
163
+#include "trace.h"
164
+
165
+REG32(SOFTWARE_RESET_REGISTER, 0x0)
166
+ FIELD(SOFTWARE_RESET_REGISTER, CEN, 1, 1)
167
+ FIELD(SOFTWARE_RESET_REGISTER, SRST, 0, 1)
168
+REG32(MODE_SELECT_REGISTER, 0x4)
169
+ FIELD(MODE_SELECT_REGISTER, ITO, 8, 8)
170
+ FIELD(MODE_SELECT_REGISTER, ABR, 7, 1)
171
+ FIELD(MODE_SELECT_REGISTER, SBR, 6, 1)
172
+ FIELD(MODE_SELECT_REGISTER, DPEE, 5, 1)
173
+ FIELD(MODE_SELECT_REGISTER, DAR, 4, 1)
174
+ FIELD(MODE_SELECT_REGISTER, BRSD, 3, 1)
175
+ FIELD(MODE_SELECT_REGISTER, SNOOP, 2, 1)
176
+ FIELD(MODE_SELECT_REGISTER, LBACK, 1, 1)
177
+ FIELD(MODE_SELECT_REGISTER, SLEEP, 0, 1)
178
+REG32(ARBITRATION_PHASE_BAUD_RATE_PRESCALER_REGISTER, 0x8)
179
+ FIELD(ARBITRATION_PHASE_BAUD_RATE_PRESCALER_REGISTER, BRP, 0, 8)
180
+REG32(ARBITRATION_PHASE_BIT_TIMING_REGISTER, 0xc)
181
+ FIELD(ARBITRATION_PHASE_BIT_TIMING_REGISTER, SJW, 16, 7)
182
+ FIELD(ARBITRATION_PHASE_BIT_TIMING_REGISTER, TS2, 8, 7)
183
+ FIELD(ARBITRATION_PHASE_BIT_TIMING_REGISTER, TS1, 0, 8)
184
+REG32(ERROR_COUNTER_REGISTER, 0x10)
185
+ FIELD(ERROR_COUNTER_REGISTER, REC, 8, 8)
186
+ FIELD(ERROR_COUNTER_REGISTER, TEC, 0, 8)
187
+REG32(ERROR_STATUS_REGISTER, 0x14)
188
+ FIELD(ERROR_STATUS_REGISTER, F_BERR, 11, 1)
189
+ FIELD(ERROR_STATUS_REGISTER, F_STER, 10, 1)
190
+ FIELD(ERROR_STATUS_REGISTER, F_FMER, 9, 1)
191
+ FIELD(ERROR_STATUS_REGISTER, F_CRCER, 8, 1)
192
+ FIELD(ERROR_STATUS_REGISTER, ACKER, 4, 1)
193
+ FIELD(ERROR_STATUS_REGISTER, BERR, 3, 1)
194
+ FIELD(ERROR_STATUS_REGISTER, STER, 2, 1)
195
+ FIELD(ERROR_STATUS_REGISTER, FMER, 1, 1)
196
+ FIELD(ERROR_STATUS_REGISTER, CRCER, 0, 1)
197
+REG32(STATUS_REGISTER, 0x18)
198
+ FIELD(STATUS_REGISTER, TDCV, 16, 7)
199
+ FIELD(STATUS_REGISTER, SNOOP, 12, 1)
200
+ FIELD(STATUS_REGISTER, BSFR_CONFIG, 10, 1)
201
+ FIELD(STATUS_REGISTER, PEE_CONFIG, 9, 1)
202
+ FIELD(STATUS_REGISTER, ESTAT, 7, 2)
203
+ FIELD(STATUS_REGISTER, ERRWRN, 6, 1)
204
+ FIELD(STATUS_REGISTER, BBSY, 5, 1)
205
+ FIELD(STATUS_REGISTER, BIDLE, 4, 1)
206
+ FIELD(STATUS_REGISTER, NORMAL, 3, 1)
207
+ FIELD(STATUS_REGISTER, SLEEP, 2, 1)
208
+ FIELD(STATUS_REGISTER, LBACK, 1, 1)
209
+ FIELD(STATUS_REGISTER, CONFIG, 0, 1)
210
+REG32(INTERRUPT_STATUS_REGISTER, 0x1c)
211
+ FIELD(INTERRUPT_STATUS_REGISTER, TXEWMFLL, 31, 1)
212
+ FIELD(INTERRUPT_STATUS_REGISTER, TXEOFLW, 30, 1)
213
+ FIELD(INTERRUPT_STATUS_REGISTER, RXBOFLW_BI, 24, 6)
214
+ FIELD(INTERRUPT_STATUS_REGISTER, RXLRM_BI, 18, 6)
215
+ FIELD(INTERRUPT_STATUS_REGISTER, RXMNF, 17, 1)
216
+ FIELD(INTERRUPT_STATUS_REGISTER, RXFWMFLL_1, 16, 1)
217
+ FIELD(INTERRUPT_STATUS_REGISTER, RXFOFLW_1, 15, 1)
218
+ FIELD(INTERRUPT_STATUS_REGISTER, TXCRS, 14, 1)
219
+ FIELD(INTERRUPT_STATUS_REGISTER, TXRRS, 13, 1)
220
+ FIELD(INTERRUPT_STATUS_REGISTER, RXFWMFLL, 12, 1)
221
+ FIELD(INTERRUPT_STATUS_REGISTER, WKUP, 11, 1)
222
+ FIELD(INTERRUPT_STATUS_REGISTER, SLP, 10, 1)
223
+ FIELD(INTERRUPT_STATUS_REGISTER, BSOFF, 9, 1)
224
+ /*
225
+ * In the original HW description below bit is named as ERROR but an ERROR
226
+ * field name collides with a macro in Windows build. To avoid Windows build
227
+ * failures, the bit is renamed to ERROR_BIT.
228
+ */
229
+ FIELD(INTERRUPT_STATUS_REGISTER, ERROR_BIT, 8, 1)
230
+ FIELD(INTERRUPT_STATUS_REGISTER, RXFOFLW, 6, 1)
231
+ FIELD(INTERRUPT_STATUS_REGISTER, TSCNT_OFLW, 5, 1)
232
+ FIELD(INTERRUPT_STATUS_REGISTER, RXOK, 4, 1)
233
+ FIELD(INTERRUPT_STATUS_REGISTER, BSFRD, 3, 1)
234
+ FIELD(INTERRUPT_STATUS_REGISTER, PEE, 2, 1)
235
+ FIELD(INTERRUPT_STATUS_REGISTER, TXOK, 1, 1)
236
+ FIELD(INTERRUPT_STATUS_REGISTER, ARBLST, 0, 1)
237
+REG32(INTERRUPT_ENABLE_REGISTER, 0x20)
238
+ FIELD(INTERRUPT_ENABLE_REGISTER, ETXEWMFLL, 31, 1)
239
+ FIELD(INTERRUPT_ENABLE_REGISTER, ETXEOFLW, 30, 1)
240
+ FIELD(INTERRUPT_ENABLE_REGISTER, ERXMNF, 17, 1)
241
+ FIELD(INTERRUPT_ENABLE_REGISTER, ERXFWMFLL_1, 16, 1)
242
+ FIELD(INTERRUPT_ENABLE_REGISTER, ERXFOFLW_1, 15, 1)
243
+ FIELD(INTERRUPT_ENABLE_REGISTER, ETXCRS, 14, 1)
244
+ FIELD(INTERRUPT_ENABLE_REGISTER, ETXRRS, 13, 1)
245
+ FIELD(INTERRUPT_ENABLE_REGISTER, ERXFWMFLL, 12, 1)
246
+ FIELD(INTERRUPT_ENABLE_REGISTER, EWKUP, 11, 1)
247
+ FIELD(INTERRUPT_ENABLE_REGISTER, ESLP, 10, 1)
248
+ FIELD(INTERRUPT_ENABLE_REGISTER, EBSOFF, 9, 1)
249
+ FIELD(INTERRUPT_ENABLE_REGISTER, EERROR, 8, 1)
250
+ FIELD(INTERRUPT_ENABLE_REGISTER, ERFXOFLW, 6, 1)
251
+ FIELD(INTERRUPT_ENABLE_REGISTER, ETSCNT_OFLW, 5, 1)
252
+ FIELD(INTERRUPT_ENABLE_REGISTER, ERXOK, 4, 1)
253
+ FIELD(INTERRUPT_ENABLE_REGISTER, EBSFRD, 3, 1)
254
+ FIELD(INTERRUPT_ENABLE_REGISTER, EPEE, 2, 1)
255
+ FIELD(INTERRUPT_ENABLE_REGISTER, ETXOK, 1, 1)
256
+ FIELD(INTERRUPT_ENABLE_REGISTER, EARBLOST, 0, 1)
257
+REG32(INTERRUPT_CLEAR_REGISTER, 0x24)
258
+ FIELD(INTERRUPT_CLEAR_REGISTER, CTXEWMFLL, 31, 1)
259
+ FIELD(INTERRUPT_CLEAR_REGISTER, CTXEOFLW, 30, 1)
260
+ FIELD(INTERRUPT_CLEAR_REGISTER, CRXMNF, 17, 1)
261
+ FIELD(INTERRUPT_CLEAR_REGISTER, CRXFWMFLL_1, 16, 1)
262
+ FIELD(INTERRUPT_CLEAR_REGISTER, CRXFOFLW_1, 15, 1)
263
+ FIELD(INTERRUPT_CLEAR_REGISTER, CTXCRS, 14, 1)
264
+ FIELD(INTERRUPT_CLEAR_REGISTER, CTXRRS, 13, 1)
265
+ FIELD(INTERRUPT_CLEAR_REGISTER, CRXFWMFLL, 12, 1)
266
+ FIELD(INTERRUPT_CLEAR_REGISTER, CWKUP, 11, 1)
267
+ FIELD(INTERRUPT_CLEAR_REGISTER, CSLP, 10, 1)
268
+ FIELD(INTERRUPT_CLEAR_REGISTER, CBSOFF, 9, 1)
269
+ FIELD(INTERRUPT_CLEAR_REGISTER, CERROR, 8, 1)
270
+ FIELD(INTERRUPT_CLEAR_REGISTER, CRFXOFLW, 6, 1)
271
+ FIELD(INTERRUPT_CLEAR_REGISTER, CTSCNT_OFLW, 5, 1)
272
+ FIELD(INTERRUPT_CLEAR_REGISTER, CRXOK, 4, 1)
273
+ FIELD(INTERRUPT_CLEAR_REGISTER, CBSFRD, 3, 1)
274
+ FIELD(INTERRUPT_CLEAR_REGISTER, CPEE, 2, 1)
275
+ FIELD(INTERRUPT_CLEAR_REGISTER, CTXOK, 1, 1)
276
+ FIELD(INTERRUPT_CLEAR_REGISTER, CARBLOST, 0, 1)
277
+REG32(TIMESTAMP_REGISTER, 0x28)
278
+ FIELD(TIMESTAMP_REGISTER, TIMESTAMP_CNT, 16, 16)
279
+ FIELD(TIMESTAMP_REGISTER, CTS, 0, 1)
280
+REG32(DATA_PHASE_BAUD_RATE_PRESCALER_REGISTER, 0x88)
281
+ FIELD(DATA_PHASE_BAUD_RATE_PRESCALER_REGISTER, TDC, 16, 1)
282
+ FIELD(DATA_PHASE_BAUD_RATE_PRESCALER_REGISTER, TDCOFF, 8, 6)
283
+ FIELD(DATA_PHASE_BAUD_RATE_PRESCALER_REGISTER, DP_BRP, 0, 8)
284
+REG32(DATA_PHASE_BIT_TIMING_REGISTER, 0x8c)
285
+ FIELD(DATA_PHASE_BIT_TIMING_REGISTER, DP_SJW, 16, 4)
286
+ FIELD(DATA_PHASE_BIT_TIMING_REGISTER, DP_TS2, 8, 4)
287
+ FIELD(DATA_PHASE_BIT_TIMING_REGISTER, DP_TS1, 0, 5)
288
+REG32(TX_BUFFER_READY_REQUEST_REGISTER, 0x90)
289
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR31, 31, 1)
290
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR30, 30, 1)
291
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR29, 29, 1)
292
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR28, 28, 1)
293
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR27, 27, 1)
294
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR26, 26, 1)
295
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR25, 25, 1)
296
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR24, 24, 1)
297
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR23, 23, 1)
298
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR22, 22, 1)
299
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR21, 21, 1)
300
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR20, 20, 1)
301
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR19, 19, 1)
302
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR18, 18, 1)
303
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR17, 17, 1)
304
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR16, 16, 1)
305
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR15, 15, 1)
306
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR14, 14, 1)
307
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR13, 13, 1)
308
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR12, 12, 1)
309
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR11, 11, 1)
310
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR10, 10, 1)
311
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR9, 9, 1)
312
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR8, 8, 1)
313
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR7, 7, 1)
314
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR6, 6, 1)
315
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR5, 5, 1)
316
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR4, 4, 1)
317
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR3, 3, 1)
318
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR2, 2, 1)
319
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR1, 1, 1)
320
+ FIELD(TX_BUFFER_READY_REQUEST_REGISTER, RR0, 0, 1)
321
+REG32(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, 0x94)
322
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS31, 31, 1)
323
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS30, 30, 1)
324
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS29, 29, 1)
325
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS28, 28, 1)
326
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS27, 27, 1)
327
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS26, 26, 1)
328
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS25, 25, 1)
329
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS24, 24, 1)
330
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS23, 23, 1)
331
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS22, 22, 1)
332
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS21, 21, 1)
333
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS20, 20, 1)
334
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS19, 19, 1)
335
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS18, 18, 1)
336
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS17, 17, 1)
337
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS16, 16, 1)
338
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS15, 15, 1)
339
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS14, 14, 1)
340
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS13, 13, 1)
341
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS12, 12, 1)
342
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS11, 11, 1)
343
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS10, 10, 1)
344
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS9, 9, 1)
345
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS8, 8, 1)
346
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS7, 7, 1)
347
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS6, 6, 1)
348
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS5, 5, 1)
349
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS4, 4, 1)
350
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS3, 3, 1)
351
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS2, 2, 1)
352
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS1, 1, 1)
353
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER, ERRS0, 0, 1)
354
+REG32(TX_BUFFER_CANCEL_REQUEST_REGISTER, 0x98)
355
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR31, 31, 1)
356
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR30, 30, 1)
357
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR29, 29, 1)
358
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR28, 28, 1)
359
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR27, 27, 1)
360
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR26, 26, 1)
361
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR25, 25, 1)
362
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR24, 24, 1)
363
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR23, 23, 1)
364
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR22, 22, 1)
365
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR21, 21, 1)
366
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR20, 20, 1)
367
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR19, 19, 1)
368
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR18, 18, 1)
369
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR17, 17, 1)
370
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR16, 16, 1)
371
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR15, 15, 1)
372
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR14, 14, 1)
373
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR13, 13, 1)
374
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR12, 12, 1)
375
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR11, 11, 1)
376
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR10, 10, 1)
377
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR9, 9, 1)
378
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR8, 8, 1)
379
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR7, 7, 1)
380
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR6, 6, 1)
381
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR5, 5, 1)
382
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR4, 4, 1)
383
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR3, 3, 1)
384
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR2, 2, 1)
385
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR1, 1, 1)
386
+ FIELD(TX_BUFFER_CANCEL_REQUEST_REGISTER, CR0, 0, 1)
387
+REG32(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, 0x9c)
388
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS31, 31,
389
+ 1)
390
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS30, 30,
391
+ 1)
392
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS29, 29,
393
+ 1)
394
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS28, 28,
395
+ 1)
396
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS27, 27,
397
+ 1)
398
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS26, 26,
399
+ 1)
400
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS25, 25,
401
+ 1)
402
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS24, 24,
403
+ 1)
404
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS23, 23,
405
+ 1)
406
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS22, 22,
407
+ 1)
408
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS21, 21,
409
+ 1)
410
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS20, 20,
411
+ 1)
412
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS19, 19,
413
+ 1)
414
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS18, 18,
415
+ 1)
416
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS17, 17,
417
+ 1)
418
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS16, 16,
419
+ 1)
420
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS15, 15,
421
+ 1)
422
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS14, 14,
423
+ 1)
424
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS13, 13,
425
+ 1)
426
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS12, 12,
427
+ 1)
428
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS11, 11,
429
+ 1)
430
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS10, 10,
431
+ 1)
432
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS9, 9, 1)
433
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS8, 8, 1)
434
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS7, 7, 1)
435
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS6, 6, 1)
436
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS5, 5, 1)
437
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS4, 4, 1)
438
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS3, 3, 1)
439
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS2, 2, 1)
440
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS1, 1, 1)
441
+ FIELD(INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER, ECRS0, 0, 1)
442
+REG32(TX_EVENT_FIFO_STATUS_REGISTER, 0xa0)
443
+ FIELD(TX_EVENT_FIFO_STATUS_REGISTER, TXE_FL, 8, 6)
444
+ FIELD(TX_EVENT_FIFO_STATUS_REGISTER, TXE_IRI, 7, 1)
445
+ FIELD(TX_EVENT_FIFO_STATUS_REGISTER, TXE_RI, 0, 5)
446
+REG32(TX_EVENT_FIFO_WATERMARK_REGISTER, 0xa4)
447
+ FIELD(TX_EVENT_FIFO_WATERMARK_REGISTER, TXE_FWM, 0, 5)
448
+REG32(ACCEPTANCE_FILTER_CONTROL_REGISTER, 0xe0)
449
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF31, 31, 1)
450
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF30, 30, 1)
451
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF29, 29, 1)
452
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF28, 28, 1)
453
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF27, 27, 1)
454
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF26, 26, 1)
455
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF25, 25, 1)
456
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF24, 24, 1)
457
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF23, 23, 1)
458
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF22, 22, 1)
459
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF21, 21, 1)
460
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF20, 20, 1)
461
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF19, 19, 1)
462
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF18, 18, 1)
463
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF17, 17, 1)
464
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF16, 16, 1)
465
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF15, 15, 1)
466
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF14, 14, 1)
467
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF13, 13, 1)
468
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF12, 12, 1)
469
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF11, 11, 1)
470
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF10, 10, 1)
471
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF9, 9, 1)
472
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF8, 8, 1)
473
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF7, 7, 1)
474
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF6, 6, 1)
475
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF5, 5, 1)
476
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF4, 4, 1)
477
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF3, 3, 1)
478
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF2, 2, 1)
479
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF1, 1, 1)
480
+ FIELD(ACCEPTANCE_FILTER_CONTROL_REGISTER, UAF0, 0, 1)
481
+REG32(RX_FIFO_STATUS_REGISTER, 0xe8)
482
+ FIELD(RX_FIFO_STATUS_REGISTER, FL_1, 24, 7)
483
+ FIELD(RX_FIFO_STATUS_REGISTER, IRI_1, 23, 1)
484
+ FIELD(RX_FIFO_STATUS_REGISTER, RI_1, 16, 6)
485
+ FIELD(RX_FIFO_STATUS_REGISTER, FL, 8, 7)
486
+ FIELD(RX_FIFO_STATUS_REGISTER, IRI, 7, 1)
487
+ FIELD(RX_FIFO_STATUS_REGISTER, RI, 0, 6)
488
+REG32(RX_FIFO_WATERMARK_REGISTER, 0xec)
489
+ FIELD(RX_FIFO_WATERMARK_REGISTER, RXFP, 16, 5)
490
+ FIELD(RX_FIFO_WATERMARK_REGISTER, RXFWM_1, 8, 6)
491
+ FIELD(RX_FIFO_WATERMARK_REGISTER, RXFWM, 0, 6)
492
+REG32(TB_ID_REGISTER, 0x100)
493
+ FIELD(TB_ID_REGISTER, ID, 21, 11)
494
+ FIELD(TB_ID_REGISTER, SRR_RTR_RRS, 20, 1)
495
+ FIELD(TB_ID_REGISTER, IDE, 19, 1)
496
+ FIELD(TB_ID_REGISTER, ID_EXT, 1, 18)
497
+ FIELD(TB_ID_REGISTER, RTR_RRS, 0, 1)
498
+REG32(TB0_DLC_REGISTER, 0x104)
499
+ FIELD(TB0_DLC_REGISTER, DLC, 28, 4)
500
+ FIELD(TB0_DLC_REGISTER, FDF, 27, 1)
501
+ FIELD(TB0_DLC_REGISTER, BRS, 26, 1)
502
+ FIELD(TB0_DLC_REGISTER, RSVD2, 25, 1)
503
+ FIELD(TB0_DLC_REGISTER, EFC, 24, 1)
504
+ FIELD(TB0_DLC_REGISTER, MM, 16, 8)
505
+ FIELD(TB0_DLC_REGISTER, RSVD1, 0, 16)
506
+REG32(TB_DW0_REGISTER, 0x108)
507
+ FIELD(TB_DW0_REGISTER, DATA_BYTES0, 24, 8)
508
+ FIELD(TB_DW0_REGISTER, DATA_BYTES1, 16, 8)
509
+ FIELD(TB_DW0_REGISTER, DATA_BYTES2, 8, 8)
510
+ FIELD(TB_DW0_REGISTER, DATA_BYTES3, 0, 8)
511
+REG32(TB_DW1_REGISTER, 0x10c)
512
+ FIELD(TB_DW1_REGISTER, DATA_BYTES4, 24, 8)
513
+ FIELD(TB_DW1_REGISTER, DATA_BYTES5, 16, 8)
514
+ FIELD(TB_DW1_REGISTER, DATA_BYTES6, 8, 8)
515
+ FIELD(TB_DW1_REGISTER, DATA_BYTES7, 0, 8)
516
+REG32(TB_DW2_REGISTER, 0x110)
517
+ FIELD(TB_DW2_REGISTER, DATA_BYTES8, 24, 8)
518
+ FIELD(TB_DW2_REGISTER, DATA_BYTES9, 16, 8)
519
+ FIELD(TB_DW2_REGISTER, DATA_BYTES10, 8, 8)
520
+ FIELD(TB_DW2_REGISTER, DATA_BYTES11, 0, 8)
521
+REG32(TB_DW3_REGISTER, 0x114)
522
+ FIELD(TB_DW3_REGISTER, DATA_BYTES12, 24, 8)
523
+ FIELD(TB_DW3_REGISTER, DATA_BYTES13, 16, 8)
524
+ FIELD(TB_DW3_REGISTER, DATA_BYTES14, 8, 8)
525
+ FIELD(TB_DW3_REGISTER, DATA_BYTES15, 0, 8)
526
+REG32(TB_DW4_REGISTER, 0x118)
527
+ FIELD(TB_DW4_REGISTER, DATA_BYTES16, 24, 8)
528
+ FIELD(TB_DW4_REGISTER, DATA_BYTES17, 16, 8)
529
+ FIELD(TB_DW4_REGISTER, DATA_BYTES18, 8, 8)
530
+ FIELD(TB_DW4_REGISTER, DATA_BYTES19, 0, 8)
531
+REG32(TB_DW5_REGISTER, 0x11c)
532
+ FIELD(TB_DW5_REGISTER, DATA_BYTES20, 24, 8)
533
+ FIELD(TB_DW5_REGISTER, DATA_BYTES21, 16, 8)
534
+ FIELD(TB_DW5_REGISTER, DATA_BYTES22, 8, 8)
535
+ FIELD(TB_DW5_REGISTER, DATA_BYTES23, 0, 8)
536
+REG32(TB_DW6_REGISTER, 0x120)
537
+ FIELD(TB_DW6_REGISTER, DATA_BYTES24, 24, 8)
538
+ FIELD(TB_DW6_REGISTER, DATA_BYTES25, 16, 8)
539
+ FIELD(TB_DW6_REGISTER, DATA_BYTES26, 8, 8)
540
+ FIELD(TB_DW6_REGISTER, DATA_BYTES27, 0, 8)
541
+REG32(TB_DW7_REGISTER, 0x124)
542
+ FIELD(TB_DW7_REGISTER, DATA_BYTES28, 24, 8)
543
+ FIELD(TB_DW7_REGISTER, DATA_BYTES29, 16, 8)
544
+ FIELD(TB_DW7_REGISTER, DATA_BYTES30, 8, 8)
545
+ FIELD(TB_DW7_REGISTER, DATA_BYTES31, 0, 8)
546
+REG32(TB_DW8_REGISTER, 0x128)
547
+ FIELD(TB_DW8_REGISTER, DATA_BYTES32, 24, 8)
548
+ FIELD(TB_DW8_REGISTER, DATA_BYTES33, 16, 8)
549
+ FIELD(TB_DW8_REGISTER, DATA_BYTES34, 8, 8)
550
+ FIELD(TB_DW8_REGISTER, DATA_BYTES35, 0, 8)
551
+REG32(TB_DW9_REGISTER, 0x12c)
552
+ FIELD(TB_DW9_REGISTER, DATA_BYTES36, 24, 8)
553
+ FIELD(TB_DW9_REGISTER, DATA_BYTES37, 16, 8)
554
+ FIELD(TB_DW9_REGISTER, DATA_BYTES38, 8, 8)
555
+ FIELD(TB_DW9_REGISTER, DATA_BYTES39, 0, 8)
556
+REG32(TB_DW10_REGISTER, 0x130)
557
+ FIELD(TB_DW10_REGISTER, DATA_BYTES40, 24, 8)
558
+ FIELD(TB_DW10_REGISTER, DATA_BYTES41, 16, 8)
559
+ FIELD(TB_DW10_REGISTER, DATA_BYTES42, 8, 8)
560
+ FIELD(TB_DW10_REGISTER, DATA_BYTES43, 0, 8)
561
+REG32(TB_DW11_REGISTER, 0x134)
562
+ FIELD(TB_DW11_REGISTER, DATA_BYTES44, 24, 8)
563
+ FIELD(TB_DW11_REGISTER, DATA_BYTES45, 16, 8)
564
+ FIELD(TB_DW11_REGISTER, DATA_BYTES46, 8, 8)
565
+ FIELD(TB_DW11_REGISTER, DATA_BYTES47, 0, 8)
566
+REG32(TB_DW12_REGISTER, 0x138)
567
+ FIELD(TB_DW12_REGISTER, DATA_BYTES48, 24, 8)
568
+ FIELD(TB_DW12_REGISTER, DATA_BYTES49, 16, 8)
569
+ FIELD(TB_DW12_REGISTER, DATA_BYTES50, 8, 8)
570
+ FIELD(TB_DW12_REGISTER, DATA_BYTES51, 0, 8)
571
+REG32(TB_DW13_REGISTER, 0x13c)
572
+ FIELD(TB_DW13_REGISTER, DATA_BYTES52, 24, 8)
573
+ FIELD(TB_DW13_REGISTER, DATA_BYTES53, 16, 8)
574
+ FIELD(TB_DW13_REGISTER, DATA_BYTES54, 8, 8)
575
+ FIELD(TB_DW13_REGISTER, DATA_BYTES55, 0, 8)
576
+REG32(TB_DW14_REGISTER, 0x140)
577
+ FIELD(TB_DW14_REGISTER, DATA_BYTES56, 24, 8)
578
+ FIELD(TB_DW14_REGISTER, DATA_BYTES57, 16, 8)
579
+ FIELD(TB_DW14_REGISTER, DATA_BYTES58, 8, 8)
580
+ FIELD(TB_DW14_REGISTER, DATA_BYTES59, 0, 8)
581
+REG32(TB_DW15_REGISTER, 0x144)
582
+ FIELD(TB_DW15_REGISTER, DATA_BYTES60, 24, 8)
583
+ FIELD(TB_DW15_REGISTER, DATA_BYTES61, 16, 8)
584
+ FIELD(TB_DW15_REGISTER, DATA_BYTES62, 8, 8)
585
+ FIELD(TB_DW15_REGISTER, DATA_BYTES63, 0, 8)
586
+REG32(AFMR_REGISTER, 0xa00)
587
+ FIELD(AFMR_REGISTER, AMID, 21, 11)
588
+ FIELD(AFMR_REGISTER, AMSRR, 20, 1)
589
+ FIELD(AFMR_REGISTER, AMIDE, 19, 1)
590
+ FIELD(AFMR_REGISTER, AMID_EXT, 1, 18)
591
+ FIELD(AFMR_REGISTER, AMRTR, 0, 1)
592
+REG32(AFIR_REGISTER, 0xa04)
593
+ FIELD(AFIR_REGISTER, AIID, 21, 11)
594
+ FIELD(AFIR_REGISTER, AISRR, 20, 1)
595
+ FIELD(AFIR_REGISTER, AIIDE, 19, 1)
596
+ FIELD(AFIR_REGISTER, AIID_EXT, 1, 18)
597
+ FIELD(AFIR_REGISTER, AIRTR, 0, 1)
598
+REG32(TXE_FIFO_TB_ID_REGISTER, 0x2000)
599
+ FIELD(TXE_FIFO_TB_ID_REGISTER, ID, 21, 11)
600
+ FIELD(TXE_FIFO_TB_ID_REGISTER, SRR_RTR_RRS, 20, 1)
601
+ FIELD(TXE_FIFO_TB_ID_REGISTER, IDE, 19, 1)
602
+ FIELD(TXE_FIFO_TB_ID_REGISTER, ID_EXT, 1, 18)
603
+ FIELD(TXE_FIFO_TB_ID_REGISTER, RTR_RRS, 0, 1)
604
+REG32(TXE_FIFO_TB_DLC_REGISTER, 0x2004)
605
+ FIELD(TXE_FIFO_TB_DLC_REGISTER, DLC, 28, 4)
606
+ FIELD(TXE_FIFO_TB_DLC_REGISTER, FDF, 27, 1)
607
+ FIELD(TXE_FIFO_TB_DLC_REGISTER, BRS, 26, 1)
608
+ FIELD(TXE_FIFO_TB_DLC_REGISTER, ET, 24, 2)
609
+ FIELD(TXE_FIFO_TB_DLC_REGISTER, MM, 16, 8)
610
+ FIELD(TXE_FIFO_TB_DLC_REGISTER, TIMESTAMP, 0, 16)
611
+REG32(RB_ID_REGISTER, 0x2100)
612
+ FIELD(RB_ID_REGISTER, ID, 21, 11)
613
+ FIELD(RB_ID_REGISTER, SRR_RTR_RRS, 20, 1)
614
+ FIELD(RB_ID_REGISTER, IDE, 19, 1)
615
+ FIELD(RB_ID_REGISTER, ID_EXT, 1, 18)
616
+ FIELD(RB_ID_REGISTER, RTR_RRS, 0, 1)
617
+REG32(RB_DLC_REGISTER, 0x2104)
618
+ FIELD(RB_DLC_REGISTER, DLC, 28, 4)
619
+ FIELD(RB_DLC_REGISTER, FDF, 27, 1)
620
+ FIELD(RB_DLC_REGISTER, BRS, 26, 1)
621
+ FIELD(RB_DLC_REGISTER, ESI, 25, 1)
622
+ FIELD(RB_DLC_REGISTER, MATCHED_FILTER_INDEX, 16, 5)
623
+ FIELD(RB_DLC_REGISTER, TIMESTAMP, 0, 16)
624
+REG32(RB_DW0_REGISTER, 0x2108)
625
+ FIELD(RB_DW0_REGISTER, DATA_BYTES0, 24, 8)
626
+ FIELD(RB_DW0_REGISTER, DATA_BYTES1, 16, 8)
627
+ FIELD(RB_DW0_REGISTER, DATA_BYTES2, 8, 8)
628
+ FIELD(RB_DW0_REGISTER, DATA_BYTES3, 0, 8)
629
+REG32(RB_DW1_REGISTER, 0x210c)
630
+ FIELD(RB_DW1_REGISTER, DATA_BYTES4, 24, 8)
631
+ FIELD(RB_DW1_REGISTER, DATA_BYTES5, 16, 8)
632
+ FIELD(RB_DW1_REGISTER, DATA_BYTES6, 8, 8)
633
+ FIELD(RB_DW1_REGISTER, DATA_BYTES7, 0, 8)
634
+REG32(RB_DW2_REGISTER, 0x2110)
635
+ FIELD(RB_DW2_REGISTER, DATA_BYTES8, 24, 8)
636
+ FIELD(RB_DW2_REGISTER, DATA_BYTES9, 16, 8)
637
+ FIELD(RB_DW2_REGISTER, DATA_BYTES10, 8, 8)
638
+ FIELD(RB_DW2_REGISTER, DATA_BYTES11, 0, 8)
639
+REG32(RB_DW3_REGISTER, 0x2114)
640
+ FIELD(RB_DW3_REGISTER, DATA_BYTES12, 24, 8)
641
+ FIELD(RB_DW3_REGISTER, DATA_BYTES13, 16, 8)
642
+ FIELD(RB_DW3_REGISTER, DATA_BYTES14, 8, 8)
643
+ FIELD(RB_DW3_REGISTER, DATA_BYTES15, 0, 8)
644
+REG32(RB_DW4_REGISTER, 0x2118)
645
+ FIELD(RB_DW4_REGISTER, DATA_BYTES16, 24, 8)
646
+ FIELD(RB_DW4_REGISTER, DATA_BYTES17, 16, 8)
647
+ FIELD(RB_DW4_REGISTER, DATA_BYTES18, 8, 8)
648
+ FIELD(RB_DW4_REGISTER, DATA_BYTES19, 0, 8)
649
+REG32(RB_DW5_REGISTER, 0x211c)
650
+ FIELD(RB_DW5_REGISTER, DATA_BYTES20, 24, 8)
651
+ FIELD(RB_DW5_REGISTER, DATA_BYTES21, 16, 8)
652
+ FIELD(RB_DW5_REGISTER, DATA_BYTES22, 8, 8)
653
+ FIELD(RB_DW5_REGISTER, DATA_BYTES23, 0, 8)
654
+REG32(RB_DW6_REGISTER, 0x2120)
655
+ FIELD(RB_DW6_REGISTER, DATA_BYTES24, 24, 8)
656
+ FIELD(RB_DW6_REGISTER, DATA_BYTES25, 16, 8)
657
+ FIELD(RB_DW6_REGISTER, DATA_BYTES26, 8, 8)
658
+ FIELD(RB_DW6_REGISTER, DATA_BYTES27, 0, 8)
659
+REG32(RB_DW7_REGISTER, 0x2124)
660
+ FIELD(RB_DW7_REGISTER, DATA_BYTES28, 24, 8)
661
+ FIELD(RB_DW7_REGISTER, DATA_BYTES29, 16, 8)
662
+ FIELD(RB_DW7_REGISTER, DATA_BYTES30, 8, 8)
663
+ FIELD(RB_DW7_REGISTER, DATA_BYTES31, 0, 8)
664
+REG32(RB_DW8_REGISTER, 0x2128)
665
+ FIELD(RB_DW8_REGISTER, DATA_BYTES32, 24, 8)
666
+ FIELD(RB_DW8_REGISTER, DATA_BYTES33, 16, 8)
667
+ FIELD(RB_DW8_REGISTER, DATA_BYTES34, 8, 8)
668
+ FIELD(RB_DW8_REGISTER, DATA_BYTES35, 0, 8)
669
+REG32(RB_DW9_REGISTER, 0x212c)
670
+ FIELD(RB_DW9_REGISTER, DATA_BYTES36, 24, 8)
671
+ FIELD(RB_DW9_REGISTER, DATA_BYTES37, 16, 8)
672
+ FIELD(RB_DW9_REGISTER, DATA_BYTES38, 8, 8)
673
+ FIELD(RB_DW9_REGISTER, DATA_BYTES39, 0, 8)
674
+REG32(RB_DW10_REGISTER, 0x2130)
675
+ FIELD(RB_DW10_REGISTER, DATA_BYTES40, 24, 8)
676
+ FIELD(RB_DW10_REGISTER, DATA_BYTES41, 16, 8)
677
+ FIELD(RB_DW10_REGISTER, DATA_BYTES42, 8, 8)
678
+ FIELD(RB_DW10_REGISTER, DATA_BYTES43, 0, 8)
679
+REG32(RB_DW11_REGISTER, 0x2134)
680
+ FIELD(RB_DW11_REGISTER, DATA_BYTES44, 24, 8)
681
+ FIELD(RB_DW11_REGISTER, DATA_BYTES45, 16, 8)
682
+ FIELD(RB_DW11_REGISTER, DATA_BYTES46, 8, 8)
683
+ FIELD(RB_DW11_REGISTER, DATA_BYTES47, 0, 8)
684
+REG32(RB_DW12_REGISTER, 0x2138)
685
+ FIELD(RB_DW12_REGISTER, DATA_BYTES48, 24, 8)
686
+ FIELD(RB_DW12_REGISTER, DATA_BYTES49, 16, 8)
687
+ FIELD(RB_DW12_REGISTER, DATA_BYTES50, 8, 8)
688
+ FIELD(RB_DW12_REGISTER, DATA_BYTES51, 0, 8)
689
+REG32(RB_DW13_REGISTER, 0x213c)
690
+ FIELD(RB_DW13_REGISTER, DATA_BYTES52, 24, 8)
691
+ FIELD(RB_DW13_REGISTER, DATA_BYTES53, 16, 8)
692
+ FIELD(RB_DW13_REGISTER, DATA_BYTES54, 8, 8)
693
+ FIELD(RB_DW13_REGISTER, DATA_BYTES55, 0, 8)
694
+REG32(RB_DW14_REGISTER, 0x2140)
695
+ FIELD(RB_DW14_REGISTER, DATA_BYTES56, 24, 8)
696
+ FIELD(RB_DW14_REGISTER, DATA_BYTES57, 16, 8)
697
+ FIELD(RB_DW14_REGISTER, DATA_BYTES58, 8, 8)
698
+ FIELD(RB_DW14_REGISTER, DATA_BYTES59, 0, 8)
699
+REG32(RB_DW15_REGISTER, 0x2144)
700
+ FIELD(RB_DW15_REGISTER, DATA_BYTES60, 24, 8)
701
+ FIELD(RB_DW15_REGISTER, DATA_BYTES61, 16, 8)
702
+ FIELD(RB_DW15_REGISTER, DATA_BYTES62, 8, 8)
703
+ FIELD(RB_DW15_REGISTER, DATA_BYTES63, 0, 8)
704
+REG32(RB_ID_REGISTER_1, 0x4100)
705
+ FIELD(RB_ID_REGISTER_1, ID, 21, 11)
706
+ FIELD(RB_ID_REGISTER_1, SRR_RTR_RRS, 20, 1)
707
+ FIELD(RB_ID_REGISTER_1, IDE, 19, 1)
708
+ FIELD(RB_ID_REGISTER_1, ID_EXT, 1, 18)
709
+ FIELD(RB_ID_REGISTER_1, RTR_RRS, 0, 1)
710
+REG32(RB_DLC_REGISTER_1, 0x4104)
711
+ FIELD(RB_DLC_REGISTER_1, DLC, 28, 4)
712
+ FIELD(RB_DLC_REGISTER_1, FDF, 27, 1)
713
+ FIELD(RB_DLC_REGISTER_1, BRS, 26, 1)
714
+ FIELD(RB_DLC_REGISTER_1, ESI, 25, 1)
715
+ FIELD(RB_DLC_REGISTER_1, MATCHED_FILTER_INDEX, 16, 5)
716
+ FIELD(RB_DLC_REGISTER_1, TIMESTAMP, 0, 16)
717
+REG32(RB0_DW0_REGISTER_1, 0x4108)
718
+ FIELD(RB0_DW0_REGISTER_1, DATA_BYTES0, 24, 8)
719
+ FIELD(RB0_DW0_REGISTER_1, DATA_BYTES1, 16, 8)
720
+ FIELD(RB0_DW0_REGISTER_1, DATA_BYTES2, 8, 8)
721
+ FIELD(RB0_DW0_REGISTER_1, DATA_BYTES3, 0, 8)
722
+REG32(RB_DW1_REGISTER_1, 0x410c)
723
+ FIELD(RB_DW1_REGISTER_1, DATA_BYTES4, 24, 8)
724
+ FIELD(RB_DW1_REGISTER_1, DATA_BYTES5, 16, 8)
725
+ FIELD(RB_DW1_REGISTER_1, DATA_BYTES6, 8, 8)
726
+ FIELD(RB_DW1_REGISTER_1, DATA_BYTES7, 0, 8)
727
+REG32(RB_DW2_REGISTER_1, 0x4110)
728
+ FIELD(RB_DW2_REGISTER_1, DATA_BYTES8, 24, 8)
729
+ FIELD(RB_DW2_REGISTER_1, DATA_BYTES9, 16, 8)
730
+ FIELD(RB_DW2_REGISTER_1, DATA_BYTES10, 8, 8)
731
+ FIELD(RB_DW2_REGISTER_1, DATA_BYTES11, 0, 8)
732
+REG32(RB_DW3_REGISTER_1, 0x4114)
733
+ FIELD(RB_DW3_REGISTER_1, DATA_BYTES12, 24, 8)
734
+ FIELD(RB_DW3_REGISTER_1, DATA_BYTES13, 16, 8)
735
+ FIELD(RB_DW3_REGISTER_1, DATA_BYTES14, 8, 8)
736
+ FIELD(RB_DW3_REGISTER_1, DATA_BYTES15, 0, 8)
737
+REG32(RB_DW4_REGISTER_1, 0x4118)
738
+ FIELD(RB_DW4_REGISTER_1, DATA_BYTES16, 24, 8)
739
+ FIELD(RB_DW4_REGISTER_1, DATA_BYTES17, 16, 8)
740
+ FIELD(RB_DW4_REGISTER_1, DATA_BYTES18, 8, 8)
741
+ FIELD(RB_DW4_REGISTER_1, DATA_BYTES19, 0, 8)
742
+REG32(RB_DW5_REGISTER_1, 0x411c)
743
+ FIELD(RB_DW5_REGISTER_1, DATA_BYTES20, 24, 8)
744
+ FIELD(RB_DW5_REGISTER_1, DATA_BYTES21, 16, 8)
745
+ FIELD(RB_DW5_REGISTER_1, DATA_BYTES22, 8, 8)
746
+ FIELD(RB_DW5_REGISTER_1, DATA_BYTES23, 0, 8)
747
+REG32(RB_DW6_REGISTER_1, 0x4120)
748
+ FIELD(RB_DW6_REGISTER_1, DATA_BYTES24, 24, 8)
749
+ FIELD(RB_DW6_REGISTER_1, DATA_BYTES25, 16, 8)
750
+ FIELD(RB_DW6_REGISTER_1, DATA_BYTES26, 8, 8)
751
+ FIELD(RB_DW6_REGISTER_1, DATA_BYTES27, 0, 8)
752
+REG32(RB_DW7_REGISTER_1, 0x4124)
753
+ FIELD(RB_DW7_REGISTER_1, DATA_BYTES28, 24, 8)
754
+ FIELD(RB_DW7_REGISTER_1, DATA_BYTES29, 16, 8)
755
+ FIELD(RB_DW7_REGISTER_1, DATA_BYTES30, 8, 8)
756
+ FIELD(RB_DW7_REGISTER_1, DATA_BYTES31, 0, 8)
757
+REG32(RB_DW8_REGISTER_1, 0x4128)
758
+ FIELD(RB_DW8_REGISTER_1, DATA_BYTES32, 24, 8)
759
+ FIELD(RB_DW8_REGISTER_1, DATA_BYTES33, 16, 8)
760
+ FIELD(RB_DW8_REGISTER_1, DATA_BYTES34, 8, 8)
761
+ FIELD(RB_DW8_REGISTER_1, DATA_BYTES35, 0, 8)
762
+REG32(RB_DW9_REGISTER_1, 0x412c)
763
+ FIELD(RB_DW9_REGISTER_1, DATA_BYTES36, 24, 8)
764
+ FIELD(RB_DW9_REGISTER_1, DATA_BYTES37, 16, 8)
765
+ FIELD(RB_DW9_REGISTER_1, DATA_BYTES38, 8, 8)
766
+ FIELD(RB_DW9_REGISTER_1, DATA_BYTES39, 0, 8)
767
+REG32(RB_DW10_REGISTER_1, 0x4130)
768
+ FIELD(RB_DW10_REGISTER_1, DATA_BYTES40, 24, 8)
769
+ FIELD(RB_DW10_REGISTER_1, DATA_BYTES41, 16, 8)
770
+ FIELD(RB_DW10_REGISTER_1, DATA_BYTES42, 8, 8)
771
+ FIELD(RB_DW10_REGISTER_1, DATA_BYTES43, 0, 8)
772
+REG32(RB_DW11_REGISTER_1, 0x4134)
773
+ FIELD(RB_DW11_REGISTER_1, DATA_BYTES44, 24, 8)
774
+ FIELD(RB_DW11_REGISTER_1, DATA_BYTES45, 16, 8)
775
+ FIELD(RB_DW11_REGISTER_1, DATA_BYTES46, 8, 8)
776
+ FIELD(RB_DW11_REGISTER_1, DATA_BYTES47, 0, 8)
777
+REG32(RB_DW12_REGISTER_1, 0x4138)
778
+ FIELD(RB_DW12_REGISTER_1, DATA_BYTES48, 24, 8)
779
+ FIELD(RB_DW12_REGISTER_1, DATA_BYTES49, 16, 8)
780
+ FIELD(RB_DW12_REGISTER_1, DATA_BYTES50, 8, 8)
781
+ FIELD(RB_DW12_REGISTER_1, DATA_BYTES51, 0, 8)
782
+REG32(RB_DW13_REGISTER_1, 0x413c)
783
+ FIELD(RB_DW13_REGISTER_1, DATA_BYTES52, 24, 8)
784
+ FIELD(RB_DW13_REGISTER_1, DATA_BYTES53, 16, 8)
785
+ FIELD(RB_DW13_REGISTER_1, DATA_BYTES54, 8, 8)
786
+ FIELD(RB_DW13_REGISTER_1, DATA_BYTES55, 0, 8)
787
+REG32(RB_DW14_REGISTER_1, 0x4140)
788
+ FIELD(RB_DW14_REGISTER_1, DATA_BYTES56, 24, 8)
789
+ FIELD(RB_DW14_REGISTER_1, DATA_BYTES57, 16, 8)
790
+ FIELD(RB_DW14_REGISTER_1, DATA_BYTES58, 8, 8)
791
+ FIELD(RB_DW14_REGISTER_1, DATA_BYTES59, 0, 8)
792
+REG32(RB_DW15_REGISTER_1, 0x4144)
793
+ FIELD(RB_DW15_REGISTER_1, DATA_BYTES60, 24, 8)
794
+ FIELD(RB_DW15_REGISTER_1, DATA_BYTES61, 16, 8)
795
+ FIELD(RB_DW15_REGISTER_1, DATA_BYTES62, 8, 8)
796
+ FIELD(RB_DW15_REGISTER_1, DATA_BYTES63, 0, 8)
797
+
798
+static uint8_t canfd_dlc_array[8] = {8, 12, 16, 20, 24, 32, 48, 64};
799
+
800
+static void canfd_update_irq(XlnxVersalCANFDState *s)
801
+{
802
+ unsigned int irq = s->regs[R_INTERRUPT_STATUS_REGISTER] &
803
+ s->regs[R_INTERRUPT_ENABLE_REGISTER];
804
+ g_autofree char *path = object_get_canonical_path(OBJECT(s));
805
+
806
+ /* RX watermark interrupts. */
807
+ if (ARRAY_FIELD_EX32(s->regs, RX_FIFO_STATUS_REGISTER, FL) >
808
+ ARRAY_FIELD_EX32(s->regs, RX_FIFO_WATERMARK_REGISTER, RXFWM)) {
809
+ ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXFWMFLL, 1);
810
+ }
811
+
812
+ if (ARRAY_FIELD_EX32(s->regs, RX_FIFO_STATUS_REGISTER, FL_1) >
813
+ ARRAY_FIELD_EX32(s->regs, RX_FIFO_WATERMARK_REGISTER, RXFWM_1)) {
814
+ ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXFWMFLL_1, 1);
815
+ }
816
+
817
+ /* TX watermark interrupt. */
818
+ if (ARRAY_FIELD_EX32(s->regs, TX_EVENT_FIFO_STATUS_REGISTER, TXE_FL) >
819
+ ARRAY_FIELD_EX32(s->regs, TX_EVENT_FIFO_WATERMARK_REGISTER, TXE_FWM)) {
820
+ ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, TXEWMFLL, 1);
821
+ }
822
+
823
+ trace_xlnx_canfd_update_irq(path, s->regs[R_INTERRUPT_STATUS_REGISTER],
824
+ s->regs[R_INTERRUPT_ENABLE_REGISTER], irq);
825
+
826
+ qemu_set_irq(s->irq_canfd_int, irq);
827
+}
828
+
829
+static void canfd_ier_post_write(RegisterInfo *reg, uint64_t val64)
830
+{
831
+ XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
832
+
833
+ canfd_update_irq(s);
834
+}
835
+
836
+static uint64_t canfd_icr_pre_write(RegisterInfo *reg, uint64_t val64)
837
+{
838
+ XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
839
+ uint32_t val = val64;
840
+
841
+ s->regs[R_INTERRUPT_STATUS_REGISTER] &= ~val;
842
+
843
+ /*
844
+ * RXBOFLW_BI field is automatically cleared to default if RXBOFLW bit is
845
+ * cleared in ISR.
846
+ */
847
+ if (ARRAY_FIELD_EX32(s->regs, INTERRUPT_STATUS_REGISTER, RXFWMFLL_1)) {
848
+ ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXBOFLW_BI, 0);
849
+ }
850
+
851
+ canfd_update_irq(s);
852
+
853
+ return 0;
854
+}
855
+
856
+static void canfd_config_reset(XlnxVersalCANFDState *s)
857
+{
858
+
859
+ unsigned int i;
860
+
861
+ /* Reset all the configuration registers. */
862
+ for (i = 0; i < R_RX_FIFO_WATERMARK_REGISTER; ++i) {
863
+ register_reset(&s->reg_info[i]);
864
+ }
865
+
866
+ canfd_update_irq(s);
867
+}
868
+
869
+static void canfd_config_mode(XlnxVersalCANFDState *s)
870
+{
871
+ register_reset(&s->reg_info[R_ERROR_COUNTER_REGISTER]);
872
+ register_reset(&s->reg_info[R_ERROR_STATUS_REGISTER]);
873
+ register_reset(&s->reg_info[R_STATUS_REGISTER]);
874
+
875
+ /* Put XlnxVersalCANFDState in configuration mode. */
876
+ ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, CONFIG, 1);
877
+ ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, WKUP, 0);
878
+ ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, SLP, 0);
879
+ ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, BSOFF, 0);
880
+ ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, ERROR_BIT, 0);
881
+ ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXFOFLW, 0);
882
+ ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXFOFLW_1, 0);
883
+ ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXOK, 0);
884
+ ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, TXOK, 0);
885
+ ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, ARBLST, 0);
886
+
887
+ /* Clear the time stamp. */
888
+ ptimer_transaction_begin(s->canfd_timer);
889
+ ptimer_set_count(s->canfd_timer, 0);
890
+ ptimer_transaction_commit(s->canfd_timer);
891
+
892
+ canfd_update_irq(s);
893
+}
894
+
895
+static void update_status_register_mode_bits(XlnxVersalCANFDState *s)
896
+{
897
+ bool sleep_status = ARRAY_FIELD_EX32(s->regs, STATUS_REGISTER, SLEEP);
898
+ bool sleep_mode = ARRAY_FIELD_EX32(s->regs, MODE_SELECT_REGISTER, SLEEP);
899
+ /* Wake up interrupt bit. */
900
+ bool wakeup_irq_val = !sleep_mode && sleep_status;
901
+ /* Sleep interrupt bit. */
902
+ bool sleep_irq_val = sleep_mode && !sleep_status;
903
+
904
+ /* Clear previous core mode status bits. */
905
+ ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, LBACK, 0);
906
+ ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, SLEEP, 0);
907
+ ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, SNOOP, 0);
908
+ ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, NORMAL, 0);
909
+
910
+ /* set current mode bit and generate irqs accordingly. */
911
+ if (ARRAY_FIELD_EX32(s->regs, MODE_SELECT_REGISTER, LBACK)) {
912
+ ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, LBACK, 1);
913
+ } else if (ARRAY_FIELD_EX32(s->regs, MODE_SELECT_REGISTER, SLEEP)) {
914
+ ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, SLEEP, 1);
915
+ ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, SLP,
916
+ sleep_irq_val);
917
+ } else if (ARRAY_FIELD_EX32(s->regs, MODE_SELECT_REGISTER, SNOOP)) {
918
+ ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, SNOOP, 1);
919
+ } else {
920
+ /* If all bits are zero, XlnxVersalCANFDState is set in normal mode. */
921
+ ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, NORMAL, 1);
922
+ /* Set wakeup interrupt bit. */
923
+ ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, WKUP,
924
+ wakeup_irq_val);
925
+ }
926
+
927
+ /* Put the CANFD in error active state. */
928
+ ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, ESTAT, 1);
929
+
930
+ canfd_update_irq(s);
931
+}
932
+
933
+static uint64_t canfd_msr_pre_write(RegisterInfo *reg, uint64_t val64)
934
+{
935
+ XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
936
+ uint32_t val = val64;
937
+ uint8_t multi_mode = 0;
938
+
939
+ /*
940
+ * Multiple mode set check. This is done to make sure user doesn't set
941
+ * multiple modes.
942
+ */
943
+ multi_mode = FIELD_EX32(val, MODE_SELECT_REGISTER, LBACK) +
944
+ FIELD_EX32(val, MODE_SELECT_REGISTER, SLEEP) +
945
+ FIELD_EX32(val, MODE_SELECT_REGISTER, SNOOP);
946
+
947
+ if (multi_mode > 1) {
948
+ qemu_log_mask(LOG_GUEST_ERROR, "Attempting to configure several modes"
949
+ " simultaneously. One mode will be selected according to"
950
+ " their priority: LBACK > SLEEP > SNOOP.\n");
951
+ }
952
+
953
+ if (ARRAY_FIELD_EX32(s->regs, SOFTWARE_RESET_REGISTER, CEN) == 0) {
954
+ /* In configuration mode, any mode can be selected. */
955
+ s->regs[R_MODE_SELECT_REGISTER] = val;
956
+ } else {
957
+ bool sleep_mode_bit = FIELD_EX32(val, MODE_SELECT_REGISTER, SLEEP);
958
+
959
+ ARRAY_FIELD_DP32(s->regs, MODE_SELECT_REGISTER, SLEEP, sleep_mode_bit);
960
+
961
+ if (FIELD_EX32(val, MODE_SELECT_REGISTER, LBACK)) {
962
+ qemu_log_mask(LOG_GUEST_ERROR, "Attempting to set LBACK mode"
963
+ " without setting CEN bit as 0\n");
964
+ } else if (FIELD_EX32(val, MODE_SELECT_REGISTER, SNOOP)) {
965
+ qemu_log_mask(LOG_GUEST_ERROR, "Attempting to set SNOOP mode"
966
+ " without setting CEN bit as 0\n");
967
+ }
968
+
969
+ update_status_register_mode_bits(s);
970
+ }
971
+
972
+ return s->regs[R_MODE_SELECT_REGISTER];
973
+}
974
+
975
+static void canfd_exit_sleep_mode(XlnxVersalCANFDState *s)
976
+{
977
+ ARRAY_FIELD_DP32(s->regs, MODE_SELECT_REGISTER, SLEEP, 0);
978
+ update_status_register_mode_bits(s);
979
+}
980
+
981
+static void regs2frame(XlnxVersalCANFDState *s, qemu_can_frame *frame,
982
+ uint32_t reg_num)
983
+{
984
+ uint32_t i = 0;
985
+ uint32_t j = 0;
986
+ uint32_t val = 0;
987
+ uint32_t dlc_reg_val = 0;
988
+ uint32_t dlc_value = 0;
989
+
990
+ /* Check that reg_num should be within TX register space. */
991
+ assert(reg_num <= R_TB_ID_REGISTER + (NUM_REGS_PER_MSG_SPACE *
992
+ s->cfg.tx_fifo));
993
+
994
+ dlc_reg_val = s->regs[reg_num + 1];
995
+ dlc_value = FIELD_EX32(dlc_reg_val, TB0_DLC_REGISTER, DLC);
996
+
997
+ frame->can_id = s->regs[reg_num];
998
+
999
+ if (FIELD_EX32(dlc_reg_val, TB0_DLC_REGISTER, FDF)) {
1000
+ /*
1001
+ * CANFD frame.
1002
+ * Converting dlc(0 to 15) 4 Byte data to plain length(i.e. 0 to 64)
1003
+ * 1 Byte data. This is done to make it work with SocketCAN.
1004
+ * On actual CANFD frame, this value can't be more than 0xF.
1005
+ * Conversion table for DLC to plain length:
1006
+ *
1007
+ * DLC Plain Length
1008
+ * 0 - 8 0 - 8
1009
+ * 9 9 - 12
1010
+ * 10 13 - 16
1011
+ * 11 17 - 20
1012
+ * 12 21 - 24
1013
+ * 13 25 - 32
1014
+ * 14 33 - 48
1015
+ * 15 49 - 64
1016
+ */
1017
+
1018
+ frame->flags = QEMU_CAN_FRMF_TYPE_FD;
1019
+
1020
+ if (dlc_value < 8) {
1021
+ frame->can_dlc = dlc_value;
1022
+ } else {
1023
+ assert((dlc_value - 8) < ARRAY_SIZE(canfd_dlc_array));
1024
+ frame->can_dlc = canfd_dlc_array[dlc_value - 8];
1025
+ }
1026
+ } else {
1027
+ /*
1028
+ * FD Format bit not set that means it is a CAN Frame.
1029
+ * Conversion table for classic CAN:
1030
+ *
1031
+ * DLC Plain Length
1032
+ * 0 - 7 0 - 7
1033
+ * 8 - 15 8
1034
+ */
1035
+
1036
+ if (dlc_value > 8) {
1037
+ frame->can_dlc = 8;
1038
+ qemu_log_mask(LOG_GUEST_ERROR, "Maximum DLC value for Classic CAN"
1039
+ " frame is 8. Only 8 byte data will be sent.\n");
1040
+ } else {
1041
+ frame->can_dlc = dlc_value;
1042
+ }
1043
+ }
1044
+
1045
+ for (j = 0; j < frame->can_dlc; j++) {
1046
+ val = 8 * i;
1047
+
1048
+ frame->data[j] = extract32(s->regs[reg_num + 2 + (j / 4)], val, 8);
1049
+ i++;
1050
+
1051
+ if (i % 4 == 0) {
1052
+ i = 0;
1053
+ }
1054
+ }
1055
+}
1056
+
1057
+static void process_cancellation_requests(XlnxVersalCANFDState *s)
1058
+{
1059
+ uint32_t clear_mask = s->regs[R_TX_BUFFER_READY_REQUEST_REGISTER] &
1060
+ s->regs[R_TX_BUFFER_CANCEL_REQUEST_REGISTER];
1061
+
1062
+ s->regs[R_TX_BUFFER_READY_REQUEST_REGISTER] &= ~clear_mask;
1063
+ s->regs[R_TX_BUFFER_CANCEL_REQUEST_REGISTER] &= ~clear_mask;
1064
+
1065
+ canfd_update_irq(s);
1066
+}
1067
+
1068
+static void store_rx_sequential(XlnxVersalCANFDState *s,
1069
+ const qemu_can_frame *frame,
1070
+ uint32_t fill_level, uint32_t read_index,
1071
+ uint32_t store_location, uint8_t rx_fifo,
1072
+ bool rx_fifo_id, uint8_t filter_index)
1073
+{
1074
+ int i;
1075
+ bool is_canfd_frame;
1076
+ uint8_t dlc = frame->can_dlc;
1077
+ uint8_t rx_reg_num = 0;
1078
+ uint32_t dlc_reg_val = 0;
1079
+ uint32_t data_reg_val = 0;
1080
+
1081
+ /* Getting RX0/1 fill level */
1082
+ if ((fill_level) > rx_fifo - 1) {
1083
+ g_autofree char *path = object_get_canonical_path(OBJECT(s));
1084
+
1085
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: RX%d Buffer is full. Discarding the"
1086
+ " message\n", path, rx_fifo_id);
1087
+
1088
+ /* Set the corresponding RF buffer overflow interrupt. */
1089
+ if (rx_fifo_id == 0) {
1090
+ ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXFOFLW, 1);
1091
+ } else {
1092
+ ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXFOFLW_1, 1);
1093
+ }
1094
+ } else {
1095
+ uint16_t rx_timestamp = CANFD_TIMER_MAX -
1096
+ ptimer_get_count(s->canfd_timer);
1097
+
1098
+ if (rx_timestamp == 0xFFFF) {
1099
+ ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, TSCNT_OFLW, 1);
1100
+ } else {
1101
+ ARRAY_FIELD_DP32(s->regs, TIMESTAMP_REGISTER, TIMESTAMP_CNT,
1102
+ rx_timestamp);
1103
+ }
1104
+
1105
+ if (rx_fifo_id == 0) {
1106
+ ARRAY_FIELD_DP32(s->regs, RX_FIFO_STATUS_REGISTER, FL,
1107
+ fill_level + 1);
1108
+ assert(store_location <=
1109
+ R_RB_ID_REGISTER + (s->cfg.rx0_fifo *
1110
+ NUM_REGS_PER_MSG_SPACE));
1111
+ } else {
1112
+ ARRAY_FIELD_DP32(s->regs, RX_FIFO_STATUS_REGISTER, FL_1,
1113
+ fill_level + 1);
1114
+ assert(store_location <=
1115
+ R_RB_ID_REGISTER_1 + (s->cfg.rx1_fifo *
1116
+ NUM_REGS_PER_MSG_SPACE));
1117
+ }
1118
+
1119
+ s->regs[store_location] = frame->can_id;
1120
+
1121
+ dlc = frame->can_dlc;
1122
+
1123
+ if (frame->flags == QEMU_CAN_FRMF_TYPE_FD) {
1124
+ is_canfd_frame = true;
1125
+
1126
+ /* Store dlc value in Xilinx specific format. */
1127
+ for (i = 0; i < ARRAY_SIZE(canfd_dlc_array); i++) {
1128
+ if (canfd_dlc_array[i] == frame->can_dlc) {
1129
+ dlc_reg_val = FIELD_DP32(0, RB_DLC_REGISTER, DLC, 8 + i);
1130
+ }
1131
+ }
1132
+ } else {
1133
+ is_canfd_frame = false;
1134
+
1135
+ if (frame->can_dlc > 8) {
1136
+ dlc = 8;
1137
+ }
1138
+
1139
+ dlc_reg_val = FIELD_DP32(0, RB_DLC_REGISTER, DLC, dlc);
1140
+ }
1141
+
1142
+ dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, FDF, is_canfd_frame);
1143
+ dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, TIMESTAMP, rx_timestamp);
1144
+ dlc_reg_val |= FIELD_DP32(0, RB_DLC_REGISTER, MATCHED_FILTER_INDEX,
1145
+ filter_index);
1146
+ s->regs[store_location + 1] = dlc_reg_val;
1147
+
1148
+ for (i = 0; i < dlc; i++) {
1149
+ /* Register size is 4 byte but frame->data each is 1 byte. */
1150
+ switch (i % 4) {
1151
+ case 0:
1152
+ rx_reg_num = i / 4;
1153
+
1154
+ data_reg_val = FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES3,
1155
+ frame->data[i]);
1156
+ break;
1157
+ case 1:
1158
+ data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES2,
1159
+ frame->data[i]);
1160
+ break;
1161
+ case 2:
1162
+ data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES1,
1163
+ frame->data[i]);
1164
+ break;
1165
+ case 3:
1166
+ data_reg_val |= FIELD_DP32(0, RB_DW0_REGISTER, DATA_BYTES0,
1167
+ frame->data[i]);
1168
+ /*
1169
+ * Last Bytes data which means we have all 4 bytes ready to
1170
+ * store in one rx regs.
1171
+ */
1172
+ s->regs[store_location + rx_reg_num + 2] = data_reg_val;
1173
+ break;
1174
+ }
1175
+ }
1176
+
1177
+ if (i % 4) {
1178
+ /*
1179
+ * In case DLC is not multiplier of 4, data is not saved to RX FIFO
1180
+ * in above switch case. Store the remaining bytes here.
1181
+ */
1182
+ s->regs[store_location + rx_reg_num + 2] = data_reg_val;
1183
+ }
1184
+
1185
+ /* set the interrupt as RXOK. */
1186
+ ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXOK, 1);
1187
+ }
1188
+}
1189
+
1190
+static void update_rx_sequential(XlnxVersalCANFDState *s,
1191
+ const qemu_can_frame *frame)
1192
+{
1193
+ bool filter_pass = false;
1194
+ uint8_t filter_index = 0;
1195
+ int i;
1196
+ int filter_partition = ARRAY_FIELD_EX32(s->regs,
1197
+ RX_FIFO_WATERMARK_REGISTER, RXFP);
1198
+ uint32_t store_location;
1199
+ uint32_t fill_level;
1200
+ uint32_t read_index;
1201
+ uint8_t store_index = 0;
1202
+ g_autofree char *path = NULL;
1203
+ /*
1204
+ * If all UAF bits are set to 0, then received messages are not stored
1205
+ * in the RX buffers.
1206
+ */
1207
+ if (s->regs[R_ACCEPTANCE_FILTER_CONTROL_REGISTER]) {
1208
+ uint32_t acceptance_filter_status =
1209
+ s->regs[R_ACCEPTANCE_FILTER_CONTROL_REGISTER];
1210
+
1211
+ for (i = 0; i < 32; i++) {
1212
+ if (acceptance_filter_status & 0x1) {
1213
+ uint32_t msg_id_masked = s->regs[R_AFMR_REGISTER + 2 * i] &
1214
+ frame->can_id;
1215
+ uint32_t afir_id_masked = s->regs[R_AFIR_REGISTER + 2 * i] &
1216
+ s->regs[R_AFMR_REGISTER + 2 * i];
1217
+ uint16_t std_msg_id_masked = FIELD_EX32(msg_id_masked,
1218
+ AFIR_REGISTER, AIID);
1219
+ uint16_t std_afir_id_masked = FIELD_EX32(afir_id_masked,
1220
+ AFIR_REGISTER, AIID);
1221
+ uint32_t ext_msg_id_masked = FIELD_EX32(msg_id_masked,
1222
+ AFIR_REGISTER,
1223
+ AIID_EXT);
1224
+ uint32_t ext_afir_id_masked = FIELD_EX32(afir_id_masked,
1225
+ AFIR_REGISTER,
1226
+ AIID_EXT);
1227
+ bool ext_ide = FIELD_EX32(s->regs[R_AFMR_REGISTER + 2 * i],
1228
+ AFMR_REGISTER, AMIDE);
1229
+
1230
+ if (std_msg_id_masked == std_afir_id_masked) {
1231
+ if (ext_ide) {
1232
+ /* Extended message ID message. */
1233
+ if (ext_msg_id_masked == ext_afir_id_masked) {
1234
+ filter_pass = true;
1235
+ filter_index = i;
1236
+
1237
+ break;
1238
+ }
1239
+ } else {
1240
+ /* Standard message ID. */
1241
+ filter_pass = true;
1242
+ filter_index = i;
1243
+
1244
+ break;
1245
+ }
1246
+ }
1247
+ }
1248
+ acceptance_filter_status >>= 1;
1249
+ }
1250
+ }
1251
+
1252
+ if (!filter_pass) {
1253
+ path = object_get_canonical_path(OBJECT(s));
1254
+
1255
+ trace_xlnx_canfd_rx_fifo_filter_reject(path, frame->can_id,
1256
+ frame->can_dlc);
1257
+ } else {
1258
+ if (filter_index <= filter_partition) {
1259
+ fill_level = ARRAY_FIELD_EX32(s->regs, RX_FIFO_STATUS_REGISTER, FL);
1260
+ read_index = ARRAY_FIELD_EX32(s->regs, RX_FIFO_STATUS_REGISTER, RI);
1261
+ store_index = read_index + fill_level;
1262
+
1263
+ if (read_index == s->cfg.rx0_fifo - 1) {
1264
+ /*
1265
+ * When ri is s->cfg.rx0_fifo - 1 i.e. max, it goes cyclic that
1266
+ * means we reset the ri to 0x0.
1267
+ */
1268
+ read_index = 0;
1269
+ ARRAY_FIELD_DP32(s->regs, RX_FIFO_STATUS_REGISTER, RI,
1270
+ read_index);
1271
+ }
1272
+
1273
+ if (store_index > s->cfg.rx0_fifo - 1) {
1274
+ store_index -= s->cfg.rx0_fifo - 1;
1275
+ }
1276
+
1277
+ store_location = R_RB_ID_REGISTER +
1278
+ (store_index * NUM_REGS_PER_MSG_SPACE);
1279
+
1280
+ store_rx_sequential(s, frame, fill_level, read_index,
1281
+ store_location, s->cfg.rx0_fifo, 0,
1282
+ filter_index);
1283
+ } else {
1284
+ /* RX 1 fill level message */
1285
+ fill_level = ARRAY_FIELD_EX32(s->regs, RX_FIFO_STATUS_REGISTER,
1286
+ FL_1);
1287
+ read_index = ARRAY_FIELD_EX32(s->regs, RX_FIFO_STATUS_REGISTER,
1288
+ RI_1);
1289
+ store_index = read_index + fill_level;
1290
+
1291
+ if (read_index == s->cfg.rx1_fifo - 1) {
1292
+ /*
1293
+ * When ri is s->cfg.rx1_fifo - 1 i.e. max, it goes cyclic that
1294
+ * means we reset the ri to 0x0.
1295
+ */
1296
+ read_index = 0;
1297
+ ARRAY_FIELD_DP32(s->regs, RX_FIFO_STATUS_REGISTER, RI_1,
1298
+ read_index);
1299
+ }
1300
+
1301
+ if (store_index > s->cfg.rx1_fifo - 1) {
1302
+ store_index -= s->cfg.rx1_fifo - 1;
1303
+ }
1304
+
1305
+ store_location = R_RB_ID_REGISTER_1 +
1306
+ (store_index * NUM_REGS_PER_MSG_SPACE);
1307
+
1308
+ store_rx_sequential(s, frame, fill_level, read_index,
1309
+ store_location, s->cfg.rx1_fifo, 1,
1310
+ filter_index);
1311
+ }
1312
+
1313
+ path = object_get_canonical_path(OBJECT(s));
1314
+
1315
+ trace_xlnx_canfd_rx_data(path, frame->can_id, frame->can_dlc,
1316
+ frame->flags);
1317
+ canfd_update_irq(s);
1318
+ }
1319
+}
1320
+
1321
+static bool tx_ready_check(XlnxVersalCANFDState *s)
1322
+{
1323
+ if (ARRAY_FIELD_EX32(s->regs, SOFTWARE_RESET_REGISTER, SRST)) {
1324
+ g_autofree char *path = object_get_canonical_path(OBJECT(s));
1325
+
1326
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Attempting to transfer data while"
1327
+ " XlnxVersalCANFDState is in reset mode\n", path);
1328
+
1329
+ return false;
1330
+ }
1331
+
1332
+ if (ARRAY_FIELD_EX32(s->regs, SOFTWARE_RESET_REGISTER, CEN) == 0) {
1333
+ g_autofree char *path = object_get_canonical_path(OBJECT(s));
1334
+
1335
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Attempting to transfer data while"
1336
+ " XlnxVersalCANFDState is in configuration mode."
1337
+ " Reset the core so operations can start fresh\n",
1338
+ path);
1339
+ return false;
1340
+ }
1341
+
1342
+ if (ARRAY_FIELD_EX32(s->regs, MODE_SELECT_REGISTER, SNOOP)) {
1343
+ g_autofree char *path = object_get_canonical_path(OBJECT(s));
1344
+
1345
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Attempting to transfer data while"
1346
+ " XlnxVersalCANFDState is in SNOOP MODE\n",
1347
+ path);
1348
+ return false;
1349
+ }
1350
+
1351
+ return true;
1352
+}
1353
+
1354
+static void tx_fifo_stamp(XlnxVersalCANFDState *s, uint32_t tb0_regid)
1355
+{
1356
+ /*
1357
+ * If EFC bit in DLC message is set, this means we will store the
1358
+ * event of this transmitted message with time stamp.
1359
+ */
1360
+ uint32_t dlc_reg_val = 0;
1361
+
1362
+ if (FIELD_EX32(s->regs[tb0_regid + 1], TB0_DLC_REGISTER, EFC)) {
1363
+ uint8_t dlc_val = FIELD_EX32(s->regs[tb0_regid + 1], TB0_DLC_REGISTER,
1364
+ DLC);
1365
+ bool fdf_val = FIELD_EX32(s->regs[tb0_regid + 1], TB0_DLC_REGISTER,
1366
+ FDF);
1367
+ bool brs_val = FIELD_EX32(s->regs[tb0_regid + 1], TB0_DLC_REGISTER,
1368
+ BRS);
1369
+ uint8_t mm_val = FIELD_EX32(s->regs[tb0_regid + 1], TB0_DLC_REGISTER,
1370
+ MM);
1371
+ uint8_t fill_level = ARRAY_FIELD_EX32(s->regs,
1372
+ TX_EVENT_FIFO_STATUS_REGISTER,
1373
+ TXE_FL);
1374
+ uint8_t read_index = ARRAY_FIELD_EX32(s->regs,
1375
+ TX_EVENT_FIFO_STATUS_REGISTER,
1376
+ TXE_RI);
1377
+ uint8_t store_index = fill_level + read_index;
1378
+
1379
+ if ((fill_level) > s->cfg.tx_fifo - 1) {
1380
+ qemu_log_mask(LOG_GUEST_ERROR, "TX Event Buffer is full."
1381
+ " Discarding the message\n");
1382
+ ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, TXEOFLW, 1);
1383
+ } else {
1384
+ if (read_index == s->cfg.tx_fifo - 1) {
1385
+ /*
1386
+ * When ri is s->cfg.tx_fifo - 1 i.e. max, it goes cyclic that
1387
+ * means we reset the ri to 0x0.
1388
+ */
1389
+ read_index = 0;
1390
+ ARRAY_FIELD_DP32(s->regs, TX_EVENT_FIFO_STATUS_REGISTER, TXE_RI,
1391
+ read_index);
1392
+ }
1393
+
1394
+ if (store_index > s->cfg.tx_fifo - 1) {
1395
+ store_index -= s->cfg.tx_fifo - 1;
1396
+ }
1397
+
1398
+ assert(store_index < s->cfg.tx_fifo);
1399
+
1400
+ uint32_t tx_event_reg0_id = R_TXE_FIFO_TB_ID_REGISTER +
1401
+ (store_index * 2);
1402
+
1403
+ /* Store message ID in TX event register. */
1404
+ s->regs[tx_event_reg0_id] = s->regs[tb0_regid];
1405
+
1406
+ uint16_t tx_timestamp = CANFD_TIMER_MAX -
1407
+ ptimer_get_count(s->canfd_timer);
1408
+
1409
+ /* Store DLC with time stamp in DLC regs. */
1410
+ dlc_reg_val = FIELD_DP32(0, TXE_FIFO_TB_DLC_REGISTER, DLC, dlc_val);
1411
+ dlc_reg_val |= FIELD_DP32(0, TXE_FIFO_TB_DLC_REGISTER, FDF,
1412
+ fdf_val);
1413
+ dlc_reg_val |= FIELD_DP32(0, TXE_FIFO_TB_DLC_REGISTER, BRS,
1414
+ brs_val);
1415
+ dlc_reg_val |= FIELD_DP32(0, TXE_FIFO_TB_DLC_REGISTER, ET, 0x3);
1416
+ dlc_reg_val |= FIELD_DP32(0, TXE_FIFO_TB_DLC_REGISTER, MM, mm_val);
1417
+ dlc_reg_val |= FIELD_DP32(0, TXE_FIFO_TB_DLC_REGISTER, TIMESTAMP,
1418
+ tx_timestamp);
1419
+ s->regs[tx_event_reg0_id + 1] = dlc_reg_val;
1420
+
1421
+ ARRAY_FIELD_DP32(s->regs, TX_EVENT_FIFO_STATUS_REGISTER, TXE_FL,
1422
+ fill_level + 1);
1423
+ }
1424
+ }
1425
+}
1426
+
1427
+static gint g_cmp_ids(gconstpointer data1, gconstpointer data2)
1428
+{
1429
+ tx_ready_reg_info *tx_reg_1 = (tx_ready_reg_info *) data1;
1430
+ tx_ready_reg_info *tx_reg_2 = (tx_ready_reg_info *) data2;
1431
+
1432
+ return tx_reg_1->can_id - tx_reg_2->can_id;
1433
+}
1434
+
1435
+static void free_list(GSList *list)
1436
+{
1437
+ GSList *iterator = NULL;
1438
+
1439
+ for (iterator = list; iterator != NULL; iterator = iterator->next) {
1440
+ g_free((tx_ready_reg_info *)iterator->data);
1441
+ }
1442
+
1443
+ g_slist_free(list);
1444
+
1445
+ return;
1446
+}
1447
+
1448
+static GSList *prepare_tx_data(XlnxVersalCANFDState *s)
1449
+{
1450
+ uint8_t i = 0;
1451
+ GSList *list = NULL;
1452
+ uint32_t reg_num = 0;
1453
+ uint32_t reg_ready = s->regs[R_TX_BUFFER_READY_REQUEST_REGISTER];
1454
+
1455
+ /* First find the messages which are ready for transmission. */
1456
+ for (i = 0; i < s->cfg.tx_fifo; i++) {
1457
+ if (reg_ready & 1) {
1458
+ reg_num = R_TB_ID_REGISTER + (NUM_REGS_PER_MSG_SPACE * i);
1459
+ tx_ready_reg_info *temp = g_new(tx_ready_reg_info, 1);
1460
+
1461
+ temp->can_id = s->regs[reg_num];
1462
+ temp->reg_num = reg_num;
1463
+ list = g_slist_prepend(list, temp);
1464
+ list = g_slist_sort(list, g_cmp_ids);
1465
+ }
1466
+
1467
+ reg_ready >>= 1;
1468
+ }
1469
+
1470
+ s->regs[R_TX_BUFFER_READY_REQUEST_REGISTER] = 0;
1471
+ s->regs[R_TX_BUFFER_CANCEL_REQUEST_REGISTER] = 0;
1472
+
1473
+ return list;
1474
+}
1475
+
1476
+static void transfer_data(XlnxVersalCANFDState *s)
1477
+{
1478
+ bool canfd_tx = tx_ready_check(s);
1479
+ GSList *list, *iterator = NULL;
1480
+ qemu_can_frame frame;
1481
+
1482
+ if (!canfd_tx) {
1483
+ g_autofree char *path = object_get_canonical_path(OBJECT(s));
1484
+
1485
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Controller not enabled for data"
1486
+ " transfer\n", path);
1487
+ return;
1488
+ }
1489
+
1490
+ list = prepare_tx_data(s);
1491
+ if (list == NULL) {
1492
+ return;
1493
+ }
1494
+
1495
+ for (iterator = list; iterator != NULL; iterator = iterator->next) {
1496
+ regs2frame(s, &frame,
1497
+ ((tx_ready_reg_info *)iterator->data)->reg_num);
1498
+
1499
+ if (ARRAY_FIELD_EX32(s->regs, STATUS_REGISTER, LBACK)) {
1500
+ update_rx_sequential(s, &frame);
1501
+ tx_fifo_stamp(s, ((tx_ready_reg_info *)iterator->data)->reg_num);
1502
+
1503
+ ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXOK, 1);
1504
+ } else {
1505
+ g_autofree char *path = object_get_canonical_path(OBJECT(s));
1506
+
1507
+ trace_xlnx_canfd_tx_data(path, frame.can_id, frame.can_dlc,
1508
+ frame.flags);
1509
+ can_bus_client_send(&s->bus_client, &frame, 1);
1510
+ tx_fifo_stamp(s,
1511
+ ((tx_ready_reg_info *)iterator->data)->reg_num);
1512
+
1513
+ ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, TXRRS, 1);
1514
+
1515
+ if (ARRAY_FIELD_EX32(s->regs, STATUS_REGISTER, SLEEP)) {
1516
+ canfd_exit_sleep_mode(s);
1517
+ }
1518
+ }
1519
+ }
1520
+
1521
+ ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, TXOK, 1);
1522
+ free_list(list);
1523
+
1524
+ canfd_update_irq(s);
1525
+}
1526
+
1527
+static uint64_t canfd_srr_pre_write(RegisterInfo *reg, uint64_t val64)
1528
+{
1529
+ XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
1530
+ uint32_t val = val64;
1531
+
1532
+ ARRAY_FIELD_DP32(s->regs, SOFTWARE_RESET_REGISTER, CEN,
1533
+ FIELD_EX32(val, SOFTWARE_RESET_REGISTER, CEN));
1534
+
1535
+ if (FIELD_EX32(val, SOFTWARE_RESET_REGISTER, SRST)) {
1536
+ g_autofree char *path = object_get_canonical_path(OBJECT(s));
1537
+
1538
+ trace_xlnx_canfd_reset(path, val64);
1539
+
1540
+ /* First, core will do software reset then will enter in config mode. */
1541
+ canfd_config_reset(s);
1542
+ } else if (ARRAY_FIELD_EX32(s->regs, SOFTWARE_RESET_REGISTER, CEN) == 0) {
1543
+ canfd_config_mode(s);
1544
+ } else {
1545
+ /*
1546
+ * Leave config mode. Now XlnxVersalCANFD core will enter Normal, Sleep,
1547
+ * snoop or Loopback mode depending upon LBACK, SLEEP, SNOOP register
1548
+ * states.
1549
+ */
1550
+ ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, CONFIG, 0);
1551
+
1552
+ ptimer_transaction_begin(s->canfd_timer);
1553
+ ptimer_set_count(s->canfd_timer, 0);
1554
+ ptimer_transaction_commit(s->canfd_timer);
1555
+ update_status_register_mode_bits(s);
1556
+ transfer_data(s);
1557
+ }
1558
+
1559
+ return s->regs[R_SOFTWARE_RESET_REGISTER];
1560
+}
1561
+
1562
+static uint64_t filter_mask(RegisterInfo *reg, uint64_t val64)
1563
+{
1564
+ XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
1565
+ uint32_t reg_idx = (reg->access->addr) / 4;
1566
+ uint32_t val = val64;
1567
+ uint32_t filter_offset = (reg_idx - R_AFMR_REGISTER) / 2;
1568
+
1569
+ if (!(s->regs[R_ACCEPTANCE_FILTER_CONTROL_REGISTER] &
1570
+ (1 << filter_offset))) {
1571
+ s->regs[reg_idx] = val;
1572
+ } else {
1573
+ g_autofree char *path = object_get_canonical_path(OBJECT(s));
1574
+
1575
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Acceptance filter %d not enabled\n",
1576
+ path, filter_offset + 1);
1577
+ }
1578
+
1579
+ return s->regs[reg_idx];
1580
+}
1581
+
1582
+static uint64_t filter_id(RegisterInfo *reg, uint64_t val64)
1583
+{
1584
+ XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
1585
+ hwaddr reg_idx = (reg->access->addr) / 4;
1586
+ uint32_t val = val64;
1587
+ uint32_t filter_offset = (reg_idx - R_AFIR_REGISTER) / 2;
1588
+
1589
+ if (!(s->regs[R_ACCEPTANCE_FILTER_CONTROL_REGISTER] &
1590
+ (1 << filter_offset))) {
1591
+ s->regs[reg_idx] = val;
1592
+ } else {
1593
+ g_autofree char *path = object_get_canonical_path(OBJECT(s));
1594
+
1595
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Acceptance filter %d not enabled\n",
1596
+ path, filter_offset + 1);
1597
+ }
1598
+
1599
+ return s->regs[reg_idx];
1600
+}
1601
+
1602
+static uint64_t canfd_tx_fifo_status_prew(RegisterInfo *reg, uint64_t val64)
1603
+{
1604
+ XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
1605
+ uint32_t val = val64;
1606
+ uint8_t read_ind = 0;
1607
+ uint8_t fill_ind = ARRAY_FIELD_EX32(s->regs, TX_EVENT_FIFO_STATUS_REGISTER,
1608
+ TXE_FL);
1609
+
1610
+ if (FIELD_EX32(val, TX_EVENT_FIFO_STATUS_REGISTER, TXE_IRI) && fill_ind) {
1611
+ read_ind = ARRAY_FIELD_EX32(s->regs, TX_EVENT_FIFO_STATUS_REGISTER,
1612
+ TXE_RI) + 1;
1613
+
1614
+ if (read_ind > s->cfg.tx_fifo - 1) {
1615
+ read_ind = 0;
1616
+ }
1617
+
1618
+ /*
1619
+ * Increase the read index by 1 and decrease the fill level by 1.
1620
+ */
1621
+ ARRAY_FIELD_DP32(s->regs, TX_EVENT_FIFO_STATUS_REGISTER, TXE_RI,
1622
+ read_ind);
1623
+ ARRAY_FIELD_DP32(s->regs, TX_EVENT_FIFO_STATUS_REGISTER, TXE_FL,
1624
+ fill_ind - 1);
1625
+ }
1626
+
1627
+ return s->regs[R_TX_EVENT_FIFO_STATUS_REGISTER];
1628
+}
1629
+
1630
+static uint64_t canfd_rx_fifo_status_prew(RegisterInfo *reg, uint64_t val64)
1631
+{
1632
+ XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
1633
+ uint32_t val = val64;
1634
+ uint8_t read_ind = 0;
1635
+ uint8_t fill_ind = 0;
1636
+
1637
+ if (FIELD_EX32(val, RX_FIFO_STATUS_REGISTER, IRI)) {
1638
+ /* FL index is zero, setting IRI bit has no effect. */
1639
+ if (FIELD_EX32(val, RX_FIFO_STATUS_REGISTER, FL) != 0) {
1640
+ read_ind = FIELD_EX32(val, RX_FIFO_STATUS_REGISTER, RI) + 1;
1641
+
1642
+ if (read_ind > s->cfg.rx0_fifo - 1) {
1643
+ read_ind = 0;
1644
+ }
1645
+
1646
+ fill_ind = FIELD_EX32(val, RX_FIFO_STATUS_REGISTER, FL) - 1;
1647
+
1648
+ ARRAY_FIELD_DP32(s->regs, RX_FIFO_STATUS_REGISTER, RI, read_ind);
1649
+ ARRAY_FIELD_DP32(s->regs, RX_FIFO_STATUS_REGISTER, FL, fill_ind);
1650
+ }
1651
+ }
1652
+
1653
+ if (FIELD_EX32(val, RX_FIFO_STATUS_REGISTER, IRI_1)) {
1654
+ /* FL_1 index is zero, setting IRI_1 bit has no effect. */
1655
+ if (FIELD_EX32(val, RX_FIFO_STATUS_REGISTER, FL_1) != 0) {
1656
+ read_ind = FIELD_EX32(val, RX_FIFO_STATUS_REGISTER, RI_1) + 1;
1657
+
1658
+ if (read_ind > s->cfg.rx1_fifo - 1) {
1659
+ read_ind = 0;
1660
+ }
1661
+
1662
+ fill_ind = FIELD_EX32(val, RX_FIFO_STATUS_REGISTER, FL_1) - 1;
1663
+
1664
+ ARRAY_FIELD_DP32(s->regs, RX_FIFO_STATUS_REGISTER, RI_1, read_ind);
1665
+ ARRAY_FIELD_DP32(s->regs, RX_FIFO_STATUS_REGISTER, FL_1, fill_ind);
1666
+ }
1667
+ }
1668
+
1669
+ return s->regs[R_RX_FIFO_STATUS_REGISTER];
1670
+}
1671
+
1672
+static uint64_t canfd_tsr_pre_write(RegisterInfo *reg, uint64_t val64)
1673
+{
1674
+ XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
1675
+ uint32_t val = val64;
1676
+
1677
+ if (FIELD_EX32(val, TIMESTAMP_REGISTER, CTS)) {
1678
+ ARRAY_FIELD_DP32(s->regs, TIMESTAMP_REGISTER, TIMESTAMP_CNT, 0);
1679
+ ptimer_transaction_begin(s->canfd_timer);
1680
+ ptimer_set_count(s->canfd_timer, 0);
1681
+ ptimer_transaction_commit(s->canfd_timer);
1682
+ }
1683
+
1684
+ return 0;
1685
+}
1686
+
1687
+static uint64_t canfd_trr_reg_prew(RegisterInfo *reg, uint64_t val64)
1688
+{
1689
+ XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
1690
+
1691
+ if (ARRAY_FIELD_EX32(s->regs, MODE_SELECT_REGISTER, SNOOP)) {
1692
+ g_autofree char *path = object_get_canonical_path(OBJECT(s));
1693
+
1694
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: Controller is in SNOOP mode."
1695
+ " tx_ready_register will stay in reset mode\n", path);
1696
+ return 0;
1697
+ } else {
1698
+ return val64;
1699
+ }
1700
+}
1701
+
1702
+static void canfd_trr_reg_postw(RegisterInfo *reg, uint64_t val64)
1703
+{
1704
+ XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
1705
+
1706
+ transfer_data(s);
1707
+}
1708
+
1709
+static void canfd_cancel_reg_postw(RegisterInfo *reg, uint64_t val64)
1710
+{
1711
+ XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
1712
+
1713
+ process_cancellation_requests(s);
1714
+}
1715
+
1716
+static uint64_t canfd_write_check_prew(RegisterInfo *reg, uint64_t val64)
1717
+{
1718
+ XlnxVersalCANFDState *s = XILINX_CANFD(reg->opaque);
1719
+ uint32_t val = val64;
1720
+
1721
+ if (ARRAY_FIELD_EX32(s->regs, SOFTWARE_RESET_REGISTER, CEN) == 0) {
1722
+ return val;
1723
+ }
1724
+ return 0;
1725
+}
1726
+
1727
+static const RegisterAccessInfo canfd_tx_regs[] = {
1728
+ { .name = "TB_ID_REGISTER", .addr = A_TB_ID_REGISTER,
1729
+ },{ .name = "TB0_DLC_REGISTER", .addr = A_TB0_DLC_REGISTER,
1730
+ },{ .name = "TB_DW0_REGISTER", .addr = A_TB_DW0_REGISTER,
1731
+ },{ .name = "TB_DW1_REGISTER", .addr = A_TB_DW1_REGISTER,
1732
+ },{ .name = "TB_DW2_REGISTER", .addr = A_TB_DW2_REGISTER,
1733
+ },{ .name = "TB_DW3_REGISTER", .addr = A_TB_DW3_REGISTER,
1734
+ },{ .name = "TB_DW4_REGISTER", .addr = A_TB_DW4_REGISTER,
1735
+ },{ .name = "TB_DW5_REGISTER", .addr = A_TB_DW5_REGISTER,
1736
+ },{ .name = "TB_DW6_REGISTER", .addr = A_TB_DW6_REGISTER,
1737
+ },{ .name = "TB_DW7_REGISTER", .addr = A_TB_DW7_REGISTER,
1738
+ },{ .name = "TB_DW8_REGISTER", .addr = A_TB_DW8_REGISTER,
1739
+ },{ .name = "TB_DW9_REGISTER", .addr = A_TB_DW9_REGISTER,
1740
+ },{ .name = "TB_DW10_REGISTER", .addr = A_TB_DW10_REGISTER,
1741
+ },{ .name = "TB_DW11_REGISTER", .addr = A_TB_DW11_REGISTER,
1742
+ },{ .name = "TB_DW12_REGISTER", .addr = A_TB_DW12_REGISTER,
1743
+ },{ .name = "TB_DW13_REGISTER", .addr = A_TB_DW13_REGISTER,
1744
+ },{ .name = "TB_DW14_REGISTER", .addr = A_TB_DW14_REGISTER,
1745
+ },{ .name = "TB_DW15_REGISTER", .addr = A_TB_DW15_REGISTER,
1746
+ }
1747
+};
1748
+
1749
+static const RegisterAccessInfo canfd_rx0_regs[] = {
1750
+ { .name = "RB_ID_REGISTER", .addr = A_RB_ID_REGISTER,
1751
+ .ro = 0xffffffff,
1752
+ },{ .name = "RB_DLC_REGISTER", .addr = A_RB_DLC_REGISTER,
1753
+ .ro = 0xfe1fffff,
1754
+ },{ .name = "RB_DW0_REGISTER", .addr = A_RB_DW0_REGISTER,
1755
+ .ro = 0xffffffff,
1756
+ },{ .name = "RB_DW1_REGISTER", .addr = A_RB_DW1_REGISTER,
1757
+ .ro = 0xffffffff,
1758
+ },{ .name = "RB_DW2_REGISTER", .addr = A_RB_DW2_REGISTER,
1759
+ .ro = 0xffffffff,
1760
+ },{ .name = "RB_DW3_REGISTER", .addr = A_RB_DW3_REGISTER,
1761
+ .ro = 0xffffffff,
1762
+ },{ .name = "RB_DW4_REGISTER", .addr = A_RB_DW4_REGISTER,
1763
+ .ro = 0xffffffff,
1764
+ },{ .name = "RB_DW5_REGISTER", .addr = A_RB_DW5_REGISTER,
1765
+ .ro = 0xffffffff,
1766
+ },{ .name = "RB_DW6_REGISTER", .addr = A_RB_DW6_REGISTER,
1767
+ .ro = 0xffffffff,
1768
+ },{ .name = "RB_DW7_REGISTER", .addr = A_RB_DW7_REGISTER,
1769
+ .ro = 0xffffffff,
1770
+ },{ .name = "RB_DW8_REGISTER", .addr = A_RB_DW8_REGISTER,
1771
+ .ro = 0xffffffff,
1772
+ },{ .name = "RB_DW9_REGISTER", .addr = A_RB_DW9_REGISTER,
1773
+ .ro = 0xffffffff,
1774
+ },{ .name = "RB_DW10_REGISTER", .addr = A_RB_DW10_REGISTER,
1775
+ .ro = 0xffffffff,
1776
+ },{ .name = "RB_DW11_REGISTER", .addr = A_RB_DW11_REGISTER,
1777
+ .ro = 0xffffffff,
1778
+ },{ .name = "RB_DW12_REGISTER", .addr = A_RB_DW12_REGISTER,
1779
+ .ro = 0xffffffff,
1780
+ },{ .name = "RB_DW13_REGISTER", .addr = A_RB_DW13_REGISTER,
1781
+ .ro = 0xffffffff,
1782
+ },{ .name = "RB_DW14_REGISTER", .addr = A_RB_DW14_REGISTER,
1783
+ .ro = 0xffffffff,
1784
+ },{ .name = "RB_DW15_REGISTER", .addr = A_RB_DW15_REGISTER,
1785
+ .ro = 0xffffffff,
1786
+ }
1787
+};
1788
+
1789
+static const RegisterAccessInfo canfd_rx1_regs[] = {
1790
+ { .name = "RB_ID_REGISTER_1", .addr = A_RB_ID_REGISTER_1,
1791
+ .ro = 0xffffffff,
1792
+ },{ .name = "RB_DLC_REGISTER_1", .addr = A_RB_DLC_REGISTER_1,
1793
+ .ro = 0xfe1fffff,
1794
+ },{ .name = "RB0_DW0_REGISTER_1", .addr = A_RB0_DW0_REGISTER_1,
1795
+ .ro = 0xffffffff,
1796
+ },{ .name = "RB_DW1_REGISTER_1", .addr = A_RB_DW1_REGISTER_1,
1797
+ .ro = 0xffffffff,
1798
+ },{ .name = "RB_DW2_REGISTER_1", .addr = A_RB_DW2_REGISTER_1,
1799
+ .ro = 0xffffffff,
1800
+ },{ .name = "RB_DW3_REGISTER_1", .addr = A_RB_DW3_REGISTER_1,
1801
+ .ro = 0xffffffff,
1802
+ },{ .name = "RB_DW4_REGISTER_1", .addr = A_RB_DW4_REGISTER_1,
1803
+ .ro = 0xffffffff,
1804
+ },{ .name = "RB_DW5_REGISTER_1", .addr = A_RB_DW5_REGISTER_1,
1805
+ .ro = 0xffffffff,
1806
+ },{ .name = "RB_DW6_REGISTER_1", .addr = A_RB_DW6_REGISTER_1,
1807
+ .ro = 0xffffffff,
1808
+ },{ .name = "RB_DW7_REGISTER_1", .addr = A_RB_DW7_REGISTER_1,
1809
+ .ro = 0xffffffff,
1810
+ },{ .name = "RB_DW8_REGISTER_1", .addr = A_RB_DW8_REGISTER_1,
1811
+ .ro = 0xffffffff,
1812
+ },{ .name = "RB_DW9_REGISTER_1", .addr = A_RB_DW9_REGISTER_1,
1813
+ .ro = 0xffffffff,
1814
+ },{ .name = "RB_DW10_REGISTER_1", .addr = A_RB_DW10_REGISTER_1,
1815
+ .ro = 0xffffffff,
1816
+ },{ .name = "RB_DW11_REGISTER_1", .addr = A_RB_DW11_REGISTER_1,
1817
+ .ro = 0xffffffff,
1818
+ },{ .name = "RB_DW12_REGISTER_1", .addr = A_RB_DW12_REGISTER_1,
1819
+ .ro = 0xffffffff,
1820
+ },{ .name = "RB_DW13_REGISTER_1", .addr = A_RB_DW13_REGISTER_1,
1821
+ .ro = 0xffffffff,
1822
+ },{ .name = "RB_DW14_REGISTER_1", .addr = A_RB_DW14_REGISTER_1,
1823
+ .ro = 0xffffffff,
1824
+ },{ .name = "RB_DW15_REGISTER_1", .addr = A_RB_DW15_REGISTER_1,
1825
+ .ro = 0xffffffff,
1826
+ }
1827
+};
1828
+
1829
+/* Acceptance filter registers. */
1830
+static const RegisterAccessInfo canfd_af_regs[] = {
1831
+ { .name = "AFMR_REGISTER", .addr = A_AFMR_REGISTER,
1832
+ .pre_write = filter_mask,
1833
+ },{ .name = "AFIR_REGISTER", .addr = A_AFIR_REGISTER,
1834
+ .pre_write = filter_id,
1835
+ }
1836
+};
1837
+
1838
+static const RegisterAccessInfo canfd_txe_regs[] = {
1839
+ { .name = "TXE_FIFO_TB_ID_REGISTER", .addr = A_TXE_FIFO_TB_ID_REGISTER,
1840
+ .ro = 0xffffffff,
1841
+ },{ .name = "TXE_FIFO_TB_DLC_REGISTER", .addr = A_TXE_FIFO_TB_DLC_REGISTER,
1842
+ .ro = 0xffffffff,
1843
+ }
1844
+};
1845
+
1846
+static const RegisterAccessInfo canfd_regs_info[] = {
1847
+ { .name = "SOFTWARE_RESET_REGISTER", .addr = A_SOFTWARE_RESET_REGISTER,
1848
+ .pre_write = canfd_srr_pre_write,
1849
+ },{ .name = "MODE_SELECT_REGISTER", .addr = A_MODE_SELECT_REGISTER,
1850
+ .pre_write = canfd_msr_pre_write,
1851
+ },{ .name = "ARBITRATION_PHASE_BAUD_RATE_PRESCALER_REGISTER",
1852
+ .addr = A_ARBITRATION_PHASE_BAUD_RATE_PRESCALER_REGISTER,
1853
+ .pre_write = canfd_write_check_prew,
1854
+ },{ .name = "ARBITRATION_PHASE_BIT_TIMING_REGISTER",
1855
+ .addr = A_ARBITRATION_PHASE_BIT_TIMING_REGISTER,
1856
+ .pre_write = canfd_write_check_prew,
1857
+ },{ .name = "ERROR_COUNTER_REGISTER", .addr = A_ERROR_COUNTER_REGISTER,
1858
+ .ro = 0xffff,
1859
+ },{ .name = "ERROR_STATUS_REGISTER", .addr = A_ERROR_STATUS_REGISTER,
1860
+ .w1c = 0xf1f,
1861
+ },{ .name = "STATUS_REGISTER", .addr = A_STATUS_REGISTER,
1862
+ .reset = 0x1,
1863
+ .ro = 0x7f17ff,
1864
+ },{ .name = "INTERRUPT_STATUS_REGISTER",
1865
+ .addr = A_INTERRUPT_STATUS_REGISTER,
1866
+ .ro = 0xffffff7f,
1867
+ },{ .name = "INTERRUPT_ENABLE_REGISTER",
1868
+ .addr = A_INTERRUPT_ENABLE_REGISTER,
1869
+ .post_write = canfd_ier_post_write,
1870
+ },{ .name = "INTERRUPT_CLEAR_REGISTER",
1871
+ .addr = A_INTERRUPT_CLEAR_REGISTER, .pre_write = canfd_icr_pre_write,
1872
+ },{ .name = "TIMESTAMP_REGISTER", .addr = A_TIMESTAMP_REGISTER,
1873
+ .ro = 0xffff0000,
1874
+ .pre_write = canfd_tsr_pre_write,
1875
+ },{ .name = "DATA_PHASE_BAUD_RATE_PRESCALER_REGISTER",
1876
+ .addr = A_DATA_PHASE_BAUD_RATE_PRESCALER_REGISTER,
1877
+ .pre_write = canfd_write_check_prew,
1878
+ },{ .name = "DATA_PHASE_BIT_TIMING_REGISTER",
1879
+ .addr = A_DATA_PHASE_BIT_TIMING_REGISTER,
1880
+ .pre_write = canfd_write_check_prew,
1881
+ },{ .name = "TX_BUFFER_READY_REQUEST_REGISTER",
1882
+ .addr = A_TX_BUFFER_READY_REQUEST_REGISTER,
1883
+ .pre_write = canfd_trr_reg_prew,
1884
+ .post_write = canfd_trr_reg_postw,
1885
+ },{ .name = "INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER",
1886
+ .addr = A_INTERRUPT_ENABLE_TX_BUFFER_READY_REQUEST_REGISTER,
1887
+ },{ .name = "TX_BUFFER_CANCEL_REQUEST_REGISTER",
1888
+ .addr = A_TX_BUFFER_CANCEL_REQUEST_REGISTER,
1889
+ .post_write = canfd_cancel_reg_postw,
1890
+ },{ .name = "INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER",
1891
+ .addr = A_INTERRUPT_ENABLE_TX_BUFFER_CANCELLATION_REQUEST_REGISTER,
1892
+ },{ .name = "TX_EVENT_FIFO_STATUS_REGISTER",
1893
+ .addr = A_TX_EVENT_FIFO_STATUS_REGISTER,
1894
+ .ro = 0x3f1f, .pre_write = canfd_tx_fifo_status_prew,
1895
+ },{ .name = "TX_EVENT_FIFO_WATERMARK_REGISTER",
1896
+ .addr = A_TX_EVENT_FIFO_WATERMARK_REGISTER,
1897
+ .reset = 0xf,
1898
+ .pre_write = canfd_write_check_prew,
1899
+ },{ .name = "ACCEPTANCE_FILTER_CONTROL_REGISTER",
1900
+ .addr = A_ACCEPTANCE_FILTER_CONTROL_REGISTER,
1901
+ },{ .name = "RX_FIFO_STATUS_REGISTER", .addr = A_RX_FIFO_STATUS_REGISTER,
1902
+ .ro = 0x7f3f7f3f, .pre_write = canfd_rx_fifo_status_prew,
1903
+ },{ .name = "RX_FIFO_WATERMARK_REGISTER",
1904
+ .addr = A_RX_FIFO_WATERMARK_REGISTER,
1905
+ .reset = 0x1f0f0f,
1906
+ .pre_write = canfd_write_check_prew,
1907
+ }
1908
+};
1909
+
1910
+static void xlnx_versal_canfd_ptimer_cb(void *opaque)
1911
+{
1912
+ /* No action required on the timer rollover. */
1913
+}
1914
+
1915
+static const MemoryRegionOps canfd_ops = {
1916
+ .read = register_read_memory,
1917
+ .write = register_write_memory,
1918
+ .endianness = DEVICE_LITTLE_ENDIAN,
1919
+ .valid = {
1920
+ .min_access_size = 4,
1921
+ .max_access_size = 4,
1922
+ },
1923
+};
1924
+
1925
+static void canfd_reset(DeviceState *dev)
1926
+{
1927
+ XlnxVersalCANFDState *s = XILINX_CANFD(dev);
1928
+ unsigned int i;
1929
+
1930
+ for (i = 0; i < ARRAY_SIZE(s->reg_info); ++i) {
1931
+ register_reset(&s->reg_info[i]);
1932
+ }
1933
+
1934
+ ptimer_transaction_begin(s->canfd_timer);
1935
+ ptimer_set_count(s->canfd_timer, 0);
1936
+ ptimer_transaction_commit(s->canfd_timer);
1937
+}
1938
+
1939
+static bool can_xilinx_canfd_receive(CanBusClientState *client)
1940
+{
1941
+ XlnxVersalCANFDState *s = container_of(client, XlnxVersalCANFDState,
1942
+ bus_client);
1943
+
1944
+ bool reset_state = ARRAY_FIELD_EX32(s->regs, SOFTWARE_RESET_REGISTER, SRST);
1945
+ bool can_enabled = ARRAY_FIELD_EX32(s->regs, SOFTWARE_RESET_REGISTER, CEN);
1946
+
1947
+ return !reset_state && can_enabled;
1948
+}
1949
+
1950
+static ssize_t canfd_xilinx_receive(CanBusClientState *client,
1951
+ const qemu_can_frame *buf,
1952
+ size_t buf_size)
1953
+{
1954
+ XlnxVersalCANFDState *s = container_of(client, XlnxVersalCANFDState,
1955
+ bus_client);
1956
+ const qemu_can_frame *frame = buf;
1957
+
1958
+ assert(buf_size > 0);
1959
+
1960
+ if (ARRAY_FIELD_EX32(s->regs, STATUS_REGISTER, LBACK)) {
1961
+ /*
1962
+ * XlnxVersalCANFDState will not participate in normal bus communication
1963
+ * and does not receive any messages transmitted by other CAN nodes.
1964
+ */
1965
+ return 1;
1966
+ }
1967
+
1968
+ /* Update the status register that we are receiving message. */
1969
+ ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, BBSY, 1);
1970
+
1971
+ if (ARRAY_FIELD_EX32(s->regs, STATUS_REGISTER, SNOOP)) {
1972
+ /* Snoop Mode: Just keep the data. no response back. */
1973
+ update_rx_sequential(s, frame);
1974
+ } else {
1975
+ if ((ARRAY_FIELD_EX32(s->regs, STATUS_REGISTER, SLEEP))) {
1976
+ /*
1977
+ * XlnxVersalCANFDState is in sleep mode. Any data on bus will bring
1978
+ * it to the wake up state.
1979
+ */
1980
+ canfd_exit_sleep_mode(s);
1981
+ }
1982
+
1983
+ update_rx_sequential(s, frame);
1984
+ }
1985
+
1986
+ /* Message processing done. Update the status back to !busy */
1987
+ ARRAY_FIELD_DP32(s->regs, STATUS_REGISTER, BBSY, 0);
1988
+ return 1;
1989
+}
1990
+
1991
+static CanBusClientInfo canfd_xilinx_bus_client_info = {
1992
+ .can_receive = can_xilinx_canfd_receive,
1993
+ .receive = canfd_xilinx_receive,
1994
+};
1995
+
1996
+static int xlnx_canfd_connect_to_bus(XlnxVersalCANFDState *s,
1997
+ CanBusState *bus)
1998
+{
1999
+ s->bus_client.info = &canfd_xilinx_bus_client_info;
2000
+
2001
+ return can_bus_insert_client(bus, &s->bus_client);
2002
+}
2003
+
2004
+#define NUM_REG_PER_AF ARRAY_SIZE(canfd_af_regs)
2005
+#define NUM_AF 32
2006
+#define NUM_REG_PER_TXE ARRAY_SIZE(canfd_txe_regs)
2007
+#define NUM_TXE 32
2008
+
2009
+static int canfd_populate_regarray(XlnxVersalCANFDState *s,
2010
+ RegisterInfoArray *r_array, int pos,
2011
+ const RegisterAccessInfo *rae,
2012
+ int num_rae)
2013
+{
2014
+ int i;
2015
+
2016
+ for (i = 0; i < num_rae; i++) {
2017
+ int index = rae[i].addr / 4;
2018
+ RegisterInfo *r = &s->reg_info[index];
2019
+
2020
+ object_initialize(r, sizeof(*r), TYPE_REGISTER);
2021
+
2022
+ *r = (RegisterInfo) {
2023
+ .data = &s->regs[index],
2024
+ .data_size = sizeof(uint32_t),
2025
+ .access = &rae[i],
2026
+ .opaque = OBJECT(s),
2027
+ };
2028
+
2029
+ r_array->r[i + pos] = r;
2030
+ }
2031
+ return i + pos;
2032
+}
2033
+
2034
+static void canfd_create_rai(RegisterAccessInfo *rai_array,
2035
+ const RegisterAccessInfo *canfd_regs,
2036
+ int template_rai_array_sz,
2037
+ int num_template_to_copy)
2038
+{
2039
+ int i;
2040
+ int reg_num;
2041
+
2042
+ for (reg_num = 0; reg_num < num_template_to_copy; reg_num++) {
2043
+ int pos = reg_num * template_rai_array_sz;
2044
+
2045
+ memcpy(rai_array + pos, canfd_regs,
2046
+ template_rai_array_sz * sizeof(RegisterAccessInfo));
2047
+
2048
+ for (i = 0; i < template_rai_array_sz; i++) {
2049
+ const char *name = canfd_regs[i].name;
2050
+ uint64_t addr = canfd_regs[i].addr;
2051
+ rai_array[i + pos].name = g_strdup_printf("%s%d", name, reg_num);
2052
+ rai_array[i + pos].addr = addr + pos * 4;
2053
+ }
2054
+ }
2055
+}
2056
+
2057
+static RegisterInfoArray *canfd_create_regarray(XlnxVersalCANFDState *s)
2058
+{
2059
+ const char *device_prefix = object_get_typename(OBJECT(s));
2060
+ uint64_t memory_size = XLNX_VERSAL_CANFD_R_MAX * 4;
2061
+ int num_regs;
2062
+ int pos = 0;
2063
+ RegisterInfoArray *r_array;
2064
+
2065
+ num_regs = ARRAY_SIZE(canfd_regs_info) +
2066
+ s->cfg.tx_fifo * NUM_REGS_PER_MSG_SPACE +
2067
+ s->cfg.rx0_fifo * NUM_REGS_PER_MSG_SPACE +
2068
+ NUM_AF * NUM_REG_PER_AF +
2069
+ NUM_TXE * NUM_REG_PER_TXE;
2070
+
2071
+ s->tx_regs = g_new0(RegisterAccessInfo,
2072
+ s->cfg.tx_fifo * ARRAY_SIZE(canfd_tx_regs));
2073
+
2074
+ canfd_create_rai(s->tx_regs, canfd_tx_regs,
2075
+ ARRAY_SIZE(canfd_tx_regs), s->cfg.tx_fifo);
2076
+
2077
+ s->rx0_regs = g_new0(RegisterAccessInfo,
2078
+ s->cfg.rx0_fifo * ARRAY_SIZE(canfd_rx0_regs));
2079
+
2080
+ canfd_create_rai(s->rx0_regs, canfd_rx0_regs,
2081
+ ARRAY_SIZE(canfd_rx0_regs), s->cfg.rx0_fifo);
2082
+
2083
+ s->af_regs = g_new0(RegisterAccessInfo,
2084
+ NUM_AF * ARRAY_SIZE(canfd_af_regs));
2085
+
2086
+ canfd_create_rai(s->af_regs, canfd_af_regs,
2087
+ ARRAY_SIZE(canfd_af_regs), NUM_AF);
2088
+
2089
+ s->txe_regs = g_new0(RegisterAccessInfo,
2090
+ NUM_TXE * ARRAY_SIZE(canfd_txe_regs));
2091
+
2092
+ canfd_create_rai(s->txe_regs, canfd_txe_regs,
2093
+ ARRAY_SIZE(canfd_txe_regs), NUM_TXE);
2094
+
2095
+ if (s->cfg.enable_rx_fifo1) {
2096
+ num_regs += s->cfg.rx1_fifo * NUM_REGS_PER_MSG_SPACE;
2097
+
2098
+ s->rx1_regs = g_new0(RegisterAccessInfo,
2099
+ s->cfg.rx1_fifo * ARRAY_SIZE(canfd_rx1_regs));
2100
+
2101
+ canfd_create_rai(s->rx1_regs, canfd_rx1_regs,
2102
+ ARRAY_SIZE(canfd_rx1_regs), s->cfg.rx1_fifo);
2103
+ }
2104
+
2105
+ r_array = g_new0(RegisterInfoArray, 1);
2106
+ r_array->r = g_new0(RegisterInfo * , num_regs);
2107
+ r_array->num_elements = num_regs;
2108
+ r_array->prefix = device_prefix;
2109
+
2110
+ pos = canfd_populate_regarray(s, r_array, pos,
2111
+ canfd_regs_info,
2112
+ ARRAY_SIZE(canfd_regs_info));
2113
+ pos = canfd_populate_regarray(s, r_array, pos,
2114
+ s->tx_regs, s->cfg.tx_fifo *
2115
+ NUM_REGS_PER_MSG_SPACE);
2116
+ pos = canfd_populate_regarray(s, r_array, pos,
2117
+ s->rx0_regs, s->cfg.rx0_fifo *
2118
+ NUM_REGS_PER_MSG_SPACE);
2119
+ if (s->cfg.enable_rx_fifo1) {
2120
+ pos = canfd_populate_regarray(s, r_array, pos,
2121
+ s->rx1_regs, s->cfg.rx1_fifo *
2122
+ NUM_REGS_PER_MSG_SPACE);
2123
+ }
2124
+ pos = canfd_populate_regarray(s, r_array, pos,
2125
+ s->af_regs, NUM_AF * NUM_REG_PER_AF);
2126
+ pos = canfd_populate_regarray(s, r_array, pos,
2127
+ s->txe_regs, NUM_TXE * NUM_REG_PER_TXE);
2128
+
2129
+ memory_region_init_io(&r_array->mem, OBJECT(s), &canfd_ops, r_array,
2130
+ device_prefix, memory_size);
2131
+ return r_array;
2132
+}
2133
+
2134
+static void canfd_realize(DeviceState *dev, Error **errp)
2135
+{
2136
+ XlnxVersalCANFDState *s = XILINX_CANFD(dev);
2137
+ RegisterInfoArray *reg_array;
2138
+
2139
+ reg_array = canfd_create_regarray(s);
2140
+ memory_region_add_subregion(&s->iomem, 0x00, &reg_array->mem);
2141
+ sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
2142
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq_canfd_int);
2143
+
2144
+ if (s->canfdbus) {
2145
+ if (xlnx_canfd_connect_to_bus(s, s->canfdbus) < 0) {
2146
+ g_autofree char *path = object_get_canonical_path(OBJECT(s));
2147
+
2148
+ error_setg(errp, "%s: xlnx_canfd_connect_to_bus failed", path);
2149
+ return;
2150
+ }
2151
+
2152
+ }
2153
+
2154
+ /* Allocate a new timer. */
2155
+ s->canfd_timer = ptimer_init(xlnx_versal_canfd_ptimer_cb, s,
2156
+ PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD |
2157
+ PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT |
2158
+ PTIMER_POLICY_NO_IMMEDIATE_RELOAD);
2159
+
2160
+ ptimer_transaction_begin(s->canfd_timer);
2161
+
2162
+ ptimer_set_freq(s->canfd_timer, s->cfg.ext_clk_freq);
2163
+ ptimer_set_limit(s->canfd_timer, CANFD_TIMER_MAX, 1);
2164
+ ptimer_run(s->canfd_timer, 0);
2165
+ ptimer_transaction_commit(s->canfd_timer);
2166
+}
2167
+
2168
+static void canfd_init(Object *obj)
2169
+{
2170
+ XlnxVersalCANFDState *s = XILINX_CANFD(obj);
2171
+
2172
+ memory_region_init(&s->iomem, obj, TYPE_XILINX_CANFD,
2173
+ XLNX_VERSAL_CANFD_R_MAX * 4);
2174
+}
2175
+
2176
+static const VMStateDescription vmstate_canfd = {
2177
+ .name = TYPE_XILINX_CANFD,
2178
+ .version_id = 1,
2179
+ .minimum_version_id = 1,
2180
+ .fields = (VMStateField[]) {
2181
+ VMSTATE_UINT32_ARRAY(regs, XlnxVersalCANFDState,
2182
+ XLNX_VERSAL_CANFD_R_MAX),
2183
+ VMSTATE_PTIMER(canfd_timer, XlnxVersalCANFDState),
2184
+ VMSTATE_END_OF_LIST(),
2185
+ }
2186
+};
2187
+
2188
+static Property canfd_core_properties[] = {
2189
+ DEFINE_PROP_UINT8("rx-fifo0", XlnxVersalCANFDState, cfg.rx0_fifo, 0x40),
2190
+ DEFINE_PROP_UINT8("rx-fifo1", XlnxVersalCANFDState, cfg.rx1_fifo, 0x40),
2191
+ DEFINE_PROP_UINT8("tx-fifo", XlnxVersalCANFDState, cfg.tx_fifo, 0x20),
2192
+ DEFINE_PROP_BOOL("enable-rx-fifo1", XlnxVersalCANFDState,
2193
+ cfg.enable_rx_fifo1, true),
2194
+ DEFINE_PROP_UINT32("ext_clk_freq", XlnxVersalCANFDState, cfg.ext_clk_freq,
2195
+ CANFD_DEFAULT_CLOCK),
2196
+ DEFINE_PROP_LINK("canfdbus", XlnxVersalCANFDState, canfdbus, TYPE_CAN_BUS,
2197
+ CanBusState *),
2198
+ DEFINE_PROP_END_OF_LIST(),
2199
+};
2200
+
2201
+static void canfd_class_init(ObjectClass *klass, void *data)
2202
+{
2203
+ DeviceClass *dc = DEVICE_CLASS(klass);
2204
+
2205
+ dc->reset = canfd_reset;
2206
+ dc->realize = canfd_realize;
2207
+ device_class_set_props(dc, canfd_core_properties);
2208
+ dc->vmsd = &vmstate_canfd;
2209
+}
2210
+
2211
+static const TypeInfo canfd_info = {
2212
+ .name = TYPE_XILINX_CANFD,
2213
+ .parent = TYPE_SYS_BUS_DEVICE,
2214
+ .instance_size = sizeof(XlnxVersalCANFDState),
2215
+ .class_init = canfd_class_init,
2216
+ .instance_init = canfd_init,
2217
+};
2218
+
2219
+static void canfd_register_types(void)
2220
+{
2221
+ type_register_static(&canfd_info);
2222
+}
2223
+
2224
+type_init(canfd_register_types)
2225
diff --git a/hw/net/can/meson.build b/hw/net/can/meson.build
15
index XXXXXXX..XXXXXXX 100644
2226
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/cpu.h
2227
--- a/hw/net/can/meson.build
17
+++ b/target/arm/cpu.h
2228
+++ b/hw/net/can/meson.build
18
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64ISAR1, GPI, 28, 4)
2229
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_CAN_PCI', if_true: files('can_mioe3680_pci.c'))
19
FIELD(ID_AA64ISAR1, FRINTTS, 32, 4)
2230
softmmu_ss.add(when: 'CONFIG_CAN_CTUCANFD', if_true: files('ctucan_core.c'))
20
FIELD(ID_AA64ISAR1, SB, 36, 4)
2231
softmmu_ss.add(when: 'CONFIG_CAN_CTUCANFD_PCI', if_true: files('ctucan_pci.c'))
21
FIELD(ID_AA64ISAR1, SPECRES, 40, 4)
2232
softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP', if_true: files('xlnx-zynqmp-can.c'))
22
+FIELD(ID_AA64ISAR1, BF16, 44, 4)
2233
+softmmu_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-canfd.c'))
23
+FIELD(ID_AA64ISAR1, DGH, 48, 4)
2234
diff --git a/hw/net/can/trace-events b/hw/net/can/trace-events
24
+FIELD(ID_AA64ISAR1, I8MM, 52, 4)
2235
index XXXXXXX..XXXXXXX 100644
25
2236
--- a/hw/net/can/trace-events
26
FIELD(ID_AA64PFR0, EL0, 0, 4)
2237
+++ b/hw/net/can/trace-events
27
FIELD(ID_AA64PFR0, EL1, 4, 4)
2238
@@ -XXX,XX +XXX,XX @@ xlnx_can_filter_mask_pre_write(uint8_t filter_num, uint32_t value) "Filter%d MAS
28
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64PFR0, ADVSIMD, 20, 4)
2239
xlnx_can_tx_data(uint32_t id, uint8_t dlc, uint8_t db0, uint8_t db1, uint8_t db2, uint8_t db3, uint8_t db4, uint8_t db5, uint8_t db6, uint8_t db7) "Frame: ID: 0x%08x DLC: 0x%02x DATA: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x"
29
FIELD(ID_AA64PFR0, GIC, 24, 4)
2240
xlnx_can_rx_data(uint32_t id, uint32_t dlc, uint8_t db0, uint8_t db1, uint8_t db2, uint8_t db3, uint8_t db4, uint8_t db5, uint8_t db6, uint8_t db7) "Frame: ID: 0x%08x DLC: 0x%02x DATA: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x"
30
FIELD(ID_AA64PFR0, RAS, 28, 4)
2241
xlnx_can_rx_discard(uint32_t status) "Controller is not enabled for bus communication. Status Register: 0x%08x"
31
FIELD(ID_AA64PFR0, SVE, 32, 4)
2242
+
32
+FIELD(ID_AA64PFR0, SEL2, 36, 4)
2243
+# xlnx-versal-canfd.c
33
+FIELD(ID_AA64PFR0, MPAM, 40, 4)
2244
+xlnx_canfd_update_irq(char *path, uint32_t isr, uint32_t ier, uint32_t irq) "%s: ISR: 0x%08x IER: 0x%08x IRQ: 0x%08x"
34
+FIELD(ID_AA64PFR0, AMU, 44, 4)
2245
+xlnx_canfd_rx_fifo_filter_reject(char *path, uint32_t id, uint8_t dlc) "%s: Frame: ID: 0x%08x DLC: 0x%02x"
35
+FIELD(ID_AA64PFR0, DIT, 48, 4)
2246
+xlnx_canfd_rx_data(char *path, uint32_t id, uint8_t dlc, uint8_t flags) "%s: Frame: ID: 0x%08x DLC: 0x%02x CANFD Flag: 0x%02x"
36
+FIELD(ID_AA64PFR0, CSV2, 56, 4)
2247
+xlnx_canfd_tx_data(char *path, uint32_t id, uint8_t dlc, uint8_t flgas) "%s: Frame: ID: 0x%08x DLC: 0x%02x CANFD Flag: 0x%02x"
37
+FIELD(ID_AA64PFR0, CSV3, 60, 4)
2248
+xlnx_canfd_reset(char *path, uint32_t val) "%s: Resetting controller with value = 0x%08x"
38
39
FIELD(ID_AA64PFR1, BT, 0, 4)
40
FIELD(ID_AA64PFR1, SSBS, 4, 4)
41
FIELD(ID_AA64PFR1, MTE, 8, 4)
42
FIELD(ID_AA64PFR1, RAS_FRAC, 12, 4)
43
+FIELD(ID_AA64PFR1, MPAM_FRAC, 16, 4)
44
45
FIELD(ID_AA64MMFR0, PARANGE, 0, 4)
46
FIELD(ID_AA64MMFR0, ASIDBITS, 4, 4)
47
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64MMFR0, TGRAN16_2, 32, 4)
48
FIELD(ID_AA64MMFR0, TGRAN64_2, 36, 4)
49
FIELD(ID_AA64MMFR0, TGRAN4_2, 40, 4)
50
FIELD(ID_AA64MMFR0, EXS, 44, 4)
51
+FIELD(ID_AA64MMFR0, FGT, 56, 4)
52
+FIELD(ID_AA64MMFR0, ECV, 60, 4)
53
54
FIELD(ID_AA64MMFR1, HAFDBS, 0, 4)
55
FIELD(ID_AA64MMFR1, VMIDBITS, 4, 4)
56
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64MMFR1, LO, 16, 4)
57
FIELD(ID_AA64MMFR1, PAN, 20, 4)
58
FIELD(ID_AA64MMFR1, SPECSEI, 24, 4)
59
FIELD(ID_AA64MMFR1, XNX, 28, 4)
60
+FIELD(ID_AA64MMFR1, TWED, 32, 4)
61
+FIELD(ID_AA64MMFR1, ETS, 36, 4)
62
63
FIELD(ID_AA64MMFR2, CNP, 0, 4)
64
FIELD(ID_AA64MMFR2, UAO, 4, 4)
65
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64DFR0, CTX_CMPS, 28, 4)
66
FIELD(ID_AA64DFR0, PMSVER, 32, 4)
67
FIELD(ID_AA64DFR0, DOUBLELOCK, 36, 4)
68
FIELD(ID_AA64DFR0, TRACEFILT, 40, 4)
69
+FIELD(ID_AA64DFR0, MTPMU, 48, 4)
70
71
FIELD(ID_DFR0, COPDBG, 0, 4)
72
FIELD(ID_DFR0, COPSDBG, 4, 4)
73
--
2249
--
74
2.20.1
2250
2.34.1
75
76
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
From: Vikram Garhwal <vikram.garhwal@amd.com>
2
2
3
A device shouldn't access its parent object which is QOM internal.
3
Connect CANFD0 and CANFD1 on the Versal-virt machine and update xlnx-versal-virt
4
Instead it should use type cast for this purporse. This patch fixes this
4
document with CANFD command line examples.
5
issue for all NPCM7XX Devices.
6
5
7
Signed-off-by: Hao Wu <wuhaotsh@google.com>
6
Signed-off-by: Vikram Garhwal <vikram.garhwal@amd.com>
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Message-id: 20210108190945.949196-7-wuhaotsh@google.com
8
Reviewed-by: Francisco Iglesias <frasse.iglesias@gmail.com>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
10
---
12
hw/arm/npcm7xx_boards.c | 2 +-
11
docs/system/arm/xlnx-versal-virt.rst | 31 ++++++++++++++++
13
hw/mem/npcm7xx_mc.c | 2 +-
12
include/hw/arm/xlnx-versal.h | 12 +++++++
14
hw/misc/npcm7xx_clk.c | 2 +-
13
hw/arm/xlnx-versal-virt.c | 53 ++++++++++++++++++++++++++++
15
hw/misc/npcm7xx_gcr.c | 2 +-
14
hw/arm/xlnx-versal.c | 37 +++++++++++++++++++
16
hw/misc/npcm7xx_rng.c | 2 +-
15
4 files changed, 133 insertions(+)
17
hw/nvram/npcm7xx_otp.c | 2 +-
18
hw/ssi/npcm7xx_fiu.c | 2 +-
19
7 files changed, 7 insertions(+), 7 deletions(-)
20
16
21
diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c
17
diff --git a/docs/system/arm/xlnx-versal-virt.rst b/docs/system/arm/xlnx-versal-virt.rst
22
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
23
--- a/hw/arm/npcm7xx_boards.c
19
--- a/docs/system/arm/xlnx-versal-virt.rst
24
+++ b/hw/arm/npcm7xx_boards.c
20
+++ b/docs/system/arm/xlnx-versal-virt.rst
25
@@ -XXX,XX +XXX,XX @@ static NPCM7xxState *npcm7xx_create_soc(MachineState *machine,
21
@@ -XXX,XX +XXX,XX @@ Implemented devices:
26
uint32_t hw_straps)
22
- DDR memory
23
- BBRAM (36 bytes of Battery-backed RAM)
24
- eFUSE (3072 bytes of one-time field-programmable bit array)
25
+- 2 CANFDs
26
27
QEMU does not yet model any other devices, including the PL and the AI Engine.
28
29
@@ -XXX,XX +XXX,XX @@ To use a different index value, N, from default of 1, add:
30
31
Better yet, do not use actual product data when running guest image
32
on this Xilinx Versal Virt board.
33
+
34
+Using CANFDs for Versal Virt
35
+""""""""""""""""""""""""""""
36
+Versal CANFD controller is developed based on SocketCAN and QEMU CAN bus
37
+implementation. Bus connection and socketCAN connection for each CAN module
38
+can be set through command lines.
39
+
40
+To connect both CANFD0 and CANFD1 on the same bus:
41
+
42
+.. code-block:: bash
43
+
44
+ -object can-bus,id=canbus -machine canbus0=canbus -machine canbus1=canbus
45
+
46
+To connect CANFD0 and CANFD1 to separate buses:
47
+
48
+.. code-block:: bash
49
+
50
+ -object can-bus,id=canbus0 -object can-bus,id=canbus1 \
51
+ -machine canbus0=canbus0 -machine canbus1=canbus1
52
+
53
+The SocketCAN interface can connect to a Physical or a Virtual CAN interfaces on
54
+the host machine. Please check this document to learn about CAN interface on
55
+Linux: docs/system/devices/can.rst
56
+
57
+To connect CANFD0 and CANFD1 to host machine's CAN interface can0:
58
+
59
+.. code-block:: bash
60
+
61
+ -object can-bus,id=canbus -machine canbus0=canbus -machine canbus1=canbus
62
+ -object can-host-socketcan,id=canhost0,if=can0,canbus=canbus
63
diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h
64
index XXXXXXX..XXXXXXX 100644
65
--- a/include/hw/arm/xlnx-versal.h
66
+++ b/include/hw/arm/xlnx-versal.h
67
@@ -XXX,XX +XXX,XX @@
68
#include "hw/dma/xlnx_csu_dma.h"
69
#include "hw/misc/xlnx-versal-crl.h"
70
#include "hw/misc/xlnx-versal-pmc-iou-slcr.h"
71
+#include "hw/net/xlnx-versal-canfd.h"
72
73
#define TYPE_XLNX_VERSAL "xlnx-versal"
74
OBJECT_DECLARE_SIMPLE_TYPE(Versal, XLNX_VERSAL)
75
@@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_SIMPLE_TYPE(Versal, XLNX_VERSAL)
76
#define XLNX_VERSAL_NR_SDS 2
77
#define XLNX_VERSAL_NR_XRAM 4
78
#define XLNX_VERSAL_NR_IRQS 192
79
+#define XLNX_VERSAL_NR_CANFD 2
80
+#define XLNX_VERSAL_CANFD_REF_CLK (24 * 1000 * 1000)
81
82
struct Versal {
83
/*< private >*/
84
@@ -XXX,XX +XXX,XX @@ struct Versal {
85
CadenceGEMState gem[XLNX_VERSAL_NR_GEMS];
86
XlnxZDMA adma[XLNX_VERSAL_NR_ADMAS];
87
VersalUsb2 usb;
88
+ CanBusState *canbus[XLNX_VERSAL_NR_CANFD];
89
+ XlnxVersalCANFDState canfd[XLNX_VERSAL_NR_CANFD];
90
} iou;
91
92
/* Real-time Processing Unit. */
93
@@ -XXX,XX +XXX,XX @@ struct Versal {
94
#define VERSAL_CRL_IRQ 10
95
#define VERSAL_UART0_IRQ_0 18
96
#define VERSAL_UART1_IRQ_0 19
97
+#define VERSAL_CANFD0_IRQ_0 20
98
+#define VERSAL_CANFD1_IRQ_0 21
99
#define VERSAL_USB0_IRQ_0 22
100
#define VERSAL_GEM0_IRQ_0 56
101
#define VERSAL_GEM0_WAKE_IRQ_0 57
102
@@ -XXX,XX +XXX,XX @@ struct Versal {
103
#define MM_UART1 0xff010000U
104
#define MM_UART1_SIZE 0x10000
105
106
+#define MM_CANFD0 0xff060000U
107
+#define MM_CANFD0_SIZE 0x10000
108
+#define MM_CANFD1 0xff070000U
109
+#define MM_CANFD1_SIZE 0x10000
110
+
111
#define MM_GEM0 0xff0c0000U
112
#define MM_GEM0_SIZE 0x10000
113
#define MM_GEM1 0xff0d0000U
114
diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c
115
index XXXXXXX..XXXXXXX 100644
116
--- a/hw/arm/xlnx-versal-virt.c
117
+++ b/hw/arm/xlnx-versal-virt.c
118
@@ -XXX,XX +XXX,XX @@ struct VersalVirt {
119
uint32_t clk_25Mhz;
120
uint32_t usb;
121
uint32_t dwc;
122
+ uint32_t canfd[2];
123
} phandle;
124
struct arm_boot_info binfo;
125
126
+ CanBusState *canbus[XLNX_VERSAL_NR_CANFD];
127
struct {
128
bool secure;
129
} cfg;
130
@@ -XXX,XX +XXX,XX @@ static void fdt_add_uart_nodes(VersalVirt *s)
131
}
132
}
133
134
+static void fdt_add_canfd_nodes(VersalVirt *s)
135
+{
136
+ uint64_t addrs[] = { MM_CANFD1, MM_CANFD0 };
137
+ uint32_t size[] = { MM_CANFD1_SIZE, MM_CANFD0_SIZE };
138
+ unsigned int irqs[] = { VERSAL_CANFD1_IRQ_0, VERSAL_CANFD0_IRQ_0 };
139
+ const char clocknames[] = "can_clk\0s_axi_aclk";
140
+ int i;
141
+
142
+ /* Create and connect CANFD0 and CANFD1 nodes to canbus0. */
143
+ for (i = 0; i < ARRAY_SIZE(addrs); i++) {
144
+ char *name = g_strdup_printf("/canfd@%" PRIx64, addrs[i]);
145
+ qemu_fdt_add_subnode(s->fdt, name);
146
+
147
+ qemu_fdt_setprop_cell(s->fdt, name, "rx-fifo-depth", 0x40);
148
+ qemu_fdt_setprop_cell(s->fdt, name, "tx-mailbox-count", 0x20);
149
+
150
+ qemu_fdt_setprop_cells(s->fdt, name, "clocks",
151
+ s->phandle.clk_25Mhz, s->phandle.clk_25Mhz);
152
+ qemu_fdt_setprop(s->fdt, name, "clock-names",
153
+ clocknames, sizeof(clocknames));
154
+ qemu_fdt_setprop_cells(s->fdt, name, "interrupts",
155
+ GIC_FDT_IRQ_TYPE_SPI, irqs[i],
156
+ GIC_FDT_IRQ_FLAGS_LEVEL_HI);
157
+ qemu_fdt_setprop_sized_cells(s->fdt, name, "reg",
158
+ 2, addrs[i], 2, size[i]);
159
+ qemu_fdt_setprop_string(s->fdt, name, "compatible",
160
+ "xlnx,canfd-2.0");
161
+
162
+ g_free(name);
163
+ }
164
+}
165
+
166
static void fdt_add_fixed_link_nodes(VersalVirt *s, char *gemname,
167
uint32_t phandle)
27
{
168
{
28
NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_GET_CLASS(machine);
169
@@ -XXX,XX +XXX,XX @@ static void versal_virt_init(MachineState *machine)
29
- MachineClass *mc = &nmc->parent;
170
TYPE_XLNX_VERSAL);
30
+ MachineClass *mc = MACHINE_CLASS(nmc);
171
object_property_set_link(OBJECT(&s->soc), "ddr", OBJECT(machine->ram),
31
Object *obj;
172
&error_abort);
32
173
+ object_property_set_link(OBJECT(&s->soc), "canbus0", OBJECT(s->canbus[0]),
33
if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) {
174
+ &error_abort);
34
diff --git a/hw/mem/npcm7xx_mc.c b/hw/mem/npcm7xx_mc.c
175
+ object_property_set_link(OBJECT(&s->soc), "canbus1", OBJECT(s->canbus[1]),
35
index XXXXXXX..XXXXXXX 100644
176
+ &error_abort);
36
--- a/hw/mem/npcm7xx_mc.c
177
sysbus_realize(SYS_BUS_DEVICE(&s->soc), &error_fatal);
37
+++ b/hw/mem/npcm7xx_mc.c
178
38
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_mc_realize(DeviceState *dev, Error **errp)
179
fdt_create(s);
39
180
create_virtio_regions(s);
40
memory_region_init_io(&s->mmio, OBJECT(s), &npcm7xx_mc_ops, s, "regs",
181
fdt_add_gem_nodes(s);
41
NPCM7XX_MC_REGS_SIZE);
182
fdt_add_uart_nodes(s);
42
- sysbus_init_mmio(&s->parent, &s->mmio);
183
+ fdt_add_canfd_nodes(s);
43
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio);
184
fdt_add_gic_nodes(s);
185
fdt_add_timer_nodes(s);
186
fdt_add_zdma_nodes(s);
187
@@ -XXX,XX +XXX,XX @@ static void versal_virt_init(MachineState *machine)
188
189
static void versal_virt_machine_instance_init(Object *obj)
190
{
191
+ VersalVirt *s = XLNX_VERSAL_VIRT_MACHINE(obj);
192
+
193
+ /*
194
+ * User can set canbus0 and canbus1 properties to can-bus object and connect
195
+ * to socketcan(optional) interface via command line.
196
+ */
197
+ object_property_add_link(obj, "canbus0", TYPE_CAN_BUS,
198
+ (Object **)&s->canbus[0],
199
+ object_property_allow_set_link,
200
+ 0);
201
+ object_property_add_link(obj, "canbus1", TYPE_CAN_BUS,
202
+ (Object **)&s->canbus[1],
203
+ object_property_allow_set_link,
204
+ 0);
44
}
205
}
45
206
46
static void npcm7xx_mc_class_init(ObjectClass *klass, void *data)
207
static void versal_virt_machine_class_init(ObjectClass *oc, void *data)
47
diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
208
diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c
48
index XXXXXXX..XXXXXXX 100644
209
index XXXXXXX..XXXXXXX 100644
49
--- a/hw/misc/npcm7xx_clk.c
210
--- a/hw/arm/xlnx-versal.c
50
+++ b/hw/misc/npcm7xx_clk.c
211
+++ b/hw/arm/xlnx-versal.c
51
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_init(Object *obj)
212
@@ -XXX,XX +XXX,XX @@ static void versal_create_uarts(Versal *s, qemu_irq *pic)
52
213
}
53
memory_region_init_io(&s->iomem, obj, &npcm7xx_clk_ops, s,
54
TYPE_NPCM7XX_CLK, 4 * KiB);
55
- sysbus_init_mmio(&s->parent, &s->iomem);
56
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
57
}
214
}
58
215
59
static int npcm7xx_clk_post_load(void *opaque, int version_id)
216
+static void versal_create_canfds(Versal *s, qemu_irq *pic)
60
diff --git a/hw/misc/npcm7xx_gcr.c b/hw/misc/npcm7xx_gcr.c
217
+{
61
index XXXXXXX..XXXXXXX 100644
218
+ int i;
62
--- a/hw/misc/npcm7xx_gcr.c
219
+ uint32_t irqs[] = { VERSAL_CANFD0_IRQ_0, VERSAL_CANFD1_IRQ_0};
63
+++ b/hw/misc/npcm7xx_gcr.c
220
+ uint64_t addrs[] = { MM_CANFD0, MM_CANFD1 };
64
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_gcr_init(Object *obj)
221
+
65
222
+ for (i = 0; i < ARRAY_SIZE(s->lpd.iou.canfd); i++) {
66
memory_region_init_io(&s->iomem, obj, &npcm7xx_gcr_ops, s,
223
+ char *name = g_strdup_printf("canfd%d", i);
67
TYPE_NPCM7XX_GCR, 4 * KiB);
224
+ SysBusDevice *sbd;
68
- sysbus_init_mmio(&s->parent, &s->iomem);
225
+ MemoryRegion *mr;
69
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
226
+
70
}
227
+ object_initialize_child(OBJECT(s), name, &s->lpd.iou.canfd[i],
71
228
+ TYPE_XILINX_CANFD);
72
static const VMStateDescription vmstate_npcm7xx_gcr = {
229
+ sbd = SYS_BUS_DEVICE(&s->lpd.iou.canfd[i]);
73
diff --git a/hw/misc/npcm7xx_rng.c b/hw/misc/npcm7xx_rng.c
230
+
74
index XXXXXXX..XXXXXXX 100644
231
+ object_property_set_int(OBJECT(&s->lpd.iou.canfd[i]), "ext_clk_freq",
75
--- a/hw/misc/npcm7xx_rng.c
232
+ XLNX_VERSAL_CANFD_REF_CLK , &error_abort);
76
+++ b/hw/misc/npcm7xx_rng.c
233
+
77
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_rng_init(Object *obj)
234
+ object_property_set_link(OBJECT(&s->lpd.iou.canfd[i]), "canfdbus",
78
235
+ OBJECT(s->lpd.iou.canbus[i]),
79
memory_region_init_io(&s->iomem, obj, &npcm7xx_rng_ops, s, "regs",
236
+ &error_abort);
80
NPCM7XX_RNG_REGS_SIZE);
237
+
81
- sysbus_init_mmio(&s->parent, &s->iomem);
238
+ sysbus_realize(sbd, &error_fatal);
82
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
239
+
83
}
240
+ mr = sysbus_mmio_get_region(sbd, 0);
84
241
+ memory_region_add_subregion(&s->mr_ps, addrs[i], mr);
85
static const VMStateDescription vmstate_npcm7xx_rng = {
242
+
86
diff --git a/hw/nvram/npcm7xx_otp.c b/hw/nvram/npcm7xx_otp.c
243
+ sysbus_connect_irq(sbd, 0, pic[irqs[i]]);
87
index XXXXXXX..XXXXXXX 100644
244
+ g_free(name);
88
--- a/hw/nvram/npcm7xx_otp.c
245
+ }
89
+++ b/hw/nvram/npcm7xx_otp.c
246
+}
90
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_otp_realize(DeviceState *dev, Error **errp)
247
+
248
static void versal_create_usbs(Versal *s, qemu_irq *pic)
91
{
249
{
92
NPCM7xxOTPClass *oc = NPCM7XX_OTP_GET_CLASS(dev);
250
DeviceState *dev;
93
NPCM7xxOTPState *s = NPCM7XX_OTP(dev);
251
@@ -XXX,XX +XXX,XX @@ static void versal_realize(DeviceState *dev, Error **errp)
94
- SysBusDevice *sbd = &s->parent;
252
versal_create_apu_gic(s, pic);
95
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
253
versal_create_rpu_cpus(s);
96
254
versal_create_uarts(s, pic);
97
memset(s->array, 0, sizeof(s->array));
255
+ versal_create_canfds(s, pic);
98
256
versal_create_usbs(s, pic);
99
diff --git a/hw/ssi/npcm7xx_fiu.c b/hw/ssi/npcm7xx_fiu.c
257
versal_create_gems(s, pic);
100
index XXXXXXX..XXXXXXX 100644
258
versal_create_admas(s, pic);
101
--- a/hw/ssi/npcm7xx_fiu.c
259
@@ -XXX,XX +XXX,XX @@ static void versal_init(Object *obj)
102
+++ b/hw/ssi/npcm7xx_fiu.c
260
static Property versal_properties[] = {
103
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_fiu_hold_reset(Object *obj)
261
DEFINE_PROP_LINK("ddr", Versal, cfg.mr_ddr, TYPE_MEMORY_REGION,
104
static void npcm7xx_fiu_realize(DeviceState *dev, Error **errp)
262
MemoryRegion *),
105
{
263
+ DEFINE_PROP_LINK("canbus0", Versal, lpd.iou.canbus[0],
106
NPCM7xxFIUState *s = NPCM7XX_FIU(dev);
264
+ TYPE_CAN_BUS, CanBusState *),
107
- SysBusDevice *sbd = &s->parent;
265
+ DEFINE_PROP_LINK("canbus1", Versal, lpd.iou.canbus[1],
108
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
266
+ TYPE_CAN_BUS, CanBusState *),
109
int i;
267
DEFINE_PROP_END_OF_LIST()
110
268
};
111
if (s->cs_count <= 0) {
269
112
--
270
--
113
2.20.1
271
2.34.1
114
115
diff view generated by jsdifflib
1
A copy-and-paste error meant that the return value for register offset 0x44
1
From: Vikram Garhwal <vikram.garhwal@amd.com>
2
(the RX Status FIFO PEEK register) returned a byte from a bogus offset in
3
the rx status FIFO. Fix the typo.
4
2
5
Cc: qemu-stable@nongnu.org
3
Signed-off-by: Vikram Garhwal <vikram.garhwal@amd.com>
6
Fixes: https://bugs.launchpad.net/qemu/+bug/1904954
4
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Francisco Iglesias <frasse.iglesias@gmail.com>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Message-id: 20210108180401.2263-2-peter.maydell@linaro.org
10
---
7
---
11
hw/net/lan9118.c | 2 +-
8
MAINTAINERS | 2 +-
12
1 file changed, 1 insertion(+), 1 deletion(-)
9
1 file changed, 1 insertion(+), 1 deletion(-)
13
10
14
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
11
diff --git a/MAINTAINERS b/MAINTAINERS
15
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/net/lan9118.c
13
--- a/MAINTAINERS
17
+++ b/hw/net/lan9118.c
14
+++ b/MAINTAINERS
18
@@ -XXX,XX +XXX,XX @@ static uint64_t lan9118_readl(void *opaque, hwaddr offset,
15
@@ -XXX,XX +XXX,XX @@ M: Francisco Iglesias <francisco.iglesias@amd.com>
19
case 0x40:
16
S: Maintained
20
return rx_status_fifo_pop(s);
17
F: hw/net/can/xlnx-*
21
case 0x44:
18
F: include/hw/net/xlnx-*
22
- return s->rx_status_fifo[s->tx_status_fifo_head];
19
-F: tests/qtest/xlnx-can-test*
23
+ return s->rx_status_fifo[s->rx_status_fifo_head];
20
+F: tests/qtest/xlnx-can*-test*
24
case 0x48:
21
25
return tx_status_fifo_pop(s);
22
EDU
26
case 0x4c:
23
M: Jiri Slaby <jslaby@suse.cz>
27
--
24
--
28
2.20.1
25
2.34.1
29
30
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
From: Vikram Garhwal <vikram.garhwal@amd.com>
2
2
3
We add a qtest for the PWM in the previous patch. It proves it works as
3
The QTests perform three tests on the Xilinx VERSAL CANFD controller:
4
expected.
4
Tests the CANFD controllers in loopback.
5
Tests the CANFD controllers in normal mode with CAN frame.
6
Tests the CANFD controllers in normal mode with CANFD frame.
5
7
6
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
8
Signed-off-by: Vikram Garhwal <vikram.garhwal@amd.com>
7
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
9
Acked-by: Thomas Huth <thuth@redhat.com>
8
Signed-off-by: Hao Wu <wuhaotsh@google.com>
10
Reviewed-by: Francisco Iglesias <francisco.iglesias@amd.com>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Message-id: 20210108190945.949196-6-wuhaotsh@google.com
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
13
---
13
tests/qtest/npcm7xx_pwm-test.c | 490 +++++++++++++++++++++++++++++++++
14
tests/qtest/xlnx-canfd-test.c | 423 ++++++++++++++++++++++++++++++++++
14
tests/qtest/meson.build | 1 +
15
tests/qtest/meson.build | 1 +
15
2 files changed, 491 insertions(+)
16
2 files changed, 424 insertions(+)
16
create mode 100644 tests/qtest/npcm7xx_pwm-test.c
17
create mode 100644 tests/qtest/xlnx-canfd-test.c
17
18
18
diff --git a/tests/qtest/npcm7xx_pwm-test.c b/tests/qtest/npcm7xx_pwm-test.c
19
diff --git a/tests/qtest/xlnx-canfd-test.c b/tests/qtest/xlnx-canfd-test.c
19
new file mode 100644
20
new file mode 100644
20
index XXXXXXX..XXXXXXX
21
index XXXXXXX..XXXXXXX
21
--- /dev/null
22
--- /dev/null
22
+++ b/tests/qtest/npcm7xx_pwm-test.c
23
+++ b/tests/qtest/xlnx-canfd-test.c
23
@@ -XXX,XX +XXX,XX @@
24
@@ -XXX,XX +XXX,XX @@
24
+/*
25
+/*
25
+ * QTests for Nuvoton NPCM7xx PWM Modules.
26
+ * SPDX-License-Identifier: MIT
26
+ *
27
+ *
27
+ * Copyright 2020 Google LLC
28
+ * QTests for the Xilinx Versal CANFD controller.
28
+ *
29
+ *
29
+ * This program is free software; you can redistribute it and/or modify it
30
+ * Copyright (c) 2022 AMD Inc.
30
+ * under the terms of the GNU General Public License as published by the
31
+ *
31
+ * Free Software Foundation; either version 2 of the License, or
32
+ * Written-by: Vikram Garhwal<vikram.garhwal@amd.com>
32
+ * (at your option) any later version.
33
+ *
33
+ *
34
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
34
+ * This program is distributed in the hope that it will be useful, but WITHOUT
35
+ * of this software and associated documentation files (the "Software"), to deal
35
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
36
+ * in the Software without restriction, including without limitation the rights
36
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
37
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
37
+ * for more details.
38
+ * copies of the Software, and to permit persons to whom the Software is
39
+ * furnished to do so, subject to the following conditions:
40
+ *
41
+ * The above copyright notice and this permission notice shall be included in
42
+ * all copies or substantial portions of the Software.
43
+ *
44
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
45
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
46
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
47
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
48
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
49
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
50
+ * THE SOFTWARE.
38
+ */
51
+ */
39
+
52
+
40
+#include "qemu/osdep.h"
53
+#include "qemu/osdep.h"
41
+#include "qemu/bitops.h"
54
+#include "libqtest.h"
42
+#include "libqos/libqtest.h"
55
+
43
+#include "qapi/qmp/qdict.h"
56
+/* Base address. */
44
+#include "qapi/qmp/qnum.h"
57
+#define CANFD0_BASE_ADDR 0xff060000
45
+
58
+#define CANFD1_BASE_ADDR 0xff070000
46
+#define REF_HZ 25000000
59
+
47
+
60
+/* Register addresses. */
48
+/* Register field definitions. */
61
+#define R_SRR_OFFSET 0x00
49
+#define CH_EN BIT(0)
62
+#define R_MSR_OFFSET 0x04
50
+#define CH_INV BIT(2)
63
+#define R_FILTER_CONTROL_REGISTER 0xe0
51
+#define CH_MOD BIT(3)
64
+#define R_SR_OFFSET 0x18
52
+
65
+#define R_ISR_OFFSET 0x1c
53
+/* Registers shared between all PWMs in a module */
66
+#define R_IER_OFFSET 0x20
54
+#define PPR 0x00
67
+#define R_ICR_OFFSET 0x24
55
+#define CSR 0x04
68
+#define R_TX_READY_REQ_REGISTER 0x90
56
+#define PCR 0x08
69
+#define RX_FIFO_STATUS_REGISTER 0xe8
57
+#define PIER 0x3c
70
+#define R_TXID_OFFSET 0x100
58
+#define PIIR 0x40
71
+#define R_TXDLC_OFFSET 0x104
59
+
72
+#define R_TXDATA1_OFFSET 0x108
60
+/* CLK module related */
73
+#define R_TXDATA2_OFFSET 0x10c
61
+#define CLK_BA 0xf0801000
74
+#define R_AFMR_REGISTER0 0xa00
62
+#define CLKSEL 0x04
75
+#define R_AFIR_REGISTER0 0xa04
63
+#define CLKDIV1 0x08
76
+#define R_RX0_ID_OFFSET 0x2100
64
+#define CLKDIV2 0x2c
77
+#define R_RX0_DLC_OFFSET 0x2104
65
+#define PLLCON0 0x0c
78
+#define R_RX0_DATA1_OFFSET 0x2108
66
+#define PLLCON1 0x10
79
+#define R_RX0_DATA2_OFFSET 0x210c
67
+#define PLL_INDV(rv) extract32((rv), 0, 6)
80
+
68
+#define PLL_FBDV(rv) extract32((rv), 16, 12)
81
+/* CANFD modes. */
69
+#define PLL_OTDV1(rv) extract32((rv), 8, 3)
82
+#define SRR_CONFIG_MODE 0x00
70
+#define PLL_OTDV2(rv) extract32((rv), 13, 3)
83
+#define MSR_NORMAL_MODE 0x00
71
+#define APB3CKDIV(rv) extract32((rv), 28, 2)
84
+#define MSR_LOOPBACK_MODE (1 << 1)
72
+#define CLK2CKDIV(rv) extract32((rv), 0, 1)
85
+#define ENABLE_CANFD (1 << 1)
73
+#define CLK4CKDIV(rv) extract32((rv), 26, 2)
86
+
74
+#define CPUCKSEL(rv) extract32((rv), 0, 2)
87
+/* CANFD status. */
75
+
88
+#define STATUS_CONFIG_MODE (1 << 0)
76
+#define MAX_DUTY 1000000
89
+#define STATUS_NORMAL_MODE (1 << 3)
77
+
90
+#define STATUS_LOOPBACK_MODE (1 << 1)
78
+typedef struct PWMModule {
91
+#define ISR_TXOK (1 << 1)
79
+ int irq;
92
+#define ISR_RXOK (1 << 4)
80
+ uint64_t base_addr;
93
+
81
+} PWMModule;
94
+#define ENABLE_ALL_FILTERS 0xffffffff
82
+
95
+#define ENABLE_ALL_INTERRUPTS 0xffffffff
83
+typedef struct PWM {
96
+
84
+ uint32_t cnr_offset;
97
+/* We are sending one canfd message. */
85
+ uint32_t cmr_offset;
98
+#define TX_READY_REG_VAL 0x1
86
+ uint32_t pdr_offset;
99
+
87
+ uint32_t pwdr_offset;
100
+#define FIRST_RX_STORE_INDEX 0x1
88
+} PWM;
101
+#define STATUS_REG_MASK 0xf
89
+
102
+#define DLC_FD_BIT_SHIFT 0x1b
90
+typedef struct TestData {
103
+#define DLC_FD_BIT_MASK 0xf8000000
91
+ const PWMModule *module;
104
+#define FIFO_STATUS_READ_INDEX_MASK 0x3f
92
+ const PWM *pwm;
105
+#define FIFO_STATUS_FILL_LEVEL_MASK 0x7f00
93
+} TestData;
106
+#define FILL_LEVEL_SHIFT 0x8
94
+
107
+
95
+static const PWMModule pwm_module_list[] = {
108
+/* CANFD frame size ID, DLC and 16 DATA word. */
96
+ {
109
+#define CANFD_FRAME_SIZE 18
97
+ .irq = 93,
110
+/* CAN frame size ID, DLC and 2 DATA word. */
98
+ .base_addr = 0xf0103000
111
+#define CAN_FRAME_SIZE 4
99
+ },
112
+
100
+ {
113
+/* Set the filters for CANFD controller. */
101
+ .irq = 94,
114
+static void enable_filters(QTestState *qts)
102
+ .base_addr = 0xf0104000
115
+{
103
+ }
116
+ const uint32_t arr_afmr[32] = { 0xb423deaa, 0xa2a40bdc, 0x1b64f486,
104
+};
117
+ 0x95c0d4ee, 0xe0c44528, 0x4b407904,
105
+
118
+ 0xd2673f46, 0x9fc638d6, 0x8844f3d8,
106
+static const PWM pwm_list[] = {
119
+ 0xa607d1e8, 0x67871bf4, 0xc2557dc,
107
+ {
120
+ 0x9ea5b53e, 0x3643c0cc, 0x5a05ea8e,
108
+ .cnr_offset = 0x0c,
121
+ 0x83a46d84, 0x4a25c2b8, 0x93a66008,
109
+ .cmr_offset = 0x10,
122
+ 0x2e467470, 0xedc66118, 0x9086f9f2,
110
+ .pdr_offset = 0x14,
123
+ 0xfa23dd36, 0xb6654b90, 0xb221b8ca,
111
+ .pwdr_offset = 0x44,
124
+ 0x3467d1e2, 0xa3a55542, 0x5b26a012,
112
+ },
125
+ 0x2281ea7e, 0xcea0ece8, 0xdc61e588,
113
+ {
126
+ 0x2e5676a, 0x16821320 };
114
+ .cnr_offset = 0x18,
127
+
115
+ .cmr_offset = 0x1c,
128
+ const uint32_t arr_afir[32] = { 0xa833dfa1, 0x255a477e, 0x3a4bb1c5,
116
+ .pdr_offset = 0x20,
129
+ 0x8f560a6c, 0x27f38903, 0x2fecec4d,
117
+ .pwdr_offset = 0x48,
130
+ 0xa014c66d, 0xec289b8, 0x7e52dead,
118
+ },
131
+ 0x82e94f3c, 0xcf3e3c5c, 0x66059871,
119
+ {
132
+ 0x3f213df4, 0x25ac3959, 0xa12e9bef,
120
+ .cnr_offset = 0x24,
133
+ 0xa3ad3af, 0xbafd7fe, 0xb3cb40fd,
121
+ .cmr_offset = 0x28,
134
+ 0x5d9caa81, 0x2ed61902, 0x7cd64a0,
122
+ .pdr_offset = 0x2c,
135
+ 0x4b1fa538, 0x9b5ced8c, 0x150de059,
123
+ .pwdr_offset = 0x4c,
136
+ 0xd2794227, 0x635e820a, 0xbb6b02cf,
124
+ },
137
+ 0xbb58176, 0x570025bb, 0xa78d9658,
125
+ {
138
+ 0x49d735df, 0xe5399d2f };
126
+ .cnr_offset = 0x30,
139
+
127
+ .cmr_offset = 0x34,
140
+ /* Passing the respective array values to all the AFMR and AFIR pairs. */
128
+ .pdr_offset = 0x38,
141
+ for (int i = 0; i < 32; i++) {
129
+ .pwdr_offset = 0x50,
142
+ /* For CANFD0. */
130
+ },
143
+ qtest_writel(qts, CANFD0_BASE_ADDR + R_AFMR_REGISTER0 + 8 * i,
131
+};
144
+ arr_afmr[i]);
132
+
145
+ qtest_writel(qts, CANFD0_BASE_ADDR + R_AFIR_REGISTER0 + 8 * i,
133
+static const int ppr_base[] = { 0, 0, 8, 8 };
146
+ arr_afir[i]);
134
+static const int csr_base[] = { 0, 4, 8, 12 };
147
+
135
+static const int pcr_base[] = { 0, 8, 12, 16 };
148
+ /* For CANFD1. */
136
+
149
+ qtest_writel(qts, CANFD1_BASE_ADDR + R_AFMR_REGISTER0 + 8 * i,
137
+static const uint32_t ppr_list[] = {
150
+ arr_afmr[i]);
138
+ 0,
151
+ qtest_writel(qts, CANFD1_BASE_ADDR + R_AFIR_REGISTER0 + 8 * i,
139
+ 1,
152
+ arr_afir[i]);
140
+ 10,
153
+ }
141
+ 100,
154
+
142
+ 255, /* Max possible value. */
155
+ /* Enable all the pairs from AFR register. */
143
+};
156
+ qtest_writel(qts, CANFD0_BASE_ADDR + R_FILTER_CONTROL_REGISTER,
144
+
157
+ ENABLE_ALL_FILTERS);
145
+static const uint32_t csr_list[] = {
158
+ qtest_writel(qts, CANFD1_BASE_ADDR + R_FILTER_CONTROL_REGISTER,
146
+ 0,
159
+ ENABLE_ALL_FILTERS);
147
+ 1,
160
+}
148
+ 2,
161
+
149
+ 3,
162
+static void configure_canfd(QTestState *qts, uint8_t mode)
150
+ 4, /* Max possible value. */
163
+{
151
+};
164
+ uint32_t status = 0;
152
+
165
+
153
+static const uint32_t cnr_list[] = {
166
+ /* Put CANFD0 and CANFD1 in config mode. */
154
+ 0,
167
+ qtest_writel(qts, CANFD0_BASE_ADDR + R_SRR_OFFSET, SRR_CONFIG_MODE);
155
+ 1,
168
+ qtest_writel(qts, CANFD1_BASE_ADDR + R_SRR_OFFSET, SRR_CONFIG_MODE);
156
+ 50,
169
+
157
+ 100,
170
+ /* Write mode of operation in Mode select register. */
158
+ 150,
171
+ qtest_writel(qts, CANFD0_BASE_ADDR + R_MSR_OFFSET, mode);
159
+ 200,
172
+ qtest_writel(qts, CANFD1_BASE_ADDR + R_MSR_OFFSET, mode);
160
+ 1000,
173
+
161
+ 10000,
174
+ enable_filters(qts);
162
+ 65535, /* Max possible value. */
175
+
163
+};
176
+ /* Check here if CANFD0 and CANFD1 are in config mode. */
164
+
177
+ status = qtest_readl(qts, CANFD0_BASE_ADDR + R_SR_OFFSET);
165
+static const uint32_t cmr_list[] = {
178
+ status = status & STATUS_REG_MASK;
166
+ 0,
179
+ g_assert_cmpint(status, ==, STATUS_CONFIG_MODE);
167
+ 1,
180
+
168
+ 10,
181
+ status = qtest_readl(qts, CANFD1_BASE_ADDR + R_SR_OFFSET);
169
+ 50,
182
+ status = status & STATUS_REG_MASK;
170
+ 100,
183
+ g_assert_cmpint(status, ==, STATUS_CONFIG_MODE);
171
+ 150,
184
+
172
+ 200,
185
+ qtest_writel(qts, CANFD1_BASE_ADDR + R_IER_OFFSET, ENABLE_ALL_INTERRUPTS);
173
+ 1000,
186
+ qtest_writel(qts, CANFD1_BASE_ADDR + R_IER_OFFSET, ENABLE_ALL_INTERRUPTS);
174
+ 10000,
187
+
175
+ 65535, /* Max possible value. */
188
+ qtest_writel(qts, CANFD0_BASE_ADDR + R_SRR_OFFSET, ENABLE_CANFD);
176
+};
189
+ qtest_writel(qts, CANFD1_BASE_ADDR + R_SRR_OFFSET, ENABLE_CANFD);
177
+
190
+}
178
+/* Returns the index of the PWM module. */
191
+
179
+static int pwm_module_index(const PWMModule *module)
192
+static void generate_random_data(uint32_t *buf_tx, bool is_canfd_frame)
180
+{
193
+{
181
+ ptrdiff_t diff = module - pwm_module_list;
194
+ /* Generate random TX data for CANFD frame. */
182
+
195
+ if (is_canfd_frame) {
183
+ g_assert_true(diff >= 0 && diff < ARRAY_SIZE(pwm_module_list));
196
+ for (int i = 0; i < CANFD_FRAME_SIZE - 2; i++) {
184
+
197
+ buf_tx[2 + i] = rand();
185
+ return diff;
198
+ }
186
+}
187
+
188
+/* Returns the index of the PWM entry. */
189
+static int pwm_index(const PWM *pwm)
190
+{
191
+ ptrdiff_t diff = pwm - pwm_list;
192
+
193
+ g_assert_true(diff >= 0 && diff < ARRAY_SIZE(pwm_list));
194
+
195
+ return diff;
196
+}
197
+
198
+static uint64_t pwm_qom_get(QTestState *qts, const char *path, const char *name)
199
+{
200
+ QDict *response;
201
+
202
+ g_test_message("Getting properties %s from %s", name, path);
203
+ response = qtest_qmp(qts, "{ 'execute': 'qom-get',"
204
+ " 'arguments': { 'path': %s, 'property': %s}}",
205
+ path, name);
206
+ /* The qom set message returns successfully. */
207
+ g_assert_true(qdict_haskey(response, "return"));
208
+ return qnum_get_uint(qobject_to(QNum, qdict_get(response, "return")));
209
+}
210
+
211
+static uint64_t pwm_get_freq(QTestState *qts, int module_index, int pwm_index)
212
+{
213
+ char path[100];
214
+ char name[100];
215
+
216
+ sprintf(path, "/machine/soc/pwm[%d]", module_index);
217
+ sprintf(name, "freq[%d]", pwm_index);
218
+
219
+ return pwm_qom_get(qts, path, name);
220
+}
221
+
222
+static uint64_t pwm_get_duty(QTestState *qts, int module_index, int pwm_index)
223
+{
224
+ char path[100];
225
+ char name[100];
226
+
227
+ sprintf(path, "/machine/soc/pwm[%d]", module_index);
228
+ sprintf(name, "duty[%d]", pwm_index);
229
+
230
+ return pwm_qom_get(qts, path, name);
231
+}
232
+
233
+static uint32_t get_pll(uint32_t con)
234
+{
235
+ return REF_HZ * PLL_FBDV(con) / (PLL_INDV(con) * PLL_OTDV1(con)
236
+ * PLL_OTDV2(con));
237
+}
238
+
239
+static uint64_t read_pclk(QTestState *qts)
240
+{
241
+ uint64_t freq = REF_HZ;
242
+ uint32_t clksel = qtest_readl(qts, CLK_BA + CLKSEL);
243
+ uint32_t pllcon;
244
+ uint32_t clkdiv1 = qtest_readl(qts, CLK_BA + CLKDIV1);
245
+ uint32_t clkdiv2 = qtest_readl(qts, CLK_BA + CLKDIV2);
246
+
247
+ switch (CPUCKSEL(clksel)) {
248
+ case 0:
249
+ pllcon = qtest_readl(qts, CLK_BA + PLLCON0);
250
+ freq = get_pll(pllcon);
251
+ break;
252
+ case 1:
253
+ pllcon = qtest_readl(qts, CLK_BA + PLLCON1);
254
+ freq = get_pll(pllcon);
255
+ break;
256
+ case 2:
257
+ break;
258
+ case 3:
259
+ break;
260
+ default:
261
+ g_assert_not_reached();
262
+ }
263
+
264
+ freq >>= (CLK2CKDIV(clkdiv1) + CLK4CKDIV(clkdiv1) + APB3CKDIV(clkdiv2));
265
+
266
+ return freq;
267
+}
268
+
269
+static uint32_t pwm_selector(uint32_t csr)
270
+{
271
+ switch (csr) {
272
+ case 0:
273
+ return 2;
274
+ case 1:
275
+ return 4;
276
+ case 2:
277
+ return 8;
278
+ case 3:
279
+ return 16;
280
+ case 4:
281
+ return 1;
282
+ default:
283
+ g_assert_not_reached();
284
+ }
285
+}
286
+
287
+static uint64_t pwm_compute_freq(QTestState *qts, uint32_t ppr, uint32_t csr,
288
+ uint32_t cnr)
289
+{
290
+ return read_pclk(qts) / ((ppr + 1) * pwm_selector(csr) * (cnr + 1));
291
+}
292
+
293
+static uint64_t pwm_compute_duty(uint32_t cnr, uint32_t cmr, bool inverted)
294
+{
295
+ uint64_t duty;
296
+
297
+ if (cnr == 0) {
298
+ /* PWM is stopped. */
299
+ duty = 0;
300
+ } else if (cmr >= cnr) {
301
+ duty = MAX_DUTY;
302
+ } else {
199
+ } else {
303
+ duty = MAX_DUTY * (cmr + 1) / (cnr + 1);
200
+ /* Generate random TX data for CAN frame. */
304
+ }
201
+ for (int i = 0; i < CAN_FRAME_SIZE - 2; i++) {
305
+
202
+ buf_tx[2 + i] = rand();
306
+ if (inverted) {
203
+ }
307
+ duty = MAX_DUTY - duty;
204
+ }
308
+ }
205
+}
309
+
206
+
310
+ return duty;
207
+static void read_data(QTestState *qts, uint64_t can_base_addr, uint32_t *buf_rx)
311
+}
208
+{
312
+
209
+ uint32_t int_status;
313
+static uint32_t pwm_read(QTestState *qts, const TestData *td, unsigned offset)
210
+ uint32_t fifo_status_reg_value;
314
+{
211
+ /* At which RX FIFO the received data is stored. */
315
+ return qtest_readl(qts, td->module->base_addr + offset);
212
+ uint8_t store_ind = 0;
316
+}
213
+ bool is_canfd_frame = false;
317
+
214
+
318
+static void pwm_write(QTestState *qts, const TestData *td, unsigned offset,
215
+ /* Read the interrupt on CANFD rx. */
319
+ uint32_t value)
216
+ int_status = qtest_readl(qts, can_base_addr + R_ISR_OFFSET) & ISR_RXOK;
320
+{
217
+
321
+ qtest_writel(qts, td->module->base_addr + offset, value);
218
+ g_assert_cmpint(int_status, ==, ISR_RXOK);
322
+}
219
+
323
+
220
+ /* Find the fill level and read index. */
324
+static uint32_t pwm_read_ppr(QTestState *qts, const TestData *td)
221
+ fifo_status_reg_value = qtest_readl(qts, can_base_addr +
325
+{
222
+ RX_FIFO_STATUS_REGISTER);
326
+ return extract32(pwm_read(qts, td, PPR), ppr_base[pwm_index(td->pwm)], 8);
223
+
327
+}
224
+ store_ind = (fifo_status_reg_value & FIFO_STATUS_READ_INDEX_MASK) +
328
+
225
+ ((fifo_status_reg_value & FIFO_STATUS_FILL_LEVEL_MASK) >>
329
+static void pwm_write_ppr(QTestState *qts, const TestData *td, uint32_t value)
226
+ FILL_LEVEL_SHIFT);
330
+{
227
+
331
+ pwm_write(qts, td, PPR, value << ppr_base[pwm_index(td->pwm)]);
228
+ g_assert_cmpint(store_ind, ==, FIRST_RX_STORE_INDEX);
332
+}
229
+
333
+
230
+ /* Read the RX register data for CANFD. */
334
+static uint32_t pwm_read_csr(QTestState *qts, const TestData *td)
231
+ buf_rx[0] = qtest_readl(qts, can_base_addr + R_RX0_ID_OFFSET);
335
+{
232
+ buf_rx[1] = qtest_readl(qts, can_base_addr + R_RX0_DLC_OFFSET);
336
+ return extract32(pwm_read(qts, td, CSR), csr_base[pwm_index(td->pwm)], 3);
233
+
337
+}
234
+ is_canfd_frame = (buf_rx[1] >> DLC_FD_BIT_SHIFT) & 1;
338
+
235
+
339
+static void pwm_write_csr(QTestState *qts, const TestData *td, uint32_t value)
236
+ if (is_canfd_frame) {
340
+{
237
+ for (int i = 0; i < CANFD_FRAME_SIZE - 2; i++) {
341
+ pwm_write(qts, td, CSR, value << csr_base[pwm_index(td->pwm)]);
238
+ buf_rx[i + 2] = qtest_readl(qts,
342
+}
239
+ can_base_addr + R_RX0_DATA1_OFFSET + 4 * i);
343
+
240
+ }
344
+static uint32_t pwm_read_pcr(QTestState *qts, const TestData *td)
241
+ } else {
345
+{
242
+ buf_rx[2] = qtest_readl(qts, can_base_addr + R_RX0_DATA1_OFFSET);
346
+ return extract32(pwm_read(qts, td, PCR), pcr_base[pwm_index(td->pwm)], 4);
243
+ buf_rx[3] = qtest_readl(qts, can_base_addr + R_RX0_DATA2_OFFSET);
347
+}
244
+ }
348
+
245
+
349
+static void pwm_write_pcr(QTestState *qts, const TestData *td, uint32_t value)
246
+ /* Clear the RX interrupt. */
350
+{
247
+ qtest_writel(qts, CANFD1_BASE_ADDR + R_ICR_OFFSET, ISR_RXOK);
351
+ pwm_write(qts, td, PCR, value << pcr_base[pwm_index(td->pwm)]);
248
+}
352
+}
249
+
353
+
250
+static void write_data(QTestState *qts, uint64_t can_base_addr,
354
+static uint32_t pwm_read_cnr(QTestState *qts, const TestData *td)
251
+ const uint32_t *buf_tx, bool is_canfd_frame)
355
+{
252
+{
356
+ return pwm_read(qts, td, td->pwm->cnr_offset);
253
+ /* Write the TX register data for CANFD. */
357
+}
254
+ qtest_writel(qts, can_base_addr + R_TXID_OFFSET, buf_tx[0]);
358
+
255
+ qtest_writel(qts, can_base_addr + R_TXDLC_OFFSET, buf_tx[1]);
359
+static void pwm_write_cnr(QTestState *qts, const TestData *td, uint32_t value)
256
+
360
+{
257
+ if (is_canfd_frame) {
361
+ pwm_write(qts, td, td->pwm->cnr_offset, value);
258
+ for (int i = 0; i < CANFD_FRAME_SIZE - 2; i++) {
362
+}
259
+ qtest_writel(qts, can_base_addr + R_TXDATA1_OFFSET + 4 * i,
363
+
260
+ buf_tx[2 + i]);
364
+static uint32_t pwm_read_cmr(QTestState *qts, const TestData *td)
261
+ }
365
+{
262
+ } else {
366
+ return pwm_read(qts, td, td->pwm->cmr_offset);
263
+ qtest_writel(qts, can_base_addr + R_TXDATA1_OFFSET, buf_tx[2]);
367
+}
264
+ qtest_writel(qts, can_base_addr + R_TXDATA2_OFFSET, buf_tx[3]);
368
+
265
+ }
369
+static void pwm_write_cmr(QTestState *qts, const TestData *td, uint32_t value)
266
+}
370
+{
267
+
371
+ pwm_write(qts, td, td->pwm->cmr_offset, value);
268
+static void send_data(QTestState *qts, uint64_t can_base_addr)
372
+}
269
+{
373
+
270
+ uint32_t int_status;
374
+/* Check pwm registers can be reset to default value */
271
+
375
+static void test_init(gconstpointer test_data)
272
+ qtest_writel(qts, can_base_addr + R_TX_READY_REQ_REGISTER,
376
+{
273
+ TX_READY_REG_VAL);
377
+ const TestData *td = test_data;
274
+
378
+ QTestState *qts = qtest_init("-machine quanta-gsj");
275
+ /* Read the interrupt on CANFD for tx. */
379
+ int module = pwm_module_index(td->module);
276
+ int_status = qtest_readl(qts, can_base_addr + R_ISR_OFFSET) & ISR_TXOK;
380
+ int pwm = pwm_index(td->pwm);
277
+
381
+
278
+ g_assert_cmpint(int_status, ==, ISR_TXOK);
382
+ g_assert_cmpuint(pwm_get_freq(qts, module, pwm), ==, 0);
279
+
383
+ g_assert_cmpuint(pwm_get_duty(qts, module, pwm), ==, 0);
280
+ /* Clear the interrupt for tx. */
281
+ qtest_writel(qts, CANFD0_BASE_ADDR + R_ICR_OFFSET, ISR_TXOK);
282
+}
283
+
284
+static void match_rx_tx_data(const uint32_t *buf_tx, const uint32_t *buf_rx,
285
+ bool is_canfd_frame)
286
+{
287
+ uint16_t size = 0;
288
+ uint8_t len = CAN_FRAME_SIZE;
289
+
290
+ if (is_canfd_frame) {
291
+ len = CANFD_FRAME_SIZE;
292
+ }
293
+
294
+ while (size < len) {
295
+ if (R_RX0_ID_OFFSET + 4 * size == R_RX0_DLC_OFFSET) {
296
+ g_assert_cmpint((buf_rx[size] & DLC_FD_BIT_MASK), ==,
297
+ (buf_tx[size] & DLC_FD_BIT_MASK));
298
+ } else {
299
+ if (!is_canfd_frame && size == 4) {
300
+ break;
301
+ }
302
+
303
+ g_assert_cmpint(buf_rx[size], ==, buf_tx[size]);
304
+ }
305
+
306
+ size++;
307
+ }
308
+}
309
+/*
310
+ * Xilinx CANFD supports both CAN and CANFD frames. This test will be
311
+ * transferring CAN frame i.e. 8 bytes of data from CANFD0 and CANFD1 through
312
+ * canbus. CANFD0 initiate the data transfer to can-bus, CANFD1 receives the
313
+ * data. Test compares the can frame data sent from CANFD0 and received on
314
+ * CANFD1.
315
+ */
316
+static void test_can_data_transfer(void)
317
+{
318
+ uint32_t buf_tx[CAN_FRAME_SIZE] = { 0x5a5bb9a4, 0x80000000,
319
+ 0x12345678, 0x87654321 };
320
+ uint32_t buf_rx[CAN_FRAME_SIZE] = { 0x00, 0x00, 0x00, 0x00 };
321
+ uint32_t status = 0;
322
+
323
+ generate_random_data(buf_tx, false);
324
+
325
+ QTestState *qts = qtest_init("-machine xlnx-versal-virt"
326
+ " -object can-bus,id=canbus"
327
+ " -machine canbus0=canbus"
328
+ " -machine canbus1=canbus"
329
+ );
330
+
331
+ configure_canfd(qts, MSR_NORMAL_MODE);
332
+
333
+ /* Check if CANFD0 and CANFD1 are in Normal mode. */
334
+ status = qtest_readl(qts, CANFD0_BASE_ADDR + R_SR_OFFSET);
335
+ status = status & STATUS_REG_MASK;
336
+ g_assert_cmpint(status, ==, STATUS_NORMAL_MODE);
337
+
338
+ status = qtest_readl(qts, CANFD1_BASE_ADDR + R_SR_OFFSET);
339
+ status = status & STATUS_REG_MASK;
340
+ g_assert_cmpint(status, ==, STATUS_NORMAL_MODE);
341
+
342
+ write_data(qts, CANFD0_BASE_ADDR, buf_tx, false);
343
+
344
+ send_data(qts, CANFD0_BASE_ADDR);
345
+ read_data(qts, CANFD1_BASE_ADDR, buf_rx);
346
+ match_rx_tx_data(buf_tx, buf_rx, false);
384
+
347
+
385
+ qtest_quit(qts);
348
+ qtest_quit(qts);
386
+}
349
+}
387
+
350
+
388
+/* One-shot mode should not change frequency and duty cycle. */
351
+/*
389
+static void test_oneshot(gconstpointer test_data)
352
+ * This test will be transferring CANFD frame i.e. 64 bytes of data from CANFD0
390
+{
353
+ * and CANFD1 through canbus. CANFD0 initiate the data transfer to can-bus,
391
+ const TestData *td = test_data;
354
+ * CANFD1 receives the data. Test compares the CANFD frame data sent from CANFD0
392
+ QTestState *qts = qtest_init("-machine quanta-gsj");
355
+ * with received on CANFD1.
393
+ int module = pwm_module_index(td->module);
356
+ */
394
+ int pwm = pwm_index(td->pwm);
357
+static void test_canfd_data_transfer(void)
395
+ uint32_t ppr, csr, pcr;
358
+{
396
+ int i, j;
359
+ uint32_t buf_tx[CANFD_FRAME_SIZE] = { 0x5a5bb9a4, 0xf8000000 };
397
+
360
+ uint32_t buf_rx[CANFD_FRAME_SIZE] = { 0x00, 0x00, 0x00, 0x00 };
398
+ pcr = CH_EN;
361
+ uint32_t status = 0;
399
+ for (i = 0; i < ARRAY_SIZE(ppr_list); ++i) {
362
+
400
+ ppr = ppr_list[i];
363
+ generate_random_data(buf_tx, true);
401
+ pwm_write_ppr(qts, td, ppr);
364
+
402
+
365
+ QTestState *qts = qtest_init("-machine xlnx-versal-virt"
403
+ for (j = 0; j < ARRAY_SIZE(csr_list); ++j) {
366
+ " -object can-bus,id=canbus"
404
+ csr = csr_list[j];
367
+ " -machine canbus0=canbus"
405
+ pwm_write_csr(qts, td, csr);
368
+ " -machine canbus1=canbus"
406
+ pwm_write_pcr(qts, td, pcr);
369
+ );
407
+
370
+
408
+ g_assert_cmpuint(pwm_read_ppr(qts, td), ==, ppr);
371
+ configure_canfd(qts, MSR_NORMAL_MODE);
409
+ g_assert_cmpuint(pwm_read_csr(qts, td), ==, csr);
372
+
410
+ g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr);
373
+ /* Check if CANFD0 and CANFD1 are in Normal mode. */
411
+ g_assert_cmpuint(pwm_get_freq(qts, module, pwm), ==, 0);
374
+ status = qtest_readl(qts, CANFD0_BASE_ADDR + R_SR_OFFSET);
412
+ g_assert_cmpuint(pwm_get_duty(qts, module, pwm), ==, 0);
375
+ status = status & STATUS_REG_MASK;
413
+ }
376
+ g_assert_cmpint(status, ==, STATUS_NORMAL_MODE);
414
+ }
377
+
378
+ status = qtest_readl(qts, CANFD1_BASE_ADDR + R_SR_OFFSET);
379
+ status = status & STATUS_REG_MASK;
380
+ g_assert_cmpint(status, ==, STATUS_NORMAL_MODE);
381
+
382
+ write_data(qts, CANFD0_BASE_ADDR, buf_tx, true);
383
+
384
+ send_data(qts, CANFD0_BASE_ADDR);
385
+ read_data(qts, CANFD1_BASE_ADDR, buf_rx);
386
+ match_rx_tx_data(buf_tx, buf_rx, true);
415
+
387
+
416
+ qtest_quit(qts);
388
+ qtest_quit(qts);
417
+}
389
+}
418
+
390
+
419
+/* In toggle mode, the PWM generates correct outputs. */
391
+/*
420
+static void test_toggle(gconstpointer test_data)
392
+ * This test is performing loopback mode on CANFD0 and CANFD1. Data sent from
421
+{
393
+ * TX of each CANFD0 and CANFD1 are compared with RX register data for
422
+ const TestData *td = test_data;
394
+ * respective CANFD Controller.
423
+ QTestState *qts = qtest_init("-machine quanta-gsj");
395
+ */
424
+ int module = pwm_module_index(td->module);
396
+static void test_can_loopback(void)
425
+ int pwm = pwm_index(td->pwm);
397
+{
426
+ uint32_t ppr, csr, pcr, cnr, cmr;
398
+ uint32_t buf_tx[CANFD_FRAME_SIZE] = { 0x5a5bb9a4, 0xf8000000 };
427
+ int i, j, k, l;
399
+ uint32_t buf_rx[CANFD_FRAME_SIZE] = { 0x00, 0x00, 0x00, 0x00 };
428
+ uint64_t expected_freq, expected_duty;
400
+ uint32_t status = 0;
429
+
401
+
430
+ pcr = CH_EN | CH_MOD;
402
+ generate_random_data(buf_tx, true);
431
+ for (i = 0; i < ARRAY_SIZE(ppr_list); ++i) {
403
+
432
+ ppr = ppr_list[i];
404
+ QTestState *qts = qtest_init("-machine xlnx-versal-virt"
433
+ pwm_write_ppr(qts, td, ppr);
405
+ " -object can-bus,id=canbus"
434
+
406
+ " -machine canbus0=canbus"
435
+ for (j = 0; j < ARRAY_SIZE(csr_list); ++j) {
407
+ " -machine canbus1=canbus"
436
+ csr = csr_list[j];
408
+ );
437
+ pwm_write_csr(qts, td, csr);
409
+
438
+
410
+ configure_canfd(qts, MSR_LOOPBACK_MODE);
439
+ for (k = 0; k < ARRAY_SIZE(cnr_list); ++k) {
411
+
440
+ cnr = cnr_list[k];
412
+ /* Check if CANFD0 and CANFD1 are set in correct loopback mode. */
441
+ pwm_write_cnr(qts, td, cnr);
413
+ status = qtest_readl(qts, CANFD0_BASE_ADDR + R_SR_OFFSET);
442
+
414
+ status = status & STATUS_REG_MASK;
443
+ for (l = 0; l < ARRAY_SIZE(cmr_list); ++l) {
415
+ g_assert_cmpint(status, ==, STATUS_LOOPBACK_MODE);
444
+ cmr = cmr_list[l];
416
+
445
+ pwm_write_cmr(qts, td, cmr);
417
+ status = qtest_readl(qts, CANFD1_BASE_ADDR + R_SR_OFFSET);
446
+ expected_freq = pwm_compute_freq(qts, ppr, csr, cnr);
418
+ status = status & STATUS_REG_MASK;
447
+ expected_duty = pwm_compute_duty(cnr, cmr, false);
419
+ g_assert_cmpint(status, ==, STATUS_LOOPBACK_MODE);
448
+
420
+
449
+ pwm_write_pcr(qts, td, pcr);
421
+ write_data(qts, CANFD0_BASE_ADDR, buf_tx, true);
450
+ g_assert_cmpuint(pwm_read_ppr(qts, td), ==, ppr);
422
+
451
+ g_assert_cmpuint(pwm_read_csr(qts, td), ==, csr);
423
+ send_data(qts, CANFD0_BASE_ADDR);
452
+ g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr);
424
+ read_data(qts, CANFD0_BASE_ADDR, buf_rx);
453
+ g_assert_cmpuint(pwm_read_cnr(qts, td), ==, cnr);
425
+ match_rx_tx_data(buf_tx, buf_rx, true);
454
+ g_assert_cmpuint(pwm_read_cmr(qts, td), ==, cmr);
426
+
455
+ g_assert_cmpuint(pwm_get_duty(qts, module, pwm),
427
+ generate_random_data(buf_tx, true);
456
+ ==, expected_duty);
428
+
457
+ if (expected_duty != 0 && expected_duty != 100) {
429
+ write_data(qts, CANFD1_BASE_ADDR, buf_tx, true);
458
+ /* Duty cycle with 0 or 100 doesn't need frequency. */
430
+
459
+ g_assert_cmpuint(pwm_get_freq(qts, module, pwm),
431
+ send_data(qts, CANFD1_BASE_ADDR);
460
+ ==, expected_freq);
432
+ read_data(qts, CANFD1_BASE_ADDR, buf_rx);
461
+ }
433
+ match_rx_tx_data(buf_tx, buf_rx, true);
462
+
463
+ /* Test inverted mode */
464
+ expected_duty = pwm_compute_duty(cnr, cmr, true);
465
+ pwm_write_pcr(qts, td, pcr | CH_INV);
466
+ g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr | CH_INV);
467
+ g_assert_cmpuint(pwm_get_duty(qts, module, pwm),
468
+ ==, expected_duty);
469
+ if (expected_duty != 0 && expected_duty != 100) {
470
+ /* Duty cycle with 0 or 100 doesn't need frequency. */
471
+ g_assert_cmpuint(pwm_get_freq(qts, module, pwm),
472
+ ==, expected_freq);
473
+ }
474
+
475
+ }
476
+ }
477
+ }
478
+ }
479
+
434
+
480
+ qtest_quit(qts);
435
+ qtest_quit(qts);
481
+}
436
+}
482
+
437
+
483
+static void pwm_add_test(const char *name, const TestData* td,
484
+ GTestDataFunc fn)
485
+{
486
+ g_autofree char *full_name = g_strdup_printf(
487
+ "npcm7xx_pwm/module[%d]/pwm[%d]/%s", pwm_module_index(td->module),
488
+ pwm_index(td->pwm), name);
489
+ qtest_add_data_func(full_name, td, fn);
490
+}
491
+#define add_test(name, td) pwm_add_test(#name, td, test_##name)
492
+
493
+int main(int argc, char **argv)
438
+int main(int argc, char **argv)
494
+{
439
+{
495
+ TestData test_data_list[ARRAY_SIZE(pwm_module_list) * ARRAY_SIZE(pwm_list)];
496
+
497
+ g_test_init(&argc, &argv, NULL);
440
+ g_test_init(&argc, &argv, NULL);
498
+
441
+
499
+ for (int i = 0; i < ARRAY_SIZE(pwm_module_list); ++i) {
442
+ qtest_add_func("/net/canfd/can_data_transfer", test_can_data_transfer);
500
+ for (int j = 0; j < ARRAY_SIZE(pwm_list); ++j) {
443
+ qtest_add_func("/net/canfd/canfd_data_transfer", test_canfd_data_transfer);
501
+ TestData *td = &test_data_list[i * ARRAY_SIZE(pwm_list) + j];
444
+ qtest_add_func("/net/canfd/can_loopback", test_can_loopback);
502
+
503
+ td->module = &pwm_module_list[i];
504
+ td->pwm = &pwm_list[j];
505
+
506
+ add_test(init, td);
507
+ add_test(oneshot, td);
508
+ add_test(toggle, td);
509
+ }
510
+ }
511
+
445
+
512
+ return g_test_run();
446
+ return g_test_run();
513
+}
447
+}
514
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
448
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
515
index XXXXXXX..XXXXXXX 100644
449
index XXXXXXX..XXXXXXX 100644
516
--- a/tests/qtest/meson.build
450
--- a/tests/qtest/meson.build
517
+++ b/tests/qtest/meson.build
451
+++ b/tests/qtest/meson.build
518
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
452
@@ -XXX,XX +XXX,XX @@ qtests_aarch64 = \
519
qtests_npcm7xx = \
453
(config_all.has_key('CONFIG_TCG') and config_all_devices.has_key('CONFIG_TPM_TIS_SYSBUS') ? \
520
['npcm7xx_adc-test',
454
['tpm-tis-device-test', 'tpm-tis-device-swtpm-test'] : []) + \
521
'npcm7xx_gpio-test',
455
(config_all_devices.has_key('CONFIG_XLNX_ZYNQMP_ARM') ? ['xlnx-can-test', 'fuzz-xlnx-dp-test'] : []) + \
522
+ 'npcm7xx_pwm-test',
456
+ (config_all_devices.has_key('CONFIG_XLNX_VERSAL') ? ['xlnx-canfd-test'] : []) + \
523
'npcm7xx_rng-test',
457
(config_all_devices.has_key('CONFIG_RASPI') ? ['bcm2835-dma-test'] : []) + \
524
'npcm7xx_timer-test',
458
(config_all.has_key('CONFIG_TCG') and \
525
'npcm7xx_watchdog_timer-test']
459
config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test'] : []) + \
526
--
460
--
527
2.20.1
461
2.34.1
528
529
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
From: qianfan Zhao <qianfanguijin@163.com>
2
2
3
The ADC is part of NPCM7XX Module. Its behavior is controled by the
3
Allwinner R40 (sun8i) SoC features a Quad-Core Cortex-A7 ARM CPU,
4
ADC_CON register. It converts one of the eight analog inputs into a
4
and a Mali400 MP2 GPU from ARM. It's also known as the Allwinner T3
5
digital input and stores it in the ADC_DATA register when enabled.
5
for In-Car Entertainment usage, A40i and A40pro are variants that
6
differ in applicable temperatures range (industrial and military).
6
7
7
Users can alter input value by using qom-set QMP command.
8
Signed-off-by: qianfan Zhao <qianfanguijin@163.com>
8
9
Reviewed-by: Niek Linnenbank <nieklinnenbank@gmail.com>
9
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
10
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
11
Signed-off-by: Hao Wu <wuhaotsh@google.com>
12
Message-id: 20210108190945.949196-4-wuhaotsh@google.com
13
[PMM: Added missing hw/adc/trace.h file]
14
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
---
11
---
17
docs/system/arm/nuvoton.rst | 2 +-
12
include/hw/arm/allwinner-r40.h | 110 +++++++++
18
meson.build | 1 +
13
hw/arm/allwinner-r40.c | 415 +++++++++++++++++++++++++++++++++
19
hw/adc/trace.h | 1 +
14
hw/arm/bananapi_m2u.c | 129 ++++++++++
20
include/hw/adc/npcm7xx_adc.h | 69 ++++++
15
hw/arm/Kconfig | 10 +
21
include/hw/arm/npcm7xx.h | 2 +
16
hw/arm/meson.build | 1 +
22
hw/adc/npcm7xx_adc.c | 301 ++++++++++++++++++++++++++
17
5 files changed, 665 insertions(+)
23
hw/arm/npcm7xx.c | 24 ++-
18
create mode 100644 include/hw/arm/allwinner-r40.h
24
tests/qtest/npcm7xx_adc-test.c | 377 +++++++++++++++++++++++++++++++++
19
create mode 100644 hw/arm/allwinner-r40.c
25
hw/adc/meson.build | 1 +
20
create mode 100644 hw/arm/bananapi_m2u.c
26
hw/adc/trace-events | 5 +
27
tests/qtest/meson.build | 3 +-
28
11 files changed, 783 insertions(+), 3 deletions(-)
29
create mode 100644 hw/adc/trace.h
30
create mode 100644 include/hw/adc/npcm7xx_adc.h
31
create mode 100644 hw/adc/npcm7xx_adc.c
32
create mode 100644 tests/qtest/npcm7xx_adc-test.c
33
create mode 100644 hw/adc/trace-events
34
21
35
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
22
diff --git a/include/hw/arm/allwinner-r40.h b/include/hw/arm/allwinner-r40.h
36
index XXXXXXX..XXXXXXX 100644
37
--- a/docs/system/arm/nuvoton.rst
38
+++ b/docs/system/arm/nuvoton.rst
39
@@ -XXX,XX +XXX,XX @@ Supported devices
40
* Random Number Generator (RNG)
41
* USB host (USBH)
42
* GPIO controller
43
+ * Analog to Digital Converter (ADC)
44
45
Missing devices
46
---------------
47
@@ -XXX,XX +XXX,XX @@ Missing devices
48
* USB device (USBD)
49
* SMBus controller (SMBF)
50
* Peripheral SPI controller (PSPI)
51
- * Analog to Digital Converter (ADC)
52
* SD/MMC host
53
* PECI interface
54
* Pulse Width Modulation (PWM)
55
diff --git a/meson.build b/meson.build
56
index XXXXXXX..XXXXXXX 100644
57
--- a/meson.build
58
+++ b/meson.build
59
@@ -XXX,XX +XXX,XX @@ if have_system
60
'chardev',
61
'hw/9pfs',
62
'hw/acpi',
63
+ 'hw/adc',
64
'hw/alpha',
65
'hw/arm',
66
'hw/audio',
67
diff --git a/hw/adc/trace.h b/hw/adc/trace.h
68
new file mode 100644
23
new file mode 100644
69
index XXXXXXX..XXXXXXX
24
index XXXXXXX..XXXXXXX
70
--- /dev/null
25
--- /dev/null
71
+++ b/hw/adc/trace.h
26
+++ b/include/hw/arm/allwinner-r40.h
72
@@ -0,0 +1 @@
27
@@ -XXX,XX +XXX,XX @@
73
+#include "trace/trace-hw_adc.h"
28
+/*
74
diff --git a/include/hw/adc/npcm7xx_adc.h b/include/hw/adc/npcm7xx_adc.h
29
+ * Allwinner R40/A40i/T3 System on Chip emulation
30
+ *
31
+ * Copyright (C) 2023 qianfan Zhao <qianfanguijin@163.com>
32
+ *
33
+ * This program is free software: you can redistribute it and/or modify
34
+ * it under the terms of the GNU General Public License as published by
35
+ * the Free Software Foundation, either version 2 of the License, or
36
+ * (at your option) any later version.
37
+ *
38
+ * This program is distributed in the hope that it will be useful,
39
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
40
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
41
+ * GNU General Public License for more details.
42
+ *
43
+ * You should have received a copy of the GNU General Public License
44
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
45
+ */
46
+
47
+#ifndef HW_ARM_ALLWINNER_R40_H
48
+#define HW_ARM_ALLWINNER_R40_H
49
+
50
+#include "qom/object.h"
51
+#include "hw/arm/boot.h"
52
+#include "hw/timer/allwinner-a10-pit.h"
53
+#include "hw/intc/arm_gic.h"
54
+#include "hw/sd/allwinner-sdhost.h"
55
+#include "target/arm/cpu.h"
56
+#include "sysemu/block-backend.h"
57
+
58
+enum {
59
+ AW_R40_DEV_SRAM_A1,
60
+ AW_R40_DEV_SRAM_A2,
61
+ AW_R40_DEV_SRAM_A3,
62
+ AW_R40_DEV_SRAM_A4,
63
+ AW_R40_DEV_MMC0,
64
+ AW_R40_DEV_MMC1,
65
+ AW_R40_DEV_MMC2,
66
+ AW_R40_DEV_MMC3,
67
+ AW_R40_DEV_CCU,
68
+ AW_R40_DEV_PIT,
69
+ AW_R40_DEV_UART0,
70
+ AW_R40_DEV_GIC_DIST,
71
+ AW_R40_DEV_GIC_CPU,
72
+ AW_R40_DEV_GIC_HYP,
73
+ AW_R40_DEV_GIC_VCPU,
74
+ AW_R40_DEV_SDRAM
75
+};
76
+
77
+#define AW_R40_NUM_CPUS (4)
78
+
79
+/**
80
+ * Allwinner R40 object model
81
+ * @{
82
+ */
83
+
84
+/** Object type for the Allwinner R40 SoC */
85
+#define TYPE_AW_R40 "allwinner-r40"
86
+
87
+/** Convert input object to Allwinner R40 state object */
88
+OBJECT_DECLARE_SIMPLE_TYPE(AwR40State, AW_R40)
89
+
90
+/** @} */
91
+
92
+/**
93
+ * Allwinner R40 object
94
+ *
95
+ * This struct contains the state of all the devices
96
+ * which are currently emulated by the R40 SoC code.
97
+ */
98
+#define AW_R40_NUM_MMCS 4
99
+
100
+struct AwR40State {
101
+ /*< private >*/
102
+ DeviceState parent_obj;
103
+ /*< public >*/
104
+
105
+ ARMCPU cpus[AW_R40_NUM_CPUS];
106
+ const hwaddr *memmap;
107
+ AwA10PITState timer;
108
+ AwSdHostState mmc[AW_R40_NUM_MMCS];
109
+ GICState gic;
110
+ MemoryRegion sram_a1;
111
+ MemoryRegion sram_a2;
112
+ MemoryRegion sram_a3;
113
+ MemoryRegion sram_a4;
114
+};
115
+
116
+/**
117
+ * Emulate Boot ROM firmware setup functionality.
118
+ *
119
+ * A real Allwinner R40 SoC contains a Boot ROM
120
+ * which is the first code that runs right after
121
+ * the SoC is powered on. The Boot ROM is responsible
122
+ * for loading user code (e.g. a bootloader) from any
123
+ * of the supported external devices and writing the
124
+ * downloaded code to internal SRAM. After loading the SoC
125
+ * begins executing the code written to SRAM.
126
+ *
127
+ * This function emulates the Boot ROM by copying 32 KiB
128
+ * of data from the given block device and writes it to
129
+ * the start of the first internal SRAM memory.
130
+ *
131
+ * @s: Allwinner R40 state object pointer
132
+ * @blk: Block backend device object pointer
133
+ * @unit: the mmc control's unit
134
+ */
135
+bool allwinner_r40_bootrom_setup(AwR40State *s, BlockBackend *blk, int unit);
136
+
137
+#endif /* HW_ARM_ALLWINNER_R40_H */
138
diff --git a/hw/arm/allwinner-r40.c b/hw/arm/allwinner-r40.c
75
new file mode 100644
139
new file mode 100644
76
index XXXXXXX..XXXXXXX
140
index XXXXXXX..XXXXXXX
77
--- /dev/null
141
--- /dev/null
78
+++ b/include/hw/adc/npcm7xx_adc.h
142
+++ b/hw/arm/allwinner-r40.c
79
@@ -XXX,XX +XXX,XX @@
143
@@ -XXX,XX +XXX,XX @@
80
+/*
144
+/*
81
+ * Nuvoton NPCM7xx ADC Module
145
+ * Allwinner R40/A40i/T3 System on Chip emulation
82
+ *
146
+ *
83
+ * Copyright 2020 Google LLC
147
+ * Copyright (C) 2023 qianfan Zhao <qianfanguijin@163.com>
84
+ *
148
+ *
85
+ * This program is free software; you can redistribute it and/or modify it
149
+ * This program is free software: you can redistribute it and/or modify
86
+ * under the terms of the GNU General Public License as published by the
150
+ * it under the terms of the GNU General Public License as published by
87
+ * Free Software Foundation; either version 2 of the License, or
151
+ * the Free Software Foundation, either version 2 of the License, or
88
+ * (at your option) any later version.
152
+ * (at your option) any later version.
89
+ *
153
+ *
90
+ * This program is distributed in the hope that it will be useful, but WITHOUT
154
+ * This program is distributed in the hope that it will be useful,
91
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
155
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
92
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
156
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
93
+ * for more details.
157
+ * GNU General Public License for more details.
158
+ *
159
+ * You should have received a copy of the GNU General Public License
160
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
94
+ */
161
+ */
95
+#ifndef NPCM7XX_ADC_H
162
+
96
+#define NPCM7XX_ADC_H
163
+#include "qemu/osdep.h"
97
+
164
+#include "qapi/error.h"
98
+#include "hw/clock.h"
165
+#include "qemu/error-report.h"
99
+#include "hw/irq.h"
166
+#include "qemu/bswap.h"
167
+#include "qemu/module.h"
168
+#include "qemu/units.h"
169
+#include "hw/qdev-core.h"
100
+#include "hw/sysbus.h"
170
+#include "hw/sysbus.h"
101
+#include "qemu/timer.h"
171
+#include "hw/char/serial.h"
102
+
172
+#include "hw/misc/unimp.h"
103
+#define NPCM7XX_ADC_NUM_INPUTS 8
173
+#include "hw/usb/hcd-ehci.h"
104
+/**
174
+#include "hw/loader.h"
105
+ * This value should not be changed unless write_adc_calibration function in
175
+#include "sysemu/sysemu.h"
106
+ * hw/arm/npcm7xx.c is also changed.
176
+#include "hw/arm/allwinner-r40.h"
107
+ */
177
+
108
+#define NPCM7XX_ADC_NUM_CALIB 2
178
+/* Memory map */
109
+
179
+const hwaddr allwinner_r40_memmap[] = {
110
+/**
180
+ [AW_R40_DEV_SRAM_A1] = 0x00000000,
111
+ * struct NPCM7xxADCState - Analog to Digital Converter Module device state.
181
+ [AW_R40_DEV_SRAM_A2] = 0x00004000,
112
+ * @parent: System bus device.
182
+ [AW_R40_DEV_SRAM_A3] = 0x00008000,
113
+ * @iomem: Memory region through which registers are accessed.
183
+ [AW_R40_DEV_SRAM_A4] = 0x0000b400,
114
+ * @conv_timer: The timer counts down remaining cycles for the conversion.
184
+ [AW_R40_DEV_MMC0] = 0x01c0f000,
115
+ * @irq: GIC interrupt line to fire on expiration (if enabled).
185
+ [AW_R40_DEV_MMC1] = 0x01c10000,
116
+ * @con: The Control Register.
186
+ [AW_R40_DEV_MMC2] = 0x01c11000,
117
+ * @data: The Data Buffer.
187
+ [AW_R40_DEV_MMC3] = 0x01c12000,
118
+ * @clock: The ADC Clock.
188
+ [AW_R40_DEV_PIT] = 0x01c20c00,
119
+ * @adci: The input voltage in units of uV. 1uv = 1e-6V.
189
+ [AW_R40_DEV_UART0] = 0x01c28000,
120
+ * @vref: The external reference voltage.
190
+ [AW_R40_DEV_GIC_DIST] = 0x01c81000,
121
+ * @iref: The internal reference voltage, initialized at launch time.
191
+ [AW_R40_DEV_GIC_CPU] = 0x01c82000,
122
+ * @rv: The calibrated output values of 0.5V and 1.5V for the ADC.
192
+ [AW_R40_DEV_GIC_HYP] = 0x01c84000,
123
+ */
193
+ [AW_R40_DEV_GIC_VCPU] = 0x01c86000,
124
+typedef struct {
194
+ [AW_R40_DEV_SDRAM] = 0x40000000
125
+ SysBusDevice parent;
195
+};
126
+
196
+
127
+ MemoryRegion iomem;
197
+/* List of unimplemented devices */
128
+
198
+struct AwR40Unimplemented {
129
+ QEMUTimer conv_timer;
199
+ const char *device_name;
130
+
200
+ hwaddr base;
131
+ qemu_irq irq;
201
+ hwaddr size;
132
+ uint32_t con;
202
+};
133
+ uint32_t data;
203
+
134
+ Clock *clock;
204
+static struct AwR40Unimplemented r40_unimplemented[] = {
135
+
205
+ { "d-engine", 0x01000000, 4 * MiB },
136
+ /* Voltages are in unit of uV. 1V = 1000000uV. */
206
+ { "d-inter", 0x01400000, 128 * KiB },
137
+ uint32_t adci[NPCM7XX_ADC_NUM_INPUTS];
207
+ { "sram-c", 0x01c00000, 4 * KiB },
138
+ uint32_t vref;
208
+ { "dma", 0x01c02000, 4 * KiB },
139
+ uint32_t iref;
209
+ { "nfdc", 0x01c03000, 4 * KiB },
140
+
210
+ { "ts", 0x01c04000, 4 * KiB },
141
+ uint16_t calibration_r_values[NPCM7XX_ADC_NUM_CALIB];
211
+ { "spi0", 0x01c05000, 4 * KiB },
142
+} NPCM7xxADCState;
212
+ { "spi1", 0x01c06000, 4 * KiB },
143
+
213
+ { "cs0", 0x01c09000, 4 * KiB },
144
+#define TYPE_NPCM7XX_ADC "npcm7xx-adc"
214
+ { "keymem", 0x01c0a000, 4 * KiB },
145
+#define NPCM7XX_ADC(obj) \
215
+ { "emac", 0x01c0b000, 4 * KiB },
146
+ OBJECT_CHECK(NPCM7xxADCState, (obj), TYPE_NPCM7XX_ADC)
216
+ { "usb0-otg", 0x01c13000, 4 * KiB },
147
+
217
+ { "usb0-host", 0x01c14000, 4 * KiB },
148
+#endif /* NPCM7XX_ADC_H */
218
+ { "crypto", 0x01c15000, 4 * KiB },
149
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
219
+ { "spi2", 0x01c17000, 4 * KiB },
150
index XXXXXXX..XXXXXXX 100644
220
+ { "sata", 0x01c18000, 4 * KiB },
151
--- a/include/hw/arm/npcm7xx.h
221
+ { "usb1-host", 0x01c19000, 4 * KiB },
152
+++ b/include/hw/arm/npcm7xx.h
222
+ { "sid", 0x01c1b000, 4 * KiB },
153
@@ -XXX,XX +XXX,XX @@
223
+ { "usb2-host", 0x01c1c000, 4 * KiB },
154
#define NPCM7XX_H
224
+ { "cs1", 0x01c1d000, 4 * KiB },
155
225
+ { "spi3", 0x01c1f000, 4 * KiB },
156
#include "hw/boards.h"
226
+ { "ccu", 0x01c20000, 1 * KiB },
157
+#include "hw/adc/npcm7xx_adc.h"
227
+ { "rtc", 0x01c20400, 1 * KiB },
158
#include "hw/cpu/a9mpcore.h"
228
+ { "pio", 0x01c20800, 1 * KiB },
159
#include "hw/gpio/npcm7xx_gpio.h"
229
+ { "owa", 0x01c21000, 1 * KiB },
160
#include "hw/mem/npcm7xx_mc.h"
230
+ { "ac97", 0x01c21400, 1 * KiB },
161
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
231
+ { "cir0", 0x01c21800, 1 * KiB },
162
NPCM7xxGCRState gcr;
232
+ { "cir1", 0x01c21c00, 1 * KiB },
163
NPCM7xxCLKState clk;
233
+ { "pcm0", 0x01c22000, 1 * KiB },
164
NPCM7xxTimerCtrlState tim[3];
234
+ { "pcm1", 0x01c22400, 1 * KiB },
165
+ NPCM7xxADCState adc;
235
+ { "pcm2", 0x01c22800, 1 * KiB },
166
NPCM7xxOTPState key_storage;
236
+ { "audio", 0x01c22c00, 1 * KiB },
167
NPCM7xxOTPState fuse_array;
237
+ { "keypad", 0x01c23000, 1 * KiB },
168
NPCM7xxMCState mc;
238
+ { "pwm", 0x01c23400, 1 * KiB },
169
diff --git a/hw/adc/npcm7xx_adc.c b/hw/adc/npcm7xx_adc.c
239
+ { "keyadc", 0x01c24400, 1 * KiB },
240
+ { "ths", 0x01c24c00, 1 * KiB },
241
+ { "rtp", 0x01c25000, 1 * KiB },
242
+ { "pmu", 0x01c25400, 1 * KiB },
243
+ { "cpu-cfg", 0x01c25c00, 1 * KiB },
244
+ { "uart0", 0x01c28000, 1 * KiB },
245
+ { "uart1", 0x01c28400, 1 * KiB },
246
+ { "uart2", 0x01c28800, 1 * KiB },
247
+ { "uart3", 0x01c28c00, 1 * KiB },
248
+ { "uart4", 0x01c29000, 1 * KiB },
249
+ { "uart5", 0x01c29400, 1 * KiB },
250
+ { "uart6", 0x01c29800, 1 * KiB },
251
+ { "uart7", 0x01c29c00, 1 * KiB },
252
+ { "ps20", 0x01c2a000, 1 * KiB },
253
+ { "ps21", 0x01c2a400, 1 * KiB },
254
+ { "twi0", 0x01c2ac00, 1 * KiB },
255
+ { "twi1", 0x01c2b000, 1 * KiB },
256
+ { "twi2", 0x01c2b400, 1 * KiB },
257
+ { "twi3", 0x01c2b800, 1 * KiB },
258
+ { "twi4", 0x01c2c000, 1 * KiB },
259
+ { "scr", 0x01c2c400, 1 * KiB },
260
+ { "tvd-top", 0x01c30000, 4 * KiB },
261
+ { "tvd0", 0x01c31000, 4 * KiB },
262
+ { "tvd1", 0x01c32000, 4 * KiB },
263
+ { "tvd2", 0x01c33000, 4 * KiB },
264
+ { "tvd3", 0x01c34000, 4 * KiB },
265
+ { "gpu", 0x01c40000, 64 * KiB },
266
+ { "gmac", 0x01c50000, 64 * KiB },
267
+ { "hstmr", 0x01c60000, 4 * KiB },
268
+ { "dram-com", 0x01c62000, 4 * KiB },
269
+ { "dram-ctl", 0x01c63000, 4 * KiB },
270
+ { "tcon-top", 0x01c70000, 4 * KiB },
271
+ { "lcd0", 0x01c71000, 4 * KiB },
272
+ { "lcd1", 0x01c72000, 4 * KiB },
273
+ { "tv0", 0x01c73000, 4 * KiB },
274
+ { "tv1", 0x01c74000, 4 * KiB },
275
+ { "tve-top", 0x01c90000, 16 * KiB },
276
+ { "tve0", 0x01c94000, 16 * KiB },
277
+ { "tve1", 0x01c98000, 16 * KiB },
278
+ { "mipi_dsi", 0x01ca0000, 4 * KiB },
279
+ { "mipi_dphy", 0x01ca1000, 4 * KiB },
280
+ { "ve", 0x01d00000, 1024 * KiB },
281
+ { "mp", 0x01e80000, 128 * KiB },
282
+ { "hdmi", 0x01ee0000, 128 * KiB },
283
+ { "prcm", 0x01f01400, 1 * KiB },
284
+ { "debug", 0x3f500000, 64 * KiB },
285
+ { "cpubist", 0x3f501000, 4 * KiB },
286
+ { "dcu", 0x3fff0000, 64 * KiB },
287
+ { "hstmr", 0x01c60000, 4 * KiB },
288
+ { "brom", 0xffff0000, 36 * KiB }
289
+};
290
+
291
+/* Per Processor Interrupts */
292
+enum {
293
+ AW_R40_GIC_PPI_MAINT = 9,
294
+ AW_R40_GIC_PPI_HYPTIMER = 10,
295
+ AW_R40_GIC_PPI_VIRTTIMER = 11,
296
+ AW_R40_GIC_PPI_SECTIMER = 13,
297
+ AW_R40_GIC_PPI_PHYSTIMER = 14
298
+};
299
+
300
+/* Shared Processor Interrupts */
301
+enum {
302
+ AW_R40_GIC_SPI_UART0 = 1,
303
+ AW_R40_GIC_SPI_TIMER0 = 22,
304
+ AW_R40_GIC_SPI_TIMER1 = 23,
305
+ AW_R40_GIC_SPI_MMC0 = 32,
306
+ AW_R40_GIC_SPI_MMC1 = 33,
307
+ AW_R40_GIC_SPI_MMC2 = 34,
308
+ AW_R40_GIC_SPI_MMC3 = 35,
309
+};
310
+
311
+/* Allwinner R40 general constants */
312
+enum {
313
+ AW_R40_GIC_NUM_SPI = 128
314
+};
315
+
316
+#define BOOT0_MAGIC "eGON.BT0"
317
+
318
+/* The low 8-bits of the 'boot_media' field in the SPL header */
319
+#define SUNXI_BOOTED_FROM_MMC0 0
320
+#define SUNXI_BOOTED_FROM_NAND 1
321
+#define SUNXI_BOOTED_FROM_MMC2 2
322
+#define SUNXI_BOOTED_FROM_SPI 3
323
+
324
+struct boot_file_head {
325
+ uint32_t b_instruction;
326
+ uint8_t magic[8];
327
+ uint32_t check_sum;
328
+ uint32_t length;
329
+ uint32_t pub_head_size;
330
+ uint32_t fel_script_address;
331
+ uint32_t fel_uEnv_length;
332
+ uint32_t dt_name_offset;
333
+ uint32_t dram_size;
334
+ uint32_t boot_media;
335
+ uint32_t string_pool[13];
336
+};
337
+
338
+bool allwinner_r40_bootrom_setup(AwR40State *s, BlockBackend *blk, int unit)
339
+{
340
+ const int64_t rom_size = 32 * KiB;
341
+ g_autofree uint8_t *buffer = g_new0(uint8_t, rom_size);
342
+ struct boot_file_head *head = (struct boot_file_head *)buffer;
343
+
344
+ if (blk_pread(blk, 8 * KiB, rom_size, buffer, 0) < 0) {
345
+ error_setg(&error_fatal, "%s: failed to read BlockBackend data",
346
+ __func__);
347
+ return false;
348
+ }
349
+
350
+ /* we only check the magic string here. */
351
+ if (memcmp(head->magic, BOOT0_MAGIC, sizeof(head->magic))) {
352
+ return false;
353
+ }
354
+
355
+ /*
356
+ * Simulate the behavior of the bootROM, it will change the boot_media
357
+ * flag to indicate where the chip is booting from. R40 can boot from
358
+ * mmc0 or mmc2, the default value of boot_media is zero
359
+ * (SUNXI_BOOTED_FROM_MMC0), let's fix this flag when it is booting from
360
+ * the others.
361
+ */
362
+ if (unit == 2) {
363
+ head->boot_media = cpu_to_le32(SUNXI_BOOTED_FROM_MMC2);
364
+ } else {
365
+ head->boot_media = cpu_to_le32(SUNXI_BOOTED_FROM_MMC0);
366
+ }
367
+
368
+ rom_add_blob("allwinner-r40.bootrom", buffer, rom_size,
369
+ rom_size, s->memmap[AW_R40_DEV_SRAM_A1],
370
+ NULL, NULL, NULL, NULL, false);
371
+ return true;
372
+}
373
+
374
+static void allwinner_r40_init(Object *obj)
375
+{
376
+ static const char *mmc_names[AW_R40_NUM_MMCS] = {
377
+ "mmc0", "mmc1", "mmc2", "mmc3"
378
+ };
379
+ AwR40State *s = AW_R40(obj);
380
+
381
+ s->memmap = allwinner_r40_memmap;
382
+
383
+ for (int i = 0; i < AW_R40_NUM_CPUS; i++) {
384
+ object_initialize_child(obj, "cpu[*]", &s->cpus[i],
385
+ ARM_CPU_TYPE_NAME("cortex-a7"));
386
+ }
387
+
388
+ object_initialize_child(obj, "gic", &s->gic, TYPE_ARM_GIC);
389
+
390
+ object_initialize_child(obj, "timer", &s->timer, TYPE_AW_A10_PIT);
391
+ object_property_add_alias(obj, "clk0-freq", OBJECT(&s->timer),
392
+ "clk0-freq");
393
+ object_property_add_alias(obj, "clk1-freq", OBJECT(&s->timer),
394
+ "clk1-freq");
395
+
396
+ for (int i = 0; i < AW_R40_NUM_MMCS; i++) {
397
+ object_initialize_child(obj, mmc_names[i], &s->mmc[i],
398
+ TYPE_AW_SDHOST_SUN5I);
399
+ }
400
+}
401
+
402
+static void allwinner_r40_realize(DeviceState *dev, Error **errp)
403
+{
404
+ AwR40State *s = AW_R40(dev);
405
+ unsigned i;
406
+
407
+ /* CPUs */
408
+ for (i = 0; i < AW_R40_NUM_CPUS; i++) {
409
+
410
+ /*
411
+ * Disable secondary CPUs. Guest EL3 firmware will start
412
+ * them via CPU reset control registers.
413
+ */
414
+ qdev_prop_set_bit(DEVICE(&s->cpus[i]), "start-powered-off",
415
+ i > 0);
416
+
417
+ /* All exception levels required */
418
+ qdev_prop_set_bit(DEVICE(&s->cpus[i]), "has_el3", true);
419
+ qdev_prop_set_bit(DEVICE(&s->cpus[i]), "has_el2", true);
420
+
421
+ /* Mark realized */
422
+ qdev_realize(DEVICE(&s->cpus[i]), NULL, &error_fatal);
423
+ }
424
+
425
+ /* Generic Interrupt Controller */
426
+ qdev_prop_set_uint32(DEVICE(&s->gic), "num-irq", AW_R40_GIC_NUM_SPI +
427
+ GIC_INTERNAL);
428
+ qdev_prop_set_uint32(DEVICE(&s->gic), "revision", 2);
429
+ qdev_prop_set_uint32(DEVICE(&s->gic), "num-cpu", AW_R40_NUM_CPUS);
430
+ qdev_prop_set_bit(DEVICE(&s->gic), "has-security-extensions", false);
431
+ qdev_prop_set_bit(DEVICE(&s->gic), "has-virtualization-extensions", true);
432
+ sysbus_realize(SYS_BUS_DEVICE(&s->gic), &error_fatal);
433
+
434
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 0, s->memmap[AW_R40_DEV_GIC_DIST]);
435
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 1, s->memmap[AW_R40_DEV_GIC_CPU]);
436
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 2, s->memmap[AW_R40_DEV_GIC_HYP]);
437
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 3, s->memmap[AW_R40_DEV_GIC_VCPU]);
438
+
439
+ /*
440
+ * Wire the outputs from each CPU's generic timer and the GICv2
441
+ * maintenance interrupt signal to the appropriate GIC PPI inputs,
442
+ * and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs.
443
+ */
444
+ for (i = 0; i < AW_R40_NUM_CPUS; i++) {
445
+ DeviceState *cpudev = DEVICE(&s->cpus[i]);
446
+ int ppibase = AW_R40_GIC_NUM_SPI + i * GIC_INTERNAL + GIC_NR_SGIS;
447
+ int irq;
448
+ /*
449
+ * Mapping from the output timer irq lines from the CPU to the
450
+ * GIC PPI inputs used for this board.
451
+ */
452
+ const int timer_irq[] = {
453
+ [GTIMER_PHYS] = AW_R40_GIC_PPI_PHYSTIMER,
454
+ [GTIMER_VIRT] = AW_R40_GIC_PPI_VIRTTIMER,
455
+ [GTIMER_HYP] = AW_R40_GIC_PPI_HYPTIMER,
456
+ [GTIMER_SEC] = AW_R40_GIC_PPI_SECTIMER,
457
+ };
458
+
459
+ /* Connect CPU timer outputs to GIC PPI inputs */
460
+ for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
461
+ qdev_connect_gpio_out(cpudev, irq,
462
+ qdev_get_gpio_in(DEVICE(&s->gic),
463
+ ppibase + timer_irq[irq]));
464
+ }
465
+
466
+ /* Connect GIC outputs to CPU interrupt inputs */
467
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i,
468
+ qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
469
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i + AW_R40_NUM_CPUS,
470
+ qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
471
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i + (2 * AW_R40_NUM_CPUS),
472
+ qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
473
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i + (3 * AW_R40_NUM_CPUS),
474
+ qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
475
+
476
+ /* GIC maintenance signal */
477
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gic), i + (4 * AW_R40_NUM_CPUS),
478
+ qdev_get_gpio_in(DEVICE(&s->gic),
479
+ ppibase + AW_R40_GIC_PPI_MAINT));
480
+ }
481
+
482
+ /* Timer */
483
+ sysbus_realize(SYS_BUS_DEVICE(&s->timer), &error_fatal);
484
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->timer), 0, s->memmap[AW_R40_DEV_PIT]);
485
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer), 0,
486
+ qdev_get_gpio_in(DEVICE(&s->gic),
487
+ AW_R40_GIC_SPI_TIMER0));
488
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer), 1,
489
+ qdev_get_gpio_in(DEVICE(&s->gic),
490
+ AW_R40_GIC_SPI_TIMER1));
491
+
492
+ /* SRAM */
493
+ memory_region_init_ram(&s->sram_a1, OBJECT(dev), "sram A1",
494
+ 16 * KiB, &error_abort);
495
+ memory_region_init_ram(&s->sram_a2, OBJECT(dev), "sram A2",
496
+ 16 * KiB, &error_abort);
497
+ memory_region_init_ram(&s->sram_a3, OBJECT(dev), "sram A3",
498
+ 13 * KiB, &error_abort);
499
+ memory_region_init_ram(&s->sram_a4, OBJECT(dev), "sram A4",
500
+ 3 * KiB, &error_abort);
501
+ memory_region_add_subregion(get_system_memory(),
502
+ s->memmap[AW_R40_DEV_SRAM_A1], &s->sram_a1);
503
+ memory_region_add_subregion(get_system_memory(),
504
+ s->memmap[AW_R40_DEV_SRAM_A2], &s->sram_a2);
505
+ memory_region_add_subregion(get_system_memory(),
506
+ s->memmap[AW_R40_DEV_SRAM_A3], &s->sram_a3);
507
+ memory_region_add_subregion(get_system_memory(),
508
+ s->memmap[AW_R40_DEV_SRAM_A4], &s->sram_a4);
509
+
510
+ /* SD/MMC */
511
+ for (int i = 0; i < AW_R40_NUM_MMCS; i++) {
512
+ qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->gic),
513
+ AW_R40_GIC_SPI_MMC0 + i);
514
+ const hwaddr addr = s->memmap[AW_R40_DEV_MMC0 + i];
515
+
516
+ object_property_set_link(OBJECT(&s->mmc[i]), "dma-memory",
517
+ OBJECT(get_system_memory()), &error_fatal);
518
+ sysbus_realize(SYS_BUS_DEVICE(&s->mmc[i]), &error_fatal);
519
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->mmc[i]), 0, addr);
520
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->mmc[i]), 0, irq);
521
+ }
522
+
523
+ /* UART0. For future clocktree API: All UARTS are connected to APB2_CLK. */
524
+ serial_mm_init(get_system_memory(), s->memmap[AW_R40_DEV_UART0], 2,
525
+ qdev_get_gpio_in(DEVICE(&s->gic), AW_R40_GIC_SPI_UART0),
526
+ 115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
527
+
528
+ /* Unimplemented devices */
529
+ for (i = 0; i < ARRAY_SIZE(r40_unimplemented); i++) {
530
+ create_unimplemented_device(r40_unimplemented[i].device_name,
531
+ r40_unimplemented[i].base,
532
+ r40_unimplemented[i].size);
533
+ }
534
+}
535
+
536
+static void allwinner_r40_class_init(ObjectClass *oc, void *data)
537
+{
538
+ DeviceClass *dc = DEVICE_CLASS(oc);
539
+
540
+ dc->realize = allwinner_r40_realize;
541
+ /* Reason: uses serial_hd() in realize function */
542
+ dc->user_creatable = false;
543
+}
544
+
545
+static const TypeInfo allwinner_r40_type_info = {
546
+ .name = TYPE_AW_R40,
547
+ .parent = TYPE_DEVICE,
548
+ .instance_size = sizeof(AwR40State),
549
+ .instance_init = allwinner_r40_init,
550
+ .class_init = allwinner_r40_class_init,
551
+};
552
+
553
+static void allwinner_r40_register_types(void)
554
+{
555
+ type_register_static(&allwinner_r40_type_info);
556
+}
557
+
558
+type_init(allwinner_r40_register_types)
559
diff --git a/hw/arm/bananapi_m2u.c b/hw/arm/bananapi_m2u.c
170
new file mode 100644
560
new file mode 100644
171
index XXXXXXX..XXXXXXX
561
index XXXXXXX..XXXXXXX
172
--- /dev/null
562
--- /dev/null
173
+++ b/hw/adc/npcm7xx_adc.c
563
+++ b/hw/arm/bananapi_m2u.c
174
@@ -XXX,XX +XXX,XX @@
564
@@ -XXX,XX +XXX,XX @@
175
+/*
565
+/*
176
+ * Nuvoton NPCM7xx ADC Module
566
+ * Bananapi M2U emulation
177
+ *
567
+ *
178
+ * Copyright 2020 Google LLC
568
+ * Copyright (C) 2023 qianfan Zhao <qianfanguijin@163.com>
179
+ *
569
+ *
180
+ * This program is free software; you can redistribute it and/or modify it
570
+ * This program is free software: you can redistribute it and/or modify
181
+ * under the terms of the GNU General Public License as published by the
571
+ * it under the terms of the GNU General Public License as published by
182
+ * Free Software Foundation; either version 2 of the License, or
572
+ * the Free Software Foundation, either version 2 of the License, or
183
+ * (at your option) any later version.
573
+ * (at your option) any later version.
184
+ *
574
+ *
185
+ * This program is distributed in the hope that it will be useful, but WITHOUT
575
+ * This program is distributed in the hope that it will be useful,
186
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
576
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
187
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
577
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
188
+ * for more details.
578
+ * GNU General Public License for more details.
579
+ *
580
+ * You should have received a copy of the GNU General Public License
581
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
189
+ */
582
+ */
190
+
583
+
191
+#include "qemu/osdep.h"
584
+#include "qemu/osdep.h"
192
+#include "hw/adc/npcm7xx_adc.h"
585
+#include "qemu/units.h"
193
+#include "hw/qdev-clock.h"
586
+#include "exec/address-spaces.h"
587
+#include "qapi/error.h"
588
+#include "qemu/error-report.h"
589
+#include "hw/boards.h"
194
+#include "hw/qdev-properties.h"
590
+#include "hw/qdev-properties.h"
195
+#include "hw/registerfields.h"
591
+#include "hw/arm/allwinner-r40.h"
196
+#include "migration/vmstate.h"
592
+
197
+#include "qemu/log.h"
593
+static struct arm_boot_info bpim2u_binfo;
198
+#include "qemu/module.h"
594
+
199
+#include "qemu/timer.h"
595
+/*
200
+#include "qemu/units.h"
596
+ * R40 can boot from mmc0 and mmc2, and bpim2u has two mmc interface, one is
201
+#include "trace.h"
597
+ * connected to sdcard and another mount an emmc media.
202
+
598
+ * Attach the mmc driver and try loading bootloader.
203
+REG32(NPCM7XX_ADC_CON, 0x0)
599
+ */
204
+REG32(NPCM7XX_ADC_DATA, 0x4)
600
+static void mmc_attach_drive(AwR40State *s, AwSdHostState *mmc, int unit,
205
+
601
+ bool load_bootroom, bool *bootroom_loaded)
206
+/* Register field definitions. */
207
+#define NPCM7XX_ADC_CON_MUX(rv) extract32(rv, 24, 4)
208
+#define NPCM7XX_ADC_CON_INT_EN BIT(21)
209
+#define NPCM7XX_ADC_CON_REFSEL BIT(19)
210
+#define NPCM7XX_ADC_CON_INT BIT(18)
211
+#define NPCM7XX_ADC_CON_EN BIT(17)
212
+#define NPCM7XX_ADC_CON_RST BIT(16)
213
+#define NPCM7XX_ADC_CON_CONV BIT(14)
214
+#define NPCM7XX_ADC_CON_DIV(rv) extract32(rv, 1, 8)
215
+
216
+#define NPCM7XX_ADC_MAX_RESULT 1023
217
+#define NPCM7XX_ADC_DEFAULT_IREF 2000000
218
+#define NPCM7XX_ADC_CONV_CYCLES 20
219
+#define NPCM7XX_ADC_RESET_CYCLES 10
220
+#define NPCM7XX_ADC_R0_INPUT 500000
221
+#define NPCM7XX_ADC_R1_INPUT 1500000
222
+
223
+static void npcm7xx_adc_reset(NPCM7xxADCState *s)
224
+{
602
+{
225
+ timer_del(&s->conv_timer);
603
+ DriveInfo *di = drive_get(IF_SD, 0, unit);
226
+ s->con = 0x000c0001;
604
+ BlockBackend *blk = di ? blk_by_legacy_dinfo(di) : NULL;
227
+ s->data = 0x00000000;
605
+ BusState *bus;
606
+ DeviceState *carddev;
607
+
608
+ bus = qdev_get_child_bus(DEVICE(mmc), "sd-bus");
609
+ if (bus == NULL) {
610
+ error_report("No SD bus found in SOC object");
611
+ exit(1);
612
+ }
613
+
614
+ carddev = qdev_new(TYPE_SD_CARD);
615
+ qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal);
616
+ qdev_realize_and_unref(carddev, bus, &error_fatal);
617
+
618
+ if (load_bootroom && blk && blk_is_available(blk)) {
619
+ /* Use Boot ROM to copy data from SD card to SRAM */
620
+ *bootroom_loaded = allwinner_r40_bootrom_setup(s, blk, unit);
621
+ }
228
+}
622
+}
229
+
623
+
230
+static uint32_t npcm7xx_adc_convert(uint32_t input, uint32_t ref)
624
+static void bpim2u_init(MachineState *machine)
231
+{
625
+{
232
+ uint32_t result;
626
+ bool bootroom_loaded = false;
233
+
627
+ AwR40State *r40;
234
+ result = input * (NPCM7XX_ADC_MAX_RESULT + 1) / ref;
628
+
235
+ if (result > NPCM7XX_ADC_MAX_RESULT) {
629
+ /* BIOS is not supported by this board */
236
+ result = NPCM7XX_ADC_MAX_RESULT;
630
+ if (machine->firmware) {
237
+ }
631
+ error_report("BIOS not supported for this machine");
238
+
632
+ exit(1);
239
+ return result;
633
+ }
634
+
635
+ /* Only allow Cortex-A7 for this board */
636
+ if (strcmp(machine->cpu_type, ARM_CPU_TYPE_NAME("cortex-a7")) != 0) {
637
+ error_report("This board can only be used with cortex-a7 CPU");
638
+ exit(1);
639
+ }
640
+
641
+ r40 = AW_R40(object_new(TYPE_AW_R40));
642
+ object_property_add_child(OBJECT(machine), "soc", OBJECT(r40));
643
+ object_unref(OBJECT(r40));
644
+
645
+ /* Setup timer properties */
646
+ object_property_set_int(OBJECT(r40), "clk0-freq", 32768, &error_abort);
647
+ object_property_set_int(OBJECT(r40), "clk1-freq", 24 * 1000 * 1000,
648
+ &error_abort);
649
+
650
+ /* Mark R40 object realized */
651
+ qdev_realize(DEVICE(r40), NULL, &error_abort);
652
+
653
+ /*
654
+ * Plug in SD card and try load bootrom, R40 has 4 mmc controllers but can
655
+ * only booting from mmc0 and mmc2.
656
+ */
657
+ for (int i = 0; i < AW_R40_NUM_MMCS; i++) {
658
+ switch (i) {
659
+ case 0:
660
+ case 2:
661
+ mmc_attach_drive(r40, &r40->mmc[i], i,
662
+ !machine->kernel_filename && !bootroom_loaded,
663
+ &bootroom_loaded);
664
+ break;
665
+ default:
666
+ mmc_attach_drive(r40, &r40->mmc[i], i, false, NULL);
667
+ break;
668
+ }
669
+ }
670
+
671
+ /* SDRAM */
672
+ memory_region_add_subregion(get_system_memory(),
673
+ r40->memmap[AW_R40_DEV_SDRAM], machine->ram);
674
+
675
+ bpim2u_binfo.loader_start = r40->memmap[AW_R40_DEV_SDRAM];
676
+ bpim2u_binfo.ram_size = machine->ram_size;
677
+ bpim2u_binfo.psci_conduit = QEMU_PSCI_CONDUIT_SMC;
678
+ arm_load_kernel(ARM_CPU(first_cpu), machine, &bpim2u_binfo);
240
+}
679
+}
241
+
680
+
242
+static uint32_t npcm7xx_adc_prescaler(NPCM7xxADCState *s)
681
+static void bpim2u_machine_init(MachineClass *mc)
243
+{
682
+{
244
+ return 2 * (NPCM7XX_ADC_CON_DIV(s->con) + 1);
683
+ mc->desc = "Bananapi M2U (Cortex-A7)";
684
+ mc->init = bpim2u_init;
685
+ mc->min_cpus = AW_R40_NUM_CPUS;
686
+ mc->max_cpus = AW_R40_NUM_CPUS;
687
+ mc->default_cpus = AW_R40_NUM_CPUS;
688
+ mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a7");
689
+ mc->default_ram_size = 1 * GiB;
690
+ mc->default_ram_id = "bpim2u.ram";
245
+}
691
+}
246
+
692
+
247
+static void npcm7xx_adc_start_timer(Clock *clk, QEMUTimer *timer,
693
+DEFINE_MACHINE("bpim2u", bpim2u_machine_init)
248
+ uint32_t cycles, uint32_t prescaler)
694
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
249
+{
250
+ int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
251
+ int64_t ticks = cycles;
252
+ int64_t ns;
253
+
254
+ ticks *= prescaler;
255
+ ns = clock_ticks_to_ns(clk, ticks);
256
+ ns += now;
257
+ timer_mod(timer, ns);
258
+}
259
+
260
+static void npcm7xx_adc_start_convert(NPCM7xxADCState *s)
261
+{
262
+ uint32_t prescaler = npcm7xx_adc_prescaler(s);
263
+
264
+ npcm7xx_adc_start_timer(s->clock, &s->conv_timer, NPCM7XX_ADC_CONV_CYCLES,
265
+ prescaler);
266
+}
267
+
268
+static void npcm7xx_adc_convert_done(void *opaque)
269
+{
270
+ NPCM7xxADCState *s = opaque;
271
+ uint32_t input = NPCM7XX_ADC_CON_MUX(s->con);
272
+ uint32_t ref = (s->con & NPCM7XX_ADC_CON_REFSEL)
273
+ ? s->iref : s->vref;
274
+
275
+ if (input >= NPCM7XX_ADC_NUM_INPUTS) {
276
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid input: %u\n",
277
+ __func__, input);
278
+ return;
279
+ }
280
+ s->data = npcm7xx_adc_convert(s->adci[input], ref);
281
+ if (s->con & NPCM7XX_ADC_CON_INT_EN) {
282
+ s->con |= NPCM7XX_ADC_CON_INT;
283
+ qemu_irq_raise(s->irq);
284
+ }
285
+ s->con &= ~NPCM7XX_ADC_CON_CONV;
286
+}
287
+
288
+static void npcm7xx_adc_calibrate(NPCM7xxADCState *adc)
289
+{
290
+ adc->calibration_r_values[0] = npcm7xx_adc_convert(NPCM7XX_ADC_R0_INPUT,
291
+ adc->iref);
292
+ adc->calibration_r_values[1] = npcm7xx_adc_convert(NPCM7XX_ADC_R1_INPUT,
293
+ adc->iref);
294
+}
295
+
296
+static void npcm7xx_adc_write_con(NPCM7xxADCState *s, uint32_t new_con)
297
+{
298
+ uint32_t old_con = s->con;
299
+
300
+ /* Write ADC_INT to 1 to clear it */
301
+ if (new_con & NPCM7XX_ADC_CON_INT) {
302
+ new_con &= ~NPCM7XX_ADC_CON_INT;
303
+ qemu_irq_lower(s->irq);
304
+ } else if (old_con & NPCM7XX_ADC_CON_INT) {
305
+ new_con |= NPCM7XX_ADC_CON_INT;
306
+ }
307
+
308
+ s->con = new_con;
309
+
310
+ if (s->con & NPCM7XX_ADC_CON_RST) {
311
+ npcm7xx_adc_reset(s);
312
+ return;
313
+ }
314
+
315
+ if ((s->con & NPCM7XX_ADC_CON_EN)) {
316
+ if (s->con & NPCM7XX_ADC_CON_CONV) {
317
+ if (!(old_con & NPCM7XX_ADC_CON_CONV)) {
318
+ npcm7xx_adc_start_convert(s);
319
+ }
320
+ } else {
321
+ timer_del(&s->conv_timer);
322
+ }
323
+ }
324
+}
325
+
326
+static uint64_t npcm7xx_adc_read(void *opaque, hwaddr offset, unsigned size)
327
+{
328
+ uint64_t value = 0;
329
+ NPCM7xxADCState *s = opaque;
330
+
331
+ switch (offset) {
332
+ case A_NPCM7XX_ADC_CON:
333
+ value = s->con;
334
+ break;
335
+
336
+ case A_NPCM7XX_ADC_DATA:
337
+ value = s->data;
338
+ break;
339
+
340
+ default:
341
+ qemu_log_mask(LOG_GUEST_ERROR,
342
+ "%s: invalid offset 0x%04" HWADDR_PRIx "\n",
343
+ __func__, offset);
344
+ break;
345
+ }
346
+
347
+ trace_npcm7xx_adc_read(DEVICE(s)->canonical_path, offset, value);
348
+ return value;
349
+}
350
+
351
+static void npcm7xx_adc_write(void *opaque, hwaddr offset, uint64_t v,
352
+ unsigned size)
353
+{
354
+ NPCM7xxADCState *s = opaque;
355
+
356
+ trace_npcm7xx_adc_write(DEVICE(s)->canonical_path, offset, v);
357
+ switch (offset) {
358
+ case A_NPCM7XX_ADC_CON:
359
+ npcm7xx_adc_write_con(s, v);
360
+ break;
361
+
362
+ case A_NPCM7XX_ADC_DATA:
363
+ qemu_log_mask(LOG_GUEST_ERROR,
364
+ "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n",
365
+ __func__, offset);
366
+ break;
367
+
368
+ default:
369
+ qemu_log_mask(LOG_GUEST_ERROR,
370
+ "%s: invalid offset 0x%04" HWADDR_PRIx "\n",
371
+ __func__, offset);
372
+ break;
373
+ }
374
+
375
+}
376
+
377
+static const struct MemoryRegionOps npcm7xx_adc_ops = {
378
+ .read = npcm7xx_adc_read,
379
+ .write = npcm7xx_adc_write,
380
+ .endianness = DEVICE_LITTLE_ENDIAN,
381
+ .valid = {
382
+ .min_access_size = 4,
383
+ .max_access_size = 4,
384
+ .unaligned = false,
385
+ },
386
+};
387
+
388
+static void npcm7xx_adc_enter_reset(Object *obj, ResetType type)
389
+{
390
+ NPCM7xxADCState *s = NPCM7XX_ADC(obj);
391
+
392
+ npcm7xx_adc_reset(s);
393
+}
394
+
395
+static void npcm7xx_adc_hold_reset(Object *obj)
396
+{
397
+ NPCM7xxADCState *s = NPCM7XX_ADC(obj);
398
+
399
+ qemu_irq_lower(s->irq);
400
+}
401
+
402
+static void npcm7xx_adc_init(Object *obj)
403
+{
404
+ NPCM7xxADCState *s = NPCM7XX_ADC(obj);
405
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
406
+ int i;
407
+
408
+ sysbus_init_irq(sbd, &s->irq);
409
+
410
+ timer_init_ns(&s->conv_timer, QEMU_CLOCK_VIRTUAL,
411
+ npcm7xx_adc_convert_done, s);
412
+ memory_region_init_io(&s->iomem, obj, &npcm7xx_adc_ops, s,
413
+ TYPE_NPCM7XX_ADC, 4 * KiB);
414
+ sysbus_init_mmio(sbd, &s->iomem);
415
+ s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL);
416
+
417
+ for (i = 0; i < NPCM7XX_ADC_NUM_INPUTS; ++i) {
418
+ object_property_add_uint32_ptr(obj, "adci[*]",
419
+ &s->adci[i], OBJ_PROP_FLAG_WRITE);
420
+ }
421
+ object_property_add_uint32_ptr(obj, "vref",
422
+ &s->vref, OBJ_PROP_FLAG_WRITE);
423
+ npcm7xx_adc_calibrate(s);
424
+}
425
+
426
+static const VMStateDescription vmstate_npcm7xx_adc = {
427
+ .name = "npcm7xx-adc",
428
+ .version_id = 0,
429
+ .minimum_version_id = 0,
430
+ .fields = (VMStateField[]) {
431
+ VMSTATE_TIMER(conv_timer, NPCM7xxADCState),
432
+ VMSTATE_UINT32(con, NPCM7xxADCState),
433
+ VMSTATE_UINT32(data, NPCM7xxADCState),
434
+ VMSTATE_CLOCK(clock, NPCM7xxADCState),
435
+ VMSTATE_UINT32_ARRAY(adci, NPCM7xxADCState, NPCM7XX_ADC_NUM_INPUTS),
436
+ VMSTATE_UINT32(vref, NPCM7xxADCState),
437
+ VMSTATE_UINT32(iref, NPCM7xxADCState),
438
+ VMSTATE_UINT16_ARRAY(calibration_r_values, NPCM7xxADCState,
439
+ NPCM7XX_ADC_NUM_CALIB),
440
+ VMSTATE_END_OF_LIST(),
441
+ },
442
+};
443
+
444
+static Property npcm7xx_timer_properties[] = {
445
+ DEFINE_PROP_UINT32("iref", NPCM7xxADCState, iref, NPCM7XX_ADC_DEFAULT_IREF),
446
+ DEFINE_PROP_END_OF_LIST(),
447
+};
448
+
449
+static void npcm7xx_adc_class_init(ObjectClass *klass, void *data)
450
+{
451
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
452
+ DeviceClass *dc = DEVICE_CLASS(klass);
453
+
454
+ dc->desc = "NPCM7xx ADC Module";
455
+ dc->vmsd = &vmstate_npcm7xx_adc;
456
+ rc->phases.enter = npcm7xx_adc_enter_reset;
457
+ rc->phases.hold = npcm7xx_adc_hold_reset;
458
+
459
+ device_class_set_props(dc, npcm7xx_timer_properties);
460
+}
461
+
462
+static const TypeInfo npcm7xx_adc_info = {
463
+ .name = TYPE_NPCM7XX_ADC,
464
+ .parent = TYPE_SYS_BUS_DEVICE,
465
+ .instance_size = sizeof(NPCM7xxADCState),
466
+ .class_init = npcm7xx_adc_class_init,
467
+ .instance_init = npcm7xx_adc_init,
468
+};
469
+
470
+static void npcm7xx_adc_register_types(void)
471
+{
472
+ type_register_static(&npcm7xx_adc_info);
473
+}
474
+
475
+type_init(npcm7xx_adc_register_types);
476
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
477
index XXXXXXX..XXXXXXX 100644
695
index XXXXXXX..XXXXXXX 100644
478
--- a/hw/arm/npcm7xx.c
696
--- a/hw/arm/Kconfig
479
+++ b/hw/arm/npcm7xx.c
697
+++ b/hw/arm/Kconfig
480
@@ -XXX,XX +XXX,XX @@
698
@@ -XXX,XX +XXX,XX @@ config ALLWINNER_H3
481
#define NPCM7XX_EHCI_BA (0xf0806000)
699
select USB_EHCI_SYSBUS
482
#define NPCM7XX_OHCI_BA (0xf0807000)
700
select SD
483
701
484
+/* ADC Module */
702
+config ALLWINNER_R40
485
+#define NPCM7XX_ADC_BA (0xf000c000)
703
+ bool
486
+
704
+ default y if TCG && ARM
487
/* Internal AHB SRAM */
705
+ select ALLWINNER_A10_PIT
488
#define NPCM7XX_RAM3_BA (0xc0008000)
706
+ select SERIAL
489
#define NPCM7XX_RAM3_SZ (4 * KiB)
707
+ select ARM_TIMER
490
@@ -XXX,XX +XXX,XX @@
708
+ select ARM_GIC
491
#define NPCM7XX_ROM_BA (0xffff0000)
709
+ select UNIMP
492
#define NPCM7XX_ROM_SZ (64 * KiB)
710
+ select SD
493
711
+
494
+
712
config RASPI
495
/* Clock configuration values to be fixed up when bypassing bootloader */
713
bool
496
714
default y
497
/* Run PLL1 at 1600 MHz */
715
diff --git a/hw/arm/meson.build b/hw/arm/meson.build
498
@@ -XXX,XX +XXX,XX @@
499
* interrupts.
500
*/
501
enum NPCM7xxInterrupt {
502
+ NPCM7XX_ADC_IRQ = 0,
503
NPCM7XX_UART0_IRQ = 2,
504
NPCM7XX_UART1_IRQ,
505
NPCM7XX_UART2_IRQ,
506
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init_fuses(NPCM7xxState *s)
507
sizeof(value));
508
}
509
510
+static void npcm7xx_write_adc_calibration(NPCM7xxState *s)
511
+{
512
+ /* Both ADC and the fuse array must have realized. */
513
+ QEMU_BUILD_BUG_ON(sizeof(s->adc.calibration_r_values) != 4);
514
+ npcm7xx_otp_array_write(&s->fuse_array, s->adc.calibration_r_values,
515
+ NPCM7XX_FUSE_ADC_CALIB, sizeof(s->adc.calibration_r_values));
516
+}
517
+
518
static qemu_irq npcm7xx_irq(NPCM7xxState *s, int n)
519
{
520
return qdev_get_gpio_in(DEVICE(&s->a9mpcore), n);
521
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
522
TYPE_NPCM7XX_FUSE_ARRAY);
523
object_initialize_child(obj, "mc", &s->mc, TYPE_NPCM7XX_MC);
524
object_initialize_child(obj, "rng", &s->rng, TYPE_NPCM7XX_RNG);
525
+ object_initialize_child(obj, "adc", &s->adc, TYPE_NPCM7XX_ADC);
526
527
for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
528
object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
529
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
530
sysbus_realize(SYS_BUS_DEVICE(&s->mc), &error_abort);
531
sysbus_mmio_map(SYS_BUS_DEVICE(&s->mc), 0, NPCM7XX_MC_BA);
532
533
+ /* ADC Modules. Cannot fail. */
534
+ qdev_connect_clock_in(DEVICE(&s->adc), "clock", qdev_get_clock_out(
535
+ DEVICE(&s->clk), "adc-clock"));
536
+ sysbus_realize(SYS_BUS_DEVICE(&s->adc), &error_abort);
537
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->adc), 0, NPCM7XX_ADC_BA);
538
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0,
539
+ npcm7xx_irq(s, NPCM7XX_ADC_IRQ));
540
+ npcm7xx_write_adc_calibration(s);
541
+
542
/* Timer Modules (TIM). Cannot fail. */
543
QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_tim_addr) != ARRAY_SIZE(s->tim));
544
for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
545
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
546
create_unimplemented_device("npcm7xx.vdmx", 0xe0800000, 4 * KiB);
547
create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB);
548
create_unimplemented_device("npcm7xx.kcs", 0xf0007000, 4 * KiB);
549
- create_unimplemented_device("npcm7xx.adc", 0xf000c000, 4 * KiB);
550
create_unimplemented_device("npcm7xx.gfxi", 0xf000e000, 4 * KiB);
551
create_unimplemented_device("npcm7xx.gpio[0]", 0xf0010000, 4 * KiB);
552
create_unimplemented_device("npcm7xx.gpio[1]", 0xf0011000, 4 * KiB);
553
diff --git a/tests/qtest/npcm7xx_adc-test.c b/tests/qtest/npcm7xx_adc-test.c
554
new file mode 100644
555
index XXXXXXX..XXXXXXX
556
--- /dev/null
557
+++ b/tests/qtest/npcm7xx_adc-test.c
558
@@ -XXX,XX +XXX,XX @@
559
+/*
560
+ * QTests for Nuvoton NPCM7xx ADCModules.
561
+ *
562
+ * Copyright 2020 Google LLC
563
+ *
564
+ * This program is free software; you can redistribute it and/or modify it
565
+ * under the terms of the GNU General Public License as published by the
566
+ * Free Software Foundation; either version 2 of the License, or
567
+ * (at your option) any later version.
568
+ *
569
+ * This program is distributed in the hope that it will be useful, but WITHOUT
570
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
571
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
572
+ * for more details.
573
+ */
574
+
575
+#include "qemu/osdep.h"
576
+#include "qemu/bitops.h"
577
+#include "qemu/timer.h"
578
+#include "libqos/libqtest.h"
579
+#include "qapi/qmp/qdict.h"
580
+
581
+#define REF_HZ (25000000)
582
+
583
+#define CON_OFFSET 0x0
584
+#define DATA_OFFSET 0x4
585
+
586
+#define NUM_INPUTS 8
587
+#define DEFAULT_IREF 2000000
588
+#define CONV_CYCLES 20
589
+#define RESET_CYCLES 10
590
+#define R0_INPUT 500000
591
+#define R1_INPUT 1500000
592
+#define MAX_RESULT 1023
593
+
594
+#define DEFAULT_CLKDIV 5
595
+
596
+#define FUSE_ARRAY_BA 0xf018a000
597
+#define FCTL_OFFSET 0x14
598
+#define FST_OFFSET 0x0
599
+#define FADDR_OFFSET 0x4
600
+#define FDATA_OFFSET 0x8
601
+#define ADC_CALIB_ADDR 24
602
+#define FUSE_READ 0x2
603
+
604
+/* Register field definitions. */
605
+#define CON_MUX(rv) ((rv) << 24)
606
+#define CON_INT_EN BIT(21)
607
+#define CON_REFSEL BIT(19)
608
+#define CON_INT BIT(18)
609
+#define CON_EN BIT(17)
610
+#define CON_RST BIT(16)
611
+#define CON_CONV BIT(14)
612
+#define CON_DIV(rv) extract32(rv, 1, 8)
613
+
614
+#define FST_RDST BIT(1)
615
+#define FDATA_MASK 0xff
616
+
617
+#define MAX_ERROR 10000
618
+#define MIN_CALIB_INPUT 100000
619
+#define MAX_CALIB_INPUT 1800000
620
+
621
+static const uint32_t input_list[] = {
622
+ 100000,
623
+ 500000,
624
+ 1000000,
625
+ 1500000,
626
+ 1800000,
627
+ 2000000,
628
+};
629
+
630
+static const uint32_t vref_list[] = {
631
+ 2000000,
632
+ 2200000,
633
+ 2500000,
634
+};
635
+
636
+static const uint32_t iref_list[] = {
637
+ 1800000,
638
+ 1900000,
639
+ 2000000,
640
+ 2100000,
641
+ 2200000,
642
+};
643
+
644
+static const uint32_t div_list[] = {0, 1, 3, 7, 15};
645
+
646
+typedef struct ADC {
647
+ int irq;
648
+ uint64_t base_addr;
649
+} ADC;
650
+
651
+ADC adc = {
652
+ .irq = 0,
653
+ .base_addr = 0xf000c000
654
+};
655
+
656
+static uint32_t adc_read_con(QTestState *qts, const ADC *adc)
657
+{
658
+ return qtest_readl(qts, adc->base_addr + CON_OFFSET);
659
+}
660
+
661
+static void adc_write_con(QTestState *qts, const ADC *adc, uint32_t value)
662
+{
663
+ qtest_writel(qts, adc->base_addr + CON_OFFSET, value);
664
+}
665
+
666
+static uint32_t adc_read_data(QTestState *qts, const ADC *adc)
667
+{
668
+ return qtest_readl(qts, adc->base_addr + DATA_OFFSET);
669
+}
670
+
671
+static uint32_t adc_calibrate(uint32_t measured, uint32_t *rv)
672
+{
673
+ return R0_INPUT + (R1_INPUT - R0_INPUT) * (int32_t)(measured - rv[0])
674
+ / (int32_t)(rv[1] - rv[0]);
675
+}
676
+
677
+static void adc_qom_set(QTestState *qts, const ADC *adc,
678
+ const char *name, uint32_t value)
679
+{
680
+ QDict *response;
681
+ const char *path = "/machine/soc/adc";
682
+
683
+ g_test_message("Setting properties %s of %s with value %u",
684
+ name, path, value);
685
+ response = qtest_qmp(qts, "{ 'execute': 'qom-set',"
686
+ " 'arguments': { 'path': %s, 'property': %s, 'value': %u}}",
687
+ path, name, value);
688
+ /* The qom set message returns successfully. */
689
+ g_assert_true(qdict_haskey(response, "return"));
690
+}
691
+
692
+static void adc_write_input(QTestState *qts, const ADC *adc,
693
+ uint32_t index, uint32_t value)
694
+{
695
+ char name[100];
696
+
697
+ sprintf(name, "adci[%u]", index);
698
+ adc_qom_set(qts, adc, name, value);
699
+}
700
+
701
+static void adc_write_vref(QTestState *qts, const ADC *adc, uint32_t value)
702
+{
703
+ adc_qom_set(qts, adc, "vref", value);
704
+}
705
+
706
+static uint32_t adc_calculate_output(uint32_t input, uint32_t ref)
707
+{
708
+ uint32_t output;
709
+
710
+ g_assert_cmpuint(input, <=, ref);
711
+ output = (input * (MAX_RESULT + 1)) / ref;
712
+ if (output > MAX_RESULT) {
713
+ output = MAX_RESULT;
714
+ }
715
+
716
+ return output;
717
+}
718
+
719
+static uint32_t adc_prescaler(QTestState *qts, const ADC *adc)
720
+{
721
+ uint32_t div = extract32(adc_read_con(qts, adc), 1, 8);
722
+
723
+ return 2 * (div + 1);
724
+}
725
+
726
+static int64_t adc_calculate_steps(uint32_t cycles, uint32_t prescale,
727
+ uint32_t clkdiv)
728
+{
729
+ return (NANOSECONDS_PER_SECOND / (REF_HZ >> clkdiv)) * cycles * prescale;
730
+}
731
+
732
+static void adc_wait_conv_finished(QTestState *qts, const ADC *adc,
733
+ uint32_t clkdiv)
734
+{
735
+ uint32_t prescaler = adc_prescaler(qts, adc);
736
+
737
+ /*
738
+ * ADC should takes roughly 20 cycles to convert one sample. So we assert it
739
+ * should take 10~30 cycles here.
740
+ */
741
+ qtest_clock_step(qts, adc_calculate_steps(CONV_CYCLES / 2, prescaler,
742
+ clkdiv));
743
+ /* ADC is still converting. */
744
+ g_assert_true(adc_read_con(qts, adc) & CON_CONV);
745
+ qtest_clock_step(qts, adc_calculate_steps(CONV_CYCLES, prescaler, clkdiv));
746
+ /* ADC has finished conversion. */
747
+ g_assert_false(adc_read_con(qts, adc) & CON_CONV);
748
+}
749
+
750
+/* Check ADC can be reset to default value. */
751
+static void test_init(gconstpointer adc_p)
752
+{
753
+ const ADC *adc = adc_p;
754
+
755
+ QTestState *qts = qtest_init("-machine quanta-gsj");
756
+ adc_write_con(qts, adc, CON_REFSEL | CON_INT);
757
+ g_assert_cmphex(adc_read_con(qts, adc), ==, CON_REFSEL);
758
+ qtest_quit(qts);
759
+}
760
+
761
+/* Check ADC can convert from an internal reference. */
762
+static void test_convert_internal(gconstpointer adc_p)
763
+{
764
+ const ADC *adc = adc_p;
765
+ uint32_t index, input, output, expected_output;
766
+ QTestState *qts = qtest_init("-machine quanta-gsj");
767
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
768
+
769
+ for (index = 0; index < NUM_INPUTS; ++index) {
770
+ for (size_t i = 0; i < ARRAY_SIZE(input_list); ++i) {
771
+ input = input_list[i];
772
+ expected_output = adc_calculate_output(input, DEFAULT_IREF);
773
+
774
+ adc_write_input(qts, adc, index, input);
775
+ adc_write_con(qts, adc, CON_MUX(index) | CON_REFSEL | CON_INT |
776
+ CON_EN | CON_CONV);
777
+ adc_wait_conv_finished(qts, adc, DEFAULT_CLKDIV);
778
+ g_assert_cmphex(adc_read_con(qts, adc), ==, CON_MUX(index) |
779
+ CON_REFSEL | CON_EN);
780
+ g_assert_false(qtest_get_irq(qts, adc->irq));
781
+ output = adc_read_data(qts, adc);
782
+ g_assert_cmpuint(output, ==, expected_output);
783
+ }
784
+ }
785
+
786
+ qtest_quit(qts);
787
+}
788
+
789
+/* Check ADC can convert from an external reference. */
790
+static void test_convert_external(gconstpointer adc_p)
791
+{
792
+ const ADC *adc = adc_p;
793
+ uint32_t index, input, vref, output, expected_output;
794
+ QTestState *qts = qtest_init("-machine quanta-gsj");
795
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
796
+
797
+ for (index = 0; index < NUM_INPUTS; ++index) {
798
+ for (size_t i = 0; i < ARRAY_SIZE(input_list); ++i) {
799
+ for (size_t j = 0; j < ARRAY_SIZE(vref_list); ++j) {
800
+ input = input_list[i];
801
+ vref = vref_list[j];
802
+ expected_output = adc_calculate_output(input, vref);
803
+
804
+ adc_write_input(qts, adc, index, input);
805
+ adc_write_vref(qts, adc, vref);
806
+ adc_write_con(qts, adc, CON_MUX(index) | CON_INT | CON_EN |
807
+ CON_CONV);
808
+ adc_wait_conv_finished(qts, adc, DEFAULT_CLKDIV);
809
+ g_assert_cmphex(adc_read_con(qts, adc), ==,
810
+ CON_MUX(index) | CON_EN);
811
+ g_assert_false(qtest_get_irq(qts, adc->irq));
812
+ output = adc_read_data(qts, adc);
813
+ g_assert_cmpuint(output, ==, expected_output);
814
+ }
815
+ }
816
+ }
817
+
818
+ qtest_quit(qts);
819
+}
820
+
821
+/* Check ADC interrupt files if and only if CON_INT_EN is set. */
822
+static void test_interrupt(gconstpointer adc_p)
823
+{
824
+ const ADC *adc = adc_p;
825
+ uint32_t index, input, output, expected_output;
826
+ QTestState *qts = qtest_init("-machine quanta-gsj");
827
+
828
+ index = 1;
829
+ input = input_list[1];
830
+ expected_output = adc_calculate_output(input, DEFAULT_IREF);
831
+
832
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
833
+ adc_write_input(qts, adc, index, input);
834
+ g_assert_false(qtest_get_irq(qts, adc->irq));
835
+ adc_write_con(qts, adc, CON_MUX(index) | CON_INT_EN | CON_REFSEL | CON_INT
836
+ | CON_EN | CON_CONV);
837
+ adc_wait_conv_finished(qts, adc, DEFAULT_CLKDIV);
838
+ g_assert_cmphex(adc_read_con(qts, adc), ==, CON_MUX(index) | CON_INT_EN
839
+ | CON_REFSEL | CON_INT | CON_EN);
840
+ g_assert_true(qtest_get_irq(qts, adc->irq));
841
+ output = adc_read_data(qts, adc);
842
+ g_assert_cmpuint(output, ==, expected_output);
843
+
844
+ qtest_quit(qts);
845
+}
846
+
847
+/* Check ADC is reset after setting ADC_RST for 10 ADC cycles. */
848
+static void test_reset(gconstpointer adc_p)
849
+{
850
+ const ADC *adc = adc_p;
851
+ QTestState *qts = qtest_init("-machine quanta-gsj");
852
+
853
+ for (size_t i = 0; i < ARRAY_SIZE(div_list); ++i) {
854
+ uint32_t div = div_list[i];
855
+
856
+ adc_write_con(qts, adc, CON_INT | CON_EN | CON_RST | CON_DIV(div));
857
+ qtest_clock_step(qts, adc_calculate_steps(RESET_CYCLES,
858
+ adc_prescaler(qts, adc), DEFAULT_CLKDIV));
859
+ g_assert_false(adc_read_con(qts, adc) & CON_EN);
860
+ }
861
+ qtest_quit(qts);
862
+}
863
+
864
+/* Check ADC Calibration works as desired. */
865
+static void test_calibrate(gconstpointer adc_p)
866
+{
867
+ int i, j;
868
+ const ADC *adc = adc_p;
869
+
870
+ for (j = 0; j < ARRAY_SIZE(iref_list); ++j) {
871
+ uint32_t iref = iref_list[j];
872
+ uint32_t expected_rv[] = {
873
+ adc_calculate_output(R0_INPUT, iref),
874
+ adc_calculate_output(R1_INPUT, iref),
875
+ };
876
+ char buf[100];
877
+ QTestState *qts;
878
+
879
+ sprintf(buf, "-machine quanta-gsj -global npcm7xx-adc.iref=%u", iref);
880
+ qts = qtest_init(buf);
881
+
882
+ /* Check the converted value is correct using the calibration value. */
883
+ for (i = 0; i < ARRAY_SIZE(input_list); ++i) {
884
+ uint32_t input;
885
+ uint32_t output;
886
+ uint32_t expected_output;
887
+ uint32_t calibrated_voltage;
888
+ uint32_t index = 0;
889
+
890
+ input = input_list[i];
891
+ /* Calibration only works for input range 0.1V ~ 1.8V. */
892
+ if (input < MIN_CALIB_INPUT || input > MAX_CALIB_INPUT) {
893
+ continue;
894
+ }
895
+ expected_output = adc_calculate_output(input, iref);
896
+
897
+ adc_write_input(qts, adc, index, input);
898
+ adc_write_con(qts, adc, CON_MUX(index) | CON_REFSEL | CON_INT |
899
+ CON_EN | CON_CONV);
900
+ adc_wait_conv_finished(qts, adc, DEFAULT_CLKDIV);
901
+ g_assert_cmphex(adc_read_con(qts, adc), ==,
902
+ CON_REFSEL | CON_MUX(index) | CON_EN);
903
+ output = adc_read_data(qts, adc);
904
+ g_assert_cmpuint(output, ==, expected_output);
905
+
906
+ calibrated_voltage = adc_calibrate(output, expected_rv);
907
+ g_assert_cmpuint(calibrated_voltage, >, input - MAX_ERROR);
908
+ g_assert_cmpuint(calibrated_voltage, <, input + MAX_ERROR);
909
+ }
910
+
911
+ qtest_quit(qts);
912
+ }
913
+}
914
+
915
+static void adc_add_test(const char *name, const ADC* wd,
916
+ GTestDataFunc fn)
917
+{
918
+ g_autofree char *full_name = g_strdup_printf("npcm7xx_adc/%s", name);
919
+ qtest_add_data_func(full_name, wd, fn);
920
+}
921
+#define add_test(name, td) adc_add_test(#name, td, test_##name)
922
+
923
+int main(int argc, char **argv)
924
+{
925
+ g_test_init(&argc, &argv, NULL);
926
+
927
+ add_test(init, &adc);
928
+ add_test(convert_internal, &adc);
929
+ add_test(convert_external, &adc);
930
+ add_test(interrupt, &adc);
931
+ add_test(reset, &adc);
932
+ add_test(calibrate, &adc);
933
+
934
+ return g_test_run();
935
+}
936
diff --git a/hw/adc/meson.build b/hw/adc/meson.build
937
index XXXXXXX..XXXXXXX 100644
716
index XXXXXXX..XXXXXXX 100644
938
--- a/hw/adc/meson.build
717
--- a/hw/arm/meson.build
939
+++ b/hw/adc/meson.build
718
+++ b/hw/arm/meson.build
940
@@ -1 +1,2 @@
719
@@ -XXX,XX +XXX,XX @@ arm_ss.add(when: 'CONFIG_OMAP', if_true: files('omap1.c', 'omap2.c'))
941
softmmu_ss.add(when: 'CONFIG_STM32F2XX_ADC', if_true: files('stm32f2xx_adc.c'))
720
arm_ss.add(when: 'CONFIG_STRONGARM', if_true: files('strongarm.c'))
942
+softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_adc.c'))
721
arm_ss.add(when: 'CONFIG_ALLWINNER_A10', if_true: files('allwinner-a10.c', 'cubieboard.c'))
943
diff --git a/hw/adc/trace-events b/hw/adc/trace-events
722
arm_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3.c', 'orangepi.c'))
944
new file mode 100644
723
+arm_ss.add(when: 'CONFIG_ALLWINNER_R40', if_true: files('allwinner-r40.c', 'bananapi_m2u.c'))
945
index XXXXXXX..XXXXXXX
724
arm_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2836.c', 'raspi.c'))
946
--- /dev/null
725
arm_ss.add(when: 'CONFIG_STM32F100_SOC', if_true: files('stm32f100_soc.c'))
947
+++ b/hw/adc/trace-events
726
arm_ss.add(when: 'CONFIG_STM32F205_SOC', if_true: files('stm32f205_soc.c'))
948
@@ -XXX,XX +XXX,XX @@
949
+# See docs/devel/tracing.txt for syntax documentation.
950
+
951
+# npcm7xx_adc.c
952
+npcm7xx_adc_read(const char *id, uint64_t offset, uint32_t value) " %s offset: 0x%04" PRIx64 " value 0x%04" PRIx32
953
+npcm7xx_adc_write(const char *id, uint64_t offset, uint32_t value) "%s offset: 0x%04" PRIx64 " value 0x%04" PRIx32
954
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
955
index XXXXXXX..XXXXXXX 100644
956
--- a/tests/qtest/meson.build
957
+++ b/tests/qtest/meson.build
958
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
959
['prom-env-test', 'boot-serial-test']
960
961
qtests_npcm7xx = \
962
- ['npcm7xx_gpio-test',
963
+ ['npcm7xx_adc-test',
964
+ 'npcm7xx_gpio-test',
965
'npcm7xx_rng-test',
966
'npcm7xx_timer-test',
967
'npcm7xx_watchdog_timer-test']
968
--
727
--
969
2.20.1
728
2.34.1
970
971
diff view generated by jsdifflib
New patch
1
From: qianfan Zhao <qianfanguijin@163.com>
1
2
3
The CCU provides the registers to program the PLLs and the controls
4
most of the clock generation, division, distribution, synchronization
5
and gating.
6
7
This commit adds support for the Clock Control Unit which emulates
8
a simple read/write register interface.
9
10
Signed-off-by: qianfan Zhao <qianfanguijin@163.com>
11
Reviewed-by: Niek Linnenbank <nieklinnenbank@gmail.com>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
14
include/hw/arm/allwinner-r40.h | 2 +
15
include/hw/misc/allwinner-r40-ccu.h | 65 +++++++++
16
hw/arm/allwinner-r40.c | 8 +-
17
hw/misc/allwinner-r40-ccu.c | 209 ++++++++++++++++++++++++++++
18
hw/misc/meson.build | 1 +
19
5 files changed, 284 insertions(+), 1 deletion(-)
20
create mode 100644 include/hw/misc/allwinner-r40-ccu.h
21
create mode 100644 hw/misc/allwinner-r40-ccu.c
22
23
diff --git a/include/hw/arm/allwinner-r40.h b/include/hw/arm/allwinner-r40.h
24
index XXXXXXX..XXXXXXX 100644
25
--- a/include/hw/arm/allwinner-r40.h
26
+++ b/include/hw/arm/allwinner-r40.h
27
@@ -XXX,XX +XXX,XX @@
28
#include "hw/timer/allwinner-a10-pit.h"
29
#include "hw/intc/arm_gic.h"
30
#include "hw/sd/allwinner-sdhost.h"
31
+#include "hw/misc/allwinner-r40-ccu.h"
32
#include "target/arm/cpu.h"
33
#include "sysemu/block-backend.h"
34
35
@@ -XXX,XX +XXX,XX @@ struct AwR40State {
36
const hwaddr *memmap;
37
AwA10PITState timer;
38
AwSdHostState mmc[AW_R40_NUM_MMCS];
39
+ AwR40ClockCtlState ccu;
40
GICState gic;
41
MemoryRegion sram_a1;
42
MemoryRegion sram_a2;
43
diff --git a/include/hw/misc/allwinner-r40-ccu.h b/include/hw/misc/allwinner-r40-ccu.h
44
new file mode 100644
45
index XXXXXXX..XXXXXXX
46
--- /dev/null
47
+++ b/include/hw/misc/allwinner-r40-ccu.h
48
@@ -XXX,XX +XXX,XX @@
49
+/*
50
+ * Allwinner R40 Clock Control Unit emulation
51
+ *
52
+ * Copyright (C) 2023 qianfan Zhao <qianfanguijin@163.com>
53
+ *
54
+ * This program is free software: you can redistribute it and/or modify
55
+ * it under the terms of the GNU General Public License as published by
56
+ * the Free Software Foundation, either version 2 of the License, or
57
+ * (at your option) any later version.
58
+ *
59
+ * This program is distributed in the hope that it will be useful,
60
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
61
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
62
+ * GNU General Public License for more details.
63
+ *
64
+ * You should have received a copy of the GNU General Public License
65
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
66
+ */
67
+
68
+#ifndef HW_MISC_ALLWINNER_R40_CCU_H
69
+#define HW_MISC_ALLWINNER_R40_CCU_H
70
+
71
+#include "qom/object.h"
72
+#include "hw/sysbus.h"
73
+
74
+/**
75
+ * @name Constants
76
+ * @{
77
+ */
78
+
79
+/** Size of register I/O address space used by CCU device */
80
+#define AW_R40_CCU_IOSIZE (0x400)
81
+
82
+/** Total number of known registers */
83
+#define AW_R40_CCU_REGS_NUM (AW_R40_CCU_IOSIZE / sizeof(uint32_t))
84
+
85
+/** @} */
86
+
87
+/**
88
+ * @name Object model
89
+ * @{
90
+ */
91
+
92
+#define TYPE_AW_R40_CCU "allwinner-r40-ccu"
93
+OBJECT_DECLARE_SIMPLE_TYPE(AwR40ClockCtlState, AW_R40_CCU)
94
+
95
+/** @} */
96
+
97
+/**
98
+ * Allwinner R40 CCU object instance state.
99
+ */
100
+struct AwR40ClockCtlState {
101
+ /*< private >*/
102
+ SysBusDevice parent_obj;
103
+ /*< public >*/
104
+
105
+ /** Maps I/O registers in physical memory */
106
+ MemoryRegion iomem;
107
+
108
+ /** Array of hardware registers */
109
+ uint32_t regs[AW_R40_CCU_REGS_NUM];
110
+
111
+};
112
+
113
+#endif /* HW_MISC_ALLWINNER_R40_CCU_H */
114
diff --git a/hw/arm/allwinner-r40.c b/hw/arm/allwinner-r40.c
115
index XXXXXXX..XXXXXXX 100644
116
--- a/hw/arm/allwinner-r40.c
117
+++ b/hw/arm/allwinner-r40.c
118
@@ -XXX,XX +XXX,XX @@ const hwaddr allwinner_r40_memmap[] = {
119
[AW_R40_DEV_MMC1] = 0x01c10000,
120
[AW_R40_DEV_MMC2] = 0x01c11000,
121
[AW_R40_DEV_MMC3] = 0x01c12000,
122
+ [AW_R40_DEV_CCU] = 0x01c20000,
123
[AW_R40_DEV_PIT] = 0x01c20c00,
124
[AW_R40_DEV_UART0] = 0x01c28000,
125
[AW_R40_DEV_GIC_DIST] = 0x01c81000,
126
@@ -XXX,XX +XXX,XX @@ static struct AwR40Unimplemented r40_unimplemented[] = {
127
{ "usb2-host", 0x01c1c000, 4 * KiB },
128
{ "cs1", 0x01c1d000, 4 * KiB },
129
{ "spi3", 0x01c1f000, 4 * KiB },
130
- { "ccu", 0x01c20000, 1 * KiB },
131
{ "rtc", 0x01c20400, 1 * KiB },
132
{ "pio", 0x01c20800, 1 * KiB },
133
{ "owa", 0x01c21000, 1 * KiB },
134
@@ -XXX,XX +XXX,XX @@ static void allwinner_r40_init(Object *obj)
135
object_property_add_alias(obj, "clk1-freq", OBJECT(&s->timer),
136
"clk1-freq");
137
138
+ object_initialize_child(obj, "ccu", &s->ccu, TYPE_AW_R40_CCU);
139
+
140
for (int i = 0; i < AW_R40_NUM_MMCS; i++) {
141
object_initialize_child(obj, mmc_names[i], &s->mmc[i],
142
TYPE_AW_SDHOST_SUN5I);
143
@@ -XXX,XX +XXX,XX @@ static void allwinner_r40_realize(DeviceState *dev, Error **errp)
144
memory_region_add_subregion(get_system_memory(),
145
s->memmap[AW_R40_DEV_SRAM_A4], &s->sram_a4);
146
147
+ /* Clock Control Unit */
148
+ sysbus_realize(SYS_BUS_DEVICE(&s->ccu), &error_fatal);
149
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccu), 0, s->memmap[AW_R40_DEV_CCU]);
150
+
151
/* SD/MMC */
152
for (int i = 0; i < AW_R40_NUM_MMCS; i++) {
153
qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->gic),
154
diff --git a/hw/misc/allwinner-r40-ccu.c b/hw/misc/allwinner-r40-ccu.c
155
new file mode 100644
156
index XXXXXXX..XXXXXXX
157
--- /dev/null
158
+++ b/hw/misc/allwinner-r40-ccu.c
159
@@ -XXX,XX +XXX,XX @@
160
+/*
161
+ * Allwinner R40 Clock Control Unit emulation
162
+ *
163
+ * Copyright (C) 2023 qianfan Zhao <qianfanguijin@163.com>
164
+ *
165
+ * This program is free software: you can redistribute it and/or modify
166
+ * it under the terms of the GNU General Public License as published by
167
+ * the Free Software Foundation, either version 2 of the License, or
168
+ * (at your option) any later version.
169
+ *
170
+ * This program is distributed in the hope that it will be useful,
171
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
172
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
173
+ * GNU General Public License for more details.
174
+ *
175
+ * You should have received a copy of the GNU General Public License
176
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
177
+ */
178
+
179
+#include "qemu/osdep.h"
180
+#include "qemu/units.h"
181
+#include "hw/sysbus.h"
182
+#include "migration/vmstate.h"
183
+#include "qemu/log.h"
184
+#include "qemu/module.h"
185
+#include "hw/misc/allwinner-r40-ccu.h"
186
+
187
+/* CCU register offsets */
188
+enum {
189
+ REG_PLL_CPUX_CTRL = 0x0000,
190
+ REG_PLL_AUDIO_CTRL = 0x0008,
191
+ REG_PLL_VIDEO0_CTRL = 0x0010,
192
+ REG_PLL_VE_CTRL = 0x0018,
193
+ REG_PLL_DDR0_CTRL = 0x0020,
194
+ REG_PLL_PERIPH0_CTRL = 0x0028,
195
+ REG_PLL_PERIPH1_CTRL = 0x002c,
196
+ REG_PLL_VIDEO1_CTRL = 0x0030,
197
+ REG_PLL_SATA_CTRL = 0x0034,
198
+ REG_PLL_GPU_CTRL = 0x0038,
199
+ REG_PLL_MIPI_CTRL = 0x0040,
200
+ REG_PLL_DE_CTRL = 0x0048,
201
+ REG_PLL_DDR1_CTRL = 0x004c,
202
+ REG_AHB1_APB1_CFG = 0x0054,
203
+ REG_APB2_CFG = 0x0058,
204
+ REG_MMC0_CLK = 0x0088,
205
+ REG_MMC1_CLK = 0x008c,
206
+ REG_MMC2_CLK = 0x0090,
207
+ REG_MMC3_CLK = 0x0094,
208
+ REG_USBPHY_CFG = 0x00cc,
209
+ REG_PLL_DDR_AUX = 0x00f0,
210
+ REG_DRAM_CFG = 0x00f4,
211
+ REG_PLL_DDR1_CFG = 0x00f8,
212
+ REG_DRAM_CLK_GATING = 0x0100,
213
+ REG_GMAC_CLK = 0x0164,
214
+ REG_SYS_32K_CLK = 0x0310,
215
+ REG_PLL_LOCK_CTRL = 0x0320,
216
+};
217
+
218
+#define REG_INDEX(offset) (offset / sizeof(uint32_t))
219
+
220
+/* CCU register flags */
221
+enum {
222
+ REG_PLL_ENABLE = (1 << 31),
223
+ REG_PLL_LOCK = (1 << 28),
224
+};
225
+
226
+static uint64_t allwinner_r40_ccu_read(void *opaque, hwaddr offset,
227
+ unsigned size)
228
+{
229
+ const AwR40ClockCtlState *s = AW_R40_CCU(opaque);
230
+ const uint32_t idx = REG_INDEX(offset);
231
+
232
+ switch (offset) {
233
+ case 0x324 ... AW_R40_CCU_IOSIZE:
234
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n",
235
+ __func__, (uint32_t)offset);
236
+ return 0;
237
+ }
238
+
239
+ return s->regs[idx];
240
+}
241
+
242
+static void allwinner_r40_ccu_write(void *opaque, hwaddr offset,
243
+ uint64_t val, unsigned size)
244
+{
245
+ AwR40ClockCtlState *s = AW_R40_CCU(opaque);
246
+
247
+ switch (offset) {
248
+ case REG_DRAM_CFG: /* DRAM Configuration(for DDR0) */
249
+ /* bit16: SDRCLK_UPD (SDRCLK configuration 0 update) */
250
+ val &= ~(1 << 16);
251
+ break;
252
+ case REG_PLL_DDR1_CTRL: /* DDR1 Control register */
253
+ /* bit30: SDRPLL_UPD */
254
+ val &= ~(1 << 30);
255
+ if (val & REG_PLL_ENABLE) {
256
+ val |= REG_PLL_LOCK;
257
+ }
258
+ break;
259
+ case REG_PLL_CPUX_CTRL:
260
+ case REG_PLL_AUDIO_CTRL:
261
+ case REG_PLL_VE_CTRL:
262
+ case REG_PLL_VIDEO0_CTRL:
263
+ case REG_PLL_DDR0_CTRL:
264
+ case REG_PLL_PERIPH0_CTRL:
265
+ case REG_PLL_PERIPH1_CTRL:
266
+ case REG_PLL_VIDEO1_CTRL:
267
+ case REG_PLL_SATA_CTRL:
268
+ case REG_PLL_GPU_CTRL:
269
+ case REG_PLL_MIPI_CTRL:
270
+ case REG_PLL_DE_CTRL:
271
+ if (val & REG_PLL_ENABLE) {
272
+ val |= REG_PLL_LOCK;
273
+ }
274
+ break;
275
+ case 0x324 ... AW_R40_CCU_IOSIZE:
276
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n",
277
+ __func__, (uint32_t)offset);
278
+ break;
279
+ default:
280
+ qemu_log_mask(LOG_UNIMP, "%s: unimplemented write offset 0x%04x\n",
281
+ __func__, (uint32_t)offset);
282
+ break;
283
+ }
284
+
285
+ s->regs[REG_INDEX(offset)] = (uint32_t) val;
286
+}
287
+
288
+static const MemoryRegionOps allwinner_r40_ccu_ops = {
289
+ .read = allwinner_r40_ccu_read,
290
+ .write = allwinner_r40_ccu_write,
291
+ .endianness = DEVICE_NATIVE_ENDIAN,
292
+ .valid = {
293
+ .min_access_size = 4,
294
+ .max_access_size = 4,
295
+ },
296
+ .impl.min_access_size = 4,
297
+};
298
+
299
+static void allwinner_r40_ccu_reset(DeviceState *dev)
300
+{
301
+ AwR40ClockCtlState *s = AW_R40_CCU(dev);
302
+
303
+ memset(s->regs, 0, sizeof(s->regs));
304
+
305
+ /* Set default values for registers */
306
+ s->regs[REG_INDEX(REG_PLL_CPUX_CTRL)] = 0x00001000;
307
+ s->regs[REG_INDEX(REG_PLL_AUDIO_CTRL)] = 0x00035514;
308
+ s->regs[REG_INDEX(REG_PLL_VIDEO0_CTRL)] = 0x03006207;
309
+ s->regs[REG_INDEX(REG_PLL_VE_CTRL)] = 0x03006207;
310
+ s->regs[REG_INDEX(REG_PLL_DDR0_CTRL)] = 0x00001000,
311
+ s->regs[REG_INDEX(REG_PLL_PERIPH0_CTRL)] = 0x00041811;
312
+ s->regs[REG_INDEX(REG_PLL_PERIPH1_CTRL)] = 0x00041811;
313
+ s->regs[REG_INDEX(REG_PLL_VIDEO1_CTRL)] = 0x03006207;
314
+ s->regs[REG_INDEX(REG_PLL_SATA_CTRL)] = 0x00001811;
315
+ s->regs[REG_INDEX(REG_PLL_GPU_CTRL)] = 0x03006207;
316
+ s->regs[REG_INDEX(REG_PLL_MIPI_CTRL)] = 0x00000515;
317
+ s->regs[REG_INDEX(REG_PLL_DE_CTRL)] = 0x03006207;
318
+ s->regs[REG_INDEX(REG_PLL_DDR1_CTRL)] = 0x00001800;
319
+ s->regs[REG_INDEX(REG_AHB1_APB1_CFG)] = 0x00001010;
320
+ s->regs[REG_INDEX(REG_APB2_CFG)] = 0x01000000;
321
+ s->regs[REG_INDEX(REG_PLL_DDR_AUX)] = 0x00000001;
322
+ s->regs[REG_INDEX(REG_PLL_DDR1_CFG)] = 0x0ccca000;
323
+ s->regs[REG_INDEX(REG_SYS_32K_CLK)] = 0x0000000f;
324
+}
325
+
326
+static void allwinner_r40_ccu_init(Object *obj)
327
+{
328
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
329
+ AwR40ClockCtlState *s = AW_R40_CCU(obj);
330
+
331
+ /* Memory mapping */
332
+ memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_r40_ccu_ops, s,
333
+ TYPE_AW_R40_CCU, AW_R40_CCU_IOSIZE);
334
+ sysbus_init_mmio(sbd, &s->iomem);
335
+}
336
+
337
+static const VMStateDescription allwinner_r40_ccu_vmstate = {
338
+ .name = "allwinner-r40-ccu",
339
+ .version_id = 1,
340
+ .minimum_version_id = 1,
341
+ .fields = (VMStateField[]) {
342
+ VMSTATE_UINT32_ARRAY(regs, AwR40ClockCtlState, AW_R40_CCU_REGS_NUM),
343
+ VMSTATE_END_OF_LIST()
344
+ }
345
+};
346
+
347
+static void allwinner_r40_ccu_class_init(ObjectClass *klass, void *data)
348
+{
349
+ DeviceClass *dc = DEVICE_CLASS(klass);
350
+
351
+ dc->reset = allwinner_r40_ccu_reset;
352
+ dc->vmsd = &allwinner_r40_ccu_vmstate;
353
+}
354
+
355
+static const TypeInfo allwinner_r40_ccu_info = {
356
+ .name = TYPE_AW_R40_CCU,
357
+ .parent = TYPE_SYS_BUS_DEVICE,
358
+ .instance_init = allwinner_r40_ccu_init,
359
+ .instance_size = sizeof(AwR40ClockCtlState),
360
+ .class_init = allwinner_r40_ccu_class_init,
361
+};
362
+
363
+static void allwinner_r40_ccu_register(void)
364
+{
365
+ type_register_static(&allwinner_r40_ccu_info);
366
+}
367
+
368
+type_init(allwinner_r40_ccu_register)
369
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
370
index XXXXXXX..XXXXXXX 100644
371
--- a/hw/misc/meson.build
372
+++ b/hw/misc/meson.build
373
@@ -XXX,XX +XXX,XX @@ specific_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-cpucfg.c'
374
softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3-dramc.c'))
375
softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3-sysctrl.c'))
376
softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-sid.c'))
377
+softmmu_ss.add(when: 'CONFIG_ALLWINNER_R40', if_true: files('allwinner-r40-ccu.c'))
378
softmmu_ss.add(when: 'CONFIG_AXP209_PMU', if_true: files('axp209.c'))
379
softmmu_ss.add(when: 'CONFIG_REALVIEW', if_true: files('arm_sysctl.c'))
380
softmmu_ss.add(when: 'CONFIG_NSERIES', if_true: files('cbus.c'))
381
--
382
2.34.1
diff view generated by jsdifflib
New patch
1
From: qianfan Zhao <qianfanguijin@163.com>
1
2
3
R40 has eight UARTs, support both 16450 and 16550 compatible modes.
4
5
Signed-off-by: qianfan Zhao <qianfanguijin@163.com>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
---
8
include/hw/arm/allwinner-r40.h | 8 ++++++++
9
hw/arm/allwinner-r40.c | 34 +++++++++++++++++++++++++++++++---
10
2 files changed, 39 insertions(+), 3 deletions(-)
11
12
diff --git a/include/hw/arm/allwinner-r40.h b/include/hw/arm/allwinner-r40.h
13
index XXXXXXX..XXXXXXX 100644
14
--- a/include/hw/arm/allwinner-r40.h
15
+++ b/include/hw/arm/allwinner-r40.h
16
@@ -XXX,XX +XXX,XX @@ enum {
17
AW_R40_DEV_CCU,
18
AW_R40_DEV_PIT,
19
AW_R40_DEV_UART0,
20
+ AW_R40_DEV_UART1,
21
+ AW_R40_DEV_UART2,
22
+ AW_R40_DEV_UART3,
23
+ AW_R40_DEV_UART4,
24
+ AW_R40_DEV_UART5,
25
+ AW_R40_DEV_UART6,
26
+ AW_R40_DEV_UART7,
27
AW_R40_DEV_GIC_DIST,
28
AW_R40_DEV_GIC_CPU,
29
AW_R40_DEV_GIC_HYP,
30
@@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_SIMPLE_TYPE(AwR40State, AW_R40)
31
* which are currently emulated by the R40 SoC code.
32
*/
33
#define AW_R40_NUM_MMCS 4
34
+#define AW_R40_NUM_UARTS 8
35
36
struct AwR40State {
37
/*< private >*/
38
diff --git a/hw/arm/allwinner-r40.c b/hw/arm/allwinner-r40.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/hw/arm/allwinner-r40.c
41
+++ b/hw/arm/allwinner-r40.c
42
@@ -XXX,XX +XXX,XX @@ const hwaddr allwinner_r40_memmap[] = {
43
[AW_R40_DEV_CCU] = 0x01c20000,
44
[AW_R40_DEV_PIT] = 0x01c20c00,
45
[AW_R40_DEV_UART0] = 0x01c28000,
46
+ [AW_R40_DEV_UART1] = 0x01c28400,
47
+ [AW_R40_DEV_UART2] = 0x01c28800,
48
+ [AW_R40_DEV_UART3] = 0x01c28c00,
49
+ [AW_R40_DEV_UART4] = 0x01c29000,
50
+ [AW_R40_DEV_UART5] = 0x01c29400,
51
+ [AW_R40_DEV_UART6] = 0x01c29800,
52
+ [AW_R40_DEV_UART7] = 0x01c29c00,
53
[AW_R40_DEV_GIC_DIST] = 0x01c81000,
54
[AW_R40_DEV_GIC_CPU] = 0x01c82000,
55
[AW_R40_DEV_GIC_HYP] = 0x01c84000,
56
@@ -XXX,XX +XXX,XX @@ enum {
57
/* Shared Processor Interrupts */
58
enum {
59
AW_R40_GIC_SPI_UART0 = 1,
60
+ AW_R40_GIC_SPI_UART1 = 2,
61
+ AW_R40_GIC_SPI_UART2 = 3,
62
+ AW_R40_GIC_SPI_UART3 = 4,
63
+ AW_R40_GIC_SPI_UART4 = 17,
64
+ AW_R40_GIC_SPI_UART5 = 18,
65
+ AW_R40_GIC_SPI_UART6 = 19,
66
+ AW_R40_GIC_SPI_UART7 = 20,
67
AW_R40_GIC_SPI_TIMER0 = 22,
68
AW_R40_GIC_SPI_TIMER1 = 23,
69
AW_R40_GIC_SPI_MMC0 = 32,
70
@@ -XXX,XX +XXX,XX @@ static void allwinner_r40_realize(DeviceState *dev, Error **errp)
71
}
72
73
/* UART0. For future clocktree API: All UARTS are connected to APB2_CLK. */
74
- serial_mm_init(get_system_memory(), s->memmap[AW_R40_DEV_UART0], 2,
75
- qdev_get_gpio_in(DEVICE(&s->gic), AW_R40_GIC_SPI_UART0),
76
- 115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
77
+ for (int i = 0; i < AW_R40_NUM_UARTS; i++) {
78
+ static const int uart_irqs[AW_R40_NUM_UARTS] = {
79
+ AW_R40_GIC_SPI_UART0,
80
+ AW_R40_GIC_SPI_UART1,
81
+ AW_R40_GIC_SPI_UART2,
82
+ AW_R40_GIC_SPI_UART3,
83
+ AW_R40_GIC_SPI_UART4,
84
+ AW_R40_GIC_SPI_UART5,
85
+ AW_R40_GIC_SPI_UART6,
86
+ AW_R40_GIC_SPI_UART7,
87
+ };
88
+ const hwaddr addr = s->memmap[AW_R40_DEV_UART0 + i];
89
+
90
+ serial_mm_init(get_system_memory(), addr, 2,
91
+ qdev_get_gpio_in(DEVICE(&s->gic), uart_irqs[i]),
92
+ 115200, serial_hd(i), DEVICE_NATIVE_ENDIAN);
93
+ }
94
95
/* Unimplemented devices */
96
for (i = 0; i < ARRAY_SIZE(r40_unimplemented); i++) {
97
--
98
2.34.1
diff view generated by jsdifflib
New patch
1
From: qianfan Zhao <qianfanguijin@163.com>
1
2
3
TWI(i2c) is designed to be used as an interface between CPU host and the
4
serial 2-Wire bus. It can support all standard 2-Wire transfer, can be
5
operated in standard mode(100kbit/s) or fast-mode, supporting data rate
6
up to 400kbit/s.
7
8
Signed-off-by: qianfan Zhao <qianfanguijin@163.com>
9
Reviewed-by: Niek Linnenbank <nieklinnenbank@gmail.com>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
12
include/hw/arm/allwinner-r40.h | 3 +++
13
hw/arm/allwinner-r40.c | 11 ++++++++++-
14
2 files changed, 13 insertions(+), 1 deletion(-)
15
16
diff --git a/include/hw/arm/allwinner-r40.h b/include/hw/arm/allwinner-r40.h
17
index XXXXXXX..XXXXXXX 100644
18
--- a/include/hw/arm/allwinner-r40.h
19
+++ b/include/hw/arm/allwinner-r40.h
20
@@ -XXX,XX +XXX,XX @@
21
#include "hw/intc/arm_gic.h"
22
#include "hw/sd/allwinner-sdhost.h"
23
#include "hw/misc/allwinner-r40-ccu.h"
24
+#include "hw/i2c/allwinner-i2c.h"
25
#include "target/arm/cpu.h"
26
#include "sysemu/block-backend.h"
27
28
@@ -XXX,XX +XXX,XX @@ enum {
29
AW_R40_DEV_UART5,
30
AW_R40_DEV_UART6,
31
AW_R40_DEV_UART7,
32
+ AW_R40_DEV_TWI0,
33
AW_R40_DEV_GIC_DIST,
34
AW_R40_DEV_GIC_CPU,
35
AW_R40_DEV_GIC_HYP,
36
@@ -XXX,XX +XXX,XX @@ struct AwR40State {
37
AwA10PITState timer;
38
AwSdHostState mmc[AW_R40_NUM_MMCS];
39
AwR40ClockCtlState ccu;
40
+ AWI2CState i2c0;
41
GICState gic;
42
MemoryRegion sram_a1;
43
MemoryRegion sram_a2;
44
diff --git a/hw/arm/allwinner-r40.c b/hw/arm/allwinner-r40.c
45
index XXXXXXX..XXXXXXX 100644
46
--- a/hw/arm/allwinner-r40.c
47
+++ b/hw/arm/allwinner-r40.c
48
@@ -XXX,XX +XXX,XX @@ const hwaddr allwinner_r40_memmap[] = {
49
[AW_R40_DEV_UART5] = 0x01c29400,
50
[AW_R40_DEV_UART6] = 0x01c29800,
51
[AW_R40_DEV_UART7] = 0x01c29c00,
52
+ [AW_R40_DEV_TWI0] = 0x01c2ac00,
53
[AW_R40_DEV_GIC_DIST] = 0x01c81000,
54
[AW_R40_DEV_GIC_CPU] = 0x01c82000,
55
[AW_R40_DEV_GIC_HYP] = 0x01c84000,
56
@@ -XXX,XX +XXX,XX @@ static struct AwR40Unimplemented r40_unimplemented[] = {
57
{ "uart7", 0x01c29c00, 1 * KiB },
58
{ "ps20", 0x01c2a000, 1 * KiB },
59
{ "ps21", 0x01c2a400, 1 * KiB },
60
- { "twi0", 0x01c2ac00, 1 * KiB },
61
{ "twi1", 0x01c2b000, 1 * KiB },
62
{ "twi2", 0x01c2b400, 1 * KiB },
63
{ "twi3", 0x01c2b800, 1 * KiB },
64
@@ -XXX,XX +XXX,XX @@ enum {
65
AW_R40_GIC_SPI_UART1 = 2,
66
AW_R40_GIC_SPI_UART2 = 3,
67
AW_R40_GIC_SPI_UART3 = 4,
68
+ AW_R40_GIC_SPI_TWI0 = 7,
69
AW_R40_GIC_SPI_UART4 = 17,
70
AW_R40_GIC_SPI_UART5 = 18,
71
AW_R40_GIC_SPI_UART6 = 19,
72
@@ -XXX,XX +XXX,XX @@ static void allwinner_r40_init(Object *obj)
73
object_initialize_child(obj, mmc_names[i], &s->mmc[i],
74
TYPE_AW_SDHOST_SUN5I);
75
}
76
+
77
+ object_initialize_child(obj, "twi0", &s->i2c0, TYPE_AW_I2C_SUN6I);
78
}
79
80
static void allwinner_r40_realize(DeviceState *dev, Error **errp)
81
@@ -XXX,XX +XXX,XX @@ static void allwinner_r40_realize(DeviceState *dev, Error **errp)
82
115200, serial_hd(i), DEVICE_NATIVE_ENDIAN);
83
}
84
85
+ /* I2C */
86
+ sysbus_realize(SYS_BUS_DEVICE(&s->i2c0), &error_fatal);
87
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c0), 0, s->memmap[AW_R40_DEV_TWI0]);
88
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c0), 0,
89
+ qdev_get_gpio_in(DEVICE(&s->gic), AW_R40_GIC_SPI_TWI0));
90
+
91
/* Unimplemented devices */
92
for (i = 0; i < ARRAY_SIZE(r40_unimplemented); i++) {
93
create_unimplemented_device(r40_unimplemented[i].device_name,
94
--
95
2.34.1
diff view generated by jsdifflib
1
When we first converted our documentation to Sphinx, we split it into
1
From: qianfan Zhao <qianfanguijin@163.com>
2
multiple manuals (system, interop, tools, etc), which are all built
3
separately. The primary driver for this was wanting to be able to
4
avoid shipping the 'devel' manual to end-users. However, this is
5
working against the grain of the way Sphinx wants to be used and
6
causes some annoyances:
7
* Cross-references between documents become much harder or
8
possibly impossible
9
* There is no single index to the whole documentation
10
* Within one manual there's no links or table-of-contents info
11
that lets you easily navigate to the others
12
* The devel manual doesn't get published on the QEMU website
13
(it would be nice to able to refer to it there)
14
2
15
Merely hiding our developer documentation from end users seems like
3
This patch adds minimal support for AXP-221 PMU and connect it to
16
it's not enough benefit for these costs. Combine all the
4
bananapi M2U board.
17
documentation into a single manual (the same way that the readthedocs
18
site builds it) and install the whole thing. The previous manual
19
divisions remain as the new top level sections in the manual.
20
5
21
* The per-manual conf.py files are no longer needed
6
Signed-off-by: qianfan Zhao <qianfanguijin@163.com>
22
* The man_pages[] specifications previously in each per-manual
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
23
conf.py move to the top level conf.py
8
---
24
* docs/meson.build logic is simplified as we now only need to run
9
hw/arm/bananapi_m2u.c | 6 +
25
Sphinx once for the HTML and then once for the manpages5B
10
hw/misc/axp209.c | 238 -----------------------------------
26
* The old index.html.in that produced the top-level page with
11
hw/misc/axp2xx.c | 283 ++++++++++++++++++++++++++++++++++++++++++
27
links to each manual is no longer needed
12
hw/arm/Kconfig | 3 +-
13
hw/misc/Kconfig | 2 +-
14
hw/misc/meson.build | 2 +-
15
hw/misc/trace-events | 8 +-
16
7 files changed, 297 insertions(+), 245 deletions(-)
17
delete mode 100644 hw/misc/axp209.c
18
create mode 100644 hw/misc/axp2xx.c
28
19
29
Unfortunately this means that we now have to build the HTML
20
diff --git a/hw/arm/bananapi_m2u.c b/hw/arm/bananapi_m2u.c
30
documentation into docs/manual in the build tree rather than directly
31
into docs/; otherwise it is too awkward to ensure we install only the
32
built manual and not also the dependency info, stamp file, etc. The
33
manual still ends up in the same place in the final installed
34
directory, but anybody who was consulting documentation from within
35
the build tree will have to adjust where they're looking.
36
37
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
38
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
39
Message-id: 20210108161416.21129-3-peter.maydell@linaro.org
40
---
41
docs/conf.py | 46 ++++++++++++++++++++++++++++++-
42
docs/devel/conf.py | 15 -----------
43
docs/index.html.in | 17 ------------
44
docs/interop/conf.py | 28 -------------------
45
docs/meson.build | 64 +++++++++++++++++---------------------------
46
docs/specs/conf.py | 16 -----------
47
docs/system/conf.py | 28 -------------------
48
docs/tools/conf.py | 37 -------------------------
49
docs/user/conf.py | 15 -----------
50
9 files changed, 70 insertions(+), 196 deletions(-)
51
delete mode 100644 docs/devel/conf.py
52
delete mode 100644 docs/index.html.in
53
delete mode 100644 docs/interop/conf.py
54
delete mode 100644 docs/specs/conf.py
55
delete mode 100644 docs/system/conf.py
56
delete mode 100644 docs/tools/conf.py
57
delete mode 100644 docs/user/conf.py
58
59
diff --git a/docs/conf.py b/docs/conf.py
60
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
61
--- a/docs/conf.py
22
--- a/hw/arm/bananapi_m2u.c
62
+++ b/docs/conf.py
23
+++ b/hw/arm/bananapi_m2u.c
63
@@ -XXX,XX +XXX,XX @@ latex_documents = [
24
@@ -XXX,XX +XXX,XX @@
64
25
#include "qapi/error.h"
65
# -- Options for manual page output ---------------------------------------
26
#include "qemu/error-report.h"
66
# Individual manual/conf.py can override this to create man pages
27
#include "hw/boards.h"
67
-man_pages = []
28
+#include "hw/i2c/i2c.h"
68
+man_pages = [
29
#include "hw/qdev-properties.h"
69
+ ('interop/qemu-ga', 'qemu-ga',
30
#include "hw/arm/allwinner-r40.h"
70
+ 'QEMU Guest Agent',
31
71
+ ['Michael Roth <mdroth@linux.vnet.ibm.com>'], 8),
32
@@ -XXX,XX +XXX,XX @@ static void bpim2u_init(MachineState *machine)
72
+ ('interop/qemu-ga-ref', 'qemu-ga-ref',
33
{
73
+ 'QEMU Guest Agent Protocol Reference',
34
bool bootroom_loaded = false;
74
+ [], 7),
35
AwR40State *r40;
75
+ ('interop/qemu-qmp-ref', 'qemu-qmp-ref',
36
+ I2CBus *i2c;
76
+ 'QEMU QMP Reference Manual',
37
77
+ [], 7),
38
/* BIOS is not supported by this board */
78
+ ('interop/qemu-storage-daemon-qmp-ref', 'qemu-storage-daemon-qmp-ref',
39
if (machine->firmware) {
79
+ 'QEMU Storage Daemon QMP Reference Manual',
40
@@ -XXX,XX +XXX,XX @@ static void bpim2u_init(MachineState *machine)
80
+ [], 7),
41
}
81
+ ('system/qemu-manpage', 'qemu',
42
}
82
+ 'QEMU User Documentation',
43
83
+ ['Fabrice Bellard'], 1),
44
+ /* Connect AXP221 */
84
+ ('system/qemu-block-drivers', 'qemu-block-drivers',
45
+ i2c = I2C_BUS(qdev_get_child_bus(DEVICE(&r40->i2c0), "i2c"));
85
+ 'QEMU block drivers reference',
46
+ i2c_slave_create_simple(i2c, "axp221_pmu", 0x34);
86
+ ['Fabrice Bellard and the QEMU Project developers'], 7),
47
+
87
+ ('system/qemu-cpu-models', 'qemu-cpu-models',
48
/* SDRAM */
88
+ 'QEMU CPU Models',
49
memory_region_add_subregion(get_system_memory(),
89
+ ['The QEMU Project developers'], 7),
50
r40->memmap[AW_R40_DEV_SDRAM], machine->ram);
90
+ ('tools/qemu-img', 'qemu-img',
51
diff --git a/hw/misc/axp209.c b/hw/misc/axp209.c
91
+ 'QEMU disk image utility',
92
+ ['Fabrice Bellard'], 1),
93
+ ('tools/qemu-nbd', 'qemu-nbd',
94
+ 'QEMU Disk Network Block Device Server',
95
+ ['Anthony Liguori <anthony@codemonkey.ws>'], 8),
96
+ ('tools/qemu-pr-helper', 'qemu-pr-helper',
97
+ 'QEMU persistent reservation helper',
98
+ [], 8),
99
+ ('tools/qemu-storage-daemon', 'qemu-storage-daemon',
100
+ 'QEMU storage daemon',
101
+ [], 1),
102
+ ('tools/qemu-trace-stap', 'qemu-trace-stap',
103
+ 'QEMU SystemTap trace tool',
104
+ [], 1),
105
+ ('tools/virtfs-proxy-helper', 'virtfs-proxy-helper',
106
+ 'QEMU 9p virtfs proxy filesystem helper',
107
+ ['M. Mohan Kumar'], 1),
108
+ ('tools/virtiofsd', 'virtiofsd',
109
+ 'QEMU virtio-fs shared file system daemon',
110
+ ['Stefan Hajnoczi <stefanha@redhat.com>',
111
+ 'Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>'], 1),
112
+]
113
114
# -- Options for Texinfo output -------------------------------------------
115
116
diff --git a/docs/devel/conf.py b/docs/devel/conf.py
117
deleted file mode 100644
52
deleted file mode 100644
118
index XXXXXXX..XXXXXXX
53
index XXXXXXX..XXXXXXX
119
--- a/docs/devel/conf.py
54
--- a/hw/misc/axp209.c
120
+++ /dev/null
55
+++ /dev/null
121
@@ -XXX,XX +XXX,XX @@
56
@@ -XXX,XX +XXX,XX @@
122
-# -*- coding: utf-8 -*-
57
-/*
123
-#
58
- * AXP-209 PMU Emulation
124
-# QEMU documentation build configuration file for the 'devel' manual.
59
- *
125
-#
60
- * Copyright (C) 2022 Strahinja Jankovic <strahinja.p.jankovic@gmail.com>
126
-# This includes the top level conf file and then makes any necessary tweaks.
61
- *
127
-import sys
62
- * Permission is hereby granted, free of charge, to any person obtaining a
128
-import os
63
- * copy of this software and associated documentation files (the "Software"),
129
-
64
- * to deal in the Software without restriction, including without limitation
130
-qemu_docdir = os.path.abspath("..")
65
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
131
-parent_config = os.path.join(qemu_docdir, "conf.py")
66
- * and/or sell copies of the Software, and to permit persons to whom the
132
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
67
- * Software is furnished to do so, subject to the following conditions:
133
-
68
- *
134
-# This slightly misuses the 'description', but is the best way to get
69
- * The above copyright notice and this permission notice shall be included in
135
-# the manual title to appear in the sidebar.
70
- * all copies or substantial portions of the Software.
136
-html_theme_options['description'] = u'Developer''s Guide'
71
- *
137
diff --git a/docs/index.html.in b/docs/index.html.in
72
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
138
deleted file mode 100644
73
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
74
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
75
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
76
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
77
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
78
- * DEALINGS IN THE SOFTWARE.
79
- *
80
- * SPDX-License-Identifier: MIT
81
- */
82
-
83
-#include "qemu/osdep.h"
84
-#include "qemu/log.h"
85
-#include "trace.h"
86
-#include "hw/i2c/i2c.h"
87
-#include "migration/vmstate.h"
88
-
89
-#define TYPE_AXP209_PMU "axp209_pmu"
90
-
91
-#define AXP209(obj) \
92
- OBJECT_CHECK(AXP209I2CState, (obj), TYPE_AXP209_PMU)
93
-
94
-/* registers */
95
-enum {
96
- REG_POWER_STATUS = 0x0u,
97
- REG_OPERATING_MODE,
98
- REG_OTG_VBUS_STATUS,
99
- REG_CHIP_VERSION,
100
- REG_DATA_CACHE_0,
101
- REG_DATA_CACHE_1,
102
- REG_DATA_CACHE_2,
103
- REG_DATA_CACHE_3,
104
- REG_DATA_CACHE_4,
105
- REG_DATA_CACHE_5,
106
- REG_DATA_CACHE_6,
107
- REG_DATA_CACHE_7,
108
- REG_DATA_CACHE_8,
109
- REG_DATA_CACHE_9,
110
- REG_DATA_CACHE_A,
111
- REG_DATA_CACHE_B,
112
- REG_POWER_OUTPUT_CTRL = 0x12u,
113
- REG_DC_DC2_OUT_V_CTRL = 0x23u,
114
- REG_DC_DC2_DVS_CTRL = 0x25u,
115
- REG_DC_DC3_OUT_V_CTRL = 0x27u,
116
- REG_LDO2_4_OUT_V_CTRL,
117
- REG_LDO3_OUT_V_CTRL,
118
- REG_VBUS_CH_MGMT = 0x30u,
119
- REG_SHUTDOWN_V_CTRL,
120
- REG_SHUTDOWN_CTRL,
121
- REG_CHARGE_CTRL_1,
122
- REG_CHARGE_CTRL_2,
123
- REG_SPARE_CHARGE_CTRL,
124
- REG_PEK_KEY_CTRL,
125
- REG_DC_DC_FREQ_SET,
126
- REG_CHR_TEMP_TH_SET,
127
- REG_CHR_HIGH_TEMP_TH_CTRL,
128
- REG_IPSOUT_WARN_L1,
129
- REG_IPSOUT_WARN_L2,
130
- REG_DISCHR_TEMP_TH_SET,
131
- REG_DISCHR_HIGH_TEMP_TH_CTRL,
132
- REG_IRQ_BANK_1_CTRL = 0x40u,
133
- REG_IRQ_BANK_2_CTRL,
134
- REG_IRQ_BANK_3_CTRL,
135
- REG_IRQ_BANK_4_CTRL,
136
- REG_IRQ_BANK_5_CTRL,
137
- REG_IRQ_BANK_1_STAT = 0x48u,
138
- REG_IRQ_BANK_2_STAT,
139
- REG_IRQ_BANK_3_STAT,
140
- REG_IRQ_BANK_4_STAT,
141
- REG_IRQ_BANK_5_STAT,
142
- REG_ADC_ACIN_V_H = 0x56u,
143
- REG_ADC_ACIN_V_L,
144
- REG_ADC_ACIN_CURR_H,
145
- REG_ADC_ACIN_CURR_L,
146
- REG_ADC_VBUS_V_H,
147
- REG_ADC_VBUS_V_L,
148
- REG_ADC_VBUS_CURR_H,
149
- REG_ADC_VBUS_CURR_L,
150
- REG_ADC_INT_TEMP_H,
151
- REG_ADC_INT_TEMP_L,
152
- REG_ADC_TEMP_SENS_V_H = 0x62u,
153
- REG_ADC_TEMP_SENS_V_L,
154
- REG_ADC_BAT_V_H = 0x78u,
155
- REG_ADC_BAT_V_L,
156
- REG_ADC_BAT_DISCHR_CURR_H,
157
- REG_ADC_BAT_DISCHR_CURR_L,
158
- REG_ADC_BAT_CHR_CURR_H,
159
- REG_ADC_BAT_CHR_CURR_L,
160
- REG_ADC_IPSOUT_V_H,
161
- REG_ADC_IPSOUT_V_L,
162
- REG_DC_DC_MOD_SEL = 0x80u,
163
- REG_ADC_EN_1,
164
- REG_ADC_EN_2,
165
- REG_ADC_SR_CTRL,
166
- REG_ADC_IN_RANGE,
167
- REG_GPIO1_ADC_IRQ_RISING_TH,
168
- REG_GPIO1_ADC_IRQ_FALLING_TH,
169
- REG_TIMER_CTRL = 0x8au,
170
- REG_VBUS_CTRL_MON_SRP,
171
- REG_OVER_TEMP_SHUTDOWN = 0x8fu,
172
- REG_GPIO0_FEAT_SET,
173
- REG_GPIO_OUT_HIGH_SET,
174
- REG_GPIO1_FEAT_SET,
175
- REG_GPIO2_FEAT_SET,
176
- REG_GPIO_SIG_STATE_SET_MON,
177
- REG_GPIO3_SET,
178
- REG_COULOMB_CNTR_CTRL = 0xb8u,
179
- REG_POWER_MEAS_RES,
180
- NR_REGS
181
-};
182
-
183
-#define AXP209_CHIP_VERSION_ID (0x01)
184
-#define AXP209_DC_DC2_OUT_V_CTRL_RESET (0x16)
185
-#define AXP209_IRQ_BANK_1_CTRL_RESET (0xd8)
186
-
187
-/* A simple I2C slave which returns values of ID or CNT register. */
188
-typedef struct AXP209I2CState {
189
- /*< private >*/
190
- I2CSlave i2c;
191
- /*< public >*/
192
- uint8_t regs[NR_REGS]; /* peripheral registers */
193
- uint8_t ptr; /* current register index */
194
- uint8_t count; /* counter used for tx/rx */
195
-} AXP209I2CState;
196
-
197
-/* Reset all counters and load ID register */
198
-static void axp209_reset_enter(Object *obj, ResetType type)
199
-{
200
- AXP209I2CState *s = AXP209(obj);
201
-
202
- memset(s->regs, 0, NR_REGS);
203
- s->ptr = 0;
204
- s->count = 0;
205
- s->regs[REG_CHIP_VERSION] = AXP209_CHIP_VERSION_ID;
206
- s->regs[REG_DC_DC2_OUT_V_CTRL] = AXP209_DC_DC2_OUT_V_CTRL_RESET;
207
- s->regs[REG_IRQ_BANK_1_CTRL] = AXP209_IRQ_BANK_1_CTRL_RESET;
208
-}
209
-
210
-/* Handle events from master. */
211
-static int axp209_event(I2CSlave *i2c, enum i2c_event event)
212
-{
213
- AXP209I2CState *s = AXP209(i2c);
214
-
215
- s->count = 0;
216
-
217
- return 0;
218
-}
219
-
220
-/* Called when master requests read */
221
-static uint8_t axp209_rx(I2CSlave *i2c)
222
-{
223
- AXP209I2CState *s = AXP209(i2c);
224
- uint8_t ret = 0xff;
225
-
226
- if (s->ptr < NR_REGS) {
227
- ret = s->regs[s->ptr++];
228
- }
229
-
230
- trace_axp209_rx(s->ptr - 1, ret);
231
-
232
- return ret;
233
-}
234
-
235
-/*
236
- * Called when master sends write.
237
- * Update ptr with byte 0, then perform write with second byte.
238
- */
239
-static int axp209_tx(I2CSlave *i2c, uint8_t data)
240
-{
241
- AXP209I2CState *s = AXP209(i2c);
242
-
243
- if (s->count == 0) {
244
- /* Store register address */
245
- s->ptr = data;
246
- s->count++;
247
- trace_axp209_select(data);
248
- } else {
249
- trace_axp209_tx(s->ptr, data);
250
- if (s->ptr == REG_DC_DC2_OUT_V_CTRL) {
251
- s->regs[s->ptr++] = data;
252
- }
253
- }
254
-
255
- return 0;
256
-}
257
-
258
-static const VMStateDescription vmstate_axp209 = {
259
- .name = TYPE_AXP209_PMU,
260
- .version_id = 1,
261
- .fields = (VMStateField[]) {
262
- VMSTATE_UINT8_ARRAY(regs, AXP209I2CState, NR_REGS),
263
- VMSTATE_UINT8(count, AXP209I2CState),
264
- VMSTATE_UINT8(ptr, AXP209I2CState),
265
- VMSTATE_END_OF_LIST()
266
- }
267
-};
268
-
269
-static void axp209_class_init(ObjectClass *oc, void *data)
270
-{
271
- DeviceClass *dc = DEVICE_CLASS(oc);
272
- I2CSlaveClass *isc = I2C_SLAVE_CLASS(oc);
273
- ResettableClass *rc = RESETTABLE_CLASS(oc);
274
-
275
- rc->phases.enter = axp209_reset_enter;
276
- dc->vmsd = &vmstate_axp209;
277
- isc->event = axp209_event;
278
- isc->recv = axp209_rx;
279
- isc->send = axp209_tx;
280
-}
281
-
282
-static const TypeInfo axp209_info = {
283
- .name = TYPE_AXP209_PMU,
284
- .parent = TYPE_I2C_SLAVE,
285
- .instance_size = sizeof(AXP209I2CState),
286
- .class_init = axp209_class_init
287
-};
288
-
289
-static void axp209_register_devices(void)
290
-{
291
- type_register_static(&axp209_info);
292
-}
293
-
294
-type_init(axp209_register_devices);
295
diff --git a/hw/misc/axp2xx.c b/hw/misc/axp2xx.c
296
new file mode 100644
139
index XXXXXXX..XXXXXXX
297
index XXXXXXX..XXXXXXX
140
--- a/docs/index.html.in
298
--- /dev/null
141
+++ /dev/null
299
+++ b/hw/misc/axp2xx.c
142
@@ -XXX,XX +XXX,XX @@
300
@@ -XXX,XX +XXX,XX @@
143
-<!DOCTYPE html>
301
+/*
144
-<html lang="en">
302
+ * AXP-2XX PMU Emulation, supported lists:
145
- <head>
303
+ * AXP209
146
- <meta charset="UTF-8">
304
+ * AXP221
147
- <title>QEMU @VERSION@ Documentation</title>
305
+ *
148
- </head>
306
+ * Copyright (C) 2022 Strahinja Jankovic <strahinja.p.jankovic@gmail.com>
149
- <body>
307
+ * Copyright (C) 2023 qianfan Zhao <qianfanguijin@163.com>
150
- <h1>QEMU @VERSION@ Documentation</h1>
308
+ *
151
- <ul>
309
+ * Permission is hereby granted, free of charge, to any person obtaining a
152
- <li><a href="system/index.html">System Emulation User's Guide</a></li>
310
+ * copy of this software and associated documentation files (the "Software"),
153
- <li><a href="user/index.html">User Mode Emulation User's Guide</a></li>
311
+ * to deal in the Software without restriction, including without limitation
154
- <li><a href="tools/index.html">Tools Guide</a></li>
312
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
155
- <li><a href="interop/index.html">System Emulation Management and Interoperability Guide</a></li>
313
+ * and/or sell copies of the Software, and to permit persons to whom the
156
- <li><a href="specs/index.html">System Emulation Guest Hardware Specifications</a></li>
314
+ * Software is furnished to do so, subject to the following conditions:
157
- </ul>
315
+ *
158
- </body>
316
+ * The above copyright notice and this permission notice shall be included in
159
-</html>
317
+ * all copies or substantial portions of the Software.
160
diff --git a/docs/interop/conf.py b/docs/interop/conf.py
318
+ *
161
deleted file mode 100644
319
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
162
index XXXXXXX..XXXXXXX
320
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
163
--- a/docs/interop/conf.py
321
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
164
+++ /dev/null
322
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
165
@@ -XXX,XX +XXX,XX @@
323
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
166
-# -*- coding: utf-8 -*-
324
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
167
-#
325
+ * DEALINGS IN THE SOFTWARE.
168
-# QEMU documentation build configuration file for the 'interop' manual.
326
+ *
169
-#
327
+ * SPDX-License-Identifier: MIT
170
-# This includes the top level conf file and then makes any necessary tweaks.
328
+ */
171
-import sys
329
+
172
-import os
330
+#include "qemu/osdep.h"
173
-
331
+#include "qemu/log.h"
174
-qemu_docdir = os.path.abspath("..")
332
+#include "qom/object.h"
175
-parent_config = os.path.join(qemu_docdir, "conf.py")
333
+#include "trace.h"
176
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
334
+#include "hw/i2c/i2c.h"
177
-
335
+#include "migration/vmstate.h"
178
-# This slightly misuses the 'description', but is the best way to get
336
+
179
-# the manual title to appear in the sidebar.
337
+#define TYPE_AXP2XX "axp2xx_pmu"
180
-html_theme_options['description'] = u'System Emulation Management and Interoperability Guide'
338
+#define TYPE_AXP209_PMU "axp209_pmu"
181
-
339
+#define TYPE_AXP221_PMU "axp221_pmu"
182
-# One entry per manual page. List of tuples
340
+
183
-# (source start file, name, description, authors, manual section).
341
+OBJECT_DECLARE_TYPE(AXP2xxI2CState, AXP2xxClass, AXP2XX)
184
-man_pages = [
342
+
185
- ('qemu-ga', 'qemu-ga', u'QEMU Guest Agent',
343
+#define NR_REGS (0xff)
186
- ['Michael Roth <mdroth@linux.vnet.ibm.com>'], 8),
344
+
187
- ('qemu-ga-ref', 'qemu-ga-ref', 'QEMU Guest Agent Protocol Reference',
345
+/* A simple I2C slave which returns values of ID or CNT register. */
188
- [], 7),
346
+typedef struct AXP2xxI2CState {
189
- ('qemu-qmp-ref', 'qemu-qmp-ref', 'QEMU QMP Reference Manual',
347
+ /*< private >*/
190
- [], 7),
348
+ I2CSlave i2c;
191
- ('qemu-storage-daemon-qmp-ref', 'qemu-storage-daemon-qmp-ref',
349
+ /*< public >*/
192
- 'QEMU Storage Daemon QMP Reference Manual', [], 7),
350
+ uint8_t regs[NR_REGS]; /* peripheral registers */
193
-]
351
+ uint8_t ptr; /* current register index */
194
diff --git a/docs/meson.build b/docs/meson.build
352
+ uint8_t count; /* counter used for tx/rx */
353
+} AXP2xxI2CState;
354
+
355
+typedef struct AXP2xxClass {
356
+ /*< private >*/
357
+ I2CSlaveClass parent_class;
358
+ /*< public >*/
359
+ void (*reset_enter)(AXP2xxI2CState *s, ResetType type);
360
+} AXP2xxClass;
361
+
362
+#define AXP209_CHIP_VERSION_ID (0x01)
363
+#define AXP209_DC_DC2_OUT_V_CTRL_RESET (0x16)
364
+
365
+/* Reset all counters and load ID register */
366
+static void axp209_reset_enter(AXP2xxI2CState *s, ResetType type)
367
+{
368
+ memset(s->regs, 0, NR_REGS);
369
+ s->ptr = 0;
370
+ s->count = 0;
371
+
372
+ s->regs[0x03] = AXP209_CHIP_VERSION_ID;
373
+ s->regs[0x23] = AXP209_DC_DC2_OUT_V_CTRL_RESET;
374
+
375
+ s->regs[0x30] = 0x60;
376
+ s->regs[0x32] = 0x46;
377
+ s->regs[0x34] = 0x41;
378
+ s->regs[0x35] = 0x22;
379
+ s->regs[0x36] = 0x5d;
380
+ s->regs[0x37] = 0x08;
381
+ s->regs[0x38] = 0xa5;
382
+ s->regs[0x39] = 0x1f;
383
+ s->regs[0x3a] = 0x68;
384
+ s->regs[0x3b] = 0x5f;
385
+ s->regs[0x3c] = 0xfc;
386
+ s->regs[0x3d] = 0x16;
387
+ s->regs[0x40] = 0xd8;
388
+ s->regs[0x42] = 0xff;
389
+ s->regs[0x43] = 0x3b;
390
+ s->regs[0x80] = 0xe0;
391
+ s->regs[0x82] = 0x83;
392
+ s->regs[0x83] = 0x80;
393
+ s->regs[0x84] = 0x32;
394
+ s->regs[0x86] = 0xff;
395
+ s->regs[0x90] = 0x07;
396
+ s->regs[0x91] = 0xa0;
397
+ s->regs[0x92] = 0x07;
398
+ s->regs[0x93] = 0x07;
399
+}
400
+
401
+#define AXP221_PWR_STATUS_ACIN_PRESENT BIT(7)
402
+#define AXP221_PWR_STATUS_ACIN_AVAIL BIT(6)
403
+#define AXP221_PWR_STATUS_VBUS_PRESENT BIT(5)
404
+#define AXP221_PWR_STATUS_VBUS_USED BIT(4)
405
+#define AXP221_PWR_STATUS_BAT_CHARGING BIT(2)
406
+#define AXP221_PWR_STATUS_ACIN_VBUS_POWERED BIT(1)
407
+
408
+/* Reset all counters and load ID register */
409
+static void axp221_reset_enter(AXP2xxI2CState *s, ResetType type)
410
+{
411
+ memset(s->regs, 0, NR_REGS);
412
+ s->ptr = 0;
413
+ s->count = 0;
414
+
415
+ /* input power status register */
416
+ s->regs[0x00] = AXP221_PWR_STATUS_ACIN_PRESENT
417
+ | AXP221_PWR_STATUS_ACIN_AVAIL
418
+ | AXP221_PWR_STATUS_ACIN_VBUS_POWERED;
419
+
420
+ s->regs[0x01] = 0x00; /* no battery is connected */
421
+
422
+ /*
423
+ * CHIPID register, no documented on datasheet, but it is checked in
424
+ * u-boot spl. I had read it from AXP221s and got 0x06 value.
425
+ * So leave 06h here.
426
+ */
427
+ s->regs[0x03] = 0x06;
428
+
429
+ s->regs[0x10] = 0xbf;
430
+ s->regs[0x13] = 0x01;
431
+ s->regs[0x30] = 0x60;
432
+ s->regs[0x31] = 0x03;
433
+ s->regs[0x32] = 0x43;
434
+ s->regs[0x33] = 0xc6;
435
+ s->regs[0x34] = 0x45;
436
+ s->regs[0x35] = 0x0e;
437
+ s->regs[0x36] = 0x5d;
438
+ s->regs[0x37] = 0x08;
439
+ s->regs[0x38] = 0xa5;
440
+ s->regs[0x39] = 0x1f;
441
+ s->regs[0x3c] = 0xfc;
442
+ s->regs[0x3d] = 0x16;
443
+ s->regs[0x80] = 0x80;
444
+ s->regs[0x82] = 0xe0;
445
+ s->regs[0x84] = 0x32;
446
+ s->regs[0x8f] = 0x01;
447
+
448
+ s->regs[0x90] = 0x07;
449
+ s->regs[0x91] = 0x1f;
450
+ s->regs[0x92] = 0x07;
451
+ s->regs[0x93] = 0x1f;
452
+
453
+ s->regs[0x40] = 0xd8;
454
+ s->regs[0x41] = 0xff;
455
+ s->regs[0x42] = 0x03;
456
+ s->regs[0x43] = 0x03;
457
+
458
+ s->regs[0xb8] = 0xc0;
459
+ s->regs[0xb9] = 0x64;
460
+ s->regs[0xe6] = 0xa0;
461
+}
462
+
463
+static void axp2xx_reset_enter(Object *obj, ResetType type)
464
+{
465
+ AXP2xxI2CState *s = AXP2XX(obj);
466
+ AXP2xxClass *sc = AXP2XX_GET_CLASS(s);
467
+
468
+ sc->reset_enter(s, type);
469
+}
470
+
471
+/* Handle events from master. */
472
+static int axp2xx_event(I2CSlave *i2c, enum i2c_event event)
473
+{
474
+ AXP2xxI2CState *s = AXP2XX(i2c);
475
+
476
+ s->count = 0;
477
+
478
+ return 0;
479
+}
480
+
481
+/* Called when master requests read */
482
+static uint8_t axp2xx_rx(I2CSlave *i2c)
483
+{
484
+ AXP2xxI2CState *s = AXP2XX(i2c);
485
+ uint8_t ret = 0xff;
486
+
487
+ if (s->ptr < NR_REGS) {
488
+ ret = s->regs[s->ptr++];
489
+ }
490
+
491
+ trace_axp2xx_rx(s->ptr - 1, ret);
492
+
493
+ return ret;
494
+}
495
+
496
+/*
497
+ * Called when master sends write.
498
+ * Update ptr with byte 0, then perform write with second byte.
499
+ */
500
+static int axp2xx_tx(I2CSlave *i2c, uint8_t data)
501
+{
502
+ AXP2xxI2CState *s = AXP2XX(i2c);
503
+
504
+ if (s->count == 0) {
505
+ /* Store register address */
506
+ s->ptr = data;
507
+ s->count++;
508
+ trace_axp2xx_select(data);
509
+ } else {
510
+ trace_axp2xx_tx(s->ptr, data);
511
+ s->regs[s->ptr++] = data;
512
+ }
513
+
514
+ return 0;
515
+}
516
+
517
+static const VMStateDescription vmstate_axp2xx = {
518
+ .name = TYPE_AXP2XX,
519
+ .version_id = 1,
520
+ .fields = (VMStateField[]) {
521
+ VMSTATE_UINT8_ARRAY(regs, AXP2xxI2CState, NR_REGS),
522
+ VMSTATE_UINT8(ptr, AXP2xxI2CState),
523
+ VMSTATE_UINT8(count, AXP2xxI2CState),
524
+ VMSTATE_END_OF_LIST()
525
+ }
526
+};
527
+
528
+static void axp2xx_class_init(ObjectClass *oc, void *data)
529
+{
530
+ DeviceClass *dc = DEVICE_CLASS(oc);
531
+ I2CSlaveClass *isc = I2C_SLAVE_CLASS(oc);
532
+ ResettableClass *rc = RESETTABLE_CLASS(oc);
533
+
534
+ rc->phases.enter = axp2xx_reset_enter;
535
+ dc->vmsd = &vmstate_axp2xx;
536
+ isc->event = axp2xx_event;
537
+ isc->recv = axp2xx_rx;
538
+ isc->send = axp2xx_tx;
539
+}
540
+
541
+static const TypeInfo axp2xx_info = {
542
+ .name = TYPE_AXP2XX,
543
+ .parent = TYPE_I2C_SLAVE,
544
+ .instance_size = sizeof(AXP2xxI2CState),
545
+ .class_size = sizeof(AXP2xxClass),
546
+ .class_init = axp2xx_class_init,
547
+ .abstract = true,
548
+};
549
+
550
+static void axp209_class_init(ObjectClass *oc, void *data)
551
+{
552
+ AXP2xxClass *sc = AXP2XX_CLASS(oc);
553
+
554
+ sc->reset_enter = axp209_reset_enter;
555
+}
556
+
557
+static const TypeInfo axp209_info = {
558
+ .name = TYPE_AXP209_PMU,
559
+ .parent = TYPE_AXP2XX,
560
+ .class_init = axp209_class_init
561
+};
562
+
563
+static void axp221_class_init(ObjectClass *oc, void *data)
564
+{
565
+ AXP2xxClass *sc = AXP2XX_CLASS(oc);
566
+
567
+ sc->reset_enter = axp221_reset_enter;
568
+}
569
+
570
+static const TypeInfo axp221_info = {
571
+ .name = TYPE_AXP221_PMU,
572
+ .parent = TYPE_AXP2XX,
573
+ .class_init = axp221_class_init,
574
+};
575
+
576
+static void axp2xx_register_devices(void)
577
+{
578
+ type_register_static(&axp2xx_info);
579
+ type_register_static(&axp209_info);
580
+ type_register_static(&axp221_info);
581
+}
582
+
583
+type_init(axp2xx_register_devices);
584
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
195
index XXXXXXX..XXXXXXX 100644
585
index XXXXXXX..XXXXXXX 100644
196
--- a/docs/meson.build
586
--- a/hw/arm/Kconfig
197
+++ b/docs/meson.build
587
+++ b/hw/arm/Kconfig
198
@@ -XXX,XX +XXX,XX @@ if build_docs
588
@@ -XXX,XX +XXX,XX @@ config ALLWINNER_A10
199
meson.source_root() / 'docs/sphinx/qmp_lexer.py',
589
select ALLWINNER_WDT
200
qapi_gen_depends ]
590
select ALLWINNER_EMAC
201
591
select ALLWINNER_I2C
202
- configure_file(output: 'index.html',
592
- select AXP209_PMU
203
- input: files('index.html.in'),
593
+ select AXP2XX_PMU
204
- configuration: {'VERSION': meson.project_version()},
594
select SERIAL
205
- install_dir: qemu_docdir)
595
select UNIMP
206
- manuals = [ 'devel', 'interop', 'tools', 'specs', 'system', 'user' ]
596
207
man_pages = {
597
@@ -XXX,XX +XXX,XX @@ config ALLWINNER_R40
208
- 'interop' : {
598
bool
209
'qemu-ga.8': (have_tools ? 'man8' : ''),
599
default y if TCG && ARM
210
'qemu-ga-ref.7': 'man7',
600
select ALLWINNER_A10_PIT
211
'qemu-qmp-ref.7': 'man7',
601
+ select AXP2XX_PMU
212
'qemu-storage-daemon-qmp-ref.7': (have_tools ? 'man7' : ''),
602
select SERIAL
213
- },
603
select ARM_TIMER
214
- 'tools': {
604
select ARM_GIC
215
'qemu-img.1': (have_tools ? 'man1' : ''),
605
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
216
'qemu-nbd.8': (have_tools ? 'man8' : ''),
606
index XXXXXXX..XXXXXXX 100644
217
'qemu-pr-helper.8': (have_tools ? 'man8' : ''),
607
--- a/hw/misc/Kconfig
218
@@ -XXX,XX +XXX,XX @@ if build_docs
608
+++ b/hw/misc/Kconfig
219
'qemu-trace-stap.1': (config_host.has_key('CONFIG_TRACE_SYSTEMTAP') ? 'man1' : ''),
609
@@ -XXX,XX +XXX,XX @@ config ALLWINNER_A10_CCM
220
'virtfs-proxy-helper.1': (have_virtfs_proxy_helper ? 'man1' : ''),
610
config ALLWINNER_A10_DRAMC
221
'virtiofsd.1': (have_virtiofsd ? 'man1' : ''),
611
bool
222
- },
612
223
- 'system': {
613
-config AXP209_PMU
224
'qemu.1': 'man1',
614
+config AXP2XX_PMU
225
'qemu-block-drivers.7': 'man7',
615
bool
226
'qemu-cpu-models.7': 'man7'
616
depends on I2C
227
- },
617
228
}
618
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
229
619
index XXXXXXX..XXXXXXX 100644
230
sphinxdocs = []
620
--- a/hw/misc/meson.build
231
sphinxmans = []
621
+++ b/hw/misc/meson.build
232
- foreach manual : manuals
622
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3-dramc.c
233
- private_dir = meson.current_build_dir() / (manual + '.p')
623
softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3-sysctrl.c'))
234
- output_dir = meson.current_build_dir() / manual
624
softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-sid.c'))
235
- input_dir = meson.current_source_dir() / manual
625
softmmu_ss.add(when: 'CONFIG_ALLWINNER_R40', if_true: files('allwinner-r40-ccu.c'))
236
626
-softmmu_ss.add(when: 'CONFIG_AXP209_PMU', if_true: files('axp209.c'))
237
- this_manual = custom_target(manual + ' manual',
627
+softmmu_ss.add(when: 'CONFIG_AXP2XX_PMU', if_true: files('axp2xx.c'))
238
+ private_dir = meson.current_build_dir() / 'manual.p'
628
softmmu_ss.add(when: 'CONFIG_REALVIEW', if_true: files('arm_sysctl.c'))
239
+ output_dir = meson.current_build_dir() / 'manual'
629
softmmu_ss.add(when: 'CONFIG_NSERIES', if_true: files('cbus.c'))
240
+ input_dir = meson.current_source_dir()
630
softmmu_ss.add(when: 'CONFIG_ECCMEMCTL', if_true: files('eccmemctl.c'))
241
+
631
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
242
+ this_manual = custom_target('QEMU manual',
632
index XXXXXXX..XXXXXXX 100644
243
build_by_default: build_docs,
633
--- a/hw/misc/trace-events
244
- output: [manual + '.stamp'],
634
+++ b/hw/misc/trace-events
245
- input: [files('conf.py'), files(manual / 'conf.py')],
635
@@ -XXX,XX +XXX,XX @@ allwinner_sid_write(uint64_t offset, uint64_t data, unsigned size) "offset 0x%"
246
- depfile: manual + '.d',
636
avr_power_read(uint8_t value) "power_reduc read value:%u"
247
+ output: 'docs.stamp',
637
avr_power_write(uint8_t value) "power_reduc write value:%u"
248
+ input: files('conf.py'),
638
249
+ depfile: 'docs.d',
639
-# axp209.c
250
depend_files: sphinx_extn_depends,
640
-axp209_rx(uint8_t reg, uint8_t data) "Read reg 0x%" PRIx8 " : 0x%" PRIx8
251
command: [SPHINX_ARGS, '-Ddepfile=@DEPFILE@',
641
-axp209_select(uint8_t reg) "Accessing reg 0x%" PRIx8
252
'-Ddepfile_stamp=@OUTPUT0@',
642
-axp209_tx(uint8_t reg, uint8_t data) "Write reg 0x%" PRIx8 " : 0x%" PRIx8
253
'-b', 'html', '-d', private_dir,
643
+# axp2xx
254
input_dir, output_dir])
644
+axp2xx_rx(uint8_t reg, uint8_t data) "Read reg 0x%" PRIx8 " : 0x%" PRIx8
255
- sphinxdocs += this_manual
645
+axp2xx_select(uint8_t reg) "Accessing reg 0x%" PRIx8
256
- if build_docs and manual != 'devel'
646
+axp2xx_tx(uint8_t reg, uint8_t data) "Write reg 0x%" PRIx8 " : 0x%" PRIx8
257
- install_subdir(output_dir, install_dir: qemu_docdir)
647
258
- endif
648
# eccmemctl.c
259
+ sphinxdocs += this_manual
649
ecc_mem_writel_mer(uint32_t val) "Write memory enable 0x%08x"
260
+ install_subdir(output_dir, install_dir: qemu_docdir, strip_directory: true)
261
262
- these_man_pages = []
263
- install_dirs = []
264
- foreach page, section : man_pages.get(manual, {})
265
- these_man_pages += page
266
- install_dirs += section == '' ? false : get_option('mandir') / section
267
- endforeach
268
- if these_man_pages.length() > 0
269
- sphinxmans += custom_target(manual + ' man pages',
270
- build_by_default: build_docs,
271
- output: these_man_pages,
272
- input: this_manual,
273
- install: build_docs,
274
- install_dir: install_dirs,
275
- command: [SPHINX_ARGS, '-b', 'man', '-d', private_dir,
276
- input_dir, meson.current_build_dir()])
277
- endif
278
+ these_man_pages = []
279
+ install_dirs = []
280
+ foreach page, section : man_pages
281
+ these_man_pages += page
282
+ install_dirs += section == '' ? false : get_option('mandir') / section
283
endforeach
284
+
285
+ sphinxmans += custom_target('QEMU man pages',
286
+ build_by_default: build_docs,
287
+ output: these_man_pages,
288
+ input: this_manual,
289
+ install: build_docs,
290
+ install_dir: install_dirs,
291
+ command: [SPHINX_ARGS, '-b', 'man', '-d', private_dir,
292
+ input_dir, meson.current_build_dir()])
293
+
294
alias_target('sphinxdocs', sphinxdocs)
295
alias_target('html', sphinxdocs)
296
alias_target('man', sphinxmans)
297
diff --git a/docs/specs/conf.py b/docs/specs/conf.py
298
deleted file mode 100644
299
index XXXXXXX..XXXXXXX
300
--- a/docs/specs/conf.py
301
+++ /dev/null
302
@@ -XXX,XX +XXX,XX @@
303
-# -*- coding: utf-8 -*-
304
-#
305
-# QEMU documentation build configuration file for the 'specs' manual.
306
-#
307
-# This includes the top level conf file and then makes any necessary tweaks.
308
-import sys
309
-import os
310
-
311
-qemu_docdir = os.path.abspath("..")
312
-parent_config = os.path.join(qemu_docdir, "conf.py")
313
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
314
-
315
-# This slightly misuses the 'description', but is the best way to get
316
-# the manual title to appear in the sidebar.
317
-html_theme_options['description'] = \
318
- u'System Emulation Guest Hardware Specifications'
319
diff --git a/docs/system/conf.py b/docs/system/conf.py
320
deleted file mode 100644
321
index XXXXXXX..XXXXXXX
322
--- a/docs/system/conf.py
323
+++ /dev/null
324
@@ -XXX,XX +XXX,XX @@
325
-# -*- coding: utf-8 -*-
326
-#
327
-# QEMU documentation build configuration file for the 'system' manual.
328
-#
329
-# This includes the top level conf file and then makes any necessary tweaks.
330
-import sys
331
-import os
332
-
333
-qemu_docdir = os.path.abspath("..")
334
-parent_config = os.path.join(qemu_docdir, "conf.py")
335
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
336
-
337
-# This slightly misuses the 'description', but is the best way to get
338
-# the manual title to appear in the sidebar.
339
-html_theme_options['description'] = u'System Emulation User''s Guide'
340
-
341
-# One entry per manual page. List of tuples
342
-# (source start file, name, description, authors, manual section).
343
-man_pages = [
344
- ('qemu-manpage', 'qemu', u'QEMU User Documentation',
345
- ['Fabrice Bellard'], 1),
346
- ('qemu-block-drivers', 'qemu-block-drivers',
347
- u'QEMU block drivers reference',
348
- ['Fabrice Bellard and the QEMU Project developers'], 7),
349
- ('qemu-cpu-models', 'qemu-cpu-models',
350
- u'QEMU CPU Models',
351
- ['The QEMU Project developers'], 7)
352
-]
353
diff --git a/docs/tools/conf.py b/docs/tools/conf.py
354
deleted file mode 100644
355
index XXXXXXX..XXXXXXX
356
--- a/docs/tools/conf.py
357
+++ /dev/null
358
@@ -XXX,XX +XXX,XX @@
359
-# -*- coding: utf-8 -*-
360
-#
361
-# QEMU documentation build configuration file for the 'tools' manual.
362
-#
363
-# This includes the top level conf file and then makes any necessary tweaks.
364
-import sys
365
-import os
366
-
367
-qemu_docdir = os.path.abspath("..")
368
-parent_config = os.path.join(qemu_docdir, "conf.py")
369
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
370
-
371
-# This slightly misuses the 'description', but is the best way to get
372
-# the manual title to appear in the sidebar.
373
-html_theme_options['description'] = \
374
- u'Tools Guide'
375
-
376
-# One entry per manual page. List of tuples
377
-# (source start file, name, description, authors, manual section).
378
-man_pages = [
379
- ('qemu-img', 'qemu-img', u'QEMU disk image utility',
380
- ['Fabrice Bellard'], 1),
381
- ('qemu-storage-daemon', 'qemu-storage-daemon', u'QEMU storage daemon',
382
- [], 1),
383
- ('qemu-nbd', 'qemu-nbd', u'QEMU Disk Network Block Device Server',
384
- ['Anthony Liguori <anthony@codemonkey.ws>'], 8),
385
- ('qemu-pr-helper', 'qemu-pr-helper', 'QEMU persistent reservation helper',
386
- [], 8),
387
- ('qemu-trace-stap', 'qemu-trace-stap', u'QEMU SystemTap trace tool',
388
- [], 1),
389
- ('virtfs-proxy-helper', 'virtfs-proxy-helper',
390
- u'QEMU 9p virtfs proxy filesystem helper',
391
- ['M. Mohan Kumar'], 1),
392
- ('virtiofsd', 'virtiofsd', u'QEMU virtio-fs shared file system daemon',
393
- ['Stefan Hajnoczi <stefanha@redhat.com>',
394
- 'Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>'], 1),
395
-]
396
diff --git a/docs/user/conf.py b/docs/user/conf.py
397
deleted file mode 100644
398
index XXXXXXX..XXXXXXX
399
--- a/docs/user/conf.py
400
+++ /dev/null
401
@@ -XXX,XX +XXX,XX @@
402
-# -*- coding: utf-8 -*-
403
-#
404
-# QEMU documentation build configuration file for the 'user' manual.
405
-#
406
-# This includes the top level conf file and then makes any necessary tweaks.
407
-import sys
408
-import os
409
-
410
-qemu_docdir = os.path.abspath("..")
411
-parent_config = os.path.join(qemu_docdir, "conf.py")
412
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
413
-
414
-# This slightly misuses the 'description', but is the best way to get
415
-# the manual title to appear in the sidebar.
416
-html_theme_options['description'] = u'User Mode Emulation User''s Guide'
417
--
650
--
418
2.20.1
651
2.34.1
419
420
diff view generated by jsdifflib
New patch
1
From: qianfan Zhao <qianfanguijin@163.com>
1
2
3
Types of memory that the SDRAM controller supports are DDR2/DDR3
4
and capacities of up to 2GiB. This commit adds emulation support
5
of the Allwinner R40 SDRAM controller.
6
7
This driver only support 256M, 512M and 1024M memory now.
8
9
Signed-off-by: qianfan Zhao <qianfanguijin@163.com>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
12
include/hw/arm/allwinner-r40.h | 13 +-
13
include/hw/misc/allwinner-r40-dramc.h | 108 ++++++
14
hw/arm/allwinner-r40.c | 21 +-
15
hw/arm/bananapi_m2u.c | 7 +
16
hw/misc/allwinner-r40-dramc.c | 513 ++++++++++++++++++++++++++
17
hw/misc/meson.build | 1 +
18
hw/misc/trace-events | 14 +
19
7 files changed, 674 insertions(+), 3 deletions(-)
20
create mode 100644 include/hw/misc/allwinner-r40-dramc.h
21
create mode 100644 hw/misc/allwinner-r40-dramc.c
22
23
diff --git a/include/hw/arm/allwinner-r40.h b/include/hw/arm/allwinner-r40.h
24
index XXXXXXX..XXXXXXX 100644
25
--- a/include/hw/arm/allwinner-r40.h
26
+++ b/include/hw/arm/allwinner-r40.h
27
@@ -XXX,XX +XXX,XX @@
28
#include "hw/intc/arm_gic.h"
29
#include "hw/sd/allwinner-sdhost.h"
30
#include "hw/misc/allwinner-r40-ccu.h"
31
+#include "hw/misc/allwinner-r40-dramc.h"
32
#include "hw/i2c/allwinner-i2c.h"
33
#include "target/arm/cpu.h"
34
#include "sysemu/block-backend.h"
35
@@ -XXX,XX +XXX,XX @@ enum {
36
AW_R40_DEV_GIC_CPU,
37
AW_R40_DEV_GIC_HYP,
38
AW_R40_DEV_GIC_VCPU,
39
- AW_R40_DEV_SDRAM
40
+ AW_R40_DEV_SDRAM,
41
+ AW_R40_DEV_DRAMCOM,
42
+ AW_R40_DEV_DRAMCTL,
43
+ AW_R40_DEV_DRAMPHY,
44
};
45
46
#define AW_R40_NUM_CPUS (4)
47
@@ -XXX,XX +XXX,XX @@ struct AwR40State {
48
DeviceState parent_obj;
49
/*< public >*/
50
51
+ /** Physical base address for start of RAM */
52
+ hwaddr ram_addr;
53
+
54
+ /** Total RAM size in megabytes */
55
+ uint32_t ram_size;
56
+
57
ARMCPU cpus[AW_R40_NUM_CPUS];
58
const hwaddr *memmap;
59
AwA10PITState timer;
60
AwSdHostState mmc[AW_R40_NUM_MMCS];
61
AwR40ClockCtlState ccu;
62
+ AwR40DramCtlState dramc;
63
AWI2CState i2c0;
64
GICState gic;
65
MemoryRegion sram_a1;
66
diff --git a/include/hw/misc/allwinner-r40-dramc.h b/include/hw/misc/allwinner-r40-dramc.h
67
new file mode 100644
68
index XXXXXXX..XXXXXXX
69
--- /dev/null
70
+++ b/include/hw/misc/allwinner-r40-dramc.h
71
@@ -XXX,XX +XXX,XX @@
72
+/*
73
+ * Allwinner R40 SDRAM Controller emulation
74
+ *
75
+ * Copyright (C) 2023 qianfan Zhao <qianfanguijin@163.com>
76
+ *
77
+ * This program is free software: you can redistribute it and/or modify
78
+ * it under the terms of the GNU General Public License as published by
79
+ * the Free Software Foundation, either version 2 of the License, or
80
+ * (at your option) any later version.
81
+ *
82
+ * This program is distributed in the hope that it will be useful,
83
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
84
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
85
+ * GNU General Public License for more details.
86
+ *
87
+ * You should have received a copy of the GNU General Public License
88
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
89
+ */
90
+
91
+#ifndef HW_MISC_ALLWINNER_R40_DRAMC_H
92
+#define HW_MISC_ALLWINNER_R40_DRAMC_H
93
+
94
+#include "qom/object.h"
95
+#include "hw/sysbus.h"
96
+#include "exec/hwaddr.h"
97
+
98
+/**
99
+ * Constants
100
+ * @{
101
+ */
102
+
103
+/** Highest register address used by DRAMCOM module */
104
+#define AW_R40_DRAMCOM_REGS_MAXADDR (0x804)
105
+
106
+/** Total number of known DRAMCOM registers */
107
+#define AW_R40_DRAMCOM_REGS_NUM (AW_R40_DRAMCOM_REGS_MAXADDR / \
108
+ sizeof(uint32_t))
109
+
110
+/** Highest register address used by DRAMCTL module */
111
+#define AW_R40_DRAMCTL_REGS_MAXADDR (0x88c)
112
+
113
+/** Total number of known DRAMCTL registers */
114
+#define AW_R40_DRAMCTL_REGS_NUM (AW_R40_DRAMCTL_REGS_MAXADDR / \
115
+ sizeof(uint32_t))
116
+
117
+/** Highest register address used by DRAMPHY module */
118
+#define AW_R40_DRAMPHY_REGS_MAXADDR (0x4)
119
+
120
+/** Total number of known DRAMPHY registers */
121
+#define AW_R40_DRAMPHY_REGS_NUM (AW_R40_DRAMPHY_REGS_MAXADDR / \
122
+ sizeof(uint32_t))
123
+
124
+/** @} */
125
+
126
+/**
127
+ * Object model
128
+ * @{
129
+ */
130
+
131
+#define TYPE_AW_R40_DRAMC "allwinner-r40-dramc"
132
+OBJECT_DECLARE_SIMPLE_TYPE(AwR40DramCtlState, AW_R40_DRAMC)
133
+
134
+/** @} */
135
+
136
+/**
137
+ * Allwinner R40 SDRAM Controller object instance state.
138
+ */
139
+struct AwR40DramCtlState {
140
+ /*< private >*/
141
+ SysBusDevice parent_obj;
142
+ /*< public >*/
143
+
144
+ /** Physical base address for start of RAM */
145
+ hwaddr ram_addr;
146
+
147
+ /** Total RAM size in megabytes */
148
+ uint32_t ram_size;
149
+
150
+ uint8_t set_row_bits;
151
+ uint8_t set_bank_bits;
152
+ uint8_t set_col_bits;
153
+
154
+ /**
155
+ * @name Memory Regions
156
+ * @{
157
+ */
158
+ MemoryRegion dramcom_iomem; /**< DRAMCOM module I/O registers */
159
+ MemoryRegion dramctl_iomem; /**< DRAMCTL module I/O registers */
160
+ MemoryRegion dramphy_iomem; /**< DRAMPHY module I/O registers */
161
+ MemoryRegion dram_high; /**< The high 1G dram for dualrank detect */
162
+ MemoryRegion detect_cells; /**< DRAM memory cells for auto detect */
163
+
164
+ /** @} */
165
+
166
+ /**
167
+ * @name Hardware Registers
168
+ * @{
169
+ */
170
+
171
+ uint32_t dramcom[AW_R40_DRAMCOM_REGS_NUM]; /**< DRAMCOM registers */
172
+ uint32_t dramctl[AW_R40_DRAMCTL_REGS_NUM]; /**< DRAMCTL registers */
173
+ uint32_t dramphy[AW_R40_DRAMPHY_REGS_NUM] ;/**< DRAMPHY registers */
174
+
175
+ /** @} */
176
+
177
+};
178
+
179
+#endif /* HW_MISC_ALLWINNER_R40_DRAMC_H */
180
diff --git a/hw/arm/allwinner-r40.c b/hw/arm/allwinner-r40.c
181
index XXXXXXX..XXXXXXX 100644
182
--- a/hw/arm/allwinner-r40.c
183
+++ b/hw/arm/allwinner-r40.c
184
@@ -XXX,XX +XXX,XX @@
185
#include "hw/loader.h"
186
#include "sysemu/sysemu.h"
187
#include "hw/arm/allwinner-r40.h"
188
+#include "hw/misc/allwinner-r40-dramc.h"
189
190
/* Memory map */
191
const hwaddr allwinner_r40_memmap[] = {
192
@@ -XXX,XX +XXX,XX @@ const hwaddr allwinner_r40_memmap[] = {
193
[AW_R40_DEV_UART6] = 0x01c29800,
194
[AW_R40_DEV_UART7] = 0x01c29c00,
195
[AW_R40_DEV_TWI0] = 0x01c2ac00,
196
+ [AW_R40_DEV_DRAMCOM] = 0x01c62000,
197
+ [AW_R40_DEV_DRAMCTL] = 0x01c63000,
198
+ [AW_R40_DEV_DRAMPHY] = 0x01c65000,
199
[AW_R40_DEV_GIC_DIST] = 0x01c81000,
200
[AW_R40_DEV_GIC_CPU] = 0x01c82000,
201
[AW_R40_DEV_GIC_HYP] = 0x01c84000,
202
@@ -XXX,XX +XXX,XX @@ static struct AwR40Unimplemented r40_unimplemented[] = {
203
{ "gpu", 0x01c40000, 64 * KiB },
204
{ "gmac", 0x01c50000, 64 * KiB },
205
{ "hstmr", 0x01c60000, 4 * KiB },
206
- { "dram-com", 0x01c62000, 4 * KiB },
207
- { "dram-ctl", 0x01c63000, 4 * KiB },
208
{ "tcon-top", 0x01c70000, 4 * KiB },
209
{ "lcd0", 0x01c71000, 4 * KiB },
210
{ "lcd1", 0x01c72000, 4 * KiB },
211
@@ -XXX,XX +XXX,XX @@ static void allwinner_r40_init(Object *obj)
212
}
213
214
object_initialize_child(obj, "twi0", &s->i2c0, TYPE_AW_I2C_SUN6I);
215
+
216
+ object_initialize_child(obj, "dramc", &s->dramc, TYPE_AW_R40_DRAMC);
217
+ object_property_add_alias(obj, "ram-addr", OBJECT(&s->dramc),
218
+ "ram-addr");
219
+ object_property_add_alias(obj, "ram-size", OBJECT(&s->dramc),
220
+ "ram-size");
221
}
222
223
static void allwinner_r40_realize(DeviceState *dev, Error **errp)
224
@@ -XXX,XX +XXX,XX @@ static void allwinner_r40_realize(DeviceState *dev, Error **errp)
225
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c0), 0,
226
qdev_get_gpio_in(DEVICE(&s->gic), AW_R40_GIC_SPI_TWI0));
227
228
+ /* DRAMC */
229
+ sysbus_realize(SYS_BUS_DEVICE(&s->dramc), &error_fatal);
230
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->dramc), 0,
231
+ s->memmap[AW_R40_DEV_DRAMCOM]);
232
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->dramc), 1,
233
+ s->memmap[AW_R40_DEV_DRAMCTL]);
234
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->dramc), 2,
235
+ s->memmap[AW_R40_DEV_DRAMPHY]);
236
+
237
/* Unimplemented devices */
238
for (i = 0; i < ARRAY_SIZE(r40_unimplemented); i++) {
239
create_unimplemented_device(r40_unimplemented[i].device_name,
240
diff --git a/hw/arm/bananapi_m2u.c b/hw/arm/bananapi_m2u.c
241
index XXXXXXX..XXXXXXX 100644
242
--- a/hw/arm/bananapi_m2u.c
243
+++ b/hw/arm/bananapi_m2u.c
244
@@ -XXX,XX +XXX,XX @@ static void bpim2u_init(MachineState *machine)
245
object_property_set_int(OBJECT(r40), "clk1-freq", 24 * 1000 * 1000,
246
&error_abort);
247
248
+ /* DRAMC */
249
+ r40->ram_size = machine->ram_size / MiB;
250
+ object_property_set_uint(OBJECT(r40), "ram-addr",
251
+ r40->memmap[AW_R40_DEV_SDRAM], &error_abort);
252
+ object_property_set_int(OBJECT(r40), "ram-size",
253
+ r40->ram_size, &error_abort);
254
+
255
/* Mark R40 object realized */
256
qdev_realize(DEVICE(r40), NULL, &error_abort);
257
258
diff --git a/hw/misc/allwinner-r40-dramc.c b/hw/misc/allwinner-r40-dramc.c
259
new file mode 100644
260
index XXXXXXX..XXXXXXX
261
--- /dev/null
262
+++ b/hw/misc/allwinner-r40-dramc.c
263
@@ -XXX,XX +XXX,XX @@
264
+/*
265
+ * Allwinner R40 SDRAM Controller emulation
266
+ *
267
+ * CCopyright (C) 2023 qianfan Zhao <qianfanguijin@163.com>
268
+ *
269
+ * This program is free software: you can redistribute it and/or modify
270
+ * it under the terms of the GNU General Public License as published by
271
+ * the Free Software Foundation, either version 2 of the License, or
272
+ * (at your option) any later version.
273
+ *
274
+ * This program is distributed in the hope that it will be useful,
275
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
276
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
277
+ * GNU General Public License for more details.
278
+ *
279
+ * You should have received a copy of the GNU General Public License
280
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
281
+ */
282
+
283
+#include "qemu/osdep.h"
284
+#include "qemu/units.h"
285
+#include "qemu/error-report.h"
286
+#include "hw/sysbus.h"
287
+#include "migration/vmstate.h"
288
+#include "qemu/log.h"
289
+#include "qemu/module.h"
290
+#include "exec/address-spaces.h"
291
+#include "hw/qdev-properties.h"
292
+#include "qapi/error.h"
293
+#include "qemu/bitops.h"
294
+#include "hw/misc/allwinner-r40-dramc.h"
295
+#include "trace.h"
296
+
297
+#define REG_INDEX(offset) (offset / sizeof(uint32_t))
298
+
299
+/* DRAMCOM register offsets */
300
+enum {
301
+ REG_DRAMCOM_CR = 0x0000, /* Control Register */
302
+};
303
+
304
+/* DRAMCOMM register flags */
305
+enum {
306
+ REG_DRAMCOM_CR_DUAL_RANK = (1 << 0),
307
+};
308
+
309
+/* DRAMCTL register offsets */
310
+enum {
311
+ REG_DRAMCTL_PIR = 0x0000, /* PHY Initialization Register */
312
+ REG_DRAMCTL_PGSR = 0x0010, /* PHY General Status Register */
313
+ REG_DRAMCTL_STATR = 0x0018, /* Status Register */
314
+ REG_DRAMCTL_PGCR = 0x0100, /* PHY general configuration registers */
315
+};
316
+
317
+/* DRAMCTL register flags */
318
+enum {
319
+ REG_DRAMCTL_PGSR_INITDONE = (1 << 0),
320
+ REG_DRAMCTL_PGSR_READ_TIMEOUT = (1 << 13),
321
+ REG_DRAMCTL_PGCR_ENABLE_READ_TIMEOUT = (1 << 25),
322
+};
323
+
324
+enum {
325
+ REG_DRAMCTL_STATR_ACTIVE = (1 << 0),
326
+};
327
+
328
+#define DRAM_MAX_ROW_BITS 16
329
+#define DRAM_MAX_COL_BITS 13 /* 8192 */
330
+#define DRAM_MAX_BANK 3
331
+
332
+static uint64_t dram_autodetect_cells[DRAM_MAX_ROW_BITS]
333
+ [DRAM_MAX_BANK]
334
+ [DRAM_MAX_COL_BITS];
335
+struct VirtualDDRChip {
336
+ uint32_t ram_size;
337
+ uint8_t bank_bits;
338
+ uint8_t row_bits;
339
+ uint8_t col_bits;
340
+};
341
+
342
+/*
343
+ * Only power of 2 RAM sizes from 256MiB up to 2048MiB are supported,
344
+ * 2GiB memory is not supported due to dual rank feature.
345
+ */
346
+static const struct VirtualDDRChip dummy_ddr_chips[] = {
347
+ {
348
+ .ram_size = 256,
349
+ .bank_bits = 3,
350
+ .row_bits = 12,
351
+ .col_bits = 13,
352
+ }, {
353
+ .ram_size = 512,
354
+ .bank_bits = 3,
355
+ .row_bits = 13,
356
+ .col_bits = 13,
357
+ }, {
358
+ .ram_size = 1024,
359
+ .bank_bits = 3,
360
+ .row_bits = 14,
361
+ .col_bits = 13,
362
+ }, {
363
+ 0
364
+ }
365
+};
366
+
367
+static const struct VirtualDDRChip *get_match_ddr(uint32_t ram_size)
368
+{
369
+ const struct VirtualDDRChip *ddr;
370
+
371
+ for (ddr = &dummy_ddr_chips[0]; ddr->ram_size; ddr++) {
372
+ if (ddr->ram_size == ram_size) {
373
+ return ddr;
374
+ }
375
+ }
376
+
377
+ return NULL;
378
+}
379
+
380
+static uint64_t *address_to_autodetect_cells(AwR40DramCtlState *s,
381
+ const struct VirtualDDRChip *ddr,
382
+ uint32_t offset)
383
+{
384
+ int row_index = 0, bank_index = 0, col_index = 0;
385
+ uint32_t row_addr, bank_addr, col_addr;
386
+
387
+ row_addr = extract32(offset, s->set_col_bits + s->set_bank_bits,
388
+ s->set_row_bits);
389
+ bank_addr = extract32(offset, s->set_col_bits, s->set_bank_bits);
390
+ col_addr = extract32(offset, 0, s->set_col_bits);
391
+
392
+ for (int i = 0; i < ddr->row_bits; i++) {
393
+ if (row_addr & BIT(i)) {
394
+ row_index = i;
395
+ }
396
+ }
397
+
398
+ for (int i = 0; i < ddr->bank_bits; i++) {
399
+ if (bank_addr & BIT(i)) {
400
+ bank_index = i;
401
+ }
402
+ }
403
+
404
+ for (int i = 0; i < ddr->col_bits; i++) {
405
+ if (col_addr & BIT(i)) {
406
+ col_index = i;
407
+ }
408
+ }
409
+
410
+ trace_allwinner_r40_dramc_offset_to_cell(offset, row_index, bank_index,
411
+ col_index);
412
+ return &dram_autodetect_cells[row_index][bank_index][col_index];
413
+}
414
+
415
+static void allwinner_r40_dramc_map_rows(AwR40DramCtlState *s, uint8_t row_bits,
416
+ uint8_t bank_bits, uint8_t col_bits)
417
+{
418
+ const struct VirtualDDRChip *ddr = get_match_ddr(s->ram_size);
419
+ bool enable_detect_cells;
420
+
421
+ trace_allwinner_r40_dramc_map_rows(row_bits, bank_bits, col_bits);
422
+
423
+ if (!ddr) {
424
+ return;
425
+ }
426
+
427
+ s->set_row_bits = row_bits;
428
+ s->set_bank_bits = bank_bits;
429
+ s->set_col_bits = col_bits;
430
+
431
+ enable_detect_cells = ddr->bank_bits != bank_bits
432
+ || ddr->row_bits != row_bits
433
+ || ddr->col_bits != col_bits;
434
+
435
+ if (enable_detect_cells) {
436
+ trace_allwinner_r40_dramc_detect_cells_enable();
437
+ } else {
438
+ trace_allwinner_r40_dramc_detect_cells_disable();
439
+ }
440
+
441
+ memory_region_set_enabled(&s->detect_cells, enable_detect_cells);
442
+}
443
+
444
+static uint64_t allwinner_r40_dramcom_read(void *opaque, hwaddr offset,
445
+ unsigned size)
446
+{
447
+ const AwR40DramCtlState *s = AW_R40_DRAMC(opaque);
448
+ const uint32_t idx = REG_INDEX(offset);
449
+
450
+ if (idx >= AW_R40_DRAMCOM_REGS_NUM) {
451
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n",
452
+ __func__, (uint32_t)offset);
453
+ return 0;
454
+ }
455
+
456
+ trace_allwinner_r40_dramcom_read(offset, s->dramcom[idx], size);
457
+ return s->dramcom[idx];
458
+}
459
+
460
+static void allwinner_r40_dramcom_write(void *opaque, hwaddr offset,
461
+ uint64_t val, unsigned size)
462
+{
463
+ AwR40DramCtlState *s = AW_R40_DRAMC(opaque);
464
+ const uint32_t idx = REG_INDEX(offset);
465
+
466
+ trace_allwinner_r40_dramcom_write(offset, val, size);
467
+
468
+ if (idx >= AW_R40_DRAMCOM_REGS_NUM) {
469
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n",
470
+ __func__, (uint32_t)offset);
471
+ return;
472
+ }
473
+
474
+ switch (offset) {
475
+ case REG_DRAMCOM_CR: /* Control Register */
476
+ if (!(val & REG_DRAMCOM_CR_DUAL_RANK)) {
477
+ allwinner_r40_dramc_map_rows(s, ((val >> 4) & 0xf) + 1,
478
+ ((val >> 2) & 0x1) + 2,
479
+ (((val >> 8) & 0xf) + 3));
480
+ }
481
+ break;
482
+ };
483
+
484
+ s->dramcom[idx] = (uint32_t) val;
485
+}
486
+
487
+static uint64_t allwinner_r40_dramctl_read(void *opaque, hwaddr offset,
488
+ unsigned size)
489
+{
490
+ const AwR40DramCtlState *s = AW_R40_DRAMC(opaque);
491
+ const uint32_t idx = REG_INDEX(offset);
492
+
493
+ if (idx >= AW_R40_DRAMCTL_REGS_NUM) {
494
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n",
495
+ __func__, (uint32_t)offset);
496
+ return 0;
497
+ }
498
+
499
+ trace_allwinner_r40_dramctl_read(offset, s->dramctl[idx], size);
500
+ return s->dramctl[idx];
501
+}
502
+
503
+static void allwinner_r40_dramctl_write(void *opaque, hwaddr offset,
504
+ uint64_t val, unsigned size)
505
+{
506
+ AwR40DramCtlState *s = AW_R40_DRAMC(opaque);
507
+ const uint32_t idx = REG_INDEX(offset);
508
+
509
+ trace_allwinner_r40_dramctl_write(offset, val, size);
510
+
511
+ if (idx >= AW_R40_DRAMCTL_REGS_NUM) {
512
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n",
513
+ __func__, (uint32_t)offset);
514
+ return;
515
+ }
516
+
517
+ switch (offset) {
518
+ case REG_DRAMCTL_PIR: /* PHY Initialization Register */
519
+ s->dramctl[REG_INDEX(REG_DRAMCTL_PGSR)] |= REG_DRAMCTL_PGSR_INITDONE;
520
+ s->dramctl[REG_INDEX(REG_DRAMCTL_STATR)] |= REG_DRAMCTL_STATR_ACTIVE;
521
+ break;
522
+ }
523
+
524
+ s->dramctl[idx] = (uint32_t) val;
525
+}
526
+
527
+static uint64_t allwinner_r40_dramphy_read(void *opaque, hwaddr offset,
528
+ unsigned size)
529
+{
530
+ const AwR40DramCtlState *s = AW_R40_DRAMC(opaque);
531
+ const uint32_t idx = REG_INDEX(offset);
532
+
533
+ if (idx >= AW_R40_DRAMPHY_REGS_NUM) {
534
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n",
535
+ __func__, (uint32_t)offset);
536
+ return 0;
537
+ }
538
+
539
+ trace_allwinner_r40_dramphy_read(offset, s->dramphy[idx], size);
540
+ return s->dramphy[idx];
541
+}
542
+
543
+static void allwinner_r40_dramphy_write(void *opaque, hwaddr offset,
544
+ uint64_t val, unsigned size)
545
+{
546
+ AwR40DramCtlState *s = AW_R40_DRAMC(opaque);
547
+ const uint32_t idx = REG_INDEX(offset);
548
+
549
+ trace_allwinner_r40_dramphy_write(offset, val, size);
550
+
551
+ if (idx >= AW_R40_DRAMPHY_REGS_NUM) {
552
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n",
553
+ __func__, (uint32_t)offset);
554
+ return;
555
+ }
556
+
557
+ s->dramphy[idx] = (uint32_t) val;
558
+}
559
+
560
+static const MemoryRegionOps allwinner_r40_dramcom_ops = {
561
+ .read = allwinner_r40_dramcom_read,
562
+ .write = allwinner_r40_dramcom_write,
563
+ .endianness = DEVICE_NATIVE_ENDIAN,
564
+ .valid = {
565
+ .min_access_size = 4,
566
+ .max_access_size = 4,
567
+ },
568
+ .impl.min_access_size = 4,
569
+};
570
+
571
+static const MemoryRegionOps allwinner_r40_dramctl_ops = {
572
+ .read = allwinner_r40_dramctl_read,
573
+ .write = allwinner_r40_dramctl_write,
574
+ .endianness = DEVICE_NATIVE_ENDIAN,
575
+ .valid = {
576
+ .min_access_size = 4,
577
+ .max_access_size = 4,
578
+ },
579
+ .impl.min_access_size = 4,
580
+};
581
+
582
+static const MemoryRegionOps allwinner_r40_dramphy_ops = {
583
+ .read = allwinner_r40_dramphy_read,
584
+ .write = allwinner_r40_dramphy_write,
585
+ .endianness = DEVICE_NATIVE_ENDIAN,
586
+ .valid = {
587
+ .min_access_size = 4,
588
+ .max_access_size = 4,
589
+ },
590
+ .impl.min_access_size = 4,
591
+};
592
+
593
+static uint64_t allwinner_r40_detect_read(void *opaque, hwaddr offset,
594
+ unsigned size)
595
+{
596
+ AwR40DramCtlState *s = AW_R40_DRAMC(opaque);
597
+ const struct VirtualDDRChip *ddr = get_match_ddr(s->ram_size);
598
+ uint64_t data = 0;
599
+
600
+ if (ddr) {
601
+ data = *address_to_autodetect_cells(s, ddr, (uint32_t)offset);
602
+ }
603
+
604
+ trace_allwinner_r40_dramc_detect_cell_read(offset, data);
605
+ return data;
606
+}
607
+
608
+static void allwinner_r40_detect_write(void *opaque, hwaddr offset,
609
+ uint64_t data, unsigned size)
610
+{
611
+ AwR40DramCtlState *s = AW_R40_DRAMC(opaque);
612
+ const struct VirtualDDRChip *ddr = get_match_ddr(s->ram_size);
613
+
614
+ if (ddr) {
615
+ uint64_t *cell = address_to_autodetect_cells(s, ddr, (uint32_t)offset);
616
+ trace_allwinner_r40_dramc_detect_cell_write(offset, data);
617
+ *cell = data;
618
+ }
619
+}
620
+
621
+static const MemoryRegionOps allwinner_r40_detect_ops = {
622
+ .read = allwinner_r40_detect_read,
623
+ .write = allwinner_r40_detect_write,
624
+ .endianness = DEVICE_NATIVE_ENDIAN,
625
+ .valid = {
626
+ .min_access_size = 4,
627
+ .max_access_size = 4,
628
+ },
629
+ .impl.min_access_size = 4,
630
+};
631
+
632
+/*
633
+ * mctl_r40_detect_rank_count in u-boot will write the high 1G of DDR
634
+ * to detect wether the board support dual_rank or not. Create a virtual memory
635
+ * if the board's ram_size less or equal than 1G, and set read time out flag of
636
+ * REG_DRAMCTL_PGSR when the user touch this high dram.
637
+ */
638
+static uint64_t allwinner_r40_dualrank_detect_read(void *opaque, hwaddr offset,
639
+ unsigned size)
640
+{
641
+ AwR40DramCtlState *s = AW_R40_DRAMC(opaque);
642
+ uint32_t reg;
643
+
644
+ reg = s->dramctl[REG_INDEX(REG_DRAMCTL_PGCR)];
645
+ if (reg & REG_DRAMCTL_PGCR_ENABLE_READ_TIMEOUT) { /* Enable read time out */
646
+ /*
647
+ * this driver only support one rank, mark READ_TIMEOUT when try
648
+ * read the second rank.
649
+ */
650
+ s->dramctl[REG_INDEX(REG_DRAMCTL_PGSR)]
651
+ |= REG_DRAMCTL_PGSR_READ_TIMEOUT;
652
+ }
653
+
654
+ return 0;
655
+}
656
+
657
+static const MemoryRegionOps allwinner_r40_dualrank_detect_ops = {
658
+ .read = allwinner_r40_dualrank_detect_read,
659
+ .endianness = DEVICE_NATIVE_ENDIAN,
660
+ .valid = {
661
+ .min_access_size = 4,
662
+ .max_access_size = 4,
663
+ },
664
+ .impl.min_access_size = 4,
665
+};
666
+
667
+static void allwinner_r40_dramc_reset(DeviceState *dev)
668
+{
669
+ AwR40DramCtlState *s = AW_R40_DRAMC(dev);
670
+
671
+ /* Set default values for registers */
672
+ memset(&s->dramcom, 0, sizeof(s->dramcom));
673
+ memset(&s->dramctl, 0, sizeof(s->dramctl));
674
+ memset(&s->dramphy, 0, sizeof(s->dramphy));
675
+}
676
+
677
+static void allwinner_r40_dramc_realize(DeviceState *dev, Error **errp)
678
+{
679
+ AwR40DramCtlState *s = AW_R40_DRAMC(dev);
680
+
681
+ if (!get_match_ddr(s->ram_size)) {
682
+ error_report("%s: ram-size %u MiB is not supported",
683
+ __func__, s->ram_size);
684
+ exit(1);
685
+ }
686
+
687
+ /* detect_cells */
688
+ sysbus_mmio_map_overlap(SYS_BUS_DEVICE(s), 3, s->ram_addr, 10);
689
+ memory_region_set_enabled(&s->detect_cells, false);
690
+
691
+ /*
692
+ * We only support DRAM size up to 1G now, so prepare a high memory page
693
+ * after 1G for dualrank detect. index = 4
694
+ */
695
+ memory_region_init_io(&s->dram_high, OBJECT(s),
696
+ &allwinner_r40_dualrank_detect_ops, s,
697
+ "DRAMHIGH", KiB);
698
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->dram_high);
699
+ sysbus_mmio_map(SYS_BUS_DEVICE(s), 4, s->ram_addr + GiB);
700
+}
701
+
702
+static void allwinner_r40_dramc_init(Object *obj)
703
+{
704
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
705
+ AwR40DramCtlState *s = AW_R40_DRAMC(obj);
706
+
707
+ /* DRAMCOM registers, index 0 */
708
+ memory_region_init_io(&s->dramcom_iomem, OBJECT(s),
709
+ &allwinner_r40_dramcom_ops, s,
710
+ "DRAMCOM", 4 * KiB);
711
+ sysbus_init_mmio(sbd, &s->dramcom_iomem);
712
+
713
+ /* DRAMCTL registers, index 1 */
714
+ memory_region_init_io(&s->dramctl_iomem, OBJECT(s),
715
+ &allwinner_r40_dramctl_ops, s,
716
+ "DRAMCTL", 4 * KiB);
717
+ sysbus_init_mmio(sbd, &s->dramctl_iomem);
718
+
719
+ /* DRAMPHY registers. index 2 */
720
+ memory_region_init_io(&s->dramphy_iomem, OBJECT(s),
721
+ &allwinner_r40_dramphy_ops, s,
722
+ "DRAMPHY", 4 * KiB);
723
+ sysbus_init_mmio(sbd, &s->dramphy_iomem);
724
+
725
+ /* R40 support max 2G memory but we only support up to 1G now. index 3 */
726
+ memory_region_init_io(&s->detect_cells, OBJECT(s),
727
+ &allwinner_r40_detect_ops, s,
728
+ "DRAMCELLS", 1 * GiB);
729
+ sysbus_init_mmio(sbd, &s->detect_cells);
730
+}
731
+
732
+static Property allwinner_r40_dramc_properties[] = {
733
+ DEFINE_PROP_UINT64("ram-addr", AwR40DramCtlState, ram_addr, 0x0),
734
+ DEFINE_PROP_UINT32("ram-size", AwR40DramCtlState, ram_size, 256), /* MiB */
735
+ DEFINE_PROP_END_OF_LIST()
736
+};
737
+
738
+static const VMStateDescription allwinner_r40_dramc_vmstate = {
739
+ .name = "allwinner-r40-dramc",
740
+ .version_id = 1,
741
+ .minimum_version_id = 1,
742
+ .fields = (VMStateField[]) {
743
+ VMSTATE_UINT32_ARRAY(dramcom, AwR40DramCtlState,
744
+ AW_R40_DRAMCOM_REGS_NUM),
745
+ VMSTATE_UINT32_ARRAY(dramctl, AwR40DramCtlState,
746
+ AW_R40_DRAMCTL_REGS_NUM),
747
+ VMSTATE_UINT32_ARRAY(dramphy, AwR40DramCtlState,
748
+ AW_R40_DRAMPHY_REGS_NUM),
749
+ VMSTATE_END_OF_LIST()
750
+ }
751
+};
752
+
753
+static void allwinner_r40_dramc_class_init(ObjectClass *klass, void *data)
754
+{
755
+ DeviceClass *dc = DEVICE_CLASS(klass);
756
+
757
+ dc->reset = allwinner_r40_dramc_reset;
758
+ dc->vmsd = &allwinner_r40_dramc_vmstate;
759
+ dc->realize = allwinner_r40_dramc_realize;
760
+ device_class_set_props(dc, allwinner_r40_dramc_properties);
761
+}
762
+
763
+static const TypeInfo allwinner_r40_dramc_info = {
764
+ .name = TYPE_AW_R40_DRAMC,
765
+ .parent = TYPE_SYS_BUS_DEVICE,
766
+ .instance_init = allwinner_r40_dramc_init,
767
+ .instance_size = sizeof(AwR40DramCtlState),
768
+ .class_init = allwinner_r40_dramc_class_init,
769
+};
770
+
771
+static void allwinner_r40_dramc_register(void)
772
+{
773
+ type_register_static(&allwinner_r40_dramc_info);
774
+}
775
+
776
+type_init(allwinner_r40_dramc_register)
777
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
778
index XXXXXXX..XXXXXXX 100644
779
--- a/hw/misc/meson.build
780
+++ b/hw/misc/meson.build
781
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3-dramc.c
782
softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3-sysctrl.c'))
783
softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-sid.c'))
784
softmmu_ss.add(when: 'CONFIG_ALLWINNER_R40', if_true: files('allwinner-r40-ccu.c'))
785
+softmmu_ss.add(when: 'CONFIG_ALLWINNER_R40', if_true: files('allwinner-r40-dramc.c'))
786
softmmu_ss.add(when: 'CONFIG_AXP2XX_PMU', if_true: files('axp2xx.c'))
787
softmmu_ss.add(when: 'CONFIG_REALVIEW', if_true: files('arm_sysctl.c'))
788
softmmu_ss.add(when: 'CONFIG_NSERIES', if_true: files('cbus.c'))
789
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
790
index XXXXXXX..XXXXXXX 100644
791
--- a/hw/misc/trace-events
792
+++ b/hw/misc/trace-events
793
@@ -XXX,XX +XXX,XX @@ allwinner_h3_dramctl_write(uint64_t offset, uint64_t data, unsigned size) "Write
794
allwinner_h3_dramphy_read(uint64_t offset, uint64_t data, unsigned size) "Read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
795
allwinner_h3_dramphy_write(uint64_t offset, uint64_t data, unsigned size) "write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
796
797
+# allwinner-r40-dramc.c
798
+allwinner_r40_dramc_detect_cells_disable(void) "Disable detect cells"
799
+allwinner_r40_dramc_detect_cells_enable(void) "Enable detect cells"
800
+allwinner_r40_dramc_map_rows(uint8_t row_bits, uint8_t bank_bits, uint8_t col_bits) "DRAM layout: row_bits %d, bank_bits %d, col_bits %d"
801
+allwinner_r40_dramc_offset_to_cell(uint64_t offset, int row, int bank, int col) "offset 0x%" PRIx64 " row %d bank %d col %d"
802
+allwinner_r40_dramc_detect_cell_write(uint64_t offset, uint64_t data) "offset 0x%" PRIx64 " data 0x%" PRIx64 ""
803
+allwinner_r40_dramc_detect_cell_read(uint64_t offset, uint64_t data) "offset 0x%" PRIx64 " data 0x%" PRIx64 ""
804
+allwinner_r40_dramcom_read(uint64_t offset, uint64_t data, unsigned size) "Read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
805
+allwinner_r40_dramcom_write(uint64_t offset, uint64_t data, unsigned size) "Write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
806
+allwinner_r40_dramctl_read(uint64_t offset, uint64_t data, unsigned size) "Read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
807
+allwinner_r40_dramctl_write(uint64_t offset, uint64_t data, unsigned size) "Write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
808
+allwinner_r40_dramphy_read(uint64_t offset, uint64_t data, unsigned size) "Read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
809
+allwinner_r40_dramphy_write(uint64_t offset, uint64_t data, unsigned size) "write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
810
+
811
# allwinner-sid.c
812
allwinner_sid_read(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
813
allwinner_sid_write(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
814
--
815
2.34.1
diff view generated by jsdifflib
1
From: Leif Lindholm <leif@nuviainc.com>
1
From: qianfan Zhao <qianfanguijin@163.com>
2
2
3
SBSS -> SSBS
3
A64's sd register was similar to H3, and it introduced a new register
4
4
named SAMP_DL_REG location at 0x144. The dma descriptor buffer size of
5
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
5
mmc2 is only 8K and the other mmc controllers has 64K.
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Also fix allwinner-r40's mmc controller type.
8
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
8
9
Message-id: 20210108185154.8108-2-leif@nuviainc.com
9
Signed-off-by: qianfan Zhao <qianfanguijin@163.com>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
11
---
12
target/arm/cpu.h | 2 +-
12
include/hw/sd/allwinner-sdhost.h | 9 ++++
13
1 file changed, 1 insertion(+), 1 deletion(-)
13
hw/arm/allwinner-r40.c | 2 +-
14
14
hw/sd/allwinner-sdhost.c | 72 ++++++++++++++++++++++++++++++--
15
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
15
3 files changed, 79 insertions(+), 4 deletions(-)
16
17
diff --git a/include/hw/sd/allwinner-sdhost.h b/include/hw/sd/allwinner-sdhost.h
16
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/cpu.h
19
--- a/include/hw/sd/allwinner-sdhost.h
18
+++ b/target/arm/cpu.h
20
+++ b/include/hw/sd/allwinner-sdhost.h
19
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64PFR0, RAS, 28, 4)
21
@@ -XXX,XX +XXX,XX @@
20
FIELD(ID_AA64PFR0, SVE, 32, 4)
22
/** Allwinner sun5i family and newer (A13, H2+, H3, etc) */
21
23
#define TYPE_AW_SDHOST_SUN5I TYPE_AW_SDHOST "-sun5i"
22
FIELD(ID_AA64PFR1, BT, 0, 4)
24
23
-FIELD(ID_AA64PFR1, SBSS, 4, 4)
25
+/** Allwinner sun50i-a64 */
24
+FIELD(ID_AA64PFR1, SSBS, 4, 4)
26
+#define TYPE_AW_SDHOST_SUN50I_A64 TYPE_AW_SDHOST "-sun50i-a64"
25
FIELD(ID_AA64PFR1, MTE, 8, 4)
27
+
26
FIELD(ID_AA64PFR1, RAS_FRAC, 12, 4)
28
+/** Allwinner sun50i-a64 emmc */
29
+#define TYPE_AW_SDHOST_SUN50I_A64_EMMC TYPE_AW_SDHOST "-sun50i-a64-emmc"
30
+
31
/** @} */
32
33
/**
34
@@ -XXX,XX +XXX,XX @@ struct AwSdHostState {
35
uint32_t startbit_detect; /**< eMMC DDR Start Bit Detection Control */
36
uint32_t response_crc; /**< Response CRC */
37
uint32_t data_crc[8]; /**< Data CRC */
38
+ uint32_t sample_delay; /**< Sample delay control */
39
uint32_t status_crc; /**< Status CRC */
40
41
/** @} */
42
@@ -XXX,XX +XXX,XX @@ struct AwSdHostClass {
43
size_t max_desc_size;
44
bool is_sun4i;
45
46
+ /** does the IP block support autocalibration? */
47
+ bool can_calibrate;
48
};
49
50
#endif /* HW_SD_ALLWINNER_SDHOST_H */
51
diff --git a/hw/arm/allwinner-r40.c b/hw/arm/allwinner-r40.c
52
index XXXXXXX..XXXXXXX 100644
53
--- a/hw/arm/allwinner-r40.c
54
+++ b/hw/arm/allwinner-r40.c
55
@@ -XXX,XX +XXX,XX @@ static void allwinner_r40_init(Object *obj)
56
57
for (int i = 0; i < AW_R40_NUM_MMCS; i++) {
58
object_initialize_child(obj, mmc_names[i], &s->mmc[i],
59
- TYPE_AW_SDHOST_SUN5I);
60
+ TYPE_AW_SDHOST_SUN50I_A64);
61
}
62
63
object_initialize_child(obj, "twi0", &s->i2c0, TYPE_AW_I2C_SUN6I);
64
diff --git a/hw/sd/allwinner-sdhost.c b/hw/sd/allwinner-sdhost.c
65
index XXXXXXX..XXXXXXX 100644
66
--- a/hw/sd/allwinner-sdhost.c
67
+++ b/hw/sd/allwinner-sdhost.c
68
@@ -XXX,XX +XXX,XX @@ enum {
69
REG_SD_DATA1_CRC = 0x12C, /* CRC Data 1 from card/eMMC */
70
REG_SD_DATA0_CRC = 0x130, /* CRC Data 0 from card/eMMC */
71
REG_SD_CRC_STA = 0x134, /* CRC status from card/eMMC during write */
72
+ REG_SD_SAMP_DL = 0x144, /* Sample Delay Control (sun50i-a64) */
73
REG_SD_FIFO = 0x200, /* Read/Write FIFO */
74
};
75
76
@@ -XXX,XX +XXX,XX @@ enum {
77
REG_SD_RES_CRC_RST = 0x0,
78
REG_SD_DATA_CRC_RST = 0x0,
79
REG_SD_CRC_STA_RST = 0x0,
80
+ REG_SD_SAMPLE_DL_RST = 0x00002000,
81
REG_SD_FIFO_RST = 0x0,
82
};
83
84
@@ -XXX,XX +XXX,XX @@ static uint64_t allwinner_sdhost_read(void *opaque, hwaddr offset,
85
{
86
AwSdHostState *s = AW_SDHOST(opaque);
87
AwSdHostClass *sc = AW_SDHOST_GET_CLASS(s);
88
+ bool out_of_bounds = false;
89
uint32_t res = 0;
90
91
switch (offset) {
92
@@ -XXX,XX +XXX,XX @@ static uint64_t allwinner_sdhost_read(void *opaque, hwaddr offset,
93
case REG_SD_FIFO: /* Read/Write FIFO */
94
res = allwinner_sdhost_fifo_read(s);
95
break;
96
+ case REG_SD_SAMP_DL: /* Sample Delay */
97
+ if (sc->can_calibrate) {
98
+ res = s->sample_delay;
99
+ } else {
100
+ out_of_bounds = true;
101
+ }
102
+ break;
103
default:
104
- qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset %"
105
- HWADDR_PRIx"\n", __func__, offset);
106
+ out_of_bounds = true;
107
res = 0;
108
break;
109
}
110
111
+ if (out_of_bounds) {
112
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset %"
113
+ HWADDR_PRIx"\n", __func__, offset);
114
+ }
115
+
116
trace_allwinner_sdhost_read(offset, res, size);
117
return res;
118
}
119
@@ -XXX,XX +XXX,XX @@ static void allwinner_sdhost_write(void *opaque, hwaddr offset,
120
{
121
AwSdHostState *s = AW_SDHOST(opaque);
122
AwSdHostClass *sc = AW_SDHOST_GET_CLASS(s);
123
+ bool out_of_bounds = false;
124
125
trace_allwinner_sdhost_write(offset, value, size);
126
127
@@ -XXX,XX +XXX,XX @@ static void allwinner_sdhost_write(void *opaque, hwaddr offset,
128
case REG_SD_DATA0_CRC: /* CRC Data 0 from card/eMMC */
129
case REG_SD_CRC_STA: /* CRC status from card/eMMC in write operation */
130
break;
131
+ case REG_SD_SAMP_DL: /* Sample delay control */
132
+ if (sc->can_calibrate) {
133
+ s->sample_delay = value;
134
+ } else {
135
+ out_of_bounds = true;
136
+ }
137
+ break;
138
default:
139
+ out_of_bounds = true;
140
+ break;
141
+ }
142
+
143
+ if (out_of_bounds) {
144
qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset %"
145
HWADDR_PRIx"\n", __func__, offset);
146
- break;
147
}
148
}
149
150
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_allwinner_sdhost = {
151
VMSTATE_UINT32(response_crc, AwSdHostState),
152
VMSTATE_UINT32_ARRAY(data_crc, AwSdHostState, 8),
153
VMSTATE_UINT32(status_crc, AwSdHostState),
154
+ VMSTATE_UINT32(sample_delay, AwSdHostState),
155
VMSTATE_END_OF_LIST()
156
}
157
};
158
@@ -XXX,XX +XXX,XX @@ static void allwinner_sdhost_realize(DeviceState *dev, Error **errp)
159
static void allwinner_sdhost_reset(DeviceState *dev)
160
{
161
AwSdHostState *s = AW_SDHOST(dev);
162
+ AwSdHostClass *sc = AW_SDHOST_GET_CLASS(s);
163
164
s->global_ctl = REG_SD_GCTL_RST;
165
s->clock_ctl = REG_SD_CKCR_RST;
166
@@ -XXX,XX +XXX,XX @@ static void allwinner_sdhost_reset(DeviceState *dev)
167
}
168
169
s->status_crc = REG_SD_CRC_STA_RST;
170
+
171
+ if (sc->can_calibrate) {
172
+ s->sample_delay = REG_SD_SAMPLE_DL_RST;
173
+ }
174
}
175
176
static void allwinner_sdhost_bus_class_init(ObjectClass *klass, void *data)
177
@@ -XXX,XX +XXX,XX @@ static void allwinner_sdhost_sun4i_class_init(ObjectClass *klass, void *data)
178
AwSdHostClass *sc = AW_SDHOST_CLASS(klass);
179
sc->max_desc_size = 8 * KiB;
180
sc->is_sun4i = true;
181
+ sc->can_calibrate = false;
182
}
183
184
static void allwinner_sdhost_sun5i_class_init(ObjectClass *klass, void *data)
185
@@ -XXX,XX +XXX,XX @@ static void allwinner_sdhost_sun5i_class_init(ObjectClass *klass, void *data)
186
AwSdHostClass *sc = AW_SDHOST_CLASS(klass);
187
sc->max_desc_size = 64 * KiB;
188
sc->is_sun4i = false;
189
+ sc->can_calibrate = false;
190
+}
191
+
192
+static void allwinner_sdhost_sun50i_a64_class_init(ObjectClass *klass,
193
+ void *data)
194
+{
195
+ AwSdHostClass *sc = AW_SDHOST_CLASS(klass);
196
+ sc->max_desc_size = 64 * KiB;
197
+ sc->is_sun4i = false;
198
+ sc->can_calibrate = true;
199
+}
200
+
201
+static void allwinner_sdhost_sun50i_a64_emmc_class_init(ObjectClass *klass,
202
+ void *data)
203
+{
204
+ AwSdHostClass *sc = AW_SDHOST_CLASS(klass);
205
+ sc->max_desc_size = 8 * KiB;
206
+ sc->is_sun4i = false;
207
+ sc->can_calibrate = true;
208
}
209
210
static const TypeInfo allwinner_sdhost_info = {
211
@@ -XXX,XX +XXX,XX @@ static const TypeInfo allwinner_sdhost_sun5i_info = {
212
.class_init = allwinner_sdhost_sun5i_class_init,
213
};
214
215
+static const TypeInfo allwinner_sdhost_sun50i_a64_info = {
216
+ .name = TYPE_AW_SDHOST_SUN50I_A64,
217
+ .parent = TYPE_AW_SDHOST,
218
+ .class_init = allwinner_sdhost_sun50i_a64_class_init,
219
+};
220
+
221
+static const TypeInfo allwinner_sdhost_sun50i_a64_emmc_info = {
222
+ .name = TYPE_AW_SDHOST_SUN50I_A64_EMMC,
223
+ .parent = TYPE_AW_SDHOST,
224
+ .class_init = allwinner_sdhost_sun50i_a64_emmc_class_init,
225
+};
226
+
227
static const TypeInfo allwinner_sdhost_bus_info = {
228
.name = TYPE_AW_SDHOST_BUS,
229
.parent = TYPE_SD_BUS,
230
@@ -XXX,XX +XXX,XX @@ static void allwinner_sdhost_register_types(void)
231
type_register_static(&allwinner_sdhost_info);
232
type_register_static(&allwinner_sdhost_sun4i_info);
233
type_register_static(&allwinner_sdhost_sun5i_info);
234
+ type_register_static(&allwinner_sdhost_sun50i_a64_info);
235
+ type_register_static(&allwinner_sdhost_sun50i_a64_emmc_info);
236
type_register_static(&allwinner_sdhost_bus_info);
237
}
27
238
28
--
239
--
29
2.20.1
240
2.34.1
30
31
diff view generated by jsdifflib
New patch
1
From: qianfan Zhao <qianfanguijin@163.com>
1
2
3
R40 has two ethernet controllers named as emac and gmac. The emac is
4
compatibled with A10, and the GMAC is compatibled with H3.
5
6
Signed-off-by: qianfan Zhao <qianfanguijin@163.com>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
---
9
include/hw/arm/allwinner-r40.h | 6 ++++
10
hw/arm/allwinner-r40.c | 50 ++++++++++++++++++++++++++++++++--
11
hw/arm/bananapi_m2u.c | 3 ++
12
3 files changed, 57 insertions(+), 2 deletions(-)
13
14
diff --git a/include/hw/arm/allwinner-r40.h b/include/hw/arm/allwinner-r40.h
15
index XXXXXXX..XXXXXXX 100644
16
--- a/include/hw/arm/allwinner-r40.h
17
+++ b/include/hw/arm/allwinner-r40.h
18
@@ -XXX,XX +XXX,XX @@
19
#include "hw/misc/allwinner-r40-ccu.h"
20
#include "hw/misc/allwinner-r40-dramc.h"
21
#include "hw/i2c/allwinner-i2c.h"
22
+#include "hw/net/allwinner_emac.h"
23
+#include "hw/net/allwinner-sun8i-emac.h"
24
#include "target/arm/cpu.h"
25
#include "sysemu/block-backend.h"
26
27
@@ -XXX,XX +XXX,XX @@ enum {
28
AW_R40_DEV_SRAM_A2,
29
AW_R40_DEV_SRAM_A3,
30
AW_R40_DEV_SRAM_A4,
31
+ AW_R40_DEV_EMAC,
32
AW_R40_DEV_MMC0,
33
AW_R40_DEV_MMC1,
34
AW_R40_DEV_MMC2,
35
@@ -XXX,XX +XXX,XX @@ enum {
36
AW_R40_DEV_UART6,
37
AW_R40_DEV_UART7,
38
AW_R40_DEV_TWI0,
39
+ AW_R40_DEV_GMAC,
40
AW_R40_DEV_GIC_DIST,
41
AW_R40_DEV_GIC_CPU,
42
AW_R40_DEV_GIC_HYP,
43
@@ -XXX,XX +XXX,XX @@ struct AwR40State {
44
AwR40ClockCtlState ccu;
45
AwR40DramCtlState dramc;
46
AWI2CState i2c0;
47
+ AwEmacState emac;
48
+ AwSun8iEmacState gmac;
49
GICState gic;
50
MemoryRegion sram_a1;
51
MemoryRegion sram_a2;
52
diff --git a/hw/arm/allwinner-r40.c b/hw/arm/allwinner-r40.c
53
index XXXXXXX..XXXXXXX 100644
54
--- a/hw/arm/allwinner-r40.c
55
+++ b/hw/arm/allwinner-r40.c
56
@@ -XXX,XX +XXX,XX @@ const hwaddr allwinner_r40_memmap[] = {
57
[AW_R40_DEV_SRAM_A2] = 0x00004000,
58
[AW_R40_DEV_SRAM_A3] = 0x00008000,
59
[AW_R40_DEV_SRAM_A4] = 0x0000b400,
60
+ [AW_R40_DEV_EMAC] = 0x01c0b000,
61
[AW_R40_DEV_MMC0] = 0x01c0f000,
62
[AW_R40_DEV_MMC1] = 0x01c10000,
63
[AW_R40_DEV_MMC2] = 0x01c11000,
64
@@ -XXX,XX +XXX,XX @@ const hwaddr allwinner_r40_memmap[] = {
65
[AW_R40_DEV_UART6] = 0x01c29800,
66
[AW_R40_DEV_UART7] = 0x01c29c00,
67
[AW_R40_DEV_TWI0] = 0x01c2ac00,
68
+ [AW_R40_DEV_GMAC] = 0x01c50000,
69
[AW_R40_DEV_DRAMCOM] = 0x01c62000,
70
[AW_R40_DEV_DRAMCTL] = 0x01c63000,
71
[AW_R40_DEV_DRAMPHY] = 0x01c65000,
72
@@ -XXX,XX +XXX,XX @@ static struct AwR40Unimplemented r40_unimplemented[] = {
73
{ "spi1", 0x01c06000, 4 * KiB },
74
{ "cs0", 0x01c09000, 4 * KiB },
75
{ "keymem", 0x01c0a000, 4 * KiB },
76
- { "emac", 0x01c0b000, 4 * KiB },
77
{ "usb0-otg", 0x01c13000, 4 * KiB },
78
{ "usb0-host", 0x01c14000, 4 * KiB },
79
{ "crypto", 0x01c15000, 4 * KiB },
80
@@ -XXX,XX +XXX,XX @@ static struct AwR40Unimplemented r40_unimplemented[] = {
81
{ "tvd2", 0x01c33000, 4 * KiB },
82
{ "tvd3", 0x01c34000, 4 * KiB },
83
{ "gpu", 0x01c40000, 64 * KiB },
84
- { "gmac", 0x01c50000, 64 * KiB },
85
{ "hstmr", 0x01c60000, 4 * KiB },
86
{ "tcon-top", 0x01c70000, 4 * KiB },
87
{ "lcd0", 0x01c71000, 4 * KiB },
88
@@ -XXX,XX +XXX,XX @@ enum {
89
AW_R40_GIC_SPI_MMC1 = 33,
90
AW_R40_GIC_SPI_MMC2 = 34,
91
AW_R40_GIC_SPI_MMC3 = 35,
92
+ AW_R40_GIC_SPI_EMAC = 55,
93
+ AW_R40_GIC_SPI_GMAC = 85,
94
};
95
96
/* Allwinner R40 general constants */
97
@@ -XXX,XX +XXX,XX @@ static void allwinner_r40_init(Object *obj)
98
99
object_initialize_child(obj, "twi0", &s->i2c0, TYPE_AW_I2C_SUN6I);
100
101
+ object_initialize_child(obj, "emac", &s->emac, TYPE_AW_EMAC);
102
+ object_initialize_child(obj, "gmac", &s->gmac, TYPE_AW_SUN8I_EMAC);
103
+ object_property_add_alias(obj, "gmac-phy-addr",
104
+ OBJECT(&s->gmac), "phy-addr");
105
+
106
object_initialize_child(obj, "dramc", &s->dramc, TYPE_AW_R40_DRAMC);
107
object_property_add_alias(obj, "ram-addr", OBJECT(&s->dramc),
108
"ram-addr");
109
@@ -XXX,XX +XXX,XX @@ static void allwinner_r40_init(Object *obj)
110
111
static void allwinner_r40_realize(DeviceState *dev, Error **errp)
112
{
113
+ const char *r40_nic_models[] = { "gmac", "emac", NULL };
114
AwR40State *s = AW_R40(dev);
115
unsigned i;
116
117
@@ -XXX,XX +XXX,XX @@ static void allwinner_r40_realize(DeviceState *dev, Error **errp)
118
sysbus_mmio_map(SYS_BUS_DEVICE(&s->dramc), 2,
119
s->memmap[AW_R40_DEV_DRAMPHY]);
120
121
+ /* nic support gmac and emac */
122
+ for (int i = 0; i < ARRAY_SIZE(r40_nic_models) - 1; i++) {
123
+ NICInfo *nic = &nd_table[i];
124
+
125
+ if (!nic->used) {
126
+ continue;
127
+ }
128
+ if (qemu_show_nic_models(nic->model, r40_nic_models)) {
129
+ exit(0);
130
+ }
131
+
132
+ switch (qemu_find_nic_model(nic, r40_nic_models, r40_nic_models[0])) {
133
+ case 0: /* gmac */
134
+ qdev_set_nic_properties(DEVICE(&s->gmac), nic);
135
+ break;
136
+ case 1: /* emac */
137
+ qdev_set_nic_properties(DEVICE(&s->emac), nic);
138
+ break;
139
+ default:
140
+ exit(1);
141
+ break;
142
+ }
143
+ }
144
+
145
+ /* GMAC */
146
+ object_property_set_link(OBJECT(&s->gmac), "dma-memory",
147
+ OBJECT(get_system_memory()), &error_fatal);
148
+ sysbus_realize(SYS_BUS_DEVICE(&s->gmac), &error_fatal);
149
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->gmac), 0, s->memmap[AW_R40_DEV_GMAC]);
150
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gmac), 0,
151
+ qdev_get_gpio_in(DEVICE(&s->gic), AW_R40_GIC_SPI_GMAC));
152
+
153
+ /* EMAC */
154
+ sysbus_realize(SYS_BUS_DEVICE(&s->emac), &error_fatal);
155
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->emac), 0, s->memmap[AW_R40_DEV_EMAC]);
156
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->emac), 0,
157
+ qdev_get_gpio_in(DEVICE(&s->gic), AW_R40_GIC_SPI_EMAC));
158
+
159
/* Unimplemented devices */
160
for (i = 0; i < ARRAY_SIZE(r40_unimplemented); i++) {
161
create_unimplemented_device(r40_unimplemented[i].device_name,
162
diff --git a/hw/arm/bananapi_m2u.c b/hw/arm/bananapi_m2u.c
163
index XXXXXXX..XXXXXXX 100644
164
--- a/hw/arm/bananapi_m2u.c
165
+++ b/hw/arm/bananapi_m2u.c
166
@@ -XXX,XX +XXX,XX @@ static void bpim2u_init(MachineState *machine)
167
object_property_set_int(OBJECT(r40), "ram-size",
168
r40->ram_size, &error_abort);
169
170
+ /* GMAC PHY */
171
+ object_property_set_uint(OBJECT(r40), "gmac-phy-addr", 1, &error_abort);
172
+
173
/* Mark R40 object realized */
174
qdev_realize(DEVICE(r40), NULL, &error_abort);
175
176
--
177
2.34.1
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
From: qianfan Zhao <qianfanguijin@163.com>
2
2
3
The PWM module is part of NPCM7XX module. Each NPCM7XX module has two
3
Only a few important registers are added, especially the SRAM_VER
4
identical PWM modules. Each module contains 4 PWM entries. Each PWM has
4
register.
5
two outputs: frequency and duty_cycle. Both are computed using inputs
6
from software side.
7
5
8
This module does not model detail pulse signals since it is expensive.
6
Signed-off-by: qianfan Zhao <qianfanguijin@163.com>
9
It also does not model interrupts and watchdogs that are dependant on
7
Reviewed-by: Niek Linnenbank <nieklinnenbank@gmail.com>
10
the detail models. The interfaces for these are left in the module so
11
that anyone in need for these functionalities can implement on their
12
own.
13
14
The user can read the duty cycle and frequency using qom-get command.
15
16
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
17
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
18
Signed-off-by: Hao Wu <wuhaotsh@google.com>
19
Message-id: 20210108190945.949196-5-wuhaotsh@google.com
20
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
22
---
9
---
23
docs/system/arm/nuvoton.rst | 2 +-
10
include/hw/arm/allwinner-r40.h | 3 +
24
include/hw/arm/npcm7xx.h | 2 +
11
include/hw/misc/allwinner-sramc.h | 69 +++++++++++
25
include/hw/misc/npcm7xx_pwm.h | 105 +++++++
12
hw/arm/allwinner-r40.c | 7 +-
26
hw/arm/npcm7xx.c | 26 +-
13
hw/misc/allwinner-sramc.c | 184 ++++++++++++++++++++++++++++++
27
hw/misc/npcm7xx_pwm.c | 550 ++++++++++++++++++++++++++++++++++
14
hw/arm/Kconfig | 1 +
28
hw/misc/meson.build | 1 +
15
hw/misc/Kconfig | 3 +
29
hw/misc/trace-events | 6 +
16
hw/misc/meson.build | 1 +
30
7 files changed, 689 insertions(+), 3 deletions(-)
17
hw/misc/trace-events | 4 +
31
create mode 100644 include/hw/misc/npcm7xx_pwm.h
18
8 files changed, 271 insertions(+), 1 deletion(-)
32
create mode 100644 hw/misc/npcm7xx_pwm.c
19
create mode 100644 include/hw/misc/allwinner-sramc.h
20
create mode 100644 hw/misc/allwinner-sramc.c
33
21
34
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
22
diff --git a/include/hw/arm/allwinner-r40.h b/include/hw/arm/allwinner-r40.h
35
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
36
--- a/docs/system/arm/nuvoton.rst
24
--- a/include/hw/arm/allwinner-r40.h
37
+++ b/docs/system/arm/nuvoton.rst
25
+++ b/include/hw/arm/allwinner-r40.h
38
@@ -XXX,XX +XXX,XX @@ Supported devices
39
* USB host (USBH)
40
* GPIO controller
41
* Analog to Digital Converter (ADC)
42
+ * Pulse Width Modulation (PWM)
43
44
Missing devices
45
---------------
46
@@ -XXX,XX +XXX,XX @@ Missing devices
47
* Peripheral SPI controller (PSPI)
48
* SD/MMC host
49
* PECI interface
50
- * Pulse Width Modulation (PWM)
51
* Tachometer
52
* PCI and PCIe root complex and bridges
53
* VDM and MCTP support
54
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
55
index XXXXXXX..XXXXXXX 100644
56
--- a/include/hw/arm/npcm7xx.h
57
+++ b/include/hw/arm/npcm7xx.h
58
@@ -XXX,XX +XXX,XX @@
26
@@ -XXX,XX +XXX,XX @@
59
#include "hw/mem/npcm7xx_mc.h"
27
#include "hw/sd/allwinner-sdhost.h"
60
#include "hw/misc/npcm7xx_clk.h"
28
#include "hw/misc/allwinner-r40-ccu.h"
61
#include "hw/misc/npcm7xx_gcr.h"
29
#include "hw/misc/allwinner-r40-dramc.h"
62
+#include "hw/misc/npcm7xx_pwm.h"
30
+#include "hw/misc/allwinner-sramc.h"
63
#include "hw/misc/npcm7xx_rng.h"
31
#include "hw/i2c/allwinner-i2c.h"
64
#include "hw/nvram/npcm7xx_otp.h"
32
#include "hw/net/allwinner_emac.h"
65
#include "hw/timer/npcm7xx_timer.h"
33
#include "hw/net/allwinner-sun8i-emac.h"
66
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
34
@@ -XXX,XX +XXX,XX @@ enum {
67
NPCM7xxCLKState clk;
35
AW_R40_DEV_SRAM_A2,
68
NPCM7xxTimerCtrlState tim[3];
36
AW_R40_DEV_SRAM_A3,
69
NPCM7xxADCState adc;
37
AW_R40_DEV_SRAM_A4,
70
+ NPCM7xxPWMState pwm[2];
38
+ AW_R40_DEV_SRAMC,
71
NPCM7xxOTPState key_storage;
39
AW_R40_DEV_EMAC,
72
NPCM7xxOTPState fuse_array;
40
AW_R40_DEV_MMC0,
73
NPCM7xxMCState mc;
41
AW_R40_DEV_MMC1,
74
diff --git a/include/hw/misc/npcm7xx_pwm.h b/include/hw/misc/npcm7xx_pwm.h
42
@@ -XXX,XX +XXX,XX @@ struct AwR40State {
43
44
ARMCPU cpus[AW_R40_NUM_CPUS];
45
const hwaddr *memmap;
46
+ AwSRAMCState sramc;
47
AwA10PITState timer;
48
AwSdHostState mmc[AW_R40_NUM_MMCS];
49
AwR40ClockCtlState ccu;
50
diff --git a/include/hw/misc/allwinner-sramc.h b/include/hw/misc/allwinner-sramc.h
75
new file mode 100644
51
new file mode 100644
76
index XXXXXXX..XXXXXXX
52
index XXXXXXX..XXXXXXX
77
--- /dev/null
53
--- /dev/null
78
+++ b/include/hw/misc/npcm7xx_pwm.h
54
+++ b/include/hw/misc/allwinner-sramc.h
79
@@ -XXX,XX +XXX,XX @@
55
@@ -XXX,XX +XXX,XX @@
80
+/*
56
+/*
81
+ * Nuvoton NPCM7xx PWM Module
57
+ * Allwinner SRAM controller emulation
82
+ *
58
+ *
83
+ * Copyright 2020 Google LLC
59
+ * Copyright (C) 2023 qianfan Zhao <qianfanguijin@163.com>
84
+ *
60
+ *
85
+ * This program is free software; you can redistribute it and/or modify it
61
+ * This program is free software: you can redistribute it and/or modify
86
+ * under the terms of the GNU General Public License as published by the
62
+ * it under the terms of the GNU General Public License as published by
87
+ * Free Software Foundation; either version 2 of the License, or
63
+ * the Free Software Foundation, either version 2 of the License, or
88
+ * (at your option) any later version.
64
+ * (at your option) any later version.
89
+ *
65
+ *
90
+ * This program is distributed in the hope that it will be useful, but WITHOUT
66
+ * This program is distributed in the hope that it will be useful,
91
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
67
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
92
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
68
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
93
+ * for more details.
69
+ * GNU General Public License for more details.
94
+ */
70
+ *
95
+#ifndef NPCM7XX_PWM_H
71
+ * You should have received a copy of the GNU General Public License
96
+#define NPCM7XX_PWM_H
72
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
97
+
73
+ */
98
+#include "hw/clock.h"
74
+
75
+#ifndef HW_MISC_ALLWINNER_SRAMC_H
76
+#define HW_MISC_ALLWINNER_SRAMC_H
77
+
78
+#include "qom/object.h"
99
+#include "hw/sysbus.h"
79
+#include "hw/sysbus.h"
100
+#include "hw/irq.h"
80
+#include "qemu/uuid.h"
101
+
102
+/* Each PWM module holds 4 PWM channels. */
103
+#define NPCM7XX_PWM_PER_MODULE 4
104
+
105
+/*
106
+ * Number of registers in one pwm module. Don't change this without increasing
107
+ * the version_id in vmstate.
108
+ */
109
+#define NPCM7XX_PWM_NR_REGS (0x54 / sizeof(uint32_t))
110
+
111
+/*
112
+ * The maximum duty values. Each duty unit represents 1/NPCM7XX_PWM_MAX_DUTY
113
+ * cycles. For example, if NPCM7XX_PWM_MAX_DUTY=1,000,000 and a PWM has a duty
114
+ * value of 100,000 the duty cycle for that PWM is 10%.
115
+ */
116
+#define NPCM7XX_PWM_MAX_DUTY 1000000
117
+
118
+typedef struct NPCM7xxPWMState NPCM7xxPWMState;
119
+
81
+
120
+/**
82
+/**
121
+ * struct NPCM7xxPWM - The state of a single PWM channel.
83
+ * Object model
122
+ * @module: The PWM module that contains this channel.
84
+ * @{
123
+ * @irq: GIC interrupt line to fire on expiration if enabled.
85
+ */
124
+ * @running: Whether this PWM channel is generating output.
86
+#define TYPE_AW_SRAMC "allwinner-sramc"
125
+ * @inverted: Whether this PWM channel is inverted.
87
+#define TYPE_AW_SRAMC_SUN8I_R40 TYPE_AW_SRAMC "-sun8i-r40"
126
+ * @index: The index of this PWM channel.
88
+OBJECT_DECLARE_TYPE(AwSRAMCState, AwSRAMCClass, AW_SRAMC)
127
+ * @cnr: The counter register.
89
+
128
+ * @cmr: The comparator register.
90
+/** @} */
129
+ * @pdr: The data register.
130
+ * @pwdr: The watchdog register.
131
+ * @freq: The frequency of this PWM channel.
132
+ * @duty: The duty cycle of this PWM channel. One unit represents
133
+ * 1/NPCM7XX_MAX_DUTY cycles.
134
+ */
135
+typedef struct NPCM7xxPWM {
136
+ NPCM7xxPWMState *module;
137
+
138
+ qemu_irq irq;
139
+
140
+ bool running;
141
+ bool inverted;
142
+
143
+ uint8_t index;
144
+ uint32_t cnr;
145
+ uint32_t cmr;
146
+ uint32_t pdr;
147
+ uint32_t pwdr;
148
+
149
+ uint32_t freq;
150
+ uint32_t duty;
151
+} NPCM7xxPWM;
152
+
91
+
153
+/**
92
+/**
154
+ * struct NPCM7xxPWMState - Pulse Width Modulation device state.
93
+ * Allwinner SRAMC object instance state
155
+ * @parent: System bus device.
94
+ */
156
+ * @iomem: Memory region through which registers are accessed.
95
+struct AwSRAMCState {
157
+ * @clock: The PWM clock.
96
+ /*< private >*/
158
+ * @pwm: The PWM channels owned by this module.
97
+ SysBusDevice parent_obj;
159
+ * @ppr: The prescaler register.
98
+ /*< public >*/
160
+ * @csr: The clock selector register.
99
+
161
+ * @pcr: The control register.
100
+ /** Maps I/O registers in physical memory */
162
+ * @pier: The interrupt enable register.
163
+ * @piir: The interrupt indication register.
164
+ */
165
+struct NPCM7xxPWMState {
166
+ SysBusDevice parent;
167
+
168
+ MemoryRegion iomem;
101
+ MemoryRegion iomem;
169
+
102
+
170
+ Clock *clock;
103
+ /* registers */
171
+ NPCM7xxPWM pwm[NPCM7XX_PWM_PER_MODULE];
104
+ uint32_t sram_ctl1;
172
+
105
+ uint32_t sram_ver;
173
+ uint32_t ppr;
106
+ uint32_t sram_soft_entry_reg0;
174
+ uint32_t csr;
107
+};
175
+ uint32_t pcr;
108
+
176
+ uint32_t pier;
109
+/**
177
+ uint32_t piir;
110
+ * Allwinner SRAM Controller class-level struct.
178
+};
111
+ *
179
+
112
+ * This struct is filled by each sunxi device specific code
180
+#define TYPE_NPCM7XX_PWM "npcm7xx-pwm"
113
+ * such that the generic code can use this struct to support
181
+#define NPCM7XX_PWM(obj) \
114
+ * all devices.
182
+ OBJECT_CHECK(NPCM7xxPWMState, (obj), TYPE_NPCM7XX_PWM)
115
+ */
183
+
116
+struct AwSRAMCClass {
184
+#endif /* NPCM7XX_PWM_H */
117
+ /*< private >*/
185
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
118
+ SysBusDeviceClass parent_class;
186
index XXXXXXX..XXXXXXX 100644
119
+ /*< public >*/
187
--- a/hw/arm/npcm7xx.c
120
+
188
+++ b/hw/arm/npcm7xx.c
121
+ uint32_t sram_version_code;
189
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxInterrupt {
122
+};
190
NPCM7XX_WDG2_IRQ, /* Timer Module 2 Watchdog */
123
+
191
NPCM7XX_EHCI_IRQ = 61,
124
+#endif /* HW_MISC_ALLWINNER_SRAMC_H */
192
NPCM7XX_OHCI_IRQ = 62,
125
diff --git a/hw/arm/allwinner-r40.c b/hw/arm/allwinner-r40.c
193
+ NPCM7XX_PWM0_IRQ = 93, /* PWM module 0 */
126
index XXXXXXX..XXXXXXX 100644
194
+ NPCM7XX_PWM1_IRQ, /* PWM module 1 */
127
--- a/hw/arm/allwinner-r40.c
195
NPCM7XX_GPIO0_IRQ = 116,
128
+++ b/hw/arm/allwinner-r40.c
196
NPCM7XX_GPIO1_IRQ,
129
@@ -XXX,XX +XXX,XX @@ const hwaddr allwinner_r40_memmap[] = {
197
NPCM7XX_GPIO2_IRQ,
130
[AW_R40_DEV_SRAM_A2] = 0x00004000,
198
@@ -XXX,XX +XXX,XX @@ static const hwaddr npcm7xx_fiu3_flash_addr[] = {
131
[AW_R40_DEV_SRAM_A3] = 0x00008000,
199
0xb8000000, /* CS3 */
132
[AW_R40_DEV_SRAM_A4] = 0x0000b400,
200
};
133
+ [AW_R40_DEV_SRAMC] = 0x01c00000,
201
134
[AW_R40_DEV_EMAC] = 0x01c0b000,
202
+/* Register base address for each PWM Module */
135
[AW_R40_DEV_MMC0] = 0x01c0f000,
203
+static const hwaddr npcm7xx_pwm_addr[] = {
136
[AW_R40_DEV_MMC1] = 0x01c10000,
204
+ 0xf0103000,
137
@@ -XXX,XX +XXX,XX @@ struct AwR40Unimplemented {
205
+ 0xf0104000,
138
static struct AwR40Unimplemented r40_unimplemented[] = {
206
+};
139
{ "d-engine", 0x01000000, 4 * MiB },
207
+
140
{ "d-inter", 0x01400000, 128 * KiB },
208
static const struct {
141
- { "sram-c", 0x01c00000, 4 * KiB },
209
hwaddr regs_addr;
142
{ "dma", 0x01c02000, 4 * KiB },
210
uint32_t unconnected_pins;
143
{ "nfdc", 0x01c03000, 4 * KiB },
211
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
144
{ "ts", 0x01c04000, 4 * KiB },
212
object_initialize_child(obj, npcm7xx_fiu[i].name, &s->fiu[i],
145
@@ -XXX,XX +XXX,XX @@ static void allwinner_r40_init(Object *obj)
213
TYPE_NPCM7XX_FIU);
146
"ram-addr");
214
}
147
object_property_add_alias(obj, "ram-size", OBJECT(&s->dramc),
215
+
148
"ram-size");
216
+ for (i = 0; i < ARRAY_SIZE(s->pwm); i++) {
149
+
217
+ object_initialize_child(obj, "pwm[*]", &s->pwm[i], TYPE_NPCM7XX_PWM);
150
+ object_initialize_child(obj, "sramc", &s->sramc, TYPE_AW_SRAMC_SUN8I_R40);
218
+ }
219
}
151
}
220
152
221
static void npcm7xx_realize(DeviceState *dev, Error **errp)
153
static void allwinner_r40_realize(DeviceState *dev, Error **errp)
222
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
154
@@ -XXX,XX +XXX,XX @@ static void allwinner_r40_realize(DeviceState *dev, Error **errp)
223
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ohci), 0,
155
AW_R40_GIC_SPI_TIMER1));
224
npcm7xx_irq(s, NPCM7XX_OHCI_IRQ));
156
225
157
/* SRAM */
226
+ /* PWM Modules. Cannot fail. */
158
+ sysbus_realize(SYS_BUS_DEVICE(&s->sramc), &error_fatal);
227
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_pwm_addr) != ARRAY_SIZE(s->pwm));
159
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->sramc), 0, s->memmap[AW_R40_DEV_SRAMC]);
228
+ for (i = 0; i < ARRAY_SIZE(s->pwm); i++) {
160
+
229
+ SysBusDevice *sbd = SYS_BUS_DEVICE(&s->pwm[i]);
161
memory_region_init_ram(&s->sram_a1, OBJECT(dev), "sram A1",
230
+
162
16 * KiB, &error_abort);
231
+ qdev_connect_clock_in(DEVICE(&s->pwm[i]), "clock", qdev_get_clock_out(
163
memory_region_init_ram(&s->sram_a2, OBJECT(dev), "sram A2",
232
+ DEVICE(&s->clk), "apb3-clock"));
164
diff --git a/hw/misc/allwinner-sramc.c b/hw/misc/allwinner-sramc.c
233
+ sysbus_realize(sbd, &error_abort);
234
+ sysbus_mmio_map(sbd, 0, npcm7xx_pwm_addr[i]);
235
+ sysbus_connect_irq(sbd, i, npcm7xx_irq(s, NPCM7XX_PWM0_IRQ + i));
236
+ }
237
+
238
/*
239
* Flash Interface Unit (FIU). Can fail if incorrect number of chip selects
240
* specified, but this is a programming error.
241
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
242
create_unimplemented_device("npcm7xx.peci", 0xf0100000, 4 * KiB);
243
create_unimplemented_device("npcm7xx.siox[1]", 0xf0101000, 4 * KiB);
244
create_unimplemented_device("npcm7xx.siox[2]", 0xf0102000, 4 * KiB);
245
- create_unimplemented_device("npcm7xx.pwm[0]", 0xf0103000, 4 * KiB);
246
- create_unimplemented_device("npcm7xx.pwm[1]", 0xf0104000, 4 * KiB);
247
create_unimplemented_device("npcm7xx.mft[0]", 0xf0180000, 4 * KiB);
248
create_unimplemented_device("npcm7xx.mft[1]", 0xf0181000, 4 * KiB);
249
create_unimplemented_device("npcm7xx.mft[2]", 0xf0182000, 4 * KiB);
250
diff --git a/hw/misc/npcm7xx_pwm.c b/hw/misc/npcm7xx_pwm.c
251
new file mode 100644
165
new file mode 100644
252
index XXXXXXX..XXXXXXX
166
index XXXXXXX..XXXXXXX
253
--- /dev/null
167
--- /dev/null
254
+++ b/hw/misc/npcm7xx_pwm.c
168
+++ b/hw/misc/allwinner-sramc.c
255
@@ -XXX,XX +XXX,XX @@
169
@@ -XXX,XX +XXX,XX @@
256
+/*
170
+/*
257
+ * Nuvoton NPCM7xx PWM Module
171
+ * Allwinner R40 SRAM controller emulation
258
+ *
172
+ *
259
+ * Copyright 2020 Google LLC
173
+ * Copyright (C) 2023 qianfan Zhao <qianfanguijin@163.com>
260
+ *
174
+ *
261
+ * This program is free software; you can redistribute it and/or modify it
175
+ * This program is free software: you can redistribute it and/or modify
262
+ * under the terms of the GNU General Public License as published by the
176
+ * it under the terms of the GNU General Public License as published by
263
+ * Free Software Foundation; either version 2 of the License, or
177
+ * the Free Software Foundation, either version 2 of the License, or
264
+ * (at your option) any later version.
178
+ * (at your option) any later version.
265
+ *
179
+ *
266
+ * This program is distributed in the hope that it will be useful, but WITHOUT
180
+ * This program is distributed in the hope that it will be useful,
267
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
181
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
268
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
182
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
269
+ * for more details.
183
+ * GNU General Public License for more details.
184
+ *
185
+ * You should have received a copy of the GNU General Public License
186
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
270
+ */
187
+ */
271
+
188
+
272
+#include "qemu/osdep.h"
189
+#include "qemu/osdep.h"
273
+#include "hw/irq.h"
190
+#include "qemu/units.h"
274
+#include "hw/qdev-clock.h"
191
+#include "hw/sysbus.h"
275
+#include "hw/qdev-properties.h"
276
+#include "hw/misc/npcm7xx_pwm.h"
277
+#include "hw/registerfields.h"
278
+#include "migration/vmstate.h"
192
+#include "migration/vmstate.h"
279
+#include "qemu/bitops.h"
280
+#include "qemu/error-report.h"
281
+#include "qemu/log.h"
193
+#include "qemu/log.h"
282
+#include "qemu/module.h"
194
+#include "qemu/module.h"
283
+#include "qemu/units.h"
195
+#include "qapi/error.h"
196
+#include "hw/qdev-properties.h"
197
+#include "hw/qdev-properties-system.h"
198
+#include "hw/misc/allwinner-sramc.h"
284
+#include "trace.h"
199
+#include "trace.h"
285
+
200
+
286
+REG32(NPCM7XX_PWM_PPR, 0x00);
201
+/*
287
+REG32(NPCM7XX_PWM_CSR, 0x04);
202
+ * register offsets
288
+REG32(NPCM7XX_PWM_PCR, 0x08);
203
+ * https://linux-sunxi.org/SRAM_Controller_Register_Guide
289
+REG32(NPCM7XX_PWM_CNR0, 0x0c);
204
+ */
290
+REG32(NPCM7XX_PWM_CMR0, 0x10);
205
+enum {
291
+REG32(NPCM7XX_PWM_PDR0, 0x14);
206
+ REG_SRAM_CTL1_CFG = 0x04, /* SRAM Control register 1 */
292
+REG32(NPCM7XX_PWM_CNR1, 0x18);
207
+ REG_SRAM_VER = 0x24, /* SRAM Version register */
293
+REG32(NPCM7XX_PWM_CMR1, 0x1c);
208
+ REG_SRAM_R40_SOFT_ENTRY_REG0 = 0xbc,
294
+REG32(NPCM7XX_PWM_PDR1, 0x20);
209
+};
295
+REG32(NPCM7XX_PWM_CNR2, 0x24);
210
+
296
+REG32(NPCM7XX_PWM_CMR2, 0x28);
211
+/* REG_SRAMC_VERSION bit defines */
297
+REG32(NPCM7XX_PWM_PDR2, 0x2c);
212
+#define SRAM_VER_READ_ENABLE (1 << 15)
298
+REG32(NPCM7XX_PWM_CNR3, 0x30);
213
+#define SRAM_VER_VERSION_SHIFT 16
299
+REG32(NPCM7XX_PWM_CMR3, 0x34);
214
+#define SRAM_VERSION_SUN8I_R40 0x1701
300
+REG32(NPCM7XX_PWM_PDR3, 0x38);
215
+
301
+REG32(NPCM7XX_PWM_PIER, 0x3c);
216
+static uint64_t allwinner_sramc_read(void *opaque, hwaddr offset,
302
+REG32(NPCM7XX_PWM_PIIR, 0x40);
217
+ unsigned size)
303
+REG32(NPCM7XX_PWM_PWDR0, 0x44);
218
+{
304
+REG32(NPCM7XX_PWM_PWDR1, 0x48);
219
+ AwSRAMCState *s = AW_SRAMC(opaque);
305
+REG32(NPCM7XX_PWM_PWDR2, 0x4c);
220
+ AwSRAMCClass *sc = AW_SRAMC_GET_CLASS(s);
306
+REG32(NPCM7XX_PWM_PWDR3, 0x50);
221
+ uint64_t val = 0;
307
+
222
+
308
+/* Register field definitions. */
223
+ switch (offset) {
309
+#define NPCM7XX_PPR(rv, index) extract32((rv), npcm7xx_ppr_base[index], 8)
224
+ case REG_SRAM_CTL1_CFG:
310
+#define NPCM7XX_CSR(rv, index) extract32((rv), npcm7xx_csr_base[index], 3)
225
+ val = s->sram_ctl1;
311
+#define NPCM7XX_CH(rv, index) extract32((rv), npcm7xx_ch_base[index], 4)
226
+ break;
312
+#define NPCM7XX_CH_EN BIT(0)
227
+ case REG_SRAM_VER:
313
+#define NPCM7XX_CH_INV BIT(2)
228
+ /* bit15: lock bit, set this bit before reading this register */
314
+#define NPCM7XX_CH_MOD BIT(3)
229
+ if (s->sram_ver & SRAM_VER_READ_ENABLE) {
315
+
230
+ val = SRAM_VER_READ_ENABLE |
316
+/* Offset of each PWM channel's prescaler in the PPR register. */
231
+ (sc->sram_version_code << SRAM_VER_VERSION_SHIFT);
317
+static const int npcm7xx_ppr_base[] = { 0, 0, 8, 8 };
232
+ }
318
+/* Offset of each PWM channel's clock selector in the CSR register. */
233
+ break;
319
+static const int npcm7xx_csr_base[] = { 0, 4, 8, 12 };
234
+ case REG_SRAM_R40_SOFT_ENTRY_REG0:
320
+/* Offset of each PWM channel's control variable in the PCR register. */
235
+ val = s->sram_soft_entry_reg0;
321
+static const int npcm7xx_ch_base[] = { 0, 8, 12, 16 };
236
+ break;
322
+
237
+ default:
323
+static uint32_t npcm7xx_pwm_calculate_freq(NPCM7xxPWM *p)
238
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n",
324
+{
239
+ __func__, (uint32_t)offset);
325
+ uint32_t ppr;
326
+ uint32_t csr;
327
+ uint32_t freq;
328
+
329
+ if (!p->running) {
330
+ return 0;
240
+ return 0;
331
+ }
241
+ }
332
+
242
+
333
+ csr = NPCM7XX_CSR(p->module->csr, p->index);
243
+ trace_allwinner_sramc_read(offset, val);
334
+ ppr = NPCM7XX_PPR(p->module->ppr, p->index);
244
+
335
+ freq = clock_get_hz(p->module->clock);
245
+ return val;
336
+ freq /= ppr + 1;
246
+}
337
+ /* csr can only be 0~4 */
247
+
338
+ if (csr > 4) {
248
+static void allwinner_sramc_write(void *opaque, hwaddr offset,
339
+ qemu_log_mask(LOG_GUEST_ERROR,
249
+ uint64_t val, unsigned size)
340
+ "%s: invalid csr value %u\n",
250
+{
341
+ __func__, csr);
251
+ AwSRAMCState *s = AW_SRAMC(opaque);
342
+ csr = 4;
252
+
253
+ trace_allwinner_sramc_write(offset, val);
254
+
255
+ switch (offset) {
256
+ case REG_SRAM_CTL1_CFG:
257
+ s->sram_ctl1 = val;
258
+ break;
259
+ case REG_SRAM_VER:
260
+ /* Only the READ_ENABLE bit is writeable */
261
+ s->sram_ver = val & SRAM_VER_READ_ENABLE;
262
+ break;
263
+ case REG_SRAM_R40_SOFT_ENTRY_REG0:
264
+ s->sram_soft_entry_reg0 = val;
265
+ break;
266
+ default:
267
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n",
268
+ __func__, (uint32_t)offset);
269
+ break;
343
+ }
270
+ }
344
+ /* freq won't be changed if csr == 4. */
271
+}
345
+ if (csr < 4) {
272
+
346
+ freq >>= csr + 1;
273
+static const MemoryRegionOps allwinner_sramc_ops = {
274
+ .read = allwinner_sramc_read,
275
+ .write = allwinner_sramc_write,
276
+ .endianness = DEVICE_NATIVE_ENDIAN,
277
+ .valid = {
278
+ .min_access_size = 4,
279
+ .max_access_size = 4,
280
+ },
281
+ .impl.min_access_size = 4,
282
+};
283
+
284
+static const VMStateDescription allwinner_sramc_vmstate = {
285
+ .name = "allwinner-sramc",
286
+ .version_id = 1,
287
+ .minimum_version_id = 1,
288
+ .fields = (VMStateField[]) {
289
+ VMSTATE_UINT32(sram_ver, AwSRAMCState),
290
+ VMSTATE_UINT32(sram_soft_entry_reg0, AwSRAMCState),
291
+ VMSTATE_END_OF_LIST()
347
+ }
292
+ }
348
+
293
+};
349
+ return freq / (p->cnr + 1);
294
+
350
+}
295
+static void allwinner_sramc_reset(DeviceState *dev)
351
+
296
+{
352
+static uint32_t npcm7xx_pwm_calculate_duty(NPCM7xxPWM *p)
297
+ AwSRAMCState *s = AW_SRAMC(dev);
353
+{
298
+ AwSRAMCClass *sc = AW_SRAMC_GET_CLASS(s);
354
+ uint64_t duty;
299
+
355
+
300
+ switch (sc->sram_version_code) {
356
+ if (p->running) {
301
+ case SRAM_VERSION_SUN8I_R40:
357
+ if (p->cnr == 0) {
302
+ s->sram_ctl1 = 0x1300;
358
+ duty = 0;
303
+ break;
359
+ } else if (p->cmr >= p->cnr) {
360
+ duty = NPCM7XX_PWM_MAX_DUTY;
361
+ } else {
362
+ duty = NPCM7XX_PWM_MAX_DUTY * (p->cmr + 1) / (p->cnr + 1);
363
+ }
364
+ } else {
365
+ duty = 0;
366
+ }
304
+ }
367
+
305
+}
368
+ if (p->inverted) {
306
+
369
+ duty = NPCM7XX_PWM_MAX_DUTY - duty;
307
+static void allwinner_sramc_class_init(ObjectClass *klass, void *data)
370
+ }
308
+{
371
+
309
+ DeviceClass *dc = DEVICE_CLASS(klass);
372
+ return duty;
310
+
373
+}
311
+ dc->reset = allwinner_sramc_reset;
374
+
312
+ dc->vmsd = &allwinner_sramc_vmstate;
375
+static void npcm7xx_pwm_update_freq(NPCM7xxPWM *p)
313
+}
376
+{
314
+
377
+ uint32_t freq = npcm7xx_pwm_calculate_freq(p);
315
+static void allwinner_sramc_init(Object *obj)
378
+
316
+{
379
+ if (freq != p->freq) {
380
+ trace_npcm7xx_pwm_update_freq(DEVICE(p->module)->canonical_path,
381
+ p->index, p->freq, freq);
382
+ p->freq = freq;
383
+ }
384
+}
385
+
386
+static void npcm7xx_pwm_update_duty(NPCM7xxPWM *p)
387
+{
388
+ uint32_t duty = npcm7xx_pwm_calculate_duty(p);
389
+
390
+ if (duty != p->duty) {
391
+ trace_npcm7xx_pwm_update_duty(DEVICE(p->module)->canonical_path,
392
+ p->index, p->duty, duty);
393
+ p->duty = duty;
394
+ }
395
+}
396
+
397
+static void npcm7xx_pwm_update_output(NPCM7xxPWM *p)
398
+{
399
+ npcm7xx_pwm_update_freq(p);
400
+ npcm7xx_pwm_update_duty(p);
401
+}
402
+
403
+static void npcm7xx_pwm_write_ppr(NPCM7xxPWMState *s, uint32_t new_ppr)
404
+{
405
+ int i;
406
+ uint32_t old_ppr = s->ppr;
407
+
408
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_ppr_base) != NPCM7XX_PWM_PER_MODULE);
409
+ s->ppr = new_ppr;
410
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
411
+ if (NPCM7XX_PPR(old_ppr, i) != NPCM7XX_PPR(new_ppr, i)) {
412
+ npcm7xx_pwm_update_freq(&s->pwm[i]);
413
+ }
414
+ }
415
+}
416
+
417
+static void npcm7xx_pwm_write_csr(NPCM7xxPWMState *s, uint32_t new_csr)
418
+{
419
+ int i;
420
+ uint32_t old_csr = s->csr;
421
+
422
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_csr_base) != NPCM7XX_PWM_PER_MODULE);
423
+ s->csr = new_csr;
424
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
425
+ if (NPCM7XX_CSR(old_csr, i) != NPCM7XX_CSR(new_csr, i)) {
426
+ npcm7xx_pwm_update_freq(&s->pwm[i]);
427
+ }
428
+ }
429
+}
430
+
431
+static void npcm7xx_pwm_write_pcr(NPCM7xxPWMState *s, uint32_t new_pcr)
432
+{
433
+ int i;
434
+ bool inverted;
435
+ uint32_t pcr;
436
+ NPCM7xxPWM *p;
437
+
438
+ s->pcr = new_pcr;
439
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_ch_base) != NPCM7XX_PWM_PER_MODULE);
440
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
441
+ p = &s->pwm[i];
442
+ pcr = NPCM7XX_CH(new_pcr, i);
443
+ inverted = pcr & NPCM7XX_CH_INV;
444
+
445
+ /*
446
+ * We only run a PWM channel with toggle mode. Single-shot mode does not
447
+ * generate frequency and duty-cycle values.
448
+ */
449
+ if ((pcr & NPCM7XX_CH_EN) && (pcr & NPCM7XX_CH_MOD)) {
450
+ if (p->running) {
451
+ /* Re-run this PWM channel if inverted changed. */
452
+ if (p->inverted ^ inverted) {
453
+ p->inverted = inverted;
454
+ npcm7xx_pwm_update_duty(p);
455
+ }
456
+ } else {
457
+ /* Run this PWM channel. */
458
+ p->running = true;
459
+ p->inverted = inverted;
460
+ npcm7xx_pwm_update_output(p);
461
+ }
462
+ } else {
463
+ /* Clear this PWM channel. */
464
+ p->running = false;
465
+ p->inverted = inverted;
466
+ npcm7xx_pwm_update_output(p);
467
+ }
468
+ }
469
+
470
+}
471
+
472
+static hwaddr npcm7xx_cnr_index(hwaddr offset)
473
+{
474
+ switch (offset) {
475
+ case A_NPCM7XX_PWM_CNR0:
476
+ return 0;
477
+ case A_NPCM7XX_PWM_CNR1:
478
+ return 1;
479
+ case A_NPCM7XX_PWM_CNR2:
480
+ return 2;
481
+ case A_NPCM7XX_PWM_CNR3:
482
+ return 3;
483
+ default:
484
+ g_assert_not_reached();
485
+ }
486
+}
487
+
488
+static hwaddr npcm7xx_cmr_index(hwaddr offset)
489
+{
490
+ switch (offset) {
491
+ case A_NPCM7XX_PWM_CMR0:
492
+ return 0;
493
+ case A_NPCM7XX_PWM_CMR1:
494
+ return 1;
495
+ case A_NPCM7XX_PWM_CMR2:
496
+ return 2;
497
+ case A_NPCM7XX_PWM_CMR3:
498
+ return 3;
499
+ default:
500
+ g_assert_not_reached();
501
+ }
502
+}
503
+
504
+static hwaddr npcm7xx_pdr_index(hwaddr offset)
505
+{
506
+ switch (offset) {
507
+ case A_NPCM7XX_PWM_PDR0:
508
+ return 0;
509
+ case A_NPCM7XX_PWM_PDR1:
510
+ return 1;
511
+ case A_NPCM7XX_PWM_PDR2:
512
+ return 2;
513
+ case A_NPCM7XX_PWM_PDR3:
514
+ return 3;
515
+ default:
516
+ g_assert_not_reached();
517
+ }
518
+}
519
+
520
+static hwaddr npcm7xx_pwdr_index(hwaddr offset)
521
+{
522
+ switch (offset) {
523
+ case A_NPCM7XX_PWM_PWDR0:
524
+ return 0;
525
+ case A_NPCM7XX_PWM_PWDR1:
526
+ return 1;
527
+ case A_NPCM7XX_PWM_PWDR2:
528
+ return 2;
529
+ case A_NPCM7XX_PWM_PWDR3:
530
+ return 3;
531
+ default:
532
+ g_assert_not_reached();
533
+ }
534
+}
535
+
536
+static uint64_t npcm7xx_pwm_read(void *opaque, hwaddr offset, unsigned size)
537
+{
538
+ NPCM7xxPWMState *s = opaque;
539
+ uint64_t value = 0;
540
+
541
+ switch (offset) {
542
+ case A_NPCM7XX_PWM_CNR0:
543
+ case A_NPCM7XX_PWM_CNR1:
544
+ case A_NPCM7XX_PWM_CNR2:
545
+ case A_NPCM7XX_PWM_CNR3:
546
+ value = s->pwm[npcm7xx_cnr_index(offset)].cnr;
547
+ break;
548
+
549
+ case A_NPCM7XX_PWM_CMR0:
550
+ case A_NPCM7XX_PWM_CMR1:
551
+ case A_NPCM7XX_PWM_CMR2:
552
+ case A_NPCM7XX_PWM_CMR3:
553
+ value = s->pwm[npcm7xx_cmr_index(offset)].cmr;
554
+ break;
555
+
556
+ case A_NPCM7XX_PWM_PDR0:
557
+ case A_NPCM7XX_PWM_PDR1:
558
+ case A_NPCM7XX_PWM_PDR2:
559
+ case A_NPCM7XX_PWM_PDR3:
560
+ value = s->pwm[npcm7xx_pdr_index(offset)].pdr;
561
+ break;
562
+
563
+ case A_NPCM7XX_PWM_PWDR0:
564
+ case A_NPCM7XX_PWM_PWDR1:
565
+ case A_NPCM7XX_PWM_PWDR2:
566
+ case A_NPCM7XX_PWM_PWDR3:
567
+ value = s->pwm[npcm7xx_pwdr_index(offset)].pwdr;
568
+ break;
569
+
570
+ case A_NPCM7XX_PWM_PPR:
571
+ value = s->ppr;
572
+ break;
573
+
574
+ case A_NPCM7XX_PWM_CSR:
575
+ value = s->csr;
576
+ break;
577
+
578
+ case A_NPCM7XX_PWM_PCR:
579
+ value = s->pcr;
580
+ break;
581
+
582
+ case A_NPCM7XX_PWM_PIER:
583
+ value = s->pier;
584
+ break;
585
+
586
+ case A_NPCM7XX_PWM_PIIR:
587
+ value = s->piir;
588
+ break;
589
+
590
+ default:
591
+ qemu_log_mask(LOG_GUEST_ERROR,
592
+ "%s: invalid offset 0x%04" HWADDR_PRIx "\n",
593
+ __func__, offset);
594
+ break;
595
+ }
596
+
597
+ trace_npcm7xx_pwm_read(DEVICE(s)->canonical_path, offset, value);
598
+ return value;
599
+}
600
+
601
+static void npcm7xx_pwm_write(void *opaque, hwaddr offset,
602
+ uint64_t v, unsigned size)
603
+{
604
+ NPCM7xxPWMState *s = opaque;
605
+ NPCM7xxPWM *p;
606
+ uint32_t value = v;
607
+
608
+ trace_npcm7xx_pwm_write(DEVICE(s)->canonical_path, offset, value);
609
+ switch (offset) {
610
+ case A_NPCM7XX_PWM_CNR0:
611
+ case A_NPCM7XX_PWM_CNR1:
612
+ case A_NPCM7XX_PWM_CNR2:
613
+ case A_NPCM7XX_PWM_CNR3:
614
+ p = &s->pwm[npcm7xx_cnr_index(offset)];
615
+ p->cnr = value;
616
+ npcm7xx_pwm_update_output(p);
617
+ break;
618
+
619
+ case A_NPCM7XX_PWM_CMR0:
620
+ case A_NPCM7XX_PWM_CMR1:
621
+ case A_NPCM7XX_PWM_CMR2:
622
+ case A_NPCM7XX_PWM_CMR3:
623
+ p = &s->pwm[npcm7xx_cmr_index(offset)];
624
+ p->cmr = value;
625
+ npcm7xx_pwm_update_output(p);
626
+ break;
627
+
628
+ case A_NPCM7XX_PWM_PDR0:
629
+ case A_NPCM7XX_PWM_PDR1:
630
+ case A_NPCM7XX_PWM_PDR2:
631
+ case A_NPCM7XX_PWM_PDR3:
632
+ qemu_log_mask(LOG_GUEST_ERROR,
633
+ "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n",
634
+ __func__, offset);
635
+ break;
636
+
637
+ case A_NPCM7XX_PWM_PWDR0:
638
+ case A_NPCM7XX_PWM_PWDR1:
639
+ case A_NPCM7XX_PWM_PWDR2:
640
+ case A_NPCM7XX_PWM_PWDR3:
641
+ qemu_log_mask(LOG_UNIMP,
642
+ "%s: register @ 0x%04" HWADDR_PRIx " is not implemented\n",
643
+ __func__, offset);
644
+ break;
645
+
646
+ case A_NPCM7XX_PWM_PPR:
647
+ npcm7xx_pwm_write_ppr(s, value);
648
+ break;
649
+
650
+ case A_NPCM7XX_PWM_CSR:
651
+ npcm7xx_pwm_write_csr(s, value);
652
+ break;
653
+
654
+ case A_NPCM7XX_PWM_PCR:
655
+ npcm7xx_pwm_write_pcr(s, value);
656
+ break;
657
+
658
+ case A_NPCM7XX_PWM_PIER:
659
+ qemu_log_mask(LOG_UNIMP,
660
+ "%s: register @ 0x%04" HWADDR_PRIx " is not implemented\n",
661
+ __func__, offset);
662
+ break;
663
+
664
+ case A_NPCM7XX_PWM_PIIR:
665
+ qemu_log_mask(LOG_UNIMP,
666
+ "%s: register @ 0x%04" HWADDR_PRIx " is not implemented\n",
667
+ __func__, offset);
668
+ break;
669
+
670
+ default:
671
+ qemu_log_mask(LOG_GUEST_ERROR,
672
+ "%s: invalid offset 0x%04" HWADDR_PRIx "\n",
673
+ __func__, offset);
674
+ break;
675
+ }
676
+}
677
+
678
+static const struct MemoryRegionOps npcm7xx_pwm_ops = {
679
+ .read = npcm7xx_pwm_read,
680
+ .write = npcm7xx_pwm_write,
681
+ .endianness = DEVICE_LITTLE_ENDIAN,
682
+ .valid = {
683
+ .min_access_size = 4,
684
+ .max_access_size = 4,
685
+ .unaligned = false,
686
+ },
687
+};
688
+
689
+static void npcm7xx_pwm_enter_reset(Object *obj, ResetType type)
690
+{
691
+ NPCM7xxPWMState *s = NPCM7XX_PWM(obj);
692
+ int i;
693
+
694
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; i++) {
695
+ NPCM7xxPWM *p = &s->pwm[i];
696
+
697
+ p->cnr = 0x00000000;
698
+ p->cmr = 0x00000000;
699
+ p->pdr = 0x00000000;
700
+ p->pwdr = 0x00000000;
701
+ }
702
+
703
+ s->ppr = 0x00000000;
704
+ s->csr = 0x00000000;
705
+ s->pcr = 0x00000000;
706
+ s->pier = 0x00000000;
707
+ s->piir = 0x00000000;
708
+}
709
+
710
+static void npcm7xx_pwm_hold_reset(Object *obj)
711
+{
712
+ NPCM7xxPWMState *s = NPCM7XX_PWM(obj);
713
+ int i;
714
+
715
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; i++) {
716
+ qemu_irq_lower(s->pwm[i].irq);
717
+ }
718
+}
719
+
720
+static void npcm7xx_pwm_init(Object *obj)
721
+{
722
+ NPCM7xxPWMState *s = NPCM7XX_PWM(obj);
723
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
317
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
724
+ int i;
318
+ AwSRAMCState *s = AW_SRAMC(obj);
725
+
319
+
726
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; i++) {
320
+ /* Memory mapping */
727
+ NPCM7xxPWM *p = &s->pwm[i];
321
+ memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_sramc_ops, s,
728
+ p->module = s;
322
+ TYPE_AW_SRAMC, 1 * KiB);
729
+ p->index = i;
730
+ sysbus_init_irq(sbd, &p->irq);
731
+ }
732
+
733
+ memory_region_init_io(&s->iomem, obj, &npcm7xx_pwm_ops, s,
734
+ TYPE_NPCM7XX_PWM, 4 * KiB);
735
+ sysbus_init_mmio(sbd, &s->iomem);
323
+ sysbus_init_mmio(sbd, &s->iomem);
736
+ s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL);
324
+}
737
+
325
+
738
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
326
+static const TypeInfo allwinner_sramc_info = {
739
+ object_property_add_uint32_ptr(obj, "freq[*]",
327
+ .name = TYPE_AW_SRAMC,
740
+ &s->pwm[i].freq, OBJ_PROP_FLAG_READ);
328
+ .parent = TYPE_SYS_BUS_DEVICE,
741
+ object_property_add_uint32_ptr(obj, "duty[*]",
329
+ .instance_init = allwinner_sramc_init,
742
+ &s->pwm[i].duty, OBJ_PROP_FLAG_READ);
330
+ .instance_size = sizeof(AwSRAMCState),
743
+ }
331
+ .class_init = allwinner_sramc_class_init,
744
+}
332
+};
745
+
333
+
746
+static const VMStateDescription vmstate_npcm7xx_pwm = {
334
+static void allwinner_r40_sramc_class_init(ObjectClass *klass, void *data)
747
+ .name = "npcm7xx-pwm",
335
+{
748
+ .version_id = 0,
336
+ AwSRAMCClass *sc = AW_SRAMC_CLASS(klass);
749
+ .minimum_version_id = 0,
337
+
750
+ .fields = (VMStateField[]) {
338
+ sc->sram_version_code = SRAM_VERSION_SUN8I_R40;
751
+ VMSTATE_BOOL(running, NPCM7xxPWM),
339
+}
752
+ VMSTATE_BOOL(inverted, NPCM7xxPWM),
340
+
753
+ VMSTATE_UINT8(index, NPCM7xxPWM),
341
+static const TypeInfo allwinner_r40_sramc_info = {
754
+ VMSTATE_UINT32(cnr, NPCM7xxPWM),
342
+ .name = TYPE_AW_SRAMC_SUN8I_R40,
755
+ VMSTATE_UINT32(cmr, NPCM7xxPWM),
343
+ .parent = TYPE_AW_SRAMC,
756
+ VMSTATE_UINT32(pdr, NPCM7xxPWM),
344
+ .class_init = allwinner_r40_sramc_class_init,
757
+ VMSTATE_UINT32(pwdr, NPCM7xxPWM),
345
+};
758
+ VMSTATE_UINT32(freq, NPCM7xxPWM),
346
+
759
+ VMSTATE_UINT32(duty, NPCM7xxPWM),
347
+static void allwinner_sramc_register(void)
760
+ VMSTATE_END_OF_LIST(),
348
+{
761
+ },
349
+ type_register_static(&allwinner_sramc_info);
762
+};
350
+ type_register_static(&allwinner_r40_sramc_info);
763
+
351
+}
764
+static const VMStateDescription vmstate_npcm7xx_pwm_module = {
352
+
765
+ .name = "npcm7xx-pwm-module",
353
+type_init(allwinner_sramc_register)
766
+ .version_id = 0,
354
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
767
+ .minimum_version_id = 0,
355
index XXXXXXX..XXXXXXX 100644
768
+ .fields = (VMStateField[]) {
356
--- a/hw/arm/Kconfig
769
+ VMSTATE_CLOCK(clock, NPCM7xxPWMState),
357
+++ b/hw/arm/Kconfig
770
+ VMSTATE_STRUCT_ARRAY(pwm, NPCM7xxPWMState,
358
@@ -XXX,XX +XXX,XX @@ config ALLWINNER_H3
771
+ NPCM7XX_PWM_PER_MODULE, 0, vmstate_npcm7xx_pwm,
359
config ALLWINNER_R40
772
+ NPCM7xxPWM),
360
bool
773
+ VMSTATE_UINT32(ppr, NPCM7xxPWMState),
361
default y if TCG && ARM
774
+ VMSTATE_UINT32(csr, NPCM7xxPWMState),
362
+ select ALLWINNER_SRAMC
775
+ VMSTATE_UINT32(pcr, NPCM7xxPWMState),
363
select ALLWINNER_A10_PIT
776
+ VMSTATE_UINT32(pier, NPCM7xxPWMState),
364
select AXP2XX_PMU
777
+ VMSTATE_UINT32(piir, NPCM7xxPWMState),
365
select SERIAL
778
+ VMSTATE_END_OF_LIST(),
366
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
779
+ },
367
index XXXXXXX..XXXXXXX 100644
780
+};
368
--- a/hw/misc/Kconfig
781
+
369
+++ b/hw/misc/Kconfig
782
+static void npcm7xx_pwm_class_init(ObjectClass *klass, void *data)
370
@@ -XXX,XX +XXX,XX @@ config VIRT_CTRL
783
+{
371
config LASI
784
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
372
bool
785
+ DeviceClass *dc = DEVICE_CLASS(klass);
373
786
+
374
+config ALLWINNER_SRAMC
787
+ dc->desc = "NPCM7xx PWM Controller";
375
+ bool
788
+ dc->vmsd = &vmstate_npcm7xx_pwm_module;
376
+
789
+ rc->phases.enter = npcm7xx_pwm_enter_reset;
377
config ALLWINNER_A10_CCM
790
+ rc->phases.hold = npcm7xx_pwm_hold_reset;
378
bool
791
+}
379
792
+
793
+static const TypeInfo npcm7xx_pwm_info = {
794
+ .name = TYPE_NPCM7XX_PWM,
795
+ .parent = TYPE_SYS_BUS_DEVICE,
796
+ .instance_size = sizeof(NPCM7xxPWMState),
797
+ .class_init = npcm7xx_pwm_class_init,
798
+ .instance_init = npcm7xx_pwm_init,
799
+};
800
+
801
+static void npcm7xx_pwm_register_type(void)
802
+{
803
+ type_register_static(&npcm7xx_pwm_info);
804
+}
805
+type_init(npcm7xx_pwm_register_type);
806
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
380
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
807
index XXXXXXX..XXXXXXX 100644
381
index XXXXXXX..XXXXXXX 100644
808
--- a/hw/misc/meson.build
382
--- a/hw/misc/meson.build
809
+++ b/hw/misc/meson.build
383
+++ b/hw/misc/meson.build
810
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mst_fpga.c'))
384
@@ -XXX,XX +XXX,XX @@ subdir('macio')
811
softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
385
812
'npcm7xx_clk.c',
386
softmmu_ss.add(when: 'CONFIG_IVSHMEM_DEVICE', if_true: files('ivshmem.c'))
813
'npcm7xx_gcr.c',
387
814
+ 'npcm7xx_pwm.c',
388
+softmmu_ss.add(when: 'CONFIG_ALLWINNER_SRAMC', if_true: files('allwinner-sramc.c'))
815
'npcm7xx_rng.c',
389
softmmu_ss.add(when: 'CONFIG_ALLWINNER_A10_CCM', if_true: files('allwinner-a10-ccm.c'))
816
))
390
softmmu_ss.add(when: 'CONFIG_ALLWINNER_A10_DRAMC', if_true: files('allwinner-a10-dramc.c'))
817
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files(
391
softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3-ccu.c'))
818
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
392
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
819
index XXXXXXX..XXXXXXX 100644
393
index XXXXXXX..XXXXXXX 100644
820
--- a/hw/misc/trace-events
394
--- a/hw/misc/trace-events
821
+++ b/hw/misc/trace-events
395
+++ b/hw/misc/trace-events
822
@@ -XXX,XX +XXX,XX @@ npcm7xx_gcr_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " valu
396
@@ -XXX,XX +XXX,XX @@ allwinner_r40_dramphy_write(uint64_t offset, uint64_t data, unsigned size) "writ
823
npcm7xx_rng_read(uint64_t offset, uint64_t value, unsigned size) "offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
397
allwinner_sid_read(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
824
npcm7xx_rng_write(uint64_t offset, uint64_t value, unsigned size) "offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
398
allwinner_sid_write(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
825
399
826
+# npcm7xx_pwm.c
400
+# allwinner-sramc.c
827
+npcm7xx_pwm_read(const char *id, uint64_t offset, uint32_t value) "%s offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
401
+allwinner_sramc_read(uint64_t offset, uint64_t data) "offset 0x%" PRIx64 " data 0x%" PRIx64
828
+npcm7xx_pwm_write(const char *id, uint64_t offset, uint32_t value) "%s offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
402
+allwinner_sramc_write(uint64_t offset, uint64_t data) "offset 0x%" PRIx64 " data 0x%" PRIx64
829
+npcm7xx_pwm_update_freq(const char *id, uint8_t index, uint32_t old_value, uint32_t new_value) "%s pwm[%u] Update Freq: old_freq: %u, new_freq: %u"
403
+
830
+npcm7xx_pwm_update_duty(const char *id, uint8_t index, uint32_t old_value, uint32_t new_value) "%s pwm[%u] Update Duty: old_duty: %u, new_duty: %u"
404
# avr_power.c
831
+
405
avr_power_read(uint8_t value) "power_reduc read value:%u"
832
# stm32f4xx_syscfg.c
406
avr_power_write(uint8_t value) "power_reduc write value:%u"
833
stm32f4xx_syscfg_set_irq(int gpio, int line, int level) "Interupt: GPIO: %d, Line: %d; Level: %d"
834
stm32f4xx_pulse_exti(int irq) "Pulse EXTI: %d"
835
--
407
--
836
2.20.1
408
2.34.1
837
838
diff view generated by jsdifflib
New patch
1
From: qianfan Zhao <qianfanguijin@163.com>
1
2
3
Add test case for booting from initrd and sd card.
4
5
Signed-off-by: qianfan Zhao <qianfanguijin@163.com>
6
Reviewed-by: Niek Linnenbank <nieklinnenbank@gmail.com>
7
Tested-by: Niek Linnenbank <nieklinnenbank@gmail.com>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
10
tests/avocado/boot_linux_console.py | 176 ++++++++++++++++++++++++++++
11
1 file changed, 176 insertions(+)
12
13
diff --git a/tests/avocado/boot_linux_console.py b/tests/avocado/boot_linux_console.py
14
index XXXXXXX..XXXXXXX 100644
15
--- a/tests/avocado/boot_linux_console.py
16
+++ b/tests/avocado/boot_linux_console.py
17
@@ -XXX,XX +XXX,XX @@ def test_arm_quanta_gsj_initrd(self):
18
self.wait_for_console_pattern(
19
'Give root password for system maintenance')
20
21
+ def test_arm_bpim2u(self):
22
+ """
23
+ :avocado: tags=arch:arm
24
+ :avocado: tags=machine:bpim2u
25
+ :avocado: tags=accel:tcg
26
+ """
27
+ deb_url = ('https://apt.armbian.com/pool/main/l/linux-5.10.16-sunxi/'
28
+ 'linux-image-current-sunxi_21.02.2_armhf.deb')
29
+ deb_hash = '9fa84beda245cabf0b4fa84cf6eaa7738ead1da0'
30
+ deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
31
+ kernel_path = self.extract_from_deb(deb_path,
32
+ '/boot/vmlinuz-5.10.16-sunxi')
33
+ dtb_path = ('/usr/lib/linux-image-current-sunxi/'
34
+ 'sun8i-r40-bananapi-m2-ultra.dtb')
35
+ dtb_path = self.extract_from_deb(deb_path, dtb_path)
36
+
37
+ self.vm.set_console()
38
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
39
+ 'console=ttyS0,115200n8 '
40
+ 'earlycon=uart,mmio32,0x1c28000')
41
+ self.vm.add_args('-kernel', kernel_path,
42
+ '-dtb', dtb_path,
43
+ '-append', kernel_command_line)
44
+ self.vm.launch()
45
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
46
+ self.wait_for_console_pattern(console_pattern)
47
+
48
+ def test_arm_bpim2u_initrd(self):
49
+ """
50
+ :avocado: tags=arch:arm
51
+ :avocado: tags=accel:tcg
52
+ :avocado: tags=machine:bpim2u
53
+ """
54
+ deb_url = ('https://apt.armbian.com/pool/main/l/linux-5.10.16-sunxi/'
55
+ 'linux-image-current-sunxi_21.02.2_armhf.deb')
56
+ deb_hash = '9fa84beda245cabf0b4fa84cf6eaa7738ead1da0'
57
+ deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
58
+ kernel_path = self.extract_from_deb(deb_path,
59
+ '/boot/vmlinuz-5.10.16-sunxi')
60
+ dtb_path = ('/usr/lib/linux-image-current-sunxi/'
61
+ 'sun8i-r40-bananapi-m2-ultra.dtb')
62
+ dtb_path = self.extract_from_deb(deb_path, dtb_path)
63
+ initrd_url = ('https://github.com/groeck/linux-build-test/raw/'
64
+ '2eb0a73b5d5a28df3170c546ddaaa9757e1e0848/rootfs/'
65
+ 'arm/rootfs-armv7a.cpio.gz')
66
+ initrd_hash = '604b2e45cdf35045846b8bbfbf2129b1891bdc9c'
67
+ initrd_path_gz = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
68
+ initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
69
+ archive.gzip_uncompress(initrd_path_gz, initrd_path)
70
+
71
+ self.vm.set_console()
72
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
73
+ 'console=ttyS0,115200 '
74
+ 'panic=-1 noreboot')
75
+ self.vm.add_args('-kernel', kernel_path,
76
+ '-dtb', dtb_path,
77
+ '-initrd', initrd_path,
78
+ '-append', kernel_command_line,
79
+ '-no-reboot')
80
+ self.vm.launch()
81
+ self.wait_for_console_pattern('Boot successful.')
82
+
83
+ exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
84
+ 'Allwinner sun8i Family')
85
+ exec_command_and_wait_for_pattern(self, 'cat /proc/iomem',
86
+ 'system-control@1c00000')
87
+ exec_command_and_wait_for_pattern(self, 'reboot',
88
+ 'reboot: Restarting system')
89
+ # Wait for VM to shut down gracefully
90
+ self.vm.wait()
91
+
92
+ def test_arm_bpim2u_gmac(self):
93
+ """
94
+ :avocado: tags=arch:arm
95
+ :avocado: tags=accel:tcg
96
+ :avocado: tags=machine:bpim2u
97
+ :avocado: tags=device:sd
98
+ """
99
+ self.require_netdev('user')
100
+
101
+ deb_url = ('https://apt.armbian.com/pool/main/l/linux-5.10.16-sunxi/'
102
+ 'linux-image-current-sunxi_21.02.2_armhf.deb')
103
+ deb_hash = '9fa84beda245cabf0b4fa84cf6eaa7738ead1da0'
104
+ deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash)
105
+ kernel_path = self.extract_from_deb(deb_path,
106
+ '/boot/vmlinuz-5.10.16-sunxi')
107
+ dtb_path = ('/usr/lib/linux-image-current-sunxi/'
108
+ 'sun8i-r40-bananapi-m2-ultra.dtb')
109
+ dtb_path = self.extract_from_deb(deb_path, dtb_path)
110
+ rootfs_url = ('http://storage.kernelci.org/images/rootfs/buildroot/'
111
+ 'buildroot-baseline/20221116.0/armel/rootfs.ext2.xz')
112
+ rootfs_hash = 'fae32f337c7b87547b10f42599acf109da8b6d9a'
113
+ rootfs_path_xz = self.fetch_asset(rootfs_url, asset_hash=rootfs_hash)
114
+ rootfs_path = os.path.join(self.workdir, 'rootfs.cpio')
115
+ archive.lzma_uncompress(rootfs_path_xz, rootfs_path)
116
+ image_pow2ceil_expand(rootfs_path)
117
+
118
+ self.vm.set_console()
119
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
120
+ 'console=ttyS0,115200 '
121
+ 'root=/dev/mmcblk0 rootwait rw '
122
+ 'panic=-1 noreboot')
123
+ self.vm.add_args('-kernel', kernel_path,
124
+ '-dtb', dtb_path,
125
+ '-drive', 'file=' + rootfs_path + ',if=sd,format=raw',
126
+ '-net', 'nic,model=gmac,netdev=host_gmac',
127
+ '-netdev', 'user,id=host_gmac',
128
+ '-append', kernel_command_line,
129
+ '-no-reboot')
130
+ self.vm.launch()
131
+ shell_ready = "/bin/sh: can't access tty; job control turned off"
132
+ self.wait_for_console_pattern(shell_ready)
133
+
134
+ exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
135
+ 'Allwinner sun8i Family')
136
+ exec_command_and_wait_for_pattern(self, 'cat /proc/partitions',
137
+ 'mmcblk0')
138
+ exec_command_and_wait_for_pattern(self, 'ifconfig eth0 up',
139
+ 'eth0: Link is Up')
140
+ exec_command_and_wait_for_pattern(self, 'udhcpc eth0',
141
+ 'udhcpc: lease of 10.0.2.15 obtained')
142
+ exec_command_and_wait_for_pattern(self, 'ping -c 3 10.0.2.2',
143
+ '3 packets transmitted, 3 packets received, 0% packet loss')
144
+ exec_command_and_wait_for_pattern(self, 'reboot',
145
+ 'reboot: Restarting system')
146
+ # Wait for VM to shut down gracefully
147
+ self.vm.wait()
148
+
149
+ @skipUnless(os.getenv('AVOCADO_ALLOW_LARGE_STORAGE'), 'storage limited')
150
+ def test_arm_bpim2u_openwrt_22_03_3(self):
151
+ """
152
+ :avocado: tags=arch:arm
153
+ :avocado: tags=machine:bpim2u
154
+ :avocado: tags=device:sd
155
+ """
156
+
157
+ # This test download a 8.9 MiB compressed image and expand it
158
+ # to 127 MiB.
159
+ image_url = ('https://downloads.openwrt.org/releases/22.03.3/targets/'
160
+ 'sunxi/cortexa7/openwrt-22.03.3-sunxi-cortexa7-'
161
+ 'sinovoip_bananapi-m2-ultra-ext4-sdcard.img.gz')
162
+ image_hash = ('5b41b4e11423e562c6011640f9a7cd3b'
163
+ 'dd0a3d42b83430f7caa70a432e6cd82c')
164
+ image_path_gz = self.fetch_asset(image_url, asset_hash=image_hash,
165
+ algorithm='sha256')
166
+ image_path = archive.extract(image_path_gz, self.workdir)
167
+ image_pow2ceil_expand(image_path)
168
+
169
+ self.vm.set_console()
170
+ self.vm.add_args('-drive', 'file=' + image_path + ',if=sd,format=raw',
171
+ '-nic', 'user',
172
+ '-no-reboot')
173
+ self.vm.launch()
174
+
175
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
176
+ 'usbcore.nousb '
177
+ 'noreboot')
178
+
179
+ self.wait_for_console_pattern('U-Boot SPL')
180
+
181
+ interrupt_interactive_console_until_pattern(
182
+ self, 'Hit any key to stop autoboot:', '=>')
183
+ exec_command_and_wait_for_pattern(self, "setenv extraargs '" +
184
+ kernel_command_line + "'", '=>')
185
+ exec_command_and_wait_for_pattern(self, 'boot', 'Starting kernel ...');
186
+
187
+ self.wait_for_console_pattern(
188
+ 'Please press Enter to activate this console.')
189
+
190
+ exec_command_and_wait_for_pattern(self, ' ', 'root@')
191
+
192
+ exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo',
193
+ 'Allwinner sun8i Family')
194
+ exec_command_and_wait_for_pattern(self, 'cat /proc/iomem',
195
+ 'system-control@1c00000')
196
+
197
def test_arm_orangepi(self):
198
"""
199
:avocado: tags=arch:arm
200
--
201
2.34.1
diff view generated by jsdifflib
New patch
1
From: qianfan Zhao <qianfanguijin@163.com>
1
2
3
Add documents for Banana Pi M2U
4
5
Signed-off-by: qianfan Zhao <qianfanguijin@163.com>
6
Reviewed-by: Niek Linnenbank <nieklinnenbank@gmail.com>
7
[PMM: Minor format fixes to correct sphinx errors]
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
10
docs/system/arm/bananapi_m2u.rst | 139 +++++++++++++++++++++++++++++++
11
docs/system/target-arm.rst | 1 +
12
2 files changed, 140 insertions(+)
13
create mode 100644 docs/system/arm/bananapi_m2u.rst
14
15
diff --git a/docs/system/arm/bananapi_m2u.rst b/docs/system/arm/bananapi_m2u.rst
16
new file mode 100644
17
index XXXXXXX..XXXXXXX
18
--- /dev/null
19
+++ b/docs/system/arm/bananapi_m2u.rst
20
@@ -XXX,XX +XXX,XX @@
21
+Banana Pi BPI-M2U (``bpim2u``)
22
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
23
+
24
+Banana Pi BPI-M2 Ultra is a quad-core mini single board computer built with
25
+Allwinner A40i/R40/V40 SoC. It features 2GB of RAM and 8GB eMMC. It also
26
+has onboard WiFi and BT. On the ports side, the BPI-M2 Ultra has 2 USB A
27
+2.0 ports, 1 USB OTG port, 1 HDMI port, 1 audio jack, a DC power port,
28
+and last but not least, a SATA port.
29
+
30
+Supported devices
31
+"""""""""""""""""
32
+
33
+The Banana Pi M2U machine supports the following devices:
34
+
35
+ * SMP (Quad Core Cortex-A7)
36
+ * Generic Interrupt Controller configuration
37
+ * SRAM mappings
38
+ * SDRAM controller
39
+ * Timer device (re-used from Allwinner A10)
40
+ * UART
41
+ * SD/MMC storage controller
42
+ * EMAC ethernet
43
+ * GMAC ethernet
44
+ * Clock Control Unit
45
+ * TWI (I2C)
46
+
47
+Limitations
48
+"""""""""""
49
+
50
+Currently, Banana Pi M2U does *not* support the following features:
51
+
52
+- Graphical output via HDMI, GPU and/or the Display Engine
53
+- Audio output
54
+- Hardware Watchdog
55
+- Real Time Clock
56
+- USB 2.0 interfaces
57
+
58
+Also see the 'unimplemented' array in the Allwinner R40 SoC module
59
+for a complete list of unimplemented I/O devices: ``./hw/arm/allwinner-r40.c``
60
+
61
+Boot options
62
+""""""""""""
63
+
64
+The Banana Pi M2U machine can start using the standard -kernel functionality
65
+for loading a Linux kernel or ELF executable. Additionally, the Banana Pi M2U
66
+machine can also emulate the BootROM which is present on an actual Allwinner R40
67
+based SoC, which loads the bootloader from a SD card, specified via the -sd
68
+argument to qemu-system-arm.
69
+
70
+Running mainline Linux
71
+""""""""""""""""""""""
72
+
73
+To build a Linux mainline kernel that can be booted by the Banana Pi M2U machine,
74
+simply configure the kernel using the sunxi_defconfig configuration:
75
+
76
+.. code-block:: bash
77
+
78
+ $ ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- make mrproper
79
+ $ ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- make sunxi_defconfig
80
+
81
+To boot the newly build linux kernel in QEMU with the Banana Pi M2U machine, use:
82
+
83
+.. code-block:: bash
84
+
85
+ $ qemu-system-arm -M bpim2u -nographic \
86
+ -kernel /path/to/linux/arch/arm/boot/zImage \
87
+ -append 'console=ttyS0,115200' \
88
+ -dtb /path/to/linux/arch/arm/boot/dts/sun8i-r40-bananapi-m2-ultra.dtb
89
+
90
+Banana Pi M2U images
91
+""""""""""""""""""""
92
+
93
+Note that the mainline kernel does not have a root filesystem. You can choose
94
+to build you own image with buildroot using the bananapi_m2_ultra_defconfig.
95
+Also see https://buildroot.org for more information.
96
+
97
+Another possibility is to run an OpenWrt image for Banana Pi M2U which
98
+can be downloaded from:
99
+
100
+ https://downloads.openwrt.org/releases/22.03.3/targets/sunxi/cortexa7/
101
+
102
+When using an image as an SD card, it must be resized to a power of two. This can be
103
+done with the ``qemu-img`` command. It is recommended to only increase the image size
104
+instead of shrinking it to a power of two, to avoid loss of data. For example,
105
+to prepare a downloaded Armbian image, first extract it and then increase
106
+its size to one gigabyte as follows:
107
+
108
+.. code-block:: bash
109
+
110
+ $ qemu-img resize \
111
+ openwrt-22.03.3-sunxi-cortexa7-sinovoip_bananapi-m2-ultra-ext4-sdcard.img \
112
+ 1G
113
+
114
+Instead of providing a custom Linux kernel via the -kernel command you may also
115
+choose to let the Banana Pi M2U machine load the bootloader from SD card, just like
116
+a real board would do using the BootROM. Simply pass the selected image via the -sd
117
+argument and remove the -kernel, -append, -dbt and -initrd arguments:
118
+
119
+.. code-block:: bash
120
+
121
+ $ qemu-system-arm -M bpim2u -nic user -nographic \
122
+ -sd openwrt-22.03.3-sunxi-cortexa7-sinovoip_bananapi-m2-ultra-ext4-sdcard.img
123
+
124
+Running U-Boot
125
+""""""""""""""
126
+
127
+U-Boot mainline can be build and configured using the Bananapi_M2_Ultra_defconfig
128
+using similar commands as describe above for Linux. Note that it is recommended
129
+for development/testing to select the following configuration setting in U-Boot:
130
+
131
+ Device Tree Control > Provider for DTB for DT Control > Embedded DTB
132
+
133
+The BootROM of allwinner R40 loading u-boot from the 8KiB offset of sdcard.
134
+Let's create an bootable disk image:
135
+
136
+.. code-block:: bash
137
+
138
+ $ dd if=/dev/zero of=sd.img bs=32M count=1
139
+ $ dd if=u-boot-sunxi-with-spl.bin of=sd.img bs=1k seek=8 conv=notrunc
140
+
141
+And then boot it.
142
+
143
+.. code-block:: bash
144
+
145
+ $ qemu-system-arm -M bpim2u -nographic -sd sd.img
146
+
147
+Banana Pi M2U integration tests
148
+"""""""""""""""""""""""""""""""
149
+
150
+The Banana Pi M2U machine has several integration tests included.
151
+To run the whole set of tests, build QEMU from source and simply
152
+provide the following command:
153
+
154
+.. code-block:: bash
155
+
156
+ $ cd qemu-build-dir
157
+ $ AVOCADO_ALLOW_LARGE_STORAGE=yes tests/venv/bin/avocado \
158
+ --verbose --show=app,console run -t machine:bpim2u \
159
+ ../tests/avocado/boot_linux_console.py
160
diff --git a/docs/system/target-arm.rst b/docs/system/target-arm.rst
161
index XXXXXXX..XXXXXXX 100644
162
--- a/docs/system/target-arm.rst
163
+++ b/docs/system/target-arm.rst
164
@@ -XXX,XX +XXX,XX @@ undocumented; you can get a complete list by running
165
arm/versatile
166
arm/vexpress
167
arm/aspeed
168
+ arm/bananapi_m2u.rst
169
arm/sabrelite
170
arm/digic
171
arm/cubieboard
172
--
173
2.34.1
diff view generated by jsdifflib
1
From: Leif Lindholm <leif@nuviainc.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
3
Document the meaning of exclusive_high in a big-endian context,
4
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
4
and why we can't change it now.
5
Message-id: 20210108185154.8108-5-leif@nuviainc.com
5
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20230530191438.411344-2-richard.henderson@linaro.org
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
---
10
---
8
target/arm/cpu.h | 31 +++++++++++++++++++++++++++++++
11
target/arm/cpu.h | 8 ++++++++
9
1 file changed, 31 insertions(+)
12
1 file changed, 8 insertions(+)
10
13
11
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
14
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
12
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
13
--- a/target/arm/cpu.h
16
--- a/target/arm/cpu.h
14
+++ b/target/arm/cpu.h
17
+++ b/target/arm/cpu.h
15
@@ -XXX,XX +XXX,XX @@ FIELD(V7M_FPCCR, ASPEN, 31, 1)
18
@@ -XXX,XX +XXX,XX @@ typedef struct CPUArchState {
16
/*
19
uint64_t zcr_el[4]; /* ZCR_EL[1-3] */
17
* System register ID fields.
20
uint64_t smcr_el[4]; /* SMCR_EL[1-3] */
18
*/
21
} vfp;
19
+FIELD(CLIDR_EL1, CTYPE1, 0, 3)
20
+FIELD(CLIDR_EL1, CTYPE2, 3, 3)
21
+FIELD(CLIDR_EL1, CTYPE3, 6, 3)
22
+FIELD(CLIDR_EL1, CTYPE4, 9, 3)
23
+FIELD(CLIDR_EL1, CTYPE5, 12, 3)
24
+FIELD(CLIDR_EL1, CTYPE6, 15, 3)
25
+FIELD(CLIDR_EL1, CTYPE7, 18, 3)
26
+FIELD(CLIDR_EL1, LOUIS, 21, 3)
27
+FIELD(CLIDR_EL1, LOC, 24, 3)
28
+FIELD(CLIDR_EL1, LOUU, 27, 3)
29
+FIELD(CLIDR_EL1, ICB, 30, 3)
30
+
22
+
31
+/* When FEAT_CCIDX is implemented */
23
uint64_t exclusive_addr;
32
+FIELD(CCSIDR_EL1, CCIDX_LINESIZE, 0, 3)
24
uint64_t exclusive_val;
33
+FIELD(CCSIDR_EL1, CCIDX_ASSOCIATIVITY, 3, 21)
25
+ /*
34
+FIELD(CCSIDR_EL1, CCIDX_NUMSETS, 32, 24)
26
+ * Contains the 'val' for the second 64-bit register of LDXP, which comes
35
+
27
+ * from the higher address, not the high part of a complete 128-bit value.
36
+/* When FEAT_CCIDX is not implemented */
28
+ * In some ways it might be more convenient to record the exclusive value
37
+FIELD(CCSIDR_EL1, LINESIZE, 0, 3)
29
+ * as the low and high halves of a 128 bit data value, but the current
38
+FIELD(CCSIDR_EL1, ASSOCIATIVITY, 3, 10)
30
+ * semantics of these fields are baked into the migration format.
39
+FIELD(CCSIDR_EL1, NUMSETS, 13, 15)
31
+ */
40
+
32
uint64_t exclusive_high;
41
+FIELD(CTR_EL0, IMINLINE, 0, 4)
33
42
+FIELD(CTR_EL0, L1IP, 14, 2)
34
/* iwMMXt coprocessor state. */
43
+FIELD(CTR_EL0, DMINLINE, 16, 4)
44
+FIELD(CTR_EL0, ERG, 20, 4)
45
+FIELD(CTR_EL0, CWG, 24, 4)
46
+FIELD(CTR_EL0, IDC, 28, 1)
47
+FIELD(CTR_EL0, DIC, 29, 1)
48
+FIELD(CTR_EL0, TMINLINE, 32, 6)
49
+
50
FIELD(MIDR_EL1, REVISION, 0, 4)
51
FIELD(MIDR_EL1, PARTNUM, 4, 12)
52
FIELD(MIDR_EL1, ARCHITECTURE, 16, 4)
53
--
35
--
54
2.20.1
36
2.34.1
55
56
diff view generated by jsdifflib
1
From: Leif Lindholm <leif@nuviainc.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
When FEAT_MTE is implemented, the AArch64 view of CTR_EL0 adds the
3
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
4
TminLine field in bits [37:32].
4
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
5
Extend the ctr field to be able to hold this context.
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
6
Message-id: 20230530191438.411344-3-richard.henderson@linaro.org
7
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
8
Reviewed-by: Hao Wu <wuhaotsh@google.com>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
11
Message-id: 20210108185154.8108-4-leif@nuviainc.com
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
8
---
14
target/arm/cpu.h | 2 +-
9
target/arm/cpu.h | 5 +++++
15
1 file changed, 1 insertion(+), 1 deletion(-)
10
1 file changed, 5 insertions(+)
16
11
17
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
12
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
18
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/cpu.h
14
--- a/target/arm/cpu.h
20
+++ b/target/arm/cpu.h
15
+++ b/target/arm/cpu.h
21
@@ -XXX,XX +XXX,XX @@ struct ARMCPU {
16
@@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_st(const ARMISARegisters *id)
22
uint64_t midr;
17
return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, ST) != 0;
23
uint32_t revidr;
18
}
24
uint32_t reset_fpsid;
19
25
- uint32_t ctr;
20
+static inline bool isar_feature_aa64_lse2(const ARMISARegisters *id)
26
+ uint64_t ctr;
21
+{
27
uint32_t reset_sctlr;
22
+ return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, AT) != 0;
28
uint64_t pmceid0;
23
+}
29
uint64_t pmceid1;
24
+
25
static inline bool isar_feature_aa64_fwb(const ARMISARegisters *id)
26
{
27
return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, FWB) != 0;
30
--
28
--
31
2.20.1
29
2.34.1
32
30
33
31
diff view generated by jsdifflib
1
The lan9118 code mostly uses symbolic constants for register offsets;
1
From: Richard Henderson <richard.henderson@linaro.org>
2
the exceptions are those which the datasheet doesn't give an official
3
symbolic name to.
4
2
5
Add some names for the registers which don't already have them, based
3
Let finalize_memop_atom be the new basic function, with
6
on the longer names they are given in the memory map.
4
finalize_memop and finalize_memop_pair testing FEAT_LSE2
5
to apply the appropriate atomicity.
7
6
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 20230530191438.411344-4-richard.henderson@linaro.org
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
Message-id: 20210108180401.2263-3-peter.maydell@linaro.org
11
---
12
---
12
hw/net/lan9118.c | 24 ++++++++++++++++++------
13
target/arm/tcg/translate.h | 39 +++++++++++++++++++++++++++++-----
13
1 file changed, 18 insertions(+), 6 deletions(-)
14
target/arm/tcg/translate-a64.c | 2 ++
15
target/arm/tcg/translate.c | 1 +
16
3 files changed, 37 insertions(+), 5 deletions(-)
14
17
15
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
18
diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h
16
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/net/lan9118.c
20
--- a/target/arm/tcg/translate.h
18
+++ b/hw/net/lan9118.c
21
+++ b/target/arm/tcg/translate.h
19
@@ -XXX,XX +XXX,XX @@ do { hw_error("lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
22
@@ -XXX,XX +XXX,XX @@ typedef struct DisasContext {
20
do { fprintf(stderr, "lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
23
uint64_t features; /* CPU features bits */
24
bool aarch64;
25
bool thumb;
26
+ bool lse2;
27
/* Because unallocated encodings generate different exception syndrome
28
* information from traps due to FP being disabled, we can't do a single
29
* "is fp access disabled" check at a high level in the decode tree.
30
@@ -XXX,XX +XXX,XX @@ static inline TCGv_ptr fpstatus_ptr(ARMFPStatusFlavour flavour)
31
}
32
33
/**
34
- * finalize_memop:
35
+ * finalize_memop_atom:
36
* @s: DisasContext
37
* @opc: size+sign+align of the memory operation
38
+ * @atom: atomicity of the memory operation
39
*
40
- * Build the complete MemOp for a memory operation, including alignment
41
- * and endianness.
42
+ * Build the complete MemOp for a memory operation, including alignment,
43
+ * endianness, and atomicity.
44
*
45
* If (op & MO_AMASK) then the operation already contains the required
46
* alignment, e.g. for AccType_ATOMIC. Otherwise, this an optionally
47
@@ -XXX,XX +XXX,XX @@ static inline TCGv_ptr fpstatus_ptr(ARMFPStatusFlavour flavour)
48
* and this is applied here. Note that there is no way to indicate that
49
* no alignment should ever be enforced; this must be handled manually.
50
*/
51
-static inline MemOp finalize_memop(DisasContext *s, MemOp opc)
52
+static inline MemOp finalize_memop_atom(DisasContext *s, MemOp opc, MemOp atom)
53
{
54
if (s->align_mem && !(opc & MO_AMASK)) {
55
opc |= MO_ALIGN;
56
}
57
- return opc | s->be_data;
58
+ return opc | atom | s->be_data;
59
+}
60
+
61
+/**
62
+ * finalize_memop:
63
+ * @s: DisasContext
64
+ * @opc: size+sign+align of the memory operation
65
+ *
66
+ * Like finalize_memop_atom, but with default atomicity.
67
+ */
68
+static inline MemOp finalize_memop(DisasContext *s, MemOp opc)
69
+{
70
+ MemOp atom = s->lse2 ? MO_ATOM_WITHIN16 : MO_ATOM_IFALIGN;
71
+ return finalize_memop_atom(s, opc, atom);
72
+}
73
+
74
+/**
75
+ * finalize_memop_pair:
76
+ * @s: DisasContext
77
+ * @opc: size+sign+align of the memory operation
78
+ *
79
+ * Like finalize_memop_atom, but with atomicity for a pair.
80
+ * C.f. Pseudocode for Mem[], operand ispair.
81
+ */
82
+static inline MemOp finalize_memop_pair(DisasContext *s, MemOp opc)
83
+{
84
+ MemOp atom = s->lse2 ? MO_ATOM_WITHIN16_PAIR : MO_ATOM_IFALIGN_PAIR;
85
+ return finalize_memop_atom(s, opc, atom);
86
}
87
88
/**
89
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
90
index XXXXXXX..XXXXXXX 100644
91
--- a/target/arm/tcg/translate-a64.c
92
+++ b/target/arm/tcg/translate-a64.c
93
@@ -XXX,XX +XXX,XX @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
94
tcg_debug_assert(dc->tbid & 1);
21
#endif
95
#endif
22
96
23
+/* The tx and rx fifo ports are a range of aliased 32-bit registers */
97
+ dc->lse2 = dc_isar_feature(aa64_lse2, dc);
24
+#define RX_DATA_FIFO_PORT_FIRST 0x00
25
+#define RX_DATA_FIFO_PORT_LAST 0x1f
26
+#define TX_DATA_FIFO_PORT_FIRST 0x20
27
+#define TX_DATA_FIFO_PORT_LAST 0x3f
28
+
98
+
29
+#define RX_STATUS_FIFO_PORT 0x40
99
/* Single step state. The code-generation logic here is:
30
+#define RX_STATUS_FIFO_PEEK 0x44
100
* SS_ACTIVE == 0:
31
+#define TX_STATUS_FIFO_PORT 0x48
101
* generate code with no special handling for single-stepping (except
32
+#define TX_STATUS_FIFO_PEEK 0x4c
102
diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c
33
+
103
index XXXXXXX..XXXXXXX 100644
34
#define CSR_ID_REV 0x50
104
--- a/target/arm/tcg/translate.c
35
#define CSR_IRQ_CFG 0x54
105
+++ b/target/arm/tcg/translate.c
36
#define CSR_INT_STS 0x58
106
@@ -XXX,XX +XXX,XX @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
37
@@ -XXX,XX +XXX,XX @@ static void lan9118_writel(void *opaque, hwaddr offset,
107
dc->sme_trap_nonstreaming =
38
offset &= 0xff;
108
EX_TBFLAG_A32(tb_flags, SME_TRAP_NONSTREAMING);
39
40
//DPRINTF("Write reg 0x%02x = 0x%08x\n", (int)offset, val);
41
- if (offset >= 0x20 && offset < 0x40) {
42
+ if (offset >= TX_DATA_FIFO_PORT_FIRST &&
43
+ offset <= TX_DATA_FIFO_PORT_LAST) {
44
/* TX FIFO */
45
tx_fifo_push(s, val);
46
return;
47
@@ -XXX,XX +XXX,XX @@ static uint64_t lan9118_readl(void *opaque, hwaddr offset,
48
lan9118_state *s = (lan9118_state *)opaque;
49
50
//DPRINTF("Read reg 0x%02x\n", (int)offset);
51
- if (offset < 0x20) {
52
+ if (offset <= RX_DATA_FIFO_PORT_LAST) {
53
/* RX FIFO */
54
return rx_fifo_pop(s);
55
}
109
}
56
switch (offset) {
110
+ dc->lse2 = false; /* applies only to aarch64 */
57
- case 0x40:
111
dc->cp_regs = cpu->cp_regs;
58
+ case RX_STATUS_FIFO_PORT:
112
dc->features = env->features;
59
return rx_status_fifo_pop(s);
113
60
- case 0x44:
61
+ case RX_STATUS_FIFO_PEEK:
62
return s->rx_status_fifo[s->rx_status_fifo_head];
63
- case 0x48:
64
+ case TX_STATUS_FIFO_PORT:
65
return tx_status_fifo_pop(s);
66
- case 0x4c:
67
+ case TX_STATUS_FIFO_PEEK:
68
return s->tx_status_fifo[s->tx_status_fifo_head];
69
case CSR_ID_REV:
70
return 0x01180001;
71
--
114
--
72
2.20.1
115
2.34.1
73
116
74
117
diff view generated by jsdifflib
New patch
1
From: Richard Henderson <richard.henderson@linaro.org>
1
2
3
While we don't require 16-byte atomicity here, using a single larger
4
load simplifies the code, and makes it a closer match to STXP.
5
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20230530191438.411344-5-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
target/arm/tcg/translate-a64.c | 31 ++++++++++++++++++++-----------
12
1 file changed, 20 insertions(+), 11 deletions(-)
13
14
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/tcg/translate-a64.c
17
+++ b/target/arm/tcg/translate-a64.c
18
@@ -XXX,XX +XXX,XX @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
19
TCGv_i64 addr, int size, bool is_pair)
20
{
21
int idx = get_mem_index(s);
22
- MemOp memop = s->be_data;
23
+ MemOp memop;
24
25
g_assert(size <= 3);
26
if (is_pair) {
27
g_assert(size >= 2);
28
if (size == 2) {
29
/* The pair must be single-copy atomic for the doubleword. */
30
- memop |= MO_64 | MO_ALIGN;
31
+ memop = finalize_memop(s, MO_64 | MO_ALIGN);
32
tcg_gen_qemu_ld_i64(cpu_exclusive_val, addr, idx, memop);
33
if (s->be_data == MO_LE) {
34
tcg_gen_extract_i64(cpu_reg(s, rt), cpu_exclusive_val, 0, 32);
35
@@ -XXX,XX +XXX,XX @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
36
tcg_gen_extract_i64(cpu_reg(s, rt2), cpu_exclusive_val, 0, 32);
37
}
38
} else {
39
- /* The pair must be single-copy atomic for *each* doubleword, not
40
- the entire quadword, however it must be quadword aligned. */
41
- memop |= MO_64;
42
- tcg_gen_qemu_ld_i64(cpu_exclusive_val, addr, idx,
43
- memop | MO_ALIGN_16);
44
+ /*
45
+ * The pair must be single-copy atomic for *each* doubleword, not
46
+ * the entire quadword, however it must be quadword aligned.
47
+ * Expose the complete load to tcg, for ease of tlb lookup,
48
+ * but indicate that only 8-byte atomicity is required.
49
+ */
50
+ TCGv_i128 t16 = tcg_temp_new_i128();
51
52
- TCGv_i64 addr2 = tcg_temp_new_i64();
53
- tcg_gen_addi_i64(addr2, addr, 8);
54
- tcg_gen_qemu_ld_i64(cpu_exclusive_high, addr2, idx, memop);
55
+ memop = finalize_memop_atom(s, MO_128 | MO_ALIGN_16,
56
+ MO_ATOM_IFALIGN_PAIR);
57
+ tcg_gen_qemu_ld_i128(t16, addr, idx, memop);
58
59
+ if (s->be_data == MO_LE) {
60
+ tcg_gen_extr_i128_i64(cpu_exclusive_val,
61
+ cpu_exclusive_high, t16);
62
+ } else {
63
+ tcg_gen_extr_i128_i64(cpu_exclusive_high,
64
+ cpu_exclusive_val, t16);
65
+ }
66
tcg_gen_mov_i64(cpu_reg(s, rt), cpu_exclusive_val);
67
tcg_gen_mov_i64(cpu_reg(s, rt2), cpu_exclusive_high);
68
}
69
} else {
70
- memop |= size | MO_ALIGN;
71
+ memop = finalize_memop(s, size | MO_ALIGN);
72
tcg_gen_qemu_ld_i64(cpu_exclusive_val, addr, idx, memop);
73
tcg_gen_mov_i64(cpu_reg(s, rt), cpu_exclusive_val);
74
}
75
--
76
2.34.1
diff view generated by jsdifflib
New patch
1
From: Richard Henderson <richard.henderson@linaro.org>
1
2
3
While we don't require 16-byte atomicity here, using a single larger
4
operation simplifies the code. Introduce finalize_memop_asimd for this.
5
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20230530191438.411344-6-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
target/arm/tcg/translate.h | 24 +++++++++++++++++++++++
12
target/arm/tcg/translate-a64.c | 35 +++++++++++-----------------------
13
2 files changed, 35 insertions(+), 24 deletions(-)
14
15
diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h
16
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/tcg/translate.h
18
+++ b/target/arm/tcg/translate.h
19
@@ -XXX,XX +XXX,XX @@ static inline MemOp finalize_memop_pair(DisasContext *s, MemOp opc)
20
return finalize_memop_atom(s, opc, atom);
21
}
22
23
+/**
24
+ * finalize_memop_asimd:
25
+ * @s: DisasContext
26
+ * @opc: size+sign+align of the memory operation
27
+ *
28
+ * Like finalize_memop_atom, but with atomicity of AccessType_ASIMD.
29
+ */
30
+static inline MemOp finalize_memop_asimd(DisasContext *s, MemOp opc)
31
+{
32
+ /*
33
+ * In the pseudocode for Mem[], with AccessType_ASIMD, size == 16,
34
+ * if IsAligned(8), the first case provides separate atomicity for
35
+ * the pair of 64-bit accesses. If !IsAligned(8), the middle cases
36
+ * do not apply, and we're left with the final case of no atomicity.
37
+ * Thus MO_ATOM_IFALIGN_PAIR.
38
+ *
39
+ * For other sizes, normal LSE2 rules apply.
40
+ */
41
+ if ((opc & MO_SIZE) == MO_128) {
42
+ return finalize_memop_atom(s, opc, MO_ATOM_IFALIGN_PAIR);
43
+ }
44
+ return finalize_memop(s, opc);
45
+}
46
+
47
/**
48
* asimd_imm_const: Expand an encoded SIMD constant value
49
*
50
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
51
index XXXXXXX..XXXXXXX 100644
52
--- a/target/arm/tcg/translate-a64.c
53
+++ b/target/arm/tcg/translate-a64.c
54
@@ -XXX,XX +XXX,XX @@ static void do_fp_st(DisasContext *s, int srcidx, TCGv_i64 tcg_addr, int size)
55
{
56
/* This writes the bottom N bits of a 128 bit wide vector to memory */
57
TCGv_i64 tmplo = tcg_temp_new_i64();
58
- MemOp mop;
59
+ MemOp mop = finalize_memop_asimd(s, size);
60
61
tcg_gen_ld_i64(tmplo, cpu_env, fp_reg_offset(s, srcidx, MO_64));
62
63
- if (size < 4) {
64
- mop = finalize_memop(s, size);
65
+ if (size < MO_128) {
66
tcg_gen_qemu_st_i64(tmplo, tcg_addr, get_mem_index(s), mop);
67
} else {
68
- bool be = s->be_data == MO_BE;
69
- TCGv_i64 tcg_hiaddr = tcg_temp_new_i64();
70
TCGv_i64 tmphi = tcg_temp_new_i64();
71
+ TCGv_i128 t16 = tcg_temp_new_i128();
72
73
tcg_gen_ld_i64(tmphi, cpu_env, fp_reg_hi_offset(s, srcidx));
74
+ tcg_gen_concat_i64_i128(t16, tmplo, tmphi);
75
76
- mop = s->be_data | MO_UQ;
77
- tcg_gen_qemu_st_i64(be ? tmphi : tmplo, tcg_addr, get_mem_index(s),
78
- mop | (s->align_mem ? MO_ALIGN_16 : 0));
79
- tcg_gen_addi_i64(tcg_hiaddr, tcg_addr, 8);
80
- tcg_gen_qemu_st_i64(be ? tmplo : tmphi, tcg_hiaddr,
81
- get_mem_index(s), mop);
82
+ tcg_gen_qemu_st_i128(t16, tcg_addr, get_mem_index(s), mop);
83
}
84
}
85
86
@@ -XXX,XX +XXX,XX @@ static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size)
87
/* This always zero-extends and writes to a full 128 bit wide vector */
88
TCGv_i64 tmplo = tcg_temp_new_i64();
89
TCGv_i64 tmphi = NULL;
90
- MemOp mop;
91
+ MemOp mop = finalize_memop_asimd(s, size);
92
93
- if (size < 4) {
94
- mop = finalize_memop(s, size);
95
+ if (size < MO_128) {
96
tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), mop);
97
} else {
98
- bool be = s->be_data == MO_BE;
99
- TCGv_i64 tcg_hiaddr;
100
+ TCGv_i128 t16 = tcg_temp_new_i128();
101
+
102
+ tcg_gen_qemu_ld_i128(t16, tcg_addr, get_mem_index(s), mop);
103
104
tmphi = tcg_temp_new_i64();
105
- tcg_hiaddr = tcg_temp_new_i64();
106
-
107
- mop = s->be_data | MO_UQ;
108
- tcg_gen_qemu_ld_i64(be ? tmphi : tmplo, tcg_addr, get_mem_index(s),
109
- mop | (s->align_mem ? MO_ALIGN_16 : 0));
110
- tcg_gen_addi_i64(tcg_hiaddr, tcg_addr, 8);
111
- tcg_gen_qemu_ld_i64(be ? tmplo : tmphi, tcg_hiaddr,
112
- get_mem_index(s), mop);
113
+ tcg_gen_extr_i128_i64(tmplo, tmphi, t16);
114
}
115
116
tcg_gen_st_i64(tmplo, cpu_env, fp_reg_offset(s, destidx, MO_64));
117
--
118
2.34.1
diff view generated by jsdifflib
New patch
1
From: Richard Henderson <richard.henderson@linaro.org>
1
2
3
This fixes a bug in that these two insns should have been using atomic
4
16-byte stores, since MTE is ARMv8.5 and LSE2 is mandatory from ARMv8.4.
5
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20230530191438.411344-7-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
target/arm/tcg/translate-a64.c | 17 ++++++++++-------
12
1 file changed, 10 insertions(+), 7 deletions(-)
13
14
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/tcg/translate-a64.c
17
+++ b/target/arm/tcg/translate-a64.c
18
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_tag(DisasContext *s, uint32_t insn)
19
20
if (is_zero) {
21
TCGv_i64 clean_addr = clean_data_tbi(s, addr);
22
- TCGv_i64 tcg_zero = tcg_constant_i64(0);
23
+ TCGv_i64 zero64 = tcg_constant_i64(0);
24
+ TCGv_i128 zero128 = tcg_temp_new_i128();
25
int mem_index = get_mem_index(s);
26
- int i, n = (1 + is_pair) << LOG2_TAG_GRANULE;
27
+ MemOp mop = finalize_memop(s, MO_128 | MO_ALIGN);
28
29
- tcg_gen_qemu_st_i64(tcg_zero, clean_addr, mem_index,
30
- MO_UQ | MO_ALIGN_16);
31
- for (i = 8; i < n; i += 8) {
32
- tcg_gen_addi_i64(clean_addr, clean_addr, 8);
33
- tcg_gen_qemu_st_i64(tcg_zero, clean_addr, mem_index, MO_UQ);
34
+ tcg_gen_concat_i64_i128(zero128, zero64, zero64);
35
+
36
+ /* This is 1 or 2 atomic 16-byte operations. */
37
+ tcg_gen_qemu_st_i128(zero128, clean_addr, mem_index, mop);
38
+ if (is_pair) {
39
+ tcg_gen_addi_i64(clean_addr, clean_addr, 16);
40
+ tcg_gen_qemu_st_i128(zero128, clean_addr, mem_index, mop);
41
}
42
}
43
44
--
45
2.34.1
diff view generated by jsdifflib
New patch
1
From: Richard Henderson <richard.henderson@linaro.org>
1
2
3
Round len_align to 16 instead of 8, handling an odd 8-byte as part
4
of the tail. Use MO_ATOM_NONE to indicate that all of these memory
5
ops have only byte atomicity.
6
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20230530191438.411344-8-richard.henderson@linaro.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
12
target/arm/tcg/translate-sve.c | 95 +++++++++++++++++++++++++---------
13
1 file changed, 70 insertions(+), 25 deletions(-)
14
15
diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/tcg/translate-sve.c
18
+++ b/target/arm/tcg/translate-sve.c
19
@@ -XXX,XX +XXX,XX @@ TRANS_FEAT(UCVTF_dd, aa64_sve, gen_gvec_fpst_arg_zpz,
20
void gen_sve_ldr(DisasContext *s, TCGv_ptr base, int vofs,
21
int len, int rn, int imm)
22
{
23
- int len_align = QEMU_ALIGN_DOWN(len, 8);
24
- int len_remain = len % 8;
25
- int nparts = len / 8 + ctpop8(len_remain);
26
+ int len_align = QEMU_ALIGN_DOWN(len, 16);
27
+ int len_remain = len % 16;
28
+ int nparts = len / 16 + ctpop8(len_remain);
29
int midx = get_mem_index(s);
30
TCGv_i64 dirty_addr, clean_addr, t0, t1;
31
+ TCGv_i128 t16;
32
33
dirty_addr = tcg_temp_new_i64();
34
tcg_gen_addi_i64(dirty_addr, cpu_reg_sp(s, rn), imm);
35
@@ -XXX,XX +XXX,XX @@ void gen_sve_ldr(DisasContext *s, TCGv_ptr base, int vofs,
36
int i;
37
38
t0 = tcg_temp_new_i64();
39
- for (i = 0; i < len_align; i += 8) {
40
- tcg_gen_qemu_ld_i64(t0, clean_addr, midx, MO_LEUQ);
41
+ t1 = tcg_temp_new_i64();
42
+ t16 = tcg_temp_new_i128();
43
+
44
+ for (i = 0; i < len_align; i += 16) {
45
+ tcg_gen_qemu_ld_i128(t16, clean_addr, midx,
46
+ MO_LE | MO_128 | MO_ATOM_NONE);
47
+ tcg_gen_extr_i128_i64(t0, t1, t16);
48
tcg_gen_st_i64(t0, base, vofs + i);
49
- tcg_gen_addi_i64(clean_addr, clean_addr, 8);
50
+ tcg_gen_st_i64(t1, base, vofs + i + 8);
51
+ tcg_gen_addi_i64(clean_addr, clean_addr, 16);
52
}
53
} else {
54
TCGLabel *loop = gen_new_label();
55
@@ -XXX,XX +XXX,XX @@ void gen_sve_ldr(DisasContext *s, TCGv_ptr base, int vofs,
56
tcg_gen_movi_ptr(i, 0);
57
gen_set_label(loop);
58
59
- t0 = tcg_temp_new_i64();
60
- tcg_gen_qemu_ld_i64(t0, clean_addr, midx, MO_LEUQ);
61
- tcg_gen_addi_i64(clean_addr, clean_addr, 8);
62
+ t16 = tcg_temp_new_i128();
63
+ tcg_gen_qemu_ld_i128(t16, clean_addr, midx,
64
+ MO_LE | MO_128 | MO_ATOM_NONE);
65
+ tcg_gen_addi_i64(clean_addr, clean_addr, 16);
66
67
tp = tcg_temp_new_ptr();
68
tcg_gen_add_ptr(tp, base, i);
69
- tcg_gen_addi_ptr(i, i, 8);
70
+ tcg_gen_addi_ptr(i, i, 16);
71
+
72
+ t0 = tcg_temp_new_i64();
73
+ t1 = tcg_temp_new_i64();
74
+ tcg_gen_extr_i128_i64(t0, t1, t16);
75
+
76
tcg_gen_st_i64(t0, tp, vofs);
77
+ tcg_gen_st_i64(t1, tp, vofs + 8);
78
79
tcg_gen_brcondi_ptr(TCG_COND_LTU, i, len_align, loop);
80
}
81
@@ -XXX,XX +XXX,XX @@ void gen_sve_ldr(DisasContext *s, TCGv_ptr base, int vofs,
82
* Predicate register loads can be any multiple of 2.
83
* Note that we still store the entire 64-bit unit into cpu_env.
84
*/
85
+ if (len_remain >= 8) {
86
+ t0 = tcg_temp_new_i64();
87
+ tcg_gen_qemu_ld_i64(t0, clean_addr, midx, MO_LEUQ | MO_ATOM_NONE);
88
+ tcg_gen_st_i64(t0, base, vofs + len_align);
89
+ len_remain -= 8;
90
+ len_align += 8;
91
+ if (len_remain) {
92
+ tcg_gen_addi_i64(clean_addr, clean_addr, 8);
93
+ }
94
+ }
95
if (len_remain) {
96
t0 = tcg_temp_new_i64();
97
switch (len_remain) {
98
@@ -XXX,XX +XXX,XX @@ void gen_sve_ldr(DisasContext *s, TCGv_ptr base, int vofs,
99
case 4:
100
case 8:
101
tcg_gen_qemu_ld_i64(t0, clean_addr, midx,
102
- MO_LE | ctz32(len_remain));
103
+ MO_LE | ctz32(len_remain) | MO_ATOM_NONE);
104
break;
105
106
case 6:
107
t1 = tcg_temp_new_i64();
108
- tcg_gen_qemu_ld_i64(t0, clean_addr, midx, MO_LEUL);
109
+ tcg_gen_qemu_ld_i64(t0, clean_addr, midx, MO_LEUL | MO_ATOM_NONE);
110
tcg_gen_addi_i64(clean_addr, clean_addr, 4);
111
- tcg_gen_qemu_ld_i64(t1, clean_addr, midx, MO_LEUW);
112
+ tcg_gen_qemu_ld_i64(t1, clean_addr, midx, MO_LEUW | MO_ATOM_NONE);
113
tcg_gen_deposit_i64(t0, t0, t1, 32, 32);
114
break;
115
116
@@ -XXX,XX +XXX,XX @@ void gen_sve_ldr(DisasContext *s, TCGv_ptr base, int vofs,
117
void gen_sve_str(DisasContext *s, TCGv_ptr base, int vofs,
118
int len, int rn, int imm)
119
{
120
- int len_align = QEMU_ALIGN_DOWN(len, 8);
121
- int len_remain = len % 8;
122
- int nparts = len / 8 + ctpop8(len_remain);
123
+ int len_align = QEMU_ALIGN_DOWN(len, 16);
124
+ int len_remain = len % 16;
125
+ int nparts = len / 16 + ctpop8(len_remain);
126
int midx = get_mem_index(s);
127
- TCGv_i64 dirty_addr, clean_addr, t0;
128
+ TCGv_i64 dirty_addr, clean_addr, t0, t1;
129
+ TCGv_i128 t16;
130
131
dirty_addr = tcg_temp_new_i64();
132
tcg_gen_addi_i64(dirty_addr, cpu_reg_sp(s, rn), imm);
133
@@ -XXX,XX +XXX,XX @@ void gen_sve_str(DisasContext *s, TCGv_ptr base, int vofs,
134
int i;
135
136
t0 = tcg_temp_new_i64();
137
+ t1 = tcg_temp_new_i64();
138
+ t16 = tcg_temp_new_i128();
139
for (i = 0; i < len_align; i += 8) {
140
tcg_gen_ld_i64(t0, base, vofs + i);
141
- tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEUQ);
142
- tcg_gen_addi_i64(clean_addr, clean_addr, 8);
143
+ tcg_gen_ld_i64(t1, base, vofs + i + 8);
144
+ tcg_gen_concat_i64_i128(t16, t0, t1);
145
+ tcg_gen_qemu_st_i128(t16, clean_addr, midx,
146
+ MO_LE | MO_128 | MO_ATOM_NONE);
147
+ tcg_gen_addi_i64(clean_addr, clean_addr, 16);
148
}
149
} else {
150
TCGLabel *loop = gen_new_label();
151
@@ -XXX,XX +XXX,XX @@ void gen_sve_str(DisasContext *s, TCGv_ptr base, int vofs,
152
gen_set_label(loop);
153
154
t0 = tcg_temp_new_i64();
155
+ t1 = tcg_temp_new_i64();
156
tp = tcg_temp_new_ptr();
157
tcg_gen_add_ptr(tp, base, i);
158
tcg_gen_ld_i64(t0, tp, vofs);
159
- tcg_gen_addi_ptr(i, i, 8);
160
+ tcg_gen_ld_i64(t1, tp, vofs + 8);
161
+ tcg_gen_addi_ptr(i, i, 16);
162
163
- tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEUQ);
164
- tcg_gen_addi_i64(clean_addr, clean_addr, 8);
165
+ t16 = tcg_temp_new_i128();
166
+ tcg_gen_concat_i64_i128(t16, t0, t1);
167
+
168
+ tcg_gen_qemu_st_i128(t16, clean_addr, midx, MO_LEUQ);
169
+ tcg_gen_addi_i64(clean_addr, clean_addr, 16);
170
171
tcg_gen_brcondi_ptr(TCG_COND_LTU, i, len_align, loop);
172
}
173
174
/* Predicate register stores can be any multiple of 2. */
175
+ if (len_remain >= 8) {
176
+ t0 = tcg_temp_new_i64();
177
+ tcg_gen_st_i64(t0, base, vofs + len_align);
178
+ tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEUQ | MO_ATOM_NONE);
179
+ len_remain -= 8;
180
+ len_align += 8;
181
+ if (len_remain) {
182
+ tcg_gen_addi_i64(clean_addr, clean_addr, 8);
183
+ }
184
+ }
185
if (len_remain) {
186
t0 = tcg_temp_new_i64();
187
tcg_gen_ld_i64(t0, base, vofs + len_align);
188
@@ -XXX,XX +XXX,XX @@ void gen_sve_str(DisasContext *s, TCGv_ptr base, int vofs,
189
case 4:
190
case 8:
191
tcg_gen_qemu_st_i64(t0, clean_addr, midx,
192
- MO_LE | ctz32(len_remain));
193
+ MO_LE | ctz32(len_remain) | MO_ATOM_NONE);
194
break;
195
196
case 6:
197
- tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEUL);
198
+ tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEUL | MO_ATOM_NONE);
199
tcg_gen_addi_i64(clean_addr, clean_addr, 4);
200
tcg_gen_shri_i64(t0, t0, 32);
201
- tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEUW);
202
+ tcg_gen_qemu_st_i64(t0, clean_addr, midx, MO_LEUW | MO_ATOM_NONE);
203
break;
204
205
default:
206
--
207
2.34.1
diff view generated by jsdifflib
New patch
1
From: Richard Henderson <richard.henderson@linaro.org>
1
2
3
No need to duplicate this check across multiple call sites.
4
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20230530191438.411344-9-richard.henderson@linaro.org
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
10
target/arm/tcg/translate-a64.c | 44 ++++++++++++++++------------------
11
1 file changed, 21 insertions(+), 23 deletions(-)
12
13
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/tcg/translate-a64.c
16
+++ b/target/arm/tcg/translate-a64.c
17
@@ -XXX,XX +XXX,XX @@ static void disas_b_exc_sys(DisasContext *s, uint32_t insn)
18
* races in multi-threaded linux-user and when MTTCG softmmu is
19
* enabled.
20
*/
21
-static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
22
- TCGv_i64 addr, int size, bool is_pair)
23
+static void gen_load_exclusive(DisasContext *s, int rt, int rt2, int rn,
24
+ int size, bool is_pair)
25
{
26
int idx = get_mem_index(s);
27
MemOp memop;
28
+ TCGv_i64 dirty_addr, clean_addr;
29
+
30
+ s->is_ldex = true;
31
+ dirty_addr = cpu_reg_sp(s, rn);
32
+ clean_addr = gen_mte_check1(s, dirty_addr, false, rn != 31, size);
33
34
g_assert(size <= 3);
35
if (is_pair) {
36
@@ -XXX,XX +XXX,XX @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
37
if (size == 2) {
38
/* The pair must be single-copy atomic for the doubleword. */
39
memop = finalize_memop(s, MO_64 | MO_ALIGN);
40
- tcg_gen_qemu_ld_i64(cpu_exclusive_val, addr, idx, memop);
41
+ tcg_gen_qemu_ld_i64(cpu_exclusive_val, clean_addr, idx, memop);
42
if (s->be_data == MO_LE) {
43
tcg_gen_extract_i64(cpu_reg(s, rt), cpu_exclusive_val, 0, 32);
44
tcg_gen_extract_i64(cpu_reg(s, rt2), cpu_exclusive_val, 32, 32);
45
@@ -XXX,XX +XXX,XX @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
46
47
memop = finalize_memop_atom(s, MO_128 | MO_ALIGN_16,
48
MO_ATOM_IFALIGN_PAIR);
49
- tcg_gen_qemu_ld_i128(t16, addr, idx, memop);
50
+ tcg_gen_qemu_ld_i128(t16, clean_addr, idx, memop);
51
52
if (s->be_data == MO_LE) {
53
tcg_gen_extr_i128_i64(cpu_exclusive_val,
54
@@ -XXX,XX +XXX,XX @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
55
}
56
} else {
57
memop = finalize_memop(s, size | MO_ALIGN);
58
- tcg_gen_qemu_ld_i64(cpu_exclusive_val, addr, idx, memop);
59
+ tcg_gen_qemu_ld_i64(cpu_exclusive_val, clean_addr, idx, memop);
60
tcg_gen_mov_i64(cpu_reg(s, rt), cpu_exclusive_val);
61
}
62
- tcg_gen_mov_i64(cpu_exclusive_addr, addr);
63
+ tcg_gen_mov_i64(cpu_exclusive_addr, clean_addr);
64
}
65
66
static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
67
- TCGv_i64 addr, int size, int is_pair)
68
+ int rn, int size, int is_pair)
69
{
70
/* if (env->exclusive_addr == addr && env->exclusive_val == [addr]
71
* && (!is_pair || env->exclusive_high == [addr + datasize])) {
72
@@ -XXX,XX +XXX,XX @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
73
*/
74
TCGLabel *fail_label = gen_new_label();
75
TCGLabel *done_label = gen_new_label();
76
- TCGv_i64 tmp;
77
+ TCGv_i64 tmp, dirty_addr, clean_addr;
78
79
- tcg_gen_brcond_i64(TCG_COND_NE, addr, cpu_exclusive_addr, fail_label);
80
+ dirty_addr = cpu_reg_sp(s, rn);
81
+ clean_addr = gen_mte_check1(s, dirty_addr, true, rn != 31, size);
82
+
83
+ tcg_gen_brcond_i64(TCG_COND_NE, clean_addr, cpu_exclusive_addr, fail_label);
84
85
tmp = tcg_temp_new_i64();
86
if (is_pair) {
87
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
88
if (is_lasr) {
89
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
90
}
91
- clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn),
92
- true, rn != 31, size);
93
- gen_store_exclusive(s, rs, rt, rt2, clean_addr, size, false);
94
+ gen_store_exclusive(s, rs, rt, rt2, rn, size, false);
95
return;
96
97
case 0x4: /* LDXR */
98
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
99
if (rn == 31) {
100
gen_check_sp_alignment(s);
101
}
102
- clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn),
103
- false, rn != 31, size);
104
- s->is_ldex = true;
105
- gen_load_exclusive(s, rt, rt2, clean_addr, size, false);
106
+ gen_load_exclusive(s, rt, rt2, rn, size, false);
107
if (is_lasr) {
108
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
109
}
110
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
111
if (is_lasr) {
112
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
113
}
114
- clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn),
115
- true, rn != 31, size);
116
- gen_store_exclusive(s, rs, rt, rt2, clean_addr, size, true);
117
+ gen_store_exclusive(s, rs, rt, rt2, rn, size, true);
118
return;
119
}
120
if (rt2 == 31
121
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
122
if (rn == 31) {
123
gen_check_sp_alignment(s);
124
}
125
- clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn),
126
- false, rn != 31, size);
127
- s->is_ldex = true;
128
- gen_load_exclusive(s, rt, rt2, clean_addr, size, true);
129
+ gen_load_exclusive(s, rt, rt2, rn, size, true);
130
if (is_lasr) {
131
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
132
}
133
--
134
2.34.1
diff view generated by jsdifflib
New patch
1
From: Richard Henderson <richard.henderson@linaro.org>
1
2
3
This is required for LSE2, where the pair must be treated atomically if
4
it does not cross a 16-byte boundary. But it simplifies the code to do
5
this always.
6
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20230530191438.411344-10-richard.henderson@linaro.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
12
target/arm/tcg/translate-a64.c | 70 ++++++++++++++++++++++++++--------
13
1 file changed, 55 insertions(+), 15 deletions(-)
14
15
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/tcg/translate-a64.c
18
+++ b/target/arm/tcg/translate-a64.c
19
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn)
20
} else {
21
TCGv_i64 tcg_rt = cpu_reg(s, rt);
22
TCGv_i64 tcg_rt2 = cpu_reg(s, rt2);
23
+ MemOp mop = size + 1;
24
+
25
+ /*
26
+ * With LSE2, non-sign-extending pairs are treated atomically if
27
+ * aligned, and if unaligned one of the pair will be completely
28
+ * within a 16-byte block and that element will be atomic.
29
+ * Otherwise each element is separately atomic.
30
+ * In all cases, issue one operation with the correct atomicity.
31
+ *
32
+ * This treats sign-extending loads like zero-extending loads,
33
+ * since that reuses the most code below.
34
+ */
35
+ if (s->align_mem) {
36
+ mop |= (size == 2 ? MO_ALIGN_4 : MO_ALIGN_8);
37
+ }
38
+ mop = finalize_memop_pair(s, mop);
39
40
if (is_load) {
41
- TCGv_i64 tmp = tcg_temp_new_i64();
42
+ if (size == 2) {
43
+ int o2 = s->be_data == MO_LE ? 32 : 0;
44
+ int o1 = o2 ^ 32;
45
46
- /* Do not modify tcg_rt before recognizing any exception
47
- * from the second load.
48
- */
49
- do_gpr_ld(s, tmp, clean_addr, size + is_signed * MO_SIGN,
50
- false, false, 0, false, false);
51
- tcg_gen_addi_i64(clean_addr, clean_addr, 1 << size);
52
- do_gpr_ld(s, tcg_rt2, clean_addr, size + is_signed * MO_SIGN,
53
- false, false, 0, false, false);
54
+ tcg_gen_qemu_ld_i64(tcg_rt, clean_addr, get_mem_index(s), mop);
55
+ if (is_signed) {
56
+ tcg_gen_sextract_i64(tcg_rt2, tcg_rt, o2, 32);
57
+ tcg_gen_sextract_i64(tcg_rt, tcg_rt, o1, 32);
58
+ } else {
59
+ tcg_gen_extract_i64(tcg_rt2, tcg_rt, o2, 32);
60
+ tcg_gen_extract_i64(tcg_rt, tcg_rt, o1, 32);
61
+ }
62
+ } else {
63
+ TCGv_i128 tmp = tcg_temp_new_i128();
64
65
- tcg_gen_mov_i64(tcg_rt, tmp);
66
+ tcg_gen_qemu_ld_i128(tmp, clean_addr, get_mem_index(s), mop);
67
+ if (s->be_data == MO_LE) {
68
+ tcg_gen_extr_i128_i64(tcg_rt, tcg_rt2, tmp);
69
+ } else {
70
+ tcg_gen_extr_i128_i64(tcg_rt2, tcg_rt, tmp);
71
+ }
72
+ }
73
} else {
74
- do_gpr_st(s, tcg_rt, clean_addr, size,
75
- false, 0, false, false);
76
- tcg_gen_addi_i64(clean_addr, clean_addr, 1 << size);
77
- do_gpr_st(s, tcg_rt2, clean_addr, size,
78
- false, 0, false, false);
79
+ if (size == 2) {
80
+ TCGv_i64 tmp = tcg_temp_new_i64();
81
+
82
+ if (s->be_data == MO_LE) {
83
+ tcg_gen_concat32_i64(tmp, tcg_rt, tcg_rt2);
84
+ } else {
85
+ tcg_gen_concat32_i64(tmp, tcg_rt2, tcg_rt);
86
+ }
87
+ tcg_gen_qemu_st_i64(tmp, clean_addr, get_mem_index(s), mop);
88
+ } else {
89
+ TCGv_i128 tmp = tcg_temp_new_i128();
90
+
91
+ if (s->be_data == MO_LE) {
92
+ tcg_gen_concat_i64_i128(tmp, tcg_rt, tcg_rt2);
93
+ } else {
94
+ tcg_gen_concat_i64_i128(tmp, tcg_rt2, tcg_rt);
95
+ }
96
+ tcg_gen_qemu_st_i128(tmp, clean_addr, get_mem_index(s), mop);
97
+ }
98
}
99
}
100
101
--
102
2.34.1
diff view generated by jsdifflib
New patch
1
From: Richard Henderson <richard.henderson@linaro.org>
1
2
3
We are going to need the complete memop beforehand,
4
so let's not compute it twice.
5
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20230530191438.411344-11-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
target/arm/tcg/translate-a64.c | 61 +++++++++++++++++++---------------
12
1 file changed, 35 insertions(+), 26 deletions(-)
13
14
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/tcg/translate-a64.c
17
+++ b/target/arm/tcg/translate-a64.c
18
@@ -XXX,XX +XXX,XX @@ static void do_gpr_st_memidx(DisasContext *s, TCGv_i64 source,
19
unsigned int iss_srt,
20
bool iss_sf, bool iss_ar)
21
{
22
- memop = finalize_memop(s, memop);
23
tcg_gen_qemu_st_i64(source, tcg_addr, memidx, memop);
24
25
if (iss_valid) {
26
@@ -XXX,XX +XXX,XX @@ static void do_gpr_ld_memidx(DisasContext *s, TCGv_i64 dest, TCGv_i64 tcg_addr,
27
bool iss_valid, unsigned int iss_srt,
28
bool iss_sf, bool iss_ar)
29
{
30
- memop = finalize_memop(s, memop);
31
tcg_gen_qemu_ld_i64(dest, tcg_addr, memidx, memop);
32
33
if (extend && (memop & MO_SIGN)) {
34
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
35
int o2_L_o1_o0 = extract32(insn, 21, 3) * 2 | is_lasr;
36
int size = extract32(insn, 30, 2);
37
TCGv_i64 clean_addr;
38
+ MemOp memop;
39
40
switch (o2_L_o1_o0) {
41
case 0x0: /* STXR */
42
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
43
gen_check_sp_alignment(s);
44
}
45
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
46
+ /* TODO: ARMv8.4-LSE SCTLR.nAA */
47
+ memop = finalize_memop(s, size | MO_ALIGN);
48
clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn),
49
true, rn != 31, size);
50
- /* TODO: ARMv8.4-LSE SCTLR.nAA */
51
- do_gpr_st(s, cpu_reg(s, rt), clean_addr, size | MO_ALIGN, true, rt,
52
+ do_gpr_st(s, cpu_reg(s, rt), clean_addr, memop, true, rt,
53
disas_ldst_compute_iss_sf(size, false, 0), is_lasr);
54
return;
55
56
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
57
if (rn == 31) {
58
gen_check_sp_alignment(s);
59
}
60
+ /* TODO: ARMv8.4-LSE SCTLR.nAA */
61
+ memop = finalize_memop(s, size | MO_ALIGN);
62
clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn),
63
false, rn != 31, size);
64
- /* TODO: ARMv8.4-LSE SCTLR.nAA */
65
- do_gpr_ld(s, cpu_reg(s, rt), clean_addr, size | MO_ALIGN, false, true,
66
+ do_gpr_ld(s, cpu_reg(s, rt), clean_addr, memop, false, true,
67
rt, disas_ldst_compute_iss_sf(size, false, 0), is_lasr);
68
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
69
return;
70
@@ -XXX,XX +XXX,XX @@ static void disas_ld_lit(DisasContext *s, uint32_t insn)
71
} else {
72
/* Only unsigned 32bit loads target 32bit registers. */
73
bool iss_sf = opc != 0;
74
+ MemOp memop = finalize_memop(s, size + is_signed * MO_SIGN);
75
76
- do_gpr_ld(s, tcg_rt, clean_addr, size + is_signed * MO_SIGN,
77
- false, true, rt, iss_sf, false);
78
+ do_gpr_ld(s, tcg_rt, clean_addr, memop, false, true, rt, iss_sf, false);
79
}
80
}
81
82
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn,
83
bool post_index;
84
bool writeback;
85
int memidx;
86
-
87
+ MemOp memop;
88
TCGv_i64 clean_addr, dirty_addr;
89
90
if (is_vector) {
91
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn,
92
return;
93
}
94
is_store = (opc == 0);
95
- is_signed = extract32(opc, 1, 1);
96
+ is_signed = !is_store && extract32(opc, 1, 1);
97
is_extended = (size < 3) && extract32(opc, 0, 1);
98
}
99
100
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn,
101
}
102
103
memidx = is_unpriv ? get_a64_user_mem_index(s) : get_mem_index(s);
104
+ memop = finalize_memop(s, size + is_signed * MO_SIGN);
105
+
106
clean_addr = gen_mte_check1_mmuidx(s, dirty_addr, is_store,
107
writeback || rn != 31,
108
size, is_unpriv, memidx);
109
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn,
110
bool iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc);
111
112
if (is_store) {
113
- do_gpr_st_memidx(s, tcg_rt, clean_addr, size, memidx,
114
+ do_gpr_st_memidx(s, tcg_rt, clean_addr, memop, memidx,
115
iss_valid, rt, iss_sf, false);
116
} else {
117
- do_gpr_ld_memidx(s, tcg_rt, clean_addr, size + is_signed * MO_SIGN,
118
+ do_gpr_ld_memidx(s, tcg_rt, clean_addr, memop,
119
is_extended, memidx,
120
iss_valid, rt, iss_sf, false);
121
}
122
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn,
123
bool is_signed = false;
124
bool is_store = false;
125
bool is_extended = false;
126
-
127
TCGv_i64 tcg_rm, clean_addr, dirty_addr;
128
+ MemOp memop;
129
130
if (extract32(opt, 1, 1) == 0) {
131
unallocated_encoding(s);
132
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn,
133
return;
134
}
135
is_store = (opc == 0);
136
- is_signed = extract32(opc, 1, 1);
137
+ is_signed = !is_store && extract32(opc, 1, 1);
138
is_extended = (size < 3) && extract32(opc, 0, 1);
139
}
140
141
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn,
142
ext_and_shift_reg(tcg_rm, tcg_rm, opt, shift ? size : 0);
143
144
tcg_gen_add_i64(dirty_addr, dirty_addr, tcg_rm);
145
+
146
+ memop = finalize_memop(s, size + is_signed * MO_SIGN);
147
clean_addr = gen_mte_check1(s, dirty_addr, is_store, true, size);
148
149
if (is_vector) {
150
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn,
151
} else {
152
TCGv_i64 tcg_rt = cpu_reg(s, rt);
153
bool iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc);
154
+
155
if (is_store) {
156
- do_gpr_st(s, tcg_rt, clean_addr, size,
157
+ do_gpr_st(s, tcg_rt, clean_addr, memop,
158
true, rt, iss_sf, false);
159
} else {
160
- do_gpr_ld(s, tcg_rt, clean_addr, size + is_signed * MO_SIGN,
161
+ do_gpr_ld(s, tcg_rt, clean_addr, memop,
162
is_extended, true, rt, iss_sf, false);
163
}
164
}
165
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn,
166
int rn = extract32(insn, 5, 5);
167
unsigned int imm12 = extract32(insn, 10, 12);
168
unsigned int offset;
169
-
170
TCGv_i64 clean_addr, dirty_addr;
171
-
172
bool is_store;
173
bool is_signed = false;
174
bool is_extended = false;
175
+ MemOp memop;
176
177
if (is_vector) {
178
size |= (opc & 2) << 1;
179
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn,
180
return;
181
}
182
is_store = (opc == 0);
183
- is_signed = extract32(opc, 1, 1);
184
+ is_signed = !is_store && extract32(opc, 1, 1);
185
is_extended = (size < 3) && extract32(opc, 0, 1);
186
}
187
188
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn,
189
dirty_addr = read_cpu_reg_sp(s, rn, 1);
190
offset = imm12 << size;
191
tcg_gen_addi_i64(dirty_addr, dirty_addr, offset);
192
+
193
+ memop = finalize_memop(s, size + is_signed * MO_SIGN);
194
clean_addr = gen_mte_check1(s, dirty_addr, is_store, rn != 31, size);
195
196
if (is_vector) {
197
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn,
198
TCGv_i64 tcg_rt = cpu_reg(s, rt);
199
bool iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc);
200
if (is_store) {
201
- do_gpr_st(s, tcg_rt, clean_addr, size,
202
- true, rt, iss_sf, false);
203
+ do_gpr_st(s, tcg_rt, clean_addr, memop, true, rt, iss_sf, false);
204
} else {
205
- do_gpr_ld(s, tcg_rt, clean_addr, size + is_signed * MO_SIGN,
206
+ do_gpr_ld(s, tcg_rt, clean_addr, memop,
207
is_extended, true, rt, iss_sf, false);
208
}
209
}
210
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn,
211
bool a = extract32(insn, 23, 1);
212
TCGv_i64 tcg_rs, tcg_rt, clean_addr;
213
AtomicThreeOpFn *fn = NULL;
214
- MemOp mop = s->be_data | size | MO_ALIGN;
215
+ MemOp mop = finalize_memop(s, size | MO_ALIGN);
216
217
if (is_vector || !dc_isar_feature(aa64_atomics, s)) {
218
unallocated_encoding(s);
219
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn,
220
* full load-acquire (we only need "load-acquire processor consistent"),
221
* but we choose to implement them as full LDAQ.
222
*/
223
- do_gpr_ld(s, cpu_reg(s, rt), clean_addr, size, false,
224
+ do_gpr_ld(s, cpu_reg(s, rt), clean_addr, mop, false,
225
true, rt, disas_ldst_compute_iss_sf(size, false, 0), true);
226
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
227
return;
228
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_pac(DisasContext *s, uint32_t insn,
229
bool use_key_a = !extract32(insn, 23, 1);
230
int offset;
231
TCGv_i64 clean_addr, dirty_addr, tcg_rt;
232
+ MemOp memop;
233
234
if (size != 3 || is_vector || !dc_isar_feature(aa64_pauth, s)) {
235
unallocated_encoding(s);
236
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_pac(DisasContext *s, uint32_t insn,
237
offset = sextract32(offset << size, 0, 10 + size);
238
tcg_gen_addi_i64(dirty_addr, dirty_addr, offset);
239
240
+ memop = finalize_memop(s, size);
241
+
242
/* Note that "clean" and "dirty" here refer to TBI not PAC. */
243
clean_addr = gen_mte_check1(s, dirty_addr, false,
244
is_wback || rn != 31, size);
245
246
tcg_rt = cpu_reg(s, rt);
247
- do_gpr_ld(s, tcg_rt, clean_addr, size,
248
+ do_gpr_ld(s, tcg_rt, clean_addr, memop,
249
/* extend */ false, /* iss_valid */ !is_wback,
250
/* iss_srt */ rt, /* iss_sf */ true, /* iss_ar */ false);
251
252
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_ldapr_stlr(DisasContext *s, uint32_t insn)
253
}
254
255
/* TODO: ARMv8.4-LSE SCTLR.nAA */
256
- mop = size | MO_ALIGN;
257
+ mop = finalize_memop(s, size | MO_ALIGN);
258
259
switch (opc) {
260
case 0: /* STLURB */
261
--
262
2.34.1
diff view generated by jsdifflib
1
In commit 1982e1602d15 we added a new qemu-storage-daemon(1) manpage.
1
From: Richard Henderson <richard.henderson@linaro.org>
2
At the moment new manpages have to be listed both in the conf.py for
3
Sphinx and also in docs/meson.build for Meson. We forgot the second
4
of those -- correct the omission.
5
2
3
We are going to need the complete memop beforehand,
4
so let's not compute it twice.
5
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20230530191438.411344-12-richard.henderson@linaro.org
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
9
Message-id: 20210108161416.21129-2-peter.maydell@linaro.org
10
---
11
---
11
docs/meson.build | 1 +
12
target/arm/tcg/translate-a64.c | 43 ++++++++++++++++++----------------
12
1 file changed, 1 insertion(+)
13
1 file changed, 23 insertions(+), 20 deletions(-)
13
14
14
diff --git a/docs/meson.build b/docs/meson.build
15
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
15
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
16
--- a/docs/meson.build
17
--- a/target/arm/tcg/translate-a64.c
17
+++ b/docs/meson.build
18
+++ b/target/arm/tcg/translate-a64.c
18
@@ -XXX,XX +XXX,XX @@ if build_docs
19
@@ -XXX,XX +XXX,XX @@ static void do_gpr_ld(DisasContext *s, TCGv_i64 dest, TCGv_i64 tcg_addr,
19
'qemu-img.1': (have_tools ? 'man1' : ''),
20
/*
20
'qemu-nbd.8': (have_tools ? 'man8' : ''),
21
* Store from FP register to memory
21
'qemu-pr-helper.8': (have_tools ? 'man8' : ''),
22
*/
22
+ 'qemu-storage-daemon.1': (have_tools ? 'man1' : ''),
23
-static void do_fp_st(DisasContext *s, int srcidx, TCGv_i64 tcg_addr, int size)
23
'qemu-trace-stap.1': (config_host.has_key('CONFIG_TRACE_SYSTEMTAP') ? 'man1' : ''),
24
+static void do_fp_st(DisasContext *s, int srcidx, TCGv_i64 tcg_addr, MemOp mop)
24
'virtfs-proxy-helper.1': (have_virtfs_proxy_helper ? 'man1' : ''),
25
{
25
'virtiofsd.1': (have_virtiofsd ? 'man1' : ''),
26
/* This writes the bottom N bits of a 128 bit wide vector to memory */
27
TCGv_i64 tmplo = tcg_temp_new_i64();
28
- MemOp mop = finalize_memop_asimd(s, size);
29
30
tcg_gen_ld_i64(tmplo, cpu_env, fp_reg_offset(s, srcidx, MO_64));
31
32
- if (size < MO_128) {
33
+ if ((mop & MO_SIZE) < MO_128) {
34
tcg_gen_qemu_st_i64(tmplo, tcg_addr, get_mem_index(s), mop);
35
} else {
36
TCGv_i64 tmphi = tcg_temp_new_i64();
37
@@ -XXX,XX +XXX,XX @@ static void do_fp_st(DisasContext *s, int srcidx, TCGv_i64 tcg_addr, int size)
38
/*
39
* Load from memory to FP register
40
*/
41
-static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size)
42
+static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, MemOp mop)
43
{
44
/* This always zero-extends and writes to a full 128 bit wide vector */
45
TCGv_i64 tmplo = tcg_temp_new_i64();
46
TCGv_i64 tmphi = NULL;
47
- MemOp mop = finalize_memop_asimd(s, size);
48
49
- if (size < MO_128) {
50
+ if ((mop & MO_SIZE) < MO_128) {
51
tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), mop);
52
} else {
53
TCGv_i128 t16 = tcg_temp_new_i128();
54
@@ -XXX,XX +XXX,XX @@ static void disas_ld_lit(DisasContext *s, uint32_t insn)
55
bool is_signed = false;
56
int size = 2;
57
TCGv_i64 tcg_rt, clean_addr;
58
+ MemOp memop;
59
60
if (is_vector) {
61
if (opc == 3) {
62
@@ -XXX,XX +XXX,XX @@ static void disas_ld_lit(DisasContext *s, uint32_t insn)
63
if (!fp_access_check(s)) {
64
return;
65
}
66
+ memop = finalize_memop_asimd(s, size);
67
} else {
68
if (opc == 3) {
69
/* PRFM (literal) : prefetch */
70
@@ -XXX,XX +XXX,XX @@ static void disas_ld_lit(DisasContext *s, uint32_t insn)
71
}
72
size = 2 + extract32(opc, 0, 1);
73
is_signed = extract32(opc, 1, 1);
74
+ memop = finalize_memop(s, size + is_signed * MO_SIGN);
75
}
76
77
tcg_rt = cpu_reg(s, rt);
78
79
clean_addr = tcg_temp_new_i64();
80
gen_pc_plus_diff(s, clean_addr, imm);
81
+
82
if (is_vector) {
83
- do_fp_ld(s, rt, clean_addr, size);
84
+ do_fp_ld(s, rt, clean_addr, memop);
85
} else {
86
/* Only unsigned 32bit loads target 32bit registers. */
87
bool iss_sf = opc != 0;
88
- MemOp memop = finalize_memop(s, size + is_signed * MO_SIGN);
89
-
90
do_gpr_ld(s, tcg_rt, clean_addr, memop, false, true, rt, iss_sf, false);
91
}
92
}
93
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn)
94
(wback || rn != 31) && !set_tag, 2 << size);
95
96
if (is_vector) {
97
+ MemOp mop = finalize_memop_asimd(s, size);
98
+
99
if (is_load) {
100
- do_fp_ld(s, rt, clean_addr, size);
101
+ do_fp_ld(s, rt, clean_addr, mop);
102
} else {
103
- do_fp_st(s, rt, clean_addr, size);
104
+ do_fp_st(s, rt, clean_addr, mop);
105
}
106
tcg_gen_addi_i64(clean_addr, clean_addr, 1 << size);
107
if (is_load) {
108
- do_fp_ld(s, rt2, clean_addr, size);
109
+ do_fp_ld(s, rt2, clean_addr, mop);
110
} else {
111
- do_fp_st(s, rt2, clean_addr, size);
112
+ do_fp_st(s, rt2, clean_addr, mop);
113
}
114
} else {
115
TCGv_i64 tcg_rt = cpu_reg(s, rt);
116
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn,
117
if (!fp_access_check(s)) {
118
return;
119
}
120
+ memop = finalize_memop_asimd(s, size);
121
} else {
122
if (size == 3 && opc == 2) {
123
/* PRFM - prefetch */
124
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn,
125
is_store = (opc == 0);
126
is_signed = !is_store && extract32(opc, 1, 1);
127
is_extended = (size < 3) && extract32(opc, 0, 1);
128
+ memop = finalize_memop(s, size + is_signed * MO_SIGN);
129
}
130
131
switch (idx) {
132
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn,
133
}
134
135
memidx = is_unpriv ? get_a64_user_mem_index(s) : get_mem_index(s);
136
- memop = finalize_memop(s, size + is_signed * MO_SIGN);
137
138
clean_addr = gen_mte_check1_mmuidx(s, dirty_addr, is_store,
139
writeback || rn != 31,
140
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn,
141
142
if (is_vector) {
143
if (is_store) {
144
- do_fp_st(s, rt, clean_addr, size);
145
+ do_fp_st(s, rt, clean_addr, memop);
146
} else {
147
- do_fp_ld(s, rt, clean_addr, size);
148
+ do_fp_ld(s, rt, clean_addr, memop);
149
}
150
} else {
151
TCGv_i64 tcg_rt = cpu_reg(s, rt);
152
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn,
153
154
if (is_vector) {
155
if (is_store) {
156
- do_fp_st(s, rt, clean_addr, size);
157
+ do_fp_st(s, rt, clean_addr, memop);
158
} else {
159
- do_fp_ld(s, rt, clean_addr, size);
160
+ do_fp_ld(s, rt, clean_addr, memop);
161
}
162
} else {
163
TCGv_i64 tcg_rt = cpu_reg(s, rt);
164
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn,
165
166
if (is_vector) {
167
if (is_store) {
168
- do_fp_st(s, rt, clean_addr, size);
169
+ do_fp_st(s, rt, clean_addr, memop);
170
} else {
171
- do_fp_ld(s, rt, clean_addr, size);
172
+ do_fp_ld(s, rt, clean_addr, memop);
173
}
174
} else {
175
TCGv_i64 tcg_rt = cpu_reg(s, rt);
26
--
176
--
27
2.20.1
177
2.34.1
28
178
29
179
diff view generated by jsdifflib
New patch
1
From: Richard Henderson <richard.henderson@linaro.org>
1
2
3
Pass the completed memop to gen_mte_check1_mmuidx.
4
For the moment, do nothing more than extract the size.
5
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20230530191438.411344-13-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
target/arm/tcg/translate-a64.h | 2 +-
12
target/arm/tcg/translate-a64.c | 82 ++++++++++++++++++----------------
13
target/arm/tcg/translate-sve.c | 7 +--
14
3 files changed, 49 insertions(+), 42 deletions(-)
15
16
diff --git a/target/arm/tcg/translate-a64.h b/target/arm/tcg/translate-a64.h
17
index XXXXXXX..XXXXXXX 100644
18
--- a/target/arm/tcg/translate-a64.h
19
+++ b/target/arm/tcg/translate-a64.h
20
@@ -XXX,XX +XXX,XX @@ static inline bool sme_smza_enabled_check(DisasContext *s)
21
22
TCGv_i64 clean_data_tbi(DisasContext *s, TCGv_i64 addr);
23
TCGv_i64 gen_mte_check1(DisasContext *s, TCGv_i64 addr, bool is_write,
24
- bool tag_checked, int log2_size);
25
+ bool tag_checked, MemOp memop);
26
TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write,
27
bool tag_checked, int size);
28
29
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/target/arm/tcg/translate-a64.c
32
+++ b/target/arm/tcg/translate-a64.c
33
@@ -XXX,XX +XXX,XX @@ static void gen_probe_access(DisasContext *s, TCGv_i64 ptr,
34
*/
35
static TCGv_i64 gen_mte_check1_mmuidx(DisasContext *s, TCGv_i64 addr,
36
bool is_write, bool tag_checked,
37
- int log2_size, bool is_unpriv,
38
+ MemOp memop, bool is_unpriv,
39
int core_idx)
40
{
41
if (tag_checked && s->mte_active[is_unpriv]) {
42
@@ -XXX,XX +XXX,XX @@ static TCGv_i64 gen_mte_check1_mmuidx(DisasContext *s, TCGv_i64 addr,
43
desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid);
44
desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma);
45
desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write);
46
- desc = FIELD_DP32(desc, MTEDESC, SIZEM1, (1 << log2_size) - 1);
47
+ desc = FIELD_DP32(desc, MTEDESC, SIZEM1, memop_size(memop) - 1);
48
49
ret = tcg_temp_new_i64();
50
gen_helper_mte_check(ret, cpu_env, tcg_constant_i32(desc), addr);
51
@@ -XXX,XX +XXX,XX @@ static TCGv_i64 gen_mte_check1_mmuidx(DisasContext *s, TCGv_i64 addr,
52
}
53
54
TCGv_i64 gen_mte_check1(DisasContext *s, TCGv_i64 addr, bool is_write,
55
- bool tag_checked, int log2_size)
56
+ bool tag_checked, MemOp memop)
57
{
58
- return gen_mte_check1_mmuidx(s, addr, is_write, tag_checked, log2_size,
59
+ return gen_mte_check1_mmuidx(s, addr, is_write, tag_checked, memop,
60
false, get_mem_index(s));
61
}
62
63
@@ -XXX,XX +XXX,XX @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2, int rn,
64
int size, bool is_pair)
65
{
66
int idx = get_mem_index(s);
67
- MemOp memop;
68
TCGv_i64 dirty_addr, clean_addr;
69
+ MemOp memop;
70
+
71
+ /*
72
+ * For pairs:
73
+ * if size == 2, the operation is single-copy atomic for the doubleword.
74
+ * if size == 3, the operation is single-copy atomic for *each* doubleword,
75
+ * not the entire quadword, however it must be quadword aligned.
76
+ */
77
+ memop = size + is_pair;
78
+ if (memop == MO_128) {
79
+ memop = finalize_memop_atom(s, MO_128 | MO_ALIGN,
80
+ MO_ATOM_IFALIGN_PAIR);
81
+ } else {
82
+ memop = finalize_memop(s, memop | MO_ALIGN);
83
+ }
84
85
s->is_ldex = true;
86
dirty_addr = cpu_reg_sp(s, rn);
87
- clean_addr = gen_mte_check1(s, dirty_addr, false, rn != 31, size);
88
+ clean_addr = gen_mte_check1(s, dirty_addr, false, rn != 31, memop);
89
90
g_assert(size <= 3);
91
if (is_pair) {
92
g_assert(size >= 2);
93
if (size == 2) {
94
- /* The pair must be single-copy atomic for the doubleword. */
95
- memop = finalize_memop(s, MO_64 | MO_ALIGN);
96
tcg_gen_qemu_ld_i64(cpu_exclusive_val, clean_addr, idx, memop);
97
if (s->be_data == MO_LE) {
98
tcg_gen_extract_i64(cpu_reg(s, rt), cpu_exclusive_val, 0, 32);
99
@@ -XXX,XX +XXX,XX @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2, int rn,
100
tcg_gen_extract_i64(cpu_reg(s, rt2), cpu_exclusive_val, 0, 32);
101
}
102
} else {
103
- /*
104
- * The pair must be single-copy atomic for *each* doubleword, not
105
- * the entire quadword, however it must be quadword aligned.
106
- * Expose the complete load to tcg, for ease of tlb lookup,
107
- * but indicate that only 8-byte atomicity is required.
108
- */
109
TCGv_i128 t16 = tcg_temp_new_i128();
110
111
- memop = finalize_memop_atom(s, MO_128 | MO_ALIGN_16,
112
- MO_ATOM_IFALIGN_PAIR);
113
tcg_gen_qemu_ld_i128(t16, clean_addr, idx, memop);
114
115
if (s->be_data == MO_LE) {
116
@@ -XXX,XX +XXX,XX @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2, int rn,
117
tcg_gen_mov_i64(cpu_reg(s, rt2), cpu_exclusive_high);
118
}
119
} else {
120
- memop = finalize_memop(s, size | MO_ALIGN);
121
tcg_gen_qemu_ld_i64(cpu_exclusive_val, clean_addr, idx, memop);
122
tcg_gen_mov_i64(cpu_reg(s, rt), cpu_exclusive_val);
123
}
124
@@ -XXX,XX +XXX,XX @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
125
TCGLabel *fail_label = gen_new_label();
126
TCGLabel *done_label = gen_new_label();
127
TCGv_i64 tmp, dirty_addr, clean_addr;
128
+ MemOp memop;
129
+
130
+ memop = (size + is_pair) | MO_ALIGN;
131
+ memop = finalize_memop(s, memop);
132
133
dirty_addr = cpu_reg_sp(s, rn);
134
- clean_addr = gen_mte_check1(s, dirty_addr, true, rn != 31, size);
135
+ clean_addr = gen_mte_check1(s, dirty_addr, true, rn != 31, memop);
136
137
tcg_gen_brcond_i64(TCG_COND_NE, clean_addr, cpu_exclusive_addr, fail_label);
138
139
@@ -XXX,XX +XXX,XX @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
140
}
141
tcg_gen_atomic_cmpxchg_i64(tmp, cpu_exclusive_addr,
142
cpu_exclusive_val, tmp,
143
- get_mem_index(s),
144
- MO_64 | MO_ALIGN | s->be_data);
145
+ get_mem_index(s), memop);
146
tcg_gen_setcond_i64(TCG_COND_NE, tmp, tmp, cpu_exclusive_val);
147
} else {
148
TCGv_i128 t16 = tcg_temp_new_i128();
149
@@ -XXX,XX +XXX,XX @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
150
}
151
152
tcg_gen_atomic_cmpxchg_i128(t16, cpu_exclusive_addr, c16, t16,
153
- get_mem_index(s),
154
- MO_128 | MO_ALIGN | s->be_data);
155
+ get_mem_index(s), memop);
156
157
a = tcg_temp_new_i64();
158
b = tcg_temp_new_i64();
159
@@ -XXX,XX +XXX,XX @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
160
}
161
} else {
162
tcg_gen_atomic_cmpxchg_i64(tmp, cpu_exclusive_addr, cpu_exclusive_val,
163
- cpu_reg(s, rt), get_mem_index(s),
164
- size | MO_ALIGN | s->be_data);
165
+ cpu_reg(s, rt), get_mem_index(s), memop);
166
tcg_gen_setcond_i64(TCG_COND_NE, tmp, tmp, cpu_exclusive_val);
167
}
168
tcg_gen_mov_i64(cpu_reg(s, rd), tmp);
169
@@ -XXX,XX +XXX,XX @@ static void gen_compare_and_swap(DisasContext *s, int rs, int rt,
170
TCGv_i64 tcg_rt = cpu_reg(s, rt);
171
int memidx = get_mem_index(s);
172
TCGv_i64 clean_addr;
173
+ MemOp memop;
174
175
if (rn == 31) {
176
gen_check_sp_alignment(s);
177
}
178
- clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), true, rn != 31, size);
179
- tcg_gen_atomic_cmpxchg_i64(tcg_rs, clean_addr, tcg_rs, tcg_rt, memidx,
180
- size | MO_ALIGN | s->be_data);
181
+ memop = finalize_memop(s, size | MO_ALIGN);
182
+ clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), true, rn != 31, memop);
183
+ tcg_gen_atomic_cmpxchg_i64(tcg_rs, clean_addr, tcg_rs, tcg_rt,
184
+ memidx, memop);
185
}
186
187
static void gen_compare_and_swap_pair(DisasContext *s, int rs, int rt,
188
@@ -XXX,XX +XXX,XX @@ static void gen_compare_and_swap_pair(DisasContext *s, int rs, int rt,
189
TCGv_i64 t2 = cpu_reg(s, rt + 1);
190
TCGv_i64 clean_addr;
191
int memidx = get_mem_index(s);
192
+ MemOp memop;
193
194
if (rn == 31) {
195
gen_check_sp_alignment(s);
196
}
197
198
/* This is a single atomic access, despite the "pair". */
199
- clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), true, rn != 31, size + 1);
200
+ memop = finalize_memop(s, (size + 1) | MO_ALIGN);
201
+ clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), true, rn != 31, memop);
202
203
if (size == 2) {
204
TCGv_i64 cmp = tcg_temp_new_i64();
205
@@ -XXX,XX +XXX,XX @@ static void gen_compare_and_swap_pair(DisasContext *s, int rs, int rt,
206
tcg_gen_concat32_i64(cmp, s2, s1);
207
}
208
209
- tcg_gen_atomic_cmpxchg_i64(cmp, clean_addr, cmp, val, memidx,
210
- MO_64 | MO_ALIGN | s->be_data);
211
+ tcg_gen_atomic_cmpxchg_i64(cmp, clean_addr, cmp, val, memidx, memop);
212
213
if (s->be_data == MO_LE) {
214
tcg_gen_extr32_i64(s1, s2, cmp);
215
@@ -XXX,XX +XXX,XX @@ static void gen_compare_and_swap_pair(DisasContext *s, int rs, int rt,
216
tcg_gen_concat_i64_i128(cmp, s2, s1);
217
}
218
219
- tcg_gen_atomic_cmpxchg_i128(cmp, clean_addr, cmp, val, memidx,
220
- MO_128 | MO_ALIGN | s->be_data);
221
+ tcg_gen_atomic_cmpxchg_i128(cmp, clean_addr, cmp, val, memidx, memop);
222
223
if (s->be_data == MO_LE) {
224
tcg_gen_extr_i128_i64(s1, s2, cmp);
225
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
226
/* TODO: ARMv8.4-LSE SCTLR.nAA */
227
memop = finalize_memop(s, size | MO_ALIGN);
228
clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn),
229
- true, rn != 31, size);
230
+ true, rn != 31, memop);
231
do_gpr_st(s, cpu_reg(s, rt), clean_addr, memop, true, rt,
232
disas_ldst_compute_iss_sf(size, false, 0), is_lasr);
233
return;
234
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
235
/* TODO: ARMv8.4-LSE SCTLR.nAA */
236
memop = finalize_memop(s, size | MO_ALIGN);
237
clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn),
238
- false, rn != 31, size);
239
+ false, rn != 31, memop);
240
do_gpr_ld(s, cpu_reg(s, rt), clean_addr, memop, false, true,
241
rt, disas_ldst_compute_iss_sf(size, false, 0), is_lasr);
242
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
243
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn,
244
tcg_gen_add_i64(dirty_addr, dirty_addr, tcg_rm);
245
246
memop = finalize_memop(s, size + is_signed * MO_SIGN);
247
- clean_addr = gen_mte_check1(s, dirty_addr, is_store, true, size);
248
+ clean_addr = gen_mte_check1(s, dirty_addr, is_store, true, memop);
249
250
if (is_vector) {
251
if (is_store) {
252
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn,
253
tcg_gen_addi_i64(dirty_addr, dirty_addr, offset);
254
255
memop = finalize_memop(s, size + is_signed * MO_SIGN);
256
- clean_addr = gen_mte_check1(s, dirty_addr, is_store, rn != 31, size);
257
+ clean_addr = gen_mte_check1(s, dirty_addr, is_store, rn != 31, memop);
258
259
if (is_vector) {
260
if (is_store) {
261
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn,
262
if (rn == 31) {
263
gen_check_sp_alignment(s);
264
}
265
- clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), false, rn != 31, size);
266
+ clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), false, rn != 31, mop);
267
268
if (o3_opc == 014) {
269
/*
270
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_pac(DisasContext *s, uint32_t insn,
271
272
/* Note that "clean" and "dirty" here refer to TBI not PAC. */
273
clean_addr = gen_mte_check1(s, dirty_addr, false,
274
- is_wback || rn != 31, size);
275
+ is_wback || rn != 31, memop);
276
277
tcg_rt = cpu_reg(s, rt);
278
do_gpr_ld(s, tcg_rt, clean_addr, memop,
279
diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c
280
index XXXXXXX..XXXXXXX 100644
281
--- a/target/arm/tcg/translate-sve.c
282
+++ b/target/arm/tcg/translate-sve.c
283
@@ -XXX,XX +XXX,XX @@ static bool trans_LD1R_zpri(DisasContext *s, arg_rpri_load *a)
284
unsigned msz = dtype_msz(a->dtype);
285
TCGLabel *over;
286
TCGv_i64 temp, clean_addr;
287
+ MemOp memop;
288
289
if (!dc_isar_feature(aa64_sve, s)) {
290
return false;
291
@@ -XXX,XX +XXX,XX @@ static bool trans_LD1R_zpri(DisasContext *s, arg_rpri_load *a)
292
/* Load the data. */
293
temp = tcg_temp_new_i64();
294
tcg_gen_addi_i64(temp, cpu_reg_sp(s, a->rn), a->imm << msz);
295
- clean_addr = gen_mte_check1(s, temp, false, true, msz);
296
297
- tcg_gen_qemu_ld_i64(temp, clean_addr, get_mem_index(s),
298
- finalize_memop(s, dtype_mop[a->dtype]));
299
+ memop = finalize_memop(s, dtype_mop[a->dtype]);
300
+ clean_addr = gen_mte_check1(s, temp, false, true, memop);
301
+ tcg_gen_qemu_ld_i64(temp, clean_addr, get_mem_index(s), memop);
302
303
/* Broadcast to *all* elements. */
304
tcg_gen_gvec_dup_i64(esz, vec_full_reg_offset(s, a->rd),
305
--
306
2.34.1
diff view generated by jsdifflib
New patch
1
From: Richard Henderson <richard.henderson@linaro.org>
1
2
3
Pass the individual memop to gen_mte_checkN.
4
For the moment, do nothing with it.
5
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20230530191438.411344-14-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
target/arm/tcg/translate-a64.h | 2 +-
12
target/arm/tcg/translate-a64.c | 31 +++++++++++++++++++------------
13
target/arm/tcg/translate-sve.c | 4 ++--
14
3 files changed, 22 insertions(+), 15 deletions(-)
15
16
diff --git a/target/arm/tcg/translate-a64.h b/target/arm/tcg/translate-a64.h
17
index XXXXXXX..XXXXXXX 100644
18
--- a/target/arm/tcg/translate-a64.h
19
+++ b/target/arm/tcg/translate-a64.h
20
@@ -XXX,XX +XXX,XX @@ TCGv_i64 clean_data_tbi(DisasContext *s, TCGv_i64 addr);
21
TCGv_i64 gen_mte_check1(DisasContext *s, TCGv_i64 addr, bool is_write,
22
bool tag_checked, MemOp memop);
23
TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write,
24
- bool tag_checked, int size);
25
+ bool tag_checked, int total_size, MemOp memop);
26
27
/* We should have at some point before trying to access an FP register
28
* done the necessary access check, so assert that
29
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/target/arm/tcg/translate-a64.c
32
+++ b/target/arm/tcg/translate-a64.c
33
@@ -XXX,XX +XXX,XX @@ TCGv_i64 gen_mte_check1(DisasContext *s, TCGv_i64 addr, bool is_write,
34
* For MTE, check multiple logical sequential accesses.
35
*/
36
TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write,
37
- bool tag_checked, int size)
38
+ bool tag_checked, int total_size, MemOp single_mop)
39
{
40
if (tag_checked && s->mte_active[0]) {
41
TCGv_i64 ret;
42
@@ -XXX,XX +XXX,XX @@ TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write,
43
desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid);
44
desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma);
45
desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write);
46
- desc = FIELD_DP32(desc, MTEDESC, SIZEM1, size - 1);
47
+ desc = FIELD_DP32(desc, MTEDESC, SIZEM1, total_size - 1);
48
49
ret = tcg_temp_new_i64();
50
gen_helper_mte_check(ret, cpu_env, tcg_constant_i32(desc), addr);
51
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn)
52
bool is_vector = extract32(insn, 26, 1);
53
bool is_load = extract32(insn, 22, 1);
54
int opc = extract32(insn, 30, 2);
55
-
56
bool is_signed = false;
57
bool postindex = false;
58
bool wback = false;
59
bool set_tag = false;
60
-
61
TCGv_i64 clean_addr, dirty_addr;
62
-
63
+ MemOp mop;
64
int size;
65
66
if (opc == 3) {
67
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn)
68
}
69
}
70
71
+ if (is_vector) {
72
+ mop = finalize_memop_asimd(s, size);
73
+ } else {
74
+ mop = finalize_memop(s, size);
75
+ }
76
clean_addr = gen_mte_checkN(s, dirty_addr, !is_load,
77
- (wback || rn != 31) && !set_tag, 2 << size);
78
+ (wback || rn != 31) && !set_tag,
79
+ 2 << size, mop);
80
81
if (is_vector) {
82
- MemOp mop = finalize_memop_asimd(s, size);
83
-
84
+ /* LSE2 does not merge FP pairs; leave these as separate operations. */
85
if (is_load) {
86
do_fp_ld(s, rt, clean_addr, mop);
87
} else {
88
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn)
89
} else {
90
TCGv_i64 tcg_rt = cpu_reg(s, rt);
91
TCGv_i64 tcg_rt2 = cpu_reg(s, rt2);
92
- MemOp mop = size + 1;
93
94
/*
95
+ * We built mop above for the single logical access -- rebuild it
96
+ * now for the paired operation.
97
+ *
98
* With LSE2, non-sign-extending pairs are treated atomically if
99
* aligned, and if unaligned one of the pair will be completely
100
* within a 16-byte block and that element will be atomic.
101
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn)
102
* This treats sign-extending loads like zero-extending loads,
103
* since that reuses the most code below.
104
*/
105
+ mop = size + 1;
106
if (s->align_mem) {
107
mop |= (size == 2 ? MO_ALIGN_4 : MO_ALIGN_8);
108
}
109
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn)
110
* promote consecutive little-endian elements below.
111
*/
112
clean_addr = gen_mte_checkN(s, tcg_rn, is_store, is_postidx || rn != 31,
113
- total);
114
+ total, finalize_memop(s, size));
115
116
/*
117
* Consecutive little-endian elements from a single register
118
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn)
119
total = selem << scale;
120
tcg_rn = cpu_reg_sp(s, rn);
121
122
- clean_addr = gen_mte_checkN(s, tcg_rn, !is_load, is_postidx || rn != 31,
123
- total);
124
mop = finalize_memop(s, scale);
125
126
+ clean_addr = gen_mte_checkN(s, tcg_rn, !is_load, is_postidx || rn != 31,
127
+ total, mop);
128
+
129
tcg_ebytes = tcg_constant_i64(1 << scale);
130
for (xs = 0; xs < selem; xs++) {
131
if (replicate) {
132
diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c
133
index XXXXXXX..XXXXXXX 100644
134
--- a/target/arm/tcg/translate-sve.c
135
+++ b/target/arm/tcg/translate-sve.c
136
@@ -XXX,XX +XXX,XX @@ void gen_sve_ldr(DisasContext *s, TCGv_ptr base, int vofs,
137
138
dirty_addr = tcg_temp_new_i64();
139
tcg_gen_addi_i64(dirty_addr, cpu_reg_sp(s, rn), imm);
140
- clean_addr = gen_mte_checkN(s, dirty_addr, false, rn != 31, len);
141
+ clean_addr = gen_mte_checkN(s, dirty_addr, false, rn != 31, len, MO_8);
142
143
/*
144
* Note that unpredicated load/store of vector/predicate registers
145
@@ -XXX,XX +XXX,XX @@ void gen_sve_str(DisasContext *s, TCGv_ptr base, int vofs,
146
147
dirty_addr = tcg_temp_new_i64();
148
tcg_gen_addi_i64(dirty_addr, cpu_reg_sp(s, rn), imm);
149
- clean_addr = gen_mte_checkN(s, dirty_addr, false, rn != 31, len);
150
+ clean_addr = gen_mte_checkN(s, dirty_addr, false, rn != 31, len, MO_8);
151
152
/* Note that unpredicated load/store of vector/predicate registers
153
* are defined as a stream of bytes, which equates to little-endian
154
--
155
2.34.1
diff view generated by jsdifflib
1
In commit cd8be50e58f63413c0 we converted the A32 coprocessor
1
From: Richard Henderson <richard.henderson@linaro.org>
2
insns to decodetree. This accidentally broke XScale/iWMMXt insns,
3
because it moved the handling of "cp insns which are handled
4
by looking up the cp register in the hashtable" from after the
5
call to the legacy disas_xscale_insn() decode to before it,
6
with the result that all XScale/iWMMXt insns now UNDEF.
7
2
8
Update valid_cp() so that it knows that on XScale cp 0 and 1
3
Fixes a bug in that with SCTLR.A set, we should raise any
9
are not standard coprocessor instructions; this will cause
4
alignment fault before raising any MTE check fault.
10
the decodetree trans_ functions to ignore them, so that
11
execution will correctly get through to the legacy decode again.
12
5
13
Cc: qemu-stable@nongnu.org
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
14
Reported-by: Guenter Roeck <linux@roeck-us.net>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20230530191438.411344-15-richard.henderson@linaro.org
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>
17
Tested-by: Guenter Roeck <linux@roeck-us.net>
18
Message-id: 20210108195157.32067-1-peter.maydell@linaro.org
19
---
10
---
20
target/arm/translate.c | 7 +++++++
11
target/arm/internals.h | 3 ++-
21
1 file changed, 7 insertions(+)
12
target/arm/tcg/mte_helper.c | 18 ++++++++++++++++++
13
target/arm/tcg/translate-a64.c | 2 ++
14
3 files changed, 22 insertions(+), 1 deletion(-)
22
15
23
diff --git a/target/arm/translate.c b/target/arm/translate.c
16
diff --git a/target/arm/internals.h b/target/arm/internals.h
24
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
25
--- a/target/arm/translate.c
18
--- a/target/arm/internals.h
26
+++ b/target/arm/translate.c
19
+++ b/target/arm/internals.h
27
@@ -XXX,XX +XXX,XX @@ static bool valid_cp(DisasContext *s, int cp)
20
@@ -XXX,XX +XXX,XX @@ FIELD(MTEDESC, MIDX, 0, 4)
28
* only cp14 and cp15 are valid, and other values aren't considered
21
FIELD(MTEDESC, TBI, 4, 2)
29
* to be in the coprocessor-instruction space at all. v8M still
22
FIELD(MTEDESC, TCMA, 6, 2)
30
* permits coprocessors 0..7.
23
FIELD(MTEDESC, WRITE, 8, 1)
31
+ * For XScale, we must not decode the XScale cp0, cp1 space as
24
-FIELD(MTEDESC, SIZEM1, 9, SIMD_DATA_BITS - 9) /* size - 1 */
32
+ * a standard coprocessor insn, because we want to fall through to
25
+FIELD(MTEDESC, ALIGN, 9, 3)
33
+ * the legacy disas_xscale_insn() decoder after decodetree is done.
26
+FIELD(MTEDESC, SIZEM1, 12, SIMD_DATA_BITS - 12) /* size - 1 */
34
*/
27
35
+ if (arm_dc_feature(s, ARM_FEATURE_XSCALE) && (cp == 0 || cp == 1)) {
28
bool mte_probe(CPUARMState *env, uint32_t desc, uint64_t ptr);
36
+ return false;
29
uint64_t mte_check(CPUARMState *env, uint32_t desc, uint64_t ptr, uintptr_t ra);
30
diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/target/arm/tcg/mte_helper.c
33
+++ b/target/arm/tcg/mte_helper.c
34
@@ -XXX,XX +XXX,XX @@ uint64_t mte_check(CPUARMState *env, uint32_t desc, uint64_t ptr, uintptr_t ra)
35
36
uint64_t HELPER(mte_check)(CPUARMState *env, uint32_t desc, uint64_t ptr)
37
{
38
+ /*
39
+ * R_XCHFJ: Alignment check not caused by memory type is priority 1,
40
+ * higher than any translation fault. When MTE is disabled, tcg
41
+ * performs the alignment check during the code generated for the
42
+ * memory access. With MTE enabled, we must check this here before
43
+ * raising any translation fault in allocation_tag_mem.
44
+ */
45
+ unsigned align = FIELD_EX32(desc, MTEDESC, ALIGN);
46
+ if (unlikely(align)) {
47
+ align = (1u << align) - 1;
48
+ if (unlikely(ptr & align)) {
49
+ int idx = FIELD_EX32(desc, MTEDESC, MIDX);
50
+ bool w = FIELD_EX32(desc, MTEDESC, WRITE);
51
+ MMUAccessType type = w ? MMU_DATA_STORE : MMU_DATA_LOAD;
52
+ arm_cpu_do_unaligned_access(env_cpu(env), ptr, type, idx, GETPC());
53
+ }
37
+ }
54
+ }
38
+
55
+
39
if (arm_dc_feature(s, ARM_FEATURE_V8) &&
56
return mte_check(env, desc, ptr, GETPC());
40
!arm_dc_feature(s, ARM_FEATURE_M)) {
57
}
41
return cp >= 14;
58
59
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
60
index XXXXXXX..XXXXXXX 100644
61
--- a/target/arm/tcg/translate-a64.c
62
+++ b/target/arm/tcg/translate-a64.c
63
@@ -XXX,XX +XXX,XX @@ static TCGv_i64 gen_mte_check1_mmuidx(DisasContext *s, TCGv_i64 addr,
64
desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid);
65
desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma);
66
desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write);
67
+ desc = FIELD_DP32(desc, MTEDESC, ALIGN, get_alignment_bits(memop));
68
desc = FIELD_DP32(desc, MTEDESC, SIZEM1, memop_size(memop) - 1);
69
70
ret = tcg_temp_new_i64();
71
@@ -XXX,XX +XXX,XX @@ TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write,
72
desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid);
73
desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma);
74
desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write);
75
+ desc = FIELD_DP32(desc, MTEDESC, ALIGN, get_alignment_bits(single_mop));
76
desc = FIELD_DP32(desc, MTEDESC, SIZEM1, total_size - 1);
77
78
ret = tcg_temp_new_i64();
42
--
79
--
43
2.20.1
80
2.34.1
44
45
diff view generated by jsdifflib
1
From: Leif Lindholm <leif@nuviainc.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
The AArch64 view of CLIDR_EL1 extends the ICB field to include also bit
4
32, as well as adding a Ttype<n> field when FEAT_MTE is implemented.
5
Extend the clidr field to be able to hold this context.
6
7
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
3
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
11
Message-id: 20210108185154.8108-3-leif@nuviainc.com
5
Message-id: 20230530191438.411344-16-richard.henderson@linaro.org
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
7
---
14
target/arm/cpu.h | 2 +-
8
target/arm/cpu.h | 3 ++-
15
1 file changed, 1 insertion(+), 1 deletion(-)
9
target/arm/tcg/translate.h | 2 ++
10
target/arm/tcg/hflags.c | 6 ++++++
11
target/arm/tcg/translate-a64.c | 1 +
12
4 files changed, 11 insertions(+), 1 deletion(-)
16
13
17
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
14
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
18
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/cpu.h
16
--- a/target/arm/cpu.h
20
+++ b/target/arm/cpu.h
17
+++ b/target/arm/cpu.h
21
@@ -XXX,XX +XXX,XX @@ struct ARMCPU {
18
@@ -XXX,XX +XXX,XX @@ void pmu_init(ARMCPU *cpu);
22
uint32_t id_afr0;
19
#define SCTLR_D (1U << 5) /* up to v5; RAO in v6 */
23
uint64_t id_aa64afr0;
20
#define SCTLR_CP15BEN (1U << 5) /* v7 onward */
24
uint64_t id_aa64afr1;
21
#define SCTLR_L (1U << 6) /* up to v5; RAO in v6 and v7; RAZ in v8 */
25
- uint32_t clidr;
22
-#define SCTLR_nAA (1U << 6) /* when v8.4-LSE is implemented */
26
+ uint64_t clidr;
23
+#define SCTLR_nAA (1U << 6) /* when FEAT_LSE2 is implemented */
27
uint64_t mp_affinity; /* MP ID without feature bits */
24
#define SCTLR_B (1U << 7) /* up to v6; RAZ in v7 */
28
/* The elements of this array are the CCSIDR values for each cache,
25
#define SCTLR_ITD (1U << 7) /* v8 onward */
29
* in the order L1DCache, L1ICache, L2DCache, L2ICache, etc.
26
#define SCTLR_S (1U << 8) /* up to v6; RAZ in v7 */
27
@@ -XXX,XX +XXX,XX @@ FIELD(TBFLAG_A64, SVL, 24, 4)
28
/* Indicates that SME Streaming mode is active, and SMCR_ELx.FA64 is not. */
29
FIELD(TBFLAG_A64, SME_TRAP_NONSTREAMING, 28, 1)
30
FIELD(TBFLAG_A64, FGT_ERET, 29, 1)
31
+FIELD(TBFLAG_A64, NAA, 30, 1)
32
33
/*
34
* Helpers for using the above.
35
diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h
36
index XXXXXXX..XXXXXXX 100644
37
--- a/target/arm/tcg/translate.h
38
+++ b/target/arm/tcg/translate.h
39
@@ -XXX,XX +XXX,XX @@ typedef struct DisasContext {
40
bool fgt_eret;
41
/* True if fine-grained trap on SVC is enabled */
42
bool fgt_svc;
43
+ /* True if FEAT_LSE2 SCTLR_ELx.nAA is set */
44
+ bool naa;
45
/*
46
* >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI.
47
* < 0, set by the current instruction.
48
diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/target/arm/tcg/hflags.c
51
+++ b/target/arm/tcg/hflags.c
52
@@ -XXX,XX +XXX,XX @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
53
}
54
}
55
56
+ if (cpu_isar_feature(aa64_lse2, env_archcpu(env))) {
57
+ if (sctlr & SCTLR_nAA) {
58
+ DP_TBFLAG_A64(flags, NAA, 1);
59
+ }
60
+ }
61
+
62
/* Compute the condition for using AccType_UNPRIV for LDTR et al. */
63
if (!(env->pstate & PSTATE_UAO)) {
64
switch (mmu_idx) {
65
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
66
index XXXXXXX..XXXXXXX 100644
67
--- a/target/arm/tcg/translate-a64.c
68
+++ b/target/arm/tcg/translate-a64.c
69
@@ -XXX,XX +XXX,XX @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
70
dc->pstate_sm = EX_TBFLAG_A64(tb_flags, PSTATE_SM);
71
dc->pstate_za = EX_TBFLAG_A64(tb_flags, PSTATE_ZA);
72
dc->sme_trap_nonstreaming = EX_TBFLAG_A64(tb_flags, SME_TRAP_NONSTREAMING);
73
+ dc->naa = EX_TBFLAG_A64(tb_flags, NAA);
74
dc->vec_len = 0;
75
dc->vec_stride = 0;
76
dc->cp_regs = arm_cpu->cp_regs;
30
--
77
--
31
2.20.1
78
2.34.1
32
33
diff view generated by jsdifflib
1
From: Roman Bolshakov <r.bolshakov@yadro.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
QEMU documentation can't be opened if QEMU is run from build tree
3
FEAT_LSE2 only requires that atomic operations not cross a
4
because executables are placed in the top of build tree after conversion
4
16-byte boundary. Ordered operations may be completely
5
to meson.
5
unaligned if SCTLR.nAA is set.
6
6
7
Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
7
Because this alignment check is so special, do it by hand.
8
Reported-by: Peter Maydell <peter.maydell@linaro.org>
8
Make sure not to keep TCG temps live across the branch.
9
Message-id: 20210108213815.64678-1-r.bolshakov@yadro.com
9
10
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
11
Message-id: 20230530191438.411344-17-richard.henderson@linaro.org
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
12
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
14
---
13
ui/cocoa.m | 2 +-
15
target/arm/tcg/helper-a64.h | 3 +
14
1 file changed, 1 insertion(+), 1 deletion(-)
16
target/arm/tcg/helper-a64.c | 7 ++
15
17
target/arm/tcg/translate-a64.c | 120 ++++++++++++++++++++++++++-------
16
diff --git a/ui/cocoa.m b/ui/cocoa.m
18
3 files changed, 104 insertions(+), 26 deletions(-)
19
20
diff --git a/target/arm/tcg/helper-a64.h b/target/arm/tcg/helper-a64.h
17
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
18
--- a/ui/cocoa.m
22
--- a/target/arm/tcg/helper-a64.h
19
+++ b/ui/cocoa.m
23
+++ b/target/arm/tcg/helper-a64.h
20
@@ -XXX,XX +XXX,XX @@ QemuCocoaView *cocoaView;
24
@@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_2(st2g_stub, TCG_CALL_NO_WG, void, env, i64)
21
- (void) openDocumentation: (NSString *) filename
25
DEF_HELPER_FLAGS_2(ldgm, TCG_CALL_NO_WG, i64, env, i64)
26
DEF_HELPER_FLAGS_3(stgm, TCG_CALL_NO_WG, void, env, i64, i64)
27
DEF_HELPER_FLAGS_3(stzgm_tags, TCG_CALL_NO_WG, void, env, i64, i64)
28
+
29
+DEF_HELPER_FLAGS_4(unaligned_access, TCG_CALL_NO_WG,
30
+ noreturn, env, i64, i32, i32)
31
diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/target/arm/tcg/helper-a64.c
34
+++ b/target/arm/tcg/helper-a64.c
35
@@ -XXX,XX +XXX,XX @@ void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
36
37
memset(mem, 0, blocklen);
38
}
39
+
40
+void HELPER(unaligned_access)(CPUARMState *env, uint64_t addr,
41
+ uint32_t access_type, uint32_t mmu_idx)
42
+{
43
+ arm_cpu_do_unaligned_access(env_cpu(env), addr, access_type,
44
+ mmu_idx, GETPC());
45
+}
46
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
47
index XXXXXXX..XXXXXXX 100644
48
--- a/target/arm/tcg/translate-a64.c
49
+++ b/target/arm/tcg/translate-a64.c
50
@@ -XXX,XX +XXX,XX @@ TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write,
51
return clean_data_tbi(s, addr);
52
}
53
54
+/*
55
+ * Generate the special alignment check that applies to AccType_ATOMIC
56
+ * and AccType_ORDERED insns under FEAT_LSE2: the access need not be
57
+ * naturally aligned, but it must not cross a 16-byte boundary.
58
+ * See AArch64.CheckAlignment().
59
+ */
60
+static void check_lse2_align(DisasContext *s, int rn, int imm,
61
+ bool is_write, MemOp mop)
62
+{
63
+ TCGv_i32 tmp;
64
+ TCGv_i64 addr;
65
+ TCGLabel *over_label;
66
+ MMUAccessType type;
67
+ int mmu_idx;
68
+
69
+ tmp = tcg_temp_new_i32();
70
+ tcg_gen_extrl_i64_i32(tmp, cpu_reg_sp(s, rn));
71
+ tcg_gen_addi_i32(tmp, tmp, imm & 15);
72
+ tcg_gen_andi_i32(tmp, tmp, 15);
73
+ tcg_gen_addi_i32(tmp, tmp, memop_size(mop));
74
+
75
+ over_label = gen_new_label();
76
+ tcg_gen_brcondi_i32(TCG_COND_LEU, tmp, 16, over_label);
77
+
78
+ addr = tcg_temp_new_i64();
79
+ tcg_gen_addi_i64(addr, cpu_reg_sp(s, rn), imm);
80
+
81
+ type = is_write ? MMU_DATA_STORE : MMU_DATA_LOAD,
82
+ mmu_idx = get_mem_index(s);
83
+ gen_helper_unaligned_access(cpu_env, addr, tcg_constant_i32(type),
84
+ tcg_constant_i32(mmu_idx));
85
+
86
+ gen_set_label(over_label);
87
+
88
+}
89
+
90
+/* Handle the alignment check for AccType_ATOMIC instructions. */
91
+static MemOp check_atomic_align(DisasContext *s, int rn, MemOp mop)
92
+{
93
+ MemOp size = mop & MO_SIZE;
94
+
95
+ if (size == MO_8) {
96
+ return mop;
97
+ }
98
+
99
+ /*
100
+ * If size == MO_128, this is a LDXP, and the operation is single-copy
101
+ * atomic for each doubleword, not the entire quadword; it still must
102
+ * be quadword aligned.
103
+ */
104
+ if (size == MO_128) {
105
+ return finalize_memop_atom(s, MO_128 | MO_ALIGN,
106
+ MO_ATOM_IFALIGN_PAIR);
107
+ }
108
+ if (dc_isar_feature(aa64_lse2, s)) {
109
+ check_lse2_align(s, rn, 0, true, mop);
110
+ } else {
111
+ mop |= MO_ALIGN;
112
+ }
113
+ return finalize_memop(s, mop);
114
+}
115
+
116
+/* Handle the alignment check for AccType_ORDERED instructions. */
117
+static MemOp check_ordered_align(DisasContext *s, int rn, int imm,
118
+ bool is_write, MemOp mop)
119
+{
120
+ MemOp size = mop & MO_SIZE;
121
+
122
+ if (size == MO_8) {
123
+ return mop;
124
+ }
125
+ if (size == MO_128) {
126
+ return finalize_memop_atom(s, MO_128 | MO_ALIGN,
127
+ MO_ATOM_IFALIGN_PAIR);
128
+ }
129
+ if (!dc_isar_feature(aa64_lse2, s)) {
130
+ mop |= MO_ALIGN;
131
+ } else if (!s->naa) {
132
+ check_lse2_align(s, rn, imm, is_write, mop);
133
+ }
134
+ return finalize_memop(s, mop);
135
+}
136
+
137
typedef struct DisasCompare64 {
138
TCGCond cond;
139
TCGv_i64 value;
140
@@ -XXX,XX +XXX,XX @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2, int rn,
22
{
141
{
23
/* Where to look for local files */
142
int idx = get_mem_index(s);
24
- NSString *path_array[] = {@"../share/doc/qemu/", @"../doc/qemu/", @"../docs/"};
143
TCGv_i64 dirty_addr, clean_addr;
25
+ NSString *path_array[] = {@"../share/doc/qemu/", @"../doc/qemu/", @"docs/"};
144
- MemOp memop;
26
NSString *full_file_path;
145
-
27
146
- /*
28
/* iterate thru the possible paths until the file is found */
147
- * For pairs:
148
- * if size == 2, the operation is single-copy atomic for the doubleword.
149
- * if size == 3, the operation is single-copy atomic for *each* doubleword,
150
- * not the entire quadword, however it must be quadword aligned.
151
- */
152
- memop = size + is_pair;
153
- if (memop == MO_128) {
154
- memop = finalize_memop_atom(s, MO_128 | MO_ALIGN,
155
- MO_ATOM_IFALIGN_PAIR);
156
- } else {
157
- memop = finalize_memop(s, memop | MO_ALIGN);
158
- }
159
+ MemOp memop = check_atomic_align(s, rn, size + is_pair);
160
161
s->is_ldex = true;
162
dirty_addr = cpu_reg_sp(s, rn);
163
@@ -XXX,XX +XXX,XX @@ static void gen_compare_and_swap(DisasContext *s, int rs, int rt,
164
if (rn == 31) {
165
gen_check_sp_alignment(s);
166
}
167
- memop = finalize_memop(s, size | MO_ALIGN);
168
+ memop = check_atomic_align(s, rn, size);
169
clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), true, rn != 31, memop);
170
tcg_gen_atomic_cmpxchg_i64(tcg_rs, clean_addr, tcg_rs, tcg_rt,
171
memidx, memop);
172
@@ -XXX,XX +XXX,XX @@ static void gen_compare_and_swap_pair(DisasContext *s, int rs, int rt,
173
}
174
175
/* This is a single atomic access, despite the "pair". */
176
- memop = finalize_memop(s, (size + 1) | MO_ALIGN);
177
+ memop = check_atomic_align(s, rn, size + 1);
178
clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), true, rn != 31, memop);
179
180
if (size == 2) {
181
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
182
gen_check_sp_alignment(s);
183
}
184
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
185
- /* TODO: ARMv8.4-LSE SCTLR.nAA */
186
- memop = finalize_memop(s, size | MO_ALIGN);
187
+ memop = check_ordered_align(s, rn, 0, true, size);
188
clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn),
189
true, rn != 31, memop);
190
do_gpr_st(s, cpu_reg(s, rt), clean_addr, memop, true, rt,
191
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
192
if (rn == 31) {
193
gen_check_sp_alignment(s);
194
}
195
- /* TODO: ARMv8.4-LSE SCTLR.nAA */
196
- memop = finalize_memop(s, size | MO_ALIGN);
197
+ memop = check_ordered_align(s, rn, 0, false, size);
198
clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn),
199
false, rn != 31, memop);
200
do_gpr_ld(s, cpu_reg(s, rt), clean_addr, memop, false, true,
201
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn,
202
bool a = extract32(insn, 23, 1);
203
TCGv_i64 tcg_rs, tcg_rt, clean_addr;
204
AtomicThreeOpFn *fn = NULL;
205
- MemOp mop = finalize_memop(s, size | MO_ALIGN);
206
+ MemOp mop = size;
207
208
if (is_vector || !dc_isar_feature(aa64_atomics, s)) {
209
unallocated_encoding(s);
210
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_atomic(DisasContext *s, uint32_t insn,
211
if (rn == 31) {
212
gen_check_sp_alignment(s);
213
}
214
+
215
+ mop = check_atomic_align(s, rn, mop);
216
clean_addr = gen_mte_check1(s, cpu_reg_sp(s, rn), false, rn != 31, mop);
217
218
if (o3_opc == 014) {
219
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_ldapr_stlr(DisasContext *s, uint32_t insn)
220
bool is_store = false;
221
bool extend = false;
222
bool iss_sf;
223
- MemOp mop;
224
+ MemOp mop = size;
225
226
if (!dc_isar_feature(aa64_rcpc_8_4, s)) {
227
unallocated_encoding(s);
228
return;
229
}
230
231
- /* TODO: ARMv8.4-LSE SCTLR.nAA */
232
- mop = finalize_memop(s, size | MO_ALIGN);
233
-
234
switch (opc) {
235
case 0: /* STLURB */
236
is_store = true;
237
@@ -XXX,XX +XXX,XX @@ static void disas_ldst_ldapr_stlr(DisasContext *s, uint32_t insn)
238
gen_check_sp_alignment(s);
239
}
240
241
+ mop = check_ordered_align(s, rn, offset, is_store, mop);
242
+
243
dirty_addr = read_cpu_reg_sp(s, rn, 1);
244
tcg_gen_addi_i64(dirty_addr, dirty_addr, offset);
245
clean_addr = clean_data_tbi(s, dirty_addr);
29
--
246
--
30
2.20.1
247
2.34.1
31
32
diff view generated by jsdifflib
New patch
1
From: Richard Henderson <richard.henderson@linaro.org>
1
2
3
Push the mte check behind the exclusive_addr check.
4
Document the several ways that we are still out of spec
5
with this implementation.
6
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20230530191438.411344-18-richard.henderson@linaro.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
12
target/arm/tcg/translate-a64.c | 42 +++++++++++++++++++++++++++++-----
13
1 file changed, 36 insertions(+), 6 deletions(-)
14
15
diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/tcg/translate-a64.c
18
+++ b/target/arm/tcg/translate-a64.c
19
@@ -XXX,XX +XXX,XX @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
20
*/
21
TCGLabel *fail_label = gen_new_label();
22
TCGLabel *done_label = gen_new_label();
23
- TCGv_i64 tmp, dirty_addr, clean_addr;
24
+ TCGv_i64 tmp, clean_addr;
25
MemOp memop;
26
27
- memop = (size + is_pair) | MO_ALIGN;
28
- memop = finalize_memop(s, memop);
29
-
30
- dirty_addr = cpu_reg_sp(s, rn);
31
- clean_addr = gen_mte_check1(s, dirty_addr, true, rn != 31, memop);
32
+ /*
33
+ * FIXME: We are out of spec here. We have recorded only the address
34
+ * from load_exclusive, not the entire range, and we assume that the
35
+ * size of the access on both sides match. The architecture allows the
36
+ * store to be smaller than the load, so long as the stored bytes are
37
+ * within the range recorded by the load.
38
+ */
39
40
+ /* See AArch64.ExclusiveMonitorsPass() and AArch64.IsExclusiveVA(). */
41
+ clean_addr = clean_data_tbi(s, cpu_reg_sp(s, rn));
42
tcg_gen_brcond_i64(TCG_COND_NE, clean_addr, cpu_exclusive_addr, fail_label);
43
44
+ /*
45
+ * The write, and any associated faults, only happen if the virtual
46
+ * and physical addresses pass the exclusive monitor check. These
47
+ * faults are exceedingly unlikely, because normally the guest uses
48
+ * the exact same address register for the load_exclusive, and we
49
+ * would have recognized these faults there.
50
+ *
51
+ * It is possible to trigger an alignment fault pre-LSE2, e.g. with an
52
+ * unaligned 4-byte write within the range of an aligned 8-byte load.
53
+ * With LSE2, the store would need to cross a 16-byte boundary when the
54
+ * load did not, which would mean the store is outside the range
55
+ * recorded for the monitor, which would have failed a corrected monitor
56
+ * check above. For now, we assume no size change and retain the
57
+ * MO_ALIGN to let tcg know what we checked in the load_exclusive.
58
+ *
59
+ * It is possible to trigger an MTE fault, by performing the load with
60
+ * a virtual address with a valid tag and performing the store with the
61
+ * same virtual address and a different invalid tag.
62
+ */
63
+ memop = size + is_pair;
64
+ if (memop == MO_128 || !dc_isar_feature(aa64_lse2, s)) {
65
+ memop |= MO_ALIGN;
66
+ }
67
+ memop = finalize_memop(s, memop);
68
+ gen_mte_check1(s, cpu_reg_sp(s, rn), true, rn != 31, memop);
69
+
70
tmp = tcg_temp_new_i64();
71
if (is_pair) {
72
if (size == 2) {
73
--
74
2.34.1
diff view generated by jsdifflib
1
From: Hao Wu <wuhaotsh@google.com>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
This patch makes NPCM7XX Timer to use a the timer clock generated by the
3
We have many other instances of stg in the testsuite;
4
CLK module instead of the magic number TIMER_REF_HZ.
4
change these to provide an instance of stz2g.
5
5
6
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
7
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
8
Signed-off-by: Hao Wu <wuhaotsh@google.com>
9
Message-id: 20210108190945.949196-3-wuhaotsh@google.com
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20230530191438.411344-19-richard.henderson@linaro.org
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
10
---
13
include/hw/misc/npcm7xx_clk.h | 6 -----
11
tests/tcg/aarch64/mte-7.c | 3 +--
14
include/hw/timer/npcm7xx_timer.h | 1 +
12
1 file changed, 1 insertion(+), 2 deletions(-)
15
hw/arm/npcm7xx.c | 5 ++++
16
hw/timer/npcm7xx_timer.c | 39 +++++++++++++++-----------------
17
4 files changed, 24 insertions(+), 27 deletions(-)
18
13
19
diff --git a/include/hw/misc/npcm7xx_clk.h b/include/hw/misc/npcm7xx_clk.h
14
diff --git a/tests/tcg/aarch64/mte-7.c b/tests/tcg/aarch64/mte-7.c
20
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
21
--- a/include/hw/misc/npcm7xx_clk.h
16
--- a/tests/tcg/aarch64/mte-7.c
22
+++ b/include/hw/misc/npcm7xx_clk.h
17
+++ b/tests/tcg/aarch64/mte-7.c
23
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@ int main(int ac, char **av)
24
#include "hw/clock.h"
19
p = (void *)((unsigned long)p | (1ul << 56));
25
#include "hw/sysbus.h"
20
26
21
/* Store tag in sequential granules. */
27
-/*
22
- asm("stg %0, [%0]" : : "r"(p + 0x0ff0));
28
- * The reference clock frequency for the timer modules, and the SECCNT and
23
- asm("stg %0, [%0]" : : "r"(p + 0x1000));
29
- * CNTR25M registers in this module, is always 25 MHz.
24
+ asm("stz2g %0, [%0]" : : "r"(p + 0x0ff0));
30
- */
31
-#define NPCM7XX_TIMER_REF_HZ (25000000)
32
-
33
/*
34
* Number of registers in our device state structure. Don't change this without
35
* incrementing the version_id in the vmstate.
36
diff --git a/include/hw/timer/npcm7xx_timer.h b/include/hw/timer/npcm7xx_timer.h
37
index XXXXXXX..XXXXXXX 100644
38
--- a/include/hw/timer/npcm7xx_timer.h
39
+++ b/include/hw/timer/npcm7xx_timer.h
40
@@ -XXX,XX +XXX,XX @@ struct NPCM7xxTimerCtrlState {
41
42
uint32_t tisr;
43
44
+ Clock *clock;
45
NPCM7xxTimer timer[NPCM7XX_TIMERS_PER_CTRL];
46
NPCM7xxWatchdogTimer watchdog_timer;
47
};
48
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/hw/arm/npcm7xx.c
51
+++ b/hw/arm/npcm7xx.c
52
@@ -XXX,XX +XXX,XX @@
53
#include "hw/char/serial.h"
54
#include "hw/loader.h"
55
#include "hw/misc/unimp.h"
56
+#include "hw/qdev-clock.h"
57
#include "hw/qdev-properties.h"
58
#include "qapi/error.h"
59
#include "qemu/units.h"
60
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
61
int first_irq;
62
int j;
63
64
+ /* Connect the timer clock. */
65
+ qdev_connect_clock_in(DEVICE(&s->tim[i]), "clock", qdev_get_clock_out(
66
+ DEVICE(&s->clk), "timer-clock"));
67
+
68
sysbus_realize(sbd, &error_abort);
69
sysbus_mmio_map(sbd, 0, npcm7xx_tim_addr[i]);
70
71
diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c
72
index XXXXXXX..XXXXXXX 100644
73
--- a/hw/timer/npcm7xx_timer.c
74
+++ b/hw/timer/npcm7xx_timer.c
75
@@ -XXX,XX +XXX,XX @@
76
#include "qemu/osdep.h"
77
78
#include "hw/irq.h"
79
+#include "hw/qdev-clock.h"
80
#include "hw/qdev-properties.h"
81
-#include "hw/misc/npcm7xx_clk.h"
82
#include "hw/timer/npcm7xx_timer.h"
83
#include "migration/vmstate.h"
84
#include "qemu/bitops.h"
85
@@ -XXX,XX +XXX,XX @@ static uint32_t npcm7xx_tcsr_prescaler(uint32_t tcsr)
86
/* Convert a timer cycle count to a time interval in nanoseconds. */
87
static int64_t npcm7xx_timer_count_to_ns(NPCM7xxTimer *t, uint32_t count)
88
{
89
- int64_t ns = count;
90
+ int64_t ticks = count;
91
92
- ns *= NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ;
93
- ns *= npcm7xx_tcsr_prescaler(t->tcsr);
94
+ ticks *= npcm7xx_tcsr_prescaler(t->tcsr);
95
96
- return ns;
97
+ return clock_ticks_to_ns(t->ctrl->clock, ticks);
98
}
99
100
/* Convert a time interval in nanoseconds to a timer cycle count. */
101
static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns)
102
{
103
- int64_t count;
104
-
105
- count = ns / (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ);
106
- count /= npcm7xx_tcsr_prescaler(t->tcsr);
107
-
108
- return count;
109
+ return ns / clock_ticks_to_ns(t->ctrl->clock,
110
+ npcm7xx_tcsr_prescaler(t->tcsr));
111
}
112
113
static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t)
114
@@ -XXX,XX +XXX,XX @@ static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t)
115
static void npcm7xx_watchdog_timer_reset_cycles(NPCM7xxWatchdogTimer *t,
116
int64_t cycles)
117
{
118
- uint32_t prescaler = npcm7xx_watchdog_timer_prescaler(t);
119
- int64_t ns = (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ) * cycles;
120
+ int64_t ticks = cycles * npcm7xx_watchdog_timer_prescaler(t);
121
+ int64_t ns = clock_ticks_to_ns(t->ctrl->clock, ticks);
122
25
123
/*
26
/*
124
* The reset function always clears the current timer. The caller of the
27
* Perform an unaligned store with tag 1 crossing the pages.
125
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_watchdog_timer_reset_cycles(NPCM7xxWatchdogTimer *t,
126
*/
127
npcm7xx_timer_clear(&t->base_timer);
128
129
- ns *= prescaler;
130
t->base_timer.remaining_ns = ns;
131
}
132
133
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_hold_reset(Object *obj)
134
qemu_irq_lower(s->watchdog_timer.irq);
135
}
136
137
-static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
138
+static void npcm7xx_timer_init(Object *obj)
139
{
140
- NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(dev);
141
- SysBusDevice *sbd = &s->parent;
142
+ NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(obj);
143
+ DeviceState *dev = DEVICE(obj);
144
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
145
int i;
146
NPCM7xxWatchdogTimer *w;
147
148
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
149
npcm7xx_watchdog_timer_expired, w);
150
sysbus_init_irq(sbd, &w->irq);
151
152
- memory_region_init_io(&s->iomem, OBJECT(s), &npcm7xx_timer_ops, s,
153
+ memory_region_init_io(&s->iomem, obj, &npcm7xx_timer_ops, s,
154
TYPE_NPCM7XX_TIMER, 4 * KiB);
155
sysbus_init_mmio(sbd, &s->iomem);
156
qdev_init_gpio_out_named(dev, &w->reset_signal,
157
NPCM7XX_WATCHDOG_RESET_GPIO_OUT, 1);
158
+ s->clock = qdev_init_clock_in(dev, "clock", NULL, NULL);
159
}
160
161
static const VMStateDescription vmstate_npcm7xx_base_timer = {
162
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_npcm7xx_watchdog_timer = {
163
164
static const VMStateDescription vmstate_npcm7xx_timer_ctrl = {
165
.name = "npcm7xx-timer-ctrl",
166
- .version_id = 1,
167
- .minimum_version_id = 1,
168
+ .version_id = 2,
169
+ .minimum_version_id = 2,
170
.fields = (VMStateField[]) {
171
VMSTATE_UINT32(tisr, NPCM7xxTimerCtrlState),
172
+ VMSTATE_CLOCK(clock, NPCM7xxTimerCtrlState),
173
VMSTATE_STRUCT_ARRAY(timer, NPCM7xxTimerCtrlState,
174
NPCM7XX_TIMERS_PER_CTRL, 0, vmstate_npcm7xx_timer,
175
NPCM7xxTimer),
176
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_class_init(ObjectClass *klass, void *data)
177
QEMU_BUILD_BUG_ON(NPCM7XX_TIMER_REGS_END > NPCM7XX_TIMER_NR_REGS);
178
179
dc->desc = "NPCM7xx Timer Controller";
180
- dc->realize = npcm7xx_timer_realize;
181
dc->vmsd = &vmstate_npcm7xx_timer_ctrl;
182
rc->phases.enter = npcm7xx_timer_enter_reset;
183
rc->phases.hold = npcm7xx_timer_hold_reset;
184
@@ -XXX,XX +XXX,XX @@ static const TypeInfo npcm7xx_timer_info = {
185
.parent = TYPE_SYS_BUS_DEVICE,
186
.instance_size = sizeof(NPCM7xxTimerCtrlState),
187
.class_init = npcm7xx_timer_class_init,
188
+ .instance_init = npcm7xx_timer_init,
189
};
190
191
static void npcm7xx_timer_register_type(void)
192
--
28
--
193
2.20.1
29
2.34.1
194
195
diff view generated by jsdifflib
New patch
1
From: Richard Henderson <richard.henderson@linaro.org>
1
2
3
With -cpu max and FEAT_LSE2, the __aarch64__ section will only raise
4
an alignment exception when the load crosses a 16-byte boundary.
5
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20230530191438.411344-20-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
tests/tcg/multiarch/sigbus.c | 13 +++++++++----
12
1 file changed, 9 insertions(+), 4 deletions(-)
13
14
diff --git a/tests/tcg/multiarch/sigbus.c b/tests/tcg/multiarch/sigbus.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/tcg/multiarch/sigbus.c
17
+++ b/tests/tcg/multiarch/sigbus.c
18
@@ -XXX,XX +XXX,XX @@
19
#include <endian.h>
20
21
22
-unsigned long long x = 0x8877665544332211ull;
23
-void * volatile p = (void *)&x + 1;
24
+char x[32] __attribute__((aligned(16))) = {
25
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
26
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
27
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
28
+ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
29
+};
30
+void * volatile p = (void *)&x + 15;
31
32
void sigbus(int sig, siginfo_t *info, void *uc)
33
{
34
@@ -XXX,XX +XXX,XX @@ int main()
35
* We might as well validate the unaligned load worked.
36
*/
37
if (BYTE_ORDER == LITTLE_ENDIAN) {
38
- assert(tmp == 0x55443322);
39
+ assert(tmp == 0x13121110);
40
} else {
41
- assert(tmp == 0x77665544);
42
+ assert(tmp == 0x10111213);
43
}
44
return EXIT_SUCCESS;
45
}
46
--
47
2.34.1
diff view generated by jsdifflib
New patch
1
From: Richard Henderson <richard.henderson@linaro.org>
1
2
3
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
4
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
5
Message-id: 20230530191438.411344-21-richard.henderson@linaro.org
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
---
8
docs/system/arm/emulation.rst | 1 +
9
target/arm/tcg/cpu64.c | 1 +
10
2 files changed, 2 insertions(+)
11
12
diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst
13
index XXXXXXX..XXXXXXX 100644
14
--- a/docs/system/arm/emulation.rst
15
+++ b/docs/system/arm/emulation.rst
16
@@ -XXX,XX +XXX,XX @@ the following architecture extensions:
17
- FEAT_LRCPC (Load-acquire RCpc instructions)
18
- FEAT_LRCPC2 (Load-acquire RCpc instructions v2)
19
- FEAT_LSE (Large System Extensions)
20
+- FEAT_LSE2 (Large System Extensions v2)
21
- FEAT_LVA (Large Virtual Address space)
22
- FEAT_MTE (Memory Tagging Extension)
23
- FEAT_MTE2 (Memory Tagging Extension)
24
diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c
25
index XXXXXXX..XXXXXXX 100644
26
--- a/target/arm/tcg/cpu64.c
27
+++ b/target/arm/tcg/cpu64.c
28
@@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj)
29
t = FIELD_DP64(t, ID_AA64MMFR2, IESB, 1); /* FEAT_IESB */
30
t = FIELD_DP64(t, ID_AA64MMFR2, VARANGE, 1); /* FEAT_LVA */
31
t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* FEAT_TTST */
32
+ t = FIELD_DP64(t, ID_AA64MMFR2, AT, 1); /* FEAT_LSE2 */
33
t = FIELD_DP64(t, ID_AA64MMFR2, IDS, 1); /* FEAT_IDST */
34
t = FIELD_DP64(t, ID_AA64MMFR2, FWB, 1); /* FEAT_S2FWB */
35
t = FIELD_DP64(t, ID_AA64MMFR2, TTL, 1); /* FEAT_TTL */
36
--
37
2.34.1
diff view generated by jsdifflib
1
From: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
1
From: Zhuojia Shen <chaosdefinition@hotmail.com>
2
2
3
This adds for the Small Translation tables extension in AArch64 state.
3
DC CVAP and DC CVADP instructions can be executed in EL0 on Linux,
4
either directly when SCTLR_EL1.UCI == 1 or emulated by the kernel (see
5
user_cache_maint_handler() in arch/arm64/kernel/traps.c).
4
6
5
Signed-off-by: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
7
This patch enables execution of the two instructions in user mode
8
emulation.
9
10
Signed-off-by: Zhuojia Shen <chaosdefinition@hotmail.com>
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
12
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
---
14
---
9
target/arm/cpu.h | 5 +++++
15
target/arm/helper.c | 6 ++----
10
target/arm/helper.c | 15 +++++++++++++--
16
1 file changed, 2 insertions(+), 4 deletions(-)
11
2 files changed, 18 insertions(+), 2 deletions(-)
12
17
13
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
14
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/cpu.h
16
+++ b/target/arm/cpu.h
17
@@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_uao(const ARMISARegisters *id)
18
return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, UAO) != 0;
19
}
20
21
+static inline bool isar_feature_aa64_st(const ARMISARegisters *id)
22
+{
23
+ return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, ST) != 0;
24
+}
25
+
26
static inline bool isar_feature_aa64_bti(const ARMISARegisters *id)
27
{
28
return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0;
29
diff --git a/target/arm/helper.c b/target/arm/helper.c
18
diff --git a/target/arm/helper.c b/target/arm/helper.c
30
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
31
--- a/target/arm/helper.c
20
--- a/target/arm/helper.c
32
+++ b/target/arm/helper.c
21
+++ b/target/arm/helper.c
33
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
22
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo rndr_reginfo[] = {
23
.access = PL0_R, .readfn = rndr_readfn },
24
};
25
26
-#ifndef CONFIG_USER_ONLY
27
static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *opaque,
28
uint64_t value)
34
{
29
{
35
uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr;
30
@@ -XXX,XX +XXX,XX @@ static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *opaque,
36
bool epd, hpd, using16k, using64k;
31
/* This won't be crossing page boundaries */
37
- int select, tsz, tbi;
32
haddr = probe_read(env, vaddr, dline_size, mem_idx, GETPC());
38
+ int select, tsz, tbi, max_tsz;
33
if (haddr) {
39
34
+#ifndef CONFIG_USER_ONLY
40
if (!regime_has_2_ranges(mmu_idx)) {
35
41
select = 0;
36
ram_addr_t offset;
42
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
37
MemoryRegion *mr;
43
hpd = extract64(tcr, 42, 1);
38
@@ -XXX,XX +XXX,XX @@ static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *opaque,
39
if (mr) {
40
memory_region_writeback(mr, offset, dline_size);
41
}
42
+#endif /*CONFIG_USER_ONLY*/
43
}
44
}
45
46
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo dcpodp_reg[] = {
47
.fgt = FGT_DCCVADP,
48
.accessfn = aa64_cacheop_poc_access, .writefn = dccvap_writefn },
49
};
50
-#endif /*CONFIG_USER_ONLY*/
51
52
static CPAccessResult access_aa64_tid5(CPUARMState *env, const ARMCPRegInfo *ri,
53
bool isread)
54
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
55
if (cpu_isar_feature(aa64_tlbios, cpu)) {
56
define_arm_cp_regs(cpu, tlbios_reginfo);
57
}
58
-#ifndef CONFIG_USER_ONLY
59
/* Data Cache clean instructions up to PoP */
60
if (cpu_isar_feature(aa64_dcpop, cpu)) {
61
define_one_arm_cp_reg(cpu, dcpop_reg);
62
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
63
define_one_arm_cp_reg(cpu, dcpodp_reg);
44
}
64
}
45
}
65
}
46
- tsz = MIN(tsz, 39); /* TODO: ARMv8.4-TTST */
66
-#endif /*CONFIG_USER_ONLY*/
47
+
67
48
+ if (cpu_isar_feature(aa64_st, env_archcpu(env))) {
68
/*
49
+ max_tsz = 48 - using64k;
69
* If full MTE is enabled, add all of the system registers.
50
+ } else {
51
+ max_tsz = 39;
52
+ }
53
+
54
+ tsz = MIN(tsz, max_tsz);
55
tsz = MAX(tsz, 16); /* TODO: ARMv8.2-LVA */
56
57
/* Present TBI as a composite with TBID. */
58
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
59
if (!aarch64 || stride == 9) {
60
/* AArch32 or 4KB pages */
61
startlevel = 2 - sl0;
62
+
63
+ if (cpu_isar_feature(aa64_st, cpu)) {
64
+ startlevel &= 3;
65
+ }
66
} else {
67
/* 16KB or 64KB pages */
68
startlevel = 3 - sl0;
69
--
70
--
70
2.20.1
71
2.34.1
71
72
diff view generated by jsdifflib
1
From: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
1
From: Zhuojia Shen <chaosdefinition@hotmail.com>
2
2
3
Signed-off-by: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
3
Test execution of DC CVAP and DC CVADP instructions under user mode
4
emulation.
5
6
Signed-off-by: Zhuojia Shen <chaosdefinition@hotmail.com>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
---
10
---
7
target/arm/cpu64.c | 1 +
11
tests/tcg/aarch64/dcpodp.c | 63 +++++++++++++++++++++++++++++++
8
1 file changed, 1 insertion(+)
12
tests/tcg/aarch64/dcpop.c | 63 +++++++++++++++++++++++++++++++
13
tests/tcg/aarch64/Makefile.target | 11 ++++++
14
3 files changed, 137 insertions(+)
15
create mode 100644 tests/tcg/aarch64/dcpodp.c
16
create mode 100644 tests/tcg/aarch64/dcpop.c
9
17
10
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
18
diff --git a/tests/tcg/aarch64/dcpodp.c b/tests/tcg/aarch64/dcpodp.c
19
new file mode 100644
20
index XXXXXXX..XXXXXXX
21
--- /dev/null
22
+++ b/tests/tcg/aarch64/dcpodp.c
23
@@ -XXX,XX +XXX,XX @@
24
+/*
25
+ * Test execution of DC CVADP instruction.
26
+ *
27
+ * Copyright (c) 2023 Zhuojia Shen <chaosdefinition@hotmail.com>
28
+ * SPDX-License-Identifier: GPL-2.0-or-later
29
+ */
30
+
31
+#include <asm/hwcap.h>
32
+#include <sys/auxv.h>
33
+
34
+#include <signal.h>
35
+#include <stdbool.h>
36
+#include <stdio.h>
37
+#include <stdlib.h>
38
+
39
+#ifndef HWCAP2_DCPODP
40
+#define HWCAP2_DCPODP (1 << 0)
41
+#endif
42
+
43
+bool should_fail = false;
44
+
45
+static void signal_handler(int sig, siginfo_t *si, void *data)
46
+{
47
+ ucontext_t *uc = (ucontext_t *)data;
48
+
49
+ if (should_fail) {
50
+ uc->uc_mcontext.pc += 4;
51
+ } else {
52
+ exit(EXIT_FAILURE);
53
+ }
54
+}
55
+
56
+static int do_dc_cvadp(void)
57
+{
58
+ struct sigaction sa = {
59
+ .sa_flags = SA_SIGINFO,
60
+ .sa_sigaction = signal_handler,
61
+ };
62
+
63
+ sigemptyset(&sa.sa_mask);
64
+ if (sigaction(SIGSEGV, &sa, NULL) < 0) {
65
+ perror("sigaction");
66
+ return EXIT_FAILURE;
67
+ }
68
+
69
+ asm volatile("dc cvadp, %0\n\t" :: "r"(&sa));
70
+
71
+ should_fail = true;
72
+ asm volatile("dc cvadp, %0\n\t" :: "r"(NULL));
73
+ should_fail = false;
74
+
75
+ return EXIT_SUCCESS;
76
+}
77
+
78
+int main(void)
79
+{
80
+ if (getauxval(AT_HWCAP2) & HWCAP2_DCPODP) {
81
+ return do_dc_cvadp();
82
+ } else {
83
+ printf("SKIP: no HWCAP2_DCPODP on this system\n");
84
+ return EXIT_SUCCESS;
85
+ }
86
+}
87
diff --git a/tests/tcg/aarch64/dcpop.c b/tests/tcg/aarch64/dcpop.c
88
new file mode 100644
89
index XXXXXXX..XXXXXXX
90
--- /dev/null
91
+++ b/tests/tcg/aarch64/dcpop.c
92
@@ -XXX,XX +XXX,XX @@
93
+/*
94
+ * Test execution of DC CVAP instruction.
95
+ *
96
+ * Copyright (c) 2023 Zhuojia Shen <chaosdefinition@hotmail.com>
97
+ * SPDX-License-Identifier: GPL-2.0-or-later
98
+ */
99
+
100
+#include <asm/hwcap.h>
101
+#include <sys/auxv.h>
102
+
103
+#include <signal.h>
104
+#include <stdbool.h>
105
+#include <stdio.h>
106
+#include <stdlib.h>
107
+
108
+#ifndef HWCAP_DCPOP
109
+#define HWCAP_DCPOP (1 << 16)
110
+#endif
111
+
112
+bool should_fail = false;
113
+
114
+static void signal_handler(int sig, siginfo_t *si, void *data)
115
+{
116
+ ucontext_t *uc = (ucontext_t *)data;
117
+
118
+ if (should_fail) {
119
+ uc->uc_mcontext.pc += 4;
120
+ } else {
121
+ exit(EXIT_FAILURE);
122
+ }
123
+}
124
+
125
+static int do_dc_cvap(void)
126
+{
127
+ struct sigaction sa = {
128
+ .sa_flags = SA_SIGINFO,
129
+ .sa_sigaction = signal_handler,
130
+ };
131
+
132
+ sigemptyset(&sa.sa_mask);
133
+ if (sigaction(SIGSEGV, &sa, NULL) < 0) {
134
+ perror("sigaction");
135
+ return EXIT_FAILURE;
136
+ }
137
+
138
+ asm volatile("dc cvap, %0\n\t" :: "r"(&sa));
139
+
140
+ should_fail = true;
141
+ asm volatile("dc cvap, %0\n\t" :: "r"(NULL));
142
+ should_fail = false;
143
+
144
+ return EXIT_SUCCESS;
145
+}
146
+
147
+int main(void)
148
+{
149
+ if (getauxval(AT_HWCAP) & HWCAP_DCPOP) {
150
+ return do_dc_cvap();
151
+ } else {
152
+ printf("SKIP: no HWCAP_DCPOP on this system\n");
153
+ return EXIT_SUCCESS;
154
+ }
155
+}
156
diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
11
index XXXXXXX..XXXXXXX 100644
157
index XXXXXXX..XXXXXXX 100644
12
--- a/target/arm/cpu64.c
158
--- a/tests/tcg/aarch64/Makefile.target
13
+++ b/target/arm/cpu64.c
159
+++ b/tests/tcg/aarch64/Makefile.target
14
@@ -XXX,XX +XXX,XX @@ static void aarch64_max_initfn(Object *obj)
160
@@ -XXX,XX +XXX,XX @@ config-cc.mak: Makefile
15
t = cpu->isar.id_aa64mmfr2;
161
    $(quiet-@)( \
16
t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1);
162
     $(call cc-option,-march=armv8.1-a+sve, CROSS_CC_HAS_SVE); \
17
t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* TTCNP */
163
     $(call cc-option,-march=armv8.1-a+sve2, CROSS_CC_HAS_SVE2); \
18
+ t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* TTST */
164
+     $(call cc-option,-march=armv8.2-a, CROSS_CC_HAS_ARMV8_2); \
19
cpu->isar.id_aa64mmfr2 = t;
165
     $(call cc-option,-march=armv8.3-a, CROSS_CC_HAS_ARMV8_3); \
20
166
+     $(call cc-option,-march=armv8.5-a, CROSS_CC_HAS_ARMV8_5); \
21
/* Replicate the same data to the 32-bit id registers. */
167
     $(call cc-option,-mbranch-protection=standard, CROSS_CC_HAS_ARMV8_BTI); \
168
     $(call cc-option,-march=armv8.5-a+memtag, CROSS_CC_HAS_ARMV8_MTE); \
169
     $(call cc-option,-march=armv9-a+sme, CROSS_CC_HAS_ARMV9_SME)) 3> config-cc.mak
170
-include config-cc.mak
171
172
+ifneq ($(CROSS_CC_HAS_ARMV8_2),)
173
+AARCH64_TESTS += dcpop
174
+dcpop: CFLAGS += -march=armv8.2-a
175
+endif
176
+ifneq ($(CROSS_CC_HAS_ARMV8_5),)
177
+AARCH64_TESTS += dcpodp
178
+dcpodp: CFLAGS += -march=armv8.5-a
179
+endif
180
+
181
# Pauth Tests
182
ifneq ($(CROSS_CC_HAS_ARMV8_3),)
183
AARCH64_TESTS += pauth-1 pauth-2 pauth-4 pauth-5
22
--
184
--
23
2.20.1
185
2.34.1
24
25
diff view generated by jsdifflib
1
From: Roman Bolshakov <r.bolshakov@yadro.com>
1
From: Zhuojia Shen <chaosdefinition@hotmail.com>
2
2
3
ui/cocoa.m:1188:44: warning: 'openFile:' is deprecated: first deprecated in macOS 11.0 - Use -[NSWorkspace openURL:] instead.
3
Accessing EL0-accessible Debug Communication Channel (DCC) registers in
4
[-Wdeprecated-declarations]
4
user mode emulation is currently enabled. However, it does not match
5
if ([[NSWorkspace sharedWorkspace] openFile: full_file_path] == YES) {
5
Linux behavior as Linux sets MDSCR_EL1.TDCC on startup to disable EL0
6
^
6
access to DCC (see __cpu_setup() in arch/arm64/mm/proc.S).
7
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/AppKit.framework/Headers/NSWorkspace.h:350:1: note:
8
'openFile:' has been explicitly marked deprecated here
9
- (BOOL)openFile:(NSString *)fullPath API_DEPRECATED("Use -[NSWorkspace openURL:] instead.", macos(10.0, 11.0));
10
^
11
7
12
Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
8
This patch fixes access_tdcc() to check MDSCR_EL1.TDCC for EL0 and sets
13
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
MDSCR_EL1.TDCC for user mode emulation to match Linux.
14
Message-id: 20210102150718.47618-1-r.bolshakov@yadro.com
10
11
Signed-off-by: Zhuojia Shen <chaosdefinition@hotmail.com>
12
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
13
Message-id: DS7PR12MB630905198DD8E69F6817544CAC4EA@DS7PR12MB6309.namprd12.prod.outlook.com
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
---
15
---
17
ui/cocoa.m | 5 ++++-
16
target/arm/cpu.c | 2 ++
18
1 file changed, 4 insertions(+), 1 deletion(-)
17
target/arm/debug_helper.c | 5 +++++
18
2 files changed, 7 insertions(+)
19
19
20
diff --git a/ui/cocoa.m b/ui/cocoa.m
20
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
21
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
22
--- a/ui/cocoa.m
22
--- a/target/arm/cpu.c
23
+++ b/ui/cocoa.m
23
+++ b/target/arm/cpu.c
24
@@ -XXX,XX +XXX,XX @@ QemuCocoaView *cocoaView;
24
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_reset_hold(Object *obj)
25
/* Where to look for local files */
25
* This is not yet exposed from the Linux kernel in any way.
26
NSString *path_array[] = {@"../share/doc/qemu/", @"../doc/qemu/", @"docs/"};
26
*/
27
NSString *full_file_path;
27
env->cp15.sctlr_el[1] |= SCTLR_TSCXT;
28
+ NSURL *full_file_url;
28
+ /* Disable access to Debug Communication Channel (DCC). */
29
29
+ env->cp15.mdscr_el1 |= 1 << 12;
30
/* iterate thru the possible paths until the file is found */
30
#else
31
int index;
31
/* Reset into the highest available EL */
32
@@ -XXX,XX +XXX,XX @@ QemuCocoaView *cocoaView;
32
if (arm_feature(env, ARM_FEATURE_EL3)) {
33
full_file_path = [full_file_path stringByDeletingLastPathComponent];
33
diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c
34
full_file_path = [NSString stringWithFormat: @"%@/%@%@", full_file_path,
34
index XXXXXXX..XXXXXXX 100644
35
path_array[index], filename];
35
--- a/target/arm/debug_helper.c
36
- if ([[NSWorkspace sharedWorkspace] openFile: full_file_path] == YES) {
36
+++ b/target/arm/debug_helper.c
37
+ full_file_url = [NSURL fileURLWithPath: full_file_path
37
@@ -XXX,XX +XXX,XX @@ static CPAccessResult access_tda(CPUARMState *env, const ARMCPRegInfo *ri,
38
+ isDirectory: false];
38
* is implemented then these are controlled by MDCR_EL2.TDCC for
39
+ if ([[NSWorkspace sharedWorkspace] openURL: full_file_url] == YES) {
39
* EL2 and MDCR_EL3.TDCC for EL3. They are also controlled by
40
return;
40
* the general debug access trap bits MDCR_EL2.TDA and MDCR_EL3.TDA.
41
}
41
+ * For EL0, they are also controlled by MDSCR_EL1.TDCC.
42
*/
43
static CPAccessResult access_tdcc(CPUARMState *env, const ARMCPRegInfo *ri,
44
bool isread)
45
{
46
int el = arm_current_el(env);
47
uint64_t mdcr_el2 = arm_mdcr_el2_eff(env);
48
+ bool mdscr_el1_tdcc = extract32(env->cp15.mdscr_el1, 12, 1);
49
bool mdcr_el2_tda = (mdcr_el2 & MDCR_TDA) || (mdcr_el2 & MDCR_TDE) ||
50
(arm_hcr_el2_eff(env) & HCR_TGE);
51
bool mdcr_el2_tdcc = cpu_isar_feature(aa64_fgt, env_archcpu(env)) &&
52
@@ -XXX,XX +XXX,XX @@ static CPAccessResult access_tdcc(CPUARMState *env, const ARMCPRegInfo *ri,
53
bool mdcr_el3_tdcc = cpu_isar_feature(aa64_fgt, env_archcpu(env)) &&
54
(env->cp15.mdcr_el3 & MDCR_TDCC);
55
56
+ if (el < 1 && mdscr_el1_tdcc) {
57
+ return CP_ACCESS_TRAP;
58
+ }
59
if (el < 2 && (mdcr_el2_tda || mdcr_el2_tdcc)) {
60
return CP_ACCESS_TRAP_EL2;
42
}
61
}
43
--
62
--
44
2.20.1
63
2.34.1
45
46
diff view generated by jsdifflib