mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-04 16:23:55 -06:00
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:
commit
09951f5a27
68 changed files with 2439 additions and 383 deletions
13
MAINTAINERS
13
MAINTAINERS
|
@ -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
|
||||
|
|
70
docs/system/arm/imx8mp-evk.rst
Normal file
70
docs/system/arm/imx8mp-evk.rst
Normal 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
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1 +1 @@
|
|||
specific_ss.add(when: 'CONFIG_TCG', if_true: files('softfloat.c'))
|
||||
common_ss.add(when: 'CONFIG_TCG', if_true: files('softfloat.c'))
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
714
hw/arm/fsl-imx8mp.c
Normal 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
74
hw/arm/imx8mp-evk.c
Normal 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)
|
|
@ -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'))
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
160
hw/misc/imx8mp_analog.c
Normal 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
175
hw/misc/imx8mp_ccm.c
Normal 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);
|
|
@ -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',
|
||||
|
|
|
@ -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);
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,6 +99,9 @@ config ASTRO
|
|||
bool
|
||||
select PCI
|
||||
|
||||
config PCI_EXPRESS_FSL_IMX8M_PHY
|
||||
bool
|
||||
|
||||
config GT64120
|
||||
bool
|
||||
select PCI
|
||||
|
|
|
@ -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),
|
||||
|
|
98
hw/pci-host/fsl_imx8m_phy.c
Normal file
98
hw/pci-host/fsl_imx8m_phy.c
Normal 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)
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 PROGRAMMER’S 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
284
include/hw/arm/fsl-imx8mp.h
Normal 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 */
|
|
@ -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 */
|
||||
|
|
81
include/hw/misc/imx8mp_analog.h
Normal file
81
include/hw/misc/imx8mp_analog.h
Normal 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 */
|
30
include/hw/misc/imx8mp_ccm.h
Normal file
30
include/hw/misc/imx8mp_ccm.h
Normal 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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
28
include/hw/pci-host/fsl_imx8m_phy.h
Normal file
28
include/hw/pci-host/fsl_imx8m_phy.h
Normal 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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
155
target/arm/vfp_fpscr.c
Normal 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);
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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, "ient, &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 {
|
||||
|
|
|
@ -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 PROGRAMMER’S 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++) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
/*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue