target-arm queue:

* Implement AArch32 ARMv8-R support
  * Add Cortex-R52 CPU
  * fix handling of HLT semihosting in system mode
  * hw/timer/ixm_epit: cleanup and fix bug in compare handling
  * target/arm: Coding style fixes
  * target/arm: Clean up includes
  * nseries: minor code cleanups
  * target/arm: align exposed ID registers with Linux
  * hw/arm/smmu-common: remove unnecessary inlines
  * i.MX7D: Handle GPT timers
  * i.MX7D: Connect IRQs to GPIO devices
  * i.MX6UL: Add a specific GPT timer instance
  * hw/net: Fix read of uninitialized memory in imx_fec
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmO2/iYZHHBldGVyLm1h
 eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3sy1EACPsxR5R19BbfwuR3e2VKrA
 3ltc1ZwiEiDzKE0YJ+VL8zSyzNKFs0OD4O+ZOBPu5PegwhLdH5QI5QrhkRwlWr6T
 XJfNDF+8oUUIlNYeD9iSOiZt+W7cnaWrHoM4Oga3O610eS6f0hGmfVxlXUxUfT/4
 3x/MKcSXI4SnwXuXrxmqmTm7sVCXP8cbqrIZzN5VUo341B1uqQ5bp1hRmiLt+cvY
 pnCk3MgYCuZAXRQrLShJkFeu3lJ/W89DVAY5v5+VAMR3jD/tTvQ5bP4HdBMJP4RY
 AyoI/4cmlAnvOq4Yr8wKdWo7/fgkj9sTHV11sRWkiOdKhLZe9aNYnv1Bd2COhmvH
 gJcWZ8SNpJ364iRoQPy1PeKxuSMQaesUKWXkvkqjsaGKD9gr2QjTpI3yN6wU3O5+
 lT4wGsDMHDhpQml2r19+D3XGm5oA+t2sr1/27WjKBDYopTtZF/KuJ1xVMnIRxzJW
 M+V3BcM4RPivmv0a+ICA6f1WwE59EeBBzOfZ+VjBpnQAfTv9HRN1yCIVWRN8hIiz
 cC/iuY6tGxpdZf965fYCIj5cZ2OmCbIw1mh5hUSLDIaCd9+qXl7cgT7stpLar7kA
 tYDazF2J3v+XqUeyWtPndzAFdgr4rLNH9Q9kDKS9fyXOspIFqv6bBhAMMxiiTbT5
 zj5Y2K1lAyHLTTwWmcNruw==
 =b/pm
 -----END PGP SIGNATURE-----

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

target-arm queue:
 * Implement AArch32 ARMv8-R support
 * Add Cortex-R52 CPU
 * fix handling of HLT semihosting in system mode
 * hw/timer/ixm_epit: cleanup and fix bug in compare handling
 * target/arm: Coding style fixes
 * target/arm: Clean up includes
 * nseries: minor code cleanups
 * target/arm: align exposed ID registers with Linux
 * hw/arm/smmu-common: remove unnecessary inlines
 * i.MX7D: Handle GPT timers
 * i.MX7D: Connect IRQs to GPIO devices
 * i.MX6UL: Add a specific GPT timer instance
 * hw/net: Fix read of uninitialized memory in imx_fec

# gpg: Signature made Thu 05 Jan 2023 16:43:18 GMT
# gpg:                using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg:                issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate]
# gpg:                 aka "Peter Maydell <peter@archaic.org.uk>" [ultimate]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* tag 'pull-target-arm-20230105' of https://git.linaro.org/people/pmaydell/qemu-arm: (34 commits)
  hw/net: Fix read of uninitialized memory in imx_fec.
  i.MX7D: Connect IRQs to GPIO devices.
  i.MX6UL: Add a specific GPT timer instance for the i.MX6UL
  i.MX7D: Compute clock frequency for the fixed frequency clocks.
  i.MX7D: Connect GPT timers to IRQ
  hw/arm/smmu-common: Avoid using inlined functions with external linkage
  hw/arm/smmu-common: Reduce smmu_inv_notifiers_mr() scope
  target/arm: align exposed ID registers with Linux
  hw/arm/nseries: Silent -Wmissing-field-initializers warning
  hw/arm/nseries: Constify various read-only arrays
  hw/input/tsc2xxx: Constify set_transform()'s MouseTransformInfo arg
  target/arm: cleanup cpu includes
  target/arm: Remove unused includes from helper.c
  target/arm: Remove unused includes from m_helper.c
  target/arm: Fix checkpatch brace errors in helper.c
  target/arm: Fix checkpatch space errors in helper.c
  target/arm: Fix checkpatch comment style warnings in helper.c
  hw/timer/imx_epit: fix compare timer handling
  hw/timer/imx_epit: remove explicit fields cnt and freq
  hw/timer/imx_epit: factor out register write handlers
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2023-01-05 21:04:52 +00:00
commit d365cb0b9d
30 changed files with 1330 additions and 461 deletions

View file

