1
A random mix of items here, nothing very major.
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
thanks
5
thanks
4
-- PMM
6
-- PMM
5
7
8
The following changes since commit b3f846c59d8405bb87c551187721fc92ff2f1b92:
6
9
7
The following changes since commit d0dff238a87fa81393ed72754d4dc8b09e50b08b:
10
Merge remote-tracking branch 'remotes/huth-gitlab/tags/pull-request-2021-01-11v2' into staging (2021-01-11 15:15:35 +0000)
8
11
9
Merge remote-tracking branch 'remotes/juanquintela/tags/migration/20170206' into staging (2017-02-07 15:29:26 +0000)
12
are available in the Git repository at:
10
13
11
are available in the git repository at:
14
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20210112
12
15
13
git://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20170207
16
for you to fetch changes up to 19d131395ccaf503db21dadd8257e6dc9fc1d7de:
14
17
15
for you to fetch changes up to 7727b832886fafbdec7299eb7773dc9071bf4cdd:
18
ui/cocoa: Fix openFile: deprecation on Big Sur (2021-01-12 11:38:37 +0000)
16
17
stellaris: Use the 'unimplemented' device for parts we don't implement (2017-02-07 18:30:00 +0000)
18
19
19
----------------------------------------------------------------
20
----------------------------------------------------------------
20
target-arm:
21
target-arm queue:
21
* new "unimplemented" device for stubbing out devices in a
22
* arm: Support emulation of ARMv8.4-TTST extension
22
system model so accesses can be logged
23
* arm: Update cpu.h ID register field definitions
23
* stellaris: document the SoC memory map
24
* arm: Fix breakage of XScale instruction emulation
24
* arm: create instruction syndromes for AArch32 data aborts
25
* hw/net/lan9118: Fix RX Status FIFO PEEK value
25
* arm: Correctly handle watchpoints for BE32 CPUs
26
* npcm7xx: Add ADC and PWM emulation
26
* Fix Thumb-1 BE32 execution and disassembly
27
* ui/cocoa: Make "open docs" help menu entry work again when binary
27
* arm: Add cfgend parameter for ARM CPU selection
28
is run from the build tree
28
* sd: sdhci: check data length during dma_memory_read
29
* ui/cocoa: Fix openFile: deprecation on Big Sur
29
* aspeed: add a watchdog controller
30
* docs: Add qemu-storage-daemon(1) manpage to meson.build
30
* integratorcp: adding vmstate for save/restore
31
* docs: Build and install all the docs in a single manual
31
32
32
----------------------------------------------------------------
33
----------------------------------------------------------------
33
Cédric Le Goater (2):
34
Hao Wu (6):
34
wdt: Add Aspeed watchdog device model
35
hw/misc: Add clock converter in NPCM7XX CLK module
35
aspeed: add a watchdog controller
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
36
41
37
Julian Brown (4):
42
Leif Lindholm (6):
38
hw/arm/integratorcp: Support specifying features via -cpu
43
target/arm: fix typo in cpu.h ID_AA64PFR1 field name
39
target/arm: Add cfgend parameter for ARM CPU selection.
44
target/arm: make ARMCPU.clidr 64-bit
40
Fix Thumb-1 BE32 execution and disassembly.
45
target/arm: make ARMCPU.ctr 64-bit
41
arm: Correctly handle watchpoints for BE32 CPUs
46
target/arm: add descriptions of CLIDR_EL1, CCSIDR_EL1, CTR_EL0 to cpu.h
42
47
target/arm: add aarch64 ID register fields to cpu.h
43
Pavel Dovgalyuk (1):
48
target/arm: add aarch32 ID register fields to cpu.h
44
integratorcp: adding vmstate for save/restore
45
49
46
Peter Maydell (5):
50
Peter Maydell (5):
47
target/arm: Abstract out pbit/wbit tests in ARM ldr/str decode
51
docs: Add qemu-storage-daemon(1) manpage to meson.build
48
target/arm: A32, T32: Create Instruction Syndromes for Data Aborts
52
docs: Build and install all the docs in a single manual
49
stellaris: Document memory map and which SoC devices are unimplemented
53
target/arm: Don't decode insns in the XScale/iWMMXt space as cp insns
50
hw/misc: New "unimplemented" sysbus device
54
hw/net/lan9118: Fix RX Status FIFO PEEK value
51
stellaris: Use the 'unimplemented' device for parts we don't implement
55
hw/net/lan9118: Add symbolic constants for register offsets
52
56
53
Prasad J Pandit (1):
57
Roman Bolshakov (2):
54
sd: sdhci: check data length during dma_memory_read
58
ui/cocoa: Update path to docs in build tree
59
ui/cocoa: Fix openFile: deprecation on Big Sur
55
60
56
hw/misc/Makefile.objs | 2 +
61
Rémi Denis-Courmont (2):
57
hw/watchdog/Makefile.objs | 1 +
62
target/arm: ARMv8.4-TTST extension
58
include/disas/bfd.h | 7 ++
63
target/arm: enable Small Translation tables in max CPU
59
include/hw/arm/aspeed_soc.h | 2 +
60
include/hw/misc/unimp.h | 39 +++++++
61
include/hw/watchdog/wdt_aspeed.h | 32 ++++++
62
include/qom/cpu.h | 3 +
63
target/arm/arm_ldst.h | 10 +-
64
target/arm/cpu.h | 7 ++
65
target/arm/internals.h | 5 +
66
target/arm/translate.h | 14 +++
67
disas.c | 1 +
68
exec.c | 1 +
69
hw/arm/aspeed_soc.c | 13 +++
70
hw/arm/integratorcp.c | 78 +++++++++++++-
71
hw/arm/stellaris.c | 48 +++++++++
72
hw/misc/unimp.c | 107 +++++++++++++++++++
73
hw/sd/sdhci.c | 2 +-
74
hw/watchdog/wdt_aspeed.c | 225 +++++++++++++++++++++++++++++++++++++++
75
qom/cpu.c | 6 ++
76
target/arm/cpu.c | 39 +++++++
77
target/arm/op_helper.c | 22 ++++
78
target/arm/translate-a64.c | 14 ---
79
target/arm/translate.c | 193 ++++++++++++++++++++++++---------
80
24 files changed, 801 insertions(+), 70 deletions(-)
81
create mode 100644 include/hw/misc/unimp.h
82
create mode 100644 include/hw/watchdog/wdt_aspeed.h
83
create mode 100644 hw/misc/unimp.c
84
create mode 100644 hw/watchdog/wdt_aspeed.c
85
64
65
docs/conf.py | 46 ++-
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
122
diff view generated by jsdifflib
1
From: Julian Brown <julian@codesourcery.com>
1
From: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
2
2
3
In BE32 mode, sub-word size watchpoints can fail to trigger because the
3
This adds for the Small Translation tables extension in AArch64 state.
4
address of the access is adjusted in the opcode helpers before being
5
compared with the watchpoint registers. This patch reverses the address
6
adjustment before performing the comparison with the help of a new CPUClass
7
hook.
8
4
9
This version of the patch augments and tidies up comments a little.
5
Signed-off-by: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
10
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
11
Signed-off-by: Julian Brown <julian@codesourcery.com>
12
Message-id: caaf64ffc72f6ae183015337b7afdbd4b8989cb6.1484929304.git.julian@codesourcery.com
13
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
---
8
---
16
include/qom/cpu.h | 3 +++
9
target/arm/cpu.h | 5 +++++
17
target/arm/internals.h | 5 +++++
10
target/arm/helper.c | 15 +++++++++++++--
18
exec.c | 1 +
11
2 files changed, 18 insertions(+), 2 deletions(-)
19
qom/cpu.c | 6 ++++++
20
target/arm/cpu.c | 3 +++
21
target/arm/op_helper.c | 22 ++++++++++++++++++++++
22
6 files changed, 40 insertions(+)
23
12
24
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
13
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
25
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
26
--- a/include/qom/cpu.h
15
--- a/target/arm/cpu.h
27
+++ b/include/qom/cpu.h
16
+++ b/target/arm/cpu.h
28
@@ -XXX,XX +XXX,XX @@ struct TranslationBlock;
17
@@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_uao(const ARMISARegisters *id)
29
* @cpu_exec_exit: Callback for cpu_exec cleanup.
18
return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, UAO) != 0;
30
* @cpu_exec_interrupt: Callback for processing interrupts in cpu_exec.
31
* @disas_set_info: Setup architecture specific components of disassembly info
32
+ * @adjust_watchpoint_address: Perform a target-specific adjustment to an
33
+ * address before attempting to match it against watchpoints.
34
*
35
* Represents a CPU family or model.
36
*/
37
@@ -XXX,XX +XXX,XX @@ typedef struct CPUClass {
38
bool (*cpu_exec_interrupt)(CPUState *cpu, int interrupt_request);
39
40
void (*disas_set_info)(CPUState *cpu, disassemble_info *info);
41
+ vaddr (*adjust_watchpoint_address)(CPUState *cpu, vaddr addr, int len);
42
} CPUClass;
43
44
#ifdef HOST_WORDS_BIGENDIAN
45
diff --git a/target/arm/internals.h b/target/arm/internals.h
46
index XXXXXXX..XXXXXXX 100644
47
--- a/target/arm/internals.h
48
+++ b/target/arm/internals.h
49
@@ -XXX,XX +XXX,XX @@ void hw_breakpoint_update_all(ARMCPU *cpu);
50
/* Callback function for checking if a watchpoint should trigger. */
51
bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp);
52
53
+/* Adjust addresses (in BE32 mode) before testing against watchpoint
54
+ * addresses.
55
+ */
56
+vaddr arm_adjust_watchpoint_address(CPUState *cs, vaddr addr, int len);
57
+
58
/* Callback function for when a watchpoint or breakpoint triggers. */
59
void arm_debug_excp_handler(CPUState *cs);
60
61
diff --git a/exec.c b/exec.c
62
index XXXXXXX..XXXXXXX 100644
63
--- a/exec.c
64
+++ b/exec.c
65
@@ -XXX,XX +XXX,XX @@ static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags)
66
return;
67
}
68
vaddr = (cpu->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
69
+ vaddr = cc->adjust_watchpoint_address(cpu, vaddr, len);
70
QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
71
if (cpu_watchpoint_address_matches(wp, vaddr, len)
72
&& (wp->flags & flags)) {
73
diff --git a/qom/cpu.c b/qom/cpu.c
74
index XXXXXXX..XXXXXXX 100644
75
--- a/qom/cpu.c
76
+++ b/qom/cpu.c
77
@@ -XXX,XX +XXX,XX @@ static int64_t cpu_common_get_arch_id(CPUState *cpu)
78
return cpu->cpu_index;
79
}
19
}
80
20
81
+static vaddr cpu_adjust_watchpoint_address(CPUState *cpu, vaddr addr, int len)
21
+static inline bool isar_feature_aa64_st(const ARMISARegisters *id)
82
+{
22
+{
83
+ return addr;
23
+ return FIELD_EX64(id->id_aa64mmfr2, ID_AA64MMFR2, ST) != 0;
84
+}
24
+}
85
+
25
+
86
static void cpu_class_init(ObjectClass *klass, void *data)
26
static inline bool isar_feature_aa64_bti(const ARMISARegisters *id)
87
{
27
{
88
DeviceClass *dc = DEVICE_CLASS(klass);
28
return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, BT) != 0;
89
@@ -XXX,XX +XXX,XX @@ static void cpu_class_init(ObjectClass *klass, void *data)
29
diff --git a/target/arm/helper.c b/target/arm/helper.c
90
k->cpu_exec_enter = cpu_common_noop;
91
k->cpu_exec_exit = cpu_common_noop;
92
k->cpu_exec_interrupt = cpu_common_exec_interrupt;
93
+ k->adjust_watchpoint_address = cpu_adjust_watchpoint_address;
94
set_bit(DEVICE_CATEGORY_CPU, dc->categories);
95
dc->realize = cpu_common_realizefn;
96
dc->unrealize = cpu_common_unrealizefn;
97
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
98
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
99
--- a/target/arm/cpu.c
31
--- a/target/arm/helper.c
100
+++ b/target/arm/cpu.c
32
+++ b/target/arm/helper.c
101
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
33
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
102
cc->gdb_stop_before_watchpoint = true;
34
{
103
cc->debug_excp_handler = arm_debug_excp_handler;
35
uint64_t tcr = regime_tcr(env, mmu_idx)->raw_tcr;
104
cc->debug_check_watchpoint = arm_debug_check_watchpoint;
36
bool epd, hpd, using16k, using64k;
105
+#if !defined(CONFIG_USER_ONLY)
37
- int select, tsz, tbi;
106
+ cc->adjust_watchpoint_address = arm_adjust_watchpoint_address;
38
+ int select, tsz, tbi, max_tsz;
107
+#endif
39
108
40
if (!regime_has_2_ranges(mmu_idx)) {
109
cc->disas_set_info = arm_disas_set_info;
41
select = 0;
110
}
42
@@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
111
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
43
hpd = extract64(tcr, 42, 1);
112
index XXXXXXX..XXXXXXX 100644
44
}
113
--- a/target/arm/op_helper.c
45
}
114
+++ b/target/arm/op_helper.c
46
- tsz = MIN(tsz, 39); /* TODO: ARMv8.4-TTST */
115
@@ -XXX,XX +XXX,XX @@ bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp)
116
return check_watchpoints(cpu);
117
}
118
119
+vaddr arm_adjust_watchpoint_address(CPUState *cs, vaddr addr, int len)
120
+{
121
+ ARMCPU *cpu = ARM_CPU(cs);
122
+ CPUARMState *env = &cpu->env;
123
+
47
+
124
+ /* In BE32 system mode, target memory is stored byteswapped (on a
48
+ if (cpu_isar_feature(aa64_st, env_archcpu(env))) {
125
+ * little-endian host system), and by the time we reach here (via an
49
+ max_tsz = 48 - using64k;
126
+ * opcode helper) the addresses of subword accesses have been adjusted
50
+ } else {
127
+ * to account for that, which means that watchpoints will not match.
51
+ max_tsz = 39;
128
+ * Undo the adjustment here.
129
+ */
130
+ if (arm_sctlr_b(env)) {
131
+ if (len == 1) {
132
+ addr ^= 3;
133
+ } else if (len == 2) {
134
+ addr ^= 2;
135
+ }
136
+ }
52
+ }
137
+
53
+
138
+ return addr;
54
+ tsz = MIN(tsz, max_tsz);
139
+}
55
tsz = MAX(tsz, 16); /* TODO: ARMv8.2-LVA */
56
57
/* Present TBI as a composite with TBID. */
58
@@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
59
if (!aarch64 || stride == 9) {
60
/* AArch32 or 4KB pages */
61
startlevel = 2 - sl0;
140
+
62
+
141
void arm_debug_excp_handler(CPUState *cs)
63
+ if (cpu_isar_feature(aa64_st, cpu)) {
142
{
64
+ startlevel &= 3;
143
/* Called by core code when a watchpoint or breakpoint fires;
65
+ }
66
} else {
67
/* 16KB or 64KB pages */
68
startlevel = 3 - sl0;
144
--
69
--
145
2.7.4
70
2.20.1
146
71
147
72
diff view generated by jsdifflib
New patch
1
From: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
1
2
3
Signed-off-by: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
4
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
---
7
target/arm/cpu64.c | 1 +
8
1 file changed, 1 insertion(+)
9
10
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/target/arm/cpu64.c
13
+++ b/target/arm/cpu64.c
14
@@ -XXX,XX +XXX,XX @@ static void aarch64_max_initfn(Object *obj)
15
t = cpu->isar.id_aa64mmfr2;
16
t = FIELD_DP64(t, ID_AA64MMFR2, UAO, 1);
17
t = FIELD_DP64(t, ID_AA64MMFR2, CNP, 1); /* TTCNP */
18
+ t = FIELD_DP64(t, ID_AA64MMFR2, ST, 1); /* TTST */
19
cpu->isar.id_aa64mmfr2 = t;
20
21
/* Replicate the same data to the 32-bit id registers. */
22
--
23
2.20.1
24
25
diff view generated by jsdifflib
New patch
1
From: Leif Lindholm <leif@nuviainc.com>
1
2
3
SBSS -> SSBS
4
5
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
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>
11
---
12
target/arm/cpu.h | 2 +-
13
1 file changed, 1 insertion(+), 1 deletion(-)
14
15
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
16
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/cpu.h
18
+++ b/target/arm/cpu.h
19
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64PFR0, RAS, 28, 4)
20
FIELD(ID_AA64PFR0, SVE, 32, 4)
21
22
FIELD(ID_AA64PFR1, BT, 0, 4)
23
-FIELD(ID_AA64PFR1, SBSS, 4, 4)
24
+FIELD(ID_AA64PFR1, SSBS, 4, 4)
25
FIELD(ID_AA64PFR1, MTE, 8, 4)
26
FIELD(ID_AA64PFR1, RAS_FRAC, 12, 4)
27
28
--
29
2.20.1
30
31
diff view generated by jsdifflib
New patch
1
From: Leif Lindholm <leif@nuviainc.com>
1
2
3
The AArch64 view of CLIDR_EL1 extends the ICB field to include also bit
4
32, as well as adding a Ttype<n> field when FEAT_MTE is implemented.
5
Extend the clidr field to be able to hold this context.
6
7
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
11
Message-id: 20210108185154.8108-3-leif@nuviainc.com
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
14
target/arm/cpu.h | 2 +-
15
1 file changed, 1 insertion(+), 1 deletion(-)
16
17
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
18
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/cpu.h
20
+++ b/target/arm/cpu.h
21
@@ -XXX,XX +XXX,XX @@ struct ARMCPU {
22
uint32_t id_afr0;
23
uint64_t id_aa64afr0;
24
uint64_t id_aa64afr1;
25
- uint32_t clidr;
26
+ uint64_t clidr;
27
uint64_t mp_affinity; /* MP ID without feature bits */
28
/* The elements of this array are the CCSIDR values for each cache,
29
* in the order L1DCache, L1ICache, L2DCache, L2ICache, etc.
30
--
31
2.20.1
32
33
diff view generated by jsdifflib
1
From: Julian Brown <julian@codesourcery.com>
1
From: Leif Lindholm <leif@nuviainc.com>
2
2
3
Add a new "cfgend" property which selects whether the CPU resets into
3
When FEAT_MTE is implemented, the AArch64 view of CTR_EL0 adds the
4
big-endian mode or not. This setting affects whether we reset with
4
TminLine field in bits [37:32].
5
SCTLR_B (ARMv6 and earlier) or SCTLR_EE (ARMv7 and later) set.
5
Extend the ctr field to be able to hold this context.
6
6
7
Signed-off-by: Julian Brown <julian@codesourcery.com>
7
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
8
Message-id: 11420d1c49636c1790e60578ee996e51f0f0b835.1484929304.git.julian@codesourcery.com
8
Reviewed-by: Hao Wu <wuhaotsh@google.com>
9
[PMM: use error_report_err() rather than error_report();
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
move the integratorcp changes to their own patch;
10
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
11
drop an unnecessary extra #include;
11
Message-id: 20210108185154.8108-4-leif@nuviainc.com
12
rephrase commit message accordingly;
13
move setting of reset_sctlr above registration of cpregs
14
so it actually has an effect]
15
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
17
---
13
---
18
target/arm/cpu.h | 7 +++++++
14
target/arm/cpu.h | 2 +-
19
target/arm/cpu.c | 13 +++++++++++++
15
1 file changed, 1 insertion(+), 1 deletion(-)
20
2 files changed, 20 insertions(+)
21
16
22
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
17
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
23
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
24
--- a/target/arm/cpu.h
19
--- a/target/arm/cpu.h
25
+++ b/target/arm/cpu.h
20
+++ b/target/arm/cpu.h
26
@@ -XXX,XX +XXX,XX @@ struct ARMCPU {
21
@@ -XXX,XX +XXX,XX @@ struct ARMCPU {
27
int gic_vpribits; /* number of virtual priority bits */
22
uint64_t midr;
28
int gic_vprebits; /* number of virtual preemption bits */
23
uint32_t revidr;
29
24
uint32_t reset_fpsid;
30
+ /* Whether the cfgend input is high (i.e. this CPU should reset into
25
- uint32_t ctr;
31
+ * big-endian mode). This setting isn't used directly: instead it modifies
26
+ uint64_t ctr;
32
+ * the reset_sctlr value to have SCTLR_B or SCTLR_EE set, depending on the
27
uint32_t reset_sctlr;
33
+ * architecture version.
28
uint64_t pmceid0;
34
+ */
29
uint64_t pmceid1;
35
+ bool cfgend;
36
+
37
ARMELChangeHook *el_change_hook;
38
void *el_change_hook_opaque;
39
};
40
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
41
index XXXXXXX..XXXXXXX 100644
42
--- a/target/arm/cpu.c
43
+++ b/target/arm/cpu.c
44
@@ -XXX,XX +XXX,XX @@ static Property arm_cpu_has_el2_property =
45
static Property arm_cpu_has_el3_property =
46
DEFINE_PROP_BOOL("has_el3", ARMCPU, has_el3, true);
47
48
+static Property arm_cpu_cfgend_property =
49
+ DEFINE_PROP_BOOL("cfgend", ARMCPU, cfgend, false);
50
+
51
/* use property name "pmu" to match other archs and virt tools */
52
static Property arm_cpu_has_pmu_property =
53
DEFINE_PROP_BOOL("pmu", ARMCPU, has_pmu, true);
54
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_post_init(Object *obj)
55
}
56
}
57
58
+ qdev_property_add_static(DEVICE(obj), &arm_cpu_cfgend_property,
59
+ &error_abort);
60
}
61
62
static void arm_cpu_finalizefn(Object *obj)
63
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
64
cpu->reset_sctlr |= (1 << 13);
65
}
66
67
+ if (cpu->cfgend) {
68
+ if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
69
+ cpu->reset_sctlr |= SCTLR_EE;
70
+ } else {
71
+ cpu->reset_sctlr |= SCTLR_B;
72
+ }
73
+ }
74
+
75
if (!cpu->has_el3) {
76
/* If the has_el3 CPU property is disabled then we need to disable the
77
* feature.
78
--
30
--
79
2.7.4
31
2.20.1
80
32
81
33
diff view generated by jsdifflib
New patch
1
From: Leif Lindholm <leif@nuviainc.com>
1
2
3
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
4
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
5
Message-id: 20210108185154.8108-5-leif@nuviainc.com
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
---
8
target/arm/cpu.h | 31 +++++++++++++++++++++++++++++++
9
1 file changed, 31 insertions(+)
10
11
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
12
index XXXXXXX..XXXXXXX 100644
13
--- a/target/arm/cpu.h
14
+++ b/target/arm/cpu.h
15
@@ -XXX,XX +XXX,XX @@ FIELD(V7M_FPCCR, ASPEN, 31, 1)
16
/*
17
* System register ID fields.
18
*/
19
+FIELD(CLIDR_EL1, CTYPE1, 0, 3)
20
+FIELD(CLIDR_EL1, CTYPE2, 3, 3)
21
+FIELD(CLIDR_EL1, CTYPE3, 6, 3)
22
+FIELD(CLIDR_EL1, CTYPE4, 9, 3)
23
+FIELD(CLIDR_EL1, CTYPE5, 12, 3)
24
+FIELD(CLIDR_EL1, CTYPE6, 15, 3)
25
+FIELD(CLIDR_EL1, CTYPE7, 18, 3)
26
+FIELD(CLIDR_EL1, LOUIS, 21, 3)
27
+FIELD(CLIDR_EL1, LOC, 24, 3)
28
+FIELD(CLIDR_EL1, LOUU, 27, 3)
29
+FIELD(CLIDR_EL1, ICB, 30, 3)
30
+
31
+/* When FEAT_CCIDX is implemented */
32
+FIELD(CCSIDR_EL1, CCIDX_LINESIZE, 0, 3)
33
+FIELD(CCSIDR_EL1, CCIDX_ASSOCIATIVITY, 3, 21)
34
+FIELD(CCSIDR_EL1, CCIDX_NUMSETS, 32, 24)
35
+
36
+/* When FEAT_CCIDX is not implemented */
37
+FIELD(CCSIDR_EL1, LINESIZE, 0, 3)
38
+FIELD(CCSIDR_EL1, ASSOCIATIVITY, 3, 10)
39
+FIELD(CCSIDR_EL1, NUMSETS, 13, 15)
40
+
41
+FIELD(CTR_EL0, IMINLINE, 0, 4)
42
+FIELD(CTR_EL0, L1IP, 14, 2)
43
+FIELD(CTR_EL0, DMINLINE, 16, 4)
44
+FIELD(CTR_EL0, ERG, 20, 4)
45
+FIELD(CTR_EL0, CWG, 24, 4)
46
+FIELD(CTR_EL0, IDC, 28, 1)
47
+FIELD(CTR_EL0, DIC, 29, 1)
48
+FIELD(CTR_EL0, TMINLINE, 32, 6)
49
+
50
FIELD(MIDR_EL1, REVISION, 0, 4)
51
FIELD(MIDR_EL1, PARTNUM, 4, 12)
52
FIELD(MIDR_EL1, ARCHITECTURE, 16, 4)
53
--
54
2.20.1
55
56
diff view generated by jsdifflib
New patch
1
From: Leif Lindholm <leif@nuviainc.com>
1
2
3
Add entries present in ARM DDI 0487F.c (August 2020).
4
5
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
8
Message-id: 20210108185154.8108-6-leif@nuviainc.com
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
target/arm/cpu.h | 15 +++++++++++++++
12
1 file changed, 15 insertions(+)
13
14
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
15
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/cpu.h
17
+++ b/target/arm/cpu.h
18
@@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64ISAR1, GPI, 28, 4)
19
FIELD(ID_AA64ISAR1, FRINTTS, 32, 4)
20
FIELD(ID_AA64ISAR1, SB, 36, 4)
21
FIELD(ID_AA64ISAR1, SPECRES, 40, 4)
22
+FIELD(ID_AA64ISAR1, BF16, 44, 4)
23
+FIELD(ID_AA64ISAR1, DGH, 48, 4)
24
+FIELD(ID_AA64ISAR1, I8MM, 52, 4)
25
26
FIELD(ID_AA64PFR0, EL0, 0, 4)
27
FIELD(ID_AA64PFR0, EL1, 4, 4)
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)
73
--
74
2.20.1
75
76
diff view generated by jsdifflib
New patch
1
From: Leif Lindholm <leif@nuviainc.com>
1
2
3
Add entries present in ARM DDI 0487F.c (August 2020).
4
5
Signed-off-by: Leif Lindholm <leif@nuviainc.com>
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Laurent Desnogues <laurent.desnogues@gmail.com>
8
Message-id: 20210108185154.8108-7-leif@nuviainc.com
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
---
11
target/arm/cpu.h | 28 ++++++++++++++++++++++++++++
12
1 file changed, 28 insertions(+)
13
14
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
15
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/cpu.h
17
+++ b/target/arm/cpu.h
18
@@ -XXX,XX +XXX,XX @@ FIELD(ID_ISAR6, DP, 4, 4)
19
FIELD(ID_ISAR6, FHM, 8, 4)
20
FIELD(ID_ISAR6, SB, 12, 4)
21
FIELD(ID_ISAR6, SPECRES, 16, 4)
22
+FIELD(ID_ISAR6, BF16, 20, 4)
23
+FIELD(ID_ISAR6, I8MM, 24, 4)
24
25
FIELD(ID_MMFR0, VMSA, 0, 4)
26
FIELD(ID_MMFR0, PMSA, 4, 4)
27
@@ -XXX,XX +XXX,XX @@ FIELD(ID_MMFR0, AUXREG, 20, 4)
28
FIELD(ID_MMFR0, FCSE, 24, 4)
29
FIELD(ID_MMFR0, INNERSHR, 28, 4)
30
31
+FIELD(ID_MMFR1, L1HVDVA, 0, 4)
32
+FIELD(ID_MMFR1, L1UNIVA, 4, 4)
33
+FIELD(ID_MMFR1, L1HVDSW, 8, 4)
34
+FIELD(ID_MMFR1, L1UNISW, 12, 4)
35
+FIELD(ID_MMFR1, L1HVD, 16, 4)
36
+FIELD(ID_MMFR1, L1UNI, 20, 4)
37
+FIELD(ID_MMFR1, L1TSTCLN, 24, 4)
38
+FIELD(ID_MMFR1, BPRED, 28, 4)
39
+
40
+FIELD(ID_MMFR2, L1HVDFG, 0, 4)
41
+FIELD(ID_MMFR2, L1HVDBG, 4, 4)
42
+FIELD(ID_MMFR2, L1HVDRNG, 8, 4)
43
+FIELD(ID_MMFR2, HVDTLB, 12, 4)
44
+FIELD(ID_MMFR2, UNITLB, 16, 4)
45
+FIELD(ID_MMFR2, MEMBARR, 20, 4)
46
+FIELD(ID_MMFR2, WFISTALL, 24, 4)
47
+FIELD(ID_MMFR2, HWACCFLG, 28, 4)
48
+
49
FIELD(ID_MMFR3, CMAINTVA, 0, 4)
50
FIELD(ID_MMFR3, CMAINTSW, 4, 4)
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)
81
--
82
2.20.1
83
84
diff view generated by jsdifflib
1
From: Julian Brown <julian@codesourcery.com>
1
From: Roman Bolshakov <r.bolshakov@yadro.com>
2
2
3
Thumb-1 code has some issues in BE32 mode (as currently implemented). In
3
QEMU documentation can't be opened if QEMU is run from build tree
4
short, since bytes are swapped within words at load time for BE32
4
because executables are placed in the top of build tree after conversion
5
executables, this also swaps pairs of adjacent Thumb-1 instructions.
5
to meson.
6
6
7
This patch un-swaps those pairs of instructions again, both for execution,
7
Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
8
and for disassembly. (The previous version of the patch always read four
8
Reported-by: Peter Maydell <peter.maydell@linaro.org>
9
bytes in arm_read_memory_func and then extracted the proper two bytes,
9
Message-id: 20210108213815.64678-1-r.bolshakov@yadro.com
10
in a probably misguided attempt to match the behaviour of actual hardware
11
as described by e.g. the ARM9TDMI TRM, section 3.3 "Endian effects for
12
instruction fetches". It's less complicated to just read the correct
13
two bytes though.)
14
15
Signed-off-by: Julian Brown <julian@codesourcery.com>
16
Message-id: ca20462a044848000370318a8bd41dd0a4ed273f.1484929304.git.julian@codesourcery.com
17
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
18
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
19
---
12
---
20
include/disas/bfd.h | 7 +++++++
13
ui/cocoa.m | 2 +-
21
target/arm/arm_ldst.h | 10 +++++++++-
14
1 file changed, 1 insertion(+), 1 deletion(-)
22
disas.c | 1 +
23
target/arm/cpu.c | 23 +++++++++++++++++++++++
24
4 files changed, 40 insertions(+), 1 deletion(-)
25
15
26
diff --git a/include/disas/bfd.h b/include/disas/bfd.h
16
diff --git a/ui/cocoa.m b/ui/cocoa.m
27
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
28
--- a/include/disas/bfd.h
18
--- a/ui/cocoa.m
29
+++ b/include/disas/bfd.h
19
+++ b/ui/cocoa.m
30
@@ -XXX,XX +XXX,XX @@ typedef struct disassemble_info {
20
@@ -XXX,XX +XXX,XX @@ QemuCocoaView *cocoaView;
31
The bottom 16 bits are for the internal use of the disassembler. */
21
- (void) openDocumentation: (NSString *) filename
32
unsigned long flags;
33
#define INSN_HAS_RELOC    0x80000000
34
+#define INSN_ARM_BE32    0x00010000
35
PTR private_data;
36
37
/* Function used to get bytes to disassemble. MEMADDR is the
38
@@ -XXX,XX +XXX,XX @@ typedef struct disassemble_info {
39
(bfd_vma memaddr, bfd_byte *myaddr, int length,
40
     struct disassemble_info *info);
41
42
+ /* A place to stash the real read_memory_func if read_memory_func wants to
43
+ do some funky address arithmetic or similar (e.g. for ARM BE32 mode). */
44
+ int (*read_memory_inner_func)
45
+ (bfd_vma memaddr, bfd_byte *myaddr, int length,
46
+ struct disassemble_info *info);
47
+
48
/* Function which should be called if we get an error that we can't
49
recover from. STATUS is the errno value from read_memory_func and
50
MEMADDR is the address that we were trying to read. INFO is a
51
diff --git a/target/arm/arm_ldst.h b/target/arm/arm_ldst.h
52
index XXXXXXX..XXXXXXX 100644
53
--- a/target/arm/arm_ldst.h
54
+++ b/target/arm/arm_ldst.h
55
@@ -XXX,XX +XXX,XX @@ static inline uint32_t arm_ldl_code(CPUARMState *env, target_ulong addr,
56
static inline uint16_t arm_lduw_code(CPUARMState *env, target_ulong addr,
57
bool sctlr_b)
58
{
22
{
59
- uint16_t insn = cpu_lduw_code(env, addr);
23
/* Where to look for local files */
60
+ uint16_t insn;
24
- NSString *path_array[] = {@"../share/doc/qemu/", @"../doc/qemu/", @"../docs/"};
61
+#ifndef CONFIG_USER_ONLY
25
+ NSString *path_array[] = {@"../share/doc/qemu/", @"../doc/qemu/", @"docs/"};
62
+ /* In big-endian (BE32) mode, adjacent Thumb instructions have been swapped
26
NSString *full_file_path;
63
+ within each word. Undo that now. */
27
64
+ if (sctlr_b) {
28
/* iterate thru the possible paths until the file is found */
65
+ addr ^= 2;
66
+ }
67
+#endif
68
+ insn = cpu_lduw_code(env, addr);
69
if (bswap_code(sctlr_b)) {
70
return bswap16(insn);
71
}
72
diff --git a/disas.c b/disas.c
73
index XXXXXXX..XXXXXXX 100644
74
--- a/disas.c
75
+++ b/disas.c
76
@@ -XXX,XX +XXX,XX @@ void target_disas(FILE *out, CPUState *cpu, target_ulong code,
77
78
s.cpu = cpu;
79
s.info.read_memory_func = target_read_memory;
80
+ s.info.read_memory_inner_func = NULL;
81
s.info.buffer_vma = code;
82
s.info.buffer_length = size;
83
s.info.print_address_func = generic_print_address;
84
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
85
index XXXXXXX..XXXXXXX 100644
86
--- a/target/arm/cpu.c
87
+++ b/target/arm/cpu.c
88
@@ -XXX,XX +XXX,XX @@ print_insn_thumb1(bfd_vma pc, disassemble_info *info)
89
return print_insn_arm(pc | 1, info);
90
}
91
92
+static int arm_read_memory_func(bfd_vma memaddr, bfd_byte *b,
93
+ int length, struct disassemble_info *info)
94
+{
95
+ assert(info->read_memory_inner_func);
96
+ assert((info->flags & INSN_ARM_BE32) == 0 || length == 2 || length == 4);
97
+
98
+ if ((info->flags & INSN_ARM_BE32) != 0 && length == 2) {
99
+ assert(info->endian == BFD_ENDIAN_LITTLE);
100
+ return info->read_memory_inner_func(memaddr ^ 2, (bfd_byte *)b, 2,
101
+ info);
102
+ } else {
103
+ return info->read_memory_inner_func(memaddr, b, length, info);
104
+ }
105
+}
106
+
107
static void arm_disas_set_info(CPUState *cpu, disassemble_info *info)
108
{
109
ARMCPU *ac = ARM_CPU(cpu);
110
@@ -XXX,XX +XXX,XX @@ static void arm_disas_set_info(CPUState *cpu, disassemble_info *info)
111
info->endian = BFD_ENDIAN_BIG;
112
#endif
113
}
114
+ if (info->read_memory_inner_func == NULL) {
115
+ info->read_memory_inner_func = info->read_memory_func;
116
+ info->read_memory_func = arm_read_memory_func;
117
+ }
118
+ info->flags &= ~INSN_ARM_BE32;
119
+ if (arm_sctlr_b(env)) {
120
+ info->flags |= INSN_ARM_BE32;
121
+ }
122
}
123
124
static void arm_cpu_initfn(Object *obj)
125
--
29
--
126
2.7.4
30
2.20.1
127
31
128
32
diff view generated by jsdifflib
New patch
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.
1
5
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(+)
13
14
diff --git a/docs/meson.build b/docs/meson.build
15
index XXXXXXX..XXXXXXX 100644
16
--- a/docs/meson.build
17
+++ b/docs/meson.build
18
@@ -XXX,XX +XXX,XX @@ if build_docs
19
'qemu-img.1': (have_tools ? 'man1' : ''),
20
'qemu-nbd.8': (have_tools ? 'man8' : ''),
21
'qemu-pr-helper.8': (have_tools ? 'man8' : ''),
22
+ 'qemu-storage-daemon.1': (have_tools ? 'man1' : ''),
23
'qemu-trace-stap.1': (config_host.has_key('CONFIG_TRACE_SYSTEMTAP') ? 'man1' : ''),
24
'virtfs-proxy-helper.1': (have_virtfs_proxy_helper ? 'man1' : ''),
25
'virtiofsd.1': (have_virtiofsd ? 'man1' : ''),
26
--
27
2.20.1
28
29
diff view generated by jsdifflib
New patch
1
1
When we first converted our documentation to Sphinx, we split it into
2
multiple manuals (system, interop, tools, etc), which are all built
3
separately. The primary driver for this was wanting to be able to
4
avoid shipping the 'devel' manual to end-users. However, this is
5
working against the grain of the way Sphinx wants to be used and
6
causes some annoyances:
7
* Cross-references between documents become much harder or
8
possibly impossible
9
* There is no single index to the whole documentation
10
* Within one manual there's no links or table-of-contents info
11
that lets you easily navigate to the others
12
* The devel manual doesn't get published on the QEMU website
13
(it would be nice to able to refer to it there)
14
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.
36
37
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
38
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
39
Message-id: 20210108161416.21129-3-peter.maydell@linaro.org
40
---
41
docs/conf.py | 46 ++++++++++++++++++++++++++++++-
42
docs/devel/conf.py | 15 -----------
43
docs/index.html.in | 17 ------------
44
docs/interop/conf.py | 28 -------------------
45
docs/meson.build | 64 +++++++++++++++++---------------------------
46
docs/specs/conf.py | 16 -----------
47
docs/system/conf.py | 28 -------------------
48
docs/tools/conf.py | 37 -------------------------
49
docs/user/conf.py | 15 -----------
50
9 files changed, 70 insertions(+), 196 deletions(-)
51
delete mode 100644 docs/devel/conf.py
52
delete mode 100644 docs/index.html.in
53
delete mode 100644 docs/interop/conf.py
54
delete mode 100644 docs/specs/conf.py
55
delete mode 100644 docs/system/conf.py
56
delete mode 100644 docs/tools/conf.py
57
delete mode 100644 docs/user/conf.py
58
59
diff --git a/docs/conf.py b/docs/conf.py
60
index XXXXXXX..XXXXXXX 100644
61
--- a/docs/conf.py
62
+++ b/docs/conf.py
63
@@ -XXX,XX +XXX,XX @@ latex_documents = [
64
65
# -- Options for manual page output ---------------------------------------
66
# Individual manual/conf.py can override this to create man pages
67
-man_pages = []
68
+man_pages = [
69
+ ('interop/qemu-ga', 'qemu-ga',
70
+ 'QEMU Guest Agent',
71
+ ['Michael Roth <mdroth@linux.vnet.ibm.com>'], 8),
72
+ ('interop/qemu-ga-ref', 'qemu-ga-ref',
73
+ 'QEMU Guest Agent Protocol Reference',
74
+ [], 7),
75
+ ('interop/qemu-qmp-ref', 'qemu-qmp-ref',
76
+ 'QEMU QMP Reference Manual',
77
+ [], 7),
78
+ ('interop/qemu-storage-daemon-qmp-ref', 'qemu-storage-daemon-qmp-ref',
79
+ 'QEMU Storage Daemon QMP Reference Manual',
80
+ [], 7),
81
+ ('system/qemu-manpage', 'qemu',
82
+ 'QEMU User Documentation',
83
+ ['Fabrice Bellard'], 1),
84
+ ('system/qemu-block-drivers', 'qemu-block-drivers',
85
+ 'QEMU block drivers reference',
86
+ ['Fabrice Bellard and the QEMU Project developers'], 7),
87
+ ('system/qemu-cpu-models', 'qemu-cpu-models',
88
+ 'QEMU CPU Models',
89
+ ['The QEMU Project developers'], 7),
90
+ ('tools/qemu-img', 'qemu-img',
91
+ 'QEMU disk image utility',
92
+ ['Fabrice Bellard'], 1),
93
+ ('tools/qemu-nbd', 'qemu-nbd',
94
+ 'QEMU Disk Network Block Device Server',
95
+ ['Anthony Liguori <anthony@codemonkey.ws>'], 8),
96
+ ('tools/qemu-pr-helper', 'qemu-pr-helper',
97
+ 'QEMU persistent reservation helper',
98
+ [], 8),
99
+ ('tools/qemu-storage-daemon', 'qemu-storage-daemon',
100
+ 'QEMU storage daemon',
101
+ [], 1),
102
+ ('tools/qemu-trace-stap', 'qemu-trace-stap',
103
+ 'QEMU SystemTap trace tool',
104
+ [], 1),
105
+ ('tools/virtfs-proxy-helper', 'virtfs-proxy-helper',
106
+ 'QEMU 9p virtfs proxy filesystem helper',
107
+ ['M. Mohan Kumar'], 1),
108
+ ('tools/virtiofsd', 'virtiofsd',
109
+ 'QEMU virtio-fs shared file system daemon',
110
+ ['Stefan Hajnoczi <stefanha@redhat.com>',
111
+ 'Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>'], 1),
112
+]
113
114
# -- Options for Texinfo output -------------------------------------------
115
116
diff --git a/docs/devel/conf.py b/docs/devel/conf.py
117
deleted file mode 100644
118
index XXXXXXX..XXXXXXX
119
--- a/docs/devel/conf.py
120
+++ /dev/null
121
@@ -XXX,XX +XXX,XX @@
122
-# -*- coding: utf-8 -*-
123
-#
124
-# QEMU documentation build configuration file for the 'devel' manual.
125
-#
126
-# This includes the top level conf file and then makes any necessary tweaks.
127
-import sys
128
-import os
129
-
130
-qemu_docdir = os.path.abspath("..")
131
-parent_config = os.path.join(qemu_docdir, "conf.py")
132
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
133
-
134
-# This slightly misuses the 'description', but is the best way to get
135
-# the manual title to appear in the sidebar.
136
-html_theme_options['description'] = u'Developer''s Guide'
137
diff --git a/docs/index.html.in b/docs/index.html.in
138
deleted file mode 100644
139
index XXXXXXX..XXXXXXX
140
--- a/docs/index.html.in
141
+++ /dev/null
142
@@ -XXX,XX +XXX,XX @@
143
-<!DOCTYPE html>
144
-<html lang="en">
145
- <head>
146
- <meta charset="UTF-8">
147
- <title>QEMU @VERSION@ Documentation</title>
148
- </head>
149
- <body>
150
- <h1>QEMU @VERSION@ Documentation</h1>
151
- <ul>
152
- <li><a href="system/index.html">System Emulation User's Guide</a></li>
153
- <li><a href="user/index.html">User Mode Emulation User's Guide</a></li>
154
- <li><a href="tools/index.html">Tools Guide</a></li>
155
- <li><a href="interop/index.html">System Emulation Management and Interoperability Guide</a></li>
156
- <li><a href="specs/index.html">System Emulation Guest Hardware Specifications</a></li>
157
- </ul>
158
- </body>
159
-</html>
160
diff --git a/docs/interop/conf.py b/docs/interop/conf.py
161
deleted file mode 100644
162
index XXXXXXX..XXXXXXX
163
--- a/docs/interop/conf.py
164
+++ /dev/null
165
@@ -XXX,XX +XXX,XX @@
166
-# -*- coding: utf-8 -*-
167
-#
168
-# QEMU documentation build configuration file for the 'interop' manual.
169
-#
170
-# This includes the top level conf file and then makes any necessary tweaks.
171
-import sys
172
-import os
173
-
174
-qemu_docdir = os.path.abspath("..")
175
-parent_config = os.path.join(qemu_docdir, "conf.py")
176
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
177
-
178
-# This slightly misuses the 'description', but is the best way to get
179
-# the manual title to appear in the sidebar.
180
-html_theme_options['description'] = u'System Emulation Management and Interoperability Guide'
181
-
182
-# One entry per manual page. List of tuples
183
-# (source start file, name, description, authors, manual section).
184
-man_pages = [
185
- ('qemu-ga', 'qemu-ga', u'QEMU Guest Agent',
186
- ['Michael Roth <mdroth@linux.vnet.ibm.com>'], 8),
187
- ('qemu-ga-ref', 'qemu-ga-ref', 'QEMU Guest Agent Protocol Reference',
188
- [], 7),
189
- ('qemu-qmp-ref', 'qemu-qmp-ref', 'QEMU QMP Reference Manual',
190
- [], 7),
191
- ('qemu-storage-daemon-qmp-ref', 'qemu-storage-daemon-qmp-ref',
192
- 'QEMU Storage Daemon QMP Reference Manual', [], 7),
193
-]
194
diff --git a/docs/meson.build b/docs/meson.build
195
index XXXXXXX..XXXXXXX 100644
196
--- a/docs/meson.build
197
+++ b/docs/meson.build
198
@@ -XXX,XX +XXX,XX @@ if build_docs
199
meson.source_root() / 'docs/sphinx/qmp_lexer.py',
200
qapi_gen_depends ]
201
202
- configure_file(output: 'index.html',
203
- input: files('index.html.in'),
204
- configuration: {'VERSION': meson.project_version()},
205
- install_dir: qemu_docdir)
206
- manuals = [ 'devel', 'interop', 'tools', 'specs', 'system', 'user' ]
207
man_pages = {
208
- 'interop' : {
209
'qemu-ga.8': (have_tools ? 'man8' : ''),
210
'qemu-ga-ref.7': 'man7',
211
'qemu-qmp-ref.7': 'man7',
212
'qemu-storage-daemon-qmp-ref.7': (have_tools ? 'man7' : ''),
213
- },
214
- 'tools': {
215
'qemu-img.1': (have_tools ? 'man1' : ''),
216
'qemu-nbd.8': (have_tools ? 'man8' : ''),
217
'qemu-pr-helper.8': (have_tools ? 'man8' : ''),
218
@@ -XXX,XX +XXX,XX @@ if build_docs
219
'qemu-trace-stap.1': (config_host.has_key('CONFIG_TRACE_SYSTEMTAP') ? 'man1' : ''),
220
'virtfs-proxy-helper.1': (have_virtfs_proxy_helper ? 'man1' : ''),
221
'virtiofsd.1': (have_virtiofsd ? 'man1' : ''),
222
- },
223
- 'system': {
224
'qemu.1': 'man1',
225
'qemu-block-drivers.7': 'man7',
226
'qemu-cpu-models.7': 'man7'
227
- },
228
}
229
230
sphinxdocs = []
231
sphinxmans = []
232
- foreach manual : manuals
233
- private_dir = meson.current_build_dir() / (manual + '.p')
234
- output_dir = meson.current_build_dir() / manual
235
- input_dir = meson.current_source_dir() / manual
236
237
- this_manual = custom_target(manual + ' manual',
238
+ private_dir = meson.current_build_dir() / 'manual.p'
239
+ output_dir = meson.current_build_dir() / 'manual'
240
+ input_dir = meson.current_source_dir()
241
+
242
+ this_manual = custom_target('QEMU manual',
243
build_by_default: build_docs,
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'
417
--
418
2.20.1
419
420
diff view generated by jsdifflib
1
In the ARM ldr/str decode path, rather than directly testing
1
In commit cd8be50e58f63413c0 we converted the A32 coprocessor
2
"insn & (1 << 21)" and "insn & (1 << 24)", abstract these
2
insns to decodetree. This accidentally broke XScale/iWMMXt insns,
3
bits out into wbit and pbit local flags. (We will want to
3
because it moved the handling of "cp insns which are handled
4
do more tests against them to determine whether we need to
4
by looking up the cp register in the hashtable" from after the
5
provide syndrome information.)
5
call to the legacy disas_xscale_insn() decode to before it,
6
with the result that all XScale/iWMMXt insns now UNDEF.
6
7
8
Update valid_cp() so that it knows that on XScale cp 0 and 1
9
are not standard coprocessor instructions; this will cause
10
the decodetree trans_ functions to ignore them, so that
11
execution will correctly get through to the legacy decode again.
12
13
Cc: qemu-stable@nongnu.org
14
Reported-by: Guenter Roeck <linux@roeck-us.net>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
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
9
---
19
---
10
target/arm/translate.c | 9 ++++++---
20
target/arm/translate.c | 7 +++++++
11
1 file changed, 6 insertions(+), 3 deletions(-)
21
1 file changed, 7 insertions(+)
12
22
13
diff --git a/target/arm/translate.c b/target/arm/translate.c
23
diff --git a/target/arm/translate.c b/target/arm/translate.c
14
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/translate.c
25
--- a/target/arm/translate.c
16
+++ b/target/arm/translate.c
26
+++ b/target/arm/translate.c
17
@@ -XXX,XX +XXX,XX @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
27
@@ -XXX,XX +XXX,XX @@ static bool valid_cp(DisasContext *s, int cp)
18
} else {
28
* only cp14 and cp15 are valid, and other values aren't considered
19
int address_offset;
29
* to be in the coprocessor-instruction space at all. v8M still
20
bool load = insn & (1 << 20);
30
* permits coprocessors 0..7.
21
+ bool wbit = insn & (1 << 21);
31
+ * For XScale, we must not decode the XScale cp0, cp1 space as
22
+ bool pbit = insn & (1 << 24);
32
+ * a standard coprocessor insn, because we want to fall through to
23
bool doubleword = false;
33
+ * the legacy disas_xscale_insn() decoder after decodetree is done.
24
/* Misc load/store */
34
*/
25
rn = (insn >> 16) & 0xf;
35
+ if (arm_dc_feature(s, ARM_FEATURE_XSCALE) && (cp == 0 || cp == 1)) {
26
@@ -XXX,XX +XXX,XX @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
36
+ return false;
27
}
37
+ }
28
38
+
29
addr = load_reg(s, rn);
39
if (arm_dc_feature(s, ARM_FEATURE_V8) &&
30
- if (insn & (1 << 24))
40
!arm_dc_feature(s, ARM_FEATURE_M)) {
31
+ if (pbit) {
41
return cp >= 14;
32
gen_add_datah_offset(s, insn, 0, addr);
33
+ }
34
address_offset = 0;
35
36
if (doubleword) {
37
@@ -XXX,XX +XXX,XX @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
38
ensure correct behavior with overlapping index registers.
39
ldrd with base writeback is undefined if the
40
destination and index registers overlap. */
41
- if (!(insn & (1 << 24))) {
42
+ if (!pbit) {
43
gen_add_datah_offset(s, insn, address_offset, addr);
44
store_reg(s, rn, addr);
45
- } else if (insn & (1 << 21)) {
46
+ } else if (wbit) {
47
if (address_offset)
48
tcg_gen_addi_i32(addr, addr, address_offset);
49
store_reg(s, rn, addr);
50
--
42
--
51
2.7.4
43
2.20.1
52
44
53
45
diff view generated by jsdifflib
1
From: Prasad J Pandit <pjp@fedoraproject.org>
1
A copy-and-paste error meant that the return value for register offset 0x44
2
2
(the RX Status FIFO PEEK register) returned a byte from a bogus offset in
3
While doing multi block SDMA transfer in routine
3
the rx status FIFO. Fix the typo.
4
'sdhci_sdma_transfer_multi_blocks', the 's->fifo_buffer' starting
5
index 'begin' and data length 's->data_count' could end up to be same.
6
This could lead to an OOB access issue. Correct transfer data length
7
to avoid it.
8
4
9
Cc: qemu-stable@nongnu.org
5
Cc: qemu-stable@nongnu.org
10
Reported-by: Jiang Xin <jiangxin1@huawei.com>
6
Fixes: https://bugs.launchpad.net/qemu/+bug/1904954
11
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
12
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
13
Message-id: 20170130064736.9236-1-ppandit@redhat.com
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
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
15
---
10
---
16
hw/sd/sdhci.c | 2 +-
11
hw/net/lan9118.c | 2 +-
17
1 file changed, 1 insertion(+), 1 deletion(-)
12
1 file changed, 1 insertion(+), 1 deletion(-)
18
13
19
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
14
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
20
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
21
--- a/hw/sd/sdhci.c
16
--- a/hw/net/lan9118.c
22
+++ b/hw/sd/sdhci.c
17
+++ b/hw/net/lan9118.c
23
@@ -XXX,XX +XXX,XX @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
18
@@ -XXX,XX +XXX,XX @@ static uint64_t lan9118_readl(void *opaque, hwaddr offset,
24
boundary_count -= block_size - begin;
19
case 0x40:
25
}
20
return rx_status_fifo_pop(s);
26
dma_memory_read(&address_space_memory, s->sdmasysad,
21
case 0x44:
27
- &s->fifo_buffer[begin], s->data_count);
22
- return s->rx_status_fifo[s->tx_status_fifo_head];
28
+ &s->fifo_buffer[begin], s->data_count - begin);
23
+ return s->rx_status_fifo[s->rx_status_fifo_head];
29
s->sdmasysad += s->data_count - begin;
24
case 0x48:
30
if (s->data_count == block_size) {
25
return tx_status_fifo_pop(s);
31
for (n = 0; n < block_size; n++) {
26
case 0x4c:
32
--
27
--
33
2.7.4
28
2.20.1
34
29
35
30
diff view generated by jsdifflib
1
Add a comment documenting the memory map of the SoC devices and which
1
The lan9118 code mostly uses symbolic constants for register offsets;
2
are not implemented.
2
the exceptions are those which the datasheet doesn't give an official
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.
3
7
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Message-id: 1484247815-15279-2-git-send-email-peter.maydell@linaro.org
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
Message-id: 20210108180401.2263-3-peter.maydell@linaro.org
6
---
11
---
7
hw/arm/stellaris.c | 34 ++++++++++++++++++++++++++++++++++
12
hw/net/lan9118.c | 24 ++++++++++++++++++------
8
1 file changed, 34 insertions(+)
13
1 file changed, 18 insertions(+), 6 deletions(-)
9
14
10
diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
15
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
11
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
12
--- a/hw/arm/stellaris.c
17
--- a/hw/net/lan9118.c
13
+++ b/hw/arm/stellaris.c
18
+++ b/hw/net/lan9118.c
14
@@ -XXX,XX +XXX,XX @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
19
@@ -XXX,XX +XXX,XX @@ do { hw_error("lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
15
0x40024000, 0x40025000, 0x40026000};
20
do { fprintf(stderr, "lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
16
static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};
21
#endif
17
22
18
+ /* Memory map of SoC devices, from
23
+/* The tx and rx fifo ports are a range of aliased 32-bit registers */
19
+ * Stellaris LM3S6965 Microcontroller Data Sheet (rev I)
24
+#define RX_DATA_FIFO_PORT_FIRST 0x00
20
+ * http://www.ti.com/lit/ds/symlink/lm3s6965.pdf
25
+#define RX_DATA_FIFO_PORT_LAST 0x1f
21
+ *
26
+#define TX_DATA_FIFO_PORT_FIRST 0x20
22
+ * 40000000 wdtimer (unimplemented)
27
+#define TX_DATA_FIFO_PORT_LAST 0x3f
23
+ * 40002000 i2c (unimplemented)
24
+ * 40004000 GPIO
25
+ * 40005000 GPIO
26
+ * 40006000 GPIO
27
+ * 40007000 GPIO
28
+ * 40008000 SSI
29
+ * 4000c000 UART
30
+ * 4000d000 UART
31
+ * 4000e000 UART
32
+ * 40020000 i2c
33
+ * 40021000 i2c (unimplemented)
34
+ * 40024000 GPIO
35
+ * 40025000 GPIO
36
+ * 40026000 GPIO
37
+ * 40028000 PWM (unimplemented)
38
+ * 4002c000 QEI (unimplemented)
39
+ * 4002d000 QEI (unimplemented)
40
+ * 40030000 gptimer
41
+ * 40031000 gptimer
42
+ * 40032000 gptimer
43
+ * 40033000 gptimer
44
+ * 40038000 ADC
45
+ * 4003c000 analogue comparator (unimplemented)
46
+ * 40048000 ethernet
47
+ * 400fc000 hibernation module (unimplemented)
48
+ * 400fd000 flash memory control (unimplemented)
49
+ * 400fe000 system control
50
+ */
51
+
28
+
52
DeviceState *gpio_dev[7], *nvic;
29
+#define RX_STATUS_FIFO_PORT 0x40
53
qemu_irq gpio_in[7][8];
30
+#define RX_STATUS_FIFO_PEEK 0x44
54
qemu_irq gpio_out[7][8];
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;
55
--
71
--
56
2.7.4
72
2.20.1
57
73
58
74
diff view generated by jsdifflib
1
From: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
VMState added by this patch preserves correct
3
This patch allows NPCM7XX CLK module to compute clocks that are used by
4
loading of the integratorcp device state.
4
other NPCM7XX modules.
5
5
6
Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
6
Add a new struct NPCM7xxClockConverterState which represents a
7
Message-id: 20170131114310.6768.79416.stgit@PASHA-ISP
7
single converter. Each clock converter in CLK module represents one
8
[PMM: removed unnecessary minimum_version_id_old lines]
8
converter in NPCM7XX CLK Module(PLL, SEL or Divider). Each converter
9
takes one or more input clocks and converts them into one output clock.
10
They form a clock hierarchy in the CLK module and are responsible for
11
outputing clocks for various other modules in an NPCM7XX SoC.
12
13
Each converter has a function pointer called "convert" which represents
14
the unique logic for that converter.
15
16
The clock contains two initialization information: ConverterInitInfo and
17
ConverterConnectionInfo. They represent the vertices and edges in the
18
clock diagram respectively.
19
20
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
21
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
22
Signed-off-by: Hao Wu <wuhaotsh@google.com>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
23
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
24
Message-id: 20210108190945.949196-2-wuhaotsh@google.com
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
25
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
---
26
---
12
hw/arm/integratorcp.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++
27
include/hw/misc/npcm7xx_clk.h | 140 +++++-
13
1 file changed, 59 insertions(+)
28
hw/misc/npcm7xx_clk.c | 805 +++++++++++++++++++++++++++++++++-
29
2 files changed, 932 insertions(+), 13 deletions(-)
14
30
15
diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c
31
diff --git a/include/hw/misc/npcm7xx_clk.h b/include/hw/misc/npcm7xx_clk.h
16
index XXXXXXX..XXXXXXX 100644
32
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/arm/integratorcp.c
33
--- a/include/hw/misc/npcm7xx_clk.h
18
+++ b/hw/arm/integratorcp.c
34
+++ b/include/hw/misc/npcm7xx_clk.h
19
@@ -XXX,XX +XXX,XX @@ static uint8_t integrator_spd[128] = {
35
@@ -XXX,XX +XXX,XX @@
20
0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40
36
#define NPCM7XX_CLK_H
37
38
#include "exec/memory.h"
39
+#include "hw/clock.h"
40
#include "hw/sysbus.h"
41
42
/*
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
198
index XXXXXXX..XXXXXXX 100644
199
--- a/hw/misc/npcm7xx_clk.c
200
+++ b/hw/misc/npcm7xx_clk.c
201
@@ -XXX,XX +XXX,XX @@
202
203
#include "hw/misc/npcm7xx_clk.h"
204
#include "hw/timer/npcm7xx_timer.h"
205
+#include "hw/qdev-clock.h"
206
#include "migration/vmstate.h"
207
#include "qemu/error-report.h"
208
#include "qemu/log.h"
209
@@ -XXX,XX +XXX,XX @@
210
#include "trace.h"
211
#include "sysemu/watchdog.h"
212
213
+/*
214
+ * The reference clock hz, and the SECCNT and CNTR25M registers in this module,
215
+ * is always 25 MHz.
216
+ */
217
+#define NPCM7XX_CLOCK_REF_HZ (25000000)
218
+
219
+/* Register Field Definitions */
220
+#define NPCM7XX_CLK_WDRCR_CA9C BIT(0) /* Cortex A9 Cores */
221
+
222
#define PLLCON_LOKI BIT(31)
223
#define PLLCON_LOKS BIT(30)
224
#define PLLCON_PWDEN BIT(12)
225
+#define PLLCON_FBDV(con) extract32((con), 16, 12)
226
+#define PLLCON_OTDV2(con) extract32((con), 13, 3)
227
+#define PLLCON_OTDV1(con) extract32((con), 8, 3)
228
+#define PLLCON_INDV(con) extract32((con), 0, 6)
229
230
enum NPCM7xxCLKRegisters {
231
NPCM7XX_CLK_CLKEN1,
232
@@ -XXX,XX +XXX,XX @@ static const uint32_t cold_reset_values[NPCM7XX_CLK_NR_REGS] = {
233
[NPCM7XX_CLK_AHBCKFI] = 0x000000c8,
21
};
234
};
22
235
23
+static const VMStateDescription vmstate_integratorcm = {
236
-/* Register Field Definitions */
24
+ .name = "integratorcm",
237
-#define NPCM7XX_CLK_WDRCR_CA9C BIT(0) /* Cortex A9 Cores */
238
-
239
/* The number of watchdogs that can trigger a reset. */
240
#define NPCM7XX_NR_WATCHDOGS (3)
241
242
+/* Clock converter functions */
243
+
244
+#define TYPE_NPCM7XX_CLOCK_PLL "npcm7xx-clock-pll"
245
+#define NPCM7XX_CLOCK_PLL(obj) OBJECT_CHECK(NPCM7xxClockPLLState, \
246
+ (obj), TYPE_NPCM7XX_CLOCK_PLL)
247
+#define TYPE_NPCM7XX_CLOCK_SEL "npcm7xx-clock-sel"
248
+#define NPCM7XX_CLOCK_SEL(obj) OBJECT_CHECK(NPCM7xxClockSELState, \
249
+ (obj), TYPE_NPCM7XX_CLOCK_SEL)
250
+#define TYPE_NPCM7XX_CLOCK_DIVIDER "npcm7xx-clock-divider"
251
+#define NPCM7XX_CLOCK_DIVIDER(obj) OBJECT_CHECK(NPCM7xxClockDividerState, \
252
+ (obj), TYPE_NPCM7XX_CLOCK_DIVIDER)
253
+
254
+static void npcm7xx_clk_update_pll(void *opaque)
255
+{
256
+ NPCM7xxClockPLLState *s = opaque;
257
+ uint32_t con = s->clk->regs[s->reg];
258
+ uint64_t freq;
259
+
260
+ /* The PLL is grounded if it is not locked yet. */
261
+ if (con & PLLCON_LOKI) {
262
+ freq = clock_get_hz(s->clock_in);
263
+ freq *= PLLCON_FBDV(con);
264
+ freq /= PLLCON_INDV(con) * PLLCON_OTDV1(con) * PLLCON_OTDV2(con);
265
+ } else {
266
+ freq = 0;
267
+ }
268
+
269
+ clock_update_hz(s->clock_out, freq);
270
+}
271
+
272
+static void npcm7xx_clk_update_sel(void *opaque)
273
+{
274
+ NPCM7xxClockSELState *s = opaque;
275
+ uint32_t index = extract32(s->clk->regs[NPCM7XX_CLK_CLKSEL], s->offset,
276
+ s->len);
277
+
278
+ if (index >= s->input_size) {
279
+ qemu_log_mask(LOG_GUEST_ERROR,
280
+ "%s: SEL index: %u out of range\n",
281
+ __func__, index);
282
+ index = 0;
283
+ }
284
+ clock_update_hz(s->clock_out, clock_get_hz(s->clock_in[index]));
285
+}
286
+
287
+static void npcm7xx_clk_update_divider(void *opaque)
288
+{
289
+ NPCM7xxClockDividerState *s = opaque;
290
+ uint32_t freq;
291
+
292
+ freq = s->divide(s);
293
+ clock_update_hz(s->clock_out, freq);
294
+}
295
+
296
+static uint32_t divide_by_constant(NPCM7xxClockDividerState *s)
297
+{
298
+ return clock_get_hz(s->clock_in) / s->divisor;
299
+}
300
+
301
+static uint32_t divide_by_reg_divisor(NPCM7xxClockDividerState *s)
302
+{
303
+ return clock_get_hz(s->clock_in) /
304
+ (extract32(s->clk->regs[s->reg], s->offset, s->len) + 1);
305
+}
306
+
307
+static uint32_t divide_by_reg_divisor_times_2(NPCM7xxClockDividerState *s)
308
+{
309
+ return divide_by_reg_divisor(s) / 2;
310
+}
311
+
312
+static uint32_t shift_by_reg_divisor(NPCM7xxClockDividerState *s)
313
+{
314
+ return clock_get_hz(s->clock_in) >>
315
+ extract32(s->clk->regs[s->reg], s->offset, s->len);
316
+}
317
+
318
+static NPCM7xxClockPLL find_pll_by_reg(enum NPCM7xxCLKRegisters reg)
319
+{
320
+ switch (reg) {
321
+ case NPCM7XX_CLK_PLLCON0:
322
+ return NPCM7XX_CLOCK_PLL0;
323
+ case NPCM7XX_CLK_PLLCON1:
324
+ return NPCM7XX_CLOCK_PLL1;
325
+ case NPCM7XX_CLK_PLLCON2:
326
+ return NPCM7XX_CLOCK_PLL2;
327
+ case NPCM7XX_CLK_PLLCONG:
328
+ return NPCM7XX_CLOCK_PLLG;
329
+ default:
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
}
857
}
858
+ /* Only update PLL when it is locked. */
859
+ if (value & PLLCON_LOKI) {
860
+ npcm7xx_clk_update_pll(&s->plls[find_pll_by_reg(reg)]);
861
+ }
862
+ break;
863
+
864
+ case NPCM7XX_CLK_CLKSEL:
865
+ npcm7xx_clk_update_all_sels(s);
866
+ break;
867
+
868
+ case NPCM7XX_CLK_CLKDIV1:
869
+ case NPCM7XX_CLK_CLKDIV2:
870
+ case NPCM7XX_CLK_CLKDIV3:
871
+ npcm7xx_clk_update_all_dividers(s);
872
break;
873
874
case NPCM7XX_CLK_CNTR25M:
875
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_enter_reset(Object *obj, ResetType type)
876
case RESET_TYPE_COLD:
877
memcpy(s->regs, cold_reset_values, sizeof(cold_reset_values));
878
s->ref_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
879
+ npcm7xx_clk_update_all_clocks(s);
880
return;
881
}
882
883
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_enter_reset(Object *obj, ResetType type)
884
__func__, type);
885
}
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",
25
+ .version_id = 1,
1010
+ .version_id = 1,
26
+ .minimum_version_id = 1,
1011
+ .minimum_version_id = 1,
27
+ .fields = (VMStateField[]) {
1012
+ .post_load = npcm7xx_clk_post_load,
28
+ VMSTATE_UINT32(cm_osc, IntegratorCMState),
1013
+ .fields = (VMStateField[]) {
29
+ VMSTATE_UINT32(cm_ctrl, IntegratorCMState),
1014
+ VMSTATE_UINT32_ARRAY(regs, NPCM7xxCLKState, NPCM7XX_CLK_NR_REGS),
30
+ VMSTATE_UINT32(cm_lock, IntegratorCMState),
1015
+ VMSTATE_INT64(ref_ns, NPCM7xxCLKState),
31
+ VMSTATE_UINT32(cm_auxosc, IntegratorCMState),
1016
+ VMSTATE_CLOCK(clkref, NPCM7xxCLKState),
32
+ VMSTATE_UINT32(cm_sdram, IntegratorCMState),
1017
+ VMSTATE_END_OF_LIST(),
33
+ VMSTATE_UINT32(cm_init, IntegratorCMState),
1018
+ },
34
+ VMSTATE_UINT32(cm_flags, IntegratorCMState),
35
+ VMSTATE_UINT32(cm_nvflags, IntegratorCMState),
36
+ VMSTATE_UINT32(int_level, IntegratorCMState),
37
+ VMSTATE_UINT32(irq_enabled, IntegratorCMState),
38
+ VMSTATE_UINT32(fiq_enabled, IntegratorCMState),
39
+ VMSTATE_END_OF_LIST()
40
+ }
41
+};
1019
+};
42
+
1020
+
43
static uint64_t integratorcm_read(void *opaque, hwaddr offset,
1021
+static void npcm7xx_clk_pll_class_init(ObjectClass *klass, void *data)
44
unsigned size)
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)
45
{
1046
{
46
@@ -XXX,XX +XXX,XX @@ typedef struct icp_pic_state {
1047
ResettableClass *rc = RESETTABLE_CLASS(klass);
47
qemu_irq parent_fiq;
1048
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_class_init(ObjectClass *klass, void *data)
48
} icp_pic_state;
1049
49
1050
dc->desc = "NPCM7xx Clock Control Registers";
50
+static const VMStateDescription vmstate_icp_pic = {
1051
dc->vmsd = &vmstate_npcm7xx_clk;
51
+ .name = "icp_pic",
1052
+ dc->realize = npcm7xx_clk_realize;
52
+ .version_id = 1,
1053
rc->phases.enter = npcm7xx_clk_enter_reset;
53
+ .minimum_version_id = 1,
1054
}
54
+ .fields = (VMStateField[]) {
1055
55
+ VMSTATE_UINT32(level, icp_pic_state),
1056
+static const TypeInfo npcm7xx_clk_pll_info = {
56
+ VMSTATE_UINT32(irq_enabled, icp_pic_state),
1057
+ .name = TYPE_NPCM7XX_CLOCK_PLL,
57
+ VMSTATE_UINT32(fiq_enabled, icp_pic_state),
1058
+ .parent = TYPE_DEVICE,
58
+ VMSTATE_END_OF_LIST()
1059
+ .instance_size = sizeof(NPCM7xxClockPLLState),
59
+ }
1060
+ .instance_init = npcm7xx_clk_pll_init,
1061
+ .class_init = npcm7xx_clk_pll_class_init,
60
+};
1062
+};
61
+
1063
+
62
static void icp_pic_update(icp_pic_state *s)
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)
63
{
1086
{
64
uint32_t flags;
1087
+ type_register_static(&npcm7xx_clk_pll_info);
65
@@ -XXX,XX +XXX,XX @@ typedef struct ICPCtrlRegsState {
1088
+ type_register_static(&npcm7xx_clk_sel_info);
66
#define ICP_INTREG_WPROT (1 << 0)
1089
+ type_register_static(&npcm7xx_clk_divider_info);
67
#define ICP_INTREG_CARDIN (1 << 3)
1090
type_register_static(&npcm7xx_clk_info);
68
69
+static const VMStateDescription vmstate_icp_control = {
70
+ .name = "icp_control",
71
+ .version_id = 1,
72
+ .minimum_version_id = 1,
73
+ .fields = (VMStateField[]) {
74
+ VMSTATE_UINT32(intreg_state, ICPCtrlRegsState),
75
+ VMSTATE_END_OF_LIST()
76
+ }
77
+};
78
+
79
static uint64_t icp_control_read(void *opaque, hwaddr offset,
80
unsigned size)
81
{
82
@@ -XXX,XX +XXX,XX @@ static void core_class_init(ObjectClass *klass, void *data)
83
84
dc->props = core_properties;
85
dc->realize = integratorcm_realize;
86
+ dc->vmsd = &vmstate_integratorcm;
87
+}
88
+
89
+static void icp_pic_class_init(ObjectClass *klass, void *data)
90
+{
91
+ DeviceClass *dc = DEVICE_CLASS(klass);
92
+
93
+ dc->vmsd = &vmstate_icp_pic;
94
+}
95
+
96
+static void icp_control_class_init(ObjectClass *klass, void *data)
97
+{
98
+ DeviceClass *dc = DEVICE_CLASS(klass);
99
+
100
+ dc->vmsd = &vmstate_icp_control;
101
}
1091
}
102
1092
type_init(npcm7xx_clk_register_type);
103
static const TypeInfo core_info = {
104
@@ -XXX,XX +XXX,XX @@ static const TypeInfo icp_pic_info = {
105
.parent = TYPE_SYS_BUS_DEVICE,
106
.instance_size = sizeof(icp_pic_state),
107
.instance_init = icp_pic_init,
108
+ .class_init = icp_pic_class_init,
109
};
110
111
static const TypeInfo icp_ctrl_regs_info = {
112
@@ -XXX,XX +XXX,XX @@ static const TypeInfo icp_ctrl_regs_info = {
113
.parent = TYPE_SYS_BUS_DEVICE,
114
.instance_size = sizeof(ICPCtrlRegsState),
115
.instance_init = icp_control_init,
116
+ .class_init = icp_control_class_init,
117
};
118
119
static void integratorcp_register_types(void)
120
--
1093
--
121
2.7.4
1094
2.20.1
122
1095
123
1096
diff view generated by jsdifflib
1
Add support for generating the ISS (Instruction Specific Syndrome)
1
From: Hao Wu <wuhaotsh@google.com>
2
for Data Abort exceptions taken from AArch32. These syndromes are
3
used by hypervisors for example to trap and emulate memory accesses.
4
2
5
This is the equivalent for AArch32 guests of the work done for AArch64
3
This patch makes NPCM7XX Timer to use a the timer clock generated by the
6
guests in commit aaa1f954d4cab243.
4
CLK module instead of the magic number TIMER_REF_HZ.
7
5
6
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
7
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
8
Signed-off-by: Hao Wu <wuhaotsh@google.com>
9
Message-id: 20210108190945.949196-3-wuhaotsh@google.com
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
10
---
12
---
11
target/arm/translate.h | 14 ++++
13
include/hw/misc/npcm7xx_clk.h | 6 -----
12
target/arm/translate-a64.c | 14 ----
14
include/hw/timer/npcm7xx_timer.h | 1 +
13
target/arm/translate.c | 184 +++++++++++++++++++++++++++++++++------------
15
hw/arm/npcm7xx.c | 5 ++++
14
3 files changed, 149 insertions(+), 63 deletions(-)
16
hw/timer/npcm7xx_timer.c | 39 +++++++++++++++-----------------
17
4 files changed, 24 insertions(+), 27 deletions(-)
15
18
16
diff --git a/target/arm/translate.h b/target/arm/translate.h
19
diff --git a/include/hw/misc/npcm7xx_clk.h b/include/hw/misc/npcm7xx_clk.h
17
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
18
--- a/target/arm/translate.h
21
--- a/include/hw/misc/npcm7xx_clk.h
19
+++ b/target/arm/translate.h
22
+++ b/include/hw/misc/npcm7xx_clk.h
20
@@ -XXX,XX +XXX,XX @@ static inline int default_exception_el(DisasContext *s)
23
@@ -XXX,XX +XXX,XX @@
21
? 3 : MAX(1, s->current_el);
24
#include "hw/clock.h"
25
#include "hw/sysbus.h"
26
27
-/*
28
- * The reference clock frequency for the timer modules, and the SECCNT and
29
- * CNTR25M registers in this module, is always 25 MHz.
30
- */
31
-#define NPCM7XX_TIMER_REF_HZ (25000000)
32
-
33
/*
34
* Number of registers in our device state structure. Don't change this without
35
* incrementing the version_id in the vmstate.
36
diff --git a/include/hw/timer/npcm7xx_timer.h b/include/hw/timer/npcm7xx_timer.h
37
index XXXXXXX..XXXXXXX 100644
38
--- a/include/hw/timer/npcm7xx_timer.h
39
+++ b/include/hw/timer/npcm7xx_timer.h
40
@@ -XXX,XX +XXX,XX @@ struct NPCM7xxTimerCtrlState {
41
42
uint32_t tisr;
43
44
+ Clock *clock;
45
NPCM7xxTimer timer[NPCM7XX_TIMERS_PER_CTRL];
46
NPCM7xxWatchdogTimer watchdog_timer;
47
};
48
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/hw/arm/npcm7xx.c
51
+++ b/hw/arm/npcm7xx.c
52
@@ -XXX,XX +XXX,XX @@
53
#include "hw/char/serial.h"
54
#include "hw/loader.h"
55
#include "hw/misc/unimp.h"
56
+#include "hw/qdev-clock.h"
57
#include "hw/qdev-properties.h"
58
#include "qapi/error.h"
59
#include "qemu/units.h"
60
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
61
int first_irq;
62
int j;
63
64
+ /* Connect the timer clock. */
65
+ qdev_connect_clock_in(DEVICE(&s->tim[i]), "clock", qdev_get_clock_out(
66
+ DEVICE(&s->clk), "timer-clock"));
67
+
68
sysbus_realize(sbd, &error_abort);
69
sysbus_mmio_map(sbd, 0, npcm7xx_tim_addr[i]);
70
71
diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c
72
index XXXXXXX..XXXXXXX 100644
73
--- a/hw/timer/npcm7xx_timer.c
74
+++ b/hw/timer/npcm7xx_timer.c
75
@@ -XXX,XX +XXX,XX @@
76
#include "qemu/osdep.h"
77
78
#include "hw/irq.h"
79
+#include "hw/qdev-clock.h"
80
#include "hw/qdev-properties.h"
81
-#include "hw/misc/npcm7xx_clk.h"
82
#include "hw/timer/npcm7xx_timer.h"
83
#include "migration/vmstate.h"
84
#include "qemu/bitops.h"
85
@@ -XXX,XX +XXX,XX @@ static uint32_t npcm7xx_tcsr_prescaler(uint32_t tcsr)
86
/* Convert a timer cycle count to a time interval in nanoseconds. */
87
static int64_t npcm7xx_timer_count_to_ns(NPCM7xxTimer *t, uint32_t count)
88
{
89
- int64_t ns = count;
90
+ int64_t ticks = count;
91
92
- ns *= NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ;
93
- ns *= npcm7xx_tcsr_prescaler(t->tcsr);
94
+ ticks *= npcm7xx_tcsr_prescaler(t->tcsr);
95
96
- return ns;
97
+ return clock_ticks_to_ns(t->ctrl->clock, ticks);
22
}
98
}
23
99
24
+static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
100
/* Convert a time interval in nanoseconds to a timer cycle count. */
25
+{
101
static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns)
26
+ /* We don't need to save all of the syndrome so we mask and shift
102
{
27
+ * out unneeded bits to help the sleb128 encoder do a better job.
103
- int64_t count;
28
+ */
104
-
29
+ syn &= ARM_INSN_START_WORD2_MASK;
105
- count = ns / (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ);
30
+ syn >>= ARM_INSN_START_WORD2_SHIFT;
106
- count /= npcm7xx_tcsr_prescaler(t->tcsr);
31
+
107
-
32
+ /* We check and clear insn_start_idx to catch multiple updates. */
108
- return count;
33
+ assert(s->insn_start_idx != 0);
109
+ return ns / clock_ticks_to_ns(t->ctrl->clock,
34
+ tcg_set_insn_param(s->insn_start_idx, 2, syn);
110
+ npcm7xx_tcsr_prescaler(t->tcsr));
35
+ s->insn_start_idx = 0;
36
+}
37
+
38
/* target-specific extra values for is_jmp */
39
/* These instructions trap after executing, so the A32/T32 decoder must
40
* defer them until after the conditional execution state has been updated.
41
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
42
index XXXXXXX..XXXXXXX 100644
43
--- a/target/arm/translate-a64.c
44
+++ b/target/arm/translate-a64.c
45
@@ -XXX,XX +XXX,XX @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
46
}
47
}
111
}
48
112
49
-static void disas_set_insn_syndrome(DisasContext *s, uint32_t syn)
113
static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t)
50
-{
114
@@ -XXX,XX +XXX,XX @@ static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t)
51
- /* We don't need to save all of the syndrome so we mask and shift
115
static void npcm7xx_watchdog_timer_reset_cycles(NPCM7xxWatchdogTimer *t,
52
- * out uneeded bits to help the sleb128 encoder do a better job.
116
int64_t cycles)
53
- */
54
- syn &= ARM_INSN_START_WORD2_MASK;
55
- syn >>= ARM_INSN_START_WORD2_SHIFT;
56
-
57
- /* We check and clear insn_start_idx to catch multiple updates. */
58
- assert(s->insn_start_idx != 0);
59
- tcg_set_insn_param(s->insn_start_idx, 2, syn);
60
- s->insn_start_idx = 0;
61
-}
62
-
63
static void unallocated_encoding(DisasContext *s)
64
{
117
{
65
/* Unallocated and reserved encodings are uncategorized */
118
- uint32_t prescaler = npcm7xx_watchdog_timer_prescaler(t);
66
diff --git a/target/arm/translate.c b/target/arm/translate.c
119
- int64_t ns = (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ) * cycles;
67
index XXXXXXX..XXXXXXX 100644
120
+ int64_t ticks = cycles * npcm7xx_watchdog_timer_prescaler(t);
68
--- a/target/arm/translate.c
121
+ int64_t ns = clock_ticks_to_ns(t->ctrl->clock, ticks);
69
+++ b/target/arm/translate.c
122
70
@@ -XXX,XX +XXX,XX @@ void arm_translate_init(void)
123
/*
71
a64_translate_init();
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,
126
*/
127
npcm7xx_timer_clear(&t->base_timer);
128
129
- ns *= prescaler;
130
t->base_timer.remaining_ns = ns;
72
}
131
}
73
132
74
+/* Flags for the disas_set_da_iss info argument:
133
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_hold_reset(Object *obj)
75
+ * lower bits hold the Rt register number, higher bits are flags.
134
qemu_irq_lower(s->watchdog_timer.irq);
76
+ */
135
}
77
+typedef enum ISSInfo {
136
78
+ ISSNone = 0,
137
-static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
79
+ ISSRegMask = 0x1f,
138
+static void npcm7xx_timer_init(Object *obj)
80
+ ISSInvalid = (1 << 5),
81
+ ISSIsAcqRel = (1 << 6),
82
+ ISSIsWrite = (1 << 7),
83
+ ISSIs16Bit = (1 << 8),
84
+} ISSInfo;
85
+
86
+/* Save the syndrome information for a Data Abort */
87
+static void disas_set_da_iss(DisasContext *s, TCGMemOp memop, ISSInfo issinfo)
88
+{
89
+ uint32_t syn;
90
+ int sas = memop & MO_SIZE;
91
+ bool sse = memop & MO_SIGN;
92
+ bool is_acqrel = issinfo & ISSIsAcqRel;
93
+ bool is_write = issinfo & ISSIsWrite;
94
+ bool is_16bit = issinfo & ISSIs16Bit;
95
+ int srt = issinfo & ISSRegMask;
96
+
97
+ if (issinfo & ISSInvalid) {
98
+ /* Some callsites want to conditionally provide ISS info,
99
+ * eg "only if this was not a writeback"
100
+ */
101
+ return;
102
+ }
103
+
104
+ if (srt == 15) {
105
+ /* For AArch32, insns where the src/dest is R15 never generate
106
+ * ISS information. Catching that here saves checking at all
107
+ * the call sites.
108
+ */
109
+ return;
110
+ }
111
+
112
+ syn = syn_data_abort_with_iss(0, sas, sse, srt, 0, is_acqrel,
113
+ 0, 0, 0, is_write, 0, is_16bit);
114
+ disas_set_insn_syndrome(s, syn);
115
+}
116
+
117
static inline ARMMMUIdx get_a32_user_mem_index(DisasContext *s)
118
{
139
{
119
/* Return the mmu_idx to use for A32/T32 "unprivileged load/store"
140
- NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(dev);
120
@@ -XXX,XX +XXX,XX @@ static inline void gen_aa32_ld##SUFF(DisasContext *s, TCGv_i32 val, \
141
- SysBusDevice *sbd = &s->parent;
121
TCGv_i32 a32, int index) \
142
+ NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(obj);
122
{ \
143
+ DeviceState *dev = DEVICE(obj);
123
gen_aa32_ld_i32(s, val, a32, index, OPC | s->be_data); \
144
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
124
+} \
145
int i;
125
+static inline void gen_aa32_ld##SUFF##_iss(DisasContext *s, \
146
NPCM7xxWatchdogTimer *w;
126
+ TCGv_i32 val, \
147
127
+ TCGv_i32 a32, int index, \
148
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
128
+ ISSInfo issinfo) \
149
npcm7xx_watchdog_timer_expired, w);
129
+{ \
150
sysbus_init_irq(sbd, &w->irq);
130
+ gen_aa32_ld_i32(s, val, a32, index, OPC | s->be_data); \
151
131
+ disas_set_da_iss(s, OPC, issinfo); \
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);
132
}
159
}
133
160
134
#define DO_GEN_ST(SUFF, OPC) \
161
static const VMStateDescription vmstate_npcm7xx_base_timer = {
135
@@ -XXX,XX +XXX,XX @@ static inline void gen_aa32_st##SUFF(DisasContext *s, TCGv_i32 val, \
162
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_npcm7xx_watchdog_timer = {
136
TCGv_i32 a32, int index) \
163
137
{ \
164
static const VMStateDescription vmstate_npcm7xx_timer_ctrl = {
138
gen_aa32_st_i32(s, val, a32, index, OPC | s->be_data); \
165
.name = "npcm7xx-timer-ctrl",
139
+} \
166
- .version_id = 1,
140
+static inline void gen_aa32_st##SUFF##_iss(DisasContext *s, \
167
- .minimum_version_id = 1,
141
+ TCGv_i32 val, \
168
+ .version_id = 2,
142
+ TCGv_i32 a32, int index, \
169
+ .minimum_version_id = 2,
143
+ ISSInfo issinfo) \
170
.fields = (VMStateField[]) {
144
+{ \
171
VMSTATE_UINT32(tisr, NPCM7xxTimerCtrlState),
145
+ gen_aa32_st_i32(s, val, a32, index, OPC | s->be_data); \
172
+ VMSTATE_CLOCK(clock, NPCM7xxTimerCtrlState),
146
+ disas_set_da_iss(s, OPC, issinfo | ISSIsWrite); \
173
VMSTATE_STRUCT_ARRAY(timer, NPCM7xxTimerCtrlState,
147
}
174
NPCM7XX_TIMERS_PER_CTRL, 0, vmstate_npcm7xx_timer,
148
175
NPCM7xxTimer),
149
static inline void gen_aa32_frob64(DisasContext *s, TCGv_i64 val)
176
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_class_init(ObjectClass *klass, void *data)
150
@@ -XXX,XX +XXX,XX @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
177
QEMU_BUILD_BUG_ON(NPCM7XX_TIMER_REGS_END > NPCM7XX_TIMER_NR_REGS);
151
tmp = tcg_temp_new_i32();
178
152
switch (op1) {
179
dc->desc = "NPCM7xx Timer Controller";
153
case 0: /* lda */
180
- dc->realize = npcm7xx_timer_realize;
154
- gen_aa32_ld32u(s, tmp, addr,
181
dc->vmsd = &vmstate_npcm7xx_timer_ctrl;
155
- get_mem_index(s));
182
rc->phases.enter = npcm7xx_timer_enter_reset;
156
+ gen_aa32_ld32u_iss(s, tmp, addr,
183
rc->phases.hold = npcm7xx_timer_hold_reset;
157
+ get_mem_index(s),
184
@@ -XXX,XX +XXX,XX @@ static const TypeInfo npcm7xx_timer_info = {
158
+ rd | ISSIsAcqRel);
185
.parent = TYPE_SYS_BUS_DEVICE,
159
break;
186
.instance_size = sizeof(NPCM7xxTimerCtrlState),
160
case 2: /* ldab */
187
.class_init = npcm7xx_timer_class_init,
161
- gen_aa32_ld8u(s, tmp, addr,
188
+ .instance_init = npcm7xx_timer_init,
162
- get_mem_index(s));
189
};
163
+ gen_aa32_ld8u_iss(s, tmp, addr,
190
164
+ get_mem_index(s),
191
static void npcm7xx_timer_register_type(void)
165
+ rd | ISSIsAcqRel);
166
break;
167
case 3: /* ldah */
168
- gen_aa32_ld16u(s, tmp, addr,
169
- get_mem_index(s));
170
+ gen_aa32_ld16u_iss(s, tmp, addr,
171
+ get_mem_index(s),
172
+ rd | ISSIsAcqRel);
173
break;
174
default:
175
abort();
176
@@ -XXX,XX +XXX,XX @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
177
tmp = load_reg(s, rm);
178
switch (op1) {
179
case 0: /* stl */
180
- gen_aa32_st32(s, tmp, addr,
181
- get_mem_index(s));
182
+ gen_aa32_st32_iss(s, tmp, addr,
183
+ get_mem_index(s),
184
+ rm | ISSIsAcqRel);
185
break;
186
case 2: /* stlb */
187
- gen_aa32_st8(s, tmp, addr,
188
- get_mem_index(s));
189
+ gen_aa32_st8_iss(s, tmp, addr,
190
+ get_mem_index(s),
191
+ rm | ISSIsAcqRel);
192
break;
193
case 3: /* stlh */
194
- gen_aa32_st16(s, tmp, addr,
195
- get_mem_index(s));
196
+ gen_aa32_st16_iss(s, tmp, addr,
197
+ get_mem_index(s),
198
+ rm | ISSIsAcqRel);
199
break;
200
default:
201
abort();
202
@@ -XXX,XX +XXX,XX @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
203
bool wbit = insn & (1 << 21);
204
bool pbit = insn & (1 << 24);
205
bool doubleword = false;
206
+ ISSInfo issinfo;
207
+
208
/* Misc load/store */
209
rn = (insn >> 16) & 0xf;
210
rd = (insn >> 12) & 0xf;
211
212
+ /* ISS not valid if writeback */
213
+ issinfo = (pbit & !wbit) ? rd : ISSInvalid;
214
+
215
if (!load && (sh & 2)) {
216
/* doubleword */
217
ARCH(5TE);
218
@@ -XXX,XX +XXX,XX @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
219
tmp = tcg_temp_new_i32();
220
switch (sh) {
221
case 1:
222
- gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
223
+ gen_aa32_ld16u_iss(s, tmp, addr, get_mem_index(s),
224
+ issinfo);
225
break;
226
case 2:
227
- gen_aa32_ld8s(s, tmp, addr, get_mem_index(s));
228
+ gen_aa32_ld8s_iss(s, tmp, addr, get_mem_index(s),
229
+ issinfo);
230
break;
231
default:
232
case 3:
233
- gen_aa32_ld16s(s, tmp, addr, get_mem_index(s));
234
+ gen_aa32_ld16s_iss(s, tmp, addr, get_mem_index(s),
235
+ issinfo);
236
break;
237
}
238
} else {
239
/* store */
240
tmp = load_reg(s, rd);
241
- gen_aa32_st16(s, tmp, addr, get_mem_index(s));
242
+ gen_aa32_st16_iss(s, tmp, addr, get_mem_index(s), issinfo);
243
tcg_temp_free_i32(tmp);
244
}
245
/* Perform base writeback before the loaded value to
246
@@ -XXX,XX +XXX,XX @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
247
/* load */
248
tmp = tcg_temp_new_i32();
249
if (insn & (1 << 22)) {
250
- gen_aa32_ld8u(s, tmp, tmp2, i);
251
+ gen_aa32_ld8u_iss(s, tmp, tmp2, i, rd);
252
} else {
253
- gen_aa32_ld32u(s, tmp, tmp2, i);
254
+ gen_aa32_ld32u_iss(s, tmp, tmp2, i, rd);
255
}
256
} else {
257
/* store */
258
tmp = load_reg(s, rd);
259
if (insn & (1 << 22)) {
260
- gen_aa32_st8(s, tmp, tmp2, i);
261
+ gen_aa32_st8_iss(s, tmp, tmp2, i, rd);
262
} else {
263
- gen_aa32_st32(s, tmp, tmp2, i);
264
+ gen_aa32_st32_iss(s, tmp, tmp2, i, rd);
265
}
266
tcg_temp_free_i32(tmp);
267
}
268
@@ -XXX,XX +XXX,XX @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
269
tmp = tcg_temp_new_i32();
270
switch (op) {
271
case 0: /* ldab */
272
- gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
273
+ gen_aa32_ld8u_iss(s, tmp, addr, get_mem_index(s),
274
+ rs | ISSIsAcqRel);
275
break;
276
case 1: /* ldah */
277
- gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
278
+ gen_aa32_ld16u_iss(s, tmp, addr, get_mem_index(s),
279
+ rs | ISSIsAcqRel);
280
break;
281
case 2: /* lda */
282
- gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
283
+ gen_aa32_ld32u_iss(s, tmp, addr, get_mem_index(s),
284
+ rs | ISSIsAcqRel);
285
break;
286
default:
287
abort();
288
@@ -XXX,XX +XXX,XX @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
289
tmp = load_reg(s, rs);
290
switch (op) {
291
case 0: /* stlb */
292
- gen_aa32_st8(s, tmp, addr, get_mem_index(s));
293
+ gen_aa32_st8_iss(s, tmp, addr, get_mem_index(s),
294
+ rs | ISSIsAcqRel);
295
break;
296
case 1: /* stlh */
297
- gen_aa32_st16(s, tmp, addr, get_mem_index(s));
298
+ gen_aa32_st16_iss(s, tmp, addr, get_mem_index(s),
299
+ rs | ISSIsAcqRel);
300
break;
301
case 2: /* stl */
302
- gen_aa32_st32(s, tmp, addr, get_mem_index(s));
303
+ gen_aa32_st32_iss(s, tmp, addr, get_mem_index(s),
304
+ rs | ISSIsAcqRel);
305
break;
306
default:
307
abort();
308
@@ -XXX,XX +XXX,XX @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
309
int postinc = 0;
310
int writeback = 0;
311
int memidx;
312
+ ISSInfo issinfo;
313
+
314
if ((insn & 0x01100000) == 0x01000000) {
315
if (disas_neon_ls_insn(s, insn)) {
316
goto illegal_op;
317
@@ -XXX,XX +XXX,XX @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
318
}
319
}
320
}
321
+
322
+ issinfo = writeback ? ISSInvalid : rs;
323
+
324
if (insn & (1 << 20)) {
325
/* Load. */
326
tmp = tcg_temp_new_i32();
327
switch (op) {
328
case 0:
329
- gen_aa32_ld8u(s, tmp, addr, memidx);
330
+ gen_aa32_ld8u_iss(s, tmp, addr, memidx, issinfo);
331
break;
332
case 4:
333
- gen_aa32_ld8s(s, tmp, addr, memidx);
334
+ gen_aa32_ld8s_iss(s, tmp, addr, memidx, issinfo);
335
break;
336
case 1:
337
- gen_aa32_ld16u(s, tmp, addr, memidx);
338
+ gen_aa32_ld16u_iss(s, tmp, addr, memidx, issinfo);
339
break;
340
case 5:
341
- gen_aa32_ld16s(s, tmp, addr, memidx);
342
+ gen_aa32_ld16s_iss(s, tmp, addr, memidx, issinfo);
343
break;
344
case 2:
345
- gen_aa32_ld32u(s, tmp, addr, memidx);
346
+ gen_aa32_ld32u_iss(s, tmp, addr, memidx, issinfo);
347
break;
348
default:
349
tcg_temp_free_i32(tmp);
350
@@ -XXX,XX +XXX,XX @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
351
tmp = load_reg(s, rs);
352
switch (op) {
353
case 0:
354
- gen_aa32_st8(s, tmp, addr, memidx);
355
+ gen_aa32_st8_iss(s, tmp, addr, memidx, issinfo);
356
break;
357
case 1:
358
- gen_aa32_st16(s, tmp, addr, memidx);
359
+ gen_aa32_st16_iss(s, tmp, addr, memidx, issinfo);
360
break;
361
case 2:
362
- gen_aa32_st32(s, tmp, addr, memidx);
363
+ gen_aa32_st32_iss(s, tmp, addr, memidx, issinfo);
364
break;
365
default:
366
tcg_temp_free_i32(tmp);
367
@@ -XXX,XX +XXX,XX @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
368
addr = tcg_temp_new_i32();
369
tcg_gen_movi_i32(addr, val);
370
tmp = tcg_temp_new_i32();
371
- gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
372
+ gen_aa32_ld32u_iss(s, tmp, addr, get_mem_index(s),
373
+ rd | ISSIs16Bit);
374
tcg_temp_free_i32(addr);
375
store_reg(s, rd, tmp);
376
break;
377
@@ -XXX,XX +XXX,XX @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
378
379
switch (op) {
380
case 0: /* str */
381
- gen_aa32_st32(s, tmp, addr, get_mem_index(s));
382
+ gen_aa32_st32_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
383
break;
384
case 1: /* strh */
385
- gen_aa32_st16(s, tmp, addr, get_mem_index(s));
386
+ gen_aa32_st16_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
387
break;
388
case 2: /* strb */
389
- gen_aa32_st8(s, tmp, addr, get_mem_index(s));
390
+ gen_aa32_st8_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
391
break;
392
case 3: /* ldrsb */
393
- gen_aa32_ld8s(s, tmp, addr, get_mem_index(s));
394
+ gen_aa32_ld8s_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
395
break;
396
case 4: /* ldr */
397
- gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
398
+ gen_aa32_ld32u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
399
break;
400
case 5: /* ldrh */
401
- gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
402
+ gen_aa32_ld16u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
403
break;
404
case 6: /* ldrb */
405
- gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
406
+ gen_aa32_ld8u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
407
break;
408
case 7: /* ldrsh */
409
- gen_aa32_ld16s(s, tmp, addr, get_mem_index(s));
410
+ gen_aa32_ld16s_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
411
break;
412
}
413
if (op >= 3) { /* load */
414
@@ -XXX,XX +XXX,XX @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
415
if (insn & (1 << 11)) {
416
/* load */
417
tmp = tcg_temp_new_i32();
418
- gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
419
+ gen_aa32_ld8u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
420
store_reg(s, rd, tmp);
421
} else {
422
/* store */
423
tmp = load_reg(s, rd);
424
- gen_aa32_st8(s, tmp, addr, get_mem_index(s));
425
+ gen_aa32_st8_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
426
tcg_temp_free_i32(tmp);
427
}
428
tcg_temp_free_i32(addr);
429
@@ -XXX,XX +XXX,XX @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
430
if (insn & (1 << 11)) {
431
/* load */
432
tmp = tcg_temp_new_i32();
433
- gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
434
+ gen_aa32_ld16u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
435
store_reg(s, rd, tmp);
436
} else {
437
/* store */
438
tmp = load_reg(s, rd);
439
- gen_aa32_st16(s, tmp, addr, get_mem_index(s));
440
+ gen_aa32_st16_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
441
tcg_temp_free_i32(tmp);
442
}
443
tcg_temp_free_i32(addr);
444
@@ -XXX,XX +XXX,XX @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
445
if (insn & (1 << 11)) {
446
/* load */
447
tmp = tcg_temp_new_i32();
448
- gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
449
+ gen_aa32_ld32u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
450
store_reg(s, rd, tmp);
451
} else {
452
/* store */
453
tmp = load_reg(s, rd);
454
- gen_aa32_st32(s, tmp, addr, get_mem_index(s));
455
+ gen_aa32_st32_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
456
tcg_temp_free_i32(tmp);
457
}
458
tcg_temp_free_i32(addr);
459
@@ -XXX,XX +XXX,XX @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
460
store_cpu_field(tmp, condexec_bits);
461
}
462
do {
463
+ dc->insn_start_idx = tcg_op_buf_count();
464
tcg_gen_insn_start(dc->pc,
465
(dc->condexec_cond << 4) | (dc->condexec_mask >> 1),
466
0);
467
--
192
--
468
2.7.4
193
2.20.1
469
194
470
195
diff view generated by jsdifflib
1
Create a new "unimplemented" sysbus device, which simply accepts
1
From: Hao Wu <wuhaotsh@google.com>
2
all read and write accesses, and implements them as read-as-zero,
3
write-ignored, with logging of the access as LOG_UNIMP.
4
2
5
This is useful for stubbing out bits of an SoC or board model
3
The ADC is part of NPCM7XX Module. Its behavior is controled by the
6
which haven't been written yet.
4
ADC_CON register. It converts one of the eight analog inputs into a
5
digital input and stores it in the ADC_DATA register when enabled.
7
6
7
Users can alter input value by using qom-set QMP command.
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]
14
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
10
Message-id: 1484247815-15279-3-git-send-email-peter.maydell@linaro.org
11
---
16
---
12
hw/misc/Makefile.objs | 2 +
17
docs/system/arm/nuvoton.rst | 2 +-
13
include/hw/misc/unimp.h | 39 ++++++++++++++++++
18
meson.build | 1 +
14
hw/misc/unimp.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++
19
hw/adc/trace.h | 1 +
15
3 files changed, 148 insertions(+)
20
include/hw/adc/npcm7xx_adc.h | 69 ++++++
16
create mode 100644 include/hw/misc/unimp.h
21
include/hw/arm/npcm7xx.h | 2 +
17
create mode 100644 hw/misc/unimp.c
22
hw/adc/npcm7xx_adc.c | 301 ++++++++++++++++++++++++++
23
hw/arm/npcm7xx.c | 24 ++-
24
tests/qtest/npcm7xx_adc-test.c | 377 +++++++++++++++++++++++++++++++++
25
hw/adc/meson.build | 1 +
26
hw/adc/trace-events | 5 +
27
tests/qtest/meson.build | 3 +-
28
11 files changed, 783 insertions(+), 3 deletions(-)
29
create mode 100644 hw/adc/trace.h
30
create mode 100644 include/hw/adc/npcm7xx_adc.h
31
create mode 100644 hw/adc/npcm7xx_adc.c
32
create mode 100644 tests/qtest/npcm7xx_adc-test.c
33
create mode 100644 hw/adc/trace-events
18
34
19
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
35
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
20
index XXXXXXX..XXXXXXX 100644
36
index XXXXXXX..XXXXXXX 100644
21
--- a/hw/misc/Makefile.objs
37
--- a/docs/system/arm/nuvoton.rst
22
+++ b/hw/misc/Makefile.objs
38
+++ b/docs/system/arm/nuvoton.rst
23
@@ -XXX,XX +XXX,XX @@ common-obj-$(CONFIG_SGA) += sga.o
39
@@ -XXX,XX +XXX,XX @@ Supported devices
24
common-obj-$(CONFIG_ISA_TESTDEV) += pc-testdev.o
40
* Random Number Generator (RNG)
25
common-obj-$(CONFIG_PCI_TESTDEV) += pci-testdev.o
41
* USB host (USBH)
26
42
* GPIO controller
27
+common-obj-y += unimp.o
43
+ * Analog to Digital Converter (ADC)
28
+
44
29
obj-$(CONFIG_VMPORT) += vmport.o
45
Missing devices
30
46
---------------
31
# ARM devices
47
@@ -XXX,XX +XXX,XX @@ Missing devices
32
diff --git a/include/hw/misc/unimp.h b/include/hw/misc/unimp.h
48
* USB device (USBD)
49
* SMBus controller (SMBF)
50
* Peripheral SPI controller (PSPI)
51
- * Analog to Digital Converter (ADC)
52
* SD/MMC host
53
* PECI interface
54
* Pulse Width Modulation (PWM)
55
diff --git a/meson.build b/meson.build
56
index XXXXXXX..XXXXXXX 100644
57
--- a/meson.build
58
+++ b/meson.build
59
@@ -XXX,XX +XXX,XX @@ if have_system
60
'chardev',
61
'hw/9pfs',
62
'hw/acpi',
63
+ 'hw/adc',
64
'hw/alpha',
65
'hw/arm',
66
'hw/audio',
67
diff --git a/hw/adc/trace.h b/hw/adc/trace.h
33
new file mode 100644
68
new file mode 100644
34
index XXXXXXX..XXXXXXX
69
index XXXXXXX..XXXXXXX
35
--- /dev/null
70
--- /dev/null
36
+++ b/include/hw/misc/unimp.h
71
+++ b/hw/adc/trace.h
37
@@ -XXX,XX +XXX,XX @@
72
@@ -0,0 +1 @@
38
+/*
73
+#include "trace/trace-hw_adc.h"
39
+ * "Unimplemented" device
74
diff --git a/include/hw/adc/npcm7xx_adc.h b/include/hw/adc/npcm7xx_adc.h
40
+ *
41
+ * Copyright Linaro Limited, 2017
42
+ * Written by Peter Maydell
43
+ */
44
+
45
+#ifndef HW_MISC_UNIMP_H
46
+#define HW_MISC_UNIMP_H
47
+
48
+#define TYPE_UNIMPLEMENTED_DEVICE "unimplemented-device"
49
+
50
+/**
51
+ * create_unimplemented_device: create and map a dummy device
52
+ * @name: name of the device for debug logging
53
+ * @base: base address of the device's MMIO region
54
+ * @size: size of the device's MMIO region
55
+ *
56
+ * This utility function creates and maps an instance of unimplemented-device,
57
+ * which is a dummy device which simply logs all guest accesses to
58
+ * it via the qemu_log LOG_UNIMP debug log.
59
+ * The device is mapped at priority -1000, which means that you can
60
+ * use it to cover a large region and then map other devices on top of it
61
+ * if necessary.
62
+ */
63
+static inline void create_unimplemented_device(const char *name,
64
+ hwaddr base,
65
+ hwaddr size)
66
+{
67
+ DeviceState *dev = qdev_create(NULL, TYPE_UNIMPLEMENTED_DEVICE);
68
+
69
+ qdev_prop_set_string(dev, "name", name);
70
+ qdev_prop_set_uint64(dev, "size", size);
71
+ qdev_init_nofail(dev);
72
+
73
+ sysbus_mmio_map_overlap(SYS_BUS_DEVICE(dev), 0, base, -1000);
74
+}
75
+
76
+#endif
77
diff --git a/hw/misc/unimp.c b/hw/misc/unimp.c
78
new file mode 100644
75
new file mode 100644
79
index XXXXXXX..XXXXXXX
76
index XXXXXXX..XXXXXXX
80
--- /dev/null
77
--- /dev/null
81
+++ b/hw/misc/unimp.c
78
+++ b/include/hw/adc/npcm7xx_adc.h
82
@@ -XXX,XX +XXX,XX @@
79
@@ -XXX,XX +XXX,XX @@
83
+/* "Unimplemented" device
80
+/*
81
+ * Nuvoton NPCM7xx ADC Module
84
+ *
82
+ *
85
+ * This is a dummy device which accepts and logs all accesses.
83
+ * Copyright 2020 Google LLC
86
+ * It's useful for stubbing out regions of an SoC or board
87
+ * map which correspond to devices that have not yet been
88
+ * implemented. This is often sufficient to placate initial
89
+ * guest device driver probing such that the system will
90
+ * come up.
91
+ *
84
+ *
92
+ * Copyright Linaro Limited, 2017
85
+ * This program is free software; you can redistribute it and/or modify it
93
+ * Written by Peter Maydell
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
+ */
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
+ */
95
+
190
+
96
+#include "qemu/osdep.h"
191
+#include "qemu/osdep.h"
97
+#include "hw/hw.h"
192
+#include "hw/adc/npcm7xx_adc.h"
98
+#include "hw/sysbus.h"
193
+#include "hw/qdev-clock.h"
99
+#include "hw/misc/unimp.h"
194
+#include "hw/qdev-properties.h"
195
+#include "hw/registerfields.h"
196
+#include "migration/vmstate.h"
100
+#include "qemu/log.h"
197
+#include "qemu/log.h"
101
+#include "qapi/error.h"
198
+#include "qemu/module.h"
102
+
199
+#include "qemu/timer.h"
103
+#define UNIMPLEMENTED_DEVICE(obj) \
200
+#include "qemu/units.h"
104
+ OBJECT_CHECK(UnimplementedDeviceState, (obj), TYPE_UNIMPLEMENTED_DEVICE)
201
+#include "trace.h"
105
+
202
+
106
+typedef struct {
203
+REG32(NPCM7XX_ADC_CON, 0x0)
107
+ SysBusDevice parent_obj;
204
+REG32(NPCM7XX_ADC_DATA, 0x4)
108
+ MemoryRegion iomem;
205
+
109
+ char *name;
206
+/* Register field definitions. */
110
+ uint64_t size;
207
+#define NPCM7XX_ADC_CON_MUX(rv) extract32(rv, 24, 4)
111
+} UnimplementedDeviceState;
208
+#define NPCM7XX_ADC_CON_INT_EN BIT(21)
112
+
209
+#define NPCM7XX_ADC_CON_REFSEL BIT(19)
113
+static uint64_t unimp_read(void *opaque, hwaddr offset, unsigned size)
210
+#define NPCM7XX_ADC_CON_INT BIT(18)
114
+{
211
+#define NPCM7XX_ADC_CON_EN BIT(17)
115
+ UnimplementedDeviceState *s = UNIMPLEMENTED_DEVICE(opaque);
212
+#define NPCM7XX_ADC_CON_RST BIT(16)
116
+
213
+#define NPCM7XX_ADC_CON_CONV BIT(14)
117
+ qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read "
214
+#define NPCM7XX_ADC_CON_DIV(rv) extract32(rv, 1, 8)
118
+ "(size %d, offset 0x%" HWADDR_PRIx ")\n",
215
+
119
+ s->name, size, offset);
216
+#define NPCM7XX_ADC_MAX_RESULT 1023
120
+ return 0;
217
+#define NPCM7XX_ADC_DEFAULT_IREF 2000000
121
+}
218
+#define NPCM7XX_ADC_CONV_CYCLES 20
122
+
219
+#define NPCM7XX_ADC_RESET_CYCLES 10
123
+static void unimp_write(void *opaque, hwaddr offset,
220
+#define NPCM7XX_ADC_R0_INPUT 500000
124
+ uint64_t value, unsigned size)
221
+#define NPCM7XX_ADC_R1_INPUT 1500000
125
+{
222
+
126
+ UnimplementedDeviceState *s = UNIMPLEMENTED_DEVICE(opaque);
223
+static void npcm7xx_adc_reset(NPCM7xxADCState *s)
127
+
224
+{
128
+ qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write "
225
+ timer_del(&s->conv_timer);
129
+ "(size %d, value 0x%" PRIx64
226
+ s->con = 0x000c0001;
130
+ ", offset 0x%" HWADDR_PRIx ")\n",
227
+ s->data = 0x00000000;
131
+ s->name, size, value, offset);
228
+}
132
+}
229
+
133
+
230
+static uint32_t npcm7xx_adc_convert(uint32_t input, uint32_t ref)
134
+static const MemoryRegionOps unimp_ops = {
231
+{
135
+ .read = unimp_read,
232
+ uint32_t result;
136
+ .write = unimp_write,
233
+
137
+ .impl.min_access_size = 1,
234
+ result = input * (NPCM7XX_ADC_MAX_RESULT + 1) / ref;
138
+ .impl.max_access_size = 8,
235
+ if (result > NPCM7XX_ADC_MAX_RESULT) {
139
+ .valid.min_access_size = 1,
236
+ result = NPCM7XX_ADC_MAX_RESULT;
140
+ .valid.max_access_size = 8,
237
+ }
141
+ .endianness = DEVICE_NATIVE_ENDIAN,
238
+
239
+ return result;
240
+}
241
+
242
+static uint32_t npcm7xx_adc_prescaler(NPCM7xxADCState *s)
243
+{
244
+ return 2 * (NPCM7XX_ADC_CON_DIV(s->con) + 1);
245
+}
246
+
247
+static void npcm7xx_adc_start_timer(Clock *clk, QEMUTimer *timer,
248
+ uint32_t cycles, uint32_t prescaler)
249
+{
250
+ int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
251
+ int64_t ticks = cycles;
252
+ int64_t ns;
253
+
254
+ ticks *= prescaler;
255
+ ns = clock_ticks_to_ns(clk, ticks);
256
+ ns += now;
257
+ timer_mod(timer, ns);
258
+}
259
+
260
+static void npcm7xx_adc_start_convert(NPCM7xxADCState *s)
261
+{
262
+ uint32_t prescaler = npcm7xx_adc_prescaler(s);
263
+
264
+ npcm7xx_adc_start_timer(s->clock, &s->conv_timer, NPCM7XX_ADC_CONV_CYCLES,
265
+ prescaler);
266
+}
267
+
268
+static void npcm7xx_adc_convert_done(void *opaque)
269
+{
270
+ NPCM7xxADCState *s = opaque;
271
+ uint32_t input = NPCM7XX_ADC_CON_MUX(s->con);
272
+ uint32_t ref = (s->con & NPCM7XX_ADC_CON_REFSEL)
273
+ ? s->iref : s->vref;
274
+
275
+ if (input >= NPCM7XX_ADC_NUM_INPUTS) {
276
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid input: %u\n",
277
+ __func__, input);
278
+ return;
279
+ }
280
+ s->data = npcm7xx_adc_convert(s->adci[input], ref);
281
+ if (s->con & NPCM7XX_ADC_CON_INT_EN) {
282
+ s->con |= NPCM7XX_ADC_CON_INT;
283
+ qemu_irq_raise(s->irq);
284
+ }
285
+ s->con &= ~NPCM7XX_ADC_CON_CONV;
286
+}
287
+
288
+static void npcm7xx_adc_calibrate(NPCM7xxADCState *adc)
289
+{
290
+ adc->calibration_r_values[0] = npcm7xx_adc_convert(NPCM7XX_ADC_R0_INPUT,
291
+ adc->iref);
292
+ adc->calibration_r_values[1] = npcm7xx_adc_convert(NPCM7XX_ADC_R1_INPUT,
293
+ adc->iref);
294
+}
295
+
296
+static void npcm7xx_adc_write_con(NPCM7xxADCState *s, uint32_t new_con)
297
+{
298
+ uint32_t old_con = s->con;
299
+
300
+ /* Write ADC_INT to 1 to clear it */
301
+ if (new_con & NPCM7XX_ADC_CON_INT) {
302
+ new_con &= ~NPCM7XX_ADC_CON_INT;
303
+ qemu_irq_lower(s->irq);
304
+ } else if (old_con & NPCM7XX_ADC_CON_INT) {
305
+ new_con |= NPCM7XX_ADC_CON_INT;
306
+ }
307
+
308
+ s->con = new_con;
309
+
310
+ if (s->con & NPCM7XX_ADC_CON_RST) {
311
+ npcm7xx_adc_reset(s);
312
+ return;
313
+ }
314
+
315
+ if ((s->con & NPCM7XX_ADC_CON_EN)) {
316
+ if (s->con & NPCM7XX_ADC_CON_CONV) {
317
+ if (!(old_con & NPCM7XX_ADC_CON_CONV)) {
318
+ npcm7xx_adc_start_convert(s);
319
+ }
320
+ } else {
321
+ timer_del(&s->conv_timer);
322
+ }
323
+ }
324
+}
325
+
326
+static uint64_t npcm7xx_adc_read(void *opaque, hwaddr offset, unsigned size)
327
+{
328
+ uint64_t value = 0;
329
+ NPCM7xxADCState *s = opaque;
330
+
331
+ switch (offset) {
332
+ case A_NPCM7XX_ADC_CON:
333
+ value = s->con;
334
+ break;
335
+
336
+ case A_NPCM7XX_ADC_DATA:
337
+ value = s->data;
338
+ break;
339
+
340
+ default:
341
+ qemu_log_mask(LOG_GUEST_ERROR,
342
+ "%s: invalid offset 0x%04" HWADDR_PRIx "\n",
343
+ __func__, offset);
344
+ break;
345
+ }
346
+
347
+ trace_npcm7xx_adc_read(DEVICE(s)->canonical_path, offset, value);
348
+ return value;
349
+}
350
+
351
+static void npcm7xx_adc_write(void *opaque, hwaddr offset, uint64_t v,
352
+ unsigned size)
353
+{
354
+ NPCM7xxADCState *s = opaque;
355
+
356
+ trace_npcm7xx_adc_write(DEVICE(s)->canonical_path, offset, v);
357
+ switch (offset) {
358
+ case A_NPCM7XX_ADC_CON:
359
+ npcm7xx_adc_write_con(s, v);
360
+ break;
361
+
362
+ case A_NPCM7XX_ADC_DATA:
363
+ qemu_log_mask(LOG_GUEST_ERROR,
364
+ "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n",
365
+ __func__, offset);
366
+ break;
367
+
368
+ default:
369
+ qemu_log_mask(LOG_GUEST_ERROR,
370
+ "%s: invalid offset 0x%04" HWADDR_PRIx "\n",
371
+ __func__, offset);
372
+ break;
373
+ }
374
+
375
+}
376
+
377
+static const struct MemoryRegionOps npcm7xx_adc_ops = {
378
+ .read = npcm7xx_adc_read,
379
+ .write = npcm7xx_adc_write,
380
+ .endianness = DEVICE_LITTLE_ENDIAN,
381
+ .valid = {
382
+ .min_access_size = 4,
383
+ .max_access_size = 4,
384
+ .unaligned = false,
385
+ },
142
+};
386
+};
143
+
387
+
144
+static void unimp_realize(DeviceState *dev, Error **errp)
388
+static void npcm7xx_adc_enter_reset(Object *obj, ResetType type)
145
+{
389
+{
146
+ UnimplementedDeviceState *s = UNIMPLEMENTED_DEVICE(dev);
390
+ NPCM7xxADCState *s = NPCM7XX_ADC(obj);
147
+
391
+
148
+ if (s->size == 0) {
392
+ npcm7xx_adc_reset(s);
149
+ error_setg(errp, "property 'size' not specified or zero");
393
+}
150
+ return;
394
+
151
+ }
395
+static void npcm7xx_adc_hold_reset(Object *obj)
152
+
396
+{
153
+ if (s->name == NULL) {
397
+ NPCM7xxADCState *s = NPCM7XX_ADC(obj);
154
+ error_setg(errp, "property 'name' not specified");
398
+
155
+ return;
399
+ qemu_irq_lower(s->irq);
156
+ }
400
+}
157
+
401
+
158
+ memory_region_init_io(&s->iomem, OBJECT(s), &unimp_ops, s,
402
+static void npcm7xx_adc_init(Object *obj)
159
+ s->name, s->size);
403
+{
160
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
404
+ NPCM7xxADCState *s = NPCM7XX_ADC(obj);
161
+}
405
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
162
+
406
+ int i;
163
+static Property unimp_properties[] = {
407
+
164
+ DEFINE_PROP_UINT64("size", UnimplementedDeviceState, size, 0),
408
+ sysbus_init_irq(sbd, &s->irq);
165
+ DEFINE_PROP_STRING("name", UnimplementedDeviceState, name),
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),
166
+ DEFINE_PROP_END_OF_LIST(),
446
+ DEFINE_PROP_END_OF_LIST(),
167
+};
447
+};
168
+
448
+
169
+static void unimp_class_init(ObjectClass *klass, void *data)
449
+static void npcm7xx_adc_class_init(ObjectClass *klass, void *data)
170
+{
450
+{
451
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
171
+ DeviceClass *dc = DEVICE_CLASS(klass);
452
+ DeviceClass *dc = DEVICE_CLASS(klass);
172
+
453
+
173
+ dc->realize = unimp_realize;
454
+ dc->desc = "NPCM7xx ADC Module";
174
+ dc->props = unimp_properties;
455
+ dc->vmsd = &vmstate_npcm7xx_adc;
175
+}
456
+ rc->phases.enter = npcm7xx_adc_enter_reset;
176
+
457
+ rc->phases.hold = npcm7xx_adc_hold_reset;
177
+static const TypeInfo unimp_info = {
458
+
178
+ .name = TYPE_UNIMPLEMENTED_DEVICE,
459
+ device_class_set_props(dc, npcm7xx_timer_properties);
179
+ .parent = TYPE_SYS_BUS_DEVICE,
460
+}
180
+ .instance_size = sizeof(UnimplementedDeviceState),
461
+
181
+ .class_init = unimp_class_init,
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,
182
+};
468
+};
183
+
469
+
184
+static void unimp_register_types(void)
470
+static void npcm7xx_adc_register_types(void)
185
+{
471
+{
186
+ type_register_static(&unimp_info);
472
+ type_register_static(&npcm7xx_adc_info);
187
+}
473
+}
188
+
474
+
189
+type_init(unimp_register_types)
475
+type_init(npcm7xx_adc_register_types);
476
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
477
index XXXXXXX..XXXXXXX 100644
478
--- a/hw/arm/npcm7xx.c
479
+++ b/hw/arm/npcm7xx.c
480
@@ -XXX,XX +XXX,XX @@
481
#define NPCM7XX_EHCI_BA (0xf0806000)
482
#define NPCM7XX_OHCI_BA (0xf0807000)
483
484
+/* ADC Module */
485
+#define NPCM7XX_ADC_BA (0xf000c000)
486
+
487
/* Internal AHB SRAM */
488
#define NPCM7XX_RAM3_BA (0xc0008000)
489
#define NPCM7XX_RAM3_SZ (4 * KiB)
490
@@ -XXX,XX +XXX,XX @@
491
#define NPCM7XX_ROM_BA (0xffff0000)
492
#define NPCM7XX_ROM_SZ (64 * KiB)
493
494
+
495
/* Clock configuration values to be fixed up when bypassing bootloader */
496
497
/* Run PLL1 at 1600 MHz */
498
@@ -XXX,XX +XXX,XX @@
499
* interrupts.
500
*/
501
enum NPCM7xxInterrupt {
502
+ NPCM7XX_ADC_IRQ = 0,
503
NPCM7XX_UART0_IRQ = 2,
504
NPCM7XX_UART1_IRQ,
505
NPCM7XX_UART2_IRQ,
506
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init_fuses(NPCM7xxState *s)
507
sizeof(value));
508
}
509
510
+static void npcm7xx_write_adc_calibration(NPCM7xxState *s)
511
+{
512
+ /* Both ADC and the fuse array must have realized. */
513
+ QEMU_BUILD_BUG_ON(sizeof(s->adc.calibration_r_values) != 4);
514
+ npcm7xx_otp_array_write(&s->fuse_array, s->adc.calibration_r_values,
515
+ NPCM7XX_FUSE_ADC_CALIB, sizeof(s->adc.calibration_r_values));
516
+}
517
+
518
static qemu_irq npcm7xx_irq(NPCM7xxState *s, int n)
519
{
520
return qdev_get_gpio_in(DEVICE(&s->a9mpcore), n);
521
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
522
TYPE_NPCM7XX_FUSE_ARRAY);
523
object_initialize_child(obj, "mc", &s->mc, TYPE_NPCM7XX_MC);
524
object_initialize_child(obj, "rng", &s->rng, TYPE_NPCM7XX_RNG);
525
+ object_initialize_child(obj, "adc", &s->adc, TYPE_NPCM7XX_ADC);
526
527
for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
528
object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
529
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
530
sysbus_realize(SYS_BUS_DEVICE(&s->mc), &error_abort);
531
sysbus_mmio_map(SYS_BUS_DEVICE(&s->mc), 0, NPCM7XX_MC_BA);
532
533
+ /* ADC Modules. Cannot fail. */
534
+ qdev_connect_clock_in(DEVICE(&s->adc), "clock", qdev_get_clock_out(
535
+ DEVICE(&s->clk), "adc-clock"));
536
+ sysbus_realize(SYS_BUS_DEVICE(&s->adc), &error_abort);
537
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->adc), 0, NPCM7XX_ADC_BA);
538
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0,
539
+ npcm7xx_irq(s, NPCM7XX_ADC_IRQ));
540
+ npcm7xx_write_adc_calibration(s);
541
+
542
/* Timer Modules (TIM). Cannot fail. */
543
QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_tim_addr) != ARRAY_SIZE(s->tim));
544
for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
545
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
546
create_unimplemented_device("npcm7xx.vdmx", 0xe0800000, 4 * KiB);
547
create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB);
548
create_unimplemented_device("npcm7xx.kcs", 0xf0007000, 4 * KiB);
549
- create_unimplemented_device("npcm7xx.adc", 0xf000c000, 4 * KiB);
550
create_unimplemented_device("npcm7xx.gfxi", 0xf000e000, 4 * KiB);
551
create_unimplemented_device("npcm7xx.gpio[0]", 0xf0010000, 4 * KiB);
552
create_unimplemented_device("npcm7xx.gpio[1]", 0xf0011000, 4 * KiB);
553
diff --git a/tests/qtest/npcm7xx_adc-test.c b/tests/qtest/npcm7xx_adc-test.c
554
new file mode 100644
555
index XXXXXXX..XXXXXXX
556
--- /dev/null
557
+++ b/tests/qtest/npcm7xx_adc-test.c
558
@@ -XXX,XX +XXX,XX @@
559
+/*
560
+ * QTests for Nuvoton NPCM7xx ADCModules.
561
+ *
562
+ * Copyright 2020 Google LLC
563
+ *
564
+ * This program is free software; you can redistribute it and/or modify it
565
+ * under the terms of the GNU General Public License as published by the
566
+ * Free Software Foundation; either version 2 of the License, or
567
+ * (at your option) any later version.
568
+ *
569
+ * This program is distributed in the hope that it will be useful, but WITHOUT
570
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
571
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
572
+ * for more details.
573
+ */
574
+
575
+#include "qemu/osdep.h"
576
+#include "qemu/bitops.h"
577
+#include "qemu/timer.h"
578
+#include "libqos/libqtest.h"
579
+#include "qapi/qmp/qdict.h"
580
+
581
+#define REF_HZ (25000000)
582
+
583
+#define CON_OFFSET 0x0
584
+#define DATA_OFFSET 0x4
585
+
586
+#define NUM_INPUTS 8
587
+#define DEFAULT_IREF 2000000
588
+#define CONV_CYCLES 20
589
+#define RESET_CYCLES 10
590
+#define R0_INPUT 500000
591
+#define R1_INPUT 1500000
592
+#define MAX_RESULT 1023
593
+
594
+#define DEFAULT_CLKDIV 5
595
+
596
+#define FUSE_ARRAY_BA 0xf018a000
597
+#define FCTL_OFFSET 0x14
598
+#define FST_OFFSET 0x0
599
+#define FADDR_OFFSET 0x4
600
+#define FDATA_OFFSET 0x8
601
+#define ADC_CALIB_ADDR 24
602
+#define FUSE_READ 0x2
603
+
604
+/* Register field definitions. */
605
+#define CON_MUX(rv) ((rv) << 24)
606
+#define CON_INT_EN BIT(21)
607
+#define CON_REFSEL BIT(19)
608
+#define CON_INT BIT(18)
609
+#define CON_EN BIT(17)
610
+#define CON_RST BIT(16)
611
+#define CON_CONV BIT(14)
612
+#define CON_DIV(rv) extract32(rv, 1, 8)
613
+
614
+#define FST_RDST BIT(1)
615
+#define FDATA_MASK 0xff
616
+
617
+#define MAX_ERROR 10000
618
+#define MIN_CALIB_INPUT 100000
619
+#define MAX_CALIB_INPUT 1800000
620
+
621
+static const uint32_t input_list[] = {
622
+ 100000,
623
+ 500000,
624
+ 1000000,
625
+ 1500000,
626
+ 1800000,
627
+ 2000000,
628
+};
629
+
630
+static const uint32_t vref_list[] = {
631
+ 2000000,
632
+ 2200000,
633
+ 2500000,
634
+};
635
+
636
+static const uint32_t iref_list[] = {
637
+ 1800000,
638
+ 1900000,
639
+ 2000000,
640
+ 2100000,
641
+ 2200000,
642
+};
643
+
644
+static const uint32_t div_list[] = {0, 1, 3, 7, 15};
645
+
646
+typedef struct ADC {
647
+ int irq;
648
+ uint64_t base_addr;
649
+} ADC;
650
+
651
+ADC adc = {
652
+ .irq = 0,
653
+ .base_addr = 0xf000c000
654
+};
655
+
656
+static uint32_t adc_read_con(QTestState *qts, const ADC *adc)
657
+{
658
+ return qtest_readl(qts, adc->base_addr + CON_OFFSET);
659
+}
660
+
661
+static void adc_write_con(QTestState *qts, const ADC *adc, uint32_t value)
662
+{
663
+ qtest_writel(qts, adc->base_addr + CON_OFFSET, value);
664
+}
665
+
666
+static uint32_t adc_read_data(QTestState *qts, const ADC *adc)
667
+{
668
+ return qtest_readl(qts, adc->base_addr + DATA_OFFSET);
669
+}
670
+
671
+static uint32_t adc_calibrate(uint32_t measured, uint32_t *rv)
672
+{
673
+ return R0_INPUT + (R1_INPUT - R0_INPUT) * (int32_t)(measured - rv[0])
674
+ / (int32_t)(rv[1] - rv[0]);
675
+}
676
+
677
+static void adc_qom_set(QTestState *qts, const ADC *adc,
678
+ const char *name, uint32_t value)
679
+{
680
+ QDict *response;
681
+ const char *path = "/machine/soc/adc";
682
+
683
+ g_test_message("Setting properties %s of %s with value %u",
684
+ name, path, value);
685
+ response = qtest_qmp(qts, "{ 'execute': 'qom-set',"
686
+ " 'arguments': { 'path': %s, 'property': %s, 'value': %u}}",
687
+ path, name, value);
688
+ /* The qom set message returns successfully. */
689
+ g_assert_true(qdict_haskey(response, "return"));
690
+}
691
+
692
+static void adc_write_input(QTestState *qts, const ADC *adc,
693
+ uint32_t index, uint32_t value)
694
+{
695
+ char name[100];
696
+
697
+ sprintf(name, "adci[%u]", index);
698
+ adc_qom_set(qts, adc, name, value);
699
+}
700
+
701
+static void adc_write_vref(QTestState *qts, const ADC *adc, uint32_t value)
702
+{
703
+ adc_qom_set(qts, adc, "vref", value);
704
+}
705
+
706
+static uint32_t adc_calculate_output(uint32_t input, uint32_t ref)
707
+{
708
+ uint32_t output;
709
+
710
+ g_assert_cmpuint(input, <=, ref);
711
+ output = (input * (MAX_RESULT + 1)) / ref;
712
+ if (output > MAX_RESULT) {
713
+ output = MAX_RESULT;
714
+ }
715
+
716
+ return output;
717
+}
718
+
719
+static uint32_t adc_prescaler(QTestState *qts, const ADC *adc)
720
+{
721
+ uint32_t div = extract32(adc_read_con(qts, adc), 1, 8);
722
+
723
+ return 2 * (div + 1);
724
+}
725
+
726
+static int64_t adc_calculate_steps(uint32_t cycles, uint32_t prescale,
727
+ uint32_t clkdiv)
728
+{
729
+ return (NANOSECONDS_PER_SECOND / (REF_HZ >> clkdiv)) * cycles * prescale;
730
+}
731
+
732
+static void adc_wait_conv_finished(QTestState *qts, const ADC *adc,
733
+ uint32_t clkdiv)
734
+{
735
+ uint32_t prescaler = adc_prescaler(qts, adc);
736
+
737
+ /*
738
+ * ADC should takes roughly 20 cycles to convert one sample. So we assert it
739
+ * should take 10~30 cycles here.
740
+ */
741
+ qtest_clock_step(qts, adc_calculate_steps(CONV_CYCLES / 2, prescaler,
742
+ clkdiv));
743
+ /* ADC is still converting. */
744
+ g_assert_true(adc_read_con(qts, adc) & CON_CONV);
745
+ qtest_clock_step(qts, adc_calculate_steps(CONV_CYCLES, prescaler, clkdiv));
746
+ /* ADC has finished conversion. */
747
+ g_assert_false(adc_read_con(qts, adc) & CON_CONV);
748
+}
749
+
750
+/* Check ADC can be reset to default value. */
751
+static void test_init(gconstpointer adc_p)
752
+{
753
+ const ADC *adc = adc_p;
754
+
755
+ QTestState *qts = qtest_init("-machine quanta-gsj");
756
+ adc_write_con(qts, adc, CON_REFSEL | CON_INT);
757
+ g_assert_cmphex(adc_read_con(qts, adc), ==, CON_REFSEL);
758
+ qtest_quit(qts);
759
+}
760
+
761
+/* Check ADC can convert from an internal reference. */
762
+static void test_convert_internal(gconstpointer adc_p)
763
+{
764
+ const ADC *adc = adc_p;
765
+ uint32_t index, input, output, expected_output;
766
+ QTestState *qts = qtest_init("-machine quanta-gsj");
767
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
768
+
769
+ for (index = 0; index < NUM_INPUTS; ++index) {
770
+ for (size_t i = 0; i < ARRAY_SIZE(input_list); ++i) {
771
+ input = input_list[i];
772
+ expected_output = adc_calculate_output(input, DEFAULT_IREF);
773
+
774
+ adc_write_input(qts, adc, index, input);
775
+ adc_write_con(qts, adc, CON_MUX(index) | CON_REFSEL | CON_INT |
776
+ CON_EN | CON_CONV);
777
+ adc_wait_conv_finished(qts, adc, DEFAULT_CLKDIV);
778
+ g_assert_cmphex(adc_read_con(qts, adc), ==, CON_MUX(index) |
779
+ CON_REFSEL | CON_EN);
780
+ g_assert_false(qtest_get_irq(qts, adc->irq));
781
+ output = adc_read_data(qts, adc);
782
+ g_assert_cmpuint(output, ==, expected_output);
783
+ }
784
+ }
785
+
786
+ qtest_quit(qts);
787
+}
788
+
789
+/* Check ADC can convert from an external reference. */
790
+static void test_convert_external(gconstpointer adc_p)
791
+{
792
+ const ADC *adc = adc_p;
793
+ uint32_t index, input, vref, output, expected_output;
794
+ QTestState *qts = qtest_init("-machine quanta-gsj");
795
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
796
+
797
+ for (index = 0; index < NUM_INPUTS; ++index) {
798
+ for (size_t i = 0; i < ARRAY_SIZE(input_list); ++i) {
799
+ for (size_t j = 0; j < ARRAY_SIZE(vref_list); ++j) {
800
+ input = input_list[i];
801
+ vref = vref_list[j];
802
+ expected_output = adc_calculate_output(input, vref);
803
+
804
+ adc_write_input(qts, adc, index, input);
805
+ adc_write_vref(qts, adc, vref);
806
+ adc_write_con(qts, adc, CON_MUX(index) | CON_INT | CON_EN |
807
+ CON_CONV);
808
+ adc_wait_conv_finished(qts, adc, DEFAULT_CLKDIV);
809
+ g_assert_cmphex(adc_read_con(qts, adc), ==,
810
+ CON_MUX(index) | CON_EN);
811
+ g_assert_false(qtest_get_irq(qts, adc->irq));
812
+ output = adc_read_data(qts, adc);
813
+ g_assert_cmpuint(output, ==, expected_output);
814
+ }
815
+ }
816
+ }
817
+
818
+ qtest_quit(qts);
819
+}
820
+
821
+/* Check ADC interrupt files if and only if CON_INT_EN is set. */
822
+static void test_interrupt(gconstpointer adc_p)
823
+{
824
+ const ADC *adc = adc_p;
825
+ uint32_t index, input, output, expected_output;
826
+ QTestState *qts = qtest_init("-machine quanta-gsj");
827
+
828
+ index = 1;
829
+ input = input_list[1];
830
+ expected_output = adc_calculate_output(input, DEFAULT_IREF);
831
+
832
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
833
+ adc_write_input(qts, adc, index, input);
834
+ g_assert_false(qtest_get_irq(qts, adc->irq));
835
+ adc_write_con(qts, adc, CON_MUX(index) | CON_INT_EN | CON_REFSEL | CON_INT
836
+ | CON_EN | CON_CONV);
837
+ adc_wait_conv_finished(qts, adc, DEFAULT_CLKDIV);
838
+ g_assert_cmphex(adc_read_con(qts, adc), ==, CON_MUX(index) | CON_INT_EN
839
+ | CON_REFSEL | CON_INT | CON_EN);
840
+ g_assert_true(qtest_get_irq(qts, adc->irq));
841
+ output = adc_read_data(qts, adc);
842
+ g_assert_cmpuint(output, ==, expected_output);
843
+
844
+ qtest_quit(qts);
845
+}
846
+
847
+/* Check ADC is reset after setting ADC_RST for 10 ADC cycles. */
848
+static void test_reset(gconstpointer adc_p)
849
+{
850
+ const ADC *adc = adc_p;
851
+ QTestState *qts = qtest_init("-machine quanta-gsj");
852
+
853
+ for (size_t i = 0; i < ARRAY_SIZE(div_list); ++i) {
854
+ uint32_t div = div_list[i];
855
+
856
+ adc_write_con(qts, adc, CON_INT | CON_EN | CON_RST | CON_DIV(div));
857
+ qtest_clock_step(qts, adc_calculate_steps(RESET_CYCLES,
858
+ adc_prescaler(qts, adc), DEFAULT_CLKDIV));
859
+ g_assert_false(adc_read_con(qts, adc) & CON_EN);
860
+ }
861
+ qtest_quit(qts);
862
+}
863
+
864
+/* Check ADC Calibration works as desired. */
865
+static void test_calibrate(gconstpointer adc_p)
866
+{
867
+ int i, j;
868
+ const ADC *adc = adc_p;
869
+
870
+ for (j = 0; j < ARRAY_SIZE(iref_list); ++j) {
871
+ uint32_t iref = iref_list[j];
872
+ uint32_t expected_rv[] = {
873
+ adc_calculate_output(R0_INPUT, iref),
874
+ adc_calculate_output(R1_INPUT, iref),
875
+ };
876
+ char buf[100];
877
+ QTestState *qts;
878
+
879
+ sprintf(buf, "-machine quanta-gsj -global npcm7xx-adc.iref=%u", iref);
880
+ qts = qtest_init(buf);
881
+
882
+ /* Check the converted value is correct using the calibration value. */
883
+ for (i = 0; i < ARRAY_SIZE(input_list); ++i) {
884
+ uint32_t input;
885
+ uint32_t output;
886
+ uint32_t expected_output;
887
+ uint32_t calibrated_voltage;
888
+ uint32_t index = 0;
889
+
890
+ input = input_list[i];
891
+ /* Calibration only works for input range 0.1V ~ 1.8V. */
892
+ if (input < MIN_CALIB_INPUT || input > MAX_CALIB_INPUT) {
893
+ continue;
894
+ }
895
+ expected_output = adc_calculate_output(input, iref);
896
+
897
+ adc_write_input(qts, adc, index, input);
898
+ adc_write_con(qts, adc, CON_MUX(index) | CON_REFSEL | CON_INT |
899
+ CON_EN | CON_CONV);
900
+ adc_wait_conv_finished(qts, adc, DEFAULT_CLKDIV);
901
+ g_assert_cmphex(adc_read_con(qts, adc), ==,
902
+ CON_REFSEL | CON_MUX(index) | CON_EN);
903
+ output = adc_read_data(qts, adc);
904
+ g_assert_cmpuint(output, ==, expected_output);
905
+
906
+ calibrated_voltage = adc_calibrate(output, expected_rv);
907
+ g_assert_cmpuint(calibrated_voltage, >, input - MAX_ERROR);
908
+ g_assert_cmpuint(calibrated_voltage, <, input + MAX_ERROR);
909
+ }
910
+
911
+ qtest_quit(qts);
912
+ }
913
+}
914
+
915
+static void adc_add_test(const char *name, const ADC* wd,
916
+ GTestDataFunc fn)
917
+{
918
+ g_autofree char *full_name = g_strdup_printf("npcm7xx_adc/%s", name);
919
+ qtest_add_data_func(full_name, wd, fn);
920
+}
921
+#define add_test(name, td) adc_add_test(#name, td, test_##name)
922
+
923
+int main(int argc, char **argv)
924
+{
925
+ g_test_init(&argc, &argv, NULL);
926
+
927
+ add_test(init, &adc);
928
+ add_test(convert_internal, &adc);
929
+ add_test(convert_external, &adc);
930
+ add_test(interrupt, &adc);
931
+ add_test(reset, &adc);
932
+ add_test(calibrate, &adc);
933
+
934
+ return g_test_run();
935
+}
936
diff --git a/hw/adc/meson.build b/hw/adc/meson.build
937
index XXXXXXX..XXXXXXX 100644
938
--- a/hw/adc/meson.build
939
+++ b/hw/adc/meson.build
940
@@ -1 +1,2 @@
941
softmmu_ss.add(when: 'CONFIG_STM32F2XX_ADC', if_true: files('stm32f2xx_adc.c'))
942
+softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_adc.c'))
943
diff --git a/hw/adc/trace-events b/hw/adc/trace-events
944
new file mode 100644
945
index XXXXXXX..XXXXXXX
946
--- /dev/null
947
+++ b/hw/adc/trace-events
948
@@ -XXX,XX +XXX,XX @@
949
+# See docs/devel/tracing.txt for syntax documentation.
950
+
951
+# npcm7xx_adc.c
952
+npcm7xx_adc_read(const char *id, uint64_t offset, uint32_t value) " %s offset: 0x%04" PRIx64 " value 0x%04" PRIx32
953
+npcm7xx_adc_write(const char *id, uint64_t offset, uint32_t value) "%s offset: 0x%04" PRIx64 " value 0x%04" PRIx32
954
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
955
index XXXXXXX..XXXXXXX 100644
956
--- a/tests/qtest/meson.build
957
+++ b/tests/qtest/meson.build
958
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
959
['prom-env-test', 'boot-serial-test']
960
961
qtests_npcm7xx = \
962
- ['npcm7xx_gpio-test',
963
+ ['npcm7xx_adc-test',
964
+ 'npcm7xx_gpio-test',
965
'npcm7xx_rng-test',
966
'npcm7xx_timer-test',
967
'npcm7xx_watchdog_timer-test']
190
--
968
--
191
2.7.4
969
2.20.1
192
970
193
971
diff view generated by jsdifflib
1
From: Cédric Le Goater <clg@kaod.org>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
The Aspeed SoC includes a set of watchdog timers using 32-bit
3
The PWM module is part of NPCM7XX module. Each NPCM7XX module has two
4
decrement counters, which can be based either on the APB clock or
4
identical PWM modules. Each module contains 4 PWM entries. Each PWM has
5
a 1 MHz clock.
5
two outputs: frequency and duty_cycle. Both are computed using inputs
6
from software side.
6
7
7
The watchdog timer is designed to prevent system deadlock and, in
8
This module does not model detail pulse signals since it is expensive.
8
general, it should be restarted before timeout. When a timeout occurs,
9
It also does not model interrupts and watchdogs that are dependant on
9
different types of signals can be generated, ARM reset, SOC reset,
10
the detail models. The interfaces for these are left in the module so
10
System reset, CPU Interrupt, external signal or boot from alternate
11
that anyone in need for these functionalities can implement on their
11
block. The current model only performs the system reset function as
12
own.
12
this is used by U-Boot and Linux.
13
13
14
Signed-off-by: Joel Stanley <joel@jms.id.au>
14
The user can read the duty cycle and frequency using qom-get command.
15
Message-id: 1485452251-1593-2-git-send-email-clg@kaod.org
15
16
[clg: - fixed compile breakage
16
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
17
- fixed io region size
17
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
18
- added watchdog_perform_action() on timer expiry
18
Signed-off-by: Hao Wu <wuhaotsh@google.com>
19
- wrote a commit log
19
Message-id: 20210108190945.949196-5-wuhaotsh@google.com
20
- merged fixes from Andrew Jeffery to scale the reload value ]
21
Signed-off-by: Cédric Le Goater <clg@kaod.org>
22
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
20
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
23
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
24
---
22
---
25
hw/watchdog/Makefile.objs | 1 +
23
docs/system/arm/nuvoton.rst | 2 +-
26
include/hw/watchdog/wdt_aspeed.h | 32 ++++++
24
include/hw/arm/npcm7xx.h | 2 +
27
hw/watchdog/wdt_aspeed.c | 225 +++++++++++++++++++++++++++++++++++++++
25
include/hw/misc/npcm7xx_pwm.h | 105 +++++++
28
3 files changed, 258 insertions(+)
26
hw/arm/npcm7xx.c | 26 +-
29
create mode 100644 include/hw/watchdog/wdt_aspeed.h
27
hw/misc/npcm7xx_pwm.c | 550 ++++++++++++++++++++++++++++++++++
30
create mode 100644 hw/watchdog/wdt_aspeed.c
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
31
33
32
diff --git a/hw/watchdog/Makefile.objs b/hw/watchdog/Makefile.objs
34
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
33
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
34
--- a/hw/watchdog/Makefile.objs
36
--- a/docs/system/arm/nuvoton.rst
35
+++ b/hw/watchdog/Makefile.objs
37
+++ b/docs/system/arm/nuvoton.rst
36
@@ -XXX,XX +XXX,XX @@ common-obj-y += watchdog.o
38
@@ -XXX,XX +XXX,XX @@ Supported devices
37
common-obj-$(CONFIG_WDT_IB6300ESB) += wdt_i6300esb.o
39
* USB host (USBH)
38
common-obj-$(CONFIG_WDT_IB700) += wdt_ib700.o
40
* GPIO controller
39
common-obj-$(CONFIG_WDT_DIAG288) += wdt_diag288.o
41
* Analog to Digital Converter (ADC)
40
+common-obj-$(CONFIG_ASPEED_SOC) += wdt_aspeed.o
42
+ * Pulse Width Modulation (PWM)
41
diff --git a/include/hw/watchdog/wdt_aspeed.h b/include/hw/watchdog/wdt_aspeed.h
43
44
Missing devices
45
---------------
46
@@ -XXX,XX +XXX,XX @@ Missing devices
47
* Peripheral SPI controller (PSPI)
48
* SD/MMC host
49
* PECI interface
50
- * Pulse Width Modulation (PWM)
51
* Tachometer
52
* PCI and PCIe root complex and bridges
53
* VDM and MCTP support
54
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
55
index XXXXXXX..XXXXXXX 100644
56
--- a/include/hw/arm/npcm7xx.h
57
+++ b/include/hw/arm/npcm7xx.h
58
@@ -XXX,XX +XXX,XX @@
59
#include "hw/mem/npcm7xx_mc.h"
60
#include "hw/misc/npcm7xx_clk.h"
61
#include "hw/misc/npcm7xx_gcr.h"
62
+#include "hw/misc/npcm7xx_pwm.h"
63
#include "hw/misc/npcm7xx_rng.h"
64
#include "hw/nvram/npcm7xx_otp.h"
65
#include "hw/timer/npcm7xx_timer.h"
66
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
67
NPCM7xxCLKState clk;
68
NPCM7xxTimerCtrlState tim[3];
69
NPCM7xxADCState adc;
70
+ NPCM7xxPWMState pwm[2];
71
NPCM7xxOTPState key_storage;
72
NPCM7xxOTPState fuse_array;
73
NPCM7xxMCState mc;
74
diff --git a/include/hw/misc/npcm7xx_pwm.h b/include/hw/misc/npcm7xx_pwm.h
42
new file mode 100644
75
new file mode 100644
43
index XXXXXXX..XXXXXXX
76
index XXXXXXX..XXXXXXX
44
--- /dev/null
77
--- /dev/null
45
+++ b/include/hw/watchdog/wdt_aspeed.h
78
+++ b/include/hw/misc/npcm7xx_pwm.h
46
@@ -XXX,XX +XXX,XX @@
79
@@ -XXX,XX +XXX,XX @@
47
+/*
80
+/*
48
+ * ASPEED Watchdog Controller
81
+ * Nuvoton NPCM7xx PWM Module
49
+ *
82
+ *
50
+ * Copyright (C) 2016-2017 IBM Corp.
83
+ * Copyright 2020 Google LLC
51
+ *
84
+ *
52
+ * This code is licensed under the GPL version 2 or later. See the
85
+ * This program is free software; you can redistribute it and/or modify it
53
+ * COPYING file in the top-level directory.
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.
54
+ */
94
+ */
55
+#ifndef ASPEED_WDT_H
95
+#ifndef NPCM7XX_PWM_H
56
+#define ASPEED_WDT_H
96
+#define NPCM7XX_PWM_H
57
+
97
+
98
+#include "hw/clock.h"
58
+#include "hw/sysbus.h"
99
+#include "hw/sysbus.h"
59
+
100
+#include "hw/irq.h"
60
+#define TYPE_ASPEED_WDT "aspeed.wdt"
101
+
61
+#define ASPEED_WDT(obj) \
102
+/* Each PWM module holds 4 PWM channels. */
62
+ OBJECT_CHECK(AspeedWDTState, (obj), TYPE_ASPEED_WDT)
103
+#define NPCM7XX_PWM_PER_MODULE 4
63
+
104
+
64
+#define ASPEED_WDT_REGS_MAX (0x20 / 4)
105
+/*
65
+
106
+ * Number of registers in one pwm module. Don't change this without increasing
66
+typedef struct AspeedWDTState {
107
+ * the version_id in vmstate.
67
+ /*< private >*/
108
+ */
68
+ SysBusDevice parent_obj;
109
+#define NPCM7XX_PWM_NR_REGS (0x54 / sizeof(uint32_t))
69
+ QEMUTimer *timer;
110
+
70
+
111
+/*
71
+ /*< public >*/
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
+
72
+ MemoryRegion iomem;
168
+ MemoryRegion iomem;
73
+ uint32_t regs[ASPEED_WDT_REGS_MAX];
169
+
74
+
170
+ Clock *clock;
75
+ uint32_t pclk_freq;
171
+ NPCM7xxPWM pwm[NPCM7XX_PWM_PER_MODULE];
76
+} AspeedWDTState;
172
+
77
+
173
+ uint32_t ppr;
78
+#endif /* ASPEED_WDT_H */
174
+ uint32_t csr;
79
diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c
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);
214
}
215
+
216
+ for (i = 0; i < ARRAY_SIZE(s->pwm); i++) {
217
+ object_initialize_child(obj, "pwm[*]", &s->pwm[i], TYPE_NPCM7XX_PWM);
218
+ }
219
}
220
221
static void npcm7xx_realize(DeviceState *dev, Error **errp)
222
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
223
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ohci), 0,
224
npcm7xx_irq(s, NPCM7XX_OHCI_IRQ));
225
226
+ /* PWM Modules. Cannot fail. */
227
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_pwm_addr) != ARRAY_SIZE(s->pwm));
228
+ for (i = 0; i < ARRAY_SIZE(s->pwm); i++) {
229
+ SysBusDevice *sbd = SYS_BUS_DEVICE(&s->pwm[i]);
230
+
231
+ qdev_connect_clock_in(DEVICE(&s->pwm[i]), "clock", qdev_get_clock_out(
232
+ DEVICE(&s->clk), "apb3-clock"));
233
+ sysbus_realize(sbd, &error_abort);
234
+ sysbus_mmio_map(sbd, 0, npcm7xx_pwm_addr[i]);
235
+ sysbus_connect_irq(sbd, i, npcm7xx_irq(s, NPCM7XX_PWM0_IRQ + i));
236
+ }
237
+
238
/*
239
* Flash Interface Unit (FIU). Can fail if incorrect number of chip selects
240
* specified, but this is a programming error.
241
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
242
create_unimplemented_device("npcm7xx.peci", 0xf0100000, 4 * KiB);
243
create_unimplemented_device("npcm7xx.siox[1]", 0xf0101000, 4 * KiB);
244
create_unimplemented_device("npcm7xx.siox[2]", 0xf0102000, 4 * KiB);
245
- create_unimplemented_device("npcm7xx.pwm[0]", 0xf0103000, 4 * KiB);
246
- create_unimplemented_device("npcm7xx.pwm[1]", 0xf0104000, 4 * KiB);
247
create_unimplemented_device("npcm7xx.mft[0]", 0xf0180000, 4 * KiB);
248
create_unimplemented_device("npcm7xx.mft[1]", 0xf0181000, 4 * KiB);
249
create_unimplemented_device("npcm7xx.mft[2]", 0xf0182000, 4 * KiB);
250
diff --git a/hw/misc/npcm7xx_pwm.c b/hw/misc/npcm7xx_pwm.c
80
new file mode 100644
251
new file mode 100644
81
index XXXXXXX..XXXXXXX
252
index XXXXXXX..XXXXXXX
82
--- /dev/null
253
--- /dev/null
83
+++ b/hw/watchdog/wdt_aspeed.c
254
+++ b/hw/misc/npcm7xx_pwm.c
84
@@ -XXX,XX +XXX,XX @@
255
@@ -XXX,XX +XXX,XX @@
85
+/*
256
+/*
86
+ * ASPEED Watchdog Controller
257
+ * Nuvoton NPCM7xx PWM Module
87
+ *
258
+ *
88
+ * Copyright (C) 2016-2017 IBM Corp.
259
+ * Copyright 2020 Google LLC
89
+ *
260
+ *
90
+ * This code is licensed under the GPL version 2 or later. See the
261
+ * This program is free software; you can redistribute it and/or modify it
91
+ * COPYING file in the top-level directory.
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.
92
+ */
270
+ */
93
+
271
+
94
+#include "qemu/osdep.h"
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"
95
+#include "qemu/log.h"
281
+#include "qemu/log.h"
96
+#include "sysemu/watchdog.h"
282
+#include "qemu/module.h"
97
+#include "hw/sysbus.h"
283
+#include "qemu/units.h"
98
+#include "qemu/timer.h"
284
+#include "trace.h"
99
+#include "hw/watchdog/wdt_aspeed.h"
285
+
100
+
286
+REG32(NPCM7XX_PWM_PPR, 0x00);
101
+#define WDT_STATUS (0x00 / 4)
287
+REG32(NPCM7XX_PWM_CSR, 0x04);
102
+#define WDT_RELOAD_VALUE (0x04 / 4)
288
+REG32(NPCM7XX_PWM_PCR, 0x08);
103
+#define WDT_RESTART (0x08 / 4)
289
+REG32(NPCM7XX_PWM_CNR0, 0x0c);
104
+#define WDT_CTRL (0x0C / 4)
290
+REG32(NPCM7XX_PWM_CMR0, 0x10);
105
+#define WDT_CTRL_RESET_MODE_SOC (0x00 << 5)
291
+REG32(NPCM7XX_PWM_PDR0, 0x14);
106
+#define WDT_CTRL_RESET_MODE_FULL_CHIP (0x01 << 5)
292
+REG32(NPCM7XX_PWM_CNR1, 0x18);
107
+#define WDT_CTRL_1MHZ_CLK BIT(4)
293
+REG32(NPCM7XX_PWM_CMR1, 0x1c);
108
+#define WDT_CTRL_WDT_EXT BIT(3)
294
+REG32(NPCM7XX_PWM_PDR1, 0x20);
109
+#define WDT_CTRL_WDT_INTR BIT(2)
295
+REG32(NPCM7XX_PWM_CNR2, 0x24);
110
+#define WDT_CTRL_RESET_SYSTEM BIT(1)
296
+REG32(NPCM7XX_PWM_CMR2, 0x28);
111
+#define WDT_CTRL_ENABLE BIT(0)
297
+REG32(NPCM7XX_PWM_PDR2, 0x2c);
112
+
298
+REG32(NPCM7XX_PWM_CNR3, 0x30);
113
+#define WDT_TIMEOUT_STATUS (0x10 / 4)
299
+REG32(NPCM7XX_PWM_CMR3, 0x34);
114
+#define WDT_TIMEOUT_CLEAR (0x14 / 4)
300
+REG32(NPCM7XX_PWM_PDR3, 0x38);
115
+#define WDT_RESET_WDITH (0x18 / 4)
301
+REG32(NPCM7XX_PWM_PIER, 0x3c);
116
+
302
+REG32(NPCM7XX_PWM_PIIR, 0x40);
117
+#define WDT_RESTART_MAGIC 0x4755
303
+REG32(NPCM7XX_PWM_PWDR0, 0x44);
118
+
304
+REG32(NPCM7XX_PWM_PWDR1, 0x48);
119
+static bool aspeed_wdt_is_enabled(const AspeedWDTState *s)
305
+REG32(NPCM7XX_PWM_PWDR2, 0x4c);
120
+{
306
+REG32(NPCM7XX_PWM_PWDR3, 0x50);
121
+ return s->regs[WDT_CTRL] & WDT_CTRL_ENABLE;
307
+
122
+}
308
+/* Register field definitions. */
123
+
309
+#define NPCM7XX_PPR(rv, index) extract32((rv), npcm7xx_ppr_base[index], 8)
124
+static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset, unsigned size)
310
+#define NPCM7XX_CSR(rv, index) extract32((rv), npcm7xx_csr_base[index], 3)
125
+{
311
+#define NPCM7XX_CH(rv, index) extract32((rv), npcm7xx_ch_base[index], 4)
126
+ AspeedWDTState *s = ASPEED_WDT(opaque);
312
+#define NPCM7XX_CH_EN BIT(0)
127
+
313
+#define NPCM7XX_CH_INV BIT(2)
128
+ offset >>= 2;
314
+#define NPCM7XX_CH_MOD BIT(3)
129
+
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
+ }
364
+ } else {
365
+ duty = 0;
366
+ }
367
+
368
+ if (p->inverted) {
369
+ duty = NPCM7XX_PWM_MAX_DUTY - duty;
370
+ }
371
+
372
+ return duty;
373
+}
374
+
375
+static void npcm7xx_pwm_update_freq(NPCM7xxPWM *p)
376
+{
377
+ uint32_t freq = npcm7xx_pwm_calculate_freq(p);
378
+
379
+ if (freq != p->freq) {
380
+ trace_npcm7xx_pwm_update_freq(DEVICE(p->module)->canonical_path,
381
+ p->index, p->freq, freq);
382
+ p->freq = freq;
383
+ }
384
+}
385
+
386
+static void npcm7xx_pwm_update_duty(NPCM7xxPWM *p)
387
+{
388
+ uint32_t duty = npcm7xx_pwm_calculate_duty(p);
389
+
390
+ if (duty != p->duty) {
391
+ trace_npcm7xx_pwm_update_duty(DEVICE(p->module)->canonical_path,
392
+ p->index, p->duty, duty);
393
+ p->duty = duty;
394
+ }
395
+}
396
+
397
+static void npcm7xx_pwm_update_output(NPCM7xxPWM *p)
398
+{
399
+ npcm7xx_pwm_update_freq(p);
400
+ npcm7xx_pwm_update_duty(p);
401
+}
402
+
403
+static void npcm7xx_pwm_write_ppr(NPCM7xxPWMState *s, uint32_t new_ppr)
404
+{
405
+ int i;
406
+ uint32_t old_ppr = s->ppr;
407
+
408
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_ppr_base) != NPCM7XX_PWM_PER_MODULE);
409
+ s->ppr = new_ppr;
410
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
411
+ if (NPCM7XX_PPR(old_ppr, i) != NPCM7XX_PPR(new_ppr, i)) {
412
+ npcm7xx_pwm_update_freq(&s->pwm[i]);
413
+ }
414
+ }
415
+}
416
+
417
+static void npcm7xx_pwm_write_csr(NPCM7xxPWMState *s, uint32_t new_csr)
418
+{
419
+ int i;
420
+ uint32_t old_csr = s->csr;
421
+
422
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_csr_base) != NPCM7XX_PWM_PER_MODULE);
423
+ s->csr = new_csr;
424
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
425
+ if (NPCM7XX_CSR(old_csr, i) != NPCM7XX_CSR(new_csr, i)) {
426
+ npcm7xx_pwm_update_freq(&s->pwm[i]);
427
+ }
428
+ }
429
+}
430
+
431
+static void npcm7xx_pwm_write_pcr(NPCM7xxPWMState *s, uint32_t new_pcr)
432
+{
433
+ int i;
434
+ bool inverted;
435
+ uint32_t pcr;
436
+ NPCM7xxPWM *p;
437
+
438
+ s->pcr = new_pcr;
439
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_ch_base) != NPCM7XX_PWM_PER_MODULE);
440
+ for (i = 0; i < NPCM7XX_PWM_PER_MODULE; ++i) {
441
+ p = &s->pwm[i];
442
+ pcr = NPCM7XX_CH(new_pcr, i);
443
+ inverted = pcr & NPCM7XX_CH_INV;
444
+
445
+ /*
446
+ * We only run a PWM channel with toggle mode. Single-shot mode does not
447
+ * generate frequency and duty-cycle values.
448
+ */
449
+ if ((pcr & NPCM7XX_CH_EN) && (pcr & NPCM7XX_CH_MOD)) {
450
+ if (p->running) {
451
+ /* Re-run this PWM channel if inverted changed. */
452
+ if (p->inverted ^ inverted) {
453
+ p->inverted = inverted;
454
+ npcm7xx_pwm_update_duty(p);
455
+ }
456
+ } else {
457
+ /* Run this PWM channel. */
458
+ p->running = true;
459
+ p->inverted = inverted;
460
+ npcm7xx_pwm_update_output(p);
461
+ }
462
+ } else {
463
+ /* Clear this PWM channel. */
464
+ p->running = false;
465
+ p->inverted = inverted;
466
+ npcm7xx_pwm_update_output(p);
467
+ }
468
+ }
469
+
470
+}
471
+
472
+static hwaddr npcm7xx_cnr_index(hwaddr offset)
473
+{
130
+ switch (offset) {
474
+ switch (offset) {
131
+ case WDT_STATUS:
475
+ case A_NPCM7XX_PWM_CNR0:
132
+ return s->regs[WDT_STATUS];
133
+ case WDT_RELOAD_VALUE:
134
+ return s->regs[WDT_RELOAD_VALUE];
135
+ case WDT_RESTART:
136
+ qemu_log_mask(LOG_GUEST_ERROR,
137
+ "%s: read from write-only reg at offset 0x%"
138
+ HWADDR_PRIx "\n", __func__, offset);
139
+ return 0;
476
+ return 0;
140
+ case WDT_CTRL:
477
+ case A_NPCM7XX_PWM_CNR1:
141
+ return s->regs[WDT_CTRL];
478
+ return 1;
142
+ case WDT_TIMEOUT_STATUS:
479
+ case A_NPCM7XX_PWM_CNR2:
143
+ case WDT_TIMEOUT_CLEAR:
480
+ return 2;
144
+ case WDT_RESET_WDITH:
481
+ case A_NPCM7XX_PWM_CNR3:
145
+ qemu_log_mask(LOG_UNIMP,
482
+ return 3;
146
+ "%s: uninmplemented read at offset 0x%" HWADDR_PRIx "\n",
483
+ default:
147
+ __func__, offset);
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:
148
+ return 0;
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
+
149
+ default:
590
+ default:
150
+ qemu_log_mask(LOG_GUEST_ERROR,
591
+ qemu_log_mask(LOG_GUEST_ERROR,
151
+ "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
592
+ "%s: invalid offset 0x%04" HWADDR_PRIx "\n",
152
+ __func__, offset);
593
+ __func__, offset);
153
+ return 0;
594
+ break;
154
+ }
595
+ }
155
+
596
+
156
+}
597
+ trace_npcm7xx_pwm_read(DEVICE(s)->canonical_path, offset, value);
157
+
598
+ return value;
158
+static void aspeed_wdt_reload(AspeedWDTState *s, bool pclk)
599
+}
159
+{
600
+
160
+ uint32_t reload;
601
+static void npcm7xx_pwm_write(void *opaque, hwaddr offset,
161
+
602
+ uint64_t v, unsigned size)
162
+ if (pclk) {
603
+{
163
+ reload = muldiv64(s->regs[WDT_RELOAD_VALUE], NANOSECONDS_PER_SECOND,
604
+ NPCM7xxPWMState *s = opaque;
164
+ s->pclk_freq);
605
+ NPCM7xxPWM *p;
165
+ } else {
606
+ uint32_t value = v;
166
+ reload = s->regs[WDT_RELOAD_VALUE] * 1000;
607
+
167
+ }
608
+ trace_npcm7xx_pwm_write(DEVICE(s)->canonical_path, offset, value);
168
+
169
+ if (aspeed_wdt_is_enabled(s)) {
170
+ timer_mod(s->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + reload);
171
+ }
172
+}
173
+
174
+static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data,
175
+ unsigned size)
176
+{
177
+ AspeedWDTState *s = ASPEED_WDT(opaque);
178
+ bool enable = data & WDT_CTRL_ENABLE;
179
+
180
+ offset >>= 2;
181
+
182
+ switch (offset) {
609
+ switch (offset) {
183
+ case WDT_STATUS:
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:
184
+ qemu_log_mask(LOG_GUEST_ERROR,
632
+ qemu_log_mask(LOG_GUEST_ERROR,
185
+ "%s: write to read-only reg at offset 0x%"
633
+ "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n",
186
+ HWADDR_PRIx "\n", __func__, offset);
634
+ __func__, offset);
187
+ break;
635
+ break;
188
+ case WDT_RELOAD_VALUE:
636
+
189
+ s->regs[WDT_RELOAD_VALUE] = data;
637
+ case A_NPCM7XX_PWM_PWDR0:
190
+ break;
638
+ case A_NPCM7XX_PWM_PWDR1:
191
+ case WDT_RESTART:
639
+ case A_NPCM7XX_PWM_PWDR2:
192
+ if ((data & 0xFFFF) == WDT_RESTART_MAGIC) {
640
+ case A_NPCM7XX_PWM_PWDR3:
193
+ s->regs[WDT_STATUS] = s->regs[WDT_RELOAD_VALUE];
194
+ aspeed_wdt_reload(s, !(data & WDT_CTRL_1MHZ_CLK));
195
+ }
196
+ break;
197
+ case WDT_CTRL:
198
+ if (enable && !aspeed_wdt_is_enabled(s)) {
199
+ s->regs[WDT_CTRL] = data;
200
+ aspeed_wdt_reload(s, !(data & WDT_CTRL_1MHZ_CLK));
201
+ } else if (!enable && aspeed_wdt_is_enabled(s)) {
202
+ s->regs[WDT_CTRL] = data;
203
+ timer_del(s->timer);
204
+ }
205
+ break;
206
+ case WDT_TIMEOUT_STATUS:
207
+ case WDT_TIMEOUT_CLEAR:
208
+ case WDT_RESET_WDITH:
209
+ qemu_log_mask(LOG_UNIMP,
641
+ qemu_log_mask(LOG_UNIMP,
210
+ "%s: uninmplemented write at offset 0x%" HWADDR_PRIx "\n",
642
+ "%s: register @ 0x%04" HWADDR_PRIx " is not implemented\n",
211
+ __func__, offset);
643
+ __func__, offset);
212
+ break;
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
+
213
+ default:
670
+ default:
214
+ qemu_log_mask(LOG_GUEST_ERROR,
671
+ qemu_log_mask(LOG_GUEST_ERROR,
215
+ "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
672
+ "%s: invalid offset 0x%04" HWADDR_PRIx "\n",
216
+ __func__, offset);
673
+ __func__, offset);
217
+ }
674
+ break;
218
+ return;
675
+ }
219
+}
676
+}
220
+
677
+
221
+static WatchdogTimerModel model = {
678
+static const struct MemoryRegionOps npcm7xx_pwm_ops = {
222
+ .wdt_name = TYPE_ASPEED_WDT,
679
+ .read = npcm7xx_pwm_read,
223
+ .wdt_description = "Aspeed watchdog device",
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
+ },
224
+};
687
+};
225
+
688
+
226
+static const VMStateDescription vmstate_aspeed_wdt = {
689
+static void npcm7xx_pwm_enter_reset(Object *obj, ResetType type)
227
+ .name = "vmstate_aspeed_wdt",
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",
228
+ .version_id = 0,
748
+ .version_id = 0,
229
+ .minimum_version_id = 0,
749
+ .minimum_version_id = 0,
230
+ .fields = (VMStateField[]) {
750
+ .fields = (VMStateField[]) {
231
+ VMSTATE_TIMER_PTR(timer, AspeedWDTState),
751
+ VMSTATE_BOOL(running, NPCM7xxPWM),
232
+ VMSTATE_UINT32_ARRAY(regs, AspeedWDTState, ASPEED_WDT_REGS_MAX),
752
+ VMSTATE_BOOL(inverted, NPCM7xxPWM),
233
+ VMSTATE_END_OF_LIST()
753
+ VMSTATE_UINT8(index, NPCM7xxPWM),
234
+ }
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
+ },
235
+};
762
+};
236
+
763
+
237
+static const MemoryRegionOps aspeed_wdt_ops = {
764
+static const VMStateDescription vmstate_npcm7xx_pwm_module = {
238
+ .read = aspeed_wdt_read,
765
+ .name = "npcm7xx-pwm-module",
239
+ .write = aspeed_wdt_write,
766
+ .version_id = 0,
240
+ .endianness = DEVICE_LITTLE_ENDIAN,
767
+ .minimum_version_id = 0,
241
+ .valid.min_access_size = 4,
768
+ .fields = (VMStateField[]) {
242
+ .valid.max_access_size = 4,
769
+ VMSTATE_CLOCK(clock, NPCM7xxPWMState),
243
+ .valid.unaligned = false,
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
+ },
244
+};
780
+};
245
+
781
+
246
+static void aspeed_wdt_reset(DeviceState *dev)
782
+static void npcm7xx_pwm_class_init(ObjectClass *klass, void *data)
247
+{
783
+{
248
+ AspeedWDTState *s = ASPEED_WDT(dev);
784
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
249
+
250
+ s->regs[WDT_STATUS] = 0x3EF1480;
251
+ s->regs[WDT_RELOAD_VALUE] = 0x03EF1480;
252
+ s->regs[WDT_RESTART] = 0;
253
+ s->regs[WDT_CTRL] = 0;
254
+
255
+ timer_del(s->timer);
256
+}
257
+
258
+static void aspeed_wdt_timer_expired(void *dev)
259
+{
260
+ AspeedWDTState *s = ASPEED_WDT(dev);
261
+
262
+ qemu_log_mask(CPU_LOG_RESET, "Watchdog timer expired.\n");
263
+ watchdog_perform_action();
264
+ timer_del(s->timer);
265
+}
266
+
267
+#define PCLK_HZ 24000000
268
+
269
+static void aspeed_wdt_realize(DeviceState *dev, Error **errp)
270
+{
271
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
272
+ AspeedWDTState *s = ASPEED_WDT(dev);
273
+
274
+ s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, aspeed_wdt_timer_expired, dev);
275
+
276
+ /* FIXME: This setting should be derived from the SCU hw strapping
277
+ * register SCU70
278
+ */
279
+ s->pclk_freq = PCLK_HZ;
280
+
281
+ memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_wdt_ops, s,
282
+ TYPE_ASPEED_WDT, ASPEED_WDT_REGS_MAX * 4);
283
+ sysbus_init_mmio(sbd, &s->iomem);
284
+}
285
+
286
+static void aspeed_wdt_class_init(ObjectClass *klass, void *data)
287
+{
288
+ DeviceClass *dc = DEVICE_CLASS(klass);
785
+ DeviceClass *dc = DEVICE_CLASS(klass);
289
+
786
+
290
+ dc->realize = aspeed_wdt_realize;
787
+ dc->desc = "NPCM7xx PWM Controller";
291
+ dc->reset = aspeed_wdt_reset;
788
+ dc->vmsd = &vmstate_npcm7xx_pwm_module;
292
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
789
+ rc->phases.enter = npcm7xx_pwm_enter_reset;
293
+ dc->vmsd = &vmstate_aspeed_wdt;
790
+ rc->phases.hold = npcm7xx_pwm_hold_reset;
294
+}
791
+}
295
+
792
+
296
+static const TypeInfo aspeed_wdt_info = {
793
+static const TypeInfo npcm7xx_pwm_info = {
297
+ .parent = TYPE_SYS_BUS_DEVICE,
794
+ .name = TYPE_NPCM7XX_PWM,
298
+ .name = TYPE_ASPEED_WDT,
795
+ .parent = TYPE_SYS_BUS_DEVICE,
299
+ .instance_size = sizeof(AspeedWDTState),
796
+ .instance_size = sizeof(NPCM7xxPWMState),
300
+ .class_init = aspeed_wdt_class_init,
797
+ .class_init = npcm7xx_pwm_class_init,
798
+ .instance_init = npcm7xx_pwm_init,
301
+};
799
+};
302
+
800
+
303
+static void wdt_aspeed_register_types(void)
801
+static void npcm7xx_pwm_register_type(void)
304
+{
802
+{
305
+ watchdog_add_model(&model);
803
+ type_register_static(&npcm7xx_pwm_info);
306
+ type_register_static(&aspeed_wdt_info);
804
+}
307
+}
805
+type_init(npcm7xx_pwm_register_type);
308
+
806
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
309
+type_init(wdt_aspeed_register_types)
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"
310
--
835
--
311
2.7.4
836
2.20.1
312
837
313
838
diff view generated by jsdifflib
1
From: Julian Brown <julian@codesourcery.com>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
Since the integratorcp board creates the CPU object directly
3
We add a qtest for the PWM in the previous patch. It proves it works as
4
rather than via cpu_arm_init(), we have to call the CPU
4
expected.
5
class parse_features() method ourselves if we want to
6
support the user passing features via the -cpu command
7
line argument as well as just the cpu name. Do so.
8
5
9
Signed-off-by: Julian Brown <julian@codesourcery.com>
6
Reviewed-by: Havard Skinnemoen <hskinnemoen@google.com>
10
[PMM: split out into its own patch]
7
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
8
Signed-off-by: Hao Wu <wuhaotsh@google.com>
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
10
Message-id: 20210108190945.949196-6-wuhaotsh@google.com
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
---
12
---
14
hw/arm/integratorcp.c | 19 +++++++++++++++++--
13
tests/qtest/npcm7xx_pwm-test.c | 490 +++++++++++++++++++++++++++++++++
15
1 file changed, 17 insertions(+), 2 deletions(-)
14
tests/qtest/meson.build | 1 +
15
2 files changed, 491 insertions(+)
16
create mode 100644 tests/qtest/npcm7xx_pwm-test.c
16
17
17
diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c
18
diff --git a/tests/qtest/npcm7xx_pwm-test.c b/tests/qtest/npcm7xx_pwm-test.c
19
new file mode 100644
20
index XXXXXXX..XXXXXXX
21
--- /dev/null
22
+++ b/tests/qtest/npcm7xx_pwm-test.c
23
@@ -XXX,XX +XXX,XX @@
24
+/*
25
+ * QTests for Nuvoton NPCM7xx PWM Modules.
26
+ *
27
+ * Copyright 2020 Google LLC
28
+ *
29
+ * This program is free software; you can redistribute it and/or modify it
30
+ * under the terms of the GNU General Public License as published by the
31
+ * Free Software Foundation; either version 2 of the License, or
32
+ * (at your option) any later version.
33
+ *
34
+ * This program is distributed in the hope that it will be useful, but WITHOUT
35
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
36
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
37
+ * for more details.
38
+ */
39
+
40
+#include "qemu/osdep.h"
41
+#include "qemu/bitops.h"
42
+#include "libqos/libqtest.h"
43
+#include "qapi/qmp/qdict.h"
44
+#include "qapi/qmp/qnum.h"
45
+
46
+#define REF_HZ 25000000
47
+
48
+/* Register field definitions. */
49
+#define CH_EN BIT(0)
50
+#define CH_INV BIT(2)
51
+#define CH_MOD BIT(3)
52
+
53
+/* Registers shared between all PWMs in a module */
54
+#define PPR 0x00
55
+#define CSR 0x04
56
+#define PCR 0x08
57
+#define PIER 0x3c
58
+#define PIIR 0x40
59
+
60
+/* CLK module related */
61
+#define CLK_BA 0xf0801000
62
+#define CLKSEL 0x04
63
+#define CLKDIV1 0x08
64
+#define CLKDIV2 0x2c
65
+#define PLLCON0 0x0c
66
+#define PLLCON1 0x10
67
+#define PLL_INDV(rv) extract32((rv), 0, 6)
68
+#define PLL_FBDV(rv) extract32((rv), 16, 12)
69
+#define PLL_OTDV1(rv) extract32((rv), 8, 3)
70
+#define PLL_OTDV2(rv) extract32((rv), 13, 3)
71
+#define APB3CKDIV(rv) extract32((rv), 28, 2)
72
+#define CLK2CKDIV(rv) extract32((rv), 0, 1)
73
+#define CLK4CKDIV(rv) extract32((rv), 26, 2)
74
+#define CPUCKSEL(rv) extract32((rv), 0, 2)
75
+
76
+#define MAX_DUTY 1000000
77
+
78
+typedef struct PWMModule {
79
+ int irq;
80
+ uint64_t base_addr;
81
+} PWMModule;
82
+
83
+typedef struct PWM {
84
+ uint32_t cnr_offset;
85
+ uint32_t cmr_offset;
86
+ uint32_t pdr_offset;
87
+ uint32_t pwdr_offset;
88
+} PWM;
89
+
90
+typedef struct TestData {
91
+ const PWMModule *module;
92
+ const PWM *pwm;
93
+} TestData;
94
+
95
+static const PWMModule pwm_module_list[] = {
96
+ {
97
+ .irq = 93,
98
+ .base_addr = 0xf0103000
99
+ },
100
+ {
101
+ .irq = 94,
102
+ .base_addr = 0xf0104000
103
+ }
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);
384
+
385
+ qtest_quit(qts);
386
+}
387
+
388
+/* One-shot mode should not change frequency and duty cycle. */
389
+static void test_oneshot(gconstpointer test_data)
390
+{
391
+ const TestData *td = test_data;
392
+ QTestState *qts = qtest_init("-machine quanta-gsj");
393
+ int module = pwm_module_index(td->module);
394
+ int pwm = pwm_index(td->pwm);
395
+ uint32_t ppr, csr, pcr;
396
+ int i, j;
397
+
398
+ pcr = CH_EN;
399
+ for (i = 0; i < ARRAY_SIZE(ppr_list); ++i) {
400
+ ppr = ppr_list[i];
401
+ pwm_write_ppr(qts, td, ppr);
402
+
403
+ for (j = 0; j < ARRAY_SIZE(csr_list); ++j) {
404
+ csr = csr_list[j];
405
+ pwm_write_csr(qts, td, csr);
406
+ pwm_write_pcr(qts, td, pcr);
407
+
408
+ g_assert_cmpuint(pwm_read_ppr(qts, td), ==, ppr);
409
+ g_assert_cmpuint(pwm_read_csr(qts, td), ==, csr);
410
+ g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr);
411
+ g_assert_cmpuint(pwm_get_freq(qts, module, pwm), ==, 0);
412
+ g_assert_cmpuint(pwm_get_duty(qts, module, pwm), ==, 0);
413
+ }
414
+ }
415
+
416
+ qtest_quit(qts);
417
+}
418
+
419
+/* In toggle mode, the PWM generates correct outputs. */
420
+static void test_toggle(gconstpointer test_data)
421
+{
422
+ const TestData *td = test_data;
423
+ QTestState *qts = qtest_init("-machine quanta-gsj");
424
+ int module = pwm_module_index(td->module);
425
+ int pwm = pwm_index(td->pwm);
426
+ uint32_t ppr, csr, pcr, cnr, cmr;
427
+ int i, j, k, l;
428
+ uint64_t expected_freq, expected_duty;
429
+
430
+ pcr = CH_EN | CH_MOD;
431
+ for (i = 0; i < ARRAY_SIZE(ppr_list); ++i) {
432
+ ppr = ppr_list[i];
433
+ pwm_write_ppr(qts, td, ppr);
434
+
435
+ for (j = 0; j < ARRAY_SIZE(csr_list); ++j) {
436
+ csr = csr_list[j];
437
+ pwm_write_csr(qts, td, csr);
438
+
439
+ for (k = 0; k < ARRAY_SIZE(cnr_list); ++k) {
440
+ cnr = cnr_list[k];
441
+ pwm_write_cnr(qts, td, cnr);
442
+
443
+ for (l = 0; l < ARRAY_SIZE(cmr_list); ++l) {
444
+ cmr = cmr_list[l];
445
+ pwm_write_cmr(qts, td, cmr);
446
+ expected_freq = pwm_compute_freq(qts, ppr, csr, cnr);
447
+ expected_duty = pwm_compute_duty(cnr, cmr, false);
448
+
449
+ pwm_write_pcr(qts, td, pcr);
450
+ g_assert_cmpuint(pwm_read_ppr(qts, td), ==, ppr);
451
+ g_assert_cmpuint(pwm_read_csr(qts, td), ==, csr);
452
+ g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr);
453
+ g_assert_cmpuint(pwm_read_cnr(qts, td), ==, cnr);
454
+ g_assert_cmpuint(pwm_read_cmr(qts, td), ==, cmr);
455
+ g_assert_cmpuint(pwm_get_duty(qts, module, pwm),
456
+ ==, expected_duty);
457
+ if (expected_duty != 0 && expected_duty != 100) {
458
+ /* Duty cycle with 0 or 100 doesn't need frequency. */
459
+ g_assert_cmpuint(pwm_get_freq(qts, module, pwm),
460
+ ==, expected_freq);
461
+ }
462
+
463
+ /* Test inverted mode */
464
+ expected_duty = pwm_compute_duty(cnr, cmr, true);
465
+ pwm_write_pcr(qts, td, pcr | CH_INV);
466
+ g_assert_cmpuint(pwm_read_pcr(qts, td), ==, pcr | CH_INV);
467
+ g_assert_cmpuint(pwm_get_duty(qts, module, pwm),
468
+ ==, expected_duty);
469
+ if (expected_duty != 0 && expected_duty != 100) {
470
+ /* Duty cycle with 0 or 100 doesn't need frequency. */
471
+ g_assert_cmpuint(pwm_get_freq(qts, module, pwm),
472
+ ==, expected_freq);
473
+ }
474
+
475
+ }
476
+ }
477
+ }
478
+ }
479
+
480
+ qtest_quit(qts);
481
+}
482
+
483
+static void pwm_add_test(const char *name, const TestData* td,
484
+ GTestDataFunc fn)
485
+{
486
+ g_autofree char *full_name = g_strdup_printf(
487
+ "npcm7xx_pwm/module[%d]/pwm[%d]/%s", pwm_module_index(td->module),
488
+ pwm_index(td->pwm), name);
489
+ qtest_add_data_func(full_name, td, fn);
490
+}
491
+#define add_test(name, td) pwm_add_test(#name, td, test_##name)
492
+
493
+int main(int argc, char **argv)
494
+{
495
+ TestData test_data_list[ARRAY_SIZE(pwm_module_list) * ARRAY_SIZE(pwm_list)];
496
+
497
+ g_test_init(&argc, &argv, NULL);
498
+
499
+ for (int i = 0; i < ARRAY_SIZE(pwm_module_list); ++i) {
500
+ for (int j = 0; j < ARRAY_SIZE(pwm_list); ++j) {
501
+ TestData *td = &test_data_list[i * ARRAY_SIZE(pwm_list) + j];
502
+
503
+ td->module = &pwm_module_list[i];
504
+ td->pwm = &pwm_list[j];
505
+
506
+ add_test(init, td);
507
+ add_test(oneshot, td);
508
+ add_test(toggle, td);
509
+ }
510
+ }
511
+
512
+ return g_test_run();
513
+}
514
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
18
index XXXXXXX..XXXXXXX 100644
515
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/arm/integratorcp.c
516
--- a/tests/qtest/meson.build
20
+++ b/hw/arm/integratorcp.c
517
+++ b/tests/qtest/meson.build
21
@@ -XXX,XX +XXX,XX @@ static void integratorcp_init(MachineState *machine)
518
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
22
const char *kernel_filename = machine->kernel_filename;
519
qtests_npcm7xx = \
23
const char *kernel_cmdline = machine->kernel_cmdline;
520
['npcm7xx_adc-test',
24
const char *initrd_filename = machine->initrd_filename;
521
'npcm7xx_gpio-test',
25
+ char **cpustr;
522
+ 'npcm7xx_pwm-test',
26
ObjectClass *cpu_oc;
523
'npcm7xx_rng-test',
27
+ CPUClass *cc;
524
'npcm7xx_timer-test',
28
Object *cpuobj;
525
'npcm7xx_watchdog_timer-test']
29
ARMCPU *cpu;
30
+ const char *typename;
31
MemoryRegion *address_space_mem = get_system_memory();
32
MemoryRegion *ram = g_new(MemoryRegion, 1);
33
MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
34
qemu_irq pic[32];
35
DeviceState *dev, *sic, *icp;
36
int i;
37
+ Error *err = NULL;
38
39
if (!cpu_model) {
40
cpu_model = "arm926";
41
}
42
43
- cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
44
+ cpustr = g_strsplit(cpu_model, ",", 2);
45
+
46
+ cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpustr[0]);
47
if (!cpu_oc) {
48
fprintf(stderr, "Unable to find CPU definition\n");
49
exit(1);
50
}
51
+ typename = object_class_get_name(cpu_oc);
52
+
53
+ cc = CPU_CLASS(cpu_oc);
54
+ cc->parse_features(typename, cpustr[1], &err);
55
+ g_strfreev(cpustr);
56
+ if (err) {
57
+ error_report_err(err);
58
+ exit(1);
59
+ }
60
61
- cpuobj = object_new(object_class_get_name(cpu_oc));
62
+ cpuobj = object_new(typename);
63
64
/* By default ARM1176 CPUs have EL3 enabled. This board does not
65
* currently support EL3 so the CPU EL3 property is disabled before
66
--
526
--
67
2.7.4
527
2.20.1
68
528
69
529
diff view generated by jsdifflib
1
From: Cédric Le Goater <clg@kaod.org>
1
From: Hao Wu <wuhaotsh@google.com>
2
2
3
This enables reboot of a guest from U-Boot and Linux.
3
A device shouldn't access its parent object which is QOM internal.
4
Instead it should use type cast for this purporse. This patch fixes this
5
issue for all NPCM7XX Devices.
4
6
5
Signed-off-by: Cédric Le Goater <clg@kaod.org>
7
Signed-off-by: Hao Wu <wuhaotsh@google.com>
6
Reviewed-by: Joel Stanley <joel@jms.id.au>
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Message-id: 1485452251-1593-3-git-send-email-clg@kaod.org
9
Message-id: 20210108190945.949196-7-wuhaotsh@google.com
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
---
11
---
10
include/hw/arm/aspeed_soc.h | 2 ++
12
hw/arm/npcm7xx_boards.c | 2 +-
11
hw/arm/aspeed_soc.c | 13 +++++++++++++
13
hw/mem/npcm7xx_mc.c | 2 +-
12
2 files changed, 15 insertions(+)
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(-)
13
20
14
diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h
21
diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c
15
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
16
--- a/include/hw/arm/aspeed_soc.h
23
--- a/hw/arm/npcm7xx_boards.c
17
+++ b/include/hw/arm/aspeed_soc.h
24
+++ b/hw/arm/npcm7xx_boards.c
18
@@ -XXX,XX +XXX,XX @@
25
@@ -XXX,XX +XXX,XX @@ static NPCM7xxState *npcm7xx_create_soc(MachineState *machine,
19
#include "hw/timer/aspeed_timer.h"
26
uint32_t hw_straps)
20
#include "hw/i2c/aspeed_i2c.h"
27
{
21
#include "hw/ssi/aspeed_smc.h"
28
NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_GET_CLASS(machine);
22
+#include "hw/watchdog/wdt_aspeed.h"
29
- MachineClass *mc = &nmc->parent;
23
30
+ MachineClass *mc = MACHINE_CLASS(nmc);
24
#define ASPEED_SPIS_NUM 2
31
Object *obj;
25
32
26
@@ -XXX,XX +XXX,XX @@ typedef struct AspeedSoCState {
33
if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) {
27
AspeedSMCState fmc;
34
diff --git a/hw/mem/npcm7xx_mc.c b/hw/mem/npcm7xx_mc.c
28
AspeedSMCState spi[ASPEED_SPIS_NUM];
29
AspeedSDMCState sdmc;
30
+ AspeedWDTState wdt;
31
} AspeedSoCState;
32
33
#define TYPE_ASPEED_SOC "aspeed-soc"
34
diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c
35
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
36
--- a/hw/arm/aspeed_soc.c
36
--- a/hw/mem/npcm7xx_mc.c
37
+++ b/hw/arm/aspeed_soc.c
37
+++ b/hw/mem/npcm7xx_mc.c
38
@@ -XXX,XX +XXX,XX @@
38
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_mc_realize(DeviceState *dev, Error **errp)
39
#define ASPEED_SOC_SCU_BASE 0x1E6E2000
39
40
#define ASPEED_SOC_SRAM_BASE 0x1E720000
40
memory_region_init_io(&s->mmio, OBJECT(s), &npcm7xx_mc_ops, s, "regs",
41
#define ASPEED_SOC_TIMER_BASE 0x1E782000
41
NPCM7XX_MC_REGS_SIZE);
42
+#define ASPEED_SOC_WDT_BASE 0x1E785000
42
- sysbus_init_mmio(&s->parent, &s->mmio);
43
#define ASPEED_SOC_I2C_BASE 0x1E78A000
43
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio);
44
45
static const int uart_irqs[] = { 9, 32, 33, 34, 10 };
46
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_init(Object *obj)
47
sc->info->silicon_rev);
48
object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc),
49
"ram-size", &error_abort);
50
+
51
+ object_initialize(&s->wdt, sizeof(s->wdt), TYPE_ASPEED_WDT);
52
+ object_property_add_child(obj, "wdt", OBJECT(&s->wdt), NULL);
53
+ qdev_set_parent_bus(DEVICE(&s->wdt), sysbus_get_default());
54
}
44
}
55
45
56
static void aspeed_soc_realize(DeviceState *dev, Error **errp)
46
static void npcm7xx_mc_class_init(ObjectClass *klass, void *data)
57
@@ -XXX,XX +XXX,XX @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
47
diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
58
return;
48
index XXXXXXX..XXXXXXX 100644
59
}
49
--- a/hw/misc/npcm7xx_clk.c
60
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, ASPEED_SOC_SDMC_BASE);
50
+++ b/hw/misc/npcm7xx_clk.c
61
+
51
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_init(Object *obj)
62
+ /* Watch dog */
52
63
+ object_property_set_bool(OBJECT(&s->wdt), true, "realized", &err);
53
memory_region_init_io(&s->iomem, obj, &npcm7xx_clk_ops, s,
64
+ if (err) {
54
TYPE_NPCM7XX_CLK, 4 * KiB);
65
+ error_propagate(errp, err);
55
- sysbus_init_mmio(&s->parent, &s->iomem);
66
+ return;
56
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
67
+ }
68
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt), 0, ASPEED_SOC_WDT_BASE);
69
}
57
}
70
58
71
static void aspeed_soc_class_init(ObjectClass *oc, void *data)
59
static int npcm7xx_clk_post_load(void *opaque, int version_id)
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)
91
{
92
NPCM7xxOTPClass *oc = NPCM7XX_OTP_GET_CLASS(dev);
93
NPCM7xxOTPState *s = NPCM7XX_OTP(dev);
94
- SysBusDevice *sbd = &s->parent;
95
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
96
97
memset(s->array, 0, sizeof(s->array));
98
99
diff --git a/hw/ssi/npcm7xx_fiu.c b/hw/ssi/npcm7xx_fiu.c
100
index XXXXXXX..XXXXXXX 100644
101
--- a/hw/ssi/npcm7xx_fiu.c
102
+++ b/hw/ssi/npcm7xx_fiu.c
103
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_fiu_hold_reset(Object *obj)
104
static void npcm7xx_fiu_realize(DeviceState *dev, Error **errp)
105
{
106
NPCM7xxFIUState *s = NPCM7XX_FIU(dev);
107
- SysBusDevice *sbd = &s->parent;
108
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
109
int i;
110
111
if (s->cs_count <= 0) {
72
--
112
--
73
2.7.4
113
2.20.1
74
114
75
115
diff view generated by jsdifflib
1
Use the 'unimplemented' dummy device to cover regions of the
1
From: Roman Bolshakov <r.bolshakov@yadro.com>
2
SoC device memory map which we don't have proper device
3
implementations for yet.
4
2
3
ui/cocoa.m:1188:44: warning: 'openFile:' is deprecated: first deprecated in macOS 11.0 - Use -[NSWorkspace openURL:] instead.
4
[-Wdeprecated-declarations]
5
if ([[NSWorkspace sharedWorkspace] openFile: full_file_path] == YES) {
6
^
7
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/AppKit.framework/Headers/NSWorkspace.h:350:1: note:
8
'openFile:' has been explicitly marked deprecated here
9
- (BOOL)openFile:(NSString *)fullPath API_DEPRECATED("Use -[NSWorkspace openURL:] instead.", macos(10.0, 11.0));
10
^
11
12
Signed-off-by: Roman Bolshakov <r.bolshakov@yadro.com>
13
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
14
Message-id: 20210102150718.47618-1-r.bolshakov@yadro.com
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
7
Message-id: 1484247815-15279-4-git-send-email-peter.maydell@linaro.org
8
---
16
---
9
hw/arm/stellaris.c | 14 ++++++++++++++
17
ui/cocoa.m | 5 ++++-
10
1 file changed, 14 insertions(+)
18
1 file changed, 4 insertions(+), 1 deletion(-)
11
19
12
diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
20
diff --git a/ui/cocoa.m b/ui/cocoa.m
13
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/arm/stellaris.c
22
--- a/ui/cocoa.m
15
+++ b/hw/arm/stellaris.c
23
+++ b/ui/cocoa.m
16
@@ -XXX,XX +XXX,XX @@
24
@@ -XXX,XX +XXX,XX @@ QemuCocoaView *cocoaView;
17
#include "exec/address-spaces.h"
25
/* Where to look for local files */
18
#include "sysemu/sysemu.h"
26
NSString *path_array[] = {@"../share/doc/qemu/", @"../doc/qemu/", @"docs/"};
19
#include "hw/char/pl011.h"
27
NSString *full_file_path;
20
+#include "hw/misc/unimp.h"
28
+ NSURL *full_file_url;
21
29
22
#define GPIO_A 0
30
/* iterate thru the possible paths until the file is found */
23
#define GPIO_B 1
31
int index;
24
@@ -XXX,XX +XXX,XX @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
32
@@ -XXX,XX +XXX,XX @@ QemuCocoaView *cocoaView;
25
}
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;
26
}
41
}
27
}
42
}
28
+
29
+ /* Add dummy regions for the devices we don't implement yet,
30
+ * so guest accesses don't cause unlogged crashes.
31
+ */
32
+ create_unimplemented_device("wdtimer", 0x40000000, 0x1000);
33
+ create_unimplemented_device("i2c-0", 0x40002000, 0x1000);
34
+ create_unimplemented_device("i2c-2", 0x40021000, 0x1000);
35
+ create_unimplemented_device("PWM", 0x40028000, 0x1000);
36
+ create_unimplemented_device("QEI-0", 0x4002c000, 0x1000);
37
+ create_unimplemented_device("QEI-1", 0x4002d000, 0x1000);
38
+ create_unimplemented_device("analogue-comparator", 0x4003c000, 0x1000);
39
+ create_unimplemented_device("hibernation", 0x400fc000, 0x1000);
40
+ create_unimplemented_device("flash-control", 0x400fd000, 0x1000);
41
}
42
43
/* FIXME: Figure out how to generate these from stellaris_boards. */
44
--
43
--
45
2.7.4
44
2.20.1
46
45
47
46
diff view generated by jsdifflib