1
The following changes since commit 64ada298b98a51eb2512607f6e6180cb330c47b1:
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/legoater/tags/pull-ppc-20220302' into staging (2022-03-02 12:38:46 +0000)
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-20220302
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 268c11984e67867c22f53beb3c7f8b98900d66b2:
16
for you to fetch changes up to 19d131395ccaf503db21dadd8257e6dc9fc1d7de:
10
17
11
ui/cocoa.m: Remove unnecessary NSAutoreleasePools (2022-03-02 19:27:37 +0000)
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
* mps3-an547: Add missing user ahb interfaces
22
* arm: Support emulation of ARMv8.4-TTST extension
16
* hw/arm/mps2-tz.c: Update AN547 documentation URL
23
* arm: Update cpu.h ID register field definitions
17
* hw/input/tsc210x: Don't abort on bad SPI word widths
24
* arm: Fix breakage of XScale instruction emulation
18
* hw/i2c: flatten pca954x mux device
25
* hw/net/lan9118: Fix RX Status FIFO PEEK value
19
* target/arm: Support PSCI 1.1 and SMCCC 1.0
26
* npcm7xx: Add ADC and PWM emulation
20
* target/arm: Fix early free of TCG temp in handle_simd_shift_fpint_conv()
27
* ui/cocoa: Make "open docs" help menu entry work again when binary
21
* tests/qtest: add qtests for npcm7xx sdhci
28
is run from the build tree
22
* Implement FEAT_LVA
29
* ui/cocoa: Fix openFile: deprecation on Big Sur
23
* Implement FEAT_LPA
30
* docs: Add qemu-storage-daemon(1) manpage to meson.build
24
* Implement FEAT_LPA2 (but do not enable it yet)
31
* docs: Build and install all the docs in a single manual
25
* Report KVM's actual PSCI version to guest in dtb
26
* ui/cocoa.m: Fix updateUIInfo threading issues
27
* ui/cocoa.m: Remove unnecessary NSAutoreleasePools
28
32
29
----------------------------------------------------------------
33
----------------------------------------------------------------
30
Akihiko Odaki (1):
34
Hao Wu (6):
31
target/arm: Support PSCI 1.1 and SMCCC 1.0
35
hw/misc: Add clock converter in NPCM7XX CLK module
36
hw/timer: Refactor NPCM7XX Timer to use CLK clock
37
hw/adc: Add an ADC module for NPCM7XX
38
hw/misc: Add a PWM module for NPCM7XX
39
hw/misc: Add QTest for NPCM7XX PWM Module
40
hw/*: Use type casting for SysBusDevice in NPCM7XX
32
41
33
Jimmy Brisson (1):
42
Leif Lindholm (6):
34
mps3-an547: Add missing user ahb interfaces
43
target/arm: fix typo in cpu.h ID_AA64PFR1 field name
35
44
target/arm: make ARMCPU.clidr 64-bit
36
Patrick Venture (1):
45
target/arm: make ARMCPU.ctr 64-bit
37
hw/i2c: flatten pca954x mux device
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
hw/arm/mps2-tz.c: Update AN547 documentation URL
51
docs: Add qemu-storage-daemon(1) manpage to meson.build
41
hw/input/tsc210x: Don't abort on bad SPI word widths
52
docs: Build and install all the docs in a single manual
42
target/arm: Report KVM's actual PSCI version to guest in dtb
53
target/arm: Don't decode insns in the XScale/iWMMXt space as cp insns
43
ui/cocoa.m: Fix updateUIInfo threading issues
54
hw/net/lan9118: Fix RX Status FIFO PEEK value
44
ui/cocoa.m: Remove unnecessary NSAutoreleasePools
55
hw/net/lan9118: Add symbolic constants for register offsets
45
56
46
Richard Henderson (16):
57
Roman Bolshakov (2):
47
hw/registerfields: Add FIELD_SEX<N> and FIELD_SDP<N>
58
ui/cocoa: Update path to docs in build tree
48
target/arm: Set TCR_EL1.TSZ for user-only
59
ui/cocoa: Fix openFile: deprecation on Big Sur
49
target/arm: Fault on invalid TCR_ELx.TxSZ
50
target/arm: Move arm_pamax out of line
51
target/arm: Pass outputsize down to check_s2_mmu_setup
52
target/arm: Use MAKE_64BIT_MASK to compute indexmask
53
target/arm: Honor TCR_ELx.{I}PS
54
target/arm: Prepare DBGBVR and DBGWVR for FEAT_LVA
55
target/arm: Implement FEAT_LVA
56
target/arm: Implement FEAT_LPA
57
target/arm: Extend arm_fi_to_lfsc to level -1
58
target/arm: Introduce tlbi_aa64_get_range
59
target/arm: Fix TLBIRange.base for 16k and 64k pages
60
target/arm: Validate tlbi TG matches translation granule in use
61
target/arm: Advertise all page sizes for -cpu max
62
target/arm: Implement FEAT_LPA2
63
60
64
Shengtan Mao (1):
61
Rémi Denis-Courmont (2):
65
tests/qtest: add qtests for npcm7xx sdhci
62
target/arm: ARMv8.4-TTST extension
63
target/arm: enable Small Translation tables in max CPU
66
64
67
Wentao_Liang (1):
65
docs/conf.py | 46 ++-
68
target/arm: Fix early free of TCG temp in handle_simd_shift_fpint_conv()
66
docs/devel/conf.py | 15 -
67
docs/index.html.in | 17 -
68
docs/interop/conf.py | 28 --
69
docs/meson.build | 65 ++--
70
docs/specs/conf.py | 16 -
71
docs/system/arm/nuvoton.rst | 4 +-
72
docs/system/conf.py | 28 --
73
docs/tools/conf.py | 37 --
74
docs/user/conf.py | 15 -
75
meson.build | 1 +
76
hw/adc/trace.h | 1 +
77
include/hw/adc/npcm7xx_adc.h | 69 ++++
78
include/hw/arm/npcm7xx.h | 4 +
79
include/hw/misc/npcm7xx_clk.h | 146 ++++++-
80
include/hw/misc/npcm7xx_pwm.h | 105 +++++
81
include/hw/timer/npcm7xx_timer.h | 1 +
82
target/arm/cpu.h | 85 ++++-
83
hw/adc/npcm7xx_adc.c | 301 +++++++++++++++
84
hw/arm/npcm7xx.c | 55 ++-
85
hw/arm/npcm7xx_boards.c | 2 +-
86
hw/mem/npcm7xx_mc.c | 2 +-
87
hw/misc/npcm7xx_clk.c | 807 ++++++++++++++++++++++++++++++++++++++-
88
hw/misc/npcm7xx_gcr.c | 2 +-
89
hw/misc/npcm7xx_pwm.c | 550 ++++++++++++++++++++++++++
90
hw/misc/npcm7xx_rng.c | 2 +-
91
hw/net/lan9118.c | 26 +-
92
hw/nvram/npcm7xx_otp.c | 2 +-
93
hw/ssi/npcm7xx_fiu.c | 2 +-
94
hw/timer/npcm7xx_timer.c | 39 +-
95
target/arm/cpu64.c | 1 +
96
target/arm/helper.c | 15 +-
97
target/arm/translate.c | 7 +
98
tests/qtest/npcm7xx_adc-test.c | 377 ++++++++++++++++++
99
tests/qtest/npcm7xx_pwm-test.c | 490 ++++++++++++++++++++++++
100
hw/adc/meson.build | 1 +
101
hw/adc/trace-events | 5 +
102
hw/misc/meson.build | 1 +
103
hw/misc/trace-events | 6 +
104
tests/qtest/meson.build | 4 +-
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
69
122
70
docs/system/arm/emulation.rst | 3 +
71
include/hw/registerfields.h | 48 +++++-
72
target/arm/cpu-param.h | 4 +-
73
target/arm/cpu.h | 27 ++++
74
target/arm/internals.h | 58 ++++---
75
target/arm/kvm-consts.h | 14 +-
76
hw/arm/boot.c | 11 +-
77
hw/arm/mps2-tz.c | 6 +-
78
hw/i2c/i2c_mux_pca954x.c | 77 ++-------
79
hw/input/tsc210x.c | 8 +-
80
target/arm/cpu.c | 8 +-
81
target/arm/cpu64.c | 7 +-
82
target/arm/helper.c | 332 ++++++++++++++++++++++++++++++---------
83
target/arm/hvf/hvf.c | 27 +++-
84
target/arm/kvm64.c | 14 +-
85
target/arm/psci.c | 35 ++++-
86
target/arm/translate-a64.c | 2 +-
87
tests/qtest/npcm7xx_sdhci-test.c | 215 +++++++++++++++++++++++++
88
tests/qtest/meson.build | 1 +
89
ui/cocoa.m | 31 ++--
90
20 files changed, 736 insertions(+), 192 deletions(-)
91
create mode 100644 tests/qtest/npcm7xx_sdhci-test.c
diff view generated by jsdifflib
Deleted patch
1
From: Jimmy Brisson <jimmy.brisson@linaro.org>
2
1
3
With these interfaces missing, TFM would delegate peripherals 0, 1,
4
2, 3 and 8, and qemu would ignore the delegation of interface 8, as
5
it thought interface 4 was eth & USB.
6
7
This patch corrects this behavior and allows TFM to delegate the
8
eth & USB peripheral to NS mode.
9
10
(The old QEMU behaviour was based on revision B of the AN547
11
appnote; revision C corrects this error in the documentation,
12
and this commit brings QEMU in to line with how the FPGA
13
image really behaves.)
14
15
Signed-off-by: Jimmy Brisson <jimmy.brisson@linaro.org>
16
Message-id: 20220210210227.3203883-1-jimmy.brisson@linaro.org
17
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
18
[PMM: added commit message note clarifying that the old behaviour
19
was a docs issue, not because there were two different versions
20
of the FPGA image]
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
22
---
23
hw/arm/mps2-tz.c | 4 ++++
24
1 file changed, 4 insertions(+)
25
26
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
27
index XXXXXXX..XXXXXXX 100644
28
--- a/hw/arm/mps2-tz.c
29
+++ b/hw/arm/mps2-tz.c
30
@@ -XXX,XX +XXX,XX @@ static void mps2tz_common_init(MachineState *machine)
31
{ "gpio1", make_unimp_dev, &mms->gpio[1], 0x41101000, 0x1000 },
32
{ "gpio2", make_unimp_dev, &mms->gpio[2], 0x41102000, 0x1000 },
33
{ "gpio3", make_unimp_dev, &mms->gpio[3], 0x41103000, 0x1000 },
34
+ { /* port 4 USER AHB interface 0 */ },
35
+ { /* port 5 USER AHB interface 1 */ },
36
+ { /* port 6 USER AHB interface 2 */ },
37
+ { /* port 7 USER AHB interface 3 */ },
38
{ "eth-usb", make_eth_usb, NULL, 0x41400000, 0x200000, { 49 } },
39
},
40
},
41
--
42
2.25.1
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
This feature widens physical addresses (and intermediate physical
3
This adds for the Small Translation tables extension in AArch64 state.
4
addresses for 2-stage translation) from 48 to 52 bits, when using
5
4k or 16k pages.
6
4
7
This introduces the DS bit to TCR_ELx, which is RES0 unless the
5
Signed-off-by: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
8
page size is enabled and supports LPA2, resulting in the effective
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
value of DS for a given table walk. The DS bit changes the format
10
of the page table descriptor slightly, moving the PS field out to
11
TCR so that all pages have the same sharability and repurposing
12
those bits of the page table descriptor for the highest bits of
13
the output address.
14
15
Do not yet enable FEAT_LPA2; we need extra plumbing to avoid
16
tickling an old kernel bug.
17
18
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
19
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
20
Message-id: 20220301215958.157011-17-richard.henderson@linaro.org
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
22
---
8
---
23
docs/system/arm/emulation.rst | 1 +
9
target/arm/cpu.h | 5 +++++
24
target/arm/cpu.h | 22 ++++++++
10
target/arm/helper.c | 15 +++++++++++++--
25
target/arm/internals.h | 2 +
11
2 files changed, 18 insertions(+), 2 deletions(-)
26
target/arm/helper.c | 102 +++++++++++++++++++++++++++++-----
27
4 files changed, 112 insertions(+), 15 deletions(-)
28
12
29
diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst
30
index XXXXXXX..XXXXXXX 100644
31
--- a/docs/system/arm/emulation.rst
32
+++ b/docs/system/arm/emulation.rst
33
@@ -XXX,XX +XXX,XX @@ the following architecture extensions:
34
- FEAT_JSCVT (JavaScript conversion instructions)
35
- FEAT_LOR (Limited ordering regions)
36
- FEAT_LPA (Large Physical Address space)
37
+- FEAT_LPA2 (Large Physical and virtual Address space v2)
38
- FEAT_LRCPC (Load-acquire RCpc instructions)
39
- FEAT_LRCPC2 (Load-acquire RCpc instructions v2)
40
- FEAT_LSE (Large System Extensions)
41
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
42
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
43
--- a/target/arm/cpu.h
15
--- a/target/arm/cpu.h
44
+++ b/target/arm/cpu.h
16
+++ b/target/arm/cpu.h
45
@@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_i8mm(const ARMISARegisters *id)
17
@@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_uao(const ARMISARegisters *id)
46
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, I8MM) != 0;
18
return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, UAO) != 0;
47
}
19
}
48
20
49
+static inline bool isar_feature_aa64_tgran4_lpa2(const ARMISARegisters *id)
21
+static inline bool isar_feature_aa64_st(const ARMISARegisters *id)
50
+{
22
+{
51
+ return FIELD_SEX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN4) >= 1;
23
+ return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, ST) != 0;
52
+}
24
+}
53
+
25
+
54
+static inline bool isar_feature_aa64_tgran4_2_lpa2(const ARMISARegisters *id)
26
static inline bool isar_feature_aa64_bti(const ARMISARegisters *id)
55
+{
56
+ unsigned t = FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN4_2);
57
+ return t >= 3 || (t == 0 && isar_feature_aa64_tgran4_lpa2(id));
58
+}
59
+
60
+static inline bool isar_feature_aa64_tgran16_lpa2(const ARMISARegisters *id)
61
+{
62
+ return FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN16) >= 2;
63
+}
64
+
65
+static inline bool isar_feature_aa64_tgran16_2_lpa2(const ARMISARegisters *id)
66
+{
67
+ unsigned t = FIELD_EX64(id->id_aa64mmfr0, ID_AA64MMFR0, TGRAN16_2);
68
+ return t >= 3 || (t == 0 && isar_feature_aa64_tgran16_lpa2(id));
69
+}
70
+
71
static inline bool isar_feature_aa64_ccidx(const ARMISARegisters *id)
72
{
27
{
73
return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, CCIDX) != 0;
28
return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0;
74
diff --git a/target/arm/internals.h b/target/arm/internals.h
75
index XXXXXXX..XXXXXXX 100644
76
--- a/target/arm/internals.h
77
+++ b/target/arm/internals.h
78
@@ -XXX,XX +XXX,XX @@ static inline uint32_t aarch64_pstate_valid_mask(const ARMISARegisters *id)
79
typedef struct ARMVAParameters {
80
unsigned tsz : 8;
81
unsigned ps : 3;
82
+ unsigned sh : 2;
83
unsigned select : 1;
84
bool tbi : 1;
85
bool epd : 1;
86
@@ -XXX,XX +XXX,XX @@ typedef struct ARMVAParameters {
87
bool using16k : 1;
88
bool using64k : 1;
89
bool tsz_oob : 1; /* tsz has been clamped to legal range */
90
+ bool ds : 1;
91
} ARMVAParameters;
92
93
ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
94
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
95
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
96
--- a/target/arm/helper.c
31
--- a/target/arm/helper.c
97
+++ b/target/arm/helper.c
32
+++ b/target/arm/helper.c
98
@@ -XXX,XX +XXX,XX @@ static TLBIRange tlbi_aa64_get_range(CPUARMState *env, ARMMMUIdx mmuidx,
99
} else {
100
ret.base = extract64(value, 0, 37);
101
}
102
+ if (param.ds) {
103
+ /*
104
+ * With DS=1, BaseADDR is always shifted 16 so that it is able
105
+ * to address all 52 va bits. The input address is perforce
106
+ * aligned on a 64k boundary regardless of translation granule.
107
+ */
108
+ page_shift = 16;
109
+ }
110
ret.base <<= page_shift;
111
112
return ret;
113
@@ -XXX,XX +XXX,XX @@ static bool check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, int level,
114
const int grainsize = stride + 3;
115
int startsizecheck;
116
117
- /* Negative levels are never allowed. */
118
- if (level < 0) {
119
+ /*
120
+ * Negative levels are usually not allowed...
121
+ * Except for FEAT_LPA2, 4k page table, 52-bit address space, which
122
+ * begins with level -1. Note that previous feature tests will have
123
+ * eliminated this combination if it is not enabled.
124
+ */
125
+ if (level < (inputsize == 52 && stride == 9 ? -1 : 0)) {
126
return false;
127
}
128
129
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
33
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
130
ARMMMUIdx mmu_idx, bool data)
131
{
34
{
132
uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr;
35
uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr;
133
- bool epd, hpd, using16k, using64k, tsz_oob;
36
bool epd, hpd, using16k, using64k;
134
- int select, tsz, tbi, max_tsz, min_tsz, ps;
37
- int select, tsz, tbi;
135
+ bool epd, hpd, using16k, using64k, tsz_oob, ds;
38
+ int select, tsz, tbi, max_tsz;
136
+ int select, tsz, tbi, max_tsz, min_tsz, ps, sh;
137
+ ARMCPU *cpu = env_archcpu(env);
138
39
139
if (!regime_has_2_ranges(mmu_idx)) {
40
if (!regime_has_2_ranges(mmu_idx)) {
140
select = 0;
41
select = 0;
141
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
42
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
142
hpd = extract32(tcr, 24, 1);
143
}
144
epd = false;
145
+ sh = extract32(tcr, 12, 2);
146
ps = extract32(tcr, 16, 3);
147
+ ds = extract64(tcr, 32, 1);
148
} else {
149
/*
150
* Bit 55 is always between the two regions, and is canonical for
151
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
152
if (!select) {
153
tsz = extract32(tcr, 0, 6);
154
epd = extract32(tcr, 7, 1);
155
+ sh = extract32(tcr, 12, 2);
156
using64k = extract32(tcr, 14, 1);
157
using16k = extract32(tcr, 15, 1);
158
hpd = extract64(tcr, 41, 1);
159
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
160
using64k = tg == 3;
161
tsz = extract32(tcr, 16, 6);
162
epd = extract32(tcr, 23, 1);
163
+ sh = extract32(tcr, 28, 2);
164
hpd = extract64(tcr, 42, 1);
43
hpd = extract64(tcr, 42, 1);
165
}
44
}
166
ps = extract64(tcr, 32, 3);
167
+ ds = extract64(tcr, 59, 1);
168
}
45
}
169
46
- tsz = MIN(tsz, 39); /* TODO: ARMv8.4-TTST */
170
- if (cpu_isar_feature(aa64_st, env_archcpu(env))) {
47
+
171
+ if (cpu_isar_feature(aa64_st, cpu)) {
48
+ if (cpu_isar_feature(aa64_st, env_archcpu(env))) {
172
max_tsz = 48 - using64k;
49
+ max_tsz = 48 - using64k;
173
} else {
50
+ } else {
174
max_tsz = 39;
51
+ max_tsz = 39;
175
}
52
+ }
176
53
+
177
+ /*
54
+ tsz = MIN(tsz, max_tsz);
178
+ * DS is RES0 unless FEAT_LPA2 is supported for the given page size;
55
tsz = MAX(tsz, 16); /* TODO: ARMv8.2-LVA */
179
+ * adjust the effective value of DS, as documented.
56
180
+ */
57
/* Present TBI as a composite with TBID. */
181
min_tsz = 16;
182
if (using64k) {
183
- if (cpu_isar_feature(aa64_lva, env_archcpu(env))) {
184
+ if (cpu_isar_feature(aa64_lva, cpu)) {
185
+ min_tsz = 12;
186
+ }
187
+ ds = false;
188
+ } else if (ds) {
189
+ switch (mmu_idx) {
190
+ case ARMMMUIdx_Stage2:
191
+ case ARMMMUIdx_Stage2_S:
192
+ if (using16k) {
193
+ ds = cpu_isar_feature(aa64_tgran16_2_lpa2, cpu);
194
+ } else {
195
+ ds = cpu_isar_feature(aa64_tgran4_2_lpa2, cpu);
196
+ }
197
+ break;
198
+ default:
199
+ if (using16k) {
200
+ ds = cpu_isar_feature(aa64_tgran16_lpa2, cpu);
201
+ } else {
202
+ ds = cpu_isar_feature(aa64_tgran4_lpa2, cpu);
203
+ }
204
+ break;
205
+ }
206
+ if (ds) {
207
min_tsz = 12;
208
}
209
}
210
- /* TODO: FEAT_LPA2 */
211
212
if (tsz > max_tsz) {
213
tsz = max_tsz;
214
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
215
return (ARMVAParameters) {
216
.tsz = tsz,
217
.ps = ps,
218
+ .sh = sh,
219
.select = select,
220
.tbi = tbi,
221
.epd = epd,
222
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
223
.using16k = using16k,
224
.using64k = using64k,
225
.tsz_oob = tsz_oob,
226
+ .ds = ds,
227
};
228
}
229
230
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
58
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
231
* VTCR_EL2.SL0 field (whose interpretation depends on the page size)
59
if (!aarch64 || stride == 9) {
232
*/
233
uint32_t sl0 = extract32(tcr->raw_tcr, 6, 2);
234
+ uint32_t sl2 = extract64(tcr->raw_tcr, 33, 1);
235
uint32_t startlevel;
236
bool ok;
237
238
- if (!aarch64 || stride == 9) {
239
+ /* SL2 is RES0 unless DS=1 & 4kb granule. */
240
+ if (param.ds && stride == 9 && sl2) {
241
+ if (sl0 != 0) {
242
+ level = 0;
243
+ fault_type = ARMFault_Translation;
244
+ goto do_fault;
245
+ }
246
+ startlevel = -1;
247
+ } else if (!aarch64 || stride == 9) {
248
/* AArch32 or 4KB pages */
60
/* AArch32 or 4KB pages */
249
startlevel = 2 - sl0;
61
startlevel = 2 - sl0;
250
62
+
251
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
63
+ if (cpu_isar_feature(aa64_st, cpu)) {
252
* for both v7 and v8. However, for v8 the SBZ bits [47:40] must be 0
64
+ startlevel &= 3;
253
* or an AddressSize fault is raised. So for v8 we extract those SBZ
254
* bits as part of the address, which will be checked via outputsize.
255
- * For AArch64, the address field always goes up to bit 47 (with extra
256
- * bits for FEAT_LPA placed elsewhere). AArch64 implies v8.
257
+ * For AArch64, the address field goes up to bit 47, or 49 with FEAT_LPA2;
258
+ * the highest bits of a 52-bit output are placed elsewhere.
259
*/
260
- if (arm_feature(env, ARM_FEATURE_V8)) {
261
+ if (param.ds) {
262
+ descaddrmask = MAKE_64BIT_MASK(0, 50);
263
+ } else if (arm_feature(env, ARM_FEATURE_V8)) {
264
descaddrmask = MAKE_64BIT_MASK(0, 48);
265
} else {
266
descaddrmask = MAKE_64BIT_MASK(0, 40);
267
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
268
269
/*
270
* For FEAT_LPA and PS=6, bits [51:48] of descaddr are in [15:12]
271
- * of descriptor. Otherwise, if descaddr is out of range, raise
272
- * AddressSizeFault.
273
+ * of descriptor. For FEAT_LPA2 and effective DS, bits [51:50] of
274
+ * descaddr are in [9:8]. Otherwise, if descaddr is out of range,
275
+ * raise AddressSizeFault.
276
*/
277
if (outputsize > 48) {
278
- descaddr |= extract64(descriptor, 12, 4) << 48;
279
+ if (param.ds) {
280
+ descaddr |= extract64(descriptor, 8, 2) << 50;
281
+ } else {
282
+ descaddr |= extract64(descriptor, 12, 4) << 48;
283
+ }
65
+ }
284
} else if (descaddr >> outputsize) {
66
} else {
285
fault_type = ARMFault_AddressSize;
67
/* 16KB or 64KB pages */
286
goto do_fault;
68
startlevel = 3 - sl0;
287
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
288
assert(attrindx <= 7);
289
cacheattrs->attrs = extract64(mair, attrindx * 8, 8);
290
}
291
- cacheattrs->shareability = extract32(attrs, 6, 2);
292
+
293
+ /*
294
+ * For FEAT_LPA2 and effective DS, the SH field in the attributes
295
+ * was re-purposed for output address bits. The SH attribute in
296
+ * that case comes from TCR_ELx, which we extracted earlier.
297
+ */
298
+ if (param.ds) {
299
+ cacheattrs->shareability = param.sh;
300
+ } else {
301
+ cacheattrs->shareability = extract32(attrs, 6, 2);
302
+ }
303
304
*phys_ptr = descaddr;
305
*page_size_ptr = page_size;
306
--
69
--
307
2.25.1
70
2.20.1
71
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
We support 16k pages, but do not advertize that in ID_AA64MMFR0.
3
Signed-off-by: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
4
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
The value 0 in the TGRAN*_2 fields indicates that stage2 lookups defer
6
to the same support as stage1 lookups. This setting is deprecated, so
7
indicate support for all stage2 page sizes directly.
8
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Message-id: 20220301215958.157011-16-richard.henderson@linaro.org
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
6
---
14
target/arm/cpu64.c | 4 ++++
7
target/arm/cpu64.c | 1 +
15
1 file changed, 4 insertions(+)
8
1 file changed, 1 insertion(+)
16
9
17
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
10
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
18
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/cpu64.c
12
--- a/target/arm/cpu64.c
20
+++ b/target/arm/cpu64.c
13
+++ b/target/arm/cpu64.c
21
@@ -XXX,XX +XXX,XX @@ static void aarch64_max_initfn(Object *obj)
14
@@ -XXX,XX +XXX,XX @@ static void aarch64_max_initfn(Object *obj)
22
15
t = cpu->isar.id_aa64mmfr2;
23
t = cpu->isar.id_aa64mmfr0;
16
t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1);
24
t = FIELD_DP64(t, ID_AA64MMFR0, PARANGE, 6); /* FEAT_LPA: 52 bits */
17
t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* TTCNP */
25
+ t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN16, 1); /* 16k pages supported */
18
+ t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* TTST */
26
+ t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN16_2, 2); /* 16k stage2 supported */
19
cpu->isar.id_aa64mmfr2 = t;
27
+ t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN64_2, 2); /* 64k stage2 supported */
20
28
+ t = FIELD_DP64(t, ID_AA64MMFR0, TGRAN4_2, 2); /* 4k stage2 supported */
21
/* Replicate the same data to the 32-bit id registers. */
29
cpu->isar.id_aa64mmfr0 = t;
30
31
t = cpu->isar.id_aa64mmfr1;
32
--
22
--
33
2.25.1
23
2.20.1
24
25
diff view generated by jsdifflib
1
From: Wentao_Liang <Wentao_Liang_g@163.com>
1
From: Leif Lindholm <leif@nuviainc.com>
2
2
3
handle_simd_shift_fpint_conv() was accidentally freeing the TCG
3
SBSS -> SSBS
4
temporary tcg_fpstatus too early, before the last use of it. Move
5
the free down to where it belongs.
6
4
7
Signed-off-by: Wentao_Liang <Wentao_Liang_g@163.com>
5
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
[PMM: cleaned up commit message]
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
9
Message-id: 20210108185154.8108-2-leif@nuviainc.com
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
11
---
12
target/arm/translate-a64.c | 2 +-
12
target/arm/cpu.h | 2 +-
13
1 file changed, 1 insertion(+), 1 deletion(-)
13
1 file changed, 1 insertion(+), 1 deletion(-)
14
14
15
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
15
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
16
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/translate-a64.c
17
--- a/target/arm/cpu.h
18
+++ b/target/arm/translate-a64.c
18
+++ b/target/arm/cpu.h
19
@@ -XXX,XX +XXX,XX @@ static void handle_simd_shift_fpint_conv(DisasContext *s, bool is_scalar,
19
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64PFR0, RAS, 28, 4)
20
}
20
FIELD(ID_AA64PFR0, SVE, 32, 4)
21
}
21
22
22
FIELD(ID_AA64PFR1, BT, 0, 4)
23
- tcg_temp_free_ptr(tcg_fpstatus);
23
-FIELD(ID_AA64PFR1, SBSS, 4, 4)
24
tcg_temp_free_i32(tcg_shift);
24
+FIELD(ID_AA64PFR1, SSBS, 4, 4)
25
gen_helper_set_rmode(tcg_rmode, tcg_rmode, tcg_fpstatus);
25
FIELD(ID_AA64PFR1, MTE, 8, 4)
26
+ tcg_temp_free_ptr(tcg_fpstatus);
26
FIELD(ID_AA64PFR1, RAS_FRAC, 12, 4)
27
tcg_temp_free_i32(tcg_rmode);
28
}
29
27
30
--
28
--
31
2.25.1
29
2.20.1
30
31
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Leif Lindholm <leif@nuviainc.com>
2
2
3
For FEAT_LPA2, we will need other ARMVAParameters, which themselves
3
The AArch64 view of CLIDR_EL1 extends the ICB field to include also bit
4
depend on the translation granule in use. We might as well validate
4
32, as well as adding a Ttype<n> field when FEAT_MTE is implemented.
5
that the given TG matches; the architecture "does not require that
5
Extend the clidr field to be able to hold this context.
6
the instruction invalidates any entries" if this is not true.
7
6
7
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
10
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
10
Message-id: 20220301215958.157011-15-richard.henderson@linaro.org
11
Message-id: 20210108185154.8108-3-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
target/arm/helper.c | 10 +++++++---
14
target/arm/cpu.h | 2 +-
14
1 file changed, 7 insertions(+), 3 deletions(-)
15
1 file changed, 1 insertion(+), 1 deletion(-)
15
16
16
diff --git a/target/arm/helper.c b/target/arm/helper.c
17
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
17
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
18
--- a/target/arm/helper.c
19
--- a/target/arm/cpu.h
19
+++ b/target/arm/helper.c
20
+++ b/target/arm/cpu.h
20
@@ -XXX,XX +XXX,XX @@ static TLBIRange tlbi_aa64_get_range(CPUARMState *env, ARMMMUIdx mmuidx,
21
@@ -XXX,XX +XXX,XX @@ struct ARMCPU {
21
uint64_t value)
22
uint32_t id_afr0;
22
{
23
uint64_t id_aa64afr0;
23
unsigned int page_size_granule, page_shift, num, scale, exponent;
24
uint64_t id_aa64afr1;
24
+ /* Extract one bit to represent the va selector in use. */
25
- uint32_t clidr;
25
+ uint64_t select = sextract64(value, 36, 1);
26
+ uint64_t clidr;
26
+ ARMVAParameters param = aa64_va_parameters(env, select, mmuidx, true);
27
uint64_t mp_affinity; /* MP ID without feature bits */
27
TLBIRange ret = { };
28
/* The elements of this array are the CCSIDR values for each cache,
28
29
* in the order L1DCache, L1ICache, L2DCache, L2ICache, etc.
29
page_size_granule = extract64(value, 46, 2);
30
31
- if (page_size_granule == 0) {
32
- qemu_log_mask(LOG_GUEST_ERROR, "Invalid page size granule %d\n",
33
+ /* The granule encoded in value must match the granule in use. */
34
+ if (page_size_granule != (param.using64k ? 3 : param.using16k ? 2 : 1)) {
35
+ qemu_log_mask(LOG_GUEST_ERROR, "Invalid tlbi page size granule %d\n",
36
page_size_granule);
37
return ret;
38
}
39
@@ -XXX,XX +XXX,XX @@ static TLBIRange tlbi_aa64_get_range(CPUARMState *env, ARMMMUIdx mmuidx,
40
41
ret.length = (num + 1) << (exponent + page_shift);
42
43
- if (regime_has_2_ranges(mmuidx)) {
44
+ if (param.select) {
45
ret.base = sextract64(value, 0, 37);
46
} else {
47
ret.base = extract64(value, 0, 37);
48
--
30
--
49
2.25.1
31
2.20.1
32
33
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Leif Lindholm <leif@nuviainc.com>
2
2
3
The shift of the BaseADDR field depends on the translation
3
When FEAT_MTE is implemented, the AArch64 view of CTR_EL0 adds the
4
granule in use.
4
TminLine field in bits [37:32].
5
Extend the ctr field to be able to hold this context.
5
6
6
Fixes: 84940ed8255 ("target/arm: Add support for FEAT_TLBIRANGE")
7
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
7
Reported-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Hao Wu <wuhaotsh@google.com>
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
10
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
10
Message-id: 20220301215958.157011-14-richard.henderson@linaro.org
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
target/arm/helper.c | 5 +++--
14
target/arm/cpu.h | 2 +-
14
1 file changed, 3 insertions(+), 2 deletions(-)
15
1 file changed, 1 insertion(+), 1 deletion(-)
15
16
16
diff --git a/target/arm/helper.c b/target/arm/helper.c
17
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
17
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
18
--- a/target/arm/helper.c
19
--- a/target/arm/cpu.h
19
+++ b/target/arm/helper.c
20
+++ b/target/arm/cpu.h
20
@@ -XXX,XX +XXX,XX @@ static TLBIRange tlbi_aa64_get_range(CPUARMState *env, ARMMMUIdx mmuidx,
21
@@ -XXX,XX +XXX,XX @@ struct ARMCPU {
21
ret.length = (num + 1) << (exponent + page_shift);
22
uint64_t midr;
22
23
uint32_t revidr;
23
if (regime_has_2_ranges(mmuidx)) {
24
uint32_t reset_fpsid;
24
- ret.base = sextract64(value, 0, 37) << TARGET_PAGE_BITS;
25
- uint32_t ctr;
25
+ ret.base = sextract64(value, 0, 37);
26
+ uint64_t ctr;
26
} else {
27
uint32_t reset_sctlr;
27
- ret.base = extract64(value, 0, 37) << TARGET_PAGE_BITS;
28
uint64_t pmceid0;
28
+ ret.base = extract64(value, 0, 37);
29
uint64_t pmceid1;
29
}
30
+ ret.base <<= page_shift;
31
32
return ret;
33
}
34
--
30
--
35
2.25.1
31
2.20.1
32
33
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Leif Lindholm <leif@nuviainc.com>
2
2
3
This feature is relatively small, as it applies only to
3
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
4
64k pages and thus requires no additional changes to the
4
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
5
table descriptor walking algorithm, only a change to the
5
Message-id: 20210108185154.8108-5-leif@nuviainc.com
6
minimum TSZ (which is the inverse of the maximum virtual
7
address space size).
8
9
Note that this feature widens VBAR_ELx, but we already
10
treat the register as being 64 bits wide.
11
12
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
13
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
14
Message-id: 20220301215958.157011-10-richard.henderson@linaro.org
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
---
7
---
17
docs/system/arm/emulation.rst | 1 +
8
target/arm/cpu.h | 31 +++++++++++++++++++++++++++++++
18
target/arm/cpu-param.h | 2 +-
9
1 file changed, 31 insertions(+)
19
target/arm/cpu.h | 5 +++++
20
target/arm/cpu64.c | 1 +
21
target/arm/helper.c | 9 ++++++++-
22
5 files changed, 16 insertions(+), 2 deletions(-)
23
10
24
diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst
25
index XXXXXXX..XXXXXXX 100644
26
--- a/docs/system/arm/emulation.rst
27
+++ b/docs/system/arm/emulation.rst
28
@@ -XXX,XX +XXX,XX @@ the following architecture extensions:
29
- FEAT_LRCPC (Load-acquire RCpc instructions)
30
- FEAT_LRCPC2 (Load-acquire RCpc instructions v2)
31
- FEAT_LSE (Large System Extensions)
32
+- FEAT_LVA (Large Virtual Address space)
33
- FEAT_MTE (Memory Tagging Extension)
34
- FEAT_MTE2 (Memory Tagging Extension)
35
- FEAT_MTE3 (MTE Asymmetric Fault Handling)
36
diff --git a/target/arm/cpu-param.h b/target/arm/cpu-param.h
37
index XXXXXXX..XXXXXXX 100644
38
--- a/target/arm/cpu-param.h
39
+++ b/target/arm/cpu-param.h
40
@@ -XXX,XX +XXX,XX @@
41
#ifdef TARGET_AARCH64
42
# define TARGET_LONG_BITS 64
43
# define TARGET_PHYS_ADDR_SPACE_BITS 48
44
-# define TARGET_VIRT_ADDR_SPACE_BITS 48
45
+# define TARGET_VIRT_ADDR_SPACE_BITS 52
46
#else
47
# define TARGET_LONG_BITS 32
48
# define TARGET_PHYS_ADDR_SPACE_BITS 40
49
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
11
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
50
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
51
--- a/target/arm/cpu.h
13
--- a/target/arm/cpu.h
52
+++ b/target/arm/cpu.h
14
+++ b/target/arm/cpu.h
53
@@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_ccidx(const ARMISARegisters *id)
15
@@ -XXX,XX +XXX,XX @@ FIELD(V7M_FPCCR, ASPEN, 31, 1)
54
return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, CCIDX) != 0;
16
/*
55
}
17
* System register ID fields.
56
18
*/
57
+static inline bool isar_feature_aa64_lva(const ARMISARegisters *id)
19
+FIELD(CLIDR_EL1, CTYPE1, 0, 3)
58
+{
20
+FIELD(CLIDR_EL1, CTYPE2, 3, 3)
59
+ return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, VARANGE) != 0;
21
+FIELD(CLIDR_EL1, CTYPE3, 6, 3)
60
+}
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)
61
+
30
+
62
static inline bool isar_feature_aa64_tts2uxn(const ARMISARegisters *id)
31
+/* When FEAT_CCIDX is implemented */
63
{
32
+FIELD(CCSIDR_EL1, CCIDX_LINESIZE, 0, 3)
64
return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, XNX) != 0;
33
+FIELD(CCSIDR_EL1, CCIDX_ASSOCIATIVITY, 3, 21)
65
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
34
+FIELD(CCSIDR_EL1, CCIDX_NUMSETS, 32, 24)
66
index XXXXXXX..XXXXXXX 100644
67
--- a/target/arm/cpu64.c
68
+++ b/target/arm/cpu64.c
69
@@ -XXX,XX +XXX,XX @@ static void aarch64_max_initfn(Object *obj)
70
t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1);
71
t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* TTCNP */
72
t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* TTST */
73
+ t = FIELD_DP64(t, ID_AA64MMFR2, VARANGE, 1); /* FEAT_LVA */
74
cpu->isar.id_aa64mmfr2 = t;
75
76
t = cpu->isar.id_aa64zfr0;
77
diff --git a/target/arm/helper.c b/target/arm/helper.c
78
index XXXXXXX..XXXXXXX 100644
79
--- a/target/arm/helper.c
80
+++ b/target/arm/helper.c
81
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
82
} else {
83
max_tsz = 39;
84
}
85
- min_tsz = 16; /* TODO: ARMv8.2-LVA */
86
+
35
+
87
+ min_tsz = 16;
36
+/* When FEAT_CCIDX is not implemented */
88
+ if (using64k) {
37
+FIELD(CCSIDR_EL1, LINESIZE, 0, 3)
89
+ if (cpu_isar_feature(aa64_lva, env_archcpu(env))) {
38
+FIELD(CCSIDR_EL1, ASSOCIATIVITY, 3, 10)
90
+ min_tsz = 12;
39
+FIELD(CCSIDR_EL1, NUMSETS, 13, 15)
91
+ }
40
+
92
+ }
41
+FIELD(CTR_EL0, IMINLINE, 0, 4)
93
+ /* TODO: FEAT_LPA2 */
42
+FIELD(CTR_EL0, L1IP, 14, 2)
94
43
+FIELD(CTR_EL0, DMINLINE, 16, 4)
95
if (tsz > max_tsz) {
44
+FIELD(CTR_EL0, ERG, 20, 4)
96
tsz = max_tsz;
45
+FIELD(CTR_EL0, CWG, 24, 4)
46
+FIELD(CTR_EL0, IDC, 28, 1)
47
+FIELD(CTR_EL0, DIC, 29, 1)
48
+FIELD(CTR_EL0, TMINLINE, 32, 6)
49
+
50
FIELD(MIDR_EL1, REVISION, 0, 4)
51
FIELD(MIDR_EL1, PARTNUM, 4, 12)
52
FIELD(MIDR_EL1, ARCHITECTURE, 16, 4)
97
--
53
--
98
2.25.1
54
2.20.1
55
56
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Leif Lindholm <leif@nuviainc.com>
2
2
3
The macro is a bit more readable than the inlined computation.
3
Add entries present in ARM DDI 0487F.c (August 2020).
4
4
5
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
5
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Message-id: 20220301215958.157011-7-richard.henderson@linaro.org
7
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
8
Message-id: 20210108185154.8108-6-leif@nuviainc.com
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
10
---
10
target/arm/helper.c | 4 ++--
11
target/arm/cpu.h | 15 +++++++++++++++
11
1 file changed, 2 insertions(+), 2 deletions(-)
12
1 file changed, 15 insertions(+)
12
13
13
diff --git a/target/arm/helper.c b/target/arm/helper.c
14
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
14
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/helper.c
16
--- a/target/arm/cpu.h
16
+++ b/target/arm/helper.c
17
+++ b/target/arm/cpu.h
17
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
18
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64ISAR1, GPI, 28, 4)
18
level = startlevel;
19
FIELD(ID_AA64ISAR1, FRINTTS, 32, 4)
19
}
20
FIELD(ID_AA64ISAR1, SB, 36, 4)
20
21
FIELD(ID_AA64ISAR1, SPECRES, 40, 4)
21
- indexmask_grainsize = (1ULL << (stride + 3)) - 1;
22
+FIELD(ID_AA64ISAR1, BF16, 44, 4)
22
- indexmask = (1ULL << (inputsize - (stride * (4 - level)))) - 1;
23
+FIELD(ID_AA64ISAR1, DGH, 48, 4)
23
+ indexmask_grainsize = MAKE_64BIT_MASK(0, stride + 3);
24
+FIELD(ID_AA64ISAR1, I8MM, 52, 4)
24
+ indexmask = MAKE_64BIT_MASK(0, inputsize - (stride * (4 - level)));
25
25
26
FIELD(ID_AA64PFR0, EL0, 0, 4)
26
/* Now we can extract the actual base address from the TTBR */
27
FIELD(ID_AA64PFR0, EL1, 4, 4)
27
descaddr = extract64(ttbr, 0, 48);
28
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64PFR0, ADVSIMD, 20, 4)
29
FIELD(ID_AA64PFR0, GIC, 24, 4)
30
FIELD(ID_AA64PFR0, RAS, 28, 4)
31
FIELD(ID_AA64PFR0, SVE, 32, 4)
32
+FIELD(ID_AA64PFR0, SEL2, 36, 4)
33
+FIELD(ID_AA64PFR0, MPAM, 40, 4)
34
+FIELD(ID_AA64PFR0, AMU, 44, 4)
35
+FIELD(ID_AA64PFR0, DIT, 48, 4)
36
+FIELD(ID_AA64PFR0, CSV2, 56, 4)
37
+FIELD(ID_AA64PFR0, CSV3, 60, 4)
38
39
FIELD(ID_AA64PFR1, BT, 0, 4)
40
FIELD(ID_AA64PFR1, SSBS, 4, 4)
41
FIELD(ID_AA64PFR1, MTE, 8, 4)
42
FIELD(ID_AA64PFR1, RAS_FRAC, 12, 4)
43
+FIELD(ID_AA64PFR1, MPAM_FRAC, 16, 4)
44
45
FIELD(ID_AA64MMFR0, PARANGE, 0, 4)
46
FIELD(ID_AA64MMFR0, ASIDBITS, 4, 4)
47
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64MMFR0, TGRAN16_2, 32, 4)
48
FIELD(ID_AA64MMFR0, TGRAN64_2, 36, 4)
49
FIELD(ID_AA64MMFR0, TGRAN4_2, 40, 4)
50
FIELD(ID_AA64MMFR0, EXS, 44, 4)
51
+FIELD(ID_AA64MMFR0, FGT, 56, 4)
52
+FIELD(ID_AA64MMFR0, ECV, 60, 4)
53
54
FIELD(ID_AA64MMFR1, HAFDBS, 0, 4)
55
FIELD(ID_AA64MMFR1, VMIDBITS, 4, 4)
56
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64MMFR1, LO, 16, 4)
57
FIELD(ID_AA64MMFR1, PAN, 20, 4)
58
FIELD(ID_AA64MMFR1, SPECSEI, 24, 4)
59
FIELD(ID_AA64MMFR1, XNX, 28, 4)
60
+FIELD(ID_AA64MMFR1, TWED, 32, 4)
61
+FIELD(ID_AA64MMFR1, ETS, 36, 4)
62
63
FIELD(ID_AA64MMFR2, CNP, 0, 4)
64
FIELD(ID_AA64MMFR2, UAO, 4, 4)
65
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64DFR0, CTX_CMPS, 28, 4)
66
FIELD(ID_AA64DFR0, PMSVER, 32, 4)
67
FIELD(ID_AA64DFR0, DOUBLELOCK, 36, 4)
68
FIELD(ID_AA64DFR0, TRACEFILT, 40, 4)
69
+FIELD(ID_AA64DFR0, MTPMU, 48, 4)
70
71
FIELD(ID_DFR0, COPDBG, 0, 4)
72
FIELD(ID_DFR0, COPSDBG, 4, 4)
28
--
73
--
29
2.25.1
74
2.20.1
30
75
31
76
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Leif Lindholm <leif@nuviainc.com>
2
2
3
We will shortly share parts of this function with other portions
3
Add entries present in ARM DDI 0487F.c (August 2020).
4
of address translation.
5
4
5
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
7
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Message-id: 20210108185154.8108-7-leif@nuviainc.com
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 20220301215958.157011-5-richard.henderson@linaro.org
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
---
10
---
13
target/arm/internals.h | 19 +------------------
11
target/arm/cpu.h | 28 ++++++++++++++++++++++++++++
14
target/arm/helper.c | 22 ++++++++++++++++++++++
12
1 file changed, 28 insertions(+)
15
2 files changed, 23 insertions(+), 18 deletions(-)
16
13
17
diff --git a/target/arm/internals.h b/target/arm/internals.h
14
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
18
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/internals.h
16
--- a/target/arm/cpu.h
20
+++ b/target/arm/internals.h
17
+++ b/target/arm/cpu.h
21
@@ -XXX,XX +XXX,XX @@ static inline void update_spsel(CPUARMState *env, uint32_t imm)
18
@@ -XXX,XX +XXX,XX @@ FIELD(ID_ISAR6, DP, 4, 4)
22
* Returns the implementation defined bit-width of physical addresses.
19
FIELD(ID_ISAR6, FHM, 8, 4)
23
* The ARMv8 reference manuals refer to this as PAMax().
20
FIELD(ID_ISAR6, SB, 12, 4)
24
*/
21
FIELD(ID_ISAR6, SPECRES, 16, 4)
25
-static inline unsigned int arm_pamax(ARMCPU *cpu)
22
+FIELD(ID_ISAR6, BF16, 20, 4)
26
-{
23
+FIELD(ID_ISAR6, I8MM, 24, 4)
27
- static const unsigned int pamax_map[] = {
24
28
- [0] = 32,
25
FIELD(ID_MMFR0, VMSA, 0, 4)
29
- [1] = 36,
26
FIELD(ID_MMFR0, PMSA, 4, 4)
30
- [2] = 40,
27
@@ -XXX,XX +XXX,XX @@ FIELD(ID_MMFR0, AUXREG, 20, 4)
31
- [3] = 42,
28
FIELD(ID_MMFR0, FCSE, 24, 4)
32
- [4] = 44,
29
FIELD(ID_MMFR0, INNERSHR, 28, 4)
33
- [5] = 48,
30
34
- };
31
+FIELD(ID_MMFR1, L1HVDVA, 0, 4)
35
- unsigned int parange =
32
+FIELD(ID_MMFR1, L1UNIVA, 4, 4)
36
- FIELD_EX64(cpu->isar.id_aa64mmfr0, ID_AA64MMFR0, PARANGE);
33
+FIELD(ID_MMFR1, L1HVDSW, 8, 4)
37
-
34
+FIELD(ID_MMFR1, L1UNISW, 12, 4)
38
- /* id_aa64mmfr0 is a read-only register so values outside of the
35
+FIELD(ID_MMFR1, L1HVD, 16, 4)
39
- * supported mappings can be considered an implementation error. */
36
+FIELD(ID_MMFR1, L1UNI, 20, 4)
40
- assert(parange < ARRAY_SIZE(pamax_map));
37
+FIELD(ID_MMFR1, L1TSTCLN, 24, 4)
41
- return pamax_map[parange];
38
+FIELD(ID_MMFR1, BPRED, 28, 4)
42
-}
43
+unsigned int arm_pamax(ARMCPU *cpu);
44
45
/* Return true if extended addresses are enabled.
46
* This is always the case if our translation regime is 64 bit,
47
diff --git a/target/arm/helper.c b/target/arm/helper.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/target/arm/helper.c
50
+++ b/target/arm/helper.c
51
@@ -XXX,XX +XXX,XX @@ static uint8_t convert_stage2_attrs(CPUARMState *env, uint8_t s2attrs)
52
}
53
#endif /* !CONFIG_USER_ONLY */
54
55
+/* The cpu-specific constant value of PAMax; also used by hw/arm/virt. */
56
+unsigned int arm_pamax(ARMCPU *cpu)
57
+{
58
+ static const unsigned int pamax_map[] = {
59
+ [0] = 32,
60
+ [1] = 36,
61
+ [2] = 40,
62
+ [3] = 42,
63
+ [4] = 44,
64
+ [5] = 48,
65
+ };
66
+ unsigned int parange =
67
+ FIELD_EX64(cpu->isar.id_aa64mmfr0, ID_AA64MMFR0, PARANGE);
68
+
39
+
69
+ /*
40
+FIELD(ID_MMFR2, L1HVDFG, 0, 4)
70
+ * id_aa64mmfr0 is a read-only register so values outside of the
41
+FIELD(ID_MMFR2, L1HVDBG, 4, 4)
71
+ * supported mappings can be considered an implementation error.
42
+FIELD(ID_MMFR2, L1HVDRNG, 8, 4)
72
+ */
43
+FIELD(ID_MMFR2, HVDTLB, 12, 4)
73
+ assert(parange < ARRAY_SIZE(pamax_map));
44
+FIELD(ID_MMFR2, UNITLB, 16, 4)
74
+ return pamax_map[parange];
45
+FIELD(ID_MMFR2, MEMBARR, 20, 4)
75
+}
46
+FIELD(ID_MMFR2, WFISTALL, 24, 4)
47
+FIELD(ID_MMFR2, HWACCFLG, 28, 4)
76
+
48
+
77
static int aa64_va_parameter_tbi(uint64_t tcr, ARMMMUIdx mmu_idx)
49
FIELD(ID_MMFR3, CMAINTVA, 0, 4)
78
{
50
FIELD(ID_MMFR3, CMAINTSW, 4, 4)
79
if (regime_has_2_ranges(mmu_idx)) {
51
FIELD(ID_MMFR3, BPMAINT, 8, 4)
52
@@ -XXX,XX +XXX,XX @@ FIELD(ID_MMFR4, LSM, 20, 4)
53
FIELD(ID_MMFR4, CCIDX, 24, 4)
54
FIELD(ID_MMFR4, EVT, 28, 4)
55
56
+FIELD(ID_MMFR5, ETS, 0, 4)
57
+
58
FIELD(ID_PFR0, STATE0, 0, 4)
59
FIELD(ID_PFR0, STATE1, 4, 4)
60
FIELD(ID_PFR0, STATE2, 8, 4)
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)
68
+
69
FIELD(ID_AA64ISAR0, AES, 4, 4)
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)
77
+
78
FIELD(DBGDIDR, SE_IMP, 12, 1)
79
FIELD(DBGDIDR, NSUHD_IMP, 14, 1)
80
FIELD(DBGDIDR, VERSION, 16, 4)
80
--
81
--
81
2.25.1
82
2.20.1
82
83
83
84
diff view generated by jsdifflib
1
In commit 6e657e64cdc478 in 2013 we added some autorelease pools to
1
From: Roman Bolshakov <r.bolshakov@yadro.com>
2
deal with complaints from macOS when we made calls into Cocoa from
3
threads that didn't have automatically created autorelease pools.
4
Later on, macOS got stricter about forbidding cross-thread Cocoa
5
calls, and in commit 5588840ff77800e839d8 we restructured the code to
6
avoid them. This left the autorelease pool creation in several
7
functions without any purpose; delete it.
8
2
9
We still need the pool in cocoa_refresh() for the clipboard related
3
QEMU documentation can't be opened if QEMU is run from build tree
10
code which is called directly there.
4
because executables are placed in the top of build tree after conversion
5
to meson.
11
6
7
Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
8
Reported-by: Peter Maydell <peter.maydell@linaro.org>
9
Message-id: 20210108213815.64678-1-r.bolshakov@yadro.com
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Reviewed-by: Akihiko Odaki <akihiko.odaki@gmail.com>
14
Tested-by: Akihiko Odaki <akihiko.odaki@gmail.com>
15
Message-id: 20220224101330.967429-3-peter.maydell@linaro.org
16
---
12
---
17
ui/cocoa.m | 6 ------
13
ui/cocoa.m | 2 +-
18
1 file changed, 6 deletions(-)
14
1 file changed, 1 insertion(+), 1 deletion(-)
19
15
20
diff --git a/ui/cocoa.m b/ui/cocoa.m
16
diff --git a/ui/cocoa.m b/ui/cocoa.m
21
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
22
--- a/ui/cocoa.m
18
--- a/ui/cocoa.m
23
+++ b/ui/cocoa.m
19
+++ b/ui/cocoa.m
24
@@ -XXX,XX +XXX,XX @@ int main (int argc, char **argv) {
20
@@ -XXX,XX +XXX,XX @@ QemuCocoaView *cocoaView;
25
static void cocoa_update(DisplayChangeListener *dcl,
21
- (void) openDocumentation: (NSString *) filename
26
int x, int y, int w, int h)
27
{
22
{
28
- NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
23
/* Where to look for local files */
29
-
24
- NSString *path_array[] = {@"../share/doc/qemu/", @"../doc/qemu/", @"../docs/"};
30
COCOA_DEBUG("qemu_cocoa: cocoa_update\n");
25
+ NSString *path_array[] = {@"../share/doc/qemu/", @"../doc/qemu/", @"docs/"};
31
26
NSString *full_file_path;
32
dispatch_async(dispatch_get_main_queue(), ^{
27
33
@@ -XXX,XX +XXX,XX @@ static void cocoa_update(DisplayChangeListener *dcl,
28
/* iterate thru the possible paths until the file is found */
34
}
35
[cocoaView setNeedsDisplayInRect:rect];
36
});
37
-
38
- [pool release];
39
}
40
41
static void cocoa_switch(DisplayChangeListener *dcl,
42
DisplaySurface *surface)
43
{
44
- NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
45
pixman_image_t *image = surface->image;
46
47
COCOA_DEBUG("qemu_cocoa: cocoa_switch\n");
48
@@ -XXX,XX +XXX,XX @@ static void cocoa_switch(DisplayChangeListener *dcl,
49
[cocoaView updateUIInfo];
50
[cocoaView switchSurface:image];
51
});
52
- [pool release];
53
}
54
55
static void cocoa_refresh(DisplayChangeListener *dcl)
56
--
29
--
57
2.25.1
30
2.20.1
31
32
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
In commit 1982e1602d15 we added a new qemu-storage-daemon(1) manpage.
2
At the moment new manpages have to be listed both in the conf.py for
3
Sphinx and also in docs/meson.build for Meson. We forgot the second
4
of those -- correct the omission.
2
5
3
Add new macros to manipulate signed fields within the register.
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
9
Message-id: 20210108161416.21129-2-peter.maydell@linaro.org
10
---
11
docs/meson.build | 1 +
12
1 file changed, 1 insertion(+)
4
13
5
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
14
diff --git a/docs/meson.build b/docs/meson.build
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20220301215958.157011-2-richard.henderson@linaro.org
8
Suggested-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
12
include/hw/registerfields.h | 48 ++++++++++++++++++++++++++++++++++++-
13
1 file changed, 47 insertions(+), 1 deletion(-)
14
15
diff --git a/include/hw/registerfields.h b/include/hw/registerfields.h
16
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
17
--- a/include/hw/registerfields.h
16
--- a/docs/meson.build
18
+++ b/include/hw/registerfields.h
17
+++ b/docs/meson.build
19
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@ if build_docs
20
extract64((storage), R_ ## reg ## _ ## field ## _SHIFT, \
19
'qemu-img.1': (have_tools ? 'man1' : ''),
21
R_ ## reg ## _ ## field ## _LENGTH)
20
'qemu-nbd.8': (have_tools ? 'man8' : ''),
22
21
'qemu-pr-helper.8': (have_tools ? 'man8' : ''),
23
+#define FIELD_SEX8(storage, reg, field) \
22
+ 'qemu-storage-daemon.1': (have_tools ? 'man1' : ''),
24
+ sextract8((storage), R_ ## reg ## _ ## field ## _SHIFT, \
23
'qemu-trace-stap.1': (config_host.has_key('CONFIG_TRACE_SYSTEMTAP') ? 'man1' : ''),
25
+ R_ ## reg ## _ ## field ## _LENGTH)
24
'virtfs-proxy-helper.1': (have_virtfs_proxy_helper ? 'man1' : ''),
26
+#define FIELD_SEX16(storage, reg, field) \
25
'virtiofsd.1': (have_virtiofsd ? 'man1' : ''),
27
+ sextract16((storage), R_ ## reg ## _ ## field ## _SHIFT, \
28
+ R_ ## reg ## _ ## field ## _LENGTH)
29
+#define FIELD_SEX32(storage, reg, field) \
30
+ sextract32((storage), R_ ## reg ## _ ## field ## _SHIFT, \
31
+ R_ ## reg ## _ ## field ## _LENGTH)
32
+#define FIELD_SEX64(storage, reg, field) \
33
+ sextract64((storage), R_ ## reg ## _ ## field ## _SHIFT, \
34
+ R_ ## reg ## _ ## field ## _LENGTH)
35
+
36
/* Extract a field from an array of registers */
37
#define ARRAY_FIELD_EX32(regs, reg, field) \
38
FIELD_EX32((regs)[R_ ## reg], reg, field)
39
@@ -XXX,XX +XXX,XX @@
40
_d; })
41
#define FIELD_DP64(storage, reg, field, val) ({ \
42
struct { \
43
- uint64_t v:R_ ## reg ## _ ## field ## _LENGTH; \
44
+ uint64_t v:R_ ## reg ## _ ## field ## _LENGTH; \
45
+ } _v = { .v = val }; \
46
+ uint64_t _d; \
47
+ _d = deposit64((storage), R_ ## reg ## _ ## field ## _SHIFT, \
48
+ R_ ## reg ## _ ## field ## _LENGTH, _v.v); \
49
+ _d; })
50
+
51
+#define FIELD_SDP8(storage, reg, field, val) ({ \
52
+ struct { \
53
+ signed int v:R_ ## reg ## _ ## field ## _LENGTH; \
54
+ } _v = { .v = val }; \
55
+ uint8_t _d; \
56
+ _d = deposit32((storage), R_ ## reg ## _ ## field ## _SHIFT, \
57
+ R_ ## reg ## _ ## field ## _LENGTH, _v.v); \
58
+ _d; })
59
+#define FIELD_SDP16(storage, reg, field, val) ({ \
60
+ struct { \
61
+ signed int v:R_ ## reg ## _ ## field ## _LENGTH; \
62
+ } _v = { .v = val }; \
63
+ uint16_t _d; \
64
+ _d = deposit32((storage), R_ ## reg ## _ ## field ## _SHIFT, \
65
+ R_ ## reg ## _ ## field ## _LENGTH, _v.v); \
66
+ _d; })
67
+#define FIELD_SDP32(storage, reg, field, val) ({ \
68
+ struct { \
69
+ signed int v:R_ ## reg ## _ ## field ## _LENGTH; \
70
+ } _v = { .v = val }; \
71
+ uint32_t _d; \
72
+ _d = deposit32((storage), R_ ## reg ## _ ## field ## _SHIFT, \
73
+ R_ ## reg ## _ ## field ## _LENGTH, _v.v); \
74
+ _d; })
75
+#define FIELD_SDP64(storage, reg, field, val) ({ \
76
+ struct { \
77
+ int64_t v:R_ ## reg ## _ ## field ## _LENGTH; \
78
} _v = { .v = val }; \
79
uint64_t _d; \
80
_d = deposit64((storage), R_ ## reg ## _ ## field ## _SHIFT, \
81
--
26
--
82
2.25.1
27
2.20.1
83
28
84
29
diff view generated by jsdifflib
1
When we're using KVM, the PSCI implementation is provided by the
1
When we first converted our documentation to Sphinx, we split it into
2
kernel, but QEMU has to tell the guest about it via the device tree.
2
multiple manuals (system, interop, tools, etc), which are all built
3
Currently we look at the KVM_CAP_ARM_PSCI_0_2 capability to determine
3
separately. The primary driver for this was wanting to be able to
4
if the kernel is providing at least PSCI 0.2, but if the kernel
4
avoid shipping the 'devel' manual to end-users. However, this is
5
provides a newer version than that we will still only tell the guest
5
working against the grain of the way Sphinx wants to be used and
6
it has PSCI 0.2. (This is fairly harmless; it just means the guest
6
causes some annoyances:
7
won't use newer parts of the PSCI API.)
7
* Cross-references between documents become much harder or
8
8
possibly impossible
9
The kernel exposes the specific PSCI version it is implementing via
9
* There is no single index to the whole documentation
10
the ONE_REG API; use this to report in the dtb that the PSCI
10
* Within one manual there's no links or table-of-contents info
11
implementation is 1.0-compatible if appropriate. (The device tree
11
that lets you easily navigate to the others
12
binding currently only distinguishes "pre-0.2", "0.2-compatible" and
12
* The devel manual doesn't get published on the QEMU website
13
"1.0-compatible".)
13
(it would be nice to able to refer to it there)
14
15
Merely hiding our developer documentation from end users seems like
16
it's not enough benefit for these costs. Combine all the
17
documentation into a single manual (the same way that the readthedocs
18
site builds it) and install the whole thing. The previous manual
19
divisions remain as the new top level sections in the manual.
20
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.
14
36
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
37
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
Reviewed-by: Marc Zyngier <maz@kernel.org>
38
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
17
Reviewed-by: Akihiko Odaki <akihiko.odaki@gmail.com>
39
Message-id: 20210108161416.21129-3-peter.maydell@linaro.org
18
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
19
Reviewed-by: Andrew Jones <drjones@redhat.com>
20
Message-id: 20220224134655.1207865-1-peter.maydell@linaro.org
21
---
40
---
22
target/arm/kvm-consts.h | 1 +
41
docs/conf.py | 46 ++++++++++++++++++++++++++++++-
23
hw/arm/boot.c | 5 ++---
42
docs/devel/conf.py | 15 -----------
24
target/arm/kvm64.c | 12 ++++++++++++
43
docs/index.html.in | 17 ------------
25
3 files changed, 15 insertions(+), 3 deletions(-)
44
docs/interop/conf.py | 28 -------------------
26
45
docs/meson.build | 64 +++++++++++++++++---------------------------
27
diff --git a/target/arm/kvm-consts.h b/target/arm/kvm-consts.h
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/target/arm/kvm-consts.h
61
--- a/docs/conf.py
30
+++ b/target/arm/kvm-consts.h
62
+++ b/docs/conf.py
31
@@ -XXX,XX +XXX,XX @@ MISMATCH_CHECK(QEMU_PSCI_1_0_FN_PSCI_FEATURES, PSCI_1_0_FN_PSCI_FEATURES);
63
@@ -XXX,XX +XXX,XX @@ latex_documents = [
32
64
33
#define QEMU_PSCI_VERSION_0_1 0x00001
65
# -- Options for manual page output ---------------------------------------
34
#define QEMU_PSCI_VERSION_0_2 0x00002
66
# Individual manual/conf.py can override this to create man pages
35
+#define QEMU_PSCI_VERSION_1_0 0x10000
67
-man_pages = []
36
#define QEMU_PSCI_VERSION_1_1 0x10001
68
+man_pages = [
37
69
+ ('interop/qemu-ga', 'qemu-ga',
38
MISMATCH_CHECK(QEMU_PSCI_0_2_RET_TOS_MIGRATION_NOT_REQUIRED, PSCI_0_2_TOS_MP);
70
+ 'QEMU Guest Agent',
39
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
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
40
index XXXXXXX..XXXXXXX 100644
195
index XXXXXXX..XXXXXXX 100644
41
--- a/hw/arm/boot.c
196
--- a/docs/meson.build
42
+++ b/hw/arm/boot.c
197
+++ b/docs/meson.build
43
@@ -XXX,XX +XXX,XX @@ static void fdt_add_psci_node(void *fdt)
198
@@ -XXX,XX +XXX,XX @@ if build_docs
44
}
199
meson.source_root() / 'docs/sphinx/qmp_lexer.py',
45
200
qapi_gen_depends ]
46
qemu_fdt_add_subnode(fdt, "/psci");
201
47
- if (armcpu->psci_version == QEMU_PSCI_VERSION_0_2 ||
202
- configure_file(output: 'index.html',
48
- armcpu->psci_version == QEMU_PSCI_VERSION_1_1) {
203
- input: files('index.html.in'),
49
- if (armcpu->psci_version == QEMU_PSCI_VERSION_0_2) {
204
- configuration: {'VERSION': meson.project_version()},
50
+ if (armcpu->psci_version >= QEMU_PSCI_VERSION_0_2) {
205
- install_dir: qemu_docdir)
51
+ if (armcpu->psci_version < QEMU_PSCI_VERSION_1_0) {
206
- manuals = [ 'devel', 'interop', 'tools', 'specs', 'system', 'user' ]
52
const char comp[] = "arm,psci-0.2\0arm,psci";
207
man_pages = {
53
qemu_fdt_setprop(fdt, "/psci", "compatible", comp, sizeof(comp));
208
- 'interop' : {
54
} else {
209
'qemu-ga.8': (have_tools ? 'man8' : ''),
55
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
210
'qemu-ga-ref.7': 'man7',
56
index XXXXXXX..XXXXXXX 100644
211
'qemu-qmp-ref.7': 'man7',
57
--- a/target/arm/kvm64.c
212
'qemu-storage-daemon-qmp-ref.7': (have_tools ? 'man7' : ''),
58
+++ b/target/arm/kvm64.c
213
- },
59
@@ -XXX,XX +XXX,XX @@ int kvm_arch_init_vcpu(CPUState *cs)
214
- 'tools': {
60
uint64_t mpidr;
215
'qemu-img.1': (have_tools ? 'man1' : ''),
61
ARMCPU *cpu = ARM_CPU(cs);
216
'qemu-nbd.8': (have_tools ? 'man8' : ''),
62
CPUARMState *env = &cpu->env;
217
'qemu-pr-helper.8': (have_tools ? 'man8' : ''),
63
+ uint64_t psciver;
218
@@ -XXX,XX +XXX,XX @@ if build_docs
64
219
'qemu-trace-stap.1': (config_host.has_key('CONFIG_TRACE_SYSTEMTAP') ? 'man1' : ''),
65
if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE ||
220
'virtfs-proxy-helper.1': (have_virtfs_proxy_helper ? 'man1' : ''),
66
!object_dynamic_cast(OBJECT(cpu), TYPE_AARCH64_CPU)) {
221
'virtiofsd.1': (have_virtiofsd ? 'man1' : ''),
67
@@ -XXX,XX +XXX,XX @@ int kvm_arch_init_vcpu(CPUState *cs)
222
- },
68
}
223
- 'system': {
69
}
224
'qemu.1': 'man1',
70
225
'qemu-block-drivers.7': 'man7',
71
+ /*
226
'qemu-cpu-models.7': 'man7'
72
+ * KVM reports the exact PSCI version it is implementing via a
227
- },
73
+ * special sysreg. If it is present, use its contents to determine
228
}
74
+ * what to report to the guest in the dtb (it is the PSCI version,
229
75
+ * in the same 15-bits major 16-bits minor format that PSCI_VERSION
230
sphinxdocs = []
76
+ * returns).
231
sphinxmans = []
77
+ */
232
- foreach manual : manuals
78
+ if (!kvm_get_one_reg(cs, KVM_REG_ARM_PSCI_VERSION, &psciver)) {
233
- private_dir = meson.current_build_dir() / (manual + '.p')
79
+ cpu->psci_version = psciver;
234
- output_dir = meson.current_build_dir() / manual
80
+ }
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()
81
+
241
+
82
/*
242
+ this_manual = custom_target('QEMU manual',
83
* When KVM is in use, PSCI is emulated in-kernel and not by qemu.
243
build_by_default: build_docs,
84
* Currently KVM has its own idea about MPIDR assignment, so we
244
- output: [manual + '.stamp'],
245
- input: [files('conf.py'), files(manual / 'conf.py')],
246
- depfile: manual + '.d',
247
+ output: 'docs.stamp',
248
+ input: files('conf.py'),
249
+ depfile: 'docs.d',
250
depend_files: sphinx_extn_depends,
251
command: [SPHINX_ARGS, '-Ddepfile=@DEPFILE@',
252
'-Ddepfile_stamp=@OUTPUT0@',
253
'-b', 'html', '-d', private_dir,
254
input_dir, output_dir])
255
- sphinxdocs += this_manual
256
- if build_docs and manual != 'devel'
257
- install_subdir(output_dir, install_dir: qemu_docdir)
258
- endif
259
+ sphinxdocs += this_manual
260
+ install_subdir(output_dir, install_dir: qemu_docdir, strip_directory: true)
261
262
- these_man_pages = []
263
- install_dirs = []
264
- foreach page, section : man_pages.get(manual, {})
265
- these_man_pages += page
266
- install_dirs += section == '' ? false : get_option('mandir') / section
267
- endforeach
268
- if these_man_pages.length() > 0
269
- sphinxmans += custom_target(manual + ' man pages',
270
- build_by_default: build_docs,
271
- output: these_man_pages,
272
- input: this_manual,
273
- install: build_docs,
274
- install_dir: install_dirs,
275
- command: [SPHINX_ARGS, '-b', 'man', '-d', private_dir,
276
- input_dir, meson.current_build_dir()])
277
- endif
278
+ these_man_pages = []
279
+ install_dirs = []
280
+ foreach page, section : man_pages
281
+ these_man_pages += page
282
+ install_dirs += section == '' ? false : get_option('mandir') / section
283
endforeach
284
+
285
+ sphinxmans += custom_target('QEMU man pages',
286
+ build_by_default: build_docs,
287
+ output: these_man_pages,
288
+ input: this_manual,
289
+ install: build_docs,
290
+ install_dir: install_dirs,
291
+ command: [SPHINX_ARGS, '-b', 'man', '-d', private_dir,
292
+ input_dir, meson.current_build_dir()])
293
+
294
alias_target('sphinxdocs', sphinxdocs)
295
alias_target('html', sphinxdocs)
296
alias_target('man', sphinxmans)
297
diff --git a/docs/specs/conf.py b/docs/specs/conf.py
298
deleted file mode 100644
299
index XXXXXXX..XXXXXXX
300
--- a/docs/specs/conf.py
301
+++ /dev/null
302
@@ -XXX,XX +XXX,XX @@
303
-# -*- coding: utf-8 -*-
304
-#
305
-# QEMU documentation build configuration file for the 'specs' manual.
306
-#
307
-# This includes the top level conf file and then makes any necessary tweaks.
308
-import sys
309
-import os
310
-
311
-qemu_docdir = os.path.abspath("..")
312
-parent_config = os.path.join(qemu_docdir, "conf.py")
313
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
314
-
315
-# This slightly misuses the 'description', but is the best way to get
316
-# the manual title to appear in the sidebar.
317
-html_theme_options['description'] = \
318
- u'System Emulation Guest Hardware Specifications'
319
diff --git a/docs/system/conf.py b/docs/system/conf.py
320
deleted file mode 100644
321
index XXXXXXX..XXXXXXX
322
--- a/docs/system/conf.py
323
+++ /dev/null
324
@@ -XXX,XX +XXX,XX @@
325
-# -*- coding: utf-8 -*-
326
-#
327
-# QEMU documentation build configuration file for the 'system' manual.
328
-#
329
-# This includes the top level conf file and then makes any necessary tweaks.
330
-import sys
331
-import os
332
-
333
-qemu_docdir = os.path.abspath("..")
334
-parent_config = os.path.join(qemu_docdir, "conf.py")
335
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
336
-
337
-# This slightly misuses the 'description', but is the best way to get
338
-# the manual title to appear in the sidebar.
339
-html_theme_options['description'] = u'System Emulation User''s Guide'
340
-
341
-# One entry per manual page. List of tuples
342
-# (source start file, name, description, authors, manual section).
343
-man_pages = [
344
- ('qemu-manpage', 'qemu', u'QEMU User Documentation',
345
- ['Fabrice Bellard'], 1),
346
- ('qemu-block-drivers', 'qemu-block-drivers',
347
- u'QEMU block drivers reference',
348
- ['Fabrice Bellard and the QEMU Project developers'], 7),
349
- ('qemu-cpu-models', 'qemu-cpu-models',
350
- u'QEMU CPU Models',
351
- ['The QEMU Project developers'], 7)
352
-]
353
diff --git a/docs/tools/conf.py b/docs/tools/conf.py
354
deleted file mode 100644
355
index XXXXXXX..XXXXXXX
356
--- a/docs/tools/conf.py
357
+++ /dev/null
358
@@ -XXX,XX +XXX,XX @@
359
-# -*- coding: utf-8 -*-
360
-#
361
-# QEMU documentation build configuration file for the 'tools' manual.
362
-#
363
-# This includes the top level conf file and then makes any necessary tweaks.
364
-import sys
365
-import os
366
-
367
-qemu_docdir = os.path.abspath("..")
368
-parent_config = os.path.join(qemu_docdir, "conf.py")
369
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
370
-
371
-# This slightly misuses the 'description', but is the best way to get
372
-# the manual title to appear in the sidebar.
373
-html_theme_options['description'] = \
374
- u'Tools Guide'
375
-
376
-# One entry per manual page. List of tuples
377
-# (source start file, name, description, authors, manual section).
378
-man_pages = [
379
- ('qemu-img', 'qemu-img', u'QEMU disk image utility',
380
- ['Fabrice Bellard'], 1),
381
- ('qemu-storage-daemon', 'qemu-storage-daemon', u'QEMU storage daemon',
382
- [], 1),
383
- ('qemu-nbd', 'qemu-nbd', u'QEMU Disk Network Block Device Server',
384
- ['Anthony Liguori <anthony@codemonkey.ws>'], 8),
385
- ('qemu-pr-helper', 'qemu-pr-helper', 'QEMU persistent reservation helper',
386
- [], 8),
387
- ('qemu-trace-stap', 'qemu-trace-stap', u'QEMU SystemTap trace tool',
388
- [], 1),
389
- ('virtfs-proxy-helper', 'virtfs-proxy-helper',
390
- u'QEMU 9p virtfs proxy filesystem helper',
391
- ['M. Mohan Kumar'], 1),
392
- ('virtiofsd', 'virtiofsd', u'QEMU virtio-fs shared file system daemon',
393
- ['Stefan Hajnoczi <stefanha@redhat.com>',
394
- 'Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>'], 1),
395
-]
396
diff --git a/docs/user/conf.py b/docs/user/conf.py
397
deleted file mode 100644
398
index XXXXXXX..XXXXXXX
399
--- a/docs/user/conf.py
400
+++ /dev/null
401
@@ -XXX,XX +XXX,XX @@
402
-# -*- coding: utf-8 -*-
403
-#
404
-# QEMU documentation build configuration file for the 'user' manual.
405
-#
406
-# This includes the top level conf file and then makes any necessary tweaks.
407
-import sys
408
-import os
409
-
410
-qemu_docdir = os.path.abspath("..")
411
-parent_config = os.path.join(qemu_docdir, "conf.py")
412
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
413
-
414
-# This slightly misuses the 'description', but is the best way to get
415
-# the manual title to appear in the sidebar.
416
-html_theme_options['description'] = u'User Mode Emulation User''s Guide'
85
--
417
--
86
2.25.1
418
2.20.1
419
420
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
In commit cd8be50e58f63413c0 we converted the A32 coprocessor
2
insns to decodetree. This accidentally broke XScale/iWMMXt insns,
3
because it moved the handling of "cp insns which are handled
4
by looking up the cp register in the hashtable" from after the
5
call to the legacy disas_xscale_insn() decode to before it,
6
with the result that all XScale/iWMMXt insns now UNDEF.
2
7
3
This field controls the output (intermediate) physical address size
8
Update valid_cp() so that it knows that on XScale cp 0 and 1
4
of the translation process. V8 requires to raise an AddressSize
9
are not standard coprocessor instructions; this will cause
5
fault if the page tables are programmed incorrectly, such that any
10
the decodetree trans_ functions to ignore them, so that
6
intermediate descriptor address, or the final translated address,
11
execution will correctly get through to the legacy decode again.
7
is out of range.
8
12
9
Add a PS field to ARMVAParameters, and properly compute outputsize
13
Cc: qemu-stable@nongnu.org
10
in get_phys_addr_lpae. Test the descaddr as extracted from TTBR
14
Reported-by: Guenter Roeck <linux@roeck-us.net>
11
and from page table entries.
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
17
Tested-by: Guenter Roeck <linux@roeck-us.net>
18
Message-id: 20210108195157.32067-1-peter.maydell@linaro.org
19
---
20
target/arm/translate.c | 7 +++++++
21
1 file changed, 7 insertions(+)
12
22
13
Restrict descaddrmask so that we won't raise the fault for v7.
23
diff --git a/target/arm/translate.c b/target/arm/translate.c
14
15
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
16
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
17
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
18
Message-id: 20220301215958.157011-8-richard.henderson@linaro.org
19
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
20
---
21
target/arm/internals.h | 1 +
22
target/arm/helper.c | 72 ++++++++++++++++++++++++++++++++----------
23
2 files changed, 57 insertions(+), 16 deletions(-)
24
25
diff --git a/target/arm/internals.h b/target/arm/internals.h
26
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
27
--- a/target/arm/internals.h
25
--- a/target/arm/translate.c
28
+++ b/target/arm/internals.h
26
+++ b/target/arm/translate.c
29
@@ -XXX,XX +XXX,XX @@ static inline uint32_t aarch64_pstate_valid_mask(const ARMISARegisters *id)
27
@@ -XXX,XX +XXX,XX @@ static bool valid_cp(DisasContext *s, int cp)
30
*/
28
* only cp14 and cp15 are valid, and other values aren't considered
31
typedef struct ARMVAParameters {
29
* to be in the coprocessor-instruction space at all. v8M still
32
unsigned tsz : 8;
30
* permits coprocessors 0..7.
33
+ unsigned ps : 3;
31
+ * For XScale, we must not decode the XScale cp0, cp1 space as
34
unsigned select : 1;
32
+ * a standard coprocessor insn, because we want to fall through to
35
bool tbi : 1;
33
+ * the legacy disas_xscale_insn() decoder after decodetree is done.
36
bool epd : 1;
34
*/
37
diff --git a/target/arm/helper.c b/target/arm/helper.c
35
+ if (arm_dc_feature(s, ARM_FEATURE_XSCALE) && (cp == 0 || cp == 1)) {
38
index XXXXXXX..XXXXXXX 100644
36
+ return false;
39
--- a/target/arm/helper.c
40
+++ b/target/arm/helper.c
41
@@ -XXX,XX +XXX,XX @@ static uint8_t convert_stage2_attrs(CPUARMState *env, uint8_t s2attrs)
42
}
43
#endif /* !CONFIG_USER_ONLY */
44
45
+/* This mapping is common between ID_AA64MMFR0.PARANGE and TCR_ELx.{I}PS. */
46
+static const uint8_t pamax_map[] = {
47
+ [0] = 32,
48
+ [1] = 36,
49
+ [2] = 40,
50
+ [3] = 42,
51
+ [4] = 44,
52
+ [5] = 48,
53
+};
54
+
55
/* The cpu-specific constant value of PAMax; also used by hw/arm/virt. */
56
unsigned int arm_pamax(ARMCPU *cpu)
57
{
58
- static const unsigned int pamax_map[] = {
59
- [0] = 32,
60
- [1] = 36,
61
- [2] = 40,
62
- [3] = 42,
63
- [4] = 44,
64
- [5] = 48,
65
- };
66
unsigned int parange =
67
FIELD_EX64(cpu->isar.id_aa64mmfr0, ID_AA64MMFR0, PARANGE);
68
69
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
70
{
71
uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr;
72
bool epd, hpd, using16k, using64k, tsz_oob;
73
- int select, tsz, tbi, max_tsz, min_tsz;
74
+ int select, tsz, tbi, max_tsz, min_tsz, ps;
75
76
if (!regime_has_2_ranges(mmu_idx)) {
77
select = 0;
78
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
79
hpd = extract32(tcr, 24, 1);
80
}
81
epd = false;
82
+ ps = extract32(tcr, 16, 3);
83
} else {
84
/*
85
* Bit 55 is always between the two regions, and is canonical for
86
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
87
epd = extract32(tcr, 23, 1);
88
hpd = extract64(tcr, 42, 1);
89
}
90
+ ps = extract64(tcr, 32, 3);
91
}
92
93
if (cpu_isar_feature(aa64_st, env_archcpu(env))) {
94
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
95
96
return (ARMVAParameters) {
97
.tsz = tsz,
98
+ .ps = ps,
99
.select = select,
100
.tbi = tbi,
101
.epd = epd,
102
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
103
104
/* TODO: This code does not support shareability levels. */
105
if (aarch64) {
106
+ int ps;
107
+
108
param = aa64_va_parameters(env, address, mmu_idx,
109
access_type != MMU_INST_FETCH);
110
level = 0;
111
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
112
113
addrsize = 64 - 8 * param.tbi;
114
inputsize = 64 - param.tsz;
115
- outputsize = arm_pamax(cpu);
116
+
117
+ /*
118
+ * Bound PS by PARANGE to find the effective output address size.
119
+ * ID_AA64MMFR0 is a read-only register so values outside of the
120
+ * supported mappings can be considered an implementation error.
121
+ */
122
+ ps = FIELD_EX64(cpu->isar.id_aa64mmfr0, ID_AA64MMFR0, PARANGE);
123
+ ps = MIN(ps, param.ps);
124
+ assert(ps < ARRAY_SIZE(pamax_map));
125
+ outputsize = pamax_map[ps];
126
} else {
127
param = aa32_va_parameters(env, address, mmu_idx);
128
level = 1;
129
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
130
131
/* Now we can extract the actual base address from the TTBR */
132
descaddr = extract64(ttbr, 0, 48);
133
+
134
+ /*
135
+ * If the base address is out of range, raise AddressSizeFault.
136
+ * In the pseudocode, this is !IsZero(baseregister<47:outputsize>),
137
+ * but we've just cleared the bits above 47, so simplify the test.
138
+ */
139
+ if (descaddr >> outputsize) {
140
+ level = 0;
141
+ fault_type = ARMFault_AddressSize;
142
+ goto do_fault;
143
+ }
37
+ }
144
+
38
+
145
/*
39
if (arm_dc_feature(s, ARM_FEATURE_V8) &&
146
* We rely on this masking to clear the RES0 bits at the bottom of the TTBR
40
!arm_dc_feature(s, ARM_FEATURE_M)) {
147
* and also to mask out CnP (bit 0) which could validly be non-zero.
41
return cp >= 14;
148
*/
149
descaddr &= ~indexmask;
150
151
- /* The address field in the descriptor goes up to bit 39 for ARMv7
152
- * but up to bit 47 for ARMv8, but we use the descaddrmask
153
- * up to bit 39 for AArch32, because we don't need other bits in that case
154
- * to construct next descriptor address (anyway they should be all zeroes).
155
+ /*
156
+ * For AArch32, the address field in the descriptor goes up to bit 39
157
+ * for both v7 and v8. However, for v8 the SBZ bits [47:40] must be 0
158
+ * or an AddressSize fault is raised. So for v8 we extract those SBZ
159
+ * bits as part of the address, which will be checked via outputsize.
160
+ * For AArch64, the address field always goes up to bit 47 (with extra
161
+ * bits for FEAT_LPA placed elsewhere). AArch64 implies v8.
162
*/
163
- descaddrmask = ((1ull << (aarch64 ? 48 : 40)) - 1) &
164
- ~indexmask_grainsize;
165
+ if (arm_feature(env, ARM_FEATURE_V8)) {
166
+ descaddrmask = MAKE_64BIT_MASK(0, 48);
167
+ } else {
168
+ descaddrmask = MAKE_64BIT_MASK(0, 40);
169
+ }
170
+ descaddrmask &= ~indexmask_grainsize;
171
172
/* Secure accesses start with the page table in secure memory and
173
* can be downgraded to non-secure at any step. Non-secure accesses
174
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
175
/* Invalid, or the Reserved level 3 encoding */
176
goto do_fault;
177
}
178
+
179
descaddr = descriptor & descaddrmask;
180
+ if (descaddr >> outputsize) {
181
+ fault_type = ARMFault_AddressSize;
182
+ goto do_fault;
183
+ }
184
185
if ((descriptor & 2) && (level < 3)) {
186
/* Table entry. The top five bits are attributes which may
187
--
42
--
188
2.25.1
43
2.20.1
189
44
190
45
diff view generated by jsdifflib
1
The tsc210x doesn't support anything other than 16-bit reads on the
1
A copy-and-paste error meant that the return value for register offset 0x44
2
SPI bus, but the guest can program the SPI controller to attempt
2
(the RX Status FIFO PEEK register) returned a byte from a bogus offset in
3
them anyway. If this happens, don't abort QEMU, just log this as
3
the rx status FIFO. Fix the typo.
4
a guest error.
5
4
6
This fixes our machine_arm_n8x0.py:N8x0Machine.test_n800
5
Cc: qemu-stable@nongnu.org
7
acceptance test, which hits this assertion.
6
Fixes: https://bugs.launchpad.net/qemu/+bug/1904954
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(-)
8
13
9
The reason we hit the assertion is because the guest kernel thinks
14
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
10
there is a TSC2005 on this SPI bus address, not a TSC210x. (The n810
11
*does* have a TSC2005 at this address.) The TSC2005 supports the
12
24-bit accesses which the guest driver makes, and the TSC210x does
13
not (that is, our TSC210x emulation is not missing support for a word
14
width the hardware can handle). It's not clear whether the problem
15
here is that the guest kernel incorrectly thinks the n800 has the
16
same device at this SPI bus address as the n810, or that QEMU's n810
17
board model doesn't get the SPI devices right. At this late date
18
there no longer appears to be any reliable information on the web
19
about the hardware behaviour, but I am inclined to think this is a
20
guest kernel bug. In any case, we prefer not to abort QEMU for
21
guest-triggerable conditions, so logging the error is the right thing
22
to do.
23
24
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/736
25
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
26
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
27
Message-id: 20220221140750.514557-1-peter.maydell@linaro.org
28
---
29
hw/input/tsc210x.c | 8 ++++++--
30
1 file changed, 6 insertions(+), 2 deletions(-)
31
32
diff --git a/hw/input/tsc210x.c b/hw/input/tsc210x.c
33
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
34
--- a/hw/input/tsc210x.c
16
--- a/hw/net/lan9118.c
35
+++ b/hw/input/tsc210x.c
17
+++ b/hw/net/lan9118.c
36
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@ static uint64_t lan9118_readl(void *opaque, hwaddr offset,
37
#include "hw/hw.h"
19
case 0x40:
38
#include "audio/audio.h"
20
return rx_status_fifo_pop(s);
39
#include "qemu/timer.h"
21
case 0x44:
40
+#include "qemu/log.h"
22
- return s->rx_status_fifo[s->tx_status_fifo_head];
41
#include "sysemu/reset.h"
23
+ return s->rx_status_fifo[s->rx_status_fifo_head];
42
#include "ui/console.h"
24
case 0x48:
43
#include "hw/arm/omap.h" /* For I2SCodec */
25
return tx_status_fifo_pop(s);
44
@@ -XXX,XX +XXX,XX @@ uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len)
26
case 0x4c:
45
TSC210xState *s = opaque;
46
uint32_t ret = 0;
47
48
- if (len != 16)
49
- hw_error("%s: FIXME: bad SPI word width %i\n", __func__, len);
50
+ if (len != 16) {
51
+ qemu_log_mask(LOG_GUEST_ERROR,
52
+ "%s: bad SPI word width %i\n", __func__, len);
53
+ return 0;
54
+ }
55
56
/* TODO: sequential reads etc - how do we make sure the host doesn't
57
* unintentionally read out a conversion result from a register while
58
--
27
--
59
2.25.1
28
2.20.1
60
29
61
30
diff view generated by jsdifflib
1
The AN547 application note URL has changed: update our comment
1
The lan9118 code mostly uses symbolic constants for register offsets;
2
accordingly. (Rev B is still downloadable from the old URL,
2
the exceptions are those which the datasheet doesn't give an official
3
but there is a new Rev C of the document now.)
3
symbolic name to.
4
5
Add some names for the registers which don't already have them, based
6
on the longer names they are given in the memory map.
4
7
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
Message-id: 20210108180401.2263-3-peter.maydell@linaro.org
8
Message-id: 20220221094144.426191-1-peter.maydell@linaro.org
9
---
11
---
10
hw/arm/mps2-tz.c | 2 +-
12
hw/net/lan9118.c | 24 ++++++++++++++++++------
11
1 file changed, 1 insertion(+), 1 deletion(-)
13
1 file changed, 18 insertions(+), 6 deletions(-)
12
14
13
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
15
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
14
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/arm/mps2-tz.c
17
--- a/hw/net/lan9118.c
16
+++ b/hw/arm/mps2-tz.c
18
+++ b/hw/net/lan9118.c
17
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@ do { hw_error("lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
18
* Application Note AN524:
20
do { fprintf(stderr, "lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
19
* https://developer.arm.com/documentation/dai0524/latest/
21
#endif
20
* Application Note AN547:
22
21
- * https://developer.arm.com/-/media/Arm%20Developer%20Community/PDF/DAI0547B_SSE300_PLUS_U55_FPGA_for_mps3.pdf
23
+/* The tx and rx fifo ports are a range of aliased 32-bit registers */
22
+ * https://developer.arm.com/documentation/dai0547/latest/
24
+#define RX_DATA_FIFO_PORT_FIRST 0x00
23
*
25
+#define RX_DATA_FIFO_PORT_LAST 0x1f
24
* The AN505 defers to the Cortex-M33 processor ARMv8M IoT Kit FVP User Guide
26
+#define TX_DATA_FIFO_PORT_FIRST 0x20
25
* (ARM ECM0601256) for the details of some of the device layout:
27
+#define TX_DATA_FIFO_PORT_LAST 0x3f
28
+
29
+#define RX_STATUS_FIFO_PORT 0x40
30
+#define RX_STATUS_FIFO_PEEK 0x44
31
+#define TX_STATUS_FIFO_PORT 0x48
32
+#define TX_STATUS_FIFO_PEEK 0x4c
33
+
34
#define CSR_ID_REV 0x50
35
#define CSR_IRQ_CFG 0x54
36
#define CSR_INT_STS 0x58
37
@@ -XXX,XX +XXX,XX @@ static void lan9118_writel(void *opaque, hwaddr offset,
38
offset &= 0xff;
39
40
//DPRINTF("Write reg 0x%02x = 0x%08x\n", (int)offset, val);
41
- if (offset >= 0x20 && offset < 0x40) {
42
+ if (offset >= TX_DATA_FIFO_PORT_FIRST &&
43
+ offset <= TX_DATA_FIFO_PORT_LAST) {
44
/* TX FIFO */
45
tx_fifo_push(s, val);
46
return;
47
@@ -XXX,XX +XXX,XX @@ static uint64_t lan9118_readl(void *opaque, hwaddr offset,
48
lan9118_state *s = (lan9118_state *)opaque;
49
50
//DPRINTF("Read reg 0x%02x\n", (int)offset);
51
- if (offset < 0x20) {
52
+ if (offset <= RX_DATA_FIFO_PORT_LAST) {
53
/* RX FIFO */
54
return rx_fifo_pop(s);
55
}
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;
26
--
71
--
27
2.25.1
72
2.20.1
28
73
29
74
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
This feature widens physical addresses (and intermediate physical
3
This patch allows NPCM7XX CLK module to compute clocks that are used by
4
addresses for 2-stage translation) from 48 to 52 bits, when using
4
other NPCM7XX modules.
5
64k pages. The only thing left at this point is to handle the
6
extra bits in the TTBR and in the table descriptors.
7
5
8
Note that PAR_EL1 and HPFAR_EL2 are nominally extended, but we don't
6
Add a new struct NPCM7xxClockConverterState which represents a
9
mask out the high bits when writing to those registers, so no changes
7
single converter. Each clock converter in CLK module represents one
10
are required there.
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.
11
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>
12
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
23
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
13
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
24
Message-id: 20210108190945.949196-2-wuhaotsh@google.com
14
Message-id: 20220301215958.157011-11-richard.henderson@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
docs/system/arm/emulation.rst | 1 +
27
include/hw/misc/npcm7xx_clk.h | 140 +++++-
18
target/arm/cpu-param.h | 2 +-
28
hw/misc/npcm7xx_clk.c | 805 +++++++++++++++++++++++++++++++++-
19
target/arm/cpu64.c | 2 +-
29
2 files changed, 932 insertions(+), 13 deletions(-)
20
target/arm/helper.c | 19 ++++++++++++++++---
21
4 files changed, 19 insertions(+), 5 deletions(-)
22
30
23
diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst
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/docs/system/arm/emulation.rst
33
--- a/include/hw/misc/npcm7xx_clk.h
26
+++ b/docs/system/arm/emulation.rst
34
+++ b/include/hw/misc/npcm7xx_clk.h
27
@@ -XXX,XX +XXX,XX @@ the following architecture extensions:
35
@@ -XXX,XX +XXX,XX @@
28
- FEAT_I8MM (AArch64 Int8 matrix multiplication instructions)
36
#define NPCM7XX_CLK_H
29
- FEAT_JSCVT (JavaScript conversion instructions)
37
30
- FEAT_LOR (Limited ordering regions)
38
#include "exec/memory.h"
31
+- FEAT_LPA (Large Physical Address space)
39
+#include "hw/clock.h"
32
- FEAT_LRCPC (Load-acquire RCpc instructions)
40
#include "hw/sysbus.h"
33
- FEAT_LRCPC2 (Load-acquire RCpc instructions v2)
41
34
- FEAT_LSE (Large System Extensions)
42
/*
35
diff --git a/target/arm/cpu-param.h b/target/arm/cpu-param.h
43
@@ -XXX,XX +XXX,XX @@
44
45
#define NPCM7XX_WATCHDOG_RESET_GPIO_IN "npcm7xx-clk-watchdog-reset-gpio-in"
46
47
-typedef struct NPCM7xxCLKState {
48
+/* Maximum amount of clock inputs in a SEL module. */
49
+#define NPCM7XX_CLK_SEL_MAX_INPUT 5
50
+
51
+/* PLLs in CLK module. */
52
+typedef enum NPCM7xxClockPLL {
53
+ NPCM7XX_CLOCK_PLL0,
54
+ NPCM7XX_CLOCK_PLL1,
55
+ NPCM7XX_CLOCK_PLL2,
56
+ NPCM7XX_CLOCK_PLLG,
57
+ NPCM7XX_CLOCK_NR_PLLS,
58
+} NPCM7xxClockPLL;
59
+
60
+/* SEL/MUX in CLK module. */
61
+typedef enum NPCM7xxClockSEL {
62
+ NPCM7XX_CLOCK_PIXCKSEL,
63
+ NPCM7XX_CLOCK_MCCKSEL,
64
+ NPCM7XX_CLOCK_CPUCKSEL,
65
+ NPCM7XX_CLOCK_CLKOUTSEL,
66
+ NPCM7XX_CLOCK_UARTCKSEL,
67
+ NPCM7XX_CLOCK_TIMCKSEL,
68
+ NPCM7XX_CLOCK_SDCKSEL,
69
+ NPCM7XX_CLOCK_GFXMSEL,
70
+ NPCM7XX_CLOCK_SUCKSEL,
71
+ NPCM7XX_CLOCK_NR_SELS,
72
+} NPCM7xxClockSEL;
73
+
74
+/* Dividers in CLK module. */
75
+typedef enum NPCM7xxClockDivider {
76
+ NPCM7XX_CLOCK_PLL1D2, /* PLL1/2 */
77
+ NPCM7XX_CLOCK_PLL2D2, /* PLL2/2 */
78
+ NPCM7XX_CLOCK_MC_DIVIDER,
79
+ NPCM7XX_CLOCK_AXI_DIVIDER,
80
+ NPCM7XX_CLOCK_AHB_DIVIDER,
81
+ NPCM7XX_CLOCK_AHB3_DIVIDER,
82
+ NPCM7XX_CLOCK_SPI0_DIVIDER,
83
+ NPCM7XX_CLOCK_SPIX_DIVIDER,
84
+ NPCM7XX_CLOCK_APB1_DIVIDER,
85
+ NPCM7XX_CLOCK_APB2_DIVIDER,
86
+ NPCM7XX_CLOCK_APB3_DIVIDER,
87
+ NPCM7XX_CLOCK_APB4_DIVIDER,
88
+ NPCM7XX_CLOCK_APB5_DIVIDER,
89
+ NPCM7XX_CLOCK_CLKOUT_DIVIDER,
90
+ NPCM7XX_CLOCK_UART_DIVIDER,
91
+ NPCM7XX_CLOCK_TIMER_DIVIDER,
92
+ NPCM7XX_CLOCK_ADC_DIVIDER,
93
+ NPCM7XX_CLOCK_MMC_DIVIDER,
94
+ NPCM7XX_CLOCK_SDHC_DIVIDER,
95
+ NPCM7XX_CLOCK_GFXM_DIVIDER, /* divide by 3 */
96
+ NPCM7XX_CLOCK_UTMI_DIVIDER,
97
+ NPCM7XX_CLOCK_NR_DIVIDERS,
98
+} NPCM7xxClockConverter;
99
+
100
+typedef struct NPCM7xxCLKState NPCM7xxCLKState;
101
+
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
36
index XXXXXXX..XXXXXXX 100644
198
index XXXXXXX..XXXXXXX 100644
37
--- a/target/arm/cpu-param.h
199
--- a/hw/misc/npcm7xx_clk.c
38
+++ b/target/arm/cpu-param.h
200
+++ b/hw/misc/npcm7xx_clk.c
39
@@ -XXX,XX +XXX,XX @@
201
@@ -XXX,XX +XXX,XX @@
40
202
41
#ifdef TARGET_AARCH64
203
#include "hw/misc/npcm7xx_clk.h"
42
# define TARGET_LONG_BITS 64
204
#include "hw/timer/npcm7xx_timer.h"
43
-# define TARGET_PHYS_ADDR_SPACE_BITS 48
205
+#include "hw/qdev-clock.h"
44
+# define TARGET_PHYS_ADDR_SPACE_BITS 52
206
#include "migration/vmstate.h"
45
# define TARGET_VIRT_ADDR_SPACE_BITS 52
207
#include "qemu/error-report.h"
46
#else
208
#include "qemu/log.h"
47
# define TARGET_LONG_BITS 32
209
@@ -XXX,XX +XXX,XX @@
48
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
210
#include "trace.h"
49
index XXXXXXX..XXXXXXX 100644
211
#include "sysemu/watchdog.h"
50
--- a/target/arm/cpu64.c
212
51
+++ b/target/arm/cpu64.c
213
+/*
52
@@ -XXX,XX +XXX,XX @@ static void aarch64_max_initfn(Object *obj)
214
+ * The reference clock hz, and the SECCNT and CNTR25M registers in this module,
53
cpu->isar.id_aa64pfr1 = t;
215
+ * is always 25 MHz.
54
216
+ */
55
t = cpu->isar.id_aa64mmfr0;
217
+#define NPCM7XX_CLOCK_REF_HZ (25000000)
56
- t = FIELD_DP64(t, ID_AA64MMFR0, PARANGE, 5); /* PARange: 48 bits */
218
+
57
+ t = FIELD_DP64(t, ID_AA64MMFR0, PARANGE, 6); /* FEAT_LPA: 52 bits */
219
+/* Register Field Definitions */
58
cpu->isar.id_aa64mmfr0 = t;
220
+#define NPCM7XX_CLK_WDRCR_CA9C BIT(0) /* Cortex A9 Cores */
59
221
+
60
t = cpu->isar.id_aa64mmfr1;
222
#define PLLCON_LOKI BIT(31)
61
diff --git a/target/arm/helper.c b/target/arm/helper.c
223
#define PLLCON_LOKS BIT(30)
62
index XXXXXXX..XXXXXXX 100644
224
#define PLLCON_PWDEN BIT(12)
63
--- a/target/arm/helper.c
225
+#define PLLCON_FBDV(con) extract32((con), 16, 12)
64
+++ b/target/arm/helper.c
226
+#define PLLCON_OTDV2(con) extract32((con), 13, 3)
65
@@ -XXX,XX +XXX,XX @@ static const uint8_t pamax_map[] = {
227
+#define PLLCON_OTDV1(con) extract32((con), 8, 3)
66
[3] = 42,
228
+#define PLLCON_INDV(con) extract32((con), 0, 6)
67
[4] = 44,
229
68
[5] = 48,
230
enum NPCM7xxCLKRegisters {
69
+ [6] = 52,
231
NPCM7XX_CLK_CLKEN1,
232
@@ -XXX,XX +XXX,XX @@ static const uint32_t cold_reset_values[NPCM7XX_CLK_NR_REGS] = {
233
[NPCM7XX_CLK_AHBCKFI] = 0x000000c8,
70
};
234
};
71
235
72
/* The cpu-specific constant value of PAMax; also used by hw/arm/virt. */
236
-/* Register Field Definitions */
73
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
237
-#define NPCM7XX_CLK_WDRCR_CA9C BIT(0) /* Cortex A9 Cores */
74
descaddr = extract64(ttbr, 0, 48);
238
-
75
239
/* The number of watchdogs that can trigger a reset. */
76
/*
240
#define NPCM7XX_NR_WATCHDOGS (3)
77
- * If the base address is out of range, raise AddressSizeFault.
241
78
+ * For FEAT_LPA and PS=6, bits [51:48] of descaddr are in [5:2] of TTBR.
242
+/* Clock converter functions */
79
+ *
243
+
80
+ * Otherwise, if the base address is out of range, raise AddressSizeFault.
244
+#define TYPE_NPCM7XX_CLOCK_PLL "npcm7xx-clock-pll"
81
* In the pseudocode, this is !IsZero(baseregister<47:outputsize>),
245
+#define NPCM7XX_CLOCK_PLL(obj) OBJECT_CHECK(NPCM7xxClockPLLState, \
82
* but we've just cleared the bits above 47, so simplify the test.
246
+ (obj), TYPE_NPCM7XX_CLOCK_PLL)
83
*/
247
+#define TYPE_NPCM7XX_CLOCK_SEL "npcm7xx-clock-sel"
84
- if (descaddr >> outputsize) {
248
+#define NPCM7XX_CLOCK_SEL(obj) OBJECT_CHECK(NPCM7xxClockSELState, \
85
+ if (outputsize > 48) {
249
+ (obj), TYPE_NPCM7XX_CLOCK_SEL)
86
+ descaddr |= extract64(ttbr, 2, 4) << 48;
250
+#define TYPE_NPCM7XX_CLOCK_DIVIDER "npcm7xx-clock-divider"
87
+ } else if (descaddr >> outputsize) {
251
+#define NPCM7XX_CLOCK_DIVIDER(obj) OBJECT_CHECK(NPCM7xxClockDividerState, \
88
level = 0;
252
+ (obj), TYPE_NPCM7XX_CLOCK_DIVIDER)
89
fault_type = ARMFault_AddressSize;
253
+
90
goto do_fault;
254
+static void npcm7xx_clk_update_pll(void *opaque)
91
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
255
+{
256
+ NPCM7xxClockPLLState *s = opaque;
257
+ uint32_t con = s->clk->regs[s->reg];
258
+ uint64_t freq;
259
+
260
+ /* The PLL is grounded if it is not locked yet. */
261
+ if (con & PLLCON_LOKI) {
262
+ freq = clock_get_hz(s->clock_in);
263
+ freq *= PLLCON_FBDV(con);
264
+ freq /= PLLCON_INDV(con) * PLLCON_OTDV1(con) * PLLCON_OTDV2(con);
265
+ } else {
266
+ freq = 0;
267
+ }
268
+
269
+ clock_update_hz(s->clock_out, freq);
270
+}
271
+
272
+static void npcm7xx_clk_update_sel(void *opaque)
273
+{
274
+ NPCM7xxClockSELState *s = opaque;
275
+ uint32_t index = extract32(s->clk->regs[NPCM7XX_CLK_CLKSEL], s->offset,
276
+ s->len);
277
+
278
+ if (index >= s->input_size) {
279
+ qemu_log_mask(LOG_GUEST_ERROR,
280
+ "%s: SEL index: %u out of range\n",
281
+ __func__, index);
282
+ index = 0;
283
+ }
284
+ clock_update_hz(s->clock_out, clock_get_hz(s->clock_in[index]));
285
+}
286
+
287
+static void npcm7xx_clk_update_divider(void *opaque)
288
+{
289
+ NPCM7xxClockDividerState *s = opaque;
290
+ uint32_t freq;
291
+
292
+ freq = s->divide(s);
293
+ clock_update_hz(s->clock_out, freq);
294
+}
295
+
296
+static uint32_t divide_by_constant(NPCM7xxClockDividerState *s)
297
+{
298
+ return clock_get_hz(s->clock_in) / s->divisor;
299
+}
300
+
301
+static uint32_t divide_by_reg_divisor(NPCM7xxClockDividerState *s)
302
+{
303
+ return clock_get_hz(s->clock_in) /
304
+ (extract32(s->clk->regs[s->reg], s->offset, s->len) + 1);
305
+}
306
+
307
+static uint32_t divide_by_reg_divisor_times_2(NPCM7xxClockDividerState *s)
308
+{
309
+ return divide_by_reg_divisor(s) / 2;
310
+}
311
+
312
+static uint32_t shift_by_reg_divisor(NPCM7xxClockDividerState *s)
313
+{
314
+ return clock_get_hz(s->clock_in) >>
315
+ extract32(s->clk->regs[s->reg], s->offset, s->len);
316
+}
317
+
318
+static NPCM7xxClockPLL find_pll_by_reg(enum NPCM7xxCLKRegisters reg)
319
+{
320
+ switch (reg) {
321
+ case NPCM7XX_CLK_PLLCON0:
322
+ return NPCM7XX_CLOCK_PLL0;
323
+ case NPCM7XX_CLK_PLLCON1:
324
+ return NPCM7XX_CLOCK_PLL1;
325
+ case NPCM7XX_CLK_PLLCON2:
326
+ return NPCM7XX_CLOCK_PLL2;
327
+ case NPCM7XX_CLK_PLLCONG:
328
+ return NPCM7XX_CLOCK_PLLG;
329
+ default:
330
+ g_assert_not_reached();
331
+ }
332
+}
333
+
334
+static void npcm7xx_clk_update_all_plls(NPCM7xxCLKState *clk)
335
+{
336
+ int i;
337
+
338
+ for (i = 0; i < NPCM7XX_CLOCK_NR_PLLS; ++i) {
339
+ npcm7xx_clk_update_pll(&clk->plls[i]);
340
+ }
341
+}
342
+
343
+static void npcm7xx_clk_update_all_sels(NPCM7xxCLKState *clk)
344
+{
345
+ int i;
346
+
347
+ for (i = 0; i < NPCM7XX_CLOCK_NR_SELS; ++i) {
348
+ npcm7xx_clk_update_sel(&clk->sels[i]);
349
+ }
350
+}
351
+
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);
833
+ }
834
+ }
835
+ for (i = 0; i < NPCM7XX_CLOCK_NR_DIVIDERS; ++i) {
836
+ src = npcm7xx_get_clock(clk, divider_init_info_list[i].src_type,
837
+ divider_init_info_list[i].src_index);
838
+ clock_set_source(clk->dividers[i].clock_in, src);
839
+ }
840
+}
841
+
842
static uint64_t npcm7xx_clk_read(void *opaque, hwaddr offset, unsigned size)
843
{
844
uint32_t reg = offset / sizeof(uint32_t);
845
@@ -XXX,XX +XXX,XX @@ static uint64_t npcm7xx_clk_read(void *opaque, hwaddr offset, unsigned size)
846
*
847
* The 4 LSBs are always zero: (1e9 / 640) << 4 = 25000000.
848
*/
849
- value = (((now_ns - s->ref_ns) / 640) << 4) % NPCM7XX_TIMER_REF_HZ;
850
+ value = (((now_ns - s->ref_ns) / 640) << 4) % NPCM7XX_CLOCK_REF_HZ;
851
break;
852
853
default:
854
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_write(void *opaque, hwaddr offset,
855
value |= (value & PLLCON_LOKS);
856
}
92
}
857
}
93
858
+ /* Only update PLL when it is locked. */
94
descaddr = descriptor & descaddrmask;
859
+ if (value & PLLCON_LOKI) {
95
- if (descaddr >> outputsize) {
860
+ npcm7xx_clk_update_pll(&s->plls[find_pll_by_reg(reg)]);
96
+
861
+ }
97
+ /*
862
+ break;
98
+ * For FEAT_LPA and PS=6, bits [51:48] of descaddr are in [15:12]
863
+
99
+ * of descriptor. Otherwise, if descaddr is out of range, raise
864
+ case NPCM7XX_CLK_CLKSEL:
100
+ * AddressSizeFault.
865
+ npcm7xx_clk_update_all_sels(s);
101
+ */
866
+ break;
102
+ if (outputsize > 48) {
867
+
103
+ descaddr |= extract64(descriptor, 12, 4) << 48;
868
+ case NPCM7XX_CLK_CLKDIV1:
104
+ } else if (descaddr >> outputsize) {
869
+ case NPCM7XX_CLK_CLKDIV2:
105
fault_type = ARMFault_AddressSize;
870
+ case NPCM7XX_CLK_CLKDIV3:
106
goto do_fault;
871
+ npcm7xx_clk_update_all_dividers(s);
107
}
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;
960
+ }
961
+ }
962
+ for (i = 0; i < NPCM7XX_CLOCK_NR_SELS; ++i) {
963
+ if (!qdev_realize(DEVICE(&s->sels[i]), NULL, errp)) {
964
+ return;
965
+ }
966
+ }
967
+ for (i = 0; i < NPCM7XX_CLOCK_NR_DIVIDERS; ++i) {
968
+ if (!qdev_realize(DEVICE(&s->dividers[i]), NULL, errp)) {
969
+ return;
970
+ }
971
+ }
972
+}
973
+
974
+static const VMStateDescription vmstate_npcm7xx_clk_pll = {
975
+ .name = "npcm7xx-clock-pll",
976
.version_id = 0,
977
.minimum_version_id = 0,
978
- .fields = (VMStateField[]) {
979
- VMSTATE_UINT32_ARRAY(regs, NPCM7xxCLKState, NPCM7XX_CLK_NR_REGS),
980
- VMSTATE_INT64(ref_ns, NPCM7xxCLKState),
981
+ .fields = (VMStateField[]) {
982
+ VMSTATE_CLOCK(clock_in, NPCM7xxClockPLLState),
983
VMSTATE_END_OF_LIST(),
984
},
985
};
986
987
+static const VMStateDescription vmstate_npcm7xx_clk_sel = {
988
+ .name = "npcm7xx-clock-sel",
989
+ .version_id = 0,
990
+ .minimum_version_id = 0,
991
+ .fields = (VMStateField[]) {
992
+ VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(clock_in, NPCM7xxClockSELState,
993
+ NPCM7XX_CLK_SEL_MAX_INPUT, 0, vmstate_clock, Clock),
994
+ VMSTATE_END_OF_LIST(),
995
+ },
996
+};
997
+
998
+static const VMStateDescription vmstate_npcm7xx_clk_divider = {
999
+ .name = "npcm7xx-clock-divider",
1000
+ .version_id = 0,
1001
+ .minimum_version_id = 0,
1002
+ .fields = (VMStateField[]) {
1003
+ VMSTATE_CLOCK(clock_in, NPCM7xxClockDividerState),
1004
+ VMSTATE_END_OF_LIST(),
1005
+ },
1006
+};
1007
+
1008
+static const VMStateDescription vmstate_npcm7xx_clk = {
1009
+ .name = "npcm7xx-clk",
1010
+ .version_id = 1,
1011
+ .minimum_version_id = 1,
1012
+ .post_load = npcm7xx_clk_post_load,
1013
+ .fields = (VMStateField[]) {
1014
+ VMSTATE_UINT32_ARRAY(regs, NPCM7xxCLKState, NPCM7XX_CLK_NR_REGS),
1015
+ VMSTATE_INT64(ref_ns, NPCM7xxCLKState),
1016
+ VMSTATE_CLOCK(clkref, NPCM7xxCLKState),
1017
+ VMSTATE_END_OF_LIST(),
1018
+ },
1019
+};
1020
+
1021
+static void npcm7xx_clk_pll_class_init(ObjectClass *klass, void *data)
1022
+{
1023
+ DeviceClass *dc = DEVICE_CLASS(klass);
1024
+
1025
+ dc->desc = "NPCM7xx Clock PLL Module";
1026
+ dc->vmsd = &vmstate_npcm7xx_clk_pll;
1027
+}
1028
+
1029
+static void npcm7xx_clk_sel_class_init(ObjectClass *klass, void *data)
1030
+{
1031
+ DeviceClass *dc = DEVICE_CLASS(klass);
1032
+
1033
+ dc->desc = "NPCM7xx Clock SEL Module";
1034
+ dc->vmsd = &vmstate_npcm7xx_clk_sel;
1035
+}
1036
+
1037
+static void npcm7xx_clk_divider_class_init(ObjectClass *klass, void *data)
1038
+{
1039
+ DeviceClass *dc = DEVICE_CLASS(klass);
1040
+
1041
+ dc->desc = "NPCM7xx Clock Divider Module";
1042
+ dc->vmsd = &vmstate_npcm7xx_clk_divider;
1043
+}
1044
+
1045
static void npcm7xx_clk_class_init(ObjectClass *klass, void *data)
1046
{
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;
1054
}
1055
1056
+static const TypeInfo npcm7xx_clk_pll_info = {
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)
1086
{
1087
+ type_register_static(&npcm7xx_clk_pll_info);
1088
+ type_register_static(&npcm7xx_clk_sel_info);
1089
+ type_register_static(&npcm7xx_clk_divider_info);
1090
type_register_static(&npcm7xx_clk_info);
1091
}
1092
type_init(npcm7xx_clk_register_type);
108
--
1093
--
109
2.25.1
1094
2.20.1
1095
1096
diff view generated by jsdifflib
1
From: Patrick Venture <venture@google.com>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
Previously this device created N subdevices which each owned an i2c bus.
3
This patch makes NPCM7XX Timer to use a the timer clock generated by the
4
Now this device simply owns the N i2c busses directly.
4
CLK module instead of the magic number TIMER_REF_HZ.
5
5
6
Tested: Verified devices behind mux are still accessible via qmp and i2c
6
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
7
from within an arm32 SoC.
7
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
8
8
Signed-off-by: Hao Wu <wuhaotsh@google.com>
9
Reviewed-by: Hao Wu <wuhaotsh@google.com>
9
Message-id: 20210108190945.949196-3-wuhaotsh@google.com
10
Signed-off-by: Patrick Venture <venture@google.com>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
12
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
13
Message-id: 20220202164533.1283668-1-venture@google.com
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
---
12
---
16
hw/i2c/i2c_mux_pca954x.c | 77 +++++++---------------------------------
13
include/hw/misc/npcm7xx_clk.h | 6 -----
17
1 file changed, 13 insertions(+), 64 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(-)
18
18
19
diff --git a/hw/i2c/i2c_mux_pca954x.c b/hw/i2c/i2c_mux_pca954x.c
19
diff --git a/include/hw/misc/npcm7xx_clk.h b/include/hw/misc/npcm7xx_clk.h
20
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
21
--- a/hw/i2c/i2c_mux_pca954x.c
21
--- a/include/hw/misc/npcm7xx_clk.h
22
+++ b/hw/i2c/i2c_mux_pca954x.c
22
+++ b/include/hw/misc/npcm7xx_clk.h
23
@@ -XXX,XX +XXX,XX @@
23
@@ -XXX,XX +XXX,XX @@
24
#define PCA9548_CHANNEL_COUNT 8
24
#include "hw/clock.h"
25
#define PCA9546_CHANNEL_COUNT 4
25
#include "hw/sysbus.h"
26
26
27
-/*
27
-/*
28
- * struct Pca954xChannel - The i2c mux device will have N of these states
28
- * The reference clock frequency for the timer modules, and the SECCNT and
29
- * that own the i2c channel bus.
29
- * CNTR25M registers in this module, is always 25 MHz.
30
- * @bus: The owned channel bus.
31
- * @enabled: Is this channel active?
32
- */
30
- */
33
-typedef struct Pca954xChannel {
31
-#define NPCM7XX_TIMER_REF_HZ (25000000)
34
- SysBusDevice parent;
35
-
36
- I2CBus *bus;
37
-
38
- bool enabled;
39
-} Pca954xChannel;
40
-
41
-#define TYPE_PCA954X_CHANNEL "pca954x-channel"
42
-#define PCA954X_CHANNEL(obj) \
43
- OBJECT_CHECK(Pca954xChannel, (obj), TYPE_PCA954X_CHANNEL)
44
-
32
-
45
/*
33
/*
46
* struct Pca954xState - The pca954x state object.
34
* Number of registers in our device state structure. Don't change this without
47
* @control: The value written to the mux control.
35
* incrementing the version_id in the vmstate.
48
@@ -XXX,XX +XXX,XX @@ typedef struct Pca954xState {
36
diff --git a/include/hw/timer/npcm7xx_timer.h b/include/hw/timer/npcm7xx_timer.h
49
37
index XXXXXXX..XXXXXXX 100644
50
uint8_t control;
38
--- a/include/hw/timer/npcm7xx_timer.h
51
39
+++ b/include/hw/timer/npcm7xx_timer.h
52
- /* The channel i2c buses. */
40
@@ -XXX,XX +XXX,XX @@ struct NPCM7xxTimerCtrlState {
53
- Pca954xChannel channel[PCA9548_CHANNEL_COUNT];
41
54
+ bool enabled[PCA9548_CHANNEL_COUNT];
42
uint32_t tisr;
55
+ I2CBus *bus[PCA9548_CHANNEL_COUNT];
43
56
} Pca954xState;
44
+ Clock *clock;
57
45
NPCM7xxTimer timer[NPCM7XX_TIMERS_PER_CTRL];
58
/*
46
NPCM7xxWatchdogTimer watchdog_timer;
59
@@ -XXX,XX +XXX,XX @@ static bool pca954x_match(I2CSlave *candidate, uint8_t address,
47
};
60
}
48
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
61
49
index XXXXXXX..XXXXXXX 100644
62
for (i = 0; i < mc->nchans; i++) {
50
--- a/hw/arm/npcm7xx.c
63
- if (!mux->channel[i].enabled) {
51
+++ b/hw/arm/npcm7xx.c
64
+ if (!mux->enabled[i]) {
52
@@ -XXX,XX +XXX,XX @@
65
continue;
53
#include "hw/char/serial.h"
66
}
54
#include "hw/loader.h"
67
55
#include "hw/misc/unimp.h"
68
- if (i2c_scan_bus(mux->channel[i].bus, address, broadcast,
56
+#include "hw/qdev-clock.h"
69
+ if (i2c_scan_bus(mux->bus[i], address, broadcast,
57
#include "hw/qdev-properties.h"
70
current_devs)) {
58
#include "qapi/error.h"
71
if (!broadcast) {
59
#include "qemu/units.h"
72
return true;
60
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
73
@@ -XXX,XX +XXX,XX @@ static void pca954x_enable_channel(Pca954xState *s, uint8_t enable_mask)
61
int first_irq;
62
int j;
63
64
+ /* Connect the timer clock. */
65
+ qdev_connect_clock_in(DEVICE(&s->tim[i]), "clock", qdev_get_clock_out(
66
+ DEVICE(&s->clk), "timer-clock"));
67
+
68
sysbus_realize(sbd, &error_abort);
69
sysbus_mmio_map(sbd, 0, npcm7xx_tim_addr[i]);
70
71
diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c
72
index XXXXXXX..XXXXXXX 100644
73
--- a/hw/timer/npcm7xx_timer.c
74
+++ b/hw/timer/npcm7xx_timer.c
75
@@ -XXX,XX +XXX,XX @@
76
#include "qemu/osdep.h"
77
78
#include "hw/irq.h"
79
+#include "hw/qdev-clock.h"
80
#include "hw/qdev-properties.h"
81
-#include "hw/misc/npcm7xx_clk.h"
82
#include "hw/timer/npcm7xx_timer.h"
83
#include "migration/vmstate.h"
84
#include "qemu/bitops.h"
85
@@ -XXX,XX +XXX,XX @@ static uint32_t npcm7xx_tcsr_prescaler(uint32_t tcsr)
86
/* Convert a timer cycle count to a time interval in nanoseconds. */
87
static int64_t npcm7xx_timer_count_to_ns(NPCM7xxTimer *t, uint32_t count)
88
{
89
- int64_t ns = count;
90
+ int64_t ticks = count;
91
92
- ns *= NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ;
93
- ns *= npcm7xx_tcsr_prescaler(t->tcsr);
94
+ ticks *= npcm7xx_tcsr_prescaler(t->tcsr);
95
96
- return ns;
97
+ return clock_ticks_to_ns(t->ctrl->clock, ticks);
98
}
99
100
/* Convert a time interval in nanoseconds to a timer cycle count. */
101
static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns)
102
{
103
- int64_t count;
104
-
105
- count = ns / (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ);
106
- count /= npcm7xx_tcsr_prescaler(t->tcsr);
107
-
108
- return count;
109
+ return ns / clock_ticks_to_ns(t->ctrl->clock,
110
+ npcm7xx_tcsr_prescaler(t->tcsr));
111
}
112
113
static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t)
114
@@ -XXX,XX +XXX,XX @@ static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t)
115
static void npcm7xx_watchdog_timer_reset_cycles(NPCM7xxWatchdogTimer *t,
116
int64_t cycles)
117
{
118
- uint32_t prescaler = npcm7xx_watchdog_timer_prescaler(t);
119
- int64_t ns = (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ) * cycles;
120
+ int64_t ticks = cycles * npcm7xx_watchdog_timer_prescaler(t);
121
+ int64_t ns = clock_ticks_to_ns(t->ctrl->clock, ticks);
122
123
/*
124
* The reset function always clears the current timer. The caller of the
125
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_watchdog_timer_reset_cycles(NPCM7xxWatchdogTimer *t,
74
*/
126
*/
75
for (i = 0; i < mc->nchans; i++) {
127
npcm7xx_timer_clear(&t->base_timer);
76
if (enable_mask & (1 << i)) {
128
77
- s->channel[i].enabled = true;
129
- ns *= prescaler;
78
+ s->enabled[i] = true;
130
t->base_timer.remaining_ns = ns;
79
} else {
80
- s->channel[i].enabled = false;
81
+ s->enabled[i] = false;
82
}
83
}
84
}
131
}
85
@@ -XXX,XX +XXX,XX @@ I2CBus *pca954x_i2c_get_bus(I2CSlave *mux, uint8_t channel)
132
86
Pca954xState *pca954x = PCA954X(mux);
133
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_hold_reset(Object *obj)
87
134
qemu_irq_lower(s->watchdog_timer.irq);
88
g_assert(channel < pc->nchans);
89
- return I2C_BUS(qdev_get_child_bus(DEVICE(&pca954x->channel[channel]),
90
- "i2c-bus"));
91
-}
92
-
93
-static void pca954x_channel_init(Object *obj)
94
-{
95
- Pca954xChannel *s = PCA954X_CHANNEL(obj);
96
- s->bus = i2c_init_bus(DEVICE(s), "i2c-bus");
97
-
98
- /* Start all channels as disabled. */
99
- s->enabled = false;
100
-}
101
-
102
-static void pca954x_channel_class_init(ObjectClass *klass, void *data)
103
-{
104
- DeviceClass *dc = DEVICE_CLASS(klass);
105
- dc->desc = "Pca954x Channel";
106
+ return pca954x->bus[channel];
107
}
135
}
108
136
109
static void pca9546_class_init(ObjectClass *klass, void *data)
137
-static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
110
@@ -XXX,XX +XXX,XX @@ static void pca9548_class_init(ObjectClass *klass, void *data)
138
+static void npcm7xx_timer_init(Object *obj)
111
s->nchans = PCA9548_CHANNEL_COUNT;
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);
112
}
159
}
113
160
114
-static void pca954x_realize(DeviceState *dev, Error **errp)
161
static const VMStateDescription vmstate_npcm7xx_base_timer = {
115
-{
162
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_npcm7xx_watchdog_timer = {
116
- Pca954xState *s = PCA954X(dev);
163
117
- Pca954xClass *c = PCA954X_GET_CLASS(s);
164
static const VMStateDescription vmstate_npcm7xx_timer_ctrl = {
118
- int i;
165
.name = "npcm7xx-timer-ctrl",
119
-
166
- .version_id = 1,
120
- /* SMBus modules. Cannot fail. */
167
- .minimum_version_id = 1,
121
- for (i = 0; i < c->nchans; i++) {
168
+ .version_id = 2,
122
- sysbus_realize(SYS_BUS_DEVICE(&s->channel[i]), &error_abort);
169
+ .minimum_version_id = 2,
123
- }
170
.fields = (VMStateField[]) {
124
-}
171
VMSTATE_UINT32(tisr, NPCM7xxTimerCtrlState),
125
-
172
+ VMSTATE_CLOCK(clock, NPCM7xxTimerCtrlState),
126
static void pca954x_init(Object *obj)
173
VMSTATE_STRUCT_ARRAY(timer, NPCM7xxTimerCtrlState,
127
{
174
NPCM7XX_TIMERS_PER_CTRL, 0, vmstate_npcm7xx_timer,
128
Pca954xState *s = PCA954X(obj);
175
NPCM7xxTimer),
129
Pca954xClass *c = PCA954X_GET_CLASS(obj);
176
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_class_init(ObjectClass *klass, void *data)
130
int i;
177
QEMU_BUILD_BUG_ON(NPCM7XX_TIMER_REGS_END > NPCM7XX_TIMER_NR_REGS);
131
178
132
- /* Only initialize the children we expect. */
179
dc->desc = "NPCM7xx Timer Controller";
133
+ /* SMBus modules. Cannot fail. */
180
- dc->realize = npcm7xx_timer_realize;
134
for (i = 0; i < c->nchans; i++) {
181
dc->vmsd = &vmstate_npcm7xx_timer_ctrl;
135
- object_initialize_child(obj, "channel[*]", &s->channel[i],
182
rc->phases.enter = npcm7xx_timer_enter_reset;
136
- TYPE_PCA954X_CHANNEL);
183
rc->phases.hold = npcm7xx_timer_hold_reset;
137
+ g_autofree gchar *bus_name = g_strdup_printf("i2c.%d", i);
184
@@ -XXX,XX +XXX,XX @@ static const TypeInfo npcm7xx_timer_info = {
138
+
185
.parent = TYPE_SYS_BUS_DEVICE,
139
+ /* start all channels as disabled. */
186
.instance_size = sizeof(NPCM7xxTimerCtrlState),
140
+ s->enabled[i] = false;
187
.class_init = npcm7xx_timer_class_init,
141
+ s->bus[i] = i2c_init_bus(DEVICE(s), bus_name);
188
+ .instance_init = npcm7xx_timer_init,
142
}
143
}
144
145
@@ -XXX,XX +XXX,XX @@ static void pca954x_class_init(ObjectClass *klass, void *data)
146
rc->phases.enter = pca954x_enter_reset;
147
148
dc->desc = "Pca954x i2c-mux";
149
- dc->realize = pca954x_realize;
150
151
k->write_data = pca954x_write_data;
152
k->receive_byte = pca954x_read_byte;
153
@@ -XXX,XX +XXX,XX @@ static const TypeInfo pca954x_info[] = {
154
.parent = TYPE_PCA954X,
155
.class_init = pca9548_class_init,
156
},
157
- {
158
- .name = TYPE_PCA954X_CHANNEL,
159
- .parent = TYPE_SYS_BUS_DEVICE,
160
- .class_init = pca954x_channel_class_init,
161
- .instance_size = sizeof(Pca954xChannel),
162
- .instance_init = pca954x_channel_init,
163
- }
164
};
189
};
165
190
166
DEFINE_TYPES(pca954x_info)
191
static void npcm7xx_timer_register_type(void)
167
--
192
--
168
2.25.1
193
2.20.1
169
194
170
195
diff view generated by jsdifflib
1
From: Akihiko Odaki <akihiko.odaki@gmail.com>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
Support the latest PSCI on TCG and HVF. A 64-bit function called from
3
The ADC is part of NPCM7XX Module. Its behavior is controled by the
4
AArch32 now returns NOT_SUPPORTED, which is necessary to adhere to SMC
4
ADC_CON register. It converts one of the eight analog inputs into a
5
Calling Convention 1.0. It is still not compliant with SMCCC 1.3 since
5
digital input and stores it in the ADC_DATA register when enabled.
6
they do not implement mandatory functions.
7
6
8
Signed-off-by: Akihiko Odaki <akihiko.odaki@gmail.com>
7
Users can alter input value by using qom-set QMP command.
9
Message-id: 20220213035753.34577-1-akihiko.odaki@gmail.com
8
9
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
10
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
11
Signed-off-by: Hao Wu <wuhaotsh@google.com>
12
Message-id: 20210108190945.949196-4-wuhaotsh@google.com
13
[PMM: Added missing hw/adc/trace.h file]
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
14
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
[PMM: update MISMATCH_CHECK checks on PSCI_VERSION macros to match]
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
16
---
14
target/arm/kvm-consts.h | 13 +++++++++----
17
docs/system/arm/nuvoton.rst | 2 +-
15
hw/arm/boot.c | 12 +++++++++---
18
meson.build | 1 +
16
target/arm/cpu.c | 5 +++--
19
hw/adc/trace.h | 1 +
17
target/arm/hvf/hvf.c | 27 ++++++++++++++++++++++++++-
20
include/hw/adc/npcm7xx_adc.h | 69 ++++++
18
target/arm/kvm64.c | 2 +-
21
include/hw/arm/npcm7xx.h | 2 +
19
target/arm/psci.c | 35 ++++++++++++++++++++++++++++++++---
22
hw/adc/npcm7xx_adc.c | 301 ++++++++++++++++++++++++++
20
6 files changed, 80 insertions(+), 14 deletions(-)
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
21
34
22
diff --git a/target/arm/kvm-consts.h b/target/arm/kvm-consts.h
35
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
23
index XXXXXXX..XXXXXXX 100644
36
index XXXXXXX..XXXXXXX 100644
24
--- a/target/arm/kvm-consts.h
37
--- a/docs/system/arm/nuvoton.rst
25
+++ b/target/arm/kvm-consts.h
38
+++ b/docs/system/arm/nuvoton.rst
26
@@ -XXX,XX +XXX,XX @@ MISMATCH_CHECK(QEMU_PSCI_0_1_FN_MIGRATE, KVM_PSCI_FN_MIGRATE);
39
@@ -XXX,XX +XXX,XX @@ Supported devices
27
#define QEMU_PSCI_0_2_FN64_AFFINITY_INFO QEMU_PSCI_0_2_FN64(4)
40
* Random Number Generator (RNG)
28
#define QEMU_PSCI_0_2_FN64_MIGRATE QEMU_PSCI_0_2_FN64(5)
41
* USB host (USBH)
29
42
* GPIO controller
30
+#define QEMU_PSCI_1_0_FN_PSCI_FEATURES QEMU_PSCI_0_2_FN(10)
43
+ * Analog to Digital Converter (ADC)
31
+
44
32
MISMATCH_CHECK(QEMU_PSCI_0_2_FN_CPU_SUSPEND, PSCI_0_2_FN_CPU_SUSPEND);
45
Missing devices
33
MISMATCH_CHECK(QEMU_PSCI_0_2_FN_CPU_OFF, PSCI_0_2_FN_CPU_OFF);
46
---------------
34
MISMATCH_CHECK(QEMU_PSCI_0_2_FN_CPU_ON, PSCI_0_2_FN_CPU_ON);
47
@@ -XXX,XX +XXX,XX @@ Missing devices
35
@@ -XXX,XX +XXX,XX @@ MISMATCH_CHECK(QEMU_PSCI_0_2_FN_MIGRATE, PSCI_0_2_FN_MIGRATE);
48
* USB device (USBD)
36
MISMATCH_CHECK(QEMU_PSCI_0_2_FN64_CPU_SUSPEND, PSCI_0_2_FN64_CPU_SUSPEND);
49
* SMBus controller (SMBF)
37
MISMATCH_CHECK(QEMU_PSCI_0_2_FN64_CPU_ON, PSCI_0_2_FN64_CPU_ON);
50
* Peripheral SPI controller (PSPI)
38
MISMATCH_CHECK(QEMU_PSCI_0_2_FN64_MIGRATE, PSCI_0_2_FN64_MIGRATE);
51
- * Analog to Digital Converter (ADC)
39
+MISMATCH_CHECK(QEMU_PSCI_1_0_FN_PSCI_FEATURES, PSCI_1_0_FN_PSCI_FEATURES);
52
* SD/MMC host
40
53
* PECI interface
41
/* PSCI v0.2 return values used by TCG emulation of PSCI */
54
* Pulse Width Modulation (PWM)
42
55
diff --git a/meson.build b/meson.build
43
/* No Trusted OS migration to worry about when offlining CPUs */
44
#define QEMU_PSCI_0_2_RET_TOS_MIGRATION_NOT_REQUIRED 2
45
46
-/* We implement version 0.2 only */
47
-#define QEMU_PSCI_0_2_RET_VERSION_0_2 2
48
+#define QEMU_PSCI_VERSION_0_1 0x00001
49
+#define QEMU_PSCI_VERSION_0_2 0x00002
50
+#define QEMU_PSCI_VERSION_1_1 0x10001
51
52
MISMATCH_CHECK(QEMU_PSCI_0_2_RET_TOS_MIGRATION_NOT_REQUIRED, PSCI_0_2_TOS_MP);
53
-MISMATCH_CHECK(QEMU_PSCI_0_2_RET_VERSION_0_2,
54
- (PSCI_VERSION_MAJOR(0) | PSCI_VERSION_MINOR(2)));
55
+/* We don't bother to check every possible version value */
56
+MISMATCH_CHECK(QEMU_PSCI_VERSION_0_2, PSCI_VERSION(0, 2));
57
+MISMATCH_CHECK(QEMU_PSCI_VERSION_1_1, PSCI_VERSION(1, 1));
58
59
/* PSCI return values (inclusive of all PSCI versions) */
60
#define QEMU_PSCI_RET_SUCCESS 0
61
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
62
index XXXXXXX..XXXXXXX 100644
56
index XXXXXXX..XXXXXXX 100644
63
--- a/hw/arm/boot.c
57
--- a/meson.build
64
+++ b/hw/arm/boot.c
58
+++ b/meson.build
65
@@ -XXX,XX +XXX,XX @@ static void fdt_add_psci_node(void *fdt)
59
@@ -XXX,XX +XXX,XX @@ if have_system
66
}
60
'chardev',
67
61
'hw/9pfs',
68
qemu_fdt_add_subnode(fdt, "/psci");
62
'hw/acpi',
69
- if (armcpu->psci_version == 2) {
63
+ 'hw/adc',
70
- const char comp[] = "arm,psci-0.2\0arm,psci";
64
'hw/alpha',
71
- qemu_fdt_setprop(fdt, "/psci", "compatible", comp, sizeof(comp));
65
'hw/arm',
72
+ if (armcpu->psci_version == QEMU_PSCI_VERSION_0_2 ||
66
'hw/audio',
73
+ armcpu->psci_version == QEMU_PSCI_VERSION_1_1) {
67
diff --git a/hw/adc/trace.h b/hw/adc/trace.h
74
+ if (armcpu->psci_version == QEMU_PSCI_VERSION_0_2) {
68
new file mode 100644
75
+ const char comp[] = "arm,psci-0.2\0arm,psci";
69
index XXXXXXX..XXXXXXX
76
+ qemu_fdt_setprop(fdt, "/psci", "compatible", comp, sizeof(comp));
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
79
@@ -XXX,XX +XXX,XX @@
80
+/*
81
+ * Nuvoton NPCM7xx ADC 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_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
+ }
77
+ } else {
320
+ } else {
78
+ const char comp[] = "arm,psci-1.0\0arm,psci-0.2\0arm,psci";
321
+ timer_del(&s->conv_timer);
79
+ qemu_fdt_setprop(fdt, "/psci", "compatible", comp, sizeof(comp));
80
+ }
322
+ }
81
323
+ }
82
cpu_off_fn = QEMU_PSCI_0_2_FN_CPU_OFF;
324
+}
83
if (arm_feature(&armcpu->env, ARM_FEATURE_AARCH64)) {
325
+
84
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
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
85
index XXXXXXX..XXXXXXX 100644
477
index XXXXXXX..XXXXXXX 100644
86
--- a/target/arm/cpu.c
478
--- a/hw/arm/npcm7xx.c
87
+++ b/target/arm/cpu.c
479
+++ b/hw/arm/npcm7xx.c
88
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_initfn(Object *obj)
480
@@ -XXX,XX +XXX,XX @@
89
* picky DTB consumer will also provide a helpful error message.
481
#define NPCM7XX_EHCI_BA (0xf0806000)
90
*/
482
#define NPCM7XX_OHCI_BA (0xf0807000)
91
cpu->dtb_compatible = "qemu,unknown";
483
92
- cpu->psci_version = 1; /* By default assume PSCI v0.1 */
484
+/* ADC Module */
93
+ cpu->psci_version = QEMU_PSCI_VERSION_0_1; /* By default assume PSCI v0.1 */
485
+#define NPCM7XX_ADC_BA (0xf000c000)
94
cpu->kvm_target = QEMU_KVM_ARM_TARGET_NONE;
486
+
95
487
/* Internal AHB SRAM */
96
if (tcg_enabled() || hvf_enabled()) {
488
#define NPCM7XX_RAM3_BA (0xc0008000)
97
- cpu->psci_version = 2; /* TCG and HVF implement PSCI 0.2 */
489
#define NPCM7XX_RAM3_SZ (4 * KiB)
98
+ /* TCG and HVF implement PSCI 1.1 */
490
@@ -XXX,XX +XXX,XX @@
99
+ cpu->psci_version = QEMU_PSCI_VERSION_1_1;
491
#define NPCM7XX_ROM_BA (0xffff0000)
100
}
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));
101
}
508
}
102
509
103
diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c
510
+static void npcm7xx_write_adc_calibration(NPCM7xxState *s)
511
+{
512
+ /* Both ADC and the fuse array must have realized. */
513
+ QEMU_BUILD_BUG_ON(sizeof(s->adc.calibration_r_values) != 4);
514
+ npcm7xx_otp_array_write(&s->fuse_array, s->adc.calibration_r_values,
515
+ NPCM7XX_FUSE_ADC_CALIB, sizeof(s->adc.calibration_r_values));
516
+}
517
+
518
static qemu_irq npcm7xx_irq(NPCM7xxState *s, int n)
519
{
520
return qdev_get_gpio_in(DEVICE(&s->a9mpcore), n);
521
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
522
TYPE_NPCM7XX_FUSE_ARRAY);
523
object_initialize_child(obj, "mc", &s->mc, TYPE_NPCM7XX_MC);
524
object_initialize_child(obj, "rng", &s->rng, TYPE_NPCM7XX_RNG);
525
+ object_initialize_child(obj, "adc", &s->adc, TYPE_NPCM7XX_ADC);
526
527
for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
528
object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
529
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
530
sysbus_realize(SYS_BUS_DEVICE(&s->mc), &error_abort);
531
sysbus_mmio_map(SYS_BUS_DEVICE(&s->mc), 0, NPCM7XX_MC_BA);
532
533
+ /* ADC Modules. Cannot fail. */
534
+ qdev_connect_clock_in(DEVICE(&s->adc), "clock", qdev_get_clock_out(
535
+ DEVICE(&s->clk), "adc-clock"));
536
+ sysbus_realize(SYS_BUS_DEVICE(&s->adc), &error_abort);
537
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->adc), 0, NPCM7XX_ADC_BA);
538
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0,
539
+ npcm7xx_irq(s, NPCM7XX_ADC_IRQ));
540
+ npcm7xx_write_adc_calibration(s);
541
+
542
/* Timer Modules (TIM). Cannot fail. */
543
QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_tim_addr) != ARRAY_SIZE(s->tim));
544
for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
545
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
546
create_unimplemented_device("npcm7xx.vdmx", 0xe0800000, 4 * KiB);
547
create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB);
548
create_unimplemented_device("npcm7xx.kcs", 0xf0007000, 4 * KiB);
549
- create_unimplemented_device("npcm7xx.adc", 0xf000c000, 4 * KiB);
550
create_unimplemented_device("npcm7xx.gfxi", 0xf000e000, 4 * KiB);
551
create_unimplemented_device("npcm7xx.gpio[0]", 0xf0010000, 4 * KiB);
552
create_unimplemented_device("npcm7xx.gpio[1]", 0xf0011000, 4 * KiB);
553
diff --git a/tests/qtest/npcm7xx_adc-test.c b/tests/qtest/npcm7xx_adc-test.c
554
new file mode 100644
555
index XXXXXXX..XXXXXXX
556
--- /dev/null
557
+++ b/tests/qtest/npcm7xx_adc-test.c
558
@@ -XXX,XX +XXX,XX @@
559
+/*
560
+ * QTests for Nuvoton NPCM7xx ADCModules.
561
+ *
562
+ * Copyright 2020 Google LLC
563
+ *
564
+ * This program is free software; you can redistribute it and/or modify it
565
+ * under the terms of the GNU General Public License as published by the
566
+ * Free Software Foundation; either version 2 of the License, or
567
+ * (at your option) any later version.
568
+ *
569
+ * This program is distributed in the hope that it will be useful, but WITHOUT
570
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
571
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
572
+ * for more details.
573
+ */
574
+
575
+#include "qemu/osdep.h"
576
+#include "qemu/bitops.h"
577
+#include "qemu/timer.h"
578
+#include "libqos/libqtest.h"
579
+#include "qapi/qmp/qdict.h"
580
+
581
+#define REF_HZ (25000000)
582
+
583
+#define CON_OFFSET 0x0
584
+#define DATA_OFFSET 0x4
585
+
586
+#define NUM_INPUTS 8
587
+#define DEFAULT_IREF 2000000
588
+#define CONV_CYCLES 20
589
+#define RESET_CYCLES 10
590
+#define R0_INPUT 500000
591
+#define R1_INPUT 1500000
592
+#define MAX_RESULT 1023
593
+
594
+#define DEFAULT_CLKDIV 5
595
+
596
+#define FUSE_ARRAY_BA 0xf018a000
597
+#define FCTL_OFFSET 0x14
598
+#define FST_OFFSET 0x0
599
+#define FADDR_OFFSET 0x4
600
+#define FDATA_OFFSET 0x8
601
+#define ADC_CALIB_ADDR 24
602
+#define FUSE_READ 0x2
603
+
604
+/* Register field definitions. */
605
+#define CON_MUX(rv) ((rv) << 24)
606
+#define CON_INT_EN BIT(21)
607
+#define CON_REFSEL BIT(19)
608
+#define CON_INT BIT(18)
609
+#define CON_EN BIT(17)
610
+#define CON_RST BIT(16)
611
+#define CON_CONV BIT(14)
612
+#define CON_DIV(rv) extract32(rv, 1, 8)
613
+
614
+#define FST_RDST BIT(1)
615
+#define FDATA_MASK 0xff
616
+
617
+#define MAX_ERROR 10000
618
+#define MIN_CALIB_INPUT 100000
619
+#define MAX_CALIB_INPUT 1800000
620
+
621
+static const uint32_t input_list[] = {
622
+ 100000,
623
+ 500000,
624
+ 1000000,
625
+ 1500000,
626
+ 1800000,
627
+ 2000000,
628
+};
629
+
630
+static const uint32_t vref_list[] = {
631
+ 2000000,
632
+ 2200000,
633
+ 2500000,
634
+};
635
+
636
+static const uint32_t iref_list[] = {
637
+ 1800000,
638
+ 1900000,
639
+ 2000000,
640
+ 2100000,
641
+ 2200000,
642
+};
643
+
644
+static const uint32_t div_list[] = {0, 1, 3, 7, 15};
645
+
646
+typedef struct ADC {
647
+ int irq;
648
+ uint64_t base_addr;
649
+} ADC;
650
+
651
+ADC adc = {
652
+ .irq = 0,
653
+ .base_addr = 0xf000c000
654
+};
655
+
656
+static uint32_t adc_read_con(QTestState *qts, const ADC *adc)
657
+{
658
+ return qtest_readl(qts, adc->base_addr + CON_OFFSET);
659
+}
660
+
661
+static void adc_write_con(QTestState *qts, const ADC *adc, uint32_t value)
662
+{
663
+ qtest_writel(qts, adc->base_addr + CON_OFFSET, value);
664
+}
665
+
666
+static uint32_t adc_read_data(QTestState *qts, const ADC *adc)
667
+{
668
+ return qtest_readl(qts, adc->base_addr + DATA_OFFSET);
669
+}
670
+
671
+static uint32_t adc_calibrate(uint32_t measured, uint32_t *rv)
672
+{
673
+ return R0_INPUT + (R1_INPUT - R0_INPUT) * (int32_t)(measured - rv[0])
674
+ / (int32_t)(rv[1] - rv[0]);
675
+}
676
+
677
+static void adc_qom_set(QTestState *qts, const ADC *adc,
678
+ const char *name, uint32_t value)
679
+{
680
+ QDict *response;
681
+ const char *path = "/machine/soc/adc";
682
+
683
+ g_test_message("Setting properties %s of %s with value %u",
684
+ name, path, value);
685
+ response = qtest_qmp(qts, "{ 'execute': 'qom-set',"
686
+ " 'arguments': { 'path': %s, 'property': %s, 'value': %u}}",
687
+ path, name, value);
688
+ /* The qom set message returns successfully. */
689
+ g_assert_true(qdict_haskey(response, "return"));
690
+}
691
+
692
+static void adc_write_input(QTestState *qts, const ADC *adc,
693
+ uint32_t index, uint32_t value)
694
+{
695
+ char name[100];
696
+
697
+ sprintf(name, "adci[%u]", index);
698
+ adc_qom_set(qts, adc, name, value);
699
+}
700
+
701
+static void adc_write_vref(QTestState *qts, const ADC *adc, uint32_t value)
702
+{
703
+ adc_qom_set(qts, adc, "vref", value);
704
+}
705
+
706
+static uint32_t adc_calculate_output(uint32_t input, uint32_t ref)
707
+{
708
+ uint32_t output;
709
+
710
+ g_assert_cmpuint(input, <=, ref);
711
+ output = (input * (MAX_RESULT + 1)) / ref;
712
+ if (output > MAX_RESULT) {
713
+ output = MAX_RESULT;
714
+ }
715
+
716
+ return output;
717
+}
718
+
719
+static uint32_t adc_prescaler(QTestState *qts, const ADC *adc)
720
+{
721
+ uint32_t div = extract32(adc_read_con(qts, adc), 1, 8);
722
+
723
+ return 2 * (div + 1);
724
+}
725
+
726
+static int64_t adc_calculate_steps(uint32_t cycles, uint32_t prescale,
727
+ uint32_t clkdiv)
728
+{
729
+ return (NANOSECONDS_PER_SECOND / (REF_HZ >> clkdiv)) * cycles * prescale;
730
+}
731
+
732
+static void adc_wait_conv_finished(QTestState *qts, const ADC *adc,
733
+ uint32_t clkdiv)
734
+{
735
+ uint32_t prescaler = adc_prescaler(qts, adc);
736
+
737
+ /*
738
+ * ADC should takes roughly 20 cycles to convert one sample. So we assert it
739
+ * should take 10~30 cycles here.
740
+ */
741
+ qtest_clock_step(qts, adc_calculate_steps(CONV_CYCLES / 2, prescaler,
742
+ clkdiv));
743
+ /* ADC is still converting. */
744
+ g_assert_true(adc_read_con(qts, adc) & CON_CONV);
745
+ qtest_clock_step(qts, adc_calculate_steps(CONV_CYCLES, prescaler, clkdiv));
746
+ /* ADC has finished conversion. */
747
+ g_assert_false(adc_read_con(qts, adc) & CON_CONV);
748
+}
749
+
750
+/* Check ADC can be reset to default value. */
751
+static void test_init(gconstpointer adc_p)
752
+{
753
+ const ADC *adc = adc_p;
754
+
755
+ QTestState *qts = qtest_init("-machine quanta-gsj");
756
+ adc_write_con(qts, adc, CON_REFSEL | CON_INT);
757
+ g_assert_cmphex(adc_read_con(qts, adc), ==, CON_REFSEL);
758
+ qtest_quit(qts);
759
+}
760
+
761
+/* Check ADC can convert from an internal reference. */
762
+static void test_convert_internal(gconstpointer adc_p)
763
+{
764
+ const ADC *adc = adc_p;
765
+ uint32_t index, input, output, expected_output;
766
+ QTestState *qts = qtest_init("-machine quanta-gsj");
767
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
768
+
769
+ for (index = 0; index < NUM_INPUTS; ++index) {
770
+ for (size_t i = 0; i < ARRAY_SIZE(input_list); ++i) {
771
+ input = input_list[i];
772
+ expected_output = adc_calculate_output(input, DEFAULT_IREF);
773
+
774
+ adc_write_input(qts, adc, index, input);
775
+ adc_write_con(qts, adc, CON_MUX(index) | CON_REFSEL | CON_INT |
776
+ CON_EN | CON_CONV);
777
+ adc_wait_conv_finished(qts, adc, DEFAULT_CLKDIV);
778
+ g_assert_cmphex(adc_read_con(qts, adc), ==, CON_MUX(index) |
779
+ CON_REFSEL | CON_EN);
780
+ g_assert_false(qtest_get_irq(qts, adc->irq));
781
+ output = adc_read_data(qts, adc);
782
+ g_assert_cmpuint(output, ==, expected_output);
783
+ }
784
+ }
785
+
786
+ qtest_quit(qts);
787
+}
788
+
789
+/* Check ADC can convert from an external reference. */
790
+static void test_convert_external(gconstpointer adc_p)
791
+{
792
+ const ADC *adc = adc_p;
793
+ uint32_t index, input, vref, output, expected_output;
794
+ QTestState *qts = qtest_init("-machine quanta-gsj");
795
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
796
+
797
+ for (index = 0; index < NUM_INPUTS; ++index) {
798
+ for (size_t i = 0; i < ARRAY_SIZE(input_list); ++i) {
799
+ for (size_t j = 0; j < ARRAY_SIZE(vref_list); ++j) {
800
+ input = input_list[i];
801
+ vref = vref_list[j];
802
+ expected_output = adc_calculate_output(input, vref);
803
+
804
+ adc_write_input(qts, adc, index, input);
805
+ adc_write_vref(qts, adc, vref);
806
+ adc_write_con(qts, adc, CON_MUX(index) | CON_INT | CON_EN |
807
+ CON_CONV);
808
+ adc_wait_conv_finished(qts, adc, DEFAULT_CLKDIV);
809
+ g_assert_cmphex(adc_read_con(qts, adc), ==,
810
+ CON_MUX(index) | CON_EN);
811
+ g_assert_false(qtest_get_irq(qts, adc->irq));
812
+ output = adc_read_data(qts, adc);
813
+ g_assert_cmpuint(output, ==, expected_output);
814
+ }
815
+ }
816
+ }
817
+
818
+ qtest_quit(qts);
819
+}
820
+
821
+/* Check ADC interrupt files if and only if CON_INT_EN is set. */
822
+static void test_interrupt(gconstpointer adc_p)
823
+{
824
+ const ADC *adc = adc_p;
825
+ uint32_t index, input, output, expected_output;
826
+ QTestState *qts = qtest_init("-machine quanta-gsj");
827
+
828
+ index = 1;
829
+ input = input_list[1];
830
+ expected_output = adc_calculate_output(input, DEFAULT_IREF);
831
+
832
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
833
+ adc_write_input(qts, adc, index, input);
834
+ g_assert_false(qtest_get_irq(qts, adc->irq));
835
+ adc_write_con(qts, adc, CON_MUX(index) | CON_INT_EN | CON_REFSEL | CON_INT
836
+ | CON_EN | CON_CONV);
837
+ adc_wait_conv_finished(qts, adc, DEFAULT_CLKDIV);
838
+ g_assert_cmphex(adc_read_con(qts, adc), ==, CON_MUX(index) | CON_INT_EN
839
+ | CON_REFSEL | CON_INT | CON_EN);
840
+ g_assert_true(qtest_get_irq(qts, adc->irq));
841
+ output = adc_read_data(qts, adc);
842
+ g_assert_cmpuint(output, ==, expected_output);
843
+
844
+ qtest_quit(qts);
845
+}
846
+
847
+/* Check ADC is reset after setting ADC_RST for 10 ADC cycles. */
848
+static void test_reset(gconstpointer adc_p)
849
+{
850
+ const ADC *adc = adc_p;
851
+ QTestState *qts = qtest_init("-machine quanta-gsj");
852
+
853
+ for (size_t i = 0; i < ARRAY_SIZE(div_list); ++i) {
854
+ uint32_t div = div_list[i];
855
+
856
+ adc_write_con(qts, adc, CON_INT | CON_EN | CON_RST | CON_DIV(div));
857
+ qtest_clock_step(qts, adc_calculate_steps(RESET_CYCLES,
858
+ adc_prescaler(qts, adc), DEFAULT_CLKDIV));
859
+ g_assert_false(adc_read_con(qts, adc) & CON_EN);
860
+ }
861
+ qtest_quit(qts);
862
+}
863
+
864
+/* Check ADC Calibration works as desired. */
865
+static void test_calibrate(gconstpointer adc_p)
866
+{
867
+ int i, j;
868
+ const ADC *adc = adc_p;
869
+
870
+ for (j = 0; j < ARRAY_SIZE(iref_list); ++j) {
871
+ uint32_t iref = iref_list[j];
872
+ uint32_t expected_rv[] = {
873
+ adc_calculate_output(R0_INPUT, iref),
874
+ adc_calculate_output(R1_INPUT, iref),
875
+ };
876
+ char buf[100];
877
+ QTestState *qts;
878
+
879
+ sprintf(buf, "-machine quanta-gsj -global npcm7xx-adc.iref=%u", iref);
880
+ qts = qtest_init(buf);
881
+
882
+ /* Check the converted value is correct using the calibration value. */
883
+ for (i = 0; i < ARRAY_SIZE(input_list); ++i) {
884
+ uint32_t input;
885
+ uint32_t output;
886
+ uint32_t expected_output;
887
+ uint32_t calibrated_voltage;
888
+ uint32_t index = 0;
889
+
890
+ input = input_list[i];
891
+ /* Calibration only works for input range 0.1V ~ 1.8V. */
892
+ if (input < MIN_CALIB_INPUT || input > MAX_CALIB_INPUT) {
893
+ continue;
894
+ }
895
+ expected_output = adc_calculate_output(input, iref);
896
+
897
+ adc_write_input(qts, adc, index, input);
898
+ adc_write_con(qts, adc, CON_MUX(index) | CON_REFSEL | CON_INT |
899
+ CON_EN | CON_CONV);
900
+ adc_wait_conv_finished(qts, adc, DEFAULT_CLKDIV);
901
+ g_assert_cmphex(adc_read_con(qts, adc), ==,
902
+ CON_REFSEL | CON_MUX(index) | CON_EN);
903
+ output = adc_read_data(qts, adc);
904
+ g_assert_cmpuint(output, ==, expected_output);
905
+
906
+ calibrated_voltage = adc_calibrate(output, expected_rv);
907
+ g_assert_cmpuint(calibrated_voltage, >, input - MAX_ERROR);
908
+ g_assert_cmpuint(calibrated_voltage, <, input + MAX_ERROR);
909
+ }
910
+
911
+ qtest_quit(qts);
912
+ }
913
+}
914
+
915
+static void adc_add_test(const char *name, const ADC* wd,
916
+ GTestDataFunc fn)
917
+{
918
+ g_autofree char *full_name = g_strdup_printf("npcm7xx_adc/%s", name);
919
+ qtest_add_data_func(full_name, wd, fn);
920
+}
921
+#define add_test(name, td) adc_add_test(#name, td, test_##name)
922
+
923
+int main(int argc, char **argv)
924
+{
925
+ g_test_init(&argc, &argv, NULL);
926
+
927
+ add_test(init, &adc);
928
+ add_test(convert_internal, &adc);
929
+ add_test(convert_external, &adc);
930
+ add_test(interrupt, &adc);
931
+ add_test(reset, &adc);
932
+ add_test(calibrate, &adc);
933
+
934
+ return g_test_run();
935
+}
936
diff --git a/hw/adc/meson.build b/hw/adc/meson.build
104
index XXXXXXX..XXXXXXX 100644
937
index XXXXXXX..XXXXXXX 100644
105
--- a/target/arm/hvf/hvf.c
938
--- a/hw/adc/meson.build
106
+++ b/target/arm/hvf/hvf.c
939
+++ b/hw/adc/meson.build
107
@@ -XXX,XX +XXX,XX @@ static bool hvf_handle_psci_call(CPUState *cpu)
940
@@ -1 +1,2 @@
108
941
softmmu_ss.add(when: 'CONFIG_STM32F2XX_ADC', if_true: files('stm32f2xx_adc.c'))
109
switch (param[0]) {
942
+softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_adc.c'))
110
case QEMU_PSCI_0_2_FN_PSCI_VERSION:
943
diff --git a/hw/adc/trace-events b/hw/adc/trace-events
111
- ret = QEMU_PSCI_0_2_RET_VERSION_0_2;
944
new file mode 100644
112
+ ret = QEMU_PSCI_VERSION_1_1;
945
index XXXXXXX..XXXXXXX
113
break;
946
--- /dev/null
114
case QEMU_PSCI_0_2_FN_MIGRATE_INFO_TYPE:
947
+++ b/hw/adc/trace-events
115
ret = QEMU_PSCI_0_2_RET_TOS_MIGRATION_NOT_REQUIRED; /* No trusted OS */
948
@@ -XXX,XX +XXX,XX @@
116
@@ -XXX,XX +XXX,XX @@ static bool hvf_handle_psci_call(CPUState *cpu)
949
+# See docs/devel/tracing.txt for syntax documentation.
117
case QEMU_PSCI_0_2_FN_MIGRATE:
950
+
118
ret = QEMU_PSCI_RET_NOT_SUPPORTED;
951
+# npcm7xx_adc.c
119
break;
952
+npcm7xx_adc_read(const char *id, uint64_t offset, uint32_t value) " %s offset: 0x%04" PRIx64 " value 0x%04" PRIx32
120
+ case QEMU_PSCI_1_0_FN_PSCI_FEATURES:
953
+npcm7xx_adc_write(const char *id, uint64_t offset, uint32_t value) "%s offset: 0x%04" PRIx64 " value 0x%04" PRIx32
121
+ switch (param[1]) {
954
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
122
+ case QEMU_PSCI_0_2_FN_PSCI_VERSION:
123
+ case QEMU_PSCI_0_2_FN_MIGRATE_INFO_TYPE:
124
+ case QEMU_PSCI_0_2_FN_AFFINITY_INFO:
125
+ case QEMU_PSCI_0_2_FN64_AFFINITY_INFO:
126
+ case QEMU_PSCI_0_2_FN_SYSTEM_RESET:
127
+ case QEMU_PSCI_0_2_FN_SYSTEM_OFF:
128
+ case QEMU_PSCI_0_1_FN_CPU_ON:
129
+ case QEMU_PSCI_0_2_FN_CPU_ON:
130
+ case QEMU_PSCI_0_2_FN64_CPU_ON:
131
+ case QEMU_PSCI_0_1_FN_CPU_OFF:
132
+ case QEMU_PSCI_0_2_FN_CPU_OFF:
133
+ case QEMU_PSCI_0_1_FN_CPU_SUSPEND:
134
+ case QEMU_PSCI_0_2_FN_CPU_SUSPEND:
135
+ case QEMU_PSCI_0_2_FN64_CPU_SUSPEND:
136
+ case QEMU_PSCI_1_0_FN_PSCI_FEATURES:
137
+ ret = 0;
138
+ break;
139
+ case QEMU_PSCI_0_1_FN_MIGRATE:
140
+ case QEMU_PSCI_0_2_FN_MIGRATE:
141
+ default:
142
+ ret = QEMU_PSCI_RET_NOT_SUPPORTED;
143
+ }
144
+ break;
145
default:
146
return false;
147
}
148
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
149
index XXXXXXX..XXXXXXX 100644
955
index XXXXXXX..XXXXXXX 100644
150
--- a/target/arm/kvm64.c
956
--- a/tests/qtest/meson.build
151
+++ b/target/arm/kvm64.c
957
+++ b/tests/qtest/meson.build
152
@@ -XXX,XX +XXX,XX @@ int kvm_arch_init_vcpu(CPUState *cs)
958
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
153
cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_POWER_OFF;
959
['prom-env-test', 'boot-serial-test']
154
}
960
155
if (kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PSCI_0_2)) {
961
qtests_npcm7xx = \
156
- cpu->psci_version = 2;
962
- ['npcm7xx_gpio-test',
157
+ cpu->psci_version = QEMU_PSCI_VERSION_0_2;
963
+ ['npcm7xx_adc-test',
158
cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PSCI_0_2;
964
+ 'npcm7xx_gpio-test',
159
}
965
'npcm7xx_rng-test',
160
if (!arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
966
'npcm7xx_timer-test',
161
diff --git a/target/arm/psci.c b/target/arm/psci.c
967
'npcm7xx_watchdog_timer-test']
162
index XXXXXXX..XXXXXXX 100644
163
--- a/target/arm/psci.c
164
+++ b/target/arm/psci.c
165
@@ -XXX,XX +XXX,XX @@ void arm_handle_psci_call(ARMCPU *cpu)
166
{
167
/*
168
* This function partially implements the logic for dispatching Power State
169
- * Coordination Interface (PSCI) calls (as described in ARM DEN 0022B.b),
170
+ * Coordination Interface (PSCI) calls (as described in ARM DEN 0022D.b),
171
* to the extent required for bringing up and taking down secondary cores,
172
* and for handling reset and poweroff requests.
173
* Additional information about the calling convention used is available in
174
@@ -XXX,XX +XXX,XX @@ void arm_handle_psci_call(ARMCPU *cpu)
175
}
176
177
if ((param[0] & QEMU_PSCI_0_2_64BIT) && !is_a64(env)) {
178
- ret = QEMU_PSCI_RET_INVALID_PARAMS;
179
+ ret = QEMU_PSCI_RET_NOT_SUPPORTED;
180
goto err;
181
}
182
183
@@ -XXX,XX +XXX,XX @@ void arm_handle_psci_call(ARMCPU *cpu)
184
ARMCPU *target_cpu;
185
186
case QEMU_PSCI_0_2_FN_PSCI_VERSION:
187
- ret = QEMU_PSCI_0_2_RET_VERSION_0_2;
188
+ ret = QEMU_PSCI_VERSION_1_1;
189
break;
190
case QEMU_PSCI_0_2_FN_MIGRATE_INFO_TYPE:
191
ret = QEMU_PSCI_0_2_RET_TOS_MIGRATION_NOT_REQUIRED; /* No trusted OS */
192
@@ -XXX,XX +XXX,XX @@ void arm_handle_psci_call(ARMCPU *cpu)
193
}
194
helper_wfi(env, 4);
195
break;
196
+ case QEMU_PSCI_1_0_FN_PSCI_FEATURES:
197
+ switch (param[1]) {
198
+ case QEMU_PSCI_0_2_FN_PSCI_VERSION:
199
+ case QEMU_PSCI_0_2_FN_MIGRATE_INFO_TYPE:
200
+ case QEMU_PSCI_0_2_FN_AFFINITY_INFO:
201
+ case QEMU_PSCI_0_2_FN64_AFFINITY_INFO:
202
+ case QEMU_PSCI_0_2_FN_SYSTEM_RESET:
203
+ case QEMU_PSCI_0_2_FN_SYSTEM_OFF:
204
+ case QEMU_PSCI_0_1_FN_CPU_ON:
205
+ case QEMU_PSCI_0_2_FN_CPU_ON:
206
+ case QEMU_PSCI_0_2_FN64_CPU_ON:
207
+ case QEMU_PSCI_0_1_FN_CPU_OFF:
208
+ case QEMU_PSCI_0_2_FN_CPU_OFF:
209
+ case QEMU_PSCI_0_1_FN_CPU_SUSPEND:
210
+ case QEMU_PSCI_0_2_FN_CPU_SUSPEND:
211
+ case QEMU_PSCI_0_2_FN64_CPU_SUSPEND:
212
+ case QEMU_PSCI_1_0_FN_PSCI_FEATURES:
213
+ if (!(param[1] & QEMU_PSCI_0_2_64BIT) || is_a64(env)) {
214
+ ret = 0;
215
+ break;
216
+ }
217
+ /* fallthrough */
218
+ case QEMU_PSCI_0_1_FN_MIGRATE:
219
+ case QEMU_PSCI_0_2_FN_MIGRATE:
220
+ default:
221
+ ret = QEMU_PSCI_RET_NOT_SUPPORTED;
222
+ break;
223
+ }
224
+ break;
225
case QEMU_PSCI_0_1_FN_MIGRATE:
226
case QEMU_PSCI_0_2_FN_MIGRATE:
227
default:
228
--
968
--
229
2.25.1
969
2.20.1
970
971
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
Without FEAT_LVA, the behaviour of programming an invalid value
3
The PWM module is part of NPCM7XX module. Each NPCM7XX module has two
4
is IMPLEMENTATION DEFINED. With FEAT_LVA, programming an invalid
4
identical PWM modules. Each module contains 4 PWM entries. Each PWM has
5
minimum value requires a Translation fault.
5
two outputs: frequency and duty_cycle. Both are computed using inputs
6
from software side.
6
7
7
It is most self-consistent to choose to generate the fault always.
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.
8
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
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
20
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
11
Message-id: 20220301215958.157011-4-richard.henderson@linaro.org
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
22
---
14
target/arm/internals.h | 1 +
23
docs/system/arm/nuvoton.rst | 2 +-
15
target/arm/helper.c | 32 ++++++++++++++++++++++++++++----
24
include/hw/arm/npcm7xx.h | 2 +
16
2 files changed, 29 insertions(+), 4 deletions(-)
25
include/hw/misc/npcm7xx_pwm.h | 105 +++++++
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
17
33
18
diff --git a/target/arm/internals.h b/target/arm/internals.h
34
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
19
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
20
--- a/target/arm/internals.h
36
--- a/docs/system/arm/nuvoton.rst
21
+++ b/target/arm/internals.h
37
+++ b/docs/system/arm/nuvoton.rst
22
@@ -XXX,XX +XXX,XX @@ typedef struct ARMVAParameters {
38
@@ -XXX,XX +XXX,XX @@ Supported devices
23
bool hpd : 1;
39
* USB host (USBH)
24
bool using16k : 1;
40
* GPIO controller
25
bool using64k : 1;
41
* Analog to Digital Converter (ADC)
26
+ bool tsz_oob : 1; /* tsz has been clamped to legal range */
42
+ * Pulse Width Modulation (PWM)
27
} ARMVAParameters;
43
28
44
Missing devices
29
ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
45
---------------
30
diff --git a/target/arm/helper.c b/target/arm/helper.c
46
@@ -XXX,XX +XXX,XX @@ Missing devices
47
* Peripheral SPI controller (PSPI)
48
* SD/MMC host
49
* PECI interface
50
- * Pulse Width Modulation (PWM)
51
* Tachometer
52
* PCI and PCIe root complex and bridges
53
* VDM and MCTP support
54
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
31
index XXXXXXX..XXXXXXX 100644
55
index XXXXXXX..XXXXXXX 100644
32
--- a/target/arm/helper.c
56
--- a/include/hw/arm/npcm7xx.h
33
+++ b/target/arm/helper.c
57
+++ b/include/hw/arm/npcm7xx.h
34
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
58
@@ -XXX,XX +XXX,XX @@
35
ARMMMUIdx mmu_idx, bool data)
59
#include "hw/mem/npcm7xx_mc.h"
36
{
60
#include "hw/misc/npcm7xx_clk.h"
37
uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr;
61
#include "hw/misc/npcm7xx_gcr.h"
38
- bool epd, hpd, using16k, using64k;
62
+#include "hw/misc/npcm7xx_pwm.h"
39
- int select, tsz, tbi, max_tsz;
63
#include "hw/misc/npcm7xx_rng.h"
40
+ bool epd, hpd, using16k, using64k, tsz_oob;
64
#include "hw/nvram/npcm7xx_otp.h"
41
+ int select, tsz, tbi, max_tsz, min_tsz;
65
#include "hw/timer/npcm7xx_timer.h"
42
66
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
43
if (!regime_has_2_ranges(mmu_idx)) {
67
NPCM7xxCLKState clk;
44
select = 0;
68
NPCM7xxTimerCtrlState tim[3];
45
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
69
NPCM7xxADCState adc;
46
} else {
70
+ NPCM7xxPWMState pwm[2];
47
max_tsz = 39;
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
186
index XXXXXXX..XXXXXXX 100644
187
--- a/hw/arm/npcm7xx.c
188
+++ b/hw/arm/npcm7xx.c
189
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxInterrupt {
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 */
200
};
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);
48
}
214
}
49
+ min_tsz = 16; /* TODO: ARMv8.2-LVA */
215
+
50
216
+ for (i = 0; i < ARRAY_SIZE(s->pwm); i++) {
51
- tsz = MIN(tsz, max_tsz);
217
+ object_initialize_child(obj, "pwm[*]", &s->pwm[i], TYPE_NPCM7XX_PWM);
52
- tsz = MAX(tsz, 16); /* TODO: ARMv8.2-LVA */
218
+ }
53
+ if (tsz > max_tsz) {
219
}
54
+ tsz = max_tsz;
220
55
+ tsz_oob = true;
221
static void npcm7xx_realize(DeviceState *dev, Error **errp)
56
+ } else if (tsz < min_tsz) {
222
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
57
+ tsz = min_tsz;
223
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ohci), 0,
58
+ tsz_oob = true;
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 @@
256
+/*
257
+ * Nuvoton NPCM7xx PWM Module
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.
270
+ */
271
+
272
+#include "qemu/osdep.h"
273
+#include "hw/irq.h"
274
+#include "hw/qdev-clock.h"
275
+#include "hw/qdev-properties.h"
276
+#include "hw/misc/npcm7xx_pwm.h"
277
+#include "hw/registerfields.h"
278
+#include "migration/vmstate.h"
279
+#include "qemu/bitops.h"
280
+#include "qemu/error-report.h"
281
+#include "qemu/log.h"
282
+#include "qemu/module.h"
283
+#include "qemu/units.h"
284
+#include "trace.h"
285
+
286
+REG32(NPCM7XX_PWM_PPR, 0x00);
287
+REG32(NPCM7XX_PWM_CSR, 0x04);
288
+REG32(NPCM7XX_PWM_PCR, 0x08);
289
+REG32(NPCM7XX_PWM_CNR0, 0x0c);
290
+REG32(NPCM7XX_PWM_CMR0, 0x10);
291
+REG32(NPCM7XX_PWM_PDR0, 0x14);
292
+REG32(NPCM7XX_PWM_CNR1, 0x18);
293
+REG32(NPCM7XX_PWM_CMR1, 0x1c);
294
+REG32(NPCM7XX_PWM_PDR1, 0x20);
295
+REG32(NPCM7XX_PWM_CNR2, 0x24);
296
+REG32(NPCM7XX_PWM_CMR2, 0x28);
297
+REG32(NPCM7XX_PWM_PDR2, 0x2c);
298
+REG32(NPCM7XX_PWM_CNR3, 0x30);
299
+REG32(NPCM7XX_PWM_CMR3, 0x34);
300
+REG32(NPCM7XX_PWM_PDR3, 0x38);
301
+REG32(NPCM7XX_PWM_PIER, 0x3c);
302
+REG32(NPCM7XX_PWM_PIIR, 0x40);
303
+REG32(NPCM7XX_PWM_PWDR0, 0x44);
304
+REG32(NPCM7XX_PWM_PWDR1, 0x48);
305
+REG32(NPCM7XX_PWM_PWDR2, 0x4c);
306
+REG32(NPCM7XX_PWM_PWDR3, 0x50);
307
+
308
+/* Register field definitions. */
309
+#define NPCM7XX_PPR(rv, index) extract32((rv), npcm7xx_ppr_base[index], 8)
310
+#define NPCM7XX_CSR(rv, index) extract32((rv), npcm7xx_csr_base[index], 3)
311
+#define NPCM7XX_CH(rv, index) extract32((rv), npcm7xx_ch_base[index], 4)
312
+#define NPCM7XX_CH_EN BIT(0)
313
+#define NPCM7XX_CH_INV BIT(2)
314
+#define NPCM7XX_CH_MOD BIT(3)
315
+
316
+/* Offset of each PWM channel's prescaler in the PPR register. */
317
+static const int npcm7xx_ppr_base[] = { 0, 0, 8, 8 };
318
+/* Offset of each PWM channel's clock selector in the CSR register. */
319
+static const int npcm7xx_csr_base[] = { 0, 4, 8, 12 };
320
+/* Offset of each PWM channel's control variable in the PCR register. */
321
+static const int npcm7xx_ch_base[] = { 0, 8, 12, 16 };
322
+
323
+static uint32_t npcm7xx_pwm_calculate_freq(NPCM7xxPWM *p)
324
+{
325
+ uint32_t ppr;
326
+ uint32_t csr;
327
+ uint32_t freq;
328
+
329
+ if (!p->running) {
330
+ return 0;
331
+ }
332
+
333
+ csr = NPCM7XX_CSR(p->module->csr, p->index);
334
+ ppr = NPCM7XX_PPR(p->module->ppr, p->index);
335
+ freq = clock_get_hz(p->module->clock);
336
+ freq /= ppr + 1;
337
+ /* csr can only be 0~4 */
338
+ if (csr > 4) {
339
+ qemu_log_mask(LOG_GUEST_ERROR,
340
+ "%s: invalid csr value %u\n",
341
+ __func__, csr);
342
+ csr = 4;
343
+ }
344
+ /* freq won't be changed if csr == 4. */
345
+ if (csr < 4) {
346
+ freq >>= csr + 1;
347
+ }
348
+
349
+ return freq / (p->cnr + 1);
350
+}
351
+
352
+static uint32_t npcm7xx_pwm_calculate_duty(NPCM7xxPWM *p)
353
+{
354
+ uint64_t duty;
355
+
356
+ if (p->running) {
357
+ if (p->cnr == 0) {
358
+ duty = 0;
359
+ } else if (p->cmr >= p->cnr) {
360
+ duty = NPCM7XX_PWM_MAX_DUTY;
361
+ } else {
362
+ duty = NPCM7XX_PWM_MAX_DUTY * (p->cmr + 1) / (p->cnr + 1);
363
+ }
59
+ } else {
364
+ } else {
60
+ tsz_oob = false;
365
+ duty = 0;
61
+ }
366
+ }
62
367
+
63
/* Present TBI as a composite with TBID. */
368
+ if (p->inverted) {
64
tbi = aa64_va_parameter_tbi(tcr, mmu_idx);
369
+ duty = NPCM7XX_PWM_MAX_DUTY - duty;
65
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
370
+ }
66
.hpd = hpd,
371
+
67
.using16k = using16k,
372
+ return duty;
68
.using64k = using64k,
373
+}
69
+ .tsz_oob = tsz_oob,
374
+
70
};
375
+static void npcm7xx_pwm_update_freq(NPCM7xxPWM *p)
71
}
376
+{
72
377
+ uint32_t freq = npcm7xx_pwm_calculate_freq(p);
73
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
378
+
74
param = aa64_va_parameters(env, address, mmu_idx,
379
+ if (freq != p->freq) {
75
access_type != MMU_INST_FETCH);
380
+ trace_npcm7xx_pwm_update_freq(DEVICE(p->module)->canonical_path,
76
level = 0;
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;
77
+
444
+
78
+ /*
445
+ /*
79
+ * If TxSZ is programmed to a value larger than the maximum,
446
+ * We only run a PWM channel with toggle mode. Single-shot mode does not
80
+ * or smaller than the effective minimum, it is IMPLEMENTATION
447
+ * generate frequency and duty-cycle values.
81
+ * DEFINED whether we behave as if the field were programmed
82
+ * within bounds, or if a level 0 Translation fault is generated.
83
+ *
84
+ * With FEAT_LVA, fault on less than minimum becomes required,
85
+ * so our choice is to always raise the fault.
86
+ */
448
+ */
87
+ if (param.tsz_oob) {
449
+ if ((pcr & NPCM7XX_CH_EN) && (pcr & NPCM7XX_CH_MOD)) {
88
+ fault_type = ARMFault_Translation;
450
+ if (p->running) {
89
+ goto do_fault;
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);
90
+ }
467
+ }
91
+
468
+ }
92
addrsize = 64 - 8 * param.tbi;
469
+
93
inputsize = 64 - param.tsz;
470
+}
94
} else {
471
+
472
+static hwaddr npcm7xx_cnr_index(hwaddr offset)
473
+{
474
+ switch (offset) {
475
+ case A_NPCM7XX_PWM_CNR0:
476
+ return 0;
477
+ case A_NPCM7XX_PWM_CNR1:
478
+ return 1;
479
+ case A_NPCM7XX_PWM_CNR2:
480
+ return 2;
481
+ case A_NPCM7XX_PWM_CNR3:
482
+ return 3;
483
+ default:
484
+ g_assert_not_reached();
485
+ }
486
+}
487
+
488
+static hwaddr npcm7xx_cmr_index(hwaddr offset)
489
+{
490
+ switch (offset) {
491
+ case A_NPCM7XX_PWM_CMR0:
492
+ return 0;
493
+ case A_NPCM7XX_PWM_CMR1:
494
+ return 1;
495
+ case A_NPCM7XX_PWM_CMR2:
496
+ return 2;
497
+ case A_NPCM7XX_PWM_CMR3:
498
+ return 3;
499
+ default:
500
+ g_assert_not_reached();
501
+ }
502
+}
503
+
504
+static hwaddr npcm7xx_pdr_index(hwaddr offset)
505
+{
506
+ switch (offset) {
507
+ case A_NPCM7XX_PWM_PDR0:
508
+ return 0;
509
+ case A_NPCM7XX_PWM_PDR1:
510
+ return 1;
511
+ case A_NPCM7XX_PWM_PDR2:
512
+ return 2;
513
+ case A_NPCM7XX_PWM_PDR3:
514
+ return 3;
515
+ default:
516
+ g_assert_not_reached();
517
+ }
518
+}
519
+
520
+static hwaddr npcm7xx_pwdr_index(hwaddr offset)
521
+{
522
+ switch (offset) {
523
+ case A_NPCM7XX_PWM_PWDR0:
524
+ return 0;
525
+ case A_NPCM7XX_PWM_PWDR1:
526
+ return 1;
527
+ case A_NPCM7XX_PWM_PWDR2:
528
+ return 2;
529
+ case A_NPCM7XX_PWM_PWDR3:
530
+ return 3;
531
+ default:
532
+ g_assert_not_reached();
533
+ }
534
+}
535
+
536
+static uint64_t npcm7xx_pwm_read(void *opaque, hwaddr offset, unsigned size)
537
+{
538
+ NPCM7xxPWMState *s = opaque;
539
+ uint64_t value = 0;
540
+
541
+ switch (offset) {
542
+ case A_NPCM7XX_PWM_CNR0:
543
+ case A_NPCM7XX_PWM_CNR1:
544
+ case A_NPCM7XX_PWM_CNR2:
545
+ case A_NPCM7XX_PWM_CNR3:
546
+ value = s->pwm[npcm7xx_cnr_index(offset)].cnr;
547
+ break;
548
+
549
+ case A_NPCM7XX_PWM_CMR0:
550
+ case A_NPCM7XX_PWM_CMR1:
551
+ case A_NPCM7XX_PWM_CMR2:
552
+ case A_NPCM7XX_PWM_CMR3:
553
+ value = s->pwm[npcm7xx_cmr_index(offset)].cmr;
554
+ break;
555
+
556
+ case A_NPCM7XX_PWM_PDR0:
557
+ case A_NPCM7XX_PWM_PDR1:
558
+ case A_NPCM7XX_PWM_PDR2:
559
+ case A_NPCM7XX_PWM_PDR3:
560
+ value = s->pwm[npcm7xx_pdr_index(offset)].pdr;
561
+ break;
562
+
563
+ case A_NPCM7XX_PWM_PWDR0:
564
+ case A_NPCM7XX_PWM_PWDR1:
565
+ case A_NPCM7XX_PWM_PWDR2:
566
+ case A_NPCM7XX_PWM_PWDR3:
567
+ value = s->pwm[npcm7xx_pwdr_index(offset)].pwdr;
568
+ break;
569
+
570
+ case A_NPCM7XX_PWM_PPR:
571
+ value = s->ppr;
572
+ break;
573
+
574
+ case A_NPCM7XX_PWM_CSR:
575
+ value = s->csr;
576
+ break;
577
+
578
+ case A_NPCM7XX_PWM_PCR:
579
+ value = s->pcr;
580
+ break;
581
+
582
+ case A_NPCM7XX_PWM_PIER:
583
+ value = s->pier;
584
+ break;
585
+
586
+ case A_NPCM7XX_PWM_PIIR:
587
+ value = s->piir;
588
+ break;
589
+
590
+ default:
591
+ qemu_log_mask(LOG_GUEST_ERROR,
592
+ "%s: invalid offset 0x%04" HWADDR_PRIx "\n",
593
+ __func__, offset);
594
+ break;
595
+ }
596
+
597
+ trace_npcm7xx_pwm_read(DEVICE(s)->canonical_path, offset, value);
598
+ return value;
599
+}
600
+
601
+static void npcm7xx_pwm_write(void *opaque, hwaddr offset,
602
+ uint64_t v, unsigned size)
603
+{
604
+ NPCM7xxPWMState *s = opaque;
605
+ NPCM7xxPWM *p;
606
+ uint32_t value = v;
607
+
608
+ trace_npcm7xx_pwm_write(DEVICE(s)->canonical_path, offset, value);
609
+ switch (offset) {
610
+ case A_NPCM7XX_PWM_CNR0:
611
+ case A_NPCM7XX_PWM_CNR1:
612
+ case A_NPCM7XX_PWM_CNR2:
613
+ case A_NPCM7XX_PWM_CNR3:
614
+ p = &s->pwm[npcm7xx_cnr_index(offset)];
615
+ p->cnr = value;
616
+ npcm7xx_pwm_update_output(p);
617
+ break;
618
+
619
+ case A_NPCM7XX_PWM_CMR0:
620
+ case A_NPCM7XX_PWM_CMR1:
621
+ case A_NPCM7XX_PWM_CMR2:
622
+ case A_NPCM7XX_PWM_CMR3:
623
+ p = &s->pwm[npcm7xx_cmr_index(offset)];
624
+ p->cmr = value;
625
+ npcm7xx_pwm_update_output(p);
626
+ break;
627
+
628
+ case A_NPCM7XX_PWM_PDR0:
629
+ case A_NPCM7XX_PWM_PDR1:
630
+ case A_NPCM7XX_PWM_PDR2:
631
+ case A_NPCM7XX_PWM_PDR3:
632
+ qemu_log_mask(LOG_GUEST_ERROR,
633
+ "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n",
634
+ __func__, offset);
635
+ break;
636
+
637
+ case A_NPCM7XX_PWM_PWDR0:
638
+ case A_NPCM7XX_PWM_PWDR1:
639
+ case A_NPCM7XX_PWM_PWDR2:
640
+ case A_NPCM7XX_PWM_PWDR3:
641
+ qemu_log_mask(LOG_UNIMP,
642
+ "%s: register @ 0x%04" HWADDR_PRIx " is not implemented\n",
643
+ __func__, offset);
644
+ break;
645
+
646
+ case A_NPCM7XX_PWM_PPR:
647
+ npcm7xx_pwm_write_ppr(s, value);
648
+ break;
649
+
650
+ case A_NPCM7XX_PWM_CSR:
651
+ npcm7xx_pwm_write_csr(s, value);
652
+ break;
653
+
654
+ case A_NPCM7XX_PWM_PCR:
655
+ npcm7xx_pwm_write_pcr(s, value);
656
+ break;
657
+
658
+ case A_NPCM7XX_PWM_PIER:
659
+ qemu_log_mask(LOG_UNIMP,
660
+ "%s: register @ 0x%04" HWADDR_PRIx " is not implemented\n",
661
+ __func__, offset);
662
+ break;
663
+
664
+ case A_NPCM7XX_PWM_PIIR:
665
+ qemu_log_mask(LOG_UNIMP,
666
+ "%s: register @ 0x%04" HWADDR_PRIx " is not implemented\n",
667
+ __func__, offset);
668
+ break;
669
+
670
+ default:
671
+ qemu_log_mask(LOG_GUEST_ERROR,
672
+ "%s: invalid offset 0x%04" HWADDR_PRIx "\n",
673
+ __func__, offset);
674
+ break;
675
+ }
676
+}
677
+
678
+static const struct MemoryRegionOps npcm7xx_pwm_ops = {
679
+ .read = npcm7xx_pwm_read,
680
+ .write = npcm7xx_pwm_write,
681
+ .endianness = DEVICE_LITTLE_ENDIAN,
682
+ .valid = {
683
+ .min_access_size = 4,
684
+ .max_access_size = 4,
685
+ .unaligned = false,
686
+ },
687
+};
688
+
689
+static void npcm7xx_pwm_enter_reset(Object *obj, ResetType type)
690
+{
691
+ NPCM7xxPWMState *s = NPCM7XX_PWM(obj);
692
+ int i;
693
+
694
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; i++) {
695
+ NPCM7xxPWM *p = &s->pwm[i];
696
+
697
+ p->cnr = 0x00000000;
698
+ p->cmr = 0x00000000;
699
+ p->pdr = 0x00000000;
700
+ p->pwdr = 0x00000000;
701
+ }
702
+
703
+ s->ppr = 0x00000000;
704
+ s->csr = 0x00000000;
705
+ s->pcr = 0x00000000;
706
+ s->pier = 0x00000000;
707
+ s->piir = 0x00000000;
708
+}
709
+
710
+static void npcm7xx_pwm_hold_reset(Object *obj)
711
+{
712
+ NPCM7xxPWMState *s = NPCM7XX_PWM(obj);
713
+ int i;
714
+
715
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; i++) {
716
+ qemu_irq_lower(s->pwm[i].irq);
717
+ }
718
+}
719
+
720
+static void npcm7xx_pwm_init(Object *obj)
721
+{
722
+ NPCM7xxPWMState *s = NPCM7XX_PWM(obj);
723
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
724
+ int i;
725
+
726
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; i++) {
727
+ NPCM7xxPWM *p = &s->pwm[i];
728
+ p->module = s;
729
+ p->index = i;
730
+ sysbus_init_irq(sbd, &p->irq);
731
+ }
732
+
733
+ memory_region_init_io(&s->iomem, obj, &npcm7xx_pwm_ops, s,
734
+ TYPE_NPCM7XX_PWM, 4 * KiB);
735
+ sysbus_init_mmio(sbd, &s->iomem);
736
+ s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL);
737
+
738
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
739
+ object_property_add_uint32_ptr(obj, "freq[*]",
740
+ &s->pwm[i].freq, OBJ_PROP_FLAG_READ);
741
+ object_property_add_uint32_ptr(obj, "duty[*]",
742
+ &s->pwm[i].duty, OBJ_PROP_FLAG_READ);
743
+ }
744
+}
745
+
746
+static const VMStateDescription vmstate_npcm7xx_pwm = {
747
+ .name = "npcm7xx-pwm",
748
+ .version_id = 0,
749
+ .minimum_version_id = 0,
750
+ .fields = (VMStateField[]) {
751
+ VMSTATE_BOOL(running, NPCM7xxPWM),
752
+ VMSTATE_BOOL(inverted, NPCM7xxPWM),
753
+ VMSTATE_UINT8(index, NPCM7xxPWM),
754
+ VMSTATE_UINT32(cnr, NPCM7xxPWM),
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"
95
--
835
--
96
2.25.1
836
2.20.1
837
838
diff view generated by jsdifflib
1
From: Shengtan Mao <stmao@google.com>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
Reviewed-by: Hao Wu <wuhaotsh@google.com>
3
We add a qtest for the PWM in the previous patch. It proves it works as
4
Reviewed-by: Chris Rauer <crauer@google.com>
4
expected.
5
Signed-off-by: Shengtan Mao <stmao@google.com>
5
6
Signed-off-by: Patrick Venture <venture@google.com>
6
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
7
Message-id: 20220225174451.192304-1-wuhaotsh@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>
10
Message-id: 20210108190945.949196-6-wuhaotsh@google.com
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
12
---
10
tests/qtest/npcm7xx_sdhci-test.c | 215 +++++++++++++++++++++++++++++++
13
tests/qtest/npcm7xx_pwm-test.c | 490 +++++++++++++++++++++++++++++++++
11
tests/qtest/meson.build | 1 +
14
tests/qtest/meson.build | 1 +
12
2 files changed, 216 insertions(+)
15
2 files changed, 491 insertions(+)
13
create mode 100644 tests/qtest/npcm7xx_sdhci-test.c
16
create mode 100644 tests/qtest/npcm7xx_pwm-test.c
14
17
15
diff --git a/tests/qtest/npcm7xx_sdhci-test.c b/tests/qtest/npcm7xx_sdhci-test.c
18
diff --git a/tests/qtest/npcm7xx_pwm-test.c b/tests/qtest/npcm7xx_pwm-test.c
16
new file mode 100644
19
new file mode 100644
17
index XXXXXXX..XXXXXXX
20
index XXXXXXX..XXXXXXX
18
--- /dev/null
21
--- /dev/null
19
+++ b/tests/qtest/npcm7xx_sdhci-test.c
22
+++ b/tests/qtest/npcm7xx_pwm-test.c
20
@@ -XXX,XX +XXX,XX @@
23
@@ -XXX,XX +XXX,XX @@
21
+/*
24
+/*
22
+ * QTests for NPCM7xx SD-3.0 / MMC-4.51 Host Controller
25
+ * QTests for Nuvoton NPCM7xx PWM Modules.
23
+ *
26
+ *
24
+ * Copyright (c) 2022 Google LLC
27
+ * Copyright 2020 Google LLC
25
+ *
28
+ *
26
+ * This program is free software; you can redistribute it and/or modify it
29
+ * This program is free software; you can redistribute it and/or modify it
27
+ * under the terms of the GNU General Public License as published by the
30
+ * under the terms of the GNU General Public License as published by the
28
+ * Free Software Foundation; either version 2 of the License, or
31
+ * Free Software Foundation; either version 2 of the License, or
29
+ * (at your option) any later version.
32
+ * (at your option) any later version.
...
...
33
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
36
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
34
+ * for more details.
37
+ * for more details.
35
+ */
38
+ */
36
+
39
+
37
+#include "qemu/osdep.h"
40
+#include "qemu/osdep.h"
38
+#include "hw/sd/npcm7xx_sdhci.h"
41
+#include "qemu/bitops.h"
39
+
40
+#include "libqos/libqtest.h"
42
+#include "libqos/libqtest.h"
41
+#include "libqtest-single.h"
43
+#include "qapi/qmp/qdict.h"
42
+#include "libqos/sdhci-cmd.h"
44
+#include "qapi/qmp/qnum.h"
43
+
45
+
44
+#define NPCM7XX_REG_SIZE 0x100
46
+#define REF_HZ 25000000
45
+#define NPCM7XX_MMC_BA 0xF0842000
47
+
46
+#define NPCM7XX_BLK_SIZE 512
48
+/* Register field definitions. */
47
+#define NPCM7XX_TEST_IMAGE_SIZE (1 << 30)
49
+#define CH_EN BIT(0)
48
+
50
+#define CH_INV BIT(2)
49
+char *sd_path;
51
+#define CH_MOD BIT(3)
50
+
52
+
51
+static QTestState *setup_sd_card(void)
53
+/* Registers shared between all PWMs in a module */
52
+{
54
+#define PPR 0x00
53
+ QTestState *qts = qtest_initf(
55
+#define CSR 0x04
54
+ "-machine kudo-bmc "
56
+#define PCR 0x08
55
+ "-device sd-card,drive=drive0 "
57
+#define PIER 0x3c
56
+ "-drive id=drive0,if=none,file=%s,format=raw,auto-read-only=off",
58
+#define PIIR 0x40
57
+ sd_path);
59
+
58
+
60
+/* CLK module related */
59
+ qtest_writew(qts, NPCM7XX_MMC_BA + SDHC_SWRST, SDHC_RESET_ALL);
61
+#define CLK_BA 0xf0801000
60
+ qtest_writew(qts, NPCM7XX_MMC_BA + SDHC_CLKCON,
62
+#define CLKSEL 0x04
61
+ SDHC_CLOCK_SDCLK_EN | SDHC_CLOCK_INT_STABLE |
63
+#define CLKDIV1 0x08
62
+ SDHC_CLOCK_INT_EN);
64
+#define CLKDIV2 0x2c
63
+ sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0, 0, SDHC_APP_CMD);
65
+#define PLLCON0 0x0c
64
+ sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0x41200000, 0, (41 << 8));
66
+#define PLLCON1 0x10
65
+ sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0, 0, SDHC_ALL_SEND_CID);
67
+#define PLL_INDV(rv) extract32((rv), 0, 6)
66
+ sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0, 0, SDHC_SEND_RELATIVE_ADDR);
68
+#define PLL_FBDV(rv) extract32((rv), 16, 12)
67
+ sdhci_cmd_regs(qts, NPCM7XX_MMC_BA, 0, 0, 0x45670000, 0,
69
+#define PLL_OTDV1(rv) extract32((rv), 8, 3)
68
+ SDHC_SELECT_DESELECT_CARD);
70
+#define PLL_OTDV2(rv) extract32((rv), 13, 3)
69
+
71
+#define APB3CKDIV(rv) extract32((rv), 28, 2)
70
+ return qts;
72
+#define CLK2CKDIV(rv) extract32((rv), 0, 1)
71
+}
73
+#define CLK4CKDIV(rv) extract32((rv), 26, 2)
72
+
74
+#define CPUCKSEL(rv) extract32((rv), 0, 2)
73
+static void write_sdread(QTestState *qts, const char *msg)
75
+
74
+{
76
+#define MAX_DUTY 1000000
75
+ int fd, ret;
77
+
76
+ size_t len = strlen(msg);
78
+typedef struct PWMModule {
77
+ char *rmsg = g_malloc(len);
79
+ int irq;
78
+
80
+ uint64_t base_addr;
79
+ /* write message to sd */
81
+} PWMModule;
80
+ fd = open(sd_path, O_WRONLY);
82
+
81
+ g_assert(fd >= 0);
83
+typedef struct PWM {
82
+ ret = write(fd, msg, len);
84
+ uint32_t cnr_offset;
83
+ close(fd);
85
+ uint32_t cmr_offset;
84
+ g_assert(ret == len);
86
+ uint32_t pdr_offset;
85
+
87
+ uint32_t pwdr_offset;
86
+ /* read message using sdhci */
88
+} PWM;
87
+ ret = sdhci_read_cmd(qts, NPCM7XX_MMC_BA, rmsg, len);
89
+
88
+ g_assert(ret == len);
90
+typedef struct TestData {
89
+ g_assert(!memcmp(rmsg, msg, len));
91
+ const PWMModule *module;
90
+
92
+ const PWM *pwm;
91
+ g_free(rmsg);
93
+} TestData;
92
+}
94
+
93
+
95
+static const PWMModule pwm_module_list[] = {
94
+/* Check MMC can read values from sd */
96
+ {
95
+static void test_read_sd(void)
97
+ .irq = 93,
96
+{
98
+ .base_addr = 0xf0103000
97
+ QTestState *qts = setup_sd_card();
99
+ },
98
+
100
+ {
99
+ write_sdread(qts, "hello world");
101
+ .irq = 94,
100
+ write_sdread(qts, "goodbye");
102
+ .base_addr = 0xf0104000
103
+ }
104
+};
105
+
106
+static const PWM pwm_list[] = {
107
+ {
108
+ .cnr_offset = 0x0c,
109
+ .cmr_offset = 0x10,
110
+ .pdr_offset = 0x14,
111
+ .pwdr_offset = 0x44,
112
+ },
113
+ {
114
+ .cnr_offset = 0x18,
115
+ .cmr_offset = 0x1c,
116
+ .pdr_offset = 0x20,
117
+ .pwdr_offset = 0x48,
118
+ },
119
+ {
120
+ .cnr_offset = 0x24,
121
+ .cmr_offset = 0x28,
122
+ .pdr_offset = 0x2c,
123
+ .pwdr_offset = 0x4c,
124
+ },
125
+ {
126
+ .cnr_offset = 0x30,
127
+ .cmr_offset = 0x34,
128
+ .pdr_offset = 0x38,
129
+ .pwdr_offset = 0x50,
130
+ },
131
+};
132
+
133
+static const int ppr_base[] = { 0, 0, 8, 8 };
134
+static const int csr_base[] = { 0, 4, 8, 12 };
135
+static const int pcr_base[] = { 0, 8, 12, 16 };
136
+
137
+static const uint32_t ppr_list[] = {
138
+ 0,
139
+ 1,
140
+ 10,
141
+ 100,
142
+ 255, /* Max possible value. */
143
+};
144
+
145
+static const uint32_t csr_list[] = {
146
+ 0,
147
+ 1,
148
+ 2,
149
+ 3,
150
+ 4, /* Max possible value. */
151
+};
152
+
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);
251
+ break;
252
+ case 1:
253
+ pllcon = qtest_readl(qts, CLK_BA + PLLCON1);
254
+ freq = get_pll(pllcon);
255
+ break;
256
+ case 2:
257
+ break;
258
+ case 3:
259
+ break;
260
+ default:
261
+ g_assert_not_reached();
262
+ }
263
+
264
+ freq >>= (CLK2CKDIV(clkdiv1) + CLK4CKDIV(clkdiv1) + APB3CKDIV(clkdiv2));
265
+
266
+ return freq;
267
+}
268
+
269
+static uint32_t pwm_selector(uint32_t csr)
270
+{
271
+ switch (csr) {
272
+ case 0:
273
+ return 2;
274
+ case 1:
275
+ return 4;
276
+ case 2:
277
+ return 8;
278
+ case 3:
279
+ return 16;
280
+ case 4:
281
+ return 1;
282
+ default:
283
+ g_assert_not_reached();
284
+ }
285
+}
286
+
287
+static uint64_t pwm_compute_freq(QTestState *qts, uint32_t ppr, uint32_t csr,
288
+ uint32_t cnr)
289
+{
290
+ return read_pclk(qts) / ((ppr + 1) * pwm_selector(csr) * (cnr + 1));
291
+}
292
+
293
+static uint64_t pwm_compute_duty(uint32_t cnr, uint32_t cmr, bool inverted)
294
+{
295
+ uint64_t duty;
296
+
297
+ if (cnr == 0) {
298
+ /* PWM is stopped. */
299
+ duty = 0;
300
+ } else if (cmr >= cnr) {
301
+ duty = MAX_DUTY;
302
+ } else {
303
+ duty = MAX_DUTY * (cmr + 1) / (cnr + 1);
304
+ }
305
+
306
+ if (inverted) {
307
+ duty = MAX_DUTY - duty;
308
+ }
309
+
310
+ return duty;
311
+}
312
+
313
+static uint32_t pwm_read(QTestState *qts, const TestData *td, unsigned offset)
314
+{
315
+ return qtest_readl(qts, td->module->base_addr + offset);
316
+}
317
+
318
+static void pwm_write(QTestState *qts, const TestData *td, unsigned offset,
319
+ uint32_t value)
320
+{
321
+ qtest_writel(qts, td->module->base_addr + offset, value);
322
+}
323
+
324
+static uint32_t pwm_read_ppr(QTestState *qts, const TestData *td)
325
+{
326
+ return extract32(pwm_read(qts, td, PPR), ppr_base[pwm_index(td->pwm)], 8);
327
+}
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);
101
+
384
+
102
+ qtest_quit(qts);
385
+ qtest_quit(qts);
103
+}
386
+}
104
+
387
+
105
+static void sdwrite_read(QTestState *qts, const char *msg)
388
+/* One-shot mode should not change frequency and duty cycle. */
106
+{
389
+static void test_oneshot(gconstpointer test_data)
107
+ int fd, ret;
390
+{
108
+ size_t len = strlen(msg);
391
+ const TestData *td = test_data;
109
+ char *rmsg = g_malloc(len);
392
+ QTestState *qts = qtest_init("-machine quanta-gsj");
110
+
393
+ int module = pwm_module_index(td->module);
111
+ /* write message using sdhci */
394
+ int pwm = pwm_index(td->pwm);
112
+ sdhci_write_cmd(qts, NPCM7XX_MMC_BA, msg, len, NPCM7XX_BLK_SIZE);
395
+ uint32_t ppr, csr, pcr;
113
+
396
+ int i, j;
114
+ /* read message from sd */
397
+
115
+ fd = open(sd_path, O_RDONLY);
398
+ pcr = CH_EN;
116
+ g_assert(fd >= 0);
399
+ for (i = 0; i < ARRAY_SIZE(ppr_list); ++i) {
117
+ ret = read(fd, rmsg, len);
400
+ ppr = ppr_list[i];
118
+ close(fd);
401
+ pwm_write_ppr(qts, td, ppr);
119
+ g_assert(ret == len);
402
+
120
+
403
+ for (j = 0; j < ARRAY_SIZE(csr_list); ++j) {
121
+ g_assert(!memcmp(rmsg, msg, len));
404
+ csr = csr_list[j];
122
+
405
+ pwm_write_csr(qts, td, csr);
123
+ g_free(rmsg);
406
+ pwm_write_pcr(qts, td, pcr);
124
+}
407
+
125
+
408
+ g_assert_cmpuint(pwm_read_ppr(qts, td), ==, ppr);
126
+/* Check MMC can write values to sd */
409
+ g_assert_cmpuint(pwm_read_csr(qts, td), ==, csr);
127
+static void test_write_sd(void)
410
+ g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr);
128
+{
411
+ g_assert_cmpuint(pwm_get_freq(qts, module, pwm), ==, 0);
129
+ QTestState *qts = setup_sd_card();
412
+ g_assert_cmpuint(pwm_get_duty(qts, module, pwm), ==, 0);
130
+
413
+ }
131
+ sdwrite_read(qts, "hello world");
414
+ }
132
+ sdwrite_read(qts, "goodbye");
133
+
415
+
134
+ qtest_quit(qts);
416
+ qtest_quit(qts);
135
+}
417
+}
136
+
418
+
137
+/* Check SDHCI has correct default values. */
419
+/* In toggle mode, the PWM generates correct outputs. */
138
+static void test_reset(void)
420
+static void test_toggle(gconstpointer test_data)
139
+{
421
+{
140
+ QTestState *qts = qtest_init("-machine kudo-bmc");
422
+ const TestData *td = test_data;
141
+ uint64_t addr = NPCM7XX_MMC_BA;
423
+ QTestState *qts = qtest_init("-machine quanta-gsj");
142
+ uint64_t end_addr = addr + NPCM7XX_REG_SIZE;
424
+ int module = pwm_module_index(td->module);
143
+ uint16_t prstvals_resets[] = {NPCM7XX_PRSTVALS_0_RESET,
425
+ int pwm = pwm_index(td->pwm);
144
+ NPCM7XX_PRSTVALS_1_RESET,
426
+ uint32_t ppr, csr, pcr, cnr, cmr;
145
+ 0,
427
+ int i, j, k, l;
146
+ NPCM7XX_PRSTVALS_3_RESET,
428
+ uint64_t expected_freq, expected_duty;
147
+ 0,
429
+
148
+ 0};
430
+ pcr = CH_EN | CH_MOD;
149
+ int i;
431
+ for (i = 0; i < ARRAY_SIZE(ppr_list); ++i) {
150
+ uint32_t mask;
432
+ ppr = ppr_list[i];
151
+
433
+ pwm_write_ppr(qts, td, ppr);
152
+ while (addr < end_addr) {
434
+
153
+ switch (addr - NPCM7XX_MMC_BA) {
435
+ for (j = 0; j < ARRAY_SIZE(csr_list); ++j) {
154
+ case SDHC_PRNSTS:
436
+ csr = csr_list[j];
155
+ /*
437
+ pwm_write_csr(qts, td, csr);
156
+ * ignores bits 20 to 24: they are changed when reading registers
438
+
157
+ */
439
+ for (k = 0; k < ARRAY_SIZE(cnr_list); ++k) {
158
+ mask = 0x1f00000;
440
+ cnr = cnr_list[k];
159
+ g_assert_cmphex(qtest_readl(qts, addr) | mask, ==,
441
+ pwm_write_cnr(qts, td, cnr);
160
+ NPCM7XX_PRSNTS_RESET | mask);
442
+
161
+ addr += 4;
443
+ for (l = 0; l < ARRAY_SIZE(cmr_list); ++l) {
162
+ break;
444
+ cmr = cmr_list[l];
163
+ case SDHC_BLKGAP:
445
+ pwm_write_cmr(qts, td, cmr);
164
+ g_assert_cmphex(qtest_readb(qts, addr), ==, NPCM7XX_BLKGAP_RESET);
446
+ expected_freq = pwm_compute_freq(qts, ppr, csr, cnr);
165
+ addr += 1;
447
+ expected_duty = pwm_compute_duty(cnr, cmr, false);
166
+ break;
448
+
167
+ case SDHC_CAPAB:
449
+ pwm_write_pcr(qts, td, pcr);
168
+ g_assert_cmphex(qtest_readq(qts, addr), ==, NPCM7XX_CAPAB_RESET);
450
+ g_assert_cmpuint(pwm_read_ppr(qts, td), ==, ppr);
169
+ addr += 8;
451
+ g_assert_cmpuint(pwm_read_csr(qts, td), ==, csr);
170
+ break;
452
+ g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr);
171
+ case SDHC_MAXCURR:
453
+ g_assert_cmpuint(pwm_read_cnr(qts, td), ==, cnr);
172
+ g_assert_cmphex(qtest_readq(qts, addr), ==, NPCM7XX_MAXCURR_RESET);
454
+ g_assert_cmpuint(pwm_read_cmr(qts, td), ==, cmr);
173
+ addr += 8;
455
+ g_assert_cmpuint(pwm_get_duty(qts, module, pwm),
174
+ break;
456
+ ==, expected_duty);
175
+ case SDHC_HCVER:
457
+ if (expected_duty != 0 && expected_duty != 100) {
176
+ g_assert_cmphex(qtest_readw(qts, addr), ==, NPCM7XX_HCVER_RESET);
458
+ /* Duty cycle with 0 or 100 doesn't need frequency. */
177
+ addr += 2;
459
+ g_assert_cmpuint(pwm_get_freq(qts, module, pwm),
178
+ break;
460
+ ==, expected_freq);
179
+ case NPCM7XX_PRSTVALS:
461
+ }
180
+ for (i = 0; i < NPCM7XX_PRSTVALS_SIZE; ++i) {
462
+
181
+ g_assert_cmphex(qtest_readw(qts, addr + 2 * i), ==,
463
+ /* Test inverted mode */
182
+ prstvals_resets[i]);
464
+ expected_duty = pwm_compute_duty(cnr, cmr, true);
465
+ pwm_write_pcr(qts, td, pcr | CH_INV);
466
+ g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr | CH_INV);
467
+ g_assert_cmpuint(pwm_get_duty(qts, module, pwm),
468
+ ==, expected_duty);
469
+ if (expected_duty != 0 && expected_duty != 100) {
470
+ /* Duty cycle with 0 or 100 doesn't need frequency. */
471
+ g_assert_cmpuint(pwm_get_freq(qts, module, pwm),
472
+ ==, expected_freq);
473
+ }
474
+
475
+ }
183
+ }
476
+ }
184
+ addr += NPCM7XX_PRSTVALS_SIZE * 2;
185
+ break;
186
+ default:
187
+ g_assert_cmphex(qtest_readb(qts, addr), ==, 0);
188
+ addr += 1;
189
+ }
477
+ }
190
+ }
478
+ }
191
+
479
+
192
+ qtest_quit(qts);
480
+ qtest_quit(qts);
193
+}
481
+}
194
+
482
+
195
+static void drive_destroy(void)
483
+static void pwm_add_test(const char *name, const TestData* td,
196
+{
484
+ GTestDataFunc fn)
197
+ unlink(sd_path);
485
+{
198
+ g_free(sd_path);
486
+ g_autofree char *full_name = g_strdup_printf(
199
+}
487
+ "npcm7xx_pwm/module[%d]/pwm[%d]/%s", pwm_module_index(td->module),
200
+
488
+ pwm_index(td->pwm), name);
201
+static void drive_create(void)
489
+ qtest_add_data_func(full_name, td, fn);
202
+{
490
+}
203
+ int fd, ret;
491
+#define add_test(name, td) pwm_add_test(#name, td, test_##name)
204
+ GError *error = NULL;
205
+
206
+ /* Create a temporary raw image */
207
+ fd = g_file_open_tmp("sdhci_XXXXXX", &sd_path, &error);
208
+ if (fd == -1) {
209
+ fprintf(stderr, "unable to create sdhci file: %s\n", error->message);
210
+ g_error_free(error);
211
+ }
212
+ g_assert(sd_path != NULL);
213
+
214
+ ret = ftruncate(fd, NPCM7XX_TEST_IMAGE_SIZE);
215
+ g_assert_cmpint(ret, ==, 0);
216
+ g_message("%s", sd_path);
217
+ close(fd);
218
+}
219
+
492
+
220
+int main(int argc, char **argv)
493
+int main(int argc, char **argv)
221
+{
494
+{
222
+ int ret;
495
+ TestData test_data_list[ARRAY_SIZE(pwm_module_list) * ARRAY_SIZE(pwm_list)];
223
+
224
+ drive_create();
225
+
496
+
226
+ g_test_init(&argc, &argv, NULL);
497
+ g_test_init(&argc, &argv, NULL);
227
+
498
+
228
+ qtest_add_func("npcm7xx_sdhci/reset", test_reset);
499
+ for (int i = 0; i < ARRAY_SIZE(pwm_module_list); ++i) {
229
+ qtest_add_func("npcm7xx_sdhci/write_sd", test_write_sd);
500
+ for (int j = 0; j < ARRAY_SIZE(pwm_list); ++j) {
230
+ qtest_add_func("npcm7xx_sdhci/read_sd", test_read_sd);
501
+ TestData *td = &test_data_list[i * ARRAY_SIZE(pwm_list) + j];
231
+
502
+
232
+ ret = g_test_run();
503
+ td->module = &pwm_module_list[i];
233
+ drive_destroy();
504
+ td->pwm = &pwm_list[j];
234
+ return ret;
505
+
506
+ add_test(init, td);
507
+ add_test(oneshot, td);
508
+ add_test(toggle, td);
509
+ }
510
+ }
511
+
512
+ return g_test_run();
235
+}
513
+}
236
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
514
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
237
index XXXXXXX..XXXXXXX 100644
515
index XXXXXXX..XXXXXXX 100644
238
--- a/tests/qtest/meson.build
516
--- a/tests/qtest/meson.build
239
+++ b/tests/qtest/meson.build
517
+++ b/tests/qtest/meson.build
240
@@ -XXX,XX +XXX,XX @@ qtests_npcm7xx = \
518
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
519
qtests_npcm7xx = \
520
['npcm7xx_adc-test',
241
'npcm7xx_gpio-test',
521
'npcm7xx_gpio-test',
242
'npcm7xx_pwm-test',
522
+ 'npcm7xx_pwm-test',
243
'npcm7xx_rng-test',
523
'npcm7xx_rng-test',
244
+ 'npcm7xx_sdhci-test',
245
'npcm7xx_smbus-test',
246
'npcm7xx_timer-test',
524
'npcm7xx_timer-test',
247
'npcm7xx_watchdog_timer-test'] + \
525
'npcm7xx_watchdog_timer-test']
248
--
526
--
249
2.25.1
527
2.20.1
528
529
diff view generated by jsdifflib
Deleted patch
1
From: Richard Henderson <richard.henderson@linaro.org>
2
1
3
Set this as the kernel would, to 48 bits, to keep the computation
4
of the address space correct for PAuth.
5
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20220301215958.157011-3-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
target/arm/cpu.c | 3 ++-
12
1 file changed, 2 insertions(+), 1 deletion(-)
13
14
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/cpu.c
17
+++ b/target/arm/cpu.c
18
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_reset(DeviceState *dev)
19
aarch64_sve_zcr_get_valid_len(cpu, cpu->sve_default_vq - 1);
20
}
21
/*
22
+ * Enable 48-bit address space (TODO: take reserved_va into account).
23
* Enable TBI0 but not TBI1.
24
* Note that this must match useronly_clean_ptr.
25
*/
26
- env->cp15.tcr_el[1].raw_tcr = (1ULL << 37);
27
+ env->cp15.tcr_el[1].raw_tcr = 5 | (1ULL << 37);
28
29
/* Enable MTE */
30
if (cpu_isar_feature(aa64_mte, cpu)) {
31
--
32
2.25.1
diff view generated by jsdifflib
Deleted patch
1
From: Richard Henderson <richard.henderson@linaro.org>
2
1
3
Pass down the width of the output address from translation.
4
For now this is still just PAMax, but a subsequent patch will
5
compute the correct value from TCR_ELx.{I}PS.
6
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20220301215958.157011-6-richard.henderson@linaro.org
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
12
target/arm/helper.c | 21 ++++++++++-----------
13
1 file changed, 10 insertions(+), 11 deletions(-)
14
15
diff --git a/target/arm/helper.c b/target/arm/helper.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/helper.c
18
+++ b/target/arm/helper.c
19
@@ -XXX,XX +XXX,XX @@ do_fault:
20
* false otherwise.
21
*/
22
static bool check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, int level,
23
- int inputsize, int stride)
24
+ int inputsize, int stride, int outputsize)
25
{
26
const int grainsize = stride + 3;
27
int startsizecheck;
28
@@ -XXX,XX +XXX,XX @@ static bool check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, int level,
29
}
30
31
if (is_aa64) {
32
- CPUARMState *env = &cpu->env;
33
- unsigned int pamax = arm_pamax(cpu);
34
-
35
switch (stride) {
36
case 13: /* 64KB Pages. */
37
- if (level == 0 || (level == 1 && pamax <= 42)) {
38
+ if (level == 0 || (level == 1 && outputsize <= 42)) {
39
return false;
40
}
41
break;
42
case 11: /* 16KB Pages. */
43
- if (level == 0 || (level == 1 && pamax <= 40)) {
44
+ if (level == 0 || (level == 1 && outputsize <= 40)) {
45
return false;
46
}
47
break;
48
case 9: /* 4KB Pages. */
49
- if (level == 0 && pamax <= 42) {
50
+ if (level == 0 && outputsize <= 42) {
51
return false;
52
}
53
break;
54
@@ -XXX,XX +XXX,XX @@ static bool check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, int level,
55
}
56
57
/* Inputsize checks. */
58
- if (inputsize > pamax &&
59
- (arm_el_is_aa64(env, 1) || inputsize > 40)) {
60
+ if (inputsize > outputsize &&
61
+ (arm_el_is_aa64(&cpu->env, 1) || inputsize > 40)) {
62
/* This is CONSTRAINED UNPREDICTABLE and we choose to fault. */
63
return false;
64
}
65
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
66
target_ulong page_size;
67
uint32_t attrs;
68
int32_t stride;
69
- int addrsize, inputsize;
70
+ int addrsize, inputsize, outputsize;
71
TCR *tcr = regime_tcr(env, mmu_idx);
72
int ap, ns, xn, pxn;
73
uint32_t el = regime_el(env, mmu_idx);
74
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
75
76
addrsize = 64 - 8 * param.tbi;
77
inputsize = 64 - param.tsz;
78
+ outputsize = arm_pamax(cpu);
79
} else {
80
param = aa32_va_parameters(env, address, mmu_idx);
81
level = 1;
82
addrsize = (mmu_idx == ARMMMUIdx_Stage2 ? 40 : 32);
83
inputsize = addrsize - param.tsz;
84
+ outputsize = 40;
85
}
86
87
/*
88
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
89
90
/* Check that the starting level is valid. */
91
ok = check_s2_mmu_setup(cpu, aarch64, startlevel,
92
- inputsize, stride);
93
+ inputsize, stride, outputsize);
94
if (!ok) {
95
fault_type = ARMFault_Translation;
96
goto do_fault;
97
--
98
2.25.1
diff view generated by jsdifflib
Deleted patch
1
From: Richard Henderson <richard.henderson@linaro.org>
2
1
3
The original A.a revision of the AArch64 ARM required that we
4
force-extend the addresses in these registers from 49 bits.
5
This language has been loosened via a combination of IMPLEMENTATION
6
DEFINED and CONSTRAINTED UNPREDICTABLE to allow consideration of
7
the entire aligned address.
8
9
This means that we do not have to consider whether or not FEAT_LVA
10
is enabled, and decide from which bit an address might need to be
11
extended.
12
13
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
14
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
15
Message-id: 20220301215958.157011-9-richard.henderson@linaro.org
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
---
18
target/arm/helper.c | 32 ++++++++++++++++++++++++--------
19
1 file changed, 24 insertions(+), 8 deletions(-)
20
21
diff --git a/target/arm/helper.c b/target/arm/helper.c
22
index XXXXXXX..XXXXXXX 100644
23
--- a/target/arm/helper.c
24
+++ b/target/arm/helper.c
25
@@ -XXX,XX +XXX,XX @@ static void dbgwvr_write(CPUARMState *env, const ARMCPRegInfo *ri,
26
ARMCPU *cpu = env_archcpu(env);
27
int i = ri->crm;
28
29
- /* Bits [63:49] are hardwired to the value of bit [48]; that is, the
30
- * register reads and behaves as if values written are sign extended.
31
+ /*
32
* Bits [1:0] are RES0.
33
+ *
34
+ * It is IMPLEMENTATION DEFINED whether [63:49] ([63:53] with FEAT_LVA)
35
+ * are hardwired to the value of bit [48] ([52] with FEAT_LVA), or if
36
+ * they contain the value written. It is CONSTRAINED UNPREDICTABLE
37
+ * whether the RESS bits are ignored when comparing an address.
38
+ *
39
+ * Therefore we are allowed to compare the entire register, which lets
40
+ * us avoid considering whether or not FEAT_LVA is actually enabled.
41
*/
42
- value = sextract64(value, 0, 49) & ~3ULL;
43
+ value &= ~3ULL;
44
45
raw_write(env, ri, value);
46
hw_watchpoint_update(cpu, i);
47
@@ -XXX,XX +XXX,XX @@ void hw_breakpoint_update(ARMCPU *cpu, int n)
48
case 0: /* unlinked address match */
49
case 1: /* linked address match */
50
{
51
- /* Bits [63:49] are hardwired to the value of bit [48]; that is,
52
- * we behave as if the register was sign extended. Bits [1:0] are
53
- * RES0. The BAS field is used to allow setting breakpoints on 16
54
- * bit wide instructions; it is CONSTRAINED UNPREDICTABLE whether
55
+ /*
56
+ * Bits [1:0] are RES0.
57
+ *
58
+ * It is IMPLEMENTATION DEFINED whether bits [63:49]
59
+ * ([63:53] for FEAT_LVA) are hardwired to a copy of the sign bit
60
+ * of the VA field ([48] or [52] for FEAT_LVA), or whether the
61
+ * value is read as written. It is CONSTRAINED UNPREDICTABLE
62
+ * whether the RESS bits are ignored when comparing an address.
63
+ * Therefore we are allowed to compare the entire register, which
64
+ * lets us avoid considering whether FEAT_LVA is actually enabled.
65
+ *
66
+ * The BAS field is used to allow setting breakpoints on 16-bit
67
+ * wide instructions; it is CONSTRAINED UNPREDICTABLE whether
68
* a bp will fire if the addresses covered by the bp and the addresses
69
* covered by the insn overlap but the insn doesn't start at the
70
* start of the bp address range. We choose to require the insn and
71
@@ -XXX,XX +XXX,XX @@ void hw_breakpoint_update(ARMCPU *cpu, int n)
72
* See also figure D2-3 in the v8 ARM ARM (DDI0487A.c).
73
*/
74
int bas = extract64(bcr, 5, 4);
75
- addr = sextract64(bvr, 0, 49) & ~3ULL;
76
+ addr = bvr & ~3ULL;
77
if (bas == 0) {
78
return;
79
}
80
--
81
2.25.1
diff view generated by jsdifflib
Deleted patch
1
From: Richard Henderson <richard.henderson@linaro.org>
2
1
3
With FEAT_LPA2, rather than introducing translation level 4,
4
we introduce level -1, below the current level 0. Extend
5
arm_fi_to_lfsc to handle these faults.
6
7
Assert that this new translation level does not leak into
8
fault types for which it is not defined, which allows some
9
masking of fi->level to be removed.
10
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
13
Message-id: 20220301215958.157011-12-richard.henderson@linaro.org
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
---
16
target/arm/internals.h | 35 +++++++++++++++++++++++++++++------
17
1 file changed, 29 insertions(+), 6 deletions(-)
18
19
diff --git a/target/arm/internals.h b/target/arm/internals.h
20
index XXXXXXX..XXXXXXX 100644
21
--- a/target/arm/internals.h
22
+++ b/target/arm/internals.h
23
@@ -XXX,XX +XXX,XX @@ static inline uint32_t arm_fi_to_lfsc(ARMMMUFaultInfo *fi)
24
case ARMFault_None:
25
return 0;
26
case ARMFault_AddressSize:
27
- fsc = fi->level & 3;
28
+ assert(fi->level >= -1 && fi->level <= 3);
29
+ if (fi->level < 0) {
30
+ fsc = 0b101001;
31
+ } else {
32
+ fsc = fi->level;
33
+ }
34
break;
35
case ARMFault_AccessFlag:
36
- fsc = (fi->level & 3) | (0x2 << 2);
37
+ assert(fi->level >= 0 && fi->level <= 3);
38
+ fsc = 0b001000 | fi->level;
39
break;
40
case ARMFault_Permission:
41
- fsc = (fi->level & 3) | (0x3 << 2);
42
+ assert(fi->level >= 0 && fi->level <= 3);
43
+ fsc = 0b001100 | fi->level;
44
break;
45
case ARMFault_Translation:
46
- fsc = (fi->level & 3) | (0x1 << 2);
47
+ assert(fi->level >= -1 && fi->level <= 3);
48
+ if (fi->level < 0) {
49
+ fsc = 0b101011;
50
+ } else {
51
+ fsc = 0b000100 | fi->level;
52
+ }
53
break;
54
case ARMFault_SyncExternal:
55
fsc = 0x10 | (fi->ea << 12);
56
break;
57
case ARMFault_SyncExternalOnWalk:
58
- fsc = (fi->level & 3) | (0x5 << 2) | (fi->ea << 12);
59
+ assert(fi->level >= -1 && fi->level <= 3);
60
+ if (fi->level < 0) {
61
+ fsc = 0b010011;
62
+ } else {
63
+ fsc = 0b010100 | fi->level;
64
+ }
65
+ fsc |= fi->ea << 12;
66
break;
67
case ARMFault_SyncParity:
68
fsc = 0x18;
69
break;
70
case ARMFault_SyncParityOnWalk:
71
- fsc = (fi->level & 3) | (0x7 << 2);
72
+ assert(fi->level >= -1 && fi->level <= 3);
73
+ if (fi->level < 0) {
74
+ fsc = 0b011011;
75
+ } else {
76
+ fsc = 0b011100 | fi->level;
77
+ }
78
break;
79
case ARMFault_AsyncParity:
80
fsc = 0x19;
81
--
82
2.25.1
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
Merge tlbi_aa64_range_get_length and tlbi_aa64_range_get_base,
3
A device shouldn't access its parent object which is QOM internal.
4
returning a structure containing both results. Pass in the
4
Instead it should use type cast for this purporse. This patch fixes this
5
ARMMMUIdx, rather than the digested two_ranges boolean.
5
issue for all NPCM7XX Devices.
6
6
7
This is in preparation for FEAT_LPA2, where the interpretation
7
Signed-off-by: Hao Wu <wuhaotsh@google.com>
8
of 'value' depends on the effective value of DS for the regime.
9
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20210108190945.949196-7-wuhaotsh@google.com
12
Message-id: 20220301215958.157011-13-richard.henderson@linaro.org
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
14
---
11
---
15
target/arm/helper.c | 58 +++++++++++++++++++--------------------------
12
hw/arm/npcm7xx_boards.c | 2 +-
16
1 file changed, 24 insertions(+), 34 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(-)
17
20
18
diff --git a/target/arm/helper.c b/target/arm/helper.c
21
diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c
19
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
20
--- a/target/arm/helper.c
23
--- a/hw/arm/npcm7xx_boards.c
21
+++ b/target/arm/helper.c
24
+++ b/hw/arm/npcm7xx_boards.c
22
@@ -XXX,XX +XXX,XX @@ static void tlbi_aa64_vae3is_write(CPUARMState *env, const ARMCPRegInfo *ri,
25
@@ -XXX,XX +XXX,XX @@ static NPCM7xxState *npcm7xx_create_soc(MachineState *machine,
26
uint32_t hw_straps)
27
{
28
NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_GET_CLASS(machine);
29
- MachineClass *mc = &nmc->parent;
30
+ MachineClass *mc = MACHINE_CLASS(nmc);
31
Object *obj;
32
33
if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) {
34
diff --git a/hw/mem/npcm7xx_mc.c b/hw/mem/npcm7xx_mc.c
35
index XXXXXXX..XXXXXXX 100644
36
--- a/hw/mem/npcm7xx_mc.c
37
+++ b/hw/mem/npcm7xx_mc.c
38
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_mc_realize(DeviceState *dev, Error **errp)
39
40
memory_region_init_io(&s->mmio, OBJECT(s), &npcm7xx_mc_ops, s, "regs",
41
NPCM7XX_MC_REGS_SIZE);
42
- sysbus_init_mmio(&s->parent, &s->mmio);
43
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio);
23
}
44
}
24
45
25
#ifdef TARGET_AARCH64
46
static void npcm7xx_mc_class_init(ObjectClass *klass, void *data)
26
-static uint64_t tlbi_aa64_range_get_length(CPUARMState *env,
47
diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
27
- uint64_t value)
48
index XXXXXXX..XXXXXXX 100644
28
-{
49
--- a/hw/misc/npcm7xx_clk.c
29
- unsigned int page_shift;
50
+++ b/hw/misc/npcm7xx_clk.c
30
- unsigned int page_size_granule;
51
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_init(Object *obj)
31
- uint64_t num;
52
32
- uint64_t scale;
53
memory_region_init_io(&s->iomem, obj, &npcm7xx_clk_ops, s,
33
- uint64_t exponent;
54
TYPE_NPCM7XX_CLK, 4 * KiB);
34
+typedef struct {
55
- sysbus_init_mmio(&s->parent, &s->iomem);
35
+ uint64_t base;
56
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
36
uint64_t length;
37
+} TLBIRange;
38
+
39
+static TLBIRange tlbi_aa64_get_range(CPUARMState *env, ARMMMUIdx mmuidx,
40
+ uint64_t value)
41
+{
42
+ unsigned int page_size_granule, page_shift, num, scale, exponent;
43
+ TLBIRange ret = { };
44
45
- num = extract64(value, 39, 5);
46
- scale = extract64(value, 44, 2);
47
page_size_granule = extract64(value, 46, 2);
48
49
if (page_size_granule == 0) {
50
qemu_log_mask(LOG_GUEST_ERROR, "Invalid page size granule %d\n",
51
page_size_granule);
52
- return 0;
53
+ return ret;
54
}
55
56
page_shift = (page_size_granule - 1) * 2 + 12;
57
-
58
+ num = extract64(value, 39, 5);
59
+ scale = extract64(value, 44, 2);
60
exponent = (5 * scale) + 1;
61
- length = (num + 1) << (exponent + page_shift);
62
63
- return length;
64
-}
65
+ ret.length = (num + 1) << (exponent + page_shift);
66
67
-static uint64_t tlbi_aa64_range_get_base(CPUARMState *env, uint64_t value,
68
- bool two_ranges)
69
-{
70
- /* TODO: ARMv8.7 FEAT_LPA2 */
71
- uint64_t pageaddr;
72
-
73
- if (two_ranges) {
74
- pageaddr = sextract64(value, 0, 37) << TARGET_PAGE_BITS;
75
+ if (regime_has_2_ranges(mmuidx)) {
76
+ ret.base = sextract64(value, 0, 37) << TARGET_PAGE_BITS;
77
} else {
78
- pageaddr = extract64(value, 0, 37) << TARGET_PAGE_BITS;
79
+ ret.base = extract64(value, 0, 37) << TARGET_PAGE_BITS;
80
}
81
82
- return pageaddr;
83
+ return ret;
84
}
57
}
85
58
86
static void do_rvae_write(CPUARMState *env, uint64_t value,
59
static int npcm7xx_clk_post_load(void *opaque, int version_id)
87
int idxmap, bool synced)
60
diff --git a/hw/misc/npcm7xx_gcr.c b/hw/misc/npcm7xx_gcr.c
61
index XXXXXXX..XXXXXXX 100644
62
--- a/hw/misc/npcm7xx_gcr.c
63
+++ b/hw/misc/npcm7xx_gcr.c
64
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_gcr_init(Object *obj)
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);
70
}
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)
88
{
91
{
89
ARMMMUIdx one_idx = ARM_MMU_IDX_A | ctz32(idxmap);
92
NPCM7xxOTPClass *oc = NPCM7XX_OTP_GET_CLASS(dev);
90
- bool two_ranges = regime_has_2_ranges(one_idx);
93
NPCM7xxOTPState *s = NPCM7XX_OTP(dev);
91
- uint64_t baseaddr, length;
94
- SysBusDevice *sbd = &s->parent;
92
+ TLBIRange range;
95
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
93
int bits;
96
94
97
memset(s->array, 0, sizeof(s->array));
95
- baseaddr = tlbi_aa64_range_get_base(env, value, two_ranges);
98
96
- length = tlbi_aa64_range_get_length(env, value);
99
diff --git a/hw/ssi/npcm7xx_fiu.c b/hw/ssi/npcm7xx_fiu.c
97
- bits = tlbbits_for_regime(env, one_idx, baseaddr);
100
index XXXXXXX..XXXXXXX 100644
98
+ range = tlbi_aa64_get_range(env, one_idx, value);
101
--- a/hw/ssi/npcm7xx_fiu.c
99
+ bits = tlbbits_for_regime(env, one_idx, range.base);
102
+++ b/hw/ssi/npcm7xx_fiu.c
100
103
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_fiu_hold_reset(Object *obj)
101
if (synced) {
104
static void npcm7xx_fiu_realize(DeviceState *dev, Error **errp)
102
tlb_flush_range_by_mmuidx_all_cpus_synced(env_cpu(env),
105
{
103
- baseaddr,
106
NPCM7xxFIUState *s = NPCM7XX_FIU(dev);
104
- length,
107
- SysBusDevice *sbd = &s->parent;
105
+ range.base,
108
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
106
+ range.length,
109
int i;
107
idxmap,
110
108
bits);
111
if (s->cs_count <= 0) {
109
} else {
110
- tlb_flush_range_by_mmuidx(env_cpu(env), baseaddr,
111
- length, idxmap, bits);
112
+ tlb_flush_range_by_mmuidx(env_cpu(env), range.base,
113
+ range.length, idxmap, bits);
114
}
115
}
116
117
--
112
--
118
2.25.1
113
2.20.1
114
115
diff view generated by jsdifflib
1
The updateUIInfo method makes Cocoa API calls. It also calls back
1
From: Roman Bolshakov <r.bolshakov@yadro.com>
2
into QEMU functions like dpy_set_ui_info(). To do this safely, we
3
need to follow two rules:
4
* Cocoa API calls are made on the Cocoa UI thread
5
* When calling back into QEMU we must hold the iothread lock
6
2
7
Fix the places where we got this wrong, by taking the iothread lock
3
ui/cocoa.m:1188:44: warning: 'openFile:' is deprecated: first deprecated in macOS 11.0 - Use -[NSWorkspace openURL:] instead.
8
while executing updateUIInfo, and moving the call in cocoa_switch()
4
[-Wdeprecated-declarations]
9
inside the dispatch_async block.
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
^
10
11
11
Some of the Cocoa UI methods which call updateUIInfo are invoked as
12
Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
12
part of the initial application startup, while we're still doing the
13
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
13
little cross-thread dance described in the comment just above
14
Message-id: 20210102150718.47618-1-r.bolshakov@yadro.com
14
call_qemu_main(). This meant they were calling back into the QEMU UI
15
layer before we'd actually finished initializing our display and
16
registered the DisplayChangeListener, which isn't really valid. Once
17
updateUIInfo takes the iothread lock, we no longer get away with
18
this, because during this startup phase the iothread lock is held by
19
the QEMU main-loop thread which is waiting for us to finish our
20
display initialization. So we must suppress updateUIInfo until
21
applicationDidFinishLaunching allows the QEMU main-loop thread to
22
continue.
23
24
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
25
Reviewed-by: Akihiko Odaki <akihiko.odaki@gmail.com>
26
Tested-by: Akihiko Odaki <akihiko.odaki@gmail.com>
27
Message-id: 20220224101330.967429-2-peter.maydell@linaro.org
28
---
16
---
29
ui/cocoa.m | 25 ++++++++++++++++++++++---
17
ui/cocoa.m | 5 ++++-
30
1 file changed, 22 insertions(+), 3 deletions(-)
18
1 file changed, 4 insertions(+), 1 deletion(-)
31
19
32
diff --git a/ui/cocoa.m b/ui/cocoa.m
20
diff --git a/ui/cocoa.m b/ui/cocoa.m
33
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
34
--- a/ui/cocoa.m
22
--- a/ui/cocoa.m
35
+++ b/ui/cocoa.m
23
+++ b/ui/cocoa.m
36
@@ -XXX,XX +XXX,XX @@ QemuCocoaView *cocoaView;
24
@@ -XXX,XX +XXX,XX @@ QemuCocoaView *cocoaView;
25
/* Where to look for local files */
26
NSString *path_array[] = {@"../share/doc/qemu/", @"../doc/qemu/", @"docs/"};
27
NSString *full_file_path;
28
+ NSURL *full_file_url;
29
30
/* iterate thru the possible paths until the file is found */
31
int index;
32
@@ -XXX,XX +XXX,XX @@ QemuCocoaView *cocoaView;
33
full_file_path = [full_file_path stringByDeletingLastPathComponent];
34
full_file_path = [NSString stringWithFormat: @"%@/%@%@", full_file_path,
35
path_array[index], filename];
36
- if ([[NSWorkspace sharedWorkspace] openFile: full_file_path] == YES) {
37
+ full_file_url = [NSURL fileURLWithPath: full_file_path
38
+ isDirectory: false];
39
+ if ([[NSWorkspace sharedWorkspace] openURL: full_file_url] == YES) {
40
return;
41
}
37
}
42
}
38
}
39
40
-- (void) updateUIInfo
41
+- (void) updateUIInfoLocked
42
{
43
+ /* Must be called with the iothread lock, i.e. via updateUIInfo */
44
NSSize frameSize;
45
QemuUIInfo info;
46
47
@@ -XXX,XX +XXX,XX @@ QemuCocoaView *cocoaView;
48
dpy_set_ui_info(dcl.con, &info, TRUE);
49
}
50
51
+- (void) updateUIInfo
52
+{
53
+ if (!allow_events) {
54
+ /*
55
+ * Don't try to tell QEMU about UI information in the application
56
+ * startup phase -- we haven't yet registered dcl with the QEMU UI
57
+ * layer, and also trying to take the iothread lock would deadlock.
58
+ * When cocoa_display_init() does register the dcl, the UI layer
59
+ * will call cocoa_switch(), which will call updateUIInfo, so
60
+ * we don't lose any information here.
61
+ */
62
+ return;
63
+ }
64
+
65
+ with_iothread_lock(^{
66
+ [self updateUIInfoLocked];
67
+ });
68
+}
69
+
70
- (void)viewDidMoveToWindow
71
{
72
[self updateUIInfo];
73
@@ -XXX,XX +XXX,XX @@ static void cocoa_switch(DisplayChangeListener *dcl,
74
75
COCOA_DEBUG("qemu_cocoa: cocoa_switch\n");
76
77
- [cocoaView updateUIInfo];
78
-
79
// The DisplaySurface will be freed as soon as this callback returns.
80
// We take a reference to the underlying pixman image here so it does
81
// not disappear from under our feet; the switchSurface method will
82
@@ -XXX,XX +XXX,XX @@ static void cocoa_switch(DisplayChangeListener *dcl,
83
pixman_image_ref(image);
84
85
dispatch_async(dispatch_get_main_queue(), ^{
86
+ [cocoaView updateUIInfo];
87
[cocoaView switchSurface:image];
88
});
89
[pool release];
90
--
43
--
91
2.25.1
44
2.20.1
45
46
diff view generated by jsdifflib