@ -81,7 +81,7 @@ static void fsl_imx6ul_init(Object *obj)
*/ */
for (i = 0; i < FSL_IMX6UL_NUM_GPTS; i++) { for (i = 0; i < FSL_IMX6UL_NUM_GPTS; i++) {
snprintf(name, NAME_SIZE, "gpt%d", i); snprintf(name, NAME_SIZE, "gpt%d", i);
object_initialize_child(obj, name, &s->gpt[i], TYPE_IMX7_GPT); object_initialize_child(obj, name, &s->gpt[i], TYPE_IMX6UL_GPT);
} }
/* /*

View file

@ -219,9 +219,19 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
FSL_IMX7_GPT4_ADDR, FSL_IMX7_GPT4_ADDR,
}; };
static const int FSL_IMX7_GPTn_IRQ[FSL_IMX7_NUM_GPTS] = {
FSL_IMX7_GPT1_IRQ,
FSL_IMX7_GPT2_IRQ,
FSL_IMX7_GPT3_IRQ,
FSL_IMX7_GPT4_IRQ,
};
s->gpt[i].ccm = IMX_CCM(&s->ccm); s->gpt[i].ccm = IMX_CCM(&s->ccm);
sysbus_realize(SYS_BUS_DEVICE(&s->gpt[i]), &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->gpt[i]), &error_abort);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt[i]), 0, FSL_IMX7_GPTn_ADDR[i]); sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpt[i]), 0, FSL_IMX7_GPTn_ADDR[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpt[i]), 0,
qdev_get_gpio_in(DEVICE(&s->a7mpcore),
FSL_IMX7_GPTn_IRQ[i]));
} }
for (i = 0; i < FSL_IMX7_NUM_GPIOS; i++) { for (i = 0; i < FSL_IMX7_NUM_GPIOS; i++) {
@ -235,8 +245,37 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
FSL_IMX7_GPIO7_ADDR, FSL_IMX7_GPIO7_ADDR,
}; };
static const int FSL_IMX7_GPIOn_LOW_IRQ[FSL_IMX7_NUM_GPIOS] = {
FSL_IMX7_GPIO1_LOW_IRQ,
FSL_IMX7_GPIO2_LOW_IRQ,
FSL_IMX7_GPIO3_LOW_IRQ,
FSL_IMX7_GPIO4_LOW_IRQ,
FSL_IMX7_GPIO5_LOW_IRQ,
FSL_IMX7_GPIO6_LOW_IRQ,
FSL_IMX7_GPIO7_LOW_IRQ,
};
static const int FSL_IMX7_GPIOn_HIGH_IRQ[FSL_IMX7_NUM_GPIOS] = {
FSL_IMX7_GPIO1_HIGH_IRQ,
FSL_IMX7_GPIO2_HIGH_IRQ,
FSL_IMX7_GPIO3_HIGH_IRQ,
FSL_IMX7_GPIO4_HIGH_IRQ,
FSL_IMX7_GPIO5_HIGH_IRQ,
FSL_IMX7_GPIO6_HIGH_IRQ,
FSL_IMX7_GPIO7_HIGH_IRQ,
};
sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->gpio[i]), &error_abort);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0, FSL_IMX7_GPIOn_ADDR[i]); sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio[i]), 0,
FSL_IMX7_GPIOn_ADDR[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 0,
qdev_get_gpio_in(DEVICE(&s->a7mpcore),
FSL_IMX7_GPIOn_LOW_IRQ[i]));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio[i]), 1,
qdev_get_gpio_in(DEVICE(&s->a7mpcore),
FSL_IMX7_GPIOn_HIGH_IRQ[i]));
} }
/* /*

View file

@ -230,13 +230,13 @@ static void n8x0_i2c_setup(struct n800_s *s)
} }
/* Touchscreen and keypad controller */ /* Touchscreen and keypad controller */
static MouseTransformInfo n800_pointercal = { static const MouseTransformInfo n800_pointercal = {
.x = 800, .x = 800,
.y = 480, .y = 480,
.a = { 14560, -68, -3455208, -39, -9621, 35152972, 65536 }, .a = { 14560, -68, -3455208, -39, -9621, 35152972, 65536 },
}; };
static MouseTransformInfo n810_pointercal = { static const MouseTransformInfo n810_pointercal = {
.x = 800, .x = 800,
.y = 480, .y = 480,
.a = { 15041, 148, -4731056, 171, -10238, 35933380, 65536 }, .a = { 15041, 148, -4731056, 171, -10238, 35933380, 65536 },
@ -334,7 +334,7 @@ static void n810_key_event(void *opaque, int keycode)
#define M 0 #define M 0
static int n810_keys[0x80] = { static const int n810_keys[0x80] = {
[0x01] = 16, /* Q */ [0x01] = 16, /* Q */
[0x02] = 37, /* K */ [0x02] = 37, /* K */
[0x03] = 24, /* O */ [0x03] = 24, /* O */
@ -810,7 +810,7 @@ static void n8x0_usb_setup(struct n800_s *s)
/* Setup done before the main bootloader starts by some early setup code /* Setup done before the main bootloader starts by some early setup code
* - used when we want to run the main bootloader in emulation. This * - used when we want to run the main bootloader in emulation. This
* isn't documented. */ * isn't documented. */
static uint32_t n800_pinout[104] = { static const uint32_t n800_pinout[104] = {
0x080f00d8, 0x00d40808, 0x03080808, 0x080800d0, 0x080f00d8, 0x00d40808, 0x03080808, 0x080800d0,
0x00dc0808, 0x0b0f0f00, 0x080800b4, 0x00c00808, 0x00dc0808, 0x0b0f0f00, 0x080800b4, 0x00c00808,
0x08080808, 0x180800c4, 0x00b80000, 0x08080808, 0x08080808, 0x180800c4, 0x00b80000, 0x08080808,
@ -1060,7 +1060,7 @@ static void n8x0_boot_init(void *opaque)
#define OMAP_TAG_CBUS 0x4e03 #define OMAP_TAG_CBUS 0x4e03
#define OMAP_TAG_EM_ASIC_BB5 0x4e04 #define OMAP_TAG_EM_ASIC_BB5 0x4e04
static struct omap_gpiosw_info_s { static const struct omap_gpiosw_info_s {
const char *name; const char *name;
int line; int line;
int type; int type;
@ -1078,7 +1078,7 @@ static struct omap_gpiosw_info_s {
"headphone", N8X0_HEADPHONE_GPIO, "headphone", N8X0_HEADPHONE_GPIO,
OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED, OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED,
}, },
{ NULL } { /* end of list */ }
}, n810_gpiosw_info[] = { }, n810_gpiosw_info[] = {
{ {
"gps_reset", N810_GPS_RESET_GPIO, "gps_reset", N810_GPS_RESET_GPIO,
@ -1099,10 +1099,10 @@ static struct omap_gpiosw_info_s {
"slide", N810_SLIDE_GPIO, "slide", N810_SLIDE_GPIO,
OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED, OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
}, },
{ NULL } { /* end of list */ }
}; };
static struct omap_partition_info_s { static const struct omap_partition_info_s {
uint32_t offset; uint32_t offset;
uint32_t size; uint32_t size;
int mask; int mask;
@ -1113,27 +1113,25 @@ static struct omap_partition_info_s {
{ 0x00080000, 0x00200000, 0x0, "kernel" }, { 0x00080000, 0x00200000, 0x0, "kernel" },
{ 0x00280000, 0x00200000, 0x3, "initfs" }, { 0x00280000, 0x00200000, 0x3, "initfs" },
{ 0x00480000, 0x0fb80000, 0x3, "rootfs" }, { 0x00480000, 0x0fb80000, 0x3, "rootfs" },
{ /* end of list */ }
{ 0, 0, 0, NULL }
}, n810_part_info[] = { }, n810_part_info[] = {
{ 0x00000000, 0x00020000, 0x3, "bootloader" }, { 0x00000000, 0x00020000, 0x3, "bootloader" },
{ 0x00020000, 0x00060000, 0x0, "config" }, { 0x00020000, 0x00060000, 0x0, "config" },
{ 0x00080000, 0x00220000, 0x0, "kernel" }, { 0x00080000, 0x00220000, 0x0, "kernel" },
{ 0x002a0000, 0x00400000, 0x0, "initfs" }, { 0x002a0000, 0x00400000, 0x0, "initfs" },
{ 0x006a0000, 0x0f960000, 0x0, "rootfs" }, { 0x006a0000, 0x0f960000, 0x0, "rootfs" },
{ /* end of list */ }
{ 0, 0, 0, NULL }
}; };
static uint8_t n8x0_bd_addr[6] = { N8X0_BD_ADDR }; static const uint8_t n8x0_bd_addr[6] = { N8X0_BD_ADDR };
static int n8x0_atag_setup(void *p, int model) static int n8x0_atag_setup(void *p, int model)
{ {
uint8_t *b; uint8_t *b;
uint16_t *w; uint16_t *w;
uint32_t *l; uint32_t *l;
struct omap_gpiosw_info_s *gpiosw; const struct omap_gpiosw_info_s *gpiosw;
struct omap_partition_info_s *partition; const struct omap_partition_info_s *partition;
const char *tag; const char *tag;
w = p; w = p;

View file

@ -116,7 +116,7 @@ void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *new)
g_hash_table_insert(bs->iotlb, key, new); g_hash_table_insert(bs->iotlb, key, new);
} }
inline void smmu_iotlb_inv_all(SMMUState *s) void smmu_iotlb_inv_all(SMMUState *s)
{ {
trace_smmu_iotlb_inv_all(); trace_smmu_iotlb_inv_all();
g_hash_table_remove_all(s->iotlb); g_hash_table_remove_all(s->iotlb);
@ -146,9 +146,8 @@ static gboolean smmu_hash_remove_by_asid_iova(gpointer key, gpointer value,
((entry->iova & ~info->mask) == info->iova); ((entry->iova & ~info->mask) == info->iova);
} }
inline void void smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova,
smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova, uint8_t tg, uint64_t num_pages, uint8_t ttl)
uint8_t tg, uint64_t num_pages, uint8_t ttl)
{ {
/* if tg is not set we use 4KB range invalidation */ /* if tg is not set we use 4KB range invalidation */
uint8_t granule = tg ? tg * 2 + 10 : 12; uint8_t granule = tg ? tg * 2 + 10 : 12;
@ -174,7 +173,7 @@ smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova,
&info); &info);
} }
inline void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid) void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid)
{ {
trace_smmu_iotlb_inv_asid(asid); trace_smmu_iotlb_inv_asid(asid);
g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_asid, &asid); g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_asid, &asid);
@ -374,8 +373,8 @@ error:
* *
* return 0 on success * return 0 on success
*/ */
inline int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm, int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm,
SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info) SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info)
{ {
if (!cfg->aa64) { if (!cfg->aa64) {
/* /*
@ -483,7 +482,7 @@ static void smmu_unmap_notifier_range(IOMMUNotifier *n)
} }
/* Unmap all notifiers attached to @mr */ /* Unmap all notifiers attached to @mr */
inline void smmu_inv_notifiers_mr(IOMMUMemoryRegion *mr) static void smmu_inv_notifiers_mr(IOMMUMemoryRegion *mr)
{ {
IOMMUNotifier *n; IOMMUNotifier *n;

View file

@ -523,7 +523,7 @@ void *tsc2005_init(qemu_irq pintdav)
* from the touchscreen. Assuming 12-bit precision was used during * from the touchscreen. Assuming 12-bit precision was used during
* tslib calibration. * tslib calibration.
*/ */
void tsc2005_set_transform(void *opaque, MouseTransformInfo *info) void tsc2005_set_transform(void *opaque, const MouseTransformInfo *info)
{ {
TSC2005State *s = (TSC2005State *) opaque; TSC2005State *s = (TSC2005State *) opaque;

View file

@ -1176,8 +1176,7 @@ I2SCodec *tsc210x_codec(uWireSlave *chip)
* from the touchscreen. Assuming 12-bit precision was used during * from the touchscreen. Assuming 12-bit precision was used during
* tslib calibration. * tslib calibration.
*/ */
void tsc210x_set_transform(uWireSlave *chip, void tsc210x_set_transform(uWireSlave *chip, const MouseTransformInfo *info)
MouseTransformInfo *info)
{ {
TSC210xState *s = (TSC210xState *) chip->opaque; TSC210xState *s = (TSC210xState *) chip->opaque;
#if 0 #if 0

View file

@ -522,12 +522,6 @@ static uint32_t imx6ul_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
case CLK_32k: case CLK_32k:
freq = CKIL_FREQ; freq = CKIL_FREQ;
break; break;
case CLK_HIGH:
freq = CKIH_FREQ;
break;
case CLK_HIGH_DIV:
freq = CKIH_FREQ / 8;
break;
default: default:
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n", qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
TYPE_IMX6UL_CCM, __func__, clock); TYPE_IMX6UL_CCM, __func__, clock);

View file

@ -16,6 +16,10 @@
#include "hw/misc/imx7_ccm.h" #include "hw/misc/imx7_ccm.h"
#include "migration/vmstate.h" #include "migration/vmstate.h"
#include "trace.h"
#define CKIH_FREQ 24000000 /* 24MHz crystal input */
static void imx7_analog_reset(DeviceState *dev) static void imx7_analog_reset(DeviceState *dev)
{ {
IMX7AnalogState *s = IMX7_ANALOG(dev); IMX7AnalogState *s = IMX7_ANALOG(dev);
@ -219,16 +223,43 @@ static const VMStateDescription vmstate_imx7_ccm = {
static uint32_t imx7_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock) static uint32_t imx7_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
{ {
/* /*
* This function is "consumed" by GPT emulation code, however on * This function is "consumed" by GPT emulation code. Some clocks
* i.MX7 each GPT block can have their own clock root. This means * have fixed frequencies and we can provide requested frequency
* that this functions needs somehow to know requester's identity * easily. However for CCM provided clocks (like IPG) each GPT
* and the way to pass it: be it via additional IMXClk constants * timer can have its own clock root.
* or by adding another argument to this method needs to be * This means we need additionnal information when calling this
* figured out * function to know the requester's identity.
*/ */
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Not implemented\n", uint32_t freq = 0;
TYPE_IMX7_CCM, __func__);
return 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_IMX7_CCM, __func__, clock);
break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
TYPE_IMX7_CCM, __func__, clock);
break;
}
trace_ccm_clock_freq(clock, freq);
return freq;
} }
static void imx7_ccm_class_init(ObjectClass *klass, void *data) static void imx7_ccm_class_init(ObjectClass *klass, void *data)

View file

@ -1068,9 +1068,9 @@ static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf,
return 0; return 0;
} }
/* 4 bytes for the CRC. */
size += 4;
crc = cpu_to_be32(crc32(~0, buf, size)); crc = cpu_to_be32(crc32(~0, buf, size));
/* Increase size by 4, loop below reads the last 4 bytes from crc_ptr. */
size += 4;
crc_ptr = (uint8_t *) &crc; crc_ptr = (uint8_t *) &crc;
/* Huge frames are truncated. */ /* Huge frames are truncated. */
@ -1164,9 +1164,9 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf,
return 0; return 0;
} }
/* 4 bytes for the CRC. */
size += 4;
crc = cpu_to_be32(crc32(~0, buf, size)); crc = cpu_to_be32(crc32(~0, buf, size));
/* Increase size by 4, loop below reads the last 4 bytes from crc_ptr. */
size += 4;
crc_ptr = (uint8_t *) &crc; crc_ptr = (uint8_t *) &crc;
if (shift16) { if (shift16) {

View file

@ -6,6 +6,7 @@
* Originally written by Hans Jiang * Originally written by Hans Jiang
* Updated by Peter Chubb * Updated by Peter Chubb
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net> * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
* Updated by Axel Heider
* *
* This code is licensed under GPL version 2 or later. See * This code is licensed under GPL version 2 or later. See
* the COPYING file in the top-level directory. * the COPYING file in the top-level directory.
@ -66,73 +67,54 @@ static const IMXClk imx_epit_clocks[] = {
*/ */
static void imx_epit_update_int(IMXEPITState *s) static void imx_epit_update_int(IMXEPITState *s)
{ {
if (s->sr && (s->cr & CR_OCIEN) && (s->cr & CR_EN)) { if ((s->sr & SR_OCIF) && (s->cr & CR_OCIEN) && (s->cr & CR_EN)) {
qemu_irq_raise(s->irq); qemu_irq_raise(s->irq);
} else { } else {
qemu_irq_lower(s->irq); qemu_irq_lower(s->irq);
} }
} }
/* static uint32_t imx_epit_get_freq(IMXEPITState *s)
* Must be called from within a ptimer_transaction_begin/commit block
* for both s->timer_cmp and s->timer_reload.
*/
static void imx_epit_set_freq(IMXEPITState *s)
{ {
uint32_t clksrc; uint32_t clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, CR_CLKSRC_BITS);
uint32_t prescaler; uint32_t prescaler = 1 + extract32(s->cr, CR_PRESCALE_SHIFT, CR_PRESCALE_BITS);
uint32_t f_in = imx_ccm_get_clock_frequency(s->ccm, imx_epit_clocks[clksrc]);
clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, 2); uint32_t freq = f_in / prescaler;
prescaler = 1 + extract32(s->cr, CR_PRESCALE_SHIFT, 12); DPRINTF("ptimer frequency is %u\n", freq);
return freq;
s->freq = imx_ccm_get_clock_frequency(s->ccm,
imx_epit_clocks[clksrc]) / prescaler;
DPRINTF("Setting ptimer frequency to %u\n", s->freq);
if (s->freq) {
ptimer_set_freq(s->timer_reload, s->freq);
ptimer_set_freq(s->timer_cmp, s->freq);
}
} }
static void imx_epit_reset(DeviceState *dev) /*
* This is called both on hardware (device) reset and software reset.
*/
static void imx_epit_reset(IMXEPITState *s, bool is_hard_reset)
{ {
IMXEPITState *s = IMX_EPIT(dev); /* Soft reset doesn't touch some bits; hard reset clears them */
if (is_hard_reset) {
/* s->cr = 0;
* Soft reset doesn't touch some bits; hard reset clears them } else {
*/ s->cr &= (CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN);
s->cr &= (CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN); }
s->sr = 0; s->sr = 0;
s->lr = EPIT_TIMER_MAX; s->lr = EPIT_TIMER_MAX;
s->cmp = 0; s->cmp = 0;
s->cnt = 0;
ptimer_transaction_begin(s->timer_cmp); ptimer_transaction_begin(s->timer_cmp);
ptimer_transaction_begin(s->timer_reload); ptimer_transaction_begin(s->timer_reload);
/* stop both timers */
/*
* The reset switches off the input clock, so even if the CR.EN is still
* set, the timers are no longer running.
*/
assert(imx_epit_get_freq(s) == 0);
ptimer_stop(s->timer_cmp); ptimer_stop(s->timer_cmp);
ptimer_stop(s->timer_reload); ptimer_stop(s->timer_reload);
/* compute new frequency */
imx_epit_set_freq(s);
/* init both timers to EPIT_TIMER_MAX */ /* init both timers to EPIT_TIMER_MAX */
ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1); ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1);
ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1); ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1);
if (s->freq && (s->cr & CR_EN)) {
/* if the timer is still enabled, restart it */
ptimer_run(s->timer_reload, 0);
}
ptimer_transaction_commit(s->timer_cmp); ptimer_transaction_commit(s->timer_cmp);
ptimer_transaction_commit(s->timer_reload); ptimer_transaction_commit(s->timer_reload);
} }
static uint32_t imx_epit_update_count(IMXEPITState *s)
{
s->cnt = ptimer_get_count(s->timer_reload);
return s->cnt;
}
static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size) static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size)
{ {
IMXEPITState *s = IMX_EPIT(opaque); IMXEPITState *s = IMX_EPIT(opaque);
@ -156,8 +138,7 @@ static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size)
break; break;
case 4: /* CNT */ case 4: /* CNT */
imx_epit_update_count(s); reg_value = ptimer_get_count(s->timer_reload);
reg_value = s->cnt;
break; break;
default: default:
@ -171,144 +152,219 @@ static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size)
return reg_value; return reg_value;
} }
/* Must be called from ptimer_transaction_begin/commit block for s->timer_cmp */ /*
static void imx_epit_reload_compare_timer(IMXEPITState *s) * Must be called from a ptimer_transaction_begin/commit block for
* s->timer_cmp, but outside of a transaction block of s->timer_reload,
* so the proper counter value is read.
*/
static void imx_epit_update_compare_timer(IMXEPITState *s)
{ {
if ((s->cr & (CR_EN | CR_OCIEN)) == (CR_EN | CR_OCIEN)) { uint64_t counter = 0;
/* if the compare feature is on and timers are running */ bool is_oneshot = false;
uint32_t tmp = imx_epit_update_count(s); /*
uint64_t next; * The compare timer only has to run if the timer peripheral is active
if (tmp > s->cmp) { * and there is an input clock, Otherwise it can be switched off.
/* It'll fire in this round of the timer */ */
next = tmp - s->cmp; bool is_active = (s->cr & CR_EN) && imx_epit_get_freq(s);
} else { /* catch it next time around */ if (is_active) {
next = tmp - s->cmp + ((s->cr & CR_RLD) ? EPIT_TIMER_MAX : s->lr); /*
* Calculate next timeout for compare timer. Reading the reload
* counter returns proper results only if pending transactions
* on it are committed here. Otherwise stale values are be read.
*/
counter = ptimer_get_count(s->timer_reload);
uint64_t limit = ptimer_get_limit(s->timer_cmp);
/*
* The compare timer is a periodic timer if the limit is at least
* the compare value. Otherwise it may fire at most once in the
* current round.
*/
bool is_oneshot = (limit >= s->cmp);
if (counter >= s->cmp) {
/* The compare timer fires in the current round. */
counter -= s->cmp;
} else if (!is_oneshot) {
/*
* The compare timer fires after a reload, as it is below the
* compare value already in this round. Note that the counter
* value calculated below can be above the 32-bit limit, which
* is legal here because the compare timer is an internal
* helper ptimer only.
*/
counter += limit - s->cmp;
} else {
/*
* The compare timer won't fire in this round, and the limit is
* set to a value below the compare value. This practically means
* it will never fire, so it can be switched off.
*/
is_active = false;
} }
ptimer_set_count(s->timer_cmp, next);
} }
/*
* Set the compare timer and let it run, or stop it. This is agnostic
* of CR.OCIEN bit, as this bit affects interrupt generation only. The
* compare timer needs to run even if no interrupts are to be generated,
* because the SR.OCIF bit must be updated also.
* Note that the timer might already be stopped or be running with
* counter values. However, finding out when an update is needed and
* when not is not trivial. It's much easier applying the setting again,
* as this does not harm either and the overhead is negligible.
*/
if (is_active) {
ptimer_set_count(s->timer_cmp, counter);
ptimer_run(s->timer_cmp, is_oneshot ? 1 : 0);
} else {
ptimer_stop(s->timer_cmp);
}
}
static void imx_epit_write_cr(IMXEPITState *s, uint32_t value)
{
uint32_t oldcr = s->cr;
s->cr = value & 0x03ffffff;
if (s->cr & CR_SWR) {
/*
* Reset clears CR.SWR again. It does not touch CR.EN, but the timers
* are still stopped because the input clock is disabled.
*/
imx_epit_reset(s, false);
} else {
uint32_t freq;
uint32_t toggled_cr_bits = oldcr ^ s->cr;
/* re-initialize the limits if CR.RLD has changed */
bool set_limit = toggled_cr_bits & CR_RLD;
/* set the counter if the timer got just enabled and CR.ENMOD is set */
bool is_switched_on = (toggled_cr_bits & s->cr) & CR_EN;
bool set_counter = is_switched_on && (s->cr & CR_ENMOD);
ptimer_transaction_begin(s->timer_cmp);
ptimer_transaction_begin(s->timer_reload);
freq = imx_epit_get_freq(s);
if (freq) {
ptimer_set_freq(s->timer_reload, freq);
ptimer_set_freq(s->timer_cmp, freq);
}
if (set_limit || set_counter) {
uint64_t limit = (s->cr & CR_RLD) ? s->lr : EPIT_TIMER_MAX;
ptimer_set_limit(s->timer_reload, limit, set_counter ? 1 : 0);
if (set_limit) {
ptimer_set_limit(s->timer_cmp, limit, 0);
}
}
/*
* If there is an input clock and the peripheral is enabled, then
* ensure the wall clock timer is ticking. Otherwise stop the timers.
* The compare timer will be updated later.
*/
if (freq && (s->cr & CR_EN)) {
ptimer_run(s->timer_reload, 0);
} else {
ptimer_stop(s->timer_reload);
}
/* Commit changes to reload timer, so they can propagate. */
ptimer_transaction_commit(s->timer_reload);
/* Update compare timer based on the committed reload timer value. */
imx_epit_update_compare_timer(s);
ptimer_transaction_commit(s->timer_cmp);
}
/*
* The interrupt state can change due to:
* - reset clears both SR.OCIF and CR.OCIE
* - write to CR.EN or CR.OCIE
*/
imx_epit_update_int(s);
}
static void imx_epit_write_sr(IMXEPITState *s, uint32_t value)
{
/* writing 1 to SR.OCIF clears this bit and turns the interrupt off */
if (value & SR_OCIF) {
s->sr = 0; /* SR.OCIF is the only bit in this register anyway */
imx_epit_update_int(s);
}
}
static void imx_epit_write_lr(IMXEPITState *s, uint32_t value)
{
s->lr = value;
ptimer_transaction_begin(s->timer_cmp);
ptimer_transaction_begin(s->timer_reload);
if (s->cr & CR_RLD) {
/* Also set the limit if the LRD bit is set */
/* If IOVW bit is set then set the timer value */
ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW);
ptimer_set_limit(s->timer_cmp, s->lr, 0);
} else if (s->cr & CR_IOVW) {
/* If IOVW bit is set then set the timer value */
ptimer_set_count(s->timer_reload, s->lr);
}
/* Commit the changes to s->timer_reload, so they can propagate. */
ptimer_transaction_commit(s->timer_reload);
/* Update the compare timer based on the committed reload timer value. */
imx_epit_update_compare_timer(s);
ptimer_transaction_commit(s->timer_cmp);
}
static void imx_epit_write_cmp(IMXEPITState *s, uint32_t value)
{
s->cmp = value;
/* Update the compare timer based on the committed reload timer value. */
ptimer_transaction_begin(s->timer_cmp);
imx_epit_update_compare_timer(s);
ptimer_transaction_commit(s->timer_cmp);
} }
static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value, static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value,
unsigned size) unsigned size)
{ {
IMXEPITState *s = IMX_EPIT(opaque); IMXEPITState *s = IMX_EPIT(opaque);
uint64_t oldcr;
DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(offset >> 2), DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(offset >> 2),
(uint32_t)value); (uint32_t)value);
switch (offset >> 2) { switch (offset >> 2) {
case 0: /* CR */ case 0: /* CR */
imx_epit_write_cr(s, (uint32_t)value);
oldcr = s->cr;
s->cr = value & 0x03ffffff;
if (s->cr & CR_SWR) {
/* handle the reset */
imx_epit_reset(DEVICE(s));
/*
* TODO: could we 'break' here? following operations appear
* to duplicate the work imx_epit_reset() already did.
*/
}
ptimer_transaction_begin(s->timer_cmp);
ptimer_transaction_begin(s->timer_reload);
if (!(s->cr & CR_SWR)) {
imx_epit_set_freq(s);
}
if (s->freq && (s->cr & CR_EN) && !(oldcr & CR_EN)) {
if (s->cr & CR_ENMOD) {
if (s->cr & CR_RLD) {
ptimer_set_limit(s->timer_reload, s->lr, 1);
ptimer_set_limit(s->timer_cmp, s->lr, 1);
} else {
ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1);
ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1);
}
}
imx_epit_reload_compare_timer(s);
ptimer_run(s->timer_reload, 0);
if (s->cr & CR_OCIEN) {
ptimer_run(s->timer_cmp, 0);
} else {
ptimer_stop(s->timer_cmp);
}
} else if (!(s->cr & CR_EN)) {
/* stop both timers */
ptimer_stop(s->timer_reload);
ptimer_stop(s->timer_cmp);
} else if (s->cr & CR_OCIEN) {
if (!(oldcr & CR_OCIEN)) {
imx_epit_reload_compare_timer(s);
ptimer_run(s->timer_cmp, 0);
}
} else {
ptimer_stop(s->timer_cmp);
}
ptimer_transaction_commit(s->timer_cmp);
ptimer_transaction_commit(s->timer_reload);
break; break;
case 1: /* SR - ACK*/ case 1: /* SR */
/* writing 1 to OCIF clear the OCIF bit */ imx_epit_write_sr(s, (uint32_t)value);
if (value & 0x01) {
s->sr = 0;
imx_epit_update_int(s);
}
break; break;
case 2: /* LR - set ticks */ case 2: /* LR */
s->lr = value; imx_epit_write_lr(s, (uint32_t)value);
ptimer_transaction_begin(s->timer_cmp);
ptimer_transaction_begin(s->timer_reload);
if (s->cr & CR_RLD) {
/* Also set the limit if the LRD bit is set */
/* If IOVW bit is set then set the timer value */
ptimer_set_limit(s->timer_reload, s->lr, s->cr & CR_IOVW);
ptimer_set_limit(s->timer_cmp, s->lr, 0);
} else if (s->cr & CR_IOVW) {
/* If IOVW bit is set then set the timer value */
ptimer_set_count(s->timer_reload, s->lr);
}
/*
* Commit the change to s->timer_reload, so it can propagate. Otherwise
* the timer interrupt may not fire properly. The commit must happen
* before calling imx_epit_reload_compare_timer(), which reads
* s->timer_reload internally again.
*/
ptimer_transaction_commit(s->timer_reload);
imx_epit_reload_compare_timer(s);
ptimer_transaction_commit(s->timer_cmp);
break; break;
case 3: /* CMP */ case 3: /* CMP */
s->cmp = value; imx_epit_write_cmp(s, (uint32_t)value);
ptimer_transaction_begin(s->timer_cmp);
imx_epit_reload_compare_timer(s);
ptimer_transaction_commit(s->timer_cmp);
break; break;
default: default:
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%" qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
HWADDR_PRIx "\n", TYPE_IMX_EPIT, __func__, offset); HWADDR_PRIx "\n", TYPE_IMX_EPIT, __func__, offset);
break; break;
} }
} }
static void imx_epit_cmp(void *opaque) static void imx_epit_cmp(void *opaque)
{ {
IMXEPITState *s = IMX_EPIT(opaque); IMXEPITState *s = IMX_EPIT(opaque);
DPRINTF("sr was %d\n", s->sr); /* The cmp ptimer can't be running when the peripheral is disabled */
assert(s->cr & CR_EN);
s->sr = 1; DPRINTF("sr was %d\n", s->sr);
/* Set interrupt status bit SR.OCIF and update the interrupt state */
s->sr |= SR_OCIF;
imx_epit_update_int(s); imx_epit_update_int(s);
} }
@ -325,15 +381,13 @@ static const MemoryRegionOps imx_epit_ops = {
static const VMStateDescription vmstate_imx_timer_epit = { static const VMStateDescription vmstate_imx_timer_epit = {
.name = TYPE_IMX_EPIT, .name = TYPE_IMX_EPIT,
.version_id = 2, .version_id = 3,
.minimum_version_id = 2, .minimum_version_id = 3,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT32(cr, IMXEPITState), VMSTATE_UINT32(cr, IMXEPITState),
VMSTATE_UINT32(sr, IMXEPITState), VMSTATE_UINT32(sr, IMXEPITState),
VMSTATE_UINT32(lr, IMXEPITState), VMSTATE_UINT32(lr, IMXEPITState),
VMSTATE_UINT32(cmp, IMXEPITState), VMSTATE_UINT32(cmp, IMXEPITState),
VMSTATE_UINT32(cnt, IMXEPITState),
VMSTATE_UINT32(freq, IMXEPITState),
VMSTATE_PTIMER(timer_reload, IMXEPITState), VMSTATE_PTIMER(timer_reload, IMXEPITState),
VMSTATE_PTIMER(timer_cmp, IMXEPITState), VMSTATE_PTIMER(timer_cmp, IMXEPITState),
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
@ -352,17 +406,33 @@ static void imx_epit_realize(DeviceState *dev, Error **errp)
0x00001000); 0x00001000);
sysbus_init_mmio(sbd, &s->iomem); sysbus_init_mmio(sbd, &s->iomem);
/*
* The reload timer keeps running when the peripheral is enabled. It is a
* kind of wall clock that does not generate any interrupts. The callback
* needs to be provided, but it does nothing as the ptimer already supports
* all necessary reloading functionality.
*/
s->timer_reload = ptimer_init(imx_epit_reload, s, PTIMER_POLICY_LEGACY); s->timer_reload = ptimer_init(imx_epit_reload, s, PTIMER_POLICY_LEGACY);
/*
* The compare timer is running only when the peripheral configuration is
* in a state that will generate compare interrupts.
*/
s->timer_cmp = ptimer_init(imx_epit_cmp, s, PTIMER_POLICY_LEGACY); s->timer_cmp = ptimer_init(imx_epit_cmp, s, PTIMER_POLICY_LEGACY);
} }
static void imx_epit_dev_reset(DeviceState *dev)
{
IMXEPITState *s = IMX_EPIT(dev);
imx_epit_reset(s, true);
}
static void imx_epit_class_init(ObjectClass *klass, void *data) static void imx_epit_class_init(ObjectClass *klass, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = imx_epit_realize; dc->realize = imx_epit_realize;
dc->reset = imx_epit_reset; dc->reset = imx_epit_dev_reset;
dc->vmsd = &vmstate_imx_timer_epit; dc->vmsd = &vmstate_imx_timer_epit;
dc->desc = "i.MX periodic timer"; dc->desc = "i.MX periodic timer";
} }

