mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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:
+1
-1
@@ -81,7 +81,7 @@ static void fsl_imx6ul_init(Object *obj)
|
||||
*/
|
||||
for (i = 0; i < FSL_IMX6UL_NUM_GPTS; 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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+40
-1
@@ -219,9 +219,19 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
|
||||
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);
|
||||
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_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++) {
|
||||
@@ -235,8 +245,37 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
|
||||
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_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]));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+13
-15
@@ -230,13 +230,13 @@ static void n8x0_i2c_setup(struct n800_s *s)
|
||||
}
|
||||
|
||||
/* Touchscreen and keypad controller */
|
||||
static MouseTransformInfo n800_pointercal = {
|
||||
static const MouseTransformInfo n800_pointercal = {
|
||||
.x = 800,
|
||||
.y = 480,
|
||||
.a = { 14560, -68, -3455208, -39, -9621, 35152972, 65536 },
|
||||
};
|
||||
|
||||
static MouseTransformInfo n810_pointercal = {
|
||||
static const MouseTransformInfo n810_pointercal = {
|
||||
.x = 800,
|
||||
.y = 480,
|
||||
.a = { 15041, 148, -4731056, 171, -10238, 35933380, 65536 },
|
||||
@@ -334,7 +334,7 @@ static void n810_key_event(void *opaque, int keycode)
|
||||
|
||||
#define M 0
|
||||
|
||||
static int n810_keys[0x80] = {
|
||||
static const int n810_keys[0x80] = {
|
||||
[0x01] = 16, /* Q */
|
||||
[0x02] = 37, /* K */
|
||||
[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
|
||||
* - used when we want to run the main bootloader in emulation. This
|
||||
* isn't documented. */
|
||||
static uint32_t n800_pinout[104] = {
|
||||
static const uint32_t n800_pinout[104] = {
|
||||
0x080f00d8, 0x00d40808, 0x03080808, 0x080800d0,
|
||||
0x00dc0808, 0x0b0f0f00, 0x080800b4, 0x00c00808,
|
||||
0x08080808, 0x180800c4, 0x00b80000, 0x08080808,
|
||||
@@ -1060,7 +1060,7 @@ static void n8x0_boot_init(void *opaque)
|
||||
#define OMAP_TAG_CBUS 0x4e03
|
||||
#define OMAP_TAG_EM_ASIC_BB5 0x4e04
|
||||
|
||||
static struct omap_gpiosw_info_s {
|
||||
static const struct omap_gpiosw_info_s {
|
||||
const char *name;
|
||||
int line;
|
||||
int type;
|
||||
@@ -1078,7 +1078,7 @@ static struct omap_gpiosw_info_s {
|
||||
"headphone", N8X0_HEADPHONE_GPIO,
|
||||
OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED,
|
||||
},
|
||||
{ NULL }
|
||||
{ /* end of list */ }
|
||||
}, n810_gpiosw_info[] = {
|
||||
{
|
||||
"gps_reset", N810_GPS_RESET_GPIO,
|
||||
@@ -1099,10 +1099,10 @@ static struct omap_gpiosw_info_s {
|
||||
"slide", N810_SLIDE_GPIO,
|
||||
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 size;
|
||||
int mask;
|
||||
@@ -1113,27 +1113,25 @@ static struct omap_partition_info_s {
|
||||
{ 0x00080000, 0x00200000, 0x0, "kernel" },
|
||||
{ 0x00280000, 0x00200000, 0x3, "initfs" },
|
||||
{ 0x00480000, 0x0fb80000, 0x3, "rootfs" },
|
||||
|
||||
{ 0, 0, 0, NULL }
|
||||
{ /* end of list */ }
|
||||
}, n810_part_info[] = {
|
||||
{ 0x00000000, 0x00020000, 0x3, "bootloader" },
|
||||
{ 0x00020000, 0x00060000, 0x0, "config" },
|
||||
{ 0x00080000, 0x00220000, 0x0, "kernel" },
|
||||
{ 0x002a0000, 0x00400000, 0x0, "initfs" },
|
||||
{ 0x006a0000, 0x0f960000, 0x0, "rootfs" },
|
||||
|
||||
{ 0, 0, 0, NULL }
|
||||
{ /* end of list */ }
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
uint8_t *b;
|
||||
uint16_t *w;
|
||||
uint32_t *l;
|
||||
struct omap_gpiosw_info_s *gpiosw;
|
||||
struct omap_partition_info_s *partition;
|
||||
const struct omap_gpiosw_info_s *gpiosw;
|
||||
const struct omap_partition_info_s *partition;
|
||||
const char *tag;
|
||||
|
||||
w = p;
|
||||
|
||||
@@ -116,7 +116,7 @@ void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *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();
|
||||
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);
|
||||
}
|
||||
|
||||
inline void
|
||||
smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova,
|
||||
uint8_t tg, uint64_t num_pages, uint8_t ttl)
|
||||
void smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova,
|
||||
uint8_t tg, uint64_t num_pages, uint8_t ttl)
|
||||
{
|
||||
/* if tg is not set we use 4KB range invalidation */
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_asid, &asid);
|
||||
@@ -374,8 +373,8 @@ error:
|
||||
*
|
||||
* return 0 on success
|
||||
*/
|
||||
inline int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm,
|
||||
SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info)
|
||||
int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm,
|
||||
SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info)
|
||||
{
|
||||
if (!cfg->aa64) {
|
||||
/*
|
||||
@@ -483,7 +482,7 @@ static void smmu_unmap_notifier_range(IOMMUNotifier *n)
|
||||
}
|
||||
|
||||
/* Unmap all notifiers attached to @mr */
|
||||
inline void smmu_inv_notifiers_mr(IOMMUMemoryRegion *mr)
|
||||
static void smmu_inv_notifiers_mr(IOMMUMemoryRegion *mr)
|
||||
{
|
||||
IOMMUNotifier *n;
|
||||
|
||||
|
||||
+1
-1
@@ -523,7 +523,7 @@ void *tsc2005_init(qemu_irq pintdav)
|
||||
* from the touchscreen. Assuming 12-bit precision was used during
|
||||
* tslib calibration.
|
||||
*/
|
||||
void tsc2005_set_transform(void *opaque, MouseTransformInfo *info)
|
||||
void tsc2005_set_transform(void *opaque, const MouseTransformInfo *info)
|
||||
{
|
||||
TSC2005State *s = (TSC2005State *) opaque;
|
||||
|
||||
|
||||
+1
-2
@@ -1176,8 +1176,7 @@ I2SCodec *tsc210x_codec(uWireSlave *chip)
|
||||
* from the touchscreen. Assuming 12-bit precision was used during
|
||||
* tslib calibration.
|
||||
*/
|
||||
void tsc210x_set_transform(uWireSlave *chip,
|
||||
MouseTransformInfo *info)
|
||||
void tsc210x_set_transform(uWireSlave *chip, const MouseTransformInfo *info)
|
||||
{
|
||||
TSC210xState *s = (TSC210xState *) chip->opaque;
|
||||
#if 0
|
||||
|
||||
@@ -522,12 +522,6 @@ static uint32_t imx6ul_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
|
||||
case CLK_32k:
|
||||
freq = CKIL_FREQ;
|
||||
break;
|
||||
case CLK_HIGH:
|
||||
freq = CKIH_FREQ;
|
||||
break;
|
||||
case CLK_HIGH_DIV:
|
||||
freq = CKIH_FREQ / 8;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
|
||||
TYPE_IMX6UL_CCM, __func__, clock);
|
||||
|
||||
+40
-9
@@ -16,6 +16,10 @@
|
||||
#include "hw/misc/imx7_ccm.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
#define CKIH_FREQ 24000000 /* 24MHz crystal input */
|
||||
|
||||
static void imx7_analog_reset(DeviceState *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)
|
||||
{
|
||||
/*
|
||||
* This function is "consumed" by GPT emulation code, however on
|
||||
* i.MX7 each GPT block can have their own clock root. This means
|
||||
* that this functions needs somehow to know requester's identity
|
||||
* and the way to pass it: be it via additional IMXClk constants
|
||||
* or by adding another argument to this method needs to be
|
||||
* figured out
|
||||
* 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 additionnal information when calling this
|
||||
* function to know the requester's identity.
|
||||
*/
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Not implemented\n",
|
||||
TYPE_IMX7_CCM, __func__);
|
||||
return 0;
|
||||
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_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)
|
||||
|
||||
+4
-4
@@ -1068,9 +1068,9 @@ static ssize_t imx_fec_receive(NetClientState *nc, const uint8_t *buf,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 4 bytes for the CRC. */
|
||||
size += 4;
|
||||
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;
|
||||
|
||||
/* Huge frames are truncated. */
|
||||
@@ -1164,9 +1164,9 @@ static ssize_t imx_enet_receive(NetClientState *nc, const uint8_t *buf,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 4 bytes for the CRC. */
|
||||
size += 4;
|
||||
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;
|
||||
|
||||
if (shift16) {
|
||||
|
||||
+223
-153
@@ -6,6 +6,7 @@
|
||||
* Originally written by Hans Jiang
|
||||
* Updated by Peter Chubb
|
||||
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
|
||||
* Updated by Axel Heider
|
||||
*
|
||||
* This code is licensed under GPL version 2 or later. See
|
||||
* 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)
|
||||
{
|
||||
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);
|
||||
} else {
|
||||
qemu_irq_lower(s->irq);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
static uint32_t imx_epit_get_freq(IMXEPITState *s)
|
||||
{
|
||||
uint32_t clksrc;
|
||||
uint32_t prescaler;
|
||||
|
||||
clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, 2);
|
||||
prescaler = 1 + extract32(s->cr, CR_PRESCALE_SHIFT, 12);
|
||||
|
||||
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);
|
||||
}
|
||||
uint32_t clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, CR_CLKSRC_BITS);
|
||||
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]);
|
||||
uint32_t freq = f_in / prescaler;
|
||||
DPRINTF("ptimer frequency is %u\n", freq);
|
||||
return 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
|
||||
*/
|
||||
s->cr &= (CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN);
|
||||
/* Soft reset doesn't touch some bits; hard reset clears them */
|
||||
if (is_hard_reset) {
|
||||
s->cr = 0;
|
||||
} else {
|
||||
s->cr &= (CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN);
|
||||
}
|
||||
s->sr = 0;
|
||||
s->lr = EPIT_TIMER_MAX;
|
||||
s->cmp = 0;
|
||||
s->cnt = 0;
|
||||
ptimer_transaction_begin(s->timer_cmp);
|
||||
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_reload);
|
||||
/* compute new frequency */
|
||||
imx_epit_set_freq(s);
|
||||
/* init both timers to EPIT_TIMER_MAX */
|
||||
ptimer_set_limit(s->timer_cmp, 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_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)
|
||||
{
|
||||
IMXEPITState *s = IMX_EPIT(opaque);
|
||||
@@ -156,8 +138,7 @@ static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size)
|
||||
break;
|
||||
|
||||
case 4: /* CNT */
|
||||
imx_epit_update_count(s);
|
||||
reg_value = s->cnt;
|
||||
reg_value = ptimer_get_count(s->timer_reload);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -171,144 +152,219 @@ static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size)
|
||||
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)) {
|
||||
/* if the compare feature is on and timers are running */
|
||||
uint32_t tmp = imx_epit_update_count(s);
|
||||
uint64_t next;
|
||||
if (tmp > s->cmp) {
|
||||
/* It'll fire in this round of the timer */
|
||||
next = tmp - s->cmp;
|
||||
} else { /* catch it next time around */
|
||||
next = tmp - s->cmp + ((s->cr & CR_RLD) ? EPIT_TIMER_MAX : s->lr);
|
||||
uint64_t counter = 0;
|
||||
bool is_oneshot = false;
|
||||
/*
|
||||
* The compare timer only has to run if the timer peripheral is active
|
||||
* and there is an input clock, Otherwise it can be switched off.
|
||||
*/
|
||||
bool is_active = (s->cr & CR_EN) && imx_epit_get_freq(s);
|
||||
if (is_active) {
|
||||
/*
|
||||
* 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,
|
||||
unsigned size)
|
||||
{
|
||||
IMXEPITState *s = IMX_EPIT(opaque);
|
||||
uint64_t oldcr;
|
||||
|
||||
DPRINTF("(%s, value = 0x%08x)\n", imx_epit_reg_name(offset >> 2),
|
||||
(uint32_t)value);
|
||||
|
||||
switch (offset >> 2) {
|
||||
case 0: /* CR */
|
||||
|
||||
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);
|
||||
imx_epit_write_cr(s, (uint32_t)value);
|
||||
break;
|
||||
|
||||
case 1: /* SR - ACK*/
|
||||
/* writing 1 to OCIF clear the OCIF bit */
|
||||
if (value & 0x01) {
|
||||
s->sr = 0;
|
||||
imx_epit_update_int(s);
|
||||
}
|
||||
case 1: /* SR */
|
||||
imx_epit_write_sr(s, (uint32_t)value);
|
||||
break;
|
||||
|
||||
case 2: /* LR - set ticks */
|
||||
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 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);
|
||||
case 2: /* LR */
|
||||
imx_epit_write_lr(s, (uint32_t)value);
|
||||
break;
|
||||
|
||||
case 3: /* CMP */
|
||||
s->cmp = value;
|
||||
|
||||
ptimer_transaction_begin(s->timer_cmp);
|
||||
imx_epit_reload_compare_timer(s);
|
||||
ptimer_transaction_commit(s->timer_cmp);
|
||||
|
||||
imx_epit_write_cmp(s, (uint32_t)value);
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
|
||||
HWADDR_PRIx "\n", TYPE_IMX_EPIT, __func__, offset);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void imx_epit_cmp(void *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);
|
||||
}
|
||||
|
||||
@@ -325,15 +381,13 @@ static const MemoryRegionOps imx_epit_ops = {
|
||||
|
||||
static const VMStateDescription vmstate_imx_timer_epit = {
|
||||
.name = TYPE_IMX_EPIT,
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 3,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(cr, IMXEPITState),
|
||||
VMSTATE_UINT32(sr, IMXEPITState),
|
||||
VMSTATE_UINT32(lr, IMXEPITState),
|
||||
VMSTATE_UINT32(cmp, IMXEPITState),
|
||||
VMSTATE_UINT32(cnt, IMXEPITState),
|
||||
VMSTATE_UINT32(freq, IMXEPITState),
|
||||
VMSTATE_PTIMER(timer_reload, IMXEPITState),
|
||||
VMSTATE_PTIMER(timer_cmp, IMXEPITState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
@@ -352,17 +406,33 @@ static void imx_epit_realize(DeviceState *dev, Error **errp)
|
||||
0x00001000);
|
||||
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);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = imx_epit_realize;
|
||||
dc->reset = imx_epit_reset;
|
||||
dc->reset = imx_epit_dev_reset;
|
||||
dc->vmsd = &vmstate_imx_timer_epit;
|
||||
dc->desc = "i.MX periodic timer";
|
||||
}
|
||||
|
||||
@@ -115,6 +115,17 @@ static const IMXClk imx6_gpt_clocks[] = {
|
||||
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[] = {
|
||||
CLK_NONE, /* 000 No clock source */
|
||||
CLK_IPG, /* 001 ipg_clk, 532MHz*/
|
||||
@@ -539,6 +550,13 @@ static void imx6_gpt_init(Object *obj)
|
||||
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)
|
||||
{
|
||||
IMXGPTState *s = IMX_GPT(obj);
|
||||
@@ -566,6 +584,12 @@ static const TypeInfo imx6_gpt_info = {
|
||||
.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 = {
|
||||
.name = TYPE_IMX7_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(&imx31_gpt_info);
|
||||
type_register_static(&imx6_gpt_info);
|
||||
type_register_static(&imx6ul_gpt_info);
|
||||
type_register_static(&imx7_gpt_info);
|
||||
}
|
||||
|
||||
|
||||
@@ -235,6 +235,26 @@ enum FslIMX7IRQs {
|
||||
FSL_IMX7_USB2_IRQ = 42,
|
||||
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_WDOG2_IRQ = 79,
|
||||
FSL_IMX7_WDOG3_IRQ = 10,
|
||||
|
||||
@@ -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 */
|
||||
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 */
|
||||
|
||||
@@ -30,12 +30,12 @@ uWireSlave *tsc2102_init(qemu_irq pint);
|
||||
uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav);
|
||||
I2SCodec *tsc210x_codec(uWireSlave *chip);
|
||||
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);
|
||||
|
||||
/* tsc2005.c */
|
||||
void *tsc2005_init(qemu_irq pintdav);
|
||||
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
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
#define CR_OCIEN (1 << 2)
|
||||
#define CR_RLD (1 << 3)
|
||||
#define CR_PRESCALE_SHIFT (4)
|
||||
#define CR_PRESCALE_MASK (0xfff)
|
||||
#define CR_PRESCALE_BITS (12)
|
||||
#define CR_SWR (1 << 16)
|
||||
#define CR_IOVW (1 << 17)
|
||||
#define CR_DBGEN (1 << 18)
|
||||
@@ -51,7 +51,9 @@
|
||||
#define CR_DOZEN (1 << 20)
|
||||
#define CR_STOPEN (1 << 21)
|
||||
#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
|
||||
|
||||
@@ -72,9 +74,7 @@ struct IMXEPITState {
|
||||
uint32_t sr;
|
||||
uint32_t lr;
|
||||
uint32_t cmp;
|
||||
uint32_t cnt;
|
||||
|
||||
uint32_t freq;
|
||||
qemu_irq irq;
|
||||
};
|
||||
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
#define TYPE_IMX25_GPT "imx25.gpt"
|
||||
#define TYPE_IMX31_GPT "imx31.gpt"
|
||||
#define TYPE_IMX6_GPT "imx6.gpt"
|
||||
#define TYPE_IMX6UL_GPT "imx6ul.gpt"
|
||||
#define TYPE_IMX7_GPT "imx7.gpt"
|
||||
|
||||
#define TYPE_IMX_GPT TYPE_IMX25_GPT
|
||||
|
||||
+29
-6
@@ -26,7 +26,6 @@
|
||||
#include "target/arm/idau.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "cpu.h"
|
||||
#ifdef CONFIG_TCG
|
||||
#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,
|
||||
CPACR, CP11, 3);
|
||||
#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)
|
||||
@@ -487,6 +490,14 @@ static void arm_cpu_reset_hold(Object *obj)
|
||||
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_S] = 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);
|
||||
}
|
||||
|
||||
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
|
||||
if (arm_feature(&cpu->env, ARM_FEATURE_V8)) {
|
||||
object_property_add_uint64_ptr(obj, "rvbar",
|
||||
&cpu->rvbar_prop,
|
||||
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
|
||||
* to false or by setting pmsav7-dregion to 0.
|
||||
*/
|
||||
if (!cpu->has_mpu) {
|
||||
cpu->pmsav7_dregion = 0;
|
||||
}
|
||||
if (cpu->pmsav7_dregion == 0) {
|
||||
if (!cpu->has_mpu || cpu->pmsav7_dregion == 0) {
|
||||
cpu->has_mpu = false;
|
||||
cpu->pmsav7_dregion = 0;
|
||||
cpu->pmsav8r_hdregion = 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
|
||||
@@ -309,6 +309,7 @@ typedef struct CPUArchState {
|
||||
};
|
||||
uint64_t sctlr_el[4];
|
||||
};
|
||||
uint64_t vsctlr; /* Virtualization System control register. */
|
||||
uint64_t cpacr_el1; /* Architectural feature access control register */
|
||||
uint64_t cptr_el[4]; /* ARMv8 feature trap registers */
|
||||
uint32_t c1_xscaleauxcr; /* XScale auxiliary control register. */
|
||||
@@ -745,8 +746,11 @@ typedef struct CPUArchState {
|
||||
*/
|
||||
uint32_t *rbar[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 mair1[M_REG_NUM_BANKS];
|
||||
uint32_t hprselr;
|
||||
} pmsav8;
|
||||
|
||||
/* v8M SAU */
|
||||
@@ -906,6 +910,8 @@ struct ArchCPU {
|
||||
bool has_mpu;
|
||||
/* PMSAv7 MPU number of supported regions */
|
||||
uint32_t pmsav7_dregion;
|
||||
/* PMSAv8 MPU number of supported hyp regions */
|
||||
uint32_t pmsav8r_hdregion;
|
||||
/* v8M SAU number of supported regions */
|
||||
uint32_t sau_sregion;
|
||||
|
||||
|
||||
@@ -21,13 +21,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "cpu.h"
|
||||
#ifdef CONFIG_TCG
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
#endif /* CONFIG_TCG */
|
||||
#include "qemu/module.h"
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#include "hw/loader.h"
|
||||
#endif
|
||||
#include "sysemu/kvm.h"
|
||||
#include "sysemu/hvf.h"
|
||||
#include "kvm_arm.h"
|
||||
|
||||
@@ -854,6 +854,47 @@ static void cortex_r5_initfn(Object *obj)
|
||||
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)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(obj);
|
||||
@@ -1163,6 +1204,7 @@ static const ARMCPUInfo arm_tcg_cpus[] = {
|
||||
.class_init = arm_v7m_class_init },
|
||||
{ .name = "cortex-r5", .initfn = cortex_r5_initfn },
|
||||
{ .name = "cortex-r5f", .initfn = cortex_r5f_initfn },
|
||||
{ .name = "cortex-r52", .initfn = cortex_r52_initfn },
|
||||
{ .name = "ti925t", .initfn = ti925t_initfn },
|
||||
{ .name = "sa1100", .initfn = sa1100_initfn },
|
||||
{ .name = "sa1110", .initfn = sa1110_initfn },
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user