target-arm queue:

* hw/arm/smmuv3: Fill u.f_cd_fetch.addr for SMMU_EVT_F_CD_FETCH
  * hw/arm/virt: Support larger highmem MMIO regions
  * machine: Centralize -machine dumpdtb option handling and report
    attempt to dump nonexistent DTB as an error
  * fpu: remove target ifdefs and build it only once
  * target/arm: Refactor to move TCG-only vfp_helper code into tcg/
  * target/arm/hvf: Disable SME feature
  * target/arm/hvf: sign extend the data for a load operation when SSE=1
  * hw/misc/npcm_clk: fix buffer-overflow
  * hw/arm: Add i.MX 8M Plus EVK board ("imx8mp-evk")
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAme+BaQZHHBldGVyLm1h
 eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3kG0EACuWqAhqYdn2muu1Rc3WQMh
 uMOdb/f7oaqbCpeBEdV1dazWfZJQ1Zk05J31t+tdoYowqM7nS55Vw9zrSntoC6Ll
 IYRzBmGWE+FnsODKhA0wx/lQO08GeMTrkHoGM72hiwIjbuC/Nps9aOQ2GH6WOCjN
 TACXF1dYNpoy+H979yIwGMWH1SSgn1fS+9zw3LsKCGtbnt7g80DyWpb6qlfKPJ78
 KHmpth//sCPbu6UtsFKTBlIb0dYtAWTnRoS834WBq9bw51OPh81WoApSBkjV479z
 kTcLyaJnoTKsPnz+6A/z3Fm/qi4aATk4/eCCT2ry3Oyi3ffafSlBf/KiFqAZ0Fue
 vq6/b/wsVTdyjnkcptmCHJ+6qEhPshNi3F4hu8YOFQsx+6zFR7NUkZrNt/IQIhZB
 DOcjtMFymg/duEbRW9RdLeVC3Ds2qVuxnzEbLmNJntBp+jkhm5QkWf6ZEJ6iviOf
 tSP+SLOFyCT71BdQSIMhLJHS9UPJ3vzgGkN54YCLDYg24aNCMSe0nqLFMxfchQJm
 njn1BdyX4pDibXv6tdDJdtOv3sLgvVaZZKEGlTGtNx8kq8qmXnzIJl6iQSBTrmD5
 qMb4NxaYG6hpzSQOV+XxLQ1BdLNj2qXs90EU1Jqfp378sOdl6Oyx5po5NIcyp36o
 g+GsbLqphJL4DkosoH8eFA==
 =MBWK
 -----END PGP SIGNATURE-----

Merge tag 'pull-target-arm-20250225' of https://git.linaro.org/people/pmaydell/qemu-arm into staging

target-arm queue:
 * hw/arm/smmuv3: Fill u.f_cd_fetch.addr for SMMU_EVT_F_CD_FETCH
 * hw/arm/virt: Support larger highmem MMIO regions
 * machine: Centralize -machine dumpdtb option handling and report
   attempt to dump nonexistent DTB as an error
 * fpu: remove target ifdefs and build it only once
 * target/arm: Refactor to move TCG-only vfp_helper code into tcg/
 * target/arm/hvf: Disable SME feature
 * target/arm/hvf: sign extend the data for a load operation when SSE=1
 * hw/misc/npcm_clk: fix buffer-overflow
 * hw/arm: Add i.MX 8M Plus EVK board ("imx8mp-evk")

# -----BEGIN PGP SIGNATURE-----
#
# iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAme+BaQZHHBldGVyLm1h
# eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3kG0EACuWqAhqYdn2muu1Rc3WQMh
# uMOdb/f7oaqbCpeBEdV1dazWfZJQ1Zk05J31t+tdoYowqM7nS55Vw9zrSntoC6Ll
# IYRzBmGWE+FnsODKhA0wx/lQO08GeMTrkHoGM72hiwIjbuC/Nps9aOQ2GH6WOCjN
# TACXF1dYNpoy+H979yIwGMWH1SSgn1fS+9zw3LsKCGtbnt7g80DyWpb6qlfKPJ78
# KHmpth//sCPbu6UtsFKTBlIb0dYtAWTnRoS834WBq9bw51OPh81WoApSBkjV479z
# kTcLyaJnoTKsPnz+6A/z3Fm/qi4aATk4/eCCT2ry3Oyi3ffafSlBf/KiFqAZ0Fue
# vq6/b/wsVTdyjnkcptmCHJ+6qEhPshNi3F4hu8YOFQsx+6zFR7NUkZrNt/IQIhZB
# DOcjtMFymg/duEbRW9RdLeVC3Ds2qVuxnzEbLmNJntBp+jkhm5QkWf6ZEJ6iviOf
# tSP+SLOFyCT71BdQSIMhLJHS9UPJ3vzgGkN54YCLDYg24aNCMSe0nqLFMxfchQJm
# njn1BdyX4pDibXv6tdDJdtOv3sLgvVaZZKEGlTGtNx8kq8qmXnzIJl6iQSBTrmD5
# qMb4NxaYG6hpzSQOV+XxLQ1BdLNj2qXs90EU1Jqfp378sOdl6Oyx5po5NIcyp36o
# g+GsbLqphJL4DkosoH8eFA==
# =MBWK
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed 26 Feb 2025 02:02:12 HKT
# gpg:                using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg:                issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [full]
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>" [full]
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [full]
# gpg:                 aka "Peter Maydell <peter@archaic.org.uk>" [unknown]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* tag 'pull-target-arm-20250225' of https://git.linaro.org/people/pmaydell/qemu-arm: (43 commits)
  hw/arm/fsl-imx8mp: Add on-chip RAM
  hw/arm/fsl-imx8mp: Add USB support
  hw/arm/fsl-imx8mp: Add Ethernet controller
  hw/arm/fsl-imx8mp: Implement general purpose timers
  hw/arm/fsl-imx8mp: Add watchdog support
  hw/arm/fsl-imx8mp: Add SPI controllers
  hw/arm/fsl-imx8mp: Add I2C controllers
  hw/arm/fsl-imx8mp: Add GPIO controllers
  hw/arm/fsl-imx8mp: Add PCIe support
  hw/arm/fsl-imx8mp: Add USDHC storage controllers
  hw/arm/fsl-imx8mp: Add SNVS
  hw/arm/fsl-imx8mp: Implement clock tree
  hw/arm: Add i.MX 8M Plus EVK board
  hw/gpio/pca955*: Move Kconfig switches next to implementations
  hw/pci-host/designware: Prevent device attachment on internal PCIe root bus
  hw/usb/hcd-dwc3: Align global registers size with Linux
  hw/misc/npcm_clk: fix buffer-overflow
  target/arm/hvf: sign extend the data for a load operation when SSE=1
  target/arm/hvf: Disable SME feature
  target/arm: Rename vfp_helper.c to vfp_fpscr.c
  ...

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2025-03-03 10:20:03 +08:00
commit 09951f5a27
68 changed files with 2439 additions and 383 deletions

View file

@ -820,6 +820,19 @@ F: hw/pci-host/designware.c
F: include/hw/pci-host/designware.h
F: docs/system/arm/mcimx7d-sabre.rst
MCIMX8MP-EVK / i.MX8MP
M: Bernhard Beschow <shentey@gmail.com>
L: qemu-arm@nongnu.org
S: Maintained
F: hw/arm/imx8mp-evk.c
F: hw/arm/fsl-imx8mp.c
F: hw/misc/imx8mp_*.c
F: hw/pci-host/fsl_imx8m_phy.c
F: include/hw/arm/fsl-imx8mp.h
F: include/hw/misc/imx8mp_*.h
F: include/hw/pci-host/fsl_imx8m_phy.h
F: docs/system/arm/imx8mp-evk.rst
MPS2 / MPS3
M: Peter Maydell <peter.maydell@linaro.org>
L: qemu-arm@nongnu.org

View file

@ -0,0 +1,70 @@
NXP i.MX 8M Plus Evaluation Kit (``imx8mp-evk``)
================================================
The ``imx8mp-evk`` machine models the i.MX 8M Plus Evaluation Kit, based on an
i.MX 8M Plus SoC.
Supported devices
-----------------
The ``imx8mp-evk`` machine implements the following devices:
* Up to 4 Cortex-A53 cores
* Generic Interrupt Controller (GICv3)
* 4 UARTs
* 3 USDHC Storage Controllers
* 1 Designware PCI Express Controller
* 1 Ethernet Controller
* 2 Designware USB 3 Controllers
* 5 GPIO Controllers
* 6 I2C Controllers
* 3 SPI Controllers
* 3 Watchdogs
* 6 General Purpose Timers
* Secure Non-Volatile Storage (SNVS) including an RTC
* Clock Tree
Boot options
------------
The ``imx8mp-evk`` machine can start a Linux kernel directly using the standard
``-kernel`` functionality.
Direct Linux Kernel Boot
''''''''''''''''''''''''
Probably the easiest way to get started with a whole Linux system on the machine
is to generate an image with Buildroot. Version 2024.11.1 is tested at the time
of writing and involves three steps. First run the following commands in the
toplevel directory of the Buildroot source tree:
.. code-block:: bash
$ make freescale_imx8mpevk_defconfig
$ make
Once finished successfully there is an ``output/image`` subfolder. Navigate into
it and resize the SD card image to a power of two:
.. code-block:: bash
$ qemu-img resize sdcard.img 256M
Finally, the device tree needs to be patched with the following commands which
will remove the ``cpu-idle-states`` properties from CPU nodes:
.. code-block:: bash
$ dtc imx8mp-evk.dtb | sed '/cpu-idle-states/d' > imx8mp-evk-patched.dts
$ dtc imx8mp-evk-patched.dts -o imx8mp-evk-patched.dtb
Now that everything is prepared the machine can be started as follows:
.. code-block:: bash
$ qemu-system-aarch64 -M imx8mp-evk -smp 4 -m 3G \
-display none -serial null -serial stdio \
-kernel Image \
-dtb imx8mp-evk-patched.dtb \
-append "root=/dev/mmcblk2p2" \
-drive file=sdcard.img,if=sd,bus=2,format=raw,id=mmcblk2

View file

@ -144,6 +144,10 @@ highmem-mmio
Set ``on``/``off`` to enable/disable the high memory region for PCI MMIO.
The default is ``on``.
highmem-mmio-size
Set the high memory region size for PCI MMIO. Must be a power of 2 and
greater than or equal to the default size (512G).
gic-version
Specify the version of the Generic Interrupt Controller (GIC) to provide.
Valid values are:

View file

@ -95,6 +95,7 @@ Board-specific documentation
arm/imx25-pdk
arm/mcimx6ul-evk
arm/mcimx7d-sabre
arm/imx8mp-evk
arm/orangepi
arm/raspi
arm/collie

View file

@ -1 +1 @@
specific_ss.add(when: 'CONFIG_TCG', if_true: files('softfloat.c'))
common_ss.add(when: 'CONFIG_TCG', if_true: files('softfloat.c'))

View file