View file

@ -115,6 +115,17 @@ static const IMXClk imx6_gpt_clocks[] = {
CLK_HIGH, /* 111 reference clock */ CLK_HIGH, /* 111 reference clock */
}; };
static const IMXClk imx6ul_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_NONE, /* 101 not defined */
CLK_NONE, /* 110 not defined */
CLK_NONE, /* 111 not defined */
};
static const IMXClk imx7_gpt_clocks[] = { static const IMXClk imx7_gpt_clocks[] = {
CLK_NONE, /* 000 No clock source */ CLK_NONE, /* 000 No clock source */
CLK_IPG, /* 001 ipg_clk, 532MHz*/ CLK_IPG, /* 001 ipg_clk, 532MHz*/
@ -539,6 +550,13 @@ static void imx6_gpt_init(Object *obj)
s->clocks = imx6_gpt_clocks; s->clocks = imx6_gpt_clocks;
} }
static void imx6ul_gpt_init(Object *obj)
{
IMXGPTState *s = IMX_GPT(obj);
s->clocks = imx6ul_gpt_clocks;
}
static void imx7_gpt_init(Object *obj) static void imx7_gpt_init(Object *obj)
{ {
IMXGPTState *s = IMX_GPT(obj); IMXGPTState *s = IMX_GPT(obj);
@ -566,6 +584,12 @@ static const TypeInfo imx6_gpt_info = {
.instance_init = imx6_gpt_init, .instance_init = imx6_gpt_init,
}; };
static const TypeInfo imx6ul_gpt_info = {
.name = TYPE_IMX6UL_GPT,
.parent = TYPE_IMX25_GPT,
.instance_init = imx6ul_gpt_init,
};
static const TypeInfo imx7_gpt_info = { static const TypeInfo imx7_gpt_info = {
.name = TYPE_IMX7_GPT, .name = TYPE_IMX7_GPT,
.parent = TYPE_IMX25_GPT, .parent = TYPE_IMX25_GPT,
@ -577,6 +601,7 @@ static void imx_gpt_register_types(void)
type_register_static(&imx25_gpt_info); type_register_static(&imx25_gpt_info);
type_register_static(&imx31_gpt_info); type_register_static(&imx31_gpt_info);
type_register_static(&imx6_gpt_info); type_register_static(&imx6_gpt_info);
type_register_static(&imx6ul_gpt_info);
type_register_static(&imx7_gpt_info); type_register_static(&imx7_gpt_info);
} }

View file

@ -235,6 +235,26 @@ enum FslIMX7IRQs {
FSL_IMX7_USB2_IRQ = 42, FSL_IMX7_USB2_IRQ = 42,
FSL_IMX7_USB3_IRQ = 40, FSL_IMX7_USB3_IRQ = 40,
FSL_IMX7_GPT1_IRQ = 55,
FSL_IMX7_GPT2_IRQ = 54,
FSL_IMX7_GPT3_IRQ = 53,
FSL_IMX7_GPT4_IRQ = 52,
FSL_IMX7_GPIO1_LOW_IRQ = 64,
FSL_IMX7_GPIO1_HIGH_IRQ = 65,
FSL_IMX7_GPIO2_LOW_IRQ = 66,
FSL_IMX7_GPIO2_HIGH_IRQ = 67,
FSL_IMX7_GPIO3_LOW_IRQ = 68,
FSL_IMX7_GPIO3_HIGH_IRQ = 69,
FSL_IMX7_GPIO4_LOW_IRQ = 70,
FSL_IMX7_GPIO4_HIGH_IRQ = 71,
FSL_IMX7_GPIO5_LOW_IRQ = 72,
FSL_IMX7_GPIO5_HIGH_IRQ = 73,
FSL_IMX7_GPIO6_LOW_IRQ = 74,
FSL_IMX7_GPIO6_HIGH_IRQ = 75,
FSL_IMX7_GPIO7_LOW_IRQ = 76,
FSL_IMX7_GPIO7_HIGH_IRQ = 77,
FSL_IMX7_WDOG1_IRQ = 78, FSL_IMX7_WDOG1_IRQ = 78,
FSL_IMX7_WDOG2_IRQ = 79, FSL_IMX7_WDOG2_IRQ = 79,
FSL_IMX7_WDOG3_IRQ = 10, FSL_IMX7_WDOG3_IRQ = 10,

View file

@ -173,7 +173,4 @@ void smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova,
/* Unmap the range of all the notifiers registered to any IOMMU mr */ /* Unmap the range of all the notifiers registered to any IOMMU mr */
void smmu_inv_notifiers_all(SMMUState *s); void smmu_inv_notifiers_all(SMMUState *s);
/* Unmap the range of all the notifiers registered to @mr */
void smmu_inv_notifiers_mr(IOMMUMemoryRegion *mr);
#endif /* HW_ARM_SMMU_COMMON_H */ #endif /* HW_ARM_SMMU_COMMON_H */

View file

@ -30,12 +30,12 @@ uWireSlave *tsc2102_init(qemu_irq pint);
uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav); uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav);
I2SCodec *tsc210x_codec(uWireSlave *chip); I2SCodec *tsc210x_codec(uWireSlave *chip);
uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len); uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len);
void tsc210x_set_transform(uWireSlave *chip, MouseTransformInfo *info); void tsc210x_set_transform(uWireSlave *chip, const MouseTransformInfo *info);
void tsc210x_key_event(uWireSlave *chip, int key, int down); void tsc210x_key_event(uWireSlave *chip, int key, int down);
/* tsc2005.c */ /* tsc2005.c */
void *tsc2005_init(qemu_irq pintdav); void *tsc2005_init(qemu_irq pintdav);
uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len); uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len);
void tsc2005_set_transform(void *opaque, MouseTransformInfo *info); void tsc2005_set_transform(void *opaque, const MouseTransformInfo *info);
#endif #endif

View file

@ -43,7 +43,7 @@
#define CR_OCIEN (1 << 2) #define CR_OCIEN (1 << 2)
#define CR_RLD (1 << 3) #define CR_RLD (1 << 3)
#define CR_PRESCALE_SHIFT (4) #define CR_PRESCALE_SHIFT (4)
#define CR_PRESCALE_MASK (0xfff) #define CR_PRESCALE_BITS (12)
#define CR_SWR (1 << 16) #define CR_SWR (1 << 16)
#define CR_IOVW (1 << 17) #define CR_IOVW (1 << 17)
#define CR_DBGEN (1 << 18) #define CR_DBGEN (1 << 18)
@ -51,7 +51,9 @@
#define CR_DOZEN (1 << 20) #define CR_DOZEN (1 << 20)
#define CR_STOPEN (1 << 21) #define CR_STOPEN (1 << 21)
#define CR_CLKSRC_SHIFT (24) #define CR_CLKSRC_SHIFT (24)
#define CR_CLKSRC_MASK (0x3 << CR_CLKSRC_SHIFT) #define CR_CLKSRC_BITS (2)
#define SR_OCIF (1 << 0)
#define EPIT_TIMER_MAX 0XFFFFFFFFUL #define EPIT_TIMER_MAX 0XFFFFFFFFUL
@ -72,9 +74,7 @@ struct IMXEPITState {
uint32_t sr; uint32_t sr;
uint32_t lr; uint32_t lr;
uint32_t cmp; uint32_t cmp;
uint32_t cnt;
uint32_t freq;
qemu_irq irq; qemu_irq irq;
}; };

