1
The following changes since commit eae587e8e3694b1aceab23239493fb4c7e1a80f5:
1
Arm queue; not huge but I figured I might as well send it out since
2
I've been doing code review today and there's no queue of unprocessed
3
pullreqs...
2
4
3
Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2021-09-13' into staging (2021-09-13 11:00:30 +0100)
5
thanks
6
-- PMM
7
8
The following changes since commit b3f846c59d8405bb87c551187721fc92ff2f1b92:
9
10
Merge remote-tracking branch 'remotes/huth-gitlab/tags/pull-request-2021-01-11v2' into staging (2021-01-11 15:15:35 +0000)
4
11
5
are available in the Git repository at:
12
are available in the Git repository at:
6
13
7
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20210913
14
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20210112
8
15
9
for you to fetch changes up to 9a2b2ecf4d25a3943918c95d2db4508b304161b5:
16
for you to fetch changes up to 19d131395ccaf503db21dadd8257e6dc9fc1d7de:
10
17
11
hw/arm/mps2.c: Mark internal-only I2C buses as 'full' (2021-09-13 17:09:28 +0100)
18
ui/cocoa: Fix openFile: deprecation on Big Sur (2021-01-12 11:38:37 +0000)
12
19
13
----------------------------------------------------------------
20
----------------------------------------------------------------
14
target-arm queue:
21
target-arm queue:
15
* mark MPS2/MPS3 board-internal i2c buses as 'full' so that command
22
* arm: Support emulation of ARMv8.4-TTST extension
16
line user-created devices are not plugged into them
23
* arm: Update cpu.h ID register field definitions
17
* Take an exception if PSTATE.IL is set
24
* arm: Fix breakage of XScale instruction emulation
18
* Support an emulated ITS in the virt board
25
* hw/net/lan9118: Fix RX Status FIFO PEEK value
19
* Add support for kudo-bmc board
26
* npcm7xx: Add ADC and PWM emulation
20
* Probe for KVM_CAP_ARM_VM_IPA_SIZE when creating scratch VM
27
* ui/cocoa: Make "open docs" help menu entry work again when binary
21
* cadence_uart: Fix clock handling issues that prevented
28
is run from the build tree
22
u-boot from running
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
23
32
24
----------------------------------------------------------------
33
----------------------------------------------------------------
25
Bin Meng (6):
34
Hao Wu (6):
26
hw/misc: zynq_slcr: Correctly compute output clocks in the reset exit phase
35
hw/misc: Add clock converter in NPCM7XX CLK module
27
hw/char: cadence_uart: Disable transmit when input clock is disabled
36
hw/timer: Refactor NPCM7XX Timer to use CLK clock
28
hw/char: cadence_uart: Move clock/reset check to uart_can_receive()
37
hw/adc: Add an ADC module for NPCM7XX
29
hw/char: cadence_uart: Convert to memop_with_attrs() ops
38
hw/misc: Add a PWM module for NPCM7XX
30
hw/char: cadence_uart: Ignore access when unclocked or in reset for uart_{read, write}()
39
hw/misc: Add QTest for NPCM7XX PWM Module
31
hw/char: cadence_uart: Log a guest error when device is unclocked or in reset
40
hw/*: Use type casting for SysBusDevice in NPCM7XX
32
41
33
Chris Rauer (1):
42
Leif Lindholm (6):
34
hw/arm: Add support for kudo-bmc board.
43
target/arm: fix typo in cpu.h ID_AA64PFR1 field name
35
44
target/arm: make ARMCPU.clidr 64-bit
36
Marc Zyngier (1):
45
target/arm: make ARMCPU.ctr 64-bit
37
hw/arm/virt: KVM: Probe for KVM_CAP_ARM_VM_IPA_SIZE when creating scratch VM
46
target/arm: add descriptions of CLIDR_EL1, CCSIDR_EL1, CTR_EL0 to cpu.h
47
target/arm: add aarch64 ID register fields to cpu.h
48
target/arm: add aarch32 ID register fields to cpu.h
38
49
39
Peter Maydell (5):
50
Peter Maydell (5):
40
target/arm: Take an exception if PSTATE.IL is set
51
docs: Add qemu-storage-daemon(1) manpage to meson.build
41
qdev: Support marking individual buses as 'full'
52
docs: Build and install all the docs in a single manual
42
hw/arm/mps2-tz.c: Add extra data parameter to MakeDevFn
53
target/arm: Don't decode insns in the XScale/iWMMXt space as cp insns
43
hw/arm/mps2-tz.c: Mark internal-only I2C buses as 'full'
54
hw/net/lan9118: Fix RX Status FIFO PEEK value
44
hw/arm/mps2.c: Mark internal-only I2C buses as 'full'
55
hw/net/lan9118: Add symbolic constants for register offsets
45
56
46
Richard Henderson (1):
57
Roman Bolshakov (2):
47
target/arm: Merge disas_a64_insn into aarch64_tr_translate_insn
58
ui/cocoa: Update path to docs in build tree
59
ui/cocoa: Fix openFile: deprecation on Big Sur
48
60
49
Shashi Mallela (9):
61
Rémi Denis-Courmont (2):
50
hw/intc: GICv3 ITS initial framework
62
target/arm: ARMv8.4-TTST extension
51
hw/intc: GICv3 ITS register definitions added
63
target/arm: enable Small Translation tables in max CPU
52
hw/intc: GICv3 ITS command queue framework
53
hw/intc: GICv3 ITS Command processing
54
hw/intc: GICv3 ITS Feature enablement
55
hw/intc: GICv3 redistributor ITS processing
56
tests/data/acpi/virt: Add IORT files for ITS
57
hw/arm/virt: add ITS support in virt GIC
58
tests/data/acpi/virt: Update IORT files for ITS
59
64
60
docs/system/arm/nuvoton.rst | 1 +
65
docs/conf.py | 46 ++-
61
hw/intc/gicv3_internal.h | 188 ++++-
66
docs/devel/conf.py | 15 -
62
include/hw/arm/virt.h | 2 +
67
docs/index.html.in | 17 -
63
include/hw/intc/arm_gicv3_common.h | 13 +
68
docs/interop/conf.py | 28 --
64
include/hw/intc/arm_gicv3_its_common.h | 32 +-
69
docs/meson.build | 65 ++--
65
include/hw/qdev-core.h | 24 +
70
docs/specs/conf.py | 16 -
66
target/arm/cpu.h | 1 +
71
docs/system/arm/nuvoton.rst | 4 +-
67
target/arm/kvm_arm.h | 4 +-
72
docs/system/conf.py | 28 --
68
target/arm/syndrome.h | 5 +
73
docs/tools/conf.py | 37 --
69
target/arm/translate.h | 2 +
74
docs/user/conf.py | 15 -
70
hw/arm/mps2-tz.c | 92 ++-
75
meson.build | 1 +
71
hw/arm/mps2.c | 12 +-
76
hw/adc/trace.h | 1 +
72
hw/arm/npcm7xx_boards.c | 34 +
77
include/hw/adc/npcm7xx_adc.h | 69 ++++
73
hw/arm/virt.c | 29 +-
78
include/hw/arm/npcm7xx.h | 4 +
74
hw/char/cadence_uart.c | 61 +-
79
include/hw/misc/npcm7xx_clk.h | 146 ++++++-
75
hw/intc/arm_gicv3.c | 14 +
80
include/hw/misc/npcm7xx_pwm.h | 105 +++++
76
hw/intc/arm_gicv3_common.c | 13 +
81
include/hw/timer/npcm7xx_timer.h | 1 +
77
hw/intc/arm_gicv3_cpuif.c | 7 +-
82
target/arm/cpu.h | 85 ++++-
78
hw/intc/arm_gicv3_dist.c | 5 +-
83
hw/adc/npcm7xx_adc.c | 301 +++++++++++++++
79
hw/intc/arm_gicv3_its.c | 1322 ++++++++++++++++++++++++++++++++
84
hw/arm/npcm7xx.c | 55 ++-
80
hw/intc/arm_gicv3_its_common.c | 7 +-
85
hw/arm/npcm7xx_boards.c | 2 +-
81
hw/intc/arm_gicv3_its_kvm.c | 2 +-
86
hw/mem/npcm7xx_mc.c | 2 +-
82
hw/intc/arm_gicv3_redist.c | 153 +++-
87
hw/misc/npcm7xx_clk.c | 807 ++++++++++++++++++++++++++++++++++++++-
83
hw/misc/zynq_slcr.c | 31 +-
88
hw/misc/npcm7xx_gcr.c | 2 +-
84
softmmu/qdev-monitor.c | 7 +-
89
hw/misc/npcm7xx_pwm.c | 550 ++++++++++++++++++++++++++
85
target/arm/helper-a64.c | 1 +
90
hw/misc/npcm7xx_rng.c | 2 +-
86
target/arm/helper.c | 8 +
91
hw/net/lan9118.c | 26 +-
87
target/arm/kvm.c | 7 +-
92
hw/nvram/npcm7xx_otp.c | 2 +-
88
target/arm/translate-a64.c | 255 +++---
93
hw/ssi/npcm7xx_fiu.c | 2 +-
89
target/arm/translate.c | 21 +
94
hw/timer/npcm7xx_timer.c | 39 +-
90
hw/intc/meson.build | 1 +
95
target/arm/cpu64.c | 1 +
91
tests/data/acpi/virt/IORT | Bin 0 -> 124 bytes
96
target/arm/helper.c | 15 +-
92
tests/data/acpi/virt/IORT.memhp | Bin 0 -> 124 bytes
97
target/arm/translate.c | 7 +
93
tests/data/acpi/virt/IORT.numamem | Bin 0 -> 124 bytes
98
tests/qtest/npcm7xx_adc-test.c | 377 ++++++++++++++++++
94
tests/data/acpi/virt/IORT.pxb | Bin 0 -> 124 bytes
99
tests/qtest/npcm7xx_pwm-test.c | 490 ++++++++++++++++++++++++
95
35 files changed, 2144 insertions(+), 210 deletions(-)
100
hw/adc/meson.build | 1 +
96
create mode 100644 hw/intc/arm_gicv3_its.c
101
hw/adc/trace-events | 5 +
97
create mode 100644 tests/data/acpi/virt/IORT
102
hw/misc/meson.build | 1 +
98
create mode 100644 tests/data/acpi/virt/IORT.memhp
103
hw/misc/trace-events | 6 +
99
create mode 100644 tests/data/acpi/virt/IORT.numamem
104
tests/qtest/meson.build | 4 +-
100
create mode 100644 tests/data/acpi/virt/IORT.pxb
105
ui/cocoa.m | 7 +-
106
41 files changed, 3124 insertions(+), 263 deletions(-)
107
delete mode 100644 docs/devel/conf.py
108
delete mode 100644 docs/index.html.in
109
delete mode 100644 docs/interop/conf.py
110
delete mode 100644 docs/specs/conf.py
111
delete mode 100644 docs/system/conf.py
112
delete mode 100644 docs/tools/conf.py
113
delete mode 100644 docs/user/conf.py
114
create mode 100644 hw/adc/trace.h
115
create mode 100644 include/hw/adc/npcm7xx_adc.h
116
create mode 100644 include/hw/misc/npcm7xx_pwm.h
117
create mode 100644 hw/adc/npcm7xx_adc.c
118
create mode 100644 hw/misc/npcm7xx_pwm.c
119
create mode 100644 tests/qtest/npcm7xx_adc-test.c
120
create mode 100644 tests/qtest/npcm7xx_pwm-test.c
121
create mode 100644 hw/adc/trace-events
101
122
diff view generated by jsdifflib
1
In v8A, the PSTATE.IL bit is set for various kinds of illegal
1
From: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
2
exception return or mode-change attempts. We already set PSTATE.IL
3
(or its AArch32 equivalent CPSR.IL) in all those cases, but we
4
weren't implementing the part of the behaviour where attempting to
5
execute an instruction with PSTATE.IL takes an immediate exception
6
with an appropriate syndrome value.
7
2
8
Add a new TB flags bit tracking PSTATE.IL/CPSR.IL, and generate code
3
This adds for the Small Translation tables extension in AArch64 state.
9
to take an exception instead of whatever the instruction would have
10
been.
11
4
12
PSTATE.IL and CPSR.IL change only on exception entry, attempted
5
Signed-off-by: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
13
exception exit, and various AArch32 mode changes via cpsr_write().
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
14
These places generally already rebuild the hflags, so the only place
15
we need an extra rebuild_hflags call is in the illegal-return
16
codepath of the AArch64 exception_return helper.
17
18
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
19
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
20
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
21
Message-id: 20210821195958.41312-2-richard.henderson@linaro.org
22
Message-Id: <20210817162118.24319-1-peter.maydell@linaro.org>
23
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
24
[rth: Added missing returns; set IL bit in syndrome]
25
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
26
---
8
---
27
target/arm/cpu.h | 1 +
9
target/arm/cpu.h | 5 +++++
28
target/arm/syndrome.h | 5 +++++
10
target/arm/helper.c | 15 +++++++++++++--
29
target/arm/translate.h | 2 ++
11
2 files changed, 18 insertions(+), 2 deletions(-)
30
target/arm/helper-a64.c | 1 +
31
target/arm/helper.c | 8 ++++++++
32
target/arm/translate-a64.c | 11 +++++++++++
33
target/arm/translate.c | 21 +++++++++++++++++++++
34
7 files changed, 49 insertions(+)
35
12
36
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
13
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
37
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
38
--- a/target/arm/cpu.h
15
--- a/target/arm/cpu.h
39
+++ b/target/arm/cpu.h
16
+++ b/target/arm/cpu.h
40
@@ -XXX,XX +XXX,XX @@ FIELD(TBFLAG_ANY, FPEXC_EL, 8, 2)
17
@@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_uao(const ARMISARegisters *id)
41
FIELD(TBFLAG_ANY, DEBUG_TARGET_EL, 10, 2)
18
return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, UAO) != 0;
42
/* Memory operations require alignment: SCTLR_ELx.A or CCR.UNALIGN_TRP */
43
FIELD(TBFLAG_ANY, ALIGN_MEM, 12, 1)
44
+FIELD(TBFLAG_ANY, PSTATE__IL, 13, 1)
45
46
/*
47
* Bit usage when in AArch32 state, both A- and M-profile.
48
diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h
49
index XXXXXXX..XXXXXXX 100644
50
--- a/target/arm/syndrome.h
51
+++ b/target/arm/syndrome.h
52
@@ -XXX,XX +XXX,XX @@ static inline uint32_t syn_wfx(int cv, int cond, int ti, bool is_16bit)
53
(cv << 24) | (cond << 20) | ti;
54
}
19
}
55
20
56
+static inline uint32_t syn_illegalstate(void)
21
+static inline bool isar_feature_aa64_st(const ARMISARegisters *id)
57
+{
22
+{
58
+ return (EC_ILLEGALSTATE << ARM_EL_EC_SHIFT) | ARM_EL_IL;
23
+ return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, ST) != 0;
59
+}
24
+}
60
+
25
+
61
#endif /* TARGET_ARM_SYNDROME_H */
26
static inline bool isar_feature_aa64_bti(const ARMISARegisters *id)
62
diff --git a/target/arm/translate.h b/target/arm/translate.h
27
{
63
index XXXXXXX..XXXXXXX 100644
28
return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0;
64
--- a/target/arm/translate.h
65
+++ b/target/arm/translate.h
66
@@ -XXX,XX +XXX,XX @@ typedef struct DisasContext {
67
bool hstr_active;
68
/* True if memory operations require alignment */
69
bool align_mem;
70
+ /* True if PSTATE.IL is set */
71
+ bool pstate_il;
72
/*
73
* >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI.
74
* < 0, set by the current instruction.
75
diff --git a/target/arm/helper-a64.c b/target/arm/helper-a64.c
76
index XXXXXXX..XXXXXXX 100644
77
--- a/target/arm/helper-a64.c
78
+++ b/target/arm/helper-a64.c
79
@@ -XXX,XX +XXX,XX @@ illegal_return:
80
if (!arm_singlestep_active(env)) {
81
env->pstate &= ~PSTATE_SS;
82
}
83
+ helper_rebuild_hflags_a64(env, cur_el);
84
qemu_log_mask(LOG_GUEST_ERROR, "Illegal exception return at EL%d: "
85
"resuming execution at 0x%" PRIx64 "\n", cur_el, env->pc);
86
}
87
diff --git a/target/arm/helper.c b/target/arm/helper.c
29
diff --git a/target/arm/helper.c b/target/arm/helper.c
88
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
89
--- a/target/arm/helper.c
31
--- a/target/arm/helper.c
90
+++ b/target/arm/helper.c
32
+++ b/target/arm/helper.c
91
@@ -XXX,XX +XXX,XX @@ static CPUARMTBFlags rebuild_hflags_a32(CPUARMState *env, int fp_el,
33
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
92
DP_TBFLAG_A32(flags, HSTR_ACTIVE, 1);
34
{
35
uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr;
36
bool epd, hpd, using16k, using64k;
37
- int select, tsz, tbi;
38
+ int select, tsz, tbi, max_tsz;
39
40
if (!regime_has_2_ranges(mmu_idx)) {
41
select = 0;
42
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
43
hpd = extract64(tcr, 42, 1);
44
}
93
}
45
}
94
46
- tsz = MIN(tsz, 39); /* TODO: ARMv8.4-TTST */
95
+ if (env->uncached_cpsr & CPSR_IL) {
47
+
96
+ DP_TBFLAG_ANY(flags, PSTATE__IL, 1);
48
+ if (cpu_isar_feature(aa64_st, env_archcpu(env))) {
49
+ max_tsz = 48 - using64k;
50
+ } else {
51
+ max_tsz = 39;
97
+ }
52
+ }
98
+
53
+
99
return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags);
54
+ tsz = MIN(tsz, max_tsz);
100
}
55
tsz = MAX(tsz, 16); /* TODO: ARMv8.2-LVA */
101
56
102
@@ -XXX,XX +XXX,XX @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
57
/* Present TBI as a composite with TBID. */
103
}
58
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
104
}
59
if (!aarch64 || stride == 9) {
105
60
/* AArch32 or 4KB pages */
106
+ if (env->pstate & PSTATE_IL) {
61
startlevel = 2 - sl0;
107
+ DP_TBFLAG_ANY(flags, PSTATE__IL, 1);
108
+ }
109
+
62
+
110
if (cpu_isar_feature(aa64_mte, env_archcpu(env))) {
63
+ if (cpu_isar_feature(aa64_st, cpu)) {
111
/*
64
+ startlevel &= 3;
112
* Set MTE_ACTIVE if any access may be Checked, and leave clear
65
+ }
113
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
66
} else {
114
index XXXXXXX..XXXXXXX 100644
67
/* 16KB or 64KB pages */
115
--- a/target/arm/translate-a64.c
68
startlevel = 3 - sl0;
116
+++ b/target/arm/translate-a64.c
117
@@ -XXX,XX +XXX,XX @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
118
s->fp_access_checked = false;
119
s->sve_access_checked = false;
120
121
+ if (s->pstate_il) {
122
+ /*
123
+ * Illegal execution state. This has priority over BTI
124
+ * exceptions, but comes after instruction abort exceptions.
125
+ */
126
+ gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
127
+ syn_illegalstate(), default_exception_el(s));
128
+ return;
129
+ }
130
+
131
if (dc_isar_feature(aa64_bti, s)) {
132
if (s->base.num_insns == 1) {
133
/*
134
@@ -XXX,XX +XXX,XX @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
135
#endif
136
dc->fp_excp_el = EX_TBFLAG_ANY(tb_flags, FPEXC_EL);
137
dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM);
138
+ dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL);
139
dc->sve_excp_el = EX_TBFLAG_A64(tb_flags, SVEEXC_EL);
140
dc->sve_len = (EX_TBFLAG_A64(tb_flags, ZCR_LEN) + 1) * 16;
141
dc->pauth_active = EX_TBFLAG_A64(tb_flags, PAUTH_ACTIVE);
142
diff --git a/target/arm/translate.c b/target/arm/translate.c
143
index XXXXXXX..XXXXXXX 100644
144
--- a/target/arm/translate.c
145
+++ b/target/arm/translate.c
146
@@ -XXX,XX +XXX,XX @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
147
return;
148
}
149
150
+ if (s->pstate_il) {
151
+ /*
152
+ * Illegal execution state. This has priority over BTI
153
+ * exceptions, but comes after instruction abort exceptions.
154
+ */
155
+ gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
156
+ syn_illegalstate(), default_exception_el(s));
157
+ return;
158
+ }
159
+
160
if (cond == 0xf) {
161
/* In ARMv3 and v4 the NV condition is UNPREDICTABLE; we
162
* choose to UNDEF. In ARMv5 and above the space is used
163
@@ -XXX,XX +XXX,XX @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
164
#endif
165
dc->fp_excp_el = EX_TBFLAG_ANY(tb_flags, FPEXC_EL);
166
dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM);
167
+ dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL);
168
169
if (arm_feature(env, ARM_FEATURE_M)) {
170
dc->vfp_enabled = 1;
171
@@ -XXX,XX +XXX,XX @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
172
}
173
dc->insn = insn;
174
175
+ if (dc->pstate_il) {
176
+ /*
177
+ * Illegal execution state. This has priority over BTI
178
+ * exceptions, but comes after instruction abort exceptions.
179
+ */
180
+ gen_exception_insn(dc, dc->pc_curr, EXCP_UDEF,
181
+ syn_illegalstate(), default_exception_el(dc));
182
+ return;
183
+ }
184
+
185
if (dc->eci) {
186
/*
187
* For M-profile continuable instructions, ECI/ICI handling
188
--
69
--
189
2.20.1
70
2.20.1
190
71
191
72
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
2
2
3
It is confusing to have different exits from translation
3
Signed-off-by: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
4
for various conditions in separate functions.
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
6
Merge disas_a64_insn into its only caller. Standardize
7
on the "s" name for the DisasContext, as the code from
8
disas_a64_insn had more instances.
9
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
12
Message-id: 20210821195958.41312-3-richard.henderson@linaro.org
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
---
6
---
15
target/arm/translate-a64.c | 224 ++++++++++++++++++-------------------
7
target/arm/cpu64.c | 1 +
16
1 file changed, 109 insertions(+), 115 deletions(-)
8
1 file changed, 1 insertion(+)
17
9
18
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
10
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
19
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
20
--- a/target/arm/translate-a64.c
12
--- a/target/arm/cpu64.c
21
+++ b/target/arm/translate-a64.c
13
+++ b/target/arm/cpu64.c
22
@@ -XXX,XX +XXX,XX @@ static bool btype_destination_ok(uint32_t insn, bool bt, int btype)
14
@@ -XXX,XX +XXX,XX @@ static void aarch64_max_initfn(Object *obj)
23
return false;
15
t = cpu->isar.id_aa64mmfr2;
24
}
16
t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1);
25
17
t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* TTCNP */
26
-/* C3.1 A64 instruction index by encoding */
18
+ t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* TTST */
27
-static void disas_a64_insn(CPUARMState *env, DisasContext *s)
19
cpu->isar.id_aa64mmfr2 = t;
28
-{
20
29
- uint32_t insn;
21
/* Replicate the same data to the 32-bit id registers. */
30
-
31
- s->pc_curr = s->base.pc_next;
32
- insn = arm_ldl_code(env, s->base.pc_next, s->sctlr_b);
33
- s->insn = insn;
34
- s->base.pc_next += 4;
35
-
36
- s->fp_access_checked = false;
37
- s->sve_access_checked = false;
38
-
39
- if (s->pstate_il) {
40
- /*
41
- * Illegal execution state. This has priority over BTI
42
- * exceptions, but comes after instruction abort exceptions.
43
- */
44
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
45
- syn_illegalstate(), default_exception_el(s));
46
- return;
47
- }
48
-
49
- if (dc_isar_feature(aa64_bti, s)) {
50
- if (s->base.num_insns == 1) {
51
- /*
52
- * At the first insn of the TB, compute s->guarded_page.
53
- * We delayed computing this until successfully reading
54
- * the first insn of the TB, above. This (mostly) ensures
55
- * that the softmmu tlb entry has been populated, and the
56
- * page table GP bit is available.
57
- *
58
- * Note that we need to compute this even if btype == 0,
59
- * because this value is used for BR instructions later
60
- * where ENV is not available.
61
- */
62
- s->guarded_page = is_guarded_page(env, s);
63
-
64
- /* First insn can have btype set to non-zero. */
65
- tcg_debug_assert(s->btype >= 0);
66
-
67
- /*
68
- * Note that the Branch Target Exception has fairly high
69
- * priority -- below debugging exceptions but above most
70
- * everything else. This allows us to handle this now
71
- * instead of waiting until the insn is otherwise decoded.
72
- */
73
- if (s->btype != 0
74
- && s->guarded_page
75
- && !btype_destination_ok(insn, s->bt, s->btype)) {
76
- gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
77
- syn_btitrap(s->btype),
78
- default_exception_el(s));
79
- return;
80
- }
81
- } else {
82
- /* Not the first insn: btype must be 0. */
83
- tcg_debug_assert(s->btype == 0);
84
- }
85
- }
86
-
87
- switch (extract32(insn, 25, 4)) {
88
- case 0x0: case 0x1: case 0x3: /* UNALLOCATED */
89
- unallocated_encoding(s);
90
- break;
91
- case 0x2:
92
- if (!dc_isar_feature(aa64_sve, s) || !disas_sve(s, insn)) {
93
- unallocated_encoding(s);
94
- }
95
- break;
96
- case 0x8: case 0x9: /* Data processing - immediate */
97
- disas_data_proc_imm(s, insn);
98
- break;
99
- case 0xa: case 0xb: /* Branch, exception generation and system insns */
100
- disas_b_exc_sys(s, insn);
101
- break;
102
- case 0x4:
103
- case 0x6:
104
- case 0xc:
105
- case 0xe: /* Loads and stores */
106
- disas_ldst(s, insn);
107
- break;
108
- case 0x5:
109
- case 0xd: /* Data processing - register */
110
- disas_data_proc_reg(s, insn);
111
- break;
112
- case 0x7:
113
- case 0xf: /* Data processing - SIMD and floating point */
114
- disas_data_proc_simd_fp(s, insn);
115
- break;
116
- default:
117
- assert(FALSE); /* all 15 cases should be handled above */
118
- break;
119
- }
120
-
121
- /* if we allocated any temporaries, free them here */
122
- free_tmp_a64(s);
123
-
124
- /*
125
- * After execution of most insns, btype is reset to 0.
126
- * Note that we set btype == -1 when the insn sets btype.
127
- */
128
- if (s->btype > 0 && s->base.is_jmp != DISAS_NORETURN) {
129
- reset_btype(s);
130
- }
131
-}
132
-
133
static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
134
CPUState *cpu)
135
{
136
@@ -XXX,XX +XXX,XX @@ static void aarch64_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
137
138
static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
139
{
140
- DisasContext *dc = container_of(dcbase, DisasContext, base);
141
+ DisasContext *s = container_of(dcbase, DisasContext, base);
142
CPUARMState *env = cpu->env_ptr;
143
+ uint32_t insn;
144
145
- if (dc->ss_active && !dc->pstate_ss) {
146
+ if (s->ss_active && !s->pstate_ss) {
147
/* Singlestep state is Active-pending.
148
* If we're in this state at the start of a TB then either
149
* a) we just took an exception to an EL which is being debugged
150
@@ -XXX,XX +XXX,XX @@ static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
151
* "did not step an insn" case, and so the syndrome ISV and EX
152
* bits should be zero.
153
*/
154
- assert(dc->base.num_insns == 1);
155
- gen_swstep_exception(dc, 0, 0);
156
- dc->base.is_jmp = DISAS_NORETURN;
157
- } else {
158
- disas_a64_insn(env, dc);
159
+ assert(s->base.num_insns == 1);
160
+ gen_swstep_exception(s, 0, 0);
161
+ s->base.is_jmp = DISAS_NORETURN;
162
+ return;
163
}
164
165
- translator_loop_temp_check(&dc->base);
166
+ s->pc_curr = s->base.pc_next;
167
+ insn = arm_ldl_code(env, s->base.pc_next, s->sctlr_b);
168
+ s->insn = insn;
169
+ s->base.pc_next += 4;
170
+
171
+ s->fp_access_checked = false;
172
+ s->sve_access_checked = false;
173
+
174
+ if (s->pstate_il) {
175
+ /*
176
+ * Illegal execution state. This has priority over BTI
177
+ * exceptions, but comes after instruction abort exceptions.
178
+ */
179
+ gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
180
+ syn_illegalstate(), default_exception_el(s));
181
+ return;
182
+ }
183
+
184
+ if (dc_isar_feature(aa64_bti, s)) {
185
+ if (s->base.num_insns == 1) {
186
+ /*
187
+ * At the first insn of the TB, compute s->guarded_page.
188
+ * We delayed computing this until successfully reading
189
+ * the first insn of the TB, above. This (mostly) ensures
190
+ * that the softmmu tlb entry has been populated, and the
191
+ * page table GP bit is available.
192
+ *
193
+ * Note that we need to compute this even if btype == 0,
194
+ * because this value is used for BR instructions later
195
+ * where ENV is not available.
196
+ */
197
+ s->guarded_page = is_guarded_page(env, s);
198
+
199
+ /* First insn can have btype set to non-zero. */
200
+ tcg_debug_assert(s->btype >= 0);
201
+
202
+ /*
203
+ * Note that the Branch Target Exception has fairly high
204
+ * priority -- below debugging exceptions but above most
205
+ * everything else. This allows us to handle this now
206
+ * instead of waiting until the insn is otherwise decoded.
207
+ */
208
+ if (s->btype != 0
209
+ && s->guarded_page
210
+ && !btype_destination_ok(insn, s->bt, s->btype)) {
211
+ gen_exception_insn(s, s->pc_curr, EXCP_UDEF,
212
+ syn_btitrap(s->btype),
213
+ default_exception_el(s));
214
+ return;
215
+ }
216
+ } else {
217
+ /* Not the first insn: btype must be 0. */
218
+ tcg_debug_assert(s->btype == 0);
219
+ }
220
+ }
221
+
222
+ switch (extract32(insn, 25, 4)) {
223
+ case 0x0: case 0x1: case 0x3: /* UNALLOCATED */
224
+ unallocated_encoding(s);
225
+ break;
226
+ case 0x2:
227
+ if (!dc_isar_feature(aa64_sve, s) || !disas_sve(s, insn)) {
228
+ unallocated_encoding(s);
229
+ }
230
+ break;
231
+ case 0x8: case 0x9: /* Data processing - immediate */
232
+ disas_data_proc_imm(s, insn);
233
+ break;
234
+ case 0xa: case 0xb: /* Branch, exception generation and system insns */
235
+ disas_b_exc_sys(s, insn);
236
+ break;
237
+ case 0x4:
238
+ case 0x6:
239
+ case 0xc:
240
+ case 0xe: /* Loads and stores */
241
+ disas_ldst(s, insn);
242
+ break;
243
+ case 0x5:
244
+ case 0xd: /* Data processing - register */
245
+ disas_data_proc_reg(s, insn);
246
+ break;
247
+ case 0x7:
248
+ case 0xf: /* Data processing - SIMD and floating point */
249
+ disas_data_proc_simd_fp(s, insn);
250
+ break;
251
+ default:
252
+ assert(FALSE); /* all 15 cases should be handled above */
253
+ break;
254
+ }
255
+
256
+ /* if we allocated any temporaries, free them here */
257
+ free_tmp_a64(s);
258
+
259
+ /*
260
+ * After execution of most insns, btype is reset to 0.
261
+ * Note that we set btype == -1 when the insn sets btype.
262
+ */
263
+ if (s->btype > 0 && s->base.is_jmp != DISAS_NORETURN) {
264
+ reset_btype(s);
265
+ }
266
+
267
+ translator_loop_temp_check(&s->base);
268
}
269
270
static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
271
--
22
--
272
2.20.1
23
2.20.1
273
24
274
25
diff view generated by jsdifflib
1
From: Shashi Mallela <shashi.mallela@linaro.org>
1
From: Leif Lindholm <leif@nuviainc.com>
2
2
3
Included creation of ITS as part of virt platform GIC
3
SBSS -> SSBS
4
initialization. This Emulated ITS model now co-exists with kvm
5
ITS and is enabled in absence of kvm irq kernel support in a
6
platform.
7
4
8
Signed-off-by: Shashi Mallela <shashi.mallela@linaro.org>
5
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Message-id: 20210910143951.92242-9-shashi.mallela@linaro.org
8
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
9
Message-id: 20210108185154.8108-2-leif@nuviainc.com
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
11
---
13
include/hw/arm/virt.h | 2 ++
12
target/arm/cpu.h | 2 +-
14
target/arm/kvm_arm.h | 4 ++--
13
1 file changed, 1 insertion(+), 1 deletion(-)
15
hw/arm/virt.c | 29 +++++++++++++++++++++++++++--
16
3 files changed, 31 insertions(+), 4 deletions(-)
17
14
18
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
15
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
19
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
20
--- a/include/hw/arm/virt.h
17
--- a/target/arm/cpu.h
21
+++ b/include/hw/arm/virt.h
18
+++ b/target/arm/cpu.h
22
@@ -XXX,XX +XXX,XX @@ struct VirtMachineClass {
19
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64PFR0, RAS, 28, 4)
23
MachineClass parent;
20
FIELD(ID_AA64PFR0, SVE, 32, 4)
24
bool disallow_affinity_adjustment;
21
25
bool no_its;
22
FIELD(ID_AA64PFR1, BT, 0, 4)
26
+ bool no_tcg_its;
23
-FIELD(ID_AA64PFR1, SBSS, 4, 4)
27
bool no_pmu;
24
+FIELD(ID_AA64PFR1, SSBS, 4, 4)
28
bool claim_edge_triggered_timers;
25
FIELD(ID_AA64PFR1, MTE, 8, 4)
29
bool smbios_old_sys_ver;
26
FIELD(ID_AA64PFR1, RAS_FRAC, 12, 4)
30
@@ -XXX,XX +XXX,XX @@ struct VirtMachineState {
31
bool highmem;
32
bool highmem_ecam;
33
bool its;
34
+ bool tcg_its;
35
bool virt;
36
bool ras;
37
bool mte;
38
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
39
index XXXXXXX..XXXXXXX 100644
40
--- a/target/arm/kvm_arm.h
41
+++ b/target/arm/kvm_arm.h
42
@@ -XXX,XX +XXX,XX @@ static inline const char *its_class_name(void)
43
/* KVM implementation requires this capability */
44
return kvm_direct_msi_enabled() ? "arm-its-kvm" : NULL;
45
} else {
46
- /* Software emulation is not implemented yet */
47
- return NULL;
48
+ /* Software emulation based model */
49
+ return "arm-gicv3-its";
50
}
51
}
52
53
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
54
index XXXXXXX..XXXXXXX 100644
55
--- a/hw/arm/virt.c
56
+++ b/hw/arm/virt.c
57
@@ -XXX,XX +XXX,XX @@ static void create_its(VirtMachineState *vms)
58
const char *itsclass = its_class_name();
59
DeviceState *dev;
60
61
+ if (!strcmp(itsclass, "arm-gicv3-its")) {
62
+ if (!vms->tcg_its) {
63
+ itsclass = NULL;
64
+ }
65
+ }
66
+
67
if (!itsclass) {
68
/* Do nothing if not supported */
69
return;
70
@@ -XXX,XX +XXX,XX @@ static void create_v2m(VirtMachineState *vms)
71
vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
72
}
73
74
-static void create_gic(VirtMachineState *vms)
75
+static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
76
{
77
MachineState *ms = MACHINE(vms);
78
/* We create a standalone GIC */
79
@@ -XXX,XX +XXX,XX @@ static void create_gic(VirtMachineState *vms)
80
nb_redist_regions);
81
qdev_prop_set_uint32(vms->gic, "redist-region-count[0]", redist0_count);
82
83
+ if (!kvm_irqchip_in_kernel()) {
84
+ if (vms->tcg_its) {
85
+ object_property_set_link(OBJECT(vms->gic), "sysmem",
86
+ OBJECT(mem), &error_fatal);
87
+ qdev_prop_set_bit(vms->gic, "has-lpi", true);
88
+ }
89
+ }
90
+
91
if (nb_redist_regions == 2) {
92
uint32_t redist1_capacity =
93
vms->memmap[VIRT_HIGH_GIC_REDIST2].size / GICV3_REDIST_SIZE;
94
@@ -XXX,XX +XXX,XX @@ static void machvirt_init(MachineState *machine)
95
96
virt_flash_fdt(vms, sysmem, secure_sysmem ?: sysmem);
97
98
- create_gic(vms);
99
+ create_gic(vms, sysmem);
100
101
virt_cpu_post_init(vms, sysmem);
102
103
@@ -XXX,XX +XXX,XX @@ static void virt_instance_init(Object *obj)
104
} else {
105
/* Default allows ITS instantiation */
106
vms->its = true;
107
+
108
+ if (vmc->no_tcg_its) {
109
+ vms->tcg_its = false;
110
+ } else {
111
+ vms->tcg_its = true;
112
+ }
113
}
114
115
/* Default disallows iommu instantiation */
116
@@ -XXX,XX +XXX,XX @@ DEFINE_VIRT_MACHINE_AS_LATEST(6, 2)
117
118
static void virt_machine_6_1_options(MachineClass *mc)
119
{
120
+ VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
121
+
122
virt_machine_6_2_options(mc);
123
compat_props_add(mc->compat_props, hw_compat_6_1, hw_compat_6_1_len);
124
+
125
+ /* qemu ITS was introduced with 6.2 */
126
+ vmc->no_tcg_its = true;
127
}
128
DEFINE_VIRT_MACHINE(6, 1)
129
27
130
--
28
--
131
2.20.1
29
2.20.1
132
30
133
31
diff view generated by jsdifflib
1
From: Shashi Mallela <shashi.mallela@linaro.org>
1
From: Leif Lindholm <leif@nuviainc.com>
2
2
3
Updated expected IORT files applicable with latest GICv3
3
The AArch64 view of CLIDR_EL1 extends the ICB field to include also bit
4
ITS changes.
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.
5
6
6
Full diff of new file disassembly:
7
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
7
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
/*
9
* Intel ACPI Component Architecture
10
* AML/ASL+ Disassembler version 20180629 (64-bit version)
11
* Copyright (c) 2000 - 2018 Intel Corporation
12
*
13
* Disassembly of tests/data/acpi/virt/IORT.pxb, Tue Jun 29 17:35:38 2021
14
*
15
* ACPI Data Table [IORT]
16
*
17
* Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue
18
*/
19
20
[000h 0000 4] Signature : "IORT" [IO Remapping Table]
21
[004h 0004 4] Table Length : 0000007C
22
[008h 0008 1] Revision : 00
23
[009h 0009 1] Checksum : 07
24
[00Ah 0010 6] Oem ID : "BOCHS "
25
[010h 0016 8] Oem Table ID : "BXPC "
26
[018h 0024 4] Oem Revision : 00000001
27
[01Ch 0028 4] Asl Compiler ID : "BXPC"
28
[020h 0032 4] Asl Compiler Revision : 00000001
29
30
[024h 0036 4] Node Count : 00000002
31
[028h 0040 4] Node Offset : 00000030
32
[02Ch 0044 4] Reserved : 00000000
33
34
[030h 0048 1] Type : 00
35
[031h 0049 2] Length : 0018
36
[033h 0051 1] Revision : 00
37
[034h 0052 4] Reserved : 00000000
38
[038h 0056 4] Mapping Count : 00000000
39
[03Ch 0060 4] Mapping Offset : 00000000
40
41
[040h 0064 4] ItsCount : 00000001
42
[044h 0068 4] Identifiers : 00000000
43
44
[048h 0072 1] Type : 02
45
[049h 0073 2] Length : 0034
46
[04Bh 0075 1] Revision : 00
47
[04Ch 0076 4] Reserved : 00000000
48
[050h 0080 4] Mapping Count : 00000001
49
[054h 0084 4] Mapping Offset : 00000020
50
51
[058h 0088 8] Memory Properties : [IORT Memory Access Properties]
52
[058h 0088 4] Cache Coherency : 00000001
53
[05Ch 0092 1] Hints (decoded below) : 00
54
Transient : 0
55
Write Allocate : 0
56
Read Allocate : 0
57
Override : 0
58
[05Dh 0093 2] Reserved : 0000
59
[05Fh 0095 1] Memory Flags (decoded below) : 03
60
Coherency : 1
61
Device Attribute : 1
62
[060h 0096 4] ATS Attribute : 00000000
63
[064h 0100 4] PCI Segment Number : 00000000
64
[068h 0104 1] Memory Size Limit : 00
65
[069h 0105 3] Reserved : 000000
66
67
[068h 0104 4] Input base : 00000000
68
[06Ch 0108 4] ID Count : 0000FFFF
69
[070h 0112 4] Output Base : 00000000
70
[074h 0116 4] Output Reference : 00000030
71
[078h 0120 4] Flags (decoded below) : 00000000
72
Single Mapping : 0
73
74
Raw Table Data: Length 124 (0x7C)
75
76
0000: 49 4F 52 54 7C 00 00 00 00 07 42 4F 43 48 53 20 // IORT|.....BOCHS
77
0010: 42 58 50 43 20 20 20 20 01 00 00 00 42 58 50 43 // BXPC ....BXPC
78
0020: 01 00 00 00 02 00 00 00 30 00 00 00 00 00 00 00 // ........0.......
79
0030: 00 18 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // ................
80
0040: 01 00 00 00 00 00 00 00 02 34 00 00 00 00 00 00 // .........4......
81
0050: 01 00 00 00 20 00 00 00 01 00 00 00 00 00 00 03 // .... ...........
82
0060: 00 00 00 00 00 00 00 00 00 00 00 00 FF FF 00 00 // ................
83
0070: 00 00 00 00 30 00 00 00 00 00 00 00 // ....0.......
84
85
Signed-off-by: Shashi Mallela <shashi.mallela@linaro.org>
86
Acked-by: Igor Mammedov <imammedo@redhat.com>
87
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
88
Message-id: 20210910143951.92242-10-shashi.mallela@linaro.org
10
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
11
Message-id: 20210108185154.8108-3-leif@nuviainc.com
89
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
90
---
13
---
91
tests/qtest/bios-tables-test-allowed-diff.h | 4 ----
14
target/arm/cpu.h | 2 +-
92
tests/data/acpi/virt/IORT | Bin 0 -> 124 bytes
15
1 file changed, 1 insertion(+), 1 deletion(-)
93
tests/data/acpi/virt/IORT.memhp | Bin 0 -> 124 bytes
94
tests/data/acpi/virt/IORT.numamem | Bin 0 -> 124 bytes
95
tests/data/acpi/virt/IORT.pxb | Bin 0 -> 124 bytes
96
5 files changed, 4 deletions(-)
97
16
98
diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h
17
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
99
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
100
--- a/tests/qtest/bios-tables-test-allowed-diff.h
19
--- a/target/arm/cpu.h
101
+++ b/tests/qtest/bios-tables-test-allowed-diff.h
20
+++ b/target/arm/cpu.h
102
@@ -1,5 +1 @@
21
@@ -XXX,XX +XXX,XX @@ struct ARMCPU {
103
/* List of comma-separated changed AML files to ignore */
22
uint32_t id_afr0;
104
-"tests/data/acpi/virt/IORT",
23
uint64_t id_aa64afr0;
105
-"tests/data/acpi/virt/IORT.memhp",
24
uint64_t id_aa64afr1;
106
-"tests/data/acpi/virt/IORT.numamem",
25
- uint32_t clidr;
107
-"tests/data/acpi/virt/IORT.pxb",
26
+ uint64_t clidr;
108
diff --git a/tests/data/acpi/virt/IORT b/tests/data/acpi/virt/IORT
27
uint64_t mp_affinity; /* MP ID without feature bits */
109
index XXXXXXX..XXXXXXX 100644
28
/* The elements of this array are the CCSIDR values for each cache,
110
GIT binary patch
29
* in the order L1DCache, L1ICache, L2DCache, L2ICache, etc.
111
literal 124
112
zcmebD4+^Pa00MR=e`k+i1*eDrX9XZ&1PX!JAesq?4S*O7Bw!2(4Uz`|CKCt^;wu0#
113
QRGb+i3L*dhhtM#y0PN=p0RR91
114
115
literal 0
116
HcmV?d00001
117
118
diff --git a/tests/data/acpi/virt/IORT.memhp b/tests/data/acpi/virt/IORT.memhp
119
index XXXXXXX..XXXXXXX 100644
120
GIT binary patch
121
literal 124
122
zcmebD4+^Pa00MR=e`k+i1*eDrX9XZ&1PX!JAesq?4S*O7Bw!2(4Uz`|CKCt^;wu0#
123
QRGb+i3L*dhhtM#y0PN=p0RR91
124
125
literal 0
126
HcmV?d00001
127
128
diff --git a/tests/data/acpi/virt/IORT.numamem b/tests/data/acpi/virt/IORT.numamem
129
index XXXXXXX..XXXXXXX 100644
130
GIT binary patch
131
literal 124
132
zcmebD4+^Pa00MR=e`k+i1*eDrX9XZ&1PX!JAesq?4S*O7Bw!2(4Uz`|CKCt^;wu0#
133
QRGb+i3L*dhhtM#y0PN=p0RR91
134
135
literal 0
136
HcmV?d00001
137
138
diff --git a/tests/data/acpi/virt/IORT.pxb b/tests/data/acpi/virt/IORT.pxb
139
index XXXXXXX..XXXXXXX 100644
140
GIT binary patch
141
literal 124
142
zcmebD4+^Pa00MR=e`k+i1*eDrX9XZ&1PX!JAesq?4S*O7Bw!2(4Uz`|CKCt^;wu0#
143
QRGb+i3L*dhhtM#y0PN=p0RR91
144
145
literal 0
146
HcmV?d00001
147
148
--
30
--
149
2.20.1
31
2.20.1
150
32
151
33
diff view generated by jsdifflib
1
From: Shashi Mallela <shashi.mallela@linaro.org>
1
From: Leif Lindholm <leif@nuviainc.com>
2
2
3
Added expected IORT files applicable with latest GICv3
3
When FEAT_MTE is implemented, the AArch64 view of CTR_EL0 adds the
4
ITS changes.Temporarily differences in these files are
4
TminLine field in bits [37:32].
5
okay.
5
Extend the ctr field to be able to hold this context.
6
6
7
Signed-off-by: Shashi Mallela <shashi.mallela@linaro.org>
7
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
8
Acked-by: Igor Mammedov <imammedo@redhat.com>
8
Reviewed-by: Hao Wu <wuhaotsh@google.com>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 20210910143951.92242-8-shashi.mallela@linaro.org
10
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
11
Message-id: 20210108185154.8108-4-leif@nuviainc.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/bios-tables-test-allowed-diff.h | 4 ++++
14
target/arm/cpu.h | 2 +-
14
tests/data/acpi/virt/IORT | 0
15
1 file changed, 1 insertion(+), 1 deletion(-)
15
tests/data/acpi/virt/IORT.memhp | 0
16
tests/data/acpi/virt/IORT.numamem | 0
17
tests/data/acpi/virt/IORT.pxb | 0
18
5 files changed, 4 insertions(+)
19
create mode 100644 tests/data/acpi/virt/IORT
20
create mode 100644 tests/data/acpi/virt/IORT.memhp
21
create mode 100644 tests/data/acpi/virt/IORT.numamem
22
create mode 100644 tests/data/acpi/virt/IORT.pxb
23
16
24
diff --git a/tests/qtest/bios-tables-test-allowed-diff.h b/tests/qtest/bios-tables-test-allowed-diff.h
17
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
25
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
26
--- a/tests/qtest/bios-tables-test-allowed-diff.h
19
--- a/target/arm/cpu.h
27
+++ b/tests/qtest/bios-tables-test-allowed-diff.h
20
+++ b/target/arm/cpu.h
28
@@ -1 +1,5 @@
21
@@ -XXX,XX +XXX,XX @@ struct ARMCPU {
29
/* List of comma-separated changed AML files to ignore */
22
uint64_t midr;
30
+"tests/data/acpi/virt/IORT",
23
uint32_t revidr;
31
+"tests/data/acpi/virt/IORT.memhp",
24
uint32_t reset_fpsid;
32
+"tests/data/acpi/virt/IORT.numamem",
25
- uint32_t ctr;
33
+"tests/data/acpi/virt/IORT.pxb",
26
+ uint64_t ctr;
34
diff --git a/tests/data/acpi/virt/IORT b/tests/data/acpi/virt/IORT
27
uint32_t reset_sctlr;
35
new file mode 100644
28
uint64_t pmceid0;
36
index XXXXXXX..XXXXXXX
29
uint64_t pmceid1;
37
diff --git a/tests/data/acpi/virt/IORT.memhp b/tests/data/acpi/virt/IORT.memhp
38
new file mode 100644
39
index XXXXXXX..XXXXXXX
40
diff --git a/tests/data/acpi/virt/IORT.numamem b/tests/data/acpi/virt/IORT.numamem
41
new file mode 100644
42
index XXXXXXX..XXXXXXX
43
diff --git a/tests/data/acpi/virt/IORT.pxb b/tests/data/acpi/virt/IORT.pxb
44
new file mode 100644
45
index XXXXXXX..XXXXXXX
46
--
30
--
47
2.20.1
31
2.20.1
48
32
49
33
diff view generated by jsdifflib
1
From: Shashi Mallela <shashi.mallela@linaro.org>
1
From: Leif Lindholm <leif@nuviainc.com>
2
2
3
Implemented lpi processing at redistributor to get lpi config info
3
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
4
from lpi configuration table,determine priority,set pending state in
4
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
5
lpi pending table and forward the lpi to cpuif.Added logic to invoke
5
Message-id: 20210108185154.8108-5-leif@nuviainc.com
6
redistributor lpi processing with translated LPI which set/clear LPI
7
from ITS device as part of ITS INT,CLEAR,DISCARD command and
8
GITS_TRANSLATER processing.
9
10
Signed-off-by: Shashi Mallela <shashi.mallela@linaro.org>
11
Tested-by: Neil Armstrong <narmstrong@baylibre.com>
12
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
13
Message-id: 20210910143951.92242-7-shashi.mallela@linaro.org
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
---
7
---
16
hw/intc/gicv3_internal.h | 9 ++
8
target/arm/cpu.h | 31 +++++++++++++++++++++++++++++++
17
include/hw/intc/arm_gicv3_common.h | 7 ++
9
1 file changed, 31 insertions(+)
18
hw/intc/arm_gicv3.c | 14 +++
19
hw/intc/arm_gicv3_common.c | 1 +
20
hw/intc/arm_gicv3_cpuif.c | 7 +-
21
hw/intc/arm_gicv3_its.c | 23 +++++
22
hw/intc/arm_gicv3_redist.c | 141 +++++++++++++++++++++++++++++
23
7 files changed, 200 insertions(+), 2 deletions(-)
24
10
25
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
11
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
26
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
27
--- a/hw/intc/gicv3_internal.h
13
--- a/target/arm/cpu.h
28
+++ b/hw/intc/gicv3_internal.h
14
+++ b/target/arm/cpu.h
29
@@ -XXX,XX +XXX,XX @@ FIELD(GICR_PENDBASER, PHYADDR, 16, 36)
15
@@ -XXX,XX +XXX,XX @@ FIELD(V7M_FPCCR, ASPEN, 31, 1)
30
FIELD(GICR_PENDBASER, OUTERCACHE, 56, 3)
16
/*
31
FIELD(GICR_PENDBASER, PTZ, 62, 1)
17
* System register ID fields.
32
18
*/
33
+#define GICR_PROPBASER_IDBITS_THRESHOLD 0xd
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)
34
+
30
+
35
#define ICC_CTLR_EL1_CBPR (1U << 0)
31
+/* When FEAT_CCIDX is implemented */
36
#define ICC_CTLR_EL1_EOIMODE (1U << 1)
32
+FIELD(CCSIDR_EL1, CCIDX_LINESIZE, 0, 3)
37
#define ICC_CTLR_EL1_PMHE (1U << 6)
33
+FIELD(CCSIDR_EL1, CCIDX_ASSOCIATIVITY, 3, 21)
38
@@ -XXX,XX +XXX,XX @@ FIELD(GITS_TYPER, CIL, 36, 1)
34
+FIELD(CCSIDR_EL1, CCIDX_NUMSETS, 32, 24)
39
40
#define L1TABLE_ENTRY_SIZE 8
41
42
+#define LPI_CTE_ENABLED TABLE_ENTRY_VALID_MASK
43
+#define LPI_PRIORITY_MASK 0xfc
44
+
35
+
45
#define GITS_CMDQ_ENTRY_SIZE 32
36
+/* When FEAT_CCIDX is not implemented */
46
#define NUM_BYTES_IN_DW 8
37
+FIELD(CCSIDR_EL1, LINESIZE, 0, 3)
47
38
+FIELD(CCSIDR_EL1, ASSOCIATIVITY, 3, 10)
48
@@ -XXX,XX +XXX,XX @@ FIELD(MAPC, RDBASE, 16, 32)
39
+FIELD(CCSIDR_EL1, NUMSETS, 13, 15)
49
* Valid = 1 bit,RDBase = 36 bits(considering max RDBASE)
50
*/
51
#define GITS_CTE_SIZE (0x8ULL)
52
+#define GITS_CTE_RDBASE_PROCNUM_MASK MAKE_64BIT_MASK(1, RDBASE_PROCNUM_LENGTH)
53
54
/* Special interrupt IDs */
55
#define INTID_SECURE 1020
56
@@ -XXX,XX +XXX,XX @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
57
unsigned size, MemTxAttrs attrs);
58
void gicv3_dist_set_irq(GICv3State *s, int irq, int level);
59
void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level);
60
+void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level);
61
+void gicv3_redist_lpi_pending(GICv3CPUState *cs, int irq, int level);
62
+void gicv3_redist_update_lpi(GICv3CPUState *cs);
63
void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns);
64
void gicv3_init_cpuif(GICv3State *s);
65
66
diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
67
index XXXXXXX..XXXXXXX 100644
68
--- a/include/hw/intc/arm_gicv3_common.h
69
+++ b/include/hw/intc/arm_gicv3_common.h
70
@@ -XXX,XX +XXX,XX @@ struct GICv3CPUState {
71
* real state above; it doesn't need to be migrated.
72
*/
73
PendingIrq hppi;
74
+
40
+
75
+ /*
41
+FIELD(CTR_EL0, IMINLINE, 0, 4)
76
+ * Cached information recalculated from LPI tables
42
+FIELD(CTR_EL0, L1IP, 14, 2)
77
+ * in guest memory
43
+FIELD(CTR_EL0, DMINLINE, 16, 4)
78
+ */
44
+FIELD(CTR_EL0, ERG, 20, 4)
79
+ PendingIrq hpplpi;
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)
80
+
49
+
81
/* This is temporary working state, to avoid a malloc in gicv3_update() */
50
FIELD(MIDR_EL1, REVISION, 0, 4)
82
bool seenbetter;
51
FIELD(MIDR_EL1, PARTNUM, 4, 12)
83
};
52
FIELD(MIDR_EL1, ARCHITECTURE, 16, 4)
84
diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
85
index XXXXXXX..XXXXXXX 100644
86
--- a/hw/intc/arm_gicv3.c
87
+++ b/hw/intc/arm_gicv3.c
88
@@ -XXX,XX +XXX,XX @@ static void gicv3_redist_update_noirqset(GICv3CPUState *cs)
89
cs->hppi.grp = gicv3_irq_group(cs->gic, cs, cs->hppi.irq);
90
}
91
92
+ if ((cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) && cs->gic->lpi_enable &&
93
+ (cs->hpplpi.prio != 0xff)) {
94
+ if (irqbetter(cs, cs->hpplpi.irq, cs->hpplpi.prio)) {
95
+ cs->hppi.irq = cs->hpplpi.irq;
96
+ cs->hppi.prio = cs->hpplpi.prio;
97
+ cs->hppi.grp = cs->hpplpi.grp;
98
+ seenbetter = true;
99
+ }
100
+ }
101
+
102
/* If the best interrupt we just found would preempt whatever
103
* was the previous best interrupt before this update, then
104
* we know it's definitely the best one now.
105
@@ -XXX,XX +XXX,XX @@ static void gicv3_set_irq(void *opaque, int irq, int level)
106
107
static void arm_gicv3_post_load(GICv3State *s)
108
{
109
+ int i;
110
/* Recalculate our cached idea of the current highest priority
111
* pending interrupt, but don't set IRQ or FIQ lines.
112
*/
113
+ for (i = 0; i < s->num_cpu; i++) {
114
+ gicv3_redist_update_lpi(&s->cpu[i]);
115
+ }
116
gicv3_full_update_noirqset(s);
117
/* Repopulate the cache of GICv3CPUState pointers for target CPUs */
118
gicv3_cache_all_target_cpustates(s);
119
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
120
index XXXXXXX..XXXXXXX 100644
121
--- a/hw/intc/arm_gicv3_common.c
122
+++ b/hw/intc/arm_gicv3_common.c
123
@@ -XXX,XX +XXX,XX @@ static void arm_gicv3_common_reset(DeviceState *dev)
124
memset(cs->gicr_ipriorityr, 0, sizeof(cs->gicr_ipriorityr));
125
126
cs->hppi.prio = 0xff;
127
+ cs->hpplpi.prio = 0xff;
128
129
/* State in the CPU interface must *not* be reset here, because it
130
* is part of the CPU's reset domain, not the GIC device's.
131
diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c
132
index XXXXXXX..XXXXXXX 100644
133
--- a/hw/intc/arm_gicv3_cpuif.c
134
+++ b/hw/intc/arm_gicv3_cpuif.c
135
@@ -XXX,XX +XXX,XX @@ static void icc_activate_irq(GICv3CPUState *cs, int irq)
136
cs->gicr_iactiver0 = deposit32(cs->gicr_iactiver0, irq, 1, 1);
137
cs->gicr_ipendr0 = deposit32(cs->gicr_ipendr0, irq, 1, 0);
138
gicv3_redist_update(cs);
139
- } else {
140
+ } else if (irq < GICV3_LPI_INTID_START) {
141
gicv3_gicd_active_set(cs->gic, irq);
142
gicv3_gicd_pending_clear(cs->gic, irq);
143
gicv3_update(cs->gic, irq, 1);
144
+ } else {
145
+ gicv3_redist_lpi_pending(cs, irq, 0);
146
}
147
}
148
149
@@ -XXX,XX +XXX,XX @@ static void icc_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri,
150
trace_gicv3_icc_eoir_write(is_eoir0 ? 0 : 1,
151
gicv3_redist_affid(cs), value);
152
153
- if (irq >= cs->gic->num_irq) {
154
+ if ((irq >= cs->gic->num_irq) &&
155
+ !(cs->gic->lpi_enable && (irq >= GICV3_LPI_INTID_START))) {
156
/* This handles two cases:
157
* 1. If software writes the ID of a spurious interrupt [ie 1020-1023]
158
* to the GICC_EOIR, the GIC ignores that write.
159
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
160
index XXXXXXX..XXXXXXX 100644
161
--- a/hw/intc/arm_gicv3_its.c
162
+++ b/hw/intc/arm_gicv3_its.c
163
@@ -XXX,XX +XXX,XX @@ static bool process_its_cmd(GICv3ITSState *s, uint64_t value, uint32_t offset,
164
uint64_t cte = 0;
165
bool cte_valid = false;
166
bool result = false;
167
+ uint64_t rdbase;
168
169
if (cmd == NONE) {
170
devid = offset;
171
@@ -XXX,XX +XXX,XX @@ static bool process_its_cmd(GICv3ITSState *s, uint64_t value, uint32_t offset,
172
* Current implementation only supports rdbase == procnum
173
* Hence rdbase physical address is ignored
174
*/
175
+ rdbase = (cte & GITS_CTE_RDBASE_PROCNUM_MASK) >> 1U;
176
+
177
+ if (rdbase > s->gicv3->num_cpu) {
178
+ return result;
179
+ }
180
+
181
+ if ((cmd == CLEAR) || (cmd == DISCARD)) {
182
+ gicv3_redist_process_lpi(&s->gicv3->cpu[rdbase], pIntid, 0);
183
+ } else {
184
+ gicv3_redist_process_lpi(&s->gicv3->cpu[rdbase], pIntid, 1);
185
+ }
186
+
187
if (cmd == DISCARD) {
188
IteEntry ite = {};
189
/* remove mapping from interrupt translation table */
190
@@ -XXX,XX +XXX,XX @@ static void process_cmdq(GICv3ITSState *s)
191
MemTxResult res = MEMTX_OK;
192
bool result = true;
193
uint8_t cmd;
194
+ int i;
195
196
if (!(s->ctlr & ITS_CTLR_ENABLED)) {
197
return;
198
@@ -XXX,XX +XXX,XX @@ static void process_cmdq(GICv3ITSState *s)
199
break;
200
case GITS_CMD_INV:
201
case GITS_CMD_INVALL:
202
+ /*
203
+ * Current implementation doesn't cache any ITS tables,
204
+ * but the calculated lpi priority information. We only
205
+ * need to trigger lpi priority re-calculation to be in
206
+ * sync with LPI config table or pending table changes.
207
+ */
208
+ for (i = 0; i < s->gicv3->num_cpu; i++) {
209
+ gicv3_redist_update_lpi(&s->gicv3->cpu[i]);
210
+ }
211
break;
212
default:
213
break;
214
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
215
index XXXXXXX..XXXXXXX 100644
216
--- a/hw/intc/arm_gicv3_redist.c
217
+++ b/hw/intc/arm_gicv3_redist.c
218
@@ -XXX,XX +XXX,XX @@ static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset,
219
if (cs->gicr_typer & GICR_TYPER_PLPIS) {
220
if (value & GICR_CTLR_ENABLE_LPIS) {
221
cs->gicr_ctlr |= GICR_CTLR_ENABLE_LPIS;
222
+ /* Check for any pending interr in pending table */
223
+ gicv3_redist_update_lpi(cs);
224
+ gicv3_redist_update(cs);
225
} else {
226
cs->gicr_ctlr &= ~GICR_CTLR_ENABLE_LPIS;
227
}
228
@@ -XXX,XX +XXX,XX @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
229
return r;
230
}
231
232
+static void gicv3_redist_check_lpi_priority(GICv3CPUState *cs, int irq)
233
+{
234
+ AddressSpace *as = &cs->gic->dma_as;
235
+ uint64_t lpict_baddr;
236
+ uint8_t lpite;
237
+ uint8_t prio;
238
+
239
+ lpict_baddr = cs->gicr_propbaser & R_GICR_PROPBASER_PHYADDR_MASK;
240
+
241
+ address_space_read(as, lpict_baddr + ((irq - GICV3_LPI_INTID_START) *
242
+ sizeof(lpite)), MEMTXATTRS_UNSPECIFIED, &lpite,
243
+ sizeof(lpite));
244
+
245
+ if (!(lpite & LPI_CTE_ENABLED)) {
246
+ return;
247
+ }
248
+
249
+ if (cs->gic->gicd_ctlr & GICD_CTLR_DS) {
250
+ prio = lpite & LPI_PRIORITY_MASK;
251
+ } else {
252
+ prio = ((lpite & LPI_PRIORITY_MASK) >> 1) | 0x80;
253
+ }
254
+
255
+ if ((prio < cs->hpplpi.prio) ||
256
+ ((prio == cs->hpplpi.prio) && (irq <= cs->hpplpi.irq))) {
257
+ cs->hpplpi.irq = irq;
258
+ cs->hpplpi.prio = prio;
259
+ /* LPIs are always non-secure Grp1 interrupts */
260
+ cs->hpplpi.grp = GICV3_G1NS;
261
+ }
262
+}
263
+
264
+void gicv3_redist_update_lpi(GICv3CPUState *cs)
265
+{
266
+ /*
267
+ * This function scans the LPI pending table and for each pending
268
+ * LPI, reads the corresponding entry from LPI configuration table
269
+ * to extract the priority info and determine if the current LPI
270
+ * priority is lower than the last computed high priority lpi interrupt.
271
+ * If yes, replace current LPI as the new high priority lpi interrupt.
272
+ */
273
+ AddressSpace *as = &cs->gic->dma_as;
274
+ uint64_t lpipt_baddr;
275
+ uint32_t pendt_size = 0;
276
+ uint8_t pend;
277
+ int i, bit;
278
+ uint64_t idbits;
279
+
280
+ idbits = MIN(FIELD_EX64(cs->gicr_propbaser, GICR_PROPBASER, IDBITS),
281
+ GICD_TYPER_IDBITS);
282
+
283
+ if (!(cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) || !cs->gicr_propbaser ||
284
+ !cs->gicr_pendbaser) {
285
+ return;
286
+ }
287
+
288
+ cs->hpplpi.prio = 0xff;
289
+
290
+ lpipt_baddr = cs->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK;
291
+
292
+ /* Determine the highest priority pending interrupt among LPIs */
293
+ pendt_size = (1ULL << (idbits + 1));
294
+
295
+ for (i = GICV3_LPI_INTID_START / 8; i < pendt_size / 8; i++) {
296
+ address_space_read(as, lpipt_baddr + i, MEMTXATTRS_UNSPECIFIED, &pend,
297
+ sizeof(pend));
298
+
299
+ while (pend) {
300
+ bit = ctz32(pend);
301
+ gicv3_redist_check_lpi_priority(cs, i * 8 + bit);
302
+ pend &= ~(1 << bit);
303
+ }
304
+ }
305
+}
306
+
307
+void gicv3_redist_lpi_pending(GICv3CPUState *cs, int irq, int level)
308
+{
309
+ /*
310
+ * This function updates the pending bit in lpi pending table for
311
+ * the irq being activated or deactivated.
312
+ */
313
+ AddressSpace *as = &cs->gic->dma_as;
314
+ uint64_t lpipt_baddr;
315
+ bool ispend = false;
316
+ uint8_t pend;
317
+
318
+ /*
319
+ * get the bit value corresponding to this irq in the
320
+ * lpi pending table
321
+ */
322
+ lpipt_baddr = cs->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK;
323
+
324
+ address_space_read(as, lpipt_baddr + ((irq / 8) * sizeof(pend)),
325
+ MEMTXATTRS_UNSPECIFIED, &pend, sizeof(pend));
326
+
327
+ ispend = extract32(pend, irq % 8, 1);
328
+
329
+ /* no change in the value of pending bit, return */
330
+ if (ispend == level) {
331
+ return;
332
+ }
333
+ pend = deposit32(pend, irq % 8, 1, level ? 1 : 0);
334
+
335
+ address_space_write(as, lpipt_baddr + ((irq / 8) * sizeof(pend)),
336
+ MEMTXATTRS_UNSPECIFIED, &pend, sizeof(pend));
337
+
338
+ /*
339
+ * check if this LPI is better than the current hpplpi, if yes
340
+ * just set hpplpi.prio and .irq without doing a full rescan
341
+ */
342
+ if (level) {
343
+ gicv3_redist_check_lpi_priority(cs, irq);
344
+ } else {
345
+ if (irq == cs->hpplpi.irq) {
346
+ gicv3_redist_update_lpi(cs);
347
+ }
348
+ }
349
+}
350
+
351
+void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level)
352
+{
353
+ uint64_t idbits;
354
+
355
+ idbits = MIN(FIELD_EX64(cs->gicr_propbaser, GICR_PROPBASER, IDBITS),
356
+ GICD_TYPER_IDBITS);
357
+
358
+ if (!(cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) || !cs->gicr_propbaser ||
359
+ !cs->gicr_pendbaser || (irq > (1ULL << (idbits + 1)) - 1) ||
360
+ irq < GICV3_LPI_INTID_START) {
361
+ return;
362
+ }
363
+
364
+ /* set/clear the pending bit for this irq */
365
+ gicv3_redist_lpi_pending(cs, irq, level);
366
+
367
+ gicv3_redist_update(cs);
368
+}
369
+
370
void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level)
371
{
372
/* Update redistributor state for a change in an external PPI input line */
373
--
53
--
374
2.20.1
54
2.20.1
375
55
376
56
diff view generated by jsdifflib
1
From: Shashi Mallela <shashi.mallela@linaro.org>
1
From: Leif Lindholm <leif@nuviainc.com>
2
2
3
Added properties to enable ITS feature and define qemu system
3
Add entries present in ARM DDI 0487F.c (August 2020).
4
address space memory in gicv3 common,setup distributor and
5
redistributor registers to indicate LPI support.
6
4
7
Signed-off-by: Shashi Mallela <shashi.mallela@linaro.org>
5
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Tested-by: Neil Armstrong <narmstrong@baylibre.com>
7
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
10
Message-id: 20210910143951.92242-6-shashi.mallela@linaro.org
8
Message-id: 20210108185154.8108-6-leif@nuviainc.com
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
10
---
13
hw/intc/gicv3_internal.h | 2 ++
11
target/arm/cpu.h | 15 +++++++++++++++
14
include/hw/intc/arm_gicv3_common.h | 1 +
12
1 file changed, 15 insertions(+)
15
hw/intc/arm_gicv3_common.c | 12 ++++++++++++
16
hw/intc/arm_gicv3_dist.c | 5 ++++-
17
hw/intc/arm_gicv3_redist.c | 12 +++++++++---
18
5 files changed, 28 insertions(+), 4 deletions(-)
19
13
20
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
14
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
21
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
22
--- a/hw/intc/gicv3_internal.h
16
--- a/target/arm/cpu.h
23
+++ b/hw/intc/gicv3_internal.h
17
+++ b/target/arm/cpu.h
24
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64ISAR1, GPI, 28, 4)
25
#define GICD_CTLR_E1NWF (1U << 7)
19
FIELD(ID_AA64ISAR1, FRINTTS, 32, 4)
26
#define GICD_CTLR_RWP (1U << 31)
20
FIELD(ID_AA64ISAR1, SB, 36, 4)
27
21
FIELD(ID_AA64ISAR1, SPECRES, 40, 4)
28
+#define GICD_TYPER_LPIS_SHIFT 17
22
+FIELD(ID_AA64ISAR1, BF16, 44, 4)
29
+
23
+FIELD(ID_AA64ISAR1, DGH, 48, 4)
30
/* 16 bits EventId */
24
+FIELD(ID_AA64ISAR1, I8MM, 52, 4)
31
#define GICD_TYPER_IDBITS 0xf
25
32
26
FIELD(ID_AA64PFR0, EL0, 0, 4)
33
diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
27
FIELD(ID_AA64PFR0, EL1, 4, 4)
34
index XXXXXXX..XXXXXXX 100644
28
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64PFR0, ADVSIMD, 20, 4)
35
--- a/include/hw/intc/arm_gicv3_common.h
29
FIELD(ID_AA64PFR0, GIC, 24, 4)
36
+++ b/include/hw/intc/arm_gicv3_common.h
30
FIELD(ID_AA64PFR0, RAS, 28, 4)
37
@@ -XXX,XX +XXX,XX @@ struct GICv3State {
31
FIELD(ID_AA64PFR0, SVE, 32, 4)
38
uint32_t num_cpu;
32
+FIELD(ID_AA64PFR0, SEL2, 36, 4)
39
uint32_t num_irq;
33
+FIELD(ID_AA64PFR0, MPAM, 40, 4)
40
uint32_t revision;
34
+FIELD(ID_AA64PFR0, AMU, 44, 4)
41
+ bool lpi_enable;
35
+FIELD(ID_AA64PFR0, DIT, 48, 4)
42
bool security_extn;
36
+FIELD(ID_AA64PFR0, CSV2, 56, 4)
43
bool irq_reset_nonsecure;
37
+FIELD(ID_AA64PFR0, CSV3, 60, 4)
44
bool gicd_no_migration_shift_bug;
38
45
diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
39
FIELD(ID_AA64PFR1, BT, 0, 4)
46
index XXXXXXX..XXXXXXX 100644
40
FIELD(ID_AA64PFR1, SSBS, 4, 4)
47
--- a/hw/intc/arm_gicv3_common.c
41
FIELD(ID_AA64PFR1, MTE, 8, 4)
48
+++ b/hw/intc/arm_gicv3_common.c
42
FIELD(ID_AA64PFR1, RAS_FRAC, 12, 4)
49
@@ -XXX,XX +XXX,XX @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
43
+FIELD(ID_AA64PFR1, MPAM_FRAC, 16, 4)
50
return;
44
51
}
45
FIELD(ID_AA64MMFR0, PARANGE, 0, 4)
52
46
FIELD(ID_AA64MMFR0, ASIDBITS, 4, 4)
53
+ if (s->lpi_enable && !s->dma) {
47
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64MMFR0, TGRAN16_2, 32, 4)
54
+ error_setg(errp, "Redist-ITS: Guest 'sysmem' reference link not set");
48
FIELD(ID_AA64MMFR0, TGRAN64_2, 36, 4)
55
+ return;
49
FIELD(ID_AA64MMFR0, TGRAN4_2, 40, 4)
56
+ }
50
FIELD(ID_AA64MMFR0, EXS, 44, 4)
57
+
51
+FIELD(ID_AA64MMFR0, FGT, 56, 4)
58
s->cpu = g_new0(GICv3CPUState, s->num_cpu);
52
+FIELD(ID_AA64MMFR0, ECV, 60, 4)
59
53
60
for (i = 0; i < s->num_cpu; i++) {
54
FIELD(ID_AA64MMFR1, HAFDBS, 0, 4)
61
@@ -XXX,XX +XXX,XX @@ static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
55
FIELD(ID_AA64MMFR1, VMIDBITS, 4, 4)
62
(1 << 24) |
56
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64MMFR1, LO, 16, 4)
63
(i << 8) |
57
FIELD(ID_AA64MMFR1, PAN, 20, 4)
64
(last << 4);
58
FIELD(ID_AA64MMFR1, SPECSEI, 24, 4)
65
+
59
FIELD(ID_AA64MMFR1, XNX, 28, 4)
66
+ if (s->lpi_enable) {
60
+FIELD(ID_AA64MMFR1, TWED, 32, 4)
67
+ s->cpu[i].gicr_typer |= GICR_TYPER_PLPIS;
61
+FIELD(ID_AA64MMFR1, ETS, 36, 4)
68
+ }
62
69
}
63
FIELD(ID_AA64MMFR2, CNP, 0, 4)
70
}
64
FIELD(ID_AA64MMFR2, UAO, 4, 4)
71
65
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64DFR0, CTX_CMPS, 28, 4)
72
@@ -XXX,XX +XXX,XX @@ static Property arm_gicv3_common_properties[] = {
66
FIELD(ID_AA64DFR0, PMSVER, 32, 4)
73
DEFINE_PROP_UINT32("num-cpu", GICv3State, num_cpu, 1),
67
FIELD(ID_AA64DFR0, DOUBLELOCK, 36, 4)
74
DEFINE_PROP_UINT32("num-irq", GICv3State, num_irq, 32),
68
FIELD(ID_AA64DFR0, TRACEFILT, 40, 4)
75
DEFINE_PROP_UINT32("revision", GICv3State, revision, 3),
69
+FIELD(ID_AA64DFR0, MTPMU, 48, 4)
76
+ DEFINE_PROP_BOOL("has-lpi", GICv3State, lpi_enable, 0),
70
77
DEFINE_PROP_BOOL("has-security-extensions", GICv3State, security_extn, 0),
71
FIELD(ID_DFR0, COPDBG, 0, 4)
78
DEFINE_PROP_ARRAY("redist-region-count", GICv3State, nb_redist_regions,
72
FIELD(ID_DFR0, COPSDBG, 4, 4)
79
redist_region_count, qdev_prop_uint32, uint32_t),
80
+ DEFINE_PROP_LINK("sysmem", GICv3State, dma, TYPE_MEMORY_REGION,
81
+ MemoryRegion *),
82
DEFINE_PROP_END_OF_LIST(),
83
};
84
85
diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c
86
index XXXXXXX..XXXXXXX 100644
87
--- a/hw/intc/arm_gicv3_dist.c
88
+++ b/hw/intc/arm_gicv3_dist.c
89
@@ -XXX,XX +XXX,XX @@ static bool gicd_readl(GICv3State *s, hwaddr offset,
90
* A3V == 1 (non-zero values of Affinity level 3 supported)
91
* IDbits == 0xf (we support 16-bit interrupt identifiers)
92
* DVIS == 0 (Direct virtual LPI injection not supported)
93
- * LPIS == 0 (LPIs not supported)
94
+ * LPIS == 1 (LPIs are supported if affinity routing is enabled)
95
+ * num_LPIs == 0b00000 (bits [15:11],Number of LPIs as indicated
96
+ * by GICD_TYPER.IDbits)
97
* MBIS == 0 (message-based SPIs not supported)
98
* SecurityExtn == 1 if security extns supported
99
* CPUNumber == 0 since for us ARE is always 1
100
@@ -XXX,XX +XXX,XX @@ static bool gicd_readl(GICv3State *s, hwaddr offset,
101
bool sec_extn = !(s->gicd_ctlr & GICD_CTLR_DS);
102
103
*data = (1 << 25) | (1 << 24) | (sec_extn << 10) |
104
+ (s->lpi_enable << GICD_TYPER_LPIS_SHIFT) |
105
(0xf << 19) | itlinesnumber;
106
return true;
107
}
108
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
109
index XXXXXXX..XXXXXXX 100644
110
--- a/hw/intc/arm_gicv3_redist.c
111
+++ b/hw/intc/arm_gicv3_redist.c
112
@@ -XXX,XX +XXX,XX @@ static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset,
113
case GICR_CTLR:
114
/* For our implementation, GICR_TYPER.DPGS is 0 and so all
115
* the DPG bits are RAZ/WI. We don't do anything asynchronously,
116
- * so UWP and RWP are RAZ/WI. And GICR_TYPER.LPIS is 0 (we don't
117
- * implement LPIs) so Enable_LPIs is RES0. So there are no writable
118
- * bits for us.
119
+ * so UWP and RWP are RAZ/WI. GICR_TYPER.LPIS is 1 (we
120
+ * implement LPIs) so Enable_LPIs is programmable.
121
*/
122
+ if (cs->gicr_typer & GICR_TYPER_PLPIS) {
123
+ if (value & GICR_CTLR_ENABLE_LPIS) {
124
+ cs->gicr_ctlr |= GICR_CTLR_ENABLE_LPIS;
125
+ } else {
126
+ cs->gicr_ctlr &= ~GICR_CTLR_ENABLE_LPIS;
127
+ }
128
+ }
129
return MEMTX_OK;
130
case GICR_STATUSR:
131
/* RAZ/WI for our implementation */
132
--
73
--
133
2.20.1
74
2.20.1
134
75
135
76
diff view generated by jsdifflib
1
From: Shashi Mallela <shashi.mallela@linaro.org>
1
From: Leif Lindholm <leif@nuviainc.com>
2
2
3
Added functionality to trigger ITS command queue processing on
3
Add entries present in ARM DDI 0487F.c (August 2020).
4
write to CWRITE register and process each command queue entry to
5
identify the command type and handle commands like MAPD,MAPC,SYNC.
6
4
7
Signed-off-by: Shashi Mallela <shashi.mallela@linaro.org>
5
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Eric Auger <eric.auger@redhat.com>
7
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
10
Tested-by: Neil Armstrong <narmstrong@baylibre.com>
8
Message-id: 20210108185154.8108-7-leif@nuviainc.com
11
Message-id: 20210910143951.92242-4-shashi.mallela@linaro.org
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
10
---
14
hw/intc/gicv3_internal.h | 40 +++++
11
target/arm/cpu.h | 28 ++++++++++++++++++++++++++++
15
hw/intc/arm_gicv3_its.c | 319 +++++++++++++++++++++++++++++++++++++++
12
1 file changed, 28 insertions(+)
16
2 files changed, 359 insertions(+)
17
13
18
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
14
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
19
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
20
--- a/hw/intc/gicv3_internal.h
16
--- a/target/arm/cpu.h
21
+++ b/hw/intc/gicv3_internal.h
17
+++ b/target/arm/cpu.h
22
@@ -XXX,XX +XXX,XX @@ FIELD(GITS_TYPER, CIL, 36, 1)
18
@@ -XXX,XX +XXX,XX @@ FIELD(ID_ISAR6, DP, 4, 4)
23
#define L1TABLE_ENTRY_SIZE 8
19
FIELD(ID_ISAR6, FHM, 8, 4)
24
20
FIELD(ID_ISAR6, SB, 12, 4)
25
#define GITS_CMDQ_ENTRY_SIZE 32
21
FIELD(ID_ISAR6, SPECRES, 16, 4)
26
+#define NUM_BYTES_IN_DW 8
22
+FIELD(ID_ISAR6, BF16, 20, 4)
23
+FIELD(ID_ISAR6, I8MM, 24, 4)
24
25
FIELD(ID_MMFR0, VMSA, 0, 4)
26
FIELD(ID_MMFR0, PMSA, 4, 4)
27
@@ -XXX,XX +XXX,XX @@ FIELD(ID_MMFR0, AUXREG, 20, 4)
28
FIELD(ID_MMFR0, FCSE, 24, 4)
29
FIELD(ID_MMFR0, INNERSHR, 28, 4)
30
31
+FIELD(ID_MMFR1, L1HVDVA, 0, 4)
32
+FIELD(ID_MMFR1, L1UNIVA, 4, 4)
33
+FIELD(ID_MMFR1, L1HVDSW, 8, 4)
34
+FIELD(ID_MMFR1, L1UNISW, 12, 4)
35
+FIELD(ID_MMFR1, L1HVD, 16, 4)
36
+FIELD(ID_MMFR1, L1UNI, 20, 4)
37
+FIELD(ID_MMFR1, L1TSTCLN, 24, 4)
38
+FIELD(ID_MMFR1, BPRED, 28, 4)
27
+
39
+
28
+#define CMD_MASK 0xff
40
+FIELD(ID_MMFR2, L1HVDFG, 0, 4)
41
+FIELD(ID_MMFR2, L1HVDBG, 4, 4)
42
+FIELD(ID_MMFR2, L1HVDRNG, 8, 4)
43
+FIELD(ID_MMFR2, HVDTLB, 12, 4)
44
+FIELD(ID_MMFR2, UNITLB, 16, 4)
45
+FIELD(ID_MMFR2, MEMBARR, 20, 4)
46
+FIELD(ID_MMFR2, WFISTALL, 24, 4)
47
+FIELD(ID_MMFR2, HWACCFLG, 28, 4)
29
+
48
+
30
+/* ITS Commands */
49
FIELD(ID_MMFR3, CMAINTVA, 0, 4)
31
+#define GITS_CMD_CLEAR 0x04
50
FIELD(ID_MMFR3, CMAINTSW, 4, 4)
32
+#define GITS_CMD_DISCARD 0x0F
51
FIELD(ID_MMFR3, BPMAINT, 8, 4)
33
+#define GITS_CMD_INT 0x03
52
@@ -XXX,XX +XXX,XX @@ FIELD(ID_MMFR4, LSM, 20, 4)
34
+#define GITS_CMD_MAPC 0x09
53
FIELD(ID_MMFR4, CCIDX, 24, 4)
35
+#define GITS_CMD_MAPD 0x08
54
FIELD(ID_MMFR4, EVT, 28, 4)
36
+#define GITS_CMD_MAPI 0x0B
55
37
+#define GITS_CMD_MAPTI 0x0A
56
+FIELD(ID_MMFR5, ETS, 0, 4)
38
+#define GITS_CMD_INV 0x0C
39
+#define GITS_CMD_INVALL 0x0D
40
+#define GITS_CMD_SYNC 0x05
41
+
57
+
42
+/* MAPC command fields */
58
FIELD(ID_PFR0, STATE0, 0, 4)
43
+#define ICID_LENGTH 16
59
FIELD(ID_PFR0, STATE1, 4, 4)
44
+#define ICID_MASK ((1U << ICID_LENGTH) - 1)
60
FIELD(ID_PFR0, STATE2, 8, 4)
45
+FIELD(MAPC, RDBASE, 16, 32)
61
@@ -XXX,XX +XXX,XX @@ FIELD(ID_PFR1, SEC_FRAC, 20, 4)
62
FIELD(ID_PFR1, VIRT_FRAC, 24, 4)
63
FIELD(ID_PFR1, GIC, 28, 4)
64
65
+FIELD(ID_PFR2, CSV3, 0, 4)
66
+FIELD(ID_PFR2, SSBS, 4, 4)
67
+FIELD(ID_PFR2, RAS_FRAC, 8, 4)
46
+
68
+
47
+#define RDBASE_PROCNUM_LENGTH 16
69
FIELD(ID_AA64ISAR0, AES, 4, 4)
48
+#define RDBASE_PROCNUM_MASK ((1ULL << RDBASE_PROCNUM_LENGTH) - 1)
70
FIELD(ID_AA64ISAR0, SHA1, 8, 4)
71
FIELD(ID_AA64ISAR0, SHA2, 12, 4)
72
@@ -XXX,XX +XXX,XX @@ FIELD(ID_DFR0, MPROFDBG, 20, 4)
73
FIELD(ID_DFR0, PERFMON, 24, 4)
74
FIELD(ID_DFR0, TRACEFILT, 28, 4)
75
76
+FIELD(ID_DFR1, MTPMU, 0, 4)
49
+
77
+
50
+/* MAPD command fields */
78
FIELD(DBGDIDR, SE_IMP, 12, 1)
51
+#define ITTADDR_LENGTH 44
79
FIELD(DBGDIDR, NSUHD_IMP, 14, 1)
52
+#define ITTADDR_SHIFT 8
80
FIELD(DBGDIDR, VERSION, 16, 4)
53
+#define ITTADDR_MASK MAKE_64BIT_MASK(ITTADDR_SHIFT, ITTADDR_LENGTH)
54
+#define SIZE_MASK 0x1f
55
+
56
+#define DEVID_SHIFT 32
57
+#define DEVID_MASK MAKE_64BIT_MASK(32, 32)
58
+
59
+#define VALID_SHIFT 63
60
+#define CMD_FIELD_VALID_MASK (1ULL << VALID_SHIFT)
61
+#define L2_TABLE_VALID_MASK CMD_FIELD_VALID_MASK
62
+#define TABLE_ENTRY_VALID_MASK (1ULL << 0)
63
64
/**
65
* Default features advertised by this version of ITS
66
@@ -XXX,XX +XXX,XX @@ FIELD(GITS_TYPER, CIL, 36, 1)
67
* Valid = 1 bit,ITTAddr = 44 bits,Size = 5 bits
68
*/
69
#define GITS_DTE_SIZE (0x8ULL)
70
+#define GITS_DTE_ITTADDR_SHIFT 6
71
+#define GITS_DTE_ITTADDR_MASK MAKE_64BIT_MASK(GITS_DTE_ITTADDR_SHIFT, \
72
+ ITTADDR_LENGTH)
73
74
/*
75
* 8 bytes Collection Table Entry size
76
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
77
index XXXXXXX..XXXXXXX 100644
78
--- a/hw/intc/arm_gicv3_its.c
79
+++ b/hw/intc/arm_gicv3_its.c
80
@@ -XXX,XX +XXX,XX @@ static uint64_t baser_base_addr(uint64_t value, uint32_t page_sz)
81
return result;
82
}
83
84
+static bool update_cte(GICv3ITSState *s, uint16_t icid, bool valid,
85
+ uint64_t rdbase)
86
+{
87
+ AddressSpace *as = &s->gicv3->dma_as;
88
+ uint64_t value;
89
+ uint64_t l2t_addr;
90
+ bool valid_l2t;
91
+ uint32_t l2t_id;
92
+ uint32_t max_l2_entries;
93
+ uint64_t cte = 0;
94
+ MemTxResult res = MEMTX_OK;
95
+
96
+ if (!s->ct.valid) {
97
+ return true;
98
+ }
99
+
100
+ if (valid) {
101
+ /* add mapping entry to collection table */
102
+ cte = (valid & TABLE_ENTRY_VALID_MASK) | (rdbase << 1ULL);
103
+ }
104
+
105
+ /*
106
+ * The specification defines the format of level 1 entries of a
107
+ * 2-level table, but the format of level 2 entries and the format
108
+ * of flat-mapped tables is IMPDEF.
109
+ */
110
+ if (s->ct.indirect) {
111
+ l2t_id = icid / (s->ct.page_sz / L1TABLE_ENTRY_SIZE);
112
+
113
+ value = address_space_ldq_le(as,
114
+ s->ct.base_addr +
115
+ (l2t_id * L1TABLE_ENTRY_SIZE),
116
+ MEMTXATTRS_UNSPECIFIED, &res);
117
+
118
+ if (res != MEMTX_OK) {
119
+ return false;
120
+ }
121
+
122
+ valid_l2t = (value & L2_TABLE_VALID_MASK) != 0;
123
+
124
+ if (valid_l2t) {
125
+ max_l2_entries = s->ct.page_sz / s->ct.entry_sz;
126
+
127
+ l2t_addr = value & ((1ULL << 51) - 1);
128
+
129
+ address_space_stq_le(as, l2t_addr +
130
+ ((icid % max_l2_entries) * GITS_CTE_SIZE),
131
+ cte, MEMTXATTRS_UNSPECIFIED, &res);
132
+ }
133
+ } else {
134
+ /* Flat level table */
135
+ address_space_stq_le(as, s->ct.base_addr + (icid * GITS_CTE_SIZE),
136
+ cte, MEMTXATTRS_UNSPECIFIED, &res);
137
+ }
138
+ if (res != MEMTX_OK) {
139
+ return false;
140
+ } else {
141
+ return true;
142
+ }
143
+}
144
+
145
+static bool process_mapc(GICv3ITSState *s, uint32_t offset)
146
+{
147
+ AddressSpace *as = &s->gicv3->dma_as;
148
+ uint16_t icid;
149
+ uint64_t rdbase;
150
+ bool valid;
151
+ MemTxResult res = MEMTX_OK;
152
+ bool result = false;
153
+ uint64_t value;
154
+
155
+ offset += NUM_BYTES_IN_DW;
156
+ offset += NUM_BYTES_IN_DW;
157
+
158
+ value = address_space_ldq_le(as, s->cq.base_addr + offset,
159
+ MEMTXATTRS_UNSPECIFIED, &res);
160
+
161
+ if (res != MEMTX_OK) {
162
+ return result;
163
+ }
164
+
165
+ icid = value & ICID_MASK;
166
+
167
+ rdbase = (value & R_MAPC_RDBASE_MASK) >> R_MAPC_RDBASE_SHIFT;
168
+ rdbase &= RDBASE_PROCNUM_MASK;
169
+
170
+ valid = (value & CMD_FIELD_VALID_MASK);
171
+
172
+ if ((icid > s->ct.maxids.max_collids) || (rdbase > s->gicv3->num_cpu)) {
173
+ qemu_log_mask(LOG_GUEST_ERROR,
174
+ "ITS MAPC: invalid collection table attributes "
175
+ "icid %d rdbase %lu\n", icid, rdbase);
176
+ /*
177
+ * in this implementation, in case of error
178
+ * we ignore this command and move onto the next
179
+ * command in the queue
180
+ */
181
+ } else {
182
+ result = update_cte(s, icid, valid, rdbase);
183
+ }
184
+
185
+ return result;
186
+}
187
+
188
+static bool update_dte(GICv3ITSState *s, uint32_t devid, bool valid,
189
+ uint8_t size, uint64_t itt_addr)
190
+{
191
+ AddressSpace *as = &s->gicv3->dma_as;
192
+ uint64_t value;
193
+ uint64_t l2t_addr;
194
+ bool valid_l2t;
195
+ uint32_t l2t_id;
196
+ uint32_t max_l2_entries;
197
+ uint64_t dte = 0;
198
+ MemTxResult res = MEMTX_OK;
199
+
200
+ if (s->dt.valid) {
201
+ if (valid) {
202
+ /* add mapping entry to device table */
203
+ dte = (valid & TABLE_ENTRY_VALID_MASK) |
204
+ ((size & SIZE_MASK) << 1U) |
205
+ (itt_addr << GITS_DTE_ITTADDR_SHIFT);
206
+ }
207
+ } else {
208
+ return true;
209
+ }
210
+
211
+ /*
212
+ * The specification defines the format of level 1 entries of a
213
+ * 2-level table, but the format of level 2 entries and the format
214
+ * of flat-mapped tables is IMPDEF.
215
+ */
216
+ if (s->dt.indirect) {
217
+ l2t_id = devid / (s->dt.page_sz / L1TABLE_ENTRY_SIZE);
218
+
219
+ value = address_space_ldq_le(as,
220
+ s->dt.base_addr +
221
+ (l2t_id * L1TABLE_ENTRY_SIZE),
222
+ MEMTXATTRS_UNSPECIFIED, &res);
223
+
224
+ if (res != MEMTX_OK) {
225
+ return false;
226
+ }
227
+
228
+ valid_l2t = (value & L2_TABLE_VALID_MASK) != 0;
229
+
230
+ if (valid_l2t) {
231
+ max_l2_entries = s->dt.page_sz / s->dt.entry_sz;
232
+
233
+ l2t_addr = value & ((1ULL << 51) - 1);
234
+
235
+ address_space_stq_le(as, l2t_addr +
236
+ ((devid % max_l2_entries) * GITS_DTE_SIZE),
237
+ dte, MEMTXATTRS_UNSPECIFIED, &res);
238
+ }
239
+ } else {
240
+ /* Flat level table */
241
+ address_space_stq_le(as, s->dt.base_addr + (devid * GITS_DTE_SIZE),
242
+ dte, MEMTXATTRS_UNSPECIFIED, &res);
243
+ }
244
+ if (res != MEMTX_OK) {
245
+ return false;
246
+ } else {
247
+ return true;
248
+ }
249
+}
250
+
251
+static bool process_mapd(GICv3ITSState *s, uint64_t value, uint32_t offset)
252
+{
253
+ AddressSpace *as = &s->gicv3->dma_as;
254
+ uint32_t devid;
255
+ uint8_t size;
256
+ uint64_t itt_addr;
257
+ bool valid;
258
+ MemTxResult res = MEMTX_OK;
259
+ bool result = false;
260
+
261
+ devid = ((value & DEVID_MASK) >> DEVID_SHIFT);
262
+
263
+ offset += NUM_BYTES_IN_DW;
264
+ value = address_space_ldq_le(as, s->cq.base_addr + offset,
265
+ MEMTXATTRS_UNSPECIFIED, &res);
266
+
267
+ if (res != MEMTX_OK) {
268
+ return result;
269
+ }
270
+
271
+ size = (value & SIZE_MASK);
272
+
273
+ offset += NUM_BYTES_IN_DW;
274
+ value = address_space_ldq_le(as, s->cq.base_addr + offset,
275
+ MEMTXATTRS_UNSPECIFIED, &res);
276
+
277
+ if (res != MEMTX_OK) {
278
+ return result;
279
+ }
280
+
281
+ itt_addr = (value & ITTADDR_MASK) >> ITTADDR_SHIFT;
282
+
283
+ valid = (value & CMD_FIELD_VALID_MASK);
284
+
285
+ if ((devid > s->dt.maxids.max_devids) ||
286
+ (size > FIELD_EX64(s->typer, GITS_TYPER, IDBITS))) {
287
+ qemu_log_mask(LOG_GUEST_ERROR,
288
+ "ITS MAPD: invalid device table attributes "
289
+ "devid %d or size %d\n", devid, size);
290
+ /*
291
+ * in this implementation, in case of error
292
+ * we ignore this command and move onto the next
293
+ * command in the queue
294
+ */
295
+ } else {
296
+ result = update_dte(s, devid, valid, size, itt_addr);
297
+ }
298
+
299
+ return result;
300
+}
301
+
302
+/*
303
+ * Current implementation blocks until all
304
+ * commands are processed
305
+ */
306
+static void process_cmdq(GICv3ITSState *s)
307
+{
308
+ uint32_t wr_offset = 0;
309
+ uint32_t rd_offset = 0;
310
+ uint32_t cq_offset = 0;
311
+ uint64_t data;
312
+ AddressSpace *as = &s->gicv3->dma_as;
313
+ MemTxResult res = MEMTX_OK;
314
+ bool result = true;
315
+ uint8_t cmd;
316
+
317
+ if (!(s->ctlr & ITS_CTLR_ENABLED)) {
318
+ return;
319
+ }
320
+
321
+ wr_offset = FIELD_EX64(s->cwriter, GITS_CWRITER, OFFSET);
322
+
323
+ if (wr_offset > s->cq.max_entries) {
324
+ qemu_log_mask(LOG_GUEST_ERROR,
325
+ "%s: invalid write offset "
326
+ "%d\n", __func__, wr_offset);
327
+ return;
328
+ }
329
+
330
+ rd_offset = FIELD_EX64(s->creadr, GITS_CREADR, OFFSET);
331
+
332
+ if (rd_offset > s->cq.max_entries) {
333
+ qemu_log_mask(LOG_GUEST_ERROR,
334
+ "%s: invalid read offset "
335
+ "%d\n", __func__, rd_offset);
336
+ return;
337
+ }
338
+
339
+ while (wr_offset != rd_offset) {
340
+ cq_offset = (rd_offset * GITS_CMDQ_ENTRY_SIZE);
341
+ data = address_space_ldq_le(as, s->cq.base_addr + cq_offset,
342
+ MEMTXATTRS_UNSPECIFIED, &res);
343
+ if (res != MEMTX_OK) {
344
+ result = false;
345
+ }
346
+ cmd = (data & CMD_MASK);
347
+
348
+ switch (cmd) {
349
+ case GITS_CMD_INT:
350
+ break;
351
+ case GITS_CMD_CLEAR:
352
+ break;
353
+ case GITS_CMD_SYNC:
354
+ /*
355
+ * Current implementation makes a blocking synchronous call
356
+ * for every command issued earlier, hence the internal state
357
+ * is already consistent by the time SYNC command is executed.
358
+ * Hence no further processing is required for SYNC command.
359
+ */
360
+ break;
361
+ case GITS_CMD_MAPD:
362
+ result = process_mapd(s, data, cq_offset);
363
+ break;
364
+ case GITS_CMD_MAPC:
365
+ result = process_mapc(s, cq_offset);
366
+ break;
367
+ case GITS_CMD_MAPTI:
368
+ break;
369
+ case GITS_CMD_MAPI:
370
+ break;
371
+ case GITS_CMD_DISCARD:
372
+ break;
373
+ case GITS_CMD_INV:
374
+ case GITS_CMD_INVALL:
375
+ break;
376
+ default:
377
+ break;
378
+ }
379
+ if (result) {
380
+ rd_offset++;
381
+ rd_offset %= s->cq.max_entries;
382
+ s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, OFFSET, rd_offset);
383
+ } else {
384
+ /*
385
+ * in this implementation, in case of dma read/write error
386
+ * we stall the command processing
387
+ */
388
+ s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, STALLED, 1);
389
+ qemu_log_mask(LOG_GUEST_ERROR,
390
+ "%s: %x cmd processing failed\n", __func__, cmd);
391
+ break;
392
+ }
393
+ }
394
+}
395
+
396
/*
397
* This function extracts the ITS Device and Collection table specific
398
* parameters (like base_addr, size etc) from GITS_BASER register.
399
@@ -XXX,XX +XXX,XX @@ static bool its_writel(GICv3ITSState *s, hwaddr offset,
400
extract_table_params(s);
401
extract_cmdq_params(s);
402
s->creadr = 0;
403
+ process_cmdq(s);
404
}
405
break;
406
case GITS_CBASER:
407
@@ -XXX,XX +XXX,XX @@ static bool its_writel(GICv3ITSState *s, hwaddr offset,
408
case GITS_CWRITER:
409
s->cwriter = deposit64(s->cwriter, 0, 32,
410
(value & ~R_GITS_CWRITER_RETRY_MASK));
411
+ if (s->cwriter != s->creadr) {
412
+ process_cmdq(s);
413
+ }
414
break;
415
case GITS_CWRITER + 4:
416
s->cwriter = deposit64(s->cwriter, 32, 32, value);
417
@@ -XXX,XX +XXX,XX @@ static bool its_writell(GICv3ITSState *s, hwaddr offset,
418
break;
419
case GITS_CWRITER:
420
s->cwriter = value & ~R_GITS_CWRITER_RETRY_MASK;
421
+ if (s->cwriter != s->creadr) {
422
+ process_cmdq(s);
423
+ }
424
break;
425
case GITS_CREADR:
426
if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) {
427
--
81
--
428
2.20.1
82
2.20.1
429
83
430
84
diff view generated by jsdifflib
1
From: Bin Meng <bmeng.cn@gmail.com>
1
From: Roman Bolshakov <r.bolshakov@yadro.com>
2
2
3
We've got SW that expects FSBL (Bootlooader) to setup clocks and
3
QEMU documentation can't be opened if QEMU is run from build tree
4
resets. It's quite common that users run that SW on QEMU without
4
because executables are placed in the top of build tree after conversion
5
FSBL (FSBL typically requires the Xilinx tools installed). That's
5
to meson.
6
fine, since users can stil use -device loader to enable clocks etc.
7
6
8
To help folks understand what's going, a log (guest-error) message
7
Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
9
would be helpful here. In particular with the serial port since
8
Reported-by: Peter Maydell <peter.maydell@linaro.org>
10
things will go very quiet if they get things wrong.
9
Message-id: 20210108213815.64678-1-r.bolshakov@yadro.com
11
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
12
Suggested-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
13
Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
14
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
15
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
16
Message-id: 20210901124521.30599-7-bmeng.cn@gmail.com
17
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
18
---
12
---
19
hw/char/cadence_uart.c | 8 ++++++++
13
ui/cocoa.m | 2 +-
20
1 file changed, 8 insertions(+)
14
1 file changed, 1 insertion(+), 1 deletion(-)
21
15
22
diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
16
diff --git a/ui/cocoa.m b/ui/cocoa.m
23
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
24
--- a/hw/char/cadence_uart.c
18
--- a/ui/cocoa.m
25
+++ b/hw/char/cadence_uart.c
19
+++ b/ui/cocoa.m
26
@@ -XXX,XX +XXX,XX @@ static int uart_can_receive(void *opaque)
20
@@ -XXX,XX +XXX,XX @@ QemuCocoaView *cocoaView;
27
21
- (void) openDocumentation: (NSString *) filename
28
/* ignore characters when unclocked or in reset */
22
{
29
if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) {
23
/* Where to look for local files */
30
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: uart is unclocked or in reset\n",
24
- NSString *path_array[] = {@"../share/doc/qemu/", @"../doc/qemu/", @"../docs/"};
31
+ __func__);
25
+ NSString *path_array[] = {@"../share/doc/qemu/", @"../doc/qemu/", @"docs/"};
32
return 0;
26
NSString *full_file_path;
33
}
27
34
28
/* iterate thru the possible paths until the file is found */
35
@@ -XXX,XX +XXX,XX @@ static void uart_event(void *opaque, QEMUChrEvent event)
36
37
/* ignore characters when unclocked or in reset */
38
if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) {
39
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: uart is unclocked or in reset\n",
40
+ __func__);
41
return;
42
}
43
44
@@ -XXX,XX +XXX,XX @@ static MemTxResult uart_write(void *opaque, hwaddr offset,
45
46
/* ignore access when unclocked or in reset */
47
if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) {
48
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: uart is unclocked or in reset\n",
49
+ __func__);
50
return MEMTX_ERROR;
51
}
52
53
@@ -XXX,XX +XXX,XX @@ static MemTxResult uart_read(void *opaque, hwaddr offset,
54
55
/* ignore access when unclocked or in reset */
56
if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) {
57
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: uart is unclocked or in reset\n",
58
+ __func__);
59
return MEMTX_ERROR;
60
}
61
62
--
29
--
63
2.20.1
30
2.20.1
64
31
65
32
diff view generated by jsdifflib
1
The various MPS2 boards implemented in mps2.c have multiple I2C
1
In commit 1982e1602d15 we added a new qemu-storage-daemon(1) manpage.
2
buses: a bus dedicated to the audio configuration, one for the LCD
2
At the moment new manpages have to be listed both in the conf.py for
3
touchscreen controller, and two which are connected to the external
3
Sphinx and also in docs/meson.build for Meson. We forgot the second
4
Shield expansion connector. Mark the buses which are used only for
4
of those -- correct the omission.
5
board-internal devices as 'full' so that if the user creates i2c
6
devices on the commandline without specifying a bus name then they
7
will be connected to the I2C controller used for the Shield
8
connector, where guest software will expect them.
9
5
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
12
Message-id: 20210903151435.22379-5-peter.maydell@linaro.org
8
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
9
Message-id: 20210108161416.21129-2-peter.maydell@linaro.org
13
---
10
---
14
hw/arm/mps2.c | 12 +++++++++++-
11
docs/meson.build | 1 +
15
1 file changed, 11 insertions(+), 1 deletion(-)
12
1 file changed, 1 insertion(+)
16
13
17
diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c
14
diff --git a/docs/meson.build b/docs/meson.build
18
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/arm/mps2.c
16
--- a/docs/meson.build
20
+++ b/hw/arm/mps2.c
17
+++ b/docs/meson.build
21
@@ -XXX,XX +XXX,XX @@ static void mps2_common_init(MachineState *machine)
18
@@ -XXX,XX +XXX,XX @@ if build_docs
22
0x40023000, /* Audio */
19
'qemu-img.1': (have_tools ? 'man1' : ''),
23
0x40029000, /* Shield0 */
20
'qemu-nbd.8': (have_tools ? 'man8' : ''),
24
0x4002a000}; /* Shield1 */
21
'qemu-pr-helper.8': (have_tools ? 'man8' : ''),
25
- sysbus_create_simple(TYPE_ARM_SBCON_I2C, i2cbase[i], NULL);
22
+ 'qemu-storage-daemon.1': (have_tools ? 'man1' : ''),
26
+ DeviceState *dev;
23
'qemu-trace-stap.1': (config_host.has_key('CONFIG_TRACE_SYSTEMTAP') ? 'man1' : ''),
27
+
24
'virtfs-proxy-helper.1': (have_virtfs_proxy_helper ? 'man1' : ''),
28
+ dev = sysbus_create_simple(TYPE_ARM_SBCON_I2C, i2cbase[i], NULL);
25
'virtiofsd.1': (have_virtiofsd ? 'man1' : ''),
29
+ if (i < 2) {
30
+ /*
31
+ * internal-only bus: mark it full to avoid user-created
32
+ * i2c devices being plugged into it.
33
+ */
34
+ BusState *qbus = qdev_get_child_bus(dev, "i2c");
35
+ qbus_mark_full(qbus);
36
+ }
37
}
38
create_unimplemented_device("i2s", 0x40024000, 0x400);
39
40
--
26
--
41
2.20.1
27
2.20.1
42
28
43
29
diff view generated by jsdifflib
1
The mps2-tz boards use a data-driven structure to create the devices
1
When we first converted our documentation to Sphinx, we split it into
2
that sit behind peripheral protection controllers. Currently the
2
multiple manuals (system, interop, tools, etc), which are all built
3
functions which create these devices are passed an 'opaque' pointer
3
separately. The primary driver for this was wanting to be able to
4
which is always the address within the machine struct of the device
4
avoid shipping the 'devel' manual to end-users. However, this is
5
to create, and some "all devices need this" information like irqs and
5
working against the grain of the way Sphinx wants to be used and
6
addresses.
6
causes some annoyances:
7
7
* Cross-references between documents become much harder or
8
If a specific device needs more information than this, it is
8
possibly impossible
9
currently not possible to pass that through from the PPCInfo
9
* There is no single index to the whole documentation
10
data structure. Add support for passing an extra data parameter,
10
* Within one manual there's no links or table-of-contents info
11
so that we can more flexibly handle the needs of specific
11
that lets you easily navigate to the others
12
device types. To provide some type-safety we make this extra
12
* The devel manual doesn't get published on the QEMU website
13
parameter a pointer to a union (which initially has no members).
13
(it would be nice to able to refer to it there)
14
14
15
In particular, we would like to be able to indicate which of the
15
Merely hiding our developer documentation from end users seems like
16
i2c controllers are for on-board devices only and which are
16
it's not enough benefit for these costs. Combine all the
17
connected to the external 'shield' expansion port; a subsequent
17
documentation into a single manual (the same way that the readthedocs
18
patch will use this mechanism for that purpose.
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
21
* The per-manual conf.py files are no longer needed
22
* The man_pages[] specifications previously in each per-manual
23
conf.py move to the top level conf.py
24
* docs/meson.build logic is simplified as we now only need to run
25
Sphinx once for the HTML and then once for the manpages5B
26
* The old index.html.in that produced the top-level page with
27
links to each manual is no longer needed
28
29
Unfortunately this means that we now have to build the HTML
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.
19
36
20
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
37
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
21
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
38
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
22
Message-id: 20210903151435.22379-3-peter.maydell@linaro.org
39
Message-id: 20210108161416.21129-3-peter.maydell@linaro.org
23
---
40
---
24
hw/arm/mps2-tz.c | 35 ++++++++++++++++++++++-------------
41
docs/conf.py | 46 ++++++++++++++++++++++++++++++-
25
1 file changed, 22 insertions(+), 13 deletions(-)
42
docs/devel/conf.py | 15 -----------
26
43
docs/index.html.in | 17 ------------
27
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
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
28
index XXXXXXX..XXXXXXX 100644
60
index XXXXXXX..XXXXXXX 100644
29
--- a/hw/arm/mps2-tz.c
61
--- a/docs/conf.py
30
+++ b/hw/arm/mps2-tz.c
62
+++ b/docs/conf.py
31
@@ -XXX,XX +XXX,XX @@ static qemu_irq get_sse_irq_in(MPS2TZMachineState *mms, int irqno)
63
@@ -XXX,XX +XXX,XX @@ latex_documents = [
32
}
64
33
}
65
# -- Options for manual page output ---------------------------------------
34
66
# Individual manual/conf.py can override this to create man pages
35
+/* Union describing the device-specific extra data we pass to the devfn. */
67
-man_pages = []
36
+typedef union PPCExtraData {
68
+man_pages = [
37
+} PPCExtraData;
69
+ ('interop/qemu-ga', 'qemu-ga',
70
+ 'QEMU Guest Agent',
71
+ ['Michael Roth <mdroth@linux.vnet.ibm.com>'], 8),
72
+ ('interop/qemu-ga-ref', 'qemu-ga-ref',
73
+ 'QEMU Guest Agent Protocol Reference',
74
+ [], 7),
75
+ ('interop/qemu-qmp-ref', 'qemu-qmp-ref',
76
+ 'QEMU QMP Reference Manual',
77
+ [], 7),
78
+ ('interop/qemu-storage-daemon-qmp-ref', 'qemu-storage-daemon-qmp-ref',
79
+ 'QEMU Storage Daemon QMP Reference Manual',
80
+ [], 7),
81
+ ('system/qemu-manpage', 'qemu',
82
+ 'QEMU User Documentation',
83
+ ['Fabrice Bellard'], 1),
84
+ ('system/qemu-block-drivers', 'qemu-block-drivers',
85
+ 'QEMU block drivers reference',
86
+ ['Fabrice Bellard and the QEMU Project developers'], 7),
87
+ ('system/qemu-cpu-models', 'qemu-cpu-models',
88
+ 'QEMU CPU Models',
89
+ ['The QEMU Project developers'], 7),
90
+ ('tools/qemu-img', 'qemu-img',
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
118
index XXXXXXX..XXXXXXX
119
--- a/docs/devel/conf.py
120
+++ /dev/null
121
@@ -XXX,XX +XXX,XX @@
122
-# -*- coding: utf-8 -*-
123
-#
124
-# QEMU documentation build configuration file for the 'devel' manual.
125
-#
126
-# This includes the top level conf file and then makes any necessary tweaks.
127
-import sys
128
-import os
129
-
130
-qemu_docdir = os.path.abspath("..")
131
-parent_config = os.path.join(qemu_docdir, "conf.py")
132
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
133
-
134
-# This slightly misuses the 'description', but is the best way to get
135
-# the manual title to appear in the sidebar.
136
-html_theme_options['description'] = u'Developer''s Guide'
137
diff --git a/docs/index.html.in b/docs/index.html.in
138
deleted file mode 100644
139
index XXXXXXX..XXXXXXX
140
--- a/docs/index.html.in
141
+++ /dev/null
142
@@ -XXX,XX +XXX,XX @@
143
-<!DOCTYPE html>
144
-<html lang="en">
145
- <head>
146
- <meta charset="UTF-8">
147
- <title>QEMU @VERSION@ Documentation</title>
148
- </head>
149
- <body>
150
- <h1>QEMU @VERSION@ Documentation</h1>
151
- <ul>
152
- <li><a href="system/index.html">System Emulation User's Guide</a></li>
153
- <li><a href="user/index.html">User Mode Emulation User's Guide</a></li>
154
- <li><a href="tools/index.html">Tools Guide</a></li>
155
- <li><a href="interop/index.html">System Emulation Management and Interoperability Guide</a></li>
156
- <li><a href="specs/index.html">System Emulation Guest Hardware Specifications</a></li>
157
- </ul>
158
- </body>
159
-</html>
160
diff --git a/docs/interop/conf.py b/docs/interop/conf.py
161
deleted file mode 100644
162
index XXXXXXX..XXXXXXX
163
--- a/docs/interop/conf.py
164
+++ /dev/null
165
@@ -XXX,XX +XXX,XX @@
166
-# -*- coding: utf-8 -*-
167
-#
168
-# QEMU documentation build configuration file for the 'interop' manual.
169
-#
170
-# This includes the top level conf file and then makes any necessary tweaks.
171
-import sys
172
-import os
173
-
174
-qemu_docdir = os.path.abspath("..")
175
-parent_config = os.path.join(qemu_docdir, "conf.py")
176
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
177
-
178
-# This slightly misuses the 'description', but is the best way to get
179
-# the manual title to appear in the sidebar.
180
-html_theme_options['description'] = u'System Emulation Management and Interoperability Guide'
181
-
182
-# One entry per manual page. List of tuples
183
-# (source start file, name, description, authors, manual section).
184
-man_pages = [
185
- ('qemu-ga', 'qemu-ga', u'QEMU Guest Agent',
186
- ['Michael Roth <mdroth@linux.vnet.ibm.com>'], 8),
187
- ('qemu-ga-ref', 'qemu-ga-ref', 'QEMU Guest Agent Protocol Reference',
188
- [], 7),
189
- ('qemu-qmp-ref', 'qemu-qmp-ref', 'QEMU QMP Reference Manual',
190
- [], 7),
191
- ('qemu-storage-daemon-qmp-ref', 'qemu-storage-daemon-qmp-ref',
192
- 'QEMU Storage Daemon QMP Reference Manual', [], 7),
193
-]
194
diff --git a/docs/meson.build b/docs/meson.build
195
index XXXXXXX..XXXXXXX 100644
196
--- a/docs/meson.build
197
+++ b/docs/meson.build
198
@@ -XXX,XX +XXX,XX @@ if build_docs
199
meson.source_root() / 'docs/sphinx/qmp_lexer.py',
200
qapi_gen_depends ]
201
202
- configure_file(output: 'index.html',
203
- input: files('index.html.in'),
204
- configuration: {'VERSION': meson.project_version()},
205
- install_dir: qemu_docdir)
206
- manuals = [ 'devel', 'interop', 'tools', 'specs', 'system', 'user' ]
207
man_pages = {
208
- 'interop' : {
209
'qemu-ga.8': (have_tools ? 'man8' : ''),
210
'qemu-ga-ref.7': 'man7',
211
'qemu-qmp-ref.7': 'man7',
212
'qemu-storage-daemon-qmp-ref.7': (have_tools ? 'man7' : ''),
213
- },
214
- 'tools': {
215
'qemu-img.1': (have_tools ? 'man1' : ''),
216
'qemu-nbd.8': (have_tools ? 'man8' : ''),
217
'qemu-pr-helper.8': (have_tools ? 'man8' : ''),
218
@@ -XXX,XX +XXX,XX @@ if build_docs
219
'qemu-trace-stap.1': (config_host.has_key('CONFIG_TRACE_SYSTEMTAP') ? 'man1' : ''),
220
'virtfs-proxy-helper.1': (have_virtfs_proxy_helper ? 'man1' : ''),
221
'virtiofsd.1': (have_virtiofsd ? 'man1' : ''),
222
- },
223
- 'system': {
224
'qemu.1': 'man1',
225
'qemu-block-drivers.7': 'man7',
226
'qemu-cpu-models.7': 'man7'
227
- },
228
}
229
230
sphinxdocs = []
231
sphinxmans = []
232
- foreach manual : manuals
233
- private_dir = meson.current_build_dir() / (manual + '.p')
234
- output_dir = meson.current_build_dir() / manual
235
- input_dir = meson.current_source_dir() / manual
236
237
- this_manual = custom_target(manual + ' manual',
238
+ private_dir = meson.current_build_dir() / 'manual.p'
239
+ output_dir = meson.current_build_dir() / 'manual'
240
+ input_dir = meson.current_source_dir()
38
+
241
+
39
/* Most of the devices in the AN505 FPGA image sit behind
242
+ this_manual = custom_target('QEMU manual',
40
* Peripheral Protection Controllers. These data structures
243
build_by_default: build_docs,
41
* define the layout of which devices sit behind which PPCs.
244
- output: [manual + '.stamp'],
42
@@ -XXX,XX +XXX,XX @@ static qemu_irq get_sse_irq_in(MPS2TZMachineState *mms, int irqno)
245
- input: [files('conf.py'), files(manual / 'conf.py')],
43
*/
246
- depfile: manual + '.d',
44
typedef MemoryRegion *MakeDevFn(MPS2TZMachineState *mms, void *opaque,
247
+ output: 'docs.stamp',
45
const char *name, hwaddr size,
248
+ input: files('conf.py'),
46
- const int *irqs);
249
+ depfile: 'docs.d',
47
+ const int *irqs,
250
depend_files: sphinx_extn_depends,
48
+ const PPCExtraData *extradata);
251
command: [SPHINX_ARGS, '-Ddepfile=@DEPFILE@',
49
252
'-Ddepfile_stamp=@OUTPUT0@',
50
typedef struct PPCPortInfo {
253
'-b', 'html', '-d', private_dir,
51
const char *name;
254
input_dir, output_dir])
52
@@ -XXX,XX +XXX,XX @@ typedef struct PPCPortInfo {
255
- sphinxdocs += this_manual
53
hwaddr addr;
256
- if build_docs and manual != 'devel'
54
hwaddr size;
257
- install_subdir(output_dir, install_dir: qemu_docdir)
55
int irqs[3]; /* currently no device needs more IRQ lines than this */
258
- endif
56
+ PPCExtraData extradata; /* to pass device-specific info to the devfn */
259
+ sphinxdocs += this_manual
57
} PPCPortInfo;
260
+ install_subdir(output_dir, install_dir: qemu_docdir, strip_directory: true)
58
261
59
typedef struct PPCInfo {
262
- these_man_pages = []
60
@@ -XXX,XX +XXX,XX @@ typedef struct PPCInfo {
263
- install_dirs = []
61
static MemoryRegion *make_unimp_dev(MPS2TZMachineState *mms,
264
- foreach page, section : man_pages.get(manual, {})
62
void *opaque,
265
- these_man_pages += page
63
const char *name, hwaddr size,
266
- install_dirs += section == '' ? false : get_option('mandir') / section
64
- const int *irqs)
267
- endforeach
65
+ const int *irqs,
268
- if these_man_pages.length() > 0
66
+ const PPCExtraData *extradata)
269
- sphinxmans += custom_target(manual + ' man pages',
67
{
270
- build_by_default: build_docs,
68
/* Initialize, configure and realize a TYPE_UNIMPLEMENTED_DEVICE,
271
- output: these_man_pages,
69
* and return a pointer to its MemoryRegion.
272
- input: this_manual,
70
@@ -XXX,XX +XXX,XX @@ static MemoryRegion *make_unimp_dev(MPS2TZMachineState *mms,
273
- install: build_docs,
71
274
- install_dir: install_dirs,
72
static MemoryRegion *make_uart(MPS2TZMachineState *mms, void *opaque,
275
- command: [SPHINX_ARGS, '-b', 'man', '-d', private_dir,
73
const char *name, hwaddr size,
276
- input_dir, meson.current_build_dir()])
74
- const int *irqs)
277
- endif
75
+ const int *irqs, const PPCExtraData *extradata)
278
+ these_man_pages = []
76
{
279
+ install_dirs = []
77
/* The irq[] array is tx, rx, combined, in that order */
280
+ foreach page, section : man_pages
78
MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms);
281
+ these_man_pages += page
79
@@ -XXX,XX +XXX,XX @@ static MemoryRegion *make_uart(MPS2TZMachineState *mms, void *opaque,
282
+ install_dirs += section == '' ? false : get_option('mandir') / section
80
283
endforeach
81
static MemoryRegion *make_scc(MPS2TZMachineState *mms, void *opaque,
284
+
82
const char *name, hwaddr size,
285
+ sphinxmans += custom_target('QEMU man pages',
83
- const int *irqs)
286
+ build_by_default: build_docs,
84
+ const int *irqs, const PPCExtraData *extradata)
287
+ output: these_man_pages,
85
{
288
+ input: this_manual,
86
MPS2SCC *scc = opaque;
289
+ install: build_docs,
87
DeviceState *sccdev;
290
+ install_dir: install_dirs,
88
@@ -XXX,XX +XXX,XX @@ static MemoryRegion *make_scc(MPS2TZMachineState *mms, void *opaque,
291
+ command: [SPHINX_ARGS, '-b', 'man', '-d', private_dir,
89
292
+ input_dir, meson.current_build_dir()])
90
static MemoryRegion *make_fpgaio(MPS2TZMachineState *mms, void *opaque,
293
+
91
const char *name, hwaddr size,
294
alias_target('sphinxdocs', sphinxdocs)
92
- const int *irqs)
295
alias_target('html', sphinxdocs)
93
+ const int *irqs, const PPCExtraData *extradata)
296
alias_target('man', sphinxmans)
94
{
297
diff --git a/docs/specs/conf.py b/docs/specs/conf.py
95
MPS2FPGAIO *fpgaio = opaque;
298
deleted file mode 100644
96
MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_GET_CLASS(mms);
299
index XXXXXXX..XXXXXXX
97
@@ -XXX,XX +XXX,XX @@ static MemoryRegion *make_fpgaio(MPS2TZMachineState *mms, void *opaque,
300
--- a/docs/specs/conf.py
98
301
+++ /dev/null
99
static MemoryRegion *make_eth_dev(MPS2TZMachineState *mms, void *opaque,
302
@@ -XXX,XX +XXX,XX @@
100
const char *name, hwaddr size,
303
-# -*- coding: utf-8 -*-
101
- const int *irqs)
304
-#
102
+ const int *irqs,
305
-# QEMU documentation build configuration file for the 'specs' manual.
103
+ const PPCExtraData *extradata)
306
-#
104
{
307
-# This includes the top level conf file and then makes any necessary tweaks.
105
SysBusDevice *s;
308
-import sys
106
NICInfo *nd = &nd_table[0];
309
-import os
107
@@ -XXX,XX +XXX,XX @@ static MemoryRegion *make_eth_dev(MPS2TZMachineState *mms, void *opaque,
310
-
108
311
-qemu_docdir = os.path.abspath("..")
109
static MemoryRegion *make_eth_usb(MPS2TZMachineState *mms, void *opaque,
312
-parent_config = os.path.join(qemu_docdir, "conf.py")
110
const char *name, hwaddr size,
313
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
111
- const int *irqs)
314
-
112
+ const int *irqs,
315
-# This slightly misuses the 'description', but is the best way to get
113
+ const PPCExtraData *extradata)
316
-# the manual title to appear in the sidebar.
114
{
317
-html_theme_options['description'] = \
115
/*
318
- u'System Emulation Guest Hardware Specifications'
116
* The AN524 makes the ethernet and USB share a PPC port.
319
diff --git a/docs/system/conf.py b/docs/system/conf.py
117
@@ -XXX,XX +XXX,XX @@ static MemoryRegion *make_eth_usb(MPS2TZMachineState *mms, void *opaque,
320
deleted file mode 100644
118
321
index XXXXXXX..XXXXXXX
119
static MemoryRegion *make_mpc(MPS2TZMachineState *mms, void *opaque,
322
--- a/docs/system/conf.py
120
const char *name, hwaddr size,
323
+++ /dev/null
121
- const int *irqs)
324
@@ -XXX,XX +XXX,XX @@
122
+ const int *irqs, const PPCExtraData *extradata)
325
-# -*- coding: utf-8 -*-
123
{
326
-#
124
TZMPC *mpc = opaque;
327
-# QEMU documentation build configuration file for the 'system' manual.
125
int i = mpc - &mms->mpc[0];
328
-#
126
@@ -XXX,XX +XXX,XX @@ static void remap_irq_fn(void *opaque, int n, int level)
329
-# This includes the top level conf file and then makes any necessary tweaks.
127
330
-import sys
128
static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque,
331
-import os
129
const char *name, hwaddr size,
332
-
130
- const int *irqs)
333
-qemu_docdir = os.path.abspath("..")
131
+ const int *irqs, const PPCExtraData *extradata)
334
-parent_config = os.path.join(qemu_docdir, "conf.py")
132
{
335
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
133
/* The irq[] array is DMACINTR, DMACINTERR, DMACINTTC, in that order */
336
-
134
PL080State *dma = opaque;
337
-# This slightly misuses the 'description', but is the best way to get
135
@@ -XXX,XX +XXX,XX @@ static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque,
338
-# the manual title to appear in the sidebar.
136
339
-html_theme_options['description'] = u'System Emulation User''s Guide'
137
static MemoryRegion *make_spi(MPS2TZMachineState *mms, void *opaque,
340
-
138
const char *name, hwaddr size,
341
-# One entry per manual page. List of tuples
139
- const int *irqs)
342
-# (source start file, name, description, authors, manual section).
140
+ const int *irqs, const PPCExtraData *extradata)
343
-man_pages = [
141
{
344
- ('qemu-manpage', 'qemu', u'QEMU User Documentation',
142
/*
345
- ['Fabrice Bellard'], 1),
143
* The AN505 has five PL022 SPI controllers.
346
- ('qemu-block-drivers', 'qemu-block-drivers',
144
@@ -XXX,XX +XXX,XX @@ static MemoryRegion *make_spi(MPS2TZMachineState *mms, void *opaque,
347
- u'QEMU block drivers reference',
145
348
- ['Fabrice Bellard and the QEMU Project developers'], 7),
146
static MemoryRegion *make_i2c(MPS2TZMachineState *mms, void *opaque,
349
- ('qemu-cpu-models', 'qemu-cpu-models',
147
const char *name, hwaddr size,
350
- u'QEMU CPU Models',
148
- const int *irqs)
351
- ['The QEMU Project developers'], 7)
149
+ const int *irqs, const PPCExtraData *extradata)
352
-]
150
{
353
diff --git a/docs/tools/conf.py b/docs/tools/conf.py
151
ArmSbconI2CState *i2c = opaque;
354
deleted file mode 100644
152
SysBusDevice *s;
355
index XXXXXXX..XXXXXXX
153
@@ -XXX,XX +XXX,XX @@ static MemoryRegion *make_i2c(MPS2TZMachineState *mms, void *opaque,
356
--- a/docs/tools/conf.py
154
357
+++ /dev/null
155
static MemoryRegion *make_rtc(MPS2TZMachineState *mms, void *opaque,
358
@@ -XXX,XX +XXX,XX @@
156
const char *name, hwaddr size,
359
-# -*- coding: utf-8 -*-
157
- const int *irqs)
360
-#
158
+ const int *irqs, const PPCExtraData *extradata)
361
-# QEMU documentation build configuration file for the 'tools' manual.
159
{
362
-#
160
PL031State *pl031 = opaque;
363
-# This includes the top level conf file and then makes any necessary tweaks.
161
SysBusDevice *s;
364
-import sys
162
@@ -XXX,XX +XXX,XX @@ static void mps2tz_common_init(MachineState *machine)
365
-import os
163
}
366
-
164
367
-qemu_docdir = os.path.abspath("..")
165
mr = pinfo->devfn(mms, pinfo->opaque, pinfo->name, pinfo->size,
368
-parent_config = os.path.join(qemu_docdir, "conf.py")
166
- pinfo->irqs);
369
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
167
+ pinfo->irqs, &pinfo->extradata);
370
-
168
portname = g_strdup_printf("port[%d]", port);
371
-# This slightly misuses the 'description', but is the best way to get
169
object_property_set_link(OBJECT(ppc), portname, OBJECT(mr),
372
-# the manual title to appear in the sidebar.
170
&error_fatal);
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'
171
--
417
--
172
2.20.1
418
2.20.1
173
419
174
420
diff view generated by jsdifflib
1
The various MPS2 boards have multiple I2C buses: typically a bus
1
In commit cd8be50e58f63413c0 we converted the A32 coprocessor
2
dedicated to the audio configuration, one for the LCD touchscreen
2
insns to decodetree. This accidentally broke XScale/iWMMXt insns,
3
controller, one for a DDR4 EEPROM, and two which are connected to the
3
because it moved the handling of "cp insns which are handled
4
external Shield expansion connector. Mark the buses which are used
4
by looking up the cp register in the hashtable" from after the
5
only for board-internal devices as 'full' so that if the user creates
5
call to the legacy disas_xscale_insn() decode to before it,
6
i2c devices on the commandline without specifying a bus name then
6
with the result that all XScale/iWMMXt insns now UNDEF.
7
they will be connected to the I2C controller used for the Shield
8
connector, where guest software will expect them.
9
7
8
Update valid_cp() so that it knows that on XScale cp 0 and 1
9
are not standard coprocessor instructions; this will cause
10
the decodetree trans_ functions to ignore them, so that
11
execution will correctly get through to the legacy decode again.
12
13
Cc: qemu-stable@nongnu.org
14
Reported-by: Guenter Roeck <linux@roeck-us.net>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
16
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
12
Message-id: 20210903151435.22379-4-peter.maydell@linaro.org
17
Tested-by: Guenter Roeck <linux@roeck-us.net>
18
Message-id: 20210108195157.32067-1-peter.maydell@linaro.org
13
---
19
---
14
hw/arm/mps2-tz.c | 57 ++++++++++++++++++++++++++++++++++++------------
20
target/arm/translate.c | 7 +++++++
15
1 file changed, 43 insertions(+), 14 deletions(-)
21
1 file changed, 7 insertions(+)
16
22
17
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
23
diff --git a/target/arm/translate.c b/target/arm/translate.c
18
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/arm/mps2-tz.c
25
--- a/target/arm/translate.c
20
+++ b/hw/arm/mps2-tz.c
26
+++ b/target/arm/translate.c
21
@@ -XXX,XX +XXX,XX @@ static qemu_irq get_sse_irq_in(MPS2TZMachineState *mms, int irqno)
27
@@ -XXX,XX +XXX,XX @@ static bool valid_cp(DisasContext *s, int cp)
22
28
* only cp14 and cp15 are valid, and other values aren't considered
23
/* Union describing the device-specific extra data we pass to the devfn. */
29
* to be in the coprocessor-instruction space at all. v8M still
24
typedef union PPCExtraData {
30
* permits coprocessors 0..7.
25
+ bool i2c_internal;
31
+ * For XScale, we must not decode the XScale cp0, cp1 space as
26
} PPCExtraData;
32
+ * a standard coprocessor insn, because we want to fall through to
27
33
+ * the legacy disas_xscale_insn() decoder after decodetree is done.
28
/* Most of the devices in the AN505 FPGA image sit behind
34
*/
29
@@ -XXX,XX +XXX,XX @@ static MemoryRegion *make_i2c(MPS2TZMachineState *mms, void *opaque,
35
+ if (arm_dc_feature(s, ARM_FEATURE_XSCALE) && (cp == 0 || cp == 1)) {
30
object_initialize_child(OBJECT(mms), name, i2c, TYPE_ARM_SBCON_I2C);
36
+ return false;
31
s = SYS_BUS_DEVICE(i2c);
32
sysbus_realize(s, &error_fatal);
33
+
34
+ /*
35
+ * If this is an internal-use-only i2c bus, mark it full
36
+ * so that user-created i2c devices are not plugged into it.
37
+ * If we implement models of any on-board i2c devices that
38
+ * plug in to one of the internal-use-only buses, then we will
39
+ * need to create and plugging those in here before we mark the
40
+ * bus as full.
41
+ */
42
+ if (extradata->i2c_internal) {
43
+ BusState *qbus = qdev_get_child_bus(DEVICE(i2c), "i2c");
44
+ qbus_mark_full(qbus);
45
+ }
37
+ }
46
+
38
+
47
return sysbus_mmio_get_region(s, 0);
39
if (arm_dc_feature(s, ARM_FEATURE_V8) &&
48
}
40
!arm_dc_feature(s, ARM_FEATURE_M)) {
49
41
return cp >= 14;
50
@@ -XXX,XX +XXX,XX @@ static void mps2tz_common_init(MachineState *machine)
51
{ "uart2", make_uart, &mms->uart[2], 0x40202000, 0x1000, { 36, 37, 44 } },
52
{ "uart3", make_uart, &mms->uart[3], 0x40203000, 0x1000, { 38, 39, 45 } },
53
{ "uart4", make_uart, &mms->uart[4], 0x40204000, 0x1000, { 40, 41, 46 } },
54
- { "i2c0", make_i2c, &mms->i2c[0], 0x40207000, 0x1000 },
55
- { "i2c1", make_i2c, &mms->i2c[1], 0x40208000, 0x1000 },
56
- { "i2c2", make_i2c, &mms->i2c[2], 0x4020c000, 0x1000 },
57
- { "i2c3", make_i2c, &mms->i2c[3], 0x4020d000, 0x1000 },
58
+ { "i2c0", make_i2c, &mms->i2c[0], 0x40207000, 0x1000, {},
59
+ { .i2c_internal = true /* touchscreen */ } },
60
+ { "i2c1", make_i2c, &mms->i2c[1], 0x40208000, 0x1000, {},
61
+ { .i2c_internal = true /* audio conf */ } },
62
+ { "i2c2", make_i2c, &mms->i2c[2], 0x4020c000, 0x1000, {},
63
+ { .i2c_internal = false /* shield 0 */ } },
64
+ { "i2c3", make_i2c, &mms->i2c[3], 0x4020d000, 0x1000, {},
65
+ { .i2c_internal = false /* shield 1 */ } },
66
},
67
}, {
68
.name = "apb_ppcexp2",
69
@@ -XXX,XX +XXX,XX @@ static void mps2tz_common_init(MachineState *machine)
70
}, {
71
.name = "apb_ppcexp1",
72
.ports = {
73
- { "i2c0", make_i2c, &mms->i2c[0], 0x41200000, 0x1000 },
74
- { "i2c1", make_i2c, &mms->i2c[1], 0x41201000, 0x1000 },
75
+ { "i2c0", make_i2c, &mms->i2c[0], 0x41200000, 0x1000, {},
76
+ { .i2c_internal = true /* touchscreen */ } },
77
+ { "i2c1", make_i2c, &mms->i2c[1], 0x41201000, 0x1000, {},
78
+ { .i2c_internal = true /* audio conf */ } },
79
{ "spi0", make_spi, &mms->spi[0], 0x41202000, 0x1000, { 52 } },
80
{ "spi1", make_spi, &mms->spi[1], 0x41203000, 0x1000, { 53 } },
81
{ "spi2", make_spi, &mms->spi[2], 0x41204000, 0x1000, { 54 } },
82
- { "i2c2", make_i2c, &mms->i2c[2], 0x41205000, 0x1000 },
83
- { "i2c3", make_i2c, &mms->i2c[3], 0x41206000, 0x1000 },
84
+ { "i2c2", make_i2c, &mms->i2c[2], 0x41205000, 0x1000, {},
85
+ { .i2c_internal = false /* shield 0 */ } },
86
+ { "i2c3", make_i2c, &mms->i2c[3], 0x41206000, 0x1000, {},
87
+ { .i2c_internal = false /* shield 1 */ } },
88
{ /* port 7 reserved */ },
89
- { "i2c4", make_i2c, &mms->i2c[4], 0x41208000, 0x1000 },
90
+ { "i2c4", make_i2c, &mms->i2c[4], 0x41208000, 0x1000, {},
91
+ { .i2c_internal = true /* DDR4 EEPROM */ } },
92
},
93
}, {
94
.name = "apb_ppcexp2",
95
@@ -XXX,XX +XXX,XX @@ static void mps2tz_common_init(MachineState *machine)
96
}, {
97
.name = "apb_ppcexp1",
98
.ports = {
99
- { "i2c0", make_i2c, &mms->i2c[0], 0x49200000, 0x1000 },
100
- { "i2c1", make_i2c, &mms->i2c[1], 0x49201000, 0x1000 },
101
+ { "i2c0", make_i2c, &mms->i2c[0], 0x49200000, 0x1000, {},
102
+ { .i2c_internal = true /* touchscreen */ } },
103
+ { "i2c1", make_i2c, &mms->i2c[1], 0x49201000, 0x1000, {},
104
+ { .i2c_internal = true /* audio conf */ } },
105
{ "spi0", make_spi, &mms->spi[0], 0x49202000, 0x1000, { 53 } },
106
{ "spi1", make_spi, &mms->spi[1], 0x49203000, 0x1000, { 54 } },
107
{ "spi2", make_spi, &mms->spi[2], 0x49204000, 0x1000, { 55 } },
108
- { "i2c2", make_i2c, &mms->i2c[2], 0x49205000, 0x1000 },
109
- { "i2c3", make_i2c, &mms->i2c[3], 0x49206000, 0x1000 },
110
+ { "i2c2", make_i2c, &mms->i2c[2], 0x49205000, 0x1000, {},
111
+ { .i2c_internal = false /* shield 0 */ } },
112
+ { "i2c3", make_i2c, &mms->i2c[3], 0x49206000, 0x1000, {},
113
+ { .i2c_internal = false /* shield 1 */ } },
114
{ /* port 7 reserved */ },
115
- { "i2c4", make_i2c, &mms->i2c[4], 0x49208000, 0x1000 },
116
+ { "i2c4", make_i2c, &mms->i2c[4], 0x49208000, 0x1000, {},
117
+ { .i2c_internal = true /* DDR4 EEPROM */ } },
118
},
119
}, {
120
.name = "apb_ppcexp2",
121
--
42
--
122
2.20.1
43
2.20.1
123
44
124
45
diff view generated by jsdifflib
1
From: Marc Zyngier <maz@kernel.org>
1
A copy-and-paste error meant that the return value for register offset 0x44
2
(the RX Status FIFO PEEK register) returned a byte from a bogus offset in
3
the rx status FIFO. Fix the typo.
2
4
3
Although we probe for the IPA limits imposed by KVM (and the hardware)
5
Cc: qemu-stable@nongnu.org
4
when computing the memory map, we still use the old style '0' when
6
Fixes: https://bugs.launchpad.net/qemu/+bug/1904954
5
creating a scratch VM in kvm_arm_create_scratch_host_vcpu().
7
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
---
11
hw/net/lan9118.c | 2 +-
12
1 file changed, 1 insertion(+), 1 deletion(-)
6
13
7
On systems that are severely IPA challenged (such as the Apple M1),
14
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
8
this results in a failure as KVM cannot use the default 40bit that
9
'0' represents.
10
11
Instead, probe for the extension and use the reported IPA limit
12
if available.
13
14
Cc: Andrew Jones <drjones@redhat.com>
15
Cc: Eric Auger <eric.auger@redhat.com>
16
Cc: Peter Maydell <peter.maydell@linaro.org>
17
Signed-off-by: Marc Zyngier <maz@kernel.org>
18
Reviewed-by: Andrew Jones <drjones@redhat.com>
19
Message-id: 20210822144441.1290891-2-maz@kernel.org
20
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
21
---
22
target/arm/kvm.c | 7 ++++++-
23
1 file changed, 6 insertions(+), 1 deletion(-)
24
25
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
26
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
27
--- a/target/arm/kvm.c
16
--- a/hw/net/lan9118.c
28
+++ b/target/arm/kvm.c
17
+++ b/hw/net/lan9118.c
29
@@ -XXX,XX +XXX,XX @@ bool kvm_arm_create_scratch_host_vcpu(const uint32_t *cpus_to_try,
18
@@ -XXX,XX +XXX,XX @@ static uint64_t lan9118_readl(void *opaque, hwaddr offset,
30
struct kvm_vcpu_init *init)
19
case 0x40:
31
{
20
return rx_status_fifo_pop(s);
32
int ret = 0, kvmfd = -1, vmfd = -1, cpufd = -1;
21
case 0x44:
33
+ int max_vm_pa_size;
22
- return s->rx_status_fifo[s->tx_status_fifo_head];
34
23
+ return s->rx_status_fifo[s->rx_status_fifo_head];
35
kvmfd = qemu_open_old("/dev/kvm", O_RDWR);
24
case 0x48:
36
if (kvmfd < 0) {
25
return tx_status_fifo_pop(s);
37
goto err;
26
case 0x4c:
38
}
39
- vmfd = ioctl(kvmfd, KVM_CREATE_VM, 0);
40
+ max_vm_pa_size = ioctl(kvmfd, KVM_CHECK_EXTENSION, KVM_CAP_ARM_VM_IPA_SIZE);
41
+ if (max_vm_pa_size < 0) {
42
+ max_vm_pa_size = 0;
43
+ }
44
+ vmfd = ioctl(kvmfd, KVM_CREATE_VM, max_vm_pa_size);
45
if (vmfd < 0) {
46
goto err;
47
}
48
--
27
--
49
2.20.1
28
2.20.1
50
29
51
30
diff view generated by jsdifflib
1
By default, QEMU will allow devices to be plugged into a bus up to
1
The lan9118 code mostly uses symbolic constants for register offsets;
2
the bus class's device count limit. If the user creates a device on
2
the exceptions are those which the datasheet doesn't give an official
3
the command line or via the monitor and doesn't explicitly specify
3
symbolic name to.
4
the bus to plug it in, QEMU will plug it into the first non-full bus
5
that it finds.
6
4
7
This is fine in most cases, but some machines have multiple buses of
5
Add some names for the registers which don't already have them, based
8
a given type, some of which are dedicated to on-board devices and
6
on the longer names they are given in the memory map.
9
some of which have an externally exposed connector for user-pluggable
10
devices. One example is I2C buses.
11
12
Provide a new function qbus_mark_full() so that a machine model can
13
mark this kind of "internal only" bus as 'full' after it has created
14
all the devices that should be plugged into that bus. The "find a
15
non-full bus" algorithm will then skip the internal-only bus when
16
looking for a place to plug in user-created devices.
17
7
18
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
19
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
20
Message-id: 20210903151435.22379-2-peter.maydell@linaro.org
10
Message-id: 20210108180401.2263-3-peter.maydell@linaro.org
21
---
11
---
22
include/hw/qdev-core.h | 24 ++++++++++++++++++++++++
12
hw/net/lan9118.c | 24 ++++++++++++++++++------
23
softmmu/qdev-monitor.c | 7 ++++++-
13
1 file changed, 18 insertions(+), 6 deletions(-)
24
2 files changed, 30 insertions(+), 1 deletion(-)
25
14
26
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
15
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
27
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
28
--- a/include/hw/qdev-core.h
17
--- a/hw/net/lan9118.c
29
+++ b/include/hw/qdev-core.h
18
+++ b/hw/net/lan9118.c
30
@@ -XXX,XX +XXX,XX @@ struct BusState {
19
@@ -XXX,XX +XXX,XX @@ do { hw_error("lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
31
HotplugHandler *hotplug_handler;
20
do { fprintf(stderr, "lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
32
int max_index;
21
#endif
33
bool realized;
22
34
+ bool full;
23
+/* The tx and rx fifo ports are a range of aliased 32-bit registers */
35
int num_children;
24
+#define RX_DATA_FIFO_PORT_FIRST 0x00
36
25
+#define RX_DATA_FIFO_PORT_LAST 0x1f
37
/*
26
+#define TX_DATA_FIFO_PORT_FIRST 0x20
38
@@ -XXX,XX +XXX,XX @@ static inline bool qbus_is_hotpluggable(BusState *bus)
27
+#define TX_DATA_FIFO_PORT_LAST 0x3f
39
return bus->hotplug_handler;
40
}
41
42
+/**
43
+ * qbus_mark_full: Mark this bus as full, so no more devices can be attached
44
+ * @bus: Bus to mark as full
45
+ *
46
+ * By default, QEMU will allow devices to be plugged into a bus up
47
+ * to the bus class's device count limit. Calling this function
48
+ * marks a particular bus as full, so that no more devices can be
49
+ * plugged into it. In particular this means that the bus will not
50
+ * be considered as a candidate for plugging in devices created by
51
+ * the user on the commandline or via the monitor.
52
+ * If a machine has multiple buses of a given type, such as I2C,
53
+ * where some of those buses in the real hardware are used only for
54
+ * internal devices and some are exposed via expansion ports, you
55
+ * can use this function to mark the internal-only buses as full
56
+ * after you have created all their internal devices. Then user
57
+ * created devices will appear on the expansion-port bus where
58
+ * guest software expects them.
59
+ */
60
+static inline void qbus_mark_full(BusState *bus)
61
+{
62
+ bus->full = true;
63
+}
64
+
28
+
65
void device_listener_register(DeviceListener *listener);
29
+#define RX_STATUS_FIFO_PORT 0x40
66
void device_listener_unregister(DeviceListener *listener);
30
+#define RX_STATUS_FIFO_PEEK 0x44
67
31
+#define TX_STATUS_FIFO_PORT 0x48
68
diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
32
+#define TX_STATUS_FIFO_PEEK 0x4c
69
index XXXXXXX..XXXXXXX 100644
70
--- a/softmmu/qdev-monitor.c
71
+++ b/softmmu/qdev-monitor.c
72
@@ -XXX,XX +XXX,XX @@ static DeviceState *qbus_find_dev(BusState *bus, char *elem)
73
74
static inline bool qbus_is_full(BusState *bus)
75
{
76
- BusClass *bus_class = BUS_GET_CLASS(bus);
77
+ BusClass *bus_class;
78
+
33
+
79
+ if (bus->full) {
34
#define CSR_ID_REV 0x50
80
+ return true;
35
#define CSR_IRQ_CFG 0x54
81
+ }
36
#define CSR_INT_STS 0x58
82
+ bus_class = BUS_GET_CLASS(bus);
37
@@ -XXX,XX +XXX,XX @@ static void lan9118_writel(void *opaque, hwaddr offset,
83
return bus_class->max_dev && bus->num_children >= bus_class->max_dev;
38
offset &= 0xff;
84
}
39
85
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
}
56
switch (offset) {
57
- case 0x40:
58
+ case RX_STATUS_FIFO_PORT:
59
return rx_status_fifo_pop(s);
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;
86
--
71
--
87
2.20.1
72
2.20.1
88
73
89
74
diff view generated by jsdifflib
1
From: Shashi Mallela <shashi.mallela@linaro.org>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
Defined descriptors for ITS device table,collection table and ITS
3
This patch allows NPCM7XX CLK module to compute clocks that are used by
4
command queue entities.Implemented register read/write functions,
4
other NPCM7XX modules.
5
extract ITS table parameters and command queue parameters,extended
6
gicv3 common to capture qemu address space(which host the ITS table
7
platform memories required for subsequent ITS processing) and
8
initialize the same in ITS device.
9
5
10
Signed-off-by: Shashi Mallela <shashi.mallela@linaro.org>
6
Add a new struct NPCM7xxClockConverterState which represents a
7
single converter. Each clock converter in CLK module represents one
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>
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
23
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
12
Reviewed-by: Eric Auger <eric.auger@redhat.com>
24
Message-id: 20210108190945.949196-2-wuhaotsh@google.com
13
Tested-by: Neil Armstrong <narmstrong@baylibre.com>
14
Message-id: 20210910143951.92242-3-shashi.mallela@linaro.org
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
25
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
---
26
---
17
hw/intc/gicv3_internal.h | 29 ++
27
include/hw/misc/npcm7xx_clk.h | 140 +++++-
18
include/hw/intc/arm_gicv3_common.h | 3 +
28
hw/misc/npcm7xx_clk.c | 805 +++++++++++++++++++++++++++++++++-
19
include/hw/intc/arm_gicv3_its_common.h | 23 ++
29
2 files changed, 932 insertions(+), 13 deletions(-)
20
hw/intc/arm_gicv3_its.c | 376 +++++++++++++++++++++++++
21
4 files changed, 431 insertions(+)
22
30
23
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
31
diff --git a/include/hw/misc/npcm7xx_clk.h b/include/hw/misc/npcm7xx_clk.h
24
index XXXXXXX..XXXXXXX 100644
32
index XXXXXXX..XXXXXXX 100644
25
--- a/hw/intc/gicv3_internal.h
33
--- a/include/hw/misc/npcm7xx_clk.h
26
+++ b/hw/intc/gicv3_internal.h
34
+++ b/include/hw/misc/npcm7xx_clk.h
27
@@ -XXX,XX +XXX,XX @@ FIELD(GITS_BASER, INNERCACHE, 59, 3)
35
@@ -XXX,XX +XXX,XX @@
28
FIELD(GITS_BASER, INDIRECT, 62, 1)
36
#define NPCM7XX_CLK_H
29
FIELD(GITS_BASER, VALID, 63, 1)
37
30
38
#include "exec/memory.h"
31
+FIELD(GITS_CBASER, SIZE, 0, 8)
39
+#include "hw/clock.h"
32
+FIELD(GITS_CBASER, SHAREABILITY, 10, 2)
40
#include "hw/sysbus.h"
33
+FIELD(GITS_CBASER, PHYADDR, 12, 40)
41
34
+FIELD(GITS_CBASER, OUTERCACHE, 53, 3)
42
/*
35
+FIELD(GITS_CBASER, INNERCACHE, 59, 3)
43
@@ -XXX,XX +XXX,XX @@
36
+FIELD(GITS_CBASER, VALID, 63, 1)
44
37
+
45
#define NPCM7XX_WATCHDOG_RESET_GPIO_IN "npcm7xx-clk-watchdog-reset-gpio-in"
38
+FIELD(GITS_CREADR, STALLED, 0, 1)
46
39
+FIELD(GITS_CREADR, OFFSET, 5, 15)
47
-typedef struct NPCM7xxCLKState {
40
+
48
+/* Maximum amount of clock inputs in a SEL module. */
41
+FIELD(GITS_CWRITER, RETRY, 0, 1)
49
+#define NPCM7XX_CLK_SEL_MAX_INPUT 5
42
+FIELD(GITS_CWRITER, OFFSET, 5, 15)
50
+
43
+
51
+/* PLLs in CLK module. */
44
+FIELD(GITS_CTLR, ENABLED, 0, 1)
52
+typedef enum NPCM7xxClockPLL {
45
FIELD(GITS_CTLR, QUIESCENT, 31, 1)
53
+ NPCM7XX_CLOCK_PLL0,
46
54
+ NPCM7XX_CLOCK_PLL1,
47
FIELD(GITS_TYPER, PHYSICAL, 0, 1)
55
+ NPCM7XX_CLOCK_PLL2,
48
@@ -XXX,XX +XXX,XX @@ FIELD(GITS_TYPER, PTA, 19, 1)
56
+ NPCM7XX_CLOCK_PLLG,
49
FIELD(GITS_TYPER, CIDBITS, 32, 4)
57
+ NPCM7XX_CLOCK_NR_PLLS,
50
FIELD(GITS_TYPER, CIL, 36, 1)
58
+} NPCM7xxClockPLL;
51
59
+
52
+#define GITS_IDREGS 0xFFD0
60
+/* SEL/MUX in CLK module. */
53
+
61
+typedef enum NPCM7xxClockSEL {
54
+#define ITS_CTLR_ENABLED (1U) /* ITS Enabled */
62
+ NPCM7XX_CLOCK_PIXCKSEL,
55
+
63
+ NPCM7XX_CLOCK_MCCKSEL,
56
+#define GITS_BASER_RO_MASK (R_GITS_BASER_ENTRYSIZE_MASK | \
64
+ NPCM7XX_CLOCK_CPUCKSEL,
57
+ R_GITS_BASER_TYPE_MASK)
65
+ NPCM7XX_CLOCK_CLKOUTSEL,
58
+
66
+ NPCM7XX_CLOCK_UARTCKSEL,
59
#define GITS_BASER_PAGESIZE_4K 0
67
+ NPCM7XX_CLOCK_TIMCKSEL,
60
#define GITS_BASER_PAGESIZE_16K 1
68
+ NPCM7XX_CLOCK_SDCKSEL,
61
#define GITS_BASER_PAGESIZE_64K 2
69
+ NPCM7XX_CLOCK_GFXMSEL,
62
@@ -XXX,XX +XXX,XX @@ FIELD(GITS_TYPER, CIL, 36, 1)
70
+ NPCM7XX_CLOCK_SUCKSEL,
63
#define GITS_BASER_TYPE_DEVICE 1ULL
71
+ NPCM7XX_CLOCK_NR_SELS,
64
#define GITS_BASER_TYPE_COLLECTION 4ULL
72
+} NPCM7xxClockSEL;
65
73
+
66
+#define GITS_PAGE_SIZE_4K 0x1000
74
+/* Dividers in CLK module. */
67
+#define GITS_PAGE_SIZE_16K 0x4000
75
+typedef enum NPCM7xxClockDivider {
68
+#define GITS_PAGE_SIZE_64K 0x10000
76
+ NPCM7XX_CLOCK_PLL1D2, /* PLL1/2 */
69
+
77
+ NPCM7XX_CLOCK_PLL2D2, /* PLL2/2 */
70
+#define L1TABLE_ENTRY_SIZE 8
78
+ NPCM7XX_CLOCK_MC_DIVIDER,
71
+
79
+ NPCM7XX_CLOCK_AXI_DIVIDER,
72
+#define GITS_CMDQ_ENTRY_SIZE 32
80
+ NPCM7XX_CLOCK_AHB_DIVIDER,
73
+
81
+ NPCM7XX_CLOCK_AHB3_DIVIDER,
74
/**
82
+ NPCM7XX_CLOCK_SPI0_DIVIDER,
75
* Default features advertised by this version of ITS
83
+ NPCM7XX_CLOCK_SPIX_DIVIDER,
76
*/
84
+ NPCM7XX_CLOCK_APB1_DIVIDER,
77
diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
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
+
102
+/**
103
+ * struct NPCM7xxClockPLLState - A PLL module in CLK module.
104
+ * @name: The name of the module.
105
+ * @clk: The CLK module that owns this module.
106
+ * @clock_in: The input clock of this module.
107
+ * @clock_out: The output clock of this module.
108
+ * @reg: The control registers for this PLL module.
109
+ */
110
+typedef struct NPCM7xxClockPLLState {
111
+ DeviceState parent;
112
+
113
+ const char *name;
114
+ NPCM7xxCLKState *clk;
115
+ Clock *clock_in;
116
+ Clock *clock_out;
117
+
118
+ int reg;
119
+} NPCM7xxClockPLLState;
120
+
121
+/**
122
+ * struct NPCM7xxClockSELState - A SEL module in CLK module.
123
+ * @name: The name of the module.
124
+ * @clk: The CLK module that owns this module.
125
+ * @input_size: The size of inputs of this module.
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
+ */
131
+typedef struct NPCM7xxClockSELState {
132
+ DeviceState parent;
133
+
134
+ const char *name;
135
+ NPCM7xxCLKState *clk;
136
+ uint8_t input_size;
137
+ Clock *clock_in[NPCM7XX_CLK_SEL_MAX_INPUT];
138
+ Clock *clock_out;
139
+
140
+ int offset;
141
+ int len;
142
+} NPCM7xxClockSELState;
143
+
144
+/**
145
+ * struct NPCM7xxClockDividerState - A Divider module in CLK module.
146
+ * @name: The name of the module.
147
+ * @clk: The CLK module that owns this module.
148
+ * @clock_in: The input clock of this module.
149
+ * @clock_out: The output clock of this module.
150
+ * @divide: The function the divider uses to divide the input.
151
+ * @reg: The index of the control register that contains the divisor.
152
+ * @offset: The offset of the divisor in the control register.
153
+ * @len: The length of the divisor in the control register.
154
+ * @divisor: The divisor for a constant divisor
155
+ */
156
+typedef struct NPCM7xxClockDividerState {
157
+ DeviceState parent;
158
+
159
+ const char *name;
160
+ NPCM7xxCLKState *clk;
161
+ Clock *clock_in;
162
+ Clock *clock_out;
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
+ };
173
+} NPCM7xxClockDividerState;
174
+
175
+struct NPCM7xxCLKState {
176
SysBusDevice parent;
177
178
MemoryRegion iomem;
179
180
+ /* Clock converters */
181
+ NPCM7xxClockPLLState plls[NPCM7XX_CLOCK_NR_PLLS];
182
+ NPCM7xxClockSELState sels[NPCM7XX_CLOCK_NR_SELS];
183
+ NPCM7xxClockDividerState dividers[NPCM7XX_CLOCK_NR_DIVIDERS];
184
+
185
uint32_t regs[NPCM7XX_CLK_NR_REGS];
186
187
/* Time reference for SECCNT and CNTR25M, initialized by power on reset */
188
int64_t ref_ns;
189
-} NPCM7xxCLKState;
190
+
191
+ /* The incoming reference clock. */
192
+ Clock *clkref;
193
+};
194
195
#define TYPE_NPCM7XX_CLK "npcm7xx-clk"
196
#define NPCM7XX_CLK(obj) OBJECT_CHECK(NPCM7xxCLKState, (obj), TYPE_NPCM7XX_CLK)
197
diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
78
index XXXXXXX..XXXXXXX 100644
198
index XXXXXXX..XXXXXXX 100644
79
--- a/include/hw/intc/arm_gicv3_common.h
199
--- a/hw/misc/npcm7xx_clk.c
80
+++ b/include/hw/intc/arm_gicv3_common.h
200
+++ b/hw/misc/npcm7xx_clk.c
81
@@ -XXX,XX +XXX,XX @@ struct GICv3State {
82
int dev_fd; /* kvm device fd if backed by kvm vgic support */
83
Error *migration_blocker;
84
85
+ MemoryRegion *dma;
86
+ AddressSpace dma_as;
87
+
88
/* Distributor */
89
90
/* for a GIC with the security extensions the NS banked version of this
91
diff --git a/include/hw/intc/arm_gicv3_its_common.h b/include/hw/intc/arm_gicv3_its_common.h
92
index XXXXXXX..XXXXXXX 100644
93
--- a/include/hw/intc/arm_gicv3_its_common.h
94
+++ b/include/hw/intc/arm_gicv3_its_common.h
95
@@ -XXX,XX +XXX,XX @@
201
@@ -XXX,XX +XXX,XX @@
96
202
97
#define GITS_TRANSLATER 0x0040
203
#include "hw/misc/npcm7xx_clk.h"
98
204
#include "hw/timer/npcm7xx_timer.h"
99
+typedef struct {
205
+#include "hw/qdev-clock.h"
100
+ bool valid;
206
#include "migration/vmstate.h"
101
+ bool indirect;
207
#include "qemu/error-report.h"
102
+ uint16_t entry_sz;
208
#include "qemu/log.h"
103
+ uint32_t page_sz;
209
@@ -XXX,XX +XXX,XX @@
104
+ uint32_t max_entries;
210
#include "trace.h"
105
+ union {
211
#include "sysemu/watchdog.h"
106
+ uint32_t max_devids;
212
107
+ uint32_t max_collids;
213
+/*
108
+ } maxids;
214
+ * The reference clock hz, and the SECCNT and CNTR25M registers in this module,
109
+ uint64_t base_addr;
215
+ * is always 25 MHz.
110
+} TableDesc;
216
+ */
111
+
217
+#define NPCM7XX_CLOCK_REF_HZ (25000000)
112
+typedef struct {
218
+
113
+ bool valid;
219
+/* Register Field Definitions */
114
+ uint32_t max_entries;
220
+#define NPCM7XX_CLK_WDRCR_CA9C BIT(0) /* Cortex A9 Cores */
115
+ uint64_t base_addr;
221
+
116
+} CmdQDesc;
222
#define PLLCON_LOKI BIT(31)
117
+
223
#define PLLCON_LOKS BIT(30)
118
struct GICv3ITSState {
224
#define PLLCON_PWDEN BIT(12)
119
SysBusDevice parent_obj;
225
+#define PLLCON_FBDV(con) extract32((con), 16, 12)
120
226
+#define PLLCON_OTDV2(con) extract32((con), 13, 3)
121
@@ -XXX,XX +XXX,XX @@ struct GICv3ITSState {
227
+#define PLLCON_OTDV1(con) extract32((con), 8, 3)
122
uint64_t creadr;
228
+#define PLLCON_INDV(con) extract32((con), 0, 6)
123
uint64_t baser[8];
229
124
230
enum NPCM7xxCLKRegisters {
125
+ TableDesc dt;
231
NPCM7XX_CLK_CLKEN1,
126
+ TableDesc ct;
232
@@ -XXX,XX +XXX,XX @@ static const uint32_t cold_reset_values[NPCM7XX_CLK_NR_REGS] = {
127
+ CmdQDesc cq;
233
[NPCM7XX_CLK_AHBCKFI] = 0x000000c8,
128
+
129
Error *migration_blocker;
130
};
234
};
131
235
132
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
236
-/* Register Field Definitions */
133
index XXXXXXX..XXXXXXX 100644
237
-#define NPCM7XX_CLK_WDRCR_CA9C BIT(0) /* Cortex A9 Cores */
134
--- a/hw/intc/arm_gicv3_its.c
238
-
135
+++ b/hw/intc/arm_gicv3_its.c
239
/* The number of watchdogs that can trigger a reset. */
136
@@ -XXX,XX +XXX,XX @@ struct GICv3ITSClass {
240
#define NPCM7XX_NR_WATCHDOGS (3)
137
void (*parent_reset)(DeviceState *dev);
241
138
};
242
+/* Clock converter functions */
139
243
+
140
+static uint64_t baser_base_addr(uint64_t value, uint32_t page_sz)
244
+#define TYPE_NPCM7XX_CLOCK_PLL "npcm7xx-clock-pll"
141
+{
245
+#define NPCM7XX_CLOCK_PLL(obj) OBJECT_CHECK(NPCM7xxClockPLLState, \
142
+ uint64_t result = 0;
246
+ (obj), TYPE_NPCM7XX_CLOCK_PLL)
143
+
247
+#define TYPE_NPCM7XX_CLOCK_SEL "npcm7xx-clock-sel"
144
+ switch (page_sz) {
248
+#define NPCM7XX_CLOCK_SEL(obj) OBJECT_CHECK(NPCM7xxClockSELState, \
145
+ case GITS_PAGE_SIZE_4K:
249
+ (obj), TYPE_NPCM7XX_CLOCK_SEL)
146
+ case GITS_PAGE_SIZE_16K:
250
+#define TYPE_NPCM7XX_CLOCK_DIVIDER "npcm7xx-clock-divider"
147
+ result = FIELD_EX64(value, GITS_BASER, PHYADDR) << 12;
251
+#define NPCM7XX_CLOCK_DIVIDER(obj) OBJECT_CHECK(NPCM7xxClockDividerState, \
148
+ break;
252
+ (obj), TYPE_NPCM7XX_CLOCK_DIVIDER)
149
+
253
+
150
+ case GITS_PAGE_SIZE_64K:
254
+static void npcm7xx_clk_update_pll(void *opaque)
151
+ result = FIELD_EX64(value, GITS_BASER, PHYADDRL_64K) << 16;
255
+{
152
+ result |= FIELD_EX64(value, GITS_BASER, PHYADDRH_64K) << 48;
256
+ NPCM7xxClockPLLState *s = opaque;
153
+ break;
257
+ uint32_t con = s->clk->regs[s->reg];
154
+
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;
155
+ default:
329
+ default:
156
+ break;
330
+ g_assert_not_reached();
157
+ }
331
+ }
158
+ return result;
332
+}
159
+}
333
+
160
+
334
+static void npcm7xx_clk_update_all_plls(NPCM7xxCLKState *clk)
161
+/*
335
+{
162
+ * This function extracts the ITS Device and Collection table specific
336
+ int i;
163
+ * parameters (like base_addr, size etc) from GITS_BASER register.
337
+
164
+ * It is called during ITS enable and also during post_load migration
338
+ for (i = 0; i < NPCM7XX_CLOCK_NR_PLLS; ++i) {
165
+ */
339
+ npcm7xx_clk_update_pll(&clk->plls[i]);
166
+static void extract_table_params(GICv3ITSState *s)
340
+ }
167
+{
341
+}
168
+ uint16_t num_pages = 0;
342
+
169
+ uint8_t page_sz_type;
343
+static void npcm7xx_clk_update_all_sels(NPCM7xxCLKState *clk)
170
+ uint8_t type;
344
+{
171
+ uint32_t page_sz = 0;
345
+ int i;
172
+ uint64_t value;
346
+
173
+
347
+ for (i = 0; i < NPCM7XX_CLOCK_NR_SELS; ++i) {
174
+ for (int i = 0; i < 8; i++) {
348
+ npcm7xx_clk_update_sel(&clk->sels[i]);
175
+ value = s->baser[i];
349
+ }
176
+
350
+}
177
+ if (!value) {
351
+
178
+ continue;
352
+static void npcm7xx_clk_update_all_dividers(NPCM7xxCLKState *clk)
353
+{
354
+ int i;
355
+
356
+ for (i = 0; i < NPCM7XX_CLOCK_NR_DIVIDERS; ++i) {
357
+ npcm7xx_clk_update_divider(&clk->dividers[i]);
358
+ }
359
+}
360
+
361
+static void npcm7xx_clk_update_all_clocks(NPCM7xxCLKState *clk)
362
+{
363
+ clock_update_hz(clk->clkref, NPCM7XX_CLOCK_REF_HZ);
364
+ npcm7xx_clk_update_all_plls(clk);
365
+ npcm7xx_clk_update_all_sels(clk);
366
+ npcm7xx_clk_update_all_dividers(clk);
367
+}
368
+
369
+/* Types of clock sources. */
370
+typedef enum ClockSrcType {
371
+ CLKSRC_REF,
372
+ CLKSRC_PLL,
373
+ CLKSRC_SEL,
374
+ CLKSRC_DIV,
375
+} ClockSrcType;
376
+
377
+typedef struct PLLInitInfo {
378
+ const char *name;
379
+ ClockSrcType src_type;
380
+ int src_index;
381
+ int reg;
382
+ const char *public_name;
383
+} PLLInitInfo;
384
+
385
+typedef struct SELInitInfo {
386
+ const char *name;
387
+ uint8_t input_size;
388
+ ClockSrcType src_type[NPCM7XX_CLK_SEL_MAX_INPUT];
389
+ int src_index[NPCM7XX_CLK_SEL_MAX_INPUT];
390
+ int offset;
391
+ int len;
392
+ const char *public_name;
393
+} SELInitInfo;
394
+
395
+typedef struct DividerInitInfo {
396
+ const char *name;
397
+ ClockSrcType src_type;
398
+ int src_index;
399
+ uint32_t (*divide)(NPCM7xxClockDividerState *s);
400
+ int reg; /* not used when type == CONSTANT */
401
+ int offset; /* not used when type == CONSTANT */
402
+ int len; /* not used when type == CONSTANT */
403
+ int divisor; /* used only when type == CONSTANT */
404
+ const char *public_name;
405
+} DividerInitInfo;
406
+
407
+static const PLLInitInfo pll_init_info_list[] = {
408
+ [NPCM7XX_CLOCK_PLL0] = {
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);
179
+ }
833
+ }
180
+
834
+ }
181
+ page_sz_type = FIELD_EX64(value, GITS_BASER, PAGESIZE);
835
+ for (i = 0; i < NPCM7XX_CLOCK_NR_DIVIDERS; ++i) {
182
+
836
+ src = npcm7xx_get_clock(clk, divider_init_info_list[i].src_type,
183
+ switch (page_sz_type) {
837
+ divider_init_info_list[i].src_index);
184
+ case 0:
838
+ clock_set_source(clk->dividers[i].clock_in, src);
185
+ page_sz = GITS_PAGE_SIZE_4K;
839
+ }
186
+ break;
840
+}
187
+
841
+
188
+ case 1:
842
static uint64_t npcm7xx_clk_read(void *opaque, hwaddr offset, unsigned size)
189
+ page_sz = GITS_PAGE_SIZE_16K;
190
+ break;
191
+
192
+ case 2:
193
+ case 3:
194
+ page_sz = GITS_PAGE_SIZE_64K;
195
+ break;
196
+
197
+ default:
198
+ g_assert_not_reached();
199
+ }
200
+
201
+ num_pages = FIELD_EX64(value, GITS_BASER, SIZE) + 1;
202
+
203
+ type = FIELD_EX64(value, GITS_BASER, TYPE);
204
+
205
+ switch (type) {
206
+
207
+ case GITS_BASER_TYPE_DEVICE:
208
+ memset(&s->dt, 0 , sizeof(s->dt));
209
+ s->dt.valid = FIELD_EX64(value, GITS_BASER, VALID);
210
+
211
+ if (!s->dt.valid) {
212
+ return;
213
+ }
214
+
215
+ s->dt.page_sz = page_sz;
216
+ s->dt.indirect = FIELD_EX64(value, GITS_BASER, INDIRECT);
217
+ s->dt.entry_sz = FIELD_EX64(value, GITS_BASER, ENTRYSIZE);
218
+
219
+ if (!s->dt.indirect) {
220
+ s->dt.max_entries = (num_pages * page_sz) / s->dt.entry_sz;
221
+ } else {
222
+ s->dt.max_entries = (((num_pages * page_sz) /
223
+ L1TABLE_ENTRY_SIZE) *
224
+ (page_sz / s->dt.entry_sz));
225
+ }
226
+
227
+ s->dt.maxids.max_devids = (1UL << (FIELD_EX64(s->typer, GITS_TYPER,
228
+ DEVBITS) + 1));
229
+
230
+ s->dt.base_addr = baser_base_addr(value, page_sz);
231
+
232
+ break;
233
+
234
+ case GITS_BASER_TYPE_COLLECTION:
235
+ memset(&s->ct, 0 , sizeof(s->ct));
236
+ s->ct.valid = FIELD_EX64(value, GITS_BASER, VALID);
237
+
238
+ /*
239
+ * GITS_TYPER.HCC is 0 for this implementation
240
+ * hence writes are discarded if ct.valid is 0
241
+ */
242
+ if (!s->ct.valid) {
243
+ return;
244
+ }
245
+
246
+ s->ct.page_sz = page_sz;
247
+ s->ct.indirect = FIELD_EX64(value, GITS_BASER, INDIRECT);
248
+ s->ct.entry_sz = FIELD_EX64(value, GITS_BASER, ENTRYSIZE);
249
+
250
+ if (!s->ct.indirect) {
251
+ s->ct.max_entries = (num_pages * page_sz) / s->ct.entry_sz;
252
+ } else {
253
+ s->ct.max_entries = (((num_pages * page_sz) /
254
+ L1TABLE_ENTRY_SIZE) *
255
+ (page_sz / s->ct.entry_sz));
256
+ }
257
+
258
+ if (FIELD_EX64(s->typer, GITS_TYPER, CIL)) {
259
+ s->ct.maxids.max_collids = (1UL << (FIELD_EX64(s->typer,
260
+ GITS_TYPER, CIDBITS) + 1));
261
+ } else {
262
+ /* 16-bit CollectionId supported when CIL == 0 */
263
+ s->ct.maxids.max_collids = (1UL << 16);
264
+ }
265
+
266
+ s->ct.base_addr = baser_base_addr(value, page_sz);
267
+
268
+ break;
269
+
270
+ default:
271
+ break;
272
+ }
273
+ }
274
+}
275
+
276
+static void extract_cmdq_params(GICv3ITSState *s)
277
+{
278
+ uint16_t num_pages = 0;
279
+ uint64_t value = s->cbaser;
280
+
281
+ num_pages = FIELD_EX64(value, GITS_CBASER, SIZE) + 1;
282
+
283
+ memset(&s->cq, 0 , sizeof(s->cq));
284
+ s->cq.valid = FIELD_EX64(value, GITS_CBASER, VALID);
285
+
286
+ if (s->cq.valid) {
287
+ s->cq.max_entries = (num_pages * GITS_PAGE_SIZE_4K) /
288
+ GITS_CMDQ_ENTRY_SIZE;
289
+ s->cq.base_addr = FIELD_EX64(value, GITS_CBASER, PHYADDR);
290
+ s->cq.base_addr <<= R_GITS_CBASER_PHYADDR_SHIFT;
291
+ }
292
+}
293
+
294
static MemTxResult gicv3_its_translation_write(void *opaque, hwaddr offset,
295
uint64_t data, unsigned size,
296
MemTxAttrs attrs)
297
@@ -XXX,XX +XXX,XX @@ static bool its_writel(GICv3ITSState *s, hwaddr offset,
298
uint64_t value, MemTxAttrs attrs)
299
{
843
{
300
bool result = true;
844
uint32_t reg = offset / sizeof(uint32_t);
301
+ int index;
845
@@ -XXX,XX +XXX,XX @@ static uint64_t npcm7xx_clk_read(void *opaque, hwaddr offset, unsigned size)
302
846
*
303
+ switch (offset) {
847
* The 4 LSBs are always zero: (1e9 / 640) << 4 = 25000000.
304
+ case GITS_CTLR:
848
*/
305
+ s->ctlr |= (value & ~(s->ctlr));
849
- value = (((now_ns - s->ref_ns) / 640) << 4) % NPCM7XX_TIMER_REF_HZ;
306
+
850
+ value = (((now_ns - s->ref_ns) / 640) << 4) % NPCM7XX_CLOCK_REF_HZ;
307
+ if (s->ctlr & ITS_CTLR_ENABLED) {
851
break;
308
+ extract_table_params(s);
852
309
+ extract_cmdq_params(s);
853
default:
310
+ s->creadr = 0;
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)]);
311
+ }
861
+ }
312
+ break;
862
+ break;
313
+ case GITS_CBASER:
863
+
314
+ /*
864
+ case NPCM7XX_CLK_CLKSEL:
315
+ * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
865
+ npcm7xx_clk_update_all_sels(s);
316
+ * already enabled
866
+ break;
317
+ */
867
+
318
+ if (!(s->ctlr & ITS_CTLR_ENABLED)) {
868
+ case NPCM7XX_CLK_CLKDIV1:
319
+ s->cbaser = deposit64(s->cbaser, 0, 32, value);
869
+ case NPCM7XX_CLK_CLKDIV2:
320
+ s->creadr = 0;
870
+ case NPCM7XX_CLK_CLKDIV3:
321
+ s->cwriter = s->creadr;
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
}
886
887
+static void npcm7xx_clk_init_clock_hierarchy(NPCM7xxCLKState *s)
888
+{
889
+ int i;
890
+
891
+ s->clkref = qdev_init_clock_in(DEVICE(s), "clkref", NULL, NULL);
892
+
893
+ /* First pass: init all converter modules */
894
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(pll_init_info_list) != NPCM7XX_CLOCK_NR_PLLS);
895
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(sel_init_info_list) != NPCM7XX_CLOCK_NR_SELS);
896
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(divider_init_info_list)
897
+ != NPCM7XX_CLOCK_NR_DIVIDERS);
898
+ for (i = 0; i < NPCM7XX_CLOCK_NR_PLLS; ++i) {
899
+ object_initialize_child(OBJECT(s), pll_init_info_list[i].name,
900
+ &s->plls[i], TYPE_NPCM7XX_CLOCK_PLL);
901
+ npcm7xx_init_clock_pll(&s->plls[i], s,
902
+ &pll_init_info_list[i]);
903
+ }
904
+ for (i = 0; i < NPCM7XX_CLOCK_NR_SELS; ++i) {
905
+ object_initialize_child(OBJECT(s), sel_init_info_list[i].name,
906
+ &s->sels[i], TYPE_NPCM7XX_CLOCK_SEL);
907
+ npcm7xx_init_clock_sel(&s->sels[i], s,
908
+ &sel_init_info_list[i]);
909
+ }
910
+ for (i = 0; i < NPCM7XX_CLOCK_NR_DIVIDERS; ++i) {
911
+ object_initialize_child(OBJECT(s), divider_init_info_list[i].name,
912
+ &s->dividers[i], TYPE_NPCM7XX_CLOCK_DIVIDER);
913
+ npcm7xx_init_clock_divider(&s->dividers[i], s,
914
+ &divider_init_info_list[i]);
915
+ }
916
+
917
+ /* Second pass: connect converter modules */
918
+ npcm7xx_connect_clocks(s);
919
+
920
+ clock_update_hz(s->clkref, NPCM7XX_CLOCK_REF_HZ);
921
+}
922
+
923
static void npcm7xx_clk_init(Object *obj)
924
{
925
NPCM7xxCLKState *s = NPCM7XX_CLK(obj);
926
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_init(Object *obj)
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
}
933
934
-static const VMStateDescription vmstate_npcm7xx_clk = {
935
- .name = "npcm7xx-clk",
936
+static int npcm7xx_clk_post_load(void *opaque, int version_id)
937
+{
938
+ if (version_id >= 1) {
939
+ NPCM7xxCLKState *clk = opaque;
940
+
941
+ npcm7xx_clk_update_all_clocks(clk);
942
+ }
943
+
944
+ return 0;
945
+}
946
+
947
+static void npcm7xx_clk_realize(DeviceState *dev, Error **errp)
948
+{
949
+ int i;
950
+ NPCM7xxCLKState *s = NPCM7XX_CLK(dev);
951
+
952
+ qdev_init_gpio_in_named(DEVICE(s), npcm7xx_clk_perform_watchdog_reset,
953
+ NPCM7XX_WATCHDOG_RESET_GPIO_IN, NPCM7XX_NR_WATCHDOGS);
954
+ npcm7xx_clk_init_clock_hierarchy(s);
955
+
956
+ /* Realize child devices */
957
+ for (i = 0; i < NPCM7XX_CLOCK_NR_PLLS; ++i) {
958
+ if (!qdev_realize(DEVICE(&s->plls[i]), NULL, errp)) {
959
+ return;
322
+ }
960
+ }
323
+ break;
961
+ }
324
+ case GITS_CBASER + 4:
962
+ for (i = 0; i < NPCM7XX_CLOCK_NR_SELS; ++i) {
325
+ /*
963
+ if (!qdev_realize(DEVICE(&s->sels[i]), NULL, errp)) {
326
+ * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
964
+ return;
327
+ * already enabled
328
+ */
329
+ if (!(s->ctlr & ITS_CTLR_ENABLED)) {
330
+ s->cbaser = deposit64(s->cbaser, 32, 32, value);
331
+ s->creadr = 0;
332
+ s->cwriter = s->creadr;
333
+ }
965
+ }
334
+ break;
966
+ }
335
+ case GITS_CWRITER:
967
+ for (i = 0; i < NPCM7XX_CLOCK_NR_DIVIDERS; ++i) {
336
+ s->cwriter = deposit64(s->cwriter, 0, 32,
968
+ if (!qdev_realize(DEVICE(&s->dividers[i]), NULL, errp)) {
337
+ (value & ~R_GITS_CWRITER_RETRY_MASK));
969
+ return;
338
+ break;
339
+ case GITS_CWRITER + 4:
340
+ s->cwriter = deposit64(s->cwriter, 32, 32, value);
341
+ break;
342
+ case GITS_CREADR:
343
+ if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) {
344
+ s->creadr = deposit64(s->creadr, 0, 32,
345
+ (value & ~R_GITS_CREADR_STALLED_MASK));
346
+ } else {
347
+ /* RO register, ignore the write */
348
+ qemu_log_mask(LOG_GUEST_ERROR,
349
+ "%s: invalid guest write to RO register at offset "
350
+ TARGET_FMT_plx "\n", __func__, offset);
351
+ }
970
+ }
352
+ break;
971
+ }
353
+ case GITS_CREADR + 4:
972
+}
354
+ if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) {
973
+
355
+ s->creadr = deposit64(s->creadr, 32, 32, value);
974
+static const VMStateDescription vmstate_npcm7xx_clk_pll = {
356
+ } else {
975
+ .name = "npcm7xx-clock-pll",
357
+ /* RO register, ignore the write */
976
.version_id = 0,
358
+ qemu_log_mask(LOG_GUEST_ERROR,
977
.minimum_version_id = 0,
359
+ "%s: invalid guest write to RO register at offset "
978
- .fields = (VMStateField[]) {
360
+ TARGET_FMT_plx "\n", __func__, offset);
979
- VMSTATE_UINT32_ARRAY(regs, NPCM7xxCLKState, NPCM7XX_CLK_NR_REGS),
361
+ }
980
- VMSTATE_INT64(ref_ns, NPCM7xxCLKState),
362
+ break;
981
+ .fields = (VMStateField[]) {
363
+ case GITS_BASER ... GITS_BASER + 0x3f:
982
+ VMSTATE_CLOCK(clock_in, NPCM7xxClockPLLState),
364
+ /*
983
VMSTATE_END_OF_LIST(),
365
+ * IMPDEF choice:- GITS_BASERn register becomes RO if ITS is
984
},
366
+ * already enabled
985
};
367
+ */
986
368
+ if (!(s->ctlr & ITS_CTLR_ENABLED)) {
987
+static const VMStateDescription vmstate_npcm7xx_clk_sel = {
369
+ index = (offset - GITS_BASER) / 8;
988
+ .name = "npcm7xx-clock-sel",
370
+
989
+ .version_id = 0,
371
+ if (offset & 7) {
990
+ .minimum_version_id = 0,
372
+ value <<= 32;
991
+ .fields = (VMStateField[]) {
373
+ value &= ~GITS_BASER_RO_MASK;
992
+ VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(clock_in, NPCM7xxClockSELState,
374
+ s->baser[index] &= GITS_BASER_RO_MASK | MAKE_64BIT_MASK(0, 32);
993
+ NPCM7XX_CLK_SEL_MAX_INPUT, 0, vmstate_clock, Clock),
375
+ s->baser[index] |= value;
994
+ VMSTATE_END_OF_LIST(),
376
+ } else {
995
+ },
377
+ value &= ~GITS_BASER_RO_MASK;
996
+};
378
+ s->baser[index] &= GITS_BASER_RO_MASK | MAKE_64BIT_MASK(32, 32);
997
+
379
+ s->baser[index] |= value;
998
+static const VMStateDescription vmstate_npcm7xx_clk_divider = {
380
+ }
999
+ .name = "npcm7xx-clock-divider",
381
+ }
1000
+ .version_id = 0,
382
+ break;
1001
+ .minimum_version_id = 0,
383
+ case GITS_IIDR:
1002
+ .fields = (VMStateField[]) {
384
+ case GITS_IDREGS ... GITS_IDREGS + 0x2f:
1003
+ VMSTATE_CLOCK(clock_in, NPCM7xxClockDividerState),
385
+ /* RO registers, ignore the write */
1004
+ VMSTATE_END_OF_LIST(),
386
+ qemu_log_mask(LOG_GUEST_ERROR,
1005
+ },
387
+ "%s: invalid guest write to RO register at offset "
1006
+};
388
+ TARGET_FMT_plx "\n", __func__, offset);
1007
+
389
+ break;
1008
+static const VMStateDescription vmstate_npcm7xx_clk = {
390
+ default:
1009
+ .name = "npcm7xx-clk",
391
+ result = false;
1010
+ .version_id = 1,
392
+ break;
1011
+ .minimum_version_id = 1,
393
+ }
1012
+ .post_load = npcm7xx_clk_post_load,
394
return result;
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
{
1047
ResettableClass *rc = RESETTABLE_CLASS(klass);
1048
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_class_init(ObjectClass *klass, void *data)
1049
1050
dc->desc = "NPCM7xx Clock Control Registers";
1051
dc->vmsd = &vmstate_npcm7xx_clk;
1052
+ dc->realize = npcm7xx_clk_realize;
1053
rc->phases.enter = npcm7xx_clk_enter_reset;
395
}
1054
}
396
1055
397
@@ -XXX,XX +XXX,XX @@ static bool its_readl(GICv3ITSState *s, hwaddr offset,
1056
+static const TypeInfo npcm7xx_clk_pll_info = {
398
uint64_t *data, MemTxAttrs attrs)
1057
+ .name = TYPE_NPCM7XX_CLOCK_PLL,
1058
+ .parent = TYPE_DEVICE,
1059
+ .instance_size = sizeof(NPCM7xxClockPLLState),
1060
+ .instance_init = npcm7xx_clk_pll_init,
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)
399
{
1086
{
400
bool result = true;
1087
+ type_register_static(&npcm7xx_clk_pll_info);
401
+ int index;
1088
+ type_register_static(&npcm7xx_clk_sel_info);
402
1089
+ type_register_static(&npcm7xx_clk_divider_info);
403
+ switch (offset) {
1090
type_register_static(&npcm7xx_clk_info);
404
+ case GITS_CTLR:
405
+ *data = s->ctlr;
406
+ break;
407
+ case GITS_IIDR:
408
+ *data = gicv3_iidr();
409
+ break;
410
+ case GITS_IDREGS ... GITS_IDREGS + 0x2f:
411
+ /* ID registers */
412
+ *data = gicv3_idreg(offset - GITS_IDREGS);
413
+ break;
414
+ case GITS_TYPER:
415
+ *data = extract64(s->typer, 0, 32);
416
+ break;
417
+ case GITS_TYPER + 4:
418
+ *data = extract64(s->typer, 32, 32);
419
+ break;
420
+ case GITS_CBASER:
421
+ *data = extract64(s->cbaser, 0, 32);
422
+ break;
423
+ case GITS_CBASER + 4:
424
+ *data = extract64(s->cbaser, 32, 32);
425
+ break;
426
+ case GITS_CREADR:
427
+ *data = extract64(s->creadr, 0, 32);
428
+ break;
429
+ case GITS_CREADR + 4:
430
+ *data = extract64(s->creadr, 32, 32);
431
+ break;
432
+ case GITS_CWRITER:
433
+ *data = extract64(s->cwriter, 0, 32);
434
+ break;
435
+ case GITS_CWRITER + 4:
436
+ *data = extract64(s->cwriter, 32, 32);
437
+ break;
438
+ case GITS_BASER ... GITS_BASER + 0x3f:
439
+ index = (offset - GITS_BASER) / 8;
440
+ if (offset & 7) {
441
+ *data = extract64(s->baser[index], 32, 32);
442
+ } else {
443
+ *data = extract64(s->baser[index], 0, 32);
444
+ }
445
+ break;
446
+ default:
447
+ result = false;
448
+ break;
449
+ }
450
return result;
451
}
1091
}
452
1092
type_init(npcm7xx_clk_register_type);
453
@@ -XXX,XX +XXX,XX @@ static bool its_writell(GICv3ITSState *s, hwaddr offset,
454
uint64_t value, MemTxAttrs attrs)
455
{
456
bool result = true;
457
+ int index;
458
459
+ switch (offset) {
460
+ case GITS_BASER ... GITS_BASER + 0x3f:
461
+ /*
462
+ * IMPDEF choice:- GITS_BASERn register becomes RO if ITS is
463
+ * already enabled
464
+ */
465
+ if (!(s->ctlr & ITS_CTLR_ENABLED)) {
466
+ index = (offset - GITS_BASER) / 8;
467
+ s->baser[index] &= GITS_BASER_RO_MASK;
468
+ s->baser[index] |= (value & ~GITS_BASER_RO_MASK);
469
+ }
470
+ break;
471
+ case GITS_CBASER:
472
+ /*
473
+ * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
474
+ * already enabled
475
+ */
476
+ if (!(s->ctlr & ITS_CTLR_ENABLED)) {
477
+ s->cbaser = value;
478
+ s->creadr = 0;
479
+ s->cwriter = s->creadr;
480
+ }
481
+ break;
482
+ case GITS_CWRITER:
483
+ s->cwriter = value & ~R_GITS_CWRITER_RETRY_MASK;
484
+ break;
485
+ case GITS_CREADR:
486
+ if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) {
487
+ s->creadr = value & ~R_GITS_CREADR_STALLED_MASK;
488
+ } else {
489
+ /* RO register, ignore the write */
490
+ qemu_log_mask(LOG_GUEST_ERROR,
491
+ "%s: invalid guest write to RO register at offset "
492
+ TARGET_FMT_plx "\n", __func__, offset);
493
+ }
494
+ break;
495
+ case GITS_TYPER:
496
+ /* RO registers, ignore the write */
497
+ qemu_log_mask(LOG_GUEST_ERROR,
498
+ "%s: invalid guest write to RO register at offset "
499
+ TARGET_FMT_plx "\n", __func__, offset);
500
+ break;
501
+ default:
502
+ result = false;
503
+ break;
504
+ }
505
return result;
506
}
507
508
@@ -XXX,XX +XXX,XX @@ static bool its_readll(GICv3ITSState *s, hwaddr offset,
509
uint64_t *data, MemTxAttrs attrs)
510
{
511
bool result = true;
512
+ int index;
513
514
+ switch (offset) {
515
+ case GITS_TYPER:
516
+ *data = s->typer;
517
+ break;
518
+ case GITS_BASER ... GITS_BASER + 0x3f:
519
+ index = (offset - GITS_BASER) / 8;
520
+ *data = s->baser[index];
521
+ break;
522
+ case GITS_CBASER:
523
+ *data = s->cbaser;
524
+ break;
525
+ case GITS_CREADR:
526
+ *data = s->creadr;
527
+ break;
528
+ case GITS_CWRITER:
529
+ *data = s->cwriter;
530
+ break;
531
+ default:
532
+ result = false;
533
+ break;
534
+ }
535
return result;
536
}
537
538
@@ -XXX,XX +XXX,XX @@ static void gicv3_arm_its_realize(DeviceState *dev, Error **errp)
539
540
gicv3_its_init_mmio(s, &gicv3_its_control_ops, &gicv3_its_translation_ops);
541
542
+ address_space_init(&s->gicv3->dma_as, s->gicv3->dma,
543
+ "gicv3-its-sysmem");
544
+
545
/* set the ITS default features supported */
546
s->typer = FIELD_DP64(s->typer, GITS_TYPER, PHYSICAL,
547
GITS_TYPE_PHYSICAL);
548
@@ -XXX,XX +XXX,XX @@ static void gicv3_its_reset(DeviceState *dev)
549
GITS_CTE_SIZE - 1);
550
}
551
552
+static void gicv3_its_post_load(GICv3ITSState *s)
553
+{
554
+ if (s->ctlr & ITS_CTLR_ENABLED) {
555
+ extract_table_params(s);
556
+ extract_cmdq_params(s);
557
+ }
558
+}
559
+
560
static Property gicv3_its_props[] = {
561
DEFINE_PROP_LINK("parent-gicv3", GICv3ITSState, gicv3, "arm-gicv3",
562
GICv3State *),
563
@@ -XXX,XX +XXX,XX @@ static void gicv3_its_class_init(ObjectClass *klass, void *data)
564
{
565
DeviceClass *dc = DEVICE_CLASS(klass);
566
GICv3ITSClass *ic = ARM_GICV3_ITS_CLASS(klass);
567
+ GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass);
568
569
dc->realize = gicv3_arm_its_realize;
570
device_class_set_props(dc, gicv3_its_props);
571
device_class_set_parent_reset(dc, gicv3_its_reset, &ic->parent_reset);
572
+ icc->post_load = gicv3_its_post_load;
573
}
574
575
static const TypeInfo gicv3_its_info = {
576
--
1093
--
577
2.20.1
1094
2.20.1
578
1095
579
1096
diff view generated by jsdifflib
1
From: Bin Meng <bmeng.cn@gmail.com>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
This converts uart_read() and uart_write() to memop_with_attrs() ops.
3
This patch makes NPCM7XX Timer to use a the timer clock generated by the
4
CLK module instead of the magic number TIMER_REF_HZ.
4
5
5
Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
6
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
6
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
7
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
7
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
8
Signed-off-by: Hao Wu <wuhaotsh@google.com>
8
Message-id: 20210901124521.30599-5-bmeng.cn@gmail.com
9
Message-id: 20210108190945.949196-3-wuhaotsh@google.com
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
12
---
11
hw/char/cadence_uart.c | 26 +++++++++++++++-----------
13
include/hw/misc/npcm7xx_clk.h | 6 -----
12
1 file changed, 15 insertions(+), 11 deletions(-)
14
include/hw/timer/npcm7xx_timer.h | 1 +
15
hw/arm/npcm7xx.c | 5 ++++
16
hw/timer/npcm7xx_timer.c | 39 +++++++++++++++-----------------
17
4 files changed, 24 insertions(+), 27 deletions(-)
13
18
14
diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
19
diff --git a/include/hw/misc/npcm7xx_clk.h b/include/hw/misc/npcm7xx_clk.h
15
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/char/cadence_uart.c
21
--- a/include/hw/misc/npcm7xx_clk.h
17
+++ b/hw/char/cadence_uart.c
22
+++ b/include/hw/misc/npcm7xx_clk.h
18
@@ -XXX,XX +XXX,XX @@ static void uart_read_rx_fifo(CadenceUARTState *s, uint32_t *c)
23
@@ -XXX,XX +XXX,XX @@
19
uart_update_status(s);
24
#include "hw/clock.h"
25
#include "hw/sysbus.h"
26
27
-/*
28
- * The reference clock frequency for the timer modules, and the SECCNT and
29
- * CNTR25M registers in this module, is always 25 MHz.
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);
20
}
98
}
21
99
22
-static void uart_write(void *opaque, hwaddr offset,
100
/* Convert a time interval in nanoseconds to a timer cycle count. */
23
- uint64_t value, unsigned size)
101
static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns)
24
+static MemTxResult uart_write(void *opaque, hwaddr offset,
25
+ uint64_t value, unsigned size, MemTxAttrs attrs)
26
{
102
{
27
CadenceUARTState *s = opaque;
103
- int64_t count;
28
104
-
29
DB_PRINT(" offset:%x data:%08x\n", (unsigned)offset, (unsigned)value);
105
- count = ns / (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ);
30
offset >>= 2;
106
- count /= npcm7xx_tcsr_prescaler(t->tcsr);
31
if (offset >= CADENCE_UART_R_MAX) {
107
-
32
- return;
108
- return count;
33
+ return MEMTX_DECODE_ERROR;
109
+ return ns / clock_ticks_to_ns(t->ctrl->clock,
34
}
110
+ npcm7xx_tcsr_prescaler(t->tcsr));
35
switch (offset) {
36
case R_IER: /* ier (wts imr) */
37
@@ -XXX,XX +XXX,XX @@ static void uart_write(void *opaque, hwaddr offset,
38
break;
39
}
40
uart_update_status(s);
41
+
42
+ return MEMTX_OK;
43
}
111
}
44
112
45
-static uint64_t uart_read(void *opaque, hwaddr offset,
113
static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t)
46
- unsigned size)
114
@@ -XXX,XX +XXX,XX @@ static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t)
47
+static MemTxResult uart_read(void *opaque, hwaddr offset,
115
static void npcm7xx_watchdog_timer_reset_cycles(NPCM7xxWatchdogTimer *t,
48
+ uint64_t *value, unsigned size, MemTxAttrs attrs)
116
int64_t cycles)
49
{
117
{
50
CadenceUARTState *s = opaque;
118
- uint32_t prescaler = npcm7xx_watchdog_timer_prescaler(t);
51
uint32_t c = 0;
119
- int64_t ns = (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ) * cycles;
52
120
+ int64_t ticks = cycles * npcm7xx_watchdog_timer_prescaler(t);
53
offset >>= 2;
121
+ int64_t ns = clock_ticks_to_ns(t->ctrl->clock, ticks);
54
if (offset >= CADENCE_UART_R_MAX) {
122
55
- c = 0;
123
/*
56
- } else if (offset == R_TX_RX) {
124
* The reset function always clears the current timer. The caller of the
57
+ return MEMTX_DECODE_ERROR;
125
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_watchdog_timer_reset_cycles(NPCM7xxWatchdogTimer *t,
58
+ }
126
*/
59
+ if (offset == R_TX_RX) {
127
npcm7xx_timer_clear(&t->base_timer);
60
uart_read_rx_fifo(s, &c);
128
61
} else {
129
- ns *= prescaler;
62
- c = s->r[offset];
130
t->base_timer.remaining_ns = ns;
63
+ c = s->r[offset];
64
}
65
66
DB_PRINT(" offset:%x data:%08x\n", (unsigned)(offset << 2), (unsigned)c);
67
- return c;
68
+ *value = c;
69
+ return MEMTX_OK;
70
}
131
}
71
132
72
static const MemoryRegionOps uart_ops = {
133
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_hold_reset(Object *obj)
73
- .read = uart_read,
134
qemu_irq_lower(s->watchdog_timer.irq);
74
- .write = uart_write,
135
}
75
+ .read_with_attrs = uart_read,
136
76
+ .write_with_attrs = uart_write,
137
-static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
77
.endianness = DEVICE_NATIVE_ENDIAN,
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,
78
};
189
};
79
190
191
static void npcm7xx_timer_register_type(void)
80
--
192
--
81
2.20.1
193
2.20.1
82
194
83
195
diff view generated by jsdifflib
1
From: Chris Rauer <crauer@google.com>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
kudo-bmc is a board supported by OpenBMC.
3
The ADC is part of NPCM7XX Module. Its behavior is controled by the
4
https://github.com/openbmc/openbmc/tree/master/meta-fii/meta-kudo
4
ADC_CON register. It converts one of the eight analog inputs into a
5
digital input and stores it in the ADC_DATA register when enabled.
5
6
6
Since v1:
7
Users can alter input value by using qom-set QMP command.
7
- hyphenated Cortex-A9
8
8
9
Tested: Booted kudo firmware.
9
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
10
Signed-off-by: Chris Rauer <crauer@google.com>
10
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
11
Reviewed-by: Patrick Venture <venture@google.com>
11
Signed-off-by: Hao Wu <wuhaotsh@google.com>
12
Message-id: 20210907223234.1165705-1-crauer@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>
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
---
16
---
15
docs/system/arm/nuvoton.rst | 1 +
17
docs/system/arm/nuvoton.rst | 2 +-
16
hw/arm/npcm7xx_boards.c | 34 ++++++++++++++++++++++++++++++++++
18
meson.build | 1 +
17
2 files changed, 35 insertions(+)
19
hw/adc/trace.h | 1 +
20
include/hw/adc/npcm7xx_adc.h | 69 ++++++
21
include/hw/arm/npcm7xx.h | 2 +
22
hw/adc/npcm7xx_adc.c | 301 ++++++++++++++++++++++++++
23
hw/arm/npcm7xx.c | 24 ++-
24
tests/qtest/npcm7xx_adc-test.c | 377 +++++++++++++++++++++++++++++++++
25
hw/adc/meson.build | 1 +
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
18
34
19
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
35
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
20
index XXXXXXX..XXXXXXX 100644
36
index XXXXXXX..XXXXXXX 100644
21
--- a/docs/system/arm/nuvoton.rst
37
--- a/docs/system/arm/nuvoton.rst
22
+++ b/docs/system/arm/nuvoton.rst
38
+++ b/docs/system/arm/nuvoton.rst
23
@@ -XXX,XX +XXX,XX @@ Hyperscale applications. The following machines are based on this chip :
39
@@ -XXX,XX +XXX,XX @@ Supported devices
24
40
* Random Number Generator (RNG)
25
- ``quanta-gbs-bmc`` Quanta GBS server BMC
41
* USB host (USBH)
26
- ``quanta-gsj`` Quanta GSJ server BMC
42
* GPIO controller
27
+- ``kudo-bmc`` Fii USA Kudo server BMC
43
+ * Analog to Digital Converter (ADC)
28
44
29
There are also two more SoCs, NPCM710 and NPCM705, which are single-core
45
Missing devices
30
variants of NPCM750 and NPCM730, respectively. These are currently not
46
---------------
31
diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c
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
32
index XXXXXXX..XXXXXXX 100644
56
index XXXXXXX..XXXXXXX 100644
33
--- a/hw/arm/npcm7xx_boards.c
57
--- a/meson.build
34
+++ b/hw/arm/npcm7xx_boards.c
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
69
index XXXXXXX..XXXXXXX
70
--- /dev/null
71
+++ b/hw/adc/trace.h
72
@@ -0,0 +1 @@
73
+#include "trace/trace-hw_adc.h"
74
diff --git a/include/hw/adc/npcm7xx_adc.h b/include/hw/adc/npcm7xx_adc.h
75
new file mode 100644
76
index XXXXXXX..XXXXXXX
77
--- /dev/null
78
+++ b/include/hw/adc/npcm7xx_adc.h
35
@@ -XXX,XX +XXX,XX @@
79
@@ -XXX,XX +XXX,XX @@
36
#define NPCM750_EVB_POWER_ON_STRAPS 0x00001ff7
80
+/*
37
#define QUANTA_GSJ_POWER_ON_STRAPS 0x00001fff
81
+ * Nuvoton NPCM7xx ADC Module
38
#define QUANTA_GBS_POWER_ON_STRAPS 0x000017ff
82
+ *
39
+#define KUDO_BMC_POWER_ON_STRAPS 0x00001fff
83
+ * Copyright 2020 Google LLC
40
84
+ *
41
static const char npcm7xx_default_bootrom[] = "npcm7xx_bootrom.bin";
85
+ * This program is free software; you can redistribute it and/or modify it
42
86
+ * under the terms of the GNU General Public License as published by the
43
@@ -XXX,XX +XXX,XX @@ static void quanta_gbs_init(MachineState *machine)
87
+ * Free Software Foundation; either version 2 of the License, or
44
npcm7xx_load_kernel(machine, soc);
88
+ * (at your option) any later version.
89
+ *
90
+ * This program is distributed in the hope that it will be useful, but WITHOUT
91
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
92
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
93
+ * for more details.
94
+ */
95
+#ifndef NPCM7XX_ADC_H
96
+#define NPCM7XX_ADC_H
97
+
98
+#include "hw/clock.h"
99
+#include "hw/irq.h"
100
+#include "hw/sysbus.h"
101
+#include "qemu/timer.h"
102
+
103
+#define NPCM7XX_ADC_NUM_INPUTS 8
104
+/**
105
+ * This value should not be changed unless write_adc_calibration function in
106
+ * hw/arm/npcm7xx.c is also changed.
107
+ */
108
+#define NPCM7XX_ADC_NUM_CALIB 2
109
+
110
+/**
111
+ * struct NPCM7xxADCState - Analog to Digital Converter Module device state.
112
+ * @parent: System bus device.
113
+ * @iomem: Memory region through which registers are accessed.
114
+ * @conv_timer: The timer counts down remaining cycles for the conversion.
115
+ * @irq: GIC interrupt line to fire on expiration (if enabled).
116
+ * @con: The Control Register.
117
+ * @data: The Data Buffer.
118
+ * @clock: The ADC Clock.
119
+ * @adci: The input voltage in units of uV. 1uv = 1e-6V.
120
+ * @vref: The external reference voltage.
121
+ * @iref: The internal reference voltage, initialized at launch time.
122
+ * @rv: The calibrated output values of 0.5V and 1.5V for the ADC.
123
+ */
124
+typedef struct {
125
+ SysBusDevice parent;
126
+
127
+ MemoryRegion iomem;
128
+
129
+ QEMUTimer conv_timer;
130
+
131
+ qemu_irq irq;
132
+ uint32_t con;
133
+ uint32_t data;
134
+ Clock *clock;
135
+
136
+ /* Voltages are in unit of uV. 1V = 1000000uV. */
137
+ uint32_t adci[NPCM7XX_ADC_NUM_INPUTS];
138
+ uint32_t vref;
139
+ uint32_t iref;
140
+
141
+ uint16_t calibration_r_values[NPCM7XX_ADC_NUM_CALIB];
142
+} NPCM7xxADCState;
143
+
144
+#define TYPE_NPCM7XX_ADC "npcm7xx-adc"
145
+#define NPCM7XX_ADC(obj) \
146
+ OBJECT_CHECK(NPCM7xxADCState, (obj), TYPE_NPCM7XX_ADC)
147
+
148
+#endif /* NPCM7XX_ADC_H */
149
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
150
index XXXXXXX..XXXXXXX 100644
151
--- a/include/hw/arm/npcm7xx.h
152
+++ b/include/hw/arm/npcm7xx.h
153
@@ -XXX,XX +XXX,XX @@
154
#define NPCM7XX_H
155
156
#include "hw/boards.h"
157
+#include "hw/adc/npcm7xx_adc.h"
158
#include "hw/cpu/a9mpcore.h"
159
#include "hw/gpio/npcm7xx_gpio.h"
160
#include "hw/mem/npcm7xx_mc.h"
161
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
162
NPCM7xxGCRState gcr;
163
NPCM7xxCLKState clk;
164
NPCM7xxTimerCtrlState tim[3];
165
+ NPCM7xxADCState adc;
166
NPCM7xxOTPState key_storage;
167
NPCM7xxOTPState fuse_array;
168
NPCM7xxMCState mc;
169
diff --git a/hw/adc/npcm7xx_adc.c b/hw/adc/npcm7xx_adc.c
170
new file mode 100644
171
index XXXXXXX..XXXXXXX
172
--- /dev/null
173
+++ b/hw/adc/npcm7xx_adc.c
174
@@ -XXX,XX +XXX,XX @@
175
+/*
176
+ * Nuvoton NPCM7xx ADC Module
177
+ *
178
+ * Copyright 2020 Google LLC
179
+ *
180
+ * This program is free software; you can redistribute it and/or modify it
181
+ * under the terms of the GNU General Public License as published by the
182
+ * Free Software Foundation; either version 2 of the License, or
183
+ * (at your option) any later version.
184
+ *
185
+ * This program is distributed in the hope that it will be useful, but WITHOUT
186
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
187
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
188
+ * for more details.
189
+ */
190
+
191
+#include "qemu/osdep.h"
192
+#include "hw/adc/npcm7xx_adc.h"
193
+#include "hw/qdev-clock.h"
194
+#include "hw/qdev-properties.h"
195
+#include "hw/registerfields.h"
196
+#include "migration/vmstate.h"
197
+#include "qemu/log.h"
198
+#include "qemu/module.h"
199
+#include "qemu/timer.h"
200
+#include "qemu/units.h"
201
+#include "trace.h"
202
+
203
+REG32(NPCM7XX_ADC_CON, 0x0)
204
+REG32(NPCM7XX_ADC_DATA, 0x4)
205
+
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
+{
225
+ timer_del(&s->conv_timer);
226
+ s->con = 0x000c0001;
227
+ s->data = 0x00000000;
228
+}
229
+
230
+static uint32_t npcm7xx_adc_convert(uint32_t input, uint32_t ref)
231
+{
232
+ uint32_t result;
233
+
234
+ result = input * (NPCM7XX_ADC_MAX_RESULT + 1) / ref;
235
+ if (result > NPCM7XX_ADC_MAX_RESULT) {
236
+ result = NPCM7XX_ADC_MAX_RESULT;
237
+ }
238
+
239
+ return result;
240
+}
241
+
242
+static uint32_t npcm7xx_adc_prescaler(NPCM7xxADCState *s)
243
+{
244
+ return 2 * (NPCM7XX_ADC_CON_DIV(s->con) + 1);
245
+}
246
+
247
+static void npcm7xx_adc_start_timer(Clock *clk, QEMUTimer *timer,
248
+ uint32_t cycles, uint32_t prescaler)
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
478
--- a/hw/arm/npcm7xx.c
479
+++ b/hw/arm/npcm7xx.c
480
@@ -XXX,XX +XXX,XX @@
481
#define NPCM7XX_EHCI_BA (0xf0806000)
482
#define NPCM7XX_OHCI_BA (0xf0807000)
483
484
+/* ADC Module */
485
+#define NPCM7XX_ADC_BA (0xf000c000)
486
+
487
/* Internal AHB SRAM */
488
#define NPCM7XX_RAM3_BA (0xc0008000)
489
#define NPCM7XX_RAM3_SZ (4 * KiB)
490
@@ -XXX,XX +XXX,XX @@
491
#define NPCM7XX_ROM_BA (0xffff0000)
492
#define NPCM7XX_ROM_SZ (64 * KiB)
493
494
+
495
/* Clock configuration values to be fixed up when bypassing bootloader */
496
497
/* Run PLL1 at 1600 MHz */
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));
45
}
508
}
46
509
47
+static void kudo_bmc_init(MachineState *machine)
510
+static void npcm7xx_write_adc_calibration(NPCM7xxState *s)
48
+{
511
+{
49
+ NPCM7xxState *soc;
512
+ /* Both ADC and the fuse array must have realized. */
50
+
513
+ QEMU_BUILD_BUG_ON(sizeof(s->adc.calibration_r_values) != 4);
51
+ soc = npcm7xx_create_soc(machine, KUDO_BMC_POWER_ON_STRAPS);
514
+ npcm7xx_otp_array_write(&s->fuse_array, s->adc.calibration_r_values,
52
+ npcm7xx_connect_dram(soc, machine->ram);
515
+ NPCM7XX_FUSE_ADC_CALIB, sizeof(s->adc.calibration_r_values));
53
+ qdev_realize(DEVICE(soc), NULL, &error_fatal);
516
+}
54
+
517
+
55
+ npcm7xx_load_bootrom(machine, soc);
518
static qemu_irq npcm7xx_irq(NPCM7xxState *s, int n)
56
+ npcm7xx_connect_flash(&soc->fiu[0], 0, "mx66u51235f",
57
+ drive_get(IF_MTD, 0, 0));
58
+ npcm7xx_connect_flash(&soc->fiu[1], 0, "mx66u51235f",
59
+ drive_get(IF_MTD, 3, 0));
60
+
61
+ npcm7xx_load_kernel(machine, soc);
62
+}
63
+
64
static void npcm7xx_set_soc_type(NPCM7xxMachineClass *nmc, const char *type)
65
{
519
{
66
NPCM7xxClass *sc = NPCM7XX_CLASS(object_class_by_name(type));
520
return qdev_get_gpio_in(DEVICE(&s->a9mpcore), n);
67
@@ -XXX,XX +XXX,XX @@ static void gbs_bmc_machine_class_init(ObjectClass *oc, void *data)
521
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
68
mc->default_ram_size = 1 * GiB;
522
TYPE_NPCM7XX_FUSE_ARRAY);
69
}
523
object_initialize_child(obj, "mc", &s->mc, TYPE_NPCM7XX_MC);
70
524
object_initialize_child(obj, "rng", &s->rng, TYPE_NPCM7XX_RNG);
71
+static void kudo_bmc_machine_class_init(ObjectClass *oc, void *data)
525
+ object_initialize_child(obj, "adc", &s->adc, TYPE_NPCM7XX_ADC);
72
+{
526
73
+ NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc);
527
for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
74
+ MachineClass *mc = MACHINE_CLASS(oc);
528
object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
75
+
529
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
76
+ npcm7xx_set_soc_type(nmc, TYPE_NPCM730);
530
sysbus_realize(SYS_BUS_DEVICE(&s->mc), &error_abort);
77
+
531
sysbus_mmio_map(SYS_BUS_DEVICE(&s->mc), 0, NPCM7XX_MC_BA);
78
+ mc->desc = "Kudo BMC (Cortex-A9)";
532
79
+ mc->init = kudo_bmc_init;
533
+ /* ADC Modules. Cannot fail. */
80
+ mc->default_ram_size = 1 * GiB;
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,
81
+};
628
+};
82
+
629
+
83
static const TypeInfo npcm7xx_machine_types[] = {
630
+static const uint32_t vref_list[] = {
84
{
631
+ 2000000,
85
.name = TYPE_NPCM7XX_MACHINE,
632
+ 2200000,
86
@@ -XXX,XX +XXX,XX @@ static const TypeInfo npcm7xx_machine_types[] = {
633
+ 2500000,
87
.name = MACHINE_TYPE_NAME("quanta-gbs-bmc"),
634
+};
88
.parent = TYPE_NPCM7XX_MACHINE,
635
+
89
.class_init = gbs_bmc_machine_class_init,
636
+static const uint32_t iref_list[] = {
90
+ }, {
637
+ 1800000,
91
+ .name = MACHINE_TYPE_NAME("kudo-bmc"),
638
+ 1900000,
92
+ .parent = TYPE_NPCM7XX_MACHINE,
639
+ 2000000,
93
+ .class_init = kudo_bmc_machine_class_init,
640
+ 2100000,
94
},
641
+ 2200000,
95
};
642
+};
96
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
938
--- a/hw/adc/meson.build
939
+++ b/hw/adc/meson.build
940
@@ -1 +1,2 @@
941
softmmu_ss.add(when: 'CONFIG_STM32F2XX_ADC', if_true: files('stm32f2xx_adc.c'))
942
+softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_adc.c'))
943
diff --git a/hw/adc/trace-events b/hw/adc/trace-events
944
new file mode 100644
945
index XXXXXXX..XXXXXXX
946
--- /dev/null
947
+++ b/hw/adc/trace-events
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']
97
--
968
--
98
2.20.1
969
2.20.1
99
970
100
971
diff view generated by jsdifflib
1
From: Shashi Mallela <shashi.mallela@linaro.org>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
Added ITS command queue handling for MAPTI,MAPI commands,handled ITS
3
The PWM module is part of NPCM7XX module. Each NPCM7XX module has two
4
translation which triggers an LPI via INT command as well as write
4
identical PWM modules. Each module contains 4 PWM entries. Each PWM has
5
to GITS_TRANSLATER register,defined enum to differentiate between ITS
5
two outputs: frequency and duty_cycle. Both are computed using inputs
6
command interrupt trigger and GITS_TRANSLATER based interrupt trigger.
6
from software side.
7
Each of these commands make use of other functionalities implemented to
8
get device table entry,collection table entry or interrupt translation
9
table entry required for their processing.
10
7
11
Signed-off-by: Shashi Mallela <shashi.mallela@linaro.org>
8
This module does not model detail pulse signals since it is expensive.
9
It also does not model interrupts and watchdogs that are dependant on
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
12
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
20
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
13
Message-id: 20210910143951.92242-5-shashi.mallela@linaro.org
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
---
22
---
16
hw/intc/gicv3_internal.h | 12 +
23
docs/system/arm/nuvoton.rst | 2 +-
17
include/hw/intc/arm_gicv3_common.h | 2 +
24
include/hw/arm/npcm7xx.h | 2 +
18
hw/intc/arm_gicv3_its.c | 365 ++++++++++++++++++++++++++++-
25
include/hw/misc/npcm7xx_pwm.h | 105 +++++++
19
3 files changed, 378 insertions(+), 1 deletion(-)
26
hw/arm/npcm7xx.c | 26 +-
27
hw/misc/npcm7xx_pwm.c | 550 ++++++++++++++++++++++++++++++++++
28
hw/misc/meson.build | 1 +
29
hw/misc/trace-events | 6 +
30
7 files changed, 689 insertions(+), 3 deletions(-)
31
create mode 100644 include/hw/misc/npcm7xx_pwm.h
32
create mode 100644 hw/misc/npcm7xx_pwm.c
20
33
21
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
34
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
22
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
23
--- a/hw/intc/gicv3_internal.h
36
--- a/docs/system/arm/nuvoton.rst
24
+++ b/hw/intc/gicv3_internal.h
37
+++ b/docs/system/arm/nuvoton.rst
25
@@ -XXX,XX +XXX,XX @@ FIELD(MAPC, RDBASE, 16, 32)
38
@@ -XXX,XX +XXX,XX @@ Supported devices
26
#define ITTADDR_MASK MAKE_64BIT_MASK(ITTADDR_SHIFT, ITTADDR_LENGTH)
39
* USB host (USBH)
27
#define SIZE_MASK 0x1f
40
* GPIO controller
28
41
* Analog to Digital Converter (ADC)
29
+/* MAPI command fields */
42
+ * Pulse Width Modulation (PWM)
30
+#define EVENTID_MASK ((1ULL << 32) - 1)
43
31
+
44
Missing devices
32
+/* MAPTI command fields */
45
---------------
33
+#define pINTID_SHIFT 32
46
@@ -XXX,XX +XXX,XX @@ Missing devices
34
+#define pINTID_MASK MAKE_64BIT_MASK(32, 32)
47
* Peripheral SPI controller (PSPI)
35
+
48
* SD/MMC host
36
#define DEVID_SHIFT 32
49
* PECI interface
37
#define DEVID_MASK MAKE_64BIT_MASK(32, 32)
50
- * Pulse Width Modulation (PWM)
38
51
* Tachometer
39
@@ -XXX,XX +XXX,XX @@ FIELD(MAPC, RDBASE, 16, 32)
52
* PCI and PCIe root complex and bridges
40
* Values: | vPEID | ICID |
53
* VDM and MCTP support
41
*/
54
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
42
#define ITS_ITT_ENTRY_SIZE 0xC
43
+#define ITE_ENTRY_INTTYPE_SHIFT 1
44
+#define ITE_ENTRY_INTID_SHIFT 2
45
+#define ITE_ENTRY_INTID_MASK MAKE_64BIT_MASK(2, 24)
46
+#define ITE_ENTRY_INTSP_SHIFT 26
47
+#define ITE_ENTRY_ICID_MASK MAKE_64BIT_MASK(0, 16)
48
49
/* 16 bits EventId */
50
#define ITS_IDBITS GICD_TYPER_IDBITS
51
diff --git a/include/hw/intc/arm_gicv3_common.h b/include/hw/intc/arm_gicv3_common.h
52
index XXXXXXX..XXXXXXX 100644
55
index XXXXXXX..XXXXXXX 100644
53
--- a/include/hw/intc/arm_gicv3_common.h
56
--- a/include/hw/arm/npcm7xx.h
54
+++ b/include/hw/intc/arm_gicv3_common.h
57
+++ b/include/hw/arm/npcm7xx.h
55
@@ -XXX,XX +XXX,XX @@
58
@@ -XXX,XX +XXX,XX @@
56
#define GICV3_MAXIRQ 1020
59
#include "hw/mem/npcm7xx_mc.h"
57
#define GICV3_MAXSPI (GICV3_MAXIRQ - GIC_INTERNAL)
60
#include "hw/misc/npcm7xx_clk.h"
58
61
#include "hw/misc/npcm7xx_gcr.h"
59
+#define GICV3_LPI_INTID_START 8192
62
+#include "hw/misc/npcm7xx_pwm.h"
60
+
63
#include "hw/misc/npcm7xx_rng.h"
61
#define GICV3_REDIST_SIZE 0x20000
64
#include "hw/nvram/npcm7xx_otp.h"
62
65
#include "hw/timer/npcm7xx_timer.h"
63
/* Number of SGI target-list bits */
66
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
64
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
67
NPCM7xxCLKState clk;
68
NPCM7xxTimerCtrlState tim[3];
69
NPCM7xxADCState adc;
70
+ NPCM7xxPWMState pwm[2];
71
NPCM7xxOTPState key_storage;
72
NPCM7xxOTPState fuse_array;
73
NPCM7xxMCState mc;
74
diff --git a/include/hw/misc/npcm7xx_pwm.h b/include/hw/misc/npcm7xx_pwm.h
75
new file mode 100644
76
index XXXXXXX..XXXXXXX
77
--- /dev/null
78
+++ b/include/hw/misc/npcm7xx_pwm.h
79
@@ -XXX,XX +XXX,XX @@
80
+/*
81
+ * Nuvoton NPCM7xx PWM Module
82
+ *
83
+ * Copyright 2020 Google LLC
84
+ *
85
+ * This program is free software; you can redistribute it and/or modify it
86
+ * under the terms of the GNU General Public License as published by the
87
+ * Free Software Foundation; either version 2 of the License, or
88
+ * (at your option) any later version.
89
+ *
90
+ * This program is distributed in the hope that it will be useful, but WITHOUT
91
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
92
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
93
+ * for more details.
94
+ */
95
+#ifndef NPCM7XX_PWM_H
96
+#define NPCM7XX_PWM_H
97
+
98
+#include "hw/clock.h"
99
+#include "hw/sysbus.h"
100
+#include "hw/irq.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
+
120
+/**
121
+ * struct NPCM7xxPWM - The state of a single PWM channel.
122
+ * @module: The PWM module that contains this channel.
123
+ * @irq: GIC interrupt line to fire on expiration if enabled.
124
+ * @running: Whether this PWM channel is generating output.
125
+ * @inverted: Whether this PWM channel is inverted.
126
+ * @index: The index of this PWM channel.
127
+ * @cnr: The counter register.
128
+ * @cmr: The comparator register.
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
+
153
+/**
154
+ * struct NPCM7xxPWMState - Pulse Width Modulation device state.
155
+ * @parent: System bus device.
156
+ * @iomem: Memory region through which registers are accessed.
157
+ * @clock: The PWM clock.
158
+ * @pwm: The PWM channels owned by this module.
159
+ * @ppr: The prescaler register.
160
+ * @csr: The clock selector register.
161
+ * @pcr: The control register.
162
+ * @pier: The interrupt enable register.
163
+ * @piir: The interrupt indication register.
164
+ */
165
+struct NPCM7xxPWMState {
166
+ SysBusDevice parent;
167
+
168
+ MemoryRegion iomem;
169
+
170
+ Clock *clock;
171
+ NPCM7xxPWM pwm[NPCM7XX_PWM_PER_MODULE];
172
+
173
+ uint32_t ppr;
174
+ uint32_t csr;
175
+ uint32_t pcr;
176
+ uint32_t pier;
177
+ uint32_t piir;
178
+};
179
+
180
+#define TYPE_NPCM7XX_PWM "npcm7xx-pwm"
181
+#define NPCM7XX_PWM(obj) \
182
+ OBJECT_CHECK(NPCM7xxPWMState, (obj), TYPE_NPCM7XX_PWM)
183
+
184
+#endif /* NPCM7XX_PWM_H */
185
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
65
index XXXXXXX..XXXXXXX 100644
186
index XXXXXXX..XXXXXXX 100644
66
--- a/hw/intc/arm_gicv3_its.c
187
--- a/hw/arm/npcm7xx.c
67
+++ b/hw/intc/arm_gicv3_its.c
188
+++ b/hw/arm/npcm7xx.c
68
@@ -XXX,XX +XXX,XX @@ struct GICv3ITSClass {
189
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxInterrupt {
69
void (*parent_reset)(DeviceState *dev);
190
NPCM7XX_WDG2_IRQ, /* Timer Module 2 Watchdog */
191
NPCM7XX_EHCI_IRQ = 61,
192
NPCM7XX_OHCI_IRQ = 62,
193
+ NPCM7XX_PWM0_IRQ = 93, /* PWM module 0 */
194
+ NPCM7XX_PWM1_IRQ, /* PWM module 1 */
195
NPCM7XX_GPIO0_IRQ = 116,
196
NPCM7XX_GPIO1_IRQ,
197
NPCM7XX_GPIO2_IRQ,
198
@@ -XXX,XX +XXX,XX @@ static const hwaddr npcm7xx_fiu3_flash_addr[] = {
199
0xb8000000, /* CS3 */
70
};
200
};
71
201
202
+/* Register base address for each PWM Module */
203
+static const hwaddr npcm7xx_pwm_addr[] = {
204
+ 0xf0103000,
205
+ 0xf0104000,
206
+};
207
+
208
static const struct {
209
hwaddr regs_addr;
210
uint32_t unconnected_pins;
211
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
212
object_initialize_child(obj, npcm7xx_fiu[i].name, &s->fiu[i],
213
TYPE_NPCM7XX_FIU);
214
}
215
+
216
+ for (i = 0; i < ARRAY_SIZE(s->pwm); i++) {
217
+ object_initialize_child(obj, "pwm[*]", &s->pwm[i], TYPE_NPCM7XX_PWM);
218
+ }
219
}
220
221
static void npcm7xx_realize(DeviceState *dev, Error **errp)
222
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
223
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ohci), 0,
224
npcm7xx_irq(s, NPCM7XX_OHCI_IRQ));
225
226
+ /* PWM Modules. Cannot fail. */
227
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_pwm_addr) != ARRAY_SIZE(s->pwm));
228
+ for (i = 0; i < ARRAY_SIZE(s->pwm); i++) {
229
+ SysBusDevice *sbd = SYS_BUS_DEVICE(&s->pwm[i]);
230
+
231
+ qdev_connect_clock_in(DEVICE(&s->pwm[i]), "clock", qdev_get_clock_out(
232
+ DEVICE(&s->clk), "apb3-clock"));
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
252
index XXXXXXX..XXXXXXX
253
--- /dev/null
254
+++ b/hw/misc/npcm7xx_pwm.c
255
@@ -XXX,XX +XXX,XX @@
72
+/*
256
+/*
73
+ * This is an internal enum used to distinguish between LPI triggered
257
+ * Nuvoton NPCM7xx PWM Module
74
+ * via command queue and LPI triggered via gits_translater write.
258
+ *
259
+ * Copyright 2020 Google LLC
260
+ *
261
+ * This program is free software; you can redistribute it and/or modify it
262
+ * under the terms of the GNU General Public License as published by the
263
+ * Free Software Foundation; either version 2 of the License, or
264
+ * (at your option) any later version.
265
+ *
266
+ * This program is distributed in the hope that it will be useful, but WITHOUT
267
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
268
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
269
+ * for more details.
75
+ */
270
+ */
76
+typedef enum ItsCmdType {
271
+
77
+ NONE = 0, /* internal indication for GITS_TRANSLATER write */
272
+#include "qemu/osdep.h"
78
+ CLEAR = 1,
273
+#include "hw/irq.h"
79
+ DISCARD = 2,
274
+#include "hw/qdev-clock.h"
80
+ INT = 3,
275
+#include "hw/qdev-properties.h"
81
+} ItsCmdType;
276
+#include "hw/misc/npcm7xx_pwm.h"
82
+
277
+#include "hw/registerfields.h"
83
+typedef struct {
278
+#include "migration/vmstate.h"
84
+ uint32_t iteh;
279
+#include "qemu/bitops.h"
85
+ uint64_t itel;
280
+#include "qemu/error-report.h"
86
+} IteEntry;
281
+#include "qemu/log.h"
87
+
282
+#include "qemu/module.h"
88
static uint64_t baser_base_addr(uint64_t value, uint32_t page_sz)
283
+#include "qemu/units.h"
89
{
284
+#include "trace.h"
90
uint64_t result = 0;
285
+
91
@@ -XXX,XX +XXX,XX @@ static uint64_t baser_base_addr(uint64_t value, uint32_t page_sz)
286
+REG32(NPCM7XX_PWM_PPR, 0x00);
92
return result;
287
+REG32(NPCM7XX_PWM_CSR, 0x04);
93
}
288
+REG32(NPCM7XX_PWM_PCR, 0x08);
94
289
+REG32(NPCM7XX_PWM_CNR0, 0x0c);
95
+static bool get_cte(GICv3ITSState *s, uint16_t icid, uint64_t *cte,
290
+REG32(NPCM7XX_PWM_CMR0, 0x10);
96
+ MemTxResult *res)
291
+REG32(NPCM7XX_PWM_PDR0, 0x14);
97
+{
292
+REG32(NPCM7XX_PWM_CNR1, 0x18);
98
+ AddressSpace *as = &s->gicv3->dma_as;
293
+REG32(NPCM7XX_PWM_CMR1, 0x1c);
99
+ uint64_t l2t_addr;
294
+REG32(NPCM7XX_PWM_PDR1, 0x20);
100
+ uint64_t value;
295
+REG32(NPCM7XX_PWM_CNR2, 0x24);
101
+ bool valid_l2t;
296
+REG32(NPCM7XX_PWM_CMR2, 0x28);
102
+ uint32_t l2t_id;
297
+REG32(NPCM7XX_PWM_PDR2, 0x2c);
103
+ uint32_t max_l2_entries;
298
+REG32(NPCM7XX_PWM_CNR3, 0x30);
104
+
299
+REG32(NPCM7XX_PWM_CMR3, 0x34);
105
+ if (s->ct.indirect) {
300
+REG32(NPCM7XX_PWM_PDR3, 0x38);
106
+ l2t_id = icid / (s->ct.page_sz / L1TABLE_ENTRY_SIZE);
301
+REG32(NPCM7XX_PWM_PIER, 0x3c);
107
+
302
+REG32(NPCM7XX_PWM_PIIR, 0x40);
108
+ value = address_space_ldq_le(as,
303
+REG32(NPCM7XX_PWM_PWDR0, 0x44);
109
+ s->ct.base_addr +
304
+REG32(NPCM7XX_PWM_PWDR1, 0x48);
110
+ (l2t_id * L1TABLE_ENTRY_SIZE),
305
+REG32(NPCM7XX_PWM_PWDR2, 0x4c);
111
+ MEMTXATTRS_UNSPECIFIED, res);
306
+REG32(NPCM7XX_PWM_PWDR3, 0x50);
112
+
307
+
113
+ if (*res == MEMTX_OK) {
308
+/* Register field definitions. */
114
+ valid_l2t = (value & L2_TABLE_VALID_MASK) != 0;
309
+#define NPCM7XX_PPR(rv, index) extract32((rv), npcm7xx_ppr_base[index], 8)
115
+
310
+#define NPCM7XX_CSR(rv, index) extract32((rv), npcm7xx_csr_base[index], 3)
116
+ if (valid_l2t) {
311
+#define NPCM7XX_CH(rv, index) extract32((rv), npcm7xx_ch_base[index], 4)
117
+ max_l2_entries = s->ct.page_sz / s->ct.entry_sz;
312
+#define NPCM7XX_CH_EN BIT(0)
118
+
313
+#define NPCM7XX_CH_INV BIT(2)
119
+ l2t_addr = value & ((1ULL << 51) - 1);
314
+#define NPCM7XX_CH_MOD BIT(3)
120
+
315
+
121
+ *cte = address_space_ldq_le(as, l2t_addr +
316
+/* Offset of each PWM channel's prescaler in the PPR register. */
122
+ ((icid % max_l2_entries) * GITS_CTE_SIZE),
317
+static const int npcm7xx_ppr_base[] = { 0, 0, 8, 8 };
123
+ MEMTXATTRS_UNSPECIFIED, res);
318
+/* Offset of each PWM channel's clock selector in the CSR register. */
124
+ }
319
+static const int npcm7xx_csr_base[] = { 0, 4, 8, 12 };
125
+ }
320
+/* Offset of each PWM channel's control variable in the PCR register. */
126
+ } else {
321
+static const int npcm7xx_ch_base[] = { 0, 8, 12, 16 };
127
+ /* Flat level table */
322
+
128
+ *cte = address_space_ldq_le(as, s->ct.base_addr +
323
+static uint32_t npcm7xx_pwm_calculate_freq(NPCM7xxPWM *p)
129
+ (icid * GITS_CTE_SIZE),
324
+{
130
+ MEMTXATTRS_UNSPECIFIED, res);
325
+ uint32_t ppr;
131
+ }
326
+ uint32_t csr;
132
+
327
+ uint32_t freq;
133
+ return (*cte & TABLE_ENTRY_VALID_MASK) != 0;
328
+
134
+}
329
+ if (!p->running) {
135
+
330
+ return 0;
136
+static bool update_ite(GICv3ITSState *s, uint32_t eventid, uint64_t dte,
331
+ }
137
+ IteEntry ite)
332
+
138
+{
333
+ csr = NPCM7XX_CSR(p->module->csr, p->index);
139
+ AddressSpace *as = &s->gicv3->dma_as;
334
+ ppr = NPCM7XX_PPR(p->module->ppr, p->index);
140
+ uint64_t itt_addr;
335
+ freq = clock_get_hz(p->module->clock);
141
+ MemTxResult res = MEMTX_OK;
336
+ freq /= ppr + 1;
142
+
337
+ /* csr can only be 0~4 */
143
+ itt_addr = (dte & GITS_DTE_ITTADDR_MASK) >> GITS_DTE_ITTADDR_SHIFT;
338
+ if (csr > 4) {
144
+ itt_addr <<= ITTADDR_SHIFT; /* 256 byte aligned */
339
+ qemu_log_mask(LOG_GUEST_ERROR,
145
+
340
+ "%s: invalid csr value %u\n",
146
+ address_space_stq_le(as, itt_addr + (eventid * (sizeof(uint64_t) +
341
+ __func__, csr);
147
+ sizeof(uint32_t))), ite.itel, MEMTXATTRS_UNSPECIFIED,
342
+ csr = 4;
148
+ &res);
343
+ }
149
+
344
+ /* freq won't be changed if csr == 4. */
150
+ if (res == MEMTX_OK) {
345
+ if (csr < 4) {
151
+ address_space_stl_le(as, itt_addr + (eventid * (sizeof(uint64_t) +
346
+ freq >>= csr + 1;
152
+ sizeof(uint32_t))) + sizeof(uint32_t), ite.iteh,
347
+ }
153
+ MEMTXATTRS_UNSPECIFIED, &res);
348
+
154
+ }
349
+ return freq / (p->cnr + 1);
155
+ if (res != MEMTX_OK) {
350
+}
156
+ return false;
351
+
157
+ } else {
352
+static uint32_t npcm7xx_pwm_calculate_duty(NPCM7xxPWM *p)
158
+ return true;
353
+{
159
+ }
354
+ uint64_t duty;
160
+}
355
+
161
+
356
+ if (p->running) {
162
+static bool get_ite(GICv3ITSState *s, uint32_t eventid, uint64_t dte,
357
+ if (p->cnr == 0) {
163
+ uint16_t *icid, uint32_t *pIntid, MemTxResult *res)
358
+ duty = 0;
164
+{
359
+ } else if (p->cmr >= p->cnr) {
165
+ AddressSpace *as = &s->gicv3->dma_as;
360
+ duty = NPCM7XX_PWM_MAX_DUTY;
166
+ uint64_t itt_addr;
361
+ } else {
167
+ bool status = false;
362
+ duty = NPCM7XX_PWM_MAX_DUTY * (p->cmr + 1) / (p->cnr + 1);
168
+ IteEntry ite = {};
169
+
170
+ itt_addr = (dte & GITS_DTE_ITTADDR_MASK) >> GITS_DTE_ITTADDR_SHIFT;
171
+ itt_addr <<= ITTADDR_SHIFT; /* 256 byte aligned */
172
+
173
+ ite.itel = address_space_ldq_le(as, itt_addr +
174
+ (eventid * (sizeof(uint64_t) +
175
+ sizeof(uint32_t))), MEMTXATTRS_UNSPECIFIED,
176
+ res);
177
+
178
+ if (*res == MEMTX_OK) {
179
+ ite.iteh = address_space_ldl_le(as, itt_addr +
180
+ (eventid * (sizeof(uint64_t) +
181
+ sizeof(uint32_t))) + sizeof(uint32_t),
182
+ MEMTXATTRS_UNSPECIFIED, res);
183
+
184
+ if (*res == MEMTX_OK) {
185
+ if (ite.itel & TABLE_ENTRY_VALID_MASK) {
186
+ if ((ite.itel >> ITE_ENTRY_INTTYPE_SHIFT) &
187
+ GITS_TYPE_PHYSICAL) {
188
+ *pIntid = (ite.itel & ITE_ENTRY_INTID_MASK) >>
189
+ ITE_ENTRY_INTID_SHIFT;
190
+ *icid = ite.iteh & ITE_ENTRY_ICID_MASK;
191
+ status = true;
192
+ }
193
+ }
194
+ }
195
+ }
196
+ return status;
197
+}
198
+
199
+static uint64_t get_dte(GICv3ITSState *s, uint32_t devid, MemTxResult *res)
200
+{
201
+ AddressSpace *as = &s->gicv3->dma_as;
202
+ uint64_t l2t_addr;
203
+ uint64_t value;
204
+ bool valid_l2t;
205
+ uint32_t l2t_id;
206
+ uint32_t max_l2_entries;
207
+
208
+ if (s->dt.indirect) {
209
+ l2t_id = devid / (s->dt.page_sz / L1TABLE_ENTRY_SIZE);
210
+
211
+ value = address_space_ldq_le(as,
212
+ s->dt.base_addr +
213
+ (l2t_id * L1TABLE_ENTRY_SIZE),
214
+ MEMTXATTRS_UNSPECIFIED, res);
215
+
216
+ if (*res == MEMTX_OK) {
217
+ valid_l2t = (value & L2_TABLE_VALID_MASK) != 0;
218
+
219
+ if (valid_l2t) {
220
+ max_l2_entries = s->dt.page_sz / s->dt.entry_sz;
221
+
222
+ l2t_addr = value & ((1ULL << 51) - 1);
223
+
224
+ value = address_space_ldq_le(as, l2t_addr +
225
+ ((devid % max_l2_entries) * GITS_DTE_SIZE),
226
+ MEMTXATTRS_UNSPECIFIED, res);
227
+ }
228
+ }
363
+ }
229
+ } else {
364
+ } else {
230
+ /* Flat level table */
365
+ duty = 0;
231
+ value = address_space_ldq_le(as, s->dt.base_addr +
366
+ }
232
+ (devid * GITS_DTE_SIZE),
367
+
233
+ MEMTXATTRS_UNSPECIFIED, res);
368
+ if (p->inverted) {
234
+ }
369
+ duty = NPCM7XX_PWM_MAX_DUTY - duty;
235
+
370
+ }
371
+
372
+ return duty;
373
+}
374
+
375
+static void npcm7xx_pwm_update_freq(NPCM7xxPWM *p)
376
+{
377
+ uint32_t freq = npcm7xx_pwm_calculate_freq(p);
378
+
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);
236
+ return value;
598
+ return value;
237
+}
599
+}
238
+
600
+
239
+/*
601
+static void npcm7xx_pwm_write(void *opaque, hwaddr offset,
240
+ * This function handles the processing of following commands based on
602
+ uint64_t v, unsigned size)
241
+ * the ItsCmdType parameter passed:-
603
+{
242
+ * 1. triggering of lpi interrupt translation via ITS INT command
604
+ NPCM7xxPWMState *s = opaque;
243
+ * 2. triggering of lpi interrupt translation via gits_translater register
605
+ NPCM7xxPWM *p;
244
+ * 3. handling of ITS CLEAR command
606
+ uint32_t value = v;
245
+ * 4. handling of ITS DISCARD command
607
+
246
+ */
608
+ trace_npcm7xx_pwm_write(DEVICE(s)->canonical_path, offset, value);
247
+static bool process_its_cmd(GICv3ITSState *s, uint64_t value, uint32_t offset,
609
+ switch (offset) {
248
+ ItsCmdType cmd)
610
+ case A_NPCM7XX_PWM_CNR0:
249
+{
611
+ case A_NPCM7XX_PWM_CNR1:
250
+ AddressSpace *as = &s->gicv3->dma_as;
612
+ case A_NPCM7XX_PWM_CNR2:
251
+ uint32_t devid, eventid;
613
+ case A_NPCM7XX_PWM_CNR3:
252
+ MemTxResult res = MEMTX_OK;
614
+ p = &s->pwm[npcm7xx_cnr_index(offset)];
253
+ bool dte_valid;
615
+ p->cnr = value;
254
+ uint64_t dte = 0;
616
+ npcm7xx_pwm_update_output(p);
255
+ uint32_t max_eventid;
617
+ break;
256
+ uint16_t icid = 0;
618
+
257
+ uint32_t pIntid = 0;
619
+ case A_NPCM7XX_PWM_CMR0:
258
+ bool ite_valid = false;
620
+ case A_NPCM7XX_PWM_CMR1:
259
+ uint64_t cte = 0;
621
+ case A_NPCM7XX_PWM_CMR2:
260
+ bool cte_valid = false;
622
+ case A_NPCM7XX_PWM_CMR3:
261
+ bool result = false;
623
+ p = &s->pwm[npcm7xx_cmr_index(offset)];
262
+
624
+ p->cmr = value;
263
+ if (cmd == NONE) {
625
+ npcm7xx_pwm_update_output(p);
264
+ devid = offset;
626
+ break;
265
+ } else {
627
+
266
+ devid = ((value & DEVID_MASK) >> DEVID_SHIFT);
628
+ case A_NPCM7XX_PWM_PDR0:
267
+
629
+ case A_NPCM7XX_PWM_PDR1:
268
+ offset += NUM_BYTES_IN_DW;
630
+ case A_NPCM7XX_PWM_PDR2:
269
+ value = address_space_ldq_le(as, s->cq.base_addr + offset,
631
+ case A_NPCM7XX_PWM_PDR3:
270
+ MEMTXATTRS_UNSPECIFIED, &res);
271
+ }
272
+
273
+ if (res != MEMTX_OK) {
274
+ return result;
275
+ }
276
+
277
+ eventid = (value & EVENTID_MASK);
278
+
279
+ dte = get_dte(s, devid, &res);
280
+
281
+ if (res != MEMTX_OK) {
282
+ return result;
283
+ }
284
+ dte_valid = dte & TABLE_ENTRY_VALID_MASK;
285
+
286
+ if (dte_valid) {
287
+ max_eventid = (1UL << (((dte >> 1U) & SIZE_MASK) + 1));
288
+
289
+ ite_valid = get_ite(s, eventid, dte, &icid, &pIntid, &res);
290
+
291
+ if (res != MEMTX_OK) {
292
+ return result;
293
+ }
294
+
295
+ if (ite_valid) {
296
+ cte_valid = get_cte(s, icid, &cte, &res);
297
+ }
298
+
299
+ if (res != MEMTX_OK) {
300
+ return result;
301
+ }
302
+ }
303
+
304
+ if ((devid > s->dt.maxids.max_devids) || !dte_valid || !ite_valid ||
305
+ !cte_valid || (eventid > max_eventid)) {
306
+ qemu_log_mask(LOG_GUEST_ERROR,
632
+ qemu_log_mask(LOG_GUEST_ERROR,
307
+ "%s: invalid command attributes "
633
+ "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n",
308
+ "devid %d or eventid %d or invalid dte %d or"
634
+ __func__, offset);
309
+ "invalid cte %d or invalid ite %d\n",
635
+ break;
310
+ __func__, devid, eventid, dte_valid, cte_valid,
636
+
311
+ ite_valid);
637
+ case A_NPCM7XX_PWM_PWDR0:
312
+ /*
638
+ case A_NPCM7XX_PWM_PWDR1:
313
+ * in this implementation, in case of error
639
+ case A_NPCM7XX_PWM_PWDR2:
314
+ * we ignore this command and move onto the next
640
+ case A_NPCM7XX_PWM_PWDR3:
315
+ * command in the queue
641
+ qemu_log_mask(LOG_UNIMP,
316
+ */
642
+ "%s: register @ 0x%04" HWADDR_PRIx " is not implemented\n",
317
+ } else {
643
+ __func__, offset);
318
+ /*
644
+ break;
319
+ * Current implementation only supports rdbase == procnum
645
+
320
+ * Hence rdbase physical address is ignored
646
+ case A_NPCM7XX_PWM_PPR:
321
+ */
647
+ npcm7xx_pwm_write_ppr(s, value);
322
+ if (cmd == DISCARD) {
648
+ break;
323
+ IteEntry ite = {};
649
+
324
+ /* remove mapping from interrupt translation table */
650
+ case A_NPCM7XX_PWM_CSR:
325
+ result = update_ite(s, eventid, dte, ite);
651
+ npcm7xx_pwm_write_csr(s, value);
326
+ }
652
+ break;
327
+ }
653
+
328
+
654
+ case A_NPCM7XX_PWM_PCR:
329
+ return result;
655
+ npcm7xx_pwm_write_pcr(s, value);
330
+}
656
+ break;
331
+
657
+
332
+static bool process_mapti(GICv3ITSState *s, uint64_t value, uint32_t offset,
658
+ case A_NPCM7XX_PWM_PIER:
333
+ bool ignore_pInt)
659
+ qemu_log_mask(LOG_UNIMP,
334
+{
660
+ "%s: register @ 0x%04" HWADDR_PRIx " is not implemented\n",
335
+ AddressSpace *as = &s->gicv3->dma_as;
661
+ __func__, offset);
336
+ uint32_t devid, eventid;
662
+ break;
337
+ uint32_t pIntid = 0;
663
+
338
+ uint32_t max_eventid, max_Intid;
664
+ case A_NPCM7XX_PWM_PIIR:
339
+ bool dte_valid;
665
+ qemu_log_mask(LOG_UNIMP,
340
+ MemTxResult res = MEMTX_OK;
666
+ "%s: register @ 0x%04" HWADDR_PRIx " is not implemented\n",
341
+ uint16_t icid = 0;
667
+ __func__, offset);
342
+ uint64_t dte = 0;
668
+ break;
343
+ IteEntry ite;
669
+
344
+ uint32_t int_spurious = INTID_SPURIOUS;
670
+ default:
345
+ bool result = false;
346
+
347
+ devid = ((value & DEVID_MASK) >> DEVID_SHIFT);
348
+ offset += NUM_BYTES_IN_DW;
349
+ value = address_space_ldq_le(as, s->cq.base_addr + offset,
350
+ MEMTXATTRS_UNSPECIFIED, &res);
351
+
352
+ if (res != MEMTX_OK) {
353
+ return result;
354
+ }
355
+
356
+ eventid = (value & EVENTID_MASK);
357
+
358
+ if (!ignore_pInt) {
359
+ pIntid = ((value & pINTID_MASK) >> pINTID_SHIFT);
360
+ }
361
+
362
+ offset += NUM_BYTES_IN_DW;
363
+ value = address_space_ldq_le(as, s->cq.base_addr + offset,
364
+ MEMTXATTRS_UNSPECIFIED, &res);
365
+
366
+ if (res != MEMTX_OK) {
367
+ return result;
368
+ }
369
+
370
+ icid = value & ICID_MASK;
371
+
372
+ dte = get_dte(s, devid, &res);
373
+
374
+ if (res != MEMTX_OK) {
375
+ return result;
376
+ }
377
+ dte_valid = dte & TABLE_ENTRY_VALID_MASK;
378
+
379
+ max_eventid = (1UL << (((dte >> 1U) & SIZE_MASK) + 1));
380
+
381
+ if (!ignore_pInt) {
382
+ max_Intid = (1ULL << (GICD_TYPER_IDBITS + 1)) - 1;
383
+ }
384
+
385
+ if ((devid > s->dt.maxids.max_devids) || (icid > s->ct.maxids.max_collids)
386
+ || !dte_valid || (eventid > max_eventid) ||
387
+ (!ignore_pInt && (((pIntid < GICV3_LPI_INTID_START) ||
388
+ (pIntid > max_Intid)) && (pIntid != INTID_SPURIOUS)))) {
389
+ qemu_log_mask(LOG_GUEST_ERROR,
671
+ qemu_log_mask(LOG_GUEST_ERROR,
390
+ "%s: invalid command attributes "
672
+ "%s: invalid offset 0x%04" HWADDR_PRIx "\n",
391
+ "devid %d or icid %d or eventid %d or pIntid %d or"
673
+ __func__, offset);
392
+ "unmapped dte %d\n", __func__, devid, icid, eventid,
674
+ break;
393
+ pIntid, dte_valid);
675
+ }
394
+ /*
676
+}
395
+ * in this implementation, in case of error
677
+
396
+ * we ignore this command and move onto the next
678
+static const struct MemoryRegionOps npcm7xx_pwm_ops = {
397
+ * command in the queue
679
+ .read = npcm7xx_pwm_read,
398
+ */
680
+ .write = npcm7xx_pwm_write,
399
+ } else {
681
+ .endianness = DEVICE_LITTLE_ENDIAN,
400
+ /* add ite entry to interrupt translation table */
682
+ .valid = {
401
+ ite.itel = (dte_valid & TABLE_ENTRY_VALID_MASK) |
683
+ .min_access_size = 4,
402
+ (GITS_TYPE_PHYSICAL << ITE_ENTRY_INTTYPE_SHIFT);
684
+ .max_access_size = 4,
403
+
685
+ .unaligned = false,
404
+ if (ignore_pInt) {
686
+ },
405
+ ite.itel |= (eventid << ITE_ENTRY_INTID_SHIFT);
687
+};
406
+ } else {
688
+
407
+ ite.itel |= (pIntid << ITE_ENTRY_INTID_SHIFT);
689
+static void npcm7xx_pwm_enter_reset(Object *obj, ResetType type)
408
+ }
690
+{
409
+ ite.itel |= (int_spurious << ITE_ENTRY_INTSP_SHIFT);
691
+ NPCM7xxPWMState *s = NPCM7XX_PWM(obj);
410
+ ite.iteh = icid;
692
+ int i;
411
+
693
+
412
+ result = update_ite(s, eventid, dte, ite);
694
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; i++) {
413
+ }
695
+ NPCM7xxPWM *p = &s->pwm[i];
414
+
696
+
415
+ return result;
697
+ p->cnr = 0x00000000;
416
+}
698
+ p->cmr = 0x00000000;
417
+
699
+ p->pdr = 0x00000000;
418
static bool update_cte(GICv3ITSState *s, uint16_t icid, bool valid,
700
+ p->pwdr = 0x00000000;
419
uint64_t rdbase)
701
+ }
420
{
702
+
421
@@ -XXX,XX +XXX,XX @@ static void process_cmdq(GICv3ITSState *s)
703
+ s->ppr = 0x00000000;
422
704
+ s->csr = 0x00000000;
423
switch (cmd) {
705
+ s->pcr = 0x00000000;
424
case GITS_CMD_INT:
706
+ s->pier = 0x00000000;
425
+ res = process_its_cmd(s, data, cq_offset, INT);
707
+ s->piir = 0x00000000;
426
break;
708
+}
427
case GITS_CMD_CLEAR:
709
+
428
+ res = process_its_cmd(s, data, cq_offset, CLEAR);
710
+static void npcm7xx_pwm_hold_reset(Object *obj)
429
break;
711
+{
430
case GITS_CMD_SYNC:
712
+ NPCM7xxPWMState *s = NPCM7XX_PWM(obj);
431
/*
713
+ int i;
432
@@ -XXX,XX +XXX,XX @@ static void process_cmdq(GICv3ITSState *s)
714
+
433
result = process_mapc(s, cq_offset);
715
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; i++) {
434
break;
716
+ qemu_irq_lower(s->pwm[i].irq);
435
case GITS_CMD_MAPTI:
717
+ }
436
+ result = process_mapti(s, data, cq_offset, false);
718
+}
437
break;
719
+
438
case GITS_CMD_MAPI:
720
+static void npcm7xx_pwm_init(Object *obj)
439
+ result = process_mapti(s, data, cq_offset, true);
721
+{
440
break;
722
+ NPCM7xxPWMState *s = NPCM7XX_PWM(obj);
441
case GITS_CMD_DISCARD:
723
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
442
+ result = process_its_cmd(s, data, cq_offset, DISCARD);
724
+ int i;
443
break;
725
+
444
case GITS_CMD_INV:
726
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; i++) {
445
case GITS_CMD_INVALL:
727
+ NPCM7xxPWM *p = &s->pwm[i];
446
@@ -XXX,XX +XXX,XX @@ static MemTxResult gicv3_its_translation_write(void *opaque, hwaddr offset,
728
+ p->module = s;
447
uint64_t data, unsigned size,
729
+ p->index = i;
448
MemTxAttrs attrs)
730
+ sysbus_init_irq(sbd, &p->irq);
449
{
731
+ }
450
- return MEMTX_OK;
732
+
451
+ GICv3ITSState *s = (GICv3ITSState *)opaque;
733
+ memory_region_init_io(&s->iomem, obj, &npcm7xx_pwm_ops, s,
452
+ bool result = true;
734
+ TYPE_NPCM7XX_PWM, 4 * KiB);
453
+ uint32_t devid = 0;
735
+ sysbus_init_mmio(sbd, &s->iomem);
454
+
736
+ s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL);
455
+ switch (offset) {
737
+
456
+ case GITS_TRANSLATER:
738
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
457
+ if (s->ctlr & ITS_CTLR_ENABLED) {
739
+ object_property_add_uint32_ptr(obj, "freq[*]",
458
+ devid = attrs.requester_id;
740
+ &s->pwm[i].freq, OBJ_PROP_FLAG_READ);
459
+ result = process_its_cmd(s, data, devid, NONE);
741
+ object_property_add_uint32_ptr(obj, "duty[*]",
460
+ }
742
+ &s->pwm[i].duty, OBJ_PROP_FLAG_READ);
461
+ break;
743
+ }
462
+ default:
744
+}
463
+ break;
745
+
464
+ }
746
+static const VMStateDescription vmstate_npcm7xx_pwm = {
465
+
747
+ .name = "npcm7xx-pwm",
466
+ if (result) {
748
+ .version_id = 0,
467
+ return MEMTX_OK;
749
+ .minimum_version_id = 0,
468
+ } else {
750
+ .fields = (VMStateField[]) {
469
+ return MEMTX_ERROR;
751
+ VMSTATE_BOOL(running, NPCM7xxPWM),
470
+ }
752
+ VMSTATE_BOOL(inverted, NPCM7xxPWM),
471
}
753
+ VMSTATE_UINT8(index, NPCM7xxPWM),
472
754
+ VMSTATE_UINT32(cnr, NPCM7xxPWM),
473
static bool its_writel(GICv3ITSState *s, hwaddr offset,
755
+ VMSTATE_UINT32(cmr, NPCM7xxPWM),
756
+ VMSTATE_UINT32(pdr, NPCM7xxPWM),
757
+ VMSTATE_UINT32(pwdr, NPCM7xxPWM),
758
+ VMSTATE_UINT32(freq, NPCM7xxPWM),
759
+ VMSTATE_UINT32(duty, NPCM7xxPWM),
760
+ VMSTATE_END_OF_LIST(),
761
+ },
762
+};
763
+
764
+static const VMStateDescription vmstate_npcm7xx_pwm_module = {
765
+ .name = "npcm7xx-pwm-module",
766
+ .version_id = 0,
767
+ .minimum_version_id = 0,
768
+ .fields = (VMStateField[]) {
769
+ VMSTATE_CLOCK(clock, NPCM7xxPWMState),
770
+ VMSTATE_STRUCT_ARRAY(pwm, NPCM7xxPWMState,
771
+ NPCM7XX_PWM_PER_MODULE, 0, vmstate_npcm7xx_pwm,
772
+ NPCM7xxPWM),
773
+ VMSTATE_UINT32(ppr, NPCM7xxPWMState),
774
+ VMSTATE_UINT32(csr, NPCM7xxPWMState),
775
+ VMSTATE_UINT32(pcr, NPCM7xxPWMState),
776
+ VMSTATE_UINT32(pier, NPCM7xxPWMState),
777
+ VMSTATE_UINT32(piir, NPCM7xxPWMState),
778
+ VMSTATE_END_OF_LIST(),
779
+ },
780
+};
781
+
782
+static void npcm7xx_pwm_class_init(ObjectClass *klass, void *data)
783
+{
784
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
785
+ DeviceClass *dc = DEVICE_CLASS(klass);
786
+
787
+ dc->desc = "NPCM7xx PWM Controller";
788
+ dc->vmsd = &vmstate_npcm7xx_pwm_module;
789
+ rc->phases.enter = npcm7xx_pwm_enter_reset;
790
+ rc->phases.hold = npcm7xx_pwm_hold_reset;
791
+}
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
807
index XXXXXXX..XXXXXXX 100644
808
--- a/hw/misc/meson.build
809
+++ b/hw/misc/meson.build
810
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mst_fpga.c'))
811
softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
812
'npcm7xx_clk.c',
813
'npcm7xx_gcr.c',
814
+ 'npcm7xx_pwm.c',
815
'npcm7xx_rng.c',
816
))
817
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files(
818
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
819
index XXXXXXX..XXXXXXX 100644
820
--- a/hw/misc/trace-events
821
+++ b/hw/misc/trace-events
822
@@ -XXX,XX +XXX,XX @@ npcm7xx_gcr_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " valu
823
npcm7xx_rng_read(uint64_t offset, uint64_t value, unsigned size) "offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
824
npcm7xx_rng_write(uint64_t offset, uint64_t value, unsigned size) "offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
825
826
+# npcm7xx_pwm.c
827
+npcm7xx_pwm_read(const char *id, uint64_t offset, uint32_t value) "%s offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
828
+npcm7xx_pwm_write(const char *id, uint64_t offset, uint32_t value) "%s offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
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"
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"
831
+
832
# stm32f4xx_syscfg.c
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"
474
--
835
--
475
2.20.1
836
2.20.1
476
837
477
838
diff view generated by jsdifflib
1
From: Shashi Mallela <shashi.mallela@linaro.org>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
Added register definitions relevant to ITS,implemented overall
3
We add a qtest for the PWM in the previous patch. It proves it works as
4
ITS device framework with stubs for ITS control and translater
4
expected.
5
regions read/write,extended ITS common to handle mmio init between
6
existing kvm device and newer qemu device.
7
5
8
Signed-off-by: Shashi Mallela <shashi.mallela@linaro.org>
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
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Eric Auger <eric.auger@redhat.com>
10
Message-id: 20210108190945.949196-6-wuhaotsh@google.com
11
Tested-by: Neil Armstrong <narmstrong@baylibre.com>
12
Message-id: 20210910143951.92242-2-shashi.mallela@linaro.org
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
---
12
---
15
hw/intc/gicv3_internal.h | 96 +++++++++-
13
tests/qtest/npcm7xx_pwm-test.c | 490 +++++++++++++++++++++++++++++++++
16
include/hw/intc/arm_gicv3_its_common.h | 9 +-
14
tests/qtest/meson.build | 1 +
17
hw/intc/arm_gicv3_its.c | 241 +++++++++++++++++++++++++
15
2 files changed, 491 insertions(+)
18
hw/intc/arm_gicv3_its_common.c | 7 +-
16
create mode 100644 tests/qtest/npcm7xx_pwm-test.c
19
hw/intc/arm_gicv3_its_kvm.c | 2 +-
20
hw/intc/meson.build | 1 +
21
6 files changed, 342 insertions(+), 14 deletions(-)
22
create mode 100644 hw/intc/arm_gicv3_its.c
23
17
24
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
18
diff --git a/tests/qtest/npcm7xx_pwm-test.c b/tests/qtest/npcm7xx_pwm-test.c
25
index XXXXXXX..XXXXXXX 100644
26
--- a/hw/intc/gicv3_internal.h
27
+++ b/hw/intc/gicv3_internal.h
28
@@ -XXX,XX +XXX,XX @@
29
#ifndef QEMU_ARM_GICV3_INTERNAL_H
30
#define QEMU_ARM_GICV3_INTERNAL_H
31
32
+#include "hw/registerfields.h"
33
#include "hw/intc/arm_gicv3_common.h"
34
35
/* Distributor registers, as offsets from the distributor base address */
36
@@ -XXX,XX +XXX,XX @@
37
#define GICD_CTLR_E1NWF (1U << 7)
38
#define GICD_CTLR_RWP (1U << 31)
39
40
+/* 16 bits EventId */
41
+#define GICD_TYPER_IDBITS 0xf
42
+
43
/*
44
* Redistributor frame offsets from RD_base
45
*/
46
@@ -XXX,XX +XXX,XX @@
47
#define GICR_WAKER_ProcessorSleep (1U << 1)
48
#define GICR_WAKER_ChildrenAsleep (1U << 2)
49
50
-#define GICR_PROPBASER_OUTER_CACHEABILITY_MASK (7ULL << 56)
51
-#define GICR_PROPBASER_ADDR_MASK (0xfffffffffULL << 12)
52
-#define GICR_PROPBASER_SHAREABILITY_MASK (3U << 10)
53
-#define GICR_PROPBASER_CACHEABILITY_MASK (7U << 7)
54
-#define GICR_PROPBASER_IDBITS_MASK (0x1f)
55
+FIELD(GICR_PROPBASER, IDBITS, 0, 5)
56
+FIELD(GICR_PROPBASER, INNERCACHE, 7, 3)
57
+FIELD(GICR_PROPBASER, SHAREABILITY, 10, 2)
58
+FIELD(GICR_PROPBASER, PHYADDR, 12, 40)
59
+FIELD(GICR_PROPBASER, OUTERCACHE, 56, 3)
60
61
-#define GICR_PENDBASER_PTZ (1ULL << 62)
62
-#define GICR_PENDBASER_OUTER_CACHEABILITY_MASK (7ULL << 56)
63
-#define GICR_PENDBASER_ADDR_MASK (0xffffffffULL << 16)
64
-#define GICR_PENDBASER_SHAREABILITY_MASK (3U << 10)
65
-#define GICR_PENDBASER_CACHEABILITY_MASK (7U << 7)
66
+FIELD(GICR_PENDBASER, INNERCACHE, 7, 3)
67
+FIELD(GICR_PENDBASER, SHAREABILITY, 10, 2)
68
+FIELD(GICR_PENDBASER, PHYADDR, 16, 36)
69
+FIELD(GICR_PENDBASER, OUTERCACHE, 56, 3)
70
+FIELD(GICR_PENDBASER, PTZ, 62, 1)
71
72
#define ICC_CTLR_EL1_CBPR (1U << 0)
73
#define ICC_CTLR_EL1_EOIMODE (1U << 1)
74
@@ -XXX,XX +XXX,XX @@
75
#define ICH_VTR_EL2_PREBITS_SHIFT 26
76
#define ICH_VTR_EL2_PRIBITS_SHIFT 29
77
78
+/* ITS Registers */
79
+
80
+FIELD(GITS_BASER, SIZE, 0, 8)
81
+FIELD(GITS_BASER, PAGESIZE, 8, 2)
82
+FIELD(GITS_BASER, SHAREABILITY, 10, 2)
83
+FIELD(GITS_BASER, PHYADDR, 12, 36)
84
+FIELD(GITS_BASER, PHYADDRL_64K, 16, 32)
85
+FIELD(GITS_BASER, PHYADDRH_64K, 12, 4)
86
+FIELD(GITS_BASER, ENTRYSIZE, 48, 5)
87
+FIELD(GITS_BASER, OUTERCACHE, 53, 3)
88
+FIELD(GITS_BASER, TYPE, 56, 3)
89
+FIELD(GITS_BASER, INNERCACHE, 59, 3)
90
+FIELD(GITS_BASER, INDIRECT, 62, 1)
91
+FIELD(GITS_BASER, VALID, 63, 1)
92
+
93
+FIELD(GITS_CTLR, QUIESCENT, 31, 1)
94
+
95
+FIELD(GITS_TYPER, PHYSICAL, 0, 1)
96
+FIELD(GITS_TYPER, ITT_ENTRY_SIZE, 4, 4)
97
+FIELD(GITS_TYPER, IDBITS, 8, 5)
98
+FIELD(GITS_TYPER, DEVBITS, 13, 5)
99
+FIELD(GITS_TYPER, SEIS, 18, 1)
100
+FIELD(GITS_TYPER, PTA, 19, 1)
101
+FIELD(GITS_TYPER, CIDBITS, 32, 4)
102
+FIELD(GITS_TYPER, CIL, 36, 1)
103
+
104
+#define GITS_BASER_PAGESIZE_4K 0
105
+#define GITS_BASER_PAGESIZE_16K 1
106
+#define GITS_BASER_PAGESIZE_64K 2
107
+
108
+#define GITS_BASER_TYPE_DEVICE 1ULL
109
+#define GITS_BASER_TYPE_COLLECTION 4ULL
110
+
111
+/**
112
+ * Default features advertised by this version of ITS
113
+ */
114
+/* Physical LPIs supported */
115
+#define GITS_TYPE_PHYSICAL (1U << 0)
116
+
117
+/*
118
+ * 12 bytes Interrupt translation Table Entry size
119
+ * as per Table 5.3 in GICv3 spec
120
+ * ITE Lower 8 Bytes
121
+ * Bits: | 49 ... 26 | 25 ... 2 | 1 | 0 |
122
+ * Values: | 1023 | IntNum | IntType | Valid |
123
+ * ITE Higher 4 Bytes
124
+ * Bits: | 31 ... 16 | 15 ...0 |
125
+ * Values: | vPEID | ICID |
126
+ */
127
+#define ITS_ITT_ENTRY_SIZE 0xC
128
+
129
+/* 16 bits EventId */
130
+#define ITS_IDBITS GICD_TYPER_IDBITS
131
+
132
+/* 16 bits DeviceId */
133
+#define ITS_DEVBITS 0xF
134
+
135
+/* 16 bits CollectionId */
136
+#define ITS_CIDBITS 0xF
137
+
138
+/*
139
+ * 8 bytes Device Table Entry size
140
+ * Valid = 1 bit,ITTAddr = 44 bits,Size = 5 bits
141
+ */
142
+#define GITS_DTE_SIZE (0x8ULL)
143
+
144
+/*
145
+ * 8 bytes Collection Table Entry size
146
+ * Valid = 1 bit,RDBase = 36 bits(considering max RDBASE)
147
+ */
148
+#define GITS_CTE_SIZE (0x8ULL)
149
+
150
/* Special interrupt IDs */
151
#define INTID_SECURE 1020
152
#define INTID_NONSECURE 1021
153
diff --git a/include/hw/intc/arm_gicv3_its_common.h b/include/hw/intc/arm_gicv3_its_common.h
154
index XXXXXXX..XXXXXXX 100644
155
--- a/include/hw/intc/arm_gicv3_its_common.h
156
+++ b/include/hw/intc/arm_gicv3_its_common.h
157
@@ -XXX,XX +XXX,XX @@
158
#include "hw/intc/arm_gicv3_common.h"
159
#include "qom/object.h"
160
161
+#define TYPE_ARM_GICV3_ITS "arm-gicv3-its"
162
+
163
#define ITS_CONTROL_SIZE 0x10000
164
#define ITS_TRANS_SIZE 0x10000
165
#define ITS_SIZE (ITS_CONTROL_SIZE + ITS_TRANS_SIZE)
166
167
#define GITS_CTLR 0x0
168
#define GITS_IIDR 0x4
169
+#define GITS_TYPER 0x8
170
#define GITS_CBASER 0x80
171
#define GITS_CWRITER 0x88
172
#define GITS_CREADR 0x90
173
#define GITS_BASER 0x100
174
175
+#define GITS_TRANSLATER 0x0040
176
+
177
struct GICv3ITSState {
178
SysBusDevice parent_obj;
179
180
@@ -XXX,XX +XXX,XX @@ struct GICv3ITSState {
181
/* Registers */
182
uint32_t ctlr;
183
uint32_t iidr;
184
+ uint64_t typer;
185
uint64_t cbaser;
186
uint64_t cwriter;
187
uint64_t creadr;
188
@@ -XXX,XX +XXX,XX @@ struct GICv3ITSState {
189
190
typedef struct GICv3ITSState GICv3ITSState;
191
192
-void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops);
193
+void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops,
194
+ const MemoryRegionOps *tops);
195
196
#define TYPE_ARM_GICV3_ITS_COMMON "arm-gicv3-its-common"
197
typedef struct GICv3ITSCommonClass GICv3ITSCommonClass;
198
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
199
new file mode 100644
19
new file mode 100644
200
index XXXXXXX..XXXXXXX
20
index XXXXXXX..XXXXXXX
201
--- /dev/null
21
--- /dev/null
202
+++ b/hw/intc/arm_gicv3_its.c
22
+++ b/tests/qtest/npcm7xx_pwm-test.c
203
@@ -XXX,XX +XXX,XX @@
23
@@ -XXX,XX +XXX,XX @@
204
+/*
24
+/*
205
+ * ITS emulation for a GICv3-based system
25
+ * QTests for Nuvoton NPCM7xx PWM Modules.
206
+ *
26
+ *
207
+ * Copyright Linaro.org 2021
27
+ * Copyright 2020 Google LLC
208
+ *
28
+ *
209
+ * Authors:
29
+ * This program is free software; you can redistribute it and/or modify it
210
+ * Shashi Mallela <shashi.mallela@linaro.org>
30
+ * under the terms of the GNU General Public License as published by the
31
+ * Free Software Foundation; either version 2 of the License, or
32
+ * (at your option) any later version.
211
+ *
33
+ *
212
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
34
+ * This program is distributed in the hope that it will be useful, but WITHOUT
213
+ * option) any later version. See the COPYING file in the top-level directory.
35
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
214
+ *
36
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
37
+ * for more details.
215
+ */
38
+ */
216
+
39
+
217
+#include "qemu/osdep.h"
40
+#include "qemu/osdep.h"
218
+#include "qemu/log.h"
41
+#include "qemu/bitops.h"
219
+#include "hw/qdev-properties.h"
42
+#include "libqos/libqtest.h"
220
+#include "hw/intc/arm_gicv3_its_common.h"
43
+#include "qapi/qmp/qdict.h"
221
+#include "gicv3_internal.h"
44
+#include "qapi/qmp/qnum.h"
222
+#include "qom/object.h"
45
+
223
+#include "qapi/error.h"
46
+#define REF_HZ 25000000
224
+
47
+
225
+typedef struct GICv3ITSClass GICv3ITSClass;
48
+/* Register field definitions. */
226
+/* This is reusing the GICv3ITSState typedef from ARM_GICV3_ITS_COMMON */
49
+#define CH_EN BIT(0)
227
+DECLARE_OBJ_CHECKERS(GICv3ITSState, GICv3ITSClass,
50
+#define CH_INV BIT(2)
228
+ ARM_GICV3_ITS, TYPE_ARM_GICV3_ITS)
51
+#define CH_MOD BIT(3)
229
+
52
+
230
+struct GICv3ITSClass {
53
+/* Registers shared between all PWMs in a module */
231
+ GICv3ITSCommonClass parent_class;
54
+#define PPR 0x00
232
+ void (*parent_reset)(DeviceState *dev);
55
+#define CSR 0x04
56
+#define PCR 0x08
57
+#define PIER 0x3c
58
+#define PIIR 0x40
59
+
60
+/* CLK module related */
61
+#define CLK_BA 0xf0801000
62
+#define CLKSEL 0x04
63
+#define CLKDIV1 0x08
64
+#define CLKDIV2 0x2c
65
+#define PLLCON0 0x0c
66
+#define PLLCON1 0x10
67
+#define PLL_INDV(rv) extract32((rv), 0, 6)
68
+#define PLL_FBDV(rv) extract32((rv), 16, 12)
69
+#define PLL_OTDV1(rv) extract32((rv), 8, 3)
70
+#define PLL_OTDV2(rv) extract32((rv), 13, 3)
71
+#define APB3CKDIV(rv) extract32((rv), 28, 2)
72
+#define CLK2CKDIV(rv) extract32((rv), 0, 1)
73
+#define CLK4CKDIV(rv) extract32((rv), 26, 2)
74
+#define CPUCKSEL(rv) extract32((rv), 0, 2)
75
+
76
+#define MAX_DUTY 1000000
77
+
78
+typedef struct PWMModule {
79
+ int irq;
80
+ uint64_t base_addr;
81
+} PWMModule;
82
+
83
+typedef struct PWM {
84
+ uint32_t cnr_offset;
85
+ uint32_t cmr_offset;
86
+ uint32_t pdr_offset;
87
+ uint32_t pwdr_offset;
88
+} PWM;
89
+
90
+typedef struct TestData {
91
+ const PWMModule *module;
92
+ const PWM *pwm;
93
+} TestData;
94
+
95
+static const PWMModule pwm_module_list[] = {
96
+ {
97
+ .irq = 93,
98
+ .base_addr = 0xf0103000
99
+ },
100
+ {
101
+ .irq = 94,
102
+ .base_addr = 0xf0104000
103
+ }
233
+};
104
+};
234
+
105
+
235
+static MemTxResult gicv3_its_translation_write(void *opaque, hwaddr offset,
106
+static const PWM pwm_list[] = {
236
+ uint64_t data, unsigned size,
107
+ {
237
+ MemTxAttrs attrs)
108
+ .cnr_offset = 0x0c,
238
+{
109
+ .cmr_offset = 0x10,
239
+ return MEMTX_OK;
110
+ .pdr_offset = 0x14,
240
+}
111
+ .pwdr_offset = 0x44,
241
+
112
+ },
242
+static bool its_writel(GICv3ITSState *s, hwaddr offset,
113
+ {
243
+ uint64_t value, MemTxAttrs attrs)
114
+ .cnr_offset = 0x18,
244
+{
115
+ .cmr_offset = 0x1c,
245
+ bool result = true;
116
+ .pdr_offset = 0x20,
246
+
117
+ .pwdr_offset = 0x48,
247
+ return result;
118
+ },
248
+}
119
+ {
249
+
120
+ .cnr_offset = 0x24,
250
+static bool its_readl(GICv3ITSState *s, hwaddr offset,
121
+ .cmr_offset = 0x28,
251
+ uint64_t *data, MemTxAttrs attrs)
122
+ .pdr_offset = 0x2c,
252
+{
123
+ .pwdr_offset = 0x4c,
253
+ bool result = true;
124
+ },
254
+
125
+ {
255
+ return result;
126
+ .cnr_offset = 0x30,
256
+}
127
+ .cmr_offset = 0x34,
257
+
128
+ .pdr_offset = 0x38,
258
+static bool its_writell(GICv3ITSState *s, hwaddr offset,
129
+ .pwdr_offset = 0x50,
259
+ uint64_t value, MemTxAttrs attrs)
130
+ },
260
+{
131
+};
261
+ bool result = true;
132
+
262
+
133
+static const int ppr_base[] = { 0, 0, 8, 8 };
263
+ return result;
134
+static const int csr_base[] = { 0, 4, 8, 12 };
264
+}
135
+static const int pcr_base[] = { 0, 8, 12, 16 };
265
+
136
+
266
+static bool its_readll(GICv3ITSState *s, hwaddr offset,
137
+static const uint32_t ppr_list[] = {
267
+ uint64_t *data, MemTxAttrs attrs)
138
+ 0,
268
+{
139
+ 1,
269
+ bool result = true;
140
+ 10,
270
+
141
+ 100,
271
+ return result;
142
+ 255, /* Max possible value. */
272
+}
143
+};
273
+
144
+
274
+static MemTxResult gicv3_its_read(void *opaque, hwaddr offset, uint64_t *data,
145
+static const uint32_t csr_list[] = {
275
+ unsigned size, MemTxAttrs attrs)
146
+ 0,
276
+{
147
+ 1,
277
+ GICv3ITSState *s = (GICv3ITSState *)opaque;
148
+ 2,
278
+ bool result;
149
+ 3,
279
+
150
+ 4, /* Max possible value. */
280
+ switch (size) {
151
+};
281
+ case 4:
152
+
282
+ result = its_readl(s, offset, data, attrs);
153
+static const uint32_t cnr_list[] = {
154
+ 0,
155
+ 1,
156
+ 50,
157
+ 100,
158
+ 150,
159
+ 200,
160
+ 1000,
161
+ 10000,
162
+ 65535, /* Max possible value. */
163
+};
164
+
165
+static const uint32_t cmr_list[] = {
166
+ 0,
167
+ 1,
168
+ 10,
169
+ 50,
170
+ 100,
171
+ 150,
172
+ 200,
173
+ 1000,
174
+ 10000,
175
+ 65535, /* Max possible value. */
176
+};
177
+
178
+/* Returns the index of the PWM module. */
179
+static int pwm_module_index(const PWMModule *module)
180
+{
181
+ ptrdiff_t diff = module - pwm_module_list;
182
+
183
+ g_assert_true(diff >= 0 && diff < ARRAY_SIZE(pwm_module_list));
184
+
185
+ return diff;
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);
283
+ break;
251
+ break;
284
+ case 8:
252
+ case 1:
285
+ result = its_readll(s, offset, data, attrs);
253
+ pllcon = qtest_readl(qts, CLK_BA + PLLCON1);
254
+ freq = get_pll(pllcon);
255
+ break;
256
+ case 2:
257
+ break;
258
+ case 3:
286
+ break;
259
+ break;
287
+ default:
260
+ default:
288
+ result = false;
261
+ g_assert_not_reached();
289
+ break;
262
+ }
290
+ }
263
+
291
+
264
+ freq >>= (CLK2CKDIV(clkdiv1) + CLK4CKDIV(clkdiv1) + APB3CKDIV(clkdiv2));
292
+ if (!result) {
265
+
293
+ qemu_log_mask(LOG_GUEST_ERROR,
266
+ return freq;
294
+ "%s: invalid guest read at offset " TARGET_FMT_plx
267
+}
295
+ "size %u\n", __func__, offset, size);
268
+
296
+ /*
269
+static uint32_t pwm_selector(uint32_t csr)
297
+ * The spec requires that reserved registers are RAZ/WI;
270
+{
298
+ * so use false returns from leaf functions as a way to
271
+ switch (csr) {
299
+ * trigger the guest-error logging but don't return it to
272
+ case 0:
300
+ * the caller, or we'll cause a spurious guest data abort.
273
+ return 2;
301
+ */
274
+ case 1:
302
+ *data = 0;
275
+ return 4;
303
+ }
276
+ case 2:
304
+ return MEMTX_OK;
277
+ return 8;
305
+}
278
+ case 3:
306
+
279
+ return 16;
307
+static MemTxResult gicv3_its_write(void *opaque, hwaddr offset, uint64_t data,
308
+ unsigned size, MemTxAttrs attrs)
309
+{
310
+ GICv3ITSState *s = (GICv3ITSState *)opaque;
311
+ bool result;
312
+
313
+ switch (size) {
314
+ case 4:
280
+ case 4:
315
+ result = its_writel(s, offset, data, attrs);
281
+ return 1;
316
+ break;
317
+ case 8:
318
+ result = its_writell(s, offset, data, attrs);
319
+ break;
320
+ default:
282
+ default:
321
+ result = false;
283
+ g_assert_not_reached();
322
+ break;
284
+ }
323
+ }
285
+}
324
+
286
+
325
+ if (!result) {
287
+static uint64_t pwm_compute_freq(QTestState *qts, uint32_t ppr, uint32_t csr,
326
+ qemu_log_mask(LOG_GUEST_ERROR,
288
+ uint32_t cnr)
327
+ "%s: invalid guest write at offset " TARGET_FMT_plx
289
+{
328
+ "size %u\n", __func__, offset, size);
290
+ return read_pclk(qts) / ((ppr + 1) * pwm_selector(csr) * (cnr + 1));
329
+ /*
291
+}
330
+ * The spec requires that reserved registers are RAZ/WI;
292
+
331
+ * so use false returns from leaf functions as a way to
293
+static uint64_t pwm_compute_duty(uint32_t cnr, uint32_t cmr, bool inverted)
332
+ * trigger the guest-error logging but don't return it to
294
+{
333
+ * the caller, or we'll cause a spurious guest data abort.
295
+ uint64_t duty;
334
+ */
296
+
335
+ }
297
+ if (cnr == 0) {
336
+ return MEMTX_OK;
298
+ /* PWM is stopped. */
337
+}
299
+ duty = 0;
338
+
300
+ } else if (cmr >= cnr) {
339
+static const MemoryRegionOps gicv3_its_control_ops = {
301
+ duty = MAX_DUTY;
340
+ .read_with_attrs = gicv3_its_read,
302
+ } else {
341
+ .write_with_attrs = gicv3_its_write,
303
+ duty = MAX_DUTY * (cmr + 1) / (cnr + 1);
342
+ .valid.min_access_size = 4,
304
+ }
343
+ .valid.max_access_size = 8,
305
+
344
+ .impl.min_access_size = 4,
306
+ if (inverted) {
345
+ .impl.max_access_size = 8,
307
+ duty = MAX_DUTY - duty;
346
+ .endianness = DEVICE_NATIVE_ENDIAN,
308
+ }
347
+};
309
+
348
+
310
+ return duty;
349
+static const MemoryRegionOps gicv3_its_translation_ops = {
311
+}
350
+ .write_with_attrs = gicv3_its_translation_write,
312
+
351
+ .valid.min_access_size = 2,
313
+static uint32_t pwm_read(QTestState *qts, const TestData *td, unsigned offset)
352
+ .valid.max_access_size = 4,
314
+{
353
+ .impl.min_access_size = 2,
315
+ return qtest_readl(qts, td->module->base_addr + offset);
354
+ .impl.max_access_size = 4,
316
+}
355
+ .endianness = DEVICE_NATIVE_ENDIAN,
317
+
356
+};
318
+static void pwm_write(QTestState *qts, const TestData *td, unsigned offset,
357
+
319
+ uint32_t value)
358
+static void gicv3_arm_its_realize(DeviceState *dev, Error **errp)
320
+{
359
+{
321
+ qtest_writel(qts, td->module->base_addr + offset, value);
360
+ GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
322
+}
361
+ int i;
323
+
362
+
324
+static uint32_t pwm_read_ppr(QTestState *qts, const TestData *td)
363
+ for (i = 0; i < s->gicv3->num_cpu; i++) {
325
+{
364
+ if (!(s->gicv3->cpu[i].gicr_typer & GICR_TYPER_PLPIS)) {
326
+ return extract32(pwm_read(qts, td, PPR), ppr_base[pwm_index(td->pwm)], 8);
365
+ error_setg(errp, "Physical LPI not supported by CPU %d", i);
327
+}
366
+ return;
328
+
329
+static void pwm_write_ppr(QTestState *qts, const TestData *td, uint32_t value)
330
+{
331
+ pwm_write(qts, td, PPR, value << ppr_base[pwm_index(td->pwm)]);
332
+}
333
+
334
+static uint32_t pwm_read_csr(QTestState *qts, const TestData *td)
335
+{
336
+ return extract32(pwm_read(qts, td, CSR), csr_base[pwm_index(td->pwm)], 3);
337
+}
338
+
339
+static void pwm_write_csr(QTestState *qts, const TestData *td, uint32_t value)
340
+{
341
+ pwm_write(qts, td, CSR, value << csr_base[pwm_index(td->pwm)]);
342
+}
343
+
344
+static uint32_t pwm_read_pcr(QTestState *qts, const TestData *td)
345
+{
346
+ return extract32(pwm_read(qts, td, PCR), pcr_base[pwm_index(td->pwm)], 4);
347
+}
348
+
349
+static void pwm_write_pcr(QTestState *qts, const TestData *td, uint32_t value)
350
+{
351
+ pwm_write(qts, td, PCR, value << pcr_base[pwm_index(td->pwm)]);
352
+}
353
+
354
+static uint32_t pwm_read_cnr(QTestState *qts, const TestData *td)
355
+{
356
+ return pwm_read(qts, td, td->pwm->cnr_offset);
357
+}
358
+
359
+static void pwm_write_cnr(QTestState *qts, const TestData *td, uint32_t value)
360
+{
361
+ pwm_write(qts, td, td->pwm->cnr_offset, value);
362
+}
363
+
364
+static uint32_t pwm_read_cmr(QTestState *qts, const TestData *td)
365
+{
366
+ return pwm_read(qts, td, td->pwm->cmr_offset);
367
+}
368
+
369
+static void pwm_write_cmr(QTestState *qts, const TestData *td, uint32_t value)
370
+{
371
+ pwm_write(qts, td, td->pwm->cmr_offset, value);
372
+}
373
+
374
+/* Check pwm registers can be reset to default value */
375
+static void test_init(gconstpointer test_data)
376
+{
377
+ const TestData *td = test_data;
378
+ QTestState *qts = qtest_init("-machine quanta-gsj");
379
+ int module = pwm_module_index(td->module);
380
+ int pwm = pwm_index(td->pwm);
381
+
382
+ g_assert_cmpuint(pwm_get_freq(qts, module, pwm), ==, 0);
383
+ g_assert_cmpuint(pwm_get_duty(qts, module, pwm), ==, 0);
384
+
385
+ qtest_quit(qts);
386
+}
387
+
388
+/* One-shot mode should not change frequency and duty cycle. */
389
+static void test_oneshot(gconstpointer test_data)
390
+{
391
+ const TestData *td = test_data;
392
+ QTestState *qts = qtest_init("-machine quanta-gsj");
393
+ int module = pwm_module_index(td->module);
394
+ int pwm = pwm_index(td->pwm);
395
+ uint32_t ppr, csr, pcr;
396
+ int i, j;
397
+
398
+ pcr = CH_EN;
399
+ for (i = 0; i < ARRAY_SIZE(ppr_list); ++i) {
400
+ ppr = ppr_list[i];
401
+ pwm_write_ppr(qts, td, ppr);
402
+
403
+ for (j = 0; j < ARRAY_SIZE(csr_list); ++j) {
404
+ csr = csr_list[j];
405
+ pwm_write_csr(qts, td, csr);
406
+ pwm_write_pcr(qts, td, pcr);
407
+
408
+ g_assert_cmpuint(pwm_read_ppr(qts, td), ==, ppr);
409
+ g_assert_cmpuint(pwm_read_csr(qts, td), ==, csr);
410
+ g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr);
411
+ g_assert_cmpuint(pwm_get_freq(qts, module, pwm), ==, 0);
412
+ g_assert_cmpuint(pwm_get_duty(qts, module, pwm), ==, 0);
367
+ }
413
+ }
368
+ }
414
+ }
369
+
415
+
370
+ gicv3_its_init_mmio(s, &gicv3_its_control_ops, &gicv3_its_translation_ops);
416
+ qtest_quit(qts);
371
+
417
+}
372
+ /* set the ITS default features supported */
418
+
373
+ s->typer = FIELD_DP64(s->typer, GITS_TYPER, PHYSICAL,
419
+/* In toggle mode, the PWM generates correct outputs. */
374
+ GITS_TYPE_PHYSICAL);
420
+static void test_toggle(gconstpointer test_data)
375
+ s->typer = FIELD_DP64(s->typer, GITS_TYPER, ITT_ENTRY_SIZE,
421
+{
376
+ ITS_ITT_ENTRY_SIZE - 1);
422
+ const TestData *td = test_data;
377
+ s->typer = FIELD_DP64(s->typer, GITS_TYPER, IDBITS, ITS_IDBITS);
423
+ QTestState *qts = qtest_init("-machine quanta-gsj");
378
+ s->typer = FIELD_DP64(s->typer, GITS_TYPER, DEVBITS, ITS_DEVBITS);
424
+ int module = pwm_module_index(td->module);
379
+ s->typer = FIELD_DP64(s->typer, GITS_TYPER, CIL, 1);
425
+ int pwm = pwm_index(td->pwm);
380
+ s->typer = FIELD_DP64(s->typer, GITS_TYPER, CIDBITS, ITS_CIDBITS);
426
+ uint32_t ppr, csr, pcr, cnr, cmr;
381
+}
427
+ int i, j, k, l;
382
+
428
+ uint64_t expected_freq, expected_duty;
383
+static void gicv3_its_reset(DeviceState *dev)
429
+
384
+{
430
+ pcr = CH_EN | CH_MOD;
385
+ GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
431
+ for (i = 0; i < ARRAY_SIZE(ppr_list); ++i) {
386
+ GICv3ITSClass *c = ARM_GICV3_ITS_GET_CLASS(s);
432
+ ppr = ppr_list[i];
387
+
433
+ pwm_write_ppr(qts, td, ppr);
388
+ c->parent_reset(dev);
434
+
389
+
435
+ for (j = 0; j < ARRAY_SIZE(csr_list); ++j) {
390
+ /* Quiescent bit reset to 1 */
436
+ csr = csr_list[j];
391
+ s->ctlr = FIELD_DP32(s->ctlr, GITS_CTLR, QUIESCENT, 1);
437
+ pwm_write_csr(qts, td, csr);
392
+
438
+
393
+ /*
439
+ for (k = 0; k < ARRAY_SIZE(cnr_list); ++k) {
394
+ * setting GITS_BASER0.Type = 0b001 (Device)
440
+ cnr = cnr_list[k];
395
+ * GITS_BASER1.Type = 0b100 (Collection Table)
441
+ pwm_write_cnr(qts, td, cnr);
396
+ * GITS_BASER<n>.Type,where n = 3 to 7 are 0b00 (Unimplemented)
442
+
397
+ * GITS_BASER<0,1>.Page_Size = 64KB
443
+ for (l = 0; l < ARRAY_SIZE(cmr_list); ++l) {
398
+ * and default translation table entry size to 16 bytes
444
+ cmr = cmr_list[l];
399
+ */
445
+ pwm_write_cmr(qts, td, cmr);
400
+ s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, TYPE,
446
+ expected_freq = pwm_compute_freq(qts, ppr, csr, cnr);
401
+ GITS_BASER_TYPE_DEVICE);
447
+ expected_duty = pwm_compute_duty(cnr, cmr, false);
402
+ s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, PAGESIZE,
448
+
403
+ GITS_BASER_PAGESIZE_64K);
449
+ pwm_write_pcr(qts, td, pcr);
404
+ s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, ENTRYSIZE,
450
+ g_assert_cmpuint(pwm_read_ppr(qts, td), ==, ppr);
405
+ GITS_DTE_SIZE - 1);
451
+ g_assert_cmpuint(pwm_read_csr(qts, td), ==, csr);
406
+
452
+ g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr);
407
+ s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, TYPE,
453
+ g_assert_cmpuint(pwm_read_cnr(qts, td), ==, cnr);
408
+ GITS_BASER_TYPE_COLLECTION);
454
+ g_assert_cmpuint(pwm_read_cmr(qts, td), ==, cmr);
409
+ s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, PAGESIZE,
455
+ g_assert_cmpuint(pwm_get_duty(qts, module, pwm),
410
+ GITS_BASER_PAGESIZE_64K);
456
+ ==, expected_duty);
411
+ s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, ENTRYSIZE,
457
+ if (expected_duty != 0 && expected_duty != 100) {
412
+ GITS_CTE_SIZE - 1);
458
+ /* Duty cycle with 0 or 100 doesn't need frequency. */
413
+}
459
+ g_assert_cmpuint(pwm_get_freq(qts, module, pwm),
414
+
460
+ ==, expected_freq);
415
+static Property gicv3_its_props[] = {
461
+ }
416
+ DEFINE_PROP_LINK("parent-gicv3", GICv3ITSState, gicv3, "arm-gicv3",
462
+
417
+ GICv3State *),
463
+ /* Test inverted mode */
418
+ DEFINE_PROP_END_OF_LIST(),
464
+ expected_duty = pwm_compute_duty(cnr, cmr, true);
419
+};
465
+ pwm_write_pcr(qts, td, pcr | CH_INV);
420
+
466
+ g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr | CH_INV);
421
+static void gicv3_its_class_init(ObjectClass *klass, void *data)
467
+ g_assert_cmpuint(pwm_get_duty(qts, module, pwm),
422
+{
468
+ ==, expected_duty);
423
+ DeviceClass *dc = DEVICE_CLASS(klass);
469
+ if (expected_duty != 0 && expected_duty != 100) {
424
+ GICv3ITSClass *ic = ARM_GICV3_ITS_CLASS(klass);
470
+ /* Duty cycle with 0 or 100 doesn't need frequency. */
425
+
471
+ g_assert_cmpuint(pwm_get_freq(qts, module, pwm),
426
+ dc->realize = gicv3_arm_its_realize;
472
+ ==, expected_freq);
427
+ device_class_set_props(dc, gicv3_its_props);
473
+ }
428
+ device_class_set_parent_reset(dc, gicv3_its_reset, &ic->parent_reset);
474
+
429
+}
475
+ }
430
+
476
+ }
431
+static const TypeInfo gicv3_its_info = {
477
+ }
432
+ .name = TYPE_ARM_GICV3_ITS,
478
+ }
433
+ .parent = TYPE_ARM_GICV3_ITS_COMMON,
479
+
434
+ .instance_size = sizeof(GICv3ITSState),
480
+ qtest_quit(qts);
435
+ .class_init = gicv3_its_class_init,
481
+}
436
+ .class_size = sizeof(GICv3ITSClass),
482
+
437
+};
483
+static void pwm_add_test(const char *name, const TestData* td,
438
+
484
+ GTestDataFunc fn)
439
+static void gicv3_its_register_types(void)
485
+{
440
+{
486
+ g_autofree char *full_name = g_strdup_printf(
441
+ type_register_static(&gicv3_its_info);
487
+ "npcm7xx_pwm/module[%d]/pwm[%d]/%s", pwm_module_index(td->module),
442
+}
488
+ pwm_index(td->pwm), name);
443
+
489
+ qtest_add_data_func(full_name, td, fn);
444
+type_init(gicv3_its_register_types)
490
+}
445
diff --git a/hw/intc/arm_gicv3_its_common.c b/hw/intc/arm_gicv3_its_common.c
491
+#define add_test(name, td) pwm_add_test(#name, td, test_##name)
492
+
493
+int main(int argc, char **argv)
494
+{
495
+ TestData test_data_list[ARRAY_SIZE(pwm_module_list) * ARRAY_SIZE(pwm_list)];
496
+
497
+ g_test_init(&argc, &argv, NULL);
498
+
499
+ for (int i = 0; i < ARRAY_SIZE(pwm_module_list); ++i) {
500
+ for (int j = 0; j < ARRAY_SIZE(pwm_list); ++j) {
501
+ TestData *td = &test_data_list[i * ARRAY_SIZE(pwm_list) + j];
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
+
512
+ return g_test_run();
513
+}
514
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
446
index XXXXXXX..XXXXXXX 100644
515
index XXXXXXX..XXXXXXX 100644
447
--- a/hw/intc/arm_gicv3_its_common.c
516
--- a/tests/qtest/meson.build
448
+++ b/hw/intc/arm_gicv3_its_common.c
517
+++ b/tests/qtest/meson.build
449
@@ -XXX,XX +XXX,XX @@ static int gicv3_its_post_load(void *opaque, int version_id)
518
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
450
519
qtests_npcm7xx = \
451
static const VMStateDescription vmstate_its = {
520
['npcm7xx_adc-test',
452
.name = "arm_gicv3_its",
521
'npcm7xx_gpio-test',
453
+ .version_id = 1,
522
+ 'npcm7xx_pwm-test',
454
+ .minimum_version_id = 1,
523
'npcm7xx_rng-test',
455
.pre_save = gicv3_its_pre_save,
524
'npcm7xx_timer-test',
456
.post_load = gicv3_its_post_load,
525
'npcm7xx_watchdog_timer-test']
457
.priority = MIG_PRI_GICV3_ITS,
458
@@ -XXX,XX +XXX,XX @@ static const MemoryRegionOps gicv3_its_trans_ops = {
459
.endianness = DEVICE_NATIVE_ENDIAN,
460
};
461
462
-void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops)
463
+void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops,
464
+ const MemoryRegionOps *tops)
465
{
466
SysBusDevice *sbd = SYS_BUS_DEVICE(s);
467
468
memory_region_init_io(&s->iomem_its_cntrl, OBJECT(s), ops, s,
469
"control", ITS_CONTROL_SIZE);
470
memory_region_init_io(&s->iomem_its_translation, OBJECT(s),
471
- &gicv3_its_trans_ops, s,
472
+ tops ? tops : &gicv3_its_trans_ops, s,
473
"translation", ITS_TRANS_SIZE);
474
475
/* Our two regions are always adjacent, therefore we now combine them
476
diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c
477
index XXXXXXX..XXXXXXX 100644
478
--- a/hw/intc/arm_gicv3_its_kvm.c
479
+++ b/hw/intc/arm_gicv3_its_kvm.c
480
@@ -XXX,XX +XXX,XX @@ static void kvm_arm_its_realize(DeviceState *dev, Error **errp)
481
kvm_arm_register_device(&s->iomem_its_cntrl, -1, KVM_DEV_ARM_VGIC_GRP_ADDR,
482
KVM_VGIC_ITS_ADDR_TYPE, s->dev_fd, 0);
483
484
- gicv3_its_init_mmio(s, NULL);
485
+ gicv3_its_init_mmio(s, NULL, NULL);
486
487
if (!kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ITS_REGS,
488
GITS_CTLR)) {
489
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
490
index XXXXXXX..XXXXXXX 100644
491
--- a/hw/intc/meson.build
492
+++ b/hw/intc/meson.build
493
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_ARM_GIC', if_true: files(
494
'arm_gicv3_dist.c',
495
'arm_gicv3_its_common.c',
496
'arm_gicv3_redist.c',
497
+ 'arm_gicv3_its.c',
498
))
499
softmmu_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_pic.c'))
500
softmmu_ss.add(when: 'CONFIG_HEATHROW_PIC', if_true: files('heathrow_pic.c'))
501
--
526
--
502
2.20.1
527
2.20.1
503
528
504
529
diff view generated by jsdifflib
1
From: Bin Meng <bmeng.cn@gmail.com>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
As of today, when booting upstream U-Boot for Xilinx Zynq, the UART
3
A device shouldn't access its parent object which is QOM internal.
4
does not receive anything. Debugging shows that the UART input clock
4
Instead it should use type cast for this purporse. This patch fixes this
5
frequency is zero which prevents the UART from receiving anything as
5
issue for all NPCM7XX Devices.
6
per the logic in uart_receive().
7
6
8
From zynq_slcr_reset_exit() comment, it intends to compute output
7
Signed-off-by: Hao Wu <wuhaotsh@google.com>
9
clocks according to ps_clk and registers. zynq_slcr_compute_clocks()
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
is called to accomplish the task, inside which device_is_in_reset()
9
Message-id: 20210108190945.949196-7-wuhaotsh@google.com
11
is called to actually make the attempt in vain.
12
13
Rework reset_hold() and reset_exit() so that in the reset exit phase,
14
the logic can really compute output clocks in reset_exit().
15
16
With this change, upstream U-Boot boots properly again with:
17
18
$ qemu-system-arm -M xilinx-zynq-a9 -m 1G -display none -serial null -serial stdio \
19
-device loader,file=u-boot-dtb.bin,addr=0x4000000,cpu-num=0
20
21
Fixes: 38867cb7ec90 ("hw/misc/zynq_slcr: add clock generation for uarts")
22
Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
23
Acked-by: Alistair Francis <alistair.francis@wdc.com>
24
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
25
Message-id: 20210901124521.30599-2-bmeng.cn@gmail.com
26
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
27
---
11
---
28
hw/misc/zynq_slcr.c | 31 ++++++++++++++++++-------------
12
hw/arm/npcm7xx_boards.c | 2 +-
29
1 file changed, 18 insertions(+), 13 deletions(-)
13
hw/mem/npcm7xx_mc.c | 2 +-
14
hw/misc/npcm7xx_clk.c | 2 +-
15
hw/misc/npcm7xx_gcr.c | 2 +-
16
hw/misc/npcm7xx_rng.c | 2 +-
17
hw/nvram/npcm7xx_otp.c | 2 +-
18
hw/ssi/npcm7xx_fiu.c | 2 +-
19
7 files changed, 7 insertions(+), 7 deletions(-)
30
20
31
diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c
21
diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c
32
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
33
--- a/hw/misc/zynq_slcr.c
23
--- a/hw/arm/npcm7xx_boards.c
34
+++ b/hw/misc/zynq_slcr.c
24
+++ b/hw/arm/npcm7xx_boards.c
35
@@ -XXX,XX +XXX,XX @@ static uint64_t zynq_slcr_compute_clock(const uint64_t periods[],
25
@@ -XXX,XX +XXX,XX @@ static NPCM7xxState *npcm7xx_create_soc(MachineState *machine,
36
zynq_slcr_compute_clock((plls), (state)->regs[reg], \
26
uint32_t hw_straps)
37
reg ## _ ## enable_field ## _SHIFT)
27
{
38
28
NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_GET_CLASS(machine);
39
+static void zynq_slcr_compute_clocks_internal(ZynqSLCRState *s, uint64_t ps_clk)
29
- MachineClass *mc = &nmc->parent;
40
+{
30
+ MachineClass *mc = MACHINE_CLASS(nmc);
41
+ uint64_t io_pll = zynq_slcr_compute_pll(ps_clk, s->regs[R_IO_PLL_CTRL]);
31
Object *obj;
42
+ uint64_t arm_pll = zynq_slcr_compute_pll(ps_clk, s->regs[R_ARM_PLL_CTRL]);
32
43
+ uint64_t ddr_pll = zynq_slcr_compute_pll(ps_clk, s->regs[R_DDR_PLL_CTRL]);
33
if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) {
44
+
34
diff --git a/hw/mem/npcm7xx_mc.c b/hw/mem/npcm7xx_mc.c
45
+ uint64_t uart_mux[4] = {io_pll, io_pll, arm_pll, ddr_pll};
35
index XXXXXXX..XXXXXXX 100644
46
+
36
--- a/hw/mem/npcm7xx_mc.c
47
+ /* compute uartX reference clocks */
37
+++ b/hw/mem/npcm7xx_mc.c
48
+ clock_set(s->uart0_ref_clk,
38
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_mc_realize(DeviceState *dev, Error **errp)
49
+ ZYNQ_COMPUTE_CLK(s, uart_mux, R_UART_CLK_CTRL, CLKACT0));
39
50
+ clock_set(s->uart1_ref_clk,
40
memory_region_init_io(&s->mmio, OBJECT(s), &npcm7xx_mc_ops, s, "regs",
51
+ ZYNQ_COMPUTE_CLK(s, uart_mux, R_UART_CLK_CTRL, CLKACT1));
41
NPCM7XX_MC_REGS_SIZE);
52
+}
42
- sysbus_init_mmio(&s->parent, &s->mmio);
53
+
43
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio);
54
/**
55
* Compute and set the ouputs clocks periods.
56
* But do not propagate them further. Connected clocks
57
@@ -XXX,XX +XXX,XX @@ static void zynq_slcr_compute_clocks(ZynqSLCRState *s)
58
ps_clk = 0;
59
}
60
61
- uint64_t io_pll = zynq_slcr_compute_pll(ps_clk, s->regs[R_IO_PLL_CTRL]);
62
- uint64_t arm_pll = zynq_slcr_compute_pll(ps_clk, s->regs[R_ARM_PLL_CTRL]);
63
- uint64_t ddr_pll = zynq_slcr_compute_pll(ps_clk, s->regs[R_DDR_PLL_CTRL]);
64
-
65
- uint64_t uart_mux[4] = {io_pll, io_pll, arm_pll, ddr_pll};
66
-
67
- /* compute uartX reference clocks */
68
- clock_set(s->uart0_ref_clk,
69
- ZYNQ_COMPUTE_CLK(s, uart_mux, R_UART_CLK_CTRL, CLKACT0));
70
- clock_set(s->uart1_ref_clk,
71
- ZYNQ_COMPUTE_CLK(s, uart_mux, R_UART_CLK_CTRL, CLKACT1));
72
+ zynq_slcr_compute_clocks_internal(s, ps_clk);
73
}
44
}
74
45
75
/**
46
static void npcm7xx_mc_class_init(ObjectClass *klass, void *data)
76
@@ -XXX,XX +XXX,XX @@ static void zynq_slcr_reset_hold(Object *obj)
47
diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
77
ZynqSLCRState *s = ZYNQ_SLCR(obj);
48
index XXXXXXX..XXXXXXX 100644
78
49
--- a/hw/misc/npcm7xx_clk.c
79
/* will disable all output clocks */
50
+++ b/hw/misc/npcm7xx_clk.c
80
- zynq_slcr_compute_clocks(s);
51
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_init(Object *obj)
81
+ zynq_slcr_compute_clocks_internal(s, 0);
52
82
zynq_slcr_propagate_clocks(s);
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);
83
}
57
}
84
58
85
@@ -XXX,XX +XXX,XX @@ static void zynq_slcr_reset_exit(Object *obj)
59
static int npcm7xx_clk_post_load(void *opaque, int version_id)
86
ZynqSLCRState *s = ZYNQ_SLCR(obj);
60
diff --git a/hw/misc/npcm7xx_gcr.c b/hw/misc/npcm7xx_gcr.c
87
61
index XXXXXXX..XXXXXXX 100644
88
/* will compute output clocks according to ps_clk and registers */
62
--- a/hw/misc/npcm7xx_gcr.c
89
- zynq_slcr_compute_clocks(s);
63
+++ b/hw/misc/npcm7xx_gcr.c
90
+ zynq_slcr_compute_clocks_internal(s, clock_get(s->ps_clk));
64
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_gcr_init(Object *obj)
91
zynq_slcr_propagate_clocks(s);
65
66
memory_region_init_io(&s->iomem, obj, &npcm7xx_gcr_ops, s,
67
TYPE_NPCM7XX_GCR, 4 * KiB);
68
- sysbus_init_mmio(&s->parent, &s->iomem);
69
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
92
}
70
}
93
71
72
static const VMStateDescription vmstate_npcm7xx_gcr = {
73
diff --git a/hw/misc/npcm7xx_rng.c b/hw/misc/npcm7xx_rng.c
74
index XXXXXXX..XXXXXXX 100644
75
--- a/hw/misc/npcm7xx_rng.c
76
+++ b/hw/misc/npcm7xx_rng.c
77
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_rng_init(Object *obj)
78
79
memory_region_init_io(&s->iomem, obj, &npcm7xx_rng_ops, s, "regs",
80
NPCM7XX_RNG_REGS_SIZE);
81
- sysbus_init_mmio(&s->parent, &s->iomem);
82
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
83
}
84
85
static const VMStateDescription vmstate_npcm7xx_rng = {
86
diff --git a/hw/nvram/npcm7xx_otp.c b/hw/nvram/npcm7xx_otp.c
87
index XXXXXXX..XXXXXXX 100644
88
--- a/hw/nvram/npcm7xx_otp.c
89
+++ b/hw/nvram/npcm7xx_otp.c
90
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_otp_realize(DeviceState *dev, Error **errp)
91
{
92
NPCM7xxOTPClass *oc = NPCM7XX_OTP_GET_CLASS(dev);
93
NPCM7xxOTPState *s = NPCM7XX_OTP(dev);
94
- SysBusDevice *sbd = &s->parent;
95
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
96
97
memset(s->array, 0, sizeof(s->array));
98
99
diff --git a/hw/ssi/npcm7xx_fiu.c b/hw/ssi/npcm7xx_fiu.c
100
index XXXXXXX..XXXXXXX 100644
101
--- a/hw/ssi/npcm7xx_fiu.c
102
+++ b/hw/ssi/npcm7xx_fiu.c
103
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_fiu_hold_reset(Object *obj)
104
static void npcm7xx_fiu_realize(DeviceState *dev, Error **errp)
105
{
106
NPCM7xxFIUState *s = NPCM7XX_FIU(dev);
107
- SysBusDevice *sbd = &s->parent;
108
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
109
int i;
110
111
if (s->cs_count <= 0) {
94
--
112
--
95
2.20.1
113
2.20.1
96
114
97
115
diff view generated by jsdifflib
Deleted patch
1
From: Bin Meng <bmeng.cn@gmail.com>
2
1
3
At present when input clock is disabled, any character transmitted
4
to tx fifo can still show on the serial line, which is wrong.
5
6
Fixes: b636db306e06 ("hw/char/cadence_uart: add clock support")
7
Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
8
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
9
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
10
Message-id: 20210901124521.30599-3-bmeng.cn@gmail.com
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
13
hw/char/cadence_uart.c | 5 +++++
14
1 file changed, 5 insertions(+)
15
16
diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/char/cadence_uart.c
19
+++ b/hw/char/cadence_uart.c
20
@@ -XXX,XX +XXX,XX @@ static gboolean cadence_uart_xmit(void *do_not_use, GIOCondition cond,
21
static void uart_write_tx_fifo(CadenceUARTState *s, const uint8_t *buf,
22
int size)
23
{
24
+ /* ignore characters when unclocked or in reset */
25
+ if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) {
26
+ return;
27
+ }
28
+
29
if ((s->r[R_CR] & UART_CR_TX_DIS) || !(s->r[R_CR] & UART_CR_TX_EN)) {
30
return;
31
}
32
--
33
2.20.1
34
35
diff view generated by jsdifflib
1
From: Bin Meng <bmeng.cn@gmail.com>
1
From: Roman Bolshakov <r.bolshakov@yadro.com>
2
2
3
Currently the clock/reset check is done in uart_receive(), but we
3
ui/cocoa.m:1188:44: warning: 'openFile:' is deprecated: first deprecated in macOS 11.0 - Use -[NSWorkspace openURL:] instead.
4
can move the check to uart_can_receive() which is earlier.
4
[-Wdeprecated-declarations]
5
if ([[NSWorkspace sharedWorkspace] openFile: full_file_path] == YES) {
6
^
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
^
5
11
6
Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
12
Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
7
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
13
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
14
Message-id: 20210102150718.47618-1-r.bolshakov@yadro.com
9
Message-id: 20210901124521.30599-4-bmeng.cn@gmail.com
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
16
---
12
hw/char/cadence_uart.c | 17 ++++++++++-------
17
ui/cocoa.m | 5 ++++-
13
1 file changed, 10 insertions(+), 7 deletions(-)
18
1 file changed, 4 insertions(+), 1 deletion(-)
14
19
15
diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
20
diff --git a/ui/cocoa.m b/ui/cocoa.m
16
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/char/cadence_uart.c
22
--- a/ui/cocoa.m
18
+++ b/hw/char/cadence_uart.c
23
+++ b/ui/cocoa.m
19
@@ -XXX,XX +XXX,XX @@ static void uart_parameters_setup(CadenceUARTState *s)
24
@@ -XXX,XX +XXX,XX @@ QemuCocoaView *cocoaView;
20
static int uart_can_receive(void *opaque)
25
/* Where to look for local files */
21
{
26
NSString *path_array[] = {@"../share/doc/qemu/", @"../doc/qemu/", @"docs/"};
22
CadenceUARTState *s = opaque;
27
NSString *full_file_path;
23
- int ret = MAX(CADENCE_UART_RX_FIFO_SIZE, CADENCE_UART_TX_FIFO_SIZE);
28
+ NSURL *full_file_url;
24
- uint32_t ch_mode = s->r[R_MR] & UART_MR_CHMODE;
29
25
+ int ret;
30
/* iterate thru the possible paths until the file is found */
26
+ uint32_t ch_mode;
31
int index;
27
+
32
@@ -XXX,XX +XXX,XX @@ QemuCocoaView *cocoaView;
28
+ /* ignore characters when unclocked or in reset */
33
full_file_path = [full_file_path stringByDeletingLastPathComponent];
29
+ if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) {
34
full_file_path = [NSString stringWithFormat: @"%@/%@%@", full_file_path,
30
+ return 0;
35
path_array[index], filename];
31
+ }
36
- if ([[NSWorkspace sharedWorkspace] openFile: full_file_path] == YES) {
32
+
37
+ full_file_url = [NSURL fileURLWithPath: full_file_path
33
+ ret = MAX(CADENCE_UART_RX_FIFO_SIZE, CADENCE_UART_TX_FIFO_SIZE);
38
+ isDirectory: false];
34
+ ch_mode = s->r[R_MR] & UART_MR_CHMODE;
39
+ if ([[NSWorkspace sharedWorkspace] openURL: full_file_url] == YES) {
35
40
return;
36
if (ch_mode == NORMAL_MODE || ch_mode == ECHO_MODE) {
41
}
37
ret = MIN(ret, CADENCE_UART_RX_FIFO_SIZE - s->rx_count);
38
@@ -XXX,XX +XXX,XX @@ static void uart_receive(void *opaque, const uint8_t *buf, int size)
39
CadenceUARTState *s = opaque;
40
uint32_t ch_mode = s->r[R_MR] & UART_MR_CHMODE;
41
42
- /* ignore characters when unclocked or in reset */
43
- if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) {
44
- return;
45
- }
46
-
47
if (ch_mode == NORMAL_MODE || ch_mode == ECHO_MODE) {
48
uart_write_rx_fifo(opaque, buf, size);
49
}
42
}
50
--
43
--
51
2.20.1
44
2.20.1
52
45
53
46
diff view generated by jsdifflib
Deleted patch
1
From: Bin Meng <bmeng.cn@gmail.com>
2
1
3
Read or write to uart registers when unclocked or in reset should be
4
ignored. Add the check there, and as a result of this, the check in
5
uart_write_tx_fifo() is now unnecessary.
6
7
Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
8
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
9
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
10
Message-id: 20210901124521.30599-6-bmeng.cn@gmail.com
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
13
hw/char/cadence_uart.c | 15 ++++++++++-----
14
1 file changed, 10 insertions(+), 5 deletions(-)
15
16
diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/char/cadence_uart.c
19
+++ b/hw/char/cadence_uart.c
20
@@ -XXX,XX +XXX,XX @@ static gboolean cadence_uart_xmit(void *do_not_use, GIOCondition cond,
21
static void uart_write_tx_fifo(CadenceUARTState *s, const uint8_t *buf,
22
int size)
23
{
24
- /* ignore characters when unclocked or in reset */
25
- if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) {
26
- return;
27
- }
28
-
29
if ((s->r[R_CR] & UART_CR_TX_DIS) || !(s->r[R_CR] & UART_CR_TX_EN)) {
30
return;
31
}
32
@@ -XXX,XX +XXX,XX @@ static MemTxResult uart_write(void *opaque, hwaddr offset,
33
{
34
CadenceUARTState *s = opaque;
35
36
+ /* ignore access when unclocked or in reset */
37
+ if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) {
38
+ return MEMTX_ERROR;
39
+ }
40
+
41
DB_PRINT(" offset:%x data:%08x\n", (unsigned)offset, (unsigned)value);
42
offset >>= 2;
43
if (offset >= CADENCE_UART_R_MAX) {
44
@@ -XXX,XX +XXX,XX @@ static MemTxResult uart_read(void *opaque, hwaddr offset,
45
CadenceUARTState *s = opaque;
46
uint32_t c = 0;
47
48
+ /* ignore access when unclocked or in reset */
49
+ if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) {
50
+ return MEMTX_ERROR;
51
+ }
52
+
53
offset >>= 2;
54
if (offset >= CADENCE_UART_R_MAX) {
55
return MEMTX_DECODE_ERROR;
56
--
57
2.20.1
58
59
diff view generated by jsdifflib