@ -195,6 +195,25 @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
static void partsN(canonicalize)(FloatPartsN *p, float_status *status,
const FloatFmt *fmt)
{
/*
* It's target-dependent how to handle the case of exponent 0
* and Integer bit set. Intel calls these "pseudodenormals",
* and treats them as if the integer bit was 0, and never
* produces them on output. This is the default behaviour for QEMU.
* For m68k, the integer bit is considered validly part of the
* input value when the exponent is 0, and may be 0 or 1,
* giving extra range. They may also be generated as outputs.
* (The m68k manual actually calls these values part of the
* normalized number range, not the denormalized number range,
* but that distinction is not important for us, because
* m68k doesn't care about the input_denormal_used status flag.)
* floatx80_pseudo_denormal_valid selects the m68k behaviour,
* which changes both how we canonicalize such a value and
* how we uncanonicalize results.
*/
bool has_pseudo_denormals = fmt->has_explicit_bit &&
(status->floatx80_behaviour & floatx80_pseudo_denormal_valid);
if (unlikely(p->exp == 0)) {
if (likely(frac_eqz(p))) {
p->cls = float_class_zero;
@ -206,7 +225,7 @@ static void partsN(canonicalize)(FloatPartsN *p, float_status *status,
int shift = frac_normalize(p);
p->cls = float_class_denormal;
p->exp = fmt->frac_shift - fmt->exp_bias
- shift + !fmt->m68k_denormal;
- shift + !has_pseudo_denormals;
}
} else if (likely(p->exp < fmt->exp_max) || fmt->arm_althp) {
p->cls = float_class_normal;
@ -342,13 +361,15 @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s,
frac_clear(p);
} else {
bool is_tiny = s->tininess_before_rounding || exp < 0;
bool has_pseudo_denormals = fmt->has_explicit_bit &&
(s->floatx80_behaviour & floatx80_pseudo_denormal_valid);
if (!is_tiny) {
FloatPartsN discard;
is_tiny = !frac_addi(&discard, p, inc);
}
frac_shrjam(p, !fmt->m68k_denormal - exp);
frac_shrjam(p, !has_pseudo_denormals - exp);
if (p->frac_lo & round_mask) {
/* Need to recompute round-to-even/round-to-odd. */
@ -379,7 +400,7 @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s,
p->frac_lo &= ~round_mask;
}
exp = (p->frac_hi & DECOMPOSED_IMPLICIT_BIT) && !fmt->m68k_denormal;
exp = (p->frac_hi & DECOMPOSED_IMPLICIT_BIT) && !has_pseudo_denormals;
frac_shr(p, frac_shift);
if (is_tiny) {

View file

@ -85,11 +85,7 @@ this code that are retained.
*/
static inline bool no_signaling_nans(float_status *status)
{
#if defined(TARGET_XTENSA)
return status->no_signaling_nans;
#else
return false;
#endif
}
/* Define how the architecture discriminates signaling NaNs.
@ -97,17 +93,10 @@ static inline bool no_signaling_nans(float_status *status)
* In IEEE 754-1985 this was implementation defined, but in IEEE 754-2008
* the msb must be zero. MIPS is (so far) unique in supporting both the
* 2008 revision and backward compatibility with their original choice.
* Thus for MIPS we must make the choice at runtime.
*/
static inline bool snan_bit_is_one(float_status *status)
{
#if defined(TARGET_MIPS)
return status->snan_bit_is_one;
#elif defined(TARGET_HPPA) || defined(TARGET_SH4)
return 1;
#else
return 0;
#endif
}
/*----------------------------------------------------------------------------
@ -227,15 +216,15 @@ floatx80 floatx80_default_nan(float_status *status)
| The pattern for a default generated extended double-precision inf.
*----------------------------------------------------------------------------*/
#define floatx80_infinity_high 0x7FFF
#if defined(TARGET_M68K)
#define floatx80_infinity_low UINT64_C(0x0000000000000000)
#else
#define floatx80_infinity_low UINT64_C(0x8000000000000000)
#endif
const floatx80 floatx80_infinity
= make_floatx80_init(floatx80_infinity_high, floatx80_infinity_low);
floatx80 floatx80_default_inf(bool zSign, float_status *status)
{
/*
* Whether the Integer bit is set in the default Infinity is
* target dependent.
*/
bool z = status->floatx80_behaviour & floatx80_default_inf_int_bit_is_zero;
return packFloatx80(zSign, 0x7fff, z ? 0 : (1ULL << 63));
}
/*----------------------------------------------------------------------------
| Returns 1 if the half-precision floating-point value `a' is a quiet

View file

@ -79,9 +79,6 @@ this code that are retained.
* version 2 or later. See the COPYING file in the top-level directory.
*/
/* softfloat (and in particular the code in softfloat-specialize.h) is
* target-dependent and needs the TARGET_* macros.
*/
#include "qemu/osdep.h"
#include <math.h>
#include "qemu/bitops.h"
@ -220,11 +217,9 @@ GEN_INPUT_FLUSH3(float64_input_flush3, float64)
* the use of hardfloat, since hardfloat relies on the inexact flag being
* already set.
*/
#if defined(TARGET_PPC) || defined(__FAST_MATH__)
# if defined(__FAST_MATH__)
# warning disabling hardfloat due to -ffast-math: hardfloat requires an exact \
IEEE implementation
# endif
# define QEMU_NO_HARDFLOAT 1
# define QEMU_SOFTFLOAT_ATTR QEMU_FLATTEN
#else
@ -537,7 +532,8 @@ typedef struct {
* round_mask: bits below lsb which must be rounded
* The following optional modifiers are available:
* arm_althp: handle ARM Alternative Half Precision
* m68k_denormal: explicit integer bit for extended precision may be 1
* has_explicit_bit: has an explicit integer bit; this affects whether
* the float_status floatx80_behaviour handling applies
*/
typedef struct {
int exp_size;
@ -547,7 +543,7 @@ typedef struct {
int frac_size;
int frac_shift;
bool arm_althp;
bool m68k_denormal;
bool has_explicit_bit;
uint64_t round_mask;
} FloatFmt;
@ -600,9 +596,7 @@ static const FloatFmt floatx80_params[3] = {
[floatx80_precision_d] = { FLOATX80_PARAMS(52) },
[floatx80_precision_x] = {
FLOATX80_PARAMS(64),
#ifdef TARGET_M68K
.m68k_denormal = true,
#endif
.has_explicit_bit = true,
},
};
@ -1810,7 +1804,7 @@ static bool floatx80_unpack_canonical(FloatParts128 *p, floatx80 f,
g_assert_not_reached();
}
if (unlikely(floatx80_invalid_encoding(f))) {
if (unlikely(floatx80_invalid_encoding(f, s))) {
float_raise(float_flag_invalid, s);
return false;
}
@ -1860,7 +1854,8 @@ static floatx80 floatx80_round_pack_canonical(FloatParts128 *p,
case float_class_inf:
/* x86 and m68k differ in the setting of the integer bit. */
frac = floatx80_infinity_low;
frac = s->floatx80_behaviour & floatx80_default_inf_int_bit_is_zero ?
0 : (1ULL << 63);
exp = fmt->exp_max;
break;
@ -5144,9 +5139,7 @@ floatx80 roundAndPackFloatx80(FloatX80RoundPrec roundingPrecision, bool zSign,
) {
return packFloatx80( zSign, 0x7FFE, ~ roundMask );
}
return packFloatx80(zSign,
floatx80_infinity_high,
floatx80_infinity_low);
return floatx80_default_inf(zSign, status);
}
if ( zExp <= 0 ) {
isTiny = status->tininess_before_rounding

View file

@ -593,6 +593,30 @@ config FSL_IMX7
select UNIMP
select USB_CHIPIDEA
config FSL_IMX8MP
bool
imply I2C_DEVICES
imply PCI_DEVICES
select ARM_GIC
select FSL_IMX8MP_ANALOG
select FSL_IMX8MP_CCM
select IMX
select IMX_FEC
select IMX_I2C
select OR_IRQ
select PCI_EXPRESS_DESIGNWARE
select PCI_EXPRESS_FSL_IMX8M_PHY
select SDHCI
select UNIMP
select USB_DWC3
select WDT_IMX2
config FSL_IMX8MP_EVK
bool
default y
depends on TCG && AARCH64
select FSL_IMX8MP
config ARM_SMMUV3
bool

View file

@ -661,8 +661,6 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
binfo->modify_dtb(binfo, fdt);
}
qemu_fdt_dumpdtb(fdt, size);
/* Put the DTB into the memory map as a ROM image: this will ensure
* the DTB is copied again upon reset, even if addr points into RAM.
*/

714
hw/arm/fsl-imx8mp.c Normal file
View file

@ -0,0 +1,714 @@
/*
* i.MX 8M Plus SoC Implementation
*
* Based on hw/arm/fsl-imx6.c
*
* Copyright (c) 2024, Bernhard Beschow <shentey@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "exec/address-spaces.h"
#include "hw/arm/bsa.h"
#include "hw/arm/fsl-imx8mp.h"
#include "hw/intc/arm_gicv3.h"
#include "hw/misc/unimp.h"
#include "hw/boards.h"
#include "system/system.h"
#include "target/arm/cpu-qom.h"
#include "qapi/error.h"
#include "qobject/qlist.h"
static const struct {
hwaddr addr;
size_t size;
const char *name;
} fsl_imx8mp_memmap[] = {
[FSL_IMX8MP_RAM] = { FSL_IMX8MP_RAM_START, FSL_IMX8MP_RAM_SIZE_MAX, "ram" },
[FSL_IMX8MP_DDR_PHY_BROADCAST] = { 0x3dc00000, 4 * MiB, "ddr_phy_broadcast" },
[FSL_IMX8MP_DDR_PERF_MON] = { 0x3d800000, 4 * MiB, "ddr_perf_mon" },
[FSL_IMX8MP_DDR_CTL] = { 0x3d400000, 4 * MiB, "ddr_ctl" },
[FSL_IMX8MP_DDR_BLK_CTRL] = { 0x3d000000, 1 * MiB, "ddr_blk_ctrl" },
[FSL_IMX8MP_DDR_PHY] = { 0x3c000000, 16 * MiB, "ddr_phy" },
[FSL_IMX8MP_AUDIO_DSP] = { 0x3b000000, 16 * MiB, "audio_dsp" },
[FSL_IMX8MP_GIC_DIST] = { 0x38800000, 512 * KiB, "gic_dist" },
[FSL_IMX8MP_GIC_REDIST] = { 0x38880000, 512 * KiB, "gic_redist" },
[FSL_IMX8MP_NPU] = { 0x38500000, 2 * MiB, "npu" },
[FSL_IMX8MP_VPU] = { 0x38340000, 2 * MiB, "vpu" },
[FSL_IMX8MP_VPU_BLK_CTRL] = { 0x38330000, 2 * MiB, "vpu_blk_ctrl" },
[FSL_IMX8MP_VPU_VC8000E_ENCODER] = { 0x38320000, 2 * MiB, "vpu_vc8000e_encoder" },
[FSL_IMX8MP_VPU_G2_DECODER] = { 0x38310000, 2 * MiB, "vpu_g2_decoder" },
[FSL_IMX8MP_VPU_G1_DECODER] = { 0x38300000, 2 * MiB, "vpu_g1_decoder" },
[FSL_IMX8MP_USB2_GLUE] = { 0x382f0000, 0x100, "usb2_glue" },
[FSL_IMX8MP_USB2_OTG] = { 0x3820cc00, 0x100, "usb2_otg" },
[FSL_IMX8MP_USB2_DEV] = { 0x3820c700, 0x500, "usb2_dev" },
[FSL_IMX8MP_USB2] = { 0x38200000, 0xc700, "usb2" },
[FSL_IMX8MP_USB1_GLUE] = { 0x381f0000, 0x100, "usb1_glue" },
[FSL_IMX8MP_USB1_OTG] = { 0x3810cc00, 0x100, "usb1_otg" },
[FSL_IMX8MP_USB1_DEV] = { 0x3810c700, 0x500, "usb1_dev" },
[FSL_IMX8MP_USB1] = { 0x38100000, 0xc700, "usb1" },
[FSL_IMX8MP_GPU2D] = { 0x38008000, 32 * KiB, "gpu2d" },
[FSL_IMX8MP_GPU3D] = { 0x38000000, 32 * KiB, "gpu3d" },
[FSL_IMX8MP_QSPI1_RX_BUFFER] = { 0x34000000, 32 * MiB, "qspi1_rx_buffer" },
[FSL_IMX8MP_PCIE1] = { 0x33800000, 4 * MiB, "pcie1" },
[FSL_IMX8MP_QSPI1_TX_BUFFER] = { 0x33008000, 32 * KiB, "qspi1_tx_buffer" },
[FSL_IMX8MP_APBH_DMA] = { 0x33000000, 32 * KiB, "apbh_dma" },
/* AIPS-5 Begin */
[FSL_IMX8MP_MU_3_B] = { 0x30e90000, 64 * KiB, "mu_3_b" },
[FSL_IMX8MP_MU_3_A] = { 0x30e80000, 64 * KiB, "mu_3_a" },
[FSL_IMX8MP_MU_2_B] = { 0x30e70000, 64 * KiB, "mu_2_b" },
[FSL_IMX8MP_MU_2_A] = { 0x30e60000, 64 * KiB, "mu_2_a" },
[FSL_IMX8MP_EDMA_CHANNELS] = { 0x30e40000, 128 * KiB, "edma_channels" },
[FSL_IMX8MP_EDMA_MANAGEMENT_PAGE] = { 0x30e30000, 64 * KiB, "edma_management_page" },
[FSL_IMX8MP_AUDIO_BLK_CTRL] = { 0x30e20000, 64 * KiB, "audio_blk_ctrl" },
[FSL_IMX8MP_SDMA2] = { 0x30e10000, 64 * KiB, "sdma2" },
[FSL_IMX8MP_SDMA3] = { 0x30e00000, 64 * KiB, "sdma3" },
[FSL_IMX8MP_AIPS5_CONFIGURATION] = { 0x30df0000, 64 * KiB, "aips5_configuration" },
[FSL_IMX8MP_SPBA2] = { 0x30cf0000, 64 * KiB, "spba2" },
[FSL_IMX8MP_AUDIO_XCVR_RX] = { 0x30cc0000, 64 * KiB, "audio_xcvr_rx" },
[FSL_IMX8MP_HDMI_TX_AUDLNK_MSTR] = { 0x30cb0000, 64 * KiB, "hdmi_tx_audlnk_mstr" },
[FSL_IMX8MP_PDM] = { 0x30ca0000, 64 * KiB, "pdm" },
[FSL_IMX8MP_ASRC] = { 0x30c90000, 64 * KiB, "asrc" },
[FSL_IMX8MP_SAI7] = { 0x30c80000, 64 * KiB, "sai7" },
[FSL_IMX8MP_SAI6] = { 0x30c60000, 64 * KiB, "sai6" },
[FSL_IMX8MP_SAI5] = { 0x30c50000, 64 * KiB, "sai5" },
[FSL_IMX8MP_SAI3] = { 0x30c30000, 64 * KiB, "sai3" },
[FSL_IMX8MP_SAI2] = { 0x30c20000, 64 * KiB, "sai2" },
[FSL_IMX8MP_SAI1] = { 0x30c10000, 64 * KiB, "sai1" },
/* AIPS-5 End */
/* AIPS-4 Begin */
[FSL_IMX8MP_HDMI_TX] = { 0x32fc0000, 128 * KiB, "hdmi_tx" },
[FSL_IMX8MP_TZASC] = { 0x32f80000, 64 * KiB, "tzasc" },
[FSL_IMX8MP_HSIO_BLK_CTL] = { 0x32f10000, 64 * KiB, "hsio_blk_ctl" },
[FSL_IMX8MP_PCIE_PHY1] = { 0x32f00000, 64 * KiB, "pcie_phy1" },
[FSL_IMX8MP_MEDIA_BLK_CTL] = { 0x32ec0000, 64 * KiB, "media_blk_ctl" },
[FSL_IMX8MP_LCDIF2] = { 0x32e90000, 64 * KiB, "lcdif2" },
[FSL_IMX8MP_LCDIF1] = { 0x32e80000, 64 * KiB, "lcdif1" },
[FSL_IMX8MP_MIPI_DSI1] = { 0x32e60000, 64 * KiB, "mipi_dsi1" },
[FSL_IMX8MP_MIPI_CSI2] = { 0x32e50000, 64 * KiB, "mipi_csi2" },
[FSL_IMX8MP_MIPI_CSI1] = { 0x32e40000, 64 * KiB, "mipi_csi1" },
[FSL_IMX8MP_IPS_DEWARP] = { 0x32e30000, 64 * KiB, "ips_dewarp" },
[FSL_IMX8MP_ISP2] = { 0x32e20000, 64 * KiB, "isp2" },
[FSL_IMX8MP_ISP1] = { 0x32e10000, 64 * KiB, "isp1" },
[FSL_IMX8MP_ISI] = { 0x32e00000, 64 * KiB, "isi" },
[FSL_IMX8MP_AIPS4_CONFIGURATION] = { 0x32df0000, 64 * KiB, "aips4_configuration" },
/* AIPS-4 End */
[FSL_IMX8MP_INTERCONNECT] = { 0x32700000, 1 * MiB, "interconnect" },
/* AIPS-3 Begin */
[FSL_IMX8MP_ENET2_TSN] = { 0x30bf0000, 64 * KiB, "enet2_tsn" },
[FSL_IMX8MP_ENET1] = { 0x30be0000, 64 * KiB, "enet1" },
[FSL_IMX8MP_SDMA1] = { 0x30bd0000, 64 * KiB, "sdma1" },
[FSL_IMX8MP_QSPI] = { 0x30bb0000, 64 * KiB, "qspi" },
[FSL_IMX8MP_USDHC3] = { 0x30b60000, 64 * KiB, "usdhc3" },
[FSL_IMX8MP_USDHC2] = { 0x30b50000, 64 * KiB, "usdhc2" },
[FSL_IMX8MP_USDHC1] = { 0x30b40000, 64 * KiB, "usdhc1" },
[FSL_IMX8MP_I2C6] = { 0x30ae0000, 64 * KiB, "i2c6" },
[FSL_IMX8MP_I2C5] = { 0x30ad0000, 64 * KiB, "i2c5" },
[FSL_IMX8MP_SEMAPHORE_HS] = { 0x30ac0000, 64 * KiB, "semaphore_hs" },
[FSL_IMX8MP_MU_1_B] = { 0x30ab0000, 64 * KiB, "mu_1_b" },
[FSL_IMX8MP_MU_1_A] = { 0x30aa0000, 64 * KiB, "mu_1_a" },
[FSL_IMX8MP_AUD_IRQ_STEER] = { 0x30a80000, 64 * KiB, "aud_irq_steer" },
[FSL_IMX8MP_UART4] = { 0x30a60000, 64 * KiB, "uart4" },
[FSL_IMX8MP_I2C4] = { 0x30a50000, 64 * KiB, "i2c4" },
[FSL_IMX8MP_I2C3] = { 0x30a40000, 64 * KiB, "i2c3" },
[FSL_IMX8MP_I2C2] = { 0x30a30000, 64 * KiB, "i2c2" },
[FSL_IMX8MP_I2C1] = { 0x30a20000, 64 * KiB, "i2c1" },
[FSL_IMX8MP_AIPS3_CONFIGURATION] = { 0x309f0000, 64 * KiB, "aips3_configuration" },
[FSL_IMX8MP_CAAM] = { 0x30900000, 256 * KiB, "caam" },
[FSL_IMX8MP_SPBA1] = { 0x308f0000, 64 * KiB, "spba1" },
[FSL_IMX8MP_FLEXCAN2] = { 0x308d0000, 64 * KiB, "flexcan2" },
[FSL_IMX8MP_FLEXCAN1] = { 0x308c0000, 64 * KiB, "flexcan1" },
[FSL_IMX8MP_UART2] = { 0x30890000, 64 * KiB, "uart2" },
[FSL_IMX8MP_UART3] = { 0x30880000, 64 * KiB, "uart3" },
[FSL_IMX8MP_UART1] = { 0x30860000, 64 * KiB, "uart1" },
[FSL_IMX8MP_ECSPI3] = { 0x30840000, 64 * KiB, "ecspi3" },
[FSL_IMX8MP_ECSPI2] = { 0x30830000, 64 * KiB, "ecspi2" },
[FSL_IMX8MP_ECSPI1] = { 0x30820000, 64 * KiB, "ecspi1" },
/* AIPS-3 End */
/* AIPS-2 Begin */
[FSL_IMX8MP_QOSC] = { 0x307f0000, 64 * KiB, "qosc" },
[FSL_IMX8MP_PERFMON2] = { 0x307d0000, 64 * KiB, "perfmon2" },
[FSL_IMX8MP_PERFMON1] = { 0x307c0000, 64 * KiB, "perfmon1" },
[FSL_IMX8MP_GPT4] = { 0x30700000, 64 * KiB, "gpt4" },
[FSL_IMX8MP_GPT5] = { 0x306f0000, 64 * KiB, "gpt5" },
[FSL_IMX8MP_GPT6] = { 0x306e0000, 64 * KiB, "gpt6" },
[FSL_IMX8MP_SYSCNT_CTRL] = { 0x306c0000, 64 * KiB, "syscnt_ctrl" },
[FSL_IMX8MP_SYSCNT_CMP] = { 0x306b0000, 64 * KiB, "syscnt_cmp" },
[FSL_IMX8MP_SYSCNT_RD] = { 0x306a0000, 64 * KiB, "syscnt_rd" },
[FSL_IMX8MP_PWM4] = { 0x30690000, 64 * KiB, "pwm4" },
[FSL_IMX8MP_PWM3] = { 0x30680000, 64 * KiB, "pwm3" },
[FSL_IMX8MP_PWM2] = { 0x30670000, 64 * KiB, "pwm2" },
[FSL_IMX8MP_PWM1] = { 0x30660000, 64 * KiB, "pwm1" },
[FSL_IMX8MP_AIPS2_CONFIGURATION] = { 0x305f0000, 64 * KiB, "aips2_configuration" },
/* AIPS-2 End */
/* AIPS-1 Begin */
[FSL_IMX8MP_CSU] = { 0x303e0000, 64 * KiB, "csu" },
[FSL_IMX8MP_RDC] = { 0x303d0000, 64 * KiB, "rdc" },
[FSL_IMX8MP_SEMAPHORE2] = { 0x303c0000, 64 * KiB, "semaphore2" },
[FSL_IMX8MP_SEMAPHORE1] = { 0x303b0000, 64 * KiB, "semaphore1" },
[FSL_IMX8MP_GPC] = { 0x303a0000, 64 * KiB, "gpc" },
[FSL_IMX8MP_SRC] = { 0x30390000, 64 * KiB, "src" },
[FSL_IMX8MP_CCM] = { 0x30380000, 64 * KiB, "ccm" },
[FSL_IMX8MP_SNVS_HP] = { 0x30370000, 64 * KiB, "snvs_hp" },
[FSL_IMX8MP_ANA_PLL] = { 0x30360000, 64 * KiB, "ana_pll" },
[FSL_IMX8MP_OCOTP_CTRL] = { 0x30350000, 64 * KiB, "ocotp_ctrl" },
[FSL_IMX8MP_IOMUXC_GPR] = { 0x30340000, 64 * KiB, "iomuxc_gpr" },
[FSL_IMX8MP_IOMUXC] = { 0x30330000, 64 * KiB, "iomuxc" },
[FSL_IMX8MP_GPT3] = { 0x302f0000, 64 * KiB, "gpt3" },
[FSL_IMX8MP_GPT2] = { 0x302e0000, 64 * KiB, "gpt2" },
[FSL_IMX8MP_GPT1] = { 0x302d0000, 64 * KiB, "gpt1" },
[FSL_IMX8MP_WDOG3] = { 0x302a0000, 64 * KiB, "wdog3" },
[FSL_IMX8MP_WDOG2] = { 0x30290000, 64 * KiB, "wdog2" },
[FSL_IMX8MP_WDOG1] = { 0x30280000, 64 * KiB, "wdog1" },
[FSL_IMX8MP_ANA_OSC] = { 0x30270000, 64 * KiB, "ana_osc" },
[FSL_IMX8MP_ANA_TSENSOR] = { 0x30260000, 64 * KiB, "ana_tsensor" },
[FSL_IMX8MP_GPIO5] = { 0x30240000, 64 * KiB, "gpio5" },
[FSL_IMX8MP_GPIO4] = { 0x30230000, 64 * KiB, "gpio4" },
[FSL_IMX8MP_GPIO3] = { 0x30220000, 64 * KiB, "gpio3" },
[FSL_IMX8MP_GPIO2] = { 0x30210000, 64 * KiB, "gpio2" },
[FSL_IMX8MP_GPIO1] = { 0x30200000, 64 * KiB, "gpio1" },
[FSL_IMX8MP_AIPS1_CONFIGURATION] = { 0x301f0000, 64 * KiB, "aips1_configuration" },
/* AIPS-1 End */
[FSL_IMX8MP_A53_DAP] = { 0x28000000, 16 * MiB, "a53_dap" },
[FSL_IMX8MP_PCIE1_MEM] = { 0x18000000, 128 * MiB, "pcie1_mem" },
[FSL_IMX8MP_QSPI_MEM] = { 0x08000000, 256 * MiB, "qspi_mem" },
[FSL_IMX8MP_OCRAM] = { 0x00900000, 576 * KiB, "ocram" },
[FSL_IMX8MP_TCM_DTCM] = { 0x00800000, 128 * KiB, "tcm_dtcm" },
[FSL_IMX8MP_TCM_ITCM] = { 0x007e0000, 128 * KiB, "tcm_itcm" },
[FSL_IMX8MP_OCRAM_S] = { 0x00180000, 36 * KiB, "ocram_s" },
[FSL_IMX8MP_CAAM_MEM] = { 0x00100000, 32 * KiB, "caam_mem" },
[FSL_IMX8MP_BOOT_ROM_PROTECTED] = { 0x0003f000, 4 * KiB, "boot_rom_protected" },
[FSL_IMX8MP_BOOT_ROM] = { 0x00000000, 252 * KiB, "boot_rom" },
};
static void fsl_imx8mp_init(Object *obj)
{
MachineState *ms = MACHINE(qdev_get_machine());
FslImx8mpState *s = FSL_IMX8MP(obj);
int i;
for (i = 0; i < MIN(ms->smp.cpus, FSL_IMX8MP_NUM_CPUS); i++) {
g_autofree char *name = g_strdup_printf("cpu%d", i);
object_initialize_child(obj, name, &s->cpu[i],
ARM_CPU_TYPE_NAME("cortex-a53"));
}
object_initialize_child(obj, "gic", &s->gic, TYPE_ARM_GICV3);
object_initialize_child(obj, "ccm", &s->ccm, TYPE_IMX8MP_CCM);
object_initialize_child(obj, "analog", &s->analog, TYPE_IMX8MP_ANALOG);
object_initialize_child(obj, "snvs", &s->snvs, TYPE_IMX7_SNVS);
for (i = 0; i < FSL_IMX8MP_NUM_UARTS; i++) {
g_autofree char *name = g_strdup_printf("uart%d", i + 1);
object_initialize_child(obj, name, &s->uart[i], TYPE_IMX_SERIAL);
}
for (i = 0; i < FSL_IMX8MP_NUM_GPTS; i++) {
g_autofree char *name = g_strdup_printf("gpt%d", i + 1);
object_initialize_child(obj, name, &s->gpt[i], TYPE_IMX8MP_GPT);
}
object_initialize_child(obj, "gpt5-gpt6-irq", &s->gpt5_gpt6_irq,
TYPE_OR_IRQ);
for (i = 0; i < FSL_IMX8MP_NUM_I2CS; i++) {
g_autofree char *name = g_strdup_printf("i2c%d", i + 1);
object_initialize_child(obj, name, &s->i2c[i], TYPE_IMX_I2C);
}
for (i = 0; i < FSL_IMX8MP_NUM_GPIOS; i++) {
g_autofree char *name = g_strdup_printf("gpio%d", i + 1);
object_initialize_child(obj, name, &s->gpio[i], TYPE_IMX_GPIO);
}
for (i = 0; i < FSL_IMX8MP_NUM_USDHCS; i++) {
g_autofree char *name = g_strdup_printf("usdhc%d", i + 1);
object_initialize_child(obj, name, &s->usdhc[i], TYPE_IMX_USDHC);
}
for (i = 0; i < FSL_IMX8MP_NUM_USBS; i++) {
g_autofree char *name = g_strdup_printf("usb%d", i);
object_initialize_child(obj, name, &s->usb[i], TYPE_USB_DWC3);
}
for (i = 0; i < FSL_IMX8MP_NUM_ECSPIS; i++) {
g_autofree char *name = g_strdup_printf("spi%d", i + 1);
object_initialize_child(obj, name, &s->spi[i], TYPE_IMX_SPI);
}
for (i = 0; i < FSL_IMX8MP_NUM_WDTS; i++) {
g_autofree char *name = g_strdup_printf("wdt%d", i);
object_initialize_child(obj, name, &s->wdt[i], TYPE_IMX2_WDT);
}
object_initialize_child(obj, "eth0", &s->enet, TYPE_IMX_ENET);
object_initialize_child(obj, "pcie", &s->pcie, TYPE_DESIGNWARE_PCIE_HOST);
object_initialize_child(obj, "pcie_phy", &s->pcie_phy,
TYPE_FSL_IMX8M_PCIE_PHY);
}
static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
{
MachineState *ms = MACHINE(qdev_get_machine());
FslImx8mpState *s = FSL_IMX8MP(dev);
DeviceState *gicdev = DEVICE(&s->gic);
int i;
if (ms->smp.cpus > FSL_IMX8MP_NUM_CPUS) {
error_setg(errp, "%s: Only %d CPUs are supported (%d requested)",
TYPE_FSL_IMX8MP, FSL_IMX8MP_NUM_CPUS, ms->smp.cpus);
return;
}
/* CPUs */
for (i = 0; i < ms->smp.cpus; i++) {
/* On uniprocessor, the CBAR is set to 0 */
if (ms->smp.cpus > 1) {
object_property_set_int(OBJECT(&s->cpu[i]), "reset-cbar",
fsl_imx8mp_memmap[FSL_IMX8MP_GIC_DIST].addr,
&error_abort);
}
/*
* CNTFID0 base frequency in Hz of system counter
*/
object_property_set_int(OBJECT(&s->cpu[i]), "cntfrq", 8000000,
&error_abort);
if (i) {
/*
* Secondary CPUs start in powered-down state (and can be
* powered up via the SRC system reset controller)
*/
object_property_set_bool(OBJECT(&s->cpu[i]), "start-powered-off",
true, &error_abort);
}
if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) {
return;
}
}
/* GIC */
{
SysBusDevice *gicsbd = SYS_BUS_DEVICE(&s->gic);
QList *redist_region_count;
qdev_prop_set_uint32(gicdev, "num-cpu", ms->smp.cpus);
qdev_prop_set_uint32(gicdev, "num-irq",
FSL_IMX8MP_NUM_IRQS + GIC_INTERNAL);
redist_region_count = qlist_new();
qlist_append_int(redist_region_count, ms->smp.cpus);
qdev_prop_set_array(gicdev, "redist-region-count", redist_region_count);
object_property_set_link(OBJECT(&s->gic), "sysmem",
OBJECT(get_system_memory()), &error_fatal);
if (!sysbus_realize(gicsbd, errp)) {
return;
}
sysbus_mmio_map(gicsbd, 0, fsl_imx8mp_memmap[FSL_IMX8MP_GIC_DIST].addr);
sysbus_mmio_map(gicsbd, 1, fsl_imx8mp_memmap[FSL_IMX8MP_GIC_REDIST].addr);
/*
* Wire the outputs from each CPU's generic timer and the GICv3
* maintenance interrupt signal to the appropriate GIC PPI inputs, and
* the GIC's IRQ/FIQ interrupt outputs to the CPU's inputs.
*/
for (i = 0; i < ms->smp.cpus; i++) {
DeviceState *cpudev = DEVICE(&s->cpu[i]);
int intidbase = FSL_IMX8MP_NUM_IRQS + i * GIC_INTERNAL;
qemu_irq irq;
/*
* Mapping from the output timer irq lines from the CPU to the
* GIC PPI inputs.
*/
static const int timer_irqs[] = {
[GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ,
[GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ,
[GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
[GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
};
for (int j = 0; j < ARRAY_SIZE(timer_irqs); j++) {
irq = qdev_get_gpio_in(gicdev, intidbase + timer_irqs[j]);
qdev_connect_gpio_out(cpudev, j, irq);
}
irq = qdev_get_gpio_in(gicdev, intidbase + ARCH_GIC_MAINT_IRQ);
qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt",
0, irq);
irq = qdev_get_gpio_in(gicdev, intidbase + VIRTUAL_PMU_IRQ);
qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0, irq);
sysbus_connect_irq(gicsbd, i,
qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
sysbus_connect_irq(gicsbd, i + ms->smp.cpus,
qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
}
}
/* CCM */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->ccm), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->ccm), 0,
fsl_imx8mp_memmap[FSL_IMX8MP_CCM].addr);
/* Analog */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->analog), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->analog), 0,
fsl_imx8mp_memmap[FSL_IMX8MP_ANA_PLL].addr);
/* UARTs */
for (i = 0; i < FSL_IMX8MP_NUM_UARTS; i++) {
struct {
hwaddr addr;
unsigned int irq;
} serial_table[FSL_IMX8MP_NUM_UARTS] = {
{ fsl_imx8mp_memmap[FSL_IMX8MP_UART1].addr, FSL_IMX8MP_UART1_IRQ },
{ fsl_imx8mp_memmap[FSL_IMX8MP_UART2].addr, FSL_IMX8MP_UART2_IRQ },
{ fsl_imx8mp_memmap[FSL_IMX8MP_UART3].addr, FSL_IMX8MP_UART3_IRQ },
{ fsl_imx8mp_memmap[FSL_IMX8MP_UART4].addr, FSL_IMX8MP_UART4_IRQ },
};
qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", serial_hd(i));
if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->uart[i]), 0, serial_table[i].addr);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0,
qdev_get_gpio_in(gicdev, serial_table[i].irq));
}
/* GPTs */
object_property_set_int(OBJECT(&s->gpt5_gpt6_irq), "num-lines", 2,
&error_abort);
if (!qdev_realize(DEVICE(&s->gpt5_gpt6_irq), NULL, errp)) {
return;
}
qdev_connect_gpio_out(DEVICE(&s->gpt5_gpt6_irq), 0,
qdev_get_gpio_in(gicdev, FSL_IMX8MP_GPT5_GPT6_IRQ));
for (i = 0; i < FSL_IMX8MP_NUM_GPTS; i++) {
hwaddr gpt_addrs[FSL_IMX8MP_NUM_GPTS] = {
fsl_imx8mp_memmap[FSL_IMX8MP_GPT1].addr,
fsl_imx8mp_memmap[FSL_IMX8MP_GPT2].addr,
fsl_imx8mp_memmap[FSL_IMX8MP_GPT3].addr,
fsl_imx8mp_memmap[FSL_IMX8MP_GPT4].addr,
fsl_imx8mp_memmap[FSL_IMX8MP_GPT5].addr,
fsl_imx8mp_memmap[FSL_IMX8MP_GPT6].addr,
};
s->gpt[i].ccm = IMX_CCM(&s->ccm);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpt[i]), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt[i]), 0, gpt_addrs[i]);
if (i < FSL_IMX8MP_NUM_GPTS - 2) {
static const unsigned int gpt_irqs[FSL_IMX8MP_NUM_GPTS - 2] = {
FSL_IMX8MP_GPT1_IRQ,
FSL_IMX8MP_GPT2_IRQ,
FSL_IMX8MP_GPT3_IRQ,
FSL_IMX8MP_GPT4_IRQ,
};
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0,
qdev_get_gpio_in(gicdev, gpt_irqs[i]));
} else {
int irq = i - FSL_IMX8MP_NUM_GPTS + 2;
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0,
qdev_get_gpio_in(DEVICE(&s->gpt5_gpt6_irq), irq));
}
}
/* I2Cs */
for (i = 0; i < FSL_IMX8MP_NUM_I2CS; i++) {
struct {
hwaddr addr;
unsigned int irq;
} i2c_table[FSL_IMX8MP_NUM_I2CS] = {
{ fsl_imx8mp_memmap[FSL_IMX8MP_I2C1].addr, FSL_IMX8MP_I2C1_IRQ },
{ fsl_imx8mp_memmap[FSL_IMX8MP_I2C2].addr, FSL_IMX8MP_I2C2_IRQ },
{ fsl_imx8mp_memmap[FSL_IMX8MP_I2C3].addr, FSL_IMX8MP_I2C3_IRQ },
{ fsl_imx8mp_memmap[FSL_IMX8MP_I2C4].addr, FSL_IMX8MP_I2C4_IRQ },
{ fsl_imx8mp_memmap[FSL_IMX8MP_I2C5].addr, FSL_IMX8MP_I2C5_IRQ },
{ fsl_imx8mp_memmap[FSL_IMX8MP_I2C6].addr, FSL_IMX8MP_I2C6_IRQ },
};
if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c[i]), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c[i]), 0, i2c_table[i].addr);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c[i]), 0,
qdev_get_gpio_in(gicdev, i2c_table[i].irq));
}
/* GPIOs */
for (i = 0; i < FSL_IMX8MP_NUM_GPIOS; i++) {
struct {
hwaddr addr;
unsigned int irq_low;
unsigned int irq_high;
} gpio_table[FSL_IMX8MP_NUM_GPIOS] = {
{
fsl_imx8mp_memmap[FSL_IMX8MP_GPIO1].addr,
FSL_IMX8MP_GPIO1_LOW_IRQ,
FSL_IMX8MP_GPIO1_HIGH_IRQ
},
{
fsl_imx8mp_memmap[FSL_IMX8MP_GPIO2].addr,
FSL_IMX8MP_GPIO2_LOW_IRQ,
FSL_IMX8MP_GPIO2_HIGH_IRQ
},
{
fsl_imx8mp_memmap[FSL_IMX8MP_GPIO3].addr,
FSL_IMX8MP_GPIO3_LOW_IRQ,
FSL_IMX8MP_GPIO3_HIGH_IRQ
},
{
fsl_imx8mp_memmap[FSL_IMX8MP_GPIO4].addr,
FSL_IMX8MP_GPIO4_LOW_IRQ,
FSL_IMX8MP_GPIO4_HIGH_IRQ
},
{
fsl_imx8mp_memmap[FSL_IMX8MP_GPIO5].addr,
FSL_IMX8MP_GPIO5_LOW_IRQ,
FSL_IMX8MP_GPIO5_HIGH_IRQ
},
};
object_property_set_bool(OBJECT(&s->gpio[i]), "has-edge-sel", true,
&error_abort);
object_property_set_bool(OBJECT(&s->gpio[i]), "has-upper-pin-irq",
true, &error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, gpio_table[i].addr);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
qdev_get_gpio_in(gicdev, gpio_table[i].irq_low));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 1,
qdev_get_gpio_in(gicdev, gpio_table[i].irq_high));
}
/* USDHCs */
for (i = 0; i < FSL_IMX8MP_NUM_USDHCS; i++) {
struct {
hwaddr addr;
unsigned int irq;
} usdhc_table[FSL_IMX8MP_NUM_USDHCS] = {
{ fsl_imx8mp_memmap[FSL_IMX8MP_USDHC1].addr, FSL_IMX8MP_USDHC1_IRQ },
{ fsl_imx8mp_memmap[FSL_IMX8MP_USDHC2].addr, FSL_IMX8MP_USDHC2_IRQ },
{ fsl_imx8mp_memmap[FSL_IMX8MP_USDHC3].addr, FSL_IMX8MP_USDHC3_IRQ },
};
object_property_set_uint(OBJECT(&s->usdhc[i]), "vendor",
SDHCI_VENDOR_IMX, &error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->usdhc[i]), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->usdhc[i]), 0, usdhc_table[i].addr);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->usdhc[i]), 0,
qdev_get_gpio_in(gicdev, usdhc_table[i].irq));
}
/* USBs */
for (i = 0; i < FSL_IMX8MP_NUM_USBS; i++) {
struct {
hwaddr addr;
unsigned int irq;
} usb_table[FSL_IMX8MP_NUM_USBS] = {
{ fsl_imx8mp_memmap[FSL_IMX8MP_USB1].addr, FSL_IMX8MP_USB1_IRQ },
{ fsl_imx8mp_memmap[FSL_IMX8MP_USB2].addr, FSL_IMX8MP_USB2_IRQ },
};
qdev_prop_set_uint32(DEVICE(&s->usb[i].sysbus_xhci), "p2", 1);
qdev_prop_set_uint32(DEVICE(&s->usb[i].sysbus_xhci), "p3", 1);
qdev_prop_set_uint32(DEVICE(&s->usb[i].sysbus_xhci), "slots", 2);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->usb[i]), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->usb[i]), 0, usb_table[i].addr);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->usb[i].sysbus_xhci), 0,
qdev_get_gpio_in(gicdev, usb_table[i].irq));
}
/* ECSPIs */
for (i = 0; i < FSL_IMX8MP_NUM_ECSPIS; i++) {
struct {
hwaddr addr;
unsigned int irq;
} spi_table[FSL_IMX8MP_NUM_ECSPIS] = {
{ fsl_imx8mp_memmap[FSL_IMX8MP_ECSPI1].addr, FSL_IMX8MP_ECSPI1_IRQ },
{ fsl_imx8mp_memmap[FSL_IMX8MP_ECSPI2].addr, FSL_IMX8MP_ECSPI2_IRQ },
{ fsl_imx8mp_memmap[FSL_IMX8MP_ECSPI3].addr, FSL_IMX8MP_ECSPI3_IRQ },
};
if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, spi_table[i].addr);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0,
qdev_get_gpio_in(gicdev, spi_table[i].irq));
}
/* ENET1 */
object_property_set_uint(OBJECT(&s->enet), "phy-num", s->phy_num,
&error_abort);
object_property_set_uint(OBJECT(&s->enet), "tx-ring-num", 3, &error_abort);
qemu_configure_nic_device(DEVICE(&s->enet), true, NULL);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->enet), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->enet), 0,
fsl_imx8mp_memmap[FSL_IMX8MP_ENET1].addr);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->enet), 0,
qdev_get_gpio_in(gicdev, FSL_IMX8MP_ENET1_MAC_IRQ));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->enet), 1,
qdev_get_gpio_in(gicdev, FSL_IMX6_ENET1_MAC_1588_IRQ));
/* SNVS */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->snvs), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->snvs), 0,
fsl_imx8mp_memmap[FSL_IMX8MP_SNVS_HP].addr);
/* Watchdogs */
for (i = 0; i < FSL_IMX8MP_NUM_WDTS; i++) {
struct {
hwaddr addr;
unsigned int irq;
} wdog_table[FSL_IMX8MP_NUM_WDTS] = {
{ fsl_imx8mp_memmap[FSL_IMX8MP_WDOG1].addr, FSL_IMX8MP_WDOG1_IRQ },
{ fsl_imx8mp_memmap[FSL_IMX8MP_WDOG2].addr, FSL_IMX8MP_WDOG2_IRQ },
{ fsl_imx8mp_memmap[FSL_IMX8MP_WDOG3].addr, FSL_IMX8MP_WDOG3_IRQ },
};
object_property_set_bool(OBJECT(&s->wdt[i]), "pretimeout-support",
true, &error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0, wdog_table[i].addr);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[i]), 0,
qdev_get_gpio_in(gicdev, wdog_table[i].irq));
}
/* PCIe */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcie), 0,
fsl_imx8mp_memmap[FSL_IMX8MP_PCIE1].addr);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 0,
qdev_get_gpio_in(gicdev, FSL_IMX8MP_PCI_INTA_IRQ));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 1,
qdev_get_gpio_in(gicdev, FSL_IMX8MP_PCI_INTB_IRQ));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 2,
qdev_get_gpio_in(gicdev, FSL_IMX8MP_PCI_INTC_IRQ));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 3,
qdev_get_gpio_in(gicdev, FSL_IMX8MP_PCI_INTD_IRQ));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie), 4,
qdev_get_gpio_in(gicdev, FSL_IMX8MP_PCI_MSI_IRQ));
if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie_phy), errp)) {
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcie_phy), 0,
fsl_imx8mp_memmap[FSL_IMX8MP_PCIE_PHY1].addr);
/* On-Chip RAM */
if (!memory_region_init_ram(&s->ocram, NULL, "imx8mp.ocram",
fsl_imx8mp_memmap[FSL_IMX8MP_OCRAM].size,
errp)) {
return;
}
memory_region_add_subregion(get_system_memory(),
fsl_imx8mp_memmap[FSL_IMX8MP_OCRAM].addr,
&s->ocram);
/* Unimplemented devices */
for (i = 0; i < ARRAY_SIZE(fsl_imx8mp_memmap); i++) {
switch (i) {
case FSL_IMX8MP_ANA_PLL:
case FSL_IMX8MP_CCM:
case FSL_IMX8MP_GIC_DIST:
case FSL_IMX8MP_GIC_REDIST:
case FSL_IMX8MP_GPIO1 ... FSL_IMX8MP_GPIO5:
case FSL_IMX8MP_ECSPI1 ... FSL_IMX8MP_ECSPI3:
case FSL_IMX8MP_ENET1:
case FSL_IMX8MP_I2C1 ... FSL_IMX8MP_I2C6:
case FSL_IMX8MP_OCRAM:
case FSL_IMX8MP_PCIE1:
case FSL_IMX8MP_PCIE_PHY1:
case FSL_IMX8MP_RAM:
case FSL_IMX8MP_SNVS_HP:
case FSL_IMX8MP_UART1 ... FSL_IMX8MP_UART4:
case FSL_IMX8MP_USB1 ... FSL_IMX8MP_USB2:
case FSL_IMX8MP_USDHC1 ... FSL_IMX8MP_USDHC3:
case FSL_IMX8MP_WDOG1 ... FSL_IMX8MP_WDOG3:
/* device implemented and treated above */
break;
default:
create_unimplemented_device(fsl_imx8mp_memmap[i].name,
fsl_imx8mp_memmap[i].addr,
fsl_imx8mp_memmap[i].size);
break;
}
}
}
static const Property fsl_imx8mp_properties[] = {
DEFINE_PROP_UINT32("fec1-phy-num", FslImx8mpState, phy_num, 0),
DEFINE_PROP_BOOL("fec1-phy-connected", FslImx8mpState, phy_connected, true),
};
static void fsl_imx8mp_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
device_class_set_props(dc, fsl_imx8mp_properties);
dc->realize = fsl_imx8mp_realize;
dc->desc = "i.MX 8M Plus SoC";
}
static const TypeInfo fsl_imx8mp_types[] = {
{
.name = TYPE_FSL_IMX8MP,
.parent = TYPE_DEVICE,
.instance_size = sizeof(FslImx8mpState),
.instance_init = fsl_imx8mp_init,
.class_init = fsl_imx8mp_class_init,
},
};
DEFINE_TYPES(fsl_imx8mp_types)