View file

@ -78,6 +78,7 @@
#define TYPE_IMX25_GPT "imx25.gpt" #define TYPE_IMX25_GPT "imx25.gpt"
#define TYPE_IMX31_GPT "imx31.gpt" #define TYPE_IMX31_GPT "imx31.gpt"
#define TYPE_IMX6_GPT "imx6.gpt" #define TYPE_IMX6_GPT "imx6.gpt"
#define TYPE_IMX6UL_GPT "imx6ul.gpt"
#define TYPE_IMX7_GPT "imx7.gpt" #define TYPE_IMX7_GPT "imx7.gpt"
#define TYPE_IMX_GPT TYPE_IMX25_GPT #define TYPE_IMX_GPT TYPE_IMX25_GPT

View file

@ -26,7 +26,6 @@
#include "target/arm/idau.h" #include "target/arm/idau.h"
#include "qemu/module.h" #include "qemu/module.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qapi/visitor.h"
#include "cpu.h" #include "cpu.h"
#ifdef CONFIG_TCG #ifdef CONFIG_TCG
#include "hw/core/tcg-cpu-ops.h" #include "hw/core/tcg-cpu-ops.h"
@ -309,6 +308,10 @@ static void arm_cpu_reset_hold(Object *obj)
env->cp15.cpacr_el1 = FIELD_DP64(env->cp15.cpacr_el1, env->cp15.cpacr_el1 = FIELD_DP64(env->cp15.cpacr_el1,
CPACR, CP11, 3); CPACR, CP11, 3);
#endif #endif
if (arm_feature(env, ARM_FEATURE_V8)) {
env->cp15.rvbar = cpu->rvbar_prop;
env->regs[15] = cpu->rvbar_prop;
}
} }
#if defined(CONFIG_USER_ONLY) #if defined(CONFIG_USER_ONLY)
@ -487,6 +490,14 @@ static void arm_cpu_reset_hold(Object *obj)
sizeof(*env->pmsav7.dracr) * cpu->pmsav7_dregion); sizeof(*env->pmsav7.dracr) * cpu->pmsav7_dregion);
} }
} }
if (cpu->pmsav8r_hdregion > 0) {
memset(env->pmsav8.hprbar, 0,
sizeof(*env->pmsav8.hprbar) * cpu->pmsav8r_hdregion);
memset(env->pmsav8.hprlar, 0,
sizeof(*env->pmsav8.hprlar) * cpu->pmsav8r_hdregion);
}
env->pmsav7.rnr[M_REG_NS] = 0; env->pmsav7.rnr[M_REG_NS] = 0;
env->pmsav7.rnr[M_REG_S] = 0; env->pmsav7.rnr[M_REG_S] = 0;
env->pmsav8.mair0[M_REG_NS] = 0; env->pmsav8.mair0[M_REG_NS] = 0;
@ -1345,7 +1356,7 @@ void arm_cpu_post_init(Object *obj)
qdev_property_add_static(DEVICE(obj), &arm_cpu_reset_hivecs_property); qdev_property_add_static(DEVICE(obj), &arm_cpu_reset_hivecs_property);
} }
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { if (arm_feature(&cpu->env, ARM_FEATURE_V8)) {
object_property_add_uint64_ptr(obj, "rvbar", object_property_add_uint64_ptr(obj, "rvbar",
&cpu->rvbar_prop, &cpu->rvbar_prop,
OBJ_PROP_FLAG_READWRITE); OBJ_PROP_FLAG_READWRITE);
@ -1998,11 +2009,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
/* MPU can be configured out of a PMSA CPU either by setting has-mpu /* MPU can be configured out of a PMSA CPU either by setting has-mpu
* to false or by setting pmsav7-dregion to 0. * to false or by setting pmsav7-dregion to 0.
*/ */
if (!cpu->has_mpu) { if (!cpu->has_mpu || cpu->pmsav7_dregion == 0) {
cpu->pmsav7_dregion = 0;
}
if (cpu->pmsav7_dregion == 0) {
cpu->has_mpu = false; cpu->has_mpu = false;
cpu->pmsav7_dregion = 0;
cpu->pmsav8r_hdregion = 0;
} }
if (arm_feature(env, ARM_FEATURE_PMSA) && if (arm_feature(env, ARM_FEATURE_PMSA) &&
@ -2029,6 +2039,19 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
env->pmsav7.dracr = g_new0(uint32_t, nr); env->pmsav7.dracr = g_new0(uint32_t, nr);
} }
} }
if (cpu->pmsav8r_hdregion > 0xff) {
error_setg(errp, "PMSAv8 MPU EL2 #regions invalid %" PRIu32,
cpu->pmsav8r_hdregion);
return;
}
if (cpu->pmsav8r_hdregion) {
env->pmsav8.hprbar = g_new0(uint32_t,
cpu->pmsav8r_hdregion);
env->pmsav8.hprlar = g_new0(uint32_t,
cpu->pmsav8r_hdregion);
}
} }
if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {

View file

@ -309,6 +309,7 @@ typedef struct CPUArchState {
}; };
uint64_t sctlr_el[4]; uint64_t sctlr_el[4];
}; };
uint64_t vsctlr; /* Virtualization System control register. */
uint64_t cpacr_el1; /* Architectural feature access control register */ uint64_t cpacr_el1; /* Architectural feature access control register */
uint64_t cptr_el[4]; /* ARMv8 feature trap registers */ uint64_t cptr_el[4]; /* ARMv8 feature trap registers */
uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */ uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */
@ -745,8 +746,11 @@ typedef struct CPUArchState {
*/ */
uint32_t *rbar[M_REG_NUM_BANKS]; uint32_t *rbar[M_REG_NUM_BANKS];
uint32_t *rlar[M_REG_NUM_BANKS]; uint32_t *rlar[M_REG_NUM_BANKS];
uint32_t *hprbar;
uint32_t *hprlar;
uint32_t mair0[M_REG_NUM_BANKS]; uint32_t mair0[M_REG_NUM_BANKS];
uint32_t mair1[M_REG_NUM_BANKS]; uint32_t mair1[M_REG_NUM_BANKS];
uint32_t hprselr;
} pmsav8; } pmsav8;
/* v8M SAU */ /* v8M SAU */
@ -906,6 +910,8 @@ struct ArchCPU {
bool has_mpu; bool has_mpu;
/* PMSAv7 MPU number of supported regions */ /* PMSAv7 MPU number of supported regions */
uint32_t pmsav7_dregion; uint32_t pmsav7_dregion;
/* PMSAv8 MPU number of supported hyp regions */
uint32_t pmsav8r_hdregion;
/* v8M SAU number of supported regions */ /* v8M SAU number of supported regions */
uint32_t sau_sregion; uint32_t sau_sregion;

View file

@ -21,13 +21,7 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "cpu.h" #include "cpu.h"
#ifdef CONFIG_TCG
#include "hw/core/tcg-cpu-ops.h"
#endif /* CONFIG_TCG */
#include "qemu/module.h" #include "qemu/module.h"
#if !defined(CONFIG_USER_ONLY)
#include "hw/loader.h"
#endif
#include "sysemu/kvm.h" #include "sysemu/kvm.h"
#include "sysemu/hvf.h" #include "sysemu/hvf.h"
#include "kvm_arm.h" #include "kvm_arm.h"

View file

@ -854,6 +854,47 @@ static void cortex_r5_initfn(Object *obj)
define_arm_cp_regs(cpu, cortexr5_cp_reginfo); define_arm_cp_regs(cpu, cortexr5_cp_reginfo);
} }
static void cortex_r52_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
set_feature(&cpu->env, ARM_FEATURE_V8);
set_feature(&cpu->env, ARM_FEATURE_EL2);
set_feature(&cpu->env, ARM_FEATURE_PMSA);
set_feature(&cpu->env, ARM_FEATURE_NEON);
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
cpu->midr = 0x411fd133; /* r1p3 */
cpu->revidr = 0x00000000;
cpu->reset_fpsid = 0x41034023;
cpu->isar.mvfr0 = 0x10110222;
cpu->isar.mvfr1 = 0x12111111;
cpu->isar.mvfr2 = 0x00000043;
cpu->ctr = 0x8144c004;
cpu->reset_sctlr = 0x30c50838;
cpu->isar.id_pfr0 = 0x00000131;
cpu->isar.id_pfr1 = 0x10111001;
cpu->isar.id_dfr0 = 0x03010006;
cpu->id_afr0 = 0x00000000;
cpu->isar.id_mmfr0 = 0x00211040;
cpu->isar.id_mmfr1 = 0x40000000;
cpu->isar.id_mmfr2 = 0x01200000;
cpu->isar.id_mmfr3 = 0xf0102211;
cpu->isar.id_mmfr4 = 0x00000010;
cpu->isar.id_isar0 = 0x02101110;
cpu->isar.id_isar1 = 0x13112111;
cpu->isar.id_isar2 = 0x21232142;
cpu->isar.id_isar3 = 0x01112131;
cpu->isar.id_isar4 = 0x00010142;
cpu->isar.id_isar5 = 0x00010001;
cpu->isar.dbgdidr = 0x77168000;
cpu->clidr = (1 << 27) | (1 << 24) | 0x3;
cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */
cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */
cpu->pmsav7_dregion = 16;
cpu->pmsav8r_hdregion = 16;
}
static void cortex_r5f_initfn(Object *obj) static void cortex_r5f_initfn(Object *obj)
{ {
ARMCPU *cpu = ARM_CPU(obj); ARMCPU *cpu = ARM_CPU(obj);
@ -1163,6 +1204,7 @@ static const ARMCPUInfo arm_tcg_cpus[] = {
.class_init = arm_v7m_class_init }, .class_init = arm_v7m_class_init },
{ .name = "cortex-r5", .initfn = cortex_r5_initfn }, { .name = "cortex-r5", .initfn = cortex_r5_initfn },
{ .name = "cortex-r5f", .initfn = cortex_r5f_initfn }, { .name = "cortex-r5f", .initfn = cortex_r5f_initfn },
{ .name = "cortex-r52", .initfn = cortex_r52_initfn },
{ .name = "ti925t", .initfn = ti925t_initfn }, { .name = "ti925t", .initfn = ti925t_initfn },
{ .name = "sa1100", .initfn = sa1100_initfn }, { .name = "sa1100", .initfn = sa1100_initfn },
{ .name = "sa1110", .initfn = sa1110_initfn }, { .name = "sa1110", .initfn = sa1110_initfn },

View file

@ -437,6 +437,9 @@ static uint32_t arm_debug_exception_fsr(CPUARMState *env)
if (target_el == 2 || arm_el_is_aa64(env, target_el)) { if (target_el == 2 || arm_el_is_aa64(env, target_el)) {
using_lpae = true; using_lpae = true;
} else if (arm_feature(env, ARM_FEATURE_PMSA) &&
arm_feature(env, ARM_FEATURE_V8)) {
using_lpae = true;
} else { } else {
if (arm_feature(env, ARM_FEATURE_LPAE) && if (arm_feature(env, ARM_FEATURE_LPAE) &&
(env->cp15.tcr_el[target_el] & TTBCR_EAE)) { (env->cp15.tcr_el[target_el] & TTBCR_EAE)) {

File diff suppressed because it is too large Load diff

View file

@ -257,6 +257,10 @@ unsigned int arm_pamax(ARMCPU *cpu);
static inline bool extended_addresses_enabled(CPUARMState *env) static inline bool extended_addresses_enabled(CPUARMState *env)
{ {
uint64_t tcr = env->cp15.tcr_el[arm_is_secure(env) ? 3 : 1]; uint64_t tcr = env->cp15.tcr_el[arm_is_secure(env) ? 3 : 1];
if (arm_feature(env, ARM_FEATURE_PMSA) &&
arm_feature(env, ARM_FEATURE_V8)) {
return true;
}
return arm_el_is_aa64(env, 1) || return arm_el_is_aa64(env, 1) ||
(arm_feature(env, ARM_FEATURE_LPAE) && (tcr & TTBCR_EAE)); (arm_feature(env, ARM_FEATURE_LPAE) && (tcr & TTBCR_EAE));
} }

View file

@ -7,30 +7,14 @@
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu/units.h"
#include "target/arm/idau.h"
#include "trace.h"
#include "cpu.h" #include "cpu.h"
#include "internals.h" #include "internals.h"
#include "exec/gdbstub.h"
#include "exec/helper-proto.h" #include "exec/helper-proto.h"
#include "qemu/host-utils.h"
#include "qemu/main-loop.h" #include "qemu/main-loop.h"
#include "qemu/bitops.h" #include "qemu/bitops.h"
#include "qemu/crc32c.h"
#include "qemu/qemu-print.h"
#include "qemu/log.h" #include "qemu/log.h"
#include "exec/exec-all.h" #include "exec/exec-all.h"
#include <zlib.h> /* For crc32 */
#include "semihosting/semihost.h"
#include "sysemu/cpus.h"
#include "sysemu/kvm.h"
#include "qemu/range.h"
#include "qapi/qapi-commands-machine-target.h"
#include "qapi/error.h"
#include "qemu/guest-random.h"
#ifdef CONFIG_TCG #ifdef CONFIG_TCG
#include "arm_ldst.h"
#include "exec/cpu_ldst.h" #include "exec/cpu_ldst.h"
#include "semihosting/common-semi.h" #include "semihosting/common-semi.h"
#endif #endif

View file

@ -487,6 +487,30 @@ static bool pmsav8_needed(void *opaque)
arm_feature(env, ARM_FEATURE_V8); arm_feature(env, ARM_FEATURE_V8);
} }
static bool pmsav8r_needed(void *opaque)
{
ARMCPU *cpu = opaque;
CPUARMState *env = &cpu->env;
return arm_feature(env, ARM_FEATURE_PMSA) &&
arm_feature(env, ARM_FEATURE_V8) &&
!arm_feature(env, ARM_FEATURE_M);
}
static const VMStateDescription vmstate_pmsav8r = {
.name = "cpu/pmsav8/pmsav8r",
.version_id = 1,
.minimum_version_id = 1,
.needed = pmsav8r_needed,
.fields = (VMStateField[]) {
VMSTATE_VARRAY_UINT32(env.pmsav8.hprbar, ARMCPU,
pmsav8r_hdregion, 0, vmstate_info_uint32, uint32_t),
VMSTATE_VARRAY_UINT32(env.pmsav8.hprlar, ARMCPU,
pmsav8r_hdregion, 0, vmstate_info_uint32, uint32_t),
VMSTATE_END_OF_LIST()
},
};
static const VMStateDescription vmstate_pmsav8 = { static const VMStateDescription vmstate_pmsav8 = {
.name = "cpu/pmsav8", .name = "cpu/pmsav8",
.version_id = 1, .version_id = 1,
@ -500,6 +524,10 @@ static const VMStateDescription vmstate_pmsav8 = {
VMSTATE_UINT32(env.pmsav8.mair0[M_REG_NS], ARMCPU), VMSTATE_UINT32(env.pmsav8.mair0[M_REG_NS], ARMCPU),
VMSTATE_UINT32(env.pmsav8.mair1[M_REG_NS], ARMCPU), VMSTATE_UINT32(env.pmsav8.mair1[M_REG_NS], ARMCPU),
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription * []) {
&vmstate_pmsav8r,
NULL
} }
}; };

View file

@ -1758,9 +1758,13 @@ static bool pmsav7_use_background_region(ARMCPU *cpu, ARMMMUIdx mmu_idx,
if (arm_feature(env, ARM_FEATURE_M)) { if (arm_feature(env, ARM_FEATURE_M)) {
return env->v7m.mpu_ctrl[is_secure] & R_V7M_MPU_CTRL_PRIVDEFENA_MASK; return env->v7m.mpu_ctrl[is_secure] & R_V7M_MPU_CTRL_PRIVDEFENA_MASK;
} else {
return regime_sctlr(env, mmu_idx) & SCTLR_BR;
} }
if (mmu_idx == ARMMMUIdx_Stage2) {
return false;
}
return regime_sctlr(env, mmu_idx) & SCTLR_BR;
} }
static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address, static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address,
@ -1952,6 +1956,26 @@ static bool get_phys_addr_pmsav7(CPUARMState *env, uint32_t address,
return !(result->f.prot & (1 << access_type)); return !(result->f.prot & (1 << access_type));
} }
static uint32_t *regime_rbar(CPUARMState *env, ARMMMUIdx mmu_idx,
uint32_t secure)
{
if (regime_el(env, mmu_idx) == 2) {
return env->pmsav8.hprbar;
} else {
return env->pmsav8.rbar[secure];
}
}
static uint32_t *regime_rlar(CPUARMState *env, ARMMMUIdx mmu_idx,
uint32_t secure)
{
if (regime_el(env, mmu_idx) == 2) {
return env->pmsav8.hprlar;
} else {
return env->pmsav8.rlar[secure];
}
}
bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address, bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
MMUAccessType access_type, ARMMMUIdx mmu_idx, MMUAccessType access_type, ARMMMUIdx mmu_idx,
bool secure, GetPhysAddrResult *result, bool secure, GetPhysAddrResult *result,
@ -1974,6 +1998,13 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
bool hit = false; bool hit = false;
uint32_t addr_page_base = address & TARGET_PAGE_MASK; uint32_t addr_page_base = address & TARGET_PAGE_MASK;
uint32_t addr_page_limit = addr_page_base + (TARGET_PAGE_SIZE - 1); uint32_t addr_page_limit = addr_page_base + (TARGET_PAGE_SIZE - 1);
int region_counter;
if (regime_el(env, mmu_idx) == 2) {
region_counter = cpu->pmsav8r_hdregion;
} else {
region_counter = cpu->pmsav7_dregion;
}
result->f.lg_page_size = TARGET_PAGE_BITS; result->f.lg_page_size = TARGET_PAGE_BITS;
result->f.phys_addr = address; result->f.phys_addr = address;
@ -1982,6 +2013,10 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
*mregion = -1; *mregion = -1;
} }
if (mmu_idx == ARMMMUIdx_Stage2) {
fi->stage2 = true;
}
/* /*
* Unlike the ARM ARM pseudocode, we don't need to check whether this * Unlike the ARM ARM pseudocode, we don't need to check whether this
* was an exception vector read from the vector table (which is always * was an exception vector read from the vector table (which is always
@ -1998,17 +2033,26 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
hit = true; hit = true;
} }
for (n = (int)cpu->pmsav7_dregion - 1; n >= 0; n--) { uint32_t bitmask;
if (arm_feature(env, ARM_FEATURE_M)) {
bitmask = 0x1f;
} else {
bitmask = 0x3f;
fi->level = 0;
}
for (n = region_counter - 1; n >= 0; n--) {
/* region search */ /* region search */
/* /*
* Note that the base address is bits [31:5] from the register * Note that the base address is bits [31:x] from the register
* with bits [4:0] all zeroes, but the limit address is bits * with bits [x-1:0] all zeroes, but the limit address is bits
* [31:5] from the register with bits [4:0] all ones. * [31:x] from the register with bits [x:0] all ones. Where x is
* 5 for Cortex-M and 6 for Cortex-R
*/ */
uint32_t base = env->pmsav8.rbar[secure][n] & ~0x1f; uint32_t base = regime_rbar(env, mmu_idx, secure)[n] & ~bitmask;
uint32_t limit = env->pmsav8.rlar[secure][n] | 0x1f; uint32_t limit = regime_rlar(env, mmu_idx, secure)[n] | bitmask;
if (!(env->pmsav8.rlar[secure][n] & 0x1)) { if (!(regime_rlar(env, mmu_idx, secure)[n] & 0x1)) {
/* Region disabled */ /* Region disabled */
continue; continue;
} }
@ -2042,7 +2086,9 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
* PMSAv7 where highest-numbered-region wins) * PMSAv7 where highest-numbered-region wins)
*/ */
fi->type = ARMFault_Permission; fi->type = ARMFault_Permission;
fi->level = 1; if (arm_feature(env, ARM_FEATURE_M)) {
fi->level = 1;
}
return true; return true;
} }
@ -2052,8 +2098,11 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
} }
if (!hit) { if (!hit) {
/* background fault */ if (arm_feature(env, ARM_FEATURE_M)) {
fi->type = ARMFault_Background; fi->type = ARMFault_Background;
} else {
fi->type = ARMFault_Permission;
}
return true; return true;
} }
@ -2061,12 +2110,14 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
/* hit using the background region */ /* hit using the background region */
get_phys_addr_pmsav7_default(env, mmu_idx, address, &result->f.prot); get_phys_addr_pmsav7_default(env, mmu_idx, address, &result->f.prot);
} else { } else {
uint32_t ap = extract32(env->pmsav8.rbar[secure][matchregion], 1, 2); uint32_t matched_rbar = regime_rbar(env, mmu_idx, secure)[matchregion];
uint32_t xn = extract32(env->pmsav8.rbar[secure][matchregion], 0, 1); uint32_t matched_rlar = regime_rlar(env, mmu_idx, secure)[matchregion];
uint32_t ap = extract32(matched_rbar, 1, 2);
uint32_t xn = extract32(matched_rbar, 0, 1);
bool pxn = false; bool pxn = false;
if (arm_feature(env, ARM_FEATURE_V8_1M)) { if (arm_feature(env, ARM_FEATURE_V8_1M)) {
pxn = extract32(env->pmsav8.rlar[secure][matchregion], 4, 1); pxn = extract32(matched_rlar, 4, 1);
} }
if (m_is_system_region(env, address)) { if (m_is_system_region(env, address)) {
@ -2074,21 +2125,46 @@ bool pmsav8_mpu_lookup(CPUARMState *env, uint32_t address,
xn = 1; xn = 1;
} }
result->f.prot = simple_ap_to_rw_prot(env, mmu_idx, ap); if (regime_el(env, mmu_idx) == 2) {
result->f.prot = simple_ap_to_rw_prot_is_user(ap,
mmu_idx != ARMMMUIdx_E2);
} else {
result->f.prot = simple_ap_to_rw_prot(env, mmu_idx, ap);
}
if (!arm_feature(env, ARM_FEATURE_M)) {
uint8_t attrindx = extract32(matched_rlar, 1, 3);
uint64_t mair = env->cp15.mair_el[regime_el(env, mmu_idx)];
uint8_t sh = extract32(matched_rlar, 3, 2);
if (regime_sctlr(env, mmu_idx) & SCTLR_WXN &&
result->f.prot & PAGE_WRITE && mmu_idx != ARMMMUIdx_Stage2) {
xn = 0x1;
}
if ((regime_el(env, mmu_idx) == 1) &&
regime_sctlr(env, mmu_idx) & SCTLR_UWXN && ap == 0x1) {
pxn = 0x1;
}
result->cacheattrs.is_s2_format = false;
result->cacheattrs.attrs = extract64(mair, attrindx * 8, 8);
result->cacheattrs.shareability = sh;
}
if (result->f.prot && !xn && !(pxn && !is_user)) { if (result->f.prot && !xn && !(pxn && !is_user)) {
result->f.prot |= PAGE_EXEC; result->f.prot |= PAGE_EXEC;
} }
/*
* We don't need to look the attribute up in the MAIR0/MAIR1
* registers because that only tells us about cacheability.
*/
if (mregion) { if (mregion) {
*mregion = matchregion; *mregion = matchregion;
} }
} }
fi->type = ARMFault_Permission; fi->type = ARMFault_Permission;
fi->level = 1; if (arm_feature(env, ARM_FEATURE_M)) {
fi->level = 1;
}
return !(result->f.prot & (1 << access_type)); return !(result->f.prot & (1 << access_type));
} }
@ -2361,7 +2437,11 @@ static uint8_t combined_attrs_nofwb(uint64_t hcr,
{ {
uint8_t s1lo, s2lo, s1hi, s2hi, s2_mair_attrs, ret_attrs; uint8_t s1lo, s2lo, s1hi, s2hi, s2_mair_attrs, ret_attrs;
s2_mair_attrs = convert_stage2_attrs(hcr, s2.attrs); if (s2.is_s2_format) {
s2_mair_attrs = convert_stage2_attrs(hcr, s2.attrs);
} else {
s2_mair_attrs = s2.attrs;
}
s1lo = extract32(s1.attrs, 0, 4); s1lo = extract32(s1.attrs, 0, 4);
s2lo = extract32(s2_mair_attrs, 0, 4); s2lo = extract32(s2_mair_attrs, 0, 4);
@ -2418,6 +2498,8 @@ static uint8_t force_cacheattr_nibble_wb(uint8_t attr)
*/ */
static uint8_t combined_attrs_fwb(ARMCacheAttrs s1, ARMCacheAttrs s2) static uint8_t combined_attrs_fwb(ARMCacheAttrs s1, ARMCacheAttrs s2)
{ {
assert(s2.is_s2_format && !s1.is_s2_format);
switch (s2.attrs) { switch (s2.attrs) {
case 7: case 7:
/* Use stage 1 attributes */ /* Use stage 1 attributes */
@ -2467,7 +2549,7 @@ static ARMCacheAttrs combine_cacheattrs(uint64_t hcr,
ARMCacheAttrs ret; ARMCacheAttrs ret;
bool tagged = false; bool tagged = false;
assert(s2.is_s2_format && !s1.is_s2_format); assert(!s1.is_s2_format);
ret.is_s2_format = false; ret.is_s2_format = false;
if (s1.attrs == 0xf0) { if (s1.attrs == 0xf0) {
@ -2643,7 +2725,13 @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw,
cacheattrs1 = result->cacheattrs; cacheattrs1 = result->cacheattrs;
memset(result, 0, sizeof(*result)); memset(result, 0, sizeof(*result));
ret = get_phys_addr_lpae(env, ptw, ipa, access_type, is_el0, result, fi); if (arm_feature(env, ARM_FEATURE_PMSA)) {
ret = get_phys_addr_pmsav8(env, ipa, access_type,
ptw->in_mmu_idx, is_secure, result, fi);
} else {
ret = get_phys_addr_lpae(env, ptw, ipa, access_type,
is_el0, result, fi);
}
fi->s2addr = ipa; fi->s2addr = ipa;
/* Combine the S1 and S2 perms. */ /* Combine the S1 and S2 perms. */
@ -2655,10 +2743,20 @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw,
} }
/* /*
* Use the maximum of the S1 & S2 page size, so that invalidation * If either S1 or S2 returned a result smaller than TARGET_PAGE_SIZE,
* of pages > TARGET_PAGE_SIZE works correctly. * this means "don't put this in the TLB"; in this case, return a
* result with lg_page_size == 0 to achieve that. Otherwise,
* use the maximum of the S1 & S2 page size, so that invalidation
* of pages > TARGET_PAGE_SIZE works correctly. (This works even though
* we know the combined result permissions etc only cover the minimum
* of the S1 and S2 page size, because we know that the common TLB code
* never actually creates TLB entries bigger than TARGET_PAGE_SIZE,
* and passing a larger page size value only affects invalidations.)
*/ */
if (result->f.lg_page_size < s1_lgpgsz) { if (result->f.lg_page_size < TARGET_PAGE_BITS ||
s1_lgpgsz < TARGET_PAGE_BITS) {
result->f.lg_page_size = 0;
} else if (result->f.lg_page_size < s1_lgpgsz) {
result->f.lg_page_size = s1_lgpgsz; result->f.lg_page_size = s1_lgpgsz;
} }

View file

@ -19,6 +19,10 @@ bool regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx)
if (el == 2 || arm_el_is_aa64(env, el)) { if (el == 2 || arm_el_is_aa64(env, el)) {
return true; return true;
} }
if (arm_feature(env, ARM_FEATURE_PMSA) &&
arm_feature(env, ARM_FEATURE_V8)) {
return true;
}
if (arm_feature(env, ARM_FEATURE_LPAE) if (arm_feature(env, ARM_FEATURE_LPAE)
&& (regime_tcr(env, mmu_idx) & TTBCR_EAE)) { && (regime_tcr(env, mmu_idx) & TTBCR_EAE)) {
return true; return true;

View file

@ -1184,7 +1184,7 @@ static inline void gen_hlt(DisasContext *s, int imm)
* semihosting, to provide some semblance of security * semihosting, to provide some semblance of security
* (and for consistency with our 32-bit semihosting). * (and for consistency with our 32-bit semihosting).
*/ */
if (semihosting_enabled(s->current_el != 0) && if (semihosting_enabled(s->current_el == 0) &&
(imm == (s->thumb ? 0x3c : 0xf000))) { (imm == (s->thumb ? 0x3c : 0xf000))) {
gen_exception_internal_insn(s, EXCP_SEMIHOST); gen_exception_internal_insn(s, EXCP_SEMIHOST);
return; return;

View file

@ -23,7 +23,8 @@ config-cc.mak: Makefile
$(call cc-option,-march=armv8.1-a+sve2, CROSS_CC_HAS_SVE2); \ $(call cc-option,-march=armv8.1-a+sve2, CROSS_CC_HAS_SVE2); \
$(call cc-option,-march=armv8.3-a, CROSS_CC_HAS_ARMV8_3); \ $(call cc-option,-march=armv8.3-a, CROSS_CC_HAS_ARMV8_3); \
$(call cc-option,-mbranch-protection=standard, CROSS_CC_HAS_ARMV8_BTI); \ $(call cc-option,-mbranch-protection=standard, CROSS_CC_HAS_ARMV8_BTI); \
$(call cc-option,-march=armv8.5-a+memtag, CROSS_CC_HAS_ARMV8_MTE)) 3> config-cc.mak $(call cc-option,-march=armv8.5-a+memtag, CROSS_CC_HAS_ARMV8_MTE); \
$(call cc-option,-march=armv9-a+sme, CROSS_CC_HAS_ARMV9_SME)) 3> config-cc.mak
-include config-cc.mak -include config-cc.mak
# Pauth Tests # Pauth Tests
@ -53,7 +54,11 @@ endif
ifneq ($(CROSS_CC_HAS_SVE),) ifneq ($(CROSS_CC_HAS_SVE),)
# System Registers Tests # System Registers Tests
AARCH64_TESTS += sysregs AARCH64_TESTS += sysregs
ifneq ($(CROSS_CC_HAS_ARMV9_SME),)
sysregs: CFLAGS+=-march=armv9-a+sme -DHAS_ARMV9_SME
else
sysregs: CFLAGS+=-march=armv8.1-a+sve sysregs: CFLAGS+=-march=armv8.1-a+sve
endif
# SVE ioctl test # SVE ioctl test
AARCH64_TESTS += sve-ioctls AARCH64_TESTS += sve-ioctls

View file

@ -22,6 +22,13 @@
#define HWCAP_CPUID (1 << 11) #define HWCAP_CPUID (1 << 11)
#endif #endif
/*
* Older assemblers don't recognize newer system register names,
* but we can still access them by the Sn_n_Cn_Cn_n syntax.
*/
#define SYS_ID_AA64ISAR2_EL1 S3_0_C0_C6_2
#define SYS_ID_AA64MMFR2_EL1 S3_0_C0_C7_2
int failed_bit_count; int failed_bit_count;
/* Read and print system register `id' value */ /* Read and print system register `id' value */
@ -112,18 +119,23 @@ int main(void)
* minimum valid fields - for the purposes of this check allowed * minimum valid fields - for the purposes of this check allowed
* to have non-zero values. * to have non-zero values.
*/ */
get_cpu_reg_check_mask(id_aa64isar0_el1, _m(00ff,ffff,f0ff,fff0)); get_cpu_reg_check_mask(id_aa64isar0_el1, _m(f0ff,ffff,f0ff,fff0));
get_cpu_reg_check_mask(id_aa64isar1_el1, _m(0000,00f0,ffff,ffff)); get_cpu_reg_check_mask(id_aa64isar1_el1, _m(00ff,f0ff,ffff,ffff));
get_cpu_reg_check_mask(SYS_ID_AA64ISAR2_EL1, _m(0000,0000,0000,ffff));
/* TGran4 & TGran64 as pegged to -1 */ /* TGran4 & TGran64 as pegged to -1 */
get_cpu_reg_check_mask(id_aa64mmfr0_el1, _m(0000,0000,ff00,0000)); get_cpu_reg_check_mask(id_aa64mmfr0_el1, _m(f000,0000,ff00,0000));
get_cpu_reg_check_zero(id_aa64mmfr1_el1); get_cpu_reg_check_mask(id_aa64mmfr1_el1, _m(0000,f000,0000,0000));
get_cpu_reg_check_mask(SYS_ID_AA64MMFR2_EL1, _m(0000,000f,0000,0000));
/* EL1/EL0 reported as AA64 only */ /* EL1/EL0 reported as AA64 only */
get_cpu_reg_check_mask(id_aa64pfr0_el1, _m(000f,000f,00ff,0011)); get_cpu_reg_check_mask(id_aa64pfr0_el1, _m(000f,000f,00ff,0011));
get_cpu_reg_check_mask(id_aa64pfr1_el1, _m(0000,0000,0000,00f0)); get_cpu_reg_check_mask(id_aa64pfr1_el1, _m(0000,0000,0f00,0fff));
/* all hidden, DebugVer fixed to 0x6 (ARMv8 debug architecture) */ /* all hidden, DebugVer fixed to 0x6 (ARMv8 debug architecture) */
get_cpu_reg_check_mask(id_aa64dfr0_el1, _m(0000,0000,0000,0006)); get_cpu_reg_check_mask(id_aa64dfr0_el1, _m(0000,0000,0000,0006));
get_cpu_reg_check_zero(id_aa64dfr1_el1); get_cpu_reg_check_zero(id_aa64dfr1_el1);
get_cpu_reg_check_zero(id_aa64zfr0_el1); get_cpu_reg_check_mask(id_aa64zfr0_el1, _m(0ff0,ff0f,00ff,00ff));
#ifdef HAS_ARMV9_SME
get_cpu_reg_check_mask(id_aa64smfr0_el1, _m(80f1,00fd,0000,0000));
#endif
get_cpu_reg_check_zero(id_aa64afr0_el1); get_cpu_reg_check_zero(id_aa64afr0_el1);
get_cpu_reg_check_zero(id_aa64afr1_el1); get_cpu_reg_check_zero(id_aa64afr1_el1);