1
target-arm queue: this clears out a bunch of patches I'd sent over
1
Last minute pullreq for arm related patches; quite large because
2
the last coupled of weeks that have now got reviewed. Mostly
2
there were several series that only just made it through code review
3
this is MPS2 device support improvements, put there is also
3
in time.
4
more of the incremental work towards supporting AArch32 Hyp mode,
5
a floating point bugfix, and the raspi framebuffer viewport support.
6
4
7
thanks
5
thanks
8
-- PMM
6
-- PMM
9
7
10
The following changes since commit 5ccac548faf041ff5229a8e8342e3be14a34c8af:
8
The following changes since commit 091e3e3dbc499d84c004e1c50bc9870af37f6e99:
11
9
12
Merge remote-tracking branch 'remotes/cody/tags/block-pull-request' into staging (2018-08-23 17:35:48 +0100)
10
Merge remote-tracking branch 'remotes/ericb/tags/pull-bitmaps-2020-10-26' into staging (2020-10-26 22:36:35 +0000)
13
11
14
are available in the Git repository at:
12
are available in the Git repository at:
15
13
16
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20180824
14
https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20201027-1
17
15
18
for you to fetch changes up to 30a719e3cb5c5367f3651eba8fa935634bfee286:
16
for you to fetch changes up to 32bd322a0134ed89db00f2b9b3894982db3dedcb:
19
17
20
hw/arm/mps2: Fix ID register errors on AN511 and AN385 (2018-08-24 10:22:44 +0100)
18
hw/timer/armv7m_systick: Rewrite to use ptimers (2020-10-27 11:15:31 +0000)
21
19
22
----------------------------------------------------------------
20
----------------------------------------------------------------
23
target-arm queue:
21
target-arm queue:
24
* Fix rounding errors in scaling float-to-int and int-to-float operations
22
* raspi: add model of cprman clock manager
25
* Connect virtualization-related IRQs and memory regions of GICv2
23
* sbsa-ref: add an SBSA generic watchdog device
26
in boards that use Cortex-A7 or Cortex-A15
24
* arm/trace: Fix hex printing
27
* Support taking exceptions to AArch32 Hyp mode
25
* raspi: Add models of Pi 3 model A+, Pi Zero and Pi A+
28
* Clear CPSR.IL and CPSR.J on 32-bit exception entry
26
* hw/arm/smmuv3: Set the restoration priority of the vSMMUv3 explicitly
29
(a minor bug fix that won't affect non-buggy guest code)
27
* Nuvoton NPCM7xx: Add USB, RNG, GPIO and watchdog support
30
* mps2-an505: Implement various missing devices:
28
* hw/arm: fix min_cpus for xlnx-versal-virt platform
31
dual timer, watchdogs, counters in the FPGAIO registers,
29
* hw/arm/highbank: Silence warnings about missing fallthrough statements
32
some missing ID/control registers, TrustZone Master Security
30
* linux-user: Support Aarch64 BTI
33
Controllers, PL081 DMA controllers, PL022 SPI controllers
31
* Armv7M systick: fix corner case bugs by rewriting to use ptimer
34
* correct ID register values for mps2-an385, -an511, -an505
35
* fix some hardcoded tabs in untouched backwaters of the
36
target/arm codebase
37
* raspi: Refactor framebuffer property handling code and implement
38
support for the virtual framebuffer/viewport
39
32
40
----------------------------------------------------------------
33
----------------------------------------------------------------
41
Peter Maydell (48):
34
Dr. David Alan Gilbert (1):
42
hw/intc/arm_gic: Make per-cpu GICH memory regions 0x200 bytes large
35
arm/trace: Fix hex printing
43
hw/arm/vexpress: Connect VIRQ and VFIQ
44
hw/arm/highbank: Connect VIRQ and VFIQ
45
hw/arm/fsl-imx6ul: Connect VIRQ and VFIQ
46
hw/arm/fsl-imx6ul: Connect VIRQ and VFIQ
47
hw/cpu/a15mpcore: If CPU has EL2, enable it on the GIC and wire it up
48
hw/arm/vexpress: Don't set info->secure_boot if CPU doesn't have EL3
49
hw/arm/vexpress: Add "virtualization" property controlling presence of EL2
50
target/arm: Implement RAZ/WI HACTLR2
51
target/arm: Implement AArch32 HCR and HCR2
52
target/arm: Factor out code for taking an AArch32 exception
53
target/arm: Implement support for taking exceptions to Hyp mode
54
target/arm: Clear CPSR.IL and CPSR.J on 32-bit exception entry
55
hw/arm/boot: AArch32 kernels should be started in Hyp mode if available
56
hw/misc/mps2-fpgaio: Implement 1Hz and 100Hz counters
57
hw/misc/mps2-fpgaio: Implement PSCNTR and COUNTER
58
hw/timer/cmsdk-apb-dualtimer: Implement CMSDK dual timer module
59
hw/arm/iotkit: Wire up the dualtimer
60
hw/arm/mps2: Wire up dual-timer in mps2-an385 and mps2-an511
61
hw/arm/iotkit: Wire up the watchdogs
62
hw/arm/iotkit: Wire up the S32KTIMER
63
hw/misc/iotkit-sysctl: Implement IoTKit system control element
64
hw/misc/iotkit-sysinfo: Implement IoTKit system information block
65
hw/misc/iotkit: Wire up the sysctl and sysinfo register blocks
66
hw/misc/tz-msc: Model TrustZone Master Security Controller
67
hw/misc/iotkit-secctl: Wire up registers for controlling MSCs
68
hw/arm/iotkit: Wire up the lines for MSCs
69
hw/arm/mps2-tz: Create PL081s and MSCs
70
hw/ssi/pl022: Allow use as embedded-struct device
71
hw/ssi/pl022: Set up reset function in class init
72
hw/ssi/pl022: Don't directly call vmstate_register()
73
hw/ssi/pl022: Use DeviceState::realize rather than SysBusDevice::init
74
hw/ssi/pl022: Correct wrong value for PL022_INT_RT
75
hw/ssi/pl022: Correct wrong DMACR and ICR handling
76
hw/arm/mps2-tz: Instantiate SPI controllers
77
hw/arm/mps2-tz: Fix MPS2 SCC config register values
78
target/arm: Untabify translate.c
79
target/arm: Untabify iwmmxt_helper.c
80
target/arm: Remove a handful of stray tabs
81
hw/misc/bcm2835_fb: Move config fields to their own struct
82
hw/misc/bcm2835_property: Track fb settings using BCM2835FBConfig
83
hw/display/bcm2835_fb: Drop unused size and pitch fields
84
hw/display/bcm2835_fb: Reset resolution, etc correctly
85
hw/display/bcm2835_fb: Abstract out calculation of pitch, size
86
hw/display/bcm2835_fb: Fix handling of virtual framebuffer
87
hw/display/bcm2835_fb: Validate config settings
88
hw/display/bcm2835_fb: Validate bcm2835_fb_mbox_push() config
89
hw/arm/mps2: Fix ID register errors on AN511 and AN385
90
36
91
Richard Henderson (4):
37
Hao Wu (1):
92
softfloat: Add scaling int-to-float routines
38
hw/timer: Adding watchdog for NPCM7XX Timer.
93
softfloat: Add scaling float-to-int routines
94
target/arm: Use the int-to-float-scale softfloat routines
95
target/arm: Use the float-to-int-scale softfloat routines
96
39
97
hw/misc/Makefile.objs | 3 +
40
Havard Skinnemoen (4):
98
hw/timer/Makefile.objs | 1 +
41
Move npcm7xx_timer_reached_zero call out of npcm7xx_timer_pause
99
include/fpu/softfloat.h | 169 +++++++---
42
hw/misc: Add npcm7xx random number generator
100
include/hw/arm/iotkit.h | 25 +-
43
hw/arm/npcm7xx: Add EHCI and OHCI controllers
101
include/hw/display/bcm2835_fb.h | 59 +++-
44
hw/gpio: Add GPIO model for Nuvoton NPCM7xx
102
include/hw/misc/iotkit-secctl.h | 14 +
103
include/hw/misc/iotkit-sysctl.h | 49 +++
104
include/hw/misc/iotkit-sysinfo.h | 37 +++
105
include/hw/misc/mps2-fpgaio.h | 10 +
106
include/hw/misc/tz-msc.h | 79 +++++
107
include/hw/ssi/pl022.h | 51 +++
108
include/hw/timer/cmsdk-apb-dualtimer.h | 72 ++++
109
target/arm/cpu.h | 16 +-
110
fpu/softfloat.c | 579 ++++++++++++++++++++++++++-------
111
hw/arm/boot.c | 11 +
112
hw/arm/fsl-imx6ul.c | 4 +
113
hw/arm/fsl-imx7.c | 4 +
114
hw/arm/highbank.c | 6 +
115
hw/arm/iotkit.c | 114 ++++++-
116
hw/arm/mps2-tz.c | 142 +++++++-
117
hw/arm/mps2.c | 17 +-
118
hw/arm/vexpress.c | 64 +++-
119
hw/cpu/a15mpcore.c | 31 +-
120
hw/display/bcm2835_fb.c | 218 ++++++++-----
121
hw/intc/arm_gic.c | 2 +-
122
hw/misc/bcm2835_property.c | 123 ++++---
123
hw/misc/iotkit-secctl.c | 73 ++++-
124
hw/misc/iotkit-sysctl.c | 261 +++++++++++++++
125
hw/misc/iotkit-sysinfo.c | 128 ++++++++
126
hw/misc/mps2-fpgaio.c | 146 ++++++++-
127
hw/misc/tz-msc.c | 308 ++++++++++++++++++
128
hw/ssi/pl022.c | 57 ++--
129
hw/timer/cmsdk-apb-dualtimer.c | 515 +++++++++++++++++++++++++++++
130
target/arm/arm-semi.c | 2 +-
131
target/arm/helper.c | 342 +++++++++++++------
132
target/arm/iwmmxt_helper.c | 234 ++++++-------
133
target/arm/translate.c | 122 +++----
134
MAINTAINERS | 10 +
135
default-configs/arm-softmmu.mak | 4 +
136
hw/misc/trace-events | 16 +
137
hw/timer/trace-events | 5 +
138
41 files changed, 3405 insertions(+), 718 deletions(-)
139
create mode 100644 include/hw/misc/iotkit-sysctl.h
140
create mode 100644 include/hw/misc/iotkit-sysinfo.h
141
create mode 100644 include/hw/misc/tz-msc.h
142
create mode 100644 include/hw/ssi/pl022.h
143
create mode 100644 include/hw/timer/cmsdk-apb-dualtimer.h
144
create mode 100644 hw/misc/iotkit-sysctl.c
145
create mode 100644 hw/misc/iotkit-sysinfo.c
146
create mode 100644 hw/misc/tz-msc.c
147
create mode 100644 hw/timer/cmsdk-apb-dualtimer.c
148
45
46
Luc Michel (14):
47
hw/core/clock: provide the VMSTATE_ARRAY_CLOCK macro
48
hw/core/clock: trace clock values in Hz instead of ns
49
hw/arm/raspi: fix CPRMAN base address
50
hw/arm/raspi: add a skeleton implementation of the CPRMAN
51
hw/misc/bcm2835_cprman: add a PLL skeleton implementation
52
hw/misc/bcm2835_cprman: implement PLLs behaviour
53
hw/misc/bcm2835_cprman: add a PLL channel skeleton implementation
54
hw/misc/bcm2835_cprman: implement PLL channels behaviour
55
hw/misc/bcm2835_cprman: add a clock mux skeleton implementation
56
hw/misc/bcm2835_cprman: implement clock mux behaviour
57
hw/misc/bcm2835_cprman: add the DSI0HSCK multiplexer
58
hw/misc/bcm2835_cprman: add sane reset values to the registers
59
hw/char/pl011: add a clock input
60
hw/arm/bcm2835_peripherals: connect the UART clock
61
62
Pavel Dovgalyuk (1):
63
hw/arm: fix min_cpus for xlnx-versal-virt platform
64
65
Peter Maydell (2):
66
hw/core/ptimer: Support ptimer being disabled by timer callback
67
hw/timer/armv7m_systick: Rewrite to use ptimers
68
69
Philippe Mathieu-Daudé (10):
70
linux-user/elfload: Avoid leaking interp_name using GLib memory API
71
hw/arm/bcm2836: Restrict BCM283XInfo declaration to C source
72
hw/arm/bcm2836: QOM'ify more by adding class_init() to each SoC type
73
hw/arm/bcm2836: Introduce BCM283XClass::core_count
74
hw/arm/bcm2836: Only provide "enabled-cpus" property to multicore SoCs
75
hw/arm/bcm2836: Split out common realize() code
76
hw/arm/bcm2836: Introduce the BCM2835 SoC
77
hw/arm/raspi: Add the Raspberry Pi A+ machine
78
hw/arm/raspi: Add the Raspberry Pi Zero machine
79
hw/arm/raspi: Add the Raspberry Pi 3 model A+
80
81
Richard Henderson (11):
82
linux-user/aarch64: Reset btype for signals
83
linux-user: Set PAGE_TARGET_1 for TARGET_PROT_BTI
84
include/elf: Add defines related to GNU property notes for AArch64
85
linux-user/elfload: Fix coding style in load_elf_image
86
linux-user/elfload: Adjust iteration over phdr
87
linux-user/elfload: Move PT_INTERP detection to first loop
88
linux-user/elfload: Use Error for load_elf_image
89
linux-user/elfload: Use Error for load_elf_interp
90
linux-user/elfload: Parse NT_GNU_PROPERTY_TYPE_0 notes
91
linux-user/elfload: Parse GNU_PROPERTY_AARCH64_FEATURE_1_AND
92
tests/tcg/aarch64: Add bti smoke tests
93
94
Shashi Mallela (2):
95
hw/watchdog: Implement SBSA watchdog device
96
hw/arm/sbsa-ref: add SBSA watchdog device
97
98
Thomas Huth (1):
99
hw/arm/highbank: Silence warnings about missing fallthrough statements
100
101
Zenghui Yu (1):
102
hw/arm/smmuv3: Set the restoration priority of the vSMMUv3 explicitly
103
104
docs/system/arm/nuvoton.rst | 6 +-
105
hw/usb/hcd-ehci.h | 1 +
106
include/elf.h | 22 +
107
include/exec/cpu-all.h | 2 +
108
include/hw/arm/bcm2835_peripherals.h | 5 +-
109
include/hw/arm/bcm2836.h | 9 +-
110
include/hw/arm/npcm7xx.h | 8 +
111
include/hw/arm/raspi_platform.h | 5 +-
112
include/hw/char/pl011.h | 1 +
113
include/hw/clock.h | 5 +
114
include/hw/gpio/npcm7xx_gpio.h | 55 ++
115
include/hw/misc/bcm2835_cprman.h | 210 ++++++
116
include/hw/misc/bcm2835_cprman_internals.h | 1019 ++++++++++++++++++++++++++++
117
include/hw/misc/npcm7xx_clk.h | 2 +
118
include/hw/misc/npcm7xx_rng.h | 34 +
119
include/hw/timer/armv7m_systick.h | 3 +-
120
include/hw/timer/npcm7xx_timer.h | 48 +-
121
include/hw/watchdog/sbsa_gwdt.h | 79 +++
122
linux-user/qemu.h | 4 +
123
linux-user/syscall_defs.h | 4 +
124
target/arm/cpu.h | 5 +
125
hw/arm/bcm2835_peripherals.c | 15 +-
126
hw/arm/bcm2836.c | 182 +++--
127
hw/arm/highbank.c | 2 +
128
hw/arm/npcm7xx.c | 126 +++-
129
hw/arm/raspi.c | 41 ++
130
hw/arm/sbsa-ref.c | 23 +
131
hw/arm/smmuv3.c | 1 +
132
hw/arm/xlnx-versal-virt.c | 1 +
133
hw/char/pl011.c | 45 ++
134
hw/core/clock.c | 6 +-
135
hw/core/ptimer.c | 4 +
136
hw/gpio/npcm7xx_gpio.c | 424 ++++++++++++
137
hw/misc/bcm2835_cprman.c | 808 ++++++++++++++++++++++
138
hw/misc/npcm7xx_clk.c | 28 +
139
hw/misc/npcm7xx_rng.c | 180 +++++
140
hw/timer/armv7m_systick.c | 124 ++--
141
hw/timer/npcm7xx_timer.c | 270 ++++++--
142
hw/usb/hcd-ehci-sysbus.c | 19 +
143
hw/watchdog/sbsa_gwdt.c | 293 ++++++++
144
linux-user/aarch64/signal.c | 10 +-
145
linux-user/elfload.c | 326 +++++++--
146
linux-user/mmap.c | 16 +
147
target/arm/translate-a64.c | 6 +-
148
tests/qtest/npcm7xx_gpio-test.c | 385 +++++++++++
149
tests/qtest/npcm7xx_rng-test.c | 278 ++++++++
150
tests/qtest/npcm7xx_watchdog_timer-test.c | 319 +++++++++
151
tests/tcg/aarch64/bti-1.c | 62 ++
152
tests/tcg/aarch64/bti-2.c | 116 ++++
153
tests/tcg/aarch64/bti-crt.inc.c | 51 ++
154
MAINTAINERS | 1 +
155
hw/arm/Kconfig | 1 +
156
hw/arm/trace-events | 2 +-
157
hw/char/trace-events | 1 +
158
hw/core/trace-events | 4 +-
159
hw/gpio/meson.build | 1 +
160
hw/gpio/trace-events | 7 +
161
hw/misc/meson.build | 2 +
162
hw/misc/trace-events | 9 +
163
hw/watchdog/Kconfig | 3 +
164
hw/watchdog/meson.build | 1 +
165
tests/qtest/meson.build | 6 +-
166
tests/tcg/aarch64/Makefile.target | 10 +
167
tests/tcg/configure.sh | 4 +
168
64 files changed, 5461 insertions(+), 279 deletions(-)
169
create mode 100644 include/hw/gpio/npcm7xx_gpio.h
170
create mode 100644 include/hw/misc/bcm2835_cprman.h
171
create mode 100644 include/hw/misc/bcm2835_cprman_internals.h
172
create mode 100644 include/hw/misc/npcm7xx_rng.h
173
create mode 100644 include/hw/watchdog/sbsa_gwdt.h
174
create mode 100644 hw/gpio/npcm7xx_gpio.c
175
create mode 100644 hw/misc/bcm2835_cprman.c
176
create mode 100644 hw/misc/npcm7xx_rng.c
177
create mode 100644 hw/watchdog/sbsa_gwdt.c
178
create mode 100644 tests/qtest/npcm7xx_gpio-test.c
179
create mode 100644 tests/qtest/npcm7xx_rng-test.c
180
create mode 100644 tests/qtest/npcm7xx_watchdog_timer-test.c
181
create mode 100644 tests/tcg/aarch64/bti-1.c
182
create mode 100644 tests/tcg/aarch64/bti-2.c
183
create mode 100644 tests/tcg/aarch64/bti-crt.inc.c
184
diff view generated by jsdifflib
1
The BCM2835FBState struct has a 'pitch' field which is a
1
From: Richard Henderson <richard.henderson@linaro.org>
2
cached copy of xres * (bpp >> 3), and a 'size' field which is
3
a cached copy of pitch * yres. However we don't actually do
4
anything with these fields; delete them. We retain the
5
now-unused slots in the VMState struct for migration
6
compatibility.
7
2
3
The kernel sets btype for the signal handler as if for a call.
4
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20201021173749.111103-2-richard.henderson@linaro.org
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 20180814144436.679-4-peter.maydell@linaro.org
11
---
9
---
12
include/hw/display/bcm2835_fb.h | 4 ----
10
linux-user/aarch64/signal.c | 10 ++++++++--
13
hw/display/bcm2835_fb.c | 19 ++++++++-----------
11
1 file changed, 8 insertions(+), 2 deletions(-)
14
2 files changed, 8 insertions(+), 15 deletions(-)
15
12
16
diff --git a/include/hw/display/bcm2835_fb.h b/include/hw/display/bcm2835_fb.h
13
diff --git a/linux-user/aarch64/signal.c b/linux-user/aarch64/signal.c
17
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
18
--- a/include/hw/display/bcm2835_fb.h
15
--- a/linux-user/aarch64/signal.c
19
+++ b/include/hw/display/bcm2835_fb.h
16
+++ b/linux-user/aarch64/signal.c
20
@@ -XXX,XX +XXX,XX @@ typedef struct {
17
@@ -XXX,XX +XXX,XX @@ static void target_setup_frame(int usig, struct target_sigaction *ka,
21
bool lock, invalidate, pending;
18
+ offsetof(struct target_rt_frame_record, tramp);
22
19
}
23
BCM2835FBConfig config;
20
env->xregs[0] = usig;
24
-
21
- env->xregs[31] = frame_addr;
25
- /* These are just cached values calculated from the config settings */
22
env->xregs[29] = frame_addr + fr_ofs;
26
- uint32_t size;
23
- env->pc = ka->_sa_handler;
27
- uint32_t pitch;
24
env->xregs[30] = return_addr;
28
} BCM2835FBState;
25
+ env->xregs[31] = frame_addr;
29
26
+ env->pc = ka->_sa_handler;
30
void bcm2835_fb_reconfigure(BCM2835FBState *s, BCM2835FBConfig *newconfig);
31
diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/hw/display/bcm2835_fb.c
34
+++ b/hw/display/bcm2835_fb.c
35
@@ -XXX,XX +XXX,XX @@ static void fb_update_display(void *opaque)
36
37
static void bcm2835_fb_mbox_push(BCM2835FBState *s, uint32_t value)
38
{
39
+ uint32_t pitch;
40
+ uint32_t size;
41
+
27
+
42
value &= ~0xf;
28
+ /* Invoke the signal handler as if by indirect call. */
43
29
+ if (cpu_isar_feature(aa64_bti, env_archcpu(env))) {
44
s->lock = true;
30
+ env->btype = 2;
45
@@ -XXX,XX +XXX,XX @@ static void bcm2835_fb_mbox_push(BCM2835FBState *s, uint32_t value)
31
+ }
46
32
+
47
/* TODO - Manage properly virtual resolution */
33
if (info) {
48
34
tswap_siginfo(&frame->info, info);
49
- s->pitch = s->config.xres * (s->config.bpp >> 3);
35
env->xregs[1] = frame_addr + offsetof(struct target_rt_sigframe, info);
50
- s->size = s->config.yres * s->pitch;
51
+ pitch = s->config.xres * (s->config.bpp >> 3);
52
+ size = s->config.yres * pitch;
53
54
- stl_le_phys(&s->dma_as, value + 16, s->pitch);
55
+ stl_le_phys(&s->dma_as, value + 16, pitch);
56
stl_le_phys(&s->dma_as, value + 32, s->config.base);
57
- stl_le_phys(&s->dma_as, value + 36, s->size);
58
+ stl_le_phys(&s->dma_as, value + 36, size);
59
60
s->invalidate = true;
61
qemu_console_resize(s->con, s->config.xres, s->config.yres);
62
@@ -XXX,XX +XXX,XX @@ void bcm2835_fb_reconfigure(BCM2835FBState *s, BCM2835FBConfig *newconfig)
63
64
/* TODO - Manage properly virtual resolution */
65
66
- s->pitch = s->config.xres * (s->config.bpp >> 3);
67
- s->size = s->config.yres * s->pitch;
68
-
69
s->invalidate = true;
70
qemu_console_resize(s->con, s->config.xres, s->config.yres);
71
s->lock = false;
72
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_bcm2835_fb = {
73
VMSTATE_UINT32(config.yoffset, BCM2835FBState),
74
VMSTATE_UINT32(config.bpp, BCM2835FBState),
75
VMSTATE_UINT32(config.base, BCM2835FBState),
76
- VMSTATE_UINT32(pitch, BCM2835FBState),
77
- VMSTATE_UINT32(size, BCM2835FBState),
78
+ VMSTATE_UNUSED(8), /* Was pitch and size */
79
VMSTATE_UINT32(config.pixo, BCM2835FBState),
80
VMSTATE_UINT32(config.alpha, BCM2835FBState),
81
VMSTATE_END_OF_LIST()
82
@@ -XXX,XX +XXX,XX @@ static void bcm2835_fb_reset(DeviceState *dev)
83
s->config.xoffset = 0;
84
s->config.yoffset = 0;
85
s->config.base = s->vcram_base + BCM2835_FB_OFFSET;
86
- s->pitch = s->config.xres * (s->config.bpp >> 3);
87
- s->size = s->config.yres * s->pitch;
88
89
s->invalidate = true;
90
s->lock = false;
91
--
36
--
92
2.18.0
37
2.20.1
93
38
94
39
diff view generated by jsdifflib
1
Following the bulk conversion of the iwMMXt code, there are
1
From: Richard Henderson <richard.henderson@linaro.org>
2
just a handful of hard coded tabs in target/arm; fix them.
3
This is a whitespace-only patch.
4
2
3
Transform the prot bit to a qemu internal page bit, and save
4
it in the page tables.
5
6
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20201021173749.111103-3-richard.henderson@linaro.org
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Message-id: 20180821165215.29069-4-peter.maydell@linaro.org
7
---
10
---
8
target/arm/cpu.h | 16 ++++++++--------
11
include/exec/cpu-all.h | 2 ++
9
target/arm/arm-semi.c | 2 +-
12
linux-user/syscall_defs.h | 4 ++++
10
2 files changed, 9 insertions(+), 9 deletions(-)
13
target/arm/cpu.h | 5 +++++
14
linux-user/mmap.c | 16 ++++++++++++++++
15
target/arm/translate-a64.c | 6 +++---
16
5 files changed, 30 insertions(+), 3 deletions(-)
11
17
18
diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h
19
index XXXXXXX..XXXXXXX 100644
20
--- a/include/exec/cpu-all.h
21
+++ b/include/exec/cpu-all.h
22
@@ -XXX,XX +XXX,XX @@ extern intptr_t qemu_host_page_mask;
23
/* FIXME: Code that sets/uses this is broken and needs to go away. */
24
#define PAGE_RESERVED 0x0020
25
#endif
26
+/* Target-specific bits that will be used via page_get_flags(). */
27
+#define PAGE_TARGET_1 0x0080
28
29
#if defined(CONFIG_USER_ONLY)
30
void page_dump(FILE *f);
31
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
32
index XXXXXXX..XXXXXXX 100644
33
--- a/linux-user/syscall_defs.h
34
+++ b/linux-user/syscall_defs.h
35
@@ -XXX,XX +XXX,XX @@ struct target_winsize {
36
#define TARGET_PROT_SEM 0x08
37
#endif
38
39
+#ifdef TARGET_AARCH64
40
+#define TARGET_PROT_BTI 0x10
41
+#endif
42
+
43
/* Common */
44
#define TARGET_MAP_SHARED    0x01        /* Share changes */
45
#define TARGET_MAP_PRIVATE    0x02        /* Changes are private */
12
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
46
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
13
index XXXXXXX..XXXXXXX 100644
47
index XXXXXXX..XXXXXXX 100644
14
--- a/target/arm/cpu.h
48
--- a/target/arm/cpu.h
15
+++ b/target/arm/cpu.h
49
+++ b/target/arm/cpu.h
16
@@ -XXX,XX +XXX,XX @@ enum arm_cpu_mode {
50
@@ -XXX,XX +XXX,XX @@ static inline MemTxAttrs *typecheck_memtxattrs(MemTxAttrs *x)
17
#define ARM_VFP_FPINST2 10
51
#define arm_tlb_bti_gp(x) (typecheck_memtxattrs(x)->target_tlb_bit0)
18
52
#define arm_tlb_mte_tagged(x) (typecheck_memtxattrs(x)->target_tlb_bit1)
19
/* iwMMXt coprocessor control registers. */
53
20
-#define ARM_IWMMXT_wCID        0
54
+/*
21
-#define ARM_IWMMXT_wCon        1
55
+ * AArch64 usage of the PAGE_TARGET_* bits for linux-user.
22
-#define ARM_IWMMXT_wCSSF    2
56
+ */
23
-#define ARM_IWMMXT_wCASF    3
57
+#define PAGE_BTI PAGE_TARGET_1
24
-#define ARM_IWMMXT_wCGR0    8
58
+
25
-#define ARM_IWMMXT_wCGR1    9
59
/*
26
-#define ARM_IWMMXT_wCGR2    10
60
* Naming convention for isar_feature functions:
27
-#define ARM_IWMMXT_wCGR3    11
61
* Functions which test 32-bit ID registers should have _aa32_ in
28
+#define ARM_IWMMXT_wCID 0
62
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
29
+#define ARM_IWMMXT_wCon 1
30
+#define ARM_IWMMXT_wCSSF 2
31
+#define ARM_IWMMXT_wCASF 3
32
+#define ARM_IWMMXT_wCGR0 8
33
+#define ARM_IWMMXT_wCGR1 9
34
+#define ARM_IWMMXT_wCGR2 10
35
+#define ARM_IWMMXT_wCGR3 11
36
37
/* V7M CCR bits */
38
FIELD(V7M_CCR, NONBASETHRDENA, 0, 1)
39
diff --git a/target/arm/arm-semi.c b/target/arm/arm-semi.c
40
index XXXXXXX..XXXXXXX 100644
63
index XXXXXXX..XXXXXXX 100644
41
--- a/target/arm/arm-semi.c
64
--- a/linux-user/mmap.c
42
+++ b/target/arm/arm-semi.c
65
+++ b/linux-user/mmap.c
43
@@ -XXX,XX +XXX,XX @@ static void arm_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
66
@@ -XXX,XX +XXX,XX @@ static int validate_prot_to_pageflags(int *host_prot, int prot)
44
#ifdef CONFIG_USER_ONLY
67
*host_prot = (prot & (PROT_READ | PROT_WRITE))
45
ts->swi_errno = err;
68
| (prot & PROT_EXEC ? PROT_READ : 0);
46
#else
69
47
-    syscall_err = err;
70
+#ifdef TARGET_AARCH64
48
+ syscall_err = err;
71
+ /*
49
#endif
72
+ * The PROT_BTI bit is only accepted if the cpu supports the feature.
50
reg0 = ret;
73
+ * Since this is the unusual case, don't bother checking unless
51
} else {
74
+ * the bit has been requested. If set and valid, record the bit
75
+ * within QEMU's page_flags.
76
+ */
77
+ if (prot & TARGET_PROT_BTI) {
78
+ ARMCPU *cpu = ARM_CPU(thread_cpu);
79
+ if (cpu_isar_feature(aa64_bti, cpu)) {
80
+ valid |= TARGET_PROT_BTI;
81
+ page_flags |= PAGE_BTI;
82
+ }
83
+ }
84
+#endif
85
+
86
return prot & ~valid ? 0 : page_flags;
87
}
88
89
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
90
index XXXXXXX..XXXXXXX 100644
91
--- a/target/arm/translate-a64.c
92
+++ b/target/arm/translate-a64.c
93
@@ -XXX,XX +XXX,XX @@ static void disas_data_proc_simd_fp(DisasContext *s, uint32_t insn)
94
*/
95
static bool is_guarded_page(CPUARMState *env, DisasContext *s)
96
{
97
-#ifdef CONFIG_USER_ONLY
98
- return false; /* FIXME */
99
-#else
100
uint64_t addr = s->base.pc_first;
101
+#ifdef CONFIG_USER_ONLY
102
+ return page_get_flags(addr) & PAGE_BTI;
103
+#else
104
int mmu_idx = arm_to_core_mmu_idx(s->mmu_idx);
105
unsigned int index = tlb_index(env, mmu_idx, addr);
106
CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr);
52
--
107
--
53
2.18.0
108
2.20.1
54
109
55
110
diff view generated by jsdifflib
1
Refactor the fb property setting code so that rather than
1
From: Richard Henderson <richard.henderson@linaro.org>
2
using a set of pointers to local variables to track
3
whether a config value has been updated in the current
4
mbox and if so what its new value is, we just copy
5
all the current settings of the fb at the start, and
6
then update that copy as we go along, before asking
7
the fb to switch to it at the end.
8
2
3
These are all of the defines required to parse
4
GNU_PROPERTY_AARCH64_FEATURE_1_AND, copied from binutils.
5
Other missing defines related to other GNU program headers
6
and notes are elided for now.
7
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 20201021173749.111103-4-richard.henderson@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
11
Message-id: 20180814144436.679-3-peter.maydell@linaro.org
12
---
12
---
13
include/hw/display/bcm2835_fb.h | 4 +-
13
include/elf.h | 22 ++++++++++++++++++++++
14
hw/display/bcm2835_fb.c | 27 ++---------
14
1 file changed, 22 insertions(+)
15
hw/misc/bcm2835_property.c | 80 ++++++++++++++-------------------
16
3 files changed, 37 insertions(+), 74 deletions(-)
17
15
18
diff --git a/include/hw/display/bcm2835_fb.h b/include/hw/display/bcm2835_fb.h
16
diff --git a/include/elf.h b/include/elf.h
19
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
20
--- a/include/hw/display/bcm2835_fb.h
18
--- a/include/elf.h
21
+++ b/include/hw/display/bcm2835_fb.h
19
+++ b/include/elf.h
22
@@ -XXX,XX +XXX,XX @@ typedef struct {
20
@@ -XXX,XX +XXX,XX @@ typedef int64_t Elf64_Sxword;
23
uint32_t pitch;
21
#define PT_NOTE 4
24
} BCM2835FBState;
22
#define PT_SHLIB 5
25
23
#define PT_PHDR 6
26
-void bcm2835_fb_reconfigure(BCM2835FBState *s, uint32_t *xres, uint32_t *yres,
24
+#define PT_LOOS 0x60000000
27
- uint32_t *xoffset, uint32_t *yoffset, uint32_t *bpp,
25
+#define PT_HIOS 0x6fffffff
28
- uint32_t *pixo, uint32_t *alpha);
26
#define PT_LOPROC 0x70000000
29
+void bcm2835_fb_reconfigure(BCM2835FBState *s, BCM2835FBConfig *newconfig);
27
#define PT_HIPROC 0x7fffffff
30
28
31
#endif
29
+#define PT_GNU_PROPERTY (PT_LOOS + 0x474e553)
32
diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/hw/display/bcm2835_fb.c
35
+++ b/hw/display/bcm2835_fb.c
36
@@ -XXX,XX +XXX,XX @@ static void bcm2835_fb_mbox_push(BCM2835FBState *s, uint32_t value)
37
s->lock = false;
38
}
39
40
-void bcm2835_fb_reconfigure(BCM2835FBState *s, uint32_t *xres, uint32_t *yres,
41
- uint32_t *xoffset, uint32_t *yoffset, uint32_t *bpp,
42
- uint32_t *pixo, uint32_t *alpha)
43
+void bcm2835_fb_reconfigure(BCM2835FBState *s, BCM2835FBConfig *newconfig)
44
{
45
s->lock = true;
46
47
/* TODO: input validation! */
48
- if (xres) {
49
- s->config.xres = *xres;
50
- }
51
- if (yres) {
52
- s->config.yres = *yres;
53
- }
54
- if (xoffset) {
55
- s->config.xoffset = *xoffset;
56
- }
57
- if (yoffset) {
58
- s->config.yoffset = *yoffset;
59
- }
60
- if (bpp) {
61
- s->config.bpp = *bpp;
62
- }
63
- if (pixo) {
64
- s->config.pixo = *pixo;
65
- }
66
- if (alpha) {
67
- s->config.alpha = *alpha;
68
- }
69
+
30
+
70
+ s->config = *newconfig;
31
#define PT_MIPS_REGINFO 0x70000000
71
32
#define PT_MIPS_RTPROC 0x70000001
72
/* TODO - Manage properly virtual resolution */
33
#define PT_MIPS_OPTIONS 0x70000002
73
34
@@ -XXX,XX +XXX,XX @@ typedef struct elf64_shdr {
74
diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c
35
#define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */
75
index XXXXXXX..XXXXXXX 100644
36
#define NT_ARM_SVE 0x405 /* ARM Scalable Vector Extension regs */
76
--- a/hw/misc/bcm2835_property.c
37
77
+++ b/hw/misc/bcm2835_property.c
38
+/* Defined note types for GNU systems. */
78
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
79
uint32_t tmp;
80
int n;
81
uint32_t offset, length, color;
82
- uint32_t xres, yres, xoffset, yoffset, bpp, pixo, alpha;
83
- uint32_t tmp_xres, tmp_yres, tmp_xoffset, tmp_yoffset;
84
- uint32_t tmp_bpp, tmp_pixo, tmp_alpha;
85
- uint32_t *newxres = NULL, *newyres = NULL, *newxoffset = NULL,
86
- *newyoffset = NULL, *newbpp = NULL, *newpixo = NULL, *newalpha = NULL;
87
+
39
+
88
+ /*
40
+#define NT_GNU_PROPERTY_TYPE_0 5 /* Program property */
89
+ * Copy the current state of the framebuffer config; we will update
41
+
90
+ * this copy as we process tags and then ask the framebuffer to use
42
+/* Values used in GNU .note.gnu.property notes (NT_GNU_PROPERTY_TYPE_0). */
91
+ * it at the end.
43
+
92
+ */
44
+#define GNU_PROPERTY_STACK_SIZE 1
93
+ BCM2835FBConfig fbconfig = s->fbdev->config;
45
+#define GNU_PROPERTY_NO_COPY_ON_PROTECTED 2
94
+ bool fbconfig_updated = false;
46
+
95
47
+#define GNU_PROPERTY_LOPROC 0xc0000000
96
value &= ~0xf;
48
+#define GNU_PROPERTY_HIPROC 0xdfffffff
97
49
+#define GNU_PROPERTY_LOUSER 0xe0000000
98
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
50
+#define GNU_PROPERTY_HIUSER 0xffffffff
99
/* Frame buffer */
51
+
100
52
+#define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000
101
case 0x00040001: /* Allocate buffer */
53
+#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI (1u << 0)
102
- stl_le_phys(&s->dma_as, value + 12, s->fbdev->config.base);
54
+#define GNU_PROPERTY_AARCH64_FEATURE_1_PAC (1u << 1)
103
- tmp_xres = newxres != NULL ? *newxres : s->fbdev->config.xres;
55
+
104
- tmp_yres = newyres != NULL ? *newyres : s->fbdev->config.yres;
56
/*
105
- tmp_bpp = newbpp != NULL ? *newbpp : s->fbdev->config.bpp;
57
* Physical entry point into the kernel.
106
+ stl_le_phys(&s->dma_as, value + 12, fbconfig.base);
58
*
107
stl_le_phys(&s->dma_as, value + 16,
108
- tmp_xres * tmp_yres * tmp_bpp / 8);
109
+ fbconfig.xres * fbconfig.yres * fbconfig.bpp / 8);
110
resplen = 8;
111
break;
112
case 0x00048001: /* Release buffer */
113
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
114
break;
115
case 0x00040003: /* Get display width/height */
116
case 0x00040004:
117
- tmp_xres = newxres != NULL ? *newxres : s->fbdev->config.xres;
118
- tmp_yres = newyres != NULL ? *newyres : s->fbdev->config.yres;
119
- stl_le_phys(&s->dma_as, value + 12, tmp_xres);
120
- stl_le_phys(&s->dma_as, value + 16, tmp_yres);
121
+ stl_le_phys(&s->dma_as, value + 12, fbconfig.xres);
122
+ stl_le_phys(&s->dma_as, value + 16, fbconfig.yres);
123
resplen = 8;
124
break;
125
case 0x00044003: /* Test display width/height */
126
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
127
break;
128
case 0x00048003: /* Set display width/height */
129
case 0x00048004:
130
- xres = ldl_le_phys(&s->dma_as, value + 12);
131
- newxres = &xres;
132
- yres = ldl_le_phys(&s->dma_as, value + 16);
133
- newyres = &yres;
134
+ fbconfig.xres = ldl_le_phys(&s->dma_as, value + 12);
135
+ fbconfig.yres = ldl_le_phys(&s->dma_as, value + 16);
136
+ fbconfig_updated = true;
137
resplen = 8;
138
break;
139
case 0x00040005: /* Get depth */
140
- tmp_bpp = newbpp != NULL ? *newbpp : s->fbdev->config.bpp;
141
- stl_le_phys(&s->dma_as, value + 12, tmp_bpp);
142
+ stl_le_phys(&s->dma_as, value + 12, fbconfig.bpp);
143
resplen = 4;
144
break;
145
case 0x00044005: /* Test depth */
146
resplen = 4;
147
break;
148
case 0x00048005: /* Set depth */
149
- bpp = ldl_le_phys(&s->dma_as, value + 12);
150
- newbpp = &bpp;
151
+ fbconfig.bpp = ldl_le_phys(&s->dma_as, value + 12);
152
+ fbconfig_updated = true;
153
resplen = 4;
154
break;
155
case 0x00040006: /* Get pixel order */
156
- tmp_pixo = newpixo != NULL ? *newpixo : s->fbdev->config.pixo;
157
- stl_le_phys(&s->dma_as, value + 12, tmp_pixo);
158
+ stl_le_phys(&s->dma_as, value + 12, fbconfig.pixo);
159
resplen = 4;
160
break;
161
case 0x00044006: /* Test pixel order */
162
resplen = 4;
163
break;
164
case 0x00048006: /* Set pixel order */
165
- pixo = ldl_le_phys(&s->dma_as, value + 12);
166
- newpixo = &pixo;
167
+ fbconfig.pixo = ldl_le_phys(&s->dma_as, value + 12);
168
+ fbconfig_updated = true;
169
resplen = 4;
170
break;
171
case 0x00040007: /* Get alpha */
172
- tmp_alpha = newalpha != NULL ? *newalpha : s->fbdev->config.alpha;
173
- stl_le_phys(&s->dma_as, value + 12, tmp_alpha);
174
+ stl_le_phys(&s->dma_as, value + 12, fbconfig.alpha);
175
resplen = 4;
176
break;
177
case 0x00044007: /* Test pixel alpha */
178
resplen = 4;
179
break;
180
case 0x00048007: /* Set alpha */
181
- alpha = ldl_le_phys(&s->dma_as, value + 12);
182
- newalpha = &alpha;
183
+ fbconfig.alpha = ldl_le_phys(&s->dma_as, value + 12);
184
+ fbconfig_updated = true;
185
resplen = 4;
186
break;
187
case 0x00040008: /* Get pitch */
188
- tmp_xres = newxres != NULL ? *newxres : s->fbdev->config.xres;
189
- tmp_bpp = newbpp != NULL ? *newbpp : s->fbdev->config.bpp;
190
- stl_le_phys(&s->dma_as, value + 12, tmp_xres * tmp_bpp / 8);
191
+ stl_le_phys(&s->dma_as, value + 12,
192
+ fbconfig.xres * fbconfig.bpp / 8);
193
resplen = 4;
194
break;
195
case 0x00040009: /* Get virtual offset */
196
- tmp_xoffset = newxoffset != NULL ?
197
- *newxoffset : s->fbdev->config.xoffset;
198
- tmp_yoffset = newyoffset != NULL ?
199
- *newyoffset : s->fbdev->config.yoffset;
200
- stl_le_phys(&s->dma_as, value + 12, tmp_xoffset);
201
- stl_le_phys(&s->dma_as, value + 16, tmp_yoffset);
202
+ stl_le_phys(&s->dma_as, value + 12, fbconfig.xoffset);
203
+ stl_le_phys(&s->dma_as, value + 16, fbconfig.yoffset);
204
resplen = 8;
205
break;
206
case 0x00044009: /* Test virtual offset */
207
resplen = 8;
208
break;
209
case 0x00048009: /* Set virtual offset */
210
- xoffset = ldl_le_phys(&s->dma_as, value + 12);
211
- newxoffset = &xoffset;
212
- yoffset = ldl_le_phys(&s->dma_as, value + 16);
213
- newyoffset = &yoffset;
214
+ fbconfig.xoffset = ldl_le_phys(&s->dma_as, value + 12);
215
+ fbconfig.yoffset = ldl_le_phys(&s->dma_as, value + 16);
216
+ fbconfig_updated = true;
217
resplen = 8;
218
break;
219
case 0x0004000a: /* Get/Test/Set overscan */
220
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
221
}
222
223
/* Reconfigure framebuffer if required */
224
- if (newxres || newyres || newxoffset || newyoffset || newbpp || newpixo
225
- || newalpha) {
226
- bcm2835_fb_reconfigure(s->fbdev, newxres, newyres, newxoffset,
227
- newyoffset, newbpp, newpixo, newalpha);
228
+ if (fbconfig_updated) {
229
+ bcm2835_fb_reconfigure(s->fbdev, &fbconfig);
230
}
231
232
/* Buffer response code */
233
--
59
--
234
2.18.0
60
2.20.1
235
61
236
62
diff view generated by jsdifflib
1
Now we have a model of the CMSDK dual timer, we can wire it
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
up in the IoTKit.
3
2
3
Fix an unlikely memory leak in load_elf_image().
4
5
Fixes: bf858897b7 ("linux-user: Re-use load_elf_image for the main binary.")
6
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20201021173749.111103-5-richard.henderson@linaro.org
9
Message-Id: <20201003174944.1972444-1-f4bug@amsat.org>
10
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
11
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20180820141116.9118-5-peter.maydell@linaro.org
8
---
13
---
9
include/hw/arm/iotkit.h | 3 ++-
14
linux-user/elfload.c | 8 ++++----
10
hw/arm/iotkit.c | 8 +++++---
15
1 file changed, 4 insertions(+), 4 deletions(-)
11
2 files changed, 7 insertions(+), 4 deletions(-)
12
16
13
diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h
17
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
14
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
15
--- a/include/hw/arm/iotkit.h
19
--- a/linux-user/elfload.c
16
+++ b/include/hw/arm/iotkit.h
20
+++ b/linux-user/elfload.c
17
@@ -XXX,XX +XXX,XX @@
21
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
18
#include "hw/misc/tz-ppc.h"
22
info->brk = vaddr_em;
19
#include "hw/misc/tz-mpc.h"
23
}
20
#include "hw/timer/cmsdk-apb-timer.h"
24
} else if (eppnt->p_type == PT_INTERP && pinterp_name) {
21
+#include "hw/timer/cmsdk-apb-dualtimer.h"
25
- char *interp_name;
22
#include "hw/misc/unimp.h"
26
+ g_autofree char *interp_name = NULL;
23
#include "hw/or-irq.h"
27
24
#include "hw/core/split-irq.h"
28
if (*pinterp_name) {
25
@@ -XXX,XX +XXX,XX @@ typedef struct IoTKit {
29
errmsg = "Multiple PT_INTERP entries";
26
SplitIRQ mpc_irq_splitter[IOTS_NUM_EXP_MPC + IOTS_NUM_MPC];
30
goto exit_errmsg;
27
qemu_or_irq mpc_irq_orgate;
31
}
28
32
- interp_name = malloc(eppnt->p_filesz);
29
- UnimplementedDeviceState dualtimer;
33
+ interp_name = g_malloc(eppnt->p_filesz);
30
+ CMSDKAPBDualTimer dualtimer;
34
if (!interp_name) {
31
UnimplementedDeviceState s32ktimer;
35
goto exit_perror;
32
36
}
33
MemoryRegion container;
37
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
34
diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c
38
errmsg = "Invalid PT_INTERP entry";
35
index XXXXXXX..XXXXXXX 100644
39
goto exit_errmsg;
36
--- a/hw/arm/iotkit.c
40
}
37
+++ b/hw/arm/iotkit.c
41
- *pinterp_name = interp_name;
38
@@ -XXX,XX +XXX,XX @@ static void iotkit_init(Object *obj)
42
+ *pinterp_name = g_steal_pointer(&interp_name);
39
sysbus_init_child_obj(obj, "timer1", &s->timer1, sizeof(s->timer1),
43
#ifdef TARGET_MIPS
40
TYPE_CMSDK_APB_TIMER);
44
} else if (eppnt->p_type == PT_MIPS_ABIFLAGS) {
41
sysbus_init_child_obj(obj, "dualtimer", &s->dualtimer, sizeof(s->dualtimer),
45
Mips_elf_abiflags_v0 abiflags;
42
- TYPE_UNIMPLEMENTED_DEVICE);
46
@@ -XXX,XX +XXX,XX @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
43
+ TYPE_CMSDK_APB_DUALTIMER);
47
if (elf_interpreter) {
44
object_initialize_child(obj, "ppc-irq-orgate", &s->ppc_irq_orgate,
48
info->load_bias = interp_info.load_bias;
45
sizeof(s->ppc_irq_orgate), TYPE_OR_IRQ,
49
info->entry = interp_info.entry;
46
&error_abort, NULL);
50
- free(elf_interpreter);
47
@@ -XXX,XX +XXX,XX @@ static void iotkit_realize(DeviceState *dev, Error **errp)
51
+ g_free(elf_interpreter);
48
return;
49
}
52
}
50
53
51
- qdev_prop_set_string(DEVICE(&s->dualtimer), "name", "Dual timer");
54
#ifdef USE_ELF_CORE_DUMP
52
- qdev_prop_set_uint64(DEVICE(&s->dualtimer), "size", 0x1000);
53
+
54
+ qdev_prop_set_uint32(DEVICE(&s->dualtimer), "pclk-frq", s->mainclk_frq);
55
object_property_set_bool(OBJECT(&s->dualtimer), true, "realized", &err);
56
if (err) {
57
error_propagate(errp, err);
58
return;
59
}
60
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->dualtimer), 0,
61
+ qdev_get_gpio_in(DEVICE(&s->armv7m), 5));
62
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->dualtimer), 0);
63
object_property_set_link(OBJECT(&s->apb_ppc0), OBJECT(mr), "port[2]", &err);
64
if (err) {
65
--
55
--
66
2.18.0
56
2.20.1
67
57
68
58
diff view generated by jsdifflib
1
Untabify the arm iwmmxt_helper.c. This affects only the iwMMXt code.
1
From: Richard Henderson <richard.henderson@linaro.org>
2
We've never touched that code in years, so it's not going to get
3
fixed up by our "change when touched" process, and a bulk change is
4
not going to be too disruptive.
5
2
6
This commit was produced using Emacs "untabify" (plus one
3
Fixing this now will clarify following patches.
7
by-hand removal of a space to fix a checkpatch nit); it is
8
a whitespace-only change.
9
4
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20201021173749.111103-6-richard.henderson@linaro.org
7
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Message-id: 20180821165215.29069-3-peter.maydell@linaro.org
12
---
9
---
13
target/arm/iwmmxt_helper.c | 234 ++++++++++++++++++-------------------
10
linux-user/elfload.c | 12 +++++++++---
14
1 file changed, 117 insertions(+), 117 deletions(-)
11
1 file changed, 9 insertions(+), 3 deletions(-)
15
12
16
diff --git a/target/arm/iwmmxt_helper.c b/target/arm/iwmmxt_helper.c
13
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
17
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
18
--- a/target/arm/iwmmxt_helper.c
15
--- a/linux-user/elfload.c
19
+++ b/target/arm/iwmmxt_helper.c
16
+++ b/linux-user/elfload.c
20
@@ -XXX,XX +XXX,XX @@
17
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
21
/* iwMMXt macros extracted from GNU gdb. */
18
abi_ulong vaddr, vaddr_po, vaddr_ps, vaddr_ef, vaddr_em, vaddr_len;
22
19
int elf_prot = 0;
23
/* Set the SIMD wCASF flags for 8, 16, 32 or 64-bit operations. */
20
24
-#define SIMD8_SET( v, n, b)    ((v != 0) << ((((b) + 1) * 4) + (n)))
21
- if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
25
-#define SIMD16_SET(v, n, h)    ((v != 0) << ((((h) + 1) * 8) + (n)))
22
- if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
26
-#define SIMD32_SET(v, n, w)    ((v != 0) << ((((w) + 1) * 16) + (n)))
23
- if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
27
-#define SIMD64_SET(v, n)    ((v != 0) << (32 + (n)))
24
+ if (eppnt->p_flags & PF_R) {
28
+#define SIMD8_SET(v, n, b) ((v != 0) << ((((b) + 1) * 4) + (n)))
25
+ elf_prot |= PROT_READ;
29
+#define SIMD16_SET(v, n, h) ((v != 0) << ((((h) + 1) * 8) + (n)))
26
+ }
30
+#define SIMD32_SET(v, n, w) ((v != 0) << ((((w) + 1) * 16) + (n)))
27
+ if (eppnt->p_flags & PF_W) {
31
+#define SIMD64_SET(v, n) ((v != 0) << (32 + (n)))
28
+ elf_prot |= PROT_WRITE;
32
/* Flags to pass as "n" above. */
29
+ }
33
-#define SIMD_NBIT    -1
30
+ if (eppnt->p_flags & PF_X) {
34
-#define SIMD_ZBIT    -2
31
+ elf_prot |= PROT_EXEC;
35
-#define SIMD_CBIT    -3
32
+ }
36
-#define SIMD_VBIT    -4
33
37
+#define SIMD_NBIT -1
34
vaddr = load_bias + eppnt->p_vaddr;
38
+#define SIMD_ZBIT -2
35
vaddr_po = TARGET_ELF_PAGEOFFSET(vaddr);
39
+#define SIMD_CBIT -3
40
+#define SIMD_VBIT -4
41
/* Various status bit macros. */
42
-#define NBIT8(x)    ((x) & 0x80)
43
-#define NBIT16(x)    ((x) & 0x8000)
44
-#define NBIT32(x)    ((x) & 0x80000000)
45
-#define NBIT64(x)    ((x) & 0x8000000000000000ULL)
46
-#define ZBIT8(x)    (((x) & 0xff) == 0)
47
-#define ZBIT16(x)    (((x) & 0xffff) == 0)
48
-#define ZBIT32(x)    (((x) & 0xffffffff) == 0)
49
-#define ZBIT64(x)    (x == 0)
50
+#define NBIT8(x) ((x) & 0x80)
51
+#define NBIT16(x) ((x) & 0x8000)
52
+#define NBIT32(x) ((x) & 0x80000000)
53
+#define NBIT64(x) ((x) & 0x8000000000000000ULL)
54
+#define ZBIT8(x) (((x) & 0xff) == 0)
55
+#define ZBIT16(x) (((x) & 0xffff) == 0)
56
+#define ZBIT32(x) (((x) & 0xffffffff) == 0)
57
+#define ZBIT64(x) (x == 0)
58
/* Sign extension macros. */
59
-#define EXTEND8H(a)    ((uint16_t) (int8_t) (a))
60
-#define EXTEND8(a)    ((uint32_t) (int8_t) (a))
61
-#define EXTEND16(a)    ((uint32_t) (int16_t) (a))
62
-#define EXTEND16S(a)    ((int32_t) (int16_t) (a))
63
-#define EXTEND32(a)    ((uint64_t) (int32_t) (a))
64
+#define EXTEND8H(a) ((uint16_t) (int8_t) (a))
65
+#define EXTEND8(a) ((uint32_t) (int8_t) (a))
66
+#define EXTEND16(a) ((uint32_t) (int16_t) (a))
67
+#define EXTEND16S(a) ((int32_t) (int16_t) (a))
68
+#define EXTEND32(a) ((uint64_t) (int32_t) (a))
69
70
uint64_t HELPER(iwmmxt_maddsq)(uint64_t a, uint64_t b)
71
{
72
@@ -XXX,XX +XXX,XX @@ uint64_t HELPER(iwmmxt_macuw)(uint64_t a, uint64_t b)
73
#define NZBIT64(x) \
74
SIMD64_SET(NBIT64(x), SIMD_NBIT) | \
75
SIMD64_SET(ZBIT64(x), SIMD_ZBIT)
76
-#define IWMMXT_OP_UNPACK(S, SH0, SH1, SH2, SH3)            \
77
+#define IWMMXT_OP_UNPACK(S, SH0, SH1, SH2, SH3) \
78
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, b)))(CPUARMState *env, \
79
uint64_t a, uint64_t b) \
80
-{                                \
81
- a =                             \
82
- (((a >> SH0) & 0xff) << 0) | (((b >> SH0) & 0xff) << 8) |    \
83
- (((a >> SH1) & 0xff) << 16) | (((b >> SH1) & 0xff) << 24) |    \
84
- (((a >> SH2) & 0xff) << 32) | (((b >> SH2) & 0xff) << 40) |    \
85
- (((a >> SH3) & 0xff) << 48) | (((b >> SH3) & 0xff) << 56);    \
86
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =            \
87
- NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) |         \
88
- NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) |        \
89
- NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) |        \
90
- NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7);        \
91
+{ \
92
+ a = \
93
+ (((a >> SH0) & 0xff) << 0) | (((b >> SH0) & 0xff) << 8) | \
94
+ (((a >> SH1) & 0xff) << 16) | (((b >> SH1) & 0xff) << 24) | \
95
+ (((a >> SH2) & 0xff) << 32) | (((b >> SH2) & 0xff) << 40) | \
96
+ (((a >> SH3) & 0xff) << 48) | (((b >> SH3) & 0xff) << 56); \
97
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
98
+ NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) | \
99
+ NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) | \
100
+ NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) | \
101
+ NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7); \
102
return a; \
103
-}                                \
104
+} \
105
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, w)))(CPUARMState *env, \
106
uint64_t a, uint64_t b) \
107
-{                                \
108
- a =                             \
109
- (((a >> SH0) & 0xffff) << 0) |                \
110
- (((b >> SH0) & 0xffff) << 16) |             \
111
- (((a >> SH2) & 0xffff) << 32) |             \
112
- (((b >> SH2) & 0xffff) << 48);                \
113
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =            \
114
- NZBIT8(a >> 0, 0) | NZBIT8(a >> 16, 1) |        \
115
- NZBIT8(a >> 32, 2) | NZBIT8(a >> 48, 3);        \
116
+{ \
117
+ a = \
118
+ (((a >> SH0) & 0xffff) << 0) | \
119
+ (((b >> SH0) & 0xffff) << 16) | \
120
+ (((a >> SH2) & 0xffff) << 32) | \
121
+ (((b >> SH2) & 0xffff) << 48); \
122
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
123
+ NZBIT8(a >> 0, 0) | NZBIT8(a >> 16, 1) | \
124
+ NZBIT8(a >> 32, 2) | NZBIT8(a >> 48, 3); \
125
return a; \
126
-}                                \
127
+} \
128
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, l)))(CPUARMState *env, \
129
uint64_t a, uint64_t b) \
130
-{                                \
131
- a =                             \
132
- (((a >> SH0) & 0xffffffff) << 0) |            \
133
- (((b >> SH0) & 0xffffffff) << 32);            \
134
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =            \
135
- NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1);        \
136
+{ \
137
+ a = \
138
+ (((a >> SH0) & 0xffffffff) << 0) | \
139
+ (((b >> SH0) & 0xffffffff) << 32); \
140
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
141
+ NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1); \
142
return a; \
143
-}                                \
144
+} \
145
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ub)))(CPUARMState *env, \
146
uint64_t x) \
147
-{                                \
148
- x =                             \
149
- (((x >> SH0) & 0xff) << 0) |                \
150
- (((x >> SH1) & 0xff) << 16) |                \
151
- (((x >> SH2) & 0xff) << 32) |                \
152
- (((x >> SH3) & 0xff) << 48);                \
153
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =            \
154
- NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) |        \
155
- NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3);        \
156
+{ \
157
+ x = \
158
+ (((x >> SH0) & 0xff) << 0) | \
159
+ (((x >> SH1) & 0xff) << 16) | \
160
+ (((x >> SH2) & 0xff) << 32) | \
161
+ (((x >> SH3) & 0xff) << 48); \
162
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
163
+ NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | \
164
+ NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); \
165
return x; \
166
-}                                \
167
+} \
168
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, uw)))(CPUARMState *env, \
169
uint64_t x) \
170
-{                                \
171
- x =                             \
172
- (((x >> SH0) & 0xffff) << 0) |                \
173
- (((x >> SH2) & 0xffff) << 32);                \
174
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =            \
175
- NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1);        \
176
+{ \
177
+ x = \
178
+ (((x >> SH0) & 0xffff) << 0) | \
179
+ (((x >> SH2) & 0xffff) << 32); \
180
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
181
+ NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); \
182
return x; \
183
-}                                \
184
+} \
185
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, ul)))(CPUARMState *env, \
186
uint64_t x) \
187
-{                                \
188
- x = (((x >> SH0) & 0xffffffff) << 0);            \
189
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x >> 0);    \
190
+{ \
191
+ x = (((x >> SH0) & 0xffffffff) << 0); \
192
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x >> 0); \
193
return x; \
194
-}                                \
195
+} \
196
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sb)))(CPUARMState *env, \
197
uint64_t x) \
198
-{                                \
199
- x =                             \
200
- ((uint64_t) EXTEND8H((x >> SH0) & 0xff) << 0) |     \
201
- ((uint64_t) EXTEND8H((x >> SH1) & 0xff) << 16) |    \
202
- ((uint64_t) EXTEND8H((x >> SH2) & 0xff) << 32) |    \
203
- ((uint64_t) EXTEND8H((x >> SH3) & 0xff) << 48);     \
204
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =            \
205
- NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) |        \
206
- NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3);        \
207
+{ \
208
+ x = \
209
+ ((uint64_t) EXTEND8H((x >> SH0) & 0xff) << 0) | \
210
+ ((uint64_t) EXTEND8H((x >> SH1) & 0xff) << 16) | \
211
+ ((uint64_t) EXTEND8H((x >> SH2) & 0xff) << 32) | \
212
+ ((uint64_t) EXTEND8H((x >> SH3) & 0xff) << 48); \
213
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
214
+ NZBIT16(x >> 0, 0) | NZBIT16(x >> 16, 1) | \
215
+ NZBIT16(x >> 32, 2) | NZBIT16(x >> 48, 3); \
216
return x; \
217
-}                                \
218
+} \
219
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sw)))(CPUARMState *env, \
220
uint64_t x) \
221
-{                                \
222
- x =                             \
223
- ((uint64_t) EXTEND16((x >> SH0) & 0xffff) << 0) |    \
224
- ((uint64_t) EXTEND16((x >> SH2) & 0xffff) << 32);    \
225
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =            \
226
- NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1);        \
227
+{ \
228
+ x = \
229
+ ((uint64_t) EXTEND16((x >> SH0) & 0xffff) << 0) | \
230
+ ((uint64_t) EXTEND16((x >> SH2) & 0xffff) << 32); \
231
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
232
+ NZBIT32(x >> 0, 0) | NZBIT32(x >> 32, 1); \
233
return x; \
234
-}                                \
235
+} \
236
uint64_t HELPER(glue(iwmmxt_unpack, glue(S, sl)))(CPUARMState *env, \
237
uint64_t x) \
238
-{                                \
239
- x = EXTEND32((x >> SH0) & 0xffffffff);            \
240
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x >> 0);    \
241
+{ \
242
+ x = EXTEND32((x >> SH0) & 0xffffffff); \
243
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(x >> 0); \
244
return x; \
245
}
246
IWMMXT_OP_UNPACK(l, 0, 8, 16, 24)
247
IWMMXT_OP_UNPACK(h, 32, 40, 48, 56)
248
249
-#define IWMMXT_OP_CMP(SUFF, Tb, Tw, Tl, O)            \
250
+#define IWMMXT_OP_CMP(SUFF, Tb, Tw, Tl, O) \
251
uint64_t HELPER(glue(iwmmxt_, glue(SUFF, b)))(CPUARMState *env, \
252
uint64_t a, uint64_t b) \
253
-{                                \
254
- a =                             \
255
- CMP(0, Tb, O, 0xff) | CMP(8, Tb, O, 0xff) |        \
256
- CMP(16, Tb, O, 0xff) | CMP(24, Tb, O, 0xff) |        \
257
- CMP(32, Tb, O, 0xff) | CMP(40, Tb, O, 0xff) |        \
258
- CMP(48, Tb, O, 0xff) | CMP(56, Tb, O, 0xff);        \
259
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =            \
260
- NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) |         \
261
- NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) |        \
262
- NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) |        \
263
- NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7);        \
264
+{ \
265
+ a = \
266
+ CMP(0, Tb, O, 0xff) | CMP(8, Tb, O, 0xff) | \
267
+ CMP(16, Tb, O, 0xff) | CMP(24, Tb, O, 0xff) | \
268
+ CMP(32, Tb, O, 0xff) | CMP(40, Tb, O, 0xff) | \
269
+ CMP(48, Tb, O, 0xff) | CMP(56, Tb, O, 0xff); \
270
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
271
+ NZBIT8(a >> 0, 0) | NZBIT8(a >> 8, 1) | \
272
+ NZBIT8(a >> 16, 2) | NZBIT8(a >> 24, 3) | \
273
+ NZBIT8(a >> 32, 4) | NZBIT8(a >> 40, 5) | \
274
+ NZBIT8(a >> 48, 6) | NZBIT8(a >> 56, 7); \
275
return a; \
276
-}                                \
277
+} \
278
uint64_t HELPER(glue(iwmmxt_, glue(SUFF, w)))(CPUARMState *env, \
279
uint64_t a, uint64_t b) \
280
-{                                \
281
- a = CMP(0, Tw, O, 0xffff) | CMP(16, Tw, O, 0xffff) |    \
282
- CMP(32, Tw, O, 0xffff) | CMP(48, Tw, O, 0xffff);    \
283
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =            \
284
- NZBIT16(a >> 0, 0) | NZBIT16(a >> 16, 1) |        \
285
- NZBIT16(a >> 32, 2) | NZBIT16(a >> 48, 3);        \
286
+{ \
287
+ a = CMP(0, Tw, O, 0xffff) | CMP(16, Tw, O, 0xffff) | \
288
+ CMP(32, Tw, O, 0xffff) | CMP(48, Tw, O, 0xffff); \
289
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
290
+ NZBIT16(a >> 0, 0) | NZBIT16(a >> 16, 1) | \
291
+ NZBIT16(a >> 32, 2) | NZBIT16(a >> 48, 3); \
292
return a; \
293
-}                                \
294
+} \
295
uint64_t HELPER(glue(iwmmxt_, glue(SUFF, l)))(CPUARMState *env, \
296
uint64_t a, uint64_t b) \
297
-{                                \
298
- a = CMP(0, Tl, O, 0xffffffff) |                \
299
- CMP(32, Tl, O, 0xffffffff);                \
300
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =            \
301
- NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1);        \
302
+{ \
303
+ a = CMP(0, Tl, O, 0xffffffff) | \
304
+ CMP(32, Tl, O, 0xffffffff); \
305
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
306
+ NZBIT32(a >> 0, 0) | NZBIT32(a >> 32, 1); \
307
return a; \
308
}
309
#define CMP(SHR, TYPE, OPER, MASK) ((((TYPE) ((a >> SHR) & MASK) OPER \
310
--
36
--
311
2.18.0
37
2.20.1
312
38
313
39
diff view generated by jsdifflib
1
The PL022 interrupt registers have bits allocated as:
1
From: Richard Henderson <richard.henderson@linaro.org>
2
0: ROR (receive overrun)
3
1: RT (receive timeout)
4
2: RX (receive FIFO half full or less)
5
3: TX (transmit FIFO half full or less)
6
2
7
A cut and paste error meant we had the wrong value for
3
The second loop uses a loop induction variable, and the first
8
the PL022_INT_RT constant. This bug doesn't affect device
4
does not. Transform the first to match the second, to simplify
9
behaviour, because we don't implement the receive timeout
5
a following patch moving code between them.
10
feature and so never set that interrupt bit.
11
6
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20201021173749.111103-7-richard.henderson@linaro.org
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Message-id: 20180820141116.9118-20-peter.maydell@linaro.org
14
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
15
---
11
---
16
hw/ssi/pl022.c | 2 +-
12
linux-user/elfload.c | 9 +++++----
17
1 file changed, 1 insertion(+), 1 deletion(-)
13
1 file changed, 5 insertions(+), 4 deletions(-)
18
14
19
diff --git a/hw/ssi/pl022.c b/hw/ssi/pl022.c
15
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
20
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
21
--- a/hw/ssi/pl022.c
17
--- a/linux-user/elfload.c
22
+++ b/hw/ssi/pl022.c
18
+++ b/linux-user/elfload.c
23
@@ -XXX,XX +XXX,XX @@ do { fprintf(stderr, "pl022: error: " fmt , ## __VA_ARGS__);} while (0)
19
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
24
#define PL022_SR_BSY 0x10
20
loaddr = -1, hiaddr = 0;
25
21
info->alignment = 0;
26
#define PL022_INT_ROR 0x01
22
for (i = 0; i < ehdr->e_phnum; ++i) {
27
-#define PL022_INT_RT 0x04
23
- if (phdr[i].p_type == PT_LOAD) {
28
+#define PL022_INT_RT 0x02
24
- abi_ulong a = phdr[i].p_vaddr - phdr[i].p_offset;
29
#define PL022_INT_RX 0x04
25
+ struct elf_phdr *eppnt = phdr + i;
30
#define PL022_INT_TX 0x08
26
+ if (eppnt->p_type == PT_LOAD) {
27
+ abi_ulong a = eppnt->p_vaddr - eppnt->p_offset;
28
if (a < loaddr) {
29
loaddr = a;
30
}
31
- a = phdr[i].p_vaddr + phdr[i].p_memsz;
32
+ a = eppnt->p_vaddr + eppnt->p_memsz;
33
if (a > hiaddr) {
34
hiaddr = a;
35
}
36
++info->nsegs;
37
- info->alignment |= phdr[i].p_align;
38
+ info->alignment |= eppnt->p_align;
39
}
40
}
31
41
32
--
42
--
33
2.18.0
43
2.20.1
34
44
35
45
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
For BTI, we need to know if the executable is static or dynamic,
4
which means looking for PT_INTERP earlier.
5
3
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
4
Message-id: 20180814002653.12828-4-richard.henderson@linaro.org
7
Message-id: 20201021173749.111103-8-richard.henderson@linaro.org
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
---
10
---
8
target/arm/helper.c | 29 +++++------------------------
11
linux-user/elfload.c | 60 +++++++++++++++++++++++---------------------
9
1 file changed, 5 insertions(+), 24 deletions(-)
12
1 file changed, 31 insertions(+), 29 deletions(-)
10
13
11
diff --git a/target/arm/helper.c b/target/arm/helper.c
14
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
12
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
13
--- a/target/arm/helper.c
16
--- a/linux-user/elfload.c
14
+++ b/target/arm/helper.c
17
+++ b/linux-user/elfload.c
15
@@ -XXX,XX +XXX,XX @@ float32 VFP_HELPER(fcvts, d)(float64 x, CPUARMState *env)
18
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
16
#define VFP_CONV_FIX_FLOAT(name, p, fsz, isz, itype) \
19
17
float##fsz HELPER(vfp_##name##to##p)(uint##isz##_t x, uint32_t shift, \
20
mmap_lock();
18
void *fpstp) \
21
19
-{ \
22
- /* Find the maximum size of the image and allocate an appropriate
20
- float_status *fpst = fpstp; \
23
- amount of memory to handle that. */
21
- float##fsz tmp; \
24
+ /*
22
- tmp = itype##_to_##float##fsz(x, fpst); \
25
+ * Find the maximum size of the image and allocate an appropriate
23
- return float##fsz##_scalbn(tmp, -(int)shift, fpst); \
26
+ * amount of memory to handle that. Locate the interpreter, if any.
24
-}
27
+ */
25
+{ return itype##_to_##float##fsz##_scalbn(x, -shift, fpstp); }
28
loaddr = -1, hiaddr = 0;
26
29
info->alignment = 0;
27
/* Notice that we want only input-denormal exception flags from the
30
for (i = 0; i < ehdr->e_phnum; ++i) {
28
* scalbn operation: the other possible flags (overflow+inexact if
31
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
29
@@ -XXX,XX +XXX,XX @@ VFP_CONV_FIX_A64(uq, s, 32, 64, uint64)
32
}
30
#undef VFP_CONV_FLOAT_FIX_ROUND
33
++info->nsegs;
31
#undef VFP_CONV_FIX_A64
34
info->alignment |= eppnt->p_align;
32
35
+ } else if (eppnt->p_type == PT_INTERP && pinterp_name) {
33
-/* Conversion to/from f16 can overflow to infinity before/after scaling.
36
+ g_autofree char *interp_name = NULL;
34
- * Therefore we convert to f64, scale, and then convert f64 to f16; or
37
+
35
- * vice versa for conversion to integer.
38
+ if (*pinterp_name) {
36
- *
39
+ errmsg = "Multiple PT_INTERP entries";
37
- * For 16- and 32-bit integers, the conversion to f64 never rounds.
40
+ goto exit_errmsg;
38
- * For 64-bit integers, any integer that would cause rounding will also
41
+ }
39
- * overflow to f16 infinity, so there is no double rounding problem.
42
+ interp_name = g_malloc(eppnt->p_filesz);
40
- */
43
+ if (!interp_name) {
44
+ goto exit_perror;
45
+ }
46
+
47
+ if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
48
+ memcpy(interp_name, bprm_buf + eppnt->p_offset,
49
+ eppnt->p_filesz);
50
+ } else {
51
+ retval = pread(image_fd, interp_name, eppnt->p_filesz,
52
+ eppnt->p_offset);
53
+ if (retval != eppnt->p_filesz) {
54
+ goto exit_perror;
55
+ }
56
+ }
57
+ if (interp_name[eppnt->p_filesz - 1] != 0) {
58
+ errmsg = "Invalid PT_INTERP entry";
59
+ goto exit_errmsg;
60
+ }
61
+ *pinterp_name = g_steal_pointer(&interp_name);
62
}
63
}
64
65
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
66
if (vaddr_em > info->brk) {
67
info->brk = vaddr_em;
68
}
69
- } else if (eppnt->p_type == PT_INTERP && pinterp_name) {
70
- g_autofree char *interp_name = NULL;
41
-
71
-
42
-static float16 do_postscale_fp16(float64 f, int shift, float_status *fpst)
72
- if (*pinterp_name) {
43
-{
73
- errmsg = "Multiple PT_INTERP entries";
44
- return float64_to_float16(float64_scalbn(f, -shift, fpst), true, fpst);
74
- goto exit_errmsg;
45
-}
75
- }
76
- interp_name = g_malloc(eppnt->p_filesz);
77
- if (!interp_name) {
78
- goto exit_perror;
79
- }
46
-
80
-
47
uint32_t HELPER(vfp_sltoh)(uint32_t x, uint32_t shift, void *fpst)
81
- if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
48
{
82
- memcpy(interp_name, bprm_buf + eppnt->p_offset,
49
- return do_postscale_fp16(int32_to_float64(x, fpst), shift, fpst);
83
- eppnt->p_filesz);
50
+ return int32_to_float16_scalbn(x, -shift, fpst);
84
- } else {
51
}
85
- retval = pread(image_fd, interp_name, eppnt->p_filesz,
52
86
- eppnt->p_offset);
53
uint32_t HELPER(vfp_ultoh)(uint32_t x, uint32_t shift, void *fpst)
87
- if (retval != eppnt->p_filesz) {
54
{
88
- goto exit_perror;
55
- return do_postscale_fp16(uint32_to_float64(x, fpst), shift, fpst);
89
- }
56
+ return uint32_to_float16_scalbn(x, -shift, fpst);
90
- }
57
}
91
- if (interp_name[eppnt->p_filesz - 1] != 0) {
58
92
- errmsg = "Invalid PT_INTERP entry";
59
uint32_t HELPER(vfp_sqtoh)(uint64_t x, uint32_t shift, void *fpst)
93
- goto exit_errmsg;
60
{
94
- }
61
- return do_postscale_fp16(int64_to_float64(x, fpst), shift, fpst);
95
- *pinterp_name = g_steal_pointer(&interp_name);
62
+ return int64_to_float16_scalbn(x, -shift, fpst);
96
#ifdef TARGET_MIPS
63
}
97
} else if (eppnt->p_type == PT_MIPS_ABIFLAGS) {
64
98
Mips_elf_abiflags_v0 abiflags;
65
uint32_t HELPER(vfp_uqtoh)(uint64_t x, uint32_t shift, void *fpst)
66
{
67
- return do_postscale_fp16(uint64_to_float64(x, fpst), shift, fpst);
68
+ return uint64_to_float16_scalbn(x, -shift, fpst);
69
}
70
71
static float64 do_prescale_fp16(float16 f, int shift, float_status *fpst)
72
--
99
--
73
2.18.0
100
2.20.1
74
101
75
102
diff view generated by jsdifflib
1
The IoTKit doesn't have any MSCs itself but it does need
1
From: Richard Henderson <richard.henderson@linaro.org>
2
some wiring to connect the external signals from MSCs
3
in the outer board model up to the registers and the
4
NVIC IRQ line.
5
2
6
We also need to expose a MemoryRegion corresponding to
3
This is a bit clearer than open-coding some of this
7
the AHB bus, so that MSCs in the outer board model can
4
with a bare c string.
8
use that as their downstream port. (In the FPGA this is
9
the "AHB Slave Expansion" ports shown in the block
10
diagram in the AN505 documentation.)
11
5
6
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20201021173749.111103-9-richard.henderson@linaro.org
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
14
Message-id: 20180820141116.9118-14-peter.maydell@linaro.org
15
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
16
---
10
---
17
include/hw/arm/iotkit.h | 8 ++++++++
11
linux-user/elfload.c | 37 ++++++++++++++++++++-----------------
18
hw/arm/iotkit.c | 15 +++++++++++++++
12
1 file changed, 20 insertions(+), 17 deletions(-)
19
2 files changed, 23 insertions(+)
20
13
21
diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h
14
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
22
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
23
--- a/include/hw/arm/iotkit.h
16
--- a/linux-user/elfload.c
24
+++ b/include/hw/arm/iotkit.h
17
+++ b/linux-user/elfload.c
25
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@
26
* + QOM property "EXP_NUMIRQ" sets the number of expansion interrupts
19
#include "qemu/guest-random.h"
27
* + Named GPIO inputs "EXP_IRQ" 0..n are the expansion interrupts, which
20
#include "qemu/units.h"
28
* are wired to the NVIC lines 32 .. n+32
21
#include "qemu/selfmap.h"
29
+ * + sysbus MMIO region 0 is the "AHB Slave Expansion" which allows
22
+#include "qapi/error.h"
30
+ * bus master devices in the board model to make transactions into
23
31
+ * all the devices and memory areas in the IoTKit
24
#ifdef _ARCH_PPC64
32
* Controlling up to 4 AHB expansion PPBs which a system using the IoTKit
25
#undef ARCH_DLINFO
33
* might provide:
26
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
34
* + named GPIO outputs apb_ppcexp{0,1,2,3}_nonsec[0..15]
27
struct elf_phdr *phdr;
35
@@ -XXX,XX +XXX,XX @@
28
abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
36
* Controlling each of the 16 expansion MPCs which a system using the IoTKit
29
int i, retval;
37
* might provide:
30
- const char *errmsg;
38
* + named GPIO inputs mpcexp_status[0..15]
31
+ Error *err = NULL;
39
+ * Controlling each of the 16 expansion MSCs which a system using the IoTKit
32
40
+ * might provide:
33
/* First of all, some simple consistency checks */
41
+ * + named GPIO inputs mscexp_status[0..15]
34
- errmsg = "Invalid ELF image for this architecture";
42
+ * + named GPIO outputs mscexp_clear[0..15]
35
if (!elf_check_ident(ehdr)) {
43
+ * + named GPIO outputs mscexp_ns[0..15]
36
+ error_setg(&err, "Invalid ELF image for this architecture");
44
*/
37
goto exit_errmsg;
45
38
}
46
#ifndef IOTKIT_H
39
bswap_ehdr(ehdr);
47
diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c
40
if (!elf_check_ehdr(ehdr)) {
48
index XXXXXXX..XXXXXXX 100644
41
+ error_setg(&err, "Invalid ELF image for this architecture");
49
--- a/hw/arm/iotkit.c
42
goto exit_errmsg;
50
+++ b/hw/arm/iotkit.c
43
}
51
@@ -XXX,XX +XXX,XX @@ static void iotkit_realize(DeviceState *dev, Error **errp)
44
52
45
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
53
iotkit_forward_sec_resp_cfg(s);
46
g_autofree char *interp_name = NULL;
54
47
55
+ /* Forward the MSC related signals */
48
if (*pinterp_name) {
56
+ qdev_pass_gpios(dev_secctl, dev, "mscexp_status");
49
- errmsg = "Multiple PT_INTERP entries";
57
+ qdev_pass_gpios(dev_secctl, dev, "mscexp_clear");
50
+ error_setg(&err, "Multiple PT_INTERP entries");
58
+ qdev_pass_gpios(dev_secctl, dev, "mscexp_ns");
51
goto exit_errmsg;
59
+ qdev_connect_gpio_out_named(dev_secctl, "msc_irq", 0,
52
}
60
+ qdev_get_gpio_in(DEVICE(&s->armv7m), 11));
61
+
53
+
62
+ /*
54
interp_name = g_malloc(eppnt->p_filesz);
63
+ * Expose our container region to the board model; this corresponds
55
- if (!interp_name) {
64
+ * to the AHB Slave Expansion ports which allow bus master devices
56
- goto exit_perror;
65
+ * (eg DMA controllers) in the board model to make transactions into
57
- }
66
+ * devices in the IoTKit.
58
67
+ */
59
if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
68
+ sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->container);
60
memcpy(interp_name, bprm_buf + eppnt->p_offset,
69
+
61
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
70
system_clock_scale = NANOSECONDS_PER_SECOND / s->mainclk_frq;
62
retval = pread(image_fd, interp_name, eppnt->p_filesz,
63
eppnt->p_offset);
64
if (retval != eppnt->p_filesz) {
65
- goto exit_perror;
66
+ goto exit_read;
67
}
68
}
69
if (interp_name[eppnt->p_filesz - 1] != 0) {
70
- errmsg = "Invalid PT_INTERP entry";
71
+ error_setg(&err, "Invalid PT_INTERP entry");
72
goto exit_errmsg;
73
}
74
*pinterp_name = g_steal_pointer(&interp_name);
75
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
76
(ehdr->e_type == ET_EXEC ? MAP_FIXED : 0),
77
-1, 0);
78
if (load_addr == -1) {
79
- goto exit_perror;
80
+ goto exit_mmap;
81
}
82
load_bias = load_addr - loaddr;
83
84
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
85
image_fd, eppnt->p_offset - vaddr_po);
86
87
if (error == -1) {
88
- goto exit_perror;
89
+ goto exit_mmap;
90
}
91
}
92
93
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
94
} else if (eppnt->p_type == PT_MIPS_ABIFLAGS) {
95
Mips_elf_abiflags_v0 abiflags;
96
if (eppnt->p_filesz < sizeof(Mips_elf_abiflags_v0)) {
97
- errmsg = "Invalid PT_MIPS_ABIFLAGS entry";
98
+ error_setg(&err, "Invalid PT_MIPS_ABIFLAGS entry");
99
goto exit_errmsg;
100
}
101
if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
102
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
103
retval = pread(image_fd, &abiflags, sizeof(Mips_elf_abiflags_v0),
104
eppnt->p_offset);
105
if (retval != sizeof(Mips_elf_abiflags_v0)) {
106
- goto exit_perror;
107
+ goto exit_read;
108
}
109
}
110
bswap_mips_abiflags(&abiflags);
111
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
112
113
exit_read:
114
if (retval >= 0) {
115
- errmsg = "Incomplete read of file header";
116
- goto exit_errmsg;
117
+ error_setg(&err, "Incomplete read of file header");
118
+ } else {
119
+ error_setg_errno(&err, errno, "Error reading file header");
120
}
121
- exit_perror:
122
- errmsg = strerror(errno);
123
+ goto exit_errmsg;
124
+ exit_mmap:
125
+ error_setg_errno(&err, errno, "Error mapping file");
126
+ goto exit_errmsg;
127
exit_errmsg:
128
- fprintf(stderr, "%s: %s\n", image_name, errmsg);
129
+ error_reportf_err(err, "%s: ", image_name);
130
exit(-1);
71
}
131
}
72
132
73
--
133
--
74
2.18.0
134
2.20.1
75
135
76
136
diff view generated by jsdifflib
1
The handling of framebuffer properties in the bcm2835_property code
1
From: Richard Henderson <richard.henderson@linaro.org>
2
is a bit clumsy, because for each of the many fb related properties
3
we try to track the value we're about to set and whether we're going
4
to be setting a value, and then we hand all the new values off
5
to the framebuffer via a function which takes them all as separate
6
arguments. It would be simpler if the property code could easily
7
copy all the framebuffer's current settings, update them with
8
the new specified values and then ask the framebuffer to switch
9
to the new set.
10
2
11
As the first part of this refactoring, pull all the fb config
3
This is slightly clearer than just using strerror, though
12
settings fields in BCM2835FBState out into their own struct.
4
the different forms produced by error_setg_file_open and
5
error_setg_errno isn't entirely convenient.
13
6
7
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20201021173749.111103-10-richard.henderson@linaro.org
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
16
Message-id: 20180814144436.679-2-peter.maydell@linaro.org
17
---
11
---
18
include/hw/display/bcm2835_fb.h | 26 ++++++--
12
linux-user/elfload.c | 15 ++++++++-------
19
hw/display/bcm2835_fb.c | 114 +++++++++++++++++---------------
13
1 file changed, 8 insertions(+), 7 deletions(-)
20
hw/misc/bcm2835_property.c | 28 ++++----
21
3 files changed, 94 insertions(+), 74 deletions(-)
22
14
23
diff --git a/include/hw/display/bcm2835_fb.h b/include/hw/display/bcm2835_fb.h
15
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
24
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
25
--- a/include/hw/display/bcm2835_fb.h
17
--- a/linux-user/elfload.c
26
+++ b/include/hw/display/bcm2835_fb.h
18
+++ b/linux-user/elfload.c
27
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@ static void load_elf_interp(const char *filename, struct image_info *info,
28
#define TYPE_BCM2835_FB "bcm2835-fb"
20
char bprm_buf[BPRM_BUF_SIZE])
29
#define BCM2835_FB(obj) OBJECT_CHECK(BCM2835FBState, (obj), TYPE_BCM2835_FB)
21
{
30
22
int fd, retval;
31
+/*
23
+ Error *err = NULL;
32
+ * Configuration information about the fb which the guest can program
24
33
+ * via the mailbox property interface.
25
fd = open(path(filename), O_RDONLY);
34
+ */
26
if (fd < 0) {
35
+typedef struct {
27
- goto exit_perror;
36
+ uint32_t xres, yres;
28
+ error_setg_file_open(&err, errno, filename);
37
+ uint32_t xres_virtual, yres_virtual;
29
+ error_report_err(err);
38
+ uint32_t xoffset, yoffset;
30
+ exit(-1);
39
+ uint32_t bpp;
31
}
40
+ uint32_t base;
32
41
+ uint32_t pixo;
33
retval = read(fd, bprm_buf, BPRM_BUF_SIZE);
42
+ uint32_t alpha;
34
if (retval < 0) {
43
+} BCM2835FBConfig;
35
- goto exit_perror;
36
+ error_setg_errno(&err, errno, "Error reading file header");
37
+ error_reportf_err(err, "%s: ", filename);
38
+ exit(-1);
39
}
44
+
40
+
45
typedef struct {
41
if (retval < BPRM_BUF_SIZE) {
46
/*< private >*/
42
memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval);
47
SysBusDevice busdev;
48
@@ -XXX,XX +XXX,XX @@ typedef struct {
49
qemu_irq mbox_irq;
50
51
bool lock, invalidate, pending;
52
- uint32_t xres, yres;
53
- uint32_t xres_virtual, yres_virtual;
54
- uint32_t xoffset, yoffset;
55
- uint32_t bpp;
56
- uint32_t base, pitch, size;
57
- uint32_t pixo, alpha;
58
+
59
+ BCM2835FBConfig config;
60
+
61
+ /* These are just cached values calculated from the config settings */
62
+ uint32_t size;
63
+ uint32_t pitch;
64
} BCM2835FBState;
65
66
void bcm2835_fb_reconfigure(BCM2835FBState *s, uint32_t *xres, uint32_t *yres,
67
diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c
68
index XXXXXXX..XXXXXXX 100644
69
--- a/hw/display/bcm2835_fb.c
70
+++ b/hw/display/bcm2835_fb.c
71
@@ -XXX,XX +XXX,XX @@ static void draw_line_src16(void *opaque, uint8_t *dst, const uint8_t *src,
72
int bpp = surface_bits_per_pixel(surface);
73
74
while (width--) {
75
- switch (s->bpp) {
76
+ switch (s->config.bpp) {
77
case 8:
78
/* lookup palette starting at video ram base
79
* TODO: cache translation, rather than doing this each time!
80
@@ -XXX,XX +XXX,XX @@ static void draw_line_src16(void *opaque, uint8_t *dst, const uint8_t *src,
81
break;
82
}
83
84
- if (s->pixo == 0) {
85
+ if (s->config.pixo == 0) {
86
/* swap to BGR pixel format */
87
uint8_t tmp = r;
88
r = b;
89
@@ -XXX,XX +XXX,XX @@ static void fb_update_display(void *opaque)
90
int src_width = 0;
91
int dest_width = 0;
92
93
- if (s->lock || !s->xres) {
94
+ if (s->lock || !s->config.xres) {
95
return;
96
}
43
}
97
44
98
- src_width = s->xres * (s->bpp >> 3);
45
load_elf_image(filename, fd, info, NULL, bprm_buf);
99
- dest_width = s->xres;
46
- return;
100
+ src_width = s->config.xres * (s->config.bpp >> 3);
47
-
101
+ dest_width = s->config.xres;
48
- exit_perror:
102
49
- fprintf(stderr, "%s: %s\n", filename, strerror(errno));
103
switch (surface_bits_per_pixel(surface)) {
50
- exit(-1);
104
case 0:
105
@@ -XXX,XX +XXX,XX @@ static void fb_update_display(void *opaque)
106
}
107
108
if (s->invalidate) {
109
- framebuffer_update_memory_section(&s->fbsection, s->dma_mr, s->base,
110
- s->yres, src_width);
111
+ framebuffer_update_memory_section(&s->fbsection, s->dma_mr,
112
+ s->config.base,
113
+ s->config.yres, src_width);
114
}
115
116
- framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
117
+ framebuffer_update_display(surface, &s->fbsection,
118
+ s->config.xres, s->config.yres,
119
src_width, dest_width, 0, s->invalidate,
120
draw_line_src16, s, &first, &last);
121
122
if (first >= 0) {
123
- dpy_gfx_update(s->con, 0, first, s->xres, last - first + 1);
124
+ dpy_gfx_update(s->con, 0, first, s->config.xres, last - first + 1);
125
}
126
127
s->invalidate = false;
128
@@ -XXX,XX +XXX,XX @@ static void bcm2835_fb_mbox_push(BCM2835FBState *s, uint32_t value)
129
130
s->lock = true;
131
132
- s->xres = ldl_le_phys(&s->dma_as, value);
133
- s->yres = ldl_le_phys(&s->dma_as, value + 4);
134
- s->xres_virtual = ldl_le_phys(&s->dma_as, value + 8);
135
- s->yres_virtual = ldl_le_phys(&s->dma_as, value + 12);
136
- s->bpp = ldl_le_phys(&s->dma_as, value + 20);
137
- s->xoffset = ldl_le_phys(&s->dma_as, value + 24);
138
- s->yoffset = ldl_le_phys(&s->dma_as, value + 28);
139
+ s->config.xres = ldl_le_phys(&s->dma_as, value);
140
+ s->config.yres = ldl_le_phys(&s->dma_as, value + 4);
141
+ s->config.xres_virtual = ldl_le_phys(&s->dma_as, value + 8);
142
+ s->config.yres_virtual = ldl_le_phys(&s->dma_as, value + 12);
143
+ s->config.bpp = ldl_le_phys(&s->dma_as, value + 20);
144
+ s->config.xoffset = ldl_le_phys(&s->dma_as, value + 24);
145
+ s->config.yoffset = ldl_le_phys(&s->dma_as, value + 28);
146
147
- s->base = s->vcram_base | (value & 0xc0000000);
148
- s->base += BCM2835_FB_OFFSET;
149
+ s->config.base = s->vcram_base | (value & 0xc0000000);
150
+ s->config.base += BCM2835_FB_OFFSET;
151
152
/* TODO - Manage properly virtual resolution */
153
154
- s->pitch = s->xres * (s->bpp >> 3);
155
- s->size = s->yres * s->pitch;
156
+ s->pitch = s->config.xres * (s->config.bpp >> 3);
157
+ s->size = s->config.yres * s->pitch;
158
159
stl_le_phys(&s->dma_as, value + 16, s->pitch);
160
- stl_le_phys(&s->dma_as, value + 32, s->base);
161
+ stl_le_phys(&s->dma_as, value + 32, s->config.base);
162
stl_le_phys(&s->dma_as, value + 36, s->size);
163
164
s->invalidate = true;
165
- qemu_console_resize(s->con, s->xres, s->yres);
166
+ qemu_console_resize(s->con, s->config.xres, s->config.yres);
167
s->lock = false;
168
}
51
}
169
52
170
@@ -XXX,XX +XXX,XX @@ void bcm2835_fb_reconfigure(BCM2835FBState *s, uint32_t *xres, uint32_t *yres,
53
static int symfind(const void *s0, const void *s1)
171
172
/* TODO: input validation! */
173
if (xres) {
174
- s->xres = *xres;
175
+ s->config.xres = *xres;
176
}
177
if (yres) {
178
- s->yres = *yres;
179
+ s->config.yres = *yres;
180
}
181
if (xoffset) {
182
- s->xoffset = *xoffset;
183
+ s->config.xoffset = *xoffset;
184
}
185
if (yoffset) {
186
- s->yoffset = *yoffset;
187
+ s->config.yoffset = *yoffset;
188
}
189
if (bpp) {
190
- s->bpp = *bpp;
191
+ s->config.bpp = *bpp;
192
}
193
if (pixo) {
194
- s->pixo = *pixo;
195
+ s->config.pixo = *pixo;
196
}
197
if (alpha) {
198
- s->alpha = *alpha;
199
+ s->config.alpha = *alpha;
200
}
201
202
/* TODO - Manage properly virtual resolution */
203
204
- s->pitch = s->xres * (s->bpp >> 3);
205
- s->size = s->yres * s->pitch;
206
+ s->pitch = s->config.xres * (s->config.bpp >> 3);
207
+ s->size = s->config.yres * s->pitch;
208
209
s->invalidate = true;
210
- qemu_console_resize(s->con, s->xres, s->yres);
211
+ qemu_console_resize(s->con, s->config.xres, s->config.yres);
212
s->lock = false;
213
}
214
215
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_bcm2835_fb = {
216
VMSTATE_BOOL(lock, BCM2835FBState),
217
VMSTATE_BOOL(invalidate, BCM2835FBState),
218
VMSTATE_BOOL(pending, BCM2835FBState),
219
- VMSTATE_UINT32(xres, BCM2835FBState),
220
- VMSTATE_UINT32(yres, BCM2835FBState),
221
- VMSTATE_UINT32(xres_virtual, BCM2835FBState),
222
- VMSTATE_UINT32(yres_virtual, BCM2835FBState),
223
- VMSTATE_UINT32(xoffset, BCM2835FBState),
224
- VMSTATE_UINT32(yoffset, BCM2835FBState),
225
- VMSTATE_UINT32(bpp, BCM2835FBState),
226
- VMSTATE_UINT32(base, BCM2835FBState),
227
+ VMSTATE_UINT32(config.xres, BCM2835FBState),
228
+ VMSTATE_UINT32(config.yres, BCM2835FBState),
229
+ VMSTATE_UINT32(config.xres_virtual, BCM2835FBState),
230
+ VMSTATE_UINT32(config.yres_virtual, BCM2835FBState),
231
+ VMSTATE_UINT32(config.xoffset, BCM2835FBState),
232
+ VMSTATE_UINT32(config.yoffset, BCM2835FBState),
233
+ VMSTATE_UINT32(config.bpp, BCM2835FBState),
234
+ VMSTATE_UINT32(config.base, BCM2835FBState),
235
VMSTATE_UINT32(pitch, BCM2835FBState),
236
VMSTATE_UINT32(size, BCM2835FBState),
237
- VMSTATE_UINT32(pixo, BCM2835FBState),
238
- VMSTATE_UINT32(alpha, BCM2835FBState),
239
+ VMSTATE_UINT32(config.pixo, BCM2835FBState),
240
+ VMSTATE_UINT32(config.alpha, BCM2835FBState),
241
VMSTATE_END_OF_LIST()
242
}
243
};
244
@@ -XXX,XX +XXX,XX @@ static void bcm2835_fb_reset(DeviceState *dev)
245
246
s->pending = false;
247
248
- s->xres_virtual = s->xres;
249
- s->yres_virtual = s->yres;
250
- s->xoffset = 0;
251
- s->yoffset = 0;
252
- s->base = s->vcram_base + BCM2835_FB_OFFSET;
253
- s->pitch = s->xres * (s->bpp >> 3);
254
- s->size = s->yres * s->pitch;
255
+ s->config.xres_virtual = s->config.xres;
256
+ s->config.yres_virtual = s->config.yres;
257
+ s->config.xoffset = 0;
258
+ s->config.yoffset = 0;
259
+ s->config.base = s->vcram_base + BCM2835_FB_OFFSET;
260
+ s->pitch = s->config.xres * (s->config.bpp >> 3);
261
+ s->size = s->config.yres * s->pitch;
262
263
s->invalidate = true;
264
s->lock = false;
265
@@ -XXX,XX +XXX,XX @@ static void bcm2835_fb_realize(DeviceState *dev, Error **errp)
266
bcm2835_fb_reset(dev);
267
268
s->con = graphic_console_init(dev, 0, &vgafb_ops, s);
269
- qemu_console_resize(s->con, s->xres, s->yres);
270
+ qemu_console_resize(s->con, s->config.xres, s->config.yres);
271
}
272
273
static Property bcm2835_fb_props[] = {
274
DEFINE_PROP_UINT32("vcram-base", BCM2835FBState, vcram_base, 0),/*required*/
275
DEFINE_PROP_UINT32("vcram-size", BCM2835FBState, vcram_size,
276
DEFAULT_VCRAM_SIZE),
277
- DEFINE_PROP_UINT32("xres", BCM2835FBState, xres, 640),
278
- DEFINE_PROP_UINT32("yres", BCM2835FBState, yres, 480),
279
- DEFINE_PROP_UINT32("bpp", BCM2835FBState, bpp, 16),
280
- DEFINE_PROP_UINT32("pixo", BCM2835FBState, pixo, 1), /* 1=RGB, 0=BGR */
281
- DEFINE_PROP_UINT32("alpha", BCM2835FBState, alpha, 2), /* alpha ignored */
282
+ DEFINE_PROP_UINT32("xres", BCM2835FBState, config.xres, 640),
283
+ DEFINE_PROP_UINT32("yres", BCM2835FBState, config.yres, 480),
284
+ DEFINE_PROP_UINT32("bpp", BCM2835FBState, config.bpp, 16),
285
+ DEFINE_PROP_UINT32("pixo",
286
+ BCM2835FBState, config.pixo, 1), /* 1=RGB, 0=BGR */
287
+ DEFINE_PROP_UINT32("alpha",
288
+ BCM2835FBState, config.alpha, 2), /* alpha ignored */
289
DEFINE_PROP_END_OF_LIST()
290
};
291
292
diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c
293
index XXXXXXX..XXXXXXX 100644
294
--- a/hw/misc/bcm2835_property.c
295
+++ b/hw/misc/bcm2835_property.c
296
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
297
/* Frame buffer */
298
299
case 0x00040001: /* Allocate buffer */
300
- stl_le_phys(&s->dma_as, value + 12, s->fbdev->base);
301
- tmp_xres = newxres != NULL ? *newxres : s->fbdev->xres;
302
- tmp_yres = newyres != NULL ? *newyres : s->fbdev->yres;
303
- tmp_bpp = newbpp != NULL ? *newbpp : s->fbdev->bpp;
304
+ stl_le_phys(&s->dma_as, value + 12, s->fbdev->config.base);
305
+ tmp_xres = newxres != NULL ? *newxres : s->fbdev->config.xres;
306
+ tmp_yres = newyres != NULL ? *newyres : s->fbdev->config.yres;
307
+ tmp_bpp = newbpp != NULL ? *newbpp : s->fbdev->config.bpp;
308
stl_le_phys(&s->dma_as, value + 16,
309
tmp_xres * tmp_yres * tmp_bpp / 8);
310
resplen = 8;
311
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
312
break;
313
case 0x00040003: /* Get display width/height */
314
case 0x00040004:
315
- tmp_xres = newxres != NULL ? *newxres : s->fbdev->xres;
316
- tmp_yres = newyres != NULL ? *newyres : s->fbdev->yres;
317
+ tmp_xres = newxres != NULL ? *newxres : s->fbdev->config.xres;
318
+ tmp_yres = newyres != NULL ? *newyres : s->fbdev->config.yres;
319
stl_le_phys(&s->dma_as, value + 12, tmp_xres);
320
stl_le_phys(&s->dma_as, value + 16, tmp_yres);
321
resplen = 8;
322
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
323
resplen = 8;
324
break;
325
case 0x00040005: /* Get depth */
326
- tmp_bpp = newbpp != NULL ? *newbpp : s->fbdev->bpp;
327
+ tmp_bpp = newbpp != NULL ? *newbpp : s->fbdev->config.bpp;
328
stl_le_phys(&s->dma_as, value + 12, tmp_bpp);
329
resplen = 4;
330
break;
331
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
332
resplen = 4;
333
break;
334
case 0x00040006: /* Get pixel order */
335
- tmp_pixo = newpixo != NULL ? *newpixo : s->fbdev->pixo;
336
+ tmp_pixo = newpixo != NULL ? *newpixo : s->fbdev->config.pixo;
337
stl_le_phys(&s->dma_as, value + 12, tmp_pixo);
338
resplen = 4;
339
break;
340
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
341
resplen = 4;
342
break;
343
case 0x00040007: /* Get alpha */
344
- tmp_alpha = newalpha != NULL ? *newalpha : s->fbdev->alpha;
345
+ tmp_alpha = newalpha != NULL ? *newalpha : s->fbdev->config.alpha;
346
stl_le_phys(&s->dma_as, value + 12, tmp_alpha);
347
resplen = 4;
348
break;
349
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
350
resplen = 4;
351
break;
352
case 0x00040008: /* Get pitch */
353
- tmp_xres = newxres != NULL ? *newxres : s->fbdev->xres;
354
- tmp_bpp = newbpp != NULL ? *newbpp : s->fbdev->bpp;
355
+ tmp_xres = newxres != NULL ? *newxres : s->fbdev->config.xres;
356
+ tmp_bpp = newbpp != NULL ? *newbpp : s->fbdev->config.bpp;
357
stl_le_phys(&s->dma_as, value + 12, tmp_xres * tmp_bpp / 8);
358
resplen = 4;
359
break;
360
case 0x00040009: /* Get virtual offset */
361
- tmp_xoffset = newxoffset != NULL ? *newxoffset : s->fbdev->xoffset;
362
- tmp_yoffset = newyoffset != NULL ? *newyoffset : s->fbdev->yoffset;
363
+ tmp_xoffset = newxoffset != NULL ?
364
+ *newxoffset : s->fbdev->config.xoffset;
365
+ tmp_yoffset = newyoffset != NULL ?
366
+ *newyoffset : s->fbdev->config.yoffset;
367
stl_le_phys(&s->dma_as, value + 12, tmp_xoffset);
368
stl_le_phys(&s->dma_as, value + 16, tmp_yoffset);
369
resplen = 8;
370
--
54
--
371
2.18.0
55
2.20.1
372
56
373
57
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
This is generic support, with the code disabled for all targets.
4
3
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
4
Message-id: 20180814002653.12828-2-richard.henderson@linaro.org
6
Message-id: 20201021173749.111103-11-richard.henderson@linaro.org
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
---
9
---
8
include/fpu/softfloat.h | 56 ++++++++----
10
linux-user/qemu.h | 4 ++
9
fpu/softfloat.c | 188 +++++++++++++++++++++++++++++-----------
11
linux-user/elfload.c | 157 +++++++++++++++++++++++++++++++++++++++++++
10
2 files changed, 179 insertions(+), 65 deletions(-)
12
2 files changed, 161 insertions(+)
11
13
12
diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h
14
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
13
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
14
--- a/include/fpu/softfloat.h
16
--- a/linux-user/qemu.h
15
+++ b/include/fpu/softfloat.h
17
+++ b/linux-user/qemu.h
16
@@ -XXX,XX +XXX,XX @@ enum {
18
@@ -XXX,XX +XXX,XX @@ struct image_info {
17
/*----------------------------------------------------------------------------
19
abi_ulong interpreter_loadmap_addr;
18
| Software IEC/IEEE integer-to-floating-point conversion routines.
20
abi_ulong interpreter_pt_dynamic_addr;
19
*----------------------------------------------------------------------------*/
21
struct image_info *other_info;
20
+
22
+
21
+float16 int16_to_float16_scalbn(int16_t a, int, float_status *status);
23
+ /* For target-specific processing of NT_GNU_PROPERTY_TYPE_0. */
22
+float16 int32_to_float16_scalbn(int32_t a, int, float_status *status);
24
+ uint32_t note_flags;
23
+float16 int64_to_float16_scalbn(int64_t a, int, float_status *status);
25
+
24
+float16 uint16_to_float16_scalbn(uint16_t a, int, float_status *status);
26
#ifdef TARGET_MIPS
25
+float16 uint32_to_float16_scalbn(uint32_t a, int, float_status *status);
27
int fp_abi;
26
+float16 uint64_to_float16_scalbn(uint64_t a, int, float_status *status);
28
int interp_fp_abi;
27
+
29
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
28
+float16 int16_to_float16(int16_t a, float_status *status);
29
+float16 int32_to_float16(int32_t a, float_status *status);
30
+float16 int64_to_float16(int64_t a, float_status *status);
31
+float16 uint16_to_float16(uint16_t a, float_status *status);
32
+float16 uint32_to_float16(uint32_t a, float_status *status);
33
+float16 uint64_to_float16(uint64_t a, float_status *status);
34
+
35
+float32 int16_to_float32_scalbn(int16_t, int, float_status *status);
36
+float32 int32_to_float32_scalbn(int32_t, int, float_status *status);
37
+float32 int64_to_float32_scalbn(int64_t, int, float_status *status);
38
+float32 uint16_to_float32_scalbn(uint16_t, int, float_status *status);
39
+float32 uint32_to_float32_scalbn(uint32_t, int, float_status *status);
40
+float32 uint64_to_float32_scalbn(uint64_t, int, float_status *status);
41
+
42
float32 int16_to_float32(int16_t, float_status *status);
43
float32 int32_to_float32(int32_t, float_status *status);
44
-float64 int16_to_float64(int16_t, float_status *status);
45
-float64 int32_to_float64(int32_t, float_status *status);
46
+float32 int64_to_float32(int64_t, float_status *status);
47
float32 uint16_to_float32(uint16_t, float_status *status);
48
float32 uint32_to_float32(uint32_t, float_status *status);
49
+float32 uint64_to_float32(uint64_t, float_status *status);
50
+
51
+float64 int16_to_float64_scalbn(int16_t, int, float_status *status);
52
+float64 int32_to_float64_scalbn(int32_t, int, float_status *status);
53
+float64 int64_to_float64_scalbn(int64_t, int, float_status *status);
54
+float64 uint16_to_float64_scalbn(uint16_t, int, float_status *status);
55
+float64 uint32_to_float64_scalbn(uint32_t, int, float_status *status);
56
+float64 uint64_to_float64_scalbn(uint64_t, int, float_status *status);
57
+
58
+float64 int16_to_float64(int16_t, float_status *status);
59
+float64 int32_to_float64(int32_t, float_status *status);
60
+float64 int64_to_float64(int64_t, float_status *status);
61
float64 uint16_to_float64(uint16_t, float_status *status);
62
float64 uint32_to_float64(uint32_t, float_status *status);
63
-floatx80 int32_to_floatx80(int32_t, float_status *status);
64
-float128 int32_to_float128(int32_t, float_status *status);
65
-float32 int64_to_float32(int64_t, float_status *status);
66
-float64 int64_to_float64(int64_t, float_status *status);
67
-floatx80 int64_to_floatx80(int64_t, float_status *status);
68
-float128 int64_to_float128(int64_t, float_status *status);
69
-float32 uint64_to_float32(uint64_t, float_status *status);
70
float64 uint64_to_float64(uint64_t, float_status *status);
71
+
72
+floatx80 int32_to_floatx80(int32_t, float_status *status);
73
+floatx80 int64_to_floatx80(int64_t, float_status *status);
74
+
75
+float128 int32_to_float128(int32_t, float_status *status);
76
+float128 int64_to_float128(int64_t, float_status *status);
77
float128 uint64_to_float128(uint64_t, float_status *status);
78
79
/*----------------------------------------------------------------------------
80
@@ -XXX,XX +XXX,XX @@ int64_t float16_to_int64(float16, float_status *status);
81
uint64_t float16_to_uint64(float16 a, float_status *status);
82
int64_t float16_to_int64_round_to_zero(float16, float_status *status);
83
uint64_t float16_to_uint64_round_to_zero(float16 a, float_status *status);
84
-float16 int16_to_float16(int16_t a, float_status *status);
85
-float16 int32_to_float16(int32_t a, float_status *status);
86
-float16 int64_to_float16(int64_t a, float_status *status);
87
-float16 uint16_to_float16(uint16_t a, float_status *status);
88
-float16 uint32_to_float16(uint32_t a, float_status *status);
89
-float16 uint64_to_float16(uint64_t a, float_status *status);
90
91
/*----------------------------------------------------------------------------
92
| Software half-precision operations.
93
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
94
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
95
--- a/fpu/softfloat.c
31
--- a/linux-user/elfload.c
96
+++ b/fpu/softfloat.c
32
+++ b/linux-user/elfload.c
97
@@ -XXX,XX +XXX,XX @@ FLOAT_TO_UINT(64, 64)
33
@@ -XXX,XX +XXX,XX @@ static void elf_core_copy_regs(target_elf_gregset_t *regs,
98
* to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
34
99
*/
35
#include "elf.h"
100
36
101
-static FloatParts int_to_float(int64_t a, float_status *status)
37
+static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
102
+static FloatParts int_to_float(int64_t a, int scale, float_status *status)
38
+ const uint32_t *data,
39
+ struct image_info *info,
40
+ Error **errp)
41
+{
42
+ g_assert_not_reached();
43
+}
44
+#define ARCH_USE_GNU_PROPERTY 0
45
+
46
struct exec
103
{
47
{
104
- FloatParts r = {};
48
unsigned int a_info; /* Use macros N_MAGIC, etc for access */
105
+ FloatParts r = { .sign = false };
49
@@ -XXX,XX +XXX,XX @@ void probe_guest_base(const char *image_name, abi_ulong guest_loaddr,
106
+
50
"@ 0x%" PRIx64 "\n", (uint64_t)guest_base);
107
if (a == 0) {
108
r.cls = float_class_zero;
109
- r.sign = false;
110
- } else if (a == (1ULL << 63)) {
111
- r.cls = float_class_normal;
112
- r.sign = true;
113
- r.frac = DECOMPOSED_IMPLICIT_BIT;
114
- r.exp = 63;
115
} else {
116
- uint64_t f;
117
- if (a < 0) {
118
- f = -a;
119
- r.sign = true;
120
- } else {
121
- f = a;
122
- r.sign = false;
123
- }
124
- int shift = clz64(f) - 1;
125
+ uint64_t f = a;
126
+ int shift;
127
+
128
r.cls = float_class_normal;
129
- r.exp = (DECOMPOSED_BINARY_POINT - shift);
130
- r.frac = f << shift;
131
+ if (a < 0) {
132
+ f = -f;
133
+ r.sign = true;
134
+ }
135
+ shift = clz64(f) - 1;
136
+ scale = MIN(MAX(scale, -0x10000), 0x10000);
137
+
138
+ r.exp = DECOMPOSED_BINARY_POINT - shift + scale;
139
+ r.frac = (shift < 0 ? DECOMPOSED_IMPLICIT_BIT : f << shift);
140
}
141
142
return r;
143
}
51
}
144
52
145
+float16 int64_to_float16_scalbn(int64_t a, int scale, float_status *status)
53
+enum {
54
+ /* The string "GNU\0" as a magic number. */
55
+ GNU0_MAGIC = const_le32('G' | 'N' << 8 | 'U' << 16),
56
+ NOTE_DATA_SZ = 1 * KiB,
57
+ NOTE_NAME_SZ = 4,
58
+ ELF_GNU_PROPERTY_ALIGN = ELF_CLASS == ELFCLASS32 ? 4 : 8,
59
+};
60
+
61
+/*
62
+ * Process a single gnu_property entry.
63
+ * Return false for error.
64
+ */
65
+static bool parse_elf_property(const uint32_t *data, int *off, int datasz,
66
+ struct image_info *info, bool have_prev_type,
67
+ uint32_t *prev_type, Error **errp)
146
+{
68
+{
147
+ FloatParts pa = int_to_float(a, scale, status);
69
+ uint32_t pr_type, pr_datasz, step;
148
+ return float16_round_pack_canonical(pa, status);
70
+
71
+ if (*off > datasz || !QEMU_IS_ALIGNED(*off, ELF_GNU_PROPERTY_ALIGN)) {
72
+ goto error_data;
73
+ }
74
+ datasz -= *off;
75
+ data += *off / sizeof(uint32_t);
76
+
77
+ if (datasz < 2 * sizeof(uint32_t)) {
78
+ goto error_data;
79
+ }
80
+ pr_type = data[0];
81
+ pr_datasz = data[1];
82
+ data += 2;
83
+ datasz -= 2 * sizeof(uint32_t);
84
+ step = ROUND_UP(pr_datasz, ELF_GNU_PROPERTY_ALIGN);
85
+ if (step > datasz) {
86
+ goto error_data;
87
+ }
88
+
89
+ /* Properties are supposed to be unique and sorted on pr_type. */
90
+ if (have_prev_type && pr_type <= *prev_type) {
91
+ if (pr_type == *prev_type) {
92
+ error_setg(errp, "Duplicate property in PT_GNU_PROPERTY");
93
+ } else {
94
+ error_setg(errp, "Unsorted property in PT_GNU_PROPERTY");
95
+ }
96
+ return false;
97
+ }
98
+ *prev_type = pr_type;
99
+
100
+ if (!arch_parse_elf_property(pr_type, pr_datasz, data, info, errp)) {
101
+ return false;
102
+ }
103
+
104
+ *off += 2 * sizeof(uint32_t) + step;
105
+ return true;
106
+
107
+ error_data:
108
+ error_setg(errp, "Ill-formed property in PT_GNU_PROPERTY");
109
+ return false;
149
+}
110
+}
150
+
111
+
151
+float16 int32_to_float16_scalbn(int32_t a, int scale, float_status *status)
112
+/* Process NT_GNU_PROPERTY_TYPE_0. */
113
+static bool parse_elf_properties(int image_fd,
114
+ struct image_info *info,
115
+ const struct elf_phdr *phdr,
116
+ char bprm_buf[BPRM_BUF_SIZE],
117
+ Error **errp)
152
+{
118
+{
153
+ return int64_to_float16_scalbn(a, scale, status);
119
+ union {
120
+ struct elf_note nhdr;
121
+ uint32_t data[NOTE_DATA_SZ / sizeof(uint32_t)];
122
+ } note;
123
+
124
+ int n, off, datasz;
125
+ bool have_prev_type;
126
+ uint32_t prev_type;
127
+
128
+ /* Unless the arch requires properties, ignore them. */
129
+ if (!ARCH_USE_GNU_PROPERTY) {
130
+ return true;
131
+ }
132
+
133
+ /* If the properties are crazy large, that's too bad. */
134
+ n = phdr->p_filesz;
135
+ if (n > sizeof(note)) {
136
+ error_setg(errp, "PT_GNU_PROPERTY too large");
137
+ return false;
138
+ }
139
+ if (n < sizeof(note.nhdr)) {
140
+ error_setg(errp, "PT_GNU_PROPERTY too small");
141
+ return false;
142
+ }
143
+
144
+ if (phdr->p_offset + n <= BPRM_BUF_SIZE) {
145
+ memcpy(&note, bprm_buf + phdr->p_offset, n);
146
+ } else {
147
+ ssize_t len = pread(image_fd, &note, n, phdr->p_offset);
148
+ if (len != n) {
149
+ error_setg_errno(errp, errno, "Error reading file header");
150
+ return false;
151
+ }
152
+ }
153
+
154
+ /*
155
+ * The contents of a valid PT_GNU_PROPERTY is a sequence
156
+ * of uint32_t -- swap them all now.
157
+ */
158
+#ifdef BSWAP_NEEDED
159
+ for (int i = 0; i < n / 4; i++) {
160
+ bswap32s(note.data + i);
161
+ }
162
+#endif
163
+
164
+ /*
165
+ * Note that nhdr is 3 words, and that the "name" described by namesz
166
+ * immediately follows nhdr and is thus at the 4th word. Further, all
167
+ * of the inputs to the kernel's round_up are multiples of 4.
168
+ */
169
+ if (note.nhdr.n_type != NT_GNU_PROPERTY_TYPE_0 ||
170
+ note.nhdr.n_namesz != NOTE_NAME_SZ ||
171
+ note.data[3] != GNU0_MAGIC) {
172
+ error_setg(errp, "Invalid note in PT_GNU_PROPERTY");
173
+ return false;
174
+ }
175
+ off = sizeof(note.nhdr) + NOTE_NAME_SZ;
176
+
177
+ datasz = note.nhdr.n_descsz + off;
178
+ if (datasz > n) {
179
+ error_setg(errp, "Invalid note size in PT_GNU_PROPERTY");
180
+ return false;
181
+ }
182
+
183
+ have_prev_type = false;
184
+ prev_type = 0;
185
+ while (1) {
186
+ if (off == datasz) {
187
+ return true; /* end, exit ok */
188
+ }
189
+ if (!parse_elf_property(note.data, &off, datasz, info,
190
+ have_prev_type, &prev_type, errp)) {
191
+ return false;
192
+ }
193
+ have_prev_type = true;
194
+ }
154
+}
195
+}
155
+
196
+
156
+float16 int16_to_float16_scalbn(int16_t a, int scale, float_status *status)
197
/* Load an ELF image into the address space.
157
+{
198
158
+ return int64_to_float16_scalbn(a, scale, status);
199
IMAGE_NAME is the filename of the image, to use in error messages.
159
+}
200
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
160
+
201
goto exit_errmsg;
161
float16 int64_to_float16(int64_t a, float_status *status)
202
}
162
{
203
*pinterp_name = g_steal_pointer(&interp_name);
163
- FloatParts pa = int_to_float(a, status);
204
+ } else if (eppnt->p_type == PT_GNU_PROPERTY) {
164
- return float16_round_pack_canonical(pa, status);
205
+ if (!parse_elf_properties(image_fd, info, eppnt, bprm_buf, &err)) {
165
+ return int64_to_float16_scalbn(a, 0, status);
206
+ goto exit_errmsg;
166
}
207
+ }
167
168
float16 int32_to_float16(int32_t a, float_status *status)
169
{
170
- return int64_to_float16(a, status);
171
+ return int64_to_float16_scalbn(a, 0, status);
172
}
173
174
float16 int16_to_float16(int16_t a, float_status *status)
175
{
176
- return int64_to_float16(a, status);
177
+ return int64_to_float16_scalbn(a, 0, status);
178
+}
179
+
180
+float32 int64_to_float32_scalbn(int64_t a, int scale, float_status *status)
181
+{
182
+ FloatParts pa = int_to_float(a, scale, status);
183
+ return float32_round_pack_canonical(pa, status);
184
+}
185
+
186
+float32 int32_to_float32_scalbn(int32_t a, int scale, float_status *status)
187
+{
188
+ return int64_to_float32_scalbn(a, scale, status);
189
+}
190
+
191
+float32 int16_to_float32_scalbn(int16_t a, int scale, float_status *status)
192
+{
193
+ return int64_to_float32_scalbn(a, scale, status);
194
}
195
196
float32 int64_to_float32(int64_t a, float_status *status)
197
{
198
- FloatParts pa = int_to_float(a, status);
199
- return float32_round_pack_canonical(pa, status);
200
+ return int64_to_float32_scalbn(a, 0, status);
201
}
202
203
float32 int32_to_float32(int32_t a, float_status *status)
204
{
205
- return int64_to_float32(a, status);
206
+ return int64_to_float32_scalbn(a, 0, status);
207
}
208
209
float32 int16_to_float32(int16_t a, float_status *status)
210
{
211
- return int64_to_float32(a, status);
212
+ return int64_to_float32_scalbn(a, 0, status);
213
+}
214
+
215
+float64 int64_to_float64_scalbn(int64_t a, int scale, float_status *status)
216
+{
217
+ FloatParts pa = int_to_float(a, scale, status);
218
+ return float64_round_pack_canonical(pa, status);
219
+}
220
+
221
+float64 int32_to_float64_scalbn(int32_t a, int scale, float_status *status)
222
+{
223
+ return int64_to_float64_scalbn(a, scale, status);
224
+}
225
+
226
+float64 int16_to_float64_scalbn(int16_t a, int scale, float_status *status)
227
+{
228
+ return int64_to_float64_scalbn(a, scale, status);
229
}
230
231
float64 int64_to_float64(int64_t a, float_status *status)
232
{
233
- FloatParts pa = int_to_float(a, status);
234
- return float64_round_pack_canonical(pa, status);
235
+ return int64_to_float64_scalbn(a, 0, status);
236
}
237
238
float64 int32_to_float64(int32_t a, float_status *status)
239
{
240
- return int64_to_float64(a, status);
241
+ return int64_to_float64_scalbn(a, 0, status);
242
}
243
244
float64 int16_to_float64(int16_t a, float_status *status)
245
{
246
- return int64_to_float64(a, status);
247
+ return int64_to_float64_scalbn(a, 0, status);
248
}
249
250
251
@@ -XXX,XX +XXX,XX @@ float64 int16_to_float64(int16_t a, float_status *status)
252
* IEC/IEEE Standard for Binary Floating-Point Arithmetic.
253
*/
254
255
-static FloatParts uint_to_float(uint64_t a, float_status *status)
256
+static FloatParts uint_to_float(uint64_t a, int scale, float_status *status)
257
{
258
- FloatParts r = { .sign = false};
259
+ FloatParts r = { .sign = false };
260
261
if (a == 0) {
262
r.cls = float_class_zero;
263
} else {
264
- int spare_bits = clz64(a) - 1;
265
+ scale = MIN(MAX(scale, -0x10000), 0x10000);
266
r.cls = float_class_normal;
267
- r.exp = DECOMPOSED_BINARY_POINT - spare_bits;
268
- if (spare_bits < 0) {
269
- shift64RightJamming(a, -spare_bits, &a);
270
+ if ((int64_t)a < 0) {
271
+ r.exp = DECOMPOSED_BINARY_POINT + 1 + scale;
272
+ shift64RightJamming(a, 1, &a);
273
r.frac = a;
274
} else {
275
- r.frac = a << spare_bits;
276
+ int shift = clz64(a) - 1;
277
+ r.exp = DECOMPOSED_BINARY_POINT - shift + scale;
278
+ r.frac = a << shift;
279
}
208
}
280
}
209
}
281
210
282
return r;
283
}
284
285
+float16 uint64_to_float16_scalbn(uint64_t a, int scale, float_status *status)
286
+{
287
+ FloatParts pa = uint_to_float(a, scale, status);
288
+ return float16_round_pack_canonical(pa, status);
289
+}
290
+
291
+float16 uint32_to_float16_scalbn(uint32_t a, int scale, float_status *status)
292
+{
293
+ return uint64_to_float16_scalbn(a, scale, status);
294
+}
295
+
296
+float16 uint16_to_float16_scalbn(uint16_t a, int scale, float_status *status)
297
+{
298
+ return uint64_to_float16_scalbn(a, scale, status);
299
+}
300
+
301
float16 uint64_to_float16(uint64_t a, float_status *status)
302
{
303
- FloatParts pa = uint_to_float(a, status);
304
- return float16_round_pack_canonical(pa, status);
305
+ return uint64_to_float16_scalbn(a, 0, status);
306
}
307
308
float16 uint32_to_float16(uint32_t a, float_status *status)
309
{
310
- return uint64_to_float16(a, status);
311
+ return uint64_to_float16_scalbn(a, 0, status);
312
}
313
314
float16 uint16_to_float16(uint16_t a, float_status *status)
315
{
316
- return uint64_to_float16(a, status);
317
+ return uint64_to_float16_scalbn(a, 0, status);
318
+}
319
+
320
+float32 uint64_to_float32_scalbn(uint64_t a, int scale, float_status *status)
321
+{
322
+ FloatParts pa = uint_to_float(a, scale, status);
323
+ return float32_round_pack_canonical(pa, status);
324
+}
325
+
326
+float32 uint32_to_float32_scalbn(uint32_t a, int scale, float_status *status)
327
+{
328
+ return uint64_to_float32_scalbn(a, scale, status);
329
+}
330
+
331
+float32 uint16_to_float32_scalbn(uint16_t a, int scale, float_status *status)
332
+{
333
+ return uint64_to_float32_scalbn(a, scale, status);
334
}
335
336
float32 uint64_to_float32(uint64_t a, float_status *status)
337
{
338
- FloatParts pa = uint_to_float(a, status);
339
- return float32_round_pack_canonical(pa, status);
340
+ return uint64_to_float32_scalbn(a, 0, status);
341
}
342
343
float32 uint32_to_float32(uint32_t a, float_status *status)
344
{
345
- return uint64_to_float32(a, status);
346
+ return uint64_to_float32_scalbn(a, 0, status);
347
}
348
349
float32 uint16_to_float32(uint16_t a, float_status *status)
350
{
351
- return uint64_to_float32(a, status);
352
+ return uint64_to_float32_scalbn(a, 0, status);
353
+}
354
+
355
+float64 uint64_to_float64_scalbn(uint64_t a, int scale, float_status *status)
356
+{
357
+ FloatParts pa = uint_to_float(a, scale, status);
358
+ return float64_round_pack_canonical(pa, status);
359
+}
360
+
361
+float64 uint32_to_float64_scalbn(uint32_t a, int scale, float_status *status)
362
+{
363
+ return uint64_to_float64_scalbn(a, scale, status);
364
+}
365
+
366
+float64 uint16_to_float64_scalbn(uint16_t a, int scale, float_status *status)
367
+{
368
+ return uint64_to_float64_scalbn(a, scale, status);
369
}
370
371
float64 uint64_to_float64(uint64_t a, float_status *status)
372
{
373
- FloatParts pa = uint_to_float(a, status);
374
- return float64_round_pack_canonical(pa, status);
375
+ return uint64_to_float64_scalbn(a, 0, status);
376
}
377
378
float64 uint32_to_float64(uint32_t a, float_status *status)
379
{
380
- return uint64_to_float64(a, status);
381
+ return uint64_to_float64_scalbn(a, 0, status);
382
}
383
384
float64 uint16_to_float64(uint16_t a, float_status *status)
385
{
386
- return uint64_to_float64(a, status);
387
+ return uint64_to_float64_scalbn(a, 0, status);
388
}
389
390
/* Float Min/Max */
391
--
211
--
392
2.18.0
212
2.20.1
393
213
394
214
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Richard Henderson <richard.henderson@linaro.org>
2
2
3
Use the new generic support for NT_GNU_PROPERTY_TYPE_0.
4
3
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
5
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
4
Message-id: 20180814002653.12828-3-richard.henderson@linaro.org
6
Message-id: 20201021173749.111103-12-richard.henderson@linaro.org
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
---
9
---
8
include/fpu/softfloat.h | 85 ++++++---
10
linux-user/elfload.c | 48 ++++++++++++++++++++++++++++++++++++++++++--
9
fpu/softfloat.c | 391 ++++++++++++++++++++++++++++++++--------
11
1 file changed, 46 insertions(+), 2 deletions(-)
10
2 files changed, 379 insertions(+), 97 deletions(-)
11
12
12
diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h
13
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
13
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
14
--- a/include/fpu/softfloat.h
15
--- a/linux-user/elfload.c
15
+++ b/include/fpu/softfloat.h
16
+++ b/linux-user/elfload.c
16
@@ -XXX,XX +XXX,XX @@ float128 uint64_to_float128(uint64_t, float_status *status);
17
@@ -XXX,XX +XXX,XX @@ static void elf_core_copy_regs(target_elf_gregset_t *regs,
17
/*----------------------------------------------------------------------------
18
18
| Software half-precision conversion routines.
19
#include "elf.h"
19
*----------------------------------------------------------------------------*/
20
21
+/* We must delay the following stanzas until after "elf.h". */
22
+#if defined(TARGET_AARCH64)
20
+
23
+
21
float16 float32_to_float16(float32, bool ieee, float_status *status);
24
+static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
22
float32 float16_to_float32(float16, bool ieee, float_status *status);
25
+ const uint32_t *data,
23
float16 float64_to_float16(float64 a, bool ieee, float_status *status);
26
+ struct image_info *info,
24
float64 float16_to_float64(float16 a, bool ieee, float_status *status);
27
+ Error **errp)
28
+{
29
+ if (pr_type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) {
30
+ if (pr_datasz != sizeof(uint32_t)) {
31
+ error_setg(errp, "Ill-formed GNU_PROPERTY_AARCH64_FEATURE_1_AND");
32
+ return false;
33
+ }
34
+ /* We will extract GNU_PROPERTY_AARCH64_FEATURE_1_BTI later. */
35
+ info->note_flags = *data;
36
+ }
37
+ return true;
38
+}
39
+#define ARCH_USE_GNU_PROPERTY 1
25
+
40
+
26
+int16_t float16_to_int16_scalbn(float16, int, int, float_status *status);
41
+#else
27
+int32_t float16_to_int32_scalbn(float16, int, int, float_status *status);
28
+int64_t float16_to_int64_scalbn(float16, int, int, float_status *status);
29
+
42
+
30
int16_t float16_to_int16(float16, float_status *status);
43
static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
31
-uint16_t float16_to_uint16(float16 a, float_status *status);
44
const uint32_t *data,
32
-int16_t float16_to_int16_round_to_zero(float16, float_status *status);
45
struct image_info *info,
33
-uint16_t float16_to_uint16_round_to_zero(float16 a, float_status *status);
46
@@ -XXX,XX +XXX,XX @@ static bool arch_parse_elf_property(uint32_t pr_type, uint32_t pr_datasz,
34
int32_t float16_to_int32(float16, float_status *status);
47
}
35
-uint32_t float16_to_uint32(float16 a, float_status *status);
48
#define ARCH_USE_GNU_PROPERTY 0
36
-int32_t float16_to_int32_round_to_zero(float16, float_status *status);
49
37
-uint32_t float16_to_uint32_round_to_zero(float16 a, float_status *status);
50
+#endif
38
int64_t float16_to_int64(float16, float_status *status);
39
-uint64_t float16_to_uint64(float16 a, float_status *status);
40
+
51
+
41
+int16_t float16_to_int16_round_to_zero(float16, float_status *status);
52
struct exec
42
+int32_t float16_to_int32_round_to_zero(float16, float_status *status);
53
{
43
int64_t float16_to_int64_round_to_zero(float16, float_status *status);
54
unsigned int a_info; /* Use macros N_MAGIC, etc for access */
55
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
56
struct elfhdr *ehdr = (struct elfhdr *)bprm_buf;
57
struct elf_phdr *phdr;
58
abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
59
- int i, retval;
60
+ int i, retval, prot_exec;
61
Error *err = NULL;
62
63
/* First of all, some simple consistency checks */
64
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
65
info->brk = 0;
66
info->elf_flags = ehdr->e_flags;
67
68
+ prot_exec = PROT_EXEC;
69
+#ifdef TARGET_AARCH64
70
+ /*
71
+ * If the BTI feature is present, this indicates that the executable
72
+ * pages of the startup binary should be mapped with PROT_BTI, so that
73
+ * branch targets are enforced.
74
+ *
75
+ * The startup binary is either the interpreter or the static executable.
76
+ * The interpreter is responsible for all pages of a dynamic executable.
77
+ *
78
+ * Elf notes are backward compatible to older cpus.
79
+ * Do not enable BTI unless it is supported.
80
+ */
81
+ if ((info->note_flags & GNU_PROPERTY_AARCH64_FEATURE_1_BTI)
82
+ && (pinterp_name == NULL || *pinterp_name == 0)
83
+ && cpu_isar_feature(aa64_bti, ARM_CPU(thread_cpu))) {
84
+ prot_exec |= TARGET_PROT_BTI;
85
+ }
86
+#endif
44
+
87
+
45
+uint16_t float16_to_uint16_scalbn(float16 a, int, int, float_status *status);
88
for (i = 0; i < ehdr->e_phnum; i++) {
46
+uint32_t float16_to_uint32_scalbn(float16 a, int, int, float_status *status);
89
struct elf_phdr *eppnt = phdr + i;
47
+uint64_t float16_to_uint64_scalbn(float16 a, int, int, float_status *status);
90
if (eppnt->p_type == PT_LOAD) {
48
+
91
@@ -XXX,XX +XXX,XX @@ static void load_elf_image(const char *image_name, int image_fd,
49
+uint16_t float16_to_uint16(float16 a, float_status *status);
92
elf_prot |= PROT_WRITE;
50
+uint32_t float16_to_uint32(float16 a, float_status *status);
93
}
51
+uint64_t float16_to_uint64(float16 a, float_status *status);
94
if (eppnt->p_flags & PF_X) {
52
+
95
- elf_prot |= PROT_EXEC;
53
+uint16_t float16_to_uint16_round_to_zero(float16 a, float_status *status);
96
+ elf_prot |= prot_exec;
54
+uint32_t float16_to_uint32_round_to_zero(float16 a, float_status *status);
97
}
55
uint64_t float16_to_uint64_round_to_zero(float16 a, float_status *status);
98
56
99
vaddr = load_bias + eppnt->p_vaddr;
57
/*----------------------------------------------------------------------------
58
@@ -XXX,XX +XXX,XX @@ float16 float16_default_nan(float_status *status);
59
/*----------------------------------------------------------------------------
60
| Software IEC/IEEE single-precision conversion routines.
61
*----------------------------------------------------------------------------*/
62
+
63
+int16_t float32_to_int16_scalbn(float32, int, int, float_status *status);
64
+int32_t float32_to_int32_scalbn(float32, int, int, float_status *status);
65
+int64_t float32_to_int64_scalbn(float32, int, int, float_status *status);
66
+
67
int16_t float32_to_int16(float32, float_status *status);
68
-uint16_t float32_to_uint16(float32, float_status *status);
69
-int16_t float32_to_int16_round_to_zero(float32, float_status *status);
70
-uint16_t float32_to_uint16_round_to_zero(float32, float_status *status);
71
int32_t float32_to_int32(float32, float_status *status);
72
-int32_t float32_to_int32_round_to_zero(float32, float_status *status);
73
-uint32_t float32_to_uint32(float32, float_status *status);
74
-uint32_t float32_to_uint32_round_to_zero(float32, float_status *status);
75
int64_t float32_to_int64(float32, float_status *status);
76
-uint64_t float32_to_uint64(float32, float_status *status);
77
-uint64_t float32_to_uint64_round_to_zero(float32, float_status *status);
78
+
79
+int16_t float32_to_int16_round_to_zero(float32, float_status *status);
80
+int32_t float32_to_int32_round_to_zero(float32, float_status *status);
81
int64_t float32_to_int64_round_to_zero(float32, float_status *status);
82
+
83
+uint16_t float32_to_uint16_scalbn(float32, int, int, float_status *status);
84
+uint32_t float32_to_uint32_scalbn(float32, int, int, float_status *status);
85
+uint64_t float32_to_uint64_scalbn(float32, int, int, float_status *status);
86
+
87
+uint16_t float32_to_uint16(float32, float_status *status);
88
+uint32_t float32_to_uint32(float32, float_status *status);
89
+uint64_t float32_to_uint64(float32, float_status *status);
90
+
91
+uint16_t float32_to_uint16_round_to_zero(float32, float_status *status);
92
+uint32_t float32_to_uint32_round_to_zero(float32, float_status *status);
93
+uint64_t float32_to_uint64_round_to_zero(float32, float_status *status);
94
+
95
float64 float32_to_float64(float32, float_status *status);
96
floatx80 float32_to_floatx80(float32, float_status *status);
97
float128 float32_to_float128(float32, float_status *status);
98
@@ -XXX,XX +XXX,XX @@ float32 float32_default_nan(float_status *status);
99
/*----------------------------------------------------------------------------
100
| Software IEC/IEEE double-precision conversion routines.
101
*----------------------------------------------------------------------------*/
102
+
103
+int16_t float64_to_int16_scalbn(float64, int, int, float_status *status);
104
+int32_t float64_to_int32_scalbn(float64, int, int, float_status *status);
105
+int64_t float64_to_int64_scalbn(float64, int, int, float_status *status);
106
+
107
int16_t float64_to_int16(float64, float_status *status);
108
-uint16_t float64_to_uint16(float64, float_status *status);
109
-int16_t float64_to_int16_round_to_zero(float64, float_status *status);
110
-uint16_t float64_to_uint16_round_to_zero(float64, float_status *status);
111
int32_t float64_to_int32(float64, float_status *status);
112
-int32_t float64_to_int32_round_to_zero(float64, float_status *status);
113
-uint32_t float64_to_uint32(float64, float_status *status);
114
-uint32_t float64_to_uint32_round_to_zero(float64, float_status *status);
115
int64_t float64_to_int64(float64, float_status *status);
116
+
117
+int16_t float64_to_int16_round_to_zero(float64, float_status *status);
118
+int32_t float64_to_int32_round_to_zero(float64, float_status *status);
119
int64_t float64_to_int64_round_to_zero(float64, float_status *status);
120
-uint64_t float64_to_uint64(float64 a, float_status *status);
121
-uint64_t float64_to_uint64_round_to_zero(float64 a, float_status *status);
122
+
123
+uint16_t float64_to_uint16_scalbn(float64, int, int, float_status *status);
124
+uint32_t float64_to_uint32_scalbn(float64, int, int, float_status *status);
125
+uint64_t float64_to_uint64_scalbn(float64, int, int, float_status *status);
126
+
127
+uint16_t float64_to_uint16(float64, float_status *status);
128
+uint32_t float64_to_uint32(float64, float_status *status);
129
+uint64_t float64_to_uint64(float64, float_status *status);
130
+
131
+uint16_t float64_to_uint16_round_to_zero(float64, float_status *status);
132
+uint32_t float64_to_uint32_round_to_zero(float64, float_status *status);
133
+uint64_t float64_to_uint64_round_to_zero(float64, float_status *status);
134
+
135
float32 float64_to_float32(float64, float_status *status);
136
floatx80 float64_to_floatx80(float64, float_status *status);
137
float128 float64_to_float128(float64, float_status *status);
138
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
139
index XXXXXXX..XXXXXXX 100644
140
--- a/fpu/softfloat.c
141
+++ b/fpu/softfloat.c
142
@@ -XXX,XX +XXX,XX @@ float32 float64_to_float32(float64 a, float_status *s)
143
* Arithmetic.
144
*/
145
146
-static FloatParts round_to_int(FloatParts a, int rounding_mode, float_status *s)
147
+static FloatParts round_to_int(FloatParts a, int rmode,
148
+ int scale, float_status *s)
149
{
150
- if (is_nan(a.cls)) {
151
- return return_nan(a, s);
152
- }
153
-
154
switch (a.cls) {
155
+ case float_class_qnan:
156
+ case float_class_snan:
157
+ return return_nan(a, s);
158
+
159
case float_class_zero:
160
case float_class_inf:
161
- case float_class_qnan:
162
/* already "integral" */
163
break;
164
+
165
case float_class_normal:
166
+ scale = MIN(MAX(scale, -0x10000), 0x10000);
167
+ a.exp += scale;
168
+
169
if (a.exp >= DECOMPOSED_BINARY_POINT) {
170
/* already integral */
171
break;
172
@@ -XXX,XX +XXX,XX @@ static FloatParts round_to_int(FloatParts a, int rounding_mode, float_status *s)
173
bool one;
174
/* all fractional */
175
s->float_exception_flags |= float_flag_inexact;
176
- switch (rounding_mode) {
177
+ switch (rmode) {
178
case float_round_nearest_even:
179
one = a.exp == -1 && a.frac > DECOMPOSED_IMPLICIT_BIT;
180
break;
181
@@ -XXX,XX +XXX,XX @@ static FloatParts round_to_int(FloatParts a, int rounding_mode, float_status *s)
182
uint64_t rnd_mask = rnd_even_mask >> 1;
183
uint64_t inc;
184
185
- switch (rounding_mode) {
186
+ switch (rmode) {
187
case float_round_nearest_even:
188
inc = ((a.frac & rnd_even_mask) != frac_lsbm1 ? frac_lsbm1 : 0);
189
break;
190
@@ -XXX,XX +XXX,XX @@ static FloatParts round_to_int(FloatParts a, int rounding_mode, float_status *s)
191
float16 float16_round_to_int(float16 a, float_status *s)
192
{
193
FloatParts pa = float16_unpack_canonical(a, s);
194
- FloatParts pr = round_to_int(pa, s->float_rounding_mode, s);
195
+ FloatParts pr = round_to_int(pa, s->float_rounding_mode, 0, s);
196
return float16_round_pack_canonical(pr, s);
197
}
198
199
float32 float32_round_to_int(float32 a, float_status *s)
200
{
201
FloatParts pa = float32_unpack_canonical(a, s);
202
- FloatParts pr = round_to_int(pa, s->float_rounding_mode, s);
203
+ FloatParts pr = round_to_int(pa, s->float_rounding_mode, 0, s);
204
return float32_round_pack_canonical(pr, s);
205
}
206
207
float64 float64_round_to_int(float64 a, float_status *s)
208
{
209
FloatParts pa = float64_unpack_canonical(a, s);
210
- FloatParts pr = round_to_int(pa, s->float_rounding_mode, s);
211
+ FloatParts pr = round_to_int(pa, s->float_rounding_mode, 0, s);
212
return float64_round_pack_canonical(pr, s);
213
}
214
215
float64 float64_trunc_to_int(float64 a, float_status *s)
216
{
217
FloatParts pa = float64_unpack_canonical(a, s);
218
- FloatParts pr = round_to_int(pa, float_round_to_zero, s);
219
+ FloatParts pr = round_to_int(pa, float_round_to_zero, 0, s);
220
return float64_round_pack_canonical(pr, s);
221
}
222
223
@@ -XXX,XX +XXX,XX @@ float64 float64_trunc_to_int(float64 a, float_status *s)
224
* is returned.
225
*/
226
227
-static int64_t round_to_int_and_pack(FloatParts in, int rmode,
228
+static int64_t round_to_int_and_pack(FloatParts in, int rmode, int scale,
229
int64_t min, int64_t max,
230
float_status *s)
231
{
232
uint64_t r;
233
int orig_flags = get_float_exception_flags(s);
234
- FloatParts p = round_to_int(in, rmode, s);
235
+ FloatParts p = round_to_int(in, rmode, scale, s);
236
237
switch (p.cls) {
238
case float_class_snan:
239
@@ -XXX,XX +XXX,XX @@ static int64_t round_to_int_and_pack(FloatParts in, int rmode,
240
}
241
}
242
243
-#define FLOAT_TO_INT(fsz, isz) \
244
-int ## isz ## _t float ## fsz ## _to_int ## isz(float ## fsz a, \
245
- float_status *s) \
246
-{ \
247
- FloatParts p = float ## fsz ## _unpack_canonical(a, s); \
248
- return round_to_int_and_pack(p, s->float_rounding_mode, \
249
- INT ## isz ## _MIN, INT ## isz ## _MAX,\
250
- s); \
251
-} \
252
- \
253
-int ## isz ## _t float ## fsz ## _to_int ## isz ## _round_to_zero \
254
- (float ## fsz a, float_status *s) \
255
-{ \
256
- FloatParts p = float ## fsz ## _unpack_canonical(a, s); \
257
- return round_to_int_and_pack(p, float_round_to_zero, \
258
- INT ## isz ## _MIN, INT ## isz ## _MAX,\
259
- s); \
260
+int16_t float16_to_int16_scalbn(float16 a, int rmode, int scale,
261
+ float_status *s)
262
+{
263
+ return round_to_int_and_pack(float16_unpack_canonical(a, s),
264
+ rmode, scale, INT16_MIN, INT16_MAX, s);
265
}
266
267
-FLOAT_TO_INT(16, 16)
268
-FLOAT_TO_INT(16, 32)
269
-FLOAT_TO_INT(16, 64)
270
+int32_t float16_to_int32_scalbn(float16 a, int rmode, int scale,
271
+ float_status *s)
272
+{
273
+ return round_to_int_and_pack(float16_unpack_canonical(a, s),
274
+ rmode, scale, INT32_MIN, INT32_MAX, s);
275
+}
276
277
-FLOAT_TO_INT(32, 16)
278
-FLOAT_TO_INT(32, 32)
279
-FLOAT_TO_INT(32, 64)
280
+int64_t float16_to_int64_scalbn(float16 a, int rmode, int scale,
281
+ float_status *s)
282
+{
283
+ return round_to_int_and_pack(float16_unpack_canonical(a, s),
284
+ rmode, scale, INT64_MIN, INT64_MAX, s);
285
+}
286
287
-FLOAT_TO_INT(64, 16)
288
-FLOAT_TO_INT(64, 32)
289
-FLOAT_TO_INT(64, 64)
290
+int16_t float32_to_int16_scalbn(float32 a, int rmode, int scale,
291
+ float_status *s)
292
+{
293
+ return round_to_int_and_pack(float32_unpack_canonical(a, s),
294
+ rmode, scale, INT16_MIN, INT16_MAX, s);
295
+}
296
297
-#undef FLOAT_TO_INT
298
+int32_t float32_to_int32_scalbn(float32 a, int rmode, int scale,
299
+ float_status *s)
300
+{
301
+ return round_to_int_and_pack(float32_unpack_canonical(a, s),
302
+ rmode, scale, INT32_MIN, INT32_MAX, s);
303
+}
304
+
305
+int64_t float32_to_int64_scalbn(float32 a, int rmode, int scale,
306
+ float_status *s)
307
+{
308
+ return round_to_int_and_pack(float32_unpack_canonical(a, s),
309
+ rmode, scale, INT64_MIN, INT64_MAX, s);
310
+}
311
+
312
+int16_t float64_to_int16_scalbn(float64 a, int rmode, int scale,
313
+ float_status *s)
314
+{
315
+ return round_to_int_and_pack(float64_unpack_canonical(a, s),
316
+ rmode, scale, INT16_MIN, INT16_MAX, s);
317
+}
318
+
319
+int32_t float64_to_int32_scalbn(float64 a, int rmode, int scale,
320
+ float_status *s)
321
+{
322
+ return round_to_int_and_pack(float64_unpack_canonical(a, s),
323
+ rmode, scale, INT32_MIN, INT32_MAX, s);
324
+}
325
+
326
+int64_t float64_to_int64_scalbn(float64 a, int rmode, int scale,
327
+ float_status *s)
328
+{
329
+ return round_to_int_and_pack(float64_unpack_canonical(a, s),
330
+ rmode, scale, INT64_MIN, INT64_MAX, s);
331
+}
332
+
333
+int16_t float16_to_int16(float16 a, float_status *s)
334
+{
335
+ return float16_to_int16_scalbn(a, s->float_rounding_mode, 0, s);
336
+}
337
+
338
+int32_t float16_to_int32(float16 a, float_status *s)
339
+{
340
+ return float16_to_int32_scalbn(a, s->float_rounding_mode, 0, s);
341
+}
342
+
343
+int64_t float16_to_int64(float16 a, float_status *s)
344
+{
345
+ return float16_to_int64_scalbn(a, s->float_rounding_mode, 0, s);
346
+}
347
+
348
+int16_t float32_to_int16(float32 a, float_status *s)
349
+{
350
+ return float32_to_int16_scalbn(a, s->float_rounding_mode, 0, s);
351
+}
352
+
353
+int32_t float32_to_int32(float32 a, float_status *s)
354
+{
355
+ return float32_to_int32_scalbn(a, s->float_rounding_mode, 0, s);
356
+}
357
+
358
+int64_t float32_to_int64(float32 a, float_status *s)
359
+{
360
+ return float32_to_int64_scalbn(a, s->float_rounding_mode, 0, s);
361
+}
362
+
363
+int16_t float64_to_int16(float64 a, float_status *s)
364
+{
365
+ return float64_to_int16_scalbn(a, s->float_rounding_mode, 0, s);
366
+}
367
+
368
+int32_t float64_to_int32(float64 a, float_status *s)
369
+{
370
+ return float64_to_int32_scalbn(a, s->float_rounding_mode, 0, s);
371
+}
372
+
373
+int64_t float64_to_int64(float64 a, float_status *s)
374
+{
375
+ return float64_to_int64_scalbn(a, s->float_rounding_mode, 0, s);
376
+}
377
+
378
+int16_t float16_to_int16_round_to_zero(float16 a, float_status *s)
379
+{
380
+ return float16_to_int16_scalbn(a, float_round_to_zero, 0, s);
381
+}
382
+
383
+int32_t float16_to_int32_round_to_zero(float16 a, float_status *s)
384
+{
385
+ return float16_to_int32_scalbn(a, float_round_to_zero, 0, s);
386
+}
387
+
388
+int64_t float16_to_int64_round_to_zero(float16 a, float_status *s)
389
+{
390
+ return float16_to_int64_scalbn(a, float_round_to_zero, 0, s);
391
+}
392
+
393
+int16_t float32_to_int16_round_to_zero(float32 a, float_status *s)
394
+{
395
+ return float32_to_int16_scalbn(a, float_round_to_zero, 0, s);
396
+}
397
+
398
+int32_t float32_to_int32_round_to_zero(float32 a, float_status *s)
399
+{
400
+ return float32_to_int32_scalbn(a, float_round_to_zero, 0, s);
401
+}
402
+
403
+int64_t float32_to_int64_round_to_zero(float32 a, float_status *s)
404
+{
405
+ return float32_to_int64_scalbn(a, float_round_to_zero, 0, s);
406
+}
407
+
408
+int16_t float64_to_int16_round_to_zero(float64 a, float_status *s)
409
+{
410
+ return float64_to_int16_scalbn(a, float_round_to_zero, 0, s);
411
+}
412
+
413
+int32_t float64_to_int32_round_to_zero(float64 a, float_status *s)
414
+{
415
+ return float64_to_int32_scalbn(a, float_round_to_zero, 0, s);
416
+}
417
+
418
+int64_t float64_to_int64_round_to_zero(float64 a, float_status *s)
419
+{
420
+ return float64_to_int64_scalbn(a, float_round_to_zero, 0, s);
421
+}
422
423
/*
424
* Returns the result of converting the floating-point value `a' to
425
@@ -XXX,XX +XXX,XX @@ FLOAT_TO_INT(64, 64)
426
* flag.
427
*/
428
429
-static uint64_t round_to_uint_and_pack(FloatParts in, int rmode, uint64_t max,
430
- float_status *s)
431
+static uint64_t round_to_uint_and_pack(FloatParts in, int rmode, int scale,
432
+ uint64_t max, float_status *s)
433
{
434
int orig_flags = get_float_exception_flags(s);
435
- FloatParts p = round_to_int(in, rmode, s);
436
+ FloatParts p = round_to_int(in, rmode, scale, s);
437
+ uint64_t r;
438
439
switch (p.cls) {
440
case float_class_snan:
441
@@ -XXX,XX +XXX,XX @@ static uint64_t round_to_uint_and_pack(FloatParts in, int rmode, uint64_t max,
442
case float_class_zero:
443
return 0;
444
case float_class_normal:
445
- {
446
- uint64_t r;
447
if (p.sign) {
448
s->float_exception_flags = orig_flags | float_flag_invalid;
449
return 0;
450
@@ -XXX,XX +XXX,XX @@ static uint64_t round_to_uint_and_pack(FloatParts in, int rmode, uint64_t max,
451
if (r > max) {
452
s->float_exception_flags = orig_flags | float_flag_invalid;
453
return max;
454
- } else {
455
- return r;
456
}
457
- }
458
+ return r;
459
default:
460
g_assert_not_reached();
461
}
462
}
463
464
-#define FLOAT_TO_UINT(fsz, isz) \
465
-uint ## isz ## _t float ## fsz ## _to_uint ## isz(float ## fsz a, \
466
- float_status *s) \
467
-{ \
468
- FloatParts p = float ## fsz ## _unpack_canonical(a, s); \
469
- return round_to_uint_and_pack(p, s->float_rounding_mode, \
470
- UINT ## isz ## _MAX, s); \
471
-} \
472
- \
473
-uint ## isz ## _t float ## fsz ## _to_uint ## isz ## _round_to_zero \
474
- (float ## fsz a, float_status *s) \
475
-{ \
476
- FloatParts p = float ## fsz ## _unpack_canonical(a, s); \
477
- return round_to_uint_and_pack(p, float_round_to_zero, \
478
- UINT ## isz ## _MAX, s); \
479
+uint16_t float16_to_uint16_scalbn(float16 a, int rmode, int scale,
480
+ float_status *s)
481
+{
482
+ return round_to_uint_and_pack(float16_unpack_canonical(a, s),
483
+ rmode, scale, UINT16_MAX, s);
484
}
485
486
-FLOAT_TO_UINT(16, 16)
487
-FLOAT_TO_UINT(16, 32)
488
-FLOAT_TO_UINT(16, 64)
489
+uint32_t float16_to_uint32_scalbn(float16 a, int rmode, int scale,
490
+ float_status *s)
491
+{
492
+ return round_to_uint_and_pack(float16_unpack_canonical(a, s),
493
+ rmode, scale, UINT32_MAX, s);
494
+}
495
496
-FLOAT_TO_UINT(32, 16)
497
-FLOAT_TO_UINT(32, 32)
498
-FLOAT_TO_UINT(32, 64)
499
+uint64_t float16_to_uint64_scalbn(float16 a, int rmode, int scale,
500
+ float_status *s)
501
+{
502
+ return round_to_uint_and_pack(float16_unpack_canonical(a, s),
503
+ rmode, scale, UINT64_MAX, s);
504
+}
505
506
-FLOAT_TO_UINT(64, 16)
507
-FLOAT_TO_UINT(64, 32)
508
-FLOAT_TO_UINT(64, 64)
509
+uint16_t float32_to_uint16_scalbn(float32 a, int rmode, int scale,
510
+ float_status *s)
511
+{
512
+ return round_to_uint_and_pack(float32_unpack_canonical(a, s),
513
+ rmode, scale, UINT16_MAX, s);
514
+}
515
516
-#undef FLOAT_TO_UINT
517
+uint32_t float32_to_uint32_scalbn(float32 a, int rmode, int scale,
518
+ float_status *s)
519
+{
520
+ return round_to_uint_and_pack(float32_unpack_canonical(a, s),
521
+ rmode, scale, UINT32_MAX, s);
522
+}
523
+
524
+uint64_t float32_to_uint64_scalbn(float32 a, int rmode, int scale,
525
+ float_status *s)
526
+{
527
+ return round_to_uint_and_pack(float32_unpack_canonical(a, s),
528
+ rmode, scale, UINT64_MAX, s);
529
+}
530
+
531
+uint16_t float64_to_uint16_scalbn(float64 a, int rmode, int scale,
532
+ float_status *s)
533
+{
534
+ return round_to_uint_and_pack(float64_unpack_canonical(a, s),
535
+ rmode, scale, UINT16_MAX, s);
536
+}
537
+
538
+uint32_t float64_to_uint32_scalbn(float64 a, int rmode, int scale,
539
+ float_status *s)
540
+{
541
+ return round_to_uint_and_pack(float64_unpack_canonical(a, s),
542
+ rmode, scale, UINT32_MAX, s);
543
+}
544
+
545
+uint64_t float64_to_uint64_scalbn(float64 a, int rmode, int scale,
546
+ float_status *s)
547
+{
548
+ return round_to_uint_and_pack(float64_unpack_canonical(a, s),
549
+ rmode, scale, UINT64_MAX, s);
550
+}
551
+
552
+uint16_t float16_to_uint16(float16 a, float_status *s)
553
+{
554
+ return float16_to_uint16_scalbn(a, s->float_rounding_mode, 0, s);
555
+}
556
+
557
+uint32_t float16_to_uint32(float16 a, float_status *s)
558
+{
559
+ return float16_to_uint32_scalbn(a, s->float_rounding_mode, 0, s);
560
+}
561
+
562
+uint64_t float16_to_uint64(float16 a, float_status *s)
563
+{
564
+ return float16_to_uint64_scalbn(a, s->float_rounding_mode, 0, s);
565
+}
566
+
567
+uint16_t float32_to_uint16(float32 a, float_status *s)
568
+{
569
+ return float32_to_uint16_scalbn(a, s->float_rounding_mode, 0, s);
570
+}
571
+
572
+uint32_t float32_to_uint32(float32 a, float_status *s)
573
+{
574
+ return float32_to_uint32_scalbn(a, s->float_rounding_mode, 0, s);
575
+}
576
+
577
+uint64_t float32_to_uint64(float32 a, float_status *s)
578
+{
579
+ return float32_to_uint64_scalbn(a, s->float_rounding_mode, 0, s);
580
+}
581
+
582
+uint16_t float64_to_uint16(float64 a, float_status *s)
583
+{
584
+ return float64_to_uint16_scalbn(a, s->float_rounding_mode, 0, s);
585
+}
586
+
587
+uint32_t float64_to_uint32(float64 a, float_status *s)
588
+{
589
+ return float64_to_uint32_scalbn(a, s->float_rounding_mode, 0, s);
590
+}
591
+
592
+uint64_t float64_to_uint64(float64 a, float_status *s)
593
+{
594
+ return float64_to_uint64_scalbn(a, s->float_rounding_mode, 0, s);
595
+}
596
+
597
+uint16_t float16_to_uint16_round_to_zero(float16 a, float_status *s)
598
+{
599
+ return float16_to_uint16_scalbn(a, float_round_to_zero, 0, s);
600
+}
601
+
602
+uint32_t float16_to_uint32_round_to_zero(float16 a, float_status *s)
603
+{
604
+ return float16_to_uint32_scalbn(a, float_round_to_zero, 0, s);
605
+}
606
+
607
+uint64_t float16_to_uint64_round_to_zero(float16 a, float_status *s)
608
+{
609
+ return float16_to_uint64_scalbn(a, float_round_to_zero, 0, s);
610
+}
611
+
612
+uint16_t float32_to_uint16_round_to_zero(float32 a, float_status *s)
613
+{
614
+ return float32_to_uint16_scalbn(a, float_round_to_zero, 0, s);
615
+}
616
+
617
+uint32_t float32_to_uint32_round_to_zero(float32 a, float_status *s)
618
+{
619
+ return float32_to_uint32_scalbn(a, float_round_to_zero, 0, s);
620
+}
621
+
622
+uint64_t float32_to_uint64_round_to_zero(float32 a, float_status *s)
623
+{
624
+ return float32_to_uint64_scalbn(a, float_round_to_zero, 0, s);
625
+}
626
+
627
+uint16_t float64_to_uint16_round_to_zero(float64 a, float_status *s)
628
+{
629
+ return float64_to_uint16_scalbn(a, float_round_to_zero, 0, s);
630
+}
631
+
632
+uint32_t float64_to_uint32_round_to_zero(float64 a, float_status *s)
633
+{
634
+ return float64_to_uint32_scalbn(a, float_round_to_zero, 0, s);
635
+}
636
+
637
+uint64_t float64_to_uint64_round_to_zero(float64 a, float_status *s)
638
+{
639
+ return float64_to_uint64_scalbn(a, float_round_to_zero, 0, s);
640
+}
641
642
/*
643
* Integer to float conversions
644
--
100
--
645
2.18.0
101
2.20.1
646
102
647
103
diff view generated by jsdifflib
1
Create a new include file for the pl022's device struct,
1
From: Richard Henderson <richard.henderson@linaro.org>
2
type macros, etc, so that it can be instantiated using
2
3
the "embedded struct" coding style.
3
The note test requires gcc 10 for -mbranch-protection=standard.
4
4
The mmap test uses PROT_BTI and does not require special compiler support.
5
While we're adding the new file to MAINTAINERS, add
5
6
also the .c file, which was missing an entry.
6
Acked-by: Alex Bennée <alex.bennee@linaro.org>
7
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20201021173749.111103-13-richard.henderson@linaro.org
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
Message-id: 20180820141116.9118-16-peter.maydell@linaro.org
11
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
12
---
11
---
13
include/hw/ssi/pl022.h | 51 ++++++++++++++++++++++++++++++++++++++++++
12
tests/tcg/aarch64/bti-1.c | 62 ++++++++++++++++
14
hw/ssi/pl022.c | 26 +--------------------
13
tests/tcg/aarch64/bti-2.c | 116 ++++++++++++++++++++++++++++++
15
MAINTAINERS | 2 ++
14
tests/tcg/aarch64/bti-crt.inc.c | 51 +++++++++++++
16
3 files changed, 54 insertions(+), 25 deletions(-)
15
tests/tcg/aarch64/Makefile.target | 10 +++
17
create mode 100644 include/hw/ssi/pl022.h
16
tests/tcg/configure.sh | 4 ++
18
17
5 files changed, 243 insertions(+)
19
diff --git a/include/hw/ssi/pl022.h b/include/hw/ssi/pl022.h
18
create mode 100644 tests/tcg/aarch64/bti-1.c
19
create mode 100644 tests/tcg/aarch64/bti-2.c
20
create mode 100644 tests/tcg/aarch64/bti-crt.inc.c
21
22
diff --git a/tests/tcg/aarch64/bti-1.c b/tests/tcg/aarch64/bti-1.c
20
new file mode 100644
23
new file mode 100644
21
index XXXXXXX..XXXXXXX
24
index XXXXXXX..XXXXXXX
22
--- /dev/null
25
--- /dev/null
23
+++ b/include/hw/ssi/pl022.h
26
+++ b/tests/tcg/aarch64/bti-1.c
24
@@ -XXX,XX +XXX,XX @@
27
@@ -XXX,XX +XXX,XX @@
25
+/*
28
+/*
26
+ * ARM PrimeCell PL022 Synchronous Serial Port
29
+ * Branch target identification, basic notskip cases.
30
+ */
31
+
32
+#include "bti-crt.inc.c"
33
+
34
+static void skip2_sigill(int sig, siginfo_t *info, ucontext_t *uc)
35
+{
36
+ uc->uc_mcontext.pc += 8;
37
+ uc->uc_mcontext.pstate = 1;
38
+}
39
+
40
+#define NOP "nop"
41
+#define BTI_N "hint #32"
42
+#define BTI_C "hint #34"
43
+#define BTI_J "hint #36"
44
+#define BTI_JC "hint #38"
45
+
46
+#define BTYPE_1(DEST) \
47
+ asm("mov %0,#1; adr x16, 1f; br x16; 1: " DEST "; mov %0,#0" \
48
+ : "=r"(skipped) : : "x16")
49
+
50
+#define BTYPE_2(DEST) \
51
+ asm("mov %0,#1; adr x16, 1f; blr x16; 1: " DEST "; mov %0,#0" \
52
+ : "=r"(skipped) : : "x16", "x30")
53
+
54
+#define BTYPE_3(DEST) \
55
+ asm("mov %0,#1; adr x15, 1f; br x15; 1: " DEST "; mov %0,#0" \
56
+ : "=r"(skipped) : : "x15")
57
+
58
+#define TEST(WHICH, DEST, EXPECT) \
59
+ do { WHICH(DEST); fail += skipped ^ EXPECT; } while (0)
60
+
61
+
62
+int main()
63
+{
64
+ int fail = 0;
65
+ int skipped;
66
+
67
+ /* Signal-like with SA_SIGINFO. */
68
+ signal_info(SIGILL, skip2_sigill);
69
+
70
+ TEST(BTYPE_1, NOP, 1);
71
+ TEST(BTYPE_1, BTI_N, 1);
72
+ TEST(BTYPE_1, BTI_C, 0);
73
+ TEST(BTYPE_1, BTI_J, 0);
74
+ TEST(BTYPE_1, BTI_JC, 0);
75
+
76
+ TEST(BTYPE_2, NOP, 1);
77
+ TEST(BTYPE_2, BTI_N, 1);
78
+ TEST(BTYPE_2, BTI_C, 0);
79
+ TEST(BTYPE_2, BTI_J, 1);
80
+ TEST(BTYPE_2, BTI_JC, 0);
81
+
82
+ TEST(BTYPE_3, NOP, 1);
83
+ TEST(BTYPE_3, BTI_N, 1);
84
+ TEST(BTYPE_3, BTI_C, 1);
85
+ TEST(BTYPE_3, BTI_J, 0);
86
+ TEST(BTYPE_3, BTI_JC, 0);
87
+
88
+ return fail;
89
+}
90
diff --git a/tests/tcg/aarch64/bti-2.c b/tests/tcg/aarch64/bti-2.c
91
new file mode 100644
92
index XXXXXXX..XXXXXXX
93
--- /dev/null
94
+++ b/tests/tcg/aarch64/bti-2.c
95
@@ -XXX,XX +XXX,XX @@
96
+/*
97
+ * Branch target identification, basic notskip cases.
98
+ */
99
+
100
+#include <stdio.h>
101
+#include <signal.h>
102
+#include <string.h>
103
+#include <unistd.h>
104
+#include <sys/mman.h>
105
+
106
+#ifndef PROT_BTI
107
+#define PROT_BTI 0x10
108
+#endif
109
+
110
+static void skip2_sigill(int sig, siginfo_t *info, void *vuc)
111
+{
112
+ ucontext_t *uc = vuc;
113
+ uc->uc_mcontext.pc += 8;
114
+ uc->uc_mcontext.pstate = 1;
115
+}
116
+
117
+#define NOP "nop"
118
+#define BTI_N "hint #32"
119
+#define BTI_C "hint #34"
120
+#define BTI_J "hint #36"
121
+#define BTI_JC "hint #38"
122
+
123
+#define BTYPE_1(DEST) \
124
+ "mov x1, #1\n\t" \
125
+ "adr x16, 1f\n\t" \
126
+ "br x16\n" \
127
+"1: " DEST "\n\t" \
128
+ "mov x1, #0"
129
+
130
+#define BTYPE_2(DEST) \
131
+ "mov x1, #1\n\t" \
132
+ "adr x16, 1f\n\t" \
133
+ "blr x16\n" \
134
+"1: " DEST "\n\t" \
135
+ "mov x1, #0"
136
+
137
+#define BTYPE_3(DEST) \
138
+ "mov x1, #1\n\t" \
139
+ "adr x15, 1f\n\t" \
140
+ "br x15\n" \
141
+"1: " DEST "\n\t" \
142
+ "mov x1, #0"
143
+
144
+#define TEST(WHICH, DEST, EXPECT) \
145
+ WHICH(DEST) "\n" \
146
+ ".if " #EXPECT "\n\t" \
147
+ "eor x1, x1," #EXPECT "\n" \
148
+ ".endif\n\t" \
149
+ "add x0, x0, x1\n\t"
150
+
151
+asm("\n"
152
+"test_begin:\n\t"
153
+ BTI_C "\n\t"
154
+ "mov x2, x30\n\t"
155
+ "mov x0, #0\n\t"
156
+
157
+ TEST(BTYPE_1, NOP, 1)
158
+ TEST(BTYPE_1, BTI_N, 1)
159
+ TEST(BTYPE_1, BTI_C, 0)
160
+ TEST(BTYPE_1, BTI_J, 0)
161
+ TEST(BTYPE_1, BTI_JC, 0)
162
+
163
+ TEST(BTYPE_2, NOP, 1)
164
+ TEST(BTYPE_2, BTI_N, 1)
165
+ TEST(BTYPE_2, BTI_C, 0)
166
+ TEST(BTYPE_2, BTI_J, 1)
167
+ TEST(BTYPE_2, BTI_JC, 0)
168
+
169
+ TEST(BTYPE_3, NOP, 1)
170
+ TEST(BTYPE_3, BTI_N, 1)
171
+ TEST(BTYPE_3, BTI_C, 1)
172
+ TEST(BTYPE_3, BTI_J, 0)
173
+ TEST(BTYPE_3, BTI_JC, 0)
174
+
175
+ "ret x2\n"
176
+"test_end:"
177
+);
178
+
179
+int main()
180
+{
181
+ struct sigaction sa;
182
+ void *tb, *te;
183
+
184
+ void *p = mmap(0, getpagesize(),
185
+ PROT_EXEC | PROT_READ | PROT_WRITE | PROT_BTI,
186
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
187
+ if (p == MAP_FAILED) {
188
+ perror("mmap");
189
+ return 1;
190
+ }
191
+
192
+ memset(&sa, 0, sizeof(sa));
193
+ sa.sa_sigaction = skip2_sigill;
194
+ sa.sa_flags = SA_SIGINFO;
195
+ if (sigaction(SIGILL, &sa, NULL) < 0) {
196
+ perror("sigaction");
197
+ return 1;
198
+ }
199
+
200
+ /*
201
+ * ??? With "extern char test_begin[]", some compiler versions
202
+ * will use :got references, and some linker versions will
203
+ * resolve this reference to a static symbol incorrectly.
204
+ * Bypass this error by using a pc-relative reference directly.
205
+ */
206
+ asm("adr %0, test_begin; adr %1, test_end" : "=r"(tb), "=r"(te));
207
+
208
+ memcpy(p, tb, te - tb);
209
+
210
+ return ((int (*)(void))p)();
211
+}
212
diff --git a/tests/tcg/aarch64/bti-crt.inc.c b/tests/tcg/aarch64/bti-crt.inc.c
213
new file mode 100644
214
index XXXXXXX..XXXXXXX
215
--- /dev/null
216
+++ b/tests/tcg/aarch64/bti-crt.inc.c
217
@@ -XXX,XX +XXX,XX @@
218
+/*
219
+ * Minimal user-environment for testing BTI.
27
+ *
220
+ *
28
+ * Copyright (c) 2007 CodeSourcery.
221
+ * Normal libc is not (yet) built with BTI support enabled,
29
+ * Written by Paul Brook
222
+ * and so could generate a BTI TRAP before ever reaching main.
30
+ *
31
+ * This program is free software; you can redistribute it and/or modify
32
+ * it under the terms of the GNU General Public License version 2 or
33
+ * (at your option) any later version.
34
+ */
223
+ */
35
+
224
+
36
+/* This is a model of the Arm PrimeCell PL022 synchronous serial port.
225
+#include <stdlib.h>
37
+ * The PL022 TRM is:
226
+#include <signal.h>
38
+ * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0194h/DDI0194H_ssp_pl022_trm.pdf
227
+#include <ucontext.h>
39
+ *
228
+#include <asm/unistd.h>
40
+ * QEMU interface:
229
+
41
+ * + sysbus IRQ: SSPINTR combined interrupt line
230
+int main(void);
42
+ * + sysbus MMIO region 0: MemoryRegion for the device's registers
231
+
232
+void _start(void)
233
+{
234
+ exit(main());
235
+}
236
+
237
+void exit(int ret)
238
+{
239
+ register int x0 __asm__("x0") = ret;
240
+ register int x8 __asm__("x8") = __NR_exit;
241
+
242
+ asm volatile("svc #0" : : "r"(x0), "r"(x8));
243
+ __builtin_unreachable();
244
+}
245
+
246
+/*
247
+ * Irritatingly, the user API struct sigaction does not match the
248
+ * kernel API struct sigaction. So for simplicity, isolate the
249
+ * kernel ABI here, and make this act like signal.
43
+ */
250
+ */
44
+
251
+void signal_info(int sig, void (*fn)(int, siginfo_t *, ucontext_t *))
45
+#ifndef HW_SSI_PL022_H
252
+{
46
+#define HW_SSI_PL022_H
253
+ struct kernel_sigaction {
47
+
254
+ void (*handler)(int, siginfo_t *, ucontext_t *);
48
+#include "hw/sysbus.h"
255
+ unsigned long flags;
49
+
256
+ unsigned long restorer;
50
+#define TYPE_PL022 "pl022"
257
+ unsigned long mask;
51
+#define PL022(obj) OBJECT_CHECK(PL022State, (obj), TYPE_PL022)
258
+ } sa = { fn, SA_SIGINFO, 0, 0 };
52
+
259
+
53
+typedef struct PL022State {
260
+ register int x0 __asm__("x0") = sig;
54
+ SysBusDevice parent_obj;
261
+ register void *x1 __asm__("x1") = &sa;
55
+
262
+ register void *x2 __asm__("x2") = 0;
56
+ MemoryRegion iomem;
263
+ register int x3 __asm__("x3") = sizeof(unsigned long);
57
+ uint32_t cr0;
264
+ register int x8 __asm__("x8") = __NR_rt_sigaction;
58
+ uint32_t cr1;
265
+
59
+ uint32_t bitmask;
266
+ asm volatile("svc #0"
60
+ uint32_t sr;
267
+ : : "r"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x8) : "memory");
61
+ uint32_t cpsr;
268
+}
62
+ uint32_t is;
269
diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target
63
+ uint32_t im;
64
+ /* The FIFO head points to the next empty entry. */
65
+ int tx_fifo_head;
66
+ int rx_fifo_head;
67
+ int tx_fifo_len;
68
+ int rx_fifo_len;
69
+ uint16_t tx_fifo[8];
70
+ uint16_t rx_fifo[8];
71
+ qemu_irq irq;
72
+ SSIBus *ssi;
73
+} PL022State;
74
+
75
+#endif
76
diff --git a/hw/ssi/pl022.c b/hw/ssi/pl022.c
77
index XXXXXXX..XXXXXXX 100644
270
index XXXXXXX..XXXXXXX 100644
78
--- a/hw/ssi/pl022.c
271
--- a/tests/tcg/aarch64/Makefile.target
79
+++ b/hw/ssi/pl022.c
272
+++ b/tests/tcg/aarch64/Makefile.target
80
@@ -XXX,XX +XXX,XX @@
273
@@ -XXX,XX +XXX,XX @@ run-pauth-%: QEMU_OPTS += -cpu max
81
274
run-plugin-pauth-%: QEMU_OPTS += -cpu max
82
#include "qemu/osdep.h"
275
endif
83
#include "hw/sysbus.h"
276
84
+#include "hw/ssi/pl022.h"
277
+# BTI Tests
85
#include "hw/ssi/ssi.h"
278
+# bti-1 tests the elf notes, so we require special compiler support.
86
#include "qemu/log.h"
279
+ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_ARMV8_BTI),)
87
280
+AARCH64_TESTS += bti-1
88
@@ -XXX,XX +XXX,XX @@ do { fprintf(stderr, "pl022: error: " fmt , ## __VA_ARGS__);} while (0)
281
+bti-1: CFLAGS += -mbranch-protection=standard
89
#define PL022_INT_RX 0x04
282
+bti-1: LDFLAGS += -nostdlib
90
#define PL022_INT_TX 0x08
283
+endif
91
284
+# bti-2 tests PROT_BTI, so no special compiler support required.
92
-#define TYPE_PL022 "pl022"
285
+AARCH64_TESTS += bti-2
93
-#define PL022(obj) OBJECT_CHECK(PL022State, (obj), TYPE_PL022)
286
+
94
-
287
# Semihosting smoke test for linux-user
95
-typedef struct PL022State {
288
AARCH64_TESTS += semihosting
96
- SysBusDevice parent_obj;
289
run-semihosting: semihosting
97
-
290
diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh
98
- MemoryRegion iomem;
291
index XXXXXXX..XXXXXXX 100755
99
- uint32_t cr0;
292
--- a/tests/tcg/configure.sh
100
- uint32_t cr1;
293
+++ b/tests/tcg/configure.sh
101
- uint32_t bitmask;
294
@@ -XXX,XX +XXX,XX @@ for target in $target_list; do
102
- uint32_t sr;
295
-march=armv8.3-a -o $TMPE $TMPC; then
103
- uint32_t cpsr;
296
echo "CROSS_CC_HAS_ARMV8_3=y" >> $config_target_mak
104
- uint32_t is;
297
fi
105
- uint32_t im;
298
+ if do_compiler "$target_compiler" $target_compiler_cflags \
106
- /* The FIFO head points to the next empty entry. */
299
+ -mbranch-protection=standard -o $TMPE $TMPC; then
107
- int tx_fifo_head;
300
+ echo "CROSS_CC_HAS_ARMV8_BTI=y" >> $config_target_mak
108
- int rx_fifo_head;
301
+ fi
109
- int tx_fifo_len;
302
;;
110
- int rx_fifo_len;
303
esac
111
- uint16_t tx_fifo[8];
304
112
- uint16_t rx_fifo[8];
113
- qemu_irq irq;
114
- SSIBus *ssi;
115
-} PL022State;
116
-
117
static const unsigned char pl022_id[8] =
118
{ 0x22, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
119
120
diff --git a/MAINTAINERS b/MAINTAINERS
121
index XXXXXXX..XXXXXXX 100644
122
--- a/MAINTAINERS
123
+++ b/MAINTAINERS
124
@@ -XXX,XX +XXX,XX @@ F: hw/gpio/pl061.c
125
F: hw/input/pl050.c
126
F: hw/intc/pl190.c
127
F: hw/sd/pl181.c
128
+F: hw/ssi/pl022.c
129
+F: include/hw/ssi/pl022.h
130
F: hw/timer/pl031.c
131
F: include/hw/arm/primecell.h
132
F: hw/timer/cmsdk-apb-timer.c
133
--
305
--
134
2.18.0
306
2.20.1
135
307
136
308
diff view generated by jsdifflib
1
Connect the VIRQ and VFIQ lines from the GIC to the CPU;
1
From: Thomas Huth <thuth@redhat.com>
2
these exist always for both CPU and GIC whether the
3
virtualization extensions are enabled or not, so we
4
can just unconditionally connect them.
5
2
3
When compiling with -Werror=implicit-fallthrough, gcc complains about
4
missing fallthrough annotations in this file. Looking at the code,
5
the fallthrough is very likely intended here, so add some comments
6
to silence the compiler warnings.
7
8
Signed-off-by: Thomas Huth <thuth@redhat.com>
9
Message-id: 20201020105938.23209-1-thuth@redhat.com
10
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
8
Message-id: 20180821132811.17675-5-peter.maydell@linaro.org
9
---
12
---
10
hw/arm/highbank.c | 6 ++++++
13
hw/arm/highbank.c | 2 ++
11
1 file changed, 6 insertions(+)
14
1 file changed, 2 insertions(+)
12
15
13
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
16
diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c
14
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/arm/highbank.c
18
--- a/hw/arm/highbank.c
16
+++ b/hw/arm/highbank.c
19
+++ b/hw/arm/highbank.c
17
@@ -XXX,XX +XXX,XX @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
20
@@ -XXX,XX +XXX,XX @@ static void hb_reset_secondary(ARMCPU *cpu, const struct arm_boot_info *info)
18
int n;
21
address_space_stl_notdirty(&address_space_memory,
19
qemu_irq cpu_irq[4];
22
SMP_BOOT_REG + 0x30, 0,
20
qemu_irq cpu_fiq[4];
23
MEMTXATTRS_UNSPECIFIED, NULL);
21
+ qemu_irq cpu_virq[4];
24
+ /* fallthrough */
22
+ qemu_irq cpu_vfiq[4];
25
case 3:
23
MemoryRegion *sysram;
26
address_space_stl_notdirty(&address_space_memory,
24
MemoryRegion *dram;
27
SMP_BOOT_REG + 0x20, 0,
25
MemoryRegion *sysmem;
28
MEMTXATTRS_UNSPECIFIED, NULL);
26
@@ -XXX,XX +XXX,XX @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
29
+ /* fallthrough */
27
object_property_set_bool(cpuobj, true, "realized", &error_fatal);
30
case 2:
28
cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ);
31
address_space_stl_notdirty(&address_space_memory,
29
cpu_fiq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ);
32
SMP_BOOT_REG + 0x10, 0,
30
+ cpu_virq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_VIRQ);
31
+ cpu_vfiq[n] = qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_VFIQ);
32
}
33
34
sysmem = get_system_memory();
35
@@ -XXX,XX +XXX,XX @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id)
36
for (n = 0; n < smp_cpus; n++) {
37
sysbus_connect_irq(busdev, n, cpu_irq[n]);
38
sysbus_connect_irq(busdev, n + smp_cpus, cpu_fiq[n]);
39
+ sysbus_connect_irq(busdev, n + 2 * smp_cpus, cpu_virq[n]);
40
+ sysbus_connect_irq(busdev, n + 3 * smp_cpus, cpu_vfiq[n]);
41
}
42
43
for (n = 0; n < 128; n++) {
44
--
33
--
45
2.18.0
34
2.20.1
46
35
47
36
diff view generated by jsdifflib
1
Untabify the arm translate.c. This affects only some lines,
1
From: Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru>
2
mostly comments, in the iwMMXt code. We've never touched
3
that code in years, so it's not going to get fixed up
4
by our "change when touched" process, and a bulk change
5
is not going to be too disruptive.
6
2
7
This commit was produced using Emacs "untabify"; it is
3
This patch sets min_cpus field for xlnx-versal-virt platform,
8
a whitespace-only change.
4
because it always creates XLNX_VERSAL_NR_ACPUS cpus even with
5
-smp 1 command line option.
9
6
7
Signed-off-by: Pavel Dovgalyuk <pavel.dovgalyuk@ispras.ru>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
10
Message-id: 160343854912.8460.17915238517799132371.stgit@pasha-ThinkPad-X280
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Message-id: 20180821165215.29069-2-peter.maydell@linaro.org
12
---
12
---
13
target/arm/translate.c | 122 ++++++++++++++++++++---------------------
13
hw/arm/xlnx-versal-virt.c | 1 +
14
1 file changed, 61 insertions(+), 61 deletions(-)
14
1 file changed, 1 insertion(+)
15
15
16
diff --git a/target/arm/translate.c b/target/arm/translate.c
16
diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c
17
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
18
--- a/target/arm/translate.c
18
--- a/hw/arm/xlnx-versal-virt.c
19
+++ b/target/arm/translate.c
19
+++ b/hw/arm/xlnx-versal-virt.c
20
@@ -XXX,XX +XXX,XX @@ static inline void gen_mov_vreg_F0(int dp, int reg)
20
@@ -XXX,XX +XXX,XX @@ static void versal_virt_machine_class_init(ObjectClass *oc, void *data)
21
tcg_gen_st_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
21
22
}
22
mc->desc = "Xilinx Versal Virtual development board";
23
23
mc->init = versal_virt_init;
24
-#define ARM_CP_RW_BIT    (1 << 20)
24
+ mc->min_cpus = XLNX_VERSAL_NR_ACPUS;
25
+#define ARM_CP_RW_BIT (1 << 20)
25
mc->max_cpus = XLNX_VERSAL_NR_ACPUS;
26
26
mc->default_cpus = XLNX_VERSAL_NR_ACPUS;
27
static inline void iwmmxt_load_reg(TCGv_i64 var, int reg)
27
mc->no_cdrom = true;
28
{
29
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
30
wrd = insn & 0xf;
31
rdlo = (insn >> 12) & 0xf;
32
rdhi = (insn >> 16) & 0xf;
33
- if (insn & ARM_CP_RW_BIT) {            /* TMRRC */
34
+ if (insn & ARM_CP_RW_BIT) { /* TMRRC */
35
iwmmxt_load_reg(cpu_V0, wrd);
36
tcg_gen_extrl_i64_i32(cpu_R[rdlo], cpu_V0);
37
tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
38
tcg_gen_extrl_i64_i32(cpu_R[rdhi], cpu_V0);
39
- } else {                    /* TMCRR */
40
+ } else { /* TMCRR */
41
tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]);
42
iwmmxt_store_reg(cpu_V0, wrd);
43
gen_op_iwmmxt_set_mup();
44
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
45
return 1;
46
}
47
if (insn & ARM_CP_RW_BIT) {
48
- if ((insn >> 28) == 0xf) {            /* WLDRW wCx */
49
+ if ((insn >> 28) == 0xf) { /* WLDRW wCx */
50
tmp = tcg_temp_new_i32();
51
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
52
iwmmxt_store_creg(wrd, tmp);
53
} else {
54
i = 1;
55
if (insn & (1 << 8)) {
56
- if (insn & (1 << 22)) {        /* WLDRD */
57
+ if (insn & (1 << 22)) { /* WLDRD */
58
gen_aa32_ld64(s, cpu_M0, addr, get_mem_index(s));
59
i = 0;
60
- } else {                /* WLDRW wRd */
61
+ } else { /* WLDRW wRd */
62
tmp = tcg_temp_new_i32();
63
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
64
}
65
} else {
66
tmp = tcg_temp_new_i32();
67
- if (insn & (1 << 22)) {        /* WLDRH */
68
+ if (insn & (1 << 22)) { /* WLDRH */
69
gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
70
- } else {                /* WLDRB */
71
+ } else { /* WLDRB */
72
gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
73
}
74
}
75
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
76
gen_op_iwmmxt_movq_wRn_M0(wrd);
77
}
78
} else {
79
- if ((insn >> 28) == 0xf) {            /* WSTRW wCx */
80
+ if ((insn >> 28) == 0xf) { /* WSTRW wCx */
81
tmp = iwmmxt_load_creg(wrd);
82
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
83
} else {
84
gen_op_iwmmxt_movq_M0_wRn(wrd);
85
tmp = tcg_temp_new_i32();
86
if (insn & (1 << 8)) {
87
- if (insn & (1 << 22)) {        /* WSTRD */
88
+ if (insn & (1 << 22)) { /* WSTRD */
89
gen_aa32_st64(s, cpu_M0, addr, get_mem_index(s));
90
- } else {                /* WSTRW wRd */
91
+ } else { /* WSTRW wRd */
92
tcg_gen_extrl_i64_i32(tmp, cpu_M0);
93
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
94
}
95
} else {
96
- if (insn & (1 << 22)) {        /* WSTRH */
97
+ if (insn & (1 << 22)) { /* WSTRH */
98
tcg_gen_extrl_i64_i32(tmp, cpu_M0);
99
gen_aa32_st16(s, tmp, addr, get_mem_index(s));
100
- } else {                /* WSTRB */
101
+ } else { /* WSTRB */
102
tcg_gen_extrl_i64_i32(tmp, cpu_M0);
103
gen_aa32_st8(s, tmp, addr, get_mem_index(s));
104
}
105
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
106
return 1;
107
108
switch (((insn >> 12) & 0xf00) | ((insn >> 4) & 0xff)) {
109
- case 0x000:                        /* WOR */
110
+ case 0x000: /* WOR */
111
wrd = (insn >> 12) & 0xf;
112
rd0 = (insn >> 0) & 0xf;
113
rd1 = (insn >> 16) & 0xf;
114
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
115
gen_op_iwmmxt_set_mup();
116
gen_op_iwmmxt_set_cup();
117
break;
118
- case 0x011:                        /* TMCR */
119
+ case 0x011: /* TMCR */
120
if (insn & 0xf)
121
return 1;
122
rd = (insn >> 12) & 0xf;
123
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
124
return 1;
125
}
126
break;
127
- case 0x100:                        /* WXOR */
128
+ case 0x100: /* WXOR */
129
wrd = (insn >> 12) & 0xf;
130
rd0 = (insn >> 0) & 0xf;
131
rd1 = (insn >> 16) & 0xf;
132
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
133
gen_op_iwmmxt_set_mup();
134
gen_op_iwmmxt_set_cup();
135
break;
136
- case 0x111:                        /* TMRC */
137
+ case 0x111: /* TMRC */
138
if (insn & 0xf)
139
return 1;
140
rd = (insn >> 12) & 0xf;
141
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
142
tmp = iwmmxt_load_creg(wrd);
143
store_reg(s, rd, tmp);
144
break;
145
- case 0x300:                        /* WANDN */
146
+ case 0x300: /* WANDN */
147
wrd = (insn >> 12) & 0xf;
148
rd0 = (insn >> 0) & 0xf;
149
rd1 = (insn >> 16) & 0xf;
150
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
151
gen_op_iwmmxt_set_mup();
152
gen_op_iwmmxt_set_cup();
153
break;
154
- case 0x200:                        /* WAND */
155
+ case 0x200: /* WAND */
156
wrd = (insn >> 12) & 0xf;
157
rd0 = (insn >> 0) & 0xf;
158
rd1 = (insn >> 16) & 0xf;
159
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
160
gen_op_iwmmxt_set_mup();
161
gen_op_iwmmxt_set_cup();
162
break;
163
- case 0x810: case 0xa10:                /* WMADD */
164
+ case 0x810: case 0xa10: /* WMADD */
165
wrd = (insn >> 12) & 0xf;
166
rd0 = (insn >> 0) & 0xf;
167
rd1 = (insn >> 16) & 0xf;
168
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
169
gen_op_iwmmxt_movq_wRn_M0(wrd);
170
gen_op_iwmmxt_set_mup();
171
break;
172
- case 0x10e: case 0x50e: case 0x90e: case 0xd0e:    /* WUNPCKIL */
173
+ case 0x10e: case 0x50e: case 0x90e: case 0xd0e: /* WUNPCKIL */
174
wrd = (insn >> 12) & 0xf;
175
rd0 = (insn >> 16) & 0xf;
176
rd1 = (insn >> 0) & 0xf;
177
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
178
gen_op_iwmmxt_set_mup();
179
gen_op_iwmmxt_set_cup();
180
break;
181
- case 0x10c: case 0x50c: case 0x90c: case 0xd0c:    /* WUNPCKIH */
182
+ case 0x10c: case 0x50c: case 0x90c: case 0xd0c: /* WUNPCKIH */
183
wrd = (insn >> 12) & 0xf;
184
rd0 = (insn >> 16) & 0xf;
185
rd1 = (insn >> 0) & 0xf;
186
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
187
gen_op_iwmmxt_set_mup();
188
gen_op_iwmmxt_set_cup();
189
break;
190
- case 0x012: case 0x112: case 0x412: case 0x512:    /* WSAD */
191
+ case 0x012: case 0x112: case 0x412: case 0x512: /* WSAD */
192
wrd = (insn >> 12) & 0xf;
193
rd0 = (insn >> 16) & 0xf;
194
rd1 = (insn >> 0) & 0xf;
195
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
196
gen_op_iwmmxt_movq_wRn_M0(wrd);
197
gen_op_iwmmxt_set_mup();
198
break;
199
- case 0x010: case 0x110: case 0x210: case 0x310:    /* WMUL */
200
+ case 0x010: case 0x110: case 0x210: case 0x310: /* WMUL */
201
wrd = (insn >> 12) & 0xf;
202
rd0 = (insn >> 16) & 0xf;
203
rd1 = (insn >> 0) & 0xf;
204
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
205
gen_op_iwmmxt_movq_wRn_M0(wrd);
206
gen_op_iwmmxt_set_mup();
207
break;
208
- case 0x410: case 0x510: case 0x610: case 0x710:    /* WMAC */
209
+ case 0x410: case 0x510: case 0x610: case 0x710: /* WMAC */
210
wrd = (insn >> 12) & 0xf;
211
rd0 = (insn >> 16) & 0xf;
212
rd1 = (insn >> 0) & 0xf;
213
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
214
gen_op_iwmmxt_movq_wRn_M0(wrd);
215
gen_op_iwmmxt_set_mup();
216
break;
217
- case 0x006: case 0x406: case 0x806: case 0xc06:    /* WCMPEQ */
218
+ case 0x006: case 0x406: case 0x806: case 0xc06: /* WCMPEQ */
219
wrd = (insn >> 12) & 0xf;
220
rd0 = (insn >> 16) & 0xf;
221
rd1 = (insn >> 0) & 0xf;
222
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
223
gen_op_iwmmxt_set_mup();
224
gen_op_iwmmxt_set_cup();
225
break;
226
- case 0x800: case 0x900: case 0xc00: case 0xd00:    /* WAVG2 */
227
+ case 0x800: case 0x900: case 0xc00: case 0xd00: /* WAVG2 */
228
wrd = (insn >> 12) & 0xf;
229
rd0 = (insn >> 16) & 0xf;
230
rd1 = (insn >> 0) & 0xf;
231
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
232
gen_op_iwmmxt_set_mup();
233
gen_op_iwmmxt_set_cup();
234
break;
235
- case 0x802: case 0x902: case 0xa02: case 0xb02:    /* WALIGNR */
236
+ case 0x802: case 0x902: case 0xa02: case 0xb02: /* WALIGNR */
237
wrd = (insn >> 12) & 0xf;
238
rd0 = (insn >> 16) & 0xf;
239
rd1 = (insn >> 0) & 0xf;
240
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
241
gen_op_iwmmxt_movq_wRn_M0(wrd);
242
gen_op_iwmmxt_set_mup();
243
break;
244
- case 0x601: case 0x605: case 0x609: case 0x60d:    /* TINSR */
245
+ case 0x601: case 0x605: case 0x609: case 0x60d: /* TINSR */
246
if (((insn >> 6) & 3) == 3)
247
return 1;
248
rd = (insn >> 12) & 0xf;
249
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
250
gen_op_iwmmxt_movq_wRn_M0(wrd);
251
gen_op_iwmmxt_set_mup();
252
break;
253
- case 0x107: case 0x507: case 0x907: case 0xd07:    /* TEXTRM */
254
+ case 0x107: case 0x507: case 0x907: case 0xd07: /* TEXTRM */
255
rd = (insn >> 12) & 0xf;
256
wrd = (insn >> 16) & 0xf;
257
if (rd == 15 || ((insn >> 22) & 3) == 3)
258
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
259
}
260
store_reg(s, rd, tmp);
261
break;
262
- case 0x117: case 0x517: case 0x917: case 0xd17:    /* TEXTRC */
263
+ case 0x117: case 0x517: case 0x917: case 0xd17: /* TEXTRC */
264
if ((insn & 0x000ff008) != 0x0003f000 || ((insn >> 22) & 3) == 3)
265
return 1;
266
tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
267
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
268
gen_set_nzcv(tmp);
269
tcg_temp_free_i32(tmp);
270
break;
271
- case 0x401: case 0x405: case 0x409: case 0x40d:    /* TBCST */
272
+ case 0x401: case 0x405: case 0x409: case 0x40d: /* TBCST */
273
if (((insn >> 6) & 3) == 3)
274
return 1;
275
rd = (insn >> 12) & 0xf;
276
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
277
gen_op_iwmmxt_movq_wRn_M0(wrd);
278
gen_op_iwmmxt_set_mup();
279
break;
280
- case 0x113: case 0x513: case 0x913: case 0xd13:    /* TANDC */
281
+ case 0x113: case 0x513: case 0x913: case 0xd13: /* TANDC */
282
if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3)
283
return 1;
284
tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
285
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
286
tcg_temp_free_i32(tmp2);
287
tcg_temp_free_i32(tmp);
288
break;
289
- case 0x01c: case 0x41c: case 0x81c: case 0xc1c:    /* WACC */
290
+ case 0x01c: case 0x41c: case 0x81c: case 0xc1c: /* WACC */
291
wrd = (insn >> 12) & 0xf;
292
rd0 = (insn >> 16) & 0xf;
293
gen_op_iwmmxt_movq_M0_wRn(rd0);
294
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
295
gen_op_iwmmxt_movq_wRn_M0(wrd);
296
gen_op_iwmmxt_set_mup();
297
break;
298
- case 0x115: case 0x515: case 0x915: case 0xd15:    /* TORC */
299
+ case 0x115: case 0x515: case 0x915: case 0xd15: /* TORC */
300
if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3)
301
return 1;
302
tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
303
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
304
tcg_temp_free_i32(tmp2);
305
tcg_temp_free_i32(tmp);
306
break;
307
- case 0x103: case 0x503: case 0x903: case 0xd03:    /* TMOVMSK */
308
+ case 0x103: case 0x503: case 0x903: case 0xd03: /* TMOVMSK */
309
rd = (insn >> 12) & 0xf;
310
rd0 = (insn >> 16) & 0xf;
311
if ((insn & 0xf) != 0 || ((insn >> 22) & 3) == 3)
312
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
313
}
314
store_reg(s, rd, tmp);
315
break;
316
- case 0x106: case 0x306: case 0x506: case 0x706:    /* WCMPGT */
317
+ case 0x106: case 0x306: case 0x506: case 0x706: /* WCMPGT */
318
case 0x906: case 0xb06: case 0xd06: case 0xf06:
319
wrd = (insn >> 12) & 0xf;
320
rd0 = (insn >> 16) & 0xf;
321
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
322
gen_op_iwmmxt_set_mup();
323
gen_op_iwmmxt_set_cup();
324
break;
325
- case 0x00e: case 0x20e: case 0x40e: case 0x60e:    /* WUNPCKEL */
326
+ case 0x00e: case 0x20e: case 0x40e: case 0x60e: /* WUNPCKEL */
327
case 0x80e: case 0xa0e: case 0xc0e: case 0xe0e:
328
wrd = (insn >> 12) & 0xf;
329
rd0 = (insn >> 16) & 0xf;
330
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
331
gen_op_iwmmxt_set_mup();
332
gen_op_iwmmxt_set_cup();
333
break;
334
- case 0x00c: case 0x20c: case 0x40c: case 0x60c:    /* WUNPCKEH */
335
+ case 0x00c: case 0x20c: case 0x40c: case 0x60c: /* WUNPCKEH */
336
case 0x80c: case 0xa0c: case 0xc0c: case 0xe0c:
337
wrd = (insn >> 12) & 0xf;
338
rd0 = (insn >> 16) & 0xf;
339
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
340
gen_op_iwmmxt_set_mup();
341
gen_op_iwmmxt_set_cup();
342
break;
343
- case 0x204: case 0x604: case 0xa04: case 0xe04:    /* WSRL */
344
+ case 0x204: case 0x604: case 0xa04: case 0xe04: /* WSRL */
345
case 0x214: case 0x614: case 0xa14: case 0xe14:
346
if (((insn >> 22) & 3) == 0)
347
return 1;
348
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
349
gen_op_iwmmxt_set_mup();
350
gen_op_iwmmxt_set_cup();
351
break;
352
- case 0x004: case 0x404: case 0x804: case 0xc04:    /* WSRA */
353
+ case 0x004: case 0x404: case 0x804: case 0xc04: /* WSRA */
354
case 0x014: case 0x414: case 0x814: case 0xc14:
355
if (((insn >> 22) & 3) == 0)
356
return 1;
357
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
358
gen_op_iwmmxt_set_mup();
359
gen_op_iwmmxt_set_cup();
360
break;
361
- case 0x104: case 0x504: case 0x904: case 0xd04:    /* WSLL */
362
+ case 0x104: case 0x504: case 0x904: case 0xd04: /* WSLL */
363
case 0x114: case 0x514: case 0x914: case 0xd14:
364
if (((insn >> 22) & 3) == 0)
365
return 1;
366
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
367
gen_op_iwmmxt_set_mup();
368
gen_op_iwmmxt_set_cup();
369
break;
370
- case 0x304: case 0x704: case 0xb04: case 0xf04:    /* WROR */
371
+ case 0x304: case 0x704: case 0xb04: case 0xf04: /* WROR */
372
case 0x314: case 0x714: case 0xb14: case 0xf14:
373
if (((insn >> 22) & 3) == 0)
374
return 1;
375
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
376
gen_op_iwmmxt_set_mup();
377
gen_op_iwmmxt_set_cup();
378
break;
379
- case 0x116: case 0x316: case 0x516: case 0x716:    /* WMIN */
380
+ case 0x116: case 0x316: case 0x516: case 0x716: /* WMIN */
381
case 0x916: case 0xb16: case 0xd16: case 0xf16:
382
wrd = (insn >> 12) & 0xf;
383
rd0 = (insn >> 16) & 0xf;
384
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
385
gen_op_iwmmxt_movq_wRn_M0(wrd);
386
gen_op_iwmmxt_set_mup();
387
break;
388
- case 0x016: case 0x216: case 0x416: case 0x616:    /* WMAX */
389
+ case 0x016: case 0x216: case 0x416: case 0x616: /* WMAX */
390
case 0x816: case 0xa16: case 0xc16: case 0xe16:
391
wrd = (insn >> 12) & 0xf;
392
rd0 = (insn >> 16) & 0xf;
393
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
394
gen_op_iwmmxt_movq_wRn_M0(wrd);
395
gen_op_iwmmxt_set_mup();
396
break;
397
- case 0x002: case 0x102: case 0x202: case 0x302:    /* WALIGNI */
398
+ case 0x002: case 0x102: case 0x202: case 0x302: /* WALIGNI */
399
case 0x402: case 0x502: case 0x602: case 0x702:
400
wrd = (insn >> 12) & 0xf;
401
rd0 = (insn >> 16) & 0xf;
402
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
403
gen_op_iwmmxt_movq_wRn_M0(wrd);
404
gen_op_iwmmxt_set_mup();
405
break;
406
- case 0x01a: case 0x11a: case 0x21a: case 0x31a:    /* WSUB */
407
+ case 0x01a: case 0x11a: case 0x21a: case 0x31a: /* WSUB */
408
case 0x41a: case 0x51a: case 0x61a: case 0x71a:
409
case 0x81a: case 0x91a: case 0xa1a: case 0xb1a:
410
case 0xc1a: case 0xd1a: case 0xe1a: case 0xf1a:
411
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
412
gen_op_iwmmxt_set_mup();
413
gen_op_iwmmxt_set_cup();
414
break;
415
- case 0x01e: case 0x11e: case 0x21e: case 0x31e:    /* WSHUFH */
416
+ case 0x01e: case 0x11e: case 0x21e: case 0x31e: /* WSHUFH */
417
case 0x41e: case 0x51e: case 0x61e: case 0x71e:
418
case 0x81e: case 0x91e: case 0xa1e: case 0xb1e:
419
case 0xc1e: case 0xd1e: case 0xe1e: case 0xf1e:
420
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
421
gen_op_iwmmxt_set_mup();
422
gen_op_iwmmxt_set_cup();
423
break;
424
- case 0x018: case 0x118: case 0x218: case 0x318:    /* WADD */
425
+ case 0x018: case 0x118: case 0x218: case 0x318: /* WADD */
426
case 0x418: case 0x518: case 0x618: case 0x718:
427
case 0x818: case 0x918: case 0xa18: case 0xb18:
428
case 0xc18: case 0xd18: case 0xe18: case 0xf18:
429
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
430
gen_op_iwmmxt_set_mup();
431
gen_op_iwmmxt_set_cup();
432
break;
433
- case 0x008: case 0x108: case 0x208: case 0x308:    /* WPACK */
434
+ case 0x008: case 0x108: case 0x208: case 0x308: /* WPACK */
435
case 0x408: case 0x508: case 0x608: case 0x708:
436
case 0x808: case 0x908: case 0xa08: case 0xb08:
437
case 0xc08: case 0xd08: case 0xe08: case 0xf08:
438
@@ -XXX,XX +XXX,XX @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
439
tmp = load_reg(s, rd0);
440
tmp2 = load_reg(s, rd1);
441
switch ((insn >> 16) & 0xf) {
442
- case 0x0:                    /* TMIA */
443
+ case 0x0: /* TMIA */
444
gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2);
445
break;
446
- case 0x8:                    /* TMIAPH */
447
+ case 0x8: /* TMIAPH */
448
gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2);
449
break;
450
- case 0xc: case 0xd: case 0xe: case 0xf:        /* TMIAxy */
451
+ case 0xc: case 0xd: case 0xe: case 0xf: /* TMIAxy */
452
if (insn & (1 << 16))
453
tcg_gen_shri_i32(tmp, tmp, 16);
454
if (insn & (1 << 17))
455
@@ -XXX,XX +XXX,XX @@ static int disas_dsp_insn(DisasContext *s, uint32_t insn)
456
tmp = load_reg(s, rd0);
457
tmp2 = load_reg(s, rd1);
458
switch ((insn >> 16) & 0xf) {
459
- case 0x0:                    /* MIA */
460
+ case 0x0: /* MIA */
461
gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2);
462
break;
463
- case 0x8:                    /* MIAPH */
464
+ case 0x8: /* MIAPH */
465
gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2);
466
break;
467
- case 0xc:                    /* MIABB */
468
- case 0xd:                    /* MIABT */
469
- case 0xe:                    /* MIATB */
470
- case 0xf:                    /* MIATT */
471
+ case 0xc: /* MIABB */
472
+ case 0xd: /* MIABT */
473
+ case 0xe: /* MIATB */
474
+ case 0xf: /* MIATT */
475
if (insn & (1 << 16))
476
tcg_gen_shri_i32(tmp, tmp, 16);
477
if (insn & (1 << 17))
478
@@ -XXX,XX +XXX,XX @@ static int disas_dsp_insn(DisasContext *s, uint32_t insn)
479
if (acc != 0)
480
return 1;
481
482
- if (insn & ARM_CP_RW_BIT) {            /* MRA */
483
+ if (insn & ARM_CP_RW_BIT) { /* MRA */
484
iwmmxt_load_reg(cpu_V0, acc);
485
tcg_gen_extrl_i64_i32(cpu_R[rdlo], cpu_V0);
486
tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
487
tcg_gen_extrl_i64_i32(cpu_R[rdhi], cpu_V0);
488
tcg_gen_andi_i32(cpu_R[rdhi], cpu_R[rdhi], (1 << (40 - 32)) - 1);
489
- } else {                    /* MAR */
490
+ } else { /* MAR */
491
tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]);
492
iwmmxt_store_reg(cpu_V0, acc);
493
}
494
--
28
--
495
2.18.0
29
2.20.1
496
30
497
31
diff view generated by jsdifflib
1
Fix MPS2 SCC config register values for the mps2-an511
1
From: Havard Skinnemoen <hskinnemoen@google.com>
2
and mps2-an385 boards:
3
* the SCC_AID bits [23:20] specify the FPGA build target board revision,
4
and the SCC_CFG4 register specifies the actual board revision, so
5
these should have matching values. Claim to be board revision C,
6
consistently -- we had the revision in the wrong part of SCC_AID.
7
* SCC_ID bits [15:4] should be the board number in hex, not decimal
8
2
3
This allows us to reuse npcm7xx_timer_pause for the watchdog timer.
4
5
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
11
Message-id: 20180823175225.22612-1-peter.maydell@linaro.org
12
---
8
---
13
hw/arm/mps2.c | 6 +++---
9
hw/timer/npcm7xx_timer.c | 6 +++---
14
1 file changed, 3 insertions(+), 3 deletions(-)
10
1 file changed, 3 insertions(+), 3 deletions(-)
15
11
16
diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c
12
diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c
17
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/arm/mps2.c
14
--- a/hw/timer/npcm7xx_timer.c
19
+++ b/hw/arm/mps2.c
15
+++ b/hw/timer/npcm7xx_timer.c
20
@@ -XXX,XX +XXX,XX @@ static void mps2_common_init(MachineState *machine)
16
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_pause(NPCM7xxTimer *t)
21
sccdev = DEVICE(&mms->scc);
17
timer_del(&t->qtimer);
22
qdev_set_parent_bus(sccdev, sysbus_get_default());
18
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
23
qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2);
19
t->remaining_ns = t->expires_ns - now;
24
- qdev_prop_set_uint32(sccdev, "scc-aid", 0x02000008);
20
- if (t->remaining_ns <= 0) {
25
+ qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008);
21
- npcm7xx_timer_reached_zero(t);
26
qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id);
22
- }
27
object_property_set_bool(OBJECT(&mms->scc), true, "realized",
28
&error_fatal);
29
@@ -XXX,XX +XXX,XX @@ static void mps2_an385_class_init(ObjectClass *oc, void *data)
30
mc->desc = "ARM MPS2 with AN385 FPGA image for Cortex-M3";
31
mmc->fpga_type = FPGA_AN385;
32
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3");
33
- mmc->scc_id = 0x41040000 | (385 << 4);
34
+ mmc->scc_id = 0x41043850;
35
}
23
}
36
24
37
static void mps2_an511_class_init(ObjectClass *oc, void *data)
25
/*
38
@@ -XXX,XX +XXX,XX @@ static void mps2_an511_class_init(ObjectClass *oc, void *data)
26
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr)
39
mc->desc = "ARM MPS2 with AN511 DesignStart FPGA image for Cortex-M3";
27
} else {
40
mmc->fpga_type = FPGA_AN511;
28
t->tcsr &= ~NPCM7XX_TCSR_CACT;
41
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3");
29
npcm7xx_timer_pause(t);
42
- mmc->scc_id = 0x4104000 | (511 << 4);
30
+ if (t->remaining_ns <= 0) {
43
+ mmc->scc_id = 0x41045110;
31
+ npcm7xx_timer_reached_zero(t);
32
+ }
33
}
34
}
44
}
35
}
45
46
static const TypeInfo mps2_info = {
47
--
36
--
48
2.18.0
37
2.20.1
49
38
50
39
diff view generated by jsdifflib
1
The raspi framebuffir in bcm2835_fb supports the definition
1
From: Hao Wu <wuhaotsh@google.com>
2
of a virtual "viewport", which is smaller than the full
3
physical framebuffer size and at an adjustable offset within
4
it. Only the viewport area is sent to the screen. This allows
5
the guest to do things like double buffering, or scrolling
6
by adjusting the viewport origin. Currently QEMU doesn't
7
implement this at all.
8
2
9
Add support for this feature:
3
The watchdog is part of NPCM7XX's timer module. Its behavior is
10
* the property mailbox code needs to distinguish the
4
controlled by the WTCR register in the timer.
11
virtual width/height from the physical width/height
12
* the framebuffer code needs to do something with the
13
virtual width/height/origin information
14
5
15
Note that the wiki documentation on the semantics of the
6
When enabled, the watchdog issues an interrupt signal after a pre-set
16
virtual and physical height and width has it the wrong way
7
amount of cycles, and issues a reset signal shortly after that.
17
around -- the virtual size is the size of the allocated
18
buffer, and the physical size is the size of the display,
19
so the virtual size is always the same as or larger than
20
the physical.
21
8
22
If the viewport size is set smaller than the physical
9
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
23
screen size, we ignore the viewport settings completely
10
Signed-off-by: Hao Wu <wuhaotsh@google.com>
24
and just display the physical screen area.
11
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
12
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
13
[PMM: deleted blank line at end of npcm_watchdog_timer-test.c]
14
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
---
16
include/hw/misc/npcm7xx_clk.h | 2 +
17
include/hw/timer/npcm7xx_timer.h | 48 +++-
18
hw/arm/npcm7xx.c | 12 +
19
hw/misc/npcm7xx_clk.c | 28 ++
20
hw/timer/npcm7xx_timer.c | 266 ++++++++++++++----
21
tests/qtest/npcm7xx_watchdog_timer-test.c | 319 ++++++++++++++++++++++
22
MAINTAINERS | 1 +
23
tests/qtest/meson.build | 2 +-
24
8 files changed, 624 insertions(+), 54 deletions(-)
25
create mode 100644 tests/qtest/npcm7xx_watchdog_timer-test.c
25
26
26
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
27
diff --git a/include/hw/misc/npcm7xx_clk.h b/include/hw/misc/npcm7xx_clk.h
27
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
28
Message-id: 20180814144436.679-7-peter.maydell@linaro.org
29
---
30
include/hw/display/bcm2835_fb.h | 6 ++++--
31
hw/display/bcm2835_fb.c | 28 ++++++++++++++++++++++------
32
hw/misc/bcm2835_property.c | 21 +++++++++++++++------
33
3 files changed, 41 insertions(+), 14 deletions(-)
34
35
diff --git a/include/hw/display/bcm2835_fb.h b/include/hw/display/bcm2835_fb.h
36
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
37
--- a/include/hw/display/bcm2835_fb.h
29
--- a/include/hw/misc/npcm7xx_clk.h
38
+++ b/include/hw/display/bcm2835_fb.h
30
+++ b/include/hw/misc/npcm7xx_clk.h
39
@@ -XXX,XX +XXX,XX @@ void bcm2835_fb_reconfigure(BCM2835FBState *s, BCM2835FBConfig *newconfig);
31
@@ -XXX,XX +XXX,XX @@
40
*/
32
*/
41
static inline uint32_t bcm2835_fb_get_pitch(BCM2835FBConfig *config)
33
#define NPCM7XX_CLK_NR_REGS (0x70 / sizeof(uint32_t))
34
35
+#define NPCM7XX_WATCHDOG_RESET_GPIO_IN "npcm7xx-clk-watchdog-reset-gpio-in"
36
+
37
typedef struct NPCM7xxCLKState {
38
SysBusDevice parent;
39
40
diff --git a/include/hw/timer/npcm7xx_timer.h b/include/hw/timer/npcm7xx_timer.h
41
index XXXXXXX..XXXXXXX 100644
42
--- a/include/hw/timer/npcm7xx_timer.h
43
+++ b/include/hw/timer/npcm7xx_timer.h
44
@@ -XXX,XX +XXX,XX @@
45
*/
46
#define NPCM7XX_TIMER_NR_REGS (0x54 / sizeof(uint32_t))
47
48
+/* The basic watchdog timer period is 2^14 clock cycles. */
49
+#define NPCM7XX_WATCHDOG_BASETIME_SHIFT 14
50
+
51
+#define NPCM7XX_WATCHDOG_RESET_GPIO_OUT "npcm7xx-clk-watchdog-reset-gpio-out"
52
+
53
typedef struct NPCM7xxTimerCtrlState NPCM7xxTimerCtrlState;
54
55
/**
56
- * struct NPCM7xxTimer - Individual timer state.
57
- * @irq: GIC interrupt line to fire on expiration (if enabled).
58
+ * struct NPCM7xxBaseTimer - Basic functionality that both regular timer and
59
+ * watchdog timer use.
60
* @qtimer: QEMU timer that notifies us on expiration.
61
* @expires_ns: Absolute virtual expiration time.
62
* @remaining_ns: Remaining time until expiration if timer is paused.
63
+ */
64
+typedef struct NPCM7xxBaseTimer {
65
+ QEMUTimer qtimer;
66
+ int64_t expires_ns;
67
+ int64_t remaining_ns;
68
+} NPCM7xxBaseTimer;
69
+
70
+/**
71
+ * struct NPCM7xxTimer - Individual timer state.
72
+ * @ctrl: The timer module that owns this timer.
73
+ * @irq: GIC interrupt line to fire on expiration (if enabled).
74
+ * @base_timer: The basic timer functionality for this timer.
75
* @tcsr: The Timer Control and Status Register.
76
* @ticr: The Timer Initial Count Register.
77
*/
78
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxTimer {
79
NPCM7xxTimerCtrlState *ctrl;
80
81
qemu_irq irq;
82
- QEMUTimer qtimer;
83
- int64_t expires_ns;
84
- int64_t remaining_ns;
85
+ NPCM7xxBaseTimer base_timer;
86
87
uint32_t tcsr;
88
uint32_t ticr;
89
} NPCM7xxTimer;
90
91
+/**
92
+ * struct NPCM7xxWatchdogTimer - The watchdog timer state.
93
+ * @ctrl: The timer module that owns this timer.
94
+ * @irq: GIC interrupt line to fire on expiration (if enabled).
95
+ * @reset_signal: The GPIO used to send a reset signal.
96
+ * @base_timer: The basic timer functionality for this timer.
97
+ * @wtcr: The Watchdog Timer Control Register.
98
+ */
99
+typedef struct NPCM7xxWatchdogTimer {
100
+ NPCM7xxTimerCtrlState *ctrl;
101
+
102
+ qemu_irq irq;
103
+ qemu_irq reset_signal;
104
+ NPCM7xxBaseTimer base_timer;
105
+
106
+ uint32_t wtcr;
107
+} NPCM7xxWatchdogTimer;
108
+
109
/**
110
* struct NPCM7xxTimerCtrlState - Timer Module device state.
111
* @parent: System bus device.
112
* @iomem: Memory region through which registers are accessed.
113
+ * @index: The index of this timer module.
114
* @tisr: The Timer Interrupt Status Register.
115
- * @wtcr: The Watchdog Timer Control Register.
116
* @timer: The five individual timers managed by this module.
117
+ * @watchdog_timer: The watchdog timer managed by this module.
118
*/
119
struct NPCM7xxTimerCtrlState {
120
SysBusDevice parent;
121
@@ -XXX,XX +XXX,XX @@ struct NPCM7xxTimerCtrlState {
122
MemoryRegion iomem;
123
124
uint32_t tisr;
125
- uint32_t wtcr;
126
127
NPCM7xxTimer timer[NPCM7XX_TIMERS_PER_CTRL];
128
+ NPCM7xxWatchdogTimer watchdog_timer;
129
};
130
131
#define TYPE_NPCM7XX_TIMER "npcm7xx-timer"
132
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
133
index XXXXXXX..XXXXXXX 100644
134
--- a/hw/arm/npcm7xx.c
135
+++ b/hw/arm/npcm7xx.c
136
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxInterrupt {
137
NPCM7XX_TIMER12_IRQ,
138
NPCM7XX_TIMER13_IRQ,
139
NPCM7XX_TIMER14_IRQ,
140
+ NPCM7XX_WDG0_IRQ = 47, /* Timer Module 0 Watchdog */
141
+ NPCM7XX_WDG1_IRQ, /* Timer Module 1 Watchdog */
142
+ NPCM7XX_WDG2_IRQ, /* Timer Module 2 Watchdog */
143
};
144
145
/* Total number of GIC interrupts, including internal Cortex-A9 interrupts. */
146
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
147
qemu_irq irq = npcm7xx_irq(s, first_irq + j);
148
sysbus_connect_irq(sbd, j, irq);
149
}
150
+
151
+ /* IRQ for watchdogs */
152
+ sysbus_connect_irq(sbd, NPCM7XX_TIMERS_PER_CTRL,
153
+ npcm7xx_irq(s, NPCM7XX_WDG0_IRQ + i));
154
+ /* GPIO that connects clk module with watchdog */
155
+ qdev_connect_gpio_out_named(DEVICE(&s->tim[i]),
156
+ NPCM7XX_WATCHDOG_RESET_GPIO_OUT, 0,
157
+ qdev_get_gpio_in_named(DEVICE(&s->clk),
158
+ NPCM7XX_WATCHDOG_RESET_GPIO_IN, i));
159
}
160
161
/* UART0..3 (16550 compatible) */
162
diff --git a/hw/misc/npcm7xx_clk.c b/hw/misc/npcm7xx_clk.c
163
index XXXXXXX..XXXXXXX 100644
164
--- a/hw/misc/npcm7xx_clk.c
165
+++ b/hw/misc/npcm7xx_clk.c
166
@@ -XXX,XX +XXX,XX @@
167
#include "qemu/osdep.h"
168
169
#include "hw/misc/npcm7xx_clk.h"
170
+#include "hw/timer/npcm7xx_timer.h"
171
#include "migration/vmstate.h"
172
#include "qemu/error-report.h"
173
#include "qemu/log.h"
174
@@ -XXX,XX +XXX,XX @@
175
#include "qemu/timer.h"
176
#include "qemu/units.h"
177
#include "trace.h"
178
+#include "sysemu/watchdog.h"
179
180
#define PLLCON_LOKI BIT(31)
181
#define PLLCON_LOKS BIT(30)
182
@@ -XXX,XX +XXX,XX @@ static const uint32_t cold_reset_values[NPCM7XX_CLK_NR_REGS] = {
183
[NPCM7XX_CLK_AHBCKFI] = 0x000000c8,
184
};
185
186
+/* Register Field Definitions */
187
+#define NPCM7XX_CLK_WDRCR_CA9C BIT(0) /* Cortex A9 Cores */
188
+
189
+/* The number of watchdogs that can trigger a reset. */
190
+#define NPCM7XX_NR_WATCHDOGS (3)
191
+
192
static uint64_t npcm7xx_clk_read(void *opaque, hwaddr offset, unsigned size)
42
{
193
{
43
- return config->xres * (config->bpp >> 3);
194
uint32_t reg = offset / sizeof(uint32_t);
44
+ uint32_t xres = MAX(config->xres, config->xres_virtual);
195
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_write(void *opaque, hwaddr offset,
45
+ return xres * (config->bpp >> 3);
196
s->regs[reg] = value;
46
}
197
}
47
198
48
/**
199
+/* Perform reset action triggered by a watchdog */
49
@@ -XXX,XX +XXX,XX @@ static inline uint32_t bcm2835_fb_get_pitch(BCM2835FBConfig *config)
200
+static void npcm7xx_clk_perform_watchdog_reset(void *opaque, int n,
201
+ int level)
202
+{
203
+ NPCM7xxCLKState *clk = NPCM7XX_CLK(opaque);
204
+ uint32_t rcr;
205
+
206
+ g_assert(n >= 0 && n <= NPCM7XX_NR_WATCHDOGS);
207
+ rcr = clk->regs[NPCM7XX_CLK_WD0RCR + n];
208
+ if (rcr & NPCM7XX_CLK_WDRCR_CA9C) {
209
+ watchdog_perform_action();
210
+ } else {
211
+ qemu_log_mask(LOG_UNIMP,
212
+ "%s: only CPU reset is implemented. (requested 0x%" PRIx32")\n",
213
+ __func__, rcr);
214
+ }
215
+}
216
+
217
static const struct MemoryRegionOps npcm7xx_clk_ops = {
218
.read = npcm7xx_clk_read,
219
.write = npcm7xx_clk_write,
220
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_clk_init(Object *obj)
221
memory_region_init_io(&s->iomem, obj, &npcm7xx_clk_ops, s,
222
TYPE_NPCM7XX_CLK, 4 * KiB);
223
sysbus_init_mmio(&s->parent, &s->iomem);
224
+ qdev_init_gpio_in_named(DEVICE(s), npcm7xx_clk_perform_watchdog_reset,
225
+ NPCM7XX_WATCHDOG_RESET_GPIO_IN, NPCM7XX_NR_WATCHDOGS);
226
}
227
228
static const VMStateDescription vmstate_npcm7xx_clk = {
229
diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c
230
index XXXXXXX..XXXXXXX 100644
231
--- a/hw/timer/npcm7xx_timer.c
232
+++ b/hw/timer/npcm7xx_timer.c
233
@@ -XXX,XX +XXX,XX @@
234
#include "qemu/osdep.h"
235
236
#include "hw/irq.h"
237
+#include "hw/qdev-properties.h"
238
#include "hw/misc/npcm7xx_clk.h"
239
#include "hw/timer/npcm7xx_timer.h"
240
#include "migration/vmstate.h"
241
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxTimerRegisters {
242
#define NPCM7XX_TCSR_PRESCALE_START 0
243
#define NPCM7XX_TCSR_PRESCALE_LEN 8
244
245
+#define NPCM7XX_WTCR_WTCLK(rv) extract32(rv, 10, 2)
246
+#define NPCM7XX_WTCR_FREEZE_EN BIT(9)
247
+#define NPCM7XX_WTCR_WTE BIT(7)
248
+#define NPCM7XX_WTCR_WTIE BIT(6)
249
+#define NPCM7XX_WTCR_WTIS(rv) extract32(rv, 4, 2)
250
+#define NPCM7XX_WTCR_WTIF BIT(3)
251
+#define NPCM7XX_WTCR_WTRF BIT(2)
252
+#define NPCM7XX_WTCR_WTRE BIT(1)
253
+#define NPCM7XX_WTCR_WTR BIT(0)
254
+
255
+/*
256
+ * The number of clock cycles between interrupt and reset in watchdog, used
257
+ * by the software to handle the interrupt before system is reset.
258
+ */
259
+#define NPCM7XX_WATCHDOG_INTERRUPT_TO_RESET_CYCLES 1024
260
+
261
+/* Start or resume the timer. */
262
+static void npcm7xx_timer_start(NPCM7xxBaseTimer *t)
263
+{
264
+ int64_t now;
265
+
266
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
267
+ t->expires_ns = now + t->remaining_ns;
268
+ timer_mod(&t->qtimer, t->expires_ns);
269
+}
270
+
271
+/* Stop counting. Record the time remaining so we can continue later. */
272
+static void npcm7xx_timer_pause(NPCM7xxBaseTimer *t)
273
+{
274
+ int64_t now;
275
+
276
+ timer_del(&t->qtimer);
277
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
278
+ t->remaining_ns = t->expires_ns - now;
279
+}
280
+
281
+/* Delete the timer and reset it to default state. */
282
+static void npcm7xx_timer_clear(NPCM7xxBaseTimer *t)
283
+{
284
+ timer_del(&t->qtimer);
285
+ t->expires_ns = 0;
286
+ t->remaining_ns = 0;
287
+}
288
+
289
/*
290
* Returns the index of timer in the tc->timer array. This can be used to
291
* locate the registers that belong to this timer.
292
@@ -XXX,XX +XXX,XX @@ static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns)
293
return count;
294
}
295
296
+static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t)
297
+{
298
+ switch (NPCM7XX_WTCR_WTCLK(t->wtcr)) {
299
+ case 0:
300
+ return 1;
301
+ case 1:
302
+ return 256;
303
+ case 2:
304
+ return 2048;
305
+ case 3:
306
+ return 65536;
307
+ default:
308
+ g_assert_not_reached();
309
+ }
310
+}
311
+
312
+static void npcm7xx_watchdog_timer_reset_cycles(NPCM7xxWatchdogTimer *t,
313
+ int64_t cycles)
314
+{
315
+ uint32_t prescaler = npcm7xx_watchdog_timer_prescaler(t);
316
+ int64_t ns = (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ) * cycles;
317
+
318
+ /*
319
+ * The reset function always clears the current timer. The caller of the
320
+ * this needs to decide whether to start the watchdog timer based on
321
+ * specific flag in WTCR.
322
+ */
323
+ npcm7xx_timer_clear(&t->base_timer);
324
+
325
+ ns *= prescaler;
326
+ t->base_timer.remaining_ns = ns;
327
+}
328
+
329
+static void npcm7xx_watchdog_timer_reset(NPCM7xxWatchdogTimer *t)
330
+{
331
+ int64_t cycles = 1;
332
+ uint32_t s = NPCM7XX_WTCR_WTIS(t->wtcr);
333
+
334
+ g_assert(s <= 3);
335
+
336
+ cycles <<= NPCM7XX_WATCHDOG_BASETIME_SHIFT;
337
+ cycles <<= 2 * s;
338
+
339
+ npcm7xx_watchdog_timer_reset_cycles(t, cycles);
340
+}
341
+
342
/*
343
* Raise the interrupt line if there's a pending interrupt and interrupts are
344
* enabled for this timer. If not, lower it.
345
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_check_interrupt(NPCM7xxTimer *t)
346
trace_npcm7xx_timer_irq(DEVICE(tc)->canonical_path, index, pending);
347
}
348
349
-/* Start or resume the timer. */
350
-static void npcm7xx_timer_start(NPCM7xxTimer *t)
351
-{
352
- int64_t now;
353
-
354
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
355
- t->expires_ns = now + t->remaining_ns;
356
- timer_mod(&t->qtimer, t->expires_ns);
357
-}
358
-
359
/*
360
* Called when the counter reaches zero. Sets the interrupt flag, and either
361
* restarts or disables the timer.
362
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_reached_zero(NPCM7xxTimer *t)
363
tc->tisr |= BIT(index);
364
365
if (t->tcsr & NPCM7XX_TCSR_PERIODIC) {
366
- t->remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
367
+ t->base_timer.remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
368
if (t->tcsr & NPCM7XX_TCSR_CEN) {
369
- npcm7xx_timer_start(t);
370
+ npcm7xx_timer_start(&t->base_timer);
371
}
372
} else {
373
t->tcsr &= ~(NPCM7XX_TCSR_CEN | NPCM7XX_TCSR_CACT);
374
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_reached_zero(NPCM7xxTimer *t)
375
npcm7xx_timer_check_interrupt(t);
376
}
377
378
-/* Stop counting. Record the time remaining so we can continue later. */
379
-static void npcm7xx_timer_pause(NPCM7xxTimer *t)
380
-{
381
- int64_t now;
382
-
383
- timer_del(&t->qtimer);
384
- now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
385
- t->remaining_ns = t->expires_ns - now;
386
-}
387
388
/*
389
* Restart the timer from its initial value. If the timer was enabled and stays
390
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_pause(NPCM7xxTimer *t)
50
*/
391
*/
51
static inline uint32_t bcm2835_fb_get_size(BCM2835FBConfig *config)
392
static void npcm7xx_timer_restart(NPCM7xxTimer *t, uint32_t old_tcsr)
52
{
393
{
53
- return config->yres * bcm2835_fb_get_pitch(config);
394
- t->remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
54
+ uint32_t yres = MAX(config->yres, config->yres_virtual);
395
+ t->base_timer.remaining_ns = npcm7xx_timer_count_to_ns(t, t->ticr);
55
+ return yres * bcm2835_fb_get_pitch(config);
396
56
}
397
if (old_tcsr & t->tcsr & NPCM7XX_TCSR_CEN) {
57
398
- npcm7xx_timer_start(t);
58
#endif
399
+ npcm7xx_timer_start(&t->base_timer);
59
diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c
60
index XXXXXXX..XXXXXXX 100644
61
--- a/hw/display/bcm2835_fb.c
62
+++ b/hw/display/bcm2835_fb.c
63
@@ -XXX,XX +XXX,XX @@ static void draw_line_src16(void *opaque, uint8_t *dst, const uint8_t *src,
64
}
400
}
65
}
401
}
66
402
67
+static bool fb_use_offsets(BCM2835FBConfig *config)
403
@@ -XXX,XX +XXX,XX @@ static uint32_t npcm7xx_timer_read_tdr(NPCM7xxTimer *t)
68
+{
404
if (t->tcsr & NPCM7XX_TCSR_CEN) {
405
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
406
407
- return npcm7xx_timer_ns_to_count(t, t->expires_ns - now);
408
+ return npcm7xx_timer_ns_to_count(t, t->base_timer.expires_ns - now);
409
}
410
411
- return npcm7xx_timer_ns_to_count(t, t->remaining_ns);
412
+ return npcm7xx_timer_ns_to_count(t, t->base_timer.remaining_ns);
413
}
414
415
static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr)
416
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr)
417
418
if (npcm7xx_tcsr_prescaler(old_tcsr) != npcm7xx_tcsr_prescaler(new_tcsr)) {
419
/* Recalculate time remaining based on the current TDR value. */
420
- t->remaining_ns = npcm7xx_timer_count_to_ns(t, tdr);
421
+ t->base_timer.remaining_ns = npcm7xx_timer_count_to_ns(t, tdr);
422
if (old_tcsr & t->tcsr & NPCM7XX_TCSR_CEN) {
423
- npcm7xx_timer_start(t);
424
+ npcm7xx_timer_start(&t->base_timer);
425
}
426
}
427
428
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_write_tcsr(NPCM7xxTimer *t, uint32_t new_tcsr)
429
if ((old_tcsr ^ new_tcsr) & NPCM7XX_TCSR_CEN) {
430
if (new_tcsr & NPCM7XX_TCSR_CEN) {
431
t->tcsr |= NPCM7XX_TCSR_CACT;
432
- npcm7xx_timer_start(t);
433
+ npcm7xx_timer_start(&t->base_timer);
434
} else {
435
t->tcsr &= ~NPCM7XX_TCSR_CACT;
436
- npcm7xx_timer_pause(t);
437
- if (t->remaining_ns <= 0) {
438
+ npcm7xx_timer_pause(&t->base_timer);
439
+ if (t->base_timer.remaining_ns <= 0) {
440
npcm7xx_timer_reached_zero(t);
441
}
442
}
443
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_write_tisr(NPCM7xxTimerCtrlState *s, uint32_t value)
444
if (value & (1U << i)) {
445
npcm7xx_timer_check_interrupt(&s->timer[i]);
446
}
447
+
448
}
449
}
450
451
+static void npcm7xx_timer_write_wtcr(NPCM7xxWatchdogTimer *t, uint32_t new_wtcr)
452
+{
453
+ uint32_t old_wtcr = t->wtcr;
454
+
69
+ /*
455
+ /*
70
+ * Return true if we should use the viewport offsets.
456
+ * WTIF and WTRF are cleared by writing 1. Writing 0 makes these bits
71
+ * Experimentally, the hardware seems to do this only if the
457
+ * unchanged.
72
+ * viewport size is larger than the physical screen. (It doesn't
73
+ * prevent the guest setting this silly viewport setting, though...)
74
+ */
458
+ */
75
+ return config->xres_virtual > config->xres &&
459
+ if (new_wtcr & NPCM7XX_WTCR_WTIF) {
76
+ config->yres_virtual > config->yres;
460
+ new_wtcr &= ~NPCM7XX_WTCR_WTIF;
77
+}
461
+ } else if (old_wtcr & NPCM7XX_WTCR_WTIF) {
78
+
462
+ new_wtcr |= NPCM7XX_WTCR_WTIF;
79
static void fb_update_display(void *opaque)
463
+ }
464
+ if (new_wtcr & NPCM7XX_WTCR_WTRF) {
465
+ new_wtcr &= ~NPCM7XX_WTCR_WTRF;
466
+ } else if (old_wtcr & NPCM7XX_WTCR_WTRF) {
467
+ new_wtcr |= NPCM7XX_WTCR_WTRF;
468
+ }
469
+
470
+ t->wtcr = new_wtcr;
471
+
472
+ if (new_wtcr & NPCM7XX_WTCR_WTR) {
473
+ t->wtcr &= ~NPCM7XX_WTCR_WTR;
474
+ npcm7xx_watchdog_timer_reset(t);
475
+ if (new_wtcr & NPCM7XX_WTCR_WTE) {
476
+ npcm7xx_timer_start(&t->base_timer);
477
+ }
478
+ } else if ((old_wtcr ^ new_wtcr) & NPCM7XX_WTCR_WTE) {
479
+ if (new_wtcr & NPCM7XX_WTCR_WTE) {
480
+ npcm7xx_timer_start(&t->base_timer);
481
+ } else {
482
+ npcm7xx_timer_pause(&t->base_timer);
483
+ }
484
+ }
485
+
486
+}
487
+
488
static hwaddr npcm7xx_tcsr_index(hwaddr reg)
80
{
489
{
81
BCM2835FBState *s = opaque;
490
switch (reg) {
82
@@ -XXX,XX +XXX,XX @@ static void fb_update_display(void *opaque)
491
@@ -XXX,XX +XXX,XX @@ static uint64_t npcm7xx_timer_read(void *opaque, hwaddr offset, unsigned size)
83
int last = 0;
492
break;
84
int src_width = 0;
493
85
int dest_width = 0;
494
case NPCM7XX_TIMER_WTCR:
86
+ uint32_t xoff = 0, yoff = 0;
495
- value = s->wtcr;
87
496
+ value = s->watchdog_timer.wtcr;
88
if (s->lock || !s->config.xres) {
497
break;
498
499
default:
500
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_write(void *opaque, hwaddr offset,
501
return;
502
503
case NPCM7XX_TIMER_WTCR:
504
- qemu_log_mask(LOG_UNIMP, "%s: WTCR write not implemented: 0x%08x\n",
505
- __func__, value);
506
+ npcm7xx_timer_write_wtcr(&s->watchdog_timer, value);
89
return;
507
return;
90
}
508
}
91
509
92
src_width = bcm2835_fb_get_pitch(&s->config);
510
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_enter_reset(Object *obj, ResetType type)
93
+ if (fb_use_offsets(&s->config)) {
511
for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) {
94
+ xoff = s->config.xoffset;
512
NPCM7xxTimer *t = &s->timer[i];
95
+ yoff = s->config.yoffset;
513
514
- timer_del(&t->qtimer);
515
- t->expires_ns = 0;
516
- t->remaining_ns = 0;
517
+ npcm7xx_timer_clear(&t->base_timer);
518
t->tcsr = 0x00000005;
519
t->ticr = 0x00000000;
520
}
521
522
s->tisr = 0x00000000;
523
- s->wtcr = 0x00000400;
524
+ /*
525
+ * Set WTCLK to 1(default) and reset all flags except WTRF.
526
+ * WTRF is not reset during a core domain reset.
527
+ */
528
+ s->watchdog_timer.wtcr = 0x00000400 | (s->watchdog_timer.wtcr &
529
+ NPCM7XX_WTCR_WTRF);
530
+}
531
+
532
+static void npcm7xx_watchdog_timer_expired(void *opaque)
533
+{
534
+ NPCM7xxWatchdogTimer *t = opaque;
535
+
536
+ if (t->wtcr & NPCM7XX_WTCR_WTE) {
537
+ if (t->wtcr & NPCM7XX_WTCR_WTIF) {
538
+ if (t->wtcr & NPCM7XX_WTCR_WTRE) {
539
+ t->wtcr |= NPCM7XX_WTCR_WTRF;
540
+ /* send reset signal to CLK module*/
541
+ qemu_irq_raise(t->reset_signal);
542
+ }
543
+ } else {
544
+ t->wtcr |= NPCM7XX_WTCR_WTIF;
545
+ if (t->wtcr & NPCM7XX_WTCR_WTIE) {
546
+ /* send interrupt */
547
+ qemu_irq_raise(t->irq);
548
+ }
549
+ npcm7xx_watchdog_timer_reset_cycles(t,
550
+ NPCM7XX_WATCHDOG_INTERRUPT_TO_RESET_CYCLES);
551
+ npcm7xx_timer_start(&t->base_timer);
552
+ }
96
+ }
553
+ }
97
+
554
}
98
dest_width = s->config.xres;
555
99
556
static void npcm7xx_timer_hold_reset(Object *obj)
100
switch (surface_bits_per_pixel(surface)) {
557
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_hold_reset(Object *obj)
101
@@ -XXX,XX +XXX,XX @@ static void fb_update_display(void *opaque)
558
for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) {
559
qemu_irq_lower(s->timer[i].irq);
102
}
560
}
103
561
+ qemu_irq_lower(s->watchdog_timer.irq);
104
if (s->invalidate) {
562
}
105
+ hwaddr base = s->config.base + xoff + yoff * src_width;
563
106
framebuffer_update_memory_section(&s->fbsection, s->dma_mr,
564
static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
107
- s->config.base,
565
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
108
+ base,
566
NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(dev);
109
s->config.yres, src_width);
567
SysBusDevice *sbd = &s->parent;
568
int i;
569
+ NPCM7xxWatchdogTimer *w;
570
571
for (i = 0; i < NPCM7XX_TIMERS_PER_CTRL; i++) {
572
NPCM7xxTimer *t = &s->timer[i];
573
t->ctrl = s;
574
- timer_init_ns(&t->qtimer, QEMU_CLOCK_VIRTUAL, npcm7xx_timer_expired, t);
575
+ timer_init_ns(&t->base_timer.qtimer, QEMU_CLOCK_VIRTUAL,
576
+ npcm7xx_timer_expired, t);
577
sysbus_init_irq(sbd, &t->irq);
110
}
578
}
111
579
112
@@ -XXX,XX +XXX,XX @@ static void fb_update_display(void *opaque)
580
+ w = &s->watchdog_timer;
113
draw_line_src16, s, &first, &last);
581
+ w->ctrl = s;
114
582
+ timer_init_ns(&w->base_timer.qtimer, QEMU_CLOCK_VIRTUAL,
115
if (first >= 0) {
583
+ npcm7xx_watchdog_timer_expired, w);
116
- dpy_gfx_update(s->con, 0, first, s->config.xres, last - first + 1);
584
+ sysbus_init_irq(sbd, &w->irq);
117
+ dpy_gfx_update(s->con, 0, first, s->config.xres,
585
+
118
+ last - first + 1);
586
memory_region_init_io(&s->iomem, OBJECT(s), &npcm7xx_timer_ops, s,
119
}
587
TYPE_NPCM7XX_TIMER, 4 * KiB);
120
588
sysbus_init_mmio(sbd, &s->iomem);
121
s->invalidate = false;
589
+ qdev_init_gpio_out_named(dev, &w->reset_signal,
122
@@ -XXX,XX +XXX,XX @@ static void bcm2835_fb_mbox_push(BCM2835FBState *s, uint32_t value)
590
+ NPCM7XX_WATCHDOG_RESET_GPIO_OUT, 1);
123
s->config.base = s->vcram_base | (value & 0xc0000000);
591
}
124
s->config.base += BCM2835_FB_OFFSET;
592
125
593
-static const VMStateDescription vmstate_npcm7xx_timer = {
126
- /* TODO - Manage properly virtual resolution */
594
- .name = "npcm7xx-timer",
127
-
595
+static const VMStateDescription vmstate_npcm7xx_base_timer = {
128
pitch = bcm2835_fb_get_pitch(&s->config);
596
+ .name = "npcm7xx-base-timer",
129
size = bcm2835_fb_get_size(&s->config);
597
.version_id = 0,
130
598
.minimum_version_id = 0,
131
@@ -XXX,XX +XXX,XX @@ void bcm2835_fb_reconfigure(BCM2835FBState *s, BCM2835FBConfig *newconfig)
599
.fields = (VMStateField[]) {
132
600
- VMSTATE_TIMER(qtimer, NPCM7xxTimer),
133
s->config = *newconfig;
601
- VMSTATE_INT64(expires_ns, NPCM7xxTimer),
134
602
- VMSTATE_INT64(remaining_ns, NPCM7xxTimer),
135
- /* TODO - Manage properly virtual resolution */
603
+ VMSTATE_TIMER(qtimer, NPCM7xxBaseTimer),
136
-
604
+ VMSTATE_INT64(expires_ns, NPCM7xxBaseTimer),
137
s->invalidate = true;
605
+ VMSTATE_INT64(remaining_ns, NPCM7xxBaseTimer),
138
qemu_console_resize(s->con, s->config.xres, s->config.yres);
606
+ VMSTATE_END_OF_LIST(),
139
s->lock = false;
607
+ },
140
diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c
608
+};
609
+
610
+static const VMStateDescription vmstate_npcm7xx_timer = {
611
+ .name = "npcm7xx-timer",
612
+ .version_id = 1,
613
+ .minimum_version_id = 1,
614
+ .fields = (VMStateField[]) {
615
+ VMSTATE_STRUCT(base_timer, NPCM7xxTimer,
616
+ 0, vmstate_npcm7xx_base_timer,
617
+ NPCM7xxBaseTimer),
618
VMSTATE_UINT32(tcsr, NPCM7xxTimer),
619
VMSTATE_UINT32(ticr, NPCM7xxTimer),
620
VMSTATE_END_OF_LIST(),
621
},
622
};
623
624
-static const VMStateDescription vmstate_npcm7xx_timer_ctrl = {
625
- .name = "npcm7xx-timer-ctrl",
626
+static const VMStateDescription vmstate_npcm7xx_watchdog_timer = {
627
+ .name = "npcm7xx-watchdog-timer",
628
.version_id = 0,
629
.minimum_version_id = 0,
630
+ .fields = (VMStateField[]) {
631
+ VMSTATE_STRUCT(base_timer, NPCM7xxWatchdogTimer,
632
+ 0, vmstate_npcm7xx_base_timer,
633
+ NPCM7xxBaseTimer),
634
+ VMSTATE_UINT32(wtcr, NPCM7xxWatchdogTimer),
635
+ VMSTATE_END_OF_LIST(),
636
+ },
637
+};
638
+
639
+static const VMStateDescription vmstate_npcm7xx_timer_ctrl = {
640
+ .name = "npcm7xx-timer-ctrl",
641
+ .version_id = 1,
642
+ .minimum_version_id = 1,
643
.fields = (VMStateField[]) {
644
VMSTATE_UINT32(tisr, NPCM7xxTimerCtrlState),
645
- VMSTATE_UINT32(wtcr, NPCM7xxTimerCtrlState),
646
VMSTATE_STRUCT_ARRAY(timer, NPCM7xxTimerCtrlState,
647
NPCM7XX_TIMERS_PER_CTRL, 0, vmstate_npcm7xx_timer,
648
NPCM7xxTimer),
649
+ VMSTATE_STRUCT(watchdog_timer, NPCM7xxTimerCtrlState,
650
+ 0, vmstate_npcm7xx_watchdog_timer,
651
+ NPCM7xxWatchdogTimer),
652
VMSTATE_END_OF_LIST(),
653
},
654
};
655
diff --git a/tests/qtest/npcm7xx_watchdog_timer-test.c b/tests/qtest/npcm7xx_watchdog_timer-test.c
656
new file mode 100644
657
index XXXXXXX..XXXXXXX
658
--- /dev/null
659
+++ b/tests/qtest/npcm7xx_watchdog_timer-test.c
660
@@ -XXX,XX +XXX,XX @@
661
+/*
662
+ * QTests for Nuvoton NPCM7xx Timer Watchdog Modules.
663
+ *
664
+ * Copyright 2020 Google LLC
665
+ *
666
+ * This program is free software; you can redistribute it and/or modify it
667
+ * under the terms of the GNU General Public License as published by the
668
+ * Free Software Foundation; either version 2 of the License, or
669
+ * (at your option) any later version.
670
+ *
671
+ * This program is distributed in the hope that it will be useful, but WITHOUT
672
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
673
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
674
+ * for more details.
675
+ */
676
+
677
+#include "qemu/osdep.h"
678
+#include "qemu/timer.h"
679
+
680
+#include "libqos/libqtest.h"
681
+#include "qapi/qmp/qdict.h"
682
+
683
+#define WTCR_OFFSET 0x1c
684
+#define REF_HZ (25000000)
685
+
686
+/* WTCR bit fields */
687
+#define WTCLK(rv) ((rv) << 10)
688
+#define WTE BIT(7)
689
+#define WTIE BIT(6)
690
+#define WTIS(rv) ((rv) << 4)
691
+#define WTIF BIT(3)
692
+#define WTRF BIT(2)
693
+#define WTRE BIT(1)
694
+#define WTR BIT(0)
695
+
696
+typedef struct Watchdog {
697
+ int irq;
698
+ uint64_t base_addr;
699
+} Watchdog;
700
+
701
+static const Watchdog watchdog_list[] = {
702
+ {
703
+ .irq = 47,
704
+ .base_addr = 0xf0008000
705
+ },
706
+ {
707
+ .irq = 48,
708
+ .base_addr = 0xf0009000
709
+ },
710
+ {
711
+ .irq = 49,
712
+ .base_addr = 0xf000a000
713
+ }
714
+};
715
+
716
+static int watchdog_index(const Watchdog *wd)
717
+{
718
+ ptrdiff_t diff = wd - watchdog_list;
719
+
720
+ g_assert(diff >= 0 && diff < ARRAY_SIZE(watchdog_list));
721
+
722
+ return diff;
723
+}
724
+
725
+static uint32_t watchdog_read_wtcr(QTestState *qts, const Watchdog *wd)
726
+{
727
+ return qtest_readl(qts, wd->base_addr + WTCR_OFFSET);
728
+}
729
+
730
+static void watchdog_write_wtcr(QTestState *qts, const Watchdog *wd,
731
+ uint32_t value)
732
+{
733
+ qtest_writel(qts, wd->base_addr + WTCR_OFFSET, value);
734
+}
735
+
736
+static uint32_t watchdog_prescaler(QTestState *qts, const Watchdog *wd)
737
+{
738
+ switch (extract32(watchdog_read_wtcr(qts, wd), 10, 2)) {
739
+ case 0:
740
+ return 1;
741
+ case 1:
742
+ return 256;
743
+ case 2:
744
+ return 2048;
745
+ case 3:
746
+ return 65536;
747
+ default:
748
+ g_assert_not_reached();
749
+ }
750
+}
751
+
752
+static QDict *get_watchdog_action(QTestState *qts)
753
+{
754
+ QDict *ev = qtest_qmp_eventwait_ref(qts, "WATCHDOG");
755
+ QDict *data;
756
+
757
+ data = qdict_get_qdict(ev, "data");
758
+ qobject_ref(data);
759
+ qobject_unref(ev);
760
+ return data;
761
+}
762
+
763
+#define RESET_CYCLES 1024
764
+static uint32_t watchdog_interrupt_cycles(QTestState *qts, const Watchdog *wd)
765
+{
766
+ uint32_t wtis = extract32(watchdog_read_wtcr(qts, wd), 4, 2);
767
+ return 1 << (14 + 2 * wtis);
768
+}
769
+
770
+static int64_t watchdog_calculate_steps(uint32_t count, uint32_t prescale)
771
+{
772
+ return (NANOSECONDS_PER_SECOND / REF_HZ) * count * prescale;
773
+}
774
+
775
+static int64_t watchdog_interrupt_steps(QTestState *qts, const Watchdog *wd)
776
+{
777
+ return watchdog_calculate_steps(watchdog_interrupt_cycles(qts, wd),
778
+ watchdog_prescaler(qts, wd));
779
+}
780
+
781
+/* Check wtcr can be reset to default value */
782
+static void test_init(gconstpointer watchdog)
783
+{
784
+ const Watchdog *wd = watchdog;
785
+ QTestState *qts = qtest_init("-machine quanta-gsj");
786
+
787
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
788
+
789
+ watchdog_write_wtcr(qts, wd, WTCLK(1) | WTRF | WTIF | WTR);
790
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(1));
791
+
792
+ qtest_quit(qts);
793
+}
794
+
795
+/* Check a watchdog can generate interrupt and reset actions */
796
+static void test_reset_action(gconstpointer watchdog)
797
+{
798
+ const Watchdog *wd = watchdog;
799
+ QTestState *qts = qtest_init("-machine quanta-gsj");
800
+ QDict *ad;
801
+
802
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
803
+
804
+ watchdog_write_wtcr(qts, wd,
805
+ WTCLK(0) | WTE | WTRF | WTRE | WTIF | WTIE | WTR);
806
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==,
807
+ WTCLK(0) | WTE | WTRE | WTIE);
808
+
809
+ /* Check a watchdog can generate an interrupt */
810
+ qtest_clock_step(qts, watchdog_interrupt_steps(qts, wd));
811
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==,
812
+ WTCLK(0) | WTE | WTIF | WTIE | WTRE);
813
+ g_assert_true(qtest_get_irq(qts, wd->irq));
814
+
815
+ /* Check a watchdog can generate a reset signal */
816
+ qtest_clock_step(qts, watchdog_calculate_steps(RESET_CYCLES,
817
+ watchdog_prescaler(qts, wd)));
818
+ ad = get_watchdog_action(qts);
819
+ /* The signal is a reset signal */
820
+ g_assert_false(strcmp(qdict_get_str(ad, "action"), "reset"));
821
+ qobject_unref(ad);
822
+ qtest_qmp_eventwait(qts, "RESET");
823
+ /*
824
+ * Make sure WTCR is reset to default except for WTRF bit which shouldn't
825
+ * be reset.
826
+ */
827
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(1) | WTRF);
828
+ qtest_quit(qts);
829
+}
830
+
831
+/* Check a watchdog works with all possible WTCLK prescalers and WTIS cycles */
832
+static void test_prescaler(gconstpointer watchdog)
833
+{
834
+ const Watchdog *wd = watchdog;
835
+
836
+ for (int wtclk = 0; wtclk < 4; ++wtclk) {
837
+ for (int wtis = 0; wtis < 4; ++wtis) {
838
+ QTestState *qts = qtest_init("-machine quanta-gsj");
839
+
840
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
841
+ watchdog_write_wtcr(qts, wd,
842
+ WTCLK(wtclk) | WTE | WTIF | WTIS(wtis) | WTIE | WTR);
843
+ /*
844
+ * The interrupt doesn't fire until watchdog_interrupt_steps()
845
+ * cycles passed
846
+ */
847
+ qtest_clock_step(qts, watchdog_interrupt_steps(qts, wd) - 1);
848
+ g_assert_false(watchdog_read_wtcr(qts, wd) & WTIF);
849
+ g_assert_false(qtest_get_irq(qts, wd->irq));
850
+ qtest_clock_step(qts, 1);
851
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
852
+ g_assert_true(qtest_get_irq(qts, wd->irq));
853
+
854
+ qtest_quit(qts);
855
+ }
856
+ }
857
+}
858
+
859
+/*
860
+ * Check a watchdog doesn't fire if corresponding flags (WTIE and WTRE) are not
861
+ * set.
862
+ */
863
+static void test_enabling_flags(gconstpointer watchdog)
864
+{
865
+ const Watchdog *wd = watchdog;
866
+ QTestState *qts;
867
+
868
+ /* Neither WTIE or WTRE is set, no interrupt or reset should happen */
869
+ qts = qtest_init("-machine quanta-gsj");
870
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
871
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTE | WTIF | WTRF | WTR);
872
+ qtest_clock_step(qts, watchdog_interrupt_steps(qts, wd));
873
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
874
+ g_assert_false(qtest_get_irq(qts, wd->irq));
875
+ qtest_clock_step(qts, watchdog_calculate_steps(RESET_CYCLES,
876
+ watchdog_prescaler(qts, wd)));
877
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
878
+ g_assert_false(watchdog_read_wtcr(qts, wd) & WTRF);
879
+ qtest_quit(qts);
880
+
881
+ /* Only WTIE is set, interrupt is triggered but reset should not happen */
882
+ qts = qtest_init("-machine quanta-gsj");
883
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
884
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTE | WTIF | WTIE | WTRF | WTR);
885
+ qtest_clock_step(qts, watchdog_interrupt_steps(qts, wd));
886
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
887
+ g_assert_true(qtest_get_irq(qts, wd->irq));
888
+ qtest_clock_step(qts, watchdog_calculate_steps(RESET_CYCLES,
889
+ watchdog_prescaler(qts, wd)));
890
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
891
+ g_assert_false(watchdog_read_wtcr(qts, wd) & WTRF);
892
+ qtest_quit(qts);
893
+
894
+ /* Only WTRE is set, interrupt is triggered but reset should not happen */
895
+ qts = qtest_init("-machine quanta-gsj");
896
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
897
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTE | WTIF | WTRE | WTRF | WTR);
898
+ qtest_clock_step(qts, watchdog_interrupt_steps(qts, wd));
899
+ g_assert_true(watchdog_read_wtcr(qts, wd) & WTIF);
900
+ g_assert_false(qtest_get_irq(qts, wd->irq));
901
+ qtest_clock_step(qts, watchdog_calculate_steps(RESET_CYCLES,
902
+ watchdog_prescaler(qts, wd)));
903
+ g_assert_false(strcmp(qdict_get_str(get_watchdog_action(qts), "action"),
904
+ "reset"));
905
+ qtest_qmp_eventwait(qts, "RESET");
906
+ qtest_quit(qts);
907
+
908
+ /*
909
+ * The case when both flags are set is already tested in
910
+ * test_reset_action().
911
+ */
912
+}
913
+
914
+/* Check a watchdog can pause and resume by setting WTE bits */
915
+static void test_pause(gconstpointer watchdog)
916
+{
917
+ const Watchdog *wd = watchdog;
918
+ QTestState *qts;
919
+ int64_t remaining_steps, steps;
920
+
921
+ qts = qtest_init("-machine quanta-gsj");
922
+ qtest_irq_intercept_in(qts, "/machine/soc/a9mpcore/gic");
923
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTE | WTIF | WTIE | WTRF | WTR);
924
+ remaining_steps = watchdog_interrupt_steps(qts, wd);
925
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(0) | WTE | WTIE);
926
+
927
+ /* Run for half of the execution period. */
928
+ steps = remaining_steps / 2;
929
+ remaining_steps -= steps;
930
+ qtest_clock_step(qts, steps);
931
+
932
+ /* Pause the watchdog */
933
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTIE);
934
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(0) | WTIE);
935
+
936
+ /* Run for a long period of time, the watchdog shouldn't fire */
937
+ qtest_clock_step(qts, steps << 4);
938
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(0) | WTIE);
939
+ g_assert_false(qtest_get_irq(qts, wd->irq));
940
+
941
+ /* Resume the watchdog */
942
+ watchdog_write_wtcr(qts, wd, WTCLK(0) | WTE | WTIE);
943
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==, WTCLK(0) | WTE | WTIE);
944
+
945
+ /* Run for the reset of the execution period, the watchdog should fire */
946
+ qtest_clock_step(qts, remaining_steps);
947
+ g_assert_cmphex(watchdog_read_wtcr(qts, wd), ==,
948
+ WTCLK(0) | WTE | WTIF | WTIE);
949
+ g_assert_true(qtest_get_irq(qts, wd->irq));
950
+
951
+ qtest_quit(qts);
952
+}
953
+
954
+static void watchdog_add_test(const char *name, const Watchdog* wd,
955
+ GTestDataFunc fn)
956
+{
957
+ g_autofree char *full_name = g_strdup_printf(
958
+ "npcm7xx_watchdog_timer[%d]/%s", watchdog_index(wd), name);
959
+ qtest_add_data_func(full_name, wd, fn);
960
+}
961
+#define add_test(name, td) watchdog_add_test(#name, td, test_##name)
962
+
963
+int main(int argc, char **argv)
964
+{
965
+ g_test_init(&argc, &argv, NULL);
966
+ g_test_set_nonfatal_assertions();
967
+
968
+ for (int i = 0; i < ARRAY_SIZE(watchdog_list); ++i) {
969
+ const Watchdog *wd = &watchdog_list[i];
970
+
971
+ add_test(init, wd);
972
+ add_test(reset_action, wd);
973
+ add_test(prescaler, wd);
974
+ add_test(enabling_flags, wd);
975
+ add_test(pause, wd);
976
+ }
977
+
978
+ return g_test_run();
979
+}
980
diff --git a/MAINTAINERS b/MAINTAINERS
141
index XXXXXXX..XXXXXXX 100644
981
index XXXXXXX..XXXXXXX 100644
142
--- a/hw/misc/bcm2835_property.c
982
--- a/MAINTAINERS
143
+++ b/hw/misc/bcm2835_property.c
983
+++ b/MAINTAINERS
144
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
984
@@ -XXX,XX +XXX,XX @@ L: qemu-arm@nongnu.org
145
case 0x00040002: /* Blank screen */
985
S: Supported
146
resplen = 4;
986
F: hw/*/npcm7xx*
147
break;
987
F: include/hw/*/npcm7xx*
148
- case 0x00040003: /* Get display width/height */
988
+F: tests/qtest/npcm7xx*
149
- case 0x00040004:
989
F: pc-bios/npcm7xx_bootrom.bin
150
+ case 0x00040003: /* Get physical display width/height */
990
F: roms/vbootrom
151
stl_le_phys(&s->dma_as, value + 12, fbconfig.xres);
991
152
stl_le_phys(&s->dma_as, value + 16, fbconfig.yres);
992
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
153
resplen = 8;
993
index XXXXXXX..XXXXXXX 100644
154
break;
994
--- a/tests/qtest/meson.build
155
- case 0x00044003: /* Test display width/height */
995
+++ b/tests/qtest/meson.build
156
- case 0x00044004:
996
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
157
+ case 0x00040004: /* Get virtual display width/height */
997
(config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) + \
158
+ stl_le_phys(&s->dma_as, value + 12, fbconfig.xres_virtual);
998
['prom-env-test', 'boot-serial-test']
159
+ stl_le_phys(&s->dma_as, value + 16, fbconfig.yres_virtual);
999
160
resplen = 8;
1000
-qtests_npcm7xx = ['npcm7xx_timer-test']
161
break;
1001
+qtests_npcm7xx = ['npcm7xx_timer-test', 'npcm7xx_watchdog_timer-test']
162
- case 0x00048003: /* Set display width/height */
1002
qtests_arm = \
163
- case 0x00048004:
1003
(config_all_devices.has_key('CONFIG_PFLASH_CFI02') ? ['pflash-cfi02-test'] : []) + \
164
+ case 0x00044003: /* Test physical display width/height */
1004
(config_all_devices.has_key('CONFIG_NPCM7XX') ? qtests_npcm7xx : []) + \
165
+ case 0x00044004: /* Test virtual display width/height */
166
+ resplen = 8;
167
+ break;
168
+ case 0x00048003: /* Set physical display width/height */
169
fbconfig.xres = ldl_le_phys(&s->dma_as, value + 12);
170
fbconfig.yres = ldl_le_phys(&s->dma_as, value + 16);
171
fbconfig_updated = true;
172
resplen = 8;
173
break;
174
+ case 0x00048004: /* Set virtual display width/height */
175
+ fbconfig.xres_virtual = ldl_le_phys(&s->dma_as, value + 12);
176
+ fbconfig.yres_virtual = ldl_le_phys(&s->dma_as, value + 16);
177
+ fbconfig_updated = true;
178
+ resplen = 8;
179
+ break;
180
case 0x00040005: /* Get depth */
181
stl_le_phys(&s->dma_as, value + 12, fbconfig.bpp);
182
resplen = 4;
183
--
1005
--
184
2.18.0
1006
2.20.1
185
1007
186
1008
diff view generated by jsdifflib
1
Implement the IoTKit system control element's system information
1
From: Havard Skinnemoen <hskinnemoen@google.com>
2
block; this is just a pair of read-only version/config registers,
3
plus the usual PID/CID ID registers.
4
2
3
The RNG module returns a byte of randomness when the Data Valid bit is
4
set.
5
6
This implementation ignores the prescaler setting, and loads a new value
7
into RNGD every time RNGCS is read while the RNG is enabled and random
8
data is available.
9
10
A qtest featuring some simple randomness tests is included.
11
12
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
13
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
14
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20180820141116.9118-10-peter.maydell@linaro.org
9
---
16
---
10
hw/misc/Makefile.objs | 1 +
17
docs/system/arm/nuvoton.rst | 2 +-
11
include/hw/misc/iotkit-sysinfo.h | 37 +++++++++
18
include/hw/arm/npcm7xx.h | 2 +
12
hw/misc/iotkit-sysinfo.c | 128 +++++++++++++++++++++++++++++++
19
include/hw/misc/npcm7xx_rng.h | 34 ++++
13
MAINTAINERS | 2 +
20
hw/arm/npcm7xx.c | 7 +-
14
default-configs/arm-softmmu.mak | 1 +
21
hw/misc/npcm7xx_rng.c | 180 +++++++++++++++++++++
15
5 files changed, 169 insertions(+)
22
tests/qtest/npcm7xx_rng-test.c | 278 +++++++++++++++++++++++++++++++++
16
create mode 100644 include/hw/misc/iotkit-sysinfo.h
23
hw/misc/meson.build | 1 +
17
create mode 100644 hw/misc/iotkit-sysinfo.c
24
hw/misc/trace-events | 4 +
25
tests/qtest/meson.build | 5 +-
26
9 files changed, 510 insertions(+), 3 deletions(-)
27
create mode 100644 include/hw/misc/npcm7xx_rng.h
28
create mode 100644 hw/misc/npcm7xx_rng.c
29
create mode 100644 tests/qtest/npcm7xx_rng-test.c
18
30
19
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
31
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
20
index XXXXXXX..XXXXXXX 100644
32
index XXXXXXX..XXXXXXX 100644
21
--- a/hw/misc/Makefile.objs
33
--- a/docs/system/arm/nuvoton.rst
22
+++ b/hw/misc/Makefile.objs
34
+++ b/docs/system/arm/nuvoton.rst
23
@@ -XXX,XX +XXX,XX @@ obj-$(CONFIG_TZ_MPC) += tz-mpc.o
35
@@ -XXX,XX +XXX,XX @@ Supported devices
24
obj-$(CONFIG_TZ_PPC) += tz-ppc.o
36
* DDR4 memory controller (dummy interface indicating memory training is done)
25
obj-$(CONFIG_IOTKIT_SECCTL) += iotkit-secctl.o
37
* OTP controllers (no protection features)
26
obj-$(CONFIG_IOTKIT_SYSCTL) += iotkit-sysctl.o
38
* Flash Interface Unit (FIU; no protection features)
27
+obj-$(CONFIG_IOTKIT_SYSINFO) += iotkit-sysinfo.o
39
+ * Random Number Generator (RNG)
28
40
29
obj-$(CONFIG_PVPANIC) += pvpanic.o
41
Missing devices
30
obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o
42
---------------
31
diff --git a/include/hw/misc/iotkit-sysinfo.h b/include/hw/misc/iotkit-sysinfo.h
43
@@ -XXX,XX +XXX,XX @@ Missing devices
44
* Peripheral SPI controller (PSPI)
45
* Analog to Digital Converter (ADC)
46
* SD/MMC host
47
- * Random Number Generator (RNG)
48
* PECI interface
49
* Pulse Width Modulation (PWM)
50
* Tachometer
51
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
52
index XXXXXXX..XXXXXXX 100644
53
--- a/include/hw/arm/npcm7xx.h
54
+++ b/include/hw/arm/npcm7xx.h
55
@@ -XXX,XX +XXX,XX @@
56
#include "hw/mem/npcm7xx_mc.h"
57
#include "hw/misc/npcm7xx_clk.h"
58
#include "hw/misc/npcm7xx_gcr.h"
59
+#include "hw/misc/npcm7xx_rng.h"
60
#include "hw/nvram/npcm7xx_otp.h"
61
#include "hw/timer/npcm7xx_timer.h"
62
#include "hw/ssi/npcm7xx_fiu.h"
63
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
64
NPCM7xxOTPState key_storage;
65
NPCM7xxOTPState fuse_array;
66
NPCM7xxMCState mc;
67
+ NPCM7xxRNGState rng;
68
NPCM7xxFIUState fiu[2];
69
} NPCM7xxState;
70
71
diff --git a/include/hw/misc/npcm7xx_rng.h b/include/hw/misc/npcm7xx_rng.h
32
new file mode 100644
72
new file mode 100644
33
index XXXXXXX..XXXXXXX
73
index XXXXXXX..XXXXXXX
34
--- /dev/null
74
--- /dev/null
35
+++ b/include/hw/misc/iotkit-sysinfo.h
75
+++ b/include/hw/misc/npcm7xx_rng.h
36
@@ -XXX,XX +XXX,XX @@
76
@@ -XXX,XX +XXX,XX @@
37
+/*
77
+/*
38
+ * ARM IoTKit system information block
78
+ * Nuvoton NPCM7xx Random Number Generator.
39
+ *
79
+ *
40
+ * Copyright (c) 2018 Linaro Limited
80
+ * Copyright 2020 Google LLC
41
+ * Written by Peter Maydell
81
+ *
42
+ *
82
+ * This program is free software; you can redistribute it and/or modify it
43
+ * This program is free software; you can redistribute it and/or modify
83
+ * under the terms of the GNU General Public License as published by the
44
+ * it under the terms of the GNU General Public License version 2 or
84
+ * Free Software Foundation; either version 2 of the License, or
45
+ * (at your option) any later version.
85
+ * (at your option) any later version.
46
+ */
86
+ *
47
+
87
+ * This program is distributed in the hope that it will be useful, but WITHOUT
48
+/*
88
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
49
+ * This is a model of the "system information block" which is part of the
89
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
50
+ * Arm IoTKit and documented in
90
+ * for more details.
51
+ * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
91
+ */
52
+ * QEMU interface:
92
+#ifndef NPCM7XX_RNG_H
53
+ * + sysbus MMIO region 0: the system information register bank
93
+#define NPCM7XX_RNG_H
54
+ */
55
+
56
+#ifndef HW_MISC_IOTKIT_SYSINFO_H
57
+#define HW_MISC_IOTKIT_SYSINFO_H
58
+
94
+
59
+#include "hw/sysbus.h"
95
+#include "hw/sysbus.h"
60
+
96
+
61
+#define TYPE_IOTKIT_SYSINFO "iotkit-sysinfo"
97
+typedef struct NPCM7xxRNGState {
62
+#define IOTKIT_SYSINFO(obj) OBJECT_CHECK(IoTKitSysInfo, (obj), \
98
+ SysBusDevice parent;
63
+ TYPE_IOTKIT_SYSINFO)
99
+
64
+
65
+typedef struct IoTKitSysInfo {
66
+ /*< private >*/
67
+ SysBusDevice parent_obj;
68
+
69
+ /*< public >*/
70
+ MemoryRegion iomem;
100
+ MemoryRegion iomem;
71
+} IoTKitSysInfo;
101
+
72
+
102
+ uint8_t rngcs;
73
+#endif
103
+ uint8_t rngd;
74
diff --git a/hw/misc/iotkit-sysinfo.c b/hw/misc/iotkit-sysinfo.c
104
+ uint8_t rngmode;
105
+} NPCM7xxRNGState;
106
+
107
+#define TYPE_NPCM7XX_RNG "npcm7xx-rng"
108
+#define NPCM7XX_RNG(obj) OBJECT_CHECK(NPCM7xxRNGState, (obj), TYPE_NPCM7XX_RNG)
109
+
110
+#endif /* NPCM7XX_RNG_H */
111
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
112
index XXXXXXX..XXXXXXX 100644
113
--- a/hw/arm/npcm7xx.c
114
+++ b/hw/arm/npcm7xx.c
115
@@ -XXX,XX +XXX,XX @@
116
#define NPCM7XX_GCR_BA (0xf0800000)
117
#define NPCM7XX_CLK_BA (0xf0801000)
118
#define NPCM7XX_MC_BA (0xf0824000)
119
+#define NPCM7XX_RNG_BA (0xf000b000)
120
121
/* Internal AHB SRAM */
122
#define NPCM7XX_RAM3_BA (0xc0008000)
123
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
124
object_initialize_child(obj, "otp2", &s->fuse_array,
125
TYPE_NPCM7XX_FUSE_ARRAY);
126
object_initialize_child(obj, "mc", &s->mc, TYPE_NPCM7XX_MC);
127
+ object_initialize_child(obj, "rng", &s->rng, TYPE_NPCM7XX_RNG);
128
129
for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
130
object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
131
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
132
serial_hd(i), DEVICE_LITTLE_ENDIAN);
133
}
134
135
+ /* Random Number Generator. Cannot fail. */
136
+ sysbus_realize(SYS_BUS_DEVICE(&s->rng), &error_abort);
137
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->rng), 0, NPCM7XX_RNG_BA);
138
+
139
/*
140
* Flash Interface Unit (FIU). Can fail if incorrect number of chip selects
141
* specified, but this is a programming error.
142
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
143
create_unimplemented_device("npcm7xx.vdmx", 0xe0800000, 4 * KiB);
144
create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB);
145
create_unimplemented_device("npcm7xx.kcs", 0xf0007000, 4 * KiB);
146
- create_unimplemented_device("npcm7xx.rng", 0xf000b000, 4 * KiB);
147
create_unimplemented_device("npcm7xx.adc", 0xf000c000, 4 * KiB);
148
create_unimplemented_device("npcm7xx.gfxi", 0xf000e000, 4 * KiB);
149
create_unimplemented_device("npcm7xx.gpio[0]", 0xf0010000, 4 * KiB);
150
diff --git a/hw/misc/npcm7xx_rng.c b/hw/misc/npcm7xx_rng.c
75
new file mode 100644
151
new file mode 100644
76
index XXXXXXX..XXXXXXX
152
index XXXXXXX..XXXXXXX
77
--- /dev/null
153
--- /dev/null
78
+++ b/hw/misc/iotkit-sysinfo.c
154
+++ b/hw/misc/npcm7xx_rng.c
79
@@ -XXX,XX +XXX,XX @@
155
@@ -XXX,XX +XXX,XX @@
80
+/*
156
+/*
81
+ * ARM IoTKit system information block
157
+ * Nuvoton NPCM7xx Random Number Generator.
82
+ *
158
+ *
83
+ * Copyright (c) 2018 Linaro Limited
159
+ * Copyright 2020 Google LLC
84
+ * Written by Peter Maydell
160
+ *
85
+ *
161
+ * This program is free software; you can redistribute it and/or modify it
86
+ * This program is free software; you can redistribute it and/or modify
162
+ * under the terms of the GNU General Public License as published by the
87
+ * it under the terms of the GNU General Public License version 2 or
163
+ * Free Software Foundation; either version 2 of the License, or
88
+ * (at your option) any later version.
164
+ * (at your option) any later version.
89
+ */
165
+ *
90
+
166
+ * This program is distributed in the hope that it will be useful, but WITHOUT
91
+/*
167
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
92
+ * This is a model of the "system information block" which is part of the
168
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
93
+ * Arm IoTKit and documented in
169
+ * for more details.
94
+ * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
95
+ * It consists of 2 read-only version/config registers, plus the
96
+ * usual ID registers.
97
+ */
170
+ */
98
+
171
+
99
+#include "qemu/osdep.h"
172
+#include "qemu/osdep.h"
173
+
174
+#include "hw/misc/npcm7xx_rng.h"
175
+#include "migration/vmstate.h"
176
+#include "qemu/bitops.h"
177
+#include "qemu/guest-random.h"
100
+#include "qemu/log.h"
178
+#include "qemu/log.h"
179
+#include "qemu/module.h"
180
+#include "qemu/units.h"
181
+
101
+#include "trace.h"
182
+#include "trace.h"
102
+#include "qapi/error.h"
183
+
103
+#include "sysemu/sysemu.h"
184
+#define NPCM7XX_RNG_REGS_SIZE (4 * KiB)
104
+#include "hw/sysbus.h"
185
+
105
+#include "hw/registerfields.h"
186
+#define NPCM7XX_RNGCS (0x00)
106
+#include "hw/misc/iotkit-sysinfo.h"
187
+#define NPCM7XX_RNGCS_CLKP(rv) extract32(rv, 2, 4)
107
+
188
+#define NPCM7XX_RNGCS_DVALID BIT(1)
108
+REG32(SYS_VERSION, 0x0)
189
+#define NPCM7XX_RNGCS_RNGE BIT(0)
109
+REG32(SYS_CONFIG, 0x4)
190
+
110
+REG32(PID4, 0xfd0)
191
+#define NPCM7XX_RNGD (0x04)
111
+REG32(PID5, 0xfd4)
192
+#define NPCM7XX_RNGMODE (0x08)
112
+REG32(PID6, 0xfd8)
193
+#define NPCM7XX_RNGMODE_NORMAL (0x02)
113
+REG32(PID7, 0xfdc)
194
+
114
+REG32(PID0, 0xfe0)
195
+static bool npcm7xx_rng_is_enabled(NPCM7xxRNGState *s)
115
+REG32(PID1, 0xfe4)
196
+{
116
+REG32(PID2, 0xfe8)
197
+ return (s->rngcs & NPCM7XX_RNGCS_RNGE) &&
117
+REG32(PID3, 0xfec)
198
+ (s->rngmode == NPCM7XX_RNGMODE_NORMAL);
118
+REG32(CID0, 0xff0)
199
+}
119
+REG32(CID1, 0xff4)
200
+
120
+REG32(CID2, 0xff8)
201
+static uint64_t npcm7xx_rng_read(void *opaque, hwaddr offset, unsigned size)
121
+REG32(CID3, 0xffc)
202
+{
122
+
203
+ NPCM7xxRNGState *s = opaque;
123
+/* PID/CID values */
204
+ uint64_t value = 0;
124
+static const int sysinfo_id[] = {
125
+ 0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
126
+ 0x58, 0xb8, 0x0b, 0x00, /* PID0..PID3 */
127
+ 0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
128
+};
129
+
130
+static uint64_t iotkit_sysinfo_read(void *opaque, hwaddr offset,
131
+ unsigned size)
132
+{
133
+ uint64_t r;
134
+
205
+
135
+ switch (offset) {
206
+ switch (offset) {
136
+ case A_SYS_VERSION:
207
+ case NPCM7XX_RNGCS:
137
+ r = 0x41743;
208
+ /*
138
+ break;
209
+ * If the RNG is enabled, but we don't have any valid random data, try
139
+
210
+ * obtaining some and update the DVALID bit accordingly.
140
+ case A_SYS_CONFIG:
211
+ */
141
+ r = 0x31;
212
+ if (!npcm7xx_rng_is_enabled(s)) {
142
+ break;
213
+ s->rngcs &= ~NPCM7XX_RNGCS_DVALID;
143
+ case A_PID4 ... A_CID3:
214
+ } else if (!(s->rngcs & NPCM7XX_RNGCS_DVALID)) {
144
+ r = sysinfo_id[(offset - A_PID4) / 4];
215
+ uint8_t byte = 0;
145
+ break;
216
+
217
+ if (qemu_guest_getrandom(&byte, sizeof(byte), NULL) == 0) {
218
+ s->rngd = byte;
219
+ s->rngcs |= NPCM7XX_RNGCS_DVALID;
220
+ }
221
+ }
222
+ value = s->rngcs;
223
+ break;
224
+ case NPCM7XX_RNGD:
225
+ if (npcm7xx_rng_is_enabled(s) && s->rngcs & NPCM7XX_RNGCS_DVALID) {
226
+ s->rngcs &= ~NPCM7XX_RNGCS_DVALID;
227
+ value = s->rngd;
228
+ s->rngd = 0;
229
+ }
230
+ break;
231
+ case NPCM7XX_RNGMODE:
232
+ value = s->rngmode;
233
+ break;
234
+
146
+ default:
235
+ default:
147
+ qemu_log_mask(LOG_GUEST_ERROR,
236
+ qemu_log_mask(LOG_GUEST_ERROR,
148
+ "IoTKit SysInfo read: bad offset %x\n", (int)offset);
237
+ "%s: read from invalid offset 0x%" HWADDR_PRIx "\n",
149
+ r = 0;
238
+ DEVICE(s)->canonical_path, offset);
150
+ break;
239
+ break;
151
+ }
240
+ }
152
+ trace_iotkit_sysinfo_read(offset, r, size);
241
+
153
+ return r;
242
+ trace_npcm7xx_rng_read(offset, value, size);
154
+}
243
+
155
+
244
+ return value;
156
+static void iotkit_sysinfo_write(void *opaque, hwaddr offset,
245
+}
157
+ uint64_t value, unsigned size)
246
+
158
+{
247
+static void npcm7xx_rng_write(void *opaque, hwaddr offset, uint64_t value,
159
+ trace_iotkit_sysinfo_write(offset, value, size);
248
+ unsigned size)
160
+
249
+{
161
+ qemu_log_mask(LOG_GUEST_ERROR,
250
+ NPCM7xxRNGState *s = opaque;
162
+ "IoTKit SysInfo: write to RO offset 0x%x\n", (int)offset);
251
+
163
+}
252
+ trace_npcm7xx_rng_write(offset, value, size);
164
+
253
+
165
+static const MemoryRegionOps iotkit_sysinfo_ops = {
254
+ switch (offset) {
166
+ .read = iotkit_sysinfo_read,
255
+ case NPCM7XX_RNGCS:
167
+ .write = iotkit_sysinfo_write,
256
+ s->rngcs &= NPCM7XX_RNGCS_DVALID;
257
+ s->rngcs |= value & ~NPCM7XX_RNGCS_DVALID;
258
+ break;
259
+ case NPCM7XX_RNGD:
260
+ qemu_log_mask(LOG_GUEST_ERROR,
261
+ "%s: write to read-only register @ 0x%" HWADDR_PRIx "\n",
262
+ DEVICE(s)->canonical_path, offset);
263
+ break;
264
+ case NPCM7XX_RNGMODE:
265
+ s->rngmode = value;
266
+ break;
267
+ default:
268
+ qemu_log_mask(LOG_GUEST_ERROR,
269
+ "%s: write to invalid offset 0x%" HWADDR_PRIx "\n",
270
+ DEVICE(s)->canonical_path, offset);
271
+ break;
272
+ }
273
+}
274
+
275
+static const MemoryRegionOps npcm7xx_rng_ops = {
276
+ .read = npcm7xx_rng_read,
277
+ .write = npcm7xx_rng_write,
168
+ .endianness = DEVICE_LITTLE_ENDIAN,
278
+ .endianness = DEVICE_LITTLE_ENDIAN,
169
+ /* byte/halfword accesses are just zero-padded on reads and writes */
279
+ .valid = {
170
+ .impl.min_access_size = 4,
280
+ .min_access_size = 1,
171
+ .impl.max_access_size = 4,
281
+ .max_access_size = 4,
172
+ .valid.min_access_size = 1,
282
+ .unaligned = false,
173
+ .valid.max_access_size = 4,
283
+ },
174
+};
284
+};
175
+
285
+
176
+static void iotkit_sysinfo_init(Object *obj)
286
+static void npcm7xx_rng_enter_reset(Object *obj, ResetType type)
177
+{
287
+{
178
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
288
+ NPCM7xxRNGState *s = NPCM7XX_RNG(obj);
179
+ IoTKitSysInfo *s = IOTKIT_SYSINFO(obj);
289
+
180
+
290
+ s->rngcs = 0;
181
+ memory_region_init_io(&s->iomem, obj, &iotkit_sysinfo_ops,
291
+ s->rngd = 0;
182
+ s, "iotkit-sysinfo", 0x1000);
292
+ s->rngmode = 0;
183
+ sysbus_init_mmio(sbd, &s->iomem);
293
+}
184
+}
294
+
185
+
295
+static void npcm7xx_rng_init(Object *obj)
186
+static void iotkit_sysinfo_class_init(ObjectClass *klass, void *data)
296
+{
187
+{
297
+ NPCM7xxRNGState *s = NPCM7XX_RNG(obj);
188
+ /*
298
+
189
+ * This device has no guest-modifiable state and so it
299
+ memory_region_init_io(&s->iomem, obj, &npcm7xx_rng_ops, s, "regs",
190
+ * does not need a reset function or VMState.
300
+ NPCM7XX_RNG_REGS_SIZE);
191
+ */
301
+ sysbus_init_mmio(&s->parent, &s->iomem);
192
+}
302
+}
193
+
303
+
194
+static const TypeInfo iotkit_sysinfo_info = {
304
+static const VMStateDescription vmstate_npcm7xx_rng = {
195
+ .name = TYPE_IOTKIT_SYSINFO,
305
+ .name = "npcm7xx-rng",
196
+ .parent = TYPE_SYS_BUS_DEVICE,
306
+ .version_id = 0,
197
+ .instance_size = sizeof(IoTKitSysInfo),
307
+ .minimum_version_id = 0,
198
+ .instance_init = iotkit_sysinfo_init,
308
+ .fields = (VMStateField[]) {
199
+ .class_init = iotkit_sysinfo_class_init,
309
+ VMSTATE_UINT8(rngcs, NPCM7xxRNGState),
310
+ VMSTATE_UINT8(rngd, NPCM7xxRNGState),
311
+ VMSTATE_UINT8(rngmode, NPCM7xxRNGState),
312
+ VMSTATE_END_OF_LIST(),
313
+ },
200
+};
314
+};
201
+
315
+
202
+static void iotkit_sysinfo_register_types(void)
316
+static void npcm7xx_rng_class_init(ObjectClass *klass, void *data)
203
+{
317
+{
204
+ type_register_static(&iotkit_sysinfo_info);
318
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
205
+}
319
+ DeviceClass *dc = DEVICE_CLASS(klass);
206
+
320
+
207
+type_init(iotkit_sysinfo_register_types);
321
+ dc->desc = "NPCM7xx Random Number Generator";
208
diff --git a/MAINTAINERS b/MAINTAINERS
322
+ dc->vmsd = &vmstate_npcm7xx_rng;
323
+ rc->phases.enter = npcm7xx_rng_enter_reset;
324
+}
325
+
326
+static const TypeInfo npcm7xx_rng_types[] = {
327
+ {
328
+ .name = TYPE_NPCM7XX_RNG,
329
+ .parent = TYPE_SYS_BUS_DEVICE,
330
+ .instance_size = sizeof(NPCM7xxRNGState),
331
+ .class_init = npcm7xx_rng_class_init,
332
+ .instance_init = npcm7xx_rng_init,
333
+ },
334
+};
335
+DEFINE_TYPES(npcm7xx_rng_types);
336
diff --git a/tests/qtest/npcm7xx_rng-test.c b/tests/qtest/npcm7xx_rng-test.c
337
new file mode 100644
338
index XXXXXXX..XXXXXXX
339
--- /dev/null
340
+++ b/tests/qtest/npcm7xx_rng-test.c
341
@@ -XXX,XX +XXX,XX @@
342
+/*
343
+ * QTest testcase for the Nuvoton NPCM7xx Random Number Generator
344
+ *
345
+ * Copyright 2020 Google LLC
346
+ *
347
+ * This program is free software; you can redistribute it and/or modify it
348
+ * under the terms of the GNU General Public License as published by the
349
+ * Free Software Foundation; either version 2 of the License, or
350
+ * (at your option) any later version.
351
+ *
352
+ * This program is distributed in the hope that it will be useful, but WITHOUT
353
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
354
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
355
+ * for more details.
356
+ */
357
+
358
+#include "qemu/osdep.h"
359
+
360
+#include <math.h>
361
+
362
+#include "libqtest-single.h"
363
+#include "qemu/bitops.h"
364
+
365
+#define RNG_BASE_ADDR 0xf000b000
366
+
367
+/* Control and Status Register */
368
+#define RNGCS 0x00
369
+# define DVALID BIT(1) /* Data Valid */
370
+# define RNGE BIT(0) /* RNG Enable */
371
+/* Data Register */
372
+#define RNGD 0x04
373
+/* Mode Register */
374
+#define RNGMODE 0x08
375
+# define ROSEL_NORMAL (2) /* RNG only works in this mode */
376
+
377
+/* Number of bits to collect for randomness tests. */
378
+#define TEST_INPUT_BITS (128)
379
+
380
+static void rng_writeb(unsigned int offset, uint8_t value)
381
+{
382
+ writeb(RNG_BASE_ADDR + offset, value);
383
+}
384
+
385
+static uint8_t rng_readb(unsigned int offset)
386
+{
387
+ return readb(RNG_BASE_ADDR + offset);
388
+}
389
+
390
+/* Disable RNG and set normal ring oscillator mode. */
391
+static void rng_reset(void)
392
+{
393
+ rng_writeb(RNGCS, 0);
394
+ rng_writeb(RNGMODE, ROSEL_NORMAL);
395
+}
396
+
397
+/* Reset RNG and then enable it. */
398
+static void rng_reset_enable(void)
399
+{
400
+ rng_reset();
401
+ rng_writeb(RNGCS, RNGE);
402
+}
403
+
404
+/* Wait until Data Valid bit is set. */
405
+static bool rng_wait_ready(void)
406
+{
407
+ /* qemu_guest_getrandom may fail. Assume it won't fail 10 times in a row. */
408
+ int retries = 10;
409
+
410
+ while (retries-- > 0) {
411
+ if (rng_readb(RNGCS) & DVALID) {
412
+ return true;
413
+ }
414
+ }
415
+
416
+ return false;
417
+}
418
+
419
+/*
420
+ * Perform a frequency (monobit) test, as defined by NIST SP 800-22, on the
421
+ * sequence in buf and return the P-value. This represents the probability of a
422
+ * truly random sequence having the same proportion of zeros and ones as the
423
+ * sequence in buf.
424
+ *
425
+ * An RNG which always returns 0x00 or 0xff, or has some bits stuck at 0 or 1,
426
+ * will fail this test. However, an RNG which always returns 0x55, 0xf0 or some
427
+ * other value with an equal number of zeroes and ones will pass.
428
+ */
429
+static double calc_monobit_p(const uint8_t *buf, unsigned int len)
430
+{
431
+ unsigned int i;
432
+ double s_obs;
433
+ int sn = 0;
434
+
435
+ for (i = 0; i < len; i++) {
436
+ /*
437
+ * Each 1 counts as 1, each 0 counts as -1.
438
+ * s = cp - (8 - cp) = 2 * cp - 8
439
+ */
440
+ sn += 2 * ctpop8(buf[i]) - 8;
441
+ }
442
+
443
+ s_obs = abs(sn) / sqrt(len * BITS_PER_BYTE);
444
+
445
+ return erfc(s_obs / sqrt(2));
446
+}
447
+
448
+/*
449
+ * Perform a runs test, as defined by NIST SP 800-22, and return the P-value.
450
+ * This represents the probability of a truly random sequence having the same
451
+ * number of runs (i.e. uninterrupted sequences of identical bits) as the
452
+ * sequence in buf.
453
+ */
454
+static double calc_runs_p(const unsigned long *buf, unsigned int nr_bits)
455
+{
456
+ unsigned int j;
457
+ unsigned int k;
458
+ int nr_ones = 0;
459
+ int vn_obs = 0;
460
+ double pi;
461
+
462
+ g_assert(nr_bits % BITS_PER_LONG == 0);
463
+
464
+ for (j = 0; j < nr_bits / BITS_PER_LONG; j++) {
465
+ nr_ones += __builtin_popcountl(buf[j]);
466
+ }
467
+ pi = (double)nr_ones / nr_bits;
468
+
469
+ for (k = 0; k < nr_bits - 1; k++) {
470
+ vn_obs += !(test_bit(k, buf) ^ test_bit(k + 1, buf));
471
+ }
472
+ vn_obs += 1;
473
+
474
+ return erfc(fabs(vn_obs - 2 * nr_bits * pi * (1.0 - pi))
475
+ / (2 * sqrt(2 * nr_bits) * pi * (1.0 - pi)));
476
+}
477
+
478
+/*
479
+ * Verifies that DVALID is clear, and RNGD reads zero, when RNGE is cleared,
480
+ * and DVALID eventually becomes set when RNGE is set.
481
+ */
482
+static void test_enable_disable(void)
483
+{
484
+ /* Disable: DVALID should not be set, and RNGD should read zero */
485
+ rng_reset();
486
+ g_assert_cmphex(rng_readb(RNGCS), ==, 0);
487
+ g_assert_cmphex(rng_readb(RNGD), ==, 0);
488
+
489
+ /* Enable: DVALID should be set, but we can't make assumptions about RNGD */
490
+ rng_writeb(RNGCS, RNGE);
491
+ g_assert_true(rng_wait_ready());
492
+ g_assert_cmphex(rng_readb(RNGCS), ==, DVALID | RNGE);
493
+
494
+ /* Disable: DVALID should not be set, and RNGD should read zero */
495
+ rng_writeb(RNGCS, 0);
496
+ g_assert_cmphex(rng_readb(RNGCS), ==, 0);
497
+ g_assert_cmphex(rng_readb(RNGD), ==, 0);
498
+}
499
+
500
+/*
501
+ * Verifies that the RNG only produces data when RNGMODE is set to 'normal'
502
+ * ring oscillator mode.
503
+ */
504
+static void test_rosel(void)
505
+{
506
+ rng_reset_enable();
507
+ g_assert_true(rng_wait_ready());
508
+ rng_writeb(RNGMODE, 0);
509
+ g_assert_false(rng_wait_ready());
510
+ rng_writeb(RNGMODE, ROSEL_NORMAL);
511
+ g_assert_true(rng_wait_ready());
512
+ rng_writeb(RNGMODE, 0);
513
+ g_assert_false(rng_wait_ready());
514
+}
515
+
516
+/*
517
+ * Verifies that a continuous sequence of bits collected after enabling the RNG
518
+ * satisfies a monobit test.
519
+ */
520
+static void test_continuous_monobit(void)
521
+{
522
+ uint8_t buf[TEST_INPUT_BITS / BITS_PER_BYTE];
523
+ unsigned int i;
524
+
525
+ rng_reset_enable();
526
+ for (i = 0; i < sizeof(buf); i++) {
527
+ g_assert_true(rng_wait_ready());
528
+ buf[i] = rng_readb(RNGD);
529
+ }
530
+
531
+ g_assert_cmpfloat(calc_monobit_p(buf, sizeof(buf)), >, 0.01);
532
+}
533
+
534
+/*
535
+ * Verifies that a continuous sequence of bits collected after enabling the RNG
536
+ * satisfies a runs test.
537
+ */
538
+static void test_continuous_runs(void)
539
+{
540
+ union {
541
+ unsigned long l[TEST_INPUT_BITS / BITS_PER_LONG];
542
+ uint8_t c[TEST_INPUT_BITS / BITS_PER_BYTE];
543
+ } buf;
544
+ unsigned int i;
545
+
546
+ rng_reset_enable();
547
+ for (i = 0; i < sizeof(buf); i++) {
548
+ g_assert_true(rng_wait_ready());
549
+ buf.c[i] = rng_readb(RNGD);
550
+ }
551
+
552
+ g_assert_cmpfloat(calc_runs_p(buf.l, sizeof(buf) * BITS_PER_BYTE), >, 0.01);
553
+}
554
+
555
+/*
556
+ * Verifies that the first data byte collected after enabling the RNG satisfies
557
+ * a monobit test.
558
+ */
559
+static void test_first_byte_monobit(void)
560
+{
561
+ /* Enable, collect one byte, disable. Repeat until we have 100 bits. */
562
+ uint8_t buf[TEST_INPUT_BITS / BITS_PER_BYTE];
563
+ unsigned int i;
564
+
565
+ rng_reset();
566
+ for (i = 0; i < sizeof(buf); i++) {
567
+ rng_writeb(RNGCS, RNGE);
568
+ g_assert_true(rng_wait_ready());
569
+ buf[i] = rng_readb(RNGD);
570
+ rng_writeb(RNGCS, 0);
571
+ }
572
+
573
+ g_assert_cmpfloat(calc_monobit_p(buf, sizeof(buf)), >, 0.01);
574
+}
575
+
576
+/*
577
+ * Verifies that the first data byte collected after enabling the RNG satisfies
578
+ * a runs test.
579
+ */
580
+static void test_first_byte_runs(void)
581
+{
582
+ /* Enable, collect one byte, disable. Repeat until we have 100 bits. */
583
+ union {
584
+ unsigned long l[TEST_INPUT_BITS / BITS_PER_LONG];
585
+ uint8_t c[TEST_INPUT_BITS / BITS_PER_BYTE];
586
+ } buf;
587
+ unsigned int i;
588
+
589
+ rng_reset();
590
+ for (i = 0; i < sizeof(buf); i++) {
591
+ rng_writeb(RNGCS, RNGE);
592
+ g_assert_true(rng_wait_ready());
593
+ buf.c[i] = rng_readb(RNGD);
594
+ rng_writeb(RNGCS, 0);
595
+ }
596
+
597
+ g_assert_cmpfloat(calc_runs_p(buf.l, sizeof(buf) * BITS_PER_BYTE), >, 0.01);
598
+}
599
+
600
+int main(int argc, char **argv)
601
+{
602
+ int ret;
603
+
604
+ g_test_init(&argc, &argv, NULL);
605
+ g_test_set_nonfatal_assertions();
606
+
607
+ qtest_add_func("npcm7xx_rng/enable_disable", test_enable_disable);
608
+ qtest_add_func("npcm7xx_rng/rosel", test_rosel);
609
+ qtest_add_func("npcm7xx_rng/continuous/monobit", test_continuous_monobit);
610
+ qtest_add_func("npcm7xx_rng/continuous/runs", test_continuous_runs);
611
+ qtest_add_func("npcm7xx_rng/first_byte/monobit", test_first_byte_monobit);
612
+ qtest_add_func("npcm7xx_rng/first_byte/runs", test_first_byte_runs);
613
+
614
+ qtest_start("-machine npcm750-evb");
615
+ ret = g_test_run();
616
+ qtest_end();
617
+
618
+ return ret;
619
+}
620
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
209
index XXXXXXX..XXXXXXX 100644
621
index XXXXXXX..XXXXXXX 100644
210
--- a/MAINTAINERS
622
--- a/hw/misc/meson.build
211
+++ b/MAINTAINERS
623
+++ b/hw/misc/meson.build
212
@@ -XXX,XX +XXX,XX @@ F: hw/arm/iotkit.c
624
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mst_fpga.c'))
213
F: include/hw/arm/iotkit.h
625
softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
214
F: hw/misc/iotkit-sysctl.c
626
'npcm7xx_clk.c',
215
F: include/hw/misc/iotkit-sysctl.h
627
'npcm7xx_gcr.c',
216
+F: hw/misc/iotkit-sysinfo.c
628
+ 'npcm7xx_rng.c',
217
+F: include/hw/misc/iotkit-sysinfo.h
629
))
218
630
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files(
219
Musicpal
631
'omap_clk.c',
220
M: Jan Kiszka <jan.kiszka@web.de>
632
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
221
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
222
index XXXXXXX..XXXXXXX 100644
633
index XXXXXXX..XXXXXXX 100644
223
--- a/default-configs/arm-softmmu.mak
634
--- a/hw/misc/trace-events
224
+++ b/default-configs/arm-softmmu.mak
635
+++ b/hw/misc/trace-events
225
@@ -XXX,XX +XXX,XX @@ CONFIG_TZ_PPC=y
636
@@ -XXX,XX +XXX,XX @@ npcm7xx_clk_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " valu
226
CONFIG_IOTKIT=y
637
npcm7xx_gcr_read(uint64_t offset, uint32_t value) " offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
227
CONFIG_IOTKIT_SECCTL=y
638
npcm7xx_gcr_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
228
CONFIG_IOTKIT_SYSCTL=y
639
229
+CONFIG_IOTKIT_SYSINFO=y
640
+# npcm7xx_rng.c
230
641
+npcm7xx_rng_read(uint64_t offset, uint64_t value, unsigned size) "offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
231
CONFIG_VERSATILE=y
642
+npcm7xx_rng_write(uint64_t offset, uint64_t value, unsigned size) "offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
232
CONFIG_VERSATILE_PCI=y
643
+
644
# stm32f4xx_syscfg.c
645
stm32f4xx_syscfg_set_irq(int gpio, int line, int level) "Interupt: GPIO: %d, Line: %d; Level: %d"
646
stm32f4xx_pulse_exti(int irq) "Pulse EXTI: %d"
647
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
648
index XXXXXXX..XXXXXXX 100644
649
--- a/tests/qtest/meson.build
650
+++ b/tests/qtest/meson.build
651
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
652
(config_all_devices.has_key('CONFIG_ISA_TESTDEV') ? ['endianness-test'] : []) + \
653
['prom-env-test', 'boot-serial-test']
654
655
-qtests_npcm7xx = ['npcm7xx_timer-test', 'npcm7xx_watchdog_timer-test']
656
+qtests_npcm7xx = \
657
+ ['npcm7xx_rng-test',
658
+ 'npcm7xx_timer-test',
659
+ 'npcm7xx_watchdog_timer-test']
660
qtests_arm = \
661
(config_all_devices.has_key('CONFIG_PFLASH_CFI02') ? ['pflash-cfi02-test'] : []) + \
662
(config_all_devices.has_key('CONFIG_NPCM7XX') ? qtests_npcm7xx : []) + \
233
--
663
--
234
2.18.0
664
2.20.1
235
665
236
666
diff view generated by jsdifflib
1
The v8 AArch32 HACTLR2 register maps to bits [63:32] of ACTLR_EL2.
1
From: Havard Skinnemoen <hskinnemoen@google.com>
2
We implement ACTLR_EL2 as RAZ/WI, so make HACTLR2 also RAZ/WI.
3
(We put the regdef next to ACTLR_EL2 as a reminder in case we
4
ever make ACTLR_EL2 something other than RAZ/WI).
5
2
3
The NPCM730 and NPCM750 chips have a single USB host port shared between
4
a USB 2.0 EHCI host controller and a USB 1.1 OHCI host controller. This
5
adds support for both of them.
6
7
Testing notes:
8
* With -device usb-kbd, qemu will automatically insert a full-speed
9
hub, and the keyboard becomes controlled by the OHCI controller.
10
* With -device usb-kbd,bus=usb-bus.0,port=1, the keyboard is directly
11
attached to the port without any hubs, and the device becomes
12
controlled by the EHCI controller since it's high speed capable.
13
* With -device usb-kbd,bus=usb-bus.0,port=1,usb_version=1, the
14
keyboard is directly attached to the port, but it only advertises
15
itself as full-speed capable, so it becomes controlled by the OHCI
16
controller.
17
18
In all cases, the keyboard device enumerates correctly.
19
20
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
21
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
22
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
23
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
9
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
10
Message-id: 20180820153020.21478-2-peter.maydell@linaro.org
11
---
24
---
12
target/arm/helper.c | 10 ++++++++++
25
docs/system/arm/nuvoton.rst | 2 +-
13
1 file changed, 10 insertions(+)
26
hw/usb/hcd-ehci.h | 1 +
27
include/hw/arm/npcm7xx.h | 4 ++++
28
hw/arm/npcm7xx.c | 27 +++++++++++++++++++++++++--
29
hw/usb/hcd-ehci-sysbus.c | 19 +++++++++++++++++++
30
5 files changed, 50 insertions(+), 3 deletions(-)
14
31
15
diff --git a/target/arm/helper.c b/target/arm/helper.c
32
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
16
index XXXXXXX..XXXXXXX 100644
33
index XXXXXXX..XXXXXXX 100644
17
--- a/target/arm/helper.c
34
--- a/docs/system/arm/nuvoton.rst
18
+++ b/target/arm/helper.c
35
+++ b/docs/system/arm/nuvoton.rst
19
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
36
@@ -XXX,XX +XXX,XX @@ Supported devices
20
REGINFO_SENTINEL
37
* OTP controllers (no protection features)
21
};
38
* Flash Interface Unit (FIU; no protection features)
22
define_arm_cp_regs(cpu, auxcr_reginfo);
39
* Random Number Generator (RNG)
23
+ if (arm_feature(env, ARM_FEATURE_V8)) {
40
+ * USB host (USBH)
24
+ /* HACTLR2 maps to ACTLR_EL2[63:32] and is not in ARMv7 */
41
25
+ ARMCPRegInfo hactlr2_reginfo = {
42
Missing devices
26
+ .name = "HACTLR2", .state = ARM_CP_STATE_AA32,
43
---------------
27
+ .cp = 15, .opc1 = 4, .crn = 1, .crm = 0, .opc2 = 3,
44
@@ -XXX,XX +XXX,XX @@ Missing devices
28
+ .access = PL2_RW, .type = ARM_CP_CONST,
45
* eSPI slave interface
29
+ .resetvalue = 0
46
30
+ };
47
* Ethernet controllers (GMAC and EMC)
31
+ define_one_arm_cp_reg(cpu, &hactlr2_reginfo);
48
- * USB host (USBH)
32
+ }
49
* USB device (USBD)
50
* SMBus controller (SMBF)
51
* Peripheral SPI controller (PSPI)
52
diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
53
index XXXXXXX..XXXXXXX 100644
54
--- a/hw/usb/hcd-ehci.h
55
+++ b/hw/usb/hcd-ehci.h
56
@@ -XXX,XX +XXX,XX @@ struct EHCIPCIState {
57
#define TYPE_PLATFORM_EHCI "platform-ehci-usb"
58
#define TYPE_EXYNOS4210_EHCI "exynos4210-ehci-usb"
59
#define TYPE_AW_H3_EHCI "aw-h3-ehci-usb"
60
+#define TYPE_NPCM7XX_EHCI "npcm7xx-ehci-usb"
61
#define TYPE_TEGRA2_EHCI "tegra2-ehci-usb"
62
#define TYPE_PPC4xx_EHCI "ppc4xx-ehci-usb"
63
#define TYPE_FUSBH200_EHCI "fusbh200-ehci-usb"
64
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
65
index XXXXXXX..XXXXXXX 100644
66
--- a/include/hw/arm/npcm7xx.h
67
+++ b/include/hw/arm/npcm7xx.h
68
@@ -XXX,XX +XXX,XX @@
69
#include "hw/nvram/npcm7xx_otp.h"
70
#include "hw/timer/npcm7xx_timer.h"
71
#include "hw/ssi/npcm7xx_fiu.h"
72
+#include "hw/usb/hcd-ehci.h"
73
+#include "hw/usb/hcd-ohci.h"
74
#include "target/arm/cpu.h"
75
76
#define NPCM7XX_MAX_NUM_CPUS (2)
77
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
78
NPCM7xxOTPState fuse_array;
79
NPCM7xxMCState mc;
80
NPCM7xxRNGState rng;
81
+ EHCISysBusState ehci;
82
+ OHCISysBusState ohci;
83
NPCM7xxFIUState fiu[2];
84
} NPCM7xxState;
85
86
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
87
index XXXXXXX..XXXXXXX 100644
88
--- a/hw/arm/npcm7xx.c
89
+++ b/hw/arm/npcm7xx.c
90
@@ -XXX,XX +XXX,XX @@
91
#define NPCM7XX_MC_BA (0xf0824000)
92
#define NPCM7XX_RNG_BA (0xf000b000)
93
94
+/* USB Host modules */
95
+#define NPCM7XX_EHCI_BA (0xf0806000)
96
+#define NPCM7XX_OHCI_BA (0xf0807000)
97
+
98
/* Internal AHB SRAM */
99
#define NPCM7XX_RAM3_BA (0xc0008000)
100
#define NPCM7XX_RAM3_SZ (4 * KiB)
101
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxInterrupt {
102
NPCM7XX_WDG0_IRQ = 47, /* Timer Module 0 Watchdog */
103
NPCM7XX_WDG1_IRQ, /* Timer Module 1 Watchdog */
104
NPCM7XX_WDG2_IRQ, /* Timer Module 2 Watchdog */
105
+ NPCM7XX_EHCI_IRQ = 61,
106
+ NPCM7XX_OHCI_IRQ = 62,
107
};
108
109
/* Total number of GIC interrupts, including internal Cortex-A9 interrupts. */
110
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
111
object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
33
}
112
}
34
113
35
if (arm_feature(env, ARM_FEATURE_CBAR)) {
114
+ object_initialize_child(obj, "ehci", &s->ehci, TYPE_NPCM7XX_EHCI);
115
+ object_initialize_child(obj, "ohci", &s->ohci, TYPE_SYSBUS_OHCI);
116
+
117
QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_fiu) != ARRAY_SIZE(s->fiu));
118
for (i = 0; i < ARRAY_SIZE(s->fiu); i++) {
119
object_initialize_child(obj, npcm7xx_fiu[i].name, &s->fiu[i],
120
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
121
sysbus_realize(SYS_BUS_DEVICE(&s->rng), &error_abort);
122
sysbus_mmio_map(SYS_BUS_DEVICE(&s->rng), 0, NPCM7XX_RNG_BA);
123
124
+ /* USB Host */
125
+ object_property_set_bool(OBJECT(&s->ehci), "companion-enable", true,
126
+ &error_abort);
127
+ sysbus_realize(SYS_BUS_DEVICE(&s->ehci), &error_abort);
128
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->ehci), 0, NPCM7XX_EHCI_BA);
129
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci), 0,
130
+ npcm7xx_irq(s, NPCM7XX_EHCI_IRQ));
131
+
132
+ object_property_set_str(OBJECT(&s->ohci), "masterbus", "usb-bus.0",
133
+ &error_abort);
134
+ object_property_set_uint(OBJECT(&s->ohci), "num-ports", 1, &error_abort);
135
+ sysbus_realize(SYS_BUS_DEVICE(&s->ohci), &error_abort);
136
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->ohci), 0, NPCM7XX_OHCI_BA);
137
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->ohci), 0,
138
+ npcm7xx_irq(s, NPCM7XX_OHCI_IRQ));
139
+
140
/*
141
* Flash Interface Unit (FIU). Can fail if incorrect number of chip selects
142
* specified, but this is a programming error.
143
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
144
create_unimplemented_device("npcm7xx.mcphy", 0xf05f0000, 64 * KiB);
145
create_unimplemented_device("npcm7xx.gmac1", 0xf0802000, 8 * KiB);
146
create_unimplemented_device("npcm7xx.gmac2", 0xf0804000, 8 * KiB);
147
- create_unimplemented_device("npcm7xx.ehci", 0xf0806000, 4 * KiB);
148
- create_unimplemented_device("npcm7xx.ohci", 0xf0807000, 4 * KiB);
149
create_unimplemented_device("npcm7xx.vcd", 0xf0810000, 64 * KiB);
150
create_unimplemented_device("npcm7xx.ece", 0xf0820000, 8 * KiB);
151
create_unimplemented_device("npcm7xx.vdma", 0xf0822000, 8 * KiB);
152
diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c
153
index XXXXXXX..XXXXXXX 100644
154
--- a/hw/usb/hcd-ehci-sysbus.c
155
+++ b/hw/usb/hcd-ehci-sysbus.c
156
@@ -XXX,XX +XXX,XX @@ static const TypeInfo ehci_aw_h3_type_info = {
157
.class_init = ehci_aw_h3_class_init,
158
};
159
160
+static void ehci_npcm7xx_class_init(ObjectClass *oc, void *data)
161
+{
162
+ SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
163
+ DeviceClass *dc = DEVICE_CLASS(oc);
164
+
165
+ sec->capsbase = 0x0;
166
+ sec->opregbase = 0x10;
167
+ sec->portscbase = 0x44;
168
+ sec->portnr = 1;
169
+ set_bit(DEVICE_CATEGORY_USB, dc->categories);
170
+}
171
+
172
+static const TypeInfo ehci_npcm7xx_type_info = {
173
+ .name = TYPE_NPCM7XX_EHCI,
174
+ .parent = TYPE_SYS_BUS_EHCI,
175
+ .class_init = ehci_npcm7xx_class_init,
176
+};
177
+
178
static void ehci_tegra2_class_init(ObjectClass *oc, void *data)
179
{
180
SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
181
@@ -XXX,XX +XXX,XX @@ static void ehci_sysbus_register_types(void)
182
type_register_static(&ehci_platform_type_info);
183
type_register_static(&ehci_exynos4210_type_info);
184
type_register_static(&ehci_aw_h3_type_info);
185
+ type_register_static(&ehci_npcm7xx_type_info);
186
type_register_static(&ehci_tegra2_type_info);
187
type_register_static(&ehci_ppc4xx_type_info);
188
type_register_static(&ehci_fusbh200_type_info);
36
--
189
--
37
2.18.0
190
2.20.1
38
191
39
192
diff view generated by jsdifflib
1
The Arm Cortex-M System Design Kit includes a "dual-input timer module"
1
From: Havard Skinnemoen <hskinnemoen@google.com>
2
which combines two programmable down-counters. Implement a model
3
of this device.
4
2
3
The NPCM7xx chips have multiple GPIO controllers that are mostly
4
identical except for some minor differences like the reset values of
5
some registers. Each controller controls up to 32 pins.
6
7
Each individual pin is modeled as a pair of unnamed GPIOs -- one for
8
emitting the actual pin state, and one for driving the pin externally.
9
Like the nRF51 GPIO controller, a gpio level may be negative, which
10
means the pin is not driven, or floating.
11
12
Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
13
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
14
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20180820141116.9118-4-peter.maydell@linaro.org
8
---
16
---
9
hw/timer/Makefile.objs | 1 +
17
docs/system/arm/nuvoton.rst | 2 +-
10
include/hw/timer/cmsdk-apb-dualtimer.h | 72 ++++
18
include/hw/arm/npcm7xx.h | 2 +
11
hw/timer/cmsdk-apb-dualtimer.c | 515 +++++++++++++++++++++++++
19
include/hw/gpio/npcm7xx_gpio.h | 55 +++++
12
MAINTAINERS | 2 +
20
hw/arm/npcm7xx.c | 80 ++++++
13
default-configs/arm-softmmu.mak | 1 +
21
hw/gpio/npcm7xx_gpio.c | 424 ++++++++++++++++++++++++++++++++
14
hw/timer/trace-events | 5 +
22
tests/qtest/npcm7xx_gpio-test.c | 385 +++++++++++++++++++++++++++++
15
6 files changed, 596 insertions(+)
23
hw/gpio/meson.build | 1 +
16
create mode 100644 include/hw/timer/cmsdk-apb-dualtimer.h
24
hw/gpio/trace-events | 7 +
17
create mode 100644 hw/timer/cmsdk-apb-dualtimer.c
25
tests/qtest/meson.build | 3 +-
26
9 files changed, 957 insertions(+), 2 deletions(-)
27
create mode 100644 include/hw/gpio/npcm7xx_gpio.h
28
create mode 100644 hw/gpio/npcm7xx_gpio.c
29
create mode 100644 tests/qtest/npcm7xx_gpio-test.c
18
30
19
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
31
diff --git a/docs/system/arm/nuvoton.rst b/docs/system/arm/nuvoton.rst
20
index XXXXXXX..XXXXXXX 100644
32
index XXXXXXX..XXXXXXX 100644
21
--- a/hw/timer/Makefile.objs
33
--- a/docs/system/arm/nuvoton.rst
22
+++ b/hw/timer/Makefile.objs
34
+++ b/docs/system/arm/nuvoton.rst
23
@@ -XXX,XX +XXX,XX @@ common-obj-$(CONFIG_ASPEED_SOC) += aspeed_timer.o
35
@@ -XXX,XX +XXX,XX @@ Supported devices
24
36
* Flash Interface Unit (FIU; no protection features)
25
common-obj-$(CONFIG_SUN4V_RTC) += sun4v-rtc.o
37
* Random Number Generator (RNG)
26
common-obj-$(CONFIG_CMSDK_APB_TIMER) += cmsdk-apb-timer.o
38
* USB host (USBH)
27
+common-obj-$(CONFIG_CMSDK_APB_DUALTIMER) += cmsdk-apb-dualtimer.o
39
+ * GPIO controller
28
common-obj-$(CONFIG_MSF2) += mss-timer.o
40
29
diff --git a/include/hw/timer/cmsdk-apb-dualtimer.h b/include/hw/timer/cmsdk-apb-dualtimer.h
41
Missing devices
42
---------------
43
44
- * GPIO controller
45
* LPC/eSPI host-to-BMC interface, including
46
47
* Keyboard and mouse controller interface (KBCI)
48
diff --git a/include/hw/arm/npcm7xx.h b/include/hw/arm/npcm7xx.h
49
index XXXXXXX..XXXXXXX 100644
50
--- a/include/hw/arm/npcm7xx.h
51
+++ b/include/hw/arm/npcm7xx.h
52
@@ -XXX,XX +XXX,XX @@
53
54
#include "hw/boards.h"
55
#include "hw/cpu/a9mpcore.h"
56
+#include "hw/gpio/npcm7xx_gpio.h"
57
#include "hw/mem/npcm7xx_mc.h"
58
#include "hw/misc/npcm7xx_clk.h"
59
#include "hw/misc/npcm7xx_gcr.h"
60
@@ -XXX,XX +XXX,XX @@ typedef struct NPCM7xxState {
61
NPCM7xxOTPState fuse_array;
62
NPCM7xxMCState mc;
63
NPCM7xxRNGState rng;
64
+ NPCM7xxGPIOState gpio[8];
65
EHCISysBusState ehci;
66
OHCISysBusState ohci;
67
NPCM7xxFIUState fiu[2];
68
diff --git a/include/hw/gpio/npcm7xx_gpio.h b/include/hw/gpio/npcm7xx_gpio.h
30
new file mode 100644
69
new file mode 100644
31
index XXXXXXX..XXXXXXX
70
index XXXXXXX..XXXXXXX
32
--- /dev/null
71
--- /dev/null
33
+++ b/include/hw/timer/cmsdk-apb-dualtimer.h
72
+++ b/include/hw/gpio/npcm7xx_gpio.h
34
@@ -XXX,XX +XXX,XX @@
73
@@ -XXX,XX +XXX,XX @@
35
+/*
74
+/*
36
+ * ARM CMSDK APB dual-timer emulation
75
+ * Nuvoton NPCM7xx General Purpose Input / Output (GPIO)
37
+ *
76
+ *
38
+ * Copyright (c) 2018 Linaro Limited
77
+ * Copyright 2020 Google LLC
39
+ * Written by Peter Maydell
40
+ *
78
+ *
41
+ * This program is free software; you can redistribute it and/or modify
79
+ * This program is free software; you can redistribute it and/or
42
+ * it under the terms of the GNU General Public License version 2 or
80
+ * modify it under the terms of the GNU General Public License
43
+ * (at your option) any later version.
81
+ * version 2 as published by the Free Software Foundation.
82
+ *
83
+ * This program is distributed in the hope that it will be useful,
84
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
85
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
86
+ * GNU General Public License for more details.
44
+ */
87
+ */
88
+#ifndef NPCM7XX_GPIO_H
89
+#define NPCM7XX_GPIO_H
90
+
91
+#include "exec/memory.h"
92
+#include "hw/sysbus.h"
93
+
94
+/* Number of pins managed by each controller. */
95
+#define NPCM7XX_GPIO_NR_PINS (32)
45
+
96
+
46
+/*
97
+/*
47
+ * This is a model of the "APB dual-input timer" which is part of the Cortex-M
98
+ * Number of registers in our device state structure. Don't change this without
48
+ * System Design Kit (CMSDK) and documented in the Cortex-M System
99
+ * incrementing the version_id in the vmstate.
49
+ * Design Kit Technical Reference Manual (ARM DDI0479C):
50
+ * https://developer.arm.com/products/system-design/system-design-kits/cortex-m-system-design-kit
51
+ *
52
+ * QEMU interface:
53
+ * + QOM property "pclk-frq": frequency at which the timer is clocked
54
+ * + sysbus MMIO region 0: the register bank
55
+ * + sysbus IRQ 0: combined timer interrupt TIMINTC
56
+ * + sysbus IRO 1: timer block 1 interrupt TIMINT1
57
+ * + sysbus IRQ 2: timer block 2 interrupt TIMINT2
58
+ */
100
+ */
59
+
101
+#define NPCM7XX_GPIO_NR_REGS (0x80 / sizeof(uint32_t))
60
+#ifndef CMSDK_APB_DUALTIMER_H
102
+
61
+#define CMSDK_APB_DUALTIMER_H
103
+typedef struct NPCM7xxGPIOState {
62
+
104
+ SysBusDevice parent;
63
+#include "hw/sysbus.h"
105
+
64
+#include "hw/ptimer.h"
106
+ /* Properties to be defined by the SoC */
65
+
107
+ uint32_t reset_pu;
66
+#define TYPE_CMSDK_APB_DUALTIMER "cmsdk-apb-dualtimer"
108
+ uint32_t reset_pd;
67
+#define CMSDK_APB_DUALTIMER(obj) OBJECT_CHECK(CMSDKAPBDualTimer, (obj), \
109
+ uint32_t reset_osrc;
68
+ TYPE_CMSDK_APB_DUALTIMER)
110
+ uint32_t reset_odsc;
69
+
111
+
70
+typedef struct CMSDKAPBDualTimer CMSDKAPBDualTimer;
112
+ MemoryRegion mmio;
71
+
113
+
72
+/* One of the two identical timer modules in the dual-timer module */
114
+ qemu_irq irq;
73
+typedef struct CMSDKAPBDualTimerModule {
115
+ qemu_irq output[NPCM7XX_GPIO_NR_PINS];
74
+ CMSDKAPBDualTimer *parent;
116
+
75
+ struct ptimer_state *timer;
117
+ uint32_t pin_level;
76
+ qemu_irq timerint;
118
+ uint32_t ext_level;
77
+ /*
119
+ uint32_t ext_driven;
78
+ * We must track the guest LOAD and VALUE register state by hand
120
+
79
+ * rather than leaving this state only in the ptimer limit/count,
121
+ uint32_t regs[NPCM7XX_GPIO_NR_REGS];
80
+ * because if CONTROL.SIZE is 0 then only the low 16 bits of the
122
+} NPCM7xxGPIOState;
81
+ * counter actually counts, but the high half is still guest
123
+
82
+ * accessible.
124
+#define TYPE_NPCM7XX_GPIO "npcm7xx-gpio"
83
+ */
125
+#define NPCM7XX_GPIO(obj) \
84
+ uint32_t load;
126
+ OBJECT_CHECK(NPCM7xxGPIOState, (obj), TYPE_NPCM7XX_GPIO)
85
+ uint32_t value;
127
+
86
+ uint32_t control;
128
+#endif /* NPCM7XX_GPIO_H */
87
+ uint32_t intstatus;
129
diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c
88
+} CMSDKAPBDualTimerModule;
130
index XXXXXXX..XXXXXXX 100644
89
+
131
--- a/hw/arm/npcm7xx.c
90
+#define CMSDK_APB_DUALTIMER_NUM_MODULES 2
132
+++ b/hw/arm/npcm7xx.c
91
+
133
@@ -XXX,XX +XXX,XX @@ enum NPCM7xxInterrupt {
92
+struct CMSDKAPBDualTimer {
134
NPCM7XX_WDG2_IRQ, /* Timer Module 2 Watchdog */
93
+ /*< private >*/
135
NPCM7XX_EHCI_IRQ = 61,
94
+ SysBusDevice parent_obj;
136
NPCM7XX_OHCI_IRQ = 62,
95
+
137
+ NPCM7XX_GPIO0_IRQ = 116,
96
+ /*< public >*/
138
+ NPCM7XX_GPIO1_IRQ,
97
+ MemoryRegion iomem;
139
+ NPCM7XX_GPIO2_IRQ,
98
+ qemu_irq timerintc;
140
+ NPCM7XX_GPIO3_IRQ,
99
+ uint32_t pclk_frq;
141
+ NPCM7XX_GPIO4_IRQ,
100
+
142
+ NPCM7XX_GPIO5_IRQ,
101
+ CMSDKAPBDualTimerModule timermod[CMSDK_APB_DUALTIMER_NUM_MODULES];
143
+ NPCM7XX_GPIO6_IRQ,
102
+ uint32_t timeritcr;
144
+ NPCM7XX_GPIO7_IRQ,
103
+ uint32_t timeritop;
145
};
146
147
/* Total number of GIC interrupts, including internal Cortex-A9 interrupts. */
148
@@ -XXX,XX +XXX,XX @@ static const hwaddr npcm7xx_fiu3_flash_addr[] = {
149
0xb8000000, /* CS3 */
150
};
151
152
+static const struct {
153
+ hwaddr regs_addr;
154
+ uint32_t unconnected_pins;
155
+ uint32_t reset_pu;
156
+ uint32_t reset_pd;
157
+ uint32_t reset_osrc;
158
+ uint32_t reset_odsc;
159
+} npcm7xx_gpio[] = {
160
+ {
161
+ .regs_addr = 0xf0010000,
162
+ .reset_pu = 0xff03ffff,
163
+ .reset_pd = 0x00fc0000,
164
+ }, {
165
+ .regs_addr = 0xf0011000,
166
+ .unconnected_pins = 0x0000001e,
167
+ .reset_pu = 0xfefffe07,
168
+ .reset_pd = 0x010001e0,
169
+ }, {
170
+ .regs_addr = 0xf0012000,
171
+ .reset_pu = 0x780fffff,
172
+ .reset_pd = 0x07f00000,
173
+ .reset_odsc = 0x00700000,
174
+ }, {
175
+ .regs_addr = 0xf0013000,
176
+ .reset_pu = 0x00fc0000,
177
+ .reset_pd = 0xff000000,
178
+ }, {
179
+ .regs_addr = 0xf0014000,
180
+ .reset_pu = 0xffffffff,
181
+ }, {
182
+ .regs_addr = 0xf0015000,
183
+ .reset_pu = 0xbf83f801,
184
+ .reset_pd = 0x007c0000,
185
+ .reset_osrc = 0x000000f1,
186
+ .reset_odsc = 0x3f9f80f1,
187
+ }, {
188
+ .regs_addr = 0xf0016000,
189
+ .reset_pu = 0xfc00f801,
190
+ .reset_pd = 0x000007fe,
191
+ .reset_odsc = 0x00000800,
192
+ }, {
193
+ .regs_addr = 0xf0017000,
194
+ .unconnected_pins = 0xffffff00,
195
+ .reset_pu = 0x0000007f,
196
+ .reset_osrc = 0x0000007f,
197
+ .reset_odsc = 0x0000007f,
198
+ },
104
+};
199
+};
105
+
200
+
106
+#endif
201
static const struct {
107
diff --git a/hw/timer/cmsdk-apb-dualtimer.c b/hw/timer/cmsdk-apb-dualtimer.c
202
const char *name;
203
hwaddr regs_addr;
204
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_init(Object *obj)
205
object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
206
}
207
208
+ for (i = 0; i < ARRAY_SIZE(s->gpio); i++) {
209
+ object_initialize_child(obj, "gpio[*]", &s->gpio[i], TYPE_NPCM7XX_GPIO);
210
+ }
211
+
212
object_initialize_child(obj, "ehci", &s->ehci, TYPE_NPCM7XX_EHCI);
213
object_initialize_child(obj, "ohci", &s->ohci, TYPE_SYSBUS_OHCI);
214
215
@@ -XXX,XX +XXX,XX @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
216
sysbus_realize(SYS_BUS_DEVICE(&s->rng), &error_abort);
217
sysbus_mmio_map(SYS_BUS_DEVICE(&s->rng), 0, NPCM7XX_RNG_BA);
218
219
+ /* GPIO modules. Cannot fail. */
220
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_gpio) != ARRAY_SIZE(s->gpio));
221
+ for (i = 0; i < ARRAY_SIZE(s->gpio); i++) {
222
+ Object *obj = OBJECT(&s->gpio[i]);
223
+
224
+ object_property_set_uint(obj, "reset-pullup",
225
+ npcm7xx_gpio[i].reset_pu, &error_abort);
226
+ object_property_set_uint(obj, "reset-pulldown",
227
+ npcm7xx_gpio[i].reset_pd, &error_abort);
228
+ object_property_set_uint(obj, "reset-osrc",
229
+ npcm7xx_gpio[i].reset_osrc, &error_abort);
230
+ object_property_set_uint(obj, "reset-odsc",
231
+ npcm7xx_gpio[i].reset_odsc, &error_abort);
232
+ sysbus_realize(SYS_BUS_DEVICE(obj), &error_abort);
233
+ sysbus_mmio_map(SYS_BUS_DEVICE(obj), 0, npcm7xx_gpio[i].regs_addr);
234
+ sysbus_connect_irq(SYS_BUS_DEVICE(obj), 0,
235
+ npcm7xx_irq(s, NPCM7XX_GPIO0_IRQ + i));
236
+ }
237
+
238
/* USB Host */
239
object_property_set_bool(OBJECT(&s->ehci), "companion-enable", true,
240
&error_abort);
241
diff --git a/hw/gpio/npcm7xx_gpio.c b/hw/gpio/npcm7xx_gpio.c
108
new file mode 100644
242
new file mode 100644
109
index XXXXXXX..XXXXXXX
243
index XXXXXXX..XXXXXXX
110
--- /dev/null
244
--- /dev/null
111
+++ b/hw/timer/cmsdk-apb-dualtimer.c
245
+++ b/hw/gpio/npcm7xx_gpio.c
112
@@ -XXX,XX +XXX,XX @@
246
@@ -XXX,XX +XXX,XX @@
113
+/*
247
+/*
114
+ * ARM CMSDK APB dual-timer emulation
248
+ * Nuvoton NPCM7xx General Purpose Input / Output (GPIO)
115
+ *
249
+ *
116
+ * Copyright (c) 2018 Linaro Limited
250
+ * Copyright 2020 Google LLC
117
+ * Written by Peter Maydell
118
+ *
251
+ *
119
+ * This program is free software; you can redistribute it and/or modify
252
+ * This program is free software; you can redistribute it and/or
120
+ * it under the terms of the GNU General Public License version 2 or
253
+ * modify it under the terms of the GNU General Public License
121
+ * (at your option) any later version.
254
+ * version 2 as published by the Free Software Foundation.
255
+ *
256
+ * This program is distributed in the hope that it will be useful,
257
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
258
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
259
+ * GNU General Public License for more details.
122
+ */
260
+ */
123
+
261
+
124
+/*
125
+ * This is a model of the "APB dual-input timer" which is part of the Cortex-M
126
+ * System Design Kit (CMSDK) and documented in the Cortex-M System
127
+ * Design Kit Technical Reference Manual (ARM DDI0479C):
128
+ * https://developer.arm.com/products/system-design/system-design-kits/cortex-m-system-design-kit
129
+ */
130
+
131
+#include "qemu/osdep.h"
262
+#include "qemu/osdep.h"
263
+
264
+#include "hw/gpio/npcm7xx_gpio.h"
265
+#include "hw/irq.h"
266
+#include "hw/qdev-properties.h"
267
+#include "migration/vmstate.h"
268
+#include "qapi/error.h"
132
+#include "qemu/log.h"
269
+#include "qemu/log.h"
270
+#include "qemu/module.h"
271
+#include "qemu/units.h"
133
+#include "trace.h"
272
+#include "trace.h"
134
+#include "qapi/error.h"
273
+
135
+#include "qemu/main-loop.h"
274
+/* 32-bit register indices. */
136
+#include "hw/sysbus.h"
275
+enum NPCM7xxGPIORegister {
137
+#include "hw/registerfields.h"
276
+ NPCM7XX_GPIO_TLOCK1,
138
+#include "hw/timer/cmsdk-apb-dualtimer.h"
277
+ NPCM7XX_GPIO_DIN,
139
+
278
+ NPCM7XX_GPIO_POL,
140
+REG32(TIMER1LOAD, 0x0)
279
+ NPCM7XX_GPIO_DOUT,
141
+REG32(TIMER1VALUE, 0x4)
280
+ NPCM7XX_GPIO_OE,
142
+REG32(TIMER1CONTROL, 0x8)
281
+ NPCM7XX_GPIO_OTYP,
143
+ FIELD(CONTROL, ONESHOT, 0, 1)
282
+ NPCM7XX_GPIO_MP,
144
+ FIELD(CONTROL, SIZE, 1, 1)
283
+ NPCM7XX_GPIO_PU,
145
+ FIELD(CONTROL, PRESCALE, 2, 2)
284
+ NPCM7XX_GPIO_PD,
146
+ FIELD(CONTROL, INTEN, 5, 1)
285
+ NPCM7XX_GPIO_DBNC,
147
+ FIELD(CONTROL, MODE, 6, 1)
286
+ NPCM7XX_GPIO_EVTYP,
148
+ FIELD(CONTROL, ENABLE, 7, 1)
287
+ NPCM7XX_GPIO_EVBE,
149
+#define R_CONTROL_VALID_MASK (R_CONTROL_ONESHOT_MASK | R_CONTROL_SIZE_MASK | \
288
+ NPCM7XX_GPIO_OBL0,
150
+ R_CONTROL_PRESCALE_MASK | R_CONTROL_INTEN_MASK | \
289
+ NPCM7XX_GPIO_OBL1,
151
+ R_CONTROL_MODE_MASK | R_CONTROL_ENABLE_MASK)
290
+ NPCM7XX_GPIO_OBL2,
152
+REG32(TIMER1INTCLR, 0xc)
291
+ NPCM7XX_GPIO_OBL3,
153
+REG32(TIMER1RIS, 0x10)
292
+ NPCM7XX_GPIO_EVEN,
154
+REG32(TIMER1MIS, 0x14)
293
+ NPCM7XX_GPIO_EVENS,
155
+REG32(TIMER1BGLOAD, 0x18)
294
+ NPCM7XX_GPIO_EVENC,
156
+REG32(TIMER2LOAD, 0x20)
295
+ NPCM7XX_GPIO_EVST,
157
+REG32(TIMER2VALUE, 0x24)
296
+ NPCM7XX_GPIO_SPLCK,
158
+REG32(TIMER2CONTROL, 0x28)
297
+ NPCM7XX_GPIO_MPLCK,
159
+REG32(TIMER2INTCLR, 0x2c)
298
+ NPCM7XX_GPIO_IEM,
160
+REG32(TIMER2RIS, 0x30)
299
+ NPCM7XX_GPIO_OSRC,
161
+REG32(TIMER2MIS, 0x34)
300
+ NPCM7XX_GPIO_ODSC,
162
+REG32(TIMER2BGLOAD, 0x38)
301
+ NPCM7XX_GPIO_DOS = 0x68 / sizeof(uint32_t),
163
+REG32(TIMERITCR, 0xf00)
302
+ NPCM7XX_GPIO_DOC,
164
+ FIELD(TIMERITCR, ENABLE, 0, 1)
303
+ NPCM7XX_GPIO_OES,
165
+#define R_TIMERITCR_VALID_MASK R_TIMERITCR_ENABLE_MASK
304
+ NPCM7XX_GPIO_OEC,
166
+REG32(TIMERITOP, 0xf04)
305
+ NPCM7XX_GPIO_TLOCK2 = 0x7c / sizeof(uint32_t),
167
+ FIELD(TIMERITOP, TIMINT1, 0, 1)
306
+ NPCM7XX_GPIO_REGS_END,
168
+ FIELD(TIMERITOP, TIMINT2, 1, 1)
169
+#define R_TIMERITOP_VALID_MASK (R_TIMERITOP_TIMINT1_MASK | \
170
+ R_TIMERITOP_TIMINT2_MASK)
171
+REG32(PID4, 0xfd0)
172
+REG32(PID5, 0xfd4)
173
+REG32(PID6, 0xfd8)
174
+REG32(PID7, 0xfdc)
175
+REG32(PID0, 0xfe0)
176
+REG32(PID1, 0xfe4)
177
+REG32(PID2, 0xfe8)
178
+REG32(PID3, 0xfec)
179
+REG32(CID0, 0xff0)
180
+REG32(CID1, 0xff4)
181
+REG32(CID2, 0xff8)
182
+REG32(CID3, 0xffc)
183
+
184
+/* PID/CID values */
185
+static const int timer_id[] = {
186
+ 0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
187
+ 0x23, 0xb8, 0x1b, 0x00, /* PID0..PID3 */
188
+ 0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
189
+};
307
+};
190
+
308
+
191
+static bool cmsdk_dualtimermod_intstatus(CMSDKAPBDualTimerModule *m)
309
+#define NPCM7XX_GPIO_REGS_SIZE (4 * KiB)
192
+{
310
+
193
+ /* Return masked interrupt status for the timer module */
311
+#define NPCM7XX_GPIO_LOCK_MAGIC1 (0xc0defa73)
194
+ return m->intstatus && (m->control & R_CONTROL_INTEN_MASK);
312
+#define NPCM7XX_GPIO_LOCK_MAGIC2 (0xc0de1248)
195
+}
313
+
196
+
314
+static void npcm7xx_gpio_update_events(NPCM7xxGPIOState *s, uint32_t din_diff)
197
+static void cmsdk_apb_dualtimer_update(CMSDKAPBDualTimer *s)
315
+{
198
+{
316
+ uint32_t din_new = s->regs[NPCM7XX_GPIO_DIN];
199
+ bool timint1, timint2, timintc;
317
+
200
+
318
+ /* Trigger on high level */
201
+ if (s->timeritcr) {
319
+ s->regs[NPCM7XX_GPIO_EVST] |= din_new & ~s->regs[NPCM7XX_GPIO_EVTYP];
202
+ /* Integration test mode: outputs driven directly from TIMERITOP bits */
320
+ /* Trigger on both edges */
203
+ timint1 = s->timeritop & R_TIMERITOP_TIMINT1_MASK;
321
+ s->regs[NPCM7XX_GPIO_EVST] |= (din_diff & s->regs[NPCM7XX_GPIO_EVTYP]
204
+ timint2 = s->timeritop & R_TIMERITOP_TIMINT2_MASK;
322
+ & s->regs[NPCM7XX_GPIO_EVBE]);
205
+ } else {
323
+ /* Trigger on rising edge */
206
+ timint1 = cmsdk_dualtimermod_intstatus(&s->timermod[0]);
324
+ s->regs[NPCM7XX_GPIO_EVST] |= (din_diff & din_new
207
+ timint2 = cmsdk_dualtimermod_intstatus(&s->timermod[1]);
325
+ & s->regs[NPCM7XX_GPIO_EVTYP]);
326
+
327
+ trace_npcm7xx_gpio_update_events(DEVICE(s)->canonical_path,
328
+ s->regs[NPCM7XX_GPIO_EVST],
329
+ s->regs[NPCM7XX_GPIO_EVEN]);
330
+ qemu_set_irq(s->irq, !!(s->regs[NPCM7XX_GPIO_EVST]
331
+ & s->regs[NPCM7XX_GPIO_EVEN]));
332
+}
333
+
334
+static void npcm7xx_gpio_update_pins(NPCM7xxGPIOState *s, uint32_t diff)
335
+{
336
+ uint32_t drive_en;
337
+ uint32_t drive_lvl;
338
+ uint32_t not_driven;
339
+ uint32_t undefined;
340
+ uint32_t pin_diff;
341
+ uint32_t din_old;
342
+
343
+ /* Calculate level of each pin driven by GPIO controller. */
344
+ drive_lvl = s->regs[NPCM7XX_GPIO_DOUT] ^ s->regs[NPCM7XX_GPIO_POL];
345
+ /* If OTYP=1, only drive low (open drain) */
346
+ drive_en = s->regs[NPCM7XX_GPIO_OE] & ~(s->regs[NPCM7XX_GPIO_OTYP]
347
+ & drive_lvl);
348
+ /*
349
+ * If a pin is driven to opposite levels by the GPIO controller and the
350
+ * external driver, the result is undefined.
351
+ */
352
+ undefined = drive_en & s->ext_driven & (drive_lvl ^ s->ext_level);
353
+ if (undefined) {
354
+ qemu_log_mask(LOG_GUEST_ERROR,
355
+ "%s: pins have multiple drivers: 0x%" PRIx32 "\n",
356
+ DEVICE(s)->canonical_path, undefined);
208
+ }
357
+ }
209
+
358
+
210
+ timintc = timint1 || timint2;
359
+ not_driven = ~(drive_en | s->ext_driven);
211
+
360
+ pin_diff = s->pin_level;
212
+ qemu_set_irq(s->timermod[0].timerint, timint1);
361
+
213
+ qemu_set_irq(s->timermod[1].timerint, timint2);
362
+ /* Set pins to externally driven level. */
214
+ qemu_set_irq(s->timerintc, timintc);
363
+ s->pin_level = s->ext_level & s->ext_driven;
215
+}
364
+ /* Set internally driven pins, ignoring any conflicts. */
216
+
365
+ s->pin_level |= drive_lvl & drive_en;
217
+static void cmsdk_dualtimermod_write_control(CMSDKAPBDualTimerModule *m,
366
+ /* Pull up undriven pins with internal pull-up enabled. */
218
+ uint32_t newctrl)
367
+ s->pin_level |= not_driven & s->regs[NPCM7XX_GPIO_PU];
219
+{
368
+ /* Pins not driven, pulled up or pulled down are undefined */
220
+ /* Handle a write to the CONTROL register */
369
+ undefined |= not_driven & ~(s->regs[NPCM7XX_GPIO_PU]
221
+ uint32_t changed;
370
+ | s->regs[NPCM7XX_GPIO_PD]);
222
+
371
+
223
+ newctrl &= R_CONTROL_VALID_MASK;
372
+ /* If any pins changed state, update the outgoing GPIOs. */
224
+
373
+ pin_diff ^= s->pin_level;
225
+ changed = m->control ^ newctrl;
374
+ pin_diff |= undefined & diff;
226
+
375
+ if (pin_diff) {
227
+ if (changed & ~newctrl & R_CONTROL_ENABLE_MASK) {
376
+ int i;
228
+ /* ENABLE cleared, stop timer before any further changes */
377
+
229
+ ptimer_stop(m->timer);
378
+ for (i = 0; i < NPCM7XX_GPIO_NR_PINS; i++) {
230
+ }
379
+ uint32_t mask = BIT(i);
231
+
380
+ if (pin_diff & mask) {
232
+ if (changed & R_CONTROL_PRESCALE_MASK) {
381
+ int level = (undefined & mask) ? -1 : !!(s->pin_level & mask);
233
+ int divisor;
382
+ trace_npcm7xx_gpio_set_output(DEVICE(s)->canonical_path,
234
+
383
+ i, level);
235
+ switch (FIELD_EX32(newctrl, CONTROL, PRESCALE)) {
384
+ qemu_set_irq(s->output[i], level);
236
+ case 0:
237
+ divisor = 1;
238
+ break;
239
+ case 1:
240
+ divisor = 16;
241
+ break;
242
+ case 2:
243
+ divisor = 256;
244
+ break;
245
+ case 3:
246
+ /* UNDEFINED; complain, and arbitrarily treat like 2 */
247
+ qemu_log_mask(LOG_GUEST_ERROR,
248
+ "CMSDK APB dual-timer: CONTROL.PRESCALE==0b11"
249
+ " is undefined behaviour\n");
250
+ divisor = 256;
251
+ break;
252
+ default:
253
+ g_assert_not_reached();
254
+ }
255
+ ptimer_set_freq(m->timer, m->parent->pclk_frq / divisor);
256
+ }
257
+
258
+ if (changed & R_CONTROL_MODE_MASK) {
259
+ uint32_t load;
260
+ if (newctrl & R_CONTROL_MODE_MASK) {
261
+ /* Periodic: the limit is the LOAD register value */
262
+ load = m->load;
263
+ } else {
264
+ /* Free-running: counter wraps around */
265
+ load = ptimer_get_limit(m->timer);
266
+ if (!(m->control & R_CONTROL_SIZE_MASK)) {
267
+ load = deposit32(m->load, 0, 16, load);
268
+ }
269
+ m->load = load;
270
+ load = 0xffffffff;
271
+ }
272
+ if (!(m->control & R_CONTROL_SIZE_MASK)) {
273
+ load &= 0xffff;
274
+ }
275
+ ptimer_set_limit(m->timer, load, 0);
276
+ }
277
+
278
+ if (changed & R_CONTROL_SIZE_MASK) {
279
+ /* Timer switched between 16 and 32 bit count */
280
+ uint32_t value, load;
281
+
282
+ value = ptimer_get_count(m->timer);
283
+ load = ptimer_get_limit(m->timer);
284
+ if (newctrl & R_CONTROL_SIZE_MASK) {
285
+ /* 16 -> 32, top half of VALUE is in struct field */
286
+ value = deposit32(m->value, 0, 16, value);
287
+ } else {
288
+ /* 32 -> 16: save top half to struct field and truncate */
289
+ m->value = value;
290
+ value &= 0xffff;
291
+ }
292
+
293
+ if (newctrl & R_CONTROL_MODE_MASK) {
294
+ /* Periodic, timer limit has LOAD value */
295
+ if (newctrl & R_CONTROL_SIZE_MASK) {
296
+ load = deposit32(m->load, 0, 16, load);
297
+ } else {
298
+ m->load = load;
299
+ load &= 0xffff;
300
+ }
301
+ } else {
302
+ /* Free-running, timer limit is set to give wraparound */
303
+ if (newctrl & R_CONTROL_SIZE_MASK) {
304
+ load = 0xffffffff;
305
+ } else {
306
+ load = 0xffff;
307
+ }
385
+ }
308
+ }
386
+ }
309
+ ptimer_set_count(m->timer, value);
310
+ ptimer_set_limit(m->timer, load, 0);
311
+ }
387
+ }
312
+
388
+
313
+ if (newctrl & R_CONTROL_ENABLE_MASK) {
389
+ /* Calculate new value of DIN after masking and polarity setting. */
314
+ /*
390
+ din_old = s->regs[NPCM7XX_GPIO_DIN];
315
+ * ENABLE is set; start the timer after all other changes.
391
+ s->regs[NPCM7XX_GPIO_DIN] = ((s->pin_level & s->regs[NPCM7XX_GPIO_IEM])
316
+ * We start it even if the ENABLE bit didn't actually change,
392
+ ^ s->regs[NPCM7XX_GPIO_POL]);
317
+ * in case the timer was an expired one-shot timer that has
393
+
318
+ * now been changed into a free-running or periodic timer.
394
+ /* See if any new events triggered because of all this. */
319
+ */
395
+ npcm7xx_gpio_update_events(s, din_old ^ s->regs[NPCM7XX_GPIO_DIN]);
320
+ ptimer_run(m->timer, !!(newctrl & R_CONTROL_ONESHOT_MASK));
396
+}
397
+
398
+static bool npcm7xx_gpio_is_locked(NPCM7xxGPIOState *s)
399
+{
400
+ return s->regs[NPCM7XX_GPIO_TLOCK1] == 1;
401
+}
402
+
403
+static uint64_t npcm7xx_gpio_regs_read(void *opaque, hwaddr addr,
404
+ unsigned int size)
405
+{
406
+ hwaddr reg = addr / sizeof(uint32_t);
407
+ NPCM7xxGPIOState *s = opaque;
408
+ uint64_t value = 0;
409
+
410
+ switch (reg) {
411
+ case NPCM7XX_GPIO_TLOCK1 ... NPCM7XX_GPIO_EVEN:
412
+ case NPCM7XX_GPIO_EVST ... NPCM7XX_GPIO_ODSC:
413
+ value = s->regs[reg];
414
+ break;
415
+
416
+ case NPCM7XX_GPIO_EVENS ... NPCM7XX_GPIO_EVENC:
417
+ case NPCM7XX_GPIO_DOS ... NPCM7XX_GPIO_TLOCK2:
418
+ qemu_log_mask(LOG_GUEST_ERROR,
419
+ "%s: read from write-only register 0x%" HWADDR_PRIx "\n",
420
+ DEVICE(s)->canonical_path, addr);
421
+ break;
422
+
423
+ default:
424
+ qemu_log_mask(LOG_GUEST_ERROR,
425
+ "%s: read from invalid offset 0x%" HWADDR_PRIx "\n",
426
+ DEVICE(s)->canonical_path, addr);
427
+ break;
321
+ }
428
+ }
322
+
429
+
323
+ m->control = newctrl;
430
+ trace_npcm7xx_gpio_read(DEVICE(s)->canonical_path, addr, value);
324
+}
431
+
325
+
432
+ return value;
326
+static uint64_t cmsdk_apb_dualtimer_read(void *opaque, hwaddr offset,
433
+}
327
+ unsigned size)
434
+
328
+{
435
+static void npcm7xx_gpio_regs_write(void *opaque, hwaddr addr, uint64_t v,
329
+ CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(opaque);
436
+ unsigned int size)
330
+ uint64_t r;
437
+{
331
+
438
+ hwaddr reg = addr / sizeof(uint32_t);
332
+ if (offset >= A_TIMERITCR) {
439
+ NPCM7xxGPIOState *s = opaque;
333
+ switch (offset) {
440
+ uint32_t value = v;
334
+ case A_TIMERITCR:
441
+ uint32_t diff;
335
+ r = s->timeritcr;
442
+
443
+ trace_npcm7xx_gpio_write(DEVICE(s)->canonical_path, addr, v);
444
+
445
+ if (npcm7xx_gpio_is_locked(s)) {
446
+ switch (reg) {
447
+ case NPCM7XX_GPIO_TLOCK1:
448
+ if (s->regs[NPCM7XX_GPIO_TLOCK2] == NPCM7XX_GPIO_LOCK_MAGIC2 &&
449
+ value == NPCM7XX_GPIO_LOCK_MAGIC1) {
450
+ s->regs[NPCM7XX_GPIO_TLOCK1] = 0;
451
+ s->regs[NPCM7XX_GPIO_TLOCK2] = 0;
452
+ }
336
+ break;
453
+ break;
337
+ case A_PID4 ... A_CID3:
454
+
338
+ r = timer_id[(offset - A_PID4) / 4];
455
+ case NPCM7XX_GPIO_TLOCK2:
456
+ s->regs[reg] = value;
339
+ break;
457
+ break;
458
+
340
+ default:
459
+ default:
341
+ bad_offset:
342
+ qemu_log_mask(LOG_GUEST_ERROR,
460
+ qemu_log_mask(LOG_GUEST_ERROR,
343
+ "CMSDK APB dual-timer read: bad offset %x\n",
461
+ "%s: write to locked register @ 0x%" HWADDR_PRIx "\n",
344
+ (int) offset);
462
+ DEVICE(s)->canonical_path, addr);
345
+ r = 0;
346
+ break;
463
+ break;
347
+ }
464
+ }
348
+ } else {
465
+
349
+ int timer = offset >> 5;
350
+ CMSDKAPBDualTimerModule *m;
351
+
352
+ if (timer >= ARRAY_SIZE(s->timermod)) {
353
+ goto bad_offset;
354
+ }
355
+
356
+ m = &s->timermod[timer];
357
+
358
+ switch (offset & 0x1F) {
359
+ case A_TIMER1LOAD:
360
+ case A_TIMER1BGLOAD:
361
+ if (m->control & R_CONTROL_MODE_MASK) {
362
+ /*
363
+ * Periodic: the ptimer limit is the LOAD register value, (or
364
+ * just the low 16 bits of it if the timer is in 16-bit mode)
365
+ */
366
+ r = ptimer_get_limit(m->timer);
367
+ if (!(m->control & R_CONTROL_SIZE_MASK)) {
368
+ r = deposit32(m->load, 0, 16, r);
369
+ }
370
+ } else {
371
+ /* Free-running: LOAD register value is just in m->load */
372
+ r = m->load;
373
+ }
374
+ break;
375
+ case A_TIMER1VALUE:
376
+ r = ptimer_get_count(m->timer);
377
+ if (!(m->control & R_CONTROL_SIZE_MASK)) {
378
+ r = deposit32(m->value, 0, 16, r);
379
+ }
380
+ break;
381
+ case A_TIMER1CONTROL:
382
+ r = m->control;
383
+ break;
384
+ case A_TIMER1RIS:
385
+ r = m->intstatus;
386
+ break;
387
+ case A_TIMER1MIS:
388
+ r = cmsdk_dualtimermod_intstatus(m);
389
+ break;
390
+ default:
391
+ goto bad_offset;
392
+ }
393
+ }
394
+
395
+ trace_cmsdk_apb_dualtimer_read(offset, r, size);
396
+ return r;
397
+}
398
+
399
+static void cmsdk_apb_dualtimer_write(void *opaque, hwaddr offset,
400
+ uint64_t value, unsigned size)
401
+{
402
+ CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(opaque);
403
+
404
+ trace_cmsdk_apb_dualtimer_write(offset, value, size);
405
+
406
+ if (offset >= A_TIMERITCR) {
407
+ switch (offset) {
408
+ case A_TIMERITCR:
409
+ s->timeritcr = value & R_TIMERITCR_VALID_MASK;
410
+ cmsdk_apb_dualtimer_update(s);
411
+ case A_TIMERITOP:
412
+ s->timeritop = value & R_TIMERITOP_VALID_MASK;
413
+ cmsdk_apb_dualtimer_update(s);
414
+ default:
415
+ bad_offset:
416
+ qemu_log_mask(LOG_GUEST_ERROR,
417
+ "CMSDK APB dual-timer write: bad offset %x\n",
418
+ (int) offset);
419
+ break;
420
+ }
421
+ } else {
422
+ int timer = offset >> 5;
423
+ CMSDKAPBDualTimerModule *m;
424
+
425
+ if (timer >= ARRAY_SIZE(s->timermod)) {
426
+ goto bad_offset;
427
+ }
428
+
429
+ m = &s->timermod[timer];
430
+
431
+ switch (offset & 0x1F) {
432
+ case A_TIMER1LOAD:
433
+ /* Set the limit, and immediately reload the count from it */
434
+ m->load = value;
435
+ m->value = value;
436
+ if (!(m->control & R_CONTROL_SIZE_MASK)) {
437
+ value &= 0xffff;
438
+ }
439
+ if (!(m->control & R_CONTROL_MODE_MASK)) {
440
+ /*
441
+ * In free-running mode this won't set the limit but will
442
+ * still change the current count value.
443
+ */
444
+ ptimer_set_count(m->timer, value);
445
+ } else {
446
+ if (!value) {
447
+ ptimer_stop(m->timer);
448
+ }
449
+ ptimer_set_limit(m->timer, value, 1);
450
+ if (value && (m->control & R_CONTROL_ENABLE_MASK)) {
451
+ /* Force possibly-expired oneshot timer to restart */
452
+ ptimer_run(m->timer, 1);
453
+ }
454
+ }
455
+ break;
456
+ case A_TIMER1BGLOAD:
457
+ /* Set the limit, but not the current count */
458
+ m->load = value;
459
+ if (!(m->control & R_CONTROL_MODE_MASK)) {
460
+ /* In free-running mode there is no limit */
461
+ break;
462
+ }
463
+ if (!(m->control & R_CONTROL_SIZE_MASK)) {
464
+ value &= 0xffff;
465
+ }
466
+ ptimer_set_limit(m->timer, value, 0);
467
+ break;
468
+ case A_TIMER1CONTROL:
469
+ cmsdk_dualtimermod_write_control(m, value);
470
+ cmsdk_apb_dualtimer_update(s);
471
+ break;
472
+ case A_TIMER1INTCLR:
473
+ m->intstatus = 0;
474
+ cmsdk_apb_dualtimer_update(s);
475
+ break;
476
+ default:
477
+ goto bad_offset;
478
+ }
479
+ }
480
+}
481
+
482
+static const MemoryRegionOps cmsdk_apb_dualtimer_ops = {
483
+ .read = cmsdk_apb_dualtimer_read,
484
+ .write = cmsdk_apb_dualtimer_write,
485
+ .endianness = DEVICE_LITTLE_ENDIAN,
486
+ /* byte/halfword accesses are just zero-padded on reads and writes */
487
+ .impl.min_access_size = 4,
488
+ .impl.max_access_size = 4,
489
+ .valid.min_access_size = 1,
490
+ .valid.max_access_size = 4,
491
+};
492
+
493
+static void cmsdk_dualtimermod_tick(void *opaque)
494
+{
495
+ CMSDKAPBDualTimerModule *m = opaque;
496
+
497
+ m->intstatus = 1;
498
+ cmsdk_apb_dualtimer_update(m->parent);
499
+}
500
+
501
+static void cmsdk_dualtimermod_reset(CMSDKAPBDualTimerModule *m)
502
+{
503
+ m->control = R_CONTROL_INTEN_MASK;
504
+ m->intstatus = 0;
505
+ m->load = 0;
506
+ m->value = 0xffffffff;
507
+ ptimer_stop(m->timer);
508
+ /*
509
+ * We start in free-running mode, with VALUE at 0xffffffff, and
510
+ * in 16-bit counter mode. This means that the ptimer count and
511
+ * limit must both be set to 0xffff, so we wrap at 16 bits.
512
+ */
513
+ ptimer_set_limit(m->timer, 0xffff, 1);
514
+ ptimer_set_freq(m->timer, m->parent->pclk_frq);
515
+}
516
+
517
+static void cmsdk_apb_dualtimer_reset(DeviceState *dev)
518
+{
519
+ CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(dev);
520
+ int i;
521
+
522
+ trace_cmsdk_apb_dualtimer_reset();
523
+
524
+ for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
525
+ cmsdk_dualtimermod_reset(&s->timermod[i]);
526
+ }
527
+ s->timeritcr = 0;
528
+ s->timeritop = 0;
529
+}
530
+
531
+static void cmsdk_apb_dualtimer_init(Object *obj)
532
+{
533
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
534
+ CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(obj);
535
+ int i;
536
+
537
+ memory_region_init_io(&s->iomem, obj, &cmsdk_apb_dualtimer_ops,
538
+ s, "cmsdk-apb-dualtimer", 0x1000);
539
+ sysbus_init_mmio(sbd, &s->iomem);
540
+ sysbus_init_irq(sbd, &s->timerintc);
541
+
542
+ for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
543
+ sysbus_init_irq(sbd, &s->timermod[i].timerint);
544
+ }
545
+}
546
+
547
+static void cmsdk_apb_dualtimer_realize(DeviceState *dev, Error **errp)
548
+{
549
+ CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(dev);
550
+ int i;
551
+
552
+ if (s->pclk_frq == 0) {
553
+ error_setg(errp, "CMSDK APB timer: pclk-frq property must be set");
554
+ return;
466
+ return;
555
+ }
467
+ }
556
+
468
+
557
+ for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
469
+ diff = s->regs[reg] ^ value;
558
+ CMSDKAPBDualTimerModule *m = &s->timermod[i];
470
+
559
+ QEMUBH *bh = qemu_bh_new(cmsdk_dualtimermod_tick, m);
471
+ switch (reg) {
560
+
472
+ case NPCM7XX_GPIO_TLOCK1:
561
+ m->parent = s;
473
+ case NPCM7XX_GPIO_TLOCK2:
562
+ m->timer = ptimer_init(bh,
474
+ s->regs[NPCM7XX_GPIO_TLOCK1] = 1;
563
+ PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD |
475
+ s->regs[NPCM7XX_GPIO_TLOCK2] = 0;
564
+ PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT |
476
+ break;
565
+ PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
477
+
566
+ PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
478
+ case NPCM7XX_GPIO_DIN:
479
+ qemu_log_mask(LOG_GUEST_ERROR,
480
+ "%s: write to read-only register @ 0x%" HWADDR_PRIx "\n",
481
+ DEVICE(s)->canonical_path, addr);
482
+ break;
483
+
484
+ case NPCM7XX_GPIO_POL:
485
+ case NPCM7XX_GPIO_DOUT:
486
+ case NPCM7XX_GPIO_OE:
487
+ case NPCM7XX_GPIO_OTYP:
488
+ case NPCM7XX_GPIO_PU:
489
+ case NPCM7XX_GPIO_PD:
490
+ case NPCM7XX_GPIO_IEM:
491
+ s->regs[reg] = value;
492
+ npcm7xx_gpio_update_pins(s, diff);
493
+ break;
494
+
495
+ case NPCM7XX_GPIO_DOS:
496
+ s->regs[NPCM7XX_GPIO_DOUT] |= value;
497
+ npcm7xx_gpio_update_pins(s, value);
498
+ break;
499
+ case NPCM7XX_GPIO_DOC:
500
+ s->regs[NPCM7XX_GPIO_DOUT] &= ~value;
501
+ npcm7xx_gpio_update_pins(s, value);
502
+ break;
503
+ case NPCM7XX_GPIO_OES:
504
+ s->regs[NPCM7XX_GPIO_OE] |= value;
505
+ npcm7xx_gpio_update_pins(s, value);
506
+ break;
507
+ case NPCM7XX_GPIO_OEC:
508
+ s->regs[NPCM7XX_GPIO_OE] &= ~value;
509
+ npcm7xx_gpio_update_pins(s, value);
510
+ break;
511
+
512
+ case NPCM7XX_GPIO_EVTYP:
513
+ case NPCM7XX_GPIO_EVBE:
514
+ case NPCM7XX_GPIO_EVEN:
515
+ s->regs[reg] = value;
516
+ npcm7xx_gpio_update_events(s, 0);
517
+ break;
518
+
519
+ case NPCM7XX_GPIO_EVENS:
520
+ s->regs[NPCM7XX_GPIO_EVEN] |= value;
521
+ npcm7xx_gpio_update_events(s, 0);
522
+ break;
523
+ case NPCM7XX_GPIO_EVENC:
524
+ s->regs[NPCM7XX_GPIO_EVEN] &= ~value;
525
+ npcm7xx_gpio_update_events(s, 0);
526
+ break;
527
+
528
+ case NPCM7XX_GPIO_EVST:
529
+ s->regs[reg] &= ~value;
530
+ npcm7xx_gpio_update_events(s, 0);
531
+ break;
532
+
533
+ case NPCM7XX_GPIO_MP:
534
+ case NPCM7XX_GPIO_DBNC:
535
+ case NPCM7XX_GPIO_OSRC:
536
+ case NPCM7XX_GPIO_ODSC:
537
+ /* Nothing to do; just store the value. */
538
+ s->regs[reg] = value;
539
+ break;
540
+
541
+ case NPCM7XX_GPIO_OBL0:
542
+ case NPCM7XX_GPIO_OBL1:
543
+ case NPCM7XX_GPIO_OBL2:
544
+ case NPCM7XX_GPIO_OBL3:
545
+ s->regs[reg] = value;
546
+ qemu_log_mask(LOG_UNIMP, "%s: Blinking is not implemented\n",
547
+ __func__);
548
+ break;
549
+
550
+ case NPCM7XX_GPIO_SPLCK:
551
+ case NPCM7XX_GPIO_MPLCK:
552
+ qemu_log_mask(LOG_UNIMP, "%s: Per-pin lock is not implemented\n",
553
+ __func__);
554
+ break;
555
+
556
+ default:
557
+ qemu_log_mask(LOG_GUEST_ERROR,
558
+ "%s: write to invalid offset 0x%" HWADDR_PRIx "\n",
559
+ DEVICE(s)->canonical_path, addr);
560
+ break;
567
+ }
561
+ }
568
+}
562
+}
569
+
563
+
570
+static const VMStateDescription cmsdk_dualtimermod_vmstate = {
564
+static const MemoryRegionOps npcm7xx_gpio_regs_ops = {
571
+ .name = "cmsdk-apb-dualtimer-module",
565
+ .read = npcm7xx_gpio_regs_read,
572
+ .version_id = 1,
566
+ .write = npcm7xx_gpio_regs_write,
573
+ .minimum_version_id = 1,
567
+ .endianness = DEVICE_NATIVE_ENDIAN,
568
+ .valid = {
569
+ .min_access_size = 4,
570
+ .max_access_size = 4,
571
+ .unaligned = false,
572
+ },
573
+};
574
+
575
+static void npcm7xx_gpio_set_input(void *opaque, int line, int level)
576
+{
577
+ NPCM7xxGPIOState *s = opaque;
578
+
579
+ trace_npcm7xx_gpio_set_input(DEVICE(s)->canonical_path, line, level);
580
+
581
+ g_assert(line >= 0 && line < NPCM7XX_GPIO_NR_PINS);
582
+
583
+ s->ext_driven = deposit32(s->ext_driven, line, 1, level >= 0);
584
+ s->ext_level = deposit32(s->ext_level, line, 1, level > 0);
585
+
586
+ npcm7xx_gpio_update_pins(s, BIT(line));
587
+}
588
+
589
+static void npcm7xx_gpio_enter_reset(Object *obj, ResetType type)
590
+{
591
+ NPCM7xxGPIOState *s = NPCM7XX_GPIO(obj);
592
+
593
+ memset(s->regs, 0, sizeof(s->regs));
594
+
595
+ s->regs[NPCM7XX_GPIO_PU] = s->reset_pu;
596
+ s->regs[NPCM7XX_GPIO_PD] = s->reset_pd;
597
+ s->regs[NPCM7XX_GPIO_OSRC] = s->reset_osrc;
598
+ s->regs[NPCM7XX_GPIO_ODSC] = s->reset_odsc;
599
+}
600
+
601
+static void npcm7xx_gpio_hold_reset(Object *obj)
602
+{
603
+ NPCM7xxGPIOState *s = NPCM7XX_GPIO(obj);
604
+
605
+ npcm7xx_gpio_update_pins(s, -1);
606
+}
607
+
608
+static void npcm7xx_gpio_init(Object *obj)
609
+{
610
+ NPCM7xxGPIOState *s = NPCM7XX_GPIO(obj);
611
+ DeviceState *dev = DEVICE(obj);
612
+
613
+ memory_region_init_io(&s->mmio, obj, &npcm7xx_gpio_regs_ops, s,
614
+ "regs", NPCM7XX_GPIO_REGS_SIZE);
615
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
616
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
617
+
618
+ qdev_init_gpio_in(dev, npcm7xx_gpio_set_input, NPCM7XX_GPIO_NR_PINS);
619
+ qdev_init_gpio_out(dev, s->output, NPCM7XX_GPIO_NR_PINS);
620
+}
621
+
622
+static const VMStateDescription vmstate_npcm7xx_gpio = {
623
+ .name = "npcm7xx-gpio",
624
+ .version_id = 0,
625
+ .minimum_version_id = 0,
574
+ .fields = (VMStateField[]) {
626
+ .fields = (VMStateField[]) {
575
+ VMSTATE_PTIMER(timer, CMSDKAPBDualTimerModule),
627
+ VMSTATE_UINT32(pin_level, NPCM7xxGPIOState),
576
+ VMSTATE_UINT32(load, CMSDKAPBDualTimerModule),
628
+ VMSTATE_UINT32(ext_level, NPCM7xxGPIOState),
577
+ VMSTATE_UINT32(value, CMSDKAPBDualTimerModule),
629
+ VMSTATE_UINT32(ext_driven, NPCM7xxGPIOState),
578
+ VMSTATE_UINT32(control, CMSDKAPBDualTimerModule),
630
+ VMSTATE_UINT32_ARRAY(regs, NPCM7xxGPIOState, NPCM7XX_GPIO_NR_REGS),
579
+ VMSTATE_UINT32(intstatus, CMSDKAPBDualTimerModule),
631
+ VMSTATE_END_OF_LIST(),
580
+ VMSTATE_END_OF_LIST()
632
+ },
581
+ }
582
+};
633
+};
583
+
634
+
584
+static const VMStateDescription cmsdk_apb_dualtimer_vmstate = {
635
+static Property npcm7xx_gpio_properties[] = {
585
+ .name = "cmsdk-apb-dualtimer",
636
+ /* Bit n set => pin n has pullup enabled by default. */
586
+ .version_id = 1,
637
+ DEFINE_PROP_UINT32("reset-pullup", NPCM7xxGPIOState, reset_pu, 0),
587
+ .minimum_version_id = 1,
638
+ /* Bit n set => pin n has pulldown enabled by default. */
588
+ .fields = (VMStateField[]) {
639
+ DEFINE_PROP_UINT32("reset-pulldown", NPCM7xxGPIOState, reset_pd, 0),
589
+ VMSTATE_STRUCT_ARRAY(timermod, CMSDKAPBDualTimer,
640
+ /* Bit n set => pin n has high slew rate by default. */
590
+ CMSDK_APB_DUALTIMER_NUM_MODULES,
641
+ DEFINE_PROP_UINT32("reset-osrc", NPCM7xxGPIOState, reset_osrc, 0),
591
+ 1, cmsdk_dualtimermod_vmstate,
642
+ /* Bit n set => pin n has high drive strength by default. */
592
+ CMSDKAPBDualTimerModule),
643
+ DEFINE_PROP_UINT32("reset-odsc", NPCM7xxGPIOState, reset_odsc, 0),
593
+ VMSTATE_UINT32(timeritcr, CMSDKAPBDualTimer),
594
+ VMSTATE_UINT32(timeritop, CMSDKAPBDualTimer),
595
+ VMSTATE_END_OF_LIST()
596
+ }
597
+};
598
+
599
+static Property cmsdk_apb_dualtimer_properties[] = {
600
+ DEFINE_PROP_UINT32("pclk-frq", CMSDKAPBDualTimer, pclk_frq, 0),
601
+ DEFINE_PROP_END_OF_LIST(),
644
+ DEFINE_PROP_END_OF_LIST(),
602
+};
645
+};
603
+
646
+
604
+static void cmsdk_apb_dualtimer_class_init(ObjectClass *klass, void *data)
647
+static void npcm7xx_gpio_class_init(ObjectClass *klass, void *data)
605
+{
648
+{
649
+ ResettableClass *reset = RESETTABLE_CLASS(klass);
606
+ DeviceClass *dc = DEVICE_CLASS(klass);
650
+ DeviceClass *dc = DEVICE_CLASS(klass);
607
+
651
+
608
+ dc->realize = cmsdk_apb_dualtimer_realize;
652
+ QEMU_BUILD_BUG_ON(NPCM7XX_GPIO_REGS_END > NPCM7XX_GPIO_NR_REGS);
609
+ dc->vmsd = &cmsdk_apb_dualtimer_vmstate;
653
+
610
+ dc->reset = cmsdk_apb_dualtimer_reset;
654
+ dc->desc = "NPCM7xx GPIO Controller";
611
+ dc->props = cmsdk_apb_dualtimer_properties;
655
+ dc->vmsd = &vmstate_npcm7xx_gpio;
612
+}
656
+ reset->phases.enter = npcm7xx_gpio_enter_reset;
613
+
657
+ reset->phases.hold = npcm7xx_gpio_hold_reset;
614
+static const TypeInfo cmsdk_apb_dualtimer_info = {
658
+ device_class_set_props(dc, npcm7xx_gpio_properties);
615
+ .name = TYPE_CMSDK_APB_DUALTIMER,
659
+}
616
+ .parent = TYPE_SYS_BUS_DEVICE,
660
+
617
+ .instance_size = sizeof(CMSDKAPBDualTimer),
661
+static const TypeInfo npcm7xx_gpio_types[] = {
618
+ .instance_init = cmsdk_apb_dualtimer_init,
662
+ {
619
+ .class_init = cmsdk_apb_dualtimer_class_init,
663
+ .name = TYPE_NPCM7XX_GPIO,
664
+ .parent = TYPE_SYS_BUS_DEVICE,
665
+ .instance_size = sizeof(NPCM7xxGPIOState),
666
+ .class_init = npcm7xx_gpio_class_init,
667
+ .instance_init = npcm7xx_gpio_init,
668
+ },
620
+};
669
+};
621
+
670
+DEFINE_TYPES(npcm7xx_gpio_types);
622
+static void cmsdk_apb_dualtimer_register_types(void)
671
diff --git a/tests/qtest/npcm7xx_gpio-test.c b/tests/qtest/npcm7xx_gpio-test.c
623
+{
672
new file mode 100644
624
+ type_register_static(&cmsdk_apb_dualtimer_info);
673
index XXXXXXX..XXXXXXX
625
+}
674
--- /dev/null
626
+
675
+++ b/tests/qtest/npcm7xx_gpio-test.c
627
+type_init(cmsdk_apb_dualtimer_register_types);
676
@@ -XXX,XX +XXX,XX @@
628
diff --git a/MAINTAINERS b/MAINTAINERS
677
+/*
678
+ * QTest testcase for the Nuvoton NPCM7xx GPIO modules.
679
+ *
680
+ * Copyright 2020 Google LLC
681
+ *
682
+ * This program is free software; you can redistribute it and/or modify it
683
+ * under the terms of the GNU General Public License as published by the
684
+ * Free Software Foundation; either version 2 of the License, or
685
+ * (at your option) any later version.
686
+ *
687
+ * This program is distributed in the hope that it will be useful, but WITHOUT
688
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
689
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
690
+ * for more details.
691
+ */
692
+
693
+#include "qemu/osdep.h"
694
+#include "libqtest-single.h"
695
+
696
+#define NR_GPIO_DEVICES (8)
697
+#define GPIO(x) (0xf0010000 + (x) * 0x1000)
698
+#define GPIO_IRQ(x) (116 + (x))
699
+
700
+/* GPIO registers */
701
+#define GP_N_TLOCK1 0x00
702
+#define GP_N_DIN 0x04 /* Data IN */
703
+#define GP_N_POL 0x08 /* Polarity */
704
+#define GP_N_DOUT 0x0c /* Data OUT */
705
+#define GP_N_OE 0x10 /* Output Enable */
706
+#define GP_N_OTYP 0x14
707
+#define GP_N_MP 0x18
708
+#define GP_N_PU 0x1c /* Pull-up */
709
+#define GP_N_PD 0x20 /* Pull-down */
710
+#define GP_N_DBNC 0x24 /* Debounce */
711
+#define GP_N_EVTYP 0x28 /* Event Type */
712
+#define GP_N_EVBE 0x2c /* Event Both Edge */
713
+#define GP_N_OBL0 0x30
714
+#define GP_N_OBL1 0x34
715
+#define GP_N_OBL2 0x38
716
+#define GP_N_OBL3 0x3c
717
+#define GP_N_EVEN 0x40 /* Event Enable */
718
+#define GP_N_EVENS 0x44 /* Event Set (enable) */
719
+#define GP_N_EVENC 0x48 /* Event Clear (disable) */
720
+#define GP_N_EVST 0x4c /* Event Status */
721
+#define GP_N_SPLCK 0x50
722
+#define GP_N_MPLCK 0x54
723
+#define GP_N_IEM 0x58 /* Input Enable */
724
+#define GP_N_OSRC 0x5c
725
+#define GP_N_ODSC 0x60
726
+#define GP_N_DOS 0x68 /* Data OUT Set */
727
+#define GP_N_DOC 0x6c /* Data OUT Clear */
728
+#define GP_N_OES 0x70 /* Output Enable Set */
729
+#define GP_N_OEC 0x74 /* Output Enable Clear */
730
+#define GP_N_TLOCK2 0x7c
731
+
732
+static void gpio_unlock(int n)
733
+{
734
+ if (readl(GPIO(n) + GP_N_TLOCK1) != 0) {
735
+ writel(GPIO(n) + GP_N_TLOCK2, 0xc0de1248);
736
+ writel(GPIO(n) + GP_N_TLOCK1, 0xc0defa73);
737
+ }
738
+}
739
+
740
+/* Restore the GPIO controller to a sensible default state. */
741
+static void gpio_reset(int n)
742
+{
743
+ gpio_unlock(0);
744
+
745
+ writel(GPIO(n) + GP_N_EVEN, 0x00000000);
746
+ writel(GPIO(n) + GP_N_EVST, 0xffffffff);
747
+ writel(GPIO(n) + GP_N_POL, 0x00000000);
748
+ writel(GPIO(n) + GP_N_DOUT, 0x00000000);
749
+ writel(GPIO(n) + GP_N_OE, 0x00000000);
750
+ writel(GPIO(n) + GP_N_OTYP, 0x00000000);
751
+ writel(GPIO(n) + GP_N_PU, 0xffffffff);
752
+ writel(GPIO(n) + GP_N_PD, 0x00000000);
753
+ writel(GPIO(n) + GP_N_IEM, 0xffffffff);
754
+}
755
+
756
+static void test_dout_to_din(void)
757
+{
758
+ gpio_reset(0);
759
+
760
+ /* When output is enabled, DOUT should be reflected on DIN. */
761
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
762
+ /* PU and PD shouldn't have any impact on DIN. */
763
+ writel(GPIO(0) + GP_N_PU, 0xffff0000);
764
+ writel(GPIO(0) + GP_N_PD, 0x0000ffff);
765
+ writel(GPIO(0) + GP_N_DOUT, 0x12345678);
766
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0x12345678);
767
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x12345678);
768
+}
769
+
770
+static void test_pullup_pulldown(void)
771
+{
772
+ gpio_reset(0);
773
+
774
+ /*
775
+ * When output is disabled, and PD is the inverse of PU, PU should be
776
+ * reflected on DIN. If PD is not the inverse of PU, the state of DIN is
777
+ * undefined, so we don't test that.
778
+ */
779
+ writel(GPIO(0) + GP_N_OE, 0x00000000);
780
+ /* DOUT shouldn't have any impact on DIN. */
781
+ writel(GPIO(0) + GP_N_DOUT, 0xffff0000);
782
+ writel(GPIO(0) + GP_N_PU, 0x23456789);
783
+ writel(GPIO(0) + GP_N_PD, ~0x23456789U);
784
+ g_assert_cmphex(readl(GPIO(0) + GP_N_PU), ==, 0x23456789);
785
+ g_assert_cmphex(readl(GPIO(0) + GP_N_PD), ==, ~0x23456789U);
786
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x23456789);
787
+}
788
+
789
+static void test_output_enable(void)
790
+{
791
+ gpio_reset(0);
792
+
793
+ /*
794
+ * With all pins weakly pulled down, and DOUT all-ones, OE should be
795
+ * reflected on DIN.
796
+ */
797
+ writel(GPIO(0) + GP_N_DOUT, 0xffffffff);
798
+ writel(GPIO(0) + GP_N_PU, 0x00000000);
799
+ writel(GPIO(0) + GP_N_PD, 0xffffffff);
800
+ writel(GPIO(0) + GP_N_OE, 0x3456789a);
801
+ g_assert_cmphex(readl(GPIO(0) + GP_N_OE), ==, 0x3456789a);
802
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x3456789a);
803
+
804
+ writel(GPIO(0) + GP_N_OEC, 0x00030002);
805
+ g_assert_cmphex(readl(GPIO(0) + GP_N_OE), ==, 0x34547898);
806
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x34547898);
807
+
808
+ writel(GPIO(0) + GP_N_OES, 0x0000f001);
809
+ g_assert_cmphex(readl(GPIO(0) + GP_N_OE), ==, 0x3454f899);
810
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x3454f899);
811
+}
812
+
813
+static void test_open_drain(void)
814
+{
815
+ gpio_reset(0);
816
+
817
+ /*
818
+ * Upper half of DOUT drives a 1 only if the corresponding bit in OTYP is
819
+ * not set. If OTYP is set, DIN is determined by PU/PD. Lower half of
820
+ * DOUT always drives a 0 regardless of OTYP; PU/PD have no effect. When
821
+ * OE is 0, output is determined by PU/PD; OTYP has no effect.
822
+ */
823
+ writel(GPIO(0) + GP_N_OTYP, 0x456789ab);
824
+ writel(GPIO(0) + GP_N_OE, 0xf0f0f0f0);
825
+ writel(GPIO(0) + GP_N_DOUT, 0xffff0000);
826
+ writel(GPIO(0) + GP_N_PU, 0xff00ff00);
827
+ writel(GPIO(0) + GP_N_PD, 0x00ff00ff);
828
+ g_assert_cmphex(readl(GPIO(0) + GP_N_OTYP), ==, 0x456789ab);
829
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0xff900f00);
830
+}
831
+
832
+static void test_polarity(void)
833
+{
834
+ gpio_reset(0);
835
+
836
+ /*
837
+ * In push-pull mode, DIN should reflect DOUT because the signal is
838
+ * inverted in both directions.
839
+ */
840
+ writel(GPIO(0) + GP_N_OTYP, 0x00000000);
841
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
842
+ writel(GPIO(0) + GP_N_DOUT, 0x56789abc);
843
+ writel(GPIO(0) + GP_N_POL, 0x6789abcd);
844
+ g_assert_cmphex(readl(GPIO(0) + GP_N_POL), ==, 0x6789abcd);
845
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0x56789abc);
846
+
847
+ /*
848
+ * When turning off the drivers, DIN should reflect the inverse of the
849
+ * pulled-up lines.
850
+ */
851
+ writel(GPIO(0) + GP_N_OE, 0x00000000);
852
+ writel(GPIO(0) + GP_N_POL, 0xffffffff);
853
+ writel(GPIO(0) + GP_N_PU, 0x789abcde);
854
+ writel(GPIO(0) + GP_N_PD, ~0x789abcdeU);
855
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, ~0x789abcdeU);
856
+
857
+ /*
858
+ * In open-drain mode, DOUT=1 will appear to drive the pin high (since DIN
859
+ * is inverted), while DOUT=0 will leave the pin floating.
860
+ */
861
+ writel(GPIO(0) + GP_N_OTYP, 0xffffffff);
862
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
863
+ writel(GPIO(0) + GP_N_PU, 0xffff0000);
864
+ writel(GPIO(0) + GP_N_PD, 0x0000ffff);
865
+ writel(GPIO(0) + GP_N_DOUT, 0xff00ff00);
866
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0xff00ffff);
867
+}
868
+
869
+static void test_input_mask(void)
870
+{
871
+ gpio_reset(0);
872
+
873
+ /* IEM=0 forces the input to zero before polarity inversion. */
874
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
875
+ writel(GPIO(0) + GP_N_DOUT, 0xff00ff00);
876
+ writel(GPIO(0) + GP_N_POL, 0xffff0000);
877
+ writel(GPIO(0) + GP_N_IEM, 0x87654321);
878
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DIN), ==, 0xff9a4300);
879
+}
880
+
881
+static void test_temp_lock(void)
882
+{
883
+ gpio_reset(0);
884
+
885
+ writel(GPIO(0) + GP_N_DOUT, 0x98765432);
886
+
887
+ /* Make sure we're unlocked initially. */
888
+ g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 0);
889
+ /* Writing any value to TLOCK1 will lock. */
890
+ writel(GPIO(0) + GP_N_TLOCK1, 0);
891
+ g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 1);
892
+ writel(GPIO(0) + GP_N_DOUT, 0xa9876543);
893
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0x98765432);
894
+ /* Now, try to unlock. */
895
+ gpio_unlock(0);
896
+ g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 0);
897
+ writel(GPIO(0) + GP_N_DOUT, 0xa9876543);
898
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0xa9876543);
899
+
900
+ /* Try it again, but write TLOCK2 to lock. */
901
+ writel(GPIO(0) + GP_N_TLOCK2, 0);
902
+ g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 1);
903
+ writel(GPIO(0) + GP_N_DOUT, 0x98765432);
904
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0xa9876543);
905
+ /* Now, try to unlock. */
906
+ gpio_unlock(0);
907
+ g_assert_cmphex(readl(GPIO(0) + GP_N_TLOCK1), ==, 0);
908
+ writel(GPIO(0) + GP_N_DOUT, 0x98765432);
909
+ g_assert_cmphex(readl(GPIO(0) + GP_N_DOUT), ==, 0x98765432);
910
+}
911
+
912
+static void test_events_level(void)
913
+{
914
+ gpio_reset(0);
915
+
916
+ writel(GPIO(0) + GP_N_EVTYP, 0x00000000);
917
+ writel(GPIO(0) + GP_N_DOUT, 0xba987654);
918
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
919
+ writel(GPIO(0) + GP_N_EVST, 0xffffffff);
920
+
921
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0xba987654);
922
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
923
+ writel(GPIO(0) + GP_N_DOUT, 0x00000000);
924
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0xba987654);
925
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
926
+ writel(GPIO(0) + GP_N_EVST, 0x00007654);
927
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0xba980000);
928
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
929
+ writel(GPIO(0) + GP_N_EVST, 0xba980000);
930
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
931
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
932
+}
933
+
934
+static void test_events_rising_edge(void)
935
+{
936
+ gpio_reset(0);
937
+
938
+ writel(GPIO(0) + GP_N_EVTYP, 0xffffffff);
939
+ writel(GPIO(0) + GP_N_EVBE, 0x00000000);
940
+ writel(GPIO(0) + GP_N_DOUT, 0xffff0000);
941
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
942
+ writel(GPIO(0) + GP_N_EVST, 0xffffffff);
943
+
944
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
945
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
946
+ writel(GPIO(0) + GP_N_DOUT, 0xff00ff00);
947
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x0000ff00);
948
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
949
+ writel(GPIO(0) + GP_N_DOUT, 0x00ff0000);
950
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00ffff00);
951
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
952
+ writel(GPIO(0) + GP_N_EVST, 0x0000f000);
953
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00ff0f00);
954
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
955
+ writel(GPIO(0) + GP_N_EVST, 0x00ff0f00);
956
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
957
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
958
+}
959
+
960
+static void test_events_both_edges(void)
961
+{
962
+ gpio_reset(0);
963
+
964
+ writel(GPIO(0) + GP_N_EVTYP, 0xffffffff);
965
+ writel(GPIO(0) + GP_N_EVBE, 0xffffffff);
966
+ writel(GPIO(0) + GP_N_DOUT, 0xffff0000);
967
+ writel(GPIO(0) + GP_N_OE, 0xffffffff);
968
+ writel(GPIO(0) + GP_N_EVST, 0xffffffff);
969
+
970
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
971
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
972
+ writel(GPIO(0) + GP_N_DOUT, 0xff00ff00);
973
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00ffff00);
974
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
975
+ writel(GPIO(0) + GP_N_DOUT, 0xef00ff08);
976
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x10ffff08);
977
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
978
+ writel(GPIO(0) + GP_N_EVST, 0x0000f000);
979
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x10ff0f08);
980
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
981
+ writel(GPIO(0) + GP_N_EVST, 0x10ff0f08);
982
+ g_assert_cmphex(readl(GPIO(0) + GP_N_EVST), ==, 0x00000000);
983
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(0)));
984
+}
985
+
986
+static void test_gpion_irq(gconstpointer test_data)
987
+{
988
+ intptr_t n = (intptr_t)test_data;
989
+
990
+ gpio_reset(n);
991
+
992
+ writel(GPIO(n) + GP_N_EVTYP, 0x00000000);
993
+ writel(GPIO(n) + GP_N_DOUT, 0x00000000);
994
+ writel(GPIO(n) + GP_N_OE, 0xffffffff);
995
+ writel(GPIO(n) + GP_N_EVST, 0xffffffff);
996
+ writel(GPIO(n) + GP_N_EVEN, 0x00000000);
997
+
998
+ /* Trigger an event; interrupts are masked. */
999
+ g_assert_cmphex(readl(GPIO(n) + GP_N_EVST), ==, 0x00000000);
1000
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1001
+ writel(GPIO(n) + GP_N_DOS, 0x00008000);
1002
+ g_assert_cmphex(readl(GPIO(n) + GP_N_EVST), ==, 0x00008000);
1003
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1004
+
1005
+ /* Unmask all event interrupts; verify that the interrupt fired. */
1006
+ writel(GPIO(n) + GP_N_EVEN, 0xffffffff);
1007
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1008
+
1009
+ /* Clear the current bit, set a new bit, irq stays asserted. */
1010
+ writel(GPIO(n) + GP_N_DOC, 0x00008000);
1011
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1012
+ writel(GPIO(n) + GP_N_DOS, 0x00000200);
1013
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1014
+ writel(GPIO(n) + GP_N_EVST, 0x00008000);
1015
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1016
+
1017
+ /* Mask/unmask the event that's currently active. */
1018
+ writel(GPIO(n) + GP_N_EVENC, 0x00000200);
1019
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1020
+ writel(GPIO(n) + GP_N_EVENS, 0x00000200);
1021
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1022
+
1023
+ /* Clear the input and the status bit, irq is deasserted. */
1024
+ writel(GPIO(n) + GP_N_DOC, 0x00000200);
1025
+ g_assert_true(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1026
+ writel(GPIO(n) + GP_N_EVST, 0x00000200);
1027
+ g_assert_false(qtest_get_irq(global_qtest, GPIO_IRQ(n)));
1028
+}
1029
+
1030
+int main(int argc, char **argv)
1031
+{
1032
+ int ret;
1033
+ int i;
1034
+
1035
+ g_test_init(&argc, &argv, NULL);
1036
+ g_test_set_nonfatal_assertions();
1037
+
1038
+ qtest_add_func("/npcm7xx_gpio/dout_to_din", test_dout_to_din);
1039
+ qtest_add_func("/npcm7xx_gpio/pullup_pulldown", test_pullup_pulldown);
1040
+ qtest_add_func("/npcm7xx_gpio/output_enable", test_output_enable);
1041
+ qtest_add_func("/npcm7xx_gpio/open_drain", test_open_drain);
1042
+ qtest_add_func("/npcm7xx_gpio/polarity", test_polarity);
1043
+ qtest_add_func("/npcm7xx_gpio/input_mask", test_input_mask);
1044
+ qtest_add_func("/npcm7xx_gpio/temp_lock", test_temp_lock);
1045
+ qtest_add_func("/npcm7xx_gpio/events/level", test_events_level);
1046
+ qtest_add_func("/npcm7xx_gpio/events/rising_edge", test_events_rising_edge);
1047
+ qtest_add_func("/npcm7xx_gpio/events/both_edges", test_events_both_edges);
1048
+
1049
+ for (i = 0; i < NR_GPIO_DEVICES; i++) {
1050
+ g_autofree char *test_name =
1051
+ g_strdup_printf("/npcm7xx_gpio/gpio[%d]/irq", i);
1052
+ qtest_add_data_func(test_name, (void *)(intptr_t)i, test_gpion_irq);
1053
+ }
1054
+
1055
+ qtest_start("-machine npcm750-evb");
1056
+ qtest_irq_intercept_in(global_qtest, "/machine/soc/a9mpcore/gic");
1057
+ ret = g_test_run();
1058
+ qtest_end();
1059
+
1060
+ return ret;
1061
+}
1062
diff --git a/hw/gpio/meson.build b/hw/gpio/meson.build
629
index XXXXXXX..XXXXXXX 100644
1063
index XXXXXXX..XXXXXXX 100644
630
--- a/MAINTAINERS
1064
--- a/hw/gpio/meson.build
631
+++ b/MAINTAINERS
1065
+++ b/hw/gpio/meson.build
632
@@ -XXX,XX +XXX,XX @@ F: hw/timer/pl031.c
1066
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_gpio.c'))
633
F: include/hw/arm/primecell.h
1067
softmmu_ss.add(when: 'CONFIG_ZAURUS', if_true: files('zaurus.c'))
634
F: hw/timer/cmsdk-apb-timer.c
1068
635
F: include/hw/timer/cmsdk-apb-timer.h
1069
softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_gpio.c'))
636
+F: hw/timer/cmsdk-apb-dualtimer.c
1070
+softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_gpio.c'))
637
+F: include/hw/timer/cmsdk-apb-dualtimer.h
1071
softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_gpio.c'))
638
F: hw/char/cmsdk-apb-uart.c
1072
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_gpio.c'))
639
F: include/hw/char/cmsdk-apb-uart.h
1073
softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_gpio.c'))
640
F: hw/watchdog/cmsdk-apb-watchdog.c
1074
diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events
641
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
642
index XXXXXXX..XXXXXXX 100644
1075
index XXXXXXX..XXXXXXX 100644
643
--- a/default-configs/arm-softmmu.mak
1076
--- a/hw/gpio/trace-events
644
+++ b/default-configs/arm-softmmu.mak
1077
+++ b/hw/gpio/trace-events
645
@@ -XXX,XX +XXX,XX @@ CONFIG_STM32F2XX_SPI=y
1078
@@ -XXX,XX +XXX,XX @@
646
CONFIG_STM32F205_SOC=y
1079
# See docs/devel/tracing.txt for syntax documentation.
647
1080
648
CONFIG_CMSDK_APB_TIMER=y
1081
+# npcm7xx_gpio.c
649
+CONFIG_CMSDK_APB_DUALTIMER=y
1082
+npcm7xx_gpio_read(const char *id, uint64_t offset, uint64_t value) " %s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
650
CONFIG_CMSDK_APB_UART=y
1083
+npcm7xx_gpio_write(const char *id, uint64_t offset, uint64_t value) "%s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
651
CONFIG_CMSDK_APB_WATCHDOG=y
1084
+npcm7xx_gpio_set_input(const char *id, int32_t line, int32_t level) "%s line: %" PRIi32 " level: %" PRIi32
652
1085
+npcm7xx_gpio_set_output(const char *id, int32_t line, int32_t level) "%s line: %" PRIi32 " level: %" PRIi32
653
diff --git a/hw/timer/trace-events b/hw/timer/trace-events
1086
+npcm7xx_gpio_update_events(const char *id, uint32_t evst, uint32_t even) "%s evst: 0x%08" PRIx32 " even: 0x%08" PRIx32
1087
+
1088
# nrf51_gpio.c
1089
nrf51_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" PRIx64
1090
nrf51_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x%" PRIx64
1091
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
654
index XXXXXXX..XXXXXXX 100644
1092
index XXXXXXX..XXXXXXX 100644
655
--- a/hw/timer/trace-events
1093
--- a/tests/qtest/meson.build
656
+++ b/hw/timer/trace-events
1094
+++ b/tests/qtest/meson.build
657
@@ -XXX,XX +XXX,XX @@ cmsdk_apb_timer_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB t
1095
@@ -XXX,XX +XXX,XX @@ qtests_sparc64 = \
658
cmsdk_apb_timer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB timer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
1096
['prom-env-test', 'boot-serial-test']
659
cmsdk_apb_timer_reset(void) "CMSDK APB timer: reset"
1097
660
1098
qtests_npcm7xx = \
661
+# hw/timer/cmsdk_apb_dualtimer.c
1099
- ['npcm7xx_rng-test',
662
+cmsdk_apb_dualtimer_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB dualtimer read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
1100
+ ['npcm7xx_gpio-test',
663
+cmsdk_apb_dualtimer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB dualtimer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
1101
+ 'npcm7xx_rng-test',
664
+cmsdk_apb_dualtimer_reset(void) "CMSDK APB dualtimer: reset"
1102
'npcm7xx_timer-test',
665
+
1103
'npcm7xx_watchdog_timer-test']
666
# hw/timer/xlnx-zynqmp-rtc.c
1104
qtests_arm = \
667
xlnx_zynqmp_rtc_gettime(int year, int month, int day, int hour, int min, int sec) "Get time from host: %d-%d-%d %2d:%02d:%02d"
668
--
1105
--
669
2.18.0
1106
2.20.1
670
1107
671
1108
diff view generated by jsdifflib
1
Some of the config register values we were setting for the MPS2 SCC
1
From: Zenghui Yu <yuzenghui@huawei.com>
2
weren't correct:
3
* the SCC_AID bits [23:20] specify the FPGA build target board revision,
4
and the SCC_CFG4 register specifies the actual board revision, so
5
these should have matching values. Claim to be board revision C,
6
consistently -- we had the revision in the wrong part of SCC_AID.
7
* SCC_ID bits [15:4] should be 0x505, not decimal 505
8
2
3
Ensure the vSMMUv3 will be restored before all PCIe devices so that DMA
4
translation can work properly during migration.
5
6
Signed-off-by: Zenghui Yu <yuzenghui@huawei.com>
7
Message-id: 20201019091508.197-1-yuzenghui@huawei.com
8
Acked-by: Eric Auger <eric.auger@redhat.com>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Message-id: 20180820141116.9118-23-peter.maydell@linaro.org
11
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
12
---
10
---
13
hw/arm/mps2-tz.c | 4 ++--
11
hw/arm/smmuv3.c | 1 +
14
1 file changed, 2 insertions(+), 2 deletions(-)
12
1 file changed, 1 insertion(+)
15
13
16
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
14
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
17
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/arm/mps2-tz.c
16
--- a/hw/arm/smmuv3.c
19
+++ b/hw/arm/mps2-tz.c
17
+++ b/hw/arm/smmuv3.c
20
@@ -XXX,XX +XXX,XX @@ static MemoryRegion *make_scc(MPS2TZMachineState *mms, void *opaque,
18
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_smmuv3 = {
21
sccdev = DEVICE(scc);
19
.name = "smmuv3",
22
qdev_set_parent_bus(sccdev, sysbus_get_default());
20
.version_id = 1,
23
qdev_prop_set_uint32(sccdev, "scc-cfg4", 0x2);
21
.minimum_version_id = 1,
24
- qdev_prop_set_uint32(sccdev, "scc-aid", 0x02000008);
22
+ .priority = MIG_PRI_IOMMU,
25
+ qdev_prop_set_uint32(sccdev, "scc-aid", 0x00200008);
23
.fields = (VMStateField[]) {
26
qdev_prop_set_uint32(sccdev, "scc-id", mmc->scc_id);
24
VMSTATE_UINT32(features, SMMUv3State),
27
object_property_set_bool(OBJECT(scc), true, "realized", &error_fatal);
25
VMSTATE_UINT8(sid_size, SMMUv3State),
28
return sysbus_mmio_get_region(SYS_BUS_DEVICE(sccdev), 0);
29
@@ -XXX,XX +XXX,XX @@ static void mps2tz_an505_class_init(ObjectClass *oc, void *data)
30
mc->desc = "ARM MPS2 with AN505 FPGA image for Cortex-M33";
31
mmc->fpga_type = FPGA_AN505;
32
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m33");
33
- mmc->scc_id = 0x41040000 | (505 << 4);
34
+ mmc->scc_id = 0x41045050;
35
}
36
37
static const TypeInfo mps2tz_info = {
38
--
26
--
39
2.18.0
27
2.20.1
40
28
41
29
diff view generated by jsdifflib
1
Move from the legacy SysBusDevice::init method to using
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
DeviceState::realize.
3
2
3
No code out of bcm2836.c uses (or requires) the BCM283XInfo
4
declarations. Move it locally to the C source file.
5
6
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
7
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Message-id: 20201024170127.3592182-2-f4bug@amsat.org
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Message-id: 20180820141116.9118-19-peter.maydell@linaro.org
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
---
10
---
9
hw/ssi/pl022.c | 8 +++-----
11
include/hw/arm/bcm2836.h | 8 --------
10
1 file changed, 3 insertions(+), 5 deletions(-)
12
hw/arm/bcm2836.c | 14 ++++++++++++++
13
2 files changed, 14 insertions(+), 8 deletions(-)
11
14
12
diff --git a/hw/ssi/pl022.c b/hw/ssi/pl022.c
15
diff --git a/include/hw/arm/bcm2836.h b/include/hw/arm/bcm2836.h
13
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/ssi/pl022.c
17
--- a/include/hw/arm/bcm2836.h
15
+++ b/hw/ssi/pl022.c
18
+++ b/include/hw/arm/bcm2836.h
16
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_pl022 = {
19
@@ -XXX,XX +XXX,XX @@ struct BCM283XState {
17
}
20
BCM2835PeripheralState peripherals;
18
};
21
};
19
22
20
-static int pl022_init(SysBusDevice *sbd)
23
-typedef struct BCM283XInfo BCM283XInfo;
21
+static void pl022_realize(DeviceState *dev, Error **errp)
24
-
22
{
25
-struct BCM283XClass {
23
- DeviceState *dev = DEVICE(sbd);
26
- DeviceClass parent_class;
24
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
27
- const BCM283XInfo *info;
25
PL022State *s = PL022(dev);
28
-};
26
29
-
27
memory_region_init_io(&s->iomem, OBJECT(s), &pl022_ops, s, "pl022", 0x1000);
30
-
28
sysbus_init_mmio(sbd, &s->iomem);
31
#endif /* BCM2836_H */
29
sysbus_init_irq(sbd, &s->irq);
32
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
30
s->ssi = ssi_create_bus(dev, "ssi");
33
index XXXXXXX..XXXXXXX 100644
31
- return 0;
34
--- a/hw/arm/bcm2836.c
32
}
35
+++ b/hw/arm/bcm2836.c
33
36
@@ -XXX,XX +XXX,XX @@
34
static void pl022_class_init(ObjectClass *klass, void *data)
37
#include "hw/arm/raspi_platform.h"
35
{
38
#include "hw/sysbus.h"
36
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
39
37
DeviceClass *dc = DEVICE_CLASS(klass);
40
+typedef struct BCM283XInfo BCM283XInfo;
38
41
+
39
- sdc->init = pl022_init;
42
+typedef struct BCM283XClass {
40
dc->reset = pl022_reset;
43
+ /*< private >*/
41
dc->vmsd = &vmstate_pl022;
44
+ DeviceClass parent_class;
42
+ dc->realize = pl022_realize;
45
+ /*< public >*/
43
}
46
+ const BCM283XInfo *info;
44
47
+} BCM283XClass;
45
static const TypeInfo pl022_info = {
48
+
49
struct BCM283XInfo {
50
const char *name;
51
const char *cpu_type;
52
@@ -XXX,XX +XXX,XX @@ struct BCM283XInfo {
53
int clusterid;
54
};
55
56
+#define BCM283X_CLASS(klass) \
57
+ OBJECT_CLASS_CHECK(BCM283XClass, (klass), TYPE_BCM283X)
58
+#define BCM283X_GET_CLASS(obj) \
59
+ OBJECT_GET_CLASS(BCM283XClass, (obj), TYPE_BCM283X)
60
+
61
static const BCM283XInfo bcm283x_socs[] = {
62
{
63
.name = TYPE_BCM2836,
46
--
64
--
47
2.18.0
65
2.20.1
48
66
49
67
diff view generated by jsdifflib
1
The bcm2835_fb's initial resolution and other parameters are set
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
via QOM properties. We should reset to those initial values on
2
3
device reset, which means we need to save the QOM property
3
Remove usage of TypeInfo::class_data. Instead fill the fields in
4
values somewhere that they are not overwritten by guest
4
the corresponding class_init().
5
changes to the framebuffer configuration.
5
6
6
So far all children use the same values for almost all fields,
7
but we are going to add the BCM2711/BCM2838 SoC for the raspi4
8
machine which use different fields.
9
10
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
11
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
12
Message-id: 20201024170127.3592182-3-f4bug@amsat.org
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Message-id: 20180814144436.679-5-peter.maydell@linaro.org
10
---
14
---
11
include/hw/display/bcm2835_fb.h | 1 +
15
hw/arm/bcm2836.c | 108 ++++++++++++++++++++++-------------------------
12
hw/display/bcm2835_fb.c | 27 +++++++++++++++------------
16
1 file changed, 51 insertions(+), 57 deletions(-)
13
2 files changed, 16 insertions(+), 12 deletions(-)
17
14
18
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
15
diff --git a/include/hw/display/bcm2835_fb.h b/include/hw/display/bcm2835_fb.h
16
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
17
--- a/include/hw/display/bcm2835_fb.h
20
--- a/hw/arm/bcm2836.c
18
+++ b/include/hw/display/bcm2835_fb.h
21
+++ b/hw/arm/bcm2836.c
19
@@ -XXX,XX +XXX,XX @@ typedef struct {
22
@@ -XXX,XX +XXX,XX @@
20
bool lock, invalidate, pending;
23
#include "hw/arm/raspi_platform.h"
21
24
#include "hw/sysbus.h"
22
BCM2835FBConfig config;
25
23
+ BCM2835FBConfig initial_config;
26
-typedef struct BCM283XInfo BCM283XInfo;
24
} BCM2835FBState;
27
-
25
28
typedef struct BCM283XClass {
26
void bcm2835_fb_reconfigure(BCM2835FBState *s, BCM2835FBConfig *newconfig);
29
/*< private >*/
27
diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c
30
DeviceClass parent_class;
28
index XXXXXXX..XXXXXXX 100644
31
/*< public >*/
29
--- a/hw/display/bcm2835_fb.c
32
- const BCM283XInfo *info;
30
+++ b/hw/display/bcm2835_fb.c
33
-} BCM283XClass;
31
@@ -XXX,XX +XXX,XX @@ static void bcm2835_fb_reset(DeviceState *dev)
34
-
32
35
-struct BCM283XInfo {
33
s->pending = false;
36
const char *name;
34
37
const char *cpu_type;
35
- s->config.xres_virtual = s->config.xres;
38
hwaddr peri_base; /* Peripheral base address seen by the CPU */
36
- s->config.yres_virtual = s->config.yres;
39
hwaddr ctrl_base; /* Interrupt controller and mailboxes etc. */
37
- s->config.xoffset = 0;
40
int clusterid;
38
- s->config.yoffset = 0;
41
-};
39
- s->config.base = s->vcram_base + BCM2835_FB_OFFSET;
42
+} BCM283XClass;
40
+ s->config = s->initial_config;
43
41
44
#define BCM283X_CLASS(klass) \
42
s->invalidate = true;
45
OBJECT_CLASS_CHECK(BCM283XClass, (klass), TYPE_BCM283X)
43
s->lock = false;
46
#define BCM283X_GET_CLASS(obj) \
44
@@ -XXX,XX +XXX,XX @@ static void bcm2835_fb_realize(DeviceState *dev, Error **errp)
47
OBJECT_GET_CLASS(BCM283XClass, (obj), TYPE_BCM283X)
48
49
-static const BCM283XInfo bcm283x_socs[] = {
50
- {
51
- .name = TYPE_BCM2836,
52
- .cpu_type = ARM_CPU_TYPE_NAME("cortex-a7"),
53
- .peri_base = 0x3f000000,
54
- .ctrl_base = 0x40000000,
55
- .clusterid = 0xf,
56
- },
57
-#ifdef TARGET_AARCH64
58
- {
59
- .name = TYPE_BCM2837,
60
- .cpu_type = ARM_CPU_TYPE_NAME("cortex-a53"),
61
- .peri_base = 0x3f000000,
62
- .ctrl_base = 0x40000000,
63
- .clusterid = 0x0,
64
- },
65
-#endif
66
-};
67
-
68
static void bcm2836_init(Object *obj)
69
{
70
BCM283XState *s = BCM283X(obj);
71
BCM283XClass *bc = BCM283X_GET_CLASS(obj);
72
- const BCM283XInfo *info = bc->info;
73
int n;
74
75
for (n = 0; n < BCM283X_NCPUS; n++) {
76
object_initialize_child(obj, "cpu[*]", &s->cpu[n].core,
77
- info->cpu_type);
78
+ bc->cpu_type);
79
}
80
81
object_initialize_child(obj, "control", &s->control, TYPE_BCM2836_CONTROL);
82
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
83
{
84
BCM283XState *s = BCM283X(dev);
85
BCM283XClass *bc = BCM283X_GET_CLASS(dev);
86
- const BCM283XInfo *info = bc->info;
87
Object *obj;
88
int n;
89
90
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
91
"sd-bus");
92
93
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0,
94
- info->peri_base, 1);
95
+ bc->peri_base, 1);
96
97
/* bcm2836 interrupt controller (and mailboxes, etc.) */
98
if (!sysbus_realize(SYS_BUS_DEVICE(&s->control), errp)) {
45
return;
99
return;
46
}
100
}
47
101
48
+ /* Fill in the parts of initial_config that are not set by QOM properties */
102
- sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, info->ctrl_base);
49
+ s->initial_config.xres_virtual = s->initial_config.xres;
103
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->control), 0, bc->ctrl_base);
50
+ s->initial_config.yres_virtual = s->initial_config.yres;
104
51
+ s->initial_config.xoffset = 0;
105
sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
52
+ s->initial_config.yoffset = 0;
106
qdev_get_gpio_in_named(DEVICE(&s->control), "gpu-irq", 0));
53
+ s->initial_config.base = s->vcram_base + BCM2835_FB_OFFSET;
107
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
108
109
for (n = 0; n < BCM283X_NCPUS; n++) {
110
/* TODO: this should be converted to a property of ARM_CPU */
111
- s->cpu[n].core.mp_affinity = (info->clusterid << 8) | n;
112
+ s->cpu[n].core.mp_affinity = (bc->clusterid << 8) | n;
113
114
/* set periphbase/CBAR value for CPU-local registers */
115
if (!object_property_set_int(OBJECT(&s->cpu[n].core), "reset-cbar",
116
- info->peri_base, errp)) {
117
+ bc->peri_base, errp)) {
118
return;
119
}
120
121
@@ -XXX,XX +XXX,XX @@ static Property bcm2836_props[] = {
122
static void bcm283x_class_init(ObjectClass *oc, void *data)
123
{
124
DeviceClass *dc = DEVICE_CLASS(oc);
125
- BCM283XClass *bc = BCM283X_CLASS(oc);
126
127
- bc->info = data;
128
- dc->realize = bcm2836_realize;
129
- device_class_set_props(dc, bcm2836_props);
130
/* Reason: Must be wired up in code (see raspi_init() function) */
131
dc->user_creatable = false;
132
}
133
134
-static const TypeInfo bcm283x_type_info = {
135
- .name = TYPE_BCM283X,
136
- .parent = TYPE_DEVICE,
137
- .instance_size = sizeof(BCM283XState),
138
- .instance_init = bcm2836_init,
139
- .class_size = sizeof(BCM283XClass),
140
- .abstract = true,
141
+static void bcm2836_class_init(ObjectClass *oc, void *data)
142
+{
143
+ DeviceClass *dc = DEVICE_CLASS(oc);
144
+ BCM283XClass *bc = BCM283X_CLASS(oc);
54
+
145
+
55
s->dma_mr = MEMORY_REGION(obj);
146
+ bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a7");
56
address_space_init(&s->dma_as, s->dma_mr, NULL);
147
+ bc->peri_base = 0x3f000000;
57
148
+ bc->ctrl_base = 0x40000000;
58
@@ -XXX,XX +XXX,XX @@ static Property bcm2835_fb_props[] = {
149
+ bc->clusterid = 0xf;
59
DEFINE_PROP_UINT32("vcram-base", BCM2835FBState, vcram_base, 0),/*required*/
150
+ dc->realize = bcm2836_realize;
60
DEFINE_PROP_UINT32("vcram-size", BCM2835FBState, vcram_size,
151
+ device_class_set_props(dc, bcm2836_props);
61
DEFAULT_VCRAM_SIZE),
62
- DEFINE_PROP_UINT32("xres", BCM2835FBState, config.xres, 640),
63
- DEFINE_PROP_UINT32("yres", BCM2835FBState, config.yres, 480),
64
- DEFINE_PROP_UINT32("bpp", BCM2835FBState, config.bpp, 16),
65
- DEFINE_PROP_UINT32("pixo",
66
- BCM2835FBState, config.pixo, 1), /* 1=RGB, 0=BGR */
67
- DEFINE_PROP_UINT32("alpha",
68
- BCM2835FBState, config.alpha, 2), /* alpha ignored */
69
+ DEFINE_PROP_UINT32("xres", BCM2835FBState, initial_config.xres, 640),
70
+ DEFINE_PROP_UINT32("yres", BCM2835FBState, initial_config.yres, 480),
71
+ DEFINE_PROP_UINT32("bpp", BCM2835FBState, initial_config.bpp, 16),
72
+ DEFINE_PROP_UINT32("pixo", BCM2835FBState,
73
+ initial_config.pixo, 1), /* 1=RGB, 0=BGR */
74
+ DEFINE_PROP_UINT32("alpha", BCM2835FBState,
75
+ initial_config.alpha, 2), /* alpha ignored */
76
DEFINE_PROP_END_OF_LIST()
77
};
152
};
78
153
154
-static void bcm2836_register_types(void)
155
+#ifdef TARGET_AARCH64
156
+static void bcm2837_class_init(ObjectClass *oc, void *data)
157
{
158
- int i;
159
+ DeviceClass *dc = DEVICE_CLASS(oc);
160
+ BCM283XClass *bc = BCM283X_CLASS(oc);
161
162
- type_register_static(&bcm283x_type_info);
163
- for (i = 0; i < ARRAY_SIZE(bcm283x_socs); i++) {
164
- TypeInfo ti = {
165
- .name = bcm283x_socs[i].name,
166
- .parent = TYPE_BCM283X,
167
- .class_init = bcm283x_class_init,
168
- .class_data = (void *) &bcm283x_socs[i],
169
- };
170
- type_register(&ti);
171
+ bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a53");
172
+ bc->peri_base = 0x3f000000;
173
+ bc->ctrl_base = 0x40000000;
174
+ bc->clusterid = 0x0;
175
+ dc->realize = bcm2836_realize;
176
+ device_class_set_props(dc, bcm2836_props);
177
+};
178
+#endif
179
+
180
+static const TypeInfo bcm283x_types[] = {
181
+ {
182
+ .name = TYPE_BCM2836,
183
+ .parent = TYPE_BCM283X,
184
+ .class_init = bcm2836_class_init,
185
+#ifdef TARGET_AARCH64
186
+ }, {
187
+ .name = TYPE_BCM2837,
188
+ .parent = TYPE_BCM283X,
189
+ .class_init = bcm2837_class_init,
190
+#endif
191
+ }, {
192
+ .name = TYPE_BCM283X,
193
+ .parent = TYPE_DEVICE,
194
+ .instance_size = sizeof(BCM283XState),
195
+ .instance_init = bcm2836_init,
196
+ .class_size = sizeof(BCM283XClass),
197
+ .class_init = bcm283x_class_init,
198
+ .abstract = true,
199
}
200
-}
201
+};
202
203
-type_init(bcm2836_register_types)
204
+DEFINE_TYPES(bcm283x_types)
79
--
205
--
80
2.18.0
206
2.20.1
81
207
82
208
diff view generated by jsdifflib
1
In the PL022, register offset 0x20 is the ICR, a write-only
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
interrupt-clear register. Register offset 0x24 is DMACR, the DMA
3
control register. We were incorrectly implementing (a stub version
4
of) DMACR at 0x20, and not implementing anything at 0x24. Fix this
5
bug.
6
2
3
The BCM2835 has only one core. Introduce the core_count field to
4
be able to use values different than BCM283X_NCPUS (4).
5
6
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
7
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Message-id: 20201024170127.3592182-4-f4bug@amsat.org
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Message-id: 20180820141116.9118-21-peter.maydell@linaro.org
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
---
10
---
11
hw/ssi/pl022.c | 12 ++++++++++--
11
hw/arm/bcm2836.c | 5 ++++-
12
1 file changed, 10 insertions(+), 2 deletions(-)
12
1 file changed, 4 insertions(+), 1 deletion(-)
13
13
14
diff --git a/hw/ssi/pl022.c b/hw/ssi/pl022.c
14
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
15
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/ssi/pl022.c
16
--- a/hw/arm/bcm2836.c
17
+++ b/hw/ssi/pl022.c
17
+++ b/hw/arm/bcm2836.c
18
@@ -XXX,XX +XXX,XX @@ static uint64_t pl022_read(void *opaque, hwaddr offset,
18
@@ -XXX,XX +XXX,XX @@ typedef struct BCM283XClass {
19
return s->is;
19
/*< public >*/
20
case 0x1c: /* MIS */
20
const char *name;
21
return s->im & s->is;
21
const char *cpu_type;
22
- case 0x20: /* DMACR */
22
+ unsigned core_count;
23
+ case 0x24: /* DMACR */
23
hwaddr peri_base; /* Peripheral base address seen by the CPU */
24
/* Not implemented. */
24
hwaddr ctrl_base; /* Interrupt controller and mailboxes etc. */
25
return 0;
25
int clusterid;
26
default:
26
@@ -XXX,XX +XXX,XX @@ static void bcm2836_init(Object *obj)
27
@@ -XXX,XX +XXX,XX @@ static void pl022_write(void *opaque, hwaddr offset,
27
BCM283XClass *bc = BCM283X_GET_CLASS(obj);
28
s->im = value;
28
int n;
29
pl022_update(s);
29
30
break;
30
- for (n = 0; n < BCM283X_NCPUS; n++) {
31
- case 0x20: /* DMACR */
31
+ for (n = 0; n < bc->core_count; n++) {
32
+ case 0x20: /* ICR */
32
object_initialize_child(obj, "cpu[*]", &s->cpu[n].core,
33
+ /*
33
bc->cpu_type);
34
+ * write-1-to-clear: bit 0 clears ROR, bit 1 clears RT;
34
}
35
+ * RX and TX interrupts cannot be cleared this way.
35
@@ -XXX,XX +XXX,XX @@ static void bcm2836_class_init(ObjectClass *oc, void *data)
36
+ */
36
BCM283XClass *bc = BCM283X_CLASS(oc);
37
+ value &= PL022_INT_ROR | PL022_INT_RT;
37
38
+ s->is &= ~value;
38
bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a7");
39
+ break;
39
+ bc->core_count = BCM283X_NCPUS;
40
+ case 0x24: /* DMACR */
40
bc->peri_base = 0x3f000000;
41
if (value) {
41
bc->ctrl_base = 0x40000000;
42
qemu_log_mask(LOG_UNIMP, "pl022: DMA not implemented\n");
42
bc->clusterid = 0xf;
43
}
43
@@ -XXX,XX +XXX,XX @@ static void bcm2837_class_init(ObjectClass *oc, void *data)
44
BCM283XClass *bc = BCM283X_CLASS(oc);
45
46
bc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a53");
47
+ bc->core_count = BCM283X_NCPUS;
48
bc->peri_base = 0x3f000000;
49
bc->ctrl_base = 0x40000000;
50
bc->clusterid = 0x0;
44
--
51
--
45
2.18.0
52
2.20.1
46
53
47
54
diff view generated by jsdifflib
1
Currently the PL022 calls pl022_reset() from its class init
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
function. Make it register a DeviceState reset method instead,
3
so that we reset the device on system reset.
4
2
3
It makes no sense to set enabled-cpus=0 on single core SoCs.
4
5
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
6
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Message-id: 20201024170127.3592182-5-f4bug@amsat.org
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Message-id: 20180820141116.9118-17-peter.maydell@linaro.org
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
---
9
---
10
hw/ssi/pl022.c | 7 +++++--
10
hw/arm/bcm2836.c | 15 +++++++--------
11
1 file changed, 5 insertions(+), 2 deletions(-)
11
1 file changed, 7 insertions(+), 8 deletions(-)
12
12
13
diff --git a/hw/ssi/pl022.c b/hw/ssi/pl022.c
13
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
14
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/ssi/pl022.c
15
--- a/hw/arm/bcm2836.c
16
+++ b/hw/ssi/pl022.c
16
+++ b/hw/arm/bcm2836.c
17
@@ -XXX,XX +XXX,XX @@ static void pl022_write(void *opaque, hwaddr offset,
17
@@ -XXX,XX +XXX,XX @@ typedef struct BCM283XClass {
18
#define BCM283X_GET_CLASS(obj) \
19
OBJECT_GET_CLASS(BCM283XClass, (obj), TYPE_BCM283X)
20
21
+static Property bcm2836_enabled_cores_property =
22
+ DEFINE_PROP_UINT32("enabled-cpus", BCM283XState, enabled_cpus, 0);
23
+
24
static void bcm2836_init(Object *obj)
25
{
26
BCM283XState *s = BCM283X(obj);
27
@@ -XXX,XX +XXX,XX @@ static void bcm2836_init(Object *obj)
28
object_initialize_child(obj, "cpu[*]", &s->cpu[n].core,
29
bc->cpu_type);
30
}
31
+ if (bc->core_count > 1) {
32
+ qdev_property_add_static(DEVICE(obj), &bcm2836_enabled_cores_property);
33
+ qdev_prop_set_uint32(DEVICE(obj), "enabled-cpus", bc->core_count);
34
+ }
35
36
object_initialize_child(obj, "control", &s->control, TYPE_BCM2836_CONTROL);
37
38
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
18
}
39
}
19
}
40
}
20
41
21
-static void pl022_reset(PL022State *s)
42
-static Property bcm2836_props[] = {
22
+static void pl022_reset(DeviceState *dev)
43
- DEFINE_PROP_UINT32("enabled-cpus", BCM283XState, enabled_cpus,
44
- BCM283X_NCPUS),
45
- DEFINE_PROP_END_OF_LIST()
46
-};
47
-
48
static void bcm283x_class_init(ObjectClass *oc, void *data)
23
{
49
{
24
+ PL022State *s = PL022(dev);
50
DeviceClass *dc = DEVICE_CLASS(oc);
25
+
51
@@ -XXX,XX +XXX,XX @@ static void bcm2836_class_init(ObjectClass *oc, void *data)
26
s->rx_fifo_len = 0;
52
bc->ctrl_base = 0x40000000;
27
s->tx_fifo_len = 0;
53
bc->clusterid = 0xf;
28
s->im = 0;
54
dc->realize = bcm2836_realize;
29
@@ -XXX,XX +XXX,XX @@ static int pl022_init(SysBusDevice *sbd)
55
- device_class_set_props(dc, bcm2836_props);
30
sysbus_init_mmio(sbd, &s->iomem);
56
};
31
sysbus_init_irq(sbd, &s->irq);
57
32
s->ssi = ssi_create_bus(dev, "ssi");
58
#ifdef TARGET_AARCH64
33
- pl022_reset(s);
59
@@ -XXX,XX +XXX,XX @@ static void bcm2837_class_init(ObjectClass *oc, void *data)
34
vmstate_register(dev, -1, &vmstate_pl022, s);
60
bc->ctrl_base = 0x40000000;
35
return 0;
61
bc->clusterid = 0x0;
36
}
62
dc->realize = bcm2836_realize;
37
@@ -XXX,XX +XXX,XX @@ static int pl022_init(SysBusDevice *sbd)
63
- device_class_set_props(dc, bcm2836_props);
38
static void pl022_class_init(ObjectClass *klass, void *data)
64
};
39
{
65
#endif
40
SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
66
41
+ DeviceClass *dc = DEVICE_CLASS(klass);
42
43
sdc->init = pl022_init;
44
+ dc->reset = pl022_reset;
45
}
46
47
static const TypeInfo pl022_info = {
48
--
67
--
49
2.18.0
68
2.20.1
50
69
51
70
diff view generated by jsdifflib
1
For the A15MPCore internal peripheral object, we handle GIC
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
security extensions support by checking whether the CPUs
3
have EL3 enabled; if so then we enable it also on the GIC.
4
Handle the virtualization extensions in the same way: if the
5
CPU has EL2 then enable it on the GIC and wire up the
6
virtualization-specific memory regions and the maintenance
7
interrupt.
8
2
3
The realize() function is clearly composed of two parts,
4
each described by a comment:
5
6
void realize()
7
{
8
/* common peripherals from bcm2835 */
9
...
10
/* bcm2836 interrupt controller (and mailboxes, etc.) */
11
...
12
}
13
14
Split the two part, so we can reuse the common part with other
15
SoCs from this family.
16
17
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
18
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
19
Message-id: 20201024170127.3592182-6-f4bug@amsat.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
20
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
11
Message-id: 20180821132811.17675-8-peter.maydell@linaro.org
12
---
21
---
13
hw/cpu/a15mpcore.c | 31 ++++++++++++++++++++++++++++---
22
hw/arm/bcm2836.c | 22 ++++++++++++++++++----
14
1 file changed, 28 insertions(+), 3 deletions(-)
23
1 file changed, 18 insertions(+), 4 deletions(-)
15
24
16
diff --git a/hw/cpu/a15mpcore.c b/hw/cpu/a15mpcore.c
25
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
17
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/cpu/a15mpcore.c
27
--- a/hw/arm/bcm2836.c
19
+++ b/hw/cpu/a15mpcore.c
28
+++ b/hw/arm/bcm2836.c
20
@@ -XXX,XX +XXX,XX @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
29
@@ -XXX,XX +XXX,XX @@ static void bcm2836_init(Object *obj)
21
int i;
30
qdev_prop_set_uint32(DEVICE(obj), "enabled-cpus", bc->core_count);
22
Error *err = NULL;
23
bool has_el3;
24
+ bool has_el2;
25
Object *cpuobj;
26
27
gicdev = DEVICE(&s->gic);
28
@@ -XXX,XX +XXX,XX @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
29
has_el3 = object_property_find(cpuobj, "has_el3", NULL) &&
30
object_property_get_bool(cpuobj, "has_el3", &error_abort);
31
qdev_prop_set_bit(gicdev, "has-security-extensions", has_el3);
32
+ /* Similarly for virtualization support */
33
+ has_el2 = object_property_find(cpuobj, "has_el2", NULL) &&
34
+ object_property_get_bool(cpuobj, "has_el2", &error_abort);
35
+ qdev_prop_set_bit(gicdev, "has-virtualization-extensions", has_el2);
36
}
31
}
37
32
38
object_property_set_bool(OBJECT(&s->gic), true, "realized", &err);
33
- object_initialize_child(obj, "control", &s->control, TYPE_BCM2836_CONTROL);
39
@@ -XXX,XX +XXX,XX @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
34
+ if (bc->ctrl_base) {
40
qdev_get_gpio_in(gicdev,
35
+ object_initialize_child(obj, "control", &s->control,
41
ppibase + timer_irq[irq]));
36
+ TYPE_BCM2836_CONTROL);
42
}
37
+ }
43
+ if (has_el2) {
38
44
+ /* Connect the GIC maintenance interrupt to PPI ID 25 */
39
object_initialize_child(obj, "peripherals", &s->peripherals,
45
+ sysbus_connect_irq(SYS_BUS_DEVICE(gicdev), i + 4 * s->num_cpu,
40
TYPE_BCM2835_PERIPHERALS);
46
+ qdev_get_gpio_in(gicdev, ppibase + 25));
41
@@ -XXX,XX +XXX,XX @@ static void bcm2836_init(Object *obj)
47
+ }
42
"vcram-size");
43
}
44
45
-static void bcm2836_realize(DeviceState *dev, Error **errp)
46
+static bool bcm283x_common_realize(DeviceState *dev, Error **errp)
47
{
48
BCM283XState *s = BCM283X(dev);
49
BCM283XClass *bc = BCM283X_GET_CLASS(dev);
50
Object *obj;
51
- int n;
52
53
/* common peripherals from bcm2835 */
54
55
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
56
object_property_add_const_link(OBJECT(&s->peripherals), "ram", obj);
57
58
if (!sysbus_realize(SYS_BUS_DEVICE(&s->peripherals), errp)) {
59
- return;
60
+ return false;
48
}
61
}
49
62
50
/* Memory map (addresses are offsets from PERIPHBASE):
63
object_property_add_alias(OBJECT(s), "sd-bus", OBJECT(&s->peripherals),
51
* 0x0000-0x0fff -- reserved
64
@@ -XXX,XX +XXX,XX @@ static void bcm2836_realize(DeviceState *dev, Error **errp)
52
* 0x1000-0x1fff -- GIC Distributor
65
53
* 0x2000-0x3fff -- GIC CPU interface
66
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->peripherals), 0,
54
- * 0x4000-0x4fff -- GIC virtual interface control (not modelled)
67
bc->peri_base, 1);
55
- * 0x5000-0x5fff -- GIC virtual interface control (not modelled)
68
+ return true;
56
- * 0x6000-0x7fff -- GIC virtual CPU interface (not modelled)
69
+}
57
+ * 0x4000-0x4fff -- GIC virtual interface control for this CPU
70
+
58
+ * 0x5000-0x51ff -- GIC virtual interface control for CPU 0
71
+static void bcm2836_realize(DeviceState *dev, Error **errp)
59
+ * 0x5200-0x53ff -- GIC virtual interface control for CPU 1
72
+{
60
+ * 0x5400-0x55ff -- GIC virtual interface control for CPU 2
73
+ BCM283XState *s = BCM283X(dev);
61
+ * 0x5600-0x57ff -- GIC virtual interface control for CPU 3
74
+ BCM283XClass *bc = BCM283X_GET_CLASS(dev);
62
+ * 0x6000-0x7fff -- GIC virtual CPU interface
75
+ int n;
63
*/
76
+
64
memory_region_add_subregion(&s->container, 0x1000,
77
+ if (!bcm283x_common_realize(dev, errp)) {
65
sysbus_mmio_get_region(busdev, 0));
78
+ return;
66
memory_region_add_subregion(&s->container, 0x2000,
67
sysbus_mmio_get_region(busdev, 1));
68
+ if (has_el2) {
69
+ memory_region_add_subregion(&s->container, 0x4000,
70
+ sysbus_mmio_get_region(busdev, 2));
71
+ memory_region_add_subregion(&s->container, 0x6000,
72
+ sysbus_mmio_get_region(busdev, 3));
73
+ for (i = 0; i < s->num_cpu; i++) {
74
+ hwaddr base = 0x5000 + i * 0x200;
75
+ MemoryRegion *mr = sysbus_mmio_get_region(busdev,
76
+ 4 + s->num_cpu + i);
77
+ memory_region_add_subregion(&s->container, base, mr);
78
+ }
79
+ }
79
+ }
80
}
80
81
81
/* bcm2836 interrupt controller (and mailboxes, etc.) */
82
static Property a15mp_priv_properties[] = {
82
if (!sysbus_realize(SYS_BUS_DEVICE(&s->control), errp)) {
83
--
83
--
84
2.18.0
84
2.20.1
85
85
86
86
diff view generated by jsdifflib
1
Factor out the code which changes the CPU state so as to
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
actually take an exception to AArch32. We're going to want
3
to use this for handling exception entry to Hyp mode.
4
2
3
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
4
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
5
Message-id: 20201024170127.3592182-7-f4bug@amsat.org
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
8
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
9
Message-id: 20180820153020.21478-4-peter.maydell@linaro.org
10
---
7
---
11
target/arm/helper.c | 64 +++++++++++++++++++++++++++++----------------
8
include/hw/arm/bcm2836.h | 1 +
12
1 file changed, 41 insertions(+), 23 deletions(-)
9
hw/arm/bcm2836.c | 34 ++++++++++++++++++++++++++++++++++
10
hw/arm/raspi.c | 2 ++
11
3 files changed, 37 insertions(+)
13
12
14
diff --git a/target/arm/helper.c b/target/arm/helper.c
13
diff --git a/include/hw/arm/bcm2836.h b/include/hw/arm/bcm2836.h
15
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
16
--- a/target/arm/helper.c
15
--- a/include/hw/arm/bcm2836.h
17
+++ b/target/arm/helper.c
16
+++ b/include/hw/arm/bcm2836.h
18
@@ -XXX,XX +XXX,XX @@ void aarch64_sync_64_to_32(CPUARMState *env)
17
@@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_TYPE(BCM283XState, BCM283XClass, BCM283X)
19
env->regs[15] = env->pc;
18
* them, code using these devices should always handle them via the
19
* BCM283x base class, so they have no BCM2836(obj) etc macros.
20
*/
21
+#define TYPE_BCM2835 "bcm2835"
22
#define TYPE_BCM2836 "bcm2836"
23
#define TYPE_BCM2837 "bcm2837"
24
25
diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c
26
index XXXXXXX..XXXXXXX 100644
27
--- a/hw/arm/bcm2836.c
28
+++ b/hw/arm/bcm2836.c
29
@@ -XXX,XX +XXX,XX @@ static bool bcm283x_common_realize(DeviceState *dev, Error **errp)
30
return true;
20
}
31
}
21
32
22
+static void take_aarch32_exception(CPUARMState *env, int new_mode,
33
+static void bcm2835_realize(DeviceState *dev, Error **errp)
23
+ uint32_t mask, uint32_t offset,
24
+ uint32_t newpc)
25
+{
34
+{
26
+ /* Change the CPU state so as to actually take the exception. */
35
+ BCM283XState *s = BCM283X(dev);
27
+ switch_mode(env, new_mode);
36
+
28
+ /*
37
+ if (!bcm283x_common_realize(dev, errp)) {
29
+ * For exceptions taken to AArch32 we must clear the SS bit in both
38
+ return;
30
+ * PSTATE and in the old-state value we save to SPSR_<mode>, so zero it now.
31
+ */
32
+ env->uncached_cpsr &= ~PSTATE_SS;
33
+ env->spsr = cpsr_read(env);
34
+ /* Clear IT bits. */
35
+ env->condexec_bits = 0;
36
+ /* Switch to the new mode, and to the correct instruction set. */
37
+ env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode;
38
+ /* Set new mode endianness */
39
+ env->uncached_cpsr &= ~CPSR_E;
40
+ if (env->cp15.sctlr_el[arm_current_el(env)] & SCTLR_EE) {
41
+ env->uncached_cpsr |= CPSR_E;
42
+ }
39
+ }
43
+ env->daif |= mask;
44
+
40
+
45
+ if (new_mode == ARM_CPU_MODE_HYP) {
41
+ if (!qdev_realize(DEVICE(&s->cpu[0].core), NULL, errp)) {
46
+ env->thumb = (env->cp15.sctlr_el[2] & SCTLR_TE) != 0;
42
+ return;
47
+ env->elr_el[2] = env->regs[15];
48
+ } else {
49
+ /*
50
+ * this is a lie, as there was no c1_sys on V4T/V5, but who cares
51
+ * and we should just guard the thumb mode on V4
52
+ */
53
+ if (arm_feature(env, ARM_FEATURE_V4T)) {
54
+ env->thumb =
55
+ (A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_TE) != 0;
56
+ }
57
+ env->regs[14] = env->regs[15] + offset;
58
+ }
43
+ }
59
+ env->regs[15] = newpc;
44
+
45
+ /* Connect irq/fiq outputs from the interrupt controller. */
46
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 0,
47
+ qdev_get_gpio_in(DEVICE(&s->cpu[0].core), ARM_CPU_IRQ));
48
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->peripherals), 1,
49
+ qdev_get_gpio_in(DEVICE(&s->cpu[0].core), ARM_CPU_FIQ));
60
+}
50
+}
61
+
51
+
62
static void arm_cpu_do_interrupt_aarch32(CPUState *cs)
52
static void bcm2836_realize(DeviceState *dev, Error **errp)
63
{
53
{
64
ARMCPU *cpu = ARM_CPU(cs);
54
BCM283XState *s = BCM283X(dev);
65
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_do_interrupt_aarch32(CPUState *cs)
55
@@ -XXX,XX +XXX,XX @@ static void bcm283x_class_init(ObjectClass *oc, void *data)
66
env->cp15.scr_el3 &= ~SCR_NS;
56
dc->user_creatable = false;
67
}
68
69
- switch_mode (env, new_mode);
70
- /* For exceptions taken to AArch32 we must clear the SS bit in both
71
- * PSTATE and in the old-state value we save to SPSR_<mode>, so zero it now.
72
- */
73
- env->uncached_cpsr &= ~PSTATE_SS;
74
- env->spsr = cpsr_read(env);
75
- /* Clear IT bits. */
76
- env->condexec_bits = 0;
77
- /* Switch to the new mode, and to the correct instruction set. */
78
- env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode;
79
- /* Set new mode endianness */
80
- env->uncached_cpsr &= ~CPSR_E;
81
- if (env->cp15.sctlr_el[arm_current_el(env)] & SCTLR_EE) {
82
- env->uncached_cpsr |= CPSR_E;
83
- }
84
- env->daif |= mask;
85
- /* this is a lie, as the was no c1_sys on V4T/V5, but who cares
86
- * and we should just guard the thumb mode on V4 */
87
- if (arm_feature(env, ARM_FEATURE_V4T)) {
88
- env->thumb = (A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_TE) != 0;
89
- }
90
- env->regs[14] = env->regs[15] + offset;
91
- env->regs[15] = addr;
92
+ take_aarch32_exception(env, new_mode, mask, offset, addr);
93
}
57
}
94
58
95
/* Handle exception entry to a target EL which is using AArch64 */
59
+static void bcm2835_class_init(ObjectClass *oc, void *data)
60
+{
61
+ DeviceClass *dc = DEVICE_CLASS(oc);
62
+ BCM283XClass *bc = BCM283X_CLASS(oc);
63
+
64
+ bc->cpu_type = ARM_CPU_TYPE_NAME("arm1176");
65
+ bc->core_count = 1;
66
+ bc->peri_base = 0x20000000;
67
+ dc->realize = bcm2835_realize;
68
+};
69
+
70
static void bcm2836_class_init(ObjectClass *oc, void *data)
71
{
72
DeviceClass *dc = DEVICE_CLASS(oc);
73
@@ -XXX,XX +XXX,XX @@ static void bcm2837_class_init(ObjectClass *oc, void *data)
74
75
static const TypeInfo bcm283x_types[] = {
76
{
77
+ .name = TYPE_BCM2835,
78
+ .parent = TYPE_BCM283X,
79
+ .class_init = bcm2835_class_init,
80
+ }, {
81
.name = TYPE_BCM2836,
82
.parent = TYPE_BCM283X,
83
.class_init = bcm2836_class_init,
84
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
85
index XXXXXXX..XXXXXXX 100644
86
--- a/hw/arm/raspi.c
87
+++ b/hw/arm/raspi.c
88
@@ -XXX,XX +XXX,XX @@ FIELD(REV_CODE, MEMORY_SIZE, 20, 3);
89
FIELD(REV_CODE, STYLE, 23, 1);
90
91
typedef enum RaspiProcessorId {
92
+ PROCESSOR_ID_BCM2835 = 0,
93
PROCESSOR_ID_BCM2836 = 1,
94
PROCESSOR_ID_BCM2837 = 2,
95
} RaspiProcessorId;
96
@@ -XXX,XX +XXX,XX @@ static const struct {
97
const char *type;
98
int cores_count;
99
} soc_property[] = {
100
+ [PROCESSOR_ID_BCM2835] = {TYPE_BCM2835, 1},
101
[PROCESSOR_ID_BCM2836] = {TYPE_BCM2836, BCM283X_NCPUS},
102
[PROCESSOR_ID_BCM2837] = {TYPE_BCM2837, BCM283X_NCPUS},
103
};
96
--
104
--
97
2.18.0
105
2.20.1
98
106
99
107
diff view generated by jsdifflib
1
The AN505 FPGA image includes four PL081 DMA controllers, each
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
of which is gated by a Master Security Controller that allows
3
the guest to prevent a non-secure DMA controller from accessing
4
memory that is used by secure guest code. Create and wire
5
up these devices.
6
2
3
The Pi A is almost the first machine released.
4
It uses a BCM2835 SoC which includes a ARMv6Z core.
5
6
Example booting the machine using content from [*]
7
(we use the device tree from the B model):
8
9
$ qemu-system-arm -M raspi1ap -serial stdio \
10
-kernel raspberrypi/firmware/boot/kernel.img \
11
-dtb raspberrypi/firmware/boot/bcm2708-rpi-b-plus.dtb \
12
-append 'earlycon=pl011,0x20201000 console=ttyAMA0'
13
[ 0.000000] Booting Linux on physical CPU 0x0
14
[ 0.000000] Linux version 4.19.118+ (dom@buildbot) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611)) #1311 Mon Apr 27 14:16:15 BST 2020
15
[ 0.000000] CPU: ARMv6-compatible processor [410fb767] revision 7 (ARMv7), cr=00c5387d
16
[ 0.000000] CPU: VIPT aliasing data cache, unknown instruction cache
17
[ 0.000000] OF: fdt: Machine model: Raspberry Pi Model B+
18
...
19
20
[*] http://archive.raspberrypi.org/debian/pool/main/r/raspberrypi-firmware/raspberrypi-kernel_1.20200512-2_armhf.deb
21
22
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
23
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
24
Message-id: 20201024170127.3592182-8-f4bug@amsat.org
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
25
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Message-id: 20180820141116.9118-15-peter.maydell@linaro.org
10
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
11
---
26
---
12
hw/arm/mps2-tz.c | 100 +++++++++++++++++++++++++++++++++++++++++++----
27
hw/arm/raspi.c | 13 +++++++++++++
13
1 file changed, 93 insertions(+), 7 deletions(-)
28
1 file changed, 13 insertions(+)
14
29
15
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
30
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
16
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/arm/mps2-tz.c
32
--- a/hw/arm/raspi.c
18
+++ b/hw/arm/mps2-tz.c
33
+++ b/hw/arm/raspi.c
19
@@ -XXX,XX +XXX,XX @@
34
@@ -XXX,XX +XXX,XX @@ static void raspi_machine_class_common_init(MachineClass *mc,
20
#include "hw/misc/mps2-scc.h"
35
mc->default_ram_id = "ram";
21
#include "hw/misc/mps2-fpgaio.h"
36
};
22
#include "hw/misc/tz-mpc.h"
37
23
+#include "hw/misc/tz-msc.h"
38
+static void raspi1ap_machine_class_init(ObjectClass *oc, void *data)
24
#include "hw/arm/iotkit.h"
25
+#include "hw/dma/pl080.h"
26
#include "hw/devices.h"
27
#include "net/net.h"
28
#include "hw/core/split-irq.h"
29
@@ -XXX,XX +XXX,XX @@ typedef struct {
30
UnimplementedDeviceState i2c[4];
31
UnimplementedDeviceState i2s_audio;
32
UnimplementedDeviceState gpio[4];
33
- UnimplementedDeviceState dma[4];
34
UnimplementedDeviceState gfx;
35
+ PL080State dma[4];
36
+ TZMSC msc[4];
37
CMSDKAPBUART uart[5];
38
SplitIRQ sec_resp_splitter;
39
qemu_or_irq uart_irq_orgate;
40
@@ -XXX,XX +XXX,XX @@ static MemoryRegion *make_mpc(MPS2TZMachineState *mms, void *opaque,
41
return sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 0);
42
}
43
44
+static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque,
45
+ const char *name, hwaddr size)
46
+{
39
+{
47
+ PL080State *dma = opaque;
40
+ MachineClass *mc = MACHINE_CLASS(oc);
48
+ int i = dma - &mms->dma[0];
41
+ RaspiMachineClass *rmc = RASPI_MACHINE_CLASS(oc);
49
+ SysBusDevice *s;
50
+ char *mscname = g_strdup_printf("%s-msc", name);
51
+ TZMSC *msc = &mms->msc[i];
52
+ DeviceState *iotkitdev = DEVICE(&mms->iotkit);
53
+ MemoryRegion *msc_upstream;
54
+ MemoryRegion *msc_downstream;
55
+
42
+
56
+ /*
43
+ rmc->board_rev = 0x900021; /* Revision 1.1 */
57
+ * Each DMA device is a PL081 whose transaction master interface
44
+ raspi_machine_class_common_init(mc, rmc->board_rev);
58
+ * is guarded by a Master Security Controller. The downstream end of
45
+};
59
+ * the MSC connects to the IoTKit AHB Slave Expansion port, so the
60
+ * DMA devices can see all devices and memory that the CPU does.
61
+ */
62
+ sysbus_init_child_obj(OBJECT(mms), mscname, msc, sizeof(*msc), TYPE_TZ_MSC);
63
+ msc_downstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(&mms->iotkit), 0);
64
+ object_property_set_link(OBJECT(msc), OBJECT(msc_downstream),
65
+ "downstream", &error_fatal);
66
+ object_property_set_link(OBJECT(msc), OBJECT(mms),
67
+ "idau", &error_fatal);
68
+ object_property_set_bool(OBJECT(msc), true, "realized", &error_fatal);
69
+
46
+
70
+ qdev_connect_gpio_out_named(DEVICE(msc), "irq", 0,
47
static void raspi2b_machine_class_init(ObjectClass *oc, void *data)
71
+ qdev_get_gpio_in_named(iotkitdev,
72
+ "mscexp_status", i));
73
+ qdev_connect_gpio_out_named(iotkitdev, "mscexp_clear", i,
74
+ qdev_get_gpio_in_named(DEVICE(msc),
75
+ "irq_clear", 0));
76
+ qdev_connect_gpio_out_named(iotkitdev, "mscexp_ns", i,
77
+ qdev_get_gpio_in_named(DEVICE(msc),
78
+ "cfg_nonsec", 0));
79
+ qdev_connect_gpio_out(DEVICE(&mms->sec_resp_splitter),
80
+ ARRAY_SIZE(mms->ppc) + i,
81
+ qdev_get_gpio_in_named(DEVICE(msc),
82
+ "cfg_sec_resp", 0));
83
+ msc_upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(msc), 0);
84
+
85
+ sysbus_init_child_obj(OBJECT(mms), name, dma, sizeof(*dma), TYPE_PL081);
86
+ object_property_set_link(OBJECT(dma), OBJECT(msc_upstream),
87
+ "downstream", &error_fatal);
88
+ object_property_set_bool(OBJECT(dma), true, "realized", &error_fatal);
89
+
90
+ s = SYS_BUS_DEVICE(dma);
91
+ /* Wire up DMACINTR, DMACINTERR, DMACINTTC */
92
+ sysbus_connect_irq(s, 0, qdev_get_gpio_in_named(iotkitdev,
93
+ "EXP_IRQ", 58 + i * 3));
94
+ sysbus_connect_irq(s, 1, qdev_get_gpio_in_named(iotkitdev,
95
+ "EXP_IRQ", 56 + i * 3));
96
+ sysbus_connect_irq(s, 2, qdev_get_gpio_in_named(iotkitdev,
97
+ "EXP_IRQ", 57 + i * 3));
98
+
99
+ return sysbus_mmio_get_region(s, 0);
100
+}
101
+
102
static void mps2tz_common_init(MachineState *machine)
103
{
104
MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine);
105
@@ -XXX,XX +XXX,XX @@ static void mps2tz_common_init(MachineState *machine)
106
&error_fatal);
107
108
/* The sec_resp_cfg output from the IoTKit must be split into multiple
109
- * lines, one for each of the PPCs we create here.
110
+ * lines, one for each of the PPCs we create here, plus one per MSC.
111
*/
112
object_initialize(&mms->sec_resp_splitter, sizeof(mms->sec_resp_splitter),
113
TYPE_SPLIT_IRQ);
114
object_property_add_child(OBJECT(machine), "sec-resp-splitter",
115
OBJECT(&mms->sec_resp_splitter), &error_abort);
116
- object_property_set_int(OBJECT(&mms->sec_resp_splitter), 5,
117
+ object_property_set_int(OBJECT(&mms->sec_resp_splitter),
118
+ ARRAY_SIZE(mms->ppc) + ARRAY_SIZE(mms->msc),
119
"num-lines", &error_fatal);
120
object_property_set_bool(OBJECT(&mms->sec_resp_splitter), true,
121
"realized", &error_fatal);
122
@@ -XXX,XX +XXX,XX @@ static void mps2tz_common_init(MachineState *machine)
123
}, {
124
.name = "ahb_ppcexp1",
125
.ports = {
126
- { "dma0", make_unimp_dev, &mms->dma[0], 0x40110000, 0x1000 },
127
- { "dma1", make_unimp_dev, &mms->dma[1], 0x40111000, 0x1000 },
128
- { "dma2", make_unimp_dev, &mms->dma[2], 0x40112000, 0x1000 },
129
- { "dma3", make_unimp_dev, &mms->dma[3], 0x40113000, 0x1000 },
130
+ { "dma0", make_dma, &mms->dma[0], 0x40110000, 0x1000 },
131
+ { "dma1", make_dma, &mms->dma[1], 0x40111000, 0x1000 },
132
+ { "dma2", make_dma, &mms->dma[2], 0x40112000, 0x1000 },
133
+ { "dma3", make_dma, &mms->dma[3], 0x40113000, 0x1000 },
134
},
135
},
136
};
137
@@ -XXX,XX +XXX,XX @@ static void mps2tz_common_init(MachineState *machine)
138
armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, 0x400000);
139
}
140
141
+static void mps2_tz_idau_check(IDAUInterface *ii, uint32_t address,
142
+ int *iregion, bool *exempt, bool *ns, bool *nsc)
143
+{
144
+ /*
145
+ * The MPS2 TZ FPGA images have IDAUs in them which are connected to
146
+ * the Master Security Controllers. Thes have the same logic as
147
+ * is used by the IoTKit for the IDAU connected to the CPU, except
148
+ * that MSCs don't care about the NSC attribute.
149
+ */
150
+ int region = extract32(address, 28, 4);
151
+
152
+ *ns = !(region & 1);
153
+ *nsc = false;
154
+ /* 0xe0000000..0xe00fffff and 0xf0000000..0xf00fffff are exempt */
155
+ *exempt = (address & 0xeff00000) == 0xe0000000;
156
+ *iregion = region;
157
+}
158
+
159
static void mps2tz_class_init(ObjectClass *oc, void *data)
160
{
48
{
161
MachineClass *mc = MACHINE_CLASS(oc);
49
MachineClass *mc = MACHINE_CLASS(oc);
162
+ IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(oc);
50
@@ -XXX,XX +XXX,XX @@ static void raspi3b_machine_class_init(ObjectClass *oc, void *data)
163
51
164
mc->init = mps2tz_common_init;
52
static const TypeInfo raspi_machine_types[] = {
165
mc->max_cpus = 1;
53
{
166
+ iic->check = mps2_tz_idau_check;
54
+ .name = MACHINE_TYPE_NAME("raspi1ap"),
167
}
55
+ .parent = TYPE_RASPI_MACHINE,
168
56
+ .class_init = raspi1ap_machine_class_init,
169
static void mps2tz_an505_class_init(ObjectClass *oc, void *data)
57
+ }, {
170
@@ -XXX,XX +XXX,XX @@ static const TypeInfo mps2tz_info = {
58
.name = MACHINE_TYPE_NAME("raspi2b"),
171
.instance_size = sizeof(MPS2TZMachineState),
59
.parent = TYPE_RASPI_MACHINE,
172
.class_size = sizeof(MPS2TZMachineClass),
60
.class_init = raspi2b_machine_class_init,
173
.class_init = mps2tz_class_init,
174
+ .interfaces = (InterfaceInfo[]) {
175
+ { TYPE_IDAU_INTERFACE },
176
+ { }
177
+ },
178
};
179
180
static const TypeInfo mps2tz_an505_info = {
181
--
61
--
182
2.18.0
62
2.20.1
183
63
184
64
diff view generated by jsdifflib
1
The AArch32 HCR and HCR2 registers alias HCR_EL2
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
bits [31:0] and [63:32]; implement them.
3
2
4
Since HCR2 exists in ARMv8 but not ARMv7, we need new
3
Similarly to the Pi A, the Pi Zero uses a BCM2835 SoC (ARMv6Z core).
5
regdef arrays for "we have EL3, not EL2, we're ARMv8"
6
and "we have EL2, we're ARMv8" to hold the definitions.
7
4
5
The only difference between the revision 1.2 and 1.3 is the latter
6
exposes a CSI camera connector. As we do not implement the Unicam
7
peripheral, there is no point in exposing a camera connector :)
8
Therefore we choose to model the 1.2 revision.
9
10
Example booting the machine using content from [*]:
11
12
$ qemu-system-arm -M raspi0 -serial stdio \
13
-kernel raspberrypi/firmware/boot/kernel.img \
14
-dtb raspberrypi/firmware/boot/bcm2708-rpi-zero.dtb \
15
-append 'printk.time=0 earlycon=pl011,0x20201000 console=ttyAMA0'
16
[ 0.000000] Booting Linux on physical CPU 0x0
17
[ 0.000000] Linux version 4.19.118+ (dom@buildbot) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611)) #1311 Mon Apr 27 14:16:15 BST 2020
18
[ 0.000000] CPU: ARMv6-compatible processor [410fb767] revision 7 (ARMv7), cr=00c5387d
19
[ 0.000000] CPU: VIPT aliasing data cache, unknown instruction cache
20
[ 0.000000] OF: fdt: Machine model: Raspberry Pi Zero
21
...
22
23
[*] http://archive.raspberrypi.org/debian/pool/main/r/raspberrypi-firmware/raspberrypi-kernel_1.20200512-2_armhf.deb
24
25
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
26
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
27
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
28
Message-id: 20201024170127.3592182-9-f4bug@amsat.org
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
29
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
11
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
12
Message-id: 20180820153020.21478-3-peter.maydell@linaro.org
13
---
30
---
14
target/arm/helper.c | 54 +++++++++++++++++++++++++++++++++++++++++----
31
hw/arm/raspi.c | 13 +++++++++++++
15
1 file changed, 50 insertions(+), 4 deletions(-)
32
1 file changed, 13 insertions(+)
16
33
17
diff --git a/target/arm/helper.c b/target/arm/helper.c
34
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
18
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
19
--- a/target/arm/helper.c
36
--- a/hw/arm/raspi.c
20
+++ b/target/arm/helper.c
37
+++ b/hw/arm/raspi.c
21
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = {
38
@@ -XXX,XX +XXX,XX @@ static void raspi_machine_class_common_init(MachineClass *mc,
22
.opc0 = 3, .opc1 = 4, .crn = 12, .crm = 0, .opc2 = 0,
39
mc->default_ram_id = "ram";
23
.access = PL2_RW,
24
.readfn = arm_cp_read_zero, .writefn = arm_cp_write_ignore },
25
- { .name = "HCR_EL2", .state = ARM_CP_STATE_AA64,
26
+ { .name = "HCR_EL2", .state = ARM_CP_STATE_BOTH,
27
.type = ARM_CP_NO_RAW,
28
.opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 0,
29
.access = PL2_RW,
30
- .readfn = arm_cp_read_zero, .writefn = arm_cp_write_ignore },
31
+ .type = ARM_CP_CONST, .resetvalue = 0 },
32
{ .name = "ESR_EL2", .state = ARM_CP_STATE_BOTH,
33
.opc0 = 3, .opc1 = 4, .crn = 5, .crm = 2, .opc2 = 0,
34
.access = PL2_RW,
35
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo el3_no_el2_cp_reginfo[] = {
36
REGINFO_SENTINEL
37
};
40
};
38
41
39
+/* Ditto, but for registers which exist in ARMv8 but not v7 */
42
+static void raspi0_machine_class_init(ObjectClass *oc, void *data)
40
+static const ARMCPRegInfo el3_no_el2_v8_cp_reginfo[] = {
43
+{
41
+ { .name = "HCR2", .state = ARM_CP_STATE_AA32,
44
+ MachineClass *mc = MACHINE_CLASS(oc);
42
+ .cp = 15, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 4,
45
+ RaspiMachineClass *rmc = RASPI_MACHINE_CLASS(oc);
43
+ .access = PL2_RW,
46
+
44
+ .type = ARM_CP_CONST, .resetvalue = 0 },
47
+ rmc->board_rev = 0x920092; /* Revision 1.2 */
45
+ REGINFO_SENTINEL
48
+ raspi_machine_class_common_init(mc, rmc->board_rev);
46
+};
49
+};
47
+
50
+
48
static void hcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
51
static void raspi1ap_machine_class_init(ObjectClass *oc, void *data)
49
{
52
{
50
ARMCPU *cpu = arm_env_get_cpu(env);
53
MachineClass *mc = MACHINE_CLASS(oc);
51
@@ -XXX,XX +XXX,XX @@ static void hcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
54
@@ -XXX,XX +XXX,XX @@ static void raspi3b_machine_class_init(ObjectClass *oc, void *data)
52
* HCR_PTW forbids certain page-table setups
55
53
* HCR_DC Disables stage1 and enables stage2 translation
56
static const TypeInfo raspi_machine_types[] = {
54
*/
57
{
55
- if ((raw_read(env, ri) ^ value) & (HCR_VM | HCR_PTW | HCR_DC)) {
58
+ .name = MACHINE_TYPE_NAME("raspi0"),
56
+ if ((env->cp15.hcr_el2 ^ value) & (HCR_VM | HCR_PTW | HCR_DC)) {
59
+ .parent = TYPE_RASPI_MACHINE,
57
tlb_flush(CPU(cpu));
60
+ .class_init = raspi0_machine_class_init,
58
}
61
+ }, {
59
- raw_write(env, ri, value);
62
.name = MACHINE_TYPE_NAME("raspi1ap"),
60
+ env->cp15.hcr_el2 = value;
63
.parent = TYPE_RASPI_MACHINE,
61
+}
64
.class_init = raspi1ap_machine_class_init,
62
+
63
+static void hcr_writehigh(CPUARMState *env, const ARMCPRegInfo *ri,
64
+ uint64_t value)
65
+{
66
+ /* Handle HCR2 write, i.e. write to high half of HCR_EL2 */
67
+ value = deposit64(env->cp15.hcr_el2, 32, 32, value);
68
+ hcr_write(env, NULL, value);
69
+}
70
+
71
+static void hcr_writelow(CPUARMState *env, const ARMCPRegInfo *ri,
72
+ uint64_t value)
73
+{
74
+ /* Handle HCR write, i.e. write to low half of HCR_EL2 */
75
+ value = deposit64(env->cp15.hcr_el2, 0, 32, value);
76
+ hcr_write(env, NULL, value);
77
}
78
79
static const ARMCPRegInfo el2_cp_reginfo[] = {
80
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
81
.opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 0,
82
.access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.hcr_el2),
83
.writefn = hcr_write },
84
+ { .name = "HCR", .state = ARM_CP_STATE_AA32,
85
+ .type = ARM_CP_ALIAS,
86
+ .cp = 15, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 0,
87
+ .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.hcr_el2),
88
+ .writefn = hcr_writelow },
89
{ .name = "ELR_EL2", .state = ARM_CP_STATE_AA64,
90
.type = ARM_CP_ALIAS,
91
.opc0 = 3, .opc1 = 4, .crn = 4, .crm = 0, .opc2 = 1,
92
@@ -XXX,XX +XXX,XX @@ static const ARMCPRegInfo el2_cp_reginfo[] = {
93
REGINFO_SENTINEL
94
};
95
96
+static const ARMCPRegInfo el2_v8_cp_reginfo[] = {
97
+ { .name = "HCR2", .state = ARM_CP_STATE_AA32,
98
+ .type = ARM_CP_ALIAS,
99
+ .cp = 15, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 4,
100
+ .access = PL2_RW,
101
+ .fieldoffset = offsetofhigh32(CPUARMState, cp15.hcr_el2),
102
+ .writefn = hcr_writehigh },
103
+ REGINFO_SENTINEL
104
+};
105
+
106
static CPAccessResult nsacr_access(CPUARMState *env, const ARMCPRegInfo *ri,
107
bool isread)
108
{
109
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
110
};
111
define_arm_cp_regs(cpu, vpidr_regs);
112
define_arm_cp_regs(cpu, el2_cp_reginfo);
113
+ if (arm_feature(env, ARM_FEATURE_V8)) {
114
+ define_arm_cp_regs(cpu, el2_v8_cp_reginfo);
115
+ }
116
/* RVBAR_EL2 is only implemented if EL2 is the highest EL */
117
if (!arm_feature(env, ARM_FEATURE_EL3)) {
118
ARMCPRegInfo rvbar = {
119
@@ -XXX,XX +XXX,XX @@ void register_cp_regs_for_features(ARMCPU *cpu)
120
};
121
define_arm_cp_regs(cpu, vpidr_regs);
122
define_arm_cp_regs(cpu, el3_no_el2_cp_reginfo);
123
+ if (arm_feature(env, ARM_FEATURE_V8)) {
124
+ define_arm_cp_regs(cpu, el3_no_el2_v8_cp_reginfo);
125
+ }
126
}
127
}
128
if (arm_feature(env, ARM_FEATURE_EL3)) {
129
--
65
--
130
2.18.0
66
2.20.1
131
67
132
68
diff view generated by jsdifflib
1
Add a "virtualization" property to the vexpress-a15 board,
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
controlling presence of EL2. As with EL3, we default to
3
enabling it, but the user can disable it if they have an
4
older guest which can't cope with it being present.
5
2
3
The Pi 3A+ is a stripped down version of the 3B:
4
- 512 MiB of RAM instead of 1 GiB
5
- no on-board ethernet chipset
6
7
Add it as it is a closer match to what we model.
8
9
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
10
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
11
Message-id: 20201024170127.3592182-10-f4bug@amsat.org
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
8
Message-id: 20180821132811.17675-10-peter.maydell@linaro.org
9
---
13
---
10
hw/arm/vexpress.c | 56 ++++++++++++++++++++++++++++++++++++++++++++---
14
hw/arm/raspi.c | 13 +++++++++++++
11
1 file changed, 53 insertions(+), 3 deletions(-)
15
1 file changed, 13 insertions(+)
12
16
13
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
17
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
14
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/arm/vexpress.c
19
--- a/hw/arm/raspi.c
16
+++ b/hw/arm/vexpress.c
20
+++ b/hw/arm/raspi.c
17
@@ -XXX,XX +XXX,XX @@ typedef struct {
21
@@ -XXX,XX +XXX,XX @@ static void raspi2b_machine_class_init(ObjectClass *oc, void *data)
18
typedef struct {
19
MachineState parent;
20
bool secure;
21
+ bool virt;
22
} VexpressMachineState;
23
24
#define TYPE_VEXPRESS_MACHINE "vexpress"
25
@@ -XXX,XX +XXX,XX @@ struct VEDBoardInfo {
26
};
22
};
27
23
28
static void init_cpus(const char *cpu_type, const char *privdev,
24
#ifdef TARGET_AARCH64
29
- hwaddr periphbase, qemu_irq *pic, bool secure)
25
+static void raspi3ap_machine_class_init(ObjectClass *oc, void *data)
30
+ hwaddr periphbase, qemu_irq *pic, bool secure, bool virt)
31
{
32
DeviceState *dev;
33
SysBusDevice *busdev;
34
@@ -XXX,XX +XXX,XX @@ static void init_cpus(const char *cpu_type, const char *privdev,
35
if (!secure) {
36
object_property_set_bool(cpuobj, false, "has_el3", NULL);
37
}
38
+ if (!virt) {
39
+ if (object_property_find(cpuobj, "has_el2", NULL)) {
40
+ object_property_set_bool(cpuobj, false, "has_el2", NULL);
41
+ }
42
+ }
43
44
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
45
object_property_set_int(cpuobj, periphbase,
46
@@ -XXX,XX +XXX,XX @@ static void a9_daughterboard_init(const VexpressMachineState *vms,
47
memory_region_add_subregion(sysmem, 0x60000000, ram);
48
49
/* 0x1e000000 A9MPCore (SCU) private memory region */
50
- init_cpus(cpu_type, TYPE_A9MPCORE_PRIV, 0x1e000000, pic, vms->secure);
51
+ init_cpus(cpu_type, TYPE_A9MPCORE_PRIV, 0x1e000000, pic,
52
+ vms->secure, vms->virt);
53
54
/* Daughterboard peripherals : 0x10020000 .. 0x20000000 */
55
56
@@ -XXX,XX +XXX,XX @@ static void a15_daughterboard_init(const VexpressMachineState *vms,
57
memory_region_add_subregion(sysmem, 0x80000000, ram);
58
59
/* 0x2c000000 A15MPCore private memory region (GIC) */
60
- init_cpus(cpu_type, TYPE_A15MPCORE_PRIV, 0x2c000000, pic, vms->secure);
61
+ init_cpus(cpu_type, TYPE_A15MPCORE_PRIV, 0x2c000000, pic, vms->secure,
62
+ vms->virt);
63
64
/* A15 daughterboard peripherals: */
65
66
@@ -XXX,XX +XXX,XX @@ static void vexpress_set_secure(Object *obj, bool value, Error **errp)
67
vms->secure = value;
68
}
69
70
+static bool vexpress_get_virt(Object *obj, Error **errp)
71
+{
26
+{
72
+ VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
27
+ MachineClass *mc = MACHINE_CLASS(oc);
28
+ RaspiMachineClass *rmc = RASPI_MACHINE_CLASS(oc);
73
+
29
+
74
+ return vms->virt;
30
+ rmc->board_rev = 0x9020e0; /* Revision 1.0 */
75
+}
31
+ raspi_machine_class_common_init(mc, rmc->board_rev);
32
+};
76
+
33
+
77
+static void vexpress_set_virt(Object *obj, bool value, Error **errp)
34
static void raspi3b_machine_class_init(ObjectClass *oc, void *data)
78
+{
79
+ VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
80
+
81
+ vms->virt = value;
82
+}
83
+
84
static void vexpress_instance_init(Object *obj)
85
{
86
VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
87
@@ -XXX,XX +XXX,XX @@ static void vexpress_instance_init(Object *obj)
88
NULL);
89
}
90
91
+static void vexpress_a15_instance_init(Object *obj)
92
+{
93
+ VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
94
+
95
+ /*
96
+ * For the vexpress-a15, EL2 is by default enabled if EL3 is,
97
+ * but can also be specifically set to on or off.
98
+ */
99
+ vms->virt = true;
100
+ object_property_add_bool(obj, "virtualization", vexpress_get_virt,
101
+ vexpress_set_virt, NULL);
102
+ object_property_set_description(obj, "virtualization",
103
+ "Set on/off to enable/disable the ARM "
104
+ "Virtualization Extensions "
105
+ "(defaults to same as 'secure')",
106
+ NULL);
107
+}
108
+
109
+static void vexpress_a9_instance_init(Object *obj)
110
+{
111
+ VexpressMachineState *vms = VEXPRESS_MACHINE(obj);
112
+
113
+ /* The A9 doesn't have the virt extensions */
114
+ vms->virt = false;
115
+}
116
+
117
static void vexpress_class_init(ObjectClass *oc, void *data)
118
{
35
{
119
MachineClass *mc = MACHINE_CLASS(oc);
36
MachineClass *mc = MACHINE_CLASS(oc);
120
@@ -XXX,XX +XXX,XX @@ static const TypeInfo vexpress_a9_info = {
37
@@ -XXX,XX +XXX,XX @@ static const TypeInfo raspi_machine_types[] = {
121
.name = TYPE_VEXPRESS_A9_MACHINE,
38
.parent = TYPE_RASPI_MACHINE,
122
.parent = TYPE_VEXPRESS_MACHINE,
39
.class_init = raspi2b_machine_class_init,
123
.class_init = vexpress_a9_class_init,
40
#ifdef TARGET_AARCH64
124
+ .instance_init = vexpress_a9_instance_init,
41
+ }, {
125
};
42
+ .name = MACHINE_TYPE_NAME("raspi3ap"),
126
43
+ .parent = TYPE_RASPI_MACHINE,
127
static const TypeInfo vexpress_a15_info = {
44
+ .class_init = raspi3ap_machine_class_init,
128
.name = TYPE_VEXPRESS_A15_MACHINE,
45
}, {
129
.parent = TYPE_VEXPRESS_MACHINE,
46
.name = MACHINE_TYPE_NAME("raspi3b"),
130
.class_init = vexpress_a15_class_init,
47
.parent = TYPE_RASPI_MACHINE,
131
+ .instance_init = vexpress_a15_instance_init,
132
};
133
134
static void vexpress_machine_init(void)
135
--
48
--
136
2.18.0
49
2.20.1
137
50
138
51
diff view generated by jsdifflib
1
Use the DeviceState vmsd pointer rather than calling vmstate_register()
1
From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
2
directly.
3
2
3
Use of 0x%d - make up our mind as 0x%x
4
5
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
6
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Acked-by: Eric Auger <eric.auger@redhat.com>
8
Message-id: 20201014193355.53074-1-dgilbert@redhat.com
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Message-id: 20180820141116.9118-18-peter.maydell@linaro.org
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
---
10
---
8
hw/ssi/pl022.c | 2 +-
11
hw/arm/trace-events | 2 +-
9
1 file changed, 1 insertion(+), 1 deletion(-)
12
1 file changed, 1 insertion(+), 1 deletion(-)
10
13
11
diff --git a/hw/ssi/pl022.c b/hw/ssi/pl022.c
14
diff --git a/hw/arm/trace-events b/hw/arm/trace-events
12
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
13
--- a/hw/ssi/pl022.c
16
--- a/hw/arm/trace-events
14
+++ b/hw/ssi/pl022.c
17
+++ b/hw/arm/trace-events
15
@@ -XXX,XX +XXX,XX @@ static int pl022_init(SysBusDevice *sbd)
18
@@ -XXX,XX +XXX,XX @@ smmuv3_get_cd(uint64_t addr) "CD addr: 0x%"PRIx64
16
sysbus_init_mmio(sbd, &s->iomem);
19
smmuv3_decode_cd(uint32_t oas) "oas=%d"
17
sysbus_init_irq(sbd, &s->irq);
20
smmuv3_decode_cd_tt(int i, uint32_t tsz, uint64_t ttb, uint32_t granule_sz, bool had) "TT[%d]:tsz:%d ttb:0x%"PRIx64" granule_sz:%d had:%d"
18
s->ssi = ssi_create_bus(dev, "ssi");
21
smmuv3_cmdq_cfgi_ste(int streamid) "streamid =%d"
19
- vmstate_register(dev, -1, &vmstate_pl022, s);
22
-smmuv3_cmdq_cfgi_ste_range(int start, int end) "start=0x%d - end=0x%d"
20
return 0;
23
+smmuv3_cmdq_cfgi_ste_range(int start, int end) "start=0x%x - end=0x%x"
21
}
24
smmuv3_cmdq_cfgi_cd(uint32_t sid) "streamid = %d"
22
25
smmuv3_config_cache_hit(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache HIT for sid %d (hits=%d, misses=%d, hit rate=%d)"
23
@@ -XXX,XX +XXX,XX @@ static void pl022_class_init(ObjectClass *klass, void *data)
26
smmuv3_config_cache_miss(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache MISS for sid %d (hits=%d, misses=%d, hit rate=%d)"
24
25
sdc->init = pl022_init;
26
dc->reset = pl022_reset;
27
+ dc->vmsd = &vmstate_pl022;
28
}
29
30
static const TypeInfo pl022_info = {
31
--
27
--
32
2.18.0
28
2.20.1
33
29
34
30
diff view generated by jsdifflib
1
Reduce the size of the per-cpu GICH memory regions from 0x1000
1
From: Luc Michel <luc@lmichel.fr>
2
to 0x200. The registers only cover 0x200 bytes, and the Cortex-A15
3
wants to map them at a spacing of 0x200 bytes apart. Having the
4
region be too large interferes with mapping them like that, so
5
reduce it.
6
2
3
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
4
Reviewed-by: Damien Hedde <damien.hedde@greensocs.com>
5
Signed-off-by: Luc Michel <luc@lmichel.fr>
6
Tested-by: Guenter Roeck <linux@roeck-us.net>
7
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
9
Message-id: 20180821132811.17675-3-peter.maydell@linaro.org
10
---
9
---
11
hw/intc/arm_gic.c | 2 +-
10
include/hw/clock.h | 5 +++++
12
1 file changed, 1 insertion(+), 1 deletion(-)
11
1 file changed, 5 insertions(+)
13
12
14
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
13
diff --git a/include/hw/clock.h b/include/hw/clock.h
15
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/intc/arm_gic.c
15
--- a/include/hw/clock.h
17
+++ b/hw/intc/arm_gic.c
16
+++ b/include/hw/clock.h
18
@@ -XXX,XX +XXX,XX @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
17
@@ -XXX,XX +XXX,XX @@ extern const VMStateDescription vmstate_clock;
19
for (i = 0; i < s->num_cpu; i++) {
18
VMSTATE_CLOCK_V(field, state, 0)
20
memory_region_init_io(&s->vifaceiomem[i + 1], OBJECT(s),
19
#define VMSTATE_CLOCK_V(field, state, version) \
21
&gic_viface_ops, &s->backref[i],
20
VMSTATE_STRUCT_POINTER_V(field, state, version, vmstate_clock, Clock)
22
- "gic_viface", 0x1000);
21
+#define VMSTATE_ARRAY_CLOCK(field, state, num) \
23
+ "gic_viface", 0x200);
22
+ VMSTATE_ARRAY_CLOCK_V(field, state, num, 0)
24
sysbus_init_mmio(sbd, &s->vifaceiomem[i + 1]);
23
+#define VMSTATE_ARRAY_CLOCK_V(field, state, num, version) \
25
}
24
+ VMSTATE_ARRAY_OF_POINTER_TO_STRUCT(field, state, num, version, \
26
}
25
+ vmstate_clock, Clock)
26
27
/**
28
* clock_setup_canonical_path:
27
--
29
--
28
2.18.0
30
2.20.1
29
31
30
32
diff view generated by jsdifflib
1
Wire up the system control element's register banks
1
From: Luc Michel <luc@lmichel.fr>
2
(sysctl and sysinfo).
3
2
4
This is the last of the previously completely unimplemented
3
The nanosecond unit greatly limits the dynamic range we can display in
5
components in the IoTKit.
4
clock value traces, for values in the order of 1GHz and more. The
5
internal representation can go way beyond this value and it is quite
6
common for today's clocks to be within those ranges.
6
7
8
For example, a frequency between 500MHz+ and 1GHz will be displayed as
9
1ns. Beyond 1GHz, it will show up as 0ns.
10
11
Replace nanosecond periods traces with frequencies in the Hz unit
12
to have more dynamic range in the trace output.
13
14
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
15
Reviewed-by: Damien Hedde <damien.hedde@greensocs.com>
16
Signed-off-by: Luc Michel <luc@lmichel.fr>
17
Tested-by: Guenter Roeck <linux@roeck-us.net>
18
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
19
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
Message-id: 20180820141116.9118-11-peter.maydell@linaro.org
11
---
20
---
12
include/hw/arm/iotkit.h | 6 +++++-
21
hw/core/clock.c | 6 +++---
13
hw/arm/iotkit.c | 26 ++++++++++++++++++--------
22
hw/core/trace-events | 4 ++--
14
2 files changed, 23 insertions(+), 9 deletions(-)
23
2 files changed, 5 insertions(+), 5 deletions(-)
15
24
16
diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h
25
diff --git a/hw/core/clock.c b/hw/core/clock.c
17
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
18
--- a/include/hw/arm/iotkit.h
27
--- a/hw/core/clock.c
19
+++ b/include/hw/arm/iotkit.h
28
+++ b/hw/core/clock.c
20
@@ -XXX,XX +XXX,XX @@
29
@@ -XXX,XX +XXX,XX @@ bool clock_set(Clock *clk, uint64_t period)
21
#include "hw/timer/cmsdk-apb-timer.h"
30
if (clk->period == period) {
22
#include "hw/timer/cmsdk-apb-dualtimer.h"
31
return false;
23
#include "hw/watchdog/cmsdk-apb-watchdog.h"
32
}
24
-#include "hw/misc/unimp.h"
33
- trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_NS(clk->period),
25
+#include "hw/misc/iotkit-sysctl.h"
34
- CLOCK_PERIOD_TO_NS(period));
26
+#include "hw/misc/iotkit-sysinfo.h"
35
+ trace_clock_set(CLOCK_PATH(clk), CLOCK_PERIOD_TO_HZ(clk->period),
27
#include "hw/or-irq.h"
36
+ CLOCK_PERIOD_TO_HZ(period));
28
#include "hw/core/split-irq.h"
37
clk->period = period;
29
38
30
@@ -XXX,XX +XXX,XX @@ typedef struct IoTKit {
39
return true;
31
CMSDKAPBWatchdog nswatchdog;
40
@@ -XXX,XX +XXX,XX @@ static void clock_propagate_period(Clock *clk, bool call_callbacks)
32
CMSDKAPBWatchdog swatchdog;
41
if (child->period != clk->period) {
33
42
child->period = clk->period;
34
+ IoTKitSysCtl sysctl;
43
trace_clock_update(CLOCK_PATH(child), CLOCK_PATH(clk),
35
+ IoTKitSysCtl sysinfo;
44
- CLOCK_PERIOD_TO_NS(clk->period),
36
+
45
+ CLOCK_PERIOD_TO_HZ(clk->period),
37
MemoryRegion container;
46
call_callbacks);
38
MemoryRegion alias1;
47
if (call_callbacks && child->callback) {
39
MemoryRegion alias2;
48
child->callback(child->callback_opaque);
40
diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c
49
diff --git a/hw/core/trace-events b/hw/core/trace-events
41
index XXXXXXX..XXXXXXX 100644
50
index XXXXXXX..XXXXXXX 100644
42
--- a/hw/arm/iotkit.c
51
--- a/hw/core/trace-events
43
+++ b/hw/arm/iotkit.c
52
+++ b/hw/core/trace-events
44
@@ -XXX,XX +XXX,XX @@
53
@@ -XXX,XX +XXX,XX @@ resettable_transitional_function(void *obj, const char *objtype) "obj=%p(%s)"
45
#include "hw/sysbus.h"
54
# clock.c
46
#include "hw/registerfields.h"
55
clock_set_source(const char *clk, const char *src) "'%s', src='%s'"
47
#include "hw/arm/iotkit.h"
56
clock_disconnect(const char *clk) "'%s'"
48
-#include "hw/misc/unimp.h"
57
-clock_set(const char *clk, uint64_t old, uint64_t new) "'%s', ns=%"PRIu64"->%"PRIu64
49
#include "hw/arm/arm.h"
58
+clock_set(const char *clk, uint64_t old, uint64_t new) "'%s', %"PRIu64"Hz->%"PRIu64"Hz"
50
59
clock_propagate(const char *clk) "'%s'"
51
/* Clock frequency in HZ of the 32KHz "slow clock" */
60
-clock_update(const char *clk, const char *src, uint64_t val, int cb) "'%s', src='%s', ns=%"PRIu64", cb=%d"
52
@@ -XXX,XX +XXX,XX @@ static void iotkit_init(Object *obj)
61
+clock_update(const char *clk, const char *src, uint64_t hz, int cb) "'%s', src='%s', val=%"PRIu64"Hz cb=%d"
53
sizeof(s->nswatchdog), TYPE_CMSDK_APB_WATCHDOG);
54
sysbus_init_child_obj(obj, "swatchdog", &s->swatchdog,
55
sizeof(s->swatchdog), TYPE_CMSDK_APB_WATCHDOG);
56
+ sysbus_init_child_obj(obj, "iotkit-sysctl", &s->sysctl,
57
+ sizeof(s->sysctl), TYPE_IOTKIT_SYSCTL);
58
+ sysbus_init_child_obj(obj, "iotkit-sysinfo", &s->sysinfo,
59
+ sizeof(s->sysinfo), TYPE_IOTKIT_SYSINFO);
60
object_initialize_child(obj, "nmi-orgate", &s->nmi_orgate,
61
sizeof(s->nmi_orgate), TYPE_OR_IRQ,
62
&error_abort, NULL);
63
@@ -XXX,XX +XXX,XX @@ static void iotkit_realize(DeviceState *dev, Error **errp)
64
qdev_get_gpio_in_named(dev_apb_ppc1,
65
"cfg_sec_resp", 0));
66
67
- /* Using create_unimplemented_device() maps the stub into the
68
- * system address space rather than into our container, but the
69
- * overall effect to the guest is the same.
70
- */
71
- create_unimplemented_device("SYSINFO", 0x40020000, 0x1000);
72
-
73
- create_unimplemented_device("SYSCONTROL", 0x50021000, 0x1000);
74
+ object_property_set_bool(OBJECT(&s->sysinfo), true, "realized", &err);
75
+ if (err) {
76
+ error_propagate(errp, err);
77
+ return;
78
+ }
79
+ /* System information registers */
80
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysinfo), 0, 0x40020000);
81
+ /* System control registers */
82
+ object_property_set_bool(OBJECT(&s->sysctl), true, "realized", &err);
83
+ if (err) {
84
+ error_propagate(errp, err);
85
+ return;
86
+ }
87
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysctl), 0, 0x50021000);
88
89
/* This OR gate wires together outputs from the secure watchdogs to NMI */
90
object_property_set_int(OBJECT(&s->nmi_orgate), 2, "num-lines", &err);
91
--
62
--
92
2.18.0
63
2.20.1
93
64
94
65
diff view generated by jsdifflib
1
The IoTKit has a CMSDK timer device that runs on the S32KCLK.
1
From: Luc Michel <luc@lmichel.fr>
2
Create this and wire it up.
3
2
3
The CPRMAN (clock controller) was mapped at the watchdog/power manager
4
address. It was also split into two unimplemented peripherals (CM and
5
A2W) but this is really the same one, as shown by this extract of the
6
Raspberry Pi 3 Linux device tree:
7
8
watchdog@7e100000 {
9
compatible = "brcm,bcm2835-pm\0brcm,bcm2835-pm-wdt";
10
[...]
11
reg = <0x7e100000 0x114 0x7e00a000 0x24>;
12
[...]
13
};
14
15
[...]
16
cprman@7e101000 {
17
compatible = "brcm,bcm2835-cprman";
18
[...]
19
reg = <0x7e101000 0x2000>;
20
[...]
21
};
22
23
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
24
Signed-off-by: Luc Michel <luc@lmichel.fr>
25
Tested-by: Guenter Roeck <linux@roeck-us.net>
26
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
27
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20180820141116.9118-8-peter.maydell@linaro.org
8
---
28
---
9
include/hw/arm/iotkit.h | 2 +-
29
include/hw/arm/bcm2835_peripherals.h | 2 +-
10
hw/arm/iotkit.c | 9 +++++----
30
include/hw/arm/raspi_platform.h | 5 ++---
11
2 files changed, 6 insertions(+), 5 deletions(-)
31
hw/arm/bcm2835_peripherals.c | 4 ++--
32
3 files changed, 5 insertions(+), 6 deletions(-)
12
33
13
diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h
34
diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h
14
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
15
--- a/include/hw/arm/iotkit.h
36
--- a/include/hw/arm/bcm2835_peripherals.h
16
+++ b/include/hw/arm/iotkit.h
37
+++ b/include/hw/arm/bcm2835_peripherals.h
17
@@ -XXX,XX +XXX,XX @@ typedef struct IoTKit {
38
@@ -XXX,XX +XXX,XX @@ struct BCM2835PeripheralState {
18
TZMPC mpc;
39
BCM2835MphiState mphi;
19
CMSDKAPBTIMER timer0;
40
UnimplementedDeviceState txp;
20
CMSDKAPBTIMER timer1;
41
UnimplementedDeviceState armtmr;
21
+ CMSDKAPBTIMER s32ktimer;
42
+ UnimplementedDeviceState powermgt;
22
qemu_or_irq ppc_irq_orgate;
43
UnimplementedDeviceState cprman;
23
SplitIRQ sec_resp_splitter;
44
- UnimplementedDeviceState a2w;
24
SplitIRQ ppc_irq_splitter[NUM_PPCS];
45
PL011State uart0;
25
@@ -XXX,XX +XXX,XX @@ typedef struct IoTKit {
46
BCM2835AuxState aux;
26
qemu_or_irq nmi_orgate;
47
BCM2835FBState fb;
27
48
diff --git a/include/hw/arm/raspi_platform.h b/include/hw/arm/raspi_platform.h
28
CMSDKAPBDualTimer dualtimer;
29
- UnimplementedDeviceState s32ktimer;
30
31
CMSDKAPBWatchdog s32kwatchdog;
32
CMSDKAPBWatchdog nswatchdog;
33
diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c
34
index XXXXXXX..XXXXXXX 100644
49
index XXXXXXX..XXXXXXX 100644
35
--- a/hw/arm/iotkit.c
50
--- a/include/hw/arm/raspi_platform.h
36
+++ b/hw/arm/iotkit.c
51
+++ b/include/hw/arm/raspi_platform.h
37
@@ -XXX,XX +XXX,XX @@ static void iotkit_init(Object *obj)
52
@@ -XXX,XX +XXX,XX @@
38
TYPE_CMSDK_APB_TIMER);
53
#define ARMCTRL_TIMER0_1_OFFSET (ARM_OFFSET + 0x400) /* Timer 0 and 1 (SP804) */
39
sysbus_init_child_obj(obj, "timer1", &s->timer1, sizeof(s->timer1),
54
#define ARMCTRL_0_SBM_OFFSET (ARM_OFFSET + 0x800) /* User 0 (ARM) Semaphores
40
TYPE_CMSDK_APB_TIMER);
55
* Doorbells & Mailboxes */
41
+ sysbus_init_child_obj(obj, "s32ktimer", &s->s32ktimer, sizeof(s->s32ktimer),
56
-#define CPRMAN_OFFSET 0x100000 /* Power Management, Watchdog */
42
+ TYPE_CMSDK_APB_TIMER);
57
-#define CM_OFFSET 0x101000 /* Clock Management */
43
sysbus_init_child_obj(obj, "dualtimer", &s->dualtimer, sizeof(s->dualtimer),
58
-#define A2W_OFFSET 0x102000 /* Reset controller */
44
TYPE_CMSDK_APB_DUALTIMER);
59
+#define PM_OFFSET 0x100000 /* Power Management */
45
sysbus_init_child_obj(obj, "s32kwatchdog", &s->s32kwatchdog,
60
+#define CPRMAN_OFFSET 0x101000 /* Clock Management */
46
@@ -XXX,XX +XXX,XX @@ static void iotkit_init(Object *obj)
61
#define AVS_OFFSET 0x103000 /* Audio Video Standard */
47
TYPE_SPLIT_IRQ, &error_abort, NULL);
62
#define RNG_OFFSET 0x104000
48
g_free(name);
63
#define GPIO_OFFSET 0x200000
49
}
64
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
50
- sysbus_init_child_obj(obj, "s32ktimer", &s->s32ktimer, sizeof(s->s32ktimer),
65
index XXXXXXX..XXXXXXX 100644
51
- TYPE_UNIMPLEMENTED_DEVICE);
66
--- a/hw/arm/bcm2835_peripherals.c
52
}
67
+++ b/hw/arm/bcm2835_peripherals.c
53
68
@@ -XXX,XX +XXX,XX @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
54
static void iotkit_exp_irq(void *opaque, int n, int level)
69
55
@@ -XXX,XX +XXX,XX @@ static void iotkit_realize(DeviceState *dev, Error **errp)
70
create_unimp(s, &s->txp, "bcm2835-txp", TXP_OFFSET, 0x1000);
56
/* Devices behind APB PPC1:
71
create_unimp(s, &s->armtmr, "bcm2835-sp804", ARMCTRL_TIMER0_1_OFFSET, 0x40);
57
* 0x4002f000: S32K timer
72
- create_unimp(s, &s->cprman, "bcm2835-cprman", CPRMAN_OFFSET, 0x1000);
58
*/
73
- create_unimp(s, &s->a2w, "bcm2835-a2w", A2W_OFFSET, 0x1000);
59
- qdev_prop_set_string(DEVICE(&s->s32ktimer), "name", "S32KTIMER");
74
+ create_unimp(s, &s->powermgt, "bcm2835-powermgt", PM_OFFSET, 0x114);
60
- qdev_prop_set_uint64(DEVICE(&s->s32ktimer), "size", 0x1000);
75
+ create_unimp(s, &s->cprman, "bcm2835-cprman", CPRMAN_OFFSET, 0x2000);
61
+ qdev_prop_set_uint32(DEVICE(&s->s32ktimer), "pclk-frq", S32KCLK);
76
create_unimp(s, &s->i2s, "bcm2835-i2s", I2S_OFFSET, 0x100);
62
object_property_set_bool(OBJECT(&s->s32ktimer), true, "realized", &err);
77
create_unimp(s, &s->smi, "bcm2835-smi", SMI_OFFSET, 0x100);
63
if (err) {
78
create_unimp(s, &s->spi[0], "bcm2835-spi0", SPI0_OFFSET, 0x20);
64
error_propagate(errp, err);
65
return;
66
}
67
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->s32ktimer), 0,
68
+ qdev_get_gpio_in(DEVICE(&s->armv7m), 2));
69
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->s32ktimer), 0);
70
object_property_set_link(OBJECT(&s->apb_ppc1), OBJECT(mr), "port[0]", &err);
71
if (err) {
72
--
79
--
73
2.18.0
80
2.20.1
74
81
75
82
diff view generated by jsdifflib
1
The Arm IoTKit includes a system control element which
1
From: Luc Michel <luc@lmichel.fr>
2
provides a block of read-only ID registers and a block
2
3
of read-write control registers. Implement a minimal
3
The BCM2835 CPRMAN is the clock manager of the SoC. It is composed of a
4
version of this.
4
main oscillator, and several sub-components (PLLs, multiplexers, ...) to
5
5
generate the BCM2835 clock tree.
6
7
This commit adds a skeleton of the CPRMAN, with a dummy register
8
read/write implementation. It embeds the main oscillator (xosc) from
9
which all the clocks will be derived.
10
11
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
12
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
13
Signed-off-by: Luc Michel <luc@lmichel.fr>
14
Tested-by: Guenter Roeck <linux@roeck-us.net>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20180820141116.9118-9-peter.maydell@linaro.org
9
---
16
---
10
hw/misc/Makefile.objs | 1 +
17
include/hw/arm/bcm2835_peripherals.h | 3 +-
11
include/hw/misc/iotkit-sysctl.h | 49 ++++++
18
include/hw/misc/bcm2835_cprman.h | 37 +++++
12
hw/misc/iotkit-sysctl.c | 261 ++++++++++++++++++++++++++++++++
19
include/hw/misc/bcm2835_cprman_internals.h | 24 +++
13
MAINTAINERS | 2 +
20
hw/arm/bcm2835_peripherals.c | 11 +-
14
default-configs/arm-softmmu.mak | 1 +
21
hw/misc/bcm2835_cprman.c | 163 +++++++++++++++++++++
15
hw/misc/trace-events | 7 +
22
hw/misc/meson.build | 1 +
16
6 files changed, 321 insertions(+)
23
hw/misc/trace-events | 5 +
17
create mode 100644 include/hw/misc/iotkit-sysctl.h
24
7 files changed, 242 insertions(+), 2 deletions(-)
18
create mode 100644 hw/misc/iotkit-sysctl.c
25
create mode 100644 include/hw/misc/bcm2835_cprman.h
19
26
create mode 100644 include/hw/misc/bcm2835_cprman_internals.h
20
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
27
create mode 100644 hw/misc/bcm2835_cprman.c
28
29
diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h
21
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
22
--- a/hw/misc/Makefile.objs
31
--- a/include/hw/arm/bcm2835_peripherals.h
23
+++ b/hw/misc/Makefile.objs
32
+++ b/include/hw/arm/bcm2835_peripherals.h
24
@@ -XXX,XX +XXX,XX @@ obj-$(CONFIG_MPS2_SCC) += mps2-scc.o
33
@@ -XXX,XX +XXX,XX @@
25
obj-$(CONFIG_TZ_MPC) += tz-mpc.o
34
#include "hw/misc/bcm2835_mbox.h"
26
obj-$(CONFIG_TZ_PPC) += tz-ppc.o
35
#include "hw/misc/bcm2835_mphi.h"
27
obj-$(CONFIG_IOTKIT_SECCTL) += iotkit-secctl.o
36
#include "hw/misc/bcm2835_thermal.h"
28
+obj-$(CONFIG_IOTKIT_SYSCTL) += iotkit-sysctl.o
37
+#include "hw/misc/bcm2835_cprman.h"
29
38
#include "hw/sd/sdhci.h"
30
obj-$(CONFIG_PVPANIC) += pvpanic.o
39
#include "hw/sd/bcm2835_sdhost.h"
31
obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o
40
#include "hw/gpio/bcm2835_gpio.h"
32
diff --git a/include/hw/misc/iotkit-sysctl.h b/include/hw/misc/iotkit-sysctl.h
41
@@ -XXX,XX +XXX,XX @@ struct BCM2835PeripheralState {
42
UnimplementedDeviceState txp;
43
UnimplementedDeviceState armtmr;
44
UnimplementedDeviceState powermgt;
45
- UnimplementedDeviceState cprman;
46
+ BCM2835CprmanState cprman;
47
PL011State uart0;
48
BCM2835AuxState aux;
49
BCM2835FBState fb;
50
diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h
33
new file mode 100644
51
new file mode 100644
34
index XXXXXXX..XXXXXXX
52
index XXXXXXX..XXXXXXX
35
--- /dev/null
53
--- /dev/null
36
+++ b/include/hw/misc/iotkit-sysctl.h
54
+++ b/include/hw/misc/bcm2835_cprman.h
37
@@ -XXX,XX +XXX,XX @@
55
@@ -XXX,XX +XXX,XX @@
38
+/*
56
+/*
39
+ * ARM IoTKit system control element
57
+ * BCM2835 CPRMAN clock manager
40
+ *
58
+ *
41
+ * Copyright (c) 2018 Linaro Limited
59
+ * Copyright (c) 2020 Luc Michel <luc@lmichel.fr>
42
+ * Written by Peter Maydell
60
+ *
43
+ *
61
+ * SPDX-License-Identifier: GPL-2.0-or-later
44
+ * This program is free software; you can redistribute it and/or modify
62
+ */
45
+ * it under the terms of the GNU General Public License version 2 or
63
+
46
+ * (at your option) any later version.
64
+#ifndef HW_MISC_CPRMAN_H
47
+ */
65
+#define HW_MISC_CPRMAN_H
48
+
49
+/*
50
+ * This is a model of the "system control element" which is part of the
51
+ * Arm IoTKit and documented in
52
+ * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
53
+ * Specifically, it implements the "system information block" and
54
+ * "system control register" blocks.
55
+ *
56
+ * QEMU interface:
57
+ * + sysbus MMIO region 0: the system information register bank
58
+ * + sysbus MMIO region 1: the system control register bank
59
+ */
60
+
61
+#ifndef HW_MISC_IOTKIT_SYSCTL_H
62
+#define HW_MISC_IOTKIT_SYSCTL_H
63
+
66
+
64
+#include "hw/sysbus.h"
67
+#include "hw/sysbus.h"
65
+
68
+#include "hw/qdev-clock.h"
66
+#define TYPE_IOTKIT_SYSCTL "iotkit-sysctl"
69
+
67
+#define IOTKIT_SYSCTL(obj) OBJECT_CHECK(IoTKitSysCtl, (obj), \
70
+#define TYPE_BCM2835_CPRMAN "bcm2835-cprman"
68
+ TYPE_IOTKIT_SYSCTL)
71
+
69
+
72
+typedef struct BCM2835CprmanState BCM2835CprmanState;
70
+typedef struct IoTKitSysCtl {
73
+
74
+DECLARE_INSTANCE_CHECKER(BCM2835CprmanState, CPRMAN,
75
+ TYPE_BCM2835_CPRMAN)
76
+
77
+#define CPRMAN_NUM_REGS (0x2000 / sizeof(uint32_t))
78
+
79
+struct BCM2835CprmanState {
71
+ /*< private >*/
80
+ /*< private >*/
72
+ SysBusDevice parent_obj;
81
+ SysBusDevice parent_obj;
73
+
82
+
74
+ /*< public >*/
83
+ /*< public >*/
75
+ MemoryRegion iomem;
84
+ MemoryRegion iomem;
76
+
85
+
77
+ uint32_t secure_debug;
86
+ uint32_t regs[CPRMAN_NUM_REGS];
78
+ uint32_t reset_syndrome;
87
+ uint32_t xosc_freq;
79
+ uint32_t reset_mask;
88
+
80
+ uint32_t gretreg;
89
+ Clock *xosc;
81
+ uint32_t initsvrtor0;
90
+};
82
+ uint32_t cpuwait;
83
+ uint32_t wicctrl;
84
+} IoTKitSysCtl;
85
+
91
+
86
+#endif
92
+#endif
87
diff --git a/hw/misc/iotkit-sysctl.c b/hw/misc/iotkit-sysctl.c
93
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
88
new file mode 100644
94
new file mode 100644
89
index XXXXXXX..XXXXXXX
95
index XXXXXXX..XXXXXXX
90
--- /dev/null
96
--- /dev/null
91
+++ b/hw/misc/iotkit-sysctl.c
97
+++ b/include/hw/misc/bcm2835_cprman_internals.h
92
@@ -XXX,XX +XXX,XX @@
98
@@ -XXX,XX +XXX,XX @@
93
+/*
99
+/*
94
+ * ARM IoTKit system control element
100
+ * BCM2835 CPRMAN clock manager
95
+ *
101
+ *
96
+ * Copyright (c) 2018 Linaro Limited
102
+ * Copyright (c) 2020 Luc Michel <luc@lmichel.fr>
97
+ * Written by Peter Maydell
103
+ *
98
+ *
104
+ * SPDX-License-Identifier: GPL-2.0-or-later
99
+ * This program is free software; you can redistribute it and/or modify
105
+ */
100
+ * it under the terms of the GNU General Public License version 2 or
106
+
101
+ * (at your option) any later version.
107
+#ifndef HW_MISC_CPRMAN_INTERNALS_H
102
+ */
108
+#define HW_MISC_CPRMAN_INTERNALS_H
103
+
109
+
104
+/*
110
+#include "hw/registerfields.h"
105
+ * This is a model of the "system control element" which is part of the
111
+#include "hw/misc/bcm2835_cprman.h"
106
+ * Arm IoTKit and documented in
112
+
107
+ * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
113
+/* Register map */
108
+ * Specifically, it implements the "system control register" blocks.
114
+
115
+/*
116
+ * This field is common to all registers. Each register write value must match
117
+ * the CPRMAN_PASSWORD magic value in its 8 MSB.
118
+ */
119
+FIELD(CPRMAN, PASSWORD, 24, 8)
120
+#define CPRMAN_PASSWORD 0x5a
121
+
122
+#endif
123
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
124
index XXXXXXX..XXXXXXX 100644
125
--- a/hw/arm/bcm2835_peripherals.c
126
+++ b/hw/arm/bcm2835_peripherals.c
127
@@ -XXX,XX +XXX,XX @@ static void bcm2835_peripherals_init(Object *obj)
128
/* DWC2 */
129
object_initialize_child(obj, "dwc2", &s->dwc2, TYPE_DWC2_USB);
130
131
+ /* CPRMAN clock manager */
132
+ object_initialize_child(obj, "cprman", &s->cprman, TYPE_BCM2835_CPRMAN);
133
+
134
object_property_add_const_link(OBJECT(&s->dwc2), "dma-mr",
135
OBJECT(&s->gpu_bus_mr));
136
}
137
@@ -XXX,XX +XXX,XX @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
138
return;
139
}
140
141
+ /* CPRMAN clock manager */
142
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->cprman), errp)) {
143
+ return;
144
+ }
145
+ memory_region_add_subregion(&s->peri_mr, CPRMAN_OFFSET,
146
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cprman), 0));
147
+
148
memory_region_add_subregion(&s->peri_mr, ARMCTRL_IC_OFFSET,
149
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->ic), 0));
150
sysbus_pass_irq(SYS_BUS_DEVICE(s), SYS_BUS_DEVICE(&s->ic));
151
@@ -XXX,XX +XXX,XX @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
152
create_unimp(s, &s->txp, "bcm2835-txp", TXP_OFFSET, 0x1000);
153
create_unimp(s, &s->armtmr, "bcm2835-sp804", ARMCTRL_TIMER0_1_OFFSET, 0x40);
154
create_unimp(s, &s->powermgt, "bcm2835-powermgt", PM_OFFSET, 0x114);
155
- create_unimp(s, &s->cprman, "bcm2835-cprman", CPRMAN_OFFSET, 0x2000);
156
create_unimp(s, &s->i2s, "bcm2835-i2s", I2S_OFFSET, 0x100);
157
create_unimp(s, &s->smi, "bcm2835-smi", SMI_OFFSET, 0x100);
158
create_unimp(s, &s->spi[0], "bcm2835-spi0", SPI0_OFFSET, 0x20);
159
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
160
new file mode 100644
161
index XXXXXXX..XXXXXXX
162
--- /dev/null
163
+++ b/hw/misc/bcm2835_cprman.c
164
@@ -XXX,XX +XXX,XX @@
165
+/*
166
+ * BCM2835 CPRMAN clock manager
167
+ *
168
+ * Copyright (c) 2020 Luc Michel <luc@lmichel.fr>
169
+ *
170
+ * SPDX-License-Identifier: GPL-2.0-or-later
171
+ */
172
+
173
+/*
174
+ * This peripheral is roughly divided into 3 main parts:
175
+ * - the PLLs
176
+ * - the PLL channels
177
+ * - the clock muxes
178
+ *
179
+ * A main oscillator (xosc) feeds all the PLLs. Each PLLs has one or more
180
+ * channels. Those channel are then connected to the clock muxes. Each mux has
181
+ * multiples sources (usually the xosc, some of the PLL channels and some "test
182
+ * debug" clocks). A mux is configured to select a given source through its
183
+ * control register. Each mux has one output clock that also goes out of the
184
+ * CPRMAN. This output clock usually connects to another peripheral in the SoC
185
+ * (so a given mux is dedicated to a peripheral).
186
+ *
187
+ * At each level (PLL, channel and mux), the clock can be altered through
188
+ * dividers (and multipliers in case of the PLLs), and can be disabled (in this
189
+ * case, the next levels see no clock).
190
+ *
191
+ * This can be sum-up as follows (this is an example and not the actual BCM2835
192
+ * clock tree):
193
+ *
194
+ * /-->[PLL]-|->[PLL channel]--... [mux]--> to peripherals
195
+ * | |->[PLL channel] muxes takes [mux]
196
+ * | \->[PLL channel] inputs from [mux]
197
+ * | some channels [mux]
198
+ * [xosc]---|-->[PLL]-|->[PLL channel] and other srcs [mux]
199
+ * | \->[PLL channel] ...-->[mux]
200
+ * | [mux]
201
+ * \-->[PLL]--->[PLL channel] [mux]
202
+ *
203
+ * The page at https://elinux.org/The_Undocumented_Pi gives the actual clock
204
+ * tree configuration.
109
+ */
205
+ */
110
+
206
+
111
+#include "qemu/osdep.h"
207
+#include "qemu/osdep.h"
112
+#include "qemu/log.h"
208
+#include "qemu/log.h"
209
+#include "migration/vmstate.h"
210
+#include "hw/qdev-properties.h"
211
+#include "hw/misc/bcm2835_cprman.h"
212
+#include "hw/misc/bcm2835_cprman_internals.h"
113
+#include "trace.h"
213
+#include "trace.h"
114
+#include "qapi/error.h"
214
+
115
+#include "sysemu/sysemu.h"
215
+/* CPRMAN "top level" model */
116
+#include "hw/sysbus.h"
216
+
117
+#include "hw/registerfields.h"
217
+static uint64_t cprman_read(void *opaque, hwaddr offset,
118
+#include "hw/misc/iotkit-sysctl.h"
218
+ unsigned size)
119
+
219
+{
120
+REG32(SECDBGSTAT, 0x0)
220
+ BCM2835CprmanState *s = CPRMAN(opaque);
121
+REG32(SECDBGSET, 0x4)
221
+ uint64_t r = 0;
122
+REG32(SECDBGCLR, 0x8)
222
+ size_t idx = offset / sizeof(uint32_t);
123
+REG32(RESET_SYNDROME, 0x100)
223
+
124
+REG32(RESET_MASK, 0x104)
224
+ switch (idx) {
125
+REG32(SWRESET, 0x108)
126
+ FIELD(SWRESET, SWRESETREQ, 9, 1)
127
+REG32(GRETREG, 0x10c)
128
+REG32(INITSVRTOR0, 0x110)
129
+REG32(CPUWAIT, 0x118)
130
+REG32(BUSWAIT, 0x11c)
131
+REG32(WICCTRL, 0x120)
132
+REG32(PID4, 0xfd0)
133
+REG32(PID5, 0xfd4)
134
+REG32(PID6, 0xfd8)
135
+REG32(PID7, 0xfdc)
136
+REG32(PID0, 0xfe0)
137
+REG32(PID1, 0xfe4)
138
+REG32(PID2, 0xfe8)
139
+REG32(PID3, 0xfec)
140
+REG32(CID0, 0xff0)
141
+REG32(CID1, 0xff4)
142
+REG32(CID2, 0xff8)
143
+REG32(CID3, 0xffc)
144
+
145
+/* PID/CID values */
146
+static const int sysctl_id[] = {
147
+ 0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
148
+ 0x54, 0xb8, 0x0b, 0x00, /* PID0..PID3 */
149
+ 0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
150
+};
151
+
152
+static uint64_t iotkit_sysctl_read(void *opaque, hwaddr offset,
153
+ unsigned size)
154
+{
155
+ IoTKitSysCtl *s = IOTKIT_SYSCTL(opaque);
156
+ uint64_t r;
157
+
158
+ switch (offset) {
159
+ case A_SECDBGSTAT:
160
+ r = s->secure_debug;
161
+ break;
162
+ case A_RESET_SYNDROME:
163
+ r = s->reset_syndrome;
164
+ break;
165
+ case A_RESET_MASK:
166
+ r = s->reset_mask;
167
+ break;
168
+ case A_GRETREG:
169
+ r = s->gretreg;
170
+ break;
171
+ case A_INITSVRTOR0:
172
+ r = s->initsvrtor0;
173
+ break;
174
+ case A_CPUWAIT:
175
+ r = s->cpuwait;
176
+ break;
177
+ case A_BUSWAIT:
178
+ /* In IoTKit BUSWAIT is reserved, R/O, zero */
179
+ r = 0;
180
+ break;
181
+ case A_WICCTRL:
182
+ r = s->wicctrl;
183
+ break;
184
+ case A_PID4 ... A_CID3:
185
+ r = sysctl_id[(offset - A_PID4) / 4];
186
+ break;
187
+ case A_SECDBGSET:
188
+ case A_SECDBGCLR:
189
+ case A_SWRESET:
190
+ qemu_log_mask(LOG_GUEST_ERROR,
191
+ "IoTKit SysCtl read: read of WO offset %x\n",
192
+ (int)offset);
193
+ r = 0;
194
+ break;
195
+ default:
225
+ default:
196
+ qemu_log_mask(LOG_GUEST_ERROR,
226
+ r = s->regs[idx];
197
+ "IoTKit SysCtl read: bad offset %x\n", (int)offset);
198
+ r = 0;
199
+ break;
200
+ }
227
+ }
201
+ trace_iotkit_sysctl_read(offset, r, size);
228
+
229
+ trace_bcm2835_cprman_read(offset, r);
202
+ return r;
230
+ return r;
203
+}
231
+}
204
+
232
+
205
+static void iotkit_sysctl_write(void *opaque, hwaddr offset,
233
+static void cprman_write(void *opaque, hwaddr offset,
206
+ uint64_t value, unsigned size)
234
+ uint64_t value, unsigned size)
207
+{
235
+{
208
+ IoTKitSysCtl *s = IOTKIT_SYSCTL(opaque);
236
+ BCM2835CprmanState *s = CPRMAN(opaque);
209
+
237
+ size_t idx = offset / sizeof(uint32_t);
210
+ trace_iotkit_sysctl_write(offset, value, size);
238
+
211
+
239
+ if (FIELD_EX32(value, CPRMAN, PASSWORD) != CPRMAN_PASSWORD) {
212
+ /*
240
+ trace_bcm2835_cprman_write_invalid_magic(offset, value);
213
+ * Most of the state here has to do with control of reset and
241
+ return;
214
+ * similar kinds of power up -- for instance the guest can ask
242
+ }
215
+ * what the reason for the last reset was, or forbid reset for
243
+
216
+ * some causes (like the non-secure watchdog). Most of this is
244
+ value &= ~R_CPRMAN_PASSWORD_MASK;
217
+ * not relevant to QEMU, which doesn't really model anything other
245
+
218
+ * than a full power-on reset.
246
+ trace_bcm2835_cprman_write(offset, value);
219
+ * We just model the registers as reads-as-written.
247
+ s->regs[idx] = value;
220
+ */
248
+
221
+
249
+}
222
+ switch (offset) {
250
+
223
+ case A_RESET_SYNDROME:
251
+static const MemoryRegionOps cprman_ops = {
224
+ qemu_log_mask(LOG_UNIMP,
252
+ .read = cprman_read,
225
+ "IoTKit SysCtl RESET_SYNDROME unimplemented\n");
253
+ .write = cprman_write,
226
+ s->reset_syndrome = value;
254
+ .endianness = DEVICE_LITTLE_ENDIAN,
227
+ break;
255
+ .valid = {
228
+ case A_RESET_MASK:
229
+ qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl RESET_MASK unimplemented\n");
230
+ s->reset_mask = value;
231
+ break;
232
+ case A_GRETREG:
233
+ /*
256
+ /*
234
+ * General retention register, which is only reset by a power-on
257
+ * Although this hasn't been checked against real hardware, nor the
235
+ * reset. Technically this implementation is complete, since
258
+ * information can be found in a datasheet, it seems reasonable because
236
+ * QEMU only supports power-on resets...
259
+ * of the "PASSWORD" magic value found in every registers.
237
+ */
260
+ */
238
+ s->gretreg = value;
261
+ .min_access_size = 4,
239
+ break;
262
+ .max_access_size = 4,
240
+ case A_INITSVRTOR0:
263
+ .unaligned = false,
241
+ qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl INITSVRTOR0 unimplemented\n");
264
+ },
242
+ s->initsvrtor0 = value;
265
+ .impl = {
243
+ break;
266
+ .max_access_size = 4,
244
+ case A_CPUWAIT:
267
+ },
245
+ qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl CPUWAIT unimplemented\n");
268
+};
246
+ s->cpuwait = value;
269
+
247
+ break;
270
+static void cprman_reset(DeviceState *dev)
248
+ case A_WICCTRL:
271
+{
249
+ qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl WICCTRL unimplemented\n");
272
+ BCM2835CprmanState *s = CPRMAN(dev);
250
+ s->wicctrl = value;
273
+
251
+ break;
274
+ memset(s->regs, 0, sizeof(s->regs));
252
+ case A_SECDBGSET:
275
+
253
+ /* write-1-to-set */
276
+ clock_update_hz(s->xosc, s->xosc_freq);
254
+ qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl SECDBGSET unimplemented\n");
277
+}
255
+ s->secure_debug |= value;
278
+
256
+ break;
279
+static void cprman_init(Object *obj)
257
+ case A_SECDBGCLR:
280
+{
258
+ /* write-1-to-clear */
281
+ BCM2835CprmanState *s = CPRMAN(obj);
259
+ s->secure_debug &= ~value;
282
+
260
+ break;
283
+ s->xosc = clock_new(obj, "xosc");
261
+ case A_SWRESET:
284
+
262
+ /* One w/o bit to request a reset; all other bits reserved */
285
+ memory_region_init_io(&s->iomem, obj, &cprman_ops,
263
+ if (value & R_SWRESET_SWRESETREQ_MASK) {
286
+ s, "bcm2835-cprman", 0x2000);
264
+ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
287
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
265
+ }
288
+}
266
+ break;
289
+
267
+ case A_BUSWAIT: /* In IoTKit BUSWAIT is reserved, R/O, zero */
290
+static const VMStateDescription cprman_vmstate = {
268
+ case A_SECDBGSTAT:
291
+ .name = TYPE_BCM2835_CPRMAN,
269
+ case A_PID4 ... A_CID3:
270
+ qemu_log_mask(LOG_GUEST_ERROR,
271
+ "IoTKit SysCtl write: write of RO offset %x\n",
272
+ (int)offset);
273
+ break;
274
+ default:
275
+ qemu_log_mask(LOG_GUEST_ERROR,
276
+ "IoTKit SysCtl write: bad offset %x\n", (int)offset);
277
+ break;
278
+ }
279
+}
280
+
281
+static const MemoryRegionOps iotkit_sysctl_ops = {
282
+ .read = iotkit_sysctl_read,
283
+ .write = iotkit_sysctl_write,
284
+ .endianness = DEVICE_LITTLE_ENDIAN,
285
+ /* byte/halfword accesses are just zero-padded on reads and writes */
286
+ .impl.min_access_size = 4,
287
+ .impl.max_access_size = 4,
288
+ .valid.min_access_size = 1,
289
+ .valid.max_access_size = 4,
290
+};
291
+
292
+static void iotkit_sysctl_reset(DeviceState *dev)
293
+{
294
+ IoTKitSysCtl *s = IOTKIT_SYSCTL(dev);
295
+
296
+ trace_iotkit_sysctl_reset();
297
+ s->secure_debug = 0;
298
+ s->reset_syndrome = 1;
299
+ s->reset_mask = 0;
300
+ s->gretreg = 0;
301
+ s->initsvrtor0 = 0x10000000;
302
+ s->cpuwait = 0;
303
+ s->wicctrl = 0;
304
+}
305
+
306
+static void iotkit_sysctl_init(Object *obj)
307
+{
308
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
309
+ IoTKitSysCtl *s = IOTKIT_SYSCTL(obj);
310
+
311
+ memory_region_init_io(&s->iomem, obj, &iotkit_sysctl_ops,
312
+ s, "iotkit-sysctl", 0x1000);
313
+ sysbus_init_mmio(sbd, &s->iomem);
314
+}
315
+
316
+static const VMStateDescription iotkit_sysctl_vmstate = {
317
+ .name = "iotkit-sysctl",
318
+ .version_id = 1,
292
+ .version_id = 1,
319
+ .minimum_version_id = 1,
293
+ .minimum_version_id = 1,
320
+ .fields = (VMStateField[]) {
294
+ .fields = (VMStateField[]) {
321
+ VMSTATE_UINT32(secure_debug, IoTKitSysCtl),
295
+ VMSTATE_UINT32_ARRAY(regs, BCM2835CprmanState, CPRMAN_NUM_REGS),
322
+ VMSTATE_UINT32(reset_syndrome, IoTKitSysCtl),
323
+ VMSTATE_UINT32(reset_mask, IoTKitSysCtl),
324
+ VMSTATE_UINT32(gretreg, IoTKitSysCtl),
325
+ VMSTATE_UINT32(initsvrtor0, IoTKitSysCtl),
326
+ VMSTATE_UINT32(cpuwait, IoTKitSysCtl),
327
+ VMSTATE_UINT32(wicctrl, IoTKitSysCtl),
328
+ VMSTATE_END_OF_LIST()
296
+ VMSTATE_END_OF_LIST()
329
+ }
297
+ }
330
+};
298
+};
331
+
299
+
332
+static void iotkit_sysctl_class_init(ObjectClass *klass, void *data)
300
+static Property cprman_properties[] = {
301
+ DEFINE_PROP_UINT32("xosc-freq-hz", BCM2835CprmanState, xosc_freq, 19200000),
302
+ DEFINE_PROP_END_OF_LIST()
303
+};
304
+
305
+static void cprman_class_init(ObjectClass *klass, void *data)
333
+{
306
+{
334
+ DeviceClass *dc = DEVICE_CLASS(klass);
307
+ DeviceClass *dc = DEVICE_CLASS(klass);
335
+
308
+
336
+ dc->vmsd = &iotkit_sysctl_vmstate;
309
+ dc->reset = cprman_reset;
337
+ dc->reset = iotkit_sysctl_reset;
310
+ dc->vmsd = &cprman_vmstate;
338
+}
311
+ device_class_set_props(dc, cprman_properties);
339
+
312
+}
340
+static const TypeInfo iotkit_sysctl_info = {
313
+
341
+ .name = TYPE_IOTKIT_SYSCTL,
314
+static const TypeInfo cprman_info = {
315
+ .name = TYPE_BCM2835_CPRMAN,
342
+ .parent = TYPE_SYS_BUS_DEVICE,
316
+ .parent = TYPE_SYS_BUS_DEVICE,
343
+ .instance_size = sizeof(IoTKitSysCtl),
317
+ .instance_size = sizeof(BCM2835CprmanState),
344
+ .instance_init = iotkit_sysctl_init,
318
+ .class_init = cprman_class_init,
345
+ .class_init = iotkit_sysctl_class_init,
319
+ .instance_init = cprman_init,
346
+};
320
+};
347
+
321
+
348
+static void iotkit_sysctl_register_types(void)
322
+static void cprman_register_types(void)
349
+{
323
+{
350
+ type_register_static(&iotkit_sysctl_info);
324
+ type_register_static(&cprman_info);
351
+}
325
+}
352
+
326
+
353
+type_init(iotkit_sysctl_register_types);
327
+type_init(cprman_register_types);
354
diff --git a/MAINTAINERS b/MAINTAINERS
328
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
355
index XXXXXXX..XXXXXXX 100644
329
index XXXXXXX..XXXXXXX 100644
356
--- a/MAINTAINERS
330
--- a/hw/misc/meson.build
357
+++ b/MAINTAINERS
331
+++ b/hw/misc/meson.build
358
@@ -XXX,XX +XXX,XX @@ F: hw/misc/mps2-*.c
332
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files(
359
F: include/hw/misc/mps2-*.h
333
'bcm2835_property.c',
360
F: hw/arm/iotkit.c
334
'bcm2835_rng.c',
361
F: include/hw/arm/iotkit.h
335
'bcm2835_thermal.c',
362
+F: hw/misc/iotkit-sysctl.c
336
+ 'bcm2835_cprman.c',
363
+F: include/hw/misc/iotkit-sysctl.h
337
))
364
338
softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_misc.c'))
365
Musicpal
339
softmmu_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq_slcr.c', 'zynq-xadc.c'))
366
M: Jan Kiszka <jan.kiszka@web.de>
367
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
368
index XXXXXXX..XXXXXXX 100644
369
--- a/default-configs/arm-softmmu.mak
370
+++ b/default-configs/arm-softmmu.mak
371
@@ -XXX,XX +XXX,XX @@ CONFIG_TZ_MPC=y
372
CONFIG_TZ_PPC=y
373
CONFIG_IOTKIT=y
374
CONFIG_IOTKIT_SECCTL=y
375
+CONFIG_IOTKIT_SYSCTL=y
376
377
CONFIG_VERSATILE=y
378
CONFIG_VERSATILE_PCI=y
379
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
340
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
380
index XXXXXXX..XXXXXXX 100644
341
index XXXXXXX..XXXXXXX 100644
381
--- a/hw/misc/trace-events
342
--- a/hw/misc/trace-events
382
+++ b/hw/misc/trace-events
343
+++ b/hw/misc/trace-events
383
@@ -XXX,XX +XXX,XX @@ ccm_freq(uint32_t freq) "freq = %d\n"
344
@@ -XXX,XX +XXX,XX @@ grlib_apb_pnp_read(uint64_t addr, uint32_t value) "APB PnP read addr:0x%03"PRIx6
384
ccm_clock_freq(uint32_t clock, uint32_t freq) "(Clock = %d) = %d\n"
345
# pca9552.c
385
ccm_read_reg(const char *reg_name, uint32_t value) "reg[%s] <= 0x%" PRIx32 "\n"
346
pca955x_gpio_status(const char *description, const char *buf) "%s GPIOs 0-15 [%s]"
386
ccm_write_reg(const char *reg_name, uint32_t value) "reg[%s] => 0x%" PRIx32 "\n"
347
pca955x_gpio_change(const char *description, unsigned id, unsigned prev_state, unsigned current_state) "%s GPIO id:%u status: %u -> %u"
387
+
348
+
388
+# hw/misc/iotkit-sysctl.c
349
+# bcm2835_cprman.c
389
+iotkit_sysinfo_read(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysInfo read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
350
+bcm2835_cprman_read(uint64_t offset, uint64_t value) "offset:0x%" PRIx64 " value:0x%" PRIx64
390
+iotkit_sysinfo_write(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysInfo write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
351
+bcm2835_cprman_write(uint64_t offset, uint64_t value) "offset:0x%" PRIx64 " value:0x%" PRIx64
391
+iotkit_sysctl_read(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysCtl read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
352
+bcm2835_cprman_write_invalid_magic(uint64_t offset, uint64_t value) "offset:0x%" PRIx64 " value:0x%" PRIx64
392
+iotkit_sysctl_write(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysCtl write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
393
+iotkit_sysctl_reset(void) "IoTKit SysCtl: reset"
394
--
353
--
395
2.18.0
354
2.20.1
396
355
397
356
diff view generated by jsdifflib
1
From: Richard Henderson <richard.henderson@linaro.org>
1
From: Luc Michel <luc@lmichel.fr>
2
2
3
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
3
There are 5 PLLs in the CPRMAN, namely PLL A, C, D, H and B. All of them
4
Message-id: 20180814002653.12828-5-richard.henderson@linaro.org
4
take the xosc clock as input and produce a new clock.
5
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
5
6
This commit adds a skeleton implementation for the PLLs as sub-devices
7
of the CPRMAN. The PLLs are instantiated and connected internally to the
8
main oscillator.
9
10
Each PLL has 6 registers : CM, A2W_CTRL, A2W_ANA[0,1,2,3], A2W_FRAC. A
11
write to any of them triggers a call to the (not yet implemented)
12
pll_update function.
13
14
If the main oscillator changes frequency, an update is also triggered.
15
16
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
17
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
18
Signed-off-by: Luc Michel <luc@lmichel.fr>
19
Tested-by: Guenter Roeck <linux@roeck-us.net>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
20
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
---
21
---
8
target/arm/helper.c | 101 ++++++++++++++++++++++----------------------
22
include/hw/misc/bcm2835_cprman.h | 29 +++++
9
1 file changed, 51 insertions(+), 50 deletions(-)
23
include/hw/misc/bcm2835_cprman_internals.h | 144 +++++++++++++++++++++
10
24
hw/misc/bcm2835_cprman.c | 108 ++++++++++++++++
11
diff --git a/target/arm/helper.c b/target/arm/helper.c
25
3 files changed, 281 insertions(+)
26
27
diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h
12
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
13
--- a/target/arm/helper.c
29
--- a/include/hw/misc/bcm2835_cprman.h
14
+++ b/target/arm/helper.c
30
+++ b/include/hw/misc/bcm2835_cprman.h
15
@@ -XXX,XX +XXX,XX @@ float##fsz HELPER(vfp_##name##to##p)(uint##isz##_t x, uint32_t shift, \
31
@@ -XXX,XX +XXX,XX @@ DECLARE_INSTANCE_CHECKER(BCM2835CprmanState, CPRMAN,
16
void *fpstp) \
32
17
{ return itype##_to_##float##fsz##_scalbn(x, -shift, fpstp); }
33
#define CPRMAN_NUM_REGS (0x2000 / sizeof(uint32_t))
18
34
19
-/* Notice that we want only input-denormal exception flags from the
35
+typedef enum CprmanPll {
20
- * scalbn operation: the other possible flags (overflow+inexact if
36
+ CPRMAN_PLLA = 0,
21
- * we overflow to infinity, output-denormal) aren't correct for the
37
+ CPRMAN_PLLC,
22
- * complete scale-and-convert operation.
38
+ CPRMAN_PLLD,
23
- */
39
+ CPRMAN_PLLH,
24
-#define VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, round) \
40
+ CPRMAN_PLLB,
25
-uint##isz##_t HELPER(vfp_to##name##p##round)(float##fsz x, \
41
+
26
- uint32_t shift, \
42
+ CPRMAN_NUM_PLL
27
- void *fpstp) \
43
+} CprmanPll;
28
-{ \
44
+
29
- float_status *fpst = fpstp; \
45
+typedef struct CprmanPllState {
30
- int old_exc_flags = get_float_exception_flags(fpst); \
46
+ /*< private >*/
31
- float##fsz tmp; \
47
+ DeviceState parent_obj;
32
- if (float##fsz##_is_any_nan(x)) { \
48
+
33
- float_raise(float_flag_invalid, fpst); \
49
+ /*< public >*/
34
- return 0; \
50
+ CprmanPll id;
35
- } \
51
+
36
- tmp = float##fsz##_scalbn(x, shift, fpst); \
52
+ uint32_t *reg_cm;
37
- old_exc_flags |= get_float_exception_flags(fpst) \
53
+ uint32_t *reg_a2w_ctrl;
38
- & float_flag_input_denormal; \
54
+ uint32_t *reg_a2w_ana; /* ANA[0] .. ANA[3] */
39
- set_float_exception_flags(old_exc_flags, fpst); \
55
+ uint32_t prediv_mask; /* prediv bit in ana[1] */
40
- return float##fsz##_to_##itype##round(tmp, fpst); \
56
+ uint32_t *reg_a2w_frac;
41
+#define VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, ROUND, suff) \
57
+
42
+uint##isz##_t HELPER(vfp_to##name##p##suff)(float##fsz x, uint32_t shift, \
58
+ Clock *xosc_in;
43
+ void *fpst) \
59
+ Clock *out;
44
+{ \
60
+} CprmanPllState;
45
+ if (unlikely(float##fsz##_is_any_nan(x))) { \
61
+
46
+ float_raise(float_flag_invalid, fpst); \
62
struct BCM2835CprmanState {
47
+ return 0; \
63
/*< private >*/
48
+ } \
64
SysBusDevice parent_obj;
49
+ return float##fsz##_to_##itype##_scalbn(x, ROUND, shift, fpst); \
65
@@ -XXX,XX +XXX,XX @@ struct BCM2835CprmanState {
66
/*< public >*/
67
MemoryRegion iomem;
68
69
+ CprmanPllState plls[CPRMAN_NUM_PLL];
70
+
71
uint32_t regs[CPRMAN_NUM_REGS];
72
uint32_t xosc_freq;
73
74
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
75
index XXXXXXX..XXXXXXX 100644
76
--- a/include/hw/misc/bcm2835_cprman_internals.h
77
+++ b/include/hw/misc/bcm2835_cprman_internals.h
78
@@ -XXX,XX +XXX,XX @@
79
#include "hw/registerfields.h"
80
#include "hw/misc/bcm2835_cprman.h"
81
82
+#define TYPE_CPRMAN_PLL "bcm2835-cprman-pll"
83
+
84
+DECLARE_INSTANCE_CHECKER(CprmanPllState, CPRMAN_PLL,
85
+ TYPE_CPRMAN_PLL)
86
+
87
/* Register map */
88
89
+/* PLLs */
90
+REG32(CM_PLLA, 0x104)
91
+ FIELD(CM_PLLA, LOADDSI0, 0, 1)
92
+ FIELD(CM_PLLA, HOLDDSI0, 1, 1)
93
+ FIELD(CM_PLLA, LOADCCP2, 2, 1)
94
+ FIELD(CM_PLLA, HOLDCCP2, 3, 1)
95
+ FIELD(CM_PLLA, LOADCORE, 4, 1)
96
+ FIELD(CM_PLLA, HOLDCORE, 5, 1)
97
+ FIELD(CM_PLLA, LOADPER, 6, 1)
98
+ FIELD(CM_PLLA, HOLDPER, 7, 1)
99
+ FIELD(CM_PLLx, ANARST, 8, 1)
100
+REG32(CM_PLLC, 0x108)
101
+ FIELD(CM_PLLC, LOADCORE0, 0, 1)
102
+ FIELD(CM_PLLC, HOLDCORE0, 1, 1)
103
+ FIELD(CM_PLLC, LOADCORE1, 2, 1)
104
+ FIELD(CM_PLLC, HOLDCORE1, 3, 1)
105
+ FIELD(CM_PLLC, LOADCORE2, 4, 1)
106
+ FIELD(CM_PLLC, HOLDCORE2, 5, 1)
107
+ FIELD(CM_PLLC, LOADPER, 6, 1)
108
+ FIELD(CM_PLLC, HOLDPER, 7, 1)
109
+REG32(CM_PLLD, 0x10c)
110
+ FIELD(CM_PLLD, LOADDSI0, 0, 1)
111
+ FIELD(CM_PLLD, HOLDDSI0, 1, 1)
112
+ FIELD(CM_PLLD, LOADDSI1, 2, 1)
113
+ FIELD(CM_PLLD, HOLDDSI1, 3, 1)
114
+ FIELD(CM_PLLD, LOADCORE, 4, 1)
115
+ FIELD(CM_PLLD, HOLDCORE, 5, 1)
116
+ FIELD(CM_PLLD, LOADPER, 6, 1)
117
+ FIELD(CM_PLLD, HOLDPER, 7, 1)
118
+REG32(CM_PLLH, 0x110)
119
+ FIELD(CM_PLLH, LOADPIX, 0, 1)
120
+ FIELD(CM_PLLH, LOADAUX, 1, 1)
121
+ FIELD(CM_PLLH, LOADRCAL, 2, 1)
122
+REG32(CM_PLLB, 0x170)
123
+ FIELD(CM_PLLB, LOADARM, 0, 1)
124
+ FIELD(CM_PLLB, HOLDARM, 1, 1)
125
+
126
+REG32(A2W_PLLA_CTRL, 0x1100)
127
+ FIELD(A2W_PLLx_CTRL, NDIV, 0, 10)
128
+ FIELD(A2W_PLLx_CTRL, PDIV, 12, 3)
129
+ FIELD(A2W_PLLx_CTRL, PWRDN, 16, 1)
130
+ FIELD(A2W_PLLx_CTRL, PRST_DISABLE, 17, 1)
131
+REG32(A2W_PLLC_CTRL, 0x1120)
132
+REG32(A2W_PLLD_CTRL, 0x1140)
133
+REG32(A2W_PLLH_CTRL, 0x1160)
134
+REG32(A2W_PLLB_CTRL, 0x11e0)
135
+
136
+REG32(A2W_PLLA_ANA0, 0x1010)
137
+REG32(A2W_PLLA_ANA1, 0x1014)
138
+ FIELD(A2W_PLLx_ANA1, FB_PREDIV, 14, 1)
139
+REG32(A2W_PLLA_ANA2, 0x1018)
140
+REG32(A2W_PLLA_ANA3, 0x101c)
141
+
142
+REG32(A2W_PLLC_ANA0, 0x1030)
143
+REG32(A2W_PLLC_ANA1, 0x1034)
144
+REG32(A2W_PLLC_ANA2, 0x1038)
145
+REG32(A2W_PLLC_ANA3, 0x103c)
146
+
147
+REG32(A2W_PLLD_ANA0, 0x1050)
148
+REG32(A2W_PLLD_ANA1, 0x1054)
149
+REG32(A2W_PLLD_ANA2, 0x1058)
150
+REG32(A2W_PLLD_ANA3, 0x105c)
151
+
152
+REG32(A2W_PLLH_ANA0, 0x1070)
153
+REG32(A2W_PLLH_ANA1, 0x1074)
154
+ FIELD(A2W_PLLH_ANA1, FB_PREDIV, 11, 1)
155
+REG32(A2W_PLLH_ANA2, 0x1078)
156
+REG32(A2W_PLLH_ANA3, 0x107c)
157
+
158
+REG32(A2W_PLLB_ANA0, 0x10f0)
159
+REG32(A2W_PLLB_ANA1, 0x10f4)
160
+REG32(A2W_PLLB_ANA2, 0x10f8)
161
+REG32(A2W_PLLB_ANA3, 0x10fc)
162
+
163
+REG32(A2W_PLLA_FRAC, 0x1200)
164
+ FIELD(A2W_PLLx_FRAC, FRAC, 0, 20)
165
+REG32(A2W_PLLC_FRAC, 0x1220)
166
+REG32(A2W_PLLD_FRAC, 0x1240)
167
+REG32(A2W_PLLH_FRAC, 0x1260)
168
+REG32(A2W_PLLB_FRAC, 0x12e0)
169
+
170
/*
171
* This field is common to all registers. Each register write value must match
172
* the CPRMAN_PASSWORD magic value in its 8 MSB.
173
@@ -XXX,XX +XXX,XX @@
174
FIELD(CPRMAN, PASSWORD, 24, 8)
175
#define CPRMAN_PASSWORD 0x5a
176
177
+/* PLL init info */
178
+typedef struct PLLInitInfo {
179
+ const char *name;
180
+ size_t cm_offset;
181
+ size_t a2w_ctrl_offset;
182
+ size_t a2w_ana_offset;
183
+ uint32_t prediv_mask; /* Prediv bit in ana[1] */
184
+ size_t a2w_frac_offset;
185
+} PLLInitInfo;
186
+
187
+#define FILL_PLL_INIT_INFO(pll_) \
188
+ .cm_offset = R_CM_ ## pll_, \
189
+ .a2w_ctrl_offset = R_A2W_ ## pll_ ## _CTRL, \
190
+ .a2w_ana_offset = R_A2W_ ## pll_ ## _ANA0, \
191
+ .a2w_frac_offset = R_A2W_ ## pll_ ## _FRAC
192
+
193
+static const PLLInitInfo PLL_INIT_INFO[] = {
194
+ [CPRMAN_PLLA] = {
195
+ .name = "plla",
196
+ .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK,
197
+ FILL_PLL_INIT_INFO(PLLA),
198
+ },
199
+ [CPRMAN_PLLC] = {
200
+ .name = "pllc",
201
+ .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK,
202
+ FILL_PLL_INIT_INFO(PLLC),
203
+ },
204
+ [CPRMAN_PLLD] = {
205
+ .name = "plld",
206
+ .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK,
207
+ FILL_PLL_INIT_INFO(PLLD),
208
+ },
209
+ [CPRMAN_PLLH] = {
210
+ .name = "pllh",
211
+ .prediv_mask = R_A2W_PLLH_ANA1_FB_PREDIV_MASK,
212
+ FILL_PLL_INIT_INFO(PLLH),
213
+ },
214
+ [CPRMAN_PLLB] = {
215
+ .name = "pllb",
216
+ .prediv_mask = R_A2W_PLLx_ANA1_FB_PREDIV_MASK,
217
+ FILL_PLL_INIT_INFO(PLLB),
218
+ },
219
+};
220
+
221
+#undef FILL_PLL_CHANNEL_INIT_INFO
222
+
223
+static inline void set_pll_init_info(BCM2835CprmanState *s,
224
+ CprmanPllState *pll,
225
+ CprmanPll id)
226
+{
227
+ pll->id = id;
228
+ pll->reg_cm = &s->regs[PLL_INIT_INFO[id].cm_offset];
229
+ pll->reg_a2w_ctrl = &s->regs[PLL_INIT_INFO[id].a2w_ctrl_offset];
230
+ pll->reg_a2w_ana = &s->regs[PLL_INIT_INFO[id].a2w_ana_offset];
231
+ pll->prediv_mask = PLL_INIT_INFO[id].prediv_mask;
232
+ pll->reg_a2w_frac = &s->regs[PLL_INIT_INFO[id].a2w_frac_offset];
233
+}
234
+
235
#endif
236
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
237
index XXXXXXX..XXXXXXX 100644
238
--- a/hw/misc/bcm2835_cprman.c
239
+++ b/hw/misc/bcm2835_cprman.c
240
@@ -XXX,XX +XXX,XX @@
241
#include "hw/misc/bcm2835_cprman_internals.h"
242
#include "trace.h"
243
244
+/* PLL */
245
+
246
+static void pll_update(CprmanPllState *pll)
247
+{
248
+ clock_update(pll->out, 0);
249
+}
250
+
251
+static void pll_xosc_update(void *opaque)
252
+{
253
+ pll_update(CPRMAN_PLL(opaque));
254
+}
255
+
256
+static void pll_init(Object *obj)
257
+{
258
+ CprmanPllState *s = CPRMAN_PLL(obj);
259
+
260
+ s->xosc_in = qdev_init_clock_in(DEVICE(s), "xosc-in", pll_xosc_update, s);
261
+ s->out = qdev_init_clock_out(DEVICE(s), "out");
262
+}
263
+
264
+static const VMStateDescription pll_vmstate = {
265
+ .name = TYPE_CPRMAN_PLL,
266
+ .version_id = 1,
267
+ .minimum_version_id = 1,
268
+ .fields = (VMStateField[]) {
269
+ VMSTATE_CLOCK(xosc_in, CprmanPllState),
270
+ VMSTATE_END_OF_LIST()
271
+ }
272
+};
273
+
274
+static void pll_class_init(ObjectClass *klass, void *data)
275
+{
276
+ DeviceClass *dc = DEVICE_CLASS(klass);
277
+
278
+ dc->vmsd = &pll_vmstate;
279
+}
280
+
281
+static const TypeInfo cprman_pll_info = {
282
+ .name = TYPE_CPRMAN_PLL,
283
+ .parent = TYPE_DEVICE,
284
+ .instance_size = sizeof(CprmanPllState),
285
+ .class_init = pll_class_init,
286
+ .instance_init = pll_init,
287
+};
288
+
289
+
290
/* CPRMAN "top level" model */
291
292
static uint64_t cprman_read(void *opaque, hwaddr offset,
293
@@ -XXX,XX +XXX,XX @@ static uint64_t cprman_read(void *opaque, hwaddr offset,
294
return r;
50
}
295
}
51
296
52
#define VFP_CONV_FIX(name, p, fsz, isz, itype) \
297
+#define CASE_PLL_REGS(pll_) \
53
VFP_CONV_FIX_FLOAT(name, p, fsz, isz, itype) \
298
+ case R_CM_ ## pll_: \
54
-VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, _round_to_zero) \
299
+ case R_A2W_ ## pll_ ## _CTRL: \
55
-VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, )
300
+ case R_A2W_ ## pll_ ## _ANA0: \
56
+VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, \
301
+ case R_A2W_ ## pll_ ## _ANA1: \
57
+ float_round_to_zero, _round_to_zero) \
302
+ case R_A2W_ ## pll_ ## _ANA2: \
58
+VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, \
303
+ case R_A2W_ ## pll_ ## _ANA3: \
59
+ get_float_rounding_mode(fpst), )
304
+ case R_A2W_ ## pll_ ## _FRAC
60
305
+
61
#define VFP_CONV_FIX_A64(name, p, fsz, isz, itype) \
306
static void cprman_write(void *opaque, hwaddr offset,
62
VFP_CONV_FIX_FLOAT(name, p, fsz, isz, itype) \
307
uint64_t value, unsigned size)
63
-VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, )
308
{
64
+VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, \
309
@@ -XXX,XX +XXX,XX @@ static void cprman_write(void *opaque, hwaddr offset,
65
+ get_float_rounding_mode(fpst), )
310
trace_bcm2835_cprman_write(offset, value);
66
311
s->regs[idx] = value;
67
VFP_CONV_FIX(sh, d, 64, 64, int16)
312
68
VFP_CONV_FIX(sl, d, 64, 64, int32)
313
+ switch (idx) {
69
@@ -XXX,XX +XXX,XX @@ uint32_t HELPER(vfp_uqtoh)(uint64_t x, uint32_t shift, void *fpst)
314
+ CASE_PLL_REGS(PLLA) :
70
return uint64_to_float16_scalbn(x, -shift, fpst);
315
+ pll_update(&s->plls[CPRMAN_PLLA]);
316
+ break;
317
+
318
+ CASE_PLL_REGS(PLLC) :
319
+ pll_update(&s->plls[CPRMAN_PLLC]);
320
+ break;
321
+
322
+ CASE_PLL_REGS(PLLD) :
323
+ pll_update(&s->plls[CPRMAN_PLLD]);
324
+ break;
325
+
326
+ CASE_PLL_REGS(PLLH) :
327
+ pll_update(&s->plls[CPRMAN_PLLH]);
328
+ break;
329
+
330
+ CASE_PLL_REGS(PLLB) :
331
+ pll_update(&s->plls[CPRMAN_PLLB]);
332
+ break;
333
+ }
71
}
334
}
72
335
73
-static float64 do_prescale_fp16(float16 f, int shift, float_status *fpst)
336
+#undef CASE_PLL_REGS
74
-{
337
+
75
- if (unlikely(float16_is_any_nan(f))) {
338
static const MemoryRegionOps cprman_ops = {
76
- float_raise(float_flag_invalid, fpst);
339
.read = cprman_read,
77
- return 0;
340
.write = cprman_write,
78
- } else {
341
@@ -XXX,XX +XXX,XX @@ static const MemoryRegionOps cprman_ops = {
79
- int old_exc_flags = get_float_exception_flags(fpst);
342
static void cprman_reset(DeviceState *dev)
80
- float64 ret;
81
-
82
- ret = float16_to_float64(f, true, fpst);
83
- ret = float64_scalbn(ret, shift, fpst);
84
- old_exc_flags |= get_float_exception_flags(fpst)
85
- & float_flag_input_denormal;
86
- set_float_exception_flags(old_exc_flags, fpst);
87
-
88
- return ret;
89
- }
90
-}
91
-
92
uint32_t HELPER(vfp_toshh)(uint32_t x, uint32_t shift, void *fpst)
93
{
343
{
94
- return float64_to_int16(do_prescale_fp16(x, shift, fpst), fpst);
344
BCM2835CprmanState *s = CPRMAN(dev);
95
+ if (unlikely(float16_is_any_nan(x))) {
345
+ size_t i;
96
+ float_raise(float_flag_invalid, fpst);
346
97
+ return 0;
347
memset(s->regs, 0, sizeof(s->regs));
348
349
+ for (i = 0; i < CPRMAN_NUM_PLL; i++) {
350
+ device_cold_reset(DEVICE(&s->plls[i]));
98
+ }
351
+ }
99
+ return float16_to_int16_scalbn(x, get_float_rounding_mode(fpst),
352
+
100
+ shift, fpst);
353
clock_update_hz(s->xosc, s->xosc_freq);
101
}
354
}
102
355
103
uint32_t HELPER(vfp_touhh)(uint32_t x, uint32_t shift, void *fpst)
356
static void cprman_init(Object *obj)
104
{
357
{
105
- return float64_to_uint16(do_prescale_fp16(x, shift, fpst), fpst);
358
BCM2835CprmanState *s = CPRMAN(obj);
106
+ if (unlikely(float16_is_any_nan(x))) {
359
+ size_t i;
107
+ float_raise(float_flag_invalid, fpst);
360
+
108
+ return 0;
361
+ for (i = 0; i < CPRMAN_NUM_PLL; i++) {
362
+ object_initialize_child(obj, PLL_INIT_INFO[i].name,
363
+ &s->plls[i], TYPE_CPRMAN_PLL);
364
+ set_pll_init_info(s, &s->plls[i], i);
109
+ }
365
+ }
110
+ return float16_to_uint16_scalbn(x, get_float_rounding_mode(fpst),
366
111
+ shift, fpst);
367
s->xosc = clock_new(obj, "xosc");
368
369
@@ -XXX,XX +XXX,XX @@ static void cprman_init(Object *obj)
370
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
112
}
371
}
113
372
114
uint32_t HELPER(vfp_toslh)(uint32_t x, uint32_t shift, void *fpst)
373
+static void cprman_realize(DeviceState *dev, Error **errp)
374
+{
375
+ BCM2835CprmanState *s = CPRMAN(dev);
376
+ size_t i;
377
+
378
+ for (i = 0; i < CPRMAN_NUM_PLL; i++) {
379
+ CprmanPllState *pll = &s->plls[i];
380
+
381
+ clock_set_source(pll->xosc_in, s->xosc);
382
+
383
+ if (!qdev_realize(DEVICE(pll), NULL, errp)) {
384
+ return;
385
+ }
386
+ }
387
+}
388
+
389
static const VMStateDescription cprman_vmstate = {
390
.name = TYPE_BCM2835_CPRMAN,
391
.version_id = 1,
392
@@ -XXX,XX +XXX,XX @@ static void cprman_class_init(ObjectClass *klass, void *data)
115
{
393
{
116
- return float64_to_int32(do_prescale_fp16(x, shift, fpst), fpst);
394
DeviceClass *dc = DEVICE_CLASS(klass);
117
+ if (unlikely(float16_is_any_nan(x))) {
395
118
+ float_raise(float_flag_invalid, fpst);
396
+ dc->realize = cprman_realize;
119
+ return 0;
397
dc->reset = cprman_reset;
120
+ }
398
dc->vmsd = &cprman_vmstate;
121
+ return float16_to_int32_scalbn(x, get_float_rounding_mode(fpst),
399
device_class_set_props(dc, cprman_properties);
122
+ shift, fpst);
400
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_info = {
401
static void cprman_register_types(void)
402
{
403
type_register_static(&cprman_info);
404
+ type_register_static(&cprman_pll_info);
123
}
405
}
124
406
125
uint32_t HELPER(vfp_toulh)(uint32_t x, uint32_t shift, void *fpst)
407
type_init(cprman_register_types);
126
{
127
- return float64_to_uint32(do_prescale_fp16(x, shift, fpst), fpst);
128
+ if (unlikely(float16_is_any_nan(x))) {
129
+ float_raise(float_flag_invalid, fpst);
130
+ return 0;
131
+ }
132
+ return float16_to_uint32_scalbn(x, get_float_rounding_mode(fpst),
133
+ shift, fpst);
134
}
135
136
uint64_t HELPER(vfp_tosqh)(uint32_t x, uint32_t shift, void *fpst)
137
{
138
- return float64_to_int64(do_prescale_fp16(x, shift, fpst), fpst);
139
+ if (unlikely(float16_is_any_nan(x))) {
140
+ float_raise(float_flag_invalid, fpst);
141
+ return 0;
142
+ }
143
+ return float16_to_int64_scalbn(x, get_float_rounding_mode(fpst),
144
+ shift, fpst);
145
}
146
147
uint64_t HELPER(vfp_touqh)(uint32_t x, uint32_t shift, void *fpst)
148
{
149
- return float64_to_uint64(do_prescale_fp16(x, shift, fpst), fpst);
150
+ if (unlikely(float16_is_any_nan(x))) {
151
+ float_raise(float_flag_invalid, fpst);
152
+ return 0;
153
+ }
154
+ return float16_to_uint64_scalbn(x, get_float_rounding_mode(fpst),
155
+ shift, fpst);
156
}
157
158
/* Set the current fp rounding mode and return the old one.
159
--
408
--
160
2.18.0
409
2.20.1
161
410
162
411
diff view generated by jsdifflib
1
Validate the config settings that the guest tries to set.
1
From: Luc Michel <luc@lmichel.fr>
2
2
3
The wiki page documentation is not really accurate here:
3
The CPRMAN PLLs generate a clock based on a prescaler, a multiplier and
4
generally rather than failing requests to set bad parameters,
4
a divider. The prescaler doubles the parent (xosc) frequency, then the
5
the hardware will just clip them to something sensible.
5
multiplier/divider are applied. The multiplier has an integer and a
6
fractional part.
6
7
7
Validate the most important parameters: sizes and
8
This commit also implements the CPRMAN CM_LOCK register. This register
8
the viewport offsets. This prevents the framebuffer
9
reports which PLL is currently locked. We consider a PLL has being
9
code from trying to read out-of-range memory.
10
locked as soon as it is enabled (on real hardware, there is a delay
11
after turning a PLL on, for it to stabilize).
10
12
11
In the property handling code, we validate the new parameters every
13
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
12
time we encounter a tag that sets them. This means we validate the
14
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
13
config multiple times if the request includes multiple config-setting
15
Signed-off-by: Luc Michel <luc@lmichel.fr>
14
tags, but the code would require significant restructuring to do a
16
Tested-by: Guenter Roeck <linux@roeck-us.net>
15
validation only once but still return the clipped settings for
17
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
get-parameter tags and the buffer allocation tag.
18
---
19
include/hw/misc/bcm2835_cprman_internals.h | 8 +++
20
hw/misc/bcm2835_cprman.c | 64 +++++++++++++++++++++-
21
2 files changed, 71 insertions(+), 1 deletion(-)
17
22
18
Validation of settings made via the older bcm2835_fb_mbox_push()
23
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
19
function will be done in the next commit.
20
21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
22
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
23
Message-id: 20180814144436.679-8-peter.maydell@linaro.org
24
---
25
include/hw/display/bcm2835_fb.h | 8 +++++
26
hw/display/bcm2835_fb.c | 48 +++++++++++++++++++++++++++--
27
hw/misc/bcm2835_property.c | 54 ++++++++++++++++-----------------
28
3 files changed, 81 insertions(+), 29 deletions(-)
29
30
diff --git a/include/hw/display/bcm2835_fb.h b/include/hw/display/bcm2835_fb.h
31
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
32
--- a/include/hw/display/bcm2835_fb.h
25
--- a/include/hw/misc/bcm2835_cprman_internals.h
33
+++ b/include/hw/display/bcm2835_fb.h
26
+++ b/include/hw/misc/bcm2835_cprman_internals.h
34
@@ -XXX,XX +XXX,XX @@ static inline uint32_t bcm2835_fb_get_size(BCM2835FBConfig *config)
27
@@ -XXX,XX +XXX,XX @@ REG32(A2W_PLLD_FRAC, 0x1240)
35
return yres * bcm2835_fb_get_pitch(config);
28
REG32(A2W_PLLH_FRAC, 0x1260)
36
}
29
REG32(A2W_PLLB_FRAC, 0x12e0)
37
30
38
+/**
31
+/* misc registers */
39
+ * bcm2835_fb_validate_config: check provided config
32
+REG32(CM_LOCK, 0x114)
40
+ *
33
+ FIELD(CM_LOCK, FLOCKH, 12, 1)
41
+ * Validates the configuration information provided by the guest and
34
+ FIELD(CM_LOCK, FLOCKD, 11, 1)
42
+ * adjusts it if necessary.
35
+ FIELD(CM_LOCK, FLOCKC, 10, 1)
43
+ */
36
+ FIELD(CM_LOCK, FLOCKB, 9, 1)
44
+void bcm2835_fb_validate_config(BCM2835FBConfig *config);
37
+ FIELD(CM_LOCK, FLOCKA, 8, 1)
45
+
38
+
46
#endif
39
/*
47
diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c
40
* This field is common to all registers. Each register write value must match
41
* the CPRMAN_PASSWORD magic value in its 8 MSB.
42
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
48
index XXXXXXX..XXXXXXX 100644
43
index XXXXXXX..XXXXXXX 100644
49
--- a/hw/display/bcm2835_fb.c
44
--- a/hw/misc/bcm2835_cprman.c
50
+++ b/hw/display/bcm2835_fb.c
45
+++ b/hw/misc/bcm2835_cprman.c
51
@@ -XXX,XX +XXX,XX @@
46
@@ -XXX,XX +XXX,XX @@
52
#define DEFAULT_VCRAM_SIZE 0x4000000
47
53
#define BCM2835_FB_OFFSET 0x00100000
48
/* PLL */
54
49
55
+/* Maximum permitted framebuffer size; experimentally determined on an rpi2 */
50
+static bool pll_is_locked(const CprmanPllState *pll)
56
+#define XRES_MAX 3840
51
+{
57
+#define YRES_MAX 2560
52
+ return !FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, PWRDN)
58
+/* Framebuffer size used if guest requests zero size */
53
+ && !FIELD_EX32(*pll->reg_cm, CM_PLLx, ANARST);
59
+#define XRES_SMALL 592
54
+}
60
+#define YRES_SMALL 488
61
+
55
+
62
static void fb_invalidate_display(void *opaque)
56
static void pll_update(CprmanPllState *pll)
63
{
57
{
64
BCM2835FBState *s = BCM2835_FB(opaque);
58
- clock_update(pll->out, 0);
65
@@ -XXX,XX +XXX,XX @@ static void fb_update_display(void *opaque)
59
+ uint64_t freq, ndiv, fdiv, pdiv;
66
s->invalidate = false;
60
+
67
}
61
+ if (!pll_is_locked(pll)) {
68
62
+ clock_update(pll->out, 0);
69
+void bcm2835_fb_validate_config(BCM2835FBConfig *config)
63
+ return;
70
+{
64
+ }
71
+ /*
65
+
72
+ * Validate the config, and clip any bogus values into range,
66
+ pdiv = FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, PDIV);
73
+ * as the hardware does. Note that fb_update_display() relies on
67
+
74
+ * this happening to prevent it from performing out-of-range
68
+ if (!pdiv) {
75
+ * accesses on redraw.
69
+ clock_update(pll->out, 0);
76
+ */
70
+ return;
77
+ config->xres = MIN(config->xres, XRES_MAX);
71
+ }
78
+ config->xres_virtual = MIN(config->xres_virtual, XRES_MAX);
72
+
79
+ config->yres = MIN(config->yres, YRES_MAX);
73
+ ndiv = FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, NDIV);
80
+ config->yres_virtual = MIN(config->yres_virtual, YRES_MAX);
74
+ fdiv = FIELD_EX32(*pll->reg_a2w_frac, A2W_PLLx_FRAC, FRAC);
75
+
76
+ if (pll->reg_a2w_ana[1] & pll->prediv_mask) {
77
+ /* The prescaler doubles the parent frequency */
78
+ ndiv *= 2;
79
+ fdiv *= 2;
80
+ }
81
+
81
+
82
+ /*
82
+ /*
83
+ * These are not minima: a 40x40 framebuffer will be accepted.
83
+ * We have a multiplier with an integer part (ndiv) and a fractional part
84
+ * They're only used as defaults if the guest asks for zero size.
84
+ * (fdiv), and a divider (pdiv).
85
+ */
85
+ */
86
+ if (config->xres == 0) {
86
+ freq = clock_get_hz(pll->xosc_in) *
87
+ config->xres = XRES_SMALL;
87
+ ((ndiv << R_A2W_PLLx_FRAC_FRAC_LENGTH) + fdiv);
88
+ }
88
+ freq /= pdiv;
89
+ if (config->yres == 0) {
89
+ freq >>= R_A2W_PLLx_FRAC_FRAC_LENGTH;
90
+ config->yres = YRES_SMALL;
90
+
91
+ }
91
+ clock_update_hz(pll->out, freq);
92
+ if (config->xres_virtual == 0) {
92
}
93
+ config->xres_virtual = config->xres;
93
94
+ }
94
static void pll_xosc_update(void *opaque)
95
+ if (config->yres_virtual == 0) {
95
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_info = {
96
+ config->yres_virtual = config->yres;
96
97
/* CPRMAN "top level" model */
98
99
+static uint32_t get_cm_lock(const BCM2835CprmanState *s)
100
+{
101
+ static const int CM_LOCK_MAPPING[CPRMAN_NUM_PLL] = {
102
+ [CPRMAN_PLLA] = R_CM_LOCK_FLOCKA_SHIFT,
103
+ [CPRMAN_PLLC] = R_CM_LOCK_FLOCKC_SHIFT,
104
+ [CPRMAN_PLLD] = R_CM_LOCK_FLOCKD_SHIFT,
105
+ [CPRMAN_PLLH] = R_CM_LOCK_FLOCKH_SHIFT,
106
+ [CPRMAN_PLLB] = R_CM_LOCK_FLOCKB_SHIFT,
107
+ };
108
+
109
+ uint32_t r = 0;
110
+ size_t i;
111
+
112
+ for (i = 0; i < CPRMAN_NUM_PLL; i++) {
113
+ r |= pll_is_locked(&s->plls[i]) << CM_LOCK_MAPPING[i];
97
+ }
114
+ }
98
+
115
+
99
+ if (fb_use_offsets(config)) {
116
+ return r;
100
+ /* Clip the offsets so the viewport is within the physical screen */
101
+ config->xoffset = MIN(config->xoffset,
102
+ config->xres_virtual - config->xres);
103
+ config->yoffset = MIN(config->yoffset,
104
+ config->yres_virtual - config->yres);
105
+ }
106
+}
117
+}
107
+
118
+
108
static void bcm2835_fb_mbox_push(BCM2835FBState *s, uint32_t value)
119
static uint64_t cprman_read(void *opaque, hwaddr offset,
120
unsigned size)
109
{
121
{
110
uint32_t pitch;
122
@@ -XXX,XX +XXX,XX @@ static uint64_t cprman_read(void *opaque, hwaddr offset,
111
@@ -XXX,XX +XXX,XX @@ void bcm2835_fb_reconfigure(BCM2835FBState *s, BCM2835FBConfig *newconfig)
123
size_t idx = offset / sizeof(uint32_t);
112
{
124
113
s->lock = true;
125
switch (idx) {
114
126
+ case R_CM_LOCK:
115
- /* TODO: input validation! */
127
+ r = get_cm_lock(s);
116
-
128
+ break;
117
s->config = *newconfig;
129
+
118
130
default:
119
s->invalidate = true;
131
r = s->regs[idx];
120
diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c
132
}
121
index XXXXXXX..XXXXXXX 100644
122
--- a/hw/misc/bcm2835_property.c
123
+++ b/hw/misc/bcm2835_property.c
124
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
125
case 0x00040002: /* Blank screen */
126
resplen = 4;
127
break;
128
- case 0x00040003: /* Get physical display width/height */
129
- stl_le_phys(&s->dma_as, value + 12, fbconfig.xres);
130
- stl_le_phys(&s->dma_as, value + 16, fbconfig.yres);
131
- resplen = 8;
132
- break;
133
- case 0x00040004: /* Get virtual display width/height */
134
- stl_le_phys(&s->dma_as, value + 12, fbconfig.xres_virtual);
135
- stl_le_phys(&s->dma_as, value + 16, fbconfig.yres_virtual);
136
- resplen = 8;
137
- break;
138
case 0x00044003: /* Test physical display width/height */
139
case 0x00044004: /* Test virtual display width/height */
140
resplen = 8;
141
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
142
case 0x00048003: /* Set physical display width/height */
143
fbconfig.xres = ldl_le_phys(&s->dma_as, value + 12);
144
fbconfig.yres = ldl_le_phys(&s->dma_as, value + 16);
145
+ bcm2835_fb_validate_config(&fbconfig);
146
fbconfig_updated = true;
147
+ /* fall through */
148
+ case 0x00040003: /* Get physical display width/height */
149
+ stl_le_phys(&s->dma_as, value + 12, fbconfig.xres);
150
+ stl_le_phys(&s->dma_as, value + 16, fbconfig.yres);
151
resplen = 8;
152
break;
153
case 0x00048004: /* Set virtual display width/height */
154
fbconfig.xres_virtual = ldl_le_phys(&s->dma_as, value + 12);
155
fbconfig.yres_virtual = ldl_le_phys(&s->dma_as, value + 16);
156
+ bcm2835_fb_validate_config(&fbconfig);
157
fbconfig_updated = true;
158
+ /* fall through */
159
+ case 0x00040004: /* Get virtual display width/height */
160
+ stl_le_phys(&s->dma_as, value + 12, fbconfig.xres_virtual);
161
+ stl_le_phys(&s->dma_as, value + 16, fbconfig.yres_virtual);
162
resplen = 8;
163
break;
164
- case 0x00040005: /* Get depth */
165
- stl_le_phys(&s->dma_as, value + 12, fbconfig.bpp);
166
- resplen = 4;
167
- break;
168
case 0x00044005: /* Test depth */
169
resplen = 4;
170
break;
171
case 0x00048005: /* Set depth */
172
fbconfig.bpp = ldl_le_phys(&s->dma_as, value + 12);
173
+ bcm2835_fb_validate_config(&fbconfig);
174
fbconfig_updated = true;
175
- resplen = 4;
176
- break;
177
- case 0x00040006: /* Get pixel order */
178
- stl_le_phys(&s->dma_as, value + 12, fbconfig.pixo);
179
+ /* fall through */
180
+ case 0x00040005: /* Get depth */
181
+ stl_le_phys(&s->dma_as, value + 12, fbconfig.bpp);
182
resplen = 4;
183
break;
184
case 0x00044006: /* Test pixel order */
185
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
186
break;
187
case 0x00048006: /* Set pixel order */
188
fbconfig.pixo = ldl_le_phys(&s->dma_as, value + 12);
189
+ bcm2835_fb_validate_config(&fbconfig);
190
fbconfig_updated = true;
191
- resplen = 4;
192
- break;
193
- case 0x00040007: /* Get alpha */
194
- stl_le_phys(&s->dma_as, value + 12, fbconfig.alpha);
195
+ /* fall through */
196
+ case 0x00040006: /* Get pixel order */
197
+ stl_le_phys(&s->dma_as, value + 12, fbconfig.pixo);
198
resplen = 4;
199
break;
200
case 0x00044007: /* Test pixel alpha */
201
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
202
break;
203
case 0x00048007: /* Set alpha */
204
fbconfig.alpha = ldl_le_phys(&s->dma_as, value + 12);
205
+ bcm2835_fb_validate_config(&fbconfig);
206
fbconfig_updated = true;
207
+ /* fall through */
208
+ case 0x00040007: /* Get alpha */
209
+ stl_le_phys(&s->dma_as, value + 12, fbconfig.alpha);
210
resplen = 4;
211
break;
212
case 0x00040008: /* Get pitch */
213
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
214
bcm2835_fb_get_pitch(&fbconfig));
215
resplen = 4;
216
break;
217
- case 0x00040009: /* Get virtual offset */
218
- stl_le_phys(&s->dma_as, value + 12, fbconfig.xoffset);
219
- stl_le_phys(&s->dma_as, value + 16, fbconfig.yoffset);
220
- resplen = 8;
221
- break;
222
case 0x00044009: /* Test virtual offset */
223
resplen = 8;
224
break;
225
case 0x00048009: /* Set virtual offset */
226
fbconfig.xoffset = ldl_le_phys(&s->dma_as, value + 12);
227
fbconfig.yoffset = ldl_le_phys(&s->dma_as, value + 16);
228
+ bcm2835_fb_validate_config(&fbconfig);
229
fbconfig_updated = true;
230
+ /* fall through */
231
+ case 0x00040009: /* Get virtual offset */
232
+ stl_le_phys(&s->dma_as, value + 12, fbconfig.xoffset);
233
+ stl_le_phys(&s->dma_as, value + 16, fbconfig.yoffset);
234
resplen = 8;
235
break;
236
case 0x0004000a: /* Get/Test/Set overscan */
237
--
133
--
238
2.18.0
134
2.20.1
239
135
240
136
diff view generated by jsdifflib
1
Connect the VIRQ and VFIQ lines from the GIC to the CPU;
1
From: Luc Michel <luc@lmichel.fr>
2
these exist always for both CPU and GIC whether the
2
3
virtualization extensions are enabled or not, so we
3
PLLs are composed of multiple channels. Each channel outputs one clock
4
can just unconditionally connect them.
4
signal. They are modeled as one device taking the PLL generated clock as
5
5
input, and outputting a new clock.
6
7
A channel shares the CM register with its parent PLL, and has its own
8
A2W_CTRL register. A write to the CM register will trigger an update of
9
the PLL and all its channels, while a write to an A2W_CTRL channel
10
register will update the required channel only.
11
12
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
13
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
14
Signed-off-by: Luc Michel <luc@lmichel.fr>
15
Tested-by: Guenter Roeck <linux@roeck-us.net>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
8
Message-id: 20180821132811.17675-4-peter.maydell@linaro.org
9
---
17
---
10
hw/arm/vexpress.c | 4 ++++
18
include/hw/misc/bcm2835_cprman.h | 44 ++++++
11
1 file changed, 4 insertions(+)
19
include/hw/misc/bcm2835_cprman_internals.h | 146 +++++++++++++++++++
12
20
hw/misc/bcm2835_cprman.c | 155 +++++++++++++++++++--
13
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
21
3 files changed, 337 insertions(+), 8 deletions(-)
22
23
diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h
14
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/arm/vexpress.c
25
--- a/include/hw/misc/bcm2835_cprman.h
16
+++ b/hw/arm/vexpress.c
26
+++ b/include/hw/misc/bcm2835_cprman.h
17
@@ -XXX,XX +XXX,XX @@ static void init_cpus(const char *cpu_type, const char *privdev,
27
@@ -XXX,XX +XXX,XX @@ typedef enum CprmanPll {
18
sysbus_connect_irq(busdev, n, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
28
CPRMAN_NUM_PLL
19
sysbus_connect_irq(busdev, n + smp_cpus,
29
} CprmanPll;
20
qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
30
21
+ sysbus_connect_irq(busdev, n + 2 * smp_cpus,
31
+typedef enum CprmanPllChannel {
22
+ qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
32
+ CPRMAN_PLLA_CHANNEL_DSI0 = 0,
23
+ sysbus_connect_irq(busdev, n + 3 * smp_cpus,
33
+ CPRMAN_PLLA_CHANNEL_CORE,
24
+ qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
34
+ CPRMAN_PLLA_CHANNEL_PER,
35
+ CPRMAN_PLLA_CHANNEL_CCP2,
36
+
37
+ CPRMAN_PLLC_CHANNEL_CORE2,
38
+ CPRMAN_PLLC_CHANNEL_CORE1,
39
+ CPRMAN_PLLC_CHANNEL_PER,
40
+ CPRMAN_PLLC_CHANNEL_CORE0,
41
+
42
+ CPRMAN_PLLD_CHANNEL_DSI0,
43
+ CPRMAN_PLLD_CHANNEL_CORE,
44
+ CPRMAN_PLLD_CHANNEL_PER,
45
+ CPRMAN_PLLD_CHANNEL_DSI1,
46
+
47
+ CPRMAN_PLLH_CHANNEL_AUX,
48
+ CPRMAN_PLLH_CHANNEL_RCAL,
49
+ CPRMAN_PLLH_CHANNEL_PIX,
50
+
51
+ CPRMAN_PLLB_CHANNEL_ARM,
52
+
53
+ CPRMAN_NUM_PLL_CHANNEL,
54
+} CprmanPllChannel;
55
+
56
typedef struct CprmanPllState {
57
/*< private >*/
58
DeviceState parent_obj;
59
@@ -XXX,XX +XXX,XX @@ typedef struct CprmanPllState {
60
Clock *out;
61
} CprmanPllState;
62
63
+typedef struct CprmanPllChannelState {
64
+ /*< private >*/
65
+ DeviceState parent_obj;
66
+
67
+ /*< public >*/
68
+ CprmanPllChannel id;
69
+ CprmanPll parent;
70
+
71
+ uint32_t *reg_cm;
72
+ uint32_t hold_mask;
73
+ uint32_t load_mask;
74
+ uint32_t *reg_a2w_ctrl;
75
+ int fixed_divider;
76
+
77
+ Clock *pll_in;
78
+ Clock *out;
79
+} CprmanPllChannelState;
80
+
81
struct BCM2835CprmanState {
82
/*< private >*/
83
SysBusDevice parent_obj;
84
@@ -XXX,XX +XXX,XX @@ struct BCM2835CprmanState {
85
MemoryRegion iomem;
86
87
CprmanPllState plls[CPRMAN_NUM_PLL];
88
+ CprmanPllChannelState channels[CPRMAN_NUM_PLL_CHANNEL];
89
90
uint32_t regs[CPRMAN_NUM_REGS];
91
uint32_t xosc_freq;
92
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
93
index XXXXXXX..XXXXXXX 100644
94
--- a/include/hw/misc/bcm2835_cprman_internals.h
95
+++ b/include/hw/misc/bcm2835_cprman_internals.h
96
@@ -XXX,XX +XXX,XX @@
97
#include "hw/misc/bcm2835_cprman.h"
98
99
#define TYPE_CPRMAN_PLL "bcm2835-cprman-pll"
100
+#define TYPE_CPRMAN_PLL_CHANNEL "bcm2835-cprman-pll-channel"
101
102
DECLARE_INSTANCE_CHECKER(CprmanPllState, CPRMAN_PLL,
103
TYPE_CPRMAN_PLL)
104
+DECLARE_INSTANCE_CHECKER(CprmanPllChannelState, CPRMAN_PLL_CHANNEL,
105
+ TYPE_CPRMAN_PLL_CHANNEL)
106
107
/* Register map */
108
109
@@ -XXX,XX +XXX,XX @@ REG32(A2W_PLLD_FRAC, 0x1240)
110
REG32(A2W_PLLH_FRAC, 0x1260)
111
REG32(A2W_PLLB_FRAC, 0x12e0)
112
113
+/* PLL channels */
114
+REG32(A2W_PLLA_DSI0, 0x1300)
115
+ FIELD(A2W_PLLx_CHANNELy, DIV, 0, 8)
116
+ FIELD(A2W_PLLx_CHANNELy, DISABLE, 8, 1)
117
+REG32(A2W_PLLA_CORE, 0x1400)
118
+REG32(A2W_PLLA_PER, 0x1500)
119
+REG32(A2W_PLLA_CCP2, 0x1600)
120
+
121
+REG32(A2W_PLLC_CORE2, 0x1320)
122
+REG32(A2W_PLLC_CORE1, 0x1420)
123
+REG32(A2W_PLLC_PER, 0x1520)
124
+REG32(A2W_PLLC_CORE0, 0x1620)
125
+
126
+REG32(A2W_PLLD_DSI0, 0x1340)
127
+REG32(A2W_PLLD_CORE, 0x1440)
128
+REG32(A2W_PLLD_PER, 0x1540)
129
+REG32(A2W_PLLD_DSI1, 0x1640)
130
+
131
+REG32(A2W_PLLH_AUX, 0x1360)
132
+REG32(A2W_PLLH_RCAL, 0x1460)
133
+REG32(A2W_PLLH_PIX, 0x1560)
134
+REG32(A2W_PLLH_STS, 0x1660)
135
+
136
+REG32(A2W_PLLB_ARM, 0x13e0)
137
+
138
/* misc registers */
139
REG32(CM_LOCK, 0x114)
140
FIELD(CM_LOCK, FLOCKH, 12, 1)
141
@@ -XXX,XX +XXX,XX @@ static inline void set_pll_init_info(BCM2835CprmanState *s,
142
pll->reg_a2w_frac = &s->regs[PLL_INIT_INFO[id].a2w_frac_offset];
143
}
144
145
+
146
+/* PLL channel init info */
147
+typedef struct PLLChannelInitInfo {
148
+ const char *name;
149
+ CprmanPll parent;
150
+ size_t cm_offset;
151
+ uint32_t cm_hold_mask;
152
+ uint32_t cm_load_mask;
153
+ size_t a2w_ctrl_offset;
154
+ unsigned int fixed_divider;
155
+} PLLChannelInitInfo;
156
+
157
+#define FILL_PLL_CHANNEL_INIT_INFO_common(pll_, channel_) \
158
+ .parent = CPRMAN_ ## pll_, \
159
+ .cm_offset = R_CM_ ## pll_, \
160
+ .cm_load_mask = R_CM_ ## pll_ ## _ ## LOAD ## channel_ ## _MASK, \
161
+ .a2w_ctrl_offset = R_A2W_ ## pll_ ## _ ## channel_
162
+
163
+#define FILL_PLL_CHANNEL_INIT_INFO(pll_, channel_) \
164
+ FILL_PLL_CHANNEL_INIT_INFO_common(pll_, channel_), \
165
+ .cm_hold_mask = R_CM_ ## pll_ ## _ ## HOLD ## channel_ ## _MASK, \
166
+ .fixed_divider = 1
167
+
168
+#define FILL_PLL_CHANNEL_INIT_INFO_nohold(pll_, channel_) \
169
+ FILL_PLL_CHANNEL_INIT_INFO_common(pll_, channel_), \
170
+ .cm_hold_mask = 0
171
+
172
+static PLLChannelInitInfo PLL_CHANNEL_INIT_INFO[] = {
173
+ [CPRMAN_PLLA_CHANNEL_DSI0] = {
174
+ .name = "plla-dsi0",
175
+ FILL_PLL_CHANNEL_INIT_INFO(PLLA, DSI0),
176
+ },
177
+ [CPRMAN_PLLA_CHANNEL_CORE] = {
178
+ .name = "plla-core",
179
+ FILL_PLL_CHANNEL_INIT_INFO(PLLA, CORE),
180
+ },
181
+ [CPRMAN_PLLA_CHANNEL_PER] = {
182
+ .name = "plla-per",
183
+ FILL_PLL_CHANNEL_INIT_INFO(PLLA, PER),
184
+ },
185
+ [CPRMAN_PLLA_CHANNEL_CCP2] = {
186
+ .name = "plla-ccp2",
187
+ FILL_PLL_CHANNEL_INIT_INFO(PLLA, CCP2),
188
+ },
189
+
190
+ [CPRMAN_PLLC_CHANNEL_CORE2] = {
191
+ .name = "pllc-core2",
192
+ FILL_PLL_CHANNEL_INIT_INFO(PLLC, CORE2),
193
+ },
194
+ [CPRMAN_PLLC_CHANNEL_CORE1] = {
195
+ .name = "pllc-core1",
196
+ FILL_PLL_CHANNEL_INIT_INFO(PLLC, CORE1),
197
+ },
198
+ [CPRMAN_PLLC_CHANNEL_PER] = {
199
+ .name = "pllc-per",
200
+ FILL_PLL_CHANNEL_INIT_INFO(PLLC, PER),
201
+ },
202
+ [CPRMAN_PLLC_CHANNEL_CORE0] = {
203
+ .name = "pllc-core0",
204
+ FILL_PLL_CHANNEL_INIT_INFO(PLLC, CORE0),
205
+ },
206
+
207
+ [CPRMAN_PLLD_CHANNEL_DSI0] = {
208
+ .name = "plld-dsi0",
209
+ FILL_PLL_CHANNEL_INIT_INFO(PLLD, DSI0),
210
+ },
211
+ [CPRMAN_PLLD_CHANNEL_CORE] = {
212
+ .name = "plld-core",
213
+ FILL_PLL_CHANNEL_INIT_INFO(PLLD, CORE),
214
+ },
215
+ [CPRMAN_PLLD_CHANNEL_PER] = {
216
+ .name = "plld-per",
217
+ FILL_PLL_CHANNEL_INIT_INFO(PLLD, PER),
218
+ },
219
+ [CPRMAN_PLLD_CHANNEL_DSI1] = {
220
+ .name = "plld-dsi1",
221
+ FILL_PLL_CHANNEL_INIT_INFO(PLLD, DSI1),
222
+ },
223
+
224
+ [CPRMAN_PLLH_CHANNEL_AUX] = {
225
+ .name = "pllh-aux",
226
+ .fixed_divider = 1,
227
+ FILL_PLL_CHANNEL_INIT_INFO_nohold(PLLH, AUX),
228
+ },
229
+ [CPRMAN_PLLH_CHANNEL_RCAL] = {
230
+ .name = "pllh-rcal",
231
+ .fixed_divider = 10,
232
+ FILL_PLL_CHANNEL_INIT_INFO_nohold(PLLH, RCAL),
233
+ },
234
+ [CPRMAN_PLLH_CHANNEL_PIX] = {
235
+ .name = "pllh-pix",
236
+ .fixed_divider = 10,
237
+ FILL_PLL_CHANNEL_INIT_INFO_nohold(PLLH, PIX),
238
+ },
239
+
240
+ [CPRMAN_PLLB_CHANNEL_ARM] = {
241
+ .name = "pllb-arm",
242
+ FILL_PLL_CHANNEL_INIT_INFO(PLLB, ARM),
243
+ },
244
+};
245
+
246
+#undef FILL_PLL_CHANNEL_INIT_INFO_nohold
247
+#undef FILL_PLL_CHANNEL_INIT_INFO
248
+#undef FILL_PLL_CHANNEL_INIT_INFO_common
249
+
250
+static inline void set_pll_channel_init_info(BCM2835CprmanState *s,
251
+ CprmanPllChannelState *channel,
252
+ CprmanPllChannel id)
253
+{
254
+ channel->id = id;
255
+ channel->parent = PLL_CHANNEL_INIT_INFO[id].parent;
256
+ channel->reg_cm = &s->regs[PLL_CHANNEL_INIT_INFO[id].cm_offset];
257
+ channel->hold_mask = PLL_CHANNEL_INIT_INFO[id].cm_hold_mask;
258
+ channel->load_mask = PLL_CHANNEL_INIT_INFO[id].cm_load_mask;
259
+ channel->reg_a2w_ctrl = &s->regs[PLL_CHANNEL_INIT_INFO[id].a2w_ctrl_offset];
260
+ channel->fixed_divider = PLL_CHANNEL_INIT_INFO[id].fixed_divider;
261
+}
262
+
263
#endif
264
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
265
index XXXXXXX..XXXXXXX 100644
266
--- a/hw/misc/bcm2835_cprman.c
267
+++ b/hw/misc/bcm2835_cprman.c
268
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_info = {
269
};
270
271
272
+/* PLL channel */
273
+
274
+static void pll_channel_update(CprmanPllChannelState *channel)
275
+{
276
+ clock_update(channel->out, 0);
277
+}
278
+
279
+/* Update a PLL and all its channels */
280
+static void pll_update_all_channels(BCM2835CprmanState *s,
281
+ CprmanPllState *pll)
282
+{
283
+ size_t i;
284
+
285
+ pll_update(pll);
286
+
287
+ for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
288
+ CprmanPllChannelState *channel = &s->channels[i];
289
+ if (channel->parent == pll->id) {
290
+ pll_channel_update(channel);
291
+ }
292
+ }
293
+}
294
+
295
+static void pll_channel_pll_in_update(void *opaque)
296
+{
297
+ pll_channel_update(CPRMAN_PLL_CHANNEL(opaque));
298
+}
299
+
300
+static void pll_channel_init(Object *obj)
301
+{
302
+ CprmanPllChannelState *s = CPRMAN_PLL_CHANNEL(obj);
303
+
304
+ s->pll_in = qdev_init_clock_in(DEVICE(s), "pll-in",
305
+ pll_channel_pll_in_update, s);
306
+ s->out = qdev_init_clock_out(DEVICE(s), "out");
307
+}
308
+
309
+static const VMStateDescription pll_channel_vmstate = {
310
+ .name = TYPE_CPRMAN_PLL_CHANNEL,
311
+ .version_id = 1,
312
+ .minimum_version_id = 1,
313
+ .fields = (VMStateField[]) {
314
+ VMSTATE_CLOCK(pll_in, CprmanPllChannelState),
315
+ VMSTATE_END_OF_LIST()
316
+ }
317
+};
318
+
319
+static void pll_channel_class_init(ObjectClass *klass, void *data)
320
+{
321
+ DeviceClass *dc = DEVICE_CLASS(klass);
322
+
323
+ dc->vmsd = &pll_channel_vmstate;
324
+}
325
+
326
+static const TypeInfo cprman_pll_channel_info = {
327
+ .name = TYPE_CPRMAN_PLL_CHANNEL,
328
+ .parent = TYPE_DEVICE,
329
+ .instance_size = sizeof(CprmanPllChannelState),
330
+ .class_init = pll_channel_class_init,
331
+ .instance_init = pll_channel_init,
332
+};
333
+
334
+
335
/* CPRMAN "top level" model */
336
337
static uint32_t get_cm_lock(const BCM2835CprmanState *s)
338
@@ -XXX,XX +XXX,XX @@ static uint64_t cprman_read(void *opaque, hwaddr offset,
339
return r;
340
}
341
342
-#define CASE_PLL_REGS(pll_) \
343
- case R_CM_ ## pll_: \
344
+static inline void update_pll_and_channels_from_cm(BCM2835CprmanState *s,
345
+ size_t idx)
346
+{
347
+ size_t i;
348
+
349
+ for (i = 0; i < CPRMAN_NUM_PLL; i++) {
350
+ if (PLL_INIT_INFO[i].cm_offset == idx) {
351
+ pll_update_all_channels(s, &s->plls[i]);
352
+ return;
353
+ }
354
+ }
355
+}
356
+
357
+static inline void update_channel_from_a2w(BCM2835CprmanState *s, size_t idx)
358
+{
359
+ size_t i;
360
+
361
+ for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
362
+ if (PLL_CHANNEL_INIT_INFO[i].a2w_ctrl_offset == idx) {
363
+ pll_channel_update(&s->channels[i]);
364
+ return;
365
+ }
366
+ }
367
+}
368
+
369
+#define CASE_PLL_A2W_REGS(pll_) \
370
case R_A2W_ ## pll_ ## _CTRL: \
371
case R_A2W_ ## pll_ ## _ANA0: \
372
case R_A2W_ ## pll_ ## _ANA1: \
373
@@ -XXX,XX +XXX,XX @@ static void cprman_write(void *opaque, hwaddr offset,
374
s->regs[idx] = value;
375
376
switch (idx) {
377
- CASE_PLL_REGS(PLLA) :
378
+ case R_CM_PLLA ... R_CM_PLLH:
379
+ case R_CM_PLLB:
380
+ /*
381
+ * A given CM_PLLx register is shared by both the PLL and the channels
382
+ * of this PLL.
383
+ */
384
+ update_pll_and_channels_from_cm(s, idx);
385
+ break;
386
+
387
+ CASE_PLL_A2W_REGS(PLLA) :
388
pll_update(&s->plls[CPRMAN_PLLA]);
389
break;
390
391
- CASE_PLL_REGS(PLLC) :
392
+ CASE_PLL_A2W_REGS(PLLC) :
393
pll_update(&s->plls[CPRMAN_PLLC]);
394
break;
395
396
- CASE_PLL_REGS(PLLD) :
397
+ CASE_PLL_A2W_REGS(PLLD) :
398
pll_update(&s->plls[CPRMAN_PLLD]);
399
break;
400
401
- CASE_PLL_REGS(PLLH) :
402
+ CASE_PLL_A2W_REGS(PLLH) :
403
pll_update(&s->plls[CPRMAN_PLLH]);
404
break;
405
406
- CASE_PLL_REGS(PLLB) :
407
+ CASE_PLL_A2W_REGS(PLLB) :
408
pll_update(&s->plls[CPRMAN_PLLB]);
409
break;
410
+
411
+ case R_A2W_PLLA_DSI0:
412
+ case R_A2W_PLLA_CORE:
413
+ case R_A2W_PLLA_PER:
414
+ case R_A2W_PLLA_CCP2:
415
+ case R_A2W_PLLC_CORE2:
416
+ case R_A2W_PLLC_CORE1:
417
+ case R_A2W_PLLC_PER:
418
+ case R_A2W_PLLC_CORE0:
419
+ case R_A2W_PLLD_DSI0:
420
+ case R_A2W_PLLD_CORE:
421
+ case R_A2W_PLLD_PER:
422
+ case R_A2W_PLLD_DSI1:
423
+ case R_A2W_PLLH_AUX:
424
+ case R_A2W_PLLH_RCAL:
425
+ case R_A2W_PLLH_PIX:
426
+ case R_A2W_PLLB_ARM:
427
+ update_channel_from_a2w(s, idx);
428
+ break;
25
}
429
}
26
}
430
}
27
431
432
-#undef CASE_PLL_REGS
433
+#undef CASE_PLL_A2W_REGS
434
435
static const MemoryRegionOps cprman_ops = {
436
.read = cprman_read,
437
@@ -XXX,XX +XXX,XX @@ static void cprman_reset(DeviceState *dev)
438
device_cold_reset(DEVICE(&s->plls[i]));
439
}
440
441
+ for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
442
+ device_cold_reset(DEVICE(&s->channels[i]));
443
+ }
444
+
445
clock_update_hz(s->xosc, s->xosc_freq);
446
}
447
448
@@ -XXX,XX +XXX,XX @@ static void cprman_init(Object *obj)
449
set_pll_init_info(s, &s->plls[i], i);
450
}
451
452
+ for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
453
+ object_initialize_child(obj, PLL_CHANNEL_INIT_INFO[i].name,
454
+ &s->channels[i],
455
+ TYPE_CPRMAN_PLL_CHANNEL);
456
+ set_pll_channel_init_info(s, &s->channels[i], i);
457
+ }
458
+
459
s->xosc = clock_new(obj, "xosc");
460
461
memory_region_init_io(&s->iomem, obj, &cprman_ops,
462
@@ -XXX,XX +XXX,XX @@ static void cprman_realize(DeviceState *dev, Error **errp)
463
return;
464
}
465
}
466
+
467
+ for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
468
+ CprmanPllChannelState *channel = &s->channels[i];
469
+ CprmanPll parent = PLL_CHANNEL_INIT_INFO[i].parent;
470
+ Clock *parent_clk = s->plls[parent].out;
471
+
472
+ clock_set_source(channel->pll_in, parent_clk);
473
+
474
+ if (!qdev_realize(DEVICE(channel), NULL, errp)) {
475
+ return;
476
+ }
477
+ }
478
}
479
480
static const VMStateDescription cprman_vmstate = {
481
@@ -XXX,XX +XXX,XX @@ static void cprman_register_types(void)
482
{
483
type_register_static(&cprman_info);
484
type_register_static(&cprman_pll_info);
485
+ type_register_static(&cprman_pll_channel_info);
486
}
487
488
type_init(cprman_register_types);
28
--
489
--
29
2.18.0
490
2.20.1
30
491
31
492
diff view generated by jsdifflib
Deleted patch
1
Connect the VIRQ and VFIQ lines from the GIC to the CPU;
2
these exist always for both CPU and GIC whether the
3
virtualization extensions are enabled or not, so we
4
can just unconditionally connect them.
5
1
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
8
Message-id: 20180821132811.17675-6-peter.maydell@linaro.org
9
---
10
hw/arm/fsl-imx6ul.c | 4 ++++
11
1 file changed, 4 insertions(+)
12
13
diff --git a/hw/arm/fsl-imx6ul.c b/hw/arm/fsl-imx6ul.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/arm/fsl-imx6ul.c
16
+++ b/hw/arm/fsl-imx6ul.c
17
@@ -XXX,XX +XXX,XX @@ static void fsl_imx6ul_realize(DeviceState *dev, Error **errp)
18
irq = qdev_get_gpio_in(d, ARM_CPU_IRQ);
19
sysbus_connect_irq(sbd, i, irq);
20
sysbus_connect_irq(sbd, i + smp_cpus, qdev_get_gpio_in(d, ARM_CPU_FIQ));
21
+ sysbus_connect_irq(sbd, i + 2 * smp_cpus,
22
+ qdev_get_gpio_in(d, ARM_CPU_VIRQ));
23
+ sysbus_connect_irq(sbd, i + 3 * smp_cpus,
24
+ qdev_get_gpio_in(d, ARM_CPU_VFIQ));
25
}
26
27
/*
28
--
29
2.18.0
30
31
diff view generated by jsdifflib
1
Implement the necessary support code for taking exceptions
1
From: Luc Michel <luc@lmichel.fr>
2
to Hyp mode in AArch32.
3
2
3
A PLL channel is able to further divide the generated PLL frequency.
4
The divider is given in the CTRL_A2W register. Some channels have an
5
additional fixed divider which is always applied to the signal.
6
7
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Signed-off-by: Luc Michel <luc@lmichel.fr>
10
Tested-by: Guenter Roeck <linux@roeck-us.net>
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
7
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
8
Message-id: 20180820153020.21478-5-peter.maydell@linaro.org
9
---
12
---
10
target/arm/helper.c | 82 +++++++++++++++++++++++++++++++++++++++++++++
13
hw/misc/bcm2835_cprman.c | 33 ++++++++++++++++++++++++++++++++-
11
1 file changed, 82 insertions(+)
14
1 file changed, 32 insertions(+), 1 deletion(-)
12
15
13
diff --git a/target/arm/helper.c b/target/arm/helper.c
16
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
14
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
15
--- a/target/arm/helper.c
18
--- a/hw/misc/bcm2835_cprman.c
16
+++ b/target/arm/helper.c
19
+++ b/hw/misc/bcm2835_cprman.c
17
@@ -XXX,XX +XXX,XX @@ static void take_aarch32_exception(CPUARMState *env, int new_mode,
20
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_info = {
18
env->regs[15] = newpc;
21
19
}
22
/* PLL channel */
20
23
21
+static void arm_cpu_do_interrupt_aarch32_hyp(CPUState *cs)
24
+static bool pll_channel_is_enabled(CprmanPllChannelState *channel)
22
+{
25
+{
23
+ /*
26
+ /*
24
+ * Handle exception entry to Hyp mode; this is sufficiently
27
+ * XXX I'm not sure of the purpose of the LOAD field. The Linux driver does
25
+ * different to entry to other AArch32 modes that we handle it
28
+ * not set it when enabling the channel, but does clear it when disabling
26
+ * separately here.
29
+ * it.
27
+ *
28
+ * The vector table entry used is always the 0x14 Hyp mode entry point,
29
+ * unless this is an UNDEF/HVC/abort taken from Hyp to Hyp.
30
+ * The offset applied to the preferred return address is always zero
31
+ * (see DDI0487C.a section G1.12.3).
32
+ * PSTATE A/I/F masks are set based only on the SCR.EA/IRQ/FIQ values.
33
+ */
30
+ */
34
+ uint32_t addr, mask;
31
+ return !FIELD_EX32(*channel->reg_a2w_ctrl, A2W_PLLx_CHANNELy, DISABLE)
35
+ ARMCPU *cpu = ARM_CPU(cs);
32
+ && !(*channel->reg_cm & channel->hold_mask);
36
+ CPUARMState *env = &cpu->env;
37
+
38
+ switch (cs->exception_index) {
39
+ case EXCP_UDEF:
40
+ addr = 0x04;
41
+ break;
42
+ case EXCP_SWI:
43
+ addr = 0x14;
44
+ break;
45
+ case EXCP_BKPT:
46
+ /* Fall through to prefetch abort. */
47
+ case EXCP_PREFETCH_ABORT:
48
+ env->cp15.ifar_s = env->exception.vaddress;
49
+ qemu_log_mask(CPU_LOG_INT, "...with HIFAR 0x%x\n",
50
+ (uint32_t)env->exception.vaddress);
51
+ addr = 0x0c;
52
+ break;
53
+ case EXCP_DATA_ABORT:
54
+ env->cp15.dfar_s = env->exception.vaddress;
55
+ qemu_log_mask(CPU_LOG_INT, "...with HDFAR 0x%x\n",
56
+ (uint32_t)env->exception.vaddress);
57
+ addr = 0x10;
58
+ break;
59
+ case EXCP_IRQ:
60
+ addr = 0x18;
61
+ break;
62
+ case EXCP_FIQ:
63
+ addr = 0x1c;
64
+ break;
65
+ case EXCP_HVC:
66
+ addr = 0x08;
67
+ break;
68
+ case EXCP_HYP_TRAP:
69
+ addr = 0x14;
70
+ default:
71
+ cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
72
+ }
73
+
74
+ if (cs->exception_index != EXCP_IRQ && cs->exception_index != EXCP_FIQ) {
75
+ env->cp15.esr_el[2] = env->exception.syndrome;
76
+ }
77
+
78
+ if (arm_current_el(env) != 2 && addr < 0x14) {
79
+ addr = 0x14;
80
+ }
81
+
82
+ mask = 0;
83
+ if (!(env->cp15.scr_el3 & SCR_EA)) {
84
+ mask |= CPSR_A;
85
+ }
86
+ if (!(env->cp15.scr_el3 & SCR_IRQ)) {
87
+ mask |= CPSR_I;
88
+ }
89
+ if (!(env->cp15.scr_el3 & SCR_FIQ)) {
90
+ mask |= CPSR_F;
91
+ }
92
+
93
+ addr += env->cp15.hvbar;
94
+
95
+ take_aarch32_exception(env, ARM_CPU_MODE_HYP, mask, 0, addr);
96
+}
33
+}
97
+
34
+
98
static void arm_cpu_do_interrupt_aarch32(CPUState *cs)
35
static void pll_channel_update(CprmanPllChannelState *channel)
99
{
36
{
100
ARMCPU *cpu = ARM_CPU(cs);
37
- clock_update(channel->out, 0);
101
@@ -XXX,XX +XXX,XX @@ static void arm_cpu_do_interrupt_aarch32(CPUState *cs)
38
+ uint64_t freq, div;
102
env->cp15.mdscr_el1 = deposit64(env->cp15.mdscr_el1, 2, 4, moe);
39
+
103
}
40
+ if (!pll_channel_is_enabled(channel)) {
104
41
+ clock_update(channel->out, 0);
105
+ if (env->exception.target_el == 2) {
106
+ arm_cpu_do_interrupt_aarch32_hyp(cs);
107
+ return;
42
+ return;
108
+ }
43
+ }
109
+
44
+
110
/* TODO: Vectored interrupt controller. */
45
+ div = FIELD_EX32(*channel->reg_a2w_ctrl, A2W_PLLx_CHANNELy, DIV);
111
switch (cs->exception_index) {
46
+
112
case EXCP_UDEF:
47
+ if (!div) {
48
+ /*
49
+ * It seems that when the divider value is 0, it is considered as
50
+ * being maximum by the hardware (see the Linux driver).
51
+ */
52
+ div = R_A2W_PLLx_CHANNELy_DIV_MASK;
53
+ }
54
+
55
+ /* Some channels have an additional fixed divider */
56
+ freq = clock_get_hz(channel->pll_in) / (div * channel->fixed_divider);
57
+
58
+ clock_update_hz(channel->out, freq);
59
}
60
61
/* Update a PLL and all its channels */
113
--
62
--
114
2.18.0
63
2.20.1
115
64
116
65
diff view generated by jsdifflib
1
The IoTKit does not have any Master Security Contollers itself,
1
From: Luc Michel <luc@lmichel.fr>
2
but it does provide registers in the secure privilege control
2
3
block which allow control of MSCs in the external system.
3
The clock multiplexers are the last clock stage in the CPRMAN. Each mux
4
Add support for these registers.
4
outputs one clock signal that goes out of the CPRMAN to the SoC
5
5
peripherals.
6
7
Each mux has at most 10 sources. The sources 0 to 3 are common to all
8
muxes. They are:
9
0. ground (no clock signal)
10
1. the main oscillator (xosc)
11
2. "test debug 0" clock
12
3. "test debug 1" clock
13
14
Test debug 0 and 1 are actual clock muxes that can be used as sources to
15
other muxes (for debug purpose).
16
17
Sources 4 to 9 are mux specific and can be unpopulated (grounded). Those
18
sources are fed by the PLL channels outputs.
19
20
One corner case exists for DSI0E and DSI0P muxes. They have their source
21
number 4 connected to an intermediate multiplexer that can select
22
between PLLA-DSI0 and PLLD-DSI0 channel. This multiplexer is called
23
DSI0HSCK and is not a clock mux as such. It is really a simple mux from
24
the hardware point of view (see https://elinux.org/The_Undocumented_Pi).
25
This mux is not implemented in this commit.
26
27
Note that there is some muxes for which sources are unknown (because of
28
a lack of documentation). For those cases all the sources are connected
29
to ground in this implementation.
30
31
Each clock mux output is exported by the CPRMAN at the qdev level,
32
adding the suffix '-out' to the mux name to form the output clock name.
33
(E.g. the 'uart' mux sees its output exported as 'uart-out' at the
34
CPRMAN level.)
35
36
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
37
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
38
Signed-off-by: Luc Michel <luc@lmichel.fr>
39
Tested-by: Guenter Roeck <linux@roeck-us.net>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
40
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Message-id: 20180820141116.9118-13-peter.maydell@linaro.org
9
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
10
---
41
---
11
include/hw/misc/iotkit-secctl.h | 14 +++++++
42
include/hw/misc/bcm2835_cprman.h | 85 +++++
12
hw/misc/iotkit-secctl.c | 73 +++++++++++++++++++++++++++++----
43
include/hw/misc/bcm2835_cprman_internals.h | 422 +++++++++++++++++++++
13
2 files changed, 79 insertions(+), 8 deletions(-)
44
hw/misc/bcm2835_cprman.c | 151 ++++++++
14
45
3 files changed, 658 insertions(+)
15
diff --git a/include/hw/misc/iotkit-secctl.h b/include/hw/misc/iotkit-secctl.h
46
47
diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h
16
index XXXXXXX..XXXXXXX 100644
48
index XXXXXXX..XXXXXXX 100644
17
--- a/include/hw/misc/iotkit-secctl.h
49
--- a/include/hw/misc/bcm2835_cprman.h
18
+++ b/include/hw/misc/iotkit-secctl.h
50
+++ b/include/hw/misc/bcm2835_cprman.h
51
@@ -XXX,XX +XXX,XX @@ typedef enum CprmanPllChannel {
52
CPRMAN_PLLB_CHANNEL_ARM,
53
54
CPRMAN_NUM_PLL_CHANNEL,
55
+
56
+ /* Special values used when connecting clock sources to clocks */
57
+ CPRMAN_CLOCK_SRC_NORMAL = -1,
58
+ CPRMAN_CLOCK_SRC_FORCE_GROUND = -2,
59
+ CPRMAN_CLOCK_SRC_DSI0HSCK = -3,
60
} CprmanPllChannel;
61
62
+typedef enum CprmanClockMux {
63
+ CPRMAN_CLOCK_GNRIC,
64
+ CPRMAN_CLOCK_VPU,
65
+ CPRMAN_CLOCK_SYS,
66
+ CPRMAN_CLOCK_PERIA,
67
+ CPRMAN_CLOCK_PERII,
68
+ CPRMAN_CLOCK_H264,
69
+ CPRMAN_CLOCK_ISP,
70
+ CPRMAN_CLOCK_V3D,
71
+ CPRMAN_CLOCK_CAM0,
72
+ CPRMAN_CLOCK_CAM1,
73
+ CPRMAN_CLOCK_CCP2,
74
+ CPRMAN_CLOCK_DSI0E,
75
+ CPRMAN_CLOCK_DSI0P,
76
+ CPRMAN_CLOCK_DPI,
77
+ CPRMAN_CLOCK_GP0,
78
+ CPRMAN_CLOCK_GP1,
79
+ CPRMAN_CLOCK_GP2,
80
+ CPRMAN_CLOCK_HSM,
81
+ CPRMAN_CLOCK_OTP,
82
+ CPRMAN_CLOCK_PCM,
83
+ CPRMAN_CLOCK_PWM,
84
+ CPRMAN_CLOCK_SLIM,
85
+ CPRMAN_CLOCK_SMI,
86
+ CPRMAN_CLOCK_TEC,
87
+ CPRMAN_CLOCK_TD0,
88
+ CPRMAN_CLOCK_TD1,
89
+ CPRMAN_CLOCK_TSENS,
90
+ CPRMAN_CLOCK_TIMER,
91
+ CPRMAN_CLOCK_UART,
92
+ CPRMAN_CLOCK_VEC,
93
+ CPRMAN_CLOCK_PULSE,
94
+ CPRMAN_CLOCK_SDC,
95
+ CPRMAN_CLOCK_ARM,
96
+ CPRMAN_CLOCK_AVEO,
97
+ CPRMAN_CLOCK_EMMC,
98
+ CPRMAN_CLOCK_EMMC2,
99
+
100
+ CPRMAN_NUM_CLOCK_MUX
101
+} CprmanClockMux;
102
+
103
+typedef enum CprmanClockMuxSource {
104
+ CPRMAN_CLOCK_SRC_GND = 0,
105
+ CPRMAN_CLOCK_SRC_XOSC,
106
+ CPRMAN_CLOCK_SRC_TD0,
107
+ CPRMAN_CLOCK_SRC_TD1,
108
+ CPRMAN_CLOCK_SRC_PLLA,
109
+ CPRMAN_CLOCK_SRC_PLLC,
110
+ CPRMAN_CLOCK_SRC_PLLD,
111
+ CPRMAN_CLOCK_SRC_PLLH,
112
+ CPRMAN_CLOCK_SRC_PLLC_CORE1,
113
+ CPRMAN_CLOCK_SRC_PLLC_CORE2,
114
+
115
+ CPRMAN_NUM_CLOCK_MUX_SRC
116
+} CprmanClockMuxSource;
117
+
118
typedef struct CprmanPllState {
119
/*< private >*/
120
DeviceState parent_obj;
121
@@ -XXX,XX +XXX,XX @@ typedef struct CprmanPllChannelState {
122
Clock *out;
123
} CprmanPllChannelState;
124
125
+typedef struct CprmanClockMuxState {
126
+ /*< private >*/
127
+ DeviceState parent_obj;
128
+
129
+ /*< public >*/
130
+ CprmanClockMux id;
131
+
132
+ uint32_t *reg_ctl;
133
+ uint32_t *reg_div;
134
+ int int_bits;
135
+ int frac_bits;
136
+
137
+ Clock *srcs[CPRMAN_NUM_CLOCK_MUX_SRC];
138
+ Clock *out;
139
+
140
+ /*
141
+ * Used by clock srcs update callback to retrieve both the clock and the
142
+ * source number.
143
+ */
144
+ struct CprmanClockMuxState *backref[CPRMAN_NUM_CLOCK_MUX_SRC];
145
+} CprmanClockMuxState;
146
+
147
struct BCM2835CprmanState {
148
/*< private >*/
149
SysBusDevice parent_obj;
150
@@ -XXX,XX +XXX,XX @@ struct BCM2835CprmanState {
151
152
CprmanPllState plls[CPRMAN_NUM_PLL];
153
CprmanPllChannelState channels[CPRMAN_NUM_PLL_CHANNEL];
154
+ CprmanClockMuxState clock_muxes[CPRMAN_NUM_CLOCK_MUX];
155
156
uint32_t regs[CPRMAN_NUM_REGS];
157
uint32_t xosc_freq;
158
159
Clock *xosc;
160
+ Clock *gnd;
161
};
162
163
#endif
164
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
165
index XXXXXXX..XXXXXXX 100644
166
--- a/include/hw/misc/bcm2835_cprman_internals.h
167
+++ b/include/hw/misc/bcm2835_cprman_internals.h
19
@@ -XXX,XX +XXX,XX @@
168
@@ -XXX,XX +XXX,XX @@
20
* + named GPIO output "sec_resp_cfg" indicating whether blocked accesses
169
21
* should RAZ/WI or bus error
170
#define TYPE_CPRMAN_PLL "bcm2835-cprman-pll"
22
* + named GPIO output "nsc_cfg" whose value tracks the NSCCFG register value
171
#define TYPE_CPRMAN_PLL_CHANNEL "bcm2835-cprman-pll-channel"
23
+ * + named GPIO output "msc_irq" for the combined IRQ line from the MSCs
172
+#define TYPE_CPRMAN_CLOCK_MUX "bcm2835-cprman-clock-mux"
24
* Controlling the 2 APB PPCs in the IoTKit:
173
25
* + named GPIO outputs apb_ppc0_nonsec[0..2] and apb_ppc1_nonsec
174
DECLARE_INSTANCE_CHECKER(CprmanPllState, CPRMAN_PLL,
26
* + named GPIO outputs apb_ppc0_ap[0..2] and apb_ppc1_ap
175
TYPE_CPRMAN_PLL)
176
DECLARE_INSTANCE_CHECKER(CprmanPllChannelState, CPRMAN_PLL_CHANNEL,
177
TYPE_CPRMAN_PLL_CHANNEL)
178
+DECLARE_INSTANCE_CHECKER(CprmanClockMuxState, CPRMAN_CLOCK_MUX,
179
+ TYPE_CPRMAN_CLOCK_MUX)
180
181
/* Register map */
182
183
@@ -XXX,XX +XXX,XX @@ REG32(A2W_PLLH_STS, 0x1660)
184
185
REG32(A2W_PLLB_ARM, 0x13e0)
186
187
+/* Clock muxes */
188
+REG32(CM_GNRICCTL, 0x000)
189
+ FIELD(CM_CLOCKx_CTL, SRC, 0, 4)
190
+ FIELD(CM_CLOCKx_CTL, ENABLE, 4, 1)
191
+ FIELD(CM_CLOCKx_CTL, KILL, 5, 1)
192
+ FIELD(CM_CLOCKx_CTL, GATE, 6, 1)
193
+ FIELD(CM_CLOCKx_CTL, BUSY, 7, 1)
194
+ FIELD(CM_CLOCKx_CTL, BUSYD, 8, 1)
195
+ FIELD(CM_CLOCKx_CTL, MASH, 9, 2)
196
+ FIELD(CM_CLOCKx_CTL, FLIP, 11, 1)
197
+REG32(CM_GNRICDIV, 0x004)
198
+ FIELD(CM_CLOCKx_DIV, FRAC, 0, 12)
199
+REG32(CM_VPUCTL, 0x008)
200
+REG32(CM_VPUDIV, 0x00c)
201
+REG32(CM_SYSCTL, 0x010)
202
+REG32(CM_SYSDIV, 0x014)
203
+REG32(CM_PERIACTL, 0x018)
204
+REG32(CM_PERIADIV, 0x01c)
205
+REG32(CM_PERIICTL, 0x020)
206
+REG32(CM_PERIIDIV, 0x024)
207
+REG32(CM_H264CTL, 0x028)
208
+REG32(CM_H264DIV, 0x02c)
209
+REG32(CM_ISPCTL, 0x030)
210
+REG32(CM_ISPDIV, 0x034)
211
+REG32(CM_V3DCTL, 0x038)
212
+REG32(CM_V3DDIV, 0x03c)
213
+REG32(CM_CAM0CTL, 0x040)
214
+REG32(CM_CAM0DIV, 0x044)
215
+REG32(CM_CAM1CTL, 0x048)
216
+REG32(CM_CAM1DIV, 0x04c)
217
+REG32(CM_CCP2CTL, 0x050)
218
+REG32(CM_CCP2DIV, 0x054)
219
+REG32(CM_DSI0ECTL, 0x058)
220
+REG32(CM_DSI0EDIV, 0x05c)
221
+REG32(CM_DSI0PCTL, 0x060)
222
+REG32(CM_DSI0PDIV, 0x064)
223
+REG32(CM_DPICTL, 0x068)
224
+REG32(CM_DPIDIV, 0x06c)
225
+REG32(CM_GP0CTL, 0x070)
226
+REG32(CM_GP0DIV, 0x074)
227
+REG32(CM_GP1CTL, 0x078)
228
+REG32(CM_GP1DIV, 0x07c)
229
+REG32(CM_GP2CTL, 0x080)
230
+REG32(CM_GP2DIV, 0x084)
231
+REG32(CM_HSMCTL, 0x088)
232
+REG32(CM_HSMDIV, 0x08c)
233
+REG32(CM_OTPCTL, 0x090)
234
+REG32(CM_OTPDIV, 0x094)
235
+REG32(CM_PCMCTL, 0x098)
236
+REG32(CM_PCMDIV, 0x09c)
237
+REG32(CM_PWMCTL, 0x0a0)
238
+REG32(CM_PWMDIV, 0x0a4)
239
+REG32(CM_SLIMCTL, 0x0a8)
240
+REG32(CM_SLIMDIV, 0x0ac)
241
+REG32(CM_SMICTL, 0x0b0)
242
+REG32(CM_SMIDIV, 0x0b4)
243
+REG32(CM_TCNTCTL, 0x0c0)
244
+REG32(CM_TCNTCNT, 0x0c4)
245
+REG32(CM_TECCTL, 0x0c8)
246
+REG32(CM_TECDIV, 0x0cc)
247
+REG32(CM_TD0CTL, 0x0d0)
248
+REG32(CM_TD0DIV, 0x0d4)
249
+REG32(CM_TD1CTL, 0x0d8)
250
+REG32(CM_TD1DIV, 0x0dc)
251
+REG32(CM_TSENSCTL, 0x0e0)
252
+REG32(CM_TSENSDIV, 0x0e4)
253
+REG32(CM_TIMERCTL, 0x0e8)
254
+REG32(CM_TIMERDIV, 0x0ec)
255
+REG32(CM_UARTCTL, 0x0f0)
256
+REG32(CM_UARTDIV, 0x0f4)
257
+REG32(CM_VECCTL, 0x0f8)
258
+REG32(CM_VECDIV, 0x0fc)
259
+REG32(CM_PULSECTL, 0x190)
260
+REG32(CM_PULSEDIV, 0x194)
261
+REG32(CM_SDCCTL, 0x1a8)
262
+REG32(CM_SDCDIV, 0x1ac)
263
+REG32(CM_ARMCTL, 0x1b0)
264
+REG32(CM_AVEOCTL, 0x1b8)
265
+REG32(CM_AVEODIV, 0x1bc)
266
+REG32(CM_EMMCCTL, 0x1c0)
267
+REG32(CM_EMMCDIV, 0x1c4)
268
+REG32(CM_EMMC2CTL, 0x1d0)
269
+REG32(CM_EMMC2DIV, 0x1d4)
270
+
271
/* misc registers */
272
REG32(CM_LOCK, 0x114)
273
FIELD(CM_LOCK, FLOCKH, 12, 1)
274
@@ -XXX,XX +XXX,XX @@ static inline void set_pll_channel_init_info(BCM2835CprmanState *s,
275
channel->fixed_divider = PLL_CHANNEL_INIT_INFO[id].fixed_divider;
276
}
277
278
+/* Clock mux init info */
279
+typedef struct ClockMuxInitInfo {
280
+ const char *name;
281
+ size_t cm_offset; /* cm_offset[0]->CM_CTL, cm_offset[1]->CM_DIV */
282
+ int int_bits;
283
+ int frac_bits;
284
+
285
+ CprmanPllChannel src_mapping[CPRMAN_NUM_CLOCK_MUX_SRC];
286
+} ClockMuxInitInfo;
287
+
288
+/*
289
+ * Each clock mux can have up to 10 sources. Sources 0 to 3 are always the
290
+ * same (ground, xosc, td0, td1). Sources 4 to 9 are mux specific, and are not
291
+ * always populated. The following macros catch all those cases.
292
+ */
293
+
294
+/* Unknown mapping. Connect everything to ground */
295
+#define SRC_MAPPING_INFO_unknown \
296
+ .src_mapping = { \
297
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* gnd */ \
298
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* xosc */ \
299
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* test debug 0 */ \
300
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* test debug 1 */ \
301
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll a */ \
302
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll c */ \
303
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll d */ \
304
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll h */ \
305
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll c, core1 */ \
306
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll c, core2 */ \
307
+ }
308
+
309
+/* Only the oscillator and the two test debug clocks */
310
+#define SRC_MAPPING_INFO_xosc \
311
+ .src_mapping = { \
312
+ CPRMAN_CLOCK_SRC_NORMAL, \
313
+ CPRMAN_CLOCK_SRC_NORMAL, \
314
+ CPRMAN_CLOCK_SRC_NORMAL, \
315
+ CPRMAN_CLOCK_SRC_NORMAL, \
316
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
317
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
318
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
319
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
320
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
321
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
322
+ }
323
+
324
+/* All the PLL "core" channels */
325
+#define SRC_MAPPING_INFO_core \
326
+ .src_mapping = { \
327
+ CPRMAN_CLOCK_SRC_NORMAL, \
328
+ CPRMAN_CLOCK_SRC_NORMAL, \
329
+ CPRMAN_CLOCK_SRC_NORMAL, \
330
+ CPRMAN_CLOCK_SRC_NORMAL, \
331
+ CPRMAN_PLLA_CHANNEL_CORE, \
332
+ CPRMAN_PLLC_CHANNEL_CORE0, \
333
+ CPRMAN_PLLD_CHANNEL_CORE, \
334
+ CPRMAN_PLLH_CHANNEL_AUX, \
335
+ CPRMAN_PLLC_CHANNEL_CORE1, \
336
+ CPRMAN_PLLC_CHANNEL_CORE2, \
337
+ }
338
+
339
+/* All the PLL "per" channels */
340
+#define SRC_MAPPING_INFO_periph \
341
+ .src_mapping = { \
342
+ CPRMAN_CLOCK_SRC_NORMAL, \
343
+ CPRMAN_CLOCK_SRC_NORMAL, \
344
+ CPRMAN_CLOCK_SRC_NORMAL, \
345
+ CPRMAN_CLOCK_SRC_NORMAL, \
346
+ CPRMAN_PLLA_CHANNEL_PER, \
347
+ CPRMAN_PLLC_CHANNEL_PER, \
348
+ CPRMAN_PLLD_CHANNEL_PER, \
349
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
350
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
351
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
352
+ }
353
+
354
+/*
355
+ * The DSI0 channels. This one got an intermediate mux between the PLL channels
356
+ * and the clock input.
357
+ */
358
+#define SRC_MAPPING_INFO_dsi0 \
359
+ .src_mapping = { \
360
+ CPRMAN_CLOCK_SRC_NORMAL, \
361
+ CPRMAN_CLOCK_SRC_NORMAL, \
362
+ CPRMAN_CLOCK_SRC_NORMAL, \
363
+ CPRMAN_CLOCK_SRC_NORMAL, \
364
+ CPRMAN_CLOCK_SRC_DSI0HSCK, \
365
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
366
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
367
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
368
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
369
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
370
+ }
371
+
372
+/* The DSI1 channel */
373
+#define SRC_MAPPING_INFO_dsi1 \
374
+ .src_mapping = { \
375
+ CPRMAN_CLOCK_SRC_NORMAL, \
376
+ CPRMAN_CLOCK_SRC_NORMAL, \
377
+ CPRMAN_CLOCK_SRC_NORMAL, \
378
+ CPRMAN_CLOCK_SRC_NORMAL, \
379
+ CPRMAN_PLLD_CHANNEL_DSI1, \
380
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
381
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
382
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
383
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
384
+ CPRMAN_CLOCK_SRC_FORCE_GROUND, \
385
+ }
386
+
387
+#define FILL_CLOCK_MUX_SRC_MAPPING_INIT_INFO(kind_) \
388
+ SRC_MAPPING_INFO_ ## kind_
389
+
390
+#define FILL_CLOCK_MUX_INIT_INFO(clock_, kind_) \
391
+ .cm_offset = R_CM_ ## clock_ ## CTL, \
392
+ FILL_CLOCK_MUX_SRC_MAPPING_INIT_INFO(kind_)
393
+
394
+static ClockMuxInitInfo CLOCK_MUX_INIT_INFO[] = {
395
+ [CPRMAN_CLOCK_GNRIC] = {
396
+ .name = "gnric",
397
+ FILL_CLOCK_MUX_INIT_INFO(GNRIC, unknown),
398
+ },
399
+ [CPRMAN_CLOCK_VPU] = {
400
+ .name = "vpu",
401
+ .int_bits = 12,
402
+ .frac_bits = 8,
403
+ FILL_CLOCK_MUX_INIT_INFO(VPU, core),
404
+ },
405
+ [CPRMAN_CLOCK_SYS] = {
406
+ .name = "sys",
407
+ FILL_CLOCK_MUX_INIT_INFO(SYS, unknown),
408
+ },
409
+ [CPRMAN_CLOCK_PERIA] = {
410
+ .name = "peria",
411
+ FILL_CLOCK_MUX_INIT_INFO(PERIA, unknown),
412
+ },
413
+ [CPRMAN_CLOCK_PERII] = {
414
+ .name = "perii",
415
+ FILL_CLOCK_MUX_INIT_INFO(PERII, unknown),
416
+ },
417
+ [CPRMAN_CLOCK_H264] = {
418
+ .name = "h264",
419
+ .int_bits = 4,
420
+ .frac_bits = 8,
421
+ FILL_CLOCK_MUX_INIT_INFO(H264, core),
422
+ },
423
+ [CPRMAN_CLOCK_ISP] = {
424
+ .name = "isp",
425
+ .int_bits = 4,
426
+ .frac_bits = 8,
427
+ FILL_CLOCK_MUX_INIT_INFO(ISP, core),
428
+ },
429
+ [CPRMAN_CLOCK_V3D] = {
430
+ .name = "v3d",
431
+ FILL_CLOCK_MUX_INIT_INFO(V3D, core),
432
+ },
433
+ [CPRMAN_CLOCK_CAM0] = {
434
+ .name = "cam0",
435
+ .int_bits = 4,
436
+ .frac_bits = 8,
437
+ FILL_CLOCK_MUX_INIT_INFO(CAM0, periph),
438
+ },
439
+ [CPRMAN_CLOCK_CAM1] = {
440
+ .name = "cam1",
441
+ .int_bits = 4,
442
+ .frac_bits = 8,
443
+ FILL_CLOCK_MUX_INIT_INFO(CAM1, periph),
444
+ },
445
+ [CPRMAN_CLOCK_CCP2] = {
446
+ .name = "ccp2",
447
+ FILL_CLOCK_MUX_INIT_INFO(CCP2, unknown),
448
+ },
449
+ [CPRMAN_CLOCK_DSI0E] = {
450
+ .name = "dsi0e",
451
+ .int_bits = 4,
452
+ .frac_bits = 8,
453
+ FILL_CLOCK_MUX_INIT_INFO(DSI0E, dsi0),
454
+ },
455
+ [CPRMAN_CLOCK_DSI0P] = {
456
+ .name = "dsi0p",
457
+ .int_bits = 0,
458
+ .frac_bits = 0,
459
+ FILL_CLOCK_MUX_INIT_INFO(DSI0P, dsi0),
460
+ },
461
+ [CPRMAN_CLOCK_DPI] = {
462
+ .name = "dpi",
463
+ .int_bits = 4,
464
+ .frac_bits = 8,
465
+ FILL_CLOCK_MUX_INIT_INFO(DPI, periph),
466
+ },
467
+ [CPRMAN_CLOCK_GP0] = {
468
+ .name = "gp0",
469
+ .int_bits = 12,
470
+ .frac_bits = 12,
471
+ FILL_CLOCK_MUX_INIT_INFO(GP0, periph),
472
+ },
473
+ [CPRMAN_CLOCK_GP1] = {
474
+ .name = "gp1",
475
+ .int_bits = 12,
476
+ .frac_bits = 12,
477
+ FILL_CLOCK_MUX_INIT_INFO(GP1, periph),
478
+ },
479
+ [CPRMAN_CLOCK_GP2] = {
480
+ .name = "gp2",
481
+ .int_bits = 12,
482
+ .frac_bits = 12,
483
+ FILL_CLOCK_MUX_INIT_INFO(GP2, periph),
484
+ },
485
+ [CPRMAN_CLOCK_HSM] = {
486
+ .name = "hsm",
487
+ .int_bits = 4,
488
+ .frac_bits = 8,
489
+ FILL_CLOCK_MUX_INIT_INFO(HSM, periph),
490
+ },
491
+ [CPRMAN_CLOCK_OTP] = {
492
+ .name = "otp",
493
+ .int_bits = 4,
494
+ .frac_bits = 0,
495
+ FILL_CLOCK_MUX_INIT_INFO(OTP, xosc),
496
+ },
497
+ [CPRMAN_CLOCK_PCM] = {
498
+ .name = "pcm",
499
+ .int_bits = 12,
500
+ .frac_bits = 12,
501
+ FILL_CLOCK_MUX_INIT_INFO(PCM, periph),
502
+ },
503
+ [CPRMAN_CLOCK_PWM] = {
504
+ .name = "pwm",
505
+ .int_bits = 12,
506
+ .frac_bits = 12,
507
+ FILL_CLOCK_MUX_INIT_INFO(PWM, periph),
508
+ },
509
+ [CPRMAN_CLOCK_SLIM] = {
510
+ .name = "slim",
511
+ .int_bits = 12,
512
+ .frac_bits = 12,
513
+ FILL_CLOCK_MUX_INIT_INFO(SLIM, periph),
514
+ },
515
+ [CPRMAN_CLOCK_SMI] = {
516
+ .name = "smi",
517
+ .int_bits = 4,
518
+ .frac_bits = 8,
519
+ FILL_CLOCK_MUX_INIT_INFO(SMI, periph),
520
+ },
521
+ [CPRMAN_CLOCK_TEC] = {
522
+ .name = "tec",
523
+ .int_bits = 6,
524
+ .frac_bits = 0,
525
+ FILL_CLOCK_MUX_INIT_INFO(TEC, xosc),
526
+ },
527
+ [CPRMAN_CLOCK_TD0] = {
528
+ .name = "td0",
529
+ FILL_CLOCK_MUX_INIT_INFO(TD0, unknown),
530
+ },
531
+ [CPRMAN_CLOCK_TD1] = {
532
+ .name = "td1",
533
+ FILL_CLOCK_MUX_INIT_INFO(TD1, unknown),
534
+ },
535
+ [CPRMAN_CLOCK_TSENS] = {
536
+ .name = "tsens",
537
+ .int_bits = 5,
538
+ .frac_bits = 0,
539
+ FILL_CLOCK_MUX_INIT_INFO(TSENS, xosc),
540
+ },
541
+ [CPRMAN_CLOCK_TIMER] = {
542
+ .name = "timer",
543
+ .int_bits = 6,
544
+ .frac_bits = 12,
545
+ FILL_CLOCK_MUX_INIT_INFO(TIMER, xosc),
546
+ },
547
+ [CPRMAN_CLOCK_UART] = {
548
+ .name = "uart",
549
+ .int_bits = 10,
550
+ .frac_bits = 12,
551
+ FILL_CLOCK_MUX_INIT_INFO(UART, periph),
552
+ },
553
+ [CPRMAN_CLOCK_VEC] = {
554
+ .name = "vec",
555
+ .int_bits = 4,
556
+ .frac_bits = 0,
557
+ FILL_CLOCK_MUX_INIT_INFO(VEC, periph),
558
+ },
559
+ [CPRMAN_CLOCK_PULSE] = {
560
+ .name = "pulse",
561
+ FILL_CLOCK_MUX_INIT_INFO(PULSE, xosc),
562
+ },
563
+ [CPRMAN_CLOCK_SDC] = {
564
+ .name = "sdram",
565
+ .int_bits = 6,
566
+ .frac_bits = 0,
567
+ FILL_CLOCK_MUX_INIT_INFO(SDC, core),
568
+ },
569
+ [CPRMAN_CLOCK_ARM] = {
570
+ .name = "arm",
571
+ FILL_CLOCK_MUX_INIT_INFO(ARM, unknown),
572
+ },
573
+ [CPRMAN_CLOCK_AVEO] = {
574
+ .name = "aveo",
575
+ .int_bits = 4,
576
+ .frac_bits = 0,
577
+ FILL_CLOCK_MUX_INIT_INFO(AVEO, periph),
578
+ },
579
+ [CPRMAN_CLOCK_EMMC] = {
580
+ .name = "emmc",
581
+ .int_bits = 4,
582
+ .frac_bits = 8,
583
+ FILL_CLOCK_MUX_INIT_INFO(EMMC, periph),
584
+ },
585
+ [CPRMAN_CLOCK_EMMC2] = {
586
+ .name = "emmc2",
587
+ .int_bits = 4,
588
+ .frac_bits = 8,
589
+ FILL_CLOCK_MUX_INIT_INFO(EMMC2, unknown),
590
+ },
591
+};
592
+
593
+#undef FILL_CLOCK_MUX_INIT_INFO
594
+#undef FILL_CLOCK_MUX_SRC_MAPPING_INIT_INFO
595
+#undef SRC_MAPPING_INFO_dsi1
596
+#undef SRC_MAPPING_INFO_dsi0
597
+#undef SRC_MAPPING_INFO_periph
598
+#undef SRC_MAPPING_INFO_core
599
+#undef SRC_MAPPING_INFO_xosc
600
+#undef SRC_MAPPING_INFO_unknown
601
+
602
+static inline void set_clock_mux_init_info(BCM2835CprmanState *s,
603
+ CprmanClockMuxState *mux,
604
+ CprmanClockMux id)
605
+{
606
+ mux->id = id;
607
+ mux->reg_ctl = &s->regs[CLOCK_MUX_INIT_INFO[id].cm_offset];
608
+ mux->reg_div = &s->regs[CLOCK_MUX_INIT_INFO[id].cm_offset + 1];
609
+ mux->int_bits = CLOCK_MUX_INIT_INFO[id].int_bits;
610
+ mux->frac_bits = CLOCK_MUX_INIT_INFO[id].frac_bits;
611
+}
612
+
613
#endif
614
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
615
index XXXXXXX..XXXXXXX 100644
616
--- a/hw/misc/bcm2835_cprman.c
617
+++ b/hw/misc/bcm2835_cprman.c
27
@@ -XXX,XX +XXX,XX @@
618
@@ -XXX,XX +XXX,XX @@
28
* Controlling each of the 16 expansion MPCs which a system using the IoTKit
619
*
29
* might provide:
620
* The page at https://elinux.org/The_Undocumented_Pi gives the actual clock
30
* + named GPIO inputs mpcexp_status[0..15]
621
* tree configuration.
31
+ * Controlling each of the 16 expansion MSCs which a system using the IoTKit
622
+ *
32
+ * might provide:
623
+ * The CPRMAN exposes clock outputs with the name of the clock mux suffixed
33
+ * + named GPIO inputs mscexp_status[0..15]
624
+ * with "-out" (e.g. "uart-out", "h264-out", ...).
34
+ * + named GPIO outputs mscexp_clear[0..15]
35
+ * + named GPIO outputs mscexp_ns[0..15]
36
*/
625
*/
37
626
38
#ifndef IOTKIT_SECCTL_H
627
#include "qemu/osdep.h"
39
@@ -XXX,XX +XXX,XX @@
628
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_channel_info = {
40
#define IOTS_NUM_AHB_EXP_PPC 4
629
};
41
#define IOTS_NUM_EXP_MPC 16
630
42
#define IOTS_NUM_MPC 1
631
43
+#define IOTS_NUM_EXP_MSC 16
632
+/* clock mux */
44
633
+
45
typedef struct IoTKitSecCtl IoTKitSecCtl;
634
+static void clock_mux_update(CprmanClockMuxState *mux)
46
47
@@ -XXX,XX +XXX,XX @@ struct IoTKitSecCtl {
48
uint32_t brginten;
49
uint32_t mpcintstatus;
50
51
+ uint32_t secmscintstat;
52
+ uint32_t secmscinten;
53
+ uint32_t nsmscexp;
54
+ qemu_irq mscexp_clear[IOTS_NUM_EXP_MSC];
55
+ qemu_irq mscexp_ns[IOTS_NUM_EXP_MSC];
56
+ qemu_irq msc_irq;
57
+
58
IoTKitSecCtlPPC apb[IOTS_NUM_APB_PPC];
59
IoTKitSecCtlPPC apbexp[IOTS_NUM_APB_EXP_PPC];
60
IoTKitSecCtlPPC ahbexp[IOTS_NUM_APB_EXP_PPC];
61
diff --git a/hw/misc/iotkit-secctl.c b/hw/misc/iotkit-secctl.c
62
index XXXXXXX..XXXXXXX 100644
63
--- a/hw/misc/iotkit-secctl.c
64
+++ b/hw/misc/iotkit-secctl.c
65
@@ -XXX,XX +XXX,XX @@ static MemTxResult iotkit_secctl_s_read(void *opaque, hwaddr addr,
66
r = s->apbexp[offset_to_ppc_idx(offset)].sp;
67
break;
68
case A_SECMSCINTSTAT:
69
+ r = s->secmscintstat;
70
+ break;
71
case A_SECMSCINTEN:
72
+ r = s->secmscinten;
73
+ break;
74
case A_NSMSCEXP:
75
- qemu_log_mask(LOG_UNIMP,
76
- "IoTKit SecCtl S block read: "
77
- "unimplemented offset 0x%x\n", offset);
78
- r = 0;
79
+ r = s->nsmscexp;
80
break;
81
case A_PID4:
82
case A_PID5:
83
@@ -XXX,XX +XXX,XX @@ static void iotkit_secctl_ppc_update_irq_enable(IoTKitSecCtlPPC *ppc)
84
qemu_set_irq(ppc->irq_enable, extract32(value, ppc->irq_bit_offset, 1));
85
}
86
87
+static void iotkit_secctl_update_mscexp_irqs(qemu_irq *msc_irqs, uint32_t value)
88
+{
635
+{
89
+ int i;
636
+ clock_update(mux->out, 0);
90
+
91
+ for (i = 0; i < IOTS_NUM_EXP_MSC; i++) {
92
+ qemu_set_irq(msc_irqs[i], extract32(value, i + 16, 1));
93
+ }
94
+}
637
+}
95
+
638
+
96
+static void iotkit_secctl_update_msc_irq(IoTKitSecCtl *s)
639
+static void clock_mux_src_update(void *opaque)
97
+{
640
+{
98
+ /* Update the combined MSC IRQ, based on S_MSCEXP_STATUS and S_MSCEXP_EN */
641
+ CprmanClockMuxState **backref = opaque;
99
+ bool level = s->secmscintstat & s->secmscinten;
642
+ CprmanClockMuxState *s = *backref;
100
+
643
+
101
+ qemu_set_irq(s->msc_irq, level);
644
+ clock_mux_update(s);
102
+}
645
+}
103
+
646
+
104
static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr,
647
+static void clock_mux_init(Object *obj)
105
uint64_t value,
106
unsigned size, MemTxAttrs attrs)
107
@@ -XXX,XX +XXX,XX @@ static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr,
108
iotkit_secctl_ppc_sp_write(ppc, value);
109
break;
110
case A_SECMSCINTCLR:
111
+ iotkit_secctl_update_mscexp_irqs(s->mscexp_clear, value);
112
+ break;
113
case A_SECMSCINTEN:
114
- qemu_log_mask(LOG_UNIMP,
115
- "IoTKit SecCtl S block write: "
116
- "unimplemented offset 0x%x\n", offset);
117
+ s->secmscinten = value;
118
+ iotkit_secctl_update_msc_irq(s);
119
+ break;
120
+ case A_NSMSCEXP:
121
+ s->nsmscexp = value;
122
+ iotkit_secctl_update_mscexp_irqs(s->mscexp_ns, value);
123
break;
124
case A_SECMPCINTSTATUS:
125
case A_SECPPCINTSTAT:
126
@@ -XXX,XX +XXX,XX @@ static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr,
127
case A_BRGINTSTAT:
128
case A_AHBNSPPC0:
129
case A_AHBSPPPC0:
130
- case A_NSMSCEXP:
131
case A_PID4:
132
case A_PID5:
133
case A_PID6:
134
@@ -XXX,XX +XXX,XX @@ static void iotkit_secctl_mpcexp_status(void *opaque, int n, int level)
135
s->mpcintstatus = deposit32(s->mpcintstatus, n + 16, 1, !!level);
136
}
137
138
+static void iotkit_secctl_mscexp_status(void *opaque, int n, int level)
139
+{
648
+{
140
+ IoTKitSecCtl *s = IOTKIT_SECCTL(opaque);
649
+ CprmanClockMuxState *s = CPRMAN_CLOCK_MUX(obj);
141
+
650
+ size_t i;
142
+ s->secmscintstat = deposit32(s->secmscintstat, n + 16, 1, !!level);
651
+
143
+ iotkit_secctl_update_msc_irq(s);
652
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX_SRC; i++) {
653
+ char *name = g_strdup_printf("srcs[%zu]", i);
654
+ s->backref[i] = s;
655
+ s->srcs[i] = qdev_init_clock_in(DEVICE(s), name,
656
+ clock_mux_src_update,
657
+ &s->backref[i]);
658
+ g_free(name);
659
+ }
660
+
661
+ s->out = qdev_init_clock_out(DEVICE(s), "out");
144
+}
662
+}
145
+
663
+
146
static void iotkit_secctl_ppc_irqstatus(void *opaque, int n, int level)
664
+static const VMStateDescription clock_mux_vmstate = {
147
{
665
+ .name = TYPE_CPRMAN_CLOCK_MUX,
148
IoTKitSecCtlPPC *ppc = opaque;
149
@@ -XXX,XX +XXX,XX @@ static void iotkit_secctl_init(Object *obj)
150
qdev_init_gpio_in_named(dev, iotkit_secctl_mpcexp_status,
151
"mpcexp_status", IOTS_NUM_EXP_MPC);
152
153
+ qdev_init_gpio_in_named(dev, iotkit_secctl_mscexp_status,
154
+ "mscexp_status", IOTS_NUM_EXP_MSC);
155
+ qdev_init_gpio_out_named(dev, s->mscexp_clear, "mscexp_clear",
156
+ IOTS_NUM_EXP_MSC);
157
+ qdev_init_gpio_out_named(dev, s->mscexp_ns, "mscexp_ns",
158
+ IOTS_NUM_EXP_MSC);
159
+ qdev_init_gpio_out_named(dev, &s->msc_irq, "msc_irq", 1);
160
+
161
memory_region_init_io(&s->s_regs, obj, &iotkit_secctl_s_ops,
162
s, "iotkit-secctl-s-regs", 0x1000);
163
memory_region_init_io(&s->ns_regs, obj, &iotkit_secctl_ns_ops,
164
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription iotkit_secctl_mpcintstatus_vmstate = {
165
}
166
};
167
168
+static bool needed_always(void *opaque)
169
+{
170
+ return true;
171
+}
172
+
173
+static const VMStateDescription iotkit_secctl_msc_vmstate = {
174
+ .name = "iotkit-secctl/msc",
175
+ .version_id = 1,
666
+ .version_id = 1,
176
+ .minimum_version_id = 1,
667
+ .minimum_version_id = 1,
177
+ .needed = needed_always,
178
+ .fields = (VMStateField[]) {
668
+ .fields = (VMStateField[]) {
179
+ VMSTATE_UINT32(secmscintstat, IoTKitSecCtl),
669
+ VMSTATE_ARRAY_CLOCK(srcs, CprmanClockMuxState,
180
+ VMSTATE_UINT32(secmscinten, IoTKitSecCtl),
670
+ CPRMAN_NUM_CLOCK_MUX_SRC),
181
+ VMSTATE_UINT32(nsmscexp, IoTKitSecCtl),
182
+ VMSTATE_END_OF_LIST()
671
+ VMSTATE_END_OF_LIST()
183
+ }
672
+ }
184
+};
673
+};
185
+
674
+
186
static const VMStateDescription iotkit_secctl_vmstate = {
675
+static void clock_mux_class_init(ObjectClass *klass, void *data)
187
.name = "iotkit-secctl",
676
+{
188
.version_id = 1,
677
+ DeviceClass *dc = DEVICE_CLASS(klass);
189
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription iotkit_secctl_vmstate = {
678
+
190
},
679
+ dc->vmsd = &clock_mux_vmstate;
191
.subsections = (const VMStateDescription*[]) {
680
+}
192
&iotkit_secctl_mpcintstatus_vmstate,
681
+
193
+ &iotkit_secctl_msc_vmstate,
682
+static const TypeInfo cprman_clock_mux_info = {
194
NULL
683
+ .name = TYPE_CPRMAN_CLOCK_MUX,
195
},
684
+ .parent = TYPE_DEVICE,
196
};
685
+ .instance_size = sizeof(CprmanClockMuxState),
686
+ .class_init = clock_mux_class_init,
687
+ .instance_init = clock_mux_init,
688
+};
689
+
690
+
691
/* CPRMAN "top level" model */
692
693
static uint32_t get_cm_lock(const BCM2835CprmanState *s)
694
@@ -XXX,XX +XXX,XX @@ static inline void update_channel_from_a2w(BCM2835CprmanState *s, size_t idx)
695
}
696
}
697
698
+static inline void update_mux_from_cm(BCM2835CprmanState *s, size_t idx)
699
+{
700
+ size_t i;
701
+
702
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
703
+ if ((CLOCK_MUX_INIT_INFO[i].cm_offset == idx) ||
704
+ (CLOCK_MUX_INIT_INFO[i].cm_offset + 4 == idx)) {
705
+ /* matches CM_CTL or CM_DIV mux register */
706
+ clock_mux_update(&s->clock_muxes[i]);
707
+ return;
708
+ }
709
+ }
710
+}
711
+
712
#define CASE_PLL_A2W_REGS(pll_) \
713
case R_A2W_ ## pll_ ## _CTRL: \
714
case R_A2W_ ## pll_ ## _ANA0: \
715
@@ -XXX,XX +XXX,XX @@ static void cprman_write(void *opaque, hwaddr offset,
716
case R_A2W_PLLB_ARM:
717
update_channel_from_a2w(s, idx);
718
break;
719
+
720
+ case R_CM_GNRICCTL ... R_CM_SMIDIV:
721
+ case R_CM_TCNTCNT ... R_CM_VECDIV:
722
+ case R_CM_PULSECTL ... R_CM_PULSEDIV:
723
+ case R_CM_SDCCTL ... R_CM_ARMCTL:
724
+ case R_CM_AVEOCTL ... R_CM_EMMCDIV:
725
+ case R_CM_EMMC2CTL ... R_CM_EMMC2DIV:
726
+ update_mux_from_cm(s, idx);
727
+ break;
728
}
729
}
730
731
@@ -XXX,XX +XXX,XX @@ static void cprman_reset(DeviceState *dev)
732
device_cold_reset(DEVICE(&s->channels[i]));
733
}
734
735
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
736
+ device_cold_reset(DEVICE(&s->clock_muxes[i]));
737
+ }
738
+
739
clock_update_hz(s->xosc, s->xosc_freq);
740
}
741
742
@@ -XXX,XX +XXX,XX @@ static void cprman_init(Object *obj)
743
set_pll_channel_init_info(s, &s->channels[i], i);
744
}
745
746
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
747
+ char *alias;
748
+
749
+ object_initialize_child(obj, CLOCK_MUX_INIT_INFO[i].name,
750
+ &s->clock_muxes[i],
751
+ TYPE_CPRMAN_CLOCK_MUX);
752
+ set_clock_mux_init_info(s, &s->clock_muxes[i], i);
753
+
754
+ /* Expose muxes output as CPRMAN outputs */
755
+ alias = g_strdup_printf("%s-out", CLOCK_MUX_INIT_INFO[i].name);
756
+ qdev_alias_clock(DEVICE(&s->clock_muxes[i]), "out", DEVICE(obj), alias);
757
+ g_free(alias);
758
+ }
759
+
760
s->xosc = clock_new(obj, "xosc");
761
+ s->gnd = clock_new(obj, "gnd");
762
+
763
+ clock_set(s->gnd, 0);
764
765
memory_region_init_io(&s->iomem, obj, &cprman_ops,
766
s, "bcm2835-cprman", 0x2000);
767
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
768
}
769
770
+static void connect_mux_sources(BCM2835CprmanState *s,
771
+ CprmanClockMuxState *mux,
772
+ const CprmanPllChannel *clk_mapping)
773
+{
774
+ size_t i;
775
+ Clock *td0 = s->clock_muxes[CPRMAN_CLOCK_TD0].out;
776
+ Clock *td1 = s->clock_muxes[CPRMAN_CLOCK_TD1].out;
777
+
778
+ /* For sources from 0 to 3. Source 4 to 9 are mux specific */
779
+ Clock * const CLK_SRC_MAPPING[] = {
780
+ [CPRMAN_CLOCK_SRC_GND] = s->gnd,
781
+ [CPRMAN_CLOCK_SRC_XOSC] = s->xosc,
782
+ [CPRMAN_CLOCK_SRC_TD0] = td0,
783
+ [CPRMAN_CLOCK_SRC_TD1] = td1,
784
+ };
785
+
786
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX_SRC; i++) {
787
+ CprmanPllChannel mapping = clk_mapping[i];
788
+ Clock *src;
789
+
790
+ if (mapping == CPRMAN_CLOCK_SRC_FORCE_GROUND) {
791
+ src = s->gnd;
792
+ } else if (mapping == CPRMAN_CLOCK_SRC_DSI0HSCK) {
793
+ src = s->gnd; /* TODO */
794
+ } else if (i < CPRMAN_CLOCK_SRC_PLLA) {
795
+ src = CLK_SRC_MAPPING[i];
796
+ } else {
797
+ src = s->channels[mapping].out;
798
+ }
799
+
800
+ clock_set_source(mux->srcs[i], src);
801
+ }
802
+}
803
+
804
static void cprman_realize(DeviceState *dev, Error **errp)
805
{
806
BCM2835CprmanState *s = CPRMAN(dev);
807
@@ -XXX,XX +XXX,XX @@ static void cprman_realize(DeviceState *dev, Error **errp)
808
return;
809
}
810
}
811
+
812
+ for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
813
+ CprmanClockMuxState *clock_mux = &s->clock_muxes[i];
814
+
815
+ connect_mux_sources(s, clock_mux, CLOCK_MUX_INIT_INFO[i].src_mapping);
816
+
817
+ if (!qdev_realize(DEVICE(clock_mux), NULL, errp)) {
818
+ return;
819
+ }
820
+ }
821
}
822
823
static const VMStateDescription cprman_vmstate = {
824
@@ -XXX,XX +XXX,XX @@ static void cprman_register_types(void)
825
type_register_static(&cprman_info);
826
type_register_static(&cprman_pll_info);
827
type_register_static(&cprman_pll_channel_info);
828
+ type_register_static(&cprman_clock_mux_info);
829
}
830
831
type_init(cprman_register_types);
197
--
832
--
198
2.18.0
833
2.20.1
199
834
200
835
diff view generated by jsdifflib
1
The IoTKit includes three different instances of the
1
From: Luc Michel <luc@lmichel.fr>
2
CMSDK APB watchdog; create and wire them up.
3
2
3
A clock mux can be configured to select one of its 10 sources through
4
the CM_CTL register. It also embeds yet another clock divider, composed
5
of an integer part and a fractional part. The number of bits of each
6
part is mux dependent.
7
8
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Signed-off-by: Luc Michel <luc@lmichel.fr>
10
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
11
Tested-by: Guenter Roeck <linux@roeck-us.net>
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20180820141116.9118-7-peter.maydell@linaro.org
8
---
13
---
9
include/hw/arm/iotkit.h | 6 +++++
14
hw/misc/bcm2835_cprman.c | 53 +++++++++++++++++++++++++++++++++++++++-
10
hw/arm/iotkit.c | 58 ++++++++++++++++++++++++++++++++++++++---
15
1 file changed, 52 insertions(+), 1 deletion(-)
11
2 files changed, 61 insertions(+), 3 deletions(-)
12
16
13
diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h
17
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
14
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
15
--- a/include/hw/arm/iotkit.h
19
--- a/hw/misc/bcm2835_cprman.c
16
+++ b/include/hw/arm/iotkit.h
20
+++ b/hw/misc/bcm2835_cprman.c
17
@@ -XXX,XX +XXX,XX @@
21
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_channel_info = {
18
#include "hw/misc/tz-mpc.h"
22
19
#include "hw/timer/cmsdk-apb-timer.h"
23
/* clock mux */
20
#include "hw/timer/cmsdk-apb-dualtimer.h"
24
21
+#include "hw/watchdog/cmsdk-apb-watchdog.h"
25
+static bool clock_mux_is_enabled(CprmanClockMuxState *mux)
22
#include "hw/misc/unimp.h"
26
+{
23
#include "hw/or-irq.h"
27
+ return FIELD_EX32(*mux->reg_ctl, CM_CLOCKx_CTL, ENABLE);
24
#include "hw/core/split-irq.h"
28
+}
25
@@ -XXX,XX +XXX,XX @@ typedef struct IoTKit {
26
SplitIRQ ppc_irq_splitter[NUM_PPCS];
27
SplitIRQ mpc_irq_splitter[IOTS_NUM_EXP_MPC + IOTS_NUM_MPC];
28
qemu_or_irq mpc_irq_orgate;
29
+ qemu_or_irq nmi_orgate;
30
31
CMSDKAPBDualTimer dualtimer;
32
UnimplementedDeviceState s32ktimer;
33
34
+ CMSDKAPBWatchdog s32kwatchdog;
35
+ CMSDKAPBWatchdog nswatchdog;
36
+ CMSDKAPBWatchdog swatchdog;
37
+
29
+
38
MemoryRegion container;
30
static void clock_mux_update(CprmanClockMuxState *mux)
39
MemoryRegion alias1;
31
{
40
MemoryRegion alias2;
32
- clock_update(mux->out, 0);
41
diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c
33
+ uint64_t freq;
42
index XXXXXXX..XXXXXXX 100644
34
+ uint32_t div, src = FIELD_EX32(*mux->reg_ctl, CM_CLOCKx_CTL, SRC);
43
--- a/hw/arm/iotkit.c
35
+ bool enabled = clock_mux_is_enabled(mux);
44
+++ b/hw/arm/iotkit.c
45
@@ -XXX,XX +XXX,XX @@
46
#include "hw/misc/unimp.h"
47
#include "hw/arm/arm.h"
48
49
+/* Clock frequency in HZ of the 32KHz "slow clock" */
50
+#define S32KCLK (32 * 1000)
51
+
36
+
52
/* Create an alias region of @size bytes starting at @base
37
+ *mux->reg_ctl = FIELD_DP32(*mux->reg_ctl, CM_CLOCKx_CTL, BUSY, enabled);
53
* which mirrors the memory starting at @orig.
54
*/
55
@@ -XXX,XX +XXX,XX @@ static void iotkit_init(Object *obj)
56
TYPE_CMSDK_APB_TIMER);
57
sysbus_init_child_obj(obj, "dualtimer", &s->dualtimer, sizeof(s->dualtimer),
58
TYPE_CMSDK_APB_DUALTIMER);
59
+ sysbus_init_child_obj(obj, "s32kwatchdog", &s->s32kwatchdog,
60
+ sizeof(s->s32kwatchdog), TYPE_CMSDK_APB_WATCHDOG);
61
+ sysbus_init_child_obj(obj, "nswatchdog", &s->nswatchdog,
62
+ sizeof(s->nswatchdog), TYPE_CMSDK_APB_WATCHDOG);
63
+ sysbus_init_child_obj(obj, "swatchdog", &s->swatchdog,
64
+ sizeof(s->swatchdog), TYPE_CMSDK_APB_WATCHDOG);
65
+ object_initialize_child(obj, "nmi-orgate", &s->nmi_orgate,
66
+ sizeof(s->nmi_orgate), TYPE_OR_IRQ,
67
+ &error_abort, NULL);
68
object_initialize_child(obj, "ppc-irq-orgate", &s->ppc_irq_orgate,
69
sizeof(s->ppc_irq_orgate), TYPE_OR_IRQ,
70
&error_abort, NULL);
71
@@ -XXX,XX +XXX,XX @@ static void iotkit_realize(DeviceState *dev, Error **errp)
72
create_unimplemented_device("SYSINFO", 0x40020000, 0x1000);
73
74
create_unimplemented_device("SYSCONTROL", 0x50021000, 0x1000);
75
- create_unimplemented_device("S32KWATCHDOG", 0x5002e000, 0x1000);
76
+
38
+
77
+ /* This OR gate wires together outputs from the secure watchdogs to NMI */
39
+ if (!enabled) {
78
+ object_property_set_int(OBJECT(&s->nmi_orgate), 2, "num-lines", &err);
40
+ clock_update(mux->out, 0);
79
+ if (err) {
80
+ error_propagate(errp, err);
81
+ return;
41
+ return;
82
+ }
42
+ }
83
+ object_property_set_bool(OBJECT(&s->nmi_orgate), true, "realized", &err);
43
+
84
+ if (err) {
44
+ freq = clock_get_hz(mux->srcs[src]);
85
+ error_propagate(errp, err);
45
+
46
+ if (mux->int_bits == 0 && mux->frac_bits == 0) {
47
+ clock_update_hz(mux->out, freq);
86
+ return;
48
+ return;
87
+ }
49
+ }
88
+ qdev_connect_gpio_out(DEVICE(&s->nmi_orgate), 0,
89
+ qdev_get_gpio_in_named(DEVICE(&s->armv7m), "NMI", 0));
90
+
50
+
91
+ qdev_prop_set_uint32(DEVICE(&s->s32kwatchdog), "wdogclk-frq", S32KCLK);
51
+ /*
92
+ object_property_set_bool(OBJECT(&s->s32kwatchdog), true, "realized", &err);
52
+ * The divider has an integer and a fractional part. The size of each part
93
+ if (err) {
53
+ * varies with the muxes (int_bits and frac_bits). Both parts are
94
+ error_propagate(errp, err);
54
+ * concatenated, with the integer part always starting at bit 12.
55
+ *
56
+ * 31 12 11 0
57
+ * ------------------------------
58
+ * CM_DIV | | int | frac | |
59
+ * ------------------------------
60
+ * <-----> <------>
61
+ * int_bits frac_bits
62
+ */
63
+ div = extract32(*mux->reg_div,
64
+ R_CM_CLOCKx_DIV_FRAC_LENGTH - mux->frac_bits,
65
+ mux->int_bits + mux->frac_bits);
66
+
67
+ if (!div) {
68
+ clock_update(mux->out, 0);
95
+ return;
69
+ return;
96
+ }
70
+ }
97
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->s32kwatchdog), 0,
71
+
98
+ qdev_get_gpio_in(DEVICE(&s->nmi_orgate), 0));
72
+ freq = muldiv64(freq, 1 << mux->frac_bits, div);
99
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->s32kwatchdog), 0, 0x5002e000);
73
+
100
74
+ clock_update_hz(mux->out, freq);
101
/* 0x40080000 .. 0x4008ffff : IoTKit second Base peripheral region */
75
}
102
76
103
- create_unimplemented_device("NS watchdog", 0x40081000, 0x1000);
77
static void clock_mux_src_update(void *opaque)
104
- create_unimplemented_device("S watchdog", 0x50081000, 0x1000);
78
{
105
+ qdev_prop_set_uint32(DEVICE(&s->nswatchdog), "wdogclk-frq", s->mainclk_frq);
79
CprmanClockMuxState **backref = opaque;
106
+ object_property_set_bool(OBJECT(&s->nswatchdog), true, "realized", &err);
80
CprmanClockMuxState *s = *backref;
107
+ if (err) {
81
+ CprmanClockMuxSource src = backref - s->backref;
108
+ error_propagate(errp, err);
82
+
83
+ if (FIELD_EX32(*s->reg_ctl, CM_CLOCKx_CTL, SRC) != src) {
109
+ return;
84
+ return;
110
+ }
85
+ }
111
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->nswatchdog), 0,
86
112
+ qdev_get_gpio_in(DEVICE(&s->armv7m), 1));
87
clock_mux_update(s);
113
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->nswatchdog), 0, 0x40081000);
88
}
114
+
115
+ qdev_prop_set_uint32(DEVICE(&s->swatchdog), "wdogclk-frq", s->mainclk_frq);
116
+ object_property_set_bool(OBJECT(&s->swatchdog), true, "realized", &err);
117
+ if (err) {
118
+ error_propagate(errp, err);
119
+ return;
120
+ }
121
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->swatchdog), 0,
122
+ qdev_get_gpio_in(DEVICE(&s->nmi_orgate), 1));
123
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->swatchdog), 0, 0x50081000);
124
125
for (i = 0; i < ARRAY_SIZE(s->ppc_irq_splitter); i++) {
126
Object *splitter = OBJECT(&s->ppc_irq_splitter[i]);
127
--
89
--
128
2.18.0
90
2.20.1
129
91
130
92
diff view generated by jsdifflib
1
Refactor bcm2835_fb_mbox_push() to work by calling
1
From: Luc Michel <luc@lmichel.fr>
2
bcm2835_fb_validate_config() and bcm2835_fb_reconfigure(),
2
3
so that config set this way is also validated.
3
This simple mux sits between the PLL channels and the DSI0E and DSI0P
4
4
clock muxes. This mux selects between PLLA-DSI0 and PLLD-DSI0 channel
5
and outputs the selected signal to source number 4 of DSI0E/P clock
6
muxes. It is controlled by the cm_dsi0hsck register.
7
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
10
Signed-off-by: Luc Michel <luc@lmichel.fr>
11
Tested-by: Guenter Roeck <linux@roeck-us.net>
5
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20180814144436.679-9-peter.maydell@linaro.org
8
---
13
---
9
hw/display/bcm2835_fb.c | 63 ++++++++++++++++++++---------------------
14
include/hw/misc/bcm2835_cprman.h | 15 +++++
10
1 file changed, 31 insertions(+), 32 deletions(-)
15
include/hw/misc/bcm2835_cprman_internals.h | 6 ++
11
16
hw/misc/bcm2835_cprman.c | 74 +++++++++++++++++++++-
12
diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c
17
3 files changed, 94 insertions(+), 1 deletion(-)
18
19
diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h
13
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/display/bcm2835_fb.c
21
--- a/include/hw/misc/bcm2835_cprman.h
15
+++ b/hw/display/bcm2835_fb.c
22
+++ b/include/hw/misc/bcm2835_cprman.h
16
@@ -XXX,XX +XXX,XX @@ void bcm2835_fb_validate_config(BCM2835FBConfig *config)
23
@@ -XXX,XX +XXX,XX @@ typedef struct CprmanClockMuxState {
24
struct CprmanClockMuxState *backref[CPRMAN_NUM_CLOCK_MUX_SRC];
25
} CprmanClockMuxState;
26
27
+typedef struct CprmanDsi0HsckMuxState {
28
+ /*< private >*/
29
+ DeviceState parent_obj;
30
+
31
+ /*< public >*/
32
+ CprmanClockMux id;
33
+
34
+ uint32_t *reg_cm;
35
+
36
+ Clock *plla_in;
37
+ Clock *plld_in;
38
+ Clock *out;
39
+} CprmanDsi0HsckMuxState;
40
+
41
struct BCM2835CprmanState {
42
/*< private >*/
43
SysBusDevice parent_obj;
44
@@ -XXX,XX +XXX,XX @@ struct BCM2835CprmanState {
45
CprmanPllState plls[CPRMAN_NUM_PLL];
46
CprmanPllChannelState channels[CPRMAN_NUM_PLL_CHANNEL];
47
CprmanClockMuxState clock_muxes[CPRMAN_NUM_CLOCK_MUX];
48
+ CprmanDsi0HsckMuxState dsi0hsck_mux;
49
50
uint32_t regs[CPRMAN_NUM_REGS];
51
uint32_t xosc_freq;
52
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
53
index XXXXXXX..XXXXXXX 100644
54
--- a/include/hw/misc/bcm2835_cprman_internals.h
55
+++ b/include/hw/misc/bcm2835_cprman_internals.h
56
@@ -XXX,XX +XXX,XX @@
57
#define TYPE_CPRMAN_PLL "bcm2835-cprman-pll"
58
#define TYPE_CPRMAN_PLL_CHANNEL "bcm2835-cprman-pll-channel"
59
#define TYPE_CPRMAN_CLOCK_MUX "bcm2835-cprman-clock-mux"
60
+#define TYPE_CPRMAN_DSI0HSCK_MUX "bcm2835-cprman-dsi0hsck-mux"
61
62
DECLARE_INSTANCE_CHECKER(CprmanPllState, CPRMAN_PLL,
63
TYPE_CPRMAN_PLL)
64
@@ -XXX,XX +XXX,XX @@ DECLARE_INSTANCE_CHECKER(CprmanPllChannelState, CPRMAN_PLL_CHANNEL,
65
TYPE_CPRMAN_PLL_CHANNEL)
66
DECLARE_INSTANCE_CHECKER(CprmanClockMuxState, CPRMAN_CLOCK_MUX,
67
TYPE_CPRMAN_CLOCK_MUX)
68
+DECLARE_INSTANCE_CHECKER(CprmanDsi0HsckMuxState, CPRMAN_DSI0HSCK_MUX,
69
+ TYPE_CPRMAN_DSI0HSCK_MUX)
70
71
/* Register map */
72
73
@@ -XXX,XX +XXX,XX @@ REG32(CM_LOCK, 0x114)
74
FIELD(CM_LOCK, FLOCKB, 9, 1)
75
FIELD(CM_LOCK, FLOCKA, 8, 1)
76
77
+REG32(CM_DSI0HSCK, 0x120)
78
+ FIELD(CM_DSI0HSCK, SELPLLD, 0, 1)
79
+
80
/*
81
* This field is common to all registers. Each register write value must match
82
* the CPRMAN_PASSWORD magic value in its 8 MSB.
83
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
84
index XXXXXXX..XXXXXXX 100644
85
--- a/hw/misc/bcm2835_cprman.c
86
+++ b/hw/misc/bcm2835_cprman.c
87
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_clock_mux_info = {
88
};
89
90
91
+/* DSI0HSCK mux */
92
+
93
+static void dsi0hsck_mux_update(CprmanDsi0HsckMuxState *s)
94
+{
95
+ bool src_is_plld = FIELD_EX32(*s->reg_cm, CM_DSI0HSCK, SELPLLD);
96
+ Clock *src = src_is_plld ? s->plld_in : s->plla_in;
97
+
98
+ clock_update(s->out, clock_get(src));
99
+}
100
+
101
+static void dsi0hsck_mux_in_update(void *opaque)
102
+{
103
+ dsi0hsck_mux_update(CPRMAN_DSI0HSCK_MUX(opaque));
104
+}
105
+
106
+static void dsi0hsck_mux_init(Object *obj)
107
+{
108
+ CprmanDsi0HsckMuxState *s = CPRMAN_DSI0HSCK_MUX(obj);
109
+ DeviceState *dev = DEVICE(obj);
110
+
111
+ s->plla_in = qdev_init_clock_in(dev, "plla-in", dsi0hsck_mux_in_update, s);
112
+ s->plld_in = qdev_init_clock_in(dev, "plld-in", dsi0hsck_mux_in_update, s);
113
+ s->out = qdev_init_clock_out(DEVICE(s), "out");
114
+}
115
+
116
+static const VMStateDescription dsi0hsck_mux_vmstate = {
117
+ .name = TYPE_CPRMAN_DSI0HSCK_MUX,
118
+ .version_id = 1,
119
+ .minimum_version_id = 1,
120
+ .fields = (VMStateField[]) {
121
+ VMSTATE_CLOCK(plla_in, CprmanDsi0HsckMuxState),
122
+ VMSTATE_CLOCK(plld_in, CprmanDsi0HsckMuxState),
123
+ VMSTATE_END_OF_LIST()
124
+ }
125
+};
126
+
127
+static void dsi0hsck_mux_class_init(ObjectClass *klass, void *data)
128
+{
129
+ DeviceClass *dc = DEVICE_CLASS(klass);
130
+
131
+ dc->vmsd = &dsi0hsck_mux_vmstate;
132
+}
133
+
134
+static const TypeInfo cprman_dsi0hsck_mux_info = {
135
+ .name = TYPE_CPRMAN_DSI0HSCK_MUX,
136
+ .parent = TYPE_DEVICE,
137
+ .instance_size = sizeof(CprmanDsi0HsckMuxState),
138
+ .class_init = dsi0hsck_mux_class_init,
139
+ .instance_init = dsi0hsck_mux_init,
140
+};
141
+
142
+
143
/* CPRMAN "top level" model */
144
145
static uint32_t get_cm_lock(const BCM2835CprmanState *s)
146
@@ -XXX,XX +XXX,XX @@ static void cprman_write(void *opaque, hwaddr offset,
147
case R_CM_EMMC2CTL ... R_CM_EMMC2DIV:
148
update_mux_from_cm(s, idx);
149
break;
150
+
151
+ case R_CM_DSI0HSCK:
152
+ dsi0hsck_mux_update(&s->dsi0hsck_mux);
153
+ break;
17
}
154
}
18
}
155
}
19
156
20
-static void bcm2835_fb_mbox_push(BCM2835FBState *s, uint32_t value)
157
@@ -XXX,XX +XXX,XX @@ static void cprman_reset(DeviceState *dev)
21
-{
158
device_cold_reset(DEVICE(&s->channels[i]));
22
- uint32_t pitch;
159
}
23
- uint32_t size;
160
24
-
161
+ device_cold_reset(DEVICE(&s->dsi0hsck_mux));
25
- value &= ~0xf;
162
+
26
-
163
for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
27
- s->lock = true;
164
device_cold_reset(DEVICE(&s->clock_muxes[i]));
28
-
165
}
29
- s->config.xres = ldl_le_phys(&s->dma_as, value);
166
@@ -XXX,XX +XXX,XX @@ static void cprman_init(Object *obj)
30
- s->config.yres = ldl_le_phys(&s->dma_as, value + 4);
167
set_pll_channel_init_info(s, &s->channels[i], i);
31
- s->config.xres_virtual = ldl_le_phys(&s->dma_as, value + 8);
168
}
32
- s->config.yres_virtual = ldl_le_phys(&s->dma_as, value + 12);
169
33
- s->config.bpp = ldl_le_phys(&s->dma_as, value + 20);
170
+ object_initialize_child(obj, "dsi0hsck-mux",
34
- s->config.xoffset = ldl_le_phys(&s->dma_as, value + 24);
171
+ &s->dsi0hsck_mux, TYPE_CPRMAN_DSI0HSCK_MUX);
35
- s->config.yoffset = ldl_le_phys(&s->dma_as, value + 28);
172
+ s->dsi0hsck_mux.reg_cm = &s->regs[R_CM_DSI0HSCK];
36
-
173
+
37
- s->config.base = s->vcram_base | (value & 0xc0000000);
174
for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
38
- s->config.base += BCM2835_FB_OFFSET;
175
char *alias;
39
-
176
40
- pitch = bcm2835_fb_get_pitch(&s->config);
177
@@ -XXX,XX +XXX,XX @@ static void connect_mux_sources(BCM2835CprmanState *s,
41
- size = bcm2835_fb_get_size(&s->config);
178
if (mapping == CPRMAN_CLOCK_SRC_FORCE_GROUND) {
42
-
179
src = s->gnd;
43
- stl_le_phys(&s->dma_as, value + 16, pitch);
180
} else if (mapping == CPRMAN_CLOCK_SRC_DSI0HSCK) {
44
- stl_le_phys(&s->dma_as, value + 32, s->config.base);
181
- src = s->gnd; /* TODO */
45
- stl_le_phys(&s->dma_as, value + 36, size);
182
+ src = s->dsi0hsck_mux.out;
46
-
183
} else if (i < CPRMAN_CLOCK_SRC_PLLA) {
47
- s->invalidate = true;
184
src = CLK_SRC_MAPPING[i];
48
- qemu_console_resize(s->con, s->config.xres, s->config.yres);
185
} else {
49
- s->lock = false;
186
@@ -XXX,XX +XXX,XX @@ static void cprman_realize(DeviceState *dev, Error **errp)
50
-}
187
}
51
-
188
}
52
void bcm2835_fb_reconfigure(BCM2835FBState *s, BCM2835FBConfig *newconfig)
189
53
{
190
+ clock_set_source(s->dsi0hsck_mux.plla_in,
54
s->lock = true;
191
+ s->channels[CPRMAN_PLLA_CHANNEL_DSI0].out);
55
@@ -XXX,XX +XXX,XX @@ void bcm2835_fb_reconfigure(BCM2835FBState *s, BCM2835FBConfig *newconfig)
192
+ clock_set_source(s->dsi0hsck_mux.plld_in,
56
s->lock = false;
193
+ s->channels[CPRMAN_PLLD_CHANNEL_DSI0].out);
194
+
195
+ if (!qdev_realize(DEVICE(&s->dsi0hsck_mux), NULL, errp)) {
196
+ return;
197
+ }
198
+
199
for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
200
CprmanClockMuxState *clock_mux = &s->clock_muxes[i];
201
202
@@ -XXX,XX +XXX,XX @@ static void cprman_register_types(void)
203
type_register_static(&cprman_pll_info);
204
type_register_static(&cprman_pll_channel_info);
205
type_register_static(&cprman_clock_mux_info);
206
+ type_register_static(&cprman_dsi0hsck_mux_info);
57
}
207
}
58
208
59
+static void bcm2835_fb_mbox_push(BCM2835FBState *s, uint32_t value)
209
type_init(cprman_register_types);
60
+{
61
+ uint32_t pitch;
62
+ uint32_t size;
63
+ BCM2835FBConfig newconf;
64
+
65
+ value &= ~0xf;
66
+
67
+ newconf.xres = ldl_le_phys(&s->dma_as, value);
68
+ newconf.yres = ldl_le_phys(&s->dma_as, value + 4);
69
+ newconf.xres_virtual = ldl_le_phys(&s->dma_as, value + 8);
70
+ newconf.yres_virtual = ldl_le_phys(&s->dma_as, value + 12);
71
+ newconf.bpp = ldl_le_phys(&s->dma_as, value + 20);
72
+ newconf.xoffset = ldl_le_phys(&s->dma_as, value + 24);
73
+ newconf.yoffset = ldl_le_phys(&s->dma_as, value + 28);
74
+
75
+ newconf.base = s->vcram_base | (value & 0xc0000000);
76
+ newconf.base += BCM2835_FB_OFFSET;
77
+
78
+ bcm2835_fb_validate_config(&newconf);
79
+
80
+ pitch = bcm2835_fb_get_pitch(&newconf);
81
+ size = bcm2835_fb_get_size(&newconf);
82
+
83
+ stl_le_phys(&s->dma_as, value + 16, pitch);
84
+ stl_le_phys(&s->dma_as, value + 32, newconf.base);
85
+ stl_le_phys(&s->dma_as, value + 36, size);
86
+
87
+ bcm2835_fb_reconfigure(s, &newconf);
88
+}
89
+
90
static uint64_t bcm2835_fb_read(void *opaque, hwaddr offset, unsigned size)
91
{
92
BCM2835FBState *s = opaque;
93
--
210
--
94
2.18.0
211
2.20.1
95
212
96
213
diff view generated by jsdifflib
1
Abstract out the calculation of the pitch and size of the
1
From: Luc Michel <luc@lmichel.fr>
2
framebuffer into functions that operate on the BCM2835FBConfig
2
3
struct -- these are about to get a little more complicated
3
Those reset values have been extracted from a Raspberry Pi 3 model B
4
when we add support for virtual and physical sizes differing.
4
v1.2, using the 2020-08-20 version of raspios. The dump was done using
5
5
the debugfs interface of the CPRMAN driver in Linux (under
6
'/sys/kernel/debug/clk'). Each exposed clock tree stage (PLLs, channels
7
and muxes) can be observed by reading the 'regdump' file (e.g.
8
'plla/regdump').
9
10
Those values are set by the Raspberry Pi firmware at boot time (Linux
11
expects them to be set when it boots up).
12
13
Some stages are not exposed by the Linux driver (e.g. the PLL B). For
14
those, the reset values are unknown and left to 0 which implies a
15
disabled output.
16
17
Once booted in QEMU, the final clock tree is very similar to the one
18
visible on real hardware. The differences come from some unimplemented
19
devices for which the driver simply disable the corresponding clock.
20
21
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
22
Signed-off-by: Luc Michel <luc@lmichel.fr>
23
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
24
Tested-by: Guenter Roeck <linux@roeck-us.net>
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
25
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
8
Message-id: 20180814144436.679-6-peter.maydell@linaro.org
9
---
26
---
10
include/hw/display/bcm2835_fb.h | 22 ++++++++++++++++++++++
27
include/hw/misc/bcm2835_cprman_internals.h | 269 +++++++++++++++++++++
11
hw/display/bcm2835_fb.c | 6 +++---
28
hw/misc/bcm2835_cprman.c | 31 +++
12
hw/misc/bcm2835_property.c | 4 ++--
29
2 files changed, 300 insertions(+)
13
3 files changed, 27 insertions(+), 5 deletions(-)
30
14
31
diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
15
diff --git a/include/hw/display/bcm2835_fb.h b/include/hw/display/bcm2835_fb.h
16
index XXXXXXX..XXXXXXX 100644
32
index XXXXXXX..XXXXXXX 100644
17
--- a/include/hw/display/bcm2835_fb.h
33
--- a/include/hw/misc/bcm2835_cprman_internals.h
18
+++ b/include/hw/display/bcm2835_fb.h
34
+++ b/include/hw/misc/bcm2835_cprman_internals.h
19
@@ -XXX,XX +XXX,XX @@ typedef struct {
35
@@ -XXX,XX +XXX,XX @@ static inline void set_clock_mux_init_info(BCM2835CprmanState *s,
20
36
mux->frac_bits = CLOCK_MUX_INIT_INFO[id].frac_bits;
21
void bcm2835_fb_reconfigure(BCM2835FBState *s, BCM2835FBConfig *newconfig);
37
}
22
38
23
+/**
39
+
24
+ * bcm2835_fb_get_pitch: return number of bytes per line of the framebuffer
40
+/*
25
+ * @config: configuration info for the framebuffer
41
+ * Object reset info
26
+ *
42
+ * Those values have been dumped from a Raspberry Pi 3 Model B v1.2 using the
27
+ * Return the number of bytes per line of the framebuffer, ie the number
43
+ * clk debugfs interface in Linux.
28
+ * that must be added to a pixel address to get the address of the pixel
29
+ * directly below it on screen.
30
+ */
44
+ */
31
+static inline uint32_t bcm2835_fb_get_pitch(BCM2835FBConfig *config)
45
+typedef struct PLLResetInfo {
46
+ uint32_t cm;
47
+ uint32_t a2w_ctrl;
48
+ uint32_t a2w_ana[4];
49
+ uint32_t a2w_frac;
50
+} PLLResetInfo;
51
+
52
+static const PLLResetInfo PLL_RESET_INFO[] = {
53
+ [CPRMAN_PLLA] = {
54
+ .cm = 0x0000008a,
55
+ .a2w_ctrl = 0x0002103a,
56
+ .a2w_frac = 0x00098000,
57
+ .a2w_ana = { 0x00000000, 0x00144000, 0x00000000, 0x00000100 }
58
+ },
59
+
60
+ [CPRMAN_PLLC] = {
61
+ .cm = 0x00000228,
62
+ .a2w_ctrl = 0x0002103e,
63
+ .a2w_frac = 0x00080000,
64
+ .a2w_ana = { 0x00000000, 0x00144000, 0x00000000, 0x00000100 }
65
+ },
66
+
67
+ [CPRMAN_PLLD] = {
68
+ .cm = 0x0000020a,
69
+ .a2w_ctrl = 0x00021034,
70
+ .a2w_frac = 0x00015556,
71
+ .a2w_ana = { 0x00000000, 0x00144000, 0x00000000, 0x00000100 }
72
+ },
73
+
74
+ [CPRMAN_PLLH] = {
75
+ .cm = 0x00000000,
76
+ .a2w_ctrl = 0x0002102d,
77
+ .a2w_frac = 0x00000000,
78
+ .a2w_ana = { 0x00900000, 0x0000000c, 0x00000000, 0x00000000 }
79
+ },
80
+
81
+ [CPRMAN_PLLB] = {
82
+ /* unknown */
83
+ .cm = 0x00000000,
84
+ .a2w_ctrl = 0x00000000,
85
+ .a2w_frac = 0x00000000,
86
+ .a2w_ana = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }
87
+ }
88
+};
89
+
90
+typedef struct PLLChannelResetInfo {
91
+ /*
92
+ * Even though a PLL channel has a CM register, it shares it with its
93
+ * parent PLL. The parent already takes care of the reset value.
94
+ */
95
+ uint32_t a2w_ctrl;
96
+} PLLChannelResetInfo;
97
+
98
+static const PLLChannelResetInfo PLL_CHANNEL_RESET_INFO[] = {
99
+ [CPRMAN_PLLA_CHANNEL_DSI0] = { .a2w_ctrl = 0x00000100 },
100
+ [CPRMAN_PLLA_CHANNEL_CORE] = { .a2w_ctrl = 0x00000003 },
101
+ [CPRMAN_PLLA_CHANNEL_PER] = { .a2w_ctrl = 0x00000000 }, /* unknown */
102
+ [CPRMAN_PLLA_CHANNEL_CCP2] = { .a2w_ctrl = 0x00000100 },
103
+
104
+ [CPRMAN_PLLC_CHANNEL_CORE2] = { .a2w_ctrl = 0x00000100 },
105
+ [CPRMAN_PLLC_CHANNEL_CORE1] = { .a2w_ctrl = 0x00000100 },
106
+ [CPRMAN_PLLC_CHANNEL_PER] = { .a2w_ctrl = 0x00000002 },
107
+ [CPRMAN_PLLC_CHANNEL_CORE0] = { .a2w_ctrl = 0x00000002 },
108
+
109
+ [CPRMAN_PLLD_CHANNEL_DSI0] = { .a2w_ctrl = 0x00000100 },
110
+ [CPRMAN_PLLD_CHANNEL_CORE] = { .a2w_ctrl = 0x00000004 },
111
+ [CPRMAN_PLLD_CHANNEL_PER] = { .a2w_ctrl = 0x00000004 },
112
+ [CPRMAN_PLLD_CHANNEL_DSI1] = { .a2w_ctrl = 0x00000100 },
113
+
114
+ [CPRMAN_PLLH_CHANNEL_AUX] = { .a2w_ctrl = 0x00000004 },
115
+ [CPRMAN_PLLH_CHANNEL_RCAL] = { .a2w_ctrl = 0x00000000 },
116
+ [CPRMAN_PLLH_CHANNEL_PIX] = { .a2w_ctrl = 0x00000000 },
117
+
118
+ [CPRMAN_PLLB_CHANNEL_ARM] = { .a2w_ctrl = 0x00000000 }, /* unknown */
119
+};
120
+
121
+typedef struct ClockMuxResetInfo {
122
+ uint32_t cm_ctl;
123
+ uint32_t cm_div;
124
+} ClockMuxResetInfo;
125
+
126
+static const ClockMuxResetInfo CLOCK_MUX_RESET_INFO[] = {
127
+ [CPRMAN_CLOCK_GNRIC] = {
128
+ .cm_ctl = 0, /* unknown */
129
+ .cm_div = 0
130
+ },
131
+
132
+ [CPRMAN_CLOCK_VPU] = {
133
+ .cm_ctl = 0x00000245,
134
+ .cm_div = 0x00003000,
135
+ },
136
+
137
+ [CPRMAN_CLOCK_SYS] = {
138
+ .cm_ctl = 0, /* unknown */
139
+ .cm_div = 0
140
+ },
141
+
142
+ [CPRMAN_CLOCK_PERIA] = {
143
+ .cm_ctl = 0, /* unknown */
144
+ .cm_div = 0
145
+ },
146
+
147
+ [CPRMAN_CLOCK_PERII] = {
148
+ .cm_ctl = 0, /* unknown */
149
+ .cm_div = 0
150
+ },
151
+
152
+ [CPRMAN_CLOCK_H264] = {
153
+ .cm_ctl = 0x00000244,
154
+ .cm_div = 0x00003000,
155
+ },
156
+
157
+ [CPRMAN_CLOCK_ISP] = {
158
+ .cm_ctl = 0x00000244,
159
+ .cm_div = 0x00003000,
160
+ },
161
+
162
+ [CPRMAN_CLOCK_V3D] = {
163
+ .cm_ctl = 0, /* unknown */
164
+ .cm_div = 0
165
+ },
166
+
167
+ [CPRMAN_CLOCK_CAM0] = {
168
+ .cm_ctl = 0x00000000,
169
+ .cm_div = 0x00000000,
170
+ },
171
+
172
+ [CPRMAN_CLOCK_CAM1] = {
173
+ .cm_ctl = 0x00000000,
174
+ .cm_div = 0x00000000,
175
+ },
176
+
177
+ [CPRMAN_CLOCK_CCP2] = {
178
+ .cm_ctl = 0, /* unknown */
179
+ .cm_div = 0
180
+ },
181
+
182
+ [CPRMAN_CLOCK_DSI0E] = {
183
+ .cm_ctl = 0x00000000,
184
+ .cm_div = 0x00000000,
185
+ },
186
+
187
+ [CPRMAN_CLOCK_DSI0P] = {
188
+ .cm_ctl = 0x00000000,
189
+ .cm_div = 0x00000000,
190
+ },
191
+
192
+ [CPRMAN_CLOCK_DPI] = {
193
+ .cm_ctl = 0x00000000,
194
+ .cm_div = 0x00000000,
195
+ },
196
+
197
+ [CPRMAN_CLOCK_GP0] = {
198
+ .cm_ctl = 0x00000200,
199
+ .cm_div = 0x00000000,
200
+ },
201
+
202
+ [CPRMAN_CLOCK_GP1] = {
203
+ .cm_ctl = 0x00000096,
204
+ .cm_div = 0x00014000,
205
+ },
206
+
207
+ [CPRMAN_CLOCK_GP2] = {
208
+ .cm_ctl = 0x00000291,
209
+ .cm_div = 0x00249f00,
210
+ },
211
+
212
+ [CPRMAN_CLOCK_HSM] = {
213
+ .cm_ctl = 0x00000000,
214
+ .cm_div = 0x00000000,
215
+ },
216
+
217
+ [CPRMAN_CLOCK_OTP] = {
218
+ .cm_ctl = 0x00000091,
219
+ .cm_div = 0x00004000,
220
+ },
221
+
222
+ [CPRMAN_CLOCK_PCM] = {
223
+ .cm_ctl = 0x00000200,
224
+ .cm_div = 0x00000000,
225
+ },
226
+
227
+ [CPRMAN_CLOCK_PWM] = {
228
+ .cm_ctl = 0x00000200,
229
+ .cm_div = 0x00000000,
230
+ },
231
+
232
+ [CPRMAN_CLOCK_SLIM] = {
233
+ .cm_ctl = 0x00000200,
234
+ .cm_div = 0x00000000,
235
+ },
236
+
237
+ [CPRMAN_CLOCK_SMI] = {
238
+ .cm_ctl = 0x00000000,
239
+ .cm_div = 0x00000000,
240
+ },
241
+
242
+ [CPRMAN_CLOCK_TEC] = {
243
+ .cm_ctl = 0x00000000,
244
+ .cm_div = 0x00000000,
245
+ },
246
+
247
+ [CPRMAN_CLOCK_TD0] = {
248
+ .cm_ctl = 0, /* unknown */
249
+ .cm_div = 0
250
+ },
251
+
252
+ [CPRMAN_CLOCK_TD1] = {
253
+ .cm_ctl = 0, /* unknown */
254
+ .cm_div = 0
255
+ },
256
+
257
+ [CPRMAN_CLOCK_TSENS] = {
258
+ .cm_ctl = 0x00000091,
259
+ .cm_div = 0x0000a000,
260
+ },
261
+
262
+ [CPRMAN_CLOCK_TIMER] = {
263
+ .cm_ctl = 0x00000291,
264
+ .cm_div = 0x00013333,
265
+ },
266
+
267
+ [CPRMAN_CLOCK_UART] = {
268
+ .cm_ctl = 0x00000296,
269
+ .cm_div = 0x0000a6ab,
270
+ },
271
+
272
+ [CPRMAN_CLOCK_VEC] = {
273
+ .cm_ctl = 0x00000097,
274
+ .cm_div = 0x00002000,
275
+ },
276
+
277
+ [CPRMAN_CLOCK_PULSE] = {
278
+ .cm_ctl = 0, /* unknown */
279
+ .cm_div = 0
280
+ },
281
+
282
+ [CPRMAN_CLOCK_SDC] = {
283
+ .cm_ctl = 0x00004006,
284
+ .cm_div = 0x00003000,
285
+ },
286
+
287
+ [CPRMAN_CLOCK_ARM] = {
288
+ .cm_ctl = 0, /* unknown */
289
+ .cm_div = 0
290
+ },
291
+
292
+ [CPRMAN_CLOCK_AVEO] = {
293
+ .cm_ctl = 0x00000000,
294
+ .cm_div = 0x00000000,
295
+ },
296
+
297
+ [CPRMAN_CLOCK_EMMC] = {
298
+ .cm_ctl = 0x00000295,
299
+ .cm_div = 0x00006000,
300
+ },
301
+
302
+ [CPRMAN_CLOCK_EMMC2] = {
303
+ .cm_ctl = 0, /* unknown */
304
+ .cm_div = 0
305
+ },
306
+};
307
+
308
#endif
309
diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
310
index XXXXXXX..XXXXXXX 100644
311
--- a/hw/misc/bcm2835_cprman.c
312
+++ b/hw/misc/bcm2835_cprman.c
313
@@ -XXX,XX +XXX,XX @@
314
315
/* PLL */
316
317
+static void pll_reset(DeviceState *dev)
32
+{
318
+{
33
+ return config->xres * (config->bpp >> 3);
319
+ CprmanPllState *s = CPRMAN_PLL(dev);
320
+ const PLLResetInfo *info = &PLL_RESET_INFO[s->id];
321
+
322
+ *s->reg_cm = info->cm;
323
+ *s->reg_a2w_ctrl = info->a2w_ctrl;
324
+ memcpy(s->reg_a2w_ana, info->a2w_ana, sizeof(info->a2w_ana));
325
+ *s->reg_a2w_frac = info->a2w_frac;
34
+}
326
+}
35
+
327
+
36
+/**
328
static bool pll_is_locked(const CprmanPllState *pll)
37
+ * bcm2835_fb_get_size: return total size of framebuffer in bytes
329
{
38
+ * @config: configuration info for the framebuffer
330
return !FIELD_EX32(*pll->reg_a2w_ctrl, A2W_PLLx_CTRL, PWRDN)
39
+ */
331
@@ -XXX,XX +XXX,XX @@ static void pll_class_init(ObjectClass *klass, void *data)
40
+static inline uint32_t bcm2835_fb_get_size(BCM2835FBConfig *config)
332
{
333
DeviceClass *dc = DEVICE_CLASS(klass);
334
335
+ dc->reset = pll_reset;
336
dc->vmsd = &pll_vmstate;
337
}
338
339
@@ -XXX,XX +XXX,XX @@ static const TypeInfo cprman_pll_info = {
340
341
/* PLL channel */
342
343
+static void pll_channel_reset(DeviceState *dev)
41
+{
344
+{
42
+ return config->yres * bcm2835_fb_get_pitch(config);
345
+ CprmanPllChannelState *s = CPRMAN_PLL_CHANNEL(dev);
346
+ const PLLChannelResetInfo *info = &PLL_CHANNEL_RESET_INFO[s->id];
347
+
348
+ *s->reg_a2w_ctrl = info->a2w_ctrl;
43
+}
349
+}
44
+
350
+
45
#endif
351
static bool pll_channel_is_enabled(CprmanPllChannelState *channel)
46
diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c
352
{
47
index XXXXXXX..XXXXXXX 100644
353
/*
48
--- a/hw/display/bcm2835_fb.c
354
@@ -XXX,XX +XXX,XX @@ static void pll_channel_class_init(ObjectClass *klass, void *data)
49
+++ b/hw/display/bcm2835_fb.c
355
{
50
@@ -XXX,XX +XXX,XX @@ static void fb_update_display(void *opaque)
356
DeviceClass *dc = DEVICE_CLASS(klass);
51
return;
357
52
}
358
+ dc->reset = pll_channel_reset;
53
359
dc->vmsd = &pll_channel_vmstate;
54
- src_width = s->config.xres * (s->config.bpp >> 3);
360
}
55
+ src_width = bcm2835_fb_get_pitch(&s->config);
361
56
dest_width = s->config.xres;
362
@@ -XXX,XX +XXX,XX @@ static void clock_mux_src_update(void *opaque)
57
363
clock_mux_update(s);
58
switch (surface_bits_per_pixel(surface)) {
364
}
59
@@ -XXX,XX +XXX,XX @@ static void bcm2835_fb_mbox_push(BCM2835FBState *s, uint32_t value)
365
60
366
+static void clock_mux_reset(DeviceState *dev)
61
/* TODO - Manage properly virtual resolution */
367
+{
62
368
+ CprmanClockMuxState *clock = CPRMAN_CLOCK_MUX(dev);
63
- pitch = s->config.xres * (s->config.bpp >> 3);
369
+ const ClockMuxResetInfo *info = &CLOCK_MUX_RESET_INFO[clock->id];
64
- size = s->config.yres * pitch;
370
+
65
+ pitch = bcm2835_fb_get_pitch(&s->config);
371
+ *clock->reg_ctl = info->cm_ctl;
66
+ size = bcm2835_fb_get_size(&s->config);
372
+ *clock->reg_div = info->cm_div;
67
373
+}
68
stl_le_phys(&s->dma_as, value + 16, pitch);
374
+
69
stl_le_phys(&s->dma_as, value + 32, s->config.base);
375
static void clock_mux_init(Object *obj)
70
diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c
376
{
71
index XXXXXXX..XXXXXXX 100644
377
CprmanClockMuxState *s = CPRMAN_CLOCK_MUX(obj);
72
--- a/hw/misc/bcm2835_property.c
378
@@ -XXX,XX +XXX,XX @@ static void clock_mux_class_init(ObjectClass *klass, void *data)
73
+++ b/hw/misc/bcm2835_property.c
379
{
74
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
380
DeviceClass *dc = DEVICE_CLASS(klass);
75
case 0x00040001: /* Allocate buffer */
381
76
stl_le_phys(&s->dma_as, value + 12, fbconfig.base);
382
+ dc->reset = clock_mux_reset;
77
stl_le_phys(&s->dma_as, value + 16,
383
dc->vmsd = &clock_mux_vmstate;
78
- fbconfig.xres * fbconfig.yres * fbconfig.bpp / 8);
384
}
79
+ bcm2835_fb_get_size(&fbconfig));
385
80
resplen = 8;
81
break;
82
case 0x00048001: /* Release buffer */
83
@@ -XXX,XX +XXX,XX @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
84
break;
85
case 0x00040008: /* Get pitch */
86
stl_le_phys(&s->dma_as, value + 12,
87
- fbconfig.xres * fbconfig.bpp / 8);
88
+ bcm2835_fb_get_pitch(&fbconfig));
89
resplen = 4;
90
break;
91
case 0x00040009: /* Get virtual offset */
92
--
386
--
93
2.18.0
387
2.20.1
94
388
95
389
diff view generated by jsdifflib
1
The MPS2 FPGAIO block includes some simple free-running counters.
1
From: Luc Michel <luc@lmichel.fr>
2
Implement these.
3
2
3
Add a clock input to the PL011 UART so we can compute the current baud
4
rate and trace it. This is intended for developers who wish to use QEMU
5
to e.g. debug their firmware or to figure out the baud rate configured
6
by an unknown/closed source binary.
7
8
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Signed-off-by: Luc Michel <luc@lmichel.fr>
10
Tested-by: Guenter Roeck <linux@roeck-us.net>
11
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
6
Message-id: 20180820141116.9118-2-peter.maydell@linaro.org
7
---
13
---
8
include/hw/misc/mps2-fpgaio.h | 4 +++
14
include/hw/char/pl011.h | 1 +
9
hw/misc/mps2-fpgaio.c | 53 ++++++++++++++++++++++++++++++++++-
15
hw/char/pl011.c | 45 +++++++++++++++++++++++++++++++++++++++++
10
2 files changed, 56 insertions(+), 1 deletion(-)
16
hw/char/trace-events | 1 +
17
3 files changed, 47 insertions(+)
11
18
12
diff --git a/include/hw/misc/mps2-fpgaio.h b/include/hw/misc/mps2-fpgaio.h
19
diff --git a/include/hw/char/pl011.h b/include/hw/char/pl011.h
13
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
14
--- a/include/hw/misc/mps2-fpgaio.h
21
--- a/include/hw/char/pl011.h
15
+++ b/include/hw/misc/mps2-fpgaio.h
22
+++ b/include/hw/char/pl011.h
16
@@ -XXX,XX +XXX,XX @@ typedef struct {
23
@@ -XXX,XX +XXX,XX @@ struct PL011State {
17
uint32_t misc;
24
int read_trigger;
18
25
CharBackend chr;
19
uint32_t prescale_clk;
26
qemu_irq irq[6];
27
+ Clock *clk;
28
const unsigned char *id;
29
};
30
31
diff --git a/hw/char/pl011.c b/hw/char/pl011.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/hw/char/pl011.c
34
+++ b/hw/char/pl011.c
35
@@ -XXX,XX +XXX,XX @@
36
#include "hw/char/pl011.h"
37
#include "hw/irq.h"
38
#include "hw/sysbus.h"
39
+#include "hw/qdev-clock.h"
40
#include "migration/vmstate.h"
41
#include "chardev/char-fe.h"
42
#include "qemu/log.h"
43
@@ -XXX,XX +XXX,XX @@ static void pl011_set_read_trigger(PL011State *s)
44
s->read_trigger = 1;
45
}
46
47
+static unsigned int pl011_get_baudrate(const PL011State *s)
48
+{
49
+ uint64_t clk;
20
+
50
+
21
+ /* These hold the CLOCK_VIRTUAL ns tick when the CLK1HZ/CLK100HZ was zero */
51
+ if (s->fbrd == 0) {
22
+ int64_t clk1hz_tick_offset;
52
+ return 0;
23
+ int64_t clk100hz_tick_offset;
53
+ }
24
} MPS2FPGAIO;
54
+
25
55
+ clk = clock_get_hz(s->clk);
26
#endif
56
+ return (clk / ((s->ibrd << 6) + s->fbrd)) << 2;
27
diff --git a/hw/misc/mps2-fpgaio.c b/hw/misc/mps2-fpgaio.c
28
index XXXXXXX..XXXXXXX 100644
29
--- a/hw/misc/mps2-fpgaio.c
30
+++ b/hw/misc/mps2-fpgaio.c
31
@@ -XXX,XX +XXX,XX @@
32
#include "hw/sysbus.h"
33
#include "hw/registerfields.h"
34
#include "hw/misc/mps2-fpgaio.h"
35
+#include "qemu/timer.h"
36
37
REG32(LED0, 0)
38
REG32(BUTTON, 8)
39
@@ -XXX,XX +XXX,XX @@ REG32(PRESCALE, 0x1c)
40
REG32(PSCNTR, 0x20)
41
REG32(MISC, 0x4c)
42
43
+static uint32_t counter_from_tickoff(int64_t now, int64_t tick_offset, int frq)
44
+{
45
+ return muldiv64(now - tick_offset, frq, NANOSECONDS_PER_SECOND);
46
+}
57
+}
47
+
58
+
48
+static int64_t tickoff_from_counter(int64_t now, uint32_t count, int frq)
59
+static void pl011_trace_baudrate_change(const PL011State *s)
49
+{
60
+{
50
+ return now - muldiv64(count, NANOSECONDS_PER_SECOND, frq);
61
+ trace_pl011_baudrate_change(pl011_get_baudrate(s),
62
+ clock_get_hz(s->clk),
63
+ s->ibrd, s->fbrd);
51
+}
64
+}
52
+
65
+
53
static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size)
66
static void pl011_write(void *opaque, hwaddr offset,
67
uint64_t value, unsigned size)
54
{
68
{
55
MPS2FPGAIO *s = MPS2_FPGAIO(opaque);
69
@@ -XXX,XX +XXX,XX @@ static void pl011_write(void *opaque, hwaddr offset,
56
uint64_t r;
57
+ int64_t now;
58
59
switch (offset) {
60
case A_LED0:
61
@@ -XXX,XX +XXX,XX @@ static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size)
62
r = s->misc;
63
break;
70
break;
64
case A_CLK1HZ:
71
case 9: /* UARTIBRD */
65
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
72
s->ibrd = value;
66
+ r = counter_from_tickoff(now, s->clk1hz_tick_offset, 1);
73
+ pl011_trace_baudrate_change(s);
67
+ break;
68
case A_CLK100HZ:
69
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
70
+ r = counter_from_tickoff(now, s->clk100hz_tick_offset, 100);
71
+ break;
72
case A_COUNTER:
73
case A_PSCNTR:
74
- /* These are all upcounters of various frequencies. */
75
qemu_log_mask(LOG_UNIMP, "MPS2 FPGAIO: counters unimplemented\n");
76
r = 0;
77
break;
74
break;
78
@@ -XXX,XX +XXX,XX @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value,
75
case 10: /* UARTFBRD */
79
unsigned size)
76
s->fbrd = value;
80
{
77
+ pl011_trace_baudrate_change(s);
81
MPS2FPGAIO *s = MPS2_FPGAIO(opaque);
82
+ int64_t now;
83
84
trace_mps2_fpgaio_write(offset, value, size);
85
86
@@ -XXX,XX +XXX,XX @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value,
87
"MPS2 FPGAIO: MISC control bits unimplemented\n");
88
s->misc = value;
89
break;
78
break;
90
+ case A_CLK1HZ:
79
case 11: /* UARTLCR_H */
91
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
80
/* Reset the FIFO state on FIFO enable or disable */
92
+ s->clk1hz_tick_offset = tickoff_from_counter(now, value, 1);
81
@@ -XXX,XX +XXX,XX @@ static void pl011_event(void *opaque, QEMUChrEvent event)
93
+ break;
82
pl011_put_fifo(opaque, 0x400);
94
+ case A_CLK100HZ:
95
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
96
+ s->clk100hz_tick_offset = tickoff_from_counter(now, value, 100);
97
+ break;
98
default:
99
qemu_log_mask(LOG_GUEST_ERROR,
100
"MPS2 FPGAIO write: bad offset 0x%x\n", (int) offset);
101
@@ -XXX,XX +XXX,XX @@ static const MemoryRegionOps mps2_fpgaio_ops = {
102
static void mps2_fpgaio_reset(DeviceState *dev)
103
{
104
MPS2FPGAIO *s = MPS2_FPGAIO(dev);
105
+ int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
106
107
trace_mps2_fpgaio_reset();
108
s->led0 = 0;
109
s->prescale = 0;
110
s->misc = 0;
111
+ s->clk1hz_tick_offset = tickoff_from_counter(now, 0, 1);
112
+ s->clk100hz_tick_offset = tickoff_from_counter(now, 0, 100);
113
}
83
}
114
84
115
static void mps2_fpgaio_init(Object *obj)
85
+static void pl011_clock_update(void *opaque)
116
@@ -XXX,XX +XXX,XX @@ static void mps2_fpgaio_init(Object *obj)
117
sysbus_init_mmio(sbd, &s->iomem);
118
}
119
120
+static bool mps2_fpgaio_counters_needed(void *opaque)
121
+{
86
+{
122
+ /* Currently vmstate.c insists all subsections have a 'needed' function */
87
+ PL011State *s = PL011(opaque);
123
+ return true;
88
+
89
+ pl011_trace_baudrate_change(s);
124
+}
90
+}
125
+
91
+
126
+static const VMStateDescription mps2_fpgaio_counters_vmstate = {
92
static const MemoryRegionOps pl011_ops = {
127
+ .name = "mps2-fpgaio/counters",
93
.read = pl011_read,
94
.write = pl011_write,
95
.endianness = DEVICE_NATIVE_ENDIAN,
96
};
97
98
+static const VMStateDescription vmstate_pl011_clock = {
99
+ .name = "pl011/clock",
128
+ .version_id = 1,
100
+ .version_id = 1,
129
+ .minimum_version_id = 1,
101
+ .minimum_version_id = 1,
130
+ .needed = mps2_fpgaio_counters_needed,
131
+ .fields = (VMStateField[]) {
102
+ .fields = (VMStateField[]) {
132
+ VMSTATE_INT64(clk1hz_tick_offset, MPS2FPGAIO),
103
+ VMSTATE_CLOCK(clk, PL011State),
133
+ VMSTATE_INT64(clk100hz_tick_offset, MPS2FPGAIO),
134
+ VMSTATE_END_OF_LIST()
104
+ VMSTATE_END_OF_LIST()
135
+ }
105
+ }
136
+};
106
+};
137
+
107
+
138
static const VMStateDescription mps2_fpgaio_vmstate = {
108
static const VMStateDescription vmstate_pl011 = {
139
.name = "mps2-fpgaio",
109
.name = "pl011",
140
.version_id = 1,
110
.version_id = 2,
141
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription mps2_fpgaio_vmstate = {
111
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_pl011 = {
142
VMSTATE_UINT32(prescale, MPS2FPGAIO),
112
VMSTATE_INT32(read_count, PL011State),
143
VMSTATE_UINT32(misc, MPS2FPGAIO),
113
VMSTATE_INT32(read_trigger, PL011State),
144
VMSTATE_END_OF_LIST()
114
VMSTATE_END_OF_LIST()
145
+ },
115
+ },
146
+ .subsections = (const VMStateDescription*[]) {
116
+ .subsections = (const VMStateDescription * []) {
147
+ &mps2_fpgaio_counters_vmstate,
117
+ &vmstate_pl011_clock,
148
+ NULL
118
+ NULL
149
}
119
}
150
};
120
};
151
121
122
@@ -XXX,XX +XXX,XX @@ static void pl011_init(Object *obj)
123
sysbus_init_irq(sbd, &s->irq[i]);
124
}
125
126
+ s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update, s);
127
+
128
s->read_trigger = 1;
129
s->ifl = 0x12;
130
s->cr = 0x300;
131
diff --git a/hw/char/trace-events b/hw/char/trace-events
132
index XXXXXXX..XXXXXXX 100644
133
--- a/hw/char/trace-events
134
+++ b/hw/char/trace-events
135
@@ -XXX,XX +XXX,XX @@ pl011_write(uint32_t addr, uint32_t value) "addr 0x%08x value 0x%08x"
136
pl011_can_receive(uint32_t lcr, int read_count, int r) "LCR 0x%08x read_count %d returning %d"
137
pl011_put_fifo(uint32_t c, int read_count) "new char 0x%x read_count now %d"
138
pl011_put_fifo_full(void) "FIFO now full, RXFF set"
139
+pl011_baudrate_change(unsigned int baudrate, uint64_t clock, uint32_t ibrd, uint32_t fbrd) "new baudrate %u (clk: %" PRIu64 "hz, ibrd: %" PRIu32 ", fbrd: %" PRIu32 ")"
140
141
# cmsdk-apb-uart.c
142
cmsdk_apb_uart_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB UART read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
152
--
143
--
153
2.18.0
144
2.20.1
154
145
155
146
diff view generated by jsdifflib
1
On 32-bit exception entry, CPSR.J must always be set to 0
1
From: Luc Michel <luc@lmichel.fr>
2
(see v7A Arm ARM DDI0406C.c B1.8.5). CPSR.IL must also
3
be cleared on 32-bit exception entry (see v8A Arm ARM
4
DDI0487C.a G1.10).
5
2
6
Clear these bits. (This fixes a bug which will never be noticed
3
Connect the 'uart-out' clock from the CPRMAN to the PL011 instance.
7
by non-buggy guests.)
8
4
5
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Signed-off-by: Luc Michel <luc@lmichel.fr>
7
Tested-by: Guenter Roeck <linux@roeck-us.net>
8
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
11
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
12
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
13
Message-id: 20180820153020.21478-6-peter.maydell@linaro.org
14
---
10
---
15
target/arm/helper.c | 2 ++
11
hw/arm/bcm2835_peripherals.c | 2 ++
16
1 file changed, 2 insertions(+)
12
1 file changed, 2 insertions(+)
17
13
18
diff --git a/target/arm/helper.c b/target/arm/helper.c
14
diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
19
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
20
--- a/target/arm/helper.c
16
--- a/hw/arm/bcm2835_peripherals.c
21
+++ b/target/arm/helper.c
17
+++ b/hw/arm/bcm2835_peripherals.c
22
@@ -XXX,XX +XXX,XX @@ static void take_aarch32_exception(CPUARMState *env, int new_mode,
18
@@ -XXX,XX +XXX,XX @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp)
23
if (env->cp15.sctlr_el[arm_current_el(env)] & SCTLR_EE) {
24
env->uncached_cpsr |= CPSR_E;
25
}
19
}
26
+ /* J and IL must always be cleared for exception entry */
20
memory_region_add_subregion(&s->peri_mr, CPRMAN_OFFSET,
27
+ env->uncached_cpsr &= ~(CPSR_IL | CPSR_J);
21
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->cprman), 0));
28
env->daif |= mask;
22
+ qdev_connect_clock_in(DEVICE(&s->uart0), "clk",
29
23
+ qdev_get_clock_out(DEVICE(&s->cprman), "uart-out"));
30
if (new_mode == ARM_CPU_MODE_HYP) {
24
25
memory_region_add_subregion(&s->peri_mr, ARMCTRL_IC_OFFSET,
26
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->ic), 0));
31
--
27
--
32
2.18.0
28
2.20.1
33
29
34
30
diff view generated by jsdifflib
1
Implement a model of the TrustZone Master Securtiy Controller,
1
From: Shashi Mallela <shashi.mallela@linaro.org>
2
as documented in the Arm CoreLink SIE-200 System IP for
3
Embedded TRM (DDI0571G):
4
https://developer.arm.com/products/architecture/m-profile/docs/ddi0571/g
5
2
6
The MSC is intended to sit in front of a device which can
3
Generic watchdog device model implementation as per ARM SBSA v6.0
7
be a bus master (eg a DMA controller) and programmably gate
8
its transactions. This allows a bus-mastering device to be
9
controlled by non-secure code but still restricted from
10
making accesses to addresses which are secure-only.
11
4
5
Signed-off-by: Shashi Mallela <shashi.mallela@linaro.org>
6
Message-id: 20201027015927.29495-2-shashi.mallela@linaro.org
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
13
Message-id: 20180820141116.9118-12-peter.maydell@linaro.org
14
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
15
---
9
---
16
hw/misc/Makefile.objs | 1 +
10
include/hw/watchdog/sbsa_gwdt.h | 79 +++++++++
17
include/hw/misc/tz-msc.h | 79 ++++++++
11
hw/watchdog/sbsa_gwdt.c | 293 ++++++++++++++++++++++++++++++++
18
hw/misc/tz-msc.c | 308 ++++++++++++++++++++++++++++++++
12
hw/arm/Kconfig | 1 +
19
MAINTAINERS | 2 +
13
hw/watchdog/Kconfig | 3 +
20
default-configs/arm-softmmu.mak | 1 +
14
hw/watchdog/meson.build | 1 +
21
hw/misc/trace-events | 9 +
15
5 files changed, 377 insertions(+)
22
6 files changed, 400 insertions(+)
16
create mode 100644 include/hw/watchdog/sbsa_gwdt.h
23
create mode 100644 include/hw/misc/tz-msc.h
17
create mode 100644 hw/watchdog/sbsa_gwdt.c
24
create mode 100644 hw/misc/tz-msc.c
25
18
26
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
19
diff --git a/include/hw/watchdog/sbsa_gwdt.h b/include/hw/watchdog/sbsa_gwdt.h
27
index XXXXXXX..XXXXXXX 100644
28
--- a/hw/misc/Makefile.objs
29
+++ b/hw/misc/Makefile.objs
30
@@ -XXX,XX +XXX,XX @@ obj-$(CONFIG_MPS2_FPGAIO) += mps2-fpgaio.o
31
obj-$(CONFIG_MPS2_SCC) += mps2-scc.o
32
33
obj-$(CONFIG_TZ_MPC) += tz-mpc.o
34
+obj-$(CONFIG_TZ_MSC) += tz-msc.o
35
obj-$(CONFIG_TZ_PPC) += tz-ppc.o
36
obj-$(CONFIG_IOTKIT_SECCTL) += iotkit-secctl.o
37
obj-$(CONFIG_IOTKIT_SYSCTL) += iotkit-sysctl.o
38
diff --git a/include/hw/misc/tz-msc.h b/include/hw/misc/tz-msc.h
39
new file mode 100644
20
new file mode 100644
40
index XXXXXXX..XXXXXXX
21
index XXXXXXX..XXXXXXX
41
--- /dev/null
22
--- /dev/null
42
+++ b/include/hw/misc/tz-msc.h
23
+++ b/include/hw/watchdog/sbsa_gwdt.h
43
@@ -XXX,XX +XXX,XX @@
24
@@ -XXX,XX +XXX,XX @@
44
+/*
25
+/*
45
+ * ARM TrustZone master security controller emulation
26
+ * Copyright (c) 2020 Linaro Limited
46
+ *
27
+ *
47
+ * Copyright (c) 2018 Linaro Limited
28
+ * Authors:
48
+ * Written by Peter Maydell
29
+ * Shashi Mallela <shashi.mallela@linaro.org>
49
+ *
30
+ *
50
+ * This program is free software; you can redistribute it and/or modify
31
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
51
+ * it under the terms of the GNU General Public License version 2 or
32
+ * option) any later version. See the COPYING file in the top-level directory.
52
+ * (at your option) any later version.
33
+ *
53
+ */
34
+ */
54
+
35
+
36
+#ifndef WDT_SBSA_GWDT_H
37
+#define WDT_SBSA_GWDT_H
38
+
39
+#include "qemu/bitops.h"
40
+#include "hw/sysbus.h"
41
+#include "hw/irq.h"
42
+
43
+#define TYPE_WDT_SBSA "sbsa_gwdt"
44
+#define SBSA_GWDT(obj) \
45
+ OBJECT_CHECK(SBSA_GWDTState, (obj), TYPE_WDT_SBSA)
46
+#define SBSA_GWDT_CLASS(klass) \
47
+ OBJECT_CLASS_CHECK(SBSA_GWDTClass, (klass), TYPE_WDT_SBSA)
48
+#define SBSA_GWDT_GET_CLASS(obj) \
49
+ OBJECT_GET_CLASS(SBSA_GWDTClass, (obj), TYPE_WDT_SBSA)
50
+
51
+/* SBSA Generic Watchdog register definitions */
52
+/* refresh frame */
53
+#define SBSA_GWDT_WRR 0x000
54
+
55
+/* control frame */
56
+#define SBSA_GWDT_WCS 0x000
57
+#define SBSA_GWDT_WOR 0x008
58
+#define SBSA_GWDT_WORU 0x00C
59
+#define SBSA_GWDT_WCV 0x010
60
+#define SBSA_GWDT_WCVU 0x014
61
+
62
+/* Watchdog Interface Identification Register */
63
+#define SBSA_GWDT_W_IIDR 0xFCC
64
+
65
+/* Watchdog Control and Status Register Bits */
66
+#define SBSA_GWDT_WCS_EN BIT(0)
67
+#define SBSA_GWDT_WCS_WS0 BIT(1)
68
+#define SBSA_GWDT_WCS_WS1 BIT(2)
69
+
70
+#define SBSA_GWDT_WOR_MASK 0x0000FFFF
71
+
55
+/*
72
+/*
56
+ * This is a model of the TrustZone master security controller (MSC).
73
+ * Watchdog Interface Identification Register definition
57
+ * It is documented in the ARM CoreLink SIE-200 System IP for Embedded TRM
74
+ * considering JEP106 code for ARM in Bits [11:0]
58
+ * (DDI 0571G):
59
+ * https://developer.arm.com/products/architecture/m-profile/docs/ddi0571/g
60
+ *
61
+ * The MSC sits in front of a device which can be a bus master (such as
62
+ * a DMA controller) and allows secure software to configure it to either
63
+ * pass through or reject transactions made by that bus master.
64
+ * Rejected transactions may be configured to either be aborted, or to
65
+ * behave as RAZ/WI. An interrupt can be signalled for a rejected transaction.
66
+ *
67
+ * The MSC has no register interface -- it is configured purely by a
68
+ * collection of input signals from other hardware in the system. Typically
69
+ * they are either hardwired or exposed in an ad-hoc register interface by
70
+ * the SoC that uses the MSC.
71
+ *
72
+ * We don't currently implement the irq_enable GPIO input, because on
73
+ * the MPS2 FPGA images it is always tied high, which is awkward to
74
+ * implement in QEMU.
75
+ *
76
+ * QEMU interface:
77
+ * + Named GPIO input "cfg_nonsec": set to 1 if the bus master should be
78
+ * treated as nonsecure, or 0 for secure
79
+ * + Named GPIO input "cfg_sec_resp": set to 1 if a rejected transaction should
80
+ * result in a transaction error, or 0 for the transaction to RAZ/WI
81
+ * + Named GPIO input "irq_clear": set to 1 to clear a pending interrupt
82
+ * + Named GPIO output "irq": set for a transaction-failed interrupt
83
+ * + Property "downstream": MemoryRegion defining where bus master transactions
84
+ * are made if they are not blocked
85
+ * + Property "idau": an object implementing IDAUInterface, which defines which
86
+ * addresses should be treated as secure and which as non-secure.
87
+ * This need not be the same IDAU as the one used by the CPU.
88
+ * + sysbus MMIO region 0: MemoryRegion defining the upstream end of the MSC;
89
+ * this should be passed to the bus master device as the region it should
90
+ * make memory transactions to
91
+ */
75
+ */
92
+
76
+#define SBSA_GWDT_ID 0x1043B
93
+#ifndef TZ_MSC_H
77
+
94
+#define TZ_MSC_H
78
+/* 2 Separate memory regions for each of refresh & control register frames */
95
+
79
+#define SBSA_GWDT_RMMIO_SIZE 0x1000
96
+#include "hw/sysbus.h"
80
+#define SBSA_GWDT_CMMIO_SIZE 0x1000
97
+#include "target/arm/idau.h"
81
+
98
+
82
+#define SBSA_TIMER_FREQ 62500000 /* Hz */
99
+#define TYPE_TZ_MSC "tz-msc"
83
+
100
+#define TZ_MSC(obj) OBJECT_CHECK(TZMSC, (obj), TYPE_TZ_MSC)
84
+typedef struct SBSA_GWDTState {
101
+
85
+ /* <private> */
102
+typedef struct TZMSC {
103
+ /*< private >*/
104
+ SysBusDevice parent_obj;
86
+ SysBusDevice parent_obj;
105
+
87
+
106
+ /*< public >*/
88
+ /*< public >*/
107
+
89
+ MemoryRegion rmmio;
108
+ /* State: these just track the values of our input signals */
90
+ MemoryRegion cmmio;
109
+ bool cfg_nonsec;
110
+ bool cfg_sec_resp;
111
+ bool irq_clear;
112
+ /* State: are we asserting irq ? */
113
+ bool irq_status;
114
+
115
+ qemu_irq irq;
91
+ qemu_irq irq;
116
+ MemoryRegion *downstream;
92
+
117
+ AddressSpace downstream_as;
93
+ QEMUTimer *timer;
118
+ MemoryRegion upstream;
94
+
119
+ IDAUInterface *idau;
95
+ uint32_t id;
120
+} TZMSC;
96
+ uint32_t wcs;
121
+
97
+ uint32_t worl;
122
+#endif
98
+ uint32_t woru;
123
diff --git a/hw/misc/tz-msc.c b/hw/misc/tz-msc.c
99
+ uint32_t wcvl;
100
+ uint32_t wcvu;
101
+} SBSA_GWDTState;
102
+
103
+#endif /* WDT_SBSA_GWDT_H */
104
diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c
124
new file mode 100644
105
new file mode 100644
125
index XXXXXXX..XXXXXXX
106
index XXXXXXX..XXXXXXX
126
--- /dev/null
107
--- /dev/null
127
+++ b/hw/misc/tz-msc.c
108
+++ b/hw/watchdog/sbsa_gwdt.c
128
@@ -XXX,XX +XXX,XX @@
109
@@ -XXX,XX +XXX,XX @@
129
+/*
110
+/*
130
+ * ARM TrustZone master security controller emulation
111
+ * Generic watchdog device model for SBSA
131
+ *
112
+ *
132
+ * Copyright (c) 2018 Linaro Limited
113
+ * The watchdog device has been implemented as revision 1 variant of
133
+ * Written by Peter Maydell
114
+ * the ARM SBSA specification v6.0
134
+ *
115
+ * (https://developer.arm.com/documentation/den0029/d?lang=en)
135
+ * This program is free software; you can redistribute it and/or modify
116
+ *
136
+ * it under the terms of the GNU General Public License version 2 or
117
+ * Copyright Linaro.org 2020
137
+ * (at your option) any later version.
118
+ *
119
+ * Authors:
120
+ * Shashi Mallela <shashi.mallela@linaro.org>
121
+ *
122
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
123
+ * option) any later version. See the COPYING file in the top-level directory.
124
+ *
138
+ */
125
+ */
139
+
126
+
140
+#include "qemu/osdep.h"
127
+#include "qemu/osdep.h"
128
+#include "sysemu/reset.h"
129
+#include "sysemu/watchdog.h"
130
+#include "hw/watchdog/sbsa_gwdt.h"
131
+#include "qemu/timer.h"
132
+#include "migration/vmstate.h"
141
+#include "qemu/log.h"
133
+#include "qemu/log.h"
142
+#include "qapi/error.h"
134
+#include "qemu/module.h"
143
+#include "trace.h"
135
+
144
+#include "hw/sysbus.h"
136
+static WatchdogTimerModel model = {
145
+#include "hw/registerfields.h"
137
+ .wdt_name = TYPE_WDT_SBSA,
146
+#include "hw/misc/tz-msc.h"
138
+ .wdt_description = "SBSA-compliant generic watchdog device",
147
+
148
+static void tz_msc_update_irq(TZMSC *s)
149
+{
150
+ bool level = s->irq_status;
151
+
152
+ trace_tz_msc_update_irq(level);
153
+ qemu_set_irq(s->irq, level);
154
+}
155
+
156
+static void tz_msc_cfg_nonsec(void *opaque, int n, int level)
157
+{
158
+ TZMSC *s = TZ_MSC(opaque);
159
+
160
+ trace_tz_msc_cfg_nonsec(level);
161
+ s->cfg_nonsec = level;
162
+}
163
+
164
+static void tz_msc_cfg_sec_resp(void *opaque, int n, int level)
165
+{
166
+ TZMSC *s = TZ_MSC(opaque);
167
+
168
+ trace_tz_msc_cfg_sec_resp(level);
169
+ s->cfg_sec_resp = level;
170
+}
171
+
172
+static void tz_msc_irq_clear(void *opaque, int n, int level)
173
+{
174
+ TZMSC *s = TZ_MSC(opaque);
175
+
176
+ trace_tz_msc_irq_clear(level);
177
+
178
+ s->irq_clear = level;
179
+ if (level) {
180
+ s->irq_status = false;
181
+ tz_msc_update_irq(s);
182
+ }
183
+}
184
+
185
+/* The MSC may either block a transaction by aborting it, block a
186
+ * transaction by making it RAZ/WI, allow it through with
187
+ * MemTxAttrs indicating a secure transaction, or allow it with
188
+ * MemTxAttrs indicating a non-secure transaction.
189
+ */
190
+typedef enum MSCAction {
191
+ MSCBlockAbort,
192
+ MSCBlockRAZWI,
193
+ MSCAllowSecure,
194
+ MSCAllowNonSecure,
195
+} MSCAction;
196
+
197
+static MSCAction tz_msc_check(TZMSC *s, hwaddr addr)
198
+{
199
+ /*
200
+ * Check whether to allow an access from the bus master, returning
201
+ * an MSCAction indicating the required behaviour. If the transaction
202
+ * is blocked, the caller must check cfg_sec_resp to determine
203
+ * whether to abort or RAZ/WI the transaction.
204
+ */
205
+ IDAUInterfaceClass *iic = IDAU_INTERFACE_GET_CLASS(s->idau);
206
+ IDAUInterface *ii = IDAU_INTERFACE(s->idau);
207
+ bool idau_exempt = false, idau_ns = true, idau_nsc = true;
208
+ int idau_region = IREGION_NOTVALID;
209
+
210
+ iic->check(ii, addr, &idau_region, &idau_exempt, &idau_ns, &idau_nsc);
211
+
212
+ if (idau_exempt) {
213
+ /*
214
+ * Uncheck region -- OK, transaction type depends on
215
+ * whether bus master is configured as Secure or NonSecure
216
+ */
217
+ return s->cfg_nonsec ? MSCAllowNonSecure : MSCAllowSecure;
218
+ }
219
+
220
+ if (idau_ns) {
221
+ /* NonSecure region -- always forward as NS transaction */
222
+ return MSCAllowNonSecure;
223
+ }
224
+
225
+ if (!s->cfg_nonsec) {
226
+ /* Access to Secure region by Secure bus master: OK */
227
+ return MSCAllowSecure;
228
+ }
229
+
230
+ /* Attempted access to Secure region by NS bus master: block */
231
+ trace_tz_msc_access_blocked(addr);
232
+ if (!s->cfg_sec_resp) {
233
+ return MSCBlockRAZWI;
234
+ }
235
+
236
+ /*
237
+ * The TRM isn't clear on behaviour if irq_clear is high when a
238
+ * transaction is blocked. We assume that the MSC behaves like the
239
+ * PPC, where holding irq_clear high suppresses the interrupt.
240
+ */
241
+ if (!s->irq_clear) {
242
+ s->irq_status = true;
243
+ tz_msc_update_irq(s);
244
+ }
245
+ return MSCBlockAbort;
246
+}
247
+
248
+static MemTxResult tz_msc_read(void *opaque, hwaddr addr, uint64_t *pdata,
249
+ unsigned size, MemTxAttrs attrs)
250
+{
251
+ TZMSC *s = opaque;
252
+ AddressSpace *as = &s->downstream_as;
253
+ uint64_t data;
254
+ MemTxResult res;
255
+
256
+ switch (tz_msc_check(s, addr)) {
257
+ case MSCBlockAbort:
258
+ return MEMTX_ERROR;
259
+ case MSCBlockRAZWI:
260
+ *pdata = 0;
261
+ return MEMTX_OK;
262
+ case MSCAllowSecure:
263
+ attrs.secure = 1;
264
+ attrs.unspecified = 0;
265
+ break;
266
+ case MSCAllowNonSecure:
267
+ attrs.secure = 0;
268
+ attrs.unspecified = 0;
269
+ break;
270
+ }
271
+
272
+ switch (size) {
273
+ case 1:
274
+ data = address_space_ldub(as, addr, attrs, &res);
275
+ break;
276
+ case 2:
277
+ data = address_space_lduw_le(as, addr, attrs, &res);
278
+ break;
279
+ case 4:
280
+ data = address_space_ldl_le(as, addr, attrs, &res);
281
+ break;
282
+ case 8:
283
+ data = address_space_ldq_le(as, addr, attrs, &res);
284
+ break;
285
+ default:
286
+ g_assert_not_reached();
287
+ }
288
+ *pdata = data;
289
+ return res;
290
+}
291
+
292
+static MemTxResult tz_msc_write(void *opaque, hwaddr addr, uint64_t val,
293
+ unsigned size, MemTxAttrs attrs)
294
+{
295
+ TZMSC *s = opaque;
296
+ AddressSpace *as = &s->downstream_as;
297
+ MemTxResult res;
298
+
299
+ switch (tz_msc_check(s, addr)) {
300
+ case MSCBlockAbort:
301
+ return MEMTX_ERROR;
302
+ case MSCBlockRAZWI:
303
+ return MEMTX_OK;
304
+ case MSCAllowSecure:
305
+ attrs.secure = 1;
306
+ attrs.unspecified = 0;
307
+ break;
308
+ case MSCAllowNonSecure:
309
+ attrs.secure = 0;
310
+ attrs.unspecified = 0;
311
+ break;
312
+ }
313
+
314
+ switch (size) {
315
+ case 1:
316
+ address_space_stb(as, addr, val, attrs, &res);
317
+ break;
318
+ case 2:
319
+ address_space_stw_le(as, addr, val, attrs, &res);
320
+ break;
321
+ case 4:
322
+ address_space_stl_le(as, addr, val, attrs, &res);
323
+ break;
324
+ case 8:
325
+ address_space_stq_le(as, addr, val, attrs, &res);
326
+ break;
327
+ default:
328
+ g_assert_not_reached();
329
+ }
330
+ return res;
331
+}
332
+
333
+static const MemoryRegionOps tz_msc_ops = {
334
+ .read_with_attrs = tz_msc_read,
335
+ .write_with_attrs = tz_msc_write,
336
+ .endianness = DEVICE_LITTLE_ENDIAN,
337
+};
139
+};
338
+
140
+
339
+static void tz_msc_reset(DeviceState *dev)
141
+static const VMStateDescription vmstate_sbsa_gwdt = {
340
+{
142
+ .name = "sbsa-gwdt",
341
+ TZMSC *s = TZ_MSC(dev);
342
+
343
+ trace_tz_msc_reset();
344
+ s->cfg_sec_resp = false;
345
+ s->cfg_nonsec = false;
346
+ s->irq_clear = 0;
347
+ s->irq_status = 0;
348
+}
349
+
350
+static void tz_msc_init(Object *obj)
351
+{
352
+ DeviceState *dev = DEVICE(obj);
353
+ TZMSC *s = TZ_MSC(obj);
354
+
355
+ qdev_init_gpio_in_named(dev, tz_msc_cfg_nonsec, "cfg_nonsec", 1);
356
+ qdev_init_gpio_in_named(dev, tz_msc_cfg_sec_resp, "cfg_sec_resp", 1);
357
+ qdev_init_gpio_in_named(dev, tz_msc_irq_clear, "irq_clear", 1);
358
+ qdev_init_gpio_out_named(dev, &s->irq, "irq", 1);
359
+}
360
+
361
+static void tz_msc_realize(DeviceState *dev, Error **errp)
362
+{
363
+ Object *obj = OBJECT(dev);
364
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
365
+ TZMSC *s = TZ_MSC(dev);
366
+ const char *name = "tz-msc-downstream";
367
+ uint64_t size;
368
+
369
+ /*
370
+ * We can't create the upstream end of the port until realize,
371
+ * as we don't know the size of the MR used as the downstream until then.
372
+ * We insist on having a downstream, to avoid complicating the
373
+ * code with handling the "don't know how big this is" case. It's easy
374
+ * enough for the user to create an unimplemented_device as downstream
375
+ * if they have nothing else to plug into this.
376
+ */
377
+ if (!s->downstream) {
378
+ error_setg(errp, "MSC 'downstream' link not set");
379
+ return;
380
+ }
381
+ if (!s->idau) {
382
+ error_setg(errp, "MSC 'idau' link not set");
383
+ return;
384
+ }
385
+
386
+ size = memory_region_size(s->downstream);
387
+ address_space_init(&s->downstream_as, s->downstream, name);
388
+ memory_region_init_io(&s->upstream, obj, &tz_msc_ops, s, name, size);
389
+ sysbus_init_mmio(sbd, &s->upstream);
390
+}
391
+
392
+static const VMStateDescription tz_msc_vmstate = {
393
+ .name = "tz-msc",
394
+ .version_id = 1,
143
+ .version_id = 1,
395
+ .minimum_version_id = 1,
144
+ .minimum_version_id = 1,
396
+ .fields = (VMStateField[]) {
145
+ .fields = (VMStateField[]) {
397
+ VMSTATE_BOOL(cfg_nonsec, TZMSC),
146
+ VMSTATE_TIMER_PTR(timer, SBSA_GWDTState),
398
+ VMSTATE_BOOL(cfg_sec_resp, TZMSC),
147
+ VMSTATE_UINT32(wcs, SBSA_GWDTState),
399
+ VMSTATE_BOOL(irq_clear, TZMSC),
148
+ VMSTATE_UINT32(worl, SBSA_GWDTState),
400
+ VMSTATE_BOOL(irq_status, TZMSC),
149
+ VMSTATE_UINT32(woru, SBSA_GWDTState),
150
+ VMSTATE_UINT32(wcvl, SBSA_GWDTState),
151
+ VMSTATE_UINT32(wcvu, SBSA_GWDTState),
401
+ VMSTATE_END_OF_LIST()
152
+ VMSTATE_END_OF_LIST()
402
+ }
153
+ }
403
+};
154
+};
404
+
155
+
405
+static Property tz_msc_properties[] = {
156
+typedef enum WdtRefreshType {
406
+ DEFINE_PROP_LINK("downstream", TZMSC, downstream,
157
+ EXPLICIT_REFRESH = 0,
407
+ TYPE_MEMORY_REGION, MemoryRegion *),
158
+ TIMEOUT_REFRESH = 1,
408
+ DEFINE_PROP_LINK("idau", TZMSC, idau,
159
+} WdtRefreshType;
409
+ TYPE_IDAU_INTERFACE, IDAUInterface *),
160
+
410
+ DEFINE_PROP_END_OF_LIST(),
161
+static uint64_t sbsa_gwdt_rread(void *opaque, hwaddr addr, unsigned int size)
162
+{
163
+ SBSA_GWDTState *s = SBSA_GWDT(opaque);
164
+ uint32_t ret = 0;
165
+
166
+ switch (addr) {
167
+ case SBSA_GWDT_WRR:
168
+ /* watch refresh read has no effect and returns 0 */
169
+ ret = 0;
170
+ break;
171
+ case SBSA_GWDT_W_IIDR:
172
+ ret = s->id;
173
+ break;
174
+ default:
175
+ qemu_log_mask(LOG_GUEST_ERROR, "bad address in refresh frame read :"
176
+ " 0x%x\n", (int)addr);
177
+ }
178
+ return ret;
179
+}
180
+
181
+static uint64_t sbsa_gwdt_read(void *opaque, hwaddr addr, unsigned int size)
182
+{
183
+ SBSA_GWDTState *s = SBSA_GWDT(opaque);
184
+ uint32_t ret = 0;
185
+
186
+ switch (addr) {
187
+ case SBSA_GWDT_WCS:
188
+ ret = s->wcs;
189
+ break;
190
+ case SBSA_GWDT_WOR:
191
+ ret = s->worl;
192
+ break;
193
+ case SBSA_GWDT_WORU:
194
+ ret = s->woru;
195
+ break;
196
+ case SBSA_GWDT_WCV:
197
+ ret = s->wcvl;
198
+ break;
199
+ case SBSA_GWDT_WCVU:
200
+ ret = s->wcvu;
201
+ break;
202
+ case SBSA_GWDT_W_IIDR:
203
+ ret = s->id;
204
+ break;
205
+ default:
206
+ qemu_log_mask(LOG_GUEST_ERROR, "bad address in control frame read :"
207
+ " 0x%x\n", (int)addr);
208
+ }
209
+ return ret;
210
+}
211
+
212
+static void sbsa_gwdt_update_timer(SBSA_GWDTState *s, WdtRefreshType rtype)
213
+{
214
+ uint64_t timeout = 0;
215
+
216
+ timer_del(s->timer);
217
+
218
+ if (s->wcs & SBSA_GWDT_WCS_EN) {
219
+ /*
220
+ * Extract the upper 16 bits from woru & 32 bits from worl
221
+ * registers to construct the 48 bit offset value
222
+ */
223
+ timeout = s->woru;
224
+ timeout <<= 32;
225
+ timeout |= s->worl;
226
+ timeout = muldiv64(timeout, NANOSECONDS_PER_SECOND, SBSA_TIMER_FREQ);
227
+ timeout += qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
228
+
229
+ if ((rtype == EXPLICIT_REFRESH) || ((rtype == TIMEOUT_REFRESH) &&
230
+ (!(s->wcs & SBSA_GWDT_WCS_WS0)))) {
231
+ /* store the current timeout value into compare registers */
232
+ s->wcvu = timeout >> 32;
233
+ s->wcvl = timeout;
234
+ }
235
+ timer_mod(s->timer, timeout);
236
+ }
237
+}
238
+
239
+static void sbsa_gwdt_rwrite(void *opaque, hwaddr offset, uint64_t data,
240
+ unsigned size) {
241
+ SBSA_GWDTState *s = SBSA_GWDT(opaque);
242
+
243
+ if (offset == SBSA_GWDT_WRR) {
244
+ s->wcs &= ~(SBSA_GWDT_WCS_WS0 | SBSA_GWDT_WCS_WS1);
245
+
246
+ sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH);
247
+ } else {
248
+ qemu_log_mask(LOG_GUEST_ERROR, "bad address in refresh frame write :"
249
+ " 0x%x\n", (int)offset);
250
+ }
251
+}
252
+
253
+static void sbsa_gwdt_write(void *opaque, hwaddr offset, uint64_t data,
254
+ unsigned size) {
255
+ SBSA_GWDTState *s = SBSA_GWDT(opaque);
256
+
257
+ switch (offset) {
258
+ case SBSA_GWDT_WCS:
259
+ s->wcs = data & SBSA_GWDT_WCS_EN;
260
+ qemu_set_irq(s->irq, 0);
261
+ sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH);
262
+ break;
263
+
264
+ case SBSA_GWDT_WOR:
265
+ s->worl = data;
266
+ s->wcs &= ~(SBSA_GWDT_WCS_WS0 | SBSA_GWDT_WCS_WS1);
267
+ qemu_set_irq(s->irq, 0);
268
+ sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH);
269
+ break;
270
+
271
+ case SBSA_GWDT_WORU:
272
+ s->woru = data & SBSA_GWDT_WOR_MASK;
273
+ s->wcs &= ~(SBSA_GWDT_WCS_WS0 | SBSA_GWDT_WCS_WS1);
274
+ qemu_set_irq(s->irq, 0);
275
+ sbsa_gwdt_update_timer(s, EXPLICIT_REFRESH);
276
+ break;
277
+
278
+ case SBSA_GWDT_WCV:
279
+ s->wcvl = data;
280
+ break;
281
+
282
+ case SBSA_GWDT_WCVU:
283
+ s->wcvu = data;
284
+ break;
285
+
286
+ default:
287
+ qemu_log_mask(LOG_GUEST_ERROR, "bad address in control frame write :"
288
+ " 0x%x\n", (int)offset);
289
+ }
290
+ return;
291
+}
292
+
293
+static void wdt_sbsa_gwdt_reset(DeviceState *dev)
294
+{
295
+ SBSA_GWDTState *s = SBSA_GWDT(dev);
296
+
297
+ timer_del(s->timer);
298
+
299
+ s->wcs = 0;
300
+ s->wcvl = 0;
301
+ s->wcvu = 0;
302
+ s->worl = 0;
303
+ s->woru = 0;
304
+ s->id = SBSA_GWDT_ID;
305
+}
306
+
307
+static void sbsa_gwdt_timer_sysinterrupt(void *opaque)
308
+{
309
+ SBSA_GWDTState *s = SBSA_GWDT(opaque);
310
+
311
+ if (!(s->wcs & SBSA_GWDT_WCS_WS0)) {
312
+ s->wcs |= SBSA_GWDT_WCS_WS0;
313
+ sbsa_gwdt_update_timer(s, TIMEOUT_REFRESH);
314
+ qemu_set_irq(s->irq, 1);
315
+ } else {
316
+ s->wcs |= SBSA_GWDT_WCS_WS1;
317
+ qemu_log_mask(CPU_LOG_RESET, "Watchdog timer expired.\n");
318
+ /*
319
+ * Reset the watchdog only if the guest gets notified about
320
+ * expiry. watchdog_perform_action() may temporarily relinquish
321
+ * the BQL; reset before triggering the action to avoid races with
322
+ * sbsa_gwdt instructions.
323
+ */
324
+ switch (get_watchdog_action()) {
325
+ case WATCHDOG_ACTION_DEBUG:
326
+ case WATCHDOG_ACTION_NONE:
327
+ case WATCHDOG_ACTION_PAUSE:
328
+ break;
329
+ default:
330
+ wdt_sbsa_gwdt_reset(DEVICE(s));
331
+ }
332
+ watchdog_perform_action();
333
+ }
334
+}
335
+
336
+static const MemoryRegionOps sbsa_gwdt_rops = {
337
+ .read = sbsa_gwdt_rread,
338
+ .write = sbsa_gwdt_rwrite,
339
+ .endianness = DEVICE_LITTLE_ENDIAN,
340
+ .valid.min_access_size = 4,
341
+ .valid.max_access_size = 4,
342
+ .valid.unaligned = false,
411
+};
343
+};
412
+
344
+
413
+static void tz_msc_class_init(ObjectClass *klass, void *data)
345
+static const MemoryRegionOps sbsa_gwdt_ops = {
346
+ .read = sbsa_gwdt_read,
347
+ .write = sbsa_gwdt_write,
348
+ .endianness = DEVICE_LITTLE_ENDIAN,
349
+ .valid.min_access_size = 4,
350
+ .valid.max_access_size = 4,
351
+ .valid.unaligned = false,
352
+};
353
+
354
+static void wdt_sbsa_gwdt_realize(DeviceState *dev, Error **errp)
355
+{
356
+ SBSA_GWDTState *s = SBSA_GWDT(dev);
357
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
358
+
359
+ memory_region_init_io(&s->rmmio, OBJECT(dev),
360
+ &sbsa_gwdt_rops, s,
361
+ "sbsa_gwdt.refresh",
362
+ SBSA_GWDT_RMMIO_SIZE);
363
+
364
+ memory_region_init_io(&s->cmmio, OBJECT(dev),
365
+ &sbsa_gwdt_ops, s,
366
+ "sbsa_gwdt.control",
367
+ SBSA_GWDT_CMMIO_SIZE);
368
+
369
+ sysbus_init_mmio(sbd, &s->rmmio);
370
+ sysbus_init_mmio(sbd, &s->cmmio);
371
+
372
+ sysbus_init_irq(sbd, &s->irq);
373
+
374
+ s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, sbsa_gwdt_timer_sysinterrupt,
375
+ dev);
376
+}
377
+
378
+static void wdt_sbsa_gwdt_class_init(ObjectClass *klass, void *data)
414
+{
379
+{
415
+ DeviceClass *dc = DEVICE_CLASS(klass);
380
+ DeviceClass *dc = DEVICE_CLASS(klass);
416
+
381
+
417
+ dc->realize = tz_msc_realize;
382
+ dc->realize = wdt_sbsa_gwdt_realize;
418
+ dc->vmsd = &tz_msc_vmstate;
383
+ dc->reset = wdt_sbsa_gwdt_reset;
419
+ dc->reset = tz_msc_reset;
384
+ dc->hotpluggable = false;
420
+ dc->props = tz_msc_properties;
385
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
421
+}
386
+ dc->vmsd = &vmstate_sbsa_gwdt;
422
+
387
+}
423
+static const TypeInfo tz_msc_info = {
388
+
424
+ .name = TYPE_TZ_MSC,
389
+static const TypeInfo wdt_sbsa_gwdt_info = {
390
+ .class_init = wdt_sbsa_gwdt_class_init,
425
+ .parent = TYPE_SYS_BUS_DEVICE,
391
+ .parent = TYPE_SYS_BUS_DEVICE,
426
+ .instance_size = sizeof(TZMSC),
392
+ .name = TYPE_WDT_SBSA,
427
+ .instance_init = tz_msc_init,
393
+ .instance_size = sizeof(SBSA_GWDTState),
428
+ .class_init = tz_msc_class_init,
429
+};
394
+};
430
+
395
+
431
+static void tz_msc_register_types(void)
396
+static void wdt_sbsa_gwdt_register_types(void)
432
+{
397
+{
433
+ type_register_static(&tz_msc_info);
398
+ watchdog_add_model(&model);
434
+}
399
+ type_register_static(&wdt_sbsa_gwdt_info);
435
+
400
+}
436
+type_init(tz_msc_register_types);
401
+
437
diff --git a/MAINTAINERS b/MAINTAINERS
402
+type_init(wdt_sbsa_gwdt_register_types)
403
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
438
index XXXXXXX..XXXXXXX 100644
404
index XXXXXXX..XXXXXXX 100644
439
--- a/MAINTAINERS
405
--- a/hw/arm/Kconfig
440
+++ b/MAINTAINERS
406
+++ b/hw/arm/Kconfig
441
@@ -XXX,XX +XXX,XX @@ F: hw/misc/tz-ppc.c
407
@@ -XXX,XX +XXX,XX @@ config SBSA_REF
442
F: include/hw/misc/tz-ppc.h
408
select PL031 # RTC
443
F: hw/misc/tz-mpc.c
409
select PL061 # GPIO
444
F: include/hw/misc/tz-mpc.h
410
select USB_EHCI_SYSBUS
445
+F: hw/misc/tz-msc.c
411
+ select WDT_SBSA
446
+F: include/hw/misc/tz-msc.h
412
447
413
config SABRELITE
448
ARM cores
414
bool
449
M: Peter Maydell <peter.maydell@linaro.org>
415
diff --git a/hw/watchdog/Kconfig b/hw/watchdog/Kconfig
450
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
451
index XXXXXXX..XXXXXXX 100644
416
index XXXXXXX..XXXXXXX 100644
452
--- a/default-configs/arm-softmmu.mak
417
--- a/hw/watchdog/Kconfig
453
+++ b/default-configs/arm-softmmu.mak
418
+++ b/hw/watchdog/Kconfig
454
@@ -XXX,XX +XXX,XX @@ CONFIG_MPS2_FPGAIO=y
419
@@ -XXX,XX +XXX,XX @@ config WDT_DIAG288
455
CONFIG_MPS2_SCC=y
420
456
421
config WDT_IMX2
457
CONFIG_TZ_MPC=y
422
bool
458
+CONFIG_TZ_MSC=y
423
+
459
CONFIG_TZ_PPC=y
424
+config WDT_SBSA
460
CONFIG_IOTKIT=y
425
+ bool
461
CONFIG_IOTKIT_SECCTL=y
426
diff --git a/hw/watchdog/meson.build b/hw/watchdog/meson.build
462
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
463
index XXXXXXX..XXXXXXX 100644
427
index XXXXXXX..XXXXXXX 100644
464
--- a/hw/misc/trace-events
428
--- a/hw/watchdog/meson.build
465
+++ b/hw/misc/trace-events
429
+++ b/hw/watchdog/meson.build
466
@@ -XXX,XX +XXX,XX @@ tz_mpc_mem_blocked_write(uint64_t addr, uint64_t data, unsigned size, bool secur
430
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_WDT_IB700', if_true: files('wdt_ib700.c'))
467
tz_mpc_translate(uint64_t addr, int flags, const char *idx, const char *res) "TZ MPC translate: addr 0x%" PRIx64 " flags 0x%x iommu_idx %s: %s"
431
softmmu_ss.add(when: 'CONFIG_WDT_DIAG288', if_true: files('wdt_diag288.c'))
468
tz_mpc_iommu_notify(uint64_t addr) "TZ MPC iommu: notifying UNMAP/MAP for 0x%" PRIx64
432
softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('wdt_aspeed.c'))
469
433
softmmu_ss.add(when: 'CONFIG_WDT_IMX2', if_true: files('wdt_imx2.c'))
470
+# hw/misc/tz-msc.c
434
+softmmu_ss.add(when: 'CONFIG_WDT_SBSA', if_true: files('sbsa_gwdt.c'))
471
+tz_msc_reset(void) "TZ MSC: reset"
472
+tz_msc_cfg_nonsec(int level) "TZ MSC: cfg_nonsec = %d"
473
+tz_msc_cfg_sec_resp(int level) "TZ MSC: cfg_sec_resp = %d"
474
+tz_msc_irq_enable(int level) "TZ MSC: int_enable = %d"
475
+tz_msc_irq_clear(int level) "TZ MSC: int_clear = %d"
476
+tz_msc_update_irq(int level) "TZ MSC: setting irq line to %d"
477
+tz_msc_access_blocked(uint64_t offset) "TZ MSC: offset 0x%" PRIx64 " access blocked"
478
+
479
# hw/misc/tz-ppc.c
480
tz_ppc_reset(void) "TZ PPC: reset"
481
tz_ppc_cfg_nonsec(int n, int level) "TZ PPC: cfg_nonsec[%d] = %d"
482
--
435
--
483
2.18.0
436
2.20.1
484
437
485
438
diff view generated by jsdifflib
1
The SPI controllers in the MPS2 AN505 board are PL022s.
1
From: Shashi Mallela <shashi.mallela@linaro.org>
2
We have a model of the PL022, so create these devices.
3
2
4
We don't currently model the LCD controller that sits behind
3
Included the newly implemented SBSA generic watchdog device model into
5
one of the PL022s; the others are intended to control devices
4
SBSA platform
6
that sit on the FPGA's general purpose SPI connector or
7
"shield" expansion connectors.
8
5
6
Signed-off-by: Shashi Mallela <shashi.mallela@linaro.org>
7
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
8
Message-id: 20201027015927.29495-3-shashi.mallela@linaro.org
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
10
Message-id: 20180820141116.9118-22-peter.maydell@linaro.org
11
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
12
---
10
---
13
hw/arm/mps2-tz.c | 38 ++++++++++++++++++++++++++++++++------
11
hw/arm/sbsa-ref.c | 23 +++++++++++++++++++++++
14
1 file changed, 32 insertions(+), 6 deletions(-)
12
1 file changed, 23 insertions(+)
15
13
16
diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
14
diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c
17
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/arm/mps2-tz.c
16
--- a/hw/arm/sbsa-ref.c
19
+++ b/hw/arm/mps2-tz.c
17
+++ b/hw/arm/sbsa-ref.c
20
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@
21
#include "hw/misc/tz-msc.h"
19
#include "hw/qdev-properties.h"
22
#include "hw/arm/iotkit.h"
20
#include "hw/usb.h"
23
#include "hw/dma/pl080.h"
21
#include "hw/char/pl011.h"
24
+#include "hw/ssi/pl022.h"
22
+#include "hw/watchdog/sbsa_gwdt.h"
25
#include "hw/devices.h"
26
#include "net/net.h"
23
#include "net/net.h"
27
#include "hw/core/split-irq.h"
24
#include "qom/object.h"
28
@@ -XXX,XX +XXX,XX @@ typedef struct {
25
29
MPS2FPGAIO fpgaio;
26
@@ -XXX,XX +XXX,XX @@ enum {
30
TZPPC ppc[5];
27
SBSA_GIC_DIST,
31
TZMPC ssram_mpc[3];
28
SBSA_GIC_REDIST,
32
- UnimplementedDeviceState spi[5];
29
SBSA_SECURE_EC,
33
+ PL022State spi[5];
30
+ SBSA_GWDT,
34
UnimplementedDeviceState i2c[4];
31
+ SBSA_GWDT_REFRESH,
35
UnimplementedDeviceState i2s_audio;
32
+ SBSA_GWDT_CONTROL,
36
UnimplementedDeviceState gpio[4];
33
SBSA_SMMU,
37
@@ -XXX,XX +XXX,XX @@ static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque,
34
SBSA_UART,
38
return sysbus_mmio_get_region(s, 0);
35
SBSA_RTC,
36
@@ -XXX,XX +XXX,XX @@ static const MemMapEntry sbsa_ref_memmap[] = {
37
[SBSA_GIC_DIST] = { 0x40060000, 0x00010000 },
38
[SBSA_GIC_REDIST] = { 0x40080000, 0x04000000 },
39
[SBSA_SECURE_EC] = { 0x50000000, 0x00001000 },
40
+ [SBSA_GWDT_REFRESH] = { 0x50010000, 0x00001000 },
41
+ [SBSA_GWDT_CONTROL] = { 0x50011000, 0x00001000 },
42
[SBSA_UART] = { 0x60000000, 0x00001000 },
43
[SBSA_RTC] = { 0x60010000, 0x00001000 },
44
[SBSA_GPIO] = { 0x60020000, 0x00001000 },
45
@@ -XXX,XX +XXX,XX @@ static const int sbsa_ref_irqmap[] = {
46
[SBSA_AHCI] = 10,
47
[SBSA_EHCI] = 11,
48
[SBSA_SMMU] = 12, /* ... to 15 */
49
+ [SBSA_GWDT] = 16,
50
};
51
52
static uint64_t sbsa_ref_cpu_mp_affinity(SBSAMachineState *sms, int idx)
53
@@ -XXX,XX +XXX,XX @@ static void create_rtc(const SBSAMachineState *sms)
54
sysbus_create_simple("pl031", base, qdev_get_gpio_in(sms->gic, irq));
39
}
55
}
40
56
41
+static MemoryRegion *make_spi(MPS2TZMachineState *mms, void *opaque,
57
+static void create_wdt(const SBSAMachineState *sms)
42
+ const char *name, hwaddr size)
43
+{
58
+{
44
+ /*
59
+ hwaddr rbase = sbsa_ref_memmap[SBSA_GWDT_REFRESH].base;
45
+ * The AN505 has five PL022 SPI controllers.
60
+ hwaddr cbase = sbsa_ref_memmap[SBSA_GWDT_CONTROL].base;
46
+ * One of these should have the LCD controller behind it; the others
61
+ DeviceState *dev = qdev_new(TYPE_WDT_SBSA);
47
+ * are connected only to the FPGA's "general purpose SPI connector"
62
+ SysBusDevice *s = SYS_BUS_DEVICE(dev);
48
+ * or "shield" expansion connectors.
63
+ int irq = sbsa_ref_irqmap[SBSA_GWDT];
49
+ * Note that if we do implement devices behind SPI, the chip select
50
+ * lines are set via the "MISC" register in the MPS2 FPGAIO device.
51
+ */
52
+ PL022State *spi = opaque;
53
+ int i = spi - &mms->spi[0];
54
+ DeviceState *iotkitdev = DEVICE(&mms->iotkit);
55
+ SysBusDevice *s;
56
+
64
+
57
+ sysbus_init_child_obj(OBJECT(mms), name, spi, sizeof(mms->spi[0]),
65
+ sysbus_realize_and_unref(s, &error_fatal);
58
+ TYPE_PL022);
66
+ sysbus_mmio_map(s, 0, rbase);
59
+ object_property_set_bool(OBJECT(spi), true, "realized", &error_fatal);
67
+ sysbus_mmio_map(s, 1, cbase);
60
+ s = SYS_BUS_DEVICE(spi);
68
+ sysbus_connect_irq(s, 0, qdev_get_gpio_in(sms->gic, irq));
61
+ sysbus_connect_irq(s, 0,
62
+ qdev_get_gpio_in_named(iotkitdev, "EXP_IRQ", 51 + i));
63
+ return sysbus_mmio_get_region(s, 0);
64
+}
69
+}
65
+
70
+
66
static void mps2tz_common_init(MachineState *machine)
71
static DeviceState *gpio_key_dev;
72
static void sbsa_ref_powerdown_req(Notifier *n, void *opaque)
67
{
73
{
68
MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine);
74
@@ -XXX,XX +XXX,XX @@ static void sbsa_ref_init(MachineState *machine)
69
@@ -XXX,XX +XXX,XX @@ static void mps2tz_common_init(MachineState *machine)
75
70
}, {
76
create_rtc(sms);
71
.name = "apb_ppcexp1",
77
72
.ports = {
78
+ create_wdt(sms);
73
- { "spi0", make_unimp_dev, &mms->spi[0], 0x40205000, 0x1000 },
79
+
74
- { "spi1", make_unimp_dev, &mms->spi[1], 0x40206000, 0x1000 },
80
create_gpio(sms);
75
- { "spi2", make_unimp_dev, &mms->spi[2], 0x40209000, 0x1000 },
81
76
- { "spi3", make_unimp_dev, &mms->spi[3], 0x4020a000, 0x1000 },
82
create_ahci(sms);
77
- { "spi4", make_unimp_dev, &mms->spi[4], 0x4020b000, 0x1000 },
78
+ { "spi0", make_spi, &mms->spi[0], 0x40205000, 0x1000 },
79
+ { "spi1", make_spi, &mms->spi[1], 0x40206000, 0x1000 },
80
+ { "spi2", make_spi, &mms->spi[2], 0x40209000, 0x1000 },
81
+ { "spi3", make_spi, &mms->spi[3], 0x4020a000, 0x1000 },
82
+ { "spi4", make_spi, &mms->spi[4], 0x4020b000, 0x1000 },
83
{ "uart0", make_uart, &mms->uart[0], 0x40200000, 0x1000 },
84
{ "uart1", make_uart, &mms->uart[1], 0x40201000, 0x1000 },
85
{ "uart2", make_uart, &mms->uart[2], 0x40202000, 0x1000 },
86
--
83
--
87
2.18.0
84
2.20.1
88
85
89
86
diff view generated by jsdifflib
1
Connect the VIRQ and VFIQ lines from the GIC to the CPU;
1
In ptimer_reload(), we call the callback function provided by the
2
these exist always for both CPU and GIC whether the
2
timer device that is using the ptimer. This callback might disable
3
virtualization extensions are enabled or not, so we
3
the ptimer. The code mostly handles this correctly, except that
4
can just unconditionally connect them.
4
we'll still print the warning about "Timer with delta zero,
5
disabling" if the now-disabled timer happened to be set such that it
6
would fire again immediately if it were enabled (eg because the
7
limit/reload value is zero).
8
9
Suppress the spurious warning message and the unnecessary
10
repeat-deletion of the underlying timer in this case.
5
11
6
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
12
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
7
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
13
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
Message-id: 20180821132811.17675-7-peter.maydell@linaro.org
14
Message-id: 20201015151829.14656-2-peter.maydell@linaro.org
9
---
15
---
10
hw/arm/fsl-imx7.c | 4 ++++
16
hw/core/ptimer.c | 4 ++++
11
1 file changed, 4 insertions(+)
17
1 file changed, 4 insertions(+)
12
18
13
diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c
19
diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c
14
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/arm/fsl-imx7.c
21
--- a/hw/core/ptimer.c
16
+++ b/hw/arm/fsl-imx7.c
22
+++ b/hw/core/ptimer.c
17
@@ -XXX,XX +XXX,XX @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
23
@@ -XXX,XX +XXX,XX @@ static void ptimer_reload(ptimer_state *s, int delta_adjust)
18
sysbus_connect_irq(sbd, i, irq);
19
irq = qdev_get_gpio_in(d, ARM_CPU_FIQ);
20
sysbus_connect_irq(sbd, i + smp_cpus, irq);
21
+ irq = qdev_get_gpio_in(d, ARM_CPU_VIRQ);
22
+ sysbus_connect_irq(sbd, i + 2 * smp_cpus, irq);
23
+ irq = qdev_get_gpio_in(d, ARM_CPU_VFIQ);
24
+ sysbus_connect_irq(sbd, i + 3 * smp_cpus, irq);
25
}
24
}
26
25
27
/*
26
if (delta == 0) {
27
+ if (s->enabled == 0) {
28
+ /* trigger callback disabled the timer already */
29
+ return;
30
+ }
31
if (!qtest_enabled()) {
32
fprintf(stderr, "Timer with delta zero, disabling\n");
33
}
28
--
34
--
29
2.18.0
35
2.20.1
30
36
31
37
diff view generated by jsdifflib
Deleted patch
1
Don't request that the arm_load_kernel() code should boot in secure
2
state if the CPU doesn't have a secure state. Currently this
3
doesn't make a difference because the boot.c code only examines
4
the secure_boot flag in code guarded by an ARM_FEATURE_EL3 check,
5
but upcoming changes for supporting booting into Hyp mode will
6
change that.
7
1
8
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
9
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
10
Message-id: 20180821132811.17675-9-peter.maydell@linaro.org
11
---
12
hw/arm/vexpress.c | 4 ++--
13
1 file changed, 2 insertions(+), 2 deletions(-)
14
15
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/arm/vexpress.c
18
+++ b/hw/arm/vexpress.c
19
@@ -XXX,XX +XXX,XX @@ static void vexpress_common_init(MachineState *machine)
20
daughterboard->bootinfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
21
daughterboard->bootinfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr;
22
daughterboard->bootinfo.modify_dtb = vexpress_modify_dtb;
23
- /* Indicate that when booting Linux we should be in secure state */
24
- daughterboard->bootinfo.secure_boot = true;
25
+ /* When booting Linux we should be in secure state if the CPU has one. */
26
+ daughterboard->bootinfo.secure_boot = vms->secure;
27
arm_load_kernel(ARM_CPU(first_cpu), &daughterboard->bootinfo);
28
}
29
30
--
31
2.18.0
32
33
diff view generated by jsdifflib
Deleted patch
1
The kernel booting specification for an AArch32 kernel requires that
2
it is booted in Hyp mode if available; otherwise the kernel can't
3
enable KVM. We were incorrectly leaving the kernel in SVC mode.
4
If we're booting an AArch32 kernel in the Nonsecure state and Hyp
5
mode is available, start in it.
6
1
7
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
8
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
9
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
10
Reviewed-by: Luc Michel <luc.michel@greensocs.com>
11
Message-id: 20180820153020.21478-7-peter.maydell@linaro.org
12
---
13
hw/arm/boot.c | 11 +++++++++++
14
1 file changed, 11 insertions(+)
15
16
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/arm/boot.c
19
+++ b/hw/arm/boot.c
20
@@ -XXX,XX +XXX,XX @@ static void do_cpu_reset(void *opaque)
21
}
22
}
23
24
+ if (!env->aarch64 && !info->secure_boot &&
25
+ arm_feature(env, ARM_FEATURE_EL2)) {
26
+ /*
27
+ * This is an AArch32 boot not to Secure state, and
28
+ * we have Hyp mode available, so boot the kernel into
29
+ * Hyp mode. This is not how the CPU comes out of reset,
30
+ * so we need to manually put it there.
31
+ */
32
+ cpsr_write(env, ARM_CPU_MODE_HYP, CPSR_M, CPSRWriteRaw);
33
+ }
34
+
35
if (cs == first_cpu) {
36
AddressSpace *as = arm_boot_address_space(cpu, info);
37
38
--
39
2.18.0
40
41
diff view generated by jsdifflib
1
In the MPS2 FPGAIO, PSCNTR is a free-running downcounter with
1
The armv7m systick timer is a 24-bit decrementing, wrap-on-zero,
2
a reload value configured via the PRESCALE register, and
2
clear-on-write counter. Our current implementation has various
3
COUNTER counts up by 1 every time PSCNTR reaches zero.
3
bugs and dubious workarounds in it (for instance see
4
Implement these counters.
4
https://bugs.launchpad.net/qemu/+bug/1872237).
5
5
6
We can just increment the counters migration subsection's
6
We have an implementation of a simple decrementing counter
7
version ID because we only added it in the previous commit,
7
and we put a lot of effort into making sure it handles the
8
so no released QEMU versions will be using it.
8
interesting corner cases (like "spend a cycle at 0 before
9
reloading") -- ptimer.
10
11
Rewrite the systick timer to use a ptimer rather than
12
a raw QEMU timer.
13
14
Unfortunately this is a migration compatibility break,
15
which will affect all M-profile boards.
16
17
Among other bugs, this fixes
18
https://bugs.launchpad.net/qemu/+bug/1872237 :
19
now writes to SYST_CVR when the timer is enabled correctly
20
do nothing; when the timer is enabled via SYST_CSR.ENABLE,
21
the ptimer code will (because of POLICY_NO_IMMEDIATE_RELOAD)
22
arrange that after one timer tick the counter is reloaded
23
from SYST_RVR and then counts down from there, as the
24
architecture requires.
9
25
10
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
26
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
11
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
27
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
12
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
28
Message-id: 20201015151829.14656-3-peter.maydell@linaro.org
13
Message-id: 20180820141116.9118-3-peter.maydell@linaro.org
14
---
29
---
15
include/hw/misc/mps2-fpgaio.h | 6 +++
30
include/hw/timer/armv7m_systick.h | 3 +-
16
hw/misc/mps2-fpgaio.c | 97 +++++++++++++++++++++++++++++++++--
31
hw/timer/armv7m_systick.c | 124 +++++++++++++-----------------
17
2 files changed, 99 insertions(+), 4 deletions(-)
32
2 files changed, 54 insertions(+), 73 deletions(-)
18
33
19
diff --git a/include/hw/misc/mps2-fpgaio.h b/include/hw/misc/mps2-fpgaio.h
34
diff --git a/include/hw/timer/armv7m_systick.h b/include/hw/timer/armv7m_systick.h
20
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
21
--- a/include/hw/misc/mps2-fpgaio.h
36
--- a/include/hw/timer/armv7m_systick.h
22
+++ b/include/hw/misc/mps2-fpgaio.h
37
+++ b/include/hw/timer/armv7m_systick.h
23
@@ -XXX,XX +XXX,XX @@ typedef struct {
38
@@ -XXX,XX +XXX,XX @@
24
uint32_t prescale;
39
25
uint32_t misc;
40
#include "hw/sysbus.h"
26
41
#include "qom/object.h"
27
+ /* QEMU_CLOCK_VIRTUAL time at which counter and pscntr were last synced */
42
+#include "hw/ptimer.h"
28
+ int64_t pscntr_sync_ticks;
43
29
+ /* Values of COUNTER and PSCNTR at time pscntr_sync_ticks */
44
#define TYPE_SYSTICK "armv7m_systick"
30
+ uint32_t counter;
45
31
+ uint32_t pscntr;
46
@@ -XXX,XX +XXX,XX @@ struct SysTickState {
47
uint32_t control;
48
uint32_t reload;
49
int64_t tick;
50
- QEMUTimer *timer;
51
+ ptimer_state *ptimer;
52
MemoryRegion iomem;
53
qemu_irq irq;
54
};
55
diff --git a/hw/timer/armv7m_systick.c b/hw/timer/armv7m_systick.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/hw/timer/armv7m_systick.c
58
+++ b/hw/timer/armv7m_systick.c
59
@@ -XXX,XX +XXX,XX @@ static inline int64_t systick_scale(SysTickState *s)
60
}
61
}
62
63
-static void systick_reload(SysTickState *s, int reset)
64
-{
65
- /* The Cortex-M3 Devices Generic User Guide says that "When the
66
- * ENABLE bit is set to 1, the counter loads the RELOAD value from the
67
- * SYST RVR register and then counts down". So, we need to check the
68
- * ENABLE bit before reloading the value.
69
- */
70
- trace_systick_reload();
71
-
72
- if ((s->control & SYSTICK_ENABLE) == 0) {
73
- return;
74
- }
75
-
76
- if (reset) {
77
- s->tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
78
- }
79
- s->tick += (s->reload + 1) * systick_scale(s);
80
- timer_mod(s->timer, s->tick);
81
-}
82
-
83
static void systick_timer_tick(void *opaque)
84
{
85
SysTickState *s = (SysTickState *)opaque;
86
@@ -XXX,XX +XXX,XX @@ static void systick_timer_tick(void *opaque)
87
/* Tell the NVIC to pend the SysTick exception */
88
qemu_irq_pulse(s->irq);
89
}
90
- if (s->reload == 0) {
91
- s->control &= ~SYSTICK_ENABLE;
92
- } else {
93
- systick_reload(s, 0);
94
+ if (ptimer_get_limit(s->ptimer) == 0) {
95
+ /*
96
+ * Timer expiry with SYST_RVR zero disables the timer
97
+ * (but doesn't clear SYST_CSR.ENABLE)
98
+ */
99
+ ptimer_stop(s->ptimer);
100
}
101
}
102
103
@@ -XXX,XX +XXX,XX @@ static MemTxResult systick_read(void *opaque, hwaddr addr, uint64_t *data,
104
s->control &= ~SYSTICK_COUNTFLAG;
105
break;
106
case 0x4: /* SysTick Reload Value. */
107
- val = s->reload;
108
+ val = ptimer_get_limit(s->ptimer);
109
break;
110
case 0x8: /* SysTick Current Value. */
111
- {
112
- int64_t t;
113
-
114
- if ((s->control & SYSTICK_ENABLE) == 0) {
115
- val = 0;
116
- break;
117
- }
118
- t = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
119
- if (t >= s->tick) {
120
- val = 0;
121
- break;
122
- }
123
- val = ((s->tick - (t + 1)) / systick_scale(s)) + 1;
124
- /* The interrupt in triggered when the timer reaches zero.
125
- However the counter is not reloaded until the next clock
126
- tick. This is a hack to return zero during the first tick. */
127
- if (val > s->reload) {
128
- val = 0;
129
- }
130
+ val = ptimer_get_count(s->ptimer);
131
break;
132
- }
133
case 0xc: /* SysTick Calibration Value. */
134
val = 10000;
135
break;
136
@@ -XXX,XX +XXX,XX @@ static MemTxResult systick_write(void *opaque, hwaddr addr,
137
switch (addr) {
138
case 0x0: /* SysTick Control and Status. */
139
{
140
- uint32_t oldval = s->control;
141
+ uint32_t oldval;
142
143
+ ptimer_transaction_begin(s->ptimer);
144
+ oldval = s->control;
145
s->control &= 0xfffffff8;
146
s->control |= value & 7;
32
+
147
+
33
uint32_t prescale_clk;
148
if ((oldval ^ value) & SYSTICK_ENABLE) {
34
149
- int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
35
/* These hold the CLOCK_VIRTUAL ns tick when the CLK1HZ/CLK100HZ was zero */
150
if (value & SYSTICK_ENABLE) {
36
diff --git a/hw/misc/mps2-fpgaio.c b/hw/misc/mps2-fpgaio.c
151
- if (s->tick) {
37
index XXXXXXX..XXXXXXX 100644
152
- s->tick += now;
38
--- a/hw/misc/mps2-fpgaio.c
153
- timer_mod(s->timer, s->tick);
39
+++ b/hw/misc/mps2-fpgaio.c
154
- } else {
40
@@ -XXX,XX +XXX,XX @@ static int64_t tickoff_from_counter(int64_t now, uint32_t count, int frq)
155
- systick_reload(s, 1);
41
return now - muldiv64(count, NANOSECONDS_PER_SECOND, frq);
156
- }
42
}
157
+ /*
43
158
+ * Always reload the period in case board code has
44
+static void resync_counter(MPS2FPGAIO *s)
159
+ * changed system_clock_scale. If we ever replace that
45
+{
160
+ * global with a more sensible API then we might be able
46
+ /*
161
+ * to set the period only when it actually changes.
47
+ * Update s->counter and s->pscntr to their true current values
162
+ */
48
+ * by calculating how many times PSCNTR has ticked since the
163
+ ptimer_set_period(s->ptimer, systick_scale(s));
49
+ * last time we did a resync.
164
+ ptimer_run(s->ptimer, 0);
50
+ */
165
} else {
51
+ int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
166
- timer_del(s->timer);
52
+ int64_t elapsed = now - s->pscntr_sync_ticks;
167
- s->tick -= now;
53
+
168
- if (s->tick < 0) {
54
+ /*
169
- s->tick = 0;
55
+ * Round elapsed down to a whole number of PSCNTR ticks, so we don't
170
- }
56
+ * lose time if we do multiple resyncs in a single tick.
171
+ ptimer_stop(s->ptimer);
57
+ */
172
}
58
+ uint64_t ticks = muldiv64(elapsed, s->prescale_clk, NANOSECONDS_PER_SECOND);
173
} else if ((oldval ^ value) & SYSTICK_CLKSOURCE) {
59
+
174
- /* This is a hack. Force the timer to be reloaded
60
+ /*
175
- when the reference clock is changed. */
61
+ * Work out what PSCNTR and COUNTER have moved to. We assume that
176
- systick_reload(s, 1);
62
+ * PSCNTR reloads from PRESCALE one tick-period after it hits zero,
177
+ ptimer_set_period(s->ptimer, systick_scale(s));
63
+ * and that COUNTER increments at the same moment.
178
}
64
+ */
179
+ ptimer_transaction_commit(s->ptimer);
65
+ if (ticks == 0) {
180
break;
66
+ /* We haven't ticked since the last time we were asked */
181
}
67
+ return;
182
case 0x4: /* SysTick Reload Value. */
68
+ } else if (ticks < s->pscntr) {
183
- s->reload = value;
69
+ /* We haven't yet reached zero, just reduce the PSCNTR */
184
+ ptimer_transaction_begin(s->ptimer);
70
+ s->pscntr -= ticks;
185
+ ptimer_set_limit(s->ptimer, value & 0xffffff, 0);
71
+ } else {
186
+ ptimer_transaction_commit(s->ptimer);
72
+ if (s->prescale == 0) {
187
break;
73
+ /*
188
- case 0x8: /* SysTick Current Value. Writes reload the timer. */
74
+ * If the reload value is zero then the PSCNTR will stick
189
- systick_reload(s, 1);
75
+ * at zero once it reaches it, and so we will increment
190
+ case 0x8: /* SysTick Current Value. */
76
+ * COUNTER every tick after that.
191
+ /*
77
+ */
192
+ * Writing any value clears SYST_CVR to zero and clears
78
+ s->counter += ticks - s->pscntr;
193
+ * SYST_CSR.COUNTFLAG. The counter will then reload from SYST_RVR
79
+ s->pscntr = 0;
194
+ * on the next clock edge unless SYST_RVR is zero.
80
+ } else {
195
+ */
81
+ /*
196
+ ptimer_transaction_begin(s->ptimer);
82
+ * This is the complicated bit. This ASCII art diagram gives an
197
+ if (ptimer_get_limit(s->ptimer) == 0) {
83
+ * example with PRESCALE==5 PSCNTR==7:
198
+ ptimer_stop(s->ptimer);
84
+ *
85
+ * ticks 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
86
+ * PSCNTR 7 6 5 4 3 2 1 0 5 4 3 2 1 0 5
87
+ * cinc 1 2
88
+ * y 0 1 2 3 4 5 6 7 8 9 10 11 12
89
+ * x 0 1 2 3 4 5 0 1 2 3 4 5 0
90
+ *
91
+ * where x = y % (s->prescale + 1)
92
+ * and so PSCNTR = s->prescale - x
93
+ * and COUNTER is incremented by y / (s->prescale + 1)
94
+ *
95
+ * The case where PSCNTR < PRESCALE works out the same,
96
+ * though we must be careful to calculate y as 64-bit unsigned
97
+ * for all parts of the expression.
98
+ * y < 0 is not possible because that implies ticks < s->pscntr.
99
+ */
100
+ uint64_t y = ticks - s->pscntr + s->prescale;
101
+ s->pscntr = s->prescale - (y % (s->prescale + 1));
102
+ s->counter += y / (s->prescale + 1);
103
+ }
199
+ }
104
+ }
200
+ ptimer_set_count(s->ptimer, 0);
105
+
201
s->control &= ~SYSTICK_COUNTFLAG;
106
+ /*
202
+ ptimer_transaction_commit(s->ptimer);
107
+ * Only advance the sync time to the timestamp of the last PSCNTR tick,
108
+ * not all the way to 'now', so we don't lose time if we do multiple
109
+ * resyncs in a single tick.
110
+ */
111
+ s->pscntr_sync_ticks += muldiv64(ticks, NANOSECONDS_PER_SECOND,
112
+ s->prescale_clk);
113
+}
114
+
115
static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size)
116
{
117
MPS2FPGAIO *s = MPS2_FPGAIO(opaque);
118
@@ -XXX,XX +XXX,XX @@ static uint64_t mps2_fpgaio_read(void *opaque, hwaddr offset, unsigned size)
119
r = counter_from_tickoff(now, s->clk100hz_tick_offset, 100);
120
break;
121
case A_COUNTER:
122
+ resync_counter(s);
123
+ r = s->counter;
124
+ break;
125
case A_PSCNTR:
126
- qemu_log_mask(LOG_UNIMP, "MPS2 FPGAIO: counters unimplemented\n");
127
- r = 0;
128
+ resync_counter(s);
129
+ r = s->pscntr;
130
break;
203
break;
131
default:
204
default:
132
qemu_log_mask(LOG_GUEST_ERROR,
205
qemu_log_mask(LOG_GUEST_ERROR,
133
@@ -XXX,XX +XXX,XX @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value,
206
@@ -XXX,XX +XXX,XX @@ static void systick_reset(DeviceState *dev)
134
s->led0 = value & 0x3;
207
*/
135
break;
208
assert(system_clock_scale != 0);
136
case A_PRESCALE:
209
137
+ resync_counter(s);
210
+ ptimer_transaction_begin(s->ptimer);
138
s->prescale = value;
211
s->control = 0;
139
break;
212
- s->reload = 0;
140
case A_MISC:
213
- s->tick = 0;
141
@@ -XXX,XX +XXX,XX @@ static void mps2_fpgaio_write(void *opaque, hwaddr offset, uint64_t value,
214
- timer_del(s->timer);
142
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
215
+ ptimer_stop(s->ptimer);
143
s->clk100hz_tick_offset = tickoff_from_counter(now, value, 100);
216
+ ptimer_set_count(s->ptimer, 0);
144
break;
217
+ ptimer_set_limit(s->ptimer, 0, 0);
145
+ case A_COUNTER:
218
+ ptimer_set_period(s->ptimer, systick_scale(s));
146
+ resync_counter(s);
219
+ ptimer_transaction_commit(s->ptimer);
147
+ s->counter = value;
220
}
148
+ break;
221
149
+ case A_PSCNTR:
222
static void systick_instance_init(Object *obj)
150
+ resync_counter(s);
223
@@ -XXX,XX +XXX,XX @@ static void systick_instance_init(Object *obj)
151
+ s->pscntr = value;
224
static void systick_realize(DeviceState *dev, Error **errp)
152
+ break;
225
{
153
default:
226
SysTickState *s = SYSTICK(dev);
154
qemu_log_mask(LOG_GUEST_ERROR,
227
- s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, systick_timer_tick, s);
155
"MPS2 FPGAIO write: bad offset 0x%x\n", (int) offset);
228
+ s->ptimer = ptimer_init(systick_timer_tick, s,
156
@@ -XXX,XX +XXX,XX @@ static void mps2_fpgaio_reset(DeviceState *dev)
229
+ PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD |
157
s->misc = 0;
230
+ PTIMER_POLICY_NO_COUNTER_ROUND_DOWN |
158
s->clk1hz_tick_offset = tickoff_from_counter(now, 0, 1);
231
+ PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
159
s->clk100hz_tick_offset = tickoff_from_counter(now, 0, 100);
232
+ PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT);
160
+ s->counter = 0;
233
}
161
+ s->pscntr = 0;
234
162
+ s->pscntr_sync_ticks = now;
235
static const VMStateDescription vmstate_systick = {
163
}
236
.name = "armv7m_systick",
164
165
static void mps2_fpgaio_init(Object *obj)
166
@@ -XXX,XX +XXX,XX @@ static bool mps2_fpgaio_counters_needed(void *opaque)
167
168
static const VMStateDescription mps2_fpgaio_counters_vmstate = {
169
.name = "mps2-fpgaio/counters",
170
- .version_id = 1,
237
- .version_id = 1,
171
- .minimum_version_id = 1,
238
- .minimum_version_id = 1,
172
+ .version_id = 2,
239
+ .version_id = 2,
173
+ .minimum_version_id = 2,
240
+ .minimum_version_id = 2,
174
.needed = mps2_fpgaio_counters_needed,
175
.fields = (VMStateField[]) {
241
.fields = (VMStateField[]) {
176
VMSTATE_INT64(clk1hz_tick_offset, MPS2FPGAIO),
242
VMSTATE_UINT32(control, SysTickState),
177
VMSTATE_INT64(clk100hz_tick_offset, MPS2FPGAIO),
243
- VMSTATE_UINT32(reload, SysTickState),
178
+ VMSTATE_UINT32(counter, MPS2FPGAIO),
244
VMSTATE_INT64(tick, SysTickState),
179
+ VMSTATE_UINT32(pscntr, MPS2FPGAIO),
245
- VMSTATE_TIMER_PTR(timer, SysTickState),
180
+ VMSTATE_INT64(pscntr_sync_ticks, MPS2FPGAIO),
246
+ VMSTATE_PTIMER(ptimer, SysTickState),
181
VMSTATE_END_OF_LIST()
247
VMSTATE_END_OF_LIST()
182
}
248
}
183
};
249
};
184
--
250
--
185
2.18.0
251
2.20.1
186
252
187
253
diff view generated by jsdifflib
Deleted patch
1
The MPS2 FPGA images for the Cortex-M3 (mps2-an385 and mps2-511)
2
both include a CMSDK dual-timer module. Wire this up.
3
1
4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
5
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
7
Message-id: 20180820141116.9118-6-peter.maydell@linaro.org
8
---
9
hw/arm/mps2.c | 11 +++++++++++
10
1 file changed, 11 insertions(+)
11
12
diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/arm/mps2.c
15
+++ b/hw/arm/mps2.c
16
@@ -XXX,XX +XXX,XX @@
17
#include "hw/misc/unimp.h"
18
#include "hw/char/cmsdk-apb-uart.h"
19
#include "hw/timer/cmsdk-apb-timer.h"
20
+#include "hw/timer/cmsdk-apb-dualtimer.h"
21
#include "hw/misc/mps2-scc.h"
22
#include "hw/devices.h"
23
#include "net/net.h"
24
@@ -XXX,XX +XXX,XX @@ typedef struct {
25
MemoryRegion blockram_m3;
26
MemoryRegion sram;
27
MPS2SCC scc;
28
+ CMSDKAPBDualTimer dualtimer;
29
} MPS2MachineState;
30
31
#define TYPE_MPS2_MACHINE "mps2"
32
@@ -XXX,XX +XXX,XX @@ static void mps2_common_init(MachineState *machine)
33
cmsdk_apb_timer_create(0x40000000, qdev_get_gpio_in(armv7m, 8), SYSCLK_FRQ);
34
cmsdk_apb_timer_create(0x40001000, qdev_get_gpio_in(armv7m, 9), SYSCLK_FRQ);
35
36
+ sysbus_init_child_obj(OBJECT(mms), "dualtimer", &mms->dualtimer,
37
+ sizeof(mms->dualtimer), TYPE_CMSDK_APB_DUALTIMER);
38
+ qdev_prop_set_uint32(DEVICE(&mms->dualtimer), "pclk-frq", SYSCLK_FRQ);
39
+ object_property_set_bool(OBJECT(&mms->dualtimer), true, "realized",
40
+ &error_fatal);
41
+ sysbus_connect_irq(SYS_BUS_DEVICE(&mms->dualtimer), 0,
42
+ qdev_get_gpio_in(armv7m, 10));
43
+ sysbus_mmio_map(SYS_BUS_DEVICE(&mms->dualtimer), 0, 0x40002000);
44
+
45
object_initialize(&mms->scc, sizeof(mms->scc), TYPE_MPS2_SCC);
46
sccdev = DEVICE(&mms->scc);
47
qdev_set_parent_bus(sccdev, sysbus_get_default());
48
--
49
2.18.0
50
51
diff view generated by jsdifflib