74
hw/arm/imx8mp-evk.c Normal file
View file

@ -0,0 +1,74 @@
/*
* NXP i.MX 8M Plus Evaluation Kit System Emulation
*
* Copyright (c) 2024, Bernhard Beschow <shentey@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "exec/address-spaces.h"
#include "hw/arm/boot.h"
#include "hw/arm/fsl-imx8mp.h"
#include "hw/boards.h"
#include "hw/qdev-properties.h"
#include "system/qtest.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
static void imx8mp_evk_init(MachineState *machine)
{
static struct arm_boot_info boot_info;
FslImx8mpState *s;
if (machine->ram_size > FSL_IMX8MP_RAM_SIZE_MAX) {
error_report("RAM size " RAM_ADDR_FMT " above max supported (%08" PRIx64 ")",
machine->ram_size, FSL_IMX8MP_RAM_SIZE_MAX);
exit(1);
}
boot_info = (struct arm_boot_info) {
.loader_start = FSL_IMX8MP_RAM_START,
.board_id = -1,
.ram_size = machine->ram_size,
.psci_conduit = QEMU_PSCI_CONDUIT_SMC,
};
s = FSL_IMX8MP(object_new(TYPE_FSL_IMX8MP));
object_property_add_child(OBJECT(machine), "soc", OBJECT(s));
object_property_set_uint(OBJECT(s), "fec1-phy-num", 1, &error_fatal);
qdev_realize(DEVICE(s), NULL, &error_fatal);
memory_region_add_subregion(get_system_memory(), FSL_IMX8MP_RAM_START,
machine->ram);
for (int i = 0; i < FSL_IMX8MP_NUM_USDHCS; i++) {
BusState *bus;
DeviceState *carddev;
BlockBackend *blk;
DriveInfo *di = drive_get(IF_SD, i, 0);
if (!di) {
continue;
}
blk = blk_by_legacy_dinfo(di);
bus = qdev_get_child_bus(DEVICE(&s->usdhc[i]), "sd-bus");
carddev = qdev_new(TYPE_SD_CARD);
qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal);
qdev_realize_and_unref(carddev, bus, &error_fatal);
}
if (!qtest_enabled()) {
arm_load_kernel(&s->cpu[0], machine, &boot_info);
}
}
static void imx8mp_evk_machine_init(MachineClass *mc)
{
mc->desc = "NXP i.MX 8M Plus EVK Board";
mc->init = imx8mp_evk_init;
mc->max_cpus = FSL_IMX8MP_NUM_CPUS;
mc->default_ram_id = "imx8mp-evk.ram";
}
DEFINE_MACHINE("imx8mp-evk", imx8mp_evk_machine_init)

View file

@ -54,6 +54,8 @@ arm_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-soc.c'))
arm_ss.add(when: 'CONFIG_MUSCA', if_true: files('musca.c'))
arm_ss.add(when: 'CONFIG_ARMSSE', if_true: files('armsse.c'))
arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre.c'))
arm_ss.add(when: 'CONFIG_FSL_IMX8MP', if_true: files('fsl-imx8mp.c'))
arm_ss.add(when: 'CONFIG_FSL_IMX8MP_EVK', if_true: files('imx8mp-evk.c'))
arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmuv3.c'))
arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c'))
arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c'))

View file

@ -377,7 +377,7 @@ static int smmu_get_cd(SMMUv3State *s, STE *ste, SMMUTransCfg *cfg,
qemu_log_mask(LOG_GUEST_ERROR,
"Cannot fetch pte at address=0x%"PRIx64"\n", addr);
event->type = SMMU_EVT_F_CD_FETCH;
event->u.f_ste_fetch.addr = addr;
event->u.f_cd_fetch.addr = addr;
return -EINVAL;
}
for (i = 0; i < ARRAY_SIZE(buf->word); i++) {

View file

@ -53,6 +53,7 @@
#include "hw/loader.h"
#include "qapi/error.h"
#include "qemu/bitops.h"
#include "qemu/cutils.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "hw/pci-host/gpex.h"
@ -192,6 +193,10 @@ static const MemMapEntry base_memmap[] = {
[VIRT_MEM] = { GiB, LEGACY_RAMLIMIT_BYTES },
};
/* Update the docs for highmem-mmio-size when changing this default */
#define DEFAULT_HIGH_PCIE_MMIO_SIZE_GB 512
#define DEFAULT_HIGH_PCIE_MMIO_SIZE (DEFAULT_HIGH_PCIE_MMIO_SIZE_GB * GiB)
/*
* Highmem IO Regions: This memory map is floating, located after the RAM.
* Each MemMapEntry base (GPA) will be dynamically computed, depending on the
@ -207,13 +212,16 @@ static const MemMapEntry base_memmap[] = {
* PA space for one specific region is always reserved, even if the region
* has been disabled or doesn't fit into the PA space. However, the PA space
* for the region won't be reserved in these circumstances with compact layout.
*
* Note that the highmem-mmio-size property will update the high PCIE MMIO size
* field in this array.
*/
static MemMapEntry extended_memmap[] = {
/* Additional 64 MB redist region (can contain up to 512 redistributors) */
[VIRT_HIGH_GIC_REDIST2] = { 0x0, 64 * MiB },
[VIRT_HIGH_PCIE_ECAM] = { 0x0, 256 * MiB },
/* Second PCIe window */
[VIRT_HIGH_PCIE_MMIO] = { 0x0, 512 * GiB },
[VIRT_HIGH_PCIE_MMIO] = { 0x0, DEFAULT_HIGH_PCIE_MMIO_SIZE },
};
static const int a15irqmap[] = {
@ -2550,6 +2558,40 @@ static void virt_set_highmem_mmio(Object *obj, bool value, Error **errp)
vms->highmem_mmio = value;
}
static void virt_get_highmem_mmio_size(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
{
uint64_t size = extended_memmap[VIRT_HIGH_PCIE_MMIO].size;
visit_type_size(v, name, &size, errp);
}
static void virt_set_highmem_mmio_size(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
{
uint64_t size;
if (!visit_type_size(v, name, &size, errp)) {
return;
}
if (!is_power_of_2(size)) {
error_setg(errp, "highmem-mmio-size is not a power of 2");
return;
}
if (size < DEFAULT_HIGH_PCIE_MMIO_SIZE) {
char *sz = size_to_str(DEFAULT_HIGH_PCIE_MMIO_SIZE);
error_setg(errp, "highmem-mmio-size cannot be set to a lower value "
"than the default (%s)", sz);
g_free(sz);
return;
}
extended_memmap[VIRT_HIGH_PCIE_MMIO].size = size;
}
static bool virt_get_its(Object *obj, Error **errp)
{
@ -3207,6 +3249,14 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
"Set on/off to enable/disable high "
"memory region for PCI MMIO");
object_class_property_add(oc, "highmem-mmio-size", "size",
virt_get_highmem_mmio_size,
virt_set_highmem_mmio_size,
NULL, NULL);
object_class_property_set_description(oc, "highmem-mmio-size",
"Set the high memory region size "
"for PCI MMIO");
object_class_property_add_str(oc, "gic-version", virt_get_gic_version,
virt_set_gic_version);
object_class_property_set_description(oc, "gic-version",

View file

@ -32,8 +32,8 @@
#define FIT_LOADER_MAX_PATH (128)
static const void *fit_load_image_alloc(const void *itb, const char *name,
int *poff, size_t *psz, Error **errp)
static void *fit_load_image_alloc(const void *itb, const char *name,
int *poff, size_t *psz, Error **errp)
{
const void *data;
const char *comp;
@ -80,11 +80,11 @@ static const void *fit_load_image_alloc(const void *itb, const char *name,
return NULL;
}
data = g_realloc(uncomp_data, uncomp_len);
uncomp_data = g_realloc(uncomp_data, uncomp_len);
if (psz) {
*psz = uncomp_len;
}
return data;
return uncomp_data;
}
error_setg(errp, "unknown compression '%s'", comp);
@ -177,13 +177,12 @@ out:
static int fit_load_fdt(const struct fit_loader *ldr, const void *itb,
int cfg, void *opaque, const void *match_data,
hwaddr kernel_end, Error **errp)
hwaddr kernel_end, void **pfdt, Error **errp)
{
ERRP_GUARD();
Error *err = NULL;
const char *name;
const void *data;
const void *load_data;
void *data;
hwaddr load_addr;
int img_off;
size_t sz;
@ -194,7 +193,7 @@ static int fit_load_fdt(const struct fit_loader *ldr, const void *itb,
return 0;
}
load_data = data = fit_load_image_alloc(itb, name, &img_off, &sz, errp);
data = fit_load_image_alloc(itb, name, &img_off, &sz, errp);
if (!data) {
error_prepend(errp, "unable to load FDT image from FIT: ");
return -EINVAL;
@ -211,19 +210,23 @@ static int fit_load_fdt(const struct fit_loader *ldr, const void *itb,
}
if (ldr->fdt_filter) {
load_data = ldr->fdt_filter(opaque, data, match_data, &load_addr);
void *filtered_data;
filtered_data = ldr->fdt_filter(opaque, data, match_data, &load_addr);
if (filtered_data != data) {
g_free(data);
data = filtered_data;
}
}
load_addr = ldr->addr_to_phys(opaque, load_addr);
sz = fdt_totalsize(load_data);
rom_add_blob_fixed(name, load_data, sz, load_addr);
sz = fdt_totalsize(data);
rom_add_blob_fixed(name, data, sz, load_addr);
ret = 0;
*pfdt = data;
return 0;
out:
g_free((void *) data);
if (data != load_data) {
g_free((void *) load_data);
}
return ret;
}
@ -259,7 +262,8 @@ out:
return ret;
}
int load_fit(const struct fit_loader *ldr, const char *filename, void *opaque)
int load_fit(const struct fit_loader *ldr, const char *filename,
void **pfdt, void *opaque)
{
Error *err = NULL;
const struct fit_loader_match *match;
@ -323,7 +327,7 @@ int load_fit(const struct fit_loader *ldr, const char *filename, void *opaque)
goto out;
}
ret = fit_load_fdt(ldr, itb, cfg_off, opaque, match_data, kernel_end,
ret = fit_load_fdt(ldr, itb, cfg_off, opaque, match_data, kernel_end, pfdt,
&err);
if (ret) {
error_report_err(err);

View file

@ -19,6 +19,7 @@
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "qapi/qapi-visit-machine.h"
#include "qapi/qapi-commands-machine.h"
#include "qemu/madvise.h"
#include "qom/object_interfaces.h"
#include "system/cpus.h"
@ -1696,6 +1697,22 @@ void qemu_remove_machine_init_done_notifier(Notifier *notify)
notifier_remove(notify);
}
static void handle_machine_dumpdtb(MachineState *ms)
{
if (!ms->dumpdtb) {
return;
}
#ifdef CONFIG_FDT
qmp_dumpdtb(ms->dumpdtb, &error_fatal);
exit(0);
#else
error_report("This machine doesn't have an FDT");
error_printf("(this machine type definitely doesn't use FDT, and "
"this QEMU doesn't have FDT support compiled in)\n");
exit(1);
#endif
}
void qdev_machine_creation_done(void)
{
cpu_synchronize_all_post_init();
@ -1712,6 +1729,12 @@ void qdev_machine_creation_done(void)
phase_advance(PHASE_MACHINE_READY);
qdev_assert_realized_properly();
/*
* If the user used -machine dumpdtb=file.dtb to request that we
* dump the DTB to a file, do it now, and exit.
*/
handle_machine_dumpdtb(current_machine);
/* TODO: once all bus devices are qdevified, this should be done
* when bus is created by qdev.c */
/*

View file

@ -16,6 +16,14 @@ config SIFIVE_GPIO
config STM32L4X5_GPIO
bool
config PCA9552
bool
depends on I2C
config PCA9554
bool
depends on I2C
config PCF8574
bool
depends on I2C

View file

@ -527,7 +527,6 @@ void virt_fdt_setup(LoongArchVirtMachineState *lvms)
* Put the FDT into the memory map as a ROM image: this will ensure
* the FDT is copied again upon reset, even if addr points into RAM.
*/
qemu_fdt_dumpdtb(machine->fdt, lvms->fdt_size);
rom_add_blob_fixed_as("fdt", machine->fdt, lvms->fdt_size, FDT_BASE,
&address_space_memory);
qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds,

View file

@ -358,8 +358,8 @@ static void gen_firmware(void *p, hwaddr kernel_entry, hwaddr fdt_addr)
kernel_entry);
}
static const void *boston_fdt_filter(void *opaque, const void *fdt_orig,
const void *match_data, hwaddr *load_addr)
static void *boston_fdt_filter(void *opaque, const void *fdt_orig,
const void *match_data, hwaddr *load_addr)
{
BostonState *s = BOSTON(opaque);
MachineState *machine = s->mach;
@ -395,7 +395,6 @@ static const void *boston_fdt_filter(void *opaque, const void *fdt_orig,
1, ram_high_sz);
fdt = g_realloc(fdt, fdt_totalsize(fdt));
qemu_fdt_dumpdtb(fdt, fdt_sz);
s->fdt_base = *load_addr;
@ -797,7 +796,7 @@ static void boston_mach_init(MachineState *machine)
if (kernel_size > 0) {
int dt_size;
g_autofree const void *dtb_file_data = NULL;
g_autofree const void *dtb_load_data = NULL;
void *dtb_load_data = NULL;
hwaddr dtb_paddr = QEMU_ALIGN_UP(kernel_high, 64 * KiB);
hwaddr dtb_vaddr = cpu_mips_phys_to_kseg0(NULL, dtb_paddr);
@ -810,6 +809,12 @@ static void boston_mach_init(MachineState *machine)
dtb_load_data = boston_fdt_filter(s, dtb_file_data,
NULL, &dtb_vaddr);
if (!dtb_load_data) {
/* boston_fdt_filter() already printed the error for us */
exit(1);
}
machine->fdt = dtb_load_data;
/* Calculate real fdt size after filter */
dt_size = fdt_totalsize(dtb_load_data);
@ -818,7 +823,8 @@ static void boston_mach_init(MachineState *machine)
rom_ptr(dtb_paddr, dt_size));
} else {
/* Try to load file as FIT */
fit_err = load_fit(&boston_fit_loader, machine->kernel_filename, s);
fit_err = load_fit(&boston_fit_loader, machine->kernel_filename,
&machine->fdt, s);
if (fit_err) {
error_report("unable to load kernel image");
exit(1);

View file

@ -30,14 +30,6 @@ config EDU
default y if TEST_DEVICES
depends on PCI && MSI_NONBROKEN
config PCA9552
bool
depends on I2C
config PCA9554
bool
depends on I2C
config I2C_ECHO
bool
default y if TEST_DEVICES
@ -86,6 +78,12 @@ config IMX
select SSI
select USB_EHCI_SYSBUS
config FSL_IMX8MP_ANALOG
bool
config FSL_IMX8MP_CCM
bool
config STM32_RCC
bool

160
hw/misc/imx8mp_analog.c Normal file
View file

@ -0,0 +1,160 @@
/*
* Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
*
* i.MX 8M Plus ANALOG IP block emulation code
*
* Based on hw/misc/imx7_ccm.c
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "hw/misc/imx8mp_analog.h"
#include "migration/vmstate.h"
#define ANALOG_PLL_LOCK BIT(31)
static void imx8mp_analog_reset(DeviceState *dev)
{
IMX8MPAnalogState *s = IMX8MP_ANALOG(dev);
memset(s->analog, 0, sizeof(s->analog));
s->analog[ANALOG_AUDIO_PLL1_GEN_CTRL] = 0x00002010;
s->analog[ANALOG_AUDIO_PLL1_FDIV_CTL0] = 0x00145032;
s->analog[ANALOG_AUDIO_PLL1_FDIV_CTL1] = 0x00000000;
s->analog[ANALOG_AUDIO_PLL1_SSCG_CTRL] = 0x00000000;
s->analog[ANALOG_AUDIO_PLL1_MNIT_CTRL] = 0x00100103;
s->analog[ANALOG_AUDIO_PLL2_GEN_CTRL] = 0x00002010;
s->analog[ANALOG_AUDIO_PLL2_FDIV_CTL0] = 0x00145032;
s->analog[ANALOG_AUDIO_PLL2_FDIV_CTL1] = 0x00000000;
s->analog[ANALOG_AUDIO_PLL2_SSCG_CTRL] = 0x00000000;
s->analog[ANALOG_AUDIO_PLL2_MNIT_CTRL] = 0x00100103;
s->analog[ANALOG_VIDEO_PLL1_GEN_CTRL] = 0x00002010;
s->analog[ANALOG_VIDEO_PLL1_FDIV_CTL0] = 0x00145032;
s->analog[ANALOG_VIDEO_PLL1_FDIV_CTL1] = 0x00000000;
s->analog[ANALOG_VIDEO_PLL1_SSCG_CTRL] = 0x00000000;
s->analog[ANALOG_VIDEO_PLL1_MNIT_CTRL] = 0x00100103;
s->analog[ANALOG_DRAM_PLL_GEN_CTRL] = 0x00002010;
s->analog[ANALOG_DRAM_PLL_FDIV_CTL0] = 0x0012c032;
s->analog[ANALOG_DRAM_PLL_FDIV_CTL1] = 0x00000000;
s->analog[ANALOG_DRAM_PLL_SSCG_CTRL] = 0x00000000;
s->analog[ANALOG_DRAM_PLL_MNIT_CTRL] = 0x00100103;
s->analog[ANALOG_GPU_PLL_GEN_CTRL] = 0x00000810;
s->analog[ANALOG_GPU_PLL_FDIV_CTL0] = 0x000c8031;
s->analog[ANALOG_GPU_PLL_LOCKD_CTRL] = 0x0010003f;
s->analog[ANALOG_GPU_PLL_MNIT_CTRL] = 0x00280081;
s->analog[ANALOG_VPU_PLL_GEN_CTRL] = 0x00000810;
s->analog[ANALOG_VPU_PLL_FDIV_CTL0] = 0x0012c032;
s->analog[ANALOG_VPU_PLL_LOCKD_CTRL] = 0x0010003f;
s->analog[ANALOG_VPU_PLL_MNIT_CTRL] = 0x00280081;
s->analog[ANALOG_ARM_PLL_GEN_CTRL] = 0x00000810;
s->analog[ANALOG_ARM_PLL_FDIV_CTL0] = 0x000fa031;
s->analog[ANALOG_ARM_PLL_LOCKD_CTRL] = 0x0010003f;
s->analog[ANALOG_ARM_PLL_MNIT_CTRL] = 0x00280081;
s->analog[ANALOG_SYS_PLL1_GEN_CTRL] = 0x0aaaa810;
s->analog[ANALOG_SYS_PLL1_FDIV_CTL0] = 0x00190032;
s->analog[ANALOG_SYS_PLL1_LOCKD_CTRL] = 0x0010003f;
s->analog[ANALOG_SYS_PLL1_MNIT_CTRL] = 0x00280081;
s->analog[ANALOG_SYS_PLL2_GEN_CTRL] = 0x0aaaa810;
s->analog[ANALOG_SYS_PLL2_FDIV_CTL0] = 0x000fa031;
s->analog[ANALOG_SYS_PLL2_LOCKD_CTRL] = 0x0010003f;
s->analog[ANALOG_SYS_PLL2_MNIT_CTRL] = 0x00280081;
s->analog[ANALOG_SYS_PLL3_GEN_CTRL] = 0x00000810;
s->analog[ANALOG_SYS_PLL3_FDIV_CTL0] = 0x000fa031;
s->analog[ANALOG_SYS_PLL3_LOCKD_CTRL] = 0x0010003f;
s->analog[ANALOG_SYS_PLL3_MNIT_CTRL] = 0x00280081;
s->analog[ANALOG_OSC_MISC_CFG] = 0x00000000;
s->analog[ANALOG_ANAMIX_PLL_MNIT_CTL] = 0x00000000;
s->analog[ANALOG_DIGPROG] = 0x00824010;
/* all PLLs need to be locked */
s->analog[ANALOG_AUDIO_PLL1_GEN_CTRL] |= ANALOG_PLL_LOCK;
s->analog[ANALOG_AUDIO_PLL2_GEN_CTRL] |= ANALOG_PLL_LOCK;
s->analog[ANALOG_VIDEO_PLL1_GEN_CTRL] |= ANALOG_PLL_LOCK;
s->analog[ANALOG_DRAM_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
s->analog[ANALOG_GPU_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
s->analog[ANALOG_VPU_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
s->analog[ANALOG_ARM_PLL_GEN_CTRL] |= ANALOG_PLL_LOCK;
s->analog[ANALOG_SYS_PLL1_GEN_CTRL] |= ANALOG_PLL_LOCK;
s->analog[ANALOG_SYS_PLL2_GEN_CTRL] |= ANALOG_PLL_LOCK;
s->analog[ANALOG_SYS_PLL3_GEN_CTRL] |= ANALOG_PLL_LOCK;
}
static uint64_t imx8mp_analog_read(void *opaque, hwaddr offset, unsigned size)
{
IMX8MPAnalogState *s = opaque;
return s->analog[offset >> 2];
}
static void imx8mp_analog_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
IMX8MPAnalogState *s = opaque;
if (offset >> 2 == ANALOG_DIGPROG) {
qemu_log_mask(LOG_GUEST_ERROR,
"Guest write to read-only ANALOG_DIGPROG register\n");
} else {
s->analog[offset >> 2] = value;
}
}
static const struct MemoryRegionOps imx8mp_analog_ops = {
.read = imx8mp_analog_read,
.write = imx8mp_analog_write,
.endianness = DEVICE_NATIVE_ENDIAN,
.impl = {
.min_access_size = 4,
.max_access_size = 4,
.unaligned = false,
},
};
static void imx8mp_analog_init(Object *obj)
{
IMX8MPAnalogState *s = IMX8MP_ANALOG(obj);
SysBusDevice *sd = SYS_BUS_DEVICE(obj);
memory_region_init(&s->mmio.container, obj, TYPE_IMX8MP_ANALOG, 0x10000);
memory_region_init_io(&s->mmio.analog, obj, &imx8mp_analog_ops, s,
TYPE_IMX8MP_ANALOG, sizeof(s->analog));
memory_region_add_subregion(&s->mmio.container, 0, &s->mmio.analog);
sysbus_init_mmio(sd, &s->mmio.container);
}
static const VMStateDescription imx8mp_analog_vmstate = {
.name = TYPE_IMX8MP_ANALOG,
.version_id = 1,
.minimum_version_id = 1,
.fields = (const VMStateField[]) {
VMSTATE_UINT32_ARRAY(analog, IMX8MPAnalogState, ANALOG_MAX),
VMSTATE_END_OF_LIST()
},
};
static void imx8mp_analog_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
device_class_set_legacy_reset(dc, imx8mp_analog_reset);
dc->vmsd = &imx8mp_analog_vmstate;
dc->desc = "i.MX 8M Plus Analog Module";
}
static const TypeInfo imx8mp_analog_types[] = {
{
.name = TYPE_IMX8MP_ANALOG,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(IMX8MPAnalogState),
.instance_init = imx8mp_analog_init,
.class_init = imx8mp_analog_class_init,
}
};
DEFINE_TYPES(imx8mp_analog_types);

175
hw/misc/imx8mp_ccm.c Normal file
View file

@ -0,0 +1,175 @@
/*
* Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
*
* i.MX 8M Plus CCM IP block emulation code
*
* Based on hw/misc/imx7_ccm.c
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "hw/misc/imx8mp_ccm.h"
#include "migration/vmstate.h"
#include "trace.h"
#define CKIH_FREQ 16000000 /* 16MHz crystal input */
static void imx8mp_ccm_reset(DeviceState *dev)
{
IMX8MPCCMState *s = IMX8MP_CCM(dev);
memset(s->ccm, 0, sizeof(s->ccm));
}
#define CCM_INDEX(offset) (((offset) & ~(hwaddr)0xF) / sizeof(uint32_t))
#define CCM_BITOP(offset) ((offset) & (hwaddr)0xF)
enum {
CCM_BITOP_NONE = 0x00,
CCM_BITOP_SET = 0x04,
CCM_BITOP_CLR = 0x08,
CCM_BITOP_TOG = 0x0C,
};
static uint64_t imx8mp_set_clr_tog_read(void *opaque, hwaddr offset,
unsigned size)
{
const uint32_t *mmio = opaque;
return mmio[CCM_INDEX(offset)];
}
static void imx8mp_set_clr_tog_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
const uint8_t bitop = CCM_BITOP(offset);
const uint32_t index = CCM_INDEX(offset);
uint32_t *mmio = opaque;
switch (bitop) {
case CCM_BITOP_NONE:
mmio[index] = value;
break;
case CCM_BITOP_SET:
mmio[index] |= value;
break;
case CCM_BITOP_CLR:
mmio[index] &= ~value;
break;
case CCM_BITOP_TOG:
mmio[index] ^= value;
break;
};
}
static const struct MemoryRegionOps imx8mp_set_clr_tog_ops = {
.read = imx8mp_set_clr_tog_read,
.write = imx8mp_set_clr_tog_write,
.endianness = DEVICE_NATIVE_ENDIAN,
.impl = {
/*
* Our device would not work correctly if the guest was doing
* unaligned access. This might not be a limitation on the real
* device but in practice there is no reason for a guest to access
* this device unaligned.
*/
.min_access_size = 4,
.max_access_size = 4,
.unaligned = false,
},
};
static void imx8mp_ccm_init(Object *obj)
{
SysBusDevice *sd = SYS_BUS_DEVICE(obj);
IMX8MPCCMState *s = IMX8MP_CCM(obj);
memory_region_init_io(&s->iomem,
obj,
&imx8mp_set_clr_tog_ops,
s->ccm,
TYPE_IMX8MP_CCM ".ccm",
sizeof(s->ccm));
sysbus_init_mmio(sd, &s->iomem);
}
static const VMStateDescription imx8mp_ccm_vmstate = {
.name = TYPE_IMX8MP_CCM,
.version_id = 1,
.minimum_version_id = 1,
.fields = (const VMStateField[]) {
VMSTATE_UINT32_ARRAY(ccm, IMX8MPCCMState, CCM_MAX),
VMSTATE_END_OF_LIST()
},
};
static uint32_t imx8mp_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
{
/*
* This function is "consumed" by GPT emulation code. Some clocks
* have fixed frequencies and we can provide requested frequency
* easily. However for CCM provided clocks (like IPG) each GPT
* timer can have its own clock root.
* This means we need additional information when calling this
* function to know the requester's identity.
*/
uint32_t freq = 0;
switch (clock) {
case CLK_NONE:
break;
case CLK_32k:
freq = CKIL_FREQ;
break;
case CLK_HIGH:
freq = CKIH_FREQ;
break;
case CLK_IPG:
case CLK_IPG_HIGH:
/*
* For now we don't have a way to figure out the device this
* function is called for. Until then the IPG derived clocks
* are left unimplemented.
*/
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Clock %d Not implemented\n",
TYPE_IMX8MP_CCM, __func__, clock);
break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
TYPE_IMX8MP_CCM, __func__, clock);
break;
}
trace_ccm_clock_freq(clock, freq);
return freq;
}
static void imx8mp_ccm_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
device_class_set_legacy_reset(dc, imx8mp_ccm_reset);
dc->vmsd = &imx8mp_ccm_vmstate;
dc->desc = "i.MX 8M Plus Clock Control Module";
ccm->get_clock_frequency = imx8mp_ccm_get_clock_frequency;
}
static const TypeInfo imx8mp_ccm_types[] = {
{
.name = TYPE_IMX8MP_CCM,
.parent = TYPE_IMX_CCM,
.instance_size = sizeof(IMX8MPCCMState),
.instance_init = imx8mp_ccm_init,
.class_init = imx8mp_ccm_class_init,
},
};
DEFINE_TYPES(imx8mp_ccm_types);

View file

@ -55,6 +55,8 @@ system_ss.add(when: 'CONFIG_AXP2XX_PMU', if_true: files('axp2xx.c'))
system_ss.add(when: 'CONFIG_REALVIEW', if_true: files('arm_sysctl.c'))
system_ss.add(when: 'CONFIG_ECCMEMCTL', if_true: files('eccmemctl.c'))
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_pmu.c', 'exynos4210_clk.c', 'exynos4210_rng.c'))
system_ss.add(when: 'CONFIG_FSL_IMX8MP_ANALOG', if_true: files('imx8mp_analog.c'))
system_ss.add(when: 'CONFIG_FSL_IMX8MP_CCM', if_true: files('imx8mp_ccm.c'))
system_ss.add(when: 'CONFIG_IMX', if_true: files(
'imx25_ccm.c',
'imx31_ccm.c',

View file

@ -964,8 +964,9 @@ static void npcm_clk_enter_reset(Object *obj, ResetType type)
NPCMCLKState *s = NPCM_CLK(obj);
NPCMCLKClass *c = NPCM_CLK_GET_CLASS(s);
g_assert(sizeof(s->regs) >= c->nr_regs * sizeof(uint32_t));
memcpy(s->regs, c->cold_reset_values, sizeof(s->regs));
size_t sizeof_regs = c->nr_regs * sizeof(uint32_t);
g_assert(sizeof(s->regs) >= sizeof_regs);
memcpy(s->regs, c->cold_reset_values, sizeof_regs);
s->ref_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
npcm7xx_clk_update_all_clocks(s);
/*

View file

@ -90,8 +90,8 @@ hwaddr openrisc_load_initrd(void *fdt, const char *filename,
return start + size;
}
uint32_t openrisc_load_fdt(void *fdt, hwaddr load_start,
uint64_t mem_size)
uint32_t openrisc_load_fdt(MachineState *ms, void *fdt,
hwaddr load_start, uint64_t mem_size)
{
uint32_t fdt_addr;
int ret;
@ -109,7 +109,9 @@ uint32_t openrisc_load_fdt(void *fdt, hwaddr load_start,
/* Should only fail if we've built a corrupted tree */
g_assert(ret == 0);
/* copy in the device tree */
qemu_fdt_dumpdtb(fdt, fdtsize);
/* Save FDT for dumpdtb monitor command */
ms->fdt = fdt;
rom_add_blob_fixed_as("fdt", fdt, fdtsize, fdt_addr,
&address_space_memory);

View file

@ -354,7 +354,7 @@ static void openrisc_sim_init(MachineState *machine)
machine->initrd_filename,
load_addr, machine->ram_size);
}
boot_info.fdt_addr = openrisc_load_fdt(state->fdt, load_addr,
boot_info.fdt_addr = openrisc_load_fdt(machine, state->fdt, load_addr,
machine->ram_size);
}
}

View file

@ -540,7 +540,7 @@ static void openrisc_virt_init(MachineState *machine)
machine->initrd_filename,
load_addr, machine->ram_size);
}
boot_info.fdt_addr = openrisc_load_fdt(state->fdt, load_addr,
boot_info.fdt_addr = openrisc_load_fdt(machine, state->fdt, load_addr,
machine->ram_size);
}
}

View file

@ -99,6 +99,9 @@ config ASTRO
bool
select PCI
config PCI_EXPRESS_FSL_IMX8M_PHY
bool
config GT64120
bool
select PCI

View file

@ -55,6 +55,17 @@
#define DESIGNWARE_PCIE_ATU_DEVFN(x) (((x) >> 16) & 0xff)
#define DESIGNWARE_PCIE_ATU_UPPER_TARGET 0x91C
static void designware_pcie_root_bus_class_init(ObjectClass *klass, void *data)
{
BusClass *k = BUS_CLASS(klass);
/*
* Designware has only a single root complex. Enforce the limit on the
* parent bus
*/
k->max_dev = 1;
}
static DesignwarePCIEHost *
designware_pcie_root_to_host(DesignwarePCIERoot *root)
{
@ -699,7 +710,7 @@ static void designware_pcie_host_realize(DeviceState *dev, Error **errp)
&s->pci.memory,
&s->pci.io,
0, 4,
TYPE_PCIE_BUS);
TYPE_DESIGNWARE_PCIE_ROOT_BUS);
pci->bus->flags |= PCI_BUS_EXTENDED_CONFIG_SPACE;
memory_region_init(&s->pci.address_space_root,
@ -754,6 +765,11 @@ static void designware_pcie_host_init(Object *obj)
static const TypeInfo designware_pcie_types[] = {
{
.name = TYPE_DESIGNWARE_PCIE_ROOT_BUS,
.parent = TYPE_PCIE_BUS,
.instance_size = sizeof(DesignwarePCIERootBus),
.class_init = designware_pcie_root_bus_class_init,
}, {
.name = TYPE_DESIGNWARE_PCIE_HOST,
.parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(DesignwarePCIEHost),

View file

@ -0,0 +1,98 @@
/*
* i.MX8 PCIe PHY emulation
*
* Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "hw/pci-host/fsl_imx8m_phy.h"
#include "hw/resettable.h"
#include "migration/vmstate.h"
#define CMN_REG075 0x1d4
#define ANA_PLL_LOCK_DONE BIT(1)
#define ANA_PLL_AFC_DONE BIT(0)
static uint64_t fsl_imx8m_pcie_phy_read(void *opaque, hwaddr offset,
unsigned size)
{
FslImx8mPciePhyState *s = opaque;
if (offset == CMN_REG075) {
return s->data[offset] | ANA_PLL_LOCK_DONE | ANA_PLL_AFC_DONE;
}
return s->data[offset];
}
static void fsl_imx8m_pcie_phy_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
FslImx8mPciePhyState *s = opaque;
s->data[offset] = value;
}
static const MemoryRegionOps fsl_imx8m_pcie_phy_ops = {
.read = fsl_imx8m_pcie_phy_read,
.write = fsl_imx8m_pcie_phy_write,
.impl = {
.min_access_size = 1,
.max_access_size = 1,
},
.valid = {
.min_access_size = 1,
.max_access_size = 8,
},
.endianness = DEVICE_LITTLE_ENDIAN,
};
static void fsl_imx8m_pcie_phy_realize(DeviceState *dev, Error **errp)
{
FslImx8mPciePhyState *s = FSL_IMX8M_PCIE_PHY(dev);
memory_region_init_io(&s->iomem, OBJECT(s), &fsl_imx8m_pcie_phy_ops, s,
TYPE_FSL_IMX8M_PCIE_PHY, ARRAY_SIZE(s->data));
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
}
static void fsl_imx8m_pcie_phy_reset_hold(Object *obj, ResetType type)
{
FslImx8mPciePhyState *s = FSL_IMX8M_PCIE_PHY(obj);
memset(s->data, 0, sizeof(s->data));
}
static const VMStateDescription fsl_imx8m_pcie_phy_vmstate = {
.name = "fsl-imx8m-pcie-phy",
.version_id = 1,
.minimum_version_id = 1,
.fields = (const VMStateField[]) {
VMSTATE_UINT8_ARRAY(data, FslImx8mPciePhyState,
FSL_IMX8M_PCIE_PHY_DATA_SIZE),
VMSTATE_END_OF_LIST()
}
};
static void fsl_imx8m_pcie_phy_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
dc->realize = fsl_imx8m_pcie_phy_realize;
dc->vmsd = &fsl_imx8m_pcie_phy_vmstate;
rc->phases.hold = fsl_imx8m_pcie_phy_reset_hold;
}
static const TypeInfo fsl_imx8m_pcie_phy_types[] = {
{
.name = TYPE_FSL_IMX8M_PCIE_PHY,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(FslImx8mPciePhyState),
.class_init = fsl_imx8m_pcie_phy_class_init,
}
};
DEFINE_TYPES(fsl_imx8m_pcie_phy_types)

View file

@ -28,6 +28,7 @@ pci_ss.add(when: 'CONFIG_ARTICIA', if_true: files('articia.c'))
pci_ss.add(when: 'CONFIG_MV64361', if_true: files('mv64361.c'))
# ARM devices
pci_ss.add(when: 'CONFIG_PCI_EXPRESS_FSL_IMX8M_PHY', if_true: files('fsl_imx8m_phy.c'))
pci_ss.add(when: 'CONFIG_VERSATILE_PCI', if_true: files('versatile.c'))
# HPPA devices

View file

@ -658,7 +658,6 @@ static int ppce500_load_device_tree(PPCE500MachineState *pms,
done:
if (!dry_run) {
qemu_fdt_dumpdtb(fdt, fdt_size);
cpu_physical_memory_write(addr, fdt, fdt_size);
/* Set machine->fdt for 'dumpdtb' QMP/HMP command */

View file

@ -417,7 +417,6 @@ static void pegasos2_machine_reset(MachineState *machine, ResetType type)
d[1] = cpu_to_be64(pm->kernel_size - (pm->kernel_entry - pm->kernel_addr));
qemu_fdt_setprop(fdt, "/chosen", "qemu,boot-kernel", d, sizeof(d));
qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
g_free(pm->fdt_blob);
pm->fdt_blob = fdt;

View file

@ -744,7 +744,6 @@ static void pnv_reset(MachineState *machine, ResetType type)
_FDT((fdt_pack(fdt)));
}
qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
/* Update machine->fdt with latest fdt */

View file

@ -1760,7 +1760,6 @@ static void spapr_machine_reset(MachineState *machine, ResetType type)
0, fdt_addr, 0);
cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
}
qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
g_free(spapr->fdt_blob);
spapr->fdt_size = fdt_totalsize(fdt);

View file

@ -374,8 +374,6 @@ void riscv_load_fdt(hwaddr fdt_addr, void *fdt)
uint32_t fdtsize = fdt_totalsize(fdt);
/* copy in the device tree */
qemu_fdt_dumpdtb(fdt, fdtsize);
rom_add_blob_fixed_as("fdt", fdt, fdtsize, fdt_addr,
&address_space_memory);
qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds,

View file

@ -126,6 +126,17 @@ static const IMXClk imx7_gpt_clocks[] = {
CLK_NONE, /* 111 not defined */
};
static const IMXClk imx8mp_gpt_clocks[] = {
CLK_NONE, /* 000 No clock source */
CLK_IPG, /* 001 ipg_clk, 532MHz */
CLK_IPG_HIGH, /* 010 ipg_clk_highfreq */
CLK_EXT, /* 011 External clock */
CLK_32k, /* 100 ipg_clk_32k */
CLK_HIGH, /* 101 ipg_clk_16M */
CLK_NONE, /* 110 not defined */
CLK_NONE, /* 111 not defined */
};
/* Must be called from within ptimer_transaction_begin/commit block */
static void imx_gpt_set_freq(IMXGPTState *s)
{
@ -552,6 +563,13 @@ static void imx7_gpt_init(Object *obj)
s->clocks = imx7_gpt_clocks;
}
static void imx8mp_gpt_init(Object *obj)
{
IMXGPTState *s = IMX_GPT(obj);
s->clocks = imx8mp_gpt_clocks;
}
static const TypeInfo imx25_gpt_info = {
.name = TYPE_IMX25_GPT,
.parent = TYPE_SYS_BUS_DEVICE,
@ -584,6 +602,12 @@ static const TypeInfo imx7_gpt_info = {
.instance_init = imx7_gpt_init,
};
static const TypeInfo imx8mp_gpt_info = {
.name = TYPE_IMX8MP_GPT,
.parent = TYPE_IMX25_GPT,
.instance_init = imx8mp_gpt_init,
};
static void imx_gpt_register_types(void)
{
type_register_static(&imx25_gpt_info);
@ -591,6 +615,7 @@ static void imx_gpt_register_types(void)
type_register_static(&imx6_gpt_info);
type_register_static(&imx6ul_gpt_info);
type_register_static(&imx7_gpt_info);
type_register_static(&imx8mp_gpt_info);
}
type_init(imx_gpt_register_types)

View file

@ -343,6 +343,8 @@ REG32(GFLADJ, 0x530)
FIELD(GFLADJ, GFLADJ_REFCLK_FLADJ, 8, 14)
FIELD(GFLADJ, GFLADJ_30MHZ_SDBND_SEL, 7, 1)
FIELD(GFLADJ, GFLADJ_30MHZ, 0, 6)
REG32(GUSB2RHBCTL, 0x540)
FIELD(GUSB2RHBCTL, OVRD_L1TIMEOUT, 0, 4)
#define DWC3_GLOBAL_OFFSET 0xC100
static void reset_csr(USBDWC3 * s)
@ -560,6 +562,9 @@ static const RegisterAccessInfo usb_dwc3_regs_info[] = {
.rsvd = 0x40,
.ro = 0x400040,
.unimp = 0xffffffff,
},{ .name = "GUSB2RHBCTL", .addr = A_GUSB2RHBCTL,
.rsvd = 0xfffffff0,
.unimp = 0xffffffff,
}
};

View file

@ -75,6 +75,12 @@ static inline void set_floatx80_rounding_precision(FloatX80RoundPrec val,
status->floatx80_rounding_precision = val;
}
static inline void set_floatx80_behaviour(FloatX80Behaviour b,
float_status *status)
{
status->floatx80_behaviour = b;
}
static inline void set_float_2nan_prop_rule(Float2NaNPropRule rule,
float_status *status)
{
@ -151,6 +157,12 @@ get_floatx80_rounding_precision(const float_status *status)
return status->floatx80_rounding_precision;
}
static inline FloatX80Behaviour
get_floatx80_behaviour(const float_status *status)
{
return status->floatx80_behaviour;
}
static inline Float2NaNPropRule
get_float_2nan_prop_rule(const float_status *status)
{

View file

@ -320,6 +320,56 @@ typedef enum __attribute__((__packed__)) {
float_ftz_before_rounding = 1,
} FloatFTZDetection;
/*
* floatx80 is primarily used by x86 and m68k, and there are
* differences in the handling, largely related to the explicit
* Integer bit which floatx80 has and the other float formats do not.
* These flag values allow specification of the target's requirements
* and can be ORed together to set floatx80_behaviour.
*/
typedef enum __attribute__((__packed__)) {
/* In the default Infinity value, is the Integer bit 0 ? */
floatx80_default_inf_int_bit_is_zero = 1,
/*
* Are Pseudo-infinities (Inf with the Integer bit zero) valid?
* If so, floatx80_is_infinity() will return true for them.
* If not, floatx80_invalid_encoding will return false for them,
* and using them as inputs to a float op will raise Invalid.
*/
floatx80_pseudo_inf_valid = 2,
/*
* Are Pseudo-NaNs (NaNs where the Integer bit is zero) valid?
* If not, floatx80_invalid_encoding() will return false for them,
* and using them as inputs to a float op will raise Invalid.
*/
floatx80_pseudo_nan_valid = 4,
/*
* Are Unnormals (0 < exp < 0x7fff, Integer bit zero) valid?
* If not, floatx80_invalid_encoding() will return false for them,
* and using them as inputs to a float op will raise Invalid.
*/
floatx80_unnormal_valid = 8,
/*
* If the exponent is 0 and the Integer bit is set, Intel call
* this a "pseudo-denormal"; x86 supports that only on input
* (treating them as denormals by ignoring the Integer bit).
* For m68k, the integer bit is considered validly part of the
* input value when the exponent is 0, and may be 0 or 1,
* giving extra range. They may also be generated as outputs.
* (The m68k manual actually calls these values part of the
* normalized number range, not the denormalized number range.)
*
* By default you get the Intel behaviour where the Integer
* bit is ignored; if this is set then the Integer bit value
* is honoured, m68k-style.
*
* Either way, floatx80_invalid_encoding() will always accept
* pseudo-denormals.
*/
floatx80_pseudo_denormal_valid = 16,
} FloatX80Behaviour;
/*
* Floating Point Status. Individual architectures may maintain
* several versions of float_status for different functions. The
@ -331,6 +381,7 @@ typedef struct float_status {
uint16_t float_exception_flags;
FloatRoundMode float_rounding_mode;
FloatX80RoundPrec floatx80_rounding_precision;
FloatX80Behaviour floatx80_behaviour;
Float2NaNPropRule float_2nan_prop_rule;
Float3NaNPropRule float_3nan_prop_rule;
FloatInfZeroNaNRule float_infzeronan_rule;

View file

@ -960,7 +960,7 @@ float128 floatx80_to_float128(floatx80, float_status *status);
/*----------------------------------------------------------------------------
| The pattern for an extended double-precision inf.
*----------------------------------------------------------------------------*/
extern const floatx80 floatx80_infinity;
floatx80 floatx80_default_inf(bool zSign, float_status *status);
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision operations.
@ -995,14 +995,19 @@ static inline floatx80 floatx80_chs(floatx80 a)
return a;
}
static inline bool floatx80_is_infinity(floatx80 a)
static inline bool floatx80_is_infinity(floatx80 a, float_status *status)
{
#if defined(TARGET_M68K)
return (a.high & 0x7fff) == floatx80_infinity.high && !(a.low << 1);
#else
return (a.high & 0x7fff) == floatx80_infinity.high &&
a.low == floatx80_infinity.low;
#endif
/*
* It's target-specific whether the Integer bit is permitted
* to be 0 in a valid Infinity value. (x86 says no, m68k says yes).
*/
bool intbit = a.low >> 63;
if (!intbit &&
!(status->floatx80_behaviour & floatx80_pseudo_inf_valid)) {
return false;
}
return (a.high & 0x7fff) == 0x7fff && !(a.low << 1);
}
static inline bool floatx80_is_neg(floatx80 a)
@ -1068,41 +1073,45 @@ static inline bool floatx80_unordered_quiet(floatx80 a, floatx80 b,
/*----------------------------------------------------------------------------
| Return whether the given value is an invalid floatx80 encoding.
| Invalid floatx80 encodings arise when the integer bit is not set, but
| the exponent is not zero. The only times the integer bit is permitted to
| be zero is in subnormal numbers and the value zero.
| This includes what the Intel software developer's manual calls pseudo-NaNs,
| pseudo-infinities and un-normal numbers. It does not include
| pseudo-denormals, which must still be correctly handled as inputs even
| if they are never generated as outputs.
| Invalid floatx80 encodings may arise when the integer bit is not set
| correctly; this is target-specific. In Intel terminology the
| categories are:
| exp == 0, int = 0, mantissa == 0 : zeroes
| exp == 0, int = 0, mantissa != 0 : denormals
| exp == 0, int = 1 : pseudo-denormals
| 0 < exp < 0x7fff, int = 0 : unnormals
| 0 < exp < 0x7fff, int = 1 : normals
| exp == 0x7fff, int = 0, mantissa == 0 : pseudo-infinities
| exp == 0x7fff, int = 1, mantissa == 0 : infinities
| exp == 0x7fff, int = 0, mantissa != 0 : pseudo-NaNs
| exp == 0x7fff, int = 1, mantissa == 0 : NaNs
|
| The usual IEEE cases of zero, denormal, normal, inf and NaN are always valid.
| x87 permits as input also pseudo-denormals.
| m68k permits all those and also pseudo-infinities, pseudo-NaNs and unnormals.
|
| Since we don't have a target that handles floatx80 but prohibits
| pseudo-denormals in input, we don't currently have a floatx80_behaviour
| flag for that case, but instead always accept it. Conveniently this
| means that all cases with either exponent 0 or the integer bit set are
| valid for all targets.
*----------------------------------------------------------------------------*/
static inline bool floatx80_invalid_encoding(floatx80 a)
static inline bool floatx80_invalid_encoding(floatx80 a, float_status *s)
{
#if defined(TARGET_M68K)
/*-------------------------------------------------------------------------
| With m68k, the explicit integer bit can be zero in the case of:
| - zeros (exp == 0, mantissa == 0)
| - denormalized numbers (exp == 0, mantissa != 0)
| - unnormalized numbers (exp != 0, exp < 0x7FFF)
| - infinities (exp == 0x7FFF, mantissa == 0)
| - not-a-numbers (exp == 0x7FFF, mantissa != 0)
|
| For infinities and NaNs, the explicit integer bit can be either one or
| zero.
|
| The IEEE 754 standard does not define a zero integer bit. Such a number
| is an unnormalized number. Hardware does not directly support
| denormalized and unnormalized numbers, but implicitly supports them by
| trapping them as unimplemented data types, allowing efficient conversion
| in software.
|
| See "M68000 FAMILY PROGRAMMERS REFERENCE MANUAL",
| "1.6 FLOATING-POINT DATA TYPES"
*------------------------------------------------------------------------*/
return false;
#else
return (a.low & (1ULL << 63)) == 0 && (a.high & 0x7FFF) != 0;
#endif
if ((a.low >> 63) || (a.high & 0x7fff) == 0) {
/* Anything with the Integer bit set or the exponent 0 is valid */
return false;
}
if ((a.high & 0x7fff) == 0x7fff) {
if (a.low) {
return !(s->floatx80_behaviour & floatx80_pseudo_nan_valid);
} else {
return !(s->floatx80_behaviour & floatx80_pseudo_inf_valid);
}
} else {
return !(s->floatx80_behaviour & floatx80_unnormal_valid);
}
}
#define floatx80_zero make_floatx80(0x0000, 0x0000000000000000LL)

284
include/hw/arm/fsl-imx8mp.h Normal file
View file

@ -0,0 +1,284 @@
/*
* i.MX 8M Plus SoC Definitions
*
* Copyright (c) 2024, Bernhard Beschow <shentey@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef FSL_IMX8MP_H
#define FSL_IMX8MP_H
#include "cpu.h"
#include "hw/char/imx_serial.h"
#include "hw/gpio/imx_gpio.h"
#include "hw/i2c/imx_i2c.h"
#include "hw/intc/arm_gicv3_common.h"
#include "hw/misc/imx7_snvs.h"
#include "hw/misc/imx8mp_analog.h"
#include "hw/misc/imx8mp_ccm.h"
#include "hw/net/imx_fec.h"
#include "hw/or-irq.h"
#include "hw/pci-host/designware.h"
#include "hw/pci-host/fsl_imx8m_phy.h"
#include "hw/sd/sdhci.h"
#include "hw/ssi/imx_spi.h"
#include "hw/timer/imx_gpt.h"
#include "hw/usb/hcd-dwc3.h"
#include "hw/watchdog/wdt_imx2.h"
#include "qom/object.h"
#include "qemu/units.h"
#define TYPE_FSL_IMX8MP "fsl-imx8mp"
OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mpState, FSL_IMX8MP)
#define FSL_IMX8MP_RAM_START 0x40000000
#define FSL_IMX8MP_RAM_SIZE_MAX (8 * GiB)
enum FslImx8mpConfiguration {
FSL_IMX8MP_NUM_CPUS = 4,
FSL_IMX8MP_NUM_ECSPIS = 3,
FSL_IMX8MP_NUM_GPIOS = 5,
FSL_IMX8MP_NUM_GPTS = 6,
FSL_IMX8MP_NUM_I2CS = 6,
FSL_IMX8MP_NUM_IRQS = 160,
FSL_IMX8MP_NUM_UARTS = 4,
FSL_IMX8MP_NUM_USBS = 2,
FSL_IMX8MP_NUM_USDHCS = 3,
FSL_IMX8MP_NUM_WDTS = 3,
};
struct FslImx8mpState {
DeviceState parent_obj;
ARMCPU cpu[FSL_IMX8MP_NUM_CPUS];
GICv3State gic;
IMXGPTState gpt[FSL_IMX8MP_NUM_GPTS];
IMXGPIOState gpio[FSL_IMX8MP_NUM_GPIOS];
IMX8MPCCMState ccm;
IMX8MPAnalogState analog;
IMX7SNVSState snvs;
IMXSPIState spi[FSL_IMX8MP_NUM_ECSPIS];
IMXI2CState i2c[FSL_IMX8MP_NUM_I2CS];
IMXSerialState uart[FSL_IMX8MP_NUM_UARTS];
IMXFECState enet;
SDHCIState usdhc[FSL_IMX8MP_NUM_USDHCS];
IMX2WdtState wdt[FSL_IMX8MP_NUM_WDTS];
USBDWC3 usb[FSL_IMX8MP_NUM_USBS];
DesignwarePCIEHost pcie;
FslImx8mPciePhyState pcie_phy;
OrIRQState gpt5_gpt6_irq;
MemoryRegion ocram;
uint32_t phy_num;
bool phy_connected;
};
enum FslImx8mpMemoryRegions {
FSL_IMX8MP_A53_DAP,
FSL_IMX8MP_AIPS1_CONFIGURATION,
FSL_IMX8MP_AIPS2_CONFIGURATION,
FSL_IMX8MP_AIPS3_CONFIGURATION,
FSL_IMX8MP_AIPS4_CONFIGURATION,
FSL_IMX8MP_AIPS5_CONFIGURATION,
FSL_IMX8MP_ANA_OSC,
FSL_IMX8MP_ANA_PLL,
FSL_IMX8MP_ANA_TSENSOR,
FSL_IMX8MP_APBH_DMA,
FSL_IMX8MP_ASRC,
FSL_IMX8MP_AUDIO_BLK_CTRL,
FSL_IMX8MP_AUDIO_DSP,
FSL_IMX8MP_AUDIO_XCVR_RX,
FSL_IMX8MP_AUD_IRQ_STEER,
FSL_IMX8MP_BOOT_ROM,
FSL_IMX8MP_BOOT_ROM_PROTECTED,
FSL_IMX8MP_CAAM,
FSL_IMX8MP_CAAM_MEM,
FSL_IMX8MP_CCM,
FSL_IMX8MP_CSU,
FSL_IMX8MP_DDR_BLK_CTRL,
FSL_IMX8MP_DDR_CTL,
FSL_IMX8MP_DDR_PERF_MON,
FSL_IMX8MP_DDR_PHY,
FSL_IMX8MP_DDR_PHY_BROADCAST,
FSL_IMX8MP_ECSPI1,
FSL_IMX8MP_ECSPI2,
FSL_IMX8MP_ECSPI3,
FSL_IMX8MP_EDMA_CHANNELS,
FSL_IMX8MP_EDMA_MANAGEMENT_PAGE,
FSL_IMX8MP_ENET1,
FSL_IMX8MP_ENET2_TSN,
FSL_IMX8MP_FLEXCAN1,
FSL_IMX8MP_FLEXCAN2,
FSL_IMX8MP_GIC_DIST,
FSL_IMX8MP_GIC_REDIST,
FSL_IMX8MP_GPC,
FSL_IMX8MP_GPIO1,
FSL_IMX8MP_GPIO2,
FSL_IMX8MP_GPIO3,
FSL_IMX8MP_GPIO4,
FSL_IMX8MP_GPIO5,
FSL_IMX8MP_GPT1,
FSL_IMX8MP_GPT2,
FSL_IMX8MP_GPT3,
FSL_IMX8MP_GPT4,
FSL_IMX8MP_GPT5,
FSL_IMX8MP_GPT6,
FSL_IMX8MP_GPU2D,
FSL_IMX8MP_GPU3D,
FSL_IMX8MP_HDMI_TX,
FSL_IMX8MP_HDMI_TX_AUDLNK_MSTR,
FSL_IMX8MP_HSIO_BLK_CTL,
FSL_IMX8MP_I2C1,
FSL_IMX8MP_I2C2,
FSL_IMX8MP_I2C3,
FSL_IMX8MP_I2C4,
FSL_IMX8MP_I2C5,
FSL_IMX8MP_I2C6,
FSL_IMX8MP_INTERCONNECT,
FSL_IMX8MP_IOMUXC,
FSL_IMX8MP_IOMUXC_GPR,
FSL_IMX8MP_IPS_DEWARP,
FSL_IMX8MP_ISI,
FSL_IMX8MP_ISP1,
FSL_IMX8MP_ISP2,
FSL_IMX8MP_LCDIF1,
FSL_IMX8MP_LCDIF2,
FSL_IMX8MP_MEDIA_BLK_CTL,
FSL_IMX8MP_MIPI_CSI1,
FSL_IMX8MP_MIPI_CSI2,
FSL_IMX8MP_MIPI_DSI1,
FSL_IMX8MP_MU_1_A,
FSL_IMX8MP_MU_1_B,
FSL_IMX8MP_MU_2_A,
FSL_IMX8MP_MU_2_B,
FSL_IMX8MP_MU_3_A,
FSL_IMX8MP_MU_3_B,
FSL_IMX8MP_NPU,
FSL_IMX8MP_OCOTP_CTRL,
FSL_IMX8MP_OCRAM,
FSL_IMX8MP_OCRAM_S,
FSL_IMX8MP_PCIE1,
FSL_IMX8MP_PCIE1_MEM,
FSL_IMX8MP_PCIE_PHY1,
FSL_IMX8MP_PDM,
FSL_IMX8MP_PERFMON1,
FSL_IMX8MP_PERFMON2,
FSL_IMX8MP_PWM1,
FSL_IMX8MP_PWM2,
FSL_IMX8MP_PWM3,
FSL_IMX8MP_PWM4,
FSL_IMX8MP_QOSC,
FSL_IMX8MP_QSPI,
FSL_IMX8MP_QSPI1_RX_BUFFER,
FSL_IMX8MP_QSPI1_TX_BUFFER,
FSL_IMX8MP_QSPI_MEM,
FSL_IMX8MP_RAM,
FSL_IMX8MP_RDC,
FSL_IMX8MP_SAI1,
FSL_IMX8MP_SAI2,
FSL_IMX8MP_SAI3,
FSL_IMX8MP_SAI5,
FSL_IMX8MP_SAI6,
FSL_IMX8MP_SAI7,
FSL_IMX8MP_SDMA1,
FSL_IMX8MP_SDMA2,
FSL_IMX8MP_SDMA3,
FSL_IMX8MP_SEMAPHORE1,
FSL_IMX8MP_SEMAPHORE2,
FSL_IMX8MP_SEMAPHORE_HS,
FSL_IMX8MP_SNVS_HP,
FSL_IMX8MP_SPBA1,
FSL_IMX8MP_SPBA2,
FSL_IMX8MP_SRC,
FSL_IMX8MP_SYSCNT_CMP,
FSL_IMX8MP_SYSCNT_CTRL,
FSL_IMX8MP_SYSCNT_RD,
FSL_IMX8MP_TCM_DTCM,
FSL_IMX8MP_TCM_ITCM,
FSL_IMX8MP_TZASC,
FSL_IMX8MP_UART1,
FSL_IMX8MP_UART2,
FSL_IMX8MP_UART3,
FSL_IMX8MP_UART4,
FSL_IMX8MP_USB1,
FSL_IMX8MP_USB2,
FSL_IMX8MP_USB1_DEV,
FSL_IMX8MP_USB2_DEV,
FSL_IMX8MP_USB1_OTG,
FSL_IMX8MP_USB2_OTG,
FSL_IMX8MP_USB1_GLUE,
FSL_IMX8MP_USB2_GLUE,
FSL_IMX8MP_USDHC1,
FSL_IMX8MP_USDHC2,
FSL_IMX8MP_USDHC3,
FSL_IMX8MP_VPU,
FSL_IMX8MP_VPU_BLK_CTRL,
FSL_IMX8MP_VPU_G1_DECODER,
FSL_IMX8MP_VPU_G2_DECODER,
FSL_IMX8MP_VPU_VC8000E_ENCODER,
FSL_IMX8MP_WDOG1,
FSL_IMX8MP_WDOG2,
FSL_IMX8MP_WDOG3,
};
enum FslImx8mpIrqs {
FSL_IMX8MP_USDHC1_IRQ = 22,
FSL_IMX8MP_USDHC2_IRQ = 23,
FSL_IMX8MP_USDHC3_IRQ = 24,
FSL_IMX8MP_UART1_IRQ = 26,
FSL_IMX8MP_UART2_IRQ = 27,
FSL_IMX8MP_UART3_IRQ = 28,
FSL_IMX8MP_UART4_IRQ = 29,
FSL_IMX8MP_UART5_IRQ = 30,
FSL_IMX8MP_UART6_IRQ = 16,
FSL_IMX8MP_ECSPI1_IRQ = 31,
FSL_IMX8MP_ECSPI2_IRQ = 32,
FSL_IMX8MP_ECSPI3_IRQ = 33,
FSL_IMX8MP_ECSPI4_IRQ = 34,
FSL_IMX8MP_I2C1_IRQ = 35,
FSL_IMX8MP_I2C2_IRQ = 36,
FSL_IMX8MP_I2C3_IRQ = 37,
FSL_IMX8MP_I2C4_IRQ = 38,
FSL_IMX8MP_USB1_IRQ = 40,
FSL_IMX8MP_USB2_IRQ = 41,
FSL_IMX8MP_GPT1_IRQ = 55,
FSL_IMX8MP_GPT2_IRQ = 54,
FSL_IMX8MP_GPT3_IRQ = 53,
FSL_IMX8MP_GPT4_IRQ = 52,
FSL_IMX8MP_GPT5_GPT6_IRQ = 51,
FSL_IMX8MP_GPIO1_LOW_IRQ = 64,
FSL_IMX8MP_GPIO1_HIGH_IRQ = 65,
FSL_IMX8MP_GPIO2_LOW_IRQ = 66,
FSL_IMX8MP_GPIO2_HIGH_IRQ = 67,
FSL_IMX8MP_GPIO3_LOW_IRQ = 68,
FSL_IMX8MP_GPIO3_HIGH_IRQ = 69,
FSL_IMX8MP_GPIO4_LOW_IRQ = 70,
FSL_IMX8MP_GPIO4_HIGH_IRQ = 71,
FSL_IMX8MP_GPIO5_LOW_IRQ = 72,
FSL_IMX8MP_GPIO5_HIGH_IRQ = 73,
FSL_IMX8MP_I2C5_IRQ = 76,
FSL_IMX8MP_I2C6_IRQ = 77,
FSL_IMX8MP_WDOG1_IRQ = 78,
FSL_IMX8MP_WDOG2_IRQ = 79,
FSL_IMX8MP_WDOG3_IRQ = 10,
FSL_IMX8MP_ENET1_MAC_IRQ = 118,
FSL_IMX6_ENET1_MAC_1588_IRQ = 121,
FSL_IMX8MP_PCI_INTA_IRQ = 126,
FSL_IMX8MP_PCI_INTB_IRQ = 125,
FSL_IMX8MP_PCI_INTC_IRQ = 124,
FSL_IMX8MP_PCI_INTD_IRQ = 123,
FSL_IMX8MP_PCI_MSI_IRQ = 140,
};
#endif /* FSL_IMX8MP_H */

View file

@ -30,12 +30,27 @@ struct fit_loader_match {
struct fit_loader {
const struct fit_loader_match *matches;
hwaddr (*addr_to_phys)(void *opaque, uint64_t addr);
const void *(*fdt_filter)(void *opaque, const void *fdt,
const void *match_data, hwaddr *load_addr);
void *(*fdt_filter)(void *opaque, const void *fdt,
const void *match_data, hwaddr *load_addr);
const void *(*kernel_filter)(void *opaque, const void *kernel,
hwaddr *load_addr, hwaddr *entry_addr);
};
int load_fit(const struct fit_loader *ldr, const char *filename, void *opaque);
/**
* load_fit: load a FIT format image
* @ldr: structure defining board specific properties and hooks
* @filename: image to load
* @pfdt: pointer to update with address of FDT blob
* @opaque: opaque value passed back to the hook functions in @ldr
* Returns: 0 on success, or a negative errno on failure
*
* @pfdt is used to tell the caller about the FDT blob. On return, it
* has been set to point to the FDT blob, and it is now the caller's
* responsibility to free that memory with g_free(). Usually the caller
* will want to pass in &machine->fdt here, to record the FDT blob for
* the dumpdtb option and QMP/HMP commands.
*/
int load_fit(const struct fit_loader *ldr, const char *filename, void **pfdt,
void *opaque);
#endif /* HW_LOADER_FIT_H */

View file

@ -0,0 +1,81 @@
/*
* Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
*
* i.MX8MP ANALOG IP block emulation code
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef IMX8MP_ANALOG_H
#define IMX8MP_ANALOG_H
#include "qom/object.h"
#include "hw/sysbus.h"
enum IMX8MPAnalogRegisters {
ANALOG_AUDIO_PLL1_GEN_CTRL = 0x000 / 4,
ANALOG_AUDIO_PLL1_FDIV_CTL0 = 0x004 / 4,
ANALOG_AUDIO_PLL1_FDIV_CTL1 = 0x008 / 4,
ANALOG_AUDIO_PLL1_SSCG_CTRL = 0x00c / 4,
ANALOG_AUDIO_PLL1_MNIT_CTRL = 0x010 / 4,
ANALOG_AUDIO_PLL2_GEN_CTRL = 0x014 / 4,
ANALOG_AUDIO_PLL2_FDIV_CTL0 = 0x018 / 4,
ANALOG_AUDIO_PLL2_FDIV_CTL1 = 0x01c / 4,
ANALOG_AUDIO_PLL2_SSCG_CTRL = 0x020 / 4,
ANALOG_AUDIO_PLL2_MNIT_CTRL = 0x024 / 4,
ANALOG_VIDEO_PLL1_GEN_CTRL = 0x028 / 4,
ANALOG_VIDEO_PLL1_FDIV_CTL0 = 0x02c / 4,
ANALOG_VIDEO_PLL1_FDIV_CTL1 = 0x030 / 4,
ANALOG_VIDEO_PLL1_SSCG_CTRL = 0x034 / 4,
ANALOG_VIDEO_PLL1_MNIT_CTRL = 0x038 / 4,
ANALOG_DRAM_PLL_GEN_CTRL = 0x050 / 4,
ANALOG_DRAM_PLL_FDIV_CTL0 = 0x054 / 4,
ANALOG_DRAM_PLL_FDIV_CTL1 = 0x058 / 4,
ANALOG_DRAM_PLL_SSCG_CTRL = 0x05c / 4,
ANALOG_DRAM_PLL_MNIT_CTRL = 0x060 / 4,
ANALOG_GPU_PLL_GEN_CTRL = 0x064 / 4,
ANALOG_GPU_PLL_FDIV_CTL0 = 0x068 / 4,
ANALOG_GPU_PLL_LOCKD_CTRL = 0x06c / 4,
ANALOG_GPU_PLL_MNIT_CTRL = 0x070 / 4,
ANALOG_VPU_PLL_GEN_CTRL = 0x074 / 4,
ANALOG_VPU_PLL_FDIV_CTL0 = 0x078 / 4,
ANALOG_VPU_PLL_LOCKD_CTRL = 0x07c / 4,
ANALOG_VPU_PLL_MNIT_CTRL = 0x080 / 4,
ANALOG_ARM_PLL_GEN_CTRL = 0x084 / 4,
ANALOG_ARM_PLL_FDIV_CTL0 = 0x088 / 4,
ANALOG_ARM_PLL_LOCKD_CTRL = 0x08c / 4,
ANALOG_ARM_PLL_MNIT_CTRL = 0x090 / 4,
ANALOG_SYS_PLL1_GEN_CTRL = 0x094 / 4,
ANALOG_SYS_PLL1_FDIV_CTL0 = 0x098 / 4,
ANALOG_SYS_PLL1_LOCKD_CTRL = 0x09c / 4,
ANALOG_SYS_PLL1_MNIT_CTRL = 0x100 / 4,
ANALOG_SYS_PLL2_GEN_CTRL = 0x104 / 4,
ANALOG_SYS_PLL2_FDIV_CTL0 = 0x108 / 4,
ANALOG_SYS_PLL2_LOCKD_CTRL = 0x10c / 4,
ANALOG_SYS_PLL2_MNIT_CTRL = 0x110 / 4,
ANALOG_SYS_PLL3_GEN_CTRL = 0x114 / 4,
ANALOG_SYS_PLL3_FDIV_CTL0 = 0x118 / 4,
ANALOG_SYS_PLL3_LOCKD_CTRL = 0x11c / 4,
ANALOG_SYS_PLL3_MNIT_CTRL = 0x120 / 4,
ANALOG_OSC_MISC_CFG = 0x124 / 4,
ANALOG_ANAMIX_PLL_MNIT_CTL = 0x128 / 4,
ANALOG_DIGPROG = 0x800 / 4,
ANALOG_MAX,
};
#define TYPE_IMX8MP_ANALOG "imx8mp.analog"
OBJECT_DECLARE_SIMPLE_TYPE(IMX8MPAnalogState, IMX8MP_ANALOG)
struct IMX8MPAnalogState {
SysBusDevice parent_obj;
struct {
MemoryRegion container;
MemoryRegion analog;
} mmio;
uint32_t analog[ANALOG_MAX];
};
#endif /* IMX8MP_ANALOG_H */

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
*
* i.MX 8M Plus CCM IP block emulation code
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef IMX8MP_CCM_H
#define IMX8MP_CCM_H
#include "hw/misc/imx_ccm.h"
#include "qom/object.h"
enum IMX8MPCCMRegisters {
CCM_MAX = 0xc6fc / sizeof(uint32_t) + 1,
};
#define TYPE_IMX8MP_CCM "imx8mp.ccm"
OBJECT_DECLARE_SIMPLE_TYPE(IMX8MPCCMState, IMX8MP_CCM)
struct IMX8MPCCMState {
IMXCCMState parent_obj;
MemoryRegion iomem;
uint32_t ccm[CCM_MAX];
};
#endif /* IMX8MP_CCM_H */

View file

@ -20,6 +20,7 @@
#define OPENRISC_BOOT_H
#include "exec/cpu-defs.h"
#include "hw/boards.h"
hwaddr openrisc_load_kernel(ram_addr_t ram_size,
const char *kernel_filename,
@ -28,7 +29,7 @@ hwaddr openrisc_load_kernel(ram_addr_t ram_size,
hwaddr openrisc_load_initrd(void *fdt, const char *filename,
hwaddr load_start, uint64_t mem_size);
uint32_t openrisc_load_fdt(void *fdt, hwaddr load_start,
uint32_t openrisc_load_fdt(MachineState *ms, void *fdt, hwaddr load_start,
uint64_t mem_size);
#endif /* OPENRISC_BOOT_H */

View file

@ -25,12 +25,19 @@
#include "hw/pci/pci_bridge.h"
#include "qom/object.h"
#define TYPE_DESIGNWARE_PCIE_ROOT_BUS "designware-pcie-root-BUS"
OBJECT_DECLARE_SIMPLE_TYPE(DesignwarePCIERootBus, DESIGNWARE_PCIE_ROOT_BUS)
#define TYPE_DESIGNWARE_PCIE_HOST "designware-pcie-host"
OBJECT_DECLARE_SIMPLE_TYPE(DesignwarePCIEHost, DESIGNWARE_PCIE_HOST)
#define TYPE_DESIGNWARE_PCIE_ROOT "designware-pcie-root"
OBJECT_DECLARE_SIMPLE_TYPE(DesignwarePCIERoot, DESIGNWARE_PCIE_ROOT)
struct DesignwarePCIERootBus {
PCIBus parent;
};
typedef struct DesignwarePCIEViewport {
DesignwarePCIERoot *root;

View file

@ -0,0 +1,28 @@
/*
* i.MX8 PCIe PHY emulation
*
* Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef HW_PCIHOST_FSLIMX8MPCIEPHY_H
#define HW_PCIHOST_FSLIMX8MPCIEPHY_H
#include "hw/sysbus.h"
#include "qom/object.h"
#include "exec/memory.h"
#define TYPE_FSL_IMX8M_PCIE_PHY "fsl-imx8m-pcie-phy"
OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mPciePhyState, FSL_IMX8M_PCIE_PHY)
#define FSL_IMX8M_PCIE_PHY_DATA_SIZE 0x800
struct FslImx8mPciePhyState {
SysBusDevice parent_obj;
MemoryRegion iomem;
uint8_t data[FSL_IMX8M_PCIE_PHY_DATA_SIZE];
};
#endif

View file

@ -80,6 +80,7 @@
#define TYPE_IMX6_GPT "imx6.gpt"
#define TYPE_IMX6UL_GPT "imx6ul.gpt"
#define TYPE_IMX7_GPT "imx7.gpt"
#define TYPE_IMX8MP_GPT "imx8mp.gpt"
#define TYPE_IMX_GPT TYPE_IMX25_GPT

View file

@ -35,7 +35,7 @@
#define USB_DWC3(obj) \
OBJECT_CHECK(USBDWC3, (obj), TYPE_USB_DWC3)
#define USB_DWC3_R_MAX ((0x530 / 4) + 1)
#define USB_DWC3_R_MAX (0x600 / 4)
#define DWC3_SIZE 0x10000
typedef struct USBDWC3 {

View file

@ -133,8 +133,6 @@ int qemu_fdt_add_path(void *fdt, const char *path);
sizeof(qdt_tmp)); \
} while (0)
void qemu_fdt_dumpdtb(void *fdt, int size);
/**
* qemu_fdt_setprop_sized_cells_from_array:
* @fdt: device tree blob

View file

@ -431,6 +431,6 @@ void hmp_dumpdtb(Monitor *mon, const QDict *qdict)
return;
}
monitor_printf(mon, "dtb dumped to %s", filename);
monitor_printf(mon, "DTB dumped to '%s'\n", filename);
}
#endif

View file

@ -5,6 +5,9 @@
#ifdef CONFIG_FDT
void qmp_dumpdtb(const char *filename, Error **errp)
{
error_setg(errp, "This machine doesn't have a FDT");
ERRP_GUARD();
error_setg(errp, "This machine doesn't have an FDT");
error_append_hint(errp, "(this machine type definitely doesn't use FDT)\n");
}
#endif

View file

@ -594,21 +594,6 @@ int qemu_fdt_add_path(void *fdt, const char *path)
return retval;
}
void qemu_fdt_dumpdtb(void *fdt, int size)
{
const char *dumpdtb = current_machine->dumpdtb;
if (dumpdtb) {
/* Dump the dtb to a file and quit */
if (g_file_set_contents(dumpdtb, fdt, size, NULL)) {
info_report("dtb dumped to %s. Exiting.", dumpdtb);
exit(0);
}
error_report("%s: Failed dumping dtb to %s", __func__, dumpdtb);
exit(1);
}
}
int qemu_fdt_setprop_sized_cells_from_array(void *fdt,
const char *node_path,
const char *property,
@ -650,11 +635,16 @@ out:
void qmp_dumpdtb(const char *filename, Error **errp)
{
ERRP_GUARD();
g_autoptr(GError) err = NULL;
uint32_t size;
if (!current_machine->fdt) {
error_setg(errp, "This machine doesn't have a FDT");
error_setg(errp, "This machine doesn't have an FDT");
error_append_hint(errp,
"(Perhaps it doesn't support FDT at all, or perhaps "
"you need to provide an FDT with the -fdt option?)\n");
return;
}

View file

@ -899,6 +899,18 @@ static bool hvf_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
clamp_id_aa64mmfr0_parange_to_ipa_size(&host_isar.id_aa64mmfr0);
/*
* Disable SME, which is not properly handled by QEMU hvf yet.
* To allow this through we would need to:
* - make sure that the SME state is correctly handled in the
* get_registers/put_registers functions
* - get the SME-specific CPU properties to work with accelerators
* other than TCG
* - fix any assumptions we made that SME implies SVE (since
* on the M4 there is SME but not SVE)
*/
host_isar.id_aa64pfr1 &= ~R_ID_AA64PFR1_SME_MASK;
ahcf->isar = host_isar;
/*
@ -1971,6 +1983,7 @@ int hvf_vcpu_exec(CPUState *cpu)
bool isv = syndrome & ARM_EL_ISV;
bool iswrite = (syndrome >> 6) & 1;
bool s1ptw = (syndrome >> 7) & 1;
bool sse = (syndrome >> 21) & 1;
uint32_t sas = (syndrome >> 22) & 3;
uint32_t len = 1 << sas;
uint32_t srt = (syndrome >> 16) & 0x1f;
@ -1998,6 +2011,9 @@ int hvf_vcpu_exec(CPUState *cpu)
address_space_read(&address_space_memory,
hvf_exit->exception.physical_address,
MEMTXATTRS_UNSPECIFIED, &val, len);
if (sse) {
val = sextract64(val, 0, len * 8);
}
hvf_set_reg(cpu, srt, val);
}

View file

@ -1833,5 +1833,14 @@ int alle1_tlbmask(CPUARMState *env);
void arm_set_default_fp_behaviours(float_status *s);
/* Set the float_status behaviour to match Arm FPCR.AH=1 behaviour */
void arm_set_ah_fp_behaviours(float_status *s);
/* Read the float_status info and return the appropriate FPSR value */
uint32_t vfp_get_fpsr_from_host(CPUARMState *env);
/* Clear the exception status flags from all float_status fields */
void vfp_clear_float_status_exc_flags(CPUARMState *env);
/*
* Update float_status fields to handle the bits of the FPCR
* specified by mask changing to the values in val.
*/
void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask);
#endif

View file

@ -4,7 +4,7 @@ arm_ss.add(files(
'debug_helper.c',
'gdbstub.c',
'helper.c',
'vfp_helper.c',
'vfp_fpscr.c',
))
arm_ss.add(zlib)

View file

@ -30,3 +30,25 @@ void assert_hflags_rebuild_correctly(CPUARMState *env)
void define_tlb_insn_regs(ARMCPU *cpu)
{
}
/* With KVM, we never use float_status, so these can be no-ops */
void arm_set_default_fp_behaviours(float_status *s)
{
}
void arm_set_ah_fp_behaviours(float_status *s)
{
}
uint32_t vfp_get_fpsr_from_host(CPUARMState *env)
{
return 0;
}
void vfp_clear_float_status_exc_flags(CPUARMState *env)
{
}
void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask)
{
}

View file

@ -41,6 +41,7 @@ arm_ss.add(files(
'vec_helper.c',
'tlb-insns.c',
'arith_helper.c',
'vfp_helper.c',
))
arm_ss.add(when: 'TARGET_AARCH64', if_true: files(

View file

@ -23,13 +23,7 @@
#include "internals.h"
#include "cpu-features.h"
#include "fpu/softfloat.h"
#ifdef CONFIG_TCG
#include "qemu/log.h"
#endif
/* VFP support. We follow the convention used for VFP instructions:
Single precision routines have a "s" suffix, double precision a
"d" suffix. */
/*
* Set the float_status behaviour to match the Arm defaults:
@ -75,8 +69,6 @@ void arm_set_ah_fp_behaviours(float_status *s)
set_float_default_nan_pattern(0b11000000, s);
}
#ifdef CONFIG_TCG
/* Convert host exception flags to vfp form. */
static inline uint32_t vfp_exceptbits_from_host(int host_bits, bool ah)
{
@ -113,7 +105,7 @@ static inline uint32_t vfp_exceptbits_from_host(int host_bits, bool ah)
return target_bits;
}
static uint32_t vfp_get_fpsr_from_host(CPUARMState *env)
uint32_t vfp_get_fpsr_from_host(CPUARMState *env)
{
uint32_t a32_flags = 0, a64_flags = 0;
@ -148,7 +140,7 @@ static uint32_t vfp_get_fpsr_from_host(CPUARMState *env)
vfp_exceptbits_from_host(a32_flags, false);
}
static void vfp_clear_float_status_exc_flags(CPUARMState *env)
void vfp_clear_float_status_exc_flags(CPUARMState *env)
{
/*
* Clear out all the exception-flag information in the float_status
@ -176,7 +168,7 @@ static void vfp_sync_and_clear_float_status_exc_flags(CPUARMState *env)
vfp_clear_float_status_exc_flags(env);
}
static void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask)
void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask)
{
uint64_t changed = env->vfp.fpcr;
@ -261,166 +253,11 @@ static void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask)
}
}
#else
static uint32_t vfp_get_fpsr_from_host(CPUARMState *env)
{
return 0;
}
static void vfp_clear_float_status_exc_flags(CPUARMState *env)
{
}
static void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask)
{
}
#endif
uint32_t vfp_get_fpcr(CPUARMState *env)
{
uint32_t fpcr = env->vfp.fpcr
| (env->vfp.vec_len << 16)
| (env->vfp.vec_stride << 20);
/*
* M-profile LTPSIZE is the same bits [18:16] as A-profile Len; whichever
* of the two is not applicable to this CPU will always be zero.
*/
fpcr |= env->v7m.ltpsize << 16;
return fpcr;
}
uint32_t vfp_get_fpsr(CPUARMState *env)
{
uint32_t fpsr = env->vfp.fpsr;
uint32_t i;
fpsr |= vfp_get_fpsr_from_host(env);
i = env->vfp.qc[0] | env->vfp.qc[1] | env->vfp.qc[2] | env->vfp.qc[3];
fpsr |= i ? FPSR_QC : 0;
return fpsr;
}
uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env)
{
return (vfp_get_fpcr(env) & FPSCR_FPCR_MASK) |
(vfp_get_fpsr(env) & FPSCR_FPSR_MASK);
}
uint32_t vfp_get_fpscr(CPUARMState *env)
{
return HELPER(vfp_get_fpscr)(env);
}
void vfp_set_fpsr(CPUARMState *env, uint32_t val)
{
ARMCPU *cpu = env_archcpu(env);
if (arm_feature(env, ARM_FEATURE_NEON) ||
cpu_isar_feature(aa32_mve, cpu)) {
/*
* The bit we set within vfp.qc[] is arbitrary; the array as a
* whole being zero/non-zero is what counts.
*/
env->vfp.qc[0] = val & FPSR_QC;
env->vfp.qc[1] = 0;
env->vfp.qc[2] = 0;
env->vfp.qc[3] = 0;
}
/*
* NZCV lives only in env->vfp.fpsr. The cumulative exception flags
* IOC|DZC|OFC|UFC|IXC|IDC also live in env->vfp.fpsr, with possible
* extra pending exception information that hasn't yet been folded in
* living in the float_status values (for TCG).
* Since this FPSR write gives us the up to date values of the exception
* flags, we want to store into vfp.fpsr the NZCV and CEXC bits, zeroing
* anything else. We also need to clear out the float_status exception
* information so that the next vfp_get_fpsr does not fold in stale data.
*/
val &= FPSR_NZCV_MASK | FPSR_CEXC_MASK;
env->vfp.fpsr = val;
vfp_clear_float_status_exc_flags(env);
}
static void vfp_set_fpcr_masked(CPUARMState *env, uint32_t val, uint32_t mask)
{
/*
* We only set FPCR bits defined by mask, and leave the others alone.
* We assume the mask is sensible (e.g. doesn't try to set only
* part of a field)
*/
ARMCPU *cpu = env_archcpu(env);
/* When ARMv8.2-FP16 is not supported, FZ16 is RES0. */
if (!cpu_isar_feature(any_fp16, cpu)) {
val &= ~FPCR_FZ16;
}
if (!cpu_isar_feature(aa64_afp, cpu)) {
val &= ~(FPCR_FIZ | FPCR_AH | FPCR_NEP);
}
if (!cpu_isar_feature(aa64_ebf16, cpu)) {
val &= ~FPCR_EBF;
}
vfp_set_fpcr_to_host(env, val, mask);
if (mask & (FPCR_LEN_MASK | FPCR_STRIDE_MASK)) {
if (!arm_feature(env, ARM_FEATURE_M)) {
/*
* Short-vector length and stride; on M-profile these bits
* are used for different purposes.
* We can't make this conditional be "if MVFR0.FPShVec != 0",
* because in v7A no-short-vector-support cores still had to
* allow Stride/Len to be written with the only effect that
* some insns are required to UNDEF if the guest sets them.
*/
env->vfp.vec_len = extract32(val, 16, 3);
env->vfp.vec_stride = extract32(val, 20, 2);
} else if (cpu_isar_feature(aa32_mve, cpu)) {
env->v7m.ltpsize = extract32(val, FPCR_LTPSIZE_SHIFT,
FPCR_LTPSIZE_LENGTH);
}
}
/*
* We don't implement trapped exception handling, so the
* trap enable bits, IDE|IXE|UFE|OFE|DZE|IOE are all RAZ/WI (not RES0!)
*
* The FPCR bits we keep in vfp.fpcr are AHP, DN, FZ, RMode, EBF, FZ16,
* FIZ, AH, and NEP.
* Len, Stride and LTPSIZE we just handled. Store those bits
* there, and zero any of the other FPCR bits and the RES0 and RAZ/WI
* bits.
*/
val &= FPCR_AHP | FPCR_DN | FPCR_FZ | FPCR_RMODE_MASK | FPCR_FZ16 |
FPCR_EBF | FPCR_FIZ | FPCR_AH | FPCR_NEP;
env->vfp.fpcr &= ~mask;
env->vfp.fpcr |= val;
}
void vfp_set_fpcr(CPUARMState *env, uint32_t val)
{
vfp_set_fpcr_masked(env, val, MAKE_64BIT_MASK(0, 32));
}
void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val)
{
vfp_set_fpcr_masked(env, val, FPSCR_FPCR_MASK);
vfp_set_fpsr(env, val & FPSCR_FPSR_MASK);
}
void vfp_set_fpscr(CPUARMState *env, uint32_t val)
{
HELPER(vfp_set_fpscr)(env, val);
}
#ifdef CONFIG_TCG
/*
* VFP support. We follow the convention used for VFP instructions:
* Single precision routines have a "s" suffix, double precision a
* "d" suffix.
*/
#define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p))
@ -1520,4 +1357,12 @@ void HELPER(check_hcr_el2_trap)(CPUARMState *env, uint32_t rt, uint32_t reg)
raise_exception(env, EXCP_HYP_TRAP, syndrome, 2);
}
#endif
uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env)
{
return vfp_get_fpscr(env);
}
void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val)
{
vfp_set_fpscr(env, val);
}

155
target/arm/vfp_fpscr.c Normal file
View file

@ -0,0 +1,155 @@
/*
* ARM VFP floating-point: handling of FPSCR/FPCR/FPSR
*
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "internals.h"
#include "cpu-features.h"
uint32_t vfp_get_fpcr(CPUARMState *env)
{
uint32_t fpcr = env->vfp.fpcr
| (env->vfp.vec_len << 16)
| (env->vfp.vec_stride << 20);
/*
* M-profile LTPSIZE is the same bits [18:16] as A-profile Len; whichever
* of the two is not applicable to this CPU will always be zero.
*/
fpcr |= env->v7m.ltpsize << 16;
return fpcr;
}
uint32_t vfp_get_fpsr(CPUARMState *env)
{
uint32_t fpsr = env->vfp.fpsr;
uint32_t i;
fpsr |= vfp_get_fpsr_from_host(env);
i = env->vfp.qc[0] | env->vfp.qc[1] | env->vfp.qc[2] | env->vfp.qc[3];
fpsr |= i ? FPSR_QC : 0;
return fpsr;
}
uint32_t vfp_get_fpscr(CPUARMState *env)
{
return (vfp_get_fpcr(env) & FPSCR_FPCR_MASK) |
(vfp_get_fpsr(env) & FPSCR_FPSR_MASK);
}
void vfp_set_fpsr(CPUARMState *env, uint32_t val)
{
ARMCPU *cpu = env_archcpu(env);
if (arm_feature(env, ARM_FEATURE_NEON) ||
cpu_isar_feature(aa32_mve, cpu)) {
/*
* The bit we set within vfp.qc[] is arbitrary; the array as a
* whole being zero/non-zero is what counts.
*/
env->vfp.qc[0] = val & FPSR_QC;
env->vfp.qc[1] = 0;
env->vfp.qc[2] = 0;
env->vfp.qc[3] = 0;
}
/*
* NZCV lives only in env->vfp.fpsr. The cumulative exception flags
* IOC|DZC|OFC|UFC|IXC|IDC also live in env->vfp.fpsr, with possible
* extra pending exception information that hasn't yet been folded in
* living in the float_status values (for TCG).
* Since this FPSR write gives us the up to date values of the exception
* flags, we want to store into vfp.fpsr the NZCV and CEXC bits, zeroing
* anything else. We also need to clear out the float_status exception
* information so that the next vfp_get_fpsr does not fold in stale data.
*/
val &= FPSR_NZCV_MASK | FPSR_CEXC_MASK;
env->vfp.fpsr = val;
vfp_clear_float_status_exc_flags(env);
}
static void vfp_set_fpcr_masked(CPUARMState *env, uint32_t val, uint32_t mask)
{
/*
* We only set FPCR bits defined by mask, and leave the others alone.
* We assume the mask is sensible (e.g. doesn't try to set only
* part of a field)
*/
ARMCPU *cpu = env_archcpu(env);
/* When ARMv8.2-FP16 is not supported, FZ16 is RES0. */
if (!cpu_isar_feature(any_fp16, cpu)) {
val &= ~FPCR_FZ16;
}
if (!cpu_isar_feature(aa64_afp, cpu)) {
val &= ~(FPCR_FIZ | FPCR_AH | FPCR_NEP);
}
if (!cpu_isar_feature(aa64_ebf16, cpu)) {
val &= ~FPCR_EBF;
}
vfp_set_fpcr_to_host(env, val, mask);
if (mask & (FPCR_LEN_MASK | FPCR_STRIDE_MASK)) {
if (!arm_feature(env, ARM_FEATURE_M)) {
/*
* Short-vector length and stride; on M-profile these bits
* are used for different purposes.
* We can't make this conditional be "if MVFR0.FPShVec != 0",
* because in v7A no-short-vector-support cores still had to
* allow Stride/Len to be written with the only effect that
* some insns are required to UNDEF if the guest sets them.
*/
env->vfp.vec_len = extract32(val, 16, 3);
env->vfp.vec_stride = extract32(val, 20, 2);
} else if (cpu_isar_feature(aa32_mve, cpu)) {
env->v7m.ltpsize = extract32(val, FPCR_LTPSIZE_SHIFT,
FPCR_LTPSIZE_LENGTH);
}
}
/*
* We don't implement trapped exception handling, so the
* trap enable bits, IDE|IXE|UFE|OFE|DZE|IOE are all RAZ/WI (not RES0!)
*
* The FPCR bits we keep in vfp.fpcr are AHP, DN, FZ, RMode, EBF, FZ16,
* FIZ, AH, and NEP.
* Len, Stride and LTPSIZE we just handled. Store those bits
* there, and zero any of the other FPCR bits and the RES0 and RAZ/WI
* bits.
*/
val &= FPCR_AHP | FPCR_DN | FPCR_FZ | FPCR_RMODE_MASK | FPCR_FZ16 |
FPCR_EBF | FPCR_FIZ | FPCR_AH | FPCR_NEP;
env->vfp.fpcr &= ~mask;
env->vfp.fpcr |= val;
}
void vfp_set_fpcr(CPUARMState *env, uint32_t val)
{
vfp_set_fpcr_masked(env, val, MAKE_64BIT_MASK(0, 32));
}
void vfp_set_fpscr(CPUARMState *env, uint32_t val)
{
vfp_set_fpcr_masked(env, val, FPSCR_FPCR_MASK);
vfp_set_fpsr(env, val & FPSCR_FPSR_MASK);
}

View file

@ -67,6 +67,7 @@ void HELPER(loaded_fr0)(CPUHPPAState *env)
set_float_infzeronan_rule(float_infzeronan_dnan_never, &env->fp_status);
/* Default NaN: sign bit clear, msb-1 frac bit set */
set_float_default_nan_pattern(0b00100000, &env->fp_status);
set_snan_bit_is_one(true, &env->fp_status);
/*
* "PA-RISC 2.0 Architecture" says it is IMPDEF whether the flushing
* enabled by FPSR.D happens before or after rounding. We pick "before"

View file

@ -1141,7 +1141,7 @@ void helper_f2xm1(CPUX86State *env)
int32_t exp = extractFloatx80Exp(ST0);
bool sign = extractFloatx80Sign(ST0);
if (floatx80_invalid_encoding(ST0)) {
if (floatx80_invalid_encoding(ST0, &env->fp_status)) {
float_raise(float_flag_invalid, &env->fp_status);
ST0 = floatx80_default_nan(&env->fp_status);
} else if (floatx80_is_any_nan(ST0)) {
@ -1383,8 +1383,8 @@ void helper_fpatan(CPUX86State *env)
} else if (floatx80_is_signaling_nan(ST1, &env->fp_status)) {
float_raise(float_flag_invalid, &env->fp_status);
ST1 = floatx80_silence_nan(ST1, &env->fp_status);
} else if (floatx80_invalid_encoding(ST0) ||
floatx80_invalid_encoding(ST1)) {
} else if (floatx80_invalid_encoding(ST0, &env->fp_status) ||
floatx80_invalid_encoding(ST1, &env->fp_status)) {
float_raise(float_flag_invalid, &env->fp_status);
ST1 = floatx80_default_nan(&env->fp_status);
} else if (floatx80_is_any_nan(ST0)) {
@ -1393,7 +1393,8 @@ void helper_fpatan(CPUX86State *env)
/* Pass this NaN through. */
} else if (floatx80_is_zero(ST1) && !arg0_sign) {
/* Pass this zero through. */
} else if (((floatx80_is_infinity(ST0) && !floatx80_is_infinity(ST1)) ||
} else if (((floatx80_is_infinity(ST0, &env->fp_status) &&
!floatx80_is_infinity(ST1, &env->fp_status)) ||
arg0_exp - arg1_exp >= 80) &&
!arg0_sign) {
/*
@ -1442,8 +1443,8 @@ void helper_fpatan(CPUX86State *env)
rexp = pi_exp;
rsig0 = pi_sig_high;
rsig1 = pi_sig_low;
} else if (floatx80_is_infinity(ST1)) {
if (floatx80_is_infinity(ST0)) {
} else if (floatx80_is_infinity(ST1, &env->fp_status)) {
if (floatx80_is_infinity(ST0, &env->fp_status)) {
if (arg0_sign) {
rexp = pi_34_exp;
rsig0 = pi_34_sig_high;
@ -1462,7 +1463,8 @@ void helper_fpatan(CPUX86State *env)
rexp = pi_2_exp;
rsig0 = pi_2_sig_high;
rsig1 = pi_2_sig_low;
} else if (floatx80_is_infinity(ST0) || arg0_exp - arg1_exp >= 80) {
} else if (floatx80_is_infinity(ST0, &env->fp_status) ||
arg0_exp - arg1_exp >= 80) {
/* ST0 is negative. */
rexp = pi_exp;
rsig0 = pi_sig_high;
@ -1817,7 +1819,7 @@ void helper_fxtract(CPUX86State *env)
&env->fp_status);
fpush(env);
ST0 = temp.d;
} else if (floatx80_invalid_encoding(ST0)) {
} else if (floatx80_invalid_encoding(ST0, &env->fp_status)) {
float_raise(float_flag_invalid, &env->fp_status);
ST0 = floatx80_default_nan(&env->fp_status);
fpush(env);
@ -1829,10 +1831,10 @@ void helper_fxtract(CPUX86State *env)
}
fpush(env);
ST0 = ST1;
} else if (floatx80_is_infinity(ST0)) {
} else if (floatx80_is_infinity(ST0, &env->fp_status)) {
fpush(env);
ST0 = ST1;
ST1 = floatx80_infinity;
ST1 = floatx80_default_inf(0, &env->fp_status);
} else {
int expdif;
@ -1868,7 +1870,8 @@ static void helper_fprem_common(CPUX86State *env, bool mod)
env->fpus &= ~0x4700; /* (C3,C2,C1,C0) <-- 0000 */
if (floatx80_is_zero(ST0) || floatx80_is_zero(ST1) ||
exp0 == 0x7fff || exp1 == 0x7fff ||
floatx80_invalid_encoding(ST0) || floatx80_invalid_encoding(ST1)) {
floatx80_invalid_encoding(ST0, &env->fp_status) ||
floatx80_invalid_encoding(ST1, &env->fp_status)) {
ST0 = floatx80_modrem(ST0, ST1, mod, &quotient, &env->fp_status);
} else {
if (exp0 == 0) {
@ -2064,8 +2067,8 @@ void helper_fyl2xp1(CPUX86State *env)
} else if (floatx80_is_signaling_nan(ST1, &env->fp_status)) {
float_raise(float_flag_invalid, &env->fp_status);
ST1 = floatx80_silence_nan(ST1, &env->fp_status);
} else if (floatx80_invalid_encoding(ST0) ||
floatx80_invalid_encoding(ST1)) {
} else if (floatx80_invalid_encoding(ST0, &env->fp_status) ||
floatx80_invalid_encoding(ST1, &env->fp_status)) {
float_raise(float_flag_invalid, &env->fp_status);
ST1 = floatx80_default_nan(&env->fp_status);
} else if (floatx80_is_any_nan(ST0)) {
@ -2162,8 +2165,8 @@ void helper_fyl2x(CPUX86State *env)
} else if (floatx80_is_signaling_nan(ST1, &env->fp_status)) {
float_raise(float_flag_invalid, &env->fp_status);
ST1 = floatx80_silence_nan(ST1, &env->fp_status);
} else if (floatx80_invalid_encoding(ST0) ||
floatx80_invalid_encoding(ST1)) {
} else if (floatx80_invalid_encoding(ST0, &env->fp_status) ||
floatx80_invalid_encoding(ST1, &env->fp_status)) {
float_raise(float_flag_invalid, &env->fp_status);
ST1 = floatx80_default_nan(&env->fp_status);
} else if (floatx80_is_any_nan(ST0)) {
@ -2173,7 +2176,7 @@ void helper_fyl2x(CPUX86State *env)
} else if (arg0_sign && !floatx80_is_zero(ST0)) {
float_raise(float_flag_invalid, &env->fp_status);
ST1 = floatx80_default_nan(&env->fp_status);
} else if (floatx80_is_infinity(ST1)) {
} else if (floatx80_is_infinity(ST1, &env->fp_status)) {
FloatRelation cmp = floatx80_compare(ST0, floatx80_one,
&env->fp_status);
switch (cmp) {
@ -2188,7 +2191,7 @@ void helper_fyl2x(CPUX86State *env)
ST1 = floatx80_default_nan(&env->fp_status);
break;
}
} else if (floatx80_is_infinity(ST0)) {
} else if (floatx80_is_infinity(ST0, &env->fp_status)) {
if (floatx80_is_zero(ST1)) {
float_raise(float_flag_invalid, &env->fp_status);
ST1 = floatx80_default_nan(&env->fp_status);
@ -2329,7 +2332,8 @@ void helper_frndint(CPUX86State *env)
void helper_fscale(CPUX86State *env)
{
uint8_t old_flags = save_exception_flags(env);
if (floatx80_invalid_encoding(ST1) || floatx80_invalid_encoding(ST0)) {
if (floatx80_invalid_encoding(ST1, &env->fp_status) ||
floatx80_invalid_encoding(ST0, &env->fp_status)) {
float_raise(float_flag_invalid, &env->fp_status);
ST0 = floatx80_default_nan(&env->fp_status);
} else if (floatx80_is_any_nan(ST1)) {
@ -2341,11 +2345,11 @@ void helper_fscale(CPUX86State *env)
float_raise(float_flag_invalid, &env->fp_status);
ST0 = floatx80_silence_nan(ST0, &env->fp_status);
}
} else if (floatx80_is_infinity(ST1) &&
!floatx80_invalid_encoding(ST0) &&
} else if (floatx80_is_infinity(ST1, &env->fp_status) &&
!floatx80_invalid_encoding(ST0, &env->fp_status) &&
!floatx80_is_any_nan(ST0)) {
if (floatx80_is_neg(ST1)) {
if (floatx80_is_infinity(ST0)) {
if (floatx80_is_infinity(ST0, &env->fp_status)) {
float_raise(float_flag_invalid, &env->fp_status);
ST0 = floatx80_default_nan(&env->fp_status);
} else {
@ -2358,9 +2362,8 @@ void helper_fscale(CPUX86State *env)
float_raise(float_flag_invalid, &env->fp_status);
ST0 = floatx80_default_nan(&env->fp_status);
} else {
ST0 = (floatx80_is_neg(ST0) ?
floatx80_chs(floatx80_infinity) :
floatx80_infinity);
ST0 = floatx80_default_inf(floatx80_is_neg(ST0),
&env->fp_status);
}
}
} else {

View file

@ -107,6 +107,41 @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type)
set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status);
/* Default NaN: sign bit clear, all frac bits set */
set_float_default_nan_pattern(0b01111111, &env->fp_status);
/*
* m68k-specific floatx80 behaviour:
* * default Infinity values have a zero Integer bit
* * input Infinities may have the Integer bit either 0 or 1
* * pseudo-denormals supported for input and output
* * don't raise Invalid for pseudo-NaN/pseudo-Inf/Unnormal
*
* With m68k, the explicit integer bit can be zero in the case of:
* - zeros (exp == 0, mantissa == 0)
* - denormalized numbers (exp == 0, mantissa != 0)
* - unnormalized numbers (exp != 0, exp < 0x7FFF)
* - infinities (exp == 0x7FFF, mantissa == 0)
* - not-a-numbers (exp == 0x7FFF, mantissa != 0)
*
* For infinities and NaNs, the explicit integer bit can be either one or
* zero.
*
* The IEEE 754 standard does not define a zero integer bit. Such a number
* is an unnormalized number. Hardware does not directly support
* denormalized and unnormalized numbers, but implicitly supports them by
* trapping them as unimplemented data types, allowing efficient conversion
* in software.
*
* See "M68000 FAMILY PROGRAMMERS REFERENCE MANUAL",
* "1.6 FLOATING-POINT DATA TYPES"
*
* Note though that QEMU's fp emulation does directly handle both
* denormal and unnormal values, and does not trap to guest software.
*/
set_floatx80_behaviour(floatx80_default_inf_int_bit_is_zero |
floatx80_pseudo_inf_valid |
floatx80_pseudo_nan_valid |
floatx80_unnormal_valid |
floatx80_pseudo_denormal_valid,
&env->fp_status);
nan = floatx80_default_nan(&env->fp_status);
for (i = 0; i < 8; i++) {

View file

@ -455,7 +455,7 @@ void HELPER(ftst)(CPUM68KState *env, FPReg *val)
if (floatx80_is_any_nan(val->d)) {
cc |= FPSR_CC_A;
} else if (floatx80_is_infinity(val->d)) {
} else if (floatx80_is_infinity(val->d, &env->fp_status)) {
cc |= FPSR_CC_I;
} else if (floatx80_is_zero(val->d)) {
cc |= FPSR_CC_Z;

View file

@ -142,8 +142,7 @@ floatx80 floatx80_scale(floatx80 a, floatx80 b, float_status *status)
if ((uint64_t) (aSig << 1)) {
return propagateFloatx80NaN(a, b, status);
}
return packFloatx80(aSign, floatx80_infinity.high,
floatx80_infinity.low);
return floatx80_default_inf(aSign, status);
}
if (aExp == 0) {
if (aSig == 0) {
@ -245,7 +244,7 @@ floatx80 floatx80_lognp1(floatx80 a, float_status *status)
float_raise(float_flag_invalid, status);
return floatx80_default_nan(status);
}
return packFloatx80(0, floatx80_infinity.high, floatx80_infinity.low);
return floatx80_default_inf(0, status);
}
if (aExp == 0 && aSig == 0) {
@ -255,8 +254,7 @@ floatx80 floatx80_lognp1(floatx80 a, float_status *status)
if (aSign && aExp >= one_exp) {
if (aExp == one_exp && aSig == one_sig) {
float_raise(float_flag_divbyzero, status);
return packFloatx80(aSign, floatx80_infinity.high,
floatx80_infinity.low);
return floatx80_default_inf(aSign, status);
}
float_raise(float_flag_invalid, status);
return floatx80_default_nan(status);
@ -442,8 +440,7 @@ floatx80 floatx80_logn(floatx80 a, float_status *status)
propagateFloatx80NaNOneArg(a, status);
}
if (aSign == 0) {
return packFloatx80(0, floatx80_infinity.high,
floatx80_infinity.low);
return floatx80_default_inf(0, status);
}
}
@ -452,8 +449,7 @@ floatx80 floatx80_logn(floatx80 a, float_status *status)
if (aExp == 0) {
if (aSig == 0) { /* zero */
float_raise(float_flag_divbyzero, status);
return packFloatx80(1, floatx80_infinity.high,
floatx80_infinity.low);
return floatx80_default_inf(1, status);
}
if ((aSig & one_sig) == 0) { /* denormal */
normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
@ -610,15 +606,13 @@ floatx80 floatx80_log10(floatx80 a, float_status *status)
propagateFloatx80NaNOneArg(a, status);
}
if (aSign == 0) {
return packFloatx80(0, floatx80_infinity.high,
floatx80_infinity.low);
return floatx80_default_inf(0, status);
}
}
if (aExp == 0 && aSig == 0) {
float_raise(float_flag_divbyzero, status);
return packFloatx80(1, floatx80_infinity.high,
floatx80_infinity.low);
return floatx80_default_inf(1, status);
}
if (aSign) {
@ -668,16 +662,14 @@ floatx80 floatx80_log2(floatx80 a, float_status *status)
propagateFloatx80NaNOneArg(a, status);
}
if (aSign == 0) {
return packFloatx80(0, floatx80_infinity.high,
floatx80_infinity.low);
return floatx80_default_inf(0, status);
}
}
if (aExp == 0) {
if (aSig == 0) {
float_raise(float_flag_divbyzero, status);
return packFloatx80(1, floatx80_infinity.high,
floatx80_infinity.low);
return floatx80_default_inf(1, status);
}
normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
}
@ -740,8 +732,7 @@ floatx80 floatx80_etox(floatx80 a, float_status *status)
if (aSign) {
return packFloatx80(0, 0, 0);
}
return packFloatx80(0, floatx80_infinity.high,
floatx80_infinity.low);
return floatx80_default_inf(0, status);
}
if (aExp == 0 && aSig == 0) {
@ -924,8 +915,7 @@ floatx80 floatx80_twotox(floatx80 a, float_status *status)
if (aSign) {
return packFloatx80(0, 0, 0);
}
return packFloatx80(0, floatx80_infinity.high,
floatx80_infinity.low);
return floatx80_default_inf(0, status);
}
if (aExp == 0 && aSig == 0) {
@ -1075,8 +1065,7 @@ floatx80 floatx80_tentox(floatx80 a, float_status *status)
if (aSign) {
return packFloatx80(0, 0, 0);
}
return packFloatx80(0, floatx80_infinity.high,
floatx80_infinity.low);
return floatx80_default_inf(0, status);
}
if (aExp == 0 && aSig == 0) {
@ -2260,8 +2249,7 @@ floatx80 floatx80_atanh(floatx80 a, float_status *status)
if (compact >= 0x3FFF8000) { /* |X| >= 1 */
if (aExp == one_exp && aSig == one_sig) { /* |X| == 1 */
float_raise(float_flag_divbyzero, status);
return packFloatx80(aSign, floatx80_infinity.high,
floatx80_infinity.low);
return floatx80_default_inf(aSign, status);
} else { /* |X| > 1 */
float_raise(float_flag_invalid, status);
return floatx80_default_nan(status);
@ -2320,8 +2308,7 @@ floatx80 floatx80_etoxm1(floatx80 a, float_status *status)
if (aSign) {
return packFloatx80(aSign, one_exp, one_sig);
}
return packFloatx80(0, floatx80_infinity.high,
floatx80_infinity.low);
return floatx80_default_inf(0, status);
}
if (aExp == 0 && aSig == 0) {
@ -2687,8 +2674,7 @@ floatx80 floatx80_sinh(floatx80 a, float_status *status)
if ((uint64_t) (aSig << 1)) {
return propagateFloatx80NaNOneArg(a, status);
}
return packFloatx80(aSign, floatx80_infinity.high,
floatx80_infinity.low);
return floatx80_default_inf(aSign, status);
}
if (aExp == 0 && aSig == 0) {
@ -2774,8 +2760,7 @@ floatx80 floatx80_cosh(floatx80 a, float_status *status)
if ((uint64_t) (aSig << 1)) {
return propagateFloatx80NaNOneArg(a, status);
}
return packFloatx80(0, floatx80_infinity.high,
floatx80_infinity.low);
return floatx80_default_inf(0, status);
}
if (aExp == 0 && aSig == 0) {

View file

@ -128,6 +128,7 @@ static void superh_cpu_reset_hold(Object *obj, ResetType type)
set_flush_to_zero(1, &env->fp_status);
#endif
set_default_nan_mode(1, &env->fp_status);
set_snan_bit_is_one(true, &env->fp_status);
/* sign bit clear, set all frac bits other than msb */
set_float_default_nan_pattern(0b00111111, &env->fp_status);
/*